diff --git a/Makefile b/Makefile index cce204c3ce..49e4e5da51 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ DEPLOY_ROOT_DIR := /var/www/vhosts/mf-geoadmin3/private/branch DEPLOY_TARGET ?= 'dev' LAST_DEPLOY_TARGET := $(shell if [ -f .build-artefacts/last-deploy-target ]; then cat .build-artefacts/last-deploy-target 2> /dev/null; else echo '-none-'; fi) OL3_VERSION ?= 627abaf1a71d48627163eb00ea6a0b6fb8dede14 -OL3_CESIUM_VERSION ?= c68901adc91bbc019d6cc70056c51c00aa2fe99f +OL3_CESIUM_VERSION ?= dbbc31dd2ec4751aab9e1892d78fdc1e7b55f7eb CESIUM_VERSION ?= 3e3cf938786ee48b4b376ed932904541d798671d DEFAULT_TOPIC_ID ?= ech TRANSLATION_FALLBACK_CODE ?= de @@ -129,7 +129,7 @@ deploydev: ./scripts/deploydev.sh -s; \ else \ ./scripts/deploydev.sh; \ - fi + fi .PHONY: deploydemo deploydemo: guard-SNAPSHOT @@ -167,32 +167,25 @@ deploybranchdemo: deploybranch .PHONY: preparebranch preparebranch: rc_branch scripts/00-$(GIT_BRANCH).conf -.PHONY: ol -ol: OL_JS = ol.js ol-debug.js -ol: scripts/ol-geoadmin.json .build-artefacts/ol3 - cd .build-artefacts/ol3; \ - git reset HEAD --hard; \ - git fetch -a; \ - git checkout $(OL3_VERSION); \ - git show; \ - cat ../../scripts/ga-ol3-style.exports >> src/ol/style/style.js; \ - cat ../../scripts/ga-ol3-tilegrid.exports >> src/ol/tilegrid/tilegrid.js; \ - cat ../../scripts/ga-ol3-tilerange.exports >> src/ol/tilerange.js; \ - cat ../../scripts/ga-ol3-view.exports >> src/ol/view.js; \ - npm install; \ - node tasks/build.js config/ol-debug.json build/ol-debug.js; \ - node tasks/build.js ../../scripts/ol-geoadmin.json build/ol.js; \ - cd ../../; \ - cp $(addprefix .build-artefacts/ol3/build/,$(OL_JS)) src/lib/; - .PHONY: ol3cesium -ol3cesium: ol .build-artefacts/ol3-cesium +ol3cesium: .build-artefacts/ol3-cesium cd .build-artefacts/ol3-cesium; \ git reset HEAD --hard; \ git fetch --all; \ git checkout $(OL3_CESIUM_VERSION); \ git submodule update --recursive --init --force; \ - cd cesium; \ + cd ol3; \ + git reset HEAD --hard; \ + git fetch --all; \ + git checkout $(OL3_VERSION); \ + git show; \ + cat ../../../scripts/ga-ol3-style.exports >> src/ol/style/style.js; \ + cat ../../../scripts/ga-ol3-tilegrid.exports >> src/ol/tilegrid/tilegrid.js; \ + cat ../../../scripts/ga-ol3-tilerange.exports >> src/ol/tilerange.js; \ + cat ../../../scripts/ga-ol3-view.exports >> src/ol/view.js; \ + npm install --production; \ + node tasks/build-ext.js; \ + cd ../cesium; \ git remote | grep c2c || git remote add c2c git://github.com/camptocamp/cesium; \ git fetch --all; \ git checkout $(CESIUM_VERSION); \ @@ -201,13 +194,16 @@ ol3cesium: ol .build-artefacts/ol3-cesium ln -T -f -s ../../../../ol3-cesium-plugin/ src/plugins/geoadmin; \ ( cd cesium; [ -f node_modules/.bin/gulp ] || npm install ); \ ( cd cesium; if [ -f "Build/Cesium/Cesium.js" ] ; then echo 'Skipping Cesium minified build'; else node_modules/.bin/gulp minifyRelease; fi ); \ - NO_CESIUM=1 make dist; \ ( cd cesium; if [ -f "Build/CesiumUnminified/Cesium.js" ] ; then echo 'Skipping Cesium debug build'; else node_modules/.bin/gulp generateStubs combine; fi ); \ - node build/build.js ../../scripts/ol3cesium-debug-geoadmin.json dist/ol3cesium-debug.js; \ + npm install; \ + node build/generate-exports.js dist/exports.js; \ + node build/build.js build/ol3cesium-debug.json dist/ol3cesium-debug.js; \ + node build/build.js ../../scripts/ol3cesium-geoadmin.json dist/ol3cesium.js; \ cp dist/ol3cesium-debug.js ../../src/lib/; \ - cat cesium/Build/Cesium/Cesium.js dist/ol3cesium.js > ../../src/lib/ol3cesium.js; \ - rm -rf ../../src/lib/Cesium/*; \ - cp -r cesium/Build/CesiumUnminified/* ../../src/lib/Cesium; + cp dist/ol3cesium.js ../../src/lib/ol3cesium.js; \ + rm -rf ../../src/lib/Cesium; \ + cp -r cesium/Build/CesiumUnminified ../../src/lib/Cesium; \ + cp cesium/Build/Cesium/Cesium.js ../../src/lib/Cesium.min.js; .PHONY: fastclick fastclick: .build-artefacts/fastclick .build-artefacts/closure-compiler/compiler.jar @@ -239,8 +235,8 @@ datepicker: .build-artefacts/datepicker translate: ${PYTHON_CMD} scripts/translation2json.py \ --files $(TRANSLATE_CSV_FILES) \ - --languages "$(LANGUAGES)" \ - --empty-json-file $(TRANSLATE_EMPTY_JSON) \ + --languages "$(LANGUAGES)" \ + --empty-json-file $(TRANSLATE_EMPTY_JSON) \ --output-folder $(TRANSLATE_OUTPUT) .PHONY: fixrights @@ -264,6 +260,7 @@ prd/lib/: src/lib/d3-3.3.1.min.js \ src/lib/IE9Fixes.js \ src/lib/jQuery.XDomainRequest.js \ src/lib/Cesium \ + src/lib/Cesium.min.js \ src/lib/ol3cesium.js mkdir -p $@ cp -rf $^ $@ @@ -277,7 +274,7 @@ prd/lib/build.js: src/lib/jquery-2.0.3.min.js \ src/lib/EPSG2056.js \ src/lib/EPSG32631.js \ src/lib/EPSG32632.js \ - src/lib/ol.js \ + src/lib/ol3cesium.js \ src/lib/angular-translate.min.js \ src/lib/angular-translate-loader-static-files.min.js \ src/lib/fastclick.min.js \ @@ -487,7 +484,7 @@ $(addprefix .build-artefacts/annotated/, $(SRC_JS_FILES) src/TemplateCacheModule ${PYTHON_CMD} .build-artefacts/closure-library/closure/bin/build/closurebuilder.py \ --root=.build-artefacts/annotated \ --root=.build-artefacts/closure-library \ - --namespace="ga" \ + --namespace="geoadmin" \ --namespace="__ga_template_cache__" \ --output_mode=list > $@ @@ -581,9 +578,6 @@ scripts/00-$(GIT_BRANCH).conf: scripts/00-branch.mako-dot-conf \ test $(DEPLOY_TARGET) != $(LAST_DEPLOY_TARGET) && \ echo $(DEPLOY_TARGET) > .build-artefacts/last-deploy-target || : -.build-artefacts/ol3: - git clone https://github.com/openlayers/ol3.git $@ - .build-artefacts/ol3-cesium: git clone --recursive https://github.com/openlayers/ol3-cesium.git $@ diff --git a/ol3-cesium-plugin/garastersynchronizer.js b/ol3-cesium-plugin/garastersynchronizer.js index 8c68456b2b..8f1a020094 100644 --- a/ol3-cesium-plugin/garastersynchronizer.js +++ b/ol3-cesium-plugin/garastersynchronizer.js @@ -1,4 +1,4 @@ -goog.provide('ga.GaRasterSynchronizer'); +goog.provide('olcs.GaRasterSynchronizer'); goog.require('olcs.RasterSynchronizer'); @@ -11,16 +11,16 @@ goog.require('olcs.RasterSynchronizer'); * @extends {olcs.RasterSynchronizer} * @api */ -ga.GaRasterSynchronizer = function(map, scene) { +olcs.GaRasterSynchronizer = function(map, scene) { goog.base(this, map, scene); }; -goog.inherits(ga.GaRasterSynchronizer, olcs.RasterSynchronizer); +goog.inherits(olcs.GaRasterSynchronizer, olcs.RasterSynchronizer); /** * @override */ -ga.GaRasterSynchronizer.prototype.convertLayerToCesiumImageries = +olcs.GaRasterSynchronizer.prototype.convertLayerToCesiumImageries = function(olLayer, viewProj) { /** diff --git a/scripts/ol3cesium-geoadmin.json b/scripts/ol3cesium-geoadmin.json new file mode 100644 index 0000000000..e64d344e3c --- /dev/null +++ b/scripts/ol3cesium-geoadmin.json @@ -0,0 +1,182 @@ +{ + "src": [ + "src/**/*.js", + "ol3/src/**/*.js", + "ol3/build/ol.ext/*.js" + ], + "exports": [ + "olcs.*", + "ol.Collection", + "ol.Collection#*", + "ol.DeviceOrientation", + "ol.DeviceOrientation#*", + "ol.Feature", + "ol.Feature#*", + "ol.Geolocation", + "ol.Geolocation#*", + "ol.ImageTile#getImage", + "ol.Map", + "ol.Map#*", + "ol.MapBrowserEvent#*", + "ol.Observable.unByKey", + "ol.Overlay", + "ol.Overlay#*", + "ol.View", + "ol.View#*", + "ol.animation.bounce", + "ol.animation.pan", + "ol.animation.rotate", + "ol.animation.zoom", + "ol.color.asArray", + "ol.color.asString", + "ol.control.MousePosition", + "ol.control.MousePosition#*", + "ol.control.ScaleLine", + "ol.control.ScaleLine#*", + "ol.control.ZoomToExtent", + "ol.control.ZoomToExtent#*", + "ol.control.defaults", + "ol.coordinate.format", + "ol.coordinate.toStringHDMS", + "ol.coordinate.toStringXY", + "ol.easing.easeOut", + "ol.easing.linear", + "ol.extent.buffer", + "ol.extent.containsCoordinate", + "ol.extent.containsXY", + "ol.extent.getCenter", + "ol.extent.getHeight", + "ol.extent.getWidth", + "ol.extent.intersects", + "ol.format.GeoJSON", + "ol.format.GeoJSON#*", + "ol.format.KML", + "ol.format.KML#*", + "ol.format.WMSCapabilities", + "ol.format.WMSCapabilities#*", + "ol.geom.Circle", + "ol.geom.Circle#*", + "ol.geom.GeometryCollection", + "ol.geom.GeometryCollection#*", + "ol.geom.LinearRing", + "ol.geom.LinearRing#*", + "ol.geom.LineString", + "ol.geom.LineString#*", + "ol.geom.MultiLineString", + "ol.geom.MultiLineString#*", + "ol.geom.MultiPoint", + "ol.geom.MultiPoint#*", + "ol.geom.MultiPolygon", + "ol.geom.MultiPolygon#*", + "ol.geom.Point", + "ol.geom.Point#*", + "ol.geom.Polygon", + "ol.geom.Polygon#*", + "ol.has.DEVICE_ORIENTATION", + "ol.has.DEVICE_PIXEL_RATIO", + "ol.interaction.DragBox", + "ol.interaction.DragBox#*", + "ol.interaction.DragZoom", + "ol.interaction.DragZoom#*", + "ol.interaction.Draw", + "ol.interaction.Draw#*", + "ol.interaction.KeyboardPan", + "ol.interaction.KeyboardPan#*", + "ol.interaction.KeyboardZoom", + "ol.interaction.KeyboardZoom#*", + "ol.interaction.Modify", + "ol.interaction.Modify#*", + "ol.interaction.Select", + "ol.interaction.Select#*", + "ol.interaction.Snap", + "ol.interaction.Snap#*", + "ol.interaction.defaults", + "ol.layer.Group", + "ol.layer.Group#*", + "ol.layer.Image", + "ol.layer.Image#*", + "ol.layer.Layer", + "ol.layer.Layer#*", + "ol.layer.Tile", + "ol.layer.Tile#*", + "ol.layer.Vector", + "ol.layer.Vector#*", + "ol.proj.Projection", + "ol.proj.Projection#*", + "ol.proj.get", + "ol.proj.transform", + "ol.proj.transformExtent", + "ol.style.Circle", + "ol.style.Circle#*", + "ol.style.Fill", + "ol.style.Fill#*", + "ol.style.Icon", + "ol.style.Icon#*", + "ol.style.Image", + "ol.style.Image#*", + "ol.style.RegularShape", + "ol.style.RegularShape#*", + "ol.style.Stroke", + "ol.style.Stroke#*", + "ol.style.Style", + "ol.style.Style#*", + "ol.style.Text", + "ol.style.Text#*", + "ol.source.ImageVector", + "ol.source.ImageVector#*", + "ol.source.ImageWMS", + "ol.source.ImageWMS#*", + "ol.source.TileImage", + "ol.source.TileImage#*", + "ol.source.TileWMS", + "ol.source.TileWMS#*", + "ol.source.Vector", + "ol.source.Vector#*", + "ol.source.WMTS", + "ol.source.WMTS#*", + "ol.tilegrid.TileGrid", + "ol.tilegrid.TileGrid#*", + "ol.tilegrid.WMTS", + "ol.tilegrid.WMTS#*" + ], + "umd": true, + "compile": { + "externs": [ + "externs/olcsx.js", + "Cesium.externs.js", + "ol3/externs/bingmaps.js", + "ol3/externs/closure-compiler.js", + "ol3/externs/geojson.js", + "ol3/externs/oli.js", + "ol3/externs/olx.js", + "ol3/externs/proj4js.js", + "ol3/externs/tilejson.js", + "ol3/externs/topojson.js" + ], + "define": [ + "goog.array.ASSUME_NATIVE_FUNCTIONS=true", + "goog.dom.ASSUME_STANDARDS_MODE=true", + "goog.json.USE_NATIVE_JSON=true", + "goog.DEBUG=false", + "ol.ENABLE_DOM=false", + "ol.ENABLE_WEBGL=false" + ], + "jscomp_error": [ + "*" + ], + "jscomp_off": [ + "useOfGoogBase", + "unnecessaryCasts", + "lintChecks" + ], + "extra_annotation_name": [ + "api", "observable" + ], + "compilation_level": "ADVANCED", + "warning_level": "VERBOSE", + "use_types_for_optimization": true, + "manage_closure_dependencies": true, + "create_source_map": "dist/ol3cesium.js.map", + "source_map_format": "V3" + } +} diff --git a/src/TemplateCacheModule.mako.js b/src/TemplateCacheModule.mako.js index cb5601d1b5..e93fd36d7b 100644 --- a/src/TemplateCacheModule.mako.js +++ b/src/TemplateCacheModule.mako.js @@ -20,9 +20,9 @@ %>\ // Generated code. Do not edit. goog.provide('__ga_template_cache__'); -goog.require('ga'); +goog.require('geoadmin'); (function() { - angular.module('ga').run(['$templateCache', function($templateCache) { + angular.module('geoadmin').run(['$templateCache', function($templateCache) { % for partial in _partials: $templateCache.put('${partial}', '${_partials[partial]}'); %endfor diff --git a/src/index.mako.html b/src/index.mako.html index 1ec25219bf..02a0e31d66 100644 --- a/src/index.mako.html +++ b/src/index.mako.html @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- - % endif @@ -708,7 +708,7 @@ cache: true }); - var module = angular.module('ga'); + var module = angular.module('geoadmin'); var cacheAdd = '${version}' != '' ? '/' + '${version}' : ''; var pathname = location.pathname.replace(/(index|mobile|embed)\.html$/g, ''); @@ -719,6 +719,7 @@ % else: dev3d: !!window.location.search.match(/(dev3d=true)/), % endif + buildMode: '${mode}', pegman: !!window.location.search.match(/(pegman=true)/), mapUrl : location.origin + '${apache_base_path}', apiUrl : location.protocol + '${api_url}', diff --git a/src/js/GaCesium.js b/src/js/GaCesium.js index f9916a72d8..28ab6b9ad2 100644 --- a/src/js/GaCesium.js +++ b/src/js/GaCesium.js @@ -16,7 +16,12 @@ goog.provide('ga_cesium'); var GaCesium = function(map, gaPermalink, gaLayers, gaGlobalOptions, gaBrowserSniffer, $q, $translate) { // Url of ol3cesium library - var ol3CesiumLibUrl = gaGlobalOptions.resourceUrl + 'lib/ol3cesium.js'; + var ol3CesiumLibUrl = gaGlobalOptions.resourceUrl; + if (gaGlobalOptions.buildMode === 'prod') { + ol3CesiumLibUrl += 'lib/Cesium.min.js'; + } else { + ol3CesiumLibUrl += 'lib/Cesium/Cesium.js'; + } var cesiumLoaded = $q.defer(); var cesiumClients = $q.defer(); var ol3d = undefined; @@ -77,7 +82,7 @@ var GaCesium = function(map, gaPermalink, gaLayers, gaGlobalOptions, map: map, createSynchronizers: function(map, scene) { return [ - new ga.GaRasterSynchronizer(map, scene), + new olcs.GaRasterSynchronizer(map, scene), new olcs.VectorSynchronizer(map, scene) ]; } @@ -180,7 +185,7 @@ var GaCesium = function(map, gaPermalink, gaLayers, gaGlobalOptions, return function(activate) { // Check if cesium library is already loaded toActivate = activate; - if (!window.olcs) { + if (!window.Cesium) { loading = true; $.getScript(ol3CesiumLibUrl, function() { cesiumLoaded.resolve(toActivate); diff --git a/src/js/GaModule.js b/src/js/GaModule.js index f1143d2162..fd54ae7f15 100644 --- a/src/js/GaModule.js +++ b/src/js/GaModule.js @@ -1,4 +1,4 @@ -goog.provide('ga'); +goog.provide('geoadmin'); goog.require('ga_attribution'); @@ -62,7 +62,7 @@ goog.require('ga_waitcursor_service'); (function() { - var module = angular.module('ga', [ + var module = angular.module('geoadmin', [ 'ga_controls3d', 'ga_attribution', 'ga_catalogtree', diff --git a/src/lib/Cesium.min.js b/src/lib/Cesium.min.js new file mode 100644 index 0000000000..da3f606e7f --- /dev/null +++ b/src/lib/Cesium.min.js @@ -0,0 +1,470 @@ +/** + * Cesium - https://github.com/AnalyticalGraphicsInc/cesium + * + * Copyright 2011-2015 Cesium Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Columbus View (Pat. Pend.) + * + * Portions licensed separately. + * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details. + */ +/** + * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/almond for details + */ + +/** + @license + when.js - https://github.com/cujojs/when + + MIT License (c) copyright B Cavalier & J Hann + + * A lightweight CommonJS Promises/A and when() implementation + * when is part of the cujo.js family of libraries (http://cujojs.com/) + * + * Licensed under the MIT License at: + * http://www.opensource.org/licenses/mit-license.php + * + * @version 1.7.1 + */ + +/** +@license +mersenne-twister.js - https://gist.github.com/banksean/300494 + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @license + * + * Grauw URI utilities + * + * See: http://hg.grauw.nl/grauw-lib/file/tip/src/uri.js + * + * @author Laurens Holst (http://www.grauw.nl/) + * + * Copyright 2012 Laurens Holst + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** +@license +sprintf.js from the php.js project - https://github.com/kvz/phpjs +Directly from https://github.com/kvz/phpjs/blob/master/functions/strings/sprintf.js + +php.js is copyright 2012 Kevin van Zonneveld. + +Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld +(http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White +(http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jack, Jonas +Raoni Soares Silva (http://www.jsfromhell.com), Philip Peterson, Legaev +Andrey, Ates Goral (http://magnetiq.com), Alex, Ratheous, Martijn Wieringa, +Rafa? Kukawski (http://blog.kukawski.pl), lmeyrick +(https://sourceforge.net/projects/bcmath-js/), Nate, Philippe Baumann, +Enrique Gonzalez, Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. +L. Rodrigues (http://www.jsfromhell.com), Ash Searle +(http://hexmen.com/blog/), Jani Hartikainen, travc, Ole Vrijenhoek, +Erkekjetter, Michael Grier, Rafa? Kukawski (http://kukawski.pl), Johnny +Mast (http://www.phpvrouwen.nl), T.Wild, d3x, +http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript, +Rafa? Kukawski (http://blog.kukawski.pl/), stag019, pilus, WebDevHobo +(http://webdevhobo.blogspot.com/), marrtins, GeekFG +(http://geekfg.blogspot.com), Andrea Giammarchi +(http://webreflection.blogspot.com), Arpad Ray (mailto:arpad@php.net), +gorthaur, Paul Smith, Tim de Koning (http://www.kingsquare.nl), Joris, Oleg +Eremeev, Steve Hilder, majak, gettimeofday, KELAN, Josh Fraser +(http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/), +Marc Palau, Martin +(http://www.erlenwiese.de/), Breaking Par Consulting Inc +(http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7), +Chris, Mirek Slugen, saulius, Alfonso Jimenez +(http://www.alfonsojimenez.com), Diplom@t (http://difane.com/), felix, +Mailfaker (http://www.weedem.fr/), Tyler Akins (http://rumkin.com), Caio +Ariede (http://caioariede.com), Robin, Kankrelune +(http://www.webfaktory.info/), Karol Kowalski, Imgen Tata +(http://www.myipdf.com/), mdsjack (http://www.mdsjack.bo.it), Dreamer, +Felix Geisendoerfer (http://www.debuggable.com/felix), Lars Fischer, AJ, +David, Aman Gupta, Michael White, Public Domain +(http://www.json.org/json2.js), Steven Levithan +(http://blog.stevenlevithan.com), Sakimori, Pellentesque Malesuada, +Thunder.m, Dj (http://phpjs.org/functions/htmlentities:425#comment_134018), +Steve Clay, David James, Francois, class_exists, nobbler, T. Wild, Itsacon +(http://www.itsacon.net/), date, Ole Vrijenhoek (http://www.nervous.nl/), +Fox, Raphael (Ao RUDLER), Marco, noname, Mateusz "loonquawl" Zalega, Frank +Forte, Arno, ger, mktime, john (http://www.jd-tech.net), Nick Kolosov +(http://sammy.ru), marc andreu, Scott Cariss, Douglas Crockford +(http://javascript.crockford.com), madipta, Slawomir Kaniecki, +ReverseSyntax, Nathan, Alex Wilson, kenneth, Bayron Guevara, Adam Wallner +(http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix, +Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick +(https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan, +Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H?gfeldt +(http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb, +josh, jd, Pier Paolo Ramon (http://www.mastersoup.com/), P, merabi, Soren +Hansen, Eugene Bulkin (http://doubleaw.com/), Der Simon +(http://innerdom.sourceforge.net/), echo is bad, Ozh, XoraX +(http://www.xorax.info), EdorFaus, JB, J A R, Marc Jansen, Francesco, LH, +Stoyan Kyosev (http://www.svest.org/), nord_ua, omid +(http://phpjs.org/functions/380:380#comment_137122), Brad Touesnard, MeEtc +(http://yass.meetcweb.com), Peter-Paul Koch +(http://www.quirksmode.org/js/beat.html), Olivier Louvignes +(http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, Jalal Berrami, +Martin, JT, David Randall, Thomas Beaucourt (http://www.webapp.fr), taith, +vlado houba, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair +Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger +(http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner +B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong +(http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna, +Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni, +Marco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke +(http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski, +Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke +Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet, +sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen, +Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya +(http://www.premasolutions.com/), Philippe Jausions +(http://pear.php.net/user/jausions), Aidan Lister +(http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp, +strcmp, Taras Bogach, jpfle, Alexander Ermolaev +(http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando, +dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha +(http://www.pedrotainha.com), James, Arnout Kazemier +(http://www.3rd-Eden.com), Chris McMacken, gabriel paderni, Yannoo, +FGFEmperor, baris ozdil, Tod Gentille, Greg Frazier, jakes, 3D-GRAF, Allan +Jensen (http://www.winternet.no), Howard Yeend, Benjamin Lupton, davook, +daniel airton wermann (http://wermann.com.br), Atli T¨®r, Maximusya, Ryan +W Tenney (http://ryan.10e.us), Alexander M Beedie, fearphage +(http://http/my.opera.com/fearphage/), Nathan Sepulveda, Victor, Matteo, +Billy, stensi, Cord, Manish, T.J. Leahy, Riddler +(http://www.frontierwebdev.com/), Rafa? Kukawski, FremyCompany, Matt +Bradley, Tim de Koning, Luis Salazar (http://www.freaky-media.com/), Diogo +Resende, Rival, Andrej Pavlovic, Garagoth, Le Torbi +(http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem, +Russell Walker (http://www.nbill.co.uk/), Jamie Beck +(http://www.terabit.ca/), setcookie, Michael, YUI Library: +http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at +http://hacks.bluesmoon.info/strftime/strftime.js, Ben +(http://benblume.co.uk/), DtTvB +(http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William, +meo, incidence, Cagri Ekin, Amirouche, Amir Habibi +(http://www.residence-mixte.com/), Luke Smith (http://lucassmith.name), +Kheang Hok Chin (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani, +Tony, Yen-Wei Liu, Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben +Bryan + +Licensed under the MIT (MIT-LICENSE.txt) license. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES +OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright 2012 Google Inc., Apache 2.0 license. + +/** +@license +tween.js - https://github.com/sole/tween.js + +Copyright (c) 2010-2012 Tween.js authors. + +Easing equations Copyright (c) 2001 Robert Penner http://robertpenner.com/easing/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** + @license + fontmetrics.js - https://github.com/Pomax/fontmetrics.js + + Copyright (C) 2011 by Mike "Pomax" Kamermans + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +**/ + +/** +@license +topojson - https://github.com/mbostock/topojson + +Copyright (c) 2012, Michael Bostock +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* The name Michael Bostock may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*! + * Autolinker.js + * 0.17.1 + * + * Copyright(c) 2015 Gregory Jacobs + * MIT Licensed. http://www.opensource.org/licenses/mit-license.php + * + * https://github.com/gregjacobs/Autolinker.js + */ + +/** +@license + Copyright (c) 2013 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**/ + +/** + * @license + * Copyright (c) 2011 NVIDIA Corporation. All rights reserved. + * + * TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED + * *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS + * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA + * OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS + * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY + * OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/** + * @license + * Copyright (c) 2000-2005, Sean O'Neil (s_p_oneil@hotmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Modifications made by Analytical Graphics, Inc. + */ + +/** + * @license + * Knockout JavaScript library v3.2.0 + * (c) Steven Sanderson - http://knockoutjs.com/ + * License: MIT (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * @license + * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5 + * Copyright (c) Steve Sanderson + * MIT license + */ + +!function(){var e,t,r;!function(i){function n(e,t){return C.call(e,t)}function o(e,t){var r,i,n,o,a,s,l,u,c,h,d,p=t&&t.split("/"),m=g.map,f=m&&m["*"]||{};if(e&&"."===e.charAt(0))if(t){for(e=e.split("/"),a=e.length-1,g.nodeIdCompat&&S.test(e[a])&&(e[a]=e[a].replace(S,"")),e=p.slice(0,p.length-1).concat(e),c=0;c0&&(e.splice(c-1,2),c-=2)}e=e.join("/")}else 0===e.indexOf("./")&&(e=e.substring(2));if((p||f)&&m){for(r=e.split("/"),c=r.length;c>0;c-=1){if(i=r.slice(0,c).join("/"),p)for(h=p.length;h>0;h-=1)if(n=m[p.slice(0,h).join("/")],n&&(n=n[i])){o=n,s=c;break}if(o)break;!l&&f&&f[i]&&(l=f[i],u=c)}!o&&l&&(o=l,s=u),o&&(r.splice(0,s,o),e=r.join("/"))}return e}function a(e,t){return function(){var r=E.call(arguments,0);return"string"!=typeof r[0]&&1===r.length&&r.push(null),p.apply(i,r.concat([e,t]))}}function s(e){return function(t){return o(t,e)}}function l(e){return function(t){v[e]=t}}function u(e){if(n(_,e)){var t=_[e];delete _[e],y[e]=!0,d.apply(i,t)}if(!n(v,e)&&!n(y,e))throw new Error("No "+e);return v[e]}function c(e){var t,r=e?e.indexOf("!"):-1;return r>-1&&(t=e.substring(0,r),e=e.substring(r+1,e.length)),[t,e]}function h(e){return function(){return g&&g.config&&g.config[e]||{}}}var d,p,m,f,v={},_={},g={},y={},C=Object.prototype.hasOwnProperty,E=[].slice,S=/\.js$/;m=function(e,t){var r,i=c(e),n=i[0];return e=i[1],n&&(n=o(n,t),r=u(n)),n?e=r&&r.normalize?r.normalize(e,s(t)):o(e,t):(e=o(e,t),i=c(e),n=i[0],e=i[1],n&&(r=u(n))),{f:n?n+"!"+e:e,n:e,pr:n,p:r}},f={require:function(e){return a(e)},exports:function(e){var t=v[e];return"undefined"!=typeof t?t:v[e]={}},module:function(e){return{id:e,uri:"",exports:v[e],config:h(e)}}},d=function(e,t,r,o){var s,c,h,d,p,g,C=[],E=typeof r;if(o=o||e,"undefined"===E||"function"===E){for(t=!t.length&&r.length?["require","exports","module"]:t,p=0;p>>0,u=Math.max(0,Math.min(r,g)),h=[],c=g-u+1,d=[],p=a(),u)for(v=p.progress,f=function(e){d.push(e),--c||(m=f=_,p.reject(d))},m=function(e){h.push(e),--u||(m=f=_,p.resolve(h))},y=0;g>y;++y)y in t&&e(t[y],l,s,v);else p.resolve(h);return p.then(i,n,o)})}function u(e,t,r,i){function n(e){return t?t(e[0]):e[0]}return l(e,1,n,r,i)}function c(e,t,r,i){return v(1,arguments),d(e,g).then(t,r,i)}function h(){return d(arguments,g)}function d(t,r){return e(t,function(t){var i,n,o,s,l,u;if(o=n=t.length>>>0,i=[],u=a(),o)for(s=function(t,n){e(t,r).then(function(e){i[n]=e,--o||u.resolve(i)},u.reject)},l=0;n>l;l++)l in t?s(t[l],l):--o;else u.resolve(i);return u.promise})}function p(t,r){var i=C.call(arguments,1);return e(t,function(t){var n;return n=t.length,i[0]=function(t,i,o){return e(t,function(t){return e(i,function(e){return r(t,e,o,n)})})},y.apply(t,i)})}function m(t,r,i){var n=arguments.length>2;return e(t,function(e){return e=n?i:e,r.resolve(e),e},function(e){return r.reject(e),o(e)},r.progress)}function f(e,t){for(var r,i=0;r=e[i++];)r(t)}function v(e,t){for(var r,i=t.length;i>e;)if(r=t[--i],null!=r&&"function"!=typeof r)throw new Error("arg "+i+" must be a function")}function _(){}function g(e){return e}var y,C,E;return e.defer=a,e.resolve=t,e.reject=r,e.join=h,e.all=c,e.map=d,e.reduce=p,e.any=u,e.some=l,e.chain=m,e.isPromise=s,i.prototype={always:function(e,t){return this.then(e,e,t)},otherwise:function(e){return this.then(E,e)},"yield":function(e){return this.then(function(){return e})},spread:function(e){return this.then(function(t){return c(t,function(t){return e.apply(E,t)})})}},C=[].slice,y=[].reduce||function(e){var t,r,i,n,o;if(o=0,t=Object(this),n=t.length>>>0,r=arguments,r.length<=1)for(;;){if(o in t){i=t[o++];break}if(++o>=n)throw new TypeError}else i=r[1];for(;n>o;++o)o in t&&(i=e(i,t[o],o,t));return i},e})}("function"==typeof r&&r.amd?r:function(e){"object"==typeof exports?module.exports=e():this.when=e()}),r("Core/defined",[],function(){"use strict";var e=function(e){return void 0!==e};return e}),r("Core/defineProperties",["./defined"],function(e){"use strict";var t=function(){try{return"x"in Object.defineProperty({},"x",{})}catch(e){return!1}}(),r=Object.defineProperties;return t&&e(r)||(r=function(e){return e}),r}),r("Core/DeveloperError",["./defined"],function(e){"use strict";var t=function(e){this.name="DeveloperError",this.message=e;var t;try{throw new Error}catch(r){t=r.stack}this.stack=t};return t.prototype.toString=function(){var t=this.name+": "+this.message;return e(this.stack)&&(t+="\n"+this.stack.toString()),t},t.throwInstantiationError=function(){throw new t("This function defines an interface and should not be called directly.")},t}),r("Core/Credit",["./defined","./defineProperties","./DeveloperError"],function(e,t,r){"use strict";var i=0,n={},o=function(t,r,o){var a=e(o),s=e(r),l=e(t);l||s||(t=o),this._text=t,this._imageUrl=r,this._link=o,this._hasLink=a,this._hasImage=s;var u,c=JSON.stringify([t,r,o]);e(n[c])?u=n[c]:(u=i++,n[c]=u),this._id=u};return t(o.prototype,{text:{get:function(){return this._text}},imageUrl:{get:function(){return this._imageUrl}},link:{get:function(){return this._link}},id:{get:function(){return this._id}}}),o.prototype.hasImage=function(){return this._hasImage},o.prototype.hasLink=function(){return this._hasLink},o.equals=function(t,r){return t===r||e(t)&&e(r)&&t._id===r._id},o.prototype.equals=function(e){return o.equals(this,e)},o}),r("Core/freezeObject",["./defined"],function(e){"use strict";var t=Object.freeze;return e(t)||(t=function(e){return e}),t}),r("Core/defaultValue",["./freezeObject"],function(e){"use strict";var t=function(e,t){return void 0!==e?e:t};return t.EMPTY_OBJECT=e({}),t}),r("ThirdParty/mersenne-twister",[],function(){var e=function(e){void 0==e&&(e=(new Date).getTime()),this.N=624,this.M=397,this.MATRIX_A=2567483615,this.UPPER_MASK=2147483648,this.LOWER_MASK=2147483647,this.mt=new Array(this.N),this.mti=this.N+1,this.init_genrand(e)};return e.prototype.init_genrand=function(e){for(this.mt[0]=e>>>0,this.mti=1;this.mti>>30;this.mt[this.mti]=(1812433253*((4294901760&e)>>>16)<<16)+1812433253*(65535&e)+this.mti,this.mt[this.mti]>>>=0}},e.prototype.genrand_int32=function(){var e,t=new Array(0,this.MATRIX_A);if(this.mti>=this.N){var r;for(this.mti==this.N+1&&this.init_genrand(5489),r=0;r>>1^t[1&e];for(;r>>1^t[1&e];e=this.mt[this.N-1]&this.UPPER_MASK|this.mt[0]&this.LOWER_MASK,this.mt[this.N-1]=this.mt[this.M-1]^e>>>1^t[1&e],this.mti=0}return e=this.mt[this.mti++],e^=e>>>11,e^=e<<7&2636928640,e^=e<<15&4022730752,e^=e>>>18,e>>>0},e.prototype.random=function(){return this.genrand_int32()*(1/4294967296)},e}),r("Core/Math",["../ThirdParty/mersenne-twister","./defaultValue","./defined","./DeveloperError"],function(e,t,r,i){"use strict";var n={};n.EPSILON1=.1,n.EPSILON2=.01,n.EPSILON3=.001,n.EPSILON4=1e-4,n.EPSILON5=1e-5,n.EPSILON6=1e-6,n.EPSILON7=1e-7,n.EPSILON8=1e-8,n.EPSILON9=1e-9,n.EPSILON10=1e-10,n.EPSILON11=1e-11,n.EPSILON12=1e-12,n.EPSILON13=1e-13,n.EPSILON14=1e-14,n.EPSILON15=1e-15,n.EPSILON16=1e-16,n.EPSILON17=1e-17,n.EPSILON18=1e-18,n.EPSILON19=1e-19,n.EPSILON20=1e-20,n.GRAVITATIONALPARAMETER=3986004418e5,n.SOLAR_RADIUS=6955e5,n.LUNAR_RADIUS=1737400,n.SIXTY_FOUR_KILOBYTES=65536,n.sign=function(e){return e>0?1:0>e?-1:0},n.signNotZero=function(e){return 0>e?-1:1},n.toSNorm=function(e){return Math.round(255*(.5*n.clamp(e,-1,1)+.5))},n.fromSNorm=function(e){return n.clamp(e,0,255)/255*2-1},n.sinh=function(e){var t=Math.pow(Math.E,e),r=Math.pow(Math.E,-1*e);return.5*(t-r)},n.cosh=function(e){var t=Math.pow(Math.E,e),r=Math.pow(Math.E,-1*e);return.5*(t+r)},n.lerp=function(e,t,r){return(1-r)*e+r*t},n.PI=Math.PI,n.ONE_OVER_PI=1/Math.PI,n.PI_OVER_TWO=.5*Math.PI,n.PI_OVER_THREE=Math.PI/3,n.PI_OVER_FOUR=Math.PI/4,n.PI_OVER_SIX=Math.PI/6,n.THREE_PI_OVER_TWO=3*Math.PI*.5,n.TWO_PI=2*Math.PI,n.ONE_OVER_TWO_PI=1/(2*Math.PI),n.RADIANS_PER_DEGREE=Math.PI/180,n.DEGREES_PER_RADIAN=180/Math.PI,n.RADIANS_PER_ARCSECOND=n.RADIANS_PER_DEGREE/3600,n.toRadians=function(e){return e*n.RADIANS_PER_DEGREE},n.toDegrees=function(e){return e*n.DEGREES_PER_RADIAN},n.convertLongitudeRange=function(e){var t=n.TWO_PI,r=e-Math.floor(e/t)*t;return r<-Math.PI?r+t:r>=Math.PI?r-t:r},n.negativePiToPi=function(e){return n.zeroToTwoPi(e+n.PI)-n.PI},n.zeroToTwoPi=function(e){var t=n.mod(e,n.TWO_PI);return Math.abs(t)n.EPSILON14?n.TWO_PI:t},n.mod=function(e,t){return(e%t+t)%t},n.equalsEpsilon=function(e,r,i,n){n=t(n,i);var o=Math.abs(e-r);return n>=o||o<=i*Math.max(Math.abs(e),Math.abs(r))};var o=[1];n.factorial=function(e){var t=o.length;if(e>=t)for(var r=o[t-1],i=t;e>=i;i++)o.push(r*i);return o[e]},n.incrementWrap=function(e,r,i){return i=t(i,0),++e,e>r&&(e=i),e},n.isPowerOfTwo=function(e){return 0!==e&&0===(e&e-1)},n.nextPowerOfTwo=function(e){return--e,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e,e},n.clamp=function(e,t,r){return t>e?t:e>r?r:e};var a=new e;return n.setRandomNumberSeed=function(t){a=new e(t)},n.nextRandomNumber=function(){return a.random()},n.acosClamped=function(e){return Math.acos(n.clamp(e,-1,1))},n.asinClamped=function(e){return Math.asin(n.clamp(e,-1,1))},n.chordLength=function(e,t){return 2*t*Math.sin(.5*e)},n.fog=function(e,t){var r=e*t;return 1-Math.exp(-(r*r))},n}),r("Core/Cartesian3",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r,i){this.x=e(t,0),this.y=e(r,0),this.z=e(i,0)};o.fromSpherical=function(r,i){t(i)||(i=new o);var n=r.clock,a=r.cone,s=e(r.magnitude,1),l=s*Math.sin(a);return i.x=l*Math.cos(n),i.y=l*Math.sin(n),i.z=s*Math.cos(a),i},o.fromElements=function(e,r,i,n){return t(n)?(n.x=e,n.y=r,n.z=i,n):new o(e,r,i)},o.clone=function(e,r){return t(e)?t(r)?(r.x=e.x,r.y=e.y,r.z=e.z,r):new o(e.x,e.y,e.z):void 0},o.fromCartesian4=o.clone,o.packedLength=3,o.pack=function(t,r,i){i=e(i,0),r[i++]=t.x,r[i++]=t.y,r[i]=t.z},o.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new o),n.x=r[i++],n.y=r[i++],n.z=r[i],n},o.fromArray=o.unpack,o.maximumComponent=function(e){return Math.max(e.x,e.y,e.z)},o.minimumComponent=function(e){return Math.min(e.x,e.y,e.z)},o.minimumByComponent=function(e,t,r){return r.x=Math.min(e.x,t.x),r.y=Math.min(e.y,t.y),r.z=Math.min(e.z,t.z),r},o.maximumByComponent=function(e,t,r){return r.x=Math.max(e.x,t.x),r.y=Math.max(e.y,t.y),r.z=Math.max(e.z,t.z),r},o.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y+e.z*e.z},o.magnitude=function(e){return Math.sqrt(o.magnitudeSquared(e))};var a=new o;o.distance=function(e,t){return o.subtract(e,t,a),o.magnitude(a)},o.distanceSquared=function(e,t){return o.subtract(e,t,a),o.magnitudeSquared(a)},o.normalize=function(e,t){var r=o.magnitude(e);return t.x=e.x/r,t.y=e.y/r,t.z=e.z/r,t},o.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z},o.multiplyComponents=function(e,t,r){return r.x=e.x*t.x,r.y=e.y*t.y,r.z=e.z*t.z,r},o.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r.z=e.z+t.z,r},o.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r.z=e.z-t.z,r},o.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r.z=e.z*t,r},o.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r.z=e.z/t,r},o.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t},o.abs=function(e,t){return t.x=Math.abs(e.x),t.y=Math.abs(e.y),t.z=Math.abs(e.z),t};var s=new o;o.lerp=function(e,t,r,i){return o.multiplyByScalar(t,r,s),i=o.multiplyByScalar(e,1-r,i),o.add(s,i,i)};var l=new o,u=new o;o.angleBetween=function(e,t){o.normalize(e,l),o.normalize(t,u);var r=o.dot(l,u),i=o.magnitude(o.cross(l,u,l));return Math.atan2(i,r)};var c=new o;o.mostOrthogonalAxis=function(e,t){var r=o.normalize(e,c);return o.abs(r,r),t=r.x<=r.y?r.x<=r.z?o.clone(o.UNIT_X,t):o.clone(o.UNIT_Z,t):r.y<=r.z?o.clone(o.UNIT_Y,t):o.clone(o.UNIT_Z,t)},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.x===r.x&&e.y===r.y&&e.z===r.z},o.equalsArray=function(e,t,r){return e.x===t[r]&&e.y===t[r+1]&&e.z===t[r+2]},o.equalsEpsilon=function(e,r,i,o){return e===r||t(e)&&t(r)&&n.equalsEpsilon(e.x,r.x,i,o)&&n.equalsEpsilon(e.y,r.y,i,o)&&n.equalsEpsilon(e.z,r.z,i,o)},o.cross=function(e,t,r){var i=e.x,n=e.y,o=e.z,a=t.x,s=t.y,l=t.z,u=n*l-o*s,c=o*a-i*l,h=i*s-n*a;return r.x=u,r.y=c,r.z=h,r},o.fromDegrees=function(e,t,r,i,a){var s=n.toRadians(e),l=n.toRadians(t);return o.fromRadians(s,l,r,i,a)};var h=new o,d=new o,p=new o(40680631590769,40680631590769,40408299984661.445);return o.fromRadians=function(r,i,n,a,s){n=e(n,0);var l=t(a)?a.radiiSquared:p,u=Math.cos(i);h.x=u*Math.cos(r),h.y=u*Math.sin(r),h.z=Math.sin(i),h=o.normalize(h,h),o.multiplyComponents(l,h,d);var c=Math.sqrt(o.dot(h,d));return d=o.divideByScalar(d,c,d),h=o.multiplyByScalar(h,n,h),t(s)||(s=new o),o.add(d,h,s)},o.fromDegreesArray=function(e,t,r){for(var i=new Array(e.length),a=0;aa;a+=2){var s=e[a],l=e[a+1];i[a/2]=o.fromRadians(s,l,0,r,i[a/2])}return i},o.fromDegreesArrayHeights=function(e,t,r){for(var i=new Array(e.length),a=0;aa;a+=3){var s=e[a],l=e[a+1],u=e[a+2];i[a/3]=o.fromRadians(s,l,u,r,i[a/3])}return i},o.ZERO=i(new o(0,0,0)),o.UNIT_X=i(new o(1,0,0)),o.UNIT_Y=i(new o(0,1,0)),o.UNIT_Z=i(new o(0,0,1)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t,r){return o.equalsEpsilon(this,e,t,r)},o.prototype.toString=function(){return"("+this.x+", "+this.y+", "+this.z+")"},o}),r("Core/Cartographic",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r,i){this.longitude=e(t,0),this.latitude=e(r,0),this.height=e(i,0)};return o.fromRadians=function(r,i,n,a){return n=e(n,0),t(a)?(a.longitude=r,a.latitude=i,a.height=n,a):new o(r,i,n)},o.fromDegrees=function(e,t,r,i){return e=n.toRadians(e),t=n.toRadians(t),o.fromRadians(e,t,r,i)},o.clone=function(e,r){return t(e)?t(r)?(r.longitude=e.longitude,r.latitude=e.latitude,r.height=e.height,r):new o(e.longitude,e.latitude,e.height):void 0},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.longitude===r.longitude&&e.latitude===r.latitude&&e.height===r.height},o.equalsEpsilon=function(e,r,i){return e===r||t(e)&&t(r)&&Math.abs(e.longitude-r.longitude)<=i&&Math.abs(e.latitude-r.latitude)<=i&&Math.abs(e.height-r.height)<=i},o.ZERO=i(new o(0,0,0)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t){return o.equalsEpsilon(this,e,t)},o.prototype.toString=function(){return"("+this.longitude+", "+this.latitude+", "+this.height+")"},o}),r("Core/Ellipsoid",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n,o,a,s){"use strict";function l(t,i,n,o){i=r(i,0),n=r(n,0),o=r(o,0),t._radii=new e(i,n,o),t._radiiSquared=new e(i*i,n*n,o*o),t._radiiToTheFourth=new e(i*i*i*i,n*n*n*n,o*o*o*o),t._oneOverRadii=new e(0===i?0:1/i,0===n?0:1/n,0===o?0:1/o),t._oneOverRadiiSquared=new e(0===i?0:1/(i*i),0===n?0:1/(n*n),0===o?0:1/(o*o)),t._minimumRadius=Math.min(i,n,o),t._maximumRadius=Math.max(i,n,o),t._centerToleranceSquared=s.EPSILON1}var u=function(e,t,r){this._radii=void 0,this._radiiSquared=void 0,this._radiiToTheFourth=void 0,this._oneOverRadii=void 0,this._oneOverRadiiSquared=void 0,this._minimumRadius=void 0,this._maximumRadius=void 0,this._centerToleranceSquared=void 0,l(this,e,t,r)};n(u.prototype,{radii:{get:function(){return this._radii}},radiiSquared:{get:function(){return this._radiiSquared}},radiiToTheFourth:{get:function(){return this._radiiToTheFourth}},oneOverRadii:{get:function(){return this._oneOverRadii}},oneOverRadiiSquared:{get:function(){return this._oneOverRadiiSquared}},minimumRadius:{get:function(){return this._minimumRadius}},maximumRadius:{get:function(){return this._maximumRadius}}}),u.clone=function(t,r){if(!i(t))return void 0;var n=t._radii;return i(r)?(e.clone(n,r._radii),e.clone(t._radiiSquared,r._radiiSquared),e.clone(t._radiiToTheFourth,r._radiiToTheFourth),e.clone(t._oneOverRadii,r._oneOverRadii),e.clone(t._oneOverRadiiSquared,r._oneOverRadiiSquared),r._minimumRadius=t._minimumRadius,r._maximumRadius=t._maximumRadius,r._centerToleranceSquared=t._centerToleranceSquared,r):new u(n.x,n.y,n.z)},u.fromCartesian3=function(e,t){return i(t)||(t=new u),i(e)?(l(t,e.x,e.y,e.z),t):t},u.WGS84=a(new u(6378137,6378137,6356752.314245179)),u.UNIT_SPHERE=a(new u(1,1,1)),u.MOON=a(new u(s.LUNAR_RADIUS,s.LUNAR_RADIUS,s.LUNAR_RADIUS)),u.prototype.clone=function(e){return u.clone(this,e)},u.packedLength=e.packedLength,u.pack=function(t,i,n){n=r(n,0),e.pack(t._radii,i,n)},u.unpack=function(t,i,n){i=r(i,0);var o=e.unpack(t,i);return u.fromCartesian3(o,n)},u.prototype.geocentricSurfaceNormal=e.normalize,u.prototype.geodeticSurfaceNormalCartographic=function(t,r){var n=t.longitude,o=t.latitude,a=Math.cos(o),s=a*Math.cos(n),l=a*Math.sin(n),u=Math.sin(o);return i(r)||(r=new e),r.x=s,r.y=l,r.z=u,e.normalize(r,r)},u.prototype.geodeticSurfaceNormal=function(t,r){return i(r)||(r=new e),r=e.multiplyComponents(t,this._oneOverRadiiSquared,r),e.normalize(r,r)};var c=new e,h=new e;u.prototype.cartographicToCartesian=function(t,r){var n=c,o=h;this.geodeticSurfaceNormalCartographic(t,n),e.multiplyComponents(this._radiiSquared,n,o);var a=Math.sqrt(e.dot(n,o));return e.divideByScalar(o,a,o),e.multiplyByScalar(n,t.height,n),i(r)||(r=new e),e.add(o,n,r)},u.prototype.cartographicArrayToCartesianArray=function(e,t){var r=e.length;i(t)?t.length=r:t=new Array(r);for(var n=0;r>n;n++)t[n]=this.cartographicToCartesian(e[n],t[n]);return t};var d=new e,p=new e,m=new e;u.prototype.cartesianToCartographic=function(r,n){var o=this.scaleToGeodeticSurface(r,p);if(!i(o))return void 0;var a=this.geodeticSurfaceNormal(o,d),l=e.subtract(r,o,m),u=Math.atan2(a.y,a.x),c=Math.asin(a.z),h=s.sign(e.dot(l,r))*e.magnitude(l);return i(n)?(n.longitude=u,n.latitude=c,n.height=h,n):new t(u,c,h)},u.prototype.cartesianArrayToCartographicArray=function(e,t){var r=e.length;i(t)?t.length=r:t=new Array(r);for(var n=0;r>n;++n)t[n]=this.cartesianToCartographic(e[n],t[n]);return t};var f=new e,v=new e;return u.prototype.scaleToGeodeticSurface=function(t,r){var n=t.x,o=t.y,a=t.z,l=this._oneOverRadii,u=l.x,c=l.y,h=l.z,d=n*n*u*u,p=o*o*c*c,m=a*a*h*h,_=d+p+m,g=Math.sqrt(1/_),y=e.multiplyByScalar(t,g,f);if(_s.EPSILON12);return i(r)?(r.x=n*P,r.y=o*A,r.z=a*I,r):new e(n*P,o*A,a*I)},u.prototype.scaleToGeocentricSurface=function(t,r){i(r)||(r=new e);var n=t.x,o=t.y,a=t.z,s=this._oneOverRadiiSquared,l=1/Math.sqrt(n*n*s.x+o*o*s.y+a*a*s.z);return e.multiplyByScalar(t,l,r)},u.prototype.transformPositionToScaledSpace=function(t,r){return i(r)||(r=new e),e.multiplyComponents(t,this._oneOverRadii,r)},u.prototype.transformPositionFromScaledSpace=function(t,r){return i(r)||(r=new e),e.multiplyComponents(t,this._radii,r)},u.prototype.equals=function(t){return this===t||i(t)&&e.equals(this._radii,t._radii)},u.prototype.toString=function(){return this._radii.toString()},u}),r("Core/Event",["./defined","./defineProperties","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this._listeners=[],this._scopes=[],this._toRemove=[],this._insideRaiseEvent=!1};return t(i.prototype,{numberOfListeners:{get:function(){return this._listeners.length-this._toRemove.length}}}),i.prototype.addEventListener=function(e,t){this._listeners.push(e),this._scopes.push(t);var r=this;return function(){r.removeEventListener(e,t)}},i.prototype.removeEventListener=function(e,t){for(var r=this._listeners,i=this._scopes,n=-1,o=0;ot;t++){var o=r[t];e(o)&&r[t].apply(i[t],arguments)}var a=this._toRemove;for(n=a.length,t=0;n>t;t++){var s=a[t];r.splice(s,1),i.splice(s,1)}a.length=0,this._insideRaiseEvent=!1},i}),r("Core/Cartesian2",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r){this.x=e(t,0),this.y=e(r,0)};o.fromElements=function(e,r,i){return t(i)?(i.x=e,i.y=r,i):new o(e,r)},o.clone=function(e,r){return t(e)?t(r)?(r.x=e.x,r.y=e.y,r):new o(e.x,e.y):void 0},o.fromCartesian3=o.clone,o.fromCartesian4=o.clone,o.packedLength=2,o.pack=function(t,r,i){i=e(i,0),r[i++]=t.x,r[i]=t.y},o.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new o),n.x=r[i++],n.y=r[i],n},o.fromArray=o.unpack,o.maximumComponent=function(e){return Math.max(e.x,e.y)},o.minimumComponent=function(e){return Math.min(e.x,e.y)},o.minimumByComponent=function(e,t,r){return r.x=Math.min(e.x,t.x),r.y=Math.min(e.y,t.y),r},o.maximumByComponent=function(e,t,r){return r.x=Math.max(e.x,t.x),r.y=Math.max(e.y,t.y),r},o.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y},o.magnitude=function(e){return Math.sqrt(o.magnitudeSquared(e))};var a=new o;o.distance=function(e,t){return o.subtract(e,t,a),o.magnitude(a)},o.distanceSquared=function(e,t){return o.subtract(e,t,a),o.magnitudeSquared(a)},o.normalize=function(e,t){var r=o.magnitude(e);return t.x=e.x/r,t.y=e.y/r,t},o.dot=function(e,t){return e.x*t.x+e.y*t.y},o.multiplyComponents=function(e,t,r){return r.x=e.x*t.x,r.y=e.y*t.y,r},o.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r},o.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r},o.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r},o.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r},o.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t},o.abs=function(e,t){return t.x=Math.abs(e.x),t.y=Math.abs(e.y),t};var s=new o;o.lerp=function(e,t,r,i){return o.multiplyByScalar(t,r,s),i=o.multiplyByScalar(e,1-r,i),o.add(s,i,i)};var l=new o,u=new o;o.angleBetween=function(e,t){return o.normalize(e,l),o.normalize(t,u),n.acosClamped(o.dot(l,u))};var c=new o;return o.mostOrthogonalAxis=function(e,t){var r=o.normalize(e,c);return o.abs(r,r),t=r.x<=r.y?o.clone(o.UNIT_X,t):o.clone(o.UNIT_Y,t)},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.x===r.x&&e.y===r.y},o.equalsArray=function(e,t,r){return e.x===t[r]&&e.y===t[r+1]},o.equalsEpsilon=function(e,r,i,o){return e===r||t(e)&&t(r)&&n.equalsEpsilon(e.x,r.x,i,o)&&n.equalsEpsilon(e.y,r.y,i,o)},o.ZERO=i(new o(0,0)),o.UNIT_X=i(new o(1,0)),o.UNIT_Y=i(new o(0,1)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t,r){return o.equalsEpsilon(this,e,t,r)},o.prototype.toString=function(){return"("+this.x+", "+this.y+")"},o}),r("Core/GeographicProjection",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){this._ellipsoid=r(e,a.WGS84),this._semimajorAxis=this._ellipsoid.maximumRadius,this._oneOverSemimajorAxis=1/this._semimajorAxis};return n(s.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),s.prototype.project=function(t,r){var n=this._semimajorAxis,o=t.longitude*n,a=t.latitude*n,s=t.height;return i(r)?(r.x=o,r.y=a,r.z=s,r):new e(o,a,s)},s.prototype.unproject=function(e,r){var n=this._oneOverSemimajorAxis,o=e.x*n,a=e.y*n,s=e.z;return i(r)?(r.longitude=o,r.latitude=a,r.height=s,r):new t(o,a,s)},s}),r("Core/Rectangle",["./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./freezeObject","./Math"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,r,i,n){this.west=t(e,0),this.south=t(r,0),this.east=t(i,0),this.north=t(n,0)};i(l.prototype,{width:{get:function(){return l.computeWidth(this)}},height:{get:function(){return l.computeHeight(this)}}}),l.packedLength=4,l.pack=function(e,r,i){i=t(i,0),r[i++]=e.west,r[i++]=e.south,r[i++]=e.east,r[i]=e.north},l.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new l),n.west=e[i++],n.south=e[i++],n.east=e[i++],n.north=e[i],n},l.computeWidth=function(e){var t=e.east,r=e.west;return r>t&&(t+=s.TWO_PI),t-r},l.computeHeight=function(e){return e.north-e.south},l.fromDegrees=function(e,i,n,o,a){return e=s.toRadians(t(e,0)),i=s.toRadians(t(i,0)),n=s.toRadians(t(n,0)),o=s.toRadians(t(o,0)),r(a)?(a.west=e,a.south=i,a.east=n,a.north=o,a):new l(e,i,n,o)},l.fromCartographicArray=function(e,t){for(var i=Number.MAX_VALUE,n=-Number.MAX_VALUE,o=Number.MAX_VALUE,a=-Number.MAX_VALUE,s=0,u=e.length;u>s;s++){var c=e[s];i=Math.min(i,c.longitude),n=Math.max(n,c.longitude),o=Math.min(o,c.latitude),a=Math.max(a,c.latitude)}return r(t)?(t.west=i,t.south=o,t.east=n,t.north=a,t):new l(i,o,n,a)},l.clone=function(e,t){return r(e)?r(t)?(t.west=e.west,t.south=e.south,t.east=e.east,t.north=e.north,t):new l(e.west,e.south,e.east,e.north):void 0},l.prototype.clone=function(e){return l.clone(this,e)},l.prototype.equals=function(e){return l.equals(this,e)},l.equals=function(e,t){return e===t||r(e)&&r(t)&&e.west===t.west&&e.south===t.south&&e.east===t.east&&e.north===t.north},l.prototype.equalsEpsilon=function(e,t){return r(e)&&Math.abs(this.west-e.west)<=t&&Math.abs(this.south-e.south)<=t&&Math.abs(this.east-e.east)<=t&&Math.abs(this.north-e.north)<=t},l.validate=function(e){},l.southwest=function(t,i){return r(i)?(i.longitude=t.west,i.latitude=t.south,i.height=0,i):new e(t.west,t.south)},l.northwest=function(t,i){return r(i)?(i.longitude=t.west,i.latitude=t.north,i.height=0,i):new e(t.west,t.north)},l.northeast=function(t,i){return r(i)?(i.longitude=t.east,i.latitude=t.north,i.height=0,i):new e(t.east,t.north)},l.southeast=function(t,i){return r(i)?(i.longitude=t.east,i.latitude=t.south,i.height=0,i):new e(t.east,t.south)},l.center=function(t,i){var n=t.east,o=t.west;o>n&&(n+=s.TWO_PI);var a=s.negativePiToPi(.5*(o+n)),l=.5*(t.south+t.north);return r(i)?(i.longitude=a,i.latitude=l,i.height=0,i):new e(a,l)},l.intersection=function(e,t,i){var n=e.east,o=e.west,a=t.east,u=t.west;o>n&&a>0?n+=s.TWO_PI:u>a&&n>0&&(a+=s.TWO_PI),o>n&&0>u?u+=s.TWO_PI:u>a&&0>o&&(o+=s.TWO_PI);var c=s.negativePiToPi(Math.max(o,u)),h=s.negativePiToPi(Math.min(n,a));if((e.west=h)return void 0;var d=Math.max(e.south,t.south),p=Math.min(e.north,t.north);return d>=p?void 0:r(i)?(i.west=c,i.south=d,i.east=h,i.north=p,i):new l(c,d,h,p)},l.contains=function(e,t){var r=t.longitude,i=t.latitude,n=e.west,o=e.east;return n>o&&(o+=s.TWO_PI,0>r&&(r+=s.TWO_PI)),(r>n||s.equalsEpsilon(r,n,s.EPSILON14))&&(o>r||s.equalsEpsilon(r,o,s.EPSILON14))&&i>=e.south&&i<=e.north};var u=new e;return l.subsample=function(e,i,n,a){i=t(i,o.WGS84),n=t(n,0),r(a)||(a=[]);var c=0,h=e.north,d=e.south,p=e.east,m=e.west,f=u;f.height=n,f.longitude=m,f.latitude=h,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.longitude=p,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.latitude=d,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.longitude=m,a[c]=i.cartographicToCartesian(f,a[c]),c++,0>h?f.latitude=h:d>0?f.latitude=d:f.latitude=0;for(var v=1;8>v;++v)f.longitude=-Math.PI+v*s.PI_OVER_TWO,l.contains(e,f)&&(a[c]=i.cartographicToCartesian(f,a[c]),c++);return 0===f.latitude&&(f.longitude=m,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.longitude=p,a[c]=i.cartographicToCartesian(f,a[c]),c++),a.length=c,a},l.MAX_VALUE=a(new l(-Math.PI,-s.PI_OVER_TWO,Math.PI,s.PI_OVER_TWO)),l}),r("Core/GeographicTilingScheme",["./Cartesian2","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./GeographicProjection","./Math","./Rectangle"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(e){e=t(e,{}),this._ellipsoid=t(e.ellipsoid,o.WGS84),this._rectangle=t(e.rectangle,l.MAX_VALUE),this._projection=new a(this._ellipsoid),this._numberOfLevelZeroTilesX=t(e.numberOfLevelZeroTilesX,2),this._numberOfLevelZeroTilesY=t(e.numberOfLevelZeroTilesY,1)};return i(u.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},rectangle:{get:function(){return this._rectangle}},projection:{get:function(){return this._projection}}}),u.prototype.getNumberOfXTilesAtLevel=function(e){return this._numberOfLevelZeroTilesX<=a&&(p=a-1);var m=(o.north-t.latitude)/h|0;return m>=u&&(m=u-1),r(n)?(n.x=p,n.y=m,n):new e(p,m)},u}),r("Core/getImagePixels",["./defined"],function(e){"use strict";var t={},r=function(r,i,n){e(i)||(i=r.width),e(n)||(n=r.height);var o=t[i];e(o)||(o={},t[i]=o);var a=o[n];if(!e(a)){var s=document.createElement("canvas");s.width=i,s.height=n,a=s.getContext("2d"),a.globalCompositeOperation="copy",o[n]=a}return a.drawImage(r,0,0,i,n),a.getImageData(0,0,i,n).data};return r}),r("Core/HeightmapTessellator",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./freezeObject","./Math","./Rectangle"],function(e,t,r,i,n,o,a,s){"use strict";var l={};return l.DEFAULT_STRUCTURE=o({heightScale:1,heightOffset:0,elementsPerHeight:1,stride:1,elementMultiplier:256,isBigEndian:!1}),l.computeVertices=function(i){var o,u,c,h,d=Math.cos,p=Math.sin,m=Math.sqrt,f=Math.atan,v=Math.exp,_=a.PI_OVER_TWO,g=a.toRadians,y=i.vertices,C=i.heightmap,E=i.width,S=i.height,w=i.skirtHeight,T=t(i.isGeographic,!0),b=t(i.ellipsoid,n.WGS84),x=1/b.maximumRadius,P=i.nativeRectangle,A=i.rectangle;r(A)?(o=A.west,u=A.south,c=A.east,h=A.north):T?(o=g(P.west),u=g(P.south),c=g(P.east),h=g(P.north)):(o=P.west*x,u=_-2*f(v(-P.south*x)),c=P.east*x,h=_-2*f(v(-P.north*x)));var I=t(i.relativeToCenter,e.ZERO),M=t(i.structure,l.DEFAULT_STRUCTURE),D=t(M.heightScale,l.DEFAULT_STRUCTURE.heightScale),R=t(M.heightOffset,l.DEFAULT_STRUCTURE.heightOffset),O=t(M.elementsPerHeight,l.DEFAULT_STRUCTURE.elementsPerHeight),N=t(M.stride,l.DEFAULT_STRUCTURE.stride),L=t(M.elementMultiplier,l.DEFAULT_STRUCTURE.elementMultiplier),F=t(M.isBigEndian,l.DEFAULT_STRUCTURE.isBigEndian),B=s.computeWidth(P)/(E-1),V=s.computeHeight(P)/(S-1),z=b.radiiSquared,k=z.x,U=z.y,G=z.z,W=0,H=65536,q=-65536,j=0,Y=S,X=0,Z=E;w>0&&(--j,++Y,--X,++Z);for(var K=j;Y>K;++K){var J=K;0>J&&(J=0),J>=S&&(J=S-1);var Q=P.north-V*J;Q=T?g(Q):_-2*f(v(-Q*x));for(var $=d(Q),ee=p(Q),te=G*ee,re=(Q-u)/(h-u),ie=X;Z>ie;++ie){var ne=ie;0>ne&&(ne=0),ne>=E&&(ne=E-1);var oe=P.west+B*ne;T?oe=g(oe):oe*=x;var ae,se=J*E*N+ne*N;if(1===O)ae=C[se];else{ae=0;var le;if(F)for(le=0;O>le;++le)ae=ae*L+C[se+le];else for(le=O-1;le>=0;--le)ae=ae*L+C[se+le]}ae=ae*D+R,q=Math.max(q,ae),H=Math.min(H,ae),(ie!==ne||K!==J)&&(ae-=w);var ue=$*d(oe),ce=$*p(oe),he=k*ue,de=U*ce,pe=m(he*ue+de*ce+te*ee),me=1/pe,fe=he*me,ve=de*me,_e=te*me;y[W++]=fe+ue*ae-I.x,y[W++]=ve+ce*ae-I.y,y[W++]=_e+ee*ae-I.z,y[W++]=ae;var ge=(oe-o)/(c-o);y[W++]=ge,y[W++]=re}}return{maximumHeight:q,minimumHeight:H}},l}),r("ThirdParty/Uri",[],function(){function e(t){if(t instanceof e)this.scheme=t.scheme,this.authority=t.authority,this.path=t.path,this.query=t.query,this.fragment=t.fragment;else if(t){var r=i.exec(t);this.scheme=r[1],this.authority=r[2],this.path=r[3],this.query=r[4],this.fragment=r[5]}}function t(e){var t=unescape(e);return o.test(t)?t:e.toUpperCase()}function r(e,t,r,i){return(t||"")+r.toLowerCase()+(i||"")}e.prototype.scheme=null,e.prototype.authority=null,e.prototype.path="",e.prototype.query=null,e.prototype.fragment=null;var i=new RegExp("^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$");e.prototype.getScheme=function(){return this.scheme},e.prototype.getAuthority=function(){return this.authority},e.prototype.getPath=function(){return this.path},e.prototype.getQuery=function(){return this.query},e.prototype.getFragment=function(){return this.fragment},e.prototype.isAbsolute=function(){return!!this.scheme&&!this.fragment},e.prototype.isSameDocumentAs=function(e){return e.scheme==this.scheme&&e.authority==this.authority&&e.path==this.path&&e.query==this.query},e.prototype.equals=function(e){return this.isSameDocumentAs(e)&&e.fragment==this.fragment},e.prototype.normalize=function(){this.removeDotSegments(),this.scheme&&(this.scheme=this.scheme.toLowerCase()),this.authority&&(this.authority=this.authority.replace(a,r).replace(n,t)),this.path&&(this.path=this.path.replace(n,t)),this.query&&(this.query=this.query.replace(n,t)),this.fragment&&(this.fragment=this.fragment.replace(n,t))};var n=/%[0-9a-z]{2}/gi,o=/[a-zA-Z0-9\-\._~]/,a=/(.*@)?([^@:]*)(:.*)?/;return e.prototype.resolve=function(t){var r=new e;return this.scheme?(r.scheme=this.scheme,r.authority=this.authority,r.path=this.path,r.query=this.query):(r.scheme=t.scheme,this.authority?(r.authority=this.authority,r.path=this.path,r.query=this.query):(r.authority=t.authority,""==this.path?(r.path=t.path,r.query=this.query||t.query):("/"==this.path.charAt(0)?(r.path=this.path,r.removeDotSegments()):(t.authority&&""==t.path?r.path="/"+this.path:r.path=t.path.substring(0,t.path.lastIndexOf("/")+1)+this.path,r.removeDotSegments()),r.query=this.query))),r.fragment=this.fragment,r},e.prototype.removeDotSegments=function(){var e,t=this.path.split("/"),r=[],i=""==t[0];i&&t.shift();for(""==t[0]?t.shift():null;t.length;)e=t.shift(),".."==e?r.pop():"."!=e&&r.push(e);("."==e||".."==e)&&r.push(""),i&&r.unshift(""),this.path=r.join("/")},e.prototype.toString=function(){var e="";return this.scheme&&(e+=this.scheme+":"),this.authority&&(e+="//"+this.authority),e+=this.path,this.query&&(e+="?"+this.query),this.fragment&&(e+="#"+this.fragment),e},e}),r("Core/buildModuleUrl",["../ThirdParty/Uri","./defined","./DeveloperError","require"],function(e,t,r,i){"use strict";function n(){for(var e=document.getElementsByTagName("script"),t=0,r=e.length;r>t;++t){var i=e[t].getAttribute("src"),n=h.exec(i);if(null!==n)return n[1]}return void 0}function o(){if(t(l))return l;var i;if(i="undefined"!=typeof CESIUM_BASE_URL?CESIUM_BASE_URL:n(),!t(i))throw new r("Unable to determine Cesium base URL automatically, try defining a global variable called CESIUM_BASE_URL.");return l=new e(i).resolve(new e(document.location.href))}function a(e){return i.toUrl("../"+e)}function s(t){return new e(t).resolve(o()).toString()}var l,u,c,h=/((?:.*\/)|^)cesium[\w-]*\.js(?:\W|$)/i,d=function(e){t(u)||(u=t(i.toUrl)?a:s),t(c)||(c=document.createElement("a"));var r=u(e);return c.href=r,c.href=c.href,c.href};return d._cesiumScriptRegex=h,d.setBaseUrl=function(t){l=new e(t).resolve(new e(document.location.href))},d}),r("Core/destroyObject",["./defaultValue","./DeveloperError"],function(e,t){"use strict";function r(){return!0}var i=function(i,n){function o(){throw new t(n)}n=e(n,"This object was destroyed, i.e., destroy() was called.");for(var a in i)"function"==typeof i[a]&&(i[a]=o);return void(i.isDestroyed=r)};return i}),r("Core/isCrossOriginUrl",["./defined"],function(e){"use strict";var t,r=function(r){e(t)||(t=document.createElement("a")),t.href=window.location.href;var i=t.host,n=t.protocol;return t.href=r,t.href=t.href,n!==t.protocol||i!==t.host};return r}),r("Core/RuntimeError",["./defined"],function(e){"use strict";var t=function(e){this.name="RuntimeError",this.message=e;var t;try{throw new Error}catch(r){t=r.stack}this.stack=t};return t.prototype.toString=function(){var t=this.name+": "+this.message;return e(this.stack)&&(t+="\n"+this.stack.toString()),t},t}),r("Core/TaskProcessor",["../ThirdParty/Uri","../ThirdParty/when","./buildModuleUrl","./defaultValue","./defined","./destroyObject","./DeveloperError","./isCrossOriginUrl","./RuntimeError","require"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(){if(!n(v._canTransferArrayBuffer)){var e=new Worker(d("Workers/transferTypedArrayTest.js"));e.postMessage=i(e.webkitPostMessage,e.postMessage);var r=99,o=new Int8Array([r]);try{e.postMessage({array:o},[o.buffer])}catch(a){return v._canTransferArrayBuffer=!1,v._canTransferArrayBuffer}var s=t.defer();e.onmessage=function(t){var i=t.data.array,o=n(i)&&i[0]===r;s.resolve(o),e.terminate(),v._canTransferArrayBuffer=o},v._canTransferArrayBuffer=s.promise}return v._canTransferArrayBuffer}function h(e,t){--e._activeTasks;var r=t.id;if(n(r)){var i=e._deferreds,o=i[r];if(n(t.error)){var s=t.error;"RuntimeError"===s.name?(s=new l(t.error.message),s.stack=t.error.stack):"DeveloperError"===s.name&&(s=new a(t.error.message),s.stack=t.error.stack),o.reject(s)}else o.resolve(t.result);delete i[r]}}function d(e){var t=r(e);if(s(t)){var i,n='importScripts("'+t+'");';try{i=new Blob([n],{type:"application/javascript"})}catch(o){var a=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,l=new a;l.append(n),i=l.getBlob("application/javascript")}var u=window.URL||window.webkitURL;t=u.createObjectURL(i)}return t}function p(){return n(f)||(f=d("Workers/cesiumWorkerBootstrapper.js")),f}function m(t){var o=new Worker(p());o.postMessage=i(o.webkitPostMessage,o.postMessage);var a={loaderConfig:{},workerModule:v._workerModulePrefix+t._workerName};if(n(v._loaderConfig))a.loaderConfig=v._loaderConfig;else if(n(u.toUrl)){var s=new e("..").resolve(new e(r("Workers/cesiumWorkerBootstrapper.js"))).toString();a.loaderConfig.baseUrl=s}else a.loaderConfig.paths={Workers:r("Workers")};return o.postMessage(a),o.onmessage=function(e){h(t,e.data)},o}var f,v=function(e,t){this._workerName=e,this._maximumActiveTasks=i(t,5),this._activeTasks=0,this._deferreds={},this._nextID=0},_=[];return v.prototype.scheduleTask=function(e,r){if(n(this._worker)||(this._worker=m(this)),this._activeTasks>=this._maximumActiveTasks)return void 0;++this._activeTasks;var i=this;return t(c(),function(o){n(r)?o||(r.length=0):r=_;var a=i._nextID++,s=t.defer();return i._deferreds[a]=s,i._worker.postMessage({id:a,parameters:e,canTransferArrayBuffer:o},r),s.promise})},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){return n(this._worker)&&this._worker.terminate(),o(this)},v._defaultWorkerModulePrefix="Workers/",v._workerModulePrefix=v._defaultWorkerModulePrefix,v._loaderConfig=void 0,v._canTransferArrayBuffer=void 0,v}),r("Core/TerrainMesh",["../Core/defaultValue"],function(e){"use strict";var t=function(t,r,i,n,o,a,s,l,u){this.center=t,this.vertices=r,this.stride=e(l,6),this.indices=i,this.minimumHeight=n,this.maximumHeight=o,this.boundingSphere3D=a,this.occludeePointInScaledSpace=s,this.orientedBoundingBox=u};return t}),r("Core/TerrainProvider",["./defined","./defineProperties","./DeveloperError","./Math"],function(e,t,r,i){"use strict";var n=function(){r.throwInstantiationError()};t(n.prototype,{errorEvent:{get:r.throwInstantiationError},credit:{get:r.throwInstantiationError},tilingScheme:{get:r.throwInstantiationError},ready:{get:r.throwInstantiationError},readyPromise:{get:r.throwInstantiationError},hasWaterMask:{get:r.throwInstantiationError},hasVertexNormals:{get:r.throwInstantiationError}});var o=[];return n.getRegularGridIndices=function(t,r){var i=o[t];e(i)||(o[t]=i=[]);var n=i[r];if(!e(n)){n=i[r]=new Uint16Array((t-1)*(r-1)*6);for(var a=0,s=0,l=0;r-1>l;++l){for(var u=0;t-1>u;++u){var c=a,h=c+t,d=h+1,p=c+1;n[s++]=c,n[s++]=h,n[s++]=p,n[s++]=p,n[s++]=h,n[s++]=d,++a}++a}}return n},n.heightmapTerrainQuality=.25,n.getEstimatedLevelZeroGeometricErrorForAHeightmap=function(e,t,r){return 2*e.maximumRadius*Math.PI*n.heightmapTerrainQuality/(t*r)},n.prototype.requestTileGeometry=r.throwInstantiationError,n.prototype.getLevelMaximumGeometricError=r.throwInstantiationError,n.prototype.getTileDataAvailable=r.throwInstantiationError,n}),r("Core/HeightmapTerrainData",["../ThirdParty/when","./defaultValue","./defined","./defineProperties","./DeveloperError","./GeographicTilingScheme","./HeightmapTessellator","./Math","./Rectangle","./TaskProcessor","./TerrainMesh","./TerrainProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t,r,i,n,o,a,s){var l=1,u=e._width,c=e._height,h=o*(u-1),d=h+u-1,p=a*(c-1),m=p+c-1,f=1<1)for(C=w;T>=C;++C)for(g=E;S>=g;++g)for(var N=(C*u+g)*O,L=0;O>L;++L)D[R++]=P[N+L];else for(C=w;T>=C;++C)for(g=E;S>=g;++g)D[R++]=P[C*u+g];return new y({buffer:D,width:b,height:x,childTileMask:0,structure:e._structure,createdByUpsampling:!0})}function p(e,t,r,i,n,o,a,l){var u,c,h,d,p=e._width,v=e._height,_=e._structure,C=_.stride,E=e._buffer,S=new E.constructor(p*v*C),w=t.tileXYToRectangle(r,i,n),T=t.tileXYToRectangle(o,a,l);if(C>1){var b=_.elementsPerHeight,x=_.elementMultiplier,P=_.isBigEndian,A=Math.pow(x,b-1);for(c=0;v>c;++c)for(h=s.lerp(T.north,T.south,c/(v-1)),u=0;p>u;++u){d=s.lerp(T.west,T.east,u/(p-1));var I=f(E,b,x,C,P,w,p,v,d,h);g(S,b,x,A,C,P,c*p+u,I)}}else for(c=0;v>c;++c)for(h=s.lerp(T.north,T.south,c/(v-1)),u=0;p>u;++u)d=s.lerp(T.west,T.east,u/(p-1)),S[c*p+u]=m(E,w,p,v,d,h);return new y({buffer:S,width:p,height:v,childTileMask:0,structure:e._structure,createdByUpsampling:!0})}function m(e,t,r,i,n,o){var a=(n-t.west)*(r-1)/(t.east-t.west),s=(o-t.south)*(i-1)/(t.north-t.south),l=0|a,u=l+1;u>=r&&(u=r-1,l=r-2);var c=0|s,h=c+1;h>=i&&(h=i-1,c=i-2);var d=a-l,p=s-c;c=i-1-c,h=i-1-h;var m=e[c*r+l],f=e[c*r+u],_=e[h*r+l],g=e[h*r+u];return v(d,p,m,f,_,g)}function f(e,t,r,i,n,o,a,s,l,u){var c=(l-o.west)*(a-1)/(o.east-o.west),h=(u-o.south)*(s-1)/(o.north-o.south),d=0|c,p=d+1;p>=a&&(p=a-1,d=a-2);var m=0|h,f=m+1;f>=s&&(f=s-1,m=s-2);var g=c-d,y=h-m;m=s-1-m,f=s-1-f;var C=_(e,t,r,i,n,m*a+d),E=_(e,t,r,i,n,m*a+p),S=_(e,t,r,i,n,f*a+d),w=_(e,t,r,i,n,f*a+p);return v(g,y,C,E,S,w)}function v(e,t,r,i,n,o){return e>t?r+e*(i-r)+t*(o-i):r+e*(o-n)+t*(n-r)}function _(e,t,r,i,n,o){o*=i;var a,s=0;if(n)for(a=0;t>a;++a)s=s*r+e[o+a];else for(a=t-1;a>=0;--a)s=s*r+e[o+a];return s}function g(e,t,r,i,n,o,a,s){a*=n;var l;if(o)for(l=0;t>l;++l)e[a+l]=s/i|0,s-=e[a+l]*i,i/=r;else for(l=t-1;l>=0;--l)e[a+l]=s/i|0,s-=e[a+l]*i,i/=r}var y=function(e){this._buffer=e.buffer,this._width=e.width,this._height=e.height,this._childTileMask=t(e.childTileMask,15);var i=a.DEFAULT_STRUCTURE,n=e.structure;r(n)?n!==i&&(n.heightScale=t(n.heightScale,i.heightScale),n.heightOffset=t(n.heightOffset,i.heightOffset),n.elementsPerHeight=t(n.elementsPerHeight,i.elementsPerHeight),n.stride=t(n.stride,i.stride),n.elementMultiplier=t(n.elementMultiplier,i.elementMultiplier),n.isBigEndian=t(n.isBigEndian,i.isBigEndian)):n=i,this._structure=n,this._createdByUpsampling=t(e.createdByUpsampling,!1),this._waterMask=e.waterMask};i(y.prototype,{waterMask:{get:function(){return this._waterMask}}});var C=new u("createVerticesFromHeightmap");return y.prototype.createMesh=function(t,i,n,a){var s=t.ellipsoid,u=t.tileXYToNativeRectangle(i,n,a),d=t.tileXYToRectangle(i,n,a),p=s.cartographicToCartesian(l.center(d)),m=this._structure,f=h.getEstimatedLevelZeroGeometricErrorForAHeightmap(s,this._width,t.getNumberOfXTilesAtLevel(0)),v=f/(1<1){var l=a.elementsPerHeight,u=a.elementMultiplier,c=a.isBigEndian;i=f(this._buffer,l,u,s,c,e,n,o,t,r)}else i=m(this._buffer,e,n,o,t,r);return i*a.heightScale+a.heightOffset},y.prototype.upsample=function(e,t,r,i,n,o,a){var s;return s=this._width%2===1&&this._height%2===1?d(this,e,t,r,i,n,o,a):p(this,e,t,r,i,n,o,a)},y.prototype.isChildAvailable=function(e,t,r,i){var n=2;return r!==2*e&&++n,i!==2*t&&(n-=2),0!==(this._childTileMask&1<=a.maximumRequestsPerServer?void 0:(n[s]=l+1,t(o(e),function(e){return n[s]--,e}).otherwise(function(e){return n[s]--,t.reject(e)}))};return a.maximumRequestsPerServer=6,a}),r("Core/ArcGisImageServerTerrainProvider",["../ThirdParty/when","./Credit","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Event","./GeographicTilingScheme","./getImagePixels","./HeightmapTerrainData","./loadImage","./Math","./TerrainProvider","./throttleRequestByServer"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=function(n){this._url=n.url,this._token=n.token,this._tilingScheme=n.tilingScheme,i(this._tilingScheme)||(this._tilingScheme=new l({ellipsoid:r(n.ellipsoid,a.WGS84)})),this._heightmapWidth=65,this._levelZeroMaximumGeometricError=p.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid,this._heightmapWidth,this._tilingScheme.getNumberOfXTilesAtLevel(0)),this._proxy=n.proxy,this._terrainDataStructure={heightScale:.001,heightOffset:-1e3,elementsPerHeight:3,stride:4,elementMultiplier:256,isBigEndian:!0},this._errorEvent=new s;var o=n.credit;"string"==typeof o&&(o=new t(o)),this._credit=o,this._readyPromise=e.resolve(!0)};return n(f.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return this._credit}},tilingScheme:{get:function(){return this._tilingScheme}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},hasWaterMask:{get:function(){return!1}},hasVertexNormals:{get:function(){return!1}}}),f.prototype.requestTileGeometry=function(t,r,n){var o=this._tilingScheme.tileXYToRectangle(t,r,n),a=(o.east-o.west)/(this._heightmapWidth-1),s=(o.north-o.south)/(this._heightmapWidth-1);o.west-=.5*a,o.east+=.5*a,o.south-=.5*s,o.north+=.5*s;var l=d.toDegrees(o.west)+"%2C"+d.toDegrees(o.south)+"%2C"+d.toDegrees(o.east)+"%2C"+d.toDegrees(o.north),p=this._url+"/exportImage?interpolation=RSP_BilinearInterpolation&format=tiff&f=image&size="+this._heightmapWidth+"%2C"+this._heightmapWidth+"&bboxSR=4326&imageSR=4326&bbox="+l;this._token&&(p+="&token="+this._token);var f=this._proxy;i(f)&&(p=f.getURL(p));var v=m(p,h);if(!i(v))return void 0;var _=this;return e(v,function(e){return new c({buffer:u(e),width:_._heightmapWidth,height:_._heightmapWidth,childTileMask:15,structure:_._terrainDataStructure})})},f.prototype.getLevelMaximumGeometricError=function(e){return this._levelZeroMaximumGeometricError/(1<0&&(this._hash={},e.length=0)},i}),r("Core/AttributeCompression",["./Cartesian2","./Cartesian3","./defined","./DeveloperError","./Math"],function(e,t,r,i,n){"use strict";var o={};o.octEncode=function(e,t){if(t.x=e.x/(Math.abs(e.x)+Math.abs(e.y)+Math.abs(e.z)),t.y=e.y/(Math.abs(e.x)+Math.abs(e.y)+Math.abs(e.z)),e.z<0){var r=t.x,i=t.y;t.x=(1-Math.abs(i))*n.signNotZero(r),t.y=(1-Math.abs(r))*n.signNotZero(i)}return t.x=n.toSNorm(t.x),t.y=n.toSNorm(t.y),t},o.octDecode=function(e,r,i){if(i.x=n.fromSNorm(e),i.y=n.fromSNorm(r),i.z=1-(Math.abs(i.x)+Math.abs(i.y)),i.z<0){var o=i.x;i.x=(1-Math.abs(i.y))*n.signNotZero(o),i.y=(1-Math.abs(o))*n.signNotZero(i.y)}return t.normalize(i,i)},o.octPackFloat=function(e){return 256*e.x+e.y};var a=new e;return o.octEncodeFloat=function(e){return o.octEncode(e,a),o.octPackFloat(a)},o.octDecodeFloat=function(e,t){var r=e/256,i=Math.floor(r),n=256*(r-i);return o.octDecode(i,n,t)},o.octPack=function(e,t,r,i){var n=o.octEncodeFloat(e),s=o.octEncodeFloat(t),l=o.octEncode(r,a);return i.x=65536*l.x+n,i.y=65536*l.y+s,i},o.octUnpack=function(e,t,r,i){var n=e.x/65536,a=Math.floor(n),s=65536*(n-a);n=e.y/65536;var l=Math.floor(n),u=65536*(n-l);o.octDecodeFloat(s,t),o.octDecodeFloat(u,r),o.octDecode(a,l,i)},o.compressTextureCoordinates=function(e){var t=1===e.x?4095:4096*e.x|0,r=1===e.y?4095:4096*e.y|0;return 4096*t+r},o.decompressTextureCoordinates=function(e,t){var r=e/4096;return t.x=Math.floor(r)/4096,t.y=r-Math.floor(r),t},o}),r("Core/deprecationWarning",["./defined","./DeveloperError"],function(e,t){"use strict";var r={},i=function(t,i){e(r[t])||(r[t]=!0,console.log(i))};return i}),r("Core/Intersect",["./freezeObject"],function(e){"use strict";var t={OUTSIDE:-1,INTERSECTING:0,INSIDE:1};return e(t)}),r("Core/Plane",["./Cartesian3","./defined","./DeveloperError","./freezeObject"],function(e,t,r,i){"use strict";var n=function(t,r){this.normal=e.clone(t),this.distance=r};n.fromPointNormal=function(r,i,o){var a=-e.dot(i,r);return t(o)?(e.clone(i,o.normal),o.distance=a,o):new n(i,a)};var o=new e;return n.fromCartesian4=function(r,i){var a=e.fromCartesian4(r,o),s=r.w;return t(i)?(e.clone(a,i.normal),i.distance=s,i):new n(a,s)},n.getPointDistance=function(t,r){return e.dot(t.normal,r)+t.distance},n.ORIGIN_XY_PLANE=i(new n(e.UNIT_Z,0)),n.ORIGIN_YZ_PLANE=i(new n(e.UNIT_X,0)),n.ORIGIN_ZX_PLANE=i(new n(e.UNIT_Y,0)),n}),r("Core/AxisAlignedBoundingBox",["./Cartesian3","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Intersect","./Plane"],function(e,t,r,i,n,o,a){"use strict";var s=function(i,n,o){this.minimum=e.clone(t(i,e.ZERO)),this.maximum=e.clone(t(n,e.ZERO)),r(o)?o=e.clone(o):(o=e.add(this.minimum,this.maximum,new e),e.multiplyByScalar(o,.5,o)),this.center=o};s.fromPoints=function(t,i){if(r(i)||(i=new s),!r(t)||0===t.length)return i.minimum=e.clone(e.ZERO,i.minimum),i.maximum=e.clone(e.ZERO,i.maximum),i.center=e.clone(e.ZERO,i.center),i;for(var n=t[0].x,o=t[0].y,a=t[0].z,l=t[0].x,u=t[0].y,c=t[0].z,h=t.length,d=1;h>d;d++){var p=t[d],m=p.x,f=p.y,v=p.z;n=Math.min(m,n),l=Math.max(m,l),o=Math.min(f,o),u=Math.max(f,u),a=Math.min(v,a),c=Math.max(v,c)}var _=i.minimum;_.x=n,_.y=o,_.z=a;var g=i.maximum;g.x=l,g.y=u,g.z=c;var y=e.add(_,g,i.center);return e.multiplyByScalar(y,.5,y),i},s.clone=function(t,i){return r(t)?r(i)?(i.minimum=e.clone(t.minimum,i.minimum),i.maximum=e.clone(t.maximum,i.maximum),i.center=e.clone(t.center,i.center),i):new s(t.minimum,t.maximum):void 0},s.equals=function(t,i){return t===i||r(t)&&r(i)&&e.equals(t.center,i.center)&&e.equals(t.minimum,i.minimum)&&e.equals(t.maximum,i.maximum)};var l=new e;return s.intersectPlane=function(t,r){l=e.subtract(t.maximum,t.minimum,l);var i=e.multiplyByScalar(l,.5,l),n=r.normal,a=i.x*Math.abs(n.x)+i.y*Math.abs(n.y)+i.z*Math.abs(n.z),s=e.dot(t.center,n)+r.distance;return s-a>0?o.INSIDE:0>s+a?o.OUTSIDE:o.INTERSECTING},s.prototype.clone=function(e){return s.clone(this,e)},s.prototype.intersectPlane=function(e){return s.intersectPlane(this,e)},s.prototype.equals=function(e){return s.equals(this,e)},s}),r("Core/BingMapsApi",["./defined"],function(e){"use strict";var t={};t.defaultKey=void 0;var r=!1;return t.getKey=function(i){return e(i)?i:e(t.defaultKey)?t.defaultKey:(r||(console.log("This application is using Cesium's default Bing Maps key. Please create a new key for the application as soon as possible and prior to deployment by visiting https://www.bingmapsportal.com/, and provide your key to Cesium by setting the Cesium.BingMapsApi.defaultKey property before constructing the CesiumWidget or any other object that uses the Bing Maps API."),r=!0),"Aj1ony_-Typ-KjG9SJWiKSHY23U1KmK7yAmZa9lDmuF2osXWkcZ22VPsqmCt0TCt")},t}),r("Core/BoundingRectangle",["./Cartesian2","./Cartographic","./defaultValue","./defined","./DeveloperError","./GeographicProjection","./Intersect","./Rectangle"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,t,i,n){this.x=r(e,0),this.y=r(t,0),this.width=r(i,0),this.height=r(n,0)};l.fromPoints=function(e,t){if(i(t)||(t=new l),!i(e)||0===e.length)return t.x=0,t.y=0,t.width=0,t.height=0,t;for(var r=e.length,n=e[0].x,o=e[0].y,a=e[0].x,s=e[0].y,u=1;r>u;u++){var c=e[u],h=c.x,d=c.y;n=Math.min(h,n),a=Math.max(h,a),o=Math.min(d,o),s=Math.max(d,s)}return t.x=n,t.y=o,t.width=a-n,t.height=s-o,t};var u=new o,c=new t,h=new t;return l.fromRectangle=function(t,n,o){if(i(o)||(o=new l),!i(t))return o.x=0,o.y=0,o.width=0,o.height=0,o;n=r(n,u);var a=n.project(s.southwest(t,c)),d=n.project(s.northeast(t,h));return e.subtract(d,a,d),o.x=a.x,o.y=a.y,o.width=d.x,o.height=d.y,o},l.clone=function(e,t){return i(e)?i(t)?(t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,t):new l(e.x,e.y,e.width,e.height):void 0},l.union=function(e,t,r){i(r)||(r=new l);var n=Math.min(e.x,t.x),o=Math.min(e.y,t.y),a=Math.max(e.x+e.width,t.x+t.width),s=Math.max(e.y+e.height,t.y+t.height);return r.x=n,r.y=o,r.width=a-n,r.height=s-o,r},l.expand=function(e,t,r){r=l.clone(e,r);var i=t.x-r.x,n=t.y-r.y;return i>r.width?r.width=i:0>i&&(r.width-=i,r.x=t.x),n>r.height?r.height=n:0>n&&(r.height-=n,r.y=t.y),r},l.intersect=function(e,t){var r=e.x,i=e.y,n=t.x,o=t.y;return r>n+t.width||r+e.widtho+t.height?a.OUTSIDE:a.INTERSECTING},l.equals=function(e,t){return e===t||i(e)&&i(t)&&e.x===t.x&&e.y===t.y&&e.width===t.width&&e.height===t.height},l.prototype.clone=function(e){return l.clone(this,e)},l.prototype.intersect=function(e){return l.intersect(this,e)},l.prototype.equals=function(e){return l.equals(this,e)},l}),r("Core/Interval",["./defaultValue"],function(e){"use strict";var t=function(t,r){this.start=e(t,0),this.stop=e(r,0)};return t}),r("Core/Matrix3",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n,o){"use strict";function a(e){for(var t=0,r=0;9>r;++r){var i=e[r];t+=i*i}return Math.sqrt(t)}function s(e){for(var t=0,r=0;3>r;++r){var i=e[u.getElementIndex(p[r],d[r])];t+=2*i*i}return Math.sqrt(t)}function l(e,t){for(var r=o.EPSILON15,i=0,n=1,a=0;3>a;++a){var s=Math.abs(e[u.getElementIndex(p[a],d[a])]);s>i&&(n=a,i=s)}var l=1,c=0,h=d[n],m=p[n];if(Math.abs(e[u.getElementIndex(m,h)])>r){var f,v=e[u.getElementIndex(m,m)],_=e[u.getElementIndex(h,h)],g=e[u.getElementIndex(m,h)],y=(v-_)/2/g;f=0>y?-1/(-y+Math.sqrt(1+y*y)):1/(y+Math.sqrt(1+y*y)),l=1/Math.sqrt(1+f*f),c=f*l}return t=u.clone(u.IDENTITY,t),t[u.getElementIndex(h,h)]=t[u.getElementIndex(m,m)]=l,t[u.getElementIndex(m,h)]=c,t[u.getElementIndex(h,m)]=-c,t}var u=function(e,r,i,n,o,a,s,l,u){this[0]=t(e,0),this[1]=t(n,0),this[2]=t(s,0),this[3]=t(r,0),this[4]=t(o,0),this[5]=t(l,0),this[6]=t(i,0),this[7]=t(a,0),this[8]=t(u,0)};u.packedLength=9,u.pack=function(e,r,i){i=t(i,0),r[i++]=e[0],r[i++]=e[1],r[i++]=e[2],r[i++]=e[3],r[i++]=e[4],r[i++]=e[5],r[i++]=e[6],r[i++]=e[7],r[i++]=e[8]},u.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new u),n[0]=e[i++],n[1]=e[i++],n[2]=e[i++],n[3]=e[i++],n[4]=e[i++],n[5]=e[i++],n[6]=e[i++],n[7]=e[i++],n[8]=e[i++],n},u.clone=function(e,t){return r(e)?r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t):new u(e[0],e[3],e[6],e[1],e[4],e[7],e[2],e[5],e[8]):void 0},u.fromArray=function(e,i,n){return i=t(i,0),r(n)||(n=new u),n[0]=e[i],n[1]=e[i+1],n[2]=e[i+2],n[3]=e[i+3],n[4]=e[i+4],n[5]=e[i+5],n[6]=e[i+6],n[7]=e[i+7],n[8]=e[i+8],n},u.fromColumnMajorArray=function(e,t){return u.clone(e,t)},u.fromRowMajorArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],t):new u(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8])},u.fromQuaternion=function(e,t){var i=e.x*e.x,n=e.x*e.y,o=e.x*e.z,a=e.x*e.w,s=e.y*e.y,l=e.y*e.z,c=e.y*e.w,h=e.z*e.z,d=e.z*e.w,p=e.w*e.w,m=i-s-h+p,f=2*(n-d),v=2*(o+c),_=2*(n+d),g=-i+s-h+p,y=2*(l-a),C=2*(o-c),E=2*(l+a),S=-i-s+h+p;return r(t)?(t[0]=m,t[1]=_,t[2]=C,t[3]=f,t[4]=g,t[5]=E,t[6]=v,t[7]=y,t[8]=S,t):new u(m,f,v,_,g,y,C,E,S)},u.fromScale=function(e,t){return r(t)?(t[0]=e.x,t[1]=0,t[2]=0,t[3]=0,t[4]=e.y,t[5]=0,t[6]=0,t[7]=0,t[8]=e.z,t):new u(e.x,0,0,0,e.y,0,0,0,e.z)},u.fromUniformScale=function(e,t){return r(t)?(t[0]=e,t[1]=0,t[2]=0,t[3]=0,t[4]=e,t[5]=0,t[6]=0,t[7]=0,t[8]=e,t):new u(e,0,0,0,e,0,0,0,e)},u.fromCrossProduct=function(e,t){return r(t)?(t[0]=0,t[1]=e.z,t[2]=-e.y,t[3]=-e.z,t[4]=0,t[5]=e.x,t[6]=e.y,t[7]=-e.x,t[8]=0,t):new u(0,-e.z,e.y,e.z,0,-e.x,-e.y,e.x,0)},u.fromRotationX=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=i,t[5]=n,t[6]=0,t[7]=-n,t[8]=i,t):new u(1,0,0,0,i,-n,0,n,i)},u.fromRotationY=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=i,t[1]=0,t[2]=-n,t[3]=0,t[4]=1,t[5]=0,t[6]=n,t[7]=0,t[8]=i,t):new u(i,0,n,0,1,0,-n,0,i)},u.fromRotationZ=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=i,t[1]=n,t[2]=0,t[3]=-n,t[4]=i,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t):new u(i,-n,0,n,i,0,0,0,1)},u.toArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t):[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8]]},u.getElementIndex=function(e,t){return 3*e+t},u.getColumn=function(e,t,r){var i=3*t,n=e[i],o=e[i+1],a=e[i+2];return r.x=n,r.y=o,r.z=a,r},u.setColumn=function(e,t,r,i){i=u.clone(e,i);var n=3*t;return i[n]=r.x,i[n+1]=r.y,i[n+2]=r.z,i},u.getRow=function(e,t,r){var i=e[t],n=e[t+3],o=e[t+6];return r.x=i,r.y=n,r.z=o,r},u.setRow=function(e,t,r,i){return i=u.clone(e,i),i[t]=r.x,i[t+3]=r.y,i[t+6]=r.z,i};var c=new e;u.getScale=function(t,r){return r.x=e.magnitude(e.fromElements(t[0],t[1],t[2],c)),r.y=e.magnitude(e.fromElements(t[3],t[4],t[5],c)),r.z=e.magnitude(e.fromElements(t[6],t[7],t[8],c)),r};var h=new e;u.getMaximumScale=function(t){return u.getScale(t,h),e.maximumComponent(h)},u.multiply=function(e,t,r){var i=e[0]*t[0]+e[3]*t[1]+e[6]*t[2],n=e[1]*t[0]+e[4]*t[1]+e[7]*t[2],o=e[2]*t[0]+e[5]*t[1]+e[8]*t[2],a=e[0]*t[3]+e[3]*t[4]+e[6]*t[5],s=e[1]*t[3]+e[4]*t[4]+e[7]*t[5],l=e[2]*t[3]+e[5]*t[4]+e[8]*t[5],u=e[0]*t[6]+e[3]*t[7]+e[6]*t[8],c=e[1]*t[6]+e[4]*t[7]+e[7]*t[8],h=e[2]*t[6]+e[5]*t[7]+e[8]*t[8];return r[0]=i,r[1]=n,r[2]=o,r[3]=a,r[4]=s,r[5]=l,r[6]=u,r[7]=c,r[8]=h,r},u.add=function(e,t,r){return r[0]=e[0]+t[0],r[1]=e[1]+t[1],r[2]=e[2]+t[2],r[3]=e[3]+t[3],r[4]=e[4]+t[4],r[5]=e[5]+t[5],r[6]=e[6]+t[6],r[7]=e[7]+t[7],r[8]=e[8]+t[8],r},u.subtract=function(e,t,r){return r[0]=e[0]-t[0],r[1]=e[1]-t[1],r[2]=e[2]-t[2],r[3]=e[3]-t[3],r[4]=e[4]-t[4],r[5]=e[5]-t[5],r[6]=e[6]-t[6],r[7]=e[7]-t[7],r[8]=e[8]-t[8],r},u.multiplyByVector=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=e[0]*i+e[3]*n+e[6]*o,s=e[1]*i+e[4]*n+e[7]*o,l=e[2]*i+e[5]*n+e[8]*o;return r.x=a,r.y=s,r.z=l,r},u.multiplyByScalar=function(e,t,r){return r[0]=e[0]*t,r[1]=e[1]*t,r[2]=e[2]*t,r[3]=e[3]*t,r[4]=e[4]*t,r[5]=e[5]*t,r[6]=e[6]*t,r[7]=e[7]*t,r[8]=e[8]*t,r},u.multiplyByScale=function(e,t,r){return r[0]=e[0]*t.x,r[1]=e[1]*t.x,r[2]=e[2]*t.x,r[3]=e[3]*t.y,r[4]=e[4]*t.y,r[5]=e[5]*t.y,r[6]=e[6]*t.z,r[7]=e[7]*t.z,r[8]=e[8]*t.z,r},u.negate=function(e,t){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2], +t[3]=-e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=-e[7],t[8]=-e[8],t},u.transpose=function(e,t){var r=e[0],i=e[3],n=e[6],o=e[1],a=e[4],s=e[7],l=e[2],u=e[5],c=e[8];return t[0]=r,t[1]=i,t[2]=n,t[3]=o,t[4]=a,t[5]=s,t[6]=l,t[7]=u,t[8]=c,t};var d=[1,0,0],p=[2,2,1],m=new u,f=new u;return u.computeEigenDecomposition=function(e,t){var i=o.EPSILON20,n=10,c=0,h=0;r(t)||(t={});for(var d=t.unitary=u.clone(u.IDENTITY,t.unitary),p=t.diagonal=u.clone(e,t.diagonal),v=i*a(p);n>h&&s(p)>v;)l(p,m),u.transpose(m,f),u.multiply(p,m,p),u.multiply(f,p,p),u.multiply(d,m,d),++c>2&&(++h,c=0);return t},u.abs=function(e,t){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t[3]=Math.abs(e[3]),t[4]=Math.abs(e[4]),t[5]=Math.abs(e[5]),t[6]=Math.abs(e[6]),t[7]=Math.abs(e[7]),t[8]=Math.abs(e[8]),t},u.determinant=function(e){var t=e[0],r=e[3],i=e[6],n=e[1],o=e[4],a=e[7],s=e[2],l=e[5],u=e[8];return t*(o*u-l*a)+n*(l*i-r*u)+s*(r*a-o*i)},u.inverse=function(e,t){var r=e[0],n=e[1],a=e[2],s=e[3],l=e[4],c=e[5],h=e[6],d=e[7],p=e[8],m=u.determinant(e);if(Math.abs(m)<=o.EPSILON15)throw new i("matrix is not invertible");t[0]=l*p-d*c,t[1]=d*a-n*p,t[2]=n*c-l*a,t[3]=h*c-s*p,t[4]=r*p-h*a,t[5]=s*a-r*c,t[6]=s*d-h*l,t[7]=h*n-r*d,t[8]=r*l-s*n;var f=1/m;return u.multiplyByScalar(t,f,t)},u.equals=function(e,t){return e===t||r(e)&&r(t)&&e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[3]===t[3]&&e[4]===t[4]&&e[5]===t[5]&&e[6]===t[6]&&e[7]===t[7]&&e[8]===t[8]},u.equalsEpsilon=function(e,t,i){return e===t||r(e)&&r(t)&&Math.abs(e[0]-t[0])<=i&&Math.abs(e[1]-t[1])<=i&&Math.abs(e[2]-t[2])<=i&&Math.abs(e[3]-t[3])<=i&&Math.abs(e[4]-t[4])<=i&&Math.abs(e[5]-t[5])<=i&&Math.abs(e[6]-t[6])<=i&&Math.abs(e[7]-t[7])<=i&&Math.abs(e[8]-t[8])<=i},u.IDENTITY=n(new u(1,0,0,0,1,0,0,0,1)),u.ZERO=n(new u(0,0,0,0,0,0,0,0,0)),u.COLUMN0ROW0=0,u.COLUMN0ROW1=1,u.COLUMN0ROW2=2,u.COLUMN1ROW0=3,u.COLUMN1ROW1=4,u.COLUMN1ROW2=5,u.COLUMN2ROW0=6,u.COLUMN2ROW1=7,u.COLUMN2ROW2=8,u.prototype.clone=function(e){return u.clone(this,e)},u.prototype.equals=function(e){return u.equals(this,e)},u.equalsArray=function(e,t,r){return e[0]===t[r]&&e[1]===t[r+1]&&e[2]===t[r+2]&&e[3]===t[r+3]&&e[4]===t[r+4]&&e[5]===t[r+5]&&e[6]===t[r+6]&&e[7]===t[r+7]&&e[8]===t[r+8]},u.prototype.equalsEpsilon=function(e,t){return u.equalsEpsilon(this,e,t)},u.prototype.toString=function(){return"("+this[0]+", "+this[3]+", "+this[6]+")\n("+this[1]+", "+this[4]+", "+this[7]+")\n("+this[2]+", "+this[5]+", "+this[8]+")"},u}),r("Core/Cartesian4",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r,i,n){this.x=e(t,0),this.y=e(r,0),this.z=e(i,0),this.w=e(n,0)};o.fromElements=function(e,r,i,n,a){return t(a)?(a.x=e,a.y=r,a.z=i,a.w=n,a):new o(e,r,i,n)},o.fromColor=function(e,r){return t(r)?(r.x=e.red,r.y=e.green,r.z=e.blue,r.w=e.alpha,r):new o(e.red,e.green,e.blue,e.alpha)},o.clone=function(e,r){return t(e)?t(r)?(r.x=e.x,r.y=e.y,r.z=e.z,r.w=e.w,r):new o(e.x,e.y,e.z,e.w):void 0},o.packedLength=4,o.pack=function(t,r,i){i=e(i,0),r[i++]=t.x,r[i++]=t.y,r[i++]=t.z,r[i]=t.w},o.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new o),n.x=r[i++],n.y=r[i++],n.z=r[i++],n.w=r[i],n},o.fromArray=o.unpack,o.maximumComponent=function(e){return Math.max(e.x,e.y,e.z,e.w)},o.minimumComponent=function(e){return Math.min(e.x,e.y,e.z,e.w)},o.minimumByComponent=function(e,t,r){return r.x=Math.min(e.x,t.x),r.y=Math.min(e.y,t.y),r.z=Math.min(e.z,t.z),r.w=Math.min(e.w,t.w),r},o.maximumByComponent=function(e,t,r){return r.x=Math.max(e.x,t.x),r.y=Math.max(e.y,t.y),r.z=Math.max(e.z,t.z),r.w=Math.max(e.w,t.w),r},o.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y+e.z*e.z+e.w*e.w},o.magnitude=function(e){return Math.sqrt(o.magnitudeSquared(e))};var a=new o;o.distance=function(e,t){return o.subtract(e,t,a),o.magnitude(a)},o.distanceSquared=function(e,t){return o.subtract(e,t,a),o.magnitudeSquared(a)},o.normalize=function(e,t){var r=o.magnitude(e);return t.x=e.x/r,t.y=e.y/r,t.z=e.z/r,t.w=e.w/r,t},o.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z+e.w*t.w},o.multiplyComponents=function(e,t,r){return r.x=e.x*t.x,r.y=e.y*t.y,r.z=e.z*t.z,r.w=e.w*t.w,r},o.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r.z=e.z+t.z,r.w=e.w+t.w,r},o.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r.z=e.z-t.z,r.w=e.w-t.w,r},o.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r.z=e.z*t,r.w=e.w*t,r},o.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r.z=e.z/t,r.w=e.w/t,r},o.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t.w=-e.w,t},o.abs=function(e,t){return t.x=Math.abs(e.x),t.y=Math.abs(e.y),t.z=Math.abs(e.z),t.w=Math.abs(e.w),t};var s=new o;o.lerp=function(e,t,r,i){return o.multiplyByScalar(t,r,s),i=o.multiplyByScalar(e,1-r,i),o.add(s,i,i)};var l=new o;return o.mostOrthogonalAxis=function(e,t){var r=o.normalize(e,l);return o.abs(r,r),t=r.x<=r.y?r.x<=r.z?r.x<=r.w?o.clone(o.UNIT_X,t):o.clone(o.UNIT_W,t):r.z<=r.w?o.clone(o.UNIT_Z,t):o.clone(o.UNIT_W,t):r.y<=r.z?r.y<=r.w?o.clone(o.UNIT_Y,t):o.clone(o.UNIT_W,t):r.z<=r.w?o.clone(o.UNIT_Z,t):o.clone(o.UNIT_W,t)},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.x===r.x&&e.y===r.y&&e.z===r.z&&e.w===r.w},o.equalsArray=function(e,t,r){return e.x===t[r]&&e.y===t[r+1]&&e.z===t[r+2]&&e.w===t[r+3]},o.equalsEpsilon=function(e,r,i,o){return e===r||t(e)&&t(r)&&n.equalsEpsilon(e.x,r.x,i,o)&&n.equalsEpsilon(e.y,r.y,i,o)&&n.equalsEpsilon(e.z,r.z,i,o)&&n.equalsEpsilon(e.w,r.w,i,o)},o.ZERO=i(new o(0,0,0,0)),o.UNIT_X=i(new o(1,0,0,0)),o.UNIT_Y=i(new o(0,1,0,0)),o.UNIT_Z=i(new o(0,0,1,0)),o.UNIT_W=i(new o(0,0,0,1)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t,r){return o.equalsEpsilon(this,e,t,r)},o.prototype.toString=function(){return"("+this.x+", "+this.y+", "+this.z+", "+this.w+")"},o}),r("Core/Matrix4",["./Cartesian3","./Cartesian4","./defaultValue","./defined","./DeveloperError","./freezeObject","./Math","./Matrix3","./RuntimeError"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(e,t,i,n,o,a,s,l,u,c,h,d,p,m,f,v){this[0]=r(e,0),this[1]=r(o,0),this[2]=r(u,0),this[3]=r(p,0),this[4]=r(t,0),this[5]=r(a,0),this[6]=r(c,0),this[7]=r(m,0),this[8]=r(i,0),this[9]=r(s,0),this[10]=r(h,0),this[11]=r(f,0),this[12]=r(n,0),this[13]=r(l,0),this[14]=r(d,0),this[15]=r(v,0)};u.packedLength=16,u.pack=function(e,t,i){i=r(i,0),t[i++]=e[0],t[i++]=e[1],t[i++]=e[2],t[i++]=e[3],t[i++]=e[4],t[i++]=e[5],t[i++]=e[6],t[i++]=e[7],t[i++]=e[8],t[i++]=e[9],t[i++]=e[10],t[i++]=e[11],t[i++]=e[12],t[i++]=e[13],t[i++]=e[14],t[i]=e[15]},u.unpack=function(e,t,n){return t=r(t,0),i(n)||(n=new u),n[0]=e[t++],n[1]=e[t++],n[2]=e[t++],n[3]=e[t++],n[4]=e[t++],n[5]=e[t++],n[6]=e[t++],n[7]=e[t++],n[8]=e[t++],n[9]=e[t++],n[10]=e[t++],n[11]=e[t++],n[12]=e[t++],n[13]=e[t++],n[14]=e[t++],n[15]=e[t],n},u.clone=function(e,t){return i(e)?i(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t):new u(e[0],e[4],e[8],e[12],e[1],e[5],e[9],e[13],e[2],e[6],e[10],e[14],e[3],e[7],e[11],e[15]):void 0},u.fromArray=u.unpack,u.fromColumnMajorArray=function(e,t){return u.clone(e,t)},u.fromRowMajorArray=function(e,t){return i(t)?(t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15],t):new u(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15])},u.fromRotationTranslation=function(t,n,o){return n=r(n,e.ZERO),i(o)?(o[0]=t[0],o[1]=t[1],o[2]=t[2],o[3]=0,o[4]=t[3],o[5]=t[4],o[6]=t[5],o[7]=0,o[8]=t[6],o[9]=t[7],o[10]=t[8],o[11]=0,o[12]=n.x,o[13]=n.y,o[14]=n.z,o[15]=1,o):new u(t[0],t[3],t[6],n.x,t[1],t[4],t[7],n.y,t[2],t[5],t[8],n.z,0,0,0,1)},u.fromTranslationQuaternionRotationScale=function(e,t,r,n){i(n)||(n=new u);var o=r.x,a=r.y,s=r.z,l=t.x*t.x,c=t.x*t.y,h=t.x*t.z,d=t.x*t.w,p=t.y*t.y,m=t.y*t.z,f=t.y*t.w,v=t.z*t.z,_=t.z*t.w,g=t.w*t.w,y=l-p-v+g,C=2*(c-_),E=2*(h+f),S=2*(c+_),w=-l+p-v+g,T=2*(m-d),b=2*(h-f),x=2*(m+d),P=-l-p+v+g;return n[0]=y*o,n[1]=S*o,n[2]=b*o,n[3]=0,n[4]=C*a,n[5]=w*a,n[6]=x*a,n[7]=0,n[8]=E*s,n[9]=T*s,n[10]=P*s,n[11]=0,n[12]=e.x,n[13]=e.y,n[14]=e.z,n[15]=1,n},u.fromTranslation=function(e,t){return u.fromRotationTranslation(s.IDENTITY,e,t)},u.fromScale=function(e,t){return i(t)?(t[0]=e.x,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e.y,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e.z,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t):new u(e.x,0,0,0,0,e.y,0,0,0,0,e.z,0,0,0,0,1)},u.fromUniformScale=function(e,t){return i(t)?(t[0]=e,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t):new u(e,0,0,0,0,e,0,0,0,0,e,0,0,0,0,1)};var c=new e,h=new e,d=new e;u.fromCamera=function(t,r){var n=t.eye,o=t.target,a=t.up;e.normalize(e.subtract(o,n,c),c),e.normalize(e.cross(c,a,h),h),e.normalize(e.cross(h,c,d),d);var s=h.x,l=h.y,p=h.z,m=c.x,f=c.y,v=c.z,_=d.x,g=d.y,y=d.z,C=n.x,E=n.y,S=n.z,w=s*-C+l*-E+p*-S,T=_*-C+g*-E+y*-S,b=m*C+f*E+v*S;return i(r)?(r[0]=s,r[1]=_,r[2]=-m,r[3]=0,r[4]=l,r[5]=g,r[6]=-f,r[7]=0,r[8]=p,r[9]=y,r[10]=-v,r[11]=0,r[12]=w,r[13]=T,r[14]=b,r[15]=1,r):new u(s,l,p,w,_,g,y,T,-m,-f,-v,b,0,0,0,1)},u.computePerspectiveFieldOfView=function(e,t,r,i,n){var o=Math.tan(.5*e),a=1/o,s=a/t,l=(i+r)/(r-i),u=2*i*r/(r-i);return n[0]=s,n[1]=0,n[2]=0,n[3]=0,n[4]=0,n[5]=a,n[6]=0,n[7]=0,n[8]=0,n[9]=0,n[10]=l,n[11]=-1,n[12]=0,n[13]=0,n[14]=u,n[15]=0,n},u.computeOrthographicOffCenter=function(e,t,r,i,n,o,a){var s=1/(t-e),l=1/(i-r),u=1/(o-n),c=-(t+e)*s,h=-(i+r)*l,d=-(o+n)*u;return s*=2,l*=2,u*=-2,a[0]=s,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=l,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=u,a[11]=0,a[12]=c,a[13]=h,a[14]=d,a[15]=1,a},u.computePerspectiveOffCenter=function(e,t,r,i,n,o,a){var s=2*n/(t-e),l=2*n/(i-r),u=(t+e)/(t-e),c=(i+r)/(i-r),h=-(o+n)/(o-n),d=-1,p=-2*o*n/(o-n);return a[0]=s,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=l,a[6]=0,a[7]=0,a[8]=u,a[9]=c,a[10]=h,a[11]=d,a[12]=0,a[13]=0,a[14]=p,a[15]=0,a},u.computeInfinitePerspectiveOffCenter=function(e,t,r,i,n,o){var a=2*n/(t-e),s=2*n/(i-r),l=(t+e)/(t-e),u=(i+r)/(i-r),c=-1,h=-1,d=-2*n;return o[0]=a,o[1]=0,o[2]=0,o[3]=0,o[4]=0,o[5]=s,o[6]=0,o[7]=0,o[8]=l,o[9]=u,o[10]=c,o[11]=h,o[12]=0,o[13]=0,o[14]=d,o[15]=0,o},u.computeViewportTransformation=function(e,t,i,n){e=r(e,r.EMPTY_OBJECT);var o=r(e.x,0),a=r(e.y,0),s=r(e.width,0),l=r(e.height,0);t=r(t,0),i=r(i,1);var u=.5*s,c=.5*l,h=.5*(i-t),d=u,p=c,m=h,f=o+u,v=a+c,_=t+h,g=1;return n[0]=d,n[1]=0,n[2]=0,n[3]=0,n[4]=0,n[5]=p,n[6]=0,n[7]=0,n[8]=0,n[9]=0,n[10]=m,n[11]=0,n[12]=f,n[13]=v,n[14]=_,n[15]=g,n},u.toArray=function(e,t){return i(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t):[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]]},u.getElementIndex=function(e,t){return 4*e+t},u.getColumn=function(e,t,r){var i=4*t,n=e[i],o=e[i+1],a=e[i+2],s=e[i+3];return r.x=n,r.y=o,r.z=a,r.w=s,r},u.setColumn=function(e,t,r,i){i=u.clone(e,i);var n=4*t;return i[n]=r.x,i[n+1]=r.y,i[n+2]=r.z,i[n+3]=r.w,i},u.setTranslation=function(e,t,r){return r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=e[3],r[4]=e[4],r[5]=e[5],r[6]=e[6],r[7]=e[7],r[8]=e[8],r[9]=e[9],r[10]=e[10],r[11]=e[11],r[12]=t.x,r[13]=t.y,r[14]=t.z,r[15]=e[15],r},u.getRow=function(e,t,r){var i=e[t],n=e[t+4],o=e[t+8],a=e[t+12];return r.x=i,r.y=n,r.z=o,r.w=a,r},u.setRow=function(e,t,r,i){return i=u.clone(e,i),i[t]=r.x,i[t+4]=r.y,i[t+8]=r.z,i[t+12]=r.w,i};var p=new e;u.getScale=function(t,r){return r.x=e.magnitude(e.fromElements(t[0],t[1],t[2],p)),r.y=e.magnitude(e.fromElements(t[4],t[5],t[6],p)),r.z=e.magnitude(e.fromElements(t[8],t[9],t[10],p)),r};var m=new e;u.getMaximumScale=function(t){return u.getScale(t,m),e.maximumComponent(m)},u.multiply=function(e,t,r){var i=e[0],n=e[1],o=e[2],a=e[3],s=e[4],l=e[5],u=e[6],c=e[7],h=e[8],d=e[9],p=e[10],m=e[11],f=e[12],v=e[13],_=e[14],g=e[15],y=t[0],C=t[1],E=t[2],S=t[3],w=t[4],T=t[5],b=t[6],x=t[7],P=t[8],A=t[9],I=t[10],M=t[11],D=t[12],R=t[13],O=t[14],N=t[15],L=i*y+s*C+h*E+f*S,F=n*y+l*C+d*E+v*S,B=o*y+u*C+p*E+_*S,V=a*y+c*C+m*E+g*S,z=i*w+s*T+h*b+f*x,k=n*w+l*T+d*b+v*x,U=o*w+u*T+p*b+_*x,G=a*w+c*T+m*b+g*x,W=i*P+s*A+h*I+f*M,H=n*P+l*A+d*I+v*M,q=o*P+u*A+p*I+_*M,j=a*P+c*A+m*I+g*M,Y=i*D+s*R+h*O+f*N,X=n*D+l*R+d*O+v*N,Z=o*D+u*R+p*O+_*N,K=a*D+c*R+m*O+g*N;return r[0]=L,r[1]=F,r[2]=B,r[3]=V,r[4]=z,r[5]=k,r[6]=U,r[7]=G,r[8]=W,r[9]=H,r[10]=q,r[11]=j,r[12]=Y,r[13]=X,r[14]=Z,r[15]=K,r},u.add=function(e,t,r){return r[0]=e[0]+t[0],r[1]=e[1]+t[1],r[2]=e[2]+t[2],r[3]=e[3]+t[3],r[4]=e[4]+t[4],r[5]=e[5]+t[5],r[6]=e[6]+t[6],r[7]=e[7]+t[7],r[8]=e[8]+t[8],r[9]=e[9]+t[9],r[10]=e[10]+t[10],r[11]=e[11]+t[11],r[12]=e[12]+t[12],r[13]=e[13]+t[13],r[14]=e[14]+t[14],r[15]=e[15]+t[15],r},u.subtract=function(e,t,r){return r[0]=e[0]-t[0],r[1]=e[1]-t[1],r[2]=e[2]-t[2],r[3]=e[3]-t[3],r[4]=e[4]-t[4],r[5]=e[5]-t[5],r[6]=e[6]-t[6],r[7]=e[7]-t[7],r[8]=e[8]-t[8],r[9]=e[9]-t[9],r[10]=e[10]-t[10],r[11]=e[11]-t[11],r[12]=e[12]-t[12],r[13]=e[13]-t[13],r[14]=e[14]-t[14],r[15]=e[15]-t[15],r},u.multiplyTransformation=function(e,t,r){var i=e[0],n=e[1],o=e[2],a=e[4],s=e[5],l=e[6],u=e[8],c=e[9],h=e[10],d=e[12],p=e[13],m=e[14],f=t[0],v=t[1],_=t[2],g=t[4],y=t[5],C=t[6],E=t[8],S=t[9],w=t[10],T=t[12],b=t[13],x=t[14],P=i*f+a*v+u*_,A=n*f+s*v+c*_,I=o*f+l*v+h*_,M=i*g+a*y+u*C,D=n*g+s*y+c*C,R=o*g+l*y+h*C,O=i*E+a*S+u*w,N=n*E+s*S+c*w,L=o*E+l*S+h*w,F=i*T+a*b+u*x+d,B=n*T+s*b+c*x+p,V=o*T+l*b+h*x+m;return r[0]=P,r[1]=A,r[2]=I,r[3]=0,r[4]=M,r[5]=D,r[6]=R,r[7]=0,r[8]=O,r[9]=N,r[10]=L,r[11]=0,r[12]=F,r[13]=B,r[14]=V,r[15]=1,r},u.multiplyByMatrix3=function(e,t,r){var i=e[0],n=e[1],o=e[2],a=e[4],s=e[5],l=e[6],u=e[8],c=e[9],h=e[10],d=t[0],p=t[1],m=t[2],f=t[3],v=t[4],_=t[5],g=t[6],y=t[7],C=t[8],E=i*d+a*p+u*m,S=n*d+s*p+c*m,w=o*d+l*p+h*m,T=i*f+a*v+u*_,b=n*f+s*v+c*_,x=o*f+l*v+h*_,P=i*g+a*y+u*C,A=n*g+s*y+c*C,I=o*g+l*y+h*C;return r[0]=E,r[1]=S,r[2]=w,r[3]=0,r[4]=T,r[5]=b,r[6]=x,r[7]=0,r[8]=P,r[9]=A,r[10]=I,r[11]=0,r[12]=e[12],r[13]=e[13],r[14]=e[14],r[15]=e[15],r},u.multiplyByTranslation=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=i*e[0]+n*e[4]+o*e[8]+e[12],s=i*e[1]+n*e[5]+o*e[9]+e[13],l=i*e[2]+n*e[6]+o*e[10]+e[14];return r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=e[3],r[4]=e[4],r[5]=e[5],r[6]=e[6],r[7]=e[7],r[8]=e[8],r[9]=e[9],r[10]=e[10],r[11]=e[11],r[12]=a,r[13]=s,r[14]=l,r[15]=e[15],r};var f=new e;u.multiplyByUniformScale=function(e,t,r){return f.x=t,f.y=t,f.z=t,u.multiplyByScale(e,f,r)},u.multiplyByScale=function(e,t,r){var i=t.x,n=t.y,o=t.z;return 1===i&&1===n&&1===o?u.clone(e,r):(r[0]=i*e[0],r[1]=i*e[1],r[2]=i*e[2],r[3]=0,r[4]=n*e[4],r[5]=n*e[5],r[6]=n*e[6],r[7]=0,r[8]=o*e[8],r[9]=o*e[9],r[10]=o*e[10],r[11]=0,r[12]=e[12],r[13]=e[13],r[14]=e[14],r[15]=1,r)},u.multiplyByVector=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=t.w,s=e[0]*i+e[4]*n+e[8]*o+e[12]*a,l=e[1]*i+e[5]*n+e[9]*o+e[13]*a,u=e[2]*i+e[6]*n+e[10]*o+e[14]*a,c=e[3]*i+e[7]*n+e[11]*o+e[15]*a;return r.x=s,r.y=l,r.z=u,r.w=c,r},u.multiplyByPointAsVector=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=e[0]*i+e[4]*n+e[8]*o,s=e[1]*i+e[5]*n+e[9]*o,l=e[2]*i+e[6]*n+e[10]*o;return r.x=a,r.y=s,r.z=l,r},u.multiplyByPoint=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=e[0]*i+e[4]*n+e[8]*o+e[12],s=e[1]*i+e[5]*n+e[9]*o+e[13],l=e[2]*i+e[6]*n+e[10]*o+e[14];return r.x=a,r.y=s,r.z=l,r},u.multiplyByScalar=function(e,t,r){return r[0]=e[0]*t,r[1]=e[1]*t,r[2]=e[2]*t,r[3]=e[3]*t,r[4]=e[4]*t,r[5]=e[5]*t,r[6]=e[6]*t,r[7]=e[7]*t,r[8]=e[8]*t,r[9]=e[9]*t,r[10]=e[10]*t,r[11]=e[11]*t,r[12]=e[12]*t,r[13]=e[13]*t,r[14]=e[14]*t,r[15]=e[15]*t,r},u.negate=function(e,t){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=-e[7],t[8]=-e[8],t[9]=-e[9],t[10]=-e[10],t[11]=-e[11],t[12]=-e[12],t[13]=-e[13],t[14]=-e[14],t[15]=-e[15],t},u.transpose=function(e,t){var r=e[1],i=e[2],n=e[3],o=e[6],a=e[7],s=e[11];return t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=r,t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=i,t[9]=o,t[10]=e[10],t[11]=e[14],t[12]=n,t[13]=a,t[14]=s,t[15]=e[15],t},u.abs=function(e,t){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t[3]=Math.abs(e[3]),t[4]=Math.abs(e[4]),t[5]=Math.abs(e[5]),t[6]=Math.abs(e[6]),t[7]=Math.abs(e[7]),t[8]=Math.abs(e[8]),t[9]=Math.abs(e[9]),t[10]=Math.abs(e[10]),t[11]=Math.abs(e[11]),t[12]=Math.abs(e[12]),t[13]=Math.abs(e[13]),t[14]=Math.abs(e[14]),t[15]=Math.abs(e[15]),t},u.equals=function(e,t){return e===t||i(e)&&i(t)&&e[12]===t[12]&&e[13]===t[13]&&e[14]===t[14]&&e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[4]===t[4]&&e[5]===t[5]&&e[6]===t[6]&&e[8]===t[8]&&e[9]===t[9]&&e[10]===t[10]&&e[3]===t[3]&&e[7]===t[7]&&e[11]===t[11]&&e[15]===t[15]},u.equalsEpsilon=function(e,t,r){return e===t||i(e)&&i(t)&&Math.abs(e[0]-t[0])<=r&&Math.abs(e[1]-t[1])<=r&&Math.abs(e[2]-t[2])<=r&&Math.abs(e[3]-t[3])<=r&&Math.abs(e[4]-t[4])<=r&&Math.abs(e[5]-t[5])<=r&&Math.abs(e[6]-t[6])<=r&&Math.abs(e[7]-t[7])<=r&&Math.abs(e[8]-t[8])<=r&&Math.abs(e[9]-t[9])<=r&&Math.abs(e[10]-t[10])<=r&&Math.abs(e[11]-t[11])<=r&&Math.abs(e[12]-t[12])<=r&&Math.abs(e[13]-t[13])<=r&&Math.abs(e[14]-t[14])<=r&&Math.abs(e[15]-t[15])<=r},u.getTranslation=function(e,t){return t.x=e[12],t.y=e[13],t.z=e[14],t},u.getRotation=function(e,t){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t};var v=new s,_=new s,g=new t,y=new t(0,0,0,1);return u.inverse=function(e,r){if(s.equalsEpsilon(u.getRotation(e,v),_,a.EPSILON7)&&t.equals(u.getRow(e,3,g),y))return r[0]=0,r[1]=0,r[2]=0,r[3]=0,r[4]=0,r[5]=0,r[6]=0,r[7]=0,r[8]=0,r[9]=0,r[10]=0,r[11]=0,r[12]=-e[12],r[13]=-e[13],r[14]=-e[14],r[15]=1,r;var i=e[0],n=e[4],o=e[8],c=e[12],h=e[1],d=e[5],p=e[9],m=e[13],f=e[2],C=e[6],E=e[10],S=e[14],w=e[3],T=e[7],b=e[11],x=e[15],P=E*x,A=S*b,I=C*x,M=S*T,D=C*b,R=E*T,O=f*x,N=S*w,L=f*b,F=E*w,B=f*T,V=C*w,z=P*d+M*p+D*m-(A*d+I*p+R*m),k=A*h+O*p+F*m-(P*h+N*p+L*m),U=I*h+N*d+B*m-(M*h+O*d+V*m),G=R*h+L*d+V*p-(D*h+F*d+B*p),W=A*n+I*o+R*c-(P*n+M*o+D*c),H=P*i+N*o+L*c-(A*i+O*o+F*c),q=M*i+O*n+V*c-(I*i+N*n+B*c),j=D*i+F*n+B*o-(R*i+L*n+V*o);P=o*m,A=c*p,I=n*m,M=c*d,D=n*p,R=o*d,O=i*m,N=c*h,L=i*p,F=o*h,B=i*d,V=n*h;var Y=P*T+M*b+D*x-(A*T+I*b+R*x),X=A*w+O*b+F*x-(P*w+N*b+L*x),Z=I*w+N*T+B*x-(M*w+O*T+V*x),K=R*w+L*T+V*b-(D*w+F*T+B*b),J=I*E+R*S+A*C-(D*S+P*C+M*E),Q=L*S+P*f+N*E-(O*E+F*S+A*f),$=O*C+V*S+M*f-(B*S+I*f+N*C),ee=B*E+D*f+F*C-(L*C+V*E+R*f),te=i*z+n*k+o*U+c*G;if(Math.abs(te)d;d++){e.clone(t[d],n);var p=n.x,P=n.y,A=n.z;pl.x&&e.clone(n,l),Pu.y&&e.clone(n,u),Ac.z&&e.clone(n,c)}var I=e.magnitudeSquared(e.subtract(l,o,S)),M=e.magnitudeSquared(e.subtract(u,a,S)),D=e.magnitudeSquared(e.subtract(c,s,S)),R=o,O=l,N=I;M>N&&(N=M,R=a,O=u),D>N&&(N=D,R=s,O=c);var L=w;L.x=.5*(R.x+O.x),L.y=.5*(R.y+O.y),L.z=.5*(R.z+O.z);var F=e.magnitudeSquared(e.subtract(O,L,S)),B=Math.sqrt(F),V=T;V.x=o.x,V.y=a.y,V.z=s.z;var z=b;z.x=l.x,z.y=u.y,z.z=c.z;var k=e.multiplyByScalar(e.add(V,z,S),.5,x),U=0;for(d=0;h>d;d++){e.clone(t[d],n);var G=e.magnitude(e.subtract(n,k,S));G>U&&(U=G);var W=e.magnitudeSquared(e.subtract(n,L,S));if(W>F){var H=Math.sqrt(W);B=.5*(B+H),F=B*B;var q=H-B;L.x=(B*L.x+q*n.x)/H,L.y=(B*L.y+q*n.y)/H,L.z=(B*L.z+q*n.z)/H}}return U>B?(e.clone(L,r.center),r.radius=B):(e.clone(k,r.center),r.radius=U),r};var P=new s,A=new e,I=new e,M=new t,D=new t;m.fromRectangle2D=function(e,t,r){return m.fromRectangleWithHeights2D(e,t,0,0,r)},m.fromRectangleWithHeights2D=function(t,n,o,a,s){if(i(s)||(s=new m),!i(t))return s.center=e.clone(e.ZERO,s.center),s.radius=0,s;n=r(n,P),p.southwest(t,M),M.height=o,p.northeast(t,D),D.height=a;var l=n.project(M,A),u=n.project(D,I),c=u.x-l.x,h=u.y-l.y,d=u.z-l.z;s.radius=.5*Math.sqrt(c*c+h*h+d*d);var f=s.center;return f.x=l.x+.5*c,f.y=l.y+.5*h,f.z=l.z+.5*d,s};var R=[];m.fromRectangle3D=function(e,t,n,o){t=r(t,a.WGS84),n=r(n,0);var s;return i(e)&&(s=p.subsample(e,t,n,R)),m.fromPoints(s,o)},m.fromVertices=function(t,n,o,a){if(i(a)||(a=new m),!i(t)||0===t.length)return a.center=e.clone(e.ZERO,a.center),a.radius=0,a;n=r(n,e.ZERO),o=r(o,3);var s=E;s.x=t[0]+n.x,s.y=t[1]+n.y,s.z=t[2]+n.z;for(var l=e.clone(s,f),u=e.clone(s,v),c=e.clone(s,_),h=e.clone(s,g),d=e.clone(s,y),p=e.clone(s,C),P=t.length,A=0;P>A;A+=o){var I=t[A]+n.x,M=t[A+1]+n.y,D=t[A+2]+n.z;s.x=I,s.y=M,s.z=D,Ih.x&&e.clone(s,h),Md.y&&e.clone(s,d),Dp.z&&e.clone(s,p)}var R=e.magnitudeSquared(e.subtract(h,l,S)),O=e.magnitudeSquared(e.subtract(d,u,S)),N=e.magnitudeSquared(e.subtract(p,c,S)),L=l,F=h,B=R;O>B&&(B=O,L=u,F=d),N>B&&(B=N,L=c,F=p);var V=w;V.x=.5*(L.x+F.x),V.y=.5*(L.y+F.y),V.z=.5*(L.z+F.z);var z=e.magnitudeSquared(e.subtract(F,V,S)),k=Math.sqrt(z),U=T;U.x=l.x,U.y=u.y,U.z=c.z;var G=b;G.x=h.x,G.y=d.y,G.z=p.z;var W=e.multiplyByScalar(e.add(U,G,S),.5,x),H=0;for(A=0;P>A;A+=o){s.x=t[A]+n.x,s.y=t[A+1]+n.y,s.z=t[A+2]+n.z;var q=e.magnitude(e.subtract(s,W,S));q>H&&(H=q);var j=e.magnitudeSquared(e.subtract(s,V,S));if(j>z){var Y=Math.sqrt(j);k=.5*(k+Y),z=k*k;var X=Y-k;V.x=(k*V.x+X*s.x)/Y,V.y=(k*V.y+X*s.y)/Y,V.z=(k*V.z+X*s.z)/Y}}return H>k?(e.clone(V,a.center),a.radius=k):(e.clone(W,a.center),a.radius=H),a},m.fromCornerPoints=function(t,r,n){i(n)||(n=new m);var o=n.center;return e.add(t,r,o),e.multiplyByScalar(o,.5,o),n.radius=e.distance(o,r),n},m.fromEllipsoid=function(t,r){return i(r)||(r=new m),e.clone(e.ZERO,r.center),r.radius=t.maximumRadius,r};var O=new e;m.fromBoundingSpheres=function(t,r){if(i(r)||(r=new m),!i(t)||0===t.length)return r.center=e.clone(e.ZERO,r.center),r.radius=0,r;var n=t.length;if(1===n)return m.clone(t[0],r);if(2===n)return m.union(t[0],t[1],r);for(var o=[],a=0;n>a;a++)o.push(t[a].center);r=m.fromPoints(o,r);var s=r.center,l=r.radius;for(a=0;n>a;a++){var u=t[a];l=Math.max(l,e.distance(s,u.center,O)+u.radius)}return r.radius=l,r};var N=new e,L=new e,F=new e;m.fromOrientedBoundingBox=function(t,r){i(r)||(r=new m);var n=t.halfAxes,o=c.getColumn(n,0,N),a=c.getColumn(n,1,L),s=c.getColumn(n,2,F),l=e.magnitude(o),u=e.magnitude(a),h=e.magnitude(s);return r.center=e.clone(t.center,r.center),r.radius=Math.max(l,u,h),r},m.clone=function(t,r){return i(t)?i(r)?(r.center=e.clone(t.center,r.center),r.radius=t.radius,r):new m(t.center,t.radius):void 0},m.packedLength=4,m.pack=function(e,t,i){i=r(i,0);var n=e.center;t[i++]=n.x,t[i++]=n.y,t[i++]=n.z,t[i]=e.radius},m.unpack=function(e,t,n){t=r(t,0),i(n)||(n=new m);var o=n.center;return o.x=e[t++],o.y=e[t++],o.z=e[t++],n.radius=e[t],n};var B=new e,V=new e;m.union=function(t,r,n){i(n)||(n=new m);var o=t.center,a=t.radius,s=r.center,l=r.radius,u=e.subtract(s,o,B),c=e.magnitude(u);if(a>=c+l)return t.clone(n),n;if(l>=c+a)return r.clone(n),n;var h=.5*(a+c+l),d=e.multiplyByScalar(u,(-a+h)/c,V);return e.add(d,o,d),e.clone(d,n.center),n.radius=h,n};var z=new e;m.expand=function(t,r,i){i=m.clone(t,i);var n=e.magnitude(e.subtract(r,i.center,z));return n>i.radius&&(i.radius=n),i},m.intersectPlane=function(t,r){var i=t.center,n=t.radius,o=r.normal,a=e.dot(o,i)+r.distance;return-n>a?l.OUTSIDE:n>a?l.INTERSECTING:l.INSIDE},m.transform=function(e,t,r){return i(r)||(r=new m),r.center=h.multiplyByPoint(t,e.center,r.center),r.radius=h.getMaximumScale(t)*e.radius,r};var k=new e;m.distanceSquaredTo=function(t,r){var i=e.subtract(t.center,r,k);return e.magnitudeSquared(i)-t.radius*t.radius},m.transformWithoutScale=function(e,t,r){return i(r)||(r=new m),r.center=h.multiplyByPoint(t,e.center,r.center),r.radius=e.radius,r};var U=new e;m.computePlaneDistances=function(t,r,n,o){i(o)||(o=new u);var a=e.subtract(t.center,r,U),s=e.dot(n,a);return o.start=s-t.radius,o.stop=s+t.radius,o};for(var G=new e,W=new e,H=new e,q=new e,j=new e,Y=new t,X=new Array(8),Z=0;8>Z;++Z)X[Z]=new e;var K=new s;return m.projectTo2D=function(t,i,n){i=r(i,K);var o=i.ellipsoid,a=t.center,s=t.radius,l=o.geodeticSurfaceNormal(a,G),u=e.cross(e.UNIT_Z,l,W);e.normalize(u,u);var c=e.cross(l,u,H);e.normalize(c,c),e.multiplyByScalar(l,s,l),e.multiplyByScalar(c,s,c),e.multiplyByScalar(u,s,u);var h=e.negate(c,j),d=e.negate(u,q),p=X,f=p[0];e.add(l,c,f),e.add(f,u,f),f=p[1],e.add(l,c,f),e.add(f,d,f),f=p[2],e.add(l,h,f),e.add(f,d,f),f=p[3],e.add(l,h,f),e.add(f,u,f),e.negate(l,l),f=p[4],e.add(l,c,f),e.add(f,u,f),f=p[5],e.add(l,c,f),e.add(f,d,f),f=p[6],e.add(l,h,f),e.add(f,d,f),f=p[7],e.add(l,h,f),e.add(f,u,f);for(var v=p.length,_=0;v>_;++_){var g=p[_];e.add(a,g,g);var y=o.cartesianToCartographic(g,Y);i.project(y,g)}n=m.fromPoints(p,n),a=n.center;var C=a.x,E=a.y,S=a.z;return a.x=S,a.y=C,a.z=E,n},m.isOccluded=function(e,t){return!t.isBoundingSphereVisible(e)},m.equals=function(t,r){return t===r||i(t)&&i(r)&&e.equals(t.center,r.center)&&t.radius===r.radius},m.prototype.intersectPlane=function(e){return m.intersectPlane(this,e)},m.prototype.distanceSquaredTo=function(e){return m.distanceSquaredTo(this,e)},m.prototype.computePlaneDistances=function(e,t,r){return m.computePlaneDistances(this,e,t,r)},m.prototype.isOccluded=function(e){return m.isOccluded(this,e)},m.prototype.equals=function(e){return m.equals(this,e)},m.prototype.clone=function(e){return m.clone(this,e)},m}),r("Renderer/WebGLConstants",["../Core/freezeObject"],function(e){"use strict";var t={DEPTH_BUFFER_BIT:256,STENCIL_BUFFER_BIT:1024,COLOR_BUFFER_BIT:16384,POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6,ZERO:0,ONE:1,SRC_COLOR:768,ONE_MINUS_SRC_COLOR:769,SRC_ALPHA:770,ONE_MINUS_SRC_ALPHA:771,DST_ALPHA:772,ONE_MINUS_DST_ALPHA:773,DST_COLOR:774,ONE_MINUS_DST_COLOR:775,SRC_ALPHA_SATURATE:776,FUNC_ADD:32774,BLEND_EQUATION:32777,BLEND_EQUATION_RGB:32777,BLEND_EQUATION_ALPHA:34877,FUNC_SUBTRACT:32778,FUNC_REVERSE_SUBTRACT:32779,BLEND_DST_RGB:32968,BLEND_SRC_RGB:32969,BLEND_DST_ALPHA:32970,BLEND_SRC_ALPHA:32971,CONSTANT_COLOR:32769,ONE_MINUS_CONSTANT_COLOR:32770,CONSTANT_ALPHA:32771,ONE_MINUS_CONSTANT_ALPHA:32772,BLEND_COLOR:32773,ARRAY_BUFFER:34962,ELEMENT_ARRAY_BUFFER:34963,ARRAY_BUFFER_BINDING:34964,ELEMENT_ARRAY_BUFFER_BINDING:34965,STREAM_DRAW:35040,STATIC_DRAW:35044,DYNAMIC_DRAW:35048,BUFFER_SIZE:34660,BUFFER_USAGE:34661,CURRENT_VERTEX_ATTRIB:34342,FRONT:1028,BACK:1029,FRONT_AND_BACK:1032,CULL_FACE:2884,BLEND:3042,DITHER:3024,STENCIL_TEST:2960,DEPTH_TEST:2929,SCISSOR_TEST:3089,POLYGON_OFFSET_FILL:32823,SAMPLE_ALPHA_TO_COVERAGE:32926,SAMPLE_COVERAGE:32928,NO_ERROR:0,INVALID_ENUM:1280,INVALID_VALUE:1281,INVALID_OPERATION:1282,OUT_OF_MEMORY:1285,CW:2304,CCW:2305,LINE_WIDTH:2849,ALIASED_POINT_SIZE_RANGE:33901,ALIASED_LINE_WIDTH_RANGE:33902,CULL_FACE_MODE:2885,FRONT_FACE:2886,DEPTH_RANGE:2928,DEPTH_WRITEMASK:2930,DEPTH_CLEAR_VALUE:2931,DEPTH_FUNC:2932,STENCIL_CLEAR_VALUE:2961,STENCIL_FUNC:2962,STENCIL_FAIL:2964,STENCIL_PASS_DEPTH_FAIL:2965,STENCIL_PASS_DEPTH_PASS:2966,STENCIL_REF:2967,STENCIL_VALUE_MASK:2963,STENCIL_WRITEMASK:2968,STENCIL_BACK_FUNC:34816,STENCIL_BACK_FAIL:34817,STENCIL_BACK_PASS_DEPTH_FAIL:34818,STENCIL_BACK_PASS_DEPTH_PASS:34819,STENCIL_BACK_REF:36003,STENCIL_BACK_VALUE_MASK:36004,STENCIL_BACK_WRITEMASK:36005,VIEWPORT:2978,SCISSOR_BOX:3088,COLOR_CLEAR_VALUE:3106,COLOR_WRITEMASK:3107,UNPACK_ALIGNMENT:3317,PACK_ALIGNMENT:3333,MAX_TEXTURE_SIZE:3379,MAX_VIEWPORT_DIMS:3386,SUBPIXEL_BITS:3408,RED_BITS:3410,GREEN_BITS:3411,BLUE_BITS:3412,ALPHA_BITS:3413,DEPTH_BITS:3414,STENCIL_BITS:3415,POLYGON_OFFSET_UNITS:10752,POLYGON_OFFSET_FACTOR:32824,TEXTURE_BINDING_2D:32873,SAMPLE_BUFFERS:32936,SAMPLES:32937,SAMPLE_COVERAGE_VALUE:32938,SAMPLE_COVERAGE_INVERT:32939,COMPRESSED_TEXTURE_FORMATS:34467,DONT_CARE:4352,FASTEST:4353,NICEST:4354,GENERATE_MIPMAP_HINT:33170,BYTE:5120,UNSIGNED_BYTE:5121,SHORT:5122,UNSIGNED_SHORT:5123,INT:5124,UNSIGNED_INT:5125,FLOAT:5126,DEPTH_COMPONENT:6402,ALPHA:6406,RGB:6407,RGBA:6408,LUMINANCE:6409,LUMINANCE_ALPHA:6410,UNSIGNED_SHORT_4_4_4_4:32819,UNSIGNED_SHORT_5_5_5_1:32820,UNSIGNED_SHORT_5_6_5:33635,FRAGMENT_SHADER:35632,VERTEX_SHADER:35633,MAX_VERTEX_ATTRIBS:34921,MAX_VERTEX_UNIFORM_VECTORS:36347,MAX_VARYING_VECTORS:36348,MAX_COMBINED_TEXTURE_IMAGE_UNITS:35661,MAX_VERTEX_TEXTURE_IMAGE_UNITS:35660,MAX_TEXTURE_IMAGE_UNITS:34930,MAX_FRAGMENT_UNIFORM_VECTORS:36349,SHADER_TYPE:35663,DELETE_STATUS:35712,LINK_STATUS:35714,VALIDATE_STATUS:35715,ATTACHED_SHADERS:35717,ACTIVE_UNIFORMS:35718,ACTIVE_ATTRIBUTES:35721,SHADING_LANGUAGE_VERSION:35724,CURRENT_PROGRAM:35725,NEVER:512,LESS:513,EQUAL:514,LEQUAL:515,GREATER:516,NOTEQUAL:517,GEQUAL:518,ALWAYS:519,KEEP:7680,REPLACE:7681,INCR:7682,DECR:7683,INVERT:5386,INCR_WRAP:34055,DECR_WRAP:34056,VENDOR:7936,RENDERER:7937,VERSION:7938,NEAREST:9728,LINEAR:9729,NEAREST_MIPMAP_NEAREST:9984,LINEAR_MIPMAP_NEAREST:9985,NEAREST_MIPMAP_LINEAR:9986,LINEAR_MIPMAP_LINEAR:9987,TEXTURE_MAG_FILTER:10240,TEXTURE_MIN_FILTER:10241,TEXTURE_WRAP_S:10242,TEXTURE_WRAP_T:10243,TEXTURE_2D:3553,TEXTURE:5890,TEXTURE_CUBE_MAP:34067,TEXTURE_BINDING_CUBE_MAP:34068,TEXTURE_CUBE_MAP_POSITIVE_X:34069,TEXTURE_CUBE_MAP_NEGATIVE_X:34070,TEXTURE_CUBE_MAP_POSITIVE_Y:34071,TEXTURE_CUBE_MAP_NEGATIVE_Y:34072,TEXTURE_CUBE_MAP_POSITIVE_Z:34073,TEXTURE_CUBE_MAP_NEGATIVE_Z:34074,MAX_CUBE_MAP_TEXTURE_SIZE:34076,TEXTURE0:33984,TEXTURE1:33985,TEXTURE2:33986,TEXTURE3:33987,TEXTURE4:33988,TEXTURE5:33989,TEXTURE6:33990,TEXTURE7:33991,TEXTURE8:33992,TEXTURE9:33993,TEXTURE10:33994,TEXTURE11:33995,TEXTURE12:33996,TEXTURE13:33997,TEXTURE14:33998,TEXTURE15:33999,TEXTURE16:34e3,TEXTURE17:34001,TEXTURE18:34002,TEXTURE19:34003,TEXTURE20:34004,TEXTURE21:34005,TEXTURE22:34006,TEXTURE23:34007,TEXTURE24:34008,TEXTURE25:34009,TEXTURE26:34010,TEXTURE27:34011,TEXTURE28:34012,TEXTURE29:34013,TEXTURE30:34014,TEXTURE31:34015,ACTIVE_TEXTURE:34016,REPEAT:10497,CLAMP_TO_EDGE:33071,MIRRORED_REPEAT:33648, +FLOAT_VEC2:35664,FLOAT_VEC3:35665,FLOAT_VEC4:35666,INT_VEC2:35667,INT_VEC3:35668,INT_VEC4:35669,BOOL:35670,BOOL_VEC2:35671,BOOL_VEC3:35672,BOOL_VEC4:35673,FLOAT_MAT2:35674,FLOAT_MAT3:35675,FLOAT_MAT4:35676,SAMPLER_2D:35678,SAMPLER_CUBE:35680,VERTEX_ATTRIB_ARRAY_ENABLED:34338,VERTEX_ATTRIB_ARRAY_SIZE:34339,VERTEX_ATTRIB_ARRAY_STRIDE:34340,VERTEX_ATTRIB_ARRAY_TYPE:34341,VERTEX_ATTRIB_ARRAY_NORMALIZED:34922,VERTEX_ATTRIB_ARRAY_POINTER:34373,VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:34975,IMPLEMENTATION_COLOR_READ_TYPE:35738,IMPLEMENTATION_COLOR_READ_FORMAT:35739,COMPILE_STATUS:35713,LOW_FLOAT:36336,MEDIUM_FLOAT:36337,HIGH_FLOAT:36338,LOW_INT:36339,MEDIUM_INT:36340,HIGH_INT:36341,FRAMEBUFFER:36160,RENDERBUFFER:36161,RGBA4:32854,RGB5_A1:32855,RGB565:36194,DEPTH_COMPONENT16:33189,STENCIL_INDEX:6401,STENCIL_INDEX8:36168,DEPTH_STENCIL:34041,RENDERBUFFER_WIDTH:36162,RENDERBUFFER_HEIGHT:36163,RENDERBUFFER_INTERNAL_FORMAT:36164,RENDERBUFFER_RED_SIZE:36176,RENDERBUFFER_GREEN_SIZE:36177,RENDERBUFFER_BLUE_SIZE:36178,RENDERBUFFER_ALPHA_SIZE:36179,RENDERBUFFER_DEPTH_SIZE:36180,RENDERBUFFER_STENCIL_SIZE:36181,FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:36048,FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:36049,FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:36050,FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:36051,COLOR_ATTACHMENT0:36064,DEPTH_ATTACHMENT:36096,STENCIL_ATTACHMENT:36128,DEPTH_STENCIL_ATTACHMENT:33306,NONE:0,FRAMEBUFFER_COMPLETE:36053,FRAMEBUFFER_INCOMPLETE_ATTACHMENT:36054,FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:36055,FRAMEBUFFER_INCOMPLETE_DIMENSIONS:36057,FRAMEBUFFER_UNSUPPORTED:36061,FRAMEBUFFER_BINDING:36006,RENDERBUFFER_BINDING:36007,MAX_RENDERBUFFER_SIZE:34024,INVALID_FRAMEBUFFER_OPERATION:1286,UNPACK_FLIP_Y_WEBGL:37440,UNPACK_PREMULTIPLY_ALPHA_WEBGL:37441,CONTEXT_LOST_WEBGL:37442,UNPACK_COLORSPACE_CONVERSION_WEBGL:37443,BROWSER_DEFAULT_WEBGL:37444,DOUBLE:5130,READ_BUFFER:3074,UNPACK_ROW_LENGTH:3314,UNPACK_SKIP_ROWS:3315,UNPACK_SKIP_PIXELS:3316,PACK_ROW_LENGTH:3330,PACK_SKIP_ROWS:3331,PACK_SKIP_PIXELS:3332,COLOR:6144,DEPTH:6145,STENCIL:6146,RED:6403,RGB8:32849,RGBA8:32856,RGB10_A2:32857,TEXTURE_BINDING_3D:32874,UNPACK_SKIP_IMAGES:32877,UNPACK_IMAGE_HEIGHT:32878,TEXTURE_3D:32879,TEXTURE_WRAP_R:32882,MAX_3D_TEXTURE_SIZE:32883,UNSIGNED_INT_2_10_10_10_REV:33640,MAX_ELEMENTS_VERTICES:33e3,MAX_ELEMENTS_INDICES:33001,TEXTURE_MIN_LOD:33082,TEXTURE_MAX_LOD:33083,TEXTURE_BASE_LEVEL:33084,TEXTURE_MAX_LEVEL:33085,MIN:32775,MAX:32776,DEPTH_COMPONENT24:33190,MAX_TEXTURE_LOD_BIAS:34045,TEXTURE_COMPARE_MODE:34892,TEXTURE_COMPARE_FUNC:34893,CURRENT_QUERY:34917,QUERY_RESULT:34918,QUERY_RESULT_AVAILABLE:34919,STREAM_READ:35041,STREAM_COPY:35042,STATIC_READ:35045,STATIC_COPY:35046,DYNAMIC_READ:35049,DYNAMIC_COPY:35050,MAX_DRAW_BUFFERS:34852,DRAW_BUFFER0:34853,DRAW_BUFFER1:34854,DRAW_BUFFER2:34855,DRAW_BUFFER3:34856,DRAW_BUFFER4:34857,DRAW_BUFFER5:34858,DRAW_BUFFER6:34859,DRAW_BUFFER7:34860,DRAW_BUFFER8:34861,DRAW_BUFFER9:34862,DRAW_BUFFER10:34863,DRAW_BUFFER11:34864,DRAW_BUFFER12:34865,DRAW_BUFFER13:34866,DRAW_BUFFER14:34867,DRAW_BUFFER15:34868,MAX_FRAGMENT_UNIFORM_COMPONENTS:35657,MAX_VERTEX_UNIFORM_COMPONENTS:35658,SAMPLER_3D:35679,SAMPLER_2D_SHADOW:35682,FRAGMENT_SHADER_DERIVATIVE_HINT:35723,PIXEL_PACK_BUFFER:35051,PIXEL_UNPACK_BUFFER:35052,PIXEL_PACK_BUFFER_BINDING:35053,PIXEL_UNPACK_BUFFER_BINDING:35055,FLOAT_MAT2x3:35685,FLOAT_MAT2x4:35686,FLOAT_MAT3x2:35687,FLOAT_MAT3x4:35688,FLOAT_MAT4x2:35689,FLOAT_MAT4x3:35690,SRGB:35904,SRGB8:35905,SRGB8_ALPHA8:35907,COMPARE_REF_TO_TEXTURE:34894,RGBA32F:34836,RGB32F:34837,RGBA16F:34842,RGB16F:34843,VERTEX_ATTRIB_ARRAY_INTEGER:35069,MAX_ARRAY_TEXTURE_LAYERS:35071,MIN_PROGRAM_TEXEL_OFFSET:35076,MAX_PROGRAM_TEXEL_OFFSET:35077,MAX_VARYING_COMPONENTS:35659,TEXTURE_2D_ARRAY:35866,TEXTURE_BINDING_2D_ARRAY:35869,R11F_G11F_B10F:35898,UNSIGNED_INT_10F_11F_11F_REV:35899,RGB9_E5:35901,UNSIGNED_INT_5_9_9_9_REV:35902,TRANSFORM_FEEDBACK_BUFFER_MODE:35967,MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:35968,TRANSFORM_FEEDBACK_VARYINGS:35971,TRANSFORM_FEEDBACK_BUFFER_START:35972,TRANSFORM_FEEDBACK_BUFFER_SIZE:35973,TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:35976,RASTERIZER_DISCARD:35977,MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:35978,MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:35979,INTERLEAVED_ATTRIBS:35980,SEPARATE_ATTRIBS:35981,TRANSFORM_FEEDBACK_BUFFER:35982,TRANSFORM_FEEDBACK_BUFFER_BINDING:35983,RGBA32UI:36208,RGB32UI:36209,RGBA16UI:36214,RGB16UI:36215,RGBA8UI:36220,RGB8UI:36221,RGBA32I:36226,RGB32I:36227,RGBA16I:36232,RGB16I:36233,RGBA8I:36238,RGB8I:36239,RED_INTEGER:36244,RGB_INTEGER:36248,RGBA_INTEGER:36249,SAMPLER_2D_ARRAY:36289,SAMPLER_2D_ARRAY_SHADOW:36292,SAMPLER_CUBE_SHADOW:36293,UNSIGNED_INT_VEC2:36294,UNSIGNED_INT_VEC3:36295,UNSIGNED_INT_VEC4:36296,INT_SAMPLER_2D:36298,INT_SAMPLER_3D:36299,INT_SAMPLER_CUBE:36300,INT_SAMPLER_2D_ARRAY:36303,UNSIGNED_INT_SAMPLER_2D:36306,UNSIGNED_INT_SAMPLER_3D:36307,UNSIGNED_INT_SAMPLER_CUBE:36308,UNSIGNED_INT_SAMPLER_2D_ARRAY:36311,DEPTH_COMPONENT32F:36012,DEPTH32F_STENCIL8:36013,FLOAT_32_UNSIGNED_INT_24_8_REV:36269,FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:33296,FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:33297,FRAMEBUFFER_ATTACHMENT_RED_SIZE:33298,FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:33299,FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:33300,FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:33301,FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:33302,FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:33303,FRAMEBUFFER_DEFAULT:33304,UNSIGNED_INT_24_8:34042,DEPTH24_STENCIL8:35056,UNSIGNED_NORMALIZED:35863,DRAW_FRAMEBUFFER_BINDING:36006,READ_FRAMEBUFFER:36008,DRAW_FRAMEBUFFER:36009,READ_FRAMEBUFFER_BINDING:36010,RENDERBUFFER_SAMPLES:36011,FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:36052,MAX_COLOR_ATTACHMENTS:36063,COLOR_ATTACHMENT1:36065,COLOR_ATTACHMENT2:36066,COLOR_ATTACHMENT3:36067,COLOR_ATTACHMENT4:36068,COLOR_ATTACHMENT5:36069,COLOR_ATTACHMENT6:36070,COLOR_ATTACHMENT7:36071,COLOR_ATTACHMENT8:36072,COLOR_ATTACHMENT9:36073,COLOR_ATTACHMENT10:36074,COLOR_ATTACHMENT11:36075,COLOR_ATTACHMENT12:36076,COLOR_ATTACHMENT13:36077,COLOR_ATTACHMENT14:36078,COLOR_ATTACHMENT15:36079,FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:36182,MAX_SAMPLES:36183,HALF_FLOAT:5131,RG:33319,RG_INTEGER:33320,R8:33321,RG8:33323,R16F:33325,R32F:33326,RG16F:33327,RG32F:33328,R8I:33329,R8UI:33330,R16I:33331,R16UI:33332,R32I:33333,R32UI:33334,RG8I:33335,RG8UI:33336,RG16I:33337,RG16UI:33338,RG32I:33339,RG32UI:33340,VERTEX_ARRAY_BINDING:34229,R8_SNORM:36756,RG8_SNORM:36757,RGB8_SNORM:36758,RGBA8_SNORM:36759,SIGNED_NORMALIZED:36764,COPY_READ_BUFFER:36662,COPY_WRITE_BUFFER:36663,COPY_READ_BUFFER_BINDING:36662,COPY_WRITE_BUFFER_BINDING:36663,UNIFORM_BUFFER:35345,UNIFORM_BUFFER_BINDING:35368,UNIFORM_BUFFER_START:35369,UNIFORM_BUFFER_SIZE:35370,MAX_VERTEX_UNIFORM_BLOCKS:35371,MAX_FRAGMENT_UNIFORM_BLOCKS:35373,MAX_COMBINED_UNIFORM_BLOCKS:35374,MAX_UNIFORM_BUFFER_BINDINGS:35375,MAX_UNIFORM_BLOCK_SIZE:35376,MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:35377,MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:35379,UNIFORM_BUFFER_OFFSET_ALIGNMENT:35380,ACTIVE_UNIFORM_BLOCKS:35382,UNIFORM_TYPE:35383,UNIFORM_SIZE:35384,UNIFORM_BLOCK_INDEX:35386,UNIFORM_OFFSET:35387,UNIFORM_ARRAY_STRIDE:35388,UNIFORM_MATRIX_STRIDE:35389,UNIFORM_IS_ROW_MAJOR:35390,UNIFORM_BLOCK_BINDING:35391,UNIFORM_BLOCK_DATA_SIZE:35392,UNIFORM_BLOCK_ACTIVE_UNIFORMS:35394,UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:35395,UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:35396,UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:35398,INVALID_INDEX:4294967295,MAX_VERTEX_OUTPUT_COMPONENTS:37154,MAX_FRAGMENT_INPUT_COMPONENTS:37157,MAX_SERVER_WAIT_TIMEOUT:37137,OBJECT_TYPE:37138,SYNC_CONDITION:37139,SYNC_STATUS:37140,SYNC_FLAGS:37141,SYNC_FENCE:37142,SYNC_GPU_COMMANDS_COMPLETE:37143,UNSIGNALED:37144,SIGNALED:37145,ALREADY_SIGNALED:37146,TIMEOUT_EXPIRED:37147,CONDITION_SATISFIED:37148,WAIT_FAILED:37149,SYNC_FLUSH_COMMANDS_BIT:1,VERTEX_ATTRIB_ARRAY_DIVISOR:35070,ANY_SAMPLES_PASSED:35887,ANY_SAMPLES_PASSED_CONSERVATIVE:36202,SAMPLER_BINDING:35097,RGB10_A2UI:36975,INT_2_10_10_10_REV:36255,TRANSFORM_FEEDBACK:36386,TRANSFORM_FEEDBACK_PAUSED:36387,TRANSFORM_FEEDBACK_ACTIVE:36388,TRANSFORM_FEEDBACK_BINDING:36389,COMPRESSED_R11_EAC:37488,COMPRESSED_SIGNED_R11_EAC:37489,COMPRESSED_RG11_EAC:37490,COMPRESSED_SIGNED_RG11_EAC:37491,COMPRESSED_RGB8_ETC2:37492,COMPRESSED_SRGB8_ETC2:37493,COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:37494,COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:37495,COMPRESSED_RGBA8_ETC2_EAC:37496,COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:37497,TEXTURE_IMMUTABLE_FORMAT:37167,MAX_ELEMENT_INDEX:36203,TEXTURE_IMMUTABLE_LEVELS:33503};return e(t)}),r("Core/Fullscreen",["./defined","./defineProperties"],function(e,t){"use strict";var r,i={requestFullscreen:void 0,exitFullscreen:void 0,fullscreenEnabled:void 0,fullscreenElement:void 0,fullscreenchange:void 0,fullscreenerror:void 0},n={};return t(n,{element:{get:function(){return n.supportsFullscreen()?document[i.fullscreenElement]:void 0}},changeEventName:{get:function(){return n.supportsFullscreen()?i.fullscreenchange:void 0}},errorEventName:{get:function(){return n.supportsFullscreen()?i.fullscreenerror:void 0}},enabled:{get:function(){return n.supportsFullscreen()?document[i.fullscreenEnabled]:void 0}},fullscreen:{get:function(){return n.supportsFullscreen()?null!==n.element:void 0}}}),n.supportsFullscreen=function(){if(e(r))return r;r=!1;var t=document.body;if("function"==typeof t.requestFullscreen)return i.requestFullscreen="requestFullscreen",i.exitFullscreen="exitFullscreen",i.fullscreenEnabled="fullscreenEnabled",i.fullscreenElement="fullscreenElement",i.fullscreenchange="fullscreenchange",i.fullscreenerror="fullscreenerror",r=!0;for(var n,o=["webkit","moz","o","ms","khtml"],a=0,s=o.length;s>a;++a){var l=o[a];n=l+"RequestFullscreen","function"==typeof t[n]?(i.requestFullscreen=n,r=!0):(n=l+"RequestFullScreen","function"==typeof t[n]&&(i.requestFullscreen=n,r=!0)),n=l+"ExitFullscreen","function"==typeof document[n]?i.exitFullscreen=n:(n=l+"CancelFullScreen","function"==typeof document[n]&&(i.exitFullscreen=n)),n=l+"FullscreenEnabled",e(document[n])?i.fullscreenEnabled=n:(n=l+"FullScreenEnabled",e(document[n])&&(i.fullscreenEnabled=n)),n=l+"FullscreenElement",e(document[n])?i.fullscreenElement=n:(n=l+"FullScreenElement",e(document[n])&&(i.fullscreenElement=n)),n=l+"fullscreenchange",e(document["on"+n])&&("ms"===l&&(n="MSFullscreenChange"),i.fullscreenchange=n),n=l+"fullscreenerror",e(document["on"+n])&&("ms"===l&&(n="MSFullscreenError"),i.fullscreenerror=n)}return r},n.requestFullscreen=function(e){n.supportsFullscreen()&&e[i.requestFullscreen]()},n.exitFullscreen=function(){n.supportsFullscreen()&&document[i.exitFullscreen]()},n}),r("Core/FeatureDetection",["./defaultValue","./defined","./Fullscreen"],function(e,t,r){"use strict";function i(e){for(var t=e.split("."),r=0,i=t.length;i>r;++r)t[r]=parseInt(t[r],10);return t}function n(){if(!t(v)){v=!1;var e=/ Chrome\/([\.0-9]+)/.exec(navigator.userAgent);null!==e&&(v=!0,_=i(e[1]))}return v}function o(){return n()&&_}function a(){if(!t(g)&&(g=!1,!n()&&/ Safari\/[\.0-9]+/.test(navigator.userAgent))){var e=/ Version\/([\.0-9]+)/.exec(navigator.userAgent);null!==e&&(g=!0,y=i(e[1]))}return g}function s(){return a()&&y}function l(){if(!t(C)){C=!1;var e=/ AppleWebKit\/([\.0-9]+)(\+?)/.exec(navigator.userAgent);null!==e&&(C=!0,E=i(e[1]),E.isNightly=!!e[2])}return C}function u(){return l()&&E}function c(){if(!t(S)){S=!1;var e;"Microsoft Internet Explorer"===navigator.appName?(e=/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(navigator.userAgent),null!==e&&(S=!0,w=i(e[1]))):"Netscape"===navigator.appName&&(e=/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(navigator.userAgent),null!==e&&(S=!0,w=i(e[1])))}return S}function h(){return c()&&w}function d(){if(!t(T)){T=!1;var e=/Firefox\/([\.0-9]+)/.exec(navigator.userAgent);null!==e&&(T=!0,b=i(e[1]))}return T}function p(){return t(x)||(x=/Windows/i.test(navigator.appVersion)),x}function m(){return d()&&b}function f(){return t(P)||(P=t(window.PointerEvent)&&(!t(window.navigator.pointerEnabled)||window.navigator.pointerEnabled)),P}var v,_,g,y,C,E,S,w,T,b,x,P,A={isChrome:n,chromeVersion:o,isSafari:a,safariVersion:s,isWebkit:l,webkitVersion:u,isInternetExplorer:c,internetExplorerVersion:h,isFirefox:d,firefoxVersion:m,isWindows:p,hardwareConcurrency:e(navigator.hardwareConcurrency,3),supportsPointerEvents:f};return A.supportsFullscreen=function(){return r.supportsFullscreen()},A.supportsTypedArrays=function(){return"undefined"!=typeof ArrayBuffer},A.supportsWebWorkers=function(){return"undefined"!=typeof Worker},A}),r("Core/ComponentDatatype",["../Renderer/WebGLConstants","./defaultValue","./defined","./DeveloperError","./FeatureDetection","./freezeObject"],function(e,t,r,i,n,o){"use strict";if(!n.supportsTypedArrays())return{};var a={BYTE:e.BYTE,UNSIGNED_BYTE:e.UNSIGNED_BYTE,SHORT:e.SHORT,UNSIGNED_SHORT:e.UNSIGNED_SHORT,FLOAT:e.FLOAT,DOUBLE:e.DOUBLE};return a.getSizeInBytes=function(e){switch(e){case a.BYTE:return Int8Array.BYTES_PER_ELEMENT;case a.UNSIGNED_BYTE:return Uint8Array.BYTES_PER_ELEMENT;case a.SHORT:return Int16Array.BYTES_PER_ELEMENT;case a.UNSIGNED_SHORT:return Uint16Array.BYTES_PER_ELEMENT;case a.FLOAT:return Float32Array.BYTES_PER_ELEMENT;case a.DOUBLE:return Float64Array.BYTES_PER_ELEMENT;default:throw new i("componentDatatype is not a valid value.")}},a.fromTypedArray=function(e){return e instanceof Int8Array?a.BYTE:e instanceof Uint8Array?a.UNSIGNED_BYTE:e instanceof Int16Array?a.SHORT:e instanceof Uint16Array?a.UNSIGNED_SHORT:e instanceof Float32Array?a.FLOAT:e instanceof Float64Array?a.DOUBLE:void 0},a.validate=function(e){return r(e)&&(e===a.BYTE||e===a.UNSIGNED_BYTE||e===a.SHORT||e===a.UNSIGNED_SHORT||e===a.FLOAT||e===a.DOUBLE)},a.createTypedArray=function(e,t){switch(e){case a.BYTE:return new Int8Array(t);case a.UNSIGNED_BYTE:return new Uint8Array(t);case a.SHORT:return new Int16Array(t);case a.UNSIGNED_SHORT:return new Uint16Array(t);case a.FLOAT:return new Float32Array(t);case a.DOUBLE:return new Float64Array(t);default:throw new i("componentDatatype is not a valid value.")}},a.createArrayBufferView=function(e,r,n,o){switch(n=t(n,0),o=t(o,(r.byteLength-n)/a.getSizeInBytes(e)),e){case a.BYTE:return new Int8Array(r,n,o);case a.UNSIGNED_BYTE:return new Uint8Array(r,n,o);case a.SHORT:return new Int16Array(r,n,o);case a.UNSIGNED_SHORT:return new Uint16Array(r,n,o);case a.FLOAT:return new Float32Array(r,n,o);case a.DOUBLE:return new Float64Array(r,n,o);default:throw new i("componentDatatype is not a valid value.")}},o(a)}),r("Core/GeometryType",["./freezeObject"],function(e){"use strict";var t={NONE:0,TRIANGLES:1,LINES:2,POLYLINES:3};return e(t)}),r("Core/PrimitiveType",["../Renderer/WebGLConstants","./freezeObject"],function(e,t){"use strict";var r={POINTS:e.POINTS,LINES:e.LINES,LINE_LOOP:e.LINE_LOOP,LINE_STRIP:e.LINE_STRIP,TRIANGLES:e.TRIANGLES,TRIANGLE_STRIP:e.TRIANGLE_STRIP,TRIANGLE_FAN:e.TRIANGLE_FAN,validate:function(e){return e===r.POINTS||e===r.LINES||e===r.LINE_LOOP||e===r.LINE_STRIP||e===r.TRIANGLES||e===r.TRIANGLE_STRIP||e===r.TRIANGLE_FAN}};return t(r)}),r("Core/Geometry",["./defaultValue","./defined","./DeveloperError","./GeometryType","./PrimitiveType"],function(e,t,r,i,n){"use strict";var o=function(t){t=e(t,e.EMPTY_OBJECT),this.attributes=t.attributes,this.indices=t.indices,this.primitiveType=e(t.primitiveType,n.TRIANGLES),this.boundingSphere=t.boundingSphere,this.geometryType=e(t.geometryType,i.NONE),this.boundingSphereCV=void 0};return o.computeNumberOfVertices=function(e){var i=-1;for(var n in e.attributes)if(e.attributes.hasOwnProperty(n)&&t(e.attributes[n])&&t(e.attributes[n].values)){var o=e.attributes[n],a=o.values.length/o.componentsPerAttribute;if(i!==a&&-1!==i)throw new r("All attribute lists must have the same number of attributes.");i=a}return i},o}),r("Core/GeometryAttribute",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t){t=e(t,e.EMPTY_OBJECT),this.componentDatatype=t.componentDatatype,this.componentsPerAttribute=t.componentsPerAttribute,this.normalize=e(t.normalize,!1),this.values=t.values};return i}),r("Core/GeometryAttributes",["./defaultValue"],function(e){"use strict";var t=function(t){t=e(t,e.EMPTY_OBJECT),this.position=t.position,this.normal=t.normal,this.st=t.st,this.binormal=t.binormal,this.tangent=t.tangent,this.color=t.color};return t}),r("Core/VertexFormat",["./defaultValue","./defined","./DeveloperError","./freezeObject"],function(e,t,r,i){"use strict";var n=function(t){t=e(t,e.EMPTY_OBJECT),this.position=e(t.position,!1),this.normal=e(t.normal,!1),this.st=e(t.st,!1),this.binormal=e(t.binormal,!1),this.tangent=e(t.tangent,!1),this.color=e(t.color,!1)};return n.POSITION_ONLY=i(new n({position:!0})),n.POSITION_AND_NORMAL=i(new n({position:!0,normal:!0})),n.POSITION_NORMAL_AND_ST=i(new n({position:!0,normal:!0,st:!0})),n.POSITION_AND_ST=i(new n({position:!0,st:!0})),n.POSITION_AND_COLOR=i(new n({position:!0,color:!0})),n.ALL=i(new n({position:!0,normal:!0,st:!0,binormal:!0,tangent:!0})),n.DEFAULT=n.POSITION_NORMAL_AND_ST,n.packedLength=6,n.pack=function(t,r,i){i=e(i,0),r[i++]=t.position?1:0,r[i++]=t.normal?1:0,r[i++]=t.st?1:0,r[i++]=t.binormal?1:0,r[i++]=t.tangent?1:0,r[i++]=t.color?1:0},n.unpack=function(r,i,o){return i=e(i,0),t(o)||(o=new n),o.position=1===r[i++],o.normal=1===r[i++],o.st=1===r[i++],o.binormal=1===r[i++],o.tangent=1===r[i++],o.color=1===r[i++],o},n.clone=function(e,r){return t(e)?(t(r)||(r=new n),r.position=e.position,r.normal=e.normal,r.st=e.st,r.binormal=e.binormal,r.tangent=e.tangent,r.color=e.color,r):void 0},n}),r("Core/BoxGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";var d=new t,p=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.minimum,a=e.maximum;!n(r)&&n(e.minimumCorner)&&(r=e.minimumCorner,o("BoxGeometry","options.minimumCorner is deprecated. Use options.minimum instead.")),!n(a)&&n(e.maximumCorner)&&(a=e.maximumCorner,o("BoxGeometry","options.maximumCorner is deprecated. Use options.maximum instead."));var s=i(e.vertexFormat,h.DEFAULT);this._minimum=t.clone(r),this._maximum=t.clone(a),this._vertexFormat=s,this._workerName="createBoxGeometry"};p.fromDimensions=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.dimensions,n=t.multiplyByScalar(r,.5,new t);return new p({minimum:t.negate(n,new t),maximum:n,vertexFormat:e.vertexFormat})},p.fromAxisAlignedBoundingBox=function(e){if(!n(e))throw new a("boundingBox is required.");return new p({minimum:e.minimum,maximum:e.maximum})},p.fromAxisAlignedBoundingBox=function(e){if(!n(e))throw new a("boundingBox is required.");return new p({minimum:e.minimum,maximum:e.maximum})},p.packedLength=2*t.packedLength+h.packedLength,p.pack=function(e,r,n){n=i(n,0),t.pack(e._minimum,r,n),t.pack(e._maximum,r,n+t.packedLength),h.pack(e._vertexFormat,r,n+2*t.packedLength)};var m=new t,f=new t,v=new h,_={minimum:m,maximum:f,vertexFormat:v};return p.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,m),s=t.unpack(e,r+t.packedLength,f),l=h.unpack(e,r+2*t.packedLength,v);return n(o)?(o._minimum=t.clone(a,o._minimum),o._maximum=t.clone(s,o._maximum),o._vertexFormat=h.clone(l,o._vertexFormat),o):new p(_)},p.createGeometry=function(i){var n,o,a=i._minimum,h=i._maximum,p=i._vertexFormat,m=new u;if(p.position&&(p.st||p.normal||p.binormal||p.tangent)){if(p.position&&(o=new Float64Array(72),o[0]=a.x,o[1]=a.y,o[2]=h.z,o[3]=h.x,o[4]=a.y,o[5]=h.z,o[6]=h.x,o[7]=h.y,o[8]=h.z,o[9]=a.x,o[10]=h.y,o[11]=h.z,o[12]=a.x,o[13]=a.y,o[14]=a.z,o[15]=h.x,o[16]=a.y,o[17]=a.z,o[18]=h.x,o[19]=h.y,o[20]=a.z,o[21]=a.x,o[22]=h.y,o[23]=a.z,o[24]=h.x,o[25]=a.y,o[26]=a.z,o[27]=h.x,o[28]=h.y,o[29]=a.z,o[30]=h.x,o[31]=h.y,o[32]=h.z,o[33]=h.x,o[34]=a.y,o[35]=h.z,o[36]=a.x,o[37]=a.y,o[38]=a.z,o[39]=a.x,o[40]=h.y,o[41]=a.z,o[42]=a.x,o[43]=h.y,o[44]=h.z,o[45]=a.x,o[46]=a.y,o[47]=h.z,o[48]=a.x,o[49]=h.y,o[50]=a.z,o[51]=h.x,o[52]=h.y,o[53]=a.z,o[54]=h.x,o[55]=h.y,o[56]=h.z,o[57]=a.x,o[58]=h.y,o[59]=h.z,o[60]=a.x,o[61]=a.y,o[62]=a.z,o[63]=h.x,o[64]=a.y,o[65]=a.z,o[66]=h.x,o[67]=a.y,o[68]=h.z,o[69]=a.x,o[70]=a.y,o[71]=h.z,m.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:o})),p.normal){var f=new Float32Array(72);f[0]=0,f[1]=0,f[2]=1,f[3]=0,f[4]=0,f[5]=1,f[6]=0,f[7]=0,f[8]=1,f[9]=0,f[10]=0,f[11]=1,f[12]=0,f[13]=0,f[14]=-1,f[15]=0,f[16]=0,f[17]=-1,f[18]=0,f[19]=0,f[20]=-1,f[21]=0,f[22]=0,f[23]=-1,f[24]=1,f[25]=0,f[26]=0,f[27]=1,f[28]=0,f[29]=0,f[30]=1,f[31]=0,f[32]=0,f[33]=1,f[34]=0,f[35]=0,f[36]=-1,f[37]=0,f[38]=0,f[39]=-1,f[40]=0,f[41]=0,f[42]=-1,f[43]=0,f[44]=0,f[45]=-1,f[46]=0,f[47]=0,f[48]=0,f[49]=1,f[50]=0,f[51]=0,f[52]=1,f[53]=0,f[54]=0,f[55]=1,f[56]=0,f[57]=0,f[58]=1,f[59]=0,f[60]=0,f[61]=-1,f[62]=0,f[63]=0,f[64]=-1,f[65]=0,f[66]=0,f[67]=-1,f[68]=0,f[69]=0,f[70]=-1,f[71]=0,m.normal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:f})}if(p.st){var v=new Float32Array(48);v[0]=0,v[1]=0,v[2]=1,v[3]=0,v[4]=1,v[5]=1,v[6]=0,v[7]=1,v[8]=1,v[9]=0,v[10]=0,v[11]=0,v[12]=0,v[13]=1,v[14]=1,v[15]=1,v[16]=0,v[17]=0,v[18]=1,v[19]=0,v[20]=1,v[21]=1,v[22]=0,v[23]=1,v[24]=1,v[25]=0,v[26]=0,v[27]=0,v[28]=0,v[29]=1,v[30]=1,v[31]=1,v[32]=1,v[33]=0,v[34]=0,v[35]=0,v[36]=0,v[37]=1,v[38]=1,v[39]=1,v[40]=0,v[41]=0,v[42]=1,v[43]=0,v[44]=1,v[45]=1,v[46]=0,v[47]=1,m.st=new l({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:v})}if(p.tangent){var _=new Float32Array(72);_[0]=1,_[1]=0,_[2]=0,_[3]=1,_[4]=0,_[5]=0,_[6]=1,_[7]=0,_[8]=0,_[9]=1,_[10]=0,_[11]=0,_[12]=-1,_[13]=0,_[14]=0,_[15]=-1,_[16]=0,_[17]=0,_[18]=-1,_[19]=0,_[20]=0,_[21]=-1,_[22]=0,_[23]=0,_[24]=0,_[25]=1,_[26]=0,_[27]=0,_[28]=1,_[29]=0,_[30]=0,_[31]=1,_[32]=0,_[33]=0,_[34]=1,_[35]=0,_[36]=0,_[37]=-1,_[38]=0,_[39]=0,_[40]=-1,_[41]=0,_[42]=0,_[43]=-1,_[44]=0,_[45]=0,_[46]=-1,_[47]=0,_[48]=-1,_[49]=0,_[50]=0,_[51]=-1,_[52]=0,_[53]=0,_[54]=-1,_[55]=0,_[56]=0,_[57]=-1,_[58]=0,_[59]=0,_[60]=1,_[61]=0,_[62]=0,_[63]=1,_[64]=0,_[65]=0,_[66]=1,_[67]=0,_[68]=0,_[69]=1,_[70]=0,_[71]=0,m.tangent=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:_})}if(p.binormal){var g=new Float32Array(72);g[0]=0,g[1]=1,g[2]=0,g[3]=0,g[4]=1,g[5]=0,g[6]=0,g[7]=1,g[8]=0,g[9]=0,g[10]=1,g[11]=0,g[12]=0,g[13]=1,g[14]=0,g[15]=0,g[16]=1,g[17]=0,g[18]=0,g[19]=1,g[20]=0,g[21]=0,g[22]=1,g[23]=0,g[24]=0,g[25]=0,g[26]=1,g[27]=0,g[28]=0,g[29]=1,g[30]=0,g[31]=0,g[32]=1,g[33]=0,g[34]=0,g[35]=1,g[36]=0,g[37]=0,g[38]=1,g[39]=0,g[40]=0,g[41]=1,g[42]=0,g[43]=0,g[44]=1,g[45]=0,g[46]=0,g[47]=1,g[48]=0,g[49]=0,g[50]=1,g[51]=0,g[52]=0,g[53]=1,g[54]=0,g[55]=0,g[56]=1,g[57]=0,g[58]=0,g[59]=1,g[60]=0,g[61]=0,g[62]=1,g[63]=0,g[64]=0,g[65]=1,g[66]=0,g[67]=0,g[68]=1,g[69]=0,g[70]=0,g[71]=1,m.binormal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:g})}n=new Uint16Array(36),n[0]=0,n[1]=1,n[2]=2,n[3]=0,n[4]=2,n[5]=3,n[6]=6,n[7]=5,n[8]=4,n[9]=7,n[10]=6,n[11]=4,n[12]=8,n[13]=9,n[14]=10,n[15]=8,n[16]=10,n[17]=11,n[18]=14,n[19]=13,n[20]=12,n[21]=15,n[22]=14,n[23]=12,n[24]=18,n[25]=17,n[26]=16,n[27]=19,n[28]=18,n[29]=16,n[30]=20,n[31]=21,n[32]=22,n[33]=20,n[34]=22,n[35]=23}else o=new Float64Array(24),o[0]=a.x,o[1]=a.y,o[2]=a.z,o[3]=h.x,o[4]=a.y,o[5]=a.z,o[6]=h.x,o[7]=h.y,o[8]=a.z,o[9]=a.x,o[10]=h.y,o[11]=a.z,o[12]=a.x,o[13]=a.y,o[14]=h.z,o[15]=h.x,o[16]=a.y,o[17]=h.z,o[18]=h.x,o[19]=h.y,o[20]=h.z,o[21]=a.x,o[22]=h.y,o[23]=h.z,m.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:o}),n=new Uint16Array(36),n[0]=4,n[1]=5,n[2]=6,n[3]=4,n[4]=6,n[5]=7,n[6]=1,n[7]=0,n[8]=3,n[9]=1,n[10]=3,n[11]=2,n[12]=1,n[13]=6,n[14]=5,n[15]=1,n[16]=2,n[17]=6,n[18]=2,n[19]=3,n[20]=7,n[21]=2,n[22]=7,n[23]=6,n[24]=3,n[25]=0,n[26]=4,n[27]=3,n[28]=4,n[29]=7,n[30]=0,n[31]=1,n[32]=5,n[33]=0,n[34]=5,n[35]=4;var y=t.subtract(h,a,d),C=.5*t.magnitude(y);return new s({attributes:m,indices:n,primitiveType:c.TRIANGLES,boundingSphere:new e(t.ZERO,C)})},p}),r("Core/BoxOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";var h=new t,d=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.minimum,a=e.maximum;!n(r)&&n(e.minimumCorner)&&(r=e.minimumCorner,o("BoxOutlineGeometry","options.minimumCorner is deprecated. Use options.minimum instead.")),!n(a)&&n(e.maximumCorner)&&(a=e.maximumCorner,o("BoxOutlineGeometry","options.maximumCorner is deprecated. Use options.maximum instead.")),this._min=t.clone(r),this._max=t.clone(a),this._workerName="createBoxOutlineGeometry"};d.fromDimensions=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.dimensions,n=t.multiplyByScalar(r,.5,new t);return new d({minimum:t.negate(n,new t),maximum:n})},d.fromAxisAlignedBoundingBox=function(e){if(!n(e))throw new a("boundingBox is required.");return new d({minimum:e.minimum,maximum:e.maximum})},d.packedLength=2*t.packedLength,d.pack=function(e,r,n){n=i(n,0),t.pack(e._min,r,n),t.pack(e._max,r,n+t.packedLength)};var p=new t,m=new t,f={minimum:p,maximum:m};return d.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,p),s=t.unpack(e,r+t.packedLength,m);return n(o)?(o._min=t.clone(a,o._min),o._max=t.clone(s,o._max),o):new d(f)},d.createGeometry=function(i){var n=i._min,o=i._max,a=new u,d=new Uint16Array(24),p=new Float64Array(24);p[0]=n.x,p[1]=n.y,p[2]=n.z,p[3]=o.x,p[4]=n.y,p[5]=n.z,p[6]=o.x,p[7]=o.y,p[8]=n.z,p[9]=n.x,p[10]=o.y,p[11]=n.z,p[12]=n.x,p[13]=n.y,p[14]=o.z,p[15]=o.x,p[16]=n.y,p[17]=o.z,p[18]=o.x,p[19]=o.y,p[20]=o.z,p[21]=n.x,p[22]=o.y,p[23]=o.z,a.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:p}),d[0]=4,d[1]=5,d[2]=5,d[3]=6,d[4]=6,d[5]=7,d[6]=7,d[7]=4,d[8]=0,d[9]=1,d[10]=1,d[11]=2,d[12]=2,d[13]=3,d[14]=3,d[15]=0,d[16]=0,d[17]=4,d[18]=1,d[19]=5,d[20]=2,d[21]=6,d[22]=3,d[23]=7;var m=t.subtract(o,n,h),f=.5*t.magnitude(m);return new s({attributes:a,indices:d,primitiveType:c.LINES,boundingSphere:new e(t.ZERO,f)})},d}),r("Core/Spline",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this.times=void 0,this.points=void 0,r.throwInstantiationError()};return i.prototype.evaluate=r.throwInstantiationError,i.prototype.findTimeInterval=function(t,r){var i=this.times,n=i.length;if(r=e(r,0),t>=i[r]){if(n>r+1&&tr+2&&t=0&&t>=i[r-1])return r-1;var o;if(t>i[r])for(o=r;n-1>o&&!(t>=i[o]&&t=0&&!(t>=i[o]&&t=0;--o)l[o]=e.subtract(s[o],e.multiplyByScalar(l[o+1],a[o],l[o]),l[o]);return l},i}),r("Core/HermiteSpline",["./Cartesian3","./Cartesian4","./defaultValue","./defined","./defineProperties","./DeveloperError","./LinearSpline","./Matrix4","./Spline","./TridiagonalSystemSolver"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(t,r,n){var o=d,a=m,s=p,l=f;o.length=a.length=t.length-1,s.length=l.length=t.length;var c;o[0]=s[0]=1,a[0]=0;var h=l[0];for(i(h)||(h=l[0]=new e),e.clone(r,h),c=1;c2&&(i(a)||(a=p,e.multiplyByScalar(n[1],2,a),e.subtract(a,n[2],a),e.subtract(a,n[0],a),e.multiplyByScalar(a,.5,a)),!i(s))){var l=n.length-1;s=m,e.multiplyByScalar(n[l-1],2,s),e.subtract(n[l],s,s),e.add(s,n[l-2],s),e.multiplyByScalar(s,.5,s)}this._times=o,this._points=n,this._firstTangent=e.clone(a),this._lastTangent=e.clone(s),this._evaluateFunction=u(this),this._lastTimeIndex=0};return n(f.prototype,{times:{get:function(){return this._times}},points:{get:function(){return this._points}},firstTangent:{get:function(){return this._firstTangent}},lastTangent:{get:function(){return this._lastTangent}}}),f.catmullRomCoefficientMatrix=new s(-.5,1,-.5,0,1.5,-2.5,0,1,-1.5,2,.5,0,.5,-.5,0,0),f.prototype.findTimeInterval=l.prototype.findTimeInterval,f.prototype.evaluate=function(e,t){return this._evaluateFunction(e,t)},f}),r("Core/IndexDatatype",["../Renderer/WebGLConstants","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o={UNSIGNED_BYTE:e.UNSIGNED_BYTE,UNSIGNED_SHORT:e.UNSIGNED_SHORT,UNSIGNED_INT:e.UNSIGNED_INT};return o.getSizeInBytes=function(e){switch(e){case o.UNSIGNED_BYTE:return Uint8Array.BYTES_PER_ELEMENT;case o.UNSIGNED_SHORT:return Uint16Array.BYTES_PER_ELEMENT;case o.UNSIGNED_INT:return Uint32Array.BYTES_PER_ELEMENT}},o.validate=function(e){return t(e)&&(e===o.UNSIGNED_BYTE||e===o.UNSIGNED_SHORT||e===o.UNSIGNED_INT)},o.createTypedArray=function(e,t){return e>=n.SIXTY_FOUR_KILOBYTES?new Uint32Array(t):new Uint16Array(t)},o.createTypedArrayFromArrayBuffer=function(e,t,r,i){return e>=n.SIXTY_FOUR_KILOBYTES?new Uint32Array(t,r,i):new Uint16Array(t,r,i)},i(o)}),r("Core/definedNotNull",[],function(){"use strict";var e=function(e){return void 0!==e&&null!==e};return e}),r("Core/joinUrls",["../ThirdParty/Uri","./defaultValue","./defined","./definedNotNull","./DeveloperError"],function(e,t,r,i,n){"use strict";var o=function(n,o,a){a=t(a,!0),n instanceof e||(n=new e(n)),o instanceof e||(o=new e(o)),i(o.authority)&&!i(o.scheme)&&("undefined"!=typeof document&&r(document.location)&&r(document.location.href)?o.scheme=new e(document.location.href).scheme:o.scheme=n.scheme);var s=n;o.isAbsolute()&&(s=o);var l="";i(s.scheme)&&(l+=s.scheme+":"),i(s.authority)&&(l+="//"+s.authority,""!==s.path&&(l=l.replace(/\/?$/,"/"),s.path=s.path.replace(/^\/?/g,""))),l+=s===n?a?n.path.replace(/\/?$/,"/")+o.path.replace(/^\/?/g,""):n.path+o.path:o.path;var u=i(n.query),c=i(o.query);u&&c?l+="?"+n.query+"&"+o.query:u&&!c?l+="?"+n.query:!u&&c&&(l+="?"+o.query);var h=i(o.fragment);return i(n.fragment)&&!h?l+="#"+n.fragment:h&&(l+="#"+o.fragment),l};return o}),r("Core/parseResponseHeaders",[],function(){"use strict";var e=function(e){var t={};if(!e)return t;for(var r=e.split("\r\n"),i=0;i0){var a=n.substring(0,o),s=n.substring(o+2);t[a]=s}}return t};return e}),r("Core/RequestErrorEvent",["./defined","./parseResponseHeaders"],function(e,t){"use strict";var r=function(e,r,i){this.statusCode=e,this.response=r,this.responseHeaders=i,"string"==typeof this.responseHeaders&&(this.responseHeaders=t(this.responseHeaders))};return r.prototype.toString=function(){var t="Request has failed.";return e(this.statusCode)&&(t+=" Status Code: "+this.statusCode),t},r}),r("Core/loadWithXhr",["../ThirdParty/when","./defaultValue","./defined","./DeveloperError","./RequestErrorEvent","./RuntimeError"],function(e,t,r,i,n,o){"use strict";function a(e,t){var r=decodeURIComponent(t);return e?atob(r):r}function s(e,t){for(var r=a(e,t),i=new ArrayBuffer(r.length),n=new Uint8Array(i),o=0;oa&&a/ss&&s/ao)return[];var l=Math.sqrt(o);return[-l,l]}if(0===n)return o=-i/e,0>o?[o,0]:[0,o];var u=i*i,c=4*e*n,h=r(u,-c,t.EPSILON14);if(0>h)return[];var d=-.5*r(i,t.sign(i)*Math.sqrt(h),t.EPSILON14);return i>0?[d/e,n/d]:[n/d,d/e]},i}),r("Core/CubicRealPolynomial",["./DeveloperError","./QuadraticRealPolynomial"],function(e,t){"use strict";function r(e,t,r,i){var n,o,a=e,s=t/3,l=r/3,u=i,c=a*l,h=s*u,d=s*s,p=l*l,m=a*l-d,f=a*u-s*l,v=s*u-p,_=4*m*v-f*f;if(0>_){var g,y,C;d*h>=c*p?(g=a,y=m,C=-2*s*m+a*f):(g=u,y=v,C=-u*f+2*l*v);var E=0>C?-1:1,S=-E*Math.abs(g)*Math.sqrt(-_);o=-C+S;var w=o/2,T=0>w?-Math.pow(-w,1/3):Math.pow(w,1/3),b=o===S?-T:-y/T;return n=0>=y?T+b:-C/(T*T+b*b+y),d*h>=c*p?[(n-s)/a]:[-u/(n+l)]}var x=m,P=-2*s*m+a*f,A=v,I=-u*f+2*l*v,M=Math.sqrt(_),D=Math.sqrt(3)/2,R=Math.abs(Math.atan2(a*M,-P)/3);n=2*Math.sqrt(-x);var O=Math.cos(R);o=n*O;var N=n*(-O/2-D*Math.sin(R)),L=o+N>2*s?o-s:N-s,F=a,B=L/F;R=Math.abs(Math.atan2(u*M,-I)/3),n=2*Math.sqrt(-A),O=Math.cos(R),o=n*O,N=n*(-O/2-D*Math.sin(R));var V=-u,z=2*l>o+N?o+l:N+l,k=V/z,U=F*z,G=-L*z-F*V,W=L*V,H=(l*G-s*W)/(-s*G+l*U);return H>=B?k>=B?k>=H?[B,H,k]:[B,k,H]:[k,B,H]:k>=B?[H,B,k]:k>=H?[H,k,B]:[k,H,B]}var i={};return i.computeDiscriminant=function(e,t,r,i){var n=e*e,o=t*t,a=r*r,s=i*i,l=18*e*t*r*i+o*a-27*n*s-4*(e*a*r+o*t*i);return l},i.computeRealRoots=function(e,i,n,o){var a,s;if(0===e)return t.computeRealRoots(i,n,o);if(0===i){if(0===n){if(0===o)return[0,0,0];s=-o/e;var l=0>s?-Math.pow(-s,1/3):Math.pow(s,1/3);return[l,l,l]}return 0===o?(a=t.computeRealRoots(e,0,n),0===a.Length?[0]:[a[0],0,a[1]]):r(e,0,n,o)}return 0===n?0===o?(s=-i/e,0>s?[s,0,0]:[0,0,s]):r(e,i,0,o):0===o?(a=t.computeRealRoots(e,i,n),0===a.length?[0]:a[1]<=0?[a[0],a[1],0]:a[0]>=0?[0,a[0],a[1]]:[a[0],0,a[1]]):r(e,i,n,o)},i}),r("Core/QuarticRealPolynomial",["./CubicRealPolynomial","./DeveloperError","./Math","./QuadraticRealPolynomial"],function(e,t,r,i){"use strict";function n(t,n,o,a){var s=t*t,l=n-3*s/8,u=o-n*t/2+s*t/8,c=a-o*t/4+n*s/16-3*s*s/256,h=e.computeRealRoots(1,2*l,l*l-4*c,-u*u);if(h.length>0){var d=-t/4,p=h[h.length-1];if(Math.abs(p)=0&&_>=0){var g=Math.sqrt(v),y=Math.sqrt(_);return[d-y,d-g,d+g,d+y]}if(v>=0&&0>_)return f=Math.sqrt(v),[d-f,d+f];if(0>v&&_>=0)return f=Math.sqrt(_),[d-f,d+f]}return[]}if(p>0){var C=Math.sqrt(p),E=(l+p-u/C)/2,S=(l+p+u/C)/2,w=i.computeRealRoots(1,C,E),T=i.computeRealRoots(1,-C,S);return 0!==w.length?(w[0]+=d,w[1]+=d,0!==T.length?(T[0]+=d,T[1]+=d,w[1]<=T[0]?[w[0],w[1],T[0],T[1]]:T[1]<=w[0]?[T[0],T[1],w[0],w[1]]:w[0]>=T[0]&&w[1]<=T[1]?[T[0],w[0],w[1],T[1]]:T[0]>=w[0]&&T[1]<=w[1]?[w[0],T[0],T[1],w[1]]:w[0]>T[0]&&w[0]0){var m,f,v=p[0],_=n-v,g=_*_,y=t/2,C=_/2,E=g-4*a,S=g+4*Math.abs(a),w=u-4*v,T=u+4*Math.abs(v);if(0>v||w*S>E*T){var b=Math.sqrt(w);m=b/2,f=0===b?0:(t*C-o)/b}else{var x=Math.sqrt(E);m=0===x?0:(t*C-o)/x,f=x/2}var P,A;0===y&&0===m?(P=0,A=0):r.sign(y)===r.sign(m)?(P=y+m,A=v/P):(A=y-m,P=v/A);var I,M;0===C&&0===f?(I=0,M=0):r.sign(C)===r.sign(f)?(I=C+f,M=a/I):(M=C-f,I=a/M);var D=i.computeRealRoots(1,P,I),R=i.computeRealRoots(1,A,M);if(0!==D.length)return 0!==R.length?D[1]<=R[0]?[D[0],D[1],R[0],R[1]]:R[1]<=D[0]?[R[0],R[1],D[0],D[1]]:D[0]>=R[0]&&D[1]<=R[1]?[R[0],D[0],D[1],R[1]]:R[0]>=D[0]&&R[1]<=D[1]?[D[0],R[0],R[1],D[1]]:D[0]>R[0]&&D[0]u?1:0;switch(p+=0>c?p+1:p,p+=0>h?p+1:p,p+=0>d?p+1:p){case 0:return n(u,c,h,d);case 1:return o(u,c,h,d);case 2:return o(u,c,h,d);case 3:return n(u,c,h,d);case 4:return n(u,c,h,d);case 5:return o(u,c,h,d);case 6:return n(u,c,h,d);case 7:return n(u,c,h,d);case 8:return o(u,c,h,d);case 9:return n(u,c,h,d);case 10:return n(u,c,h,d);case 11:return o(u,c,h,d);case 12:return n(u,c,h,d);case 13:return n(u,c,h,d);case 14:return n(u,c,h,d);case 15:return n(u,c,h,d);default:return void 0}},a}),r("Core/Ray",["./Cartesian3","./defaultValue","./defined","./DeveloperError"],function(e,t,r,i){"use strict";var n=function(r,i){i=e.clone(t(i,e.ZERO)),e.equals(i,e.ZERO)||e.normalize(i,i),this.origin=e.clone(t(r,e.ZERO)),this.direction=i};return n.getPoint=function(t,i,n){return r(n)||(n=new e),n=e.multiplyByScalar(t.direction,i,n),e.add(t.origin,n,n)},n}),r("Core/IntersectionTests",["./Cartesian3","./Cartographic","./defaultValue","./defined","./DeveloperError","./Math","./Matrix3","./QuadraticRealPolynomial","./QuarticRealPolynomial","./Ray"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(t,i,n,a,s){s=r(s,!1);var l,u,c,h,d,p=t.origin,m=t.direction,f=e.subtract(n,i,v),E=e.subtract(a,i,_),S=e.cross(m,E,g),w=e.dot(f,S);if(s){if(wc||c>w)return void 0;if(u=e.cross(l,f,C),h=e.dot(m,u),0>h||c+h>w)return void 0;d=e.dot(E,u)/w}else{if(Math.abs(w)c||c>1)return void 0;if(u=e.cross(l,f,C),h=e.dot(m,u)*T,0>h||c+h>1)return void 0;d=e.dot(E,u)*T}return d}function h(e,t,r,i){var n=t*t-4*e*r;if(0>n)return void 0;if(n>0){var o=1/(2*e),a=Math.sqrt(n),s=(-t+a)*o,l=(-t-a)*o;return l>s?(i.root0=s,i.root1=l):(i.root0=l,i.root1=s),i}var u=-t/(2*e);return 0===u?void 0:(i.root0=i.root1=u,i)}function d(t,r,n){i(n)||(n={});var o=t.origin,a=t.direction,s=r.center,l=r.radius*r.radius,u=e.subtract(o,s,g),c=e.dot(a,a),d=2*e.dot(a,u),p=e.magnitudeSquared(u)-l,m=h(c,d,p,S);return i(m)?(n.start=m.root0,n.stop=m.root1,n):void 0}function p(e,t,r){var i=e+t;return o.sign(e)!==o.sign(t)&&Math.abs(i/Math.max(Math.abs(e),Math.abs(t)))N;++N){var L,F=c[N],B=F*F,V=Math.max(1-B,0),z=Math.sqrt(V);L=o.sign(m)===o.sign(v)?p(m*B+v,f*F,o.EPSILON12):o.sign(v)===o.sign(f*F)?p(m*B,f*F+v,o.EPSILON12):p(m*B+f*F,v,o.EPSILON12);var k=p(_*F,g,o.EPSILON15),U=L*k;0>U?y.push(new e(n,u*F,u*z)):U>0?y.push(new e(n,u*F,u*-z)):0!==z?(y.push(new e(n,u*F,u*-z)),y.push(new e(n,u*F,u*z)),++N):y.push(new e(n,u*F,u*z))}return y}var f={};f.rayPlane=function(t,r,n){i(n)||(n=new e);var a=t.origin,s=t.direction,l=r.normal,u=e.dot(l,s);if(Math.abs(u)c?void 0:(n=e.multiplyByScalar(s,c,n),e.add(a,n,n))};var v=new e,_=new e,g=new e,y=new e,C=new e;f.rayTriangle=function(t,r,n,o,a,s){var l=c(t,r,n,o,a);return!i(l)||0>l?void 0:(i(s)||(s=new e),e.multiplyByScalar(t.direction,l,s),e.add(t.origin,s,s))};var E=new u;f.lineSegmentTriangle=function(t,r,n,o,a,s,l){var u=E;e.clone(t,u.origin),e.subtract(r,t,u.direction),e.normalize(u.direction,u.direction);var h=c(u,n,o,a,s);return!i(h)||0>h||h>e.distance(t,r)?void 0:(i(l)||(l=new e),e.multiplyByScalar(u.direction,h,l),e.add(u.origin,l,l))};var S={root0:0,root1:0};f.raySphere=function(e,t,r){return r=d(e,t,r),!i(r)||r.stop<0?void 0:(r.start=Math.max(r.start,0),r)};var w=new u;f.lineSegmentSphere=function(t,r,n,o){var a=w,s=(e.clone(t,a.origin),e.subtract(r,t,a.direction)),l=e.magnitude(s);return e.normalize(s,s),o=d(a,n,o),!i(o)||o.stop<0||o.start>l?void 0:(o.start=Math.max(o.start,0),o.stop=Math.min(o.stop,l),o)};var T=new e,b=new e;f.rayEllipsoid=function(t,r){var i,n,o,a,s,l=r.oneOverRadii,u=e.multiplyComponents(l,t.origin,T),c=e.multiplyComponents(l,t.direction,b),h=e.magnitudeSquared(u),d=e.dot(u,c);if(h>1){if(d>=0)return void 0;var p=d*d;if(i=h-1,n=e.magnitudeSquared(c),o=n*i,o>p)return void 0;if(p>o){a=d*d-o,s=-d+Math.sqrt(a);var m=s/n,f=i/s;return f>m?{start:m,stop:f}:{start:f,stop:m}}var v=Math.sqrt(i/n);return{start:v,stop:v}}return 1>h?(i=h-1,n=e.magnitudeSquared(c),o=n*i,a=d*d-o,s=-d+Math.sqrt(a),{start:0,stop:s/n}):0>d?(n=e.magnitudeSquared(c),{start:0,stop:-d/n}):void 0};var x=new e,P=new e,A=new e,I=new e,M=new e,D=new a,R=new a,O=new a,N=new a,L=new a,F=new a,B=new a,V=new e,z=new e,k=new t;f.grazingAltitudeLocation=function(t,r){var n=t.origin,s=t.direction,l=r.geodeticSurfaceNormal(n,x);if(e.dot(s,l)>=0)return n;var u=i(this.rayEllipsoid(t,r)),c=r.transformPositionToScaledSpace(s,x),h=e.normalize(c,c),d=e.mostOrthogonalAxis(c,I),p=e.normalize(e.cross(d,h,P),P),f=e.normalize(e.cross(h,p,A),A),v=D;v[0]=h.x,v[1]=h.y,v[2]=h.z,v[3]=p.x,v[4]=p.y,v[5]=p.z,v[6]=f.x,v[7]=f.y,v[8]=f.z;var _=a.transpose(v,R),g=a.fromScale(r.radii,O),y=a.fromScale(r.oneOverRadii,N),C=L;C[0]=0,C[1]=-s.z,C[2]=s.y,C[3]=s.z,C[4]=0,C[5]=-s.x,C[6]=-s.y,C[7]=s.x,C[8]=0;var E,S,w=a.multiply(a.multiply(_,y,F),C,F),T=a.multiply(a.multiply(w,g,B),v,B),b=a.multiplyByVector(w,n,M),U=m(T,e.negate(b,x),0,0,1),G=U.length;if(G>0){for(var W=e.clone(e.ZERO,z),H=Number.NEGATIVE_INFINITY,q=0;G>q;++q){E=a.multiplyByVector(g,a.multiplyByVector(v,U[q],V),V);var j=e.normalize(e.subtract(E,n,I),I),Y=e.dot(j,s);Y>H&&(H=Y,W=e.clone(E,W))}var X=r.cartesianToCartographic(W,k);return H=o.clamp(H,0,1),S=e.magnitude(e.subtract(W,n,I))*Math.sqrt(1-H*H),S=u?-S:S,X.height=S,r.cartographicToCartesian(X,new e)}return void 0};var U=new e;return f.lineSegmentPlane=function(t,r,n,a){i(a)||(a=new e);var s=e.subtract(r,t,U),l=n.normal,u=e.dot(l,s);if(Math.abs(u)h||h>1?void 0:(e.multiplyByScalar(s,h,a),e.add(t,a,a),a)},f.trianglePlaneIntersection=function(t,r,i,n){var o=n.normal,a=n.distance,s=e.dot(o,t)+a<0,l=e.dot(o,r)+a<0,u=e.dot(o,i)+a<0,c=0;c+=s?1:0,c+=l?1:0,c+=u?1:0;var h,d;if((1===c||2===c)&&(h=new e,d=new e),1===c){if(s)return f.lineSegmentPlane(t,r,n,h),f.lineSegmentPlane(t,i,n,d),{positions:[t,r,i,h,d],indices:[0,3,4,1,2,4,1,4,3]};if(l)return f.lineSegmentPlane(r,i,n,h),f.lineSegmentPlane(r,t,n,d),{positions:[t,r,i,h,d],indices:[1,3,4,2,0,4,2,4,3]};if(u)return f.lineSegmentPlane(i,t,n,h),f.lineSegmentPlane(i,r,n,d),{positions:[t,r,i,h,d],indices:[2,3,4,0,1,4,0,4,3]}}else if(2===c){if(!s)return f.lineSegmentPlane(r,t,n,h),f.lineSegmentPlane(i,t,n,d),{positions:[t,r,i,h,d],indices:[1,2,4,1,4,3,0,3,4]};if(!l)return f.lineSegmentPlane(i,r,n,h),f.lineSegmentPlane(t,r,n,d),{positions:[t,r,i,h,d],indices:[2,0,4,2,4,3,1,3,4]};if(!u)return f.lineSegmentPlane(t,i,n,h),f.lineSegmentPlane(r,i,n,d),{positions:[t,r,i,h,d],indices:[0,1,4,0,4,3,2,3,4]}}return void 0},f}),r("Core/binarySearch",["./defined","./DeveloperError"],function(e,t){"use strict";var r=function(e,t,r){for(var i,n,o=0,a=e.length-1;a>=o;)if(i=~~((o+a)/2),n=r(e[i],t),0>n)o=i+1;else{if(!(n>0))return i;a=i-1}return~(a+1)};return r}),r("Core/EarthOrientationParametersSample",[],function(){"use strict";var e=function(e,t,r,i,n){this.xPoleWander=e,this.yPoleWander=t,this.xPoleOffset=r,this.yPoleOffset=i,this.ut1MinusUtc=n};return e}),r("ThirdParty/sprintf",[],function(){function e(){var e=/%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g,t=arguments,r=0,i=t[r++],n=function(e,t,r,i){r||(r=" ");var n=e.length>=t?"":Array(1+t-e.length>>>0).join(r);return i?e+n:n+e},o=function(e,t,r,i,o,a){var s=i-e.length;return s>0&&(e=r||!o?n(e,i,a,r):e.slice(0,t.length)+n("",s,"0",!0)+e.slice(t.length)),e},a=function(e,t,r,i,a,s,l){var u=e>>>0;return r=r&&u&&{2:"0b",8:"0",16:"0x"}[t]||"",e=r+n(u.toString(t),s||0,"0",!1),o(e,r,i,a,l)},s=function(e,t,r,i,n,a){return null!=i&&(e=e.slice(0,i)),o(e,"",t,r,n,a)},l=function(e,i,l,u,c,h,d){var p,m,f,v,_;if("%%"==e)return"%";for(var g=!1,y="",C=!1,E=!1,S=" ",w=l.length,T=0;l&&w>T;T++)switch(l.charAt(T)){case" ":y=" ";break;case"+":y="+";break;case"-":g=!0;break;case"'":S=l.charAt(T+1);break;case"0":C=!0;break;case"#":E=!0}if(u=u?"*"==u?+t[r++]:"*"==u.charAt(0)?+t[u.slice(1,-1)]:+u:0,0>u&&(u=-u,g=!0),!isFinite(u))throw new Error("sprintf: (minimum-)width must be finite");switch(h=h?"*"==h?+t[r++]:"*"==h.charAt(0)?+t[h.slice(1,-1)]:+h:"fFeE".indexOf(d)>-1?6:"d"==d?0:void 0,_=i?t[i.slice(0,-1)]:t[r++],d){case"s":return s(String(_),g,u,h,C,S);case"c":return s(String.fromCharCode(+_),g,u,h,C);case"b":return a(_,2,E,g,u,h,C);case"o":return a(_,8,E,g,u,h,C);case"x":return a(_,16,E,g,u,h,C);case"X":return a(_,16,E,g,u,h,C).toUpperCase();case"u":return a(_,10,E,g,u,h,C);case"i":case"d":return p=+_||0,p=Math.round(p-p%1),m=0>p?"-":y,_=m+n(String(Math.abs(p)),h,"0",!1),o(_,m,g,u,C);case"e":case"E":case"f":case"F":case"g":case"G":return p=+_,m=0>p?"-":y,f=["toExponential","toFixed","toPrecision"]["efg".indexOf(d.toLowerCase())],v=["toString","toUpperCase"]["eEfFgG".indexOf(d)%2],_=m+Math.abs(p)[f](h),o(_,m,g,u,C)[v]();default:return e}};return i.replace(e,l)}return e}),r("Core/GregorianDate",[],function(){"use strict";var e=function(e,t,r,i,n,o,a,s){this.year=e,this.month=t,this.day=r,this.hour=i,this.minute=n,this.second=o,this.millisecond=a,this.isLeapSecond=s};return e}),r("Core/isLeapYear",["./DeveloperError"],function(e){"use strict";function t(e){return e%4===0&&e%100!==0||e%400===0}return t}),r("Core/LeapSecond",[],function(){"use strict";var e=function(e,t){this.julianDate=e,this.offset=t};return e}),r("Core/TimeConstants",["./freezeObject"],function(e){"use strict";var t={SECONDS_PER_MILLISECOND:.001,SECONDS_PER_MINUTE:60,MINUTES_PER_HOUR:60,HOURS_PER_DAY:24,SECONDS_PER_HOUR:3600,MINUTES_PER_DAY:1440,SECONDS_PER_DAY:86400,DAYS_PER_JULIAN_CENTURY:36525,PICOSECOND:1e-9,MODIFIED_JULIAN_DATE_DIFFERENCE:2400000.5};return e(t)}),r("Core/TimeStandard",["./freezeObject"],function(e){"use strict";var t={UTC:0,TAI:1};return e(t)}),r("Core/JulianDate",["../ThirdParty/sprintf","./binarySearch","./defaultValue","./defined","./DeveloperError","./GregorianDate","./isLeapYear","./LeapSecond","./TimeConstants","./TimeStandard"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){return I.compare(e.julianDate,t.julianDate)}function h(e){g.julianDate=e;var r=I.leapSeconds,i=t(r,g,c);0>i&&(i=~i),i>=r.length&&(i=r.length-1);var n=r[i].offset;if(i>0){var o=I.secondsDifference(r[i].julianDate,e);o>n&&(i--,n=r[i].offset)}I.addSeconds(e,n,e)}function d(e,r){g.julianDate=e;var i=I.leapSeconds,n=t(i,g,c);if(0>n&&(n=~n),0===n)return I.addSeconds(e,-i[0].offset,r);if(n>=i.length)return I.addSeconds(e,-i[n-1].offset,r);var o=I.secondsDifference(i[n].julianDate,e);return 0===o?I.addSeconds(e,-i[n].offset,r):1>=o?void 0:I.addSeconds(e,-i[--n].offset,r)}function p(e,t,r){var i=t/l.SECONDS_PER_DAY|0;return e+=i,t-=l.SECONDS_PER_DAY*i,0>t&&(e--,t+=l.SECONDS_PER_DAY),r.dayNumber=e,r.secondsOfDay=t,r}function m(e,t,r,i,n,o,a){var s=(t-14)/12|0,u=e+4800+s,c=(1461*u/4|0)+(367*(t-2-12*s)/12|0)-(3*((u+100)/100|0)/4|0)+r-32075;i-=12,0>i&&(i+=24);var h=o+(i*l.SECONDS_PER_HOUR+n*l.SECONDS_PER_MINUTE+a*l.SECONDS_PER_MILLISECOND);return h>=43200&&(c-=1),[c,h]}var f=new o,v=[31,28,31,30,31,30,31,31,30,31,30,31],_=29,g=new s,y=/^(\d{4})$/,C=/^(\d{4})-(\d{2})$/,E=/^(\d{4})-?(\d{3})$/,S=/^(\d{4})-?W(\d{2})-?(\d{1})?$/,w=/^(\d{4})-?(\d{2})-?(\d{2})$/,T=/([Z+\-])?(\d{2})?:?(\d{2})?$/,b=/^(\d{2})(\.\d+)?/.source+T.source,x=/^(\d{2}):?(\d{2})(\.\d+)?/.source+T.source,P=/^(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?/.source+T.source,A="Invalid ISO 8601 date.",I=function(e,t,i){this.dayNumber=void 0,this.secondsOfDay=void 0,e=r(e,0),t=r(t,0),i=r(i,u.UTC);var n=0|e;t+=(e-n)*l.SECONDS_PER_DAY,p(n,t,this),i===u.UTC&&h(this)};I.fromDate=function(e,t){var r=m(e.getUTCFullYear(),e.getUTCMonth()+1,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds());return i(t)?(p(r[0],r[1],t),h(t),t):new I(r[0],r[1],u.UTC)},I.fromIso8601=function(e,t){e=e.replace(",",".");var r,o,s,l=e.split("T"),c=1,d=1,f=0,g=0,T=0,M=0,D=l[0],R=l[1];if(!i(D))throw new n(A);var O;if(l=D.match(w),null!==l){if(O=D.split("-").length-1,O>0&&2!==O)throw new n(A);r=+l[1],c=+l[2],d=+l[3]}else if(l=D.match(C),null!==l)r=+l[1],c=+l[2];else if(l=D.match(y),null!==l)r=+l[1];else{var N;if(l=D.match(E),null!==l){if(r=+l[1],N=+l[2],s=a(r),1>N||s&&N>366||!s&&N>365)throw new n(A)}else{if(l=D.match(S),null===l)throw new n(A);r=+l[1];var L=+l[2],F=+l[3]||0;if(O=D.split("-").length-1,O>0&&(!i(l[3])&&1!==O||i(l[3])&&2!==O))throw new n(A);var B=new Date(Date.UTC(r,0,4));N=7*L+F-B.getUTCDay()-3}o=new Date(Date.UTC(r,0,1)),o.setUTCDate(N),c=o.getUTCMonth()+1,d=o.getUTCDate()}if(s=a(r),1>c||c>12||1>d||(2!==c||!s)&&d>v[c-1]||s&&2===c&&d>_)throw new n(A);var V;if(i(R)){if(l=R.match(P),null!==l){if(O=R.split(":").length-1,O>0&&2!==O&&3!==O)throw new n(A);f=+l[1],g=+l[2],T=+l[3],M=1e3*+(l[4]||0),V=5}else if(l=R.match(x),null!==l){if(O=R.split(":").length-1,O>0&&1!==O)throw new n(A);f=+l[1],g=+l[2],T=60*+(l[3]||0),V=4}else{if(l=R.match(b),null===l)throw new n(A);f=+l[1],g=60*+(l[2]||0),V=3}if(g>=60||T>=61||f>24||24===f&&(g>0||T>0||M>0))throw new n(A);var z=l[V],k=+l[V+1],U=+(l[V+2]||0);switch(z){case"+":f-=k,g-=U;break;case"-":f+=k,g+=U;break;case"Z":break;default:g+=new Date(Date.UTC(r,c-1,d,f,g)).getTimezoneOffset()}}else g+=new Date(r,c-1,d).getTimezoneOffset();var G=60===T;for(G&&T--;g>=60;)g-=60,f++;for(;f>=24;)f-=24,d++;for(o=s&&2===c?_:v[c-1];d>o;)d-=o,c++,c>12&&(c-=12,r++),o=s&&2===c?_:v[c-1];for(;0>g;)g+=60,f--;for(;0>f;)f+=24,d--;for(;1>d;)c--,1>c&&(c+=12,r--),o=s&&2===c?_:v[c-1],d+=o;var W=m(r,c,d,f,g,T,M);return i(t)?(p(W[0],W[1],t),h(t)):t=new I(W[0],W[1],u.UTC),G&&I.addSeconds(t,1,t),t},I.now=function(e){return I.fromDate(new Date,e)};var M=new I(0,0,u.TAI);return I.toGregorianDate=function(e,t){var r=!1,n=d(e,M);i(n)||(I.addSeconds(e,-1,M),n=d(M,M),r=!0);var a=n.dayNumber,s=n.secondsOfDay;s>=43200&&(a+=1);var u=a+68569|0,c=4*u/146097|0;u=u-((146097*c+3)/4|0)|0;var h=4e3*(u+1)/1461001|0;u=u-(1461*h/4|0)+31|0;var p=80*u/2447|0,m=u-(2447*p/80|0)|0;u=p/11|0;var f=p+2-12*u|0,v=100*(c-49)+h+u|0,_=s/l.SECONDS_PER_HOUR|0,g=s-_*l.SECONDS_PER_HOUR,y=g/l.SECONDS_PER_MINUTE|0;g-=y*l.SECONDS_PER_MINUTE;var C=0|g,E=(g-C)/l.SECONDS_PER_MILLISECOND;return _+=12,_>23&&(_-=24),r&&(C+=1),i(t)?(t.year=v,t.month=f,t.day=m,t.hour=_,t.minute=y,t.second=C,t.millisecond=E,t.isLeapSecond=r,t):new o(v,f,m,_,y,C,E,r)},I.toDate=function(e){var t=I.toGregorianDate(e,f),r=t.second;return t.isLeapSecond&&(r-=1),new Date(Date.UTC(t.year,t.month-1,t.day,t.hour,t.minute,r,t.millisecond))},I.toIso8601=function(t,r){var n,o=I.toGregorianDate(t,o);return i(r)||0===o.millisecond?i(r)&&0!==r?(n=(.01*o.millisecond).toFixed(r).replace(".","").slice(0,r),e("%04d-%02d-%02dT%02d:%02d:%02d.%sZ",o.year,o.month,o.day,o.hour,o.minute,o.second,n)):e("%04d-%02d-%02dT%02d:%02d:%02dZ",o.year,o.month,o.day,o.hour,o.minute,o.second):(n=(.01*o.millisecond).toString().replace(".",""),e("%04d-%02d-%02dT%02d:%02d:%02d.%sZ",o.year,o.month,o.day,o.hour,o.minute,o.second,n))},I.clone=function(e,t){return i(e)?i(t)?(t.dayNumber=e.dayNumber,t.secondsOfDay=e.secondsOfDay,t):new I(e.dayNumber,e.secondsOfDay,u.TAI):void 0},I.compare=function(e,t){var r=e.dayNumber-t.dayNumber;return 0!==r?r:e.secondsOfDay-t.secondsOfDay},I.equals=function(e,t){return e===t||i(e)&&i(t)&&e.dayNumber===t.dayNumber&&e.secondsOfDay===t.secondsOfDay},I.equalsEpsilon=function(e,t,r){return e===t||i(e)&&i(t)&&Math.abs(I.secondsDifference(e,t))<=r},I.totalDays=function(e){return e.dayNumber+e.secondsOfDay/l.SECONDS_PER_DAY},I.secondsDifference=function(e,t){var r=(e.dayNumber-t.dayNumber)*l.SECONDS_PER_DAY;return r+(e.secondsOfDay-t.secondsOfDay)},I.daysDifference=function(e,t){var r=e.dayNumber-t.dayNumber,i=(e.secondsOfDay-t.secondsOfDay)/l.SECONDS_PER_DAY;return r+i},I.computeTaiMinusUtc=function(e){g.julianDate=e;var r=I.leapSeconds,i=t(r,g,c);return 0>i&&(i=~i,--i,0>i&&(i=0)),r[i].offset},I.addSeconds=function(e,t,r){return p(e.dayNumber,e.secondsOfDay+t,r)},I.addMinutes=function(e,t,r){var i=e.secondsOfDay+t*l.SECONDS_PER_MINUTE;return p(e.dayNumber,i,r)},I.addHours=function(e,t,r){var i=e.secondsOfDay+t*l.SECONDS_PER_HOUR;return p(e.dayNumber,i,r)},I.addDays=function(e,t,r){var i=e.dayNumber+t;return p(i,e.secondsOfDay,r)},I.lessThan=function(e,t){return I.compare(e,t)<0},I.lessThanOrEquals=function(e,t){return I.compare(e,t)<=0},I.greaterThan=function(e,t){return I.compare(e,t)>0},I.greaterThanOrEquals=function(e,t){return I.compare(e,t)>=0},I.prototype.clone=function(e){return I.clone(this,e)},I.prototype.equals=function(e){return I.equals(this,e)},I.prototype.equalsEpsilon=function(e,t){return I.equalsEpsilon(this,e,t)},I.prototype.toString=function(){return I.toIso8601(this)},I.leapSeconds=[new s(new I(2441317,43210,u.TAI),10),new s(new I(2441499,43211,u.TAI),11),new s(new I(2441683,43212,u.TAI),12),new s(new I(2442048,43213,u.TAI),13),new s(new I(2442413,43214,u.TAI),14),new s(new I(2442778,43215,u.TAI),15),new s(new I(2443144,43216,u.TAI),16),new s(new I(2443509,43217,u.TAI),17),new s(new I(2443874,43218,u.TAI),18),new s(new I(2444239,43219,u.TAI),19),new s(new I(2444786,43220,u.TAI),20),new s(new I(2445151,43221,u.TAI),21),new s(new I(2445516,43222,u.TAI),22),new s(new I(2446247,43223,u.TAI),23),new s(new I(2447161,43224,u.TAI),24),new s(new I(2447892,43225,u.TAI),25),new s(new I(2448257,43226,u.TAI),26),new s(new I(2448804,43227,u.TAI),27),new s(new I(2449169,43228,u.TAI),28),new s(new I(2449534,43229,u.TAI),29),new s(new I(2450083,43230,u.TAI),30),new s(new I(2450630,43231,u.TAI),31),new s(new I(2451179,43232,u.TAI),32),new s(new I(2453736,43233,u.TAI),33),new s(new I(2454832,43234,u.TAI),34),new s(new I(2456109,43235,u.TAI),35),new s(new I(2457204,43236,u.TAI),36)],I}),r("Core/EarthOrientationParameters",["../ThirdParty/when","./binarySearch","./defaultValue","./defined","./EarthOrientationParametersSample","./freezeObject","./JulianDate","./LeapSecond","./loadJson","./RuntimeError","./TimeConstants","./TimeStandard"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t){return a.compare(e.julianDate,t)}function p(e,r){if(!i(r.columnNames))return void(e._dataError="Error in loaded EOP data: The columnNames property is required.");if(!i(r.samples))return void(e._dataError="Error in loaded EOP data: The samples property is required.");var n=r.columnNames.indexOf("modifiedJulianDateUtc"),o=r.columnNames.indexOf("xPoleWanderRadians"),l=r.columnNames.indexOf("yPoleWanderRadians"),u=r.columnNames.indexOf("ut1MinusUtcSeconds"),p=r.columnNames.indexOf("xCelestialPoleOffsetRadians"),m=r.columnNames.indexOf("yCelestialPoleOffsetRadians"),f=r.columnNames.indexOf("taiMinusUtcSeconds");if(0>n||0>o||0>l||0>u||0>p||0>m||0>f)return void(e._dataError="Error in loaded EOP data: The columnNames property must include modifiedJulianDateUtc, xPoleWanderRadians, yPoleWanderRadians, ut1MinusUtcSeconds, xCelestialPoleOffsetRadians, yCelestialPoleOffsetRadians, and taiMinusUtcSeconds columns");var v=e._samples=r.samples,_=e._dates=[];e._dateColumn=n,e._xPoleWanderRadiansColumn=o,e._yPoleWanderRadiansColumn=l,e._ut1MinusUtcSecondsColumn=u,e._xCelestialPoleOffsetRadiansColumn=p,e._yCelestialPoleOffsetRadiansColumn=m,e._taiMinusUtcSecondsColumn=f,e._columnCount=r.columnNames.length,e._lastIndex=void 0;for(var g,y=e._addNewLeapSeconds,C=0,E=v.length;E>C;C+=e._columnCount){var S=v[C+n],w=v[C+f],T=S+c.MODIFIED_JULIAN_DATE_DIFFERENCE,b=new a(T,w,h.TAI);if(_.push(b),y){if(w!==g&&i(g)){var x=a.leapSeconds,P=t(x,b,d);if(0>P){var A=new s(b,w);x.splice(~P,0,A)}}g=w}}}function m(e,t,r,i,n){var o=r*i;n.xPoleWander=t[o+e._xPoleWanderRadiansColumn],n.yPoleWander=t[o+e._yPoleWanderRadiansColumn],n.xPoleOffset=t[o+e._xCelestialPoleOffsetRadiansColumn],n.yPoleOffset=t[o+e._yCelestialPoleOffsetRadiansColumn],n.ut1MinusUtc=t[o+e._ut1MinusUtcSecondsColumn]}function f(e,t,r){return t+e*(r-t)}function v(e,t,r,i,n,o,s){var l=e._columnCount;if(o>t.length-1)return s.xPoleWander=0,s.yPoleWander=0,s.xPoleOffset=0,s.yPoleOffset=0,s.ut1MinusUtc=0,s;var u=t[n],c=t[o];if(u.equals(c)||i.equals(u))return m(e,r,n,l,s),s;if(i.equals(c))return m(e,r,o,l,s),s;var h=a.secondsDifference(i,u)/a.secondsDifference(c,u),d=n*l,p=o*l,v=r[d+e._ut1MinusUtcSecondsColumn],_=r[p+e._ut1MinusUtcSecondsColumn],g=_-v;if(g>.5||-.5>g){var y=r[d+e._taiMinusUtcSecondsColumn],C=r[p+e._taiMinusUtcSecondsColumn];y!==C&&(c.equals(i)?v=_:_-=C-y)}return s.xPoleWander=f(h,r[d+e._xPoleWanderRadiansColumn],r[p+e._xPoleWanderRadiansColumn]),s.yPoleWander=f(h,r[d+e._yPoleWanderRadiansColumn],r[p+e._yPoleWanderRadiansColumn]),s.xPoleOffset=f(h,r[d+e._xCelestialPoleOffsetRadiansColumn],r[p+e._xCelestialPoleOffsetRadiansColumn]),s.yPoleOffset=f(h,r[d+e._yCelestialPoleOffsetRadiansColumn],r[p+e._yCelestialPoleOffsetRadiansColumn]),s.ut1MinusUtc=f(h,v,_),s}var _=function(t){if(t=r(t,r.EMPTY_OBJECT),this._dates=void 0,this._samples=void 0,this._dateColumn=-1,this._xPoleWanderRadiansColumn=-1,this._yPoleWanderRadiansColumn=-1,this._ut1MinusUtcSecondsColumn=-1,this._xCelestialPoleOffsetRadiansColumn=-1, +this._yCelestialPoleOffsetRadiansColumn=-1,this._taiMinusUtcSecondsColumn=-1,this._columnCount=0,this._lastIndex=-1,this._downloadPromise=void 0,this._dataError=void 0,this._addNewLeapSeconds=r(t.addNewLeapSeconds,!0),i(t.data))p(this,t.data);else if(i(t.url)){var n=this;this._downloadPromise=e(l(t.url),function(e){p(n,e)},function(){n._dataError="An error occurred while retrieving the EOP data from the URL "+t.url+"."})}else p(this,{columnNames:["dateIso8601","modifiedJulianDateUtc","xPoleWanderRadians","yPoleWanderRadians","ut1MinusUtcSeconds","lengthOfDayCorrectionSeconds","xCelestialPoleOffsetRadians","yCelestialPoleOffsetRadians","taiMinusUtcSeconds"],samples:[]})};return _.NONE=o({getPromiseToLoad:function(){return e()},compute:function(e,t){return i(t)?(t.xPoleWander=0,t.yPoleWander=0,t.xPoleOffset=0,t.yPoleOffset=0,t.ut1MinusUtc=0):t=new n(0,0,0,0,0),t}}),_.prototype.getPromiseToLoad=function(){return e(this._downloadPromise)},_.prototype.compute=function(e,r){if(!i(this._samples)){if(i(this._dataError))throw new u(this._dataError);return void 0}if(i(r)||(r=new n(0,0,0,0,0)),0===this._samples.length)return r.xPoleWander=0,r.yPoleWander=0,r.xPoleOffset=0,r.yPoleOffset=0,r.ut1MinusUtc=0,r;var o=this._dates,s=this._lastIndex,l=0,c=0;if(i(s)){var h=o[s],d=o[s+1],p=a.lessThanOrEquals(h,e),m=!i(d),f=m||a.greaterThanOrEquals(d,e);if(p&&f)return l=s,!m&&d.equals(e)&&++l,c=l+1,v(this,o,this._samples,e,l,c,r),r}var _=t(o,e,a.compare,this._dateColumn);return _>=0?(_l&&(l=0)),this._lastIndex=l,v(this,o,this._samples,e,l,c,r),r},_}),r("Core/Iau2006XysSample",[],function(){"use strict";var e=function(e,t,r){this.x=e,this.y=t,this.s=r};return e}),r("Core/Iau2006XysData",["../ThirdParty/when","./buildModuleUrl","./defaultValue","./defined","./Iau2006XysSample","./JulianDate","./loadJson","./TimeStandard"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t,r){var i=h;return i.dayNumber=t,i.secondsOfDay=r,o.daysDifference(i,e._sampleZeroDateTT)}function u(r,n){if(r._chunkDownloadsInProgress[n])return r._chunkDownloadsInProgress[n];var o=e.defer();r._chunkDownloadsInProgress[n]=o;var s,l=r._xysFileUrlTemplate;return s=i(l)?l.replace("{0}",n):t("Assets/IAU2006_XYS/IAU2006_XYS_"+n+".json"),e(a(s),function(e){r._chunkDownloadsInProgress[n]=!1;for(var t=r._samples,i=e.samples,a=n*r._samplesPerXysFile*3,s=0,l=i.length;l>s;++s)t[a+s]=i[s];o.resolve()}),o.promise}var c=function(e){e=r(e,r.EMPTY_OBJECT),this._xysFileUrlTemplate=e.xysFileUrlTemplate,this._interpolationOrder=r(e.interpolationOrder,9),this._sampleZeroJulianEphemerisDate=r(e.sampleZeroJulianEphemerisDate,2442396.5),this._sampleZeroDateTT=new o(this._sampleZeroJulianEphemerisDate,0,s.TAI),this._stepSizeDays=r(e.stepSizeDays,1),this._samplesPerXysFile=r(e.samplesPerXysFile,1e3),this._totalSamples=r(e.totalSamples,27426),this._samples=new Array(3*this._totalSamples),this._chunkDownloadsInProgress=[];for(var t=this._interpolationOrder,i=this._denominators=new Array(t+1),n=this._xTable=new Array(t+1),a=Math.pow(this._stepSizeDays,t),l=0;t>=l;++l){i[l]=a,n[l]=l*this._stepSizeDays;for(var u=0;t>=u;++u)u!==l&&(i[l]*=l-u);i[l]=1/i[l]}this._work=new Array(t+1),this._coef=new Array(t+1)},h=new o(0,0,s.TAI);return c.prototype.preload=function(t,r,i,n){var o=l(this,t,r),a=l(this,i,n),s=o/this._stepSizeDays-this._interpolationOrder/2|0;0>s&&(s=0);var c=a/this._stepSizeDays-this._interpolationOrder/2|0+this._interpolationOrder;c>=this._totalSamples&&(c=this._totalSamples-1);for(var h=s/this._samplesPerXysFile|0,d=c/this._samplesPerXysFile|0,p=[],m=h;d>=m;++m)p.push(u(this,m));return e.all(p)},c.prototype.computeXysRadians=function(e,t,r){var o=l(this,e,t);if(0>o)return void 0;var a=o/this._stepSizeDays|0;if(a>=this._totalSamples)return void 0;var s=this._interpolationOrder,c=a-(s/2|0);0>c&&(c=0);var h=c+s;h>=this._totalSamples&&(h=this._totalSamples-1,c=h-s,0>c&&(c=0));var d=!1,p=this._samples;if(i(p[3*c])||(u(this,c/this._samplesPerXysFile|0),d=!0),i(p[3*h])||(u(this,h/this._samplesPerXysFile|0),d=!0),d)return void 0;i(r)?(r.x=0,r.y=0,r.s=0):r=new n(0,0,0);var m,f,v=o-c*this._stepSizeDays,_=this._work,g=this._denominators,y=this._coef,C=this._xTable;for(m=0;s>=m;++m)_[m]=v-C[m];for(m=0;s>=m;++m){for(y[m]=1,f=0;s>=f;++f)f!==m&&(y[m]*=_[f]);y[m]*=g[m];var E=3*(c+m);r.x+=y[m]*p[E++],r.y+=y[m]*p[E++],r.s+=y[m]*p[E]}return r},c}),r("Core/Quaternion",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./FeatureDetection","./freezeObject","./Math","./Matrix3"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,r,i,n){this.x=t(e,0),this.y=t(r,0),this.z=t(i,0),this.w=t(n,0)},u=new e;l.fromAxisAngle=function(t,i,n){var o=i/2,a=Math.sin(o);u=e.normalize(t,u);var s=u.x*a,c=u.y*a,h=u.z*a,d=Math.cos(o);return r(n)?(n.x=s,n.y=c,n.z=h,n.w=d,n):new l(s,c,h,d)};var c=[1,2,0],h=new Array(3);l.fromRotationMatrix=function(e,t){var i,n,o,a,u,d=e[s.COLUMN0ROW0],p=e[s.COLUMN1ROW1],m=e[s.COLUMN2ROW2],f=d+p+m;if(f>0)i=Math.sqrt(f+1),u=.5*i,i=.5/i,n=(e[s.COLUMN1ROW2]-e[s.COLUMN2ROW1])*i,o=(e[s.COLUMN2ROW0]-e[s.COLUMN0ROW2])*i,a=(e[s.COLUMN0ROW1]-e[s.COLUMN1ROW0])*i;else{var v=c,_=0;p>d&&(_=1),m>d&&m>p&&(_=2);var g=v[_],y=v[g];i=Math.sqrt(e[s.getElementIndex(_,_)]-e[s.getElementIndex(g,g)]-e[s.getElementIndex(y,y)]+1);var C=h;C[_]=.5*i,i=.5/i,u=(e[s.getElementIndex(y,g)]-e[s.getElementIndex(g,y)])*i,C[g]=(e[s.getElementIndex(g,_)]+e[s.getElementIndex(_,g)])*i,C[y]=(e[s.getElementIndex(y,_)]+e[s.getElementIndex(_,y)])*i,n=-C[0],o=-C[1],a=-C[2]}return r(t)?(t.x=n,t.y=o,t.z=a,t.w=u,t):new l(n,o,a,u)};var d=new l;l.fromHeadingPitchRoll=function(t,r,i,n){var o=l.fromAxisAngle(e.UNIT_X,i,d),a=l.fromAxisAngle(e.UNIT_Y,-r,n);n=l.multiply(a,o,a);var s=l.fromAxisAngle(e.UNIT_Z,-t,d);return l.multiply(s,n,n)};var p=new e,m=new e,f=new l,v=new l,_=new l;l.packedLength=4,l.pack=function(e,r,i){i=t(i,0),r[i++]=e.x,r[i++]=e.y,r[i++]=e.z,r[i]=e.w},l.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new l),n.x=e[i],n.y=e[i+1],n.z=e[i+2],n.w=e[i+3],n},l.packedInterpolationLength=3,l.convertPackedArrayForInterpolation=function(e,t,r,i){l.unpack(e,4*r,_),l.conjugate(_,_);for(var n=0,o=r-t+1;o>n;n++){var a=3*n;l.unpack(e,4*(t+n),f),l.multiply(f,_,f),f.w<0&&l.negate(f,f),l.computeAxis(f,p);var s=l.computeAngle(f);i[a]=p.x*s,i[a+1]=p.y*s,i[a+2]=p.z*s}},l.unpackInterpolationResult=function(t,i,n,o,a){r(a)||(a=new l),e.fromArray(t,0,m);var s=e.magnitude(m);return l.unpack(i,4*o,v),0===s?l.clone(l.IDENTITY,f):l.fromAxisAngle(m,s,f),l.multiply(f,v,a)},l.clone=function(e,t){return r(e)?r(t)?(t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w,t):new l(e.x,e.y,e.z,e.w):void 0},l.conjugate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t.w=e.w,t},l.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y+e.z*e.z+e.w*e.w},l.magnitude=function(e){return Math.sqrt(l.magnitudeSquared(e))},l.normalize=function(e,t){var r=1/l.magnitude(e),i=e.x*r,n=e.y*r,o=e.z*r,a=e.w*r;return t.x=i,t.y=n,t.z=o,t.w=a,t},l.inverse=function(e,t){var r=l.magnitudeSquared(e);return t=l.conjugate(e,t),l.multiplyByScalar(t,1/r,t)},l.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r.z=e.z+t.z,r.w=e.w+t.w,r},l.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r.z=e.z-t.z,r.w=e.w-t.w,r},l.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t.w=-e.w,t},l.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z+e.w*t.w},l.multiply=function(e,t,r){var i=e.x,n=e.y,o=e.z,a=e.w,s=t.x,l=t.y,u=t.z,c=t.w,h=a*s+i*c+n*u-o*l,d=a*l-i*u+n*c+o*s,p=a*u+i*l-n*s+o*c,m=a*c-i*s-n*l-o*u;return r.x=h,r.y=d,r.z=p,r.w=m,r},l.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r.z=e.z*t,r.w=e.w*t,r},l.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r.z=e.z/t,r.w=e.w/t,r},l.computeAxis=function(e,t){var r=e.w;if(Math.abs(r-1)n&&(n=-n,o=y=l.negate(t,y)),1-nR;++R){var O=R+1,N=2*O+1;A[R]=1/(O*N),I[R]=O/N}return A[7]=P/136,I[7]=8*P/17,l.fastSlerp=function(e,t,r,i){var n,o=l.dot(e,t);o>=0?n=1:(n=-1,o=-o);for(var a=o-1,s=1-r,u=r*r,c=s*s,h=7;h>=0;--h)M[h]=(A[h]*u-I[h])*a,D[h]=(A[h]*c-I[h])*a;var d=n*r*(1+M[0]*(1+M[1]*(1+M[2]*(1+M[3]*(1+M[4]*(1+M[5]*(1+M[6]*(1+M[7])))))))),p=s*(1+D[0]*(1+D[1]*(1+D[2]*(1+D[3]*(1+D[4]*(1+D[5]*(1+D[6]*(1+D[7])))))))),m=l.multiplyByScalar(e,p,x);return l.multiplyByScalar(t,d,i),l.add(m,i,i)},l.fastSquad=function(e,t,r,i,n,o){var a=l.fastSlerp(e,t,n,T),s=l.fastSlerp(r,i,n,b);return l.fastSlerp(a,s,2*n*(1-n),o)},l.equals=function(e,t){return e===t||r(e)&&r(t)&&e.x===t.x&&e.y===t.y&&e.z===t.z&&e.w===t.w},l.equalsEpsilon=function(e,t,i){return e===t||r(e)&&r(t)&&Math.abs(e.x-t.x)<=i&&Math.abs(e.y-t.y)<=i&&Math.abs(e.z-t.z)<=i&&Math.abs(e.w-t.w)<=i},l.ZERO=o(new l(0,0,0,0)),l.IDENTITY=o(new l(0,0,0,1)),l.prototype.clone=function(e){return l.clone(this,e)},l.prototype.equals=function(e){return l.equals(this,e)},l.prototype.equalsEpsilon=function(e,t){return l.equalsEpsilon(this,e,t)},l.prototype.toString=function(){return"("+this.x+", "+this.y+", "+this.z+", "+this.w+")"},l}),r("Core/Transforms",["../ThirdParty/when","./Cartesian2","./Cartesian3","./Cartesian4","./defaultValue","./defined","./DeveloperError","./EarthOrientationParameters","./EarthOrientationParametersSample","./Ellipsoid","./Iau2006XysData","./Iau2006XysSample","./JulianDate","./Math","./Matrix3","./Matrix4","./Quaternion","./TimeConstants"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";var g={},y=new r,C=new r,E=new r;g.eastNorthUpToFixedFrame=function(e,t,i){if(p.equalsEpsilon(e.x,0,p.EPSILON14)&&p.equalsEpsilon(e.y,0,p.EPSILON14)){var a=p.sign(e.z);return o(i)?(i[0]=0,i[1]=1,i[2]=0,i[3]=0,i[4]=-a,i[5]=0,i[6]=0,i[7]=0,i[8]=0,i[9]=0,i[10]=a,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(0,-a,0,e.x,1,0,0,e.y,0,0,a,e.z,0,0,0,1)}var s=y,l=C,c=E;return t=n(t,u.WGS84),t.geodeticSurfaceNormal(e,s),l.x=-e.y,l.y=e.x,l.z=0,r.normalize(l,l),r.cross(s,l,c),o(i)?(i[0]=l.x,i[1]=l.y,i[2]=l.z,i[3]=0,i[4]=c.x,i[5]=c.y,i[6]=c.z,i[7]=0,i[8]=s.x,i[9]=s.y,i[10]=s.z,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(l.x,c.x,s.x,e.x,l.y,c.y,s.y,e.y,l.z,c.z,s.z,e.z,0,0,0,1)};var S=new r,w=new r,T=new r;g.northEastDownToFixedFrame=function(e,t,i){if(p.equalsEpsilon(e.x,0,p.EPSILON14)&&p.equalsEpsilon(e.y,0,p.EPSILON14)){var a=p.sign(e.z);return o(i)?(i[0]=-a,i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=1,i[6]=0,i[7]=0,i[8]=0,i[9]=0,i[10]=-a,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(-a,0,0,e.x,0,1,0,e.y,0,0,-a,e.z,0,0,0,1)}var s=S,l=w,c=T;return t=n(t,u.WGS84),t.geodeticSurfaceNormal(e,s),l.x=-e.y,l.y=e.x,l.z=0,r.normalize(l,l),r.cross(s,l,c),o(i)?(i[0]=c.x,i[1]=c.y,i[2]=c.z,i[3]=0,i[4]=l.x,i[5]=l.y,i[6]=l.z,i[7]=0,i[8]=-s.x,i[9]=-s.y,i[10]=-s.z,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(c.x,l.x,-s.x,e.x,c.y,l.y,-s.y,e.y,c.z,l.z,-s.z,e.z,0,0,0,1)},g.northUpEastToFixedFrame=function(e,t,i){if(p.equalsEpsilon(e.x,0,p.EPSILON14)&&p.equalsEpsilon(e.y,0,p.EPSILON14)){var a=p.sign(e.z);return o(i)?(i[0]=-a,i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=0,i[6]=a,i[7]=0,i[8]=0,i[9]=1,i[10]=0,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(-a,0,0,e.x,0,0,1,e.y,0,a,0,e.z,0,0,0,1)}var s=y,l=C,c=E;return t=n(t,u.WGS84),t.geodeticSurfaceNormal(e,s),l.x=-e.y,l.y=e.x,l.z=0,r.normalize(l,l),r.cross(s,l,c),o(i)?(i[0]=c.x,i[1]=c.y,i[2]=c.z,i[3]=0,i[4]=s.x,i[5]=s.y,i[6]=s.z,i[7]=0,i[8]=l.x,i[9]=l.y,i[10]=l.z,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(c.x,s.x,l.x,e.x,c.y,s.y,l.y,e.y,c.z,s.z,l.z,e.z,0,0,0,1)};var b=new v,x=new r(1,1,1),P=new f;g.headingPitchRollToFixedFrame=function(e,t,i,n,o,a){var s=v.fromHeadingPitchRoll(t,i,n,b),l=f.fromTranslationQuaternionRotationScale(r.ZERO,s,x,P);return a=g.eastNorthUpToFixedFrame(e,o,a),f.multiply(a,l,a)};var A=new f,I=new m;g.headingPitchRollQuaternion=function(e,t,r,i,n,o){var a=g.headingPitchRollToFixedFrame(e,t,r,i,n,A),s=f.getRotation(a,I);return v.fromRotationMatrix(s,o)};var M=24110.54841,D=8640184.812866,R=.093104,O=-62e-7,N=1.1772758384668e-19,L=72921158553e-15,F=p.TWO_PI/86400,B=new d;g.computeTemeToPseudoFixedMatrix=function(e,t){B=d.addSeconds(e,-d.computeTaiMinusUtc(e),B);var r,i=B.dayNumber,n=B.secondsOfDay,a=i-2451545;r=n>=43200?(a+.5)/_.DAYS_PER_JULIAN_CENTURY:(a-.5)/_.DAYS_PER_JULIAN_CENTURY;var s=M+r*(D+r*(R+r*O)),l=s*F%p.TWO_PI,u=L+N*(i-2451545.5),c=(n+.5*_.SECONDS_PER_DAY)%_.SECONDS_PER_DAY,h=l+u*c,f=Math.cos(h),v=Math.sin(h);return o(t)?(t[0]=f,t[1]=-v,t[2]=0,t[3]=v,t[4]=f,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t):new m(f,v,0,-v,f,0,0,0,1)},g.iau2006XysData=new c,g.earthOrientationParameters=s.NONE;var V=32.184,z=2451545;g.preloadIcrfFixed=function(t){var r=t.start.dayNumber,i=t.start.secondsOfDay+V,n=t.stop.dayNumber,o=t.stop.secondsOfDay+V,a=g.iau2006XysData.preload(r,i,n,o),s=g.earthOrientationParameters.getPromiseToLoad();return e.all([a,s])},g.computeIcrfToFixedMatrix=function(e,t){o(t)||(t=new m);var r=g.computeFixedToIcrfMatrix(e,t);return o(r)?m.transpose(r,t):void 0};var k=new h(0,0,0),U=new l(0,0,0,0,0,0),G=new m,W=new m;g.computeFixedToIcrfMatrix=function(e,t){o(t)||(t=new m);var r=g.earthOrientationParameters.compute(e,U);if(!o(r))return void 0;var i=e.dayNumber,n=e.secondsOfDay+V,a=g.iau2006XysData.computeXysRadians(i,n,k);if(!o(a))return void 0;var s=a.x+r.xPoleOffset,l=a.y+r.yPoleOffset,u=1/(1+Math.sqrt(1-s*s-l*l)),c=G;c[0]=1-u*s*s,c[3]=-u*s*l,c[6]=s,c[1]=-u*s*l,c[4]=1-u*l*l,c[7]=l,c[2]=-s,c[5]=-l,c[8]=1-u*(s*s+l*l);var h=m.fromRotationZ(-a.s,W),f=m.multiply(c,h,G),v=e.dayNumber,y=e.secondsOfDay-d.computeTaiMinusUtc(e)+r.ut1MinusUtc,C=v-2451545,E=y/_.SECONDS_PER_DAY,S=.779057273264+E+.00273781191135448*(C+E);S=S%1*p.TWO_PI;var w=m.fromRotationZ(S,W),T=m.multiply(f,w,G),b=Math.cos(r.xPoleWander),x=Math.cos(r.yPoleWander),P=Math.sin(r.xPoleWander),A=Math.sin(r.yPoleWander),I=i-z+n/_.SECONDS_PER_DAY;I/=36525;var M=-47e-6*I*p.RADIANS_PER_DEGREE/3600,D=Math.cos(M),R=Math.sin(M),O=W;return O[0]=b*D,O[1]=b*R,O[2]=P,O[3]=-x*R+A*P*D,O[4]=x*D+A*P*R,O[5]=-A*b,O[6]=-A*R-x*P*D,O[7]=A*D-x*P*R,O[8]=x*b,m.multiply(T,O,t)};var H=new i;g.pointToWindowCoordinates=function(e,t,r,i){return i=g.pointToGLWindowCoordinates(e,t,r,i),i.y=2*t[5]-i.y,i},g.pointToGLWindowCoordinates=function(e,r,n,a){o(a)||(a=new t);var s=H;return f.multiplyByVector(e,i.fromElements(n.x,n.y,n.z,1,s),s),i.multiplyByScalar(s,1/s.w,s),f.multiplyByVector(r,s,s),t.fromCartesian4(s,a)};var q=new r,j=new r,Y=new r;return g.rotationMatrixFromPositionVelocity=function(e,t,i,a){var s=n(i,u.WGS84).geodeticSurfaceNormal(e,q),l=r.cross(t,s,j);r.equalsEpsilon(l,r.ZERO,p.EPSILON6)&&(l=r.clone(r.UNIT_X,l));var c=r.cross(l,t,Y);return r.cross(t,c,l),r.negate(l,l),o(a)||(a=new m),a[0]=t.x,a[1]=t.y,a[2]=t.z,a[3]=l.x,a[4]=l.y,a[5]=l.z,a[6]=c.x,a[7]=c.y,a[8]=c.z,a},g}),r("Core/EllipsoidTangentPlane",["./AxisAlignedBoundingBox","./Cartesian2","./Cartesian3","./Cartesian4","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./IntersectionTests","./Matrix3","./Matrix4","./Plane","./Ray","./Transforms"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new i,v=function(e,t){t=n(t,l.WGS84),e=t.scaleToGeodeticSurface(e);var i=m.eastNorthUpToFixedFrame(e,t);this._ellipsoid=t,this._origin=e,this._xAxis=r.fromCartesian4(h.getColumn(i,0,f)),this._yAxis=r.fromCartesian4(h.getColumn(i,1,f));var o=r.fromCartesian4(h.getColumn(i,2,f));this._plane=d.fromPointNormal(e,o)};a(v.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},origin:{get:function(){return this._origin}},plane:{get:function(){return this._plane}},xAxis:{get:function(){return this._xAxis}},yAxis:{get:function(){return this._yAxis}},zAxis:{get:function(){return this._plane.normal}}});var _=new e;v.fromPoints=function(t,r){var i=e.fromPoints(t,_);return new v(i.center,r)};var g=new p,y=new r;v.prototype.projectPointOntoPlane=function(e,i){var n=g;n.origin=e,r.normalize(e,n.direction);var a=u.rayPlane(n,this._plane,y);if(o(a)||(r.negate(n.direction,n.direction),a=u.rayPlane(n,this._plane,y)),o(a)){var s=r.subtract(a,this._origin,a),l=r.dot(this._xAxis,s),c=r.dot(this._yAxis,s);return o(i)?(i.x=l,i.y=c,i):new t(l,c)}return void 0},v.prototype.projectPointsOntoPlane=function(e,t){o(t)||(t=[]);for(var r=0,i=e.length,n=0;i>n;n++){var a=this.projectPointOntoPlane(e[n],t[r]);o(a)&&(t[r]=a,r++)}return t.length=r,t},v.prototype.projectPointToNearestOnPlane=function(e,i){o(i)||(i=new t);var n=g;n.origin=e,r.clone(this._plane.normal,n.direction);var a=u.rayPlane(n,this._plane,y);o(a)||(r.negate(n.direction,n.direction),a=u.rayPlane(n,this._plane,y));var s=r.subtract(a,this._origin,a),l=r.dot(this._xAxis,s),c=r.dot(this._yAxis,s);return i.x=l,i.y=c,i},v.prototype.projectPointsToNearestOnPlane=function(e,t){o(t)||(t=[]);var r=e.length;t.length=r;for(var i=0;r>i;i++)t[i]=this.projectPointToNearestOnPlane(e[i],t[i]);return t};var C=new r;return v.prototype.projectPointsOntoEllipsoid=function(e,t){var i=e.length;o(t)?t.length=i:t=new Array(i);for(var n=this._ellipsoid,a=this._origin,s=this._xAxis,l=this._yAxis,u=C,c=0;i>c;++c){var h=e[c];r.multiplyByScalar(s,h.x,u),o(t[c])||(t[c]=new r);var d=r.add(a,u,t[c]);r.multiplyByScalar(l,h.y,u),r.add(d,u,d),n.scaleToGeocentricSurface(d,d)}return t},v}),r("Core/OrientedBoundingBox",["./BoundingSphere","./Cartesian2","./Cartesian3","./Cartographic","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Intersect","./Interval","./Math","./Matrix3","./Plane","./Rectangle"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=function(e,t){this.center=r.clone(n(e,r.ZERO)),this.halfAxes=d.clone(n(t,d.ZERO))},v=new r,_=new r,g=new r,y=new r,C=new r,E=new d,S={unitary:new d,diagonal:new d};f.fromPoints=function(e,t){if(o(t)||(t=new f),!o(e)||0===e.length)return t.halfAxes=d.ZERO,t.center=r.ZERO,t;var i,n=e.length,a=r.clone(e[0],v);for(i=1;n>i;i++)r.add(a,e[i],a);var s=1/n;r.multiplyByScalar(a,s,a);var l,u=0,c=0,h=0,p=0,m=0,w=0;for(i=0;n>i;i++)l=r.subtract(e[i],a,_),u+=l.x*l.x,c+=l.x*l.y,h+=l.x*l.z,p+=l.y*l.y,m+=l.y*l.z,w+=l.z*l.z;u*=s,c*=s,h*=s,p*=s,m*=s,w*=s;var T=E;T[0]=u,T[1]=c,T[2]=h,T[3]=c,T[4]=p,T[5]=m,T[6]=h,T[7]=m,T[8]=w;var b=d.computeEigenDecomposition(T,S),x=d.transpose(b.unitary,t.halfAxes);l=r.subtract(e[0],a,_);var P=d.multiplyByVector(x,l,g),A=r.clone(P,y),I=r.clone(P,C);for(i=1;n>i;i++)l=r.subtract(e[i],a,l),d.multiplyByVector(x,l,P),r.minimumByComponent(I,P,I),r.maximumByComponent(A,P,A);var M=r.add(I,A,g);r.multiplyByScalar(M,.5,M),d.multiplyByVector(x,M,M),r.add(a,M,t.center);var D=r.subtract(A,I,g);return r.multiplyByScalar(D,.5,D),d.multiplyByScale(t.halfAxes,D,t.halfAxes),t};var w=new r,T=new r,b=function(e,t,i,n,a,s,l,u){o(u)||(u=new f);var c=u.halfAxes;d.setColumn(c,0,e.xAxis,c),d.setColumn(c,1,e.yAxis,c),d.setColumn(c,2,e.zAxis,c);var h=w;h.x=(t+i)/2,h.y=(n+a)/2,h.z=(s+l)/2;var p=T;p.x=(i-t)/2,p.y=(a-n)/2,p.z=(l-s)/2;var m=u.center;return h=d.multiplyByVector(c,h,h),r.add(e.origin,h,m),d.multiplyByScale(c,p,c),u},x=new i,P=new r,A=[new i,new i,new i,new i,new i,new i,new i,new i],I=[new r,new r,new r,new r,new r,new r,new r,new r],M=[new t,new t,new t,new t,new t,new t,new t,new t];f.fromRectangle=function(e,t,r,i,o){t=n(t,0),r=n(r,0),i=n(i,s.WGS84);var a=m.center(e,x),u=i.cartographicToCartesian(a,P),c=new l(u,i),h=c.plane,d=A[0],f=A[1],v=A[2],_=A[3],g=A[4],y=A[5],C=A[6],E=A[7],S=a.longitude,w=e.south<0&&e.north>0?0:a.latitude;C.latitude=y.latitude=g.latitude=e.south,E.latitude=_.latitude=w,d.latitude=f.latitude=v.latitude=e.north,C.longitude=E.longitude=d.longitude=e.west,y.longitude=f.longitude=S,g.longitude=_.longitude=v.longitude=e.east,v.height=f.height=d.height=E.height=C.height=y.height=g.height=_.height=r,i.cartographicArrayToCartesianArray(A,I),c.projectPointsToNearestOnPlane(I,M);var T=Math.min(M[6].x,M[7].x,M[0].x),D=Math.max(M[2].x,M[3].x,M[4].x),R=Math.min(M[4].y,M[5].y,M[6].y),O=Math.max(M[0].y,M[1].y,M[2].y);v.height=d.height=g.height=C.height=t,i.cartographicArrayToCartesianArray(A,I);var N=Math.min(p.getPointDistance(h,I[0]),p.getPointDistance(h,I[2]),p.getPointDistance(h,I[4]),p.getPointDistance(h,I[6])),L=r;return b(c,T,D,R,O,N,L,o)},f.clone=function(e,t){return o(e)?o(t)?(r.clone(e.center,t.center),d.clone(e.halfAxes,t.halfAxes),t):new f(e.center,e.halfAxes):void 0},f.intersectPlane=function(e,t){var i=e.center,n=t.normal,o=e.halfAxes,a=n.x,s=n.y,l=n.z,c=Math.abs(a*o[d.COLUMN0ROW0]+s*o[d.COLUMN0ROW1]+l*o[d.COLUMN0ROW2])+Math.abs(a*o[d.COLUMN1ROW0]+s*o[d.COLUMN1ROW1]+l*o[d.COLUMN1ROW2])+Math.abs(a*o[d.COLUMN2ROW0]+s*o[d.COLUMN2ROW1]+l*o[d.COLUMN2ROW2]),h=r.dot(n,i)+t.distance;return-c>=h?u.OUTSIDE:h>=c?u.INSIDE:u.INTERSECTING};var D=new r,R=new r,O=new r,N=new r;f.distanceSquaredTo=function(e,t){var i=r.subtract(t,e.center,w),n=e.halfAxes,o=d.getColumn(n,0,D),a=d.getColumn(n,1,R),s=d.getColumn(n,2,O),l=r.magnitude(o),u=r.magnitude(a),c=r.magnitude(s);r.normalize(o,o),r.normalize(a,a),r.normalize(s,s);var h=N;h.x=r.dot(i,o),h.y=r.dot(i,a),h.z=r.dot(i,s);var p,m=0;return h.x<-l?(p=h.x+l,m+=p*p):h.x>l&&(p=h.x-l,m+=p*p),h.y<-u?(p=h.y+u,m+=p*p):h.y>u&&(p=h.y-u,m+=p*p),h.z<-c?(p=h.z+c,m+=p*p):h.z>c&&(p=h.z-c,m+=p*p),m};var L=new r,F=new r;new r;f.computePlaneDistances=function(e,t,i,n){o(n)||(n=new c);var a=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,l=e.center,u=e.halfAxes,h=d.getColumn(u,0,D),p=d.getColumn(u,1,R),m=d.getColumn(u,2,O),f=r.add(h,p,L);r.add(f,m,f),r.add(f,l,f);var v=r.subtract(f,t,F),_=r.dot(i,v);return a=Math.min(_,a),s=Math.max(_,s),r.add(l,h,f),r.add(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.add(l,h,f),r.subtract(f,p,f),r.add(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.add(l,h,f),r.subtract(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.add(f,p,f),r.add(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.add(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.subtract(f,p,f),r.add(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.subtract(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),n.start=a,n.stop=s,n};var B=new e;return f.isOccluded=function(t,r){var i=e.fromOrientedBoundingBox(t,B);return!r.isBoundingSphereVisible(i)},f.prototype.intersectPlane=function(e){return f.intersectPlane(this,e)},f.prototype.distanceSquaredTo=function(e){return f.distanceSquaredTo(this,e)},f.prototype.computePlaneDistances=function(e,t,r){return f.computePlaneDistances(this,e,t,r)},f.prototype.isOccluded=function(e){return f.isOccluded(this,e)},f.equals=function(e,t){return e===t||o(e)&&o(t)&&r.equals(e.center,t.center)&&d.equals(e.halfAxes,t.halfAxes)},f.prototype.clone=function(e){return f.clone(this,e)},f.prototype.equals=function(e){return f.equals(this,e)},f}),r("Core/Intersections2D",["./Cartesian3","./defined","./DeveloperError"],function(e,t,r){"use strict";var i={};return i.clipTriangleAtAxisAlignedThreshold=function(e,r,i,n,o,a){t(a)?a.length=0:a=[];var s,l,u;r?(s=e>i,l=e>n,u=e>o):(s=i>e,l=n>e,u=o>e);var c,h,d,p,m,f,v=s+l+u;return 1===v?s?(c=(e-i)/(n-i),h=(e-i)/(o-i),a.push(1),a.push(2),1!==h&&(a.push(-1),a.push(0),a.push(2),a.push(h)),1!==c&&(a.push(-1),a.push(0),a.push(1),a.push(c))):l?(d=(e-n)/(o-n),p=(e-n)/(i-n),a.push(2),a.push(0),1!==p&&(a.push(-1),a.push(1),a.push(0),a.push(p)),1!==d&&(a.push(-1),a.push(1),a.push(2),a.push(d))):u&&(m=(e-o)/(i-o),f=(e-o)/(n-o),a.push(0),a.push(1),1!==f&&(a.push(-1),a.push(2),a.push(1),a.push(f)),1!==m&&(a.push(-1),a.push(2),a.push(0),a.push(m))):2===v?s||i===e?l||n===e?u||o===e||(h=(e-i)/(o-i),d=(e-n)/(o-n),a.push(2),a.push(-1),a.push(0),a.push(2),a.push(h),a.push(-1),a.push(1),a.push(2),a.push(d)):(f=(e-o)/(n-o),c=(e-i)/(n-i),a.push(1),a.push(-1),a.push(2),a.push(1),a.push(f),a.push(-1),a.push(0),a.push(1),a.push(c)):(p=(e-n)/(i-n),m=(e-o)/(i-o),a.push(0),a.push(-1),a.push(1),a.push(0),a.push(p),a.push(-1),a.push(2),a.push(0),a.push(m)):3===v||(a.push(0),a.push(1),a.push(2)),a},i.computeBarycentricCoordinates=function(r,i,n,o,a,s,l,u,c){var h=n-l,d=l-a,p=s-u,m=o-u,f=1/(p*h+d*m),v=i-u,_=r-l,g=(p*_+d*v)*f,y=(-m*_+h*v)*f,C=1-g-y;return t(c)?(c.x=g,c.y=y,c.z=C,c):new e(g,y,C)},i}),r("Core/QuantizedMeshTerrainData",["../ThirdParty/when","./BoundingSphere","./Cartesian3","./defaultValue","./defined","./defineProperties","./DeveloperError","./IndexDatatype","./Intersections2D","./Math","./OrientedBoundingBox","./TaskProcessor","./TerrainMesh"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e,t,r){f.length=e.length;for(var i=!1,n=0,o=e.length;o>n;++n)f[n]=e[n],i=i||n>0&&t(e[n-1],e[n])>0;return i?(f.sort(t),s.createTypedArray(r,f)):e}var m=function(e){function t(e,t){return a[e]-a[t]}function r(e,t){return o[e]-o[t]}this._quantizedVertices=e.quantizedVertices,this._encodedNormals=e.encodedNormals,this._indices=e.indices,this._minimumHeight=e.minimumHeight,this._maximumHeight=e.maximumHeight,this._boundingSphere=e.boundingSphere,this._orientedBoundingBox=e.orientedBoundingBox,this._horizonOcclusionPoint=e.horizonOcclusionPoint;var n=this._quantizedVertices.length/3,o=this._uValues=this._quantizedVertices.subarray(0,n),a=this._vValues=this._quantizedVertices.subarray(n,2*n);this._heightValues=this._quantizedVertices.subarray(2*n,3*n);this._westIndices=p(e.westIndices,t,n),this._southIndices=p(e.southIndices,r,n),this._eastIndices=p(e.eastIndices,t,n),this._northIndices=p(e.northIndices,r,n),this._westSkirtHeight=e.westSkirtHeight,this._southSkirtHeight=e.southSkirtHeight,this._eastSkirtHeight=e.eastSkirtHeight,this._northSkirtHeight=e.northSkirtHeight,this._childTileMask=i(e.childTileMask,15),this._createdByUpsampling=i(e.createdByUpsampling,!1),this._waterMask=e.waterMask};o(m.prototype,{waterMask:{get:function(){return this._waterMask}}});var f=[],v=new h("createVerticesFromQuantizedTerrainMesh");m.prototype.createMesh=function(t,r,i,o){var a=t.ellipsoid,l=t.tileXYToRectangle(r,i,o),u=v.scheduleTask({minimumHeight:this._minimumHeight,maximumHeight:this._maximumHeight,quantizedVertices:this._quantizedVertices,octEncodedNormals:this._encodedNormals,indices:this._indices,westIndices:this._westIndices,southIndices:this._southIndices,eastIndices:this._eastIndices,northIndices:this._northIndices,westSkirtHeight:this._westSkirtHeight,southSkirtHeight:this._southSkirtHeight,eastSkirtHeight:this._eastSkirtHeight,northSkirtHeight:this._northSkirtHeight,rectangle:l,relativeToCenter:this._boundingSphere.center,ellipsoid:a});if(!n(u))return void 0;var c=this;return e(u,function(e){var t=c._quantizedVertices.length/3;t+=c._westIndices.length+c._southIndices.length+c._eastIndices.length+c._northIndices.length;var r=s.createTypedArray(t,e.indices);return new d(c._boundingSphere.center,new Float32Array(e.vertices),r,c._minimumHeight,c._maximumHeight,c._boundingSphere,c._horizonOcclusionPoint,n(c._encodedNormals)?7:6,c._orientedBoundingBox)})};var _=new h("upsampleQuantizedTerrainMesh");m.prototype.upsample=function(i,o,a,l,u,h,d){var p=2*o!==u,f=2*a===h,v=i.ellipsoid,g=i.tileXYToRectangle(u,h,d),y=_.scheduleTask({vertices:this._quantizedVertices,indices:this._indices,encodedNormals:this._encodedNormals,minimumHeight:this._minimumHeight,maximumHeight:this._maximumHeight,isEastChild:p,isNorthChild:f,childRectangle:g,ellipsoid:v});if(!n(y))return void 0;var C=Math.min(this._westSkirtHeight,this._eastSkirtHeight);C=Math.min(C,this._southSkirtHeight),C=Math.min(C,this._northSkirtHeight);var E=p?.5*C:this._westSkirtHeight,S=f?.5*C:this._southSkirtHeight,w=p?this._eastSkirtHeight:.5*C,T=f?this._northSkirtHeight:.5*C;return e(y,function(e){var i,o=new Uint16Array(e.vertices),a=s.createTypedArray(o.length/3,e.indices);return n(e.encodedNormals)&&(i=new Uint8Array(e.encodedNormals)),new m({quantizedVertices:o,indices:a,encodedNormals:i,minimumHeight:e.minimumHeight,maximumHeight:e.maximumHeight,boundingSphere:t.clone(e.boundingSphere),orientedBoundingBox:c.clone(e.orientedBoundingBox),horizonOcclusionPoint:r.clone(e.horizonOcclusionPoint),westIndices:e.westIndices,southIndices:e.southIndices,eastIndices:e.eastIndices,northIndices:e.northIndices,westSkirtHeight:E,southSkirtHeight:S,eastSkirtHeight:w,northSkirtHeight:T,childTileMask:0,createdByUpsampling:!0})})};var g=32767,y=new r;return m.prototype.interpolateHeight=function(e,t,r){var i=u.clamp((t-e.west)/e.width,0,1);i*=g;var n=u.clamp((r-e.south)/e.height,0,1);n*=g;for(var o=this._uValues,a=this._vValues,s=this._heightValues,c=this._indices,h=0,d=c.length;d>h;h+=3){var p=c[h],m=c[h+1],f=c[h+2],v=o[p],_=o[m],C=o[f],E=a[p],S=a[m],w=a[f],T=l.computeBarycentricCoordinates(i,n,v,E,_,S,C,w,y);if(T.x>=-1e-15&&T.y>=-1e-15&&T.z>=-1e-15){var b=T.x*s[p]+T.y*s[m]+T.z*s[f];return u.lerp(this._minimumHeight,this._maximumHeight,b/g)}}return void 0},m.prototype.isChildAvailable=function(e,t,r,i){var n=2;return r!==2*e&&++n,i!==2*t&&(n-=2),0!==(this._childTileMask&1<0?o.raiseEvent(d):console.log('An error occurred in "'+n.constructor.name+'": '+r(a)),d.retry&&t(c)&&c(),d},i.handleSuccess=function(e){t(e)&&(e.timesRetried=-1)},i}),r("Core/CesiumTerrainProvider",["../ThirdParty/Uri","../ThirdParty/when","./BoundingSphere","./Cartesian3","./Credit","./defaultValue","./defined","./defineProperties","./DeveloperError","./Event","./GeographicTilingScheme","./HeightmapTerrainData","./IndexDatatype","./joinUrls","./loadArrayBuffer","./loadJson","./Math","./Matrix3","./OrientedBoundingBox","./QuantizedMeshTerrainData","./RuntimeError","./TerrainProvider","./throttleRequestByServer","./TileProviderError"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";function T(e){if(a(e)&&0!==e.length){var t=e.join("-");return{Accept:"application/vnd.quantized-mesh;extensions="+t+",application/octet-stream;q=0.9,*/*;q=0.01"}}return{Accept:"application/vnd.quantized-mesh,application/octet-stream;q=0.9,*/*;q=0.01"}}function b(e,t,r,i,n,o){ +var a=new Uint16Array(t,0,e._heightmapWidth*e._heightmapWidth);return new h({buffer:a,childTileMask:new Uint8Array(t,a.byteLength,1)[0],waterMask:new Uint8Array(t,a.byteLength+1,t.byteLength-a.byteLength-1),width:e._heightmapWidth,height:e._heightmapWidth,structure:e._heightmapStructure})}function x(e,t,n,o,a,s){function l(e){return e>>1^-(1&e)}var u=0,c=3,h=c+1,p=Float64Array.BYTES_PER_ELEMENT*c,m=Float64Array.BYTES_PER_ELEMENT*h,f=3,_=Uint16Array.BYTES_PER_ELEMENT*f,C=3,E=Uint16Array.BYTES_PER_ELEMENT,S=E*C,w=new DataView(t),T=new i(w.getFloat64(u,!0),w.getFloat64(u+8,!0),w.getFloat64(u+16,!0));u+=p;var b=w.getFloat32(u,!0);u+=Float32Array.BYTES_PER_ELEMENT;var x=w.getFloat32(u,!0);u+=Float32Array.BYTES_PER_ELEMENT;var A=new r(new i(w.getFloat64(u,!0),w.getFloat64(u+8,!0),w.getFloat64(u+16,!0)),w.getFloat64(u+p,!0));u+=m;var I=new i(w.getFloat64(u,!0),w.getFloat64(u+8,!0),w.getFloat64(u+16,!0));u+=p;var D=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var R=new Uint16Array(t,u,3*D);u+=D*_,D>65536&&(E=Uint32Array.BYTES_PER_ELEMENT,S=E*C);var O,N=R.subarray(0,D),L=R.subarray(D,2*D),F=R.subarray(2*D,3*D),B=0,V=0,z=0;for(O=0;D>O;++O)B+=l(N[O]),V+=l(L[O]),z+=l(F[O]),N[O]=B,L[O]=V,F[O]=z;u%E!==0&&(u+=E-u%E);var k=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var U=d.createTypedArrayFromArrayBuffer(D,t,u,k*C);u+=k*S;var G=0;for(O=0;O=n.length)return 0;var a=n[o],s=0;return s|=A(a,2*r,2*i)?1:0,s|=A(a,2*r+1,2*i)?2:0,s|=A(a,2*r,2*i+1)?4:0,s|=A(a,2*r+1,2*i+1)?8:0}function A(e,t,r){for(var i=0,n=e.length;n>i;++i){var o=e[i];if(t>=o.startX&&t<=o.endX&&r>=o.startY&&r<=o.endY)return!0}return!1}var I=function(r){function i(t){var r;if(!t.format)return r="The tile format is not specified in the layer.json file.",void(m=w.handleError(m,v,v._errorEvent,r,void 0,void 0,void 0,l));if(!t.tiles||0===t.tiles.length)return r="The layer.json file does not specify any tile URL templates.",void(m=w.handleError(m,v,v._errorEvent,r,void 0,void 0,void 0,l));if("heightmap-1.0"===t.format)v._heightmapStructure={heightScale:.2,heightOffset:-1e3,elementsPerHeight:1,stride:1,elementMultiplier:256,isBigEndian:!1},v._hasWaterMask=!0,v._requestWaterMask=!0;else if(0!==t.format.indexOf("quantized-mesh-1."))return r='The tile format "'+t.format+'" is invalid or not supported.',void(m=w.handleError(m,v,v._errorEvent,r,void 0,void 0,void 0,l));v._tileUrlTemplates=t.tiles;for(var i=0;i=i.length)return!1;var n=i[r],o=this._tilingScheme.getNumberOfYTilesAtLevel(r),a=o-t-1;return A(n,e,a)}return void 0},I}),r("Core/EllipseGeometryLibrary",["./Cartesian3","./Math","./Matrix3","./Quaternion"],function(e,t,r,i){"use strict";function n(t,n,o,c,h,d,p,m,f,v){var _=t+n;e.multiplyByScalar(c,Math.cos(_),a),e.multiplyByScalar(o,Math.sin(_),s),e.add(a,s,a);var g=Math.cos(t);g*=g;var y=Math.sin(t);y*=y;var C=d/Math.sqrt(p*g+h*y),E=C/m;return i.fromAxisAngle(a,E,l),r.fromQuaternion(l,u),r.multiplyByVector(u,f,v),e.normalize(v,v),e.multiplyByScalar(v,m,v),v}var o={},a=new e,s=new e,l=new i,u=new r,c=new e,h=new e,d=new e,p=new e;o.raisePositionsToHeight=function(t,r,i){for(var n=r.ellipsoid,o=r.height,a=r.extrudedHeight,s=i?t.length/3*2:t.length/3,l=new Float64Array(3*s),u=t.length,m=i?u:0,f=0;u>f;f+=3){var v=f+1,_=f+2,g=e.fromArray(t,f,c);n.scaleToGeodeticSurface(g,g);var y=e.clone(g,h),C=n.geodeticSurfaceNormal(g,p),E=e.multiplyByScalar(C,o,d);e.add(g,E,g),i&&(e.multiplyByScalar(C,a,E),e.add(y,E,y),l[f+m]=y.x,l[v+m]=y.y,l[_+m]=y.z),l[f]=g.x,l[v]=g.y,l[_]=g.z}return l};var m=new e,f=new e,v=new e;return o.computeEllipsePositions=function(r,i,o){var a=r.semiMinorAxis,s=r.semiMajorAxis,l=r.rotation,u=r.center,p=8*r.granularity,_=a*a,g=s*s,y=s*a,C=e.magnitude(u),E=e.normalize(u,m),S=e.cross(e.UNIT_Z,u,f);S=e.normalize(S,S);var w=e.cross(E,S,v),T=1+Math.ceil(t.PI_OVER_TWO/p),b=t.PI_OVER_TWO/(T-1),x=t.PI_OVER_TWO-T*b;0>x&&(T-=Math.ceil(Math.abs(x)/b));var P,A,I,M,D,R=2*T*(T+1),O=i?new Array(3*R):void 0,N=0,L=c,F=h,B=3*(2*T+2*(T-1)),V=B-1,z=0,k=o?new Array(B):void 0;for(x=t.PI_OVER_TWO,P=0;T>P;++P){if(L=n(x,l,w,S,_,y,g,C,E,L),F=n(Math.PI-x,l,w,S,_,y,g,C,E,F),i){for(O[N++]=L.x,O[N++]=L.y,O[N++]=L.z,I=2*P+2,A=1;I-1>A;++A)M=A/(I-1),D=e.lerp(L,F,M,d),O[N++]=D.x,O[N++]=D.y,O[N++]=D.z;O[N++]=F.x,O[N++]=F.y,O[N++]=F.z}o&&(k[V--]=L.z,k[V--]=L.y,k[V--]=L.x,0!==P&&(k[z++]=F.x,k[z++]=F.y,k[z++]=F.z)),x=t.PI_OVER_TWO-(P+1)*b}for(P=T;P>0;--P){if(x=t.PI_OVER_TWO-(P-1)*b,L=n(-x,l,w,S,_,y,g,C,E,L),F=n(x+Math.PI,l,w,S,_,y,g,C,E,F),i){for(O[N++]=L.x,O[N++]=L.y,O[N++]=L.z,I=2*(P-1)+2,A=1;I-1>A;++A)M=A/(I-1),D=e.lerp(L,F,M,d),O[N++]=D.x,O[N++]=D.y,O[N++]=D.z;O[N++]=F.x,O[N++]=F.y,O[N++]=F.z}o&&(k[V--]=L.z,k[V--]=L.y,k[V--]=L.x,1!==P&&(k[z++]=F.x,k[z++]=F.y,k[z++]=F.z))}var U={};return i&&(U.positions=O,U.numPts=T),o&&(U.outerPositions=k),U},o}),r("Core/GeometryInstance",["./defaultValue","./defined","./DeveloperError","./Matrix4"],function(e,t,r,i){"use strict";var n=function(t){t=e(t,e.EMPTY_OBJECT),this.geometry=t.geometry,this.modelMatrix=i.clone(e(t.modelMatrix,i.IDENTITY)),this.id=t.id,this.pickPrimitive=t.pickPrimitive,this.attributes=e(t.attributes,{}),this.westHemisphereGeometry=void 0,this.eastHemisphereGeometry=void 0};return n}),r("Core/barycentricCoordinates",["./Cartesian2","./Cartesian3","./defined","./DeveloperError"],function(e,t,r,i){"use strict";var n=new t,o=new t,a=new t,s=function(i,s,l,u,c){r(c)||(c=new t);var h,d,p,m,f,v,_,g;r(s.z)?(h=t.subtract(l,s,n),d=t.subtract(u,s,o),p=t.subtract(i,s,a),m=t.dot(h,h),f=t.dot(h,d),v=t.dot(h,p),_=t.dot(d,d),g=t.dot(d,p)):(h=e.subtract(l,s,n),d=e.subtract(u,s,o),p=e.subtract(i,s,a),m=e.dot(h,h),f=e.dot(h,d),v=e.dot(h,p),_=e.dot(d,d),g=e.dot(d,p));var y=1/(m*_-f*f);return c.y=(_*v-f*g)*y,c.z=(m*g-f*v)*y,c.x=1-c.y-c.z,c};return s}),r("Core/EncodedCartesian3",["./Cartesian3","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this.high=e.clone(e.ZERO),this.low=e.clone(e.ZERO)};i.encode=function(e,r){t(r)||(r={high:0,low:0});var i;return e>=0?(i=65536*Math.floor(e/65536),r.high=i,r.low=e-i):(i=65536*Math.floor(-e/65536),r.high=-i,r.low=e+i),r};var n={high:0,low:0};i.fromCartesian=function(e,r){t(r)||(r=new i);var o=r.high,a=r.low;return i.encode(e.x,n),o.x=n.high,a.x=n.low,i.encode(e.y,n),o.y=n.high,a.y=n.low,i.encode(e.z,n),o.z=n.high,a.z=n.low,r};var o=new i;return i.writeElements=function(e,t,r){i.fromCartesian(e,o);var n=o.high,a=o.low;t[r]=n.x,t[r+1]=n.y,t[r+2]=n.z,t[r+3]=a.x,t[r+4]=a.y,t[r+5]=a.z},i}),r("Core/Tipsify",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i={};return i.calculateACMR=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.indices,n=r.maximumIndex,o=e(r.cacheSize,24),a=i.length;if(!t(n)){n=0;for(var s=0,l=i[s];a>s;)l>n&&(n=l),++s,l=i[s]}for(var u=[],c=0;n+1>c;c++)u[c]=0;for(var h=o+1,d=0;a>d;++d)h-u[i[d]]>o&&(u[i[d]]=h,++h);return(h-o+1)/(a/3)},i.tipsify=function(r){function i(e,t,r,i){for(;t.length>=1;){var n=t[t.length-1];if(t.splice(t.length-1,1),e[n].numLiveTriangles>0)return n}for(;i>o;){if(e[o].numLiveTriangles>0)return++o,o-1;++o}return-1}function n(e,t,r,n,o,a,s){for(var l,u=-1,c=-1,h=0;hc||-1===c)&&(c=l,u=d)),++h}return-1===u?i(n,a,e,s):u}r=e(r,e.EMPTY_OBJECT);var o,a=r.indices,s=r.maximumIndex,l=e(r.cacheSize,24),u=a.length,c=0,h=0,d=a[h],p=u;if(t(s))c=s+1;else{for(;p>h;)d>c&&(c=d),++h,d=a[h];if(-1===c)return 0;++c}for(var m=[],f=0;c>f;f++)m[f]={numLiveTriangles:0,timeStamp:0,vertexTriangles:[]};h=0;for(var v=0;p>h;)m[a[h]].vertexTriangles.push(v),++m[a[h]].numLiveTriangles,m[a[h+1]].vertexTriangles.push(v),++m[a[h+1]].numLiveTriangles,m[a[h+2]].vertexTriangles.push(v),++m[a[h+2]].numLiveTriangles,++v,h+=3;var _=0,g=l+1;o=1;var y,C,E=[],S=[],w=0,T=[],b=u/3,x=[];for(f=0;b>f;f++)x[f]=!1;for(var P,A;-1!==_;){E=[],C=m[_],A=C.vertexTriangles.length;for(var I=0;A>I;++I)if(v=C.vertexTriangles[I],!x[v]){x[v]=!0,h=v+v+v;for(var M=0;3>M;++M)P=a[h],E.push(P),S.push(P),T[w]=P,++w,y=m[P],--y.numLiveTriangles,g-y.timeStamp>l&&(y.timeStamp=g,++g),++h}_=n(a,l,E,m,g,S,c)}return T},i}),r("Core/GeometryPipeline",["./AttributeCompression","./barycentricCoordinates","./BoundingSphere","./Cartesian2","./Cartesian3","./Cartesian4","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./EncodedCartesian3","./GeographicProjection","./Geometry","./GeometryAttribute","./GeometryInstance","./GeometryType","./IndexDatatype","./Intersect","./IntersectionTests","./Math","./Matrix3","./Matrix4","./Plane","./PrimitiveType","./Tipsify"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b){"use strict";function x(e,t,r,i,n){e[t++]=r,e[t++]=i,e[t++]=i,e[t++]=n,e[t++]=n,e[t]=r}function P(e){for(var t=e.length,r=t/3*6,i=_.createTypedArray(t,r),n=0,o=0;t>o;o+=3,n+=6)x(i,n,e[o],e[o+1],e[o+2]);return i}function A(e){var t=e.length;if(t>=3){var r=6*(t-2),i=_.createTypedArray(t,r);x(i,0,e[0],e[1],e[2]);for(var n=6,o=3;t>o;++o,n+=6)x(i,n,e[o-1],e[o],e[o-2]);return i}return new Uint16Array}function I(e){if(e.length>0){for(var t=e.length-1,r=6*(t-1),i=_.createTypedArray(t,r),n=e[0],o=0,a=1;t>a;++a,o+=6)x(i,o,n,e[a],e[a+1]);return i}return new Uint16Array}function M(e){var t={};for(var r in e)if(e.hasOwnProperty(r)&&u(e[r])&&u(e[r].values)){var i=e[r];t[r]=new m({componentDatatype:i.componentDatatype,componentsPerAttribute:i.componentsPerAttribute,normalize:i.normalize,values:[]})}return t}function D(e,t,r){for(var i in t)if(t.hasOwnProperty(i)&&u(t[i])&&u(t[i].values))for(var n=t[i],o=0;oo;o+=3)n.unpack(r,o,oe),S.multiplyByPoint(e,oe,oe),n.pack(oe,r,o)}function O(e,t){if(u(t))for(var r=t.values,i=r.length,o=0;i>o;o+=3)n.unpack(r,o,oe),E.multiplyByVector(e,oe,oe),oe=n.normalize(oe,oe),n.pack(oe,r,o)}function N(e,t){var r,i=e.length,n={},o=e[0][t].attributes;for(r in o)if(o.hasOwnProperty(r)&&u(o[r])&&u(o[r].values)){for(var a=o[r],l=a.values.length,c=!0,h=1;i>h;++h){var d=e[h][t].attributes[r];if(!u(d)||a.componentDatatype!==d.componentDatatype||a.componentsPerAttribute!==d.componentsPerAttribute||a.normalize!==d.normalize){c=!1;break}l+=d.values.length}c&&(n[r]=new m({componentDatatype:a.componentDatatype,componentsPerAttribute:a.componentsPerAttribute,normalize:a.normalize,values:s.createTypedArray(a.componentDatatype,l)}))}return n}function L(e,t){var i,o,a,s,l,c,h,d=e.length,m=(e[0].modelMatrix,u(e[0][t].indices)),f=e[0][t].primitiveType,v=N(e,t);for(i in v)if(v.hasOwnProperty(i))for(l=v[i].values,s=0,o=0;d>o;++o)for(c=e[o][t].attributes[i].values,h=c.length,a=0;h>a;++a)l[s++]=c[a];var g;if(m){var y=0;for(o=0;d>o;++o)y+=e[o][t].indices.length;var C=p.computeNumberOfVertices(new p({attributes:v,primitiveType:T.POINTS})),E=_.createTypedArray(C,y),S=0,w=0;for(o=0;d>o;++o){var b=e[o][t].indices,x=b.length;for(s=0;x>s;++s)E[S++]=w+b[s];w+=p.computeNumberOfVertices(e[o][t])}g=E}var P,A=new n,I=0;for(o=0;d>o;++o){if(P=e[o][t].boundingSphere,!u(P)){A=void 0;break}n.add(P.center,A,A)}if(u(A))for(n.divideByScalar(A,d,A),o=0;d>o;++o){P=e[o][t].boundingSphere;var M=n.magnitude(n.subtract(P.center,A,le))+P.radius;M>I&&(I=M)}return new p({attributes:v,indices:g,primitiveType:f,boundingSphere:u(A)?new r(A,I):void 0})}function F(e){if(u(e.indices))return e;for(var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,t),i=0;t>i;++i)r[i]=i;return e.indices=r,e}function B(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,3*(t-2));r[0]=1,r[1]=0,r[2]=2;for(var i=3,n=3;t>n;++n)r[i++]=n-1,r[i++]=0,r[i++]=n;return e.indices=r,e.primitiveType=T.TRIANGLES,e}function V(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,3*(t-2));r[0]=0,r[1]=1,r[2]=2,t>3&&(r[3]=0,r[4]=2,r[5]=3);for(var i=6,n=3;t-1>n;n+=2)r[i++]=n,r[i++]=n-1,r[i++]=n+1,t>n+2&&(r[i++]=n,r[i++]=n+1,r[i++]=n+2);return e.indices=r,e.primitiveType=T.TRIANGLES,e}function z(e){if(u(e.indices))return e;for(var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,t),i=0;t>i;++i)r[i]=i;return e.indices=r,e}function k(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,2*(t-1));r[0]=0,r[1]=1;for(var i=2,n=2;t>n;++n)r[i++]=n-1,r[i++]=n;return e.indices=r,e.primitiveType=T.LINES,e}function U(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,2*t);r[0]=0,r[1]=1;for(var i=2,n=2;t>n;++n)r[i++]=n-1,r[i++]=n;return r[i++]=t-1,r[i]=0,e.indices=r,e.primitiveType=T.LINES,e}function G(e){switch(e.primitiveType){case T.TRIANGLE_FAN:return B(e);case T.TRIANGLE_STRIP:return V(e);case T.TRIANGLES:return F(e);case T.LINE_STRIP:return k(e);case T.LINE_LOOP:return U(e);case T.LINES:return z(e)}return e}function W(e,t){Math.abs(e.y)o?n>a?C.sign(e.y):C.sign(r.y):o>a?C.sign(t.y):C.sign(r.y);var s=0>i;W(e,s),W(t,s),W(r,s)}function q(e,t,r,i){n.add(e,n.multiplyByScalar(n.subtract(t,e,Ce),e.y/(e.y-t.y),Ce),r),n.clone(r,i),W(r,!0),W(i,!1)}function j(e,t,r){if(e.x>=0||t.x>=0||r.x>=0)return void 0;H(e,t,r);var i=e.y<0,n=t.y<0,o=r.y<0,a=0;a+=i?1:0,a+=n?1:0,a+=o?1:0;var s=be.indices;1===a?(s[1]=3,s[2]=4,s[5]=6,s[7]=6,s[8]=5,i?(q(e,t,Ee,we),q(e,r,Se,Te),s[0]=0,s[3]=1,s[4]=2,s[6]=1):n?(q(t,r,Ee,we),q(t,e,Se,Te),s[0]=1,s[3]=2,s[4]=0,s[6]=2):o&&(q(r,e,Ee,we),q(r,t,Se,Te),s[0]=2,s[3]=0,s[4]=1,s[6]=0)):2===a&&(s[2]=4,s[4]=4,s[5]=3,s[7]=5,s[8]=6,i?n?o||(q(r,e,Ee,we),q(r,t,Se,Te),s[0]=0,s[1]=1,s[3]=0,s[6]=2):(q(t,r,Ee,we),q(t,e,Se,Te),s[0]=2,s[1]=0,s[3]=2,s[6]=1):(q(e,t,Ee,we),q(e,r,Se,Te),s[0]=1,s[1]=2,s[3]=1,s[6]=0));var l=be.positions;return l[0]=e,l[1]=t,l[2]=r,l.length=3,(1===a||2===a)&&(l[3]=Ee,l[4]=Se,l[5]=we,l[6]=Te,l.length=7),be}function Y(e,t){var i=e.attributes;if(0===i.position.values.length)return void 0;for(var n in i)if(i.hasOwnProperty(n)&&u(i[n])&&u(i[n].values)){var o=i[n];o.values=s.createTypedArray(o.componentDatatype,o.values)}var a=p.computeNumberOfVertices(e);return e.indices=_.createTypedArray(a,e.indices),t&&(e.boundingSphere=r.fromVertices(i.position.values)),e}function X(e){var t=e.attributes,r={};for(var i in t)if(t.hasOwnProperty(i)&&u(t[i])&&u(t[i].values)){var n=t[i];r[i]=new m({componentDatatype:n.componentDatatype,componentsPerAttribute:n.componentsPerAttribute,normalize:n.normalize,values:[]})}return new p({attributes:r,indices:[],primitiveType:e.primitiveType})}function Z(e,t,r){var i=u(e.geometry.boundingSphere);t=Y(t,i),r=Y(r,i),u(r)&&!u(t)?e.geometry=r:!u(r)&&u(t)?e.geometry=t:(e.westHemisphereGeometry=t,e.eastHemisphereGeometry=r,e.geometry=void 0)}function K(e,r,o,a,s,l,c,h,d,p,m){if(u(l)||u(c)||u(h)||u(d)){var f=n.fromArray(s,3*e,xe),v=n.fromArray(s,3*r,Pe),_=n.fromArray(s,3*o,Ae),g=t(a,f,v,_,Ie);if(u(l)){var y=n.fromArray(l,3*e,xe),C=n.fromArray(l,3*r,Pe),E=n.fromArray(l,3*o,Ae);n.multiplyByScalar(y,g.x,y),n.multiplyByScalar(C,g.y,C),n.multiplyByScalar(E,g.z,E);var S=n.add(y,C,y);n.add(S,E,S),n.normalize(S,S),n.pack(S,p.normal.values,3*m)}if(u(c)){var w=n.fromArray(c,3*e,xe),T=n.fromArray(c,3*r,Pe),b=n.fromArray(c,3*o,Ae);n.multiplyByScalar(w,g.x,w),n.multiplyByScalar(T,g.y,T),n.multiplyByScalar(b,g.z,b);var x=n.add(w,T,w);n.add(x,b,x),n.normalize(x,x),n.pack(x,p.binormal.values,3*m)}if(u(h)){var P=n.fromArray(h,3*e,xe),A=n.fromArray(h,3*r,Pe),I=n.fromArray(h,3*o,Ae);n.multiplyByScalar(P,g.x,P),n.multiplyByScalar(A,g.y,A),n.multiplyByScalar(I,g.z,I);var M=n.add(P,A,P);n.add(M,I,M),n.normalize(M,M),n.pack(M,p.tangent.values,3*m)}if(u(d)){var D=i.fromArray(d,2*e,Me),R=i.fromArray(d,2*r,De),O=i.fromArray(d,2*o,Re);i.multiplyByScalar(D,g.x,D),i.multiplyByScalar(R,g.y,R),i.multiplyByScalar(O,g.z,O);var N=i.add(D,R,D);i.add(N,O,N),i.pack(N,p.st.values,2*m)}}}function J(e,t,r,i,n,o){var a=e.position.values.length/3;if(-1!==n){var s=i[n],l=r[s];return-1===l?(r[s]=a,e.position.values.push(o.x,o.y,o.z),t.push(a),a):(t.push(l),l)}return e.position.values.push(o.x,o.y,o.z),t.push(a),a}function Q(e){var t,r,i,o,a,s=e.geometry,l=s.attributes,c=l.position.values,h=u(l.normal)?l.normal.values:void 0,d=u(l.binormal)?l.binormal.values:void 0,p=u(l.tangent)?l.tangent.values:void 0,m=u(l.st)?l.st.values:void 0,f=s.indices,v=X(s),_=X(s),g=[];g.length=c.length/3;var y=[];for(y.length=c.length/3,a=0;aa;a+=3){var E=f[a],S=f[a+1],w=f[a+2],T=n.fromArray(c,3*E),b=n.fromArray(c,3*S),x=n.fromArray(c,3*w),P=j(T,b,x);if(u(P)&&P.positions.length>3)for(var A=P.positions,I=P.indices,M=I.length,D=0;M>D;++D){var R=I[D],O=A[R];O.y<0?(t=_.attributes,r=_.indices,i=g):(t=v.attributes,r=v.indices,i=y),o=J(t,r,i,f,3>R?a+R:-1,O),K(E,S,w,O,c,h,d,p,m,t,o)}else u(P)&&(T=P.positions[0],b=P.positions[1],x=P.positions[2]),T.y<0?(t=_.attributes,r=_.indices,i=g):(t=v.attributes,r=v.indices,i=y),o=J(t,r,i,f,a,T),K(E,S,w,T,c,h,d,p,m,t,o),o=J(t,r,i,f,a+1,b),K(E,S,w,b,c,h,d,p,m,t,o),o=J(t,r,i,f,a+2,x),K(E,S,w,x,c,h,d,p,m,t,o)}Z(e,_,v)}function $(e){var t,r=e.geometry,i=r.attributes,o=i.position.values,a=r.indices,s=X(r),l=X(r),c=a.length,h=[];h.length=o.length/3;var d=[];for(d.length=o.length/3,t=0;tt;t+=2){var p=a[t],m=a[t+1],f=n.fromArray(o,3*p,xe),v=n.fromArray(o,3*m,Pe);Math.abs(f.y)t;t+=4){var E=t,S=t+1,w=t+2,T=t+3,b=n.fromArray(c,3*E,Ve),x=n.fromArray(c,3*S,ze),P=n.fromArray(c,3*w,ke),A=n.fromArray(c,3*T,Ue);Math.abs(b.y)r;++r)I.prevPosition.values.push(h[r]);for(I.prevPosition.values.push(b.x,b.y,b.z,b.x,b.y,b.z),D.prevPosition.values.push(b.x,b.y,b.z,b.x,b.y,b.z),r=3*w;3*w+6>r;++r)D.prevPosition.values.push(h[r]);for(r=3*E;3*E+6>r;++r)I.nextPosition.values.push(d[r]);for(I.nextPosition.values.push(P.x,P.y,P.z,P.x,P.y,P.z),D.nextPosition.values.push(P.x,P.y,P.z,P.x,P.y,P.z),r=3*w;3*w+6>r;++r)D.nextPosition.values.push(d[r]);var F=i.fromArray(p,2*E,Fe),B=Math.abs(F.y);I.expandAndWidth.values.push(-1,B,1,B),I.expandAndWidth.values.push(-1,-B,1,-B),D.expandAndWidth.values.push(-1,B,1,B),D.expandAndWidth.values.push(-1,-B,1,-B);var V=n.magnitudeSquared(n.subtract(O,b,Ue));if(V/=n.magnitudeSquared(n.subtract(P,b,Ue)),u(f)){var z=o.fromArray(f,4*E,qe),k=o.fromArray(f,4*w,qe),U=C.lerp(z.x,k.x,V),G=C.lerp(z.y,k.y,V),W=C.lerp(z.z,k.z,V),H=C.lerp(z.w,k.w,V);for(r=4*E;4*E+8>r;++r)I.color.values.push(f[r]);for(I.color.values.push(U,G,W,H),I.color.values.push(U,G,W,H),D.color.values.push(U,G,W,H),D.color.values.push(U,G,W,H),r=4*w;4*w+8>r;++r)D.color.values.push(f[r])}if(u(m)){var q=i.fromArray(m,2*E,Fe),j=i.fromArray(m,2*(t+3),Be),Y=C.lerp(q.x,j.x,V);for(r=2*E;2*E+4>r;++r)I.st.values.push(m[r]);for(I.st.values.push(Y,q.y),I.st.values.push(Y,j.y),D.st.values.push(Y,q.y),D.st.values.push(Y,j.y),r=2*w;2*w+4>r;++r)D.st.values.push(m[r])}a=I.position.values.length/3-4,M.push(a,a+2,a+1),M.push(a+1,a+2,a+3),a=D.position.values.length/3-4,R.push(a,a+2,a+1),R.push(a+1,a+2,a+3)}else{var K,J;for(b.y<0?(K=_.attributes,J=_.indices):(K=v.attributes,J=v.indices),K.position.values.push(b.x,b.y,b.z),K.position.values.push(x.x,x.y,x.z),K.position.values.push(P.x,P.y,P.z),K.position.values.push(A.x,A.y,A.z),r=3*t;3*t+12>r;++r)K.prevPosition.values.push(h[r]),K.nextPosition.values.push(d[r]);for(r=2*t;2*t+8>r;++r)K.expandAndWidth.values.push(p[r]),u(m)&&K.st.values.push(m[r]);if(u(f))for(r=4*t;4*t+16>r;++r)K.color.values.push(f[r]);a=K.position.values.length/3-4,J.push(a,a+2,a+1),J.push(a+1,a+2,a+3)}}Z(e,_,v)}var te={};te.toWireframe=function(e){var t=e.indices;if(u(t)){switch(e.primitiveType){case T.TRIANGLES:e.indices=P(t);break;case T.TRIANGLE_STRIP:e.indices=A(t);break;case T.TRIANGLE_FAN:e.indices=I(t);break;default:throw new c("geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN.")}e.primitiveType=T.LINES}return e},te.createLineSegmentsForVectors=function(e,t,i){t=l(t,"normal"),i=l(i,1e4);for(var n=e.attributes.position.values,o=e.attributes[t].values,a=n.length,c=new Float64Array(2*a),h=0,d=0;a>d;d+=3)c[h++]=n[d],c[h++]=n[d+1],c[h++]=n[d+2],c[h++]=n[d]+o[d]*i,c[h++]=n[d+1]+o[d+1]*i,c[h++]=n[d+2]+o[d+2]*i;var f,v=e.boundingSphere;return u(v)&&(f=new r(v.center,v.radius+i)),new p({attributes:{position:new m({componentDatatype:s.DOUBLE,componentsPerAttribute:3,values:c})},primitiveType:T.LINES,boundingSphere:f})},te.createAttributeLocations=function(e){var t,r=["position","positionHigh","positionLow","position3DHigh","position3DLow","position2DHigh","position2DLow","pickColor","normal","st","binormal","tangent","compressedAttributes"],i=e.attributes,n={},o=0,a=r.length;for(t=0;a>t;++t){var s=r[t];u(i[s])&&(n[s]=o++)}for(var l in i)i.hasOwnProperty(l)&&!u(n[l])&&(n[l]=o++);return n},te.reorderForPreVertexCache=function(e){var t=p.computeNumberOfVertices(e),r=e.indices;if(u(r)){for(var i=new Int32Array(t),n=0;t>n;n++)i[n]=-1;for(var o,a=r,l=a.length,c=_.createTypedArray(t,l),h=0,d=0,m=0;l>h;)o=i[a[h]],-1!==o?c[d]=o:(o=a[h],i[o]=m,c[d]=m,++m),++h,++d;e.indices=c;var f=e.attributes;for(var v in f)if(f.hasOwnProperty(v)&&u(f[v])&&u(f[v].values)){for(var g=f[v],y=g.values,C=0,E=g.componentsPerAttribute,S=s.createTypedArray(g.componentDatatype,m*E);t>C;){var w=i[C];if(-1!==w)for(n=0;E>n;n++)S[E*w+n]=y[E*C+n];++C}g.values=S}}return e},te.reorderForPostVertexCache=function(e,t){var r=e.indices;if(e.primitiveType===T.TRIANGLES&&u(r)){for(var i=r.length,n=0,o=0;i>o;o++)r[o]>n&&(n=r[o]);e.indices=b.tipsify({indices:r,maximumIndex:n,cacheSize:t})}return e},te.fitToUnsignedShortIndices=function(e){var t=[],r=p.computeNumberOfVertices(e);if(u(e.indices)&&r>=C.SIXTY_FOUR_KILOBYTES){var i,n=[],o=[],a=0,s=M(e.attributes),l=e.indices,c=l.length;e.primitiveType===T.TRIANGLES?i=3:e.primitiveType===T.LINES?i=2:e.primitiveType===T.POINTS&&(i=1);for(var h=0;c>h;h+=i){for(var d=0;i>d;++d){var m=l[h+d],f=n[m];u(f)||(f=a++,n[m]=f,D(s,e.attributes,m)),o.push(f)}a+i>=C.SIXTY_FOUR_KILOBYTES&&(t.push(new p({attributes:s,indices:o,primitiveType:e.primitiveType,boundingSphere:e.boundingSphere,boundingSphereCV:e.boundingSphereCV})),n=[],o=[],a=0,s=M(e.attributes))}0!==o.length&&t.push(new p({attributes:s,indices:o,primitiveType:e.primitiveType,boundingSphere:e.boundingSphere,boundingSphereCV:e.boundingSphereCV}))}else t.push(e);return t};var re=new n,ie=new a;te.projectTo2D=function(e,t,r,i,o){var a=e.attributes[t];o=u(o)?o:new d;for(var l=o.ellipsoid,h=a.values,p=new Float64Array(h.length),f=0,v=0;vc;++c)h.encode(o[c],ne),l[c]=ne.high,u[c]=ne.low;var d=n.componentsPerAttribute;return e.attributes[r]=new m({componentDatatype:s.FLOAT,componentsPerAttribute:d,values:l}),e.attributes[i]=new m({componentDatatype:s.FLOAT,componentsPerAttribute:d,values:u}),delete e.attributes[t],e};var oe=new n,ae=new S,se=new E;te.transformToWorldCoordinates=function(e){var t=e.modelMatrix;if(S.equals(t,S.IDENTITY))return e;var i=e.geometry.attributes;R(t,i.position),R(t,i.prevPosition),R(t,i.nextPosition),(u(i.normal)||u(i.binormal)||u(i.tangent))&&(S.inverse(t,ae),S.transpose(ae,ae),S.getRotation(ae,se),O(se,i.normal),O(se,i.binormal),O(se,i.tangent));var n=e.geometry.boundingSphere;return u(n)&&(e.geometry.boundingSphere=r.transform(n,t,n)),e.modelMatrix=S.clone(S.IDENTITY),e};var le=new n;te.combineInstances=function(e){for(var t=[],r=[],i=e.length,n=0;i>n;++n){var o=e[n];u(o.geometry)?t.push(o):r.push(o)}var a=[];return t.length>0&&a.push(L(t,"geometry")),r.length>0&&(a.push(L(r,"westHemisphereGeometry")),a.push(L(r,"eastHemisphereGeometry"))),a};var ue=new n,ce=new n,he=new n,de=new n;te.computeNormal=function(e){for(var t=e.indices,r=e.attributes,i=r.position.values,o=r.position.values.length/3,a=t.length,l=new Array(o),u=new Array(a/3),c=new Array(a),h=0;o>h;h++)l[h]={indexOffset:0,count:0,currentCount:0};var d=0;for(h=0;a>h;h+=3){var p=t[h],f=t[h+1],v=t[h+2],_=3*p,g=3*f,y=3*v;ce.x=i[_],ce.y=i[_+1],ce.z=i[_+2],he.x=i[g],he.y=i[g+1],he.z=i[g+2],de.x=i[y],de.y=i[y+1],de.z=i[y+2],l[p].count++,l[f].count++,l[v].count++,n.subtract(he,ce,he),n.subtract(de,ce,de),u[d]=n.cross(he,de,new n),d++}var C=0;for(h=0;o>h;h++)l[h].indexOffset+=C,C+=l[h].count;d=0;var E;for(h=0;a>h;h+=3){E=l[t[h]];var S=E.indexOffset+E.currentCount;c[S]=d,E.currentCount++,E=l[t[h+1]],S=E.indexOffset+E.currentCount,c[S]=d,E.currentCount++,E=l[t[h+2]],S=E.indexOffset+E.currentCount,c[S]=d,E.currentCount++,d++}var w=new Float32Array(3*o);for(h=0;o>h;h++){var T=3*h;if(E=l[h],E.count>0){for(n.clone(n.ZERO,ue),d=0;dc;c+=3){var f=t[c],v=t[c+1],_=t[c+2];h=3*f,d=3*v,p=3*_;var g=2*f,y=2*v,C=2*_,E=r[h],S=r[h+1],w=r[h+2],T=o[g],b=o[g+1],x=o[y+1]-b,P=o[C+1]-b,A=1/((o[y]-T)*P-(o[C]-T)*x),I=(P*(r[d]-E)-x*(r[p]-E))*A,M=(P*(r[d+1]-S)-x*(r[p+1]-S))*A,D=(P*(r[d+2]-w)-x*(r[p+2]-w))*A; +u[h]+=I,u[h+1]+=M,u[h+2]+=D,u[d]+=I,u[d+1]+=M,u[d+2]+=D,u[p]+=I,u[p+1]+=M,u[p+2]+=D}var R=new Float32Array(3*a),O=new Float32Array(3*a);for(c=0;a>c;c++){h=3*c,d=h+1,p=h+2;var N=n.fromArray(i,h,pe),L=n.fromArray(u,h,fe),F=n.dot(N,L);n.multiplyByScalar(N,F,me),n.normalize(n.subtract(L,me,L),L),O[h]=L.x,O[d]=L.y,O[p]=L.z,n.normalize(n.cross(N,L,L),L),R[h]=L.x,R[d]=L.y,R[p]=L.z}return e.attributes.tangent=new m({componentDatatype:s.FLOAT,componentsPerAttribute:3,values:O}),e.attributes.binormal=new m({componentDatatype:s.FLOAT,componentsPerAttribute:3,values:R}),e};var ve=new i,_e=new n,ge=new n,ye=new n;te.compressVertices=function(t){var r=t.attributes.normal,o=t.attributes.st;if(!u(r)&&!u(o))return t;var a,l,c,h,d=t.attributes.tangent,p=t.attributes.binormal;u(r)&&(a=r.values),u(o)&&(l=o.values),u(d)&&(c=d.values),p&&(h=p.values);var f=u(a)?a.length:l.length,v=u(a)?3:2,_=f/v,g=_,y=u(l)&&u(a)?2:1;y+=u(c)||u(h)?1:0,g*=y;for(var C=new Float32Array(g),E=0,S=0;_>S;++S){u(l)&&(i.fromArray(l,2*S,ve),C[E++]=e.compressTextureCoordinates(ve));var w=3*S;u(a)&&u(c)&&u(h)?(n.fromArray(a,w,_e),n.fromArray(c,w,ge),n.fromArray(h,w,ye),e.octPack(_e,ge,ye,ve),C[E++]=ve.x,C[E++]=ve.y):(u(a)&&(n.fromArray(a,w,_e),C[E++]=e.octEncodeFloat(_e)),u(c)&&(n.fromArray(c,w,_e),C[E++]=e.octEncodeFloat(_e)),u(h)&&(n.fromArray(h,w,_e),C[E++]=e.octEncodeFloat(_e)))}return t.attributes.compressedAttributes=new m({componentDatatype:s.FLOAT,componentsPerAttribute:y,values:C}),u(a)&&delete t.attributes.normal,u(l)&&delete t.attributes.st,u(c)&&delete t.attributes.tangent,u(h)&&delete t.attributes.binormal,t};var Ce=new n,Ee=new n,Se=new n,we=new n,Te=new n,be={positions:new Array(7),indices:new Array(9)},xe=new n,Pe=new n,Ae=new n,Ie=new n,Me=new i,De=new i,Re=new i,Oe=w.fromPointNormal(n.ZERO,n.UNIT_Y),Ne=new n,Le=new n,Fe=new i,Be=new i,Ve=new n,ze=new n,ke=new n,Ue=new n,Ge=new n,We=new n,He=new n,qe=new o;new o;return te.splitLongitude=function(e){var t=e.geometry,i=t.boundingSphere;if(u(i)){var n=i.center.x-i.radius;if(n>0||r.intersectPlane(i,w.ORIGIN_ZX_PLANE)!==g.INTERSECTING)return e}if(t.geometryType!==v.NONE)switch(t.geometryType){case v.POLYLINES:ee(e);break;case v.TRIANGLES:Q(e);break;case v.LINES:$(e)}else G(t),t.primitiveType===T.TRIANGLES?Q(e):t.primitiveType===T.LINES&&$(e);return e},te}),r("Core/EllipseGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./EllipseGeometryLibrary","./Ellipsoid","./GeographicProjection","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./Matrix3","./PrimitiveType","./Quaternion","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";function S(e,i,o){var a=i.vertexFormat,s=i.center,u=i.semiMajorAxis,h=i.semiMinorAxis,m=i.ellipsoid,f=i.stRotation,v=o?e.length/3*2:e.length/3,_=a.st?new Float32Array(2*v):void 0,y=a.normal?new Float32Array(3*v):void 0,E=a.tangent?new Float32Array(3*v):void 0,S=a.binormal?new Float32Array(3*v):void 0,w=0,T=L,b=F,x=B,P=new c(m),D=P.project(m.cartesianToCartographic(s,V),z),G=m.scaleToGeodeticSurface(s,A);m.geodeticSurfaceNormal(G,G);for(var W=C.fromAxisAngle(G,f,N),H=g.fromQuaternion(W,O),q=t.fromElements(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,k),j=t.fromElements(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,U),Y=e.length,X=o?Y:0,Z=X/3*2,K=0;Y>K;K+=3){var J=K+1,Q=K+2,$=r.fromArray(e,K,A);if(a.st){var ee=g.multiplyByVector(H,$,I),te=P.project(m.cartesianToCartographic(ee,V),M);r.subtract(te,D,te),R.x=(te.x+u)/(2*u),R.y=(te.y+h)/(2*h),q.x=Math.min(R.x,q.x),q.y=Math.min(R.y,q.y),j.x=Math.max(R.x,j.x),j.y=Math.max(R.y,j.y),o&&(_[w+Z]=R.x,_[w+1+Z]=R.y),_[w++]=R.x,_[w++]=R.y}T=m.geodeticSurfaceNormal($,T),(a.normal||a.tangent||a.binormal)&&((a.tangent||a.binormal)&&(b=r.cross(r.UNIT_Z,T,b),g.multiplyByVector(H,b,b)),a.normal&&(y[K]=T.x,y[J]=T.y,y[Q]=T.z,o&&(y[K+X]=-T.x,y[J+X]=-T.y,y[Q+X]=-T.z)),a.tangent&&(E[K]=b.x,E[J]=b.y,E[Q]=b.z,o&&(E[K+X]=-b.x,E[J+X]=-b.y,E[Q+X]=-b.z)),a.binormal&&(x=r.cross(T,b,x),S[K]=x.x,S[J]=x.y,S[Q]=x.z,o&&(S[K+X]=x.x,S[J+X]=x.y,S[Q+X]=x.z)))}if(a.st){Y=_.length;for(var re=0;Y>re;re+=2)_[re]=(_[re]-q.x)/(j.x-q.x),_[re+1]=(_[re+1]-q.y)/(j.y-q.y)}var ie=new p;if(a.position){var ne=l.raisePositionsToHeight(e,i,o);ie.position=new d({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:ne})}return a.st&&(ie.st=new d({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:_})),a.normal&&(ie.normal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:y})),a.tangent&&(ie.tangent=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:E})),a.binormal&&(ie.binormal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:S})),ie}function w(e){var t,r,i,n,o,a=new Array(2*e*(e+1)),s=0;for(n=1;e>n;++n){for(i=n*(n+1),t=(n-1)*n,a[s++]=i++,a[s++]=t,a[s++]=i,r=2*n,o=0;r-1>o;++o)a[s++]=i,a[s++]=t++,a[s++]=t,a[s++]=i++,a[s++]=t,a[s++]=i;a[s++]=i++,a[s++]=t,a[s++]=i}for(r=2*e,++i,++t,n=0;r-1>n;++n)a[s++]=i,a[s++]=t++,a[s++]=t,a[s++]=i++,a[s++]=t,a[s++]=i;for(++t,++i,n=e-1;n>0;--n){for(a[s++]=t++,a[s++]=t,a[s++]=i,r=2*n,o=0;r-1>o;++o)a[s++]=i,a[s++]=t++,a[s++]=t,a[s++]=i++,a[s++]=t,a[s++]=i;a[s++]=t++,a[s++]=t++,a[s++]=i++}return a}function T(t){var i=t.center;G=r.multiplyByScalar(t.ellipsoid.geodeticSurfaceNormal(i,G),t.height,G),G=r.add(i,G,G);var n=new e(G,t.semiMajorAxis),o=l.computeEllipsePositions(t,!0,!1),a=o.positions,s=o.numPts,u=S(a,t,!1),c=w(s);return c=v.createTypedArray(a.length/3,c),{boundingSphere:n,attributes:u,indices:c}}function b(e,i){var o=i.vertexFormat,a=i.center,s=i.semiMajorAxis,l=i.semiMinorAxis,u=i.ellipsoid,h=i.height,m=i.extrudedHeight,f=i.stRotation,v=e.length/3*2,_=new Float64Array(3*v),y=o.st?new Float32Array(2*v):void 0,E=o.normal?new Float32Array(3*v):void 0,S=o.tangent?new Float32Array(3*v):void 0,w=o.binormal?new Float32Array(3*v):void 0,T=0,b=L,x=F,P=B,G=new c(u),W=G.project(u.cartesianToCartographic(a,V),z),H=u.scaleToGeodeticSurface(a,A);u.geodeticSurfaceNormal(H,H);for(var q=C.fromAxisAngle(H,f,N),j=g.fromQuaternion(q,O),Y=t.fromElements(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,k),X=t.fromElements(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,U),Z=e.length,K=Z/3*2,J=0;Z>J;J+=3){var Q,$=J+1,ee=J+2,te=r.fromArray(e,J,A);if(o.st){var re=g.multiplyByVector(j,te,I),ie=G.project(u.cartesianToCartographic(re,V),M);r.subtract(ie,W,ie),R.x=(ie.x+s)/(2*s),R.y=(ie.y+l)/(2*l),Y.x=Math.min(R.x,Y.x),Y.y=Math.min(R.y,Y.y),X.x=Math.max(R.x,X.x),X.y=Math.max(R.y,X.y),y[T+K]=R.x,y[T+1+K]=R.y,y[T++]=R.x,y[T++]=R.y}te=u.scaleToGeodeticSurface(te,te),Q=r.clone(te,I),b=u.geodeticSurfaceNormal(te,b);var ne=r.multiplyByScalar(b,h,D);if(te=r.add(te,ne,te),ne=r.multiplyByScalar(b,m,ne),Q=r.add(Q,ne,Q),o.position&&(_[J+Z]=Q.x,_[$+Z]=Q.y,_[ee+Z]=Q.z,_[J]=te.x,_[$]=te.y,_[ee]=te.z),o.normal||o.tangent||o.binormal){P=r.clone(b,P);var oe=r.fromArray(e,(J+3)%Z,D);r.subtract(oe,te,oe);var ae=r.subtract(Q,te,M);b=r.normalize(r.cross(ae,oe,b),b),o.normal&&(E[J]=b.x,E[$]=b.y,E[ee]=b.z,E[J+Z]=b.x,E[$+Z]=b.y,E[ee+Z]=b.z),o.tangent&&(x=r.normalize(r.cross(P,b,x),x),S[J]=x.x,S[$]=x.y,S[ee]=x.z,S[J+Z]=x.x,S[J+1+Z]=x.y,S[J+2+Z]=x.z),o.binormal&&(w[J]=P.x,w[$]=P.y,w[ee]=P.z,w[J+Z]=P.x,w[$+Z]=P.y,w[ee+Z]=P.z)}}if(o.st){Z=y.length;for(var se=0;Z>se;se+=2)y[se]=(y[se]-Y.x)/(X.x-Y.x),y[se+1]=(y[se+1]-Y.y)/(X.y-Y.y)}var le=new p;return o.position&&(le.position=new d({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:_})),o.st&&(le.st=new d({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:y})),o.normal&&(le.normal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:E})),o.tangent&&(le.tangent=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:S})),o.binormal&&(le.binormal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:w})),le}function x(e){for(var t=e.length/3,r=v.createTypedArray(t,6*t),i=0,n=0;t>n;n++){var o=n,a=n+t,s=(o+1)%t,l=s+t;r[i++]=o,r[i++]=a,r[i++]=s,r[i++]=s,r[i++]=a,r[i++]=l}return r}function P(t){var i=t.center,n=t.ellipsoid,o=t.semiMajorAxis,a=r.multiplyByScalar(n.geodeticSurfaceNormal(i,A),t.height,A);W.center=r.add(i,a,W.center),W.radius=o,a=r.multiplyByScalar(n.geodeticSurfaceNormal(i,a),t.extrudedHeight,a),H.center=r.add(i,a,H.center),H.radius=o;var s=l.computeEllipsePositions(t,!0,!0),u=s.positions,c=s.numPts,d=s.outerPositions,p=e.union(W,H),_=S(u,t,!0),g=w(c),C=g.length;g.length=2*C;for(var E=u.length/3,T=0;C>T;T+=3)g[T+C]=g[T+2]+E,g[T+1+C]=g[T+1]+E,g[T+2+C]=g[T]+E;var P=v.createTypedArray(2*E/3,g),I=new h({attributes:_,indices:P,primitiveType:y.TRIANGLES}),M=b(d,t);g=x(d);var D=v.createTypedArray(2*d.length/3,g),R=new h({attributes:M,indices:D,primitiveType:y.TRIANGLES}),O=f.combineInstances([new m({geometry:I}),new m({geometry:R})]);return{boundingSphere:p,attributes:O[0].attributes,indices:O[0].indices}}var A=new r,I=new r,M=new r,D=new r,R=new t,O=new g,N=new C,L=new r,F=new r,B=new r,V=new i,z=new r,k=new t,U=new t,G=new r,W=new e,H=new e,q=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.center,i=o(e.ellipsoid,u.WGS84),n=e.semiMajorAxis,s=e.semiMinorAxis,l=o(e.granularity,_.RADIANS_PER_DEGREE),c=o(e.height,0),h=e.extrudedHeight,d=a(h)&&Math.abs(c-h)>1,p=o(e.vertexFormat,E.DEFAULT);this._center=r.clone(t),this._semiMajorAxis=n,this._semiMinorAxis=s,this._ellipsoid=u.clone(i),this._rotation=o(e.rotation,0),this._stRotation=o(e.stRotation,0),this._height=c,this._granularity=l,this._vertexFormat=E.clone(p),this._extrudedHeight=o(h,c),this._extrude=d,this._workerName="createEllipseGeometry"};q.packedLength=r.packedLength+u.packedLength+E.packedLength+8,q.pack=function(e,t,i){i=o(i,0),r.pack(e._center,t,i),i+=r.packedLength,u.pack(e._ellipsoid,t,i),i+=u.packedLength,E.pack(e._vertexFormat,t,i),i+=E.packedLength,t[i++]=e._semiMajorAxis,t[i++]=e._semiMinorAxis,t[i++]=e._rotation,t[i++]=e._stRotation,t[i++]=e._height,t[i++]=e._granularity,t[i++]=e._extrudedHeight,t[i]=e._extrude?1:0};var j=new r,Y=new u,X=new E,Z={center:j,ellipsoid:Y,vertexFormat:X,semiMajorAxis:void 0,semiMinorAxis:void 0,rotation:void 0,stRotation:void 0,height:void 0,granularity:void 0,extrudedHeight:void 0};return q.unpack=function(e,t,i){t=o(t,0);var n=r.unpack(e,t,j);t+=r.packedLength;var s=u.unpack(e,t,Y);t+=u.packedLength;var l=E.unpack(e,t,X);t+=E.packedLength;var c=e[t++],h=e[t++],d=e[t++],p=e[t++],m=e[t++],f=e[t++],v=e[t++],_=1===e[t];return a(i)?(i._center=r.clone(n,i._center),i._ellipsoid=u.clone(s,i._ellipsoid),i._vertexFormat=E.clone(l,i._vertexFormat),i._semiMajorAxis=c,i._semiMinorAxis=h,i._rotation=d,i._stRotation=p,i._height=m,i._granularity=f,i._extrudedHeight=v,i._extrude=_,i):(Z.height=m,Z.extrudedHeight=v,Z.granularity=f,Z.stRotation=p,Z.rotation=d,Z.semiMajorAxis=c,Z.semiMinorAxis=h,new q(Z))},q.createGeometry=function(e){e._center=e._ellipsoid.scaleToGeodeticSurface(e._center,e._center);var t,r={center:e._center,semiMajorAxis:e._semiMajorAxis,semiMinorAxis:e._semiMinorAxis,ellipsoid:e._ellipsoid,rotation:e._rotation,height:e._height,extrudedHeight:e._extrudedHeight,granularity:e._granularity,vertexFormat:e._vertexFormat,stRotation:e._stRotation};return e._extrude?(r.extrudedHeight=Math.min(e._extrudedHeight,e._height),r.height=Math.max(e._extrudedHeight,e._height),t=P(r)):t=T(r),new h({attributes:t.attributes,indices:t.indices,primitiveType:y.TRIANGLES,boundingSphere:t.boundingSphere})},q.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new q({center:e._center,semiMajorAxis:e._semiMajorAxis,semiMinorAxis:e._semiMinorAxis,ellipsoid:n,stRotation:e._stRotation,granularity:i,extrudedHeight:o,height:a,vertexFormat:E.POSITION_ONLY})},q}),r("Core/CircleGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipseGeometry","./Ellipsoid","./Math","./VertexFormat"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.radius,i={center:e.center,semiMajorAxis:r,semiMinorAxis:r,ellipsoid:e.ellipsoid,height:e.height,extrudedHeight:e.extrudedHeight,granularity:e.granularity,vertexFormat:e.vertexFormat,stRotation:e.stRotation};this._ellipseGeometry=new n(i),this._workerName="createCircleGeometry"};l.packedLength=n.packedLength,l.pack=function(e,t,r){n.pack(e._ellipseGeometry,t,r)};var u=new n({center:new e,semiMajorAxis:1,semiMinorAxis:1}),c={center:new e,radius:void 0,ellipsoid:o.clone(o.UNIT_SPHERE),height:void 0,extrudedHeight:void 0,granularity:void 0,vertexFormat:new s,stRotation:void 0,semiMajorAxis:void 0,semiMinorAxis:void 0};return l.unpack=function(t,i,a){var h=n.unpack(t,i,u);return c.center=e.clone(h._center,c.center),c.ellipsoid=o.clone(h._ellipsoid,c.ellipsoid),c.height=h._height,c.extrudedHeight=h._extrudedHeight,c.granularity=h._granularity,c.vertexFormat=s.clone(h._vertexFormat,c.vertexFormat),c.stRotation=h._stRotation,r(a)?(c.semiMajorAxis=h._semiMajorAxis,c.semiMinorAxis=h._semiMinorAxis,a._ellipseGeometry=new n(c),a):(c.radius=h._semiMajorAxis,new l(c))},l.createGeometry=function(e){return n.createGeometry(e._ellipseGeometry)},l.createShadowVolume=function(e,t,r){var i=e._ellipseGeometry._granularity,n=e._ellipseGeometry._ellipsoid,o=t(i,n),a=r(i,n);return new l({center:e._ellipseGeometry._center,radius:e._ellipseGeometry._semiMajorAxis,ellipsoid:n,stRotation:e._ellipseGeometry._stRotation,granularity:i,extrudedHeight:o,height:a,vertexFormat:s.POSITION_ONLY})},l}),r("Core/EllipseOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./EllipseGeometryLibrary","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(i){var n=i.center;_=t.multiplyByScalar(i.ellipsoid.geodeticSurfaceNormal(n,_),i.height,_),_=t.add(n,_,_);for(var o=new e(_,i.semiMajorAxis),s=a.computeEllipsePositions(i,!1,!0).outerPositions,l=new c({position:new u({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:a.raisePositionsToHeight(s,i,!1)})}),d=s.length/3,p=h.createTypedArray(d,2*d),m=0,f=0;d>f;++f)p[m++]=f,p[m++]=(f+1)%d;return{boundingSphere:o,attributes:l,indices:p}}function f(n){var o=i(n.numberOfVerticalLines,16);o=Math.max(o,0);var s=n.center,l=n.ellipsoid,d=n.semiMajorAxis,p=t.multiplyByScalar(l.geodeticSurfaceNormal(s,v),n.height,v);g.center=t.add(s,p,g.center),g.radius=d,p=t.multiplyByScalar(l.geodeticSurfaceNormal(s,p),n.extrudedHeight,p),y.center=t.add(s,p,y.center),y.radius=d;var m=a.computeEllipsePositions(n,!1,!0).outerPositions,f=new c({position:new u({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:a.raisePositionsToHeight(m,n,!0)})});m=f.position.values;var _=e.union(g,y),C=m.length/3,E=h.createTypedArray(C,2*C+2*o);C/=2;var S,w=0;for(S=0;C>S;++S)E[w++]=S,E[w++]=(S+1)%C,E[w++]=S+C,E[w++]=(S+1)%C+C;var T;if(o>0){var b=Math.min(o,C);T=Math.round(C/b)}var x=Math.min(T*o,C);if(o>0)for(S=0;x>S;S+=T)E[w++]=S,E[w++]=S+C;return{boundingSphere:_,attributes:f,indices:E}}var v=new t,_=new t,g=new e,y=new e,C=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.center,o=i(e.ellipsoid,s.WGS84),a=e.semiMajorAxis,l=e.semiMinorAxis,u=i(e.granularity,d.RADIANS_PER_DEGREE),c=i(e.height,0),h=e.extrudedHeight,p=n(h)&&Math.abs(c-h)>1;this._center=t.clone(r),this._semiMajorAxis=a,this._semiMinorAxis=l,this._ellipsoid=s.clone(o),this._rotation=i(e.rotation,0),this._height=c,this._granularity=u,this._extrudedHeight=h,this._extrude=p,this._numberOfVerticalLines=Math.max(i(e.numberOfVerticalLines,16),0),this._workerName="createEllipseOutlineGeometry"};C.packedLength=t.packedLength+s.packedLength+9,C.pack=function(e,r,o){o=i(o,0),t.pack(e._center,r,o),o+=t.packedLength,s.pack(e._ellipsoid,r,o),o+=s.packedLength,r[o++]=e._semiMajorAxis,r[o++]=e._semiMinorAxis,r[o++]=e._rotation,r[o++]=e._height,r[o++]=e._granularity,r[o++]=n(e._extrudedHeight)?1:0,r[o++]=i(e._extrudedHeight,0),r[o++]=e._extrude?1:0,r[o]=e._numberOfVerticalLines};var E=new t,S=new s,w={center:E,ellipsoid:S,semiMajorAxis:void 0,semiMinorAxis:void 0,rotation:void 0,height:void 0,granularity:void 0,extrudedHeight:void 0,numberOfVerticalLines:void 0};return C.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,E);r+=t.packedLength;var l=s.unpack(e,r,S);r+=s.packedLength;var u=e[r++],c=e[r++],h=e[r++],d=e[r++],p=e[r++],m=e[r++],f=e[r++],v=1===e[r++],_=e[r];return n(o)?(o._center=t.clone(a,o._center),o._ellipsoid=s.clone(l,o._ellipsoid),o._semiMajorAxis=u,o._semiMinorAxis=c,o._rotation=h,o._height=d,o._granularity=p,o._extrudedHeight=m?f:void 0,o._extrude=v,o._numberOfVerticalLines=_,o):(w.height=d,w.extrudedHeight=m?f:void 0,w.granularity=p,w.rotation=h,w.semiMajorAxis=u,w.semiMinorAxis=c,w.numberOfVerticalLines=_,new C(w))},C.createGeometry=function(e){e._center=e._ellipsoid.scaleToGeodeticSurface(e._center,e._center);var t,r={center:e._center,semiMajorAxis:e._semiMajorAxis,semiMinorAxis:e._semiMinorAxis,ellipsoid:e._ellipsoid,rotation:e._rotation,height:e._height,extrudedHeight:e._extrudedHeight,granularity:e._granularity,numberOfVerticalLines:e._numberOfVerticalLines};return e._extrude?(r.extrudedHeight=Math.min(e._extrudedHeight,e._height),r.height=Math.max(e._extrudedHeight,e._height),t=f(r)):t=m(r),new l({attributes:t.attributes,indices:t.indices,primitiveType:p.LINES,boundingSphere:t.boundingSphere})},C}),r("Core/CircleOutlineGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipseOutlineGeometry","./Ellipsoid"],function(e,t,r,i,n,o){"use strict";var a=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.radius,i={center:e.center,semiMajorAxis:r,semiMinorAxis:r,ellipsoid:e.ellipsoid,height:e.height,extrudedHeight:e.extrudedHeight,granularity:e.granularity,numberOfVerticalLines:e.numberOfVerticalLines};this._ellipseGeometry=new n(i),this._workerName="createCircleOutlineGeometry"};a.packedLength=n.packedLength,a.pack=function(e,t,r){n.pack(e._ellipseGeometry,t,r)};var s=new n({center:new e,semiMajorAxis:1,semiMinorAxis:1}),l={center:new e,radius:void 0,ellipsoid:o.clone(o.UNIT_SPHERE),height:void 0,extrudedHeight:void 0,granularity:void 0,numberOfVerticalLines:void 0,semiMajorAxis:void 0,semiMinorAxis:void 0};return a.unpack=function(t,i,u){var c=n.unpack(t,i,s);return l.center=e.clone(c._center,l.center),l.ellipsoid=o.clone(c._ellipsoid,l.ellipsoid),l.height=c._height,l.extrudedHeight=c._extrudedHeight,l.granularity=c._granularity,l.numberOfVerticalLines=c._numberOfVerticalLines,r(u)?(l.semiMajorAxis=c._semiMajorAxis,l.semiMinorAxis=c._semiMinorAxis,u._ellipseGeometry=new n(l),u):(l.radius=c._semiMajorAxis,new a(l))},a.createGeometry=function(e){return n.createGeometry(e._ellipseGeometry)},a}),r("Core/ClockRange",["./freezeObject"],function(e){"use strict";var t={UNBOUNDED:0,CLAMPED:1,LOOP_STOP:2};return e(t)}),r("Core/ClockStep",["./freezeObject"],function(e){"use strict";var t={TICK_DEPENDENT:0,SYSTEM_CLOCK_MULTIPLIER:1,SYSTEM_CLOCK:2};return e(t)}),r("Core/getTimestamp",["./defined"],function(e){"use strict";var t;return t="undefined"!=typeof performance&&e(performance.now)?function(){return performance.now()}:function(){return Date.now()}}),r("Core/Clock",["./ClockRange","./ClockStep","./defaultValue","./defined","./DeveloperError","./Event","./getTimestamp","./JulianDate"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(n){n=r(n,r.EMPTY_OBJECT);var l=n.startTime,u=!i(l),c=n.stopTime,h=!i(c),d=n.currentTime,p=!i(d);u&&h&&p?(d=s.now(),l=s.clone(d),c=s.addDays(d,1,new s)):u&&h?(l=s.clone(d),c=s.addDays(d,1,new s)):u&&p?(l=s.addDays(c,-1,new s),d=s.clone(l)):p&&h?(d=s.clone(l),c=s.addDays(l,1,new s)):p?d=s.clone(l):h?c=s.addDays(d,1,new s):u&&(l=s.clone(d)),this.startTime=l,this.stopTime=c,this.currentTime=d,this.multiplier=r(n.multiplier,1),this.clockStep=r(n.clockStep,t.SYSTEM_CLOCK_MULTIPLIER),this.clockRange=r(n.clockRange,e.UNBOUNDED),this.canAnimate=r(n.canAnimate,!0),this.shouldAnimate=r(n.shouldAnimate,!0),this.onTick=new o,this._lastSystemTime=a()};return l.prototype.tick=function(){var r=a(),i=s.clone(this.currentTime),n=this.startTime,o=this.stopTime,l=this.multiplier;if(this.canAnimate&&this.shouldAnimate)if(this.clockStep===t.SYSTEM_CLOCK)i=s.now(i);else{if(this.clockStep===t.TICK_DEPENDENT)i=s.addSeconds(i,l,i);else{var u=r-this._lastSystemTime;i=s.addSeconds(i,l*(u/1e3),i)}if(this.clockRange===e.CLAMPED)s.lessThan(i,n)?i=s.clone(n,i):s.greaterThan(i,o)&&(i=s.clone(o,i));else if(this.clockRange===e.LOOP_STOP)for(s.lessThan(i,n)&&(i=s.clone(n,i));s.greaterThan(i,o);)i=s.addSeconds(n,s.secondsDifference(i,o),i)}return this.currentTime=i,this._lastSystemTime=r,this.onTick.raiseEvent(this),i},l}),r("Core/Color",["./defaultValue","./defined","./DeveloperError","./FeatureDetection","./freezeObject","./Math"],function(e,t,r,i,n,o){"use strict";function a(e,t,r){return 0>r&&(r+=1),r>1&&(r-=1),1>6*r?e+6*(t-e)*r:1>2*r?t:2>3*r?e+(t-e)*(2/3-r)*6:e}var s=function(t,r,i,n){this.red=e(t,1),this.green=e(r,1),this.blue=e(i,1),this.alpha=e(n,1)};s.fromCartesian4=function(e,r){return t(r)?(r.red=e.x,r.green=e.y,r.blue=e.z,r.alpha=e.w,r):new s(e.x,e.y,e.z,e.w)},s.fromBytes=function(r,i,n,o,a){return r=s.byteToFloat(e(r,255)),i=s.byteToFloat(e(i,255)),n=s.byteToFloat(e(n,255)),o=s.byteToFloat(e(o,255)),t(a)?(a.red=r,a.green=i,a.blue=n,a.alpha=o,a):new s(r,i,n,o)},s.fromAlpha=function(e,r,i){return t(i)?(i.red=e.red,i.green=e.green,i.blue=e.blue,i.alpha=r,i):new s(e.red,e.green,e.blue,r)};var l,u,c;i.supportsTypedArrays()&&(l=new ArrayBuffer(4),u=new Uint32Array(l),c=new Uint8Array(l)),s.fromRgba=function(e){return u[0]=e,s.fromBytes(c[0],c[1],c[2],c[3])},s.fromHsl=function(t,r,i,n){t=e(t,0)%1,r=e(r,0),i=e(i,0),n=e(n,1);var o=i,l=i,u=i;if(0!==r){var c;c=.5>i?i*(1+r):i+r-i*r;var h=2*i-c;o=a(h,c,t+1/3),l=a(h,c,t),u=a(h,c,t-1/3)}return new s(o,l,u,n)},s.fromRandom=function(r,i){r=e(r,e.EMPTY_OBJECT);var n=r.red;if(!t(n)){var a=e(r.minimumRed,0),l=e(r.maximumRed,1);n=a+o.nextRandomNumber()*(l-a)}var u=r.green;if(!t(u)){var c=e(r.minimumGreen,0),h=e(r.maximumGreen,1);u=c+o.nextRandomNumber()*(h-c)}var d=r.blue;if(!t(d)){var p=e(r.minimumBlue,0),m=e(r.maximumBlue,1);d=p+o.nextRandomNumber()*(m-p)}var f=r.alpha;if(!t(f)){var v=e(r.minimumAlpha,0),_=e(r.maximumAlpha,1);f=v+o.nextRandomNumber()*(_-v)}return t(i)?(i.red=n,i.green=u,i.blue=d,i.alpha=f,i):new s(n,u,d,f)};var h=/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i,d=/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i,p=/^rgba?\(\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)(?:\s*,\s*([0-9.]+))?\s*\)$/i,m=/^hsla?\(\s*([0-9.]+)\s*,\s*([0-9.]+%)\s*,\s*([0-9.]+%)(?:\s*,\s*([0-9.]+))?\s*\)$/i;return s.fromCssColorString=function(r){var i=s[r.toUpperCase()];if(t(i))return s.clone(i);var n=h.exec(r);return null!==n?new s(parseInt(n[1],16)/15,parseInt(n[2],16)/15,parseInt(n[3],16)/15):(n=d.exec(r),null!==n?new s(parseInt(n[1],16)/255,parseInt(n[2],16)/255,parseInt(n[3],16)/255):(n=p.exec(r),null!==n?new s(parseFloat(n[1])/("%"===n[1].substr(-1)?100:255),parseFloat(n[2])/("%"===n[2].substr(-1)?100:255),parseFloat(n[3])/("%"===n[3].substr(-1)?100:255),parseFloat(e(n[4],"1.0"))):(n=m.exec(r),null!==n?s.fromHsl(parseFloat(n[1])/360,parseFloat(n[2])/100,parseFloat(n[3])/100,parseFloat(e(n[4],"1.0"))):void 0)))},s.packedLength=4,s.pack=function(t,r,i){i=e(i,0),r[i++]=t.red,r[i++]=t.green,r[i++]=t.blue,r[i]=t.alpha},s.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new s),n.red=r[i++],n.green=r[i++],n.blue=r[i++],n.alpha=r[i],n},s.byteToFloat=function(e){return e/255},s.floatToByte=function(e){return 1===e?255:256*e|0},s.clone=function(e,r){return t(e)?t(r)?(r.red=e.red,r.green=e.green,r.blue=e.blue,r.alpha=e.alpha,r):new s(e.red,e.green,e.blue,e.alpha):void 0},s.equals=function(e,r){return e===r||t(e)&&t(r)&&e.red===r.red&&e.green===r.green&&e.blue===r.blue&&e.alpha===r.alpha},s.equalsArray=function(e,t,r){return e.red===t[r]&&e.green===t[r+1]&&e.blue===t[r+2]&&e.alpha===t[r+3]},s.prototype.clone=function(e){return s.clone(this,e)},s.prototype.equals=function(e){return s.equals(this,e)},s.prototype.equalsEpsilon=function(e,r){return this===e||t(e)&&Math.abs(this.red-e.red)<=r&&Math.abs(this.green-e.green)<=r&&Math.abs(this.blue-e.blue)<=r&&Math.abs(this.alpha-e.alpha)<=r},s.prototype.toString=function(){return"("+this.red+", "+this.green+", "+this.blue+", "+this.alpha+")"},s.prototype.toCssColorString=function(){var e=s.floatToByte(this.red),t=s.floatToByte(this.green),r=s.floatToByte(this.blue);return 1===this.alpha?"rgb("+e+","+t+","+r+")":"rgba("+e+","+t+","+r+","+this.alpha+")"},s.prototype.toBytes=function(e){var r=s.floatToByte(this.red),i=s.floatToByte(this.green),n=s.floatToByte(this.blue),o=s.floatToByte(this.alpha);return t(e)?(e[0]=r,e[1]=i,e[2]=n,e[3]=o,e):[r,i,n,o]},s.prototype.toRgba=function(){return c[0]=s.floatToByte(this.red),c[1]=s.floatToByte(this.green),c[2]=s.floatToByte(this.blue),c[3]=s.floatToByte(this.alpha),u[0]},s.prototype.brighten=function(e,t){return e=1-e,t.red=1-(1-this.red)*e,t.green=1-(1-this.green)*e,t.blue=1-(1-this.blue)*e,t.alpha=this.alpha,t},s.prototype.darken=function(e,t){return e=1-e,t.red=this.red*e,t.green=this.green*e,t.blue=this.blue*e,t.alpha=this.alpha,t},s.prototype.withAlpha=function(e,t){return s.fromAlpha(this,e,t)},s.ALICEBLUE=n(s.fromCssColorString("#F0F8FF")),s.ANTIQUEWHITE=n(s.fromCssColorString("#FAEBD7")),s.AQUA=n(s.fromCssColorString("#00FFFF")),s.AQUAMARINE=n(s.fromCssColorString("#7FFFD4")),s.AZURE=n(s.fromCssColorString("#F0FFFF")),s.BEIGE=n(s.fromCssColorString("#F5F5DC")),s.BISQUE=n(s.fromCssColorString("#FFE4C4")),s.BLACK=n(s.fromCssColorString("#000000")),s.BLANCHEDALMOND=n(s.fromCssColorString("#FFEBCD")),s.BLUE=n(s.fromCssColorString("#0000FF")),s.BLUEVIOLET=n(s.fromCssColorString("#8A2BE2")),s.BROWN=n(s.fromCssColorString("#A52A2A")),s.BURLYWOOD=n(s.fromCssColorString("#DEB887")),s.CADETBLUE=n(s.fromCssColorString("#5F9EA0")),s.CHARTREUSE=n(s.fromCssColorString("#7FFF00")),s.CHOCOLATE=n(s.fromCssColorString("#D2691E")),s.CORAL=n(s.fromCssColorString("#FF7F50")),s.CORNFLOWERBLUE=n(s.fromCssColorString("#6495ED")),s.CORNSILK=n(s.fromCssColorString("#FFF8DC")),s.CRIMSON=n(s.fromCssColorString("#DC143C")),s.CYAN=n(s.fromCssColorString("#00FFFF")),s.DARKBLUE=n(s.fromCssColorString("#00008B")),s.DARKCYAN=n(s.fromCssColorString("#008B8B")),s.DARKGOLDENROD=n(s.fromCssColorString("#B8860B")),s.DARKGRAY=n(s.fromCssColorString("#A9A9A9")),s.DARKGREEN=n(s.fromCssColorString("#006400")),s.DARKGREY=s.DARKGRAY,s.DARKKHAKI=n(s.fromCssColorString("#BDB76B")),s.DARKMAGENTA=n(s.fromCssColorString("#8B008B")),s.DARKOLIVEGREEN=n(s.fromCssColorString("#556B2F")),s.DARKORANGE=n(s.fromCssColorString("#FF8C00")),s.DARKORCHID=n(s.fromCssColorString("#9932CC")),s.DARKRED=n(s.fromCssColorString("#8B0000")),s.DARKSALMON=n(s.fromCssColorString("#E9967A")),s.DARKSEAGREEN=n(s.fromCssColorString("#8FBC8F")),s.DARKSLATEBLUE=n(s.fromCssColorString("#483D8B")),s.DARKSLATEGRAY=n(s.fromCssColorString("#2F4F4F")),s.DARKSLATEGREY=s.DARKSLATEGRAY,s.DARKTURQUOISE=n(s.fromCssColorString("#00CED1")),s.DARKVIOLET=n(s.fromCssColorString("#9400D3")),s.DEEPPINK=n(s.fromCssColorString("#FF1493")),s.DEEPSKYBLUE=n(s.fromCssColorString("#00BFFF")),s.DIMGRAY=n(s.fromCssColorString("#696969")),s.DIMGREY=s.DIMGRAY,s.DODGERBLUE=n(s.fromCssColorString("#1E90FF")),s.FIREBRICK=n(s.fromCssColorString("#B22222")),s.FLORALWHITE=n(s.fromCssColorString("#FFFAF0")),s.FORESTGREEN=n(s.fromCssColorString("#228B22")),s.FUSCHIA=n(s.fromCssColorString("#FF00FF")),s.GAINSBORO=n(s.fromCssColorString("#DCDCDC")),s.GHOSTWHITE=n(s.fromCssColorString("#F8F8FF")),s.GOLD=n(s.fromCssColorString("#FFD700")),s.GOLDENROD=n(s.fromCssColorString("#DAA520")),s.GRAY=n(s.fromCssColorString("#808080")),s.GREEN=n(s.fromCssColorString("#008000")),s.GREENYELLOW=n(s.fromCssColorString("#ADFF2F")),s.GREY=s.GRAY,s.HONEYDEW=n(s.fromCssColorString("#F0FFF0")),s.HOTPINK=n(s.fromCssColorString("#FF69B4")),s.INDIANRED=n(s.fromCssColorString("#CD5C5C")),s.INDIGO=n(s.fromCssColorString("#4B0082")),s.IVORY=n(s.fromCssColorString("#FFFFF0")),s.KHAKI=n(s.fromCssColorString("#F0E68C")),s.LAVENDER=n(s.fromCssColorString("#E6E6FA")),s.LAVENDAR_BLUSH=n(s.fromCssColorString("#FFF0F5")),s.LAWNGREEN=n(s.fromCssColorString("#7CFC00")),s.LEMONCHIFFON=n(s.fromCssColorString("#FFFACD")),s.LIGHTBLUE=n(s.fromCssColorString("#ADD8E6")),s.LIGHTCORAL=n(s.fromCssColorString("#F08080")),s.LIGHTCYAN=n(s.fromCssColorString("#E0FFFF")),s.LIGHTGOLDENRODYELLOW=n(s.fromCssColorString("#FAFAD2")),s.LIGHTGRAY=n(s.fromCssColorString("#D3D3D3")),s.LIGHTGREEN=n(s.fromCssColorString("#90EE90")),s.LIGHTGREY=s.LIGHTGRAY,s.LIGHTPINK=n(s.fromCssColorString("#FFB6C1")),s.LIGHTSEAGREEN=n(s.fromCssColorString("#20B2AA")),s.LIGHTSKYBLUE=n(s.fromCssColorString("#87CEFA")),s.LIGHTSLATEGRAY=n(s.fromCssColorString("#778899")),s.LIGHTSLATEGREY=s.LIGHTSLATEGRAY,s.LIGHTSTEELBLUE=n(s.fromCssColorString("#B0C4DE")),s.LIGHTYELLOW=n(s.fromCssColorString("#FFFFE0")),s.LIME=n(s.fromCssColorString("#00FF00")),s.LIMEGREEN=n(s.fromCssColorString("#32CD32")),s.LINEN=n(s.fromCssColorString("#FAF0E6")),s.MAGENTA=n(s.fromCssColorString("#FF00FF")),s.MAROON=n(s.fromCssColorString("#800000")),s.MEDIUMAQUAMARINE=n(s.fromCssColorString("#66CDAA")),s.MEDIUMBLUE=n(s.fromCssColorString("#0000CD")),s.MEDIUMORCHID=n(s.fromCssColorString("#BA55D3")),s.MEDIUMPURPLE=n(s.fromCssColorString("#9370DB")),s.MEDIUMSEAGREEN=n(s.fromCssColorString("#3CB371")),s.MEDIUMSLATEBLUE=n(s.fromCssColorString("#7B68EE")),s.MEDIUMSPRINGGREEN=n(s.fromCssColorString("#00FA9A")),s.MEDIUMTURQUOISE=n(s.fromCssColorString("#48D1CC")),s.MEDIUMVIOLETRED=n(s.fromCssColorString("#C71585")),s.MIDNIGHTBLUE=n(s.fromCssColorString("#191970")),s.MINTCREAM=n(s.fromCssColorString("#F5FFFA")),s.MISTYROSE=n(s.fromCssColorString("#FFE4E1")),s.MOCCASIN=n(s.fromCssColorString("#FFE4B5")),s.NAVAJOWHITE=n(s.fromCssColorString("#FFDEAD")),s.NAVY=n(s.fromCssColorString("#000080")),s.OLDLACE=n(s.fromCssColorString("#FDF5E6")),s.OLIVE=n(s.fromCssColorString("#808000")),s.OLIVEDRAB=n(s.fromCssColorString("#6B8E23")),s.ORANGE=n(s.fromCssColorString("#FFA500")),s.ORANGERED=n(s.fromCssColorString("#FF4500")),s.ORCHID=n(s.fromCssColorString("#DA70D6")),s.PALEGOLDENROD=n(s.fromCssColorString("#EEE8AA")),s.PALEGREEN=n(s.fromCssColorString("#98FB98")),s.PALETURQUOISE=n(s.fromCssColorString("#AFEEEE")),s.PALEVIOLETRED=n(s.fromCssColorString("#DB7093")),s.PAPAYAWHIP=n(s.fromCssColorString("#FFEFD5")),s.PEACHPUFF=n(s.fromCssColorString("#FFDAB9")),s.PERU=n(s.fromCssColorString("#CD853F")),s.PINK=n(s.fromCssColorString("#FFC0CB")),s.PLUM=n(s.fromCssColorString("#DDA0DD")),s.POWDERBLUE=n(s.fromCssColorString("#B0E0E6")),s.PURPLE=n(s.fromCssColorString("#800080")),s.RED=n(s.fromCssColorString("#FF0000")),s.ROSYBROWN=n(s.fromCssColorString("#BC8F8F")),s.ROYALBLUE=n(s.fromCssColorString("#4169E1")),s.SADDLEBROWN=n(s.fromCssColorString("#8B4513")),s.SALMON=n(s.fromCssColorString("#FA8072")),s.SANDYBROWN=n(s.fromCssColorString("#F4A460")),s.SEAGREEN=n(s.fromCssColorString("#2E8B57")),s.SEASHELL=n(s.fromCssColorString("#FFF5EE")),s.SIENNA=n(s.fromCssColorString("#A0522D")),s.SILVER=n(s.fromCssColorString("#C0C0C0")),s.SKYBLUE=n(s.fromCssColorString("#87CEEB")),s.SLATEBLUE=n(s.fromCssColorString("#6A5ACD")),s.SLATEGRAY=n(s.fromCssColorString("#708090")),s.SLATEGREY=s.SLATEGRAY,s.SNOW=n(s.fromCssColorString("#FFFAFA")),s.SPRINGGREEN=n(s.fromCssColorString("#00FF7F")),s.STEELBLUE=n(s.fromCssColorString("#4682B4")),s.TAN=n(s.fromCssColorString("#D2B48C")),s.TEAL=n(s.fromCssColorString("#008080")),s.THISTLE=n(s.fromCssColorString("#D8BFD8")),s.TOMATO=n(s.fromCssColorString("#FF6347")),s.TURQUOISE=n(s.fromCssColorString("#40E0D0")),s.VIOLET=n(s.fromCssColorString("#EE82EE")),s.WHEAT=n(s.fromCssColorString("#F5DEB3")),s.WHITE=n(s.fromCssColorString("#FFFFFF")),s.WHITESMOKE=n(s.fromCssColorString("#F5F5F5")),s.YELLOW=n(s.fromCssColorString("#FFFF00")),s.YELLOWGREEN=n(s.fromCssColorString("#9ACD32")),s.TRANSPARENT=n(new s(0,0,0,0)), +s}),r("Core/ColorGeometryInstanceAttribute",["./Color","./ComponentDatatype","./defaultValue","./defined","./defineProperties","./DeveloperError"],function(e,t,r,i,n,o){"use strict";var a=function(t,i,n,o){t=r(t,1),i=r(i,1),n=r(n,1),o=r(o,1),this.value=new Uint8Array([e.floatToByte(t),e.floatToByte(i),e.floatToByte(n),e.floatToByte(o)])};return n(a.prototype,{componentDatatype:{get:function(){return t.UNSIGNED_BYTE}},componentsPerAttribute:{get:function(){return 4}},normalize:{get:function(){return!0}}}),a.fromColor=function(e){return new a(e.red,e.green,e.blue,e.alpha)},a.toValue=function(e,t){return i(t)?e.toBytes(t):new Uint8Array(e.toBytes())},a}),r("Core/CornerType",["./freezeObject"],function(e){"use strict";var t={ROUNDED:0,MITERED:1,BEVELED:2};return e(t)}),r("Core/isArray",["./defined"],function(e){"use strict";var t=Array.isArray;return e(t)||(t=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),t}),r("Core/EllipsoidGeodesic",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Math"],function(e,t,r,i,n,o,a,s){"use strict";function l(e){var t=e._uSquared,r=e._ellipsoid.maximumRadius,i=e._ellipsoid.minimumRadius,n=(r-i)/r,o=Math.cos(e._startHeading),a=Math.sin(e._startHeading),s=(1-n)*Math.tan(e._start.latitude),l=1/Math.sqrt(1+s*s),u=l*s,c=Math.atan2(s,o),h=l*a,d=h*h,p=1-d,m=Math.sqrt(p),f=t/4,v=f*f,_=v*f,g=v*v,y=1+f-3*v/4+5*_/4-175*g/64,C=1-f+15*v/8-35*_/8,E=1-3*f+35*v/4,S=1-5*f,w=y*c-C*Math.sin(2*c)*f/2-E*Math.sin(4*c)*v/16-S*Math.sin(6*c)*_/48-5*Math.sin(8*c)*g/512,T=e._constants;T.a=r,T.b=i,T.f=n,T.cosineHeading=o,T.sineHeading=a,T.tanU=s,T.cosineU=l,T.sineU=u,T.sigma=c,T.sineAlpha=h,T.sineSquaredAlpha=d,T.cosineSquaredAlpha=p,T.cosineAlpha=m,T.u2Over4=f,T.u4Over16=v,T.u6Over64=_,T.u8Over256=g,T.a0=y,T.a1=C,T.a2=E,T.a3=S,T.distanceRatio=w}function u(e,t){return e*t*(4+e*(4-3*t))/16}function c(e,t,r,i,n,o,a){var s=u(e,r);return(1-s)*e*t*(i+s*n*(a+s*o*(2*a*a-1)))}function h(e,t,r,i,n,o,a){var l,u,h,d,p,m=(t-r)/t,f=o-i,v=Math.atan((1-m)*Math.tan(n)),_=Math.atan((1-m)*Math.tan(a)),g=Math.cos(v),y=Math.sin(v),C=Math.cos(_),E=Math.sin(_),S=g*C,w=g*E,T=y*E,b=y*C,x=f,P=s.TWO_PI,A=Math.cos(x),I=Math.sin(x);do{A=Math.cos(x),I=Math.sin(x);var M=w-b*A;h=Math.sqrt(C*C*I*I+M*M),u=T+S*A,l=Math.atan2(h,u);var D;0===h?(D=0,d=1):(D=S*I/h,d=1-D*D),P=x,p=u-2*T/d,isNaN(p)&&(p=0),x=f+c(m,D,d,l,h,u,p)}while(Math.abs(x-P)>s.EPSILON12);var R=d*(t*t-r*r)/(r*r),O=1+R*(4096+R*(R*(320-175*R)-768))/16384,N=R*(256+R*(R*(74-47*R)-128))/1024,L=p*p,F=N*h*(p+N*(u*(2*L-1)-N*p*(4*h*h-3)*(4*L-3)/6)/4),B=r*O*(l-F),V=Math.atan2(C*I,w-b*A),z=Math.atan2(g*I,w*A-b);e._distance=B,e._startHeading=V,e._endHeading=z,e._uSquared=R}function d(r,i,n,o){e.normalize(o.cartographicToCartesian(i,m),p),e.normalize(o.cartographicToCartesian(n,m),m);h(r,o.maximumRadius,o.minimumRadius,i.longitude,i.latitude,n.longitude,n.latitude),r._start=t.clone(i,r._start),r._end=t.clone(n,r._end),r._start.height=0,r._end.height=0,l(r)}var p=new e,m=new e,f=function(e,n,o){var s=r(o,a.WGS84);this._ellipsoid=s,this._start=new t,this._end=new t,this._constants={},this._startHeading=void 0,this._endHeading=void 0,this._distance=void 0,this._uSquared=void 0,i(e)&&i(n)&&d(this,e,n,s)};return n(f.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},surfaceDistance:{get:function(){return this._distance}},start:{get:function(){return this._start}},end:{get:function(){return this._end}},startHeading:{get:function(){return this._startHeading}},endHeading:{get:function(){return this._endHeading}}}),f.prototype.setEndPoints=function(e,t){d(this,e,t,this._ellipsoid)},f.prototype.interpolateUsingFraction=function(e,t){return this.interpolateUsingSurfaceDistance(this._distance*e,t)},f.prototype.interpolateUsingSurfaceDistance=function(e,r){var n=this._constants,o=n.distanceRatio+e/n.b,a=Math.cos(2*o),s=Math.cos(4*o),l=Math.cos(6*o),u=Math.sin(2*o),h=Math.sin(4*o),d=Math.sin(6*o),p=Math.sin(8*o),m=o*o,f=o*m,v=n.u8Over256,_=n.u2Over4,g=n.u6Over64,y=n.u4Over16,C=2*f*v*a/3+o*(1-_+7*y/4-15*g/4+579*v/64-(y-15*g/4+187*v/16)*a-(5*g/4-115*v/16)*s-29*v*l/16)+(_/2-y+71*g/32-85*v/16)*u+(5*y/16-5*g/4+383*v/96)*h-m*((g-11*v/2)*u+5*v*h/2)+(29*g/96-29*v/16)*d+539*v*p/1536,E=Math.asin(Math.sin(C)*n.cosineAlpha),S=Math.atan(n.a/n.b*Math.tan(E));C-=n.sigma;var w=Math.cos(2*n.sigma+C),T=Math.sin(C),b=Math.cos(C),x=n.cosineU*b,P=n.sineU*T,A=Math.atan2(T*n.sineHeading,x-P*n.cosineHeading),I=A-c(n.f,n.sineAlpha,n.cosineSquaredAlpha,C,T,b,w);return i(r)?(r.longitude=this._start.longitude+I,r.latitude=S,r.height=0,r):new t(this._start.longitude+I,S,0)},f}),r("Core/PolylinePipeline",["./Cartesian3","./Cartographic","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidGeodesic","./IntersectionTests","./isArray","./Math","./Matrix4","./Plane"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t,r){var i=T;i.length=e;var n;if(t===r){for(n=0;e>n;n++)i[n]=t;return i}var o=r-t,a=o/e;for(n=0;e>n;n++){var s=t+n*a;i[n]=s}return i}function p(t,r,i,n,o,a,s,l){var u=n.scaleToGeodeticSurface(t,A),c=n.scaleToGeodeticSurface(r,I),h=m.numberOfPoints(t,r,i),p=n.cartesianToCartographic(u,b),f=n.cartesianToCartographic(c,x),v=d(h,o,a);M.setEndPoints(p,f);var _=M.surfaceDistance/h,g=l;p.height=o;var y=n.cartographicToCartesian(p,P);e.pack(y,s,g),g+=3;for(var C=1;h>C;C++){var E=M.interpolateUsingSurfaceDistance(C*_,x);E.height=v[C],y=n.cartographicToCartesian(E,P),e.pack(y,s,g),g+=3}return g}var m={};m.numberOfPoints=function(t,r,i){var n=e.distance(t,r);return Math.ceil(n/i)};var f=new t;m.extractHeights=function(e,t){for(var r=e.length,i=new Array(r),n=0;r>n;n++){var o=e[n];i[n]=t.cartesianToCartographic(o,f).height}return i};var v=new c,_=new e,g=new e,y=new h(e.ZERO,0),C=new e,E=new h(e.ZERO,0),S=new e,w=new e,T=[],b=new t,x=new t,P=new e,A=new e,I=new e,M=new a;m.wrapLongitude=function(t,n){var o=[],a=[];if(i(t)&&t.length>0){n=r(n,c.IDENTITY);var l=c.inverseTransformation(n,v),u=c.multiplyByPoint(l,e.ZERO,_),d=c.multiplyByPointAsVector(l,e.UNIT_Y,g),p=h.fromPointNormal(u,d,y),m=c.multiplyByPointAsVector(l,e.UNIT_X,C),f=h.fromPointNormal(u,m,E),T=1;o.push(e.clone(t[0]));for(var b=o[0],x=t.length,P=1;x>P;++P){var A=t[P];if(h.getPointDistance(f,b)<0||h.getPointDistance(f,A)<0){var I=s.lineSegmentPlane(b,A,p,S);if(i(I)){var M=e.multiplyByScalar(d,5e-9,w);h.getPointDistance(p,b)<0&&e.negate(M,M),o.push(e.add(I,M,new e)),a.push(T+1),e.negate(M,M),o.push(e.add(I,M,new e)),T=1}}o.push(e.clone(t[P])),T++,b=A}a.push(T)}return{positions:o,lengths:a}};var D=u.EPSILON7;return m.removeDuplicates=function(t){var r=t.length;if(2>r)return t;var i,n,o;for(i=1;r>i&&(n=t[i-1],o=t[i],!e.equalsEpsilon(n,o,D));++i);if(i===r)return t;for(var a=t.slice(0,i);r>i;++i)o=t[i],e.equalsEpsilon(n,o,D)||(a.push(e.clone(o)),n=o);return a},m.generateArc=function(t){i(t)||(t={});var n=t.positions,a=n.length,s=r(t.ellipsoid,o.WGS84),c=r(t.height,0);if(1>a)return[];if(1===a){var h=s.scaleToGeodeticSurface(n[0],A);if(0!==c){var d=s.geodeticSurfaceNormal(h,P);e.multiplyByScalar(d,c,d),e.add(h,d,h)}return[h.x,h.y,h.z]}var f=t.minDistance;if(!i(f)){var v=r(t.granularity,u.RADIANS_PER_DEGREE);f=u.chordLength(v,s.maximumRadius)}var _,g=0;for(_=0;a-1>_;_++)g+=m.numberOfPoints(n[_],n[_+1],f);var y=3*(g+1),C=new Array(y),E=0,S=l(c);for(_=0;a-1>_;_++){var w=n[_],x=n[_+1],I=S?c[_]:c,M=S?c[_+1]:c;E=p(w,x,f,s,I,M,C,E)}T.length=0;var D=n[a-1],R=s.cartesianToCartographic(D,b);R.height=S?c[a-1]:c;var O=s.cartographicToCartesian(R,P);return e.pack(O,C,y-3),C},m.generateCartesianArc=function(t){for(var r=m.generateArc(t),i=r.length/3,n=new Array(i),o=0;i>o;o++)n[o]=e.unpack(r,3*o);return n},m}),r("Core/PolylineVolumeGeometryLibrary",["./Cartesian2","./Cartesian3","./Cartesian4","./Cartographic","./CornerType","./EllipsoidTangentPlane","./Math","./Matrix3","./Matrix4","./PolylinePipeline","./Quaternion","./Transforms"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t){for(var r=new Array(e.length),i=0;io;o++)c[o]=r;return c.push(i),c}var h=i-r,d=h/u;for(o=1;u>o;o++){var p=r+o*d;c[o]=p}return c[0]=r,c.push(i),c}function m(r,i,n,a){var s=new o(n,a),l=s.projectPointOntoPlane(t.add(n,r,Y),Y),u=s.projectPointOntoPlane(t.add(n,i,X),X),c=e.angleBetween(l,u);return u.x*l.y-u.y*l.x>=0?-c:c}function f(e,r,i,n,o,a,u,c){var d=k,p=U;F=h.eastNorthUpToFixedFrame(e,o,F),d=l.multiplyByPointAsVector(F,L,d),d=t.normalize(d,d);var f=m(d,r,e,o);V=s.fromRotationZ(f,V),G.z=a,F=l.multiplyTransformation(F,l.fromRotationTranslation(V,G,B),F);var v=z;v[0]=u;for(var _=0;c>_;_++)for(var g=0;gl;l++){s=e[l];var u=s.x-o,c=s.y-a;i[n++]=u,i[n++]=0,i[n++]=c,i[n++]=u,i[n++]=0,i[n++]=c}return s=e[0],i[n++]=s.x-o,i[n++]=0,i[n++]=s.y-a,i}function g(e,t){for(var r=e.length,i=new Array(3*r),n=0,o=t.x+t.width/2,a=t.y+t.height/2,s=0;r>s;s++)i[n++]=e[s].x-o,i[n++]=0,i[n++]=e[s].y-a;return i}function y(e,r,i,o,l,u,h,d,p,m){var v,_=t.angleBetween(t.subtract(r,e,D),t.subtract(i,e,R)),g=o===n.BEVELED?0:Math.ceil(_/a.toRadians(5));v=l?s.fromQuaternion(c.fromAxisAngle(t.negate(e,D),_/(g+1),H),j):s.fromQuaternion(c.fromAxisAngle(e,_/(g+1),H),j);var y,C;if(r=t.clone(r,q),g>0)for(var E=m?2:1,S=0;g>S;S++)r=s.multiplyByVector(v,r,r),y=t.subtract(r,e,D),y=t.normalize(y,y),l||(y=t.negate(y,y)),C=u.scaleToGeodeticSurface(r,R),h=f(C,y,d,h,u,p,1,E);else y=t.subtract(r,e,D),y=t.normalize(y,y),l||(y=t.negate(y,y)),C=u.scaleToGeodeticSurface(r,R),h=f(C,y,d,h,u,p,1,1),i=t.clone(i,q),y=t.subtract(i,e,D),y=t.normalize(y,y),l||(y=t.negate(y,y)),C=u.scaleToGeodeticSurface(i,R),h=f(C,y,d,h,u,p,1,1);return h}function C(e,t){return a.equalsEpsilon(e.latitude,t.latitude,a.EPSILON6)&&a.equalsEpsilon(e.longitude,t.longitude,a.EPSILON6)}var E=[new t,new t],S=new t,w=new t,T=new t,b=new t,x=new t,P=new t,A=new t,I=new t,M=new t,D=new t,R=new t,O={},N=new i,L=new t(-1,0,0),F=new l,B=new l,V=new s,z=s.IDENTITY.clone(),k=new t,U=new r,G=new t,W=new t,H=new c,q=new t,j=new s;O.removeDuplicatesFromShape=function(t){for(var r=t.length,i=[],n=r-1,o=0;r>o;n=o++){var a=t[n],s=t[o];e.equals(a,s)||i.push(s)}return i};var Y=new t,X=new t;O.angleIsGreaterThanPi=function(e,r,i,n){var a=new o(i,n),s=a.projectPointOntoPlane(t.add(i,e,Y),Y),l=a.projectPointOntoPlane(t.add(i,r,X),X);return l.x*s.y-l.y*s.x>=0};var Z=new i,K=new i;O.removeDuplicatesFromPositions=function(e,t){var r=e.length;if(2>r)return e.slice(0);var i=[];i.push(e[0]);for(var n=1;r>n;++n){var o=e[n-1],a=e[n],s=t.cartesianToCartographic(o,Z),l=t.cartesianToCartographic(a,K);C(s,l)||i.push(a)}return i};var J=new t,Q=new t;return O.computePositions=function(e,r,i,o,s){var l=o._ellipsoid,c=d(e,l),h=o._granularity,m=o._cornerType,C=s?_(r,i):g(r,i),R=s?g(r,i):void 0,N=i.height/2,L=i.width/2,F=e.length,B=[],V=s?[]:void 0,z=S,k=w,U=T,G=b,W=x,H=P,q=A,j=I,Y=M,X=e[0],Z=e[1];G=l.geodeticSurfaceNormal(X,G),z=t.subtract(Z,X,z),z=t.normalize(z,z),j=t.cross(G,z,j),j=t.normalize(j,j);var K=c[0],$=c[1];s&&(V=f(X,j,R,V,l,K+N,1,1)),Y=t.clone(X,Y),X=Z,k=t.negate(z,k);for(var ee,te,re=1;F-1>re;re++){var ie=s?2:1;Z=e[re+1],z=t.subtract(Z,X,z),z=t.normalize(z,z),U=t.add(z,k,U),U=t.normalize(U,U),G=l.geodeticSurfaceNormal(X,G);var ne=t.multiplyByScalar(G,t.dot(z,G),J);t.subtract(z,ne,ne),t.normalize(ne,ne);var oe=t.multiplyByScalar(G,t.dot(k,G),Q);t.subtract(k,oe,oe),t.normalize(oe,oe);var ae=!a.equalsEpsilon(Math.abs(t.dot(ne,oe)),1,a.EPSILON7);if(ae){U=t.cross(U,G,U),U=t.cross(G,U,U),U=t.normalize(U,U);var se=1/Math.max(.25,t.magnitude(t.cross(U,k,D))),le=O.angleIsGreaterThanPi(z,k,X,l);le?(W=t.add(X,t.multiplyByScalar(U,se*L,U),W),H=t.add(W,t.multiplyByScalar(j,L,H),H),E[0]=t.clone(Y,E[0]),E[1]=t.clone(H,E[1]),ee=p(E,K+N,$+N,h),te=u.generateArc({positions:E,granularity:h,ellipsoid:l}),B=v(te,j,C,B,l,ee,1),j=t.cross(G,z,j),j=t.normalize(j,j),q=t.add(W,t.multiplyByScalar(j,L,q),q),m===n.ROUNDED||m===n.BEVELED?y(W,H,q,m,le,l,B,C,$+N,s):(U=t.negate(U,U),B=f(X,U,C,B,l,$+N,se,ie)),Y=t.clone(q,Y)):(W=t.add(X,t.multiplyByScalar(U,se*L,U),W),H=t.add(W,t.multiplyByScalar(j,-L,H),H),E[0]=t.clone(Y,E[0]),E[1]=t.clone(H,E[1]),ee=p(E,K+N,$+N,h),te=u.generateArc({positions:E,granularity:h,ellipsoid:l}),B=v(te,j,C,B,l,ee,1),j=t.cross(G,z,j),j=t.normalize(j,j),q=t.add(W,t.multiplyByScalar(j,-L,q),q),m===n.ROUNDED||m===n.BEVELED?y(W,H,q,m,le,l,B,C,$+N,s):B=f(X,U,C,B,l,$+N,se,ie),Y=t.clone(q,Y)),k=t.negate(z,k)}else B=f(Y,j,C,B,l,K+N,1,1),Y=X;K=$,$=c[re+1],X=Z}E[0]=t.clone(Y,E[0]),E[1]=t.clone(X,E[1]),ee=p(E,K+N,$+N,h),te=u.generateArc({positions:E,granularity:h,ellipsoid:l}),B=v(te,j,C,B,l,ee,1),s&&(V=f(X,j,R,V,l,$+N,1,1)),F=B.length;var ue=s?F+V.length:F,ce=new Float64Array(ue);return ce.set(B),s&&ce.set(V,F),ce},O}),r("Core/CorridorGeometryLibrary",["./Cartesian3","./CornerType","./defined","./isArray","./Math","./Matrix3","./PolylinePipeline","./PolylineVolumeGeometryLibrary","./Quaternion"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(r,i,a,s,u){var c=e.angleBetween(e.subtract(i,r,f),e.subtract(a,r,v)),h=s===t.BEVELED?1:Math.ceil(c/n.toRadians(5))+1,d=3*h,p=new Array(d);p[d-3]=a.x,p[d-2]=a.y,p[d-1]=a.z;var m;m=u?o.fromQuaternion(l.fromAxisAngle(e.negate(r,f),c/h,M),D):o.fromQuaternion(l.fromAxisAngle(r,c/h,M),D);var _=0;i=e.clone(i,f);for(var g=0;h>g;g++)i=o.multiplyByVector(m,i,i),p[_++]=i.x,p[_++]=i.y,p[_++]=i.z;return p}function c(r){var i=C,n=E,o=S,a=r[1];n=e.fromArray(r[1],a.length-3,n),o=e.fromArray(r[0],0,o),i=e.multiplyByScalar(e.add(n,o,i),.5,i);var s=u(i,n,o,t.ROUNDED,!1),l=r.length-1,c=r[l-1];a=r[l],n=e.fromArray(c,c.length-3,n),o=e.fromArray(a,0,o),i=e.multiplyByScalar(e.add(n,o,i),.5,i);var h=u(i,n,o,t.ROUNDED,!1);return[s,h]}function h(t,r,i,n){var o=f;return n?o=e.add(t,r,o):(r=e.negate(r,r),o=e.add(t,r,o)),[o.x,o.y,o.z,i.x,i.y,i.z]}function d(t,r,i,n){for(var o=new Array(t.length),a=new Array(t.length),s=e.multiplyByScalar(r,i,f),l=e.negate(s,v),u=0,c=t.length-1,h=0;hY;Y++){g=l.geodeticSurfaceNormal(H,g),q=o[Y+1],M=e.normalize(e.subtract(q,H,M),M),L=e.normalize(e.add(M,D,L),L);var K=e.multiplyByScalar(g,e.dot(M,g),R);e.subtract(M,K,K),e.normalize(K,K);var J=e.multiplyByScalar(g,e.dot(D,g),O);e.subtract(D,J,J),e.normalize(J,J);var Q=!n.equalsEpsilon(Math.abs(e.dot(K,J)),1,n.EPSILON7);if(Q){L=e.cross(L,g,L),L=e.cross(g,L,L);var $=m/Math.max(.25,e.magnitude(e.cross(L,D,f))),ee=s.angleIsGreaterThanPi(M,D,H,l);L=e.multiplyByScalar(L,$,L),ee?(V=e.add(H,L,V),k=e.add(V,e.multiplyByScalar(N,m,k),k),z=e.add(V,e.multiplyByScalar(N,2*m,z),z),y[0]=e.clone(B,y[0]),y[1]=e.clone(k,y[1]),j=a.generateArc({positions:y,granularity:i,ellipsoid:l}),U=d(j,N,m,U),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z)),F=e.clone(z,F),N=e.normalize(e.cross(g,M,N),N),z=e.add(V,e.multiplyByScalar(N,2*m,z),z),B=e.add(V,e.multiplyByScalar(N,m,B),B),v===t.ROUNDED||v===t.BEVELED?X.push({leftPositions:u(V,F,z,v,ee)}):X.push({leftPositions:h(H,e.negate(L,L),z,ee)})):(z=e.add(H,L,z),k=e.add(z,e.negate(e.multiplyByScalar(N,m,k),k),k),V=e.add(z,e.negate(e.multiplyByScalar(N,2*m,V),V),V),y[0]=e.clone(B,y[0]),y[1]=e.clone(k,y[1]),j=a.generateArc({positions:y,granularity:i,ellipsoid:l}),U=d(j,N,m,U),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z)),F=e.clone(V,F),N=e.normalize(e.cross(g,M,N),N),V=e.add(z,e.negate(e.multiplyByScalar(N,2*m,V),V),V),B=e.add(z,e.negate(e.multiplyByScalar(N,m,B),B),B),v===t.ROUNDED||v===t.BEVELED?X.push({rightPositions:u(z,F,V,v,ee)}):X.push({rightPositions:h(H,L,V,ee)})),D=e.negate(M,D)}H=q}g=l.geodeticSurfaceNormal(H,g),y[0]=e.clone(B,y[0]),y[1]=e.clone(H,y[1]),j=a.generateArc({positions:y,granularity:i,ellipsoid:l}),U=d(j,N,m,U),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z));var te;return v===t.ROUNDED&&(te=c(U)),{positions:U,corners:X,lefts:G,normals:W,endPositions:te}};var N=new e,L=new e;return m.scaleToGeodeticHeight=function(t,r,n,o){var a=t.length,s=i(o)?o:new Array(t.length);s.length=t.length;for(var l=r,u=0;a>u;u+=3){var c=n.scaleToGeodeticSurface(e.fromArray(t,u,L),L),h=N;0!==r&&(h=n.geodeticSurfaceNormal(c,h),h=e.multiplyByScalar(h,l,h),c=e.add(c,h,c)),s[u]=c.x,s[u+1]=c.y,s[u+2]=c.z}return s},m}),r("Core/CorridorGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./CornerType","./CorridorGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e,r,i,o,a,s){var l=e.normals,u=e.tangents,c=e.binormals,h=t.normalize(t.cross(i,r,A),A);s.normal&&n.addAttribute(l,r,o,a),s.binormal&&n.addAttribute(c,i,o,a),s.tangent&&n.addAttribute(u,h,o,a)}function g(e,i,o){var s,l,u,m=e.positions,f=e.corners,v=e.endPositions,g=e.lefts,y=e.normals,C=new h,E=0,x=0,M=0;for(l=0;ll;l++)z=t.fromArray($,3*(K-1-l),z),V=t.fromArray($,3*(K+l),V),n.addAttribute(U,V,j),n.addAttribute(U,z,void 0,Y),_(q,X,Z,j,Y,i),L=j/3,B=L+1,N=(Y-2)/3,F=N-1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3}var ee=0,te=0,re=m[ee++],ie=m[ee++];U.set(re,j),U.set(ie,Y-ie.length+1),Z=t.fromArray(g,te,Z);var ne,oe;for(u=ie.length-3,l=0;u>l;l+=3)ne=o.geodeticSurfaceNormal(t.fromArray(re,l,A),A),oe=o.geodeticSurfaceNormal(t.fromArray(ie,u-l,I),I),X=t.normalize(t.add(ne,oe,X),X),_(q,X,Z,j,Y,i),L=j/3,B=L+1,N=(Y-2)/3,F=N-1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3;for(ne=o.geodeticSurfaceNormal(t.fromArray(re,u,A),A),oe=o.geodeticSurfaceNormal(t.fromArray(ie,u,I),I),X=t.normalize(t.add(ne,oe,X),X),te+=3,l=0;ll;l++)z=t.fromArray(me,3*(R-l-1),z),V=t.fromArray(me,3*l,V),n.addAttribute(U,z,void 0,Y),n.addAttribute(U,V,j),_(q,X,Z,j,Y,i),B=j/3,L=B-1,F=(Y-2)/3,N=F+1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3}if(C.position=new c({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:U}),i.st){var fe,ve,_e=new Float32Array(k/3*2),ge=0;if(O){E/=3,x/=3;var ye=Math.PI/(R+1);ve=1/(E-R+1),fe=1/(x-R+1);var Ce,Ee=R/2;for(l=Ee+1;R+1>l;l++)Ce=p.PI_OVER_TWO+ye*l,_e[ge++]=fe*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce));for(l=1;x-R+1>l;l++)_e[ge++]=l*fe,_e[ge++]=0;for(l=R;l>Ee;l--)Ce=p.PI_OVER_TWO-l*ye,_e[ge++]=1-fe*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce));for(l=Ee;l>0;l--)Ce=p.PI_OVER_TWO-ye*l,_e[ge++]=1-ve*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce));for(l=E-R;l>0;l--)_e[ge++]=l*ve,_e[ge++]=1;for(l=1;Ee+1>l;l++)Ce=p.PI_OVER_TWO+ye*l,_e[ge++]=ve*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce))}else{for(E/=3,x/=3,ve=1/(E-1),fe=1/(x-1),l=0;x>l;l++)_e[ge++]=l*fe,_e[ge++]=0;for(l=E;l>0;l--)_e[ge++]=(l-1)*ve,_e[ge++]=1}C.st=new c({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:_e})}return i.normal&&(C.normal=new c({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:q.normals})),i.tangent&&(C.tangent=new c({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:q.tangents})),i.binormal&&(C.binormal=new c({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:q.binormals})),{attributes:C,indices:J}}function y(e,r){if(!(r.normal||r.binormal||r.tangent||r.st))return e;var i,o,a=e.position.values;(r.normal||r.binormal)&&(i=e.normal.values,o=e.binormal.values);var s,l=e.position.values.length/18,u=3*l,c=2*l,h=2*u;if(r.normal||r.binormal||r.tangent){var d=r.normal?new Float32Array(6*u):void 0,p=r.binormal?new Float32Array(6*u):void 0,m=r.tangent?new Float32Array(6*u):void 0,f=S,v=w,_=T,g=b,y=x,C=P,E=h;for(s=0;u>s;s+=3){var A=E+h;f=t.fromArray(a,s,f),v=t.fromArray(a,s+u,v),_=t.fromArray(a,(s+3)%u,_),v=t.subtract(v,f,v),_=t.subtract(_,f,_),g=t.normalize(t.cross(v,_,g),g),r.normal&&(n.addAttribute(d,g,A),n.addAttribute(d,g,A+3),n.addAttribute(d,g,E),n.addAttribute(d,g,E+3)),(r.tangent||r.binormal)&&(C=t.fromArray(i,s,C),r.binormal&&(n.addAttribute(p,C,A),n.addAttribute(p,C,A+3),n.addAttribute(p,C,E),n.addAttribute(p,C,E+3)),r.tangent&&(y=t.normalize(t.cross(C,g,y),y),n.addAttribute(m,y,A),n.addAttribute(m,y,A+3),n.addAttribute(m,y,E),n.addAttribute(m,y,E+3))),E+=6}if(r.normal){for(d.set(i),s=0;u>s;s+=3)d[s+u]=-i[s],d[s+u+1]=-i[s+1],d[s+u+2]=-i[s+2];e.normal.values=d}else e.normal=void 0;if(r.binormal?(p.set(o),p.set(o,u),e.binormal.values=p):e.binormal=void 0,r.tangent){var I=e.tangent.values;m.set(I),m.set(I,u),e.tangent.values=m}}if(r.st){var M=e.st.values,D=new Float32Array(6*c);D.set(M),D.set(M,c);for(var R=2*c,O=0;2>O;O++){for(D[R++]=M[0],D[R++]=M[1],s=2;c>s;s+=2){var N=M[s],L=M[s+1];D[R++]=N,D[R++]=L,D[R++]=N,D[R++]=L}D[R++]=M[0],D[R++]=M[1]}e.st.values=D}return e}function C(e,t,r){r[t++]=e[0],r[t++]=e[1],r[t++]=e[2];for(var i=3;iE;E+=3){var x=c[E],P=c[E+1],A=c[E+2];T[b++]=A+p,T[b++]=P+p,T[b++]=x+p}u=y(u,t);var I,M,D,R;for(E=0;w>E;E+=2)I=E+w,M=I+w,D=I+1,R=M+1,T[b++]=I,T[b++]=M,T[b++]=D,T[b++]=D,T[b++]=M,T[b++]=R;return{attributes:u,indices:T}}var S=new t,w=new t,T=new t,b=new t,x=new t,P=new t,A=new t,I=new t,M=function(e){e=o(e,o.EMPTY_OBJECT);var r=e.positions,n=e.width;this._positions=r,this._ellipsoid=l.clone(o(e.ellipsoid,l.WGS84)),this._vertexFormat=v.clone(o(e.vertexFormat,v.DEFAULT)),this._width=n,this._height=o(e.height,0),this._extrudedHeight=o(e.extrudedHeight,this._height),this._cornerType=o(e.cornerType,i.ROUNDED),this._granularity=o(e.granularity,p.RADIANS_PER_DEGREE),this._workerName="createCorridorGeometry",this.packedLength=1+r.length*t.packedLength+l.packedLength+v.packedLength+5};M.pack=function(e,r,i){i=o(i,0);var n=e._positions,a=n.length;r[i++]=a;for(var s=0;a>s;++s,i+=t.packedLength)t.pack(n[s],r,i);l.pack(e._ellipsoid,r,i),i+=l.packedLength,v.pack(e._vertexFormat,r,i),i+=v.packedLength,r[i++]=e._width,r[i++]=e._height,r[i++]=e._extrudedHeight,r[i++]=e._cornerType,r[i]=e._granularity};var D=l.clone(l.UNIT_SPHERE),R=new v,O={positions:void 0,ellipsoid:D,vertexFormat:R,width:void 0,height:void 0,extrudedHeight:void 0,cornerType:void 0,granularity:void 0};return M.unpack=function(e,r,i){r=o(r,0);for(var n=e[r++],s=new Array(n),u=0;n>u;++u,r+=t.packedLength)s[u]=t.unpack(e,r);var c=l.unpack(e,r,D);r+=l.packedLength;var h=v.unpack(e,r,R);r+=v.packedLength;var d=e[r++],p=e[r++],m=e[r++],f=e[r++],_=e[r];return a(i)?(i._positions=s,i._ellipsoid=l.clone(c,i._ellipsoid),i._vertexFormat=v.clone(h,i._vertexFormat),i._width=d,i._height=p,i._extrudedHeight=m,i._cornerType=f,i._granularity=_,i):(O.positions=s,O.width=d,O.height=p,O.extrudedHeight=m,O.cornerType=f,O.granularity=_,new M(O))},M.createGeometry=function(t){var r=t._positions,i=t._height,o=t._extrudedHeight,a=i!==o,s=m.removeDuplicates(r);if(s.length<2)return void 0;var l,c=t._ellipsoid,h=t._vertexFormat,d={ellipsoid:c,positions:s,width:t._width,cornerType:t._cornerType,granularity:t._granularity,saveAttributes:!0};if(a){var p=Math.max(i,o);o=Math.min(i,o),i=p,d.height=i,d.extrudedHeight=o,l=E(d,h)}else{var v=n.computePositions(d);l=g(v,h,c),l.attributes.position.values=n.scaleToGeodeticHeight(l.attributes.position.values,i,c,l.attributes.position.values)}var _=l.attributes,y=e.fromVertices(_.position.values,void 0,3);return h.position||(l.attributes.position.values=void 0),new u({attributes:_,indices:l.indices,primitiveType:f.TRIANGLES,boundingSphere:y})},M.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new M({positions:e._positions,width:e._width,cornerType:e._cornerType,ellipsoid:n,granularity:i,extrudedHeight:o,height:a,vertexFormat:v.POSITION_ONLY})},M}),r("Core/CorridorOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./CornerType","./CorridorGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(e,o){var s,l,u,p=[],m=e.positions,f=e.corners,v=e.endPositions,_=new h,E=0,S=0,w=0;for(l=0;ll;l++)R=t.fromArray(k,3*(B-1-l),R),D=t.fromArray(k,3*(B+l),D),n.addAttribute(N,D,L),n.addAttribute(N,R,void 0,F),A=L/3,M=A+1,P=(F-2)/3,I=P-1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3}var U=0,G=m[U++],W=m[U++];for(N.set(G,L),N.set(W,F-W.length+1),u=W.length-3,p.push(L/3,(F-2)/3),l=0;u>l;l+=3)A=L/3,M=A+1,P=(F-2)/3,I=P-1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3;for(l=0;ll;l++)R=t.fromArray(Z,3*(b-l-1),R),D=t.fromArray(Z,3*l,D),n.addAttribute(N,R,void 0,F),n.addAttribute(N,D,L),M=L/3,A=M-1,I=(F-2)/3,P=I+1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3;p.push(L/3)}else p.push(L/3,(F-2)/3);return V[z++]=L/3,V[z++]=(F-2)/3,_.position=new c({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:N}),{attributes:_,indices:V,wallIndices:p}}function _(e){var t=e.ellipsoid,r=n.computePositions(e),i=v(r,e.cornerType),o=i.wallIndices,a=e.height,s=e.extrudedHeight,l=i.attributes,u=i.indices,c=l.position.values,h=c.length,p=new Float64Array(h);p.set(c);var m=new Float64Array(2*h);c=n.scaleToGeodeticHeight(c,a,t,c),p=n.scaleToGeodeticHeight(p,s,t,p),m.set(c),m.set(p,h),l.position.values=m,h/=3;var f,_=u.length,g=d.createTypedArray(m.length/3,2*(_+o.length));g.set(u);var y=_;for(f=0;_>f;f+=2){var C=u[f],E=u[f+1];g[y++]=C+h,g[y++]=E+h}var S,w;for(f=0;fs;++s,i+=t.packedLength)t.pack(n[s],r,i);l.pack(e._ellipsoid,r,i),i+=l.packedLength,r[i++]=e._width,r[i++]=e._height,r[i++]=e._extrudedHeight,r[i++]=e._cornerType,r[i]=e._granularity};var S=l.clone(l.UNIT_SPHERE),w={positions:void 0,ellipsoid:S,width:void 0,height:void 0,extrudedHeight:void 0,cornerType:void 0,granularity:void 0};return E.unpack=function(e,r,i){r=o(r,0);for(var n=e[r++],s=new Array(n),u=0;n>u;++u,r+=t.packedLength)s[u]=t.unpack(e,r);var c=l.unpack(e,r,S);r+=l.packedLength;var h=e[r++],d=e[r++],p=e[r++],m=e[r++],f=e[r];return a(i)?(i._positions=s,i._ellipsoid=l.clone(c,i._ellipsoid),i._width=h,i._height=d,i._extrudedHeight=p,i._cornerType=m,i._granularity=f,i):(w.positions=s, +w.width=h,w.height=d,w.extrudedHeight=p,w.cornerType=m,w.granularity=f,new E(w))},E.createGeometry=function(t){var r=t._positions,i=t._height,o=t._extrudedHeight,a=i!==o,s=m.removeDuplicates(r);if(s.length<2)return void 0;var l,c=t._ellipsoid,h={ellipsoid:c,positions:s,width:t._width,cornerType:t._cornerType,granularity:t._granularity,saveAttributes:!1};if(a){var d=Math.max(i,o);o=Math.min(i,o),i=d,h.height=i,h.extrudedHeight=o,l=_(h)}else{var p=n.computePositions(h);l=v(p,h.cornerType),l.attributes.position.values=n.scaleToGeodeticHeight(l.attributes.position.values,i,c,l.attributes.position.values)}var g=l.attributes,y=e.fromVertices(g.position.values,void 0,3);return new u({attributes:g,indices:l.indices,primitiveType:f.LINES,boundingSphere:y})},E}),r("Core/CylinderGeometryLibrary",["./Math"],function(e){"use strict";var t={};return t.computePositions=function(t,r,i,n,o){var a,s=.5*t,l=-s,u=n+n,c=o?2*u:u,h=new Float64Array(3*c),d=0,p=0,m=o?3*u:0,f=o?3*(u+n):3*n;for(a=0;n>a;a++){var v=a/n*e.TWO_PI,_=Math.cos(v),g=Math.sin(v),y=_*i,C=g*i,E=_*r,S=g*r;h[p+m]=y,h[p+m+1]=C,h[p+m+2]=l,h[p+f]=E,h[p+f+1]=S,h[p+f+2]=s,p+=3,o&&(h[d++]=y,h[d++]=C,h[d++]=l,h[d++]=E,h[d++]=S,h[d++]=s)}return h},t}),r("Core/CylinderGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CylinderGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new t,v=new r,_=new r,g=new r,y=new r,C=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.length,r=e.topRadius,i=e.bottomRadius,n=o(e.vertexFormat,m.DEFAULT),a=o(e.slices,128);this._length=t,this._topRadius=r,this._bottomRadius=i,this._vertexFormat=m.clone(n),this._slices=a,this._workerName="createCylinderGeometry"};C.packedLength=m.packedLength+4,C.pack=function(e,t,r){r=o(r,0),m.pack(e._vertexFormat,t,r),r+=m.packedLength,t[r++]=e._length,t[r++]=e._topRadius,t[r++]=e._bottomRadius,t[r]=e._slices};var E=new m,S={vertexFormat:E,length:void 0,topRadius:void 0,bottomRadius:void 0,slices:void 0};return C.unpack=function(e,t,r){t=o(t,0);var i=m.unpack(e,t,E);t+=m.packedLength;var n=e[t++],s=e[t++],l=e[t++],u=e[t];return a(r)?(r._vertexFormat=m.clone(i,r._vertexFormat),r._length=n,r._topRadius=s,r._bottomRadius=l,r._slices=u,r):(S.length=n,S.topRadius=s,S.bottomRadius=l,S.slices=u,new C(S))},C.createGeometry=function(o){var a,s=o._length,m=o._topRadius,C=o._bottomRadius,E=o._vertexFormat,S=o._slices,w=S+S,T=S+w,b=w+w,x=n.computePositions(s,m,C,S,!0),P=E.st?new Float32Array(2*b):void 0,A=E.normal?new Float32Array(3*b):void 0,I=E.tangent?new Float32Array(3*b):void 0,M=E.binormal?new Float32Array(3*b):void 0,D=E.normal||E.tangent||E.binormal;if(D){var R=E.tangent||E.binormal,O=0,N=0,L=0,F=v;F.z=0;var B=g,V=_;for(a=0;S>a;a++){var z=a/S*d.TWO_PI,k=Math.cos(z),U=Math.sin(z);D&&(F.x=k,F.y=U,R&&(B=r.normalize(r.cross(r.UNIT_Z,F,B),B)),E.normal&&(A[O++]=k,A[O++]=U,A[O++]=0,A[O++]=k,A[O++]=U,A[O++]=0),E.tangent&&(I[N++]=B.x,I[N++]=B.y,I[N++]=B.z,I[N++]=B.x,I[N++]=B.y,I[N++]=B.z),E.binormal&&(V=r.normalize(r.cross(F,B,V),V),M[L++]=V.x,M[L++]=V.y,M[L++]=V.z,M[L++]=V.x,M[L++]=V.y,M[L++]=V.z))}for(a=0;S>a;a++)E.normal&&(A[O++]=0,A[O++]=0,A[O++]=-1),E.tangent&&(I[N++]=1,I[N++]=0,I[N++]=0),E.binormal&&(M[L++]=0,M[L++]=-1,M[L++]=0);for(a=0;S>a;a++)E.normal&&(A[O++]=0,A[O++]=0,A[O++]=1),E.tangent&&(I[N++]=1,I[N++]=0,I[N++]=0),E.binormal&&(M[L++]=0,M[L++]=1,M[L++]=0)}var G=12*S-12,W=h.createTypedArray(b,G),H=0,q=0;for(a=0;S-1>a;a++)W[H++]=q,W[H++]=q+2,W[H++]=q+3,W[H++]=q,W[H++]=q+3,W[H++]=q+1,q+=2;for(W[H++]=w-2,W[H++]=0,W[H++]=1,W[H++]=w-2,W[H++]=1,W[H++]=w-1,a=1;S-1>a;a++)W[H++]=w+a+1,W[H++]=w+a,W[H++]=w;for(a=1;S-1>a;a++)W[H++]=T,W[H++]=T+a,W[H++]=T+a+1;var j=0;if(E.st){var Y=Math.max(m,C);for(a=0;b>a;a++){var X=r.fromArray(x,3*a,y);P[j++]=(X.x+Y)/(2*Y),P[j++]=(X.y+Y)/(2*Y)}}var Z=new c;E.position&&(Z.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:x})),E.normal&&(Z.normal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:A})),E.tangent&&(Z.tangent=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:I})),E.binormal&&(Z.binormal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:M})),E.st&&(Z.st=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:P})),f.x=.5*s,f.y=Math.max(C,m);var K=new e(r.ZERO,t.magnitude(f));return new l({attributes:Z,indices:W,primitiveType:p.TRIANGLES,boundingSphere:K})},C}),r("Core/CylinderOutlineGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CylinderGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";var p=new t,m=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.length,r=e.topRadius,i=e.bottomRadius,n=o(e.slices,128),a=Math.max(o(e.numberOfVerticalLines,16),0);this._length=t,this._topRadius=r,this._bottomRadius=i,this._slices=n,this._numberOfVerticalLines=a,this._workerName="createCylinderOutlineGeometry"};m.packedLength=5,m.pack=function(e,t,r){r=o(r,0),t[r++]=e._length,t[r++]=e._topRadius,t[r++]=e._bottomRadius,t[r++]=e._slices,t[r]=e._numberOfVerticalLines};var f={length:void 0,topRadius:void 0,bottomRadius:void 0,slices:void 0,numberOfVerticalLines:void 0};return m.unpack=function(e,t,r){t=o(t,0);var i=e[t++],n=e[t++],s=e[t++],l=e[t++],u=e[t];return a(r)?(r._length=i,r._topRadius=n,r._bottomRadius=s,r._slices=l,r._numberOfVerticalLines=u,r):(f.length=i,f.topRadius=n,f.bottomRadius=s,f.slices=l,f.numberOfVerticalLines=u,new m(f))},m.createGeometry=function(o){var a,s=o._length,m=o._topRadius,f=o._bottomRadius,v=o._slices,_=o._numberOfVerticalLines,g=2*v,y=n.computePositions(s,m,f,v,!1),C=2*v;if(_>0){var E=Math.min(_,v);a=Math.round(v/E),C+=E}for(var S=h.createTypedArray(g,2*C),w=0,T=0;v-1>T;T++)S[w++]=T,S[w++]=T+1,S[w++]=T+v,S[w++]=T+1+v;if(S[w++]=v-1,S[w++]=0,S[w++]=v+v-1,S[w++]=v,_>0)for(T=0;v>T;T+=a)S[w++]=T,S[w++]=T+v;var b=new c;b.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:y}),p.x=.5*s,p.y=Math.max(f,m);var x=new e(r.ZERO,t.magnitude(p));return new l({attributes:b,indices:S,primitiveType:d.LINES,boundingSphere:x})},m}),r("Core/DefaultProxy",[],function(){"use strict";var e=function(e){this.proxy=e};return e.prototype.getURL=function(e){return this.proxy+"?"+encodeURIComponent(e)},e}),r("ThirdParty/Tween",[],function(){void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var e=e||function(){var e=[];return{REVISION:"13",getAll:function(){return e},removeAll:function(){e=[]},add:function(t){e.push(t)},remove:function(t){var r=e.indexOf(t);-1!==r&&e.splice(r,1)},update:function(t){if(0===e.length)return!1;var r=0;for(t=void 0!==t?t:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();re;e++)f[e].stop()},this.delay=function(e){return h=e,this},this.repeat=function(e){return s=e,this},this.yoyo=function(e){return l=e,this},this.easing=function(e){return p=e,this},this.interpolation=function(e){return m=e,this},this.chain=function(){return f=arguments,this},this.onStart=function(e){return v=e,this},this.onUpdate=function(e){return g=e,this},this.onComplete=function(e){return y=e,this},this.onStop=function(e){return C=e,this},this.update=function(e){var t;if(d>e)return!0;_===!1&&(null!==v&&v.call(r),_=!0);var u=(e-d)/a;u=u>1?1:u;var C=p(u);for(t in n){var E=i[t]||0,S=n[t];S instanceof Array?r[t]=m(S,C):("string"==typeof S&&(S=E+parseFloat(S,10)),"number"==typeof S&&(r[t]=E+(S-E)*C))}if(null!==g&&g.call(r,C),1==u){if(s>0){isFinite(s)&&s--;for(t in o){if("string"==typeof n[t]&&(o[t]=o[t]+parseFloat(n[t],10)),l){var w=o[t];o[t]=n[t],n[t]=w}i[t]=o[t]}return l&&(c=!c),d=e+h,!0}null!==y&&y.call(r);for(var T=0,b=f.length;b>T;T++)f[T].start(e);return!1}return!0}},e.Easing={Linear:{None:function(e){return e}},Quadratic:{In:function(e){return e*e},Out:function(e){return e*(2-e)},InOut:function(e){return(e*=2)<1?.5*e*e:-.5*(--e*(e-2)-1)}},Cubic:{In:function(e){return e*e*e},Out:function(e){return--e*e*e+1},InOut:function(e){return(e*=2)<1?.5*e*e*e:.5*((e-=2)*e*e+2)}},Quartic:{In:function(e){return e*e*e*e},Out:function(e){return 1- --e*e*e*e},InOut:function(e){return(e*=2)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2)}},Quintic:{In:function(e){return e*e*e*e*e},Out:function(e){return--e*e*e*e*e+1},InOut:function(e){return(e*=2)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2)}},Sinusoidal:{In:function(e){return 1-Math.cos(e*Math.PI/2)},Out:function(e){return Math.sin(e*Math.PI/2)},InOut:function(e){return.5*(1-Math.cos(Math.PI*e))}},Exponential:{In:function(e){return 0===e?0:Math.pow(1024,e-1)},Out:function(e){return 1===e?1:1-Math.pow(2,-10*e)},InOut:function(e){return 0===e?0:1===e?1:(e*=2)<1?.5*Math.pow(1024,e-1):.5*(-Math.pow(2,-10*(e-1))+2)}},Circular:{In:function(e){return 1-Math.sqrt(1-e*e)},Out:function(e){return Math.sqrt(1- --e*e)},InOut:function(e){return(e*=2)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1)}},Elastic:{In:function(e){var t,r=.1,i=.4;return 0===e?0:1===e?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),-(r*Math.pow(2,10*(e-=1))*Math.sin(2*(e-t)*Math.PI/i)))},Out:function(e){var t,r=.1,i=.4;return 0===e?0:1===e?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),r*Math.pow(2,-10*e)*Math.sin(2*(e-t)*Math.PI/i)+1)},InOut:function(e){var t,r=.1,i=.4;return 0===e?0:1===e?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),(e*=2)<1?-.5*r*Math.pow(2,10*(e-=1))*Math.sin(2*(e-t)*Math.PI/i):r*Math.pow(2,-10*(e-=1))*Math.sin(2*(e-t)*Math.PI/i)*.5+1)}},Back:{In:function(e){var t=1.70158;return e*e*((t+1)*e-t)},Out:function(e){var t=1.70158;return--e*e*((t+1)*e+t)+1},InOut:function(e){var t=2.5949095;return(e*=2)<1?.5*e*e*((t+1)*e-t):.5*((e-=2)*e*((t+1)*e+t)+2)}},Bounce:{In:function(t){return 1-e.Easing.Bounce.Out(1-t)},Out:function(e){return 1/2.75>e?7.5625*e*e:2/2.75>e?7.5625*(e-=1.5/2.75)*e+.75:2.5/2.75>e?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},InOut:function(t){return.5>t?.5*e.Easing.Bounce.In(2*t):.5*e.Easing.Bounce.Out(2*t-1)+.5}}},e.Interpolation={Linear:function(t,r){var i=t.length-1,n=i*r,o=Math.floor(n),a=e.Interpolation.Utils.Linear;return 0>r?a(t[0],t[1],n):r>1?a(t[i],t[i-1],i-n):a(t[o],t[o+1>i?i:o+1],n-o)},Bezier:function(t,r){var i,n=0,o=t.length-1,a=Math.pow,s=e.Interpolation.Utils.Bernstein;for(i=0;o>=i;i++)n+=a(1-r,o-i)*a(r,i)*t[i]*s(o,i);return n},CatmullRom:function(t,r){var i=t.length-1,n=i*r,o=Math.floor(n),a=e.Interpolation.Utils.CatmullRom;return t[0]===t[i]?(0>r&&(o=Math.floor(n=i*(1+r))),a(t[(o-1+i)%i],t[o],t[(o+1)%i],t[(o+2)%i],n-o)):0>r?t[0]-(a(t[0],t[0],t[1],t[1],-n)-t[0]):r>1?t[i]-(a(t[i],t[i],t[i-1],t[i-1],n-i)-t[i]):a(t[o?o-1:0],t[o],t[o+1>i?i:o+1],t[o+2>i?i:o+2],n-o)},Utils:{Linear:function(e,t,r){return(t-e)*r+e},Bernstein:function(t,r){var i=e.Interpolation.Utils.Factorial;return i(t)/i(r)/i(t-r)},Factorial:function(){var e=[1];return function(t){var r,i=1;if(e[t])return e[t];for(r=t;r>1;r--)i*=r;return e[t]=i}}(),CatmullRom:function(e,t,r,i,n){var o=.5*(r-e),a=.5*(i-t),s=n*n,l=n*s;return(2*t-2*r+o+a)*l+(-3*t+3*r-2*o-a)*s+o*n+t}}},e}),r("Core/EasingFunction",["../ThirdParty/Tween","./freezeObject"],function(e,t){"use strict";var r={LINEAR_NONE:e.Easing.Linear.None,QUADRACTIC_IN:e.Easing.Quadratic.In,QUADRACTIC_OUT:e.Easing.Quadratic.Out,QUADRACTIC_IN_OUT:e.Easing.Quadratic.InOut,CUBIC_IN:e.Easing.Cubic.In,CUBIC_OUT:e.Easing.Cubic.Out,CUBIC_IN_OUT:e.Easing.Cubic.InOut,QUARTIC_IN:e.Easing.Quartic.In,QUARTIC_OUT:e.Easing.Quartic.Out,QUARTIC_IN_OUT:e.Easing.Quartic.InOut,QUINTIC_IN:e.Easing.Quintic.In,QUINTIC_OUT:e.Easing.Quintic.Out,QUINTIC_IN_OUT:e.Easing.Quintic.InOut,SINUSOIDAL_IN:e.Easing.Sinusoidal.In,SINUSOIDAL_OUT:e.Easing.Sinusoidal.Out,SINUSOIDAL_IN_OUT:e.Easing.Sinusoidal.InOut,EXPONENTIAL_IN:e.Easing.Exponential.In,EXPONENTIAL_OUT:e.Easing.Exponential.Out,EXPONENTIAL_IN_OUT:e.Easing.Exponential.InOut,CIRCULAR_IN:e.Easing.Circular.In,CIRCULAR_OUT:e.Easing.Circular.Out,CIRCULAR_IN_OUT:e.Easing.Circular.InOut,ELASTIC_IN:e.Easing.Elastic.In,ELASTIC_OUT:e.Easing.Elastic.Out,ELASTIC_IN_OUT:e.Easing.Elastic.InOut,BACK_IN:e.Easing.Back.In,BACK_OUT:e.Easing.Back.Out,BACK_IN_OUT:e.Easing.Back.InOut,BOUNCE_IN:e.Easing.Bounce.In,BOUNCE_OUT:e.Easing.Bounce.Out,BOUNCE_IN_OUT:e.Easing.Bounce.InOut};return t(r)}),r("Core/EllipsoidGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new r,v=new r,_=new r,g=new r,y=new r,C=new r(1,1,1),E=Math.cos,S=Math.sin,w=function(e){e=n(e,n.EMPTY_OBJECT);var t=n(e.radii,C),i=n(e.stackPartitions,64),o=n(e.slicePartitions,64),a=n(e.vertexFormat,m.DEFAULT);this._radii=r.clone(t),this._stackPartitions=i,this._slicePartitions=o,this._vertexFormat=m.clone(a),this._workerName="createEllipsoidGeometry"};w.packedLength=r.packedLength+m.packedLength+2,w.pack=function(e,t,i){i=n(i,0),r.pack(e._radii,t,i),i+=r.packedLength,m.pack(e._vertexFormat,t,i),i+=m.packedLength,t[i++]=e._stackPartitions,t[i]=e._slicePartitions};var T=new r,b=new m,x={radii:T,vertexFormat:b,stackPartitions:void 0,slicePartitions:void 0};return w.unpack=function(e,t,i){t=n(t,0);var a=r.unpack(e,t,T);t+=r.packedLength;var s=m.unpack(e,t,b);t+=m.packedLength;var l=e[t++],u=e[t];return o(i)?(i._radii=r.clone(a,i._radii),i._vertexFormat=m.clone(s,i._vertexFormat),i._stackPartitions=l,i._slicePartitions=u,i):(x.stackPartitions=l,x.slicePartitions=u,new w(x))},w.createGeometry=function(n){var o,a,m=n._radii,C=s.fromCartesian3(m),w=n._vertexFormat,T=n._slicePartitions+1,b=n._stackPartitions+1,x=b*T,P=new Float64Array(3*x),A=6*(T-1)*(b-1),I=h.createTypedArray(x,A),M=w.normal?new Float32Array(3*x):void 0,D=w.tangent?new Float32Array(3*x):void 0,R=w.binormal?new Float32Array(3*x):void 0,O=w.st?new Float32Array(2*x):void 0,N=new Array(T),L=new Array(T),F=0;for(o=0;T>o;o++){var B=d.TWO_PI*o/(T-1);N[o]=E(B),L[o]=S(B),P[F++]=0,P[F++]=0,P[F++]=m.z}for(o=1;b-1>o;o++){var V=Math.PI*o/(b-1),z=S(V),k=m.x*z,U=m.y*z,G=m.z*E(V);for(a=0;T>a;a++)P[F++]=N[a]*k,P[F++]=L[a]*U,P[F++]=G}for(o=0;T>o;o++)P[F++]=0,P[F++]=0,P[F++]=-m.z;var W=new c;w.position&&(W.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:P}));var H=0,q=0,j=0,Y=0;if(w.st||w.normal||w.tangent||w.binormal){for(o=0;x>o;o++){var X=r.fromArray(P,3*o,f),Z=C.geodeticSurfaceNormal(X,v);if(w.st){var K=t.negate(Z,y);t.magnitude(K)P.length&&(F=3*(o-T*Math.floor(.5*b))),r.fromArray(P,F,K),C.geodeticSurfaceNormal(K,K),t.negate(K,K)),O[H++]=Math.atan2(K.y,K.x)/d.TWO_PI+.5,O[H++]=Math.asin(Z.z)/Math.PI+.5}if(w.normal&&(M[q++]=Z.x,M[q++]=Z.y,M[q++]=Z.z),w.tangent||w.binormal){var J=_;if(T>o||o>x-T-1?(r.cross(r.UNIT_X,Z,J),r.normalize(J,J)):(r.cross(r.UNIT_Z,Z,J),r.normalize(J,J)),w.tangent&&(D[j++]=J.x,D[j++]=J.y,D[j++]=J.z),w.binormal){var Q=r.cross(Z,J,g);r.normalize(Q,Q),R[Y++]=Q.x,R[Y++]=Q.y,R[Y++]=Q.z}}}w.st&&(W.st=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:O})),w.normal&&(W.normal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:M})),w.tangent&&(W.tangent=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:D})),w.binormal&&(W.binormal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:R}))}for(F=0,o=0;b>o;o++){var $=o*T,ee=(o+1)*T;for(a=0;T-1>a;a++)I[F++]=ee+a,I[F++]=ee+a+1,I[F++]=$+a+1,I[F++]=ee+a,I[F++]=$+a+1,I[F++]=$+a}return new l({attributes:W,indices:I,primitiveType:p.TRIANGLES,boundingSphere:e.fromEllipsoid(C)})},w}),r("Core/EllipsoidOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";var p=new t(1,1,1),m=Math.cos,f=Math.sin,v=function(e){e=i(e,i.EMPTY_OBJECT);var r=i(e.radii,p),n=i(e.stackPartitions,10),o=i(e.slicePartitions,8),a=i(e.subdivisions,128);this._radii=t.clone(r),this._stackPartitions=n,this._slicePartitions=o,this._subdivisions=a,this._workerName="createEllipsoidOutlineGeometry"};v.packedLength=t.packedLength+3,v.pack=function(e,r,n){n=i(n,0),t.pack(e._radii,r,n),n+=t.packedLength,r[n++]=e._stackPartitions,r[n++]=e._slicePartitions,r[n]=e._subdivisions};var _=new t,g={radii:_,stackPartitions:void 0,slicePartitions:void 0,subdivisions:void 0};return v.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,_);r+=t.packedLength;var s=e[r++],l=e[r++],u=e[r++];return n(o)?(o._radii=t.clone(a,o._radii),o._stackPartitions=s,o._slicePartitions=l,o._subdivisions=u,o):(g.stackPartitions=s,g.slicePartitions=l,g.subdivisions=u,new v(g))},v.createGeometry=function(t){var i,n,o,p,v,_,g=t._radii,y=a.fromCartesian3(g),C=t._stackPartitions,E=t._slicePartitions,S=t._subdivisions,w=S*(C+E-1),T=w-E+2,b=new Float64Array(3*T),x=c.createTypedArray(T,2*w),P=0,A=new Array(S),I=new Array(S);for(i=0;S>i;i++)o=h.TWO_PI*i/S,A[i]=m(o),I[i]=f(o);for(i=1;C>i;i++)for(p=Math.PI*i/C,v=m(p),_=f(p),n=0;S>n;n++)b[P++]=g.x*A[n]*_,b[P++]=g.y*I[n]*_,b[P++]=g.z*v;for(A.length=E,I.length=E,i=0;E>i;i++)o=h.TWO_PI*i/E,A[i]=m(o),I[i]=f(o);for(b[P++]=0,b[P++]=0,b[P++]=g.z,i=1;S>i;i++)for(p=Math.PI*i/S,v=m(p),_=f(p),n=0;E>n;n++)b[P++]=g.x*A[n]*_,b[P++]=g.y*I[n]*_,b[P++]=g.z*v;for(b[P++]=0,b[P++]=0,b[P++]=-g.z,P=0,i=0;C-1>i;++i){var M=i*S;for(n=0;S-1>n;++n)x[P++]=M+n,x[P++]=M+n+1;x[P++]=M+S-1,x[P++]=M}var D=S*(C-1);for(n=1;E+1>n;++n)x[P++]=D,x[P++]=D+n;for(i=0;S-2>i;++i){var R=i*E+1+D,O=(i+1)*E+1+D;for(n=0;E-1>n;++n)x[P++]=O+n,x[P++]=R+n;x[P++]=O+E-1,x[P++]=R+E-1}var N=b.length/3-1;for(n=N-1;n>N-E-1;--n)x[P++]=N,x[P++]=n;var L=new u({position:new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:b})});return new s({attributes:L,indices:x,primitiveType:d.LINES,boundingSphere:e.fromEllipsoid(y)})},v}),r("Core/EllipsoidTerrainProvider",["../ThirdParty/when","./defaultValue","./defined","./defineProperties","./Ellipsoid","./Event","./GeographicTilingScheme","./HeightmapTerrainData","./TerrainProvider"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(i){i=t(i,{}),this._tilingScheme=i.tilingScheme,r(this._tilingScheme)||(this._tilingScheme=new a({ellipsoid:t(i.ellipsoid,n.WGS84)})),this._levelZeroMaximumGeometricError=l.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid,64,this._tilingScheme.getNumberOfXTilesAtLevel(0));var u=16,c=16;this._terrainData=new s({buffer:new Uint8Array(u*c),width:16,height:16}),this._errorEvent=new o,this._readyPromise=e.resolve(!0)};return i(u.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return void 0}},tilingScheme:{get:function(){return this._tilingScheme}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},hasWaterMask:{get:function(){return!1}},hasVertexNormals:{get:function(){return!1}}}),u.prototype.requestTileGeometry=function(e,t,r,i){return this._terrainData},u.prototype.getLevelMaximumGeometricError=function(e){return this._levelZeroMaximumGeometricError/(1<=r||r===1/0||r!==r?void 0:t.multiplyByScalar(e,r,i)}function u(e,r){return e.transformPositionToScaledSpace(r,v),t.normalize(v,v)}var c=function(e,r){this._ellipsoid=e,this._cameraPosition=new t,this._cameraPositionInScaledSpace=new t,this._distanceToLimbInScaledSpaceSquared=0,i(r)&&(this.cameraPosition=r)};n(c.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},cameraPosition:{get:function(){return this._cameraPosition},set:function(e){var r=this._ellipsoid,i=r.transformPositionToScaledSpace(e,this._cameraPositionInScaledSpace),n=t.magnitudeSquared(i)-1;t.clone(e,this._cameraPosition),this._cameraPositionInScaledSpace=i,this._distanceToLimbInScaledSpaceSquared=n}}});var h=new t;c.prototype.isPointVisible=function(e){var t=this._ellipsoid,r=t.transformPositionToScaledSpace(e,h);return this.isScaledSpacePointVisible(r)},c.prototype.isScaledSpacePointVisible=function(e){if(this._distanceToLimbInScaledSpaceSquared<0)return!0;var r=this._cameraPositionInScaledSpace,i=this._distanceToLimbInScaledSpaceSquared,n=t.subtract(e,r,h),o=-t.dot(n,r),a=o>i&&o*o/t.magnitudeSquared(n)>i;return!a},c.prototype.computeHorizonCullingPoint=function(e,r,n){i(n)||(n=new t);for(var o=this._ellipsoid,a=u(o,e),c=0,h=0,d=r.length;d>h;++h){var p=r[h],m=s(o,p,a);c=Math.max(c,m)}return l(a,c,n)};var d=new t;c.prototype.computeHorizonCullingPointFromVertices=function(e,n,o,a,c){i(c)||(c=new t),a=r(a,t.ZERO);for(var h=this._ellipsoid,p=u(h,e),m=0,f=0,v=n.length;v>f;f+=o){d.x=n[f]+a.x,d.y=n[f+1]+a.y,d.z=n[f+2]+a.z;var _=s(h,d,p);m=Math.max(m,_)}return l(p,m,c)};var p=[];c.prototype.computeHorizonCullingPointFromRectangle=function(r,i,n){var o=a.subsample(r,i,0,p),s=e.fromPoints(o);return t.magnitude(s.center)<.1*i.minimumRadius?void 0:this.computeHorizonCullingPoint(s.center,o,n)};var m=new t,f=new t,v=new t;return c}),r("Core/EventHelper",["./defined","./DeveloperError"],function(e,t){"use strict";var r=function(){this._removalFunctions=[]};return r.prototype.add=function(e,t,r){var i=e.addEventListener(t,r);this._removalFunctions.push(i);var n=this;return function(){i();var e=n._removalFunctions;e.splice(e.indexOf(i),1)}},r.prototype.removeAll=function(){for(var e=this._removalFunctions,t=0,r=e.length;r>t;++t)e[t]();e.length=0},r}),r("Core/ExtrapolationType",["./freezeObject"],function(e){"use strict";var t={NONE:0,HOLD:1,EXTRAPOLATE:2};return e(t)}),r("Core/GeometryInstanceAttribute",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t){t=e(t,e.EMPTY_OBJECT),this.componentDatatype=t.componentDatatype,this.componentsPerAttribute=t.componentsPerAttribute,this.normalize=e(t.normalize,!1),this.value=t.value};return i}),r("Core/HeadingPitchRange",["./defaultValue","./defined"],function(e,t){"use strict";var r=function(t,r,i){this.heading=e(t,0),this.pitch=e(r,0),this.range=e(i,0)};return r.clone=function(e,i){return t(e)?(t(i)||(i=new r),i.heading=e.heading,i.pitch=e.pitch,i.range=e.range,i):void 0},r}),r("Core/HermitePolynomialApproximation",["./defaultValue","./defined","./DeveloperError","./Math"],function(e,t,r,i){"use strict";function n(e,t,r,i,o,a){var s,l,u,c=0;if(i>0){for(l=0;o>l;l++){for(s=!1,u=0;ul;l++){for(s=!1,u=0;ud;d++){var p=Math.floor(d*h);for(s=0;c>s;s++)l=t[s]*o*(a+1)+d,e[p+s]=n[l];for(var m=1;c>m;m++){var f=0,v=Math.floor(m*(1-m)/2)+c*m,_=!1;for(s=0;c-m>s;s++){var g,y,C=r[t[s]],E=r[t[s+m]];if(0>=E-C)l=t[s]*o*(a+1)+o*m+d,g=n[l],y=g/i.factorial(m),e[p+v+f]=y,f++;else{var S=Math.floor((m-1)*(2-m)/2)+c*(m-1);g=e[p+S+s+1]-e[p+S+s],y=g/(E-C),e[p+v+f]=y,f++}_=_||0!==g}_&&(u=Math.max(u,m))}}return u}var a=i.factorial,s={type:"Hermite"};s.getRequiredDataPoints=function(t,r){return r=e(r,0),Math.max(Math.floor((t+1)/(r+1)),2)},s.interpolateOrderZero=function(e,r,i,o,s){t(s)||(s=new Array(o));var l,u,c,h,d,p,m=r.length,f=new Array(o);for(l=0;o>l;l++){s[l]=0;var v=new Array(m);for(f[l]=v,u=0;m>u;u++)v[u]=[]}var _=m,g=new Array(_);for(l=0;_>l;l++)g[l]=l;var y=m-1;for(h=0;o>h;h++){for(u=0;_>u;u++)p=g[u]*o+h,f[h][0].push(i[p]);for(l=1;_>l;l++){var C=!1;for(u=0;_-l>u;u++){var E,S=r[g[u]],w=r[g[u+l]];0>=w-S?(p=g[u]*o+o*l+h,E=i[p],f[h][l].push(E/a(l))):(E=f[h][l-1][u+1]-f[h][l-1][u],f[h][l].push(E/(w-S))),C=C||0!==E}C||(y=l-1)}}for(c=0,d=0;d>=c;c++)for(l=c;y>=l;l++){var T=n(e,g,r,c,l,[]);for(h=0;o>h;h++){var b=f[h][l][0];s[h+c*o]+=b*T}}return s};var l=[];return s.interpolate=function(e,r,i,a,s,u,c){var h=a*(u+1);t(c)||(c=new Array(h));for(var d=0;h>d;d++)c[d]=0;for(var p=r.length,m=new Array(p*(s+1)),f=0;p>f;f++)for(var v=0;s+1>v;v++)m[f*(s+1)+v]=f;for(var _=m.length,g=l,y=o(g,m,r,i,a,s),C=[],E=_*(_+1)/2,S=Math.min(y,u),w=0;S>=w;w++)for(f=w;y>=f;f++){C.length=0;for(var T=n(e,m,r,w,f,C),b=Math.floor(f*(1-f)/2)+_*f,x=0;a>x;x++){var P=Math.floor(x*E),A=g[P+b];c[x+w*a]+=A*T}}return c},s}),r("Core/IauOrientationParameters",[],function(){"use strict";var e=function(e,t,r,i){this.rightAscension=e,this.declination=t,this.rotation=r,this.rotationRate=i};return e}),r("Core/Iau2000Orientation",["./defined","./IauOrientationParameters","./JulianDate","./Math","./TimeConstants"],function(e,t,r,i,n){"use strict";var o={},a=32.184,s=2451545,l=-.0529921,u=-.1059842,c=13.0120009,h=13.3407154,d=.9856003,p=26.4057084,m=13.064993,f=.3287146,v=1.7484877,_=-.1589763,g=.0036096,y=.1643573,C=12.9590088,E=new r;return o.ComputeMoon=function(o,S){e(o)||(o=r.now()),E=r.addSeconds(o,a,E);var w=r.totalDays(E)-s,T=w/n.DAYS_PER_JULIAN_CENTURY,b=(125.045+l*w)*i.RADIANS_PER_DEGREE,x=(250.089+u*w)*i.RADIANS_PER_DEGREE,P=(260.008+c*w)*i.RADIANS_PER_DEGREE,A=(176.625+h*w)*i.RADIANS_PER_DEGREE,I=(357.529+d*w)*i.RADIANS_PER_DEGREE,M=(311.589+p*w)*i.RADIANS_PER_DEGREE,D=(134.963+m*w)*i.RADIANS_PER_DEGREE,R=(276.617+f*w)*i.RADIANS_PER_DEGREE,O=(34.226+v*w)*i.RADIANS_PER_DEGREE,N=(15.134+_*w)*i.RADIANS_PER_DEGREE,L=(119.743+g*w)*i.RADIANS_PER_DEGREE,F=(239.961+y*w)*i.RADIANS_PER_DEGREE,B=(25.053+C*w)*i.RADIANS_PER_DEGREE,V=Math.sin(b),z=Math.sin(x),k=Math.sin(P),U=Math.sin(A),G=Math.sin(I),W=Math.sin(M),H=Math.sin(D),q=Math.sin(R),j=Math.sin(O),Y=Math.sin(N),X=Math.sin(L),Z=Math.sin(F),K=Math.sin(B),J=Math.cos(b),Q=Math.cos(x),$=Math.cos(P),ee=Math.cos(A),te=Math.cos(I),re=Math.cos(M),ie=Math.cos(D),ne=Math.cos(R),oe=Math.cos(O),ae=Math.cos(N),se=Math.cos(L),le=Math.cos(F),ue=Math.cos(B),ce=(269.9949+.0031*T-3.8787*V-.1204*z+.07*k-.0172*U+.0072*W-.0052*Y+.0043*K)*i.RADIANS_PER_DEGREE,he=(66.5392+.013*T+1.5419*J+.0239*Q-.0278*$+.0068*ee-.0029*re+9e-4*ie+8e-4*ae-9e-4*ue)*i.RADIANS_PER_DEGREE,de=(38.3213+13.17635815*w-1.4e-12*w*w+3.561*V+.1208*z-.0642*k+.0158*U+.0252*G-.0066*W-.0047*H-.0046*q+.0028*j+.0052*Y+.004*X+.0019*Z-.0044*K)*i.RADIANS_PER_DEGREE,pe=(13.17635815-2.8e-12*w+3.561*J*l+.1208*Q*u-.0642*$*c+.0158*ee*h+.0252*te*d-.0066*re*p-.0047*ie*m-.0046*ne*f+.0028*oe*v+.0052*ae*_+.004*se*g+.0019*le*y-.0044*ue*C)/86400*i.RADIANS_PER_DEGREE;return e(S)||(S=new t),S.rightAscension=ce,S.declination=he,S.rotation=de,S.rotationRate=pe,S},o}),r("Core/IauOrientationAxes",["./Cartesian3","./defined","./Iau2000Orientation","./JulianDate","./Math","./Matrix3","./Quaternion"],function(e,t,r,i,n,o,a){"use strict";function s(r,i,a){var s=u;s.x=Math.cos(r+n.PI_OVER_TWO),s.y=Math.sin(r+n.PI_OVER_TWO),s.z=0;var l=Math.cos(i),d=h;d.x=l*Math.cos(r),d.y=l*Math.sin(r),d.z=Math.sin(i);var p=e.cross(d,s,c);return t(a)||(a=new o),a[0]=s.x,a[1]=p.x,a[2]=d.x,a[3]=s.y,a[4]=p.y,a[5]=d.y,a[6]=s.z,a[7]=p.z,a[8]=d.z,a}var l=function(e){t(e)&&"function"==typeof e||(e=r.ComputeMoon),this._computeFunction=e},u=new e,c=new e,h=new e,d=new o,p=new a;return l.prototype.evaluate=function(r,l){t(r)||(r=i.now());var u=this._computeFunction(r),c=s(u.rightAscension,u.declination,l),h=n.zeroToTwoPi(u.rotation),m=a.fromAxisAngle(e.UNIT_Z,h,p),f=o.fromQuaternion(a.conjugate(m,m),d),v=o.multiply(f,c,c);return v},l}),r("Core/InterpolationAlgorithm",["./DeveloperError"],function(e){"use strict";var t={};return t.type=void 0,t.getRequiredDataPoints=e.throwInstantiationError,t.interpolateOrderZero=e.throwInstantiationError,t.interpolate=e.throwInstantiationError,t}),r("Core/TimeInterval",["./defaultValue","./defined","./defineProperties","./DeveloperError","./freezeObject","./JulianDate"],function(e,t,r,i,n,o){"use strict";var a=function(r){r=e(r,e.EMPTY_OBJECT),this.start=t(r.start)?o.clone(r.start):new o,this.stop=t(r.stop)?o.clone(r.stop):new o,this.data=r.data,this.isStartIncluded=e(r.isStartIncluded,!0),this.isStopIncluded=e(r.isStopIncluded,!0)};r(a.prototype,{isEmpty:{get:function(){var e=o.compare(this.stop,this.start);return 0>e||0===e&&(!this.isStartIncluded||!this.isStopIncluded)}}});var s={start:void 0,stop:void 0,isStartIncluded:void 0,isStopIncluded:void 0,data:void 0};return a.fromIso8601=function(r,i){var n=r.iso8601.split("/"),l=o.fromIso8601(n[0]),u=o.fromIso8601(n[1]),c=e(r.isStartIncluded,!0),h=e(r.isStopIncluded,!0),d=r.data;return t(i)?(i.start=l,i.stop=u,i.isStartIncluded=c,i.isStopIncluded=h,i.data=d,i):(s.start=l,s.stop=u,s.isStartIncluded=c,s.isStopIncluded=h,s.data=d,new a(s))},a.toIso8601=function(e,t){return o.toIso8601(e.start,t)+"/"+o.toIso8601(e.stop,t)},a.clone=function(e,r){return t(e)?t(r)?(r.start=e.start,r.stop=e.stop,r.isStartIncluded=e.isStartIncluded,r.isStopIncluded=e.isStopIncluded,r.data=e.data,r):new a(e):void 0},a.equals=function(e,r,i){return e===r||t(e)&&t(r)&&(e.isEmpty&&r.isEmpty||e.isStartIncluded===r.isStartIncluded&&e.isStopIncluded===r.isStopIncluded&&o.equals(e.start,r.start)&&o.equals(e.stop,r.stop)&&(e.data===r.data||t(i)&&i(e.data,r.data)))},a.equalsEpsilon=function(e,r,i,n){return e===r||t(e)&&t(r)&&(e.isEmpty&&r.isEmpty||e.isStartIncluded===r.isStartIncluded&&e.isStopIncluded===r.isStopIncluded&&o.equalsEpsilon(e.start,r.start,i)&&o.equalsEpsilon(e.stop,r.stop,i)&&(e.data===r.data||t(n)&&n(e.data,r.data)))},a.intersect=function(e,r,i,n){if(!t(r))return a.clone(a.EMPTY,i);var s=e.start,l=e.stop,u=r.start,c=r.stop,h=o.greaterThanOrEquals(u,s)&&o.greaterThanOrEquals(l,u),d=!h&&o.lessThanOrEquals(u,s)&&o.lessThanOrEquals(s,c);if(!h&&!d)return a.clone(a.EMPTY,i);var p=e.isStartIncluded,m=e.isStopIncluded,f=r.isStartIncluded,v=r.isStopIncluded,_=o.lessThan(l,c);return i.start=h?u:s,i.isStartIncluded=p&&f||!o.equals(u,s)&&(h&&f||d&&p),i.stop=_?l:c,i.isStopIncluded=_?m:m&&v||!o.equals(c,l)&&v,i.data=t(n)?n(e.data,r.data):e.data,i},a.contains=function(e,t){if(e.isEmpty)return!1;var r=o.compare(e.start,t);if(0===r)return e.isStartIncluded;var i=o.compare(t,e.stop);return 0===i?e.isStopIncluded:0>r&&0>i},a.prototype.clone=function(e){return a.clone(this,e)},a.prototype.equals=function(e,t){return a.equals(this,e,t)},a.prototype.equalsEpsilon=function(e,t,r){return a.equalsEpsilon(this,e,t,r)},a.prototype.toString=function(){return a.toIso8601(this)},a.EMPTY=n(new a({start:new o,stop:new o,isStartIncluded:!1,isStopIncluded:!1})),a}),r("Core/Iso8601",["./freezeObject","./JulianDate","./TimeInterval"],function(e,t,r){ +"use strict";var i=e(t.fromIso8601("0000-01-01T00:00:00Z")),n=e(t.fromIso8601("9999-12-31T24:00:00Z")),o=e(new r({start:i,stop:n})),a={MINIMUM_VALUE:i,MAXIMUM_VALUE:n,MAXIMUM_INTERVAL:o};return a}),r("Core/KeyboardEventModifier",["./freezeObject"],function(e){"use strict";var t={SHIFT:0,CTRL:1,ALT:2};return e(t)}),r("Core/LagrangePolynomialApproximation",["./defined"],function(e){"use strict";var t={type:"Lagrange"};return t.getRequiredDataPoints=function(e){return Math.max(e+1,2)},t.interpolateOrderZero=function(t,r,i,n,o){e(o)||(o=new Array(n));var a,s,l=r.length;for(a=0;n>a;a++)o[a]=0;for(a=0;l>a;a++){var u=1;for(s=0;l>s;s++)if(s!==a){var c=r[a]-r[s];u*=(t-r[s])/c}for(s=0;n>s;s++)o[s]+=u*i[a*n+s]}return o},t}),r("Core/LinearApproximation",["./defined","./DeveloperError"],function(e,t){"use strict";var r={type:"Linear"};return r.getRequiredDataPoints=function(e){return 2},r.interpolateOrderZero=function(t,r,i,n,o){e(o)||(o=new Array(n));var a,s,l,u=r[0],c=r[1];for(a=0;n>a;a++)s=i[a],l=i[a+n],o[a]=((l-s)*t+c*s-u*l)/(c-u);return o},r}),r("Core/MapProjection",["./defineProperties","./DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return e(r.prototype,{ellipsoid:{get:t.throwInstantiationError}}),r.prototype.project=t.throwInstantiationError,r.prototype.unproject=t.throwInstantiationError,r}),r("Core/MapboxApi",["./defined"],function(e){"use strict";var t={};t.defaultAccessToken=void 0;var r=!1;return t.getAccessToken=function(i){return e(i)?i:e(t.defaultAccessToken)?t.defaultAccessToken:(r||(console.log("This application is using Cesium's default Mapbox access token. Please create a new access token for the application as soon as possible and prior to deployment by visiting https://www.mapbox.com/account/apps/, and provide your token to Cesium by setting the Cesium.MapboxApi.defaultAccessToken property before constructing the CesiumWidget or any other object that uses the Mapbox API."),r=!0),"pk.eyJ1IjoiYW5hbHl0aWNhbGdyYXBoaWNzIiwiYSI6IjA2YzBjOTM3YzFlYzljYmQ5NDAxZWI1Y2ZjNzZlM2E1In0.vDZL2SPFEpi_f7ziAIP_yw")},t}),r("Core/Matrix2",["./Cartesian2","./defaultValue","./defined","./DeveloperError","./freezeObject"],function(e,t,r,i,n){"use strict";var o=function(e,r,i,n){this[0]=t(e,0),this[1]=t(i,0),this[2]=t(r,0),this[3]=t(n,0)};o.packedLength=4,o.pack=function(e,r,i){i=t(i,0),r[i++]=e[0],r[i++]=e[1],r[i++]=e[2],r[i++]=e[3]},o.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new o),n[0]=e[i++],n[1]=e[i++],n[2]=e[i++],n[3]=e[i++],n},o.clone=function(e,t){return r(e)?r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t):new o(e[0],e[2],e[1],e[3]):void 0},o.fromArray=function(e,i,n){return i=t(i,0),r(n)||(n=new o),n[0]=e[i],n[1]=e[i+1],n[2]=e[i+2],n[3]=e[i+3],n},o.fromColumnMajorArray=function(e,t){return o.clone(e,t)},o.fromRowMajorArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[2],t[2]=e[1],t[3]=e[3],t):new o(e[0],e[1],e[2],e[3])},o.fromScale=function(e,t){return r(t)?(t[0]=e.x,t[1]=0,t[2]=0,t[3]=e.y,t):new o(e.x,0,0,e.y)},o.fromUniformScale=function(e,t){return r(t)?(t[0]=e,t[1]=0,t[2]=0,t[3]=e,t):new o(e,0,0,e)},o.fromRotation=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=i,t[1]=n,t[2]=-n,t[3]=i,t):new o(i,-n,n,i)},o.toArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t):[e[0],e[1],e[2],e[3]]},o.getElementIndex=function(e,t){return 2*e+t},o.getColumn=function(e,t,r){var i=2*t,n=e[i],o=e[i+1];return r.x=n,r.y=o,r},o.setColumn=function(e,t,r,i){i=o.clone(e,i);var n=2*t;return i[n]=r.x,i[n+1]=r.y,i},o.getRow=function(e,t,r){var i=e[t],n=e[t+2];return r.x=i,r.y=n,r},o.setRow=function(e,t,r,i){return i=o.clone(e,i),i[t]=r.x,i[t+2]=r.y,i};var a=new e;o.getScale=function(t,r){return r.x=e.magnitude(e.fromElements(t[0],t[1],a)),r.y=e.magnitude(e.fromElements(t[2],t[3],a)),r};var s=new e;return o.getMaximumScale=function(t){return o.getScale(t,s),e.maximumComponent(s)},o.multiply=function(e,t,r){var i=e[0]*t[0]+e[2]*t[1],n=e[0]*t[2]+e[2]*t[3],o=e[1]*t[0]+e[3]*t[1],a=e[1]*t[2]+e[3]*t[3];return r[0]=i,r[1]=o,r[2]=n,r[3]=a,r},o.add=function(e,t,r){return r[0]=e[0]+t[0],r[1]=e[1]+t[1],r[2]=e[2]+t[2],r[3]=e[3]+t[3],r},o.subtract=function(e,t,r){return r[0]=e[0]-t[0],r[1]=e[1]-t[1],r[2]=e[2]-t[2],r[3]=e[3]-t[3],r},o.multiplyByVector=function(e,t,r){var i=e[0]*t.x+e[2]*t.y,n=e[1]*t.x+e[3]*t.y;return r.x=i,r.y=n,r},o.multiplyByScalar=function(e,t,r){return r[0]=e[0]*t,r[1]=e[1]*t,r[2]=e[2]*t,r[3]=e[3]*t,r},o.multiplyByScale=function(e,t,r){return r[0]=e[0]*t.x,r[1]=e[1]*t.x,r[2]=e[2]*t.y,r[3]=e[3]*t.y,r},o.negate=function(e,t){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t},o.transpose=function(e,t){var r=e[0],i=e[2],n=e[1],o=e[3];return t[0]=r,t[1]=i,t[2]=n,t[3]=o,t},o.abs=function(e,t){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t[3]=Math.abs(e[3]),t},o.equals=function(e,t){return e===t||r(e)&&r(t)&&e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[3]===t[3]},o.equalsArray=function(e,t,r){return e[0]===t[r]&&e[1]===t[r+1]&&e[2]===t[r+2]&&e[3]===t[r+3]},o.equalsEpsilon=function(e,t,i){return e===t||r(e)&&r(t)&&Math.abs(e[0]-t[0])<=i&&Math.abs(e[1]-t[1])<=i&&Math.abs(e[2]-t[2])<=i&&Math.abs(e[3]-t[3])<=i},o.IDENTITY=n(new o(1,0,0,1)),o.ZERO=n(new o(0,0,0,0)),o.COLUMN0ROW0=0,o.COLUMN0ROW1=1,o.COLUMN1ROW0=2,o.COLUMN1ROW1=3,o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t){return o.equalsEpsilon(this,e,t)},o.prototype.toString=function(){return"("+this[0]+", "+this[2]+")\n("+this[1]+", "+this[3]+")"},o}),r("Core/NearFarScalar",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t,r,i,n){this.near=e(t,0),this.nearValue=e(r,0),this.far=e(i,1),this.farValue=e(n,0)};return i.clone=function(e,r){return t(e)?t(r)?(r.near=e.near,r.nearValue=e.nearValue,r.far=e.far,r.farValue=e.farValue,r):new i(e.near,e.nearValue,e.far,e.farValue):void 0},i.packedLength=4,i.pack=function(t,r,i){i=e(i,0),r[i++]=t.near,r[i++]=t.nearValue,r[i++]=t.far,r[i]=t.farValue},i.unpack=function(r,n,o){return n=e(n,0),t(o)||(o=new i),o.near=r[n++],o.nearValue=r[n++],o.far=r[n++],o.farValue=r[n],o},i.equals=function(e,r){return e===r||t(e)&&t(r)&&e.near===r.near&&e.nearValue===r.nearValue&&e.far===r.far&&e.farValue===r.farValue},i.prototype.clone=function(e){return i.clone(this,e)},i.prototype.equals=function(e){return i.equals(this,e)},i}),r("Core/Visibility",["./freezeObject"],function(e){"use strict";var t={NONE:-1,PARTIAL:0,FULL:1};return e(t)}),r("Core/Occluder",["./BoundingSphere","./Cartesian3","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Math","./Rectangle","./Visibility"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(e,r){this._occluderPosition=t.clone(e.center),this._occluderRadius=e.radius,this._horizonDistance=0,this._horizonPlaneNormal=void 0,this._horizonPlanePosition=void 0,this._cameraPosition=void 0,this.cameraPosition=r},h=new t;n(c.prototype,{position:{get:function(){return this._occluderPosition}},radius:{get:function(){return this._occluderRadius}},cameraPosition:{set:function(e){e=t.clone(e,this._cameraPosition);var r,i,n,o=t.subtract(this._occluderPosition,e,h),a=t.magnitudeSquared(o),s=this._occluderRadius*this._occluderRadius;if(a>s){r=Math.sqrt(a-s),a=1/Math.sqrt(a),i=t.multiplyByScalar(o,a,h);var l=r*r*a;n=t.add(e,t.multiplyByScalar(i,l,h),h)}else r=Number.MAX_VALUE;this._horizonDistance=r,this._horizonPlaneNormal=i,this._horizonPlanePosition=n,this._cameraPosition=e}}}),c.fromBoundingSphere=function(e,r,n){if(!i(e))throw new o("occluderBoundingSphere is required.");if(!i(r))throw new o("camera position is required.");return i(n)?(t.clone(e.center,n._occluderPosition),n._occluderRadius=e.radius,n.cameraPosition=r,n):new c(e,r)};var d=new t;c.prototype.isPointVisible=function(e){if(this._horizonDistance!==Number.MAX_VALUE){var r=t.subtract(e,this._occluderPosition,d),i=this._occluderRadius;if(i=t.magnitudeSquared(r)-i*i,i>0)return i=Math.sqrt(i)+this._horizonDistance,r=t.subtract(e,this._cameraPosition,r),i*i>t.magnitudeSquared(r)}return!1};var p=new t;c.prototype.isBoundingSphereVisible=function(e){var r=t.clone(e.center,p),i=e.radius;if(this._horizonDistance!==Number.MAX_VALUE){var n=t.subtract(r,this._occluderPosition,d),o=this._occluderRadius-i;if(o=t.magnitudeSquared(n)-o*o,i0?(o=Math.sqrt(o)+this._horizonDistance,n=t.subtract(r,this._cameraPosition,n),o*o+i*i>t.magnitudeSquared(n)):!1;if(o>0){n=t.subtract(r,this._cameraPosition,n);var a=t.magnitudeSquared(n),s=this._occluderRadius*this._occluderRadius,l=i*i;return(this._horizonDistance*this._horizonDistance+s)*l>a*s?!0:(o=Math.sqrt(o)+this._horizonDistance,o*o+l>a)}return!0}return!1};var m=new t;c.prototype.computeVisibility=function(e){if(!i(e))throw new o("occludeeBS is required.");var r=t.clone(e.center),n=e.radius;if(n>this._occluderRadius)return u.FULL;if(this._horizonDistance!==Number.MAX_VALUE){var a=t.subtract(r,this._occluderPosition,m),s=this._occluderRadius-n,l=t.magnitudeSquared(a);if(s=l-s*s,s>0){s=Math.sqrt(s)+this._horizonDistance,a=t.subtract(r,this._cameraPosition,a);var c=t.magnitudeSquared(a);return c>s*s+n*n?u.NONE:(s=this._occluderRadius+n,s=l-s*s,s>0?(s=Math.sqrt(s)+this._horizonDistance,s*s+n*n>c?u.FULL:u.PARTIAL):(a=t.subtract(r,this._horizonPlanePosition,a),t.dot(a,this._horizonPlaneNormal)>-n?u.PARTIAL:u.FULL))}}return u.NONE};var f=new t;c.computeOccludeePoint=function(e,r,i){var n=t.clone(r),a=t.clone(e.center),s=e.radius,l=i.length;if(t.equals(a,r))throw new o("occludeePosition must be different than occluderBoundingSphere.center");var u=t.normalize(t.subtract(n,a,f),f),h=-t.dot(u,a),d=c._anyRotationVector(a,u,h),p=c._horizonToPlaneNormalDotProduct(e,u,h,d,i[0]);if(!p)return void 0;for(var m,v=1;l>v;++v){if(m=c._horizonToPlaneNormalDotProduct(e,u,h,d,i[v]),!m)return void 0;p>m&&(p=m)}if(.0017453283658983088>p)return void 0;var _=s/p;return t.add(a,t.multiplyByScalar(u,_,f),f)};var v=[];c.computeOccludeePointFromRectangle=function(i,n){n=r(n,a.WGS84);var o=l.subsample(i,n,0,v),s=e.fromPoints(o),u=t.ZERO;return t.equals(u,s.center)?void 0:c.computeOccludeePoint(new e(u,n.minimumRadius),s.center,o)};var _=new t;c._anyRotationVector=function(e,r,i){var n=t.abs(r,_),o=n.x>n.y?0:1;(0===o&&n.z>n.x||1===o&&n.z>n.y)&&(o=2);var a,s=new t;0===o?(n.x=e.x,n.y=e.y+1,n.z=e.z+1,a=t.UNIT_X):1===o?(n.x=e.x+1,n.y=e.y,n.z=e.z+1,a=t.UNIT_Y):(n.x=e.x+1,n.y=e.y+1,n.z=e.z,a=t.UNIT_Z);var l=(t.dot(r,n)+i)/-t.dot(r,a);return t.normalize(t.subtract(t.add(n,t.multiplyByScalar(a,l,s),n),e,n),n)};var g=new t;c._rotationVector=function(e,r,i,n,o){var a=t.subtract(n,e,g);if(a=t.normalize(a,a),t.dot(r,a)<.9999999847691291){var l=t.cross(r,a,a),u=t.magnitude(l);if(u>s.EPSILON13)return t.normalize(l,new t)}return o};var y=new t,C=new t,E=new t,S=new t;return c._horizonToPlaneNormalDotProduct=function(e,r,i,n,o){var a=t.clone(o,y),s=t.clone(e.center,C),l=e.radius,u=t.subtract(s,a,E),c=t.magnitudeSquared(u),h=l*l;if(h>c)return!1;var d=c-h,p=Math.sqrt(d),m=Math.sqrt(c),f=1/m,v=p*f,_=v*p;u=t.normalize(u,u);var g=t.add(a,t.multiplyByScalar(u,_,S),S),w=Math.sqrt(d-_*_),T=this._rotationVector(s,r,i,a,n),b=t.fromElements(T.x*T.x*u.x+(T.x*T.y-T.z)*u.y+(T.x*T.z+T.y)*u.z,(T.x*T.y+T.z)*u.x+T.y*T.y*u.y+(T.y*T.z-T.x)*u.z,(T.x*T.z-T.y)*u.x+(T.y*T.z+T.x)*u.y+T.z*T.z*u.z,y);b=t.normalize(b,b);var x=t.multiplyByScalar(b,w,y);T=t.normalize(t.subtract(t.add(g,x,E),s,E),E);var P=t.dot(r,T);T=t.normalize(t.subtract(t.subtract(g,x,T),s,T),T);var A=t.dot(r,T);return A>P?P:A},c}),r("Core/Packable",["./DeveloperError"],function(e){"use strict";var t={packedLength:void 0,pack:e.throwInstantiationError,unpack:e.throwInstantiationError};return t}),r("Core/PackableForInterpolation",["./DeveloperError"],function(e){"use strict";var t={packedInterpolationLength:void 0,convertPackedArrayForInterpolation:e.throwInstantiationError,unpackInterpolationResult:e.throwInstantiationError};return t}),r("ThirdParty/measureText",[],function(){var e=function(e,t){return document.defaultView.getComputedStyle(e,null).getPropertyValue(t)},t=function(t,r,i,n){var o=t.measureText(r),a=e(t.canvas,"font-family"),s=e(t.canvas,"font-size").replace("px",""),l=!/\S/.test(r);o.fontsize=s;var u=document.createElement("div");u.style.position="absolute",u.style.opacity=0,u.style.font=s+"px "+a,u.innerHTML=r+"
"+r,document.body.appendChild(u),o.leading=1.2*s;var c=e(u,"height");if(c=c.replace("px",""),c>=2*s&&(o.leading=c/2|0),document.body.removeChild(u),l)o.ascent=0,o.descent=0,o.bounds={minx:0,maxx:o.width,miny:0,maxy:0},o.height=0;else{var h=document.createElement("canvas"),d=100;h.width=o.width+d,h.height=3*s,h.style.opacity=1,h.style.fontFamily=a,h.style.fontSize=s;var p=h.getContext("2d");p.font=s+"px "+a;var m=h.width,f=h.height,v=f/2;p.fillStyle="white",p.fillRect(-1,-1,m+2,f+2),i&&(p.strokeStyle="black",p.lineWidth=t.lineWidth,p.strokeText(r,d/2,v)),n&&(p.fillStyle="black",p.fillText(r,d/2,v));for(var _=p.getImageData(0,0,m,f).data,g=0,y=4*m,C=_.length;++g0&&255===_[g];);var S=g/y|0;for(g=0;C>g&&255===_[g];)g+=y,g>=C&&(g=g-C+4);var w=g%y/4|0,T=1;for(g=C-3;g>=0&&255===_[g];)g-=y,0>g&&(g=C-3-4*T++);var b=g%y/4+1|0;o.ascent=v-E,o.descent=S-v,o.bounds={minx:w-d/2,maxx:b-d/2,miny:0,maxy:S-E},o.height=1+(S-E)}return o};return t}),r("Core/writeTextToCanvas",["../ThirdParty/measureText","./Color","./defaultValue","./defined","./DeveloperError"],function(e,t,r,i,n){"use strict";var o,a=function(n,a){if(""===n)return void 0;a=r(a,r.EMPTY_OBJECT);var s=r(a.font,"10px sans-serif"),l=r(a.stroke,!1),u=r(a.fill,!0),c=r(a.strokeWidth,1),h=document.createElement("canvas");h.width=1,h.height=1,h.style.font=s;var d=h.getContext("2d");i(o)||(i(d.imageSmoothingEnabled)?o="imageSmoothingEnabled":i(d.mozImageSmoothingEnabled)?o="mozImageSmoothingEnabled":i(d.webkitImageSmoothingEnabled)?o="webkitImageSmoothingEnabled":i(d.msImageSmoothingEnabled)&&(o="msImageSmoothingEnabled")),d.font=s,d.lineJoin="round",d.lineWidth=c,d[o]=!1,d.textBaseline=r(a.textBaseline,"bottom"),h.style.visibility="hidden",document.body.appendChild(h);var p=e(d,n,l,u);p.computedWidth=Math.max(p.width,p.bounds.maxx-p.bounds.minx),h.dimensions=p,document.body.removeChild(h),h.style.visibility="";var m=p.height-p.ascent;h.width=p.computedWidth,h.height=p.height;var f=h.height-m;if(d.font=s,d.lineJoin="round",d.lineWidth=c,d[o]=!1,l){var v=r(a.strokeColor,t.BLACK);d.strokeStyle=v.toCssColorString(),d.strokeText(n,0,f)}if(u){var _=r(a.fillColor,t.WHITE);d.fillStyle=_.toCssColorString(),d.fillText(n,0,f)}return h};return a}),r("Core/PinBuilder",["./buildModuleUrl","./Color","./defined","./DeveloperError","./loadImage","./writeTextToCanvas"],function(e,t,r,i,n,o){"use strict";function a(e,t,r){e.save(),e.scale(r/24,r/24),e.fillStyle=t.toCssColorString(),e.strokeStyle=t.brighten(.6,c).toCssColorString(),e.lineWidth=.846,e.beginPath(),e.moveTo(6.72,.422),e.lineTo(17.28,.422),e.bezierCurveTo(18.553,.422,19.577,1.758,19.577,3.415),e.lineTo(19.577,10.973),e.bezierCurveTo(19.577,12.63,18.553,13.966,17.282,13.966),e.lineTo(14.386,14.008),e.lineTo(11.826,23.578),e.lineTo(9.614,14.008),e.lineTo(6.719,13.965),e.bezierCurveTo(5.446,13.983,4.422,12.629,4.422,10.972),e.lineTo(4.422,3.416),e.bezierCurveTo(4.423,1.76,5.447,.423,6.718,.423),e.closePath(),e.fill(),e.stroke(),e.restore()}function s(e,r,i){var n=i/2.5,o=n,a=n;r.width>r.height?a=n*(r.height/r.width):r.width0&&r.y>0&&r.z>0};return i}),r("Core/Queue",["../Core/defineProperties"],function(e){"use strict";var t=function(){this._array=[],this._offset=0,this._length=0};return e(t.prototype,{length:{get:function(){return this._length}}}),t.prototype.enqueue=function(e){this._array.push(e),this._length++},t.prototype.dequeue=function(){if(0===this._length)return void 0;var e=this._array,t=this._offset,r=e[t];return e[t]=void 0,t++,t>10&&2*t>e.length&&(this._array=e.slice(t),t=0),this._offset=t,this._length--,r},t.prototype.peek=function(){return 0===this._length?void 0:this._array[this._offset]},t.prototype.contains=function(e){return-1!==this._array.indexOf(e)},t.prototype.clear=function(){this._array.length=this._offset=this._length=0},t.prototype.sort=function(e){this._offset>0&&(this._array=this._array.slice(this._offset),this._offset=0),this._array.sort(e)},t}),r("Core/WindingOrder",["../Renderer/WebGLConstants","./freezeObject"],function(e,t){"use strict";var r={CLOCKWISE:e.CW,COUNTER_CLOCKWISE:e.CCW,validate:function(e){return e===r.CLOCKWISE||e===r.COUNTER_CLOCKWISE}};return t(r)}),r("Core/PolygonPipeline",["./Cartesian2","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./Math","./pointInsideTriangle","./PolylinePipeline","./PrimitiveType","./Queue","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(t,r,i){var n=e.subtract(r,t,F),o=e.subtract(i,r,B);return n.x*o.y-n.y*o.x>=0}function _(e){for(var t=e[0].x,r=0,i=0;it&&(t=e[i].x,r=i);return r}function g(e){for(var t=e[0][0].x,r=0,i=0;it&&(t=n,r=i)}return r}function y(e){for(var t=[],r=0;rc&&(c=n[h].x);c+=c-u;var d=new t(c,r.y,0);for(h=0;h=r.x||m.x>=r.x)&&(p.y>=r.y&&m.y<=r.y||p.y<=r.y&&m.y>=r.y)){var f=(m.y-p.y)*(d.x-r.x)-(m.x-p.x)*(d.y-r.y);if(0!==f){f=1/f;var v=((m.x-p.x)*(r.y-p.y)-(m.y-p.y)*(r.x-p.x))*f,g=((d.x-r.x)*(r.y-p.y)-(d.y-r.y)*(r.x-p.x))*f;if(v>=0&&1>=v&&g>=0&&1>=g){var y=new e(r.x+v*(d.x-r.x),r.y+v*(d.y-r.y)),C=e.subtract(y,r,V);f=e.magnitudeSquared(C),a>f&&(l=y,a=f,o[0]=h,o[1]=(h+1)%n.length)}}}}return l}function S(t,r){var i=g(r),n=r[i],o=_(n),a=n[o],s=[],l=E(a,t,s),u=C(t,l);if(-1!==u)return u;var d=e.magnitudeSquared(e.subtract(t[s[0]],a,z)),p=e.magnitudeSquared(e.subtract(t[s[1]],a,z)),m=p>d?t[s[0]]:t[s[1]],f=y(t),v=f.indexOf(m);-1!==v&&f.splice(v,1);for(var S=[],w=0;w0){var x=e.fromElements(1,0,z);for(w=0;wI&&(b=I,m=S[w])}}}return t.indexOf(m)}function w(e,r,i){for(var n=ee.computeWindingOrder2D(e),o=0;of?0>p&&m>0?U:G:f>0?p>0&&0>m?G:U:void 0}function M(e,t,r){return(e>t||e>r)&&(t>e||r>e)||t===r&&t===e}function D(t,r,i,n){var o=e.subtract(i,t,Y),a=r.x*n.y-r.y*n.x,s=a*a,l=e.magnitudeSquared(r),u=e.magnitudeSquared(n);if(s>j*l*u){var c=(o.x*n.y-o.y*n.x)/a;return e.add(t,e.multiplyByScalar(r,c,Y),Y)}return void 0}function R(t,r,i){for(var o=e.subtract(r,t,X),a=i.length,s=0;a>s;s++){var l=i[s].position,u=i[c.mod(s+1,a)].position;if(!(e.equals(t,l)||e.equals(r,u)||e.equals(t,u)||e.equals(r,l))){var h=e.subtract(u,l,Z),d=D(t,o,l,h);if(n(d)&&!(e.equals(d,t)||e.equals(d,r)||e.equals(d,l)||e.equals(d,u))){var p=d.x,m=d.y,f=M(p,t.x,r.x)&&M(m,t.y,r.y)&&M(p,l.x,u.x)&&M(m,l.y,u.y);if(f)return!0}}}return!1}function O(t,r,i){var n=I(t,r,i);if(n>=0)return n;var o=I(r,t,i);return o>=0?o:n!==U||o!==U||R(i[t].position,i[r].position,i)||e.equals(i[t].position,i[r].position)?J:K}function N(e){return 0===b(1,2,0,e)}function L(e){var t=e.length;if(3===t)return N(e)?[]:[e[0].index,e[1].index,e[2].index];if(e.length<3)throw new o("Invalid polygon: must have at least three vertices.");for(var r,i,n=0,a=10*e.length,s=J;K>s&&n++e.length-2;)i=T(e.length);if(r>i){var l=r;r=i,i=l}s=O(r,i,e)}if(s===K){var u=e.splice(r,i-r+1,e[r],e[i]);return L(e).concat(L(u))}return s>=0?(e.splice(s,1),L(e)):[]}var F=new e,B=new e,V=new e,z=new e(1,0),k=new e,U=-1,G=-2,W=new t,H=new t,q=new t,j=c.EPSILON14,Y=new e,X=(new e,new e),Z=new e,K=-1,J=-2,Q=new t,$=new t,ee={};ee.removeDuplicates=function(e){var r=d.removeDuplicates(e);return t.equals(r[0],r[r.length-1])?r.slice(1):r},ee.computeArea2D=function(e){for(var t=e.length,r=0,i=t-1,n=0;t>n;i=n++){var o=e[i],a=e[n];r+=o.x*a.y-a.x*o.y}return.5*r},ee.computeWindingOrder2D=function(e){var t=ee.computeArea2D(e);return t>0?f.COUNTER_CLOCKWISE:f.CLOCKWISE},ee.triangulate=function(e){for(var t=e.length,r=[],i=0;t>i;++i)r[i]={position:e[i],index:i};return L(r)};var te=new t,re=new t,ie=new t,ne=new t,oe=new t,ae=new t,se=new t;return ee.computeSubdivision=function(e,o,a,s){s=i(s,c.RADIANS_PER_DEGREE);var h,d=a.slice(0),m=o.length,f=new Array(3*m),v=0;for(h=0;m>h;h++){var _=o[h];f[v++]=_.x,f[v++]=_.y,f[v++]=_.z}for(var g=[],y={},C=e.maximumRadius,E=c.chordLength(s,C),S=E*E;d.length>0;){var w,T,b=d.pop(),x=d.pop(),P=d.pop(),A=t.fromArray(f,3*P,te),I=t.fromArray(f,3*x,re),M=t.fromArray(f,3*b,ie),D=t.multiplyByScalar(t.normalize(A,ne),C,ne),R=t.multiplyByScalar(t.normalize(I,oe),C,oe),O=t.multiplyByScalar(t.normalize(M,ae),C,ae),N=t.magnitudeSquared(t.subtract(D,R,se)),L=t.magnitudeSquared(t.subtract(R,O,se)),F=t.magnitudeSquared(t.subtract(O,D,se)),B=Math.max(N,L,F);B>S?N===B?(w=Math.min(P,x)+" "+Math.max(P,x),h=y[w],n(h)||(T=t.add(A,I,se),t.multiplyByScalar(T,.5,T),f.push(T.x,T.y,T.z),h=f.length/3-1,y[w]=h),d.push(P,h,b),d.push(h,x,b)):L===B?(w=Math.min(x,b)+" "+Math.max(x,b),h=y[w],n(h)||(T=t.add(I,M,se),t.multiplyByScalar(T,.5,T),f.push(T.x,T.y,T.z),h=f.length/3-1,y[w]=h),d.push(x,h,P),d.push(h,b,P)):F===B&&(w=Math.min(b,P)+" "+Math.max(b,P),h=y[w],n(h)||(T=t.add(M,A,se),t.multiplyByScalar(T,.5,T),f.push(T.x,T.y,T.z),h=f.length/3-1,y[w]=h),d.push(b,h,x),d.push(h,P,x)):(g.push(P),g.push(x),g.push(b))}return new l({attributes:{position:new u({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:f})},indices:g,primitiveType:p.TRIANGLES})},ee.scaleToGeodeticHeight=function(e,r,o,s){o=i(o,a.WGS84);var l=Q,u=$;if(r=i(r,0),s=i(s,!0),n(e)&&n(e.attributes)&&n(e.attributes.position))for(var c=e.attributes.position.values,h=c.length,d=0;h>d;d+=3)t.fromArray(c,d,u),s&&(u=o.scaleToGeodeticSurface(u,u)),l=o.geodeticSurfaceNormal(u,l),t.multiplyByScalar(l,r,l),t.add(u,l,u),c[d]=u.x,c[d+1]=u.y,c[d+2]=u.z;return e},ee.eliminateHoles=function(e,r,n){n=i(n,a.WGS84);for(var o=[],s=0;s0;)c=w(c,o,n);return c},ee}),r("Core/PolygonGeometryLibrary",["./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolygonPipeline","./PrimitiveType","./Queue","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(t,r,i,n){return e.subtract(r,t,_),e.multiplyByScalar(_,i/n,_),e.add(t,_,_),[_.x,_.y,_.z]}var v={};v.computeHierarchyPackedLength=function(t){for(var r=0,n=[t];n.length>0;){var o=n.pop();if(i(o)){r+=2;var a=o.positions,s=o.holes;if(i(a)&&(r+=a.length*e.packedLength),i(s))for(var l=s.length,u=0;l>u;++u)n.push(s[u])}}return r},v.packPolygonHierarchy=function(t,r,n){for(var o=[t];o.length>0;){var a=o.pop();if(i(a)){var s=a.positions,l=a.holes;if(r[n++]=i(s)?s.length:0,r[n++]=i(l)?l.length:0,i(s))for(var u=s.length,c=0;u>c;++c,n+=3)e.pack(s[c],r,n);if(i(l))for(var h=l.length,d=0;h>d;++d)o.push(l[d])}}return n},v.unpackPolygonHierarchy=function(t,r){for(var i=t[r++],n=t[r++],o=new Array(i),a=n>0?new Array(n):void 0,s=0;i>s;++s,r+=e.packedLength)o[s]=e.unpack(t,r);for(var l=0;n>l;++l)a[l]=v.unpackPolygonHierarchy(t,r),r=a[l].startingIndex,delete a[l].startingIndex;return{positions:o,holes:a,startingIndex:r}};var _=new e;v.subdivideLineCount=function(t,r,i){var n=e.distance(t,r),o=n/i,a=Math.max(0,Math.ceil(Math.log(o)/Math.log(2)));return Math.pow(2,a)},v.subdivideLine=function(t,r,n,o){var a=v.subdivideLineCount(t,r,n),s=e.distance(t,r),l=s/a;i(o)||(o=[]);var u=o;u.length=3*a;for(var c=0,h=0;a>h;h++){var d=f(t,r,h*l,s);u[c++]=d[0],u[c++]=d[1],u[c++]=d[2]}return u};var g=new e,y=new e,C=new e,E=new e;v.scaleToGeodeticHeightExtruded=function(t,o,a,s,l){s=r(s,n.WGS84);var u=g,c=y,h=C,d=E;if(i(t)&&i(t.attributes)&&i(t.attributes.position))for(var p=t.attributes.position.values,m=p.length/2,f=0;m>f;f+=3)e.fromArray(p,f,h),s.geodeticSurfaceNormal(h,u),d=s.scaleToGeodeticSurface(h,d),c=e.multiplyByScalar(u,a,c),c=e.add(d,c,c),p[f+m]=c.x,p[f+1+m]=c.y,p[f+2+m]=c.z,l&&(d=e.clone(h,d)),c=e.multiplyByScalar(u,o,c),c=e.add(d,c,c),p[f]=c.x,p[f+1]=c.y,p[f+2]=c.z;return t},v.polygonsFromHierarchy=function(e){var t=[],r=[],n=new p;for(n.enqueue(e);0!==n.length;){var o=n.dequeue(),a=o.positions,s=o.holes;if(a=h.removeDuplicates(a),!(a.length<3)){for(var l=i(s)?s.length:0,u=[],c=0;l>c;c++){var d=s[c];if(d.positions=h.removeDuplicates(d.positions),!(d.positions.length<3)){u.push(d.positions);var m=0;i(d.holes)&&(m=d.holes.length);for(var f=0;m>f;f++)n.enqueue(d.holes[f])}}r.push({outerRing:a,holes:u});var v=u.length>0?h.eliminateHoles(a,u):a;t.push(v)}}return{hierarchy:r,polygons:t}};var S=[];v.createGeometryFromPositions=function(e,r,i,n){var l=o.fromPoints(r,e),u=l.projectPointsOntoPlane(r,S),c=h.computeWindingOrder2D(u);c===m.CLOCKWISE&&(u.reverse(),r=r.slice().reverse());var p=h.triangulate(u);if(p.length<3&&(p=[0,1,2]),n){for(var f=r.length,v=new Array(3*f),_=0,g=0;f>g;g++){var y=r[g];v[_++]=y.x,v[_++]=y.y,v[_++]=y.z}return new a({attributes:{position:new s({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:v})},indices:p,primitiveType:d.TRIANGLES})}return h.computeSubdivision(e,r,p,i)};var w=[],T=new e,b=new e;return v.computeWallGeometry=function(r,i,n,o){var h,p,m,f,_,g=r.length,y=0;if(o)for(p=3*g*2,h=new Array(2*p),m=0;g>m;m++)f=r[m],_=r[(m+1)%g],h[y]=h[y+p]=f.x,++y,h[y]=h[y+p]=f.y,++y,h[y]=h[y+p]=f.z,++y,h[y]=h[y+p]=_.x,++y,h[y]=h[y+p]=_.y,++y,h[y]=h[y+p]=_.z,++y;else{var C=c.chordLength(n,i.maximumRadius),E=0;for(m=0;g>m;m++)E+=v.subdivideLineCount(r[m],r[(m+1)%g],C);for(p=3*(E+g),h=new Array(2*p),m=0;g>m;m++){f=r[m],_=r[(m+1)%g];for(var S=v.subdivideLine(f,_,C,w),x=S.length,P=0;x>P;++P,++y)h[y]=S[P],h[y+p]=S[P];h[y]=_.x,h[y+p]=_.x,++y,h[y]=_.y,h[y+p]=_.y,++y,h[y]=_.z,h[y+p]=_.z,++y}}g=h.length;var A=u.createTypedArray(g/3,g-6*r.length),I=0;for(g/=6,m=0;g>m;m++){var M=m,D=M+1,R=M+g,O=R+1;f=e.fromArray(h,3*M,T),_=e.fromArray(h,3*D,b),e.equalsEpsilon(f,_,c.EPSILON14)||(A[I++]=M,A[I++]=R,A[I++]=D,A[I++]=D,A[I++]=R,A[I++]=O)}return new a({attributes:new l({position:new s({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:h})}),indices:A,primitiveType:d.TRIANGLES})},v}),r("Core/PolygonGeometry",["./BoundingRectangle","./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./Matrix3","./PolygonGeometryLibrary","./PolygonPipeline","./Quaternion","./VertexFormat","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";function w(e,t,r,n){for(var o=C.fromAxisAngle(e._plane.normal,r,A),s=_.fromQuaternion(o,I),l=Number.POSITIVE_INFINITY,u=Number.NEGATIVE_INFINITY,c=Number.POSITIVE_INFINITY,h=Number.NEGATIVE_INFINITY,d=t.length,p=0;d>p;++p){var m=i.clone(t[p],P);_.multiplyByVector(s,m,m);var f=e.projectPointOntoPlane(m,x);a(f)&&(l=Math.min(l,f.x),u=Math.max(u,f.x),c=Math.min(c,f.y),h=Math.max(h,f.y))}return n.x=l,n.y=c,n.width=u-l,n.height=h-c,n}function T(e,t,o,a,s,l,c){if(e.st||e.normal||e.tangent||e.binormal){var d=u.fromPoints(o,a),p=w(d,o,s,M),m=B;m.x=p.x,m.y=p.y;var f=t.attributes.position.values,g=f.length,y=e.st?new Float32Array(2*(g/3)):void 0,E=e.normal?new Float32Array(g):void 0,S=e.tangent?new Float32Array(g):void 0,T=e.binormal?new Float32Array(g):void 0,b=0,x=0,P=R,A=O,I=N,G=!0,W=C.fromAxisAngle(d._plane.normal,s,k),H=_.fromQuaternion(W,U),q=g/2,j=g/3;l&&(g/=2);for(var Y=0;g>Y;Y+=3){var X=i.fromArray(f,Y,z);if(e.st){var Z=_.multiplyByVector(H,X,D),K=d.projectPointOntoPlane(Z,V);r.subtract(K,m,K),l&&(y[b+j]=K.x/p.width,y[b+1+j]=K.y/p.height),y[b]=K.x/p.width,y[b+1]=K.y/p.height,b+=2}if(e.normal||e.tangent||e.binormal){var J=x+1,Q=x+2;if(c){if(g>Y+3){var $=i.fromArray(f,Y+3,L);if(G){var ee=i.fromArray(f,Y+g,F);i.subtract($,X,$), +i.subtract(ee,X,ee),P=i.normalize(i.cross(ee,$,P),P),G=!1}i.equalsEpsilon($,X,v.EPSILON10)&&(G=!0)}(e.tangent||e.binormal)&&(I=a.geodeticSurfaceNormal(X,I),e.tangent&&(A=i.normalize(i.cross(I,P,A),A)))}else P=a.geodeticSurfaceNormal(X,P),(e.tangent||e.binormal)&&(A=i.cross(i.UNIT_Z,P,A),A=i.normalize(_.multiplyByVector(H,A,A),A),e.binormal&&(I=i.normalize(i.cross(P,A,I),I)));e.normal&&(l&&!c?(E[x+q]=-P.x,E[J+q]=-P.y,E[Q+q]=-P.z):(E[x+q]=P.x,E[J+q]=P.y,E[Q+q]=P.z),E[x]=P.x,E[J]=P.y,E[Q]=P.z),e.tangent&&(l&&!c?(S[x+q]=-A.x,S[J+q]=-A.y,S[Q+q]=-A.z):(S[x+q]=A.x,S[J+q]=A.y,S[Q+q]=A.z),S[x]=A.x,S[J]=A.y,S[Q]=A.z),e.binormal&&(l&&(T[x+q]=I.x,T[J+q]=I.y,T[Q+q]=I.z),T[x]=I.x,T[J]=I.y,T[Q]=I.z),x+=3}}e.st&&(t.attributes.st=new h({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:y})),e.normal&&(t.attributes.normal=new h({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:E})),e.tangent&&(t.attributes.tangent=new h({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:S})),e.binormal&&(t.attributes.binormal=new h({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:T}))}return t}function b(e,t,r,i,o){var a=g.createGeometryFromPositions(e,t,r,o),s=a.attributes.position.values,l=a.indices,m=s.concat(s),v=m.length/3,_=f.createTypedArray(v,2*l.length);_.set(l);var C,E=l.length,w=v/2;for(C=0;E>C;C+=3){var T=_[C]+w,b=_[C+1]+w,x=_[C+2]+w;_[C+E]=x,_[C+1+E]=b,_[C+2+E]=T}var P=new c({attributes:new d({position:new h({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:m})}),indices:_,primitiveType:a.primitiveType}),A={topAndBottom:new p({geometry:P}),walls:[]},I=i.outerRing,M=u.fromPoints(I,e),D=M.projectPointsOntoPlane(I,G),R=y.computeWindingOrder2D(D);R===S.CLOCKWISE&&(I=I.slice().reverse());var O=g.computeWallGeometry(I,e,r,o);A.walls.push(new p({geometry:O}));var N=i.holes;for(C=0;Cy;y++){var T=r[y],b=r[(y+1)%C];_[w++]=T.x,_[w++]=T.y,_[w++]=T.z,_[w++]=b.x,_[w++]=b.y,_[w++]=b.z}else{var x=0;for(y=0;C>y;y++)x+=m.subdivideLineCount(r[y],r[(y+1)%C],i);for(_=new Float64Array(3*x),y=0;C>y;y++)for(var P=m.subdivideLine(r[y],r[(y+1)%C],i,S),A=P.length,I=0;A>I;++I)_[w++]=P[I]}C=_.length/3;var M=2*C,D=d.createTypedArray(C,M);for(w=0,y=0;C-1>y;y++)D[w++]=y,D[w++]=y+1;return D[w++]=C-1,D[w++]=0,new c({geometry:new s({attributes:new u({position:new l({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:_})}),indices:D,primitiveType:v.LINES})})}function C(e,r,i,n){var o=a.fromPoints(r,e),h=o.projectPointsOntoPlane(r,E),p=f.computeWindingOrder2D(h);p===g.CLOCKWISE&&(h.reverse(),r=r.slice().reverse());var _,y,C=r.length,w=new Array(C),T=0;if(n)for(_=new Float64Array(2*C*3*2),y=0;C>y;++y){w[y]=T/3;var b=r[y],x=r[(y+1)%C];_[T++]=b.x,_[T++]=b.y,_[T++]=b.z,_[T++]=x.x,_[T++]=x.y,_[T++]=x.z}else{var P=0;for(y=0;C>y;y++)P+=m.subdivideLineCount(r[y],r[(y+1)%C],i);for(_=new Float64Array(3*P*2),y=0;C>y;++y){w[y]=T/3;for(var A=m.subdivideLine(r[y],r[(y+1)%C],i,S),I=A.length,M=0;I>M;++M)_[T++]=A[M]}}C=_.length/6;var D=w.length,R=2*(2*C+D),O=d.createTypedArray(C,R);for(T=0,y=0;C>y;++y)O[T++]=y,O[T++]=(y+1)%C,O[T++]=y+C,O[T++]=(y+1)%C+C;for(y=0;D>y;y++){var N=w[y];O[T++]=N,O[T++]=N+C}return new c({geometry:new s({attributes:new u({position:new l({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:_})}),indices:O,primitiveType:v.LINES})})}var E=[],S=[],w=function(e){var t=e.polygonHierarchy,n=r(e.ellipsoid,o.WGS84),a=r(e.granularity,p.RADIANS_PER_DEGREE),s=r(e.height,0),l=r(e.perPositionHeight,!1),u=e.extrudedHeight,c=i(u);if(c&&!l){var h=u;u=Math.min(h,s),s=Math.max(h,s)}this._ellipsoid=o.clone(n),this._granularity=a,this._height=s,this._extrudedHeight=r(u,0),this._extrude=c,this._polygonHierarchy=t,this._perPositionHeight=l,this._workerName="createPolygonOutlineGeometry",this.packedLength=m.computeHierarchyPackedLength(t)+o.packedLength+6};w.pack=function(e,t,i){i=r(i,0),i=m.packPolygonHierarchy(e._polygonHierarchy,t,i),o.pack(e._ellipsoid,t,i),i+=o.packedLength,t[i++]=e._height,t[i++]=e._extrudedHeight,t[i++]=e._granularity,t[i++]=e._extrude?1:0,t[i++]=e._perPositionHeight?1:0,t[i++]=e.packedLength};var T=o.clone(o.UNIT_SPHERE),b={polygonHierarchy:{}};return w.unpack=function(e,t,n){t=r(t,0);var a=m.unpackPolygonHierarchy(e,t);t=a.startingIndex,delete a.startingIndex;var s=o.unpack(e,t,T);t+=o.packedLength;var l=e[t++],u=e[t++],c=e[t++],h=1===e[t++],d=1===e[t++],p=e[t++];return i(n)||(n=new w(b)),n._polygonHierarchy=a,n._ellipsoid=o.clone(s,n._ellipsoid),n._height=l,n._extrudedHeight=u,n._granularity=c,n._extrude=h,n._perPositionHeight=d,n.packedLength=p,n},w.fromPositions=function(e){e=r(e,r.EMPTY_OBJECT);var t={polygonHierarchy:{positions:e.positions},height:e.height,extrudedHeight:e.extrudedHeight,ellipsoid:e.ellipsoid,granularity:e.granularity,perPositionHeight:e.perPositionHeight};return new w(t)},w.createGeometry=function(t){var r=t._ellipsoid,n=t._granularity,o=t._height,a=t._extrudedHeight,l=t._extrude,u=t._polygonHierarchy,c=t._perPositionHeight,d=[],v=new _;v.enqueue(u);for(var g;0!==v.length;){var E=v.dequeue(),S=E.positions;if(S=f.removeDuplicates(S),!(S.length<3)){var w=E.holes?E.holes.length:0;for(g=0;w>g;g++){var T=E.holes[g];if(T.positions=f.removeDuplicates(T.positions),!(T.positions.length<3)){d.push(T.positions);var b=0;i(T.holes)&&(b=T.holes.length);for(var x=0;b>x;x++)v.enqueue(T.holes[x])}}d.push(S)}}if(0===d.length)return void 0;var P,A=[],I=p.chordLength(n,r.maximumRadius);if(l)for(g=0;gs;s++)a[s]=r.clone(i);return a}var v=(d-l)/o,_=(p-u)/o,y=(m-c)/o,C=(f-h)/o;for(s=0;o>s;s++)a[s]=new r(l+s*v,u+s*_,c+s*y,h+s*C);return a}var g=[],y=function(e){e=n(e,n.EMPTY_OBJECT);var i=e.positions,a=e.colors,l=n(e.width,1),u=n(e.colorsPerVertex,!1);this._positions=i,this._colors=a,this._width=l,this._colorsPerVertex=u,this._vertexFormat=v.clone(n(e.vertexFormat,v.DEFAULT)),this._followSurface=n(e.followSurface,!0),this._granularity=n(e.granularity,p.RADIANS_PER_DEGREE),this._ellipsoid=s.clone(n(e.ellipsoid,s.WGS84)),this._workerName="createPolylineGeometry";var c=1+i.length*t.packedLength;c+=o(a)?1+a.length*r.packedLength:1,this.packedLength=c+s.packedLength+v.packedLength+4};y.pack=function(e,i,a){a=n(a,0);var l,u=e._positions,c=u.length;for(i[a++]=c,l=0;c>l;++l,a+=t.packedLength)t.pack(u[l],i,a);var h=e._colors;for(c=o(h)?h.length:0,i[a++]=c,l=0;c>l;++l,a+=r.packedLength)r.pack(h[l],i,a);s.pack(e._ellipsoid,i,a),a+=s.packedLength,v.pack(e._vertexFormat,i,a),a+=v.packedLength,i[a++]=e._width,i[a++]=e._colorsPerVertex?1:0,i[a++]=e._followSurface?1:0,i[a]=e._granularity};var C=s.clone(s.UNIT_SPHERE),E=new v,S={positions:void 0,colors:void 0,ellipsoid:C,vertexFormat:E,width:void 0,colorsPerVertex:void 0,followSurface:void 0,granularity:void 0};y.unpack=function(e,i,a){i=n(i,0);var l,u=e[i++],c=new Array(u);for(l=0;u>l;++l,i+=t.packedLength)c[l]=t.unpack(e,i);u=e[i++];var h=u>0?new Array(u):void 0;for(l=0;u>l;++l,i+=r.packedLength)h[l]=r.unpack(e,i);var d=s.unpack(e,i,C);i+=s.packedLength;var p=v.unpack(e,i,E);i+=v.packedLength;var m=e[i++],f=1===e[i++],_=1===e[i++],g=e[i];return o(a)?(a._positions=c,a._colors=h,a._ellipsoid=s.clone(d,a._ellipsoid),a._vertexFormat=v.clone(p,a._vertexFormat),a._width=m,a._colorsPerVertex=f,a._followSurface=_,a._granularity=g,a):(S.positions=c,S.colors=h,S.width=m,S.colorsPerVertex=f,S.followSurface=_,S.granularity=g,new y(S))};var w=new t,T=new t,b=new t,x=new t;return y.createGeometry=function(n){var a,s,v,y=n._width,C=n._vertexFormat,E=n._colors,S=n._colorsPerVertex,P=n._followSurface,A=n._granularity,I=n._ellipsoid,M=p.chordLength(A,I.maximumRadius),D=m.removeDuplicates(n._positions),R=D.length;if(2>R)return void 0;if(P){var O=m.extractHeights(D,I);if(o(E)){var N=1;for(a=0;R-1>a;++a)N+=m.numberOfPoints(D[a],D[a+1],M);var L=new Array(N),F=0;for(a=0;R-1>a;++a){var B=D[a],V=D[a+1],z=E[a],k=m.numberOfPoints(B,V,M);if(S&&N>a){var U=E[a+1],G=_(B,V,z,U,k),W=G.length;for(s=0;W>s;++s)L[F++]=G[s]}else for(s=0;k>s;++s)L[F++]=r.clone(z)}L[F]=r.clone(E[E.length-1]),E=L,g.length=0}D=m.generateCartesianArc({positions:D,minDistance:M,ellipsoid:I,height:O})}R=D.length;var H,q=4*R-4,j=new Float64Array(3*q),Y=new Float64Array(3*q),X=new Float64Array(3*q),Z=new Float32Array(2*q),K=C.st?new Float32Array(2*q):void 0,J=o(E)?new Uint8Array(4*q):void 0,Q=0,$=0,ee=0,te=0;for(s=0;R>s;++s){0===s?(H=w,t.subtract(D[0],D[1],H),t.add(D[0],H,H)):H=D[s-1],t.clone(H,b),t.clone(D[s],T),s===R-1?(H=w,t.subtract(D[R-1],D[R-2],H),t.add(D[R-1],H,H)):H=D[s+1],t.clone(H,x);var re,ie;o(J)&&(re=0===s||S?E[s]:E[s-1],s!==R-1&&(ie=E[s]));var ne=0===s?2:0,oe=s===R-1?2:4;for(v=ne;oe>v;++v){t.pack(T,j,Q),t.pack(b,Y,Q),t.pack(x,X,Q),Q+=3;var ae=0>v-2?-1:1;if(Z[$++]=2*(v%2)-1,Z[$++]=ae*y,C.st&&(K[ee++]=s/(R-1),K[ee++]=Math.max(Z[$-2],0)),o(J)){var se=2>v?re:ie;J[te++]=r.floatToByte(se.red),J[te++]=r.floatToByte(se.green),J[te++]=r.floatToByte(se.blue),J[te++]=r.floatToByte(se.alpha)}}}var le=new c;le.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:j}),le.prevPosition=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:Y}),le.nextPosition=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:X}),le.expandAndWidth=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:Z}),C.st&&(le.st=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:K})),o(J)&&(le.color=new u({componentDatatype:i.UNSIGNED_BYTE,componentsPerAttribute:4,values:J,normalize:!0}));var ue=d.createTypedArray(q,6*R-6),ce=0,he=0,de=R-1;for(s=0;de>s;++s)ue[he++]=ce,ue[he++]=ce+2,ue[he++]=ce+1,ue[he++]=ce+1,ue[he++]=ce+2,ue[he++]=ce+3,ce+=4;return new l({attributes:le,indices:ue,primitiveType:f.TRIANGLES,boundingSphere:e.fromPoints(D),geometryType:h.POLYLINES})},y}),r("Core/PolylineVolumeGeometry",["./BoundingRectangle","./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CornerType","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryPipeline","./IndexDatatype","./Math","./PolygonPipeline","./PolylineVolumeGeometryLibrary","./PrimitiveType","./VertexFormat","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";function E(e,r,i,o){var a=new d;o.position&&(a.position=new h({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:e}));var s,l,u,f,_,y,C=r.length,E=e.length/3,S=(E-2*C)/(2*C),w=v.triangulate(r),T=(S-1)*C*6+2*w.length,b=m.createTypedArray(E,T),x=2*C,P=0;for(s=0;S-1>s;s++){for(l=0;C-1>l;l++)u=2*l+s*C*2,y=u+x,f=u+1,_=f+x,b[P++]=f,b[P++]=u,b[P++]=_,b[P++]=_,b[P++]=u,b[P++]=y;u=2*C-2+s*C*2,f=u+1,_=f+x,y=u+x,b[P++]=f,b[P++]=u,b[P++]=_,b[P++]=_,b[P++]=u,b[P++]=y}if(o.st||o.tangent||o.binormal){var A,I,M=new Float32Array(2*E),D=1/(S-1),R=1/i.height,O=i.height/2,N=0;for(s=0;S>s;s++){for(A=s*D,I=R*(r[0].y+O),M[N++]=A,M[N++]=I,l=1;C>l;l++)I=R*(r[l].y+O),M[N++]=A,M[N++]=I,M[N++]=A,M[N++]=I;I=R*(r[0].y+O),M[N++]=A,M[N++]=I}for(l=0;C>l;l++)A=0,I=R*(r[l].y+O),M[N++]=A,M[N++]=I;for(l=0;C>l;l++)A=(S-1)*D,I=R*(r[l].y+O),M[N++]=A,M[N++]=I;a.st=new h({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:new Float32Array(M)})}var L=E-2*C;for(s=0;so;++o,n+=i.packedLength)i.pack(s[o],t,n);var c=e._shape;for(l=c.length,t[n++]=l,o=0;l>o;++o,n+=r.packedLength)r.pack(c[o],t,n);u.pack(e._ellipsoid,t,n),n+=u.packedLength,y.pack(e._vertexFormat,t,n),n+=y.packedLength,t[n++]=e._cornerType,t[n]=e._granularity};var w=u.clone(u.UNIT_SPHERE),T=new y,b={polylinePositions:void 0,shapePositions:void 0,ellipsoid:w,vertexFormat:T,cornerType:void 0,granularity:void 0};S.unpack=function(e,t,n){t=a(t,0);var o,l=e[t++],c=new Array(l);for(o=0;l>o;++o,t+=i.packedLength)c[o]=i.unpack(e,t);l=e[t++];var h=new Array(l);for(o=0;l>o;++o,t+=r.packedLength)h[o]=r.unpack(e,t);var d=u.unpack(e,t,w);t+=u.packedLength;var p=y.unpack(e,t,T);t+=y.packedLength;var m=e[t++],f=e[t];return s(n)?(n._positions=c,n._shape=h,n._ellipsoid=u.clone(d,n._ellipsoid),n._vertexFormat=y.clone(p,n._vertexFormat),n._cornerType=m,n._granularity=f,n):(b.polylinePositions=c,b.shapePositions=h,b.cornerType=m,b.granularity=f,new S(b))};var x=new e;return S.createGeometry=function(t){var r=t._positions,i=_.removeDuplicatesFromPositions(r,t._ellipsoid),n=t._shape;if(n=_.removeDuplicatesFromShape(n),i.length<2||n.length<3)return void 0;v.computeWindingOrder2D(n)===C.CLOCKWISE&&n.reverse();var o=e.fromPoints(n,x),a=_.computePositions(i,n,o,t,!0);return E(a,n,o,t._vertexFormat)},S}),r("Core/PolylineVolumeOutlineGeometry",["./BoundingRectangle","./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CornerType","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolygonPipeline","./PolylineVolumeGeometryLibrary","./PrimitiveType","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g){"use strict";function y(e,r){var i=new d;i.position=new h({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:e});var o,a,s=r.length,l=i.position.values.length/3,u=e.length/3,m=u/s,f=p.createTypedArray(l,2*s*(m+1)),v=0;o=0;var g=o*s;for(a=0;s-1>a;a++)f[v++]=a+g,f[v++]=a+g+1;for(f[v++]=s-1+g,f[v++]=g,o=m-1,g=o*s,a=0;s-1>a;a++)f[v++]=a+g,f[v++]=a+g+1;for(f[v++]=s-1+g,f[v++]=g,o=0;m-1>o;o++){var y=s*o,C=y+s;for(a=0;s>a;a++)f[v++]=a+y,f[v++]=a+C}var E=new c({attributes:i,indices:p.createTypedArray(l,f),boundingSphere:t.fromVertices(e),primitiveType:_.LINES});return E}var C=function(e){e=a(e,a.EMPTY_OBJECT);var t=e.polylinePositions,n=e.shapePositions;this._positions=t,this._shape=n,this._ellipsoid=u.clone(a(e.ellipsoid,u.WGS84)),this._cornerType=a(e.cornerType,o.ROUNDED),this._granularity=a(e.granularity,m.RADIANS_PER_DEGREE),this._workerName="createPolylineVolumeOutlineGeometry";var s=1+t.length*i.packedLength;s+=1+n.length*r.packedLength,this.packedLength=s+u.packedLength+2};C.pack=function(e,t,n){n=a(n,0);var o,s=e._positions,l=s.length;for(t[n++]=l,o=0;l>o;++o,n+=i.packedLength)i.pack(s[o],t,n);var c=e._shape;for(l=c.length,t[n++]=l,o=0;l>o;++o,n+=r.packedLength)r.pack(c[o],t,n);u.pack(e._ellipsoid,t,n),n+=u.packedLength,t[n++]=e._cornerType,t[n]=e._granularity};var E=u.clone(u.UNIT_SPHERE),S={polylinePositions:void 0,shapePositions:void 0,ellipsoid:E,height:void 0,cornerType:void 0,granularity:void 0};C.unpack=function(e,t,n){t=a(t,0);var o,l=e[t++],c=new Array(l);for(o=0;l>o;++o,t+=i.packedLength)c[o]=i.unpack(e,t);l=e[t++];var h=new Array(l);for(o=0;l>o;++o,t+=r.packedLength)h[o]=r.unpack(e,t);var d=u.unpack(e,t,E);t+=u.packedLength;var p=e[t++],m=e[t];return s(n)?(n._positions=c,n._shape=h,n._ellipsoid=u.clone(d,n._ellipsoid),n._cornerType=p,n._granularity=m,n):(S.polylinePositions=c,S.shapePositions=h,S.cornerType=p,S.granularity=m,new C(S))};var w=new e;return C.createGeometry=function(t){var r=t._positions,i=v.removeDuplicatesFromPositions(r,t._ellipsoid),n=t._shape;if(n=v.removeDuplicatesFromShape(n),i.length<2||n.length<3)return void 0;f.computeWindingOrder2D(n)===g.CLOCKWISE&&n.reverse();var o=e.fromPoints(n,w),a=v.computePositions(i,n,o,t,!1);return y(a,n)},C}),r("Core/QuaternionSpline",["./defaultValue","./defined","./defineProperties","./DeveloperError","./Quaternion","./Spline"],function(e,t,r,i,n,o){"use strict";function a(e,r,i){var o=e.length,a=new Array(o);a[0]=t(r)?r:e[0],a[o-1]=t(i)?i:e[o-1];for(var s=1;o-1>s;++s)a[s]=n.computeInnerQuadrangle(e[s-1],e[s],e[s+1],new n);return a}function s(e){var r=e.points,i=e.innerQuadrangles,o=e.times;if(r.length<3){var a=o[0],s=1/(o[1]-a),l=r[0],u=r[1];return function(e,r){t(r)||(r=new n);var i=(e-a)*s;return n.fastSlerp(l,u,i,r)}}return function(a,s){t(s)||(s=new n);var l=e._lastTimeIndex=e.findTimeInterval(a,e._lastTimeIndex),u=(a-o[l])/(o[l+1]-o[l]),c=r[l],h=r[l+1],d=i[l],p=i[l+1];return n.fastSquad(c,h,d,p,u,s)}}var l=function(t){t=e(t,e.EMPTY_OBJECT);var r=t.points,i=t.times,n=t.firstInnerQuadrangle,o=t.lastInnerQuadrangle,l=a(r,n,o);this._times=i,this._points=r,this._innerQuadrangles=l,this._evaluateFunction=s(this),this._lastTimeIndex=0};return r(l.prototype,{times:{get:function(){return this._times}},points:{get:function(){return this._points}},innerQuadrangles:{get:function(){return this._innerQuadrangles}}}),l.prototype.findTimeInterval=o.prototype.findTimeInterval,l.prototype.evaluate=function(e,t){return this._evaluateFunction(e,t)},l}),r("Core/RectangleGeometryLibrary",["./Cartesian3","./Cartographic","./defined","./DeveloperError","./GeographicProjection","./Math","./Matrix2","./Rectangle"],function(e,t,r,i,n,o,a,s){"use strict";var l=Math.cos,u=Math.sin,c=Math.sqrt,h={};h.computePosition=function(e,t,i,n,o){var s=e.ellipsoid.radiiSquared,h=e.nwCorner,d=e.rectangle,p=h.latitude-e.granYCos*t+i*e.granXSin,m=l(p),f=u(p),v=s.z*f,_=h.longitude+t*e.granYSin+i*e.granXCos,g=m*l(_),y=m*u(_),C=s.x*g,E=s.y*y,S=c(C*g+E*y+v*f);n.x=C/S,n.y=E/S,n.z=v/S,r(e.vertexFormat)&&e.vertexFormat.st&&(o.x=(_-d.west)*e.lonScalar-.5,o.y=(p-d.south)*e.latScalar-.5,a.multiplyByVector(e.textureMatrix,o,o),o.x+=.5,o.y+=.5)};var d=new a,p=new e,m=new t,f=new e,v=new n;return h.computeOptions=function(t,n,l){var u,c,h,_,g,y=t._granularity,C=t._ellipsoid,E=t._surfaceHeight,S=t._rotation,w=t._extrudedHeight,T=n.east,b=n.west,x=n.north,P=n.south,A=x-P;b>T?(g=o.TWO_PI-b+T,u=Math.ceil(g/y)+1,c=Math.ceil(A/y)+1,h=g/(u-1),_=A/(c-1)):(g=T-b,u=Math.ceil(g/y)+1,c=Math.ceil(A/y)+1,h=g/(u-1),_=A/(c-1)),l=s.northwest(n,l);var I=s.center(n,m),M=_,D=h,R=0,O=0;if(r(S)){var N=Math.cos(S);M*=N,D*=N;var L=Math.sin(S);R=_*L,O=h*L,p=v.project(l,p),f=v.project(I,f),p=e.subtract(p,f,p);var F=a.fromRotation(S,d);p=a.multiplyByVector(F,p,p),p=e.add(p,f,p),l=v.unproject(p,l);var B=l.latitude,V=B+(u-1)*O,z=B-M*(c-1),k=B-M*(c-1)+(u-1)*O;x=Math.max(B,V,z,k),P=Math.min(B,V,z,k);var U=l.longitude,G=U+(u-1)*D,W=U+(c-1)*R,H=U+(c-1)*R+(u-1)*D;if(T=Math.max(U,G,W,H),b=Math.min(U,G,W,H),x<-o.PI_OVER_TWO||x>o.PI_OVER_TWO||P<-o.PI_OVER_TWO||P>o.PI_OVER_TWO)throw new i("Rotated extent is invalid.");n.north=x,n.south=P,n.east=T,n.west=b}return{granYCos:M,granYSin:R,granXCos:D,granXSin:O,ellipsoid:C,width:u,height:c,surfaceHeight:E,extrudedHeight:w,nwCorner:l,rectangle:n}},h}),r("Core/RectangleGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./Matrix2","./Matrix3","./PolygonPipeline","./PrimitiveType","./Quaternion","./Rectangle","./RectangleGeometryLibrary","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";function T(e,t){var r=new u({attributes:new h,primitiveType:y.TRIANGLES});return r.attributes.position=new c({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:t.positions}),e.normal&&(r.attributes.normal=new c({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:t.normals})),e.tangent&&(r.attributes.tangent=new c({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:t.tangents})),e.binormal&&(r.attributes.binormal=new c({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:t.binormals})),r}function b(e,t,i,n){for(var o=e.length,a=t.normal?new Float32Array(o):void 0,s=t.tangent?new Float32Array(o):void 0,l=t.binormal?new Float32Array(o):void 0,u=0,c=N,h=O,d=R,p=0;o>p;p+=3){var m=r.fromArray(e,p,D),f=u+1,v=u+2;(t.normal||t.tangent||t.binormal)&&(d=i.geodeticSurfaceNormal(m,d),(t.tangent||t.binormal)&&(r.cross(r.UNIT_Z,d,h),_.multiplyByVector(n,h,h),r.normalize(h,h),t.binormal&&r.normalize(r.cross(d,h,c),c)),t.normal&&(a[u]=d.x,a[f]=d.y,a[v]=d.z),t.tangent&&(s[u]=h.x,s[f]=h.y,s[v]=h.z),t.binormal&&(l[u]=c.x,l[f]=c.y,l[v]=c.z)),u+=3}return T(t,{positions:e,normals:a,tangents:s,binormals:l})}function x(e,t,i){for(var n=e.length,o=t.normal?new Float32Array(n):void 0,a=t.tangent?new Float32Array(n):void 0,s=t.binormal?new Float32Array(n):void 0,l=0,u=0,c=0,h=!0,d=N,p=O,m=R,v=0;n>v;v+=6){var _=r.fromArray(e,v,D);if(t.normal||t.tangent||t.binormal){var g=r.fromArray(e,(v+6)%n,z);if(h){var y=r.fromArray(e,(v+3)%n,k);r.subtract(g,_,g),r.subtract(y,_,y),m=r.normalize(r.cross(y,g,m),m),h=!1}r.equalsEpsilon(g,_,f.EPSILON10)&&(h=!0),(t.tangent||t.binormal)&&(d=i.geodeticSurfaceNormal(_,d),t.tangent&&(p=r.normalize(r.cross(d,m,p),p))),t.normal&&(o[l++]=m.x,o[l++]=m.y,o[l++]=m.z,o[l++]=m.x,o[l++]=m.y,o[l++]=m.z),t.tangent&&(a[u++]=p.x,a[u++]=p.y,a[u++]=p.z,a[u++]=p.x,a[u++]=p.y,a[u++]=p.z),t.binormal&&(s[c++]=d.x,s[c++]=d.y,s[c++]=d.z,s[c++]=d.x,s[c++]=d.y,s[c++]=d.z)}}return T(t,{positions:e,normals:o,tangents:a,binormals:s})}function P(e){for(var t=e.vertexFormat,r=e.ellipsoid,i=e.size,o=e.height,a=e.width,s=t.position?new Float64Array(3*i):void 0,l=t.st?new Float32Array(2*i):void 0,u=0,h=0,d=D,p=F,f=Number.MAX_VALUE,v=Number.MAX_VALUE,_=Number.MIN_VALUE,g=Number.MIN_VALUE,y=0;o>y;++y)for(var C=0;a>C;++C)S.computePosition(e,y,C,d,p),s[u++]=d.x,s[u++]=d.y,s[u++]=d.z,t.st&&(l[h++]=p.x,l[h++]=p.y,f=Math.min(f,p.x),v=Math.min(v,p.y),_=Math.max(_,p.x),g=Math.max(g,p.y));if(t.st&&(0>f||0>v||_>1||g>1))for(var E=0;EI;++I){for(var M=0;a-1>M;++M){var R=P,O=R+a,N=O+1,L=R+1;x[A++]=R,x[A++]=O,x[A++]=L,x[A++]=L,x[A++]=O,x[A++]=N,++P}++P}return w.indices=x,t.st&&(w.attributes.st=new c({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:l})),w}function A(e,t,r,i,n){return e[t++]=i[r],e[t++]=i[r+1],e[t++]=i[r+2],e[t++]=n[r],e[t++]=n[r+1],e[t++]=n[r+2],e}function I(e,t,r,i){return e[t++]=i[r],e[t++]=i[r+1],e[t++]=i[r],e[t++]=i[r+1],e}function M(e){var t,i=e.vertexFormat,o=e.surfaceHeight,a=e.extrudedHeight,s=Math.min(a,o),l=Math.max(a,o),u=e.height,h=e.width,v=e.ellipsoid,_=P(e);if(f.equalsEpsilon(s,l,f.EPSILON10))return _;_=g.scaleToGeodeticHeight(_,l,v,!1);var y=new Float64Array(_.attributes.position.values),C=y.length,E=2*C,S=new Float64Array(E);S.set(y),_=g.scaleToGeodeticHeight(_,s,v);var w=_.attributes.position.values;S.set(w,C),_.attributes.position.values=S;var T,b=i.normal?new Float32Array(E):void 0,M=i.tangent?new Float32Array(E):void 0,D=i.binormal?new Float32Array(E):void 0,R=i.st?new Float32Array(E/3*2):void 0;if(i.normal){var O=_.attributes.normal.values;for(b.set(O),t=0;C>t;t++)O[t]=-O[t];b.set(O,C),_.attributes.normal.values=b}if(i.tangent){var N=_.attributes.tangent.values;for(M.set(N),t=0;C>t;t++)N[t]=-N[t];M.set(N,C),_.attributes.tangent.values=M}if(i.binormal){var L=_.attributes.binormal.values;D.set(L),D.set(L,C),_.attributes.binormal.values=D}i.st&&(T=_.attributes.st.values,R.set(T),R.set(T,C/3*2),_.attributes.st.values=R);var F=_.indices,B=F.length,V=C/3,U=m.createTypedArray(E/3,2*B);for(U.set(F),t=0;B>t;t+=3)U[t+B]=F[t+2]+V,U[t+1+B]=F[t+1]+V,U[t+2+B]=F[t]+V;_.indices=U;var G=2*h+2*u-4,W=2*(G+4),H=new Float64Array(3*W),q=i.st?new Float32Array(2*W):void 0,j=0,Y=0,X=h*u;for(t=0;X>t;t+=h)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);for(t=X-h;X>t;t++)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);for(t=X-1;t>0;t-=h)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);for(t=h-1;t>=0;t--)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);var Z=x(H,i,v);i.st&&(Z.attributes.st=new c({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:q}));var K,J,Q,$,ee=m.createTypedArray(W,6*G);C=H.length/3;var te=0;for(t=0;C-1>t;t+=2){K=t,$=(K+2)%C;var re=r.fromArray(H,3*K,z),ie=r.fromArray(H,3*$,k);r.equalsEpsilon(re,ie,f.EPSILON10)||(J=(K+1)%C,Q=(J+2)%C,ee[te++]=K,ee[te++]=J,ee[te++]=$,ee[te++]=$,ee[te++]=J,ee[te++]=Q)}return Z.indices=ee,Z=p.combineInstances([new d({geometry:_}),new d({geometry:Z})]),Z[0]}var D=new r,R=new r,O=new r,N=new r,L=new E,F=new t,B=new e,V=new e,z=new r,k=new r,U=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.rectangle,r=o(e.granularity,f.RADIANS_PER_DEGREE),i=o(e.ellipsoid,l.WGS84),n=o(e.height,0),s=o(e.rotation,0),u=o(e.stRotation,0),c=o(e.vertexFormat,w.DEFAULT),h=e.extrudedHeight,d=a(h),p=o(e.closeTop,!0),m=o(e.closeBottom,!0);this._rectangle=t,this._granularity=r,this._ellipsoid=l.clone(i),this._surfaceHeight=n,this._rotation=s,this._stRotation=u,this._vertexFormat=w.clone(c),this._extrudedHeight=o(h,0),this._extrude=d,this._closeTop=p,this._closeBottom=m,this._workerName="createRectangleGeometry"};U.packedLength=E.packedLength+l.packedLength+w.packedLength+8,U.pack=function(e,t,r){r=o(r,0),E.pack(e._rectangle,t,r),r+=E.packedLength,l.pack(e._ellipsoid,t,r),r+=l.packedLength,w.pack(e._vertexFormat,t,r),r+=w.packedLength,t[r++]=e._granularity,t[r++]=e._surfaceHeight,t[r++]=e._rotation,t[r++]=e._stRotation,t[r++]=e._extrudedHeight,t[r++]=e._extrude?1:0,t[r++]=e._closeTop?1:0,t[r]=e._closeBottom?1:0};var G=new E,W=l.clone(l.UNIT_SPHERE),H=new w,q={rectangle:G,ellipsoid:W,vertexFormat:H,granularity:void 0,height:void 0,rotation:void 0,stRotation:void 0,extrudedHeight:void 0,closeTop:void 0,closeBottom:void 0};U.unpack=function(e,t,r){t=o(t,0);var i=E.unpack(e,t,G);t+=E.packedLength;var n=l.unpack(e,t,W);t+=l.packedLength;var s=w.unpack(e,t,H);t+=w.packedLength;var u=e[t++],c=e[t++],h=e[t++],d=e[t++],p=e[t++],m=1===e[t++],f=1===e[t++],v=1===e[t];return a(r)?(r._rectangle=E.clone(i,r._rectangle),r._ellipsoid=l.clone(n,r._ellipsoid),r._vertexFormat=w.clone(s,r._vertexFormat),r._granularity=u,r._surfaceHeight=c,r._rotation=h,r._stRotation=d,r._extrudedHeight=m?p:void 0,r._extrude=m,r._closeTop=f,r._closeBottom=v,r):(q.granularity=u,q.height=c,q.rotation=h,q.stRotation=d,q.extrudedHeight=m?p:void 0,q.closeTop=f,q.closeBottom=v,new U(q))};var j=new v,Y=new _,X=new i,Z=new C,K=new i; +return U.createGeometry=function(t){var i=E.clone(t._rectangle,L),n=t._ellipsoid,o=t._surfaceHeight,s=t._extrude,l=t._extrudedHeight,c=t._stRotation,d=t._vertexFormat,p=S.computeOptions(t,i,X),m=j,f=Y;if(a(c)){v.fromRotation(-c,m);var y=E.center(i,K),w=n.cartographicToCartesian(y,z);r.normalize(w,w),C.fromAxisAngle(w,-c,Z),_.fromQuaternion(Z,f)}else v.clone(v.IDENTITY,m),_.clone(_.IDENTITY,f);p.lonScalar=1/i.width,p.latScalar=1/i.height,p.vertexFormat=d,p.textureMatrix=m,p.tangentRotationMatrix=f,p.size=p.width*p.height;var T,b;if(i=t._rectangle,s){T=M(p);var x=e.fromRectangle3D(i,n,o,V),A=e.fromRectangle3D(i,n,l,B);b=e.union(x,A)}else T=P(p),T=g.scaleToGeodeticHeight(T,o,n,!1),b=e.fromRectangle3D(i,n,o);return d.position||delete T.attributes.position,new u({attributes:new h(T.attributes),indices:T.indices,primitiveType:T.primitiveType,boundingSphere:b})},U.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new U({rectangle:e._rectangle,rotation:e._rotation,ellipsoid:n,stRotation:e._stRotation,granularity:i,extrudedHeight:a,height:o,closeTop:!0,closeBottom:!0,vertexFormat:w.POSITION_ONLY})},U}),r("Core/RectangleOutlineGeometry",["./BoundingSphere","./Cartesian3","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolygonPipeline","./PrimitiveType","./Rectangle","./RectangleGeometryLibrary"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e){var t,r=e.size,n=e.height,o=e.width,a=new Float64Array(3*r),s=0,d=0,p=E;for(t=0;o>t;t++)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(t=o-1,d=1;n>d;d++)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(d=n-1,t=o-2;t>=0;t--)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(t=0,d=n-2;d>0;d--)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(var f=a.length/3*2,_=h.createTypedArray(a.length/3,f),g=0,y=0;yC;C++)g[y++]=C,g[y++]=C+1,g[y++]=C+c,g[y++]=C+c+1;return g[y++]=c-1,g[y++]=0,g[y++]=c+c-1,g[y++]=c,g[y++]=0,g[y++]=c,g[y++]=l-1,g[y++]=c+l-1,g[y++]=l+s-2,g[y++]=l+s-2+c,g[y++]=2*l+s-3,g[y++]=2*l+s-3+c,a.indices=g,a}var y=new e,C=new e,E=new t,S=new f,w=function(e){e=n(e,n.EMPTY_OBJECT);var t=e.rectangle,r=n(e.granularity,d.RADIANS_PER_DEGREE),i=n(e.ellipsoid,s.WGS84),o=n(e.height,0),a=n(e.rotation,0),l=e.extrudedHeight;this._rectangle=t,this._granularity=r,this._ellipsoid=i,this._surfaceHeight=o,this._rotation=a,this._extrudedHeight=l,this._workerName="createRectangleOutlineGeometry"};w.packedLength=f.packedLength+s.packedLength+5,w.pack=function(e,t,r){r=n(r,0),f.pack(e._rectangle,t,r),r+=f.packedLength,s.pack(e._ellipsoid,t,r),r+=s.packedLength,t[r++]=e._granularity,t[r++]=e._surfaceHeight,t[r++]=e._rotation,t[r++]=o(e._extrudedHeight)?1:0,t[r]=n(e._extrudedHeight,0)};var T=new f,b=s.clone(s.UNIT_SPHERE),x={rectangle:T,ellipsoid:b,granularity:void 0,height:void 0,rotation:void 0,extrudedHeight:void 0};w.unpack=function(e,t,r){t=n(t,0);var i=f.unpack(e,t,T);t+=f.packedLength;var a=s.unpack(e,t,b);t+=s.packedLength;var l=e[t++],u=e[t++],c=e[t++],h=e[t++],d=e[t];return o(r)?(r._rectangle=f.clone(i,r._rectangle),r._ellipsoid=s.clone(a,r._ellipsoid),r._surfaceHeight=u,r._rotation=c,r._extrudedHeight=h?d:void 0,r):(x.granularity=l,x.height=u,x.rotation=c,x.extrudedHeight=h?d:void 0,new w(x))};var P=new r;return w.createGeometry=function(t){var r=f.clone(t._rectangle,S),i=t._ellipsoid,n=t._surfaceHeight,a=t._extrudedHeight,s=v.computeOptions(t,r,P);s.size=2*s.width+2*s.height-4;var u,c;if(r=t._rectangle,o(a)){u=g(s);var h=e.fromRectangle3D(r,i,n,C),d=e.fromRectangle3D(r,i,a,y);c=e.union(h,d)}else u=_(s),u=p.scaleToGeodeticHeight(u,n,i,!1),c=e.fromRectangle3D(r,i,n);return new l({attributes:u.attributes,indices:u.indices,primitiveType:m.LINES,boundingSphere:c})},w}),r("Core/ReferenceFrame",["./freezeObject"],function(e){"use strict";var t={FIXED:0,INERTIAL:1};return e(t)}),r("Core/ScreenSpaceEventType",["./freezeObject"],function(e){"use strict";var t={LEFT_DOWN:0,LEFT_UP:1,LEFT_CLICK:2,LEFT_DOUBLE_CLICK:3,RIGHT_DOWN:5,RIGHT_UP:6,RIGHT_CLICK:7,RIGHT_DOUBLE_CLICK:8,MIDDLE_DOWN:10,MIDDLE_UP:11,MIDDLE_CLICK:12,MIDDLE_DOUBLE_CLICK:13,MOUSE_MOVE:15,WHEEL:16,PINCH_START:17,PINCH_END:18,PINCH_MOVE:19};return e(t)}),r("Core/ScreenSpaceEventHandler",["./AssociativeArray","./Cartesian2","./defaultValue","./defined","./destroyObject","./DeveloperError","./FeatureDetection","./KeyboardEventModifier","./ScreenSpaceEventType"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t,r){var i=e._element;if(i===document)return r.x=t.clientX,r.y=t.clientY,r;var n=i.getBoundingClientRect();return r.x=t.clientX-n.left,r.y=t.clientY-n.top,r}function c(e,t){var r=e;return i(t)&&(r+="+"+t),r}function h(e){return e.shiftKey?s.SHIFT:e.ctrlKey?s.CTRL:e.altKey?s.ALT:void 0}function d(e,t,r,i){var n=function(t){i(e,t)};r.addEventListener(t,n,!1),e._removalFunctions.push(function(){r.removeEventListener(t,n,!1)})}function p(e){var t=e._element,r=i(t.disableRootEvents)?t:document;a.supportsPointerEvents()?(d(e,"pointerdown",t,b),d(e,"pointerup",t,x),d(e,"pointermove",t,P)):(d(e,"mousedown",t,f),d(e,"mouseup",r,v),d(e,"mousemove",r,_),d(e,"touchstart",t,C),d(e,"touchend",r,E),d(e,"touchmove",r,w)),d(e,"dblclick",t,g);var n;n="onwheel"in t?"wheel":i(document.onmousewheel)?"mousewheel":"DOMMouseScroll",d(e,n,t,y)}function m(e){for(var t=e._removalFunctions,r=0;r0?-120*t.detail:t.wheelDelta;if(i(r)){var o=h(t),a=e.getInputAction(l.WHEEL,o);i(a)&&(a(r),t.preventDefault())}}function C(e,r){e._seenAnyTouchEvents=!0;var i,n,o,a=r.changedTouches,s=a.length,l=e._positions;for(i=0;s>i;++i)n=a[i],o=n.identifier,l.set(o,u(e,n,new t));S(e,r);var c=e._previousPositions;for(i=0;s>i;++i)n=a[i],o=n.identifier,c.set(o,t.clone(l.get(o)))}function E(e,t){e._seenAnyTouchEvents=!0;var r,i,n,o=t.changedTouches,a=o.length,s=e._positions;for(r=0;a>r;++r)i=o[r],n=i.identifier,s.remove(n);S(e,t);var l=e._previousPositions;for(r=0;a>r;++r)i=o[r],n=i.identifier,l.remove(n)}function S(e,r){var n,o,a=h(r),s=e._positions,u=e._previousPositions,c=s.length;if(1!==c&&e._buttonDown===A.LEFT&&(e._buttonDown=void 0,n=e.getInputAction(l.LEFT_UP,a),i(n)&&(t.clone(e._primaryPosition,F.position),n(F)),0===c&&(o=e.getInputAction(l.LEFT_CLICK,a),i(o)))){var d=e._primaryStartPosition,p=u.values[0],m=d.x-p.x,f=d.y-p.y,v=Math.sqrt(m*m+f*f);vn;++n){o=s[n],a=o.identifier;var h=c.get(a);i(h)&&u(e,o,h)}T(e,r);var d=e._previousPositions;for(n=0;l>n;++n)o=s[n],a=o.identifier,t.clone(c.get(a),d.get(a))}function T(e,r){var n,o=h(r),a=e._positions,s=e._previousPositions,u=a.length;if(1===u&&e._buttonDown===A.LEFT){var c=a.values[0];t.clone(c,e._primaryPosition);var d=e._primaryPreviousPosition;n=e.getInputAction(l.MOUSE_MOVE,o),i(n)&&(t.clone(d,V.startPosition),t.clone(c,V.endPosition),n(V)),t.clone(c,d),r.preventDefault()}else if(2===u&&e._isPinching&&(n=e.getInputAction(l.PINCH_MOVE,o),i(n))){var p=a.values[0],m=a.values[1],f=s.values[0],v=s.values[1],_=m.x-p.x,g=m.y-p.y,y=.25*Math.sqrt(_*_+g*g),C=v.x-f.x,E=v.y-f.y,S=.25*Math.sqrt(C*C+E*E),w=.125*(m.y+p.y),T=.125*(v.y+f.y),b=Math.atan2(g,_),x=Math.atan2(E,C);t.fromElements(0,S,z.distance.startPosition),t.fromElements(0,y,z.distance.endPosition),t.fromElements(x,T,z.angleAndHeight.startPosition),t.fromElements(b,w,z.angleAndHeight.endPosition),n(z)}}function b(e,r){if(r.target.setPointerCapture(r.pointerId),"touch"===r.pointerType){var i=e._positions,n=r.pointerId;i.set(n,u(e,r,new t)),S(e,r);var o=e._previousPositions;o.set(n,t.clone(i.get(n)))}else f(e,r)}function x(e,t){if("touch"===t.pointerType){var r=e._positions,i=t.pointerId;r.remove(i),S(e,t);var n=e._previousPositions;n.remove(i)}else v(e,t)}function P(e,r){if("touch"===r.pointerType){var i=e._positions,n=r.pointerId;u(e,r,i.get(n)),T(e,r);var o=e._previousPositions;t.clone(i.get(n),o.get(n))}else _(e,r)}var A={LEFT:0,MIDDLE:1,RIGHT:2},I={position:new t},M={position:new t},D={position:new t},R={startPosition:new t,endPosition:new t},O={position:new t},N={position:new t},L={position1:new t,position2:new t},F={position:new t},B={position:new t},V={startPosition:new t,endPosition:new t},z={distance:{startPosition:new t,endPosition:new t},angleAndHeight:{startPosition:new t,endPosition:new t}},k=function(i){this._inputEvents={},this._buttonDown=void 0,this._isPinching=!1,this._seenAnyTouchEvents=!1,this._primaryStartPosition=new t,this._primaryPosition=new t,this._primaryPreviousPosition=new t,this._positions=new e,this._previousPositions=new e,this._removalFunctions=[],this._clickPixelTolerance=5,this._element=r(i,document),p(this)};return k.prototype.setInputAction=function(e,t,r){var i=c(t,r);this._inputEvents[i]=e},k.prototype.getInputAction=function(e,t){var r=c(e,t);return this._inputEvents[r]},k.prototype.removeInputAction=function(e,t){var r=c(e,t);delete this._inputEvents[r]},k.prototype.isDestroyed=function(){return!1},k.prototype.destroy=function(){return m(this),n(this)},k}),r("Core/ShowGeometryInstanceAttribute",["./ComponentDatatype","./defaultValue","./defined","./defineProperties","./DeveloperError"],function(e,t,r,i,n){"use strict";var o=function(e){e=t(e,!0),this.value=o.toValue(e)};return i(o.prototype,{componentDatatype:{get:function(){return e.UNSIGNED_BYTE}},componentsPerAttribute:{get:function(){return 1}},normalize:{get:function(){return!1}}}),o.toValue=function(e,t){return r(t)?(t[0]=e,t):new Uint8Array([e])},o}),r("Core/Simon1994PlanetaryPositions",["./Cartesian3","./defined","./DeveloperError","./JulianDate","./Math","./Matrix3","./TimeConstants","./TimeStandard"],function(e,t,r,i,n,o,a,s){"use strict";function l(e){var t=6.239996+.0172019696544*e;return.001657*Math.sin(t+.01671*Math.sin(t))}function u(e,t){t=i.addSeconds(e,C,t);var r=i.totalDays(t)-E;return t=i.addSeconds(t,l(r),t)}function c(i,a,s,l,u,c,p,m){if(0>s&&(s=-s,u+=n.PI),0>s||s>n.PI)throw new r("The inclination is out of range. Inclination must be greater than or equal to zero and less than or equal to Pi radians.");var v=i*(1-a),_=l-u,g=u,y=d(c-l,a),C=h(a,0);if("Hyperbolic"===C&&Math.abs(n.negativePiToPi(y))>=Math.acos(-1/a))throw new r("The true anomaly of the hyperbolic orbit lies outside of the bounds of the hyperbola.");f(_,s,g,I);var E=v*(1+a),S=Math.cos(y),w=Math.sin(y),T=1+a*S;if(T<=n.Epsilon10)throw new r("elements cannot be converted to cartesian");var b=E/T;return t(m)?(m.x=b*S,m.y=b*w,m.z=0):m=new e(b*S,b*w,0),o.multiplyByVector(I,m,m)}function h(e,t){if(0>e)throw new r("eccentricity cannot be negative.");return t>=e?"Circular":1-t>e?"Elliptical":1+t>=e?"Parabolic":"Hyperbolic"}function d(e,t){if(0>t||t>=1)throw new r("eccentricity out of range.");var i=p(e,t);return m(i,t)}function p(e,t){if(0>t||t>=1)throw new r("eccentricity out of range.");var i=Math.floor(e/n.TWO_PI);e-=i*n.TWO_PI;var o,a=e+t*Math.sin(e)/(1-Math.sin(e+t)+Math.sin(e)),s=Number.MAX_VALUE;for(o=0;M>o&&Math.abs(s-a)>D;++o){s=a;var l=s-t*Math.sin(s)-e,u=1-t*Math.cos(s);a=s-l/u}if(o>=M)throw new r("Kepler equation did not converge");return s=a+i*n.TWO_PI}function m(e,t){if(0>t||t>=1)throw new r("eccentricity out of range.");var i=Math.floor(e/n.TWO_PI);e-=i*n.TWO_PI;var o=Math.cos(e)-t,a=Math.sin(e)*Math.sqrt(1-t*t),s=Math.atan2(a,o);return s=n.zeroToTwoPi(s),0>e&&(s-=n.TWO_PI),s+=i*n.TWO_PI}function f(e,i,a,s){if(0>i||i>n.PI)throw new r("inclination out of range");var l=Math.cos(e),u=Math.sin(e),c=Math.cos(i),h=Math.sin(i),d=Math.cos(a),p=Math.sin(a);return t(s)?(s[0]=d*l-p*u*c,s[1]=p*l+d*u*c,s[2]=u*h,s[3]=-d*u-p*l*c,s[4]=-p*u+d*l*c,s[5]=l*h,s[6]=p*h,s[7]=-d*h,s[8]=c):s=new o(d*l-p*u*c,-d*u-p*l*c,p*h,p*l+d*u*c,-p*u+d*l*c,-d*h,u*h,l*h,c),s}function v(e,t){u(e,Ie);var r=Ie.dayNumber-S.dayNumber+(Ie.secondsOfDay-S.secondsOfDay)/a.SECONDS_PER_DAY,i=r/(10*a.DAYS_PER_JULIAN_CENTURY),n=.3595362*i,o=R+W*Math.cos(L*n)+J*Math.sin(L*n)+H*Math.cos(F*n)+Q*Math.sin(F*n)+q*Math.cos(B*n)+$*Math.sin(B*n)+j*Math.cos(V*n)+ee*Math.sin(V*n)+Y*Math.cos(z*n)+te*Math.sin(z*n)+X*Math.cos(k*n)+re*Math.sin(k*n)+Z*Math.cos(U*n)+ie*Math.sin(U*n)+K*Math.cos(G*n)+ne*Math.sin(G*n),s=O+N*i+pe*Math.cos(oe*n)+Ee*Math.sin(oe*n)+me*Math.cos(ae*n)+Se*Math.sin(ae*n)+fe*Math.cos(se*n)+we*Math.sin(se*n)+ve*Math.cos(le*n)+Te*Math.sin(le*n)+_e*Math.cos(ue*n)+be*Math.sin(ue*n)+ge*Math.cos(ce*n)+xe*Math.sin(ce*n)+ye*Math.cos(he*n)+Pe*Math.sin(he*n)+Ce*Math.cos(de*n)+Ae*Math.sin(de*n),l=.0167086342-.0004203654*i,h=102.93734808*x+11612.3529*P*i,d=469.97289*P*i,p=174.87317577*x-8679.27034*P*i;return c(o,l,d,h,p,s,T,t)}function _(e,t){u(e,Ie);var r=Ie.dayNumber-S.dayNumber+(Ie.secondsOfDay-S.secondsOfDay)/a.SECONDS_PER_DAY,i=r/a.DAYS_PER_JULIAN_CENTURY,n=i*i,o=n*i,s=o*i,l=383397.7725+.004*i,h=.055545526-1.6e-8*i,d=5.15668983*x,p=-8e-5*i+.02966*n-42e-6*o-1.3e-7*s,m=83.35324312*x,f=14643420.2669*i-38.2702*n-.045047*o+21301e-8*s,v=125.04455501*x,_=-6967919.3631*i+6.3602*n+.007625*o-3586e-8*s,g=218.31664563*x,y=1732559343.4847*i-6.391*n+.006588*o-3169e-8*s,C=297.85019547*x+P*(1602961601.209*i-6.3706*n+.006593*o-3169e-8*s),E=93.27209062*x+P*(1739527262.8478*i-12.7512*n-.001037*o+417e-8*s),T=134.96340251*x+P*(1717915923.2178*i+31.8792*n+.051635*o-2447e-7*s),A=357.52910918*x+P*(129596581.0481*i-.5532*n+136e-6*o-1149e-8*s),I=310.17137918*x-P*(6967051.436*i+6.2068*n+.007618*o-3219e-8*s),M=2*C,D=4*C,R=6*C,O=2*T,N=3*T,L=4*T,F=2*E;l+=3400.4*Math.cos(M)-635.6*Math.cos(M-T)-235.6*Math.cos(T)+218.1*Math.cos(M-A)+181*Math.cos(M+T),h+=.014216*Math.cos(M-T)+.008551*Math.cos(M-O)-.001383*Math.cos(T)+.001356*Math.cos(M+T)-.001147*Math.cos(D-N)-914e-6*Math.cos(D-O)+869e-6*Math.cos(M-A-T)-627e-6*Math.cos(M)-394e-6*Math.cos(D-L)+282e-6*Math.cos(M-A-O)-279e-6*Math.cos(C-T)-236e-6*Math.cos(O)+231e-6*Math.cos(D)+229e-6*Math.cos(R-L)-201e-6*Math.cos(O-F),p+=486.26*Math.cos(M-F)-40.13*Math.cos(M)+37.51*Math.cos(F)+25.73*Math.cos(O-F)+19.97*Math.cos(M-A-F),f+=-55609*Math.sin(M-T)-34711*Math.sin(M-O)-9792*Math.sin(T)+9385*Math.sin(D-N)+7505*Math.sin(D-O)+5318*Math.sin(M+T)+3484*Math.sin(D-L)-3417*Math.sin(M-A-T)-2530*Math.sin(R-L)-2376*Math.sin(M)-2075*Math.sin(M-N)-1883*Math.sin(O)-1736*Math.sin(R-5*T)+1626*Math.sin(A)-1370*Math.sin(R-N),_+=-5392*Math.sin(M-F)-540*Math.sin(A)-441*Math.sin(M)+423*Math.sin(F)-288*Math.sin(O-F),y+=-3332.9*Math.sin(M)+1197.4*Math.sin(M-T)-662.5*Math.sin(A)+396.3*Math.sin(T)-218*Math.sin(M-A);var B=2*I,V=3*I;p+=46.997*Math.cos(I)*i-.614*Math.cos(M-F+I)*i+.614*Math.cos(M-F-I)*i-.0297*Math.cos(B)*n-.0335*Math.cos(I)*n+.0012*Math.cos(M-F+B)*n-16e-5*Math.cos(I)*o+4e-5*Math.cos(V)*o+4e-5*Math.cos(B)*o;var z=2.116*Math.sin(I)*i-.111*Math.sin(M-F-I)*i-.0015*Math.sin(I)*n;f+=z,y+=z,_+=-520.77*Math.sin(I)*i+13.66*Math.sin(M-F+I)*i+1.12*Math.sin(M-I)*i-1.06*Math.sin(F-I)*i+.66*Math.sin(B)*n+.371*Math.sin(I)*n-.035*Math.sin(M-F+B)*n-.015*Math.sin(M-F+I)*n+.0014*Math.sin(I)*o-.0011*Math.sin(V)*o-9e-4*Math.sin(B)*o,l*=b;var k=d+p*P,U=m+f*P,G=g+y*P,W=v+_*P;return c(l,h,k,U,W,G,w,t)}function g(t,r){return r=_(t,r),e.multiplyByScalar(r,De,r)}var y={},C=32.184,E=2451545,S=new i(2451545,0,s.TAI),w=398600435e6,T=1.012300034*w*328900.56,b=1e3,x=n.RADIANS_PER_DEGREE,P=n.RADIANS_PER_ARCSECOND,A=14959787e4,I=new o,M=50,D=n.EPSILON8,R=1.0000010178*A,O=100.46645683*x,N=1295977422.83429*P,L=16002,F=21863,B=32004,V=10931,z=14529,k=16368,U=15318,G=32794,W=64e-7*A,H=-152*1e-7*A,q=62e-7*A,j=-8e-7*A,Y=32e-7*A,X=-41*1e-7*A,Z=19e-7*A,K=-11*1e-7*A,J=-150*1e-7*A,Q=-46*1e-7*A,$=68*1e-7*A,ee=54e-7*A,te=14e-7*A,re=24e-7*A,ie=-28*1e-7*A,ne=22e-7*A,oe=10,ae=16002,se=21863,le=10931,ue=1473,ce=32004,he=4387,de=73,pe=-325*1e-7,me=-322*1e-7,fe=-79*1e-7,ve=232*1e-7,_e=-52*1e-7,ge=97e-7,ye=55e-7,Ce=-41*1e-7,Ee=-105*1e-7,Se=-137*1e-7,we=258e-7,Te=35e-7,be=-116*1e-7,xe=-88*1e-7,Pe=-112*1e-7,Ae=-80*1e-7,Ie=new i(0,0,s.TAI),Me=.012300034,De=Me/(Me+1)*-1,Re=new o(1.0000000000000002,5.619723173785822e-16,4.690511510146299e-19,-5.154129427414611e-16,.9174820620691819,-.39777715593191376,-2.23970096136568e-16,.39777715593191376,.9174820620691819),Oe=new e;return y.computeSunPositionInEarthInertialFrame=function(r,n){return t(r)||(r=i.now()),t(n)||(n=new e),Oe=v(r,Oe),n=e.negate(Oe,n),g(r,Oe),e.subtract(n,Oe,n),o.multiplyByVector(Re,n,n),n},y.computeMoonPositionInEarthInertialFrame=function(e,r){return t(e)||(e=i.now()),r=_(e,r),o.multiplyByVector(Re,r,r),r},y}),r("Core/SimplePolylineGeometry",["./BoundingSphere","./Cartesian3","./Color","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,t,i,n,o,a,s){var l,u=p.numberOfPoints(e,t,o),c=i.red,h=i.green,d=i.blue,m=i.alpha,f=n.red,v=n.green,_=n.blue,g=n.alpha;if(r.equals(i,n)){for(l=0;u>l;l++)a[s++]=r.floatToByte(c),a[s++]=r.floatToByte(h),a[s++]=r.floatToByte(d),a[s++]=r.floatToByte(m);return s}var y=(f-c)/u,C=(v-h)/u,E=(_-d)/u,S=(g-m)/u,w=s;for(l=0;u>l;l++)a[w++]=r.floatToByte(c+l*y),a[w++]=r.floatToByte(h+l*C),a[w++]=r.floatToByte(d+l*E),a[w++]=r.floatToByte(m+l*S);return w}var v=function(e){e=n(e,n.EMPTY_OBJECT);var i=e.positions,a=e.colors,l=n(e.colorsPerVertex,!1);this._positions=i,this._colors=a,this._colorsPerVertex=l,this._followSurface=n(e.followSurface,!0),this._granularity=n(e.granularity,d.RADIANS_PER_DEGREE),this._ellipsoid=n(e.ellipsoid,s.WGS84),this._workerName="createSimplePolylineGeometry";var u=1+i.length*t.packedLength;u+=o(a)?1+a.length*r.packedLength:1,this.packedLength=u+s.packedLength+3};v.pack=function(e,i,a){a=n(a,0);var l,u=e._positions,c=u.length;for(i[a++]=c,l=0;c>l;++l,a+=t.packedLength)t.pack(u[l],i,a);var h=e._colors;for(c=o(h)?h.length:0,i[a++]=c,l=0;c>l;++l,a+=r.packedLength)r.pack(h[l],i,a);s.pack(e._ellipsoid,i,a),a+=s.packedLength,i[a++]=e._colorsPerVertex?1:0,i[a++]=e._followSurface?1:0,i[a]=e._granularity},v.unpack=function(e,i,a){i=n(i,0);var l,u=e[i++],c=new Array(u);for(l=0;u>l;++l,i+=t.packedLength)c[l]=t.unpack(e,i);u=e[i++];var h=u>0?new Array(u):void 0;for(l=0;u>l;++l,i+=r.packedLength)h[l]=r.unpack(e,i);var d=s.unpack(e,i);i+=s.packedLength;var p=1===e[i++],m=1===e[i++],f=e[i];return o(a)?(a._positions=c,a._colors=h,a._ellipsoid=d,a._colorsPerVertex=p,a._followSurface=m,a._granularity=f,a):new v({positions:c,colors:h,ellipsoid:d,colorsPerVertex:p,followSurface:m,granularity:f})};var _=new Array(2),g=new Array(2),y={positions:_,height:g,ellipsoid:void 0,minDistance:void 0};return v.createGeometry=function(n){var a,s,v,C,E,S=n._positions,w=n._colors,T=n._colorsPerVertex,b=n._followSurface,x=n._granularity,P=n._ellipsoid,A=d.chordLength(x,P.maximumRadius),I=o(w)&&!T,M=S.length,D=0;if(b){var R=p.extractHeights(S,P),O=y;if(O.minDistance=A,O.ellipsoid=P,I){var N=0;for(a=0;M-1>a;a++)N+=p.numberOfPoints(S[a],S[a+1],A)+1;s=new Float64Array(3*N),C=new Uint8Array(4*N),O.positions=_,O.height=g;var L=0;for(a=0;M-1>a;++a){_[0]=S[a],_[1]=S[a+1],g[0]=R[a],g[1]=R[a+1];var F=p.generateArc(O);if(o(w)){var B=F.length/3;E=w[a];for(var V=0;B>V;++V)C[L++]=r.floatToByte(E.red),C[L++]=r.floatToByte(E.green),C[L++]=r.floatToByte(E.blue),C[L++]=r.floatToByte(E.alpha)}s.set(F,D),D+=F.length}}else if(O.positions=S,O.height=R,s=new Float64Array(p.generateArc(O)),o(w)){for(C=new Uint8Array(s.length/3*4),a=0;M-1>a;++a){var z=S[a],k=S[a+1],U=w[a],G=w[a+1];D=f(z,k,U,G,A,C,D)}var W=w[M-1];C[D++]=r.floatToByte(W.red),C[D++]=r.floatToByte(W.green),C[D++]=r.floatToByte(W.blue),C[D++]=r.floatToByte(W.alpha)}}else{v=I?2*M-2:M,s=new Float64Array(3*v),C=o(w)?new Uint8Array(4*v):void 0;var H=0,q=0;for(a=0;M>a;++a){var j=S[a];if(I&&a>0&&(t.pack(j,s,H),H+=3,E=w[a-1],C[q++]=r.floatToByte(E.red),C[q++]=r.floatToByte(E.green),C[q++]=r.floatToByte(E.blue),C[q++]=r.floatToByte(E.alpha)),I&&a===M-1)break;t.pack(j,s,H),H+=3,o(w)&&(E=w[a],C[q++]=r.floatToByte(E.red),C[q++]=r.floatToByte(E.green),C[q++]=r.floatToByte(E.blue),C[q++]=r.floatToByte(E.alpha))}}var Y=new c;Y.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:s}),o(w)&&(Y.color=new u({componentDatatype:i.UNSIGNED_BYTE,componentsPerAttribute:4,values:C,normalize:!0})),v=s.length/3;var X=2*(v-1),Z=h.createTypedArray(v,X),K=0;for(a=0;v-1>a;++a)Z[K++]=a,Z[K++]=a+1;return new l({attributes:Y,indices:Z,primitiveType:m.LINES,boundingSphere:e.fromPoints(S)})},v}),r("Core/SphereGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipsoidGeometry","./VertexFormat"],function(e,t,r,i,n,o){"use strict";var a=function(r){var i=t(r.radius,1),o=new e(i,i,i),a={radii:o,stackPartitions:r.stackPartitions,slicePartitions:r.slicePartitions,vertexFormat:r.vertexFormat};this._ellipsoidGeometry=new n(a),this._workerName="createSphereGeometry"};a.packedLength=n.packedLength,a.pack=function(e,t,r){n.pack(e._ellipsoidGeometry,t,r)};var s=new n,l={radius:void 0,radii:new e,vertexFormat:new o,stackPartitions:void 0,slicePartitions:void 0};return a.unpack=function(t,i,u){var c=n.unpack(t,i,s);return l.vertexFormat=o.clone(c._vertexFormat,l.vertexFormat),l.stackPartitions=c._stackPartitions,l.slicePartitions=c._slicePartitions,r(u)?(e.clone(c._radii,l.radii),u._ellipsoidGeometry=new n(l),u):(l.radius=c._radii.x,new a(l))},a.createGeometry=function(e){return n.createGeometry(e._ellipsoidGeometry)},a}),r("Core/SphereOutlineGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipsoidOutlineGeometry"],function(e,t,r,i,n){"use strict";var o=function(r){var i=t(r.radius,1),o=new e(i,i,i),a={radii:o,stackPartitions:r.stackPartitions,slicePartitions:r.slicePartitions,subdivisions:r.subdivisions};this._ellipsoidGeometry=new n(a),this._workerName="createSphereOutlineGeometry"};o.packedLength=n.packedLength,o.pack=function(e,t,r){n.pack(e._ellipsoidGeometry,t,r)};var a=new n,s={radius:void 0,radii:new e,stackPartitions:void 0,slicePartitions:void 0,subdivisions:void 0};return o.unpack=function(t,i,l){var u=n.unpack(t,i,a);return s.stackPartitions=u._stackPartitions,s.slicePartitions=u._slicePartitions,s.subdivisions=u._subdivisions,r(l)?(e.clone(u._radii,s.radii),l._ellipsoidGeometry=new n(s),l):(s.radius=u._radii.x,new o(s))},o.createGeometry=function(e){return n.createGeometry(e._ellipsoidGeometry)},o}),r("Core/Spherical",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t,r,i){this.clock=e(t,0),this.cone=e(r,0),this.magnitude=e(i,1)};return i.fromCartesian3=function(e,r){var n=e.x,o=e.y,a=e.z,s=n*n+o*o;return t(r)||(r=new i),r.clock=Math.atan2(o,n),r.cone=Math.atan2(Math.sqrt(s),a),r.magnitude=Math.sqrt(s+a*a),r},i.clone=function(e,r){return t(e)?t(r)?(r.clock=e.clock,r.cone=e.cone,r.magnitude=e.magnitude,r):new i(e.clock,e.cone,e.magnitude):void 0},i.normalize=function(e,r){return t(r)?(r.clock=e.clock,r.cone=e.cone,r.magnitude=1,r):new i(e.clock,e.cone,1)},i.equals=function(e,r){return e===r||t(e)&&t(r)&&e.clock===r.clock&&e.cone===r.cone&&e.magnitude===r.magnitude},i.equalsEpsilon=function(r,i,n){return n=e(n,0),r===i||t(r)&&t(i)&&Math.abs(r.clock-i.clock)<=n&&Math.abs(r.cone-i.cone)<=n&&Math.abs(r.magnitude-i.magnitude)<=n},i.prototype.equals=function(e){return i.equals(this,e)},i.prototype.clone=function(e){return i.clone(this,e)},i.prototype.equalsEpsilon=function(e,t){return i.equalsEpsilon(this,e,t)},i.prototype.toString=function(){return"("+this.clock+", "+this.cone+", "+this.magnitude+")"},i}),r("Core/TerrainData",["./defineProperties","./DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return e(r.prototype,{waterMask:{get:t.throwInstantiationError}}),r.prototype.interpolateHeight=t.throwInstantiationError,r.prototype.isChildAvailable=t.throwInstantiationError,r.prototype.createMesh=t.throwInstantiationError,r.prototype.upsample=t.throwInstantiationError,r.prototype.wasCreatedByUpsampling=t.throwInstantiationError,r}),r("Core/TilingScheme",["./defineProperties","./DeveloperError"],function(e,t){"use strict";var r=function(e){throw new t("This type should not be instantiated directly. Instead, use WebMercatorTilingScheme or GeographicTilingScheme.")};return e(r.prototype,{ellipsoid:{get:t.throwInstantiationError},rectangle:{get:t.throwInstantiationError},projection:{get:t.throwInstantiationError}}),r.prototype.getNumberOfXTilesAtLevel=t.throwInstantiationError,r.prototype.getNumberOfYTilesAtLevel=t.throwInstantiationError,r.prototype.rectangleToNativeRectangle=t.throwInstantiationError,r.prototype.tileXYToNativeRectangle=t.throwInstantiationError,r.prototype.tileXYToRectangle=t.throwInstantiationError,r.prototype.positionToTileXY=t.throwInstantiationError,r}),r("Core/TimeIntervalCollection",["./binarySearch","./defaultValue","./defined","./defineProperties","./DeveloperError","./Event","./JulianDate","./TimeInterval"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t){return a.compare(e.start,t.start)}var u=function(e){if(this._intervals=[],this._changedEvent=new o,r(e))for(var t=e.length,i=0;t>i;i++)this.addInterval(e[i])};i(u.prototype,{changedEvent:{get:function(){return this._changedEvent}},start:{get:function(){var e=this._intervals;return 0===e.length?void 0:e[0].start}},isStartIncluded:{get:function(){var e=this._intervals;return 0===e.length?!1:e[0].isStartIncluded}},stop:{get:function(){var e=this._intervals,t=e.length;return 0===t?void 0:e[t-1].stop}},isStopIncluded:{get:function(){var e=this._intervals,t=e.length;return 0===t?!1:e[t-1].isStopIncluded}},length:{get:function(){return this._intervals.length}},isEmpty:{get:function(){return 0===this._intervals.length}}}),u.prototype.equals=function(e,t){if(this===e)return!0;if(!(e instanceof u))return!1;var r=this._intervals,i=e._intervals,n=r.length;if(n!==i.length)return!1;for(var o=0;n>o;o++)if(!s.equals(r[o],i[o],t))return!1;return!0},u.prototype.get=function(e){return this._intervals[e]},u.prototype.removeAll=function(){this._intervals.length>0&&(this._intervals.length=0,this._changedEvent.raiseEvent(this))},u.prototype.findIntervalContainingDate=function(e){var t=this.indexOf(e);return t>=0?this._intervals[t]:void 0},u.prototype.findDataForIntervalContainingDate=function(e){var t=this.indexOf(e);return t>=0?this._intervals[t].data:void 0},u.prototype.contains=function(e){return this.indexOf(e)>=0};var c=new s;return u.prototype.indexOf=function(t){var r=this._intervals;c.start=t,c.stop=t;var i=e(r,c,l);return i>=0?r[i].isStartIncluded?i:i>0&&r[i-1].stop.equals(t)&&r[i-1].isStopIncluded?i-1:~i:(i=~i,i>0&&i-1l;l++){var c=s[l];if(!(r(i)&&!c.start.equals(i)||r(n)&&!c.stop.equals(n)||r(o)&&c.isStartIncluded!==o||r(a)&&c.isStopIncluded!==a))return s[l]}return void 0},u.prototype.addInterval=function(t,i){if(!t.isEmpty){var n,o,u=this._intervals;if(0===u.length||a.greaterThan(t.start,u[u.length-1].stop))return u.push(t),void this._changedEvent.raiseEvent(this);for(o=e(u,t,l),0>o?o=~o:o>0&&t.isStartIncluded&&u[o-1].isStartIncluded&&u[o-1].start.equals(t.start)?--o:o0&&(n=a.compare(u[o-1].stop,t.start),(n>0||0===n&&(u[o-1].isStopIncluded||t.isStartIncluded))&&((r(i)?i(u[o-1].data,t.data):u[o-1].data===t.data)?(t=new s(a.greaterThan(t.stop,u[o-1].stop)?{start:u[o-1].start,stop:t.stop,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:t.isStopIncluded,data:t.data}:{start:u[o-1].start,stop:u[o-1].stop,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:u[o-1].isStopIncluded||t.stop.equals(u[o-1].stop)&&t.isStopIncluded,data:t.data}),u.splice(o-1,1),--o):(n=a.compare(u[o-1].stop,t.stop),n>0||0===n&&u[o-1].isStopIncluded&&!t.isStopIncluded?u.splice(o-1,1,new s({start:u[o-1].start,stop:t.start,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:!t.isStartIncluded,data:u[o-1].data}),new s({start:t.stop,stop:u[o-1].stop,isStartIncluded:!t.isStopIncluded,isStopIncluded:u[o-1].isStopIncluded,data:u[o-1].data})):u[o-1]=new s({start:u[o-1].start,stop:t.start,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:!t.isStartIncluded,data:u[o-1].data}))));o0||0===n&&(t.isStopIncluded||u[o].isStartIncluded));)if(r(i)?i(u[o].data,t.data):u[o].data===t.data)t=new s({start:t.start,stop:a.greaterThan(u[o].stop,t.stop)?u[o].stop:t.stop,isStartIncluded:t.isStartIncluded,isStopIncluded:a.greaterThan(u[o].stop,t.stop)?u[o].isStopIncluded:t.isStopIncluded,data:t.data}),u.splice(o,1);else{if(u[o]=new s({start:t.stop,stop:u[o].stop,isStartIncluded:!t.isStopIncluded,isStopIncluded:u[o].isStopIncluded,data:u[o].data}),!u[o].isEmpty)break;u.splice(o,1)}u.splice(o,0,t),this._changedEvent.raiseEvent(this)}},u.prototype.removeInterval=function(t){if(t.isEmpty)return!1;var r=!1,i=this._intervals,n=e(i,t,l);0>n&&(n=~n);var o=t.start,u=t.stop,c=t.isStartIncluded,h=t.isStopIncluded;if(n>0){var d=i[n-1],p=d.stop;(a.greaterThan(p,o)||s.equals(p,o)&&d.isStopIncluded&&c)&&(r=!0, +(a.greaterThan(p,u)||d.isStopIncluded&&!h&&s.equals(p,u))&&i.splice(n,0,new s({start:u,stop:p,isStartIncluded:!h,isStopIncluded:d.isStopIncluded,data:d.data})),i[n-1]=new s({start:d.start,stop:o,isStartIncluded:d.isStartIncluded,isStopIncluded:!c,data:d.data}))}var m=i[n];for(n0&&"/"!==this._url[this._url.length-1]&&(this._url+="/"),this._errorEvent=new s,this._ready=!1,this._readyPromise=e.defer(),this._proxy=n.proxy,this._terrainDataStructure={heightScale:.001,heightOffset:-1e3,elementsPerHeight:3,stride:4,elementMultiplier:256,isBigEndian:!0};var v=n.credit;"string"==typeof v&&(v=new t(v)),this._credit=v,this._tilingScheme=void 0,this._rectangles=[];var y,C=this,E=r(n.ellipsoid,a.WGS84);h()};n(E.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return this._credit}},tilingScheme:{get:function(){if(!this.ready)throw new o("requestTileGeometry must not be called before ready returns true.");return this._tilingScheme}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},hasWaterMask:{get:function(){return!1}},hasVertexNormals:{get:function(){return!1}}}),E.prototype.requestTileGeometry=function(t,n,a,s){if(!this.ready)throw new o("requestTileGeometry must not be called before ready returns true.");var l=this._tilingScheme.getNumberOfYTilesAtLevel(a),d=this._url+a+"/"+t+"/"+(l-n-1)+".tif?cesium=true",p=this._proxy;i(p)&&(d=p.getURL(d));var m;if(s=r(s,!0)){if(m=v(d,h),!i(m))return void 0}else m=h(d);var f=this;return e(m,function(e){return new c({buffer:u(e),width:f._heightmapWidth,height:f._heightmapHeight,childTileMask:y(f,t,n,a),structure:f._terrainDataStructure})})},E.prototype.getLevelMaximumGeometricError=function(e){if(!this.ready)throw new o("requestTileGeometry must not be called before ready returns true.");return this._levelZeroMaximumGeometricError/(1<a)return{positions:i};var s=t(o),u=t(n),c=new Array(a),p=new Array(a),m=new Array(a),f=i[0];c[0]=f;var v=r.cartesianToCartographic(f,h);u&&(v.height=n[0]),p[0]=v.height,s?m[0]=o[0]:m[0]=0;for(var _=1,g=1;a>g;++g){var y=i[g],C=r.cartesianToCartographic(y,d);u&&(C.height=n[g]),l(v,C)?v.height=3){var v=i.fromPoints(t,e),_=v.projectPointsOntoPlane(t);o.computeWindingOrder2D(_)===s.CLOCKWISE&&(t.reverse(),r.reverse(),l.reverse())}var g,y,C=t.length,E=n.chordLength(c,e.maximumRadius),S=f;if(S.minDistance=E,S.ellipsoid=e,h){var w,T=0;for(w=0;C-1>w;w++)T+=a.numberOfPoints(t[w],t[w+1],E)+1;g=new Float64Array(3*T),y=new Float64Array(3*T);var b=p,x=m;S.positions=b,S.height=x;var P=0;for(w=0;C-1>w;w++){b[0]=t[w],b[1]=t[w+1],x[0]=r[w],x[1]=r[w+1];var A=a.generateArc(S);g.set(A,P),x[0]=l[w],x[1]=l[w+1],y.set(a.generateArc(S),P),P+=A.length}}else S.positions=t,S.height=r,g=new Float64Array(a.generateArc(S)),S.height=l,y=new Float64Array(a.generateArc(S));return{bottomPositions:y,topPositions:g}},c}),r("Core/WallGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./VertexFormat","./WallGeometryLibrary"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new t,v=new t,_=new t,g=new t,y=new t,C=new t,E=new t,S=new t,w=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.positions,o=e.maximumHeights,s=e.minimumHeights,l=i(e.vertexFormat,p.DEFAULT),u=i(e.granularity,h.RADIANS_PER_DEGREE),c=i(e.ellipsoid,a.WGS84);this._positions=r,this._minimumHeights=s,this._maximumHeights=o,this._vertexFormat=p.clone(l),this._granularity=u,this._ellipsoid=a.clone(c),this._workerName="createWallGeometry";var d=1+r.length*t.packedLength+2;n(s)&&(d+=s.length),n(o)&&(d+=o.length),this.packedLength=d+a.packedLength+p.packedLength+1};w.pack=function(e,r,o){o=i(o,0);var s,l=e._positions,u=l.length;for(r[o++]=u,s=0;u>s;++s,o+=t.packedLength)t.pack(l[s],r,o);var c=e._minimumHeights;if(u=n(c)?c.length:0,r[o++]=u,n(c))for(s=0;u>s;++s)r[o++]=c[s];var h=e._maximumHeights;if(u=n(h)?h.length:0,r[o++]=u,n(h))for(s=0;u>s;++s)r[o++]=h[s];a.pack(e._ellipsoid,r,o),o+=a.packedLength,p.pack(e._vertexFormat,r,o),o+=p.packedLength,r[o]=e._granularity};var T=a.clone(a.UNIT_SPHERE),b=new p,x={positions:void 0,minimumHeights:void 0,maximumHeights:void 0,ellipsoid:T,vertexFormat:b,granularity:void 0};return w.unpack=function(e,r,o){r=i(r,0);var s,l=e[r++],u=new Array(l);for(s=0;l>s;++s,r+=t.packedLength)u[s]=t.unpack(e,r);l=e[r++];var c;if(l>0)for(c=new Array(l),s=0;l>s;++s)c[s]=e[r++];l=e[r++];var h;if(l>0)for(h=new Array(l),s=0;l>s;++s)h[s]=e[r++];var d=a.unpack(e,r,T);r+=a.packedLength;var m=p.unpack(e,r,b);r+=p.packedLength;var f=e[r];return n(o)?(o._positions=u,o._minimumHeights=c,o._maximumHeights=h,o._ellipsoid=a.clone(d,o._ellipsoid),o._vertexFormat=p.clone(m,o._vertexFormat),o._granularity=f,o):(x.positions=u,x.minimumHeights=c,x.maximumHeights=h,x.granularity=f,new w(x))},w.fromConstantHeights=function(e){e=i(e,i.EMPTY_OBJECT);var t,r,o=e.positions,a=e.minimumHeight,s=e.maximumHeight,l=n(a),u=n(s);if(l||u){var c=o.length;t=l?new Array(c):void 0,r=u?new Array(c):void 0;for(var h=0;c>h;++h)l&&(t[h]=a),u&&(r[h]=s)}var d={positions:o,maximumHeights:r,minimumHeights:t,ellipsoid:e.ellipsoid,vertexFormat:e.vertexFormat};return new w(d)},w.createGeometry=function(i){var o=i._positions,a=i._minimumHeights,p=i._maximumHeights,w=i._vertexFormat,T=i._granularity,b=i._ellipsoid,x=m.computePositions(b,o,p,a,T,!0);if(!n(x))return void 0;var P=x.bottomPositions,A=x.topPositions,I=A.length,M=2*I,D=w.position?new Float64Array(M):void 0,R=w.normal?new Float32Array(M):void 0,O=w.tangent?new Float32Array(M):void 0,N=w.binormal?new Float32Array(M):void 0,L=w.st?new Float32Array(M/3*2):void 0,F=0,B=0,V=0,z=0,k=0,U=S,G=E,W=C,H=!0;I/=3;var q,j=0,Y=1/(I-o.length+1);for(q=0;I>q;++q){var X=3*q,Z=t.fromArray(A,X,f),K=t.fromArray(P,X,v);if(w.position&&(D[F++]=K.x,D[F++]=K.y,D[F++]=K.z,D[F++]=Z.x,D[F++]=Z.y,D[F++]=Z.z),w.st&&(L[k++]=j,L[k++]=0,L[k++]=j,L[k++]=1),w.normal||w.tangent||w.binormal){var J,Q=t.clone(t.ZERO,y),$=b.scaleToGeodeticSurface(t.fromArray(A,X,v),v);if(I>q+1&&(J=b.scaleToGeodeticSurface(t.fromArray(A,X+3,_),_),Q=t.fromArray(A,X+3,y)),H){var ee=t.subtract(Q,Z,g),te=t.subtract($,Z,f);U=t.normalize(t.cross(te,ee,U),U),H=!1}t.equalsEpsilon(J,$,h.EPSILON10)?H=!0:(j+=Y,w.tangent&&(G=t.normalize(t.subtract(J,$,G),G)),w.binormal&&(W=t.normalize(t.cross(U,G,W),W))),w.normal&&(R[B++]=U.x,R[B++]=U.y,R[B++]=U.z,R[B++]=U.x,R[B++]=U.y,R[B++]=U.z),w.tangent&&(O[z++]=G.x,O[z++]=G.y,O[z++]=G.z,O[z++]=G.x,O[z++]=G.y,O[z++]=G.z),w.binormal&&(N[V++]=W.x,N[V++]=W.y,N[V++]=W.z,N[V++]=W.x,N[V++]=W.y,N[V++]=W.z)}}var re=new u;w.position&&(re.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:D})),w.normal&&(re.normal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:R})),w.tangent&&(re.tangent=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:O})),w.binormal&&(re.binormal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:N})),w.st&&(re.st=new l({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:L}));var ie=M/3;M-=6;var ne=c.createTypedArray(ie,M),oe=0;for(q=0;ie-2>q;q+=2){var ae=q,se=q+2,le=t.fromArray(D,3*ae,f),ue=t.fromArray(D,3*se,v);if(!t.equalsEpsilon(le,ue,h.EPSILON10)){var ce=q+1,he=q+3;ne[oe++]=ce,ne[oe++]=ae,ne[oe++]=he,ne[oe++]=he,ne[oe++]=ae,ne[oe++]=se}}return new s({attributes:re,indices:ne,primitiveType:d.TRIANGLES,boundingSphere:new e.fromVertices(D)})},w}),r("Core/WallOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./WallGeometryLibrary"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=new t,f=new t,v=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.positions,o=e.maximumHeights,s=e.minimumHeights,l=i(e.granularity,h.RADIANS_PER_DEGREE),u=i(e.ellipsoid,a.WGS84);this._positions=r,this._minimumHeights=s,this._maximumHeights=o,this._granularity=l,this._ellipsoid=a.clone(u),this._workerName="createWallOutlineGeometry";var c=1+r.length*t.packedLength+2;n(s)&&(c+=s.length),n(o)&&(c+=o.length),this.packedLength=c+a.packedLength+1};v.pack=function(e,r,o){o=i(o,0);var s,l=e._positions,u=l.length;for(r[o++]=u,s=0;u>s;++s,o+=t.packedLength)t.pack(l[s],r,o);var c=e._minimumHeights;if(u=n(c)?c.length:0,r[o++]=u,n(c))for(s=0;u>s;++s)r[o++]=c[s];var h=e._maximumHeights;if(u=n(h)?h.length:0,r[o++]=u,n(h))for(s=0;u>s;++s)r[o++]=h[s];a.pack(e._ellipsoid,r,o),o+=a.packedLength,r[o]=e._granularity};var _=a.clone(a.UNIT_SPHERE),g={positions:void 0,minimumHeights:void 0,maximumHeights:void 0,ellipsoid:_,granularity:void 0};return v.unpack=function(e,r,o){r=i(r,0);var s,l=e[r++],u=new Array(l);for(s=0;l>s;++s,r+=t.packedLength)u[s]=t.unpack(e,r);l=e[r++];var c;if(l>0)for(c=new Array(l),s=0;l>s;++s)c[s]=e[r++];l=e[r++];var h;if(l>0)for(h=new Array(l),s=0;l>s;++s)h[s]=e[r++];var d=a.unpack(e,r,_);r+=a.packedLength;var p=e[r];return n(o)?(o._positions=u,o._minimumHeights=c,o._maximumHeights=h,o._ellipsoid=a.clone(d,o._ellipsoid),o._granularity=p,o):(g.positions=u,g.minimumHeights=c,g.maximumHeights=h,g.granularity=p,new v(g))},v.fromConstantHeights=function(e){e=i(e,i.EMPTY_OBJECT);var t,r,o=e.positions,a=e.minimumHeight,s=e.maximumHeight,l=n(a),u=n(s);if(l||u){var c=o.length;t=l?new Array(c):void 0,r=u?new Array(c):void 0;for(var h=0;c>h;++h)l&&(t[h]=a),u&&(r[h]=s)}var d={positions:o,maximumHeights:r,minimumHeights:t,ellipsoid:e.ellipsoid};return new v(d)},v.createGeometry=function(i){var o=i._positions,a=i._minimumHeights,v=i._maximumHeights,_=i._granularity,g=i._ellipsoid,y=p.computePositions(g,o,v,a,_,!1);if(!n(y))return void 0;var C=y.bottomPositions,E=y.topPositions,S=E.length,w=2*S,T=new Float64Array(w),b=0;S/=3;var x;for(x=0;S>x;++x){var P=3*x,A=t.fromArray(E,P,m),I=t.fromArray(C,P,f);T[b++]=I.x,T[b++]=I.y,T[b++]=I.z,T[b++]=A.x,T[b++]=A.y,T[b++]=A.z}var M=new u({position:new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:T})}),D=w/3;w=2*D-4+D;var R=c.createTypedArray(D,w),O=0;for(x=0;D-2>x;x+=2){var N=x,L=x+2,F=t.fromArray(T,3*N,m),B=t.fromArray(T,3*L,f);if(!t.equalsEpsilon(F,B,h.EPSILON10)){var V=x+1,z=x+3;R[O++]=V,R[O++]=N,R[O++]=V,R[O++]=z,R[O++]=N,R[O++]=L}}return R[O++]=D-2,R[O++]=D-1,new s({attributes:M,indices:R,primitiveType:d.LINES,boundingSphere:new e.fromVertices(T)})},v}),r("Core/WebMercatorProjection",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Math"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){this._ellipsoid=r(e,a.WGS84),this._semimajorAxis=this._ellipsoid.maximumRadius,this._oneOverSemimajorAxis=1/this._semimajorAxis};return n(l.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),l.mercatorAngleToGeodeticLatitude=function(e){return s.PI_OVER_TWO-2*Math.atan(Math.exp(-e))},l.geodeticLatitudeToMercatorAngle=function(e){e>l.MaximumLatitude?e=l.MaximumLatitude:e<-l.MaximumLatitude&&(e=-l.MaximumLatitude);var t=Math.sin(e);return.5*Math.log((1+t)/(1-t))},l.MaximumLatitude=l.mercatorAngleToGeodeticLatitude(Math.PI),l.prototype.project=function(t,r){var n=this._semimajorAxis,o=t.longitude*n,a=l.geodeticLatitudeToMercatorAngle(t.latitude)*n,s=t.height;return i(r)?(r.x=o,r.y=a,r.z=s,r):new e(o,a,s)},l.prototype.unproject=function(e,r){var n=this._oneOverSemimajorAxis,o=e.x*n,a=l.mercatorAngleToGeodeticLatitude(e.y*n),s=e.z;return i(r)?(r.longitude=o,r.latitude=a,r.height=s,r):new t(o,a,s)},l}),r("Core/WebMercatorTilingScheme",["./Cartesian2","./defaultValue","./defined","./defineProperties","./Ellipsoid","./Rectangle","./WebMercatorProjection"],function(e,t,r,i,n,o,a){"use strict";var s=function(i){if(i=t(i,{}),this._ellipsoid=t(i.ellipsoid,n.WGS84),this._numberOfLevelZeroTilesX=t(i.numberOfLevelZeroTilesX,1),this._numberOfLevelZeroTilesY=t(i.numberOfLevelZeroTilesY,1),this._projection=new a(this._ellipsoid),r(i.rectangleSouthwestInMeters)&&r(i.rectangleNortheastInMeters))this._rectangleSouthwestInMeters=i.rectangleSouthwestInMeters,this._rectangleNortheastInMeters=i.rectangleNortheastInMeters;else{var s=this._ellipsoid.maximumRadius*Math.PI;this._rectangleSouthwestInMeters=new e(-s,-s),this._rectangleNortheastInMeters=new e(s,s)}var l=this._projection.unproject(this._rectangleSouthwestInMeters),u=this._projection.unproject(this._rectangleNortheastInMeters);this._rectangle=new o(l.longitude,l.latitude,u.longitude,u.latitude)};return i(s.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},rectangle:{get:function(){return this._rectangle}},projection:{get:function(){return this._projection}}}),s.prototype.getNumberOfXTilesAtLevel=function(e){return this._numberOfLevelZeroTilesX<=s&&(_=s-1);var g=v/d|0;return g>=l&&(g=l-1),r(n)?(n.x=_,n.y=g,n):new e(_,g)},s}),r("Core/appendForwardSlash",[],function(){"use strict";var e=function(e){return(0===e.length||"/"!==e[e.length-1])&&(e+="/"),e};return e}),r("Core/cancelAnimationFrame",["./defined"],function(e){"use strict";var t=window.cancelAnimationFrame;!function(){if(!e(t))for(var r=["webkit","moz","ms","o"],i=0,n=r.length;n>i&&!e(t);)t=window[r[i]+"CancelAnimationFrame"],e(t)||(t=window[r[i]+"CancelRequestAnimationFrame"]),++i;e(t)||(t=clearTimeout)}();var r=function(e){t(e)};return r}),r("Core/combine",["./defaultValue","./defined"],function(e,t){"use strict";var r=function(i,n,o){o=e(o,!1);var a,s,l,u={},c=t(i),h=t(n);if(c)for(a in i)i.hasOwnProperty(a)&&(s=i[a],h&&o&&"object"==typeof s&&n.hasOwnProperty(a)?(l=n[a],"object"==typeof l?u[a]=r(s,l,o):u[a]=s):u[a]=s);if(h)for(a in n)n.hasOwnProperty(a)&&!u.hasOwnProperty(a)&&(l=n[a],u[a]=l);return u};return r}),r("Core/createGuid",[],function(){"use strict";var e=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0,r="x"===e?t:3&t|8;return r.toString(16)})};return e}),r("Core/getFilenameFromUri",["../ThirdParty/Uri","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t){var r=new e(t);r.normalize();var i=r.path,n=i.lastIndexOf("/");return-1!==n&&(i=i.substr(n+1)),i};return i}),r("Core/getStringFromTypedArray",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t,r,n){return r=e(r,0),n=e(n,t.byteLength-r),t=t.subarray(r,r+n),i.decode(t)};return i.decodeWithTextDecoder=function(e){var t=new TextDecoder("utf-8");return t.decode(e)},i.decodeWithFromCharCode=function(e){for(var t="",r=e.length,i=0;r>i;++i)t+=String.fromCharCode(e[i]);return t},"undefined"!=typeof TextDecoder?i.decode=i.decodeWithTextDecoder:i.decode=i.decodeWithFromCharCode,i}),r("Core/getMagic",["../Core/defaultValue","../Core/getStringFromTypedArray"],function(e,t){"use strict";var r=function(r,i){return i=e(i,0),t(r,i,Math.min(4,r.length))};return r}),r("Core/objectToQuery",["./defined","./DeveloperError","./isArray"],function(e,t,r){"use strict";var i=function(e){var t="";for(var i in e)if(e.hasOwnProperty(i)){var n=e[i],o=encodeURIComponent(i)+"=";if(r(n))for(var a=0,s=n.length;s>a;++a)t+=o+encodeURIComponent(n[a])+"&";else t+=o+encodeURIComponent(n)+"&"}return t=t.slice(0,-1)};return i}),r("Core/queryToObject",["./defined","./DeveloperError","./isArray"],function(e,t,r){"use strict";var i=function(t){var i={};if(""===t)return i;for(var n=t.replace(/\+/g,"%20").split("&"),o=0,a=n.length;a>o;++o){var s=n[o].split("="),l=decodeURIComponent(s[0]),u=s[1];u=e(u)?decodeURIComponent(u):"";var c=i[l];"string"==typeof c?i[l]=[c,u]:r(c)?c.push(u):i[l]=u}return i};return i}),r("Core/loadJsonp",["../ThirdParty/Uri","../ThirdParty/when","./combine","./defaultValue","./defined","./DeveloperError","./objectToQuery","./queryToObject"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(o,u){u=i(u,i.EMPTY_OBJECT);var c;do c="loadJsonp"+Math.random().toString().substring(2,8);while(n(window[c]));var h=t.defer();window[c]=function(e){h.resolve(e);try{delete window[c]}catch(t){window[c]=void 0}};var d=new e(o),p=s(i(d.query,""));n(u.parameters)&&(p=r(u.parameters,p));var m=i(u.callbackParameterName,"callback");p[m]=c,d.query=a(p),o=d.toString();var f=u.proxy;return n(f)&&(o=f.getURL(o)),l.loadAndExecuteScript(o,c,h),h.promise};return l.loadAndExecuteScript=function(e,t,r){var i=document.createElement("script");i.async=!0,i.src=e;var n=document.getElementsByTagName("head")[0];i.onload=function(){i.onload=void 0,n.removeChild(i)},i.onerror=function(e){r.reject(e)},n.appendChild(i)},l.defaultLoadAndExecuteScript=l.loadAndExecuteScript,l}),r("Core/jsonp",["./deprecationWarning","./loadJsonp"],function(e,t){"use strict";var r=function(r,i){return e("jsonp","jsonp is deprecated. Use loadJsonp instead."),t(r,i)};return r.loadAndExecuteScript=function(e,r,i){t.loadAndExecuteScript(e,r,i)},r.defaultLoadAndExecuteScript=r.loadAndExecuteScript,r}),r("Core/loadBlob",["./loadWithXhr"],function(e){"use strict";var t=function(t,r){return e({url:t,responseType:"blob",headers:r})};return t}),r("Core/loadImageFromTypedArray",["../ThirdParty/when","./defined","./DeveloperError","./loadImage"],function(e,t,r,i){"use strict";var n=function(t,r){var n=new Blob([t],{type:r}),o=window.URL.createObjectURL(n);return i(o,!1).then(function(e){return window.URL.revokeObjectURL(o),e},function(t){return window.URL.revokeObjectURL(o),e.reject(t)})};return n}),r("Core/loadImageViaBlob",["../ThirdParty/when","./loadBlob","./loadImage"],function(e,t,r){"use strict";var i=/^data:/,n=function(n){return i.test(n)?r(n):t(n).then(function(t){var i=window.URL.createObjectURL(t);return r(i,!1).then(function(e){return e.blob=t,window.URL.revokeObjectURL(i),e},function(t){return window.URL.revokeObjectURL(i),e.reject(t)})})},o=function(){try{var e=new XMLHttpRequest;return e.open("GET","#",!0),e.responseType="blob","blob"===e.responseType}catch(t){return!1}}();return o?n:r}),r("Core/mergeSort",["./defined","./DeveloperError"],function(e,t){"use strict";function r(e,t,r,i,a,s){var l,u,c=a-i+1,h=s-a,d=n,p=o;for(l=0;c>l;++l)d[l]=e[i+l];for(u=0;h>u;++u)p[u]=e[a+u+1];l=0,u=0;for(var m=i;s>=m;++m){var f=d[l],v=p[u];c>l&&(u>=h||t(f,v,r)<=0)?(e[m]=f,++l):h>u&&(e[m]=v,++u)}}function i(e,t,n,o,a){if(!(o>=a)){var s=Math.floor(.5*(o+a));i(e,t,n,o,s),i(e,t,n,s+1,a),r(e,t,n,o,s,a)}}var n=[],o=[],a=function(e,t,r){var a=e.length,s=Math.ceil(.5*a);n.length=s,o.length=s,i(e,t,r,0,a-1),n.length=0,o.length=0};return a}),r("Core/requestAnimationFrame",["./defined","./getTimestamp"],function(e,t){"use strict";var r=window.requestAnimationFrame;!function(){if(!e(r))for(var i=["webkit","moz","ms","o"],n=0,o=i.length;o>n&&!e(r);)r=window[i[n]+"RequestAnimationFrame"],++n;if(!e(r)){var a=1e3/60,s=0;r=function(e){var r=t(),i=Math.max(a-(r-s),0);return s=r+i,setTimeout(function(){e(s)},i)}}}();var i=function(e){return r(e)};return i}),r("Core/sampleTerrain",["../ThirdParty/when","./defined","./DeveloperError"],function(e,t,r){"use strict";function i(t,r,i){var a,s=t.tilingScheme,l=[],u={};for(a=0;an;){var o=Math.ceil((i-n)/t--);r.push(e.slice(n,n+o)),n+=o}return r};return r}),r("Core/wrapFunction",["./DeveloperError"],function(e){"use strict";var t=function(e,t,r){return function(){r.apply(e,arguments),t.apply(e,arguments)}};return t}),r("DataSources/ConstantProperty",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event"],function(e,t,r,i,n){"use strict";var o=function(e){this._value=void 0,this._hasClone=!1,this._hasEquals=!1,this._definitionChanged=new n,this.setValue(e)};return r(o.prototype,{isConstant:{value:!0},definitionChanged:{get:function(){return this._definitionChanged}}}),o.prototype.getValue=function(e,t){return this._hasClone?this._value.clone(t):this._value},o.prototype.setValue=function(e){var r=this._value;if(r!==e){var i=t(e),n=i&&"function"==typeof e.clone,o=i&&"function"==typeof e.equals;this._hasClone=n,this._hasEquals=o;var a=!o||!e.equals(r);a&&(this._value=n?e.clone():e,this._definitionChanged.raiseEvent(this))}},o.prototype.equals=function(e){return this===e||e instanceof o&&(!this._hasEquals&&this._value===e._value||this._hasEquals&&this._value.equals(e._value))},o}),r("DataSources/createPropertyDescriptor",["../Core/defaultValue","../Core/defined","./ConstantProperty"],function(e,t,r){"use strict";function i(e,r,i,n,o){return{configurable:n,get:function(){return this[r]},set:function(n){var a=this[r],s=this[i];t(s)&&(s(),this[i]=void 0);var l=t(n);l&&!t(n.getValue)&&t(o)&&(n=o(n)),a!==n&&(this[r]=n,this._definitionChanged.raiseEvent(this,e,n,a)),t(n)&&t(n.definitionChanged)&&(this[i]=n.definitionChanged.addEventListener(function(){this._definitionChanged.raiseEvent(this,e,n,n)},this))}}}function n(e){return new r(e)}function o(t,r,o){return i(t,"_"+t.toString(),"_"+t.toString()+"Subscription",e(r,!1),e(o,n))}return o}),r("DataSources/BillboardGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._image=void 0,this._imageSubscription=void 0,this._imageSubRegion=void 0,this._imageSubRegionSubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._scale=void 0,this._scaleSubscription=void 0,this._rotation=void 0,this._rotationSubscription=void 0,this._alignedAxis=void 0,this._alignedAxisSubscription=void 0,this._horizontalOrigin=void 0,this._horizontalOriginSubscription=void 0,this._verticalOrigin=void 0,this._verticalOriginSubscription=void 0,this._color=void 0,this._colorSubscription=void 0,this._eyeOffset=void 0,this._eyeOffsetSubscription=void 0,this._pixelOffset=void 0,this._pixelOffsetSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._scaleByDistance=void 0,this._scaleByDistanceSubscription=void 0,this._translucencyByDistance=void 0,this._translucencyByDistanceSubscription=void 0,this._pixelOffsetScaleByDistance=void 0,this._pixelOffsetScaleByDistanceSubscription=void 0,this._sizeInMeters=void 0,this._sizeInMetersSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},image:o("image"),imageSubRegion:o("imageSubRegion"),scale:o("scale"),rotation:o("rotation"),alignedAxis:o("alignedAxis"),horizontalOrigin:o("horizontalOrigin"),verticalOrigin:o("verticalOrigin"),color:o("color"),eyeOffset:o("eyeOffset"),pixelOffset:o("pixelOffset"),show:o("show"),width:o("width"),height:o("height"),scaleByDistance:o("scaleByDistance"),translucencyByDistance:o("translucencyByDistance"),pixelOffsetScaleByDistance:o("pixelOffsetScaleByDistance"),sizeInMeters:o("sizeInMeters")}),a.prototype.clone=function(e){return t(e)?(e.color=this._color,e.eyeOffset=this._eyeOffset,e.horizontalOrigin=this._horizontalOrigin,e.image=this._image,e.imageSubRegion=this._imageSubRegion,e.pixelOffset=this._pixelOffset,e.scale=this._scale,e.rotation=this._rotation,e.alignedAxis=this._alignedAxis,e.show=this._show,e.verticalOrigin=this._verticalOrigin,e.width=this._width,e.height=this._height,e.scaleByDistance=this._scaleByDistance,e.translucencyByDistance=this._translucencyByDistance,e.pixelOffsetScaleByDistance=this._pixelOffsetScaleByDistance,e.sizeInMeters=this._sizeInMeters,e):new a(this)},a.prototype.merge=function(t){this.color=e(this._color,t.color),this.eyeOffset=e(this._eyeOffset,t.eyeOffset),this.horizontalOrigin=e(this._horizontalOrigin,t.horizontalOrigin),this.image=e(this._image,t.image),this.imageSubRegion=e(this._imageSubRegion,t.imageSubRegion),this.pixelOffset=e(this._pixelOffset,t.pixelOffset),this.scale=e(this._scale,t.scale),this.rotation=e(this._rotation,t.rotation),this.alignedAxis=e(this._alignedAxis,t.alignedAxis),this.show=e(this._show,t.show),this.verticalOrigin=e(this._verticalOrigin,t.verticalOrigin),this.width=e(this._width,t.width),this.height=e(this._height,t.height),this.scaleByDistance=e(this._scaleByDistance,t.scaleByDistance),this.translucencyByDistance=e(this._translucencyByDistance,t.translucencyByDistance),this.pixelOffsetScaleByDistance=e(this._pixelOffsetScaleByDistance,t.pixelOffsetScaleByDistance),this.sizeInMeters=e(this._sizeInMeters,t.sizeInMeters)},a}),r("Renderer/BufferUsage",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={STREAM_DRAW:t.STREAM_DRAW,STATIC_DRAW:t.STATIC_DRAW,DYNAMIC_DRAW:t.DYNAMIC_DRAW,validate:function(e){return e===r.STREAM_DRAW||e===r.STATIC_DRAW||e===r.DYNAMIC_DRAW}};return e(r)}),r("Renderer/Buffer",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/IndexDatatype","./BufferUsage","./WebGLConstants"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.context._gl,n=r.bufferTarget,o=r.typedArray,a=r.sizeInBytes,s=r.usage,l=t(o);l&&(a=o.byteLength);var u=i.createBuffer();i.bindBuffer(n,u), +i.bufferData(n,l?o:a,s),i.bindBuffer(n,null),this._gl=i,this._bufferTarget=n,this._sizeInBytes=a,this._usage=s,this._buffer=u,this.vertexArrayDestroyable=!0};return l.createVertexBuffer=function(e){return new l({context:e.context,bufferTarget:s.ARRAY_BUFFER,typedArray:e.typedArray,sizeInBytes:e.sizeInBytes,usage:e.usage})},l.createIndexBuffer=function(e){var t=e.context,i=e.indexDatatype,n=o.getSizeInBytes(i),a=new l({context:t,bufferTarget:s.ELEMENT_ARRAY_BUFFER,typedArray:e.typedArray,sizeInBytes:e.sizeInBytes,usage:e.usage}),u=a.sizeInBytes/n;return r(a,{indexDatatype:{get:function(){return i}},bytesPerIndex:{get:function(){return n}},numberOfIndices:{get:function(){return u}}}),a},r(l.prototype,{sizeInBytes:{get:function(){return this._sizeInBytes}},usage:{get:function(){return this._usage}}}),l.prototype._getBuffer=function(){return this._buffer},l.prototype.copyFromArrayView=function(t,r){r=e(r,0);var i=this._gl,n=this._bufferTarget;i.bindBuffer(n,this._buffer),i.bufferSubData(n,r,t),i.bindBuffer(n,null)},l.prototype.isDestroyed=function(){return!1},l.prototype.destroy=function(){return this._gl.deleteBuffer(this._buffer),i(this)},l}),r("Renderer/DrawCommand",["../Core/defaultValue","../Core/PrimitiveType"],function(e,t){"use strict";var r=function(r){r=e(r,e.EMPTY_OBJECT),this.boundingVolume=r.boundingVolume,this.orientedBoundingBox=r.orientedBoundingBox,this.cull=e(r.cull,!0),this.modelMatrix=r.modelMatrix,this.primitiveType=e(r.primitiveType,t.TRIANGLES),this.vertexArray=r.vertexArray,this.count=r.count,this.offset=e(r.offset,0),this.instanceCount=e(r.instanceCount,0),this.shaderProgram=r.shaderProgram,this.uniformMap=r.uniformMap,this.renderState=r.renderState,this.framebuffer=r.framebuffer,this.pass=r.pass,this.executeInClosestFrustum=e(r.executeInClosestFrustum,!1),this.owner=r.owner,this.debugShowBoundingVolume=e(r.debugShowBoundingVolume,!1),this.debugOverlappingFrustums=0,this.oit=void 0};return r.prototype.execute=function(e,t,r,i){e.draw(this,t,r,i)},r}),r("Renderer/ContextLimits",["../Core/defineProperties"],function(e){"use strict";var t={_maximumCombinedTextureImageUnits:0,_maximumCubeMapSize:0,_maximumFragmentUniformVectors:0,_maximumTextureImageUnits:0,_maximumRenderbufferSize:0,_maximumTextureSize:0,_maximumVaryingVectors:0,_maximumVertexAttributes:0,_maximumVertexTextureImageUnits:0,_maximumVertexUniformVectors:0,_minimumAliasedLineWidth:0,_maximumAliasedLineWidth:0,_minimumAliasedPointSize:0,_maximumAliasedPointSize:0,_maximumViewportWidth:0,_maximumViewportHeight:0,_maximumTextureFilterAnisotropy:0,_maximumDrawBuffers:0,_maximumColorAttachments:0,_highpFloatSupported:!1,_highpIntSupported:!1};return e(t,{maximumCombinedTextureImageUnits:{get:function(){return t._maximumCombinedTextureImageUnits}},maximumCubeMapSize:{get:function(){return t._maximumCubeMapSize}},maximumFragmentUniformVectors:{get:function(){return t._maximumFragmentUniformVectors}},maximumTextureImageUnits:{get:function(){return t._maximumTextureImageUnits}},maximumRenderbufferSize:{get:function(){return t._maximumRenderbufferSize}},maximumTextureSize:{get:function(){return t._maximumTextureSize}},maximumVaryingVectors:{get:function(){return t._maximumVaryingVectors}},maximumVertexAttributes:{get:function(){return t._maximumVertexAttributes}},maximumVertexTextureImageUnits:{get:function(){return t._maximumVertexTextureImageUnits}},maximumVertexUniformVectors:{get:function(){return t._maximumVertexUniformVectors}},minimumAliasedLineWidth:{get:function(){return t._minimumAliasedLineWidth}},maximumAliasedLineWidth:{get:function(){return t._maximumAliasedLineWidth}},minimumAliasedPointSize:{get:function(){return t._minimumAliasedPointSize}},maximumAliasedPointSize:{get:function(){return t._maximumAliasedPointSize}},maximumViewportWidth:{get:function(){return t._maximumViewportWidth}},maximumViewportHeight:{get:function(){return t._maximumViewportHeight}},maximumTextureFilterAnisotropy:{get:function(){return t._maximumTextureFilterAnisotropy}},maximumDrawBuffers:{get:function(){return t._maximumDrawBuffers}},maximumColorAttachments:{get:function(){return t._maximumColorAttachments}},highpFloatSupported:{get:function(){return t._highpFloatSupported}},highpIntSupported:{get:function(){return t._highpIntSupported}}}),t}),r("Renderer/RenderState",["../Core/BoundingRectangle","../Core/Color","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/RuntimeError","../Core/WindingOrder","./ContextLimits","./WebGLConstants"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t,r){r?e.enable(t):e.disable(t)}function c(e,t){e.frontFace(t.frontFace)}function h(e,t){var r=t.cull,i=r.enabled;u(e,e.CULL_FACE,i),i&&e.cullFace(r.face)}function d(e,t){e.lineWidth(t.lineWidth)}function p(e,t){var r=t.polygonOffset,i=r.enabled;u(e,e.POLYGON_OFFSET_FILL,i),i&&e.polygonOffset(r.factor,r.units)}function m(e,t,r){var n=t.scissorTest,o=i(r.scissorTest)?r.scissorTest.enabled:n.enabled;if(u(e,e.SCISSOR_TEST,o),o){var a=i(r.scissorTest)?r.scissorTest.rectangle:n.rectangle;e.scissor(a.x,a.y,a.width,a.height)}}function f(e,t){var r=t.depthRange;e.depthRange(r.near,r.far)}function v(e,t){var r=t.depthTest,i=r.enabled;u(e,e.DEPTH_TEST,i),i&&e.depthFunc(r.func)}function _(e,t){var r=t.colorMask;e.colorMask(r.red,r.green,r.blue,r.alpha)}function g(e,t){e.depthMask(t.depthMask)}function y(e,t){e.stencilMask(t.stencilMask)}function C(e,t,r){var n=t.blending,o=i(r.blendingEnabled)?r.blendingEnabled:n.enabled;u(e,e.BLEND,o),o&&(P(e,n.color),e.blendEquationSeparate(n.equationRgb,n.equationAlpha),e.blendFuncSeparate(n.functionSourceRgb,n.functionDestinationRgb,n.functionSourceAlpha,n.functionDestinationAlpha))}function E(e,t){var r=t.stencilTest,i=r.enabled;if(u(e,e.STENCIL_TEST,i),i){var n=r.frontFunction,o=r.backFunction,a=r.reference,s=r.mask;e.stencilFunc(r.frontFunction,r.reference,r.mask),e.stencilFuncSeparate(e.BACK,o,a,s),e.stencilFuncSeparate(e.FRONT,n,a,s);var l=r.frontOperation,c=l.fail,h=l.zFail,d=l.zPass;e.stencilOpSeparate(e.FRONT,c,h,d);var p=r.backOperation,m=p.fail,f=p.zFail,v=p.zPass;e.stencilOpSeparate(e.BACK,m,f,v)}}function S(e,t,r){var n=t.viewport;i(n)||(n=I,n.width=r.context.drawingBufferWidth,n.height=r.context.drawingBufferHeight),r.context.uniformState.viewport=n,e.viewport(n.x,n.y,n.width,n.height)}function w(e,t){var r=[];return e.frontFace!==t.frontFace&&r.push(c),(e.cull.enabled!==t.cull.enabled||e.cull.face!==t.cull.face)&&r.push(h),e.lineWidth!==t.lineWidth&&r.push(d),(e.polygonOffset.enabled!==t.polygonOffset.enabled||e.polygonOffset.factor!==t.polygonOffset.factor||e.polygonOffset.units!==t.polygonOffset.units)&&r.push(p),(e.depthRange.near!==t.depthRange.near||e.depthRange.far!==t.depthRange.far)&&r.push(f),(e.depthTest.enabled!==t.depthTest.enabled||e.depthTest.func!==t.depthTest.func)&&r.push(v),(e.colorMask.red!==t.colorMask.red||e.colorMask.green!==t.colorMask.green||e.colorMask.blue!==t.colorMask.blue||e.colorMask.alpha!==t.colorMask.alpha)&&r.push(_),e.depthMask!==t.depthMask&&r.push(g),e.stencilMask!==t.stencilMask&&r.push(y),(e.stencilTest.enabled!==t.stencilTest.enabled||e.stencilTest.frontFunction!==t.stencilTest.frontFunction||e.stencilTest.backFunction!==t.stencilTest.backFunction||e.stencilTest.reference!==t.stencilTest.reference||e.stencilTest.mask!==t.stencilTest.mask||e.stencilTest.frontOperation.fail!==t.stencilTest.frontOperation.fail||e.stencilTest.frontOperation.zFail!==t.stencilTest.frontOperation.zFail||e.stencilTest.backOperation.fail!==t.stencilTest.backOperation.fail||e.stencilTest.backOperation.zFail!==t.stencilTest.backOperation.zFail||e.stencilTest.backOperation.zPass!==t.stencilTest.backOperation.zPass)&&r.push(E),(e.sampleCoverage.enabled!==t.sampleCoverage.enabled||e.sampleCoverage.value!==t.sampleCoverage.value||e.sampleCoverage.invert!==t.sampleCoverage.invert)&&r.push(A),r}var T=function(n){var o=r(n,{}),s=r(o.cull,{}),u=r(o.polygonOffset,{}),c=r(o.scissorTest,{}),h=r(c.rectangle,{}),d=r(o.depthRange,{}),p=r(o.depthTest,{}),m=r(o.colorMask,{}),f=r(o.blending,{}),v=r(f.color,{}),_=r(o.stencilTest,{}),g=r(_.frontOperation,{}),y=r(_.backOperation,{}),C=r(o.sampleCoverage,{}),E=o.viewport;this.frontFace=r(o.frontFace,a.COUNTER_CLOCKWISE),this.cull={enabled:r(s.enabled,!1),face:r(s.face,l.BACK)},this.lineWidth=r(o.lineWidth,1),this.polygonOffset={enabled:r(u.enabled,!1),factor:r(u.factor,0),units:r(u.units,0)},this.scissorTest={enabled:r(c.enabled,!1),rectangle:e.clone(h)},this.depthRange={near:r(d.near,0),far:r(d.far,1)},this.depthTest={enabled:r(p.enabled,!1),func:r(p.func,l.LESS)},this.colorMask={red:r(m.red,!0),green:r(m.green,!0),blue:r(m.blue,!0),alpha:r(m.alpha,!0)},this.depthMask=r(o.depthMask,!0),this.stencilMask=r(o.stencilMask,-1),this.blending={enabled:r(f.enabled,!1),color:new t(r(v.red,0),r(v.green,0),r(v.blue,0),r(v.alpha,0)),equationRgb:r(f.equationRgb,l.FUNC_ADD),equationAlpha:r(f.equationAlpha,l.FUNC_ADD),functionSourceRgb:r(f.functionSourceRgb,l.ONE),functionSourceAlpha:r(f.functionSourceAlpha,l.ONE),functionDestinationRgb:r(f.functionDestinationRgb,l.ZERO),functionDestinationAlpha:r(f.functionDestinationAlpha,l.ZERO)},this.stencilTest={enabled:r(_.enabled,!1),frontFunction:r(_.frontFunction,l.ALWAYS),backFunction:r(_.backFunction,l.ALWAYS),reference:r(_.reference,0),mask:r(_.mask,-1),frontOperation:{fail:r(g.fail,l.KEEP),zFail:r(g.zFail,l.KEEP),zPass:r(g.zPass,l.KEEP)},backOperation:{fail:r(y.fail,l.KEEP),zFail:r(y.zFail,l.KEEP),zPass:r(y.zPass,l.KEEP)}},this.sampleCoverage={enabled:r(C.enabled,!1),value:r(C.value,1),invert:r(C.invert,!1)},this.viewport=i(E)?new e(E.x,E.y,E.width,E.height):void 0,this.id=0,this._applyFunctions=[]},b=0,x={};T.fromCache=function(e){var t=JSON.stringify(e),r=x[t];if(i(r))return++r.referenceCount,r.state;var n=new T(e),o=JSON.stringify(n);return r=x[o],i(r)||(n.id=b++,r={referenceCount:0,state:n},x[o]=r),++r.referenceCount,x[t]={referenceCount:1,state:r.state},r.state},T.removeFromCache=function(e){var t=new T(e),r=JSON.stringify(t),n=x[r],o=JSON.stringify(e),a=x[o];i(a)&&(--a.referenceCount,0===a.referenceCount&&(delete x[o],i(n)&&--n.referenceCount)),i(n)&&0===n.referenceCount&&delete x[r]},T.getCache=function(){return x},T.clearCache=function(){x={}};var P=function(e,t){e.blendColor(t.red,t.green,t.blue,t.alpha)},A=function(e,t){var r=t.sampleCoverage,i=r.enabled;u(e,e.SAMPLE_COVERAGE,i),i&&e.sampleCoverage(r.value,r.invert)},I=new e;return T.apply=function(e,t,r){c(e,t),h(e,t),d(e,t),p(e,t),f(e,t),v(e,t),_(e,t),g(e,t),y(e,t),E(e,t),A(e,t),m(e,t,r),C(e,t,r),S(e,t,r)},T.partialApply=function(e,t,r,n,o,a){if(t!==r){var s=r._applyFunctions[t.id];i(s)||(s=w(t,r),r._applyFunctions[t.id]=s);for(var l=s.length,u=0;l>u;++u)s[u](e,r)}var c=i(n.scissorTest)?n.scissorTest:t.scissorTest,h=i(o.scissorTest)?o.scissorTest:r.scissorTest;(c!==h||a)&&m(e,r,o);var d=i(n.blendingEnabled)?n.blendingEnabled:t.blending.enabled,p=i(o.blendingEnabled)?o.blendingEnabled:r.blending.enabled;(d!==p||p&&t.blending!==r.blending)&&C(e,r,o),(t!==r||n.context!==o.context)&&S(e,r,o)},T.getState=function(r){return{frontFace:r.frontFace,cull:{enabled:r.cull.enabled,face:r.cull.face},lineWidth:r.lineWidth,polygonOffset:{enabled:r.polygonOffset.enabled,factor:r.polygonOffset.factor,units:r.polygonOffset.units},scissorTest:{enabled:r.scissorTest.enabled,rectangle:e.clone(r.scissorTest.rectangle)},depthRange:{near:r.depthRange.near,far:r.depthRange.far},depthTest:{enabled:r.depthTest.enabled,func:r.depthTest.func},colorMask:{red:r.colorMask.red,green:r.colorMask.green,blue:r.colorMask.blue,alpha:r.colorMask.alpha},depthMask:r.depthMask,stencilMask:r.stencilMask,blending:{enabled:r.blending.enabled,color:t.clone(r.blending.color),equationRgb:r.blending.equationRgb,equationAlpha:r.blending.equationAlpha,functionSourceRgb:r.blending.functionSourceRgb,functionSourceAlpha:r.blending.functionSourceAlpha,functionDestinationRgb:r.blending.functionDestinationRgb,functionDestinationAlpha:r.blending.functionDestinationAlpha},stencilTest:{enabled:r.stencilTest.enabled,frontFunction:r.stencilTest.frontFunction,backFunction:r.stencilTest.backFunction,reference:r.stencilTest.reference,mask:r.stencilTest.mask,frontOperation:{fail:r.stencilTest.frontOperation.fail,zFail:r.stencilTest.frontOperation.zFail,zPass:r.stencilTest.frontOperation.zPass},backOperation:{fail:r.stencilTest.backOperation.fail,zFail:r.stencilTest.backOperation.zFail,zPass:r.stencilTest.backOperation.zPass}},sampleCoverage:{enabled:r.sampleCoverage.enabled,value:r.sampleCoverage.value,invert:r.sampleCoverage.invert},viewport:i(r.viewport)?e.clone(r.viewport):void 0}},T}),r("Renderer/AutomaticUniforms",["../Core/Cartesian3","../Core/Matrix4","./WebGLConstants"],function(e,t,r){"use strict";var i=new e,n=function(e){this._size=e.size,this._datatype=e.datatype,this.getValue=e.getValue};if("undefined"==typeof WebGLRenderingContext)return{};var o={};o[r.FLOAT]="float",o[r.FLOAT_VEC2]="vec2",o[r.FLOAT_VEC3]="vec3",o[r.FLOAT_VEC4]="vec4",o[r.INT]="int",o[r.INT_VEC2]="ivec2",o[r.INT_VEC3]="ivec3",o[r.INT_VEC4]="ivec4",o[r.BOOL]="bool",o[r.BOOL_VEC2]="bvec2",o[r.BOOL_VEC3]="bvec3",o[r.BOOL_VEC4]="bvec4",o[r.FLOAT_MAT2]="mat2",o[r.FLOAT_MAT3]="mat3",o[r.FLOAT_MAT4]="mat4",o[r.SAMPLER_2D]="sampler2D",o[r.SAMPLER_CUBE]="samplerCube",n.prototype.getDeclaration=function(e){var t="uniform "+o[this._datatype]+" "+e,r=this._size;return t+=1===r?";":"["+r.toString()+"];"};var a={czm_viewport:new n({size:1,datatype:r.FLOAT_VEC4,getValue:function(e){return e.viewportCartesian4}}),czm_viewportOrthographic:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.viewportOrthographic}}),czm_viewportTransformation:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.viewportTransformation}}),czm_globeDepthTexture:new n({size:1,datatype:r.SAMPLER_2D,getValue:function(e){return e.globeDepthTexture}}),czm_model:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.model}}),czm_inverseModel:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModel}}),czm_view:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.view}}),czm_view3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.view3D}}),czm_viewRotation:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.viewRotation}}),czm_viewRotation3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.viewRotation3D}}),czm_inverseView:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseView}}),czm_inverseView3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseView3D}}),czm_inverseViewRotation:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseViewRotation}}),czm_inverseViewRotation3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseViewRotation3D}}),czm_projection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.projection}}),czm_inverseProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseProjection}}),czm_inverseProjectionOIT:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseProjectionOIT}}),czm_infiniteProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.infiniteProjection}}),czm_modelView:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelView}}),czm_modelView3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelView3D}}),czm_modelViewRelativeToEye:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewRelativeToEye}}),czm_inverseModelView:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModelView}}),czm_inverseModelView3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModelView3D}}),czm_viewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.viewProjection}}),czm_inverseViewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseViewProjection}}),czm_modelViewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewProjection}}),czm_inverseModelViewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModelViewProjection}}),czm_modelViewProjectionRelativeToEye:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewProjectionRelativeToEye}}),czm_modelViewInfiniteProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewInfiniteProjection}}),czm_normal:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.normal}}),czm_normal3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.normal3D}}),czm_inverseNormal:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseNormal}}),czm_inverseNormal3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseNormal3D}}),czm_eyeHeight2D:new n({size:1,datatype:r.FLOAT_VEC2,getValue:function(e){return e.eyeHeight2D}}),czm_entireFrustum:new n({size:1,datatype:r.FLOAT_VEC2,getValue:function(e){return e.entireFrustum}}),czm_currentFrustum:new n({size:1,datatype:r.FLOAT_VEC2,getValue:function(e){return e.currentFrustum}}),czm_frustumPlanes:new n({size:1,datatype:r.FLOAT_VEC4,getValue:function(e){return e.frustumPlanes}}),czm_sunPositionWC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunPositionWC}}),czm_sunPositionColumbusView:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunPositionColumbusView}}),czm_sunDirectionEC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunDirectionEC}}),czm_sunDirectionWC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunDirectionWC}}),czm_moonDirectionEC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.moonDirectionEC}}),czm_encodedCameraPositionMCHigh:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.encodedCameraPositionMCHigh}}),czm_encodedCameraPositionMCLow:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.encodedCameraPositionMCLow}}),czm_viewerPositionWC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return t.getTranslation(e.inverseView,i)}}),czm_frameNumber:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.frameState.frameNumber}}),czm_morphTime:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.frameState.morphTime}}),czm_sceneMode:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.frameState.mode}}),czm_temeToPseudoFixed:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.temeToPseudoFixedMatrix}}),czm_resolutionScale:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.resolutionScale}}),czm_fogDensity:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.fogDensity}})};return a}),r("Renderer/createUniform",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/defined","../Core/DeveloperError","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Core/RuntimeError"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t,r,i){this.name=r,this.value=void 0,this._value=0,this._gl=e,this._location=i}function h(t,r,i,n){this.name=i,this.value=void 0,this._value=new e,this._gl=t,this._location=n}function d(e,t,r,i){this.name=r,this.value=void 0,this._value=void 0,this._gl=e,this._location=i}function p(e,t,r,i){this.name=r,this.value=void 0,this._value=void 0,this._gl=e,this._location=i}function m(e,t,r,i){this.name=r,this.value=void 0,this._gl=e,this._location=i,this.textureUnitIndex=void 0}function f(e,t,r,i){this.name=r,this.value=void 0,this._value=0,this._gl=e,this._location=i}function v(t,r,i,n){this.name=i,this.value=void 0,this._value=new e,this._gl=t,this._location=n}function _(e,r,i,n){this.name=i,this.value=void 0,this._value=new t,this._gl=e,this._location=n}function g(e,t,i,n){this.name=i,this.value=void 0,this._value=new r,this._gl=e,this._location=n}function y(e,t,r,i){this.name=r,this.value=void 0,this._value=new Float32Array(4),this._gl=e,this._location=i}function C(e,t,r,i){this.name=r,this.value=void 0,this._value=new Float32Array(9),this._gl=e,this._location=i}function E(e,t,r,i){this.name=r,this.value=void 0,this._value=new Float32Array(16),this._gl=e,this._location=i}var S=function(e,t,r,i){switch(t.type){case e.FLOAT:return new c(e,t,r,i);case e.FLOAT_VEC2:return new h(e,t,r,i);case e.FLOAT_VEC3:return new d(e,t,r,i);case e.FLOAT_VEC4:return new p(e,t,r,i);case e.SAMPLER_2D:case e.SAMPLER_CUBE:return new m(e,t,r,i);case e.INT:case e.BOOL:return new f(e,t,r,i);case e.INT_VEC2:case e.BOOL_VEC2:return new v(e,t,r,i);case e.INT_VEC3:case e.BOOL_VEC3:return new _(e,t,r,i);case e.INT_VEC4:case e.BOOL_VEC4:return new g(e,t,r,i);case e.FLOAT_MAT2:return new y(e,t,r,i);case e.FLOAT_MAT3:return new C(e,t,r,i);case e.FLOAT_MAT4:return new E(e,t,r,i);default:throw new u("Unrecognized uniform type: "+t.type+' for uniform "'+r+'".')}};return c.prototype.set=function(){this.value!==this._value&&(this._value=this.value,this._gl.uniform1f(this._location,this.value))},h.prototype.set=function(){var t=this.value;e.equals(t,this._value)||(e.clone(t,this._value),this._gl.uniform2f(this._location,t.x,t.y))},d.prototype.set=function(){var e=this.value;if(n(e.red))i.equals(e,this._value)||(this._value=i.clone(e,this._value),this._gl.uniform3f(this._location,e.red,e.green,e.blue));else{if(!n(e.x))throw new o('Invalid vec3 value for uniform "'+this._activethis.name+'".');t.equals(e,this._value)||(this._value=t.clone(e,this._value),this._gl.uniform3f(this._location,e.x,e.y,e.z))}},p.prototype.set=function(){var e=this.value;if(n(e.red))i.equals(e,this._value)||(this._value=i.clone(e,this._value),this._gl.uniform4f(this._location,e.red,e.green,e.blue,e.alpha));else{if(!n(e.x))throw new o('Invalid vec4 value for uniform "'+this._activethis.name+'".');r.equals(e,this._value)||(this._value=r.clone(e,this._value),this._gl.uniform4f(this._location,e.x,e.y,e.z,e.w))}},m.prototype.set=function(){var e=this._gl;e.activeTexture(e.TEXTURE0+this.textureUnitIndex);var t=this.value;e.bindTexture(t._target,t._texture)},m.prototype._setSampler=function(e){return this.textureUnitIndex=e,this._gl.uniform1i(this._location,e),e+1},f.prototype.set=function(){this.value!==this._value&&(this._value=this.value,this._gl.uniform1i(this._location,this.value))},v.prototype.set=function(){var t=this.value;e.equals(t,this._value)||(e.clone(t,this._value),this._gl.uniform2i(this._location,t.x,t.y))},_.prototype.set=function(){var e=this.value;t.equals(e,this._value)||(t.clone(e,this._value),this._gl.uniform3i(this._location,e.x,e.y,e.z))},g.prototype.set=function(){var e=this.value;r.equals(e,this._value)||(r.clone(e,this._value),this._gl.uniform4i(this._location,e.x,e.y,e.z,e.w))},y.prototype.set=function(){a.equalsArray(this.value,this._value,0)||(a.toArray(this.value,this._value),this._gl.uniformMatrix2fv(this._location,!1,this._value))},C.prototype.set=function(){s.equalsArray(this.value,this._value,0)||(s.toArray(this.value,this._value),this._gl.uniformMatrix3fv(this._location,!1,this._value))},E.prototype.set=function(){l.equalsArray(this.value,this._value,0)||(l.toArray(this.value,this._value),this._gl.uniformMatrix4fv(this._location,!1,this._value))},S}),r("Renderer/createUniformArray",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Core/RuntimeError"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(n),this._gl=e,this._location=i[0]}function d(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(2*n),this._gl=e,this._location=i[0]}function p(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(3*n),this._gl=e,this._location=i[0]}function m(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(4*n),this._gl=e,this._location=i[0]}function f(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(n),this._gl=e,this._locations=i,this.textureUnitIndex=void 0}function v(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(n),this._gl=e,this._location=i[0]}function _(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(2*n),this._gl=e,this._location=i[0]}function g(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(3*n),this._gl=e,this._location=i[0]}function y(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(4*n),this._gl=e,this._location=i[0]}function C(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(4*n),this._gl=e,this._location=i[0]}function E(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(9*n),this._gl=e,this._location=i[0]}function S(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(16*n),this._gl=e,this._location=i[0]}var w=function(e,t,r,i){switch(t.type){case e.FLOAT:return new h(e,t,r,i);case e.FLOAT_VEC2:return new d(e,t,r,i);case e.FLOAT_VEC3:return new p(e,t,r,i);case e.FLOAT_VEC4:return new m(e,t,r,i);case e.SAMPLER_2D:case e.SAMPLER_CUBE:return new f(e,t,r,i);case e.INT:case e.BOOL:return new v(e,t,r,i);case e.INT_VEC2:case e.BOOL_VEC2:return new _(e,t,r,i);case e.INT_VEC3:case e.BOOL_VEC3:return new g(e,t,r,i);case e.INT_VEC4:case e.BOOL_VEC4:return new y(e,t,r,i);case e.FLOAT_MAT2:return new C(e,t,r,i);case e.FLOAT_MAT3:return new E(e,t,r,i);case e.FLOAT_MAT4:return new S(e,t,r,i);default:throw new c("Unrecognized uniform type: "+t.type+' for uniform "'+r+'".')}};return h.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0;t>n;++n){var o=e[n];o!==r[n]&&(r[n]=o,i=!0)}i&&this._gl.uniform1fv(this._location,r)},d.prototype.set=function(){for(var t=this.value,r=t.length,i=this._value,n=!1,o=0,a=0;r>a;++a){var s=t[a];e.equalsArray(s,i,o)||(e.pack(s,i,o),n=!0),o+=2}n&&this._gl.uniform2fv(this._location,i)},p.prototype.set=function(){for(var e=this.value,r=e.length,i=this._value,o=!1,s=0,l=0;r>l;++l){var u=e[l];if(n(u.red))(u.red!==i[s]||u.green!==i[s+1]||u.blue!==i[s+2])&&(i[s]=u.red,i[s+1]=u.green,i[s+2]=u.blue,o=!0);else{if(!n(u.x))throw new a("Invalid vec3 value.");t.equalsArray(u,i,s)||(t.pack(u,i,s),o=!0)}s+=3}o&&this._gl.uniform3fv(this._location,i)},m.prototype.set=function(){for(var e=this.value,t=e.length,o=this._value,s=!1,l=0,u=0;t>u;++u){var c=e[u];if(n(c.red))i.equalsArray(c,o,l)||(i.pack(c,o,l),s=!0);else{if(!n(c.x))throw new a("Invalid vec4 value.");r.equalsArray(c,o,l)||(r.pack(c,o,l),s=!0)}l+=4}s&&this._gl.uniform4fv(this._location,o)},f.prototype.set=function(){for(var e=this._gl,t=e.TEXTURE0+this.textureUnitIndex,r=this.value,i=r.length,n=0;i>n;++n){var o=r[n];e.activeTexture(t+n),e.bindTexture(o._target,o._texture)}},f.prototype._setSampler=function(e){this.textureUnitIndex=e;for(var t=this._locations,r=t.length,i=0;r>i;++i){var n=e+i;this._gl.uniform1i(t[i],n)}return e+r},v.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0;t>n;++n){var o=e[n];o!==r[n]&&(r[n]=o,i=!0)}i&&this._gl.uniform1iv(this._location,r)},_.prototype.set=function(){for(var t=this.value,r=t.length,i=this._value,n=!1,o=0,a=0;r>a;++a){var s=t[a];e.equalsArray(s,i,o)||(e.pack(s,i,o),n=!0),o+=2}n&&this._gl.uniform2iv(this._location,i)},g.prototype.set=function(){for(var e=this.value,r=e.length,i=this._value,n=!1,o=0,a=0;r>a;++a){var s=e[a];t.equalsArray(s,i,o)||(t.pack(s,i,o),n=!0),o+=3}n&&this._gl.uniform3iv(this._location,i)},y.prototype.set=function(){for(var e=this.value,t=e.length,i=this._value,n=!1,o=0,a=0;t>a;++a){var s=e[a];r.equalsArray(s,i,o)||(r.pack(s,i,o),n=!0),o+=4}n&&this._gl.uniform4iv(this._location,i)},C.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0,o=0;t>o;++o){var a=e[o];s.equalsArray(a,r,n)||(s.pack(a,r,n),i=!0),n+=4}i&&this._gl.uniformMatrix2fv(this._location,!1,r)},E.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0,o=0;t>o;++o){var a=e[o];l.equalsArray(a,r,n)||(l.pack(a,r,n),i=!0),n+=9}i&&this._gl.uniformMatrix3fv(this._location,!1,r)},S.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0,o=0;t>o;++o){var a=e[o];u.equalsArray(a,r,n)||(u.pack(a,r,n),i=!0),n+=16}i&&this._gl.uniformMatrix4fv(this._location,!1,r)},w}),r("Renderer/ShaderProgram",["../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/RuntimeError","./AutomaticUniforms","./ContextLimits","./createUniform","./createUniformArray"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e){var t=[],i=e.match(/uniform.*?(?![^{]*})(?=[=\[;])/g);if(r(i))for(var n=i.length,o=0;n>o;o++){var a=i[o].trim(),s=a.slice(a.lastIndexOf(" ")+1);t.push(s)}return t}function d(e,t){var r={};if(!l.highpFloatSupported||!l.highpIntSupported){var i,n,o,a,s=h(e),u=h(t),c=s.length,d=u.length;for(i=0;c>i;i++)for(n=0;d>n;n++)if(s[i]===u[n]){o=s[i],a="czm_mediump_"+o;var p=new RegExp(o+"\\b","g");t=t.replace(p,a),r[a]=o}}return{fragmentShaderText:t,duplicateUniformNames:r}}function p(e,r){var i=r._vertexShaderText,n=r._fragmentShaderText,o=e.createShader(e.VERTEX_SHADER);e.shaderSource(o,i),e.compileShader(o);var s=e.createShader(e.FRAGMENT_SHADER);e.shaderSource(s,n),e.compileShader(s);var l=e.createProgram();e.attachShader(l,o),e.attachShader(l,s),e.deleteShader(o),e.deleteShader(s);var u=r._attributeLocations;if(t(u))for(var c in u)u.hasOwnProperty(c)&&e.bindAttribLocation(l,u[c],c);e.linkProgram(l);var h;if(!e.getProgramParameter(l,e.LINK_STATUS)){var d=r._debugShaders;if(!e.getShaderParameter(s,e.COMPILE_STATUS)){if(h=e.getShaderInfoLog(s),console.error(E+"Fragment shader compile log: "+h),t(d)){var p=d.getTranslatedShaderSource(s);""!==p?console.error(E+"Translated fragment shader source:\n"+p):console.error(E+"Fragment shader translation failed.")}throw e.deleteProgram(l),new a("Fragment shader failed to compile. Compile log: "+h)}if(!e.getShaderParameter(o,e.COMPILE_STATUS)){if(h=e.getShaderInfoLog(o),console.error(E+"Vertex shader compile log: "+h),t(d)){var m=d.getTranslatedShaderSource(o);""!==m?console.error(E+"Translated vertex shader source:\n"+m):console.error(E+"Vertex shader translation failed.")}throw e.deleteProgram(l),new a("Vertex shader failed to compile. Compile log: "+h)}throw h=e.getProgramInfoLog(l),console.error(E+"Shader program link log: "+h),t(d)&&(console.error(E+"Translated vertex shader source:\n"+d.getTranslatedShaderSource(o)),console.error(E+"Translated fragment shader source:\n"+d.getTranslatedShaderSource(s))),e.deleteProgram(l),new a("Program failed to link. Link log: "+h)}var f=r._logShaderCompilation;return f&&(h=e.getShaderInfoLog(o),t(h)&&h.length>0&&console.log(E+"Vertex shader compile log: "+h)),f&&(h=e.getShaderInfoLog(s),t(h)&&h.length>0&&console.log(E+"Fragment shader compile log: "+h)),f&&(h=e.getProgramInfoLog(l),t(h)&&h.length>0&&console.log(E+"Shader program link log: "+h)),l}function m(e,t,r){for(var i={},n=0;r>n;++n){var o=e.getActiveAttrib(t,n),a=e.getAttribLocation(t,o.name);i[o.name]={name:o.name,type:o.type,index:a}}return i}function f(e,r){for(var i={},n=[],o=[],a=e.getProgramParameter(r,e.ACTIVE_UNIFORMS),s=0;a>s;++s){var l=e.getActiveUniform(r,s),h="[0]",d=-1!==l.name.indexOf(h,l.name.length-h.length)?l.name.slice(0,l.name.length-3):l.name;if(0!==d.indexOf("gl_"))if(l.name.indexOf("[")<0){var p=e.getUniformLocation(r,d);if(null!==p){var m=u(e,l,d,p);i[d]=m,n.push(m),m._setSampler&&o.push(m)}}else{var f,v,_,g,y=d.indexOf("[");if(y>=0){if(f=i[d.slice(0,y)],!t(f))continue;v=f._locations, +v.length<=1&&(_=f.value,g=e.getUniformLocation(r,d),null!==g&&(v.push(g),_.push(e.getUniform(r,g))))}else{v=[];for(var C=0;Co;++o)i=r[o]._setSampler(i);return e.useProgram(null),i}function g(e){if(!t(e._program)){var r=e._gl,i=p(r,e,e._debugShaders),n=r.getProgramParameter(i,r.ACTIVE_ATTRIBUTES),o=f(r,i),a=v(e,o.uniformsByName);e._program=i,e._numberOfVertexAttributes=n,e._vertexAttributes=m(r,i,n),e._uniformsByName=o.uniformsByName,e._uniforms=o.uniforms,e._automaticUniforms=a.automaticUniforms,e._manualUniforms=a.manualUniforms,e.maximumTextureUnitIndex=_(r,i,o.samplerUniforms)}}var y=0,C=function(e){var t=d(e.vertexShaderText,e.fragmentShaderText);this._gl=e.gl,this._logShaderCompilation=e.logShaderCompilation,this._debugShaders=e.debugShaders,this._attributeLocations=e.attributeLocations,this._program=void 0,this._numberOfVertexAttributes=void 0,this._vertexAttributes=void 0,this._uniformsByName=void 0,this._uniforms=void 0,this._automaticUniforms=void 0,this._manualUniforms=void 0,this._duplicateUniformNames=t.duplicateUniformNames,this._cachedShader=void 0,this.maximumTextureUnitIndex=void 0,this._vertexShaderSource=e.vertexShaderSource,this._vertexShaderText=e.vertexShaderText,this._fragmentShaderSource=e.fragmentShaderSource,this._fragmentShaderText=t.fragmentShaderText,this.id=y++};C.fromCache=function(t){return t=e(t,e.EMPTY_OBJECT),t.context.shaderCache.getShaderProgram(t)},C.replaceCache=function(t){return t=e(t,e.EMPTY_OBJECT),t.context.shaderCache.replaceShaderProgram(t)},i(C.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},vertexAttributes:{get:function(){return g(this),this._vertexAttributes}},numberOfVertexAttributes:{get:function(){return g(this),this._numberOfVertexAttributes}},allUniforms:{get:function(){return g(this),this._uniformsByName}}});var E="[Cesium WebGL] ";return C.prototype._bind=function(){g(this),this._gl.useProgram(this._program)},C.prototype._setUniforms=function(e,r,i){var n,a;if(t(e)){var s=this._manualUniforms;for(n=s.length,a=0;n>a;++a){var l=s[a];l.value=e[l.name]()}}var u=this._automaticUniforms;for(n=u.length,a=0;n>a;++a){var c=u[a];c.uniform.value=c.automaticUniform.getValue(r)}var h=this._uniforms;for(n=h.length,a=0;n>a;++a)h[a].set();if(i){var d=this._gl,p=this._program;if(d.validateProgram(p),!d.getProgramParameter(p,d.VALIDATE_STATUS))throw new o("Program validation failed. Program info log: "+d.getProgramInfoLog(p))}},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){return void this._cachedShader.cache.releaseShaderProgram(this)},C.prototype.finalDestroy=function(){return this._gl.deleteProgram(this._program),n(this)},C}),r("Shaders/Builtin/Constants/degreesPerRadian",[],function(){"use strict";return"const float czm_degreesPerRadian = 57.29577951308232;\n"}),r("Shaders/Builtin/Constants/depthRange",[],function(){"use strict";return"const czm_depthRangeStruct czm_depthRange = czm_depthRangeStruct(0.0, 1.0);\n"}),r("Shaders/Builtin/Constants/epsilon1",[],function(){"use strict";return"const float czm_epsilon1 = 0.1;\n"}),r("Shaders/Builtin/Constants/epsilon2",[],function(){"use strict";return"const float czm_epsilon2 = 0.01;\n"}),r("Shaders/Builtin/Constants/epsilon3",[],function(){"use strict";return"const float czm_epsilon3 = 0.001;\n"}),r("Shaders/Builtin/Constants/epsilon4",[],function(){"use strict";return"const float czm_epsilon4 = 0.0001;\n"}),r("Shaders/Builtin/Constants/epsilon5",[],function(){"use strict";return"const float czm_epsilon5 = 0.00001;\n"}),r("Shaders/Builtin/Constants/epsilon6",[],function(){"use strict";return"const float czm_epsilon6 = 0.000001;\n"}),r("Shaders/Builtin/Constants/epsilon7",[],function(){"use strict";return"const float czm_epsilon7 = 0.0000001;\n"}),r("Shaders/Builtin/Constants/infinity",[],function(){"use strict";return"const float czm_infinity = 5906376272000.0;\n"}),r("Shaders/Builtin/Constants/oneOverPi",[],function(){"use strict";return"const float czm_oneOverPi = 0.3183098861837907;\n"}),r("Shaders/Builtin/Constants/oneOverTwoPi",[],function(){"use strict";return"const float czm_oneOverTwoPi = 0.15915494309189535;\n"}),r("Shaders/Builtin/Constants/pi",[],function(){"use strict";return"const float czm_pi = 3.141592653589793;\n"}),r("Shaders/Builtin/Constants/piOverFour",[],function(){"use strict";return"const float czm_piOverFour = 0.7853981633974483;\n"}),r("Shaders/Builtin/Constants/piOverSix",[],function(){"use strict";return"const float czm_piOverSix = 0.5235987755982988;\n"}),r("Shaders/Builtin/Constants/piOverThree",[],function(){"use strict";return"const float czm_piOverThree = 1.0471975511965976;\n"}),r("Shaders/Builtin/Constants/piOverTwo",[],function(){"use strict";return"const float czm_piOverTwo = 1.5707963267948966;\n"}),r("Shaders/Builtin/Constants/radiansPerDegree",[],function(){"use strict";return"const float czm_radiansPerDegree = 0.017453292519943295;\n"}),r("Shaders/Builtin/Constants/sceneMode2D",[],function(){"use strict";return"const float czm_sceneMode2D = 2.0;\n"}),r("Shaders/Builtin/Constants/sceneMode3D",[],function(){"use strict";return"const float czm_sceneMode3D = 3.0;\n"}),r("Shaders/Builtin/Constants/sceneModeColumbusView",[],function(){"use strict";return"const float czm_sceneModeColumbusView = 1.0;\n"}),r("Shaders/Builtin/Constants/sceneModeMorphing",[],function(){"use strict";return"const float czm_sceneModeMorphing = 0.0;\n"}),r("Shaders/Builtin/Constants/solarRadius",[],function(){"use strict";return"const float czm_solarRadius = 695500000.0;\n"}),r("Shaders/Builtin/Constants/threePiOver2",[],function(){"use strict";return"const float czm_threePiOver2 = 4.71238898038469;\n"}),r("Shaders/Builtin/Constants/twoPi",[],function(){"use strict";return"const float czm_twoPi = 6.283185307179586;\n"}),r("Shaders/Builtin/Constants/webMercatorMaxLatitude",[],function(){"use strict";return"const float czm_webMercatorMaxLatitude = 1.4844222297453324;\n"}),r("Shaders/Builtin/Structs/depthRangeStruct",[],function(){"use strict";return"struct czm_depthRangeStruct\n{\nfloat near;\nfloat far;\n};\n"}),r("Shaders/Builtin/Structs/ellipsoid",[],function(){"use strict";return"struct czm_ellipsoid\n{\nvec3 center;\nvec3 radii;\nvec3 inverseRadii;\nvec3 inverseRadiiSquared;\n};\n"}),r("Shaders/Builtin/Structs/material",[],function(){"use strict";return"struct czm_material\n{\nvec3 diffuse;\nfloat specular;\nfloat shininess;\nvec3 normal;\nvec3 emission;\nfloat alpha;\n};\n"}),r("Shaders/Builtin/Structs/materialInput",[],function(){"use strict";return"struct czm_materialInput\n{\nfloat s;\nvec2 st;\nvec3 str;\nvec3 normalEC;\nmat3 tangentToEyeMatrix;\nvec3 positionToEyeEC;\n};\n"}),r("Shaders/Builtin/Structs/ray",[],function(){"use strict";return"struct czm_ray\n{\nvec3 origin;\nvec3 direction;\n};\n"}),r("Shaders/Builtin/Structs/raySegment",[],function(){"use strict";return"struct czm_raySegment\n{\nfloat start;\nfloat stop;\n};\nconst czm_raySegment czm_emptyRaySegment = czm_raySegment(-czm_infinity, -czm_infinity);\nconst czm_raySegment czm_fullRaySegment = czm_raySegment(0.0, czm_infinity);\n"}),r("Shaders/Builtin/Functions/RGBToXYZ",[],function(){"use strict";return"vec3 czm_RGBToXYZ(vec3 rgb)\n{\nconst mat3 RGB2XYZ = mat3(0.4124, 0.2126, 0.0193,\n0.3576, 0.7152, 0.1192,\n0.1805, 0.0722, 0.9505);\nvec3 xyz = RGB2XYZ * rgb;\nvec3 Yxy;\nYxy.r = xyz.g;\nfloat temp = dot(vec3(1.0), xyz);\nYxy.gb = xyz.rg / temp;\nreturn Yxy;\n}\n"}),r("Shaders/Builtin/Functions/XYZToRGB",[],function(){"use strict";return"vec3 czm_XYZToRGB(vec3 Yxy)\n{\nconst mat3 XYZ2RGB = mat3( 3.2405, -0.9693, 0.0556,\n-1.5371, 1.8760, -0.2040,\n-0.4985, 0.0416, 1.0572);\nvec3 xyz;\nxyz.r = Yxy.r * Yxy.g / Yxy.b;\nxyz.g = Yxy.r;\nxyz.b = Yxy.r * (1.0 - Yxy.g - Yxy.b) / Yxy.b;\nreturn XYZ2RGB * xyz;\n}\n"}),r("Shaders/Builtin/Functions/alphaWeight",[],function(){"use strict";return"float czm_alphaWeight(float a)\n{\nfloat z;\nif (czm_sceneMode != czm_sceneMode2D)\n{\nfloat x = 2.0 * (gl_FragCoord.x - czm_viewport.x) / czm_viewport.z - 1.0;\nfloat y = 2.0 * (gl_FragCoord.y - czm_viewport.y) / czm_viewport.w - 1.0;\nz = (gl_FragCoord.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\nvec4 q = vec4(x, y, z, 0.0);\nq /= gl_FragCoord.w;\nz = (czm_inverseProjectionOIT * q).z;\n}\nelse\n{\nz = gl_FragCoord.z * (czm_currentFrustum.y - czm_currentFrustum.x) + czm_currentFrustum.x;\n}\nreturn pow(a + 0.01, 4.0) + max(1e-2, min(3.0 * 1e3, 100.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0))));\n}\n"}),r("Shaders/Builtin/Functions/antialias",[],function(){"use strict";return"vec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist, float fuzzFactor)\n{\nfloat val1 = clamp(dist / fuzzFactor, 0.0, 1.0);\nfloat val2 = clamp((dist - 0.5) / fuzzFactor, 0.0, 1.0);\nval1 = val1 * (1.0 - val2);\nval1 = val1 * val1 * (3.0 - (2.0 * val1));\nval1 = pow(val1, 0.5);\nvec4 midColor = (color1 + color2) * 0.5;\nreturn mix(midColor, currentColor, val1);\n}\nvec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist)\n{\nreturn czm_antialias(color1, color2, currentColor, dist, 0.1);\n}\n"}),r("Shaders/Builtin/Functions/columbusViewMorph",[],function(){"use strict";return"vec4 czm_columbusViewMorph(vec4 position2D, vec4 position3D, float time)\n{\nvec3 p = mix(position2D.xyz, position3D.xyz, time);\nreturn vec4(p, 1.0);\n}\n"}),r("Shaders/Builtin/Functions/computePosition",[],function(){"use strict";return"vec4 czm_computePosition();\n"}),r("Shaders/Builtin/Functions/cosineAndSine",[],function(){"use strict";return"vec2 cordic(float angle)\n{\nvec2 vector = vec2(6.0725293500888267e-1, 0.0);\nfloat sense = (angle < 0.0) ? -1.0 : 1.0;\nmat2 rotation = mat2(1.0, sense, -sense, 1.0);\nvector = rotation * vector;\nangle -= sense * 7.8539816339744828e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfloat factor = sense * 5.0e-1;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 4.6364760900080609e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 2.5e-1;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 2.4497866312686414e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.25e-1;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.2435499454676144e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 6.25e-2;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 6.2418809995957350e-2;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.125e-2;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.1239833430268277e-2;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.5625e-2;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.5623728620476831e-2;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 7.8125e-3;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 7.8123410601011111e-3;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.90625e-3;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.9062301319669718e-3;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.953125e-3;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.9531225164788188e-3;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 9.765625e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 9.7656218955931946e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 4.8828125e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 4.8828121119489829e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 2.44140625e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 2.4414062014936177e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.220703125e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.2207031189367021e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 6.103515625e-5;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 6.1035156174208773e-5;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.0517578125e-5;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.0517578115526096e-5;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.52587890625e-5;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.5258789061315762e-5;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 7.62939453125e-6;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 7.6293945311019700e-6;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.814697265625e-6;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.8146972656064961e-6;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.9073486328125e-6;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.9073486328101870e-6;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 9.5367431640625e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 9.5367431640596084e-7;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 4.76837158203125e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 4.7683715820308884e-7;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 2.384185791015625e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 2.3841857910155797e-7;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.1920928955078125e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nreturn vector;\n}\nvec2 czm_cosineAndSine(float angle)\n{\nif (angle < -czm_piOverTwo || angle > czm_piOverTwo)\n{\nif (angle < 0.0)\n{\nreturn -cordic(angle + czm_pi);\n}\nelse\n{\nreturn -cordic(angle - czm_pi);\n}\n}\nelse\n{\nreturn cordic(angle);\n}\n}\n"}),r("Shaders/Builtin/Functions/decompressTextureCoordinates",[],function(){"use strict";return"vec2 czm_decompressTextureCoordinates(float encoded)\n{\nfloat temp = encoded / 4096.0;\nfloat stx = floor(temp) / 4096.0;\nfloat sty = temp - floor(temp);\nreturn vec2(stx, sty);\n}\n"}),r("Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates",[],function(){"use strict";return"mat3 czm_eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC)\n{\nvec3 tangentMC = normalize(vec3(-positionMC.y, positionMC.x, 0.0));\nvec3 tangentEC = normalize(czm_normal3D * tangentMC);\nvec3 bitangentEC = normalize(cross(normalEC, tangentEC));\nreturn mat3(\ntangentEC.x, tangentEC.y, tangentEC.z,\nbitangentEC.x, bitangentEC.y, bitangentEC.z,\nnormalEC.x, normalEC.y, normalEC.z);\n}\n"}),r("Shaders/Builtin/Functions/ellipsoidContainsPoint",[],function(){"use strict";return"bool czm_ellipsoidContainsPoint(czm_ellipsoid ellipsoid, vec3 point)\n{\nvec3 scaled = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(point, 1.0)).xyz;\nreturn (dot(scaled, scaled) <= 1.0);\n}\n"}),r("Shaders/Builtin/Functions/ellipsoidNew",[],function(){"use strict";return"czm_ellipsoid czm_ellipsoidNew(vec3 center, vec3 radii)\n{\nvec3 inverseRadii = vec3(1.0 / radii.x, 1.0 / radii.y, 1.0 / radii.z);\nvec3 inverseRadiiSquared = inverseRadii * inverseRadii;\nczm_ellipsoid temp = czm_ellipsoid(center, radii, inverseRadii, inverseRadiiSquared);\nreturn temp;\n}\n"}),r("Shaders/Builtin/Functions/ellipsoidWgs84TextureCoordinates",[],function(){"use strict";return"vec2 czm_ellipsoidWgs84TextureCoordinates(vec3 normal)\n{\nreturn vec2(atan(normal.y, normal.x) * czm_oneOverTwoPi + 0.5, asin(normal.z) * czm_oneOverPi + 0.5);\n}\n"}),r("Shaders/Builtin/Functions/equalsEpsilon",[],function(){"use strict";return"bool czm_equalsEpsilon(vec4 left, vec4 right, float epsilon) {\nreturn all(lessThanEqual(abs(left - right), vec4(epsilon)));\n}\nbool czm_equalsEpsilon(vec3 left, vec3 right, float epsilon) {\nreturn all(lessThanEqual(abs(left - right), vec3(epsilon)));\n}\nbool czm_equalsEpsilon(vec2 left, vec2 right, float epsilon) {\nreturn all(lessThanEqual(abs(left - right), vec2(epsilon)));\n}\nbool czm_equalsEpsilon(float left, float right, float epsilon) {\nreturn (abs(left - right) <= epsilon);\n}\n"}),r("Shaders/Builtin/Functions/eyeOffset",[],function(){"use strict";return"vec4 czm_eyeOffset(vec4 positionEC, vec3 eyeOffset)\n{\nvec4 p = positionEC;\nvec4 zEyeOffset = normalize(p) * eyeOffset.z;\np.xy += eyeOffset.xy + zEyeOffset.xy;\np.z += zEyeOffset.z;\nreturn p;\n}\n"}),r("Shaders/Builtin/Functions/eyeToWindowCoordinates",[],function(){"use strict";return"vec4 czm_eyeToWindowCoordinates(vec4 positionEC)\n{\nvec4 q = czm_projection * positionEC;\nq.xyz /= q.w;\nq.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz;\nreturn q;\n}\n"}),r("Shaders/Builtin/Functions/fog",[],function(){"use strict";return"vec3 czm_fog(float distanceToCamera, vec3 color, vec3 fogColor)\n{\nfloat scalar = distanceToCamera * czm_fogDensity;\nfloat fog = 1.0 - exp(-(scalar * scalar));\nreturn mix(color, fogColor, fog);\n}\n"}),r("Shaders/Builtin/Functions/geodeticSurfaceNormal",[],function(){"use strict";return"vec3 czm_geodeticSurfaceNormal(vec3 positionOnEllipsoid, vec3 ellipsoidCenter, vec3 oneOverEllipsoidRadiiSquared)\n{\nreturn normalize((positionOnEllipsoid - ellipsoidCenter) * oneOverEllipsoidRadiiSquared);\n}\n"}),r("Shaders/Builtin/Functions/getDefaultMaterial",[],function(){"use strict";return"czm_material czm_getDefaultMaterial(czm_materialInput materialInput)\n{\nczm_material material;\nmaterial.diffuse = vec3(0.0);\nmaterial.specular = 0.0;\nmaterial.shininess = 1.0;\nmaterial.normal = materialInput.normalEC;\nmaterial.emission = vec3(0.0);\nmaterial.alpha = 1.0;\nreturn material;\n}\n"}),r("Shaders/Builtin/Functions/getLambertDiffuse",[],function(){"use strict";return"float czm_getLambertDiffuse(vec3 lightDirectionEC, vec3 normalEC)\n{\nreturn max(dot(lightDirectionEC, normalEC), 0.0);\n}\n"}),r("Shaders/Builtin/Functions/getSpecular",[],function(){"use strict";return"float czm_getSpecular(vec3 lightDirectionEC, vec3 toEyeEC, vec3 normalEC, float shininess)\n{\nvec3 toReflectedLight = reflect(-lightDirectionEC, normalEC);\nfloat specular = max(dot(toReflectedLight, toEyeEC), 0.0);\nreturn pow(specular, shininess);\n}\n"}),r("Shaders/Builtin/Functions/getWaterNoise",[],function(){"use strict";return"vec4 czm_getWaterNoise(sampler2D normalMap, vec2 uv, float time, float angleInRadians)\n{\nfloat cosAngle = cos(angleInRadians);\nfloat sinAngle = sin(angleInRadians);\nvec2 s0 = vec2(1.0/17.0, 0.0);\nvec2 s1 = vec2(-1.0/29.0, 0.0);\nvec2 s2 = vec2(1.0/101.0, 1.0/59.0);\nvec2 s3 = vec2(-1.0/109.0, -1.0/57.0);\ns0 = vec2((cosAngle * s0.x) - (sinAngle * s0.y), (sinAngle * s0.x) + (cosAngle * s0.y));\ns1 = vec2((cosAngle * s1.x) - (sinAngle * s1.y), (sinAngle * s1.x) + (cosAngle * s1.y));\ns2 = vec2((cosAngle * s2.x) - (sinAngle * s2.y), (sinAngle * s2.x) + (cosAngle * s2.y));\ns3 = vec2((cosAngle * s3.x) - (sinAngle * s3.y), (sinAngle * s3.x) + (cosAngle * s3.y));\nvec2 uv0 = (uv/103.0) + (time * s0);\nvec2 uv1 = uv/107.0 + (time * s1) + vec2(0.23);\nvec2 uv2 = uv/vec2(897.0, 983.0) + (time * s2) + vec2(0.51);\nvec2 uv3 = uv/vec2(991.0, 877.0) + (time * s3) + vec2(0.71);\nuv0 = fract(uv0);\nuv1 = fract(uv1);\nuv2 = fract(uv2);\nuv3 = fract(uv3);\nvec4 noise = (texture2D(normalMap, uv0)) +\n(texture2D(normalMap, uv1)) +\n(texture2D(normalMap, uv2)) +\n(texture2D(normalMap, uv3));\nreturn ((noise / 4.0) - 0.5) * 2.0;\n}\n"}),r("Shaders/Builtin/Functions/getWgs84EllipsoidEC",[],function(){"use strict";return"czm_ellipsoid czm_getWgs84EllipsoidEC()\n{\nvec3 radii = vec3(6378137.0, 6378137.0, 6356752.314245);\nvec3 inverseRadii = vec3(1.0 / radii.x, 1.0 / radii.y, 1.0 / radii.z);\nvec3 inverseRadiiSquared = inverseRadii * inverseRadii;\nczm_ellipsoid temp = czm_ellipsoid(czm_view[3].xyz, radii, inverseRadii, inverseRadiiSquared);\nreturn temp;\n}\n"}),r("Shaders/Builtin/Functions/hue",[],function(){"use strict";return"vec3 czm_hue(vec3 rgb, float adjustment)\n{\nconst mat3 toYIQ = mat3(0.299, 0.587, 0.114,\n0.595716, -0.274453, -0.321263,\n0.211456, -0.522591, 0.311135);\nconst mat3 toRGB = mat3(1.0, 0.9563, 0.6210,\n1.0, -0.2721, -0.6474,\n1.0, -1.107, 1.7046);\nvec3 yiq = toYIQ * rgb;\nfloat hue = atan(yiq.z, yiq.y) + adjustment;\nfloat chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);\nvec3 color = vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));\nreturn toRGB * color;\n}\n"}),r("Shaders/Builtin/Functions/isEmpty",[],function(){"use strict";return"bool czm_isEmpty(czm_raySegment interval)\n{\nreturn (interval.stop < 0.0);\n}\n"}),r("Shaders/Builtin/Functions/isFull",[],function(){"use strict";return"bool czm_isFull(czm_raySegment interval)\n{\nreturn (interval.start == 0.0 && interval.stop == czm_infinity);\n}\n"}),r("Shaders/Builtin/Functions/latitudeToWebMercatorFraction",[],function(){"use strict";return"float czm_latitudeToWebMercatorFraction(float latitude, float southMercatorY, float oneOverMercatorHeight)\n{\nfloat sinLatitude = sin(latitude);\nfloat mercatorY = 0.5 * log((1.0 + sinLatitude) / (1.0 - sinLatitude));\nreturn (mercatorY - southMercatorY) * oneOverMercatorHeight;\n}\n"}),r("Shaders/Builtin/Functions/luminance",[],function(){"use strict";return"float czm_luminance(vec3 rgb)\n{\nconst vec3 W = vec3(0.2125, 0.7154, 0.0721);\nreturn dot(rgb, W);\n}\n"}),r("Shaders/Builtin/Functions/metersPerPixel",[],function(){"use strict";return"float czm_metersPerPixel(vec4 positionEC)\n{\nfloat width = czm_viewport.z;\nfloat height = czm_viewport.w;\nfloat pixelWidth;\nfloat pixelHeight;\nfloat top = czm_frustumPlanes.x;\nfloat bottom = czm_frustumPlanes.y;\nfloat left = czm_frustumPlanes.z;\nfloat right = czm_frustumPlanes.w;\nif (czm_sceneMode == czm_sceneMode2D)\n{\nfloat frustumWidth = right - left;\nfloat frustumHeight = top - bottom;\npixelWidth = frustumWidth / width;\npixelHeight = frustumHeight / height;\n}\nelse\n{\nfloat distanceToPixel = -positionEC.z;\nfloat inverseNear = 1.0 / czm_currentFrustum.x;\nfloat tanTheta = top * inverseNear;\npixelHeight = 2.0 * distanceToPixel * tanTheta / height;\ntanTheta = right * inverseNear;\npixelWidth = 2.0 * distanceToPixel * tanTheta / width;\n}\nreturn max(pixelWidth, pixelHeight);\n}\n"}),r("Shaders/Builtin/Functions/modelToWindowCoordinates",[],function(){"use strict";return"vec4 czm_modelToWindowCoordinates(vec4 position)\n{\nvec4 q = czm_modelViewProjection * position;\nq.xyz /= q.w;\nq.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz;\nreturn q;\n}\n"}),r("Shaders/Builtin/Functions/multiplyWithColorBalance",[],function(){"use strict";return"vec3 czm_multiplyWithColorBalance(vec3 left, vec3 right)\n{\nconst vec3 W = vec3(0.2125, 0.7154, 0.0721);\nvec3 target = left * right;\nfloat leftLuminance = dot(left, W);\nfloat rightLuminance = dot(right, W);\nfloat targetLuminance = dot(target, W);\nreturn ((leftLuminance + rightLuminance) / (2.0 * targetLuminance)) * target;\n}\n"}),r("Shaders/Builtin/Functions/nearFarScalar",[],function(){"use strict";return"float czm_nearFarScalar(vec4 nearFarScalar, float cameraDistSq)\n{\nfloat valueAtMin = nearFarScalar.y;\nfloat valueAtMax = nearFarScalar.w;\nfloat nearDistanceSq = nearFarScalar.x * nearFarScalar.x;\nfloat farDistanceSq = nearFarScalar.z * nearFarScalar.z;\nfloat t = (cameraDistSq - nearDistanceSq) / (farDistanceSq - nearDistanceSq);\nt = pow(clamp(t, 0.0, 1.0), 0.2);\nreturn mix(valueAtMin, valueAtMax, t);\n}\n"}),r("Shaders/Builtin/Functions/octDecode",[],function(){"use strict";return"vec3 czm_octDecode(vec2 encoded)\n{\nencoded = encoded / 255.0 * 2.0 - 1.0;\nvec3 v = vec3(encoded.x, encoded.y, 1.0 - abs(encoded.x) - abs(encoded.y));\nif (v.z < 0.0)\n{\nv.xy = (1.0 - abs(v.yx)) * czm_signNotZero(v.xy);\n}\nreturn normalize(v);\n}\nvec3 czm_octDecode(float encoded)\n{\nfloat temp = encoded / 256.0;\nfloat x = floor(temp);\nfloat y = (temp - x) * 256.0;\nreturn czm_octDecode(vec2(x, y));\n}\nvoid czm_octDecode(vec2 encoded, out vec3 vector1, out vec3 vector2, out vec3 vector3)\n{\nfloat temp = encoded.x / 65536.0;\nfloat x = floor(temp);\nfloat encodedFloat1 = (temp - x) * 65536.0;\ntemp = encoded.y / 65536.0;\nfloat y = floor(temp);\nfloat encodedFloat2 = (temp - y) * 65536.0;\nvector1 = czm_octDecode(encodedFloat1);\nvector2 = czm_octDecode(encodedFloat2);\nvector3 = czm_octDecode(vec2(x, y));\n}\n"}),r("Shaders/Builtin/Functions/packDepth",[],function(){"use strict";return"vec4 czm_packDepth(float depth)\n{\nvec4 enc = vec4(1.0, 255.0, 65025.0, 160581375.0) * depth;\nenc = fract(enc);\nenc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\nreturn enc;\n}\n"}),r("Shaders/Builtin/Functions/phong",[],function(){"use strict";return"float czm_private_getLambertDiffuseOfMaterial(vec3 lightDirectionEC, czm_material material)\n{\nreturn czm_getLambertDiffuse(lightDirectionEC, material.normal);\n}\nfloat czm_private_getSpecularOfMaterial(vec3 lightDirectionEC, vec3 toEyeEC, czm_material material)\n{\nreturn czm_getSpecular(lightDirectionEC, toEyeEC, material.normal, material.shininess);\n}\nvec4 czm_phong(vec3 toEye, czm_material material)\n{\nfloat diffuse = czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 0.0, 1.0), material);\nif (czm_sceneMode == czm_sceneMode3D) {\ndiffuse += czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 1.0, 0.0), material);\n}\nfloat specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material) + czm_private_getSpecularOfMaterial(czm_moonDirectionEC, toEye, material);\nvec3 materialDiffuse = material.diffuse * 0.5;\nvec3 ambient = materialDiffuse;\nvec3 color = ambient + material.emission;\ncolor += materialDiffuse * diffuse;\ncolor += material.specular * specular;\nreturn vec4(color, material.alpha);\n}\nvec4 czm_private_phong(vec3 toEye, czm_material material)\n{\nfloat diffuse = czm_private_getLambertDiffuseOfMaterial(czm_sunDirectionEC, material);\nfloat specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material);\nvec3 ambient = vec3(0.0);\nvec3 color = ambient + material.emission;\ncolor += material.diffuse * diffuse;\ncolor += material.specular * specular;\nreturn vec4(color, material.alpha);\n}\n"}),r("Shaders/Builtin/Functions/pointAlongRay",[],function(){"use strict";return"vec3 czm_pointAlongRay(czm_ray ray, float time)\n{\nreturn ray.origin + (time * ray.direction);\n}\n"}),r("Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval",[],function(){"use strict";return"czm_raySegment czm_rayEllipsoidIntersectionInterval(czm_ray ray, czm_ellipsoid ellipsoid)\n{\nvec3 q = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ray.origin, 1.0)).xyz;\nvec3 w = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ray.direction, 0.0)).xyz;\nq = q - ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ellipsoid.center, 1.0)).xyz;\nfloat q2 = dot(q, q);\nfloat qw = dot(q, w);\nif (q2 > 1.0)\n{\nif (qw >= 0.0)\n{\nreturn czm_emptyRaySegment;\n}\nelse\n{\nfloat qw2 = qw * qw;\nfloat difference = q2 - 1.0;\nfloat w2 = dot(w, w);\nfloat product = w2 * difference;\nif (qw2 < product)\n{\nreturn czm_emptyRaySegment;\n}\nelse if (qw2 > product)\n{\nfloat discriminant = qw * qw - product;\nfloat temp = -qw + sqrt(discriminant);\nfloat root0 = temp / w2;\nfloat root1 = difference / temp;\nif (root0 < root1)\n{\nczm_raySegment i = czm_raySegment(root0, root1);\nreturn i;\n}\nelse\n{\nczm_raySegment i = czm_raySegment(root1, root0);\nreturn i;\n}\n}\nelse\n{\nfloat root = sqrt(difference / w2);\nczm_raySegment i = czm_raySegment(root, root);\nreturn i;\n}\n}\n}\nelse if (q2 < 1.0)\n{\nfloat difference = q2 - 1.0;\nfloat w2 = dot(w, w);\nfloat product = w2 * difference;\nfloat discriminant = qw * qw - product;\nfloat temp = -qw + sqrt(discriminant);\nczm_raySegment i = czm_raySegment(0.0, temp / w2);\nreturn i;\n}\nelse\n{\nif (qw < 0.0)\n{\nfloat w2 = dot(w, w);\nczm_raySegment i = czm_raySegment(0.0, -qw / w2);\nreturn i;\n}\nelse\n{\nreturn czm_emptyRaySegment;\n}\n}\n}\n"}),r("Shaders/Builtin/Functions/saturation",[],function(){"use strict";return"vec3 czm_saturation(vec3 rgb, float adjustment)\n{\nconst vec3 W = vec3(0.2125, 0.7154, 0.0721);\nvec3 intensity = vec3(dot(rgb, W));\nreturn mix(intensity, rgb, adjustment);\n}\n"}),r("Shaders/Builtin/Functions/signNotZero",[],function(){"use strict";return"float czm_signNotZero(float value)\n{\nreturn value >= 0.0 ? 1.0 : -1.0;\n}\nvec2 czm_signNotZero(vec2 value)\n{\nreturn vec2(czm_signNotZero(value.x), czm_signNotZero(value.y));\n}\nvec3 czm_signNotZero(vec3 value)\n{\nreturn vec3(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z));\n}\nvec4 czm_signNotZero(vec4 value)\n{\nreturn vec4(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z), czm_signNotZero(value.w));\n}\n"}),r("Shaders/Builtin/Functions/tangentToEyeSpaceMatrix",[],function(){"use strict";return"mat3 czm_tangentToEyeSpaceMatrix(vec3 normalEC, vec3 tangentEC, vec3 binormalEC)\n{\nvec3 normal = normalize(normalEC);\nvec3 tangent = normalize(tangentEC);\nvec3 binormal = normalize(binormalEC);\nreturn mat3(tangent.x, tangent.y, tangent.z,\nbinormal.x, binormal.y, binormal.z,\nnormal.x, normal.y, normal.z);\n}\n"}),r("Shaders/Builtin/Functions/translateRelativeToEye",[],function(){"use strict";return"vec4 czm_translateRelativeToEye(vec3 high, vec3 low)\n{\nvec3 highDifference = high - czm_encodedCameraPositionMCHigh;\nvec3 lowDifference = low - czm_encodedCameraPositionMCLow;\nreturn vec4(highDifference + lowDifference, 1.0);\n}\n"}),r("Shaders/Builtin/Functions/translucentPhong",[],function(){"use strict";return"vec4 czm_translucentPhong(vec3 toEye, czm_material material)\n{\nfloat diffuse = czm_getLambertDiffuse(vec3(0.0, 0.0, 1.0), material.normal);\nif (czm_sceneMode == czm_sceneMode3D) {\ndiffuse += czm_getLambertDiffuse(vec3(0.0, 1.0, 0.0), material.normal);\n}\ndiffuse = clamp(diffuse, 0.0, 1.0);\nfloat specular = czm_getSpecular(czm_sunDirectionEC, toEye, material.normal, material.shininess);\nspecular += czm_getSpecular(czm_moonDirectionEC, toEye, material.normal, material.shininess);\nvec3 materialDiffuse = material.diffuse * 0.5;\nvec3 ambient = materialDiffuse;\nvec3 color = ambient + material.emission;\ncolor += materialDiffuse * diffuse;\ncolor += material.specular * specular;\nreturn vec4(color, material.alpha);\n}\n"}),r("Shaders/Builtin/Functions/transpose",[],function(){"use strict";return"mat2 czm_transpose(mat2 matrix)\n{\nreturn mat2(\nmatrix[0][0], matrix[1][0],\nmatrix[0][1], matrix[1][1]);\n}\nmat3 czm_transpose(mat3 matrix)\n{\nreturn mat3(\nmatrix[0][0], matrix[1][0], matrix[2][0],\nmatrix[0][1], matrix[1][1], matrix[2][1],\nmatrix[0][2], matrix[1][2], matrix[2][2]);\n}\nmat4 czm_transpose(mat4 matrix)\n{\nreturn mat4(\nmatrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],\nmatrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],\nmatrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],\nmatrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);\n}\n"; +}),r("Shaders/Builtin/Functions/unpackDepth",[],function(){"use strict";return"float czm_unpackDepth(vec4 packedDepth)\n{\nreturn dot(packedDepth, vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n}\n"}),r("Shaders/Builtin/Functions/windowToEyeCoordinates",[],function(){"use strict";return"vec4 czm_windowToEyeCoordinates(vec4 fragmentCoordinate)\n{\nfloat x = 2.0 * (fragmentCoordinate.x - czm_viewport.x) / czm_viewport.z - 1.0;\nfloat y = 2.0 * (fragmentCoordinate.y - czm_viewport.y) / czm_viewport.w - 1.0;\nfloat z = (fragmentCoordinate.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\nvec4 q = vec4(x, y, z, 1.0);\nq /= fragmentCoordinate.w;\nq = czm_inverseProjection * q;\nreturn q;\n}\n"}),r("Shaders/Builtin/CzmBuiltins",["./Constants/degreesPerRadian","./Constants/depthRange","./Constants/epsilon1","./Constants/epsilon2","./Constants/epsilon3","./Constants/epsilon4","./Constants/epsilon5","./Constants/epsilon6","./Constants/epsilon7","./Constants/infinity","./Constants/oneOverPi","./Constants/oneOverTwoPi","./Constants/pi","./Constants/piOverFour","./Constants/piOverSix","./Constants/piOverThree","./Constants/piOverTwo","./Constants/radiansPerDegree","./Constants/sceneMode2D","./Constants/sceneMode3D","./Constants/sceneModeColumbusView","./Constants/sceneModeMorphing","./Constants/solarRadius","./Constants/threePiOver2","./Constants/twoPi","./Constants/webMercatorMaxLatitude","./Structs/depthRangeStruct","./Structs/ellipsoid","./Structs/material","./Structs/materialInput","./Structs/ray","./Structs/raySegment","./Functions/RGBToXYZ","./Functions/XYZToRGB","./Functions/alphaWeight","./Functions/antialias","./Functions/columbusViewMorph","./Functions/computePosition","./Functions/cosineAndSine","./Functions/decompressTextureCoordinates","./Functions/eastNorthUpToEyeCoordinates","./Functions/ellipsoidContainsPoint","./Functions/ellipsoidNew","./Functions/ellipsoidWgs84TextureCoordinates","./Functions/equalsEpsilon","./Functions/eyeOffset","./Functions/eyeToWindowCoordinates","./Functions/fog","./Functions/geodeticSurfaceNormal","./Functions/getDefaultMaterial","./Functions/getLambertDiffuse","./Functions/getSpecular","./Functions/getWaterNoise","./Functions/getWgs84EllipsoidEC","./Functions/hue","./Functions/isEmpty","./Functions/isFull","./Functions/latitudeToWebMercatorFraction","./Functions/luminance","./Functions/metersPerPixel","./Functions/modelToWindowCoordinates","./Functions/multiplyWithColorBalance","./Functions/nearFarScalar","./Functions/octDecode","./Functions/packDepth","./Functions/phong","./Functions/pointAlongRay","./Functions/rayEllipsoidIntersectionInterval","./Functions/saturation","./Functions/signNotZero","./Functions/tangentToEyeSpaceMatrix","./Functions/translateRelativeToEye","./Functions/translucentPhong","./Functions/transpose","./Functions/unpackDepth","./Functions/windowToEyeCoordinates"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe,ae,se,le,ue,ce,he,de,pe,me,fe,ve,_e,ge,ye,Ce,Ee){"use strict";return{czm_degreesPerRadian:e,czm_depthRange:t,czm_epsilon1:r,czm_epsilon2:i,czm_epsilon3:n,czm_epsilon4:o,czm_epsilon5:a,czm_epsilon6:s,czm_epsilon7:l,czm_infinity:u,czm_oneOverPi:c,czm_oneOverTwoPi:h,czm_pi:d,czm_piOverFour:p,czm_piOverSix:m,czm_piOverThree:f,czm_piOverTwo:v,czm_radiansPerDegree:_,czm_sceneMode2D:g,czm_sceneMode3D:y,czm_sceneModeColumbusView:C,czm_sceneModeMorphing:E,czm_solarRadius:S,czm_threePiOver2:w,czm_twoPi:T,czm_webMercatorMaxLatitude:b,czm_depthRangeStruct:x,czm_ellipsoid:P,czm_material:A,czm_materialInput:I,czm_ray:M,czm_raySegment:D,czm_RGBToXYZ:R,czm_XYZToRGB:O,czm_alphaWeight:N,czm_antialias:L,czm_columbusViewMorph:F,czm_computePosition:B,czm_cosineAndSine:V,czm_decompressTextureCoordinates:z,czm_eastNorthUpToEyeCoordinates:k,czm_ellipsoidContainsPoint:U,czm_ellipsoidNew:G,czm_ellipsoidWgs84TextureCoordinates:W,czm_equalsEpsilon:H,czm_eyeOffset:q,czm_eyeToWindowCoordinates:j,czm_fog:Y,czm_geodeticSurfaceNormal:X,czm_getDefaultMaterial:Z,czm_getLambertDiffuse:K,czm_getSpecular:J,czm_getWaterNoise:Q,czm_getWgs84EllipsoidEC:$,czm_hue:ee,czm_isEmpty:te,czm_isFull:re,czm_latitudeToWebMercatorFraction:ie,czm_luminance:ne,czm_metersPerPixel:oe,czm_modelToWindowCoordinates:ae,czm_multiplyWithColorBalance:se,czm_nearFarScalar:le,czm_octDecode:ue,czm_packDepth:ce,czm_phong:he,czm_pointAlongRay:de,czm_rayEllipsoidIntersectionInterval:pe,czm_saturation:me,czm_signNotZero:fe,czm_tangentToEyeSpaceMatrix:ve,czm_translateRelativeToEye:_e,czm_translucentPhong:ge,czm_transpose:ye,czm_unpackDepth:Ce,czm_windowToEyeCoordinates:Ee}}),r("Renderer/ShaderSource",["../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Shaders/Builtin/CzmBuiltins","./AutomaticUniforms"],function(e,t,r,i,n){"use strict";function o(e){return e=e.replace(/\/\/.*/g,""),e.replace(/\/\*\*[\s\S]*?\*\//gm,function(e){for(var t=e.match(/\n/gm).length,r="",i=0;t>i;++i)r+="\n";return r})}function a(e,r,i){for(var n,a=0;a0;){var n=e.pop();i.push(n),0===n.requiredBy.length&&t.push(n)}for(;t.length>0;){var o=t.shift();e.push(o);for(var a=0;a=0;--n)i=i+t[n].glslSource+"\n";return i.replace(r.glslSource,"")}function c(e,i){var n,a,s="",l=e.sources;if(t(l))for(n=0,a=l.length;a>n;++n)s+="\n#line 0\n"+l[n];s=o(s);var c;s=s.replace(/#version\s+(.*?)\n/gm,function(e,i){if(t(c)&&c!==i)throw new r("inconsistent versions found: "+c+" and "+i);return c=i,"\n"}),s=s.replace(/precision\s(lowp|mediump|highp)\s(float|int);/,"");var d=e.pickColorQualifier;t(d)&&(s=h.createPickFragmentShaderSource(s,d));var p="";t(c)&&(p="#version "+c),i&&(p+="#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n#else\n precision mediump float;\n#endif\n\n");var m=e.defines;if(t(m))for(n=0,a=m.length;a>n;++n){var f=m[n];0!==f.length&&(p+="#define "+f+"\n")}return e.includeBuiltIns&&(p+=u(s)),p+="\n#line 0\n",p+=s}var h=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.pickColorQualifier;this.defines=t(r.defines)?r.defines.slice(0):[],this.sources=t(r.sources)?r.sources.slice(0):[],this.pickColorQualifier=i,this.includeBuiltIns=e(r.includeBuiltIns,!0)};h.prototype.clone=function(){return new h({sources:this.sources,defines:this.defines,pickColorQuantifier:this.pickColorQualifier,includeBuiltIns:this.includeBuiltIns})},h.replaceMain=function(e,t){return t="void "+t+"()",e.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g,t)},h.prototype.createCombinedVertexShader=function(){return c(this,!1)},h.prototype.createCombinedFragmentShader=function(){return c(this,!0)},h._czmBuiltinsAndUniforms={};for(var d in i)i.hasOwnProperty(d)&&(h._czmBuiltinsAndUniforms[d]=i[d]);for(var p in n)if(n.hasOwnProperty(p)){var m=n[p];"function"==typeof m.getDeclaration&&(h._czmBuiltinsAndUniforms[p]=m.getDeclaration(p))}return h.createPickVertexShaderSource=function(e){var t=h.replaceMain(e,"czm_old_main"),r="attribute vec4 pickColor; \nvarying vec4 czm_pickColor; \nvoid main() \n{ \n czm_old_main(); \n czm_pickColor = pickColor; \n}";return t+"\n"+r},h.createPickFragmentShaderSource=function(e,t){var r=h.replaceMain(e,"czm_old_main"),i=t+" vec4 czm_pickColor; \nvoid main() \n{ \n czm_old_main(); \n if (gl_FragColor.a == 0.0) { \n discard; \n } \n gl_FragColor = czm_pickColor; \n}";return r+"\n"+i},h}),r("Renderer/VertexArray",["../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Geometry","../Core/IndexDatatype","../Core/Math","../Core/RuntimeError","./Buffer","./BufferUsage","./ContextLimits"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(i,n,o,a){var s=r(n.vertexBuffer),l=r(n.value),u=n.value?n.value.length:n.componentsPerAttribute,c={index:t(n.index,o),enabled:t(n.enabled,!0),vertexBuffer:n.vertexBuffer,value:l?n.value.slice(0):void 0,componentsPerAttribute:u,componentDatatype:t(n.componentDatatype,e.FLOAT),normalize:t(n.normalize,!1),offsetInBytes:t(n.offsetInBytes,0),strideInBytes:t(n.strideInBytes,0),instanceDivisor:t(n.instanceDivisor,0)};if(s)c.vertexAttrib=function(e){var t=this.index;e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer._getBuffer()),e.vertexAttribPointer(t,this.componentsPerAttribute,this.componentDatatype,this.normalize,this.strideInBytes,this.offsetInBytes),e.enableVertexAttribArray(t),this.instanceDivisor>0&&(a.glVertexAttribDivisor(t,this.instanceDivisor),a._vertexAttribDivisors[t]=this.instanceDivisor,a._previousDrawInstanced=!0)},c.disableVertexAttribArray=function(e){e.disableVertexAttribArray(this.index),this.instanceDivisor>0&&a.glVertexAttribDivisor(o,0)};else{switch(c.componentsPerAttribute){case 1:c.vertexAttrib=function(e){e.vertexAttrib1fv(this.index,this.value)};break;case 2:c.vertexAttrib=function(e){e.vertexAttrib2fv(this.index,this.value)};break;case 3:c.vertexAttrib=function(e){e.vertexAttrib3fv(this.index,this.value)};break;case 4:c.vertexAttrib=function(e){e.vertexAttrib4fv(this.index,this.value)}}c.disableVertexAttribArray=function(e){}}i.push(c)}function m(e,t,i){for(var n=0;n0)for(s=f(t[a[0]]),i=1;l>i;++i){var c=f(t[a[i]]);if(c!==s)throw new u("Each attribute list must have the same number of vertices. Attribute "+a[i]+" has a different number of vertices ("+c.toString()+") than attribute "+a[0]+" ("+s.toString()+").")}a.sort(function(r,i){return e.getSizeInBytes(t[i].componentDatatype)-e.getSizeInBytes(t[r].componentDatatype)});var h=0,d={};for(i=0;l>i;++i)n=a[i],o=t[n],d[n]=h,h+=v(o);if(h>0){var p=e.getSizeInBytes(t[a[0]].componentDatatype),m=h%p;0!==m&&(h+=p-m);var _=s*h,g=new ArrayBuffer(_),y={};for(i=0;l>i;++i){n=a[i];var C=e.getSizeInBytes(t[n].componentDatatype);y[n]={pointer:e.createTypedArray(t[n].componentDatatype,g),index:d[n]/C,strideInComponentType:h/C}}for(i=0;s>i;++i)for(var E=0;l>E;++E){n=a[E],o=t[n];for(var S=o.values,w=y[n],T=w.pointer,b=o.componentsPerAttribute,x=0;b>x;++x)T[w.index+x]=S[i*b+x];w.index+=w.strideInComponentType}return{buffer:g,offsetsInBytes:d,vertexSizeInBytes:h}}return void 0}function g(e){var t=e._context,r=e._hasInstancedAttributes;if(r||t._previousDrawInstanced){t._previousDrawInstanced=r;var i,n=t._vertexAttribDivisors,o=e._attributes,a=d.maximumVertexAttributes;if(r){var s=o.length;for(i=0;s>i;++i){var l=o[i];if(l.enabled){var u=l.instanceDivisor,c=l.index;u!==n[c]&&(t.glVertexAttribDivisor(c,u),n[c]=u)}}}else for(i=0;a>i;++i)n[i]>0&&(t.glVertexAttribDivisor(i,0),n[i]=0)}}var y=function(i){i=t(i,t.EMPTY_OBJECT);var n,o=i.context,a=o._gl,s=i.attributes,l=i.indexBuffer,u=[],c=1,h=!1,d=s.length;for(n=0;d>n;++n)p(u,s[n],n,o);for(d=u.length,n=0;d>n;++n){var f=u[n];if(r(f.vertexBuffer)&&0===f.instanceDivisor){var v=f.strideInBytes||f.componentsPerAttribute*e.getSizeInBytes(f.componentDatatype);c=f.vertexBuffer.sizeInBytes/v;break}}for(n=0;d>n;++n)if(u[n].instanceDivisor>0){h=!0;break}var _;o.vertexArrayObject&&(_=o.glCreateVertexArray(),o.glBindVertexArray(_),m(a,u,l),o.glBindVertexArray(null)),this._numberOfVertices=c,this._hasInstancedAttributes=h,this._context=o,this._gl=a,this._vao=_,this._attributes=u,this._indexBuffer=l};return y.fromGeometry=function(i){i=t(i,t.EMPTY_OBJECT);var n,o,u,d=i.context,p=t(i.geometry,t.EMPTY_OBJECT),m=t(i.bufferUsage,h.DYNAMIC_DRAW),f=t(i.attributeLocations,t.EMPTY_OBJECT),v=t(i.interleave,!1),g=i.vertexArrayAttributes,C=r(g)?g:[],E=p.attributes;if(v){var S=_(E);if(r(S)){u=c.createVertexBuffer({context:d,typedArray:S.buffer,usage:m});var w=S.offsetsInBytes,T=S.vertexSizeInBytes;for(n in E)E.hasOwnProperty(n)&&r(E[n])&&(o=E[n],r(o.values)?C.push({index:f[n],vertexBuffer:u,componentDatatype:o.componentDatatype,componentsPerAttribute:o.componentsPerAttribute,normalize:o.normalize,offsetInBytes:w[n],strideInBytes:T}):C.push({index:f[n],value:o.value,componentDatatype:o.componentDatatype,normalize:o.normalize}))}}else for(n in E)if(E.hasOwnProperty(n)&&r(E[n])){o=E[n];var b=o.componentDatatype;b===e.DOUBLE&&(b=e.FLOAT),u=void 0,r(o.values)&&(u=c.createVertexBuffer({context:d,typedArray:e.createTypedArray(b,o.values),usage:m})),C.push({index:f[n],vertexBuffer:u,value:o.value,componentDatatype:b,componentsPerAttribute:o.componentsPerAttribute,normalize:o.normalize})}var x,P=p.indices;return r(P)&&(x=a.computeNumberOfVertices(p)>=l.SIXTY_FOUR_KILOBYTES&&d.elementIndexUint?c.createIndexBuffer({context:d,typedArray:new Uint32Array(P),usage:m,indexDatatype:s.UNSIGNED_INT}):c.createIndexBuffer({context:d,typedArray:new Uint16Array(P),usage:m,indexDatatype:s.UNSIGNED_SHORT})),new y({context:d,attributes:C,indexBuffer:x})},i(y.prototype,{numberOfAttributes:{get:function(){return this._attributes.length}},numberOfVertices:{get:function(){return this._numberOfVertices}},indexBuffer:{get:function(){return this._indexBuffer}}}),y.prototype.getAttribute=function(e){return this._attributes[e]},y.prototype._bind=function(){r(this._vao)?(this._context.glBindVertexArray(this._vao),this._context.instancedArrays&&g(this)):m(this._gl,this._attributes,this._indexBuffer)},y.prototype._unBind=function(){if(r(this._vao))this._context.glBindVertexArray(null);else{for(var e=this._attributes,t=this._gl,i=0;i0){t.needsCommit=!1;var i=t.vertexBuffer,n=e._size*t.vertexSizeInBytes,o=r(i);if(!o||i.sizeInBytes0){var i=e.vertexSizeInBytes*t,n=e.vertexSizeInBytes*r;e.vertexBuffer.copyFromArrayView(new Uint8Array(e.arrayBuffer,i,n),i)}}function h(e){var t=e.va;if(r(t)){for(var i=t.length,n=0;i>n;++n)t[n].va.destroy();e.va=void 0}}var d=function(i,n,o,a){function s(t,r){return e.getSizeInBytes(r.componentDatatype)-e.getSizeInBytes(t.componentDatatype)}var l=d._verifyAttributes(n);o=t(o,0);for(var u,c,h=[],p={},m=l.length,f=0;m>f;++f){var v=l[f];v.vertexBuffer?h.push(v):(c=v.usage,u=p[c],r(u)||(u=p[c]=[]),u.push(v))}this._allBuffers=[];for(c in p)if(p.hasOwnProperty(c)){u=p[c],u.sort(s);var _=d._vertexSizeInBytes(u),g=u[0].usage,y={vertexSizeInBytes:_,vertexBuffer:void 0,usage:g,needsCommit:!1,arrayBuffer:void 0,arrayViews:d._createArrayViews(u,_)};this._allBuffers.push(y)}this._size=0,this._instanced=t(a,!1),this._precreated=h,this._context=i,this.writers=void 0,this.va=void 0,this.resize(o)};d._verifyAttributes=function(r){for(var i=[],o=0;on;++n){var o=t[n];r+=o.componentsPerAttribute*e.getSizeInBytes(o.componentDatatype)}var a=i>0?e.getSizeInBytes(t[0].componentDatatype):0,s=a>0?r%a:0,l=0===s?0:a-s;return r+=l},d._createArrayViews=function(t,r){for(var i=[],n=0,o=t.length,a=0;o>a;++a){var s=t[a],l=s.componentDatatype;i.push({index:s.index,enabled:s.enabled,componentsPerAttribute:s.componentsPerAttribute,componentDatatype:l,normalize:s.normalize,offsetInBytes:n,vertexSizeInComponentType:r/e.getSizeInBytes(l),view:void 0}),n+=s.componentsPerAttribute*e.getSizeInBytes(l)}return i},d.prototype.resize=function(e){this._size=e;var t=this._allBuffers;this.writers=[];for(var r=0,i=t.length;i>r;++r){var n=t[r];d._resize(n,this._size),d._appendWriters(this.writers,n)}h(this)},d._resize=function(t,i){if(t.vertexSizeInBytes>0){var n=new ArrayBuffer(i*t.vertexSizeInBytes);if(r(t.arrayBuffer))for(var o=new Uint8Array(n),a=new Uint8Array(t.arrayBuffer),s=a.length,l=0;s>l;++l)o[l]=a[l];for(var u=t.arrayViews,c=u.length,h=0;c>h;++h){var d=u[h];d.view=e.createArrayBufferView(d.componentDatatype,n,d.offsetInBytes)}t.arrayBuffer=n}};var p=[function(e,t,r){return function(i,n){t[i*r]=n,e.needsCommit=!0}},function(e,t,r){return function(i,n,o){var a=i*r;t[a]=n,t[a+1]=o,e.needsCommit=!0}},function(e,t,r){return function(i,n,o,a){var s=i*r;t[s]=n,t[s+1]=o,t[s+2]=a,e.needsCommit=!0}},function(e,t,r){return function(i,n,o,a,s){var l=i*r;t[l]=n,t[l+1]=o,t[l+2]=a,t[l+3]=s,e.needsCommit=!0}}];return d._appendWriters=function(e,t){for(var r=t.arrayViews,i=r.length,n=0;i>n;++n){var o=r[n];e[o.index]=p[o.componentsPerAttribute-1](t,o.view,o.vertexSizeInComponentType)}},d.prototype.commit=function(e){var t,i,n,a=!1,s=this._allBuffers;for(i=0,n=s.length;n>i;++i)t=s[i],a=u(this,t)||a;if(a||!r(this.va)){h(this);for(var c=this.va=[],p=r(e)?Math.ceil(this._size/(o.SIXTY_FOUR_KILOBYTES-1)):1,m=0;p>m;++m){var f=[];for(i=0,n=s.length;n>i;++i){t=s[i];var v=m*t.vertexSizeInBytes*(o.SIXTY_FOUR_KILOBYTES-1);d._appendAttributes(f,t,v,this._instanced)}f=f.concat(this._precreated),c.push({va:new l({context:this._context,attributes:f,indexBuffer:e}),indicesCount:1.5*(m!==p-1?o.SIXTY_FOUR_KILOBYTES-1:this._size%(o.SIXTY_FOUR_KILOBYTES-1))})}}},d._appendAttributes=function(e,t,r,i){for(var n=t.arrayViews,o=n.length,a=0;o>a;++a){var s=n[a];e.push({index:s.index,enabled:s.enabled,componentsPerAttribute:s.componentsPerAttribute,componentDatatype:s.componentDatatype,normalize:s.normalize,vertexBuffer:t.vertexBuffer,offsetInBytes:r+s.offsetInBytes,strideInBytes:t.vertexSizeInBytes,instanceDivisor:i?1:0})}},d.prototype.subCommit=function(e,t){for(var r=this._allBuffers,i=0,n=r.length;n>i;++i)c(r[i],e,t)},d.prototype.endSubCommits=function(){for(var e=this._allBuffers,t=0,r=e.length;r>t;++t)e[t].needsCommit=!1},d.prototype.isDestroyed=function(){return!1},d.prototype.destroy=function(){for(var e=this._allBuffers,t=0,r=e.length;r>t;++t){var n=e[t];n.vertexBuffer=n.vertexBuffer&&n.vertexBuffer.destroy()}return h(this),i(this)},d}),r("Shaders/BillboardCollectionFS",[],function(){"use strict";return"uniform sampler2D u_atlas;\nvarying vec2 v_textureCoordinates;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#else\nvarying vec4 v_color;\n#endif\nvoid main()\n{\n#ifdef RENDER_FOR_PICK\nvec4 vertexColor = vec4(1.0, 1.0, 1.0, 1.0);\n#else\nvec4 vertexColor = v_color;\n#endif\nvec4 color = texture2D(u_atlas, v_textureCoordinates) * vertexColor;\nif (color.a == 0.0)\n{\ndiscard;\n}\n#ifdef RENDER_FOR_PICK\ngl_FragColor = v_pickColor;\n#else\ngl_FragColor = color;\n#endif\n}\n"}),r("Shaders/BillboardCollectionVS",[],function(){"use strict";return"#ifdef INSTANCED\nattribute vec2 direction;\n#endif\nattribute vec4 positionHighAndScale;\nattribute vec4 positionLowAndRotation;\nattribute vec4 compressedAttribute0;\nattribute vec4 compressedAttribute1;\nattribute vec4 compressedAttribute2;\nattribute vec4 eyeOffset;\nattribute vec4 scaleByDistance;\nattribute vec4 pixelOffsetScaleByDistance;\nvarying vec2 v_textureCoordinates;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#else\nvarying vec4 v_color;\n#endif\nconst float UPPER_BOUND = 32768.0;\nconst float SHIFT_LEFT16 = 65536.0;\nconst float SHIFT_LEFT8 = 256.0;\nconst float SHIFT_LEFT7 = 128.0;\nconst float SHIFT_LEFT5 = 32.0;\nconst float SHIFT_LEFT3 = 8.0;\nconst float SHIFT_LEFT2 = 4.0;\nconst float SHIFT_LEFT1 = 2.0;\nconst float SHIFT_RIGHT8 = 1.0 / 256.0;\nconst float SHIFT_RIGHT7 = 1.0 / 128.0;\nconst float SHIFT_RIGHT5 = 1.0 / 32.0;\nconst float SHIFT_RIGHT3 = 1.0 / 8.0;\nconst float SHIFT_RIGHT2 = 1.0 / 4.0;\nconst float SHIFT_RIGHT1 = 1.0 / 2.0;\nvec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float scale, vec2 direction, vec2 origin, vec2 translate, vec2 pixelOffset, vec3 alignedAxis, float rotation, bool sizeInMeters)\n{\nvec2 halfSize = imageSize * scale * czm_resolutionScale;\nhalfSize *= ((direction * 2.0) - 1.0);\nif (sizeInMeters)\n{\npositionEC.xy += halfSize;\n}\nvec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\nif (sizeInMeters)\n{\npositionWC.xy += (origin * abs(halfSize)) / czm_metersPerPixel(positionEC);\n}\nelse\n{\npositionWC.xy += (origin * abs(halfSize));\n}\n#if defined(ROTATION) || defined(ALIGNED_AXIS)\nif (!all(equal(alignedAxis, vec3(0.0))) || rotation != 0.0)\n{\nfloat angle = rotation;\nif (!all(equal(alignedAxis, vec3(0.0))))\n{\nvec3 pos = positionEC.xyz + czm_encodedCameraPositionMCHigh + czm_encodedCameraPositionMCLow;\nvec3 normal = normalize(cross(alignedAxis, pos));\nvec4 tangent = vec4(normalize(cross(pos, normal)), 0.0);\ntangent = czm_modelViewProjection * tangent;\nangle += sign(-tangent.x) * acos(tangent.y / length(tangent.xy));\n}\nfloat cosTheta = cos(angle);\nfloat sinTheta = sin(angle);\nmat2 rotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta);\nhalfSize = rotationMatrix * halfSize;\n}\n#endif\nif (!sizeInMeters)\n{\npositionWC.xy += halfSize;\n}\npositionWC.xy += translate;\npositionWC.xy += (pixelOffset * czm_resolutionScale);\nreturn positionWC;\n}\nvoid main()\n{\nvec3 positionHigh = positionHighAndScale.xyz;\nvec3 positionLow = positionLowAndRotation.xyz;\nfloat scale = positionHighAndScale.w;\n#if defined(ROTATION) || defined(ALIGNED_AXIS)\nfloat rotation = positionLowAndRotation.w;\n#else\nfloat rotation = 0.0;\n#endif\nfloat compressed = compressedAttribute0.x;\nvec2 pixelOffset;\npixelOffset.x = floor(compressed * SHIFT_RIGHT7);\ncompressed -= pixelOffset.x * SHIFT_LEFT7;\npixelOffset.x -= UPPER_BOUND;\nvec2 origin;\norigin.x = floor(compressed * SHIFT_RIGHT5);\ncompressed -= origin.x * SHIFT_LEFT5;\norigin.y = floor(compressed * SHIFT_RIGHT3);\ncompressed -= origin.y * SHIFT_LEFT3;\norigin -= vec2(1.0);\nfloat show = floor(compressed * SHIFT_RIGHT2);\ncompressed -= show * SHIFT_LEFT2;\n#ifdef INSTANCED\nvec2 textureCoordinatesBottomLeft = czm_decompressTextureCoordinates(compressedAttribute0.w);\nvec2 textureCoordinatesRange = czm_decompressTextureCoordinates(eyeOffset.w);\nvec2 textureCoordinates = textureCoordinatesBottomLeft + direction * textureCoordinatesRange;\n#else\nvec2 direction;\ndirection.x = floor(compressed * SHIFT_RIGHT1);\ndirection.y = compressed - direction.x * SHIFT_LEFT1;\nvec2 textureCoordinates = czm_decompressTextureCoordinates(compressedAttribute0.w);\n#endif\nfloat temp = compressedAttribute0.y * SHIFT_RIGHT8;\npixelOffset.y = -(floor(temp) - UPPER_BOUND);\nvec2 translate;\ntranslate.y = (temp - floor(temp)) * SHIFT_LEFT16;\ntemp = compressedAttribute0.z * SHIFT_RIGHT8;\ntranslate.x = floor(temp) - UPPER_BOUND;\ntranslate.y += (temp - floor(temp)) * SHIFT_LEFT8;\ntranslate.y -= UPPER_BOUND;\ntemp = compressedAttribute1.x * SHIFT_RIGHT8;\nvec2 imageSize = vec2(floor(temp), compressedAttribute2.w);\n#ifdef EYE_DISTANCE_TRANSLUCENCY\nvec4 translucencyByDistance;\ntranslucencyByDistance.x = compressedAttribute1.z;\ntranslucencyByDistance.z = compressedAttribute1.w;\ntranslucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\ntemp = compressedAttribute1.y * SHIFT_RIGHT8;\ntranslucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n#endif\n#ifdef ALIGNED_AXIS\nvec3 alignedAxis = czm_octDecode(floor(compressedAttribute1.y * SHIFT_RIGHT8));\n#else\nvec3 alignedAxis = vec3(0.0);\n#endif\n#ifdef RENDER_FOR_PICK\ntemp = compressedAttribute2.y;\n#else\ntemp = compressedAttribute2.x;\n#endif\nvec4 color;\ntemp = temp * SHIFT_RIGHT8;\ncolor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\ncolor.g = (temp - floor(temp)) * SHIFT_LEFT8;\ncolor.r = floor(temp);\ntemp = compressedAttribute2.z * SHIFT_RIGHT8;\nbool sizeInMeters = (temp - floor(temp)) * SHIFT_LEFT8 > 0.0;\ntemp = floor(temp) * SHIFT_RIGHT8;\n#ifdef RENDER_FOR_PICK\ncolor.a = (temp - floor(temp)) * SHIFT_LEFT8;\nvec4 pickColor = color / 255.0;\n#else\ncolor.a = floor(temp);\ncolor /= 255.0;\n#endif\nvec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\nvec4 positionEC = czm_modelViewRelativeToEye * p;\npositionEC = czm_eyeOffset(positionEC, eyeOffset.xyz);\npositionEC.xyz *= show;\n#if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY) || defined(EYE_DISTANCE_PIXEL_OFFSET)\nfloat lengthSq;\nif (czm_sceneMode == czm_sceneMode2D)\n{\nlengthSq = czm_eyeHeight2D.y;\n}\nelse\n{\nlengthSq = dot(positionEC.xyz, positionEC.xyz);\n}\n#endif\n#ifdef EYE_DISTANCE_SCALING\nscale *= czm_nearFarScalar(scaleByDistance, lengthSq);\nif (scale == 0.0)\n{\npositionEC.xyz = vec3(0.0);\n}\n#endif\n#ifdef EYE_DISTANCE_PIXEL_OFFSET\nfloat position = pixelOffsetScaleByDistance.x;\nfloat cutDistSq = pixelOffsetScaleByDistance.z * pixelOffsetScaleByDistance.z;\nfloat cameraDistSq = lengthSq;\nif (cutDistSq > 0.0 && cameraDistSq > cutDistSq)\n{\npositionEC.xyz = vec3(0.0);\n}\nelse if (position > 0.0)\n{\nfloat level = floor(pow(cameraDistSq / 1000000.0, 0.20));\nif (mod(position, pow(2.0, level)) > 0.5)\n{\npositionEC.xyz = vec3(0.0);\n}\n}\n#endif\nfloat translucency = 1.0;\n#ifdef EYE_DISTANCE_TRANSLUCENCY\ntranslucency = czm_nearFarScalar(translucencyByDistance, lengthSq);\nif (translucency == 0.0)\n{\npositionEC.xyz = vec3(0.0);\n}\n#endif\n#ifdef EYE_DISTANCE_PIXEL_OFFSET\nfloat pixelOffsetScale = czm_nearFarScalar(pixelOffsetScaleByDistance, lengthSq);\npixelOffset *= pixelOffsetScale;\n#endif\n#ifdef CLAMPED_TO_GROUND\npositionEC.z *= 0.995;\norigin.y = 1.0;\n#endif\nvec4 positionWC = computePositionWindowCoordinates(positionEC, imageSize, scale, direction, origin, translate, pixelOffset, alignedAxis, rotation, sizeInMeters);\ngl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0);\nv_textureCoordinates = textureCoordinates;\n#ifdef RENDER_FOR_PICK\nv_pickColor = pickColor;\n#else\nv_color = color;\nv_color.a *= translucency;\n#endif\n}\n"}),r("Scene/HeightReference",["../Core/freezeObject"],function(e){"use strict";var t={NONE:0,CLAMP_TO_GROUND:1,RELATIVE_TO_GROUND:2};return e(t)}),r("Scene/HorizontalOrigin",["../Core/freezeObject"],function(e){"use strict";var t={CENTER:0,LEFT:1,RIGHT:-1};return e(t)}),r("Scene/SceneMode",["../Core/freezeObject"],function(e){"use strict";var t={MORPHING:0,COLUMBUS_VIEW:1,SCENE2D:2,SCENE3D:3};return t.getMorphTime=function(e){return e===t.SCENE3D?1:e===t.MORPHING?void 0:0},e(t)}),r("Scene/SceneTransforms",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defined","../Core/DeveloperError","../Core/Math","../Core/Matrix4","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c={},h=new i(0,0,0,1),d=new i,p=new l;c.wgs84ToWindowCoordinates=function(e,t,r){var n=c.computeActualWgs84Position(e.frameState,t,h);if(!o(n))return void 0;var a=e.camera,s=l.multiply(a.frustum.projectionMatrix,a.viewMatrix,p);return l.multiplyByVector(s,i.fromElements(n.x,n.y,n.z,1,d),d),d.z<0&&e.mode!==u.SCENE2D?void 0:(r=c.clipToGLWindowCoordinates(e,d,r),r.y=e.canvas.clientHeight-r.y,r)},c.wgs84ToDrawingBufferCoordinates=function(e,t,r){var n=c.computeActualWgs84Position(e.frameState,t,h);if(!o(n))return void 0;var a=e.camera,s=l.multiply(a.frustum.projectionMatrix,a.viewMatrix,p);return l.multiplyByVector(s,i.fromElements(n.x,n.y,n.z,1,d),d),d.z<0&&e.mode!==u.SCENE2D?void 0:c.clipToDrawingBufferCoordinates(e,d,r)};var m=new r,f=new n;c.computeActualWgs84Position=function(e,t,i){var n=e.mode;if(n===u.SCENE3D)return r.clone(t,i);var a=e.mapProjection,l=a.ellipsoid.cartesianToCartographic(t,f);if(!o(l))return void 0;if(a.project(l,m),n===u.COLUMBUS_VIEW)return r.fromElements(m.z,m.x,m.y,i);if(n===u.SCENE2D)return r.fromElements(0,m.x,m.y,i);var c=e.morphTime;return r.fromElements(s.lerp(m.z,t.x,c),s.lerp(m.x,t.y,c),s.lerp(m.y,t.z,c),i)};var v=new r,_=new r,g=new e,y=new l;c.clipToGLWindowCoordinates=function(e,i,n){var o=e.canvas;return r.divideByScalar(i,i.w,v),g.width=o.clientWidth,g.height=o.clientHeight,l.computeViewportTransformation(g,0,1,y),l.multiplyByPoint(y,v,_),t.fromCartesian3(_,n)},c.clipToDrawingBufferCoordinates=function(e,i,n){return r.divideByScalar(i,i.w,v),g.width=e.drawingBufferWidth,g.height=e.drawingBufferHeight,l.computeViewportTransformation(g,0,1,y),l.multiplyByPoint(y,v,_),t.fromCartesian3(_,n)},c.transformWindowToDrawingBuffer=function(e,r,i){var n=e.canvas,o=e.drawingBufferWidth/n.clientWidth,a=e.drawingBufferHeight/n.clientHeight;return t.fromElements(r.x*o,r.y*a,i)};var C=new i,E=new i;return c.drawingBufferToWgs84Coordinates=function(e,t,n,o){var a=e.context,s=a.uniformState,u=s.viewport,c=(s.viewportTransformation,i.clone(i.UNIT_W,C));c.x=(t.x-u.x)/u.width*2-1,c.y=(t.y-u.y)/u.height*2-1,c.z=2*n-1,c.w=1;var h=l.multiplyByVector(s.inverseViewProjection,c,E),d=1/h.w;return r.multiplyByScalar(h,d,h),r.fromCartesian4(h,o)},c}),r("Scene/VerticalOrigin",["../Core/freezeObject"],function(e){"use strict";var t={CENTER:0,BOTTOM:1,TOP:-1};return e(t)}),r("Scene/Billboard",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix4","../Core/NearFarScalar","./HeightReference","./HorizontalOrigin","./SceneMode","./SceneTransforms","./VerticalOrigin"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,t){var r=e._billboardCollection; +l(r)&&(r._updateBillboard(e,t),e._dirty=!0)}var y=function(e,i){e=s(e,s.EMPTY_OBJECT),this._show=s(e.show,!0),this._position=r.clone(s(e.position,r.ZERO)),this._actualPosition=r.clone(this._position),this._pixelOffset=t.clone(s(e.pixelOffset,t.ZERO)),this._translate=new t(0,0),this._eyeOffset=r.clone(s(e.eyeOffset,r.ZERO)),this._verticalOrigin=s(e.verticalOrigin,_.CENTER),this._horizontalOrigin=s(e.horizontalOrigin,m.CENTER),this._scale=s(e.scale,1),this._color=o.clone(s(e.color,o.WHITE)),this._rotation=s(e.rotation,0),this._alignedAxis=r.clone(s(e.alignedAxis,r.ZERO)),this._width=e.width,this._height=e.height,this._scaleByDistance=e.scaleByDistance,this._translucencyByDistance=e.translucencyByDistance,this._pixelOffsetScaleByDistance=e.pixelOffsetScaleByDistance,this._heightReference=s(e.heightReference,p.NONE),this._sizeInMeters=s(e.sizeInMeters,!1),this._id=e.id,this._collection=s(e.collection,i),this._pickId=void 0,this._pickPrimitive=s(e._pickPrimitive,this),this._billboardCollection=i,this._dirty=!1,this._index=-1,this._imageIndex=-1,this._imageIndexPromise=void 0,this._imageId=void 0,this._image=void 0,this._imageSubRegion=void 0,this._imageWidth=void 0,this._imageHeight=void 0;var n=e.image,u=e.imageId;l(n)&&(l(u)||(u="string"==typeof n?n:l(n.src)?n.src:a()),this._imageId=u,this._image=n),l(e.imageSubRegion)&&(this._imageId=u,this._imageSubRegion=e.imageSubRegion),l(this._billboardCollection._textureAtlas)&&this._loadImage(),this._actualClampedPosition=void 0,this._removeCallbackFunc=void 0,this._mode=f.SCENE3D,this._updateClamping()},C=y.SHOW_INDEX=0,E=y.POSITION_INDEX=1,S=y.PIXEL_OFFSET_INDEX=2,w=y.EYE_OFFSET_INDEX=3,T=y.HORIZONTAL_ORIGIN_INDEX=4,b=y.VERTICAL_ORIGIN_INDEX=5,x=y.SCALE_INDEX=6,P=y.IMAGE_INDEX_INDEX=7,A=y.COLOR_INDEX=8,I=y.ROTATION_INDEX=9,M=y.ALIGNED_AXIS_INDEX=10,D=y.SCALE_BY_DISTANCE_INDEX=11,R=y.TRANSLUCENCY_BY_DISTANCE_INDEX=12,O=y.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX=13;y.NUMBER_OF_PROPERTIES=14,u(y.prototype,{show:{get:function(){return this._show},set:function(e){this._show!==e&&(this._show=e,g(this,C))}},position:{get:function(){return this._position},set:function(e){var t=this._position;r.equals(t,e)||(r.clone(e,t),r.clone(e,this._actualPosition),this._updateClamping(),g(this,E))}},heightReference:{get:function(){return this._heightReference},set:function(e){var t=this._heightReference;e!==t&&(this._heightReference=e,this._updateClamping(),g(this,E))}},pixelOffset:{get:function(){return this._pixelOffset},set:function(e){var r=this._pixelOffset;t.equals(r,e)||(t.clone(e,r),g(this,S))}},scaleByDistance:{get:function(){return this._scaleByDistance},set:function(e){var t=this._scaleByDistance;d.equals(t,e)||(this._scaleByDistance=d.clone(e,t),g(this,D))}},translucencyByDistance:{get:function(){return this._translucencyByDistance},set:function(e){var t=this._translucencyByDistance;d.equals(t,e)||(this._translucencyByDistance=d.clone(e,t),g(this,R))}},pixelOffsetScaleByDistance:{get:function(){return this._pixelOffsetScaleByDistance},set:function(e){var t=this._pixelOffsetScaleByDistance;d.equals(t,e)||(this._pixelOffsetScaleByDistance=d.clone(e,t),g(this,O))}},eyeOffset:{get:function(){return this._eyeOffset},set:function(e){var t=this._eyeOffset;r.equals(t,e)||(r.clone(e,t),g(this,w))}},horizontalOrigin:{get:function(){return this._horizontalOrigin},set:function(e){this._horizontalOrigin!==e&&(this._horizontalOrigin=e,g(this,T))}},verticalOrigin:{get:function(){return this._verticalOrigin},set:function(e){this._verticalOrigin!==e&&(this._verticalOrigin=e,g(this,b))}},scale:{get:function(){return this._scale},set:function(e){this._scale!==e&&(this._scale=e,g(this,x))}},color:{get:function(){return this._color},set:function(e){var t=this._color;o.equals(t,e)||(o.clone(e,t),g(this,A))}},rotation:{get:function(){return this._rotation},set:function(e){this._rotation!==e&&(this._rotation=e,g(this,I))}},alignedAxis:{get:function(){return this._alignedAxis},set:function(e){var t=this._alignedAxis;r.equals(t,e)||(r.clone(e,t),g(this,M))}},width:{get:function(){return s(this._width,this._imageWidth)},set:function(e){this._width!==e&&(this._width=e,g(this,P))}},height:{get:function(){return s(this._height,this._imageHeight)},set:function(e){this._height!==e&&(this._height=e,g(this,P))}},sizeInMeters:{get:function(){return this._sizeInMeters},set:function(e){this._sizeInMeters!==e&&(this._sizeInMeters=e,g(this,A))}},id:{get:function(){return this._id},set:function(e){this._id=e,l(this._pickId)&&(this._pickId.object.id=e)}},pickPrimitive:{get:function(){return this._pickPrimitive},set:function(e){this._pickPrimitive=e,l(this._pickId)&&(this._pickId.object.primitive=e)}},image:{get:function(){return this._imageId},set:function(e){l(e)?"string"==typeof e?this.setImage(e,e):l(e.src)?this.setImage(e.src,e):this.setImage(a(),e):(this._imageIndex=-1,this._imageSubRegion=void 0,this._imageId=void 0,this._image=void 0,this._imageIndexPromise=void 0,g(this,P))}},ready:{get:function(){return-1!==this._imageIndex}},_clampedPosition:{get:function(){return this._actualClampedPosition},set:function(e){this._actualClampedPosition=r.clone(e,this._actualClampedPosition),g(this,E)}}}),y.prototype.getPickId=function(e){return l(this._pickId)||(this._pickId=e.createPickId({primitive:this._pickPrimitive,collection:this._collection,id:this._id})),this._pickId},y.prototype._updateClamping=function(){y._updateClamping(this._billboardCollection,this)};var N=new n,L=new r;y._updateClamping=function(e,t){var i=e._scene;if(l(i)){var o=i.globe,a=o.ellipsoid,s=o._surface,u=i.frameState.mode,h=i.frameState.mapProjection,d=u!==t._mode;if(t._mode=u,(t._heightReference===p.NONE||d)&&l(t._removeCallbackFunc)&&(t._removeCallbackFunc(),t._removeCallbackFunc=void 0,t._clampedPosition=void 0),t._heightReference!==p.NONE&&l(t._position)){var m=a.cartesianToCartographic(t._position);if(l(m)){l(t._removeCallbackFunc)&&t._removeCallbackFunc();var v=function(e){if(t._heightReference===p.RELATIVE_TO_GROUND)if(t._mode===f.SCENE3D){var i=a.cartesianToCartographic(e,N);i.height+=m.height,a.cartographicToCartesian(i,e)}else e.x+=m.height;t._clampedPosition=r.clone(e,t._clampedPosition)};t._removeCallbackFunc=s.updateHeight(m,v);var _=o.getHeight(m);l(_)&&(n.clone(m,N),N.height=_,t._mode===f.SCENE3D?a.cartographicToCartesian(N,L):(h.project(N,L),r.fromElements(L.z,L.x,L.y,L)),v(L))}}}else if(t._heightReference!==p.NONE)throw new c("Height reference is not supported.")},y.prototype._loadImage=function(){var t,r=this._billboardCollection._textureAtlas,i=this._imageId,n=this._image,o=this._imageSubRegion;if(l(n)&&(t=r.addImage(i,n)),l(o)&&(t=r.addSubRegion(i,o)),this._imageIndexPromise=t,l(t)){var a=this;t.then(function(t){if(a._imageId===i&&a._image===n&&e.equals(a._imageSubRegion,o)){var s=r.textureCoordinates[t];a._imageWidth=r.texture.width*s.width,a._imageHeight=r.texture.height*s.height,a._imageIndex=t,a._ready=!0,a._image=void 0,a._imageIndexPromise=void 0,g(a,P)}}).otherwise(function(e){console.error("Error loading image for billboard: "+e),a._imageIndexPromise=void 0})}},y.prototype.setImage=function(e,t){this._imageId!==e&&(this._imageIndex=-1,this._imageSubRegion=void 0,this._imageId=e,this._image=t,l(this._billboardCollection._textureAtlas)&&this._loadImage())},y.prototype.setImageSubRegion=function(t,r){this._imageId===t&&e.equals(this._imageSubRegion,r)||(this._imageIndex=-1,this._imageId=t,this._imageSubRegion=e.clone(r),l(this._billboardCollection._textureAtlas)&&this._loadImage())},y.prototype._setTranslate=function(e){var r=this._translate;t.equals(r,e)||(t.clone(e,r),g(this,S))},y.prototype._getActualPosition=function(){return l(this._clampedPosition)?this._clampedPosition:this._actualPosition},y.prototype._setActualPosition=function(e){l(this._clampedPosition)||r.clone(e,this._actualPosition),g(this,E)};var F=new i;y._computeActualPosition=function(e,t,r,i){return l(e._clampedPosition)?(r.mode!==e._mode&&e._updateClamping(),e._clampedPosition):r.mode===f.SCENE3D?t:(h.multiplyByPoint(i,t,F),v.computeActualWgs84Position(r,F))};var B=new h,V=new i,z=new r,k=new t,U=new t;y._computeScreenSpacePosition=function(e,n,o,a,s,l){var u=s.camera,c=u.viewMatrix,d=u.frustum.projectionMatrix,p=h.multiplyTransformation(c,e,B),m=h.multiplyByVector(p,i.fromElements(n.x,n.y,n.z,1,V),V),f=r.multiplyComponents(o,r.normalize(m,z),z);m.x+=o.x+f.x,m.y+=o.y+f.y,m.z+=f.z;var _=h.multiplyByVector(d,m,V),g=v.clipToGLWindowCoordinates(s,_,l);a=t.clone(a,U),a.y=-a.y;var y=t.multiplyByScalar(a,s.context.uniformState.resolutionScale,k);return g.x+=y.x,g.y+=y.y,g};var G=new t(0,0);return y.prototype.computeScreenSpacePosition=function(e,r){var i=this._billboardCollection;l(r)||(r=new t),t.clone(this._pixelOffset,G),t.add(G,this._translate,G);var n=i.modelMatrix,o=this._getActualPosition(),a=y._computeScreenSpacePosition(n,o,this._eyeOffset,G,e,r);return a.y=e.canvas.clientHeight-a.y,a},y.prototype.equals=function(i){return this===i||l(i)&&this._id===i._id&&r.equals(this._position,i._position)&&this._imageId===i._imageId&&this._show===i._show&&this._scale===i._scale&&this._verticalOrigin===i._verticalOrigin&&this._horizontalOrigin===i._horizontalOrigin&&e.equals(this._imageSubRegion,i._imageSubRegion)&&o.equals(this._color,i._color)&&t.equals(this._pixelOffset,i._pixelOffset)&&t.equals(this._translate,i._translate)&&r.equals(this._eyeOffset,i._eyeOffset)&&d.equals(this._scaleByDistance,i._scaleByDistance)&&d.equals(this._translucencyByDistance,i._translucencyByDistance)&&d.equals(this._pixelOffsetScaleByDistance,i._pixelOffsetScaleByDistance)},y.prototype._destroy=function(){l(this._customData)&&(this._billboardCollection._scene.globe._surface.removeTileCustomData(this._customData),this._customData=void 0),this.image=void 0,this._pickId=this._pickId&&this._pickId.destroy(),this._billboardCollection=void 0},y}),r("Scene/BlendEquation",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={ADD:t.FUNC_ADD,SUBTRACT:t.FUNC_SUBTRACT,REVERSE_SUBTRACT:t.FUNC_REVERSE_SUBTRACT};return e(r)}),r("Scene/BlendFunction",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={ZERO:t.ZERO,ONE:t.ONE,SOURCE_COLOR:t.SRC_COLOR,ONE_MINUS_SOURCE_COLOR:t.ONE_MINUS_SRC_COLOR,DESTINATION_COLOR:t.DST_COLOR,ONE_MINUS_DESTINATION_COLOR:t.ONE_MINUS_DST_COLOR,SOURCE_ALPHA:t.SRC_ALPHA,ONE_MINUS_SOURCE_ALPHA:t.ONE_MINUS_SRC_ALPHA,DESTINATION_ALPHA:t.DST_ALPHA,ONE_MINUS_DESTINATION_ALPHA:t.ONE_MINUS_DST_ALPHA,CONSTANT_COLOR:t.CONSTANT_COLOR,ONE_MINUS_CONSTANT_COLOR:t.ONE_MINUS_CONSTANT_ALPHA,CONSTANT_ALPHA:t.CONSTANT_ALPHA,ONE_MINUS_CONSTANT_ALPHA:t.ONE_MINUS_CONSTANT_ALPHA,SOURCE_ALPHA_SATURATE:t.SRC_ALPHA_SATURATE};return e(r)}),r("Scene/BlendingState",["../Core/freezeObject","./BlendEquation","./BlendFunction"],function(e,t,r){"use strict";var i={DISABLED:e({enabled:!1}),ALPHA_BLEND:e({enabled:!0,equationRgb:t.ADD,equationAlpha:t.ADD,functionSourceRgb:r.SOURCE_ALPHA,functionSourceAlpha:r.SOURCE_ALPHA,functionDestinationRgb:r.ONE_MINUS_SOURCE_ALPHA,functionDestinationAlpha:r.ONE_MINUS_SOURCE_ALPHA}),PRE_MULTIPLIED_ALPHA_BLEND:e({enabled:!0,equationRgb:t.ADD,equationAlpha:t.ADD,functionSourceRgb:r.ONE,functionSourceAlpha:r.ONE,functionDestinationRgb:r.ONE_MINUS_SOURCE_ALPHA,functionDestinationAlpha:r.ONE_MINUS_SOURCE_ALPHA}),ADDITIVE_BLEND:e({enabled:!0,equationRgb:t.ADD,equationAlpha:t.ADD,functionSourceRgb:r.SOURCE_ALPHA,functionSourceAlpha:r.SOURCE_ALPHA,functionDestinationRgb:r.ONE,functionDestinationAlpha:r.ONE})};return e(i)}),r("Scene/Pass",["../Core/freezeObject"],function(e){"use strict";var t={COMPUTE:0,GLOBE:1,GROUND:2,OPAQUE:3,TRANSLUCENT:4,OVERLAY:5,NUMBER_OF_PASSES:6};return e(t)}),r("Renderer/Framebuffer",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/PixelFormat","./ContextLimits"],function(e,t,r,i,n,o,a){"use strict";function s(e,t,r){var i=e._gl;i.framebufferTexture2D(i.FRAMEBUFFER,t,r._target,r._texture,0)}function l(e,t,r){var i=e._gl;i.framebufferRenderbuffer(i.FRAMEBUFFER,t,i.RENDERBUFFER,r._getRenderbuffer())}var u=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.context._gl;a.maximumColorAttachments;this._gl=i,this._framebuffer=i.createFramebuffer(),this._colorTextures=[],this._colorRenderbuffers=[],this._activeColorAttachments=[],this._depthTexture=void 0,this._depthRenderbuffer=void 0,this._stencilRenderbuffer=void 0,this._depthStencilTexture=void 0,this._depthStencilRenderbuffer=void 0,this.destroyAttachments=e(r.destroyAttachments,!0);t(r.depthTexture)||t(r.depthRenderbuffer),t(r.depthStencilTexture)||t(r.depthStencilRenderbuffer);this._bind();var n,o,u,c,h;if(t(r.colorTextures)){var d=r.colorTextures;for(c=this._colorTextures.length=this._activeColorAttachments.length=d.length,u=0;c>u;++u)n=d[u],h=this._gl.COLOR_ATTACHMENT0+u,s(this,h,n),this._activeColorAttachments[u]=h,this._colorTextures[u]=n}if(t(r.colorRenderbuffers)){var p=r.colorRenderbuffers;for(c=this._colorRenderbuffers.length=this._activeColorAttachments.length=p.length,u=0;c>u;++u)o=p[u],h=this._gl.COLOR_ATTACHMENT0+u,l(this,h,o),this._activeColorAttachments[u]=h,this._colorRenderbuffers[u]=o}t(r.depthTexture)&&(n=r.depthTexture,s(this,this._gl.DEPTH_ATTACHMENT,n),this._depthTexture=n),t(r.depthRenderbuffer)&&(o=r.depthRenderbuffer,l(this,this._gl.DEPTH_ATTACHMENT,o),this._depthRenderbuffer=o),t(r.stencilRenderbuffer)&&(o=r.stencilRenderbuffer,l(this,this._gl.STENCIL_ATTACHMENT,o),this._stencilRenderbuffer=o),t(r.depthStencilTexture)&&(n=r.depthStencilTexture,s(this,this._gl.DEPTH_STENCIL_ATTACHMENT,n),this._depthStencilTexture=n),t(r.depthStencilRenderbuffer)&&(o=r.depthStencilRenderbuffer,l(this,this._gl.DEPTH_STENCIL_ATTACHMENT,o),this._depthStencilRenderbuffer=o),this._unBind()};return r(u.prototype,{status:{get:function(){this._bind();var e=this._gl.checkFramebufferStatus(this._gl.FRAMEBUFFER);return this._unBind(),e}},numberOfColorAttachments:{get:function(){return this._activeColorAttachments.length}},depthTexture:{get:function(){return this._depthTexture}},depthRenderbuffer:{get:function(){return this._depthRenderbuffer}},stencilRenderbuffer:{get:function(){return this._stencilRenderbuffer}},depthStencilTexture:{get:function(){return this._depthStencilTexture}},depthStencilRenderbuffer:{get:function(){return this._depthStencilRenderbuffer}},hasDepthAttachment:{get:function(){return!!(this.depthTexture||this.depthRenderbuffer||this.depthStencilTexture||this.depthStencilRenderbuffer)}}}),u.prototype._bind=function(){var e=this._gl;e.bindFramebuffer(e.FRAMEBUFFER,this._framebuffer)},u.prototype._unBind=function(){var e=this._gl;e.bindFramebuffer(e.FRAMEBUFFER,null)},u.prototype._getActiveColorAttachments=function(){return this._activeColorAttachments},u.prototype.getColorTexture=function(e){return this._colorTextures[e]},u.prototype.getColorRenderbuffer=function(e){return this._colorRenderbuffers[e]},u.prototype.isDestroyed=function(){return!1},u.prototype.destroy=function(){if(this.destroyAttachments){for(var e=0,r=this._colorTextures,n=r.length;n>e;++e){var o=r[e];t(o)&&o.destroy()}var a=this._colorRenderbuffers;for(n=a.length,e=0;n>e;++e){var s=a[e];t(s)&&s.destroy()}this._depthTexture=this._depthTexture&&this._depthTexture.destroy(),this._depthRenderbuffer=this._depthRenderbuffer&&this._depthRenderbuffer.destroy(),this._stencilRenderbuffer=this._stencilRenderbuffer&&this._stencilRenderbuffer.destroy(),this._depthStencilTexture=this._depthStencilTexture&&this._depthStencilTexture.destroy(),this._depthStencilRenderbuffer=this._depthStencilRenderbuffer&&this._depthStencilRenderbuffer.destroy()}return this._gl.deleteFramebuffer(this._framebuffer),i(this)},u}),r("Renderer/MipmapHint",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={DONT_CARE:t.DONT_CARE,FASTEST:t.FASTEST,NICEST:t.NICEST,validate:function(e){return e===r.DONT_CARE||e===r.FASTEST||e===r.NICEST}};return e(r)}),r("Renderer/PixelDatatype",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={UNSIGNED_BYTE:t.UNSIGNED_BYTE,UNSIGNED_SHORT:t.UNSIGNED_SHORT,UNSIGNED_INT:t.UNSIGNED_INT,FLOAT:t.FLOAT,UNSIGNED_INT_24_8:t.UNSIGNED_INT_24_8,UNSIGNED_SHORT_4_4_4_4:t.UNSIGNED_SHORT_4_4_4_4,UNSIGNED_SHORT_5_5_5_1:t.UNSIGNED_SHORT_5_5_5_1,UNSIGNED_SHORT_5_6_5:t.UNSIGNED_SHORT_5_6_5,validate:function(e){return e===r.UNSIGNED_BYTE||e===r.UNSIGNED_SHORT||e===r.UNSIGNED_INT||e===r.FLOAT||e===r.UNSIGNED_INT_24_8||e===r.UNSIGNED_SHORT_4_4_4_4||e===r.UNSIGNED_SHORT_5_5_5_1||e===r.UNSIGNED_SHORT_5_6_5}};return e(r)}),r("Renderer/TextureMagnificationFilter",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={NEAREST:t.NEAREST,LINEAR:t.LINEAR,validate:function(e){return e===r.NEAREST||e===r.LINEAR}};return e(r)}),r("Renderer/TextureMinificationFilter",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={NEAREST:t.NEAREST,LINEAR:t.LINEAR,NEAREST_MIPMAP_NEAREST:t.NEAREST_MIPMAP_NEAREST,LINEAR_MIPMAP_NEAREST:t.LINEAR_MIPMAP_NEAREST,NEAREST_MIPMAP_LINEAR:t.NEAREST_MIPMAP_LINEAR,LINEAR_MIPMAP_LINEAR:t.LINEAR_MIPMAP_LINEAR,validate:function(e){return e===r.NEAREST||e===r.LINEAR||e===r.NEAREST_MIPMAP_NEAREST||e===r.LINEAR_MIPMAP_NEAREST||e===r.NEAREST_MIPMAP_LINEAR||e===r.LINEAR_MIPMAP_LINEAR}};return e(r)}),r("Renderer/TextureWrap",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={CLAMP_TO_EDGE:t.CLAMP_TO_EDGE,REPEAT:t.REPEAT,MIRRORED_REPEAT:t.MIRRORED_REPEAT,validate:function(e){return e===r.CLAMP_TO_EDGE||e===r.REPEAT||e===r.MIRRORED_REPEAT}};return e(r)}),r("Renderer/Sampler",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","./TextureMagnificationFilter","./TextureMinificationFilter","./TextureWrap"],function(e,t,r,i,n,o,a){"use strict";var s=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.wrapS,a.CLAMP_TO_EDGE),s=e(r.wrapT,a.CLAMP_TO_EDGE),l=e(r.minificationFilter,o.LINEAR),u=e(r.magnificationFilter,n.LINEAR),c=t(r.maximumAnisotropy)?r.maximumAnisotropy:1;this._wrapS=i,this._wrapT=s,this._minificationFilter=l,this._magnificationFilter=u,this._maximumAnisotropy=c};return r(s.prototype,{wrapS:{get:function(){return this._wrapS}},wrapT:{get:function(){return this._wrapT}},minificationFilter:{get:function(){return this._minificationFilter}},magnificationFilter:{get:function(){return this._magnificationFilter}},maximumAnisotropy:{get:function(){return this._maximumAnisotropy}}}),s}),r("Renderer/Texture",["../Core/Cartesian2","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Math","../Core/PixelFormat","./ContextLimits","./MipmapHint","./PixelDatatype","./Sampler","./TextureMagnificationFilter","./TextureMinificationFilter","./TextureWrap","./WebGLConstants"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";var v=function(i){i=t(i,t.EMPTY_OBJECT);var n=i.context,a=i.source,l=r(a)?a.width:i.width,u=r(a)?a.height:i.height,d=t(i.pixelFormat,s.RGBA),p=t(i.pixelDatatype,c.UNSIGNED_BYTE),m=d;if(n.webgl2&&(d===s.DEPTH_STENCIL?m=f.DEPTH24_STENCIL8:d===s.DEPTH_COMPONENT&&(p===c.UNSIGNED_SHORT?m=f.DEPTH_COMPONENT16:p===c.UNSIGNED_INT&&(m=f.DEPTH_COMPONENT24))),p===c.FLOAT&&!n.floatingPointTexture)throw new o("When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension. Check context.floatingPointTexture.");if(s.isDepthFormat(d)&&!n.depthTexture)throw new o("When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, this WebGL implementation must support WEBGL_depth_texture. Check context.depthTexture.");var v=i.preMultiplyAlpha||d===s.RGB||d===s.LUMINANCE,_=t(i.flipY,!0),g=n._gl,y=g.TEXTURE_2D,C=g.createTexture();g.activeTexture(g.TEXTURE0),g.bindTexture(y,C),r(a)?(g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,v),g.pixelStorei(g.UNPACK_FLIP_Y_WEBGL,_),r(a.arrayBufferView)?g.texImage2D(y,0,m,l,u,0,d,p,a.arrayBufferView):r(a.framebuffer)?(a.framebuffer!==n.defaultFramebuffer&&a.framebuffer._bind(),g.copyTexImage2D(y,0,m,a.xOffset,a.yOffset,l,u,0),a.framebuffer!==n.defaultFramebuffer&&a.framebuffer._unBind()):g.texImage2D(y,0,m,d,p,a)):g.texImage2D(y,0,m,l,u,0,d,p,null),g.bindTexture(y,null),this._context=n,this._textureFilterAnisotropic=n._textureFilterAnisotropic,this._textureTarget=y,this._texture=C,this._pixelFormat=d,this._pixelDatatype=p,this._width=l,this._height=u,this._dimensions=new e(l,u),this._preMultiplyAlpha=v,this._flipY=_,this._sampler=void 0,this.sampler=r(i.sampler)?i.sampler:new h};return v.fromFramebuffer=function(e){e=t(e,t.EMPTY_OBJECT);var i=e.context,n=i._gl,o=t(e.pixelFormat,s.RGB),a=t(e.framebufferXOffset,0),l=t(e.framebufferYOffset,0),u=t(e.width,n.drawingBufferWidth),c=t(e.height,n.drawingBufferHeight),h=e.framebuffer,d=new v({context:i,width:u,height:c,pixelFormat:o,source:{framebuffer:r(h)?h:i.defaultFramebuffer,xOffset:a,yOffset:l,width:u,height:c}});return d},i(v.prototype,{sampler:{get:function(){return this._sampler},set:function(e){var t=e.minificationFilter,i=e.magnificationFilter,n=t===p.NEAREST_MIPMAP_NEAREST||t===p.NEAREST_MIPMAP_LINEAR||t===p.LINEAR_MIPMAP_NEAREST||t===p.LINEAR_MIPMAP_LINEAR;this._pixelDatatype===c.FLOAT&&(t=n?p.NEAREST_MIPMAP_NEAREST:p.NEAREST,i=d.NEAREST);var o=this._context._gl,a=this._textureTarget;o.activeTexture(o.TEXTURE0),o.bindTexture(a,this._texture),o.texParameteri(a,o.TEXTURE_MIN_FILTER,t),o.texParameteri(a,o.TEXTURE_MAG_FILTER,i),o.texParameteri(a,o.TEXTURE_WRAP_S,e.wrapS),o.texParameteri(a,o.TEXTURE_WRAP_T,e.wrapT),r(this._textureFilterAnisotropic)&&o.texParameteri(a,this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT,e.maximumAnisotropy),o.bindTexture(a,null),this._sampler=e}},pixelFormat:{get:function(){return this._pixelFormat}},pixelDatatype:{get:function(){return this._pixelDatatype}},dimensions:{get:function(){return this._dimensions}},preMultiplyAlpha:{get:function(){return this._preMultiplyAlpha}},flipY:{get:function(){return this._flipY}},width:{get:function(){return this._width}},height:{get:function(){return this._height}},_target:{get:function(){return this._textureTarget}}}),v.prototype.copyFrom=function(e,r,i){r=t(r,0),i=t(i,0);var n=this._context._gl,o=this._textureTarget;n.pixelStorei(n.UNPACK_PREMULTIPLY_ALPHA_WEBGL,this._preMultiplyAlpha),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,this._flipY),n.activeTexture(n.TEXTURE0),n.bindTexture(o,this._texture),e.arrayBufferView?n.texSubImage2D(o,0,r,i,e.width,e.height,this._pixelFormat,this._pixelDatatype,e.arrayBufferView):n.texSubImage2D(o,0,r,i,this._pixelFormat,this._pixelDatatype,e),n.bindTexture(o,null)},v.prototype.copyFromFramebuffer=function(e,r,i,n,o,a){e=t(e,0),r=t(r,0),i=t(i,0),n=t(n,0),o=t(o,this._width),a=t(a,this._height);var s=this._context._gl,l=this._textureTarget;s.activeTexture(s.TEXTURE0),s.bindTexture(l,this._texture),s.copyTexSubImage2D(l,0,e,r,i,n,o,a),s.bindTexture(l,null)},v.prototype.generateMipmap=function(e){e=t(e,u.DONT_CARE);var r=this._context._gl,i=this._textureTarget;r.hint(r.GENERATE_MIPMAP_HINT,e),r.activeTexture(r.TEXTURE0),r.bindTexture(i,this._texture),r.generateMipmap(i),r.bindTexture(i,null)},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){return this._context._gl.deleteTexture(this._texture),n(this)},v}),r("Scene/TextureAtlas",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/loadImage","../Core/PixelFormat","../Core/RuntimeError","../Renderer/Framebuffer","../Renderer/RenderState","../Renderer/Texture","../ThirdParty/when"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,r,n,o,a){this.bottomLeft=i(e,t.ZERO),this.topRight=i(r,t.ZERO),this.childNode1=n,this.childNode2=o,this.imageIndex=a}function v(r,i){var o=r._context,a=r.numberOfImages,s=2;if(a>0){var l=r._texture.width,u=r._texture.height,c=s*(l+i.width+r._borderWidthInPixels),m=s*(u+i.height+r._borderWidthInPixels),v=l/c,_=u/m,g=new f(new t(l+r._borderWidthInPixels,0),new t(c,u)),y=new f(new t,new t(c,u),r._root,g),C=new f(new t(0,u+r._borderWidthInPixels),new t(c,m)),E=new f(new t,new t(c,m),y,C);r._root=E;for(var S=0;Ss||0>l)return void 0;if(0===s&&0===l)return r;if(s>l){r.childNode1=new f(new t(r.bottomLeft.x,r.bottomLeft.y),new t(r.bottomLeft.x+i.width,r.topRight.y));var u=r.bottomLeft.x+i.width+e._borderWidthInPixels;ur;++r)e[r]&&e[r]._destroy()}function D(e){if(e._billboardsRemoved){e._billboardsRemoved=!1;for(var t=[],r=e._billboards,i=r.length,n=0,o=0;i>n;++n){var a=r[n];a&&(a._index=o++,t.push(a))}e._billboards=t}}function R(e){var t=16384,r=e.cache.billboardCollection_indexBufferBatched;if(s(r))return r;for(var i=6*t-6,n=new Uint16Array(i),o=0,a=0;i>o;o+=6,a+=4)n[o]=a,n[o+1]=a+1,n[o+2]=a+2,n[o+3]=a+0,n[o+4]=a+2,n[o+5]=a+3;return r=f.createIndexBuffer({context:e,typedArray:n,usage:v.STATIC_DRAW,indexDatatype:d.UNSIGNED_SHORT}),r.vertexArrayDestroyable=!1,e.cache.billboardCollection_indexBufferBatched=r,r}function O(e){var t=e.cache.billboardCollection_indexBufferInstanced;return s(t)?t:(t=f.createIndexBuffer({context:e,typedArray:new Uint16Array([0,1,2,0,2,3]),usage:v.STATIC_DRAW,indexDatatype:d.UNSIGNED_SHORT}),t.vertexArrayDestroyable=!1,e.cache.billboardCollection_indexBufferInstanced=t,t)}function N(e){var t=e.cache.billboardCollection_vertexBufferInstanced;return s(t)?t:(t=f.createVertexBuffer({context:e,typedArray:new Float32Array([0,0,1,0,1,1,0,1]),usage:v.STATIC_DRAW}),t.vertexArrayDestroyable=!1,e.cache.billboardCollection_vertexBufferInstanced=t,t)}function L(e,t,r,i){var n=[{index:Y.positionHighAndScale,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[Z]},{index:Y.positionLowAndRotation,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[Z]},{index:Y.compressedAttribute0,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[K]},{index:Y.compressedAttribute1,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[ae]},{index:Y.compressedAttribute2,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[re]},{index:Y.eyeOffset,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[J]},{index:Y.scaleByDistance,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[oe]},{index:Y.pixelOffsetScaleByDistance,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[se]}];i&&n.push({index:Y.direction,componentsPerAttribute:2,componentDatatype:o.FLOAT,vertexBuffer:N(e)});var a=i?t:4*t;return new E(e,n,a,i)}function F(e,r,i,n,o){var a,s=n[Y.positionHighAndScale],l=n[Y.positionLowAndRotation],u=o._getActualPosition();e._mode===A.SCENE3D&&(t.expand(e._baseVolume,u,e._baseVolume),e._boundingVolumeDirty=!0),h.fromCartesian(u,pe);var c=o.scale,d=o.rotation;0!==d&&(e._shaderRotation=!0),e._maxScale=Math.max(e._maxScale,c);var p=pe.high,m=pe.low;e._instanced?(a=o._index,s(a,p.x,p.y,p.z,c),l(a,m.x,m.y,m.z,d)):(a=4*o._index,s(a+0,p.x,p.y,p.z,c),s(a+1,p.x,p.y,p.z,c),s(a+2,p.x,p.y,p.z,c),s(a+3,p.x,p.y,p.z,c),l(a+0,m.x,m.y,m.z,d),l(a+1,m.x,m.y,m.z,d),l(a+2,m.x,m.y,m.z,d),l(a+3,m.x,m.y,m.z,d))}function B(t,r,i,n,o){var a,s=n[Y.compressedAttribute0],l=o.pixelOffset,u=l.x,c=l.y,h=o._translate,d=h.x,m=h.y;t._maxPixelOffset=Math.max(t._maxPixelOffset,Math.abs(u+d),Math.abs(-c+m));var f=o.horizontalOrigin,v=o.verticalOrigin,_=o.show;0===o.color.alpha&&(_=!1),t._allHorizontalCenter=t._allHorizontalCenter&&f===x.CENTER,t._allVerticalCenter=t._allVerticalCenter&&v===x.CENTER;var g=0,y=0,C=0,E=0,S=o._imageIndex;if(-1!==S){var w=i[S];g=w.x,y=w.y,C=w.width,E=w.height}var T=g+C,b=y+E,P=Math.floor(p.clamp(u,-fe,fe)+fe)*ge;P+=(f+1)*ye,P+=(v+1)*Ce,P+=(_?1:0)*Ee; +var A=Math.floor(p.clamp(c,-fe,fe)+fe)*_e,I=Math.floor(p.clamp(d,-fe,fe)+fe)*_e,M=(p.clamp(m,-fe,fe)+fe)*Se,D=Math.floor(M),R=Math.floor((M-D)*_e);A+=D,I+=R,me.x=g,me.y=y;var O=e.compressTextureCoordinates(me);me.x=T;var N=e.compressTextureCoordinates(me);me.y=b;var L=e.compressTextureCoordinates(me);me.x=g;var F=e.compressTextureCoordinates(me);t._instanced?(a=o._index,s(a,P,A,I,O)):(a=4*o._index,s(a+0,P+we,A,I,O),s(a+1,P+Te,A,I,N),s(a+2,P+be,A,I,L),s(a+3,P+xe,A,I,F))}function V(t,r,n,o,l){var u,c=o[Y.compressedAttribute1],h=l.alignedAxis;i.equals(h,i.ZERO)||(t._shaderAlignedAxis=!0);var d=0,m=1,f=1,v=1,_=l.translucencyByDistance;s(_)&&(d=_.near,m=_.nearValue,f=_.far,v=_.farValue,(1!==m||1!==v)&&(t._shaderTranslucencyByDistance=!0));var g=0,y=l._imageIndex;if(-1!==y){var C=n[y];g=C.width}var E=t._textureAtlas.texture.width,S=Math.ceil(.5*a(l.width,E*g));t._maxSize=Math.max(t._maxSize,S);var w=p.clamp(S,0,ve),T=0;Math.abs(i.magnitudeSquared(h)-1)c;++c){var h=r[c],d=h.position,p=T._computeActualPosition(h,d,n,o);s(p)&&(h._setActualPosition(p),a?u.push(p):t.expand(l,p,l))}a&&t.fromPoints(u,l)}function q(e,t){var r=t.mode,i=e._billboards,n=e._billboardsToUpdate,o=e._modelMatrix;e._createVertexArray||e._mode!==r||r!==A.SCENE3D&&!m.equals(o,e.modelMatrix)?(e._mode=r,m.clone(e.modelMatrix,o),e._createVertexArray=!0,(r===A.SCENE3D||r===A.SCENE2D||r===A.COLUMBUS_VIEW)&&H(e,i,i.length,t,o,!0)):r===A.MORPHING?H(e,i,i.length,t,o,!0):(r===A.SCENE2D||r===A.COLUMBUS_VIEW)&&H(e,n,e._billboardsToUpdateIndex,t,o,!1)}function j(e,t,r){var i=1;if(!e._allSizedInMeters||0!==e._maxPixelOffset){var n=t.camera,o=n.distanceToBoundingSphere(r),a=t.context,s=t.camera.frustum.getPixelDimensions(a.drawingBufferWidth,a.drawingBufferHeight,o,Pe);i=Math.max(s.x,s.y)}var l=i*e._maxScale*e._maxSize*2;e._allHorizontalCenter&&e._allVerticalCenter&&(l*=.5);var u=i*e._maxPixelOffset+e._maxEyeOffset;r.radius+=l+u}var Y,X=T.SHOW_INDEX,Z=T.POSITION_INDEX,K=T.PIXEL_OFFSET_INDEX,J=T.EYE_OFFSET_INDEX,Q=T.HORIZONTAL_ORIGIN_INDEX,$=T.VERTICAL_ORIGIN_INDEX,ee=T.SCALE_INDEX,te=T.IMAGE_INDEX_INDEX,re=T.COLOR_INDEX,ie=T.ROTATION_INDEX,ne=T.ALIGNED_AXIS_INDEX,oe=T.SCALE_BY_DISTANCE_INDEX,ae=T.TRANSLUCENCY_BY_DISTANCE_INDEX,se=T.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX,le=T.NUMBER_OF_PROPERTIES,ue={positionHighAndScale:0,positionLowAndRotation:1,compressedAttribute0:2,compressedAttribute1:3,compressedAttribute2:4,eyeOffset:5,scaleByDistance:6,pixelOffsetScaleByDistance:7},ce={direction:0,positionHighAndScale:1,positionLowAndRotation:2,compressedAttribute0:3,compressedAttribute1:4,compressedAttribute2:5,eyeOffset:6,scaleByDistance:7,pixelOffsetScaleByDistance:8},he=function(e){e=a(e,a.EMPTY_OBJECT),this._scene=e.scene,this._textureAtlas=void 0,this._textureAtlasGUID=void 0,this._destroyTextureAtlas=!0,this._sp=void 0,this._rs=void 0,this._vaf=void 0,this._spPick=void 0,this._billboards=[],this._billboardsToUpdate=[],this._billboardsToUpdateIndex=0,this._billboardsRemoved=!1,this._createVertexArray=!1,this._shaderRotation=!1,this._compiledShaderRotation=!1,this._compiledShaderRotationPick=!1,this._shaderAlignedAxis=!1,this._compiledShaderAlignedAxis=!1,this._compiledShaderAlignedAxisPick=!1,this._shaderScaleByDistance=!1,this._compiledShaderScaleByDistance=!1,this._compiledShaderScaleByDistancePick=!1,this._shaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistancePick=!1,this._shaderPixelOffsetScaleByDistance=!1,this._compiledShaderPixelOffsetScaleByDistance=!1,this._compiledShaderPixelOffsetScaleByDistancePick=!1,this._propertiesChanged=new Uint32Array(le),this._maxSize=0,this._maxEyeOffset=0,this._maxScale=1,this._maxPixelOffset=0,this._allHorizontalCenter=!0,this._allVerticalCenter=!0,this._allSizedInMeters=!0,this._baseVolume=new t,this._baseVolumeWC=new t,this._baseVolume2D=new t,this._boundingVolume=new t,this._boundingVolumeDirty=!1,this._colorCommands=[],this._pickCommands=[],this.modelMatrix=m.clone(a(e.modelMatrix,m.IDENTITY)),this._modelMatrix=m.clone(m.IDENTITY),this.debugShowBoundingVolume=a(e.debugShowBoundingVolume,!1),this._mode=A.SCENE3D,this._buffersUsage=[v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW];var r=this;this._uniforms={u_atlas:function(){return r._textureAtlas.texture}}};l(he.prototype,{length:{get:function(){return D(this),this._billboards.length}},textureAtlas:{get:function(){return this._textureAtlas},set:function(e){this._textureAtlas!==e&&(this._textureAtlas=this._destroyTextureAtlas&&this._textureAtlas&&this._textureAtlas.destroy(),this._textureAtlas=e,this._createVertexArray=!0)}},destroyTextureAtlas:{get:function(){return this._destroyTextureAtlas},set:function(e){this._destroyTextureAtlas=e}}}),he.prototype.add=function(e){var t=new T(e,this);return t._index=this._billboards.length,this._billboards.push(t),this._createVertexArray=!0,t},he.prototype.remove=function(e){return this.contains(e)?(this._billboards[e._index]=null,this._billboardsRemoved=!0,this._createVertexArray=!0,e._destroy(),!0):!1},he.prototype.removeAll=function(){M(this._billboards),this._billboards=[],this._billboardsToUpdate=[],this._billboardsToUpdateIndex=0,this._billboardsRemoved=!1,this._createVertexArray=!0},he.prototype._updateBillboard=function(e,t){e._dirty||(this._billboardsToUpdate[this._billboardsToUpdateIndex++]=e),++this._propertiesChanged[t]},he.prototype.contains=function(e){return s(e)&&e._billboardCollection===this},he.prototype.get=function(e){return D(this),this._billboards[e]};var de;he.prototype.computeNewBuffersUsage=function(){for(var e=this._buffersUsage,t=!1,r=this._propertiesChanged,i=0;le>i;++i){var n=0===r[i]?v.STATIC_DRAW:v.STREAM_DRAW;t=t||e[i]!==n,e[i]=n}return t};var pe=new h,me=new r,fe=32768,ve=65536,_e=256,ge=128,ye=32,Ce=8,Ee=4,Se=1/256,we=0,Te=2,be=3,xe=1,Pe=new r,Ae=[];return he.prototype.update=function(e){D(this);var r=this._billboards,i=r.length,n=e.context;this._instanced=n.instancedArrays,Y=this._instanced?ce:ue,de=this._instanced?O:R;var o=this._textureAtlas;if(!s(o)){o=this._textureAtlas=new I({context:n});for(var a=0;i>a;++a)r[a]._loadImage()}var l=o.textureCoordinates;if(0!==l.length){q(this,e),r=this._billboards,i=r.length;var u=this._billboardsToUpdate,c=this._billboardsToUpdateIndex,h=this._propertiesChanged,d=o.guid,p=this._createVertexArray||this._textureAtlasGUID!==d;this._textureAtlasGUID=d;var f,v=e.passes,E=v.pick;if(p||!E&&this.computeNewBuffersUsage()){this._createVertexArray=!1;for(var T=0;le>T;++T)h[T]=0;if(this._vaf=this._vaf&&this._vaf.destroy(),i>0){this._vaf=L(n,i,this._buffersUsage,this._instanced),f=this._vaf.writers;for(var x=0;i>x;++x){var M=this._billboards[x];M._dirty=!1,W(this,n,l,f,M)}this._vaf.commit(de(n))}this._billboardsToUpdateIndex=0}else if(c>0){var N=Ae;N.length=0,(h[Z]||h[ie]||h[ee])&&N.push(F),(h[te]||h[K]||h[Q]||h[$]||h[X])&&(N.push(B),this._instanced&&N.push(k)),(h[te]||h[ne]||h[ae])&&N.push(V),(h[te]||h[re])&&N.push(z),h[J]&&N.push(k),h[oe]&&N.push(U),h[se]&&N.push(G);var H=N.length;if(f=this._vaf.writers,c/i>.1){for(var he=0;c>he;++he){var pe=u[he];pe._dirty=!1;for(var me=0;H>me;++me)N[me](this,n,l,f,pe)}this._vaf.commit(de(n))}else{for(var fe=0;c>fe;++fe){var ve=u[fe];ve._dirty=!1;for(var _e=0;H>_e;++_e)N[_e](this,n,l,f,ve);this._instanced?this._vaf.subCommit(ve._index,1):this._vaf.subCommit(4*ve._index,4)}this._vaf.endSubCommits()}this._billboardsToUpdateIndex=0}if(c>1.5*i&&(u.length=i),s(this._vaf)&&s(this._vaf.va)){this._boundingVolumeDirty&&(this._boundingVolumeDirty=!1,t.transform(this._baseVolume,this.modelMatrix,this._baseVolumeWC));var ge,ye=m.IDENTITY;e.mode===A.SCENE3D?(ye=this.modelMatrix,ge=t.clone(this._baseVolumeWC,this._boundingVolume)):ge=t.clone(this._baseVolume2D,this._boundingVolume),j(this,e,ge);var Ce,Ee,Se,we,Te,be,xe=e.commandList;if(v.render){var Pe=this._colorCommands;for(s(this._rs)||(this._rs=g.fromCache({depthTest:{enabled:!0},blending:b.ALPHA_BLEND})),s(this._sp)&&this._shaderRotation===this._compiledShaderRotation&&this._shaderAlignedAxis===this._compiledShaderAlignedAxis&&this._shaderScaleByDistance===this._compiledShaderScaleByDistance&&this._shaderTranslucencyByDistance===this._compiledShaderTranslucencyByDistance&&this._shaderPixelOffsetScaleByDistance===this._compiledShaderPixelOffsetScaleByDistance||(we=new C({sources:[w]}),this._instanced&&we.defines.push("INSTANCED"),this._shaderRotation&&we.defines.push("ROTATION"),this._shaderAlignedAxis&&we.defines.push("ALIGNED_AXIS"),this._shaderScaleByDistance&&we.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&we.defines.push("EYE_DISTANCE_TRANSLUCENCY"),this._shaderPixelOffsetScaleByDistance&&we.defines.push("EYE_DISTANCE_PIXEL_OFFSET"),s(this._scene)&&we.defines.push("CLAMPED_TO_GROUND"),this._sp=y.replaceCache({context:n,shaderProgram:this._sp,vertexShaderSource:we,fragmentShaderSource:S,attributeLocations:Y}),this._compiledShaderRotation=this._shaderRotation,this._compiledShaderAlignedAxis=this._shaderAlignedAxis,this._compiledShaderScaleByDistance=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistance=this._shaderTranslucencyByDistance,this._compiledShaderPixelOffsetScaleByDistance=this._shaderPixelOffsetScaleByDistance),Ce=this._vaf.va,Ee=Ce.length,Pe.length=Ee,be=0;Ee>be;++be)Se=Pe[be],s(Se)||(Se=Pe[be]=new _({pass:P.OPAQUE,owner:this})),Se.boundingVolume=ge,Se.modelMatrix=ye,Se.count=Ce[be].indicesCount,Se.shaderProgram=this._sp,Se.uniformMap=this._uniforms,Se.vertexArray=Ce[be].va,Se.renderState=this._rs,Se.debugShowBoundingVolume=this.debugShowBoundingVolume,this._instanced&&(Se.count=6,Se.instanceCount=i),xe.push(Se)}if(E){var Ie=this._pickCommands;for(s(this._spPick)&&this._shaderRotation===this._compiledShaderRotationPick&&this._shaderAlignedAxis===this._compiledShaderAlignedAxisPick&&this._shaderScaleByDistance===this._compiledShaderScaleByDistancePick&&this._shaderTranslucencyByDistance===this._compiledShaderTranslucencyByDistancePick&&this._shaderPixelOffsetScaleByDistance===this._compiledShaderPixelOffsetScaleByDistancePick||(we=new C({defines:["RENDER_FOR_PICK"],sources:[w]}),this._instanced&&we.defines.push("INSTANCED"),this._shaderRotation&&we.defines.push("ROTATION"),this._shaderAlignedAxis&&we.defines.push("ALIGNED_AXIS"),this._shaderScaleByDistance&&we.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&we.defines.push("EYE_DISTANCE_TRANSLUCENCY"),this._shaderPixelOffsetScaleByDistance&&we.defines.push("EYE_DISTANCE_PIXEL_OFFSET"),s(this._scene)&&we.defines.push("CLAMPED_TO_GROUND"),Te=new C({defines:["RENDER_FOR_PICK"],sources:[S]}),this._spPick=y.replaceCache({context:n,shaderProgram:this._spPick,vertexShaderSource:we,fragmentShaderSource:Te,attributeLocations:Y}),this._compiledShaderRotationPick=this._shaderRotation,this._compiledShaderAlignedAxisPick=this._shaderAlignedAxis,this._compiledShaderScaleByDistancePick=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistancePick=this._shaderTranslucencyByDistance,this._compiledShaderPixelOffsetScaleByDistancePick=this._shaderPixelOffsetScaleByDistance),Ce=this._vaf.va,Ee=Ce.length,Ie.length=Ee,be=0;Ee>be;++be)Se=Ie[be],s(Se)||(Se=Ie[be]=new _({pass:P.OPAQUE,owner:this})),Se.boundingVolume=ge,Se.modelMatrix=ye,Se.count=Ce[be].indicesCount,Se.shaderProgram=this._spPick,Se.uniformMap=this._uniforms,Se.vertexArray=Ce[be].va,Se.renderState=this._rs,this._instanced&&(Se.count=6,Se.instanceCount=i),xe.push(Se)}}}},he.prototype.isDestroyed=function(){return!1},he.prototype.destroy=function(){return this._textureAtlas=this._destroyTextureAtlas&&this._textureAtlas&&this._textureAtlas.destroy(),this._sp=this._sp&&this._sp.destroy(),this._spPick=this._spPick&&this._spPick.destroy(),this._vaf=this._vaf&&this._vaf.destroy(),M(this._billboards),u(this)},he}),r("DataSources/BoundingSphereState",["../Core/freezeObject"],function(e){"use strict";var t={DONE:0,PENDING:1,FAILED:2};return e(t)}),r("DataSources/Property",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Iso8601"],function(e,t,r,i,n){"use strict";var o=function(){i.throwInstantiationError()};return r(o.prototype,{isConstant:{get:i.throwInstantiationError},definitionChanged:{get:i.throwInstantiationError}}),o.prototype.getValue=i.throwInstantiationError,o.prototype.equals=i.throwInstantiationError,o.equals=function(e,r){return e===r||t(e)&&e.equals(r)},o.arrayEquals=function(e,r){if(e===r)return!0;if(!t(e)||!t(r)||e.length!==r.length)return!1;for(var i=e.length,n=0;i>n;n++)if(!o.equals(e[n],r[n]))return!1;return!0},o.isConstant=function(e){return!t(e)||e.isConstant},o.getValueOrUndefined=function(e,r,i){return t(e)?e.getValue(r,i):void 0},o.getValueOrDefault=function(r,i,n,o){return t(r)?e(r.getValue(i,o),n):n},o.getValueOrClonedDefault=function(e,r,i,n){var o;return t(e)&&(o=e.getValue(r,n)),t(o)||(o=i.clone(o)),o},o}),r("DataSources/BillboardVisualizer",["../Core/AssociativeArray","../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/NearFarScalar","../Scene/BillboardCollection","../Scene/HorizontalOrigin","../Scene/VerticalOrigin","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){if(o(e)){var r=e.billboard;o(r)&&(e.textureValue=void 0,e.billboard=void 0,r.show=!1,r.image=void 0,t.push(r._index))}}var f=n.WHITE,v=i.ZERO,_=r.ZERO,g=1,y=0,C=i.ZERO,E=c.CENTER,S=h.CENTER,w=!1,T=new i,b=new n,x=new i,P=new r,A=new l,I=new l,M=new l,D=new t,R=function(e){this.entity=e,this.billboard=void 0,this.textureValue=void 0},O=function(t,r){r.collectionChanged.addEventListener(O.prototype._onCollectionChanged,this),this._scene=t,this._unusedIndexes=[],this._billboardCollection=void 0,this._entityCollection=r,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return O.prototype.update=function(e){for(var t=this._items.values,r=this._unusedIndexes,i=0,n=t.length;n>i;i++){var a,s=t[i],l=s.entity,c=l._billboard,h=s.billboard,d=l.isShowing&&l.isAvailable(e)&&p.getValueOrDefault(c._show,e,!0);if(d&&(T=p.getValueOrUndefined(l._position,e,T),a=p.getValueOrUndefined(c._image,e),d=o(T)&&o(a)),d){if(!o(h)){var R=this._billboardCollection;o(R)||(R=new u,this._billboardCollection=R,this._scene.primitives.add(R));var O=r.length;h=O>0?R.get(r.pop()):R.add(),h.id=l,h.image=void 0,s.billboard=h}h.show=d,s.textureValue!==a&&(h.image=a,s.textureValue=a),h.position=T,h.color=p.getValueOrDefault(c._color,e,f,b),h.eyeOffset=p.getValueOrDefault(c._eyeOffset,e,v,x),h.pixelOffset=p.getValueOrDefault(c._pixelOffset,e,_,P),h.scale=p.getValueOrDefault(c._scale,e,g),h.rotation=p.getValueOrDefault(c._rotation,e,y),h.alignedAxis=p.getValueOrDefault(c._alignedAxis,e,C),h.horizontalOrigin=p.getValueOrDefault(c._horizontalOrigin,e,E),h.verticalOrigin=p.getValueOrDefault(c._verticalOrigin,e,S),h.width=p.getValueOrUndefined(c._width,e),h.height=p.getValueOrUndefined(c._height,e),h.scaleByDistance=p.getValueOrUndefined(c._scaleByDistance,e,A),h.translucencyByDistance=p.getValueOrUndefined(c._translucencyByDistance,e,I),h.pixelOffsetScaleByDistance=p.getValueOrUndefined(c._pixelOffsetScaleByDistance,e,M),h.sizeInMeters=p.getValueOrDefault(c._sizeInMeters,w);var N=p.getValueOrUndefined(c._imageSubRegion,e,D);o(N)&&h.setImageSubRegion(h._imageId,N)}else m(s,r)}return!0},O.prototype.getBoundingSphere=function(e,t){var r=this._items.get(e.id);return o(r)&&o(r.billboard)?(t.center=i.clone(r.billboard.position,t.center),t.radius=0,d.DONE):d.FAILED},O.prototype.isDestroyed=function(){return!1},O.prototype.destroy=function(){return this._entityCollection.collectionChanged.removeEventListener(O.prototype._onCollectionChanged,this),o(this._billboardCollection)&&this._scene.primitives.remove(this._billboardCollection),a(this)},O.prototype._onCollectionChanged=function(e,t,r,i){var n,a,s=this._unusedIndexes,l=this._items;for(n=t.length-1;n>-1;n--)a=t[n],o(a._billboard)&&o(a._position)&&l.set(a.id,new R(a));for(n=i.length-1;n>-1;n--)a=i[n],o(a._billboard)&&o(a._position)?l.contains(a.id)||l.set(a.id,new R(a)):(m(l.get(a.id),s),l.remove(a.id));for(n=r.length-1;n>-1;n--)a=r[n],m(l.get(a.id),s),l.remove(a.id)},O}),r("Shaders/Appearances/AllMaterialAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec3 v_tangentEC;\nvarying vec3 v_binormalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nmat3 tangentToEyeMatrix = czm_tangentToEyeSpaceMatrix(v_normalEC, v_tangentEC, v_binormalEC);\nvec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.tangentToEyeMatrix = tangentToEyeMatrix;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nmaterialInput.st = v_st;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/AllMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nattribute vec3 tangent;\nattribute vec3 binormal;\nattribute vec2 st;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec3 v_tangentEC;\nvarying vec3 v_binormalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\nv_tangentEC = czm_normal * tangent;\nv_binormalEC = czm_normal * binormal;\nv_st = st;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Shaders/Appearances/BasicMaterialAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nvec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/BasicMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Shaders/Appearances/TexturedMaterialAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nvec3 normalEC = normalize(v_normalEC);;\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nmaterialInput.st = v_st;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/TexturedMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nattribute vec2 st;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\nv_st = st;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Scene/CullFace",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={FRONT:t.FRONT,BACK:t.BACK,FRONT_AND_BACK:t.FRONT_AND_BACK};return e(r)}),r("Scene/Appearance",["../Core/clone","../Core/combine","../Core/defaultValue","../Core/defined","../Core/defineProperties","./BlendingState","./CullFace"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){e=r(e,r.EMPTY_OBJECT),this.material=e.material,this.translucent=r(e.translucent,!0),this._vertexShaderSource=e.vertexShaderSource,this._fragmentShaderSource=e.fragmentShaderSource,this._renderState=e.renderState,this._closed=r(e.closed,!1)};return n(s.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}}}),s.prototype.getFragmentShaderSource=function(){var e=[];return this.flat&&e.push("#define FLAT"),this.faceForward&&e.push("#define FACE_FORWARD"),i(this.material)&&e.push(this.material.shaderSource),e.push(this.fragmentShaderSource),e.join("\n")},s.prototype.isTranslucent=function(){return i(this.material)&&this.material.isTranslucent()||!i(this.material)&&this.translucent},s.prototype.getRenderState=function(){var t=this.isTranslucent(),r=e(this.renderState,!1);return t?(r.depthMask=!1,r.blending=o.ALPHA_BLEND):r.depthMask=!0,r},s.getDefaultRenderState=function(e,r,n){var s={depthTest:{enabled:!0}};return e&&(s.depthMask=!1,s.blending=o.ALPHA_BLEND),r&&(s.cull={enabled:!0,face:a.BACK}),i(n)&&(s=t(n,s,!0)),s},s}),r("Renderer/CubeMapFace",["../Core/defaultValue","../Core/defineProperties","../Core/DeveloperError","./PixelDatatype"],function(e,t,r,i){"use strict";var n=function(e,t,r,i,n,o,a,s,l){this._gl=e,this._texture=t,this._textureTarget=r,this._targetFace=i,this._pixelFormat=n,this._pixelDatatype=o,this._size=a,this._preMultiplyAlpha=s,this._flipY=l};return t(n.prototype,{pixelFormat:{get:function(){return this._pixelFormat}},pixelDatatype:{get:function(){return this._pixelDatatype}},_target:{get:function(){return this._targetFace}}}),n.prototype.copyFrom=function(t,r,i){r=e(r,0),i=e(i,0);var n=this._gl,o=this._textureTarget;n.pixelStorei(n.UNPACK_PREMULTIPLY_ALPHA_WEBGL,this._preMultiplyAlpha),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,this._flipY),n.activeTexture(n.TEXTURE0),n.bindTexture(o,this._texture),t.arrayBufferView?n.texSubImage2D(this._targetFace,0,r,i,t.width,t.height,this._pixelFormat,this._pixelDatatype,t.arrayBufferView):n.texSubImage2D(this._targetFace,0,r,i,this._pixelFormat,this._pixelDatatype,t),n.bindTexture(o,null)},n.prototype.copyFromFramebuffer=function(t,r,i,n,o,a){t=e(t,0),r=e(r,0),i=e(i,0),n=e(n,0),o=e(o,this._size),a=e(a,this._size);var s=this._gl,l=this._textureTarget;s.activeTexture(s.TEXTURE0),s.bindTexture(l,this._texture),s.copyTexSubImage2D(this._targetFace,0,t,r,i,n,o,a),s.bindTexture(l,null)},n}),r("Renderer/CubeMap",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Math","../Core/PixelFormat","./ContextLimits","./CubeMapFace","./MipmapHint","./PixelDatatype","./Sampler","./TextureMagnificationFilter","./TextureMinificationFilter","./TextureWrap"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=function(r){function i(e,t){t.arrayBufferView?g.texImage2D(e,0,m,p,p,0,m,f,t.arrayBufferView):g.texImage2D(e,0,m,m,f,t)}r=e(r,e.EMPTY_OBJECT);var n,o,s=r.context,u=r.source;if(t(u)){var d=[u.positiveX,u.negativeX,u.positiveY,u.negativeY,u.positiveZ,u.negativeZ];n=d[0].width,o=d[0].height}else n=r.width,o=r.height;var p=n,m=e(r.pixelFormat,a.RGBA),f=e(r.pixelDatatype,c.UNSIGNED_BYTE),v=r.preMultiplyAlpha||m===a.RGB||m===a.LUMINANCE,_=e(r.flipY,!0),g=s._gl,y=g.TEXTURE_CUBE_MAP,C=g.createTexture();g.activeTexture(g.TEXTURE0),g.bindTexture(y,C),t(u)?(g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,v),g.pixelStorei(g.UNPACK_FLIP_Y_WEBGL,_),i(g.TEXTURE_CUBE_MAP_POSITIVE_X,u.positiveX),i(g.TEXTURE_CUBE_MAP_NEGATIVE_X,u.negativeX),i(g.TEXTURE_CUBE_MAP_POSITIVE_Y,u.positiveY),i(g.TEXTURE_CUBE_MAP_NEGATIVE_Y,u.negativeY),i(g.TEXTURE_CUBE_MAP_POSITIVE_Z,u.positiveZ),i(g.TEXTURE_CUBE_MAP_NEGATIVE_Z,u.negativeZ)):(g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_X,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_NEGATIVE_X,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_Y,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_NEGATIVE_Y,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_Z,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_NEGATIVE_Z,0,m,p,p,0,m,f,null)),g.bindTexture(y,null),this._gl=g,this._textureFilterAnisotropic=s._textureFilterAnisotropic,this._textureTarget=y,this._texture=C,this._pixelFormat=m,this._pixelDatatype=f,this._size=p,this._preMultiplyAlpha=v,this._flipY=_,this._sampler=void 0,this._positiveX=new l(g,C,y,g.TEXTURE_CUBE_MAP_POSITIVE_X,m,f,p,v,_),this._negativeX=new l(g,C,y,g.TEXTURE_CUBE_MAP_NEGATIVE_X,m,f,p,v,_),this._positiveY=new l(g,C,y,g.TEXTURE_CUBE_MAP_POSITIVE_Y,m,f,p,v,_),this._negativeY=new l(g,C,y,g.TEXTURE_CUBE_MAP_NEGATIVE_Y,m,f,p,v,_),this._positiveZ=new l(g,C,y,g.TEXTURE_CUBE_MAP_POSITIVE_Z,m,f,p,v,_),this._negativeZ=new l(g,C,y,g.TEXTURE_CUBE_MAP_NEGATIVE_Z,m,f,p,v,_),this.sampler=new h};return r(f.prototype,{positiveX:{get:function(){return this._positiveX}},negativeX:{get:function(){return this._negativeX}},positiveY:{get:function(){return this._positiveY}},negativeY:{get:function(){return this._negativeY}},positiveZ:{get:function(){return this._positiveZ}},negativeZ:{get:function(){return this._negativeZ}},sampler:{get:function(){return this._sampler},set:function(e){var r=e.minificationFilter,i=e.magnificationFilter,n=r===p.NEAREST_MIPMAP_NEAREST||r===p.NEAREST_MIPMAP_LINEAR||r===p.LINEAR_MIPMAP_NEAREST||r===p.LINEAR_MIPMAP_LINEAR;this._pixelDatatype===c.FLOAT&&(r=n?p.NEAREST_MIPMAP_NEAREST:p.NEAREST,i=d.NEAREST);var o=this._gl,a=this._textureTarget;o.activeTexture(o.TEXTURE0),o.bindTexture(a,this._texture),o.texParameteri(a,o.TEXTURE_MIN_FILTER,r),o.texParameteri(a,o.TEXTURE_MAG_FILTER,i),o.texParameteri(a,o.TEXTURE_WRAP_S,e.wrapS),o.texParameteri(a,o.TEXTURE_WRAP_T,e.wrapT),t(this._textureFilterAnisotropic)&&o.texParameteri(a,this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT,e.maximumAnisotropy),o.bindTexture(a,null),this._sampler=e}},pixelFormat:{get:function(){return this._pixelFormat}},pixelDatatype:{get:function(){return this._pixelDatatype}},width:{get:function(){return this._size}},height:{get:function(){return this._size}},preMultiplyAlpha:{get:function(){return this._preMultiplyAlpha}},flipY:{get:function(){return this._flipY}},_target:{get:function(){return this._textureTarget}}}),f.prototype.generateMipmap=function(t){t=e(t,u.DONT_CARE);var r=this._gl,i=this._textureTarget;r.hint(r.GENERATE_MIPMAP_HINT,t),r.activeTexture(r.TEXTURE0),r.bindTexture(i,this._texture),r.generateMipmap(i),r.bindTexture(i,null)},f.prototype.isDestroyed=function(){return!1},f.prototype.destroy=function(){return this._gl.deleteTexture(this._texture),this._positiveX=i(this._positiveX),this._negativeX=i(this._negativeX),this._positiveY=i(this._positiveY),this._negativeY=i(this._negativeY),this._positiveZ=i(this._positiveZ),this._negativeZ=i(this._negativeZ),i(this)},f}),r("Shaders/Materials/BumpMapMaterial",[],function(){"use strict";return"uniform sampler2D image;\nuniform float strength;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nvec2 centerPixel = fract(repeat * st);\nfloat centerBump = texture2D(image, centerPixel).channel;\nfloat imageWidth = float(imageDimensions.x);\nvec2 rightPixel = fract(repeat * (st + vec2(1.0 / imageWidth, 0.0)));\nfloat rightBump = texture2D(image, rightPixel).channel;\nfloat imageHeight = float(imageDimensions.y);\nvec2 leftPixel = fract(repeat * (st + vec2(0.0, 1.0 / imageHeight)));\nfloat topBump = texture2D(image, leftPixel).channel;\nvec3 normalTangentSpace = normalize(vec3(centerBump - rightBump, centerBump - topBump, clamp(1.0 - strength, 0.1, 1.0)));\nvec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\nmaterial.normal = normalEC;\nmaterial.diffuse = vec3(0.01);\nreturn material;\n}\n"}),r("Shaders/Materials/CheckerboardMaterial",[],function(){"use strict";return"uniform vec4 lightColor;\nuniform vec4 darkColor;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat b = mod(floor(repeat.s * st.s) + floor(repeat.t * st.t), 2.0);\nfloat scaledWidth = fract(repeat.s * st.s);\nscaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\nfloat scaledHeight = fract(repeat.t * st.t);\nscaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\nfloat value = min(scaledWidth, scaledHeight);\nvec4 currentColor = mix(lightColor, darkColor, b);\nvec4 color = czm_antialias(lightColor, darkColor, currentColor, value, 0.03);\nmaterial.diffuse = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/DotMaterial",[],function(){"use strict";return"uniform vec4 lightColor;\nuniform vec4 darkColor;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat b = smoothstep(0.3, 0.32, length(fract(repeat * materialInput.st) - 0.5));\nvec4 color = mix(lightColor, darkColor, b);\nmaterial.diffuse = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"; +}),r("Shaders/Materials/FadeMaterial",[],function(){"use strict";return"uniform vec4 fadeInColor;\nuniform vec4 fadeOutColor;\nuniform float maximumDistance;\nuniform bool repeat;\nuniform vec2 fadeDirection;\nuniform vec2 time;\nfloat getTime(float t, float coord)\n{\nfloat scalar = 1.0 / maximumDistance;\nfloat q = distance(t, coord) * scalar;\nif (repeat)\n{\nfloat r = distance(t, coord + 1.0) * scalar;\nfloat s = distance(t, coord - 1.0) * scalar;\nq = min(min(r, s), q);\n}\nreturn clamp(q, 0.0, 1.0);\n}\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat s = getTime(time.x, st.s) * fadeDirection.s;\nfloat t = getTime(time.y, st.t) * fadeDirection.t;\nfloat u = length(vec2(s, t));\nvec4 color = mix(fadeInColor, fadeOutColor, u);\nmaterial.emission = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/GridMaterial",[],function(){"use strict";return"#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives : enable\n#endif\nuniform vec4 color;\nuniform float cellAlpha;\nuniform vec2 lineCount;\nuniform vec2 lineThickness;\nuniform vec2 lineOffset;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat scaledWidth = fract(lineCount.s * st.s - lineOffset.s);\nscaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\nfloat scaledHeight = fract(lineCount.t * st.t - lineOffset.t);\nscaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\nfloat value;\n#ifdef GL_OES_standard_derivatives\nconst float fuzz = 1.2;\nvec2 thickness = (lineThickness * czm_resolutionScale) - 1.0;\nvec2 dx = abs(dFdx(st));\nvec2 dy = abs(dFdy(st));\nvec2 dF = vec2(max(dx.s, dy.s), max(dx.t, dy.t)) * lineCount;\nvalue = min(\nsmoothstep(dF.s * thickness.s, dF.s * (fuzz + thickness.s), scaledWidth),\nsmoothstep(dF.t * thickness.t, dF.t * (fuzz + thickness.t), scaledHeight));\n#else\nconst float fuzz = 0.05;\nvec2 range = 0.5 - (lineThickness * 0.05);\nvalue = min(\n1.0 - smoothstep(range.s, range.s + fuzz, scaledWidth),\n1.0 - smoothstep(range.t, range.t + fuzz, scaledHeight));\n#endif\nfloat dRim = 1.0 - abs(dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC)));\nfloat sRim = smoothstep(0.8, 1.0, dRim);\nvalue *= (1.0 - sRim);\nvec3 halfColor = color.rgb * 0.5;\nmaterial.diffuse = halfColor;\nmaterial.emission = halfColor;\nmaterial.alpha = color.a * (1.0 - ((1.0 - cellAlpha) * value));\nreturn material;\n}\n"}),r("Shaders/Materials/NormalMapMaterial",[],function(){"use strict";return"uniform sampler2D image;\nuniform float strength;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec4 textureValue = texture2D(image, fract(repeat * materialInput.st));\nvec3 normalTangentSpace = textureValue.channels;\nnormalTangentSpace.xy = normalTangentSpace.xy * 2.0 - 1.0;\nnormalTangentSpace.z = clamp(1.0 - strength, 0.1, 1.0);\nnormalTangentSpace = normalize(normalTangentSpace);\nvec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\nmaterial.normal = normalEC;\nreturn material;\n}\n"}),r("Shaders/Materials/PolylineArrowMaterial",[],function(){"use strict";return"#extension GL_OES_standard_derivatives : enable\nuniform vec4 color;\nvarying float v_width;\nfloat getPointOnLine(vec2 p0, vec2 p1, float x)\n{\nfloat slope = (p0.y - p1.y) / (p0.x - p1.x);\nreturn slope * (x - p0.x) + p0.y;\n}\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat base = 1.0 - abs(fwidth(st.s)) * 10.0;\nvec2 center = vec2(1.0, 0.5);\nfloat ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s);\nfloat ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s);\nfloat halfWidth = 0.15;\nfloat s = step(0.5 - halfWidth, st.t);\ns *= 1.0 - step(0.5 + halfWidth, st.t);\ns *= 1.0 - step(base, st.s);\nfloat t = step(base, materialInput.st.s);\nt *= 1.0 - step(ptOnUpperLine, st.t);\nt *= step(ptOnLowerLine, st.t);\nfloat dist;\nif (st.s < base)\n{\nfloat d1 = abs(st.t - (0.5 - halfWidth));\nfloat d2 = abs(st.t - (0.5 + halfWidth));\ndist = min(d1, d2);\n}\nelse\n{\nfloat d1 = czm_infinity;\nif (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth)\n{\nd1 = abs(st.s - base);\n}\nfloat d2 = abs(st.t - ptOnUpperLine);\nfloat d3 = abs(st.t - ptOnLowerLine);\ndist = min(min(d1, d2), d3);\n}\nvec4 outsideColor = vec4(0.0);\nvec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0));\nvec4 outColor = czm_antialias(outsideColor, color, currentColor, dist);\nmaterial.diffuse = outColor.rgb;\nmaterial.alpha = outColor.a;\nreturn material;\n}\n"}),r("Shaders/Materials/PolylineGlowMaterial",[],function(){"use strict";return"uniform vec4 color;\nuniform float glowPower;\nvarying float v_width;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat glow = glowPower / abs(st.t - 0.5) - (glowPower / 0.5);\nmaterial.emission = max(vec3(glow - 1.0 + color.rgb), color.rgb);\nmaterial.alpha = clamp(0.0, 1.0, glow) * color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/PolylineOutlineMaterial",[],function(){"use strict";return"uniform vec4 color;\nuniform vec4 outlineColor;\nuniform float outlineWidth;\nvarying float v_width;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width;\nfloat b = step(0.5 - halfInteriorWidth, st.t);\nb *= 1.0 - step(0.5 + halfInteriorWidth, st.t);\nfloat d1 = abs(st.t - (0.5 - halfInteriorWidth));\nfloat d2 = abs(st.t - (0.5 + halfInteriorWidth));\nfloat dist = min(d1, d2);\nvec4 currentColor = mix(outlineColor, color, b);\nvec4 outColor = czm_antialias(outlineColor, color, currentColor, dist);\nmaterial.diffuse = outColor.rgb;\nmaterial.alpha = outColor.a;\nreturn material;\n}\n"}),r("Shaders/Materials/RimLightingMaterial",[],function(){"use strict";return"uniform vec4 color;\nuniform vec4 rimColor;\nuniform float width;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat d = 1.0 - dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC));\nfloat s = smoothstep(1.0 - width, 1.0, d);\nmaterial.diffuse = color.rgb;\nmaterial.emission = rimColor.rgb * s;\nmaterial.alpha = mix(color.a, rimColor.a, s);\nreturn material;\n}\n"}),r("Shaders/Materials/StripeMaterial",[],function(){"use strict";return"uniform vec4 evenColor;\nuniform vec4 oddColor;\nuniform float offset;\nuniform float repeat;\nuniform bool horizontal;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat coord = mix(materialInput.st.s, materialInput.st.t, float(horizontal));\nfloat value = fract((coord - offset) * (repeat * 0.5));\nfloat dist = min(value, min(abs(value - 0.5), 1.0 - value));\nvec4 currentColor = mix(evenColor, oddColor, step(0.5, value));\nvec4 color = czm_antialias(evenColor, oddColor, currentColor, dist);\nmaterial.diffuse = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/Water",[],function(){"use strict";return"uniform sampler2D specularMap;\nuniform sampler2D normalMap;\nuniform vec4 baseWaterColor;\nuniform vec4 blendColor;\nuniform float frequency;\nuniform float animationSpeed;\nuniform float amplitude;\nuniform float specularIntensity;\nuniform float fadeFactor;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat time = czm_frameNumber * animationSpeed;\nfloat fade = max(1.0, (length(materialInput.positionToEyeEC) / 10000000000.0) * frequency * fadeFactor);\nfloat specularMapValue = texture2D(specularMap, materialInput.st).r;\nvec4 noise = czm_getWaterNoise(normalMap, materialInput.st * frequency, time, 0.0);\nvec3 normalTangentSpace = noise.xyz * vec3(1.0, 1.0, (1.0 / amplitude));\nnormalTangentSpace.xy /= fade;\nnormalTangentSpace = mix(vec3(0.0, 0.0, 50.0), normalTangentSpace, specularMapValue);\nnormalTangentSpace = normalize(normalTangentSpace);\nfloat tsPerturbationRatio = clamp(dot(normalTangentSpace, vec3(0.0, 0.0, 1.0)), 0.0, 1.0);\nmaterial.alpha = specularMapValue;\nmaterial.diffuse = mix(blendColor.rgb, baseWaterColor.rgb, specularMapValue);\nmaterial.diffuse += (0.1 * tsPerturbationRatio);\nmaterial.normal = normalize(materialInput.tangentToEyeMatrix * normalTangentSpace);\nmaterial.specular = specularIntensity;\nmaterial.shininess = 10.0;\nreturn material;\n}\n"}),r("Scene/Material",["../Core/Cartesian2","../Core/clone","../Core/Color","../Core/combine","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/isArray","../Core/loadImage","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Renderer/CubeMap","../Renderer/Texture","../Shaders/Materials/BumpMapMaterial","../Shaders/Materials/CheckerboardMaterial","../Shaders/Materials/DotMaterial","../Shaders/Materials/FadeMaterial","../Shaders/Materials/GridMaterial","../Shaders/Materials/NormalMapMaterial","../Shaders/Materials/PolylineArrowMaterial","../Shaders/Materials/PolylineGlowMaterial","../Shaders/Materials/PolylineOutlineMaterial","../Shaders/Materials/RimLightingMaterial","../Shaders/Materials/StripeMaterial","../Shaders/Materials/Water","../ThirdParty/when"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e,r){e=o(e,o.EMPTY_OBJECT),r._strict=o(e.strict,!1),r._count=o(e.count,0),r._template=t(o(e.fabric,o.EMPTY_OBJECT)),r._template.uniforms=t(o(r._template.uniforms,o.EMPTY_OBJECT)),r._template.materials=t(o(r._template.materials,o.EMPTY_OBJECT)),r.type=a(r._template.type)?r._template.type:n(),r.shaderSource="",r.materials={},r.uniforms={},r._uniforms={},r._translucentFunctions=[];var s,l=H._materialCache.getMaterial(r.type);if(a(l)){var u=t(l.fabric,!0);r._template=i(r._template,u,!0),s=l.translucent}N(r),a(l)||H._materialCache.addMaterial(r.type,r),L(r),V(r),U(r);var c=0===r._translucentFunctions.length?!0:void 0;if(s=o(s,c),s=o(e.translucent,s),a(s))if("function"==typeof s){var h=function(){return s(r)};r._translucentFunctions.push(h)}else r._translucentFunctions.push(s)}function D(e,t,r,i){if(a(e))for(var n in e)if(e.hasOwnProperty(n)){var o=-1!==t.indexOf(n);(i&&!o||!i&&o)&&r(n,t)}}function R(e,t){for(var r="fabric: property name '"+e+"' is not valid. It should be ",i=0;i0&&(i[s]={type:"ivec3",x:1,y:1},z(e,s))}var l=new RegExp("uniform\\s+"+o+"\\s+"+t+"\\s*;");if(!l.test(e.shaderSource)){var c="uniform "+o+" "+t+";";e.shaderSource=c+e.shaderSource}var h=t+"_"+e._count++;if(1===G(e,t,h)&&r)throw new u("strict: shader source does not use uniform '"+t+"'.");if(e.uniforms[t]=n,"sampler2D"===o)e._uniforms[h]=function(){return e._textures[t]},e._updateFunctions.push(F(t));else if("samplerCube"===o)e._uniforms[h]=function(){return e._textures[t]},e._updateFunctions.push(B(t));else if(-1!==o.indexOf("mat")){var d=new Y[o];e._uniforms[h]=function(){return Y[o].fromColumnMajorArray(e.uniforms[t],d)}}else e._uniforms[h]=function(){return e.uniforms[t]}}}function k(e){var t=e.type;if(!a(t)){var r=typeof e;if("number"===r)t="float";else if("boolean"===r)t="bool";else if("string"===r||e instanceof HTMLCanvasElement)t=/^([rgba]){1,4}$/i.test(e)?"channels":e===H.DefaultCubeMapId?"samplerCube":"sampler2D";else if("object"===r)if(c(e))(4===e.length||9===e.length||16===e.length)&&(t="mat"+Math.sqrt(e.length));else{var i=0;for(var n in e)e.hasOwnProperty(n)&&(i+=1);i>=2&&4>=i?t="vec"+i:6===i&&(t="samplerCube")}}return t}function U(e){var t=e._strict,r=e._template.materials;for(var n in r)if(r.hasOwnProperty(n)){var o=new H({strict:t,fabric:r[n],count:e._count});e._count=o._count,e._uniforms=i(e._uniforms,o._uniforms,!0),e.materials[n]=o,e._translucentFunctions=e._translucentFunctions.concat(o._translucentFunctions);var a="czm_getMaterial",s=a+"_"+e._count++;G(o,a,s),e.shaderSource=o.shaderSource+e.shaderSource;var l=s+"(materialInput)";if(0===G(e,n,l)&&t)throw new u("strict: shader source does not use material '"+n+"'.")}}function G(e,t,r,i){i=o(i,!0);var n=0,a="([\\w])?",s="([\\w"+(i?".":"")+"])?",l=new RegExp(s+t+a,"g");return e.shaderSource=e.shaderSource.replace(l,function(e,t,i){return t||i?e:(n+=1,r)}),n}function W(e,t,r){return G(e,t,t,r)}var H=function(e){this.type=void 0,this.shaderSource=void 0,this.materials=void 0,this.uniforms=void 0,this._uniforms=void 0,this.translucent=void 0,this._strict=void 0,this._template=void 0,this._count=void 0,this._texturePaths={},this._loadedImages=[],this._loadedCubeMaps=[],this._textures={},this._updateFunctions=[],this._defaultTexture=void 0,M(e,this),s(this,{type:{value:this.type,writable:!1}}),a(H._uniformList[this.type])||(H._uniformList[this.type]=Object.keys(this._uniforms))};H._uniformList={},H.fromType=function(e,t){var r=new H({fabric:{type:e}});if(a(t))for(var i in t)t.hasOwnProperty(i)&&(r.uniforms[i]=t[i]);return r},H.prototype.isTranslucent=function(){if(a(this.translucent))return"function"==typeof this.translucent?this.translucent():this.translucent;for(var e=!0,t=this._translucentFunctions,r=t.length,i=0;r>i;++i){var n=t[i];if(e="function"==typeof n?e&&n():e&&n,!e)break}return e},H.prototype.update=function(e){var t,r,i=this._loadedImages,n=i.length;for(t=0;n>t;++t){var o=i[t];r=o.id;var a=o.image,s=new v({context:e,source:a});this._textures[r]=s;var l=r+"Dimensions";if(this.uniforms.hasOwnProperty(l)){var u=this.uniforms[l];u.x=s._width,u.y=s._height}}i.length=0;var c=this._loadedCubeMaps;for(n=c.length,t=0;n>t;++t){var h=c[t];r=h.id;var d=h.images,p=new f({context:e,source:{positiveX:d[0],negativeX:d[1],positiveY:d[2],negativeY:d[3],positiveZ:d[4],negativeZ:d[5]}});this._textures[r]=p}c.length=0;var m=this._updateFunctions;for(n=m.length,t=0;n>t;++t)m[t](this,e);var _=this.materials;for(var g in _)_.hasOwnProperty(g)&&_[g].update(e)},H.prototype.isDestroyed=function(){return!1},H.prototype.destroy=function(){var e=this._textures;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];r!==this._defaultTexture&&r.destroy()}var i=this.materials;for(var n in i)i.hasOwnProperty(n)&&i[n].destroy();return l(this)};var q=["type","materials","uniforms","components","source"],j=["diffuse","specular","shininess","normal","emission","alpha"],Y={mat2:d,mat3:p,mat4:m};return H._materialCache={_materials:{},addMaterial:function(e,t){this._materials[e]=t},getMaterial:function(e){return this._materials[e]}},H.DefaultImageId="czm_defaultImage",H.DefaultCubeMapId="czm_defaultCubeMap",H.ColorType="Color",H._materialCache.addMaterial(H.ColorType,{fabric:{type:H.ColorType,uniforms:{color:new r(1,0,0,.5)},components:{diffuse:"color.rgb",alpha:"color.a"}},translucent:function(e){return e.uniforms.color.alpha<1}}),H.ImageType="Image",H._materialCache.addMaterial(H.ImageType,{fabric:{type:H.ImageType,uniforms:{image:H.DefaultImageId,repeat:new e(1,1)},components:{diffuse:"texture2D(image, fract(repeat * materialInput.st)).rgb",alpha:"texture2D(image, fract(repeat * materialInput.st)).a"}},translucent:!0}),H.DiffuseMapType="DiffuseMap",H._materialCache.addMaterial(H.DiffuseMapType,{fabric:{type:H.DiffuseMapType,uniforms:{image:H.DefaultImageId,channels:"rgb",repeat:new e(1,1)},components:{diffuse:"texture2D(image, fract(repeat * materialInput.st)).channels"}},translucent:!1}),H.AlphaMapType="AlphaMap",H._materialCache.addMaterial(H.AlphaMapType,{fabric:{type:H.AlphaMapType,uniforms:{image:H.DefaultImageId,channel:"a",repeat:new e(1,1)},components:{alpha:"texture2D(image, fract(repeat * materialInput.st)).channel"}},translucent:!0}),H.SpecularMapType="SpecularMap",H._materialCache.addMaterial(H.SpecularMapType,{fabric:{type:H.SpecularMapType,uniforms:{image:H.DefaultImageId,channel:"r",repeat:new e(1,1)},components:{specular:"texture2D(image, fract(repeat * materialInput.st)).channel"}},translucent:!1}),H.EmissionMapType="EmissionMap",H._materialCache.addMaterial(H.EmissionMapType,{fabric:{type:H.EmissionMapType,uniforms:{image:H.DefaultImageId,channels:"rgb",repeat:new e(1,1)},components:{emission:"texture2D(image, fract(repeat * materialInput.st)).channels"}},translucent:!1}),H.BumpMapType="BumpMap",H._materialCache.addMaterial(H.BumpMapType,{fabric:{type:H.BumpMapType,uniforms:{image:H.DefaultImageId,channel:"r",strength:.8,repeat:new e(1,1)},source:_},translucent:!1}),H.NormalMapType="NormalMap",H._materialCache.addMaterial(H.NormalMapType,{fabric:{type:H.NormalMapType,uniforms:{image:H.DefaultImageId,channels:"rgb",strength:.8,repeat:new e(1,1)},source:S},translucent:!1}),H.GridType="Grid",H._materialCache.addMaterial(H.GridType,{fabric:{type:H.GridType,uniforms:{color:new r(0,1,0,1),cellAlpha:.1,lineCount:new e(8,8),lineThickness:new e(1,1),lineOffset:new e(0,0)},source:E},translucent:function(e){var t=e.uniforms;return t.color.alpha<1||t.cellAlpha<1}}),H.StripeType="Stripe",H._materialCache.addMaterial(H.StripeType,{fabric:{type:H.StripeType,uniforms:{horizontal:!0,evenColor:new r(1,1,1,.5),oddColor:new r(0,0,1,.5),offset:0,repeat:5},source:P},translucent:function(e){var t=e.uniforms;return t.evenColor.alpha<1||t.oddColor.alpha<0}}),H.CheckerboardType="Checkerboard",H._materialCache.addMaterial(H.CheckerboardType,{fabric:{type:H.CheckerboardType,uniforms:{lightColor:new r(1,1,1,.5),darkColor:new r(0,0,0,.5),repeat:new e(5,5)},source:g},translucent:function(e){var t=e.uniforms;return t.lightColor.alpha<1||t.darkColor.alpha<0}}),H.DotType="Dot",H._materialCache.addMaterial(H.DotType,{fabric:{type:H.DotType,uniforms:{lightColor:new r(1,1,0,.75),darkColor:new r(0,1,1,.75),repeat:new e(5,5)},source:y},translucent:function(e){var t=e.uniforms;return t.lightColor.alpha<1||t.darkColor.alpha<0}}),H.WaterType="Water",H._materialCache.addMaterial(H.WaterType,{fabric:{type:H.WaterType,uniforms:{baseWaterColor:new r(.2,.3,.6,1),blendColor:new r(0,1,.699,1),specularMap:H.DefaultImageId,normalMap:H.DefaultImageId,frequency:10,animationSpeed:.01,amplitude:1,specularIntensity:.5,fadeFactor:1},source:A},translucent:function(e){var t=e.uniforms;return t.baseWaterColor.alpha<1||t.blendColor.alpha<0}}),H.RimLightingType="RimLighting",H._materialCache.addMaterial(H.RimLightingType,{fabric:{type:H.RimLightingType,uniforms:{color:new r(1,0,0,.7),rimColor:new r(1,1,1,.4),width:.3},source:x},translucent:function(e){var t=e.uniforms;return t.color.alpha<1||t.rimColor.alpha<0}}),H.FadeType="Fade",H._materialCache.addMaterial(H.FadeType,{fabric:{type:H.FadeType,uniforms:{fadeInColor:new r(1,0,0,1),fadeOutColor:new r(0,0,0,0),maximumDistance:.5,repeat:!0,fadeDirection:{x:!0,y:!0},time:new e(.5,.5)},source:C},translucent:function(e){var t=e.uniforms;return t.fadeInColor.alpha<1||t.fadeOutColor.alpha<0}}),H.PolylineArrowType="PolylineArrow",H._materialCache.addMaterial(H.PolylineArrowType,{fabric:{type:H.PolylineArrowType,uniforms:{color:new r(1,1,1,1)},source:w},translucent:!0}),H.PolylineGlowType="PolylineGlow",H._materialCache.addMaterial(H.PolylineGlowType,{fabric:{type:H.PolylineGlowType,uniforms:{color:new r(0,.5,1,1),glowPower:.25},source:T},translucent:!0}),H.PolylineOutlineType="PolylineOutline",H._materialCache.addMaterial(H.PolylineOutlineType,{fabric:{type:H.PolylineOutlineType,uniforms:{color:new r(1,1,1,1),outlineColor:new r(1,0,0,1),outlineWidth:1},source:b},translucent:function(e){var t=e.uniforms;return t.color.alpha<1||t.outlineColor.alpha<1}}),H}),r("Scene/MaterialAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/freezeObject","../Core/VertexFormat","../Shaders/Appearances/AllMaterialAppearanceFS","../Shaders/Appearances/AllMaterialAppearanceVS","../Shaders/Appearances/BasicMaterialAppearanceFS","../Shaders/Appearances/BasicMaterialAppearanceVS","../Shaders/Appearances/TexturedMaterialAppearanceFS","../Shaders/Appearances/TexturedMaterialAppearanceVS","./Appearance","./Material"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";var p=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.translucent,!0),n=e(r.closed,!1),o=e(r.materialSupport,p.MaterialSupport.TEXTURED);this.material=t(r.material)?r.material:d.fromType(d.ColorType),this.translucent=i,this._vertexShaderSource=e(r.vertexShaderSource,o.vertexShaderSource),this._fragmentShaderSource=e(r.fragmentShaderSource,o.fragmentShaderSource),this._renderState=h.getDefaultRenderState(i,n,r.renderState),this._closed=n,this._materialSupport=o,this._vertexFormat=o.vertexFormat,this._flat=e(r.flat,!1),this._faceForward=e(r.faceForward,!n)};return r(p.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},materialSupport:{get:function(){return this._materialSupport}},vertexFormat:{get:function(){return this._vertexFormat}},flat:{get:function(){return this._flat}},faceForward:{get:function(){return this._faceForward}}}),p.prototype.getFragmentShaderSource=h.prototype.getFragmentShaderSource,p.prototype.isTranslucent=h.prototype.isTranslucent,p.prototype.getRenderState=h.prototype.getRenderState,p.MaterialSupport={BASIC:i({vertexFormat:n.POSITION_AND_NORMAL,vertexShaderSource:l,fragmentShaderSource:s}),TEXTURED:i({vertexFormat:n.POSITION_NORMAL_AND_ST,vertexShaderSource:c,fragmentShaderSource:u}),ALL:i({vertexFormat:n.ALL,vertexShaderSource:a,fragmentShaderSource:o})},p}),r("Shaders/Appearances/PerInstanceColorAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec4 v_color;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nvec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getDefaultMaterial(materialInput);\nmaterial.diffuse = v_color.rgb;\nmaterial.alpha = v_color.a;\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n}\n"}),r("Shaders/Appearances/PerInstanceColorAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nattribute vec4 color;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec4 v_color;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\nv_color = color;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Shaders/Appearances/PerInstanceFlatColorAppearanceFS",[],function(){"use strict";return"varying vec4 v_color;\nvoid main()\n{\ngl_FragColor = v_color;\n}\n"}),r("Shaders/Appearances/PerInstanceFlatColorAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec4 color;\nvarying vec4 v_color;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_color = color;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Scene/PerInstanceColorAppearance",["../Core/defaultValue","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/PerInstanceColorAppearanceFS","../Shaders/Appearances/PerInstanceColorAppearanceVS","../Shaders/Appearances/PerInstanceFlatColorAppearanceFS","../Shaders/Appearances/PerInstanceFlatColorAppearanceVS","./Appearance"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){t=e(t,e.EMPTY_OBJECT);var r=e(t.translucent,!0),u=e(t.closed,!1),c=e(t.flat,!1),h=c?a:n,d=c?o:i,p=c?l.FLAT_VERTEX_FORMAT:l.VERTEX_FORMAT;this.material=void 0,this.translucent=r,this._vertexShaderSource=e(t.vertexShaderSource,h),this._fragmentShaderSource=e(t.fragmentShaderSource,d),this._renderState=s.getDefaultRenderState(r,u,t.renderState),this._closed=u,this._vertexFormat=p,this._flat=c,this._faceForward=e(t.faceForward,!u)};return t(l.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return this._vertexFormat}},flat:{get:function(){return this._flat}},faceForward:{get:function(){return this._faceForward}}}),l.VERTEX_FORMAT=r.POSITION_AND_NORMAL,l.FLAT_VERTEX_FORMAT=r.POSITION_ONLY,l.prototype.getFragmentShaderSource=s.prototype.getFragmentShaderSource,l.prototype.isTranslucent=s.prototype.isTranslucent,l.prototype.getRenderState=s.prototype.getRenderState,l}),r("Scene/PrimitivePipeline",["../Core/BoundingSphere","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/Ellipsoid","../Core/FeatureDetection","../Core/GeographicProjection","../Core/Geometry","../Core/GeometryAttribute","../Core/GeometryAttributes","../Core/GeometryPipeline","../Core/IndexDatatype","../Core/Matrix4","../Core/WebMercatorProjection"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(e,t,r){var i,n=!r,o=e.length;if(!n&&o>1){var a=e[0].modelMatrix;for(i=1;o>i;++i)if(!m.equals(a,e[i].modelMatrix)){n=!0;break}}if(n)for(i=0;o>i;++i)d.transformToWorldCoordinates(e[i]);else m.multiplyTransformation(t,e[0].modelMatrix,t)}function _(e,i){var n=e.attributes,o=n.position,a=4*(o.values.length/o.componentsPerAttribute);n.pickColor=new c({componentDatatype:r.UNSIGNED_BYTE,componentsPerAttribute:4,normalize:!0,values:new Uint8Array(a)});for(var s=t.floatToByte(i.red),l=t.floatToByte(i.green),u=t.floatToByte(i.blue),h=t.floatToByte(i.alpha),d=n.pickColor.values,p=0;a>p;p+=4)d[p]=s,d[p+1]=l,d[p+2]=u,d[p+3]=h}function g(e,t){for(var r=e.length,i=0;r>i;++i){var o=e[i],a=t[i];n(o.geometry)?_(o.geometry,a):(_(o.westHemisphereGeometry,a),_(o.eastHemisphereGeometry,a))}}function y(e){var t,r=e.length,i=[],o=e[0].attributes;for(t in o)if(o.hasOwnProperty(t)){for(var a=o[t],s=!0,l=1;r>l;++l){var u=e[l].attributes[t];if(!n(u)||a.componentDatatype!==u.componentDatatype||a.componentsPerAttribute!==u.componentsPerAttribute||a.normalize!==u.normalize){s=!1;break}}s&&i.push(t)}return i}function C(e,t,i){for(var n=u.computeNumberOfVertices(t),o=i.length,a=0;o>a;++a){for(var s=i[a],l=e[s],h=l.componentDatatype,d=l.value,p=d.length,m=r.createTypedArray(h,n*p),f=0;n>f;++f)m.set(d,f*p);t.attributes[s]=new c({componentDatatype:h,componentsPerAttribute:p,normalize:l.normalize,values:m})}}function E(e,t){for(var r=e.length,i=0;r>i;++i){var o=e[i],a=o.attributes;n(o.geometry)?C(a,o.geometry,t):(C(a,o.westHemisphereGeometry,t),C(a,o.eastHemisphereGeometry,t))}}function S(t){var i,o,a=t.instances,s=t.pickIds,l=t.projection,u=t.elementIndexUintSupported,c=t.scene3DOnly,h=t.allowPicking,p=t.vertexCacheOptimize,m=t.compressVertices,f=t.modelMatrix,_=a.length;a[0].geometry.primitiveType;if(v(a,f,c),!c)for(i=0;_>i;++i)d.splitLongitude(a[i]);h&&g(a,s);var C=y(a);if(E(a,C),p)for(i=0;_>i;++i){var S=a[i];n(S.geometry)?(d.reorderForPostVertexCache(S.geometry),d.reorderForPreVertexCache(S.geometry)):(d.reorderForPostVertexCache(S.westHemisphereGeometry),d.reorderForPreVertexCache(S.westHemisphereGeometry),d.reorderForPostVertexCache(S.eastHemisphereGeometry),d.reorderForPreVertexCache(S.eastHemisphereGeometry))}var w=d.combineInstances(a);for(_=w.length,i=0;_>i;++i){o=w[i];var T,b=o.attributes;if(c)for(T in b)b.hasOwnProperty(T)&&b[T].componentDatatype===r.DOUBLE&&d.encodeAttribute(o,T,T+"3DHigh",T+"3DLow");else for(T in b)if(b.hasOwnProperty(T)&&b[T].componentDatatype===r.DOUBLE){var x=T+"3D",P=T+"2D";d.projectTo2D(o,T,x,P,l),n(o.boundingSphere)&&"position"===T&&(o.boundingSphereCV=e.fromVertices(o.attributes.position2D.values)),d.encodeAttribute(o,x,x+"High",x+"Low"),d.encodeAttribute(o,P,P+"High",P+"Low")}m&&d.compressVertices(o)}if(!u){var A=[];for(_=w.length,i=0;_>i;++i)o=w[i],A=A.concat(d.fitToUnsignedShortIndices(o));w=A}return w}function w(e,t,i){for(var n=[],o=e.attributes,a=i.length,s=0;a>s;++s){var l=i[s],u=o[l],c=u.componentDatatype;c===r.DOUBLE&&(c=r.FLOAT);var h=r.createTypedArray(c,u.values);n.push({index:t[l],componentDatatype:c,componentsPerAttribute:u.componentsPerAttribute,normalize:u.normalize,values:h}),delete o[l]}return n}function T(e,t,r,o,a,s,l,c,h){var d=u.computeNumberOfVertices(t);n(l[e])||(l[e]={boundingSphere:t.boundingSphere,boundingSphereCV:t.boundingSphereCV});for(var p=o.length,m=0;p>m;++m)for(var f=o[m],v=a[f],_=d;_>0;){for(var g,y=i(h[f],0),C=s[y],E=C.length,S=0;E>S&&(g=C[S],g.index!==v);++S);n(l[e][f])||(l[e][f]={dirty:!1,valid:!0,value:r[f].value,indices:[]});var w,T=g.values.length/g.componentsPerAttribute,b=i(c[f],0);T>b+_?(w=_,l[e][f].indices.push({attribute:g,offset:b,count:w}),c[f]=b+_):(w=T-b,l[e][f].indices.push({attribute:g,offset:b,count:w}),c[f]=0,h[f]=y+1),_-=w}}function b(e,t,r,i,o){var a,s,l,u=[],c=e.length,h={},d={};for(a=0;c>a;++a)s=e[a],l=s.attributes,n(s.geometry)&&T(a,s.geometry,l,o,i,r,u,h,d); +for(a=0;c>a;++a)s=e[a],l=s.attributes,n(s.westHemisphereGeometry)&&T(a,s.westHemisphereGeometry,l,o,i,r,u,h,d);for(a=0;c>a;++a)s=e[a],l=s.attributes,n(s.eastHemisphereGeometry)&&T(a,s.eastHemisphereGeometry,l,o,i,r,u,h,d);for(c=t.length,a=0;c>a;++a){s=t[a],l=s.attributes;var p={};u.push(p);for(var m=o.length,f=0;m>f;++f){var v=o[f];p[v]={dirty:!1,valid:!1,value:l[v].value,indices:[]}}}return u}function x(e,t){var r=e.attributes;for(var i in r)if(r.hasOwnProperty(i)){var o=r[i];n(o)&&n(o.values)&&t.push(o.values.buffer)}n(e.indices)&&t.push(e.indices.buffer)}function P(e,t){for(var r=e.length,i=0;r>i;++i)x(e[i],t)}function A(e,t){for(var r=e.length,i=0;r>i;++i)for(var n=e[i],o=n.length,a=0;o>a;++a)t.push(n[a].values.buffer)}function I(t){for(var r=1,i=t.length,o=0;i>o;o++){var a=t[o];if(++r,n(a)){var s=a.attributes;r+=6+2*e.packedLength+(n(a.indices)?a.indices.length:0);for(var l in s)if(s.hasOwnProperty(l)&&n(s[l])){var u=s[l];r+=5+u.values.length}}}return r}function M(e,t){for(var r=e.length,i=new Uint32Array(e.length),n=0;r>n;++n)i[n]=e[n].toRgba();return t.push(i.buffer),i}function D(e){for(var r=e.length,i=new Array(r),n=0;r>n;n++)i[n]=t.fromRgba(e[n]);return i}function R(e){for(var t=e.length,r=1+17*t,i=0;t>i;i++){var o=e[i].attributes;for(var a in o)if(o.hasOwnProperty(a)&&n(o[a])){var s=o[a];r+=5+s.value.length}}return r}function O(e,t){var r=new Float64Array(R(e)),i={},o=[],a=e.length,s=0;r[s++]=a;for(var l=0;a>l;l++){var u=e[l];m.pack(u.modelMatrix,r,s),s+=m.packedLength;var c=u.attributes,h=[];for(var d in c)c.hasOwnProperty(d)&&n(c[d])&&(h.push(d),n(i[d])||(i[d]=o.length,o.push(d)));r[s++]=h.length;for(var p=0;pc;c++){for(var h=i[t[a++]],d=t[a++],p=t[a++],f=0!==t[a++],v=t[a++],_=r.createTypedArray(d,v),g=0;v>g;g++)_[g]=t[a++];l[h]={componentDatatype:d,componentsPerAttribute:p,normalize:f,value:_}}n[o++]={attributes:l,modelMatrix:s}}return n}function L(t){for(var r=t.length,i=1+r,o=0;r>o;o++){var a=t[o];i+=2,i+=n(a.boundingSphere)?e.packedLength:0,i+=n(a.boundingSphereCV)?e.packedLength:0;for(var s in a)if(a.hasOwnProperty(s)&&n(a[s])&&"boundingSphere"!==s&&"boundingSphereCV"!==s){var l=a[s];i+=4+3*l.indices.length+l.value.length}}return i}function F(t,r){var i=new Float64Array(L(t)),o=[],a=[],s={},l=t.length,u=0;i[u++]=l;for(var c=0;l>c;c++){var h=t[c],d=h.boundingSphere,p=n(d);i[u++]=p?1:0,p&&(e.pack(d,i,u),u+=e.packedLength),d=h.boundingSphereCV,p=n(d),i[u++]=p?1:0,p&&(e.pack(d,i,u),u+=e.packedLength);var m=[];for(var f in h)h.hasOwnProperty(f)&&n(h[f])&&"boundingSphere"!==f&&"boundingSphereCV"!==f&&(m.push(f),n(s[f])||(s[f]=o.length,o.push(f)));i[u++]=m.length;for(var v=0;vE;E++){var S=y[E];i[u++]=S.count,i[u++]=S.offset;var w=a.indexOf(S.attribute);-1===w&&(w=a.length,a.push(S.attribute)),i[u++]=w}i[u++]=g.value.length,i.set(g.value,u),u+=g.value.length}}return r.push(i.buffer),{stringTable:o,packedData:i,attributeTable:a}}function B(t,i){for(var n=t.stringTable,o=t.attributeTable,a=t.packedData,s=new Array(a[0]),l=0,u=1,c=a.length;c>u;){var h={},d=1===a[u++];d&&(h.boundingSphere=e.unpack(a,u),u+=e.packedLength),d=1===a[u++],d&&(h.boundingSphereCV=e.unpack(a,u),u+=e.packedLength);for(var p=a[u++],m=0;p>m;m++){for(var f=n[a[u++]],v=1===a[u++],_=a[u++],g=_>0?new Array(_):void 0,y=0;_>y;y++){var C={};C.count=a[u++],C.offset=a[u++],C.attribute=o[a[u++]],g[y]=C}for(var E=a[u++],S=v?r.createTypedArray(g[0].attribute.componentDatatype,E):new Array(E),w=0;E>w;w++)S[w]=a[u++];h[f]={dirty:!1,valid:v,indices:g,value:S}}s[l++]=h}return s}if(!s.supportsTypedArrays())return{};var V={};return V.combineGeometry=function(e){var t,r,i,o,a,s=e.instances,l=e.invalidInstances;if(s.length>0){t=S(e),r=d.createAttributeLocations(t[0]),o=y(s),i=[],a=t.length;for(var u=0;a>u;++u){var c=t[u];i.push(w(c,r,o))}}o=n(o)?o:y(l);var h=b(s,l,i,r,o);return{geometries:t,modelMatrix:e.modelMatrix,attributeLocations:r,vaAttributes:i,vaAttributeLocations:h,validInstancesIndices:e.validInstancesIndices,invalidInstancesIndices:e.invalidInstancesIndices}},V.packCreateGeometryResults=function(t,r){var i=new Float64Array(I(t)),o=[],a={},s=t.length,l=0;i[l++]=s;for(var u=0;s>u;u++){var c=t[u],h=n(c);if(i[l++]=h?1:0,h){i[l++]=c.primitiveType,i[l++]=c.geometryType;var d=n(c.boundingSphere)?1:0;i[l++]=d,d&&e.pack(c.boundingSphere,i,l),l+=e.packedLength;var p=n(c.boundingSphereCV)?1:0;i[l++]=p,p&&e.pack(c.boundingSphereCV,i,l),l+=e.packedLength;var m=c.attributes,f=[];for(var v in m)m.hasOwnProperty(v)&&n(m[v])&&(f.push(v),n(a[v])||(a[v]=o.length,o.push(v)));i[l++]=f.length;for(var _=0;_0&&(i.set(c.indices,l),l+=C)}}return r.push(i.buffer),{stringTable:o,packedData:i}},V.unpackCreateGeometryResults=function(t){for(var i,n=t.stringTable,o=t.packedData,a=new Array(o[0]),s=0,l=1;li;i++){var b=n[o[l++]],x=o[l++];S=o[l++];var P=0!==o[l++];C=o[l++],E=r.createTypedArray(x,C);for(var A=0;C>A;A++)E[A]=o[l++];w[b]=new c({componentDatatype:x,componentsPerAttribute:S,normalize:P,values:E})}var I;if(C=o[l++],C>0){var M=E.length/S;for(I=p.createTypedArray(M,C),i=0;C>i;i++)I[i]=o[l++]}a[s++]=new u({primitiveType:v,geometryType:_,boundingSphere:m,indices:I,attributes:w})}else a[s++]=void 0}return a},V.packCombineGeometryParameters=function(e,t){for(var r=e.createGeometryResults,i=r.length,n=0;i>n;n++)t.push(r[n].packedData.buffer);var o;return e.allowPicking&&(o=M(e.pickIds,t)),{createGeometryResults:e.createGeometryResults,packedInstances:O(e.instances,t),packedPickIds:o,ellipsoid:e.ellipsoid,isGeographic:e.projection instanceof l,elementIndexUintSupported:e.elementIndexUintSupported,scene3DOnly:e.scene3DOnly,allowPicking:e.allowPicking,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:e.modelMatrix}},V.unpackCombineGeometryParameters=function(e){for(var t=N(e.packedInstances),r=e.allowPicking,i=r?D(e.packedPickIds):void 0,o=e.createGeometryResults,s=o.length,u=0,c=[],h=[],d=[],p=[],v=[],_=0;s>_;_++)for(var g=V.unpackCreateGeometryResults(o[_]),y=g.length,C=0;y>C;C++){var E=g[C],S=t[u];n(E)?(S.geometry=E,c.push(S),d.push(u),r&&v.push(i[u])):(h.push(S),p.push(u)),++u}var w=a.clone(e.ellipsoid),T=e.isGeographic?new l(w):new f(w);return{instances:c,invalidInstances:h,validInstancesIndices:d,invalidInstancesIndices:p,pickIds:v,ellipsoid:w,projection:T,elementIndexUintSupported:e.elementIndexUintSupported,scene3DOnly:e.scene3DOnly,allowPicking:e.allowPicking,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:m.clone(e.modelMatrix)}},V.packCombineGeometryResults=function(e,t){return n(e.geometries)&&(P(e.geometries,t),A(e.vaAttributes,t)),{geometries:e.geometries,attributeLocations:e.attributeLocations,vaAttributes:e.vaAttributes,packedVaAttributeLocations:F(e.vaAttributeLocations,t),modelMatrix:e.modelMatrix,validInstancesIndices:e.validInstancesIndices,invalidInstancesIndices:e.invalidInstancesIndices}},V.unpackCombineGeometryResults=function(e){return{geometries:e.geometries,attributeLocations:e.attributeLocations,vaAttributes:e.vaAttributes,perInstanceAttributeLocations:B(e.packedVaAttributeLocations,e.vaAttributes),modelMatrix:e.modelMatrix}},V}),r("Scene/PrimitiveState",["../Core/freezeObject"],function(e){"use strict";var t={READY:0,CREATING:1,CREATED:2,COMBINING:3,COMBINED:4,COMPLETE:5,FAILED:6};return e(t)}),r("Scene/Primitive",["../Core/BoundingSphere","../Core/Cartesian3","../Core/clone","../Core/combine","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/FeatureDetection","../Core/Geometry","../Core/GeometryAttribute","../Core/GeometryAttributes","../Core/GeometryInstance","../Core/GeometryInstanceAttribute","../Core/isArray","../Core/Matrix4","../Core/subdivideArray","../Core/TaskProcessor","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../ThirdParty/when","./CullFace","./Pass","./PrimitivePipeline","./PrimitiveState","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R){"use strict";function O(e){return new d({componentDatatype:e.componentDatatype,componentsPerAttribute:e.componentsPerAttribute,normalize:e.normalize,values:new e.values.constructor(e.values)})}function N(t){var r=t.attributes,i=new p;for(var n in r)r.hasOwnProperty(n)&&a(r[n])&&(i[n]=O(r[n]));var o;if(a(t.indices)){var s=t.indices;o=new s.constructor(s)}return new h({attributes:i,indices:o,primitiveType:t.primitiveType,boundingSphere:e.clone(t.boundingSphere)})}function L(e){return new f({componentDatatype:e.componentDatatype,componentsPerAttribute:e.componentsPerAttribute,normalize:e.normalize,value:new e.value.constructor(e.value)})}function F(e,t){var r=e.attributes,i={};for(var n in r)r.hasOwnProperty(n)&&(i[n]=L(r[n]));return new m({geometry:t,modelMatrix:_.clone(e.modelMatrix),attributes:i,pickPrimitive:e.pickPrimitive,id:e.id})}function B(e,t){if(!e.compressVertices)return t;var r=-1!==t.search(/attribute\s+vec3\s+normal;/g),i=-1!==t.search(/attribute\s+vec2\s+st;/g);if(!r&&!i)return t;var n=-1!==t.search(/attribute\s+vec3\s+tangent;/g),o=-1!==t.search(/attribute\s+vec3\s+binormal;/g),a=i&&r?2:1;a+=n||o?1:0;var s=a>1?"vec"+a:"float",l="compressedAttributes",u="attribute "+s+" "+l+";",c="",h="";if(i){c+="vec2 st;\n";var d=a>1?l+".x":l;h+=" st = czm_decompressTextureCoordinates("+d+");\n"}r&&n&&o?(c+="vec3 normal;\nvec3 tangent;\nvec3 binormal;\n",h+=" czm_octDecode("+l+"."+(i?"yz":"xy")+", normal, tangent, binormal);\n"):(r&&(c+="vec3 normal;\n",h+=" normal = czm_octDecode("+l+(a>1?"."+(i?"y":"x"):"")+");\n"),n&&(c+="vec3 tangent;\n",h+=" tangent = czm_octDecode("+l+"."+(i&&r?"z":"y")+");\n"),o&&(c+="vec3 binormal;\n",h+=" binormal = czm_octDecode("+l+"."+(i&&r?"z":"y")+");\n"));var p=t;p=p.replace(/attribute\s+vec3\s+normal;/g,""),p=p.replace(/attribute\s+vec2\s+st;/g,""),p=p.replace(/attribute\s+vec3\s+tangent;/g,""),p=p.replace(/attribute\s+vec3\s+binormal;/g,""),p=b.replaceMain(p,"czm_non_compressed_main");var m="void main() \n{ \n"+h+" czm_non_compressed_main(); \n}";return[u,c,p,m].join("\n")}function V(e,t){e.vertexAttributes}function z(e,t,r){for(var i=[],n=r.length,s=0;n>s;++s){var l={primitive:o(r[s].pickPrimitive,t)};a(r[s].id)&&(l.id=r[s].id);var u=e.createPickId(l);t._pickIds.push(u),i.push(u.color)}return i}function k(e,t){return function(){return e[t]}}function U(e,t){var r,i,n,s,l=e._instanceIds;if(e._state===D.READY){r=v(e.geometryInstances)?e.geometryInstances:[e.geometryInstances];var u=e._numberOfInstances=r.length,c=[],h=[];for(n=0;u>n;++n)i=r[n].geometry,l.push(r[n].id),h.push({moduleName:i._workerName,geometry:i});if(!a(ee))for(ee=new Array(te),n=0;te>n;n++)ee[n]=new y("createGeometry",Number.POSITIVE_INFINITY);var d;for(h=g(h,te),n=0;ns;++s)d=m[s],i=d.geometry,a(i.constructor.pack)&&(d.offset=p,p+=o(i.constructor.packedLength,i.packedLength));var C;if(p>0){var E=new Float64Array(p);for(C=[E.buffer],s=0;f>s;++s)d=m[s],i=d.geometry,a(i.constructor.pack)&&(i.constructor.pack(i,E,d.offset),d.geometry=E)}c.push(ee[n].scheduleTask({subTasks:h[n]},C))}e._state=D.CREATING,P.all(c,function(t){e._createGeometryResults=t,e._state=D.CREATED}).otherwise(function(r){J(e,t,D.FAILED,r)})}else if(e._state===D.CREATED){var S=[];r=v(e.geometryInstances)?e.geometryInstances:[e.geometryInstances];var w=e.allowPicking,T=t.scene3DOnly,b=t.mapProjection,x=re.scheduleTask(M.packCombineGeometryParameters({createGeometryResults:e._createGeometryResults,instances:r,pickIds:w?z(t.context,e,r):void 0,ellipsoid:b.ellipsoid,projection:b,elementIndexUintSupported:t.context.elementIndexUint,scene3DOnly:T,allowPicking:w,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:e.modelMatrix},S),S);e._createGeometryResults=void 0,e._state=D.COMBINING,P(x,function(r){var i=M.unpackCombineGeometryResults(r);e._geometries=i.geometries,e._attributeLocations=i.attributeLocations,e._vaAttributes=i.vaAttributes,e._perInstanceAttributeLocations=i.perInstanceAttributeLocations,e.modelMatrix=_.clone(i.modelMatrix,e.modelMatrix),e._validModelMatrix=!_.equals(e.modelMatrix,_.IDENTITY);for(var n=r.validInstancesIndices,o=r.invalidInstancesIndices,s=e._instanceIds,l=new Array(s.length),u=n.length,c=0;u>c;++c)l[c]=s[n[c]];for(var h=o.length,d=0;h>d;++d)l[u+d]=s[o[d]];e._instanceIds=l,a(e._geometries)?e._state=D.COMBINED:J(e,t,D.FAILED,void 0)}).otherwise(function(r){J(e,t,D.FAILED,r)})}}function G(e,t){var r,i,n=v(e.geometryInstances)?e.geometryInstances:[e.geometryInstances],o=e._numberOfInstances=n.length,s=new Array(o),l=new Array(o),u=[],c=e._instanceIds,h=0;for(i=0;o>i;i++){r=n[i];var d,p=r.geometry;d=a(p.attributes)&&a(p.primitiveType)?N(p):p.constructor.createGeometry(p),a(d)?(s[h]=d,l[h++]=F(r,d),c.push(r.id)):u.push(r)}s.length=h,l.length=h;var m=e.allowPicking,f=t.scene3DOnly,g=t.mapProjection,y=M.combineGeometry({instances:l,invalidInstances:u,pickIds:m?z(t.context,e,l):void 0,ellipsoid:g.ellipsoid,projection:g,elementIndexUintSupported:t.context.elementIndexUint,scene3DOnly:f,allowPicking:m,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:e.modelMatrix});for(e._geometries=y.geometries,e._attributeLocations=y.attributeLocations,e._vaAttributes=y.vaAttributes,e._perInstanceAttributeLocations=y.vaAttributeLocations,e.modelMatrix=_.clone(y.modelMatrix,e.modelMatrix),e._validModelMatrix=!_.equals(e.modelMatrix,_.IDENTITY),i=0;ih;++h){for(var d=n[h],p=o[h],m=p.length,f=0;m>f;++f){var v=p[f];v.vertexBuffer=C.createVertexBuffer({context:l,typedArray:v.values,usage:E.DYNAMIC_DRAW}),delete v.values}if(u.push(x.fromGeometry({context:l,geometry:d,attributeLocations:i,bufferUsage:E.STATIC_DRAW,interleave:t._interleave,vertexArrayAttributes:p})),a(t._createBoundingVolumeFunction))t._createBoundingVolumeFunction(r,d);else if(t._boundingSpheres.push(e.clone(d.boundingSphere)),t._boundingSphereWC.push(new e),!s){var _=d.boundingSphereCV.center,g=_.x,y=_.y,S=_.z;_.x=S,_.y=g,_.z=y,t._boundingSphereCV.push(e.clone(d.boundingSphereCV)),t._boundingSphere2D.push(new e),t._boundingSphereMorph.push(new e)}}t._va=u,t._primitiveType=n[0].primitiveType,t.releaseGeometryInstances&&(t.geometryInstances=void 0),t._geometries=void 0,J(t,r,D.COMPLETE,void 0)}function H(e,t,i,n){var o,a=i.getRenderState();n?(o=r(a,!1),o.cull={enabled:!0,face:A.BACK},e._frontFaceRS=w.fromCache(o),o.cull.face=A.FRONT,e._backFaceRS=w.fromCache(o)):(e._frontFaceRS=w.fromCache(a),e._backFaceRS=e._frontFaceRS),e.allowPicking?n?(o=r(a,!1),o.cull={enabled:!1},e._pickRS=w.fromCache(o)):e._pickRS=e._frontFaceRS:(o=r(a,!1),o.colorMask={red:!1,green:!1,blue:!1,alpha:!1},n?(o.cull={enabled:!1},e._pickRS=w.fromCache(o)):e._pickRS=w.fromCache(o))}function q(e,t,r){var i=t.context,n=Q._modifyShaderPosition(e,r.vertexShaderSource,t.scene3DOnly);n=Q._appendShowToShader(e,n),n=B(e,n);var o=r.getFragmentShaderSource(),a=e._attributeLocations;if(e._sp=T.replaceCache({context:i,shaderProgram:e._sp,vertexShaderSource:n,fragmentShaderSource:o,attributeLocations:a}),V(e._sp,a),e.allowPicking){var s=new b({sources:[o],pickColorQualifier:"varying"});e._pickSP=T.replaceCache({context:i,shaderProgram:e._pickSP,vertexShaderSource:b.createPickVertexShaderSource(n),fragmentShaderSource:s,attributeLocations:a})}else e._pickSP=T.fromCache({context:i,vertexShaderSource:n,fragmentShaderSource:o,attributeLocations:a});V(e._pickSP,a)}function j(e,t,r,n,o,s,l){var c=a(r)?r._uniforms:void 0,h={},d=t.uniforms;if(a(d))for(var p in d)if(d.hasOwnProperty(p)){if(a(c)&&a(c[p]))throw new u("Appearance and material have a uniform with the same name: "+p);h[p]=k(d,p)}var m=i(h,c);a(e.rtcCenter)&&(m.u_modifiedModelView=function(){return e._modifiedModelView});var f=n?I.TRANSLUCENT:I.OPAQUE;s.length=e._va.length*(o?2:1),l.length=e._va.length;for(var v=s.length,_=0,g=0,y=0;v>y;++y){var C;o&&(C=s[y],a(C)||(C=s[y]=new S({owner:e,primitiveType:e._primitiveType})),C.vertexArray=e._va[g],C.renderState=e._backFaceRS,C.shaderProgram=e._sp,C.uniformMap=m,C.pass=f,++y),C=s[y],a(C)||(C=s[y]=new S({owner:e,primitiveType:e._primitiveType})),C.vertexArray=e._va[g],C.renderState=e._frontFaceRS,C.shaderProgram=e._sp,C.uniformMap=m,C.pass=f;var E=l[_];a(E)||(E=l[_]=new S({owner:e,primitiveType:e._primitiveType})),E.vertexArray=e._va[g],E.renderState=e._pickRS,E.shaderProgram=e._pickSP,E.uniformMap=m,E.pass=f,++_,++g}}function Y(e){if(0!==e._dirtyAttributes.length){for(var t=e._dirtyAttributes,r=t.length,i=0;r>i;++i){for(var o=t[i],a=o.value,s=o.indices,l=s.length,u=0;l>u;++u){for(var c=s[u],h=c.offset,d=c.count,p=c.attribute,m=p.componentDatatype,f=p.componentsPerAttribute,v=n.createTypedArray(m,d*f),_=0;d>_;++_)v.set(a,_*f);var g=h*f*n.getSizeInBytes(m);p.vertexBuffer.copyFromArrayView(v,g)}o.dirty=!1}t.length=0}}function X(t,r,i,n,o,s,l,u){if(!_.equals(o,t._modelMatrix)){_.clone(o,t._modelMatrix);for(var c=t._boundingSpheres.length,h=0;c>h;++h){var d=t._boundingSpheres[h];a(d)&&(t._boundingSphereWC[h]=e.transform(d,o,t._boundingSphereWC[h]),r.scene3DOnly||(t._boundingSphere2D[h]=e.clone(t._boundingSphereCV[h],t._boundingSphere2D[h]),t._boundingSphere2D[h].center.x=0,t._boundingSphereMorph[h]=e.union(t._boundingSphereWC[h],t._boundingSphereCV[h])))}}if(a(t.rtcCenter)){var p=r.camera.viewMatrix;_.multiply(p,t._modelMatrix,t._modifiedModelView),_.multiplyByPoint(t._modifiedModelView,t.rtcCenter,ie),_.setTranslation(t._modifiedModelView,ie,t._modifiedModelView)}var m;r.mode===R.SCENE3D?m=t._boundingSphereWC:r.mode===R.COLUMBUS_VIEW?m=t._boundingSphereCV:r.mode===R.SCENE2D&&a(t._boundingSphere2D)?m=t._boundingSphere2D:a(t._boundingSphereMorph)&&(m=t._boundingSphereMorph);var f=r.commandList,v=r.passes;if(v.render)for(var g=i.length,y=0;g>y;++y){var C=u?Math.floor(y/2):y;i[y].modelMatrix=o,i[y].boundingVolume=m[C],i[y].cull=s,i[y].debugShowBoundingVolume=l,f.push(i[y])}if(v.pick)for(var E=n.length,S=0;E>S;++S)n[S].modelMatrix=o,n[S].boundingVolume=m[S],n[S].cull=s,f.push(n[S])}function Z(e,t){var r=t[e];return function(){return a(r)&&a(r.value)?t[e].value:r}}function K(e,t,r){return function(i){var n=t[e];n.value=i,!n.dirty&&n.valid&&(r.push(n),n.dirty=!0)}}function J(e,t,r,i){e._error=i,e._state=r,t.afterRender.push(function(){e._ready=e._state===D.COMPLETE||e._state===D.FAILED,a(i)?e._readyPromise.reject(i):e._readyPromise.resolve(e)})}var Q=function(e){e=o(e,o.EMPTY_OBJECT),this.geometryInstances=e.geometryInstances,this.appearance=e.appearance,this._appearance=void 0,this._material=void 0,this.modelMatrix=_.clone(o(e.modelMatrix,_.IDENTITY)),this._modelMatrix=new _,this.show=o(e.show,!0),this._vertexCacheOptimize=o(e.vertexCacheOptimize,!1),this._interleave=o(e.interleave,!1),this._releaseGeometryInstances=o(e.releaseGeometryInstances,!0),this._allowPicking=o(e.allowPicking,!0),this._asynchronous=o(e.asynchronous,!0),this._compressVertices=o(e.compressVertices,!0),this.cull=o(e.cull,!0),this.debugShowBoundingVolume=o(e.debugShowBoundingVolume,!1),this.rtcCenter=e.rtcCenter,this._modifiedModelView=new _,this._translucent=void 0,this._state=D.READY,this._geometries=[],this._vaAttributes=void 0,this._error=void 0,this._numberOfInstances=0,this._validModelMatrix=!1,this._boundingSpheres=[],this._boundingSphereWC=[],this._boundingSphereCV=[],this._boundingSphere2D=[],this._boundingSphereMorph=[],this._perInstanceAttributeLocations=void 0,this._perInstanceAttributeCache=[],this._instanceIds=[],this._lastPerInstanceAttributeIndex=0,this._dirtyAttributes=[],this._va=[],this._attributeLocations=void 0,this._primitiveType=void 0,this._frontFaceRS=void 0,this._backFaceRS=void 0,this._sp=void 0,this._pickRS=void 0,this._pickSP=void 0,this._pickIds=[],this._colorCommands=[],this._pickCommands=[],this._createBoundingVolumeFunction=e._createBoundingVolumeFunction,this._createRenderStatesFunction=e._createRenderStatesFunction,this._createShaderProgramFunction=e._createShaderProgramFunction,this._createCommandsFunction=e._createCommandsFunction,this._updateAndQueueCommandsFunction=e._updateAndQueueCommandsFunction,this._createGeometryResults=void 0,this._ready=!1,this._readyPromise=P.defer()};s(Q.prototype,{vertexCacheOptimize:{get:function(){return this._vertexCacheOptimize}},interleave:{get:function(){return this._interleave}},releaseGeometryInstances:{get:function(){return this._releaseGeometryInstances}},allowPicking:{get:function(){return this._allowPicking}},asynchronous:{get:function(){return this._asynchronous}},compressVertices:{get:function(){return this._compressVertices}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}}});var $=/attribute\s+vec(?:3|4)\s+(.*)3DHigh;/g;Q._modifyShaderPosition=function(e,t,r){for(var i,n="",o="",s="";null!==(i=$.exec(t));){var l=i[1],u="vec4 czm_compute"+l[0].toUpperCase()+l.substr(1)+"()";"vec4 czm_computePosition()"!==u&&(n+=u+";\n"),a(e.rtcCenter)?(t=t.replace(/attribute\s+vec(?:3|4)\s+position3DHigh;/g,""),t=t.replace(/attribute\s+vec(?:3|4)\s+position3DLow;/g,""),n+="uniform mat4 u_modifiedModelView;\n",o+="attribute vec4 position;\n",s+=u+"\n{\n return u_modifiedModelView * position;\n}\n\n",t=t.replace(/czm_modelViewRelativeToEye\s+\*\s+/g,""),t=t.replace(/czm_modelViewProjectionRelativeToEye/g,"czm_projection")):r?s+=u+"\n{\n return czm_translateRelativeToEye("+l+"3DHigh, "+l+"3DLow);\n}\n\n":(o+="attribute vec3 "+l+"2DHigh;\nattribute vec3 "+l+"2DLow;\n",s+=u+"\n{\n vec4 p;\n if (czm_morphTime == 1.0)\n {\n p = czm_translateRelativeToEye("+l+"3DHigh, "+l+"3DLow);\n }\n else if (czm_morphTime == 0.0)\n {\n p = czm_translateRelativeToEye("+l+"2DHigh.zxy, "+l+"2DLow.zxy);\n }\n else\n {\n p = czm_columbusViewMorph(\n czm_translateRelativeToEye("+l+"2DHigh.zxy, "+l+"2DLow.zxy),\n czm_translateRelativeToEye("+l+"3DHigh, "+l+"3DLow),\n czm_morphTime);\n }\n return p;\n}\n\n")}return[n,o,t,s].join("\n")},Q._appendShowToShader=function(e,t){if(!a(e._attributeLocations.show))return t;var r=b.replaceMain(t,"czm_non_show_main"),i="attribute float show;\nvoid main() \n{ \n czm_non_show_main(); \n gl_Position *= show; \n}";return r+"\n"+i};var ee,te=Math.max(c.hardwareConcurrency-1,1),re=new y("combineGeometry",Number.POSITIVE_INFINITY),ie=new t;return Q.prototype.update=function(e){if(!(!a(this.geometryInstances)&&0===this._va.length||a(this.geometryInstances)&&v(this.geometryInstances)&&0===this.geometryInstances.length||!a(this.appearance)||e.mode!==R.SCENE3D&&e.scene3DOnly||!e.passes.render&&!e.passes.pick)){if(a(this._error))throw this._error;if(a(this.rtcCenter)&&!e.scene3DOnly)throw new u("RTC rendering is only available for 3D only scenes.");if(this._state!==D.FAILED&&(this._state!==D.COMPLETE&&this._state!==D.COMBINED&&(this.asynchronous?U(this,e):G(this,e)),this._state===D.COMBINED&&W(this,e),this.show&&this._state===D.COMPLETE)){var t=this.appearance,r=t.material,i=!1,n=!1;this._appearance!==t?(this._appearance=t,this._material=r,i=!0,n=!0):this._material!==r&&(this._material=r,n=!0);var s=this._appearance.isTranslucent();this._translucent!==s&&(this._translucent=s,i=!0);var l=e.context;a(this._material)&&this._material.update(l);var c=t.closed&&s;if(i){var h=o(this._createRenderStatesFunction,H);h(this,l,t,c)}if(n){var d=o(this._createShaderProgramFunction,q);d(this,e,t)}if(i||n){var p=o(this._createCommandsFunction,j);p(this,t,r,s,c,this._colorCommands,this._pickCommands)}Y(this);var m=o(this._updateAndQueueCommandsFunction,X);m(this,e,this._colorCommands,this._pickCommands,this.modelMatrix,this.cull,this.debugShowBoundingVolume,c)}}},Q.prototype.getGeometryInstanceAttributes=function(e){for(var t=-1,r=this._lastPerInstanceAttributeIndex,i=this._instanceIds,n=i.length,o=0;n>o;++o){var l=(r+o)%n;if(e===i[l]){t=l;break}}if(-1===t)return void 0;var u=this._perInstanceAttributeCache[t];if(a(u))return u;var c=this._perInstanceAttributeLocations[t];u={};var h={},d=!1;for(var p in c)c.hasOwnProperty(p)&&(d=!0,h[p]={get:Z(p,c)},"boundingSphere"!==p&&"boundingSphereCV"!==p&&(h[p].set=K(p,c,this._dirtyAttributes)));return d&&s(u,h),this._lastPerInstanceAttributeIndex=t,this._perInstanceAttributeCache[t]=u,u},Q.prototype.isDestroyed=function(){return!1},Q.prototype.destroy=function(){var e,t;this._sp=this._sp&&this._sp.destroy(),this._pickSP=this._pickSP&&this._pickSP.destroy();var r=this._va;for(e=r.length,t=0;e>t;++t)r[t].destroy();this._va=void 0;var i=this._pickIds;for(e=i.length,t=0;e>t;++t)i[t].destroy();return this._pickIds=void 0,this._instanceIds=void 0,this._perInstanceAttributeCache=void 0,this._perInstanceAttributeLocations=void 0,this._attributeLocations=void 0,this._dirtyAttributes=void 0,l(this)},Q}),r("DataSources/ColorMaterialProperty",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./ConstantProperty","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this.color=e};return r(l.prototype,{isConstant:{get:function(){return s.isConstant(this._color)}},definitionChanged:{get:function(){return this._definitionChanged}},color:a("color")}),l.prototype.getType=function(e){return"Color"},l.prototype.getValue=function(r,i){return t(i)||(i={}),i.color=s.getValueOrClonedDefault(this._color,r,e.WHITE,i.color),i},l.prototype.equals=function(e){return this===e||e instanceof l&&s.equals(this._color,e._color)},l}),r("DataSources/dynamicGeometryGetBoundingSphere",["../Core/BoundingSphere","../Core/defined","../Core/DeveloperError","./BoundingSphereState"],function(e,t,r,i){"use strict";var n=function(r,n,o,a){var s;return t(n)&&n.show&&n.ready&&(s=n.getGeometryInstanceAttributes(r),t(s)&&t(s.boundingSphere))?(e.transform(s.boundingSphere,n.modelMatrix,a),i.DONE):t(o)&&o.show&&o.ready&&(s=o.getGeometryInstanceAttributes(r),t(s)&&t(s.boundingSphere))?(e.transform(s.boundingSphere,o.modelMatrix,a),i.DONE):t(n)&&!n.ready||t(o)&&!o.ready?i.PENDING:i.FAILED};return n}),r("DataSources/MaterialProperty",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Scene/Material"],function(e,t,r,i,n){"use strict";var o=function(){i.throwInstantiationError()};return r(o.prototype,{isConstant:{get:i.throwInstantiationError},definitionChanged:{get:i.throwInstantiationError}}),o.prototype.getType=i.throwInstantiationError,o.prototype.getValue=i.throwInstantiationError,o.prototype.equals=i.throwInstantiationError,o.getValue=function(r,i,o){var a;return t(i)&&(a=i.getType(r),t(a))?(t(o)&&o.type===a||(o=n.fromType(a)),i.getValue(r,o.uniforms),o):(t(o)&&o.type===n.ColorType||(o=n.fromType(n.ColorType)),e.clone(e.WHITE,o.uniforms.color),o)},o}),r("DataSources/BoxGeometryUpdater",["../Core/BoxGeometry","../Core/BoxOutlineGeometry","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(r.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(r.BLACK),x=new r,P=function(e){this.id=e,this.vertexFormat=void 0,this.dimensions=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"box",e.box,void 0)};a(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),a(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(t){var n,a,s=this._entity,l=s.isAvailable(t),u=new d(l&&s.isShowing&&this._showProperty.getValue(t)&&this._fillProperty.getValue(t));if(this._materialProperty instanceof v){var p=r.WHITE;o(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(p=this._materialProperty.color.getValue(t)),a=i.fromColor(p),n={show:u,color:a}}else n={show:u};return new c({id:s,geometry:e.fromDimensions(this._options),modelMatrix:s._getModelMatrix(h.MINIMUM_VALUE),attributes:n})},A.prototype.createOutlineGeometryInstance=function(e){var n=this._entity,o=n.isAvailable(e),a=C.getValueOrDefault(this._outlineColorProperty,e,r.BLACK);return new c({id:n,geometry:t.fromDimensions(this._options),modelMatrix:n._getModelMatrix(h.MINIMUM_VALUE),attributes:{show:new d(o&&n.isShowing&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)),color:i.fromColor(a)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),s(this)},A.prototype._onEntityPropertyChanged=function(e,t,r,i){if("availability"===t||"position"===t||"orientation"===t||"box"===t){var a=this._entity.box;if(!o(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=o(s)&&s.isConstant?s.getValue(h.MINIMUM_VALUE):!0,u=a.outline,c=o(u); +if(c&&u.isConstant&&(c=u.getValue(h.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.dimensions,f=e.position,_=a.show;if(!o(d)||!o(f)||o(_)&&_.isConstant&&!_.getValue(h.MINIMUM_VALUE))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var g=n(a.material,E),y=g instanceof v;this._materialProperty=g,this._fillProperty=n(s,w),this._showProperty=n(_,S),this._showOutlineProperty=n(a.outline,T),this._outlineColorProperty=c?n(a.outlineColor,b):void 0;var x=a.outlineWidth;if(this._fillEnabled=l,this._outlineEnabled=c,f.isConstant&&C.isConstant(e.orientation)&&d.isConstant&&C.isConstant(x)){var P=this._options;P.vertexFormat=y?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,P.dimensions=d.getValue(h.MINIMUM_VALUE,P.dimensions),this._outlineWidth=o(x)?x.getValue(h.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(n){var a=this._primitives;a.removeAndDestroy(this._primitive),a.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var s=this._geometryUpdater,l=s._entity,u=l.box;if(l.isShowing&&l.isAvailable(n)&&C.getValueOrDefault(u.show,n,!0)){var h=this._options,d=l._getModelMatrix(n),v=C.getValueOrUndefined(u.dimensions,n,h.dimensions);if(o(d)&&o(v)){if(h.dimensions=v,C.getValueOrDefault(u.fill,n,!0)){var _=y.getValue(n,s.fillMaterialProperty,this._material);this._material=_;var g=new p({material:_,translucent:_.isTranslucent(),closed:!0});h.vertexFormat=g.vertexFormat,this._primitive=a.add(new f({geometryInstances:new c({id:l,geometry:e.fromDimensions(h),modelMatrix:d}),appearance:g,asynchronous:!1}))}if(C.getValueOrDefault(u.outline,n,!1)){h.vertexFormat=m.VERTEX_FORMAT;var E=C.getValueOrClonedDefault(u.outlineColor,n,r.BLACK,x),S=C.getValueOrDefault(u.outlineWidth,n,1),w=1!==E.alpha;this._outlinePrimitive=a.add(new f({geometryInstances:new c({id:l,geometry:t.fromDimensions(h),modelMatrix:d,attributes:{color:i.fromColor(E)}}),appearance:new m({flat:!0,translucent:w,renderState:{lineWidth:s._scene.clampLineWidth(S)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),s(this)},A}),r("DataSources/ImageMaterialProperty",["../Core/Cartesian2","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=new e(1,1),l=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._image=void 0,this._imageSubscription=void 0,this._repeat=void 0,this._repeatSubscription=void 0,this.image=e.image,this.repeat=e.repeat};return i(l.prototype,{isConstant:{get:function(){return a.isConstant(this._image)&&a.isConstant(this._repeat)}},definitionChanged:{get:function(){return this._definitionChanged}},image:o("image"),repeat:o("repeat")}),l.prototype.getType=function(e){return"Image"},l.prototype.getValue=function(e,t){return r(t)||(t={}),t.image=a.getValueOrUndefined(this._image,e),t.repeat=a.getValueOrClonedDefault(this._repeat,e,s,t.repeat),t},l.prototype.equals=function(e){return this===e||e instanceof l&&a.equals(this._image,e._image)&&a.equals(this._repeat,e._repeat)},l}),r("DataSources/createMaterialPropertyDescriptor",["../Core/Color","../Core/DeveloperError","./ColorMaterialProperty","./createPropertyDescriptor","./ImageMaterialProperty"],function(e,t,r,i,n){"use strict";function o(t){if(t instanceof e)return new r(t);if("string"==typeof t||t instanceof HTMLCanvasElement){var i=new n;return i.image=t,i}}function a(e,t){return i(e,t,o)}return a}),r("DataSources/BoxGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._dimensions=void 0,this._dimensionsSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),dimensions:a("dimensions"),material:o("material"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth")}),s.prototype.clone=function(e){return t(e)?(e.dimensions=this.dimensions,e.show=this.show,e.material=this.material,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e):new s(this)},s.prototype.merge=function(t){this.dimensions=e(this.dimensions,t.dimensions),this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth)},s}),r("DataSources/CallbackProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event"],function(e,t,r,i){"use strict";var n=function(e,t){this._callback=void 0,this._isConstant=void 0,this._definitionChanged=new i,this.setCallback(e,t)};return t(n.prototype,{isConstant:{get:function(){return this._isConstant}},definitionChanged:{get:function(){return this._definitionChanged}}}),n.prototype.getValue=function(e,t){return this._callback(e,t)},n.prototype.setCallback=function(e,t){var r=this._callback!==e||this._isConstant!==t;this._callback=e,this._isConstant=t,r&&this._definitionChanged.raiseEvent(this)},n.prototype.equals=function(e){return this===e||e instanceof n&&this._callback===e._callback&&this._isConstant===e._isConstant},n}),r("DataSources/CheckerboardMaterialProperty",["../Core/Cartesian2","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=t.WHITE,u=t.BLACK,c=new e(2,2),h=function(e){e=r(e,r.EMPTY_OBJECT),this._definitionChanged=new o,this._evenColor=void 0,this._evenColorSubscription=void 0,this._oddColor=void 0,this._oddColorSubscription=void 0,this._repeat=void 0,this._repeatSubscription=void 0,this.evenColor=e.evenColor,this.oddColor=e.oddColor,this.repeat=e.repeat};return n(h.prototype,{isConstant:{get:function(){return s.isConstant(this._evenColor)&&s.isConstant(this._oddColor)&&s.isConstant(this._repeat)}},definitionChanged:{get:function(){return this._definitionChanged}},evenColor:a("evenColor"),oddColor:a("oddColor"),repeat:a("repeat")}),h.prototype.getType=function(e){return"Checkerboard"},h.prototype.getValue=function(e,t){return i(t)||(t={}),t.lightColor=s.getValueOrClonedDefault(this._evenColor,e,l,t.lightColor),t.darkColor=s.getValueOrClonedDefault(this._oddColor,e,u,t.darkColor),t.repeat=s.getValueOrDefault(this._repeat,e,c),t},h.prototype.equals=function(e){return this===e||e instanceof h&&s.equals(this._evenColor,e._evenColor)&&s.equals(this._oddColor,e._oddColor)&&s.equals(this._repeat,e._repeat)},h}),r("DataSources/PositionProperty",["../Core/Cartesian3","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix3","../Core/ReferenceFrame","../Core/Transforms"],function(e,t,r,i,n,o,a){"use strict";var s=function(){i.throwInstantiationError()};r(s.prototype,{isConstant:{get:i.throwInstantiationError},definitionChanged:{get:i.throwInstantiationError},referenceFrame:{get:i.throwInstantiationError}}),s.prototype.getValue=i.throwInstantiationError,s.prototype.getValueInReferenceFrame=i.throwInstantiationError,s.prototype.equals=i.throwInstantiationError;var l=new n;return s.convertToReferenceFrame=function(r,i,s,u,c){if(!t(i))return i;if(t(c)||(c=new e),s===u)return e.clone(i,c);var h=a.computeIcrfToFixedMatrix(r,l);return t(h)||(h=a.computeTemeToPseudoFixedMatrix(r,l)),s===o.INERTIAL?n.multiplyByVector(h,i,c):s===o.FIXED?n.multiplyByVector(n.transpose(h,l),i,c):void 0},s}),r("DataSources/ConstantPositionProperty",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","./PositionProperty"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(r,i){this._definitionChanged=new o,this._value=e.clone(r),this._referenceFrame=t(i,a.FIXED)};return i(l.prototype,{isConstant:{get:function(){return!r(this._value)||this._referenceFrame===a.FIXED}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return this._referenceFrame}}}),l.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,a.FIXED,t)},l.prototype.setValue=function(t,i){var n=!1;e.equals(this._value,t)||(n=!0,this._value=e.clone(t)),r(i)&&this._referenceFrame!==i&&(n=!0,this._referenceFrame=i),n&&this._definitionChanged.raiseEvent(this)},l.prototype.getValueInReferenceFrame=function(e,t,r){return s.convertToReferenceFrame(e,this._value,this._referenceFrame,t,r)},l.prototype.equals=function(t){return this===t||t instanceof l&&e.equals(this._value,t._value)&&this._referenceFrame===t._referenceFrame},l}),r("DataSources/CorridorGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._cornerType=void 0,this._cornerTypeSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),width:a("width"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),cornerType:a("cornerType")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.width=this.width,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.cornerType=this.cornerType,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.width=e(this.width,t.width),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.cornerType=e(this.cornerType,t.cornerType)},s}),r("DataSources/createRawPropertyDescriptor",["./createPropertyDescriptor"],function(e){"use strict";function t(e){return e}function r(r,i){return e(r,i,t)}return r}),r("DataSources/CylinderGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._length=void 0,this._lengthSubscription=void 0,this._topRadius=void 0,this._topRadiusSubscription=void 0,this._bottomRadius=void 0,this._bottomRadiusSubscription=void 0,this._numberOfVerticalLines=void 0,this._numberOfVerticalLinesSubscription=void 0,this._slices=void 0,this._slicesSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},length:a("length"),topRadius:a("topRadius"),bottomRadius:a("bottomRadius"),numberOfVerticalLines:a("numberOfVerticalLines"),slices:a("slices"),show:a("show"),material:o("material"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth")}),s.prototype.clone=function(e){return t(e)?(e.bottomRadius=this.bottomRadius,e.length=this.length,e.topRadius=this.topRadius,e.show=this.show,e.material=this.material,e.numberOfVerticalLines=this.numberOfVerticalLines,e.slices=this.slices,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e):new s(this)},s.prototype.merge=function(t){this.bottomRadius=e(this.bottomRadius,t.bottomRadius),this.length=e(this.length,t.length),this.topRadius=e(this.topRadius,t.topRadius),this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.numberOfVerticalLines=e(this.numberOfVerticalLines,t.numberOfVerticalLines),this.slices=e(this.slices,t.slices),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth)},s}),r("DataSources/EllipseGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._semiMajorAxis=void 0,this._semiMajorAxisSubscription=void 0,this._semiMinorAxis=void 0,this._semiMinorAxisSubscription=void 0,this._rotation=void 0,this._rotationSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._stRotation=void 0,this._stRotationSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._numberOfVerticalLines=void 0,this._numberOfVerticalLinesSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},semiMajorAxis:a("semiMajorAxis"),semiMinorAxis:a("semiMinorAxis"),rotation:a("rotation"),show:a("show"),material:o("material"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),stRotation:a("stRotation"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),numberOfVerticalLines:a("numberOfVerticalLines")}),s.prototype.clone=function(e){return t(e)?(e.rotation=this.rotation,e.semiMajorAxis=this.semiMajorAxis,e.semiMinorAxis=this.semiMinorAxis,e.show=this.show,e.material=this.material,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.stRotation=this.stRotation,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.numberOfVerticalLines=this.numberOfVerticalLines,e):new s(this)},s.prototype.merge=function(t){this.rotation=e(this.rotation,t.rotation),this.semiMajorAxis=e(this.semiMajorAxis,t.semiMajorAxis),this.semiMinorAxis=e(this.semiMinorAxis,t.semiMinorAxis),this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.stRotation=e(this.stRotation,t.stRotation),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.numberOfVerticalLines=e(this.numberOfVerticalLines,t.numberOfVerticalLines)},s}),r("DataSources/EllipsoidGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._radii=void 0,this._radiiSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._stackPartitions=void 0,this._stackPartitionsSubscription=void 0,this._slicePartitions=void 0,this._slicePartitionsSubscription=void 0,this._subdivisions=void 0,this._subdivisionsSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),radii:a("radii"),material:o("material"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),stackPartitions:a("stackPartitions"),slicePartitions:a("slicePartitions"),subdivisions:a("subdivisions")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.radii=this.radii,e.material=this.material,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.stackPartitions=this.stackPartitions,e.slicePartitions=this.slicePartitions,e.subdivisions=this.subdivisions,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.radii=e(this.radii,t.radii),this.material=e(this.material,t.material),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.stackPartitions=e(this.stackPartitions,t.stackPartitions),this.slicePartitions=e(this.slicePartitions,t.slicePartitions),this.subdivisions=e(this.subdivisions,t.subdivisions)},s}),r("DataSources/LabelGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._text=void 0,this._textSubscription=void 0,this._font=void 0,this._fontSubscription=void 0,this._style=void 0,this._styleSubscription=void 0,this._fillColor=void 0,this._fillColorSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._horizontalOrigin=void 0,this._horizontalOriginSubscription=void 0,this._verticalOrigin=void 0,this._verticalOriginSubscription=void 0,this._eyeOffset=void 0,this._eyeOffsetSubscription=void 0,this._pixelOffset=void 0,this._pixelOffsetSubscription=void 0,this._scale=void 0,this._scaleSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._translucencyByDistance=void 0,this._translucencyByDistanceSubscription=void 0,this._pixelOffsetScaleByDistance=void 0,this._pixelOffsetScaleByDistanceSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},text:o("text"),font:o("font"),style:o("style"),fillColor:o("fillColor"),outlineColor:o("outlineColor"),outlineWidth:o("outlineWidth"),horizontalOrigin:o("horizontalOrigin"),verticalOrigin:o("verticalOrigin"),eyeOffset:o("eyeOffset"),pixelOffset:o("pixelOffset"),scale:o("scale"),show:o("show"),translucencyByDistance:o("translucencyByDistance"),pixelOffsetScaleByDistance:o("pixelOffsetScaleByDistance")}),a.prototype.clone=function(e){return t(e)?(e.text=this.text,e.font=this.font,e.show=this.show,e.style=this.style,e.fillColor=this.fillColor,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.scale=this.scale,e.horizontalOrigin=this.horizontalOrigin,e.verticalOrigin=this.verticalOrigin,e.eyeOffset=this.eyeOffset,e.pixelOffset=this.pixelOffset,e.translucencyByDistance=this.translucencyByDistance,e.pixelOffsetScaleByDistance=this.pixelOffsetScaleByDistance,e):new a(this)},a.prototype.merge=function(t){this.text=e(this.text,t.text),this.font=e(this.font,t.font),this.show=e(this.show,t.show),this.style=e(this.style,t.style),this.fillColor=e(this.fillColor,t.fillColor),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.scale=e(this.scale,t.scale),this.horizontalOrigin=e(this.horizontalOrigin,t.horizontalOrigin),this.verticalOrigin=e(this.verticalOrigin,t.verticalOrigin),this.eyeOffset=e(this.eyeOffset,t.eyeOffset),this.pixelOffset=e(this.pixelOffset,t.pixelOffset),this.translucencyByDistance=e(this._translucencyByDistance,t.translucencyByDistance),this.pixelOffsetScaleByDistance=e(this._pixelOffsetScaleByDistance,t.pixelOffsetScaleByDistance)},a}),r("DataSources/ModelGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._show=void 0,this._showSubscription=void 0,this._scale=void 0,this._scaleSubscription=void 0,this._minimumPixelSize=void 0,this._minimumPixelSizeSubscription=void 0,this._maximumScale=void 0,this._maximumScaleSubscription=void 0,this._uri=void 0,this._uriSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:o("show"),scale:o("scale"),minimumPixelSize:o("minimumPixelSize"),maximumScale:o("maximumScale"),uri:o("uri")}),a.prototype.clone=function(e){return t(e)?(e.show=this.show,e.scale=this.scale,e.minimumPixelSize=this.minimumPixelSize,e.maximumScale=this.maximumScale,e.uri=this.uri,e):new a(this)},a.prototype.merge=function(t){this.show=e(this.show,t.show),this.scale=e(this.scale,t.scale),this.minimumPixelSize=e(this.minimumPixelSize,t.minimumPixelSize),this.maximumScale=e(this.maximumScale,t.maximumScale),this.uri=e(this.uri,t.uri)},a}),r("DataSources/PathGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._material=void 0,this._materialSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._resolution=void 0,this._resolutionSubscription=void 0,this._leadTime=void 0,this._leadTimeSubscription=void 0,this._trailTime=void 0,this._trailTimeSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),width:a("width"),resolution:a("resolution"),leadTime:a("leadTime"),trailTime:a("trailTime")}),s.prototype.clone=function(e){return t(e)?(e.material=this.material,e.width=this.width,e.resolution=this.resolution,e.show=this.show,e.leadTime=this.leadTime,e.trailTime=this.trailTime,e):new s(this)},s.prototype.merge=function(t){this.material=e(this.material,t.material),this.width=e(this.width,t.width),this.resolution=e(this.resolution,t.resolution),this.show=e(this.show,t.show),this.leadTime=e(this.leadTime,t.leadTime),this.trailTime=e(this.trailTime,t.trailTime)},s}),r("DataSources/PointGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._color=void 0,this._colorSubscription=void 0,this._pixelSize=void 0,this._pixelSizeSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._scaleByDistance=void 0,this._scaleByDistanceSubscription=void 0,this._translucencyByDistance=void 0,this._translucencyByDistanceSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},color:o("color"),pixelSize:o("pixelSize"),outlineColor:o("outlineColor"),outlineWidth:o("outlineWidth"),show:o("show"),scaleByDistance:o("scaleByDistance"),translucencyByDistance:o("translucencyByDistance")}),a.prototype.clone=function(e){return t(e)?(e.color=this.color,e.pixelSize=this.pixelSize,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.show=this.show,e.scaleByDistance=this.scaleByDistance,e.translucencyByDistance=this._translucencyByDistance,e):new a(this)},a.prototype.merge=function(t){this.color=e(this.color,t.color),this.pixelSize=e(this.pixelSize,t.pixelSize),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.show=e(this.show,t.show),this.scaleByDistance=e(this.scaleByDistance,t.scaleByDistance),this.translucencyByDistance=e(this._translucencyByDistance,t.translucencyByDistance)},a}),r("DataSources/PolygonGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._hierarchy=void 0,this._hierarchySubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._stRotation=void 0,this._stRotationSubscription=void 0,this._perPositionHeight=void 0,this._perPositionHeightSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this._fill=void 0,this._fillSubscription=void 0,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),hierarchy:a("hierarchy"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),stRotation:a("stRotation"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),perPositionHeight:a("perPositionHeight")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.hierarchy=this.hierarchy,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.stRotation=this.stRotation,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.perPositionHeight=this.perPositionHeight,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.hierarchy=e(this.hierarchy,t.hierarchy),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.stRotation=e(this.stRotation,t.stRotation),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.perPositionHeight=e(this.perPositionHeight,t.perPositionHeight)},s}),r("DataSources/PolylineGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._followSurface=void 0,this._followSurfaceSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._widthSubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),width:a("width"),followSurface:a("followSurface"),granularity:a("granularity")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions,e.width=this.width,e.followSurface=this.followSurface,e.granularity=this.granularity,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.width=e(this.width,t.width),this.followSurface=e(this.followSurface,t.followSurface),this.granularity=e(this.granularity,t.granularity)},s}),r("DataSources/PolylineVolumeGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._shape=void 0,this._shapeSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._cornerType=void 0,this._cornerTypeSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),shape:a("shape"),granularity:a("granularity"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),cornerType:a("cornerType")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions, +e.shape=this.shape,e.granularity=this.granularity,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.cornerType=this.cornerType,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.shape=e(this.shape,t.shape),this.granularity=e(this.granularity,t.granularity),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.cornerType=e(this.cornerType,t.cornerType)},s}),r("DataSources/RectangleGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._coordinates=void 0,this._coordinatesSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._stRotation=void 0,this._stRotationSubscription=void 0,this._rotation=void 0,this._rotationSubscription=void 0,this._closeTop=void 0,this._closeTopSubscription=void 0,this._closeBottom=void 0,this._closeBottomSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),coordinates:a("coordinates"),material:o("material"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),stRotation:a("stRotation"),rotation:a("rotation"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),closeTop:a("closeTop"),closeBottom:a("closeBottom")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.coordinates=this.coordinates,e.material=this.material,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.stRotation=this.stRotation,e.rotation=this.rotation,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.closeTop=this.closeTop,e.closeBottom=this.closeBottom,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.coordinates=e(this.coordinates,t.coordinates),this.material=e(this.material,t.material),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.stRotation=e(this.stRotation,t.stRotation),this.rotation=e(this.rotation,t.rotation),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.closeTop=e(this.closeTop,t.closeTop),this.closeBottom=e(this.closeBottom,t.closeBottom)},s}),r("DataSources/WallGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._minimumHeights=void 0,this._minimumHeightsSubscription=void 0,this._maximumHeights=void 0,this._maximumHeightsSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),minimumHeights:a("minimumHeights"),maximumHeights:a("maximumHeights"),granularity:a("granularity"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions,e.minimumHeights=this.minimumHeights,e.maximumHeights=this.maximumHeights,e.granularity=this.granularity,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.minimumHeights=e(this.minimumHeights,t.minimumHeights),this.maximumHeights=e(this.maximumHeights,t.maximumHeights),this.granularity=e(this.granularity,t.granularity),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth)},s}),r("DataSources/Entity",["../Core/Cartesian3","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/Matrix3","../Core/Matrix4","../Core/Quaternion","../Core/Transforms","./BillboardGraphics","./BoxGraphics","./ConstantPositionProperty","./CorridorGraphics","./createPropertyDescriptor","./createRawPropertyDescriptor","./CylinderGraphics","./EllipseGraphics","./EllipsoidGraphics","./LabelGraphics","./ModelGraphics","./PathGraphics","./PointGraphics","./PolygonGraphics","./PolylineGraphics","./PolylineVolumeGraphics","./Property","./RectangleGraphics","./WallGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e){return new p(e)}function D(e){return f(e,void 0,M)}function R(e,t){return f(e,void 0,function(e){return e instanceof t?e:new t(e)})}function O(e,t,r){for(var i=t.length,n=0;i>n;n++){var o=t[n],a=o._show,s=!r&&a,l=r&&a;s!==l&&O(o,o._children,r)}e._definitionChanged.raiseEvent(e,"isShowing",r,!r)}var N=function(e){e=r(e,r.EMPTY_OBJECT);var n=e.id;i(n)||(n=t()),this._availability=void 0,this._id=n,this._definitionChanged=new a,this._name=e.name,this._show=r(e.show,!0),this._parent=void 0,this._propertyNames=["billboard","box","corridor","cylinder","description","ellipse","ellipsoid","label","model","orientation","path","point","polygon","polyline","polylineVolume","position","rectangle","viewFrom","wall"],this._billboard=void 0,this._billboardSubscription=void 0,this._box=void 0,this._boxSubscription=void 0,this._corridor=void 0,this._corridorSubscription=void 0,this._cylinder=void 0,this._cylinderSubscription=void 0,this._description=void 0,this._descriptionSubscription=void 0,this._ellipse=void 0,this._ellipseSubscription=void 0,this._ellipsoid=void 0,this._ellipsoidSubscription=void 0,this._label=void 0,this._labelSubscription=void 0,this._model=void 0,this._modelSubscription=void 0,this._orientation=void 0,this._orientationSubscription=void 0,this._path=void 0,this._pathSubscription=void 0,this._point=void 0,this._pointSubscription=void 0,this._polygon=void 0,this._polygonSubscription=void 0,this._polyline=void 0,this._polylineSubscription=void 0,this._polylineVolume=void 0,this._polylineVolumeSubscription=void 0,this._position=void 0,this._positionSubscription=void 0,this._rectangle=void 0,this._rectangleSubscription=void 0,this._viewFrom=void 0,this._viewFromSubscription=void 0,this._wall=void 0,this._wallSubscription=void 0,this._children=[],this.entityCollection=void 0,this.parent=e.parent,this.merge(e)};n(N.prototype,{availability:v("availability"),id:{get:function(){return this._id}},definitionChanged:{get:function(){return this._definitionChanged}},name:v("name"),show:{get:function(){return this._show},set:function(e){if(e!==this._show){var t=this.isShowing;this._show=e;var r=this.isShowing;t!==r&&O(this,this._children,r),this._definitionChanged.raiseEvent(this,"show",e,!e)}}},isShowing:{get:function(){return this._show&&(!i(this._parent)||this._parent.isShowing)}},parent:{get:function(){return this._parent},set:function(e){var t=this._parent;if(t!==e){var r=this.isShowing;if(i(t)){var n=t._children.indexOf(this);t._children.splice(n,1)}this._parent=e,i(e)&&e._children.push(this);var o=this.isShowing;r!==o&&O(this,this._children,o),this._definitionChanged.raiseEvent(this,"parent",e,t)}}},propertyNames:{get:function(){return this._propertyNames}},billboard:R("billboard",h),box:R("box",d),corridor:R("corridor",m),cylinder:R("cylinder",_),description:f("description"),ellipse:R("ellipse",g),ellipsoid:R("ellipsoid",y),label:R("label",C),model:R("model",E),orientation:f("orientation"),path:R("path",S),point:R("point",w),polygon:R("polygon",T),polyline:R("polyline",b),polylineVolume:R("polylineVolume",x),position:D("position"),rectangle:R("rectangle",A),viewFrom:f("viewFrom"),wall:R("wall",I)}),N.prototype.isAvailable=function(e){var t=this._availability;return!i(t)||t.contains(e)},N.prototype.addProperty=function(e){var t=this._propertyNames;t.push(e),Object.defineProperty(this,e,v(e,!0))},N.prototype.removeProperty=function(e){this._propertyNames;this._propertyNames.push(e),delete this[e]},N.prototype.merge=function(e){this.name=r(this.name,e.name),this.availability=r(e.availability,this.availability);for(var t=this._propertyNames,n=i(e._propertyNames)?e._propertyNames:Object.keys(e),o=n.length,a=0;o>a;a++){var s=n[a];if("parent"!==s){var l=this[s],u=e[s];i(l)||-1!==t.indexOf(s)||this.addProperty(s),i(u)&&(i(l)?i(l.merge)&&l.merge(u):i(u.merge)&&i(u.clone)?this[s]=u.clone():this[s]=u)}}};var L=new s,F=new e,B=new u;return N.prototype._getModelMatrix=function(e,t){var r=P.getValueOrUndefined(this._position,e,F);if(!i(r))return void 0;var n=P.getValueOrUndefined(this._orientation,e,B);return t=i(n)?l.fromRotationTranslation(s.fromQuaternion(n,L),r,t):c.eastNorthUpToFixedFrame(r,void 0,t)},N}),r("DataSources/EntityCollection",["../Core/AssociativeArray","../Core/createGuid","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/Iso8601","../Core/JulianDate","../Core/RuntimeError","../Core/TimeInterval","./Entity"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e){if(0===e._suspendCount){var t=e._addedEntities,r=e._removedEntities,i=e._changedEntities;(0!==i.length||0!==t.length||0!==r.length)&&(e._collectionChanged.raiseEvent(e,t.values,r.values,i.values),t.removeAll(),r.removeAll(),i.removeAll())}}var d={id:void 0},p=function(r){this._owner=r,this._entities=new e,this._addedEntities=new e,this._removedEntities=new e,this._changedEntities=new e,this._suspendCount=0,this._collectionChanged=new o,this._id=t()};return p.prototype.suspendEvents=function(){this._suspendCount++},p.prototype.resumeEvents=function(){this._suspendCount--,h(this)},p.collectionChangedEventCallback=void 0,i(p.prototype,{collectionChanged:{get:function(){return this._collectionChanged}},id:{get:function(){return this._id}},values:{get:function(){return this._entities.values}},owner:{get:function(){return this._owner}}}),p.prototype.computeAvailability=function(){for(var e=a.MAXIMUM_VALUE,t=a.MINIMUM_VALUE,i=this._entities.values,n=0,o=i.length;o>n;n++){var l=i[n],c=l.availability;if(r(c)){var h=c.start,d=c.stop;s.lessThan(h,e)&&!h.equals(a.MINIMUM_VALUE)&&(e=h),s.greaterThan(d,t)&&!d.equals(a.MAXIMUM_VALUE)&&(t=d)}}return a.MAXIMUM_VALUE.equals(e)&&(e=a.MINIMUM_VALUE),a.MINIMUM_VALUE.equals(t)&&(t=a.MAXIMUM_VALUE),new u({start:e,stop:t})},p.prototype.add=function(e){e instanceof c||(e=new c(e));var t=e.id,r=this._entities;if(r.contains(t))throw new l("An entity with id "+t+" already exists in this collection.");e.entityCollection=this,r.set(t,e);this._removedEntities;return this._removedEntities.remove(t)||this._addedEntities.set(t,e),e.definitionChanged.addEventListener(p.prototype._onEntityDefinitionChanged,this),h(this),e},p.prototype.remove=function(e){return r(e)?this.removeById(e.id):!1},p.prototype.contains=function(e){return this._entities.get(e.id)===e},p.prototype.removeById=function(e){if(!r(e))return!1;var t=this._entities,i=t.get(e);return this._entities.remove(e)?(this._addedEntities.remove(e)||(this._removedEntities.set(e,i),this._changedEntities.remove(e)),this._entities.remove(e),i.definitionChanged.removeEventListener(p.prototype._onEntityDefinitionChanged,this),h(this),!0):!1},p.prototype.removeAll=function(){for(var e=this._entities,t=e.length,i=e.values,n=this._addedEntities,o=this._removedEntities,a=0;t>a;a++){var s=i[a],l=s.id,u=n.get(l);r(u)||(s.definitionChanged.removeEventListener(p.prototype._onEntityDefinitionChanged,this),o.set(l,s))}e.removeAll(),n.removeAll(),this._changedEntities.removeAll(),h(this)},p.prototype.getById=function(e){return this._entities.get(e)},p.prototype.getOrCreateEntity=function(e){var t=this._entities.get(e);return r(t)||(d.id=e,t=new c(d),this.add(t)),t},p.prototype._onEntityDefinitionChanged=function(e){var t=e.id;this._addedEntities.contains(t)||this._changedEntities.set(t,e),h(this)},p}),r("DataSources/CompositeEntityCollection",["../Core/createGuid","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Math","./Entity","./EntityCollection"],function(e,t,r,i,n,o,a){"use strict";function s(e){for(var t=e.propertyNames,r=t.length,i=0;r>i;i++)e[t[i]]=void 0}function l(e,t,r,i){m[0]=r,m[1]=i.id,t[JSON.stringify(m)]=i.definitionChanged.addEventListener(f.prototype._onDefinitionChanged,e)}function u(e,t,r,i){m[0]=r,m[1]=i.id;var n=JSON.stringify(m);t[n](),t[n]=void 0}function c(e){if(e._shouldRecomposite=!0,0===e._suspendCount){var r,i,n,c,h,d,m=e._collections,v=m.length,_=e._collectionsCopy,g=_.length,y=e._composite,C=new a(e),E=e._eventHash;for(r=0;g>r;r++)for(h=_[r],h.collectionChanged.removeEventListener(f.prototype._onCollectionChanged,e),n=h.values,d=h.id,c=n.length-1;c>-1;c--)i=n[c],u(e,E,d,i);for(r=v-1;r>=0;r--)for(h=m[r],h.collectionChanged.addEventListener(f.prototype._onCollectionChanged,e),n=h.values,d=h.id,c=n.length-1;c>-1;c--){i=n[c],l(e,E,d,i);var S=C.getById(i.id);t(S)||(S=y.getById(i.id),t(S)?s(S):(p.id=i.id,S=new o(p)),C.add(S)),S.merge(i)}e._collectionsCopy=m.slice(0),y.suspendEvents(),y.removeAll();var w=C.values;for(r=0;rh;h++){var y=i[h];u(this,_,g,y);var C=y.id;for(d=a-1;d>=0;d--)m=n[d].getById(C),t(m)&&(t(f)||(f=c.getById(C),s(f)),f.merge(m));t(f)||c.removeById(C),f=void 0}var E=r.length;for(h=0;E>h;h++){var S=r[h];l(this,_,g,S);var w=S.id;for(d=a-1;d>=0;d--)m=n[d].getById(w),t(m)&&(t(f)||(f=c.getById(w),t(f)?s(f):(p.id=w,f=new o(p),c.add(f))),f.merge(m));f=void 0}c.resumeEvents()},f.prototype._onDefinitionChanged=function(e,r,i,n){for(var o=this._collections,a=this._composite,s=o.length,l=e.id,u=a.getById(l),c=u[r],h=!t(c),d=!0,p=s-1;p>=0;p--){var m=o[p].getById(e.id);if(t(m)){var f=m[r];if(t(f)){if(d){if(d=!1,!t(f.merge)||!t(f.clone)){c=f;break}c=f.clone(c)}c.merge(f)}}}h&&-1===u.propertyNames.indexOf(r)&&u.addProperty(r),u[r]=c},f}),r("DataSources/CompositeProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/EventHelper","../Core/TimeIntervalCollection","./Property"],function(e,t,r,i,n,o,a){"use strict";function s(t,r,i,n){var o=function(){i.raiseEvent(t)},a=[];r.removeAll();for(var s=n.length,l=0;s>l;l++){var u=n.get(l);e(u.data)&&-1===a.indexOf(u.data)&&r.add(u.data.definitionChanged,o)}}var l=function(){this._eventHelper=new n,this._definitionChanged=new i,this._intervals=new o,this._intervals.changedEvent.addEventListener(l.prototype._intervalsChanged,this)};return t(l.prototype,{isConstant:{get:function(){return this._intervals.isEmpty}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._intervals}}}),l.prototype.getValue=function(t,r){var i=this._intervals.findDataForIntervalContainingDate(t);return e(i)?i.getValue(t,r):void 0},l.prototype.equals=function(e){return this===e||e instanceof l&&this._intervals.equals(e._intervals,a.equals)},l.prototype._intervalsChanged=function(){s(this,this._eventHelper,this._definitionChanged,this._intervals),this._definitionChanged.raiseEvent(this)},l}),r("DataSources/CompositeMaterialProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./CompositeProperty","./Property"],function(e,t,r,i,n,o){"use strict";var a=function(){this._definitionChanged=new i,this._composite=new n,this._composite.definitionChanged.addEventListener(a.prototype._raiseDefinitionChanged,this)};return t(a.prototype,{isConstant:{get:function(){return this._composite.isConstant}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._composite._intervals}}}),a.prototype.getType=function(t){var r=this._composite._intervals.findDataForIntervalContainingDate(t);return e(r)?r.getType(t):void 0},a.prototype.getValue=function(t,r){var i=this._composite._intervals.findDataForIntervalContainingDate(t);return e(i)?i.getValue(t,r):void 0},a.prototype.equals=function(e){return this===e||e instanceof a&&this._composite.equals(e._composite,o.equals)},a.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},a}),r("DataSources/CompositePositionProperty",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","./CompositeProperty","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){this._referenceFrame=e(t,o.FIXED),this._definitionChanged=new n,this._composite=new a,this._composite.definitionChanged.addEventListener(l.prototype._raiseDefinitionChanged,this)};return r(l.prototype,{isConstant:{get:function(){return this._composite.isConstant}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._composite.intervals}},referenceFrame:{get:function(){return this._referenceFrame},set:function(e){this._referenceFrame=e}}}),l.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,o.FIXED,t)},l.prototype.getValueInReferenceFrame=function(e,r,i){var n=this._composite._intervals.findDataForIntervalContainingDate(e);return t(n)?n.getValueInReferenceFrame(e,r,i):void 0},l.prototype.equals=function(e){return this===e||e instanceof l&&this._referenceFrame===e._referenceFrame&&this._composite.equals(e._composite,s.equals)},l.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},l}),r("DataSources/CorridorGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/CorridorGeometry","../Core/CorridorOutlineGeometry","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.positions=void 0,this.width=void 0,this.cornerType=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"corridor",e.corridor,void 0)};a(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),a(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(i){var n,a,s=this._entity,l=s.isAvailable(i),u=new d(l&&s.isShowing&&this._showProperty.getValue(i)&&this._fillProperty.getValue(i));if(this._materialProperty instanceof v){var h=e.WHITE;o(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(h=this._materialProperty.color.getValue(i)),a=t.fromColor(h),n={show:u,color:a}}else n={show:u};return new c({id:s,geometry:new r(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var n=this._entity,o=n.isAvailable(r),a=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new c({id:n,geometry:new i(this._options),attributes:{show:new d(o&&n.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(a)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),s(this)},A.prototype._onEntityPropertyChanged=function(e,t,r,i){if("availability"===t||"corridor"===t){var a=this._entity.corridor;if(!o(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=o(s)&&s.isConstant?s.getValue(h.MINIMUM_VALUE):!0,u=a.outline,c=o(u);if(c&&u.isConstant&&(c=u.getValue(h.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.positions,f=a.show;if(o(f)&&f.isConstant&&!f.getValue(h.MINIMUM_VALUE)||!o(d))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=n(a.material,E),g=_ instanceof v;this._materialProperty=_,this._fillProperty=n(s,w),this._showProperty=n(f,S),this._showOutlineProperty=n(a.outline,T),this._outlineColorProperty=c?n(a.outlineColor,b):void 0;var y=a.height,x=a.extrudedHeight,P=a.granularity,A=a.width,I=a.outlineWidth,M=a.cornerType;if(this._isClosed=o(x),this._fillEnabled=l,this._outlineEnabled=c,d.isConstant&&C.isConstant(y)&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)&&C.isConstant(I)&&C.isConstant(M)){var D=this._options;D.vertexFormat=g?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,D.positions=d.getValue(h.MINIMUM_VALUE,D.positions),D.height=o(y)?y.getValue(h.MINIMUM_VALUE):void 0,D.extrudedHeight=o(x)?x.getValue(h.MINIMUM_VALUE):void 0,D.granularity=o(P)?P.getValue(h.MINIMUM_VALUE):void 0,D.width=o(A)?A.getValue(h.MINIMUM_VALUE):void 0,D.cornerType=o(M)?M.getValue(h.MINIMUM_VALUE):void 0,this._outlineWidth=o(I)?I.getValue(h.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(n){var a=this._primitives;a.removeAndDestroy(this._primitive),a.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var s=this._geometryUpdater,l=s._entity,u=l.corridor;if(l.isShowing&&l.isAvailable(n)&&C.getValueOrDefault(u.show,n,!0)){var h=this._options,d=C.getValueOrUndefined(u.positions,n,h.positions),v=C.getValueOrUndefined(u.width,n);if(o(d)&&o(v)){if(h.positions=d,h.width=v,h.height=C.getValueOrUndefined(u.height,n),h.extrudedHeight=C.getValueOrUndefined(u.extrudedHeight,n),h.granularity=C.getValueOrUndefined(u.granularity,n),h.cornerType=C.getValueOrUndefined(u.cornerType,n),!o(u.fill)||u.fill.getValue(n)){var _=y.getValue(n,s.fillMaterialProperty,this._material);this._material=_;var g=new p({material:_,translucent:_.isTranslucent(),closed:o(h.extrudedHeight)});h.vertexFormat=g.vertexFormat,this._primitive=a.add(new f({geometryInstances:new c({id:l,geometry:new r(h)}),appearance:g,asynchronous:!1}))}if(o(u.outline)&&u.outline.getValue(n)){h.vertexFormat=m.VERTEX_FORMAT;var E=C.getValueOrClonedDefault(u.outlineColor,n,e.BLACK,x),S=C.getValueOrDefault(u.outlineWidth,n,1),w=1!==E.alpha;this._outlinePrimitive=a.add(new f({geometryInstances:new c({id:l,geometry:new i(h),attributes:{color:t.fromColor(E)}}),appearance:new m({flat:!0,translucent:w,renderState:{lineWidth:s._scene.clampLineWidth(S)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),s(this)},A}),r("DataSources/DataSource",["../Core/defineProperties","../Core/DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return e(r.prototype,{name:{get:t.throwInstantiationError},clock:{get:t.throwInstantiationError},entities:{get:t.throwInstantiationError},isLoading:{get:t.throwInstantiationError},changedEvent:{get:t.throwInstantiationError},errorEvent:{get:t.throwInstantiationError},loadingEvent:{get:t.throwInstantiationError}}),r.prototype.update=t.throwInstantiationError,r.setLoading=function(e,t){e._isLoading!==t&&(t?e._entityCollection.suspendEvents():e._entityCollection.resumeEvents(),e._isLoading=t,e._loading.raiseEvent(e,t))},r}),r("DataSources/CustomDataSource",["../Core/defineProperties","../Core/Event","./DataSource","./EntityCollection"],function(e,t,r,i){"use strict";var n=function(e){this._name=e,this._clock=void 0,this._changed=new t,this._error=new t,this._isLoading=!1,this._loading=new t,this._entityCollection=new i(this)};return e(n.prototype,{name:{get:function(){return this._name},set:function(e){this._name!==e&&(this._name=e,this._changed.raiseEvent(this))}},clock:{get:function(){return this._clock},set:function(e){this._clock!==e&&(this._clock=e,this._changed.raiseEvent(this))}},entities:{get:function(){return this._entityCollection}},isLoading:{get:function(){return this._isLoading},set:function(e){r.setLoading(this,e)}},changedEvent:{get:function(){return this._changed}},errorEvent:{get:function(){return this._error}},loadingEvent:{get:function(){return this._loading}}}),n}),r("DataSources/CylinderGeometryUpdater",["../Core/Cartesian3","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/CylinderGeometry","../Core/CylinderOutlineGeometry","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";var S=new _(t.WHITE),w=new g(!0),T=new g(!0),b=new g(!1),x=new g(t.BLACK),P=new t,A=function(e){this.id=e,this.vertexFormat=void 0,this.length=void 0,this.topRadius=void 0,this.bottomRadius=void 0,this.slices=void 0,this.numberOfVerticalLines=void 0},I=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(I.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new c,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new A(e),this._onEntityPropertyChanged(e,"cylinder",e.cylinder,void 0)};s(I,{perInstanceColorAppearanceType:{value:f},materialAppearanceType:{value:m}}),s(I.prototype,{entity:{get:function(){return this._entity}}, +fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!a(this._entity.availability)&&E.isConstant(this._showProperty)&&E.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!a(this._entity.availability)&&E.isConstant(this._showProperty)&&E.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),I.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},I.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},I.prototype.createFillGeometryInstance=function(e){var n,o,s=this._entity,l=s.isAvailable(e),u=new p(l&&s.isShowing&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e));if(this._materialProperty instanceof _){var c=t.WHITE;a(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(c=this._materialProperty.color.getValue(e)),o=r.fromColor(c),n={show:u,color:o}}else n={show:u};return new h({id:s,geometry:new i(this._options),modelMatrix:s._getModelMatrix(d.MINIMUM_VALUE),attributes:n})},I.prototype.createOutlineGeometryInstance=function(e){var i=this._entity,o=i.isAvailable(e),a=E.getValueOrDefault(this._outlineColorProperty,e,t.BLACK);return new h({id:i,geometry:new n(this._options),modelMatrix:i._getModelMatrix(d.MINIMUM_VALUE),attributes:{show:new p(o&&i.isShowing&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)),color:r.fromColor(a)}})},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){this._entitySubscription(),l(this)},I.prototype._onEntityPropertyChanged=function(e,t,r,i){if("availability"===t||"position"===t||"orientation"===t||"cylinder"===t){var n=e.cylinder;if(!a(n))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=n.fill,l=a(s)&&s.isConstant?s.getValue(d.MINIMUM_VALUE):!0,u=n.outline,c=a(u);if(c&&u.isConstant&&(c=u.getValue(d.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var h=e.position,p=n.length,v=n.topRadius,g=n.bottomRadius,y=n.show;if(a(y)&&y.isConstant&&!y.getValue(d.MINIMUM_VALUE)||!a(h)||!a(p)||!a(v)||!a(g))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var C=o(n.material,S),P=C instanceof _;this._materialProperty=C,this._fillProperty=o(s,T),this._showProperty=o(y,w),this._showOutlineProperty=o(n.outline,b),this._outlineColorProperty=c?o(n.outlineColor,x):void 0;var A=n.slices,I=n.outlineWidth,M=n.numberOfVerticalLines;if(this._fillEnabled=l,this._outlineEnabled=c,h.isConstant&&E.isConstant(e.orientation)&&p.isConstant&&v.isConstant&&g.isConstant&&E.isConstant(A)&&E.isConstant(I)&&E.isConstant(M)){var D=this._options;D.vertexFormat=P?f.VERTEX_FORMAT:m.MaterialSupport.TEXTURED.vertexFormat,D.length=p.getValue(d.MINIMUM_VALUE),D.topRadius=v.getValue(d.MINIMUM_VALUE),D.bottomRadius=g.getValue(d.MINIMUM_VALUE),D.slices=a(A)?A.getValue(d.MINIMUM_VALUE):void 0,D.numberOfVerticalLines=a(M)?M.getValue(d.MINIMUM_VALUE):void 0,this._outlineWidth=a(I)?I.getValue(d.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},I.prototype.createDynamicUpdater=function(e){return new M(e,this)};var M=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new A(t._entity)};return M.prototype.update=function(e){var o=this._primitives;o.removeAndDestroy(this._primitive),o.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var s=this._geometryUpdater,l=s._entity,u=l.cylinder;if(l.isShowing&&l.isAvailable(e)&&E.getValueOrDefault(u.show,e,!0)){var c=this._options,d=l._getModelMatrix(e),p=E.getValueOrUndefined(u.length,e),_=E.getValueOrUndefined(u.topRadius,e),g=E.getValueOrUndefined(u.bottomRadius,e);if(a(d)&&a(p)&&a(_)&&a(g)){if(c.length=p,c.topRadius=_,c.bottomRadius=g,c.slices=E.getValueOrUndefined(u.slices,e),c.numberOfVerticalLines=E.getValueOrUndefined(u.numberOfVerticalLines,e),E.getValueOrDefault(u.fill,e,!0)){var y=C.getValue(e,s.fillMaterialProperty,this._material);this._material=y;var S=new m({material:y,translucent:y.isTranslucent(),closed:!0});c.vertexFormat=S.vertexFormat,this._primitive=o.add(new v({geometryInstances:new h({id:l,geometry:new i(c),modelMatrix:d}),appearance:S,asynchronous:!1}))}if(E.getValueOrDefault(u.outline,e,!1)){c.vertexFormat=f.VERTEX_FORMAT;var w=E.getValueOrClonedDefault(u.outlineColor,e,t.BLACK,P),T=E.getValueOrDefault(u.outlineWidth,e,1),b=1!==w.alpha;this._outlinePrimitive=o.add(new v({geometryInstances:new h({id:l,geometry:new n(c),modelMatrix:d,attributes:{color:r.fromColor(w)}}),appearance:new f({flat:!0,translucent:b,renderState:{lineWidth:s._scene.clampLineWidth(T)}}),asynchronous:!1}))}}}},M.prototype.getBoundingSphere=function(e,t){return y(e,this._primitive,this._outlinePrimitive,t)},M.prototype.isDestroyed=function(){return!1},M.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),l(this)},I}),r("Scene/LabelStyle",["../Core/freezeObject"],function(e){"use strict";var t={FILL:0,OUTLINE:1,FILL_AND_OUTLINE:2};return e(t)}),r("DataSources/DataSourceClock",["../Core/Clock","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/JulianDate","./createRawPropertyDescriptor"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(){this._startTime=void 0,this._stopTime=void 0,this._currentTime=void 0,this._clockRange=void 0,this._clockStep=void 0,this._multiplier=void 0,this._definitionChanged=new o};return i(l.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},startTime:s("startTime"),stopTime:s("stopTime"),currentTime:s("currentTime"),clockRange:s("clockRange"),clockStep:s("clockStep"),multiplier:s("multiplier")}),l.prototype.clone=function(e){return r(e)||(e=new l),e.startTime=this.startTime,e.stopTime=this.stopTime,e.currentTime=this.currentTime,e.clockRange=this.clockRange,e.clockStep=this.clockStep,e.multiplier=this.multiplier,e},l.prototype.equals=function(e){return this===e||r(e)&&a.equals(this.startTime,e.startTime)&&a.equals(this.stopTime,e.stopTime)&&a.equals(this.currentTime,e.currentTime)&&this.clockRange===e.clockRange&&this.clockStep===e.clockStep&&this.multiplier===e.multiplier},l.prototype.merge=function(e){this.startTime=t(this.startTime,e.startTime),this.stopTime=t(this.stopTime,e.stopTime),this.currentTime=t(this.currentTime,e.currentTime),this.clockRange=t(this.clockRange,e.clockRange),this.clockStep=t(this.clockStep,e.clockStep),this.multiplier=t(this.multiplier,e.multiplier)},l.prototype.getValue=function(t){return r(t)||(t=new e),t.startTime=this.startTime,t.stopTime=this.stopTime,t.clockRange=this.clockRange,t.clockStep=this.clockStep,t.multiplier=this.multiplier,t.currentTime=this.currentTime,t},l}),r("DataSources/GridMaterialProperty",["../Core/Cartesian2","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=t.WHITE,u=.1,c=new e(8,8),h=new e(0,0),d=new e(1,1),p=function(e){e=r(e,r.EMPTY_OBJECT),this._definitionChanged=new o,this._color=void 0,this._colorSubscription=void 0,this._cellAlpha=void 0,this._cellAlphaSubscription=void 0,this._lineCount=void 0,this._lineCountSubscription=void 0,this._lineThickness=void 0,this._lineThicknessSubscription=void 0,this._lineOffset=void 0,this._lineOffsetSubscription=void 0,this.color=e.color,this.cellAlpha=e.cellAlpha,this.lineCount=e.lineCount,this.lineThickness=e.lineThickness,this.lineOffset=e.lineOffset};return n(p.prototype,{isConstant:{get:function(){return s.isConstant(this._color)&&s.isConstant(this._cellAlpha)&&s.isConstant(this._lineCount)&&s.isConstant(this._lineThickness)&&s.isConstant(this._lineOffset)}},definitionChanged:{get:function(){return this._definitionChanged}},color:a("color"),cellAlpha:a("cellAlpha"),lineCount:a("lineCount"),lineThickness:a("lineThickness"),lineOffset:a("lineOffset")}),p.prototype.getType=function(e){return"Grid"},p.prototype.getValue=function(e,t){return i(t)||(t={}),t.color=s.getValueOrClonedDefault(this._color,e,l,t.color),t.cellAlpha=s.getValueOrDefault(this._cellAlpha,e,u),t.lineCount=s.getValueOrClonedDefault(this._lineCount,e,c,t.lineCount),t.lineThickness=s.getValueOrClonedDefault(this._lineThickness,e,d,t.lineThickness),t.lineOffset=s.getValueOrClonedDefault(this._lineOffset,e,h,t.lineOffset),t},p.prototype.equals=function(e){return this===e||e instanceof p&&s.equals(this._color,e._color)&&s.equals(this._cellAlpha,e._cellAlpha)&&s.equals(this._lineCount,e._lineCount)&&s.equals(this._lineThickness,e._lineThickness)&&s.equals(this._lineOffset,e._lineOffset)},p}),r("DataSources/PolylineGlowMaterialProperty",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=e.WHITE,l=.25,u=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this._glowPower=void 0,this._glowPowerSubscription=void 0,this.color=e.color,this.glowPower=e.glowPower};return i(u.prototype,{isConstant:{get:function(){return a.isConstant(this._color)&&a.isConstant(this._glow)}},definitionChanged:{get:function(){return this._definitionChanged}},color:o("color"),glowPower:o("glowPower")}),u.prototype.getType=function(e){return"PolylineGlow"},u.prototype.getValue=function(e,t){return r(t)||(t={}),t.color=a.getValueOrClonedDefault(this._color,e,s,t.color),t.glowPower=a.getValueOrDefault(this._glowPower,e,l,t.glowPower),t},u.prototype.equals=function(e){return this===e||e instanceof u&&a.equals(this._color,e._color)&&a.equals(this._glowPower,e._glowPower)},u}),r("DataSources/PolylineOutlineMaterialProperty",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=e.WHITE,l=e.BLACK,u=1,c=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this.color=e.color,this.outlineColor=e.outlineColor,this.outlineWidth=e.outlineWidth};return i(c.prototype,{isConstant:{get:function(){return a.isConstant(this._color)&&a.isConstant(this._outlineColor)&&a.isConstant(this._outlineWidth)}},definitionChanged:{get:function(){return this._definitionChanged}},color:o("color"),outlineColor:o("outlineColor"),outlineWidth:o("outlineWidth")}),c.prototype.getType=function(e){return"PolylineOutline"},c.prototype.getValue=function(e,t){return r(t)||(t={}),t.color=a.getValueOrClonedDefault(this._color,e,s,t.color),t.outlineColor=a.getValueOrClonedDefault(this._outlineColor,e,l,t.outlineColor),t.outlineWidth=a.getValueOrDefault(this._outlineWidth,e,u),t},c.prototype.equals=function(e){return this===e||e instanceof c&&a.equals(this._color,e._color)&&a.equals(this._outlineColor,e._outlineColor)&&a.equals(this._outlineWidth,e._outlineWidth)},c}),r("DataSources/PositionPropertyArray",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/EventHelper","../Core/ReferenceFrame","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t,r){this._value=void 0,this._definitionChanged=new n,this._eventHelper=new o,this._referenceFrame=e(r,a.FIXED),this.setValue(t)};return r(l.prototype,{isConstant:{get:function(){var e=this._value;if(!t(e))return!0;for(var r=e.length,i=0;r>i;i++)if(!s.isConstant(e[i]))return!1;return!0}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return this._referenceFrame}}}),l.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,a.FIXED,t)},l.prototype.getValueInReferenceFrame=function(e,r,i){var n=this._value;if(!t(n))return void 0;var o=n.length;t(i)||(i=new Array(o));for(var a=0,s=0;o>a;){var l=n[a],u=l.getValueInReferenceFrame(e,r,i[a]);t(u)&&(i[s]=u,s++),a++}return i.length=s,i},l.prototype.setValue=function(e){var r=this._eventHelper;if(r.removeAll(),t(e)){this._value=e.slice();for(var i=e.length,n=0;i>n;n++){var o=e[n];t(o)&&r.add(o.definitionChanged,l.prototype._raiseDefinitionChanged,this)}}else this._value=void 0;this._definitionChanged.raiseEvent(this)},l.prototype.equals=function(e){return this===e||e instanceof l&&this._referenceFrame===e._referenceFrame&&s.arrayEquals(this._value,e._value)},l.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},l}),r("DataSources/ReferenceProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/RuntimeError","./Property"],function(e,t,r,i,n,o){"use strict";function a(t){var r=!0;if(t._resolveEntity){var i=t._targetCollection.getById(t._targetId);if(e(i)?(i.definitionChanged.addEventListener(l.prototype._onTargetEntityDefinitionChanged,t),t._targetEntity=i,t._resolveEntity=!1):(i=t._targetEntity,r=!1),!e(i))throw new n('target entity "'+t._targetId+'" could not be resolved.')}return r}function s(t){var r=t._targetProperty;if(t._resolveProperty){var i=a(t),o=t._targetPropertyNames;r=t._targetEntity;for(var s=o.length,l=0;s>l&&e(r);l++)r=r[o[l]];if(e(r))t._targetProperty=r,t._resolveProperty=!i;else if(!e(t._targetProperty))throw new n('targetProperty "'+t._targetId+"."+o.join(".")+'" could not be resolved.')}return r}var l=function(e,t,r){this._targetCollection=e,this._targetId=t,this._targetPropertyNames=r,this._targetProperty=void 0,this._targetEntity=void 0,this._definitionChanged=new i,this._resolveEntity=!0,this._resolveProperty=!0,e.collectionChanged.addEventListener(l.prototype._onCollectionChanged,this)};return t(l.prototype,{isConstant:{get:function(){return o.isConstant(s(this))}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return s(this).referenceFrame}},targetId:{get:function(){return this._targetId}},targetCollection:{get:function(){return this._targetCollection}},targetPropertyNames:{get:function(){return this._targetPropertyNames}},resolvedProperty:{get:function(){return s(this)}}}),l.fromString=function(e,t){for(var r,i=[],n=!0,o=!1,a="",s=0;sn;n++)if(t[n]!==r[n])return!1;return!0},l.prototype._onTargetEntityDefinitionChanged=function(e,t,r,i){this._targetPropertyNames[0]===t&&(this._resolveProperty=!0,this._definitionChanged.raiseEvent(this))},l.prototype._onCollectionChanged=function(t,r,i){var n=this._targetEntity;e(n)&&(-1!==i.indexOf(n)?(n.definitionChanged.removeEventListener(l.prototype._onTargetEntityDefinitionChanged,this),this._resolveEntity=!0,this._resolveProperty=!0):this._resolveEntity&&(s(this),this._resolveEntity||this._definitionChanged.raiseEvent(this)))},l}),r("DataSources/Rotation",["../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/Math"],function(e,t,r,i){"use strict";var n={packedLength:1,pack:function(t,r,i){i=e(i,0),r[i]=t},unpack:function(t,r,i){return r=e(r,0),t[r]},convertPackedArrayForInterpolation:function(t,r,n,o){r=e(r,0),n=e(n,t.length);for(var a,s=0,l=n-r+1;l>s;s++){var u=t[r+s];0===s||Math.abs(a-u)o?o+i.TWO_PI:o}};return n}),r("DataSources/SampledProperty",["../Core/binarySearch","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ExtrapolationType","../Core/JulianDate","../Core/LinearApproximation"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t,r){var i,n=e.length,o=r.length,a=n+o;if(e.length=a,n!==t){var s=n-1;for(i=a-1;i>=t;i--)e[i]=e[s--]}for(i=0;o>i;i++)e[t++]=r[i]}function c(e,t){return e instanceof s?e:"string"==typeof e?s.fromIso8601(e):s.addSeconds(t,e,new s)}var h={packedLength:1,pack:function(e,r,i){i=t(i,0),r[i]=e},unpack:function(e,r,i){return r=t(r,0),e[r]}},d=[],p=[],m=function(t,i,n,o,a){for(var l,h,m,f,v,_,g=0;gm){for(m=~m,f=m*a,h=void 0,_=i[m];g=0||r(_)&&s.compare(v,_)>=0));){for(d[y++]=v,g+=1,l=0;a>l;l++)p[C++]=o[g],g+=1;h=v}y>0&&(p.length=C,u(n,f,p),d.length=y,u(i,m,d))}else{for(l=0;a>l;l++)g++,n[m*a+l]=o[g];g++}}},f=function(e,i){var n=e;n===Number&&(n=h);var s,u=n.packedLength,c=t(n.packedInterpolationLength,u),d=0;if(r(i)){var p=i.length;s=new Array(p);for(var m=0;p>m;m++){var f=i[m];f===Number&&(f=h);var v=f.packedLength;u+=v,c+=t(f.packedInterpolationLength,v),s[m]=f}d=p}this._type=e,this._innerType=n,this._interpolationDegree=1,this._interpolationAlgorithm=l,this._numberOfPoints=0,this._times=[],this._values=[],this._xTable=[],this._yTable=[],this._packedLength=u,this._packedInterpolationLength=c,this._updateTableLength=!0,this._interpolationResult=new Array(c),this._definitionChanged=new o,this._derivativeTypes=i,this._innerDerivativeTypes=s,this._inputOrder=d,this._forwardExtrapolationType=a.NONE,this._forwardExtrapolationDuration=0,this._backwardExtrapolationType=a.NONE,this._backwardExtrapolationDuration=0};return i(f.prototype,{isConstant:{get:function(){return 0===this._values.length}},definitionChanged:{get:function(){return this._definitionChanged}},type:{get:function(){return this._type}},derivativeTypes:{get:function(){return this._derivativeTypes}},interpolationDegree:{get:function(){return this._interpolationDegree}},interpolationAlgorithm:{get:function(){return this._interpolationAlgorithm}},forwardExtrapolationType:{get:function(){return this._forwardExtrapolationType},set:function(e){this._forwardExtrapolationType!==e&&(this._forwardExtrapolationType=e,this._definitionChanged.raiseEvent(this))}},forwardExtrapolationDuration:{get:function(){return this._forwardExtrapolationDuration},set:function(e){this._forwardExtrapolationDuration!==e&&(this._forwardExtrapolationDuration=e,this._definitionChanged.raiseEvent(this))}},backwardExtrapolationType:{get:function(){return this._backwardExtrapolationType},set:function(e){this._backwardExtrapolationType!==e&&(this._backwardExtrapolationType=e,this._definitionChanged.raiseEvent(this))}},backwardExtrapolationDuration:{get:function(){return this._backwardExtrapolationDuration},set:function(e){this._backwardExtrapolationDuration!==e&&(this._backwardExtrapolationDuration=e,this._definitionChanged.raiseEvent(this))}}}),f.prototype.getValue=function(t,i){var n=this._times,o=n.length;if(0===o)return void 0;var l,u=this._innerType,c=this._values,h=e(n,t,s.compare);if(0>h){if(h=~h,0===h){var d=n[h];if(l=this._backwardExtrapolationDuration,this._backwardExtrapolationType===a.NONE||0!==l&&s.secondsDifference(d,t)>l)return void 0;if(this._backwardExtrapolationType===a.HOLD)return u.unpack(c,0,i)}if(h>=o){h=o-1;var p=n[h];if(l=this._forwardExtrapolationDuration,this._forwardExtrapolationType===a.NONE||0!==l&&s.secondsDifference(t,p)>l)return void 0;if(this._forwardExtrapolationType===a.HOLD)return h=o-1,u.unpack(c,h*u.packedLength,i)}var m=this._xTable,f=this._yTable,v=this._interpolationAlgorithm,_=this._packedInterpolationLength,g=this._inputOrder;if(this._updateTableLength){this._updateTableLength=!1;var y=Math.min(v.getRequiredDataPoints(this._interpolationDegree,g),o);y!==this._numberOfPoints&&(this._numberOfPoints=y,m.length=y,f.length=y*_)}var C=this._numberOfPoints-1;if(1>C)return void 0;var E=0,S=o-1,w=S-E+1;if(C+1>w);else{var T=h-(C/2|0)-1;E>T&&(T=E);var b=T+C;b>S&&(b=S,T=b-C,E>T&&(T=E)),E=T,S=b}for(var x=S-E+1,P=0;x>P;++P)m[P]=s.secondsDifference(n[E+P],n[S]);if(r(u.convertPackedArrayForInterpolation))u.convertPackedArrayForInterpolation(c,E,S,f);else for(var A=0,I=this._packedLength,M=E*I,D=(S+1)*I;D>M;)f[A]=c[M],M++,A++;var R,O=s.secondsDifference(t,n[S]);if(0!==g&&r(v.interpolate)){var N=Math.floor(_/(g+1));R=v.interpolate(O,m,f,N,g,g,this._interpolationResult)}else R=v.interpolateOrderZero(O,m,f,_,this._interpolationResult);return r(u.unpackInterpolationResult)?u.unpackInterpolationResult(R,c,E,S,i):u.unpack(R,0,i)}return u.unpack(c,h*this._packedLength,i)},f.prototype.setInterpolationOptions=function(e){var t=!1,r=e.interpolationAlgorithm,i=e.interpolationDegree;this._interpolationAlgorithm!==r&&(this._interpolationAlgorithm=r,t=!0),this._interpolationDegree!==i&&(this._interpolationDegree=i,t=!0),t&&(this._updateTableLength=!0,this._definitionChanged.raiseEvent(this))},f.prototype.addSample=function(e,t,i){var n=this._innerDerivativeTypes,o=r(n),a=this._innerType,s=[];if(s.push(e),a.pack(t,s,s.length),o)for(var l=n.length,u=0;l>u;u++)n[u].pack(i[u],s,s.length);m(void 0,this._times,this._values,s,this._packedLength),this._updateTableLength=!0,this._definitionChanged.raiseEvent(this)},f.prototype.addSamples=function(e,t,i){for(var n=this._innerDerivativeTypes,o=r(n),a=this._innerType,s=e.length,l=[],u=0;s>u;u++)if(l.push(e[u]),a.pack(t[u],l,l.length),o)for(var c=i[u],h=n.length,d=0;h>d;d++)n[d].pack(c[d],l,l.length);m(void 0,this._times,this._values,l,this._packedLength),this._updateTableLength=!0,this._definitionChanged.raiseEvent(this)},f.prototype.addSamplesPackedArray=function(e,t){m(t,this._times,this._values,e,this._packedLength),this._updateTableLength=!0,this._definitionChanged.raiseEvent(this)},f.prototype.equals=function(e){if(this===e)return!0;if(!r(e))return!1;if(this._type!==e._type||this._interpolationDegree!==e._interpolationDegree||this._interpolationAlgorithm!==e._interpolationAlgorithm)return!1;var t=this._derivativeTypes,i=r(t),n=e._derivativeTypes,o=r(n);if(i!==o)return!1;var a,l;if(i){if(l=t.length,l!==n.length)return!1;for(a=0;l>a;a++)if(t[a]!==n[a])return!1}var u=this._times,c=e._times;if(l=u.length,l!==c.length)return!1;for(a=0;l>a;a++)if(!s.equals(u[a],c[a]))return!1;var h=this._values,d=e._values;for(a=0;l>a;a++)if(h[a]!==d[a])return!1;return!0},f._mergeNewSamples=m,f}),r("DataSources/SampledPositionProperty",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","./PositionProperty","./Property","./SampledProperty"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(r,i){i=t(i,0);var n;if(i>0){n=new Array(i);for(var s=0;i>s;s++)n[s]=e}this._numberOfDerivatives=i,this._property=new u(e,n),this._definitionChanged=new o,this._referenceFrame=t(r,a.FIXED),this._property._definitionChanged.addEventListener(function(){this._definitionChanged.raiseEvent(this)},this)};return i(c.prototype,{isConstant:{get:function(){return this._property.isConstant}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return this._referenceFrame}},interpolationDegree:{get:function(){return this._property.interpolationDegree}},interpolationAlgorithm:{get:function(){return this._property.interpolationAlgorithm}},numberOfDerivatives:{get:function(){return this._numberOfDerivatives}},forwardExtrapolationType:{get:function(){return this._property.forwardExtrapolationType},set:function(e){this._property.forwardExtrapolationType=e}},forwardExtrapolationDuration:{get:function(){return this._property.forwardExtrapolationDuration},set:function(e){this._property.forwardExtrapolationDuration=e}},backwardExtrapolationType:{get:function(){return this._property.backwardExtrapolationType},set:function(e){this._property.backwardExtrapolationType=e}},backwardExtrapolationDuration:{get:function(){return this._property.backwardExtrapolationDuration},set:function(e){this._property.backwardExtrapolationDuration=e}}}),c.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,a.FIXED,t)},c.prototype.getValueInReferenceFrame=function(e,t,i){return i=this._property.getValue(e,i),r(i)?s.convertToReferenceFrame(e,i,this._referenceFrame,t,i):void 0},c.prototype.setInterpolationOptions=function(e){this._property.setInterpolationOptions(e)},c.prototype.addSample=function(e,t,r){this._numberOfDerivatives;this._property.addSample(e,t,r)},c.prototype.addSamples=function(e,t,r){this._property.addSamples(e,t,r)},c.prototype.addSamplesPackedArray=function(e,t){this._property.addSamplesPackedArray(e,t)},c.prototype.equals=function(e){return this===e||e instanceof c&&l.equals(this._property,e._property)&&this._referenceFrame===e._referenceFrame},c}),r("DataSources/StripeOrientation",["../Core/freezeObject"],function(e){"use strict";var t={HORIZONTAL:0,VERTICAL:1};return e(t)}),r("DataSources/StripeMaterialProperty",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property","./StripeOrientation"],function(e,t,r,i,n,o,a,s){"use strict";var l=s.HORIZONTAL,u=e.WHITE,c=e.BLACK,h=0,d=1,p=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._orientation=void 0,this._orientationSubscription=void 0,this._evenColor=void 0,this._evenColorSubscription=void 0,this._oddColor=void 0,this._oddColorSubscription=void 0,this._offset=void 0,this._offsetSubscription=void 0,this._repeat=void 0,this._repeatSubscription=void 0,this.orientation=e.orientation,this.evenColor=e.evenColor,this.oddColor=e.oddColor,this.offset=e.offset,this.repeat=e.repeat};return i(p.prototype,{isConstant:{get:function(){return a.isConstant(this._orientation)&&a.isConstant(this._evenColor)&&a.isConstant(this._oddColor)&&a.isConstant(this._offset)&&a.isConstant(this._repeat)}},definitionChanged:{get:function(){return this._definitionChanged}},orientation:o("orientation"),evenColor:o("evenColor"),oddColor:o("oddColor"),offset:o("offset"),repeat:o("repeat")}),p.prototype.getType=function(e){return"Stripe"},p.prototype.getValue=function(e,t){return r(t)||(t={}),t.horizontal=a.getValueOrDefault(this._orientation,e,l)===s.HORIZONTAL,t.evenColor=a.getValueOrClonedDefault(this._evenColor,e,u,t.evenColor),t.oddColor=a.getValueOrClonedDefault(this._oddColor,e,c,t.oddColor),t.offset=a.getValueOrDefault(this._offset,e,h),t.repeat=a.getValueOrDefault(this._repeat,e,d),t},p.prototype.equals=function(e){return this===e||e instanceof p&&a.equals(this._orientation,e._orientation)&&a.equals(this._evenColor,e._evenColor)&&a.equals(this._oddColor,e._oddColor)&&a.equals(this._offset,e._offset)&&a.equals(this._repeat,e._repeat)},p}),r("DataSources/TimeIntervalCollectionPositionProperty",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","../Core/TimeIntervalCollection","./PositionProperty","./Property"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(t){this._definitionChanged=new n,this._intervals=new a,this._intervals.changedEvent.addEventListener(u.prototype._intervalsChanged,this),this._referenceFrame=e(t,o.FIXED)};return r(u.prototype,{isConstant:{get:function(){return this._intervals.isEmpty}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._intervals}},referenceFrame:{get:function(){return this._referenceFrame}}}),u.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,o.FIXED,t)},u.prototype.getValueInReferenceFrame=function(e,r,i){var n=this._intervals.findDataForIntervalContainingDate(e);return t(n)?s.convertToReferenceFrame(e,n,this._referenceFrame,r,i):void 0},u.prototype.equals=function(e){return this===e||e instanceof u&&this._intervals.equals(e._intervals,l.equals)&&this._referenceFrame===e._referenceFrame},u.prototype._intervalsChanged=function(){this._definitionChanged.raiseEvent(this)},u}),r("DataSources/TimeIntervalCollectionProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/TimeIntervalCollection","./Property"],function(e,t,r,i,n,o){"use strict";var a=function(){this._definitionChanged=new i,this._intervals=new n,this._intervals.changedEvent.addEventListener(a.prototype._intervalsChanged,this)};return t(a.prototype,{isConstant:{get:function(){return this._intervals.isEmpty}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._intervals}}}),a.prototype.getValue=function(t,r){var i=this._intervals.findDataForIntervalContainingDate(t);return e(i)&&"function"==typeof i.clone?i.clone(r):i},a.prototype.equals=function(e){return this===e||e instanceof a&&this._intervals.equals(e._intervals,o.equals)},a.prototype._intervalsChanged=function(){this._definitionChanged.raiseEvent(this)},a}),r("DataSources/CzmlDataSource",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/ClockRange","../Core/ClockStep","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/ExtrapolationType","../Core/getFilenameFromUri","../Core/HermitePolynomialApproximation","../Core/isArray","../Core/Iso8601","../Core/JulianDate","../Core/LagrangePolynomialApproximation","../Core/LinearApproximation","../Core/loadJson","../Core/Math","../Core/Quaternion","../Core/Rectangle","../Core/ReferenceFrame","../Core/RuntimeError","../Core/Spherical","../Core/TimeInterval","../Core/TimeIntervalCollection","../Scene/HorizontalOrigin","../Scene/LabelStyle","../Scene/VerticalOrigin","../ThirdParty/Uri","../ThirdParty/when","./BillboardGraphics","./ColorMaterialProperty","./CompositeMaterialProperty","./CompositePositionProperty","./CompositeProperty","./ConstantPositionProperty","./ConstantProperty","./DataSource","./DataSourceClock","./EllipseGraphics","./EllipsoidGraphics","./EntityCollection","./GridMaterialProperty","./ImageMaterialProperty","./LabelGraphics","./ModelGraphics","./PathGraphics","./PointGraphics","./PolygonGraphics","./PolylineGlowMaterialProperty","./PolylineGraphics","./PolylineOutlineMaterialProperty","./PositionPropertyArray","./RectangleGraphics","./ReferenceProperty","./Rotation","./SampledPositionProperty","./SampledProperty","./StripeMaterialProperty","./StripeOrientation","./TimeIntervalCollectionPositionProperty","./TimeIntervalCollectionProperty","./WallGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe,ae,se,le,ue,ce,he,de,pe){"use strict";function me(e,t){return"#"===t[0]&&(t=$e+t), +oe.fromString(e,t)}function fe(e){var t=e.rgbaf;if(l(t))return t;var r=e.rgba;if(!l(r))return void 0;if(r.length===o.length)return[o.byteToFloat(r[0]),o.byteToFloat(r[1]),o.byteToFloat(r[2]),o.byteToFloat(r[3])];var i=r.length;t=new Array(i);for(var n=0;i>n;n+=5)t[n]=r[n],t[n+1]=o.byteToFloat(r[n+1]),t[n+2]=o.byteToFloat(r[n+2]),t[n+3]=o.byteToFloat(r[n+3]),t[n+4]=o.byteToFloat(r[n+4]);return t}function ve(e,t){var r=s(e.uri,e);if(l(t)){var i=new O(document.location.href);t=new O(t),r=new O(r).resolve(t.resolve(i)).toString()}return r}function _e(e){var t=e.wsenDegrees;if(l(t)){for(var r=t.length,i=0;r>i;i++)t[i]=S.toRadians(t[i]);return t}return e.wsen}function ge(e){if(l(e.cartesian))return e.cartesian;if(l(e.cartesianVelocity))return e.cartesianVelocity;if(l(e.unitCartesian))return e.unitCartesian;var r,i,n,o=e.unitSpherical;if(l(o)){if(i=o.length,2===i)tt.clock=o[0],tt.cone=o[1],t.fromSpherical(tt,et),n=[et.x,et.y,et.z];else{var a=0;for(n=new Array(i/3*4),r=0;i>r;r+=4)n[r]=o[a++],tt.clock=o[a++],tt.cone=o[a++],t.fromSpherical(tt,et),n[r+1]=et.x,n[r+2]=et.y,n[r+3]=et.z}return n}var s=e.cartographicRadians;if(l(s)){if(3===s.length)rt.longitude=s[0],rt.latitude=s[1],rt.height=s[2],h.WGS84.cartographicToCartesian(rt,et),n=[et.x,et.y,et.z];else for(i=s.length,n=new Array(i),r=0;i>r;r+=4)rt.longitude=s[r+1],rt.latitude=s[r+2],rt.height=s[r+3],h.WGS84.cartographicToCartesian(rt,et),n[r]=s[r],n[r+1]=et.x,n[r+2]=et.y,n[r+3]=et.z;return n}var u=e.cartographicDegrees;if(!l(u))throw new x(JSON.stringify(e)+" is not a valid CZML interval.");if(3===u.length)rt.longitude=S.toRadians(u[0]),rt.latitude=S.toRadians(u[1]),rt.height=u[2],h.WGS84.cartographicToCartesian(rt,et),n=[et.x,et.y,et.z];else for(i=u.length,n=new Array(i),r=0;i>r;r+=4)rt.longitude=S.toRadians(u[r+1]),rt.latitude=S.toRadians(u[r+2]),rt.height=u[r+3],h.WGS84.cartographicToCartesian(rt,et),n[r]=u[r],n[r+1]=et.x,n[r+2]=et.y,n[r+3]=et.z;return n}function ye(e,t){var r=e[t],i=e[t+1],n=e[t+2],o=e[t+3],a=1/Math.sqrt(r*r+i*i+n*n+o*o);e[t]=r*a,e[t+1]=i*a,e[t+2]=n*a,e[t+3]=o*a}function Ce(e){var t=e.unitQuaternion;if(l(t)){if(4===t.length)return ye(t,0),t;for(var r=1;rh);var y="function"==typeof e.unpack&&e!==ae;if(!d&&!v)return void(f?t[r]=me(a,i.reference):y?t[r]=new U(e.unpack(p,0)):t[r]=new U(p));var C,E=t[r],S=i.epoch;if(l(S)&&(C=g.fromIso8601(S)),d&&!v)return E instanceof le||(E=new le(e),t[r]=E),E.addSamplesPackedArray(p,C),void Se(i,E);var w;if(!d&&v)return u=u.clone(),f?u.data=me(a,i.reference):y?u.data=e.unpack(p,0):u.data=p,l(E)||(E=f?new z:new de,t[r]=E),void(!f&&E instanceof de?E.intervals.addInterval(u):E instanceof z?(u.data=f?u.data:new U(u.data),E.intervals.addInterval(u)):(w=_.MAXIMUM_INTERVAL.clone(),w.data=E,E=new z,t[r]=E,E.intervals.addInterval(w),u.data=f?u.data:new U(u.data),E.intervals.addInterval(u)));l(E)||(E=new z,t[r]=E),E instanceof z||(w=_.MAXIMUM_INTERVAL.clone(),w.data=E,E=new z,t[r]=E,E.intervals.addInterval(w));var T=E.intervals;w=T.findInterval(u),l(w)&&w.data instanceof le||(w=u.clone(),w.data=new le(e),T.addInterval(w)),w.data.addSamplesPackedArray(p,C),Se(i,w.data)}function Te(e,t,r,i,n,o,a){if(l(i))if(v(i))for(var s=0,u=i.length;u>s;s++)we(e,t,r,i[s],n,o,a);else we(e,t,r,i,n,o,a)}function be(e,r,i,n,o,a){var u,c=i.interval;l(c)?(ot.iso8601=c,u=A.fromIso8601(ot),l(n)&&(u=A.intersect(u,n,it))):l(n)&&(u=n);var h,d,p,m=!1,f=l(i.cartesianVelocity)?1:0,v=t.packedLength*(f+1),y=l(i.reference),C=l(u)&&!u.equals(_.MAXIMUM_INTERVAL);if(y||(h=s(b[i.referenceFrame],void 0),d=ge(i),p=s(d.length,1),m=p>v),!m&&!C)return void(y?e[r]=me(a,i.reference):e[r]=new k(t.unpack(d),h));var E,S=e[r],w=i.epoch;if(l(w)&&(E=g.fromIso8601(w)),m&&!C)return(!(S instanceof se)||l(h)&&S.referenceFrame!==h)&&(S=new se(h,f),e[r]=S),S.addSamplesPackedArray(d,E),void Se(i,S);var T;if(!m&&C)return u=u.clone(),y?u.data=me(a,i.reference):u.data=t.unpack(d),l(S)||(S=y?new V(h):new he(h),e[r]=S),void(!y&&S instanceof he&&l(h)&&S.referenceFrame===h?S.intervals.addInterval(u):S instanceof V?(u.data=y?u.data:new k(u.data,h),S.intervals.addInterval(u)):(T=_.MAXIMUM_INTERVAL.clone(),T.data=S,S=new V(S.referenceFrame),e[r]=S,S.intervals.addInterval(T),u.data=y?u.data:new k(u.data,h),S.intervals.addInterval(u)));l(S)?S instanceof V||(T=_.MAXIMUM_INTERVAL.clone(),T.data=S,S=new V(S.referenceFrame),e[r]=S,S.intervals.addInterval(T)):(S=new V(h),e[r]=S);var x=S.intervals;T=x.findInterval(u),l(T)&&T.data instanceof se&&(!l(h)||T.data.referenceFrame===h)||(T=u.clone(),T.data=new se(h,f),x.addInterval(T)),T.data.addSamplesPackedArray(d,E),Se(i,T.data)}function xe(e,t,r,i,n,o){if(l(r))if(v(r))for(var a=0,s=r.length;s>a;a++)be(e,t,r[a],i,n,o);else be(e,t,r,i,n,o)}function Pe(t,r,i,n,a,s){var u,c=i.interval;l(c)?(ot.iso8601=c,u=A.fromIso8601(ot),l(n)&&(u=A.intersect(u,n,it))):l(n)&&(u=n);var h,d,p=t[r];if(l(u)){p instanceof B||(p=new B,t[r]=p);var m=p.intervals;d=m.findInterval({start:u.start,stop:u.stop}),l(d)?h=d.data:(d=u.clone(),m.addInterval(d))}else h=p;var f;l(i.solidColor)?(h instanceof F||(h=new F),f=i.solidColor,Te(o,h,"color",f.color,void 0,void 0,s)):l(i.grid)?(h instanceof Y||(h=new Y),f=i.grid,Te(o,h,"color",f.color,void 0,a,s),Te(Number,h,"cellAlpha",f.cellAlpha,void 0,a,s),Te(e,h,"lineThickness",f.lineThickness,void 0,a,s),Te(e,h,"lineOffset",f.lineOffset,void 0,a,s),Te(e,h,"lineCount",f.lineCount,void 0,a,s)):l(i.image)?(h instanceof X||(h=new X),f=i.image,Te(Image,h,"image",f.image,void 0,a,s),Te(e,h,"repeat",f.repeat,void 0,a,s)):l(i.stripe)?(h instanceof ue||(h=new ue),f=i.stripe,Te(ce,h,"orientation",f.orientation,void 0,a,s),Te(o,h,"evenColor",f.evenColor,void 0,a,s),Te(o,h,"oddColor",f.oddColor,void 0,a,s),Te(Number,h,"offset",f.offset,void 0,a,s),Te(Number,h,"repeat",f.repeat,void 0,a,s)):l(i.polylineOutline)?(h instanceof re||(h=new re),f=i.polylineOutline,Te(o,h,"color",f.color,void 0,a,s),Te(o,h,"outlineColor",f.outlineColor,void 0,a,s),Te(Number,h,"outlineWidth",f.outlineWidth,void 0,a,s)):l(i.polylineGlow)&&(h instanceof ee||(h=new ee),f=i.polylineGlow,Te(o,h,"color",f.color,void 0,a,s),Te(Number,h,"glowPower",f.glowPower,void 0,a,s)),l(d)?d.data=h:t[r]=h}function Ae(e,t,r,i,n,o){if(l(r))if(v(r))for(var a=0,s=r.length;s>a;a++)Pe(e,t,r[a],i,n,o);else Pe(e,t,r,i,n,o)}function Ie(e,t,r,i){e.name=s(t.name,e.name)}function Me(e,t,r,i){var n=t.description;l(n)&&Te(String,e,"description",n,void 0,i,r)}function De(e,t,r,i){var n=t.position;l(n)&&xe(e,"position",n,void 0,i,r)}function Re(e,r,i,n){var o=r.viewFrom;l(o)&&Te(t,e,"viewFrom",o,void 0,n,i)}function Oe(e,t,r,i){var n=t.orientation;l(n)&&Te(w,e,"orientation",n,void 0,i,r)}function Ne(e,r,i,n){var o,a,s=i.references;if(l(s)){var u=[];for(o=0,a=s.length;a>o;o++)u.push(me(n,s[o]));var c=i.interval;if(l(c)){if(c=A.fromIso8601(c),!(e[r]instanceof V)){c.data=new ie(u);var d=new V;d.intervals.addInterval(c),e[r]=d}}else e[r]=new ie(u)}else{var p=[],m=i.cartesian;if(l(m)){for(o=0,a=m.length;a>o;o+=3)p.push(new t(m[o],m[o+1],m[o+2]));i.array=p}else if(m=i.cartographicRadians,l(m)){for(o=0,a=m.length;a>o;o+=3)rt.longitude=m[o],rt.latitude=m[o+1],rt.height=m[o+2],p.push(h.WGS84.cartographicToCartesian(rt));i.array=p}else if(m=i.cartographicDegrees,l(m)){for(o=0,a=m.length;a>o;o+=3)p.push(t.fromDegrees(m[o],m[o+1],m[o+2]));i.array=p}l(i.array)&&Te(Array,e,r,i,void 0,void 0,n)}}function Le(e,t,r,i){if(l(r))if(v(r))for(var n=r.length,o=0;n>o;o++)Ne(e,t,r[o],i);else Ne(e,t,r,i)}function Fe(e,t,r,i){var n,o=t.availability;if(l(o)){var a;if(v(o))for(var s=o.length,u=0;s>u;u++)l(a)||(a=new I),ot.iso8601=o[u],n=A.fromIso8601(ot),a.addInterval(n);else ot.iso8601=o,n=A.fromIso8601(ot),a=new I,a.addInterval(n);e.availability=a}}function Be(r,i,n,a){var s=i.billboard;if(l(s)){var u,c=s.interval;l(c)&&(ot.iso8601=c,u=A.fromIso8601(ot));var h=r.billboard;l(h)||(r.billboard=h=new L),Te(o,h,"color",s.color,u,a,n),Te(t,h,"eyeOffset",s.eyeOffset,u,a,n),Te(M,h,"horizontalOrigin",s.horizontalOrigin,u,a,n),Te(Image,h,"image",s.image,u,a,n),Te(e,h,"pixelOffset",s.pixelOffset,u,a,n),Te(Number,h,"scale",s.scale,u,a,n),Te(ae,h,"rotation",s.rotation,u,a,n),Te(t,h,"alignedAxis",s.alignedAxis,u,a,n),Te(Boolean,h,"show",s.show,u,a,n),Te(R,h,"verticalOrigin",s.verticalOrigin,u,a,n),Te(Boolean,h,"sizeInMeters",s.sizeInMeters,u,a,n)}}function Ve(e,t){var r=e.version;if(l(r)&&"string"==typeof r){var i=r.split(".");if(2===i.length){if("1"!==i[0])throw new x("Cesium only supports CZML version 1.");t._version=r}}if(!l(t._version))throw new x("CZML version information invalid. It is expected to be a property on the document object in the . version format.");var n=t._documentPacket;l(e.name)&&(n.name=e.name);var o=e.clock;if(l(o)){var a=n.clock;l(a)?(a.interval=s(o.interval,a.interval),a.currentTime=s(o.currentTime,a.currentTime),a.range=s(o.range,a.range),a.step=s(o.step,a.step),a.multiplier=s(o.multiplier,a.multiplier)):n.clock={interval:o.interval,currentTime:o.currentTime,range:o.range,step:o.step,multiplier:o.multiplier}}}function ze(e,t,r,i){var n=t.ellipse;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.ellipse;l(u)||(e.ellipse=u=new H),Te(Boolean,u,"show",n.show,a,i,r),Te(ae,u,"rotation",n.rotation,a,i,r),Te(Number,u,"semiMajorAxis",n.semiMajorAxis,a,i,r),Te(Number,u,"semiMinorAxis",n.semiMinorAxis,a,i,r),Te(Number,u,"height",n.height,a,i,r),Te(Number,u,"extrudedHeight",n.extrudedHeight,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(ae,u,"stRotation",n.stRotation,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Number,u,"numberOfVerticalLines",n.numberOfVerticalLines,a,i,r)}}function ke(e,r,i,n){var a=r.ellipsoid;if(l(a)){var s,u=a.interval;l(u)&&(ot.iso8601=u,s=A.fromIso8601(ot));var c=e.ellipsoid;l(c)||(e.ellipsoid=c=new q),Te(Boolean,c,"show",a.show,s,n,i),Te(t,c,"radii",a.radii,s,n,i),Ae(c,"material",a.material,s,n,i),Te(Boolean,c,"fill",a.fill,s,n,i),Te(Boolean,c,"outline",a.outline,s,n,i),Te(o,c,"outlineColor",a.outlineColor,s,n,i),Te(Number,c,"outlineWidth",a.outlineWidth,s,n,i)}}function Ue(r,i,n,a){var s=i.label;if(l(s)){var u,c=s.interval;l(c)&&(ot.iso8601=c,u=A.fromIso8601(ot));var h=r.label;l(h)||(r.label=h=new Z),Te(o,h,"fillColor",s.fillColor,u,a,n),Te(o,h,"outlineColor",s.outlineColor,u,a,n),Te(Number,h,"outlineWidth",s.outlineWidth,u,a,n),Te(t,h,"eyeOffset",s.eyeOffset,u,a,n),Te(M,h,"horizontalOrigin",s.horizontalOrigin,u,a,n),Te(String,h,"text",s.text,u,a,n),Te(e,h,"pixelOffset",s.pixelOffset,u,a,n),Te(Number,h,"scale",s.scale,u,a,n),Te(Boolean,h,"show",s.show,u,a,n),Te(R,h,"verticalOrigin",s.verticalOrigin,u,a,n),Te(String,h,"font",s.font,u,a,n),Te(D,h,"style",s.style,u,a,n)}}function Ge(e,t,r,i){var n=t.model;if(l(n)){var o,a=n.interval;l(a)&&(ot.iso8601=a,o=A.fromIso8601(ot));var s=e.model;l(s)||(e.model=s=new K),Te(Boolean,s,"show",n.show,o,i,r),Te(Number,s,"scale",n.scale,o,i,r),Te(Number,s,"minimumPixelSize",n.minimumPixelSize,o,i,r),Te(O,s,"uri",n.gltf,o,i,r)}}function We(e,t,r,i){var n=t.path;if(l(n)){var o,a=n.interval;l(a)&&(ot.iso8601=a,o=A.fromIso8601(ot));var s=e.path;l(s)||(e.path=s=new J),Te(Boolean,s,"show",n.show,o,i,r),Te(Number,s,"width",n.width,o,i,r),Te(Number,s,"resolution",n.resolution,o,i,r),Te(Number,s,"leadTime",n.leadTime,o,i,r),Te(Number,s,"trailTime",n.trailTime,o,i,r),Ae(s,"material",n.material,o,i,r)}}function He(e,t,r,i){var n=t.point;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.point;l(u)||(e.point=u=new Q),Te(o,u,"color",n.color,a,i,r),Te(Number,u,"pixelSize",n.pixelSize,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Boolean,u,"show",n.show,a,i,r)}}function qe(e,t,r,i){var n=t.polygon;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.polygon;l(u)||(e.polygon=u=new $),Te(Boolean,u,"show",n.show,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Number,u,"height",n.height,a,i,r),Te(Number,u,"extrudedHeight",n.extrudedHeight,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(ae,u,"stRotation",n.stRotation,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Boolean,u,"perPositionHeight",n.perPositionHeight,a,i,r),Le(u,"hierarchy",n.positions,r)}}function je(e,t,r,i){var n=t.rectangle;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.rectangle;l(u)||(e.rectangle=u=new ne),Te(Boolean,u,"show",n.show,a,i,r),Te(T,u,"coordinates",n.coordinates,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Number,u,"height",n.height,a,i,r),Te(Number,u,"extrudedHeight",n.extrudedHeight,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(ae,u,"rotation",n.rotation,a,i,r),Te(ae,u,"stRotation",n.stRotation,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Boolean,u,"closeBottom",n.closeBottom,a,i,r),Te(Boolean,u,"closeTop",n.closeTop,a,i,r)}}function Ye(e,t,r,i){var n=t.wall;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.wall;l(u)||(e.wall=u=new pe),Te(Boolean,u,"show",n.show,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Array,u,"minimumHeights",n.minimumHeights,a,i,r),Te(Array,u,"maximumHeights",n.maximumHeights,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Le(u,"positions",n.positions,r)}}function Xe(e,t,r,i){var n=t.polyline;if(l(n)){var o,a=n.interval;l(a)&&(ot.iso8601=a,o=A.fromIso8601(ot));var s=e.polyline;l(s)||(e.polyline=s=new te),Te(Boolean,s,"show",n.show,o,i,r),Te(Number,s,"width",n.width,o,i,r),Ae(s,"material",n.material,o,i,r),Te(Boolean,s,"followSurface",n.followSurface,o,i,r),Te(Number,s,"granularity",n.granularity,o,i,r),Le(s,"positions",n.positions,r)}}function Ze(e,t,r,i,n){var o=e.id;if(l(o)||(o=a()),$e=o,!l(n._version)&&"document"!==o)throw new x("The first CZML packet is required to be the document object.");if(e["delete"]===!0)t.removeById(o);else if("document"===o)Ve(e,n);else{var s=t.getOrCreateEntity(o),u=e.parent;l(u)&&(s.parent=t.getOrCreateEntity(u));for(var c=r.length-1;c>-1;c--)r[c](s,e,t,i)}$e=void 0}function Ke(e){var t,r=e._documentPacket.clock;if(!l(r)){if(!l(e._clock)){var o=e._entityCollection.computeAvailability();if(!o.start.equals(_.MINIMUM_VALUE)){var a=o.start,u=o.stop,c=g.secondsDifference(u,a),h=Math.round(c/120);return t=new W,t.startTime=g.clone(a),t.stopTime=g.clone(u),t.clockRange=i.LOOP_STOP,t.multiplier=h,t.currentTime=g.clone(a),t.clockStep=n.SYSTEM_CLOCK_MULTIPLIER,e._clock=t,!0}}return!1}if(l(e._clock)?t=e._clock.clone():(t=new W,t.startTime=_.MINIMUM_VALUE.clone(),t.stopTime=_.MAXIMUM_VALUE.clone(),t.currentTime=_.MINIMUM_VALUE.clone(),t.clockRange=i.LOOP_STOP,t.clockStep=n.SYSTEM_CLOCK_MULTIPLIER,t.multiplier=1),l(r.interval)){ot.iso8601=r.interval;var d=A.fromIso8601(ot);t.startTime=d.start,t.stopTime=d.stop}return l(r.currentTime)&&(t.currentTime=g.fromIso8601(r.currentTime)),l(r.range)&&(t.clockRange=s(i[r.range],i.LOOP_STOP)),l(r.step)&&(t.clockStep=s(n[r.step],n.SYSTEM_CLOCK_MULTIPLIER)),l(r.multiplier)&&(t.multiplier=r.multiplier),t.equals(e._clock)?!1:(e._clock=t.clone(e._clock),!0)}function Je(e,t,r,i){r=s(r,s.EMPTY_OBJECT);var n=t,o=r.sourceUri;return"string"==typeof t&&(n=E(t),o=s(o,t)),G.setLoading(e,!0),N(n,function(t){return Qe(e,t,o,i)}).otherwise(function(t){return G.setLoading(e,!1),e._error.raiseEvent(e,t),window.console.log(t),N.reject(t)})}function Qe(e,t,r,i){G.setLoading(e,!0);var n=e._entityCollection;i&&(e._version=void 0,e._documentPacket=new at,n.removeAll()),st._processCzml(t,n,r,void 0,e);var o=Ke(e),a=e._documentPacket;return l(a.name)&&e._name!==a.name?(e._name=a.name,o=!0):!l(e._name)&&l(r)&&(e._name=m(r),o=!0),G.setLoading(e,!1),o&&e._changed.raiseEvent(e),e}var $e,et=new t,tt=new P,rt=new r,it=new A,nt={HERMITE:f,LAGRANGE:y,LINEAR:C},ot={iso8601:void 0},at=function(){this.name=void 0,this.clock=void 0},st=function(e){this._name=e,this._changed=new d,this._error=new d,this._isLoading=!1,this._loading=new d,this._clock=void 0,this._documentPacket=new at,this._version=void 0,this._entityCollection=new j(this)};return st.load=function(e,t){return(new st).load(e,t)},u(st.prototype,{name:{get:function(){return this._name}},clock:{get:function(){return this._clock}},entities:{get:function(){return this._entityCollection}},isLoading:{get:function(){return this._isLoading}},changedEvent:{get:function(){return this._changed}},errorEvent:{get:function(){return this._error}},loadingEvent:{get:function(){return this._loading}}}),st.updaters=[Be,ze,ke,Ue,Ge,Ie,Me,We,He,qe,Xe,je,De,Re,Ye,Oe,Fe],st.prototype.process=function(e,t){return Je(this,e,t,!1)},st.prototype.load=function(e,t){return Je(this,e,t,!0)},st.processPacketData=Te,st.processPositionPacketData=xe,st.processMaterialPacketData=Ae,st._processCzml=function(e,t,r,i,n){if(i=l(i)?i:st.updaters,v(e))for(var o=0,a=e.length;a>o;o++)Ze(e[o],t,i,r,n);else Ze(e,t,i,r,n)},st}),r("DataSources/DataSourceCollection",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../ThirdParty/when"],function(e,t,r,i,n,o,a){"use strict";var s=function(){this._dataSources=[],this._dataSourceAdded=new o,this._dataSourceRemoved=new o};return r(s.prototype,{length:{get:function(){return this._dataSources.length}},dataSourceAdded:{get:function(){return this._dataSourceAdded}},dataSourceRemoved:{get:function(){return this._dataSourceRemoved}}}),s.prototype.add=function(e){var t=this,r=this._dataSources;return a(e,function(e){return r===t._dataSources&&(t._dataSources.push(e),t._dataSourceAdded.raiseEvent(t,e)),e})},s.prototype.remove=function(t,r){r=e(r,!1);var i=this._dataSources.indexOf(t);return-1!==i?(this._dataSources.splice(i,1),this._dataSourceRemoved.raiseEvent(this,t),r&&"function"==typeof t.destroy&&t.destroy(),!0):!1},s.prototype.removeAll=function(t){t=e(t,!1);for(var r=this._dataSources,i=0,n=r.length;n>i;++i){var o=r[i];this._dataSourceRemoved.raiseEvent(this,o),t&&"function"==typeof o.destroy&&o.destroy()}this._dataSources=[]},s.prototype.contains=function(e){return-1!==this.indexOf(e)},s.prototype.indexOf=function(e){return this._dataSources.indexOf(e)},s.prototype.get=function(e){return this._dataSources[e]},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this.removeAll(!0),i(this)},s}),r("DataSources/EllipseGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EllipseGeometry","../Core/EllipseOutlineGeometry","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.center=void 0,this.semiMajorAxis=void 0,this.semiMinorAxis=void 0,this.rotation=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0,this.stRotation=void 0,this.numberOfVerticalLines=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"ellipse",e.ellipse,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,l=a.isAvailable(r),u=new d(l&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var h=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(h=this._materialProperty.color.getValue(r)),o=t.fromColor(h),n={show:u,color:o}}else n={show:u};return new c({id:a,geometry:new s(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new c({id:i,geometry:new l(this._options),attributes:{show:new d(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"position"===t||"ellipse"===t){var a=this._entity.ellipse;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(h.MINIMUM_VALUE):!0,u=a.outline,c=i(u);if(c&&u.isConstant&&(c=u.getValue(h.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=this._entity.position,f=a.semiMajorAxis,_=a.semiMinorAxis,g=a.show;if(i(g)&&g.isConstant&&!g.getValue(h.MINIMUM_VALUE)||!i(d)||!i(f)||!i(_))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var y=r(a.material,E),x=y instanceof v;this._materialProperty=y,this._fillProperty=r(s,w),this._showProperty=r(g,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=c?r(a.outlineColor,b):void 0;var P=a.rotation,A=a.height,I=a.extrudedHeight,M=a.granularity,D=a.stRotation,R=a.outlineWidth,O=a.numberOfVerticalLines;if(this._isClosed=i(I),this._fillEnabled=l,this._outlineEnabled=c,d.isConstant&&f.isConstant&&_.isConstant&&C.isConstant(P)&&C.isConstant(A)&&C.isConstant(I)&&C.isConstant(M)&&C.isConstant(D)&&C.isConstant(R)&&C.isConstant(O)){var N=this._options;N.vertexFormat=x?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,N.center=d.getValue(h.MINIMUM_VALUE,N.center),N.semiMajorAxis=f.getValue(h.MINIMUM_VALUE,N.semiMajorAxis),N.semiMinorAxis=_.getValue(h.MINIMUM_VALUE,N.semiMinorAxis),N.rotation=i(P)?P.getValue(h.MINIMUM_VALUE):void 0,N.height=i(A)?A.getValue(h.MINIMUM_VALUE):void 0,N.extrudedHeight=i(I)?I.getValue(h.MINIMUM_VALUE):void 0,N.granularity=i(M)?M.getValue(h.MINIMUM_VALUE):void 0,N.stRotation=i(D)?D.getValue(h.MINIMUM_VALUE):void 0,N.numberOfVerticalLines=i(O)?O.getValue(h.MINIMUM_VALUE):void 0,this._outlineWidth=i(R)?R.getValue(h.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,u=a.ellipse;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(u.show,r,!0)){var h=this._options,d=C.getValueOrUndefined(a.position,r,h.center),v=C.getValueOrUndefined(u.semiMajorAxis,r),_=C.getValueOrUndefined(u.semiMinorAxis,r);if(i(d)&&i(v)&&i(_)){if(h.center=d,h.semiMajorAxis=v,h.semiMinorAxis=_,h.rotation=C.getValueOrUndefined(u.rotation,r),h.height=C.getValueOrUndefined(u.height,r),h.extrudedHeight=C.getValueOrUndefined(u.extrudedHeight,r),h.granularity=C.getValueOrUndefined(u.granularity,r),h.stRotation=C.getValueOrUndefined(u.stRotation,r),h.numberOfVerticalLines=C.getValueOrUndefined(u.numberOfVerticalLines,r),C.getValueOrDefault(u.fill,r,!0)){var g=y.getValue(r,o.fillMaterialProperty,this._material);this._material=g;var E=new p({material:g,translucent:g.isTranslucent(),closed:i(h.extrudedHeight)});h.vertexFormat=E.vertexFormat,this._primitive=n.add(new f({geometryInstances:new c({id:a,geometry:new s(h)}),appearance:E,asynchronous:!1}))}if(C.getValueOrDefault(u.outline,r,!1)){h.vertexFormat=m.VERTEX_FORMAT;var S=C.getValueOrClonedDefault(u.outlineColor,r,e.BLACK,x),w=C.getValueOrDefault(u.outlineWidth,r,1),T=1!==S.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new c({id:a,geometry:new l(h),attributes:{color:t.fromColor(S)}}),appearance:new m({flat:!0,translucent:T,renderState:{lineWidth:o._scene.clampLineWidth(w)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/EllipsoidGeometryUpdater",["../Core/Cartesian3","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EllipsoidGeometry","../Core/EllipsoidOutlineGeometry","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/Matrix4","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","../Scene/SceneMode","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";var T=new y(t.WHITE),b=new C(!0),x=new C(!0),P=new C(!1),A=new C(t.BLACK),I=new e,M=new t,D=new e(1,1,1),R=function(e){this.id=e,this.vertexFormat=void 0,this.radii=void 0,this.stackPartitions=void 0,this.slicePartitions=void 0,this.subdivisions=void 0},O=function(e,t){this._scene=t,this._entity=e,this._entitySubscription=e.definitionChanged.addEventListener(O.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new c,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new R(e),this._onEntityPropertyChanged(e,"ellipsoid",e.ellipsoid,void 0)};o(O,{perInstanceColorAppearanceType:{value:v},materialAppearanceType:{value:f}}),o(O.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!n(this._entity.availability)&&w.isConstant(this._showProperty)&&w.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!n(this._entity.availability)&&w.isConstant(this._showProperty)&&w.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),O.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},O.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},O.prototype.createFillGeometryInstance=function(e){var i,o,a=this._entity,s=a.isAvailable(e),u=new m(s&&a.isShowing&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e));if(this._materialProperty instanceof y){var c=t.WHITE;n(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(c=this._materialProperty.color.getValue(e)),o=r.fromColor(c),i={show:u,color:o}}else i={show:u};return new h({id:a,geometry:new l(this._options),modelMatrix:a._getModelMatrix(d.MINIMUM_VALUE),attributes:i})},O.prototype.createOutlineGeometryInstance=function(e){var i=this._entity,n=i.isAvailable(e),o=w.getValueOrDefault(this._outlineColorProperty,e,t.BLACK);return new h({id:i,geometry:new u(this._options),modelMatrix:i._getModelMatrix(d.MINIMUM_VALUE),attributes:{show:new m(n&&i.isShowing&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)),color:r.fromColor(o)}})},O.prototype.isDestroyed=function(){return!1},O.prototype.destroy=function(){this._entitySubscription(),a(this)},O.prototype._onEntityPropertyChanged=function(e,t,r,o){if("availability"===t||"position"===t||"orientation"===t||"ellipsoid"===t){ +var a=e.ellipsoid;if(!n(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=n(s)&&s.isConstant?s.getValue(d.MINIMUM_VALUE):!0,u=a.outline,c=n(u);if(c&&u.isConstant&&(c=u.getValue(d.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var h=e.position,p=a.radii,m=a.show;if(n(m)&&m.isConstant&&!m.getValue(d.MINIMUM_VALUE)||!n(h)||!n(p))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=i(a.material,T),g=_ instanceof y;this._materialProperty=_,this._fillProperty=i(s,x),this._showProperty=i(m,b),this._showOutlineProperty=i(a.outline,P),this._outlineColorProperty=c?i(a.outlineColor,A):void 0,this._fillEnabled=l,this._outlineEnabled=c;var C=a.stackPartitions,E=a.slicePartitions,S=a.outlineWidth,I=a.subdivisions;if(h.isConstant&&w.isConstant(e.orientation)&&p.isConstant&&w.isConstant(C)&&w.isConstant(E)&&w.isConstant(S)&&w.isConstant(I)){var M=this._options;M.vertexFormat=g?v.VERTEX_FORMAT:f.MaterialSupport.TEXTURED.vertexFormat,M.radii=p.getValue(d.MINIMUM_VALUE,M.radii),M.stackPartitions=n(C)?C.getValue(d.MINIMUM_VALUE):void 0,M.slicePartitions=n(E)?E.getValue(d.MINIMUM_VALUE):void 0,M.subdivisions=n(I)?I.getValue(d.MINIMUM_VALUE):void 0,this._outlineWidth=n(S)?S.getValue(d.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},O.prototype.createDynamicUpdater=function(e){return new N(e,this)};var N=function(e,t){this._entity=t._entity,this._scene=t._scene,this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new R(t._entity),this._modelMatrix=new p,this._material=void 0,this._attributes=void 0,this._outlineAttributes=void 0,this._lastSceneMode=void 0,this._lastShow=void 0,this._lastOutlineShow=void 0,this._lastOutlineWidth=void 0,this._lastOutlineColor=void 0};return N.prototype.update=function(e){var o=this._entity,a=o.ellipsoid;if(!o.isShowing||!o.isAvailable(e)||!w.getValueOrDefault(a.show,e,!0))return n(this._primitive)&&(this._primitive.show=!1),void(n(this._outlinePrimitive)&&(this._outlinePrimitive.show=!1));var s=w.getValueOrUndefined(a.radii,e,I),c=o._getModelMatrix(e,this._modelMatrix);if(!n(c)||!n(s))return n(this._primitive)&&(this._primitive.show=!1),void(n(this._outlinePrimitive)&&(this._outlinePrimitive.show=!1));var d,y=w.getValueOrDefault(a.fill,e,!0),C=w.getValueOrDefault(a.outline,e,!1),E=w.getValueOrClonedDefault(a.outlineColor,e,t.BLACK,M),b=S.getValue(e,i(a.material,T),this._material);this._material=b;var x=w.getValueOrUndefined(a.stackPartitions,e),P=w.getValueOrUndefined(a.slicePartitions,e),A=w.getValueOrUndefined(a.subdivisions,e),R=w.getValueOrDefault(a.outlineWidth,e,1),O=this._scene.mode,N=O===g.SCENE3D,L=this._options,F=!N||this._lastSceneMode!==O||!n(this._primitive)||L.stackPartitions!==x||L.slicePartitions!==P||L.subdivisions!==A||this._lastOutlineWidth!==R;if(F){var B=this._primitives;B.removeAndDestroy(this._primitive),B.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0,this._lastSceneMode=O,this._lastOutlineWidth=R,L.stackPartitions=x,L.slicePartitions=P,L.subdivisions=A,L.radii=N?D:s,d=new f({material:b,translucent:b.isTranslucent(),closed:!0}),L.vertexFormat=d.vertexFormat,this._primitive=B.add(new _({geometryInstances:new h({id:o,geometry:new l(L),modelMatrix:N?void 0:c,attributes:{show:new m(y)}}),appearance:d,asynchronous:!1})),L.vertexFormat=v.VERTEX_FORMAT,this._outlinePrimitive=B.add(new _({geometryInstances:new h({id:o,geometry:new u(L),modelMatrix:N?void 0:c,attributes:{show:new m(C),color:r.fromColor(E)}}),appearance:new v({flat:!0,translucent:1!==E.alpha,renderState:{lineWidth:this._geometryUpdater._scene.clampLineWidth(R)}}),asynchronous:!1})),this._lastShow=y,this._lastOutlineShow=C,this._lastOutlineColor=t.clone(E,this._lastOutlineColor)}else if(this._primitive.ready){var V=this._primitive,z=this._outlinePrimitive;V.show=!0,z.show=!0,d=V.appearance,d.material=b;var k=this._attributes;n(k)||(k=V.getGeometryInstanceAttributes(o),this._attributes=k),y!==this._lastShow&&(k.show=m.toValue(y,k.show),this._lastShow=y);var U=this._outlineAttributes;n(U)||(U=z.getGeometryInstanceAttributes(o),this._outlineAttributes=U),C!==this._lastOutlineShow&&(U.show=m.toValue(C,U.show),this._lastOutlineShow=C),t.equals(E,this._lastOutlineColor)||(U.color=r.toValue(E,U.color),t.clone(E,this._lastOutlineColor))}N&&(s.x=Math.max(s.x,.001),s.y=Math.max(s.y,.001),s.z=Math.max(s.z,.001),c=p.multiplyByScale(c,s,c),this._primitive.modelMatrix=c,this._outlinePrimitive.modelMatrix=c)},N.prototype.getBoundingSphere=function(e,t){return E(e,this._primitive,this._outlinePrimitive,t)},N.prototype.isDestroyed=function(){return!1},N.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),a(this)},O}),r("DataSources/StaticGeometryColorBatch",["../Core/AssociativeArray","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defined","../Core/ShowGeometryInstanceAttribute","../Scene/Primitive","./BoundingSphereState"],function(e,t,r,i,n,o,a){"use strict";var s=new t,l=function(t,r,i,n){this.translucent=r,this.appearanceType=i,this.closed=n,this.primitives=t,this.createPrimitive=!1,this.primitive=void 0,this.oldPrimitive=void 0,this.geometry=new e,this.updaters=new e,this.updatersWithAttributes=new e,this.attributes=new e,this.subscriptions=new e,this.showsUpdated=new e,this.itemsToRemove=[]};l.prototype.add=function(e,t){var r=e.entity.id;if(this.createPrimitive=!0,this.geometry.set(r,t),this.updaters.set(r,e),e.hasConstantFill&&e.fillMaterialProperty.isConstant){var i=this;this.subscriptions.set(r,e.entity.definitionChanged.addEventListener(function(t,r,n,o){"isShowing"===r&&i.showsUpdated.set(t.id,e)}))}else this.updatersWithAttributes.set(r,e)},l.prototype.remove=function(e){var t=e.entity.id;if(this.createPrimitive=this.geometry.remove(t)||this.createPrimitive,this.updaters.remove(t)){this.updatersWithAttributes.remove(t);var r=this.subscriptions.get(t);i(r)&&(r(),this.subscriptions.remove(t))}},l.prototype.update=function(e){var a,l,u=!0,c=0,h=this.primitive,d=this.primitives;if(this.createPrimitive){var p=this.geometry.values,m=p.length;if(m>0){for(i(h)&&(i(this.oldPrimitive)?d.remove(h):this.oldPrimitive=h),l=0;m>l;l++){var f=p[l],v=f.attributes;a=this.attributes.get(f.id.id),i(a)&&(i(v.show)&&(v.show.value=a.show),i(v.color)&&(v.color.value=a.color))}h=new o({asynchronous:!0,geometryInstances:p,appearance:new this.appearanceType({translucent:this.translucent,closed:this.closed})}),d.add(h),u=!1}else{i(h)&&(d.remove(h),h=void 0);var _=this.oldPrimitive;i(_)&&(d.remove(_),this.oldPrimitive=void 0)}this.attributes.removeAll(),this.primitive=h,this.createPrimitive=!1}else if(i(h)&&h.ready){i(this.oldPrimitive)&&(d.remove(this.oldPrimitive),this.oldPrimitive=void 0);var g=this.updatersWithAttributes.values,y=g.length;for(l=0;y>l;l++){var C=g[l],E=this.geometry.get(C.entity.id);if(a=this.attributes.get(E.id.id),i(a)||(a=h.getGeometryInstanceAttributes(E.id),this.attributes.set(E.id.id,a)),!C.fillMaterialProperty.isConstant){var S=C.fillMaterialProperty.color;S.getValue(e,s),t.equals(a._lastColor,s)||(a._lastColor=t.clone(s,a._lastColor),a.color=r.toValue(s,a.color),(this.translucent&&255===a.color[3]||!this.translucent&&255!==a.color[3])&&(this.itemsToRemove[c++]=C))}var w=C.entity.isShowing&&(C.hasConstantFill||C.isFilled(e)),T=1===a.show[0];w!==T&&(a.show=n.toValue(w,a.show))}this.updateShows(h)}else i(h)&&!h.ready&&(u=!1);return this.itemsToRemove.length=c,u},l.prototype.updateShows=function(e){for(var t=this.showsUpdated.values,r=t.length,o=0;r>o;o++){var a=t[o],s=this.geometry.get(a.entity.id),l=this.attributes.get(s.id.id);i(l)||(l=e.getGeometryInstanceAttributes(s.id),this.attributes.set(s.id.id,l));var u=a.entity.isShowing,c=1===l.show[0];u!==c&&(l.show=n.toValue(u,l.show))}this.showsUpdated.removeAll()},l.prototype.contains=function(e){return this.updaters.contains(e.id)},l.prototype.getBoundingSphere=function(e,t){var r=this.primitive;if(!r.ready)return a.PENDING;var n=r.getGeometryInstanceAttributes(e);return!i(n)||!i(n.boundingSphere)||i(n.show)&&0===n.show[0]?a.FAILED:(n.boundingSphere.clone(t),a.DONE)},l.prototype.removeAllPrimitives=function(){var e=this.primitives,t=this.primitive;i(t)&&(e.remove(t),this.primitive=void 0,this.geometry.removeAll(),this.updaters.removeAll());var r=this.oldPrimitive;i(r)&&(e.remove(r),this.oldPrimitive=void 0)};var u=function(e,t,r){this._solidBatch=new l(e,!1,t,r),this._translucentBatch=new l(e,!0,t,r)};return u.prototype.add=function(e,t){var r=t.createFillGeometryInstance(e);255===r.attributes.color.value[3]?this._solidBatch.add(t,r):this._translucentBatch.add(t,r)},u.prototype.remove=function(e){this._solidBatch.remove(e)||this._translucentBatch.remove(e)},u.prototype.update=function(e){var t,r,i=this._solidBatch.update(e);i=this._translucentBatch.update(e)&&i;var n=this._solidBatch.itemsToRemove,o=n.length;if(o>0)for(t=0;o>t;t++)r=n[t],this._solidBatch.remove(r),this._translucentBatch.add(r,r.createFillGeometryInstance(e));n=this._translucentBatch.itemsToRemove;var a=n.length;if(a>0)for(t=0;a>t;t++)r=n[t],this._translucentBatch.remove(r),this._solidBatch.add(r,r.createFillGeometryInstance(e));return(o>0||a>0)&&(i=this._solidBatch.update(e)&&i,i=this._translucentBatch.update(e)&&i),i},u.prototype.getBoundingSphere=function(e,t){return this._solidBatch.contains(e)?this._solidBatch.getBoundingSphere(e,t):this._translucentBatch.contains(e)?this._translucentBatch.getBoundingSphere(e,t):a.FAILED},u.prototype.removeAllPrimitives=function(){this._solidBatch.removeAllPrimitives(),this._translucentBatch.removeAllPrimitives()},u}),r("DataSources/StaticGeometryPerMaterialBatch",["../Core/AssociativeArray","../Core/defined","../Core/ShowGeometryInstanceAttribute","../Scene/Primitive","./BoundingSphereState","./MaterialProperty"],function(e,t,r,i,n,o){"use strict";var a=function(t,r,i,n){this.primitives=t,this.appearanceType=r,this.materialProperty=i,this.closed=n,this.updaters=new e,this.createPrimitive=!0,this.primitive=void 0,this.oldPrimitive=void 0,this.geometry=new e,this.material=void 0,this.updatersWithAttributes=new e,this.attributes=new e,this.invalidated=!1,this.removeMaterialSubscription=i.definitionChanged.addEventListener(a.prototype.onMaterialChanged,this),this.subscriptions=new e,this.showsUpdated=new e};a.prototype.onMaterialChanged=function(){this.invalidated=!0},a.prototype.isMaterial=function(e){var r=this.materialProperty,i=e.fillMaterialProperty;return i===r?!0:t(r)?r.equals(i):!1},a.prototype.add=function(e,t){var r=t.entity.id;if(this.updaters.set(r,t),this.geometry.set(r,t.createFillGeometryInstance(e)),t.hasConstantFill&&t.fillMaterialProperty.isConstant){var i=this;this.subscriptions.set(r,t.entity.definitionChanged.addEventListener(function(e,r,n,o){"isShowing"===r&&i.showsUpdated.set(e.id,t)}))}else this.updatersWithAttributes.set(r,t);this.createPrimitive=!0},a.prototype.remove=function(e){var r=e.entity.id,i=this.updaters.remove(r);if(i){this.geometry.remove(r),this.updatersWithAttributes.remove(r);var n=this.subscriptions.get(r);t(n)&&(n(),this.subscriptions.remove(r))}return this.createPrimitive=i,i},a.prototype.update=function(e){var n,a,s=!0,l=this.primitive,u=this.primitives,c=this.geometry.values;if(this.createPrimitive){var h=c.length;if(h>0){for(t(l)&&(t(this.oldPrimitive)?u.remove(l):this.oldPrimitive=l),a=0;h>a;a++){var d=c[a],p=d.attributes;n=this.attributes.get(d.id.id),t(n)&&(t(p.show)&&(p.show.value=n.show),t(p.color)&&(p.color.value=n.color))}this.material=o.getValue(e,this.materialProperty,this.material),l=new i({asynchronous:!0,geometryInstances:c,appearance:new this.appearanceType({material:this.material,translucent:this.material.isTranslucent(),closed:this.closed})}),u.add(l),s=!1}else{t(l)&&(u.remove(l),l=void 0);var m=this.oldPrimitive;t(m)&&(u.remove(m),this.oldPrimitive=void 0)}this.attributes.removeAll(),this.primitive=l,this.createPrimitive=!1}else if(t(l)&&l.ready){t(this.oldPrimitive)&&(u.remove(this.oldPrimitive),this.oldPrimitive=void 0),this.material=o.getValue(e,this.materialProperty,this.material),this.primitive.appearance.material=this.material;var f=this.updatersWithAttributes.values,v=f.length;for(a=0;v>a;a++){var _=f[a],g=_.entity,y=this.geometry.get(g.id);n=this.attributes.get(y.id.id),t(n)||(n=l.getGeometryInstanceAttributes(y.id),this.attributes.set(y.id.id,n));var C=g.isShowing&&(_.hasConstantFill||_.isFilled(e)),E=1===n.show[0];C!==E&&(n.show=r.toValue(C,n.show))}this.updateShows(l)}else t(l)&&!l.ready&&(s=!1);return s},a.prototype.updateShows=function(e){for(var i=this.showsUpdated.values,n=i.length,o=0;n>o;o++){var a=i[o],s=a.entity,l=this.geometry.get(s.id),u=this.attributes.get(l.id.id);t(u)||(u=e.getGeometryInstanceAttributes(l.id),this.attributes.set(l.id.id,u));var c=s.isShowing,h=1===u.show[0];c!==h&&(u.show=r.toValue(c,u.show))}this.showsUpdated.removeAll()},a.prototype.contains=function(e){return this.updaters.contains(e.id)},a.prototype.getBoundingSphere=function(e,r){var i=this.primitive;if(!i.ready)return n.PENDING;var o=i.getGeometryInstanceAttributes(e);return!t(o)||!t(o.boundingSphere)||t(o.show)&&0===o.show[0]?n.FAILED:(o.boundingSphere.clone(r),n.DONE)},a.prototype.destroy=function(e){var r=this.primitive,i=this.primitives;t(r)&&i.remove(r);var n=this.oldPrimitive;t(n)&&i.remove(n),this.removeMaterialSubscription()};var s=function(e,t,r){this._items=[],this._primitives=e,this._appearanceType=t,this._closed=r};return s.prototype.add=function(e,t){for(var r=this._items,i=r.length,n=0;i>n;n++){var o=r[n];if(o.isMaterial(t))return void o.add(e,t)}var s=new a(this._primitives,this._appearanceType,t.fillMaterialProperty,this._closed);s.add(e,t),r.push(s)},s.prototype.remove=function(e){for(var t=this._items,r=t.length,i=r-1;i>=0;i--){var n=t[i];if(n.remove(e)){0===n.updaters.length&&(t.splice(i,1),n.destroy());break}}},s.prototype.update=function(e){var t,r=this._items,i=r.length;for(t=i-1;t>=0;t--){var n=r[t];if(n.invalidated){r.splice(t,1);for(var o=n.updaters.values,a=o.length,s=0;a>s;s++)this.add(e,o[s]);n.destroy()}}var l=!0;for(t=0;i>t;t++)l=r[t].update(e)&&l;return l},s.prototype.getBoundingSphere=function(e,t){for(var r=this._items,i=r.length,o=0;i>o;o++){var a=r[o];if(a.contains(e))return a.getBoundingSphere(e,t)}return n.FAILED},s.prototype.removeAllPrimitives=function(){for(var e=this._items,t=e.length,r=0;t>r;r++)e[r].destroy();this._items.length=0},s}),r("DataSources/StaticOutlineGeometryBatch",["../Core/AssociativeArray","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defined","../Core/ShowGeometryInstanceAttribute","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./BoundingSphereState"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t,r,i){this.translucent=r,this.primitives=t,this.createPrimitive=!1,this.primitive=void 0,this.oldPrimitive=void 0,this.geometry=new e,this.updaters=new e,this.updatersWithAttributes=new e,this.attributes=new e,this.itemsToRemove=[],this.width=i,this.subscriptions=new e,this.showsUpdated=new e};l.prototype.add=function(e,t){var r=e.entity.id;if(this.createPrimitive=!0,this.geometry.set(r,t),this.updaters.set(r,e),e.hasConstantOutline&&e.outlineColorProperty.isConstant){var i=this;this.subscriptions.set(r,e.entity.definitionChanged.addEventListener(function(t,r,n,o){"isShowing"===r&&i.showsUpdated.set(t.id,e)}))}else this.updatersWithAttributes.set(r,e)},l.prototype.remove=function(e){var t=e.entity.id;if(this.createPrimitive=this.geometry.remove(t)||this.createPrimitive,this.updaters.remove(t)){this.updatersWithAttributes.remove(t);var r=this.subscriptions.get(t);i(r)&&(r(),this.subscriptions.remove(t))}};var u=new t;l.prototype.update=function(e){var s,l,c=!0,h=0,d=this.primitive,p=this.primitives;if(this.createPrimitive){var m=this.geometry.values,f=m.length;if(f>0){for(i(d)&&(i(this.oldPrimitive)?p.remove(d):this.oldPrimitive=d),l=0;f>l;l++){var v=m[l],_=v.attributes;s=this.attributes.get(v.id.id),i(s)&&(i(_.show)&&(_.show.value=s.show),i(_.color)&&(_.color.value=s.color))}d=new a({asynchronous:!0,geometryInstances:m,appearance:new o({flat:!0,translucent:this.translucent,renderState:{lineWidth:this.width}})}),p.add(d),c=!1}else{i(d)&&(p.remove(d),d=void 0);var g=this.oldPrimitive;i(g)&&(p.remove(g),this.oldPrimitive=void 0)}this.attributes.removeAll(),this.primitive=d,this.createPrimitive=!1}else if(i(d)&&d.ready){i(this.oldPrimitive)&&(p.remove(this.oldPrimitive),this.oldPrimitive=void 0);var y=this.updatersWithAttributes.values,C=y.length;for(l=0;C>l;l++){var E=y[l],S=this.geometry.get(E.entity.id);if(s=this.attributes.get(S.id.id),i(s)||(s=d.getGeometryInstanceAttributes(S.id),this.attributes.set(S.id.id,s)),!E.outlineColorProperty.isConstant){var w=E.outlineColorProperty;w.getValue(e,u),t.equals(s._lastColor,u)||(s._lastColor=t.clone(u,s._lastColor),s.color=r.toValue(u,s.color),(this.translucent&&255===s.color[3]||!this.translucent&&255!==s.color[3])&&(this.itemsToRemove[h++]=E))}var T=E.entity.isShowing&&(E.hasConstantOutline||E.isOutlineVisible(e)),b=1===s.show[0];T!==b&&(s.show=n.toValue(T,s.show))}this.updateShows(d)}else i(d)&&!d.ready&&(c=!1);return this.itemsToRemove.length=h,c},l.prototype.updateShows=function(e){for(var t=this.showsUpdated.values,r=t.length,o=0;r>o;o++){var a=t[o],s=this.geometry.get(a.entity.id),l=this.attributes.get(s.id.id);i(l)||(l=e.getGeometryInstanceAttributes(s.id),this.attributes.set(s.id.id,l));var u=a.entity.isShowing,c=1===l.show[0];u!==c&&(l.show=n.toValue(u,l.show))}this.showsUpdated.removeAll()},l.prototype.contains=function(e){return this.updaters.contains(e.id)},l.prototype.getBoundingSphere=function(e,t){var r=this.primitive;if(!r.ready)return s.PENDING;var n=r.getGeometryInstanceAttributes(e);return!i(n)||!i(n.boundingSphere)||i(n.show)&&0===n.show[0]?s.FAILED:(n.boundingSphere.clone(t),s.DONE)},l.prototype.removeAllPrimitives=function(){var e=this.primitives,t=this.primitive;i(t)&&(e.remove(t),this.primitive=void 0,this.geometry.removeAll(),this.updaters.removeAll());var r=this.oldPrimitive;i(r)&&(e.remove(r),this.oldPrimitive=void 0)};var c=function(t,r){this._primitives=t,this._scene=r,this._solidBatches=new e,this._translucentBatches=new e};return c.prototype.add=function(e,t){var r,n,o=t.createOutlineGeometryInstance(e),a=this._scene.clampLineWidth(t.outlineWidth);255===o.attributes.color.value[3]?(r=this._solidBatches,n=r.get(a),i(n)||(n=new l(this._primitives,!1,a),r.set(a,n)),n.add(t,o)):(r=this._translucentBatches,n=r.get(a),i(n)||(n=new l(this._primitives,!0,a),r.set(a,n)),n.add(t,o))},c.prototype.remove=function(e){var t,r=this._solidBatches.values,i=r.length;for(t=0;i>t;t++)if(r[t].remove(e))return;var n=this._translucentBatches.values,o=n.length;for(t=0;o>t;t++)if(n[t].remove(e))return},c.prototype.update=function(e){var t,r,i,n,o,a=this._solidBatches.values,s=a.length,l=this._translucentBatches.values,u=l.length,c=!0,h=!1;do{for(h=!1,r=0;s>r;r++){n=a[r],c=n.update(e),o=n.itemsToRemove;var d=o.length;if(d>0)for(h=!0,t=0;d>t;t++)i=o[t],n.remove(i),this.add(e,i)}for(r=0;u>r;r++){n=l[r],c=n.update(e),o=n.itemsToRemove;var p=o.length;if(p>0)for(h=!0,t=0;p>t;t++)i=o[t],n.remove(i),this.add(e,i)}}while(h);return c},c.prototype.getBoundingSphere=function(e,t){var r,i=this._solidBatches.values,n=i.length;for(r=0;n>r;r++){var o=i[r];if(o.contains(e))return o.getBoundingSphere(e,t)}var a=this._translucentBatches.values,l=a.length;for(r=0;l>r;r++){var u=a[r];if(u.contains(e))return u.getBoundingSphere(e,t)}return s.FAILED},c.prototype.removeAllPrimitives=function(){var e,t=this._solidBatches.values,r=t.length;for(e=0;r>e;e++)t[e].removeAllPrimitives();var i=this._translucentBatches.values,n=i.length;for(e=0;n>e;e++)i[e].removeAllPrimitives()},c}),r("DataSources/GeometryVisualizer",["../Core/AssociativeArray","../Core/BoundingSphere","../Core/defined","../Core/destroyObject","../Core/DeveloperError","./BoundingSphereState","./ColorMaterialProperty","./StaticGeometryColorBatch","./StaticGeometryPerMaterialBatch","./StaticOutlineGeometryBatch"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){for(var r=e._batches,i=r.length,n=0;i>n;n++)r[n].remove(t)}function h(e,t,r){return r.isDynamic?void e._dynamicBatch.add(t,r):(r.outlineEnabled&&e._outlineBatch.add(t,r),void(r.fillEnabled&&(r.isClosed?r.fillMaterialProperty instanceof a?e._closedColorBatch.add(t,r):e._closedMaterialBatch.add(t,r):r.fillMaterialProperty instanceof a?e._openColorBatch.add(t,r):e._openMaterialBatch.add(t,r))))}var d=[],p=function(t){this._primitives=t,this._dynamicUpdaters=new e};p.prototype.add=function(e,t){this._dynamicUpdaters.set(t.entity.id,t.createDynamicUpdater(this._primitives))},p.prototype.remove=function(e){var t=e.entity.id,i=this._dynamicUpdaters.get(t);r(i)&&(this._dynamicUpdaters.remove(t),i.destroy())},p.prototype.update=function(e){for(var t=this._dynamicUpdaters.values,r=0,i=t.length;i>r;r++)t[r].update(e);return!0},p.prototype.removeAllPrimitives=function(){for(var e=this._dynamicUpdaters.values,t=0,r=e.length;r>t;t++)e[t].destroy();this._dynamicUpdaters.removeAll()},p.prototype.getBoundingSphere=function(e,t){var i=this._dynamicUpdaters.get(e.id);return r(i)&&r(i.getBoundingSphere)?i.getBoundingSphere(e,t):o.FAILED};var m=function(t,r,i){this._type=t;var n=r.primitives;this._scene=r,this._primitives=n,this._entityCollection=void 0,this._addedObjects=new e,this._removedObjects=new e,this._changedObjects=new e,this._outlineBatch=new u(n,r),this._closedColorBatch=new s(n,t.perInstanceColorAppearanceType,!0),this._closedMaterialBatch=new l(n,t.materialAppearanceType,!0),this._openColorBatch=new s(n,t.perInstanceColorAppearanceType,!1),this._openMaterialBatch=new l(n,t.materialAppearanceType,!1),this._dynamicBatch=new p(n),this._batches=[this._closedColorBatch,this._closedMaterialBatch,this._openColorBatch,this._openMaterialBatch,this._dynamicBatch,this._outlineBatch],this._subscriptions=new e,this._updaters=new e,this._entityCollection=i,i.collectionChanged.addEventListener(m.prototype._onCollectionChanged,this),this._onCollectionChanged(i,i.values,d)};m.prototype.update=function(e){var t,r,i,n,o=this._addedObjects,a=o.values,s=this._removedObjects,l=s.values,u=this._changedObjects,d=u.values;for(t=d.length-1;t>-1;t--)r=d[t],i=r.id,n=this._updaters.get(i),n.entity===r?(c(this,n),h(this,e,n)):(l.push(r),a.push(r));for(t=l.length-1;t>-1;t--)r=l[t],i=r.id,n=this._updaters.get(i),c(this,n),n.destroy(),this._updaters.remove(i),this._subscriptions.get(i)(),this._subscriptions.remove(i);for(t=a.length-1;t>-1;t--)r=a[t],i=r.id,n=new this._type(r,this._scene),this._updaters.set(i,n),h(this,e,n),this._subscriptions.set(i,n.geometryChanged.addEventListener(m._onGeometryChanged,this));o.removeAll(),s.removeAll(),u.removeAll();var p=!0,f=this._batches,v=f.length;for(t=0;v>t;t++)p=f[t].update(e)&&p;return p};var f=[],v=new t;return m.prototype.getBoundingSphere=function(e,r){for(var i=f,n=v,a=0,s=o.DONE,l=this._batches,u=l.length,c=0;u>c;c++){if(s=l[c].getBoundingSphere(e,n),s===o.PENDING)return o.PENDING;s===o.DONE&&(i[a]=t.clone(n,i[a]),a++)}return 0===a?o.FAILED:(i.length=a,t.fromBoundingSpheres(i,r),o.DONE)},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){this._entityCollection.collectionChanged.removeEventListener(m.prototype._onCollectionChanged,this),this._addedObjects.removeAll(),this._removedObjects.removeAll();var e,t=this._batches,r=t.length;for(e=0;r>e;e++)t[e].removeAllPrimitives();var n=this._subscriptions.values;for(r=n.length,e=0;r>e;e++)n[e]();return this._subscriptions.removeAll(),i(this)},m._onGeometryChanged=function(e){var t=this._removedObjects,i=this._changedObjects,n=e.entity,o=n.id;r(t.get(o))||r(i.get(o))||i.set(o,n)},m.prototype._onCollectionChanged=function(e,t,r){var i,n,o,a=this._addedObjects,s=this._removedObjects,l=this._changedObjects;for(i=r.length-1;i>-1;i--)o=r[i],n=o.id,a.remove(n)||(s.set(n,o),l.remove(n));for(i=t.length-1;i>-1;i--)o=t[i],n=o.id,s.remove(n)?l.set(n,o):a.set(n,o)},m}),r("Scene/Label",["../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/NearFarScalar","./Billboard","./HeightReference","./HorizontalOrigin","./LabelStyle","./VerticalOrigin"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e){e._rebindAllGlyphs||e._repositionAllGlyphs||e._labelCollection._labelsToUpdate.push(e),e._rebindAllGlyphs=!0}function m(e){e._rebindAllGlyphs||e._repositionAllGlyphs||e._labelCollection._labelsToUpdate.push(e),e._repositionAllGlyphs=!0}var f=function(n,o){n=i(n,i.EMPTY_OBJECT),this._text=i(n.text,""),this._show=i(n.show,!0),this._font=i(n.font,"30px sans-serif"),this._fillColor=r.clone(i(n.fillColor,r.WHITE)),this._outlineColor=r.clone(i(n.outlineColor,r.BLACK)),this._outlineWidth=i(n.outlineWidth,1),this._style=i(n.style,h.FILL),this._verticalOrigin=i(n.verticalOrigin,d.BOTTOM),this._horizontalOrigin=i(n.horizontalOrigin,c.LEFT),this._pixelOffset=e.clone(i(n.pixelOffset,e.ZERO)),this._eyeOffset=t.clone(i(n.eyeOffset,t.ZERO)),this._position=t.clone(i(n.position,t.ZERO)),this._scale=i(n.scale,1),this._id=n.id,this._translucencyByDistance=n.translucencyByDistance,this._pixelOffsetScaleByDistance=n.pixelOffsetScaleByDistance,this._heightReference=i(n.heightReference,u.NONE),this._labelCollection=o,this._glyphs=[],this._rebindAllGlyphs=!0,this._repositionAllGlyphs=!0,this._actualClampedPosition=void 0,this._removeCallbackFunc=void 0,this._mode=void 0,this._updateClamping()};return o(f.prototype,{show:{get:function(){return this._show},set:function(e){if(this._show!==e){this._show=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.show=e)}}}},position:{get:function(){return this._position},set:function(e){var r=this._position;if(!t.equals(r,e))if(t.clone(e,r),this._heightReference===u.NONE)for(var i=this._glyphs,o=0,a=i.length;a>o;o++){var s=i[o];n(s.billboard)&&(s.billboard.position=e)}else this._updateClamping()}},heightReference:{get:function(){return this._heightReference},set:function(e){e!==this._heightReference&&(this._heightReference=e,this._updateClamping())}},text:{get:function(){return this._text},set:function(e){this._text!==e&&(this._text=e,p(this))}},font:{get:function(){return this._font},set:function(e){this._font!==e&&(this._font=e,p(this))}},fillColor:{get:function(){return this._fillColor},set:function(e){var t=this._fillColor;r.equals(t,e)||(r.clone(e,t),p(this))}},outlineColor:{get:function(){return this._outlineColor},set:function(e){var t=this._outlineColor;r.equals(t,e)||(r.clone(e,t),p(this))}},outlineWidth:{get:function(){return this._outlineWidth},set:function(e){this._outlineWidth!==e&&(this._outlineWidth=e,p(this))}},style:{get:function(){return this._style},set:function(e){this._style!==e&&(this._style=e,p(this))}},pixelOffset:{get:function(){return this._pixelOffset},set:function(t){var r=this._pixelOffset;if(!e.equals(r,t)){e.clone(t,r);for(var i=this._glyphs,o=0,a=i.length;a>o;o++){var s=i[o];n(s.billboard)&&(s.billboard.pixelOffset=t)}}}},translucencyByDistance:{get:function(){return this._translucencyByDistance},set:function(e){var t=this._translucencyByDistance;if(!s.equals(t,e)){this._translucencyByDistance=s.clone(e,t);for(var r=this._glyphs,i=0,o=r.length;o>i;i++){var a=r[i];n(a.billboard)&&(a.billboard.translucencyByDistance=e)}}}},pixelOffsetScaleByDistance:{get:function(){return this._pixelOffsetScaleByDistance},set:function(e){var t=this._pixelOffsetScaleByDistance;if(!s.equals(t,e)){this._pixelOffsetScaleByDistance=s.clone(e,t);for(var r=this._glyphs,i=0,o=r.length;o>i;i++){var a=r[i];n(a.billboard)&&(a.billboard.pixelOffsetScaleByDistance=e)}}}},eyeOffset:{get:function(){return this._eyeOffset},set:function(e){var r=this._eyeOffset;if(!t.equals(r,e)){t.clone(e,r);for(var i=this._glyphs,o=0,a=i.length;a>o;o++){var s=i[o];n(s.billboard)&&(s.billboard.eyeOffset=e)}}}},horizontalOrigin:{get:function(){return this._horizontalOrigin},set:function(e){this._horizontalOrigin!==e&&(this._horizontalOrigin=e,m(this))}},verticalOrigin:{get:function(){return this._verticalOrigin},set:function(e){if(this._verticalOrigin!==e){this._verticalOrigin=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.verticalOrigin=e)}m(this)}}},scale:{get:function(){return this._scale},set:function(e){if(this._scale!==e){this._scale=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.scale=e)}m(this)}}},id:{get:function(){return this._id},set:function(e){if(this._id!==e){this._id=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.id=e)}}}},_clampedPosition:{get:function(){return this._actualClampedPosition},set:function(e){this._actualClampedPosition=t.clone(e,this._actualClampedPosition);for(var r=this._glyphs,i=0,o=r.length;o>i;i++){var a=r[i];n(a.billboard)&&(a.billboard.position=e)}}}}),f.prototype._updateClamping=function(){l._updateClamping(this._labelCollection,this)},f.prototype.computeScreenSpacePosition=function(t,r){n(r)||(r=new e);var i=this._labelCollection,o=i.modelMatrix,a=l._computeActualPosition(this,this._position,t.frameState,o),s=l._computeScreenSpacePosition(o,a,this._eyeOffset,this._pixelOffset,t,r);return s.y=t.canvas.clientHeight-s.y,s},f.prototype.equals=function(i){return this===i||n(i)&&this._show===i._show&&this._scale===i._scale&&this._style===i._style&&this._verticalOrigin===i._verticalOrigin&&this._horizontalOrigin===i._horizontalOrigin&&this._text===i._text&&this._font===i._font&&t.equals(this._position,i._position)&&r.equals(this._fillColor,i._fillColor)&&r.equals(this._outlineColor,i._outlineColor)&&e.equals(this._pixelOffset,i._pixelOffset)&&t.equals(this._eyeOffset,i._eyeOffset)&&s.equals(this._translucencyByDistance,i._translucencyByDistance)&&s.equals(this._pixelOffsetScaleByDistance,i._pixelOffsetScaleByDistance)&&this._id===i._id},f.prototype.isDestroyed=function(){return!1},f}),r("Scene/LabelCollection",["../Core/Cartesian2","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Matrix4","../Core/writeTextToCanvas","./BillboardCollection","./HorizontalOrigin","./Label","./LabelStyle","./TextureAtlas","./VerticalOrigin"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(){this.textureInfo=void 0,this.dimensions=void 0,this.billboard=void 0}function f(e,t,r){this.labelCollection=e,this.index=t,this.dimensions=r}function v(e,t,r,i,n,o,a){return S.font=t,S.fillColor=r,S.strokeColor=i,S.strokeWidth=n,a===p.BOTTOM?S.textBaseline="bottom":a===p.TOP?S.textBaseline="top":S.textBaseline="middle",S.fill=o===h.FILL||o===h.FILL_AND_OUTLINE,S.stroke=o===h.OUTLINE||o===h.FILL_AND_OUTLINE,s(e,S)}function _(e,t){t.textureInfo=void 0,t.dimensions=void 0;var i=t.billboard;r(i)&&(i.show=!1,i.image=void 0,e._spareBillboards.push(i),t.billboard=void 0)}function g(e,t,r,i){e.addImage(t,r).then(function(e,t){i.index=e})}function y(e,t){var i,n,o,a=t._text,s=a.length,l=t._glyphs,c=l.length;if(c>s)for(n=s;c>n;++n)_(e,l[n]);l.length=s;var h=e._glyphTextureCache;for(o=0;s>o;++o){var d=a.charAt(o),p=t._font,y=t._fillColor,C=t._outlineColor,E=t._outlineWidth,S=t._style,w=t._verticalOrigin,T=JSON.stringify([d,p,y.toRgba(),C.toRgba(),E,+S,+w]),b=h[T];if(!r(b)){var x=v(d,p,y,C,E,S,w);b=new f(e,-1,x.dimensions),h[T]=b,x.width>0&&x.height>0&&g(e._textureAtlas,T,x,b)}if(i=l[o],r(i)?-1===b.index?_(e,i):r(i.textureInfo)&&(i.textureInfo=void 0):(i=new m, +l[o]=i),i.textureInfo=b,i.dimensions=b.dimensions,-1!==b.index){var P=i.billboard;r(P)||(P=e._spareBillboards.length>0?e._spareBillboards.pop():e._billboardCollection.add({collection:e}),i.billboard=P),P.show=t._show,P.position=t._position,P.eyeOffset=t._eyeOffset,P.pixelOffset=t._pixelOffset,P.horizontalOrigin=u.LEFT,P.verticalOrigin=t._verticalOrigin,P.scale=t._scale,P.pickPrimitive=t,P.id=t._id,P.image=T,P.translucencyByDistance=t._translucencyByDistance,P.pixelOffsetScaleByDistance=t._pixelOffsetScaleByDistance}}t._repositionAllGlyphs=!0}function C(e,t){var i,n,o=e._glyphs,a=0,s=0,l=0,c=o.length;for(l=0;c>l;++l)i=o[l],n=i.dimensions,a+=n.computedWidth,s=Math.max(s,n.height);var h=e._scale,d=e._horizontalOrigin,m=0;d===u.CENTER?m-=a/2*h:d===u.RIGHT&&(m-=a*h),w.x=m*t,w.y=0;var f=e._verticalOrigin;for(l=0;c>l;++l)i=o[l],n=i.dimensions,f===p.BOTTOM||n.height===s?w.y=-n.descent*h:f===p.TOP?w.y=-(s-n.height)*h-n.descent*h:f===p.CENTER&&(w.y=-(s-n.height)/2*h-n.descent*h),w.y*=t,r(i.billboard)&&i.billboard._setTranslate(w),w.x+=n.computedWidth*h*t}function E(e,t){for(var i=t._glyphs,o=0,a=i.length;a>o;++o)_(e,i[o]);t._labelCollection=void 0,r(t._removeCallbackFunc)&&t._removeCallbackFunc(),n(t)}var S={},w=new e,T=function(e){e=t(e,t.EMPTY_OBJECT),this._scene=e.scene,this._textureAtlas=void 0,this._billboardCollection=new l({scene:this._scene}),this._billboardCollection.destroyTextureAtlas=!1,this._spareBillboards=[],this._glyphTextureCache={},this._labels=[],this._labelsToUpdate=[],this._totalGlyphCount=0,this._resolutionScale=void 0,this.modelMatrix=a.clone(t(e.modelMatrix,a.IDENTITY)),this.debugShowBoundingVolume=t(e.debugShowBoundingVolume,!1)};return i(T.prototype,{length:{get:function(){return this._labels.length}}}),T.prototype.add=function(e){var t=new c(e,this);return this._labels.push(t),this._labelsToUpdate.push(t),t},T.prototype.remove=function(e){if(r(e)&&e._labelCollection===this){var t=this._labels.indexOf(e);if(-1!==t)return this._labels.splice(t,1),E(this,e),!0}return!1},T.prototype.removeAll=function(){for(var e=this._labels,t=0,r=e.length;r>t;++t)E(this,e[t]);e.length=0},T.prototype.contains=function(e){return r(e)&&e._labelCollection===this},T.prototype.get=function(e){return this._labels[e]},T.prototype.update=function(e){var t=this._billboardCollection;t.modelMatrix=this.modelMatrix,t.debugShowBoundingVolume=this.debugShowBoundingVolume;var i=e.context;r(this._textureAtlas)||(this._textureAtlas=new d({context:i}),t.textureAtlas=this._textureAtlas);var n=i.uniformState,o=n.resolutionScale,a=this._resolutionScale!==o;this._resolutionScale=o;var s;s=a?this._labels:this._labelsToUpdate;for(var l=s.length,u=0;l>u;++u){var c=s[u];if(!c.isDestroyed()){var h=c._glyphs.length;c._rebindAllGlyphs&&(y(this,c),c._rebindAllGlyphs=!1),(a||c._repositionAllGlyphs)&&(C(c,o),c._repositionAllGlyphs=!1);var p=c._glyphs.length-h;this._totalGlyphCount+=p}}this._labelsToUpdate.length=0,t.update(e)},T.prototype.isDestroyed=function(){return!1},T.prototype.destroy=function(){return this.removeAll(),this._billboardCollection=this._billboardCollection.destroy(),this._textureAtlas=this._textureAtlas&&this._textureAtlas.destroy(),n(this)},T}),r("DataSources/LabelVisualizer",["../Core/AssociativeArray","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/NearFarScalar","../Scene/HorizontalOrigin","../Scene/LabelCollection","../Scene/LabelStyle","../Scene/VerticalOrigin","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){if(n(e)){var r=e.label;n(r)&&(t.push(e.index),r.show=!1,e.label=void 0,e.index=-1)}}var f=1,v="30px sans-serif",_=c.FILL,g=i.WHITE,y=i.BLACK,C=1,E=t.ZERO,S=r.ZERO,w=l.CENTER,T=h.CENTER,b=new r,x=new i,P=new i,A=new r,I=new t,M=new s,D=new s,R=function(e){this.entity=e,this.label=void 0,this.index=void 0},O=function(t,r){r.collectionChanged.addEventListener(O.prototype._onCollectionChanged,this),this._scene=t,this._unusedIndexes=[],this._labelCollection=void 0,this._entityCollection=r,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return O.prototype.update=function(e){for(var t=this._items.values,r=this._unusedIndexes,i=0,o=t.length;o>i;i++){var a,s=t[i],l=s.entity,c=l._label,h=s.label,d=l.isShowing&&l.isAvailable(e)&&p.getValueOrDefault(c._show,e,!0);if(d&&(b=p.getValueOrUndefined(l._position,e,b),a=p.getValueOrUndefined(c._text,e),d=n(b)&&n(a)),d){if(!n(h)){var R=this._labelCollection;n(R)||(R=new u,this._labelCollection=R,this._scene.primitives.add(R));var O=r.length;if(O>0){var N=r.pop();s.index=N,h=R.get(N)}else h=R.add(),s.index=R.length-1;h.id=l,s.label=h}h.show=!0,h.position=b,h.text=a,h.scale=p.getValueOrDefault(c._scale,e,f),h.font=p.getValueOrDefault(c._font,e,v),h.style=p.getValueOrDefault(c._style,e,_),h.fillColor=p.getValueOrDefault(c._fillColor,e,g,x),h.outlineColor=p.getValueOrDefault(c._outlineColor,e,y,P),h.outlineWidth=p.getValueOrDefault(c._outlineWidth,e,C),h.pixelOffset=p.getValueOrDefault(c._pixelOffset,e,E,I),h.eyeOffset=p.getValueOrDefault(c._eyeOffset,e,S,A),h.horizontalOrigin=p.getValueOrDefault(c._horizontalOrigin,e,w),h.verticalOrigin=p.getValueOrDefault(c._verticalOrigin,e,T),h.translucencyByDistance=p.getValueOrUndefined(c._translucencyByDistance,e,M),h.pixelOffsetScaleByDistance=p.getValueOrUndefined(c._pixelOffsetScaleByDistance,e,D)}else m(s,r)}return!0},O.prototype.getBoundingSphere=function(e,t){var i=this._items.get(e.id);return n(i)&&n(i.label)?(t.center=r.clone(i.label.position,t.center),t.radius=0,d.DONE):d.FAILED},O.prototype.isDestroyed=function(){return!1},O.prototype.destroy=function(){return this._entityCollection.collectionChanged.removeEventListener(O.prototype._onCollectionChanged,this),n(this._labelCollection)&&this._scene.primitives.remove(this._labelCollection),o(this)},O.prototype._onCollectionChanged=function(e,t,r,i){var o,a,s=this._unusedIndexes,l=this._items;for(o=t.length-1;o>-1;o--)a=t[o],n(a._label)&&n(a._position)&&l.set(a.id,new R(a));for(o=i.length-1;o>-1;o--)a=i[o],n(a._label)&&n(a._position)?l.contains(a.id)||l.set(a.id,new R(a)):(m(l.get(a.id),s),l.remove(a.id));for(o=r.length-1;o>-1;o--)a=r[o],m(l.get(a.id),s),l.remove(a.id)},O}),r("ThirdParty/gltfDefaults",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/Quaternion","../Renderer/WebGLConstants"],function(e,t,r,i,n){"use strict";function o(e){r(e.accessors)||(e.accessors={});var i=e.accessors;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];o.byteStride=t(o.byteStride,0)}}function a(e){r(e.animations)||(e.animations={});var i=e.animations;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];r(o.channels)||(o.channels=[]),r(o.parameters)||(o.parameters={}),r(o.samplers)||(o.samplers={});var a=i.samplers;for(var s in a)if(a.hasOwnProperty(s)){var l=a[s];l.interpolation=t(l.interpolation,"LINEAR")}}}function s(e){r(e.asset)||(e.asset={});var i=e.asset;r(i.profile)&&"string"!=typeof i.profile||(i.profile={});var n=i.profile;i.premultipliedAlpha=t(i.premultipliedAlpha,!1),n.api=t(n.api,"WebGL"),n.version=t(n.version,"1.0.2"),r(e.version)&&(i.version=t(i.version,e.version),delete e.version),"number"==typeof i.version&&(i.version=i.version.toFixed(1).toString())}function l(e){r(e.buffers)||(e.buffers={});var i=e.buffers;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];o.type=t(o.type,"arraybuffer")}}function u(e){r(e.bufferViews)||(e.bufferViews={})}function c(e){r(e.cameras)||(e.cameras={})}function h(e){r(e.images)||(e.images={})}function d(e){r(e.extensions)||(e.extensions={});var i=e.extensions;r(i.KHR_materials_common)||(i.KHR_materials_common={});var n=i.KHR_materials_common;r(e.lights)?(n.lights=e.lights,delete e.lights):r(n.lights)||(n.lights={});var o=n.lights;for(var a in o)if(o.hasOwnProperty(a)){var s=o[a];if("ambient"===s.type){r(s.ambient)||(s.ambient={});var l=s.ambient;r(l.color)||(l.color=[1,1,1])}else if("directional"===s.type){r(s.directional)||(s.directional={});var u=s.directional;r(u.color)||(u.color=[1,1,1])}else if("point"===s.type){r(s.point)||(s.point={});var c=s.point;r(c.color)||(c.color=[1,1,1]),c.constantAttenuation=t(c.constantAttenuation,1),c.linearAttenuation=t(c.linearAttenuation,0),c.quadraticAttenuation=t(c.quadraticAttenuation,0)}else if("spot"===s.type){r(s.spot)||(s.spot={});var h=s.spot;r(h.color)||(h.color=[1,1,1]),h.constantAttenuation=t(h.constantAttenuation,1),h.fallOffAngle=t(h.fallOffAngle,3.14159265),h.fallOffExponent=t(h.fallOffExponent,0),h.linearAttenuation=t(h.linearAttenuation,0),h.quadraticAttenuation=t(h.quadraticAttenuation,0)}}}function p(e){r(e.materials)||(e.materials={});var t=e.materials;for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a=o.instanceTechnique;if(r(a)&&(o.technique=a.technique,o.values=a.values,delete o.instanceTechnique),!r(o.extensions))if(r(o.technique))r(o.values)||(o.values={});else{delete o.values,o.extensions={KHR_materials_common:{technique:"CONSTANT",transparent:!1,values:{emission:{type:n.FLOAT_VEC4,value:[.5,.5,.5,1]}}}},r(e.extensionsUsed)||(e.extensionsUsed=[]);var s=e.extensionsUsed;-1===s.indexOf("KHR_materials_common")&&s.push("KHR_materials_common")}}}function m(e){r(e.meshes)||(e.meshes={});var i=e.meshes;for(var o in i)if(i.hasOwnProperty(o)){var a=i[o];r(a.primitives)||(a.primitives=[]);for(var s=a.primitives.length,l=s.length,u=0;l>u;++u){var c=s[u];r(c.attributes)||(c.attributes={});var h=t(c.primitive,n.TRIANGLES);c.mode=t(c.mode,h)}}}function f(t){r(t.nodes)||(t.nodes={});var n=t.nodes,o=parseFloat(t.asset.version)<1,a=new e,s=new i;for(var l in n)if(n.hasOwnProperty(l)){var u=n[l];if(r(u.children)||(u.children=[]),o&&r(u.rotation)){var c=u.rotation;e.fromArray(c,0,a),i.fromAxisAngle(a,c[3],s),u.rotation=[s.x,s.y,s.z,s.w]}r(u.matrix)||(r(u.translation)||r(u.rotation)||r(u.scale)?(r(u.translation)||(u.translation=[0,0,0]),r(u.rotation)||(u.rotation=[0,0,0,1]),r(u.scale)||(u.scale=[1,1,1])):u.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);var h=u.instanceSkin;r(h)&&(u.skeletons=h.skeletons,u.skin=h.skin,u.meshes=h.meshes,delete u.instanceSkin)}}function v(e){r(e.programs)||(e.programs={});var t=e.programs;for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];r(n.attributes)||(n.attributes=[])}}function _(e){r(e.samplers)||(e.samplers={});var i=e.samplers;for(var o in i)if(i.hasOwnProperty(o)){var a=i[o];a.magFilter=t(a.magFilter,n.LINEAR),a.minFilter=t(a.minFilter,n.NEAREST_MIPMAP_LINEAR),a.wrapS=t(a.wrapS,n.REPEAT),a.wrapT=t(a.wrapT,n.REPEAT)}}function g(e){r(e.scenes)||(e.scenes={});var t=e.scenes;for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];r(n.node)||(n.node=[])}}function y(e){r(e.shaders)||(e.shaders={})}function C(e){r(e.skins)||(e.skins={});var t=e.skins;for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];r(n.bindShapeMatrix)&&(n.bindShapeMatrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1])}}function E(e){r(e.enable)||(e.enable=[]),r(e.disable)||(e.disable=[])}function S(e){r(e.techniques)||(e.techniques={});var i=e.techniques;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];r(o.parameters)||(o.parameters={});var a=o.parameters;for(var s in a){var l=a[s];l.node=t(l.node,l.source),l.source=void 0}var u=o.passes;if(r(u)){var c=t(o.pass,"defaultPass");if(u.hasOwnProperty(c)){var h=u[c],d=h.instanceProgram;o.attributes=t(o.attributes,d.attributes),o.program=t(o.program,d.program),o.uniforms=t(o.uniforms,d.uniforms),o.states=t(o.states,h.states)}o.passes=void 0,o.pass=void 0}r(o.attributes)||(o.attributes={}),r(o.uniforms)||(o.uniforms={}),r(o.states)||(o.states={}),E(o.states)}}function w(e){r(e.textures)||(e.textures={});var i=e.textures;for(var o in i)if(i.hasOwnProperty(o)){var a=i[o];a.format=t(a.format,n.RGBA),a.internalFormat=t(a.internalFormat,a.format),a.target=t(a.target,n.TEXTURE_2D),a.type=t(a.type,n.UNSIGNED_BYTE)}}var T=function(e){return r(e)?(r(e.allExtensions)&&(e.extensionsUsed=e.allExtensions,e.allExtensions=void 0),e.extensionsUsed=t(e.extensionsUsed,[]),o(e),a(e),s(e),l(e),u(e),c(e),h(e),d(e),p(e),m(e),f(e),v(e),_(e),g(e),y(e),C(e),S(e),w(e),e):void 0};return T}),r("Scene/getModelAccessor",["../Core/ComponentDatatype"],function(e){"use strict";var t={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},r=function(r){var i=r.componentType,n=t[r.type];return{componentsPerAttribute:n,createArrayBufferView:function(t,r,o){return e.createArrayBufferView(i,t,r,n*o)}}};return r}),r("Scene/ModelAnimationCache",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/LinearSpline","../Core/Matrix4","../Core/Quaternion","../Core/QuaternionSpline","../Renderer/WebGLConstants","./getModelAccessor"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,r){var i=e.gltf,n=i.buffers,o=i.bufferViews,a=o[r.bufferView],s=n[a.buffer],u=a.byteOffset+r.byteOffset,c=r.count*l(r).componentsPerAttribute;return e.cacheKey+"//"+t(s.path,"")+"/"+u+"/"+c}function c(e,t,r){return e.cacheKey+"//"+t+"/"+r}var h=function(){},d={},p=new e;h.getAnimationParameterValues=function(t,i){var n=u(t,i),a=d[n];if(!r(a)){var c,h=t._loadResources,m=t.gltf,f=parseFloat(m.asset.version)<1,v=m.bufferViews,_=v[i.bufferView],g=i.componentType,y=i.type,C=i.count,E=h.getBuffer(_),S=l(i).createArrayBufferView(E.buffer,E.byteOffset+i.byteOffset,C);if(g===s.FLOAT&&"SCALAR"===y)a=S;else if(g===s.FLOAT&&"VEC3"===y)for(a=new Array(C),c=0;C>c;++c)a[c]=e.fromArray(S,3*c);else if(g===s.FLOAT&&"VEC4"===y)for(a=new Array(C),c=0;C>c;++c){var w=4*c;f?a[c]=o.fromAxisAngle(e.fromArray(S,w,p),S[w+3]):a[c]=o.unpack(S,w)}r(t.cacheKey)&&(d[n]=a)}return a};var m={},f=function(e){this._value=e};f.prototype.evaluate=function(e,t){return this._value},h.getAnimationSpline=function(e,t,n,o,l,u){var h=c(e,t,o),d=m[h];if(!r(d)){var p=u[l.input],v=e.gltf.accessors[n.parameters[l.output]],_=u[l.output];if(1===p.length&&1===_.length)d=new f(_[0]);else{var g=v.componentType,y=v.type;"LINEAR"===l.interpolation&&(g===s.FLOAT&&"VEC3"===y?d=new i({times:p,points:_}):g===s.FLOAT&&"VEC4"===y&&(d=new a({times:p,points:_})))}r(e.cacheKey)&&(m[h]=d)}return d};var v={};return h.getSkinInverseBindMatrices=function(e,t){var i=u(e,t),o=v[i];if(!r(o)){var a=e._loadResources,c=e.gltf,h=c.bufferViews,d=h[t.bufferView],p=t.componentType,m=t.type,f=t.count,_=a.getBuffer(d),g=l(t).createArrayBufferView(_.buffer,_.byteOffset+t.byteOffset,f);if(o=new Array(f),p===s.FLOAT&&"MAT4"===m)for(var y=0;f>y;++y)o[y]=n.fromArray(g,16*y);v[i]=o}return o},h}),r("Scene/ModelAnimationLoop",["../Core/freezeObject"],function(e){"use strict";var t={NONE:0,REPEAT:1,MIRRORED_REPEAT:2};return e(t)}),r("Scene/ModelAnimationState",["../Core/freezeObject"],function(e){"use strict";return e({STOPPED:0,ANIMATING:1})}),r("Scene/ModelAnimation",["../Core/defaultValue","../Core/defineProperties","../Core/Event","../Core/JulianDate","./ModelAnimationLoop","./ModelAnimationState"],function(e,t,r,i,n,o){"use strict";var a=function(t,a,s){this._name=t.name,this._startTime=i.clone(t.startTime),this._delay=e(t.delay,0),this._stopTime=t.stopTime,this.removeOnStop=e(t.removeOnStop,!1),this._speedup=e(t.speedup,1),this._reverse=e(t.reverse,!1),this._loop=e(t.loop,n.NONE),this.start=new r,this.update=new r,this.stop=new r,this._state=o.STOPPED,this._runtimeAnimation=s,this._computedStartTime=void 0,this._duration=void 0;var l=this;this._raiseStartEvent=function(){l.start.raiseEvent(a,l)},this._updateEventTime=0,this._raiseUpdateEvent=function(){l.update.raiseEvent(a,l,l._updateEventTime)},this._raiseStopEvent=function(){l.stop.raiseEvent(a,l)}};return t(a.prototype,{name:{get:function(){return this._name}},startTime:{get:function(){return this._startTime}},delay:{get:function(){return this._delay}},stopTime:{get:function(){return this._stopTime}},speedup:{get:function(){return this._speedup}},reverse:{get:function(){return this._reverse}},loop:{get:function(){return this._loop}}}),a}),r("Scene/ModelAnimationCollection",["../Core/clone","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/JulianDate","../Core/Math","./ModelAnimation","./ModelAnimationLoop","./ModelAnimationState"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t){for(var r=e.channelEvaluators,i=r.length,n=0;i>n;++n)r[n](t)}function d(e,t,r){return function(){e.animationRemoved.raiseEvent(t,r)}}var p=function(e){this.animationAdded=new o,this.animationRemoved=new o,this._model=e,this._scheduledAnimations=[],this._previousTime=void 0};i(p.prototype,{length:{get:function(){return this._scheduledAnimations.length}}}),p.prototype.add=function(e){e=t(e,t.EMPTY_OBJECT);var r=this._model,i=r._runtime.animations,n=i[e.name],o=new l(e,r,n);return this._scheduledAnimations.push(o),this.animationAdded.raiseEvent(r,o),o},p.prototype.addAll=function(r){r=t(r,t.EMPTY_OBJECT),r=e(r);for(var i=[],n=this._model._animationIds,o=n.length,a=0;o>a;++a)r.name=n[a],i.push(this.add(r));return i},p.prototype.remove=function(e){if(r(e)){var t=this._scheduledAnimations,i=t.indexOf(e);if(-1!==i)return t.splice(i,1),this.animationRemoved.raiseEvent(this._model,e),!0}return!1},p.prototype.removeAll=function(){var e=this._model,t=this._scheduledAnimations,r=t.length;this._scheduledAnimations=[];for(var i=0;r>i;++i)this.animationRemoved.raiseEvent(e,t[i])},p.prototype.contains=function(e){return r(e)?-1!==this._scheduledAnimations.indexOf(e):!1},p.prototype.get=function(e){return this._scheduledAnimations[e]};var m=[];return p.prototype.update=function(e){var i=this._scheduledAnimations,n=i.length;if(0===n)return this._previousTime=void 0,!1;if(a.equals(e.time,this._previousTime))return!1;this._previousTime=a.clone(e.time,this._previousTime);for(var o=!1,l=e.time,p=this._model,f=0;n>f;++f){var v=i[f],_=v._runtimeAnimation;r(v._computedStartTime)||(v._computedStartTime=a.addSeconds(t(v.startTime,l),v.delay,new a)),r(v._duration)||(v._duration=_.stopTime*(1/v.speedup));var g=v._computedStartTime,y=v._duration,C=v.stopTime,E=0!==y?a.secondsDifference(l,g)/y:0,S=E>=0,w=S&&(1>=E||v.loop===u.REPEAT||v.loop===u.MIRRORED_REPEAT)&&(!r(C)||a.lessThanOrEquals(l,C));if(w){if(v._state===c.STOPPED&&(v._state=c.ANIMATING,v.start.numberOfListeners>0&&e.afterRender.push(v._raiseStartEvent)),v.loop===u.REPEAT)E-=Math.floor(E);else if(v.loop===u.MIRRORED_REPEAT){var T=Math.floor(E),b=E-T;E=T%2===1?1-b:b}v.reverse&&(E=1-E);var x=E*y*v.speedup;x=s.clamp(x,_.startTime,_.stopTime),h(_,x),v.update.numberOfListeners>0&&(v._updateEventTime=x,e.afterRender.push(v._raiseUpdateEvent)),o=!0}else S&&v._state===c.ANIMATING&&(v._state=c.STOPPED,v.stop.numberOfListeners>0&&e.afterRender.push(v._raiseStopEvent),v.removeOnStop&&m.push(v))}n=m.length;for(var P=0;n>P;++P){var A=m[P];i.splice(i.indexOf(A),1),e.afterRender.push(d(this,p,A))}return m.length=0,o},p}),r("Scene/modelMaterialsCommon",["../Core/defaultValue","../Core/defined","../Renderer/WebGLConstants"],function(e,t,r){"use strict";function i(e){switch(e){case r.FLOAT:return"float";case r.FLOAT_VEC2:return"vec2";case r.FLOAT_VEC3:return"vec3";case r.FLOAT_VEC4:return"vec4";case r.FLOAT_MAT2:return"mat2";case r.FLOAT_MAT3:return"mat3";case r.FLOAT_MAT4:return"mat4";case r.SAMPLER_2D:return"sampler2D"}}function n(e){var i,n={};if(t(e.extensions)&&t(e.extensions.KHR_materials_common)&&(i=e.extensions.KHR_materials_common.lights),t(i)){var o=e.nodes;for(var a in o)if(o.hasOwnProperty(a)){var s=o[a];if(t(s.extensions)&&t(s.extensions.KHR_materials_common)){var l=s.extensions.KHR_materials_common.light;t(l)&&t(i[l])&&(i[l].node=a),delete s.extensions.KHR_materials_common}}var u=0;for(var c in i)if(i.hasOwnProperty(c)){var h=i[c],d=h.type;if("ambient"!==d&&!t(h.node)){delete i[c];continue}var p="light"+u.toString();switch(h.baseName=p,d){case"ambient":var m=h.ambient;n[p+"Color"]={type:r.FLOAT_VEC3,value:m.color};break;case"directional":var f=h.directional;n[p+"Color"]={type:r.FLOAT_VEC3,value:f.color},t(h.node)&&(n[p+"Transform"]={node:h.node,semantic:"MODELVIEW",type:r.FLOAT_MAT4});break;case"point":var v=h.point;n[p+"Color"]={type:r.FLOAT_VEC3,value:v.color},t(h.node)&&(n[p+"Transform"]={node:h.node,semantic:"MODELVIEW",type:r.FLOAT_MAT4}),n[p+"Attenuation"]={type:r.FLOAT_VEC3,value:[v.constantAttenuation,v.linearAttenuation,v.quadraticAttenuation]};break;case"spot":var _=h.spot;n[p+"Color"]={type:r.FLOAT_VEC3,value:_.color},t(h.node)&&(n[p+"Transform"]={node:h.node,semantic:"MODELVIEW",type:r.FLOAT_MAT4},n[p+"InverseTransform"]={node:h.node,semantic:"MODELVIEWINVERSE",type:r.FLOAT_MAT4,useInFragment:!0}),n[p+"Attenuation"]={type:r.FLOAT_VEC3,value:[_.constantAttenuation,_.linearAttenuation,_.quadraticAttenuation]},n[p+"FallOff"]={type:r.FLOAT_VEC2,value:[_.fallOffAngle,_.fallOffExponent]}}++u}}return n}function o(r,i,n){var o,a=e(n,0);do o=i+(a++).toString();while(t(r[o]));return o}function a(n,a,s){var d,p=n.techniques,m=n.shaders,f=n.programs,v=a.technique.toUpperCase();t(n.extensions)&&t(n.extensions.KHR_materials_common)&&(d=n.extensions.KHR_materials_common.lights);var _=e(a.jointCount,0),g=_>0,y=a.values,C="precision highp float;\n",E="precision highp float;\n",S=o(p,"technique",l),w=o(m,"vertexShader",u),T=o(m,"fragmentShader",c),b=o(f,"program",h),x="CONSTANT"!==v,P={modelViewMatrix:{semantic:"MODELVIEW",type:r.FLOAT_MAT4},projectionMatrix:{semantic:"PROJECTION",type:r.FLOAT_MAT4}};x&&(P.normalMatrix={semantic:"MODELVIEWINVERSETRANSPOSE",type:r.FLOAT_MAT3}),g&&(P.jointMatrix={count:_,semantic:"JOINTMATRIX",type:r.FLOAT_MAT4});var A,I=!1;for(var M in y)if(y.hasOwnProperty(M)){var D=y[M];A=M.toLowerCase(),I||D.type!==r.SAMPLER_2D||(I=!0),P[A]={type:D.type}}if(t(s))for(var R in s)s.hasOwnProperty(R)&&(P[R]=s[R]);var O={};for(var N in P)if(P.hasOwnProperty(N)){var L=P[N];O["u_"+N]=N;var F=t(L.count)?"["+L.count+"]":"";L.type!==r.FLOAT_MAT3&&L.type!==r.FLOAT_MAT4||L.useInFragment?(E+="uniform "+i(L.type)+" u_"+N+F+";\n",delete L.useInFragment):C+="uniform "+i(L.type)+" u_"+N+F+";\n"}var B="";g&&(B+=" mat4 skinMat = a_weight.x * u_jointMatrix[int(a_joint.x)];\n",B+=" skinMat += a_weight.y * u_jointMatrix[int(a_joint.y)];\n",B+=" skinMat += a_weight.z * u_jointMatrix[int(a_joint.z)];\n",B+=" skinMat += a_weight.w * u_jointMatrix[int(a_joint.w)];\n");var V={a_position:"position"};P.position={semantic:"POSITION",type:r.FLOAT_VEC3},C+="attribute vec3 a_position;\n",C+="varying vec3 v_positionEC;\n",B+=g?" vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);\n":" vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\n",B+=" v_positionEC = pos.xyz;\n",B+=" gl_Position = u_projectionMatrix * pos;\n",E+="varying vec3 v_positionEC;\n",x&&(V.a_normal="normal",P.normal={semantic:"NORMAL",type:r.FLOAT_VEC3},C+="attribute vec3 a_normal;\n",C+="varying vec3 v_normal;\n",B+=g?" v_normal = u_normalMatrix * mat3(skinMat) * a_normal;\n":" v_normal = u_normalMatrix * a_normal;\n",E+="varying vec3 v_normal;\n");var z;I&&(V.a_texcoord_0="texcoord_0",P.texcoord_0={semantic:"TEXCOORD_0",type:r.FLOAT_VEC2},z="v_texcoord_0",C+="attribute vec2 a_texcoord_0;\n",C+="varying vec2 "+z+";\n",B+=" "+z+" = a_texcoord_0;\n",E+="varying vec2 "+z+";\n"),g&&(V.a_joint="joint",P.joint={semantic:"JOINT",type:r.FLOAT_VEC4},V.a_weight="weight",P.weight={semantic:"WEIGHT",type:r.FLOAT_VEC4},C+="attribute vec4 a_joint;\n",C+="attribute vec4 a_weight;\n");var k=x&&("BLINN"===v||"PHONG"===v)&&t(P.specular)&&t(P.shininess),U=!1,G=!1,W="";for(var H in d)if(d.hasOwnProperty(H)){var q=d[H],j=q.type.toLowerCase(),Y=q.baseName;W+=" {\n";var X,Z,K="u_"+Y+"Color";"ambient"===j?(G=!0,W+=" ambientLight += "+K+";\n"):x&&(U=!0,X="v_"+Y+"Direction",Z="v_"+Y+"Position","point"!==j&&(C+="varying vec3 "+X+";\n",E+="varying vec3 "+X+";\n",B+=" "+X+" = mat3(u_"+Y+"Transform) * vec3(0.,0.,1.);\n","directional"===j&&(W+=" vec3 l = normalize("+X+");\n")),"directional"!==j?(C+="varying vec3 "+Z+";\n",E+="varying vec3 "+Z+";\n",B+=" "+Z+" = u_"+Y+"Transform[3].xyz;\n",W+=" vec3 VP = "+Z+" - v_positionEC;\n",W+=" vec3 l = normalize(VP);\n",W+=" float range = length(VP);\n",W+=" float attenuation = 1.0 / (u_"+Y+"Attenuation.x + ",W+="(u_"+Y+"Attenuation.y * range) + ",W+="(u_"+Y+"Attenuation.z * range * range));\n"):W+=" float attenuation = 1.0;\n","spot"===j&&(W+=" float spotDot = dot(l, normalize("+X+"));\n",W+=" if (spotDot < cos(u_"+Y+"FallOff.x * 0.5))\n",W+=" {\n",W+=" attenuation = 0.0;\n",W+=" }\n",W+=" else\n",W+=" {\n",W+=" attenuation *= max(0.0, pow(spotDot, u_"+Y+"FallOff.y));\n",W+=" }\n"),W+=" diffuseLight += "+K+"* max(dot(normal,l), 0.) * attenuation;\n",k&&("BLINN"===v?(W+=" vec3 h = normalize(l + viewDir);\n",W+=" float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\n"):(W+=" vec3 reflectDir = reflect(-l, normal);\n",W+=" float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\n"),W+=" specularLight += "+K+" * specularIntensity;\n")),W+=" }\n"}G||(W+=" ambientLight += vec3(0.2, 0.2, 0.2);\n"),U||"CONSTANT"===v||(W+=" vec3 l = normalize(czm_sunDirectionEC);\n",W+=" diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), 0.);\n",k&&("BLINN"===v?(W+=" vec3 h = normalize(l + viewDir);\n",W+=" float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\n"):(W+=" vec3 reflectDir = reflect(-l, normal);\n",W+=" float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\n"),W+=" specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity;\n")),C+="void main(void) {\n",C+=B,C+="}\n",E+="void main(void) {\n";var J=" vec3 color = vec3(0.0, 0.0, 0.0);\n";x&&(E+=" vec3 normal = normalize(v_normal);\n",a.doubleSided&&(E+=" if (gl_FrontFacing == false)\n",E+=" {\n",E+=" normal = -normal;\n",E+=" }\n"));var Q;"CONSTANT"!==v?(t(P.diffuse)&&(E+=P.diffuse.type===r.SAMPLER_2D?" vec4 diffuse = texture2D(u_diffuse, "+z+");\n":" vec4 diffuse = u_diffuse;\n",E+=" vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\n",J+=" color += diffuse.rgb * diffuseLight;\n"),k&&(E+=P.specular.type===r.SAMPLER_2D?" vec3 specular = texture2D(u_specular, "+z+").rgb;\n":" vec3 specular = u_specular.rgb;\n",E+=" vec3 specularLight = vec3(0.0, 0.0, 0.0);\n",J+=" color += specular * specularLight;\n"),Q=t(P.transparency)?" gl_FragColor = vec4(color * diffuse.a, diffuse.a * u_transparency);\n":" gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n"):Q=t(P.transparency)?" gl_FragColor = vec4(color, u_transparency);\n":" gl_FragColor = vec4(color, 1.0);\n",t(P.emission)&&(E+=P.emission.type===r.SAMPLER_2D?" vec3 emission = texture2D(u_emission, "+z+").rgb;\n":" vec3 emission = u_emission.rgb;\n",J+=" color += emission;\n"),(t(P.ambient)||"CONSTANT"!==v)&&(E+=t(P.ambient)?P.ambient.type===r.SAMPLER_2D?" vec3 ambient = texture2D(u_ambient, "+z+").rgb;\n":" vec3 ambient = u_ambient.rgb;\n":" vec3 ambient = diffuse.rgb;\n",J+=" color += ambient * ambientLight;\n"),E+=" vec3 viewDir = -normalize(v_positionEC);\n",E+=" vec3 ambientLight = vec3(0.0, 0.0, 0.0);\n",E+=W,E+=J,E+=Q,E+="}\n";var $;$=a.transparent?{enable:[r.DEPTH_TEST,r.BLEND],depthMask:!1,functions:{blendEquationSeparate:[r.FUNC_ADD,r.FUNC_ADD],blendFuncSeparate:[r.ONE,r.ONE_MINUS_SRC_ALPHA,r.ONE,r.ONE_MINUS_SRC_ALPHA]}}:a.doubleSided?{enable:[r.DEPTH_TEST]}:{enable:[r.CULL_FACE,r.DEPTH_TEST]},p[S]={attributes:V,parameters:P,program:b,states:$,uniforms:O},m[w]={type:r.VERTEX_SHADER,uri:"",extras:{source:C}},m[T]={type:r.FRAGMENT_SHADER,uri:"",extras:{source:E}};var ee=Object.keys(V);return f[b]={attributes:ee,fragmentShader:T,vertexShader:w},S}function s(t){var r="";r+="technique:"+t.technique+";";for(var i=t.values,n=Object.keys(i).sort(),o=n.length,a=0;o>a;++a){var s=n[a];if(i.hasOwnProperty(s)){var l=i[s];r+=s+":"+l.type.toString(),r+=";"}}var u=e(t.doubleSided,!1);r+=u.toString()+";";var c=e(t.transparent,!1);r+=c.toString()+";";var h=e(t.jointCount,0);return r+=h.toString()+";"}var l=0,u=0,c=0,h=0,d=function(e){if(!t(e))return void 0;var r=!1,i=e.extensionsUsed;if(t(i))for(var o=i.length,l=0;o>l;++l)if("KHR_materials_common"===i[l]){r=!0,i.splice(l,1);break}if(r){t(e.programs)||(e.programs={}),t(e.shaders)||(e.shaders={}),t(e.techniques)||(e.techniques={});var u=n(e),c={},h=e.materials;for(var d in h)if(h.hasOwnProperty(d)){var p=h[d];if(t(p.extensions)&&t(p.extensions.KHR_materials_common)){var m=p.extensions.KHR_materials_common,f=s(m),v=c[f];t(v)||(v=a(e,m,u),c[f]=v),p.values={};var _=m.values;for(var g in _)if(_.hasOwnProperty(g)){var y=_[g];p.values[g]=y.value}p.technique=v,delete p.extensions.KHR_materials_common}}t(e.extensions)&&delete e.extensions.KHR_materials_common}return e};return d}),r("Scene/ModelMaterial",["../Core/defined","../Core/defineProperties","../Core/DeveloperError"],function(e,t,r){"use strict";var i=function(e,t,r){this._name=t.name,this._id=r,this._uniformMap=e._uniformMaps[r]};return t(i.prototype,{name:{get:function(){return this._name}},id:{get:function(){return this._id}}}),i.prototype.setValue=function(e,t){var r=this._uniformMap.values[e];r.value=r.clone(t,r.value)},i.prototype.getValue=function(t){var r=this._uniformMap.values[t];return e(r)?r.value:void 0},i}),r("Scene/ModelMesh",["../Core/defineProperties"],function(e){"use strict";var t=function(e,t,r){for(var i=[],n=e.primitives,o=n.length,a=0;o>a;++a){var s=n[a];i[a]=t[s.material]}this._name=e.name,this._materials=i,this._id=r};return e(t.prototype,{name:{get:function(){return this._name}},id:{get:function(){return this._id}},materials:{get:function(){return this._materials}}}),t}),r("Scene/ModelNode",["../Core/defaultValue","../Core/defineProperties","../Core/Matrix4"],function(e,t,r){"use strict";var i=function(e,t,i,n,o){this._model=e,this._runtimeNode=i,this._name=t.name,this._id=n,this.useMatrix=!1,this._show=!0,this._matrix=r.clone(o)};return t(i.prototype,{name:{get:function(){return this._name}},id:{get:function(){return this._id}},show:{get:function(){return this._show},set:function(e){this._show!==e&&(this._show=e,this._model._perNodeShowDirty=!0)}},matrix:{get:function(){return this._matrix},set:function(e){this._matrix=r.clone(e,this._matrix),this.useMatrix=!0;var t=this._model;t._cesiumAnimationsDirty=!0,this._runtimeNode.dirtyNumber=t._maxDirtyNumber}}}),i.prototype.setMatrix=function(e){r.clone(e,this._matrix)},i}),r("Scene/Model",["../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/clone","../Core/combine","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/FeatureDetection","../Core/getMagic","../Core/getStringFromTypedArray","../Core/IndexDatatype","../Core/loadArrayBuffer","../Core/loadImage","../Core/loadImageFromTypedArray","../Core/loadText","../Core/Math","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Core/PrimitiveType","../Core/Quaternion","../Core/Queue","../Core/RuntimeError","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/Sampler","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/TextureMinificationFilter","../Renderer/TextureWrap","../Renderer/VertexArray","../Renderer/WebGLConstants","../ThirdParty/gltfDefaults","../ThirdParty/Uri","../ThirdParty/when","./getModelAccessor","./ModelAnimationCache","./ModelAnimationCollection","./modelMaterialsCommon","./ModelMaterial","./ModelMesh","./ModelNode","./Pass","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$){"use strict";function ee(){this.buffersToCreate=new A,this.buffers={},this.pendingBufferLoads=0,this.programsToCreate=new A,this.shaders={},this.pendingShaderLoads=0,this.texturesToCreate=new A,this.pendingTextureLoads=0,this.texturesToCreateFromBufferView=new A,this.pendingBufferViewToImage=0,this.createSamplers=!0,this.createSkins=!0, +this.createRuntimeAnimations=!0,this.createVertexArrays=!0,this.createRenderStates=!0,this.createUniformMaps=!0,this.createRuntimeNodes=!0,this.skinnedNodesNames=[]}function te(e,t){e._cachedGltf=t,e._animationIds=re(t)}function re(e){var t=[];if(l(e)&&l(e.gltf)){var r=e.gltf.animations;for(var i in r)r.hasOwnProperty(i)&&t.push(i)}return t}function ie(e){var t="",r=e.lastIndexOf("/");return-1!==r&&(t=e.substring(0,r+1)),t}function ne(e){var t=new W(document.location.href),r=new W(e);return r.resolve(t).toString()}function oe(e,t,r){return e.subarray(t,t+r)}function ae(e){var t=f(e);return"glTF"===t}function se(e){if(!ae(e))throw new d("bgltf is not a valid Binary glTF file.");var t=new DataView(e.buffer,e.byteOffset,e.byteLength),r=0;r+=Tt,r+=Tt,r+=Tt;var i=t.getUint32(r,!0);r+=Tt;var n=t.getUint32(r,!0);r+=Tt;var o=r,a=o+i;0!==n&&(o=i,i=n,a=0);var s=v(e,o,i);return{glTF:JSON.parse(s),binaryOffset:a}}function le(e,t,r){return e._runtime[t][r]}function ue(t){for(var i=(t.asset.version,t.nodes),n=t.meshes,o=t.accessors,a=t.scenes[t.scene].nodes,s=a.length,u=[],c=new r(Number.MAX_VALUE,Number.MAX_VALUE,Number.MAX_VALUE),h=new r(Number.MIN_VALUE,Number.MIN_VALUE,Number.MIN_VALUE),d=0;s>d;++d){var p=i[a[d]];for(p._transformToRoot=ye(p),u.push(p);u.length>0;){p=u.pop();var m=p._transformToRoot,f=p.meshes;if(l(f))for(var v=f.length,_=0;v>_;++_)for(var g=n[f[_]].primitives,y=g.length,C=0;y>C;++C){var E=g[C].attributes.POSITION;if(l(E)){var S=o[E],w=r.fromArray(S.min,0,bt),T=r.fromArray(S.max,0,xt);l(c)&&l(h)&&(b.multiplyByPoint(m,w,w),b.multiplyByPoint(m,T,T),r.minimumByComponent(c,w,c),r.maximumByComponent(h,T,h))}}for(var x=p.children,P=x.length,A=0;P>A;++A){var I=i[x[A]];I._transformToRoot=ye(I),b.multiplyTransformation(m,I._transformToRoot,I._transformToRoot),u.push(I)}delete p._transformToRoot}}var M=e.fromCornerPoints(c,h);return e.transformWithoutScale(M,_t,M)}function ce(e,t,r){return function(){e._loadError=new I("Failed to load "+t+": "+r),e._state=yt.FAILED}}function he(e,t){return function(r){var i=e._loadResources;i.buffers[t]=new Uint8Array(r),--i.pendingBufferLoads}}function de(e){var t=e.gltf.buffers;for(var r in t)if(t.hasOwnProperty(r)){var i=t[r];if("CESIUM_binary_glTF"===r||"KHR_binary_glTF"===r){var n=e._loadResources;n.buffers[r]=e._cachedGltf.bgltf}else if("arraybuffer"===i.type){++e._loadResources.pendingBufferLoads;var o=new W(i.uri),a=o.resolve(e._baseUri).toString();g(a).then(he(e,r)).otherwise(ce(e,"buffer",a))}else"text"===i.type}}function pe(e){var t=e.gltf.bufferViews;for(var r in t)t.hasOwnProperty(r)&&t[r].target===U.ARRAY_BUFFER&&e._loadResources.buffersToCreate.enqueue(r)}function me(e,t){return function(r){var i=e._loadResources;i.shaders[t]={source:r,bufferView:void 0},--i.pendingShaderLoads}}function fe(e){var t=e.gltf.shaders;for(var r in t)if(t.hasOwnProperty(r)){var i=t[r];if(l(i.extras)&&l(i.extras.source))e._loadResources.shaders[r]={source:i.extras.source,bufferView:void 0};else if(l(i.extensions)&&(l(i.extensions.CESIUM_binary_glTF)||l(i.extensions.KHR_binary_glTF))){var n;n=l(i.extensions.CESIUM_binary_glTF)?i.extensions.CESIUM_binary_glTF:i.extensions.KHR_binary_glTF,e._loadResources.shaders[r]={source:void 0,bufferView:n.bufferView}}else{++e._loadResources.pendingShaderLoads;var o=new W(i.uri),a=o.resolve(e._baseUri).toString();E(a).then(me(e,r)).otherwise(ce(e,"shader",a))}}}function ve(e){var t=e.gltf.programs;for(var r in t)t.hasOwnProperty(r)&&e._loadResources.programsToCreate.enqueue(r)}function _e(e,t){return function(r){var i=e._loadResources;--i.pendingTextureLoads,i.texturesToCreate.enqueue({name:t,image:r,bufferView:void 0})}}function ge(e){var t=e.gltf.images,r=e.gltf.textures;for(var i in r)if(r.hasOwnProperty(i)){var n=t[r[i].source];if(l(n.extensions)&&(l(n.extensions.CESIUM_binary_glTF)||l(n.extensions.KHR_binary_glTF))){var o;o=l(n.extensions.CESIUM_binary_glTF)?n.extensions.CESIUM_binary_glTF:n.extensions.KHR_binary_glTF,e._loadResources.texturesToCreateFromBufferView.enqueue({name:i,image:void 0,bufferView:o.bufferView,mimeType:o.mimeType})}else{++e._loadResources.pendingTextureLoads;var a=new W(n.uri),s=a.resolve(e._baseUri).toString();y(s).then(_e(e,i)).otherwise(ce(e,"image",s))}}}function ye(e,t){return l(e.matrix)?b.fromArray(e.matrix):b.fromTranslationQuaternionRotationScale(r.fromArray(e.translation,0,Pt),P.unpack(e.rotation,0,At),r.fromArray(e.scale,0,It))}function Ce(e){var t={},r={},i=[],n=e._loadResources.skinnedNodesNames,o=e.gltf.nodes;for(var a in o)if(o.hasOwnProperty(a)){var s=o[a],u={matrix:void 0,translation:void 0,rotation:void 0,scale:void 0,computedShow:!0,transformToRoot:new b,computedMatrix:new b,dirtyNumber:0,commands:[],inverseBindMatrices:void 0,bindShapeMatrix:void 0,joints:[],computedJointMatrices:[],jointName:s.jointName,children:[],parents:[],publicNode:void 0};u.publicNode=new J(e,s,u,a,ye(s)),t[a]=u,r[s.name]=u,l(s.skin)&&(n.push(a),i.push(u))}e._runtime.nodes=t,e._runtime.nodesByName=r,e._runtime.skinnedNodes=i}function Ee(e){var t={},r={},i=e.gltf.materials,n=e._uniformMaps;for(var o in i)if(i.hasOwnProperty(o)){n[o]={uniformMap:void 0,values:void 0,jointMatrixUniformName:void 0};var a=i[o],s=new Z(e,a,o);t[a.name]=s,r[o]=s}e._runtime.materialsByName=t,e._runtime.materialsById=r}function Se(e){var t={},r=e._runtime.materialsById,i=e.gltf.meshes;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];t[o.name]=new K(o,r,n)}e._runtime.meshesByName=t}function we(e){e._loadRendererResourcesFromCache||(de(e),pe(e),fe(e),ve(e),ge(e)),Ee(e),Se(e),Ce(e)}function Te(e,t){var r=e._loadResources;if(0===r.pendingBufferLoads){for(var i,n=e.gltf.bufferViews,o=e._rendererResources.buffers;r.buffersToCreate.length>0;){var a=r.buffersToCreate.dequeue();i=n[a];var s=M.createVertexBuffer({context:t,typedArray:r.getBuffer(i),usage:D.STATIC_DRAW});s.vertexArrayDestroyable=!1,o[a]=s}var u=e.gltf.accessors;for(var c in u)if(u.hasOwnProperty(c)){var h=u[c];if(i=n[h.bufferView],i.target===U.ELEMENT_ARRAY_BUFFER&&!l(o[h.bufferView])){var d=M.createIndexBuffer({context:t,typedArray:r.getBuffer(i),usage:D.STATIC_DRAW,indexDatatype:h.componentType});d.vertexArrayDestroyable=!1,o[h.bufferView]=d}}}}function be(e){for(var t={},r=e.length,i=0;r>i;++i)t[e[i]]=i;return t}function xe(e,t){if(l(t.source))return t.source;var r=e._loadResources,i=e.gltf,n=i.bufferViews[t.bufferView];return v(r.getBuffer(n))}function Pe(e,t,r){var i=t.gltf.programs,n=t._loadResources.shaders,o=i[e],a=be(o.attributes),s=xe(t,n[o.vertexShader]),l=xe(t,n[o.fragmentShader]);if(t._rendererResources.programs[e]=L.fromCache({context:r,vertexShaderSource:s,fragmentShaderSource:l,attributeLocations:a}),t.allowPicking){var u=new F({sources:[l],pickColorQualifier:"uniform"});t._rendererResources.pickPrograms[e]=L.fromCache({context:r,vertexShaderSource:s,fragmentShaderSource:u,attributeLocations:a})}}function Ae(e,t){var r,i=e._loadResources;if(0===i.pendingShaderLoads&&0===i.pendingBufferLoads)if(e.asynchronous)i.programsToCreate.length>0&&(r=i.programsToCreate.dequeue(),Pe(r,e,t));else for(;i.programsToCreate.length>0;)r=i.programsToCreate.dequeue(),Pe(r,e,t)}function Ie(e,t){return function(r){e.texturesToCreate.enqueue({name:t.name,image:r,bufferView:void 0}),--e.pendingBufferViewToImage}}function Me(e){var t=e._loadResources;if(0===t.pendingBufferLoads)for(;t.texturesToCreateFromBufferView.length>0;){var r=t.texturesToCreateFromBufferView.dequeue(),i=e.gltf,n=i.bufferViews[r.bufferView],o=Ie(t,r),a=ce(e,"image","name: "+r.name+", bufferView: "+r.bufferView);C(t.getBuffer(n),r.mimeType).then(o).otherwise(a),++t.pendingBufferViewToImage}}function De(e,t){var r=e._loadResources;if(r.createSamplers){r.createSamplers=!1;var i=e._rendererResources.samplers,n=e.gltf.samplers;for(var o in n)if(n.hasOwnProperty(o)){var a=n[o];i[o]=new N({wrapS:a.wrapS,wrapT:a.wrapT,minificationFilter:a.minFilter,magnificationFilter:a.magFilter})}}}function Re(e,t,r){var i=t.gltf.textures,n=i[e.name],o=t._rendererResources.samplers,a=o[n.sampler],s=a.minificationFilter===V.NEAREST_MIPMAP_NEAREST||a.minificationFilter===V.NEAREST_MIPMAP_LINEAR||a.minificationFilter===V.LINEAR_MIPMAP_NEAREST||a.minificationFilter===V.LINEAR_MIPMAP_LINEAR,l=s||a.wrapS===z.REPEAT||a.wrapS===z.MIRRORED_REPEAT||a.wrapT===z.REPEAT||a.wrapT===z.MIRRORED_REPEAT,u=e.image,c=!S.isPowerOfTwo(u.width)||!S.isPowerOfTwo(u.height);if(l&&c){var h=document.createElement("canvas");h.width=S.nextPowerOfTwo(u.width),h.height=S.nextPowerOfTwo(u.height);var d=h.getContext("2d");d.drawImage(u,0,0,u.width,u.height,0,0,h.width,h.height),u=h}var p;n.target===U.TEXTURE_2D&&(p=new B({context:r,source:u,pixelFormat:n.internalFormat,pixelDatatype:n.type,flipY:!1})),s&&p.generateMipmap(),p.sampler=a,t._rendererResources.textures[e.name]=p}function Oe(e,t){var r,i=e._loadResources;if(e.asynchronous)i.texturesToCreate.length>0&&(r=i.texturesToCreate.dequeue(),Re(r,e,t));else for(;i.texturesToCreate.length>0;)r=i.texturesToCreate.dequeue(),Re(r,e,t)}function Ne(e,t){var r=e.gltf,i=(r.programs,r.techniques),n=r.materials,o={},a=i[n[t.material].technique],s=a.parameters,l=a.attributes,u=e._rendererResources.programs[a.program].vertexAttributes;for(var c in u)if(u.hasOwnProperty(c)){var h=s[l[c]];o[h.semantic]=u[c].index}return o}function Le(e,t){for(var r=e.length,i=0;r>i;++i)for(var n=[e[i]];n.length>0;){var o=n.pop();if(o.jointName===t)return o;for(var a=o.children,s=a.length,l=0;s>l;++l)n.push(a[l])}return void 0}function Fe(e,t){for(var r=e.gltf,i=r.skins,n=r.nodes,o=e._runtime.nodes,a=e._loadResources.skinnedNodesNames,s=a.length,l=0;s>l;++l){var u=a[l],c=o[u],h=n[u],d=t[h.skin];c.inverseBindMatrices=d.inverseBindMatrices,c.bindShapeMatrix=d.bindShapeMatrix;for(var p=[],m=h.skeletons,f=m.length,v=0;f>v;++v)p.push(o[m[v]]);for(var _=i[h.skin].jointNames,g=_.length,y=0;g>y;++y){var C=_[y];c.joints.push(Le(p,C))}}}function Be(e){var t=e._loadResources;if(0===t.pendingBufferLoads&&t.createSkins){t.createSkins=!1;var r=e.gltf,i=r.accessors,n=r.skins,o={};for(var a in n)if(n.hasOwnProperty(a)){var s,l=n[a],u=i[l.inverseBindMatrices];b.equals(l.bindShapeMatrix,b.IDENTITY)||(s=b.clone(l.bindShapeMatrix)),o[a]={inverseBindMatrices:j.getSkinInverseBindMatrices(e,u),bindShapeMatrix:s}}Fe(e,o)}}function Ve(e,t,r,i){return function(n){t[r]=i.evaluate(n,t[r]),t.dirtyNumber=e._maxDirtyNumber}}function ze(e){var t=e._loadResources;if(t.finishedPendingLoads()&&t.createRuntimeAnimations){t.createRuntimeAnimations=!1,e._runtime.animations={};var r,i=e._runtime.nodes,n=e.gltf.animations,o=e.gltf.accessors;for(var a in n)if(n.hasOwnProperty(a)){var s=n[a],l=s.channels,u=s.parameters,c=s.samplers,h={};for(r in u)u.hasOwnProperty(r)&&(h[r]=j.getAnimationParameterValues(e,o[u[r]]));for(var d=Number.MAX_VALUE,p=-Number.MAX_VALUE,m=l.length,f=new Array(m),v=0;m>v;++v){var _=l[v],g=_.target,y=c[_.sampler],C=h[y.input];d=Math.min(d,C[0]),p=Math.max(p,C[C.length-1]);var E=j.getAnimationSpline(e,a,s,_.sampler,y,h);f[v]=Ve(e,i[g.id],g.path,E)}e._runtime.animations[a]={startTime:d,stopTime:p,channelEvaluators:f}}}}function ke(e,t){var r=e._loadResources;if(r.finishedBuffersCreation()&&r.finishedProgramCreation()&&r.createVertexArrays){r.createVertexArrays=!1;var i=e._rendererResources.buffers,n=e._rendererResources.vertexArrays,o=e.gltf,a=o.accessors,s=o.meshes;for(var u in s)if(s.hasOwnProperty(u))for(var c=s[u].primitives,h=c.length,d=0;h>d;++d){var p=c[d],m=Ne(e,p),f=[],v=p.attributes;for(var _ in v)if(v.hasOwnProperty(_)){var g=m[_];if(l(g)){var y=a[v[_]];f.push({index:g,vertexBuffer:i[y.bufferView],componentsPerAttribute:q(y).componentsPerAttribute,componentDatatype:y.componentType,normalize:!1,offsetInBytes:y.byteOffset,strideInBytes:y.byteStride})}}var C;if(l(p.indices)){var E=a[p.indices];C=i[E.bufferView]}n[u+".primitive."+d]=new k({context:t,attributes:f,indexBuffer:C})}}}function Ue(e){var t={};t[U.BLEND]=!1,t[U.CULL_FACE]=!1,t[U.DEPTH_TEST]=!1,t[U.POLYGON_OFFSET_FILL]=!1,t[U.SCISSOR_TEST]=!1;var r,i=e.enable,n=i.length;for(r=0;n>r;++r)t[i[r]]=!0;return t}function Ge(e,t){var r=e._loadResources;if(r.createRenderStates){r.createRenderStates=!1;var i=e._rendererResources.renderStates,n=e.gltf.techniques;for(var o in n)if(n.hasOwnProperty(o)){var a=n[o],u=a.states,c=Ue(u),h=s(u.functions,s.EMPTY_OBJECT),d=s(h.blendColor,[0,0,0,0]),p=s(h.blendEquationSeparate,[U.FUNC_ADD,U.FUNC_ADD]),m=s(h.blendFuncSeparate,[U.ONE,U.ONE,U.ZERO,U.ZERO]),f=s(h.colorMask,[!0,!0,!0,!0]),v=s(h.depthRange,[0,1]),_=s(h.polygonOffset,[0,0]),g=s(h.scissor,[0,0,0,0]);i[o]=O.fromCache({frontFace:l(h.frontFace)?h.frontFace[0]:U.CCW,cull:{enabled:c[U.CULL_FACE],face:l(h.cullFace)?h.cullFace[0]:U.BACK},lineWidth:l(h.lineWidth)?h.lineWidth[0]:1,polygonOffset:{enabled:c[U.POLYGON_OFFSET_FILL],factor:_[0],units:_[1]},scissorTest:{enabled:c[U.SCISSOR_TEST],rectangle:{x:g[0],y:g[1],width:g[2],height:g[3]}},depthRange:{near:v[0],far:v[1]},depthTest:{enabled:c[U.DEPTH_TEST],func:l(h.depthFunc)?h.depthFunc[0]:U.LESS},colorMask:{red:f[0],green:f[1],blue:f[2],alpha:f[3]},depthMask:l(h.depthMask)?h.depthMask[0]:!0,blending:{enabled:c[U.BLEND],color:{red:d[0],green:d[1],blue:d[2],alpha:d[3]},equationRgb:p[0],equationAlpha:p[1],functionSourceRgb:m[0],functionSourceAlpha:m[1],functionDestinationRgb:m[2],functionDestinationAlpha:m[3]}})}}}function We(e,t){var r={value:e,clone:function(e,t){return e},func:function(){return r.value}};return r}function He(e,r){var i={value:t.fromArray(e),clone:t.clone,func:function(){return i.value}};return i}function qe(e,t){var i={value:r.fromArray(e),clone:r.clone,func:function(){return i.value}};return i}function je(e,t){var r={value:i.fromArray(e),clone:i.clone,func:function(){return r.value}};return r}function Ye(e,t){var r={value:w.fromColumnMajorArray(e),clone:w.clone,func:function(){return r.value}};return r}function Xe(e,t){var r={value:T.fromColumnMajorArray(e),clone:T.clone,func:function(){return r.value}};return r}function Ze(e,t){var r={value:b.fromColumnMajorArray(e),clone:b.clone,func:function(){return r.value}};return r}function Ke(e,t){var r={value:t._rendererResources.textures[e],clone:function(e,t){return e},func:function(){return r.value}};return r}function Je(e,t,r,i){var n=t._runtime.nodes[e];return Rt[r](i,t,n)}function Qe(e,t){var r=e._loadResources;if(r.finishedTextureCreation()&&r.finishedProgramCreation()&&r.createUniformMaps){r.createUniformMaps=!1;var i=e.gltf,n=i.materials,o=i.techniques,a=(i.programs,e._uniformMaps);for(var s in n)if(n.hasOwnProperty(s)){var u,c=n[s],h=c.values,d=o[c.technique],p=d.parameters,m=d.uniforms,f={},v={};for(var _ in m)if(m.hasOwnProperty(_)){var g=m[_],y=p[g];if(l(h[g])){var C=Dt[y.type](h[g],e);f[_]=C.func,v[g]=C}else if(l(y.node))f[_]=Je(y.node,e,y.semantic,t.uniformState);else if(l(y.semantic))"JOINTMATRIX"!==y.semantic?f[_]=Mt[y.semantic](t.uniformState,e):u=_;else if(l(y.value)){var E=Dt[y.type](y.value,e);f[_]=E.func,v[g]=E}}var S=a[s];S.uniformMap=f,S.values=v,S.jointMatrixUniformName=u}}}function $e(e){return function(){return e}}function et(e){return function(){return e.computedJointMatrices}}function tt(t,i,n,u){for(var c=t._nodeCommands,h=t._pickIds,d=t.allowPicking,p=t._runtime.meshesByName,m=(t.debugShowBoundingVolume,t._rendererResources),f=m.vertexArrays,v=m.programs,g=m.pickPrograms,y=m.renderStates,C=t._uniformMaps,E=t.gltf,S=E.accessors,w=E.meshes,T=E.techniques,x=E.materials,P=i.meshes,A=P.length,I=0;A>I;++I)for(var M=P[I],D=w[M],O=D.primitives,N=O.length,L=0;N>L;++L){var F,B=O[L],V=S[B.indices],z=x[B.material],k=T[z.technique],U=B.attributes.POSITION;if(l(U)){var G=S[U];F=e.fromCornerPoints(r.fromArray(G.min),r.fromArray(G.max))}var W,H,j=f[M+".primitive."+L];if(l(V))H=V.count,W=V.byteOffset/_.getSizeInBytes(V.componentType);else{var Y=S[B.attributes.POSITION];H=Y.count;var X=q(Y);W=Y.byteOffset/(X.componentsPerAttribute*a.getSizeInBytes(Y.componentType))}var Z=C[B.material],K=Z.uniformMap;if(l(Z.jointMatrixUniformName)){var J={};J[Z.jointMatrixUniformName]=et(n),K=o(K,J)}var $,ee=y[z.technique],te=ee.blending.enabled,re={primitive:s(t.pickPrimitive,t),id:t.id,node:n.publicNode,mesh:p[D.name]},ie=new R({boundingVolume:new e,modelMatrix:new b,primitiveType:B.mode,vertexArray:j,count:H,offset:W,shaderProgram:v[k.program],uniformMap:K,renderState:ee,owner:re,pass:te?Q.TRANSLUCENT:Q.OPAQUE});if(d){var ne=u.createPickId(re);h.push(ne);var oe=o(K,{czm_pickColor:$e(ne.color)});$=new R({boundingVolume:new e,modelMatrix:new b,primitiveType:B.mode,vertexArray:j,count:H,offset:W,shaderProgram:g[k.program],uniformMap:oe,renderState:ee,owner:re,pass:te?Q.TRANSLUCENT:Q.OPAQUE})}var ae={show:!0,boundingSphere:F,command:ie,pickCommand:$};n.commands.push(ae),c.push(ae)}}function rt(e,t){var i=e._loadResources;if(i.finishedPendingLoads()&&i.finishedResourceCreation()&&i.createRuntimeNodes){i.createRuntimeNodes=!1;for(var n=[],o=e._runtime.nodes,a=e.gltf,s=(a.asset.version,a.nodes),u=a.scenes[a.scene],c=u.nodes,h=c.length,d=[],p=(new r,0);h>p;++p)for(d.push({parentRuntimeNode:void 0,gltfNode:s[c[p]],id:c[p]});d.length>0;){var m=d.pop(),f=m.parentRuntimeNode,v=m.gltfNode,_=o[m.id];if(0===_.parents.length)if(l(v.matrix))_.matrix=b.fromColumnMajorArray(v.matrix);else{var g=v.rotation;_.translation=r.fromArray(v.translation),_.rotation=P.unpack(g),_.scale=r.fromArray(v.scale)}l(f)?(f.children.push(_),_.parents.push(f)):n.push(_),l(v.meshes)&&tt(e,v,_,t);for(var y=v.children,C=y.length,E=0;C>E;++E)d.push({parentRuntimeNode:_,gltfNode:s[y[E]],id:y[E]})}e._runtime.rootNodes=n,e._runtime.nodes=o}}function it(e,t){if(e._loadRendererResourcesFromCache){var r=e._rendererResources,i=e._cachedRendererResources;r.buffers=i.buffers,r.vertexArrays=i.vertexArrays,r.programs=i.programs,r.pickPrograms=i.pickPrograms,r.textures=i.textures,r.samplers=i.samplers,r.renderStates=i.renderStates}else Te(e,t),Ae(e,t),De(e,t),Me(e),Oe(e,t);Be(e),ze(e),e._loadRendererResourcesFromCache||(ke(e,t),Ge(e,t)),Qe(e,t),rt(e,t)}function nt(e,t){var r=e.publicNode,i=r.matrix;r.useMatrix&&l(i)?b.clone(i,t):l(e.matrix)?b.clone(e.matrix,t):(b.fromTranslationQuaternionRotationScale(e.translation,e.rotation,e.scale,t),r.setMatrix(t))}function ot(t,i,n){for(var o=t._maxDirtyNumber,a=t.allowPicking,s=t._runtime.rootNodes,u=s.length,c=Ot,h=t._computedModelMatrix,d=0;u>d;++d){var p=s[d];for(nt(p,p.transformToRoot),c.push(p);c.length>0;){p=c.pop();var m=p.transformToRoot,f=p.commands;if(p.dirtyNumber===o||i||n){var v=f.length;if(v>0)for(var _=0;v>_;++_){var g=f[_],y=g.command;if(b.multiplyTransformation(h,m,y.modelMatrix),e.transform(g.boundingSphere,y.modelMatrix,y.boundingVolume),l(t._rtcCenter)&&r.add(t._rtcCenter,y.boundingVolume.center,y.boundingVolume.center),a){var C=g.pickCommand;b.clone(y.modelMatrix,C.modelMatrix),e.clone(y.boundingVolume,C.boundingVolume)}}else p.computedMatrix=b.multiplyTransformation(h,m,p.computedMatrix)}for(var E=p.children,S=E.length,w=0;S>w;++w){var T=E[w];T.dirtyNumber=Math.max(T.dirtyNumber,p.dirtyNumber),(T.dirtyNumber===o||n)&&(nt(T,T.transformToRoot),b.multiplyTransformation(m,T.transformToRoot,T.transformToRoot)),c.push(T)}}}++t._maxDirtyNumber}function at(e){for(var t=e._runtime.skinnedNodes,r=t.length,i=0;r>i;++i){var n=t[i];Nt=b.inverseTransformation(n.transformToRoot,Nt);for(var o=n.computedJointMatrices,a=n.joints,s=n.bindShapeMatrix,u=n.inverseBindMatrices,c=u.length,h=0;c>h;++h)l(o[h])||(o[h]=new b),o[h]=b.multiplyTransformation(Nt,a[h].transformToRoot,o[h]),o[h]=b.multiplyTransformation(o[h],u[h],o[h]),l(s)&&(o[h]=b.multiplyTransformation(o[h],s,o[h]))}}function st(e){for(var t=e._runtime.rootNodes,r=t.length,i=Ot,n=0;r>n;++n){var o=t[n];for(o.computedShow=o.publicNode.show,i.push(o);i.length>0;){o=i.pop();for(var a=o.computedShow,s=o.commands,l=s.length,u=0;l>u;++u)s[u].show=a;for(var c=o.children,h=c.length,d=0;h>d;++d){var p=c[d];p.computedShow=a&&p.publicNode.show,i.push(p)}}}}function lt(e,t){var r=e.id;if(e._id!==r){e._id=r;for(var i=e._pickIds,n=i.length,o=0;n>o;++o)i[o].object.id=r}}function ut(e){if(e._debugWireframe!==e.debugWireframe){e._debugWireframe=e.debugWireframe;for(var t=e.debugWireframe?x.LINES:x.TRIANGLES,r=e._nodeCommands,i=r.length,n=0;i>n;++n)r[n].command.primitiveType=t}}function ct(e){if(e.debugShowBoundingVolume!==e._debugShowBoundingVolume){e._debugShowBoundingVolume=e.debugShowBoundingVolume;for(var t=e.debugShowBoundingVolume,r=e._nodeCommands,i=r.length,n=0;i>n;n++)r[n].command.debugShowBoundingVolume=t}}function ht(e,t,r){Ft.center=e,Ft.radius=t;var i=r.camera,n=i.distanceToBoundingSphere(Ft),o=r.context,a=i.frustum.getPixelDimensions(o.drawingBufferWidth,o.drawingBufferHeight,n,Lt),s=Math.max(a.x,a.y);return s}function dt(e,t){var i=e.scale;if(0!==e.minimumPixelSize){var n=t.context,o=Math.max(n.drawingBufferWidth,n.drawingBufferHeight),a=e.modelMatrix;Bt.x=a[12],Bt.y=a[13],Bt.z=a[14],l(e._rtcCenter)&&r.add(e._rtcCenter,Bt,Bt);var s=e.boundingSphere.radius,u=ht(Bt,s,t),c=1/u,h=Math.min(2*c*s,o);hi;++i){var n=t[i];"CESIUM_RTC"!==n&&"CESIUM_binary_glTF"!==n&&"KHR_binary_glTF"!==n&&"KHR_materials_common"!==n?(e._loadError=new I("Unsupported glTF Extension: "+n),e._state=yt.FAILED):"CESIUM_binary_glTF"===n&&c("CESIUM_binary_glTF extension","Use of the CESIUM_binary_glTF extension has been deprecated. Use the KHR_binary_glTF extension instead.")}}function ft(e){for(var t in e)e.hasOwnProperty(t)&&e[t].destroy()}function vt(e){ft(e.buffers),ft(e.vertexArrays),ft(e.programs),ft(e.pickPrograms),ft(e.textures)}if(!m.supportsTypedArrays())return{};var _t=b.fromRotationTranslation(T.fromRotationX(S.PI_OVER_TWO)),gt=new r,yt={NEEDS_LOAD:0,LOADING:1,LOADED:2,FAILED:3},Ct="model/vnd.gltf.binary,model/vnd.gltf+json,model/gltf.binary,model/gltf+json;q=0.8,application/json;q=0.2,*/*;q=0.01";ee.prototype.getBuffer=function(e){return oe(this.buffers[e.buffer],e.byteOffset,e.byteLength)},ee.prototype.finishedPendingLoads=function(){return 0===this.pendingBufferLoads&&0===this.pendingShaderLoads&&0===this.pendingTextureLoads},ee.prototype.finishedResourceCreation=function(){return 0===this.buffersToCreate.length&&0===this.programsToCreate.length&&0===this.texturesToCreate.length&&0===this.texturesToCreateFromBufferView.length&&0===this.pendingBufferViewToImage},ee.prototype.finishedBuffersCreation=function(){return 0===this.pendingBufferLoads&&0===this.buffersToCreate.length},ee.prototype.finishedProgramCreation=function(){return 0===this.pendingShaderLoads&&0===this.programsToCreate.length},ee.prototype.finishedTextureCreation=function(){return 0===this.pendingTextureLoads&&0===this.texturesToCreate.length&&0===this.texturesToCreateFromBufferView.length&&0===this.pendingBufferViewToImage};var Et=function(e){this._gltf=X(G(e.gltf)),this._bgltf=e.bgltf,this.ready=e.ready,this.modelsToLoad=[],this.count=0};u(Et.prototype,{gltf:{set:function(e){this._gltf=X(G(e))},get:function(){return this._gltf}},bgltf:{get:function(){return this._bgltf}}}),Et.prototype.makeReady=function(e,t){this.gltf=e,this._bgltf=t;for(var r=this.modelsToLoad,i=r.length,n=0;i>n;++n){var o=r[n];o.isDestroyed()||te(o,this)}this.modelsToLoad=void 0,this.ready=!0};var St={},wt=function(t){t=s(t,s.EMPTY_OBJECT);var r=t.cacheKey;this._cacheKey=r,this._cachedGltf=void 0,this._releaseGltfJson=s(t.releaseGltfJson,!1),this._animationIds=void 0;var i;if(l(r)&&l(St[r])&&St[r].ready)i=St[r],++i.count;else{var n=t.gltf;if(l(n)){if(n instanceof ArrayBuffer&&(n=new Uint8Array(n)),n instanceof Uint8Array){var o=se(n);0!==o.binaryOffset&&(n=new Uint8Array(n.buffer,o.binaryOffset)),i=new Et({gltf:o.glTF,bgltf:n,ready:!0})}else i=new Et({gltf:t.gltf,ready:!0});i.count=1,l(r)&&(St[r]=i)}}te(this,i),this._basePath=s(t.basePath,"");var a=new W(document.location.href),u=new W(this._basePath);this._baseUri=u.resolve(a),this.show=s(t.show,!0),this.modelMatrix=b.clone(s(t.modelMatrix,b.IDENTITY)),this._modelMatrix=b.clone(this.modelMatrix),this.scale=s(t.scale,1),this._scale=this.scale,this.minimumPixelSize=s(t.minimumPixelSize,0),this._minimumPixelSize=this.minimumPixelSize,this.maximumScale=t.maximumScale,this._maximumScale=this.maximumScale,this.id=t.id,this._id=t.id,this.pickPrimitive=t.pickPrimitive,this._allowPicking=s(t.allowPicking,!0),this._ready=!1,this._readyPromise=H.defer(),this.activeAnimations=new Y(this),this._asynchronous=s(t.asynchronous,!0),this.debugShowBoundingVolume=s(t.debugShowBoundingVolume,!1),this._debugShowBoundingVolume=!1,this.debugWireframe=s(t.debugWireframe,!1),this._debugWireframe=!1,this._computedModelMatrix=new b,this._initialRadius=void 0,this._boundingSphere=void 0,this._scaledBoundingSphere=new e,this._state=yt.NEEDS_LOAD,this._loadError=void 0,this._loadResources=void 0,this._perNodeShowDirty=!1,this._cesiumAnimationsDirty=!1,this._maxDirtyNumber=0,this._runtime={animations:void 0,rootNodes:void 0,nodes:void 0,nodesByName:void 0,skinnedNodes:void 0,meshesByName:void 0,materialsByName:void 0,materialsById:void 0},this._uniformMaps={},this._rendererResources={buffers:{},vertexArrays:{},programs:{},pickPrograms:{},textures:{},samplers:{},renderStates:{}},this._cachedRendererResources=void 0,this._loadRendererResourcesFromCache=!1,this._nodeCommands=[],this._pickIds=[],this._rtcCenter=void 0,this._rtcCenterEye=void 0};u(wt.prototype,{gltf:{get:function(){return l(this._cachedGltf)?this._cachedGltf.gltf:void 0}},releaseGltfJson:{get:function(){return this._releaseGltfJson}},cacheKey:{get:function(){return this._cacheKey}},basePath:{get:function(){return this._basePath}},boundingSphere:{get:function(){var e=b.getScale(this.modelMatrix,gt),t=l(this.maximumScale)?Math.min(this.maximumScale,this.scale):this.scale;r.multiplyByScalar(e,t,e);var i=this._scaledBoundingSphere;return i.center=r.multiplyComponents(this._boundingSphere.center,e,i.center),i.radius=r.maximumComponent(e)*this._initialRadius,l(this._rtcCenter)&&r.add(this._rtcCenter,i.center,i.center),i}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},asynchronous:{get:function(){return this._asynchronous}},allowPicking:{get:function(){return this._allowPicking}}});var Tt=Uint32Array.BYTES_PER_ELEMENT;wt.fromGltf=function(e){var t=e.url,r=s(e.cacheKey,ne(t));e=n(e),e.basePath=ie(t),e.cacheKey=r;var i=new wt(e);e.headers=l(e.headers)?n(e.headers):{},l(e.headers.Accept)||(e.headers.Accept=Ct);var o=St[r];return l(o)?o.ready||(++o.count,o.modelsToLoad.push(i)):(o=new Et({ready:!1}),o.count=1,o.modelsToLoad.push(i),te(i,o),St[r]=o,g(t,e.headers).then(function(e){var t=new Uint8Array(e);if(ae(t)){var r=se(t);0!==r.binaryOffset&&(t=new Uint8Array(e,r.binaryOffset)),o.makeReady(r.glTF,t)}else{var i=v(t);o.makeReady(JSON.parse(i))}}).otherwise(ce(i,"model",t))),i},wt._gltfCache=St,wt.prototype.getNode=function(e){var t=le(this,"nodesByName",e);return l(t)?t.publicNode:void 0},wt.prototype.getMesh=function(e){return le(this,"meshesByName",e)},wt.prototype.getMaterial=function(e){return le(this,"materialsByName",e)};var bt=new r,xt=new r,Pt=new r,At=new P,It=new r,Mt={MODEL:function(e,t){return function(){return e.model}},VIEW:function(e,t){return function(){return e.view}},PROJECTION:function(e,t){return function(){return e.projection}},MODELVIEW:function(e,t){return function(){return e.modelView}},CESIUM_RTC_MODELVIEW:function(e,t){var r=new b;return function(){return b.setTranslation(e.modelView,t._rtcCenterEye,r)}},MODELVIEWPROJECTION:function(e,t){return function(){return e.modelViewProjection}},MODELINVERSE:function(e,t){return function(){return e.inverseModel}},VIEWINVERSE:function(e,t){return function(){return e.inverseView}},PROJECTIONINVERSE:function(e,t){return function(){return e.inverseProjection}},MODELVIEWINVERSE:function(e,t){return function(){return e.inverseModelView}},MODELVIEWPROJECTIONINVERSE:function(e,t){return function(){return e.inverseModelViewProjection}},MODELINVERSETRANSPOSE:function(e,t){return function(){return e.inverseTranposeModel}},MODELVIEWINVERSETRANSPOSE:function(e,t){return function(){return e.normal}},VIEWPORT:function(e,t){return function(){return e.viewportCartesian4}}},Dt={};"undefined"!=typeof WebGLRenderingContext&&(Dt[U.FLOAT]=We,Dt[U.FLOAT_VEC2]=He,Dt[U.FLOAT_VEC3]=qe,Dt[U.FLOAT_VEC4]=je,Dt[U.INT]=We,Dt[U.INT_VEC2]=He,Dt[U.INT_VEC3]=qe,Dt[U.INT_VEC4]=je,Dt[U.BOOL]=We,Dt[U.BOOL_VEC2]=He,Dt[U.BOOL_VEC3]=qe,Dt[U.BOOL_VEC4]=je,Dt[U.FLOAT_MAT2]=Ye,Dt[U.FLOAT_MAT3]=Xe,Dt[U.FLOAT_MAT4]=Ze,Dt[U.SAMPLER_2D]=Ke);var Rt={MODEL:function(e,t,r){return function(){return r.computedMatrix}},VIEW:function(e,t,r){return function(){return e.view}},PROJECTION:function(e,t,r){return function(){return e.projection}},MODELVIEW:function(e,t,r){var i=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i)}},CESIUM_RTC_MODELVIEW:function(e,t,r){var i=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.setTranslation(i,t._rtcCenterEye,i)}},MODELVIEWPROJECTION:function(e,t,r){var i=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.multiply(e._projection,i,i)}},MODELINVERSE:function(e,t,r){var i=new b;return function(){return b.inverse(r.computedMatrix,i)}},VIEWINVERSE:function(e,t){return function(){return e.inverseView}},PROJECTIONINVERSE:function(e,t,r){return function(){return e.inverseProjection}},MODELVIEWINVERSE:function(e,t,r){var i=new b,n=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.inverse(i,n)}},MODELVIEWPROJECTIONINVERSE:function(e,t,r){var i=new b,n=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.multiply(e._projection,i,i),b.inverse(i,n)}},MODELINVERSETRANSPOSE:function(e,t,r){var i=new b,n=new T;return function(){return b.inverse(r.computedMatrix,i),b.getRotation(i,n),T.transpose(n,n)}},MODELVIEWINVERSETRANSPOSE:function(e,t,r){var i=new b,n=new b,o=new T;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.inverse(i,n),b.getRotation(n,o),T.transpose(o,o)}},VIEWPORT:function(e,t,r){return function(){return e.viewportCartesian4}}},Ot=[],Nt=new b,Lt=new t,Ft=new e,Bt=new r,Vt=function(e,t){this.buffers=void 0,this.vertexArrays=void 0,this.programs=void 0,this.pickPrograms=void 0,this.textures=void 0,this.samplers=void 0,this.renderStates=void 0,this.ready=!1,this.context=e,this.cacheKey=t,this.count=0};return Vt.prototype.release=function(){return 0===--this.count?(l(this.cacheKey)&&delete this.context.cache.modelRendererResourceCache[this.cacheKey],vt(this),h(this)):void 0},wt.prototype.update=function(e){if(e.mode===$.SCENE3D){var t=e.context;if(this._state===yt.NEEDS_LOAD&&l(this.gltf)){var i,n=this.cacheKey;if(l(n)){t.cache.modelRendererResourceCache=s(t.cache.modelRendererResourceCache,{});var o=t.cache.modelRendererResourceCache;if(i=o[this.cacheKey],l(i)){if(!i.ready)return;++i.count,this._loadRendererResourcesFromCache=!0}else i=new Vt(t,n),i.count=1,o[this.cacheKey]=i;this._cachedRendererResources=i}else i=new Vt(t),i.count=1,this._cachedRendererResources=i;if(this._state=yt.LOADING,this._boundingSphere=ue(this.gltf),this._initialRadius=this._boundingSphere.radius,mt(this),this._state!==yt.FAILED){var a=this.gltf.extensions;l(a)&&l(a.CESIUM_RTC)&&(this._rtcCenter=r.fromArray(a.CESIUM_RTC.center),this._rtcCenterEye=new r),this._loadResources=new ee,we(this)}}var u=!1;if(this._state===yt.FAILED)throw this._loadError;if(this._state===yt.LOADING){it(this,t);var c=this._loadResources;if(c.finishedPendingLoads()&&c.finishedResourceCreation()){this._state=yt.LOADED,this._loadResources=void 0;var h=this._rendererResources,d=this._cachedRendererResources;d.buffers=h.buffers,d.vertexArrays=h.vertexArrays,d.programs=h.programs,d.pickPrograms=h.pickPrograms,d.textures=h.textures,d.samplers=h.samplers, +d.renderStates=h.renderStates,d.ready=!0,this.releaseGltfJson&&pt(this),u=!0}}var p=this.show&&0!==this.scale;if(p&&this._state===yt.LOADED||u){var m=this.activeAnimations.update(e)||this._cesiumAnimationsDirty;this._cesiumAnimationsDirty=!1;var f=!b.equals(this._modelMatrix,this.modelMatrix)||this._scale!==this.scale||this._minimumPixelSize!==this.minimumPixelSize||0!==this.minimumPixelSize||this._maximumScale!==this.maximumScale;if(f||u){b.clone(this.modelMatrix,this._modelMatrix),this._scale=this.scale,this._minimumPixelSize=this.minimumPixelSize,this._maximumScale=this.maximumScale;var v=dt(this,e),_=this._computedModelMatrix;b.multiplyByUniformScale(this.modelMatrix,v,_),b.multiplyTransformation(_,_t,_)}(m||f||u)&&(ot(this,f,u),(m||u)&&at(this)),this._perNodeShowDirty&&(this._perNodeShowDirty=!1,st(this)),lt(this,t),ut(this),ct(this),l(this._rtcCenter)&&b.multiplyByPoint(e.camera.viewMatrix,this._rtcCenter,this._rtcCenterEye)}if(u){var g=this;return void e.afterRender.push(function(){g._ready=!0,g._readyPromise.resolve(g)})}if(p){var y,C,E=e.commandList,S=e.passes,w=this._nodeCommands,T=w.length;if(S.render)for(y=0;T>y;++y)C=w[y],C.show&&E.push(C.command);if(S.pick)for(y=0;T>y;++y)C=w[y],C.show&&E.push(C.pickCommand)}}},wt.prototype.isDestroyed=function(){return!1},wt.prototype.destroy=function(){this._rendererResources=void 0,this._cachedRendererResources=this._cachedRendererResources&&this._cachedRendererResources.release();for(var e=this._pickIds,t=e.length,r=0;t>r;++r)e[r].destroy();return pt(this),h(this)},wt}),r("DataSources/ModelVisualizer",["../Core/AssociativeArray","../Core/BoundingSphere","../Core/Cartesian3","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Matrix4","../Scene/Model","../Scene/ModelAnimationLoop","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t,r,n){var o=r[t.id];i(o)&&(n.removeAndDestroy(o.modelPrimitive),delete r[t.id])}function d(e){e.activeAnimations.addAll({loop:l.REPEAT})}function p(e){console.error(e)}var m=1,f=0,v=function(t,r){r.collectionChanged.addEventListener(v.prototype._onCollectionChanged,this),this._scene=t,this._primitives=t.primitives,this._entityCollection=r,this._modelHash={},this._entitiesToVisualize=new e,this._modelMatrixScratch=new a,this._onCollectionChanged(r,r.values,[],[])};return v.prototype.update=function(e){for(var t=(this._scene.context,this._entitiesToVisualize.values),r=this._modelHash,n=this._primitives,o=(this._scene,0),l=t.length;l>o;o++){var u,h,v=t[o],_=v._model,g=r[v.id],y=v.isShowing&&v.isAvailable(e)&&c.getValueOrDefault(_._show,e,!0);if(y&&(h=v._getModelMatrix(e,this._modelMatrixScratch),u=c.getValueOrUndefined(_._uri,e),y=i(h)&&i(u)),y){var C=i(g)?g.modelPrimitive:void 0;i(C)&&u===g.uri||(i(C)&&(n.removeAndDestroy(C),delete r[v.id]),C=s.fromGltf({url:u}),C.readyPromise.then(d).otherwise(p),C.id=v,n.add(C),g={modelPrimitive:C,uri:u},r[v.id]=g),C.show=!0,C.scale=c.getValueOrDefault(_._scale,e,m),C.minimumPixelSize=c.getValueOrDefault(_._minimumPixelSize,e,f),C.maximumScale=c.getValueOrUndefined(_._maximumScale,e),C.modelMatrix=a.clone(h,C.modelMatrix)}else i(g)&&(g.modelPrimitive.show=!1)}return!0},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){this._entityCollection.collectionChanged.removeEventListener(v.prototype._onCollectionChanged,this);for(var e=this._entitiesToVisualize.values,t=this._modelHash,r=this._primitives,i=e.length-1;i>-1;i--)h(this,e[i],t,r);return n(this)},v.prototype.getBoundingSphere=function(e,r){var n=this._modelHash[e.id];if(!i(n))return u.FAILED;var o=n.modelPrimitive;return i(o)&&o.show?o.ready?(t.transform(o.boundingSphere,o.modelMatrix,r),u.DONE):u.PENDING:u.FAILED},v.prototype._onCollectionChanged=function(e,t,r,n){var o,a,s=this._entitiesToVisualize,l=this._modelHash,u=this._primitives;for(o=t.length-1;o>-1;o--)a=t[o],i(a._model)&&i(a._position)&&s.set(a.id,a);for(o=n.length-1;o>-1;o--)a=n[o],i(a._model)&&i(a._position)?s.set(a.id,a):(h(this,a,l,u),s.remove(a.id));for(o=r.length-1;o>-1;o--)a=r[o],h(this,a,l,u),s.remove(a.id)},v}),r("Shaders/PolylineCommon",[],function(){"use strict";return"void clipLineSegmentToNearPlane(\nvec3 p0,\nvec3 p1,\nout vec4 positionWC,\nout bool clipped,\nout bool culledByNearPlane)\n{\nculledByNearPlane = false;\nclipped = false;\nvec3 p1ToP0 = p1 - p0;\nfloat magnitude = length(p1ToP0);\nvec3 direction = normalize(p1ToP0);\nfloat endPoint0Distance = -(czm_currentFrustum.x + p0.z);\nfloat denominator = -direction.z;\nif (endPoint0Distance < 0.0 && abs(denominator) < czm_epsilon7)\n{\nculledByNearPlane = true;\n}\nelse if (endPoint0Distance < 0.0 && abs(denominator) > czm_epsilon7)\n{\nfloat t = (czm_currentFrustum.x + p0.z) / denominator;\nif (t < 0.0 || t > magnitude)\n{\nculledByNearPlane = true;\n}\nelse\n{\np0 = p0 + t * direction;\nclipped = true;\n}\n}\npositionWC = czm_eyeToWindowCoordinates(vec4(p0, 1.0));\n}\nvec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious) {\nvec4 endPointWC, p0, p1;\nbool culledByNearPlane, clipped;\nvec4 positionEC = czm_modelViewRelativeToEye * position;\nvec4 prevEC = czm_modelViewRelativeToEye * previous;\nvec4 nextEC = czm_modelViewRelativeToEye * next;\nclipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, p0, clipped, culledByNearPlane);\nclipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, p1, clipped, culledByNearPlane);\nclipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, endPointWC, clipped, culledByNearPlane);\nif (culledByNearPlane)\n{\nreturn vec4(0.0, 0.0, 0.0, 1.0);\n}\nvec2 prevWC = normalize(p0.xy - endPointWC.xy);\nvec2 nextWC = normalize(p1.xy - endPointWC.xy);\nfloat expandWidth = width * 0.5;\nvec2 direction;\nif (czm_equalsEpsilon(normalize(previous.xyz - position.xyz), vec3(0.0), czm_epsilon1) || czm_equalsEpsilon(prevWC, -nextWC, czm_epsilon1))\n{\ndirection = vec2(-nextWC.y, nextWC.x);\n}\nelse if (czm_equalsEpsilon(normalize(next.xyz - position.xyz), vec3(0.0), czm_epsilon1) || clipped)\n{\ndirection = vec2(prevWC.y, -prevWC.x);\n}\nelse\n{\nvec2 normal = vec2(-nextWC.y, nextWC.x);\ndirection = normalize((nextWC + prevWC) * 0.5);\nif (dot(direction, normal) < 0.0)\n{\ndirection = -direction;\n}\nfloat sinAngle = abs(direction.x * nextWC.y - direction.y * nextWC.x);\nexpandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);\n}\nvec2 offset = direction * expandDirection * expandWidth * czm_resolutionScale;\nreturn vec4(endPointWC.xy + offset, -endPointWC.z, 1.0);\n}\n"}),r("Shaders/PolylineFS",[],function(){"use strict";return"varying vec2 v_st;\nvoid main()\n{\nczm_materialInput materialInput;\nmaterialInput.s = v_st.s;\nmaterialInput.st = v_st;\nmaterialInput.str = vec3(v_st, 0.0);\nczm_material material = czm_getMaterial(materialInput);\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n}\n"}),r("Shaders/PolylineVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 position2DHigh;\nattribute vec3 position2DLow;\nattribute vec3 prevPosition3DHigh;\nattribute vec3 prevPosition3DLow;\nattribute vec3 prevPosition2DHigh;\nattribute vec3 prevPosition2DLow;\nattribute vec3 nextPosition3DHigh;\nattribute vec3 nextPosition3DLow;\nattribute vec3 nextPosition2DHigh;\nattribute vec3 nextPosition2DLow;\nattribute vec4 texCoordExpandWidthAndShow;\nattribute vec4 pickColor;\nvarying vec2 v_st;\nvarying float v_width;\nvarying vec4 czm_pickColor;\nvoid main()\n{\nfloat texCoord = texCoordExpandWidthAndShow.x;\nfloat expandDir = texCoordExpandWidthAndShow.y;\nfloat width = abs(texCoordExpandWidthAndShow.z) + 0.5;\nbool usePrev = texCoordExpandWidthAndShow.z < 0.0;\nfloat show = texCoordExpandWidthAndShow.w;\nvec4 p, prev, next;\nif (czm_morphTime == 1.0)\n{\np = czm_translateRelativeToEye(position3DHigh.xyz, position3DLow.xyz);\nprev = czm_translateRelativeToEye(prevPosition3DHigh.xyz, prevPosition3DLow.xyz);\nnext = czm_translateRelativeToEye(nextPosition3DHigh.xyz, nextPosition3DLow.xyz);\n}\nelse if (czm_morphTime == 0.0)\n{\np = czm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy);\nprev = czm_translateRelativeToEye(prevPosition2DHigh.zxy, prevPosition2DLow.zxy);\nnext = czm_translateRelativeToEye(nextPosition2DHigh.zxy, nextPosition2DLow.zxy);\n}\nelse\n{\np = czm_columbusViewMorph(\nczm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy),\nczm_translateRelativeToEye(position3DHigh.xyz, position3DLow.xyz),\nczm_morphTime);\nprev = czm_columbusViewMorph(\nczm_translateRelativeToEye(prevPosition2DHigh.zxy, prevPosition2DLow.zxy),\nczm_translateRelativeToEye(prevPosition3DHigh.xyz, prevPosition3DLow.xyz),\nczm_morphTime);\nnext = czm_columbusViewMorph(\nczm_translateRelativeToEye(nextPosition2DHigh.zxy, nextPosition2DLow.zxy),\nczm_translateRelativeToEye(nextPosition3DHigh.xyz, nextPosition3DLow.xyz),\nczm_morphTime);\n}\nvec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\ngl_Position = czm_viewportOrthographic * positionWC * show;\nv_st = vec2(texCoord, clamp(expandDir, 0.0, 1.0));\nv_width = width;\nczm_pickColor = pickColor;\n}\n"}),r("Scene/Polyline",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix4","../Core/PolylinePipeline","./Material"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){++e._propertiesChanged[t];var r=e._polylineCollection;n(r)&&(r._updatePolyline(e,t),e._dirty=!0)}var h=function(o,a){o=i(o,i.EMPTY_OBJECT),this._show=i(o.show,!0),this._width=i(o.width,1),this._loop=i(o.loop,!1),this._material=o.material,n(this._material)||(this._material=u.fromType(u.ColorType,{color:new r(1,1,1,1)}));var c=o.positions;n(c)||(c=[]),this._positions=c,this._actualPositions=l.removeDuplicates(c),this._loop&&this._actualPositions.length>2&&(this._actualPositions===this._positions&&(this._actualPositions=c.slice()),this._actualPositions.push(t.clone(this._actualPositions[0]))),this._length=this._actualPositions.length,this._id=o.id;var h;n(a)&&(h=s.clone(a.modelMatrix)),this._modelMatrix=h,this._segments=l.wrapLongitude(this._actualPositions,h),this._actualLength=void 0,this._propertiesChanged=new Uint32Array(_),this._polylineCollection=a,this._dirty=!1,this._pickId=void 0,this._boundingVolume=e.fromPoints(this._actualPositions),this._boundingVolumeWC=e.transform(this._boundingVolume,this._modelMatrix),this._boundingVolume2D=new e},d=h.SHOW_INDEX=0,p=h.WIDTH_INDEX=1,m=h.POSITION_INDEX=2,f=h.MATERIAL_INDEX=3,v=h.POSITION_SIZE_INDEX=4,_=h.NUMBER_OF_PROPERTIES=5;return o(h.prototype,{show:{get:function(){return this._show},set:function(e){e!==this._show&&(this._show=e,c(this,d))}},positions:{get:function(){return this._positions},set:function(r){var i=l.removeDuplicates(r);this._loop&&i.length>2&&(i===r&&(i=r.slice()),i.push(t.clone(i[0]))),(this._actualPositions.length!==i.length||this._actualPositions.length!==this._length)&&c(this,v),this._positions=r,this._actualPositions=i,this._length=i.length,this._boundingVolume=e.fromPoints(this._actualPositions,this._boundingVolume),this._boundingVolumeWC=e.transform(this._boundingVolume,this._modelMatrix,this._boundingVolumeWC),c(this,m),this.update()}},material:{get:function(){return this._material},set:function(e){this._material!==e&&(this._material=e,c(this,f))}},width:{get:function(){return this._width},set:function(e){var t=this._width;e!==t&&(this._width=e,c(this,p))}},loop:{get:function(){return this._loop},set:function(e){if(e!==this._loop){var r=this._actualPositions;e?r.length>2&&!t.equals(r[0],r[r.length-1])&&(r.length===this._positions.length&&(this._actualPositions=r=this._positions.slice()),r.push(t.clone(r[0]))):r.length>2&&t.equals(r[0],r[r.length-1])&&(r.length-1===this._positions.length?this._actualPositions=this._positions:r.pop()),this._loop=e,c(this,v)}}},id:{get:function(){return this._id},set:function(e){this._id=e,n(this._pickId)&&(this._pickId.object.id=e)}}}),h.prototype.update=function(){var t=s.IDENTITY;n(this._polylineCollection)&&(t=this._polylineCollection.modelMatrix);var r=this._segments.positions.length,i=this._segments.lengths,o=this._propertiesChanged[m]>0||this._propertiesChanged[v]>0;if((!s.equals(t,this._modelMatrix)||o)&&(this._segments=l.wrapLongitude(this._actualPositions,t),this._boundingVolumeWC=e.transform(this._boundingVolume,t,this._boundingVolumeWC)),this._modelMatrix=t,this._segments.positions.length!==r)c(this,v);else for(var a=i.length,u=0;a>u;++u)if(i[u]!==this._segments.lengths[u]){c(this,v);break}},h.prototype.getPickId=function(e){return n(this._pickId)||(this._pickId=e.createPickId({primitive:this,collection:this._polylineCollection,id:this._id})),this._pickId},h.prototype._clean=function(){this._dirty=!1;for(var e=this._propertiesChanged,t=0;_-1>t;++t)e[t]=0},h.prototype._destroy=function(){this._pickId=this._pickId&&this._pickId.destroy(),this._material=this._material&&this._material.destroy(),this._polylineCollection=void 0},h}),r("Scene/PolylineCollection",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EncodedCartesian3","../Core/IndexDatatype","../Core/Intersect","../Core/Math","../Core/Matrix4","../Core/Plane","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../Shaders/PolylineCommon","../Shaders/PolylineFS","../Shaders/PolylineVS","./BlendingState","./Material","./Pass","./Polyline","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D){"use strict";function R(t,r,i,n,o){for(var a=r.context,l=r.commandList,u=i.length,c=0,h=!0,d=t._vertexArrays,p=t.debugShowBoundingVolume,m=d.length,f=0;m>f;++f)for(var v=d[f],_=v.buckets,g=_.length,C=0;g>C;++C){for(var E,S,w,T=_[C],b=T.offset,x=o?T.bucket.shaderProgram:T.bucket.pickShaderProgram,P=T.bucket.polylines,A=P.length,M=0,R=0;A>R;++R){var O=P[R],N=L(O._material);if(N!==E){if(s(E)&&M>0){var F=S.isTranslucent();c>=u?(w=new y({owner:t}),i.push(w)):w=i[c],++c,w.boundingVolume=e.clone(Q,w.boundingVolume),w.modelMatrix=n,w.shaderProgram=x,w.vertexArray=v.va,w.renderState=F?t._translucentRS:t._opaqueRS,w.pass=F?I.TRANSLUCENT:I.OPAQUE,w.debugShowBoundingVolume=o?p:!1,w.uniformMap=S._uniforms,w.count=M,w.offset=b,b+=M,M=0,h=!0,l.push(w)}S=O._material,S.update(a),E=N}for(var B=O._locatorBuckets,V=B.length,z=0;V>z;++z){var k=B[z];k.locator===T&&(M+=k.count)}var U;r.mode===D.SCENE3D?U=O._boundingVolumeWC:r.mode===D.COLUMBUS_VIEW?U=O._boundingVolume2D:r.mode===D.SCENE2D?s(O._boundingVolume2D)&&(U=e.clone(O._boundingVolume2D,$),U.center.x=0):s(O._boundingVolumeWC)&&s(O._boundingVolume2D)&&(U=e.union(O._boundingVolumeWC,O._boundingVolume2D,$)),h?(h=!1,e.clone(U,Q)):e.union(U,Q,Q)}s(E)&&M>0&&(c>=u?(w=new y({owner:t}),i.push(w)):w=i[c],++c,w.boundingVolume=e.clone(Q,w.boundingVolume),w.modelMatrix=n,w.shaderProgram=x,w.vertexArray=v.va,w.renderState=S.isTranslucent()?t._translucentRS:t._opaqueRS,w.pass=S.isTranslucent()?I.TRANSLUCENT:I.OPAQUE,w.debugShowBoundingVolume=o?p:!1,w.uniformMap=S._uniforms,w.count=M,w.offset=b,h=!0,l.push(w)),E=void 0}i.length=c}function O(e){for(var t=e._buffersUsage,r=!1,i=e._propertiesChanged,n=0;Z-2>n;++n){var o=t[n];i[n]?o.bufferUsage!==g.STREAM_DRAW?(r=!0,o.bufferUsage=g.STREAM_DRAW,o.frameCount=100):o.frameCount=100:o.bufferUsage!==g.STATIC_DRAW&&(0===o.frameCount?(r=!0,o.bufferUsage=g.STATIC_DRAW):o.frameCount--)}return r}function N(e,t,r){e._createVertexArray=!1,z(e),k(e),F(e);var i,n,a=[[]],l=a[0],u=[0],c=0,h=[[]],p=0,f=e._polylineBuckets;for(i in f)f.hasOwnProperty(i)&&(n=f[i],n.updateShader(t),p+=n.lengthOfPositions);if(p>0){var v,y=e._mode,C=new Float32Array(6*p*3),E=new Uint8Array(4*p),S=new Float32Array(4*p),T=0,b=0,x=0;for(i in f)if(f.hasOwnProperty(i)){n=f[i],n.write(C,E,S,T,b,x,t,r),y===D.MORPHING&&(s(v)||(v=new Float32Array(6*p*3)),n.writeForMorph(v,T));var P=n.lengthOfPositions;T+=6*P*3,b+=4*P,x+=4*P,c=n.updateIndices(a,u,h,c)}var A=e._buffersUsage[j].bufferUsage,I=e._buffersUsage[H].bufferUsage,M=e._buffersUsage[q].bufferUsage,R=I===g.STREAM_DRAW||M===g.STREAM_DRAW?g.STREAM_DRAW:g.STATIC_DRAW;e._positionBuffer=_.createVertexBuffer({context:t,typedArray:C,usage:A});var O;s(v)&&(O=_.createVertexBuffer({context:t,typedArray:v,usage:A})),e._pickColorBuffer=_.createVertexBuffer({context:t,typedArray:E,usage:g.STATIC_DRAW}),e._texCoordExpandWidthAndShowBuffer=_.createVertexBuffer({context:t,typedArray:S,usage:R});for(var N=4*Uint8Array.BYTES_PER_ELEMENT,L=3*Float32Array.BYTES_PER_ELEMENT,B=4*Float32Array.BYTES_PER_ELEMENT,V=0,U=a.length,G=0;U>G;++G)if(l=a[G],l.length>0){var W=new Uint16Array(l),Y=_.createIndexBuffer({context:t,typedArray:W,usage:g.STATIC_DRAW,indexDatatype:d.UNSIGNED_SHORT});V+=u[G];var X,Z,J,Q,$=6*(G*L*m.SIXTY_FOUR_KILOBYTES-V*L),te=L+$,re=L+te,ie=L+re,ne=L+ie,oe=L+ne,ae=G*N*m.SIXTY_FOUR_KILOBYTES-V*N,se=G*B*m.SIXTY_FOUR_KILOBYTES-V*B,le=[{index:K.position3DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:$,strideInBytes:6*L},{index:K.position3DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:te,strideInBytes:6*L},{index:K.position2DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:$,strideInBytes:6*L},{index:K.position2DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:te,strideInBytes:6*L},{index:K.prevPosition3DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:re,strideInBytes:6*L},{index:K.prevPosition3DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ie,strideInBytes:6*L},{index:K.prevPosition2DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:re,strideInBytes:6*L},{index:K.prevPosition2DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ie,strideInBytes:6*L},{index:K.nextPosition3DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ne,strideInBytes:6*L},{index:K.nextPosition3DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:oe,strideInBytes:6*L},{index:K.nextPosition2DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ne,strideInBytes:6*L},{index:K.nextPosition2DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:oe,strideInBytes:6*L},{index:K.texCoordExpandWidthAndShow,componentsPerAttribute:4,componentDatatype:o.FLOAT,vertexBuffer:e._texCoordExpandWidthAndShowBuffer,offsetInBytes:se},{index:K.pickColor,componentsPerAttribute:4,componentDatatype:o.UNSIGNED_BYTE,vertexBuffer:e._pickColorBuffer,offsetInBytes:ae,normalize:!0}];y===D.SCENE3D?(X=e._positionBuffer,Z="vertexBuffer",J=ee,Q="value"):y===D.SCENE2D||y===D.COLUMBUS_VIEW?(X=ee,Z="value",J=e._positionBuffer,Q="vertexBuffer"):(X=O,Z="vertexBuffer",J=e._positionBuffer,Q="vertexBuffer"),le[0][Z]=X,le[1][Z]=X,le[2][Q]=J,le[3][Q]=J,le[4][Z]=X,le[5][Z]=X,le[6][Q]=J,le[7][Q]=J,le[8][Z]=X,le[9][Z]=X,le[10][Q]=J,le[11][Q]=J;var ue=new w({context:t,attributes:le,indexBuffer:Y});e._vertexArrays.push({va:ue,buckets:h[G]})}}}function L(e){var t=A._uniformList[e.type],r=t.length;te.length=2*r;for(var i=0,n=0;r>n;++n){var o=t[n];te[i]=o,te[i+1]=e._uniforms[o](),i+=2}return e.type+":"+JSON.stringify(te)}function F(e){for(var t=e._mode,r=e._modelMatrix,i=e._polylineBuckets={},n=e._polylines,o=n.length,a=0;o>a;++a){var l=n[a];if(l._actualPositions.length>1){l.update();var u=l.material,c=i[u.type];s(c)||(c=i[u.type]=new re(u,t,r)),c.addPolyline(l)}}}function B(e,t){var r=t.mode;e._mode===r&&f.equals(e._modelMatrix,e.modelMatrix)||(e._mode=r,e._modelMatrix=f.clone(e.modelMatrix),e._createVertexArray=!0)}function V(e){if(e._polylinesRemoved){e._polylinesRemoved=!1;for(var t=[],r=e._polylines.length,i=0,n=0;r>i;++i){var o=e._polylines[i];s(o)&&(o._index=n++,t.push(o))}e._polylines=t}}function z(e){for(var t=e._polylines,r=t.length,i=0;r>i;++i)if(s(t[i])){var n=t[i]._bucket;s(n)&&(n.shaderProgram=n.shaderProgram&&n.shaderProgram.destroy())}}function k(e){for(var t=e._vertexArrays.length,r=0;t>r;++r)e._vertexArrays[r].va.destroy();e._vertexArrays.length=0}function U(e){for(var t=e._polylines,r=t.length,i=0;r>i;++i)s(t[i])&&t[i]._destroy()}function G(e,t,r){this.count=e,this.offset=t,this.bucket=r}function W(e){return t.dot(t.UNIT_X,e._boundingVolume.center)<0||e._boundingVolume.intersectPlane(v.ORIGIN_ZX_PLANE)===p.INTERSECTING}var H=M.SHOW_INDEX,q=M.WIDTH_INDEX,j=M.POSITION_INDEX,Y=M.MATERIAL_INDEX,X=M.POSITION_SIZE_INDEX,Z=M.NUMBER_OF_PROPERTIES,K={texCoordExpandWidthAndShow:0,position3DHigh:1,position3DLow:2,position2DHigh:3,position2DLow:4,prevPosition3DHigh:5,prevPosition3DLow:6,prevPosition2DHigh:7,prevPosition2DLow:8,nextPosition3DHigh:9,nextPosition3DLow:10,nextPosition2DHigh:11,nextPosition2DLow:12,pickColor:13},J=function(e){e=a(e,a.EMPTY_OBJECT),this.modelMatrix=f.clone(a(e.modelMatrix,f.IDENTITY)),this._modelMatrix=f.clone(f.IDENTITY),this.debugShowBoundingVolume=a(e.debugShowBoundingVolume,!1),this._opaqueRS=void 0,this._translucentRS=void 0,this._colorCommands=[],this._pickCommands=[],this._polylinesUpdated=!1,this._polylinesRemoved=!1,this._createVertexArray=!1,this._propertiesChanged=new Uint32Array(Z),this._polylines=[],this._polylineBuckets={},this._buffersUsage=[{bufferUsage:g.STATIC_DRAW,frameCount:0},{bufferUsage:g.STATIC_DRAW,frameCount:0},{bufferUsage:g.STATIC_DRAW,frameCount:0}],this._mode=void 0,this._polylinesToUpdate=[],this._vertexArrays=[],this._positionBuffer=void 0,this._pickColorBuffer=void 0,this._texCoordExpandWidthAndShowBuffer=void 0};l(J.prototype,{length:{get:function(){return V(this),this._polylines.length}}}),J.prototype.add=function(e){var t=new M(e,this);return t._index=this._polylines.length,this._polylines.push(t),this._createVertexArray=!0,t},J.prototype.remove=function(e){if(this.contains(e)){if(this._polylines[e._index]=void 0,this._polylinesRemoved=!0,this._createVertexArray=!0,s(e._bucket)){var t=e._bucket;t.shaderProgram=t.shaderProgram&&t.shaderProgram.destroy(),t.pickShaderProgram=t.pickShaderProgram&&t.pickShaderProgram.destroy()}return e._destroy(),!0}return!1},J.prototype.removeAll=function(){z(this),U(this),this._polylineBuckets={},this._polylinesRemoved=!1,this._polylines.length=0,this._polylinesToUpdate.length=0,this._createVertexArray=!0},J.prototype.contains=function(e){return s(e)&&e._polylineCollection===this},J.prototype.get=function(e){return V(this),this._polylines[e]},J.prototype.update=function(e,t){if(V(this),0!==this._polylines.length){B(this,e);var r,i=e.context,n=e.mapProjection,o=this._propertiesChanged;if(this._createVertexArray||O(this))N(this,i,n);else if(this._polylinesUpdated){var a=this._polylinesToUpdate;if(this._mode!==D.SCENE3D)for(var l=a.length,u=0;l>u;++u)r=a[u],r.update();if(o[X]||o[Y])N(this,i,n);else for(var c=a.length,h=this._polylineBuckets,d=0;c>d;++d){r=a[d],o=r._propertiesChanged;var p=r._bucket,m=0;for(var v in h)if(h.hasOwnProperty(v)){if(h[v]===p){(o[j]||o[H]||o[q])&&p.writeUpdate(m,r,this._positionBuffer,this._texCoordExpandWidthAndShowBuffer,n);break}m+=h[v].lengthOfPositions}r._clean()}a.length=0,this._polylinesUpdated=!1}o=this._propertiesChanged;for(var _=0;Z>_;++_)o[_]=0;var g=f.IDENTITY;e.mode===D.SCENE3D&&(g=this.modelMatrix);var y=e.passes,E=0!==e.morphTime;if(s(this._opaqueRS)&&this._opaqueRS.depthTest.enabled===E||(this._opaqueRS=C.fromCache({depthMask:E,depthTest:{enabled:E}})),s(this._translucentRS)&&this._translucentRS.depthTest.enabled===E||(this._translucentRS=C.fromCache({blending:P.ALPHA_BLEND,depthMask:!E,depthTest:{enabled:E}})),y.render){var S=this._colorCommands;R(this,e,S,g,!0)}if(y.pick){var w=this._pickCommands;R(this,e,w,g,!1)}}};var Q=new e,$=new e;J.prototype.isDestroyed=function(){return!1},J.prototype.destroy=function(){return k(this),z(this),U(this),u(this)};var ee=[0,0,0],te=[];J.prototype._updatePolyline=function(e,t){this._polylinesUpdated=!0,this._polylinesToUpdate.push(e),++this._propertiesChanged[t]};var re=function(e,t,r){this.polylines=[],this.lengthOfPositions=0,this.material=e,this.shaderProgram=void 0,this.pickShaderProgram=void 0,this.mode=t,this.modelMatrix=r};re.prototype.addPolyline=function(e){var t=this.polylines;t.push(e),e._actualLength=this.getPolylinePositionsLength(e),this.lengthOfPositions+=e._actualLength,e._bucket=this},re.prototype.updateShader=function(e){if(!s(this.shaderProgram)){var t=new S({sources:[T,x]}),r=new S({sources:[this.material.shaderSource,b]}),i=new S({sources:r.sources,pickColorQualifier:"varying"});this.shaderProgram=E.fromCache({context:e,vertexShaderSource:t,fragmentShaderSource:r,attributeLocations:K}),this.pickShaderProgram=E.fromCache({context:e,vertexShaderSource:t,fragmentShaderSource:i,attributeLocations:K})}},re.prototype.getPolylinePositionsLength=function(e){var t;if(this.mode===D.SCENE3D||!W(e))return t=e._actualPositions.length,4*t-4;var r=0,i=e._segments.lengths;t=i.length;for(var n=0;t>n;++n)r+=4*i[n]-4;return r};var ie=new t,ne=new t,oe=new t,ae=new t;re.prototype.write=function(e,r,i,o,a,s,l,u){for(var c=this.mode,d=this.polylines,p=d.length,m=0;p>m;++m)for(var f,v=d[m],_=v.width,g=v.show&&_>0,y=this.getSegments(v,u),C=y.positions,E=y.lengths,S=C.length,w=v.getPickId(l).color,T=0,b=0,x=0;S>x;++x){0===x?v._loop?f=C[S-2]:(f=ae,t.subtract(C[0],C[1],f),t.add(C[0],f,f)):f=C[x-1],ne.x=f.x,ne.y=f.y,ne.z=c!==D.SCENE2D?f.z:0,f=C[x],ie.x=f.x,ie.y=f.y,ie.z=c!==D.SCENE2D?f.z:0,x===S-1?v._loop?f=C[1]:(f=ae,t.subtract(C[S-1],C[S-2],f),t.add(C[S-1],f,f)):f=C[x+1],oe.x=f.x,oe.y=f.y,oe.z=c!==D.SCENE2D?f.z:0;var P=E[T];x===b+P&&(b+=P,++T);for(var A=x-b===0,I=x===b+E[T]-1,M=A?2:0,R=I?2:4,O=M;R>O;++O){h.writeElements(ie,e,o),h.writeElements(ne,e,o+6),h.writeElements(oe,e,o+12),r[a]=n.floatToByte(w.red),r[a+1]=n.floatToByte(w.green),r[a+2]=n.floatToByte(w.blue),r[a+3]=n.floatToByte(w.alpha);var N=0>O-2?-1:1;i[s]=x/(S-1),i[s+1]=2*(O%2)-1,i[s+2]=N*_,i[s+3]=g,o+=18,a+=4,s+=4}}};var se=new t,le=new t,ue=new t,ce=new t;re.prototype.writeForMorph=function(e,r){for(var i=this.modelMatrix,n=this.polylines,o=n.length,a=0;o>a;++a)for(var s=n[a],l=s._segments.positions,u=s._segments.lengths,c=l.length,d=0,p=0,m=0;c>m;++m){var v;0===m?s._loop?v=l[c-2]:(v=ce,t.subtract(l[0],l[1],v),t.add(l[0],v,v)):v=l[m-1],v=f.multiplyByPoint(i,v,le);var _,g=f.multiplyByPoint(i,l[m],se);m===c-1?s._loop?_=l[1]:(_=ce,t.subtract(l[c-1],l[c-2],_),t.add(l[c-1],_,_)):_=l[m+1],_=f.multiplyByPoint(i,_,ue);var y=u[d];m===p+y&&(p+=y,++d);for(var C=m-p===0,E=m===p+u[d]-1,S=C?2:0,w=E?2:4,T=S;w>T;++T)h.writeElements(g,e,r),h.writeElements(v,e,r+6),h.writeElements(_,e,r+12),r+=18}};var he=new Array(1);re.prototype.updateIndices=function(e,t,r,i){var n=r.length-1,o=new G(0,i,this);r[n].push(o);var a=0,s=e[e.length-1],l=0;s.length>0&&(l=s[s.length-1]+1);for(var u=this.polylines,c=u.length,h=0;c>h;++h){var d=u[h];d._locatorBuckets=[];var p;if(this.mode===D.SCENE3D){p=he;var f=d._actualPositions.length;if(!(f>0))continue;p[0]=f}else p=d._segments.lengths;var v=p.length;if(v>0){for(var _=0,g=0;v>g;++g)for(var y=p[g]-1,C=0;y>C;++C)l+4>=m.SIXTY_FOUR_KILOBYTES-2&&(d._locatorBuckets.push({locator:o,count:_}),_=0,t.push(4),s=[],e.push(s),l=0,o.count=a,a=0,i=0,o=new G(0,0,this),r[++n]=[o]),s.push(l,l+2,l+1),s.push(l+1,l+2,l+3),_+=6,a+=6,i+=6,l+=4;d._locatorBuckets.push({locator:o,count:_}),l+4>=m.SIXTY_FOUR_KILOBYTES-2&&(t.push(0),s=[],e.push(s),l=0,o.count=a,i=0,a=0,o=new G(0,0,this),r[++n]=[o])}d._clean()}return o.count=a,i},re.prototype.getPolylineStartIndex=function(e){for(var t=this.polylines,r=0,i=t.length,n=0;i>n;++n){var o=t[n];if(o===e)break;r+=o._actualLength}return r};var de={positions:void 0,lengths:void 0},pe=new Array(1),me=new t,fe=new i;re.prototype.getSegments=function(r,i){var n=r._actualPositions;if(this.mode===D.SCENE3D)return pe[0]=n.length,de.positions=n,de.lengths=pe,de;W(r)&&(n=r._segments.positions);for(var o,a=i.ellipsoid,s=[],l=this.modelMatrix,u=n.length,c=me,h=0;u>h;++h)o=n[h],c=f.multiplyByPoint(l,o,c),s.push(i.project(a.cartesianToCartographic(c,fe)));if(s.length>0){r._boundingVolume2D=e.fromPoints(s,r._boundingVolume2D);var d=r._boundingVolume2D.center;r._boundingVolume2D.center=new t(d.z,d.x,d.y)}return de.positions=s,de.lengths=r._segments.lengths,de};var ve,_e;return re.prototype.writeUpdate=function(e,r,i,n,o){var a=this.mode,l=r._actualLength;if(l){e+=this.getPolylineStartIndex(r);var u=ve,c=_e,d=6*l*3;!s(u)||u.lengthd&&(u=new Float32Array(u.buffer,0,d),c=new Float32Array(c.buffer,0,4*l));var p,m=0,f=0,v=this.getSegments(r,o),_=v.positions,g=v.lengths,y=0,C=0,E=r.width,S=r.show&&E>0;l=_.length;for(var w=0;l>w;++w){0===w?r._loop?p=_[l-2]:(p=ae,t.subtract(_[0],_[1],p),t.add(_[0],p,p)):p=_[w-1],ne.x=p.x,ne.y=p.y,ne.z=a!==D.SCENE2D?p.z:0,p=_[w],ie.x=p.x,ie.y=p.y,ie.z=a!==D.SCENE2D?p.z:0,w===l-1?r._loop?p=_[1]:(p=ae,t.subtract(_[l-1],_[l-2],p),t.add(_[l-1],p,p)):p=_[w+1],oe.x=p.x,oe.y=p.y,oe.z=a!==D.SCENE2D?p.z:0;var T=g[y];w===C+T&&(C+=T,++y);for(var b=w-C===0,x=w===C+g[y]-1,P=b?2:0,A=x?2:4,I=P;A>I;++I){h.writeElements(ie,u,m),h.writeElements(ne,u,m+6),h.writeElements(oe,u,m+12);var M=0>I-2?-1:1;c[f]=w/(l-1),c[f+1]=2*(I%2)-1,c[f+2]=M*E,c[f+3]=S,m+=18,f+=4}}i.copyFromArrayView(u,18*Float32Array.BYTES_PER_ELEMENT*e),n.copyFromArrayView(c,4*Float32Array.BYTES_PER_ELEMENT*e)}},J}),r("DataSources/ScaledPositionProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/ReferenceFrame","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){this._definitionChanged=new n,this._value=void 0,this._removeSubscription=void 0,this.setValue(e)};return t(s.prototype,{isConstant:{get:function(){return a.isConstant(this._value)}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return e(this._value)?this._value.referenceFrame:o.FIXED}}}),s.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,o.FIXED,t)},s.prototype.setValue=function(t){this._value!==t&&(this._value=t,e(this._removeSubscription)&&(this._removeSubscription(),this._removeSubscription=void 0),e(t)&&(this._removeSubscription=t.definitionChanged.addEventListener(this._raiseDefinitionChanged,this)),this._definitionChanged.raiseEvent(this))},s.prototype.getValueInReferenceFrame=function(t,r,n){return e(this._value)?(n=this._value.getValueInReferenceFrame(t,r,n),e(n)?i.WGS84.scaleToGeodeticSurface(n,n):void 0):void 0},s.prototype.equals=function(e){return this===e||e instanceof s&&this._value===e._value},s.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},s}),r("DataSources/PathVisualizer",["../Core/AssociativeArray","../Core/Cartesian3","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/JulianDate","../Core/Matrix3","../Core/Matrix4","../Core/ReferenceFrame","../Core/TimeInterval","../Core/Transforms","../Scene/PolylineCollection","../Scene/SceneMode","./CompositePositionProperty","./ConstantPositionProperty","./MaterialProperty","./Property","./ReferenceProperty","./SampledPositionProperty","./ScaledPositionProperty","./TimeIntervalCollectionPositionProperty"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";function E(e,t,i,n,a,s,l,u,c){var h,d=u;h=e.getValueInReferenceFrame(t,s,c[d]),r(h)&&(c[d++]=h);for(var p,m,f,v=!r(a)||o.lessThanOrEquals(a,t)||o.greaterThanOrEquals(a,i),_=0,g=n.length,y=n[_],C=i,E=!1;g>_;){if(!v&&o.greaterThanOrEquals(y,a)&&(h=e.getValueInReferenceFrame(a,s,c[d]),r(h)&&(c[d++]=h),v=!0),o.greaterThan(y,t)&&o.lessThan(y,C)&&!y.equals(a)&&(h=e.getValueInReferenceFrame(y,s,c[d]),r(h)&&(c[d++]=h)), +g-1>_){if(l>0&&!E){var S=n[_+1],w=o.secondsDifference(S,y);E=w>l,E&&(p=Math.ceil(w/l),m=0,f=w/Math.max(p,2),p=Math.max(p-1,1))}if(E&&p>m){y=o.addSeconds(y,f,new o),m++;continue}}E=!1,_++,y=n[_]}return h=e.getValueInReferenceFrame(i,s,c[d]),r(h)&&(c[d++]=h),d}function S(e,t,i,n,a,s,l,u){for(var c,h=0,d=l,p=t,m=Math.max(s,60),f=!r(n)||o.lessThanOrEquals(n,t)||o.greaterThanOrEquals(n,i);o.lessThan(p,i);)!f&&o.greaterThanOrEquals(p,n)&&(f=!0,c=e.getValueInReferenceFrame(n,a,u[d]),r(c)&&(u[d]=c,d++)),c=e.getValueInReferenceFrame(p,a,u[d]),r(c)&&(u[d]=c,d++),h++,p=o.addSeconds(t,m*h,new o);return c=e.getValueInReferenceFrame(i,a,u[d]),r(c)&&(u[d]=c,d++),d}function w(e,t,i,n,a,s,l,c){R.start=t,R.stop=i;for(var h=l,d=e.intervals,p=0;p0){var T=S.pop();c=this._polylineCollection.get(T),t.index=T}else t.index=this._polylineCollection.length,c=this._polylineCollection.add();c.id=a,t.polyline=c}var b=v.getValueOrDefault(s._resolution,e,A);c.show=!0,c.positions=P(l,i,n,e,this._referenceFrame,b,c.positions),c.material=f.getValue(e,s._material,c.material),c.width=v.getValueOrDefault(s._width,e,I)},L.prototype.removeObject=function(e){var t=e.polyline;r(t)&&(this._unusedIndexes.push(e.index),e.polyline=void 0,t.show=!1,e.index=void 0)},L.prototype.destroy=function(){return this._scene.primitives.remove(this._polylineCollection),i(this)};var F=function(t,r){r.collectionChanged.addEventListener(F.prototype._onCollectionChanged,this),this._scene=t,this._updaters={},this._entityCollection=r,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return F.prototype.update=function(e){var t=this._updaters;for(var i in t)t.hasOwnProperty(i)&&t[i].update(e);for(var n=this._items.values,o=0,a=n.length;a>o;o++){var s=n[o],u=s.entity,c=u._position,h=s.updater,p=l.FIXED;this._scene.mode===d.SCENE3D&&(p=c.referenceFrame);var m=this._updaters[p];h===m&&r(m)?m.updateObject(e,s):(r(h)&&h.removeObject(s),r(m)||(m=new L(this._scene,p),m.update(e),this._updaters[p]=m),s.updater=m,r(m)&&m.updateObject(e,s))}return!0},F.prototype.isDestroyed=function(){return!1},F.prototype.destroy=function(){this._entityCollection.collectionChanged.removeEventListener(F.prototype._onCollectionChanged,this);var e=this._updaters;for(var t in e)e.hasOwnProperty(t)&&e[t].destroy();return i(this)},F.prototype._onCollectionChanged=function(e,t,i,n){var o,a,s,l=this._items;for(o=t.length-1;o>-1;o--)a=t[o],r(a._path)&&r(a._position)&&l.set(a.id,new O(a));for(o=n.length-1;o>-1;o--)a=n[o],r(a._path)&&r(a._position)?l.contains(a.id)||l.set(a.id,new O(a)):(s=l.get(a.id),r(s)&&(s.updater.removeObject(s),l.remove(a.id)));for(o=i.length-1;o>-1;o--)a=i[o],s=l.get(a.id),r(s)&&(s.updater.removeObject(s),l.remove(a.id))},F._subSample=P,F}),r("Shaders/PointPrimitiveCollectionFS",[],function(){"use strict";return"varying vec4 v_color;\nvarying vec4 v_outlineColor;\nvarying float v_innerPercent;\nvarying float v_pixelDistance;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#endif\nvoid main()\n{\nfloat distanceToCenter = length(gl_PointCoord - vec2(0.5));\nfloat maxDistance = max(0.0, 0.5 - v_pixelDistance);\nfloat wholeAlpha = 1.0 - smoothstep(maxDistance, 0.5, distanceToCenter);\nfloat innerAlpha = 1.0 - smoothstep(maxDistance * v_innerPercent, 0.5 * v_innerPercent, distanceToCenter);\nvec4 color = mix(v_outlineColor, v_color, innerAlpha);\ncolor.a *= wholeAlpha;\nif (color.a < 0.005)\n{\ndiscard;\n}\n#ifdef RENDER_FOR_PICK\ngl_FragColor = v_pickColor;\n#else\ngl_FragColor = color;\n#endif\n}\n"}),r("Shaders/PointPrimitiveCollectionVS",[],function(){"use strict";return"uniform float u_maxTotalPointSize;\nattribute vec4 positionHighAndSize;\nattribute vec4 positionLowAndOutline;\nattribute vec4 compressedAttribute0;\nattribute vec4 compressedAttribute1;\nattribute vec4 scaleByDistance;\nvarying vec4 v_color;\nvarying vec4 v_outlineColor;\nvarying float v_innerPercent;\nvarying float v_pixelDistance;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#endif\nconst float SHIFT_LEFT8 = 256.0;\nconst float SHIFT_RIGHT8 = 1.0 / 256.0;\nvoid main()\n{\nvec3 positionHigh = positionHighAndSize.xyz;\nvec3 positionLow = positionLowAndOutline.xyz;\nfloat outlineWidthBothSides = 2.0 * positionLowAndOutline.w;\nfloat totalSize = positionHighAndSize.w + outlineWidthBothSides;\nfloat outlinePercent = outlineWidthBothSides / totalSize;\ntotalSize *= czm_resolutionScale;\ntotalSize += 3.0;\nfloat temp = compressedAttribute1.x * SHIFT_RIGHT8;\nfloat show = floor(temp);\n#ifdef EYE_DISTANCE_TRANSLUCENCY\nvec4 translucencyByDistance;\ntranslucencyByDistance.x = compressedAttribute1.z;\ntranslucencyByDistance.z = compressedAttribute1.w;\ntranslucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\ntemp = compressedAttribute1.y * SHIFT_RIGHT8;\ntranslucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n#endif\nvec4 color;\nvec4 outlineColor;\n#ifdef RENDER_FOR_PICK\ncolor = vec4(0.0);\noutlineColor = vec4(0.0);\nvec4 pickColor;\ntemp = compressedAttribute0.z * SHIFT_RIGHT8;\npickColor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\npickColor.g = (temp - floor(temp)) * SHIFT_LEFT8;\npickColor.r = floor(temp);\n#else\ntemp = compressedAttribute0.x * SHIFT_RIGHT8;\ncolor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\ncolor.g = (temp - floor(temp)) * SHIFT_LEFT8;\ncolor.r = floor(temp);\ntemp = compressedAttribute0.y * SHIFT_RIGHT8;\noutlineColor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\noutlineColor.g = (temp - floor(temp)) * SHIFT_LEFT8;\noutlineColor.r = floor(temp);\n#endif\ntemp = compressedAttribute0.w * SHIFT_RIGHT8;\n#ifdef RENDER_FOR_PICK\npickColor.a = (temp - floor(temp)) * SHIFT_LEFT8;\npickColor = pickColor / 255.0;\n#endif\ntemp = floor(temp) * SHIFT_RIGHT8;\noutlineColor.a = (temp - floor(temp)) * SHIFT_LEFT8;\noutlineColor /= 255.0;\ncolor.a = floor(temp);\ncolor /= 255.0;\nvec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\nvec4 positionEC = czm_modelViewRelativeToEye * p;\npositionEC.xyz *= show;\n#if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY)\nfloat lengthSq;\nif (czm_sceneMode == czm_sceneMode2D)\n{\nlengthSq = czm_eyeHeight2D.y;\n}\nelse\n{\nlengthSq = dot(positionEC.xyz, positionEC.xyz);\n}\n#endif\n#ifdef EYE_DISTANCE_SCALING\ntotalSize *= czm_nearFarScalar(scaleByDistance, lengthSq);\n#endif\ntotalSize = min(totalSize, u_maxTotalPointSize);\nif (totalSize < 1.0)\n{\npositionEC.xyz = vec3(0.0);\ntotalSize = 1.0;\n}\nfloat translucency = 1.0;\n#ifdef EYE_DISTANCE_TRANSLUCENCY\ntranslucency = czm_nearFarScalar(translucencyByDistance, lengthSq);\nif (translucency < 0.004)\n{\npositionEC.xyz = vec3(0.0);\n}\n#endif\nvec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\ngl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0);\nv_color = color;\nv_color.a *= translucency;\nv_outlineColor = outlineColor;\nv_outlineColor.a *= translucency;\nv_innerPercent = 1.0 - outlinePercent;\nv_pixelDistance = 2.0 / totalSize;\ngl_PointSize = totalSize;\n#ifdef RENDER_FOR_PICK\nv_pickColor = pickColor;\n#endif\n}\n"}),r("Scene/PointPrimitive",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix4","../Core/NearFarScalar","./SceneMode","./SceneTransforms"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t){var r=e._pointPrimitiveCollection;o(r)&&(r._updatePointPrimitive(e,t),e._dirty=!0)}var p=function(e,r){e=n(e,n.EMPTY_OBJECT),this._show=n(e.show,!0),this._position=t.clone(n(e.position,t.ZERO)),this._actualPosition=t.clone(this._position),this._color=i.clone(n(e.color,i.WHITE)),this._outlineColor=i.clone(n(e.outlineColor,i.TRANSPARENT)),this._outlineWidth=n(e.outlineWidth,0),this._pixelSize=n(e.pixelSize,10),this._scaleByDistance=e.scaleByDistance,this._translucencyByDistance=e.translucencyByDistance,this._id=e.id,this._collection=n(e.collection,r),this._pickId=void 0,this._pointPrimitiveCollection=r,this._dirty=!1,this._index=-1},m=p.SHOW_INDEX=0,f=p.POSITION_INDEX=1,v=p.COLOR_INDEX=2,_=p.OUTLINE_COLOR_INDEX=3,g=p.OUTLINE_WIDTH_INDEX=4,y=p.PIXEL_SIZE_INDEX=5,C=p.SCALE_BY_DISTANCE_INDEX=6,E=p.TRANSLUCENCY_BY_DISTANCE_INDEX=7;p.NUMBER_OF_PROPERTIES=8,a(p.prototype,{show:{get:function(){return this._show},set:function(e){this._show!==e&&(this._show=e,d(this,m))}},position:{get:function(){return this._position},set:function(e){var r=this._position;t.equals(r,e)||(t.clone(e,r),t.clone(e,this._actualPosition),d(this,f))}},scaleByDistance:{get:function(){return this._scaleByDistance},set:function(e){var t=this._scaleByDistance;u.equals(t,e)||(this._scaleByDistance=u.clone(e,t),d(this,C))}},translucencyByDistance:{get:function(){return this._translucencyByDistance},set:function(e){var t=this._translucencyByDistance;u.equals(t,e)||(this._translucencyByDistance=u.clone(e,t),d(this,E))}},pixelSize:{get:function(){return this._pixelSize},set:function(e){this._pixelSize!==e&&(this._pixelSize=e,d(this,y))}},color:{get:function(){return this._color},set:function(e){var t=this._color;i.equals(t,e)||(i.clone(e,t),d(this,v))}},outlineColor:{get:function(){return this._outlineColor},set:function(e){var t=this._outlineColor;i.equals(t,e)||(i.clone(e,t),d(this,_))}},outlineWidth:{get:function(){return this._outlineWidth},set:function(e){this._outlineWidth!==e&&(this._outlineWidth=e,d(this,g))}},id:{get:function(){return this._id},set:function(e){this._id=e,o(this._pickId)&&(this._pickId.object.id=e)}}}),p.prototype.getPickId=function(e){return o(this._pickId)||(this._pickId=e.createPickId({primitive:this,collection:this._collection,id:this._id})),this._pickId},p.prototype._getActualPosition=function(){return this._actualPosition},p.prototype._setActualPosition=function(e){t.clone(e,this._actualPosition),d(this,f)};var S=new r;p._computeActualPosition=function(e,t,r){return t.mode===c.SCENE3D?e:(l.multiplyByPoint(r,e,S),h.computeActualWgs84Position(t,S))};var w=new l,T=new r;return p._computeScreenSpacePosition=function(e,t,i,n){var o=i.camera,a=o.viewMatrix,s=o.frustum.projectionMatrix,u=l.multiplyTransformation(a,e,w),c=l.multiplyByVector(u,r.fromElements(t.x,t.y,t.z,1,T),T),d=l.multiplyByVector(s,c,T),p=h.clipToGLWindowCoordinates(i,d,n);return p},p.prototype.computeScreenSpacePosition=function(t,r){var i=this._pointPrimitiveCollection;o(r)||(r=new e);var n=i.modelMatrix,a=p._computeScreenSpacePosition(n,this._actualPosition,t,r);return a.y=t.canvas.clientHeight-a.y,a},p.prototype.equals=function(e){return this===e||o(e)&&this._id===e._id&&t.equals(this._position,e._position)&&i.equals(this._color,e._color)&&this._pixelSize===e._pixelSize&&this._outlineWidth===e._outlineWidth&&this._show===e._show&&i.equals(this._outlineColor,e._outlineColor)&&u.equals(this._scaleByDistance,e._scaleByDistance)&&u.equals(this._translucencyByDistance,e._translucencyByDistance)},p.prototype._destroy=function(){this._pickId=this._pickId&&this._pickId.destroy(),this._pointPrimitiveCollection=void 0},p}),r("Scene/PointPrimitiveCollection",["../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EncodedCartesian3","../Core/Math","../Core/Matrix4","../Core/PrimitiveType","../Renderer/BufferUsage","../Renderer/ContextLimits","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArrayFacade","../Shaders/PointPrimitiveCollectionFS","../Shaders/PointPrimitiveCollectionVS","./BlendingState","./Pass","./PointPrimitive","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x){"use strict";function P(e){for(var t=e.length,r=0;t>r;++r)e[r]&&e[r]._destroy()}function A(e){if(e._pointPrimitivesRemoved){e._pointPrimitivesRemoved=!1;for(var t=[],r=e._pointPrimitives,i=r.length,n=0,o=0;i>n;++n){var a=r[n];a&&(a._index=o++,t.push(a))}e._pointPrimitives=t}}function I(e,t,r){return new C(e,[{index:Y.positionHighAndSize,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[z]},{index:Y.positionLowAndShow,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[z]},{index:Y.compressedAttribute0,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[k]},{index:Y.compressedAttribute1,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[q]},{index:Y.scaleByDistance,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[H]}],t)}function M(t,r,i,n){var o=n._index,a=n._getActualPosition();t._mode===x.SCENE3D&&(e.expand(t._baseVolume,a,t._baseVolume),t._boundingVolumeDirty=!0),c.fromCartesian(a,Z);var s=n.pixelSize,l=n.outlineWidth;t._maxPixelSize=Math.max(t._maxPixelSize,s+l);var u=i[Y.positionHighAndSize],h=Z.high;u(o,h.x,h.y,h.z,s);var d=i[Y.positionLowAndOutline],p=Z.low;d(o,p.x,p.y,p.z,l)}function D(e,t,r,n){var o=n._index,a=n.color,s=n.getPickId(t).color,l=n.outlineColor,u=i.floatToByte(a.red),c=i.floatToByte(a.green),h=i.floatToByte(a.blue),d=u*K+c*J+h;u=i.floatToByte(l.red),c=i.floatToByte(l.green),h=i.floatToByte(l.blue);var p=u*K+c*J+h;u=i.floatToByte(s.red),c=i.floatToByte(s.green),h=i.floatToByte(s.blue);var m=u*K+c*J+h,f=i.floatToByte(a.alpha)*K+i.floatToByte(l.alpha)*J+i.floatToByte(s.alpha),v=r[Y.compressedAttribute0];v(o,d,p,m,f)}function R(e,t,r,i){var n=i._index,o=0,s=1,l=1,u=1,c=i.translucencyByDistance;a(c)&&(o=c.near,s=c.nearValue,l=c.far,u=c.farValue,(1!==s||1!==u)&&(e._shaderTranslucencyByDistance=!0));var d=i.show;0===i.color.alpha&&0===i.outlineColor.alpha&&(d=!1),s=h.clamp(s,0,1),s=1===s?255:255*s|0;var p=(d?1:0)*J+s;u=h.clamp(u,0,1),u=1===u?255:255*u|0;var m=u,f=r[Y.compressedAttribute1];f(n,p,m,o,l)}function O(e,t,r,i){var n=i._index,o=r[Y.scaleByDistance],s=0,l=1,u=1,c=1,h=i.scaleByDistance;a(h)&&(s=h.near,l=h.nearValue,u=h.far,c=h.farValue,(1!==l||1!==c)&&(e._shaderScaleByDistance=!0)),o(n,s,l,u,c)}function N(e,t,r,i){M(e,t,r,i),D(e,t,r,i),R(e,t,r,i),O(e,t,r,i)}function L(t,r,i,n,o,s){var l;n.mode===x.SCENE3D?(l=t._baseVolume,t._boundingVolumeDirty=!0):l=t._baseVolume2D;for(var u=[],c=0;i>c;++c){var h=r[c],d=h.position,p=b._computeActualPosition(d,n,o);a(p)&&(h._setActualPosition(p),s?u.push(p):e.expand(l,p,l))}s&&e.fromPoints(u,l)}function F(e,t){var r=t.mode,i=e._pointPrimitives,n=e._pointPrimitivesToUpdate,o=e._modelMatrix;e._createVertexArray||e._mode!==r||r!==x.SCENE3D&&!d.equals(o,e.modelMatrix)?(e._mode=r,d.clone(e.modelMatrix,o),e._createVertexArray=!0,(r===x.SCENE3D||r===x.SCENE2D||r===x.COLUMBUS_VIEW)&&L(e,i,i.length,t,o,!0)):r===x.MORPHING?L(e,i,i.length,t,o,!0):(r===x.SCENE2D||r===x.COLUMBUS_VIEW)&&L(e,n,e._pointPrimitivesToUpdateIndex,t,o,!1)}function B(e,t,i){var n=t.camera,o=n.frustum,a=r.subtract(n.positionWC,i.center,$),s=r.multiplyByScalar(n.directionWC,r.dot(a,n.directionWC),ee),l=Math.max(0,r.magnitude(s)-i.radius),u=t.context,c=o.getPixelDimensions(u.drawingBufferWidth,u.drawingBufferHeight,l,Q),h=Math.max(c.x,c.y),d=h*e._maxPixelSize;i.radius+=d}var V=b.SHOW_INDEX,z=b.POSITION_INDEX,k=b.COLOR_INDEX,U=b.OUTLINE_COLOR_INDEX,G=b.OUTLINE_WIDTH_INDEX,W=b.PIXEL_SIZE_INDEX,H=b.SCALE_BY_DISTANCE_INDEX,q=b.TRANSLUCENCY_BY_DISTANCE_INDEX,j=b.NUMBER_OF_PROPERTIES,Y={positionHighAndSize:0,positionLowAndOutline:1,compressedAttribute0:2,compressedAttribute1:3,scaleByDistance:4},X=function(t){t=o(t,o.EMPTY_OBJECT),this._sp=void 0,this._rs=void 0,this._vaf=void 0,this._spPick=void 0,this._pointPrimitives=[],this._pointPrimitivesToUpdate=[],this._pointPrimitivesToUpdateIndex=0,this._pointPrimitivesRemoved=!1,this._createVertexArray=!1,this._shaderScaleByDistance=!1,this._compiledShaderScaleByDistance=!1,this._compiledShaderScaleByDistancePick=!1,this._shaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistancePick=!1,this._propertiesChanged=new Uint32Array(j),this._maxPixelSize=1,this._baseVolume=new e,this._baseVolumeWC=new e,this._baseVolume2D=new e,this._boundingVolume=new e,this._boundingVolumeDirty=!1,this._colorCommands=[],this._pickCommands=[],this.modelMatrix=d.clone(o(t.modelMatrix,d.IDENTITY)),this._modelMatrix=d.clone(d.IDENTITY),this.debugShowBoundingVolume=o(t.debugShowBoundingVolume,!1),this._mode=x.SCENE3D,this._maxTotalPointSize=1,this._buffersUsage=[m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW];var r=this;this._uniforms={u_maxTotalPointSize:function(){return r._maxTotalPointSize}}};s(X.prototype,{length:{get:function(){return A(this),this._pointPrimitives.length}}}),X.prototype.add=function(e){var t=new b(e,this);return t._index=this._pointPrimitives.length,this._pointPrimitives.push(t),this._createVertexArray=!0,t},X.prototype.remove=function(e){return this.contains(e)?(this._pointPrimitives[e._index]=null,this._pointPrimitivesRemoved=!0,this._createVertexArray=!0,e._destroy(),!0):!1},X.prototype.removeAll=function(){P(this._pointPrimitives),this._pointPrimitives=[],this._pointPrimitivesToUpdate=[],this._pointPrimitivesToUpdateIndex=0,this._pointPrimitivesRemoved=!1,this._createVertexArray=!0},X.prototype._updatePointPrimitive=function(e,t){e._dirty||(this._pointPrimitivesToUpdate[this._pointPrimitivesToUpdateIndex++]=e),++this._propertiesChanged[t]},X.prototype.contains=function(e){return a(e)&&e._pointPrimitiveCollection===this},X.prototype.get=function(e){return A(this),this._pointPrimitives[e]},X.prototype.computeNewBuffersUsage=function(){for(var e=this._buffersUsage,t=!1,r=this._propertiesChanged,i=0;j>i;++i){var n=0===r[i]?m.STATIC_DRAW:m.STREAM_DRAW;t=t||e[i]!==n,e[i]=n}return t};var Z=new c,K=65536,J=256,Q=new t,$=new r,ee=new r,te=[];return X.prototype.update=function(t){A(this),this._maxTotalPointSize=f.maximumAliasedPointSize,F(this,t);var r,i=this._pointPrimitives,n=i.length,o=this._pointPrimitivesToUpdate,s=this._pointPrimitivesToUpdateIndex,l=this._propertiesChanged,u=this._createVertexArray,c=t.context,h=t.passes,m=h.pick;if(u||!m&&this.computeNewBuffersUsage()){this._createVertexArray=!1;for(var C=0;j>C;++C)l[C]=0;if(this._vaf=this._vaf&&this._vaf.destroy(),n>0){this._vaf=I(c,n,this._buffersUsage),r=this._vaf.writers;for(var b=0;n>b;++b){var P=this._pointPrimitives[b];P._dirty=!1,N(this,c,r,P)}this._vaf.commit()}this._pointPrimitivesToUpdateIndex=0}else if(s>0){var L=te;L.length=0,(l[z]||l[G]||l[W])&&L.push(M),(l[k]||l[U])&&L.push(D),(l[V]||l[q])&&L.push(R),l[H]&&L.push(O);var X=L.length;if(r=this._vaf.writers,s/n>.1){for(var Z=0;s>Z;++Z){var K=o[Z];K._dirty=!1;for(var J=0;X>J;++J)L[J](this,c,r,K)}this._vaf.commit()}else{for(var Q=0;s>Q;++Q){var $=o[Q];$._dirty=!1;for(var ee=0;X>ee;++ee)L[ee](this,c,r,$);this._vaf.subCommit($._index,1)}this._vaf.endSubCommits()}this._pointPrimitivesToUpdateIndex=0}if(s>1.5*n&&(o.length=n),a(this._vaf)&&a(this._vaf.va)){this._boundingVolumeDirty&&(this._boundingVolumeDirty=!1,e.transform(this._baseVolume,this.modelMatrix,this._baseVolumeWC));var re,ie=d.IDENTITY;t.mode===x.SCENE3D?(ie=this.modelMatrix,re=e.clone(this._baseVolumeWC,this._boundingVolume)):re=e.clone(this._baseVolume2D,this._boundingVolume),B(this,t,re);var ne,oe,ae,se,le,ue,ce=t.commandList;if(h.render){var he=this._colorCommands;for(a(this._rs)||(this._rs=_.fromCache({depthTest:{enabled:!0},blending:w.ALPHA_BLEND})),(!a(this._sp)||this._shaderScaleByDistance&&!this._compiledShaderScaleByDistance||this._shaderTranslucencyByDistance&&!this._compiledShaderTranslucencyByDistance)&&(le=new y({sources:[S]}),this._shaderScaleByDistance&&le.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&le.defines.push("EYE_DISTANCE_TRANSLUCENCY"),this._sp=g.replaceCache({context:c,shaderProgram:this._sp,vertexShaderSource:le,fragmentShaderSource:E,attributeLocations:Y}),this._compiledShaderScaleByDistance=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistance=this._shaderTranslucencyByDistance),ne=this._vaf.va,oe=ne.length,he.length=oe,se=0;oe>se;++se)ae=he[se],a(ae)||(ae=he[se]=new v({primitiveType:p.POINTS,pass:T.OPAQUE,owner:this})),ae.boundingVolume=re,ae.modelMatrix=ie,ae.shaderProgram=this._sp,ae.uniformMap=this._uniforms,ae.vertexArray=ne[se].va,ae.renderState=this._rs,ae.debugShowBoundingVolume=this.debugShowBoundingVolume,ce.push(ae)}if(m){var de=this._pickCommands;for((!a(this._spPick)||this._shaderScaleByDistance&&!this._compiledShaderScaleByDistancePick||this._shaderTranslucencyByDistance&&!this._compiledShaderTranslucencyByDistancePick)&&(le=new y({defines:["RENDER_FOR_PICK"],sources:[S]}),this._shaderScaleByDistance&&le.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&le.defines.push("EYE_DISTANCE_TRANSLUCENCY"),ue=new y({defines:["RENDER_FOR_PICK"],sources:[E]}),this._spPick=g.replaceCache({context:c,shaderProgram:this._spPick,vertexShaderSource:le,fragmentShaderSource:ue,attributeLocations:Y}),this._compiledShaderScaleByDistancePick=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistancePick=this._shaderTranslucencyByDistance),ne=this._vaf.va,oe=ne.length,de.length=oe,se=0;oe>se;++se)ae=de[se],a(ae)||(ae=de[se]=new v({primitiveType:p.POINTS,pass:T.OPAQUE,owner:this})),ae.boundingVolume=re,ae.modelMatrix=ie,ae.shaderProgram=this._spPick,ae.uniformMap=this._uniforms,ae.vertexArray=ne[se].va,ae.renderState=this._rs,ce.push(ae)}}},X.prototype.isDestroyed=function(){return!1},X.prototype.destroy=function(){return this._sp=this._sp&&this._sp.destroy(),this._spPick=this._spPick&&this._spPick.destroy(),this._vaf=this._vaf&&this._vaf.destroy(),P(this._pointPrimitives),l(this)},X}),r("DataSources/PointVisualizer",["../Core/AssociativeArray","../Core/Cartesian3","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/NearFarScalar","../Scene/PointPrimitiveCollection","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){if(i(e)){var r=e.pointPrimitive;i(r)&&(e.pointPrimitive=void 0,r.show=!1,t.push(r._index))}}var h=r.WHITE,d=r.BLACK,p=0,m=1,f=new r,v=new t,_=new r,g=new a,y=new a,C=function(e){this.entity=e,this.pointPrimitive=void 0,this.color=void 0,this.outlineColor=void 0,this.pixelSize=void 0,this.outlineWidth=void 0},E=function(t,r){r.collectionChanged.addEventListener(E.prototype._onCollectionChanged,this),this._scene=t,this._unusedIndexes=[],this._entityCollection=r,this._pointPrimitiveCollection=void 0,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return E.prototype.update=function(e){for(var t=this._items.values,r=this._unusedIndexes,n=0,o=t.length;o>n;n++){var a=t[n],l=a.entity,C=l._point,E=a.pointPrimitive,S=l.isShowing&&l.isAvailable(e)&&u.getValueOrDefault(C._show,e,!0);if(S&&(v=u.getValueOrUndefined(l._position,e,v),S=i(v)),S){if(!i(E)){var w=this._pointPrimitiveCollection;i(w)||(w=new s,this._pointPrimitiveCollection=w,this._scene.primitives.add(w));var T=r.length;E=T>0?w.get(r.pop()):w.add(),E.id=l,a.pointPrimitive=E}E.show=!0,E.position=v,E.scaleByDistance=u.getValueOrUndefined(C._scaleByDistance,e,g),E.translucencyByDistance=u.getValueOrUndefined(C._translucencyByDistance,e,y),E.color=u.getValueOrDefault(C._color,e,h,f),E.outlineColor=u.getValueOrDefault(C._outlineColor,e,d,_),E.outlineWidth=u.getValueOrDefault(C._outlineWidth,e,p),E.pixelSize=u.getValueOrDefault(C._pixelSize,e,m)}else c(a,r)}return!0},E.prototype.getBoundingSphere=function(e,r){var n=this._items.get(e.id);return i(n)&&i(n.pointPrimitive)?(r.center=t.clone(n.pointPrimitive.position,r.center),r.radius=0,l.DONE):l.FAILED},E.prototype.isDestroyed=function(){return!1},E.prototype.destroy=function(){return this._entityCollection.collectionChanged.removeEventListener(E.prototype._onCollectionChanged,this),i(this._pointPrimitiveCollection)&&this._scene.primitives.remove(this._pointPrimitiveCollection),n(this)},E.prototype._onCollectionChanged=function(e,t,r,n){var o,a,s=this._unusedIndexes,l=this._items;for(o=t.length-1;o>-1;o--)a=t[o],i(a._point)&&i(a._position)&&l.set(a.id,new C(a));for(o=n.length-1;o>-1;o--)a=n[o],i(a._point)&&i(a._position)?l.contains(a.id)||l.set(a.id,new C(a)):(c(l.get(a.id),s),l.remove(a.id));for(o=r.length-1;o>-1;o--)a=r[o],c(l.get(a.id),s),l.remove(a.id)},E}),r("DataSources/PolygonGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/isArray","../Core/Iso8601","../Core/PolygonGeometry","../Core/PolygonHierarchy","../Core/PolygonOutlineGeometry","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";var w=new g(e.WHITE),T=new y(!0),b=new y(!0),x=new y(!1),P=new y(e.BLACK),A=new e,I=function(e){this.id=e,this.vertexFormat=void 0,this.polygonHierarchy=void 0,this.perPositionHeight=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0,this.stRotation=void 0},M=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(M.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new I(e),this._onEntityPropertyChanged(e,"polygon",e.polygon,void 0)};n(M,{perInstanceColorAppearanceType:{value:v},materialAppearanceType:{value:f}}),n(M.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&S.isConstant(this._showProperty)&&S.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&S.isConstant(this._showProperty)&&S.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),M.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},M.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},M.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new m(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof g){var c=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(c=this._materialProperty.color.getValue(r)),o=t.fromColor(c),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new h(this._options),attributes:n})},M.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=S.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new p(this._options),attributes:{show:new m(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},M.prototype.isDestroyed=function(){return!1},M.prototype.destroy=function(){this._entitySubscription(),o(this)},M.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"polygon"===t){var a=this._entity.polygon;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(c.MINIMUM_VALUE):!0,h=a.outline,p=i(h);if(p&&h.isConstant&&(p=h.getValue(c.MINIMUM_VALUE)),!l&&!p)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var m=a.hierarchy,_=a.show;if(i(_)&&_.isConstant&&!_.getValue(c.MINIMUM_VALUE)||!i(m))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var y=r(a.material,w),C=y instanceof g;this._materialProperty=y,this._fillProperty=r(s,b),this._showProperty=r(_,T),this._showOutlineProperty=r(a.outline,x),this._outlineColorProperty=p?r(a.outlineColor,P):void 0;var E=a.height,A=a.extrudedHeight,I=a.granularity,M=a.stRotation,D=a.outlineWidth,R=a.perPositionHeight;if(this._fillEnabled=l,this._outlineEnabled=p,m.isConstant&&S.isConstant(E)&&S.isConstant(A)&&S.isConstant(I)&&S.isConstant(M)&&S.isConstant(D)&&S.isConstant(R)){var O=this._options;O.vertexFormat=C?v.VERTEX_FORMAT:f.MaterialSupport.TEXTURED.vertexFormat;var N=m.getValue(c.MINIMUM_VALUE);u(N)&&(N=new d(N));var L=i(E)?E.getValue(c.MINIMUM_VALUE):void 0,F=i(A)?A.getValue(c.MINIMUM_VALUE):void 0;O.polygonHierarchy=N,O.height=L,O.extrudedHeight=F,O.granularity=i(I)?I.getValue(c.MINIMUM_VALUE):void 0,O.stRotation=i(M)?M.getValue(c.MINIMUM_VALUE):void 0,O.perPositionHeight=i(R)?R.getValue(c.MINIMUM_VALUE):void 0,this._outlineWidth=i(D)?D.getValue(c.MINIMUM_VALUE):1,this._isClosed=i(F)&&F!==L, +this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},M.prototype.createDynamicUpdater=function(e){return new D(e,this)};var D=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new I(t._entity)};return D.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.polygon;if(a.isShowing&&a.isAvailable(r)&&S.getValueOrDefault(s.show,r,!0)){var c=this._options,m=S.getValueOrUndefined(s.hierarchy,r);if(i(m)){if(u(m)?c.polygonHierarchy=new d(m):c.polygonHierarchy=m,c.height=S.getValueOrUndefined(s.height,r),c.extrudedHeight=S.getValueOrUndefined(s.extrudedHeight,r),c.granularity=S.getValueOrUndefined(s.granularity,r),c.stRotation=S.getValueOrUndefined(s.stRotation,r),c.perPositionHeight=S.getValueOrUndefined(s.perPositionHeight,r),S.getValueOrDefault(s.fill,r,!0)){var g=E.getValue(r,o.fillMaterialProperty,this._material);this._material=g;var y=new f({material:g,translucent:g.isTranslucent(),closed:i(c.extrudedHeight)&&c.extrudedHeight!==c.height});c.vertexFormat=y.vertexFormat,this._primitive=n.add(new _({geometryInstances:new l({id:a,geometry:new h(c)}),appearance:y,asynchronous:!1}))}if(S.getValueOrDefault(s.outline,r,!1)){c.vertexFormat=v.VERTEX_FORMAT;var C=S.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,A),w=S.getValueOrDefault(s.outlineWidth,r,1),T=1!==C.alpha;this._outlinePrimitive=n.add(new _({geometryInstances:new l({id:a,geometry:new p(c),attributes:{color:t.fromColor(C)}}),appearance:new v({flat:!0,translucent:T,renderState:{lineWidth:o._scene.clampLineWidth(w)}}),asynchronous:!1}))}}}},D.prototype.getBoundingSphere=function(e,t){return C(e,this._primitive,this._outlinePrimitive,t)},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},M}),r("Shaders/Appearances/PolylineColorAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 prevPosition3DHigh;\nattribute vec3 prevPosition3DLow;\nattribute vec3 nextPosition3DHigh;\nattribute vec3 nextPosition3DLow;\nattribute vec2 expandAndWidth;\nattribute vec4 color;\nvarying vec4 v_color;\nvoid main()\n{\nfloat expandDir = expandAndWidth.x;\nfloat width = abs(expandAndWidth.y) + 0.5;\nbool usePrev = expandAndWidth.y < 0.0;\nvec4 p = czm_computePosition();\nvec4 prev = czm_computePrevPosition();\nvec4 next = czm_computeNextPosition();\nv_color = color;\nvec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\ngl_Position = czm_viewportOrthographic * positionWC;\n}\n"}),r("Scene/PolylineColorAppearance",["../Core/defaultValue","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/PerInstanceFlatColorAppearanceFS","../Shaders/Appearances/PolylineColorAppearanceVS","../Shaders/PolylineCommon","./Appearance"],function(e,t,r,i,n,o,a){"use strict";var s=o+"\n"+n,l=i,u=function(t){t=e(t,e.EMPTY_OBJECT);var r=e(t.translucent,!0),i=!1,n=u.VERTEX_FORMAT;this.material=void 0,this.translucent=r,this._vertexShaderSource=e(t.vertexShaderSource,s),this._fragmentShaderSource=e(t.fragmentShaderSource,l),this._renderState=a.getDefaultRenderState(r,i,t.renderState),this._closed=i,this._vertexFormat=n};return t(u.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return this._vertexFormat}}}),u.VERTEX_FORMAT=r.POSITION_ONLY,u.prototype.getFragmentShaderSource=a.prototype.getFragmentShaderSource,u.prototype.isTranslucent=a.prototype.isTranslucent,u.prototype.getRenderState=a.prototype.getRenderState,u}),r("Shaders/Appearances/PolylineMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 prevPosition3DHigh;\nattribute vec3 prevPosition3DLow;\nattribute vec3 nextPosition3DHigh;\nattribute vec3 nextPosition3DLow;\nattribute vec2 expandAndWidth;\nattribute vec2 st;\nvarying float v_width;\nvarying vec2 v_st;\nvoid main()\n{\nfloat expandDir = expandAndWidth.x;\nfloat width = abs(expandAndWidth.y) + 0.5;\nbool usePrev = expandAndWidth.y < 0.0;\nvec4 p = czm_computePosition();\nvec4 prev = czm_computePrevPosition();\nvec4 next = czm_computeNextPosition();\nv_width = width;\nv_st = st;\nvec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\ngl_Position = czm_viewportOrthographic * positionWC;\n}\n"}),r("Scene/PolylineMaterialAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/PolylineMaterialAppearanceVS","../Shaders/PolylineCommon","../Shaders/PolylineFS","./Appearance","./Material"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=o+"\n"+n,c=a,h=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.translucent,!0),n=!1,o=h.VERTEX_FORMAT;this.material=t(r.material)?r.material:l.fromType(l.ColorType),this.translucent=i,this._vertexShaderSource=e(r.vertexShaderSource,u),this._fragmentShaderSource=e(r.fragmentShaderSource,c),this._renderState=s.getDefaultRenderState(i,n,r.renderState),this._closed=n,this._vertexFormat=o};return r(h.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return this._vertexFormat}}}),h.VERTEX_FORMAT=i.POSITION_AND_ST,h.prototype.getFragmentShaderSource=s.prototype.getFragmentShaderSource,h.prototype.isTranslucent=s.prototype.isTranslucent,h.prototype.getRenderState=s.prototype.getRenderState,h}),r("DataSources/PolylineGeometryUpdater",["../Core/BoundingSphere","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/PolylineGeometry","../Core/PolylinePipeline","../Core/ShowGeometryInstanceAttribute","../Scene/PolylineCollection","../Scene/PolylineColorAppearance","../Scene/PolylineMaterialAppearance","./BoundingSphereState","./ColorMaterialProperty","./ConstantProperty","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";var w={},T=new y(t.WHITE),b=new C(!0),x=function(e){this.id=e,this.vertexFormat=void 0,this.positions=void 0,this.width=void 0,this.followSurface=void 0,this.granularity=void 0},P=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(P.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._options=new x(e),this._onEntityPropertyChanged(e,"polyline",e.polyline,void 0)};o(P,{perInstanceColorAppearanceType:{value:v},materialAppearanceType:{value:_}}),o(P.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!n(this._entity.availability)&&S.isConstant(this._showProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{value:!1},hasConstantOutline:{value:!0},outlineColorProperty:{value:void 0},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!1},geometryChanged:{get:function(){return this._geometryChanged}}}),P.prototype.isOutlineVisible=function(e){return!1},P.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)},P.prototype.createFillGeometryInstance=function(e){var i,o,a=this._entity,s=a.isAvailable(e),l=new m(s&&a.isShowing&&this._showProperty.getValue(e));if(this._materialProperty instanceof y){var u=t.WHITE;n(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(u=this._materialProperty.color.getValue(e)),i=r.fromColor(u),o={show:l,color:i}}else o={show:l};return new c({id:a,geometry:new d(this._options),attributes:o})},P.prototype.createOutlineGeometryInstance=function(e){},P.prototype.isDestroyed=function(){return!1},P.prototype.destroy=function(){this._entitySubscription(),a(this)},P.prototype._onEntityPropertyChanged=function(e,t,r,o){if("availability"===t||"polyline"===t){var a=this._entity.polyline;if(!n(a))return void(this._fillEnabled&&(this._fillEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.positions,l=a.show;if(n(l)&&l.isConstant&&!l.getValue(h.MINIMUM_VALUE)||!n(s))return void(this._fillEnabled&&(this._fillEnabled=!1,this._geometryChanged.raiseEvent(this)));var u=i(a.material,T),c=u instanceof y;this._materialProperty=u,this._showProperty=i(l,b),this._fillEnabled=!0;var d=a.width,p=a.followSurface,m=a.granularity;if(s.isConstant&&S.isConstant(d)&&S.isConstant(p)&&S.isConstant(m)){var f=this._options,g=s.getValue(h.MINIMUM_VALUE,f.positions);if(!n(g)||g.length<2)return void(this._fillEnabled&&(this._fillEnabled=!1,this._geometryChanged.raiseEvent(this)));f.vertexFormat=c?v.VERTEX_FORMAT:_.VERTEX_FORMAT,f.positions=g,f.width=n(d)?d.getValue(h.MINIMUM_VALUE):void 0,f.followSurface=n(p)?p.getValue(h.MINIMUM_VALUE):void 0,f.granularity=n(m)?m.getValue(h.MINIMUM_VALUE):void 0,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},P.prototype.createDynamicUpdater=function(e){return new I(e,this)};var A={positions:void 0,granularity:void 0,height:void 0,ellipsoid:void 0},I=function(e,t){var r=t._scene.id,i=w[r];!n(i)||i.isDestroyed()?(i=new f,w[r]=i,e.add(i)):e.contains(i)||e.add(i);var o=i.add();o.id=t._entity,this._line=o,this._primitives=e,this._geometryUpdater=t,this._positions=[],A.ellipsoid=t._scene.globe.ellipsoid};return I.prototype.update=function(e){var t=this._geometryUpdater,r=t._entity,i=r.polyline,o=this._line;if(!r.isShowing||!r.isAvailable(e)||!S.getValueOrDefault(i._show,e,!0))return void(o.show=!1);var a=i.positions,s=S.getValueOrUndefined(a,e,this._positions);if(!n(s)||s.length<2)return void(o.show=!1);var l=S.getValueOrDefault(i._followSurface,e,!0);l&&(A.positions=s,A.granularity=S.getValueOrUndefined(i._granularity,e),A.height=p.extractHeights(s,this._geometryUpdater._scene.globe.ellipsoid),s=p.generateCartesianArc(A)),o.show=!0,o.positions=s,o.material=E.getValue(e,t.fillMaterialProperty,o.material),o.width=S.getValueOrDefault(i._width,e,1)},I.prototype.getBoundingSphere=function(t,r){var i=this._line;return i.show&&i.positions.length>0?(e.fromPoints(i.positions,r),g.DONE):g.FAILED},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._geometryUpdater,t=e._scene.id,r=w[t];r.remove(this._line),0===r.length&&(this._primitives.removeAndDestroy(r),delete w[t]),a(this)},P}),r("DataSources/PolylineVolumeGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/PolylineVolumeGeometry","../Core/PolylineVolumeOutlineGeometry","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.polylinePositions=void 0,this.shapePositions=void 0,this.cornerType=void 0,this.granularity=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"polylineVolume",e.polylineVolume,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new d(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var h=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(h=this._materialProperty.color.getValue(r)),o=t.fromColor(h),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new c(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new h(this._options),attributes:{show:new d(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"polylineVolume"===t){var a=this._entity.polylineVolume;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(u.MINIMUM_VALUE):!0,c=a.outline,h=i(c);if(h&&c.isConstant&&(h=c.getValue(u.MINIMUM_VALUE)),!l&&!h)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.positions,f=a.shape,_=a.show;if(!i(d)||!i(f)||i(_)&&_.isConstant&&!_.getValue(u.MINIMUM_VALUE))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var g=r(a.material,E),y=g instanceof v;this._materialProperty=g,this._fillProperty=r(s,w),this._showProperty=r(_,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=h?r(a.outlineColor,b):void 0;var x=a.granularity,P=a.outlineWidth,A=a.cornerType;if(this._fillEnabled=l,this._outlineEnabled=h,d.isConstant&&f.isConstant&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)){var I=this._options;I.vertexFormat=y?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,I.polylinePositions=d.getValue(u.MINIMUM_VALUE,I.polylinePositions),I.shapePositions=f.getValue(u.MINIMUM_VALUE,I.shape),I.granularity=i(x)?x.getValue(u.MINIMUM_VALUE):void 0,I.cornerType=i(A)?A.getValue(u.MINIMUM_VALUE):void 0,this._outlineWidth=i(P)?P.getValue(u.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.polylineVolume;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(s.show,r,!0)){var u=this._options,d=C.getValueOrUndefined(s.positions,r,u.polylinePositions),v=C.getValueOrUndefined(s.shape,r);if(i(d)&&i(v)){if(u.polylinePositions=d,u.shapePositions=v,u.granularity=C.getValueOrUndefined(s.granularity,r),u.cornerType=C.getValueOrUndefined(s.cornerType,r),!i(s.fill)||s.fill.getValue(r)){var _=y.getValue(r,o.fillMaterialProperty,this._material);this._material=_;var g=new p({material:_,translucent:_.isTranslucent(),closed:!0});u.vertexFormat=g.vertexFormat,this._primitive=n.add(new f({geometryInstances:new l({id:a,geometry:new c(u)}),appearance:g,asynchronous:!1}))}if(i(s.outline)&&s.outline.getValue(r)){u.vertexFormat=m.VERTEX_FORMAT;var E=C.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,x),S=C.getValueOrDefault(s.outlineWidth,r,1),w=1!==E.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new l({id:a,geometry:new h(u),attributes:{color:t.fromColor(E)}}),appearance:new m({flat:!0,translucent:w,renderState:{lineWidth:o._scene.clampLineWidth(S)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/RectangleGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/RectangleGeometry","../Core/RectangleOutlineGeometry","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.rectangle=void 0,this.closeBottom=void 0,this.closeTop=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0,this.stRotation=void 0,this.rotation=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"rectangle",e.rectangle,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new d(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var h=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(h=this._materialProperty.color.getValue(r)),o=t.fromColor(h),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new c(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new h(this._options),attributes:{show:new d(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"rectangle"===t){var a=this._entity.rectangle;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(u.MINIMUM_VALUE):!0,c=a.outline,h=i(c);if(h&&c.isConstant&&(h=c.getValue(u.MINIMUM_VALUE)),!l&&!h)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.coordinates,f=a.show;if(i(f)&&f.isConstant&&!f.getValue(u.MINIMUM_VALUE)||!i(d))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=r(a.material,E),g=_ instanceof v;this._materialProperty=_,this._fillProperty=r(s,w),this._showProperty=r(f,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=h?r(a.outlineColor,b):void 0;var y=a.height,x=a.extrudedHeight,P=a.granularity,A=a.stRotation,I=a.rotation,M=a.outlineWidth,D=a.closeBottom,R=a.closeTop;if(this._fillEnabled=l,this._outlineEnabled=h,d.isConstant&&C.isConstant(y)&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)&&C.isConstant(I)&&C.isConstant(M)&&C.isConstant(D)&&C.isConstant(R)){var O=this._options;O.vertexFormat=g?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,O.rectangle=d.getValue(u.MINIMUM_VALUE,O.rectangle),O.height=i(y)?y.getValue(u.MINIMUM_VALUE):void 0,O.extrudedHeight=i(x)?x.getValue(u.MINIMUM_VALUE):void 0,O.granularity=i(P)?P.getValue(u.MINIMUM_VALUE):void 0,O.stRotation=i(A)?A.getValue(u.MINIMUM_VALUE):void 0,O.rotation=i(I)?I.getValue(u.MINIMUM_VALUE):void 0,O.closeBottom=i(D)?D.getValue(u.MINIMUM_VALUE):void 0,O.closeTop=i(R)?R.getValue(u.MINIMUM_VALUE):void 0,this._isClosed=i(x)&&i(O.closeTop)&&i(O.closeBottom)&&O.closeTop&&O.closeBottom,this._outlineWidth=i(M)?M.getValue(u.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.rectangle;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(s.show,r,!0)){var u=this._options,d=C.getValueOrUndefined(s.coordinates,r,u.rectangle);if(i(d)){if(u.rectangle=d,u.height=C.getValueOrUndefined(s.height,r),u.extrudedHeight=C.getValueOrUndefined(s.extrudedHeight,r),u.granularity=C.getValueOrUndefined(s.granularity,r),u.stRotation=C.getValueOrUndefined(s.stRotation,r),u.rotation=C.getValueOrUndefined(s.rotation,r),u.closeBottom=C.getValueOrUndefined(s.closeBottom,r),u.closeTop=C.getValueOrUndefined(s.closeTop,r),C.getValueOrDefault(s.fill,r,!0)){var v=y.getValue(r,o.fillMaterialProperty,this._material);this._material=v;var _=new p({material:v,translucent:v.isTranslucent(),closed:i(u.extrudedHeight)});u.vertexFormat=_.vertexFormat,this._primitive=n.add(new f({geometryInstances:new l({id:a,geometry:new c(u)}),appearance:_,asynchronous:!1}))}if(C.getValueOrDefault(s.outline,r,!1)){u.vertexFormat=m.VERTEX_FORMAT;var g=C.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,x),E=C.getValueOrDefault(s.outlineWidth,r,1),S=1!==g.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new l({id:a,geometry:new h(u),attributes:{color:t.fromColor(g)}}),appearance:new m({flat:!0,translucent:S,renderState:{lineWidth:o._scene.clampLineWidth(E)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/WallGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Core/WallGeometry","../Core/WallOutlineGeometry","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.positions=void 0,this.minimumHeights=void 0,this.maximumHeights=void 0,this.granularity=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"wall",e.wall,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return!1}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new c(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var d=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(d=this._materialProperty.color.getValue(r)),o=t.fromColor(d),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new h(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new d(this._options),attributes:{show:new c(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"wall"===t){var a=this._entity.wall;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(u.MINIMUM_VALUE):!0,c=a.outline,h=i(c);if(h&&c.isConstant&&(h=c.getValue(u.MINIMUM_VALUE)),!l&&!h)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.positions,f=a.show;if(i(f)&&f.isConstant&&!f.getValue(u.MINIMUM_VALUE)||!i(d))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=r(a.material,E),g=_ instanceof v;this._materialProperty=_,this._fillProperty=r(s,w),this._showProperty=r(f,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=h?r(a.outlineColor,b):void 0;var y=a.minimumHeights,x=a.maximumHeights,P=a.outlineWidth,A=a.granularity;if(this._fillEnabled=l,this._outlineEnabled=h,d.isConstant&&C.isConstant(y)&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)){var I=this._options;I.vertexFormat=g?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,I.positions=d.getValue(u.MINIMUM_VALUE,I.positions),I.minimumHeights=i(y)?y.getValue(u.MINIMUM_VALUE,I.minimumHeights):void 0,I.maximumHeights=i(x)?x.getValue(u.MINIMUM_VALUE,I.maximumHeights):void 0,I.granularity=i(A)?A.getValue(u.MINIMUM_VALUE):void 0,this._outlineWidth=i(P)?P.getValue(u.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0, +this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.wall;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(s.show,r,!0)){var u=this._options,c=C.getValueOrUndefined(s.positions,r,u.positions);if(i(c)){if(u.positions=c,u.minimumHeights=C.getValueOrUndefined(s.minimumHeights,r,u.minimumHeights),u.maximumHeights=C.getValueOrUndefined(s.maximumHeights,r,u.maximumHeights),u.granularity=C.getValueOrUndefined(s.granularity,r),C.getValueOrDefault(s.fill,r,!0)){var v=y.getValue(r,o.fillMaterialProperty,this._material);this._material=v;var _=new p({material:v,translucent:v.isTranslucent(),closed:i(u.extrudedHeight)});u.vertexFormat=_.vertexFormat,this._primitive=n.add(new f({geometryInstances:new l({id:a,geometry:new h(u)}),appearance:_,asynchronous:!1}))}if(C.getValueOrDefault(s.outline,r,!1)){u.vertexFormat=m.VERTEX_FORMAT;var g=C.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,x),E=C.getValueOrDefault(s.outlineWidth,r,1),S=1!==g.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new l({id:a,geometry:new d(u),attributes:{color:t.fromColor(g)}}),appearance:new m({flat:!0,translucent:S,renderState:{lineWidth:o._scene.clampLineWidth(E)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/DataSourceDisplay",["../Core/BoundingSphere","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EventHelper","./BillboardVisualizer","./BoundingSphereState","./BoxGeometryUpdater","./CorridorGeometryUpdater","./CustomDataSource","./CylinderGeometryUpdater","./EllipseGeometryUpdater","./EllipsoidGeometryUpdater","./GeometryVisualizer","./LabelVisualizer","./ModelVisualizer","./PathVisualizer","./PointVisualizer","./PolygonGeometryUpdater","./PolylineGeometryUpdater","./PolylineVolumeGeometryUpdater","./RectangleGeometryUpdater","./WallGeometryUpdater"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T){"use strict";var b=function(e){var r=e.scene,i=e.dataSourceCollection;this._eventHelper=new a,this._eventHelper.add(i.dataSourceAdded,this._onDataSourceAdded,this),this._eventHelper.add(i.dataSourceRemoved,this._onDataSourceRemoved,this),this._dataSourceCollection=i,this._scene=r,this._visualizersCallback=t(e.visualizersCallback,b.defaultVisualizersCallback);for(var n=0,o=i.length;o>n;n++)this._onDataSourceAdded(i,i.get(n));var s=new h;this._onDataSourceAdded(void 0,s),this._defaultDataSource=s};b.defaultVisualizersCallback=function(e,t){var r=t.entities;return[new s(e,r),new f(u,e,r),new f(d,e,r),new f(c,e,r),new f(p,e,r),new f(m,e,r),new f(C,e,r),new f(E,e,r),new f(S,e,r),new f(w,e,r),new f(T,e,r),new v(e,r),new _(e,r),new y(e,r),new g(e,r)]},i(b.prototype,{scene:{get:function(){return this._scene}},dataSources:{get:function(){return this._dataSourceCollection}},defaultDataSource:{get:function(){return this._defaultDataSource}}}),b.prototype.isDestroyed=function(){return!1},b.prototype.destroy=function(){this._eventHelper.removeAll();for(var e=this._dataSourceCollection,t=0,r=e.length;r>t;++t)this._onDataSourceRemoved(this._dataSourceCollection,e.get(t));return this._onDataSourceRemoved(void 0,this._defaultDataSource),n(this)},b.prototype.update=function(e){var t,i,n,o,a=!0,s=this._dataSourceCollection,l=s.length;for(t=0;l>t;t++){var u=s.get(t);for(r(u.update)&&(a=u.update(e)&&a),n=u._visualizers,o=n.length,i=0;o>i;i++)a=n[i].update(e)&&a}for(n=this._defaultDataSource._visualizers,o=n.length,i=0;o>i;i++)a=n[i].update(e)&&a;return a};var x=[],P=new e;return b.prototype.getBoundingSphere=function(t,i,n){var o,a,s=this._defaultDataSource;if(!s.entities.contains(t)){s=void 0;var u=this._dataSourceCollection;for(a=u.length,o=0;a>o;o++){var c=u.get(o);if(c.entities.contains(t)){s=c;break}}}if(!r(s))return l.FAILED;var h=x,d=P,p=0,m=l.DONE,f=s._visualizers,v=f.length;for(o=0;v>o;o++){var _=f[o];if(r(_.getBoundingSphere)){if(m=f[o].getBoundingSphere(t,d),!i&&m===l.PENDING)return l.PENDING;m===l.DONE&&(h[p]=e.clone(d,h[p]),p++)}}return 0===p?l.FAILED:(h.length=p,e.fromBoundingSpheres(h,n),l.DONE)},b.prototype._onDataSourceAdded=function(e,t){var r=this._visualizersCallback(this._scene,t);t._visualizers=r},b.prototype._onDataSourceRemoved=function(e,t){for(var r=t._visualizers,i=r.length,n=0;i>n;n++)r[n].destroy(),t._visualizers=void 0},b}),r("DataSources/DynamicGeometryUpdater",["../Core/DeveloperError"],function(e){"use strict";var t=function(){e.throwInstantiationError()};return t.prototype.update=e.throwInstantiationError,t.prototype.getBoundingSphere=e.throwInstantiationError,t.prototype.isDestroyed=e.throwInstantiationError,t.prototype.destroy=e.throwInstantiationError,t}),r("DataSources/EntityView",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartesian4","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/HeadingPitchRange","../Core/JulianDate","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Transforms","../Scene/SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,r,i,o,a,s,l){var d=e.scene.mode,f=a.getValue(s,e._lastCartesian);if(n(f)){var A,I,M,D=!1;if(d===m.SCENE3D){x=u.addSeconds(s,.001,x);var R=a.getValue(x,C);if(n(R)){var O,N=p.computeFixedToIcrfMatrix(s,v),L=p.computeFixedToIcrfMatrix(x,_);n(N)&&n(L)?O=h.transpose(N,g):(O=p.computeTemeToPseudoFixedMatrix(s,g),N=h.transpose(O,v),L=p.computeTemeToPseudoFixedMatrix(x,_),h.transpose(L,L));var F=h.multiplyByVector(N,f,T),B=h.multiplyByVector(L,R,b);t.subtract(F,B,w);var V=1e3*t.magnitude(w),z=3986004418e5,k=-z/(V*V-2*z/t.magnitude(F));0>k||k>P*l.maximumRadius?(A=E,t.normalize(f,A),t.negate(A,A),M=t.clone(t.UNIT_Z,S),I=t.cross(M,A,C),t.magnitude(I)>c.EPSILON7&&(t.normalize(A,A),t.normalize(I,I),M=t.cross(A,I,S),t.normalize(M,M),D=!0)):t.equalsEpsilon(f,R,c.EPSILON7)||(M=E,t.normalize(F,M),t.normalize(B,B),I=t.cross(M,B,S),t.equalsEpsilon(I,t.ZERO,c.EPSILON7)||(A=t.cross(I,M,C),h.multiplyByVector(O,A,A),h.multiplyByVector(O,I,I),h.multiplyByVector(O,M,M),t.normalize(A,A),t.normalize(I,I),t.normalize(M,M),D=!0))}}n(e._boundingSphereOffset)&&t.add(e._boundingSphereOffset,f,f);var U,G,W;o&&(U=t.clone(r.position,w),G=t.clone(r.direction,T),W=t.clone(r.up,b));var H=y;D?(H[0]=A.x,H[1]=A.y,H[2]=A.z,H[3]=0,H[4]=I.x,H[5]=I.y,H[6]=I.z,H[7]=0,H[8]=M.x,H[9]=M.y,H[10]=M.z,H[11]=0,H[12]=f.x,H[13]=f.y,H[14]=f.z,H[15]=0):p.eastNorthUpToFixedFrame(f,l,H),r._setTransform(H),o&&(t.clone(U,r.position),t.clone(G,r.direction),t.clone(W,r.up),t.cross(G,W,r.right))}if(i){var q=d===m.SCENE2D||t.equals(e._offset3D,t.ZERO)?void 0:e._offset3D;r.lookAtTransform(r.transform,q)}}var v=new h,_=new h,g=new h,y=new d,C=new t,E=new t,S=new t,w=new t,T=new t,b=new t,x=new u,P=1.25,A=function(r,n,o,a){this.entity=r,this.scene=n,this.ellipsoid=i(o,s.WGS84),this.boundingSphere=e.clone(a),this._boundingSphereOffset=void 0,this._lastEntity=void 0,this._mode=void 0,this._lastCartesian=new t,this._defaultOffset3D=void 0,this._offset3D=new t};o(A,{defaultOffset3D:{get:function(){return this._defaultOffset3D},set:function(e){this._defaultOffset3D=t.clone(e,new t)}}}),A.defaultOffset3D=new t(-14e3,3500,3500);var I=new l,M=new t;return A.prototype.update=function(e){var r=this.scene,i=this.entity,o=this.ellipsoid,a=r.mode;if(a!==m.MORPHING){var s=i.position,l=i!==this._lastEntity,u=a!==this._mode,h=this._offset3D,d=r.camera,p=l||u,v=!0;if(l){var _=i.viewFrom,g=n(_),y=this.boundingSphere;if(this._boundingSphereOffset=void 0,!g&&n(y)){var C=r.screenSpaceCameraController;C.minimumZoomDistance=Math.min(C.minimumZoomDistance,.5*y.radius),I.pitch=-c.PI_OVER_FOUR,I.range=0;var E=s.getValue(e,M);if(n(E)){var S=2-1/Math.max(1,t.magnitude(E)/o.maximumRadius);I.pitch*=S}d.viewBoundingSphere(y,I),this._boundingSphereOffset=t.subtract(y.center,i.position.getValue(e),new t),p=!1,v=!1}else g&&n(_.getValue(e,h))||t.clone(A._defaultOffset3D,h)}else u||r.mode===m.MORPHING||this._mode===m.SCENE2D||t.clone(d.position,h);this._lastEntity=i,this._mode=r.mode!==m.MORPHING?r.mode:this._mode,r.mode!==m.MORPHING&&f(this,d,p,v,s,e,o)}},A}),!function(){function e(e,t){function r(t){var r,i=e.arcs[0>t?~t:t],n=i[0];return e.transform?(r=[0,0],i.forEach(function(e){r[0]+=e[0],r[1]+=e[1]})):r=i[i.length-1],0>t?[r,n]:[n,r]}function i(e,t){for(var r in e){var i=e[r];delete t[i.start],delete i.start,delete i.end,i.forEach(function(e){n[0>e?~e:e]=1}),s.push(i)}}var n={},o={},a={},s=[],l=-1;return t.forEach(function(r,i){var n,o=e.arcs[0>r?~r:r];o.length<3&&!o[1][0]&&!o[1][1]&&(n=t[++l],t[l]=r,t[i]=n)}),t.forEach(function(e){var t,i,n=r(e),s=n[0],l=n[1];if(t=a[s])if(delete a[t.end],t.push(e),t.end=l,i=o[l]){delete o[i.start];var u=i===t?t:t.concat(i);o[u.start=t.start]=a[u.end=i.end]=u}else o[t.start]=a[t.end]=t;else if(t=o[l])if(delete o[t.start],t.unshift(e),t.start=s,i=a[s]){delete a[i.end];var c=i===t?t:i.concat(t);o[c.start=i.start]=a[c.end=t.end]=c}else o[t.start]=a[t.end]=t;else t=[e],o[t.start=s]=a[t.end=l]=t}),i(a,o),i(o,a),t.forEach(function(e){n[0>e?~e:e]||s.push([e])}),s}function t(t,r,i){function n(e){var t=0>e?~e:e;(c[t]||(c[t]=[])).push({i:e,g:u})}function o(e){e.forEach(n)}function a(e){e.forEach(o)}function s(e){"GeometryCollection"===e.type?e.geometries.forEach(s):e.type in h&&(u=e,h[e.type](e.arcs))}var l=[];if(arguments.length>1){var u,c=[],h={LineString:o,MultiLineString:a,Polygon:a,MultiPolygon:function(e){e.forEach(a)}};s(r),c.forEach(arguments.length<3?function(e){l.push(e[0].i)}:function(e){i(e[0].g,e[e.length-1].g)&&l.push(e[0].i)})}else for(var d=0,p=t.arcs.length;p>d;++d)l.push(d);return{type:"MultiLineString",arcs:e(t,l)}}function i(t,r){function i(e){e.forEach(function(t){t.forEach(function(t){(a[t=0>t?~t:t]||(a[t]=[])).push(e)})}),l.push(e)}function o(e){return d(s(t,{type:"Polygon",arcs:[e]}).coordinates[0])>0}var a={},l=[],u=[];return r.forEach(function(e){"Polygon"===e.type?i(e.arcs):"MultiPolygon"===e.type&&e.arcs.forEach(i)}),l.forEach(function(e){if(!e._){var t=[],r=[e];for(e._=1,u.push(t);e=r.pop();)t.push(e),e.forEach(function(e){e.forEach(function(e){a[0>e?~e:e].forEach(function(e){e._||(e._=1,r.push(e))})})})}}),l.forEach(function(e){delete e._}),{type:"MultiPolygon",arcs:u.map(function(r){var i=[];if(r.forEach(function(e){e.forEach(function(e){e.forEach(function(e){a[0>e?~e:e].length<2&&i.push(e)})})}),i=e(t,i),(n=i.length)>1)for(var s,l=o(r[0][0]),u=0;ue?~e:e],n=0,o=i.length;o>n;++n)t.push(r=i[n].slice()),u(r,n);0>e&&l(t,o)}function i(e){return e=e.slice(),u(e,0),e}function n(e){for(var t=[],i=0,n=e.length;n>i;++i)r(e[i],t);return t.length<2&&t.push(t[0].slice()),t}function o(e){for(var t=n(e);t.length<4;)t.push(t[0].slice());return t}function a(e){return e.map(o)}function s(e){var t=e.type;return"GeometryCollection"===t?{type:t,geometries:e.geometries.map(s)}:t in h?{type:t,coordinates:h[t](e)}:null}var u=v(e.transform),c=e.arcs,h={Point:function(e){return i(e.coordinates)},MultiPoint:function(e){return e.coordinates.map(i)},LineString:function(e){return n(e.arcs)},MultiLineString:function(e){return e.arcs.map(n)},Polygon:function(e){return a(e.arcs)},MultiPolygon:function(e){return e.arcs.map(a)}};return s(t)}function l(e,t){for(var r,i=e.length,n=i-t;n<--i;)r=e[n],e[n++]=e[i],e[i]=r}function u(e,t){for(var r=0,i=e.length;i>r;){var n=r+i>>>1;e[n]e&&(e=~e);var r=n[e];r?r.push(t):n[e]=[t]})}function r(e,r){e.forEach(function(e){t(e,r)})}function i(e,t){"GeometryCollection"===e.type?e.geometries.forEach(function(e){i(e,t)}):e.type in a&&a[e.type](e.arcs,t)}var n={},o=e.map(function(){return[]}),a={LineString:t,MultiLineString:r,Polygon:r,MultiPolygon:function(e,t){e.forEach(function(e){r(e,t)})}};e.forEach(i);for(var s in n)for(var l=n[s],c=l.length,h=0;c>h;++h)for(var d=h+1;c>d;++d){var p,m=l[h],f=l[d];(p=o[m])[s=u(p,f)]!==f&&p.splice(s,0,f),(p=o[f])[s=u(p,m)]!==m&&p.splice(s,0,m)}return o}function h(e,t){function r(e){o.remove(e),e[1][2]=t(e),o.push(e)}var i=v(e.transform),n=_(e.transform),o=f();return t||(t=p),e.arcs.forEach(function(e){for(var a,s,l=[],u=0,c=0,h=e.length;h>c;++c)s=e[c],i(e[c]=[s[0],s[1],1/0],c);for(var c=1,h=e.length-1;h>c;++c)a=e.slice(c-1,c+2),a[1][2]=t(a),l.push(a),o.push(a);for(var c=0,h=l.length;h>c;++c)a=l[c],a.previous=l[c-1],a.next=l[c+1];for(;a=o.pop();){var d=a.previous,p=a.next;a[1][2]0;){var r=(t+1>>1)-1,n=i[r];if(m(e,n)>=0)break;i[n._=t]=n,i[e._=t=r]=e}}function t(e,t){for(;;){var r=t+1<<1,o=r-1,a=t,s=i[a];if(n>o&&m(i[o],s)<0&&(s=i[a=o]),n>r&&m(i[r],s)<0&&(s=i[a=r]),a===t)break;i[s._=t]=s,i[e._=t=a]=e}}var r={},i=[],n=0;return r.push=function(t){return e(i[t._=n]=t,n++),n},r.pop=function(){if(!(0>=n)){var e,r=i[0];return--n>0&&(e=i[n],t(i[e._=0]=e,0)),r}},r.remove=function(r){var o,a=r._;if(i[a]===r)return a!==--n&&(o=i[n],(m(o,r)<0?e:t)(i[o._=a]=o,a)),a},r}function v(e){if(!e)return g;var t,r,i=e.scale[0],n=e.scale[1],o=e.translate[0],a=e.translate[1];return function(e,s){s||(t=r=0),e[0]=(t+=e[0])*i+o,e[1]=(r+=e[1])*n+a}}function _(e){if(!e)return g;var t,r,i=e.scale[0],n=e.scale[1],o=e.translate[0],a=e.translate[1];return function(e,s){s||(t=r=0);var l=(e[0]-o)/i|0,u=(e[1]-a)/n|0;e[0]=l-t,e[1]=u-r,t=l,r=u}}function g(){}var y={version:"1.6.18",mesh:function(e){return s(e,t.apply(this,arguments))},meshArcs:t,merge:function(e){return s(e,i.apply(this,arguments))},mergeArcs:i,feature:o,neighbors:c,presimplify:h};"function"==typeof r&&r.amd?r("ThirdParty/topojson",y):"object"==typeof module&&module.exports?module.exports=y:this.topojson=y}(),r("DataSources/GeoJsonDataSource",["../Core/Cartesian3","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/getFilenameFromUri","../Core/loadJson","../Core/PinBuilder","../Core/PolygonHierarchy","../Core/RuntimeError","../Scene/VerticalOrigin","../ThirdParty/topojson","../ThirdParty/when","./BillboardGraphics","./CallbackProperty","./ColorMaterialProperty","./ConstantPositionProperty","./ConstantProperty","./DataSource","./EntityCollection","./PolygonGraphics","./PolylineGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b){"use strict";function x(t){return e.fromDegrees(t[0],t[1],t[2])}function P(e,t){var r="";for(var i in e)if(e.hasOwnProperty(i)){if(i===t||-1!==oe.indexOf(i))continue;var n=e[i];o(n)&&(r+="object"==typeof n?""+i+""+P(n)+"":""+i+""+n+"")}return r.length>0&&(r=''+r+"
"),r}function A(e,t,r){var i;return function(o,a){return n(i)||(i=e(t,r)),i}}function I(e,t){return new g(A(P,e,t),!0)}function M(e,t,i){var a=e.id;if(o(a)&&"Feature"===e.type){for(var s=2,l=a;n(t.getById(l));)l=a+"_"+s,s++;a=l}else a=r();var u=t.getOrCreateEntity(a),c=e.properties;if(o(c)){u.addProperty("properties"),u.properties=c;var h,d=c.title;if(o(d))u.name=d,h="title";else{var p=Number.MAX_VALUE;for(var m in c)if(c.hasOwnProperty(m)&&c[m]){var f=m.toLowerCase();if(p>1&&"title"===f){p=1,h=m;break}p>2&&"name"===f?(p=2,h=m):p>3&&/title/i.test(m)?(p=3,h=m):p>4&&/name/i.test(m)&&(p=4,h=m)}o(h)&&(u.name=c[h])}var v=c.description;n(v)?null!==v&&(u.description=new E(v)):u.description=i(c,h)}return u}function D(e,t){for(var r=new Array(e.length),i=0;ia;a++)R(e,o[a],void 0,i,n)}function N(e,t,r,i,n){for(var a=r.geometries,s=0,l=a.length;l>s;s++){var u=a[s],c=u.type,h=le[c];if(!o(h))throw new p("Unknown geometry type: "+c);h(e,t,u,i,n)}}function L(e,r,a,s,l){var u=l.markerSymbol,c=l.markerColor,h=l.markerSize,d=r.properties;if(o(d)){var p=d["marker-color"];o(p)&&(c=t.fromCssColorString(p)),h=i(ne[d["marker-size"]],h);var f=d["marker-symbol"];o(f)&&(u=f)}ae[0]=u,ae[1]=c,ae[2]=h;var g;JSON.stringify(ae);g=n(u)?1===u.length?e._pinBuilder.fromText(u.toUpperCase(),c,h):e._pinBuilder.fromMakiIconId(u,c,h):e._pinBuilder.fromColor(c,h),e._promises.push(v(g,function(t){var i=new _;i.verticalOrigin=new E(m.BOTTOM),i.image=new E(t);var n=M(r,e._entityCollection,l.describe);n.billboard=i,n.position=new C(a(s))}))}function F(e,t,r,i,n){L(e,t,i,r.coordinates,n)}function B(e,t,r,i,n){for(var o=r.coordinates,a=0;aw;w++)S.push(new d(D(a[w],i)));var x=a[0];C.hierarchy=new E(new d(D(x,i),S)),x[0].length>2&&(C.perPositionHeight=new E(!0));var P=M(r,e._entityCollection,s.describe);P.polygon=C}}function G(e,t,r,i,n){U(e,t,i,r.coordinates,n)}function W(e,t,r,i,n){for(var o=r.coordinates,a=0;ao;o++){var s=r[o],l=s.getType(),u=s.getText();if("element"===l)"a"===s.getTagName()&&(s.isClosing()?i=Math.max(i-1,0):i++),n.push(u);else if("entity"===l||"comment"===l)n.push(u);else if(0===i){var c=this.linkifyStr(u);n.push(c)}else n.push(u)}return n.join("")},linkifyStr:function(e){return this.getMatchParser().replace(e,this.createMatchReturnVal,this)},createMatchReturnVal:function(t){var r;if(this.replaceFn&&(r=this.replaceFn.call(this,this,t)),"string"==typeof r)return r;if(r===!1)return t.getMatchedText();if(r instanceof e.HtmlTag)return r.toAnchorString();var i=this.getTagBuilder(),n=i.build(t);return n.toAnchorString()},getHtmlParser:function(){var t=this.htmlParser;return t||(t=this.htmlParser=new e.htmlParser.HtmlParser),t},getMatchParser:function(){var t=this.matchParser;return t||(t=this.matchParser=new e.matchParser.MatchParser({urls:this.urls,email:this.email,twitter:this.twitter,phone:this.phone,hashtag:this.hashtag,stripPrefix:this.stripPrefix})),t},getTagBuilder:function(){var t=this.tagBuilder;return t||(t=this.tagBuilder=new e.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),t}},e.link=function(t,r){var i=new e(r);return i.link(t)},e.match={},e.htmlParser={},e.matchParser={},e.Util={abstractMethod:function(){throw"abstract"},trimRegex:/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,assign:function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e},extend:function(t,r){var i=t.prototype,n=function(){};n.prototype=i;var o;o=r.hasOwnProperty("constructor")?r.constructor:function(){i.constructor.apply(this,arguments)};var a=o.prototype=new n;return a.constructor=o,a.superclass=i,delete r.constructor,e.Util.assign(a,r),o},ellipsis:function(e,t,r){return e.length>t&&(r=null==r?"..":r,e=e.substring(0,t-r.length)+r),e},indexOf:function(e,t){if(Array.prototype.indexOf)return e.indexOf(t);for(var r=0,i=e.length;i>r;r++)if(e[r]===t)return r;return-1},splitAndCapture:function(e,t){if(!t.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var r,i=[],n=0;r=t.exec(e);)i.push(e.substring(n,r.index)),i.push(r[0]),n=r.index+r[0].length;return i.push(e.substring(n)),i},trim:function(e){return e.replace(this.trimRegex,"")}},e.HtmlTag=e.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(t){e.Util.assign(this,t),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(e){return this.tagName=e,this},getTagName:function(){return this.tagName||""},setAttr:function(e,t){var r=this.getAttrs();return r[e]=t,this},getAttr:function(e){return this.getAttrs()[e]},setAttrs:function(t){var r=this.getAttrs();return e.Util.assign(r,t),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(e){return this.setAttr("class",e)},addClass:function(t){for(var r,i=this.getClass(),n=this.whitespaceRegex,o=e.Util.indexOf,a=i?i.split(n):[],s=t.split(n);r=s.shift();)-1===o(a,r)&&a.push(r);return this.getAttrs()["class"]=a.join(" "),this},removeClass:function(t){for(var r,i=this.getClass(),n=this.whitespaceRegex,o=e.Util.indexOf,a=i?i.split(n):[],s=t.split(n);a.length&&(r=s.shift());){var l=o(a,r);-1!==l&&a.splice(l,1)}return this.getAttrs()["class"]=a.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(e){return-1!==(" "+this.getClass()+" ").indexOf(" "+e+" ")},setInnerHtml:function(e){return this.innerHtml=e,this},getInnerHtml:function(){return this.innerHtml||""},toAnchorString:function(){var e=this.getTagName(),t=this.buildAttrsStr();return t=t?" "+t:"",["<",e,t,">",this.getInnerHtml(),""].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var e=this.getAttrs(),t=[];for(var r in e)e.hasOwnProperty(r)&&t.push(r+'="'+e[r]+'"');return t.join(" ")}}),e.AnchorTagBuilder=e.Util.extend(Object,{constructor:function(t){e.Util.assign(this,t)},build:function(t){var r=new e.HtmlTag({tagName:"a",attrs:this.createAttrs(t.getType(),t.getAnchorHref()),innerHtml:this.processAnchorText(t.getAnchorText())});return r},createAttrs:function(e,t){var r={href:t},i=this.createCssClass(e);return i&&(r["class"]=i),this.newWindow&&(r.target="_blank"),r},createCssClass:function(e){var t=this.className;return t?t+" "+t+"-"+e:""},processAnchorText:function(e){return e=this.doTruncate(e)},doTruncate:function(t){return e.Util.ellipsis(t,this.truncate||Number.POSITIVE_INFINITY)}}),e.htmlParser.HtmlParser=e.Util.extend(Object,{htmlRegex:function(){var e=/!--([\s\S]+?)--/,t=/[0-9a-zA-Z][0-9a-zA-Z:]*/,r=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,i=/(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/,n=r.source+"(?:\\s*=\\s*"+i.source+")?";return new RegExp(["(?:","<(!DOCTYPE)","(?:","\\s+","(?:",n,"|",i.source+")",")*",">",")","|","(?:","<(/)?","(?:",e.source,"|","(?:","("+t.source+")","(?:","\\s+",n,")*","\\s*/?",")",")",">",")"].join(""),"gi")}(),htmlCharacterEntitiesRegex:/( | |<|<|>|>|"|"|')/gi,parse:function(e){for(var t,r,i=this.htmlRegex,n=0,o=[];null!==(t=i.exec(e));){var a=t[0],s=t[3],l=t[1]||t[4],u=!!t[2],c=e.substring(n,t.index);c&&(r=this.parseTextAndEntityNodes(c),o.push.apply(o,r)),s?o.push(this.createCommentNode(a,s)):o.push(this.createElementNode(a,l,u)),n=t.index+a.length}if(nn;n+=2){var a=i[n],s=i[n+1];a&&r.push(this.createTextNode(a)),s&&r.push(this.createEntityNode(s))}return r},createCommentNode:function(t,r){return new e.htmlParser.CommentNode({text:t,comment:e.Util.trim(r)})},createElementNode:function(t,r,i){return new e.htmlParser.ElementNode({text:t,tagName:r.toLowerCase(),closing:i})},createEntityNode:function(t){return new e.htmlParser.EntityNode({text:t})},createTextNode:function(t){return new e.htmlParser.TextNode({text:t})}}),e.htmlParser.HtmlNode=e.Util.extend(Object,{text:"",constructor:function(t){e.Util.assign(this,t)},getType:e.Util.abstractMethod,getText:function(){return this.text}}),e.htmlParser.CommentNode=e.Util.extend(e.htmlParser.HtmlNode,{comment:"",getType:function(){return"comment"},getComment:function(){return this.comment}}),e.htmlParser.ElementNode=e.Util.extend(e.htmlParser.HtmlNode,{tagName:"",closing:!1,getType:function(){return"element"},getTagName:function(){return this.tagName},isClosing:function(){return this.closing}}),e.htmlParser.EntityNode=e.Util.extend(e.htmlParser.HtmlNode,{getType:function(){return"entity"}}),e.htmlParser.TextNode=e.Util.extend(e.htmlParser.HtmlNode,{getType:function(){return"text"}}),e.matchParser.MatchParser=e.Util.extend(Object,{urls:!0,email:!0,twitter:!0,phone:!0,hashtag:!1,stripPrefix:!0,matcherRegex:function(){var e=/(^|[^\w])@(\w{1,15})/,t=/(^|[^\w])#(\w{1,15})/,r=/(?:[\-;:&=\+\$,\w\.]+@)/,i=/(?:\+?\d{1,3}[-\s.])?\(?\d{3}\)?[-\s.]?\d{3}[-\s.]\d{4}/,n=/(?:[A-Za-z][-.+A-Za-z0-9]+:(?![A-Za-z][-.+A-Za-z0-9]+:\/\/)(?!\d+\/?)(?:\/\/)?)/,o=/(?:www\.)/,a=/[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/,s=/\.(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/,l=/[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]?!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]]/; +return new RegExp(["(",e.source,")","|","(",r.source,a.source,s.source,")","|","(","(?:","(",n.source,a.source,")","|","(?:","(.?//)?",o.source,a.source,")","|","(?:","(.?//)?",a.source,s.source,")",")","(?:"+l.source+")?",")","|","(",i.source,")","|","(",t.source,")"].join(""),"gi")}(),charBeforeProtocolRelMatchRegex:/^(.)?\/\//,constructor:function(t){e.Util.assign(this,t),this.matchValidator=new e.MatchValidator},replace:function(e,t,r){var i=this;return e.replace(this.matcherRegex,function(e,n,o,a,s,l,u,c,h,d,p,m,f){var v=i.processCandidateMatch(e,n,o,a,s,l,u,c,h,d,p,m,f);if(v){var _=t.call(r,v.match);return v.prefixStr+_+v.suffixStr}return e})},processCandidateMatch:function(t,r,i,n,o,a,s,l,u,c,h,d,p){var m,f=l||u,v="",_="";if(a&&!this.urls||o&&!this.email||c&&!this.phone||r&&!this.twitter||h&&!this.hashtag||!this.matchValidator.isValidMatch(a,s,f))return null;if(this.matchHasUnbalancedClosingParen(t)&&(t=t.substr(0,t.length-1),_=")"),o)m=new e.match.Email({matchedText:t,email:o});else if(r)i&&(v=i,t=t.slice(1)),m=new e.match.Twitter({matchedText:t,twitterHandle:n});else if(c){var g=t.replace(/\D/g,"");m=new e.match.Phone({matchedText:t,number:g})}else if(h)d&&(v=d,t=t.slice(1)),m=new e.match.Hashtag({matchedText:t,serviceName:this.hashtag,hashtag:p});else{if(f){var y=f.match(this.charBeforeProtocolRelMatchRegex)[1]||"";y&&(v=y,t=t.slice(1))}m=new e.match.Url({matchedText:t,url:t,protocolUrlMatch:!!s,protocolRelativeMatch:!!f,stripPrefix:this.stripPrefix})}return{prefixStr:v,suffixStr:_,match:m}},matchHasUnbalancedClosingParen:function(e){var t=e.charAt(e.length-1);if(")"===t){var r=e.match(/\(/g),i=e.match(/\)/g),n=r&&r.length||0,o=i&&i.length||0;if(o>n)return!0}return!1}}),e.MatchValidator=e.Util.extend(Object,{invalidProtocolRelMatchRegex:/^[\w]\/\//,hasFullProtocolRegex:/^[A-Za-z][-.+A-Za-z0-9]+:\/\//,uriSchemeRegex:/^[A-Za-z][-.+A-Za-z0-9]+:/,hasWordCharAfterProtocolRegex:/:[^\s]*?[A-Za-z]/,isValidMatch:function(e,t,r){return t&&!this.isValidUriScheme(t)||this.urlMatchDoesNotHaveProtocolOrDot(e,t)||this.urlMatchDoesNotHaveAtLeastOneWordChar(e,t)||this.isInvalidProtocolRelativeMatch(r)?!1:!0},isValidUriScheme:function(e){var t=e.match(this.uriSchemeRegex)[0].toLowerCase();return"javascript:"!==t&&"vbscript:"!==t},urlMatchDoesNotHaveProtocolOrDot:function(e,t){return!(!e||t&&this.hasFullProtocolRegex.test(t)||-1!==e.indexOf("."))},urlMatchDoesNotHaveAtLeastOneWordChar:function(e,t){return e&&t?!this.hasWordCharAfterProtocolRegex.test(e):!1},isInvalidProtocolRelativeMatch:function(e){return!!e&&this.invalidProtocolRelMatchRegex.test(e)}}),e.match.Match=e.Util.extend(Object,{constructor:function(t){e.Util.assign(this,t)},getType:e.Util.abstractMethod,getMatchedText:function(){return this.matchedText},getAnchorHref:e.Util.abstractMethod,getAnchorText:e.Util.abstractMethod}),e.match.Email=e.Util.extend(e.match.Match,{getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),e.match.Hashtag=e.Util.extend(e.match.Match,{getType:function(){return"hashtag"},getHashtag:function(){return this.hashtag},getAnchorHref:function(){var e=this.serviceName,t=this.hashtag;switch(e){case"twitter":return"https://twitter.com/hashtag/"+t;case"facebook":return"https://www.facebook.com/hashtag/"+t;default:throw new Error("Unknown service name to point hashtag to: ",e)}},getAnchorText:function(){return"#"+this.hashtag}}),e.match.Phone=e.Util.extend(e.match.Match,{getType:function(){return"phone"},getNumber:function(){return this.number},getAnchorHref:function(){return"tel:"+this.number},getAnchorText:function(){return this.matchedText}}),e.match.Twitter=e.Util.extend(e.match.Match,{getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),e.match.Url=e.Util.extend(e.match.Match,{urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,protocolPrepended:!1,getType:function(){return"url"},getUrl:function(){var e=this.url;return this.protocolRelativeMatch||this.protocolUrlMatch||this.protocolPrepended||(e=this.url="http://"+e,this.protocolPrepended=!0),e},getAnchorHref:function(){var e=this.getUrl();return e.replace(/&/g,"&")},getAnchorText:function(){var e=this.getUrl();return this.protocolRelativeMatch&&(e=this.stripProtocolRelativePrefix(e)),this.stripPrefix&&(e=this.stripUrlPrefix(e)),e=this.removeTrailingSlash(e)},stripUrlPrefix:function(e){return e.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(e){return e.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(e){return"/"===e.charAt(e.length-1)&&(e=e.slice(0,-1)),e}}),e}),r("ThirdParty/zip",["../Core/buildModuleUrl","../Core/defineProperties"],function(e,t){var r={};return function(r){function i(){var e=-1,t=this;t.append=function(r){var i,n=t.table;for(i=0;i>>8^n[255&(e^r[i])]},t.get=function(){return~e}}function n(e,t,r){return e.slice?e.slice(t,t+r):e.webkitSlice?e.webkitSlice(t,t+r):e.mozSlice?e.mozSlice(t,t+r):e.msSlice?e.msSlice(t,t+r):void 0}function o(e,t){var r,i;return r=new ArrayBuffer(e),i=new Uint8Array(r),t&&i.set(t,0),{buffer:r,array:i,view:new DataView(r)}}function a(){}function s(e){function t(t,r){var o=new Blob([e],{type:k});i=new u(o),i.init(function(){n.size=i.size,t()},r)}function r(e,t,r,n){i.readUint8Array(e,t,r,n)}var i,n=this;n.size=0,n.init=t,n.readUint8Array=r}function l(e){function t(t){for(var r=e.length;"="==e.charAt(r-1);)r--;i=e.indexOf(",")+1,n.size=Math.floor(.75*(r-i)),t()}function r(t,r,n){var a,s=o(r),l=4*Math.floor(t/3),u=4*Math.ceil((t+r)/3),c=window.atob(e.substring(l+i,u+i)),h=t-3*Math.floor(l/4);for(a=h;h+r>a;a++)s.array[a-h]=c.charCodeAt(a);n(s.array)}var i,n=this;n.size=0,n.init=t,n.readUint8Array=r}function u(e){function t(t){this.size=e.size,t()}function r(t,r,i,o){var a=new FileReader;a.onload=function(e){i(new Uint8Array(e.target.result))},a.onerror=o,a.readAsArrayBuffer(n(e,t,r))}var i=this;i.size=0,i.init=t,i.readUint8Array=r}function c(){}function h(e){function t(e){n=new Blob([],{type:k}),e()}function r(e,t){n=new Blob([n,A?e:e.buffer],{type:k}),t()}function i(t,r){var i=new FileReader;i.onload=function(e){t(e.target.result)},i.onerror=r,i.readAsText(n,e)}var n,o=this;o.init=t,o.writeUint8Array=r,o.getData=i}function d(e){function t(t){o+="data:"+(e||"")+";base64,",t()}function r(e,t){var r,i=a.length,n=a;for(a="",r=0;r<3*Math.floor((i+e.length)/3)-i;r++)n+=String.fromCharCode(e[r]);for(;r2?o+=window.btoa(n):a=n,t()}function i(e){e(o+window.btoa(a))}var n=this,o="",a="";n.init=t,n.writeUint8Array=r,n.getData=i}function p(e){function t(t){n=new Blob([],{type:e}),t()}function r(t,r){n=new Blob([n,A?t:t.buffer],{type:e}),r()}function i(e){e(n)}var n,o=this;o.init=t,o.writeUint8Array=r,o.getData=i}function m(e,t,r,i,n,o,a,s,l,u){function c(){e.removeEventListener(U,h,!1),s(m)}function h(e){var t=e.data,i=t.data;t.onappend&&(m+=i.length,r.writeUint8Array(i,function(){o(!1,i),d()},u)),t.onflush&&(i?(m+=i.length,r.writeUint8Array(i,function(){o(!1,i),c()},u)):c()),t.progress&&a&&a(p+t.current,n)}function d(){p=f*B,n>p?t.readUint8Array(i+p,Math.min(B,n-p),function(t){e.postMessage({append:!0,data:t}),f++,a&&a(p,n),o(!0,t)},l):e.postMessage({flush:!0})}var p,m,f=0;m=0,e.addEventListener(U,h,!1),d()}function f(e,t,r,i,n,o,a,s,l,u){function c(){var m;h=d*B,n>h?t.readUint8Array(i+h,Math.min(B,n-h),function(t){var s=e.append(t,function(){a&&a(i+h,n)});p+=s.length,o(!0,t),r.writeUint8Array(s,function(){o(!1,s),d++,setTimeout(c,1)},u),a&&a(h,n)},l):(m=e.flush(),m?(p+=m.length,r.writeUint8Array(m,function(){o(!1,m),s(p)},u)):s(p))}var h,d=0,p=0;c()}function v(e,t,n,o,a,s,l,u,c){function h(e,t){a&&!e&&v.append(t)}function d(e){s(e,v.get())}var p,v=new i;return r.zip.useWebWorkers?(p=new Worker(r.zip.workerScriptsPath+V),m(p,e,t,n,o,h,l,d,u,c)):f(new r.zip.Inflater,e,t,n,o,h,l,d,u,c),p}function _(e,t,n,o,a,s,l){function u(e,t){e&&p.append(t)}function c(e){o(e,p.get())}function h(){d.removeEventListener(U,h,!1),m(d,e,t,0,e.size,u,a,c,s,l)}var d,p=new i;return r.zip.useWebWorkers?(d=new Worker(r.zip.workerScriptsPath+z),d.addEventListener(U,h,!1),d.postMessage({init:!0,level:n})):f(new r.zip.Deflater,e,t,0,e.size,u,a,c,s,l),d}function g(e,t,r,n,o,a,s,l,u){function c(){var i=h*B;n>i?e.readUint8Array(r+i,Math.min(B,n-i),function(e){o&&d.append(e),s&&s(i,n,e),t.writeUint8Array(e,function(){h++,c()},u)},l):a(n,d.get())}var h=0,d=new i;c()}function y(e){var t,r,i="",n=["Ç","ü","é","â","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å","É","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü","ø","£","Ø","×","ƒ","á","í","ó","ú","ñ","Ñ","ª","º","¿","®","¬","½","¼","¡","«","»","_","_","_","¦","¦","Á","Â","À","©","¦","¦","+","+","¢","¥","+","+","-","-","+","-","+","ã","Ã","+","+","-","-","¦","-","+","¤","ð","Ð","Ê","Ë","È","i","Í","Î","Ï","+","+","_","_","¦","Ì","_","Ó","ß","Ô","Ò","õ","Õ","µ","þ","Þ","Ú","Û","Ù","ý","Ý","¯","´","­","±","_","¾","¶","§","÷","¸","°","¨","·","¹","³","²","_"," "];for(t=0;t127?n[r-128]:String.fromCharCode(r);return i}function C(e){return decodeURIComponent(escape(e))}function E(e){var t,r="";for(t=0;t>16,r=65535&e;try{return new Date(1980+((65024&t)>>9),((480&t)>>5)-1,31&t,(63488&r)>>11,(2016&r)>>5,2*(31&r),0)}catch(i){}}function w(e,t,r,i,n){return e.version=t.view.getUint16(r,!0),e.bitFlag=t.view.getUint16(r+2,!0),e.compressionMethod=t.view.getUint16(r+4,!0),e.lastModDateRaw=t.view.getUint32(r+6,!0),e.lastModDate=S(e.lastModDateRaw),1===(1&e.bitFlag)?void n(M):((i||8!=(8&e.bitFlag))&&(e.crc32=t.view.getUint32(r+10,!0),e.compressedSize=t.view.getUint32(r+14,!0),e.uncompressedSize=t.view.getUint32(r+18,!0)),4294967295===e.compressedSize||4294967295===e.uncompressedSize?void n(D):(e.filenameLength=t.view.getUint16(r+22,!0),void(e.extraFieldLength=t.view.getUint16(r+24,!0))))}function T(e,t){function r(){}function i(r,n){e.readUint8Array(e.size-r,r,function(e){var t=o(e.length,e).view;1347093766!=t.getUint32(0)?i(r+1,n):n(t)},function(){t(R)})}return r.prototype.getData=function(r,i,n,a){function s(e,t){d&&d.terminate(),d=null,e&&e(t)}function l(e){var t=o(4);return t.view.setUint32(0,e),p.crc32==t.view.getUint32(0)}function u(e,t){a&&!l(t)?c():r.getData(function(e){s(i,e)})}function c(){s(t,L)}function h(){s(t,N)}var d,p=this;e.readUint8Array(p.offset,30,function(i){var s,l=o(i.length,i);return 1347093252!=l.view.getUint32(0)?void t(I):(w(p,l,4,!1,t),s=p.offset+30+p.filenameLength+p.extraFieldLength,void r.init(function(){0===p.compressionMethod?g(e,r,s,p.compressedSize,a,u,n,c,h):d=v(e,r,s,p.compressedSize,a,u,n,c,h)},h))},c)},{getEntries:function(n){return e.size<22?void t(I):void i(22,function(i){var a,s;a=i.getUint32(16,!0),s=i.getUint16(8,!0),e.readUint8Array(a,e.size-a,function(e){var i,a,l,u,c=0,h=[],d=o(e.length,e);for(i=0;s>i;i++){if(a=new r,1347092738!=d.view.getUint32(c))return void t(I);w(a,d,c+6,!0,t),a.commentLength=d.view.getUint16(c+32,!0),a.directory=16==(16&d.view.getUint8(c+38)),a.offset=d.view.getUint32(c+42,!0),l=E(d.array.subarray(c+46,c+46+a.filenameLength)),a.filename=2048===(2048&a.bitFlag)?C(l):y(l),a.directory||"/"!=a.filename.charAt(a.filename.length-1)||(a.directory=!0),u=E(d.array.subarray(c+46+a.filenameLength+a.extraFieldLength,c+46+a.filenameLength+a.extraFieldLength+a.commentLength)),a.comment=2048===(2048&a.bitFlag)?C(u):y(u),h.push(a),c+=46+a.filenameLength+a.extraFieldLength+a.commentLength}n(h)},function(){t(R)})})},close:function(e){e&&e()}}}function b(e){return unescape(encodeURIComponent(e))}function x(e){var t,r=[];for(t=0;te;e++){for(r=e,t=0;8>t;t++)1&r?r=r>>>1^3988292384:r>>>=1;i[e]=r}return i}(),s.prototype=new a,s.prototype.constructor=s,l.prototype=new a,l.prototype.constructor=l,u.prototype=new a,u.prototype.constructor=u,c.prototype.getData=function(e){e(this.data)},h.prototype=new c,h.prototype.constructor=h,d.prototype=new c,d.prototype.constructor=d,p.prototype=new c,p.prototype.constructor=p,r.zip={Reader:a,Writer:c,BlobReader:u,Data64URIReader:l,TextReader:s,BlobWriter:p,Data64URIWriter:d,TextWriter:h,createReader:function(e,t,r){e.init(function(){t(T(e,r))},r)},createWriter:function(e,t,r,i){e.init(function(){t(P(e,r,i))},r)},useWebWorkers:!0};var W;t(r.zip,{workerScriptsPath:{get:function(){return"undefined"==typeof W&&(W=e("ThirdParty/Workers/")),W}}})}(r),r.zip}),r("DataSources/KmlDataSource",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/ClockRange","../Core/ClockStep","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/getFilenameFromUri","../Core/Iso8601","../Core/JulianDate","../Core/loadBlob","../Core/loadXML","../Core/Math","../Core/NearFarScalar","../Core/PinBuilder","../Core/PolygonHierarchy","../Core/Rectangle","../Core/RuntimeError","../Core/TimeInterval","../Core/TimeIntervalCollection","../Scene/HorizontalOrigin","../Scene/LabelStyle","../ThirdParty/Autolinker","../ThirdParty/Uri","../ThirdParty/when","../ThirdParty/zip","./BillboardGraphics","./CompositePositionProperty","./ConstantPositionProperty","./DataSource","./DataSourceClock","./Entity","./EntityCollection","./LabelGraphics","./PathGraphics","./PolygonGraphics","./PolylineGraphics","./PositionPropertyArray","./RectangleGraphics","./ReferenceProperty","./SampledPositionProperty","./ScaledPositionProperty","./TimeIntervalCollectionProperty","./WallGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K){"use strict";function J(e){var t=e.slice(0,Math.min(4,e.size)),r=D.defer(),i=new FileReader;return i.addEventListener("load",function(){r.resolve(1347093252===new DataView(i.result).getUint32(0,!1))}),i.addEventListener("error",function(){r.reject(i.error)}),i.readAsArrayBuffer(t),r.promise}function Q(e){var t=D.defer(),r=new FileReader;return r.addEventListener("load",function(){t.resolve(r.result)}),r.addEventListener("error",function(){t.reject(r.error)}),r.readAsText(e),t.promise}function $(e,t,r,i){t.getData(new R.TextWriter,function(e){r.kml=$e.parseFromString(e,"application/xml"),i.resolve()})}function ee(e,t,r,i){var n=s(Qe.detectFromFilename(t.filename),"application/octet-stream");t.getData(new R.Data64URIWriter(n),function(e){r[t.filename]=e,i.resolve()})}function te(e,t,r,i){for(var n=i.keys,o=new M("."),a=e.querySelectorAll(t),s=0;so;o++)i[n++]=oe(t[o]);return i}function se(e,t){if(!l(e))return void 0;var r=e.getAttribute(t);if(null!==r){var i=parseFloat(r);return isNaN(i)?void 0:i}return void 0}function le(e,t){if(!l(e))return void 0;var r=e.getAttribute(t);return null!==r?r:void 0}function ue(e,t,r){if(!l(e))return void 0;for(var i=e.childNodes,n=i.length,o=0;n>o;o++){var a=i[o];if(a.localName===t&&-1!==r.indexOf(a.namespaceURI))return a}return void 0}function ce(e,t,r){if(!l(e))return void 0;for(var i=[],n=e.getElementsByTagName(t),o=n.length,a=0;o>a;a++){var s=n[a];s.localName===t&&-1!==r.indexOf(s.namespaceURI)&&i.push(s)}return i}function he(e,t,r){if(!l(e))return[];for(var i=[],n=e.childNodes,o=n.length,a=0;o>a;a++){var s=n[a];s.localName===t&&-1!==r.indexOf(s.namespaceURI)&&i.push(s)}return i}function de(e,t,r){var i=ue(e,t,r);if(l(i)){var n=parseFloat(i.textContent);return isNaN(n)?void 0:n}return void 0}function pe(e,t,r){var i=ue(e,t,r);return l(i)?i.textContent.trim():void 0}function me(e,t,r){var i=ue(e,t,r);if(l(i)){var n=i.textContent.trim();return"1"===n||/^true$/i.test(n)}return void 0}function fe(e,t,r,i){if(!l(e))return void 0;var n=!1;if(l(i)){var o=i[e];l(o)&&(n=!0,e=o)}if(!n&&l(r)){var a=new M(document.location.href);r=new M(r),e=new M(e).resolve(r.resolve(a)).toString(),e=re(e,t)}return e}function ve(e,t){if(!l(e))return void 0;"#"===e[0]&&(e=e.substring(1));var r=parseInt(e.substring(0,2),16)/255,i=parseInt(e.substring(2,4),16)/255,n=parseInt(e.substring(4,6),16)/255,a=parseInt(e.substring(6,8),16)/255;return t?(a>0?at.maximumRed=a:at.red=0,n>0?at.maximumGreen=n:at.green=0,i>0?at.maximumBlue=i:at.blue=0,at.alpha=r,o.fromRandom(at)):new o(a,n,i,r)}function _e(e,t,r){var i=pe(e,t,r);return l(i)?ve(i,"random"===pe(e,"colorMode",r)):void 0}function ge(e){var t=ue(e,"TimeStamp",ot.kmlgx),r=pe(t,"when",ot.kmlgx);if(!l(t)||!l(r)||0===r.length)return void 0;var i=v.fromIso8601(r),n=new x;return n.addInterval(new b({start:i,stop:f.MAXIMUM_VALUE})),n}function ye(e){var t=ue(e,"TimeSpan",ot.kmlgx);if(!l(t))return void 0;var r,i=ue(t,"begin",ot.kmlgx),n=l(i)?v.fromIso8601(i.textContent):void 0,o=ue(t,"end",ot.kmlgx),a=l(o)?v.fromIso8601(o.textContent):void 0;if(l(n)&&l(a)){if(v.lessThan(a,n)){var s=n;n=a,a=s}r=new x,r.addInterval(new b({start:n,stop:a}))}else l(n)?(r=new x,r.addInterval(new b({start:n,stop:f.MAXIMUM_VALUE}))):l(a)&&(r=new x,r.addInterval(new b({start:f.MINIMUM_VALUE,stop:a})));return r}function Ce(){var e=new O;return e.width=tt,e.height=tt,e.scaleByDistance=new C(2414016,1,16093e3,.1),e}function Ee(){var e=new G;return e.outline=!0,e.outlineColor=o.WHITE,e}function Se(){var e=new k;return e.translucencyByDistance=new C(3e6,1,5e6,0),e.pixelOffset=new t(17,0),e.horizontalOrigin=P.LEFT,e.font="16px sans-serif",e.style=A.FILL_AND_OUTLINE,e}function we(i,n,o,a,u){var c=de(n,"scale",ot.kml),h=de(n,"heading",ot.kml),d=_e(n,"color",ot.kml),p=ue(n,"Icon",ot.kml),m=pe(p,"href",ot.kml),f=fe(m,i._proxy,a,u),v=de(p,"x",ot.gx),_=de(p,"y",ot.gx),g=de(p,"w",ot.gx),C=de(p,"h",ot.gx),E=ue(n,"hotSpot",ot.kml),S=se(E,"x"),w=se(E,"y"),T=le(E,"xunits"),b=le(E,"yunits"),x=o.billboard;l(x)||(x=Ce(i),o.billboard=x),x.image=f,x.scale=c,x.color=d,(l(v)||l(_)||l(g)||l(C))&&(x.imageSubRegion=new e(v,_,g,C)),l(h)&&0!==h&&(x.rotation=y.toRadians(-h),x.alignedAxis=r.UNIT_Z),c=s(c,1);var P,A;l(S)&&("pixels"===T?P=-S*c:"insetPixels"===T?P=(S-tt)*c:"fraction"===T&&(P=-tt*c*S),P+=.5*tt*c),l(w)&&("pixels"===b?A=w:"insetPixels"===b?A=-w:"fraction"===b&&(A=w*tt),A-=.5*tt*c),(l(P)||l(A))&&(x.pixelOffset=new t(P,A))}function Te(e,t,r,i,n){for(var a=0,u=t.childNodes.length;u>a;a++){var c=t.childNodes.item(a);if("IconStyle"===c.localName)we(e,c,r,i,n);else if("LabelStyle"===c.localName){var h=r.label;l(h)||(h=Se(),r.label=h),h.scale=s(de(c,"scale",ot.kml),h.scale),h.fillColor=s(_e(c,"color",ot.kml),h.fillColor),h.text=r.name}else if("LineStyle"===c.localName){var d=r.polyline;l(d)||(d=new W,r.polyline=d),d.width=de(c,"width",ot.kml),d.material=_e(c,"color",ot.kml)}else if("PolyStyle"===c.localName){var p=r.polygon;l(p)||(p=Ee(),r.polygon=p),p.material=s(_e(c,"color",ot.kml),p.material),p.fill=s(me(c,"fill",ot.kml),p.fill),p.outline=s(me(c,"outline",ot.kml),p.outline)}else if("BalloonStyle"===c.localName){var m=s(ve(pe(c,"bgColor",ot.kml)),o.WHITE),f=s(ve(pe(c,"textColor",ot.kml)),o.BLACK),v=pe(c,"text",ot.kml);r.addProperty("balloonStyle"),r.balloonStyle={bgColor:m,textColor:f,text:v}}}}function be(e,t,r,i,n,o){var a=new V,s=he(r,"Style",ot.kml),u=s.length;u>0&&Te(t,s[u-1],a,n,o);var c=pe(r,"styleUrl",ot.kml);if(l(c)){var h=c,d=i.getById(h);l(d)||(d=i.getById("#"+h)),l(d)&&a.merge(d)}return a}function xe(e,t,r){return D(g(re(t,e._proxy)),function(i){return Pe(e,i,r,t,!0)})}function Pe(e,t,r,i,n,o){var a,s,u,c,h=ce(t,"Style",ot.kml);if(l(h)){var d=h.length;for(a=0;d>a;a++)c=h[a],s=le(c,"id"),l(s)&&(s="#"+s,n&&l(i)&&(s=i+s),l(r.getById(s))||(u=new V({id:s}),r.add(u),Te(e,c,u,i,o)))}var p=ce(t,"StyleMap",ot.kml);if(l(p)){var m=p.length;for(a=0;m>a;a++){var f=p[a];if(s=le(f,"id"),l(s))for(var v=he(f,"Pair",ot.kml),_=0;_a;a++){var b=w[a].textContent;if("#"!==b[0]){var x=b.split("#");if(2===x.length){var P=x[0];if(!l(E[P])){if(l(i)){var A=new M(document.location.href);i=new M(i),P=new M(P).resolve(i.resolve(A)).toString()}S.push(xe(e,P,r,i))}}}}return S}function Ae(e,t,r){var i=new j(e._entityCollection,t.id,["position"]),n=new X(t.position);t.polyline=l(r.polyline)?r.polyline.clone():new W,t.polyline.positions=new H([i,n])}function Ie(e,t,r){return"relativeToSeaFloor"===r||"absolute"===t||"relativeToGround"===t?e:((l(t)&&"clampToGround"!==t||l(r)&&"clampToSeaFloor"!==r)&&window.console.log("KML - Unknown altitudeMode: "+s(t,r)),new X(e))}function Me(e,t,r){if(!l(e))return void 0;if("relativeToSeaFloor"===r||"absolute"===t||"relativeToGround"===t)return e;(l(t)&&"clampToGround"!==t||l(r)&&"clampToSeaFloor"!==r)&&window.console.log("KML - Unknown altitudeMode: "+s(t,r));for(var i=e.length,n=0;i>n;n++){var o=e[n];d.WGS84.scaleToGeodeticSurface(o,o)}return e}function De(e,r,i){var n=r.label;l(n)||(n=l(i.label)?i.label.clone():Se(),r.label=n),n.text=r.name;var a=r.billboard;if(l(a)||(a=l(i.billboard)?i.billboard.clone():Ce(),r.billboard=a),l(a.image)||(a.image=e._pinBuilder.fromColor(o.YELLOW,64)),l(a.scale)){var s=a.scale.getValue();0!==s?n.pixelOffset=new t(16*s+1,0):(n.pixelOffset=void 0,n.horizontalOrigin=void 0)}}function Re(e,t,r){var i=t.path;l(i)||(i=new U,i.leadTime=0,t.path=i);var n=r.polyline;l(n)&&(i.material=n.material,i.width=n.width)}function Oe(e,t,r,i){var n=pe(t,"coordinates",ot.kml),o=pe(t,"altitudeMode",ot.kml),a=pe(t,"altitudeMode",ot.gx),s=me(t,"extrude",ot.kml),l=oe(n);r.position=Ie(new L(l),o,a),De(e,r,i),s&&ne(o,a)&&Ae(e,r,i)}function Ne(e,t,r,i){var n=ue(t,"coordinates",ot.kml),a=pe(t,"altitudeMode",ot.kml),s=pe(t,"altitudeMode",ot.gx),u=me(t,"extrude",ot.kml),c=me(t,"tessellate",ot.kml),h=ne(a,s),d=ae(n),p=i.polyline;if(h&&u){var m=new K;r.wall=m,m.positions=d;var f=i.polygon;l(f)&&(m.fill=f.fill,m.outline=f.outline,m.material=f.material),l(p)&&(m.outlineColor=l(p.material)?p.material.color:o.WHITE,m.outlineWidth=p.width)}else p=l(p)?p.clone():new W,r.polyline=p,p.positions=Me(d,a,s),(!c||h)&&(p.followSurface=!1)}function Le(e,t,r,i){var n=ue(t,"outerBoundaryIs",ot.kml),a=ue(n,"LinearRing",ot.kml),s=ue(a,"coordinates",ot.kml),u=ae(s),c=me(t,"extrude",ot.kml),h=pe(t,"altitudeMode",ot.kml),d=pe(t,"altitudeMode",ot.gx),p=ne(h,d),m=l(i.polygon)?i.polygon.clone():Ee(),f=i.polyline;if(l(f)&&(m.outlineColor=l(f.material)?f.material.color:o.WHITE,m.outlineWidth=f.width),r.polygon=m,p&&(m.perPositionHeight=!0,m.extrudedHeight=c?0:void 0),l(u)){for(var v=new S(u),_=he(t,"innerBoundaryIs",ot.kml),g=0;g<_.length;g++){a=he(_[g],"LinearRing",ot.kml);for(var y=0;yp;p++){var m=oe(a[p].textContent);h.push(m),d.push(v.fromIso8601(s[p].textContent))}var f=new Y;f.addSamples(d,h),r.position=Ie(f,n,o),De(e,r,i),Re(e,r,i),r.availability=new x,s.length>0&&r.availability.addInterval(new b({start:d[0],stop:d[d.length-1]})),u&&l&&Ae(e,r,i)}function Be(e,t,r,i,n,o,a,s,l){var u=e[0],c=e[e.length-1],h=new Y;h.addSamples(e,t),r.intervals.addInterval(new b({start:u,stop:c,isStartIncluded:l,isStopIncluded:l,data:Ie(h,a,s)})),i.addInterval(new b({start:u,stop:c,isStartIncluded:l,isStopIncluded:l})),n.intervals.addInterval(new b({start:u,stop:c,isStartIncluded:l,isStopIncluded:l,data:o}))}function Ve(e,t,r,i){for(var n,o,a,s=me(t,"interpolate",ot.gx),u=he(t,"Track",ot.gx),c=!1,h=new Z,d=new x,p=new N,m=0,f=u.length;f>m;m++){var _=u[m],g=he(_,"when",ot.kml),y=he(_,"coord",ot.gx),C=pe(_,"altitudeMode",ot.kml),E=pe(_,"altitudeMode",ot.gx),S=ne(C,E),w=me(_,"extrude",ot.kml),T=Math.min(y.length,g.length),b=[];n=[];for(var P=0;T>P;P++){var A=oe(y[P].textContent);b.push(A),n.push(v.fromIso8601(g[P].textContent))}s&&(l(o)&&Be([o,n[0]],[a,b[0]],p,d,h,!1,"absolute",void 0,!1),o=n[T-1],a=b[b.length-1]),Be(n,b,p,d,h,S&&w,C,E,!0),c=c||S&&w}r.availability=d,r.position=p,De(e,r,i),Re(e,r,i),c&&(Ae(e,r,i),r.polyline.show=h)}function ze(e,t,r,i){for(var n=t.childNodes,o=0,a=n.length;a>o;o++){var s=n.item(o),u=lt[s.localName];if(l(u)){var c=ie(s,e._entityCollection);c.parent=r,c.name=r.name,c.availability=r.availability,c.description=r.description,c.kml=r.kml,u(e,s,c,i)}}}function ke(e,t){var r=ue(e,"ExtendedData",ot.kml);if(!l(r))return void 0;var i={},n=he(r,"Data",ot.kml);if(l(n))for(var o=n.length,a=0;o>a;a++){var s=n[a],u=le(s,"name");l(u)&&(i[u]={displayName:pe(s,"displayName",ot.kml),value:pe(s,"value",ot.kml)})}t.kml.extendedData=i}function Ue(e,t,r,i){var n,a,u,c=t.kml,h=c.extendedData,d=pe(e,"description",ot.kml),p=s(t.balloonStyle,r.balloonStyle),m=o.WHITE,f=o.BLACK,v=d;l(p)&&(m=s(p.bgColor,o.WHITE),f=s(p.textColor,o.BLACK),v=s(p.text,d));var _;if(l(v)){if(v=v.replace("$[name]",s(t.name,"")),v=v.replace("$[description]",s(d,"")),v=v.replace("$[address]",s(c.address,"")),v=v.replace("$[Snippet]",s(c.snippet,"")),v=v.replace("$[id]",t.id),v=v.replace("$[geDirections]",""),l(h)){var g=v.match(/\$\[.+?\]/g);if(null!==g)for(n=0;n0)){for(v='',n=0;n";v+="
"+s(_.displayName,a)+""+s(_.value,"")+"
"}if(l(v)){v=et.link(v),st.innerHTML=v;var S=st.querySelectorAll("a");for(n=0;n1&&(te(st,"a","href",i),te(st,"img","src",i));var w='
",st.innerHTML="",t.description=w}}function Ge(e,t,r,i,n,o,a){var u=ie(r,i),c=u.kml,h=be(u,e,r,n,o,a),d=pe(r,"name",ot.kml);u.name=d,u.parent=t;var p=ye(r);l(p)||(p=ge(r)),u.availability=p;var m=me(r,"visibility",ot.kml);u.show=s(m,!0);var f=ue(r,"author",ot.atom),v=c.author;v.name=pe(f,"name",ot.atom),v.uri=pe(f,"uri",ot.atom),v.email=pe(f,"email",ot.atom);var _=ue(r,"link",ot.atom),g=c.link;return g.href=le(_,"href"),g.hreflang=le(_,"hreflang"),g.rel=le(_,"rel"),g.type=le(_,"type"),g.title=le(_,"title"),g.length=le(_,"length"),c.address=pe(r,"address",ot.kml),c.phoneNumber=pe(r,"phoneNumber",ot.kml),c.snippet=pe(r,"Snippet",ot.kml),ke(r,u),Ue(r,u,h,a),{entity:u,styleEntity:h}}function We(e,t,r,i,n,o,a){for(var s=Object.keys(ut),l=s.length,u=0;l>u;u++)for(var c=s[u],h=ut[c],d=r.childNodes,p=d.length,m=0;p>m;m++){var f=d[m];f.localName===c&&-1!==ot.kml.indexOf(f.namespaceURI)&&h(e,t,f,i,n,o,a)}}function He(e,t,r,i,n,o,a){var s=Ge(e,t,r,i,n,o,a);We(e,s.entity,r,i,n,o,a)}function qe(e,t,r,i,n,o,a){for(var s=Ge(e,t,r,i,n,o,a),u=s.entity,c=s.styleEntity,h=!1,d=r.childNodes,p=0,m=d.length;m>p&&!h;p++){var f=d.item(p),v=lt[f.localName];l(v)&&(v(e,f,u,c),h=!0)}h||(u.merge(c),De(e,u,c))}function je(e,t,r,i,n,o,a){var s,u=Ge(e,t,r,i,n,o,a),c=u.entity,h=(u.stylEntity,!1),d=ae(ue(r,"LatLonQuad",ot.gx));if(l(d))s=Ee(),s.hierarchy=new S(d),c.polygon=s,h=!0;else{s=new q,c.rectangle=s;var p=ue(r,"LatLonBox",ot.kml);if(l(p)){var m=de(p,"west",ot.kml),f=de(p,"south",ot.kml),v=de(p,"east",ot.kml),_=de(p,"north",ot.kml);l(m)&&(m=y.negativePiToPi(y.toRadians(m))),l(f)&&(f=y.negativePiToPi(y.toRadians(f))),l(v)&&(v=y.negativePiToPi(y.toRadians(v))),l(_)&&(_=y.negativePiToPi(y.toRadians(_))),s.coordinates=new w(m,f,v,_);var g=de(p,"rotation",ot.kml);l(g)&&(s.rotation=y.toRadians(g))}}var C=ue(r,"Icon",ot.kml),E=pe(C,"href",ot.kml);l(E)?(h&&window.console.log("KML - gx:LatLonQuad Icon does not support texture projection."),s.material=fe(E,e._proxy,o,a)):s.material=_e(r,"color",ot.kml);var T=pe(r,"altitudeMode",ot.kml);l(T)?"absolute"===T?s.height=de(r,"altitude",ot.kml):"clampToGround"===T||window.console.log("KML - Unknown altitudeMode: "+T):(T=pe(r,"altitudeMode",ot.gx), +"relativeToSeaFloor"===T?(window.console.log("KML - altitudeMode relativeToSeaFloor is currently not supported, treating as absolute."),s.height=de(r,"altitude",ot.kml)):"clampToSeaFloor"===T?window.console.log("KML - altitudeMode clampToSeaFloor is currently not supported, treating as clampToGround."):l(T)&&window.console.log("KML - Unknown altitudeMode: "+T))}function Ye(e,t,r,i,n,o,a){window.console.log("KML - Unsupported feature: "+r.localName)}function Xe(e,t,r,i,n,o,a){var s=Ge(e,t,r,i,n,o,a),u=s.entity,c=ue(r,"Link",ot.kml);if(l(c)){var h=pe(c,"href",ot.kml);if(l(h)){h=fe(h,void 0,o,a);var d=new ct(e._proxy),p=D(d.load(h),function(){for(var t=d.entities.values,r=0;ri;i++)if(!o.isConstant(t[i]))return!1;return!0}},definitionChanged:{get:function(){return this._definitionChanged}}}),a.prototype.getValue=function(t,r){var i=this._value;if(!e(i))return void 0;var n=i.length;e(r)||(r=new Array(n));for(var o=0,a=0;n>o;){var s=this._value[o],l=s.getValue(t,r[o]);e(l)&&(r[a]=l,a++),o++}return r.length=a,r},a.prototype.setValue=function(t){var r=this._eventHelper;if(r.removeAll(),e(t)){this._value=t.slice();for(var i=t.length,n=0;i>n;n++){var o=t[n];e(o)&&r.add(o.definitionChanged,a.prototype._raiseDefinitionChanged,this)}}else this._value=void 0;this._definitionChanged.raiseEvent(this)},a.prototype.equals=function(e){return this===e||e instanceof a&&o.arrayEquals(this._value,e._value)},a.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},a}),r("DataSources/VelocityOrientationProperty",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/JulianDate","../Core/Matrix3","../Core/Quaternion","../Core/Transforms","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";var d=function(e,r){this._position=void 0,this._subscription=void 0,this._ellipsoid=void 0,this._definitionChanged=new a,this.position=e,this.ellipsoid=t(r,o.WGS84)};i(d.prototype,{isConstant:{get:function(){return h.isConstant(this._position)}},definitionChanged:{get:function(){return this._definitionChanged}},position:{get:function(){return this._position},set:function(e){var t=this._position;t!==e&&(r(t)&&this._subscription(),this._position=e,r(e)&&(this._subscription=e._definitionChanged.addEventListener(function(){this._definitionChanged.raiseEvent(this)},this)),this._definitionChanged.raiseEvent(this))}},ellipsoid:{get:function(){return this._ellipsoid},set:function(e){var t=this._ellipsoid;t!==e&&(this._ellipsoid=e,this._definitionChanged.raiseEvent(this))}}});var p=new e,m=new e,f=new e,v=new s,_=new l,g=1/60;return d.prototype.getValue=function(t,i){var n=this._position;if(h.isConstant(n))return void 0;var o=n.getValue(t,p),a=n.getValue(s.addSeconds(t,g,v),m);if(!r(o))return void 0;if(!r(a)&&(a=o,o=n.getValue(s.addSeconds(t,-g,v),m),!r(o)))return void 0;if(e.equals(o,a))return void 0;var l=e.subtract(a,o,f);e.normalize(l,l);c.rotationMatrixFromPositionVelocity(o,l,this._ellipsoid,_);return u.fromRotationMatrix(_,i)},d.prototype.equals=function(e){return this===e||e instanceof d&&h.equals(this._position,e._position)&&(this._ellipsoid===e._ellipsoid||this._ellipsoid.equals(e._ellipsoid))},d}),r("DataSources/Visualizer",["../Core/DeveloperError"],function(e){"use strict";var t=function(){e.throwInstantiationError()};return t.prototype.update=e.throwInstantiationError,t.prototype.getBoundingSphere=e.throwInstantiationError,t.prototype.isDestroyed=e.throwInstantiationError,t.prototype.destroy=e.throwInstantiationError,t}),r("Renderer/ClearCommand",["../Core/Color","../Core/defaultValue","../Core/freezeObject"],function(e,t,r){"use strict";var i=function(e){e=t(e,t.EMPTY_OBJECT),this.color=e.color,this.depth=e.depth,this.stencil=e.stencil,this.renderState=e.renderState,this.framebuffer=e.framebuffer,this.owner=e.owner};return i.ALL=r(new i({color:new e(0,0,0,0),depth:1,stencil:0})),i.prototype.execute=function(e,t){e.clear(this,t)},i}),r("Renderer/ComputeCommand",["../Core/defaultValue","../Core/PrimitiveType","../Scene/Pass"],function(e,t,r){"use strict";var i=function(t){t=e(t,e.EMPTY_OBJECT),this.vertexArray=t.vertexArray,this.fragmentShaderSource=t.fragmentShaderSource,this.shaderProgram=t.shaderProgram,this.uniformMap=t.uniformMap,this.outputTexture=t.outputTexture,this.preExecute=t.preExecute,this.postExecute=t.postExecute,this.persists=e(t.persists,!1),this.pass=r.COMPUTE,this.owner=t.owner};return i.prototype.execute=function(e){e.execute(this)},i}),r("Shaders/ViewportQuadVS",[],function(){"use strict";return"attribute vec4 position;\nattribute vec2 textureCoordinates;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_Position = position;\nv_textureCoordinates = textureCoordinates;\n}\n"}),r("Renderer/ComputeEngine",["../Core/BoundingRectangle","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Geometry","../Core/GeometryAttribute","../Core/PrimitiveType","../Shaders/ViewportQuadVS","./BufferUsage","./ClearCommand","./DrawCommand","./Framebuffer","./RenderState","./ShaderProgram"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,t){return new f({context:e,colorTextures:[t],destroyAttachments:!1})}function y(e,t){return _.fromCache({context:e,vertexShaderSource:h,fragmentShaderSource:t,attributeLocations:{position:0,textureCoordinates:1}})}function C(t,r){return n(E)&&E.viewport.width===t&&E.viewport.height===r||(E=v.fromCache({viewport:new e(0,0,t,r)})),E}var E,S=function(e){this._context=e},w=new m({primitiveType:c.TRIANGLES}),T=new p({color:new t(0,0,0,0)});return S.prototype.execute=function(e){n(e.preExecute)&&e.preExecute(e);var t=e.outputTexture,r=t.width,i=t.height,o=this._context,a=n(e.vertexArray)?e.vertexArray:o.getViewportQuadVertexArray(),s=n(e.shaderProgram)?e.shaderProgram:y(o,e.fragmentShaderSource),l=g(o,t),u=C(r,i),c=e.uniformMap,h=T;h.framebuffer=l,h.renderState=u,h.execute(o);var d=w;d.vertexArray=a,d.renderState=u,d.shaderProgram=s,d.uniformMap=c,d.framebuffer=l,d.execute(o),l.destroy(),e.persists||(s.destroy(),n(e.vertexArray)&&a.destroy()),n(e.postExecute)&&e.postExecute(t)},S.prototype.isDestroyed=function(){return!1},S.prototype.destroy=function(){return a(this)},S}),r("Renderer/PassState",[],function(){"use strict";var e=function(e){this.context=e,this.framebuffer=void 0,this.blendingEnabled=void 0,this.scissorTest=void 0};return e}),r("Renderer/RenderbufferFormat",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={RGBA4:t.RGBA4,RGB5_A1:t.RGB5_A1,RGB565:t.RGB565,DEPTH_COMPONENT16:t.DEPTH_COMPONENT16,STENCIL_INDEX8:t.STENCIL_INDEX8,DEPTH_STENCIL:t.DEPTH_STENCIL,validate:function(e){return e===r.RGBA4||e===r.RGB5_A1||e===r.RGB565||e===r.DEPTH_COMPONENT16||e===r.STENCIL_INDEX8||e===r.DEPTH_STENCIL}};return e(r)}),r("Renderer/Renderbuffer",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","./ContextLimits","./RenderbufferFormat"],function(e,t,r,i,n,o,a){"use strict";function s(r){r=e(r,e.EMPTY_OBJECT);var i=r.context,n=i._gl,s=(o.maximumRenderbufferSize,e(r.format,a.RGBA4)),l=t(r.width)?r.width:n.drawingBufferWidth,u=t(r.height)?r.height:n.drawingBufferHeight;this._gl=n,this._format=s,this._width=l,this._height=u,this._renderbuffer=this._gl.createRenderbuffer(),n.bindRenderbuffer(n.RENDERBUFFER,this._renderbuffer),n.renderbufferStorage(n.RENDERBUFFER,s,l,u),n.bindRenderbuffer(n.RENDERBUFFER,null)}return r(s.prototype,{format:{get:function(){return this._format}},width:{get:function(){return this._width}},height:{get:function(){return this._height}}}),s.prototype._getRenderbuffer=function(){return this._renderbuffer},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this._gl.deleteRenderbuffer(this._renderbuffer),i(this)},s}),r("Renderer/PickFramebuffer",["../Core/BoundingRectangle","../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","./Framebuffer","./PassState","./Renderbuffer","./RenderbufferFormat","./Texture"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(t){var r=new a(t);r.blendingEnabled=!1,r.scissorTest={enabled:!0,rectangle:new e},this._context=t,this._fb=void 0,this._passState=r,this._width=0,this._height=0};c.prototype.begin=function(t){var r=this._context,n=r.drawingBufferWidth,a=r.drawingBufferHeight;return e.clone(t,this._passState.scissorTest.rectangle),i(this._fb)&&this._width===n&&this._height===a||(this._width=n,this._height=a,this._fb=this._fb&&this._fb.destroy(),this._fb=new o({context:r,colorTextures:[new u({context:r,width:n,height:a})],depthStencilRenderbuffer:new s({context:r,format:l.DEPTH_STENCIL})}),this._passState.framebuffer=this._fb),this._passState};var h=new t;return c.prototype.end=function(e){for(var n=r(e.width,1),o=r(e.height,1),a=this._context,s=a.readPixels({x:e.x,y:e.y,width:n,height:o,framebuffer:this._fb}),l=Math.max(n,o),u=l*l,c=Math.floor(.5*n),d=Math.floor(.5*o),p=0,m=0,f=0,v=-1,_=0;u>_;++_){if(p>=-c&&c>=p&&m>=-d&&d>=m){var g=4*((d-m)*n+p+c);h.red=t.byteToFloat(s[g]),h.green=t.byteToFloat(s[g+1]),h.blue=t.byteToFloat(s[g+2]),h.alpha=t.byteToFloat(s[g+3]);var y=a.getObjectByPickColor(h);if(i(y))return y}if(p===m||0>p&&-p===m||p>0&&p===1-m){var C=f;f=-v,v=C}p+=f,m+=v}return void 0},c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return this._fb=this._fb&&this._fb.destroy(),n(this)},c}),r("Renderer/ShaderCache",["../Core/defined","../Core/defineProperties","../Core/destroyObject","./ShaderProgram","./ShaderSource"],function(e,t,r,i,n){"use strict";var o=function(e){this._context=e,this._shaders={},this._numberOfShaders=0,this._shadersToRelease={}};return t(o.prototype,{numberOfShaders:{get:function(){return this._numberOfShaders}}}),o.prototype.replaceShaderProgram=function(t){return e(t.shaderProgram)&&t.shaderProgram.destroy(),this.getShaderProgram(t)},o.prototype.getShaderProgram=function(e){var t=e.vertexShaderSource,r=e.fragmentShaderSource,o=e.attributeLocations;"string"==typeof t&&(t=new n({sources:[t]})),"string"==typeof r&&(r=new n({sources:[r]}));var a,s=t.createCombinedVertexShader(),l=r.createCombinedFragmentShader(),u=s+l+JSON.stringify(o);if(this._shaders[u])a=this._shaders[u],delete this._shadersToRelease[u];else{var c=this._context,h=new i({gl:c._gl,logShaderCompilation:c.logShaderCompilation,debugShaders:c.debugShaders,vertexShaderSource:t,vertexShaderText:s,fragmentShaderSource:r,fragmentShaderText:l,attributeLocations:o});a={cache:this,shaderProgram:h,keyword:u,count:0},h._cachedShader=a,this._shaders[u]=a,++this._numberOfShaders}return++a.count,a.shaderProgram},o.prototype.destroyReleasedShaderPrograms=function(){var e=this._shadersToRelease;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];delete this._shaders[r.keyword],r.shaderProgram.finalDestroy(),--this._numberOfShaders}this._shadersToRelease={}},o.prototype.releaseShaderProgram=function(e){if(e){var t=e._cachedShader;t&&0===--t.count&&(this._shadersToRelease[t.keyword]=t)}},o.prototype.isDestroyed=function(){return!1},o.prototype.destroy=function(){var e=this._shaders;for(var t in e)e.hasOwnProperty(t)&&e[t].shaderProgram.finalDestroy();return r(this)},o}),r("Renderer/UniformState",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defined","../Core/defineProperties","../Core/EncodedCartesian3","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Simon1994PlanetaryPositions","../Core/Transforms","../Scene/SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){c.clone(t,e._view),c.getRotation(t,e._viewRotation),e._view3DDirty=!0,e._inverseView3DDirty=!0,e._modelViewDirty=!0,e._modelView3DDirty=!0,e._modelViewRelativeToEyeDirty=!0,e._inverseModelViewDirty=!0,e._inverseModelView3DDirty=!0,e._viewProjectionDirty=!0,e._modelViewProjectionDirty=!0,e._modelViewProjectionRelativeToEyeDirty=!0,e._modelViewInfiniteProjectionDirty=!0,e._normalDirty=!0,e._inverseNormalDirty=!0,e._normal3DDirty=!0,e._inverseNormal3DDirty=!0}function f(e,t){c.clone(t,e._inverseView),c.getRotation(t,e._inverseViewRotation)}function v(e,t){c.clone(t,e._projection),e._inverseProjectionDirty=!0,e._inverseProjectionOITDirty=!0,e._viewProjectionDirty=!0,e._modelViewProjectionDirty=!0,e._modelViewProjectionRelativeToEyeDirty=!0}function _(e,t){c.clone(t,e._infiniteProjection),e._modelViewInfiniteProjectionDirty=!0}function g(e,t){r.clone(t.positionWC,e._cameraPosition),r.clone(t.directionWC,e._cameraDirection),r.clone(t.rightWC,e._cameraRight),r.clone(t.upWC,e._cameraUp),e._encodedCameraPositionMCDirty=!0}function y(e,t){o(d.computeIcrfToFixedMatrix(t.time,U))||(U=d.computeTemeToPseudoFixedMatrix(t.time,U));var i=h.computeSunPositionInEarthInertialFrame(t.time,e._sunPositionWC);u.multiplyByVector(U,i,i),r.normalize(i,e._sunDirectionWC),i=u.multiplyByVector(e.viewRotation3D,i,e._sunDirectionEC),r.normalize(i,i),i=h.computeMoonPositionInEarthInertialFrame(t.time,e._moonDirectionEC),u.multiplyByVector(U,i,i),u.multiplyByVector(e.viewRotation3D,i,i),r.normalize(i,i);var n=t.mapProjection,a=n.ellipsoid,s=a.cartesianToCartographic(e._sunPositionWC,G);n.project(s,e._sunPositionColumbusView)}function C(e){if(e._viewportDirty){var t=e._viewport;c.computeOrthographicOffCenter(t.x,t.x+t.width,t.y,t.y+t.height,0,1,e._viewportOrthographicMatrix),c.computeViewportTransformation(t,0,1,e._viewportTransformation),e._viewportDirty=!1}}function E(e){e._inverseProjectionDirty&&(e._inverseProjectionDirty=!1,c.inverse(e._projection,e._inverseProjection))}function S(e){e._inverseProjectionOITDirty&&(e._inverseProjectionOITDirty=!1,e._mode!==p.SCENE2D&&e._mode!==p.MORPHING?c.inverse(e._projection,e._inverseProjectionOIT):c.clone(c.IDENTITY,e._inverseProjectionOIT))}function w(e){e._modelViewDirty&&(e._modelViewDirty=!1,c.multiplyTransformation(e._view,e._model,e._modelView))}function T(e){e._modelView3DDirty&&(e._modelView3DDirty=!1,c.multiplyTransformation(e.view3D,e._model,e._modelView3D))}function b(e){e._inverseModelViewDirty&&(e._inverseModelViewDirty=!1,c.inverse(e.modelView,e._inverseModelView))}function x(e){e._inverseModelView3DDirty&&(e._inverseModelView3DDirty=!1,c.inverse(e.modelView3D,e._inverseModelView3D))}function P(e){e._viewProjectionDirty&&(e._viewProjectionDirty=!1,c.multiply(e._projection,e._view,e._viewProjection))}function A(e){e._inverseViewProjectionDirty&&(e._inverseViewProjectionDirty=!1,c.inverse(e.viewProjection,e._inverseViewProjection))}function I(e){e._modelViewProjectionDirty&&(e._modelViewProjectionDirty=!1,c.multiply(e._projection,e.modelView,e._modelViewProjection))}function M(e){if(e._modelViewRelativeToEyeDirty){e._modelViewRelativeToEyeDirty=!1;var t=e.modelView,r=e._modelViewRelativeToEye;r[0]=t[0],r[1]=t[1],r[2]=t[2],r[3]=t[3],r[4]=t[4],r[5]=t[5],r[6]=t[6],r[7]=t[7],r[8]=t[8],r[9]=t[9],r[10]=t[10],r[11]=t[11],r[12]=0,r[13]=0,r[14]=0,r[15]=t[15]}}function D(e){e._inverseModelViewProjectionDirty&&(e._inverseModelViewProjectionDirty=!1,c.inverse(e.modelViewProjection,e._inverseModelViewProjection))}function R(e){e._modelViewProjectionRelativeToEyeDirty&&(e._modelViewProjectionRelativeToEyeDirty=!1,c.multiply(e._projection,e.modelViewRelativeToEye,e._modelViewProjectionRelativeToEye))}function O(e){e._modelViewInfiniteProjectionDirty&&(e._modelViewInfiniteProjectionDirty=!1,c.multiply(e._infiniteProjection,e.modelView,e._modelViewInfiniteProjection))}function N(e){if(e._normalDirty){e._normalDirty=!1;var t=e._normal;c.getRotation(e.inverseModelView,t),u.transpose(t,t)}}function L(e){if(e._normal3DDirty){e._normal3DDirty=!1;var t=e._normal3D;c.getRotation(e.inverseModelView3D,t),u.transpose(t,t)}}function F(e){e._inverseNormalDirty&&(e._inverseNormalDirty=!1,c.getRotation(e.inverseModelView,e._inverseNormal))}function B(e){e._inverseNormal3DDirty&&(e._inverseNormal3DDirty=!1,c.getRotation(e.inverseModelView3D,e._inverseNormal3D))}function V(e){e._encodedCameraPositionMCDirty&&(e._encodedCameraPositionMCDirty=!1,c.multiplyByPoint(e.inverseModel,e._cameraPosition,W),s.fromCartesian(W,e._encodedCameraPositionMC))}function z(e,t,i,n,a,s,u,h){var m=H;m.x=e.y,m.y=e.z,m.z=e.x;var f=q;f.x=i.y,f.y=i.z,f.z=i.x;var v=j;v.x=n.y,v.y=n.z,v.z=n.x;var _=Y;_.x=t.y,_.y=t.z,_.z=t.x,s===p.SCENE2D&&(m.z=.5*a);var g=u.unproject(m,X);g.longitude=l.clamp(g.longitude,-Math.PI,Math.PI),g.latitude=l.clamp(g.latitude,-l.PI_OVER_TWO,l.PI_OVER_TWO);var y=u.ellipsoid,C=y.cartographicToCartesian(g,Z),E=d.eastNorthUpToFixedFrame(C,y,K);return c.multiplyByPointAsVector(E,f,f),c.multiplyByPointAsVector(E,v,v),c.multiplyByPointAsVector(E,_,_),o(h)||(h=new c),h[0]=f.x,h[1]=v.x,h[2]=-_.x,h[3]=0,h[4]=f.y,h[5]=v.y,h[6]=-_.y,h[7]=0,h[8]=f.z,h[9]=v.z,h[10]=-_.z,h[11]=0,h[12]=-r.dot(f,C),h[13]=-r.dot(v,C),h[14]=r.dot(_,C),h[15]=1,h}var k=function(){this.globeDepthTexture=void 0,this._viewport=new e,this._viewportCartesian4=new i,this._viewportDirty=!1,this._viewportOrthographicMatrix=c.clone(c.IDENTITY),this._viewportTransformation=c.clone(c.IDENTITY),this._model=c.clone(c.IDENTITY),this._view=c.clone(c.IDENTITY),this._inverseView=c.clone(c.IDENTITY),this._projection=c.clone(c.IDENTITY),this._infiniteProjection=c.clone(c.IDENTITY),this._entireFrustum=new t,this._currentFrustum=new t,this._frustumPlanes=new i,this._frameState=void 0,this._temeToPseudoFixed=u.clone(c.IDENTITY),this._view3DDirty=!0,this._view3D=new c,this._inverseView3DDirty=!0,this._inverseView3D=new c,this._inverseModelDirty=!0,this._inverseModel=new c,this._inverseTransposeModelDirty=!0,this._inverseTransposeModel=new u,this._viewRotation=new u,this._inverseViewRotation=new u,this._viewRotation3D=new u,this._inverseViewRotation3D=new u,this._inverseProjectionDirty=!0,this._inverseProjection=new c,this._inverseProjectionOITDirty=!0,this._inverseProjectionOIT=new c,this._modelViewDirty=!0,this._modelView=new c,this._modelView3DDirty=!0,this._modelView3D=new c,this._modelViewRelativeToEyeDirty=!0,this._modelViewRelativeToEye=new c,this._inverseModelViewDirty=!0,this._inverseModelView=new c,this._inverseModelView3DDirty=!0,this._inverseModelView3D=new c,this._viewProjectionDirty=!0,this._viewProjection=new c,this._inverseViewProjectionDirty=!0,this._inverseViewProjection=new c,this._modelViewProjectionDirty=!0,this._modelViewProjection=new c,this._inverseModelViewProjectionDirty=!0,this._inverseModelViewProjection=new c,this._modelViewProjectionRelativeToEyeDirty=!0,this._modelViewProjectionRelativeToEye=new c,this._modelViewInfiniteProjectionDirty=!0,this._modelViewInfiniteProjection=new c,this._normalDirty=!0,this._normal=new u,this._normal3DDirty=!0,this._normal3D=new u,this._inverseNormalDirty=!0,this._inverseNormal=new u,this._inverseNormal3DDirty=!0,this._inverseNormal3D=new u,this._encodedCameraPositionMCDirty=!0,this._encodedCameraPositionMC=new s,this._cameraPosition=new r,this._sunPositionWC=new r,this._sunPositionColumbusView=new r,this._sunDirectionWC=new r,this._sunDirectionEC=new r,this._moonDirectionEC=new r,this._mode=void 0,this._mapProjection=void 0,this._cameraDirection=new r,this._cameraRight=new r,this._cameraUp=new r,this._frustum2DWidth=0,this._eyeHeight2D=new t,this._resolutionScale=1,this._fogDensity=void 0};a(k.prototype,{frameState:{get:function(){return this._frameState}},viewport:{get:function(){return this._viewport},set:function(t){if(!e.equals(t,this._viewport)){e.clone(t,this._viewport);var r=this._viewport,i=this._viewportCartesian4;i.x=r.x,i.y=r.y,i.z=r.width,i.w=r.height,this._viewportDirty=!0}}},viewportCartesian4:{get:function(){return this._viewportCartesian4}},viewportOrthographic:{get:function(){return C(this),this._viewportOrthographicMatrix}},viewportTransformation:{get:function(){return C(this),this._viewportTransformation}},model:{get:function(){return this._model},set:function(e){c.clone(e,this._model),this._modelView3DDirty=!0,this._inverseModelView3DDirty=!0,this._inverseModelDirty=!0,this._inverseTransposeModelDirty=!0,this._modelViewDirty=!0,this._inverseModelViewDirty=!0,this._viewProjectionDirty=!0,this._inverseViewProjectionDirty=!0,this._modelViewRelativeToEyeDirty=!0,this._inverseModelViewDirty=!0,this._modelViewProjectionDirty=!0,this._inverseModelViewProjectionDirty=!0,this._modelViewProjectionRelativeToEyeDirty=!0,this._modelViewInfiniteProjectionDirty=!0,this._normalDirty=!0,this._inverseNormalDirty=!0,this._normal3DDirty=!0,this._inverseNormal3DDirty=!0,this._encodedCameraPositionMCDirty=!0}},inverseModel:{get:function(){return this._inverseModelDirty&&(this._inverseModelDirty=!1,c.inverse(this._model,this._inverseModel)),this._inverseModel}},inverseTranposeModel:{get:function(){var e=this._inverseTransposeModel;return this._inverseTransposeModelDirty&&(this._inverseTransposeModelDirty=!1,c.getRotation(this.inverseModel,e),u.transpose(e,e)),e}},view:{get:function(){return this._view}},view3D:{get:function(){return this._view3DDirty&&(this._mode===p.SCENE3D?c.clone(this._view,this._view3D):z(this._cameraPosition,this._cameraDirection,this._cameraRight,this._cameraUp,this._frustum2DWidth,this._mode,this._mapProjection,this._view3D),c.getRotation(this._view3D,this._viewRotation3D),this._view3DDirty=!1),this._view3D}},viewRotation:{get:function(){return this._viewRotation}},viewRotation3D:{get:function(){this.view3D;return this._viewRotation3D}},inverseView:{get:function(){return this._inverseView}},inverseView3D:{get:function(){return this._inverseView3DDirty&&(c.inverseTransformation(this.view3D,this._inverseView3D),c.getRotation(this._inverseView3D,this._inverseViewRotation3D),this._inverseView3DDirty=!1),this._inverseView3D}},inverseViewRotation:{get:function(){return this._inverseViewRotation}},inverseViewRotation3D:{get:function(){this.inverseView3D;return this._inverseViewRotation3D}},projection:{get:function(){return this._projection}},inverseProjection:{get:function(){return E(this),this._inverseProjection}},inverseProjectionOIT:{get:function(){return S(this),this._inverseProjectionOIT}},infiniteProjection:{get:function(){return this._infiniteProjection}},modelView:{get:function(){return w(this),this._modelView}},modelView3D:{get:function(){return T(this),this._modelView3D}},modelViewRelativeToEye:{get:function(){return M(this),this._modelViewRelativeToEye}},inverseModelView:{get:function(){return b(this),this._inverseModelView}},inverseModelView3D:{get:function(){return x(this),this._inverseModelView3D}},viewProjection:{get:function(){return P(this),this._viewProjection}},inverseViewProjection:{get:function(){return A(this),this._inverseViewProjection}},modelViewProjection:{get:function(){return I(this),this._modelViewProjection}},inverseModelViewProjection:{get:function(){return D(this),this._inverseModelViewProjection}},modelViewProjectionRelativeToEye:{get:function(){return R(this),this._modelViewProjectionRelativeToEye}},modelViewInfiniteProjection:{get:function(){return O(this),this._modelViewInfiniteProjection}},normal:{get:function(){return N(this),this._normal}},normal3D:{get:function(){return L(this),this._normal3D}},inverseNormal:{get:function(){return F(this),this._inverseNormal}},inverseNormal3D:{get:function(){return B(this),this._inverseNormal3D}},entireFrustum:{get:function(){return this._entireFrustum}},currentFrustum:{get:function(){return this._currentFrustum}},frustumPlanes:{get:function(){return this._frustumPlanes}},eyeHeight2D:{get:function(){return this._eyeHeight2D}},sunPositionWC:{get:function(){return this._sunPositionWC}},sunPositionColumbusView:{get:function(){return this._sunPositionColumbusView}},sunDirectionWC:{get:function(){return this._sunDirectionWC}},sunDirectionEC:{get:function(){return this._sunDirectionEC}},moonDirectionEC:{get:function(){return this._moonDirectionEC}},encodedCameraPositionMCHigh:{get:function(){return V(this),this._encodedCameraPositionMC.high}},encodedCameraPositionMCLow:{get:function(){return V(this),this._encodedCameraPositionMC.low}},temeToPseudoFixedMatrix:{get:function(){return this._temeToPseudoFixed}},resolutionScale:{get:function(){return this._resolutionScale}},fogDensity:{get:function(){return this._fogDensity}}});var U=new u,G=new n;k.prototype.updateFrustum=function(e){v(this,e.projectionMatrix),o(e.infiniteProjectionMatrix)&&_(this,e.infiniteProjectionMatrix),this._currentFrustum.x=e.near,this._currentFrustum.y=e.far,o(e.top)||(e=e._offCenterFrustum),this._frustumPlanes.x=e.top,this._frustumPlanes.y=e.bottom,this._frustumPlanes.z=e.left,this._frustumPlanes.w=e.right},k.prototype.update=function(e){this._mode=e.mode,this._mapProjection=e.mapProjection;var t=e.context._canvas;this._resolutionScale=t.width/t.clientWidth;var r=e.camera;m(this,r.viewMatrix),f(this,r.inverseViewMatrix),g(this,r),e.mode===p.SCENE2D?(this._frustum2DWidth=r.frustum.right-r.frustum.left,this._eyeHeight2D.x=.5*this._frustum2DWidth,this._eyeHeight2D.y=this._eyeHeight2D.x*this._eyeHeight2D.x):(this._frustum2DWidth=0,this._eyeHeight2D.x=0,this._eyeHeight2D.y=0),y(this,e),this._entireFrustum.x=r.frustum.near,this._entireFrustum.y=r.frustum.far,this.updateFrustum(r.frustum),this._fogDensity=e.fog.density,this._frameState=e,this._temeToPseudoFixed=d.computeTemeToPseudoFixedMatrix(e.time,this._temeToPseudoFixed); +};var W=new r,H=new r,q=new r,j=new r,Y=new r,X=new n,Z=new r,K=new c;return k}),r("Renderer/Context",["../Core/clone","../Core/Color","../Core/ComponentDatatype","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/FeatureDetection","../Core/Geometry","../Core/GeometryAttribute","../Core/Math","../Core/Matrix4","../Core/PrimitiveType","../Core/RuntimeError","../Shaders/ViewportQuadVS","./BufferUsage","./ClearCommand","./ContextLimits","./CubeMap","./DrawCommand","./PassState","./PickFramebuffer","./PixelDatatype","./RenderbufferFormat","./RenderState","./ShaderCache","./ShaderProgram","./Texture","./UniformState","./VertexArray","./WebGLConstants"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R){"use strict";function O(e,t){var r="WebGL Error: ";switch(t){case e.INVALID_ENUM:r+="INVALID_ENUM";break;case e.INVALID_VALUE:r+="INVALID_VALUE";break;case e.INVALID_OPERATION:r+="INVALID_OPERATION";break;case e.OUT_OF_MEMORY:r+="OUT_OF_MEMORY";break;case e.CONTEXT_LOST_WEBGL:r+="CONTEXT_LOST_WEBGL lost";break;default:r+="Unknown ("+t+")"}return r}function N(e,t,r,i){for(var n=O(e,i)+": "+t.name+"(",o=0;oi;++i){var n=e.getExtension(t[i]);if(n)return n}return void 0}function z(e,t){if(e.validateFramebuffer){var r=e._gl,i=r.checkFramebufferStatus(r.FRAMEBUFFER);if(i!==r.FRAMEBUFFER_COMPLETE){var n;switch(i){case r.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:n="Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.";break;case r.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:n="Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height.";break;case r.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:n="Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer.";break;case r.FRAMEBUFFER_UNSUPPORTED:n="Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions."}throw new l(n)}}}function k(e,t,r,i){var n=e._currentRenderState,o=e._currentPassState;e._currentRenderState=t,e._currentPassState=r,x.partialApply(e._gl,n,t,o,r,i)}function U(e,t){if(t!==e._currentFramebuffer){e._currentFramebuffer=t;var r=Y;if(o(t))t._bind(),z(e,t),r=t._getActiveColorAttachments();else{var i=e._gl;i.bindFramebuffer(i.FRAMEBUFFER,null)}e.drawBuffers&&e.glDrawBuffers(r)}}function G(e,t,r,i,o,a){var s=n(n(o,r.renderState),e._defaultRenderState);U(e,t),k(e,s,i,!1);var l=n(a,r.shaderProgram);l._bind(),e._maxFrameTextureUnitIndex=Math.max(e._maxFrameTextureUnitIndex,l.maximumTextureUnitIndex)}function W(e,t,r){var i=t.primitiveType,a=t.vertexArray,s=t.offset,l=t.count,u=t.instanceCount;e._us.model=n(t.modelMatrix,p.IDENTITY);var c=n(r,t.shaderProgram);c._setUniforms(t.uniformMap,e._us,e.validateShaderProgram),a._bind();var h=a.indexBuffer;o(h)?(s*=h.bytesPerIndex,l=n(l,h.numberOfIndices),0===u?e._gl.drawElements(i,l,h.indexDatatype,s):e.glDrawElementsInstanced(i,l,h.indexDatatype,s,u)):(l=n(l,a.numberOfVertices),0===u?e._gl.drawArrays(i,s,l):e.glDrawArraysInstanced(i,s,l,u)),a._unBind()}function H(e,t,r){this._pickObjects=e,this.key=t,this.color=r}var q=function(r,a){if("undefined"==typeof WebGLRenderingContext)throw new f("The browser does not support WebGL. Visit http://get.webgl.org.");this._canvas=r,a=e(a,!0),a=n(a,{}),a.allowTextureFilterAnisotropic=n(a.allowTextureFilterAnisotropic,!0);var s=n(a.webgl,{});s.alpha=n(s.alpha,!1);var l,u=!1,c="undefined"!=typeof WebGL2RenderingContext,h=!1;if(u&&c&&(l=r.getContext("webgl2",s)||r.getContext("experimental-webgl2",s)||void 0,o(l)&&(h=!0)),o(l)||(l=r.getContext("webgl",s)||r.getContext("experimental-webgl",s)||void 0),!o(l))throw new f("The browser supports WebGL, but initialization failed.");this._originalGLContext=l,this._webgl2=h,this._id=i(),this.validateFramebuffer=!1,this.validateShaderProgram=!1,this.logShaderCompilation=!1,this._throwOnWebGLError=!1,this._shaderCache=new P(this);var d=this._gl=this._originalGLContext;this._redBits=d.getParameter(d.RED_BITS),this._greenBits=d.getParameter(d.GREEN_BITS),this._blueBits=d.getParameter(d.BLUE_BITS),this._alphaBits=d.getParameter(d.ALPHA_BITS),this._depthBits=d.getParameter(d.DEPTH_BITS),this._stencilBits=d.getParameter(d.STENCIL_BITS),y._maximumCombinedTextureImageUnits=d.getParameter(d.MAX_COMBINED_TEXTURE_IMAGE_UNITS),y._maximumCubeMapSize=d.getParameter(d.MAX_CUBE_MAP_TEXTURE_SIZE),y._maximumFragmentUniformVectors=d.getParameter(d.MAX_FRAGMENT_UNIFORM_VECTORS),y._maximumTextureImageUnits=d.getParameter(d.MAX_TEXTURE_IMAGE_UNITS),y._maximumRenderbufferSize=d.getParameter(d.MAX_RENDERBUFFER_SIZE),y._maximumTextureSize=d.getParameter(d.MAX_TEXTURE_SIZE),y._maximumVaryingVectors=d.getParameter(d.MAX_VARYING_VECTORS),y._maximumVertexAttributes=d.getParameter(d.MAX_VERTEX_ATTRIBS),y._maximumVertexTextureImageUnits=d.getParameter(d.MAX_VERTEX_TEXTURE_IMAGE_UNITS),y._maximumVertexUniformVectors=d.getParameter(d.MAX_VERTEX_UNIFORM_VECTORS);var p=d.getParameter(d.ALIASED_LINE_WIDTH_RANGE);y._minimumAliasedLineWidth=p[0],y._maximumAliasedLineWidth=p[1];var m=d.getParameter(d.ALIASED_POINT_SIZE_RANGE);y._minimumAliasedPointSize=m[0],y._maximumAliasedPointSize=m[1];var v=d.getParameter(d.MAX_VIEWPORT_DIMS);y._maximumViewportWidth=v[0],y._maximumViewportHeight=v[1];var _=d.getShaderPrecisionFormat(d.FRAGMENT_SHADER,d.HIGH_FLOAT);y._highpFloatSupported=0!==_.precision;var g=d.getShaderPrecisionFormat(d.FRAGMENT_SHADER,d.HIGH_INT);y._highpIntSupported=0!==g.rangeMax,this._antialias=d.getContextAttributes().antialias,this._standardDerivatives=!!V(d,["OES_standard_derivatives"]),this._elementIndexUint=!!V(d,["OES_element_index_uint"]),this._depthTexture=!!V(d,["WEBGL_depth_texture","WEBKIT_WEBGL_depth_texture"]),this._textureFloat=!!V(d,["OES_texture_float"]),this._fragDepth=!!V(d,["EXT_frag_depth"]),this._debugShaders=V(d,["WEBGL_debug_shaders"]);var C=a.allowTextureFilterAnisotropic?V(d,["EXT_texture_filter_anisotropic","WEBKIT_EXT_texture_filter_anisotropic"]):void 0;this._textureFilterAnisotropic=C,y._maximumTextureFilterAnisotropy=o(C)?d.getParameter(C.MAX_TEXTURE_MAX_ANISOTROPY_EXT):1;var E,w,T,b,A,I,D,O,N,L;if(h){var F=this;E=function(){return F._gl.createVertexArray()},w=function(e){F._gl.bindVertexArray(e)},T=function(e){F._gl.deleteVertexArray(e)},b=function(e,t,r,i,n){d.drawElementsInstanced(e,t,r,i,n)},A=function(e,t,r,i){d.drawArraysInstanced(e,t,r,i)},I=function(e,t){d.vertexAttribDivisor(e,t)},D=function(e){d.drawBuffers(e)}}else O=V(d,["OES_vertex_array_object"]),o(O)&&(E=function(){return O.createVertexArrayOES()},w=function(e){O.bindVertexArrayOES(e)},T=function(e){O.deleteVertexArrayOES(e)}),N=V(d,["ANGLE_instanced_arrays"]),o(N)&&(b=function(e,t,r,i,n){N.drawElementsInstancedANGLE(e,t,r,i,n)},A=function(e,t,r,i){N.drawArraysInstancedANGLE(e,t,r,i)},I=function(e,t){N.vertexAttribDivisorANGLE(e,t)}),L=V(d,["WEBGL_draw_buffers"]),o(L)&&(D=function(e){L.drawBuffersWEBGL(e)});this.glCreateVertexArray=E,this.glBindVertexArray=w,this.glDeleteVertexArray=T,this.glDrawElementsInstanced=b,this.glDrawArraysInstanced=A,this.glVertexAttribDivisor=I,this.glDrawBuffers=D,this._vertexArrayObject=!!O,this._instancedArrays=!!N,this._drawBuffers=!!L,y._maximumDrawBuffers=this.drawBuffers?d.getParameter(R.MAX_DRAW_BUFFERS):1,y._maximumColorAttachments=this.drawBuffers?d.getParameter(R.MAX_COLOR_ATTACHMENTS):1;var B=d.getParameter(d.COLOR_CLEAR_VALUE);this._clearColor=new t(B[0],B[1],B[2],B[3]),this._clearDepth=d.getParameter(d.DEPTH_CLEAR_VALUE),this._clearStencil=d.getParameter(d.STENCIL_CLEAR_VALUE);var z=new M,k=new S(this),U=x.fromCache();this._defaultPassState=k,this._defaultRenderState=U,this._defaultTexture=void 0,this._defaultCubeMap=void 0,this._us=z,this._currentRenderState=U,this._currentPassState=k,this._currentFramebuffer=void 0,this._maxFrameTextureUnitIndex=0,this._vertexAttribDivisors=[],this._previousDrawInstanced=!1;for(var G=0;Gi;++i)e.activeTexture(e.TEXTURE0+i),e.bindTexture(e.TEXTURE_2D,null),e.bindTexture(e.TEXTURE_CUBE_MAP,null)},q.prototype.readPixels=function(e){var t=this._gl;e=e||{};var r=Math.max(e.x||0,0),i=Math.max(e.y||0,0),n=e.width||t.drawingBufferWidth,o=e.height||t.drawingBufferHeight,a=e.framebuffer,s=new Uint8Array(4*n*o);return U(this,a),t.readPixels(r,i,n,o,t.RGBA,t.UNSIGNED_BYTE,s),s};var Z={position:0,textureCoordinates:1};return q.prototype.getViewportQuadVertexArray=function(){var e=this.cache.viewportQuad_vertexArray;if(!o(e)){var t=new c({attributes:{position:new h({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:[-1,-1,1,-1,1,1,-1,1]}),textureCoordinates:new h({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:[0,0,1,0,1,1,0,1]})},indices:new Uint16Array([0,1,2,0,2,3]),primitiveType:m.TRIANGLES});e=D.fromGeometry({context:this,geometry:t,attributeLocations:Z,bufferUsage:_.STATIC_DRAW,interleave:!0}),this.cache.viewportQuad_vertexArray=e}return e},q.prototype.createViewportQuadCommand=function(e,t){return t=n(t,n.EMPTY_OBJECT),new E({vertexArray:this.getViewportQuadVertexArray(),primitiveType:m.TRIANGLES,renderState:t.renderState,shaderProgram:A.fromCache({context:this,vertexShaderSource:v,fragmentShaderSource:e,attributeLocations:Z}),uniformMap:t.uniformMap,owner:t.owner,framebuffer:t.framebuffer})},q.prototype.createPickFramebuffer=function(){return new w(this)},q.prototype.getObjectByPickColor=function(e){return this._pickObjects[e.toRgba()]},a(H.prototype,{object:{get:function(){return this._pickObjects[this.key]},set:function(e){this._pickObjects[this.key]=e}}}),H.prototype.destroy=function(){return void delete this._pickObjects[this.key]},q.prototype.createPickId=function(e){++this._nextPickColor[0];var r=this._nextPickColor[0];if(0===r)throw new f("Out of unique Pick IDs.");return this._pickObjects[r]=e,new H(this._pickObjects,r,t.fromRgba(r))},q.prototype.isDestroyed=function(){return!1},q.prototype.destroy=function(){var e=this.cache;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];o(r.destroy)&&r.destroy()}return this._shaderCache=this._shaderCache.destroy(),this._defaultTexture=this._defaultTexture&&this._defaultTexture.destroy(),this._defaultCubeMap=this._defaultCubeMap&&this._defaultCubeMap.destroy(),s(this)},q}),r("Renderer/loadCubeMap",["../Core/defined","../Core/DeveloperError","../Core/loadImage","../ThirdParty/when","./CubeMap"],function(e,t,r,i,n){"use strict";var o=function(e,t,o){var a=[r(t.positiveX,o),r(t.negativeX,o),r(t.positiveY,o),r(t.negativeY,o),r(t.positiveZ,o),r(t.negativeZ,o)];return i.all(a,function(t){return new n({context:e,source:{positiveX:t[0],negativeX:t[1],positiveY:t[2],negativeY:t[3],positiveZ:t[4],negativeZ:t[5]}})})};return o}),r("Scene/DiscardMissingTileImagePolicy",["../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/getImagePixels","../Core/loadImageViaBlob","../ThirdParty/when"],function(e,t,r,i,n,o){"use strict";var a=function(a){function s(e){t(e.blob)&&(u._missingImageByteLength=e.blob.size);var r=i(e);if(a.disableCheckIfAllPixelsAreTransparent){for(var n=!0,o=e.width,s=a.pixelsToCheck,l=0,c=s.length;n&&c>l;++l){var h=s[l],d=4*h.x+h.y*o,p=r[d+3];p>0&&(n=!1)}n&&(r=void 0)}u._missingImagePixels=r,u._isReady=!0}function l(){u._missingImagePixels=void 0,u._isReady=!0}if(a=e(a,e.EMPTY_OBJECT),!t(a.missingImageUrl))throw new r("options.missingImageUrl is required.");if(!t(a.pixelsToCheck))throw new r("options.pixelsToCheck is required.");this._pixelsToCheck=a.pixelsToCheck,this._missingImagePixels=void 0,this._missingImageByteLength=void 0,this._isReady=!1;var u=this;o(n(a.missingImageUrl),s,l)};return a.prototype.isReady=function(){return this._isReady},a.prototype.shouldDiscardImage=function(e){if(!this._isReady)throw new r("shouldDiscardImage must not be called before the discard policy is ready.");var n=this._pixelsToCheck,o=this._missingImagePixels;if(!t(o))return!1;if(t(e.blob)&&e.blob.size!==this._missingImageByteLength)return!1;for(var a=i(e),s=e.width,l=0,u=n.length;u>l;++l)for(var c=n[l],h=4*c.x+c.y*s,d=0;4>d;++d){var p=h+d;if(a[p]!==o[p])return!1}return!0},a}),r("Scene/ImageryLayerFeatureInfo",["../Core/defined"],function(e){"use strict";var t=function(){this.name=void 0,this.description=void 0,this.position=void 0,this.data=void 0,this.imageryLayer=void 0};return t.prototype.configureNameFromProperties=function(t){var r,i=10;for(var n in t)if(t.hasOwnProperty(n)&&t[n]){var o=n.toLowerCase();i>1&&"name"===o?(i=1,r=n):i>2&&"title"===o?(i=2,r=n):i>3&&/name/i.test(n)?(i=3,r=n):i>4&&/title/i.test(n)&&(i=4,r=n)}e(r)&&(this.name=t[r])},t.prototype.configureDescriptionFromProperties=function(t){function r(t){var i='';for(var n in t)if(t.hasOwnProperty(n)){var o=t[n];e(o)&&(i+="object"==typeof o?"":"")}return i+="
"+n+""+r(o)+"
"+n+""+o+"
"}this.description=r(t)},t}),r("Scene/ImageryProvider",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/loadImage","../Core/loadImageViaBlob","../Core/throttleRequestByServer"],function(e,t,r,i,n,o){"use strict";var a=function(){this.defaultAlpha=void 0,this.defaultBrightness=void 0,this.defaultContrast=void 0,this.defaultHue=void 0,this.defaultSaturation=void 0,this.defaultGamma=void 0,r.throwInstantiationError()};return t(a.prototype,{ready:{get:r.throwInstantiationError},readyPromise:{get:r.throwInstantiationError},rectangle:{get:r.throwInstantiationError},tileWidth:{get:r.throwInstantiationError},tileHeight:{get:r.throwInstantiationError},maximumLevel:{get:r.throwInstantiationError},minimumLevel:{get:r.throwInstantiationError},tilingScheme:{get:r.throwInstantiationError},tileDiscardPolicy:{get:r.throwInstantiationError},errorEvent:{get:r.throwInstantiationError},credit:{get:r.throwInstantiationError},proxy:{get:r.throwInstantiationError},hasAlphaChannel:{get:r.throwInstantiationError}}),a.prototype.getTileCredits=r.throwInstantiationError,a.prototype.requestImage=r.throwInstantiationError,a.prototype.pickFeatures=r.throwInstantiationError,a.prototype.getTileDataAvailable=r.throwInstantiationError,a.loadImage=function(t,r){return e(t.tileDiscardPolicy)?o(r,n):o(r,i)},a}),r("Scene/ArcGisMapServerImageryProvider",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicProjection","../Core/GeographicTilingScheme","../Core/loadJson","../Core/loadJsonp","../Core/Math","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorProjection","../Core/WebMercatorTilingScheme","../ThirdParty/when","./DiscardMissingTileImagePolicy","./ImageryLayerFeatureInfo","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";function w(e,t,r,i){var n;if(e._useTiles)n=e._url+"/tile/"+i+"/"+r+"/"+t;else{var a=e._tilingScheme.tileXYToNativeRectangle(t,r,i),s=a.west+"%2C"+a.south+"%2C"+a.east+"%2C"+a.north;n=e._url+"/export?",n+="bbox="+s,n+=e._tilingScheme instanceof c?"&bboxSR=4326&imageSR=4326":"&bboxSR=3857&imageSR=3857",n+="&size="+e._tileWidth+"%2C"+e._tileHeight,n+="&format=png&transparent=true&f=image",e.layers&&(n+="&layers=show:"+e.layers)}var l=e._token;o(l)&&(-1===n.indexOf("?")&&(n+="?"),"?"!==n[n.length-1]&&(n+="&"),n+="token="+l);var u=e._proxy;return o(u)&&(n=u.getURL(n)),n}var T=function(t){function r(r){var n=r.tileInfo;if(o(n)){if(h._tileWidth=n.rows,h._tileHeight=n.cols,102100===n.spatialReference.wkid||102113===n.spatialReference.wkid)h._tilingScheme=new g({ellipsoid:t.ellipsoid});else{if(4326!==r.tileInfo.spatialReference.wkid){var a="Tile spatial reference WKID "+r.tileInfo.spatialReference.wkid+" is not supported.";return void(u=v.handleError(u,h,h._errorEvent,a,void 0,void 0,void 0,s))}h._tilingScheme=new c({ellipsoid:t.ellipsoid})}if(h._maximumLevel=r.tileInfo.lods.length-1,o(r.fullExtent)){if(o(r.fullExtent.spatialReference)&&o(r.fullExtent.spatialReference.wkid))if(102100===r.fullExtent.spatialReference.wkid||102113===r.fullExtent.spatialReference.wkid){var l=new _,d=l.unproject(new e(r.fullExtent.xmin,r.fullExtent.ymin)),p=l.unproject(new e(r.fullExtent.xmax,r.fullExtent.ymax));h._rectangle=new m(d.longitude,d.latitude,p.longitude,p.latitude)}else{if(4326!==r.fullExtent.spatialReference.wkid){var f="fullExtent.spatialReference WKID "+r.fullExtent.spatialReference.wkid+" is not supported.";return void(u=v.handleError(u,h,h._errorEvent,f,void 0,void 0,void 0,s))}h._rectangle=m.fromDegrees(r.fullExtent.xmin,r.fullExtent.ymin,r.fullExtent.xmax,r.fullExtent.ymax)}}else h._rectangle=h._tilingScheme.rectangle;o(h._tileDiscardPolicy)||(h._tileDiscardPolicy=new C({missingImageUrl:w(h,0,0,h._maximumLevel),pixelsToCheck:[new e(0,0),new e(200,20),new e(20,200),new e(80,110),new e(160,130)],disableCheckIfAllPixelsAreTransparent:!0})),h._useTiles=!0}else h._useTiles=!1;o(r.copyrightText)&&r.copyrightText.length>0&&(h._credit=new i(r.copyrightText)),h._ready=!0,h._readyPromise.resolve(!0),v.handleSuccess(u)}function a(e){var t="An error occurred while accessing "+h._url+".";u=v.handleError(u,h,h._errorEvent,t,void 0,void 0,void 0,s),h._readyPromise.reject(new f(t))}function s(){var e={f:"json"};o(h._token)&&(e.token=h._token);var t=d(h._url,{parameters:e,proxy:h._proxy});y(t,r,a)}t=n(t,{}),this._url=t.url,this._token=t.token,this._tileDiscardPolicy=t.tileDiscardPolicy,this._proxy=t.proxy,this._tileWidth=n(t.tileWidth,256),this._tileHeight=n(t.tileHeight,256),this._maximumLevel=t.maximumLevel,this._tilingScheme=n(t.tilingScheme,new c({ellipsoid:t.ellipsoid})),this._credit=void 0,this._useTiles=n(t.usePreCachedTilesIfAvailable,!0),this._rectangle=n(t.rectangle,this._tilingScheme.rectangle),this._layers=t.layers,this._enablePickFeatures=n(t.enablePickFeatures,!0),this._errorEvent=new l,this._ready=!1,this._readyPromise=y.defer();var u,h=this;this._useTiles?s():(this._ready=!0,this._readyPromise.resolve(!0))};return a(T.prototype,{url:{get:function(){return this._url}},token:{get:function(){return this._token}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},usingPrecachedTiles:{get:function(){return this._useTiles}},hasAlphaChannel:{get:function(){return!0}},layers:{get:function(){return this._layers}},enablePickFeatures:{get:function(){return this._enablePickFeatures}}}),T.prototype.getTileCredits=function(e,t,r){return void 0},T.prototype.requestImage=function(e,t,r){var i=w(this,e,t,r);return S.loadImage(this,i)},T.prototype.pickFeatures=function(e,i,n,a,s){if(!this._enablePickFeatures)return void 0;var l,u,d,m=this._tilingScheme.tileXYToNativeRectangle(e,i,n);if(this._tilingScheme instanceof c)l=p.toDegrees(a),u=p.toDegrees(s),d="4326";else{var f=this._tilingScheme.projection.project(new r(a,s,0));l=f.x,u=f.y,d="3857"}var v=this._url+"/identify?f=json&tolerance=2&geometryType=esriGeometryPoint";return v+="&geometry="+l+","+u,v+="&mapExtent="+m.west+","+m.south+","+m.east+","+m.north,v+="&imageDisplay="+this._tileWidth+","+this._tileHeight+",96",v+="&sr="+d,v+="&layers=visible",o(this._layers)&&(v+=":"+this._layers),o(this._token)&&(v+="&token="+this._token),o(this._proxy)&&(v=this._proxy.getURL(v)),h(v).then(function(e){var i=[],n=e.results;if(!o(n))return i;for(var a=0;ao;++o){for(var s=e[o],l=s.coverageAreas,u=!1,h=0,d=s.coverageAreas.length;!u&&d>h;++h){var p=l[h];if(t>=p.zoomMin&&t<=p.zoomMax){var m=c.intersection(r,p.bbox,S);n(m)&&(u=!0)}}u&&i.push(s.credit)}return i}var C=function w(o){function a(e){var i=e.resourceSets[0].resources[0];S._tileWidth=i.imageWidth,S._tileHeight=i.imageHeight,S._maximumLevel=i.zoomMax-1,S._imageUrlSubdomains=i.imageUrlSubdomains,S._imageUrlTemplate=i.imageUrl.replace("{culture}",S._culture);var o=S._tileProtocol;if(!n(o)){var a=document.location.protocol;o=/^http/.test(a)?a:"http:"}S._imageUrlTemplate=S._imageUrlTemplate.replace(/^http:/,o),n(S._tileDiscardPolicy)||(S._tileDiscardPolicy=new v({missingImageUrl:g(S,0,0,S._maximumLevel),pixelsToCheck:[new t(0,0),new t(120,140),new t(130,160),new t(200,50),new t(200,200)],disableCheckIfAllPixelsAreTransparent:!0}));var s=S._attributionList=i.imageryProviders;s||(s=S._attributionList=[]);for(var l=0,h=s.length;h>l;++l){var p=s[l];p.credit=new r(p.attribution);for(var m=p.coverageAreas,f=0,_=p.coverageAreas.length;_>f;++f){var y=m[f],E=y.bbox;y.bbox=new c(u.toRadians(E[1]),u.toRadians(E[0]),u.toRadians(E[3]),u.toRadians(E[2]))}}S._ready=!0,S._readyPromise.resolve(!0),d.handleSuccess(C)}function _(e){var t="An error occurred while accessing "+E+".";C=d.handleError(C,S,S._errorEvent,t,void 0,void 0,void 0,y),S._readyPromise.reject(new h(t))}function y(){var e=l(E,{callbackParameterName:"jsonp",proxy:S._proxy});m(e,a,_)}o=i(o,{}),this._key=e.getKey(o.key),this._url=o.url,this._tileProtocol=o.tileProtocol,this._mapStyle=i(o.mapStyle,f.AERIAL),this._culture=i(o.culture,""),this._tileDiscardPolicy=o.tileDiscardPolicy,this._proxy=o.proxy,this._credit=new r("Bing Imagery",w._logoData,"http://www.bing.com"),this.defaultGamma=1,(this._mapStyle===f.AERIAL||this._mapStyle===f.AERIAL_WITH_LABELS)&&(this.defaultGamma=1.3),this._tilingScheme=new p({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:2,ellipsoid:o.ellipsoid}),this._tileWidth=void 0,this._tileHeight=void 0,this._maximumLevel=void 0,this._imageUrlTemplate=void 0,this._imageUrlSubdomains=void 0,this._errorEvent=new s,this._ready=!1,this._readyPromise=m.defer();var C,E=this._url+"/REST/v1/Imagery/Metadata/"+this._mapStyle+"?incl=ImageryProviders&key="+this._key,S=this;y()};o(C.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},key:{get:function(){return this._key}},mapStyle:{get:function(){return this._mapStyle}},culture:{get:function(){return this._culture}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!1}}});var E=new c;C.prototype.getTileCredits=function(e,t,r){if(!this._ready)throw new a("getTileCredits must not be called before the imagery provider is ready.");var i=this._tilingScheme.tileXYToRectangle(e,t,r,E);return y(this._attributionList,r,i)},C.prototype.requestImage=function(e,t,r){var i=g(this,e,t,r);return _.loadImage(this,i)},C.prototype.pickFeatures=function(){return void 0},C._logoData="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD0AAAAaCAYAAAAEy1RnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3gIDEgcPTMnXOQAAClZJREFUWMPdWGtsFNcV/u689uH1+sXaONhlWQzBENtxiUFBpBSLd60IpXHSNig4URtSYQUkRJNSi0igViVVVBJBaBsiAgKRQJSG8AgEHCCWU4iBCprY2MSgXfOI16y9D3s9Mzsztz9yB12WNU2i9Ecy0tHOzN4793zn3POdcy7BnRfJ8I7iB3SRDPeEExswLz8Y0DZIAYDIRGAgLQAm+7Xle31J3L3Anp1MZPY+BUBjorN332vgYhpgV1FRUd6TTz45ubq6OtDV1SXpuu5g//Oept9wNwlMyAi8IXDjyF245TsDTdivDMATCATGNDU1/WbhwoWPTZs2bWx1dXWhx+Oxrl+/PqTrus5t9W8KWEzjinTAYhro/xuBStwiIgBnJBLxKIoy1u/3V/r9/krDMMz3339/Z3t7e38ikUgCMDLEt8W+Q0cAI3McYTDDmZxh7DESG5Ni43jg9Gsa+X+OsxWxPSJTSj3JZFK5ZRVJErOzs8e6XC4fgGwALhbzDgAKU1hK28KEA6PMmTMn56233qpevnz5PQDcbJ7EzVUAuMrLy3MBeABkcWOEDELSyFe4y7iMoHkriZZlKYZh8ASHZDKpJJPJHAC5APIA5APIAeBlCjo5TwlpXnbOmTPHP3fu3KZVq1atZKBcDJQ9x7V48WJfc3Pzhp6enj+tXLnyR8w4MjdG4gyVDk7KICMClzKlLUrpbQMNw5AkScppbGz8cWdn57WjR4/2caw+DEBlYjO8wX1foZQWuN3uKZIklQD4G+fhlG0Yl8uVm5WVVW6app6dne0D0G8vnxbjJntHubCUOK/badZICyWanrJuAaeUknTQpmlKkUhEWbx48U8LCwtHhUKha+fPn+85fPhwV0tLyzUACSZx9jvMFhIByNFoVDEMw/qKB5HPvJfkUqBr9+7deklJyZ/j8bi5ffv2OAslieMLsG+m2DybT2QuzEQOsF5SUqJfvXo1yc2l6Xn6rgSRSCSEc+fOhVeuXLmwoqJixvTp0wcWLFgQ7unpudHR0dF97ty5z/fu3XseQJh5adjeerquy5ZlCalUivh8Pt8HH3ywzOPxyD09PZ81NjZ+2NnZaQEQx40b54vFYqaqquEVK1b4a2tr/WvWrDn18ssv144fP36SqqoD69ev371nz57rDLwAwHHkyJGfjRs3rtowDOv06dOnu7q6rs6bN2/s7Nmz9zIjDKenWoFZKg/AlMLCwl82Nzf/m3LX22+/fXb06NF/ALC8u7u7m6ZdkUhksL29/UpLS0vzunXrVgAoBzAaQBGAiY2NjUui0ei1RCLRFwwG/9PX19cVi8WCqqoOdHd3HysrK6sDMCccDl8IBoOtiqIsOnbs2D+i0eiV3t7ez8Ph8GeRSKRT07TB/v7+i1OnTp0HYBqABzs7O/+paVo0Fot1RyKRi/F4/Gp/f39XIpHoZnoUMn6wU+ZtRDaymwmxZFk2AWjvvvvuJ/F4PMn/n5+fn1VeXu6fOXNmbU1NzUOM4Bz8QqIoyg6HwxuLxfq3bdu2a+vWrW/09/dfKy0tffDVV199BEC20+n0ud3uQgBup9Pp83g8JYqieE+ePPnxxo0bt33xxRen8/Ly7n3hhRcWASh47bXX5pWVldWFw+GuXbt27XjzzTd3BoPBDq/XG1AUZRRHmAKPVfqaoKkgCCkA+oYNG84Eg0FHTU1N5ezZs8eWlJQ4CSF8/LvZYhJPQoQQpFKpwcrKyo1su9HBwUF99erVv588eXINgOOmacIwDEopdaZSKUIpxYkTJz6sr68/BMBav379RcMwZk2aNOl+AP+qq6t7xDTNVEVFxR+j0WgSAJk4ceKlTz/9tNzpdHpZvIvpjVW6pykhhBJCbkvwgiAQQogEQL558ybdtGlTsLm5OWJZdxZmlmWll5OUEEJN0zSGhob6GcOrALSzZ8/2apqWcLlc2axGACNRkRAimqaph0Kh68xIwwB0y7IMSZKcABz5+fkl8Xj8y2g0apOb5na7rYGBgS/JV54Q0qpAAoBKaS0jBWClg1ZVFeFw2AlgVF1dXeDpp5+eWVFRUVpcXOzgvQwAbrcbDJhdudlGpKZpGtx6JCcnRxIEQbQsS2PjbjM+AMvlchnMSBaXkr7ymCCIhmEYfMoVRVESBEHI0CaTTNubssUsQRBuubCtra33pZdeCk6YMCGwZs2aipqaGn9paWmuJEl3JP0bN258eeTIkRMABrm0YomiaImiKGVlZeWxLecAgBkzZvgdDkfWjRs3ggA0bpfpoiiahBCqKEqKAy2yULMA6MlkMp6Xl3cP1x2SWCwmFhQU+CmlFhfHNFOevpX4LcvSJUkyAeDQoUOh119//fpTTz01Zf78+UWBQCBHUZQ7yE/TNGPfvn0n33vvvSP79+//BECMeZsCMGRZNgRBgNPpHHXx4sVVDQ0Nf1+wYMGYJ554YikAevDgwUMA4oIgQJZlSggZdDqdBiGEZGdn6ww0tQlJURTT4/EMHz9+/MCjjz7622AwuHbZsmVbiouLvWvXrm1wOp3ZqVRqaKQTIInf1gAMl8ulU0q1CxcuBGOxmL5u3bryQCDgycrKEjORXGtra8eOHTsOHz169OyVK1cuA+hlRYrGlNRkWR7UNO2mYRiaz+cb3dLS8gYhhOi6Hj116tSOVatWHQNALcsaME0zLghClBDSZ9+zQsZ2SoJS2udwOKLPPffcvsrKyrJAIPDQ/v37txiGofX19V3r7e29UlBQMHqEVpjwnrYA6PF4PK6q6s2qqqqpZWVlitvtljOB7enpiWzbtu3wgQMHTre1tV0E0MeKkkGuIhMAqHv37u30er3Px+NxlyiKygMPPOAnhFiXLl0Kbd68uYPNsXbu3Lk6mUwaqqr2btmyZUdtbe3hd955pwvAEFNcO3jw4K/b2tqiqqpGIpGI4/HHH/9rQ0PDCa/XOyoSidDLly8PNTU1PcZ4QuNK1ju6NYHFRAGASXPnzv1Fa2vrxzTDpapqateuXR/Nnz+/SVGUhwFMBzCBFSLZLF75DsrJGpXRAH4EIABgPIBxAEoBFAPwARjFif1sNzZ25+VlOhaxufcCqAFQC+BhAPVLliz5XSqVUkOhUAuAKWnFyR3dlsw+fg+A+8eMGfPzTZs2bY9GozEb8JkzZ9qXLl36l+Li4l8B+AmAyQDGsGrOzfXNPGPawG2l85jksmcPm+vihH+2W1iF3bvZPN+sWbPuGx4eDrW3t+85fvz41o6OjmZN04Y0TYvV19cvYIbN5QqUjG2mwj5YAqDK4XDMe+aZZ55vbW09+sorr2yuqqpqYFatAuBn3uB7XzJCY297XeaUd2RoGzOJmHb6IjFj5D777LP3DQwMfDw8PBxSVbUvkUj0hEKhj1588cXH2O7zMSPdplumoxveMx5Zlj3jx4/39vb26gMDA4MsvgYZo+p8Pr7LqQX5Ds/U7d0jFxUVZS1atKg4Nzc317Isp67rZldXV6y5ufkmI78hFtcmrx8ZweMit6XsUs4+6kmlgbW+peLf9gyMZNCR374G0y/FxEzX8b/8+bkXEBxKFwAAAABJRU5ErkJggg==", +C.tileXYToQuadKey=function(e,t,r){for(var i="",n=r;n>=0;--n){var o=1<=0;--n){var o=1<i;++i){var l=e.intersectPlane(o.fromCartesian4(t[i],s));if(l===n.OUTSIDE)return n.OUTSIDE;l===n.INTERSECTING&&(r=!0)}return r?n.INTERSECTING:n.INSIDE},a.prototype.computeVisibilityWithPlaneMask=function(e,t){if(t===a.MASK_OUTSIDE||t===a.MASK_INSIDE)return t;for(var r=a.MASK_INSIDE,i=this.planes,l=0,u=i.length;u>l;++l){var c=31>l?1<l&&0===(t&c))){var h=e.intersectPlane(o.fromCartesian4(i[l],s));if(h===n.OUTSIDE)return a.MASK_OUTSIDE;h===n.INTERSECTING&&(r|=c)}}return r},a.MASK_OUTSIDE=4294967295,a.MASK_INSIDE=0,a.MASK_INDETERMINATE=2147483647,a}),r("Scene/PerspectiveOffCenterFrustum",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/Matrix4","./CullingVolume"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e){var t=e.top,r=e.bottom,i=e.right,n=e.left,o=e.near,a=e.far;(t!==e._top||r!==e._bottom||n!==e._left||i!==e._right||o!==e._near||a!==e._far)&&(e._left=n,e._right=i,e._top=t,e._bottom=r,e._near=o,e._far=a,e._perspectiveMatrix=l.computePerspectiveOffCenter(n,i,r,t,o,a,e._perspectiveMatrix),e._infinitePerspective=l.computeInfinitePerspectiveOffCenter(n,i,r,t,o,e._infinitePerspective))}var h=function(){this.left=void 0,this._left=void 0,this.right=void 0,this._right=void 0,this.top=void 0,this._top=void 0,this.bottom=void 0,this._bottom=void 0,this.near=1,this._near=this.near,this.far=5e8,this._far=this.far,this._cullingVolume=new u,this._perspectiveMatrix=new l,this._infinitePerspective=new l};o(h.prototype,{projectionMatrix:{get:function(){return c(this),this._perspectiveMatrix}},infiniteProjectionMatrix:{get:function(){return c(this),this._infinitePerspective}}});var d=new t,p=new t,m=new t,f=new t;return h.prototype.computeCullingVolume=function(e,i,o){var a=this._cullingVolume.planes,s=this.top,l=this.bottom,u=this.right,c=this.left,h=this.near,v=this.far,_=t.cross(i,o,d),g=p;t.multiplyByScalar(i,h,g),t.add(e,g,g);var y=m;t.multiplyByScalar(i,v,y),t.add(e,y,y);var C=f;t.multiplyByScalar(_,c,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(C,o,C);var E=a[0];return n(E)||(E=a[0]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),t.multiplyByScalar(_,u,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(o,C,C),E=a[1],n(E)||(E=a[1]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),t.multiplyByScalar(o,l,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(_,C,C),E=a[2],n(E)||(E=a[2]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),t.multiplyByScalar(o,s,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(C,_,C),E=a[3],n(E)||(E=a[3]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),E=a[4],n(E)||(E=a[4]=new r),E.x=i.x,E.y=i.y,E.z=i.z,E.w=-t.dot(i,g),t.negate(i,C),E=a[5],n(E)||(E=a[5]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,y),this._cullingVolume},h.prototype.getPixelSize=function(t,r,o){a("PerspectiveOffCenterFrustum","getPixelSize is deprecated. Use getPixelDimensions instead."),c(this);var s=t.x,l=t.y;r=i(r,this.near);var u=1/this.near,h=this.top*u,d=2*r*h/l;h=this.right*u;var p=2*r*h/s;return n(o)?(o.x=p,o.y=d,o):new e(p,d)},h.prototype.getPixelDimensions=function(e,t,r,i){c(this);var n=1/this.near,o=this.top*n,a=2*r*o/t;o=this.right*n;var s=2*r*o/e;return i.x=s,i.y=a,i},h.prototype.clone=function(e){return n(e)||(e=new h),e.right=this.right,e.left=this.left,e.top=this.top,e.bottom=this.bottom,e.near=this.near,e.far=this.far,e._left=void 0,e._right=void 0,e._top=void 0,e._bottom=void 0,e._near=void 0,e._far=void 0,e},h.prototype.equals=function(e){return n(e)&&this.right===e.right&&this.left===e.left&&this.top===e.top&&this.bottom===e.bottom&&this.near===e.near&&this.far===e.far},h}),r("Scene/PerspectiveFrustum",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","./PerspectiveOffCenterFrustum"],function(e,t,r,i){"use strict";function n(e){var t=e._offCenterFrustum;(e.fov!==e._fov||e.aspectRatio!==e._aspectRatio||e.near!==e._near||e.far!==e._far)&&(e._aspectRatio=e.aspectRatio,e._fov=e.fov,e._fovy=e.aspectRatio<=1?e.fov:2*Math.atan(Math.tan(.5*e.fov)/e.aspectRatio),e._near=e.near,e._far=e.far,e._sseDenominator=2*Math.tan(.5*e._fovy),t.top=e.near*Math.tan(.5*e._fovy),t.bottom=-t.top,t.right=e.aspectRatio*t.top,t.left=-t.right,t.near=e.near,t.far=e.far)}var o=function(){this._offCenterFrustum=new i,this.fov=void 0,this._fov=void 0,this._fovy=void 0,this._sseDenominator=void 0,this.aspectRatio=void 0,this._aspectRatio=void 0,this.near=1,this._near=this.near,this.far=5e8,this._far=this.far};return t(o.prototype,{projectionMatrix:{get:function(){return n(this),this._offCenterFrustum.projectionMatrix}},infiniteProjectionMatrix:{get:function(){return n(this),this._offCenterFrustum.infiniteProjectionMatrix}},fovy:{get:function(){return n(this),this._fovy}},sseDenominator:{get:function(){return n(this),this._sseDenominator}}}),o.prototype.computeCullingVolume=function(e,t,r){return n(this),this._offCenterFrustum.computeCullingVolume(e,t,r)},o.prototype.getPixelSize=function(e,t,r){return n(this),this._offCenterFrustum.getPixelSize(e,t,r)},o.prototype.getPixelDimensions=function(e,t,r,i){return n(this),this._offCenterFrustum.getPixelDimensions(e,t,r,i)},o.prototype.clone=function(t){return e(t)||(t=new o),t.aspectRatio=this.aspectRatio,t.fov=this.fov,t.near=this.near,t.far=this.far,t._aspectRatio=void 0,t._fov=void 0,t._near=void 0,t._far=void 0,this._offCenterFrustum.clone(t._offCenterFrustum),t},o.prototype.equals=function(t){return e(t)?(n(this),n(t),this.fov===t.fov&&this.aspectRatio===t.aspectRatio&&this.near===t.near&&this.far===t.far&&this._offCenterFrustum.equals(t._offCenterFrustum)):!1},o}),r("Scene/CameraFlightPath",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/EasingFunction","../Core/Math","./PerspectiveFrustum","./PerspectiveOffCenterFrustum","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t,r){var i,n,o;if(e instanceof l){var a=Math.tan(.5*e.fovy);return i=e.near,n=e.near*a,o=e.aspectRatio*n,Math.max(t*i/o,r*i/n)}return e instanceof u?(i=e.near,n=e.top,o=e.right,Math.max(t*i/o,r*i/n)):Math.max(t,r)}function d(e,r,i,o,a){var l,u=a;if(!n(a)){var c=e.position,d=r,p=e.up,m=e.right,f=e.frustum,v=t.subtract(c,d,C),_=t.magnitude(t.multiplyByScalar(p,t.dot(v,p),E)),g=t.magnitude(t.multiplyByScalar(m,t.dot(v,m),E));l=Math.max(i,o),u=Math.min(.2*h(f,_,g),1e9)}if(n(a)&&u>a||u>l){var y=8,S=1e6,w=-Math.pow((u-i)*S,1/y),T=Math.pow((u-o)*S,1/y);return function(e){var t=e*(T-w)+w;return-Math.pow(t,y)/S+u}}return function(e){return s.lerp(i,o,e)}}function p(e,t){return s.equalsEpsilon(e,s.TWO_PI,s.EPSILON11)&&(e=0),t>e+Math.PI?e+=s.TWO_PI:ts.PI&&(y.longitude+=s.TWO_PI);var E=d(c,n,f.height,y.height,u),S=function(e){var r=e.time/i,n=t.fromRadians(s.lerp(f.longitude,y.longitude,r),s.lerp(f.latitude,y.latitude,r),E(r));c.setView({destination:n,orientation:{heading:s.lerp(_,o,r),pitch:s.lerp(v,a,r),roll:s.lerp(g,l,r)}})};return S}function v(r,i,n,o,a,l,u){var c=r.camera,h=t.clone(c.position,S),m=p(c.heading,o),f=c.frustum.right-c.frustum.left,v=d(c,n,f,n.z,u),_=function(t){var r=t.time/i;c.setView({orientation:{heading:s.lerp(m,o,r)}}),e.lerp(h,n,r,c.position);var a=v(r),l=c.frustum,u=l.top/l.right,d=.5*(a-(l.right-l.left));l.right+=d,l.left-=d,l.top=u*l.right,l.bottom=-l.top};return _}function _(e,t){return{startObject:{},stopObject:{},duration:0,complete:e,cancel:t}}function g(e,t){var r=function(){"function"==typeof t&&t(),e.enableInputs=!0};return r}var y={},C=new t,E=new t,S=new t,w=new r,T=new r,b=(new t,new t,new t,new t,new r),x=new t;return y.createTween=function(r,o){o=i(o,i.EMPTY_OBJECT);var l=o.destination,u=r.mode;if(u===c.MORPHING)return _();var h=i(o.convert,!0),d=r.mapProjection,p=d.ellipsoid,y=o.maximumHeight,C=o.easingFunction;h&&u!==c.SCENE3D&&(p.cartesianToCartographic(l,b),l=d.project(b,x));var E=r.camera,S=o.endTransform;n(S)&&E._setTransform(S);var w=o.duration;n(w)||(w=Math.ceil(t.distance(E.position,l)/1e6)+2,w=Math.min(w,3));var T=i(o.heading,0),P=i(o.pitch,-s.PI_OVER_TWO),A=i(o.roll,0),I=r.screenSpaceCameraController;I.enableInputs=!1;var M=g(I,o.complete),D=g(I,o.cancel),R=E.frustum,O=r.mode===c.SCENE2D;if(O=O&&e.equalsEpsilon(E.position,l,s.EPSILON6),O=O&&s.equalsEpsilon(Math.max(R.right-R.left,R.top-R.bottom),l.z,s.EPSILON6),O=O||r.mode!==c.SCENE2D&&t.equalsEpsilon(l,E.position,s.EPSILON10)&&s.equalsEpsilon(s.negativePiToPi(T),s.negativePiToPi(E.heading),s.EPSILON10)&&s.equalsEpsilon(s.negativePiToPi(P),s.negativePiToPi(E.pitch),s.EPSILON10)&&s.equalsEpsilon(s.negativePiToPi(A),s.negativePiToPi(E.roll),s.EPSILON10))return _(M,D);var N=new Array(4);if(N[c.SCENE2D]=v,N[c.SCENE3D]=f,N[c.COLUMBUS_VIEW]=m,0>=w){var L=function(){var e=N[u](r,1,l,T,P,A,y);e({time:1}),"function"==typeof M&&M()};return _(L,D)}var F=N[u](r,w,l,T,P,A,y);if(!n(C)){var B=E.positionCartographic.height,V=u===c.SCENE3D?p.cartesianToCartographic(l).height:l.z;C=B>V&&B>11500?a.CUBIC_OUT:a.QUINTIC_IN_OUT}return{duration:w,easingFunction:C,startObject:{time:0},stopObject:{time:w},update:F,complete:M,cancel:D}},y}),r("Scene/Camera",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/EasingFunction","../Core/Ellipsoid","../Core/EllipsoidGeodesic","../Core/Event","../Core/HeadingPitchRange","../Core/IntersectionTests","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Quaternion","../Core/Ray","../Core/Rectangle","../Core/Transforms","./CameraFlightPath","./PerspectiveFrustum","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T){"use strict";function b(e){var r=e._right,i=e._up,n=e._direction,o=e._position,a=e._viewMatrix;a[0]=r.x,a[1]=i.x,a[2]=-n.x,a[3]=0,a[4]=r.y,a[5]=i.y,a[6]=-n.y,a[7]=0,a[8]=r.z,a[9]=i.z,a[10]=-n.z,a[11]=0,a[12]=-t.dot(r,o),a[13]=-t.dot(i,o),a[14]=t.dot(n,o),a[15]=1,_.multiply(a,e._actualInvTransform,e._viewMatrix),_.inverseTransformation(e._viewMatrix,e._invViewMatrix)}function x(e){var i=e._projection,n=i.ellipsoid,o=_.getColumn(e._transform,3,se),a=n.cartesianToCartographic(o,ne),s=i.project(a,oe),l=le;l.x=s.z,l.y=s.x,l.z=s.y,l.w=1;var u=r.add(_.getColumn(e._transform,0,ae),o,ae);n.cartesianToCartographic(u,a),i.project(a,s);var c=ue;c.x=s.z,c.y=s.x,c.z=s.y,c.w=0,t.subtract(c,l,c);var h=r.add(_.getColumn(e._transform,1,ae),o,ae);n.cartesianToCartographic(h,a),i.project(a,s);var d=ce;d.x=s.z,d.y=s.x,d.z=s.y,d.w=0,t.subtract(d,l,d);var p=he;t.cross(c,d,p),t.normalize(p,p),t.cross(d,p,c),t.normalize(c,c),t.cross(p,c,d),t.normalize(d,d),_.setColumn(e._actualTransform,0,c,e._actualTransform),_.setColumn(e._actualTransform,1,d,e._actualTransform),_.setColumn(e._actualTransform,2,p,e._actualTransform),_.setColumn(e._actualTransform,3,l,e._actualTransform)}function P(e){var i=e._projection,n=i.ellipsoid,o=_.getColumn(e._transform,3,se),a=n.cartesianToCartographic(o,ne),s=i.project(a,oe),l=le;l.x=s.z,l.y=s.x,l.z=s.y,l.w=1;var u=r.clone(r.UNIT_X,he),c=r.add(_.getColumn(e._transform,0,ae),o,ae);n.cartesianToCartographic(c,a),i.project(a,s);var h=ue;h.x=s.z,h.y=s.x,h.z=s.y,h.w=0,t.subtract(h,l,h),h.x=0;var d=ce;if(t.magnitudeSquared(h)>f.EPSILON10)t.cross(u,h,d);else{var p=r.add(_.getColumn(e._transform,1,ae),o,ae);n.cartesianToCartographic(p,a),i.project(a,s),d.x=s.z,d.y=s.x,d.z=s.y,d.w=0,t.subtract(d,l,d),d.x=0,t.magnitudeSquared(d)f.EPSILON2){s=t.normalize(s,e._direction),t.clone(s,e.direction);var y=1/t.magnitudeSquared(u),C=t.dot(u,s)*y,E=t.multiplyByScalar(s,C,de);u=t.normalize(t.subtract(u,E,e._up),e._up),t.clone(u,e.up),h=t.cross(s,u,e._right),t.clone(h,e.right)}}(l||p)&&(e._directionWC=_.multiplyByPointAsVector(m,s,e._directionWC)),(c||p)&&(e._upWC=_.multiplyByPointAsVector(m,u,e._upWC)),(d||p)&&(e._rightWC=_.multiplyByPointAsVector(m,h,e._rightWC)),(a||l||c||d||p)&&b(e)}function I(e,t){var r;return r=f.equalsEpsilon(Math.abs(e.z),1,f.EPSILON3)?Math.atan2(t.y,t.x)-f.PI_OVER_TWO:Math.atan2(e.y,e.x)-f.PI_OVER_TWO,f.TWO_PI-f.zeroToTwoPi(r)}function M(e){return f.PI_OVER_TWO-f.acosClamped(e.z)}function D(e,t,r){var i=0;return f.equalsEpsilon(Math.abs(e.z),1,f.EPSILON3)||(i=Math.atan2(-r.z,t.z),i=f.zeroToTwoPi(i+f.TWO_PI)),i}function R(e,r,i,n,o){var a=_.clone(e.transform,ye),s=E.eastNorthUpToFixedFrame(r,e._projection.ellipsoid,Ce);e._setTransform(s),t.clone(t.ZERO,e.position);var l=g.fromHeadingPitchRoll(i-f.PI_OVER_TWO,n,o,Ee),u=v.fromQuaternion(l,Se);v.getColumn(u,0,e.direction),v.getColumn(u,2,e.up),t.cross(e.direction,e.up,e.right),e._setTransform(a)}function O(e,r,i,n,o,a){var s=_.clone(e.transform,ye);if(e._setTransform(_.IDENTITY),!t.equals(r,e.positionWC)){if(a){var l=e._projection,u=l.ellipsoid.cartesianToCartographic(r,we);r=l.project(u,ge)}t.clone(r,e.position)}var c=g.fromHeadingPitchRoll(i-f.PI_OVER_TWO,n,o,Ee),h=v.fromQuaternion(c,Se);v.getColumn(h,0,e.direction),v.getColumn(h,2,e.up),t.cross(e.direction,e.up,e.right),e._setTransform(s)}function N(r,i,n,o){var a=-f.PI_OVER_TWO,s=0,l=_.clone(r.transform,ye);if(r._setTransform(_.IDENTITY),!t.equals(i,r.positionWC)){if(o){var u=r._projection,c=u.ellipsoid.cartesianToCartographic(i,we);i=u.project(c,ge)}e.clone(i,r.position);var h=.5*-i.z,d=-h,p=r.frustum;if(d>h){var m=p.top/p.right;p.right=d,p.left=h,p.top=p.right*m,p.bottom=-p.top}}var y=g.fromHeadingPitchRoll(n-f.PI_OVER_TWO,a,s,Ee),C=v.fromQuaternion(y,Se);v.getColumn(C,2,r.up),t.cross(r.direction,r.up,r.right),r._setTransform(l)}function L(e,r,i,n){var o=t.clone(i.direction,Te),a=t.clone(i.up,be);if(e._scene.mode===T.SCENE3D){var s=e._projection.ellipsoid,l=E.eastNorthUpToFixedFrame(r,s,pe),u=_.inverseTransformation(l,me);_.multiplyByPointAsVector(u,o,o),_.multiplyByPointAsVector(u,a,a)}var c=t.cross(o,a,xe);return n.heading=I(o,a),n.pitch=M(o),n.roll=D(o,a,c),n}function F(e,t){var r=e._maxCoord.x*e.maximumTranslateFactor;t.x>r&&(t.x=r),t.x<-r&&(t.x=-r);var i=e._maxCoord.y*e.maximumTranslateFactor;t.y>i&&(t.y=i),t.y<-i&&(t.y=-i)}function B(e,r){var i=e.position,n=t.normalize(i,Oe);if(o(e.constrainedAxis)){var a=t.equalsEpsilon(n,e.constrainedAxis,f.EPSILON2),s=t.equalsEpsilon(n,t.negate(e.constrainedAxis,Fe),f.EPSILON2);if(a||s)(a&&0>r||s&&r>0)&&e.rotate(e.right,r);else{var l=t.normalize(e.constrainedAxis,Ne),u=t.dot(n,l),c=f.acosClamped(u);if(r>0&&r>c&&(r=c-f.EPSILON4),o(e.constrainedAxisAngle)){var h=e.constrainedAxisAngle,d=c-h;0>r&&d>r&&(r=d+f.EPSILON4)}u=t.dot(n,t.negate(l,Fe)),c=f.acosClamped(u),0>r&&-r>c&&(r=-c+f.EPSILON4);var p=t.cross(l,n,Le);e.rotate(p,r)}}else e.rotate(e.right,r)}function V(e,t){o(e.constrainedAxis)?e.rotate(e.constrainedAxis,t):e.rotate(e.up,t)}function z(e,t){var r=e.frustum;t=.5*t;var i=r.right-t,n=r.left+t,o=e._maxCoord.x*e.maximumZoomFactor;i>o&&(i=o,n=-o),n>=i&&(i=1,n=-1);var a=r.top/r.right;r.right=i,r.left=n,r.top=r.right*a,r.bottom=-r.top}function k(e,t){e.move(e.direction,t)}function U(e,r,i){r=f.clamp(r,-f.PI_OVER_TWO,f.PI_OVER_TWO),e=f.zeroToTwoPi(e)-f.PI_OVER_TWO;var n=g.fromAxisAngle(t.UNIT_Y,-r,ze),o=g.fromAxisAngle(t.UNIT_Z,-e,ke),a=g.multiply(o,n,o),s=v.fromQuaternion(a,Ue),l=t.clone(t.UNIT_X,Ve);return v.multiplyByVector(s,l,l),t.negate(l,l),t.multiplyByScalar(l,i,l),l}function G(e,r,i,n){var o=Math.abs(t.dot(r,i));return o/n-t.dot(e,i)}function W(e,r,i,n){var a=e._projection.ellipsoid,s=n?e:$e,l=r.north,u=r.south,c=r.east,d=r.west;d>c&&(c+=f.TWO_PI);var p,m=.5*(d+c);if(u<-f.PI_OVER_TWO+f.RADIANS_PER_DEGREE&&l>f.PI_OVER_TWO-f.RADIANS_PER_DEGREE)p=0;else{var v=We;v.longitude=m,v.latitude=l,v.height=0;var _=He;_.longitude=m,_.latitude=u,_.height=0;var g=Ge;o(g)&&g.ellipsoid===a||(Ge=g=new h(void 0,void 0,a)),g.setEndPoints(v,_),p=g.interpolateUsingFraction(.5,We).latitude}var y=We;y.longitude=m,y.latitude=p,y.height=0;var C=a.cartographicToCartesian(y,Je),E=We;E.longitude=c,E.latitude=l;var S=a.cartographicToCartesian(E,qe);E.longitude=d;var w=a.cartographicToCartesian(E,Ye);E.longitude=m;var T=a.cartographicToCartesian(E,Ze);E.latitude=u;var b=a.cartographicToCartesian(E,Ke);E.longitude=c;var x=a.cartographicToCartesian(E,Xe);E.longitude=d;var P=a.cartographicToCartesian(E,je);t.subtract(w,C,w),t.subtract(x,C,x),t.subtract(S,C,S),t.subtract(P,C,P),t.subtract(T,C,T),t.subtract(b,C,b);var A=a.geodeticSurfaceNormal(C,s.direction);t.negate(A,A);var I=t.cross(A,t.UNIT_Z,s.right);t.normalize(I,I);var M=t.cross(I,A,s.up),D=Math.tan(.5*e.frustum.fovy),R=e.frustum.aspectRatio*D,O=Math.max(G(A,M,w,D),G(A,M,x,D),G(A,M,S,D),G(A,M,P,D),G(A,M,T,D),G(A,M,b,D),G(A,I,w,R),G(A,I,x,R),G(A,I,S,R),G(A,I,P,R),G(A,I,T,R),G(A,I,b,R));if(0>u&&l>0){var N=We;N.longitude=d,N.latitude=0,N.height=0;var L=a.cartographicToCartesian(N,Qe);t.subtract(L,C,L),O=Math.max(O,G(A,M,L,D),G(A,I,L,R)),N.longitude=c,L=a.cartographicToCartesian(N,Qe),t.subtract(L,C,L),O=Math.max(O,G(A,M,L,D),G(A,I,L,R))}return t.add(C,t.multiplyByScalar(A,-O,Qe),i)}function H(e,t,r){var i=e._projection;t.west>t.east&&(t=C.MAX_VALUE);var n=e._actualTransform,o=e._actualInvTransform,a=et;a.longitude=t.east,a.latitude=t.north;var s=i.project(a,tt);_.multiplyByPoint(n,s,s),_.multiplyByPoint(o,s,s),a.longitude=t.west,a.latitude=t.south;var l=i.project(a,rt);_.multiplyByPoint(n,l,l),_.multiplyByPoint(o,l,l);var u=Math.tan(.5*e.frustum.fovy),c=e.frustum.aspectRatio*u;return r.x=.5*(s.x-l.x)+l.x,r.y=.5*(s.y-l.y)+l.y,r.z=.5*Math.max((s.x-l.x)/c,(s.y-l.y)/u),r}function q(e,t,r){var i=e._projection;t.west>t.east&&(t=C.MAX_VALUE);var n=it;n.longitude=t.east,n.latitude=t.north;var o=i.project(n,nt);n.longitude=t.west,n.latitude=t.south;var a,s,l=i.project(n,ot),u=.5*Math.abs(o.x-l.x),c=.5*Math.abs(o.y-l.y),h=e.frustum.right/e.frustum.top,d=c*h;return u>d?(a=u,s=a/h):(s=c,a=d),c=Math.max(2*a,2*s),r.x=.5*(o.x-l.x)+l.x,r.y=.5*(o.y-l.y)+l.y,n=i.unproject(r,n),n.height=c,r=i.project(n,r)}function j(e,t,r,i){r=n(r,c.WGS84);var o=e.getPickRay(t,at),a=m.rayEllipsoid(o,r);if(!a)return void 0;var s=a.start>0?a.start:a.stop;return y.getPoint(o,s,i)}function Y(e,t,r,i){var n=e.getPickRay(t,st),o=n.origin;o.z=0;var a=r.unproject(o);return a.latitude<-f.PI_OVER_TWO||a.latitude>f.PI_OVER_TWO||a.longitude<-Math.PI||a.longitude>Math.PI?void 0:r.ellipsoid.cartographicToCartesian(a,i)}function X(e,r,i,n){var o=e.getPickRay(r,lt),a=-o.origin.x/o.direction.x;y.getPoint(o,a,n);var s=i.unproject(new t(n.y,n.z,0));return s.latitude<-f.PI_OVER_TWO||s.latitude>f.PI_OVER_TWO||s.longitude<-Math.PI||s.longitude>Math.PI?void 0:i.ellipsoid.cartographicToCartesian(s,n)}function Z(e,r,i){var n=e._scene.canvas,o=n.clientWidth,a=n.clientHeight,s=Math.tan(.5*e.frustum.fovy),l=e.frustum.aspectRatio*s,u=e.frustum.near,c=2/o*r.x-1,h=2/a*(a-r.y)-1,d=e.positionWC;t.clone(d,i.origin);var p=t.multiplyByScalar(e.directionWC,u,ut);t.add(d,p,p);var m=t.multiplyByScalar(e.rightWC,c*u*l,ct),f=t.multiplyByScalar(e.upWC,h*u*s,ht),v=t.add(p,m,i.direction);return t.add(v,f,v),t.subtract(v,d,v),t.normalize(v,v),i}function K(e,r,i){var n=e._scene.canvas,o=n.clientWidth,a=n.clientHeight,s=2/o*r.x-1;s*=.5*(e.frustum.right-e.frustum.left);var l=2/a*(a-r.y)-1;l*=.5*(e.frustum.top-e.frustum.bottom);var u=i.origin;return t.clone(e.position,u),t.multiplyByScalar(e.right,s,dt),t.add(dt,u,u),t.multiplyByScalar(e.up,l,dt),t.add(dt,u,u),t.clone(e.directionWC,i.direction),i}function J(e,r){var i=e.position,n=i.x<-e._maxCoord.x||i.x>e._maxCoord.x,o=i.y<-e._maxCoord.y||i.y>e._maxCoord.y,a=n||o,s=e.frustum,l=s.top,c=s.bottom,h=s.right,d=s.left,p=e._max2Dfrustum,m=h>e._max2Dfrustum.right;if(a||m){var v=t.clone(i);v.x>e._maxCoord.x?v.x=e._maxCoord.x:v.x<-e._maxCoord.x&&(v.x=-e._maxCoord.x),v.y>e._maxCoord.y?v.y=e._maxCoord.y:v.y<-e._maxCoord.y&&(v.y=-e._maxCoord.y);var _=function(r){a&&(e.position=t.lerp(i,v,r.time,e.position)),m&&(e.frustum.top=f.lerp(l,p.top,r.time),e.frustum.bottom=f.lerp(c,p.bottom,r.time),e.frustum.right=f.lerp(h,p.right,r.time),e.frustum.left=f.lerp(d,p.left,r.time))};return{easingFunction:u.EXPONENTIAL_OUT,startObject:{time:0},stopObject:{time:1},duration:r,update:_}}return void 0}function Q(e,r,i,n,o,a){var s=t.clone(r);i.y>n?s.y-=i.y-n:i.y<-n&&(s.y+=-n-i.y),i.z>o?s.z-=i.z-o:i.z<-o&&(s.z+=-o-i.z);var l=function(i){var n=t.lerp(r,s,i.time,new t);e.worldToCameraCoordinatesPoint(n,e.position)};return{easingFunction:u.EXPONENTIAL_OUT,startObject:{time:0},stopObject:{time:1},duration:a,update:l}}function $(e,r){var i=e.position,n=e.direction,o=e.worldToCameraCoordinatesVector(t.UNIT_X,ft),a=-t.dot(o,i)/t.dot(o,n),s=t.add(i,t.multiplyByScalar(n,a,vt),vt);e.cameraToWorldCoordinatesPoint(s,s),i=e.cameraToWorldCoordinatesPoint(e.position,_t);var l=Math.tan(.5*e.frustum.fovy),u=e.frustum.aspectRatio*l,c=t.magnitude(t.subtract(i,s,gt)),h=u*c,d=l*c,p=e._maxCoord.x,m=e._maxCoord.y,f=Math.max(h-p,p),v=Math.max(d-m,m);if(i.z<-f||i.z>f||i.y<-v||i.y>v){var _=s.y<-f||s.y>f,g=s.z<-v||s.z>v;if(_||g)return Q(e,i,s,f,v,r)}return void 0}function ee(e,t){var r=e.frustum,i=Math.tan(.5*r.fovy),n=r.aspectRatio*i;return Math.max(t/n,t/i)}function te(e,t){var r,i,n=e.frustum,o=n.right/n.top,a=t*o;return t>a?(r=t,i=r/o):(i=t,r=a),1.5*Math.max(r,i)}function re(e,t,r){o(r)||(r=p.clone(Et));var i=r.range;if(!o(i)||0===i){var n=t.radius;0===n?r.range=St:r.range=e._mode===T.SCENE2D?te(e,n):ee(e,n)}return r}var ie=function(e){this._scene=e,this._transform=_.clone(_.IDENTITY),this._invTransform=_.clone(_.IDENTITY),this._actualTransform=_.clone(_.IDENTITY),this._actualInvTransform=_.clone(_.IDENTITY),this._transformChanged=!1,this.position=new t,this._position=new t,this._positionWC=new t,this._positionCartographic=new i,this.direction=new t,this._direction=new t,this._directionWC=new t,this.up=new t,this._up=new t,this._upWC=new t,this.right=new t,this._right=new t,this._rightWC=new t,this.frustum=new w,this.frustum.aspectRatio=e.drawingBufferWidth/e.drawingBufferHeight,this.frustum.fov=f.toRadians(60),this.defaultMoveAmount=1e5,this.defaultLookAmount=Math.PI/60,this.defaultRotateAmount=Math.PI/3600,this.defaultZoomAmount=1e5,this.constrainedAxis=void 0,this.constrainedAxisAngle=void 0,this.maximumTranslateFactor=1.5,this.maximumZoomFactor=2.5,this._moveStart=new d,this._moveEnd=new d,this._viewMatrix=new _,this._invViewMatrix=new _,b(this),this._mode=T.SCENE3D,this._modeChanged=!0;var r=e.mapProjection;this._projection=r,this._maxCoord=r.project(new i(Math.PI,f.PI_OVER_TWO)),this._max2Dfrustum=void 0,W(this,ie.DEFAULT_VIEW_RECTANGLE,this.position,!0);var n=t.magnitude(this.position);n+=n*ie.DEFAULT_VIEW_FACTOR,t.normalize(this.position,this.position),t.multiplyByScalar(this.position,n,this.position)};ie.TRANSFORM_2D=new _(0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1),ie.TRANSFORM_2D_INVERSE=_.inverseTransformation(ie.TRANSFORM_2D,new _),ie.DEFAULT_VIEW_RECTANGLE=C.fromDegrees(-95,-20,-70,90),ie.DEFAULT_VIEW_FACTOR=.5;var ne=new i,oe=new t,ae=new t,se=new r,le=new r,ue=new r,ce=new r,he=new r,de=new t,pe=new _,me=new _;a(ie.prototype,{transform:{get:function(){return this._transform}},inverseTransform:{get:function(){return A(this),this._invTransform}},viewMatrix:{get:function(){return A(this),this._viewMatrix}},inverseViewMatrix:{get:function(){return A(this),this._invViewMatrix}},positionCartographic:{get:function(){return A(this),this._positionCartographic}},positionWC:{get:function(){return A(this),this._positionWC}},directionWC:{get:function(){return A(this),this._directionWC}},upWC:{get:function(){return A(this),this._upWC}},rightWC:{get:function(){return A(this),this._rightWC}},heading:{get:function(){if(this._mode!==T.MORPHING){var e=(this.positionWC,this._projection.ellipsoid),t=_.clone(this._transform,pe),r=E.eastNorthUpToFixedFrame(this.positionWC,e,me);this._setTransform(r);var i=I(this.direction,this.up);return this._setTransform(t),i}return void 0}},pitch:{get:function(){if(this._mode!==T.MORPHING){var e=(this.positionWC,this._projection.ellipsoid),t=_.clone(this._transform,pe),r=E.eastNorthUpToFixedFrame(this.positionWC,e,me);this._setTransform(r);var i=M(this.direction);return this._setTransform(t),i}return void 0}},roll:{get:function(){if(this._mode!==T.MORPHING){var e=(this.positionWC,this._projection.ellipsoid),t=_.clone(this._transform,pe),r=E.eastNorthUpToFixedFrame(this.positionWC,e,me);this._setTransform(r);var i=D(this.direction,this.up,this.right);return this._setTransform(t),i}return void 0}},moveStart:{get:function(){return this._moveStart}},moveEnd:{get:function(){return this._moveEnd}}}),ie.prototype.update=function(e){var t=!1;if(e!==this._mode&&(this._mode=e,this._modeChanged=e!==T.MORPHING,t=this._mode===T.SCENE2D),t){var r=this._max2Dfrustum=this.frustum.clone(),i=2,n=r.top/r.right;r.right=this._maxCoord.x*i,r.left=-r.right,r.top=n*r.right,r.bottom=-r.top}};var fe=new t,ve=new t,_e=new t;ie.prototype._setTransform=function(e){var r=t.clone(this.positionWC,fe),i=t.clone(this.upWC,ve),n=t.clone(this.directionWC,_e);_.clone(e,this._transform),this._transformChanged=!0,A(this);var o=this._actualInvTransform;_.multiplyByPoint(o,r,this.position),_.multiplyByPointAsVector(o,n,this.direction),_.multiplyByPointAsVector(o,i,this.up),t.cross(this.direction,this.up,this.right),A(this)};var ge=new t,ye=new _,Ce=new _,Ee=new g,Se=new v,we=new i,Te=new t,be=new t,xe=new t,Pe={destination:void 0,orientation:{direction:void 0,up:void 0,heading:void 0,pitch:void 0,roll:void 0},endTransform:void 0};ie.prototype.setView=function(e){e=n(e,n.EMPTY_OBJECT);var r=n(e.orientation,n.EMPTY_OBJECT),i=Pe,a=i.orientation;if(o(e.heading)||o(e.pitch)||o(e.roll)?(s("Camera.setView options","options.heading/pitch/roll has been moved to options.orientation.heading/pitch/roll."),a.heading=n(e.heading,this.heading),a.pitch=n(e.pitch,this.pitch),a.roll=n(e.roll,this.roll)):(a.heading=r.heading,a.pitch=r.pitch,a.roll=r.roll,a.direction=r.direction,a.up=r.up),o(e.position))s("Camera.setView options","options.position has been renamed to options.destination."),e.destination=e.position;else if(o(e.positionCartographic)){s("Camera.setView options","options.positionCartographic has been deprecated. Convert to a Cartesian3 and use options.position instead.");var l=this._projection,u=l.ellipsoid;e.destination=u.cartographicToCartesian(e.positionCartographic,ge)}else i.destination=e.destination;i.endTransform=e.endTransform,e=i,r=a;var c=this._mode;if(c!==T.MORPHING){o(e.endTransform)&&this._setTransform(e.endTransform);var h=!0,d=n(e.destination,t.clone(this.positionWC,ge));o(d)&&o(d.west)&&(d=this.getRectangleCameraCoordinates(d,ge),h=!1),o(r.direction)&&(r=L(this,d,r,Pe.orientation));var p=n(r.heading,0),m=n(r.pitch,-f.PI_OVER_TWO),v=n(r.roll,0);c===T.SCENE3D?R(this,d,p,m,v):c===T.SCENE2D?N(this,d,p,h):O(this,d,p,m,v,h)}},ie.prototype.worldToCameraCoordinates=function(e,t){return o(t)||(t=new r),A(this),_.multiplyByVector(this._actualInvTransform,e,t)},ie.prototype.worldToCameraCoordinatesPoint=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPoint(this._actualInvTransform,e,r)},ie.prototype.worldToCameraCoordinatesVector=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPointAsVector(this._actualInvTransform,e,r)},ie.prototype.cameraToWorldCoordinates=function(e,t){return o(t)||(t=new r),A(this),_.multiplyByVector(this._actualTransform,e,t)},ie.prototype.cameraToWorldCoordinatesPoint=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPoint(this._actualTransform,e,r)},ie.prototype.cameraToWorldCoordinatesVector=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPointAsVector(this._actualTransform,e,r)};var Ae=new t;ie.prototype.move=function(e,r){var i=this.position;t.multiplyByScalar(e,r,Ae),t.add(i,Ae,i),this._mode===T.SCENE2D&&F(this,i)},ie.prototype.moveForward=function(e){e=n(e,this.defaultMoveAmount),this.move(this.direction,e)},ie.prototype.moveBackward=function(e){e=n(e,this.defaultMoveAmount),this.move(this.direction,-e)},ie.prototype.moveUp=function(e){e=n(e,this.defaultMoveAmount),this.move(this.up,e)},ie.prototype.moveDown=function(e){e=n(e,this.defaultMoveAmount),this.move(this.up,-e)},ie.prototype.moveRight=function(e){e=n(e,this.defaultMoveAmount),this.move(this.right,e)},ie.prototype.moveLeft=function(e){e=n(e,this.defaultMoveAmount),this.move(this.right,-e)},ie.prototype.lookLeft=function(e){e=n(e,this.defaultLookAmount),this.look(this.up,-e)},ie.prototype.lookRight=function(e){e=n(e,this.defaultLookAmount),this.look(this.up,e)},ie.prototype.lookUp=function(e){e=n(e,this.defaultLookAmount),this.look(this.right,-e)},ie.prototype.lookDown=function(e){e=n(e,this.defaultLookAmount),this.look(this.right,e)};var Ie=new g,Me=new v;ie.prototype.look=function(e,t){var r=n(t,this.defaultLookAmount),i=g.fromAxisAngle(e,-r,Ie),o=v.fromQuaternion(i,Me),a=this.direction,s=this.up,l=this.right;v.multiplyByVector(o,a,a),v.multiplyByVector(o,s,s),v.multiplyByVector(o,l,l)},ie.prototype.twistLeft=function(e){e=n(e,this.defaultLookAmount),this.look(this.direction,e)},ie.prototype.twistRight=function(e){e=n(e,this.defaultLookAmount),this.look(this.direction,-e)};var De=new g,Re=new v;ie.prototype.rotate=function(e,r){ +var i=n(r,this.defaultRotateAmount),o=g.fromAxisAngle(e,-i,De),a=v.fromQuaternion(o,Re);v.multiplyByVector(a,this.position,this.position),v.multiplyByVector(a,this.direction,this.direction),v.multiplyByVector(a,this.up,this.up),t.cross(this.direction,this.up,this.right),t.cross(this.right,this.direction,this.up)},ie.prototype.rotateDown=function(e){e=n(e,this.defaultRotateAmount),B(this,e)},ie.prototype.rotateUp=function(e){e=n(e,this.defaultRotateAmount),B(this,-e)};var Oe=new t,Ne=new t,Le=new t,Fe=new t;ie.prototype.rotateRight=function(e){e=n(e,this.defaultRotateAmount),V(this,-e)},ie.prototype.rotateLeft=function(e){e=n(e,this.defaultRotateAmount),V(this,e)},ie.prototype.zoomIn=function(e){e=n(e,this.defaultZoomAmount),this._mode===T.SCENE2D?z(this,e):k(this,e)},ie.prototype.zoomOut=function(e){e=n(e,this.defaultZoomAmount),this._mode===T.SCENE2D?z(this,-e):k(this,-e)},ie.prototype.getMagnitude=function(){return this._mode===T.SCENE3D?t.magnitude(this.position):this._mode===T.COLUMBUS_VIEW?Math.abs(this.position.z):this._mode===T.SCENE2D?Math.max(this.frustum.right-this.frustum.left,this.frustum.top-this.frustum.bottom):void 0};var Be=new _;new _;ie.prototype.lookAt=function(e,t){var r=E.eastNorthUpToFixedFrame(e,c.WGS84,Be);this.lookAtTransform(r,t)};var Ve=new t,ze=new g,ke=new g,Ue=new v;ie.prototype.lookAtTransform=function(r,i){if(this._setTransform(r),o(i)){var n;if(n=o(i.heading)?U(i.heading,i.pitch,i.range):i,this._mode===T.SCENE2D){e.clone(e.ZERO,this.position),t.negate(n,this.up),this.up.z=0,t.magnitudeSquared(this.up)=i+Math.PI;)r-=l;for(;r0||e}}}),_.prototype.isMoving=function(e,t){var r=c(e,t);return!this._update[r]},_.prototype.getMovement=function(e,t){var r=c(e,t),i=this._movement[r];return i},_.prototype.getLastMovement=function(e,t){var r=c(e,t),i=this._lastMovement[r];return i.valid?i:void 0},_.prototype.isButtonDown=function(e,t){var r=c(e,t);return this._isDown[r]},_.prototype.getStartMousePosition=function(e,t){if(e===u.WHEEL||e===u.PINCH)return this._currentMousePosition;var r=c(e,t);return this._eventStartPosition[r]},_.prototype.getButtonPressTime=function(e,t){var r=c(e,t);return this._pressTime[r]},_.prototype.getButtonReleaseTime=function(e,t){var r=c(e,t);return this._releaseTime[r]},_.prototype.reset=function(){for(var e in this._update)this._update.hasOwnProperty(e)&&(this._update[e]=!0)},_.prototype.isDestroyed=function(){return!1},_.prototype.destroy=function(){return this._eventHandler=this._eventHandler&&this._eventHandler.destroy(),i(this)},_}),r("Scene/CreditDisplay",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError"],function(e,t,r,i,n){"use strict";function o(e,t,i){if(!r(e.element)){var n=e.text,o=e.link,a=document.createElement("span");if(e.hasLink()){var s=document.createElement("a");s.textContent=n,s.href=o,s.target="_blank",a.appendChild(s)}else a.textContent=n;a.className="cesium-credit-text",e.element=a}if(t.hasChildNodes()){var l=document.createElement("span");l.textContent=i,l.className="cesium-credit-delimiter",t.appendChild(l)}t.appendChild(e.element)}function a(e,t){if(!r(e.element)){var i=e.text,n=e.link,o=document.createElement("span"),a=document.createElement("img");if(a.src=e.imageUrl,a.style["vertical-align"]="bottom",r(i)&&(a.alt=i,a.title=i),e.hasLink()){var s=document.createElement("a");s.appendChild(a),s.href=n,s.target="_blank",o.appendChild(s)}else o.appendChild(a);o.className="cesium-credit-image",e.element=o}t.appendChild(e.element)}function s(t,r){for(var i=t.length,n=0;i>n;n++){var o=t[n];if(e.equals(o,r))return!0}return!1}function l(e){var t=e.element;if(r(t)){var i=t.parentNode;if(!e.hasImage()){var n=t.previousSibling;null===n&&(n=t.nextSibling),null!==n&&i.removeChild(n)}i.removeChild(t)}}function u(e,t){var i,n,a,s=e._displayedCredits.textCredits;for(i=0;i= 0.0) {\nt1 = (-b - sqrt(discriminant)) * 0.5;\nt2 = (-b + sqrt(discriminant)) * 0.5;\n}\nif (t1 < 0.0 && t2 < 0.0) {\ndiscard;\n}\nfloat t = min(t1, t2);\nif (t < 0.0) {\nt = 0.0;\n}\nczm_ellipsoid ellipsoid = czm_ellipsoidNew(ellipsoidCenter, u_radii);\nczm_ray ray = czm_ray(t * direction, direction);\nczm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\nif (czm_isEmpty(intersection))\n{\ndiscard;\n}\nvec4 outsideFaceColor = (intersection.start != 0.0) ? computeEllipsoidColor(ray, intersection.start, 1.0) : vec4(0.0);\nvec4 insideFaceColor = (outsideFaceColor.a < 1.0) ? computeEllipsoidColor(ray, intersection.stop, -1.0) : vec4(0.0);\ngl_FragColor = mix(insideFaceColor, outsideFaceColor, outsideFaceColor.a);\ngl_FragColor.a = 1.0 - (1.0 - insideFaceColor.a) * (1.0 - outsideFaceColor.a);\n#ifdef WRITE_DEPTH\n#ifdef GL_EXT_frag_depth\nt = (intersection.start != 0.0) ? intersection.start : intersection.stop;\nvec3 positionEC = czm_pointAlongRay(ray, t);\nvec4 positionCC = czm_projection * vec4(positionEC, 1.0);\nfloat z = positionCC.z / positionCC.w;\nfloat n = czm_depthRange.near;\nfloat f = czm_depthRange.far;\ngl_FragDepthEXT = (z * (f - n) + f + n) * 0.5;\n#endif\n#endif\n}\n"}),r("Shaders/EllipsoidVS",[],function(){"use strict";return"attribute vec3 position;\nuniform vec3 u_radii;\nvarying vec3 v_positionEC;\nvoid main()\n{\nvec4 p = vec4(u_radii * position, 1.0);\nv_positionEC = (czm_modelView * p).xyz;\ngl_Position = czm_modelViewProjection * p;\ngl_Position.z = clamp(gl_Position.z, czm_depthRange.near, czm_depthRange.far);\n}\n"}),r("Scene/EllipsoidPrimitive",["../Core/BoundingSphere","../Core/BoxGeometry","../Core/Cartesian3","../Core/combine","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Matrix4","../Core/VertexFormat","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../Shaders/EllipsoidFS","../Shaders/EllipsoidVS","./BlendingState","./CullFace","./Material","./Pass","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";function w(e){var i=e.cache.ellipsoidPrimitive_vertexArray;if(o(i))return i;var n=t.createGeometry(t.fromDimensions({dimensions:new r(2,2,2),vertexFormat:u.POSITION_ONLY}));return i=f.fromGeometry({context:e,geometry:n,attributeLocations:T,bufferUsage:c.STATIC_DRAW,interleave:!0}),e.cache.ellipsoidPrimitive_vertexArray=i,i}var T={position:0},b=function(t){t=n(t,n.EMPTY_OBJECT),this.center=r.clone(n(t.center,r.ZERO)),this._center=new r,this.radii=r.clone(t.radii),this._radii=new r,this._oneOverEllipsoidRadiiSquared=new r,this._boundingSphere=new e,this.modelMatrix=l.clone(n(t.modelMatrix,l.IDENTITY)),this._modelMatrix=new l,this._computedModelMatrix=new l,this.show=n(t.show,!0),this.material=n(t.material,C.fromType(C.ColorType)),this._material=void 0,this._translucent=void 0,this.id=t.id,this._id=void 0,this.debugShowBoundingVolume=n(t.debugShowBoundingVolume,!1),this.onlySunLighting=n(t.onlySunLighting,!1),this._onlySunLighting=!1,this._depthTestEnabled=n(t.depthTestEnabled,!0),this._sp=void 0,this._rs=void 0,this._va=void 0,this._pickSP=void 0,this._pickId=void 0,this._colorCommand=new h({owner:n(t._owner,this)}),this._pickCommand=new h({owner:n(t._owner,this)});var i=this;this._uniforms={u_radii:function(){return i.radii},u_oneOverEllipsoidRadiiSquared:function(){return i._oneOverEllipsoidRadiiSquared}},this._pickUniforms={czm_pickColor:function(){return i._pickId.color}}};return b.prototype.update=function(t){if(this.show&&t.mode===S.SCENE3D&&o(this.center)&&o(this.radii)){var n=t.context,a=this.material.isTranslucent(),s=this._translucent!==a;(!o(this._rs)||s)&&(this._translucent=a,this._rs=d.fromCache({cull:{enabled:!0,face:y.FRONT},depthTest:{enabled:this._depthTestEnabled},depthMask:!a&&n.fragmentDepth,blending:a?g.ALPHA_BLEND:void 0})),o(this._va)||(this._va=w(n));var u=!1,c=this.radii;if(!r.equals(this._radii,c)){r.clone(c,this._radii);var h=this._oneOverEllipsoidRadiiSquared;h.x=1/(c.x*c.x),h.y=1/(c.y*c.y),h.z=1/(c.z*c.z),u=!0}l.equals(this.modelMatrix,this._modelMatrix)&&r.equals(this.center,this._center)||(l.clone(this.modelMatrix,this._modelMatrix),r.clone(this.center,this._center),l.multiplyByTranslation(this.modelMatrix,this.center,this._computedModelMatrix),u=!0),u&&(r.clone(r.ZERO,this._boundingSphere.center),this._boundingSphere.radius=r.maximumComponent(c),e.transform(this._boundingSphere,this._computedModelMatrix,this._boundingSphere));var f=this._material!==this.material;this._material=this.material,this._material.update(n);var C=this.onlySunLighting!==this._onlySunLighting;this._onlySunLighting=this.onlySunLighting;var b,x=this._colorCommand;(f||C||s)&&(b=new m({sources:[this.material.shaderSource,v]}),this.onlySunLighting&&b.defines.push("ONLY_SUN_LIGHTING"),!a&&n.fragmentDepth&&b.defines.push("WRITE_DEPTH"),this._sp=p.replaceCache({context:n,shaderProgram:this._sp,vertexShaderSource:_,fragmentShaderSource:b,attributeLocations:T}),x.vertexArray=this._va,x.renderState=this._rs,x.shaderProgram=this._sp,x.uniformMap=i(this._uniforms,this.material._uniforms),x.executeInClosestFrustum=a);var P=t.commandList,A=t.passes;if(A.render&&(x.boundingVolume=this._boundingSphere,x.debugShowBoundingVolume=this.debugShowBoundingVolume,x.modelMatrix=this._computedModelMatrix,x.pass=a?E.TRANSLUCENT:E.OPAQUE,P.push(x)),A.pick){var I=this._pickCommand;o(this._pickId)&&this._id===this.id||(this._id=this.id,this._pickId=this._pickId&&this._pickId.destroy(),this._pickId=n.createPickId({primitive:this,id:this.id})),(f||C||!o(this._pickSP))&&(b=new m({sources:[this.material.shaderSource,v],pickColorQualifier:"uniform"}),this.onlySunLighting&&b.defines.push("ONLY_SUN_LIGHTING"),!a&&n.fragmentDepth&&b.defines.push("WRITE_DEPTH"),this._pickSP=p.replaceCache({context:n,shaderProgram:this._pickSP,vertexShaderSource:_,fragmentShaderSource:b,attributeLocations:T}),I.vertexArray=this._va,I.renderState=this._rs,I.shaderProgram=this._pickSP,I.uniformMap=i(i(this._uniforms,this._pickUniforms),this.material._uniforms),I.executeInClosestFrustum=a),I.boundingVolume=this._boundingSphere,I.modelMatrix=this._computedModelMatrix,I.pass=a?E.TRANSLUCENT:E.OPAQUE,P.push(I)}}},b.prototype.isDestroyed=function(){return!1},b.prototype.destroy=function(){return this._sp=this._sp&&this._sp.destroy(),this._pickSP=this._pickSP&&this._pickSP.destroy(),this._pickId=this._pickId&&this._pickId.destroy(),a(this)},b}),r("Shaders/Appearances/EllipsoidSurfaceAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_st;\nvoid main()\n{\nczm_materialInput materialInput;\nvec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nmaterialInput.s = v_st.s;\nmaterialInput.st = v_st;\nmaterialInput.str = vec3(v_st, 0.0);\nmaterialInput.normalEC = normalEC;\nmaterialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\nvec3 positionToEyeEC = -v_positionEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/EllipsoidSurfaceAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec2 st;\nvarying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionMC = position3DHigh + position3DLow;\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_st = st;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Scene/EllipsoidSurfaceAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/EllipsoidSurfaceAppearanceFS","../Shaders/Appearances/EllipsoidSurfaceAppearanceVS","./Appearance","./Material"],function(e,t,r,i,n,o,a,s){ +"use strict";var l=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.translucent,!0),l=e(r.aboveGround,!1);this.material=t(r.material)?r.material:s.fromType(s.ColorType),this.translucent=e(r.translucent,!0),this._vertexShaderSource=e(r.vertexShaderSource,o),this._fragmentShaderSource=e(r.fragmentShaderSource,n),this._renderState=a.getDefaultRenderState(i,!l,r.renderState),this._closed=!1,this._flat=e(r.flat,!1),this._faceForward=e(r.faceForward,l),this._aboveGround=l};return r(l.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return l.VERTEX_FORMAT}},flat:{get:function(){return this._flat}},faceForward:{get:function(){return this._faceForward}},aboveGround:{get:function(){return this._aboveGround}}}),l.VERTEX_FORMAT=i.POSITION_AND_ST,l.prototype.getFragmentShaderSource=a.prototype.getFragmentShaderSource,l.prototype.isTranslucent=a.prototype.isTranslucent,l.prototype.getRenderState=a.prototype.getRenderState,l}),r("Shaders/PostProcessFilters/FXAA",[],function(){"use strict";return"#ifndef FXAA_PRESET\n#define FXAA_PRESET 3\n#endif\n#if (FXAA_PRESET == 3)\n#define FXAA_EDGE_THRESHOLD (1.0/8.0)\n#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n#define FXAA_SEARCH_STEPS 16\n#define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n#define FXAA_SUBPIX_CAP (3.0/4.0)\n#define FXAA_SUBPIX_TRIM (1.0/4.0)\n#endif\n#if (FXAA_PRESET == 4)\n#define FXAA_EDGE_THRESHOLD (1.0/8.0)\n#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n#define FXAA_SEARCH_STEPS 24\n#define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n#define FXAA_SUBPIX_CAP (3.0/4.0)\n#define FXAA_SUBPIX_TRIM (1.0/4.0)\n#endif\n#if (FXAA_PRESET == 5)\n#define FXAA_EDGE_THRESHOLD (1.0/8.0)\n#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n#define FXAA_SEARCH_STEPS 32\n#define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n#define FXAA_SUBPIX_CAP (3.0/4.0)\n#define FXAA_SUBPIX_TRIM (1.0/4.0)\n#endif\n#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))\nfloat FxaaLuma(vec3 rgb) {\nreturn rgb.y * (0.587/0.299) + rgb.x;\n}\nvec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) {\nreturn (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b);\n}\nvec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) {\nfloat x = pos.x + float(off.x) * rcpFrame.x;\nfloat y = pos.y + float(off.y) * rcpFrame.y;\nreturn texture2D(tex, vec2(x, y));\n}\nvec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame)\n{\nvec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz;\nvec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz;\nvec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz;\nvec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz;\nvec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz;\nfloat lumaN = FxaaLuma(rgbN);\nfloat lumaW = FxaaLuma(rgbW);\nfloat lumaM = FxaaLuma(rgbM);\nfloat lumaE = FxaaLuma(rgbE);\nfloat lumaS = FxaaLuma(rgbS);\nfloat rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));\nfloat rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));\nfloat range = rangeMax - rangeMin;\nif(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD))\n{\nreturn rgbM;\n}\nvec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS;\nfloat lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;\nfloat rangeL = abs(lumaL - lumaM);\nfloat blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE;\nblendL = min(FXAA_SUBPIX_CAP, blendL);\nvec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz;\nvec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz;\nvec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz;\nvec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz;\nrgbL += (rgbNW + rgbNE + rgbSW + rgbSE);\nrgbL *= vec3(1.0/9.0);\nfloat lumaNW = FxaaLuma(rgbNW);\nfloat lumaNE = FxaaLuma(rgbNE);\nfloat lumaSW = FxaaLuma(rgbSW);\nfloat lumaSE = FxaaLuma(rgbSE);\nfloat edgeVert =\nabs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) +\nabs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) +\nabs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE));\nfloat edgeHorz =\nabs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) +\nabs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) +\nabs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));\nbool horzSpan = edgeHorz >= edgeVert;\nfloat lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;\nif(!horzSpan)\n{\nlumaN = lumaW;\nlumaS = lumaE;\n}\nfloat gradientN = abs(lumaN - lumaM);\nfloat gradientS = abs(lumaS - lumaM);\nlumaN = (lumaN + lumaM) * 0.5;\nlumaS = (lumaS + lumaM) * 0.5;\nif (gradientN < gradientS)\n{\nlumaN = lumaS;\nlumaN = lumaS;\ngradientN = gradientS;\nlengthSign *= -1.0;\n}\nvec2 posN;\nposN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);\nposN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);\ngradientN *= FXAA_SEARCH_THRESHOLD;\nvec2 posP = posN;\nvec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);\nfloat lumaEndN = lumaN;\nfloat lumaEndP = lumaN;\nbool doneN = false;\nbool doneP = false;\nposN += offNP * vec2(-1.0, -1.0);\nposP += offNP * vec2( 1.0, 1.0);\nfor(int i = 0; i < FXAA_SEARCH_STEPS; i++) {\nif(!doneN)\n{\nlumaEndN = FxaaLuma(texture2D(tex, posN.xy).xyz);\n}\nif(!doneP)\n{\nlumaEndP = FxaaLuma(texture2D(tex, posP.xy).xyz);\n}\ndoneN = doneN || (abs(lumaEndN - lumaN) >= gradientN);\ndoneP = doneP || (abs(lumaEndP - lumaN) >= gradientN);\nif(doneN && doneP)\n{\nbreak;\n}\nif(!doneN)\n{\nposN -= offNP;\n}\nif(!doneP)\n{\nposP += offNP;\n}\n}\nfloat dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;\nfloat dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;\nbool directionN = dstN < dstP;\nlumaEndN = directionN ? lumaEndN : lumaEndP;\nif(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))\n{\nlengthSign = 0.0;\n}\nfloat spanLength = (dstP + dstN);\ndstN = directionN ? dstN : dstP;\nfloat subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign;\nvec3 rgbF = texture2D(tex, vec2(\npos.x + (horzSpan ? 0.0 : subPixelOffset),\npos.y + (horzSpan ? subPixelOffset : 0.0))).xyz;\nreturn FxaaLerp3(rgbL, rgbF, blendL);\n}\nuniform sampler2D u_texture;\nuniform vec2 u_step;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = vec4(FxaaPixelShader(v_textureCoordinates, u_texture, u_step), 1.0);\n}\n"}),r("Scene/FXAA",["../Core/Cartesian2","../Core/Color","../Core/defined","../Core/destroyObject","../Core/PixelFormat","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/Renderbuffer","../Renderer/RenderbufferFormat","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/FXAA"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e){e._fbo=e._fbo&&e._fbo.destroy(),e._texture=e._texture&&e._texture.destroy(),e._depthTexture=e._depthTexture&&e._depthTexture.destroy(),e._depthRenderbuffer=e._depthRenderbuffer&&e._depthRenderbuffer.destroy(),e._fbo=void 0,e._texture=void 0,e._depthTexture=void 0,e._depthRenderbuffer=void 0,r(e._command)&&(e._command.shaderProgram=e._command.shaderProgram&&e._command.shaderProgram.destroy(),e._command=void 0)}var m=function(e){this._texture=void 0,this._depthTexture=void 0,this._depthRenderbuffer=void 0,this._fbo=void 0,this._command=void 0;var r=new o({color:new t(0,0,0,0),depth:1,owner:this});this._clearCommand=r};return m.prototype.update=function(t){var i=t.drawingBufferWidth,o=t.drawingBufferHeight,p=this._texture,m=!r(p)||p.width!==i||p.height!==o;if(m&&(this._texture=this._texture&&this._texture.destroy(),this._depthTexture=this._depthTexture&&this._depthTexture.destroy(),this._depthRenderbuffer=this._depthRenderbuffer&&this._depthRenderbuffer.destroy(),this._texture=new h({context:t,width:i,height:o,pixelFormat:n.RGBA,pixelDatatype:s.UNSIGNED_BYTE}),t.depthTexture?this._depthTexture=new h({context:t,width:i,height:o,pixelFormat:n.DEPTH_COMPONENT,pixelDatatype:s.UNSIGNED_SHORT}):this._depthRenderbuffer=new l({context:t,width:i,height:o,format:u.DEPTH_COMPONENT16})),(!r(this._fbo)||m)&&(this._fbo=this._fbo&&this._fbo.destroy(),this._fbo=new a({context:t,colorTextures:[this._texture],depthTexture:this._depthTexture,depthRenderbuffer:this._depthRenderbuffer,destroyAttachments:!1})),r(this._command)||(this._command=t.createViewportQuadCommand(d,{renderState:c.fromCache(),owner:this})),m){var f=this,v=new e(1/this._texture.width,1/this._texture.height);this._command.uniformMap={u_texture:function(){return f._texture},u_step:function(){return v}}}},m.prototype.execute=function(e,t){this._command.execute(e,t)},m.prototype.clear=function(e,r,i){var n=r.framebuffer;r.framebuffer=this._fbo,t.clone(i,this._clearCommand.color),this._clearCommand.execute(e,r),r.framebuffer=n},m.prototype.getColorFramebuffer=function(){return this._fbo},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return p(this),i(this)},m}),r("Scene/Fog",["../Core/Cartesian3","../Core/defined","../Core/Math","./SceneMode"],function(e,t,r,i){"use strict";function n(e){var t=a,r=t.length;if(et[r-1])return d=r-2;if(e>=t[d]){if(r>d+1&&ed+2&&e=0&&e>=t[d-1])return--d,d;var i;for(i=0;r-2>i&&!(e>=t[i]&&e8e5||o.mode!==i.SCENE3D)return void(o.fog.enabled=!1);var m=d.height,f=n(m),v=r.clamp((m-a[f])/(a[f+1]-a[f]),0,1),_=r.lerp(s[f],s[f+1],v),g=1e6*this.density,y=g/u*c;_=_*(g-y)*1e-6;var C=e.normalize(h.positionWC,p),E=r.clamp(e.dot(h.directionWC,C),0,1);_*=1-E,o.fog.density=_,o.fog.sse=this.screenSpaceErrorFactor}},o}),r("Scene/FrameRateMonitor",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/getTimestamp","../Core/TimeConstants"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t){if(!(e._pauseCount>0)){var r=a();if(e._needsQuietPeriod)e._needsQuietPeriod=!1,e._frameTimes.length=0,e._quietPeriodEndTime=r+e.quietPeriod/s.SECONDS_PER_MILLISECOND,e._warmupPeriodEndTime=e._quietPeriodEndTime+(e.warmupPeriod+e.samplingWindow)/s.SECONDS_PER_MILLISECOND;else if(r>=e._quietPeriodEndTime){e._frameTimes.push(r);var i=r-e.samplingWindow/s.SECONDS_PER_MILLISECOND;if(e._frameTimes.length>=2&&e._frameTimes[0]<=i){for(;e._frameTimes.length>=2&&e._frameTimes[1]e._warmupPeriodEndTime?e.minimumFrameRateAfterWarmup:e.minimumFrameRateDuringWarmup);n>o?e._frameRateIsLow||(e._frameRateIsLow=!0,e._needsQuietPeriod=!0,e.lowFrameRate.raiseEvent(e.scene,e._lastFramesPerSecond)):e._frameRateIsLow&&(e._frameRateIsLow=!1,e._needsQuietPeriod=!0,e.nominalFrameRate.raiseEvent(e.scene,e._lastFramesPerSecond))}}}}function u(e){document[e._hiddenPropertyName]?e.pause():e.unpause()}var c=function(r){function i(){u(n)}this._scene=r.scene,this.samplingWindow=e(r.samplingWindow,c.defaultSettings.samplingWindow),this.quietPeriod=e(r.quietPeriod,c.defaultSettings.quietPeriod),this.warmupPeriod=e(r.warmupPeriod,c.defaultSettings.warmupPeriod),this.minimumFrameRateDuringWarmup=e(r.minimumFrameRateDuringWarmup,c.defaultSettings.minimumFrameRateDuringWarmup),this.minimumFrameRateAfterWarmup=e(r.minimumFrameRateAfterWarmup,c.defaultSettings.minimumFrameRateAfterWarmup),this._lowFrameRate=new o,this._nominalFrameRate=new o,this._frameTimes=[],this._needsQuietPeriod=!0,this._quietPeriodEndTime=0,this._warmupPeriodEndTime=0,this._frameRateIsLow=!1,this._lastFramesPerSecond=void 0,this._pauseCount=0;var n=this;this._preRenderRemoveListener=this._scene.preRender.addEventListener(function(e,t){l(n,t)}),this._hiddenPropertyName=t(document.hidden)?"hidden":t(document.mozHidden)?"mozHidden":t(document.msHidden)?"msHidden":t(document.webkitHidden)?"webkitHidden":void 0;var a=t(document.hidden)?"visibilitychange":t(document.mozHidden)?"mozvisibilitychange":t(document.msHidden)?"msvisibilitychange":t(document.webkitHidden)?"webkitvisibilitychange":void 0;this._visibilityChangeRemoveListener=void 0,t(a)&&(document.addEventListener(a,i,!1),this._visibilityChangeRemoveListener=function(){document.removeEventListener(a,i,!1)})};return c.defaultSettings={samplingWindow:5,quietPeriod:2,warmupPeriod:5,minimumFrameRateDuringWarmup:4,minimumFrameRateAfterWarmup:8},c.fromScene=function(e){return(!t(e._frameRateMonitor)||e._frameRateMonitor.isDestroyed())&&(e._frameRateMonitor=new c({scene:e})),e._frameRateMonitor},r(c.prototype,{scene:{get:function(){return this._scene}},lowFrameRate:{get:function(){return this._lowFrameRate}},nominalFrameRate:{get:function(){return this._nominalFrameRate}},lastFramesPerSecond:{get:function(){return this._lastFramesPerSecond}}}),c.prototype.pause=function(){++this._pauseCount,1===this._pauseCount&&(this._frameTimes.length=0,this._lastFramesPerSecond=void 0)},c.prototype.unpause=function(){--this._pauseCount,this._pauseCount<=0&&(this._pauseCount=0,this._needsQuietPeriod=!0)},c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return this._preRenderRemoveListener(),t(this._visibilityChangeRemoveListener)&&this._visibilityChangeRemoveListener(),i(this)},c}),r("Scene/FrameState",["./SceneMode"],function(e){"use strict";var t=function(t,r){this.context=t,this.commandList=[],this.mode=e.SCENE3D,this.morphTime=e.getMorphTime(e.SCENE3D),this.frameNumber=0,this.time=void 0,this.mapProjection=void 0,this.camera=void 0,this.cullingVolume=void 0,this.occluder=void 0,this.passes={render:!1,pick:!1},this.creditDisplay=r,this.afterRender=[],this.scene3DOnly=!1,this.fog={enabled:!1,density:void 0,sse:void 0}};return t}),r("Scene/FrustumCommands",["../Core/defaultValue","./Pass"],function(e,t){"use strict";var r=function(r,i){this.near=e(r,0),this.far=e(i,0);for(var n=t.NUMBER_OF_PASSES,o=new Array(n),a=new Array(n),s=0;n>s;++s)o[s]=[],a[s]=0;this.commands=o,this.indices=a};return r}),r("Scene/GetFeatureInfoFormat",["../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/DeveloperError","../Core/RuntimeError","./ImageryLayerFeatureInfo"],function(e,t,r,i,n,o,a){"use strict";function s(t){for(var r=[],n=t.features,o=0;o1&&(t=r[1]);var i=new a;return i.name=t,i.description=e,i.data=e,[i]}var f=function(e,t,i){this.type=e,r(t)||("json"===e?t="application/json":"xml"===e?t="text/xml":"html"===e?t="text/html":"text"===e&&(t="text/plain")),this.format=t,r(i)||("json"===e?i=s:"xml"===e?i=l:"html"===e?i=m:"text"===e&&(i=m)),this.callback=i},v="http://www.mapinfo.com/mxp",_="http://www.esri.com/wms",g="http://www.opengis.net/wfs",y="http://www.opengis.net/gml",C=/\s*<\/body>/im,E=//im,S=/([\s\S]*)<\/title>/im;return f}),r("Shaders/GlobeFS",[],function(){"use strict";return"uniform vec4 u_initialColor;\n#if TEXTURE_UNITS > 0\nuniform sampler2D u_dayTextures[TEXTURE_UNITS];\nuniform vec4 u_dayTextureTranslationAndScale[TEXTURE_UNITS];\n#ifdef APPLY_ALPHA\nuniform float u_dayTextureAlpha[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_BRIGHTNESS\nuniform float u_dayTextureBrightness[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_CONTRAST\nuniform float u_dayTextureContrast[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_HUE\nuniform float u_dayTextureHue[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_SATURATION\nuniform float u_dayTextureSaturation[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_GAMMA\nuniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];\n#endif\nuniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];\n#endif\n#ifdef SHOW_REFLECTIVE_OCEAN\nuniform sampler2D u_waterMask;\nuniform vec4 u_waterMaskTranslationAndScale;\nuniform float u_zoomedOutOceanSpecularIntensity;\n#endif\n#ifdef SHOW_OCEAN_WAVES\nuniform sampler2D u_oceanNormalMap;\n#endif\n#ifdef ENABLE_DAYNIGHT_SHADING\nuniform vec2 u_lightingFadeDistance;\n#endif\nvarying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_textureCoordinates;\nvarying vec3 v_normalMC;\nvarying vec3 v_normalEC;\n#ifdef FOG\nvarying float v_distance;\nvarying vec3 v_rayleighColor;\nvarying vec3 v_mieColor;\n#endif\nvec4 sampleAndBlend(\nvec4 previousColor,\nsampler2D texture,\nvec2 tileTextureCoordinates,\nvec4 textureCoordinateRectangle,\nvec4 textureCoordinateTranslationAndScale,\nfloat textureAlpha,\nfloat textureBrightness,\nfloat textureContrast,\nfloat textureHue,\nfloat textureSaturation,\nfloat textureOneOverGamma)\n{\nvec2 alphaMultiplier = step(textureCoordinateRectangle.st, tileTextureCoordinates);\ntextureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;\nalphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates);\ntextureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;\nvec2 translation = textureCoordinateTranslationAndScale.xy;\nvec2 scale = textureCoordinateTranslationAndScale.zw;\nvec2 textureCoordinates = tileTextureCoordinates * scale + translation;\nvec4 value = texture2D(texture, textureCoordinates);\nvec3 color = value.rgb;\nfloat alpha = value.a;\n#ifdef APPLY_BRIGHTNESS\ncolor = mix(vec3(0.0), color, textureBrightness);\n#endif\n#ifdef APPLY_CONTRAST\ncolor = mix(vec3(0.5), color, textureContrast);\n#endif\n#ifdef APPLY_HUE\ncolor = czm_hue(color, textureHue);\n#endif\n#ifdef APPLY_SATURATION\ncolor = czm_saturation(color, textureSaturation);\n#endif\n#ifdef APPLY_GAMMA\ncolor = pow(color, vec3(textureOneOverGamma));\n#endif\nfloat sourceAlpha = alpha * textureAlpha;\nfloat outAlpha = mix(previousColor.a, 1.0, sourceAlpha);\nvec3 outColor = mix(previousColor.rgb * previousColor.a, color, sourceAlpha) / outAlpha;\nreturn vec4(outColor, outAlpha);\n}\nvec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates);\nvec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float specularMapValue);\nvoid main()\n{\nvec4 color = computeDayColor(u_initialColor, clamp(v_textureCoordinates, 0.0, 1.0));\n#ifdef SHOW_TILE_BOUNDARIES\nif (v_textureCoordinates.x < (1.0/256.0) || v_textureCoordinates.x > (255.0/256.0) ||\nv_textureCoordinates.y < (1.0/256.0) || v_textureCoordinates.y > (255.0/256.0))\n{\ncolor = vec4(1.0, 0.0, 0.0, 1.0);\n}\n#endif\n#if defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING)\nvec3 normalMC = normalize(czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\nvec3 normalEC = normalize(czm_normal3D * normalMC);\n#endif\n#ifdef SHOW_REFLECTIVE_OCEAN\nvec2 waterMaskTranslation = u_waterMaskTranslationAndScale.xy;\nvec2 waterMaskScale = u_waterMaskTranslationAndScale.zw;\nvec2 waterMaskTextureCoordinates = v_textureCoordinates * waterMaskScale + waterMaskTranslation;\nfloat mask = texture2D(u_waterMask, waterMaskTextureCoordinates).r;\nif (mask > 0.0)\n{\nmat3 enuToEye = czm_eastNorthUpToEyeCoordinates(v_positionMC, normalEC);\nvec2 ellipsoidTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC);\nvec2 ellipsoidFlippedTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC.zyx);\nvec2 textureCoordinates = mix(ellipsoidTextureCoordinates, ellipsoidFlippedTextureCoordinates, czm_morphTime * smoothstep(0.9, 0.95, normalMC.z));\ncolor = computeWaterColor(v_positionEC, textureCoordinates, enuToEye, color, mask);\n}\n#endif\n#ifdef ENABLE_VERTEX_LIGHTING\nfloat diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalize(v_normalEC)) * 0.9 + 0.3, 0.0, 1.0);\nvec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);\n#elif defined(ENABLE_DAYNIGHT_SHADING)\nfloat diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * 5.0 + 0.3, 0.0, 1.0);\nfloat cameraDist = length(czm_view[3]);\nfloat fadeOutDist = u_lightingFadeDistance.x;\nfloat fadeInDist = u_lightingFadeDistance.y;\nfloat t = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0);\ndiffuseIntensity = mix(1.0, diffuseIntensity, t);\nvec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);\n#else\nvec4 finalColor = color;\n#endif\n#ifdef FOG\nconst float fExposure = 2.0;\nvec3 fogColor = v_mieColor + finalColor.rgb * v_rayleighColor;\nfogColor = vec3(1.0) - exp(-fExposure * fogColor);\ngl_FragColor = vec4(czm_fog(v_distance, finalColor.rgb, fogColor), finalColor.a);\n#else\ngl_FragColor = finalColor;\n#endif\n}\n#ifdef SHOW_REFLECTIVE_OCEAN\nfloat waveFade(float edge0, float edge1, float x)\n{\nfloat y = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\nreturn pow(1.0 - y, 5.0);\n}\nfloat linearFade(float edge0, float edge1, float x)\n{\nreturn clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\nconst float oceanFrequencyLowAltitude = 825000.0;\nconst float oceanAnimationSpeedLowAltitude = 0.004;\nconst float oceanOneOverAmplitudeLowAltitude = 1.0 / 2.0;\nconst float oceanSpecularIntensity = 0.5;\nconst float oceanFrequencyHighAltitude = 125000.0;\nconst float oceanAnimationSpeedHighAltitude = 0.008;\nconst float oceanOneOverAmplitudeHighAltitude = 1.0 / 2.0;\nvec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float maskValue)\n{\nvec3 positionToEyeEC = -positionEyeCoordinates;\nfloat positionToEyeECLength = length(positionToEyeEC);\nvec3 normalizedpositionToEyeEC = normalize(normalize(positionToEyeEC));\nfloat waveIntensity = waveFade(70000.0, 1000000.0, positionToEyeECLength);\n#ifdef SHOW_OCEAN_WAVES\nfloat time = czm_frameNumber * oceanAnimationSpeedHighAltitude;\nvec4 noise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyHighAltitude, time, 0.0);\nvec3 normalTangentSpaceHighAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeHighAltitude);\ntime = czm_frameNumber * oceanAnimationSpeedLowAltitude;\nnoise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyLowAltitude, time, 0.0);\nvec3 normalTangentSpaceLowAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeLowAltitude);\nfloat highAltitudeFade = linearFade(0.0, 60000.0, positionToEyeECLength);\nfloat lowAltitudeFade = 1.0 - linearFade(20000.0, 60000.0, positionToEyeECLength);\nvec3 normalTangentSpace =\n(highAltitudeFade * normalTangentSpaceHighAltitude) +\n(lowAltitudeFade * normalTangentSpaceLowAltitude);\nnormalTangentSpace = normalize(normalTangentSpace);\nnormalTangentSpace.xy *= waveIntensity;\nnormalTangentSpace = normalize(normalTangentSpace);\n#else\nvec3 normalTangentSpace = vec3(0.0, 0.0, 1.0);\n#endif\nvec3 normalEC = enuToEye * normalTangentSpace;\nconst vec3 waveHighlightColor = vec3(0.3, 0.45, 0.6);\nfloat diffuseIntensity = czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * maskValue;\nvec3 diffuseHighlight = waveHighlightColor * diffuseIntensity;\n#ifdef SHOW_OCEAN_WAVES\nfloat tsPerturbationRatio = normalTangentSpace.z;\nvec3 nonDiffuseHighlight = mix(waveHighlightColor * 5.0 * (1.0 - tsPerturbationRatio), vec3(0.0), diffuseIntensity);\n#else\nvec3 nonDiffuseHighlight = vec3(0.0);\n#endif\nfloat specularIntensity = czm_getSpecular(czm_sunDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0) + 0.25 * czm_getSpecular(czm_moonDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0);\nfloat surfaceReflectance = mix(0.0, mix(u_zoomedOutOceanSpecularIntensity, oceanSpecularIntensity, waveIntensity), maskValue);\nfloat specular = specularIntensity * surfaceReflectance;\nreturn vec4(imageryColor.rgb + diffuseHighlight + nonDiffuseHighlight + specular, imageryColor.a);\n}\n#endif\n"}),r("Shaders/GlobeFSPole",[],function(){"use strict";return"uniform vec3 u_color;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nczm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\nvec3 direction = normalize(czm_windowToEyeCoordinates(gl_FragCoord).xyz);\nczm_ray ray = czm_ray(vec3(0.0), direction);\nczm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\nif (!czm_isEmpty(intersection))\n{\nvec3 positionEC = czm_pointAlongRay(ray, intersection.start);\nvec3 positionMC = (czm_inverseModelView * vec4(positionEC, 1.0)).xyz;\nvec3 normalMC = normalize(czm_geodeticSurfaceNormal(positionMC, vec3(0.0), vec3(1.0)));\nvec3 normalEC = normalize(czm_normal * normalMC);\nvec3 startDayColor = u_color;\ngl_FragColor = vec4(startDayColor, 1.0);\n}\nelse\n{\ndiscard;\n}\n}\n"}),r("Shaders/GlobeVS",[],function(){"use strict";return"attribute vec4 position3DAndHeight;\nattribute vec3 textureCoordAndEncodedNormals;\nuniform vec3 u_center3D;\nuniform mat4 u_modifiedModelView;\nuniform vec4 u_tileRectangle;\nuniform vec2 u_southAndNorthLatitude;\nuniform vec2 u_southMercatorYAndOneOverHeight;\nvarying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_textureCoordinates;\nvarying vec3 v_normalMC;\nvarying vec3 v_normalEC;\n#ifdef FOG\nvarying float v_distance;\nvarying vec3 v_mieColor;\nvarying vec3 v_rayleighColor;\n#endif\nvec4 getPosition(vec3 position3DWC);\nfloat get2DYPositionFraction();\nvec4 getPosition3DMode(vec3 position3DWC)\n{\nreturn czm_projection * (u_modifiedModelView * vec4(position3DAndHeight.xyz, 1.0));\n}\nfloat get2DMercatorYPositionFraction()\n{\nconst float maxTileWidth = 0.003068;\nfloat positionFraction = textureCoordAndEncodedNormals.y;\nfloat southLatitude = u_southAndNorthLatitude.x;\nfloat northLatitude = u_southAndNorthLatitude.y;\nif (northLatitude - southLatitude > maxTileWidth)\n{\nfloat southMercatorY = u_southMercatorYAndOneOverHeight.x;\nfloat oneOverMercatorHeight = u_southMercatorYAndOneOverHeight.y;\nfloat currentLatitude = mix(southLatitude, northLatitude, textureCoordAndEncodedNormals.y);\ncurrentLatitude = clamp(currentLatitude, -czm_webMercatorMaxLatitude, czm_webMercatorMaxLatitude);\npositionFraction = czm_latitudeToWebMercatorFraction(currentLatitude, southMercatorY, oneOverMercatorHeight);\n}\nreturn positionFraction;\n}\nfloat get2DGeographicYPositionFraction()\n{\nreturn textureCoordAndEncodedNormals.y;\n}\nvec4 getPositionPlanarEarth(vec3 position3DWC, float height2D)\n{\nfloat yPositionFraction = get2DYPositionFraction();\nvec4 rtcPosition2D = vec4(height2D, mix(u_tileRectangle.st, u_tileRectangle.pq, vec2(textureCoordAndEncodedNormals.x, yPositionFraction)), 1.0);\nreturn czm_projection * (u_modifiedModelView * rtcPosition2D);\n}\nvec4 getPosition2DMode(vec3 position3DWC)\n{\nreturn getPositionPlanarEarth(position3DWC, 0.0);\n}\nvec4 getPositionColumbusViewMode(vec3 position3DWC)\n{\nreturn getPositionPlanarEarth(position3DWC, position3DAndHeight.w);\n}\nvec4 getPositionMorphingMode(vec3 position3DWC)\n{\nfloat yPositionFraction = get2DYPositionFraction();\nvec4 position2DWC = vec4(0.0, mix(u_tileRectangle.st, u_tileRectangle.pq, vec2(textureCoordAndEncodedNormals.x, yPositionFraction)), 1.0);\nvec4 morphPosition = czm_columbusViewMorph(position2DWC, vec4(position3DWC, 1.0), czm_morphTime);\nreturn czm_modelViewProjection * morphPosition;\n}\nvoid main()\n{\nvec3 position3DWC = position3DAndHeight.xyz + u_center3D;\ngl_Position = getPosition(position3DWC);\n#if defined(ENABLE_VERTEX_LIGHTING)\nv_positionEC = (czm_modelView3D * vec4(position3DWC, 1.0)).xyz;\nv_positionMC = position3DWC;\nfloat encodedNormal = textureCoordAndEncodedNormals.z;\nv_normalMC = czm_octDecode(encodedNormal);\nv_normalEC = czm_normal3D * v_normalMC;\n#elif defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING)\nv_positionEC = (czm_modelView3D * vec4(position3DWC, 1.0)).xyz;\nv_positionMC = position3DWC;\n#endif\nv_textureCoordinates = textureCoordAndEncodedNormals.xy;\n#ifdef FOG\nAtmosphereColor atmosColor = computeGroundAtmosphereFromSpace(position3DWC);\nv_mieColor = atmosColor.mie;\nv_rayleighColor = atmosColor.rayleigh;\nv_distance = length((czm_modelView3D * vec4(position3DWC, 1.0)).xyz);\n#endif\n}\n"}),r("Shaders/GlobeVSPole",[],function(){"use strict";return"attribute vec4 position;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nfloat x = (position.x - czm_viewport.x) / czm_viewport.z;\nfloat y = (position.y - czm_viewport.y) / czm_viewport.w;\nv_textureCoordinates = vec2(x, y);\ngl_Position = czm_viewportOrthographic * position;\n}\n"}),r("Shaders/GroundAtmosphere",[],function(){"use strict";return"const float fInnerRadius = 6378137.0;\nconst float fOuterRadius = 6378137.0 * 1.025;\nconst float fOuterRadius2 = fOuterRadius * fOuterRadius;\nconst float Kr = 0.0025;\nconst float Km = 0.0015;\nconst float ESun = 15.0;\nconst float fKrESun = Kr * ESun;\nconst float fKmESun = Km * ESun;\nconst float fKr4PI = Kr * 4.0 * czm_pi;\nconst float fKm4PI = Km * 4.0 * czm_pi;\nconst float fScale = 1.0 / (fOuterRadius - fInnerRadius);\nconst float fScaleDepth = 0.25;\nconst float fScaleOverScaleDepth = fScale / fScaleDepth;\nstruct AtmosphereColor\n{\nvec3 mie;\nvec3 rayleigh;\n};\nconst int nSamples = 2;\nconst float fSamples = 2.0;\nfloat scale(float fCos)\n{\nfloat x = 1.0 - fCos;\nreturn fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n}\nAtmosphereColor computeGroundAtmosphereFromSpace(vec3 v3Pos)\n{\nvec3 v3InvWavelength = vec3(1.0 / pow(0.650, 4.0), 1.0 / pow(0.570, 4.0), 1.0 / pow(0.475, 4.0));\nvec3 v3Ray = v3Pos - czm_viewerPositionWC;\nfloat fFar = length(v3Ray);\nv3Ray /= fFar;\nfloat fCameraHeight = length(czm_viewerPositionWC);\nfloat fCameraHeight2 = fCameraHeight * fCameraHeight;\nfloat B = 2.0 * length(czm_viewerPositionWC) * dot(normalize(czm_viewerPositionWC), v3Ray);\nfloat C = fCameraHeight2 - fOuterRadius2;\nfloat fDet = max(0.0, B*B - 4.0 * C);\nfloat fNear = 0.5 * (-B - sqrt(fDet));\nvec3 v3Start = czm_viewerPositionWC + v3Ray * fNear;\nfFar -= fNear;\nfloat fDepth = exp((fInnerRadius - fOuterRadius) / fScaleDepth);\nfloat fLightAngle = 1.0;\nfloat fCameraAngle = dot(-v3Ray, v3Pos) / length(v3Pos);\nfloat fCameraScale = scale(fCameraAngle);\nfloat fLightScale = scale(fLightAngle);\nfloat fCameraOffset = fDepth*fCameraScale;\nfloat fTemp = (fLightScale + fCameraScale);\nfloat fSampleLength = fFar / fSamples;\nfloat fScaledLength = fSampleLength * fScale;\nvec3 v3SampleRay = v3Ray * fSampleLength;\nvec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\nvec3 v3FrontColor = vec3(0.0);\nvec3 v3Attenuate = vec3(0.0);\nfor(int i=0; i<nSamples; i++)\n{\nfloat fHeight = length(v3SamplePoint);\nfloat fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\nfloat fScatter = fDepth*fTemp - fCameraOffset;\nv3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\nv3FrontColor += v3Attenuate * (fDepth * fScaledLength);\nv3SamplePoint += v3SampleRay;\n}\nAtmosphereColor color;\ncolor.mie = v3FrontColor * (v3InvWavelength * fKrESun + fKmESun);\ncolor.rayleigh = v3Attenuate;\nreturn color;\n}\n"; +}),r("Scene/terrainAttributeLocations",[],function(){"use strict";return{position3DAndHeight:0,textureCoordAndEncodedNormals:1}}),r("Scene/GlobeSurfaceShaderSet",["../Core/defined","../Core/destroyObject","../Renderer/ShaderProgram","../Scene/SceneMode","../Scene/terrainAttributeLocations"],function(e,t,r,i,n){"use strict";function o(e,t,r){this.numberOfDayTextures=e,this.flags=t,this.shaderProgram=r}function a(){this.baseVertexShaderSource=void 0,this.baseFragmentShaderSource=void 0,this._attributeLocations=n,this._shadersByTexturesFlags=[],this._pickShaderPrograms=[]}function s(e){var t,r="vec4 getPosition(vec3 position3DWC) { return getPosition3DMode(position3DWC); }",n="vec4 getPosition(vec3 position3DWC) { return getPosition2DMode(position3DWC); }",o="vec4 getPosition(vec3 position3DWC) { return getPositionColumbusViewMode(position3DWC); }",a="vec4 getPosition(vec3 position3DWC) { return getPositionMorphingMode(position3DWC); }";switch(e){case i.SCENE3D:t=r;break;case i.SCENE2D:t=n;break;case i.COLUMBUS_VIEW:t=o;break;case i.MORPHING:t=a}return t}function l(e){var t="float get2DYPositionFraction() { return get2DGeographicYPositionFraction(); }",r="float get2DYPositionFraction() { return get2DMercatorYPositionFraction(); }";return e?r:t}return a.prototype.getShaderProgram=function(t,i,n,a,u,c,h,d,p,m,f,v,_,g,y,C){var E=i|u<<2|c<<3|h<<4|d<<5|p<<6|m<<7|f<<8|v<<9|_<<10|g<<11|y<<12|C<<13,S=n.surfaceShader;if(e(S)&&S.numberOfDayTextures===a&&S.flags===E)return S.shaderProgram;var w=this._shadersByTexturesFlags[a];if(e(w)||(w=this._shadersByTexturesFlags[a]=[]),S=w[E],!e(S)){var T=this.baseVertexShaderSource.clone(),b=this.baseFragmentShaderSource.clone();b.defines.push("TEXTURE_UNITS "+a),u&&b.defines.push("APPLY_BRIGHTNESS"),c&&b.defines.push("APPLY_CONTRAST"),h&&b.defines.push("APPLY_HUE"),d&&b.defines.push("APPLY_SATURATION"),p&&b.defines.push("APPLY_GAMMA"),m&&b.defines.push("APPLY_ALPHA"),f&&(b.defines.push("SHOW_REFLECTIVE_OCEAN"),T.defines.push("SHOW_REFLECTIVE_OCEAN")),v&&b.defines.push("SHOW_OCEAN_WAVES"),_&&(g?(T.defines.push("ENABLE_VERTEX_LIGHTING"),b.defines.push("ENABLE_VERTEX_LIGHTING")):(T.defines.push("ENABLE_DAYNIGHT_SHADING"),b.defines.push("ENABLE_DAYNIGHT_SHADING"))),C&&(T.defines.push("FOG"),b.defines.push("FOG"));for(var x=" vec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates)\n {\n vec4 color = initialColor;\n",P=0;a>P;++P)x+=" color = sampleAndBlend(\n color,\n u_dayTextures["+P+"],\n textureCoordinates,\n u_dayTextureTexCoordsRectangle["+P+"],\n u_dayTextureTranslationAndScale["+P+"],\n "+(m?"u_dayTextureAlpha["+P+"]":"1.0")+",\n "+(u?"u_dayTextureBrightness["+P+"]":"0.0")+",\n "+(c?"u_dayTextureContrast["+P+"]":"0.0")+",\n "+(h?"u_dayTextureHue["+P+"]":"0.0")+",\n "+(d?"u_dayTextureSaturation["+P+"]":"0.0")+",\n "+(p?"u_dayTextureOneOverGamma["+P+"]":"0.0")+"\n );\n";x+=" return color;\n }",b.sources.push(x),T.sources.push(s(i)),T.sources.push(l(y));var A=r.fromCache({context:t,vertexShaderSource:T,fragmentShaderSource:b,attributeLocations:this._attributeLocations});S=w[E]=new o(a,E,A)}return n.surfaceShader=S,S.shaderProgram},a.prototype.getPickShaderProgram=function(t,i,n){var o=i|n<<2,a=this._pickShaderPrograms[o];if(!e(a)){var u=this.baseVertexShaderSource.clone();u.sources.push(s(i)),u.sources.push(l(n));var c="void main()\n{\n gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n}\n";a=this._pickShaderPrograms[o]=r.fromCache({context:t,vertexShaderSource:u,fragmentShaderSource:c,attributeLocations:this._attributeLocations})}return a},a.prototype.destroy=function(){var r=this._shadersByTexturesFlags;for(var i in r)if(r.hasOwnProperty(i)){var n=r[i];if(!e(n))continue;for(var o in n)if(n.hasOwnProperty(o)){var a=n[o];e(a)&&a.shaderProgram.destroy()}}return t(this)},a}),r("Scene/ImageryState",["../Core/freezeObject"],function(e){"use strict";var t={UNLOADED:0,TRANSITIONING:1,RECEIVED:2,TEXTURE_LOADED:3,READY:4,FAILED:5,INVALID:6,PLACEHOLDER:7};return e(t)}),r("Scene/QuadtreeTileLoadState",["../Core/freezeObject"],function(e){"use strict";var t={START:0,LOADING:1,DONE:2,FAILED:3};return e(t)}),r("Scene/TerrainState",["../Core/freezeObject"],function(e){"use strict";var t={FAILED:0,UNLOADED:1,RECEIVING:2,RECEIVED:3,TRANSFORMING:4,TRANSFORMED:5,READY:6};return e(t)}),r("Scene/TileTerrain",["../Core/BoundingSphere","../Core/Cartesian3","../Core/ComponentDatatype","../Core/defined","../Core/DeveloperError","../Core/IndexDatatype","../Core/OrientedBoundingBox","../Core/TileProviderError","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/VertexArray","../ThirdParty/when","./terrainAttributeLocations","./TerrainState"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t,r,n,o){function a(t){e.data=t,e.state=p.RECEIVED}function l(){e.state=p.FAILED;var i="Failed to obtain terrain tile X: "+r+" Y: "+n+" Level: "+o+".";t._requestError=s.handleError(t._requestError,t,t.errorEvent,i,r,n,o,u)}function u(){e.data=t.requestTileGeometry(r,n,o),i(e.data)?(e.state=p.RECEIVING,h(e.data,a,l)):e.state=p.UNLOADED}u()}function f(e,t,r,n,o,a){var s=r.tilingScheme,l=e.data,u=l.createMesh(s,n,o,a);i(u)&&(e.state=p.TRANSFORMING,h(u,function(t){e.mesh=t,e.state=p.TRANSFORMED},function(){e.state=p.FAILED}))}function v(e,t,n,a,s,h){var m,f,v=r.FLOAT,_=e.mesh.vertices,g=l.createVertexBuffer({context:t,typedArray:_,usage:u.STATIC_DRAW});n.hasVertexNormals?(m=7*r.getSizeInBytes(v),f=3):(m=6*r.getSizeInBytes(v),f=2);var y=4,C=[{index:d.position3DAndHeight,vertexBuffer:g,componentDatatype:v,componentsPerAttribute:y,offsetInBytes:0,strideInBytes:m},{index:d.textureCoordAndEncodedNormals,vertexBuffer:g,componentDatatype:v,componentsPerAttribute:f,offsetInBytes:y*r.getSizeInBytes(v),strideInBytes:m}],E=e.mesh.indices.indexBuffers||{},S=E[t.id];if(!i(S)||S.isDestroyed()){var w=e.mesh.indices,T=2===w.BYTES_PER_ELEMENT?o.UNSIGNED_SHORT:o.UNSIGNED_INT;S=l.createIndexBuffer({context:t,typedArray:w,usage:u.STATIC_DRAW,indexDatatype:T}),S.vertexArrayDestroyable=!1,S.referenceCount=1,E[t.id]=S,e.mesh.indices.indexBuffers=E}else++S.referenceCount;e.vertexArray=new c({context:t,attributes:C,indexBuffer:S}),e.state=p.READY}var _=function(e){this.state=p.UNLOADED,this.data=void 0,this.mesh=void 0,this.vertexArray=void 0,this.upsampleDetails=e};return _.prototype.freeResources=function(){if(this.state=p.UNLOADED,this.data=void 0,this.mesh=void 0,i(this.vertexArray)){var e=this.vertexArray.indexBuffer;this.vertexArray.destroy(),this.vertexArray=void 0,!e.isDestroyed()&&i(e.referenceCount)&&(--e.referenceCount,0===e.referenceCount&&e.destroy())}},_.prototype.publishToTile=function(r){var i=r.data,n=this.mesh;t.clone(n.center,i.center),i.minimumHeight=n.minimumHeight,i.maximumHeight=n.maximumHeight,i.boundingSphere3D=e.clone(n.boundingSphere3D,i.boundingSphere3D),i.orientedBoundingBox=a.clone(n.orientedBoundingBox,i.orientedBoundingBox),r.data.occludeePointInScaledSpace=t.clone(n.occludeePointInScaledSpace,i.occludeePointInScaledSpace),i.freeVertexArray(),i.vertexArray=this.vertexArray,this.vertexArray=void 0},_.prototype.processLoadStateMachine=function(e,t,r,i,n){this.state===p.UNLOADED&&m(this,t,r,i,n),this.state===p.RECEIVED&&f(this,e,t,r,i,n),this.state===p.TRANSFORMED&&v(this,e,t,r,i,n)},_.prototype.processUpsampleStateMachine=function(e,t,r,n,o){if(this.state===p.UNLOADED){var a=this.upsampleDetails,s=a.data,l=a.x,u=a.y,c=a.level;if(this.data=s.upsample(t.tilingScheme,l,u,c,r,n,o),!i(this.data))return;this.state=p.RECEIVING;var d=this;h(this.data,function(e){d.data=e,d.state=p.RECEIVED},function(){d.state=p.FAILED})}this.state===p.RECEIVED&&f(this,e,t,r,n,o),this.state===p.TRANSFORMED&&v(this,e,t,r,n,o)},_}),r("Scene/GlobeSurfaceTile",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/IntersectionTests","../Core/PixelFormat","../Core/Rectangle","../Renderer/PixelDatatype","../Renderer/Sampler","../Renderer/Texture","../Renderer/TextureMagnificationFilter","../Renderer/TextureMinificationFilter","../Renderer/TextureWrap","./ImageryState","./QuadtreeTileLoadState","./SceneMode","./TerrainState","./TileTerrain"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";function E(e,r,i,n,a,s,l){if(t.unpack(n,s*a,l),t.add(e.center,l,l),o(r)&&r!==g.SCENE3D){var u=i.ellipsoid,c=u.cartesianToCartographic(l);i.project(c,l),t.fromElements(l.z,l.x,l.y,l)}return l}function S(e,r,i){var n=e.data,a=T(e);o(a)&&(n.upsampledTerrain=new C(a)),P(e,r)&&(n.loadedTerrain=new C);for(var s=0,l=i.length;l>s;++s){var c=i.get(s);c.show&&c._createTileImagerySkeletons(e,r)}var h=e.tilingScheme.ellipsoid,d=e.rectangle;h.cartographicToCartesian(u.southwest(d),n.southwestCornerCartesian),h.cartographicToCartesian(u.northeast(d),n.northeastCornerCartesian),k.longitude=d.west,k.latitude=.5*(d.south+d.north),k.height=0;var p=h.cartographicToCartesian(k,V),m=t.cross(p,t.UNIT_Z,F);t.normalize(m,n.westNormal),k.longitude=d.east;var f=h.cartographicToCartesian(k,z),v=t.cross(t.UNIT_Z,f,F);t.normalize(v,n.eastNormal);var _=h.geodeticSurfaceNormalCartographic(u.southeast(d),B),g=t.subtract(p,f,F),y=t.cross(_,g,B);t.normalize(y,n.southNormal);var E=h.geodeticSurfaceNormalCartographic(u.northwest(d),B),S=t.cross(g,E,B);t.normalize(S,n.northNormal)}function w(e,t,r){var i=e.data,a=i.loadedTerrain,s=i.upsampledTerrain,l=!1;o(a)&&(a.processLoadStateMachine(t,r,e.x,e.y,e.level),a.state>=y.RECEIVED&&(i.terrainData!==a.data&&(i.terrainData=a.data,I(t,i),x(e)),l=!0),a.state===y.READY?(a.publishToTile(e),i.pickTerrain=n(i.loadedTerrain,i.upsampledTerrain),i.loadedTerrain=void 0,i.upsampledTerrain=void 0):a.state===y.FAILED&&(i.loadedTerrain=void 0)),!l&&o(s)&&(s.processUpsampleStateMachine(t,r,e.x,e.y,e.level),s.state>=y.RECEIVED&&i.terrainData!==s.data&&(i.terrainData=s.data,r.hasWaterMask&&M(e),b(e)),s.state===y.READY?(s.publishToTile(e),i.pickTerrain=i.upsampledTerrain,i.upsampledTerrain=void 0):s.state===y.FAILED&&(i.upsampledTerrain=void 0))}function T(e){for(var t=e.parent;o(t)&&o(t.data)&&!o(t.data.terrainData);)t=t.parent;return o(t)&&o(t.data)?{data:t.data.terrainData,x:t.x,y:t.y,level:t.level}:void 0}function b(e){var t=e.data;if(o(e._children))for(var r=0;4>r;++r){var i=e._children[r];if(i.state!==_.START){var n=i.data;if(o(n.terrainData)&&!n.terrainData.wasCreatedByUpsampling())continue;o(n.upsampledTerrain)&&n.upsampledTerrain.freeResources(),n.upsampledTerrain=new C({data:t.terrainData,x:e.x,y:e.y,level:e.level}),i.state=_.LOADING}}}function x(e){var t=e.data;if(o(e.children))for(var r=0;4>r;++r){var i=e.children[r];if(i.state!==_.START){var n=i.data;if(o(n.terrainData)&&!n.terrainData.wasCreatedByUpsampling())continue;o(n.upsampledTerrain)&&n.upsampledTerrain.freeResources(),n.upsampledTerrain=new C({data:t.terrainData,x:e.x,y:e.y,level:e.level}),t.terrainData.isChildAvailable(e.x,e.y,i.x,i.y)&&(o(n.loadedTerrain)||(n.loadedTerrain=new C)),i.state=_.LOADING}}}function P(e,t){var r=t.getTileDataAvailable(e.x,e.y,e.level);if(o(r))return r;var i=e.parent;return o(i)?o(i.data)&&o(i.data.terrainData)?i.data.terrainData.isChildAvailable(i.x,i.y,e.x,e.y):!1:!0}function A(e){var t=e.cache.tile_waterMaskData;if(!o(t)){var r=new d({context:e,pixelFormat:l.LUMINANCE,pixelDatatype:c.UNSIGNED_BYTE,source:{arrayBufferView:new Uint8Array([255]),width:1,height:1}});r.referenceCount=1;var i=new h({wrapS:f.CLAMP_TO_EDGE,wrapT:f.CLAMP_TO_EDGE,minificationFilter:m.LINEAR,magnificationFilter:p.LINEAR});t={allWaterTexture:r,sampler:i,destroy:function(){this.allWaterTexture.destroy()}},e.cache.tile_waterMaskData=t}return t}function I(e,t){var i=t.waterMaskTexture;o(i)&&(--i.referenceCount,0===i.referenceCount&&i.destroy(),t.waterMaskTexture=void 0);var n=t.terrainData.waterMask;if(o(n)){var a,s=A(e),u=n.length;if(1===u){if(0===n[0])return;a=s.allWaterTexture}else{var h=Math.sqrt(u);a=new d({context:e,pixelFormat:l.LUMINANCE,pixelDatatype:c.UNSIGNED_BYTE,source:{width:h,height:h,arrayBufferView:n},sampler:s.sampler}),a.referenceCount=0}++a.referenceCount,t.waterMaskTexture=a,r.fromElements(0,0,1,1,t.waterMaskTranslationAndScale)}}function M(e){for(var t=e.data,r=e.parent;o(r)&&!o(r.data.terrainData)||r.data.terrainData.wasCreatedByUpsampling();)r=r.parent;if(o(r)&&o(r.data.waterMaskTexture)){t.waterMaskTexture=r.data.waterMaskTexture,++t.waterMaskTexture.referenceCount;var i=r.rectangle,n=e.rectangle,a=n.width,s=n.height,l=a/i.width,u=s/i.height;t.waterMaskTranslationAndScale.x=l*(n.west-i.west)/a,t.waterMaskTranslationAndScale.y=u*(n.south-i.south)/s,t.waterMaskTranslationAndScale.z=l,t.waterMaskTranslationAndScale.w=u}}var D=function(){this.imagery=[],this.southwestCornerCartesian=new t,this.northeastCornerCartesian=new t,this.westNormal=new t,this.southNormal=new t,this.eastNormal=new t,this.northNormal=new t,this.waterMaskTexture=void 0,this.waterMaskTranslationAndScale=new r(0,0,1,1),this.terrainData=void 0,this.center=new t,this.vertexArray=void 0,this.minimumHeight=0,this.maximumHeight=0,this.boundingSphere3D=new e,this.boundingSphere2D=new e,this.orientedBoundingBox=void 0,this.occludeePointInScaledSpace=new t,this.loadedTerrain=void 0,this.upsampledTerrain=void 0,this.pickBoundingSphere=new e,this.pickTerrain=void 0,this.surfaceShader=void 0};D.irregularZoomLevels=!1,a(D.prototype,{eligibleForUnloading:{get:function(){for(var e=this.loadedTerrain,t=o(e)&&(e.state===y.RECEIVING||e.state===y.TRANSFORMING),r=this.upsampledTerrain,i=o(r)&&(r.state===y.RECEIVING||r.state===y.TRANSFORMING),n=!t&&!i,a=this.imagery,s=0,l=a.length;n&&l>s;++s){var u=a[s];n=!o(u.loadingImagery)||u.loadingImagery.state!==v.TRANSITIONING}return n}}});var R=new t,O=new t,N=new t,L=new t;D.prototype.pick=function(e,r,i,n,a){var l=this.pickTerrain;if(!o(l))return void 0;var u=l.mesh;if(!o(u))return void 0;for(var c=u.vertices,h=u.stride,d=u.indices,p=d.length,m=0;p>m;m+=3){var f=d[m],v=d[m+1],_=d[m+2],g=E(this,r,i,c,h,f,R),y=E(this,r,i,c,h,v,O),C=E(this,r,i,c,h,_,N),S=s.rayTriangle(e,g,y,C,n,L);if(o(S))return t.clone(S,a)}return void 0},D.prototype.freeResources=function(){o(this.waterMaskTexture)&&(--this.waterMaskTexture.referenceCount,0===this.waterMaskTexture.referenceCount&&this.waterMaskTexture.destroy(),this.waterMaskTexture=void 0),this.terrainData=void 0,o(this.loadedTerrain)&&(this.loadedTerrain.freeResources(),this.loadedTerrain=void 0),o(this.upsampledTerrain)&&(this.upsampledTerrain.freeResources(),this.upsampledTerrain=void 0),o(this.pickTerrain)&&(this.pickTerrain.freeResources(),this.pickTerrain=void 0);var e,t,r=this.imagery;for(e=0,t=r.length;t>e;++e)r[e].freeResources();this.imagery.length=0,this.freeVertexArray()},D.prototype.freeVertexArray=function(){var e;o(this.vertexArray)&&(e=this.vertexArray.indexBuffer,this.vertexArray=this.vertexArray.destroy(),!e.isDestroyed()&&o(e.referenceCount)&&(--e.referenceCount,0===e.referenceCount&&e.destroy())),o(this.wireframeVertexArray)&&(e=this.wireframeVertexArray.indexBuffer,this.wireframeVertexArray=this.wireframeVertexArray.destroy(),!e.isDestroyed()&&o(e.referenceCount)&&(--e.referenceCount,0===e.referenceCount&&e.destroy()))},D.processStateMachine=function(e,t,r,i,n){var a=e.data;o(a)||(a=e.data=new D),e.state===_.START&&(S(e,i,n),e.state=_.LOADING),e.state===_.LOADING&&w(e,t,i);for(var s=o(a.vertexArray),l=!o(a.loadedTerrain)&&!o(a.upsampledTerrain),u=D.irregularZoomLevels?!1:o(a.terrainData)&&a.terrainData.wasCreatedByUpsampling(),c=a.imagery,h=0,d=c.length;d>h;++h){var p=c[h];if(o(p.loadingImagery)){if(p.loadingImagery.state===v.PLACEHOLDER){var m=p.loadingImagery.imageryLayer;if(m.imageryProvider.ready){p.freeResources(),c.splice(h,1),m._createTileImagerySkeletons(e,i,h),--h,d=c.length;continue}u=!1}var f=p.processStateMachine(e,t,r);l=l&&f,s=s&&(f||o(p.readyImagery)),u=u&&o(p.loadingImagery)&&(p.loadingImagery.state===v.FAILED||p.loadingImagery.state===v.INVALID)}else u=!1}e.upsampledFromParent=u,h===d&&(s&&(e.renderable=!0),l&&(e.state=_.DONE))};var F=new t,B=new t,V=new t,z=new t,k=new i;return D}),r("Shaders/ReprojectWebMercatorFS",[],function(){"use strict";return"uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n"}),r("Shaders/ReprojectWebMercatorVS",[],function(){"use strict";return"attribute vec4 position;\nattribute float webMercatorT;\nuniform vec2 u_textureDimensions;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nv_textureCoordinates = vec2(position.x, webMercatorT);\ngl_Position = czm_viewportOrthographic * (position * vec4(u_textureDimensions, 1.0, 1.0));\n}\n"}),r("Scene/Imagery",["../Core/defined","../Core/destroyObject","./ImageryState"],function(e,t,r){"use strict";var i=function(t,i,n,o,a){if(this.imageryLayer=t,this.x=i,this.y=n,this.level=o,0!==o){var s=i/2|0,l=n/2|0,u=o-1;this.parent=t.getImageryFromCache(s,l,u)}if(this.state=r.UNLOADED,this.imageUrl=void 0,this.image=void 0,this.texture=void 0,this.credits=void 0,this.referenceCount=0,!e(a)&&t.imageryProvider.ready){var c=t.imageryProvider.tilingScheme;a=c.tileXYToRectangle(i,n,o)}this.rectangle=a};return i.createPlaceholder=function(e){var t=new i(e,0,0,0);return t.addReference(),t.state=r.PLACEHOLDER,t},i.prototype.addReference=function(){++this.referenceCount},i.prototype.releaseReference=function(){return--this.referenceCount,0===this.referenceCount?(this.imageryLayer.removeImageryFromCache(this),e(this.parent)&&this.parent.releaseReference(),e(this.image)&&e(this.image.destroy)&&this.image.destroy(),e(this.texture)&&this.texture.destroy(),t(this),0):this.referenceCount},i.prototype.processStateMachine=function(e,t){this.state===r.UNLOADED&&(this.state=r.TRANSITIONING,this.imageryLayer._requestImagery(this)),this.state===r.RECEIVED&&(this.state=r.TRANSITIONING,this.imageryLayer._createTexture(e,this)),this.state===r.TEXTURE_LOADED&&(this.state=r.TRANSITIONING,this.imageryLayer._reprojectTexture(e,t,this))},i}),r("Scene/TileImagery",["../Core/defined","./ImageryState"],function(e,t){"use strict";var r=function(e,t){this.readyImagery=void 0,this.loadingImagery=e,this.textureCoordinateRectangle=t,this.textureTranslationAndScale=void 0};return r.prototype.freeResources=function(){e(this.readyImagery)&&this.readyImagery.releaseReference(),e(this.loadingImagery)&&this.loadingImagery.releaseReference()},r.prototype.processStateMachine=function(r,i,n){var o=this.loadingImagery,a=o.imageryLayer,s=o.imageryLayer.imageryProvider;if(!e(s.getTileDataAvailable)||s.getTileDataAvailable(o.x,o.y,o.level)?o.processStateMachine(i,n):o.state=t.INVALID,o.state===t.READY)return e(this.readyImagery)&&this.readyImagery.releaseReference(),this.readyImagery=this.loadingImagery,this.loadingImagery=void 0,this.textureTranslationAndScale=a._calculateTextureTranslationAndScale(r,this),!0;for(var l,u=o.parent;e(u)&&u.state!==t.READY;)u.state!==t.FAILED&&u.state!==t.INVALID&&(l=l||u),u=u.parent;return this.readyImagery!==u&&(e(this.readyImagery)&&this.readyImagery.releaseReference(),this.readyImagery=u,e(u)&&(u.addReference(),this.textureTranslationAndScale=a._calculateTextureTranslationAndScale(r,this))),o.state===t.FAILED||o.state===t.INVALID?e(l)?(l.processStateMachine(i,n),!1):!0:!1},r}),r("Scene/ImageryLayer",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian4","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/FeatureDetection","../Core/GeographicTilingScheme","../Core/IndexDatatype","../Core/Math","../Core/PixelFormat","../Core/PrimitiveType","../Core/Rectangle","../Core/TerrainProvider","../Core/TileProviderError","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/ClearCommand","../Renderer/ComputeCommand","../Renderer/ContextLimits","../Renderer/DrawCommand","../Renderer/Framebuffer","../Renderer/MipmapHint","../Renderer/RenderState","../Renderer/Sampler","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/TextureMagnificationFilter","../Renderer/TextureMinificationFilter","../Renderer/TextureWrap","../Renderer/VertexArray","../Shaders/ReprojectWebMercatorFS","../Shaders/ReprojectWebMercatorVS","../ThirdParty/when","./Imagery","./ImageryState","./TileImagery"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k){"use strict";function U(e,t,r,i){if(d.isPowerOfTwo(i.width)&&d.isPowerOfTwo(i.height)){var n=t.cache.imageryLayer_mipmapSampler;if(!a(n)){var s=S.maximumTextureFilterAnisotropy;n=t.cache.imageryLayer_mipmapSampler=new P({wrapS:O.CLAMP_TO_EDGE,wrapT:O.CLAMP_TO_EDGE,minificationFilter:R.LINEAR_MIPMAP_LINEAR,magnificationFilter:D.LINEAR,maximumAnisotropy:Math.min(s,o(e._maximumAnisotropy,s))})}i.generateMipmap(b.NICEST),i.sampler=n}else{var l=t.cache.imageryLayer_nonMipmapSampler;a(l)||(l=t.cache.imageryLayer_nonMipmapSampler=new P({wrapS:O.CLAMP_TO_EDGE,wrapT:O.CLAMP_TO_EDGE,minificationFilter:R.LINEAR,magnificationFilter:D.LINEAR})),i.sampler=l}r.state=z.READY}function G(e,t,r){return JSON.stringify([e,t,r])}function W(e,t,r,i){var n=t.cache.imageryLayer_reproject;if(!a(n)){n=t.cache.imageryLayer_reproject={vertexArray:void 0,shaderProgram:void 0,sampler:void 0,destroy:function(){a(this.framebuffer)&&this.framebuffer.destroy(),a(this.vertexArray)&&this.vertexArray.destroy(),a(this.shaderProgram)&&this.shaderProgram.destroy()}};for(var o=new Float32Array(256),s=0,l=0;64>l;++l){var u=l/63;o[s++]=0,o[s++]=u,o[s++]=1,o[s++]=u}var c={position:0,webMercatorT:1},p=v.getRegularGridIndices(2,64),m=g.createIndexBuffer({context:t,typedArray:p,usage:y.STATIC_DRAW,indexDatatype:h.UNSIGNED_SHORT});n.vertexArray=new N({context:t,attributes:[{index:c.position,vertexBuffer:g.createVertexBuffer({context:t,typedArray:o,usage:y.STATIC_DRAW}),componentsPerAttribute:2},{index:c.webMercatorT,vertexBuffer:g.createVertexBuffer({context:t,sizeInBytes:512,usage:y.STREAM_DRAW}),componentsPerAttribute:1}],indexBuffer:m});var f=new I({sources:[F]});n.shaderProgram=A.fromCache({context:t,vertexShaderSource:f,fragmentShaderSource:L,attributeLocations:c}),n.sampler=new P({wrapS:O.CLAMP_TO_EDGE,wrapT:O.CLAMP_TO_EDGE,minificationFilter:R.LINEAR,magnificationFilter:D.LINEAR})}r.sampler=n.sampler;var _=r.width,C=r.height;Z.textureDimensions.x=_,Z.textureDimensions.y=C,Z.texture=r;var E=Math.sin(i.south),S=.5*Math.log((1+E)/(1-E));E=Math.sin(i.north);var w=.5*Math.log((1+E)/(1-E)),T=1/(w-S),x=new M({context:t,width:_,height:C,pixelFormat:r.pixelFormat,pixelDatatype:r.pixelDatatype,preMultiplyAlpha:r.preMultiplyAlpha});d.isPowerOfTwo(_)&&d.isPowerOfTwo(C)&&x.generateMipmap(b.NICEST);for(var B=i.south,V=i.north,z=K,k=0,U=0;64>U;++U){var G=U/63,W=d.lerp(B,V,G);E=Math.sin(W);var H=.5*Math.log((1+E)/(1-E)),q=(H-S)*T;z[k++]=q,z[k++]=q}n.vertexArray.getAttribute(1).vertexBuffer.copyFromArrayView(z),e.shaderProgram=n.shaderProgram,e.outputTexture=x,e.uniformMap=Z,e.vertexArray=n.vertexArray}function H(e,t,r){var i=e._imageryProvider,n=i.tilingScheme,o=n.ellipsoid,a=e._imageryProvider.tilingScheme instanceof c?1:Math.cos(r),s=n.rectangle,l=o.maximumRadius*s.width*a/(i.tileWidth*n.getNumberOfXTilesAtLevel(0)),u=l/t,h=Math.log(u)/Math.log(2),d=Math.round(h);return 0|d}var q=function J(e,t){this._imageryProvider=e,t=o(t,{}),this.alpha=o(t.alpha,o(e.defaultAlpha,1)),this.brightness=o(t.brightness,o(e.defaultBrightness,J.DEFAULT_BRIGHTNESS)),this.contrast=o(t.contrast,o(e.defaultContrast,J.DEFAULT_CONTRAST)),this.hue=o(t.hue,o(e.defaultHue,J.DEFAULT_HUE)),this.saturation=o(t.saturation,o(e.defaultSaturation,J.DEFAULT_SATURATION)),this.gamma=o(t.gamma,o(e.defaultGamma,J.DEFAULT_GAMMA)),this.show=o(t.show,!0),this._minimumTerrainLevel=t.minimumTerrainLevel,this._maximumTerrainLevel=t.maximumTerrainLevel,this._rectangle=o(t.rectangle,f.MAX_VALUE),this._maximumAnisotropy=t.maximumAnisotropy,this._imageryCache={},this._skeletonPlaceholder=new k(V.createPlaceholder(this)),this._show=!0,this._layerIndex=-1,this._isBaseLayer=!1,this._requestImageError=void 0};s(q.prototype,{imageryProvider:{get:function(){return this._imageryProvider}},rectangle:{get:function(){return this._rectangle}}}),q.DEFAULT_BRIGHTNESS=1,q.DEFAULT_CONTRAST=1,q.DEFAULT_HUE=0,q.DEFAULT_SATURATION=1,q.DEFAULT_GAMMA=1,q.prototype.isBaseLayer=function(){return this._isBaseLayer},q.prototype.isDestroyed=function(){return!1},q.prototype.destroy=function(){return l(this)};var j=new f,Y=new f,X=new f;q.prototype._createTileImagerySkeletons=function(e,t,i){var n=e.data;if(a(this._minimumTerrainLevel)&&e.level<this._minimumTerrainLevel)return!1;if(a(this._maximumTerrainLevel)&&e.level>this._maximumTerrainLevel)return!1;var o=this._imageryProvider;if(a(i)||(i=n.imagery.length),!o.ready)return this._skeletonPlaceholder.loadingImagery.addReference(),n.imagery.splice(i,0,this._skeletonPlaceholder),!0;var s=f.intersection(o.rectangle,this._rectangle,j),l=f.intersection(e.rectangle,s,Y);if(!a(l)){if(!this.isBaseLayer())return!1;var u=s,c=e.rectangle;l=Y,c.south>=u.north?l.north=l.south=u.north:c.north<=u.south?l.north=l.south=u.south:(l.south=Math.max(c.south,u.south),l.north=Math.min(c.north,u.north)),c.west>=u.east?l.west=l.east=u.east:c.east<=u.west?l.west=l.east=u.west:(l.west=Math.max(c.west,u.west),l.east=Math.min(c.east,u.east))}var h=0;l.south>0?h=l.south:l.north<0&&(h=l.north);var d=1,p=d*t.getLevelMaximumGeometricError(e.level),m=H(this,p,h);m=Math.max(0,m);var v=o.maximumLevel;if(m>v&&(m=v),a(o.minimumLevel)){var _=o.minimumLevel;_>m&&(m=_)}var g=o.tilingScheme,y=g.positionToTileXY(f.northwest(l),m),C=g.positionToTileXY(f.southeast(l),m),E=e.rectangle.height/512,S=e.rectangle.width/512,w=g.tileXYToRectangle(y.x,y.y,m);Math.abs(w.south-e.rectangle.north)<S&&y.y<C.y&&++y.y,Math.abs(w.east-e.rectangle.west)<E&&y.x<C.x&&++y.x;var T=g.tileXYToRectangle(C.x,C.y,m);Math.abs(T.north-e.rectangle.south)<S&&C.y>y.y&&--C.y,Math.abs(T.west-e.rectangle.east)<E&&C.x>y.x&&--C.x;var b,x,P=e.rectangle,A=g.tileXYToRectangle(y.x,y.y,m),I=f.intersection(A,s,X),M=0,D=1;!this.isBaseLayer()&&Math.abs(I.west-e.rectangle.west)>=E&&(M=Math.min(1,(I.west-P.west)/P.width)),!this.isBaseLayer()&&Math.abs(I.north-e.rectangle.north)>=S&&(D=Math.max(0,(I.north-P.south)/P.height));for(var R=D,O=y.x;O<=C.x;O++){b=M,A=g.tileXYToRectangle(O,y.y,m),I=f.intersection(A,s,X),M=Math.min(1,(I.east-P.west)/P.width),O===C.x&&(this.isBaseLayer()||Math.abs(I.east-e.rectangle.east)<E)&&(M=1),D=R;for(var N=y.y;N<=C.y;N++){x=D,A=g.tileXYToRectangle(O,N,m),I=f.intersection(A,s,X),D=Math.max(0,(I.south-P.south)/P.height),N===C.y&&(this.isBaseLayer()||Math.abs(I.south-e.rectangle.south)<S)&&(D=0);var L=new r(b,D,M,x),F=this.getImageryFromCache(O,N,m,A);n.imagery.splice(i,0,new k(F,L)),++i}}return!0},q.prototype._calculateTextureTranslationAndScale=function(e,t){var i=t.readyImagery.rectangle,n=e.rectangle,o=n.width,a=n.height,s=o/i.width,l=a/i.height;return new r(s*(n.west-i.west)/o,l*(n.south-i.south)/a,s,l)},q.prototype._requestImagery=function(e){function t(t){return a(t)?(e.image=t,e.state=z.RECEIVED,void _.handleSuccess(o._requestImageError)):r()}function r(t){e.state=z.FAILED;var r="Failed to obtain image tile X: "+e.x+" Y: "+e.y+" Level: "+e.level+".";o._requestImageError=_.handleError(o._requestImageError,n,n.errorEvent,r,e.x,e.y,e.level,i,t)}function i(){e.state=z.TRANSITIONING;var i=n.requestImage(e.x,e.y,e.level);return a(i)?(a(n.getTileCredits)&&(e.credits=n.getTileCredits(e.x,e.y,e.level)),void B(i,t,r)):void(e.state=z.UNLOADED)}var n=this._imageryProvider,o=this;i()},q.prototype._createTexture=function(e,t){var r=this._imageryProvider;if(a(r.tileDiscardPolicy)){var i=r.tileDiscardPolicy;if(a(i)){if(!i.isReady())return void(t.state=z.RECEIVED);if(i.shouldDiscardImage(t.image))return void(t.state=z.INVALID)}}var n=new M({context:e,source:t.image,pixelFormat:r.hasAlphaChannel?p.RGBA:p.RGB});t.texture=n,t.image=void 0,t.state=z.TEXTURE_LOADED},q.prototype._reprojectTexture=function(e,t,r){var i=r.texture,n=r.rectangle;if(!(this._imageryProvider.tilingScheme instanceof c)&&n.width/i.width>1e-5){var o=this,a=new E({persists:!0,owner:this,preExecute:function(t){W(t,e,i,r.rectangle)},postExecute:function(t){i.destroy(),r.texture=t,U(o,e,r,t)}});t.push(a)}else U(this,e,r,i)},q.prototype.getImageryFromCache=function(e,t,r,i){var n=G(e,t,r),o=this._imageryCache[n];return a(o)||(o=new V(this,e,t,r,i),this._imageryCache[n]=o),o.addReference(),o},q.prototype.removeImageryFromCache=function(e){var t=G(e.x,e.y,e.level);delete this._imageryCache[t]};var Z={u_textureDimensions:function(){return this.textureDimensions},u_texture:function(){return this.texture},textureDimensions:new t,texture:void 0},K=u.supportsTypedArrays()?new Float32Array(128):void 0;return q}),r("Scene/GlobeSurfaceTileProvider",["../Core/BoundingSphere","../Core/BoxOutlineGeometry","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/FeatureDetection","../Core/GeometryInstance","../Core/GeometryPipeline","../Core/IndexDatatype","../Core/Intersect","../Core/Math","../Core/Matrix4","../Core/OrientedBoundingBox","../Core/PrimitiveType","../Core/Rectangle","../Core/SphereOutlineGeometry","../Core/Visibility","../Core/WebMercatorProjection","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/ContextLimits","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/VertexArray","../Scene/BlendingState","../Scene/DepthFunction","../Scene/Pass","../Scene/PerInstanceColorAppearance","../Scene/Primitive","../ThirdParty/when","./GlobeSurfaceTile","./ImageryLayer","./ImageryState","./QuadtreeTileLoadState","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G){"use strict";function W(e,t){var r=e.loadingImagery;l(r)||(r=e.readyImagery);var i=t.loadingImagery;return l(i)||(i=t.readyImagery),r.imageryLayer._layerIndex-i.imageryLayer._layerIndex}function H(){var e={u_initialColor:function(){return this.initialColor},u_zoomedOutOceanSpecularIntensity:function(){return this.zoomedOutOceanSpecularIntensity},u_oceanNormalMap:function(){return this.oceanNormalMap},u_lightingFadeDistance:function(){return this.lightingFadeDistance},u_center3D:function(){return this.center3D},u_tileRectangle:function(){return this.tileRectangle},u_modifiedModelView:function(){return this.modifiedModelView},u_dayTextures:function(){return this.dayTextures},u_dayTextureTranslationAndScale:function(){return this.dayTextureTranslationAndScale},u_dayTextureTexCoordsRectangle:function(){return this.dayTextureTexCoordsRectangle},u_dayTextureAlpha:function(){return this.dayTextureAlpha},u_dayTextureBrightness:function(){return this.dayTextureBrightness},u_dayTextureContrast:function(){return this.dayTextureContrast},u_dayTextureHue:function(){return this.dayTextureHue},u_dayTextureSaturation:function(){return this.dayTextureSaturation},u_dayTextureOneOverGamma:function(){return this.dayTextureOneOverGamma},u_dayIntensity:function(){return this.dayIntensity},u_southAndNorthLatitude:function(){return this.southAndNorthLatitude},u_southMercatorYAndOneOverHeight:function(){return this.southMercatorYAndOneOverHeight},u_waterMask:function(){return this.waterMask},u_waterMaskTranslationAndScale:function(){return this.waterMaskTranslationAndScale},initialColor:new n(0,0,.5,1),zoomedOutOceanSpecularIntensity:.5,oceanNormalMap:void 0,lightingFadeDistance:new r(65e5,9e6),center3D:void 0,modifiedModelView:new y,tileRectangle:new n,dayTextures:[],dayTextureTranslationAndScale:[],dayTextureTexCoordsRectangle:[],dayTextureAlpha:[],dayTextureBrightness:[],dayTextureContrast:[],dayTextureHue:[],dayTextureSaturation:[],dayTextureOneOverGamma:[],dayIntensity:0,southAndNorthLatitude:new r, +southMercatorYAndOneOverHeight:new r,waterMask:void 0,waterMaskTranslationAndScale:new n};return e}function q(e,t,r){var i=r.data;if(!l(i.wireframeVertexArray)&&!l(i.meshForWireframePromise)&&(i.meshForWireframePromise=i.terrainData.createMesh(t._terrainProvider.tilingScheme,r.x,r.y,r.level),l(i.meshForWireframePromise))){var n=i.vertexArray;B(i.meshForWireframePromise,function(t){i.vertexArray===n&&(i.wireframeVertexArray=j(e,i.vertexArray,t)),i.meshForWireframePromise=void 0})}}function j(e,t,r){var i={indices:r.indices,primitiveType:E.TRIANGLES};f.toWireframe(i);var n=i.indices,o=x.createIndexBuffer({context:e,typedArray:n,usage:P.STATIC_DRAW,indexDatatype:v.UNSIGNED_SHORT});return new D({context:e,attributes:t._attributes,indexBuffer:o})}function Y(t,r,a){var s=r.data,u=a.camera.viewMatrix,c=A.maximumTextureImageUnits,h=s.waterMaskTexture,d=t.hasWaterMask&&l(h),p=t.oceanNormalMap,m=d&&l(p),f=t.terrainProvider.ready&&t.terrainProvider.hasVertexNormals,v=a.fog.enabled;d&&--c,m&&--c;var _=s.center,w=Q,T=0,x=0,P=0,M=0,D=!1;if(a.mode!==G.SCENE3D){var R=a.mapProjection,O=R.project(S.southwest(r.rectangle),te),L=R.project(S.northeast(r.rectangle),re);w.x=O.x,w.y=O.y,w.z=L.x,w.w=L.y,a.mode!==G.MORPHING&&(_=$,_.x=0,_.y=.5*(w.z+w.x),_.z=.5*(w.w+w.y),w.x-=_.y,w.y-=_.z,w.z-=_.y,w.w-=_.z),R instanceof b&&(T=r.rectangle.south,x=r.rectangle.north,P=b.geodeticLatitudeToMercatorAngle(T),M=1/(b.geodeticLatitudeToMercatorAngle(x)-P),D=!0)}var F=y.multiplyByPoint(u,_,ee);y.setTranslation(u,F,J);var B=s.imagery,V=0,U=B.length,W=t._renderState,j=t._blendRenderState,Y=W,X=t._firstPassInitialColor,Z=a.context;l(t._debug.boundingSphereTile)||ce();do{var K,ie,ne=0;t._drawCommands.length<=t._usedDrawCommands?(K=new I,K.owner=r,K.cull=!1,K.boundingVolume=new e,K.orientedBoundingBox=void 0,ie=H(),t._drawCommands.push(K),t._uniformMaps.push(ie)):(K=t._drawCommands[t._usedDrawCommands],ie=t._uniformMaps[t._usedDrawCommands]),K.owner=r,++t._usedDrawCommands,r===t._debug.boundingSphereTile&&(l(s.orientedBoundingBox)?le(s.orientedBoundingBox,o.RED).update(a):l(s.boundingSphere3D)&&ue(s.boundingSphere3D,o.RED).update(a)),n.clone(X,ie.initialColor),ie.oceanNormalMap=p,ie.lightingFadeDistance.x=t.lightingFadeOutDistance,ie.lightingFadeDistance.y=t.lightingFadeInDistance,ie.zoomedOutOceanSpecularIntensity=t.zoomedOutOceanSpecularIntensity,ie.center3D=s.center,n.clone(w,ie.tileRectangle),ie.southAndNorthLatitude.x=T,ie.southAndNorthLatitude.y=x,ie.southMercatorYAndOneOverHeight.x=P,ie.southMercatorYAndOneOverHeight.y=M,y.clone(J,ie.modifiedModelView);for(var oe=v&&g.fog(r._distance,a.fog.density)>g.EPSILON3,ae=!1,se=!1,de=!1,pe=!1,me=!1,fe=!1;c>ne&&U>V;){var ve=B[V],_e=ve.readyImagery;if(++V,l(_e)&&_e.state===k.READY&&0!==_e.imageryLayer.alpha){var ge=_e.imageryLayer;if(l(ve.textureTranslationAndScale)||(ve.textureTranslationAndScale=ge._calculateTextureTranslationAndScale(r,ve)),ie.dayTextures[ne]=_e.texture,ie.dayTextureTranslationAndScale[ne]=ve.textureTranslationAndScale,ie.dayTextureTexCoordsRectangle[ne]=ve.textureCoordinateRectangle,ie.dayTextureAlpha[ne]=ge.alpha,fe=fe||1!==ie.dayTextureAlpha[ne],ie.dayTextureBrightness[ne]=ge.brightness,ae=ae||ie.dayTextureBrightness[ne]!==z.DEFAULT_BRIGHTNESS,ie.dayTextureContrast[ne]=ge.contrast,se=se||ie.dayTextureContrast[ne]!==z.DEFAULT_CONTRAST,ie.dayTextureHue[ne]=ge.hue,de=de||ie.dayTextureHue[ne]!==z.DEFAULT_HUE,ie.dayTextureSaturation[ne]=ge.saturation,pe=pe||ie.dayTextureSaturation[ne]!==z.DEFAULT_SATURATION,ie.dayTextureOneOverGamma[ne]=1/ge.gamma,me=me||ie.dayTextureOneOverGamma[ne]!==1/z.DEFAULT_GAMMA,l(_e.credits))for(var ye=a.creditDisplay,Ce=_e.credits,Ee=0,Se=Ce.length;Se>Ee;++Ee)ye.addCredit(Ce[Ee]);++ne}}ie.dayTextures.length=ne,ie.waterMask=h,n.clone(s.waterMaskTranslationAndScale,ie.waterMaskTranslationAndScale),K.shaderProgram=t._surfaceShaderSet.getShaderProgram(Z,a.mode,s,ne,ae,se,de,pe,me,fe,d,m,t.enableLighting,f,D,oe),K.renderState=Y,K.primitiveType=E.TRIANGLES,K.vertexArray=s.vertexArray,K.uniformMap=ie,K.pass=N.GLOBE,t._debug.wireframe&&(q(Z,t,r),l(s.wireframeVertexArray)&&(K.vertexArray=s.wireframeVertexArray,K.primitiveType=E.LINES));var we=K.boundingVolume,Te=K.orientedBoundingBox;a.mode!==G.SCENE3D?(e.fromRectangleWithHeights2D(r.rectangle,a.mapProjection,s.minimumHeight,s.maximumHeight,we),i.fromElements(we.center.z,we.center.x,we.center.y,we.center),a.mode===G.MORPHING&&(we=e.union(s.boundingSphere3D,we,we))):(K.boundingVolume=e.clone(s.boundingSphere3D,we),K.orientedBoundingBox=C.clone(s.orientedBoundingBox,Te)),a.commandList.push(K),Y=j,X=he}while(U>V)}function X(e,t,r){var i;e._pickCommands.length<=e._usedPickCommands?(i=new I,i.cull=!1,e._pickCommands.push(i)):i=e._pickCommands[e._usedPickCommands],++e._usedPickCommands;var n=r.projection instanceof b;i.shaderProgram=e._surfaceShaderSet.getShaderProgram(r.context,r.mode,n),i.renderState=e._pickRenderState,i.owner=t.owner,i.primitiveType=t.primitiveType,i.vertexArray=t.vertexArray,i.uniformMap=t.uniformMap,i.boundingVolume=t.boundingVolume,i.orientedBoundingBox=i.orientedBoundingBox,i.pass=t.pass,r.commandList.push(i)}var Z=function de(e){V.irregularZoomLevels|=!!e.terrainProvider._availableLevels,this.lightingFadeOutDistance=65e5,this.lightingFadeInDistance=9e6,this.hasWaterMask=!1,this.oceanNormalMap=void 0,this.zoomedOutOceanSpecularIntensity=.5,this.enableLighting=!1,this._quadtree=void 0,this._terrainProvider=e.terrainProvider,this._imageryLayers=e.imageryLayers,this._surfaceShaderSet=e.surfaceShaderSet,this._renderState=void 0,this._blendRenderState=void 0,this._pickRenderState=void 0,this._errorEvent=new d,this._imageryLayers.layerAdded.addEventListener(de.prototype._onLayerAdded,this),this._imageryLayers.layerRemoved.addEventListener(de.prototype._onLayerRemoved,this),this._imageryLayers.layerMoved.addEventListener(de.prototype._onLayerMoved,this),this._imageryLayers.layerShownOrHidden.addEventListener(de.prototype._onLayerShownOrHidden,this),this._layerOrderChanged=!1,this._tilesToRenderByTextureCount=[],this._drawCommands=[],this._uniformMaps=[],this._pickCommands=[],this._usedDrawCommands=0,this._usedPickCommands=0,this._debug={wireframe:!1,boundingSphereTile:void 0},this._baseColor=void 0,this._firstPassInitialColor=void 0,this.baseColor=new o(0,0,.5,1)};u(Z.prototype,{baseColor:{get:function(){return this._baseColor},set:function(e){this._baseColor=e,this._firstPassInitialColor=n.fromColor(e,this._firstPassInitialColor)}},quadtree:{get:function(){return this._quadtree},set:function(e){this._quadtree=e}},ready:{get:function(){return this._terrainProvider.ready&&(0===this._imageryLayers.length||this._imageryLayers.get(0).imageryProvider.ready)}},tilingScheme:{get:function(){return this._terrainProvider.tilingScheme}},errorEvent:{get:function(){return this._errorEvent}},terrainProvider:{get:function(){return this._terrainProvider},set:function(e){this._terrainProvider!==e&&(this._terrainProvider=e,V.irregularZoomLevels|=!!e._availableLevels,l(this._quadtree)&&this._quadtree.invalidateAllTiles())}}}),Z.prototype.beginUpdate=function(e){this._imageryLayers._update(),this._layerOrderChanged&&(this._layerOrderChanged=!1,this._quadtree.forEachLoadedTile(function(e){e.data.imagery.sort(W)}));var t,r,i=this._tilesToRenderByTextureCount;for(t=0,r=i.length;r>t;++t){var n=i[t];l(n)&&(n.length=0)}this._usedDrawCommands=0;var o=e.creditDisplay;this._terrainProvider.ready&&l(this._terrainProvider.credit)&&o.addCredit(this._terrainProvider.credit);var a=this._imageryLayers;for(t=0,r=a.length;r>t;++t){var s=a.get(t).imageryProvider;V.irregularZoomLevels|=!!s._availableLevels,s.ready&&l(s.credit)&&o.addCredit(s.credit)}},Z.prototype.endUpdate=function(e){l(this._renderState)||(this._renderState=M.fromCache({cull:{enabled:!0},depthTest:{enabled:!0,func:O.LESS}}),this._blendRenderState=M.fromCache({cull:{enabled:!0},depthTest:{enabled:!0,func:O.LESS_OR_EQUAL},blending:R.ALPHA_BLEND}));for(var t=this._tilesToRenderByTextureCount,r=0,i=t.length;i>r;++r){var n=t[r];if(l(n))for(var o=0,a=n.length;a>o;++o)Y(this,n[o],e)}},Z.prototype.updateForPick=function(e){l(this._pickRenderState)||(this._pickRenderState=M.fromCache({colorMask:{red:!1,green:!1,blue:!1,alpha:!1},depthTest:{enabled:!0}})),this._usedPickCommands=0;for(var t=this._drawCommands,r=(this._tilesToRenderByTextureCount,0),i=this._usedDrawCommands;i>r;++r)X(this,t[r],e)},Z.prototype.getLevelMaximumGeometricError=function(e){return this._terrainProvider.getLevelMaximumGeometricError(e)},Z.prototype.loadTile=function(e,t){V.processStateMachine(t,e.context,e.commandList,this._terrainProvider,this._imageryLayers)};var K=new e;Z.prototype.computeTileVisibility=function(t,r,n){var o=this.computeDistanceToTile(t,r);if(t._distance=o,r.fog.enabled&&g.fog(o,r.fog.density)>=1)return T.NONE;var a=t.data,u=r.cullingVolume,c=s(a.orientedBoundingBox,a.boundingSphere3D);r.mode!==G.SCENE3D&&(c=K,e.fromRectangleWithHeights2D(t.rectangle,r.mapProjection,a.minimumHeight,a.maximumHeight,c),i.fromElements(c.center.z,c.center.x,c.center.y,c.center),r.mode===G.MORPHING&&(c=e.union(a.boundingSphere3D,c,c)));var h=u.computeVisibility(c);if(h===_.OUTSIDE)return T.NONE;if(r.mode===G.SCENE3D){var d=a.occludeePointInScaledSpace;return l(d)?n.ellipsoid.isScaledSpacePointVisible(d)?h:T.NONE:h}return h};var J=(p.supportsTypedArrays()?new Float32Array(1):void 0,new y),Q=new n,$=new i,ee=new i,te=new i,re=new i;Z.prototype.showTileThisFrame=function(e,t){for(var r=0,i=e.data.imagery,n=0,o=i.length;o>n;++n){var a=i[n];l(a.readyImagery)&&0!==a.readyImagery.imageryLayer.alpha&&++r}var s=this._tilesToRenderByTextureCount[r];l(s)||(s=[],this._tilesToRenderByTextureCount[r]=s),s.push(e);var u=this._debug;++u.tilesRendered,u.texturesRendered+=r};var ie=new i,ne=new i,oe=new i(0,-1,0),ae=new i(0,0,-1),se=new i;Z.prototype.computeDistanceToTile=function(e,t){var r=e.data,n=r.southwestCornerCartesian,o=r.northeastCornerCartesian,a=r.westNormal,s=r.southNormal,l=r.eastNormal,u=r.northNormal,c=r.maximumHeight;t.mode!==G.SCENE3D&&(n=t.mapProjection.project(S.southwest(e.rectangle),ie),n.z=n.y,n.y=n.x,n.x=0,o=t.mapProjection.project(S.northeast(e.rectangle),ne),o.z=o.y,o.y=o.x,o.x=0,a=oe,l=i.UNIT_Y,s=ae,u=i.UNIT_Z,c=0);var h,d=t.camera.positionWC,p=t.camera.positionCartographic,m=i.subtract(d,n,se),f=i.dot(m,a),v=i.dot(m,s),_=i.subtract(d,o,se),g=i.dot(_,l),y=i.dot(_,u);h=t.mode===G.SCENE3D?p.height:d.x;var C=h-c,E=0;return f>0?E+=f*f:g>0&&(E+=g*g),v>0?E+=v*v:y>0&&(E+=y*y),C>0&&(E+=C*C),Math.sqrt(E)},Z.prototype.isDestroyed=function(){return!1},Z.prototype.destroy=function(){return this._tileProvider=this._tileProvider&&this._tileProvider.destroy(),c(this)},Z.prototype._onLayerAdded=function(e,t){if(e.show){var r=this._terrainProvider;this._quadtree.forEachLoadedTile(function(t){e._createTileImagerySkeletons(t,r)&&(t.state=U.LOADING)}),this._layerOrderChanged=!0}},Z.prototype._onLayerRemoved=function(e,t){this._quadtree.forEachLoadedTile(function(t){for(var r=t.data.imagery,i=-1,n=0,o=0,a=r.length;a>o;++o){var s=r[o],u=s.loadingImagery;if(l(u)||(u=s.readyImagery),u.imageryLayer===e)-1===i&&(i=o),s.freeResources(),++n;else if(-1!==i)break}-1!==i&&r.splice(i,n)})},Z.prototype._onLayerMoved=function(e,t,r){this._layerOrderChanged=!0},Z.prototype._onLayerShownOrHidden=function(e,t,r){r?this._onLayerAdded(e,t):this._onLayerRemoved(e,t)};var le,ue,ce;!function(){function e(e){return new F({geometryInstances:e,appearance:new L({translucent:!1,flat:!0}),asynchronous:!1})}var r,n,o=new m({geometry:t.fromDimensions({dimensions:new i(2,2,2)})}),s=new m({geometry:new w({radius:1})}),u=new y;le=function(t,i){return t===r?n:(ce(),r=t,u=y.fromRotationTranslation(t.halfAxes,t.center,u),o.modelMatrix=u,o.attributes.color=a.fromColor(i),n=e(o))},ue=function(t,i){return t===r?n:(ce(),r=t,u=y.fromTranslation(t.center,u),u=y.multiplyByUniformScale(u,t.radius,u),s.modelMatrix=u,s.attributes.color=a.fromColor(i),n=e(s))},ce=function(){l(n)&&(n.destroy(),n=void 0,r=void 0)}}();var he=new n(0,0,0,0);return Z}),r("Scene/ImageryLayerCollection",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/Math","../Core/Rectangle","../ThirdParty/when","./ImageryLayer"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){var r=e.indexOf(t);return r}function h(e,t,r){var i=e._layers;if(t=a.clamp(t,0,i.length-1),r=a.clamp(r,0,i.length-1),t!==r){var n=i[t];i[t]=i[r],i[r]=n,e._update(),e.layerMoved.raiseEvent(n,r,t)}}var d=function(){this._layers=[],this.layerAdded=new o,this.layerRemoved=new o,this.layerMoved=new o,this.layerShownOrHidden=new o};r(d.prototype,{length:{get:function(){return this._layers.length}}}),d.prototype.add=function(e,r){var i=t(r);i?this._layers.splice(r,0,e):(r=this._layers.length,this._layers.push(e)),this._update(),this.layerAdded.raiseEvent(e,r)},d.prototype.addImageryProvider=function(e,t){var r=new u(e);return this.add(r,t),r},d.prototype.remove=function(t,r){r=e(r,!0);var i=this._layers.indexOf(t);return-1!==i?(this._layers.splice(i,1),this._update(),this.layerRemoved.raiseEvent(t,i),r&&t.destroy(),!0):!1},d.prototype.removeAll=function(t){t=e(t,!0);for(var r=this._layers,i=0,n=r.length;n>i;i++){var o=r[i];this.layerRemoved.raiseEvent(o,i),t&&o.destroy()}this._layers=[]},d.prototype.contains=function(e){return-1!==this.indexOf(e)},d.prototype.indexOf=function(e){return this._layers.indexOf(e)},d.prototype.get=function(e){return this._layers[e]},d.prototype.raise=function(e){var t=c(this._layers,e);h(this,t,t+1)},d.prototype.lower=function(e){var t=c(this._layers,e);h(this,t,t-1)},d.prototype.raiseToTop=function(e){var t=c(this._layers,e);t!==this._layers.length-1&&(this._layers.splice(t,1),this._layers.push(e),this._update(),this.layerMoved.raiseEvent(e,this._layers.length-1,t))},d.prototype.lowerToBottom=function(e){var t=c(this._layers,e);0!==t&&(this._layers.splice(t,1),this._layers.splice(0,0,e),this._update(),this.layerMoved.raiseEvent(e,0,t))};var p=new s;return d.prototype.pickImageryLayerFeatures=function(e,r){var i=r.globe.pick(e,r);if(!t(i))return void 0;for(var n,o=r.globe.ellipsoid.cartesianToCartographic(i),u=r.globe._surface._tilesToRender,c=(u.length,0);!t(n)&&c<u.length;++c){var h=u[c];s.contains(h.rectangle,o)&&(n=h)}if(!t(n))return void 0;for(var d=(n.rectangle,n.data.imagery),m=[],f=[],v=d.length-1;v>=0;--v){var _=d[v],g=_.readyImagery;if(t(g)){var y=g.imageryLayer.imageryProvider;if(t(y.pickFeatures)&&s.contains(g.rectangle,o)){var C=p,E=1/1024;if(C.west=a.lerp(n.rectangle.west,n.rectangle.east,_.textureCoordinateRectangle.x-E),C.east=a.lerp(n.rectangle.west,n.rectangle.east,_.textureCoordinateRectangle.z+E),C.south=a.lerp(n.rectangle.south,n.rectangle.north,_.textureCoordinateRectangle.y-E),C.north=a.lerp(n.rectangle.south,n.rectangle.north,_.textureCoordinateRectangle.w+E),s.contains(C,o)){var S=y.pickFeatures(g.x,g.y,g.level,o.longitude,o.latitude);t(S)&&(m.push(S),f.push(g.imageryLayer))}}}}return 0===m.length?void 0:l.all(m,function(e){for(var r=[],i=0;i<e.length;++i){var n=e[i],a=f[i];if(t(n)&&n.length>0)for(var s=0;s<n.length;++s){var l=n[s];l.imageryLayer=a,t(l.position)||(l.position=o),r.push(l)}}return r})},d.prototype.isDestroyed=function(){return!1},d.prototype.destroy=function(){return this.removeAll(!0),i(this)},d.prototype._update=function(){for(var e,r,i=!0,n=this._layers,o=0,a=n.length;a>o;++o)r=n[o],r._layerIndex=o,r.show?(r._isBaseLayer=i,i=!1):r._isBaseLayer=!1,r.show!==r._show&&(t(r._show)&&(t(e)||(e=[]),e.push(r)),r._show=r.show);if(t(e))for(o=0,a=e.length;a>o;++o)r=e[o],this.layerShownOrHidden.raiseEvent(r,r._layerIndex,r.show)},d}),r("Scene/QuadtreeOccluders",["../Core/Cartesian3","../Core/defineProperties","../Core/EllipsoidalOccluder"],function(e,t,r){"use strict";var i=function(t){this._ellipsoid=new r(t.ellipsoid,e.ZERO)};return t(i.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),i}),r("Scene/QuadtreeTile",["../Core/defined","../Core/defineProperties","../Core/Cartographic","../Core/DeveloperError","../Core/Rectangle","./QuadtreeTileLoadState"],function(e,t,r,i,n,o){"use strict";var a=function(e){this._tilingScheme=e.tilingScheme,this._x=e.x,this._y=e.y,this._level=e.level,this._parent=e.parent,this._rectangle=this._tilingScheme.tileXYToRectangle(this._x,this._y,this._level),this._children=void 0,this._replacementPrevious=void 0,this._replacementNext=void 0,this._distance=0,this._customData=[],this._frameUpdated=void 0,this._frameRendered=void 0,this.state=o.START,this.renderable=!1,this.upsampledFromParent=!1,this.data=void 0};return a.createLevelZeroTiles=function(t){if(!e(t))throw new i("tilingScheme is required.");for(var r=t.getNumberOfXTilesAtLevel(0),n=t.getNumberOfYTilesAtLevel(0),o=new Array(r*n),s=0,l=0;n>l;++l)for(var u=0;r>u;++u)o[s++]=new a({tilingScheme:t,x:u,y:l,level:0});return o},a.createMinimumLevelTiles=function(e,t,i){for(var n=r.fromRadians(i.west,i.south),o=r.fromRadians(i.east,i.north),s=e.positionToTileXY(n,t),l=e.positionToTileXY(o,t),u=new Array,c=l.y;c<=s.y;c++)for(var h=s.x;h<=l.x;h++)u.push(new a({tilingScheme:e,x:h,y:c,level:t}));return u},a.prototype._updateCustomData=function(t,r,i){var o,a,s,l=this.customData;if(e(r)&&e(i)){for(o=0;o<i.length;++o){a=i[o];for(var u=0;u<l.length;++u)if(l[u]===a){l.splice(u,1);break}}for(s=this._rectangle,o=0;o<r.length;++o)a=r[o],n.contains(s,a.positionCartographic)&&l.push(a);this._frameUpdated=t}else{var c=this._parent;if(e(c)&&this._frameUpdated!==c._frameUpdated){l.length=0,s=this._rectangle;var h=c.customData;for(o=0;o<h.length;++o)a=h[o],n.contains(s,a.positionCartographic)&&l.push(a);this._frameUpdated=c._frameUpdated}}},t(a.prototype,{tilingScheme:{get:function(){return this._tilingScheme}},x:{get:function(){return this._x}},y:{get:function(){return this._y}},level:{get:function(){return this._level}},parent:{get:function(){return this._parent}},rectangle:{get:function(){return this._rectangle}},children:{get:function(){if(!e(this._children)){var t=this.tilingScheme,r=this.level+1,i=2*this.x,n=2*this.y;this._children=[new a({tilingScheme:t,x:i,y:n,level:r,parent:this}),new a({tilingScheme:t,x:i+1,y:n,level:r,parent:this}),new a({tilingScheme:t,x:i,y:n+1,level:r,parent:this}),new a({tilingScheme:t,x:i+1,y:n+1,level:r,parent:this})]}return this._children}},customData:{get:function(){return this._customData}},needsLoading:{get:function(){return this.state<o.DONE}},eligibleForUnloading:{get:function(){var t=!0;return e(this.data)&&(t=this.data.eligibleForUnloading,e(t)||(t=!0)),t}}}),a.prototype.freeResources=function(){if(this.state=o.START,this.renderable=!1,this.upsampledFromParent=!1,e(this.data)&&e(this.data.freeResources)&&this.data.freeResources(),e(this._children)){for(var t=0,r=this._children.length;r>t;++t)this._children[t].freeResources();this._children=void 0}},a}),r("Scene/TileReplacementQueue",["../Core/defined"],function(e){"use strict";function t(e,t){var r=t.replacementPrevious,i=t.replacementNext;t===e._lastBeforeStartOfFrame&&(e._lastBeforeStartOfFrame=i),t===e.head?e.head=i:r.replacementNext=i,t===e.tail?e.tail=r:i.replacementPrevious=r,t.replacementPrevious=void 0,t.replacementNext=void 0,--e.count}var r=function(){this.head=void 0,this.tail=void 0,this.count=0,this._lastBeforeStartOfFrame=void 0};return r.prototype.markStartOfRenderFrame=function(){this._lastBeforeStartOfFrame=this.head},r.prototype.trimTiles=function(r){for(var i=this.tail,n=!0;n&&e(this._lastBeforeStartOfFrame)&&this.count>r&&e(i);){n=i!==this._lastBeforeStartOfFrame;var o=i.replacementPrevious;i.eligibleForUnloading&&(i.freeResources(),t(this,i)),i=o}},r.prototype.markTileRendered=function(r){var i=this.head;return i===r?void(r===this._lastBeforeStartOfFrame&&(this._lastBeforeStartOfFrame=r.replacementNext)):(++this.count,e(i)?((e(r.replacementPrevious)||e(r.replacementNext))&&t(this,r),r.replacementPrevious=void 0,r.replacementNext=i,i.replacementPrevious=r,void(this.head=r)):(r.replacementPrevious=void 0,r.replacementNext=void 0,this.head=r,void(this.tail=r)))},r}),r("Scene/QuadtreePrimitive",["../Core/Cartesian3","../Core/Cartesian2","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/getTimestamp","../Core/Math","../Core/Queue","../Core/Ray","../Core/Rectangle","../Core/Visibility","./QuadtreeOccluders","./QuadtreeTile","./QuadtreeTileLoadState","./SceneMode","./TileReplacementQueue"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g){"use strict";function y(e,t){var r=e._debug;if(!r.suspendLodUpdate){var i,o,a=e._tilesToRender;a.length=0;var s=e._tileTraversalQueue;if(s.clear(),r.maxDepth=0,r.tilesVisited=0,r.tilesCulled=0,r.tilesRendered=0,r.tilesWaitingForChildren=0,e._tileLoadQueue.length=0,e._tileReplacementQueue.markStartOfRenderFrame(),!n(e._levelZeroTiles)){if(!e._tileProvider.ready)return;var l=e._tileProvider.tilingScheme,u=e._tileProvider._terrainProvider;if(u&&u._availableLevels&&u._rectangle){var c=u._availableLevels[0];e._levelZeroTiles=f.createMinimumLevelTiles(l,c,u._rectangle)}else e._levelZeroTiles=f.createLevelZeroTiles(l)}e._occluders.ellipsoid.cameraPosition=t.camera.positionWC;var h,d=e._tileProvider,m=e._occluders,v=e._levelZeroTiles,_=e._addHeightCallbacks,g=e._removeHeightCallbacks,y=t.frameNumber;if(_.length>0||g.length>0){for(i=0,o=v.length;o>i;++i)h=v[i],h._updateCustomData(y,_,g);_.length=0,g.length=0}for(i=0,o=v.length;o>i;++i)h=v[i],e._tileReplacementQueue.markTileRendered(h),h.needsLoading&&T(e,h),h.renderable&&d.computeTileVisibility(h,t,m)!==p.NONE?s.enqueue(h):(++r.tilesCulled,h.renderable||++r.tilesWaitingForChildren);for(n(e.sseCorrector)&&e.sseCorrector.newFrameState(t);n(h=s.dequeue());)if(++r.tilesVisited,e._tileReplacementQueue.markTileRendered(h),h._updateCustomData(y),h.level>r.maxDepth&&(r.maxDepth=h.level),C(e,t,h)<e.maximumScreenSpaceError)S(e,h);else if(w(e,h)){var E=h.children;for(i=0,o=E.length;o>i;++i)d.computeTileVisibility(E[i],t,m)!==p.NONE?s.enqueue(E[i]):++r.tilesCulled}else S(e,h);r.enableDebugOutput&&(r.tilesVisited!==r.lastTilesVisited||r.tilesRendered!==r.lastTilesRendered||r.tilesCulled!==r.lastTilesCulled||r.maxDepth!==r.lastMaxDepth||r.tilesWaitingForChildren!==r.lastTilesWaitingForChildren)&&(console.log("Visited "+r.tilesVisited+", Rendered: "+r.tilesRendered+", Culled: "+r.tilesCulled+", Max Depth: "+r.maxDepth+", Waiting for children: "+r.tilesWaitingForChildren),r.lastTilesVisited=r.tilesVisited,r.lastTilesRendered=r.tilesRendered,r.lastTilesCulled=r.tilesCulled,r.lastMaxDepth=r.maxDepth,r.lastTilesWaitingForChildren=r.tilesWaitingForChildren)}}function C(e,t,r){if(t.mode===_.SCENE2D)return E(e,t,r);var i=e._tileProvider.getLevelMaximumGeometricError(r.level),o=r._distance,a=t.context.drawingBufferHeight,s=t.camera.frustum.sseDenominator,l=i*a/(o*s);return t.fog.enabled&&(l-=u.fog(o,t.fog.density)*t.fog.sse),n(e.sseCorrector)&&(l=e.sseCorrector.correct(t,r,o,l)),l}function E(e,t,r){var i=t.camera,n=i.frustum,o=t.context,a=o.drawingBufferWidth,s=o.drawingBufferHeight,l=e._tileProvider.getLevelMaximumGeometricError(r.level),u=Math.max(n.top-n.bottom,n.right-n.left)/Math.max(a,s);return l/u}function S(e,t){e._tilesToRender.push(t),++e._debug.tilesRendered}function w(e,t){for(var r=!0,i=!0,n=t.children,o=0,a=n.length;a>o;++o){var s=n[o];e._tileReplacementQueue.markTileRendered(s),i=i&&s.upsampledFromParent,r=r&&s.renderable,s.needsLoading&&T(e,s)}return r||++e._debug.tilesWaitingForChildren,r&&!i}function T(e,t){e._tileLoadQueue.push(t)}function b(e,t){var r=e._tileLoadQueue,i=e._tileProvider;if(0!==r.length){e._tileReplacementQueue.trimTiles(e.tileCacheSize);for(var n=l(),o=e._loadQueueTimeSlice,a=n+o,s=r.length-1;s>=0;--s){var u=r[s];if(e._tileReplacementQueue.markTileRendered(u),i.loadTile(t,u),l()>=a)break}}}function x(t,i){for(var o=t._tileToUpdateHeights,a=t._tileProvider.terrainProvider,s=l(),u=t._updateHeightsTimeSlice,c=s+u,h=i.mode,p=i.mapProjection,m=p.ellipsoid;o.length>0;){var f=o[o.length-1];f!==t._lastTileUpdated&&(t._lastTileIndex=0);for(var v=f.customData,g=v.length,y=!1,C=t._lastTileIndex;g>C;++C){var E=v[C];if(f.level>E.level){n(E.position)||(E.position=m.cartographicToCartesian(E.positionCartographic)),h===_.SCENE3D?(e.clone(e.ZERO,M.origin),e.normalize(E.position,M.direction)):(r.clone(E.positionCartographic,D),D.height=-11500,p.project(D,R),e.fromElements(R.z,R.x,R.y,R),e.clone(R,M.origin),e.clone(e.UNIT_X,M.direction));var S=f.data.pick(M,h,p,!1,R);n(S)&&E.callback(S),E.level=f.level}else if(f.level===E.level){for(var w,T=f.children,b=T.length,x=0;b>x&&(w=T[x],!d.contains(w.rectangle,E.positionCartographic));++x);var P=a.getTileDataAvailable(w.x,w.y,w.level);(n(P)&&!P||n(parent)&&n(parent.data)&&n(parent.data.terrainData)&&!parent.data.terrainData.isChildAvailable(parent.x,parent.y,w.x,w.y))&&E.removeFunc()}if(l()>=c){y=!0;break}}if(y){t._lastTileUpdated=f,t._lastTileIndex=C;break}o.pop()}}function P(e,t){return e._distance-t._distance}function A(e,t){var r=e._tileProvider,i=e._tilesToRender,n=e._tileToUpdateHeights;i.sort(P);for(var o=0,a=i.length;a>o;++o){var s=i[o];r.showTileThisFrame(s,t),s._frameRendered!==t.frameNumber-1&&n.push(s),s._frameRendered=t.frameNumber}x(e,t)}var I=function(e){this._sseCorrector=e.sseCorrector,this._tileProvider=e.tileProvider,this._tileProvider.quadtree=this,this._debug={enableDebugOutput:!1,maxDepth:0,tilesVisited:0,tilesCulled:0,tilesRendered:0,tilesWaitingForChildren:0,lastMaxDepth:-1,lastTilesVisited:-1,lastTilesCulled:-1,lastTilesRendered:-1,lastTilesWaitingForChildren:-1,suspendLodUpdate:!1};var t=this._tileProvider.tilingScheme,r=t.ellipsoid;this._tilesToRender=[],this._tileTraversalQueue=new c,this._tileLoadQueue=[],this._tileReplacementQueue=new g,this._levelZeroTiles=void 0,this._levelZeroTilesReady=!1,this._loadQueueTimeSlice=5,this._addHeightCallbacks=[],this._removeHeightCallbacks=[],this._tileToUpdateHeights=[],this._lastTileIndex=0,this._updateHeightsTimeSlice=2,this.maximumScreenSpaceError=i(e.maximumScreenSpaceError,2),this.tileCacheSize=i(e.tileCacheSize,100),this._occluders=new m({ellipsoid:r})};o(I.prototype,{tileProvider:{get:function(){return this._tileProvider}}}),I.prototype.invalidateAllTiles=function(){var e=this._tileReplacementQueue;e.head=void 0,e.tail=void 0,e.count=0;var t=this._levelZeroTiles;if(n(t))for(var r=0;r<t.length;++r){for(var i=t[r],o=i.customData,a=o.length,s=0;a>s;++s){var l=o[s];l.level=0,this._addHeightCallbacks.push(l)}t[r].freeResources()}this._levelZeroTiles=void 0},I.prototype.forEachLoadedTile=function(e){for(var t=this._tileReplacementQueue.head;n(t);)t.state!==v.START&&e(t),t=t.replacementNext},I.prototype.forEachRenderedTile=function(e){for(var t=this._tilesToRender,r=0,i=t.length;i>r;++r)e(t[r])},I.prototype.updateHeight=function(e,t){var r=this,i={position:void 0,positionCartographic:e,level:-1,callback:t};return i.removeFunc=function(){r._removeHeightCallbacks.push(i)},r._addHeightCallbacks.push(i),i.removeFunc},I.prototype.update=function(e){var t=e.passes;t.render&&(this._tileProvider.beginUpdate(e),y(this,e),b(this,e),A(this,e),this._tileProvider.endUpdate(e)),t.pick&&this._tilesToRender.length>0&&this._tileProvider.endUpdate(e)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){this._tileProvider=this._tileProvider&&this._tileProvider.destroy()};var M=new h,D=new r,R=new e;return I}),r("Scene/Globe",["../Core/BoundingRectangle","../Core/BoundingSphere","../Core/buildModuleUrl","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/combine","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/EllipsoidTerrainProvider","../Core/FeatureDetection","../Core/GeographicProjection","../Core/Geometry","../Core/GeometryAttribute","../Core/Intersect","../Core/IntersectionTests","../Core/loadImage","../Core/Math","../Core/Matrix4","../Core/Occluder","../Core/PrimitiveType","../Core/Ray","../Core/Rectangle","../Core/Transforms","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/VertexArray","../Shaders/GlobeFS","../Shaders/GlobeFSPole","../Shaders/GlobeVS","../Shaders/GlobeVSPole","../Shaders/GroundAtmosphere","../ThirdParty/when","./GlobeSurfaceShaderSet","./GlobeSurfaceTileProvider","./ImageryLayerCollection","./Pass","./QuadtreePrimitive","./SceneMode","./terrainAttributeLocations"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X){"use strict";function Z(e){return function(r,i){var n=t.distanceSquaredTo(r.pickBoundingSphere,e),o=t.distanceSquaredTo(i.pickBoundingSphere,e);return n-o}}function K(t,r,i,o,a,s){le.longitude=0,le.latitude=o;var l=t._ellipsoid.cartographicToCartesian(le,ue);le.longitude=Math.PI;var u=t._ellipsoid.cartographicToCartesian(le,ce),c=.5*n.magnitude(n.subtract(l,u,oe),oe);le.longitude=0,le.latitude=i;var h,d=t._ellipsoid.cartographicToCartesian(le,ue),p=r.camera.direction;h=1-n.dot(se,p)<S.EPSILON6?n.UNIT_X:n.normalize(n.cross(p,n.UNIT_Z,oe),oe);var m=n.add(d,n.multiplyByScalar(h,c,oe),oe),f=n.add(d,n.multiplyByScalar(n.normalize(n.cross(n.UNIT_Z,h,ae),ae),c,ae),ae);A.pointToGLWindowCoordinates(a,s,d,d),A.pointToGLWindowCoordinates(a,s,m,m),A.pointToGLWindowCoordinates(a,s,f,f);var v=Math.floor(Math.max(n.distance(f,d),n.distance(m,d))),_=v;return new e(Math.floor(d.x)-v,Math.floor(d.y)-_,2*v,2*_)}function J(e,r){var i=e.terrainProvider;if(r.mode===Y.SCENE3D&&i.ready){var n=i.tilingScheme.rectangle,o=r.context,l=o.uniformState.viewProjection,c=he;c.width=o.drawingBufferWidth,c.height=o.drawingBufferHeight;var h,d,p,m,f,v,C,E=w.computeViewportTransformation(c,0,1,de),b=.05,x=e._occluder;n.north<S.PI_OVER_TWO&&(h=new P(-Math.PI,n.north,Math.PI,S.PI_OVER_TWO),d=t.fromRectangle3D(h,e._ellipsoid),p=r.cullingVolume.computeVisibility(d)===y.OUTSIDE,m=T.computeOccludeePointFromRectangle(h,e._ellipsoid),f=m&&!x.isPointVisible(m,0)||!x.isBoundingSphereVisible(d),e._drawNorthPole=!p&&!f,e._drawNorthPole&&(C=K(e,r,h.north,h.south-b,l,E),pe[0]=C.x,pe[1]=C.y,pe[2]=C.x+C.width,pe[3]=C.y,pe[4]=C.x+C.width,pe[5]=C.y+C.height,pe[6]=C.x,pe[7]=C.y+C.height,u(e._northPoleCommand.vertexArray)?e._northPoleCommand.vertexArray.getAttribute(0).vertexBuffer.copyFromArrayView(pe):(e._northPoleCommand.boundingVolume=t.fromRectangle3D(h,e._ellipsoid),v=new _({attributes:{position:new g({componentDatatype:s.FLOAT,componentsPerAttribute:2,values:pe})}}),e._northPoleCommand.vertexArray=L.fromGeometry({context:o,geometry:v,attributeLocations:{position:0},bufferUsage:I.STREAM_DRAW})))),n.south>-S.PI_OVER_TWO&&(h=new P(-Math.PI,-S.PI_OVER_TWO,Math.PI,n.south),d=t.fromRectangle3D(h,e._ellipsoid),p=r.cullingVolume.computeVisibility(d)===y.OUTSIDE,m=T.computeOccludeePointFromRectangle(h,e._ellipsoid),f=m&&!x.isPointVisible(m)||!x.isBoundingSphereVisible(d),e._drawSouthPole=!p&&!f,e._drawSouthPole&&(C=K(e,r,h.south,h.north+b,l,E),pe[0]=C.x,pe[1]=C.y,pe[2]=C.x+C.width,pe[3]=C.y,pe[4]=C.x+C.width,pe[5]=C.y+C.height,pe[6]=C.x,pe[7]=C.y+C.height,u(e._southPoleCommand.vertexArray)?e._southPoleCommand.vertexArray.getAttribute(0).vertexBuffer.copyFromArrayView(pe):(e._southPoleCommand.boundingVolume=t.fromRectangle3D(h,e._ellipsoid),v=new _({attributes:{position:new g({componentDatatype:s.FLOAT,componentsPerAttribute:2,values:pe})}}),e._southPoleCommand.vertexArray=L.fromGeometry({context:o,geometry:v,attributeLocations:{position:0},bufferUsage:I.STREAM_DRAW}))));var A=0,M=e._imageryLayerCollection.length>0?e._imageryLayerCollection.get(0):void 0;u(M)&&u(M.imageryProvider)&&u(M.imageryProvider.getPoleIntensity)&&(A=M.imageryProvider.getPoleIntensity());var D={u_dayIntensity:function(){return A}};if(!u(e._northPoleCommand.uniformMap)){var R=a(D,{u_color:function(){return e.northPoleColor}});e._northPoleCommand.uniformMap=a(R,e._drawUniforms); +}if(!u(e._southPoleCommand.uniformMap)){var O=a(D,{u_color:function(){return e.southPoleColor}});e._southPoleCommand.uniformMap=a(O,e._drawUniforms)}}}var Q=function(e){e=l(e,p.WGS84);var o=new m({ellipsoid:e}),a=new H;this._ellipsoid=e,this._imageryLayerCollection=a,this._surfaceShaderSet=new G,this._surfaceShaderSet.baseVertexShaderSource=new O({sources:[k,V]}),this._surfaceShaderSet.baseFragmentShaderSource=new O({sources:[F]}),this._surface=new j({tileProvider:new W({terrainProvider:o,imageryLayers:a,surfaceShaderSet:this._surfaceShaderSet})}),this._occluder=new T(new t(n.ZERO,e.minimumRadius),n.ZERO),this._rsColor=void 0,this._rsColorWithoutDepthTest=void 0,this._northPoleCommand=new M({pass:q.OPAQUE,owner:this}),this._southPoleCommand=new M({pass:q.OPAQUE,owner:this}),this._drawNorthPole=!1,this._drawSouthPole=!1,this._mode=Y.SCENE3D,this.terrainProvider=o,this.northPoleColor=new n(2/255,6/255,18/255),this.southPoleColor=new n(1,1,1),this.show=!0,this.oceanNormalMapUrl=r("Assets/Textures/waterNormalsSmall.jpg"),this._oceanNormalMapUrl=void 0,this.maximumScreenSpaceError=2,this.tileCacheSize=100,this.enableLighting=!1,this.lightingFadeOutDistance=65e5,this.lightingFadeInDistance=9e6,this.showWaterEffect=!0,this.depthTestAgainstTerrain=!1,this._oceanNormalMap=void 0,this._zoomedOutOceanSpecularIntensity=.5,this._lightingFadeDistance=new i(this.lightingFadeOutDistance,this.lightingFadeInDistance);var s=this;this._drawUniforms={u_zoomedOutOceanSpecularIntensity:function(){return s._zoomedOutOceanSpecularIntensity},u_oceanNormalMap:function(){return s._oceanNormalMap},u_lightingFadeDistance:function(){return s._lightingFadeDistance}}};c(Q.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},imageryLayers:{get:function(){return this._imageryLayerCollection}},baseColor:{get:function(){return this._surface.tileProvider.baseColor},set:function(e){this._surface.tileProvider.baseColor=e}}});var $=[],ee={start:0,stop:0};Q.prototype.pick=function(e,r,i){var o=r.mode,a=r.mapProjection,s=$;s.length=0;var l,c,h=this._surface._tilesToRender,d=h.length;for(c=0;d>c;++c){l=h[c];var p=l.data;if(u(p)){var m=p.pickBoundingSphere;o!==Y.SCENE3D?(t.fromRectangleWithHeights2D(l.rectangle,a,p.minimumHeight,p.maximumHeight,m),n.fromElements(m.center.z,m.center.x,m.center.y,m.center)):t.clone(p.boundingSphere3D,m);var f=C.raySphere(e,m,ee);u(f)&&s.push(p)}}s.sort(Z(e.origin));var v;for(d=s.length,c=0;d>c&&(v=s[c].pick(e,r.mode,r.mapProjection,!0,i),!u(v));++c);return v};var te=new n,re=new n,ie=new o,ne=new x;Q.prototype.getHeight=function(e){var t=this._surface._levelZeroTiles;if(u(t)){var r,i,o=t.length;for(i=0;o>i&&(r=t[i],!P.contains(r.rectangle,e));++i);if(!u(r)||!P.contains(r.rectangle,e))return void 0;for(;r.renderable;){var a=r.children;for(o=a.length,i=0;o>i&&(r=a[i],!P.contains(r.rectangle,e));++i);}for(;u(r)&&(!u(r.data)||!u(r.data.pickTerrain));)r=r.parent;if(!u(r))return void 0;var s=this._surface._tileProvider.tilingScheme.ellipsoid,l=s.cartographicToCartesian(e,te),c=ne;n.normalize(l,c.direction);var h=r.data.pick(c,void 0,void 0,!1,re);return u(h)?s.cartesianToCartographic(h,ie).height:void 0}};var oe=new n,ae=new n,se=n.negate(n.UNIT_Z,new n),le=new o(0,0),ue=new n,ce=new n,he=new e,de=new w,pe=f.supportsTypedArrays()?new Float32Array(8):[];return Q.prototype.update=function(e){if(this.show){var t=e.context,r=t.drawingBufferWidth,i=t.drawingBufferHeight;if(0!==r&&0!==i){var n=e.mode,o=(e.mapProjection,!1);this._mode===n&&u(this._rsColor)||(o=!0,n===Y.SCENE3D||n===Y.COLUMBUS_VIEW?(this._rsColor=D.fromCache({cull:{enabled:!0},depthTest:{enabled:!0}}),this._rsColorWithoutDepthTest=D.fromCache({cull:{enabled:!0}})):(this._rsColor=D.fromCache({cull:{enabled:!0}}),this._rsColorWithoutDepthTest=D.fromCache({cull:{enabled:!0}}))),this._mode=n;var a=this._northPoleCommand,s=this._southPoleCommand;a.renderState=this._rsColorWithoutDepthTest,s.renderState=this._rsColorWithoutDepthTest;var l=this._surface,c=l.tileProvider,h=this.terrainProvider,d=this.showWaterEffect&&h.ready&&h.hasWaterMask;if(d&&this.oceanNormalMapUrl!==this._oceanNormalMapUrl){var p=this.oceanNormalMapUrl;if(this._oceanNormalMapUrl=p,u(p)){var m=this;U(E(p),function(e){p===m.oceanNormalMapUrl&&(m._oceanNormalMap=m._oceanNormalMap&&m._oceanNormalMap.destroy(),m._oceanNormalMap=new N({context:t,source:e}))})}else this._oceanNormalMap=this._oceanNormalMap&&this._oceanNormalMap.destroy()}if(!u(a.shaderProgram)||!u(s.shaderProgram)){var f=R.replaceCache({context:t,shaderProgram:a.shaderProgram,vertexShaderSource:z,fragmentShaderSource:B,attributeLocations:X});a.shaderProgram=f,s.shaderProgram=f}this._occluder.cameraPosition=e.camera.positionWC,J(this,e);var v=e.commandList,_=e.passes;_.render&&(n===Y.SCENE3D&&(this._drawNorthPole&&v.push(a),this._drawSouthPole&&v.push(s)),n===Y.SCENE3D?this._zoomedOutOceanSpecularIntensity=.5:this._zoomedOutOceanSpecularIntensity=0,l.maximumScreenSpaceError=this.maximumScreenSpaceError,l.tileCacheSize=this.tileCacheSize,c.terrainProvider=this.terrainProvider,c.lightingFadeOutDistance=this.lightingFadeOutDistance,c.lightingFadeInDistance=this.lightingFadeInDistance,c.zoomedOutOceanSpecularIntensity=this._zoomedOutOceanSpecularIntensity,c.hasWaterMask=d,c.oceanNormalMap=this._oceanNormalMap,c.enableLighting=this.enableLighting,l.update(e)),_.pick&&l.update(e)}}},Q.prototype.isDestroyed=function(){return!1},Q.prototype.destroy=function(){return this._northPoleCommand.vertexArray=this._northPoleCommand.vertexArray&&this._northPoleCommand.vertexArray.destroy(),this._southPoleCommand.vertexArray=this._southPoleCommand.vertexArray&&this._southPoleCommand.vertexArray.destroy(),this._surfaceShaderSet=this._surfaceShaderSet&&this._surfaceShaderSet.destroy(),this._northPoleCommand.shaderProgram=this._northPoleCommand.shaderProgram&&this._northPoleCommand.shaderProgram.destroy(),this._southPoleCommand.shaderProgram=this._northPoleCommand.shaderProgram,this._surface=this._surface&&this._surface.destroy(),this._oceanNormalMap=this._oceanNormalMap&&this._oceanNormalMap.destroy(),h(this)},Q}),r("Shaders/PostProcessFilters/PassThrough",[],function(){"use strict";return"uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n"}),r("Scene/GlobeDepth",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/PixelFormat","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/PassThrough"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,r,i){if(!t(e._debugGlobeDepthViewportCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n float n_range = czm_depthRange.near;\n float f_range = czm_depthRange.far;\n float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n}\n";e._debugGlobeDepthViewportCommand=r.createViewportQuadCommand(n,{uniformMap:{u_texture:function(){return e._globeDepthTexture}},owner:e})}e._debugGlobeDepthViewportCommand.execute(r,i)}function d(e){e._colorTexture=e._colorTexture&&!e._colorTexture.isDestroyed()&&e._colorTexture.destroy(),e._depthStencilTexture=e._depthStencilTexture&&!e._depthStencilTexture.isDestroyed()&&e._depthStencilTexture.destroy(),e._globeDepthTexture=e._globeDepthTexture&&!e._globeDepthTexture.isDestroyed()&&e._globeDepthTexture.destroy()}function p(e){e.framebuffer=e.framebuffer&&!e.framebuffer.isDestroyed()&&e.framebuffer.destroy(),e._copyDepthFramebuffer=e._copyDepthFramebuffer&&!e._copyDepthFramebuffer.isDestroyed()&&e._copyDepthFramebuffer.destroy()}function m(e,t,r,i){e._colorTexture=new u({context:t,width:r,height:i,pixelFormat:n.RGBA,pixelDatatype:s.UNSIGNED_BYTE}),e._depthStencilTexture=new u({context:t,width:r,height:i,pixelFormat:n.DEPTH_STENCIL,pixelDatatype:s.UNSIGNED_INT_24_8}),e._globeDepthTexture=new u({context:t,width:r,height:i,pixelFormat:n.RGBA,pixelDatatype:s.UNSIGNED_BYTE})}function f(e,t,r,i){d(e),p(e),m(e,t,r,i),e.framebuffer=new a({context:t,colorTextures:[e._colorTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._copyDepthFramebuffer=new a({context:t,colorTextures:[e._globeDepthTexture],destroyAttachments:!1})}function v(e,r){var i=r.drawingBufferWidth,n=r.drawingBufferHeight,o=e._colorTexture,a=!t(o)||o.width!==i||o.height!==n;(!t(e.framebuffer)||a)&&f(e,r,i,n)}function _(r,i){if(!t(r._copyDepthCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n}\n";r._copyDepthCommand=i.createViewportQuadCommand(n,{renderState:l.fromCache(),uniformMap:{u_texture:function(){return r._depthStencilTexture}},owner:r})}r._copyDepthCommand.framebuffer=r._copyDepthFramebuffer,t(r._copyColorCommand)||(r._copyColorCommand=i.createViewportQuadCommand(c,{renderState:l.fromCache(),uniformMap:{u_texture:function(){return r._colorTexture}},owner:r})),t(r._clearColorCommand)||(r._clearColorCommand=new o({color:new e(0,0,0,0),stencil:0,owner:r})),r._clearColorCommand.framebuffer=r.framebuffer}var g=function(){this._colorTexture=void 0,this._depthStencilTexture=void 0,this._globeDepthTexture=void 0,this.framebuffer=void 0,this._copyDepthFramebuffer=void 0,this._clearColorCommand=void 0,this._copyColorCommand=void 0,this._copyDepthCommand=void 0,this._debugGlobeDepthViewportCommand=void 0};return g.prototype.executeDebugGlobeDepth=function(e,t){h(this,e,t)},g.prototype.update=function(e){v(this,e),_(this,e),e.uniformState.globeDepthTexture=void 0},g.prototype.executeCopyDepth=function(e,r){t(this._copyDepthCommand)&&(this._copyDepthCommand.execute(e,r),e.uniformState.globeDepthTexture=this._globeDepthTexture)},g.prototype.executeCopyColor=function(e,r){t(this._copyColorCommand)&&this._copyColorCommand.execute(e,r)},g.prototype.clear=function(r,i,n){var o=this._clearColorCommand;t(o)&&(e.clone(n,o.color),o.execute(r,i))},g.prototype.isDestroyed=function(){return!1},g.prototype.destroy=function(){d(this),p(this),t(this._copyColorCommand)&&(this._copyColorCommand.shaderProgram=this._copyColorCommand.shaderProgram.destroy()),t(this._copyDepthCommand)&&(this._copyDepthCommand.shaderProgram=this._copyDepthCommand.shaderProgram.destroy());var e=this._debugGlobeDepthViewportCommand;return t(e)&&(e.shaderProgram=e.shaderProgram.destroy()),i(this)},g}),r("Scene/GoogleEarthImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicTilingScheme","../Core/loadText","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t,i,n){var o=e._imageUrlTemplate;o=o.replace("{x}",t),o=o.replace("{y}",i),o=o.replace("{zoom}",n+1);var a=e._proxy;return r(a)&&(o=a.getURL(o)),o}var f=function v(i){function n(e){var t;try{t=JSON.parse(e)}catch(n){t=JSON.parse(e.replace(/([\[\{,])[\n\r ]*([A-Za-z0-9]+)[\n\r ]*:/g,'$1"$2":'))}for(var o,s=0;s<t.layers.length;s++)if(t.layers[s].id===g._channel){o=t.layers[s];break}var d;if(!r(o))throw d="Could not find layer with channel (id) of "+g._channel+".",f=c.handleError(f,g,g._errorEvent,d,void 0,void 0,void 0,m),new u(d);if(!r(o.version))throw d="Could not find a version in channel (id) "+g._channel+".",f=c.handleError(f,g,g._errorEvent,d,void 0,void 0,void 0,m),new u(d);if(g._version=o.version,r(t.projection)&&"flat"===t.projection)g._tilingScheme=new a({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:2,rectangle:new l(-Math.PI,-Math.PI,Math.PI,Math.PI),ellipsoid:i.ellipsoid});else{if(r(t.projection)&&"mercator"!==t.projection)throw d="Unsupported projection "+t.projection+".",f=c.handleError(f,g,g._errorEvent,d,void 0,void 0,void 0,m),new u(d);g._tilingScheme=new h({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:2,ellipsoid:i.ellipsoid})}g._imageUrlTemplate=g._imageUrlTemplate.replace("{request}",g._requestType).replace("{channel}",g._channel).replace("{version}",g._version),g._ready=!0,g._readyPromise.resolve(!0),c.handleSuccess(f)}function p(e){var t="An error occurred while accessing "+_+".";f=c.handleError(f,g,g._errorEvent,t,void 0,void 0,void 0,m),g._readyPromise.reject(new u(t))}function m(){var e=r(g._proxy)?g._proxy.getURL(_):_,t=s(e);d(t,n,p)}i=t(i,{}),this._url=i.url,this._path=t(i.path,"/default_map"),this._tileDiscardPolicy=i.tileDiscardPolicy,this._proxy=i.proxy,this._channel=i.channel,this._requestType="ImageryMaps",this._credit=new e("Google Imagery",v._logoData,"http://www.google.com/enterprise/mapsearth/products/earthenterprise.html"),this.defaultGamma=1.9,this._tilingScheme=void 0,this._version=void 0,this._tileWidth=256,this._tileHeight=256,this._maximumLevel=i.maximumLevel,this._imageUrlTemplate=this._url+this._path+"/query?request={request}&channel={channel}&version={version}&x={x}&y={y}&z={zoom}",this._errorEvent=new o,this._ready=!1,this._readyPromise=d.defer();var f,_=this._url+this._path+"/query?request=Json&vars=geeServerDefs&is2d=t",g=this;m()};return i(f.prototype,{url:{get:function(){return this._url}},path:{get:function(){return this._path}},proxy:{get:function(){return this._proxy}},channel:{get:function(){return this._channel}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},version:{get:function(){return this._version}},requestType:{get:function(){return this._requestType}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),f.prototype.getTileCredits=function(e,t,r){return void 0},f.prototype.requestImage=function(e,t,r){var i=m(this,e,t,r);return p.loadImage(this,i)},f.prototype.pickFeatures=function(){return void 0},f._logoData="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAnCAYAAACmP2LfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAHdElNRQfcDB4TJDr1mp5kAAAAGnRFWHRTb2Z0d2FyZQBQYWludC5ORVQgdjMuNS4xMDD0cqEAAB1zSURBVHhe7ZwHeFTFFsf/u+l9N70npOxuSAKEFFIhCSH0qhEQUHkgKCgWUFGBB6IoCAoo0ntooaRvEkIIBBBpoYSa3nvvfd+5u4sQUigPfMX8v2/Y3Tkzs3fv/d0z58zcgF69Ql1SY+MM1wQJem44ZeiJk8beEOqPwG6uC7ZqyElb9eo/JZEIkH2nRQkBIlNMauuPCS3uGN/kjkmNDghoskBAgzrZ2NLmf1+JwIKQpYsoxdmIV9+N07onCegzBPM9bOdmYKnazF6g/1N6UySPqSJzvCaaiLHtP8G/Phq+FRfgU5ogKWUXMLT6Mvzqr2BE40mMadqO8c3zMabBC6PqDDC8SlY60t9HByCLVTKu+ERmHr5TWI9wjVxEaOZivWo1pil8D1tZeWnLXv1l8iZ3PF2kjymiWRgvCoJv5U243IyAXcQq8A9Mg9W+4bDe6wv+kVGwCZkL+4Sf4ZR+BZ5VGQR3EkbWn8Hopm3wq54Lz2JD6ah/P21XGopQ9Qoc16jGSqVyTJWbQbUsibFXf42mihTwZpsvAtp3k0dOhFOSEH1+ngaDefrgjFCgFkxY8fCisCBvKgODzxRh9qslBFGfYmDGLbiV5mBwRRo8KtPhVBgPu8teMP7u73chD6kMRYRGBY5xqrFKqQwz5SdTbS/Qf5mmUYw8rf01CjHC4VP7AHZxO6E3qy9ZZCQNnio2rE/4o9/tkxiQUYp+KRXgx8XC5FsXcLz/hkCrDUU4pxLHuDVYpdwL9F+qqSJZKlPwenskfOoI5tN7YPCJGVme7wKYr5EBXzgYfW+mwTI0Gjrznaj2WW+I/y8dVPdDGLcKRzXrsEqlHO8oTKHaXqAZWe9hQXCi63NhHWYI3ilfWIW/YLjqL2JRiOFBJRz+LffhcPs09D+0J8vzn3zXdBnYnp8Mi6NboTWzH9X8fVc+DhDQodxqAroe36lU9AJNWr4cEAjNwI8OAC9cT1rbUfzwGeCfKiL7dGnNc+q1NiO80b4BY1oT4V6WDcsdc6j2xbyq4wMWrA9rQmeWFn36ey/jBaoPQ4hmLYI0G/AtAf22fC/QDols8ITrIYi/Bl6knbS2o3gRbxHQxQQ0k0S/gCa2v4OJovPwacqAQ1ICjL40klr+UrWoQbFBETo18jCpZsOoFODkvuCNJYoHW3QKXFEM7ETRcKfiQe8d6NVIFImXvg4skhY40mxnQYVRIIeA1qrHEc1GrFSpxFtP99AiFbDbNKDZpAzzGkVYVcvBuBJQEo/9/6C+dyjPitwLwak74D8V6Bfw0P5VShjXFoTR7TfhUZkL29M/wfATJan1lauWC3aDOgyaVDCuTgbf1bFkfmtkye1ogsK2asivLYfCglIoD8qCknI2NHuG4QSVGMgQyMbt0fioRYh9VYcRU7QX55uDcaHtFOJEsThMtmWtQgxsDodsWaC0c3ea3MzGBJEqxrfbYmzr6xjfPAeTmt5HQPO7eK1xDibUz8eY+k8xtHYJPCtXwvHOu7AXMrMTsF/TH8HajTis1YwVqpWY0TXQDKy1OpBr5EJA52Fukxx+bmKxtjWx2DuaWawNlZD5qhzyo9KhpHAbKpJO/6t65UCPbPHA2PYrGNacgkElabCJJDev/MpDhUKKnuq44LRoYEK1IiswkS1zYCfk5y+F0qjvoTwqBOof34dGeAnUL1ZCLboEnJ9zoe0QD/Nuj00UBVXRabzVLETM3S0ICfwA8yc7Y6C3ANYbZsA7aQ1W1xzEfZEQ6dT2BkG9pP4ouo7jGE1u42JS20QMrzkCr4xwuN4+AM+cYII3EaNar2J86zmMrP8DHulCON4NhU3YWuhOYy6SZENpH9cfx7WacFC7BSvUqjBDsRPQIiugURvazeqYVaqAw6dYrJ9WQy7gayj4nYDy3HtQOVQGpYRqKEWXQf2HdGha/AFdae9Xr4czz0ubISRA75ECbSut7agegO75OLxpahze8j5GtifBpzEDLiV30Dd2mNT6StWiCbVmLt5rUkBQCEt2zWzIMSA8HgrIBkLD+Sp0jhHISYXQ/KMYukfvQ3fQxq68XCTBHId/tMTg7LV1CFs4BszJ6hBarBgHlcRv8H7tbuSKQpFPYGe0BmND+nZ0npECaPKf0r4UIxsuoF/IMpitsAVnrA4s15uh3x8fwLXkLobUZGJIXTqcUzbDaJE5FAVq0t4S7dEcjqMEc6B2K5arVWN6Z6AbdOmm5mJelQKOHWSxF44Cy4CqxW0s6RwchCovFRohdGNfLgX3WiZ0N4aD++y7jfwYJUrAPCle/ZjKV+BFTSegrGAZIm3QjXhBytTWB3zhByzryMUU986jz16wD+96ijCNUIAgmkc3tS6G7GERjCbgR82B4OTbEESqIiCIcqsIYzoGGyrBEMSmgh8xBoIIAR2fAHZhj8Z9DOhl9FHeKkSDvn809fuc+iyCddRYaiOZBTvIt1YJfs0b4N+WDO+GHPLQN2Ab7S61vjJV60C9SRPvNSqzTpxlyQfS1dGUmjppK7gW16B/LhN6abnQu5cDwzO3YNhhqqK4WJY887sEdGzWFpxfOxmDpKZOOvgWFB8sx9L6nShvP4FyUQjKGg5gScpGKEqbUE7RxiGYv6QQ4zIG/r4D2m88sjEy/EIW/a6+TQ4gHe5VhXCvy4JL7gLYnesI2i6t4Tii04r92u1YKt767gB0ozrkGzmY26zEOh7Hkt+kAKhLTX9qOVVdg9aoNOjcToR+wUVKLYKgN0Zq7l7884wn9CKgr4AfWw/B6SwqKQRKOdXVghe9CpbherASSjtIpGpxRIHFjwygNreoXy0lb+lU7lHJBP9kPcGXQnBNghUB/Lh44fbUp5JA+5Hs71LbPPLCVRDEJZDNGIJgeQI6mG6KegKzldq1U7tGKjQmHR8vwl86kgRoAQN0xBw6ztn0nQ/ocxEdQ7L4d/BjG6g+m8aZTL/xsXPuW82Fb8t+DG1Ox5D6XAwqvQ67OA+p9ZWoUQPsei78mjSwNU9GLmEzVGZJTd3qFPTn3YZhXgYMMjNhlHsDxms/hNWfoUdrNPgEc2h7BG5d/Bo7Blt0BuNxXf4MVmXrkdRyEHWiY6hr2oc7mevRX2wc18gioEeI1+N9a+/CNnImVAZ0mhEoNOPAJT8MHjUF8KTiWhqHgbfMpVaJdhLQh3XasU9bJAZ6ekeg6zQwgEKuLSWysmd3QGmatLqD8qDNug3dCX/AIPk4jGr2wDB/JXTmkan70IvmZTY/rB9BdZlKLkG0lG0d5klAObKsw1+jzyFiWPnRawiaDrMYwTyMwMwh220WP2IWFVfqN4CKO8E3n0C6R/ZUej9Y2kUiMdDRFTRePH3nA3q/m7xpAEtAXl0QrkTwscnmS/3eptdzNEYevZLnZ5booqk8tuYs9tAny+n1LL1mghezlcULH0VtHamOZhvhIvoNOXQsd2EZIbluYnlWaMO75TCFG9kYXJ8H14o76H/10Z3yClSrCm6jGtbWK7LC7kIlYRfUmY2XHnUa+mbXYRSfCuNCptyE6b1jMBD/EPKwchQPLxGdxOWWI8iKXYBPqLozgI8pfA5YBWvxbfMeNLUfRmPTLjRnr8YKsdGvRQ5j2zZTSSRQ78H+7GhxfScFAINypsG9ukDspZ0LKKE+O0pqlGi71ggcIqD3dga6RhFKjSqYT+VEFkvu/E9Q+HNWKaE2VVDgVkPFqwAaay5CN3En9M59BM2vfKDs7AvljjPGE5LlharQdL+LoCmhOHU0rIUyD+NgVTOa+q2iVQiIcAKpHtbhXuJOjPqeVCRYThNE6VTvKNs3hM3cHGIxntxKyCbP7Erj1lHZJbVIJAG6iiCroZCAPGukvOyASJbvCgoaAoKoAQ1kHcGC7nmZDkmhBR2PfSQLtkcl4zCSAE2eO6qExYuYxrE4KqdvelBiM4+ncYQy1IY8d0wbhUSLJAZGbsUceNYdwJCGPAyuy4NbZToG3JoO1Qk9AvHvqF4ejo0KCKlisyl04Jw+AE1ma71HRUJP+QqM1t2HcVEyTEoSYVYQCuN3HenCt4XDhGA+KorAnYZ9KIj5ELOl3XpU/k/wrt+OmraDaG7cjpacbxFvYAAZDG5Vw/DWCxjRdp+ATsWAS6+D69H1+XDNsoVb1T06b0VwzCmBIOYdqUWibTojcFBH1CXQctBtUcA6Oh/RmVC4sBmKA5j6erC1qqE4sRpqG25A43QIOHuXgvOmP5R4ZH6m5UY2L9SSLjZ5sKjjsI/o8olH8ngjCZoSgmw9DMIl3t42Up0g+pq89/sEjLK47knZhSkSuDepJP4JOyNJyEFAR8VQKMOR1nbWM69yxNJYwh+VLE90ffPyxLE3EwL9Jq0huWQqwL1iA7zq8+FVl0+epgBO6T+gb2TH+OglqgastxtZrNNlkLt8E5oJx6HZdab7mFZBk3UZRjMewCT7HkzLfodZxREYr5sBjiIBPYiAPt8ehvSGPSg5vwjzpd16VNkmmDTswp22QDTXbkJrxhJkzHGDFoUQmvBpvo2hrZl0TnLhlLIYfUO7nt7dSg3hURcP1/JiDEgphuXBqVKLRFsfA3oJAf3mI6Cr2OjTwGYdqWGzzmZD6WoYVCfehdqsZKjuuwS1oB1Q+5piHac3oaxBzZ9vLZ4nHEeesoXg6niDPSYWP9yUgD5PHu48eKE64krHcErchHIEuRysTpAXjObQWIYEHiV4EQYEojp5aEoyY+IIpOQugKYYOnIdJXrdJ63PtWwXMQM6m6SVT4gfZkbHV0XHsVtaQ3K8yoJr0YfwoHDDq5ZiQSqDik/B4Q9taYtn18gyNia1qGJsmTrGlUjK2FJ1jCjRwOASDnkxDvN95ZD/og5yl0qgfCMJ2leDoeksHaFHXYOJVyrMkm/DrPwMzGr2wmjnLGipthyHL0W7t9pDkduwF2U3lmGFtvbTdyirt0OreT+iWwPRUrUBbSkLkT/fCUZwKVYikBMwpDlPXNzLwuAQ2rWX8KzUh2dDDJyLSmB7/S5Mf3WRWiR6CPSezkCXQs6qBnLCKsheyoXqnTCoL9oOFd9/Qtl9KJT6UJMX3/zhCz8iuCjhiviSYtMx3ZTJBN8lCE7eIRgF0p6krRRaRBDskTTGySBKws5SuUjJHYUiMQdpzCUE0Q3y5MnSDhJJQg5JUvjSgO5hHZofaioGmvc40IycMgbRtJktjgOZ5Ma9irzSg46xYHcaVEZevkgBHqUWGFK+FENKQ+BdGAq/wiMYWbwHI6h4FwTDOes0BMKFMHxPNg9qn1dANakYanfuQSs5FJoTpaP1qBswsSGgb9+EeUU0Af0LDH4dBhXlmv3wajuOpPYQFDcEojxtNQ6sn9ZzUsiofjfUWg/iYOt+tJatRtvN95DqZgxNuKTKwLV4Jdyqc8Wz1uCGTLjmDIVDQqewQ8anwpJi6GsYkF4Ey2O/QvsfXKlJIgboAwT07s5AZ0G1TylUIsuhdKMI6vcuQ3PVAqg+9UZ8JvGEywiuNoIwD4IzaV2X+HSa1otgE3+NwJImVkycG0kx8snfyUZJW+QFApeSu+hN9BpIn6n+ZBp9bqDv+C8Fum+8IpzzJNOmR3UhTaGFcC07iAHXmamuZw28C/S/aIt+CcthF7+ToN0EQdhqOFzcBu/Sm/ApvAGX3DzYXIiF9jtWTJf74L6ZC83UfGg8SId2xnloSZKxp+gWjC0J6KSrMK8KhmnlSugtInpkCzaBV78Hl5oPoaLpECrLt+Bi4jfgS7t1q+YDUGsPwj5KDFsLlqD97JuIpmpZmP+TftM1ezjlxsOllM4H3eReDWHwKrOBW84jqMeK5OBTv4Bu6HxxgqU1s/N3MkAHSoH+ioCe+gjoJHB0s8ENLID6/UJo3E+GVlwoNEwY278tXhR50RhmeexzgmM8JXjdF36MHwEoiXn70Csv6gxBm8PiRc6gJFD1HDzFpq1cP0omo5QJZAfqQzH0f6uHZjQgeR4cC/IJZCnUtSkYVPAWBiX2/CdU/S7Ql+9TgtFCTaiP0qAEXA2yRsqwuzECziWZcM4tgv2DSljF7ID+l+JNh9+hY38HuvcYmLOhk5EEnVPfQOmpW+33YGaXhj53E2BWuxvGebOh5cPUX/sWSgXrsa9mB2qaDqCK4C7I2IA3jn8u7tat2g6D034MIbWb0fZgHlr2DscXUhNNuYdkYRPrg/7JiXDMLYBrZS6GNEZgVJM/JjWY4I16G4xr/BCDq2nKjjoAvY+Zpwo7eXBskQK9Swr0lEdAn4a2wk3o/DMNWmn54KYUQIuZsebGQuXFQ42H4kfNk4QckSOkNZ1lGkGAUoInOKkAm2jJsVtH+om9Nj9ytZxNcNdhljXByo+JJXj/i4G2u2xM02YInPJLxFB7VudTPH0ZHkWu0hbPpwHpfnAszoFDVgVsb1fDMmoL9L8S7wTFQE/1AvR33oB+QSp0czKgl34B2iO9uwJCKib5SGaZjbqLPlkhMG1YDr1gQyioSs24vQTDitagsnIL6loCUVu9C2EJK9FjYtsWBNP2Q7hb9A155zdwY5mTeGexo0w32hEcy2F7JQaOqZfgk38KY6rDMKFBiGHNt+iGPgCNYd0/s/sbAb2fgN5JQC9Wq8bkR0AzioOOx3Xo30mGbnY+tNMKoJOQCm03qfnFxRf6E1yUFAqZJcyuZRWuQmB+TWHJcgJfkjPxImcSSIUsXviMx/O9DvqfALrPDjb6nhuBAWkZ5JFKKTYuIqhz4FUdAo9CGwzO7Ra2LjUg0w9OxdlwyKxAXzHQm8lDi4HeAT1WMPSHnYXR7aswKE6Gfl4K9PdfgZ6+uG8XSmMbKyXD/LsEmFduglH2NHA7rA3Hvg+Ve1/gYO4KNFRvQUPLQVRU7MG4yn1dJ4eiULAo3JhW9xsa77+Hml8GY8FQ425uAM5wRRivNoPlTjs4XhoH35oLGFZ/S/wglyDkbWmrrsUAvY+A3kHlSwJ6ihKzCvLnuQyElmIs9LdfhmHxA+jn5kI3jcrRFOjxU6DTbTx9DybsOBh0f034EeYEVyaFD0IYhnQ9y1pTIsiPvU5AnKYkUBL78yKmQhDLgDRPSWtPp/HFkFtHqFCfRBr73wX67qsD+qFsEubCnqKBAZllcCkkT12RjSHVMfApH0bJXfcH+aQGZg6FU1EWeeoK2NwgoMM3Q++zP/fq/Smf2g392ZEwzk2Acfl9GBHURmuSYPyn132oHBizH8B8wjX0SadQI2cWtOZZQbHTdEgRn8XN93EiczFayn5GU3Mg7lJMPab5SEeoCWZZ0TF4Ne/A/ZSPUbXdDz9Qdddrrk/KtcwR7jX34VXDzGCFGFT0GzyLu922x069kdiv145tOu34jlOHBWoz4arUAZQt0LYOhmFcHJ2H6zAsYnZDc2FwKhv60+m9UQrLUJ4hSYQAVhpM1O6jj30EDD33Q6frZyoY8cMVaWZZR560kuB5V9H6iVUas+Py5L1/IHsT2ZldR4nEkMdkUd8Y8tYd43mLIMhYhenDWvgjQSQiGFOkiEv0rEAzK2u8yG10M2WwBWFdb6q9NKDNd6rCOuYD9L2VI/57QMfcEniU5cCnJgG+lR9haAnz4MzT5ZjmA4e8HBqnGtYXamF+nK7bpx0uwHxoqGyE3sKD5HHjYVJ1C6Z5qTD5Ph2G1hnQEV/0LBhxU2E+4yYsbgTCJGsuNBfYQrnjA0CPxDo2CRYJ0xGesgD1ZWvQ3LQbKeSJ54uC0UcUDVVRGExFR/FB2y7cSf4C+Zv9sXSUeQ9P2z2pQdnmBHQsPKqKqFCyWJsM75o1GMw8O/iEhFZs/KK9CD9wRfhCTYTP1dqwnBOHrQYz8IuuH5ZxxI/MLQZH5kfoeu6D4cVQGNecgXHFbRgXZsD4Xg5MjqfDeE0KTBbRDLXsLiwOR8HkxCJoOs+Eavdr08ZBBGdYP7rYzAZILsH3LYUYtgSsAXlYRwLqW0r8Ksl2id4/Onaz47IE+kayUfwddYhsgwkqXRrLgOpHEuyhVF9B7ytoTAL//qNjeFagGfGEi5nvYPEifqOx/ek4p1J/8aKBWC8N6Icy2+oL6zOhECTmw46SuoHZpXBn/pK7/DK8K1bCp3Q0vAv7wqfIBD55OuS9teFVYASPfAFccseThw+E4Ho5LOMqYB6ZCeOdK6H1bleJH2sOOPZradqlC3otDqY5F2GafQmmCZdgFnMBZteEML2yCnprh0CZWVp66gbDuD5Q2uSLUacm43jSB0gq+h55JeuRX7wRqUUbkJL8DS4GTcPqCdZgduZ6XiZjgvcp9fIY3aAH/yY+3KvcMDBjLSXQBXDML4VbaQG8a9PgUxcOzyIneKY/Or6FHDO8q7INY+RiMFJaJijE4i2VeEylej/FDs99TAPH8Dvofv8bDK/vhVHxMRhX0W+vOgXTijiY5UXANGkNnYeRUGN2VrsPNx6XVaQNgRNM03sBgUjeOKJJ/Cr+LNzFsg61YB5/elyKtic0qM031CaZAG0gqJnVEuYBIoI49gy9D6DXrQR3GoU2j3YE+WE2FI9TGBG1FLywnhNbPt1Y/OhY+o5iGqsGNmdLaVxfqZUB+g0Iztwi2AOkNZ3FCzOm30bHeHK9tKYHKfPZMFhlAtM9c2EpjALv93zY3qlE/8xyOOUVUTiSBrfy83CvDIdbRZC4uJSGwzHzd0qgkmEVfRnGW/dC79vPobtkFLRmm0HDpVt43MnrzoOm/dfQeeOf0P3wB+guJogXrIDuhHfAsdOFbKdQ5GkaYQbNNYNht2c8/AOnYNKB6Ri//Q14zRwIuohdPC76pCbWKGFCkx9GNC7B0NZD8CiJh8Odi7A59zud7EuwvU4hVUYZBhUXwqsqA56V0RiUM1Dam36UoiyFuprQhc6fRZuKKhV5+rcLKD2hrPQ+NPsvgNb0j6C9eCG0v/kU2l9/BK0ZM8EdRJQ833noG8Qib6lDkA0lYD6i8GIJlffZ/IhhbJtQjW4TP164EiWWztTnH9T+a4L/MxpjAn02hWWYDAQnefSZzm7Io7zDOpiSzGh3grwPwd3zDccPZdH4phBEkXcWBrD4wlE07qObw5pmBUGsK43T/YPfgmAFWEe5U2EeCXhGcV5nQ3u2KrTf6w+jdTNhtud7mB/ZC4vg43QAwbAMDYLF0e3os+8HGP80D7oLx0F9dD+oj9AGZ4Y85K0Yj/Vs3kQiFgeybFPIySiDzdwAz9O3JzHjPNtYk8gjv948FOOatlGodR0Dk07Bau9n0F8wFBp+luBO1CXeuDD51Q3830PRP7UIzgUlcC0vhHPRSdic6eI53ecT3W0sKyjI2EFRxhzyz3sOO8voBkEUTclYhAyshCwr642PR79diwlbBOEs8vLMFjgbbuelhpeoz5rEDxsNNl/+9ON5RWJOLsXCysQdh5IhWWbzhUmoel6v/l/RxGpZTKgbh3EtEZQMp5AX2ASd2f3AVu7695ky/7nOuc2U/BZSCFIGp+I82F/rfprsVa/+Mk0sZ2F0tTvGNZ+gRO8B7C/HQ92beWine+/IDWDBbJUmbBN/hUNOGRyyStH34vfQeP3ZV4R61atXIu9Kefg1rIB/XRJciwso9nymLXmxbP+wxcCsVAxIKwfv1AZoDH96jN6rXr1SuVeowKsuFINrs+BSXATbc59JLU/XwCwdDMw7B/vUEpgHfQYZ7v9HCNar/2E55ynDpSwYrhXF4uKUeQiY0/Oy3kM555nCITcJgmvp0F30Yo8L9KpXL1X9E2XhkPoVBuYWwbmolKDOhmv+WHiXyGNkgbTRE1pOublXkRycCz+AfUoRzPdsgKJN1w/19KpXf7n6xlnCPikE/SkWdswrozDkNoZUfIWhFTYYWaPy4a6NkgSR2XAZXSOLIWUWcCv7FP1T7sH8wFZwp7ycxz971auXIm4AG+b77MFLEKLv7ULJMy0FefCsPAOv0t0YUrIMg0s+gVfxYrgVbIJLUSzsrl2F2ZZl4L7J/Pdp/956ca969UrEna0O41/HwSJ4F3in42Fz5Trsbt5Bv3u30e9uImyvnoV15GGY/LIA6kOZP1966pZ8r3r1n5eqhwZ0F/aB4ToHGK9zh/FPHjD60RE6H1tDaaA2cdy7mvFfI+BffksPNrEksu0AAAAASUVORK5CYII=",f}),r("Scene/GridImageryProvider",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","../Core/GeographicTilingScheme","../ThirdParty/when"],function(e,t,r,i,n,o,a){"use strict";var s=new e(1,1,1,.4),l=new e(0,1,0,.05),u=new e(0,.5,0,.2),c=function(e){e=t(e,t.EMPTY_OBJECT),this._tilingScheme=r(e.tilingScheme)?e.tilingScheme:new o({ellipsoid:e.ellipsoid}),this._cells=t(e.cells,8),this._color=t(e.color,s),this._glowColor=t(e.glowColor,l),this._glowWidth=t(e.glowWidth,6),this._backgroundColor=t(e.backgroundColor,u),this._errorEvent=new n,this._tileWidth=t(e.tileWidth,256),this._tileHeight=t(e.tileHeight,256),this._canvasSize=t(e.canvasSize,256),this._canvas=this._createGridCanvas(),this._readyPromise=a.resolve(!0)};return i(c.prototype,{proxy:{get:function(){return void 0}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return void 0}},minimumLevel:{get:function(){return void 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return void 0}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return void 0}},hasAlphaChannel:{get:function(){return!0}}}),c.prototype._drawGrid=function(e){for(var t=0,r=this._canvasSize,i=0;i<=this._cells;++i){var n=i/this._cells,o=1+n*(r-1);e.moveTo(o,t),e.lineTo(o,r),e.moveTo(t,o),e.lineTo(r,o)}e.stroke()},c.prototype._createGridCanvas=function(){var e=document.createElement("canvas");e.width=this._canvasSize,e.height=this._canvasSize;var t=0,r=this._canvasSize,i=e.getContext("2d"),n=this._backgroundColor.toCssColorString();i.fillStyle=n,i.fillRect(t,t,r,r);var o=this._glowColor.toCssColorString();i.strokeStyle=o,i.lineWidth=this._glowWidth,i.strokeRect(t,t,r,r),this._drawGrid(i),i.lineWidth=.5*this._glowWidth,i.strokeRect(t,t,r,r),this._drawGrid(i);var a=this._color.toCssColorString();return i.strokeStyle=a,i.lineWidth=2,i.strokeRect(t,t,r,r),i.lineWidth=1,this._drawGrid(i),e},c.prototype.getTileCredits=function(e,t,r){return void 0},c.prototype.requestImage=function(e,t,r){return this._canvas},c.prototype.pickFeatures=function(){return void 0},c}),r("Shaders/ShadowVolumeFS",[],function(){"use strict";return"#extension GL_EXT_frag_depth : enable\nvarying float v_WindowZ;\nvarying vec4 v_color;\nvoid writeDepthClampedToFarPlane()\n{\ngl_FragDepthEXT = min(v_WindowZ * gl_FragCoord.w, 1.0);\n}\nvoid main(void)\n{\ngl_FragColor = v_color;\nwriteDepthClampedToFarPlane();\n}\n"}),r("Shaders/ShadowVolumeVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec4 color;\nvarying float v_WindowZ;\nvarying vec4 v_color;\nvec4 depthClampFarPlane(vec4 vertexInClipCoordinates)\n{\nv_WindowZ = (0.5 * (vertexInClipCoordinates.z / vertexInClipCoordinates.w) + 0.5) * vertexInClipCoordinates.w;\nvertexInClipCoordinates.z = min(vertexInClipCoordinates.z, vertexInClipCoordinates.w);\nreturn vertexInClipCoordinates;\n}\nvoid main()\n{\nv_color = color;\nvec4 position = czm_computePosition();\ngl_Position = depthClampFarPlane(czm_modelViewProjectionRelativeToEye * position);\n}\n"}),r("Scene/StencilFunction",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={NEVER:t.NEVER,LESS:t.LESS,EQUAL:t.EQUAL,LESS_OR_EQUAL:t.LEQUAL,GREATER:t.GREATER,NOT_EQUAL:t.NOTEQUAL,GREATER_OR_EQUAL:t.GEQUAL,ALWAYS:t.ALWAYS};return e(r)}),r("Scene/StencilOperation",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={ZERO:t.ZERO,KEEP:t.KEEP,REPLACE:t.REPLACE,INCREMENT:t.INCR,DECREMENT:t.DECR,INVERT:t.INVERT,INCREMENT_WRAP:t.INCR_WRAP,DECREMENT_WRAP:t.DECR_WRAP};return e(r)}),r("Scene/GroundPrimitive",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/GeometryInstance","../Core/isArray","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/OrientedBoundingBox","../Core/Rectangle","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Shaders/ShadowVolumeFS","../Shaders/ShadowVolumeVS","../ThirdParty/when","./BlendingState","./DepthFunction","./Pass","./PerInstanceColorAppearance","./Primitive","./SceneMode","./StencilFunction","./StencilOperation"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e,t){var r=t.maximumRadius,i=r/Math.cos(.5*e)-r;return B._maxHeight+i}function D(e,t){return B._minHeight}function R(r,i,n){for(var o=n.attributes.position3DHigh.values,a=n.attributes.position3DLow.values,s=o.length,l=i.mapProjection.ellipsoid,u=Number.POSITIVE_INFINITY,c=Number.POSITIVE_INFINITY,h=Number.NEGATIVE_INFINITY,d=Number.NEGATIVE_INFINITY,m=0;s>m;m+=3){var f=t.unpack(o,m,G),v=t.unpack(a,m,W),_=t.add(f,v,H),g=l.cartesianToCartographic(_,q),y=g.latitude,C=g.longitude;u=Math.min(u,y),c=Math.min(c,C),h=Math.max(h,y),d=Math.max(d,C)}var E=j;E.north=h,E.south=u,E.east=d,E.west=c;var S=p.fromRectangle(E,B._maxHeight,B._minOBBHeight,l);if(r._boundingVolumes.push(S),!i.scene3DOnly){var w=i.mapProjection,T=e.fromRectangleWithHeights2D(E,w,B._maxHeight,B._minOBBHeight);t.fromElements(T.center.z,T.center.x,T.center.y,T.center),r._boundingVolumes2D.push(T)}}function O(e,t,r,i){n(e._rsStencilPreloadPass)||(e._rsStencilPreloadPass=v.fromCache(V),e._rsStencilDepthPass=v.fromCache(z),e._rsColorPass=v.fromCache(k),e._rsPickPass=v.fromCache(U))}function N(e,t,r){if(!n(e._sp)){var i=t.context,o=x._modifyShaderPosition(e,C,t.scene3DOnly);o=x._appendShowToShader(e._primitive,o);var a=y,s=e._primitive._attributeLocations;if(e._sp=_.replaceCache({context:i,shaderProgram:e._sp,vertexShaderSource:o,fragmentShaderSource:a,attributeLocations:s}),e._primitive.allowPicking){var l=new g({sources:[a],pickColorQualifier:"varying"});e._spPick=_.replaceCache({context:i,shaderProgram:e._spPick,vertexShaderSource:g.createPickVertexShaderSource(o),fragmentShaderSource:l,attributeLocations:s})}else e._spPick=_.fromCache({context:i,vertexShaderSource:o,fragmentShaderSource:a,attributeLocations:s})}}function L(e,t,r,i,o,a,s){var l=e._primitive,u=3*l._va.length;a.length=u,s.length=u;for(var c=0,h=0;u>h;h+=3){var d=l._va[c],p=a[h];n(p)||(p=a[h]=new f({owner:e,primitiveType:l._primitiveType})),p.vertexArray=d,p.renderState=e._rsStencilPreloadPass,p.shaderProgram=e._sp,p.uniformMap={},p.pass=T.GROUND,p=a[h+1],n(p)||(p=a[h+1]=new f({owner:e,primitiveType:l._primitiveType})),p.vertexArray=d,p.renderState=e._rsStencilDepthPass,p.shaderProgram=e._sp,p.uniformMap={},p.pass=T.GROUND,p=a[h+2],n(p)||(p=a[h+2]=new f({owner:e,primitiveType:l._primitiveType})),p.vertexArray=d,p.renderState=e._rsColorPass,p.shaderProgram=e._sp,p.uniformMap={},p.pass=T.GROUND,s[h]=a[h],s[h+1]=a[h+1],p=s[h+2],n(p)||(p=s[h+2]=new f({owner:e,primitiveType:l._primitiveType +})),p.vertexArray=d,p.renderState=e._rsPickPass,p.shaderProgram=e._spPick,p.uniformMap={},p.pass=T.GROUND}}function F(e,t,r,i,o,a,s,l){var u;t.mode===P.SCENE3D?u=e._boundingVolumes:t.mode!==P.SCENE3D&&n(e._boundingVolumes2D)&&(u=e._boundingVolumes2D);var c=t.commandList,h=t.passes;if(h.render)for(var d=r.length,p=0;d>p;++p)r[p].modelMatrix=o,r[p].boundingVolume=u[Math.floor(p/3)],r[p].cull=a,r[p].debugShowBoundingVolume=s,c.push(r[p]);if(h.pick)for(var m=i.length,f=0;m>f;++f)i[f].modelMatrix=o,i[f].boundingVolume=u[Math.floor(f/3)],i[f].cull=a,c.push(i[f])}var B=function(e){e=i(e,i.EMPTY_OBJECT),this.geometryInstance=e.geometryInstance,this.show=i(e.show,!0),this.debugShowBoundingVolume=i(e.debugShowBoundingVolume,!1),this._sp=void 0,this._spPick=void 0,this._rsStencilPreloadPass=void 0,this._rsStencilDepthPass=void 0,this._rsColorPass=void 0,this._rsPickPass=void 0,this._boundingVolumes=[],this._boundingVolumes2D=[],this._ready=!1,this._readyPromise=E.defer(),this._primitive=void 0;var t=new b({flat:!0});this._primitiveOptions={geometryInstances:void 0,appearance:t,vertexCacheOptimize:i(e.vertexCacheOptimize,!1),interleave:i(e.interleave,!1),releaseGeometryInstances:i(e.releaseGeometryInstances,!0),allowPicking:i(e.allowPicking,!0),asynchronous:i(e.asynchronous,!0),compressVertices:i(e.compressVertices,!0),_createRenderStatesFunction:void 0,_createShaderProgramFunction:void 0,_createCommandsFunction:void 0}};o(B.prototype,{vertexCacheOptimize:{get:function(){return this._primitiveOptions.vertexCacheOptimize}},interleave:{get:function(){return this._primitiveOptions.interleave}},releaseGeometryInstances:{get:function(){return this._primitiveOptions.releaseGeometryInstances}},allowPicking:{get:function(){return this._primitiveOptions.allowPicking}},asynchronous:{get:function(){return this._primitiveOptions.asynchronous}},compressVertices:{get:function(){return this._primitiveOptions.compressVertices}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}}}),B.isSupported=function(e){return e.context.fragmentDepth},B._maxHeight=9e3,B._minHeight=-1e5,B._minOBBHeight=-11500;var V={colorMask:{red:!1,green:!1,blue:!1,alpha:!1},stencilTest:{enabled:!0,frontFunction:A.ALWAYS,frontOperation:{fail:I.KEEP,zFail:I.DECREMENT_WRAP,zPass:I.DECREMENT_WRAP},backFunction:A.ALWAYS,backOperation:{fail:I.KEEP,zFail:I.INCREMENT_WRAP,zPass:I.INCREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!1},depthMask:!1},z={colorMask:{red:!1,green:!1,blue:!1,alpha:!1},stencilTest:{enabled:!0,frontFunction:A.ALWAYS,frontOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.INCREMENT_WRAP},backFunction:A.ALWAYS,backOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!0,func:w.LESS_OR_EQUAL},depthMask:!1},k={stencilTest:{enabled:!0,frontFunction:A.NOT_EQUAL,frontOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},backFunction:A.NOT_EQUAL,backOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!1},depthMask:!1,blending:S.ALPHA_BLEND},U={stencilTest:{enabled:!0,frontFunction:A.NOT_EQUAL,frontOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},backFunction:A.NOT_EQUAL,backOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!1},depthMask:!1},G=new t,W=new t,H=new t,q=new r,j=new m;return B.prototype.update=function(e){var t=e.context;if(t.fragmentDepth&&this.show&&(n(this._primitive)||n(this.geometryInstance))){if(!n(this._primitive)){var r=this.geometryInstance,i=r.geometry,o=i.constructor;n(o)&&n(o.createShadowVolume)&&(r=new l({geometry:o.createShadowVolume(i,D,M),attributes:r.attributes,modelMatrix:d.IDENTITY,id:r.id,pickPrimitive:this}));var a=this._primitiveOptions;a.geometryInstances=r;var s=this;this._primitiveOptions._createBoundingVolumeFunction=function(e,t){R(s,e,t)},this._primitiveOptions._createRenderStatesFunction=function(e,t,r,i){O(s,t)},this._primitiveOptions._createShaderProgramFunction=function(e,t,r){N(s,t)},this._primitiveOptions._createCommandsFunction=function(e,t,r,i,n,o,a){L(s,void 0,void 0,!0,!1,o,a)},this._primitiveOptions._updateAndQueueCommandsFunction=function(e,t,r,i,n,o,a,l){F(s,t,r,i,n,o,a,l)},this._primitive=new x(a),this._primitive.readyPromise.then(function(e){s._ready=!0,s.releaseGeometryInstances&&(s.geometryInstance=void 0);var t=e._error;n(t)?s._readyPromise.reject(t):s._readyPromise.resolve(s)})}this._primitive.debugShowBoundingVolume=this.debugShowBoundingVolume,this._primitive.update(e)}},B.prototype.getGeometryInstanceAttributes=function(e){return this._primitive.getGeometryInstanceAttributes(e)},B.prototype.isDestroyed=function(){return!1},B.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),this._sp=this._sp&&this._sp.destroy(),this._spPick=this._spPick&&this._spPick.destroy(),a(this)},B}),r("Scene/UrlTemplateImageryProvider",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/combine","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/freezeObject","../Core/GeographicTilingScheme","../Core/loadJson","../Core/loadText","../Core/loadWithXhr","../Core/loadXML","../Core/Math","../Core/Rectangle","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";function S(e,t,r,i){return ne=!1,ae=!1,T(e,e._urlParts,function(n){return n(e,t,r,i)})}function w(e,t,r,i,n,o,a){return ne=!1,ae=!1,le=!1,he=!1,T(e,e._pickFeaturesUrlParts,function(s){return s(e,t,r,i,n,o,a)})}function T(e,t,r){for(var i="",n=0;n<t.length;++n){var o=t[n];i+="string"==typeof o?o:encodeURIComponent(r(o))}var s=e._proxy;return a(s)&&(i=s.getURL(i)),i}function b(e,t){if(!a(e))return void 0;for(var r,i,n=[],o=0,s=Object.keys(t);o<e.length;){r=Number.MAX_VALUE,i=void 0;for(var l=0;l<s.length;++l){var u=e.indexOf(s[l],o);u>=0&&r>u&&(r=u,i=s[l])}a(i)?(r>o&&n.push(e.substring(o,r)),n.push(t[i]),o=r+i.length):(n.push(e.substring(o)),o=e.length)}return n}function x(e,t,r,i){return t}function P(e,t,r,i){return e.tilingScheme.getNumberOfXTilesAtLevel(i)-t-1}function A(e,t,r,i){return r}function I(e,t,r,i){return e.tilingScheme.getNumberOfYTilesAtLevel(i)-r-1}function M(e,t,r,i){var n=e.maximumLevel;return a(n)&&n>i?n-i-1:i}function D(e,t,r,i){return i}function R(e,t,r,i){var n=(t+r+i)%e._subdomains.length;return e._subdomains[n]}function O(e,t,r,i){ne||(e.tilingScheme.tileXYToRectangle(t,r,i,oe),oe.west=v.toDegrees(oe.west),oe.south=v.toDegrees(oe.south),oe.east=v.toDegrees(oe.east),oe.north=v.toDegrees(oe.north),ne=!0)}function N(e,t,r,i){return O(e,t,r,i),oe.west}function L(e,t,r,i){return O(e,t,r,i),oe.south}function F(e,t,r,i){return O(e,t,r,i),oe.east}function B(e,t,r,i){return O(e,t,r,i),oe.north}function V(e,t,r,i){ae||(e.tilingScheme.tileXYToNativeRectangle(t,r,i,se),ae=!0)}function z(e,t,r,i){return V(e,t,r,i),se.west}function k(e,t,r,i){return V(e,t,r,i),se.south}function U(e,t,r,i){return V(e,t,r,i),se.east}function G(e,t,r,i){return V(e,t,r,i),se.north}function W(e,t,r,i){return e.tileWidth}function H(e,t,r,i){return e.tileHeight}function q(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),ue.x}function j(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),ue.y}function Y(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),e.tileWidth-ue.x-1}function X(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),e.tileHeight-ue.y-1}function Z(e,t,r,i,n,o,a){if(!le){ee(e,t,r,i,n,o);var s=de,l=e.tilingScheme.tileXYToNativeRectangle(t,r,i,ce);ue.x=e.tileWidth*(s.x-l.west)/l.width|0,ue.y=e.tileHeight*(l.north-s.y)/l.height|0,le=!0}}function K(e,t,r,i,n,o,a){return v.toDegrees(n)}function J(e,t,r,i,n,o,a){return v.toDegrees(o)}function Q(e,t,r,i,n,o,a){return ee(e,t,r,i,n,o),de.x}function $(e,t,r,i,n,o,a){return ee(e,t,r,i,n,o),de.y}function ee(e,t,r,i,n,o,a){if(!he){var s;if(e.tilingScheme instanceof h)de.x=v.toDegrees(n),de.y=v.toDegrees(o);else{var l=pe;l.longitude=n,l.latitude=o,s=e.tilingScheme.projection.project(l,de)}he=!0}}function te(e,t,r,i,n,o,a){return a}function re(e,t,r){for(var i=0,n=e.length;n>i;++i){var o=e[i];if(t>=o.startX&&t<=o.endX&&r>=o.startY&&r<=o.endY)return!0}return!1}var ie=function(e){this._url=e.url,this._pickFeaturesUrl=e.pickFeaturesUrl,this._proxy=e.proxy,this._tileDiscardPolicy=e.tileDiscardPolicy,this._getFeatureInfoFormats=e.getFeatureInfoFormats,this._errorEvent=new u,this._subdomains=e.subdomains,Array.isArray(this._subdomains)?this._subdomains=this._subdomains.slice():a(this._subdomains)&&this._subdomains.length>0?this._subdomains=this._subdomains.split(""):this._subdomains=["a","b","c"],this._tileWidth=o(e.tileWidth,256),this._tileHeight=o(e.tileHeight,256),this._minimumLevel=o(e.minimumLevel,0),this._maximumLevel=e.maximumLevel,this._minimumRetrievingLevel=o(e.minimumRetrievingLevel,0),this._maximumRetrievingLevel=o(e.maximumRetrievingLevel,1/0),this._availableLevels=e.availableLevels,this._tilingScheme=o(e.tilingScheme,new y({ellipsoid:e.ellipsoid})),this._rectangle=o(e.rectangle,this._tilingScheme.rectangle),this._rectangle=_.intersection(this._rectangle,this._tilingScheme.rectangle),this._hasAlphaChannel=o(e.hasAlphaChannel,!0);var t=e.credit;if("string"==typeof t&&(t=new n(t)),this._credit=t,this._urlParts=b(this._url,me),this._pickFeaturesUrlParts=b(this._pickFeaturesUrl,fe),this._ready=!e.metadataUrl,this._readyPromise=C.defer(),!this._ready){var r=e.metadataUrl+"layer.json";a(this._proxy)&&(r=this._proxy.getURL(r));var i,s=this,l=function(e){s._availableTiles=e.available;for(var t=0;t<s._availableTiles.length;t++)s._availableLevels&&-1===s._availableLevels.indexOf(t)&&(s._availableTiles[t]=[]);s._ready=!0,s._readyPromise.resolve(!0)},c=function(e){s._ready=!0;var t="An error occurred while accessing "+r+".";i=g.handleError(i,s,s._errorEvent,t,void 0,void 0,void 0,h)},h=function(){var e=d(r);C(e,l,c)};h()}};s(ie.prototype,{url:{get:function(){return this._url}},pickFeaturesUrl:{get:function(){return this._pickFeaturesUrl}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return this._hasAlphaChannel}}}),ie.prototype.getTileCredits=function(e,t,r){return void 0},ie.prototype.getTileDataAvailable=function(e,t,r){var i=this._availableTiles;if(i&&0!==i.length){if(r>=i.length)return!1;var n=i[r],o=this._tilingScheme.getNumberOfYTilesAtLevel(r),a=o-t-1;return re(n,e,a)}return this._availableLevels&&-1===this._availableLevels.indexOf(r)?!1:!0},ie.transparentCanvas=function(){var e=document.createElement("canvas"),t=e.getContext("2d");return t.width=256,t.height=256,t.fillStyle="rgba(255, 0, 0, 0)",t.fillRect(0,0,255,255),e}(),ie.prototype.requestImage=function(e,t,r){if(r<this._minimumRetrievingLevel||r>this._maximumRetrievingLevel||!this.getTileDataAvailable(e,t,r))return ie.transparentCanvas;var i=S(this,e,t,r);return E.loadImage(this,i)},ie.prototype.pickFeatures=function(e,t,r,i,n){function o(e,t){return e.callback(t)}function s(){if(l>=u._getFeatureInfoFormats.length)return C([]);var a=u._getFeatureInfoFormats[l],c=w(u,e,t,r,i,n,a.format);return++l,"json"===a.type?d(c).then(a.callback).otherwise(s):"xml"===a.type?f(c).then(a.callback).otherwise(s):"text"===a.type||"html"===a.type?p(c).then(a.callback).otherwise(s):m({url:c,responseType:a.format}).then(o.bind(void 0,a)).otherwise(s)}if(!a(this._pickFeaturesUrl)||0===this._getFeatureInfoFormats.length)return void 0;var l=0,u=this;return s()};var ne=!1,oe=new _,ae=!1,se=new _,le=!1,ue=new e,ce=new _,he=!1,de=new t,pe=new r,me={"{x}":x,"{y}":A,"{z}":D,"{s}":R,"{reverseX}":P,"{reverseY}":I,"{reverseZ}":M,"{westDegrees}":N,"{southDegrees}":L,"{eastDegrees}":F,"{northDegrees}":B,"{westProjected}":z,"{southProjected}":k,"{eastProjected}":U,"{northProjected}":G,"{width}":W,"{height}":H},fe=i(me,{"{i}":q,"{j}":j,"{reverseI}":Y,"{reverseJ}":X,"{longitudeDegrees}":K,"{latitudeDegrees}":J,"{longitudeProjected}":Q,"{latitudeProjected}":$,"{format}":te});return ie}),r("Scene/MapboxImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/MapboxApi","./UrlTemplateImageryProvider"],function(e,t,r,i,n,o,a){"use strict";var s=/\/$/,l=new e("© Mapbox © OpenStreetMap",void 0,"https://www.mapbox.com/about/maps/"),u=[new e("Improve this map",void 0,"https://www.mapbox.com/map-feedback/")],c=function(i){i=t(i,t.EMPTY_OBJECT);var n=i.mapId,c=t(i.url,"//api.mapbox.com/v4/");this._url=c,this._mapId=n,this._accessToken=o.getAccessToken(i.accessToken);var h=t(i.format,"png");this._format=h.replace(".","");var d=c;if(s.test(c)||(d+="/"),d+=n+"/{z}/{x}/{y}."+this._format,r(this._accessToken)&&(d+="?access_token="+this._accessToken),r(i.credit)){var p=i.credit;"string"==typeof p&&(p=new e(p)),l=p,u.length=0}this._imageryProvider=new a({url:d,proxy:i.proxy,credit:l,ellipsoid:i.ellipsoid,minimumLevel:i.minimumLevel,maximumLevel:i.maximumLevel,rectangle:i.rectangle})};return i(c.prototype,{url:{get:function(){return this._url}},ready:{get:function(){return this._imageryProvider.ready}},readyPromise:{get:function(){return this._imageryProvider.readyPromise}},rectangle:{get:function(){return this._imageryProvider.rectangle}},tileWidth:{get:function(){return this._imageryProvider.tileWidth}},tileHeight:{get:function(){return this._imageryProvider.tileHeight}},maximumLevel:{get:function(){return this._imageryProvider.maximumLevel}},minimumLevel:{get:function(){return this._imageryProvider.minimumLevel}},tilingScheme:{get:function(){return this._imageryProvider.tilingScheme}},tileDiscardPolicy:{get:function(){return this._imageryProvider.tileDiscardPolicy}},errorEvent:{get:function(){return this._imageryProvider.errorEvent}},credit:{get:function(){return this._imageryProvider.credit}},proxy:{get:function(){return this._imageryProvider.proxy}},hasAlphaChannel:{get:function(){return this._imageryProvider.hasAlphaChannel}}}),c.prototype.getTileCredits=function(e,t,r){return u},c.prototype.requestImage=function(e,t,r){return this._imageryProvider.requestImage(e,t,r)},c.prototype.pickFeatures=function(e,t,r,i,n){return this._imageryProvider.pickFeatures(e,t,r,i,n)},c}),r("Scene/Moon",["../Core/buildModuleUrl","../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/Ellipsoid","../Core/IauOrientationAxes","../Core/Matrix3","../Core/Matrix4","../Core/Simon1994PlanetaryPositions","../Core/Transforms","./EllipsoidPrimitive","./Material"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(t){t=r(t,r.EMPTY_OBJECT);var n=t.textureUrl;i(n)||(n=e("Assets/Textures/moonSmall.jpg")),this.show=r(t.show,!0),this.textureUrl=n,this._ellipsoid=r(t.ellipsoid,a.MOON),this.onlySunLighting=r(t.onlySunLighting,!0),this._ellipsoidPrimitive=new d({radii:this.ellipsoid.radii,material:p.fromType(p.ImageType),depthTestEnabled:!1,_owner:this}),this._ellipsoidPrimitive.material.translucent=!1,this._axes=new s};n(m.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}});var f=new l,v=new l,_=new t,g=[];return m.prototype.update=function(e){if(this.show){var t=this._ellipsoidPrimitive;t.material.uniforms.image=this.textureUrl,t.onlySunLighting=this.onlySunLighting;var r=e.time;i(h.computeIcrfToFixedMatrix(r,f))||h.computeTemeToPseudoFixedMatrix(r,f);var n=this._axes.evaluate(r,v);l.transpose(n,n),l.multiply(f,n,n);var o=c.computeMoonPositionInEarthInertialFrame(r,_);l.multiplyByVector(f,o,o),u.fromRotationTranslation(n,o,t.modelMatrix);var a=e.commandList;return e.commandList=g,g.length=0,t.update(e),e.commandList=a,1===g.length?g[0]:void 0}},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return this._ellipsoidPrimitive=this._ellipsoidPrimitive&&this._ellipsoidPrimitive.destroy(),o(this)},m}),r("Scene/NeverTileDiscardPolicy",[],function(){"use strict";var e=function(e){};return e.prototype.isReady=function(){return!0},e.prototype.shouldDiscardImage=function(e){return!1},e}),r("Shaders/AdjustTranslucentFS",[],function(){"use strict";return"#ifdef MRT\n#extension GL_EXT_draw_buffers : enable\n#endif\nuniform vec4 u_bgColor;\nuniform sampler2D u_depthTexture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nif (texture2D(u_depthTexture, v_textureCoordinates).r < 1.0)\n{\n#ifdef MRT\ngl_FragData[0] = u_bgColor;\ngl_FragData[1] = vec4(u_bgColor.a);\n#else\ngl_FragColor = u_bgColor;\n#endif\nreturn;\n}\ndiscard;\n}\n"}),r("Shaders/CompositeOITFS",[],function(){"use strict";return"uniform sampler2D u_opaque;\nuniform sampler2D u_accumulation;\nuniform sampler2D u_revealage;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec4 opaque = texture2D(u_opaque, v_textureCoordinates);\nvec4 accum = texture2D(u_accumulation, v_textureCoordinates);\nfloat r = texture2D(u_revealage, v_textureCoordinates).r;\n#ifdef MRT\nvec4 transparent = vec4(accum.rgb / clamp(r, 1e-4, 5e4), accum.a);\n#else\nvec4 transparent = vec4(accum.rgb / clamp(accum.a, 1e-4, 5e4), r);\n#endif\ngl_FragColor = (1.0 - transparent.a) * transparent + transparent.a * opaque;\n}\n"}),r("Scene/OIT",["../Core/Color","../Core/defined","../Core/destroyObject","../Core/PixelFormat","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/WebGLConstants","../Shaders/AdjustTranslucentFS","../Shaders/CompositeOITFS","./BlendEquation","./BlendFunction"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(e){e._accumulationTexture=e._accumulationTexture&&!e._accumulationTexture.isDestroyed()&&e._accumulationTexture.destroy(),e._revealageTexture=e._revealageTexture&&!e._revealageTexture.isDestroyed()&&e._revealageTexture.destroy()}function _(e){e._translucentFBO=e._translucentFBO&&!e._translucentFBO.isDestroyed()&&e._translucentFBO.destroy(),e._alphaFBO=e._alphaFBO&&!e._alphaFBO.isDestroyed()&&e._alphaFBO.destroy(),e._adjustTranslucentFBO=e._adjustTranslucentFBO&&!e._adjustTranslucentFBO.isDestroyed()&&e._adjustTranslucentFBO.destroy(),e._adjustAlphaFBO=e._adjustAlphaFBO&&!e._adjustAlphaFBO.isDestroyed()&&e._adjustAlphaFBO.destroy()}function g(e){v(e),_(e)}function y(e,t,r,n){v(e),e._accumulationTexture=new c({context:t,width:r,height:n,pixelFormat:i.RGBA,pixelDatatype:a.FLOAT}),e._revealageTexture=new c({context:t,width:r,height:n,pixelFormat:i.RGBA,pixelDatatype:a.FLOAT})}function C(e,t){_(e);var r=h.FRAMEBUFFER_COMPLETE,i=!0;if(e._translucentMRTSupport&&(e._translucentFBO=new o({context:t,colorTextures:[e._accumulationTexture,e._revealageTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._adjustTranslucentFBO=new o({context:t,colorTextures:[e._accumulationTexture,e._revealageTexture],destroyAttachments:!1}),(e._translucentFBO.status!==r||e._adjustTranslucentFBO.status!==r)&&(_(e),e._translucentMRTSupport=!1)),!e._translucentMRTSupport){e._translucentFBO=new o({context:t,colorTextures:[e._accumulationTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._alphaFBO=new o({context:t,colorTextures:[e._revealageTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._adjustTranslucentFBO=new o({context:t,colorTextures:[e._accumulationTexture],destroyAttachments:!1}),e._adjustAlphaFBO=new o({context:t,colorTextures:[e._revealageTexture],destroyAttachments:!1});var n=e._translucentFBO.status===r,a=e._alphaFBO.status===r,s=e._adjustTranslucentFBO.status===r,l=e._adjustAlphaFBO.status===r;n&&a&&s&&l||(g(e),e._translucentMultipassSupport=!1,i=!1)}return i}function E(e,r,i,n){var o=i[n.id];if(!t(o)){var a=s.getState(n);a.depthMask=!1,a.blending=r,o=s.fromCache(a),i[n.id]=o}return o}function S(e,t,r){return E(t,R,e._translucentRenderStateCache,r)}function w(e,t,r){return E(t,O,e._translucentRenderStateCache,r)}function T(e,t,r){return E(t,N,e._alphaRenderStateCache,r)}function b(e,r,i,n){var o=r.id,a=i[o];if(!t(a)){var s=r._attributeLocations,c=r.fragmentShaderSource.clone();c.sources=c.sources.map(function(e){return e=u.replaceMain(e,"czm_translucent_main"),e=e.replace(/gl_FragColor/g,"czm_gl_FragColor"),e=e.replace(/\bdiscard\b/g,"czm_discard = true"),e=e.replace(/czm_phong/g,"czm_translucentPhong")}),c.sources.splice(0,0,(-1!==n.indexOf("gl_FragData")?"#extension GL_EXT_draw_buffers : enable \n":"")+"vec4 czm_gl_FragColor;\nbool czm_discard = false;\n"),c.sources.push("void main()\n{\n czm_translucent_main();\n if (czm_discard)\n {\n discard;\n }\n"+n+"}\n"),a=l.fromCache({context:e,vertexShaderSource:r.vertexShaderSource,fragmentShaderSource:c,attributeLocations:s}),i[o]=a}return a}function x(e,t,r){return b(t,r,e._translucentShaderCache,L)}function P(e,t,r){return b(t,r,e._translucentShaderCache,F)}function A(e,t,r){return b(t,r,e._alphaShaderCache,B)}function I(e,r,i,n,o){var a,s,l,u,c=r.context,h=n.framebuffer,d=o.length;n.framebuffer=e._adjustTranslucentFBO,e._adjustTranslucentCommand.execute(c,n),n.framebuffer=e._adjustAlphaFBO,e._adjustAlphaCommand.execute(c,n);var p=e._opaqueFBO;for(n.framebuffer=e._translucentFBO,u=0;d>u;++u)a=o[u],t(a.oit)&&a.shaderProgram.id===a.oit.shaderProgramId||(a.oit={colorRenderState:w(e,c,a.renderState),alphaRenderState:T(e,c,a.renderState),colorShaderProgram:P(e,c,a.shaderProgram),alphaShaderProgram:A(e,c,a.shaderProgram),shaderProgramId:a.shaderProgram.id}),s=a.oit.colorRenderState,l=a.oit.colorShaderProgram,i(a,r,c,n,s,l,p);for(n.framebuffer=e._alphaFBO,u=0;d>u;++u)a=o[u],s=a.oit.alphaRenderState,l=a.oit.alphaShaderProgram,i(a,r,c,n,s,l,p);n.framebuffer=h}function M(e,r,i,n,o){var a=r.context,s=n.framebuffer,l=o.length;n.framebuffer=e._adjustTranslucentFBO,e._adjustTranslucentCommand.execute(a,n);var u=e._opaqueFBO;n.framebuffer=e._translucentFBO;for(var c=0;l>c;++c){var h=o[c];t(h.oit)&&h.shaderProgram.id===h.oit.shaderProgramId||(h.oit={translucentRenderState:S(e,a,h.renderState),translucentShaderProgram:x(e,a,h.shaderProgram),shaderProgramId:h.shaderProgram.id});var d=h.oit.translucentRenderState,p=h.oit.translucentShaderProgram;i(h,r,a,n,d,p,u)}n.framebuffer=s}var D=function(t){this._translucentMultipassSupport=!1,this._translucentMRTSupport=!1;var r=t.floatingPointTexture&&t.depthTexture;this._translucentMRTSupport=t.drawBuffers&&r,this._translucentMultipassSupport=!this._translucentMRTSupport&&r,this._opaqueFBO=void 0,this._opaqueTexture=void 0,this._depthStencilTexture=void 0,this._accumulationTexture=void 0,this._translucentFBO=void 0,this._alphaFBO=void 0,this._adjustTranslucentFBO=void 0,this._adjustAlphaFBO=void 0,this._opaqueClearCommand=new n({color:new e(0,0,0,0),owner:this}),this._translucentMRTClearCommand=new n({color:new e(0,0,0,1),owner:this}),this._translucentMultipassClearCommand=new n({color:new e(0,0,0,0),owner:this}),this._alphaClearCommand=new n({color:new e(1,1,1,1),owner:this}),this._translucentRenderStateCache={},this._alphaRenderStateCache={},this._translucentShaderCache={},this._alphaShaderCache={},this._compositeCommand=void 0,this._adjustTranslucentCommand=void 0,this._adjustAlphaCommand=void 0};D.prototype.update=function(e,r){if(this.isSupported()){this._opaqueFBO=r,this._opaqueTexture=r.getColorTexture(0),this._depthStencilTexture=r.depthStencilTexture;var i=this._opaqueTexture.width,n=this._opaqueTexture.height,o=this._accumulationTexture,a=!t(o)||o.width!==i||o.height!==n;if(a&&y(this,e,i,n),t(this._translucentFBO)&&!a||C(this,e)){var l,c,h=this;t(this._compositeCommand)||(l=new u({sources:[p]}),this._translucentMRTSupport&&l.defines.push("MRT"),c={u_opaque:function(){return h._opaqueTexture},u_accumulation:function(){return h._accumulationTexture},u_revealage:function(){return h._revealageTexture}},this._compositeCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this})),t(this._adjustTranslucentCommand)||(this._translucentMRTSupport?(l=new u({defines:["MRT"],sources:[d]}),c={u_bgColor:function(){return h._translucentMRTClearCommand.color},u_depthTexture:function(){return h._depthStencilTexture}},this._adjustTranslucentCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this})):this._translucentMultipassSupport&&(l=new u({sources:[d]}),c={u_bgColor:function(){return h._translucentMultipassClearCommand.color},u_depthTexture:function(){return h._depthStencilTexture}},this._adjustTranslucentCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this}),c={u_bgColor:function(){return h._alphaClearCommand.color},u_depthTexture:function(){return h._depthStencilTexture}},this._adjustAlphaCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this})))}}};var R={enabled:!0,color:new e(0,0,0,0),equationRgb:m.ADD,equationAlpha:m.ADD,functionSourceRgb:f.ONE,functionDestinationRgb:f.ONE,functionSourceAlpha:f.ZERO,functionDestinationAlpha:f.ONE_MINUS_SOURCE_ALPHA},O={enabled:!0,color:new e(0,0,0,0),equationRgb:m.ADD,equationAlpha:m.ADD,functionSourceRgb:f.ONE,functionDestinationRgb:f.ONE,functionSourceAlpha:f.ONE,functionDestinationAlpha:f.ONE},N={enabled:!0,color:new e(0,0,0,0),equationRgb:m.ADD,equationAlpha:m.ADD,functionSourceRgb:f.ZERO,functionDestinationRgb:f.ONE_MINUS_SOURCE_ALPHA,functionSourceAlpha:f.ZERO,functionDestinationAlpha:f.ONE_MINUS_SOURCE_ALPHA},L=" vec3 Ci = czm_gl_FragColor.rgb * czm_gl_FragColor.a;\n float ai = czm_gl_FragColor.a;\n float wzi = czm_alphaWeight(ai);\n gl_FragData[0] = vec4(Ci * wzi, ai);\n gl_FragData[1] = vec4(ai * wzi);\n",F=" vec3 Ci = czm_gl_FragColor.rgb * czm_gl_FragColor.a;\n float ai = czm_gl_FragColor.a;\n float wzi = czm_alphaWeight(ai);\n gl_FragColor = vec4(Ci, ai) * wzi;\n",B=" float ai = czm_gl_FragColor.a;\n gl_FragColor = vec4(ai);\n";return D.prototype.executeCommands=function(e,t,r,i){return this._translucentMRTSupport?void M(this,e,t,r,i):void I(this,e,t,r,i)},D.prototype.execute=function(e,t){this._compositeCommand.execute(e,t)},D.prototype.clear=function(t,r,i){var n=r.framebuffer;r.framebuffer=this._opaqueFBO,e.clone(i,this._opaqueClearCommand.color),this._opaqueClearCommand.execute(t,r),r.framebuffer=this._translucentFBO;var o=this._translucentMRTSupport?this._translucentMRTClearCommand:this._translucentMultipassClearCommand;o.execute(t,r),this._translucentMultipassSupport&&(r.framebuffer=this._alphaFBO,this._alphaClearCommand.execute(t,r)),r.framebuffer=n},D.prototype.isSupported=function(){return this._translucentMRTSupport||this._translucentMultipassSupport},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){g(this),t(this._compositeCommand)&&(this._compositeCommand.shaderProgram=this._compositeCommand.shaderProgram&&this._compositeCommand.shaderProgram.destroy()),t(this._adjustTranslucentCommand)&&(this._adjustTranslucentCommand.shaderProgram=this._adjustTranslucentCommand.shaderProgram&&this._adjustTranslucentCommand.shaderProgram.destroy()),t(this._adjustAlphaCommand)&&(this._adjustAlphaCommand.shaderProgram=this._adjustAlphaCommand.shaderProgram&&this._adjustAlphaCommand.shaderProgram.destroy());var e,i=this._translucentShaderCache;for(e in i)i.hasOwnProperty(e)&&t(i[e])&&i[e].destroy();this._translucentShaderCache={},i=this._alphaShaderCache;for(e in i)i.hasOwnProperty(e)&&t(i[e])&&i[e].destroy();return this._alphaShaderCache={},r(this)},D}),r("Scene/OpenStreetMapImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/Rectangle","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t,i,n){var o=e._url+n+"/"+t+"/"+i+"."+e._fileExtension,a=e._proxy;return r(a)&&(o=a.getURL(o)),o}var h=/\/$/,d=new e("MapQuest, Open Street Map and contributors, CC-BY-SA"),p=function(r){r=t(r,{});var i=t(r.url,"//a.tile.openstreetmap.org/");h.test(i)||(i+="/"),this._url=i,this._fileExtension=t(r.fileExtension,"png"),this._proxy=r.proxy,this._tileDiscardPolicy=r.tileDiscardPolicy,this._tilingScheme=new s({ellipsoid:r.ellipsoid}),this._tileWidth=256,this._tileHeight=256,this._minimumLevel=t(r.minimumLevel,0),this._maximumLevel=r.maximumLevel,this._rectangle=t(r.rectangle,this._tilingScheme.rectangle);var u=this._tilingScheme.positionToTileXY(a.southwest(this._rectangle),this._minimumLevel),c=this._tilingScheme.positionToTileXY(a.northeast(this._rectangle),this._minimumLevel),p=(Math.abs(c.x-u.x)+1)*(Math.abs(c.y-u.y)+1);if(p>4)throw new n("The imagery provider's rectangle and minimumLevel indicate that there are "+p+" tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.");this._errorEvent=new o,this._ready=!0,this._readyPromise=l.resolve(!0);var m=t(r.credit,d);"string"==typeof m&&(m=new e(m)),this._credit=m};return i(p.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),p.prototype.getTileCredits=function(e,t,r){return void 0},p.prototype.requestImage=function(e,t,r){var i=c(this,e,t,r);return u.loadImage(this,i)},p.prototype.pickFeatures=function(){return void 0},p}),r("Scene/OrthographicFrustum",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/Matrix4","./CullingVolume"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e){(e.top!==e._top||e.bottom!==e._bottom||e.left!==e._left||e.right!==e._right||e.near!==e._near||e.far!==e._far)&&(e._left=e.left,e._right=e.right,e._top=e.top,e._bottom=e.bottom,e._near=e.near,e._far=e.far,e._orthographicMatrix=s.computeOrthographicOffCenter(e.left,e.right,e.bottom,e.top,e.near,e.far,e._orthographicMatrix))}var c=function(){this.left=void 0,this._left=void 0,this.right=void 0,this._right=void 0,this.top=void 0,this._top=void 0,this.bottom=void 0,this._bottom=void 0,this.near=1,this._near=this.near,this.far=5e8,this._far=this.far,this._cullingVolume=new l,this._orthographicMatrix=new s};n(c.prototype,{projectionMatrix:{get:function(){return u(this),this._orthographicMatrix}}});var h=new t,d=new t,p=new t,m=new t;return c.prototype.computeCullingVolume=function(e,n,o){var a=this._cullingVolume.planes,s=this.top,l=this.bottom,u=this.right,c=this.left,f=this.near,v=this.far,_=t.cross(n,o,h),g=d;t.multiplyByScalar(n,f,g),t.add(e,g,g);var y=p;t.multiplyByScalar(_,c,y),t.add(g,y,y);var C=a[0];return i(C)||(C=a[0]=new r),C.x=_.x,C.y=_.y,C.z=_.z,C.w=-t.dot(_,y),t.multiplyByScalar(_,u,y),t.add(g,y,y),C=a[1],i(C)||(C=a[1]=new r),C.x=-_.x,C.y=-_.y,C.z=-_.z,C.w=-t.dot(t.negate(_,m),y),t.multiplyByScalar(o,l,y), +t.add(g,y,y),C=a[2],i(C)||(C=a[2]=new r),C.x=o.x,C.y=o.y,C.z=o.z,C.w=-t.dot(o,y),t.multiplyByScalar(o,s,y),t.add(g,y,y),C=a[3],i(C)||(C=a[3]=new r),C.x=-o.x,C.y=-o.y,C.z=-o.z,C.w=-t.dot(t.negate(o,m),y),C=a[4],i(C)||(C=a[4]=new r),C.x=n.x,C.y=n.y,C.z=n.z,C.w=-t.dot(n,g),t.multiplyByScalar(n,v,y),t.add(e,y,y),C=a[5],i(C)||(C=a[5]=new r),C.x=-n.x,C.y=-n.y,C.z=-n.z,C.w=-t.dot(t.negate(n,m),y),this._cullingVolume},c.prototype.getPixelSize=function(t,r,n){o("OrthographicFrustum","getPixelSize is deprecated. Use getPixelDimensions instead."),u(this);var a=this.right-this.left,s=this.top-this.bottom,l=a/t.x,c=s/t.y;return i(n)?(n.x=l,n.y=c,n):new e(l,c)},c.prototype.getPixelDimensions=function(e,t,r,i){u(this);var n=this.right-this.left,o=this.top-this.bottom,a=n/e,s=o/t;return i.x=a,i.y=s,i},c.prototype.clone=function(e){return i(e)||(e=new c),e.left=this.left,e.right=this.right,e.top=this.top,e.bottom=this.bottom,e.near=this.near,e.far=this.far,e._left=void 0,e._right=void 0,e._top=void 0,e._bottom=void 0,e._near=void 0,e._far=void 0,e},c.prototype.equals=function(e){return i(e)&&this.right===e.right&&this.left===e.left&&this.top===e.top&&this.bottom===e.bottom&&this.near===e.near&&this.far===e.far},c}),r("Widgets/getElement",["../Core/DeveloperError"],function(e){"use strict";var t=function(e){if("string"==typeof e){var t=document.getElementById(e);e=t}return e};return t}),r("Scene/PerformanceDisplay",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/getTimestamp","../Widgets/getElement"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){e=t(e,t.EMPTY_OBJECT);var i=a(e.container);if(!r(i))throw new n("container is required");this._container=i;var o=document.createElement("div");o.className="cesium-performanceDisplay";var s=document.createElement("div");s.className="cesium-performanceDisplay-fps",this._fpsText=document.createTextNode(""),s.appendChild(this._fpsText);var l=document.createElement("div");l.className="cesium-performanceDisplay-ms",this._msText=document.createTextNode(""),l.appendChild(this._msText),o.appendChild(l),o.appendChild(s),this._container.appendChild(o),this._lastFpsSampleTime=void 0,this._frameCount=0,this._time=void 0,this._fps=0,this._frameTime=0};return s.prototype.update=function(){if(!r(this._time))return this._lastFpsSampleTime=o(),void(this._time=o());var e=this._time,t=o();this._time=t;var i=t-e;this._frameCount++;var n=this._fps,a=t-this._lastFpsSampleTime;a>1e3&&(n=1e3*this._frameCount/a|0,this._lastFpsSampleTime=t,this._frameCount=0),n!==this._fps&&(this._fpsText.nodeValue=n+" FPS",this._fps=n),i!==this._frameTime&&(this._msText.nodeValue=i.toFixed(2)+" MS",this._frameTime=i)},s.prototype.destroy=function(){return i(this)},s}),r("Scene/PickDepth",["../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/PixelFormat","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/PassThrough"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(t,r,i){if(!e(t._debugPickDepthViewportCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n float n_range = czm_depthRange.near;\n float f_range = czm_depthRange.far;\n float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n}\n";t._debugPickDepthViewportCommand=r.createViewportQuadCommand(n,{uniformMap:{u_texture:function(){return t._depthTexture}},owner:t})}t._debugPickDepthViewportCommand.execute(r,i)}function c(e){e._depthTexture=e._depthTexture&&!e._depthTexture.isDestroyed()&&e._depthTexture.destroy()}function h(e){e.framebuffer=e.framebuffer&&!e.framebuffer.isDestroyed()&&e.framebuffer.destroy()}function d(e,t,r,n){e._depthTexture=new s({context:t,width:r,height:n,pixelFormat:i.RGBA,pixelDatatype:o.UNSIGNED_BYTE})}function p(e,t,r,i){c(e),h(e),d(e,t,r,i),e.framebuffer=new n({context:t,colorTextures:[e._depthTexture],destroyAttachments:!1})}function m(t,r,i){var n=i.width,o=i.height,a=t._depthTexture,s=!e(a)||a.width!==n||a.height!==o;(!e(t.framebuffer)||s)&&p(t,r,n,o)}function f(t,r,i){if(!e(t._copyDepthCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n}\n";t._copyDepthCommand=r.createViewportQuadCommand(n,{renderState:a.fromCache(),uniformMap:{u_texture:function(){return t._textureToCopy}},owner:t})}t._textureToCopy=i,t._copyDepthCommand.framebuffer=t.framebuffer}var v=function(){this.framebuffer=void 0,this._depthTexture=void 0,this._textureToCopy=void 0,this._copyDepthCommand=void 0,this._debugPickDepthViewportCommand=void 0};return v.prototype.executeDebugPickDepth=function(e,t){u(this,e,t)},v.prototype.update=function(e,t){m(this,e,t),f(this,e,t)},v.prototype.executeCopyDepth=function(e,t){this._copyDepthCommand.execute(e,t)},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){return c(this),h(this),this._copyDepthCommand.shaderProgram=e(this._copyDepthCommand.shaderProgram)&&this._copyDepthCommand.shaderProgram.destroy(),r(this)},v}),r("Scene/Polygon",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/GeometryInstance","../Core/Math","../Core/PolygonGeometry","./EllipsoidSurfaceAppearance","./Material","./Primitive"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(i){n("Polygon","Polygon has been deprecated. Use PolygonGeometry or Entity.polygon instead."),i=t(i,t.EMPTY_OBJECT),this.ellipsoid=t(i.ellipsoid,s.WGS84),this._ellipsoid=void 0,this.granularity=t(i.granularity,u.RADIANS_PER_DEGREE),this._granularity=void 0,this.height=t(i.height,0),this._height=void 0,this.textureRotationAngle=t(i.textureRotationAngle,0),this._textureRotationAngle=void 0,this.show=t(i.show,!0);var o=d.fromType(d.ColorType,{color:new e(1,1,0,.5)});this.material=t(i.material,o),this.id=i.id,this._id=void 0,this.asynchronous=t(i.asynchronous,!0),this.debugShowBoundingVolume=t(i.debugShowBoundingVolume,!1),this._positions=void 0,this._polygonHierarchy=void 0,this._createPrimitive=!1,this._primitive=void 0,r(i.positions)?this.positions=i.positions:r(i.polygonHierarchy)&&this.configureFromPolygonHierarchy(i.polygonHierarchy)};return i(m.prototype,{positions:{get:function(){return this._positions},set:function(e){this._positions=e,this._polygonHierarchy=void 0,this._createPrimitive=!0}}}),m.prototype.configureFromPolygonHierarchy=function(e){this._positions=void 0,this._polygonHierarchy=e,this._createPrimitive=!0},m.prototype.update=function(e){if(this.show&&(this._createPrimitive||r(this._primitive))){if(this._createPrimitive||this._ellipsoid!==this.ellipsoid||this._granularity!==this.granularity||this._height!==this.height||this._textureRotationAngle!==this.textureRotationAngle||this._id!==this.id){if(this._createPrimitive=!1,this._ellipsoid=this.ellipsoid,this._granularity=this.granularity,this._height=this.height,this._textureRotationAngle=this.textureRotationAngle,this._id=this.id,this._primitive=this._primitive&&this._primitive.destroy(),!r(this._positions)&&!r(this._polygonHierarchy))return;var t;t=new l(r(this._positions)?{geometry:c.fromPositions({positions:this._positions,height:this.height,vertexFormat:h.VERTEX_FORMAT,stRotation:this.textureRotationAngle,ellipsoid:this.ellipsoid,granularity:this.granularity}),id:this.id,pickPrimitive:this}:{geometry:new c({polygonHierarchy:this._polygonHierarchy,height:this.height,vertexFormat:h.VERTEX_FORMAT,stRotation:this.textureRotationAngle,ellipsoid:this.ellipsoid,granularity:this.granularity}),id:this.id,pickPrimitive:this}),this._primitive=new p({geometryInstances:t,appearance:new h({aboveGround:this.height>0}),asynchronous:this.asynchronous})}var i=this._primitive;i.debugShowBoundingVolume=this.debugShowBoundingVolume,i.appearance.material=this.material,i.update(e)}},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),o(this)},m}),r("Scene/PrimitiveCollection",["../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError"],function(e,t,r,i,n,o){"use strict";function a(e,t){return e._primitives.indexOf(t)}var s=function(r){r=t(r,t.EMPTY_OBJECT),this._primitives=[],this._guid=e(),this.show=t(r.show,!0),this.destroyPrimitives=t(r.destroyPrimitives,!0)};return i(s.prototype,{length:{get:function(){return this._primitives.length}}}),s.prototype.add=function(e){var t=e._external=e._external||{},r=t._composites=t._composites||{};return r[this._guid]={collection:this},this._primitives.push(e),e},s.prototype.remove=function(e){if(this.contains(e)){var t=this._primitives.indexOf(e);if(-1!==t)return this._primitives.splice(t,1),delete e._external._composites[this._guid],this.destroyPrimitives&&e.destroy(),!0}return!1},s.prototype.removeAndDestroy=function(e){var t=this.remove(e);return t&&!this.destroyPrimitives&&e.destroy(),t},s.prototype.removeAll=function(){if(this.destroyPrimitives)for(var e=this._primitives,t=e.length,r=0;t>r;++r)e[r].destroy();this._primitives=[]},s.prototype.contains=function(e){return!!(r(e)&&e._external&&e._external._composites&&e._external._composites[this._guid])},s.prototype.raise=function(e){if(r(e)){var t=a(this,e),i=this._primitives;if(t!==i.length-1){var n=i[t];i[t]=i[t+1],i[t+1]=n}}},s.prototype.raiseToTop=function(e){if(r(e)){var t=a(this,e),i=this._primitives;t!==i.length-1&&(i.splice(t,1),i.push(e))}},s.prototype.lower=function(e){if(r(e)){var t=a(this,e),i=this._primitives;if(0!==t){var n=i[t];i[t]=i[t-1],i[t-1]=n}}},s.prototype.lowerToBottom=function(e){if(r(e)){var t=a(this,e),i=this._primitives;0!==t&&(i.splice(t,1),i.unshift(e))}},s.prototype.get=function(e){return this._primitives[e]},s.prototype.update=function(e){if(this.show)for(var t=this._primitives,r=0;r<t.length;++r)t[r].update(e)},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this.removeAll(),n(this)},s}),r("Scene/QuadtreeTileProvider",["../Core/defineProperties","../Core/DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return r.computeDefaultLevelZeroMaximumGeometricError=function(e){return 2*e.ellipsoid.maximumRadius*Math.PI*.25/(65*e.getNumberOfXTilesAtLevel(0))},e(r.prototype,{quadtree:{get:t.throwInstantiationError,set:t.throwInstantiationError},ready:{get:t.throwInstantiationError},tilingScheme:{get:t.throwInstantiationError},errorEvent:{get:t.throwInstantiationError}}),r.prototype.beginUpdate=t.throwInstantiationError,r.prototype.endUpdate=t.throwInstantiationError,r.prototype.getLevelMaximumGeometricError=t.throwInstantiationError,r.prototype.loadTile=t.throwInstantiationError,r.prototype.computeTileVisibility=t.throwInstantiationError,r.prototype.showTileThisFrame=t.throwInstantiationError,r.prototype.computeDistanceToTile=t.throwInstantiationError,r.prototype.isDestroyed=t.throwInstantiationError,r.prototype.destroy=t.throwInstantiationError,r}),r("Scene/RectanglePrimitive",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/deprecationWarning","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/GeometryInstance","../Core/Math","../Core/Rectangle","../Core/RectangleGeometry","./EllipsoidSurfaceAppearance","./Material","./Primitive"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(r){i("RectanglePrimitive","RectanglePrimitive has been deprecated. Use RectangleGeometry or Entity.rectangle instead."),r=t(r,t.EMPTY_OBJECT),this.ellipsoid=t(r.ellipsoid,a.WGS84),this._ellipsoid=void 0,this.rectangle=u.clone(r.rectangle),this._rectangle=void 0,this.granularity=t(r.granularity,l.RADIANS_PER_DEGREE),this._granularity=void 0,this.height=t(r.height,0),this._height=void 0,this.rotation=t(r.rotation,0),this._rotation=void 0,this.textureRotationAngle=t(r.textureRotationAngle,0),this._textureRotationAngle=void 0,this.show=t(r.show,!0);var n=d.fromType(d.ColorType,{color:new e(1,1,0,.5)});this.material=t(r.material,n),this.id=r.id,this._id=void 0,this.asynchronous=t(r.asynchronous,!0),this.debugShowBoundingVolume=t(r.debugShowBoundingVolume,!1),this._primitive=void 0};return m.prototype.update=function(e){if(this.show&&r(this.rectangle)){if(!u.equals(this._rectangle,this.rectangle)||this._ellipsoid!==this.ellipsoid||this._granularity!==this.granularity||this._height!==this.height||this._rotation!==this.rotation||this._textureRotationAngle!==this.textureRotationAngle||this._id!==this.id){this._rectangle=u.clone(this.rectangle,this._rectangle),this._ellipsoid=this.ellipsoid,this._granularity=this.granularity,this._height=this.height,this._rotation=this.rotation,this._textureRotationAngle=this.textureRotationAngle,this._id=this.id;var t=new s({geometry:new c({rectangle:this.rectangle,vertexFormat:h.VERTEX_FORMAT,ellipsoid:this.ellipsoid,granularity:this.granularity,height:this.height,rotation:this.rotation,stRotation:this.textureRotationAngle}),id:this.id,pickPrimitive:this});r(this._primitive)&&this._primitive.destroy(),this._primitive=new p({geometryInstances:t,appearance:new h({aboveGround:this.height>0}),asynchronous:this.asynchronous})}var i=this._primitive;i.appearance.material=this.material,i.debugShowBoundingVolume=this.debugShowBoundingVolume,i.update(e)}},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),n(this)},m}),r("Scene/SceneTransitioner",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/EasingFunction","../Core/Ellipsoid","../Core/Math","../Core/Matrix4","../Core/ScreenSpaceEventHandler","../Core/ScreenSpaceEventType","./Camera","./OrthographicFrustum","./PerspectiveFrustum","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,t){if(e._scene.completeMorphOnUserInput){e._morphHandler=new u(e._scene.canvas,!1);var r=function(){e._morphCancelled=!0,t(e)};e._completeMorph=r,e._morphHandler.setInputAction(r,c.LEFT_DOWN),e._morphHandler.setInputAction(r,c.MIDDLE_DOWN),e._morphHandler.setInputAction(r,c.RIGHT_DOWN),e._morphHandler.setInputAction(r,c.WHEEL)}}function v(e){for(var t=e._currentTweens,r=0;r<t.length;++r)t[r].cancelTween();e._currentTweens.length=0,e._morphHandler=e._morphHandler&&e._morphHandler.destroy()}function _(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY);var u=s.position,c=s.direction,h=s.up,d=e.clone(t._camera2D.position),p=e.clone(t._camera2D.direction),m=e.clone(t._camera2D.up),f=function(t){s.position=y(u,d,t.time),s.direction=y(c,p,t.time),s.up=y(h,m,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)},v=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:f});t._currentTweens.push(v),x(t,a,0,1,r,n)}function g(e,t,r,i){t*=.5;var n=e._scene.camera;n._setTransform(l.IDENTITY),w(e,t,r,function(){n.frustum=e._cameraCV.frustum.clone(),_(e,t,r,i)})}function y(t,r,i){return e.lerp(t,r,i,new e)}function C(t,r,i){var n=t._scene,a=n.camera,l=a.position,u=a.frustum.fov,c=.5*s.RADIANS_PER_DEGREE,h=e.magnitude(l)*Math.tan(.5*u);a.frustum.far=h/Math.tan(.5*c)+1e7;var d=function(t){a.frustum.fov=s.lerp(u,c,t.time);var r=h/Math.tan(.5*a.frustum.fov),i=new e;a.position=e.multiplyByScalar(e.normalize(a.position,i),r,i)},p=n.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:d,complete:function(){a.frustum=t._camera2D.frustum.clone(),i(t)}});t._currentTweens.push(p)}function E(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY);var u=i.maximumRadius,c=e.clone(s.position),h=e.clone(s.direction),d=e.clone(s.up),p=Math.tan(.5*t._cameraCV.frustum.fovy),m=t._cameraCV.frustum.aspectRatio*p,f=u*Math.PI/m,v=new e;v=e.multiplyByScalar(e.normalize(t._camera2D.position,v),f,v);var _=e.clone(t._camera2D.direction),g=e.clone(t._camera2D.up),E=function(t){s.position=y(c,v,t.time),s.direction=y(h,_,t.time),s.up=y(d,g,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)};r*=.5;var S=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:E,complete:function(){C(t,r,n)}});t._currentTweens.push(S)}function S(t,r,i,n){r*=.5;var o=i.maximumRadius,a=Math.tan(.5*t._camera3D.frustum.fovy),s=t._camera3D.frustum.aspectRatio*a,l=o*Math.PI/s,u={},c=new e;u.position2D=e.multiplyByScalar(e.normalize(t._camera2D.position2D,c),l,c),u.direction2D=e.clone(t._camera2D.direction2D),u.up2D=e.clone(t._camera2D.up2D);var h=function(){C(t,r,n)};b(t,r,u,h)}function w(t,r,i,n){var a=t._scene,l=a.camera,u=i.maximumRadius,c=Math.tan(.5*t._cameraCV.frustum.fovy),h=t._cameraCV.frustum.aspectRatio*c,d=u*Math.PI/h,p=new e;p=e.multiplyByScalar(e.normalize(t._camera2D.position,p),d,p);var m=l.frustum.top,f=l.frustum.bottom,v=l.frustum.right,_=l.frustum.left,g=t._camera2D.frustum,C=t._cameraCV.frustum,E=e.clone(l.position),S=function(e){l.position=y(E,p,e.time),l.frustum.top=s.lerp(m,g.top,e.time),l.frustum.bottom=s.lerp(f,g.bottom,e.time),l.frustum.right=s.lerp(v,g.right,e.time),l.frustum.left=s.lerp(_,g.left,e.time)},w=(v-_)/(2*u*Math.PI),T=1;w>T&&(w=0);var b=(T-w)*r;if(b<s.EPSILON6){if(e.equalsEpsilon(E,p,s.EPSILON6))return l.position=p,l.frustum=C.clone(),void n(t);b=r,w=0,T=1}var x=a.tweens.add({easingFunction:o.QUARTIC_OUT,duration:b,startObject:{time:w},stopObject:{time:T},update:S,complete:function(){l.frustum=C.clone(),n(t)}});t._currentTweens.push(x)}function T(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY),r*=.5;var u=function(){var i=e.clone(s.position),l=e.clone(s.direction),u=e.clone(s.up),c=e.clone(t._cameraCV.position),h=e.clone(t._cameraCV.direction),d=e.clone(t._cameraCV.up),p=function(t){s.position=y(i,c,t.time),s.direction=y(l,h,t.time),s.up=y(u,d,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)},m=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:p,complete:function(){n(t)}});t._currentTweens.push(m)};w(t,r,i,u)}function b(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY);var u=e.clone(s.position),c=e.clone(s.direction),h=e.clone(s.up),d=e.clone(i.position2D),p=e.clone(i.direction2D),m=e.clone(i.up2D),f=function(t){s.position=y(u,d,t.time),s.direction=y(c,p,t.time),s.up=y(h,m,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)},v=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:f,complete:function(){s.position=d,s.direction=p,s.up=m,s.right=e.cross(p,m,s.right),e.normalize(s.right,s.right)}});t._currentTweens.push(v),x(t,a,1,0,r,n)}function x(e,t,i,n,a,s){var l={object:t,property:"morphTime",startValue:i,stopValue:n,duration:a,easingFunction:o.QUARTIC_OUT};r(s)&&(l.complete=function(){s(e)});var u=t.tweens.addProperty(l);e._currentTweens.push(u)}function P(e){var t=e._scene,r=t.drawingBufferHeight/t.drawingBufferWidth,i=e._camera2D.frustum;i.top=i.right*r,i.bottom=-i.top,r=1/r,i=e._cameraCV.frustum,i.aspectRatio=r,i=e._camera3D.frustum,i.aspectRatio=r;var n=t.camera;switch(t.mode){case m.SCENE3D:n.frustum=e._camera3D.frustum.clone();break;case m.COLUMBUS_VIEW:n.frustum=e._cameraCV.frustum.clone();break;case m.SCENE2D:n.frustum=e._camera2D.frustum.clone()}}function A(t){var i=t._scene;if(i._mode=m.SCENE3D,i.morphTime=m.getMorphTime(m.SCENE3D),v(t),P(t),t._previousMode!==m.MORPHING||t._morphCancelled){t._morphCancelled=!1;var n=i.camera;n.position=e.clone(t._camera3D.position),n.direction=e.clone(t._camera3D.direction),n.up=e.clone(t._camera3D.up),n.right=e.cross(n.direction,n.up,n.right),e.normalize(n.right,n.right)}var o=r(t._completeMorph);t._completeMorph=void 0,i.camera.update(i.mode),t._scene.morphComplete.raiseEvent(t,t._previousMode,m.SCENE3D,o)}function I(t){var i=t._scene;i._mode=m.SCENE2D,i.morphTime=m.getMorphTime(m.SCENE2D),v(t),P(t);var n=i.camera;e.clone(t._camera2D.position,n.position),e.clone(t._camera2D.direction,n.direction),e.clone(t._camera2D.up,n.up),e.cross(n.direction,n.up,n.right),e.normalize(n.right,n.right);var o=r(t._completeMorph);t._completeMorph=void 0,i.camera.update(i.mode),t._scene.morphComplete.raiseEvent(t,t._previousMode,m.SCENE2D,o)}function M(t){var i=t._scene;if(i._mode=m.COLUMBUS_VIEW,i.morphTime=m.getMorphTime(m.COLUMBUS_VIEW),v(t),P(t),t._previousModeMode!==m.MORPHING||t._morphCancelled){t._morphCancelled=!1;var n=i.camera;e.clone(t._cameraCV.position,n.position),e.clone(t._cameraCV.direction,n.direction),e.clone(t._cameraCV.up,n.up),e.cross(n.direction,n.up,n.right),e.normalize(n.right,n.right)}var o=r(t._completeMorph);t._completeMorph=void 0,i.camera.update(i.mode),t._scene.morphComplete.raiseEvent(t,t._previousMode,m.COLUMBUS_VIEW,o)}var D=function(r,i){this._scene=r,i=t(i,a.WGS84);var n=i.maximumRadius,o=new e(0,0,2*n),u=new e;u=e.normalize(e.negate(o,u),u);var c=e.clone(e.UNIT_Y),m=l.multiplyByPoint(h.TRANSFORM_2D,o,new e),f=l.multiplyByPointAsVector(h.TRANSFORM_2D,u,new e),v=l.multiplyByPointAsVector(h.TRANSFORM_2D,c,new e),_=new d;_.right=n*Math.PI,_.left=-_.right,_.top=_.right*(r.drawingBufferHeight/r.drawingBufferWidth),_.bottom=-_.top,this._camera2D={position:o,direction:u,up:c,position2D:m,direction2D:f,up2D:v,frustum:_},o=new e(0,-1,1),o=e.multiplyByScalar(e.normalize(o,o),5*n,o),u=new e,u=e.normalize(e.subtract(e.ZERO,o,u),u);var g=new e;g=e.normalize(e.cross(u,e.UNIT_Z,g),g),c=new e,c=e.normalize(e.cross(g,u,c),c),m=l.multiplyByPoint(h.TRANSFORM_2D,o,new e),f=l.multiplyByPointAsVector(h.TRANSFORM_2D,u,new e);var y=l.multiplyByPointAsVector(h.TRANSFORM_2D,g,new e);v=new e,v=e.normalize(e.cross(y,f,v),v),_=new p,_.aspectRatio=r.drawingBufferWidth/r.drawingBufferHeight,_.fov=s.toRadians(60),this._cameraCV={position:o,direction:u,up:c,position2D:m,direction2D:f,up2D:v,frustum:_},o=new e,o=e.multiplyByScalar(e.normalize(new e(0,-2,1),o),2*n,o),u=new e,u=e.normalize(e.subtract(e.ZERO,o,u),u),g=new e,g=e.normalize(e.cross(u,e.UNIT_Z,g),g),c=new e,c=e.normalize(e.cross(g,u,c),c),this._camera3D={position:o,direction:u,up:c,frustum:_},this._currentTweens=[],this._morphHandler=void 0,this._morphCancelled=!1,this._completeMorph=void 0};return D.prototype.completeMorph=function(){r(this._completeMorph)&&this._completeMorph()},D.prototype.morphTo2D=function(e,t){r(this._completeMorph)&&this._completeMorph();var i=this._scene;this._previousMode=i.mode,this._previousMode!==m.SCENE2D&&this._previousMode!==m.MORPHING&&(this._scene.morphStart.raiseEvent(this,this._previousMode,m.SCENE2D,!0),P(this),i._mode=m.MORPHING,f(this,I),this._previousMode===m.COLUMBUS_VIEW?E(this,e,t,I):S(this,e,t,I),0===e&&r(this._completeMorph)&&this._completeMorph())},D.prototype.morphToColumbusView=function(e,t){r(this._completeMorph)&&this._completeMorph();var i=this._scene;this._previousMode=i.mode,this._previousMode!==m.COLUMBUS_VIEW&&this._previousMode!==m.MORPHING&&(this._scene.morphStart.raiseEvent(this,this._previousMode,m.COLUMBUS_VIEW,!0),P(this),i._mode=m.MORPHING,f(this,M),this._previousMode===m.SCENE2D?T(this,e,t,M):b(this,e,this._cameraCV,M),0===e&&r(this._completeMorph)&&this._completeMorph())},D.prototype.morphTo3D=function(e,t){r(this._completeMorph)&&this._completeMorph();var i=this._scene;this._previousMode=i.mode,this._previousMode!==m.SCENE3D&&this._previousMode!==m.MORPHING&&(this._scene.morphStart.raiseEvent(this,this._previousMode,m.SCENE3D,!0),P(this),i._mode=m.MORPHING,f(this,A),this._previousMode===m.SCENE2D?g(this,e,t,A):_(this,e,t,A),0===e&&r(this._completeMorph)&&this._completeMorph())},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){return v(this),i(this)},D}),r("Scene/TweenCollection",["../Core/clone","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/EasingFunction","../Core/getTimestamp","../Core/TimeConstants","../ThirdParty/Tween"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(t,r,i,n,o,a,s,l,u,c){this._tweens=t,this._tweenjs=r,this._startObject=e(i),this._stopObject=e(n),this._duration=o,this._delay=a,this._easingFunction=s,this._update=l,this._complete=u,this.cancel=c,this.needsStart=!0};i(u.prototype,{startObject:{get:function(){return this._startObject}},stopObject:{get:function(){return this._stopObject}},duration:{get:function(){return this._duration}},delay:{get:function(){return this._delay}},easingFunction:{get:function(){return this._easingFunction}},update:{get:function(){return this._update}},complete:{get:function(){return this._complete}},tweenjs:{get:function(){return this._tweenjs}}}),u.prototype.cancelTween=function(){this._tweens.remove(this)};var c=function(){this._tweens=[]};return i(c.prototype,{length:{get:function(){return this._tweens.length}}}),c.prototype.add=function(i){if(i=t(i,t.EMPTY_OBJECT),0===i.duration)return r(i.complete)&&i.complete(),new u(this);var n=i.duration/s.SECONDS_PER_MILLISECOND,a=t(i.delay,0),c=a/s.SECONDS_PER_MILLISECOND,h=t(i.easingFunction,o.LINEAR_NONE),d=i.startObject,p=new l.Tween(d);p.to(e(i.stopObject),n),p.delay(c),p.easing(h),r(i.update)&&p.onUpdate(function(){i.update(d)}),p.onComplete(t(i.complete,null)),p.repeat(t(i._repeat,0));var m=new u(this,p,i.startObject,i.stopObject,i.duration,a,h,i.update,i.complete,i.cancel);return this._tweens.push(m),m},c.prototype.addProperty=function(e){function r(e){i[n]=e.value}e=t(e,t.EMPTY_OBJECT);var i=e.object,n=e.property,o=e.startValue,a=e.stopValue;return this.add({startObject:{value:o},stopObject:{value:a},duration:t(e.duration,3),delay:e.delay,easingFunction:e.easingFunction,update:r,complete:e.complete,cancel:e.cancel,_repeat:e._repeat})},c.prototype.addAlpha=function(e){function i(e){for(var t=o.length,r=0;t>r;++r)n.uniforms[o[r]].alpha=e.alpha}e=t(e,t.EMPTY_OBJECT);var n=e.material,o=[];for(var a in n.uniforms)n.uniforms.hasOwnProperty(a)&&r(n.uniforms[a])&&r(n.uniforms[a].alpha)&&o.push(a);return this.add({startObject:{alpha:t(e.startValue,0)},stopObject:{alpha:t(e.stopValue,1)},duration:t(e.duration,3),delay:e.delay,easingFunction:e.easingFunction,update:i,complete:e.complete,cancel:e.cancel})},c.prototype.addOffsetIncrement=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.material,i=r.uniforms;return this.addProperty({object:i,property:"offset",startValue:i.offset,stopValue:i.offset+1,duration:e.duration,delay:e.delay,easingFunction:e.easingFunction,update:e.update,cancel:e.cancel,_repeat:1/0})},c.prototype.remove=function(e){if(!r(e))return!1;var t=this._tweens.indexOf(e);return-1!==t?(e.tweenjs.stop(),r(e.cancel)&&e.cancel(),this._tweens.splice(t,1),!0):!1},c.prototype.removeAll=function(){for(var e=this._tweens,t=0;t<e.length;++t){var i=e[t];i.tweenjs.stop(),r(i.cancel)&&i.cancel()}e.length=0},c.prototype.contains=function(e){return r(e)&&-1!==this._tweens.indexOf(e)},c.prototype.get=function(e){return this._tweens[e]},c.prototype.update=function(e){var t=this._tweens,i=0;for(e=r(e)?e/s.SECONDS_PER_MILLISECOND:a();i<t.length;){var n=t[i],o=n.tweenjs;n.needsStart?(n.needsStart=!1,o.start(e)):o.update(e)?i++:(o.stop(),t.splice(i,1))}},c}),r("Scene/ScreenSpaceCameraController",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/IntersectionTests","../Core/isArray","../Core/KeyboardEventModifier","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Plane","../Core/Quaternion","../Core/Ray","../Core/Transforms","./CameraEventAggregator","./CameraEventType","./SceneMode","./SceneTransforms","./TweenCollection"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";function T(e,t){if(0>e)return 0;var r=25*(1-t);return Math.exp(-r*e)}function b(t){return e.equalsEpsilon(t.startPosition,t.endPosition,d.EPSILON14)}function x(t,r,i,n,a,s,l){var u=s[l];o(u)||(u=s[l]={startPosition:new e,endPosition:new e,motion:new e,active:!1});var c=t.getButtonPressTime(r,i),h=t.getButtonReleaseTime(r,i),d=c&&h&&(h.getTime()-c.getTime())/1e3,p=new Date,m=h&&(p.getTime()-h.getTime())/1e3;if(c&&h&&$>d){var f=T(m,n);if(u.active)u.startPosition=e.clone(u.endPosition,u.startPosition),u.endPosition=e.multiplyByScalar(u.motion,f,u.endPosition),u.endPosition=e.add(u.startPosition,u.endPosition,u.endPosition),u.motion=e.clone(e.ZERO,u.motion);else{var v=t.getLastMovement(r,i);if(!o(v)||b(v))return;u.motion.x=.5*(v.endPosition.x-v.startPosition.x),u.motion.y=.5*(v.endPosition.y-v.startPosition.y),u.startPosition=e.clone(v.startPosition,u.startPosition),u.endPosition=e.multiplyByScalar(u.motion,f,u.endPosition),u.endPosition=e.add(u.startPosition,u.endPosition,u.endPosition),u.active=!0}if(isNaN(u.endPosition.x)||isNaN(u.endPosition.y)||e.distance(u.startPosition,u.endPosition)<.5)return void(u.active=!1);if(!t.isButtonDown(r,i)){var _=t.getStartMousePosition(r,i);a(s,_,u)}}else u.active=!1}function P(e,t,r,i,n,a){if(o(r)){var s=e._aggregator;c(r)||(ee[0]=r,r=ee);for(var l=r.length,u=0;l>u;++u){var h=r[u],d=o(h.eventType)?h.eventType:h,p=h.modifier,m=s.isMoving(d,p)&&s.getMovement(d,p),f=s.getStartMousePosition(d,p);e.enableInputs&&t&&(m?i(e,f,m):1>n&&x(s,d,p,n,i,e,a))}}}function A(r,i,n,a,s,l){var u=1;o(l)&&(u=d.clamp(Math.abs(l),.25,1));var c=r.minimumZoomDistance*u,h=r.maximumZoomDistance,p=s-c,m=a*p;m=d.clamp(m,r._minimumZoomRate,r._maximumZoomRate);var f=n.endPosition.y-n.startPosition.y,v=f/r._scene.canvas.clientHeight;v=Math.min(v,r.maximumMovementRatio);var _=m*v;if(!(_>0&&Math.abs(s-c)<1||0>_&&Math.abs(s-h)<1)){c>s-_?_=s-c-1:s-_>h&&(_=s-h);var g,y=r._scene,C=y.camera,w=y.mode;if(o(r._globe)&&(g=w!==E.SCENE2D?N(r,i,re):C.getPickRay(i,te).origin),!o(g))return void C.zoomIn(_);var T=e.equals(i,r._zoomMouseStart),b=r._zoomingOnVector,x=r._rotatingZoom;T||(r._zoomMouseStart=e.clone(i,r._zoomMouseStart),r._zoomWorldPosition=t.clone(g,r._zoomWorldPosition),b=r._zoomingOnVector=!1,x=r._rotatingZoom=!1);var P=w===E.COLUMBUS_VIEW;if(!T||x){if(w===E.SCENE2D){var A=r._zoomWorldPosition,I=C.position;if(!t.equals(A,I)){var M=t.subtract(A,I,ne);t.normalize(M,M);var D=t.distance(A,I)*_/(.5*C.getMagnitude());C.move(M,.5*D)}}else if(w===E.SCENE3D){var R=t.normalize(C.position,ce);if(C.positionCartographic.height<3e3&&Math.abs(t.dot(C.direction,R))<.6)P=!0;else{var O=y.canvas,L=oe;L.x=O.clientWidth/2,L.y=O.clientHeight/2;var F=N(r,L,ae);if(o(F)){var B=t.normalize(F,se),V=t.normalize(r._zoomWorldPosition,le),z=t.dot(V,B);if(z>0){var k=d.acosClamped(z),U=t.cross(V,B,ue),G=Math.abs(k)>d.toRadians(20)?.75*C.positionCartographic.height:C.positionCartographic.height-_,W=_/G;C.rotate(U,k*W)}}else P=!0}}r._rotatingZoom=!P}if(!T&&P||b){var H,q=S.wgs84ToWindowCoordinates(y,r._zoomWorldPosition,ie);H=w!==E.COLUMBUS_VIEW&&e.equals(i,r._zoomMouseStart)&&o(q)?C.getPickRay(q,te):C.getPickRay(i,te);var j=H.direction;w===E.COLUMBUS_VIEW&&t.fromElements(j.y,j.z,j.x,j),C.move(j,_),r._zoomingOnVector=!0}else C.zoomIn(_)}}function I(e,r,i){var n=e._scene,o=n.camera,a=o.getPickRay(i.startPosition,he).origin,s=o.getPickRay(i.endPosition,de).origin,l=t.subtract(a,s,pe),u=t.magnitude(l);u>0&&(t.normalize(l,l),o.move(l,u))}function M(e,t,r){o(r.distance)&&(r=r.distance);var i=e._scene,n=i.camera;A(e,t,r,e._zoomFactor,n.getMagnitude())}function D(t,r,i){if(o(i.angleAndHeight))return void R(t,r,i.angleAndHeight);var n=t._scene,a=n.camera,s=n.canvas,l=s.clientWidth,u=s.clientHeight,c=me;c.x=2/l*i.startPosition.x-1,c.y=2/u*(u-i.startPosition.y)-1,c=e.normalize(c,c); +var h=fe;h.x=2/l*i.endPosition.x-1,h.y=2/u*(u-i.endPosition.y)-1,h=e.normalize(h,h);var p=d.acosClamped(c.x);c.y<0&&(p=d.TWO_PI-p);var m=d.acosClamped(h.x);h.y<0&&(m=d.TWO_PI-m);var f=m-p;a.twistRight(f)}function R(e,t,r){var i=e._rotateFactor*e._rotateRateRangeAdjustment;i>e._maximumRotateRate&&(i=e._maximumRotateRate),i<e._minimumRotateRate&&(i=e._minimumRotateRate);var n=e._scene,o=n.camera,a=n.canvas,s=(r.endPosition.x-r.startPosition.x)/a.clientWidth;s=Math.min(s,e.maximumMovementRatio);var l=i*s*Math.PI*4;o.twistRight(l)}function O(e){var t=e._tweens;e._aggregator.anyButtonDown&&t.removeAll();var r=e._scene,i=r.camera;if(t.contains(e._tween)||(m.equals(m.IDENTITY,i.transform)?(P(e,e.enableTranslate,e.translateEventTypes,I,e.inertiaTranslate,"_lastInertiaTranslateMovement"),P(e,e.enableZoom,e.zoomEventTypes,M,e.inertiaZoom,"_lastInertiaZoomMovement"),P(e,e.enableRotate,e.tiltEventTypes,D,e.inertiaSpin,"_lastInertiaTiltMovement")):(P(e,e.enableRotate,e.translateEventTypes,D,e.inertiaSpin,"_lastInertiaSpinMovement"),P(e,e.enableZoom,e.zoomEventTypes,M,e.inertiaZoom,"_lastInertiaZoomMovement"))),!(e._aggregator.anyButtonDown||o(e._lastInertiaZoomMovement)&&e._lastInertiaZoomMovement.active||o(e._lastInertiaTranslateMovement)&&e._lastInertiaTranslateMovement.active||t.contains(e._tween))){var n=i.createCorrectPositionTween(e.bounceAnimationTime);o(n)&&(e._tween=t.add(n))}t.update()}function N(e,r,i){var n=e._scene,a=e._globe,s=n.camera;if(!o(a))return void 0;var l;n.pickPositionSupported&&(l=n.pickPosition(r,_e));var u=s.getPickRay(r,ve),c=a.pick(u,n,ge),h=o(l)?t.distance(l,s.positionWC):Number.POSITIVE_INFINITY,d=o(c)?t.distance(c,s.positionWC):Number.POSITIVE_INFINITY;return d>h?t.clone(l,i):t.clone(c,i)}function L(r,i,n){if(t.equals(i,r._translateMousePosition)||(r._looking=!1),t.equals(i,r._strafeMousePosition)||(r._strafing=!1),r._looking)return void Z(r,i,n);if(r._strafing)return void U(r,i,n);var a,s=r._scene,l=s.camera,c=e.clone(n.startPosition,xe),h=e.clone(n.endPosition,Pe),p=l.getPickRay(c,ye),m=t.clone(t.ZERO,Te),v=t.UNIT_X;if(l.position.z<r.minimumPickingTerrainHeight&&(a=N(r,c,Ee),o(a)&&(m.x=a.x)),m.x>l.position.z&&o(a))return t.clone(a,r._strafeStartPosition),r._strafing=!0,U(r,i,n),void(r._strafeMousePosition=e.clone(i,r._strafeMousePosition));var _=f.fromPointNormal(m,v,be);p=l.getPickRay(c,ye);var g=u.rayPlane(p,_,Ee),y=l.getPickRay(h,Ce),C=u.rayPlane(y,_,Se);if(!o(g)||!o(C))return r._looking=!0,Z(r,i,n),void e.clone(i,r._translateMousePosition);var E=t.subtract(g,C,we),S=E.x;E.x=E.y,E.y=E.z,E.z=S;var w=t.magnitude(E);w>d.EPSILON6&&(t.normalize(E,E),l.move(E,w))}function F(t,r,i){if(o(i.angleAndHeight)&&(i=i.angleAndHeight),e.equals(r,t._tiltCenterMousePosition)||(t._tiltCVOffMap=!1,t._looking=!1),t._looking)return void Z(t,r,i);var n=t._scene,a=n.camera,s=t._maxCoord,l=Math.abs(a.position.x)-s.x<0&&Math.abs(a.position.y)-s.y<0;t._tiltCVOffMap||!l||a.position.z>t.minimumPickingTerrainHeight?(t._tiltCVOffMap=!0,B(t,r,i)):V(t,r,i)}function B(r,i,n){var a=r._scene,s=a.camera,u=a.canvas,c=Ae;c.x=u.clientWidth/2,c.y=u.clientHeight/2;var h,p=s.getPickRay(c,Ie),f=t.UNIT_X,v=p.origin,_=p.direction,y=t.dot(f,_);if(Math.abs(y)>d.EPSILON6&&(h=-t.dot(f,v)/y),!o(h)||0>=h)return r._looking=!0,Z(r,i,n),void e.clone(i,r._tiltCenterMousePosition);var C=t.multiplyByScalar(_,h,Me);t.add(v,C,C);var E=a.mapProjection,S=E.ellipsoid;t.fromElements(C.y,C.z,C.x,C);var w=E.unproject(C,Be);S.cartographicToCartesian(w,C);var T=g.eastNorthUpToFixedFrame(C,S,Re),b=r._globe,x=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var P=m.clone(s.transform,Ve);s._setTransform(T),W(r,i,n,t.UNIT_Z),s._setTransform(P),r._globe=b,r._ellipsoid=x;var A=x.maximumRadius;r._rotateFactor=1/A,r._rotateRateRangeAdjustment=A}function V(r,i,n){var a,s,c=r._ellipsoid,h=r._scene,_=h.camera,y=t.UNIT_X;if(e.equals(i,r._tiltCenterMousePosition))a=t.clone(r._tiltCenter,Me);else{if(_.position.z<r.minimumPickingTerrainHeight&&(a=N(r,i,Me)),!o(a)){s=_.getPickRay(i,Ie);var C,E=s.origin,S=s.direction,w=t.dot(y,S);if(Math.abs(w)>d.EPSILON6&&(C=-t.dot(y,E)/w),!o(C)||0>=C)return r._looking=!0,Z(r,i,n),void e.clone(i,r._tiltCenterMousePosition);a=t.multiplyByScalar(S,C,Me),t.add(E,a,a)}e.clone(i,r._tiltCenterMousePosition),t.clone(a,r._tiltCenter)}var T=h.canvas,b=Ae;b.x=T.clientWidth/2,b.y=r._tiltCenterMousePosition.y,s=_.getPickRay(b,Ie);var x=t.clone(t.ZERO,Ne);x.x=a.x;var P=f.fromPointNormal(x,y,Le),A=u.rayPlane(s,P,De),I=_._projection;c=I.ellipsoid,t.fromElements(a.y,a.z,a.x,a);var M=I.unproject(a,Be);c.cartographicToCartesian(M,a);var D,R=g.eastNorthUpToFixedFrame(a,c,Re);o(A)?(t.fromElements(A.y,A.z,A.x,A),M=I.unproject(A,Be),c.cartographicToCartesian(M,A),D=g.eastNorthUpToFixedFrame(A,c,Oe)):D=R;var O=r._globe,L=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var F=t.UNIT_Z,B=m.clone(_.transform,Ve);_._setTransform(R);var V=t.cross(t.UNIT_Z,t.normalize(_.position,Fe),Fe),z=t.dot(_.right,V);if(W(r,i,n,F,!1,!0),_._setTransform(D),0>z){n.startPosition.y>n.endPosition.y&&(F=void 0);var k=_.constrainedAxis;_.constrainedAxis=void 0,W(r,i,n,F,!0,!1),_.constrainedAxis=k}else W(r,i,n,F,!0,!1);if(o(_.constrainedAxis)){var U=t.cross(_.direction,_.constrainedAxis,vt);t.equalsEpsilon(U,t.ZERO,d.EPSILON6)||(t.dot(U,_.right)<0&&t.negate(U,U),t.cross(U,_.direction,_.up),t.cross(_.direction,_.up,_.right),t.normalize(_.up,_.up),t.normalize(_.right,_.right))}_._setTransform(B),r._globe=O,r._ellipsoid=L;var G=L.maximumRadius;r._rotateFactor=1/G,r._rotateRateRangeAdjustment=G;var H=t.clone(_.positionWC,Fe);if(J(r),!t.equals(_.positionWC,H)){_._setTransform(D),_.worldToCameraCoordinatesPoint(H,H);var q=t.magnitudeSquared(H);t.magnitudeSquared(_.position)>q&&(t.normalize(_.position,_.position),t.multiplyByScalar(_.position,Math.sqrt(q),_.position));var j=t.angleBetween(H,_.position),Y=t.cross(H,_.position,H);t.normalize(Y,Y);var X=v.fromAxisAngle(Y,j,ze),K=p.fromQuaternion(X,ke);p.multiplyByVector(K,_.direction,_.direction),p.multiplyByVector(K,_.up,_.up),t.cross(_.direction,_.up,_.right),t.cross(_.right,_.direction,_.up),_._setTransform(B)}}function z(e,r,i){o(i.distance)&&(i=i.distance);var n=e._scene,a=n.camera,s=n.canvas,l=Ue;l.x=s.clientWidth/2,l.y=s.clientHeight/2;var u,c=a.getPickRay(l,Ge);a.position.z<e.minimumPickingTerrainHeight&&(u=N(e,l,We));var h;if(o(u))h=t.distance(c.origin,u);else{var d=t.UNIT_X,p=c.origin,m=c.direction;h=-t.dot(d,p)/t.dot(d,m)}A(e,r,i,e._zoomFactor,h)}function k(e){var t=e._scene,r=t.camera;if(m.equals(m.IDENTITY,r.transform)){var i=e._tweens;if(e._aggregator.anyButtonDown&&i.removeAll(),P(e,e.enableTilt,e.tiltEventTypes,F,e.inertiaSpin,"_lastInertiaTiltMovement"),P(e,e.enableTranslate,e.translateEventTypes,L,e.inertiaTranslate,"_lastInertiaTranslateMovement"),P(e,e.enableZoom,e.zoomEventTypes,z,e.inertiaZoom,"_lastInertiaZoomMovement"),P(e,e.enableLook,e.lookEventTypes,Z),!(e._aggregator.anyButtonDown||o(e._lastInertiaZoomMovement)&&e._lastInertiaZoomMovement.active||o(e._lastInertiaTranslateMovement)&&e._lastInertiaTranslateMovement.active||i.contains(e._tween))){var n=r.createCorrectPositionTween(e.bounceAnimationTime);o(n)&&(e._tween=i.add(n))}i.update()}else P(e,e.enableRotate,e.rotateEventTypes,W,e.inertiaSpin,"_lastInertiaSpinMovement"),P(e,e.enableZoom,e.zoomEventTypes,q,e.inertiaZoom,"_lastInertiaZoomMovement")}function U(e,r,i){var n=e._scene,a=n.camera,s=N(e,i.startPosition,Ke);if(o(s)){var l=i.endPosition,c=a.getPickRay(l,He),h=t.clone(a.direction,Ye);n.mode===E.COLUMBUS_VIEW&&t.fromElements(h.z,h.x,h.y,h);var d=f.fromPointNormal(s,h,qe),p=u.rayPlane(c,d,je);o(p)&&(h=t.subtract(s,p,h),n.mode===E.COLUMBUS_VIEW&&t.fromElements(h.y,h.z,h.x,h),t.add(a.position,h,a.position))}}function G(r,i,n){var a=r._scene,s=a.camera;if(!m.equals(s.transform,m.IDENTITY))return void W(r,i,n);var u,c,h,d,p=r._ellipsoid.geodeticSurfaceNormal(s.position,$e),f=r._ellipsoid.cartesianToCartographic(s.positionWC,Ze).height,v=r._globe,_=!1;if(o(v)&&f<r.minimumPickingTerrainHeight&&(d=N(r,n.startPosition,Ke),o(d))){var g=s.getPickRay(n.startPosition,ve),y=r._ellipsoid.geodeticSurfaceNormal(d);_=Math.abs(t.dot(g.direction,y))<.05,_&&!r._looking&&(r._rotating=!1,r._strafing=!0)}return e.equals(i,r._rotateMousePosition)?void(r._looking?Z(r,i,n,p):r._rotating?W(r,i,n):r._strafing?(t.clone(d,r._strafeStartPosition),U(r,i,n)):(u=t.magnitude(r._rotateStartPosition),c=Je,c.x=c.y=c.z=u,h=l.fromCartesian3(c,Qe),H(r,i,n,h))):(r._looking=!1,r._rotating=!1,r._strafing=!1,o(v)&&f<r.minimumPickingTerrainHeight?o(d)?t.magnitude(s.position)<t.magnitude(d)?(t.clone(d,r._strafeStartPosition),r._strafing=!0,U(r,i,n)):(u=t.magnitude(d),c=Je,c.x=c.y=c.z=u,h=l.fromCartesian3(c,Qe),H(r,i,n,h),t.clone(d,r._rotateStartPosition)):(r._looking=!0,Z(r,i,n,p)):o(s.pickEllipsoid(n.startPosition,r._ellipsoid,Xe))?(H(r,i,n,r._ellipsoid),t.clone(Xe,r._rotateStartPosition)):f>r.minimumTrackBallHeight?(r._rotating=!0,W(r,i,n)):(r._looking=!0,Z(r,i,n,p)),void e.clone(i,r._rotateMousePosition))}function W(e,r,i,a,s,l){s=n(s,!1),l=n(l,!1);var u=e._scene,c=u.camera,h=u.canvas,d=c.constrainedAxis;o(a)&&(c.constrainedAxis=a);var p=t.magnitude(c.position),m=e._rotateFactor*(p-e._rotateRateRangeAdjustment);m>e._maximumRotateRate&&(m=e._maximumRotateRate),m<e._minimumRotateRate&&(m=e._minimumRotateRate);var f=(i.startPosition.x-i.endPosition.x)/h.clientWidth,v=(i.startPosition.y-i.endPosition.y)/h.clientHeight;f=Math.min(f,e.maximumMovementRatio),v=Math.min(v,e.maximumMovementRatio);var _=m*f*Math.PI*2,g=m*v*Math.PI;s||c.rotateRight(_),l||c.rotateUp(g),c.constrainedAxis=d}function H(r,i,n,a){var s=r._scene,l=s.camera,u=e.clone(n.startPosition,at),c=e.clone(n.endPosition,st),h=l.pickEllipsoid(u,a,et),p=l.pickEllipsoid(c,a,tt);if(!o(h)||!o(p))return r._rotating=!0,void W(r,i,n);if(h=l.worldToCameraCoordinates(h,h),p=l.worldToCameraCoordinates(p,p),o(l.constrainedAxis)){var m=l.constrainedAxis,f=t.mostOrthogonalAxis(m,rt);t.cross(f,m,f),t.normalize(f,f);var v=t.cross(m,f,it),_=t.magnitude(h),g=t.dot(m,h),y=Math.acos(g/_),C=t.multiplyByScalar(m,g,nt);t.subtract(h,C,C),t.normalize(C,C);var E=t.magnitude(p),S=t.dot(m,p),w=Math.acos(S/E),T=t.multiplyByScalar(m,S,ot);t.subtract(p,T,T),t.normalize(T,T);var b=Math.acos(t.dot(C,f));t.dot(C,v)<0&&(b=d.TWO_PI-b);var x=Math.acos(t.dot(T,f));t.dot(T,v)<0&&(x=d.TWO_PI-x);var P,A=b-x;P=t.equalsEpsilon(m,l.position,d.EPSILON2)?l.right:t.cross(m,l.position,rt);var I,M=t.cross(m,P,rt),D=t.dot(M,t.subtract(h,m,it)),R=t.dot(M,t.subtract(p,m,it));I=D>0&&R>0?w-y:D>0&&0>=R?t.dot(l.position,m)>0?-y-w:y+w:y-w,l.rotateRight(A),l.rotateUp(I)}else{t.normalize(h,h),t.normalize(p,p);var O=t.dot(h,p),N=t.cross(h,p,rt);if(1>O&&!t.equalsEpsilon(N,t.ZERO,d.EPSILON14)){var L=Math.acos(O);l.rotate(N,L)}}}function q(e,r,i){o(i.distance)&&(i=i.distance);var n=e._ellipsoid,a=e._scene,s=a.camera,l=a.canvas,u=Ue;u.x=l.clientWidth/2,u.y=l.clientHeight/2;var c,h=s.getPickRay(u,Ge),d=n.cartesianToCartographic(s.position,ut).height;d<e.minimumPickingTerrainHeight&&(c=N(e,u,We));var p;p=o(c)?t.distance(h.origin,c):d;var m=t.normalize(s.position,lt);A(e,r,i,e._zoomFactor,p,t.dot(m,s.direction))}function j(t,r,i){var n=t._scene,a=n.camera;if(m.equals(a.transform,m.IDENTITY)){if(o(i.angleAndHeight)&&(i=i.angleAndHeight),e.equals(r,t._tiltCenterMousePosition)||(t._tiltOnEllipsoid=!1,t._looking=!1),t._looking){var s=t._ellipsoid.geodeticSurfaceNormal(a.position,Et);return void Z(t,r,i,s)}var l=t._ellipsoid,u=l.cartesianToCartographic(a.position,Ct);t._tiltOnEllipsoid||u.height>t.minimumCollisionTerrainHeight?(t._tiltOnEllipsoid=!0,Y(t,r,i)):X(t,r,i)}}function Y(r,i,n){var a=r._ellipsoid,s=r._scene,c=s.camera,h=.25*r.minimumZoomDistance,p=a.cartesianToCartographic(c.positionWC,St).height;if(!(p-h-1<d.EPSILON3&&n.endPosition.y-n.startPosition.y<0)){var f=s.canvas,v=ct;v.x=f.clientWidth/2,v.y=f.clientHeight/2;var y,C=c.getPickRay(v,ht),E=u.rayEllipsoid(C,a);if(o(E))y=_.getPoint(C,E.start,dt);else{if(!(p>r.minimumTrackBallHeight)){r._looking=!0;var S=r._ellipsoid.geodeticSurfaceNormal(c.position,Et);return Z(r,i,n,S),void e.clone(i,r._tiltCenterMousePosition)}var w=u.grazingAltitudeLocation(C,a);if(!o(w))return;var T=a.cartesianToCartographic(w,Ct);T.height=0,y=a.cartographicToCartesian(T,dt)}var b=g.eastNorthUpToFixedFrame(y,a,mt),x=r._globe,P=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var A=m.clone(c.transform,_t);c._setTransform(b),W(r,i,n,t.UNIT_Z),c._setTransform(A),r._globe=x,r._ellipsoid=P;var I=P.maximumRadius;r._rotateFactor=1/I,r._rotateRateRangeAdjustment=I}}function X(r,i,n){var a,s,c,h=r._ellipsoid,f=r._scene,y=f.camera;if(e.equals(i,r._tiltCenterMousePosition))a=t.clone(r._tiltCenter,dt);else{if(a=N(r,i,dt),!o(a)){if(s=y.getPickRay(i,ht),c=u.rayEllipsoid(s,h),!o(c)){var C=h.cartesianToCartographic(y.position,Ct);if(C.height<=r.minimumTrackBallHeight){r._looking=!0;var E=r._ellipsoid.geodeticSurfaceNormal(y.position,Et);Z(r,i,n,E),e.clone(i,r._tiltCenterMousePosition)}return}a=_.getPoint(s,c.start,dt)}e.clone(i,r._tiltCenterMousePosition),t.clone(a,r._tiltCenter)}var S=f.canvas,w=ct;w.x=S.clientWidth/2,w.y=r._tiltCenterMousePosition.y,s=y.getPickRay(w,ht);var T=t.magnitude(a),b=t.fromElements(T,T,T,Je),x=l.fromCartesian3(b,Qe);if(c=u.rayEllipsoid(s,x),o(c)){var P=t.magnitude(s.origin)>T?c.start:c.stop,A=_.getPoint(s,P,pt),I=g.eastNorthUpToFixedFrame(a,h,mt),M=g.eastNorthUpToFixedFrame(A,x,ft),D=r._globe,R=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var O=t.UNIT_Z,L=m.clone(y.transform,_t);y._setTransform(I);var F=t.cross(A,y.positionWC,vt),B=t.dot(y.rightWC,F);if(W(r,i,n,O,!1,!0),y._setTransform(M),0>B){n.startPosition.y>n.endPosition.y&&(O=void 0);var V=y.constrainedAxis;y.constrainedAxis=void 0,W(r,i,n,O,!0,!1),y.constrainedAxis=V}else W(r,i,n,O,!0,!1);if(o(y.constrainedAxis)){var z=t.cross(y.direction,y.constrainedAxis,vt);t.equalsEpsilon(z,t.ZERO,d.EPSILON6)||(t.dot(z,y.right)<0&&t.negate(z,z),t.cross(z,y.direction,y.up),t.cross(y.direction,y.up,y.right),t.normalize(y.up,y.up),t.normalize(y.right,y.right))}y._setTransform(L),r._globe=D,r._ellipsoid=R;var k=R.maximumRadius;r._rotateFactor=1/k,r._rotateRateRangeAdjustment=k;var U=t.clone(y.positionWC,vt);if(J(r),!t.equals(y.positionWC,U)){y._setTransform(M),y.worldToCameraCoordinatesPoint(U,U);var G=t.magnitudeSquared(U);t.magnitudeSquared(y.position)>G&&(t.normalize(y.position,y.position),t.multiplyByScalar(y.position,Math.sqrt(G),y.position));var H=t.angleBetween(U,y.position),q=t.cross(U,y.position,U);t.normalize(q,q);var j=v.fromAxisAngle(q,H,gt),Y=p.fromQuaternion(j,yt);p.multiplyByVector(Y,y.direction,y.direction),p.multiplyByVector(Y,y.up,y.up),t.cross(y.direction,y.up,y.right),t.cross(y.right,y.direction,y.up),y._setTransform(L)}}}function Z(e,r,i,a){var s=e._scene,l=s.camera,u=wt;u.x=i.startPosition.x,u.y=0;var c=Tt;c.x=i.endPosition.x,c.y=0;var h=l.getPickRay(u,bt).direction,p=l.getPickRay(c,xt).direction,m=0,f=t.dot(h,p);1>f&&(m=Math.acos(f)),m=i.startPosition.x>i.endPosition.x?-m:m;var v=e._horizontalRotationAxis;if(o(a)?l.look(a,-m):o(v)?l.look(v,-m):l.lookLeft(m),u.x=0,u.y=i.startPosition.y,c.x=0,c.y=i.endPosition.y,h=l.getPickRay(u,bt).direction,p=l.getPickRay(c,xt).direction,m=0,f=t.dot(h,p),1>f&&(m=Math.acos(f)),m=i.startPosition.y>i.endPosition.y?-m:m,a=n(a,v),o(a)){var _=l.direction,g=t.negate(a,Pt),y=t.equalsEpsilon(_,a,d.EPSILON2),C=t.equalsEpsilon(_,g,d.EPSILON2);if(y||C)(y&&0>m||C&&m>0)&&l.look(l.right,-m);else{f=t.dot(_,a);var E=d.acosClamped(f);m>0&&m>E&&(m=E-d.EPSILON4),f=t.dot(_,g),E=d.acosClamped(f),0>m&&-m>E&&(m=-E+d.EPSILON4);var S=t.cross(a,_,At);l.look(S,m)}}else l.lookUp(m)}function K(e){P(e,e.enableRotate,e.rotateEventTypes,G,e.inertiaSpin,"_lastInertiaSpinMovement"),P(e,e.enableZoom,e.zoomEventTypes,q,e.inertiaZoom,"_lastInertiaZoomMovement"),P(e,e.enableTilt,e.tiltEventTypes,j,e.inertiaSpin,"_lastInertiaTiltMovement"),P(e,e.enableLook,e.lookEventTypes,Z)}function J(e){if(e.enableCollisionDetection){var r=e._scene,i=r.mode,n=r.globe;if(o(n)&&i!==E.SCENE2D&&i!==E.MORPHING){var a,s,l=r.camera,u=n.ellipsoid,c=r.mapProjection;m.equals(l.transform,m.IDENTITY)||(a=m.clone(l.transform),s=t.magnitude(l.position),l._setTransform(m.IDENTITY));var h=It;i===E.SCENE3D?u.cartesianToCartographic(l.position,h):c.unproject(l.position,h);var d=!1;if(h.height<e.minimumCollisionTerrainHeight){var p=n.getHeight(h);o(p)&&(p+=e.minimumZoomDistance,h.height<p&&(h.height=p,i===E.SCENE3D?u.cartographicToCartesian(h,l.position):c.project(h,l.position),d=!0))}o(a)&&(l._setTransform(a),d&&(t.normalize(l.position,l.position),t.negate(l.position,l.direction),t.multiplyByScalar(l.position,Math.max(s,e.minimumZoomDistance),l.position),t.normalize(l.direction,l.direction),t.cross(l.direction,l.up,l.right),t.cross(l.right,l.direction,l.up)))}}}var Q=function(r){this.enableInputs=!0,this.enableTranslate=!0,this.enableZoom=!0,this.enableRotate=!0,this.enableTilt=!0,this.enableLook=!0,this.inertiaSpin=.9,this.inertiaTranslate=.9,this.inertiaZoom=.8,this.maximumMovementRatio=.1,this.bounceAnimationTime=3,this.minimumZoomDistance=1,this.maximumZoomDistance=Number.POSITIVE_INFINITY,this.translateEventTypes=C.LEFT_DRAG,this.zoomEventTypes=[C.RIGHT_DRAG,C.WHEEL,C.PINCH],this.rotateEventTypes=C.LEFT_DRAG,this.tiltEventTypes=[C.MIDDLE_DRAG,C.PINCH,{eventType:C.LEFT_DRAG,modifier:h.CTRL},{eventType:C.RIGHT_DRAG,modifier:h.CTRL}],this.lookEventTypes={eventType:C.LEFT_DRAG,modifier:h.SHIFT},this.minimumPickingTerrainHeight=15e4,this.minimumCollisionTerrainHeight=15e3,this.minimumTrackBallHeight=75e5,this.enableCollisionDetection=!0,this._scene=r,this._globe=void 0,this._ellipsoid=void 0,this._aggregator=new y(r.canvas),this._lastInertiaSpinMovement=void 0,this._lastInertiaZoomMovement=void 0,this._lastInertiaTranslateMovement=void 0,this._lastInertiaWheelZoomMovement=void 0,this._lastInertiaTiltMovement=void 0,this._tweens=new w,this._tween=void 0,this._horizontalRotationAxis=void 0,this._tiltCenterMousePosition=new e(-1,-1),this._tiltCenter=new t,this._rotateMousePosition=new e(-1,-1),this._rotateStartPosition=new t,this._strafeStartPosition=new t,this._zoomMouseStart=new e,this._zoomWorldPosition=new t,this._tiltCVOffMap=!1,this._looking=!1,this._rotating=!1,this._strafing=!1,this._zoomingOnVector=!1,this._rotatingZoom=!1;var n=r.mapProjection;this._maxCoord=n.project(new i(Math.PI,d.PI_OVER_TWO)),this._zoomFactor=5,this._rotateFactor=void 0,this._rotateRateRangeAdjustment=void 0,this._maximumRotateRate=1.77,this._minimumRotateRate=2e-4,this._translateFactor=1,this._minimumZoomRate=20,this._maximumZoomRate=5906376272e3},$=.4,ee=[],te=new _,re=new t,ie=new e,ne=new t,oe=new e,ae=new t,se=new t,le=new t,ue=new t,ce=new t,he=new _,de=new _,pe=new t,me=new e,fe=new e,ve=new _,_e=new t,ge=new t,ye=new _,Ce=new _,Ee=new t,Se=new t,we=new t,Te=new t,be=new f(t.ZERO,0),xe=new e,Pe=new e,Ae=new e,Ie=new _,Me=new t,De=new t,Re=new m,Oe=new m,Ne=new t,Le=new f(t.ZERO,0),Fe=new t,Be=new i,Ve=new m,ze=new v,ke=new p,Ue=new e,Ge=new _,We=new t,He=new _,qe=new f(t.ZERO,0),je=new t,Ye=new t,Xe=new t,Ze=(new _,new i),Ke=new t,Je=new t,Qe=new l,$e=new t,et=r.clone(r.UNIT_W),tt=r.clone(r.UNIT_W),rt=new t,it=new t,nt=new t,ot=new t,at=new e,st=new e,lt=new t,ut=new i,ct=new e,ht=new _,dt=new t,pt=new t,mt=new m,ft=new m,vt=new t,_t=new m,gt=new v,yt=new p,Ct=new i,Et=new t,St=new i,wt=new e,Tt=new e,bt=new _,xt=new _,Pt=new t,At=new t,It=new i;return Q.prototype.update=function(){m.equals(this._scene.camera.transform,m.IDENTITY)?(this._globe=this._scene.globe,this._ellipsoid=o(this._globe)?this._globe.ellipsoid:this._scene.mapProjection.ellipsoid):(this._globe=void 0,this._ellipsoid=l.UNIT_SPHERE);var e=this._ellipsoid.maximumRadius;this._rotateFactor=1/e,this._rotateRateRangeAdjustment=e;var r=this._scene,i=r.mode;i===E.SCENE2D?O(this):i===E.COLUMBUS_VIEW?(this._horizontalRotationAxis=t.UNIT_Z,k(this)):i===E.SCENE3D&&(this._horizontalRotationAxis=void 0,K(this)),J(this),this._aggregator.reset()},Q.prototype.isDestroyed=function(){return!1},Q.prototype.destroy=function(){return this._tweens.removeAll(),this._aggregator=this._aggregator&&this._aggregator.destroy(),a(this)},Q}),r("Shaders/PostProcessFilters/AdditiveBlend",[],function(){"use strict";return"uniform sampler2D u_texture0;\nuniform sampler2D u_texture1;\nuniform vec2 u_center;\nuniform float u_radius;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec4 color0 = texture2D(u_texture0, v_textureCoordinates);\nvec4 color1 = texture2D(u_texture1, v_textureCoordinates);\nfloat x = length(gl_FragCoord.xy - u_center) / u_radius;\nfloat t = smoothstep(0.5, 0.8, x);\ngl_FragColor = mix(color0 + color1, color0, t);\n}\n"}),r("Shaders/PostProcessFilters/BrightPass",[],function(){"use strict";return"uniform sampler2D u_texture;\nuniform float u_avgLuminance;\nuniform float u_threshold;\nuniform float u_offset;\nvarying vec2 v_textureCoordinates;\nfloat key(float avg)\n{\nfloat guess = 1.5 - (1.5 / (avg * 0.1 + 1.0));\nreturn max(0.0, guess) + 0.1;\n}\nvoid main()\n{\nvec4 color = texture2D(u_texture, v_textureCoordinates);\nvec3 xyz = czm_RGBToXYZ(color.rgb);\nfloat luminance = xyz.r;\nfloat scaledLum = key(u_avgLuminance) * luminance / u_avgLuminance;\nfloat brightLum = max(scaledLum - u_threshold, 0.0);\nfloat brightness = brightLum / (u_offset + brightLum);\nxyz.r = brightness;\ngl_FragColor = vec4(czm_XYZToRGB(xyz), 1.0);\n}\n"}),r("Shaders/PostProcessFilters/GaussianBlur1D",[],function(){"use strict";return"#define SAMPLES 8\nuniform float delta;\nuniform float sigma;\nuniform float direction;\nuniform sampler2D u_texture;\nuniform vec2 u_step;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec2 st = v_textureCoordinates;\nvec2 dir = vec2(1.0 - direction, direction);\nvec3 g;\ng.x = 1.0 / (sqrt(czm_twoPi) * sigma);\ng.y = exp((-0.5 * delta * delta) / (sigma * sigma));\ng.z = g.y * g.y;\nvec4 result = texture2D(u_texture, st) * g.x;\nfor (int i = 1; i < SAMPLES; ++i)\n{\ng.xy *= g.yz;\nvec2 offset = float(i) * dir * u_step;\nresult += texture2D(u_texture, st - offset) * g.x;\nresult += texture2D(u_texture, st + offset) * g.x;\n}\ngl_FragColor = result;\n}\n"}),r("Scene/SunPostProcess",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian4","../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/Math","../Core/Matrix4","../Core/PixelFormat","../Core/Transforms","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PassState","../Renderer/PixelDatatype","../Renderer/Renderbuffer","../Renderer/RenderbufferFormat","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/AdditiveBlend","../Shaders/PostProcessFilters/BrightPass","../Shaders/PostProcessFilters/GaussianBlur1D","../Shaders/PostProcessFilters/PassThrough"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";var w=function(){this._fbo=void 0,this._downSampleFBO1=void 0,this._downSampleFBO2=void 0,this._clearFBO1Command=void 0,this._clearFBO2Command=void 0,this._downSampleCommand=void 0,this._brightPassCommand=void 0,this._blurXCommand=void 0,this._blurYCommand=void 0,this._blendCommand=void 0,this._fullScreenCommand=void 0,this._downSamplePassState=new p,this._downSamplePassState.scissorTest={enable:!0,rectangle:new e},this._upSamplePassState=new p,this._upSamplePassState.scissorTest={enabled:!0,rectangle:new e},this._uCenter=new t,this._uRadius=void 0,this._blurStep=new t};w.prototype.clear=function(e,t){var r=this._clearFBO1Command;i.clone(n(t,i.BLACK),r.color),r.execute(e),r=this._clearFBO2Command,i.clone(n(t,i.BLACK),r.color),r.execute(e)},w.prototype.execute=function(e,t){this._downSampleCommand.execute(e,this._downSamplePassState),this._brightPassCommand.execute(e,this._downSamplePassState),this._blurXCommand.execute(e,this._downSamplePassState),this._blurYCommand.execute(e,this._downSamplePassState),this._fullScreenCommand.framebuffer=t,this._blendCommand.framebuffer=t,this._fullScreenCommand.execute(e),this._blendCommand.execute(e,this._upSamplePassState)};var T=new e,b=new e,x=new r,P=new t,A=new t,I=new l;return w.prototype.update=function(e){var r=e.drawingBufferWidth,n=e.drawingBufferHeight,a=this;if(!o(this._downSampleCommand)){this._clearFBO1Command=new h({color:new i}),this._clearFBO2Command=new h({color:new i});var p,w={};this._downSampleCommand=e.createViewportQuadCommand(S,{renderState:p,uniformMap:w,owner:this}),w={u_avgLuminance:function(){return.5},u_threshold:function(){return.25},u_offset:function(){return.1}},this._brightPassCommand=e.createViewportQuadCommand(C,{renderState:p,uniformMap:w,owner:this});var M=1,D=2;w={delta:function(){return M},sigma:function(){return D},direction:function(){return 0}},this._blurXCommand=e.createViewportQuadCommand(E,{renderState:p,uniformMap:w,owner:this}),w={delta:function(){return M},sigma:function(){return D},direction:function(){return 1}},this._blurYCommand=e.createViewportQuadCommand(E,{renderState:p,uniformMap:w,owner:this}),w={u_center:function(){return a._uCenter},u_radius:function(){return a._uRadius}},this._blendCommand=e.createViewportQuadCommand(y,{renderState:p,uniformMap:w,owner:this}),w={},this._fullScreenCommand=e.createViewportQuadCommand(S,{renderState:p,uniformMap:w,owner:this})}var R=Math.pow(2,Math.ceil(Math.log(r)/Math.log(2))-2),O=Math.pow(2,Math.ceil(Math.log(n)/Math.log(2))-2),N=Math.max(R,O),L=T;L.width=r,L.height=n;var F=b;F.width=N,F.height=N;var B=this._fbo,V=o(B)&&B.getColorTexture(0)||void 0;if(!o(V)||V.width!==r||V.height!==n){B=B&&B.destroy(),this._downSampleFBO1=this._downSampleFBO1&&this._downSampleFBO1.destroy(),this._downSampleFBO2=this._downSampleFBO2&&this._downSampleFBO2.destroy(),this._blurStep.x=this._blurStep.y=1/N;var z=[new g({context:e,width:r,height:n})];B=e.depthTexture?this._fbo=new d({context:e,colorTextures:z,depthTexture:new g({context:e,width:r,height:n,pixelFormat:u.DEPTH_COMPONENT,pixelDatatype:m.UNSIGNED_SHORT})}):this._fbo=new d({context:e,colorTextures:z,depthRenderbuffer:new f({context:e,format:v.DEPTH_COMPONENT16})}),this._downSampleFBO1=new d({context:e,colorTextures:[new g({context:e,width:N,height:N})]}),this._downSampleFBO2=new d({context:e,colorTextures:[new g({context:e,width:N,height:N})]}),this._clearFBO1Command.framebuffer=this._downSampleFBO1,this._clearFBO2Command.framebuffer=this._downSampleFBO2,this._downSampleCommand.framebuffer=this._downSampleFBO1,this._brightPassCommand.framebuffer=this._downSampleFBO2,this._blurXCommand.framebuffer=this._downSampleFBO1,this._blurYCommand.framebuffer=this._downSampleFBO2;var k=_.fromCache({viewport:F}),U=_.fromCache();this._downSampleCommand.uniformMap.u_texture=function(){return B.getColorTexture(0)},this._downSampleCommand.renderState=k,this._brightPassCommand.uniformMap.u_texture=function(){return a._downSampleFBO1.getColorTexture(0)},this._brightPassCommand.renderState=k,this._blurXCommand.uniformMap.u_texture=function(){return a._downSampleFBO2.getColorTexture(0)},this._blurXCommand.uniformMap.u_step=function(){return a._blurStep},this._blurXCommand.renderState=k,this._blurYCommand.uniformMap.u_texture=function(){return a._downSampleFBO1.getColorTexture(0)},this._blurYCommand.uniformMap.u_step=function(){return a._blurStep},this._blurYCommand.renderState=k,this._blendCommand.uniformMap.u_texture0=function(){return B.getColorTexture(0)},this._blendCommand.uniformMap.u_texture1=function(){return a._downSampleFBO2.getColorTexture(0)},this._blendCommand.renderState=U,this._fullScreenCommand.uniformMap.u_texture=function(){return B.getColorTexture(0)},this._fullScreenCommand.renderState=U}var G=e.uniformState,W=G.sunPositionWC,H=G.view,q=G.viewProjection,j=G.projection,Y=l.computeViewportTransformation(L,0,1,I),X=l.multiplyByPoint(H,W,x),Z=c.pointToGLWindowCoordinates(q,Y,W,P);X.x+=s.SOLAR_RADIUS;var K=c.pointToGLWindowCoordinates(j,Y,X,X),J=30*t.magnitude(t.subtract(K,Z,K))*2,Q=A;Q.x=J,Q.y=J;var $=this._upSamplePassState.scissorTest.rectangle;return $.x=Math.max(Z.x-.5*Q.x,0),$.y=Math.max(Z.y-.5*Q.y,0),$.width=Math.min(Q.x,r),$.height=Math.min(Q.y,n),this._uCenter=t.clone(Z,this._uCenter),this._uRadius=.5*Math.max(Q.x,Q.y),Y=l.computeViewportTransformation(F,0,1,I),Z=c.pointToGLWindowCoordinates(q,Y,W,P),Q.x*=R/r,Q.y*=O/n,$=this._downSamplePassState.scissorTest.rectangle,$.x=Math.max(Z.x-.5*Q.x,0),$.y=Math.max(Z.y-.5*Q.y,0),$.width=Math.min(Q.x,r),$.height=Math.min(Q.y,n),this._downSamplePassState.context=e,this._upSamplePassState.context=e,this._fbo},w.prototype.isDestroyed=function(){return!1},w.prototype.destroy=function(){return this._fbo=this._fbo&&this._fbo.destroy(),this._downSampleFBO1=this._downSampleFBO1&&this._downSampleFBO1.destroy(),this._downSampleFBO2=this._downSampleFBO2&&this._downSampleFBO2.destroy(),this._downSampleCommand=this._downSampleCommand&&this._downSampleCommand.shaderProgram&&this._downSampleCommand.shaderProgram.destroy(),this._brightPassCommand=this._brightPassCommand&&this._brightPassCommand.shaderProgram&&this._brightPassCommand.shaderProgram.destroy(),this._blurXCommand=this._blurXCommand&&this._blurXCommand.shaderProgram&&this._blurXCommand.shaderProgram.destroy(),this._blurYCommand=this._blurYCommand&&this._blurYCommand.shaderProgram&&this._blurYCommand.shaderProgram.destroy(),this._blendCommand=this._blendCommand&&this._blendCommand.shaderProgram&&this._blendCommand.shaderProgram.destroy(),this._fullScreenCommand=this._fullScreenCommand&&this._fullScreenCommand.shaderProgram&&this._fullScreenCommand.shaderProgram.destroy(),a(this)},w}),r("Scene/Scene",["../Core/BoundingRectangle","../Core/BoundingSphere","../Core/BoxGeometry","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EllipsoidGeometry","../Core/Event","../Core/GeographicProjection","../Core/GeometryInstance","../Core/GeometryPipeline","../Core/getTimestamp","../Core/Intersect","../Core/Interval","../Core/JulianDate","../Core/Math","../Core/Matrix4","../Core/mergeSort","../Core/Occluder","../Core/ShowGeometryInstanceAttribute","../Renderer/ClearCommand","../Renderer/ComputeEngine","../Renderer/Context","../Renderer/ContextLimits","../Renderer/PassState","../Renderer/ShaderProgram","../Renderer/ShaderSource","./Camera","./CreditDisplay","./CullingVolume","./DepthPlane","./Fog","./FrameState","./FrustumCommands","./FXAA","./GlobeDepth","./OIT","./OrthographicFrustum","./Pass","./PerformanceDisplay","./PerInstanceColorAppearance","./PerspectiveFrustum","./PerspectiveOffCenterFrustum","./PickDepth","./Primitive","./PrimitiveCollection","./SceneMode","./SceneTransforms","./SceneTransitioner","./ScreenSpaceCameraController","./SunPostProcess","./TweenCollection"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe){"use strict";function ae(e,t){var r=Math.max(Math.abs(e.x),Math.abs(t.x)),i=Math.max(Math.abs(e.y),Math.abs(t.y)),n=Math.max(Math.abs(e.z),Math.abs(t.z));return Math.max(Math.max(r,i),n)}function se(e,t,r){var i=1/Math.max(1,ae(e.position,t.position));return n.multiplyByScalar(e.position,i,Le),n.multiplyByScalar(t.position,i,Fe),n.equalsEpsilon(Le,Fe,r)&&n.equalsEpsilon(e.direction,t.direction,r)&&n.equalsEpsilon(e.up,t.up,r)&&n.equalsEpsilon(e.right,t.right,r)&&T.equalsEpsilon(e.transform,t.transform,r)}function le(e){var t=e.globe;if(e._mode===ee.SCENE3D&&c(t)){var r=t.ellipsoid;return Be.radius=r.minimumRadius,Ne=x.fromBoundingSphere(Be,e._camera.positionWC,Ne)}return void 0}function ue(e){e.render=!1,e.pick=!1}function ce(e,t,r){var i=e._camera,n=e._frameState;n.commandList.length=0,n.mode=e._mode,n.morphTime=e.morphTime,n.mapProjection=e.mapProjection, +n.frameNumber=t,n.time=S.clone(r,n.time),n.camera=i,n.cullingVolume=i.frustum.computeCullingVolume(i.positionWC,i.directionWC,i.upWC),n.occluder=le(e),ue(n.passes)}function he(e,t,r,i,n){n.length=i;for(var o=0;i>o;++o){var a=Math.max(e,Math.pow(r,o)*e),s=Math.min(t,r*a),l=n[o];c(l)?(l.near=a,l.far=s):l=n[o]=new U(a,s)}}function de(e,t,r){e.debugShowFrustums&&(t.debugOverlappingFrustums=0);for(var i=e._frustumCommandsList,n=i.length,o=0;n>o;++o){var a=i[o],s=a.near,l=a.far;if(!(r.start>l)){if(r.stop<s)break;var u=t instanceof A?j.OPAQUE:t.pass,h=a.indices[u]++;if(a.commands[u][h]=t,e.debugShowFrustums&&(t.debugOverlappingFrustums|=1<<o),t.executeInClosestFrustum)break}}if(e.debugShowFrustums){var d=e._debugFrustumStatistics.commandsInFrustums;d[t.debugOverlappingFrustums]=c(d[t.debugOverlappingFrustums])?d[t.debugOverlappingFrustums]+1:1,++e._debugFrustumStatistics.totalCommands}}function pe(e){var t=e._computeCommandList,r=e._overlayCommandList,i=e._frameState.commandList,n=e._frameState.cullingVolume,o=e._camera,a=o.directionWC,s=o.positionWC;e.debugShowFrustums&&(e._debugFrustumStatistics={totalCommands:0,commandsInFrustums:{}});for(var l=e._frustumCommandsList,u=l.length,h=j.NUMBER_OF_PASSES,d=0;u>d;++d)for(var p=0;h>p;++p)l[d].indices[p]=0;t.length=0,r.length=0;var m,f=Number.MAX_VALUE,v=Number.MIN_VALUE,_=!1;e._frameState.mode===ee.SCENE3D&&(m=e._frameState.occluder);for(var g=Ve.planes,y=0;5>y;++y)g[y]=n.planes[y];n=Ve;for(var E=i.length,S=0;E>S;++S){var w=i[S],T=w.pass;if(T===j.COMPUTE)t.push(w);else if(T===j.OVERLAY)r.push(w);else{var b=w.boundingVolume;if(c(b)){if(w.cull&&(n.computeVisibility(b)===C.OUTSIDE||c(m)&&b.isOccluded(m)))continue;ze=b.computePlaneDistances(s,a,ze),f=Math.min(f,ze.start),v=Math.max(v,ze.stop)}else ze.start=o.frustum.near,ze.stop=o.frustum.far,_=!(w instanceof A);de(e,w,ze)}}_?(f=o.frustum.near,v=o.frustum.far):(f=Math.min(Math.max(f,o.frustum.near),o.frustum.far),v=Math.max(Math.min(v,o.frustum.far),f));var x=e.farToNearRatio,P=Math.ceil(Math.log(v/f)/Math.log(x));f!==Number.MAX_VALUE&&(P!==u||0!==l.length&&(f<l[0].near||v>l[u-1].far))&&(he(f,v,x,P,l),pe(e))}function me(e){var t={},r=e.vertexAttributes;for(var i in r)r.hasOwnProperty(i)&&(t[i]=r[i].index);return t}function fe(e,t,r){var i=t.context,n=u(r,e.shaderProgram),o=n.fragmentShaderSource.clone();o.sources=o.sources.map(function(e){return e=N.replaceMain(e,"czm_Debug_main")});var s="void main() \n{ \n czm_Debug_main(); \n";if(t.debugShowCommands){c(e._debugColor)||(e._debugColor=a.fromRandom());var l=e._debugColor;s+=" gl_FragColor.rgb *= vec3("+l.red+", "+l.green+", "+l.blue+"); \n"}if(t.debugShowFrustums){var h=1&e.debugOverlappingFrustums?"1.0":"0.0",d=2&e.debugOverlappingFrustums?"1.0":"0.0",p=4&e.debugOverlappingFrustums?"1.0":"0.0";s+=" gl_FragColor.rgb *= vec3("+h+", "+d+", "+p+"); \n"}s+="}",o.sources.push(s);var m=me(n);return O.fromCache({context:i,vertexShaderSource:n.vertexShaderSource,fragmentShaderSource:o,attributeLocations:m})}function ve(e,t,r,i,n){if(c(e.shaderProgram)||c(n)){var o=fe(e,t,n);e.execute(t.context,r,i,o),o.destroy()}}function _e(e,t,i,o,a,l,u){if((!c(t.debugCommandFilter)||t.debugCommandFilter(e))&&(t.debugShowCommands||t.debugShowFrustums?ve(e,t,o,a,l):e.execute(i,o,a,l),e.debugShowBoundingVolume&&c(e.boundingVolume))){var h=t._frameState,d=e.boundingVolume;c(t._debugVolume)&&t._debugVolume.destroy();var p,f=n.clone(d.center);if(h.mode!==ee.SCENE3D){f=T.multiplyByPoint(ke,f,f);var v=h.mapProjection,y=v.unproject(f);f=v.ellipsoid.cartographicToCartesian(y)}if(c(d.radius)){var C=d.radius;p=g.toWireframe(m.createGeometry(new m({radii:new n(C,C,C),vertexFormat:X.FLAT_VERTEX_FORMAT}))),t._debugVolume=new Q({geometryInstances:new _({geometry:p,modelMatrix:T.multiplyByTranslation(T.IDENTITY,f,new T),attributes:{color:new s(1,0,0,1)}}),appearance:new X({flat:!0,translucent:!1}),asynchronous:!1})}else{var E=d.halfAxes;p=g.toWireframe(r.createGeometry(r.fromDimensions({dimensions:new n(2,2,2),vertexFormat:X.FLAT_VERTEX_FORMAT}))),t._debugVolume=new Q({geometryInstances:new _({geometry:p,modelMatrix:T.fromRotationTranslation(E,f,new T),attributes:{color:new s(1,0,0,1)}}),appearance:new X({flat:!0,translucent:!1}),asynchronous:!1})}var S=h.commandList,w=h.commandList=[];t._debugVolume.update(h);var b;c(u)&&(b=o.framebuffer,o.framebuffer=u),w[0].execute(i,o),c(b)&&(o.framebuffer=b),h.commandList=S}}function ge(e,t){if(c(e)){for(var r=t.mode===ee.SCENE3D?t.occluder:void 0,i=t.cullingVolume,n=Ve.planes,o=0;5>o;++o)n[o]=i.planes[o];i=Ve;var a=e.boundingVolume;return!(!c(e)||c(e.boundingVolume)&&e.cull&&(i.computeVisibility(a)===C.OUTSIDE||c(r)&&a.isOccluded(r)))}}function ye(e,t,r){return t.boundingVolume.distanceSquaredTo(r)-e.boundingVolume.distanceSquaredTo(r)}function Ce(e,t,r,i){var n=e.context;b(i,ye,e._camera.positionWC);for(var o=i.length,a=0;o>a;++a)t(i[a],e,n,r)}function Ee(e,t){var r=e._debugGlobeDepths[t];return!c(r)&&e.context.depthTexture&&(r=new W,e._debugGlobeDepths[t]=r),r}function Se(e,t){var r=e._pickDepths[t];return c(r)||(r=new J,e._pickDepths[t]=r),r}function we(e,t,r,i){var n,o,s=e._frameState,l=e._camera,u=e.context,h=u.uniformState;c(e.sun)&&e.sunBloom!==e._sunBloom?(e.sunBloom?e._sunPostProcess=new ne:c(e._sunPostProcess)&&(e._sunPostProcess=e._sunPostProcess.destroy()),e._sunBloom=e.sunBloom):!c(e.sun)&&c(e._sunPostProcess)&&(e._sunPostProcess=e._sunPostProcess.destroy(),e._sunBloom=!1);var d,p=s.passes.render,m=p&&c(e.skyBox)?e.skyBox.update(s):void 0,f=c(e.globe)&&e.globe._surface._tilesToRender.length>0,v=p&&c(e.skyAtmosphere)?e.skyAtmosphere.update(s):void 0,_=p&&c(e.sun)?e.sun.update(e):void 0,g=c(_)?_.drawCommand:void 0,y=c(_)?_.computeCommand:void 0,C=ge(g,s),E=p&&c(e.moon)?e.moon.update(s):void 0,S=ge(E,s),w=t.framebuffer;d=c(l.frustum.fov)?l.frustum.clone(Ue):c(l.frustum.infiniteProjectionMatrix)?l.frustum.clone(Ge):l.frustum.clone(We);var T=e._clearColorCommand;a.clone(r,T.color),T.execute(u,t);var b=!i&&c(e._globeDepth);b&&(e._globeDepth.update(u),e._globeDepth.clear(u,t,r));var x=!1,P=e._frustumCommandsList,A=P.length;for(n=0;A>n;++n)if(P[n].indices[j.TRANSLUCENT]>0){x=!0;break}var I=c(e.globe)&&(!e.globe.depthTestAgainstTerrain||e.mode===ee.SCENE2D),M=I&&e.mode===ee.SCENE3D;M&&e._depthPlane.update(s);var D=!i&&x&&c(e._oit)&&e._oit.isSupported();D&&(e._oit.update(u,e._globeDepth.framebuffer),e._oit.clear(u,t,r),D=D&&e._oit.isSupported());var R=!i&&e.fxaa;if(R&&(e._fxaa.update(u),e._fxaa.clear(u,t,r)),C&&e.sunBloom?t.framebuffer=e._sunPostProcess.update(u):b?t.framebuffer=e._globeDepth.framebuffer:R&&(t.framebuffer=e._fxaa.getColorFramebuffer()),c(t.framebuffer)&&T.execute(u,t),d.near=l.frustum.near,d.far=l.frustum.far,h.updateFrustum(d),c(m)&&_e(m,e,u,t),c(v)&&f&&_e(v,e,u,t),C&&(c(y)&&y.execute(e._computeEngine),g.execute(u,t),e.sunBloom)){var O;O=b?e._globeDepth.framebuffer:R?e._fxaa.getColorFramebuffer():w,e._sunPostProcess.execute(u,O),t.framebuffer=O}S&&E.execute(u,t);var N;D?(c(e._executeOITFunction)||(e._executeOITFunction=function(e,t,r,i){e._oit.executeCommands(e,t,r,i)}),N=e._executeOITFunction):N=Ce;var L=e._depthClearCommand;for(n=0;A>n;++n){var F=A-n-1,B=P[F];d.near=0!==F?B.near*Oe:B.near,d.far=B.far;var V,z=e.debugShowGlobeDepth?Ee(e,F):e._globeDepth;e.debugShowGlobeDepth&&c(z)&&b&&(V=t.framebuffer,t.framebuffer=z.framebuffer),h.updateFrustum(d),L.execute(u,t);var k=B.commands[j.GLOBE],U=B.indices[j.GLOBE];for(o=0;U>o;++o)_e(k[o],e,u,t);for(c(z)&&b&&(e.copyGlobeDepth||e.debugShowGlobeDepth)&&(z.update(u),z.executeCopyDepth(u,t)),e.debugShowGlobeDepth&&c(z)&&b&&(t.framebuffer=V),k=B.commands[j.GROUND],U=B.indices[j.GROUND],o=0;U>o;++o)_e(k[o],e,u,t);I&&(L.execute(u,t),M&&e._depthPlane.execute(u,t));for(var G=j.GROUND+1,W=j.TRANSLUCENT,H=G;W>H;++H)for(k=B.commands[H],U=B.indices[H],o=0;U>o;++o)_e(k[o],e,u,t);if(0!==F&&(d.near=B.near,h.updateFrustum(d)),k=B.commands[j.TRANSLUCENT],k.length=B.indices[j.TRANSLUCENT],N(e,_e,t,k),c(z)&&b){var q=Se(e,F);q.update(u,z.framebuffer.depthStencilTexture),q.executeCopyDepth(u,t)}}if(e.debugShowGlobeDepth&&b){var Y=Ee(e,e.debugShowDepthFrustum-1);Y.executeDebugGlobeDepth(u,t)}if(e.debugShowPickDepth&&b){var X=Se(e,e.debugShowDepthFrustum-1);X.executeDebugPickDepth(u,t)}D&&(t.framebuffer=R?e._fxaa.getColorFramebuffer():void 0,e._oit.execute(u,t)),R&&(!D&&b&&(t.framebuffer=e._fxaa.getColorFramebuffer(),e._globeDepth.executeCopyColor(u,t)),t.framebuffer=w,e._fxaa.execute(u,t)),D||R||!b||(t.framebuffer=w,e._globeDepth.executeCopyColor(u,t))}function Te(e){for(var t=e._computeCommandList,r=t.length,i=0;r>i;++i)t[i].execute(e._computeEngine)}function be(e,t){for(var r=e.context,i=e._overlayCommandList,n=i.length,o=0;n>o;++o)i[o].execute(r,t)}function xe(e){var t=e._frameState;e._globe&&e._globe.update(t),e._groundPrimitives.update(t),e._primitives.update(t)}function Pe(e){for(var t=e.afterRender,r=0,i=t.length;i>r;++r)t[r]();t.length=0}function Ae(e,t){c(t)||(t=S.now());var r=e._camera;se(r,e._cameraClone,w.EPSILON6)?e._cameraStartFired&&y()-e._cameraMovedTime>e.cameraEventWaitTime&&(r.moveEnd.raiseEvent(),e._cameraStartFired=!1):(e._cameraStartFired||(r.moveStart.raiseEvent(),e._cameraStartFired=!0),e._cameraMovedTime=y(),L.clone(r,e._cameraClone)),e._preRender.raiseEvent(e,t);var i=e.context,n=i.uniformState,o=e._frameState,s=w.incrementWrap(o.frameNumber,15e6,1);ce(e,s,t),o.passes.render=!0,o.creditDisplay.beginFrame(),e.fog.update(o),n.update(o),e._computeCommandList.length=0,e._overlayCommandList.length=0,xe(e),pe(e);var l=e._passState;if(l.framebuffer=void 0,l.blendingEnabled=void 0,l.scissorTest=void 0,Te(e),we(e,l,u(e.backgroundColor,a.BLACK)),be(e,l),o.creditDisplay.endFrame(),e.debugShowFramesPerSecond){if(!c(e._performanceDisplay)){var h=document.createElement("div");h.className="cesium-performanceDisplay-defaultContainer";var d=e._canvas.parentNode;d.appendChild(h);var p=new Y({container:h});e._performanceDisplay=p,e._performanceContainer=h}e._performanceDisplay.update()}else c(e._performanceDisplay)&&(e._performanceDisplay=e._performanceDisplay&&e._performanceDisplay.destroy(),e._performanceContainer.parentNode.removeChild(e._performanceContainer));i.endFrame(),Pe(o),e._postRender.raiseEvent(e,t)}function Ie(e,t,r,i){var o=e._camera,a=o.frustum,s=e.drawingBufferWidth,l=e.drawingBufferHeight,u=2/s*t.x-1;u*=.5*(a.right-a.left);var c=2/l*(l-t.y)-1;c*=.5*(a.top-a.bottom);var h=T.clone(o.transform,Xe);o._setTransform(T.IDENTITY);var d=n.clone(o.position,qe);n.multiplyByScalar(o.right,u,je),n.add(je,d,d),n.multiplyByScalar(o.up,c,je),n.add(je,d,d),o._setTransform(h),n.fromElements(d.z,d.x,d.y,d);var p=a.getPixelDimensions(s,l,1,Ye),m=He;return m.right=.5*p.x,m.left=-m.right,m.top=.5*p.y,m.bottom=-m.top,m.near=a.near,m.far=a.far,m.computeCullingVolume(d,o.directionWC,o.upWC)}function Me(e,t,r,i){var n=e._camera,o=n.frustum,a=o.near,s=e.drawingBufferWidth,l=e.drawingBufferHeight,u=Math.tan(.5*o.fovy),c=o.aspectRatio*u,h=2/s*t.x-1,d=2/l*(l-t.y)-1,p=h*a*c,m=d*a*u,f=o.getPixelDimensions(s,l,1,Ye),v=f.x*r*.5,_=f.y*i*.5,g=Ze;return g.top=m+_,g.bottom=m-_,g.right=p+v,g.left=p-v,g.near=a,g.far=o.far,g.computeCullingVolume(n.positionWC,n.directionWC,n.upWC)}function De(e,t,r,i){return e._mode===ee.SCENE2D?Ie(e,t,r,i):Me(e,t,r,i)}var Re=function(e){e=u(e,u.EMPTY_OBJECT);var t=e.canvas,r=e.contextOptions,i=e.creditContainer,n=new M(t,r);c(i)||(i=document.createElement("div"),i.style.position="absolute",i.style.bottom="0",i.style["text-shadow"]="0px 0px 2px #000000",i.style.color="#ffffff",i.style["font-size"]="10px",i.style["padding-right"]="5px",t.parentNode.appendChild(i)),this._id=l(),this._frameState=new k(n,new F(i)),this._frameState.scene3DOnly=u(e.scene3DOnly,!1),this._passState=new R(n),this._canvas=t,this._context=n,this._computeEngine=new I(n),this._globe=void 0,this._primitives=new $,this._groundPrimitives=new $,this._tweens=new oe,this._shaderFrameCount=0,this._sunPostProcess=void 0,this._computeCommandList=[],this._frustumCommandsList=[],this._overlayCommandList=[],this._pickFramebuffer=void 0,this._useOIT=u(e.orderIndependentTranslucency,!0),this._executeOITFunction=void 0;var o;n.depthTexture&&(o=new W);var s;this._useOIT&&c(o)&&(s=new H(n)),this._globeDepth=o,this._depthPlane=new V,this._oit=s,this._fxaa=new G,this._clearColorCommand=new A({color:new a,stencil:0,owner:this}),this._depthClearCommand=new A({depth:1,owner:this}),this._pickDepths=[],this._debugGlobeDepths=[],this._transitioner=new re(this),this._renderError=new f,this._preRender=new f,this._postRender=new f,this._cameraStartFired=!1,this._cameraMovedTime=void 0,this.rethrowRenderErrors=!1,this.completeMorphOnUserInput=!0,this.morphStart=new f,this.morphComplete=new f,this.skyBox=void 0,this.skyAtmosphere=void 0,this.sun=void 0,this.sunBloom=!0,this._sunBloom=void 0,this.moon=void 0,this.backgroundColor=a.clone(a.BLACK),this._mode=ee.SCENE3D,this._mapProjection=c(e.mapProjection)?e.mapProjection:new v,this._transitioner=new re(this,this._mapProjection.ellipsoid),this.morphTime=1,this.farToNearRatio=1e3,this.debugCommandFilter=void 0,this.debugShowCommands=!1,this.debugShowFrustums=!1,this._debugFrustumStatistics=void 0,this.debugShowFramesPerSecond=!1,this.debugShowGlobeDepth=!1,this.debugShowDepthFrustum=1,this.fxaa=!0,this.cameraEventWaitTime=500,this.copyGlobeDepth=!1,this.fog=new z,this._performanceDisplay=void 0,this._debugVolume=void 0;var h=new L(this);this._camera=h,this._cameraClone=L.clone(h),this._screenSpaceCameraController=new ie(this);var d=h.frustum.near,p=h.frustum.far,m=Math.ceil(Math.log(p/d)/Math.log(this.farToNearRatio));he(d,p,this.farToNearRatio,m,this._frustumCommandsList),ce(this,0,S.now()),this.initializeFrame()},Oe=.99;h(Re.prototype,{canvas:{get:function(){return this._canvas}},drawingBufferHeight:{get:function(){return this._context.drawingBufferHeight}},drawingBufferWidth:{get:function(){return this._context.drawingBufferWidth}},maximumAliasedLineWidth:{get:function(){return D.maximumAliasedLineWidth}},maximumCubeMapSize:{get:function(){return D.maximumCubeMapSize}},pickPositionSupported:{get:function(){return this._context.depthTexture}},globe:{get:function(){return this._globe},set:function(e){this._globe=this._globe&&this._globe.destroy(),this._globe=e}},primitives:{get:function(){return this._primitives}},groundPrimitives:{get:function(){return this._groundPrimitives}},camera:{get:function(){return this._camera}},screenSpaceCameraController:{get:function(){return this._screenSpaceCameraController}},mapProjection:{get:function(){return this._mapProjection}},frameState:{get:function(){return this._frameState}},tweens:{get:function(){return this._tweens}},imageryLayers:{get:function(){return this.globe.imageryLayers}},terrainProvider:{get:function(){return this.globe.terrainProvider},set:function(e){this.globe.terrainProvider=e}},renderError:{get:function(){return this._renderError}},preRender:{get:function(){return this._preRender}},postRender:{get:function(){return this._postRender}},context:{get:function(){return this._context}},debugFrustumStatistics:{get:function(){return this._debugFrustumStatistics}},scene3DOnly:{get:function(){return this._frameState.scene3DOnly}},orderIndependentTranslucency:{get:function(){return c(this._oit)}},id:{get:function(){return this._id}},mode:{get:function(){return this._mode},set:function(e){e===ee.SCENE2D?this.morphTo2D(0):e===ee.SCENE3D?this.morphTo3D(0):e===ee.COLUMBUS_VIEW&&this.morphToColumbusView(0),this._mode=e}},numberOfFrustums:{get:function(){return this._frustumCommandsList.length}}});var Ne,Le=new n,Fe=new n,Be=new t,Ve=new B,ze=new E,ke=new T(0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1);ke=T.inverseTransformation(ke,ke);var Ue=new Z,Ge=new K,We=new q;Re.prototype.initializeFrame=function(){120===this._shaderFrameCount++&&(this._shaderFrameCount=0,this._context.shaderCache.destroyReleasedShaderPrograms()),this._tweens.update(),this._camera.update(this._mode),this._screenSpaceCameraController.update()},Re.prototype.render=function(e){try{Ae(this,e)}catch(t){if(this._renderError.raiseEvent(this,t),this.rethrowRenderErrors)throw t}},Re.prototype.clampLineWidth=function(e){this._context;return Math.max(D.minimumAliasedLineWidth,Math.min(e,D.maximumAliasedLineWidth))};var He=new q,qe=new n,je=new n,Ye=(new i,new i),Xe=new T,Ze=new K,Ke=3,Je=3,Qe=new e(0,0,Ke,Je),$e=new a(0,0,0,0),et=new i;Re.prototype.pick=function(e){var t=this._context,r=t.uniformState,i=this._frameState,n=te.transformWindowToDrawingBuffer(this,e,et);c(this._pickFramebuffer)||(this._pickFramebuffer=t.createPickFramebuffer()),ce(this,i.frameNumber,i.time),i.cullingVolume=De(this,n,Ke,Je),i.passes.pick=!0,r.update(i),xe(this),pe(this),Qe.x=n.x-.5*(Ke-1),Qe.y=this.drawingBufferHeight-n.y-.5*(Je-1),we(this,this._pickFramebuffer.begin(Qe),$e,!0);var o=this._pickFramebuffer.end(Qe);return t.endFrame(),Pe(i),o};var tt=(new n,new n,new o),rt=new o(1,1/255,1/65025,1/160581375);return Re.prototype.pickPosition=function(e,t){var r=this._context,i=r.uniformState,n=te.transformWindowToDrawingBuffer(this,e,et);n.y=this.drawingBufferHeight-n.y;var a,s=this._camera;c(s.frustum.fov)?a=s.frustum.clone(Ue):c(s.frustum.infiniteProjectionMatrix)&&(a=s.frustum.clone(Ge));for(var l=this.numberOfFrustums,u=0;l>u;++u){var h=Se(this,u),d=r.readPixels({x:n.x,y:n.y,width:1,height:1,framebuffer:h.framebuffer}),p=o.unpack(d,0,tt);o.divideByScalar(p,255,p);var m=o.dot(p,rt);if(m>0&&1>m){var f=this._frustumCommandsList[u];return a.near=f.near*(0!==u?Oe:1),a.far=f.far,i.updateFrustum(a),te.drawingBufferToWgs84Coordinates(this,n,m,t)}}return void 0},Re.prototype.drillPick=function(e,t){var r,i,n=[],o=[],a=[];c(t)||(t=Number.MAX_VALUE);for(var s=this.pick(e);c(s)&&c(s.primitive)&&(n.push(s),!(0>=--t));){var l=s.primitive,u=!1;"function"==typeof l.getGeometryInstanceAttributes&&c(s.id)&&(i=l.getGeometryInstanceAttributes(s.id),c(i)&&c(i.show)&&(u=!0,i.show=P.toValue(!1,i.show),a.push(i))),u||(l.show=!1,o.push(l)),s=this.pick(e)}for(r=0;r<o.length;++r)o[r].show=!0;for(r=0;r<a.length;++r)i=a[r],i.show=P.toValue(!0,i.show);return n},Re.prototype.completeMorph=function(){this._transitioner.completeMorph()},Re.prototype.morphTo2D=function(e){var t,r=this.globe;t=c(r)?r.ellipsoid:this.mapProjection.ellipsoid,e=u(e,2),this._transitioner.morphTo2D(e,t)},Re.prototype.morphToColumbusView=function(e){var t,r=this.globe;t=c(r)?r.ellipsoid:this.mapProjection.ellipsoid,e=u(e,2),this._transitioner.morphToColumbusView(e,t)},Re.prototype.morphTo3D=function(e){var t,r=this.globe;t=c(r)?r.ellipsoid:this.mapProjection.ellipsoid,e=u(e,2),this._transitioner.morphTo3D(e,t)},Re.prototype.isDestroyed=function(){return!1},Re.prototype.destroy=function(){return this._tweens.removeAll(),this._computeEngine=this._computeEngine&&this._computeEngine.destroy(),this._screenSpaceCameraController=this._screenSpaceCameraController&&this._screenSpaceCameraController.destroy(),this._pickFramebuffer=this._pickFramebuffer&&this._pickFramebuffer.destroy(),this._primitives=this._primitives&&this._primitives.destroy(),this._groundPrimitives=this._groundPrimitives&&this._groundPrimitives.destroy(),this._globe=this._globe&&this._globe.destroy(),this.skyBox=this.skyBox&&this.skyBox.destroy(),this.skyAtmosphere=this.skyAtmosphere&&this.skyAtmosphere.destroy(),this._debugSphere=this._debugSphere&&this._debugSphere.destroy(),this.sun=this.sun&&this.sun.destroy(),this._sunPostProcess=this._sunPostProcess&&this._sunPostProcess.destroy(),this._depthPlane=this._depthPlane&&this._depthPlane.destroy(),this._transitioner.destroy(),c(this._globeDepth)&&this._globeDepth.destroy(),c(this._oit)&&this._oit.destroy(),this._fxaa.destroy(),this._context=this._context&&this._context.destroy(),this._frameState.creditDisplay.destroy(),c(this._performanceDisplay)&&(this._performanceDisplay=this._performanceDisplay&&this._performanceDisplay.destroy(),this._performanceContainer.parentNode.removeChild(this._performanceContainer)),d(this)},Re}),r("Scene/SingleTileImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicTilingScheme","../Core/loadImage","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../ThirdParty/when"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";var d=function(i){function n(e){E._image=e,E._tileWidth=e.width,E._tileHeight=e.height,E._ready=!0,E._readyPromise.resolve(!0),c.handleSuccess(E._errorEvent)}function d(e){var t="Failed to load image "+g+".";C=c.handleError(C,E,E._errorEvent,t,0,0,0,p,e),E._readyPromise.reject(new u(t))}function p(){h(s(g),n,d)}i=t(i,{});var m=i.url;this._url=m;var f=i.proxy;this._proxy=f;var v=t(i.rectangle,l.MAX_VALUE),_=new a({rectangle:v,numberOfLevelZeroTilesX:1,numberOfLevelZeroTilesY:1,ellipsoid:i.ellipsoid});this._tilingScheme=_,this._image=void 0,this._texture=void 0,this._tileWidth=0,this._tileHeight=0,this._errorEvent=new o,this._ready=!1,this._readyPromise=h.defer();var g=m;r(f)&&(g=f.getURL(g));var y=i.credit;"string"==typeof y&&(y=new e(y)),this._credit=y;var C,E=this;p()};return i(d.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return 0}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return void 0}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),d.prototype.getTileCredits=function(e,t,r){return void 0},d.prototype.requestImage=function(e,t,r){return this._image},d.prototype.pickFeatures=function(){return void 0},d}),r("Shaders/SkyAtmosphereFS",[],function(){"use strict";return"const float g = -0.95;\nconst float g2 = g * g;\nvarying vec3 v_rayleighColor;\nvarying vec3 v_mieColor;\nvarying vec3 v_toCamera;\nvarying vec3 v_positionEC;\nvoid main (void)\n{\nfloat fCos = dot(czm_sunDirectionWC, normalize(v_toCamera)) / length(v_toCamera);\nfloat fRayleighPhase = 0.75 * (1.0 + fCos * fCos);\nfloat fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos * fCos) / pow(1.0 + g2 - 2.0 * g * fCos, 1.5);\nconst float fExposure = 2.0;\nvec3 rgb = fRayleighPhase * v_rayleighColor + fMiePhase * v_mieColor;\nrgb = vec3(1.0) - exp(-fExposure * rgb);\nfloat l = czm_luminance(rgb);\ngl_FragColor = vec4(rgb, min(smoothstep(0.0, 0.1, l), 1.0) * smoothstep(0.0, 1.0, czm_morphTime));\n}\n"}),r("Shaders/SkyAtmosphereVS",[],function(){"use strict";return"attribute vec4 position;\nuniform float fCameraHeight;\nuniform float fCameraHeight2;\nuniform float fOuterRadius;\nuniform float fOuterRadius2;\nuniform float fInnerRadius;\nuniform float fScale;\nuniform float fScaleDepth;\nuniform float fScaleOverScaleDepth;\nconst float Kr = 0.0025;\nconst float fKr4PI = Kr * 4.0 * czm_pi;\nconst float Km = 0.0015;\nconst float fKm4PI = Km * 4.0 * czm_pi;\nconst float ESun = 15.0;\nconst float fKmESun = Km * ESun;\nconst float fKrESun = Kr * ESun;\nconst vec3 v3InvWavelength = vec3(\n5.60204474633241,\n9.473284437923038,\n19.643802610477206);\nconst float rayleighScaleDepth = 0.25;\nconst int nSamples = 2;\nconst float fSamples = 2.0;\nvarying vec3 v_rayleighColor;\nvarying vec3 v_mieColor;\nvarying vec3 v_toCamera;\nfloat scale(float fCos)\n{\nfloat x = 1.0 - fCos;\nreturn fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n}\nvoid main(void)\n{\nvec3 v3Pos = position.xyz;\nvec3 v3Ray = v3Pos - czm_viewerPositionWC;\nfloat fFar = length(v3Ray);\nv3Ray /= fFar;\n#ifdef SKY_FROM_SPACE\nfloat B = 2.0 * dot(czm_viewerPositionWC, v3Ray);\nfloat C = fCameraHeight2 - fOuterRadius2;\nfloat fDet = max(0.0, B*B - 4.0 * C);\nfloat fNear = 0.5 * (-B - sqrt(fDet));\nvec3 v3Start = czm_viewerPositionWC + v3Ray * fNear;\nfFar -= fNear;\nfloat fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;\nfloat fStartDepth = exp(-1.0 / fScaleDepth);\nfloat fStartOffset = fStartDepth*scale(fStartAngle);\n#else\nvec3 v3Start = czm_viewerPositionWC;\nfloat fHeight = length(v3Start);\nfloat fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fCameraHeight));\nfloat fStartAngle = dot(v3Ray, v3Start) / fHeight;\nfloat fStartOffset = fDepth*scale(fStartAngle);\n#endif\nfloat fSampleLength = fFar / fSamples;\nfloat fScaledLength = fSampleLength * fScale;\nvec3 v3SampleRay = v3Ray * fSampleLength;\nvec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\nvec3 v3FrontColor = vec3(0.0, 0.0, 0.0);\nfor(int i=0; i<nSamples; i++)\n{\nfloat fHeight = length(v3SamplePoint);\nfloat fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\nvec3 lightPosition = normalize(czm_viewerPositionWC);\nfloat fLightAngle = dot(lightPosition, v3SamplePoint) / fHeight;\nfloat fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;\nfloat fScatter = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle)));\nvec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\nv3FrontColor += v3Attenuate * (fDepth * fScaledLength);\nv3SamplePoint += v3SampleRay;\n}\nv_mieColor = v3FrontColor * fKmESun;\nv_rayleighColor = v3FrontColor * (v3InvWavelength * fKrESun);\nv_toCamera = czm_viewerPositionWC - v3Pos;\ngl_Position = czm_modelViewProjection * position;\n}\n"}),r("Scene/SkyAtmosphere",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/Ellipsoid","../Core/EllipsoidGeometry","../Core/GeometryPipeline","../Core/VertexFormat","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../Shaders/SkyAtmosphereFS","../Shaders/SkyAtmosphereVS","./BlendingState","./CullFace","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y){"use strict";var C=function(r){r=t(r,o.WGS84),this.show=!0,this._ellipsoid=r,this._command=new c({owner:this}),this._spSkyFromSpace=void 0,this._spSkyFromAtmosphere=void 0,this._fCameraHeight=void 0,this._fCameraHeight2=void 0,this._outerRadius=e.maximumComponent(e.multiplyByScalar(r.radii,1.025,new e));var i=r.maximumRadius,n=.25,a=this;this._command.uniformMap={fCameraHeight:function(){return a._fCameraHeight},fCameraHeight2:function(){return a._fCameraHeight2},fOuterRadius:function(){return a._outerRadius},fOuterRadius2:function(){return a._outerRadius*a._outerRadius},fInnerRadius:function(){return i},fScale:function(){return 1/(a._outerRadius-i)},fScaleDepth:function(){return n},fScaleOverScaleDepth:function(){return 1/(a._outerRadius-i)/n}}};return i(C.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),C.prototype.update=function(t){if(!this.show)return void 0;if(t.mode!==y.SCENE3D&&t.mode!==y.MORPHING)return void 0;if(!t.passes.render)return void 0;var i=this._command;if(!r(i.vertexArray)){var n=t.context,o=a.createGeometry(new a({radii:e.multiplyByScalar(this._ellipsoid.radii,1.025,new e),slicePartitions:256,stackPartitions:256,vertexFormat:l.POSITION_ONLY}));i.vertexArray=m.fromGeometry({context:n,geometry:o,attributeLocations:s.createAttributeLocations(o),bufferUsage:u.STATIC_DRAW}),i.renderState=h.fromCache({cull:{enabled:!0,face:g.FRONT},blending:_.ALPHA_BLEND});var c=new p({defines:["SKY_FROM_SPACE"],sources:[v]});this._spSkyFromSpace=d.fromCache({context:n,vertexShaderSource:c,fragmentShaderSource:f}),c=new p({defines:["SKY_FROM_ATMOSPHERE"],sources:[v]}),this._spSkyFromAtmosphere=d.fromCache({context:n,vertexShaderSource:c,fragmentShaderSource:f})}var C=t.camera.positionWC;return this._fCameraHeight2=e.magnitudeSquared(C),this._fCameraHeight=Math.sqrt(this._fCameraHeight2),this._fCameraHeight>this._outerRadius?i.shaderProgram=this._spSkyFromSpace:i.shaderProgram=this._spSkyFromAtmosphere,i},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){var e=this._command;return e.vertexArray=e.vertexArray&&e.vertexArray.destroy(),this._spSkyFromSpace=this._spSkyFromSpace&&this._spSkyFromSpace.destroy(),this._spSkyFromAtmosphere=this._spSkyFromAtmosphere&&this._spSkyFromAtmosphere.destroy(),n(this)},C}),r("Shaders/SkyBoxFS",[],function(){"use strict";return"uniform samplerCube u_cubeMap;\nvarying vec3 v_texCoord;\nvoid main()\n{\nvec3 rgb = textureCube(u_cubeMap, normalize(v_texCoord)).rgb;\ngl_FragColor = vec4(rgb, czm_morphTime);\n}\n"}),r("Shaders/SkyBoxVS",[],function(){"use strict";return"attribute vec3 position;\nvarying vec3 v_texCoord;\nvoid main()\n{\nvec3 p = czm_viewRotation * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position));\ngl_Position = czm_projection * vec4(p, 1.0);\nv_texCoord = position.xyz;\n}\n"}),r("Scene/SkyBox",["../Core/BoxGeometry","../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/GeometryPipeline","../Core/Matrix4","../Core/VertexFormat","../Renderer/BufferUsage","../Renderer/CubeMap","../Renderer/DrawCommand","../Renderer/loadCubeMap","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/VertexArray","../Shaders/SkyBoxFS","../Shaders/SkyBoxVS","./BlendingState","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y){"use strict";var C=function(e){this.sources=e.sources,this._sources=void 0,this.show=r(e.show,!0),this._command=new h({modelMatrix:s.clone(s.IDENTITY),owner:this}),this._cubeMap=void 0};return C.prototype.update=function(r){if(!this.show)return void 0;if(r.mode!==y.SCENE3D&&r.mode!==y.MORPHING)return void 0;if(!r.passes.render)return void 0;var n=r.context;if(this._sources!==this.sources){this._sources=this.sources;var o=this.sources;"string"==typeof o.positiveX?d(n,this._sources).then(function(e){h._cubeMap=h._cubeMap&&h._cubeMap.destroy(),h._cubeMap=e}):(this._cubeMap=this._cubeMap&&this._cubeMap.destroy(),this._cubeMap=new c({context:n,source:o}))}var s=this._command;if(!i(s.vertexArray)){var h=this;s.uniformMap={u_cubeMap:function(){return h._cubeMap}};var C=e.createGeometry(e.fromDimensions({dimensions:new t(2,2,2),vertexFormat:l.POSITION_ONLY})),E=a.createAttributeLocations(C);s.vertexArray=f.fromGeometry({context:n,geometry:C,attributeLocations:E,bufferUsage:u.STATIC_DRAW}),s.shaderProgram=m.fromCache({context:n,vertexShaderSource:_,fragmentShaderSource:v,attributeLocations:E}),s.renderState=p.fromCache({blending:g.ALPHA_BLEND})}return i(this._cubeMap)?s:void 0},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){var e=this._command;return e.vertexArray=e.vertexArray&&e.vertexArray.destroy(),e.shaderProgram=e.shaderProgram&&e.shaderProgram.destroy(),this._cubeMap=this._cubeMap&&this._cubeMap.destroy(),n(this)},C}),r("Shaders/SunFS",[],function(){"use strict";return"uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n"}),r("Shaders/SunTextureFS",[],function(){"use strict";return"uniform float u_glowLengthTS;\nuniform float u_radiusTS;\nvarying vec2 v_textureCoordinates;\nvec2 rotate(vec2 p, vec2 direction)\n{\nreturn vec2(p.x * direction.x - p.y * direction.y, p.x * direction.y + p.y * direction.x);\n}\nvec4 addBurst(vec2 position, vec2 direction)\n{\nvec2 rotatedPosition = rotate(position, direction) * vec2(25.0, 0.75);\nfloat radius = length(rotatedPosition);\nfloat burst = 1.0 - smoothstep(0.0, 0.55, radius);\nreturn vec4(burst);\n}\nvoid main()\n{\nvec2 position = v_textureCoordinates - vec2(0.5);\nfloat radius = length(position);\nfloat surface = step(radius, u_radiusTS);\nvec4 color = vec4(1.0, 1.0, surface + 0.2, surface);\nfloat glow = 1.0 - smoothstep(0.0, 0.55, radius);\ncolor.ba += mix(vec2(0.0), vec2(1.0), glow) * 0.75;\nvec4 burst = vec4(0.0);\nburst += 0.4 * addBurst(position, vec2(0.38942, 0.92106));\nburst += 0.4 * addBurst(position, vec2(0.99235, 0.12348));\nburst += 0.4 * addBurst(position, vec2(0.60327, -0.79754));\nburst += 0.3 * addBurst(position, vec2(0.31457, 0.94924));\nburst += 0.3 * addBurst(position, vec2(0.97931, 0.20239));\nburst += 0.3 * addBurst(position, vec2(0.66507, -0.74678));\ncolor += clamp(burst, vec4(0.0), vec4(1.0)) * 0.15;\ngl_FragColor = clamp(color, vec4(0.0), vec4(1.0));\n}\n"; +}),r("Shaders/SunVS",[],function(){"use strict";return"attribute vec2 direction;\nuniform float u_size;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec4 position;\nif (czm_morphTime == 1.0)\n{\nposition = vec4(czm_sunPositionWC, 1.0);\n}\nelse\n{\nposition = vec4(czm_sunPositionColumbusView.zxy, 1.0);\n}\nvec4 positionEC = czm_view * position;\nvec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\nvec2 halfSize = vec2(u_size * 0.5);\nhalfSize *= ((direction * 2.0) - 1.0);\ngl_Position = czm_viewportOrthographic * vec4(positionWC.xy + halfSize, -positionWC.z, 1.0);\nv_textureCoordinates = direction;\n}\n"}),r("Scene/Sun",["../Core/BoundingRectangle","../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/ComponentDatatype","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/IndexDatatype","../Core/Math","../Core/Matrix4","../Core/PixelFormat","../Core/PrimitiveType","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/ClearCommand","../Renderer/ComputeCommand","../Renderer/DrawCommand","../Renderer/Framebuffer","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/Texture","../Renderer/VertexArray","../Shaders/SunFS","../Shaders/SunTextureFS","../Shaders/SunVS","./BlendingState","./SceneMode","./SceneTransforms"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M){"use strict";var D=function(){this.show=!0,this._drawCommand=new y({primitiveType:m.TRIANGLES,boundingVolume:new t,owner:this}),this._commands={drawCommand:this._drawCommand,computeCommand:void 0},this._boundingVolume=new t,this._boundingVolume2D=new t,this._texture=void 0,this._drawingBufferWidth=void 0,this._drawingBufferHeight=void 0,this._radiusTS=void 0,this._size=void 0,this.glowFactor=1,this._glowFactorDirty=!1;var e=this;this._uniformMap={u_texture:function(){return e._texture},u_size:function(){return e._size}}};l(D.prototype,{glowFactor:{get:function(){return this._glowFactor},set:function(e){e=Math.max(e,0),this._glowFactor=e,this._glowFactorDirty=!0}}});var R=new r,O=new r,N=new n,L=new n;return D.prototype.update=function(e){var n=e.frameState,o=e.context;if(!this.show)return void 0;var l=n.mode;if(l===I.SCENE2D||l===I.MORPHING)return void 0;if(!n.passes.render)return void 0;var u=e.drawingBufferWidth,m=e.drawingBufferHeight;if(!s(this._texture)||u!==this._drawingBufferWidth||m!==this._drawingBufferHeight||this._glowFactorDirty){this._texture=this._texture&&this._texture.destroy(),this._drawingBufferWidth=u,this._drawingBufferHeight=m,this._glowFactorDirty=!1;var _=Math.max(u,m);_=Math.pow(2,Math.ceil(Math.log(_)/Math.log(2))-2),this._texture=new w({context:o,width:_,height:_,pixelFormat:p.RGBA}),this._glowLengthTS=5*this._glowFactor,this._radiusTS=1/(1+2*this._glowLengthTS)*.5;var y=this,C={u_glowLengthTS:function(){return y._glowLengthTS},u_radiusTS:function(){return y._radiusTS}};this._commands.computeCommand=new g({fragmentShaderSource:x,outputTexture:this._texture,uniformMap:C,persists:!1,owner:this,postExecute:function(){y._commands.computeCommand=void 0}})}var D=this._drawCommand;if(!s(D.vertexArray)){var F={direction:0},B=new Uint8Array(8);B[0]=0,B[1]=0,B[2]=255,B[3]=0,B[4]=255,B[5]=255,B[6]=0,B[7]=255;var V=f.createVertexBuffer({context:o,typedArray:B,usage:v.STATIC_DRAW}),z=[{index:F.direction,vertexBuffer:V,componentsPerAttribute:2,normalize:!0,componentDatatype:a.UNSIGNED_BYTE}],k=f.createIndexBuffer({context:o,typedArray:new Uint16Array([0,1,2,0,2,3]),usage:v.STATIC_DRAW,indexDatatype:c.UNSIGNED_SHORT});D.vertexArray=new T({context:o,attributes:z,indexBuffer:k}),D.shaderProgram=S.fromCache({context:o,vertexShaderSource:P,fragmentShaderSource:b,attributeLocations:F}),D.renderState=E.fromCache({blending:A.ALPHA_BLEND}),D.uniformMap=this._uniformMap}var U=o.uniformState.sunPositionWC,G=o.uniformState.sunPositionColumbusView,W=this._boundingVolume,H=this._boundingVolume2D;i.clone(U,W.center),H.center.x=G.z,H.center.y=G.x,H.center.z=G.y,W.radius=h.SOLAR_RADIUS+h.SOLAR_RADIUS*this._glowLengthTS,H.radius=W.radius,l===I.SCENE3D?t.clone(W,D.boundingVolume):l===I.COLUMBUS_VIEW&&t.clone(H,D.boundingVolume);var q=M.computeActualWgs84Position(n,U,L),j=i.magnitude(i.subtract(q,e.camera.position,L)),Y=o.uniformState.projection,X=N;X.x=0,X.y=0,X.z=-j,X.w=1;var Z=d.multiplyByVector(Y,X,L),K=M.clipToDrawingBufferCoordinates(e,Z,R);X.x=h.SOLAR_RADIUS;var J=d.multiplyByVector(Y,X,L),Q=M.clipToDrawingBufferCoordinates(e,J,O);return this._size=Math.ceil(r.magnitude(r.subtract(Q,K,L))),this._size=2*this._size*(1+2*this._glowLengthTS),this._commands},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){var e=this._drawCommand;return e.vertexArray=e.vertexArray&&e.vertexArray.destroy(),e.shaderProgram=e.shaderProgram&&e.shaderProgram.destroy(),this._texture=this._texture&&this._texture.destroy(),u(this)},D}),r("Scene/TileCoordinatesImageryProvider",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","../Core/GeographicTilingScheme","../ThirdParty/when"],function(e,t,r,i,n,o,a){"use strict";var s=function(i){i=t(i,t.EMPTY_OBJECT),this._tilingScheme=r(i.tilingScheme)?i.tilingScheme:new o({ellipsoid:i.ellipsoid}),this._color=t(i.color,e.YELLOW),this._errorEvent=new n,this._tileWidth=t(i.tileWidth,256),this._tileHeight=t(i.tileHeight,256),this._readyPromise=a.resolve(!0)};return i(s.prototype,{proxy:{get:function(){return void 0}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return void 0}},minimumLevel:{get:function(){return void 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return void 0}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return void 0}},hasAlphaChannel:{get:function(){return!0}}}),s.prototype.getTileCredits=function(e,t,r){return void 0},s.prototype.requestImage=function(e,t,r){var i=document.createElement("canvas");i.width=256,i.height=256;var n=i.getContext("2d"),o=this._color.toCssColorString();n.strokeStyle=o,n.lineWidth=2,n.strokeRect(1,1,255,255);var a="L"+r+"X"+e+"Y"+t;return n.font="bold 25px Arial",n.textAlign="center",n.fillStyle="black",n.fillText(a,127,127),n.fillStyle=o,n.fillText(a,124,124),i},s.prototype.pickFeatures=function(){return void 0},s}),r("Scene/TileDiscardPolicy",["../Core/DeveloperError"],function(e){"use strict";var t=function(t){e.throwInstantiationError()};return t.prototype.isReady=e.throwInstantiationError,t.prototype.shouldDiscardImage=e.throwInstantiationError,t}),r("Scene/TileMapServiceImageryProvider",["../Core/Cartesian2","../Core/Cartographic","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicTilingScheme","../Core/joinUrls","../Core/loadXML","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e,t,r,i){var o=e._tilingScheme.getNumberOfYTilesAtLevel(i),a=u(e._url,i+"/"+t+"/"+(o-r-1)+"."+e._fileExtension),s=e._proxy;return n(s)&&(a=s.getURL(a)),a}var g=function(o){function a(r){for(var a,s,c,f,v=/tileformat/i,y=/tileset/i,S=/tilesets/i,w=/boundingbox/i,T=/srs/i,b=[],x=r.childNodes[0].childNodes,P=0;P<x.length;P++)if(v.test(x.item(P).nodeName))a=x.item(P);else if(S.test(x.item(P).nodeName)){c=x.item(P);for(var A=x.item(P).childNodes,I=0;I<A.length;I++)y.test(A.item(I).nodeName)&&b.push(A.item(I))}else w.test(x.item(P).nodeName)?s=x.item(P):T.test(x.item(P).nodeName)&&(f=x.item(P).textContent);E._fileExtension=i(E._fileExtension,a.getAttribute("extension")),E._tileWidth=i(E._tileWidth,parseInt(a.getAttribute("width"),10)),E._tileHeight=i(E._tileHeight,parseInt(a.getAttribute("height"),10)),E._minimumLevel=i(E._minimumLevel,parseInt(b[0].getAttribute("order"),10)),E._maximumLevel=i(E._maximumLevel,parseInt(b[b.length-1].getAttribute("order"),10));var M=c.getAttribute("profile"),D=!1;if(("geodetic"===M||"mercator"===M)&&(D=!0),!n(E._tilingScheme))if("geodetic"===M||"global-geodetic"===M)E._tilingScheme=new l({ellipsoid:o.ellipsoid});else{if("mercator"!==M&&"global-mercator"!==M){var R=u(g,"tilemapresource.xml")+"specifies an unsupported profile attribute, "+M+".";return C=p.handleError(C,E,E._errorEvent,R,void 0,void 0,void 0,_),void E._readyPromise.reject(new d(R))}E._tilingScheme=new m({ellipsoid:o.ellipsoid})}var O=E._tilingScheme;if(!n(E._rectangle)){var N,L,F,B;if(D)N=new e(parseFloat(s.getAttribute("miny")),parseFloat(s.getAttribute("minx"))),L=new e(parseFloat(s.getAttribute("maxy")),parseFloat(s.getAttribute("maxx"))),F=t.fromDegrees(N.x,N.y),B=t.fromDegrees(L.x,L.y);else if(N=new e(parseFloat(s.getAttribute("minx")),parseFloat(s.getAttribute("miny"))),L=new e(parseFloat(s.getAttribute("maxx")),parseFloat(s.getAttribute("maxy"))),E._tilingScheme instanceof l)F=t.fromDegrees(N.x,N.y),B=t.fromDegrees(L.x,L.y);else{var V=E._tilingScheme.projection;F=V.unproject(N),B=V.unproject(L)}E._rectangle=new h(F.longitude,F.latitude,B.longitude,B.latitude)}E._rectangle.west<O.rectangle.west&&(E._rectangle.west=O.rectangle.west),E._rectangle.east>O.rectangle.east&&(E._rectangle.east=O.rectangle.east),E._rectangle.south<O.rectangle.south&&(E._rectangle.south=O.rectangle.south),E._rectangle.north>O.rectangle.north&&(E._rectangle.north=O.rectangle.north);var z=O.positionToTileXY(h.southwest(E._rectangle),E._minimumLevel),k=O.positionToTileXY(h.northeast(E._rectangle),E._minimumLevel),U=(Math.abs(k.x-z.x)+1)*(Math.abs(k.y-z.y)+1);U>4&&(E._minimumLevel=0),E._tilingScheme=O,E._ready=!0,E._readyPromise.resolve(!0)}function v(e){E._fileExtension=i(o.fileExtension,"png"),E._tileWidth=i(o.tileWidth,256),E._tileHeight=i(o.tileHeight,256),E._minimumLevel=i(o.minimumLevel,0),E._maximumLevel=o.maximumLevel,E._tilingScheme=n(o.tilingScheme)?o.tilingScheme:new m({ellipsoid:o.ellipsoid}),E._rectangle=i(o.rectangle,E._tilingScheme.rectangle),E._ready=!0,E._readyPromise.resolve(!0)}function _(){var e=u(g,"tilemapresource.xml"),t=E._proxy;n(t)&&(e=t.getURL(e)),f(c(e),a,v)}o=i(o,{});var g=o.url;this._url=g,this._ready=!1,this._readyPromise=f.defer(),this._proxy=o.proxy,this._tileDiscardPolicy=o.tileDiscardPolicy,this._errorEvent=new s,this._fileExtension=o.fileExtension,this._tileWidth=o.tileWidth,this._tileHeight=o.tileHeight,this._minimumLevel=o.minimumLevel,this._maximumLevel=o.maximumLevel,this._rectangle=h.clone(o.rectangle),this._tilingScheme=o.tilingScheme;var y=o.credit;"string"==typeof y&&(y=new r(y)),this._credit=y;var C,E=this;_()};return o(g.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),g.prototype.getTileCredits=function(e,t,r){return void 0},g.prototype.requestImage=function(e,t,r){var i=_(this,e,t,r);return v.loadImage(this,i)},g.prototype.pickFeatures=function(){return void 0},g}),r("Scene/TileState",["../Core/freezeObject"],function(e){"use strict";var t={START:0,LOADING:1,READY:2,UPSAMPLED_ONLY:3};return e(t)}),r("Shaders/ViewportQuadFS",[],function(){"use strict";return"varying vec2 v_textureCoordinates;\nvoid main()\n{\nczm_materialInput materialInput;\nmaterialInput.s = v_textureCoordinates.s;\nmaterialInput.st = v_textureCoordinates;\nmaterialInput.str = vec3(v_textureCoordinates, 0.0);\nmaterialInput.normalEC = vec3(0.0, 0.0, -1.0);\nczm_material material = czm_getMaterial(materialInput);\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n}\n"}),r("Scene/ViewportQuad",["../Core/BoundingRectangle","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Renderer/RenderState","../Renderer/ShaderSource","../Shaders/ViewportQuadFS","./BlendingState","./Material","./Pass"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";var h=function(i,n){this.show=!0,r(i)||(i=new e),this.rectangle=e.clone(i),r(n)||(n=u.fromType(u.ColorType,{color:new t(1,1,1,1)})),this.material=n,this._material=void 0,this._overlayCommand=void 0,this._rs=void 0};return h.prototype.update=function(t){if(this.show){var i=this._rs;r(i)&&e.equals(i.viewport,this.rectangle)||(this._rs=o.fromCache({blending:l.ALPHA_BLEND,viewport:this.rectangle}));var n=t.passes;if(n.render){var u=t.context;if(this._material!==this.material||!r(this._overlayCommand)){this._material=this.material,r(this._overlayCommand)&&this._overlayCommand.shaderProgram.destroy();var h=new a({sources:[this._material.shaderSource,s]});this._overlayCommand=u.createViewportQuadCommand(h,{renderState:this._rs,uniformMap:this._material._uniforms,owner:this}),this._overlayCommand.pass=c.OVERLAY}this._material.update(u),this._overlayCommand.uniformMap=this._material._uniforms,t.commandList.push(this._overlayCommand)}}},h.prototype.isDestroyed=function(){return!1},h.prototype.destroy=function(){return r(this._overlayCommand)&&(this._overlayCommand.shaderProgram=this._overlayCommand.shaderProgram&&this._overlayCommand.shaderProgram.destroy()),i(this)},h}),r("Scene/WebMapServiceImageryProvider",["../Core/combine","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/freezeObject","../Core/GeographicTilingScheme","../Core/objectToQuery","../Core/queryToObject","../Core/WebMercatorTilingScheme","../ThirdParty/Uri","./GetFeatureInfoFormat","./UrlTemplateImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e){var t={};for(var r in e)e.hasOwnProperty(r)&&(t[r.toLowerCase()]=e[r]);return t}var f=function v(i){function n(e,t){r(d[e])||(d[e]=t),r(g)&&!r(g[e])&&(g[e]=t)}i=t(i,t.EMPTY_OBJECT),this._url=i.url,this._layers=i.layers;var o=t(i.getFeatureInfoFormats,v.DefaultGetFeatureInfoFormats),a=new h(i.url),d=u(t(a.query,"")),f=e(m(t(i.parameters,t.EMPTY_OBJECT)),v.DefaultParameters);d=e(f,d);var _,g;if(t(i.enablePickFeatures,!0)){_=new h(i.url),g=u(t(_.query,""));var y=e(m(t(i.getFeatureInfoParameters,t.EMPTY_OBJECT)),v.GetFeatureInfoDefaultParameters);g=e(y,g)}n("layers",i.layers),n("srs",i.tilingScheme instanceof c?"EPSG:3857":"EPSG:4326"),n("bbox","{westProjected},{southProjected},{eastProjected},{northProjected}"),n("width","{width}"),n("height","{height}"),a.query=l(d);var C,E=a.toString().replace(/%7B/g,"{").replace(/%7D/g,"}");r(g)&&(r(g.query_layers)||(g.query_layers=i.layers),r(g.x)||(g.x="{i}"),r(g.y)||(g.y="{j}"),r(g.info_format)||(g.info_format="{format}"),_.query=l(g),C=_.toString().replace(/%7B/g,"{").replace(/%7D/g,"}")),this._tileProvider=new p({url:E,pickFeaturesUrl:C,tilingScheme:t(i.tilingScheme,new s({ellipsoid:i.ellipsoid})),rectangle:i.rectangle,tileWidth:i.tileWidth,tileHeight:i.tileHeight,minimumLevel:i.minimumLevel,maximumLevel:i.maximumLevel,minimumRetrievingLevel:i.minimumRetrievingLevel,proxy:i.proxy,subdomains:i.subdomains,tileDiscardPolicy:i.tileDiscardPolicy,credit:i.credit,getFeatureInfoFormats:o})};return i(f.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._tileProvider.proxy}},layers:{get:function(){return this._layers}},tileWidth:{get:function(){return this._tileProvider.tileWidth}},tileHeight:{get:function(){return this._tileProvider.tileHeight}},maximumLevel:{get:function(){return this._tileProvider.maximumLevel}},minimumLevel:{get:function(){return this._tileProvider.minimumLevel}},tilingScheme:{get:function(){return this._tileProvider.tilingScheme}},rectangle:{get:function(){return this._tileProvider.rectangle}},tileDiscardPolicy:{get:function(){return this._tileProvider.tileDiscardPolicy}},errorEvent:{get:function(){return this._tileProvider.errorEvent}},ready:{get:function(){return this._tileProvider.ready}},readyPromise:{get:function(){return this._tileProvider.readyPromise}},credit:{get:function(){return this._tileProvider.credit}},hasAlphaChannel:{get:function(){return this._tileProvider.hasAlphaChannel}}}),f.prototype.getTileCredits=function(e,t,r){return this._tileProvider.getTileCredits(e,t,r)},f.prototype.requestImage=function(e,t,r){return this._tileProvider.requestImage(e,t,r)},f.prototype.pickFeatures=function(e,t,r,i,n){return this._tileProvider.pickFeatures(e,t,r,i,n)},f.DefaultParameters=a({service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"}),f.GetFeatureInfoDefaultParameters=a({service:"WMS",version:"1.1.1",request:"GetFeatureInfo"}),f.DefaultGetFeatureInfoFormats=a([a(new d("json","application/json")),a(new d("xml","text/xml")),a(new d("text","text/html"))]),f}),r("Scene/WebMapTileServiceImageryProvider",["../Core/combine","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/freezeObject","../Core/objectToQuery","../Core/queryToObject","../Core/Rectangle","../Core/WebMercatorTilingScheme","../ThirdParty/Uri","../ThirdParty/when","./ImageryProvider","./UrlTemplateImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(t,n,o,a){var s,c=t._tileMatrixLabels,h=i(c)?c[a]:a.toString(),p=t._subdomains;if(t._url.indexOf("{")>=0)s=t._url.replace("{style}",t._style).replace("{Style}",t._style).replace("{TileMatrixSet}",t._tileMatrixSetID).replace("{TileMatrix}",h).replace("{TileRow}",o.toString()).replace("{TileCol}",n.toString()).replace("{s}",p[(n+o+a)%p.length]);else{var m=new d(t._url),f=u(r(m.query,""));f=e(g,f),f.tilematrix=h,f.layer=t._layer,f.style=t._style,f.tilerow=o,f.tilecol=n,f.tilematrixset=t._tileMatrixSetID,f.format=t._format,m.query=l(f),s=m.toString()}var v=t._proxy;return i(v)&&(s=v.getURL(s)),s}var _=function(e){if(e=r(e,r.EMPTY_OBJECT),!i(e.url))throw new o("options.url is required.");if(!i(e.layer))throw new o("options.layer is required.");if(!i(e.style))throw new o("options.style is required.");if(!i(e.tileMatrixSetID))throw new o("options.tileMatrixSetID is required.");this._url=e.url,this._layer=e.layer,this._style=e.style,this._tileMatrixSetID=e.tileMatrixSetID,this._tileMatrixLabels=e.tileMatrixLabels,this._format=r(e.format,"image/jpeg"),this._proxy=e.proxy,this._tileDiscardPolicy=e.tileDiscardPolicy,this._tilingScheme=i(e.tilingScheme)?e.tilingScheme:new h({ellipsoid:e.ellipsoid}),this._tileWidth=r(e.tileWidth,256),this._tileHeight=r(e.tileHeight,256),this._minimumRetrievingLevel=r(e.minimumRetrievingLevel,0),this._minimumLevel=r(e.minimumLevel,0),this._maximumLevel=e.maximumLevel,this._rectangle=r(e.rectangle,this._tilingScheme.rectangle),this._readyPromise=p.resolve(!0);var n=this._tilingScheme.positionToTileXY(c.southwest(this._rectangle),this._minimumLevel),s=this._tilingScheme.positionToTileXY(c.northeast(this._rectangle),this._minimumLevel),l=(Math.abs(s.x-n.x)+1)*(Math.abs(s.y-n.y)+1);if(l>4)throw new o("The imagery provider's rectangle and minimumLevel indicate that there are "+l+" tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.");this._errorEvent=new a;var u=e.credit;this._credit="string"==typeof u?new t(u):u,this._subdomains=e.subdomains,Array.isArray(this._subdomains)?this._subdomains=this._subdomains.slice():i(this._subdomains)&&this._subdomains.length>0?this._subdomains=this._subdomains.split(""):this._subdomains=["a","b","c"]},g=s({service:"WMTS",version:"1.0.0",request:"GetTile"});return n(_.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},format:{get:function(){return this._format}},ready:{value:!0},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),_.prototype.getTileCredits=function(e,t,r){return void 0},_.prototype.requestImage=function(e,t,r){if(r<this._minimumRetrievingLevel)return f.transparentCanvas;var i=v(this,e,t,r);return m.loadImage(this,i)},_.prototype.pickFeatures=function(){return void 0},_}),r("Scene/createTangentSpaceDebugPrimitive",["../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/GeometryInstance","../Core/GeometryPipeline","../Core/Matrix4","./PerInstanceColorAppearance","./Primitive"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(i){i=t(i,t.EMPTY_OBJECT);var u=[],c=i.geometry;r(c.attributes)&&r(c.primitiveType)||(c=c.constructor.createGeometry(c));var h=c.attributes,d=a.clone(t(i.modelMatrix,a.IDENTITY)),p=t(i.length,1e4);return r(h.normal)&&u.push(new n({geometry:o.createLineSegmentsForVectors(c,"normal",p),attributes:{color:new e(1,0,0,1)},modelMatrix:d})),r(h.binormal)&&u.push(new n({geometry:o.createLineSegmentsForVectors(c,"binormal",p),attributes:{color:new e(0,1,0,1)},modelMatrix:d})),r(h.tangent)&&u.push(new n({geometry:o.createLineSegmentsForVectors(c,"tangent",p),attributes:{color:new e(0,0,1,1)},modelMatrix:d})),u.length>0?new l({asynchronous:!1,geometryInstances:u,appearance:new s({flat:!0,translucent:!1})}):void 0};return u}),function(){!function(e){var i=this||(0,eval)("this"),n=i.document,o=i.navigator,a=i.jQuery,s=i.JSON;!function(e){"function"==typeof t&&"object"==typeof exports&&"object"==typeof module?e(module.exports||exports,t):"function"==typeof r&&r.amd?r("ThirdParty/knockout-3.2.0",["exports","require"],e):e(i.ko={})}(function(t,r){function l(e,t){return null===e||typeof e in p?e===t:!1}function u(t,r){var i;return function(){i||(i=setTimeout(function(){i=e,t()},r))}}function c(e,t){var r;return function(){clearTimeout(r),r=setTimeout(e,t)}}function h(e,t,r,i){d.d[e]={init:function(e,n,o,a,s){var l,u;return d.s(function(){var o=d.a.c(n()),a=!r!=!o,c=!u;(c||t||a!==l)&&(c&&d.Y.la()&&(u=d.a.ia(d.f.childNodes(e),!0)),a?(c||d.f.T(e,d.a.ia(u)),d.Ca(i?i(s,o):s,e)):d.f.ja(e),l=a)},null,{o:e}),{controlsDescendantBindings:!0}}},d.h.ha[e]=!1,d.f.Q[e]=!0}var d="undefined"!=typeof t?t:{};d.b=function(e,t){for(var r=e.split("."),i=d,n=0;n<r.length-1;n++)i=i[r[n]];i[r[r.length-1]]=t},d.A=function(e,t,r){e[t]=r},d.version="3.2.0",d.b("version",d.version),d.a=function(){function t(e,t){for(var r in e)e.hasOwnProperty(r)&&t(r,e[r])}function r(e,t){if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function l(e,t){return e.__proto__=t,e}var u={__proto__:[]}instanceof Array,c={},h={};c[o&&/Firefox\/2/i.test(o.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"],c.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" "),t(c,function(e,t){if(t.length)for(var r=0,i=t.length;i>r;r++)h[t[r]]=e});var p={propertychange:!0},m=n&&function(){for(var t=3,r=n.createElement("div"),i=r.getElementsByTagName("i");r.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->",i[0];);return t>4?t:e}();return{vb:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],u:function(e,t){for(var r=0,i=e.length;i>r;r++)t(e[r],r)},m:function(e,t){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(e,t);for(var r=0,i=e.length;i>r;r++)if(e[r]===t)return r;return-1},qb:function(e,t,r){for(var i=0,n=e.length;n>i;i++)if(t.call(r,e[i],i))return e[i];return null},ua:function(e,t){var r=d.a.m(e,t);r>0?e.splice(r,1):0===r&&e.shift()},rb:function(e){e=e||[];for(var t=[],r=0,i=e.length;i>r;r++)0>d.a.m(t,e[r])&&t.push(e[r]);return t},Da:function(e,t){e=e||[];for(var r=[],i=0,n=e.length;n>i;i++)r.push(t(e[i],i));return r},ta:function(e,t){e=e||[];for(var r=[],i=0,n=e.length;n>i;i++)t(e[i],i)&&r.push(e[i]);return r},ga:function(e,t){if(t instanceof Array)e.push.apply(e,t);else for(var r=0,i=t.length;i>r;r++)e.push(t[r]);return e},ea:function(e,t,r){var i=d.a.m(d.a.Xa(e),t);0>i?r&&e.push(t):r||e.splice(i,1)},xa:u,extend:r,za:l,Aa:u?l:r,G:t,na:function(e,t){if(!e)return e;var r,i={};for(r in e)e.hasOwnProperty(r)&&(i[r]=t(e[r],r,e));return i},Ka:function(e){for(;e.firstChild;)d.removeNode(e.firstChild)},oc:function(e){e=d.a.S(e);for(var t=n.createElement("div"),r=0,i=e.length;i>r;r++)t.appendChild(d.R(e[r]));return t},ia:function(e,t){for(var r=0,i=e.length,n=[];i>r;r++){var o=e[r].cloneNode(!0);n.push(t?d.R(o):o)}return n},T:function(e,t){if(d.a.Ka(e),t)for(var r=0,i=t.length;i>r;r++)e.appendChild(t[r])},Lb:function(e,t){var r=e.nodeType?[e]:e;if(0<r.length){for(var i=r[0],n=i.parentNode,o=0,a=t.length;a>o;o++)n.insertBefore(t[o],i);for(o=0,a=r.length;a>o;o++)d.removeNode(r[o])}},ka:function(e,t){if(e.length){for(t=8===t.nodeType&&t.parentNode||t;e.length&&e[0].parentNode!==t;)e.shift();if(1<e.length){var r=e[0],i=e[e.length-1];for(e.length=0;r!==i;)if(e.push(r),r=r.nextSibling,!r)return;e.push(i)}}return e},Nb:function(e,t){7>m?e.setAttribute("selected",t):e.selected=t},cb:function(t){return null===t||t===e?"":t.trim?t.trim():t.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},vc:function(e,t){return e=e||"",t.length>e.length?!1:e.substring(0,t.length)===t},cc:function(e,t){if(e===t)return!0;if(11===e.nodeType)return!1;if(t.contains)return t.contains(3===e.nodeType?e.parentNode:e);if(t.compareDocumentPosition)return 16==(16&t.compareDocumentPosition(e));for(;e&&e!=t;)e=e.parentNode;return!!e},Ja:function(e){return d.a.cc(e,e.ownerDocument.documentElement)},ob:function(e){return!!d.a.qb(e,d.a.Ja)},t:function(e){return e&&e.tagName&&e.tagName.toLowerCase()},n:function(e,t,r){var i=m&&p[t];if(!i&&a)a(e).bind(t,r);else if(i||"function"!=typeof e.addEventListener){if("undefined"==typeof e.attachEvent)throw Error("Browser doesn't support addEventListener or attachEvent");var n=function(t){r.call(e,t)},o="on"+t;e.attachEvent(o,n),d.a.w.da(e,function(){e.detachEvent(o,n)})}else e.addEventListener(t,r,!1)},oa:function(e,t){if(!e||!e.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var r;if("input"===d.a.t(e)&&e.type&&"click"==t.toLowerCase()?(r=e.type,r="checkbox"==r||"radio"==r):r=!1,a&&!r)a(e).trigger(t);else if("function"==typeof n.createEvent){if("function"!=typeof e.dispatchEvent)throw Error("The supplied element doesn't support dispatchEvent");r=n.createEvent(h[t]||"HTMLEvents"),r.initEvent(t,!0,!0,i,0,0,0,0,0,!1,!1,!1,!1,0,e),e.dispatchEvent(r)}else if(r&&e.click)e.click();else{if("undefined"==typeof e.fireEvent)throw Error("Browser doesn't support triggering events");e.fireEvent("on"+t)}},c:function(e){return d.C(e)?e():e},Xa:function(e){return d.C(e)?e.v():e},Ba:function(e,t,r){if(t){var i=/\S+/g,n=e.className.match(i)||[];d.a.u(t.match(i),function(e){d.a.ea(n,e,r)}),e.className=n.join(" ")}},bb:function(t,r){var i=d.a.c(r);(null===i||i===e)&&(i="");var n=d.f.firstChild(t);!n||3!=n.nodeType||d.f.nextSibling(n)?d.f.T(t,[t.ownerDocument.createTextNode(i)]):n.data=i,d.a.fc(t)},Mb:function(e,t){if(e.name=t,7>=m)try{e.mergeAttributes(n.createElement("<input name='"+e.name+"'/>"),!1)}catch(r){}},fc:function(e){m>=9&&(e=1==e.nodeType?e:e.parentNode,e.style&&(e.style.zoom=e.style.zoom))},dc:function(e){if(m){var t=e.style.width;e.style.width=0,e.style.width=t}},sc:function(e,t){e=d.a.c(e),t=d.a.c(t);for(var r=[],i=e;t>=i;i++)r.push(i);return r},S:function(e){for(var t=[],r=0,i=e.length;i>r;r++)t.push(e[r]);return t},yc:6===m,zc:7===m,L:m,xb:function(e,t){for(var r=d.a.S(e.getElementsByTagName("input")).concat(d.a.S(e.getElementsByTagName("textarea"))),i="string"==typeof t?function(e){return e.name===t}:function(e){return t.test(e.name)},n=[],o=r.length-1;o>=0;o--)i(r[o])&&n.push(r[o]);return n},pc:function(e){return"string"==typeof e&&(e=d.a.cb(e))?s&&s.parse?s.parse(e):new Function("return "+e)():null},eb:function(e,t,r){if(!s||!s.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");return s.stringify(d.a.c(e),t,r)},qc:function(e,r,i){i=i||{};var o=i.params||{},a=i.includeFields||this.vb,s=e;if("object"==typeof e&&"form"===d.a.t(e))for(var s=e.action,l=a.length-1;l>=0;l--)for(var u=d.a.xb(e,a[l]),c=u.length-1;c>=0;c--)o[u[c].name]=u[c].value;r=d.a.c(r);var h=n.createElement("form");h.style.display="none",h.action=s,h.method="post";for(var p in r)e=n.createElement("input"),e.type="hidden",e.name=p,e.value=d.a.eb(d.a.c(r[p])),h.appendChild(e);t(o,function(e,t){var r=n.createElement("input");r.type="hidden",r.name=e,r.value=t,h.appendChild(r)}),n.body.appendChild(h),i.submitter?i.submitter(h):h.submit(),setTimeout(function(){h.parentNode.removeChild(h)},0)}}}(),d.b("utils",d.a),d.b("utils.arrayForEach",d.a.u),d.b("utils.arrayFirst",d.a.qb),d.b("utils.arrayFilter",d.a.ta),d.b("utils.arrayGetDistinctValues",d.a.rb),d.b("utils.arrayIndexOf",d.a.m),d.b("utils.arrayMap",d.a.Da),d.b("utils.arrayPushAll",d.a.ga),d.b("utils.arrayRemoveItem",d.a.ua),d.b("utils.extend",d.a.extend),d.b("utils.fieldsIncludedWithJsonPost",d.a.vb),d.b("utils.getFormFields",d.a.xb),d.b("utils.peekObservable",d.a.Xa),d.b("utils.postJson",d.a.qc),d.b("utils.parseJson",d.a.pc),d.b("utils.registerEventHandler",d.a.n),d.b("utils.stringifyJson",d.a.eb),d.b("utils.range",d.a.sc),d.b("utils.toggleDomNodeCssClass",d.a.Ba),d.b("utils.triggerEvent",d.a.oa),d.b("utils.unwrapObservable",d.a.c),d.b("utils.objectForEach",d.a.G),d.b("utils.addOrRemoveItem",d.a.ea),d.b("unwrap",d.a.c),Function.prototype.bind||(Function.prototype.bind=function(e){var t=this,r=Array.prototype.slice.call(arguments);return e=r.shift(),function(){return t.apply(e,r.concat(Array.prototype.slice.call(arguments)))}}),d.a.e=new function(){function t(t,o){var a=t[i];if(!a||"null"===a||!n[a]){if(!o)return e;a=t[i]="ko"+r++,n[a]={}}return n[a]}var r=0,i="__ko__"+(new Date).getTime(),n={};return{get:function(r,i){var n=t(r,!1);return n===e?e:n[i]},set:function(r,i,n){(n!==e||t(r,!1)!==e)&&(t(r,!0)[i]=n)},clear:function(e){var t=e[i];return t?(delete n[t],e[i]=null,!0):!1},F:function(){return r++ +i}}},d.b("utils.domData",d.a.e),d.b("utils.domData.clear",d.a.e.clear),d.a.w=new function(){function t(t,r){var n=d.a.e.get(t,i);return n===e&&r&&(n=[],d.a.e.set(t,i,n)),n}function r(e){var i=t(e,!1);if(i)for(var i=i.slice(0),n=0;n<i.length;n++)i[n](e);if(d.a.e.clear(e),d.a.w.cleanExternalData(e),o[e.nodeType])for(i=e.firstChild;e=i;)i=e.nextSibling,8===e.nodeType&&r(e)}var i=d.a.e.F(),n={1:!0,8:!0,9:!0},o={1:!0,9:!0};return{da:function(e,r){if("function"!=typeof r)throw Error("Callback must be a function");t(e,!0).push(r)},Kb:function(r,n){var o=t(r,!1);o&&(d.a.ua(o,n),0==o.length&&d.a.e.set(r,i,e))},R:function(e){if(n[e.nodeType]&&(r(e),o[e.nodeType])){var t=[];d.a.ga(t,e.getElementsByTagName("*"));for(var i=0,a=t.length;a>i;i++)r(t[i])}return e},removeNode:function(e){d.R(e),e.parentNode&&e.parentNode.removeChild(e)},cleanExternalData:function(e){a&&"function"==typeof a.cleanData&&a.cleanData([e])}}},d.R=d.a.w.R, +d.removeNode=d.a.w.removeNode,d.b("cleanNode",d.R),d.b("removeNode",d.removeNode),d.b("utils.domNodeDisposal",d.a.w),d.b("utils.domNodeDisposal.addDisposeCallback",d.a.w.da),d.b("utils.domNodeDisposal.removeDisposeCallback",d.a.w.Kb),function(){d.a.ba=function(e){var t;if(a){if(a.parseHTML)t=a.parseHTML(e)||[];else if((t=a.clean([e]))&&t[0]){for(e=t[0];e.parentNode&&11!==e.parentNode.nodeType;)e=e.parentNode;e.parentNode&&e.parentNode.removeChild(e)}}else{var r=d.a.cb(e).toLowerCase();for(t=n.createElement("div"),r=r.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!r.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!r.indexOf("<td")||!r.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""],e="ignored<div>"+r[1]+e+r[2]+"</div>","function"==typeof i.innerShiv?t.appendChild(i.innerShiv(e)):t.innerHTML=e;r[0]--;)t=t.lastChild;t=d.a.S(t.lastChild.childNodes)}return t},d.a.$a=function(t,r){if(d.a.Ka(t),r=d.a.c(r),null!==r&&r!==e)if("string"!=typeof r&&(r=r.toString()),a)a(t).html(r);else for(var i=d.a.ba(r),n=0;n<i.length;n++)t.appendChild(i[n])}}(),d.b("utils.parseHtmlFragment",d.a.ba),d.b("utils.setHtml",d.a.$a),d.D=function(){function t(e,r){if(e)if(8==e.nodeType){var i=d.D.Gb(e.nodeValue);null!=i&&r.push({bc:e,mc:i})}else if(1==e.nodeType)for(var i=0,n=e.childNodes,o=n.length;o>i;i++)t(n[i],r)}var r={};return{Ua:function(e){if("function"!=typeof e)throw Error("You can only pass a function to ko.memoization.memoize()");var t=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);return r[t]=e,"<!--[ko_memo:"+t+"]-->"},Rb:function(t,i){var n=r[t];if(n===e)throw Error("Couldn't find any memo with ID "+t+". Perhaps it's already been unmemoized.");try{return n.apply(null,i||[]),!0}finally{delete r[t]}},Sb:function(e,r){var i=[];t(e,i);for(var n=0,o=i.length;o>n;n++){var a=i[n].bc,s=[a];r&&d.a.ga(s,r),d.D.Rb(i[n].mc,s),a.nodeValue="",a.parentNode&&a.parentNode.removeChild(a)}},Gb:function(e){return(e=e.match(/^\[ko_memo\:(.*?)\]$/))?e[1]:null}}}(),d.b("memoization",d.D),d.b("memoization.memoize",d.D.Ua),d.b("memoization.unmemoize",d.D.Rb),d.b("memoization.parseMemoText",d.D.Gb),d.b("memoization.unmemoizeDomNodeAndDescendants",d.D.Sb),d.La={throttle:function(e,t){e.throttleEvaluation=t;var r=null;return d.j({read:e,write:function(i){clearTimeout(r),r=setTimeout(function(){e(i)},t)}})},rateLimit:function(e,t){var r,i,n;"number"==typeof t?r=t:(r=t.timeout,i=t.method),n="notifyWhenChangesStop"==i?c:u,e.Ta(function(e){return n(e,r)})},notify:function(e,t){e.equalityComparer="always"==t?null:l}};var p={undefined:1,"boolean":1,number:1,string:1};d.b("extenders",d.La),d.Pb=function(e,t,r){this.target=e,this.wa=t,this.ac=r,this.Cb=!1,d.A(this,"dispose",this.K)},d.Pb.prototype.K=function(){this.Cb=!0,this.ac()},d.P=function(){d.a.Aa(this,d.P.fn),this.M={}};var m="change",f={U:function(e,t,r){var i=this;r=r||m;var n=new d.Pb(i,t?e.bind(t):e,function(){d.a.ua(i.M[r],n),i.nb&&i.nb()});return i.va&&i.va(r),i.M[r]||(i.M[r]=[]),i.M[r].push(n),n},notifySubscribers:function(e,t){if(t=t||m,this.Ab(t))try{d.k.Ea();for(var r,i=this.M[t].slice(0),n=0;r=i[n];++n)r.Cb||r.wa(e)}finally{d.k.end()}},Ta:function(e){var t,r,i,n=this,o=d.C(n);n.qa||(n.qa=n.notifySubscribers,n.notifySubscribers=function(e,t){t&&t!==m?"beforeChange"===t?n.kb(e):n.qa(e,t):n.lb(e)});var a=e(function(){o&&i===n&&(i=n()),t=!1,n.Pa(r,i)&&n.qa(r=i)});n.lb=function(e){t=!0,i=e,a()},n.kb=function(e){t||(r=e,n.qa(e,"beforeChange"))}},Ab:function(e){return this.M[e]&&this.M[e].length},yb:function(){var e=0;return d.a.G(this.M,function(t,r){e+=r.length}),e},Pa:function(e,t){return!this.equalityComparer||!this.equalityComparer(e,t)},extend:function(e){var t=this;return e&&d.a.G(e,function(e,r){var i=d.La[e];"function"==typeof i&&(t=i(t,r)||t)}),t}};d.A(f,"subscribe",f.U),d.A(f,"extend",f.extend),d.A(f,"getSubscriptionsCount",f.yb),d.a.xa&&d.a.za(f,Function.prototype),d.P.fn=f,d.Db=function(e){return null!=e&&"function"==typeof e.U&&"function"==typeof e.notifySubscribers},d.b("subscribable",d.P),d.b("isSubscribable",d.Db),d.Y=d.k=function(){function e(e){i.push(r),r=e}function t(){r=i.pop()}var r,i=[],n=0;return{Ea:e,end:t,Jb:function(e){if(r){if(!d.Db(e))throw Error("Only subscribable things can act as dependencies");r.wa(e,e.Vb||(e.Vb=++n))}},B:function(r,i,n){try{return e(),r.apply(i,n||[])}finally{t()}},la:function(){return r?r.s.la():void 0},ma:function(){return r?r.ma:void 0}}}(),d.b("computedContext",d.Y),d.b("computedContext.getDependenciesCount",d.Y.la),d.b("computedContext.isInitial",d.Y.ma),d.b("computedContext.isSleeping",d.Y.Ac),d.p=function(e){function t(){return 0<arguments.length?(t.Pa(r,arguments[0])&&(t.X(),r=arguments[0],t.W()),this):(d.k.Jb(t),r)}var r=e;return d.P.call(t),d.a.Aa(t,d.p.fn),t.v=function(){return r},t.W=function(){t.notifySubscribers(r)},t.X=function(){t.notifySubscribers(r,"beforeChange")},d.A(t,"peek",t.v),d.A(t,"valueHasMutated",t.W),d.A(t,"valueWillMutate",t.X),t},d.p.fn={equalityComparer:l};var v=d.p.rc="__ko_proto__";d.p.fn[v]=d.p,d.a.xa&&d.a.za(d.p.fn,d.P.fn),d.Ma=function(t,r){return null===t||t===e||t[v]===e?!1:t[v]===r?!0:d.Ma(t[v],r)},d.C=function(e){return d.Ma(e,d.p)},d.Ra=function(e){return"function"==typeof e&&e[v]===d.p||"function"==typeof e&&e[v]===d.j&&e.hc?!0:!1},d.b("observable",d.p),d.b("isObservable",d.C),d.b("isWriteableObservable",d.Ra),d.b("isWritableObservable",d.Ra),d.aa=function(e){if(e=e||[],"object"!=typeof e||!("length"in e))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");return e=d.p(e),d.a.Aa(e,d.aa.fn),e.extend({trackArrayChanges:!0})},d.aa.fn={remove:function(e){for(var t=this.v(),r=[],i="function"!=typeof e||d.C(e)?function(t){return t===e}:e,n=0;n<t.length;n++){var o=t[n];i(o)&&(0===r.length&&this.X(),r.push(o),t.splice(n,1),n--)}return r.length&&this.W(),r},removeAll:function(t){if(t===e){var r=this.v(),i=r.slice(0);return this.X(),r.splice(0,r.length),this.W(),i}return t?this.remove(function(e){return 0<=d.a.m(t,e)}):[]},destroy:function(e){var t=this.v(),r="function"!=typeof e||d.C(e)?function(t){return t===e}:e;this.X();for(var i=t.length-1;i>=0;i--)r(t[i])&&(t[i]._destroy=!0);this.W()},destroyAll:function(t){return t===e?this.destroy(function(){return!0}):t?this.destroy(function(e){return 0<=d.a.m(t,e)}):[]},indexOf:function(e){var t=this();return d.a.m(t,e)},replace:function(e,t){var r=this.indexOf(e);r>=0&&(this.X(),this.v()[r]=t,this.W())}},d.a.u("pop push reverse shift sort splice unshift".split(" "),function(e){d.aa.fn[e]=function(){var t=this.v();return this.X(),this.sb(t,e,arguments),t=t[e].apply(t,arguments),this.W(),t}}),d.a.u(["slice"],function(e){d.aa.fn[e]=function(){var t=this();return t[e].apply(t,arguments)}}),d.a.xa&&d.a.za(d.aa.fn,d.p.fn),d.b("observableArray",d.aa);var _="arrayChange";d.La.trackArrayChanges=function(e){function t(){if(!r){r=!0;var t=e.notifySubscribers;e.notifySubscribers=function(e,r){return r&&r!==m||++n,t.apply(this,arguments)};var o=[].concat(e.v()||[]);i=null,e.U(function(t){if(t=[].concat(t||[]),e.Ab(_)){var r;(!i||n>1)&&(i=d.a.Fa(o,t,{sparse:!0})),r=i,r.length&&e.notifySubscribers(r,_)}o=t,i=null,n=0})}}if(!e.sb){var r=!1,i=null,n=0,o=e.U;e.U=e.subscribe=function(e,r,i){return i===_&&t(),o.apply(this,arguments)},e.sb=function(e,t,o){function a(e,t,r){return s[s.length]={status:e,value:t,index:r}}if(r&&!n){var s=[],l=e.length,u=o.length,c=0;switch(t){case"push":c=l;case"unshift":for(t=0;u>t;t++)a("added",o[t],c+t);break;case"pop":c=l-1;case"shift":l&&a("deleted",e[c],c);break;case"splice":t=Math.min(Math.max(0,0>o[0]?l+o[0]:o[0]),l);for(var l=1===u?l:Math.min(t+(o[1]||0),l),u=t+u-2,c=Math.max(l,u),h=[],p=[],m=2;c>t;++t,++m)l>t&&p.push(a("deleted",e[t],t)),u>t&&h.push(a("added",o[m],t));d.a.wb(p,h);break;default:return}i=s}}}},d.s=d.j=function(t,r,i){function n(){d.a.G(b,function(e,t){t.K()}),b={}}function o(){n(),x=0,v=!0,p=!1}function a(){var e=l.throttleEvaluation;e&&e>=0?(clearTimeout(P),P=setTimeout(s,e)):l.ib?l.ib():s()}function s(t){if(m){if(g)throw Error("A 'pure' computed must not be called recursively")}else if(!v){if(w&&w()){if(!f)return void T()}else f=!1;if(m=!0,y)try{var i={};d.k.Ea({wa:function(e,t){i[t]||(i[t]=1,++x)},s:l,ma:e}),x=0,h=_.call(r)}finally{d.k.end(),m=!1}else try{var n=b,o=x;d.k.Ea({wa:function(e,t){v||(o&&n[t]?(b[t]=n[t],++x,delete n[t],--o):b[t]||(b[t]=e.U(a),++x))},s:l,ma:g?e:!x}),b={},x=0;try{var s=r?_.call(r):_()}finally{d.k.end(),o&&d.a.G(n,function(e,t){t.K()}),p=!1}l.Pa(h,s)&&(l.notifySubscribers(h,"beforeChange"),h=s,!0!==t&&l.notifySubscribers(h))}finally{m=!1}x||T()}}function l(){if(0<arguments.length){if("function"!=typeof C)throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return C.apply(r,arguments),this}return d.k.Jb(l),p&&s(!0),h}function u(){return p&&!x&&s(!0),h}function c(){return p||x>0}var h,p=!0,m=!1,f=!1,v=!1,_=t,g=!1,y=!1;if(_&&"object"==typeof _?(i=_,_=i.read):(i=i||{},_||(_=i.read)),"function"!=typeof _)throw Error("Pass a function that returns the value of the ko.computed");var C=i.write,E=i.disposeWhenNodeIsRemoved||i.o||null,S=i.disposeWhen||i.Ia,w=S,T=o,b={},x=0,P=null;r||(r=i.owner),d.P.call(l),d.a.Aa(l,d.j.fn),l.v=u,l.la=function(){return x},l.hc="function"==typeof i.write,l.K=function(){T()},l.Z=c;var A=l.Ta;return l.Ta=function(e){A.call(l,e),l.ib=function(){l.kb(h),p=!0,l.lb(l)}},i.pure?(y=g=!0,l.va=function(){y&&(y=!1,s(!0))},l.nb=function(){l.yb()||(n(),y=p=!0)}):i.deferEvaluation&&(l.va=function(){u(),delete l.va}),d.A(l,"peek",l.v),d.A(l,"dispose",l.K),d.A(l,"isActive",l.Z),d.A(l,"getDependenciesCount",l.la),E&&(f=!0,E.nodeType&&(w=function(){return!d.a.Ja(E)||S&&S()})),y||i.deferEvaluation||s(),E&&c()&&E.nodeType&&(T=function(){d.a.w.Kb(E,T),o()},d.a.w.da(E,T)),l},d.jc=function(e){return d.Ma(e,d.j)},f=d.p.rc,d.j[f]=d.p,d.j.fn={equalityComparer:l},d.j.fn[f]=d.j,d.a.xa&&d.a.za(d.j.fn,d.P.fn),d.b("dependentObservable",d.j),d.b("computed",d.j),d.b("isComputed",d.jc),d.Ib=function(e,t){return"function"==typeof e?d.s(e,t,{pure:!0}):(e=d.a.extend({},e),e.pure=!0,d.s(e,t))},d.b("pureComputed",d.Ib),function(){function t(n,o,a){if(a=a||new i,n=o(n),"object"!=typeof n||null===n||n===e||n instanceof Date||n instanceof String||n instanceof Number||n instanceof Boolean)return n;var s=n instanceof Array?[]:{};return a.save(n,s),r(n,function(r){var i=o(n[r]);switch(typeof i){case"boolean":case"number":case"string":case"function":s[r]=i;break;case"object":case"undefined":var l=a.get(i);s[r]=l!==e?l:t(i,o,a)}}),s}function r(e,t){if(e instanceof Array){for(var r=0;r<e.length;r++)t(r);"function"==typeof e.toJSON&&t("toJSON")}else for(r in e)t(r)}function i(){this.keys=[],this.hb=[]}d.Qb=function(e){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return t(e,function(e){for(var t=0;d.C(e)&&10>t;t++)e=e();return e})},d.toJSON=function(e,t,r){return e=d.Qb(e),d.a.eb(e,t,r)},i.prototype={save:function(e,t){var r=d.a.m(this.keys,e);r>=0?this.hb[r]=t:(this.keys.push(e),this.hb.push(t))},get:function(t){return t=d.a.m(this.keys,t),t>=0?this.hb[t]:e}}}(),d.b("toJS",d.Qb),d.b("toJSON",d.toJSON),function(){d.i={q:function(t){switch(d.a.t(t)){case"option":return!0===t.__ko__hasDomDataOptionValue__?d.a.e.get(t,d.d.options.Va):7>=d.a.L?t.getAttributeNode("value")&&t.getAttributeNode("value").specified?t.value:t.text:t.value;case"select":return 0<=t.selectedIndex?d.i.q(t.options[t.selectedIndex]):e;default:return t.value}},ca:function(t,r,i){switch(d.a.t(t)){case"option":switch(typeof r){case"string":d.a.e.set(t,d.d.options.Va,e),"__ko__hasDomDataOptionValue__"in t&&delete t.__ko__hasDomDataOptionValue__,t.value=r;break;default:d.a.e.set(t,d.d.options.Va,r),t.__ko__hasDomDataOptionValue__=!0,t.value="number"==typeof r?r:""}break;case"select":(""===r||null===r)&&(r=e);for(var n,o=-1,a=0,s=t.options.length;s>a;++a)if(n=d.i.q(t.options[a]),n==r||""==n&&r===e){o=a;break}(i||o>=0||r===e&&1<t.size)&&(t.selectedIndex=o);break;default:(null===r||r===e)&&(r=""),t.value=r}}}}(),d.b("selectExtensions",d.i),d.b("selectExtensions.readValue",d.i.q),d.b("selectExtensions.writeValue",d.i.ca),d.h=function(){function e(e){e=d.a.cb(e),123===e.charCodeAt(0)&&(e=e.slice(1,-1));var t,r,a=[],s=e.match(i),l=0;if(s){s.push(",");for(var u,c=0;u=s[c];++c){var h=u.charCodeAt(0);if(44===h){if(0>=l){t&&a.push(r?{key:t,value:r.join("")}:{unknown:t}),t=r=l=0;continue}}else if(58===h){if(!r)continue}else if(47===h&&c&&1<u.length)(h=s[c-1].match(n))&&!o[h[0]]&&(e=e.substr(e.indexOf(u)+1),s=e.match(i),s.push(","),c=-1,u="/");else if(40===h||123===h||91===h)++l;else if(41===h||125===h||93===h)--l;else if(!t&&!r){t=34===h||39===h?u.slice(1,-1):u;continue}r?r.push(u):r=[u]}}return a}var t=["true","false","null","undefined"],r=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,i=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),n=/[\])"'A-Za-z0-9_$]+$/,o={"in":1,"return":1,"typeof":1},a={};return{ha:[],V:a,Wa:e,ya:function(i,n){function o(e,i){var n;if(!c){var h=d.getBindingHandler(e);if(h&&h.preprocess&&!(i=h.preprocess(i,e,o)))return;(h=a[e])&&(n=i,0<=d.a.m(t,n)?n=!1:(h=n.match(r),n=null===h?!1:h[1]?"Object("+h[1]+")"+h[2]:n),h=n),h&&l.push("'"+e+"':function(_z){"+n+"=_z}")}u&&(i="function(){return "+i+" }"),s.push("'"+e+"':"+i)}n=n||{};var s=[],l=[],u=n.valueAccessors,c=n.bindingParams,h="string"==typeof i?e(i):i;return d.a.u(h,function(e){o(e.key||e.unknown,e.value)}),l.length&&o("_ko_property_writers","{"+l.join(",")+" }"),s.join(",")},lc:function(e,t){for(var r=0;r<e.length;r++)if(e[r].key==t)return!0;return!1},pa:function(e,t,r,i,n){e&&d.C(e)?!d.Ra(e)||n&&e.v()===i||e(i):(e=t.get("_ko_property_writers"))&&e[r]&&e[r](i)}}}(),d.b("expressionRewriting",d.h),d.b("expressionRewriting.bindingRewriteValidators",d.h.ha),d.b("expressionRewriting.parseObjectLiteral",d.h.Wa),d.b("expressionRewriting.preProcessBindings",d.h.ya),d.b("expressionRewriting._twoWayBindings",d.h.V),d.b("jsonExpressionRewriting",d.h),d.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",d.h.ya),function(){function e(e){return 8==e.nodeType&&a.test(o?e.text:e.nodeValue)}function t(e){return 8==e.nodeType&&s.test(o?e.text:e.nodeValue)}function r(r,i){for(var n=r,o=1,a=[];n=n.nextSibling;){if(t(n)&&(o--,0===o))return a;a.push(n),e(n)&&o++}if(!i)throw Error("Cannot find closing comment tag to match: "+r.nodeValue);return null}function i(e,t){var i=r(e,t);return i?0<i.length?i[i.length-1].nextSibling:e.nextSibling:null}var o=n&&"<!--test-->"===n.createComment("test").text,a=o?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,s=o?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,l={ul:!0,ol:!0};d.f={Q:{},childNodes:function(t){return e(t)?r(t):t.childNodes},ja:function(t){if(e(t)){t=d.f.childNodes(t);for(var r=0,i=t.length;i>r;r++)d.removeNode(t[r])}else d.a.Ka(t)},T:function(t,r){if(e(t)){d.f.ja(t);for(var i=t.nextSibling,n=0,o=r.length;o>n;n++)i.parentNode.insertBefore(r[n],i)}else d.a.T(t,r)},Hb:function(t,r){e(t)?t.parentNode.insertBefore(r,t.nextSibling):t.firstChild?t.insertBefore(r,t.firstChild):t.appendChild(r)},Bb:function(t,r,i){i?e(t)?t.parentNode.insertBefore(r,i.nextSibling):i.nextSibling?t.insertBefore(r,i.nextSibling):t.appendChild(r):d.f.Hb(t,r)},firstChild:function(r){return e(r)?!r.nextSibling||t(r.nextSibling)?null:r.nextSibling:r.firstChild},nextSibling:function(r){return e(r)&&(r=i(r)),r.nextSibling&&t(r.nextSibling)?null:r.nextSibling},gc:e,xc:function(e){return(e=(o?e.text:e.nodeValue).match(a))?e[1]:null},Fb:function(r){if(l[d.a.t(r)]){var n=r.firstChild;if(n)do if(1===n.nodeType){var o;o=n.firstChild;var a=null;if(o)do if(a)a.push(o);else if(e(o)){var s=i(o,!0);s?o=s:a=[o]}else t(o)&&(a=[o]);while(o=o.nextSibling);if(o=a)for(a=n.nextSibling,s=0;s<o.length;s++)a?r.insertBefore(o[s],a):r.appendChild(o[s])}while(n=n.nextSibling)}}}}(),d.b("virtualElements",d.f),d.b("virtualElements.allowedBindings",d.f.Q),d.b("virtualElements.emptyNode",d.f.ja),d.b("virtualElements.insertAfter",d.f.Bb),d.b("virtualElements.prepend",d.f.Hb),d.b("virtualElements.setDomNodeChildren",d.f.T),function(){d.J=function(){this.Yb={}},d.a.extend(d.J.prototype,{nodeHasBindings:function(e){switch(e.nodeType){case 1:return null!=e.getAttribute("data-bind")||d.g.getComponentNameForNode(e);case 8:return d.f.gc(e);default:return!1}},getBindings:function(e,t){var r=this.getBindingsString(e,t),r=r?this.parseBindingsString(r,t,e):null;return d.g.mb(r,e,t,!1)},getBindingAccessors:function(e,t){var r=this.getBindingsString(e,t),r=r?this.parseBindingsString(r,t,e,{valueAccessors:!0}):null;return d.g.mb(r,e,t,!0)},getBindingsString:function(e){switch(e.nodeType){case 1:return e.getAttribute("data-bind");case 8:return d.f.xc(e);default:return null}},parseBindingsString:function(e,t,r,i){try{var n,o=this.Yb,a=e+(i&&i.valueAccessors||"");if(!(n=o[a])){var s,l="with($context){with($data||{}){return{"+d.h.ya(e,i)+"}}}";s=new Function("$context","$element",l),n=o[a]=s}return n(t,r)}catch(u){throw u.message="Unable to parse bindings.\nBindings value: "+e+"\nMessage: "+u.message,u}}}),d.J.instance=new d.J}(),d.b("bindingProvider",d.J),function(){function t(e){return function(){return e}}function r(e){return e()}function n(e){return d.a.na(d.k.B(e),function(t,r){return function(){return e()[r]}})}function o(e,t){return n(this.getBindings.bind(this,e,t))}function s(e,t,r){var i,n=d.f.firstChild(t),o=d.J.instance,a=o.preprocessNode;if(a){for(;i=n;)n=d.f.nextSibling(i),a.call(o,i);n=d.f.firstChild(t)}for(;i=n;)n=d.f.nextSibling(i),l(e,i,r)}function l(e,t,r){var i=!0,n=1===t.nodeType;n&&d.f.Fb(t),(n&&r||d.J.instance.nodeHasBindings(t))&&(i=c(t,null,e,r).shouldBindDescendants),i&&!p[d.a.t(t)]&&s(e,t,!n)}function u(e){var t=[],r={},i=[];return d.a.G(e,function n(o){if(!r[o]){var a=d.getBindingHandler(o);a&&(a.after&&(i.push(o),d.a.u(a.after,function(t){if(e[t]){if(-1!==d.a.m(i,t))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+i.join(", "));n(t)}}),i.length--),t.push({key:o,zb:a})),r[o]=!0}}),t}function c(t,i,n,a){var s=d.a.e.get(t,m);if(!i){if(s)throw Error("You cannot apply bindings multiple times to the same element.");d.a.e.set(t,m,!0)}!s&&a&&d.Ob(t,n);var l;if(i&&"function"!=typeof i)l=i;else{var c=d.J.instance,h=c.getBindingAccessors||o,p=d.j(function(){return(l=i?i(n,t):h.call(c,t,n))&&n.I&&n.I(),l},null,{o:t});l&&p.Z()||(p=null)}var f;if(l){var v=p?function(e){return function(){return r(p()[e])}}:function(e){return l[e]},_=function(){return d.a.na(p?p():l,r)};_.get=function(e){return l[e]&&r(v(e))},_.has=function(e){return e in l},a=u(l),d.a.u(a,function(r){var i=r.zb.init,o=r.zb.update,a=r.key;if(8===t.nodeType&&!d.f.Q[a])throw Error("The binding '"+a+"' cannot be used with virtual elements");try{"function"==typeof i&&d.k.B(function(){var r=i(t,v(a),_,n.$data,n);if(r&&r.controlsDescendantBindings){if(f!==e)throw Error("Multiple bindings ("+f+" and "+a+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");f=a}}),"function"==typeof o&&d.j(function(){o(t,v(a),_,n.$data,n)},null,{o:t})}catch(s){throw s.message='Unable to process binding "'+a+": "+l[a]+'"\nMessage: '+s.message,s}})}return{shouldBindDescendants:f===e}}function h(e){return e&&e instanceof d.N?e:new d.N(e)}d.d={};var p={script:!0};d.getBindingHandler=function(e){return d.d[e]},d.N=function(t,r,i,n){var o,a=this,s="function"==typeof t&&!d.C(t),l=d.j(function(){var e=s?t():t,o=d.a.c(e);return r?(r.I&&r.I(),d.a.extend(a,r),l&&(a.I=l)):(a.$parents=[],a.$root=o,a.ko=d),a.$rawData=e,a.$data=o,i&&(a[i]=o),n&&n(a,r,o),a.$data},null,{Ia:function(){return o&&!d.a.ob(o)},o:!0});l.Z()&&(a.I=l,l.equalityComparer=null,o=[],l.Tb=function(t){o.push(t),d.a.w.da(t,function(t){d.a.ua(o,t),o.length||(l.K(),a.I=l=e)})})},d.N.prototype.createChildContext=function(e,t,r){return new d.N(e,this,t,function(e,t){e.$parentContext=t,e.$parent=t.$data,e.$parents=(t.$parents||[]).slice(0),e.$parents.unshift(e.$parent),r&&r(e)})},d.N.prototype.extend=function(e){return new d.N(this.I||this.$data,this,null,function(t,r){t.$rawData=r.$rawData,d.a.extend(t,"function"==typeof e?e():e)})};var m=d.a.e.F(),f=d.a.e.F();d.Ob=function(e,t){return 2!=arguments.length?d.a.e.get(e,f):(d.a.e.set(e,f,t),void(t.I&&t.I.Tb(e)))},d.ra=function(e,t,r){return 1===e.nodeType&&d.f.Fb(e),c(e,t,h(r),!0)},d.Wb=function(e,r,i){return i=h(i),d.ra(e,"function"==typeof r?n(r.bind(null,i,e)):d.a.na(r,t),i)},d.Ca=function(e,t){1!==t.nodeType&&8!==t.nodeType||s(h(e),t,!0)},d.pb=function(e,t){if(!a&&i.jQuery&&(a=i.jQuery),t&&1!==t.nodeType&&8!==t.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");t=t||i.document.body,l(h(e),t,!0)},d.Ha=function(t){switch(t.nodeType){case 1:case 8:var r=d.Ob(t);if(r)return r;if(t.parentNode)return d.Ha(t.parentNode)}return e},d.$b=function(t){return(t=d.Ha(t))?t.$data:e},d.b("bindingHandlers",d.d),d.b("applyBindings",d.pb),d.b("applyBindingsToDescendants",d.Ca),d.b("applyBindingAccessorsToNode",d.ra),d.b("applyBindingsToNode",d.Wb),d.b("contextFor",d.Ha),d.b("dataFor",d.$b)}(),function(e){function t(t,i){var a,s=n.hasOwnProperty(t)?n[t]:e;s||(s=n[t]=new d.P,r(t,function(e){o[t]=e,delete n[t],a?s.notifySubscribers(e):setTimeout(function(){s.notifySubscribers(e)},0)}),a=!0),s.U(i)}function r(e,t){i("getConfig",[e],function(r){r?i("loadComponent",[e,r],function(e){t(e)}):t(null)})}function i(t,r,n,o){o||(o=d.g.loaders.slice(0));var a=o.shift();if(a){var s=a[t];if(s){var l=!1;if(s.apply(a,r.concat(function(e){l?n(null):null!==e?n(e):i(t,r,n,o)}))!==e&&(l=!0,!a.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.")}else i(t,r,n,o)}else n(null)}var n={},o={};d.g={get:function(r,i){var n=o.hasOwnProperty(r)?o[r]:e;n?setTimeout(function(){i(n)},0):t(r,i)},tb:function(e){delete o[e]},jb:i},d.g.loaders=[],d.b("components",d.g),d.b("components.get",d.g.get),d.b("components.clearCachedDefinition",d.g.tb)}(),function(){function e(e,t,r,i){function n(){0===--a&&i(o)}var o={},a=2,l=r.template;r=r.viewModel,l?s(t,l,function(t){d.g.jb("loadTemplate",[e,t],function(e){o.template=e,n()})}):n(),r?s(t,r,function(t){d.g.jb("loadViewModel",[e,t],function(e){o[c]=e,n()})}):n()}function t(e,r,i){if("function"==typeof r)i(function(e){return new r(e)});else if("function"==typeof r[c])i(r[c]);else if("instance"in r){var n=r.instance;i(function(){return n})}else"viewModel"in r?t(e,r.viewModel,i):e("Unknown viewModel value: "+r)}function o(e){switch(d.a.t(e)){case"script":return d.a.ba(e.text);case"textarea":return d.a.ba(e.value);case"template":if(a(e.content))return d.a.ia(e.content.childNodes)}return d.a.ia(e.childNodes)}function a(e){return i.DocumentFragment?e instanceof DocumentFragment:e&&11===e.nodeType}function s(e,t,n){"string"==typeof t.require?r||i.require?(r||i.require)([t.require],n):e("Uses require, but no AMD loader is present"):n(t)}function l(e){return function(t){throw Error("Component '"+e+"': "+t)}}var u={};d.g.tc=function(e,t){if(!t)throw Error("Invalid configuration for "+e);if(d.g.Qa(e))throw Error("Component "+e+" is already registered");u[e]=t},d.g.Qa=function(e){return e in u},d.g.wc=function(e){delete u[e],d.g.tb(e)},d.g.ub={getConfig:function(e,t){t(u.hasOwnProperty(e)?u[e]:null)},loadComponent:function(t,r,i){var n=l(t);s(n,r,function(r){e(t,n,r,i)})},loadTemplate:function(e,t,r){if(e=l(e),"string"==typeof t)r(d.a.ba(t));else if(t instanceof Array)r(t);else if(a(t))r(d.a.S(t.childNodes));else if(t.element)if(t=t.element,i.HTMLElement?t instanceof HTMLElement:t&&t.tagName&&1===t.nodeType)r(o(t));else if("string"==typeof t){var s=n.getElementById(t);s?r(o(s)):e("Cannot find element with ID "+t)}else e("Unknown element type: "+t);else e("Unknown template value: "+t)},loadViewModel:function(e,r,i){t(l(e),r,i)}};var c="createViewModel";d.b("components.register",d.g.tc),d.b("components.isRegistered",d.g.Qa),d.b("components.unregister",d.g.wc),d.b("components.defaultLoader",d.g.ub),d.g.loaders.push(d.g.ub),d.g.Ub=u}(),function(){function e(e,r){var i=e.getAttribute("params");if(i){var i=t.parseBindingsString(i,r,e,{valueAccessors:!0,bindingParams:!0}),i=d.a.na(i,function(t){return d.s(t,null,{o:e})}),n=d.a.na(i,function(t){return t.Z()?d.s(function(){return d.a.c(t())},null,{o:e}):t.v()});return n.hasOwnProperty("$raw")||(n.$raw=i),n}return{$raw:{}}}d.g.getComponentNameForNode=function(e){return e=d.a.t(e),d.g.Qa(e)&&e},d.g.mb=function(t,r,i,n){if(1===r.nodeType){var o=d.g.getComponentNameForNode(r);if(o){if(t=t||{},t.component)throw Error('Cannot use the "component" binding on a custom element matching a component');var a={name:o,params:e(r,i)};t.component=n?function(){return a}:a}}return t};var t=new d.J;9>d.a.L&&(d.g.register=function(e){return function(t){return n.createElement(t),e.apply(this,arguments)}}(d.g.register),n.createDocumentFragment=function(e){return function(){var t,r=e(),i=d.g.Ub;for(t in i)i.hasOwnProperty(t)&&r.createElement(t);return r}}(n.createDocumentFragment))}(),function(){var e=0;d.d.component={init:function(t,r,i,n,o){function a(){var e=s&&s.dispose;"function"==typeof e&&e.call(s),l=null}var s,l;return d.a.w.da(t,a),d.s(function(){var i,n,u=d.a.c(r());if("string"==typeof u?i=u:(i=d.a.c(u.name),n=d.a.c(u.params)),!i)throw Error("No component name specified");var c=l=++e;d.g.get(i,function(e){if(l===c){if(a(),!e)throw Error("Unknown component '"+i+"'");var r=e.template;if(!r)throw Error("Component '"+i+"' has no template");r=d.a.ia(r),d.f.T(t,r);var r=n,u=e.createViewModel;e=u?u.call(e,r,{element:t}):r,r=o.createChildContext(e),s=e,d.Ca(r,t)}})},null,{o:t}),{controlsDescendantBindings:!0}}},d.f.Q.component=!0}();var g={"class":"className","for":"htmlFor"};d.d.attr={update:function(t,r){var i=d.a.c(r())||{};d.a.G(i,function(r,i){i=d.a.c(i);var n=!1===i||null===i||i===e;n&&t.removeAttribute(r),8>=d.a.L&&r in g?(r=g[r],n?t.removeAttribute(r):t[r]=i):n||t.setAttribute(r,i.toString()),"name"===r&&d.a.Mb(t,n?"":i.toString())})}},function(){d.d.checked={after:["value","attr"],init:function(t,r,i){function n(){var e=t.checked,n=h?a():e;if(!d.Y.ma()&&(!l||e)){var o=d.k.B(r);u?c!==n?(e&&(d.a.ea(o,n,!0),d.a.ea(o,c,!1)),c=n):d.a.ea(o,n,e):d.h.pa(o,i,"checked",n,!0)}}function o(){var e=d.a.c(r());t.checked=u?0<=d.a.m(e,a()):s?e:a()===e}var a=d.Ib(function(){return i.has("checkedValue")?d.a.c(i.get("checkedValue")):i.has("value")?d.a.c(i.get("value")):t.value}),s="checkbox"==t.type,l="radio"==t.type;if(s||l){var u=s&&d.a.c(r())instanceof Array,c=u?a():e,h=l||u;l&&!t.name&&d.d.uniqueName.init(t,function(){return!0}),d.s(n,null,{o:t}),d.a.n(t,"click",n),d.s(o,null,{o:t})}}},d.h.V.checked=!0,d.d.checkedValue={update:function(e,t){e.value=d.a.c(t())}}}(),d.d.css={update:function(e,t){var r=d.a.c(t());"object"==typeof r?d.a.G(r,function(t,r){r=d.a.c(r),d.a.Ba(e,t,r)}):(r=String(r||""),d.a.Ba(e,e.__ko__cssValue,!1),e.__ko__cssValue=r,d.a.Ba(e,r,!0))}},d.d.enable={update:function(e,t){var r=d.a.c(t());r&&e.disabled?e.removeAttribute("disabled"):r||e.disabled||(e.disabled=!0)}},d.d.disable={update:function(e,t){d.d.enable.update(e,function(){return!d.a.c(t())})}},d.d.event={init:function(e,t,r,i,n){var o=t()||{};d.a.G(o,function(o){"string"==typeof o&&d.a.n(e,o,function(e){var a,s=t()[o];if(s){try{var l=d.a.S(arguments);i=n.$data,l.unshift(i),a=s.apply(i,l)}finally{!0!==a&&(e.preventDefault?e.preventDefault():e.returnValue=!1)}!1===r.get(o+"Bubble")&&(e.cancelBubble=!0,e.stopPropagation&&e.stopPropagation())}})})}},d.d.foreach={Eb:function(e){return function(){var t=e(),r=d.a.Xa(t);return r&&"number"!=typeof r.length?(d.a.c(t),{foreach:r.data,as:r.as,includeDestroyed:r.includeDestroyed,afterAdd:r.afterAdd,beforeRemove:r.beforeRemove,afterRender:r.afterRender,beforeMove:r.beforeMove,afterMove:r.afterMove,templateEngine:d.O.Oa}):{foreach:t,templateEngine:d.O.Oa}}},init:function(e,t){return d.d.template.init(e,d.d.foreach.Eb(t))},update:function(e,t,r,i,n){return d.d.template.update(e,d.d.foreach.Eb(t),r,i,n)}},d.h.ha.foreach=!1,d.f.Q.foreach=!0,d.d.hasfocus={init:function(e,t,r){function i(i){e.__ko_hasfocusUpdating=!0;var n=e.ownerDocument;if("activeElement"in n){var o;try{o=n.activeElement}catch(a){o=n.body}i=o===e}n=t(),d.h.pa(n,r,"hasfocus",i,!0),e.__ko_hasfocusLastValue=i,e.__ko_hasfocusUpdating=!1}var n=i.bind(null,!0),o=i.bind(null,!1);d.a.n(e,"focus",n),d.a.n(e,"focusin",n),d.a.n(e,"blur",o),d.a.n(e,"focusout",o)},update:function(e,t){var r=!!d.a.c(t());e.__ko_hasfocusUpdating||e.__ko_hasfocusLastValue===r||(r?e.focus():e.blur(),d.k.B(d.a.oa,null,[e,r?"focusin":"focusout"]))}},d.h.V.hasfocus=!0,d.d.hasFocus=d.d.hasfocus,d.h.V.hasFocus=!0,d.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(e,t){d.a.$a(e,t())}},h("if"),h("ifnot",!1,!0),h("with",!0,!1,function(e,t){return e.createChildContext(t)});var y={};d.d.options={init:function(e){if("select"!==d.a.t(e))throw Error("options binding applies only to SELECT elements");for(;0<e.length;)e.remove(0);return{controlsDescendantBindings:!0}},update:function(t,r,i){function n(){return d.a.ta(t.options,function(e){return e.selected})}function o(e,t,r){var i=typeof t;return"function"==i?t(e):"string"==i?e[t]:r}function a(e,r){if(h.length){var i=0<=d.a.m(h,d.i.q(r[0]));d.a.Nb(r[0],i),p&&!i&&d.k.B(d.a.oa,null,[t,"change"])}}var s=0!=t.length&&t.multiple?t.scrollTop:null,l=d.a.c(r()),u=i.get("optionsIncludeDestroyed");r={};var c,h;h=t.multiple?d.a.Da(n(),d.i.q):0<=t.selectedIndex?[d.i.q(t.options[t.selectedIndex])]:[],l&&("undefined"==typeof l.length&&(l=[l]),c=d.a.ta(l,function(t){return u||t===e||null===t||!d.a.c(t._destroy)}),i.has("optionsCaption")&&(l=d.a.c(i.get("optionsCaption")),null!==l&&l!==e&&c.unshift(y)));var p=!1;r.beforeRemove=function(e){t.removeChild(e)},l=a,i.has("optionsAfterRender")&&(l=function(t,r){a(0,r),d.k.B(i.get("optionsAfterRender"),null,[r[0],t!==y?t:e])}),d.a.Za(t,c,function(r,n,a){return a.length&&(h=a[0].selected?[d.i.q(a[0])]:[],p=!0),n=t.ownerDocument.createElement("option"),r===y?(d.a.bb(n,i.get("optionsCaption")),d.i.ca(n,e)):(a=o(r,i.get("optionsValue"),r),d.i.ca(n,d.a.c(a)),r=o(r,i.get("optionsText"),a),d.a.bb(n,r)),[n]},r,l),d.k.B(function(){i.get("valueAllowUnset")&&i.has("value")?d.i.ca(t,d.a.c(i.get("value")),!0):(t.multiple?h.length&&n().length<h.length:h.length&&0<=t.selectedIndex?d.i.q(t.options[t.selectedIndex])!==h[0]:h.length||0<=t.selectedIndex)&&d.a.oa(t,"change")}),d.a.dc(t),s&&20<Math.abs(s-t.scrollTop)&&(t.scrollTop=s)}},d.d.options.Va=d.a.e.F(),d.d.selectedOptions={after:["options","foreach"],init:function(e,t,r){d.a.n(e,"change",function(){var i=t(),n=[];d.a.u(e.getElementsByTagName("option"),function(e){e.selected&&n.push(d.i.q(e))}),d.h.pa(i,r,"selectedOptions",n)})},update:function(e,t){if("select"!=d.a.t(e))throw Error("values binding applies only to SELECT elements");var r=d.a.c(t());r&&"number"==typeof r.length&&d.a.u(e.getElementsByTagName("option"),function(e){var t=0<=d.a.m(r,d.i.q(e));d.a.Nb(e,t)})}},d.h.V.selectedOptions=!0,d.d.style={update:function(t,r){var i=d.a.c(r()||{});d.a.G(i,function(r,i){i=d.a.c(i),(null===i||i===e||!1===i)&&(i=""),t.style[r]=i})}},d.d.submit={init:function(e,t,r,i,n){if("function"!=typeof t())throw Error("The value for a submit binding must be a function");d.a.n(e,"submit",function(r){var i,o=t();try{i=o.call(n.$data,e)}finally{!0!==i&&(r.preventDefault?r.preventDefault():r.returnValue=!1)}})}},d.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(e,t){d.a.bb(e,t())}},d.f.Q.text=!0,function(){if(i&&i.navigator)var t=function(e){return e?parseFloat(e[1]):void 0},r=i.opera&&i.opera.version&&parseInt(i.opera.version()),n=i.navigator.userAgent,o=t(n.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),a=t(n.match(/Firefox\/([^ ]*)/)); +if(10>d.a.L)var s=d.a.e.F(),l=d.a.e.F(),u=function(e){var t=this.activeElement;(t=t&&d.a.e.get(t,l))&&t(e)},c=function(e,t){var r=e.ownerDocument;d.a.e.get(r,s)||(d.a.e.set(r,s,!0),d.a.n(r,"selectionchange",u)),d.a.e.set(e,l,t)};d.d.textInput={init:function(t,i,n){function s(e,r){d.a.n(t,e,r)}function l(){var r=d.a.c(i());(null===r||r===e)&&(r=""),m!==e&&r===m?setTimeout(l,4):t.value!==r&&(f=r,t.value=r)}function u(){p||(m=t.value,p=setTimeout(h,4))}function h(){clearTimeout(p),m=p=e;var r=t.value;f!==r&&(f=r,d.h.pa(i(),n,"textInput",r))}var p,m,f=t.value;10>d.a.L?(s("propertychange",function(e){"value"===e.propertyName&&h()}),8==d.a.L&&(s("keyup",h),s("keydown",h)),8<=d.a.L&&(c(t,h),s("dragend",u))):(s("input",h),5>o&&"textarea"===d.a.t(t)?(s("keydown",u),s("paste",u),s("cut",u)):11>r?s("keydown",u):4>a&&(s("DOMAutoComplete",h),s("dragdrop",h),s("drop",h))),s("change",h),d.s(l,null,{o:t})}},d.h.V.textInput=!0,d.d.textinput={preprocess:function(e,t,r){r("textInput",e)}}}(),d.d.uniqueName={init:function(e,t){if(t()){var r="ko_unique_"+ ++d.d.uniqueName.Zb;d.a.Mb(e,r)}}},d.d.uniqueName.Zb=0,d.d.value={after:["options","foreach"],init:function(e,t,r){if("input"!=e.tagName.toLowerCase()||"checkbox"!=e.type&&"radio"!=e.type){var i=["change"],n=r.get("valueUpdate"),o=!1,a=null;n&&("string"==typeof n&&(n=[n]),d.a.ga(i,n),i=d.a.rb(i));var s=function(){a=null,o=!1;var i=t(),n=d.i.q(e);d.h.pa(i,r,"value",n)};!d.a.L||"input"!=e.tagName.toLowerCase()||"text"!=e.type||"off"==e.autocomplete||e.form&&"off"==e.form.autocomplete||-1!=d.a.m(i,"propertychange")||(d.a.n(e,"propertychange",function(){o=!0}),d.a.n(e,"focus",function(){o=!1}),d.a.n(e,"blur",function(){o&&s()})),d.a.u(i,function(t){var r=s;d.a.vc(t,"after")&&(r=function(){a=d.i.q(e),setTimeout(s,0)},t=t.substring(5)),d.a.n(e,t,r)});var l=function(){var i=d.a.c(t()),n=d.i.q(e);if(null!==a&&i===a)setTimeout(l,0);else if(i!==n)if("select"===d.a.t(e)){var o=r.get("valueAllowUnset"),n=function(){d.i.ca(e,i,o)};n(),o||i===d.i.q(e)?setTimeout(n,0):d.k.B(d.a.oa,null,[e,"change"])}else d.i.ca(e,i)};d.s(l,null,{o:e})}else d.ra(e,{checkedValue:t})},update:function(){}},d.h.V.value=!0,d.d.visible={update:function(e,t){var r=d.a.c(t()),i="none"!=e.style.display;r&&!i?e.style.display="":!r&&i&&(e.style.display="none")}},function(e){d.d[e]={init:function(t,r,i,n,o){return d.d.event.init.call(this,t,function(){var t={};return t[e]=r(),t},i,n,o)}}}("click"),d.H=function(){},d.H.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource")},d.H.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock")},d.H.prototype.makeTemplateSource=function(e,t){if("string"==typeof e){t=t||n;var r=t.getElementById(e);if(!r)throw Error("Cannot find template with ID "+e);return new d.r.l(r)}if(1==e.nodeType||8==e.nodeType)return new d.r.fa(e);throw Error("Unknown template type: "+e)},d.H.prototype.renderTemplate=function(e,t,r,i){return e=this.makeTemplateSource(e,i),this.renderTemplateSource(e,t,r)},d.H.prototype.isTemplateRewritten=function(e,t){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(e,t).data("isRewritten")},d.H.prototype.rewriteTemplate=function(e,t,r){e=this.makeTemplateSource(e,r),t=t(e.text()),e.text(t),e.data("isRewritten",!0)},d.b("templateEngine",d.H),d.fb=function(){function e(e,t,r,i){e=d.h.Wa(e);for(var n=d.h.ha,o=0;o<e.length;o++){var a=e[o].key;if(n.hasOwnProperty(a)){var s=n[a];if("function"==typeof s){if(a=s(e[o].value))throw Error(a)}else if(!s)throw Error("This template engine does not support the '"+a+"' binding within its templates")}}return r="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+d.h.ya(e,{valueAccessors:!0})+" } })()},'"+r.toLowerCase()+"')",i.createJavaScriptEvaluatorBlock(r)+t}var t=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,r=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{ec:function(e,t,r){t.isTemplateRewritten(e,r)||t.rewriteTemplate(e,function(e){return d.fb.nc(e,t)},r)},nc:function(i,n){return i.replace(t,function(t,r,i,o,a){return e(a,r,i,n)}).replace(r,function(t,r){return e(r,"<!-- ko -->","#comment",n)})},Xb:function(e,t){return d.D.Ua(function(r,i){var n=r.nextSibling;n&&n.nodeName.toLowerCase()===t&&d.ra(n,e,i)})}}}(),d.b("__tr_ambtns",d.fb.Xb),function(){d.r={},d.r.l=function(e){this.l=e},d.r.l.prototype.text=function(){var e=d.a.t(this.l),e="script"===e?"text":"textarea"===e?"value":"innerHTML";if(0==arguments.length)return this.l[e];var t=arguments[0];"innerHTML"===e?d.a.$a(this.l,t):this.l[e]=t};var t=d.a.e.F()+"_";d.r.l.prototype.data=function(e){return 1===arguments.length?d.a.e.get(this.l,t+e):void d.a.e.set(this.l,t+e,arguments[1])};var r=d.a.e.F();d.r.fa=function(e){this.l=e},d.r.fa.prototype=new d.r.l,d.r.fa.prototype.text=function(){if(0==arguments.length){var t=d.a.e.get(this.l,r)||{};return t.gb===e&&t.Ga&&(t.gb=t.Ga.innerHTML),t.gb}d.a.e.set(this.l,r,{gb:arguments[0]})},d.r.l.prototype.nodes=function(){return 0==arguments.length?(d.a.e.get(this.l,r)||{}).Ga:void d.a.e.set(this.l,r,{Ga:arguments[0]})},d.b("templateSources",d.r),d.b("templateSources.domElement",d.r.l),d.b("templateSources.anonymousTemplate",d.r.fa)}(),function(){function t(e,t,r){var i;for(t=d.f.nextSibling(t);e&&(i=e)!==t;)e=d.f.nextSibling(i),r(i,e)}function r(e,r){if(e.length){var i=e[0],n=e[e.length-1],o=i.parentNode,a=d.J.instance,s=a.preprocessNode;if(s){if(t(i,n,function(e,t){var r=e.previousSibling,o=s.call(a,e);o&&(e===i&&(i=o[0]||t),e===n&&(n=o[o.length-1]||r))}),e.length=0,!i)return;i===n?e.push(i):(e.push(i,n),d.a.ka(e,o))}t(i,n,function(e){1!==e.nodeType&&8!==e.nodeType||d.pb(r,e)}),t(i,n,function(e){1!==e.nodeType&&8!==e.nodeType||d.D.Sb(e,[r])}),d.a.ka(e,o)}}function i(e){return e.nodeType?e:0<e.length?e[0]:null}function n(e,t,n,a,s){s=s||{};var l=e&&i(e),l=l&&l.ownerDocument,u=s.templateEngine||o;if(d.fb.ec(n,u,l),n=u.renderTemplate(n,a,s,l),"number"!=typeof n.length||0<n.length&&"number"!=typeof n[0].nodeType)throw Error("Template engine must return an array of DOM nodes");switch(l=!1,t){case"replaceChildren":d.f.T(e,n),l=!0;break;case"replaceNode":d.a.Lb(e,n),l=!0;break;case"ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+t)}return l&&(r(n,a),s.afterRender&&d.k.B(s.afterRender,null,[n,a.$data])),n}var o;d.ab=function(t){if(t!=e&&!(t instanceof d.H))throw Error("templateEngine must inherit from ko.templateEngine");o=t},d.Ya=function(t,r,a,s,l){if(a=a||{},(a.templateEngine||o)==e)throw Error("Set a template engine before calling renderTemplate");if(l=l||"replaceChildren",s){var u=i(s);return d.j(function(){var e=r&&r instanceof d.N?r:new d.N(d.a.c(r)),o=d.C(t)?t():"function"==typeof t?t(e.$data,e):t,e=n(s,l,o,e,a);"replaceNode"==l&&(s=e,u=i(s))},null,{Ia:function(){return!u||!d.a.Ja(u)},o:u&&"replaceNode"==l?u.parentNode:u})}return d.D.Ua(function(e){d.Ya(t,r,a,e,"replaceNode")})},d.uc=function(t,i,o,a,s){function l(e,t){r(t,c),o.afterRender&&o.afterRender(t,e)}function u(e,r){c=s.createChildContext(e,o.as,function(e){e.$index=r});var i=d.C(t)?t():"function"==typeof t?t(e,c):t;return n(null,"ignoreTargetNode",i,c,o)}var c;return d.j(function(){var t=d.a.c(i)||[];"undefined"==typeof t.length&&(t=[t]),t=d.a.ta(t,function(t){return o.includeDestroyed||t===e||null===t||!d.a.c(t._destroy)}),d.k.B(d.a.Za,null,[a,t,u,o,l])},null,{o:a})};var a=d.a.e.F();d.d.template={init:function(e,t){var r=d.a.c(t());return"string"==typeof r||r.name?d.f.ja(e):(r=d.f.childNodes(e),r=d.a.oc(r),new d.r.fa(e).nodes(r)),{controlsDescendantBindings:!0}},update:function(t,r,i,n,o){var s,l=r();r=d.a.c(l),i=!0,n=null,"string"==typeof r?r={}:(l=r.name,"if"in r&&(i=d.a.c(r["if"])),i&&"ifnot"in r&&(i=!d.a.c(r.ifnot)),s=d.a.c(r.data)),"foreach"in r?n=d.uc(l||t,i&&r.foreach||[],r,t,o):i?(o="data"in r?o.createChildContext(s,r.as):o,n=d.Ya(l||t,o,r,t)):d.f.ja(t),o=n,(s=d.a.e.get(t,a))&&"function"==typeof s.K&&s.K(),d.a.e.set(t,a,o&&o.Z()?o:e)}},d.h.ha.template=function(e){return e=d.h.Wa(e),1==e.length&&e[0].unknown||d.h.lc(e,"name")?null:"This template engine does not support anonymous templates nested within its templates"},d.f.Q.template=!0}(),d.b("setTemplateEngine",d.ab),d.b("renderTemplate",d.Ya),d.a.wb=function(e,t,r){if(e.length&&t.length){var i,n,o,a,s;for(i=n=0;(!r||r>i)&&(a=e[n]);++n){for(o=0;s=t[o];++o)if(a.value===s.value){a.moved=s.index,s.moved=a.index,t.splice(o,1),i=o=0;break}i+=o}}},d.a.Fa=function(){function e(e,t,r,i,n){var o,a,s,l,u,c=Math.min,h=Math.max,p=[],m=e.length,f=t.length,v=f-m||1,_=m+f+1;for(o=0;m>=o;o++)for(l=s,p.push(s=[]),u=c(f,o+v),a=h(0,o-1);u>=a;a++)s[a]=a?o?e[o-1]===t[a-1]?l[a-1]:c(l[a]||_,s[a-1]||_)+1:a+1:o+1;for(c=[],h=[],v=[],o=m,a=f;o||a;)f=p[o][a]-1,a&&f===p[o][a-1]?h.push(c[c.length]={status:r,value:t[--a],index:a}):o&&f===p[o-1][a]?v.push(c[c.length]={status:i,value:e[--o],index:o}):(--a,--o,n.sparse||c.push({status:"retained",value:t[a]}));return d.a.wb(h,v,10*m),c.reverse()}return function(t,r,i){return i="boolean"==typeof i?{dontLimitMoves:i}:i||{},t=t||[],r=r||[],t.length<=r.length?e(t,r,"added","deleted",i):e(r,t,"deleted","added",i)}}(),d.b("utils.compareArrays",d.a.Fa),function(){function t(t,r,i,n,o){var a=[],s=d.j(function(){var e=r(i,o,d.a.ka(a,t))||[];0<a.length&&(d.a.Lb(a,e),n&&d.k.B(n,null,[i,e,o])),a.length=0,d.a.ga(a,e)},null,{o:t,Ia:function(){return!d.a.ob(a)}});return{$:a,j:s.Z()?s:e}}var r=d.a.e.F();d.a.Za=function(i,n,o,a,s){function l(e,t){C=h[t],_!==t&&(w[e]=C),C.Na(_++),d.a.ka(C.$,i),f.push(C),y.push(C)}function u(e,t){if(e)for(var r=0,i=t.length;i>r;r++)t[r]&&d.a.u(t[r].$,function(i){e(i,r,t[r].sa)})}n=n||[],a=a||{};var c=d.a.e.get(i,r)===e,h=d.a.e.get(i,r)||[],p=d.a.Da(h,function(e){return e.sa}),m=d.a.Fa(p,n,a.dontLimitMoves),f=[],v=0,_=0,g=[],y=[];n=[];for(var C,E,S,w=[],p=[],T=0;E=m[T];T++)switch(S=E.moved,E.status){case"deleted":S===e&&(C=h[v],C.j&&C.j.K(),g.push.apply(g,d.a.ka(C.$,i)),a.beforeRemove&&(n[T]=C,y.push(C))),v++;break;case"retained":l(T,v++);break;case"added":S!==e?l(T,S):(C={sa:E.value,Na:d.p(_++)},f.push(C),y.push(C),c||(p[T]=C))}u(a.beforeMove,w),d.a.u(g,a.beforeRemove?d.R:d.removeNode);for(var b,T=0,c=d.f.firstChild(i);C=y[T];T++){for(C.$||d.a.extend(C,t(i,o,C.sa,s,C.Na)),v=0;m=C.$[v];c=m.nextSibling,b=m,v++)m!==c&&d.f.Bb(i,m,b);!C.ic&&s&&(s(C.sa,C.$,C.Na),C.ic=!0)}u(a.beforeRemove,n),u(a.afterMove,w),u(a.afterAdd,p),d.a.e.set(i,r,f)}}(),d.b("utils.setDomNodeChildrenFromArrayMapping",d.a.Za),d.O=function(){this.allowTemplateRewriting=!1},d.O.prototype=new d.H,d.O.prototype.renderTemplateSource=function(e){var t=(9>d.a.L?0:e.nodes)?e.nodes():null;return t?d.a.S(t.cloneNode(!0).childNodes):(e=e.text(),d.a.ba(e))},d.O.Oa=new d.O,d.ab(d.O.Oa),d.b("nativeTemplateEngine",d.O),function(){d.Sa=function(){var e=this.kc=function(){if(!a||!a.tmpl)return 0;try{if(0<=a.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(e){}return 1}();this.renderTemplateSource=function(t,r,i){if(i=i||{},2>e)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var o=t.data("precompiled");return o||(o=t.text()||"",o=a.template(null,"{{ko_with $item.koBindingContext}}"+o+"{{/ko_with}}"),t.data("precompiled",o)),t=[r.$data],r=a.extend({koBindingContext:r},i.templateOptions),r=a.tmpl(o,t,r),r.appendTo(n.createElement("div")),a.fragments={},r},this.createJavaScriptEvaluatorBlock=function(e){return"{{ko_code ((function() { return "+e+" })()) }}"},this.addTemplate=function(e,t){n.write("<script type='text/html' id='"+e+"'>"+t+"</script>")},e>0&&(a.tmpl.tag.ko_code={open:"__.push($1 || '');"},a.tmpl.tag.ko_with={open:"with($1) {",close:"} "})},d.Sa.prototype=new d.H;var e=new d.Sa;0<e.kc&&d.ab(e),d.b("jqueryTmplTemplateEngine",d.Sa)}()})}()}(),r("ThirdParty/knockout-es5",[],function(){"use strict";function e(e,r){if(!e)throw new Error("When calling ko.track, you must pass an object as the first parameter.");var n=this,o=t(e,!0);return r=r||Object.getOwnPropertyNames(e),r.forEach(function(t){if(t!==h&&t!==d&&!(t in o)){var r=e[t],a=r instanceof Array,s=n.isObservable(r)?r:a?n.observableArray(r):n.observable(r);Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:s,set:n.isWriteableObservable(s)?s:void 0}),o[t]=s,a&&i(n,s)}}),e}function t(e,t){var r=e[h];return!r&&t&&(r={},Object.defineProperty(e,h,{value:r})),r}function r(t,r,i){var n=this,o={owner:t,deferEvaluation:!0};if("function"==typeof i)o.read=i;else{if("value"in i)throw new Error('For ko.defineProperty, you must not specify a "value" for the property. You must provide a "get" function.');if("function"!=typeof i.get)throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, or an options object containing a function called "get".');o.read=i.get,o.write=i.set}return t[r]=n.computed(o),e.call(n,t,[r]),t}function i(e,t){var r=null;e.computed(function(){r&&(r.dispose(),r=null);var i=t();i instanceof Array&&(r=n(e,t,i))})}function n(e,t,r){var i=o(e,r);return i.subscribe(t)}function o(e,t){var r=t[d];if(!r){r=new e.subscribable,Object.defineProperty(t,d,{value:r});var i={};a(t,r,i),s(e,t,r,i)}return r}function a(e,t,r){["pop","push","reverse","shift","sort","splice","unshift"].forEach(function(i){var n=e[i];e[i]=function(){var e=n.apply(this,arguments);return r.pause!==!0&&t.notifySubscribers(this),e}})}function s(e,t,r,i){["remove","removeAll","destroy","destroyAll","replace"].forEach(function(n){Object.defineProperty(t,n,{enumerable:!1,value:function(){var o;i.pause=!0;try{o=e.observableArray.fn[n].apply(e.observableArray(t),arguments)}finally{i.pause=!1}return r.notifySubscribers(t),o}})})}function l(e,r){if(!e)return null;var i=t(e,!1);return i&&i[r]||null}function u(e,t){var r=l(e,t);r&&r.valueHasMutated()}function c(t){t.track=e,t.getObservable=l,t.valueHasMutated=u,t.defineProperty=r}var h="__knockoutObservables",d="__knockoutSubscribable";return{attachToKo:c}}),r("Widgets/SvgPathBindingHandler",[],function(){"use strict";var e="http://www.w3.org/2000/svg",t="cesium-svgPath-svg",r={register:function(r){r.bindingHandlers.cesiumSvgPath={init:function(i,n){var o=document.createElementNS(e,"svg:svg");o.setAttribute("class",t);var a=document.createElementNS(e,"path");return o.appendChild(a),r.virtualElements.setDomNodeChildren(i,[o]),r.computed({read:function(){var e=r.unwrap(n());a.setAttribute("d",r.unwrap(e.path));var i=r.unwrap(e.width),s=r.unwrap(e.height);o.setAttribute("width",i),o.setAttribute("height",s),o.setAttribute("viewBox","0 0 "+i+" "+s),e.css&&o.setAttribute("class",t+" "+r.unwrap(e.css))},disposeWhenNodeIsRemoved:i}),{controlsDescendantBindings:!0}}},r.virtualElements.allowedBindings.cesiumSvgPath=!0}};return r}),r("ThirdParty/knockout",["./knockout-3.2.0","./knockout-es5","../Widgets/SvgPathBindingHandler"],function(e,t,r){"use strict";return t.attachToKo(e),r.register(e),e}),r("Widgets/subscribeAndEvaluate",["../ThirdParty/knockout"],function(e){"use strict";var t=function(t,r,i,n,o){return i.call(n,t[r]),e.getObservable(t,r).subscribe(i,n,o)};return t}),r("Widgets/Animation/Animation",["../../Core/Color","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../getElement","../subscribeAndEvaluate"],function(e,t,r,i,n,o,a){"use strict";function s(t){return e.fromCssColorString(window.getComputedStyle(t).getPropertyValue("color"))}function l(e){var t=document.createElementNS(v,e.tagName);for(var r in e)if(e.hasOwnProperty(r)&&"tagName"!==r)if("children"===r){var i,n=e.children.length;for(i=0;n>i;++i)t.appendChild(l(e.children[i]))}else 0===r.indexOf("xlink:")?t.setAttributeNS(_,r.substring(6),e[r]):"textContent"===r?t.textContent=e[r]:t.setAttribute(r,e[r]);return t}function u(e,t,r){var i=document.createElementNS(v,"text");i.setAttribute("x",e),i.setAttribute("y",t),i.setAttribute("class","cesium-animation-svgText");var n=document.createElementNS(v,"tspan");return n.textContent=r,i.appendChild(n),i}function c(e,t,r){e.setAttribute("transform","translate(100,100) rotate("+r+")"),t.setAttribute("transform","rotate("+r+")")}function h(e,t){var r=t.alpha,i=1-r;return x.red=e.red*i+t.red*r,x.green=e.green*i+t.green*r,x.blue=e.blue*i+t.blue*r,x.toCssColorString()}function d(e,t,r){var i={tagName:"g","class":"cesium-animation-rectButton",transform:"translate("+e+","+t+")",children:[{tagName:"rect","class":"cesium-animation-buttonGlow",width:32,height:32,rx:2,ry:2},{tagName:"rect","class":"cesium-animation-buttonMain",width:32,height:32,rx:4,ry:4},{tagName:"use","class":"cesium-animation-buttonPath","xlink:href":r},{tagName:"title",textContent:""}]};return l(i)}function p(e,t,r){var i={tagName:"g","class":"cesium-animation-rectButton",transform:"translate("+e+","+t+")",children:[{tagName:"use","class":"cesium-animation-buttonGlow","xlink:href":"#animation_pathWingButton"},{tagName:"use","class":"cesium-animation-buttonMain","xlink:href":"#animation_pathWingButton"},{tagName:"use","class":"cesium-animation-buttonPath","xlink:href":r},{tagName:"title",textContent:""}]};return l(i)}function m(e,t){var r=e._viewModel,i=r.shuttleRingDragging;if(!i||f===e)if("mousedown"===t.type||i&&"mousemove"===t.type||"touchstart"===t.type&&1===t.touches.length||i&&"touchmove"===t.type&&1===t.touches.length){var n,o,a=e._centerX,s=e._centerY,l=e._svgNode,u=l.getBoundingClientRect();if("touchstart"===t.type||"touchmove"===t.type?(n=t.touches[0].clientX,o=t.touches[0].clientY):(n=t.clientX,o=t.clientY),!i&&(n>u.right||n<u.left||o<u.top||o>u.bottom))return;var c=e._shuttleRingPointer.getBoundingClientRect(),h=n-a-u.left,d=o-s-u.top,p=180*Math.atan2(d,h)/Math.PI+90;p>180&&(p-=360);var m=r.shuttleRingAngle;i||n<c.right&&n>c.left&&o>c.top&&o<c.bottom?(f=e,r.shuttleRingDragging=!0,r.shuttleRingAngle=p):m>p?r.slower():p>m&&r.faster(),t.preventDefault()}else e===f&&(f=void 0),r.shuttleRingDragging=!1}var f,v="http://www.w3.org/2000/svg",_="http://www.w3.org/1999/xlink",g=e.fromCssColorString("rgba(247,250,255,0.384)"),y=e.fromCssColorString("rgba(143,191,255,0.216)"),C=e.fromCssColorString("rgba(153,197,255,0.098)"),E=e.fromCssColorString("rgba(255,255,255,0.086)"),S=e.fromCssColorString("rgba(255,255,255,0.267)"),w=e.fromCssColorString("rgba(255,255,255,0)"),T=e.fromCssColorString("rgba(66,67,68,0.3)"),b=e.fromCssColorString("rgba(0,0,0,0.5)"),x=new e,P=function(e,t){this._viewModel=t,this.svgElement=e,this._enabled=void 0,this._toggled=void 0;var r=this;this._clickFunction=function(){var e=r._viewModel.command;e.canExecute&&e()},e.addEventListener("click",this._clickFunction,!0),this._subscriptions=[a(t,"toggled",this.setToggled,this),a(t,"tooltip",this.setTooltip,this),a(t.command,"canExecute",this.setEnabled,this)]};P.prototype.destroy=function(){this.svgElement.removeEventListener("click",this._clickFunction,!0);for(var e=this._subscriptions,t=0,r=e.length;r>t;t++)e[t].dispose();i(this)},P.prototype.isDestroyed=function(){return!1},P.prototype.setEnabled=function(e){if(this._enabled!==e){if(this._enabled=e,!e)return void this.svgElement.setAttribute("class","cesium-animation-buttonDisabled");if(this._toggled)return void this.svgElement.setAttribute("class","cesium-animation-rectButton cesium-animation-buttonToggled");this.svgElement.setAttribute("class","cesium-animation-rectButton")}},P.prototype.setToggled=function(e){this._toggled!==e&&(this._toggled=e,this._enabled&&(e?this.svgElement.setAttribute("class","cesium-animation-rectButton cesium-animation-buttonToggled"):this.svgElement.setAttribute("class","cesium-animation-rectButton")))},P.prototype.setTooltip=function(e){this.svgElement.getElementsByTagName("title")[0].textContent=e};var A=function(e,t){e=o(e),this._viewModel=t,this._container=e,this._centerX=0,this._centerY=0,this._defsElement=void 0,this._svgNode=void 0,this._topG=void 0,this._lastHeight=void 0,this._lastWidth=void 0;var r=document.createElement("style");r.textContent=".cesium-animation-rectButton .cesium-animation-buttonGlow { filter: url(#animation_blurred); }.cesium-animation-rectButton .cesium-animation-buttonMain { fill: url(#animation_buttonNormal); }.cesium-animation-buttonToggled .cesium-animation-buttonMain { fill: url(#animation_buttonToggled); }.cesium-animation-rectButton:hover .cesium-animation-buttonMain { fill: url(#animation_buttonHovered); }.cesium-animation-buttonDisabled .cesium-animation-buttonMain { fill: url(#animation_buttonDisabled); }.cesium-animation-shuttleRingG .cesium-animation-shuttleRingSwoosh { fill: url(#animation_shuttleRingSwooshGradient); }.cesium-animation-shuttleRingG:hover .cesium-animation-shuttleRingSwoosh { fill: url(#animation_shuttleRingSwooshHovered); }.cesium-animation-shuttleRingPointer { fill: url(#animation_shuttleRingPointerGradient); }.cesium-animation-shuttleRingPausePointer { fill: url(#animation_shuttleRingPointerPaused); }.cesium-animation-knobOuter { fill: url(#animation_knobOuter); }.cesium-animation-knobInner { fill: url(#animation_knobInner); }",document.head.insertBefore(r,document.head.childNodes[0]);var i=document.createElement("div");i.className="cesium-animation-theme",i.innerHTML='<div class="cesium-animation-themeNormal"></div><div class="cesium-animation-themeHover"></div><div class="cesium-animation-themeSelect"></div><div class="cesium-animation-themeDisabled"></div><div class="cesium-animation-themeKnob"></div><div class="cesium-animation-themePointer"></div><div class="cesium-animation-themeSwoosh"></div><div class="cesium-animation-themeSwooshHover"></div>',this._theme=i,this._themeNormal=i.childNodes[0],this._themeHover=i.childNodes[1],this._themeSelect=i.childNodes[2],this._themeDisabled=i.childNodes[3],this._themeKnob=i.childNodes[4],this._themePointer=i.childNodes[5],this._themeSwoosh=i.childNodes[6],this._themeSwooshHover=i.childNodes[7];var n=document.createElementNS(v,"svg:svg");this._svgNode=n,n.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink",_);var s=document.createElementNS(v,"g");this._topG=s,this._realtimeSVG=new P(p(3,4,"#animation_pathClock"),t.playRealtimeViewModel),this._playReverseSVG=new P(d(44,99,"#animation_pathPlayReverse"),t.playReverseViewModel),this._playForwardSVG=new P(d(124,99,"#animation_pathPlay"),t.playForwardViewModel),this._pauseSVG=new P(d(84,99,"#animation_pathPause"),t.pauseViewModel);var h=document.createElementNS(v,"g");h.appendChild(this._realtimeSVG.svgElement),h.appendChild(this._playReverseSVG.svgElement),h.appendChild(this._playForwardSVG.svgElement),h.appendChild(this._pauseSVG.svgElement);var f=l({tagName:"circle","class":"cesium-animation-shuttleRingBack",cx:100,cy:100,r:99});this._shuttleRingBackPanel=f;var g=l({tagName:"g","class":"cesium-animation-shuttleRingSwoosh",children:[{tagName:"use",transform:"translate(100,97) scale(-1,1)","xlink:href":"#animation_pathSwooshFX"},{tagName:"use",transform:"translate(100,97)","xlink:href":"#animation_pathSwooshFX"},{tagName:"line",x1:100,y1:8,x2:100,y2:22}]});this._shuttleRingSwooshG=g,this._shuttleRingPointer=l({tagName:"use","class":"cesium-animation-shuttleRingPointer","xlink:href":"#animation_pathPointer"});var y=l({tagName:"g",transform:"translate(100,100)"});this._knobOuter=l({tagName:"circle","class":"cesium-animation-knobOuter",cx:0,cy:0,r:71});var C=61,E=l({tagName:"circle","class":"cesium-animation-knobInner",cx:0,cy:0,r:C});this._knobDate=u(0,-24,""),this._knobTime=u(0,-7,""),this._knobStatus=u(0,-41,"");var S=l({tagName:"circle","class":"cesium-animation-blank",cx:0,cy:0,r:C}),w=document.createElementNS(v,"g");w.setAttribute("class","cesium-animation-shuttleRingG"),e.appendChild(i),s.appendChild(w),s.appendChild(y),s.appendChild(h),w.appendChild(f),w.appendChild(g),w.appendChild(this._shuttleRingPointer),y.appendChild(this._knobOuter),y.appendChild(E),y.appendChild(this._knobDate),y.appendChild(this._knobTime),y.appendChild(this._knobStatus),y.appendChild(S),n.appendChild(s),e.appendChild(n);var T=this,b=function(e){m(T,e)};this._mouseCallback=b,f.addEventListener("mousedown",b,!0),f.addEventListener("touchstart",b,!0),g.addEventListener("mousedown",b,!0),g.addEventListener("touchstart",b,!0),document.addEventListener("mousemove",b,!0),document.addEventListener("touchmove",b,!0),document.addEventListener("mouseup",b,!0),document.addEventListener("touchend",b,!0),this._shuttleRingPointer.addEventListener("mousedown",b,!0),this._shuttleRingPointer.addEventListener("touchstart",b,!0),this._knobOuter.addEventListener("mousedown",b,!0),this._knobOuter.addEventListener("touchstart",b,!0);var x,A=this._knobTime.childNodes[0],I=this._knobDate.childNodes[0],M=this._knobStatus.childNodes[0];this._subscriptions=[a(t.pauseViewModel,"toggled",function(e){x!==e&&(x=e,x?T._shuttleRingPointer.setAttribute("class","cesium-animation-shuttleRingPausePointer"):T._shuttleRingPointer.setAttribute("class","cesium-animation-shuttleRingPointer"))}),a(t,"shuttleRingAngle",function(e){c(T._shuttleRingPointer,T._knobOuter,e)}),a(t,"dateLabel",function(e){I.textContent!==e&&(I.textContent=e)}),a(t,"timeLabel",function(e){A.textContent!==e&&(A.textContent=e)}),a(t,"multiplierLabel",function(e){M.textContent!==e&&(M.textContent=e)})],this.applyThemeChanges(),this.resize()};return r(A.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){var e=this._mouseCallback;this._shuttleRingBackPanel.removeEventListener("mousedown",e,!0),this._shuttleRingBackPanel.removeEventListener("touchstart",e,!0),this._shuttleRingSwooshG.removeEventListener("mousedown",e,!0),this._shuttleRingSwooshG.removeEventListener("touchstart",e,!0),document.removeEventListener("mousemove",e,!0),document.removeEventListener("touchmove",e,!0),document.removeEventListener("mouseup",e,!0),document.removeEventListener("touchend",e,!0),this._shuttleRingPointer.removeEventListener("mousedown",e,!0),this._shuttleRingPointer.removeEventListener("touchstart",e,!0),this._knobOuter.removeEventListener("mousedown",e,!0),this._knobOuter.removeEventListener("touchstart",e,!0),this._container.removeChild(this._svgNode),this._container.removeChild(this._theme),this._realtimeSVG.destroy(),this._playReverseSVG.destroy(),this._playForwardSVG.destroy(),this._pauseSVG.destroy();for(var t=this._subscriptions,r=0,n=t.length;n>r;r++)t[r].dispose();return i(this)},A.prototype.resize=function(){var e=this._container.clientWidth,t=this._container.clientHeight;if(e!==this._lastWidth||t!==this._lastHeight){var r=this._svgNode,i=200,n=132,o=e,a=t;0===e&&0===t?(o=i,a=n):0===e?(a=t,o=i*(t/n)):0===t&&(o=e,a=n*(e/i));var s=o/i,l=a/n;r.style.cssText="width: "+o+"px; height: "+a+"px; position: absolute; bottom: 0; left: 0; overflow: hidden;",r.setAttribute("width",o),r.setAttribute("height",a),r.setAttribute("viewBox","0 0 "+o+" "+a),this._topG.setAttribute("transform","scale("+s+","+l+")"),this._centerX=Math.max(1,100*s),this._centerY=Math.max(1,100*l),this._lastHeight=e,this._lastWidth=t}},A.prototype.applyThemeChanges=function(){var e=s(this._themeNormal),r=s(this._themeHover),i=s(this._themeSelect),n=s(this._themeDisabled),o=s(this._themeKnob),a=s(this._themePointer),u=s(this._themeSwoosh),c=s(this._themeSwooshHover),d=l({tagName:"defs",children:[{id:"animation_buttonNormal",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(e,g)},{tagName:"stop",offset:"12%","stop-color":h(e,y)},{tagName:"stop",offset:"46%","stop-color":h(e,C)},{tagName:"stop",offset:"81%","stop-color":h(e,E)}]},{id:"animation_buttonHovered",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(r,g)},{tagName:"stop",offset:"12%","stop-color":h(r,y)},{tagName:"stop",offset:"46%","stop-color":h(r,C)},{tagName:"stop",offset:"81%","stop-color":h(r,E)}]},{id:"animation_buttonToggled",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(i,g)},{tagName:"stop",offset:"12%","stop-color":h(i,y)},{tagName:"stop",offset:"46%","stop-color":h(i,C)},{tagName:"stop",offset:"81%","stop-color":h(i,E)}]},{id:"animation_buttonDisabled",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(n,S)},{tagName:"stop",offset:"75%","stop-color":h(n,w)}]},{id:"animation_blurred",tagName:"filter",width:"200%",height:"200%",x:"-50%",y:"-50%",children:[{tagName:"feGaussianBlur",stdDeviation:4,"in":"SourceGraphic"}]},{id:"animation_shuttleRingSwooshGradient",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-opacity":.2,"stop-color":u.toCssColorString()},{tagName:"stop",offset:"85%","stop-opacity":.85,"stop-color":u.toCssColorString()},{tagName:"stop",offset:"95%","stop-opacity":.05,"stop-color":u.toCssColorString()}]},{id:"animation_shuttleRingSwooshHovered",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-opacity":.2,"stop-color":c.toCssColorString()},{tagName:"stop",offset:"85%","stop-opacity":.85,"stop-color":c.toCssColorString()},{tagName:"stop",offset:"95%","stop-opacity":.05,"stop-color":c.toCssColorString()}]},{id:"animation_shuttleRingPointerGradient",tagName:"linearGradient",x1:"0%",y1:"50%",x2:"100%",y2:"50%",children:[{tagName:"stop",offset:"0%","stop-color":a.toCssColorString()},{tagName:"stop",offset:"40%","stop-color":a.toCssColorString()},{tagName:"stop",offset:"60%","stop-color":h(a,b)},{tagName:"stop",offset:"100%","stop-color":h(a,b)}]},{id:"animation_shuttleRingPointerPaused",tagName:"linearGradient",x1:"0%",y1:"50%",x2:"100%",y2:"50%",children:[{tagName:"stop",offset:"0%","stop-color":"#CCC"},{tagName:"stop",offset:"40%","stop-color":"#CCC"},{tagName:"stop",offset:"60%","stop-color":"#555"},{tagName:"stop",offset:"100%","stop-color":"#555"}]},{id:"animation_knobOuter",tagName:"linearGradient",x1:"20%",y1:"0%",x2:"90%",y2:"100%",children:[{tagName:"stop",offset:"5%","stop-color":h(o,g)},{tagName:"stop",offset:"60%","stop-color":h(o,T)},{tagName:"stop",offset:"85%","stop-color":h(o,y)}]},{id:"animation_knobInner",tagName:"linearGradient",x1:"20%",y1:"0%",x2:"90%",y2:"100%",children:[{tagName:"stop",offset:"5%","stop-color":h(o,T)},{tagName:"stop",offset:"60%","stop-color":h(o,g)},{tagName:"stop",offset:"85%","stop-color":h(o,E)}]},{id:"animation_pathReset",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M24.316,5.318,9.833,13.682,9.833,5.5,5.5,5.5,5.5,25.5,9.833,25.5,9.833,17.318,24.316,25.682z"},{id:"animation_pathPause",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M13,5.5,7.5,5.5,7.5,25.5,13,25.5zM24.5,5.5,19,5.5,19,25.5,24.5,25.5z"},{id:"animation_pathPlay",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M6.684,25.682L24.316,15.5L6.684,5.318V25.682z"},{id:"animation_pathPlayReverse",tagName:"path",transform:"translate(16,16) scale(-0.85,0.85) translate(-16,-16)",d:"M6.684,25.682L24.316,15.5L6.684,5.318V25.682z"},{id:"animation_pathLoop",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M24.249,15.499c-0.009,4.832-3.918,8.741-8.75,8.75c-2.515,0-4.768-1.064-6.365-2.763l2.068-1.442l-7.901-3.703l0.744,8.694l2.193-1.529c2.244,2.594,5.562,4.242,9.26,4.242c6.767,0,12.249-5.482,12.249-12.249H24.249zM15.499,6.75c2.516,0,4.769,1.065,6.367,2.764l-2.068,1.443l7.901,3.701l-0.746-8.693l-2.192,1.529c-2.245-2.594-5.562-4.245-9.262-4.245C8.734,3.25,3.25,8.734,3.249,15.499H6.75C6.758,10.668,10.668,6.758,15.499,6.75z"},{id:"animation_pathClock",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-15.5)",d:"M15.5,2.374C8.251,2.375,2.376,8.251,2.374,15.5C2.376,22.748,8.251,28.623,15.5,28.627c7.249-0.004,13.124-5.879,13.125-13.127C28.624,8.251,22.749,2.375,15.5,2.374zM15.5,25.623C9.909,25.615,5.385,21.09,5.375,15.5C5.385,9.909,9.909,5.384,15.5,5.374c5.59,0.01,10.115,4.535,10.124,10.125C25.615,21.09,21.091,25.615,15.5,25.623zM8.625,15.5c-0.001-0.552-0.448-0.999-1.001-1c-0.553,0-1,0.448-1,1c0,0.553,0.449,1,1,1C8.176,16.5,8.624,16.053,8.625,15.5zM8.179,18.572c-0.478,0.277-0.642,0.889-0.365,1.367c0.275,0.479,0.889,0.641,1.365,0.365c0.479-0.275,0.643-0.887,0.367-1.367C9.27,18.461,8.658,18.297,8.179,18.572zM9.18,10.696c-0.479-0.276-1.09-0.112-1.366,0.366s-0.111,1.09,0.365,1.366c0.479,0.276,1.09,0.113,1.367-0.366C9.821,11.584,9.657,10.973,9.18,10.696zM22.822,12.428c0.478-0.275,0.643-0.888,0.366-1.366c-0.275-0.478-0.89-0.642-1.366-0.366c-0.479,0.278-0.642,0.89-0.366,1.367C21.732,12.54,22.344,12.705,22.822,12.428zM12.062,21.455c-0.478-0.275-1.089-0.111-1.366,0.367c-0.275,0.479-0.111,1.09,0.366,1.365c0.478,0.277,1.091,0.111,1.365-0.365C12.704,22.344,12.54,21.732,12.062,21.455zM12.062,9.545c0.479-0.276,0.642-0.888,0.366-1.366c-0.276-0.478-0.888-0.642-1.366-0.366s-0.642,0.888-0.366,1.366C10.973,9.658,11.584,9.822,12.062,9.545zM22.823,18.572c-0.48-0.275-1.092-0.111-1.367,0.365c-0.275,0.479-0.112,1.092,0.367,1.367c0.477,0.275,1.089,0.113,1.365-0.365C23.464,19.461,23.3,18.848,22.823,18.572zM19.938,7.813c-0.477-0.276-1.091-0.111-1.365,0.366c-0.275,0.48-0.111,1.091,0.366,1.367s1.089,0.112,1.366-0.366C20.581,8.702,20.418,8.089,19.938,7.813zM23.378,14.5c-0.554,0.002-1.001,0.45-1.001,1c0.001,0.552,0.448,1,1.001,1c0.551,0,1-0.447,1-1C24.378,14.949,23.929,14.5,23.378,14.5zM15.501,6.624c-0.552,0-1,0.448-1,1l-0.466,7.343l-3.004,1.96c-0.478,0.277-0.642,0.889-0.365,1.365c0.275,0.479,0.889,0.643,1.365,0.367l3.305-1.676C15.39,16.99,15.444,17,15.501,17c0.828,0,1.5-0.671,1.5-1.5l-0.5-7.876C16.501,7.072,16.053,6.624,15.501,6.624zM15.501,22.377c-0.552,0-1,0.447-1,1s0.448,1,1,1s1-0.447,1-1S16.053,22.377,15.501,22.377zM18.939,21.455c-0.479,0.277-0.643,0.889-0.366,1.367c0.275,0.477,0.888,0.643,1.366,0.365c0.478-0.275,0.642-0.889,0.366-1.365C20.028,21.344,19.417,21.18,18.939,21.455z" +},{id:"animation_pathWingButton",tagName:"path",d:"m 4.5,0.5 c -2.216,0 -4,1.784 -4,4 l 0,24 c 0,2.216 1.784,4 4,4 l 13.71875,0 C 22.478584,27.272785 27.273681,22.511272 32.5,18.25 l 0,-13.75 c 0,-2.216 -1.784,-4 -4,-4 l -24,0 z"},{id:"animation_pathPointer",tagName:"path",d:"M-15,-65,-15,-55,15,-55,15,-65,0,-95z"},{id:"animation_pathSwooshFX",tagName:"path",d:"m 85,0 c 0,16.617 -4.813944,35.356 -13.131081,48.4508 h 6.099803 c 8.317138,-13.0948 13.13322,-28.5955 13.13322,-45.2124 0,-46.94483 -38.402714,-85.00262 -85.7743869,-85.00262 -1.0218522,0 -2.0373001,0.0241 -3.0506131,0.0589 45.958443,1.59437 82.723058,35.77285 82.723058,81.70532 z"}]});t(this._defsElement)?this._svgNode.replaceChild(d,this._defsElement):this._svgNode.appendChild(d),this._defsElement=d},A}),r("Widgets/createCommand",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../ThirdParty/knockout"],function(e,t,r,i,n,o){"use strict";var a=function(t,i){function a(){var e,r={args:arguments,cancel:!1};return s.raiseEvent(r),r.cancel||(e=t.apply(null,arguments),l.raiseEvent(e)),e}i=e(i,!0);var s=new n,l=new n;return a.canExecute=i,o.track(a,["canExecute"]),r(a,{beforeExecute:{value:s},afterExecute:{value:l}}),a};return a}),r("Widgets/ToggleButtonViewModel",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../ThirdParty/knockout"],function(e,t,r,i,n){"use strict";var o=function(t,r){this._command=t,r=e(r,e.EMPTY_OBJECT),this.toggled=e(r.toggled,!1),this.tooltip=e(r.tooltip,""),n.track(this,["toggled","tooltip"])};return r(o.prototype,{command:{get:function(){return this._command}}}),o}),r("Widgets/Animation/AnimationViewModel",["../../Core/binarySearch","../../Core/ClockRange","../../Core/ClockStep","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/JulianDate","../../ThirdParty/knockout","../../ThirdParty/sprintf","../createCommand","../ToggleButtonViewModel"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e){e.clockStep===r.SYSTEM_CLOCK&&(e.clockStep=r.SYSTEM_CLOCK_MULTIPLIER,e.multiplier=1)}function d(e){h(e),e.shouldAnimate=!0}function p(e,t){return e-t}function m(t,r){var i=e(r,t,p);return 0>i?~i:i}function f(e,t){if(Math.abs(e)<=g)return e/g;var r,i,n=g,o=y,a=0;return e>0?(r=Math.log(t[t.length-1]),i=(r-a)/(o-n),Math.exp(a+i*(e-n))):(r=Math.log(-t[0]),i=(r-a)/(o-n),-Math.exp(a+i*(Math.abs(e)-n)))}function v(e,t,i){if(i.clockStep===r.SYSTEM_CLOCK)return g;if(Math.abs(e)<=1)return e*g;var n=t[t.length-1];e>n?e=n:-n>e&&(e=-n);var o,a,s=g,l=y,u=0;return e>0?(o=Math.log(n),a=(o-u)/(l-s),(Math.log(e)-u)/a+s):(o=Math.log(-t[0]),a=(o-u)/(l-s),-((Math.log(Math.abs(e))-u)/a+s))}var _=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],g=15,y=105,C=function(e){var i=this;this._clockViewModel=e,this._allShuttleRingTicks=[],this._dateFormatter=C.defaultDateFormatter,this._timeFormatter=C.defaultTimeFormatter,this.shuttleRingDragging=!1,this.snapToTicks=!1,s.track(this,["_allShuttleRingTicks","_dateFormatter","_timeFormatter","shuttleRingDragging","snapToTicks"]),this._sortedFilteredPositiveTicks=[],this.setShuttleRingTicks(C.defaultTicks),this.timeLabel=void 0,s.defineProperty(this,"timeLabel",function(){return i._timeFormatter(i._clockViewModel.currentTime,i)}),this.dateLabel=void 0,s.defineProperty(this,"dateLabel",function(){return i._dateFormatter(i._clockViewModel.currentTime,i)}),this.multiplierLabel=void 0,s.defineProperty(this,"multiplierLabel",function(){var e=i._clockViewModel;if(e.clockStep===r.SYSTEM_CLOCK)return"Today";var t=e.multiplier;return t%1===0?t.toFixed(0)+"x":t.toFixed(3).replace(/0{0,3}$/,"")+"x"}),this.shuttleRingAngle=void 0,s.defineProperty(this,"shuttleRingAngle",{get:function(){return v(e.multiplier,i._allShuttleRingTicks,e)},set:function(e){e=Math.max(Math.min(e,y),-y);var t=i._allShuttleRingTicks,n=i._clockViewModel;if(n.clockStep=r.SYSTEM_CLOCK_MULTIPLIER,Math.abs(e)===y)return void(n.multiplier=e>0?t[t.length-1]:t[0]);var o=f(e,t);if(i.snapToTicks)o=t[m(o,t)];else if(0!==o){var a=Math.abs(o);if(a>100){var s=a.toFixed(0).length-2,l=Math.pow(10,s);o=Math.round(o/l)*l|0}else a>g?o=Math.round(o):a>1?o=+o.toFixed(1):a>0&&(o=+o.toFixed(2))}n.multiplier=o}}),this._canAnimate=void 0,s.defineProperty(this,"_canAnimate",function(){var e=i._clockViewModel,r=e.clockRange;if(i.shuttleRingDragging||r===t.UNBOUNDED)return!0;var n=e.multiplier,o=e.currentTime,s=e.startTime,l=!1;if(r===t.LOOP_STOP)l=a.greaterThan(o,s)||o.equals(s)&&n>0;else{var u=e.stopTime;l=a.greaterThan(o,s)&&a.lessThan(o,u)||o.equals(s)&&n>0||o.equals(u)&&0>n}return l||(e.shouldAnimate=!1),l}),this._isSystemTimeAvailable=void 0,s.defineProperty(this,"_isSystemTimeAvailable",function(){var e=i._clockViewModel,r=e.clockRange;if(r===t.UNBOUNDED)return!0;var n=e.systemTime;return a.greaterThanOrEquals(n,e.startTime)&&a.lessThanOrEquals(n,e.stopTime)}),this._isAnimating=void 0,s.defineProperty(this,"_isAnimating",function(){return i._clockViewModel.shouldAnimate&&(i._canAnimate||i.shuttleRingDragging)});var n=u(function(){var e=i._clockViewModel;e.shouldAnimate?(h(e),e.shouldAnimate=!1):i._canAnimate&&d(e)});this._pauseViewModel=new c(n,{toggled:s.computed(function(){return!i._isAnimating}),tooltip:"Pause"});var o=u(function(){var e=i._clockViewModel;h(e);var t=e.multiplier;t>0&&(e.multiplier=-t),e.shouldAnimate=!0});this._playReverseViewModel=new c(o,{toggled:s.computed(function(){return i._isAnimating&&e.multiplier<0}),tooltip:"Play Reverse"});var l=u(function(){var e=i._clockViewModel;h(e);var t=e.multiplier;0>t&&(e.multiplier=-t),e.shouldAnimate=!0});this._playForwardViewModel=new c(l,{toggled:s.computed(function(){return i._isAnimating&&e.multiplier>0&&e.clockStep!==r.SYSTEM_CLOCK}),tooltip:"Play Forward"});var p=u(function(){var e=i._clockViewModel;e.clockStep=r.SYSTEM_CLOCK,e.multiplier=1,e.shouldAnimate=!0},s.getObservable(this,"_isSystemTimeAvailable"));this._playRealtimeViewModel=new c(p,{toggled:s.computed(function(){return e.shouldAnimate&&e.clockStep===r.SYSTEM_CLOCK}),tooltip:s.computed(function(){return i._isSystemTimeAvailable?"Today (real-time)":"Current time not in range"})}),this._slower=u(function(){var e=i._clockViewModel;h(e);var t=i._allShuttleRingTicks,r=e.multiplier,n=m(r,t)-1;n>=0&&(e.multiplier=t[n])}),this._faster=u(function(){var e=i._clockViewModel;h(e);var t=i._allShuttleRingTicks,r=e.multiplier,n=m(r,t)+1;n<t.length&&(e.multiplier=t[n])})};return C.defaultDateFormatter=function(e,t){var r=a.toGregorianDate(e);return _[r.month-1]+" "+r.day+" "+r.year},C.defaultTicks=[.001,.002,.005,.01,.02,.05,.1,.25,.5,1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,21600,43200,86400,172800,345600,604800],C.defaultTimeFormatter=function(e,t){var r=a.toGregorianDate(e),i=Math.round(r.millisecond);return Math.abs(t._clockViewModel.multiplier)<1?l("%02d:%02d:%02d.%03d",r.hour,r.minute,r.second,i):l("%02d:%02d:%02d UTC",r.hour,r.minute,r.second)},C.prototype.getShuttleRingTicks=function(){return this._sortedFilteredPositiveTicks.slice(0)},C.prototype.setShuttleRingTicks=function(e){var t,r,i,n={},o=this._sortedFilteredPositiveTicks;for(o.length=0,t=0,r=e.length;r>t;++t)i=e[t],n.hasOwnProperty(i)||(n[i]=!0,o.push(i));o.sort(p);var a=[];for(r=o.length,t=r-1;t>=0;--t)i=o[t],0!==i&&a.push(-i);Array.prototype.push.apply(a,o),this._allShuttleRingTicks=a},n(C.prototype,{slower:{get:function(){return this._slower}},faster:{get:function(){return this._faster}},clockViewModel:{get:function(){return this._clockViewModel}},pauseViewModel:{get:function(){return this._pauseViewModel}},playReverseViewModel:{get:function(){return this._playReverseViewModel}},playForwardViewModel:{get:function(){return this._playForwardViewModel}},playRealtimeViewModel:{get:function(){return this._playRealtimeViewModel}},dateFormatter:{get:function(){return this._dateFormatter},set:function(e){this._dateFormatter=e}},timeFormatter:{get:function(){return this._timeFormatter},set:function(e){this._timeFormatter=e}}}),C._maxShuttleRingAngle=y,C._realtimeShuttleRingAngle=g,C}),r("Widgets/BaseLayerPicker/BaseLayerPickerViewModel",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/EllipsoidTerrainProvider","../../Core/isArray","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.globe,l=e(r.imageryProviderViewModels,[]),u=e(r.terrainProviderViewModels,[]);this._globe=i,this.imageryProviderViewModels=l.slice(0),this.terrainProviderViewModels=u.slice(0),this.dropDownVisible=!1,a.track(this,["imageryProviderViewModels","terrainProviderViewModels","dropDownVisible"]),this.buttonTooltip=void 0,a.defineProperty(this,"buttonTooltip",function(){var e=this.selectedImagery,r=this.selectedTerrain,i=t(e)?e.name:void 0,n=t(r)?r.name:void 0;return t(i)&&t(n)?i+"\n"+n:t(i)?i:n}),this.buttonImageUrl=void 0,a.defineProperty(this,"buttonImageUrl",function(){var e=this.selectedImagery;return t(e)?e.iconUrl:void 0}),this.selectedImagery=void 0;var c=a.observable();this._currentImageryProviders=[],a.defineProperty(this,"selectedImagery",{get:function(){return c()},set:function(e){if(c()===e)return void(this.dropDownVisible=!1);var r,i=this._currentImageryProviders,n=i.length,a=this._globe.imageryLayers;for(r=0;n>r;r++)for(var s=a.length,l=0;s>l;l++){var u=a.get(l);if(u.imageryProvider===i[r]){a.remove(u);break}}if(t(e)){var h=e.creationCommand();if(o(h)){var d=h.length;for(r=d-1;r>=0;r--)a.addImageryProvider(h[r],0);this._currentImageryProviders=h.slice(0)}else this._currentImageryProviders=[h],a.addImageryProvider(h,0)}c(e),this.dropDownVisible=!1}}),this.selectedTerrain=void 0;var h=a.observable();a.defineProperty(this,"selectedTerrain",{get:function(){return h()},set:function(e){if(h()===e)return void(this.dropDownVisible=!1);var r;t(e)&&(r=e.creationCommand()),this._globe.depthTestAgainstTerrain=!(r instanceof n),this._globe.terrainProvider=r,h(e),this.dropDownVisible=!1}});var d=this;this._toggleDropDown=s(function(){d.dropDownVisible=!d.dropDownVisible}),this.selectedImagery=e(r.selectedImageryProviderViewModel,l[0]),this.selectedTerrain=e(r.selectedTerrainProviderViewModel,u[0])};return r(l.prototype,{toggleDropDown:{get:function(){return this._toggleDropDown}},globe:{get:function(){return this._globe}}}),l}),r("Widgets/BaseLayerPicker/BaseLayerPicker",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./BaseLayerPickerViewModel"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,t){e=a(e);var r=new s(t),i=document.createElement("button");i.type="button",i.className="cesium-button cesium-toolbar-button",i.setAttribute("data-bind","attr: { title: buttonTooltip },click: toggleDropDown"),e.appendChild(i);var l=document.createElement("img");l.setAttribute("draggable","false"),l.className="cesium-baseLayerPicker-selected",l.setAttribute("data-bind","attr: { src: buttonImageUrl }"),i.appendChild(l);var u=document.createElement("div");u.className="cesium-baseLayerPicker-dropDown",u.setAttribute("data-bind",'css: { "cesium-baseLayerPicker-dropDown-visible" : dropDownVisible }'),e.appendChild(u);var c=document.createElement("div");c.className="cesium-baseLayerPicker-sectionTitle",c.setAttribute("data-bind","visible: imageryProviderViewModels.length > 0"),c.innerHTML="Imagery",u.appendChild(c);var h=document.createElement("div");h.className="cesium-baseLayerPicker-choices",h.setAttribute("data-bind","foreach: imageryProviderViewModels"),u.appendChild(h);var d=document.createElement("div");d.className="cesium-baseLayerPicker-item",d.setAttribute("data-bind",'css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedImagery },attr: { title: tooltip },visible: creationCommand.canExecute,click: function($data) { $parent.selectedImagery = $data; }'),h.appendChild(d);var p=document.createElement("img");p.className="cesium-baseLayerPicker-itemIcon",p.setAttribute("data-bind","attr: { src: iconUrl }"),p.setAttribute("draggable","false"),d.appendChild(p);var m=document.createElement("div");m.className="cesium-baseLayerPicker-itemLabel",m.setAttribute("data-bind","text: name"),d.appendChild(m);var f=document.createElement("div");f.className="cesium-baseLayerPicker-sectionTitle",f.setAttribute("data-bind","visible: terrainProviderViewModels.length > 0"),f.innerHTML="Terrain",u.appendChild(f);var v=document.createElement("div");v.className="cesium-baseLayerPicker-choices",v.setAttribute("data-bind","foreach: terrainProviderViewModels"),u.appendChild(v);var _=document.createElement("div");_.className="cesium-baseLayerPicker-item",_.setAttribute("data-bind",'css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedTerrain },attr: { title: tooltip },visible: creationCommand.canExecute,click: function($data) { $parent.selectedTerrain = $data; }'),v.appendChild(_);var g=document.createElement("img");g.className="cesium-baseLayerPicker-itemIcon",g.setAttribute("data-bind","attr: { src: iconUrl }"),g.setAttribute("draggable","false"),_.appendChild(g);var y=document.createElement("div");y.className="cesium-baseLayerPicker-itemLabel",y.setAttribute("data-bind","text: name"),_.appendChild(y),o.applyBindings(r,i),o.applyBindings(r,u),this._viewModel=r,this._container=e,this._element=i,this._dropPanel=u,this._closeDropDown=function(e){i.contains(e.target)||u.contains(e.target)||(r.dropDownVisible=!1)},n.supportsPointerEvents()?document.addEventListener("pointerdown",this._closeDropDown,!0):(document.addEventListener("mousedown",this._closeDropDown,!0),document.addEventListener("touchstart",this._closeDropDown,!0))};return t(l.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),l.prototype.isDestroyed=function(){return!1},l.prototype.destroy=function(){return n.supportsPointerEvents()?document.removeEventListener("pointerdown",this._closeDropDown,!0):(document.removeEventListener("mousedown",this._closeDropDown,!0),document.removeEventListener("touchstart",this._closeDropDown,!0)),o.cleanNode(this._element),o.cleanNode(this._dropPanel),this._container.removeChild(this._element),this._container.removeChild(this._dropPanel),r(this)},l}),r("Widgets/BaseLayerPicker/ProviderViewModel",["../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n){"use strict";var o=function(t){var r=t.creationFunction;e(r.canExecute)||(r=n(r)),this._creationCommand=r,this.name=t.name,this.tooltip=t.tooltip,this.iconUrl=t.iconUrl,i.track(this,["name","tooltip","iconUrl"])};return t(o.prototype,{creationCommand:{get:function(){return this._creationCommand}}}),o}),r("Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels",["../../Core/buildModuleUrl","../../Scene/ArcGisMapServerImageryProvider","../../Scene/BingMapsImageryProvider","../../Scene/BingMapsStyle","../../Scene/MapboxImageryProvider","../../Scene/OpenStreetMapImageryProvider","../../Scene/TileMapServiceImageryProvider","../BaseLayerPicker/ProviderViewModel"],function(e,t,r,i,n,o,a,s){"use strict";function l(){var l=[];return l.push(new s({name:"Bing Maps Aerial",iconUrl:e("Widgets/Images/ImageryProviders/bingAerial.png"),tooltip:"Bing Maps aerial imagery \nhttp://www.bing.com/maps",creationFunction:function(){return new r({url:"//dev.virtualearth.net",mapStyle:i.AERIAL})}})),l.push(new s({name:"Bing Maps Aerial with Labels",iconUrl:e("Widgets/Images/ImageryProviders/bingAerialLabels.png"),tooltip:"Bing Maps aerial imagery with label overlays \nhttp://www.bing.com/maps",creationFunction:function(){return new r({url:"//dev.virtualearth.net",mapStyle:i.AERIAL_WITH_LABELS})}})),l.push(new s({name:"Bing Maps Roads",iconUrl:e("Widgets/Images/ImageryProviders/bingRoads.png"),tooltip:"Bing Maps standard road maps\nhttp://www.bing.com/maps",creationFunction:function(){return new r({url:"//dev.virtualearth.net",mapStyle:i.ROAD})}})),l.push(new s({name:"Mapbox Satellite",tooltip:"Mapbox satellite imagery https://www.mapbox.com/maps/",iconUrl:e("Widgets/Images/ImageryProviders/mapboxSatellite.png"),creationFunction:function(){return new n({mapId:"mapbox.satellite"})}})),l.push(new s({name:"Mapbox Streets",tooltip:"Mapbox streets imagery https://www.mapbox.com/maps/",iconUrl:e("Widgets/Images/ImageryProviders/mapboxTerrain.png"),creationFunction:function(){return new n({mapId:"mapbox.streets"})}})),l.push(new s({name:"Mapbox Streets Classic",tooltip:"Mapbox streets basic imagery https://www.mapbox.com/maps/",iconUrl:e("Widgets/Images/ImageryProviders/mapboxStreets.png"),creationFunction:function(){return new n({mapId:"mapbox.streets-basic"})}})),l.push(new s({name:"ESRI World Imagery",iconUrl:e("Widgets/Images/ImageryProviders/esriWorldImagery.png"),tooltip:"World Imagery provides one meter or better satellite and aerial imagery in many parts of the world and lower resolution satellite imagery worldwide. The map includes NASA Blue Marble: Next Generation 500m resolution imagery at small scales (above 1:1,000,000), i-cubed 15m eSAT imagery at medium-to-large scales (down to 1:70,000) for the world, and USGS 15m Landsat imagery for Antarctica. The map features 0.3m resolution imagery in the continental United States and 0.6m resolution imagery in parts of Western Europe from DigitalGlobe. In other parts of the world, 1 meter resolution imagery is available from GeoEye IKONOS, i-cubed Nationwide Prime, Getmapping, AeroGRID, IGN Spain, and IGP Portugal. Additionally, imagery at different resolutions has been contributed by the GIS User Community.\nhttp://www.esri.com",creationFunction:function(){return new t({url:"//services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",enablePickFeatures:!1})}})),l.push(new s({name:"ESRI World Street Map",iconUrl:e("Widgets/Images/ImageryProviders/esriWorldStreetMap.png"),tooltip:"This worldwide street map presents highway-level data for the world. Street-level data includes the United States; much of Canada; Japan; most countries in Europe; Australia and New Zealand; India; parts of South America including Argentina, Brazil, Chile, Colombia, and Venezuela; Ghana; and parts of southern Africa including Botswana, Lesotho, Namibia, South Africa, and Swaziland.\nhttp://www.esri.com",creationFunction:function(){return new t({url:"//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",enablePickFeatures:!1})}})),l.push(new s({name:"ESRI National Geographic",iconUrl:e("Widgets/Images/ImageryProviders/esriNationalGeographic.png"),tooltip:"This web map contains the National Geographic World Map service. This map service is designed to be used as a general reference map for informational and educational purposes as well as a basemap by GIS professionals and other users for creating web maps and web mapping applications.\nhttp://www.esri.com",creationFunction:function(){return new t({url:"//services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/",enablePickFeatures:!1})}})),l.push(new s({name:"Open­Street­Map",iconUrl:e("Widgets/Images/ImageryProviders/openStreetMap.png"),tooltip:"OpenStreetMap (OSM) is a collaborative project to create a free editable map of the world.\nhttp://www.openstreetmap.org",creationFunction:function(){return new o({url:"//a.tile.openstreetmap.org/"})}})),l.push(new s({name:"Stamen Watercolor",iconUrl:e("Widgets/Images/ImageryProviders/stamenWatercolor.png"),tooltip:"Reminiscent of hand drawn maps, Stamen watercolor maps apply raster effect area washes and organic edges over a paper texture to add warm pop to any map.\nhttp://maps.stamen.com",creationFunction:function(){return new o({url:"//stamen-tiles.a.ssl.fastly.net/watercolor/",credit:"Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA."})}})),l.push(new s({name:"Stamen Toner",iconUrl:e("Widgets/Images/ImageryProviders/stamenToner.png"),tooltip:"A high contrast black and white map.\nhttp://maps.stamen.com",creationFunction:function(){return new o({url:"//stamen-tiles.a.ssl.fastly.net/toner/",credit:"Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA."})}})),l.push(new s({name:"MapQuest Open­Street­Map",iconUrl:e("Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png"),tooltip:"OpenStreetMap (OSM) is a collaborative project to create a free editable map of the world.\nhttp://www.openstreetmap.org",creationFunction:function(){return new o({url:"//otile1-s.mqcdn.com/tiles/1.0.0/osm/"})}})),l.push(new s({name:"The Black Marble",iconUrl:e("Widgets/Images/ImageryProviders/blackMarble.png"),tooltip:"The lights of cities and villages trace the outlines of civilization in this global view of the Earth at night as seen by NASA/NOAA's Suomi NPP satellite.",creationFunction:function(){return new a({url:"//cesiumjs.org/blackmarble",maximumLevel:8,credit:"Black Marble imagery courtesy NASA Earth Observatory"})}})),l.push(new s({name:"Natural Earth II",iconUrl:e("Widgets/Images/ImageryProviders/naturalEarthII.png"),tooltip:"Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/",creationFunction:function(){return new a({url:e("Assets/Textures/NaturalEarthII")})}})),l}return l}),r("Widgets/BaseLayerPicker/createDefaultTerrainProviderViewModels",["../../Core/buildModuleUrl","../../Core/CesiumTerrainProvider","../../Core/EllipsoidTerrainProvider","../BaseLayerPicker/ProviderViewModel"],function(e,t,r,i){"use strict";function n(){var n=[];return n.push(new i({name:"WGS84 Ellipsoid",iconUrl:e("Widgets/Images/TerrainProviders/Ellipsoid.png"),tooltip:"WGS84 standard ellipsoid, also known as EPSG:4326",creationFunction:function(){return new r}})),n.push(new i({name:"STK World Terrain meshes",iconUrl:e("Widgets/Images/TerrainProviders/STK.png"),tooltip:"High-resolution, mesh-based terrain for the entire globe. Free for use on the Internet. Closed-network options are available.\nhttp://www.agi.com",creationFunction:function(){return new t({url:"//assets.agi.com/stk-terrain/world",requestWaterMask:!0,requestVertexNormals:!0})}})),n}return n}),r("Widgets/CesiumInspector/CesiumInspectorViewModel",["../../Core/Color","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/Rectangle","../../Core/ScreenSpaceEventHandler","../../Core/ScreenSpaceEventType","../../Scene/DebugModelMatrixPrimitive","../../Scene/PerformanceDisplay","../../Scene/TileCoordinatesImageryProvider","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e){var r;if(t(e)){r="Command Statistics";var i=e.commandsInFrustums;for(var n in i)if(i.hasOwnProperty(n)){var o,a=parseInt(n,10);if(7===a)o="1, 2 and 3";else{for(var s=[],l=2;l>=0;l--){var u=Math.pow(2,l);a>=u&&(s.push(l+1),a-=u)}o=s.reverse().join(" and ")}r+="<br>    "+i[n]+" in frustum "+o}r+="<br>Total: "+e.totalCommands}return r}function m(e,t,r){var i=Math.min(r,t);return i=Math.max(i,e)}var f=function(e,r){var i=this,n=e.canvas,p=new a(n);this._eventHandler=p,this._scene=e,this._canvas=n,this._primitive=void 0,this._tile=void 0,this._modelMatrixPrimitive=void 0,this._performanceDisplay=void 0,this._performanceContainer=r;var f=this._scene.globe;f.depthTestAgainstTerrain=!0,this.frustums=!1,this.performance=!1,this.shaderCacheText="",this.primitiveBoundingSphere=!1,this.primitiveReferenceFrame=!1,this.filterPrimitive=!1,this.tileBoundingSphere=!1,this.filterTile=!1,this.wireframe=!1,this.globeDepth=!1,this.pickDepth=!1,this.depthFrustum=1,this._numberOfFrustums=1,this.depthFrustumText="1 of 1",this.suspendUpdates=!1,this.tileCoordinates=!1,this.frustumStatisticText="",this.tileText="",this.hasPickedPrimitive=!1,this.hasPickedTile=!1,this.pickPimitiveActive=!1,this.pickTileActive=!1,this.dropDownVisible=!0,this.generalVisible=!0,this.primitivesVisible=!1,this.terrainVisible=!1,this.generalSwitchText="-",this.primitivesSwitchText="+",this.terrainSwitchText="+",h.track(this,["filterTile","suspendUpdates","dropDownVisible","shaderCacheText","frustums","frustumStatisticText","pickTileActive","pickPrimitiveActive","hasPickedPrimitive","hasPickedTile","tileText","generalVisible","generalSwitchText","primitivesVisible","primitivesSwitchText","terrainVisible","terrainSwitchText","depthFrustumText"]),this._toggleDropDown=d(function(){i.dropDownVisible=!i.dropDownVisible}),this._toggleGeneral=d(function(){i.generalVisible=!i.generalVisible,i.generalSwitchText=i.generalVisible?"-":"+"}),this._togglePrimitives=d(function(){i.primitivesVisible=!i.primitivesVisible,i.primitivesSwitchText=i.primitivesVisible?"-":"+"}),this._toggleTerrain=d(function(){i.terrainVisible=!i.terrainVisible,i.terrainSwitchText=i.terrainVisible?"-":"+"}),this._showFrustums=d(function(){return i.frustums?i._scene.debugShowFrustums=!0:i._scene.debugShowFrustums=!1,!0}),this._showPerformance=d(function(){return i.performance?i._performanceDisplay=new u({container:i._performanceContainer}):i._performanceContainer.innerHTML="",!0}),this._showPrimitiveBoundingSphere=d(function(){return i._primitive.debugShowBoundingVolume=i.primitiveBoundingSphere,!0}),this._showPrimitiveReferenceFrame=d(function(){if(i.primitiveReferenceFrame){var e=i._primitive.modelMatrix;i._modelMatrixPrimitive=new l({modelMatrix:e}),i._scene.primitives.add(i._modelMatrixPrimitive)}else t(i._modelMatrixPrimitive)&&(i._scene.primitives.remove(i._modelMatrixPrimitive),i._modelMatrixPrimitive=void 0);return!0}),this._doFilterPrimitive=d(function(){return i.filterPrimitive?i._scene.debugCommandFilter=function(e){return t(i._modelMatrixPrimitive)&&e.owner===i._modelMatrixPrimitive._primitive?!0:t(i._primitive)?e.owner===i._primitive||e.owner===i._primitive._billboardCollection||e.owner.primitive===i._primitive:!1}:i._scene.debugCommandFilter=void 0,!0}),this._showWireframe=d(function(){return f._surface.tileProvider._debug.wireframe=i.wireframe,!0}),this._showGlobeDepth=d(function(){return i._scene.debugShowGlobeDepth=i.globeDepth,!0}),this._showPickDepth=d(function(){return i._scene.debugShowPickDepth=i.pickDepth,!0}),this._incrementDepthFrustum=d(function(){var e=i.depthFrustum+1;return i.depthFrustum=m(1,i._numberOfFrustums,e),i.scene.debugShowDepthFrustum=i.depthFrustum,!0}),this._decrementDepthFrustum=d(function(){var e=i.depthFrustum-1;return i.depthFrustum=m(1,i._numberOfFrustums,e),i.scene.debugShowDepthFrustum=i.depthFrustum,!0}),this._doSuspendUpdates=d(function(){return f._surface._debug.suspendLodUpdate=i.suspendUpdates,i.suspendUpdates||(i.filterTile=!1),!0});var v;this._showTileCoordinates=d(function(){return i.tileCoordinates&&!t(v)?v=e.imageryLayers.addImageryProvider(new c({tilingScheme:e.terrainProvider.tilingScheme})):!i.tileCoordinates&&t(v)&&(e.imageryLayers.remove(v),v=void 0),!0}),this._showTileBoundingSphere=d(function(){return i.tileBoundingSphere?f._surface.tileProvider._debug.boundingSphereTile=i._tile:f._surface.tileProvider._debug.boundingSphereTile=void 0,!0}),this._doFilterTile=d(function(){return i.filterTile?(i.suspendUpdates=!0,i.doSuspendUpdates(),f._surface._tilesToRender=[],t(i._tile)&&f._surface._tilesToRender.push(i._tile)):(i.suspendUpdates=!1,i.doSuspendUpdates()),!0});var _=function(e){p.removeInputAction(s.LEFT_CLICK),i.pickPrimitiveActive=!1;var r=i._scene.pick({x:e.position.x,y:e.position.y});t(r)&&(i.primitive=t(r.collection)?r.collection:r.primitive)};this._pickPrimitive=d(function(){i.pickPrimitiveActive=!i.pickPrimitiveActive,i.pickPrimitiveActive?p.setInputAction(_,s.LEFT_CLICK):p.removeInputAction(s.LEFT_CLICK)});var g=function(e){var r,n=f.ellipsoid,a=i._scene.camera.pickEllipsoid({x:e.position.x,y:e.position.y},n);if(t(a))for(var l=n.cartesianToCartographic(a),u=f._surface.tileProvider._tilesToRenderByTextureCount,c=0;!r&&c<u.length;++c){var h=u[c];if(t(h))for(var d=0;!r&&d<h.length;++d){var m=h[d];o.contains(m.rectangle,l)&&(r=m)}}i.tile=r,p.removeInputAction(s.LEFT_CLICK),i.pickTileActive=!1};this._pickTile=d(function(){i.pickTileActive=!i.pickTileActive,i.pickTileActive?p.setInputAction(g,s.LEFT_CLICK):p.removeInputAction(s.LEFT_CLICK)})};return r(f.prototype,{scene:{get:function(){return this._scene}},performanceContainer:{get:function(){return this._performanceContainer}},toggleDropDown:{get:function(){return this._toggleDropDown}},showFrustums:{get:function(){return this._showFrustums}},showPerformance:{get:function(){return this._showPerformance}},showPrimitiveBoundingSphere:{get:function(){return this._showPrimitiveBoundingSphere}},showPrimitiveReferenceFrame:{get:function(){return this._showPrimitiveReferenceFrame}},doFilterPrimitive:{get:function(){return this._doFilterPrimitive}},showWireframe:{get:function(){return this._showWireframe}},showGlobeDepth:{get:function(){return this._showGlobeDepth}},showPickDepth:{get:function(){return this._showPickDepth}},incrementDepthFrustum:{get:function(){return this._incrementDepthFrustum}},decrementDepthFrustum:{get:function(){return this._decrementDepthFrustum}},doSuspendUpdates:{get:function(){return this._doSuspendUpdates}},showTileCoordinates:{get:function(){return this._showTileCoordinates}},showTileBoundingSphere:{get:function(){return this._showTileBoundingSphere}},doFilterTile:{get:function(){return this._doFilterTile}},toggleGeneral:{get:function(){return this._toggleGeneral}},togglePrimitives:{get:function(){return this._togglePrimitives}},toggleTerrain:{get:function(){return this._toggleTerrain}},pickPrimitive:{get:function(){return this._pickPrimitive}},pickTile:{get:function(){return this._pickTile}},selectParent:{get:function(){var e=this;return d(function(){e.tile=e.tile.parent})}},selectNW:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[0]})}},selectNE:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[1]})}},selectSW:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[2]})}},selectSE:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[3]})}},primitive:{set:function(e){var r=this._primitive;e!==r&&(this.hasPickedPrimitive=!0,t(r)&&(r.debugShowBoundingVolume=!1),this._scene.debugCommandFilter=void 0,t(this._modelMatrixPrimitive)&&(this._scene.primitives.remove(this._modelMatrixPrimitive),this._modelMatrixPrimitive=void 0),this._primitive=e,e.show=!1,setTimeout(function(){e.show=!0},50),this.showPrimitiveBoundingSphere(),this.showPrimitiveReferenceFrame(),this.doFilterPrimitive())},get:function(){return this._primitive}},tile:{set:function(e){if(t(e)){this.hasPickedTile=!0;var r=this._tile;e!==r&&(this.tileText="L: "+e.level+" X: "+e.x+" Y: "+e.y,this.tileText+="<br>SW corner: "+e.rectangle.west+", "+e.rectangle.south,this.tileText+="<br>NE corner: "+e.rectangle.east+", "+e.rectangle.north,this.tileText+="<br>Min: "+e.data.minimumHeight+" Max: "+e.data.maximumHeight),this._tile=e,this.showTileBoundingSphere(),this.doFilterTile()}else this.hasPickedTile=!1,this._tile=void 0},get:function(){return this._tile}},update:{get:function(){var e=this;return function(){e.frustums&&(e.frustumStatisticText=p(e._scene.debugFrustumStatistics));var t=e._scene.numberOfFrustums;e._numberOfFrustums=t;var r=m(1,t,e.depthFrustum);e.depthFrustum=r,e.scene.debugShowDepthFrustum=r,e.depthFrustumText=r+" of "+t,e.performance&&e._performanceDisplay.update(),e.primitiveReferenceFrame&&(e._modelMatrixPrimitive.modelMatrix=e._primitive.modelMatrix),e.shaderCacheText="Cached shaders: "+e._scene.context.shaderCache.numberOfShaders}}}}),f.prototype.isDestroyed=function(){return!1},f.prototype.destroy=function(){return this._eventHandler.destroy(),i(this)},f}),r("Widgets/CesiumInspector/CesiumInspector",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./CesiumInspectorViewModel"],function(e,t,r,i,n,o,a){ +"use strict";var s=function(t,r){if(!e(t))throw new i("container is required.");if(!e(r))throw new i("scene is required.");t=o(t);var s=document.createElement("div"),l=new a(r,s);this._viewModel=l,this._container=t;var u=document.createElement("div");this._element=u;var c=document.createElement("div");c.textContent="Cesium Inspector",c.className="cesium-cesiumInspector-button",c.setAttribute("data-bind","click: toggleDropDown"),u.appendChild(c),u.className="cesium-cesiumInspector",u.setAttribute("data-bind",'css: { "cesium-cesiumInspector-visible" : dropDownVisible, "cesium-cesiumInspector-hidden" : !dropDownVisible }'),t.appendChild(this._element);var h=document.createElement("div");this._panel=h,h.className="cesium-cesiumInspector-dropDown",u.appendChild(h);var d=document.createElement("div");d.className="cesium-cesiumInspector-sectionHeader";var p=document.createElement("span");p.className="cesium-cesiumInspector-toggleSwitch",p.setAttribute("data-bind","click: toggleGeneral, text: generalSwitchText"),d.appendChild(p),d.appendChild(document.createTextNode("General")),h.appendChild(d);var m=document.createElement("div");m.className="cesium-cesiumInspector-section",m.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : generalVisible, "cesium-cesiumInspector-hide" : !generalVisible}'),h.appendChild(m);var f=document.createElement("div");m.appendChild(f);var v=document.createElement("div");v.className="cesium-cesiumInspector-frustumStats",v.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : frustums, "cesium-cesiumInspector-hide" : !frustums}, html: frustumStatisticText');var _=document.createElement("input");_.type="checkbox",_.setAttribute("data-bind","checked: frustums, click: showFrustums"),f.appendChild(_),f.appendChild(document.createTextNode("Show Frustums")),f.appendChild(v);var g=document.createElement("div");m.appendChild(g);var y=document.createElement("input");y.type="checkbox",y.setAttribute("data-bind","checked: performance, click: showPerformance"),g.appendChild(y),g.appendChild(document.createTextNode("Performance Display")),s.className="cesium-cesiumInspector-performanceDisplay",m.appendChild(s);var C=document.createElement("div");C.className="cesium-cesiumInspector-shaderCache",C.setAttribute("data-bind","html: shaderCacheText"),m.appendChild(C);var E=document.createElement("div");m.appendChild(E);var S=document.createElement("input");S.type="checkbox",S.setAttribute("data-bind","checked: globeDepth, click: showGlobeDepth"),E.appendChild(S),E.appendChild(document.createTextNode("Show globe depth"));var w=document.createElement("div");E.appendChild(w);var T=document.createElement("div");m.appendChild(T);var b=document.createElement("input");b.type="checkbox",b.setAttribute("data-bind","checked: pickDepth, click: showPickDepth"),T.appendChild(b),T.appendChild(document.createTextNode("Show pick depth"));var x=document.createElement("div");m.appendChild(x);var P=document.createElement("span");P.setAttribute("data-bind",'html: "     Frustum:"'),x.appendChild(P);var A=document.createElement("span");A.setAttribute("data-bind","text: depthFrustumText"),x.appendChild(A);var I=document.createElement("input");I.type="button",I.value="-",I.className="cesium-cesiumInspector-pickButton",I.setAttribute("data-bind","click: decrementDepthFrustum"),x.appendChild(I);var M=document.createElement("input");M.type="button",M.value="+",M.className="cesium-cesiumInspector-pickButton",M.setAttribute("data-bind","click: incrementDepthFrustum"),x.appendChild(M);var D=document.createElement("div");D.className="cesium-cesiumInspector-sectionHeader",p=document.createElement("span"),p.className="cesium-cesiumInspector-toggleSwitch",p.setAttribute("data-bind","click: togglePrimitives, text: primitivesSwitchText"),D.appendChild(p),D.appendChild(document.createTextNode("Primitives")),h.appendChild(D);var R=document.createElement("div");R.className="cesium-cesiumInspector-section",R.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : primitivesVisible, "cesium-cesiumInspector-hide" : !primitivesVisible}'),h.appendChild(R);var O=document.createElement("div");O.className="cesium-cesiumInspector-pickSection",R.appendChild(O);var N=document.createElement("input");N.type="button",N.value="Pick a primitive",N.className="cesium-cesiumInspector-pickButton",N.setAttribute("data-bind",'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickPrimitiveActive}, click: pickPrimitive');var L=document.createElement("div");L.className="cesium-cesiumInspector-center",L.appendChild(N),O.appendChild(L);var F=document.createElement("div");O.appendChild(F);var B=document.createElement("input");B.type="checkbox",B.setAttribute("data-bind","checked: primitiveBoundingSphere, click: showPrimitiveBoundingSphere, enable: hasPickedPrimitive"),F.appendChild(B),F.appendChild(document.createTextNode("Show bounding sphere"));var V=document.createElement("div");O.appendChild(V);var z=document.createElement("input");z.type="checkbox",z.setAttribute("data-bind","checked: primitiveReferenceFrame, click: showPrimitiveReferenceFrame, enable: hasPickedPrimitive"),V.appendChild(z),V.appendChild(document.createTextNode("Show reference frame"));var k=document.createElement("div");this._primitiveOnly=k,O.appendChild(k);var U=document.createElement("input");U.type="checkbox",U.setAttribute("data-bind","checked: filterPrimitive, click: doFilterPrimitive, enable: hasPickedPrimitive"),k.appendChild(U),k.appendChild(document.createTextNode("Show only selected"));var G=document.createElement("div");G.className="cesium-cesiumInspector-sectionHeader",p=document.createElement("span"),p.className="cesium-cesiumInspector-toggleSwitch",p.setAttribute("data-bind","click: toggleTerrain, text: terrainSwitchText"),G.appendChild(p),G.appendChild(document.createTextNode("Terrain")),h.appendChild(G);var W=document.createElement("div");W.className="cesium-cesiumInspector-section",W.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : terrainVisible, "cesium-cesiumInspector-hide" : !terrainVisible}'),h.appendChild(W);var H=document.createElement("div");H.className="cesium-cesiumInspector-pickSection",W.appendChild(H);var q=document.createElement("input");q.type="button",q.value="Pick a tile",q.className="cesium-cesiumInspector-pickButton",q.setAttribute("data-bind",'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickTileActive}, click: pickTile'),L=document.createElement("div"),L.appendChild(q),L.className="cesium-cesiumInspector-center",H.appendChild(L);var j=document.createElement("div");H.appendChild(j);var Y=document.createElement("input");Y.type="button",Y.value="Parent",Y.className="cesium-cesiumInspector-pickButton",Y.setAttribute("data-bind","click: selectParent");var X=document.createElement("input");X.type="button",X.value="NW",X.className="cesium-cesiumInspector-pickButton",X.setAttribute("data-bind","click: selectNW");var Z=document.createElement("input");Z.type="button",Z.value="NE",Z.className="cesium-cesiumInspector-pickButton",Z.setAttribute("data-bind","click: selectNE");var K=document.createElement("input");K.type="button",K.value="SW",K.className="cesium-cesiumInspector-pickButton",K.setAttribute("data-bind","click: selectSW");var J=document.createElement("input");J.type="button",J.value="SE",J.className="cesium-cesiumInspector-pickButton",J.setAttribute("data-bind","click: selectSE");var Q=document.createElement("div");Q.className="cesium-cesiumInspector-tileText",j.className="cesium-cesiumInspector-frustumStats",j.appendChild(Q),j.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : hasPickedTile, "cesium-cesiumInspector-hide" : !hasPickedTile}'),Q.setAttribute("data-bind","html: tileText");var $=document.createElement("div");$.className="cesium-cesiumInspector-relativeText",$.textContent="Select relative:",j.appendChild($);var ee=document.createElement("table"),te=document.createElement("tr"),re=document.createElement("tr"),ie=document.createElement("td");ie.appendChild(Y);var ne=document.createElement("td");ne.appendChild(X);var oe=document.createElement("td");oe.appendChild(Z),te.appendChild(ie),te.appendChild(ne),te.appendChild(oe);var ae=document.createElement("td"),se=document.createElement("td");se.appendChild(K);var le=document.createElement("td");le.appendChild(J),re.appendChild(ae),re.appendChild(se),re.appendChild(le),ee.appendChild(te),ee.appendChild(re),j.appendChild(ee);var ue=document.createElement("div");H.appendChild(ue);var ce=document.createElement("input");ce.type="checkbox",ce.setAttribute("data-bind","checked: tileBoundingSphere, enable: hasPickedTile, click: showTileBoundingSphere"),ue.appendChild(ce),ue.appendChild(document.createTextNode("Show bounding volume"));var he=document.createElement("div");H.appendChild(he);var de=document.createElement("input");de.type="checkbox",de.setAttribute("data-bind","checked: filterTile, enable: hasPickedTile, click: doFilterTile"),he.appendChild(de),he.appendChild(document.createTextNode("Show only selected"));var pe=document.createElement("div");W.appendChild(pe);var me=document.createElement("input");me.type="checkbox",me.setAttribute("data-bind","checked: wireframe, click: showWireframe"),pe.appendChild(me),pe.appendChild(document.createTextNode("Wireframe"));var fe=document.createElement("div");W.appendChild(fe);var ve=document.createElement("input");ve.type="checkbox",ve.setAttribute("data-bind","checked: suspendUpdates, click: doSuspendUpdates"),fe.appendChild(ve),fe.appendChild(document.createTextNode("Suspend LOD update"));var _e=document.createElement("div");W.appendChild(_e);var ge=document.createElement("input");ge.type="checkbox",ge.setAttribute("data-bind","checked: tileCoordinates, click: showTileCoordinates"),_e.appendChild(ge),_e.appendChild(document.createTextNode("Show tile coordinates")),n.applyBindings(l,this._element)};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return n.cleanNode(this._element),this._container.removeChild(this._element),this.viewModel.destroy(),r(this)},s}),r("Widgets/CesiumWidget/CesiumWidget",["../../Core/buildModuleUrl","../../Core/Cartesian3","../../Core/Clock","../../Core/Credit","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/Ellipsoid","../../Core/formatError","../../Core/requestAnimationFrame","../../Core/ScreenSpaceEventHandler","../../Scene/BingMapsImageryProvider","../../Scene/Globe","../../Scene/Moon","../../Scene/Scene","../../Scene/SceneMode","../../Scene/SkyAtmosphere","../../Scene/SkyBox","../../Scene/Sun","../getElement"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";function S(t){return e("Assets/Textures/SkyBox/tycho2t3_80_"+t+".jpg")}function w(e){function t(i){if(!e.isDestroyed())if(e._useDefaultRenderLoop)try{var n=e._targetFrameRate;if(o(n)){var a=1e3/n,s=i-r;s>a&&(e.resize(),e.render(),r=i-s%a),h(t)}else e.resize(),e.render(),h(t)}catch(l){if(e._useDefaultRenderLoop=!1,e._renderLoopRunning=!1,e._showRenderLoopErrors){var u="An error occurred while rendering. Rendering has stopped.";e.showErrorPanel(u,void 0,l)}}else e._renderLoopRunning=!1}e._renderLoopRunning=!0;var r=0;h(t)}function T(e){var t=e._canvas,r=t.clientWidth,i=t.clientHeight,o=n(window.devicePixelRatio,1)*e._resolutionScale;e._canvasWidth=r,e._canvasHeight=i,r*=o,i*=o,t.width=r,t.height=i,e._canRender=0!==r&&0!==i}function b(e){var t=e._canvas,r=t.width,i=t.height;if(0!==r&&0!==i){var n=e._scene.camera.frustum;o(n.aspectRatio)?n.aspectRatio=r/i:(n.top=n.right*(i/r),n.bottom=-n.top)}}var x="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHYAAAAaCAYAAABikagwAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB9wGGRQyF371QVsAABOHSURBVGje7Vp5cFTHmf91v2Nm3owGnYMuEEJCOBiEjDlsDMYQjGMOOwmXcWxiLywpJ9iuTXZd612corJssFOxi8LerXizxEGUvWsivNxxHHCQ8WYBYSFzmUMCCXQjaUajOd/V+4f6Kc14kI/KZv/xq+p6M/PmO15/9/c1wa0vwpcMQAHgBuAFoPG7mz8jAGwASQBxADFhJQGYACwAjK+vrr/AJQ8jVMqfuwH4AGQByAaQnTNqXGHWqHGFbq8/g1BJsgw9GQ12Bds/qWsxEvEeAEEAfQDCAKKCgPGVcP//BOsIVQHgAZAJIACgsHTqvDvK7150T2bR2DFaZm6W4slwUypR20yaiUg4OtDbcaP36rlPPt6/7f2B3q5mAB0AeriAE18J9y93kVu4X4W73BwAhQBK5v/gZ98ZVXXvDG92IJMx569MQDEoK0tPmOHu1s4L7799sH7vtvcAXAPQCaCfu2qLu+7h+Eh3sS8Bcyt48iVgPos2+4J7jS+BIx2etDBSynfH/Xq46y0CUL70n3/zXMmUuXepWoZHFCQhFIQARCBFJYV6/Nn+QHnVBH9Ovq/51JFWADpfJhcqEzyDcx9ukTTr/xr2VnDpng0nuHR0h1u3wvWF6EspgBIAFYAfQAGAsuU/rfm7kePvvJ0QiTj6QSgBISS9ujEGSikkxaXklIwfK8uK2Xru2HVurWKspZyezGmmWwp/LqVsupPQub4grPQ5YIejKQvPJAGflLLJSBGmxPEqKXhU4XdJEBq7BR5Z+L+DKx3MTTHWEaybx9WCud/btCJQMeX2Qevk+NPoks0YPArF/RUj0NyXxOmO2CAy1a1OmL9yUVfTmatXTx52EildYFQVNlgRmBR1xQJgCBbPBAVUhcw8lTObLz0FVk4RIEmJJyJNZzFBiCTFBRL+f50rriFUATRFiZSU/XYEAw6X5LlIUghZqXvl5p8pfycRZsgjymlKGw1Adm7JbRUVs785nwGghP5pp9mfFMOxWstmuC3gwdcrRqA/buJUWwyKRMAYgydrZNZt9337623njn+ixyN9nAmdM5nBvYOPfxc3mnEmTQ4T5VZv8hfz8aUKnocJd5tvVhxAhOMADzNefleFjRUFa/D/xzi8LQhIEpTG4VXnNBzlZYISufk7juCfqaAoLkHYcZ6HBAEM8O+ObJz3HcFDpJfDJwWYfiHMMTklviocKHv6I3+zRFLdKhEEatmALBFIBIibNhQ6KFyJEjT2JHDoUj/a+nVIVIBhBGOnzptWXzhmTFfT2TZBOH4AgSeeeGJqRUVFqdfr9btcLnVQXwapmqZpJZPJRCgUCh47duzie++9dwWAXl5enrlp06bF0WhUM01TYYwRrmg2vzNKqS3Lsunz+Yy6urpTP//5z09blkVLSkryVq9ePT03NzegqqqbUnqTGyOEMNM0k319fX2///3vz9bW1l4DYD700EPFy5Ytm65pmvbBBx9c2rp166Wnnnqq7MEHH5zAGIu8/vrr+w8ePPgJVwrRO2gAcg8cOLA2mUx62tvbB9avX39s+fLlo++///5JXNiwbXugpqam9tChQ2cEj6NzuQwlsi+//PKSzMzMQtu2qcfjMZqbm09v2LDht4J3sQEQOU2Jo8mKKzt7VEU5lSgFBi3PZkBZrgv3lGbCo1Jc7I7iSGN40JcQgoGkhXdO94ESQJEoGI+1k/M9mDKqQHEv++akl186e45rNAAE3njjjccWLFhwfyAQyJEkiabGbcc7JJNJva2trX3Lli3vvPbaa+eKi4uLV6xY8d10cf5TcZ8x5OXl5b366qs9lFLtrbfeWldVVXW7pmkuxhjS0SSEIJlMGitXrrz2/PPPv1lTU3NtypQp0x955JG/kmVZdrlcR7du3WrOnTt33pIlS+YDwNGjR68ePHiwjVtukm+wI9ichQsXPgUAHR0d3evXr78xc+bMu9asWbOQUjpENz8/v/jQoUP/IiiH40UzAeQvW7Zs1rp16/7a5/NpDr/19fWlGzZsOM4tNsphkc5iPaXTvl6uuDUvY4MZLwNQ4Ffw+LR8+KQQTCuJSQUFcMsEe88FoSkSKCFwyWSISQbg9pEefHdGAJHIdUydVjFecL3K448/Pm3hwoUPBAKBHFGIlmU5pRCRpMGEze12q2PHjh2zatWqeTt37gwODAxkOQIJhUJ6Y2Njn6IojFJqE0KYsGyPx0POnTvXnUgkfGvXrr1j5syZU7iFsKampv5YLBZ34GzbJgAwatSo7MzMTE95eXnZT37yk0dramr+PRQKZSQSCdPn88nBYNADID8UCmkAYBiGGQ6Hna6cksbdZliWZUuSRKPRKAAUBINBfywWM30+n+yEtenTp9+5YsWKGTt37oxwz+a44RwARc8+++xSr9eriQrY398v8311CUncTTHN0Q7Vl1OQJymq4iBwyxQPT8qDVwri1d1/i8ttp/AP39mOBeMn41pQx9mOGFSZ3qT52ZqMR6aMRGvXKfzbgX9Ea3PnSLEdOWXKlK/5/X4/AFy8ePHG6tWr90QikS5VVaOEEIsxRhljngcffLBi8+bNjxBCUFJSMrKkpMRvGIbboXP27Nn+2bNn/3cgEIgSQmKEEAOARQixKKVxRVEioVAoYtu2dMcdd4x24Hbv3t3+ox/96ONoNBqklMa4ppNkMinNnz8///nnn6/y+Xw0mUxaANy6rrsdl28YhguAX9d1F98jwn9TUjJkJ5N1DWV0ti0ByDAMw+PsbzQatX0+Hy0oKMhcvnz5nP3791+IxWJRIUaPfO655+ZVVlaOA4BoNGprmkZ5uJJThZouKyYAqOrWVEKoE7cwszQDlQUK3jr8S5y++iEIIXh55/fwylOH8e3KHHSEdfQnLFBuRbJEsLQyF27Sh3eO/iuudV+EaSuqkJF6MjMzs9xutwIAv/rVr06eOHHiEwCtPBHQOaPaxYsXLxcXF8cKCwtzOzo6+ltbW4OFhYU+h2nDMAgAqbu7W8xkLSEBcsos1bbtocZIIBBQs7Ky5Pb2dkvXdV1wfaipqemsqak5yF1bFABljNEU4Sj87nia1LKHCJWGLLh6AkDhiksAoLq6um/VqlWZWVlZ8gMPPHDHwoULK2tqasJcYJ7y8vKyb33rW/f4/X43YwybNm26vnnz5pIUb0tvVe44maSVjEfizDJtmwFlOS4srczGiQvv4ncnd4ASAkIo+mN92LLrB/j7Vb/GQxOz8Z/1PTDsQXc6p3QEqopU7Dr6S5y8fAiKpCKhs6SQSUqyLKsO4d7e3j4AvbxD1csFQQF4EolEaP369TVCFjuiqKiogG8w5s6dm8sY++ZwcfbZZ5/dvHXr1isnT55scVz+rFmz8urr6xc4Ls22bZZIJExd181oNGr09PREDx06dPmFF144Ho/HTVGIjiE4guECoyl1LYTPcppGEAghDAAikUjixRdfbHnppZfKfD6fa82aNfMOHz7cHgwGbwBwr1ix4u677rqrgsfU4I4dO66lCPZTXSkqpOaMa60e7mjuosw0RmYoWHf3SLT3NOKt91+CbsZBeOlDCcX5luP4rw9fw4wSH+4p9cMlU3xtpAfLJmej/vIR7PnjLyDRwXeKhoxubokWAOYkDXxTLE5brB11oTZMCrWoNQgymJwZhsHC4bAZjUaNaDRqxGIx3VnxeDzJky8TQGLHjh3n9u3bd6ytrS3U2dkZ6e3tjfX398cHBgYS8XjcIIQQr9frKioq8ldWVhb88Ic/vHfbtm3zAXhs25aHUx7uEt1COeXEXM3JfAWLvWnSxRhLbNu2rampqSlMCME3vvGNyXPmzKkCUFZeXn776tWr72WMwbZtvPDCCx+5XK6wo6BcOdhwQ4Chuu/KR39onDGS9T80u9ivkgiqD/0UbT2NcKvelMaEhXfrqlGaPwEPT5qH0lwvqopcaOtpxPb3/gmGmYBEFRBC0HUlfp67tQQALxMKYsaYU+tlcSadNN8NIOO+++4bnZ2d7Q+Hw+zIkSNJxtiQ9TQ1NUW3bNnSmJWVlZBlWaeUWs5SVTUxYsSIRF1dXScAwzTN2MMPP7w3Pz//ZFVVVUFubq7L6/VKmqZRl8ulKIriVlVVmz59ev6cOXMCLpeLLliwYDyAOpGm08SglA659mQy6eHTrwiPtRYXbi6vP2/yjI61AoDL5Ur09vZ2bt++/ezGjRvvppSSjRs3Lti9e/fvnnzyyfHjx48fyRjDwYMHL9TW1jYWFhZ6xfIs3UhUTlPQRwGE9Gv/c/ba9YGi2rPv0FONf/iUUB3Lj8SDqD60GYtmdGBcYSVOnL+K39b9Gp19zVDkwZzBSpLY9Qv9Z3lKHgOgmaYZd9zg1KlTS994441L3G3lcD6oo/1btmxZFwgEctrb27vWrFlzwLIs2cmKW1pa4q+//vp1AbchdIKiPGZHAJDFixcHpk+ffnsoFNLefvvt3ra2Nl0YSDhdt4zy8vLwsWPHsl0ul6ooigSACuEZXKBJwzAMxhhUVZW8Xm8uH5hQ3mCwOf95VVVVYx03yQVhUEpNQbBxADfefPPN6NKlS8dUVlYWVlZW5r344osz1q1bV8IYQzAYjFVXV5+IxWIdkiTlpfDCUgcC6Sw2CqBvw4ZN+7/9d+Wzo1avT5HU9N1tMpj4dfU14z/efxletx9xPYpIPAhVccO2bVBKcf189I/h3mSLkBi5b9y40RWLxZJer9f12GOPTa6oqMjq6enpJYQYlFLGyx21tLQ0MGnSpDGEECQSCZMQIjuNCF6aqI8++mheVlZWJrdYkzcoLEVREj6fL1FfX39x165dzfPnzy/7/ve/v1LXdWvlypVde/bsuRKLxQyn1LEsS2aMeebNm1fs8/lkxhgsy7IAJBRF0Yc2TZZ1AANNTU0djoJt2rRpzqxZs/K6urq6JUnSCSHMMAxZ07SsxYsXV1JKCWMMAwMDMQBhVVWTjtU6gr1y5Yq1d+/ej8aNG5eraZr6zDPPjPV4PBJjDLW1ted27dr1MYCYqqpDcpMkyRIaEyydxToxNgagr7e3t+XEe0rNxPkjnvhTznNr4Sb0KBL6YO9BovJQnRXptTqaPgr9wTLsDgAhTkOurq4+unz58vs1TRvl9/vVuXPnljHGxgqxw2GcEjLYJLlw4cKV06dPd06bNo04+MePH+/ftm3bNNG1iW5KVVVl//79ew4cONC8d+/ey88884ysKIp85513jpo8eXJh2pHX4EUIITh58uRFAN1utzvHcb0ejycGoKuurk5vbW29u7i4ODB69OisJ5988i4xxDhsKIoiEUJgmqZ94MCBOgBdmqaVODxrmhbhiaP+4x//+N2lS5dOmjBhwhiPxyMBQFdXV191dfX7tm23AdBdLtdQzFYUxWmb3iRcmqbh7vQfOz9+v/PdjvP6kcHuE288MJZWuM4Smw1mgkQvHw/v6Wga+BjADY53AEDfmTNnLq9du/Znp06datB13RA3ROwGmaZphcPhgX379v326aefftO27Tafz9fJGGOmadqMMSbLMpEkiaZbjDFommYQQsK1tbWNr7zyymvhcLifEIJbwRBCmGVZ1vHjxz9atGjRLwA0Z2dndzpdHb/fHwTQcuLEiYann3761fPnz3+i67pBCCGUUkoIofwjpZQS27ZZd3f3ja1bt1Zv3LhxL4CrmZmZPYQQkxCCjIyMEIB2AG0Amrdv3/6beDweNwzD1nXdPHXq1Indu3cf48+7MjIyupw98ng8EW4wCWH4kHbQLgsnJ4oAlN332Ji1hbeps6lEaLohQLrhQCJi9zcei77TcLh9H4CrALp4rLN5LBvBE4scAP6JEyfmBQIBL6VUopSCMcYGBgYSly5dCvX19YW5QkQAmD6fz3PvvfeWxmIxr2EYHqFXPBRrKKWWJEmG1+uNtbW1dTU0NNzgz7wA/OXl5bkFBQV+XsYQwVpZMpk0jh8/3snpRQCYo0aN8k6YMCHX5XLRa9euBRsaGnr4Jnp458c7ceLEbK/X6xL5MQzDbGhoCNq2HeO4YgBYWVmZv6KiIkdVVbS0tHQ3NDR0CsORrDlz5oyllHoYY3p9ff31cDjczeGhaVrGkiVLSg3DkLu7u/s+/PDDFn4UKeJYLhnmAJvGs9QCAKOnLMhfNHqSNl/LlHOpTORbWa4et2ORXqv1wgf9NVfO9B7nTYcuPvlICq02t9CJ8ggjOJomodOF0ZQtHNvxCC08pBnbmcIhO53jdA7mpXaKUkOSWGoxYaaKlIa7IozT0uET+XDGehDGhhBGb6bTmBHezeb8OyNPCPQk/ptzeHConCSfcZDNI1hWQXaBVl5254hZmSPVce4MKUdxEQ+VJMnUbcNIWJFoyOzoa02eOX2k+yg/79TFNWkgZchOUobe4vA63WzUEmpYsa+dCoM0Izgz5aQkTUOPpGvUpKFJBaUR8Q03cLdT8NkppyEgPGOCYcnCiNASsn2SwrstDA2Gxnbkc5xSdHGrcmaBWYoqZ+YUe4pcXuqXJCobupWIhaze3vZohzAfdOaKN2mSwPxwR0ZSZ6uptZoIN9yxFCYIiqV5v3THStgwNNPhvtXxFgzDP9K8q52Cj6ZRNnaLffoUDfI5zhVLgrvxCN0Ux5URYXYYF84Wf2qqf4uDV591ZuiLHir7c8F+mZOU5M+Iazg8n3mYjnxORkV3I6dxg6KrMQW3Yaexlq+uv8D1v2IL+t4z3B/NAAAAAElFTkSuQmCC",P=function(e,a){e=E(e),a=n(a,{});var s=document.createElement("div");s.className="cesium-widget",e.appendChild(s);var l=document.createElement("canvas");l.oncontextmenu=function(){return!1},l.onselectstart=function(){return!1},s.appendChild(l);var c=document.createElement("div");c.className="cesium-widget-credits";var h=o(a.creditContainer)?E(a.creditContainer):s;h.appendChild(c);var w=n(a.showRenderLoopErrors,!0);this._element=s,this._container=e,this._canvas=l,this._canvasWidth=0,this._canvasHeight=0,this._creditContainer=c,this._canRender=!1,this._renderLoopRunning=!1,this._showRenderLoopErrors=w,this._resolutionScale=1,this._forceResize=!1,this._clock=o(a.clock)?a.clock:new r,T(this);try{var P=new v({canvas:l,contextOptions:a.contextOptions,creditContainer:c,mapProjection:a.mapProjection,orderIndependentTranslucency:a.orderIndependentTranslucency,scene3DOnly:n(a.scene3DOnly,!1)});this._scene=P,P.camera.constrainedAxis=t.UNIT_Z,b(this);var A=n(P.mapProjection.ellipsoid,u.WGS84),I=P.frameState.creditDisplay,M=new i("Cesium",x,"http://cesiumjs.org/");I.addDefaultCredit(M);var D=a.globe;o(D)||(D=new m(A)),D!==!1&&(P.globe=D);var R=a.skyBox;o(R)||(R=new y({sources:{positiveX:S("px"),negativeX:S("mx"),positiveY:S("py"),negativeY:S("my"),positiveZ:S("pz"),negativeZ:S("mz")}})),R!==!1&&(P.skyBox=R,P.sun=new C,P.moon=new f);var O=a.skyAtmosphere;o(O)||(O=new g(A)),O!==!1&&(P.skyAtmosphere=O);var N=a.globe===!1?!1:a.imageryProvider;o(N)||(N=new p({url:"//dev.virtualearth.net"})),N!==!1&&P.imageryLayers.addImageryProvider(N),o(a.terrainProvider)&&a.globe!==!1&&(P.terrainProvider=a.terrainProvider),this._screenSpaceEventHandler=new d(l,!1),o(a.sceneMode)&&(a.sceneMode===_.SCENE2D&&this._scene.morphTo2D(0),a.sceneMode===_.COLUMBUS_VIEW&&this._scene.morphToColumbusView(0)),this._useDefaultRenderLoop=void 0,this.useDefaultRenderLoop=n(a.useDefaultRenderLoop,!0),this._targetFrameRate=void 0,this.targetFrameRate=a.targetFrameRate;var L=this;P.renderError.addEventListener(function(e,t){if(L._useDefaultRenderLoop=!1,L._renderLoopRunning=!1,L._showRenderLoopErrors){var r="An error occurred while rendering. Rendering has stopped.";L.showErrorPanel(r,void 0,t)}})}catch(F){if(w){var B="Error constructing CesiumWidget.",V='Visit <a href="http://get.webgl.org">http://get.webgl.org</a> to verify that your web browser and hardware support WebGL. Consider trying a different web browser or updating your video drivers. Detailed error information is below:';this.showErrorPanel(B,V,F)}throw F}};return a(P.prototype,{container:{get:function(){return this._container}},canvas:{get:function(){return this._canvas}},creditContainer:{get:function(){return this._creditContainer}},scene:{get:function(){return this._scene}},imageryLayers:{get:function(){return this._scene.imageryLayers}},terrainProvider:{get:function(){return this._scene.terrainProvider},set:function(e){this._scene.terrainProvider=e}},camera:{get:function(){return this._scene.camera}},clock:{get:function(){return this._clock}},screenSpaceEventHandler:{get:function(){return this._screenSpaceEventHandler}},targetFrameRate:{get:function(){return this._targetFrameRate},set:function(e){if(0>=e)throw new l("targetFrameRate must be greater than 0.");this._targetFrameRate=e}},useDefaultRenderLoop:{get:function(){return this._useDefaultRenderLoop},set:function(e){this._useDefaultRenderLoop!==e&&(this._useDefaultRenderLoop=e,e&&!this._renderLoopRunning&&w(this))}},resolutionScale:{get:function(){return this._resolutionScale},set:function(e){if(0>=e)throw new l("resolutionScale must be greater than 0.");this._resolutionScale=e,this._forceResize=!0}}}),P.prototype.showErrorPanel=function(e,t,r){var i=this._element,n=document.createElement("div");n.className="cesium-widget-errorPanel";var a=document.createElement("div");a.className="cesium-widget-errorPanel-content",n.appendChild(a);var s=document.createElement("div");s.className="cesium-widget-errorPanel-header",s.appendChild(document.createTextNode(e)),a.appendChild(s);var l=document.createElement("div");l.className="cesium-widget-errorPanel-scroll",a.appendChild(l);var u=function(){l.style.maxHeight=Math.max(Math.round(.9*i.clientHeight-100),30)+"px"};if(u(),o(window.addEventListener)&&window.addEventListener("resize",u,!1),o(t)){var h=document.createElement("div");h.className="cesium-widget-errorPanel-message",h.innerHTML="<p>"+t+"</p>",l.appendChild(h)}var d="(no error details available)";o(r)&&(d=c(r));var p=document.createElement("div");p.className="cesium-widget-errorPanel-message",p.appendChild(document.createTextNode(d)),l.appendChild(p);var m=document.createElement("div");m.className="cesium-widget-errorPanel-buttonPanel",a.appendChild(m);var f=document.createElement("button");f.setAttribute("type","button"),f.className="cesium-button",f.appendChild(document.createTextNode("OK")),f.onclick=function(){o(u)&&o(window.removeEventListener)&&window.removeEventListener("resize",u,!1),i.removeChild(n)},m.appendChild(f),i.appendChild(n),"undefined"!=typeof console&&console.error(e+"\n"+t+"\n"+d)},P.prototype.isDestroyed=function(){return!1},P.prototype.destroy=function(){this._scene=this._scene&&this._scene.destroy(),this._container.removeChild(this._element),s(this)},P.prototype.resize=function(){var e=this._canvas,t=e.clientWidth,r=e.clientHeight;(this._forceResize||this._canvasWidth!==t||this._canvasHeight!==r)&&(this._forceResize=!1,T(this),b(this))},P.prototype.render=function(){if(this._canRender){this._scene.initializeFrame();var e=this._clock.tick();this._scene.render(e)}else this._clock.tick()},P}),r("Widgets/ClockViewModel",["../Core/Clock","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/EventHelper","../Core/JulianDate","../ThirdParty/knockout"],function(e,t,r,i,n,o,a){"use strict";var s=function(r){t(r)||(r=new e),this._clock=r,this._eventHelper=new n,this._eventHelper.add(r.onTick,this.synchronize,this);var i=a.observable(r.startTime);i.equalityComparer=o.equals,this.systemTime=a.observable(o.now()),this.systemTime.equalityComparer=o.equals,a.track(this,["systemTime"]),this.startTime=void 0,a.defineProperty(this,"startTime",{get:i,set:function(e){i(e),r.startTime=e}});var s=a.observable(r.stopTime);s.equalityComparer=o.equals,this.stopTime=void 0,a.defineProperty(this,"stopTime",{get:s,set:function(e){r.stopTime=e,s(e)}});var l=a.observable(r.currentTime);l.equalityComparer=o.equals,this.currentTime=void 0,a.defineProperty(this,"currentTime",{get:l,set:function(e){r.currentTime=e,l(e)}});var u=a.observable(r.multiplier);this.multiplier=void 0,a.defineProperty(this,"multiplier",{get:u,set:function(e){r.multiplier=e,u(e)}});var c=a.observable(r.clockStep);c.equalityComparer=function(e,t){return e===t},this.clockStep=void 0,a.defineProperty(this,"clockStep",{get:c,set:function(e){c(e),r.clockStep=e}});var h=a.observable(r.clockRange);h.equalityComparer=function(e,t){return e===t},this.clockRange=void 0,a.defineProperty(this,"clockRange",{get:h,set:function(e){h(e),r.clockRange=e}});var d=a.observable(r.canAnimate);this.canAnimate=void 0,a.defineProperty(this,"canAnimate",{get:d,set:function(e){d(e),r.canAnimate=e}});var p=a.observable(r.shouldAnimate);this.shouldAnimate=void 0,a.defineProperty(this,"shouldAnimate",{get:p,set:function(e){p(e),r.shouldAnimate=e}})};return r(s.prototype,{clock:{get:function(){return this._clock}}}),s.prototype.synchronize=function(){var e=this._clock,t=e.startTime,r=e.stopTime,i=e.currentTime,n=e.multiplier,a=e.clockStep,s=e.clockRange,l=e.canAnimate,u=e.shouldAnimate;this.systemTime=o.now(),this.startTime=t,this.stopTime=r,this.currentTime=i,this.multiplier=n,this.clockStep=a,this.clockRange=s,this.canAnimate=l,this.shouldAnimate=u},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){this._eventHelper.removeAll(),i(this)},s}),r("Widgets/Command",["../Core/DeveloperError"],function(e){"use strict";var t=function(){this.canExecute=void 0,this.beforeExecute=void 0,this.afterExecute=void 0,e.throwInstantiationError()};return t}),r("Widgets/FullscreenButton/FullscreenButtonViewModel",["../../Core/defaultValue","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/Fullscreen","../../ThirdParty/knockout","../createCommand","../getElement"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){var r=this,i=o.observable(n.fullscreen),l=o.observable(n.enabled);this.isFullscreen=void 0,o.defineProperty(this,"isFullscreen",{get:function(){return i()}}),this.isFullscreenEnabled=void 0,o.defineProperty(this,"isFullscreenEnabled",{get:function(){return l()},set:function(e){l(e&&n.enabled)}}),this.tooltip=void 0,o.defineProperty(this,"tooltip",function(){return this.isFullscreenEnabled?i()?"Exit full screen":"Full screen":"Full screen unavailable"}),this._command=a(function(){n.fullscreen?n.exitFullscreen():n.requestFullscreen(r._fullscreenElement)},o.getObservable(this,"isFullscreenEnabled")),this._fullscreenElement=e(s(t),document.body),this._callback=function(){i(n.fullscreen)},document.addEventListener(n.changeEventName,this._callback)};return t(l.prototype,{fullscreenElement:{get:function(){return this._fullscreenElement},set:function(e){this._fullscreenElement=e}},command:{get:function(){return this._command}}}),l.prototype.isDestroyed=function(){return!1},l.prototype.destroy=function(){document.removeEventListener(n.changeEventName,this._callback),r(this)},l}),r("Widgets/FullscreenButton/FullscreenButton",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./FullscreenButtonViewModel"],function(e,t,r,i,n,o,a){"use strict";var s="M 83.96875 17.5625 L 83.96875 17.59375 L 76.65625 24.875 L 97.09375 24.96875 L 76.09375 45.96875 L 81.9375 51.8125 L 102.78125 30.9375 L 102.875 51.15625 L 110.15625 43.875 L 110.1875 17.59375 L 83.96875 17.5625 z M 44.125 17.59375 L 17.90625 17.625 L 17.9375 43.90625 L 25.21875 51.1875 L 25.3125 30.96875 L 46.15625 51.8125 L 52 45.96875 L 31 25 L 51.4375 24.90625 L 44.125 17.59375 z M 46.0625 76.03125 L 25.1875 96.875 L 25.09375 76.65625 L 17.8125 83.9375 L 17.8125 110.21875 L 44 110.25 L 51.3125 102.9375 L 30.90625 102.84375 L 51.875 81.875 L 46.0625 76.03125 z M 82 76.15625 L 76.15625 82 L 97.15625 103 L 76.71875 103.0625 L 84.03125 110.375 L 110.25 110.34375 L 110.21875 84.0625 L 102.9375 76.8125 L 102.84375 97 L 82 76.15625 z",l="M 104.34375 17.5625 L 83.5 38.4375 L 83.40625 18.21875 L 76.125 25.5 L 76.09375 51.78125 L 102.3125 51.8125 L 102.3125 51.78125 L 109.625 44.5 L 89.1875 44.40625 L 110.1875 23.40625 L 104.34375 17.5625 z M 23.75 17.59375 L 17.90625 23.4375 L 38.90625 44.4375 L 18.5 44.53125 L 25.78125 51.8125 L 52 51.78125 L 51.96875 25.53125 L 44.6875 18.25 L 44.625 38.46875 L 23.75 17.59375 z M 25.6875 76.03125 L 18.375 83.3125 L 38.78125 83.40625 L 17.8125 104.40625 L 23.625 110.25 L 44.5 89.375 L 44.59375 109.59375 L 51.875 102.3125 L 51.875 76.0625 L 25.6875 76.03125 z M 102.375 76.15625 L 76.15625 76.1875 L 76.1875 102.4375 L 83.46875 109.71875 L 83.5625 89.53125 L 104.40625 110.375 L 110.25 104.53125 L 89.25 83.53125 L 109.6875 83.46875 L 102.375 76.15625 z",u=function(e,t){e=o(e);var r=new a(t);r._exitFullScreenPath=l,r._enterFullScreenPath=s;var i=document.createElement("button");i.type="button",i.className="cesium-button cesium-fullscreenButton",i.setAttribute("data-bind","attr: { title: tooltip },click: command,enable: isFullscreenEnabled,cesiumSvgPath: { path: isFullscreen ? _exitFullScreenPath : _enterFullScreenPath, width: 128, height: 128 }"),e.appendChild(i),n.applyBindings(r,i),this._container=e,this._viewModel=r,this._element=i};return t(u.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),u.prototype.isDestroyed=function(){return!1},u.prototype.destroy=function(){return this._viewModel.destroy(),n.cleanNode(this._element),this._container.removeChild(this._element),r(this)},u}),r("Widgets/Geocoder/GeocoderViewModel",["../../Core/BingMapsApi","../../Core/Cartesian3","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/Event","../../Core/loadJsonp","../../Core/Matrix4","../../Core/Rectangle","../../Scene/SceneMode","../../ThirdParty/knockout","../../ThirdParty/when","../createCommand"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){e._scene.camera.flyTo({destination:t,complete:function(){e._complete.raiseEvent()},duration:e._flightDuration,endTransform:l.IDENTITY,convert:!1})}function f(e){var r=e.searchText;if(!/^\s*$/.test(r)){var i=r.match(/[^\s,\n]+/g);if(2===i.length||3===i.length){var n=+i[0],o=+i[1],a=3===i.length?+i[2]:300;if(!isNaN(n)&&!isNaN(o)&&!isNaN(a))return void m(e,t.fromDegrees(n,o,a))}e._isSearchInProgress=!0;var l=s(e._url+"REST/v1/Locations",{parameters:{query:r,key:e._key},callbackParameterName:"jsonp"}),c=e._geocodeInProgress=d(l,function(t){if(!c.cancel){if(e._isSearchInProgress=!1,0===t.resourceSets.length)return void(e.searchText=e._searchText+" (not found)");var r=t.resourceSets[0];if(0===r.resources.length)return void(e.searchText=e._searchText+" (not found)");var i=r.resources[0];e._searchText=i.name;var n=i.bbox,o=n[0],a=n[1],s=n[2],l=n[3];m(e,u.fromDegrees(a,o,l,s))}},function(){ +c.cancel||(e._isSearchInProgress=!1,e.searchText=e._searchText+" (error)")})}}function v(e){e._isSearchInProgress=!1,i(e._geocodeInProgress)&&(e._geocodeInProgress.cancel=!0,e._geocodeInProgress=void 0)}var _=function(t){this._url=r(t.url,"//dev.virtualearth.net/"),this._url.length>0&&"/"!==this._url[this._url.length-1]&&(this._url+="/"),this._key=e.getKey(t.key),this._scene=t.scene,this._flightDuration=t.flightDuration,this._searchText="",this._isSearchInProgress=!1,this._geocodeInProgress=void 0,this._complete=new a;var i=this;this._searchCommand=p(function(){i.isSearchInProgress?v(i):f(i)}),h.track(this,["_searchText","_isSearchInProgress"]),this.isSearchInProgress=void 0,h.defineProperty(this,"isSearchInProgress",{get:function(){return this._isSearchInProgress}}),this.searchText=void 0,h.defineProperty(this,"searchText",{get:function(){return this.isSearchInProgress?"Searching...":this._searchText},set:function(e){this._searchText=e}}),this.flightDuration=void 0,h.defineProperty(this,"flightDuration",{get:function(){return this._flightDuration},set:function(e){this._flightDuration=e}})};return n(_.prototype,{url:{get:function(){return this._url}},key:{get:function(){return this._key}},complete:{get:function(){return this._complete}},scene:{get:function(){return this._scene}},search:{get:function(){return this._searchCommand}}}),_}),r("Widgets/Geocoder/Geocoder",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./GeocoderViewModel"],function(e,t,r,i,n,o,a,s){"use strict";var l="M29.772,26.433l-7.126-7.126c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127L29.772,26.433zM7.203,13.885c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486c-0.007,3.58-2.905,6.476-6.484,6.484C10.106,20.361,7.209,17.465,7.203,13.885z",u="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z",c=function(e){var t=a(e.container),r=new s(e);r._startSearchPath=l,r._stopSearchPath=u;var i=document.createElement("form");i.setAttribute("data-bind","submit: search");var c=document.createElement("input");c.type="search",c.className="cesium-geocoder-input",c.setAttribute("placeholder","Enter an address or landmark..."),c.setAttribute("data-bind",'value: searchText,valueUpdate: "afterkeydown",disable: isSearchInProgress,css: { "cesium-geocoder-input-wide" : searchText.length > 0 }'),i.appendChild(c);var h=document.createElement("span");h.className="cesium-geocoder-searchButton",h.setAttribute("data-bind","click: search,cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, width: 32, height: 32 }"),i.appendChild(h),t.appendChild(i),o.applyBindings(r,i),this._container=t,this._viewModel=r,this._form=i,this._onInputBegin=function(e){t.contains(e.target)||c.blur()},this._onInputEnd=function(e){t.contains(e.target)&&c.focus()},n.supportsPointerEvents()?(document.addEventListener("pointerdown",this._onInputBegin,!0),document.addEventListener("pointerup",this._onInputEnd,!0)):(document.addEventListener("mousedown",this._onInputBegin,!0),document.addEventListener("mouseup",this._onInputEnd,!0),document.addEventListener("touchstart",this._onInputBegin,!0),document.addEventListener("touchend",this._onInputEnd,!0))};return t(c.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return n.supportsPointerEvents()?(document.removeEventListener("pointerdown",this._onInputBegin,!0),document.removeEventListener("pointerup",this._onInputEnd,!0)):(document.removeEventListener("mousedown",this._onInputBegin,!0),document.removeEventListener("mouseup",this._onInputEnd,!0),document.removeEventListener("touchstart",this._onInputBegin,!0),document.removeEventListener("touchend",this._onInputEnd,!0)),o.cleanNode(this._form),this._container.removeChild(this._form),r(this)},c}),r("Widgets/HomeButton/HomeButtonViewModel",["../../Core/Cartesian3","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/Matrix4","../../Core/Rectangle","../../Scene/Camera","../../Scene/SceneMode","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(t,i){var n=t.mode;if(r(t)&&n===l.MORPHING&&t.completeMorph(),n===l.SCENE2D)t.camera.flyTo({destination:a.MAX_VALUE,duration:i,endTransform:o.IDENTITY});else if(n===l.SCENE3D){var u=t.camera.getRectangleCameraCoordinates(s.DEFAULT_VIEW_RECTANGLE),c=e.magnitude(u);c+=c*s.DEFAULT_VIEW_FACTOR,e.normalize(u,u),e.multiplyByScalar(u,c,u),t.camera.flyTo({destination:u,duration:i,endTransform:o.IDENTITY})}else if(n===l.COLUMBUS_VIEW){var h=t.globe.ellipsoid.maximumRadius,p=new e(0,-1,1);p=e.multiplyByScalar(e.normalize(p,p),5*h,p),t.camera.flyTo({destination:p,duration:i,orientation:{heading:0,pitch:-Math.acos(e.normalize(p,d).z),roll:0},endTransform:o.IDENTITY,convert:!1})}}var d=new e,p=function(e,t){this._scene=e,this._duration=t;var r=this;this._command=c(function(){h(r._scene,r._duration)}),this.tooltip="View Home",u.track(this,["tooltip"])};return i(p.prototype,{scene:{get:function(){return this._scene}},command:{get:function(){return this._command}},duration:{get:function(){return this._duration},set:function(e){this._duration=e}}}),p}),r("Widgets/HomeButton/HomeButton",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./HomeButtonViewModel"],function(e,t,r,i,n,o,a){"use strict";var s=function(e,t,r){e=o(e);var i=new a(t,r);i._svgPath="M14,4l-10,8.75h20l-4.25-3.7188v-4.6562h-2.812v2.1875l-2.938-2.5625zm-7.0938,9.906v10.094h14.094v-10.094h-14.094zm2.1876,2.313h3.3122v4.25h-3.3122v-4.25zm5.8442,1.281h3.406v6.438h-3.406v-6.438z";var s=document.createElement("button");s.type="button",s.className="cesium-button cesium-toolbar-button cesium-home-button",s.setAttribute("data-bind","attr: { title: tooltip },click: command,cesiumSvgPath: { path: _svgPath, width: 28, height: 28 }"),e.appendChild(s),n.applyBindings(i,s),this._container=e,this._viewModel=i,this._element=s};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return n.cleanNode(this._element),this._container.removeChild(this._element),r(this)},s}),r("Widgets/InfoBox/InfoBoxViewModel",["../../Core/defined","../../Core/defineProperties","../../Core/Event","../../ThirdParty/knockout"],function(e,t,r,i){"use strict";var n="M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4853444 22.104033 11.423165 24.0625 13.84375 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 8.975298 28.305952 7.03125 25.875 7.03125 L 13.84375 7.03125 z",o="M 27.34375 1.65625 L 5.28125 27.9375 L 8.09375 30.3125 L 30.15625 4.03125 L 27.34375 1.65625 z M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4724893 20.232036 9.5676108 20.7379 9.75 21.21875 L 21.65625 7.03125 L 13.84375 7.03125 z M 28.21875 7.71875 L 14.53125 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 9.8371439 29.456025 8.4902779 28.21875 7.71875 z",a=function(){this._cameraClicked=new r,this._closeClicked=new r,this.maxHeight=500,this.enableCamera=!1,this.isCameraTracking=!1,this.showInfo=!1,this.titleText="",this.description="",i.track(this,["showInfo","titleText","description","maxHeight","enableCamera","isCameraTracking"]),this._loadingIndicatorHtml='<div class="cesium-infoBox-loadingContainer"><span class="cesium-infoBox-loading"></span></div>',this.cameraIconPath=void 0,i.defineProperty(this,"cameraIconPath",{get:function(){return!this.enableCamera||this.isCameraTracking?o:n}}),i.defineProperty(this,"_bodyless",{get:function(){return!e(this.description)||0===this.description.length}})};return a.prototype.maxHeightOffset=function(e){return this.maxHeight-e+"px"},t(a.prototype,{cameraClicked:{get:function(){return this._cameraClicked}},closeClicked:{get:function(){return this._closeClicked}}}),a}),r("Widgets/InfoBox/InfoBox",["../../Core/buildModuleUrl","../../Core/Color","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","../subscribeAndEvaluate","./InfoBoxViewModel"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(i){i=s(i);var n=document.createElement("div");n.className="cesium-infoBox",n.setAttribute("data-bind",'css: { "cesium-infoBox-visible" : showInfo, "cesium-infoBox-bodyless" : _bodyless }'),i.appendChild(n);var o=document.createElement("div");o.className="cesium-infoBox-title",o.setAttribute("data-bind","text: titleText"),n.appendChild(o);var c=document.createElement("button");c.type="button",c.className="cesium-button cesium-infoBox-camera",c.setAttribute("data-bind",'attr: { title: "Focus camera on object" },click: function () { cameraClicked.raiseEvent(this); },enable: enableCamera,cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }'),n.appendChild(c);var h=document.createElement("button");h.type="button",h.className="cesium-infoBox-close",h.setAttribute("data-bind","click: function () { closeClicked.raiseEvent(this); }"),h.innerHTML="×",n.appendChild(h);var d=document.createElement("iframe");d.className="cesium-infoBox-iframe",d.setAttribute("sandbox","allow-same-origin allow-popups allow-forms"),d.setAttribute("data-bind","style : { maxHeight : maxHeightOffset(40) }"),d.setAttribute("allowfullscreen",!0),n.appendChild(d);var p=new u;a.applyBindings(p,n),this._container=i,this._element=n,this._frame=d,this._viewModel=p,this._descriptionSubscription=void 0;var m=this;d.addEventListener("load",function(){var i=d.contentDocument,o=i.createElement("link");o.href=e("Widgets/InfoBox/InfoBoxDescription.css"),o.rel="stylesheet",o.type="text/css";var a=i.createElement("div");a.className="cesium-infoBox-description",i.head.appendChild(o),i.body.appendChild(a),m._descriptionSubscription=l(p,"description",function(e){d.style.height="5px",a.innerHTML=e;var i=null,o=a.firstElementChild;if(null!==o&&1===a.childNodes.length){var s=window.getComputedStyle(o);if(null!==s){var l=s["background-color"],u=t.fromCssColorString(l);r(u)&&0!==u.alpha&&(i=s["background-color"])}}n.style["background-color"]=i;var c=a.getBoundingClientRect().height;d.style.height=c+"px"})}),d.setAttribute("src","about:blank")};return i(c.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}},frame:{get:function(){return this._frame}}}),c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){var e=this._container;return a.cleanNode(this._element),e.removeChild(this._element),r(this._descriptionSubscription)&&this._descriptionSubscription.dispose(),n(this)},c}),r("Widgets/NavigationHelpButton/NavigationHelpButtonViewModel",["../../Core/defineProperties","../../ThirdParty/knockout","../createCommand"],function(e,t,r){"use strict";var i=function(){this.showInstructions=!1;var e=this;this._command=r(function(){e.showInstructions=!e.showInstructions}),this._showClick=r(function(){e._touch=!1}),this._showTouch=r(function(){e._touch=!0}),this._touch=!1,this.tooltip="Navigation Instructions",t.track(this,["tooltip","showInstructions","_touch"])};return e(i.prototype,{command:{get:function(){return this._command}},showClick:{get:function(){return this._showClick}},showTouch:{get:function(){return this._showTouch}}}),i}),r("Widgets/NavigationHelpButton/NavigationHelpButton",["../../Core/buildModuleUrl","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./NavigationHelpButtonViewModel"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(r){var i=l(r.container),n=new u,o=t(r.instructionsInitiallyVisible,!1);n.showInstructions=o,n._svgPath="M16,1.466C7.973,1.466,1.466,7.973,1.466,16c0,8.027,6.507,14.534,14.534,14.534c8.027,0,14.534-6.507,14.534-14.534C30.534,7.973,24.027,1.466,16,1.466z M17.328,24.371h-2.707v-2.596h2.707V24.371zM17.328,19.003v0.858h-2.707v-1.057c0-3.19,3.63-3.696,3.63-5.963c0-1.034-0.924-1.826-2.134-1.826c-1.254,0-2.354,0.924-2.354,0.924l-1.541-1.915c0,0,1.519-1.584,4.137-1.584c2.487,0,4.796,1.54,4.796,4.136C21.156,16.208,17.328,16.627,17.328,19.003z";var c=document.createElement("span");c.className="cesium-navigationHelpButton-wrapper",i.appendChild(c);var h=document.createElement("button");h.type="button",h.className="cesium-button cesium-toolbar-button cesium-navigation-help-button",h.setAttribute("data-bind","attr: { title: tooltip },click: command,cesiumSvgPath: { path: _svgPath, width: 32, height: 32 }"),c.appendChild(h);var d=document.createElement("div");d.className="cesium-navigation-help",d.setAttribute("data-bind",'css: { "cesium-navigation-help-visible" : showInstructions}'),c.appendChild(d);var p=document.createElement("button");p.type="button",p.className="cesium-navigation-button cesium-navigation-button-left",p.setAttribute("data-bind",'click: showClick, css: {"cesium-navigation-button-selected": !_touch, "cesium-navigation-button-unselected": _touch}');var m=document.createElement("img");m.src=e("Widgets/Images/NavigationHelp/Mouse.svg"),m.className="cesium-navigation-button-icon",m.style.width="25px",m.style.height="25px",p.appendChild(m),p.appendChild(document.createTextNode("Mouse"));var f=document.createElement("button");f.type="button",f.className="cesium-navigation-button cesium-navigation-button-right",f.setAttribute("data-bind",'click: showTouch, css: {"cesium-navigation-button-selected": _touch, "cesium-navigation-button-unselected": !_touch}');var v=document.createElement("img");v.src=e("Widgets/Images/NavigationHelp/Touch.svg"),v.className="cesium-navigation-button-icon",v.style.width="25px",v.style.height="25px",f.appendChild(v),f.appendChild(document.createTextNode("Touch")),d.appendChild(p),d.appendChild(f);var _=document.createElement("div");_.className="cesium-click-navigation-help cesium-navigation-help-instructions",_.setAttribute("data-bind",'css: { "cesium-click-navigation-help-visible" : !_touch}'),_.innerHTML=' <table> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/MouseLeft.svg")+'" width="48" height="48" /></td> <td> <div class="cesium-navigation-help-pan">Pan view</div> <div class="cesium-navigation-help-details">Left click + drag</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/MouseRight.svg")+'" width="48" height="48" /></td> <td> <div class="cesium-navigation-help-zoom">Zoom view</div> <div class="cesium-navigation-help-details">Right click + drag, or</div> <div class="cesium-navigation-help-details">Mouse wheel scroll</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/MouseMiddle.svg")+'" width="48" height="48" /></td> <td> <div class="cesium-navigation-help-rotate">Rotate view</div> <div class="cesium-navigation-help-details">Middle click + drag, or</div> <div class="cesium-navigation-help-details">CTRL + Left/Right click + drag</div> </td> </tr> </table>',d.appendChild(_);var g=document.createElement("div");g.className="cesium-touch-navigation-help cesium-navigation-help-instructions",g.setAttribute("data-bind",'css: { "cesium-touch-navigation-help-visible" : _touch}'),g.innerHTML=' <table> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchDrag.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-pan">Pan view</div> <div class="cesium-navigation-help-details">One finger drag</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchZoom.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-zoom">Zoom view</div> <div class="cesium-navigation-help-details">Two finger pinch</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchTilt.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-rotate">Tilt view</div> <div class="cesium-navigation-help-details">Two finger drag, same direction</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchRotate.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-tilt">Rotate view</div> <div class="cesium-navigation-help-details">Two finger drag, opposite direction</div> </td> </tr> </table>',d.appendChild(g),s.applyBindings(n,c),this._container=i,this._viewModel=n,this._wrapper=c,this._closeInstructions=function(e){c.contains(e.target)||(n.showInstructions=!1)},a.supportsPointerEvents()?document.addEventListener("pointerdown",this._closeInstructions,!0):(document.addEventListener("mousedown",this._closeInstructions,!0),document.addEventListener("touchstart",this._closeInstructions,!0))};return i(c.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return a.supportsPointerEvents()?document.removeEventListener("pointerdown",this._closeInstructions,!0):(document.removeEventListener("mousedown",this._closeInstructions,!0),document.removeEventListener("touchstart",this._closeInstructions,!0)),s.cleanNode(this._wrapper),this._container.removeChild(this._wrapper),n(this)},c}),r("Widgets/PerformanceWatchdog/PerformanceWatchdogViewModel",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Scene/FrameRateMonitor","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){this._scene=t.scene,this.lowFrameRateMessage=e(t.lowFrameRateMessage,"This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers."),this.lowFrameRateMessageDismissed=!1,this.showingLowFrameRateMessage=!1,a.track(this,["lowFrameRateMessage","lowFrameRateMessageDismissed","showingLowFrameRateMessage"]);var r=this;this._dismissMessage=s(function(){r.showingLowFrameRateMessage=!1,r.lowFrameRateMessageDismissed=!0});var i=o.fromScene(t.scene);this._unsubscribeLowFrameRate=i.lowFrameRate.addEventListener(function(){r.lowFrameRateMessageDismissed||(r.showingLowFrameRateMessage=!0)}),this._unsubscribeNominalFrameRate=i.nominalFrameRate.addEventListener(function(){r.showingLowFrameRateMessage=!1})};return r(l.prototype,{scene:{get:function(){return this._scene}},dismissMessage:{get:function(){return this._dismissMessage}}}),l.prototype.destroy=function(){return this._unsubscribeLowFrameRate(),this._unsubscribeNominalFrameRate(),i(this)},l}),r("Widgets/PerformanceWatchdog/PerformanceWatchdog",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./PerformanceWatchdogViewModel"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){var t=o(e.container),r=new a(e),i=document.createElement("div");i.className="cesium-performance-watchdog-message-area",i.setAttribute("data-bind","visible: showingLowFrameRateMessage");var s=document.createElement("button");s.setAttribute("type","button"),s.className="cesium-performance-watchdog-message-dismiss",s.innerHTML="×",s.setAttribute("data-bind","click: dismissMessage"),i.appendChild(s);var l=document.createElement("div");l.className="cesium-performance-watchdog-message",l.setAttribute("data-bind","html: lowFrameRateMessage"),i.appendChild(l),t.appendChild(i),n.applyBindings(r,i),this._container=t,this._viewModel=r,this._element=i};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this._viewModel.destroy(),n.cleanNode(this._element),this._container.removeChild(this._element),r(this)},s}),r("Widgets/SceneModePicker/SceneModePickerViewModel",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/EventHelper","../../Scene/SceneMode","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(t,r){this._scene=t;var i=this,n=function(e,t,r,n){i.sceneMode=r,i.dropDownVisible=!1};this._eventHelper=new o,this._eventHelper.add(t.morphStart,n),this._duration=e(r,2),this.sceneMode=t.mode,this.dropDownVisible=!1,this.tooltip2D="2D",this.tooltip3D="3D",this.tooltipColumbusView="Columbus View",s.track(this,["sceneMode","dropDownVisible","tooltip2D","tooltip3D","tooltipColumbusView"]),this.selectedTooltip=void 0,s.defineProperty(this,"selectedTooltip",function(){var e=i.sceneMode;return e===a.SCENE2D?i.tooltip2D:e===a.SCENE3D?i.tooltip3D:i.tooltipColumbusView}),this._toggleDropDown=l(function(){i.dropDownVisible=!i.dropDownVisible}),this._morphTo2D=l(function(){t.morphTo2D(i._duration)}),this._morphTo3D=l(function(){t.morphTo3D(i._duration)}),this._morphToColumbusView=l(function(){t.morphToColumbusView(i._duration)}),this._sceneMode=a};return r(u.prototype,{scene:{get:function(){return this._scene}},duration:{get:function(){return this._duration},set:function(e){this._duration=e}},toggleDropDown:{get:function(){return this._toggleDropDown}},morphTo2D:{get:function(){return this._morphTo2D}},morphTo3D:{get:function(){return this._morphTo3D}},morphToColumbusView:{get:function(){return this._morphToColumbusView}}}),u.prototype.isDestroyed=function(){return!1},u.prototype.destroy=function(){this._eventHelper.removeAll(),i(this)},u}),r("Widgets/SceneModePicker/SceneModePicker",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./SceneModePickerViewModel"],function(e,t,r,i,n,o,a,s){"use strict";var l="m 32.401392,4.9330437 c -7.087603,0 -14.096095,2.884602 -19.10793,7.8946843 -5.0118352,5.010083 -7.9296167,11.987468 -7.9296167,19.072999 0,7.085531 2.9177815,14.097848 7.9296167,19.107931 4.837653,4.835961 11.541408,7.631372 18.374354,7.82482 0.05712,0.01231 0.454119,0.139729 0.454119,0.139729 l 0.03493,-0.104797 c 0.08246,7.84e-4 0.162033,0.03493 0.244525,0.03493 0.08304,0 0.161515,-0.03414 0.244526,-0.03493 l 0.03493,0.104797 c 0,0 0.309474,-0.129487 0.349323,-0.139729 6.867765,-0.168094 13.582903,-2.965206 18.444218,-7.82482 2.558195,-2.5573 4.551081,-5.638134 5.903547,-8.977584 1.297191,-3.202966 2.02607,-6.661489 2.02607,-10.130347 0,-6.237309 -2.366261,-12.31219 -6.322734,-17.116794 -0.0034,-0.02316 0.0049,-0.04488 0,-0.06986 -0.01733,-0.08745 -0.104529,-0.278855 -0.104797,-0.279458 -5.31e-4,-0.0012 -0.522988,-0.628147 -0.523984,-0.62878 -3.47e-4,-2.2e-4 -0.133444,-0.03532 -0.244525,-0.06987 C 51.944299,13.447603 51.751076,13.104317 51.474391,12.827728 46.462556,7.8176457 39.488996,4.9330437 32.401392,4.9330437 z m -2.130866,3.5281554 0.104797,9.6762289 c -4.111695,-0.08361 -7.109829,-0.423664 -9.257041,-0.943171 1.198093,-2.269271 2.524531,-4.124404 3.91241,-5.414496 2.167498,-2.0147811 3.950145,-2.8540169 5.239834,-3.3185619 z m 2.794579,0 c 1.280302,0.4754953 3.022186,1.3285948 5.065173,3.2486979 1.424667,1.338973 2.788862,3.303645 3.982275,5.728886 -2.29082,0.403367 -5.381258,0.621049 -8.942651,0.698645 L 33.065105,8.4611991 z m 5.728886,0.2445256 c 4.004072,1.1230822 7.793098,3.1481363 10.724195,6.0782083 0.03468,0.03466 0.07033,0.06991 0.104797,0.104797 -0.45375,0.313891 -0.923054,0.663002 -1.956205,1.082899 -0.647388,0.263114 -1.906242,0.477396 -2.829511,0.733577 -1.382296,-2.988132 -3.027146,-5.368585 -4.785716,-7.0213781 -0.422866,-0.397432 -0.835818,-0.6453247 -1.25756,-0.9781032 z m -15.33525,0.7685092 c -0.106753,0.09503 -0.207753,0.145402 -0.31439,0.244526 -1.684973,1.5662541 -3.298068,3.8232211 -4.680919,6.5672591 -0.343797,-0.14942 -1.035052,-0.273198 -1.292493,-0.419186 -0.956528,-0.542427 -1.362964,-1.022024 -1.537018,-1.292493 -0.0241,-0.03745 -0.01868,-0.0401 -0.03493,-0.06986 2.250095,-2.163342 4.948824,-3.869984 7.859752,-5.0302421 z m -9.641296,7.0912431 c 0.464973,0.571618 0.937729,1.169056 1.956205,1.746612 0.349907,0.198425 1.107143,0.335404 1.537018,0.523983 -1.20166,3.172984 -1.998037,7.051901 -2.165798,11.772162 C 14.256557,30.361384 12.934823,30.161483 12.280427,29.90959 10.644437,29.279855 9.6888882,28.674891 9.1714586,28.267775 8.6540289,27.860658 8.6474751,27.778724 8.6474751,27.778724 l -0.069864,0.03493 C 9.3100294,23.691285 11.163248,19.798527 13.817445,16.565477 z m 37.552149,0.523984 c 2.548924,3.289983 4.265057,7.202594 4.890513,11.318043 -0.650428,0.410896 -1.756876,1.001936 -3.563088,1.606882 -1.171552,0.392383 -3.163859,0.759153 -4.960377,1.117832 -0.04367,-4.752703 -0.784809,-8.591423 -1.88634,-11.807094 0.917574,-0.263678 2.170552,-0.486495 2.864443,-0.76851 1.274693,-0.518066 2.003942,-1.001558 2.654849,-1.467153 z m -31.439008,2.619917 c 2.487341,0.672766 5.775813,1.137775 10.479669,1.222628 l 0.104797,10.689263 0,0.03493 0,0.733577 c -5.435005,-0.09059 -9.512219,-0.519044 -12.610536,-1.117831 0.106127,-4.776683 0.879334,-8.55791 2.02607,-11.562569 z m 23.264866,0.31439 c 1.073459,3.067541 1.833795,6.821314 1.816476,11.702298 -3.054474,0.423245 -7.062018,0.648559 -11.702298,0.698644 l 0,-0.838373 -0.104796,-10.654331 c 4.082416,-0.0864 7.404468,-0.403886 9.990618,-0.908238 z M 8.2632205,30.922625 c 0.7558676,0.510548 1.5529563,1.013339 3.0041715,1.57195 0.937518,0.360875 2.612202,0.647642 3.91241,0.978102 0.112814,3.85566 0.703989,7.107756 1.606883,9.920754 -1.147172,-0.324262 -2.644553,-0.640648 -3.423359,-0.978102 -1.516688,-0.657177 -2.386627,-1.287332 -2.864443,-1.71168 -0.477816,-0.424347 -0.489051,-0.489051 -0.489051,-0.489051 L 9.8002387,40.319395 C 8.791691,37.621767 8.1584238,34.769583 8.1584238,31.900727 c 0,-0.330153 0.090589,-0.648169 0.1047967,-0.978102 z m 48.2763445,0.419186 c 0.0047,0.188973 0.06986,0.36991 0.06986,0.558916 0,2.938869 -0.620228,5.873558 -1.676747,8.628261 -0.07435,0.07583 -0.06552,0.07411 -0.454119,0.349323 -0.606965,0.429857 -1.631665,1.042044 -3.318562,1.676747 -1.208528,0.454713 -3.204964,0.850894 -5.135038,1.25756 0.84593,-2.765726 1.41808,-6.005357 1.606883,-9.815957 2.232369,-0.413371 4.483758,-0.840201 5.938479,-1.327425 1.410632,-0.472457 2.153108,-0.89469 2.96924,-1.327425 z m -38.530252,2.864443 c 3.208141,0.56697 7.372279,0.898588 12.575603,0.978103 l 0.174662,9.885821 c -4.392517,-0.06139 -8.106722,-0.320566 -10.863925,-0.803441 -1.051954,-2.664695 -1.692909,-6.043794 -1.88634,-10.060483 z m 26.793022,0.31439 c -0.246298,3.923551 -0.877762,7.263679 -1.816476,9.885822 -2.561957,0.361954 -5.766249,0.560708 -9.431703,0.62878 l -0.174661,-9.815957 c 4.491734,-0.04969 8.334769,-0.293032 11.42284,-0.698645 z M 12.035901,44.860585 c 0.09977,0.04523 0.105535,0.09465 0.209594,0.139729 1.337656,0.579602 3.441099,1.058072 5.589157,1.537018 1.545042,3.399208 3.548524,5.969402 5.589157,7.789888 -3.034411,-1.215537 -5.871615,-3.007978 -8.174142,-5.309699 -1.245911,-1.245475 -2.271794,-2.662961 -3.213766,-4.156936 z m 40.69605,0 c -0.941972,1.493975 -1.967855,2.911461 -3.213765,4.156936 -2.74253,2.741571 -6.244106,4.696717 -9.955686,5.868615 0.261347,-0.241079 0.507495,-0.394491 0.768509,-0.663713 1.674841,-1.727516 3.320792,-4.181056 4.645987,-7.265904 2.962447,-0.503021 5.408965,-1.122293 7.161107,-1.781544 0.284034,-0.106865 0.337297,-0.207323 0.593848,-0.31439 z m -31.404076,2.305527 c 2.645807,0.376448 5.701178,0.649995 9.466635,0.698645 l 0.139729,7.789888 c -1.38739,-0.480844 -3.316218,-1.29837 -5.659022,-3.388427 -1.388822,-1.238993 -2.743668,-3.0113 -3.947342,-5.100106 z m 20.365491,0.104797 c -1.04872,2.041937 -2.174337,3.779068 -3.353494,4.995309 -1.853177,1.911459 -3.425515,2.82679 -4.611055,3.353494 l -0.139729,-7.789887 c 3.13091,-0.05714 5.728238,-0.278725 8.104278,-0.558916 z",u="m 2.9825053,17.550598 0,1.368113 0,26.267766 0,1.368113 1.36811,0 54.9981397,0 1.36811,0 0,-1.368113 0,-26.267766 0,-1.368113 -1.36811,0 -54.9981397,0 -1.36811,0 z m 2.73623,2.736226 10.3292497,0 0,10.466063 -10.3292497,0 0,-10.466063 z m 13.0654697,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 10.32926,0 0,10.466063 -10.32926,0 0,-10.466063 z m -41.9326497,13.202288 10.3292497,0 0,10.329252 -10.3292497,0 0,-10.329252 z m 13.0654697,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 10.32926,0 0,10.329252 -10.32926,0 0,-10.329252 z",c="m 14.723969,17.675598 -0.340489,0.817175 -11.1680536,26.183638 -0.817175,1.872692 2.076986,0 54.7506996,0 2.07698,0 -0.81717,-1.872692 -11.16805,-26.183638 -0.34049,-0.817175 -0.91933,0 -32.414586,0 -0.919322,0 z m 1.838643,2.723916 6.196908,0 -2.928209,10.418977 -7.729111,0 4.460412,-10.418977 z m 9.02297,0 4.903049,0 0,10.418977 -7.831258,0 2.928209,-10.418977 z m 7.626964,0 5.584031,0 2.62176,10.418977 -8.205791,0 0,-10.418977 z m 8.410081,0 5.51593,0 4.46042,10.418977 -7.38863,0 -2.58772,-10.418977 z m -30.678091,13.142892 8.103649,0 -2.89416,10.282782 -9.6018026,0 4.3923136,-10.282782 z m 10.929711,0 8.614384,0 0,10.282782 -11.508544,0 2.89416,-10.282782 z m 11.338299,0 8.852721,0 2.58772,10.282782 -11.440441,0 0,-10.282782 z m 11.678781,0 7.86531,0 4.39231,10.282782 -9.6699,0 -2.58772,-10.282782 z",h=function(e,t,r){e=a(e);var i=new s(t,r);i._globePath=l,i._flatMapPath=u,i._columbusViewPath=c;var h=document.createElement("span");h.className="cesium-sceneModePicker-wrapper cesium-toolbar-button",e.appendChild(h);var d=document.createElement("button");d.type="button",d.className="cesium-button cesium-toolbar-button",d.setAttribute("data-bind",'css: { "cesium-sceneModePicker-button2D": sceneMode === _sceneMode.SCENE2D, "cesium-sceneModePicker-button3D": sceneMode === _sceneMode.SCENE3D, "cesium-sceneModePicker-buttonColumbusView": sceneMode === _sceneMode.COLUMBUS_VIEW, "cesium-sceneModePicker-selected": dropDownVisible },attr: { title: selectedTooltip },click: toggleDropDown'),d.innerHTML='<!-- ko cesiumSvgPath: { path: _globePath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon3D" } --><!-- /ko --><!-- ko cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon2D" } --><!-- /ko --><!-- ko cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-iconColumbusView" } --><!-- /ko -->', +h.appendChild(d);var p=document.createElement("button");p.type="button",p.className="cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon",p.setAttribute("data-bind",'css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE3D)) || (!dropDownVisible && (sceneMode === _sceneMode.SCENE3D)), "cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE3D, "cesium-sceneModePicker-hidden" : !dropDownVisible },attr: { title: tooltip3D },click: morphTo3D,cesiumSvgPath: { path: _globePath, width: 64, height: 64 }'),h.appendChild(p);var m=document.createElement("button");m.type="button",m.className="cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon",m.setAttribute("data-bind",'css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE2D)), "cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE2D, "cesium-sceneModePicker-hidden" : !dropDownVisible },attr: { title: tooltip2D },click: morphTo2D,cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64 }'),h.appendChild(m);var f=document.createElement("button");f.type="button",f.className="cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon",f.setAttribute("data-bind",'css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.COLUMBUS_VIEW)) || (!dropDownVisible && (sceneMode === _sceneMode.COLUMBUS_VIEW)), "cesium-sceneModePicker-none" : sceneMode === _sceneMode.COLUMBUS_VIEW, "cesium-sceneModePicker-hidden" : !dropDownVisible},attr: { title: tooltipColumbusView },click: morphToColumbusView,cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64 }'),h.appendChild(f),o.applyBindings(i,h),this._viewModel=i,this._container=e,this._wrapper=h,this._closeDropDown=function(e){h.contains(e.target)||(i.dropDownVisible=!1)},n.supportsPointerEvents()?document.addEventListener("pointerdown",this._closeDropDown,!0):(document.addEventListener("mousedown",this._closeDropDown,!0),document.addEventListener("touchstart",this._closeDropDown,!0))};return t(h.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),h.prototype.isDestroyed=function(){return!1},h.prototype.destroy=function(){return this._viewModel.destroy(),n.supportsPointerEvents()?document.removeEventListener("pointerdown",this._closeDropDown,!0):(document.removeEventListener("mousedown",this._closeDropDown,!0),document.removeEventListener("touchstart",this._closeDropDown,!0)),o.cleanNode(this._wrapper),this._container.removeChild(this._wrapper),r(this)},h}),r("Widgets/SelectionIndicator/SelectionIndicatorViewModel",["../../Core/Cartesian2","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/EasingFunction","../../Scene/SceneTransforms","../../ThirdParty/knockout"],function(e,t,r,i,n,o,a,s){"use strict";var l=new e,u="-1000px",c=function(e,i,n){this._scene=e,this._screenPositionX=u,this._screenPositionY=u,this._tweens=e.tweens,this._container=t(n,document.body),this._selectionIndicatorElement=i,this._scale=1,this.position=void 0,this.showSelection=!1,s.track(this,["position","_screenPositionX","_screenPositionY","_scale","showSelection"]),this.isVisible=void 0,s.defineProperty(this,"isVisible",{get:function(){return this.showSelection&&r(this.position)}}),s.defineProperty(this,"_transform",{get:function(){return"scale("+this._scale+")"}}),this.computeScreenSpacePosition=function(t,r){return a.wgs84ToWindowCoordinates(e,t,r)}};return c.prototype.update=function(){if(this.showSelection&&r(this.position)){var e=this.computeScreenSpacePosition(this.position,l);if(r(e)){var t=this._container,i=t.parentNode.clientWidth,n=t.parentNode.clientHeight,o=this._selectionIndicatorElement.clientWidth,a=.5*o;e.x=Math.min(Math.max(e.x,-o),i+o)-a,e.y=Math.min(Math.max(e.y,-o),n+o)-a,this._screenPositionX=Math.floor(e.x+.25)+"px",this._screenPositionY=Math.floor(e.y+.25)+"px"}else this._screenPositionX=u,this._screenPositionY=u}},c.prototype.animateAppear=function(){this._tweens.addProperty({object:this,property:"_scale",startValue:2,stopValue:1,duration:.8,easingFunction:o.EXPONENTIAL_OUT})},c.prototype.animateDepart=function(){this._tweens.addProperty({object:this,property:"_scale",startValue:this._scale,stopValue:1.5,duration:.8,easingFunction:o.EXPONENTIAL_OUT})},i(c.prototype,{container:{get:function(){return this._container}},selectionIndicatorElement:{get:function(){return this._selectionIndicatorElement}},scene:{get:function(){return this._scene}}}),c}),r("Widgets/SelectionIndicator/SelectionIndicator",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./SelectionIndicatorViewModel"],function(e,t,r,i,n,o,a){"use strict";var s=function(e,t){e=o(e),this._container=e;var r=document.createElement("div");r.className="cesium-selection-wrapper",r.setAttribute("data-bind",'style: { "top" : _screenPositionY, "left" : _screenPositionX },css: { "cesium-selection-wrapper-visible" : isVisible }'),e.appendChild(r),this._element=r;var i="http://www.w3.org/2000/svg",s="M -34 -34 L -34 -11.25 L -30 -15.25 L -30 -30 L -15.25 -30 L -11.25 -34 L -34 -34 z M 11.25 -34 L 15.25 -30 L 30 -30 L 30 -15.25 L 34 -11.25 L 34 -34 L 11.25 -34 z M -34 11.25 L -34 34 L -11.25 34 L -15.25 30 L -30 30 L -30 15.25 L -34 11.25 z M 34 11.25 L 30 15.25 L 30 30 L 15.25 30 L 11.25 34 L 34 34 L 34 11.25 z",l=document.createElementNS(i,"svg:svg");l.setAttribute("width",160),l.setAttribute("height",160),l.setAttribute("viewBox","0 0 160 160");var u=document.createElementNS(i,"g");u.setAttribute("transform","translate(80,80)"),l.appendChild(u);var c=document.createElementNS(i,"path");c.setAttribute("data-bind","attr: { transform: _transform }"),c.setAttribute("d",s),u.appendChild(c),r.appendChild(l);var h=new a(t,this._element,this._container);this._viewModel=h,n.applyBindings(this._viewModel,this._element)};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){var e=this._container;return n.cleanNode(this._element),e.removeChild(this._element),r(this)},s}),r("Widgets/Timeline/TimelineHighlightRange",["../../Core/defaultValue","../../Core/JulianDate"],function(e,t){"use strict";function r(t,r,i){this._color=t,this._height=r,this._base=e(i,0)}return r.prototype.getHeight=function(){return this._height},r.prototype.getBase=function(){return this._base},r.prototype.getStartTime=function(){return this._start},r.prototype.getStopTime=function(){return this._stop},r.prototype.setRange=function(e,t){this._start=e,this._stop=t},r.prototype.render=function(e){var r="";if(this._start&&this._stop&&this._color){var i=t.secondsDifference(this._start,e.epochJulian),n=Math.round(e.timeBarWidth*e.getAlpha(i)),o=t.secondsDifference(this._stop,e.epochJulian),a=Math.round(e.timeBarWidth*e.getAlpha(o))-n;0>n&&(a+=n,n=0),n+a>e.timeBarWidth&&(a=e.timeBarWidth-n),a>0&&(r='<span class="cesium-timeline-highlight" style="left: '+n.toString()+"px; width: "+a.toString()+"px; bottom: "+this._base.toString()+"px; height: "+this._height+"px; background-color: "+this._color+';"></span>')}return r},r}),r("Widgets/Timeline/TimelineTrack",["../../Core/Color","../../Core/defined","../../Core/JulianDate"],function(e,t,r){"use strict";function i(t,r,i,n){this.interval=t,this.height=r,this.color=i||new e(.5,.5,.5,1),this.backgroundColor=n||new e(0,0,0,0)}return i.prototype.render=function(e,i){var n=this.interval.start,o=this.interval.stop,a=i.startJulian,s=r.addSeconds(i.startJulian,i.duration,new r);if(r.lessThan(n,a)&&r.greaterThan(o,s))e.fillStyle=this.color.toCssColorString(),e.fillRect(0,i.y,i.timeBarWidth,this.height);else if(r.lessThanOrEquals(n,s)&&r.greaterThanOrEquals(o,a)){var l,u,c;for(l=0;l<i.timeBarWidth;++l){var h=r.addSeconds(i.startJulian,l/i.timeBarWidth*i.duration,new r);!t(u)&&r.greaterThanOrEquals(h,n)?u=l:!t(c)&&r.greaterThanOrEquals(h,o)&&(c=l)}e.fillStyle=this.backgroundColor.toCssColorString(),e.fillRect(0,i.y,i.timeBarWidth,this.height),t(u)&&(t(c)||(c=i.timeBarWidth),e.fillStyle=this.color.toCssColorString(),e.fillRect(u,i.y,Math.max(c-u,1),this.height))}},i}),r("Widgets/Timeline/Timeline",["../../Core/ClockRange","../../Core/defined","../../Core/destroyObject","../../Core/DeveloperError","../../Core/JulianDate","../getElement","./TimelineHighlightRange","./TimelineTrack"],function(e,t,r,i,n,o,a,s){"use strict";function l(e){return 10>e?"0"+e.toString():e.toString()}function u(e){return function(t){e._mouseMode!==_.touchOnly&&(0===t.button?(e._mouseMode=_.scrub,e._scrubElement&&(e._scrubElement.style.backgroundPosition="-16px 0"),e._onMouseMove(t)):(e._mouseX=t.clientX,2===t.button?e._mouseMode=_.zoom:e._mouseMode=_.slide)),t.preventDefault()}}function c(e){return function(t){e._mouseMode=_.none,e._scrubElement&&(e._scrubElement.style.backgroundPosition="0px 0px"),e._timelineDrag=0,e._timelineDragLocation=void 0}}function h(e){return function(t){var r;if(e._mouseMode===_.scrub){t.preventDefault();var i=t.clientX-e._topDiv.getBoundingClientRect().left;0>i?(e._timelineDragLocation=0,e._timelineDrag=-.01*e._timeBarSecondsSpan):i>e._topDiv.clientWidth?(e._timelineDragLocation=e._topDiv.clientWidth,e._timelineDrag=.01*e._timeBarSecondsSpan):(e._timelineDragLocation=void 0,e._setTimeBarTime(i,i*e._timeBarSecondsSpan/e._topDiv.clientWidth))}else if(e._mouseMode===_.slide){if(r=e._mouseX-t.clientX,e._mouseX=t.clientX,0!==r){var o=r*e._timeBarSecondsSpan/e._topDiv.clientWidth;e.zoomTo(n.addSeconds(e._startJulian,o,new n),n.addSeconds(e._endJulian,o,new n))}}else e._mouseMode===_.zoom&&(r=e._mouseX-t.clientX,e._mouseX=t.clientX,0!==r&&e.zoomFrom(Math.pow(1.01,r)))}}function d(e){return function(t){var r=t.wheelDeltaY||t.wheelDelta||-t.detail;v=Math.max(Math.min(Math.abs(r),v),1),r/=v,e.zoomFrom(Math.pow(1.05,-r))}}function p(e){return function(t){var r,i,o=t.touches.length,a=e._topDiv.getBoundingClientRect().left;t.preventDefault(),e._mouseMode=_.touchOnly,1===o?(r=n.secondsDifference(e._scrubJulian,e._startJulian),i=Math.round(r*e._topDiv.clientWidth/e._timeBarSecondsSpan+a),Math.abs(t.touches[0].clientX-i)<50?(e._touchMode=g.scrub,e._scrubElement&&(e._scrubElement.style.backgroundPosition=1===o?"-16px 0":"0 0")):(e._touchMode=g.singleTap,e._touchState.centerX=t.touches[0].clientX-a)):2===o?(e._touchMode=g.slideZoom,e._touchState.centerX=.5*(t.touches[0].clientX+t.touches[1].clientX)-a,e._touchState.spanX=Math.abs(t.touches[0].clientX-t.touches[1].clientX)):e._touchMode=g.ignore}}function m(e){return function(t){var r=t.touches.length,i=e._topDiv.getBoundingClientRect().left;e._touchMode===g.singleTap?(e._touchMode=g.scrub,e._handleTouchMove(t)):e._touchMode===g.scrub&&e._handleTouchMove(t),e._mouseMode=_.touchOnly,1!==r?e._touchMode=r>0?g.ignore:g.none:e._touchMode===g.slideZoom&&(e._touchState.centerX=t.touches[0].clientX-i),e._scrubElement&&(e._scrubElement.style.backgroundPosition="0 0")}}function f(e){return function(r){var i,o,a,s,l,u,c=1,h=e._topDiv.getBoundingClientRect().left;e._touchMode===g.singleTap&&(e._touchMode=g.slideZoom),e._mouseMode=_.touchOnly,e._touchMode===g.scrub?(r.preventDefault(),1===r.changedTouches.length&&(o=r.changedTouches[0].clientX-h,o>=0&&o<=e._topDiv.clientWidth&&e._setTimeBarTime(o,o*e._timeBarSecondsSpan/e._topDiv.clientWidth))):e._touchMode===g.slideZoom&&(a=r.touches.length,2===a?(s=.5*(r.touches[0].clientX+r.touches[1].clientX)-h,l=Math.abs(r.touches[0].clientX-r.touches[1].clientX)):1===a&&(s=r.touches[0].clientX-h,l=0),t(s)&&(l>0&&e._touchState.spanX>0?(c=e._touchState.spanX/l,u=n.addSeconds(e._startJulian,(e._touchState.centerX*e._timeBarSecondsSpan-s*e._timeBarSecondsSpan*c)/e._topDiv.clientWidth,new n)):(i=e._touchState.centerX-s,u=n.addSeconds(e._startJulian,i*e._timeBarSecondsSpan/e._topDiv.clientWidth,new n)),e.zoomTo(u,n.addSeconds(u,e._timeBarSecondsSpan*c,new n)),e._touchState.centerX=s,e._touchState.spanX=l))}}var v=1e12,_={none:0,scrub:1,slide:2,zoom:3,touchOnly:4},g={none:0,scrub:1,slideZoom:2,singleTap:3,ignore:4},y=[.001,.002,.005,.01,.02,.05,.1,.25,.5,1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,21600,43200,86400,172800,345600,604800,1296e3,2592e3,5184e3,7776e3,15552e3,31536e3,63072e3,126144e3,15768e4,31536e4,63072e4,126144e4,15768e5,31536e5,63072e5,126144e5,15768e6,31536e6],C=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],E=function(e,t){e=o(e),this.container=e;var r=document.createElement("div");r.className="cesium-timeline-main",e.appendChild(r),this._topDiv=r,this._endJulian=void 0,this._epochJulian=void 0,this._lastXPos=void 0,this._scrubElement=void 0,this._startJulian=void 0,this._timeBarSecondsSpan=void 0,this._clock=t,this._scrubJulian=t.currentTime,this._mainTicSpan=-1,this._mouseMode=_.none,this._touchMode=g.none,this._touchState={centerX:0,spanX:0},this._mouseX=0,this._timelineDrag=0,this._timelineDragLocation=void 0,this._lastHeight=void 0,this._lastWidth=void 0,this._topDiv.innerHTML='<div class="cesium-timeline-bar"></div><div class="cesium-timeline-trackContainer"><canvas class="cesium-timeline-tracks" width="10" height="1"></canvas></div><div class="cesium-timeline-needle"></div><span class="cesium-timeline-ruler"></span>',this._timeBarEle=this._topDiv.childNodes[0],this._trackContainer=this._topDiv.childNodes[1],this._trackListEle=this._topDiv.childNodes[1].childNodes[0],this._needleEle=this._topDiv.childNodes[2],this._rulerEle=this._topDiv.childNodes[3],this._context=this._trackListEle.getContext("2d"),this._trackList=[],this._highlightRanges=[],this.zoomTo(t.startTime,t.stopTime),this._onMouseDown=u(this),this._onMouseUp=c(this),this._onMouseMove=h(this),this._onMouseWheel=d(this),this._onTouchStart=p(this),this._onTouchMove=f(this),this._onTouchEnd=m(this);var i=this._timeBarEle;document.addEventListener("mouseup",this._onMouseUp,!1),document.addEventListener("mousemove",this._onMouseMove,!1),i.addEventListener("mousedown",this._onMouseDown,!1),i.addEventListener("DOMMouseScroll",this._onMouseWheel,!1),i.addEventListener("mousewheel",this._onMouseWheel,!1),i.addEventListener("touchstart",this._onTouchStart,!1),i.addEventListener("touchmove",this._onTouchMove,!1),i.addEventListener("touchend",this._onTouchEnd,!1),this._topDiv.oncontextmenu=function(){return!1},t.onTick.addEventListener(this.updateFromClock,this),this.updateFromClock()};return E.prototype.addEventListener=function(e,t,r){this._topDiv.addEventListener(e,t,r)},E.prototype.removeEventListener=function(e,t,r){this._topDiv.removeEventListener(e,t,r)},E.prototype.isDestroyed=function(){return!1},E.prototype.destroy=function(){this._clock.onTick.removeEventListener(this.updateFromClock,this),document.removeEventListener("mouseup",this._onMouseUp,!1),document.removeEventListener("mousemove",this._onMouseMove,!1);var e=this._timeBarEle;e.removeEventListener("mousedown",this._onMouseDown,!1),e.removeEventListener("DOMMouseScroll",this._onMouseWheel,!1),e.removeEventListener("mousewheel",this._onMouseWheel,!1),e.removeEventListener("touchstart",this._onTouchStart,!1),e.removeEventListener("touchmove",this._onTouchMove,!1),e.removeEventListener("touchend",this._onTouchEnd,!1),this.container.removeChild(this._topDiv),r(this)},E.prototype.addHighlightRange=function(e,t,r){var i=new a(e,t,r);return this._highlightRanges.push(i),this.resize(),i},E.prototype.addTrack=function(e,t,r,i){var n=new s(e,t,r,i);return this._trackList.push(n),this._lastHeight=void 0,this.resize(),n},E.prototype.zoomTo=function(t,r){if(this._startJulian=t,this._endJulian=r,this._timeBarSecondsSpan=n.secondsDifference(r,t),this._clock&&this._clock.clockRange!==e.UNBOUNDED){var i=this._clock.startTime,o=this._clock.stopTime,a=n.secondsDifference(o,i),s=n.secondsDifference(i,this._startJulian),l=n.secondsDifference(o,this._endJulian);this._timeBarSecondsSpan>=a?(this._timeBarSecondsSpan=a,this._startJulian=this._clock.startTime,this._endJulian=this._clock.stopTime):s>0?(this._endJulian=n.addSeconds(this._endJulian,s,new n),this._startJulian=i,this._timeBarSecondsSpan=n.secondsDifference(this._endJulian,this._startJulian)):0>l&&(this._startJulian=n.addSeconds(this._startJulian,l,new n),this._endJulian=o,this._timeBarSecondsSpan=n.secondsDifference(this._endJulian,this._startJulian))}this._makeTics();var u=document.createEvent("Event");u.initEvent("setzoom",!0,!0),u.startJulian=this._startJulian,u.endJulian=this._endJulian,u.epochJulian=this._epochJulian,u.totalSpan=this._timeBarSecondsSpan,u.mainTicSpan=this._mainTicSpan,this._topDiv.dispatchEvent(u)},E.prototype.zoomFrom=function(e){var t=n.secondsDifference(this._scrubJulian,this._startJulian);e>1||0>t||t>this._timeBarSecondsSpan?t=.5*this._timeBarSecondsSpan:t+=t-.5*this._timeBarSecondsSpan;var r=this._timeBarSecondsSpan-t;this.zoomTo(n.addSeconds(this._startJulian,t-t*e,new n),n.addSeconds(this._endJulian,r*e-r,new n))},E.prototype.makeLabel=function(e){var t=n.toGregorianDate(e),r=t.millisecond,i=" UTC";if(r>0&&this._timeBarSecondsSpan<3600){for(i=Math.floor(r).toString();i.length<3;)i="0"+i;i="."+i}return C[t.month-1]+" "+t.day+" "+t.year+" "+l(t.hour)+":"+l(t.minute)+":"+l(t.second)+i},E.prototype.smallestTicInPixels=7,E.prototype._makeTics=function(){function e(e){return Math.floor(S/e)*e}function t(e,t){return Math.ceil(e/t+.5)*t}function r(e){return(e-S)/v}function i(e,t){return e-t*Math.round(e/t)}var o,a=this._timeBarEle,s=n.secondsDifference(this._scrubJulian,this._startJulian),l=Math.round(s*this._topDiv.clientWidth/this._timeBarSecondsSpan),u=l-8,c=this;this._needleEle.style.left=l.toString()+"px";var h="",d=.01,p=31536e6,m=1e-10,f=0,v=this._timeBarSecondsSpan;d>v?(v=d,this._timeBarSecondsSpan=d,this._endJulian=n.addSeconds(this._startJulian,d,new n)):v>p&&(v=p,this._timeBarSecondsSpan=p,this._endJulian=n.addSeconds(this._startJulian,p,new n));var _=this._timeBarEle.clientWidth;10>_&&(_=10);var g,C=this._startJulian,E=Math.min(v/_*1e-5,.4);g=v>31536e4?n.fromIso8601(n.toDate(C).toISOString().substring(0,2)+"00-01-01T00:00:00Z"):v>31536e3?n.fromIso8601(n.toDate(C).toISOString().substring(0,3)+"0-01-01T00:00:00Z"):v>86400?n.fromIso8601(n.toDate(C).toISOString().substring(0,4)+"-01-01T00:00:00Z"):n.fromIso8601(n.toDate(C).toISOString().substring(0,10)+"T00:00:00Z");var S=n.secondsDifference(this._startJulian,n.addSeconds(g,E,new n)),w=S+v;this._epochJulian=g,this._rulerEle.innerHTML=this.makeLabel(n.addSeconds(this._endJulian,-d,new n));var T=this._rulerEle.offsetWidth+20;30>T&&(T=180);var b=f;f-=m;var x={startTime:S,startJulian:C,epochJulian:g,duration:v,timeBarWidth:_,getAlpha:r};this._highlightRanges.forEach(function(e){h+=e.render(x)});var P=0,A=0,I=0,M=T/_;M>1&&(M=1),M*=this._timeBarSecondsSpan;var D,R=-1,O=-1,N=y.length;for(D=0;N>D;++D){var L=y[D];if(++R,P=L,L>M&&L>f)break;0>O&&_*(L/this._timeBarSecondsSpan)>=this.smallestTicInPixels&&(O=R)}if(R>0){for(;R>0;)if(--R,Math.abs(i(P,y[R]))<1e-5){y[R]>=f&&(A=y[R]);break}if(O>=0)for(;R>O;){if(Math.abs(i(A,y[O]))<1e-5&&y[O]>=f){I=y[O];break}++O}}f=b,f>m&&1e-5>I&&Math.abs(f-P)>m&&(I=f,P+m>=f&&(A=0));var F,B=-999999;if(_*(I/this._timeBarSecondsSpan)>=3)for(o=e(I);w>=o;o=t(o,I))h+='<span class="cesium-timeline-ticTiny" style="left: '+Math.round(_*r(o)).toString()+'px;"></span>';if(_*(A/this._timeBarSecondsSpan)>=3)for(o=e(A);w>=o;o=t(o,A))h+='<span class="cesium-timeline-ticSub" style="left: '+Math.round(_*r(o)).toString()+'px;"></span>';if(_*(P/this._timeBarSecondsSpan)>=2){this._mainTicSpan=P,w+=P,o=e(P);for(var V=n.computeTaiMinusUtc(g);w>=o;){var z=n.addSeconds(C,o-S,new n);if(P>2.1){var k=n.computeTaiMinusUtc(z);Math.abs(k-V)>.1&&(o+=k-V,z=n.addSeconds(C,o-S,new n))}var U=Math.round(_*r(o)),G=this.makeLabel(z);this._rulerEle.innerHTML=G,F=this._rulerEle.offsetWidth,10>F&&(F=T);var W=U-(F/2-1);W>B?(B=W+F+5,h+='<span class="cesium-timeline-ticMain" style="left: '+U.toString()+'px;"></span><span class="cesium-timeline-ticLabel" style="left: '+W.toString()+'px;">'+G+"</span>"):h+='<span class="cesium-timeline-ticSub" style="left: '+U.toString()+'px;"></span>',o=t(o,P)}}else this._mainTicSpan=-1;h+='<span class="cesium-timeline-icon16" style="left:'+u+'px;bottom:0;background-position: 0px 0px;"></span>',a.innerHTML=h,this._scrubElement=a.lastChild,this._context.clearRect(0,0,this._trackListEle.width,this._trackListEle.height),x.y=0,this._trackList.forEach(function(e){e.render(c._context,x),x.y+=e.height})},E.prototype.updateFromClock=function(){this._scrubJulian=this._clock.currentTime;var e=this._scrubElement;if(t(this._scrubElement)){var r=n.secondsDifference(this._scrubJulian,this._startJulian),i=Math.round(r*this._topDiv.clientWidth/this._timeBarSecondsSpan);this._lastXPos!==i&&(this._lastXPos=i,e.style.left=i-8+"px",this._needleEle.style.left=i+"px")}t(this._timelineDragLocation)&&(this._setTimeBarTime(this._timelineDragLocation,this._timelineDragLocation*this._timeBarSecondsSpan/this._topDiv.clientWidth),this.zoomTo(n.addSeconds(this._startJulian,this._timelineDrag,new n),n.addSeconds(this._endJulian,this._timelineDrag,new n)))},E.prototype._setTimeBarTime=function(e,t){if(e=Math.round(e),this._scrubJulian=n.addSeconds(this._startJulian,t,new n),this._scrubElement){var r=e-8;this._scrubElement.style.left=r.toString()+"px",this._needleEle.style.left=e.toString()+"px"}var i=document.createEvent("Event");i.initEvent("settime",!0,!0),i.clientX=e,i.timeSeconds=t,i.timeJulian=this._scrubJulian,i.clock=this._clock,this._topDiv.dispatchEvent(i)},E.prototype.resize=function(){var e=this.container.clientWidth,t=this.container.clientHeight;if(e!==this._lastWidth||t!==this._lastHeight){this._trackContainer.style.height=t+"px";var r=1;this._trackList.forEach(function(e){r+=e.height}),this._trackListEle.style.height=r.toString()+"px",this._trackListEle.width=this._trackListEle.clientWidth,this._trackListEle.height=r,this._makeTics(),this._lastWidth=e,this._lastHeight=t}},E}),r("Widgets/Viewer/Viewer",["../../Core/BoundingSphere","../../Core/Cartesian3","../../Core/defaultValue","../../Core/defined","../../Core/definedNotNull","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/EventHelper","../../Core/isArray","../../Core/Matrix4","../../Core/ScreenSpaceEventType","../../DataSources/BoundingSphereState","../../DataSources/ConstantPositionProperty","../../DataSources/DataSourceCollection","../../DataSources/DataSourceDisplay","../../DataSources/Entity","../../DataSources/EntityView","../../DataSources/Property","../../Scene/SceneMode","../../ThirdParty/knockout","../../ThirdParty/when","../Animation/Animation","../Animation/AnimationViewModel","../BaseLayerPicker/BaseLayerPicker","../BaseLayerPicker/createDefaultImageryProviderViewModels","../BaseLayerPicker/createDefaultTerrainProviderViewModels","../CesiumWidget/CesiumWidget","../ClockViewModel","../FullscreenButton/FullscreenButton","../Geocoder/Geocoder","../getElement","../HomeButton/HomeButton","../InfoBox/InfoBox","../NavigationHelpButton/NavigationHelpButton","../SceneModePicker/SceneModePicker","../SelectionIndicator/SelectionIndicator","../subscribeAndEvaluate","../Timeline/Timeline"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V){"use strict";function z(e){var t=e.clock;t.currentTime=e.timeJulian,t.shouldAnimate=!1}function k(e,t){var n=e.scene.pick(t.position);if(i(n)){var o=r(n.id,n.primitive.id);if(o instanceof v)return o}return i(e.scene.globe)?G(e,t.position):void 0}function U(e,t,r){if(i(r)){var n=r.clock;i(n)&&(n.getValue(t),i(e)&&(e.updateFromClock(),e.zoomTo(n.startTime,n.stopTime)))}}function G(e,t){var r=e.scene,n=r.camera.getPickRay(t),o=r.imageryLayers.pickImageryLayerFeatures(n,r);if(i(o)){var a=new v({id:"Loading...",description:"Loading feature information..."});return E(o,function(t){if(e.selectedEntity===a){if(!i(t)||0===t.length)return void(e.selectedEntity=W());var r=t[0],n=new v({id:r.name,description:r.description});if(i(r.position)){var o=e.scene.globe.ellipsoid.cartographicToCartesian(r.position,K);n.position=new p(o)}e.selectedEntity=n}},function(){e.selectedEntity===a&&(e.selectedEntity=W())}),a}}function W(){return new v({id:"None",description:"No features found."})}function H(e,t,n,o){j(e);var a=E.defer();return e._zoomPromise=a,e._zoomIsFlight=o,e._zoomOptions=n,E(t,function(t){if(e._zoomPromise===a)if(t.isLoading&&i(t.loadingEvent))var n=t.loadingEvent.addEventListener(function(){n(),e._zoomPromise===a&&(e._zoomTarget=t.entities.values.slice(0))});else t=r(t.values,t),i(t.entities)&&(t=t.entities.values),u(t)?e._zoomTarget=t.slice(0):e._zoomTarget=[t]}),a.promise}function q(e){e._zoomPromise=void 0,e._zoomTarget=void 0,e._zoomOptions=void 0}function j(e){var t=e._zoomPromise;i(t)&&(q(e),t.resolve(!1))}function Y(t){var n=t._zoomTarget;if(i(n)&&t.scene.mode!==y.MORPHING){for(var o=t._zoomPromise,a=[],s=0,l=n.length;l>s;s++){var u=t._dataSourceDisplay.getBoundingSphere(n[s],!1,Z);if(u===d.PENDING)return;u!==d.FAILED&&a.push(e.clone(Z))}if(0===a.length)return void j(t);t.trackedEntity=void 0;var h=t.scene,p=h.camera,m=e.fromBoundingSpheres(a),f=h.screenSpaceCameraController;if(f.minimumZoomDistance=Math.min(f.minimumZoomDistance,.5*m.radius),t._zoomIsFlight){var v=r(t._zoomOptions,{}),_={duration:v.duration,maximumHeight:v.maximumHeight,complete:function(){o.resolve(!0)},cancel:function(){o.resolve(!1)},offset:v.offset};q(t),p.flyToBoundingSphere(m,_)}else p.viewBoundingSphere(m,t._zoomOptions),p.lookAtTransform(c.IDENTITY),q(t),o.resolve(!0)}}function X(e){if(e._needTrackedEntityUpdate){var t=e._trackedEntity,r=e.clock.currentTime,n=g.getValueOrUndefined(t.position,r);if(i(n)){var o=e.scene,a=e._dataSourceDisplay.getBoundingSphere(t,!1,Z);if(a!==d.PENDING){var s=o.mode;(s===y.COLUMBUS_VIEW||s===y.SCENE2D)&&(o.screenSpaceCameraController.enableTranslate=!1),(s===y.COLUMBUS_VIEW||s===y.SCENE3D)&&(o.screenSpaceCameraController.enableTilt=!1);var l=a!==d.FAILED?Z:void 0;e._entityView=new _(t,o,o.mapProjection.ellipsoid,l),e._entityView.update(r),e._needTrackedEntityUpdate=!1}}}}var Z=new e,K=new t,J=function(e,t){function o(e){var t=k(Ce,e);i(t)&&(g.getValueOrUndefined(t.position,Ce.clock.currentTime)?Ce.trackedEntity=t:Ce.zoomTo(t))}function a(e){Ce.selectedEntity=k(Ce,e)}e=D(e),t=r(t,r.EMPTY_OBJECT);var u=!(i(t.globe)&&t.globe===!1||i(t.baseLayerPicker)&&t.baseLayerPicker===!1),c=document.createElement("div");c.className="cesium-viewer",e.appendChild(c);var d=document.createElement("div");d.className="cesium-viewer-cesiumWidgetContainer",c.appendChild(d);var p=document.createElement("div");p.className="cesium-viewer-bottom",c.appendChild(p);var v=r(t.scene3DOnly,!1),_=new P(d,{terrainProvider:t.terrainProvider,imageryProvider:u?!1:t.imageryProvider,clock:t.clock,skyBox:t.skyBox,skyAtmosphere:t.skyAtmosphere,sceneMode:t.sceneMode,mapProjection:t.mapProjection,globe:t.globe,orderIndependentTranslucency:t.orderIndependentTranslucency,contextOptions:t.contextOptions,useDefaultRenderLoop:t.useDefaultRenderLoop,targetFrameRate:t.targetFrameRate,showRenderLoopErrors:t.showRenderLoopErrors,creditContainer:i(t.creditContainer)?t.creditContainer:p,scene3DOnly:v}),y=t.dataSources,E=!1;i(y)||(y=new m,E=!0);var U=new f({scene:_.scene,dataSourceCollection:y}),G=_.clock,W=new A(G),H=new l;H.add(G.onTick,J.prototype._onTick,this);var q;if(!i(t.selectionIndicator)||t.selectionIndicator!==!1){var j=document.createElement("div");j.className="cesium-viewer-selectionIndicatorContainer",c.appendChild(j),q=new F(j,_.scene)}var Y;if(!i(t.infoBox)||t.infoBox!==!1){var X=document.createElement("div");X.className="cesium-viewer-infoBoxContainer",c.appendChild(X),Y=new O(X);var Z=Y.viewModel;H.add(Z.cameraClicked,J.prototype._onInfoBoxCameraClicked,this),H.add(Z.closeClicked,J.prototype._onInfoBoxClockClicked,this)}var K=document.createElement("div");K.className="cesium-viewer-toolbar",c.appendChild(K);var Q;if(!i(t.geocoder)||t.geocoder!==!1){var $=document.createElement("div");$.className="cesium-viewer-geocoderContainer",K.appendChild($),Q=new M({container:$,scene:_.scene}),H.add(Q.viewModel.search.beforeExecute,J.prototype._clearObjects,this)}var ee;if(i(t.homeButton)&&t.homeButton===!1||(ee=new R(K,_.scene),i(Q)&&H.add(ee.viewModel.command.afterExecute,function(){var e=Q.viewModel;e.searchText="",e.isSearchInProgress&&e.search()}),H.add(ee.viewModel.command.beforeExecute,J.prototype._clearTrackedObject,this)),t.sceneModePicker===!0&&v)throw new s("options.sceneModePicker is not available when options.scene3DOnly is set to true.");var te;v||i(t.sceneModePicker)&&t.sceneModePicker===!1||(te=new L(K,_.scene));var re,ie;if(u){var ne=r(t.imageryProviderViewModels,b()),oe=r(t.terrainProviderViewModels,x());re=new T(K,{globe:_.scene.globe,imageryProviderViewModels:ne,selectedImageryProviderViewModel:t.selectedImageryProviderViewModel,terrainProviderViewModels:oe,selectedTerrainProviderViewModel:t.selectedTerrainProviderViewModel});var ae=K.getElementsByClassName("cesium-baseLayerPicker-dropDown");ie=ae[0]}var se;if(!i(t.navigationHelpButton)||t.navigationHelpButton!==!1){var le=!0;try{if(n(window.localStorage)){var ue=window.localStorage.getItem("cesium-hasSeenNavHelp");i(ue)&&Boolean(ue)?le=!1:window.localStorage.setItem("cesium-hasSeenNavHelp","true")}}catch(ce){}se=new N({container:K,instructionsInitiallyVisible:r(t.navigationInstructionsInitiallyVisible,le)})}var he;if(!i(t.animation)||t.animation!==!1){var de=document.createElement("div");de.className="cesium-viewer-animationContainer",c.appendChild(de),he=new S(de,new w(W))}var pe;if(!i(t.timeline)||t.timeline!==!1){var me=document.createElement("div");me.className="cesium-viewer-timelineContainer",c.appendChild(me),pe=new V(me,G),pe.addEventListener("settime",z,!1),pe.zoomTo(G.startTime,G.stopTime)}var fe,ve;if(i(t.fullscreenButton)&&t.fullscreenButton===!1)i(pe)&&(pe.container.style.right=0);else{var _e=document.createElement("div");_e.className="cesium-viewer-fullscreenContainer",c.appendChild(_e),fe=new I(_e,t.fullscreenElement),ve=B(fe.viewModel,"isFullscreenEnabled",function(e){_e.style.display=e?"block":"none",i(pe)&&(pe.container.style.right=_e.clientWidth+"px",pe.resize())})}this._baseLayerPickerDropDown=ie,this._fullscreenSubscription=ve,this._dataSourceChangedListeners={},this._automaticallyTrackDataSourceClocks=r(t.automaticallyTrackDataSourceClocks,!0),this._container=e,this._bottomContainer=p,this._element=c,this._cesiumWidget=_,this._selectionIndicator=q,this._infoBox=Y,this._dataSourceCollection=y,this._destroyDataSourceCollection=E,this._dataSourceDisplay=U,this._clockViewModel=W,this._toolbar=K,this._homeButton=ee,this._sceneModePicker=te,this._baseLayerPicker=re,this._navigationHelpButton=se,this._animation=he,this._timeline=pe,this._fullscreenButton=fe,this._geocoder=Q,this._eventHelper=H,this._lastWidth=0,this._lastHeight=0,this._allowDataSourcesToSuspendAnimation=!0,this._entityView=void 0,this._enableInfoOrSelection=i(Y)||i(q),this._clockTrackedDataSource=void 0,this._trackedEntity=void 0,this._needTrackedEntityUpdate=!1,this._selectedEntity=void 0,this._clockTrackedDataSource=void 0,this._forceResize=!1,this._zoomIsFlight=!1,this._zoomTarget=void 0,this._zoomPromise=void 0,this._zoomOptions=void 0,C.track(this,["_trackedEntity","_selectedEntity","_clockTrackedDataSource"]),H.add(y.dataSourceAdded,J.prototype._onDataSourceAdded,this),H.add(y.dataSourceRemoved,J.prototype._onDataSourceRemoved,this),H.add(_.scene.preRender,J.prototype.resize,this),H.add(_.scene.postRender,J.prototype._postRender,this);for(var ge=y.length,ye=0;ge>ye;ye++)this._dataSourceAdded(y,y.get(ye));this._dataSourceAdded(void 0,U.defaultDataSource),H.add(y.dataSourceAdded,J.prototype._dataSourceAdded,this),H.add(y.dataSourceRemoved,J.prototype._dataSourceRemoved,this);var Ce=this; +_.screenSpaceEventHandler.setInputAction(a,h.LEFT_CLICK),_.screenSpaceEventHandler.setInputAction(o,h.LEFT_DOUBLE_CLICK)};return o(J.prototype,{container:{get:function(){return this._container}},bottomContainer:{get:function(){return this._bottomContainer}},cesiumWidget:{get:function(){return this._cesiumWidget}},selectionIndicator:{get:function(){return this._selectionIndicator}},infoBox:{get:function(){return this._infoBox}},geocoder:{get:function(){return this._geocoder}},homeButton:{get:function(){return this._homeButton}},sceneModePicker:{get:function(){return this._sceneModePicker}},baseLayerPicker:{get:function(){return this._baseLayerPicker}},navigationHelpButton:{get:function(){return this._navigationHelpButton}},animation:{get:function(){return this._animation}},timeline:{get:function(){return this._timeline}},fullscreenButton:{get:function(){return this._fullscreenButton}},dataSourceDisplay:{get:function(){return this._dataSourceDisplay}},entities:{get:function(){return this._dataSourceDisplay.defaultDataSource.entities}},dataSources:{get:function(){return this._dataSourceCollection}},canvas:{get:function(){return this._cesiumWidget.canvas}},cesiumLogo:{get:function(){return this._cesiumWidget.cesiumLogo}},scene:{get:function(){return this._cesiumWidget.scene}},imageryLayers:{get:function(){return this.scene.imageryLayers}},terrainProvider:{get:function(){return this.scene.terrainProvider},set:function(e){this.scene.terrainProvider=e}},camera:{get:function(){return this.scene.camera}},clock:{get:function(){return this._cesiumWidget.clock}},screenSpaceEventHandler:{get:function(){return this._cesiumWidget.screenSpaceEventHandler}},targetFrameRate:{get:function(){return this._cesiumWidget.targetFrameRate},set:function(e){this._cesiumWidget.targetFrameRate=e}},useDefaultRenderLoop:{get:function(){return this._cesiumWidget.useDefaultRenderLoop},set:function(e){this._cesiumWidget.useDefaultRenderLoop=e}},resolutionScale:{get:function(){return this._cesiumWidget.resolutionScale},set:function(e){this._cesiumWidget.resolutionScale=e,this._forceResize=!0}},allowDataSourcesToSuspendAnimation:{get:function(){return this._allowDataSourcesToSuspendAnimation},set:function(e){this._allowDataSourcesToSuspendAnimation=e}},trackedEntity:{get:function(){return this._trackedEntity},set:function(e){if(this._trackedEntity!==e){this._trackedEntity=e,j(this);var t=this.scene,r=t.mode;if(!i(e)||!i(e.position))return this._needTrackedEntityUpdate=!1,(r===y.COLUMBUS_VIEW||r===y.SCENE2D)&&(t.screenSpaceCameraController.enableTranslate=!0),(r===y.COLUMBUS_VIEW||r===y.SCENE3D)&&(t.screenSpaceCameraController.enableTilt=!0),this._entityView=void 0,void this.camera.lookAtTransform(c.IDENTITY);this._needTrackedEntityUpdate=!0}}},selectedEntity:{get:function(){return this._selectedEntity},set:function(e){if(this._selectedEntity!==e){this._selectedEntity=e;var t=i(this._selectionIndicator)?this._selectionIndicator.viewModel:void 0;i(e)?i(t)&&t.animateAppear():i(t)&&t.animateDepart()}}},clockTrackedDataSource:{get:function(){return this._clockTrackedDataSource},set:function(e){this._clockTrackedDataSource!==e&&(this._clockTrackedDataSource=e,U(this._timeline,this.clock,e))}}}),J.prototype.extend=function(e,t){e(this,t)},J.prototype.resize=function(){var e=this._cesiumWidget,t=this._container,r=t.clientWidth,n=t.clientHeight,o=i(this._animation),a=i(this._timeline);if(this._forceResize||r!==this._lastWidth||n!==this._lastHeight){e.resize(),this._forceResize=!1;var s=n-125,l=this._baseLayerPickerDropDown;i(l)&&(l.style.maxHeight=s+"px"),i(this._infoBox)&&(this._infoBox.viewModel.maxHeight=s);var u,c=this._timeline,h=0,d=0,p=0;if(o&&"hidden"!==window.getComputedStyle(this._animation.container).visibility){var m=this._lastWidth;u=this._animation.container,r>900?(h=169,900>=m&&(u.style.width="169px",u.style.height="112px",this._animation.resize())):r>=600?(h=136,(600>m||m>900)&&(u.style.width="136px",u.style.height="90px",this._animation.resize())):(h=106,(m>600||0===m)&&(u.style.width="106px",u.style.height="70px",this._animation.resize())),d=h+5}if(a&&"hidden"!==window.getComputedStyle(this._timeline.container).visibility){var f=this._fullscreenButton,v=c.container,_=v.style;p=v.clientHeight+3,_.left=h+"px",i(f)&&(_.right=f.container.clientWidth+"px"),c.resize()}this._bottomContainer.style.left=d+"px",this._bottomContainer.style.bottom=p+"px",this._lastWidth=r,this._lastHeight=n}},J.prototype.forceResize=function(){this._lastWidth=0,this.resize()},J.prototype.render=function(){this._cesiumWidget.render()},J.prototype.isDestroyed=function(){return!1},J.prototype.destroy=function(){var e;this.screenSpaceEventHandler.removeInputAction(h.LEFT_CLICK),this.screenSpaceEventHandler.removeInputAction(h.LEFT_DOUBLE_CLICK);var t=this.dataSources,r=t.length;for(e=0;r>e;e++)this._dataSourceRemoved(t,t.get(e));return this._dataSourceRemoved(void 0,this._dataSourceDisplay.defaultDataSource),this._container.removeChild(this._element),this._element.removeChild(this._toolbar),this._eventHelper.removeAll(),i(this._geocoder)&&(this._geocoder=this._geocoder.destroy()),i(this._homeButton)&&(this._homeButton=this._homeButton.destroy()),i(this._sceneModePicker)&&(this._sceneModePicker=this._sceneModePicker.destroy()),i(this._baseLayerPicker)&&(this._baseLayerPicker=this._baseLayerPicker.destroy()),i(this._animation)&&(this._element.removeChild(this._animation.container),this._animation=this._animation.destroy()),i(this._timeline)&&(this._timeline.removeEventListener("settime",z,!1),this._element.removeChild(this._timeline.container),this._timeline=this._timeline.destroy()),i(this._fullscreenButton)&&(this._fullscreenSubscription.dispose(),this._element.removeChild(this._fullscreenButton.container),this._fullscreenButton=this._fullscreenButton.destroy()),i(this._infoBox)&&(this._element.removeChild(this._infoBox.container),this._infoBox=this._infoBox.destroy()),i(this._selectionIndicator)&&(this._element.removeChild(this._selectionIndicator.container),this._selectionIndicator=this._selectionIndicator.destroy()),this._clockViewModel=this._clockViewModel.destroy(),this._dataSourceDisplay=this._dataSourceDisplay.destroy(),this._cesiumWidget=this._cesiumWidget.destroy(),this._destroyDataSourceCollection&&(this._dataSourceCollection=this._dataSourceCollection.destroy()),a(this)},J.prototype._dataSourceAdded=function(e,t){var r=t.entities;r.collectionChanged.addEventListener(J.prototype._onEntityCollectionChanged,this)},J.prototype._dataSourceRemoved=function(e,t){var r=t.entities;r.collectionChanged.removeEventListener(J.prototype._onEntityCollectionChanged,this),i(this.trackedEntity)&&r.getById(this.trackedEntity.id)===this.trackedEntity&&(this.trackedEntity=void 0),i(this.selectedEntity)&&r.getById(this.selectedEntity.id)===this.selectedEntity&&(this.selectedEntity=void 0)},J.prototype._onTick=function(e){var n=e.currentTime,o=this._dataSourceDisplay.update(n);this._allowDataSourcesToSuspendAnimation&&(this._clockViewModel.canAnimate=o);var a=this._entityView;i(a)&&a.update(n);var s,l=!1,u=this.selectedEntity,c=i(u)&&this._enableInfoOrSelection;if(c&&u.isShowing&&u.isAvailable(n)){var h=this._dataSourceDisplay.getBoundingSphere(u,!0,Z);h!==d.FAILED?s=Z.center:i(u.position)&&(s=u.position.getValue(n,s)),l=i(s)}var p=i(this._selectionIndicator)?this._selectionIndicator.viewModel:void 0;i(p)&&(p.position=t.clone(s,p.position),p.showSelection=c&&l,p.update());var m=i(this._infoBox)?this._infoBox.viewModel:void 0;i(m)&&(m.showInfo=c,m.enableCamera=l,m.isCameraTracking=this.trackedEntity===this.selectedEntity,c?(m.titleText=r(u.name,u.id),m.description=g.getValueOrDefault(u.description,n,"")):(m.titleText="",m.description=""))},J.prototype._onEntityCollectionChanged=function(e,t,r){for(var i=r.length,n=0;i>n;n++){var o=r[n];this.trackedEntity===o&&(this.trackedEntity=void 0),this.selectedEntity===o&&(this.selectedEntity=void 0)}},J.prototype._onInfoBoxCameraClicked=function(e){if(e.isCameraTracking&&this.trackedEntity===this.selectedEntity)this.trackedEntity=void 0;else{var t=this.selectedEntity,r=t.position;i(r)?this.trackedEntity=this.selectedEntity:this.zoomTo(this.selectedEntity)}},J.prototype._clearTrackedObject=function(){this.trackedEntity=void 0},J.prototype._onInfoBoxClockClicked=function(e){this.selectedEntity=void 0},J.prototype._clearObjects=function(){this.trackedEntity=void 0,this.selectedEntity=void 0},J.prototype._onDataSourceChanged=function(e){this.clockTrackedDataSource===e&&U(this.timeline,this.clock,e)},J.prototype._onDataSourceAdded=function(e,t){this._automaticallyTrackDataSourceClocks&&(this.clockTrackedDataSource=t);var r=t.entities.id,i=this._eventHelper.add(t.changedEvent,J.prototype._onDataSourceChanged,this);this._dataSourceChangedListeners[r]=i},J.prototype._onDataSourceRemoved=function(e,t){var r=this.clockTrackedDataSource===t,i=t.entities.id;if(this._dataSourceChangedListeners[i](),this._dataSourceChangedListeners[i]=void 0,r){var n=e.length;this._automaticallyTrackDataSourceClocks&&n>0?this.clockTrackedDataSource=e.get(n-1):this.clockTrackedDataSource=void 0}},J.prototype.zoomTo=function(e,t){return H(this,e,t,!1)},J.prototype.flyTo=function(e,t){return H(this,e,t,!0)},J.prototype._postRender=function(){Y(this),X(this)},J}),r("Widgets/Viewer/viewerCesiumInspectorMixin",["../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../CesiumInspector/CesiumInspector"],function(e,t,r,i){"use strict";var n=function(n){if(!e(n))throw new r("viewer is required.");var o=document.createElement("div");o.className="cesium-viewer-cesiumInspectorContainer",n.container.appendChild(o);var a=new i(o,n.scene);t(n,{cesiumInspector:{get:function(){return a}}}),n.scene.postRender.addEventListener(function(){n.cesiumInspector.viewModel.update()})};return n}),r("Widgets/Viewer/viewerDragDropMixin",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/Event","../../Core/wrapFunction","../../DataSources/CzmlDataSource","../../DataSources/GeoJsonDataSource","../../DataSources/KmlDataSource","../getElement"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e){e.stopPropagation(),e.preventDefault()}function h(e,r){var i=e;t(i)&&(i.removeEventListener("drop",r,!1),i.removeEventListener("dragenter",c,!1),i.removeEventListener("dragover",c,!1),i.removeEventListener("dragexit",c,!1))}function d(e,t){e.addEventListener("drop",t,!1),e.addEventListener("dragenter",c,!1),e.addEventListener("dragover",c,!1),e.addEventListener("dragexit",c,!1)}function p(e,r,i){return function(n){var o=r.name;try{var u;if(/\.czml$/i.test(o))u=a.load(JSON.parse(n.target.result),{sourceUri:o});else if(/\.geojson$/i.test(o)||/\.json$/i.test(o)||/\.topojson$/i.test(o))u=s.load(JSON.parse(n.target.result),{sourceUri:o});else{if(!/\.(kml|kmz)$/i.test(o))return void e.dropError.raiseEvent(e,o,"Unrecognized file: "+o);u=l.load(r,{sourceUri:o,proxy:i})}t(u)&&e.dataSources.add(u).then(function(t){e.flyToOnDrop&&e.flyTo(t)}).otherwise(function(t){e.dropError.raiseEvent(e,o,t)})}catch(c){e.dropError.raiseEvent(e,o,c)}}}function m(e,t){return function(r){e.dropError.raiseEvent(e,t.name,r.target.error)}}var f=function(t,i){function a(e){c(e),v&&(t.entities.removeAll(),t.dataSources.removeAll());for(var r=e.dataTransfer.files,i=r.length,n=0;i>n;n++){var o=r[n],a=new FileReader;a.onload=p(t,o,g),a.onerror=m(t,o),a.readAsText(o)}}i=e(i,e.EMPTY_OBJECT);var s=!0,l=!0,f=new n,v=e(i.clearOnDrop,!0),_=e(i.dropTarget,t.container),g=i.proxy;_=u(_),r(t,{dropTarget:{get:function(){return _},set:function(e){h(_,a),_=e,d(_,a)}},dropEnabled:{get:function(){return s},set:function(e){e!==s&&(e?d(_,a):h(_,a),s=e)}},dropError:{get:function(){return f}},clearOnDrop:{get:function(){return v},set:function(e){v=e}},flyToOnDrop:{get:function(){return l},set:function(e){l=e}},proxy:{get:function(){return g},set:function(e){g=e}}}),d(_,a),t.destroy=o(t,t.destroy,function(){t.dropEnabled=!1}),t._handleDrop=a};return f}),r("Widgets/Viewer/viewerPerformanceWatchdogMixin",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../PerformanceWatchdog/PerformanceWatchdog"],function(e,t,r,i,n){"use strict";var o=function(o,a){if(!t(o))throw new i("viewer is required.");a=e(a,e.EMPTY_OBJECT);var s=new n({scene:o.scene,container:o.bottomContainer,lowFrameRateMessage:a.lowFrameRateMessage});r(o,{performanceWatchdog:{get:function(){return s}}})};return o}),r("Workers/createTaskProcessorWorker",["../Core/defaultValue","../Core/defined","../Core/formatError"],function(e,t,r){"use strict";var i=function(i){var n,o=[],a={id:void 0,result:void 0,error:void 0};return function(s){var l=s.data;o.length=0,a.id=l.id,a.error=void 0,a.result=void 0;try{a.result=i(l.parameters,o)}catch(u){u instanceof Error?a.error={name:u.name,message:u.message,stack:u.stack}:a.error=u}t(n)||(n=e(self.webkitPostMessage,self.postMessage)),l.canTransferArrayBuffer||(o.length=0);try{n(a,o)}catch(u){a.result=void 0,a.error="postMessage failed with error: "+r(u)+"\n with responseMessage: "+JSON.stringify(a),n(a)}}};return i}),r("Cesium",["./Core/ArcGisImageServerTerrainProvider","./Core/AssociativeArray","./Core/AttributeCompression","./Core/AxisAlignedBoundingBox","./Core/BingMapsApi","./Core/BoundingRectangle","./Core/BoundingSphere","./Core/BoxGeometry","./Core/BoxOutlineGeometry","./Core/Cartesian2","./Core/Cartesian3","./Core/Cartesian4","./Core/Cartographic","./Core/CatmullRomSpline","./Core/CesiumTerrainProvider","./Core/CircleGeometry","./Core/CircleOutlineGeometry","./Core/Clock","./Core/ClockRange","./Core/ClockStep","./Core/Color","./Core/ColorGeometryInstanceAttribute","./Core/ComponentDatatype","./Core/CornerType","./Core/CorridorGeometry","./Core/CorridorGeometryLibrary","./Core/CorridorOutlineGeometry","./Core/Credit","./Core/CubicRealPolynomial","./Core/CylinderGeometry","./Core/CylinderGeometryLibrary","./Core/CylinderOutlineGeometry","./Core/DefaultProxy","./Core/DeveloperError","./Core/EarthOrientationParameters","./Core/EarthOrientationParametersSample","./Core/EasingFunction","./Core/EllipseGeometry","./Core/EllipseGeometryLibrary","./Core/EllipseOutlineGeometry","./Core/Ellipsoid","./Core/EllipsoidGeodesic","./Core/EllipsoidGeometry","./Core/EllipsoidOutlineGeometry","./Core/EllipsoidTangentPlane","./Core/EllipsoidTerrainProvider","./Core/EllipsoidalOccluder","./Core/EncodedCartesian3","./Core/Event","./Core/EventHelper","./Core/ExtrapolationType","./Core/FeatureDetection","./Core/Fullscreen","./Core/GeographicProjection","./Core/GeographicTilingScheme","./Core/Geometry","./Core/GeometryAttribute","./Core/GeometryAttributes","./Core/GeometryInstance","./Core/GeometryInstanceAttribute","./Core/GeometryPipeline","./Core/GeometryType","./Core/GregorianDate","./Core/HeadingPitchRange","./Core/HeightmapTerrainData","./Core/HeightmapTessellator","./Core/HermitePolynomialApproximation","./Core/HermiteSpline","./Core/Iau2000Orientation","./Core/Iau2006XysData","./Core/Iau2006XysSample","./Core/IauOrientationAxes","./Core/IauOrientationParameters","./Core/IndexDatatype","./Core/InterpolationAlgorithm","./Core/Intersect","./Core/IntersectionTests","./Core/Intersections2D","./Core/Interval","./Core/Iso8601","./Core/JulianDate","./Core/KeyboardEventModifier","./Core/LagrangePolynomialApproximation","./Core/LeapSecond","./Core/LinearApproximation","./Core/LinearSpline","./Core/MapProjection","./Core/MapboxApi","./Core/Math","./Core/Matrix2","./Core/Matrix3","./Core/Matrix4","./Core/NearFarScalar","./Core/Occluder","./Core/OrientedBoundingBox","./Core/Packable","./Core/PackableForInterpolation","./Core/PinBuilder","./Core/PixelFormat","./Core/Plane","./Core/PolygonGeometry","./Core/PolygonGeometryLibrary","./Core/PolygonHierarchy","./Core/PolygonOutlineGeometry","./Core/PolygonPipeline","./Core/PolylineGeometry","./Core/PolylinePipeline","./Core/PolylineVolumeGeometry","./Core/PolylineVolumeGeometryLibrary","./Core/PolylineVolumeOutlineGeometry","./Core/PrimitiveType","./Core/QuadraticRealPolynomial","./Core/QuantizedMeshTerrainData","./Core/QuarticRealPolynomial","./Core/Quaternion","./Core/QuaternionSpline","./Core/Queue","./Core/Ray","./Core/Rectangle","./Core/RectangleGeometry","./Core/RectangleGeometryLibrary","./Core/RectangleOutlineGeometry","./Core/ReferenceFrame","./Core/RequestErrorEvent","./Core/RuntimeError","./Core/ScreenSpaceEventHandler","./Core/ScreenSpaceEventType","./Core/ShowGeometryInstanceAttribute","./Core/Simon1994PlanetaryPositions","./Core/SimplePolylineGeometry","./Core/SphereGeometry","./Core/SphereOutlineGeometry","./Core/Spherical","./Core/Spline","./Core/TaskProcessor","./Core/TerrainData","./Core/TerrainMesh","./Core/TerrainProvider","./Core/TileProviderError","./Core/TilingScheme","./Core/TimeConstants","./Core/TimeInterval","./Core/TimeIntervalCollection","./Core/TimeStandard","./Core/Tipsify","./Core/Transforms","./Core/TridiagonalSystemSolver","./Core/VRTheWorldTerrainProvider","./Core/VertexFormat","./Core/Visibility","./Core/WallGeometry","./Core/WallGeometryLibrary","./Core/WallOutlineGeometry","./Core/WebMercatorProjection","./Core/WebMercatorTilingScheme","./Core/WindingOrder","./Core/appendForwardSlash","./Core/barycentricCoordinates","./Core/binarySearch","./Core/buildModuleUrl","./Core/cancelAnimationFrame","./Core/clone","./Core/combine","./Core/createGuid","./Core/defaultValue","./Core/defineProperties","./Core/defined","./Core/definedNotNull","./Core/deprecationWarning","./Core/destroyObject","./Core/formatError","./Core/freezeObject","./Core/getFilenameFromUri","./Core/getImagePixels","./Core/getMagic","./Core/getStringFromTypedArray","./Core/getTimestamp","./Core/isArray","./Core/isCrossOriginUrl","./Core/isLeapYear","./Core/joinUrls","./Core/jsonp","./Core/loadArrayBuffer","./Core/loadBlob","./Core/loadImage","./Core/loadImageFromTypedArray","./Core/loadImageViaBlob","./Core/loadJson","./Core/loadJsonp","./Core/loadText","./Core/loadWithXhr","./Core/loadXML","./Core/mergeSort","./Core/objectToQuery","./Core/parseResponseHeaders","./Core/pointInsideTriangle","./Core/queryToObject","./Core/requestAnimationFrame","./Core/sampleTerrain","./Core/subdivideArray","./Core/throttleRequestByServer","./Core/wrapFunction","./Core/writeTextToCanvas","./DataSources/BillboardGraphics","./DataSources/BillboardVisualizer","./DataSources/BoundingSphereState","./DataSources/BoxGeometryUpdater","./DataSources/BoxGraphics","./DataSources/CallbackProperty","./DataSources/CheckerboardMaterialProperty","./DataSources/ColorMaterialProperty","./DataSources/CompositeEntityCollection","./DataSources/CompositeMaterialProperty","./DataSources/CompositePositionProperty","./DataSources/CompositeProperty","./DataSources/ConstantPositionProperty","./DataSources/ConstantProperty","./DataSources/CorridorGeometryUpdater","./DataSources/CorridorGraphics","./DataSources/CustomDataSource","./DataSources/CylinderGeometryUpdater","./DataSources/CylinderGraphics","./DataSources/CzmlDataSource","./DataSources/DataSource","./DataSources/DataSourceClock","./DataSources/DataSourceCollection","./DataSources/DataSourceDisplay","./DataSources/DynamicGeometryUpdater","./DataSources/EllipseGeometryUpdater","./DataSources/EllipseGraphics","./DataSources/EllipsoidGeometryUpdater","./DataSources/EllipsoidGraphics","./DataSources/Entity","./DataSources/EntityCollection","./DataSources/EntityView","./DataSources/GeoJsonDataSource","./DataSources/GeometryUpdater","./DataSources/GeometryVisualizer","./DataSources/GridMaterialProperty","./DataSources/ImageMaterialProperty","./DataSources/KmlDataSource","./DataSources/LabelGraphics","./DataSources/LabelVisualizer","./DataSources/MaterialProperty","./DataSources/ModelGraphics","./DataSources/ModelVisualizer","./DataSources/PathGraphics","./DataSources/PathVisualizer","./DataSources/PointGraphics","./DataSources/PointVisualizer","./DataSources/PolygonGeometryUpdater","./DataSources/PolygonGraphics","./DataSources/PolylineArrowMaterialProperty","./DataSources/PolylineGeometryUpdater","./DataSources/PolylineGlowMaterialProperty","./DataSources/PolylineGraphics","./DataSources/PolylineOutlineMaterialProperty","./DataSources/PolylineVolumeGeometryUpdater","./DataSources/PolylineVolumeGraphics","./DataSources/PositionProperty","./DataSources/PositionPropertyArray","./DataSources/Property","./DataSources/PropertyArray","./DataSources/RectangleGeometryUpdater","./DataSources/RectangleGraphics","./DataSources/ReferenceProperty","./DataSources/Rotation","./DataSources/SampledPositionProperty","./DataSources/SampledProperty","./DataSources/ScaledPositionProperty","./DataSources/StaticGeometryColorBatch","./DataSources/StaticGeometryPerMaterialBatch","./DataSources/StaticOutlineGeometryBatch","./DataSources/StripeMaterialProperty","./DataSources/StripeOrientation","./DataSources/TimeIntervalCollectionPositionProperty","./DataSources/TimeIntervalCollectionProperty","./DataSources/VelocityOrientationProperty","./DataSources/Visualizer","./DataSources/WallGeometryUpdater","./DataSources/WallGraphics","./DataSources/createMaterialPropertyDescriptor","./DataSources/createPropertyDescriptor","./DataSources/createRawPropertyDescriptor","./DataSources/dynamicGeometryGetBoundingSphere","./Renderer/AutomaticUniforms","./Renderer/Buffer","./Renderer/BufferUsage","./Renderer/ClearCommand","./Renderer/ComputeCommand","./Renderer/ComputeEngine","./Renderer/Context","./Renderer/ContextLimits","./Renderer/CubeMap","./Renderer/CubeMapFace","./Renderer/DrawCommand","./Renderer/Framebuffer","./Renderer/MipmapHint","./Renderer/PassState","./Renderer/PickFramebuffer","./Renderer/PixelDatatype","./Renderer/RenderState","./Renderer/Renderbuffer","./Renderer/RenderbufferFormat","./Renderer/Sampler","./Renderer/ShaderCache","./Renderer/ShaderProgram","./Renderer/ShaderSource","./Renderer/Texture","./Renderer/TextureMagnificationFilter","./Renderer/TextureMinificationFilter","./Renderer/TextureWrap","./Renderer/UniformState","./Renderer/VertexArray","./Renderer/VertexArrayFacade","./Renderer/WebGLConstants","./Renderer/createUniform","./Renderer/createUniformArray","./Renderer/loadCubeMap","./Scene/Appearance","./Scene/ArcGisMapServerImageryProvider","./Scene/Billboard","./Scene/BillboardCollection","./Scene/BingMapsImageryProvider","./Scene/BingMapsStyle","./Scene/BlendEquation","./Scene/BlendFunction","./Scene/BlendingState","./Scene/Camera","./Scene/CameraEventAggregator","./Scene/CameraEventType","./Scene/CameraFlightPath","./Scene/CreditDisplay","./Scene/CullFace","./Scene/CullingVolume","./Scene/DebugAppearance","./Scene/DebugModelMatrixPrimitive","./Scene/DepthFunction","./Scene/DepthPlane","./Scene/DiscardMissingTileImagePolicy","./Scene/EllipsoidPrimitive","./Scene/EllipsoidSurfaceAppearance","./Scene/FXAA","./Scene/Fog","./Scene/FrameRateMonitor","./Scene/FrameState","./Scene/FrustumCommands","./Scene/GetFeatureInfoFormat","./Scene/Globe","./Scene/GlobeDepth","./Scene/GlobeSurfaceShaderSet","./Scene/GlobeSurfaceTile","./Scene/GlobeSurfaceTileProvider","./Scene/GoogleEarthImageryProvider","./Scene/GridImageryProvider","./Scene/GroundPrimitive","./Scene/HeightReference","./Scene/HorizontalOrigin","./Scene/Imagery","./Scene/ImageryLayer","./Scene/ImageryLayerCollection","./Scene/ImageryLayerFeatureInfo","./Scene/ImageryProvider","./Scene/ImageryState","./Scene/Label","./Scene/LabelCollection","./Scene/LabelStyle","./Scene/MapboxImageryProvider","./Scene/Material","./Scene/MaterialAppearance","./Scene/Model","./Scene/ModelAnimation","./Scene/ModelAnimationCache","./Scene/ModelAnimationCollection","./Scene/ModelAnimationLoop","./Scene/ModelAnimationState","./Scene/ModelMaterial","./Scene/ModelMesh","./Scene/ModelNode","./Scene/Moon","./Scene/NeverTileDiscardPolicy","./Scene/OIT","./Scene/OpenStreetMapImageryProvider","./Scene/OrthographicFrustum","./Scene/Pass","./Scene/PerInstanceColorAppearance","./Scene/PerformanceDisplay","./Scene/PerspectiveFrustum","./Scene/PerspectiveOffCenterFrustum","./Scene/PickDepth","./Scene/PointPrimitive","./Scene/PointPrimitiveCollection","./Scene/Polygon","./Scene/Polyline","./Scene/PolylineCollection","./Scene/PolylineColorAppearance","./Scene/PolylineMaterialAppearance","./Scene/Primitive","./Scene/PrimitiveCollection","./Scene/PrimitivePipeline","./Scene/PrimitiveState","./Scene/QuadtreeOccluders","./Scene/QuadtreePrimitive","./Scene/QuadtreeTile","./Scene/QuadtreeTileLoadState","./Scene/QuadtreeTileProvider","./Scene/RectanglePrimitive","./Scene/Scene","./Scene/SceneMode","./Scene/SceneTransforms","./Scene/SceneTransitioner","./Scene/ScreenSpaceCameraController","./Scene/SingleTileImageryProvider","./Scene/SkyAtmosphere","./Scene/SkyBox","./Scene/StencilFunction","./Scene/StencilOperation","./Scene/Sun","./Scene/SunPostProcess","./Scene/TerrainState","./Scene/TextureAtlas","./Scene/TileCoordinatesImageryProvider","./Scene/TileDiscardPolicy","./Scene/TileImagery","./Scene/TileMapServiceImageryProvider","./Scene/TileReplacementQueue","./Scene/TileState","./Scene/TileTerrain","./Scene/TweenCollection","./Scene/UrlTemplateImageryProvider","./Scene/VerticalOrigin","./Scene/ViewportQuad","./Scene/WebMapServiceImageryProvider","./Scene/WebMapTileServiceImageryProvider","./Scene/createTangentSpaceDebugPrimitive","./Scene/getModelAccessor","./Scene/modelMaterialsCommon","./Scene/terrainAttributeLocations","./Shaders/AdjustTranslucentFS","./Shaders/Appearances/AllMaterialAppearanceFS","./Shaders/Appearances/AllMaterialAppearanceVS","./Shaders/Appearances/BasicMaterialAppearanceFS","./Shaders/Appearances/BasicMaterialAppearanceVS","./Shaders/Appearances/EllipsoidSurfaceAppearanceFS","./Shaders/Appearances/EllipsoidSurfaceAppearanceVS","./Shaders/Appearances/PerInstanceColorAppearanceFS","./Shaders/Appearances/PerInstanceColorAppearanceVS","./Shaders/Appearances/PerInstanceFlatColorAppearanceFS","./Shaders/Appearances/PerInstanceFlatColorAppearanceVS","./Shaders/Appearances/PolylineColorAppearanceVS","./Shaders/Appearances/PolylineMaterialAppearanceVS","./Shaders/Appearances/TexturedMaterialAppearanceFS","./Shaders/Appearances/TexturedMaterialAppearanceVS","./Shaders/BillboardCollectionFS","./Shaders/BillboardCollectionVS","./Shaders/Builtin/Constants/degreesPerRadian","./Shaders/Builtin/Constants/depthRange","./Shaders/Builtin/Constants/epsilon1","./Shaders/Builtin/Constants/epsilon2","./Shaders/Builtin/Constants/epsilon3","./Shaders/Builtin/Constants/epsilon4","./Shaders/Builtin/Constants/epsilon5","./Shaders/Builtin/Constants/epsilon6","./Shaders/Builtin/Constants/epsilon7","./Shaders/Builtin/Constants/infinity","./Shaders/Builtin/Constants/oneOverPi","./Shaders/Builtin/Constants/oneOverTwoPi","./Shaders/Builtin/Constants/pi","./Shaders/Builtin/Constants/piOverFour","./Shaders/Builtin/Constants/piOverSix","./Shaders/Builtin/Constants/piOverThree","./Shaders/Builtin/Constants/piOverTwo","./Shaders/Builtin/Constants/radiansPerDegree","./Shaders/Builtin/Constants/sceneMode2D","./Shaders/Builtin/Constants/sceneMode3D","./Shaders/Builtin/Constants/sceneModeColumbusView","./Shaders/Builtin/Constants/sceneModeMorphing","./Shaders/Builtin/Constants/solarRadius","./Shaders/Builtin/Constants/threePiOver2","./Shaders/Builtin/Constants/twoPi","./Shaders/Builtin/Constants/webMercatorMaxLatitude","./Shaders/Builtin/CzmBuiltins","./Shaders/Builtin/Functions/RGBToXYZ","./Shaders/Builtin/Functions/XYZToRGB","./Shaders/Builtin/Functions/alphaWeight","./Shaders/Builtin/Functions/antialias","./Shaders/Builtin/Functions/columbusViewMorph","./Shaders/Builtin/Functions/computePosition","./Shaders/Builtin/Functions/cosineAndSine","./Shaders/Builtin/Functions/decompressTextureCoordinates","./Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates","./Shaders/Builtin/Functions/ellipsoidContainsPoint","./Shaders/Builtin/Functions/ellipsoidNew","./Shaders/Builtin/Functions/ellipsoidWgs84TextureCoordinates","./Shaders/Builtin/Functions/equalsEpsilon","./Shaders/Builtin/Functions/eyeOffset","./Shaders/Builtin/Functions/eyeToWindowCoordinates","./Shaders/Builtin/Functions/fog","./Shaders/Builtin/Functions/geodeticSurfaceNormal","./Shaders/Builtin/Functions/getDefaultMaterial","./Shaders/Builtin/Functions/getLambertDiffuse","./Shaders/Builtin/Functions/getSpecular","./Shaders/Builtin/Functions/getWaterNoise","./Shaders/Builtin/Functions/getWgs84EllipsoidEC","./Shaders/Builtin/Functions/hue","./Shaders/Builtin/Functions/isEmpty","./Shaders/Builtin/Functions/isFull","./Shaders/Builtin/Functions/latitudeToWebMercatorFraction","./Shaders/Builtin/Functions/luminance","./Shaders/Builtin/Functions/metersPerPixel","./Shaders/Builtin/Functions/modelToWindowCoordinates","./Shaders/Builtin/Functions/multiplyWithColorBalance","./Shaders/Builtin/Functions/nearFarScalar","./Shaders/Builtin/Functions/octDecode","./Shaders/Builtin/Functions/packDepth","./Shaders/Builtin/Functions/phong","./Shaders/Builtin/Functions/pointAlongRay","./Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval","./Shaders/Builtin/Functions/saturation","./Shaders/Builtin/Functions/signNotZero","./Shaders/Builtin/Functions/tangentToEyeSpaceMatrix","./Shaders/Builtin/Functions/translateRelativeToEye","./Shaders/Builtin/Functions/translucentPhong","./Shaders/Builtin/Functions/transpose","./Shaders/Builtin/Functions/unpackDepth","./Shaders/Builtin/Functions/windowToEyeCoordinates","./Shaders/Builtin/Structs/depthRangeStruct","./Shaders/Builtin/Structs/ellipsoid","./Shaders/Builtin/Structs/material","./Shaders/Builtin/Structs/materialInput","./Shaders/Builtin/Structs/ray","./Shaders/Builtin/Structs/raySegment","./Shaders/CompositeOITFS","./Shaders/DepthPlaneFS","./Shaders/DepthPlaneVS","./Shaders/EllipsoidFS","./Shaders/EllipsoidVS","./Shaders/GlobeFS","./Shaders/GlobeFSPole","./Shaders/GlobeVS","./Shaders/GlobeVSPole","./Shaders/GroundAtmosphere","./Shaders/Materials/BumpMapMaterial","./Shaders/Materials/CheckerboardMaterial","./Shaders/Materials/DotMaterial","./Shaders/Materials/FadeMaterial","./Shaders/Materials/GridMaterial","./Shaders/Materials/NormalMapMaterial","./Shaders/Materials/PolylineArrowMaterial","./Shaders/Materials/PolylineGlowMaterial","./Shaders/Materials/PolylineOutlineMaterial","./Shaders/Materials/RimLightingMaterial","./Shaders/Materials/StripeMaterial","./Shaders/Materials/Water","./Shaders/PointPrimitiveCollectionFS","./Shaders/PointPrimitiveCollectionVS","./Shaders/PolylineCommon","./Shaders/PolylineFS","./Shaders/PolylineVS","./Shaders/PostProcessFilters/AdditiveBlend","./Shaders/PostProcessFilters/BrightPass","./Shaders/PostProcessFilters/FXAA","./Shaders/PostProcessFilters/GaussianBlur1D","./Shaders/PostProcessFilters/PassThrough","./Shaders/ReprojectWebMercatorFS","./Shaders/ReprojectWebMercatorVS","./Shaders/ShadowVolumeFS","./Shaders/ShadowVolumeVS","./Shaders/SkyAtmosphereFS","./Shaders/SkyAtmosphereVS","./Shaders/SkyBoxFS","./Shaders/SkyBoxVS","./Shaders/SunFS","./Shaders/SunTextureFS","./Shaders/SunVS","./Shaders/ViewportQuadFS","./Shaders/ViewportQuadVS","./ThirdParty/Autolinker","./ThirdParty/Tween","./ThirdParty/Uri","./ThirdParty/gltfDefaults","./ThirdParty/knockout-3.2.0","./ThirdParty/knockout-es5","./ThirdParty/knockout","./ThirdParty/measureText","./ThirdParty/mersenne-twister","./ThirdParty/sprintf","./ThirdParty/topojson","./ThirdParty/when","./ThirdParty/zip","./Widgets/Animation/Animation","./Widgets/Animation/AnimationViewModel","./Widgets/BaseLayerPicker/BaseLayerPicker","./Widgets/BaseLayerPicker/BaseLayerPickerViewModel","./Widgets/BaseLayerPicker/ProviderViewModel","./Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels","./Widgets/BaseLayerPicker/createDefaultTerrainProviderViewModels","./Widgets/CesiumInspector/CesiumInspector","./Widgets/CesiumInspector/CesiumInspectorViewModel","./Widgets/CesiumWidget/CesiumWidget","./Widgets/ClockViewModel","./Widgets/Command","./Widgets/FullscreenButton/FullscreenButton","./Widgets/FullscreenButton/FullscreenButtonViewModel","./Widgets/Geocoder/Geocoder","./Widgets/Geocoder/GeocoderViewModel","./Widgets/HomeButton/HomeButton","./Widgets/HomeButton/HomeButtonViewModel","./Widgets/InfoBox/InfoBox","./Widgets/InfoBox/InfoBoxViewModel","./Widgets/NavigationHelpButton/NavigationHelpButton","./Widgets/NavigationHelpButton/NavigationHelpButtonViewModel","./Widgets/PerformanceWatchdog/PerformanceWatchdog","./Widgets/PerformanceWatchdog/PerformanceWatchdogViewModel","./Widgets/SceneModePicker/SceneModePicker","./Widgets/SceneModePicker/SceneModePickerViewModel","./Widgets/SelectionIndicator/SelectionIndicator","./Widgets/SelectionIndicator/SelectionIndicatorViewModel","./Widgets/SvgPathBindingHandler","./Widgets/Timeline/Timeline","./Widgets/Timeline/TimelineHighlightRange","./Widgets/Timeline/TimelineTrack","./Widgets/ToggleButtonViewModel","./Widgets/Viewer/Viewer","./Widgets/Viewer/viewerCesiumInspectorMixin","./Widgets/Viewer/viewerDragDropMixin","./Widgets/Viewer/viewerPerformanceWatchdogMixin","./Widgets/createCommand","./Widgets/getElement","./Widgets/subscribeAndEvaluate","./Workers/createTaskProcessorWorker"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe,ae,se,le,ue,ce,he,de,pe,me,fe,ve,_e,ge,ye,Ce,Ee,Se,we,Te,be,xe,Pe,Ae,Ie,Me,De,Re,Oe,Ne,Le,Fe,Be,Ve,ze,ke,Ue,Ge,We,He,qe,je,Ye,Xe,Ze,Ke,Je,Qe,$e,et,tt,rt,it,nt,ot,at,st,lt,ut,ct,ht,dt,pt,mt,ft,vt,_t,gt,yt,Ct,Et,St,wt,Tt,bt,xt,Pt,At,It,Mt,Dt,Rt,Ot,Nt,Lt,Ft,Bt,Vt,zt,kt,Ut,Gt,Wt,Ht,qt,jt,Yt,Xt,Zt,Kt,Jt,Qt,$t,er,tr,rr,ir,nr,or,ar,sr,lr,ur,cr,hr,dr,pr,mr,fr,vr,_r,gr,yr,Cr,Er,Sr,wr,Tr,br,xr,Pr,Ar,Ir,Mr,Dr,Rr,Or,Nr,Lr,Fr,Br,Vr,zr,kr,Ur,Gr,Wr,Hr,qr,jr,Yr,Xr,Zr,Kr,Jr,Qr,$r,ei,ti,ri,ii,ni,oi,ai,si,li,ui,ci,hi,di,pi,mi,fi,vi,_i,gi,yi,Ci,Ei,Si,wi,Ti,bi,xi,Pi,Ai,Ii,Mi,Di,Ri,Oi,Ni,Li,Fi,Bi,Vi,zi,ki,Ui,Gi,Wi,Hi,qi,ji,Yi,Xi,Zi,Ki,Ji,Qi,$i,en,tn,rn,nn,on,an,sn,ln,un,cn,hn,dn,pn,mn,fn,vn,_n,gn,yn,Cn,En,Sn,wn,Tn,bn,xn,Pn,An,In,Mn,Dn,Rn,On,Nn,Ln,Fn,Bn,Vn,zn,kn,Un,Gn,Wn,Hn,qn,jn,Yn,Xn,Zn,Kn,Jn,Qn,$n,eo,to,ro,io,no,oo,ao,so,lo,uo,co,ho,po,mo,fo,vo,_o,go,yo,Co,Eo,So,wo,To,bo,xo,Po,Ao,Io,Mo,Do,Ro,Oo,No,Lo,Fo,Bo,Vo,zo,ko,Uo,Go,Wo,Ho,qo,jo,Yo,Xo,Zo,Ko,Jo,Qo,$o,ea,ta,ra,ia,na,oa,aa,sa,la,ua,ca,ha,da,pa,ma,fa,va,_a,ga,ya,Ca,Ea,Sa,wa,Ta,ba,xa,Pa,Aa,Ia,Ma,Da,Ra,Oa,Na,La,Fa,Ba,Va,za,ka,Ua,Ga,Wa,Ha,qa,ja,Ya,Xa,Za,Ka,Ja,Qa,$a,es,ts,rs,is,ns,os,as,ss,ls,us,cs,hs,ds,ps,ms,fs,vs,_s,gs,ys,Cs,Es,Ss,ws,Ts,bs,xs,Ps,As,Is,Ms,Ds,Rs,Os,Ns,Ls,Fs,Bs,Vs,zs,ks,Us,Gs,Ws,Hs,qs,js,Ys,Xs,Zs,Ks,Js,Qs,$s,el,tl,rl,il,nl,ol,al,sl,ll,ul,cl,hl,dl,pl,ml,fl,vl,_l,gl,yl,Cl,El,Sl,wl,Tl,bl,xl,Pl,Al,Il,Ml,Dl,Rl,Ol,Nl,Ll,Fl,Bl,Vl,zl,kl,Ul,Gl,Wl,Hl,ql,jl,Yl,Xl,Zl,Kl,Jl,Ql,$l,eu,tu,ru,iu,nu,ou,au,su,lu,uu,cu,hu,du,pu,mu,fu,vu,_u,gu,yu,Cu,Eu,Su,wu,Tu,bu,xu,Pu,Au,Iu,Mu,Du,Ru,Ou,Nu,Lu,Fu,Bu,Vu,zu,ku,Uu,Gu,Wu,Hu,qu,ju,Yu,Xu,Zu,Ku,Ju,Qu,$u,ec,tc,rc,ic,nc,oc,ac,sc,lc,uc,cc,hc,dc,pc,mc,fc,vc,_c,gc,yc,Cc,Ec,Sc,wc,Tc,bc,xc,Pc,Ac,Ic,Mc,Dc,Rc,Oc,Nc,Lc,Fc,Bc,Vc){ +"use strict";var zc={VERSION:"1.15",_shaders:{}};return zc.ArcGisImageServerTerrainProvider=e,zc.AssociativeArray=t,zc.AttributeCompression=r,zc.AxisAlignedBoundingBox=i,zc.BingMapsApi=n,zc.BoundingRectangle=o,zc.BoundingSphere=a,zc.BoxGeometry=s,zc.BoxOutlineGeometry=l,zc.Cartesian2=u,zc.Cartesian3=c,zc.Cartesian4=h,zc.Cartographic=d,zc.CatmullRomSpline=p,zc.CesiumTerrainProvider=m,zc.CircleGeometry=f,zc.CircleOutlineGeometry=v,zc.Clock=_,zc.ClockRange=g,zc.ClockStep=y,zc.Color=C,zc.ColorGeometryInstanceAttribute=E,zc.ComponentDatatype=S,zc.CornerType=w,zc.CorridorGeometry=T,zc.CorridorGeometryLibrary=b,zc.CorridorOutlineGeometry=x,zc.Credit=P,zc.CubicRealPolynomial=A,zc.CylinderGeometry=I,zc.CylinderGeometryLibrary=M,zc.CylinderOutlineGeometry=D,zc.DefaultProxy=R,zc.DeveloperError=O,zc.EarthOrientationParameters=N,zc.EarthOrientationParametersSample=L,zc.EasingFunction=F,zc.EllipseGeometry=B,zc.EllipseGeometryLibrary=V,zc.EllipseOutlineGeometry=z,zc.Ellipsoid=k,zc.EllipsoidGeodesic=U,zc.EllipsoidGeometry=G,zc.EllipsoidOutlineGeometry=W,zc.EllipsoidTangentPlane=H,zc.EllipsoidTerrainProvider=q,zc.EllipsoidalOccluder=j,zc.EncodedCartesian3=Y,zc.Event=X,zc.EventHelper=Z,zc.ExtrapolationType=K,zc.FeatureDetection=J,zc.Fullscreen=Q,zc.GeographicProjection=$,zc.GeographicTilingScheme=ee,zc.Geometry=te,zc.GeometryAttribute=re,zc.GeometryAttributes=ie,zc.GeometryInstance=ne,zc.GeometryInstanceAttribute=oe,zc.GeometryPipeline=ae,zc.GeometryType=se,zc.GregorianDate=le,zc.HeadingPitchRange=ue,zc.HeightmapTerrainData=ce,zc.HeightmapTessellator=he,zc.HermitePolynomialApproximation=de,zc.HermiteSpline=pe,zc.Iau2000Orientation=me,zc.Iau2006XysData=fe,zc.Iau2006XysSample=ve,zc.IauOrientationAxes=_e,zc.IauOrientationParameters=ge,zc.IndexDatatype=ye,zc.InterpolationAlgorithm=Ce,zc.Intersect=Ee,zc.IntersectionTests=Se,zc.Intersections2D=we,zc.Interval=Te,zc.Iso8601=be,zc.JulianDate=xe,zc.KeyboardEventModifier=Pe,zc.LagrangePolynomialApproximation=Ae,zc.LeapSecond=Ie,zc.LinearApproximation=Me,zc.LinearSpline=De,zc.MapProjection=Re,zc.MapboxApi=Oe,zc.Math=Ne,zc.Matrix2=Le,zc.Matrix3=Fe,zc.Matrix4=Be,zc.NearFarScalar=Ve,zc.Occluder=ze,zc.OrientedBoundingBox=ke,zc.Packable=Ue,zc.PackableForInterpolation=Ge,zc.PinBuilder=We,zc.PixelFormat=He,zc.Plane=qe,zc.PolygonGeometry=je,zc.PolygonGeometryLibrary=Ye,zc.PolygonHierarchy=Xe,zc.PolygonOutlineGeometry=Ze,zc.PolygonPipeline=Ke,zc.PolylineGeometry=Je,zc.PolylinePipeline=Qe,zc.PolylineVolumeGeometry=$e,zc.PolylineVolumeGeometryLibrary=et,zc.PolylineVolumeOutlineGeometry=tt,zc.PrimitiveType=rt,zc.QuadraticRealPolynomial=it,zc.QuantizedMeshTerrainData=nt,zc.QuarticRealPolynomial=ot,zc.Quaternion=at,zc.QuaternionSpline=st,zc.Queue=lt,zc.Ray=ut,zc.Rectangle=ct,zc.RectangleGeometry=ht,zc.RectangleGeometryLibrary=dt,zc.RectangleOutlineGeometry=pt,zc.ReferenceFrame=mt,zc.RequestErrorEvent=ft,zc.RuntimeError=vt,zc.ScreenSpaceEventHandler=_t,zc.ScreenSpaceEventType=gt,zc.ShowGeometryInstanceAttribute=yt,zc.Simon1994PlanetaryPositions=Ct,zc.SimplePolylineGeometry=Et,zc.SphereGeometry=St,zc.SphereOutlineGeometry=wt,zc.Spherical=Tt,zc.Spline=bt,zc.TaskProcessor=xt,zc.TerrainData=Pt,zc.TerrainMesh=At,zc.TerrainProvider=It,zc.TileProviderError=Mt,zc.TilingScheme=Dt,zc.TimeConstants=Rt,zc.TimeInterval=Ot,zc.TimeIntervalCollection=Nt,zc.TimeStandard=Lt,zc.Tipsify=Ft,zc.Transforms=Bt,zc.TridiagonalSystemSolver=Vt,zc.VRTheWorldTerrainProvider=zt,zc.VertexFormat=kt,zc.Visibility=Ut,zc.WallGeometry=Gt,zc.WallGeometryLibrary=Wt,zc.WallOutlineGeometry=Ht,zc.WebMercatorProjection=qt,zc.WebMercatorTilingScheme=jt,zc.WindingOrder=Yt,zc.appendForwardSlash=Xt,zc.barycentricCoordinates=Zt,zc.binarySearch=Kt,zc.buildModuleUrl=Jt,zc.cancelAnimationFrame=Qt,zc.clone=$t,zc.combine=er,zc.createGuid=tr,zc.defaultValue=rr,zc.defineProperties=ir,zc.defined=nr,zc.definedNotNull=or,zc.deprecationWarning=ar,zc.destroyObject=sr,zc.formatError=lr,zc.freezeObject=ur,zc.getFilenameFromUri=cr,zc.getImagePixels=hr,zc.getMagic=dr,zc.getStringFromTypedArray=pr,zc.getTimestamp=mr,zc.isArray=fr,zc.isCrossOriginUrl=vr,zc.isLeapYear=_r,zc.joinUrls=gr,zc.jsonp=yr,zc.loadArrayBuffer=Cr,zc.loadBlob=Er,zc.loadImage=Sr,zc.loadImageFromTypedArray=wr,zc.loadImageViaBlob=Tr,zc.loadJson=br,zc.loadJsonp=xr,zc.loadText=Pr,zc.loadWithXhr=Ar,zc.loadXML=Ir,zc.mergeSort=Mr,zc.objectToQuery=Dr,zc.parseResponseHeaders=Rr,zc.pointInsideTriangle=Or,zc.queryToObject=Nr,zc.requestAnimationFrame=Lr,zc.sampleTerrain=Fr,zc.subdivideArray=Br,zc.throttleRequestByServer=Vr,zc.wrapFunction=zr,zc.writeTextToCanvas=kr,zc.BillboardGraphics=Ur,zc.BillboardVisualizer=Gr,zc.BoundingSphereState=Wr,zc.BoxGeometryUpdater=Hr,zc.BoxGraphics=qr,zc.CallbackProperty=jr,zc.CheckerboardMaterialProperty=Yr,zc.ColorMaterialProperty=Xr,zc.CompositeEntityCollection=Zr,zc.CompositeMaterialProperty=Kr,zc.CompositePositionProperty=Jr,zc.CompositeProperty=Qr,zc.ConstantPositionProperty=$r,zc.ConstantProperty=ei,zc.CorridorGeometryUpdater=ti,zc.CorridorGraphics=ri,zc.CustomDataSource=ii,zc.CylinderGeometryUpdater=ni,zc.CylinderGraphics=oi,zc.CzmlDataSource=ai,zc.DataSource=si,zc.DataSourceClock=li,zc.DataSourceCollection=ui,zc.DataSourceDisplay=ci,zc.DynamicGeometryUpdater=hi,zc.EllipseGeometryUpdater=di,zc.EllipseGraphics=pi,zc.EllipsoidGeometryUpdater=mi,zc.EllipsoidGraphics=fi,zc.Entity=vi,zc.EntityCollection=_i,zc.EntityView=gi,zc.GeoJsonDataSource=yi,zc.GeometryUpdater=Ci,zc.GeometryVisualizer=Ei,zc.GridMaterialProperty=Si,zc.ImageMaterialProperty=wi,zc.KmlDataSource=Ti,zc.LabelGraphics=bi,zc.LabelVisualizer=xi,zc.MaterialProperty=Pi,zc.ModelGraphics=Ai,zc.ModelVisualizer=Ii,zc.PathGraphics=Mi,zc.PathVisualizer=Di,zc.PointGraphics=Ri,zc.PointVisualizer=Oi,zc.PolygonGeometryUpdater=Ni,zc.PolygonGraphics=Li,zc.PolylineArrowMaterialProperty=Fi,zc.PolylineGeometryUpdater=Bi,zc.PolylineGlowMaterialProperty=Vi,zc.PolylineGraphics=zi,zc.PolylineOutlineMaterialProperty=ki,zc.PolylineVolumeGeometryUpdater=Ui,zc.PolylineVolumeGraphics=Gi,zc.PositionProperty=Wi,zc.PositionPropertyArray=Hi,zc.Property=qi,zc.PropertyArray=ji,zc.RectangleGeometryUpdater=Yi,zc.RectangleGraphics=Xi,zc.ReferenceProperty=Zi,zc.Rotation=Ki,zc.SampledPositionProperty=Ji,zc.SampledProperty=Qi,zc.ScaledPositionProperty=$i,zc.StaticGeometryColorBatch=en,zc.StaticGeometryPerMaterialBatch=tn,zc.StaticOutlineGeometryBatch=rn,zc.StripeMaterialProperty=nn,zc.StripeOrientation=on,zc.TimeIntervalCollectionPositionProperty=an,zc.TimeIntervalCollectionProperty=sn,zc.VelocityOrientationProperty=ln,zc.Visualizer=un,zc.WallGeometryUpdater=cn,zc.WallGraphics=hn,zc.createMaterialPropertyDescriptor=dn,zc.createPropertyDescriptor=pn,zc.createRawPropertyDescriptor=mn,zc.dynamicGeometryGetBoundingSphere=fn,zc.AutomaticUniforms=vn,zc.Buffer=_n,zc.BufferUsage=gn,zc.ClearCommand=yn,zc.ComputeCommand=Cn,zc.ComputeEngine=En,zc.Context=Sn,zc.ContextLimits=wn,zc.CubeMap=Tn,zc.CubeMapFace=bn,zc.DrawCommand=xn,zc.Framebuffer=Pn,zc.MipmapHint=An,zc.PassState=In,zc.PickFramebuffer=Mn,zc.PixelDatatype=Dn,zc.RenderState=Rn,zc.Renderbuffer=On,zc.RenderbufferFormat=Nn,zc.Sampler=Ln,zc.ShaderCache=Fn,zc.ShaderProgram=Bn,zc.ShaderSource=Vn,zc.Texture=zn,zc.TextureMagnificationFilter=kn,zc.TextureMinificationFilter=Un,zc.TextureWrap=Gn,zc.UniformState=Wn,zc.VertexArray=Hn,zc.VertexArrayFacade=qn,zc.WebGLConstants=jn,zc.createUniform=Yn,zc.createUniformArray=Xn,zc.loadCubeMap=Zn,zc.Appearance=Kn,zc.ArcGisMapServerImageryProvider=Jn,zc.Billboard=Qn,zc.BillboardCollection=$n,zc.BingMapsImageryProvider=eo,zc.BingMapsStyle=to,zc.BlendEquation=ro,zc.BlendFunction=io,zc.BlendingState=no,zc.Camera=oo,zc.CameraEventAggregator=ao,zc.CameraEventType=so,zc.CameraFlightPath=lo,zc.CreditDisplay=uo,zc.CullFace=co,zc.CullingVolume=ho,zc.DebugAppearance=po,zc.DebugModelMatrixPrimitive=mo,zc.DepthFunction=fo,zc.DepthPlane=vo,zc.DiscardMissingTileImagePolicy=_o,zc.EllipsoidPrimitive=go,zc.EllipsoidSurfaceAppearance=yo,zc.FXAA=Co,zc.Fog=Eo,zc.FrameRateMonitor=So,zc.FrameState=wo,zc.FrustumCommands=To,zc.GetFeatureInfoFormat=bo,zc.Globe=xo,zc.GlobeDepth=Po,zc.GlobeSurfaceShaderSet=Ao,zc.GlobeSurfaceTile=Io,zc.GlobeSurfaceTileProvider=Mo,zc.GoogleEarthImageryProvider=Do,zc.GridImageryProvider=Ro,zc.GroundPrimitive=Oo,zc.HeightReference=No,zc.HorizontalOrigin=Lo,zc.Imagery=Fo,zc.ImageryLayer=Bo,zc.ImageryLayerCollection=Vo,zc.ImageryLayerFeatureInfo=zo,zc.ImageryProvider=ko,zc.ImageryState=Uo,zc.Label=Go,zc.LabelCollection=Wo,zc.LabelStyle=Ho,zc.MapboxImageryProvider=qo,zc.Material=jo,zc.MaterialAppearance=Yo,zc.Model=Xo,zc.ModelAnimation=Zo,zc.ModelAnimationCache=Ko,zc.ModelAnimationCollection=Jo,zc.ModelAnimationLoop=Qo,zc.ModelAnimationState=$o,zc.ModelMaterial=ea,zc.ModelMesh=ta,zc.ModelNode=ra,zc.Moon=ia,zc.NeverTileDiscardPolicy=na,zc.OIT=oa,zc.OpenStreetMapImageryProvider=aa,zc.OrthographicFrustum=sa,zc.Pass=la,zc.PerInstanceColorAppearance=ua,zc.PerformanceDisplay=ca,zc.PerspectiveFrustum=ha,zc.PerspectiveOffCenterFrustum=da,zc.PickDepth=pa,zc.PointPrimitive=ma,zc.PointPrimitiveCollection=fa,zc.Polygon=va,zc.Polyline=_a,zc.PolylineCollection=ga,zc.PolylineColorAppearance=ya,zc.PolylineMaterialAppearance=Ca,zc.Primitive=Ea,zc.PrimitiveCollection=Sa,zc.PrimitivePipeline=wa,zc.PrimitiveState=Ta,zc.QuadtreeOccluders=ba,zc.QuadtreePrimitive=xa,zc.QuadtreeTile=Pa,zc.QuadtreeTileLoadState=Aa,zc.QuadtreeTileProvider=Ia,zc.RectanglePrimitive=Ma,zc.Scene=Da,zc.SceneMode=Ra,zc.SceneTransforms=Oa,zc.SceneTransitioner=Na,zc.ScreenSpaceCameraController=La,zc.SingleTileImageryProvider=Fa,zc.SkyAtmosphere=Ba,zc.SkyBox=Va,zc.StencilFunction=za,zc.StencilOperation=ka,zc.Sun=Ua,zc.SunPostProcess=Ga,zc.TerrainState=Wa,zc.TextureAtlas=Ha,zc.TileCoordinatesImageryProvider=qa,zc.TileDiscardPolicy=ja,zc.TileImagery=Ya,zc.TileMapServiceImageryProvider=Xa,zc.TileReplacementQueue=Za,zc.TileState=Ka,zc.TileTerrain=Ja,zc.TweenCollection=Qa,zc.UrlTemplateImageryProvider=$a,zc.VerticalOrigin=es,zc.ViewportQuad=ts,zc.WebMapServiceImageryProvider=rs,zc.WebMapTileServiceImageryProvider=is,zc.createTangentSpaceDebugPrimitive=ns,zc.getModelAccessor=os,zc.modelMaterialsCommon=as,zc.terrainAttributeLocations=ss,zc._shaders.AdjustTranslucentFS=ls,zc._shaders.AllMaterialAppearanceFS=us,zc._shaders.AllMaterialAppearanceVS=cs,zc._shaders.BasicMaterialAppearanceFS=hs,zc._shaders.BasicMaterialAppearanceVS=ds,zc._shaders.EllipsoidSurfaceAppearanceFS=ps,zc._shaders.EllipsoidSurfaceAppearanceVS=ms,zc._shaders.PerInstanceColorAppearanceFS=fs,zc._shaders.PerInstanceColorAppearanceVS=vs,zc._shaders.PerInstanceFlatColorAppearanceFS=_s,zc._shaders.PerInstanceFlatColorAppearanceVS=gs,zc._shaders.PolylineColorAppearanceVS=ys,zc._shaders.PolylineMaterialAppearanceVS=Cs,zc._shaders.TexturedMaterialAppearanceFS=Es,zc._shaders.TexturedMaterialAppearanceVS=Ss,zc._shaders.BillboardCollectionFS=ws,zc._shaders.BillboardCollectionVS=Ts,zc._shaders.degreesPerRadian=bs,zc._shaders.depthRange=xs,zc._shaders.epsilon1=Ps,zc._shaders.epsilon2=As,zc._shaders.epsilon3=Is,zc._shaders.epsilon4=Ms,zc._shaders.epsilon5=Ds,zc._shaders.epsilon6=Rs,zc._shaders.epsilon7=Os,zc._shaders.infinity=Ns,zc._shaders.oneOverPi=Ls,zc._shaders.oneOverTwoPi=Fs,zc._shaders.pi=Bs,zc._shaders.piOverFour=Vs,zc._shaders.piOverSix=zs,zc._shaders.piOverThree=ks,zc._shaders.piOverTwo=Us,zc._shaders.radiansPerDegree=Gs,zc._shaders.sceneMode2D=Ws,zc._shaders.sceneMode3D=Hs,zc._shaders.sceneModeColumbusView=qs,zc._shaders.sceneModeMorphing=js,zc._shaders.solarRadius=Ys,zc._shaders.threePiOver2=Xs,zc._shaders.twoPi=Zs,zc._shaders.webMercatorMaxLatitude=Ks,zc._shaders.CzmBuiltins=Js,zc._shaders.RGBToXYZ=Qs,zc._shaders.XYZToRGB=$s,zc._shaders.alphaWeight=el,zc._shaders.antialias=tl,zc._shaders.columbusViewMorph=rl,zc._shaders.computePosition=il,zc._shaders.cosineAndSine=nl,zc._shaders.decompressTextureCoordinates=ol,zc._shaders.eastNorthUpToEyeCoordinates=al,zc._shaders.ellipsoidContainsPoint=sl,zc._shaders.ellipsoidNew=ll,zc._shaders.ellipsoidWgs84TextureCoordinates=ul,zc._shaders.equalsEpsilon=cl,zc._shaders.eyeOffset=hl,zc._shaders.eyeToWindowCoordinates=dl,zc._shaders.fog=pl,zc._shaders.geodeticSurfaceNormal=ml,zc._shaders.getDefaultMaterial=fl,zc._shaders.getLambertDiffuse=vl,zc._shaders.getSpecular=_l,zc._shaders.getWaterNoise=gl,zc._shaders.getWgs84EllipsoidEC=yl,zc._shaders.hue=Cl,zc._shaders.isEmpty=El,zc._shaders.isFull=Sl,zc._shaders.latitudeToWebMercatorFraction=wl,zc._shaders.luminance=Tl,zc._shaders.metersPerPixel=bl,zc._shaders.modelToWindowCoordinates=xl,zc._shaders.multiplyWithColorBalance=Pl,zc._shaders.nearFarScalar=Al,zc._shaders.octDecode=Il,zc._shaders.packDepth=Ml,zc._shaders.phong=Dl,zc._shaders.pointAlongRay=Rl,zc._shaders.rayEllipsoidIntersectionInterval=Ol,zc._shaders.saturation=Nl,zc._shaders.signNotZero=Ll,zc._shaders.tangentToEyeSpaceMatrix=Fl,zc._shaders.translateRelativeToEye=Bl,zc._shaders.translucentPhong=Vl,zc._shaders.transpose=zl,zc._shaders.unpackDepth=kl,zc._shaders.windowToEyeCoordinates=Ul,zc._shaders.depthRangeStruct=Gl,zc._shaders.ellipsoid=Wl,zc._shaders.material=Hl,zc._shaders.materialInput=ql,zc._shaders.ray=jl,zc._shaders.raySegment=Yl,zc._shaders.CompositeOITFS=Xl,zc._shaders.DepthPlaneFS=Zl,zc._shaders.DepthPlaneVS=Kl,zc._shaders.EllipsoidFS=Jl,zc._shaders.EllipsoidVS=Ql,zc._shaders.GlobeFS=$l,zc._shaders.GlobeFSPole=eu,zc._shaders.GlobeVS=tu,zc._shaders.GlobeVSPole=ru,zc._shaders.GroundAtmosphere=iu,zc._shaders.BumpMapMaterial=nu,zc._shaders.CheckerboardMaterial=ou,zc._shaders.DotMaterial=au,zc._shaders.FadeMaterial=su,zc._shaders.GridMaterial=lu,zc._shaders.NormalMapMaterial=uu,zc._shaders.PolylineArrowMaterial=cu,zc._shaders.PolylineGlowMaterial=hu,zc._shaders.PolylineOutlineMaterial=du,zc._shaders.RimLightingMaterial=pu,zc._shaders.StripeMaterial=mu,zc._shaders.Water=fu,zc._shaders.PointPrimitiveCollectionFS=vu,zc._shaders.PointPrimitiveCollectionVS=_u,zc._shaders.PolylineCommon=gu,zc._shaders.PolylineFS=yu,zc._shaders.PolylineVS=Cu,zc._shaders.AdditiveBlend=Eu,zc._shaders.BrightPass=Su,zc._shaders.FXAA=wu,zc._shaders.GaussianBlur1D=Tu,zc._shaders.PassThrough=bu,zc._shaders.ReprojectWebMercatorFS=xu,zc._shaders.ReprojectWebMercatorVS=Pu,zc._shaders.ShadowVolumeFS=Au,zc._shaders.ShadowVolumeVS=Iu,zc._shaders.SkyAtmosphereFS=Mu,zc._shaders.SkyAtmosphereVS=Du,zc._shaders.SkyBoxFS=Ru,zc._shaders.SkyBoxVS=Ou,zc._shaders.SunFS=Nu,zc._shaders.SunTextureFS=Lu,zc._shaders.SunVS=Fu,zc._shaders.ViewportQuadFS=Bu,zc._shaders.ViewportQuadVS=Vu,zc.Autolinker=zu,zc.Tween=ku,zc.Uri=Uu,zc.gltfDefaults=Gu,zc["knockout-3.2.0"]=Wu,zc["knockout-es5"]=Hu,zc.knockout=qu,zc.measureText=ju,zc["mersenne-twister"]=Yu,zc.sprintf=Xu,zc.topojson=Zu,zc.when=Ku,zc.zip=Ju,zc.Animation=Qu,zc.AnimationViewModel=$u,zc.BaseLayerPicker=ec,zc.BaseLayerPickerViewModel=tc,zc.ProviderViewModel=rc,zc.createDefaultImageryProviderViewModels=ic,zc.createDefaultTerrainProviderViewModels=nc,zc.CesiumInspector=oc,zc.CesiumInspectorViewModel=ac,zc.CesiumWidget=sc,zc.ClockViewModel=lc,zc.Command=uc,zc.FullscreenButton=cc,zc.FullscreenButtonViewModel=hc,zc.Geocoder=dc,zc.GeocoderViewModel=pc,zc.HomeButton=mc,zc.HomeButtonViewModel=fc,zc.InfoBox=vc,zc.InfoBoxViewModel=_c,zc.NavigationHelpButton=gc,zc.NavigationHelpButtonViewModel=yc,zc.PerformanceWatchdog=Cc,zc.PerformanceWatchdogViewModel=Ec,zc.SceneModePicker=Sc,zc.SceneModePickerViewModel=wc,zc.SelectionIndicator=Tc,zc.SelectionIndicatorViewModel=bc,zc.SvgPathBindingHandler=xc,zc.Timeline=Pc,zc.TimelineHighlightRange=Ac,zc.TimelineTrack=Ic,zc.ToggleButtonViewModel=Mc,zc.Viewer=Dc,zc.viewerCesiumInspectorMixin=Rc,zc.viewerDragDropMixin=Oc,zc.viewerPerformanceWatchdogMixin=Nc,zc.createCommand=Lc,zc.getElement=Fc,zc.subscribeAndEvaluate=Bc,zc.createTaskProcessorWorker=Vc,zc}),t(["Cesium"],function(e){"use strict";var t="undefined"!=typeof window?window:"undefined"!=typeof self?self:{};t.Cesium=e},void 0,!0)}(); \ No newline at end of file diff --git a/src/lib/ol-debug.js b/src/lib/ol-debug.js deleted file mode 100644 index 6822ade31d..0000000000 --- a/src/lib/ol-debug.js +++ /dev/null @@ -1,133718 +0,0 @@ -// OpenLayers 3. See http://openlayers.org/ -// License: https://raw.githubusercontent.com/openlayers/ol3/master/LICENSE.md -// Version: v3.11.1-86-g627abaf - -(function (root, factory) { - if (typeof exports === "object") { - module.exports = factory(); - } else if (typeof define === "function" && define.amd) { - define([], factory); - } else { - root.ol = factory(); - } -}(this, function () { - var OPENLAYERS = {}; - var goog = this.goog = {}; -this.CLOSURE_NO_DEPS = true; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Bootstrap for the Google JS Library (Closure). - * - * In uncompiled mode base.js will write out Closure's deps file, unless the - * global <code>CLOSURE_NO_DEPS</code> is set to true. This allows projects to - * include their own deps file(s) from different locations. - * - * @author arv@google.com (Erik Arvidsson) - * - * @provideGoog - */ - - -/** - * @define {boolean} Overridden to true by the compiler when - * --process_closure_primitives is specified. - */ -var COMPILED = false; - - -/** - * Base namespace for the Closure library. Checks to see goog is already - * defined in the current scope before assigning to prevent clobbering if - * base.js is loaded more than once. - * - * @const - */ -var goog = goog || {}; - - -/** - * Reference to the global context. In most cases this will be 'window'. - */ -goog.global = this; - - -/** - * A hook for overriding the define values in uncompiled mode. - * - * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before - * loading base.js. If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES}, - * {@code goog.define} will use the value instead of the default value. This - * allows flags to be overwritten without compilation (this is normally - * accomplished with the compiler's "define" flag). - * - * Example: - * <pre> - * var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false}; - * </pre> - * - * @type {Object<string, (string|number|boolean)>|undefined} - */ -goog.global.CLOSURE_UNCOMPILED_DEFINES; - - -/** - * A hook for overriding the define values in uncompiled or compiled mode, - * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code. In - * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence. - * - * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or - * string literals or the compiler will emit an error. - * - * While any @define value may be set, only those set with goog.define will be - * effective for uncompiled code. - * - * Example: - * <pre> - * var CLOSURE_DEFINES = {'goog.DEBUG': false} ; - * </pre> - * - * @type {Object<string, (string|number|boolean)>|undefined} - */ -goog.global.CLOSURE_DEFINES; - - -/** - * Returns true if the specified value is not undefined. - * WARNING: Do not use this to test if an object has a property. Use the in - * operator instead. - * - * @param {?} val Variable to test. - * @return {boolean} Whether variable is defined. - */ -goog.isDef = function(val) { - // void 0 always evaluates to undefined and hence we do not need to depend on - // the definition of the global variable named 'undefined'. - return val !== void 0; -}; - - -/** - * Builds an object structure for the provided namespace path, ensuring that - * names that already exist are not overwritten. For example: - * "a.b.c" -> a = {};a.b={};a.b.c={}; - * Used by goog.provide and goog.exportSymbol. - * @param {string} name name of the object that this file defines. - * @param {*=} opt_object the object to expose at the end of the path. - * @param {Object=} opt_objectToExportTo The object to add the path to; default - * is |goog.global|. - * @private - */ -goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { - var parts = name.split('.'); - var cur = opt_objectToExportTo || goog.global; - - // Internet Explorer exhibits strange behavior when throwing errors from - // methods externed in this manner. See the testExportSymbolExceptions in - // base_test.html for an example. - if (!(parts[0] in cur) && cur.execScript) { - cur.execScript('var ' + parts[0]); - } - - // Certain browsers cannot parse code in the form for((a in b); c;); - // This pattern is produced by the JSCompiler when it collapses the - // statement above into the conditional loop below. To prevent this from - // happening, use a for-loop and reserve the init logic as below. - - // Parentheses added to eliminate strict JS warning in Firefox. - for (var part; parts.length && (part = parts.shift());) { - if (!parts.length && goog.isDef(opt_object)) { - // last part and we have an object; use it - cur[part] = opt_object; - } else if (cur[part]) { - cur = cur[part]; - } else { - cur = cur[part] = {}; - } - } -}; - - -/** - * Defines a named value. In uncompiled mode, the value is retrieved from - * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and - * has the property specified, and otherwise used the defined defaultValue. - * When compiled the default can be overridden using the compiler - * options or the value set in the CLOSURE_DEFINES object. - * - * @param {string} name The distinguished name to provide. - * @param {string|number|boolean} defaultValue - */ -goog.define = function(name, defaultValue) { - var value = defaultValue; - if (!COMPILED) { - if (goog.global.CLOSURE_UNCOMPILED_DEFINES && - Object.prototype.hasOwnProperty.call( - goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) { - value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name]; - } else if (goog.global.CLOSURE_DEFINES && - Object.prototype.hasOwnProperty.call( - goog.global.CLOSURE_DEFINES, name)) { - value = goog.global.CLOSURE_DEFINES[name]; - } - } - goog.exportPath_(name, value); -}; - - -/** - * @define {boolean} DEBUG is provided as a convenience so that debugging code - * that should not be included in a production js_binary can be easily stripped - * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most - * toString() methods should be declared inside an "if (goog.DEBUG)" conditional - * because they are generally used for debugging purposes and it is difficult - * for the JSCompiler to statically determine whether they are used. - */ -goog.define('goog.DEBUG', true); - - -/** - * @define {string} LOCALE defines the locale being used for compilation. It is - * used to select locale specific data to be compiled in js binary. BUILD rule - * can specify this value by "--define goog.LOCALE=<locale_name>" as JSCompiler - * option. - * - * Take into account that the locale code format is important. You should use - * the canonical Unicode format with hyphen as a delimiter. Language must be - * lowercase, Language Script - Capitalized, Region - UPPERCASE. - * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN. - * - * See more info about locale codes here: - * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers - * - * For language codes you should use values defined by ISO 693-1. See it here - * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from - * this rule: the Hebrew language. For legacy reasons the old code (iw) should - * be used instead of the new code (he), see http://wiki/Main/IIISynonyms. - */ -goog.define('goog.LOCALE', 'en'); // default to en - - -/** - * @define {boolean} Whether this code is running on trusted sites. - * - * On untrusted sites, several native functions can be defined or overridden by - * external libraries like Prototype, Datejs, and JQuery and setting this flag - * to false forces closure to use its own implementations when possible. - * - * If your JavaScript can be loaded by a third party site and you are wary about - * relying on non-standard implementations, specify - * "--define goog.TRUSTED_SITE=false" to the JSCompiler. - */ -goog.define('goog.TRUSTED_SITE', true); - - -/** - * @define {boolean} Whether a project is expected to be running in strict mode. - * - * This define can be used to trigger alternate implementations compatible with - * running in EcmaScript Strict mode or warn about unavailable functionality. - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode - * - */ -goog.define('goog.STRICT_MODE_COMPATIBLE', false); - - -/** - * @define {boolean} Whether code that calls {@link goog.setTestOnly} should - * be disallowed in the compilation unit. - */ -goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG); - - -/** - * @define {boolean} Whether to use a Chrome app CSP-compliant method for - * loading scripts via goog.require. @see appendScriptSrcNode_. - */ -goog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false); - - -/** - * Defines a namespace in Closure. - * - * A namespace may only be defined once in a codebase. It may be defined using - * goog.provide() or goog.module(). - * - * The presence of one or more goog.provide() calls in a file indicates - * that the file defines the given objects/namespaces. - * Provided symbols must not be null or undefined. - * - * In addition, goog.provide() creates the object stubs for a namespace - * (for example, goog.provide("goog.foo.bar") will create the object - * goog.foo.bar if it does not already exist). - * - * Build tools also scan for provide/require/module statements - * to discern dependencies, build dependency files (see deps.js), etc. - * - * @see goog.require - * @see goog.module - * @param {string} name Namespace provided by this file in the form - * "goog.package.part". - */ -goog.provide = function(name) { - if (!COMPILED) { - // Ensure that the same namespace isn't provided twice. - // A goog.module/goog.provide maps a goog.require to a specific file - if (goog.isProvided_(name)) { - throw Error('Namespace "' + name + '" already declared.'); - } - } - - goog.constructNamespace_(name); -}; - - -/** - * @param {string} name Namespace provided by this file in the form - * "goog.package.part". - * @param {Object=} opt_obj The object to embed in the namespace. - * @private - */ -goog.constructNamespace_ = function(name, opt_obj) { - if (!COMPILED) { - delete goog.implicitNamespaces_[name]; - - var namespace = name; - while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) { - if (goog.getObjectByName(namespace)) { - break; - } - goog.implicitNamespaces_[namespace] = true; - } - } - - goog.exportPath_(name, opt_obj); -}; - - -/** - * Module identifier validation regexp. - * Note: This is a conservative check, it is very possible to be more lenient, - * the primary exclusion here is "/" and "\" and a leading ".", these - * restrictions are intended to leave the door open for using goog.require - * with relative file paths rather than module identifiers. - * @private - */ -goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/; - - -/** - * Defines a module in Closure. - * - * Marks that this file must be loaded as a module and claims the namespace. - * - * A namespace may only be defined once in a codebase. It may be defined using - * goog.provide() or goog.module(). - * - * goog.module() has three requirements: - * - goog.module may not be used in the same file as goog.provide. - * - goog.module must be the first statement in the file. - * - only one goog.module is allowed per file. - * - * When a goog.module annotated file is loaded, it is enclosed in - * a strict function closure. This means that: - * - any variables declared in a goog.module file are private to the file - * (not global), though the compiler is expected to inline the module. - * - The code must obey all the rules of "strict" JavaScript. - * - the file will be marked as "use strict" - * - * NOTE: unlike goog.provide, goog.module does not declare any symbols by - * itself. If declared symbols are desired, use - * goog.module.declareLegacyNamespace(). - * - * - * See the public goog.module proposal: http://goo.gl/Va1hin - * - * @param {string} name Namespace provided by this file in the form - * "goog.package.part", is expected but not required. - */ -goog.module = function(name) { - if (!goog.isString(name) || - !name || - name.search(goog.VALID_MODULE_RE_) == -1) { - throw Error('Invalid module identifier'); - } - if (!goog.isInModuleLoader_()) { - throw Error('Module ' + name + ' has been loaded incorrectly.'); - } - if (goog.moduleLoaderState_.moduleName) { - throw Error('goog.module may only be called once per module.'); - } - - // Store the module name for the loader. - goog.moduleLoaderState_.moduleName = name; - if (!COMPILED) { - // Ensure that the same namespace isn't provided twice. - // A goog.module/goog.provide maps a goog.require to a specific file - if (goog.isProvided_(name)) { - throw Error('Namespace "' + name + '" already declared.'); - } - delete goog.implicitNamespaces_[name]; - } -}; - - -/** - * @param {string} name The module identifier. - * @return {?} The module exports for an already loaded module or null. - * - * Note: This is not an alternative to goog.require, it does not - * indicate a hard dependency, instead it is used to indicate - * an optional dependency or to access the exports of a module - * that has already been loaded. - * @suppress {missingProvide} - */ -goog.module.get = function(name) { - return goog.module.getInternal_(name); -}; - - -/** - * @param {string} name The module identifier. - * @return {?} The module exports for an already loaded module or null. - * @private - */ -goog.module.getInternal_ = function(name) { - if (!COMPILED) { - if (goog.isProvided_(name)) { - // goog.require only return a value with-in goog.module files. - return name in goog.loadedModules_ ? - goog.loadedModules_[name] : - goog.getObjectByName(name); - } else { - return null; - } - } -}; - - -/** - * @private {?{moduleName: (string|undefined)}} - */ -goog.moduleLoaderState_ = null; - - -/** - * @private - * @return {boolean} Whether a goog.module is currently being initialized. - */ -goog.isInModuleLoader_ = function() { - return goog.moduleLoaderState_ != null; -}; - - -/** - * Provide the module's exports as a globally accessible object under the - * module's declared name. This is intended to ease migration to goog.module - * for files that have existing usages. - * @suppress {missingProvide} - */ -goog.module.declareLegacyNamespace = function() { - if (!COMPILED && !goog.isInModuleLoader_()) { - throw new Error('goog.module.declareLegacyNamespace must be called from ' + - 'within a goog.module'); - } - if (!COMPILED && !goog.moduleLoaderState_.moduleName) { - throw Error('goog.module must be called prior to ' + - 'goog.module.declareLegacyNamespace.'); - } - goog.moduleLoaderState_.declareLegacyNamespace = true; -}; - - -/** - * Marks that the current file should only be used for testing, and never for - * live code in production. - * - * In the case of unit tests, the message may optionally be an exact namespace - * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra - * provide (if not explicitly defined in the code). - * - * @param {string=} opt_message Optional message to add to the error that's - * raised when used in production code. - */ -goog.setTestOnly = function(opt_message) { - if (goog.DISALLOW_TEST_ONLY_CODE) { - opt_message = opt_message || ''; - throw Error('Importing test-only code into non-debug environment' + - (opt_message ? ': ' + opt_message : '.')); - } -}; - - -/** - * Forward declares a symbol. This is an indication to the compiler that the - * symbol may be used in the source yet is not required and may not be provided - * in compilation. - * - * The most common usage of forward declaration is code that takes a type as a - * function parameter but does not need to require it. By forward declaring - * instead of requiring, no hard dependency is made, and (if not required - * elsewhere) the namespace may never be required and thus, not be pulled - * into the JavaScript binary. If it is required elsewhere, it will be type - * checked as normal. - * - * - * @param {string} name The namespace to forward declare in the form of - * "goog.package.part". - */ -goog.forwardDeclare = function(name) {}; - - -/** - * Forward declare type information. Used to assign types to goog.global - * referenced object that would otherwise result in unknown type references - * and thus block property disambiguation. - */ -goog.forwardDeclare('Document'); -goog.forwardDeclare('XMLHttpRequest'); - - -if (!COMPILED) { - - /** - * Check if the given name has been goog.provided. This will return false for - * names that are available only as implicit namespaces. - * @param {string} name name of the object to look for. - * @return {boolean} Whether the name has been provided. - * @private - */ - goog.isProvided_ = function(name) { - return (name in goog.loadedModules_) || - (!goog.implicitNamespaces_[name] && - goog.isDefAndNotNull(goog.getObjectByName(name))); - }; - - /** - * Namespaces implicitly defined by goog.provide. For example, - * goog.provide('goog.events.Event') implicitly declares that 'goog' and - * 'goog.events' must be namespaces. - * - * @type {!Object<string, (boolean|undefined)>} - * @private - */ - goog.implicitNamespaces_ = {'goog.module': true}; - - // NOTE: We add goog.module as an implicit namespace as goog.module is defined - // here and because the existing module package has not been moved yet out of - // the goog.module namespace. This satisifies both the debug loader and - // ahead-of-time dependency management. -} - - -/** - * Returns an object based on its fully qualified external name. The object - * is not found if null or undefined. If you are using a compilation pass that - * renames property names beware that using this function will not find renamed - * properties. - * - * @param {string} name The fully qualified name. - * @param {Object=} opt_obj The object within which to look; default is - * |goog.global|. - * @return {?} The value (object or primitive) or, if not found, null. - */ -goog.getObjectByName = function(name, opt_obj) { - var parts = name.split('.'); - var cur = opt_obj || goog.global; - for (var part; part = parts.shift(); ) { - if (goog.isDefAndNotNull(cur[part])) { - cur = cur[part]; - } else { - return null; - } - } - return cur; -}; - - -/** - * Globalizes a whole namespace, such as goog or goog.lang. - * - * @param {!Object} obj The namespace to globalize. - * @param {Object=} opt_global The object to add the properties to. - * @deprecated Properties may be explicitly exported to the global scope, but - * this should no longer be done in bulk. - */ -goog.globalize = function(obj, opt_global) { - var global = opt_global || goog.global; - for (var x in obj) { - global[x] = obj[x]; - } -}; - - -/** - * Adds a dependency from a file to the files it requires. - * @param {string} relPath The path to the js file. - * @param {!Array<string>} provides An array of strings with - * the names of the objects this file provides. - * @param {!Array<string>} requires An array of strings with - * the names of the objects this file requires. - * @param {boolean=} opt_isModule Whether this dependency must be loaded as - * a module as declared by goog.module. - */ -goog.addDependency = function(relPath, provides, requires, opt_isModule) { - if (goog.DEPENDENCIES_ENABLED) { - var provide, require; - var path = relPath.replace(/\\/g, '/'); - var deps = goog.dependencies_; - for (var i = 0; provide = provides[i]; i++) { - deps.nameToPath[provide] = path; - deps.pathIsModule[path] = !!opt_isModule; - } - for (var j = 0; require = requires[j]; j++) { - if (!(path in deps.requires)) { - deps.requires[path] = {}; - } - deps.requires[path][require] = true; - } - } -}; - - - - -// NOTE(nnaze): The debug DOM loader was included in base.js as an original way -// to do "debug-mode" development. The dependency system can sometimes be -// confusing, as can the debug DOM loader's asynchronous nature. -// -// With the DOM loader, a call to goog.require() is not blocking -- the script -// will not load until some point after the current script. If a namespace is -// needed at runtime, it needs to be defined in a previous script, or loaded via -// require() with its registered dependencies. -// User-defined namespaces may need their own deps file. See http://go/js_deps, -// http://go/genjsdeps, or, externally, DepsWriter. -// https://developers.google.com/closure/library/docs/depswriter -// -// Because of legacy clients, the DOM loader can't be easily removed from -// base.js. Work is being done to make it disableable or replaceable for -// different environments (DOM-less JavaScript interpreters like Rhino or V8, -// for example). See bootstrap/ for more information. - - -/** - * @define {boolean} Whether to enable the debug loader. - * - * If enabled, a call to goog.require() will attempt to load the namespace by - * appending a script tag to the DOM (if the namespace has been registered). - * - * If disabled, goog.require() will simply assert that the namespace has been - * provided (and depend on the fact that some outside tool correctly ordered - * the script). - */ -goog.define('goog.ENABLE_DEBUG_LOADER', true); - - -/** - * @param {string} msg - * @private - */ -goog.logToConsole_ = function(msg) { - if (goog.global.console) { - goog.global.console['error'](msg); - } -}; - - -/** - * Implements a system for the dynamic resolution of dependencies that works in - * parallel with the BUILD system. Note that all calls to goog.require will be - * stripped by the JSCompiler when the --process_closure_primitives option is - * used. - * @see goog.provide - * @param {string} name Namespace to include (as was given in goog.provide()) in - * the form "goog.package.part". - * @return {?} If called within a goog.module file, the associated namespace or - * module otherwise null. - */ -goog.require = function(name) { - // If the object already exists we do not need do do anything. - if (!COMPILED) { - if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) { - goog.maybeProcessDeferredDep_(name); - } - - if (goog.isProvided_(name)) { - if (goog.isInModuleLoader_()) { - return goog.module.getInternal_(name); - } else { - return null; - } - } - - if (goog.ENABLE_DEBUG_LOADER) { - var path = goog.getPathFromDeps_(name); - if (path) { - goog.writeScripts_(path); - return null; - } - } - - var errorMessage = 'goog.require could not find: ' + name; - goog.logToConsole_(errorMessage); - - throw Error(errorMessage); - } -}; - - -/** - * Path for included scripts. - * @type {string} - */ -goog.basePath = ''; - - -/** - * A hook for overriding the base path. - * @type {string|undefined} - */ -goog.global.CLOSURE_BASE_PATH; - - -/** - * Whether to write out Closure's deps file. By default, the deps are written. - * @type {boolean|undefined} - */ -goog.global.CLOSURE_NO_DEPS; - - -/** - * A function to import a single script. This is meant to be overridden when - * Closure is being run in non-HTML contexts, such as web workers. It's defined - * in the global scope so that it can be set before base.js is loaded, which - * allows deps.js to be imported properly. - * - * The function is passed the script source, which is a relative URI. It should - * return true if the script was imported, false otherwise. - * @type {(function(string): boolean)|undefined} - */ -goog.global.CLOSURE_IMPORT_SCRIPT; - - -/** - * Null function used for default values of callbacks, etc. - * @return {void} Nothing. - */ -goog.nullFunction = function() {}; - - -/** - * When defining a class Foo with an abstract method bar(), you can do: - * Foo.prototype.bar = goog.abstractMethod - * - * Now if a subclass of Foo fails to override bar(), an error will be thrown - * when bar() is invoked. - * - * Note: This does not take the name of the function to override as an argument - * because that would make it more difficult to obfuscate our JavaScript code. - * - * @type {!Function} - * @throws {Error} when invoked to indicate the method should be overridden. - */ -goog.abstractMethod = function() { - throw Error('unimplemented abstract method'); -}; - - -/** - * Adds a {@code getInstance} static method that always returns the same - * instance object. - * @param {!Function} ctor The constructor for the class to add the static - * method to. - */ -goog.addSingletonGetter = function(ctor) { - ctor.getInstance = function() { - if (ctor.instance_) { - return ctor.instance_; - } - if (goog.DEBUG) { - // NOTE: JSCompiler can't optimize away Array#push. - goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor; - } - return ctor.instance_ = new ctor; - }; -}; - - -/** - * All singleton classes that have been instantiated, for testing. Don't read - * it directly, use the {@code goog.testing.singleton} module. The compiler - * removes this variable if unused. - * @type {!Array<!Function>} - * @private - */ -goog.instantiatedSingletons_ = []; - - -/** - * @define {boolean} Whether to load goog.modules using {@code eval} when using - * the debug loader. This provides a better debugging experience as the - * source is unmodified and can be edited using Chrome Workspaces or similar. - * However in some environments the use of {@code eval} is banned - * so we provide an alternative. - */ -goog.define('goog.LOAD_MODULE_USING_EVAL', true); - - -/** - * @define {boolean} Whether the exports of goog.modules should be sealed when - * possible. - */ -goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG); - - -/** - * The registry of initialized modules: - * the module identifier to module exports map. - * @private @const {!Object<string, ?>} - */ -goog.loadedModules_ = {}; - - -/** - * True if goog.dependencies_ is available. - * @const {boolean} - */ -goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; - - -if (goog.DEPENDENCIES_ENABLED) { - - /** - * This object is used to keep track of dependencies and other data that is - * used for loading scripts. - * @private - * @type {{ - * pathIsModule: !Object<string, boolean>, - * nameToPath: !Object<string, string>, - * requires: !Object<string, !Object<string, boolean>>, - * visited: !Object<string, boolean>, - * written: !Object<string, boolean>, - * deferred: !Object<string, string> - * }} - */ - goog.dependencies_ = { - pathIsModule: {}, // 1 to 1 - - nameToPath: {}, // 1 to 1 - - requires: {}, // 1 to many - - // Used when resolving dependencies to prevent us from visiting file twice. - visited: {}, - - written: {}, // Used to keep track of script files we have written. - - deferred: {} // Used to track deferred module evaluations in old IEs - }; - - - /** - * Tries to detect whether is in the context of an HTML document. - * @return {boolean} True if it looks like HTML document. - * @private - */ - goog.inHtmlDocument_ = function() { - /** @type {Document} */ - var doc = goog.global.document; - return typeof doc != 'undefined' && - 'write' in doc; // XULDocument misses write. - }; - - - /** - * Tries to detect the base path of base.js script that bootstraps Closure. - * @private - */ - goog.findBasePath_ = function() { - if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) { - goog.basePath = goog.global.CLOSURE_BASE_PATH; - return; - } else if (!goog.inHtmlDocument_()) { - return; - } - /** @type {Document} */ - var doc = goog.global.document; - var scripts = doc.getElementsByTagName('SCRIPT'); - // Search backwards since the current script is in almost all cases the one - // that has base.js. - for (var i = scripts.length - 1; i >= 0; --i) { - var script = /** @type {!HTMLScriptElement} */ (scripts[i]); - var src = script.src; - var qmark = src.lastIndexOf('?'); - var l = qmark == -1 ? src.length : qmark; - if (src.substr(l - 7, 7) == 'base.js') { - goog.basePath = src.substr(0, l - 7); - return; - } - } - }; - - - /** - * Imports a script if, and only if, that script hasn't already been imported. - * (Must be called at execution time) - * @param {string} src Script source. - * @param {string=} opt_sourceText The optionally source text to evaluate - * @private - */ - goog.importScript_ = function(src, opt_sourceText) { - var importScript = goog.global.CLOSURE_IMPORT_SCRIPT || - goog.writeScriptTag_; - if (importScript(src, opt_sourceText)) { - goog.dependencies_.written[src] = true; - } - }; - - - /** @const @private {boolean} */ - goog.IS_OLD_IE_ = !!(!goog.global.atob && goog.global.document && - goog.global.document.all); - - - /** - * Given a URL initiate retrieval and execution of the module. - * @param {string} src Script source URL. - * @private - */ - goog.importModule_ = function(src) { - // In an attempt to keep browsers from timing out loading scripts using - // synchronous XHRs, put each load in its own script block. - var bootstrap = 'goog.retrieveAndExecModule_("' + src + '");'; - - if (goog.importScript_('', bootstrap)) { - goog.dependencies_.written[src] = true; - } - }; - - - /** @private {!Array<string>} */ - goog.queuedModules_ = []; - - - /** - * Return an appropriate module text. Suitable to insert into - * a script tag (that is unescaped). - * @param {string} srcUrl - * @param {string} scriptText - * @return {string} - * @private - */ - goog.wrapModule_ = function(srcUrl, scriptText) { - if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) { - return '' + - 'goog.loadModule(function(exports) {' + - '"use strict";' + - scriptText + - '\n' + // terminate any trailing single line comment. - ';return exports' + - '});' + - '\n//# sourceURL=' + srcUrl + '\n'; - } else { - return '' + - 'goog.loadModule(' + - goog.global.JSON.stringify( - scriptText + '\n//# sourceURL=' + srcUrl + '\n') + - ');'; - } - }; - - // On IE9 and earlier, it is necessary to handle - // deferred module loads. In later browsers, the - // code to be evaluated is simply inserted as a script - // block in the correct order. To eval deferred - // code at the right time, we piggy back on goog.require to call - // goog.maybeProcessDeferredDep_. - // - // The goog.requires are used both to bootstrap - // the loading process (when no deps are available) and - // declare that they should be available. - // - // Here we eval the sources, if all the deps are available - // either already eval'd or goog.require'd. This will - // be the case when all the dependencies have already - // been loaded, and the dependent module is loaded. - // - // But this alone isn't sufficient because it is also - // necessary to handle the case where there is no root - // that is not deferred. For that there we register for an event - // and trigger goog.loadQueuedModules_ handle any remaining deferred - // evaluations. - - /** - * Handle any remaining deferred goog.module evals. - * @private - */ - goog.loadQueuedModules_ = function() { - var count = goog.queuedModules_.length; - if (count > 0) { - var queue = goog.queuedModules_; - goog.queuedModules_ = []; - for (var i = 0; i < count; i++) { - var path = queue[i]; - goog.maybeProcessDeferredPath_(path); - } - } - }; - - - /** - * Eval the named module if its dependencies are - * available. - * @param {string} name The module to load. - * @private - */ - goog.maybeProcessDeferredDep_ = function(name) { - if (goog.isDeferredModule_(name) && - goog.allDepsAreAvailable_(name)) { - var path = goog.getPathFromDeps_(name); - goog.maybeProcessDeferredPath_(goog.basePath + path); - } - }; - - /** - * @param {string} name The module to check. - * @return {boolean} Whether the name represents a - * module whose evaluation has been deferred. - * @private - */ - goog.isDeferredModule_ = function(name) { - var path = goog.getPathFromDeps_(name); - if (path && goog.dependencies_.pathIsModule[path]) { - var abspath = goog.basePath + path; - return (abspath) in goog.dependencies_.deferred; - } - return false; - }; - - /** - * @param {string} name The module to check. - * @return {boolean} Whether the name represents a - * module whose declared dependencies have all been loaded - * (eval'd or a deferred module load) - * @private - */ - goog.allDepsAreAvailable_ = function(name) { - var path = goog.getPathFromDeps_(name); - if (path && (path in goog.dependencies_.requires)) { - for (var requireName in goog.dependencies_.requires[path]) { - if (!goog.isProvided_(requireName) && - !goog.isDeferredModule_(requireName)) { - return false; - } - } - } - return true; - }; - - - /** - * @param {string} abspath - * @private - */ - goog.maybeProcessDeferredPath_ = function(abspath) { - if (abspath in goog.dependencies_.deferred) { - var src = goog.dependencies_.deferred[abspath]; - delete goog.dependencies_.deferred[abspath]; - goog.globalEval(src); - } - }; - - - /** - * @param {function(?):?|string} moduleDef The module definition. - */ - goog.loadModule = function(moduleDef) { - // NOTE: we allow function definitions to be either in the from - // of a string to eval (which keeps the original source intact) or - // in a eval forbidden environment (CSP) we allow a function definition - // which in its body must call {@code goog.module}, and return the exports - // of the module. - var previousState = goog.moduleLoaderState_; - try { - goog.moduleLoaderState_ = {moduleName: undefined}; - var exports; - if (goog.isFunction(moduleDef)) { - exports = moduleDef.call(goog.global, {}); - } else if (goog.isString(moduleDef)) { - exports = goog.loadModuleFromSource_.call(goog.global, moduleDef); - } else { - throw Error('Invalid module definition'); - } - - var moduleName = goog.moduleLoaderState_.moduleName; - if (!goog.isString(moduleName) || !moduleName) { - throw Error('Invalid module name \"' + moduleName + '\"'); - } - - // Don't seal legacy namespaces as they may be uses as a parent of - // another namespace - if (goog.moduleLoaderState_.declareLegacyNamespace) { - goog.constructNamespace_(moduleName, exports); - } else if (goog.SEAL_MODULE_EXPORTS && Object.seal) { - Object.seal(exports); - } - - goog.loadedModules_[moduleName] = exports; - } finally { - goog.moduleLoaderState_ = previousState; - } - }; - - - /** - * @private @const {function(string):?} - * @suppress {newCheckTypes} - */ - goog.loadModuleFromSource_ = function() { - // NOTE: we avoid declaring parameters or local variables here to avoid - // masking globals or leaking values into the module definition. - 'use strict'; - var exports = {}; - eval(arguments[0]); - return exports; - }; - - - /** - * Writes a new script pointing to {@code src} directly into the DOM. - * - * NOTE: This method is not CSP-compliant. @see goog.appendScriptSrcNode_ for - * the fallback mechanism. - * - * @param {string} src The script URL. - * @private - */ - goog.writeScriptSrcNode_ = function(src) { - goog.global.document.write( - '<script type="text/javascript" src="' + src + '"></' + 'script>'); - }; - - - /** - * Appends a new script node to the DOM using a CSP-compliant mechanism. This - * method exists as a fallback for document.write (which is not allowed in a - * strict CSP context, e.g., Chrome apps). - * - * NOTE: This method is not analogous to using document.write to insert a - * <script> tag; specifically, the user agent will execute a script added by - * document.write immediately after the current script block finishes - * executing, whereas the DOM-appended script node will not be executed until - * the entire document is parsed and executed. That is to say, this script is - * added to the end of the script execution queue. - * - * The page must not attempt to call goog.required entities until after the - * document has loaded, e.g., in or after the window.onload callback. - * - * @param {string} src The script URL. - * @private - */ - goog.appendScriptSrcNode_ = function(src) { - /** @type {Document} */ - var doc = goog.global.document; - var scriptEl = doc.createElement('script'); - scriptEl.type = 'text/javascript'; - scriptEl.src = src; - scriptEl.defer = false; - scriptEl.async = false; - doc.head.appendChild(scriptEl); - }; - - - /** - * The default implementation of the import function. Writes a script tag to - * import the script. - * - * @param {string} src The script url. - * @param {string=} opt_sourceText The optionally source text to evaluate - * @return {boolean} True if the script was imported, false otherwise. - * @private - */ - goog.writeScriptTag_ = function(src, opt_sourceText) { - if (goog.inHtmlDocument_()) { - /** @type {Document} */ - var doc = goog.global.document; - - // If the user tries to require a new symbol after document load, - // something has gone terribly wrong. Doing a document.write would - // wipe out the page. This does not apply to the CSP-compliant method - // of writing script tags. - if (!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING && - doc.readyState == 'complete') { - // Certain test frameworks load base.js multiple times, which tries - // to write deps.js each time. If that happens, just fail silently. - // These frameworks wipe the page between each load of base.js, so this - // is OK. - var isDeps = /\bdeps.js$/.test(src); - if (isDeps) { - return false; - } else { - throw Error('Cannot write "' + src + '" after document load'); - } - } - - var isOldIE = goog.IS_OLD_IE_; - - if (opt_sourceText === undefined) { - if (!isOldIE) { - if (goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING) { - goog.appendScriptSrcNode_(src); - } else { - goog.writeScriptSrcNode_(src); - } - } else { - var state = " onreadystatechange='goog.onScriptLoad_(this, " + - ++goog.lastNonModuleScriptIndex_ + ")' "; - doc.write( - '<script type="text/javascript" src="' + - src + '"' + state + '></' + 'script>'); - } - } else { - doc.write( - '<script type="text/javascript">' + - opt_sourceText + - '</' + 'script>'); - } - return true; - } else { - return false; - } - }; - - - /** @private {number} */ - goog.lastNonModuleScriptIndex_ = 0; - - - /** - * A readystatechange handler for legacy IE - * @param {!HTMLScriptElement} script - * @param {number} scriptIndex - * @return {boolean} - * @private - */ - goog.onScriptLoad_ = function(script, scriptIndex) { - // for now load the modules when we reach the last script, - // later allow more inter-mingling. - if (script.readyState == 'complete' && - goog.lastNonModuleScriptIndex_ == scriptIndex) { - goog.loadQueuedModules_(); - } - return true; - }; - - /** - * Resolves dependencies based on the dependencies added using addDependency - * and calls importScript_ in the correct order. - * @param {string} pathToLoad The path from which to start discovering - * dependencies. - * @private - */ - goog.writeScripts_ = function(pathToLoad) { - /** @type {!Array<string>} The scripts we need to write this time. */ - var scripts = []; - var seenScript = {}; - var deps = goog.dependencies_; - - /** @param {string} path */ - function visitNode(path) { - if (path in deps.written) { - return; - } - - // We have already visited this one. We can get here if we have cyclic - // dependencies. - if (path in deps.visited) { - return; - } - - deps.visited[path] = true; - - if (path in deps.requires) { - for (var requireName in deps.requires[path]) { - // If the required name is defined, we assume that it was already - // bootstrapped by other means. - if (!goog.isProvided_(requireName)) { - if (requireName in deps.nameToPath) { - visitNode(deps.nameToPath[requireName]); - } else { - throw Error('Undefined nameToPath for ' + requireName); - } - } - } - } - - if (!(path in seenScript)) { - seenScript[path] = true; - scripts.push(path); - } - } - - visitNode(pathToLoad); - - // record that we are going to load all these scripts. - for (var i = 0; i < scripts.length; i++) { - var path = scripts[i]; - goog.dependencies_.written[path] = true; - } - - // If a module is loaded synchronously then we need to - // clear the current inModuleLoader value, and restore it when we are - // done loading the current "requires". - var moduleState = goog.moduleLoaderState_; - goog.moduleLoaderState_ = null; - - for (var i = 0; i < scripts.length; i++) { - var path = scripts[i]; - if (path) { - if (!deps.pathIsModule[path]) { - goog.importScript_(goog.basePath + path); - } else { - goog.importModule_(goog.basePath + path); - } - } else { - goog.moduleLoaderState_ = moduleState; - throw Error('Undefined script input'); - } - } - - // restore the current "module loading state" - goog.moduleLoaderState_ = moduleState; - }; - - - /** - * Looks at the dependency rules and tries to determine the script file that - * fulfills a particular rule. - * @param {string} rule In the form goog.namespace.Class or project.script. - * @return {?string} Url corresponding to the rule, or null. - * @private - */ - goog.getPathFromDeps_ = function(rule) { - if (rule in goog.dependencies_.nameToPath) { - return goog.dependencies_.nameToPath[rule]; - } else { - return null; - } - }; - - goog.findBasePath_(); - - // Allow projects to manage the deps files themselves. - if (!goog.global.CLOSURE_NO_DEPS) { - goog.importScript_(goog.basePath + 'deps.js'); - } -} - - -/** - * Normalize a file path by removing redundant ".." and extraneous "." file - * path components. - * @param {string} path - * @return {string} - * @private - */ -goog.normalizePath_ = function(path) { - var components = path.split('/'); - var i = 0; - while (i < components.length) { - if (components[i] == '.') { - components.splice(i, 1); - } else if (i && components[i] == '..' && - components[i - 1] && components[i - 1] != '..') { - components.splice(--i, 2); - } else { - i++; - } - } - return components.join('/'); -}; - - -/** - * Loads file by synchronous XHR. Should not be used in production environments. - * @param {string} src Source URL. - * @return {string} File contents. - * @private - */ -goog.loadFileSync_ = function(src) { - if (goog.global.CLOSURE_LOAD_FILE_SYNC) { - return goog.global.CLOSURE_LOAD_FILE_SYNC(src); - } else { - /** @type {XMLHttpRequest} */ - var xhr = new goog.global['XMLHttpRequest'](); - xhr.open('get', src, false); - xhr.send(); - return xhr.responseText; - } -}; - - -/** - * Retrieve and execute a module. - * @param {string} src Script source URL. - * @private - */ -goog.retrieveAndExecModule_ = function(src) { - if (!COMPILED) { - // The full but non-canonicalized URL for later use. - var originalPath = src; - // Canonicalize the path, removing any /./ or /../ since Chrome's debugging - // console doesn't auto-canonicalize XHR loads as it does <script> srcs. - src = goog.normalizePath_(src); - - var importScript = goog.global.CLOSURE_IMPORT_SCRIPT || - goog.writeScriptTag_; - - var scriptText = goog.loadFileSync_(src); - - if (scriptText != null) { - var execModuleScript = goog.wrapModule_(src, scriptText); - var isOldIE = goog.IS_OLD_IE_; - if (isOldIE) { - goog.dependencies_.deferred[originalPath] = execModuleScript; - goog.queuedModules_.push(originalPath); - } else { - importScript(src, execModuleScript); - } - } else { - throw new Error('load of ' + src + 'failed'); - } - } -}; - - -//============================================================================== -// Language Enhancements -//============================================================================== - - -/** - * This is a "fixed" version of the typeof operator. It differs from the typeof - * operator in such a way that null returns 'null' and arrays return 'array'. - * @param {*} value The value to get the type of. - * @return {string} The name of the type. - */ -goog.typeOf = function(value) { - var s = typeof value; - if (s == 'object') { - if (value) { - // Check these first, so we can avoid calling Object.prototype.toString if - // possible. - // - // IE improperly marshals tyepof across execution contexts, but a - // cross-context object will still return false for "instanceof Object". - if (value instanceof Array) { - return 'array'; - } else if (value instanceof Object) { - return s; - } - - // HACK: In order to use an Object prototype method on the arbitrary - // value, the compiler requires the value be cast to type Object, - // even though the ECMA spec explicitly allows it. - var className = Object.prototype.toString.call( - /** @type {Object} */ (value)); - // In Firefox 3.6, attempting to access iframe window objects' length - // property throws an NS_ERROR_FAILURE, so we need to special-case it - // here. - if (className == '[object Window]') { - return 'object'; - } - - // We cannot always use constructor == Array or instanceof Array because - // different frames have different Array objects. In IE6, if the iframe - // where the array was created is destroyed, the array loses its - // prototype. Then dereferencing val.splice here throws an exception, so - // we can't use goog.isFunction. Calling typeof directly returns 'unknown' - // so that will work. In this case, this function will return false and - // most array functions will still work because the array is still - // array-like (supports length and []) even though it has lost its - // prototype. - // Mark Miller noticed that Object.prototype.toString - // allows access to the unforgeable [[Class]] property. - // 15.2.4.2 Object.prototype.toString ( ) - // When the toString method is called, the following steps are taken: - // 1. Get the [[Class]] property of this object. - // 2. Compute a string value by concatenating the three strings - // "[object ", Result(1), and "]". - // 3. Return Result(2). - // and this behavior survives the destruction of the execution context. - if ((className == '[object Array]' || - // In IE all non value types are wrapped as objects across window - // boundaries (not iframe though) so we have to do object detection - // for this edge case. - typeof value.length == 'number' && - typeof value.splice != 'undefined' && - typeof value.propertyIsEnumerable != 'undefined' && - !value.propertyIsEnumerable('splice') - - )) { - return 'array'; - } - // HACK: There is still an array case that fails. - // function ArrayImpostor() {} - // ArrayImpostor.prototype = []; - // var impostor = new ArrayImpostor; - // this can be fixed by getting rid of the fast path - // (value instanceof Array) and solely relying on - // (value && Object.prototype.toString.vall(value) === '[object Array]') - // but that would require many more function calls and is not warranted - // unless closure code is receiving objects from untrusted sources. - - // IE in cross-window calls does not correctly marshal the function type - // (it appears just as an object) so we cannot use just typeof val == - // 'function'. However, if the object has a call property, it is a - // function. - if ((className == '[object Function]' || - typeof value.call != 'undefined' && - typeof value.propertyIsEnumerable != 'undefined' && - !value.propertyIsEnumerable('call'))) { - return 'function'; - } - - } else { - return 'null'; - } - - } else if (s == 'function' && typeof value.call == 'undefined') { - // In Safari typeof nodeList returns 'function', and on Firefox typeof - // behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We - // would like to return object for those and we can detect an invalid - // function by making sure that the function object has a call method. - return 'object'; - } - return s; -}; - - -/** - * Returns true if the specified value is null. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is null. - */ -goog.isNull = function(val) { - return val === null; -}; - - -/** - * Returns true if the specified value is defined and not null. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is defined and not null. - */ -goog.isDefAndNotNull = function(val) { - // Note that undefined == null. - return val != null; -}; - - -/** - * Returns true if the specified value is an array. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is an array. - */ -goog.isArray = function(val) { - return goog.typeOf(val) == 'array'; -}; - - -/** - * Returns true if the object looks like an array. To qualify as array like - * the value needs to be either a NodeList or an object with a Number length - * property. As a special case, a function value is not array like, because its - * length property is fixed to correspond to the number of expected arguments. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is an array. - */ -goog.isArrayLike = function(val) { - var type = goog.typeOf(val); - // We do not use goog.isObject here in order to exclude function values. - return type == 'array' || type == 'object' && typeof val.length == 'number'; -}; - - -/** - * Returns true if the object looks like a Date. To qualify as Date-like the - * value needs to be an object and have a getFullYear() function. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is a like a Date. - */ -goog.isDateLike = function(val) { - return goog.isObject(val) && typeof val.getFullYear == 'function'; -}; - - -/** - * Returns true if the specified value is a string. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is a string. - */ -goog.isString = function(val) { - return typeof val == 'string'; -}; - - -/** - * Returns true if the specified value is a boolean. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is boolean. - */ -goog.isBoolean = function(val) { - return typeof val == 'boolean'; -}; - - -/** - * Returns true if the specified value is a number. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is a number. - */ -goog.isNumber = function(val) { - return typeof val == 'number'; -}; - - -/** - * Returns true if the specified value is a function. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is a function. - */ -goog.isFunction = function(val) { - return goog.typeOf(val) == 'function'; -}; - - -/** - * Returns true if the specified value is an object. This includes arrays and - * functions. - * @param {?} val Variable to test. - * @return {boolean} Whether variable is an object. - */ -goog.isObject = function(val) { - var type = typeof val; - return type == 'object' && val != null || type == 'function'; - // return Object(val) === val also works, but is slower, especially if val is - // not an object. -}; - - -/** - * Gets a unique ID for an object. This mutates the object so that further calls - * with the same object as a parameter returns the same value. The unique ID is - * guaranteed to be unique across the current session amongst objects that are - * passed into {@code getUid}. There is no guarantee that the ID is unique or - * consistent across sessions. It is unsafe to generate unique ID for function - * prototypes. - * - * @param {Object} obj The object to get the unique ID for. - * @return {number} The unique ID for the object. - */ -goog.getUid = function(obj) { - // TODO(arv): Make the type stricter, do not accept null. - - // In Opera window.hasOwnProperty exists but always returns false so we avoid - // using it. As a consequence the unique ID generated for BaseClass.prototype - // and SubClass.prototype will be the same. - return obj[goog.UID_PROPERTY_] || - (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_); -}; - - -/** - * Whether the given object is already assigned a unique ID. - * - * This does not modify the object. - * - * @param {!Object} obj The object to check. - * @return {boolean} Whether there is an assigned unique id for the object. - */ -goog.hasUid = function(obj) { - return !!obj[goog.UID_PROPERTY_]; -}; - - -/** - * Removes the unique ID from an object. This is useful if the object was - * previously mutated using {@code goog.getUid} in which case the mutation is - * undone. - * @param {Object} obj The object to remove the unique ID field from. - */ -goog.removeUid = function(obj) { - // TODO(arv): Make the type stricter, do not accept null. - - // In IE, DOM nodes are not instances of Object and throw an exception if we - // try to delete. Instead we try to use removeAttribute. - if ('removeAttribute' in obj) { - obj.removeAttribute(goog.UID_PROPERTY_); - } - /** @preserveTry */ - try { - delete obj[goog.UID_PROPERTY_]; - } catch (ex) { - } -}; - - -/** - * Name for unique ID property. Initialized in a way to help avoid collisions - * with other closure JavaScript on the same page. - * @type {string} - * @private - */ -goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0); - - -/** - * Counter for UID. - * @type {number} - * @private - */ -goog.uidCounter_ = 0; - - -/** - * Adds a hash code field to an object. The hash code is unique for the - * given object. - * @param {Object} obj The object to get the hash code for. - * @return {number} The hash code for the object. - * @deprecated Use goog.getUid instead. - */ -goog.getHashCode = goog.getUid; - - -/** - * Removes the hash code field from an object. - * @param {Object} obj The object to remove the field from. - * @deprecated Use goog.removeUid instead. - */ -goog.removeHashCode = goog.removeUid; - - -/** - * Clones a value. The input may be an Object, Array, or basic type. Objects and - * arrays will be cloned recursively. - * - * WARNINGS: - * <code>goog.cloneObject</code> does not detect reference loops. Objects that - * refer to themselves will cause infinite recursion. - * - * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies - * UIDs created by <code>getUid</code> into cloned results. - * - * @param {*} obj The value to clone. - * @return {*} A clone of the input value. - * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods. - */ -goog.cloneObject = function(obj) { - var type = goog.typeOf(obj); - if (type == 'object' || type == 'array') { - if (obj.clone) { - return obj.clone(); - } - var clone = type == 'array' ? [] : {}; - for (var key in obj) { - clone[key] = goog.cloneObject(obj[key]); - } - return clone; - } - - return obj; -}; - - -/** - * A native implementation of goog.bind. - * @param {Function} fn A function to partially apply. - * @param {Object|undefined} selfObj Specifies the object which this should - * point to when the function is run. - * @param {...*} var_args Additional arguments that are partially applied to the - * function. - * @return {!Function} A partially-applied form of the function bind() was - * invoked as a method of. - * @private - * @suppress {deprecated} The compiler thinks that Function.prototype.bind is - * deprecated because some people have declared a pure-JS version. - * Only the pure-JS version is truly deprecated. - */ -goog.bindNative_ = function(fn, selfObj, var_args) { - return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments)); -}; - - -/** - * A pure-JS implementation of goog.bind. - * @param {Function} fn A function to partially apply. - * @param {Object|undefined} selfObj Specifies the object which this should - * point to when the function is run. - * @param {...*} var_args Additional arguments that are partially applied to the - * function. - * @return {!Function} A partially-applied form of the function bind() was - * invoked as a method of. - * @private - */ -goog.bindJs_ = function(fn, selfObj, var_args) { - if (!fn) { - throw new Error(); - } - - if (arguments.length > 2) { - var boundArgs = Array.prototype.slice.call(arguments, 2); - return function() { - // Prepend the bound arguments to the current arguments. - var newArgs = Array.prototype.slice.call(arguments); - Array.prototype.unshift.apply(newArgs, boundArgs); - return fn.apply(selfObj, newArgs); - }; - - } else { - return function() { - return fn.apply(selfObj, arguments); - }; - } -}; - - -/** - * Partially applies this function to a particular 'this object' and zero or - * more arguments. The result is a new function with some arguments of the first - * function pre-filled and the value of this 'pre-specified'. - * - * Remaining arguments specified at call-time are appended to the pre-specified - * ones. - * - * Also see: {@link #partial}. - * - * Usage: - * <pre>var barMethBound = goog.bind(myFunction, myObj, 'arg1', 'arg2'); - * barMethBound('arg3', 'arg4');</pre> - * - * @param {?function(this:T, ...)} fn A function to partially apply. - * @param {T} selfObj Specifies the object which this should point to when the - * function is run. - * @param {...*} var_args Additional arguments that are partially applied to the - * function. - * @return {!Function} A partially-applied form of the function goog.bind() was - * invoked as a method of. - * @template T - * @suppress {deprecated} See above. - */ -goog.bind = function(fn, selfObj, var_args) { - // TODO(nicksantos): narrow the type signature. - if (Function.prototype.bind && - // NOTE(nicksantos): Somebody pulled base.js into the default Chrome - // extension environment. This means that for Chrome extensions, they get - // the implementation of Function.prototype.bind that calls goog.bind - // instead of the native one. Even worse, we don't want to introduce a - // circular dependency between goog.bind and Function.prototype.bind, so - // we have to hack this to make sure it works correctly. - Function.prototype.bind.toString().indexOf('native code') != -1) { - goog.bind = goog.bindNative_; - } else { - goog.bind = goog.bindJs_; - } - return goog.bind.apply(null, arguments); -}; - - -/** - * Like goog.bind(), except that a 'this object' is not required. Useful when - * the target function is already bound. - * - * Usage: - * var g = goog.partial(f, arg1, arg2); - * g(arg3, arg4); - * - * @param {Function} fn A function to partially apply. - * @param {...*} var_args Additional arguments that are partially applied to fn. - * @return {!Function} A partially-applied form of the function goog.partial() - * was invoked as a method of. - */ -goog.partial = function(fn, var_args) { - var args = Array.prototype.slice.call(arguments, 1); - return function() { - // Clone the array (with slice()) and append additional arguments - // to the existing arguments. - var newArgs = args.slice(); - newArgs.push.apply(newArgs, arguments); - return fn.apply(this, newArgs); - }; -}; - - -/** - * Copies all the members of a source object to a target object. This method - * does not work on all browsers for all objects that contain keys such as - * toString or hasOwnProperty. Use goog.object.extend for this purpose. - * @param {Object} target Target. - * @param {Object} source Source. - */ -goog.mixin = function(target, source) { - for (var x in source) { - target[x] = source[x]; - } - - // For IE7 or lower, the for-in-loop does not contain any properties that are - // not enumerable on the prototype object (for example, isPrototypeOf from - // Object.prototype) but also it will not include 'replace' on objects that - // extend String and change 'replace' (not that it is common for anyone to - // extend anything except Object). -}; - - -/** - * @return {number} An integer value representing the number of milliseconds - * between midnight, January 1, 1970 and the current time. - */ -goog.now = (goog.TRUSTED_SITE && Date.now) || (function() { - // Unary plus operator converts its operand to a number which in the case of - // a date is done by calling getTime(). - return +new Date(); -}); - - -/** - * Evals JavaScript in the global scope. In IE this uses execScript, other - * browsers use goog.global.eval. If goog.global.eval does not evaluate in the - * global scope (for example, in Safari), appends a script tag instead. - * Throws an exception if neither execScript or eval is defined. - * @param {string} script JavaScript string. - */ -goog.globalEval = function(script) { - if (goog.global.execScript) { - goog.global.execScript(script, 'JavaScript'); - } else if (goog.global.eval) { - // Test to see if eval works - if (goog.evalWorksForGlobals_ == null) { - goog.global.eval('var _evalTest_ = 1;'); - if (typeof goog.global['_evalTest_'] != 'undefined') { - try { - delete goog.global['_evalTest_']; - } catch (ignore) { - // Microsoft edge fails the deletion above in strict mode. - } - goog.evalWorksForGlobals_ = true; - } else { - goog.evalWorksForGlobals_ = false; - } - } - - if (goog.evalWorksForGlobals_) { - goog.global.eval(script); - } else { - /** @type {Document} */ - var doc = goog.global.document; - var scriptElt = doc.createElement('SCRIPT'); - scriptElt.type = 'text/javascript'; - scriptElt.defer = false; - // Note(user): can't use .innerHTML since "t('<test>')" will fail and - // .text doesn't work in Safari 2. Therefore we append a text node. - scriptElt.appendChild(doc.createTextNode(script)); - doc.body.appendChild(scriptElt); - doc.body.removeChild(scriptElt); - } - } else { - throw Error('goog.globalEval not available'); - } -}; - - -/** - * Indicates whether or not we can call 'eval' directly to eval code in the - * global scope. Set to a Boolean by the first call to goog.globalEval (which - * empirically tests whether eval works for globals). @see goog.globalEval - * @type {?boolean} - * @private - */ -goog.evalWorksForGlobals_ = null; - - -/** - * Optional map of CSS class names to obfuscated names used with - * goog.getCssName(). - * @private {!Object<string, string>|undefined} - * @see goog.setCssNameMapping - */ -goog.cssNameMapping_; - - -/** - * Optional obfuscation style for CSS class names. Should be set to either - * 'BY_WHOLE' or 'BY_PART' if defined. - * @type {string|undefined} - * @private - * @see goog.setCssNameMapping - */ -goog.cssNameMappingStyle_; - - -/** - * Handles strings that are intended to be used as CSS class names. - * - * This function works in tandem with @see goog.setCssNameMapping. - * - * Without any mapping set, the arguments are simple joined with a hyphen and - * passed through unaltered. - * - * When there is a mapping, there are two possible styles in which these - * mappings are used. In the BY_PART style, each part (i.e. in between hyphens) - * of the passed in css name is rewritten according to the map. In the BY_WHOLE - * style, the full css name is looked up in the map directly. If a rewrite is - * not specified by the map, the compiler will output a warning. - * - * When the mapping is passed to the compiler, it will replace calls to - * goog.getCssName with the strings from the mapping, e.g. - * var x = goog.getCssName('foo'); - * var y = goog.getCssName(this.baseClass, 'active'); - * becomes: - * var x= 'foo'; - * var y = this.baseClass + '-active'; - * - * If one argument is passed it will be processed, if two are passed only the - * modifier will be processed, as it is assumed the first argument was generated - * as a result of calling goog.getCssName. - * - * @param {string} className The class name. - * @param {string=} opt_modifier A modifier to be appended to the class name. - * @return {string} The class name or the concatenation of the class name and - * the modifier. - */ -goog.getCssName = function(className, opt_modifier) { - var getMapping = function(cssName) { - return goog.cssNameMapping_[cssName] || cssName; - }; - - var renameByParts = function(cssName) { - // Remap all the parts individually. - var parts = cssName.split('-'); - var mapped = []; - for (var i = 0; i < parts.length; i++) { - mapped.push(getMapping(parts[i])); - } - return mapped.join('-'); - }; - - var rename; - if (goog.cssNameMapping_) { - rename = goog.cssNameMappingStyle_ == 'BY_WHOLE' ? - getMapping : renameByParts; - } else { - rename = function(a) { - return a; - }; - } - - if (opt_modifier) { - return className + '-' + rename(opt_modifier); - } else { - return rename(className); - } -}; - - -/** - * Sets the map to check when returning a value from goog.getCssName(). Example: - * <pre> - * goog.setCssNameMapping({ - * "goog": "a", - * "disabled": "b", - * }); - * - * var x = goog.getCssName('goog'); - * // The following evaluates to: "a a-b". - * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled') - * </pre> - * When declared as a map of string literals to string literals, the JSCompiler - * will replace all calls to goog.getCssName() using the supplied map if the - * --process_closure_primitives flag is set. - * - * @param {!Object} mapping A map of strings to strings where keys are possible - * arguments to goog.getCssName() and values are the corresponding values - * that should be returned. - * @param {string=} opt_style The style of css name mapping. There are two valid - * options: 'BY_PART', and 'BY_WHOLE'. - * @see goog.getCssName for a description. - */ -goog.setCssNameMapping = function(mapping, opt_style) { - goog.cssNameMapping_ = mapping; - goog.cssNameMappingStyle_ = opt_style; -}; - - -/** - * To use CSS renaming in compiled mode, one of the input files should have a - * call to goog.setCssNameMapping() with an object literal that the JSCompiler - * can extract and use to replace all calls to goog.getCssName(). In uncompiled - * mode, JavaScript code should be loaded before this base.js file that declares - * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is - * to ensure that the mapping is loaded before any calls to goog.getCssName() - * are made in uncompiled mode. - * - * A hook for overriding the CSS name mapping. - * @type {!Object<string, string>|undefined} - */ -goog.global.CLOSURE_CSS_NAME_MAPPING; - - -if (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) { - // This does not call goog.setCssNameMapping() because the JSCompiler - // requires that goog.setCssNameMapping() be called with an object literal. - goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING; -} - - -/** - * Gets a localized message. - * - * This function is a compiler primitive. If you give the compiler a localized - * message bundle, it will replace the string at compile-time with a localized - * version, and expand goog.getMsg call to a concatenated string. - * - * Messages must be initialized in the form: - * <code> - * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'}); - * </code> - * - * @param {string} str Translatable string, places holders in the form {$foo}. - * @param {Object<string, string>=} opt_values Maps place holder name to value. - * @return {string} message with placeholders filled. - */ -goog.getMsg = function(str, opt_values) { - if (opt_values) { - str = str.replace(/\{\$([^}]+)}/g, function(match, key) { - return key in opt_values ? opt_values[key] : match; - }); - } - return str; -}; - - -/** - * Gets a localized message. If the message does not have a translation, gives a - * fallback message. - * - * This is useful when introducing a new message that has not yet been - * translated into all languages. - * - * This function is a compiler primitive. Must be used in the form: - * <code>var x = goog.getMsgWithFallback(MSG_A, MSG_B);</code> - * where MSG_A and MSG_B were initialized with goog.getMsg. - * - * @param {string} a The preferred message. - * @param {string} b The fallback message. - * @return {string} The best translated message. - */ -goog.getMsgWithFallback = function(a, b) { - return a; -}; - - -/** - * Exposes an unobfuscated global namespace path for the given object. - * Note that fields of the exported object *will* be obfuscated, unless they are - * exported in turn via this function or goog.exportProperty. - * - * Also handy for making public items that are defined in anonymous closures. - * - * ex. goog.exportSymbol('public.path.Foo', Foo); - * - * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction); - * public.path.Foo.staticFunction(); - * - * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod', - * Foo.prototype.myMethod); - * new public.path.Foo().myMethod(); - * - * @param {string} publicPath Unobfuscated name to export. - * @param {*} object Object the name should point to. - * @param {Object=} opt_objectToExportTo The object to add the path to; default - * is goog.global. - */ -goog.exportSymbol = function(publicPath, object, opt_objectToExportTo) { - goog.exportPath_(publicPath, object, opt_objectToExportTo); -}; - - -/** - * Exports a property unobfuscated into the object's namespace. - * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction); - * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod); - * @param {Object} object Object whose static property is being exported. - * @param {string} publicName Unobfuscated name to export. - * @param {*} symbol Object the name should point to. - */ -goog.exportProperty = function(object, publicName, symbol) { - object[publicName] = symbol; -}; - - -/** - * Inherit the prototype methods from one constructor into another. - * - * Usage: - * <pre> - * function ParentClass(a, b) { } - * ParentClass.prototype.foo = function(a) { }; - * - * function ChildClass(a, b, c) { - * ChildClass.base(this, 'constructor', a, b); - * } - * goog.inherits(ChildClass, ParentClass); - * - * var child = new ChildClass('a', 'b', 'see'); - * child.foo(); // This works. - * </pre> - * - * @param {!Function} childCtor Child class. - * @param {!Function} parentCtor Parent class. - */ -goog.inherits = function(childCtor, parentCtor) { - /** @constructor */ - function tempCtor() {}; - tempCtor.prototype = parentCtor.prototype; - childCtor.superClass_ = parentCtor.prototype; - childCtor.prototype = new tempCtor(); - /** @override */ - childCtor.prototype.constructor = childCtor; - - /** - * Calls superclass constructor/method. - * - * This function is only available if you use goog.inherits to - * express inheritance relationships between classes. - * - * NOTE: This is a replacement for goog.base and for superClass_ - * property defined in childCtor. - * - * @param {!Object} me Should always be "this". - * @param {string} methodName The method name to call. Calling - * superclass constructor can be done with the special string - * 'constructor'. - * @param {...*} var_args The arguments to pass to superclass - * method/constructor. - * @return {*} The return value of the superclass method/constructor. - */ - childCtor.base = function(me, methodName, var_args) { - // Copying using loop to avoid deop due to passing arguments object to - // function. This is faster in many JS engines as of late 2014. - var args = new Array(arguments.length - 2); - for (var i = 2; i < arguments.length; i++) { - args[i - 2] = arguments[i]; - } - return parentCtor.prototype[methodName].apply(me, args); - }; -}; - - -/** - * Call up to the superclass. - * - * If this is called from a constructor, then this calls the superclass - * constructor with arguments 1-N. - * - * If this is called from a prototype method, then you must pass the name of the - * method as the second argument to this function. If you do not, you will get a - * runtime error. This calls the superclass' method with arguments 2-N. - * - * This function only works if you use goog.inherits to express inheritance - * relationships between your classes. - * - * This function is a compiler primitive. At compile-time, the compiler will do - * macro expansion to remove a lot of the extra overhead that this function - * introduces. The compiler will also enforce a lot of the assumptions that this - * function makes, and treat it as a compiler error if you break them. - * - * @param {!Object} me Should always be "this". - * @param {*=} opt_methodName The method name if calling a super method. - * @param {...*} var_args The rest of the arguments. - * @return {*} The return value of the superclass method. - * @suppress {es5Strict} This method can not be used in strict mode, but - * all Closure Library consumers must depend on this file. - */ -goog.base = function(me, opt_methodName, var_args) { - var caller = arguments.callee.caller; - - if (goog.STRICT_MODE_COMPATIBLE || (goog.DEBUG && !caller)) { - throw Error('arguments.caller not defined. goog.base() cannot be used ' + - 'with strict mode code. See ' + - 'http://www.ecma-international.org/ecma-262/5.1/#sec-C'); - } - - if (caller.superClass_) { - // Copying using loop to avoid deop due to passing arguments object to - // function. This is faster in many JS engines as of late 2014. - var ctorArgs = new Array(arguments.length - 1); - for (var i = 1; i < arguments.length; i++) { - ctorArgs[i - 1] = arguments[i]; - } - // This is a constructor. Call the superclass constructor. - return caller.superClass_.constructor.apply(me, ctorArgs); - } - - // Copying using loop to avoid deop due to passing arguments object to - // function. This is faster in many JS engines as of late 2014. - var args = new Array(arguments.length - 2); - for (var i = 2; i < arguments.length; i++) { - args[i - 2] = arguments[i]; - } - var foundCaller = false; - for (var ctor = me.constructor; - ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { - if (ctor.prototype[opt_methodName] === caller) { - foundCaller = true; - } else if (foundCaller) { - return ctor.prototype[opt_methodName].apply(me, args); - } - } - - // If we did not find the caller in the prototype chain, then one of two - // things happened: - // 1) The caller is an instance method. - // 2) This method was not called by the right caller. - if (me[opt_methodName] === caller) { - return me.constructor.prototype[opt_methodName].apply(me, args); - } else { - throw Error( - 'goog.base called from a method of one name ' + - 'to a method of a different name'); - } -}; - - -/** - * Allow for aliasing within scope functions. This function exists for - * uncompiled code - in compiled code the calls will be inlined and the aliases - * applied. In uncompiled code the function is simply run since the aliases as - * written are valid JavaScript. - * - * - * @param {function()} fn Function to call. This function can contain aliases - * to namespaces (e.g. "var dom = goog.dom") or classes - * (e.g. "var Timer = goog.Timer"). - */ -goog.scope = function(fn) { - fn.call(goog.global); -}; - - -/* - * To support uncompiled, strict mode bundles that use eval to divide source - * like so: - * eval('someSource;//# sourceUrl sourcefile.js'); - * We need to export the globally defined symbols "goog" and "COMPILED". - * Exporting "goog" breaks the compiler optimizations, so we required that - * be defined externally. - * NOTE: We don't use goog.exportSymbol here because we don't want to trigger - * extern generation when that compiler option is enabled. - */ -if (!COMPILED) { - goog.global['COMPILED'] = COMPILED; -} - - - -//============================================================================== -// goog.defineClass implementation -//============================================================================== - - -/** - * Creates a restricted form of a Closure "class": - * - from the compiler's perspective, the instance returned from the - * constructor is sealed (no new properties may be added). This enables - * better checks. - * - the compiler will rewrite this definition to a form that is optimal - * for type checking and optimization (initially this will be a more - * traditional form). - * - * @param {Function} superClass The superclass, Object or null. - * @param {goog.defineClass.ClassDescriptor} def - * An object literal describing - * the class. It may have the following properties: - * "constructor": the constructor function - * "statics": an object literal containing methods to add to the constructor - * as "static" methods or a function that will receive the constructor - * function as its only parameter to which static properties can - * be added. - * all other properties are added to the prototype. - * @return {!Function} The class constructor. - */ -goog.defineClass = function(superClass, def) { - // TODO(johnlenz): consider making the superClass an optional parameter. - var constructor = def.constructor; - var statics = def.statics; - // Wrap the constructor prior to setting up the prototype and static methods. - if (!constructor || constructor == Object.prototype.constructor) { - constructor = function() { - throw Error('cannot instantiate an interface (no constructor defined).'); - }; - } - - var cls = goog.defineClass.createSealingConstructor_(constructor, superClass); - if (superClass) { - goog.inherits(cls, superClass); - } - - // Remove all the properties that should not be copied to the prototype. - delete def.constructor; - delete def.statics; - - goog.defineClass.applyProperties_(cls.prototype, def); - if (statics != null) { - if (statics instanceof Function) { - statics(cls); - } else { - goog.defineClass.applyProperties_(cls, statics); - } - } - - return cls; -}; - - -/** - * @typedef { - * !Object| - * {constructor:!Function}| - * {constructor:!Function, statics:(Object|function(Function):void)}} - * @suppress {missingProvide} - */ -goog.defineClass.ClassDescriptor; - - -/** - * @define {boolean} Whether the instances returned by - * goog.defineClass should be sealed when possible. - */ -goog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG); - - -/** - * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is - * defined, this function will wrap the constructor in a function that seals the - * results of the provided constructor function. - * - * @param {!Function} ctr The constructor whose results maybe be sealed. - * @param {Function} superClass The superclass constructor. - * @return {!Function} The replacement constructor. - * @private - */ -goog.defineClass.createSealingConstructor_ = function(ctr, superClass) { - if (goog.defineClass.SEAL_CLASS_INSTANCES && - Object.seal instanceof Function) { - // Don't seal subclasses of unsealable-tagged legacy classes. - if (superClass && superClass.prototype && - superClass.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_]) { - return ctr; - } - /** - * @this {Object} - * @return {?} - */ - var wrappedCtr = function() { - // Don't seal an instance of a subclass when it calls the constructor of - // its super class as there is most likely still setup to do. - var instance = ctr.apply(this, arguments) || this; - instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_]; - if (this.constructor === wrappedCtr) { - Object.seal(instance); - } - return instance; - }; - return wrappedCtr; - } - return ctr; -}; - - -// TODO(johnlenz): share these values with the goog.object -/** - * The names of the fields that are defined on Object.prototype. - * @type {!Array<string>} - * @private - * @const - */ -goog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [ - 'constructor', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'toLocaleString', - 'toString', - 'valueOf' -]; - - -// TODO(johnlenz): share this function with the goog.object -/** - * @param {!Object} target The object to add properties to. - * @param {!Object} source The object to copy properties from. - * @private - */ -goog.defineClass.applyProperties_ = function(target, source) { - // TODO(johnlenz): update this to support ES5 getters/setters - - var key; - for (key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - - // For IE the for-in-loop does not contain any properties that are not - // enumerable on the prototype object (for example isPrototypeOf from - // Object.prototype) and it will also not include 'replace' on objects that - // extend String and change 'replace' (not that it is common for anyone to - // extend anything except Object). - for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) { - key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i]; - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } -}; - - -/** - * Sealing classes breaks the older idiom of assigning properties on the - * prototype rather than in the constructor. As such, goog.defineClass - * must not seal subclasses of these old-style classes until they are fixed. - * Until then, this marks a class as "broken", instructing defineClass - * not to seal subclasses. - * @param {!Function} ctr The legacy constructor to tag as unsealable. - */ -goog.tagUnsealableClass = function(ctr) { - if (!COMPILED && goog.defineClass.SEAL_CLASS_INSTANCES) { - ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_] = true; - } -}; - - -/** - * Name for unsealable tag property. - * @const @private {string} - */ -goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable'; - -goog.provide('ol'); - - -/** - * Constants defined with the define tag cannot be changed in application - * code, but can be set at compile time. - * Some reduce the size of the build in advanced compile mode. - */ - - -/** - * @define {boolean} Assume touch. Default is `false`. - */ -ol.ASSUME_TOUCH = false; - - -/** - * TODO: rename this to something having to do with tile grids - * see https://github.com/openlayers/ol3/issues/2076 - * @define {number} Default maximum zoom for default tile grids. - */ -ol.DEFAULT_MAX_ZOOM = 42; - - -/** - * @define {number} Default min zoom level for the map view. Default is `0`. - */ -ol.DEFAULT_MIN_ZOOM = 0; - - -/** - * @define {number} Default maximum allowed threshold (in pixels) for - * reprojection triangulation. Default is `0.5`. - */ -ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD = 0.5; - - -/** - * @define {number} Default high water mark. - */ -ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK = 2048; - - -/** - * @define {number} Default tile size. - */ -ol.DEFAULT_TILE_SIZE = 256; - - -/** - * @define {string} Default WMS version. - */ -ol.DEFAULT_WMS_VERSION = '1.3.0'; - - -/** - * @define {number} Hysteresis pixels. - */ -ol.DRAG_BOX_HYSTERESIS_PIXELS = 8; - - -/** - * @define {boolean} Enable the Canvas renderer. Default is `true`. Setting - * this to false at compile time in advanced mode removes all code - * supporting the Canvas renderer from the build. - */ -ol.ENABLE_CANVAS = true; - - -/** - * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is - * not available). Default is `true`. Setting this to false at compile time - * in advanced mode removes all code supporting the DOM renderer from the - * build. - */ -ol.ENABLE_DOM = true; - - -/** - * @define {boolean} Enable rendering of ol.layer.Image based layers. Default - * is `true`. Setting this to false at compile time in advanced mode removes - * all code supporting Image layers from the build. - */ -ol.ENABLE_IMAGE = true; - - -/** - * @define {boolean} Enable Closure named colors (`goog.color.names`). - * Enabling these colors adds about 3KB uncompressed / 1.5KB compressed to - * the final build size. Default is `false`. This setting has no effect - * with Canvas renderer, which uses its own names, whether this is true or - * false. - */ -ol.ENABLE_NAMED_COLORS = false; - - -/** - * @define {boolean} Enable integration with the Proj4js library. Default is - * `true`. - */ -ol.ENABLE_PROJ4JS = true; - - -/** - * @define {boolean} Enable automatic reprojection of raster sources. Default is - * `true`. - */ -ol.ENABLE_RASTER_REPROJECTION = true; - - -/** - * @define {boolean} Enable rendering of ol.layer.Tile based layers. Default is - * `true`. Setting this to false at compile time in advanced mode removes - * all code supporting Tile layers from the build. - */ -ol.ENABLE_TILE = true; - - -/** - * @define {boolean} Enable rendering of ol.layer.Vector based layers. Default - * is `true`. Setting this to false at compile time in advanced mode removes - * all code supporting Vector layers from the build. - */ -ol.ENABLE_VECTOR = true; - - -/** - * @define {boolean} Enable rendering of ol.layer.VectorTile based layers. - * Default is `true`. Setting this to false at compile time in advanced mode - * removes all code supporting VectorTile layers from the build. - */ -ol.ENABLE_VECTOR_TILE = true; - - -/** - * @define {boolean} Enable the WebGL renderer. Default is `true`. Setting - * this to false at compile time in advanced mode removes all code - * supporting the WebGL renderer from the build. - */ -ol.ENABLE_WEBGL = true; - - -/** - * @define {number} The size in pixels of the first atlas image. Default is - * `256`. - */ -ol.INITIAL_ATLAS_SIZE = 256; - - -/** - * @define {number} The maximum size in pixels of atlas images. Default is - * `-1`, meaning it is not used (and `ol.WEBGL_MAX_TEXTURE_SIZE` is - * used instead). - */ -ol.MAX_ATLAS_SIZE = -1; - - -/** - * @define {number} Maximum mouse wheel delta. - */ -ol.MOUSEWHEELZOOM_MAXDELTA = 1; - - -/** - * @define {number} Mouse wheel timeout duration. - */ -ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80; - - -/** - * @define {number} Maximum width and/or height extent ratio that determines - * when the overview map should be zoomed out. - */ -ol.OVERVIEWMAP_MAX_RATIO = 0.75; - - -/** - * @define {number} Minimum width and/or height extent ratio that determines - * when the overview map should be zoomed in. - */ -ol.OVERVIEWMAP_MIN_RATIO = 0.1; - - -/** - * @define {number} Maximum number of source tiles for raster reprojection of - * a single tile. - * If too many source tiles are determined to be loaded to create a single - * reprojected tile the browser can become unresponsive or even crash. - * This can happen if the developer defines projections improperly and/or - * with unlimited extents. - * If too many tiles are required, no tiles are loaded and - * `ol.TileState.ERROR` state is set. Default is `100`. - */ -ol.RASTER_REPROJECTION_MAX_SOURCE_TILES = 100; - - -/** - * @define {number} Maximum number of subdivision steps during raster - * reprojection triangulation. Prevents high memory usage and large - * number of proj4 calls (for certain transformations and areas). - * At most `2*(2^this)` triangles are created for each triangulated - * extent (tile/image). Default is `10`. - */ -ol.RASTER_REPROJECTION_MAX_SUBDIVISION = 10; - - -/** - * @define {number} Maximum allowed size of triangle relative to world width. - * When transforming corners of world extent between certain projections, - * the resulting triangulation seems to have zero error and no subdivision - * is performed. - * If the triangle width is more than this (relative to world width; 0-1), - * subdivison is forced (up to `ol.RASTER_REPROJECTION_MAX_SUBDIVISION`). - * Default is `0.25`. - */ -ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH = 0.25; - - -/** - * @define {number} Tolerance for geometry simplification in device pixels. - */ -ol.SIMPLIFY_TOLERANCE = 0.5; - - -/** - * @define {number} Texture cache high water mark. - */ -ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024; - - -/** - * The maximum supported WebGL texture size in pixels. If WebGL is not - * supported, the value is set to `undefined`. - * @const - * @type {number|undefined} - */ -ol.WEBGL_MAX_TEXTURE_SIZE; // value is set in `ol.has` - - -/** - * List of supported WebGL extensions. - * @const - * @type {Array.<string>} - */ -ol.WEBGL_EXTENSIONS; // value is set in `ol.has` - - -/** - * Inherit the prototype methods from one constructor into another. - * - * Usage: - * - * function ParentClass(a, b) { } - * ParentClass.prototype.foo = function(a) { } - * - * function ChildClass(a, b, c) { - * // Call parent constructor - * ParentClass.call(this, a, b); - * } - * ol.inherits(ChildClass, ParentClass); - * - * var child = new ChildClass('a', 'b', 'see'); - * child.foo(); // This works. - * - * In addition, a superclass' implementation of a method can be invoked as - * follows: - * - * ChildClass.prototype.foo = function(a) { - * ChildClass.base(this, 'foo', a); - * // Other code here. - * }; - * - * @param {!Function} childCtor Child constructor. - * @param {!Function} parentCtor Parent constructor. - * @function - * @api - */ -ol.inherits = - goog.inherits; -// note that the newline above is necessary to satisfy the linter - - -/** - * A reusable function, used e.g. as a default for callbacks. - * - * @return {undefined} Nothing. - */ -ol.nullFunction = function() {}; - -// FIXME factor out common code between usedTiles and wantedTiles - -goog.provide('ol.PostRenderFunction'); -goog.provide('ol.PreRenderFunction'); - - -/** - * @typedef {function(ol.Map, ?olx.FrameState): boolean} - */ -ol.PostRenderFunction; - - -/** - * Function to perform manipulations before rendering. This function is called - * with the {@link ol.Map} as first and an optional {@link olx.FrameState} as - * second argument. Return `true` to keep this function for the next frame, - * `false` to remove it. - * @typedef {function(ol.Map, ?olx.FrameState): boolean} - * @api - */ -ol.PreRenderFunction; - -// Copyright 2009 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Provides a base class for custom Error objects such that the - * stack is correctly maintained. - * - * You should never need to throw goog.debug.Error(msg) directly, Error(msg) is - * sufficient. - * - */ - -goog.provide('goog.debug.Error'); - - - -/** - * Base class for custom error objects. - * @param {*=} opt_msg The message associated with the error. - * @constructor - * @extends {Error} - */ -goog.debug.Error = function(opt_msg) { - - // Attempt to ensure there is a stack trace. - if (Error.captureStackTrace) { - Error.captureStackTrace(this, goog.debug.Error); - } else { - var stack = new Error().stack; - if (stack) { - this.stack = stack; - } - } - - if (opt_msg) { - this.message = String(opt_msg); - } - - /** - * Whether to report this error to the server. Setting this to false will - * cause the error reporter to not report the error back to the server, - * which can be useful if the client knows that the error has already been - * logged on the server. - * @type {boolean} - */ - this.reportErrorToServer = true; -}; -goog.inherits(goog.debug.Error, Error); - - -/** @override */ -goog.debug.Error.prototype.name = 'CustomError'; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of goog.dom.NodeType. - */ - -goog.provide('goog.dom.NodeType'); - - -/** - * Constants for the nodeType attribute in the Node interface. - * - * These constants match those specified in the Node interface. These are - * usually present on the Node object in recent browsers, but not in older - * browsers (specifically, early IEs) and thus are given here. - * - * In some browsers (early IEs), these are not defined on the Node object, - * so they are provided here. - * - * See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247 - * @enum {number} - */ -goog.dom.NodeType = { - ELEMENT: 1, - ATTRIBUTE: 2, - TEXT: 3, - CDATA_SECTION: 4, - ENTITY_REFERENCE: 5, - ENTITY: 6, - PROCESSING_INSTRUCTION: 7, - COMMENT: 8, - DOCUMENT: 9, - DOCUMENT_TYPE: 10, - DOCUMENT_FRAGMENT: 11, - NOTATION: 12 -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for string manipulation. - * @author arv@google.com (Erik Arvidsson) - */ - - -/** - * Namespace for string utilities - */ -goog.provide('goog.string'); -goog.provide('goog.string.Unicode'); - - -/** - * @define {boolean} Enables HTML escaping of lowercase letter "e" which helps - * with detection of double-escaping as this letter is frequently used. - */ -goog.define('goog.string.DETECT_DOUBLE_ESCAPING', false); - - -/** - * @define {boolean} Whether to force non-dom html unescaping. - */ -goog.define('goog.string.FORCE_NON_DOM_HTML_UNESCAPING', false); - - -/** - * Common Unicode string characters. - * @enum {string} - */ -goog.string.Unicode = { - NBSP: '\xa0' -}; - - -/** - * Fast prefix-checker. - * @param {string} str The string to check. - * @param {string} prefix A string to look for at the start of {@code str}. - * @return {boolean} True if {@code str} begins with {@code prefix}. - */ -goog.string.startsWith = function(str, prefix) { - return str.lastIndexOf(prefix, 0) == 0; -}; - - -/** - * Fast suffix-checker. - * @param {string} str The string to check. - * @param {string} suffix A string to look for at the end of {@code str}. - * @return {boolean} True if {@code str} ends with {@code suffix}. - */ -goog.string.endsWith = function(str, suffix) { - var l = str.length - suffix.length; - return l >= 0 && str.indexOf(suffix, l) == l; -}; - - -/** - * Case-insensitive prefix-checker. - * @param {string} str The string to check. - * @param {string} prefix A string to look for at the end of {@code str}. - * @return {boolean} True if {@code str} begins with {@code prefix} (ignoring - * case). - */ -goog.string.caseInsensitiveStartsWith = function(str, prefix) { - return goog.string.caseInsensitiveCompare( - prefix, str.substr(0, prefix.length)) == 0; -}; - - -/** - * Case-insensitive suffix-checker. - * @param {string} str The string to check. - * @param {string} suffix A string to look for at the end of {@code str}. - * @return {boolean} True if {@code str} ends with {@code suffix} (ignoring - * case). - */ -goog.string.caseInsensitiveEndsWith = function(str, suffix) { - return goog.string.caseInsensitiveCompare( - suffix, str.substr(str.length - suffix.length, suffix.length)) == 0; -}; - - -/** - * Case-insensitive equality checker. - * @param {string} str1 First string to check. - * @param {string} str2 Second string to check. - * @return {boolean} True if {@code str1} and {@code str2} are the same string, - * ignoring case. - */ -goog.string.caseInsensitiveEquals = function(str1, str2) { - return str1.toLowerCase() == str2.toLowerCase(); -}; - - -/** - * Does simple python-style string substitution. - * subs("foo%s hot%s", "bar", "dog") becomes "foobar hotdog". - * @param {string} str The string containing the pattern. - * @param {...*} var_args The items to substitute into the pattern. - * @return {string} A copy of {@code str} in which each occurrence of - * {@code %s} has been replaced an argument from {@code var_args}. - */ -goog.string.subs = function(str, var_args) { - var splitParts = str.split('%s'); - var returnString = ''; - - var subsArguments = Array.prototype.slice.call(arguments, 1); - while (subsArguments.length && - // Replace up to the last split part. We are inserting in the - // positions between split parts. - splitParts.length > 1) { - returnString += splitParts.shift() + subsArguments.shift(); - } - - return returnString + splitParts.join('%s'); // Join unused '%s' -}; - - -/** - * Converts multiple whitespace chars (spaces, non-breaking-spaces, new lines - * and tabs) to a single space, and strips leading and trailing whitespace. - * @param {string} str Input string. - * @return {string} A copy of {@code str} with collapsed whitespace. - */ -goog.string.collapseWhitespace = function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return str.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, ''); -}; - - -/** - * Checks if a string is empty or contains only whitespaces. - * @param {string} str The string to check. - * @return {boolean} Whether {@code str} is empty or whitespace only. - */ -goog.string.isEmptyOrWhitespace = function(str) { - // testing length == 0 first is actually slower in all browsers (about the - // same in Opera). - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return /^[\s\xa0]*$/.test(str); -}; - - -/** - * Checks if a string is empty. - * @param {string} str The string to check. - * @return {boolean} Whether {@code str} is empty. - */ -goog.string.isEmptyString = function(str) { - return str.length == 0; -}; - - -/** - * Checks if a string is empty or contains only whitespaces. - * - * TODO(user): Deprecate this when clients have been switched over to - * goog.string.isEmptyOrWhitespace. - * - * @param {string} str The string to check. - * @return {boolean} Whether {@code str} is empty or whitespace only. - */ -goog.string.isEmpty = goog.string.isEmptyOrWhitespace; - - -/** - * Checks if a string is null, undefined, empty or contains only whitespaces. - * @param {*} str The string to check. - * @return {boolean} Whether {@code str} is null, undefined, empty, or - * whitespace only. - * @deprecated Use goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str)) - * instead. - */ -goog.string.isEmptyOrWhitespaceSafe = function(str) { - return goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str)); -}; - - -/** - * Checks if a string is null, undefined, empty or contains only whitespaces. - * - * TODO(user): Deprecate this when clients have been switched over to - * goog.string.isEmptyOrWhitespaceSafe. - * - * @param {*} str The string to check. - * @return {boolean} Whether {@code str} is null, undefined, empty, or - * whitespace only. - */ -goog.string.isEmptySafe = goog.string.isEmptyOrWhitespaceSafe; - - -/** - * Checks if a string is all breaking whitespace. - * @param {string} str The string to check. - * @return {boolean} Whether the string is all breaking whitespace. - */ -goog.string.isBreakingWhitespace = function(str) { - return !/[^\t\n\r ]/.test(str); -}; - - -/** - * Checks if a string contains all letters. - * @param {string} str string to check. - * @return {boolean} True if {@code str} consists entirely of letters. - */ -goog.string.isAlpha = function(str) { - return !/[^a-zA-Z]/.test(str); -}; - - -/** - * Checks if a string contains only numbers. - * @param {*} str string to check. If not a string, it will be - * casted to one. - * @return {boolean} True if {@code str} is numeric. - */ -goog.string.isNumeric = function(str) { - return !/[^0-9]/.test(str); -}; - - -/** - * Checks if a string contains only numbers or letters. - * @param {string} str string to check. - * @return {boolean} True if {@code str} is alphanumeric. - */ -goog.string.isAlphaNumeric = function(str) { - return !/[^a-zA-Z0-9]/.test(str); -}; - - -/** - * Checks if a character is a space character. - * @param {string} ch Character to check. - * @return {boolean} True if {@code ch} is a space. - */ -goog.string.isSpace = function(ch) { - return ch == ' '; -}; - - -/** - * Checks if a character is a valid unicode character. - * @param {string} ch Character to check. - * @return {boolean} True if {@code ch} is a valid unicode character. - */ -goog.string.isUnicodeChar = function(ch) { - return ch.length == 1 && ch >= ' ' && ch <= '~' || - ch >= '\u0080' && ch <= '\uFFFD'; -}; - - -/** - * Takes a string and replaces newlines with a space. Multiple lines are - * replaced with a single space. - * @param {string} str The string from which to strip newlines. - * @return {string} A copy of {@code str} stripped of newlines. - */ -goog.string.stripNewlines = function(str) { - return str.replace(/(\r\n|\r|\n)+/g, ' '); -}; - - -/** - * Replaces Windows and Mac new lines with unix style: \r or \r\n with \n. - * @param {string} str The string to in which to canonicalize newlines. - * @return {string} {@code str} A copy of {@code} with canonicalized newlines. - */ -goog.string.canonicalizeNewlines = function(str) { - return str.replace(/(\r\n|\r|\n)/g, '\n'); -}; - - -/** - * Normalizes whitespace in a string, replacing all whitespace chars with - * a space. - * @param {string} str The string in which to normalize whitespace. - * @return {string} A copy of {@code str} with all whitespace normalized. - */ -goog.string.normalizeWhitespace = function(str) { - return str.replace(/\xa0|\s/g, ' '); -}; - - -/** - * Normalizes spaces in a string, replacing all consecutive spaces and tabs - * with a single space. Replaces non-breaking space with a space. - * @param {string} str The string in which to normalize spaces. - * @return {string} A copy of {@code str} with all consecutive spaces and tabs - * replaced with a single space. - */ -goog.string.normalizeSpaces = function(str) { - return str.replace(/\xa0|[ \t]+/g, ' '); -}; - - -/** - * Removes the breaking spaces from the left and right of the string and - * collapses the sequences of breaking spaces in the middle into single spaces. - * The original and the result strings render the same way in HTML. - * @param {string} str A string in which to collapse spaces. - * @return {string} Copy of the string with normalized breaking spaces. - */ -goog.string.collapseBreakingSpaces = function(str) { - return str.replace(/[\t\r\n ]+/g, ' ').replace( - /^[\t\r\n ]+|[\t\r\n ]+$/g, ''); -}; - - -/** - * Trims white spaces to the left and right of a string. - * @param {string} str The string to trim. - * @return {string} A trimmed copy of {@code str}. - */ -goog.string.trim = (goog.TRUSTED_SITE && String.prototype.trim) ? - function(str) { - return str.trim(); - } : - function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s - // character class (as required by section 7.2 of the ECMAScript spec), - // we explicitly include it in the regexp to enforce consistent - // cross-browser behavior. - return str.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); - }; - - -/** - * Trims whitespaces at the left end of a string. - * @param {string} str The string to left trim. - * @return {string} A trimmed copy of {@code str}. - */ -goog.string.trimLeft = function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return str.replace(/^[\s\xa0]+/, ''); -}; - - -/** - * Trims whitespaces at the right end of a string. - * @param {string} str The string to right trim. - * @return {string} A trimmed copy of {@code str}. - */ -goog.string.trimRight = function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return str.replace(/[\s\xa0]+$/, ''); -}; - - -/** - * A string comparator that ignores case. - * -1 = str1 less than str2 - * 0 = str1 equals str2 - * 1 = str1 greater than str2 - * - * @param {string} str1 The string to compare. - * @param {string} str2 The string to compare {@code str1} to. - * @return {number} The comparator result, as described above. - */ -goog.string.caseInsensitiveCompare = function(str1, str2) { - var test1 = String(str1).toLowerCase(); - var test2 = String(str2).toLowerCase(); - - if (test1 < test2) { - return -1; - } else if (test1 == test2) { - return 0; - } else { - return 1; - } -}; - - -/** - * Regular expression used for splitting a string into substrings of fractional - * numbers, integers, and non-numeric characters. - * @type {RegExp} - * @private - */ -goog.string.numerateCompareRegExp_ = /(\.\d+)|(\d+)|(\D+)/g; - - -/** - * String comparison function that handles numbers in a way humans might expect. - * Using this function, the string "File 2.jpg" sorts before "File 10.jpg". The - * comparison is mostly case-insensitive, though strings that are identical - * except for case are sorted with the upper-case strings before lower-case. - * - * This comparison function is significantly slower (about 500x) than either - * the default or the case-insensitive compare. It should not be used in - * time-critical code, but should be fast enough to sort several hundred short - * strings (like filenames) with a reasonable delay. - * - * @param {string} str1 The string to compare in a numerically sensitive way. - * @param {string} str2 The string to compare {@code str1} to. - * @return {number} less than 0 if str1 < str2, 0 if str1 == str2, greater than - * 0 if str1 > str2. - */ -goog.string.numerateCompare = function(str1, str2) { - if (str1 == str2) { - return 0; - } - if (!str1) { - return -1; - } - if (!str2) { - return 1; - } - - // Using match to split the entire string ahead of time turns out to be faster - // for most inputs than using RegExp.exec or iterating over each character. - var tokens1 = str1.toLowerCase().match(goog.string.numerateCompareRegExp_); - var tokens2 = str2.toLowerCase().match(goog.string.numerateCompareRegExp_); - - var count = Math.min(tokens1.length, tokens2.length); - - for (var i = 0; i < count; i++) { - var a = tokens1[i]; - var b = tokens2[i]; - - // Compare pairs of tokens, returning if one token sorts before the other. - if (a != b) { - - // Only if both tokens are integers is a special comparison required. - // Decimal numbers are sorted as strings (e.g., '.09' < '.1'). - var num1 = parseInt(a, 10); - if (!isNaN(num1)) { - var num2 = parseInt(b, 10); - if (!isNaN(num2) && num1 - num2) { - return num1 - num2; - } - } - return a < b ? -1 : 1; - } - } - - // If one string is a substring of the other, the shorter string sorts first. - if (tokens1.length != tokens2.length) { - return tokens1.length - tokens2.length; - } - - // The two strings must be equivalent except for case (perfect equality is - // tested at the head of the function.) Revert to default ASCII-betical string - // comparison to stablize the sort. - return str1 < str2 ? -1 : 1; -}; - - -/** - * URL-encodes a string - * @param {*} str The string to url-encode. - * @return {string} An encoded copy of {@code str} that is safe for urls. - * Note that '#', ':', and other characters used to delimit portions - * of URLs *will* be encoded. - */ -goog.string.urlEncode = function(str) { - return encodeURIComponent(String(str)); -}; - - -/** - * URL-decodes the string. We need to specially handle '+'s because - * the javascript library doesn't convert them to spaces. - * @param {string} str The string to url decode. - * @return {string} The decoded {@code str}. - */ -goog.string.urlDecode = function(str) { - return decodeURIComponent(str.replace(/\+/g, ' ')); -}; - - -/** - * Converts \n to <br>s or <br />s. - * @param {string} str The string in which to convert newlines. - * @param {boolean=} opt_xml Whether to use XML compatible tags. - * @return {string} A copy of {@code str} with converted newlines. - */ -goog.string.newLineToBr = function(str, opt_xml) { - return str.replace(/(\r\n|\r|\n)/g, opt_xml ? '<br />' : '<br>'); -}; - - -/** - * Escapes double quote '"' and single quote '\'' characters in addition to - * '&', '<', and '>' so that a string can be included in an HTML tag attribute - * value within double or single quotes. - * - * It should be noted that > doesn't need to be escaped for the HTML or XML to - * be valid, but it has been decided to escape it for consistency with other - * implementations. - * - * With goog.string.DETECT_DOUBLE_ESCAPING, this function escapes also the - * lowercase letter "e". - * - * NOTE(user): - * HtmlEscape is often called during the generation of large blocks of HTML. - * Using statics for the regular expressions and strings is an optimization - * that can more than half the amount of time IE spends in this function for - * large apps, since strings and regexes both contribute to GC allocations. - * - * Testing for the presence of a character before escaping increases the number - * of function calls, but actually provides a speed increase for the average - * case -- since the average case often doesn't require the escaping of all 4 - * characters and indexOf() is much cheaper than replace(). - * The worst case does suffer slightly from the additional calls, therefore the - * opt_isLikelyToContainHtmlChars option has been included for situations - * where all 4 HTML entities are very likely to be present and need escaping. - * - * Some benchmarks (times tended to fluctuate +-0.05ms): - * FireFox IE6 - * (no chars / average (mix of cases) / all 4 chars) - * no checks 0.13 / 0.22 / 0.22 0.23 / 0.53 / 0.80 - * indexOf 0.08 / 0.17 / 0.26 0.22 / 0.54 / 0.84 - * indexOf + re test 0.07 / 0.17 / 0.28 0.19 / 0.50 / 0.85 - * - * An additional advantage of checking if replace actually needs to be called - * is a reduction in the number of object allocations, so as the size of the - * application grows the difference between the various methods would increase. - * - * @param {string} str string to be escaped. - * @param {boolean=} opt_isLikelyToContainHtmlChars Don't perform a check to see - * if the character needs replacing - use this option if you expect each of - * the characters to appear often. Leave false if you expect few html - * characters to occur in your strings, such as if you are escaping HTML. - * @return {string} An escaped copy of {@code str}. - */ -goog.string.htmlEscape = function(str, opt_isLikelyToContainHtmlChars) { - - if (opt_isLikelyToContainHtmlChars) { - str = str.replace(goog.string.AMP_RE_, '&') - .replace(goog.string.LT_RE_, '<') - .replace(goog.string.GT_RE_, '>') - .replace(goog.string.QUOT_RE_, '"') - .replace(goog.string.SINGLE_QUOTE_RE_, ''') - .replace(goog.string.NULL_RE_, '�'); - if (goog.string.DETECT_DOUBLE_ESCAPING) { - str = str.replace(goog.string.E_RE_, 'e'); - } - return str; - - } else { - // quick test helps in the case when there are no chars to replace, in - // worst case this makes barely a difference to the time taken - if (!goog.string.ALL_RE_.test(str)) return str; - - // str.indexOf is faster than regex.test in this case - if (str.indexOf('&') != -1) { - str = str.replace(goog.string.AMP_RE_, '&'); - } - if (str.indexOf('<') != -1) { - str = str.replace(goog.string.LT_RE_, '<'); - } - if (str.indexOf('>') != -1) { - str = str.replace(goog.string.GT_RE_, '>'); - } - if (str.indexOf('"') != -1) { - str = str.replace(goog.string.QUOT_RE_, '"'); - } - if (str.indexOf('\'') != -1) { - str = str.replace(goog.string.SINGLE_QUOTE_RE_, '''); - } - if (str.indexOf('\x00') != -1) { - str = str.replace(goog.string.NULL_RE_, '�'); - } - if (goog.string.DETECT_DOUBLE_ESCAPING && str.indexOf('e') != -1) { - str = str.replace(goog.string.E_RE_, 'e'); - } - return str; - } -}; - - -/** - * Regular expression that matches an ampersand, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.AMP_RE_ = /&/g; - - -/** - * Regular expression that matches a less than sign, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.LT_RE_ = /</g; - - -/** - * Regular expression that matches a greater than sign, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.GT_RE_ = />/g; - - -/** - * Regular expression that matches a double quote, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.QUOT_RE_ = /"/g; - - -/** - * Regular expression that matches a single quote, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.SINGLE_QUOTE_RE_ = /'/g; - - -/** - * Regular expression that matches null character, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.NULL_RE_ = /\x00/g; - - -/** - * Regular expression that matches a lowercase letter "e", for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.E_RE_ = /e/g; - - -/** - * Regular expression that matches any character that needs to be escaped. - * @const {!RegExp} - * @private - */ -goog.string.ALL_RE_ = (goog.string.DETECT_DOUBLE_ESCAPING ? - /[\x00&<>"'e]/ : - /[\x00&<>"']/); - - -/** - * Unescapes an HTML string. - * - * @param {string} str The string to unescape. - * @return {string} An unescaped copy of {@code str}. - */ -goog.string.unescapeEntities = function(str) { - if (goog.string.contains(str, '&')) { - // We are careful not to use a DOM if we do not have one or we explicitly - // requested non-DOM html unescaping. - if (!goog.string.FORCE_NON_DOM_HTML_UNESCAPING && - 'document' in goog.global) { - return goog.string.unescapeEntitiesUsingDom_(str); - } else { - // Fall back on pure XML entities - return goog.string.unescapePureXmlEntities_(str); - } - } - return str; -}; - - -/** - * Unescapes a HTML string using the provided document. - * - * @param {string} str The string to unescape. - * @param {!Document} document A document to use in escaping the string. - * @return {string} An unescaped copy of {@code str}. - */ -goog.string.unescapeEntitiesWithDocument = function(str, document) { - if (goog.string.contains(str, '&')) { - return goog.string.unescapeEntitiesUsingDom_(str, document); - } - return str; -}; - - -/** - * Unescapes an HTML string using a DOM to resolve non-XML, non-numeric - * entities. This function is XSS-safe and whitespace-preserving. - * @private - * @param {string} str The string to unescape. - * @param {Document=} opt_document An optional document to use for creating - * elements. If this is not specified then the default window.document - * will be used. - * @return {string} The unescaped {@code str} string. - */ -goog.string.unescapeEntitiesUsingDom_ = function(str, opt_document) { - /** @type {!Object<string, string>} */ - var seen = {'&': '&', '<': '<', '>': '>', '"': '"'}; - var div; - if (opt_document) { - div = opt_document.createElement('div'); - } else { - div = goog.global.document.createElement('div'); - } - // Match as many valid entity characters as possible. If the actual entity - // happens to be shorter, it will still work as innerHTML will return the - // trailing characters unchanged. Since the entity characters do not include - // open angle bracket, there is no chance of XSS from the innerHTML use. - // Since no whitespace is passed to innerHTML, whitespace is preserved. - return str.replace(goog.string.HTML_ENTITY_PATTERN_, function(s, entity) { - // Check for cached entity. - var value = seen[s]; - if (value) { - return value; - } - // Check for numeric entity. - if (entity.charAt(0) == '#') { - // Prefix with 0 so that hex entities (e.g. ) parse as hex numbers. - var n = Number('0' + entity.substr(1)); - if (!isNaN(n)) { - value = String.fromCharCode(n); - } - } - // Fall back to innerHTML otherwise. - if (!value) { - // Append a non-entity character to avoid a bug in Webkit that parses - // an invalid entity at the end of innerHTML text as the empty string. - div.innerHTML = s + ' '; - // Then remove the trailing character from the result. - value = div.firstChild.nodeValue.slice(0, -1); - } - // Cache and return. - return seen[s] = value; - }); -}; - - -/** - * Unescapes XML entities. - * @private - * @param {string} str The string to unescape. - * @return {string} An unescaped copy of {@code str}. - */ -goog.string.unescapePureXmlEntities_ = function(str) { - return str.replace(/&([^;]+);/g, function(s, entity) { - switch (entity) { - case 'amp': - return '&'; - case 'lt': - return '<'; - case 'gt': - return '>'; - case 'quot': - return '"'; - default: - if (entity.charAt(0) == '#') { - // Prefix with 0 so that hex entities (e.g. ) parse as hex. - var n = Number('0' + entity.substr(1)); - if (!isNaN(n)) { - return String.fromCharCode(n); - } - } - // For invalid entities we just return the entity - return s; - } - }); -}; - - -/** - * Regular expression that matches an HTML entity. - * See also HTML5: Tokenization / Tokenizing character references. - * @private - * @type {!RegExp} - */ -goog.string.HTML_ENTITY_PATTERN_ = /&([^;\s<&]+);?/g; - - -/** - * Do escaping of whitespace to preserve spatial formatting. We use character - * entity #160 to make it safer for xml. - * @param {string} str The string in which to escape whitespace. - * @param {boolean=} opt_xml Whether to use XML compatible tags. - * @return {string} An escaped copy of {@code str}. - */ -goog.string.whitespaceEscape = function(str, opt_xml) { - // This doesn't use goog.string.preserveSpaces for backwards compatibility. - return goog.string.newLineToBr(str.replace(/ /g, '  '), opt_xml); -}; - - -/** - * Preserve spaces that would be otherwise collapsed in HTML by replacing them - * with non-breaking space Unicode characters. - * @param {string} str The string in which to preserve whitespace. - * @return {string} A copy of {@code str} with preserved whitespace. - */ -goog.string.preserveSpaces = function(str) { - return str.replace(/(^|[\n ]) /g, '$1' + goog.string.Unicode.NBSP); -}; - - -/** - * Strip quote characters around a string. The second argument is a string of - * characters to treat as quotes. This can be a single character or a string of - * multiple character and in that case each of those are treated as possible - * quote characters. For example: - * - * <pre> - * goog.string.stripQuotes('"abc"', '"`') --> 'abc' - * goog.string.stripQuotes('`abc`', '"`') --> 'abc' - * </pre> - * - * @param {string} str The string to strip. - * @param {string} quoteChars The quote characters to strip. - * @return {string} A copy of {@code str} without the quotes. - */ -goog.string.stripQuotes = function(str, quoteChars) { - var length = quoteChars.length; - for (var i = 0; i < length; i++) { - var quoteChar = length == 1 ? quoteChars : quoteChars.charAt(i); - if (str.charAt(0) == quoteChar && str.charAt(str.length - 1) == quoteChar) { - return str.substring(1, str.length - 1); - } - } - return str; -}; - - -/** - * Truncates a string to a certain length and adds '...' if necessary. The - * length also accounts for the ellipsis, so a maximum length of 10 and a string - * 'Hello World!' produces 'Hello W...'. - * @param {string} str The string to truncate. - * @param {number} chars Max number of characters. - * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped - * characters from being cut off in the middle. - * @return {string} The truncated {@code str} string. - */ -goog.string.truncate = function(str, chars, opt_protectEscapedCharacters) { - if (opt_protectEscapedCharacters) { - str = goog.string.unescapeEntities(str); - } - - if (str.length > chars) { - str = str.substring(0, chars - 3) + '...'; - } - - if (opt_protectEscapedCharacters) { - str = goog.string.htmlEscape(str); - } - - return str; -}; - - -/** - * Truncate a string in the middle, adding "..." if necessary, - * and favoring the beginning of the string. - * @param {string} str The string to truncate the middle of. - * @param {number} chars Max number of characters. - * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped - * characters from being cutoff in the middle. - * @param {number=} opt_trailingChars Optional number of trailing characters to - * leave at the end of the string, instead of truncating as close to the - * middle as possible. - * @return {string} A truncated copy of {@code str}. - */ -goog.string.truncateMiddle = function(str, chars, - opt_protectEscapedCharacters, opt_trailingChars) { - if (opt_protectEscapedCharacters) { - str = goog.string.unescapeEntities(str); - } - - if (opt_trailingChars && str.length > chars) { - if (opt_trailingChars > chars) { - opt_trailingChars = chars; - } - var endPoint = str.length - opt_trailingChars; - var startPoint = chars - opt_trailingChars; - str = str.substring(0, startPoint) + '...' + str.substring(endPoint); - } else if (str.length > chars) { - // Favor the beginning of the string: - var half = Math.floor(chars / 2); - var endPos = str.length - half; - half += chars % 2; - str = str.substring(0, half) + '...' + str.substring(endPos); - } - - if (opt_protectEscapedCharacters) { - str = goog.string.htmlEscape(str); - } - - return str; -}; - - -/** - * Special chars that need to be escaped for goog.string.quote. - * @private {!Object<string, string>} - */ -goog.string.specialEscapeChars_ = { - '\0': '\\0', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', - '\x0B': '\\x0B', // '\v' is not supported in JScript - '"': '\\"', - '\\': '\\\\' -}; - - -/** - * Character mappings used internally for goog.string.escapeChar. - * @private {!Object<string, string>} - */ -goog.string.jsEscapeCache_ = { - '\'': '\\\'' -}; - - -/** - * Encloses a string in double quotes and escapes characters so that the - * string is a valid JS string. - * @param {string} s The string to quote. - * @return {string} A copy of {@code s} surrounded by double quotes. - */ -goog.string.quote = function(s) { - s = String(s); - if (s.quote) { - return s.quote(); - } else { - var sb = ['"']; - for (var i = 0; i < s.length; i++) { - var ch = s.charAt(i); - var cc = ch.charCodeAt(0); - sb[i + 1] = goog.string.specialEscapeChars_[ch] || - ((cc > 31 && cc < 127) ? ch : goog.string.escapeChar(ch)); - } - sb.push('"'); - return sb.join(''); - } -}; - - -/** - * Takes a string and returns the escaped string for that character. - * @param {string} str The string to escape. - * @return {string} An escaped string representing {@code str}. - */ -goog.string.escapeString = function(str) { - var sb = []; - for (var i = 0; i < str.length; i++) { - sb[i] = goog.string.escapeChar(str.charAt(i)); - } - return sb.join(''); -}; - - -/** - * Takes a character and returns the escaped string for that character. For - * example escapeChar(String.fromCharCode(15)) -> "\\x0E". - * @param {string} c The character to escape. - * @return {string} An escaped string representing {@code c}. - */ -goog.string.escapeChar = function(c) { - if (c in goog.string.jsEscapeCache_) { - return goog.string.jsEscapeCache_[c]; - } - - if (c in goog.string.specialEscapeChars_) { - return goog.string.jsEscapeCache_[c] = goog.string.specialEscapeChars_[c]; - } - - var rv = c; - var cc = c.charCodeAt(0); - if (cc > 31 && cc < 127) { - rv = c; - } else { - // tab is 9 but handled above - if (cc < 256) { - rv = '\\x'; - if (cc < 16 || cc > 256) { - rv += '0'; - } - } else { - rv = '\\u'; - if (cc < 4096) { // \u1000 - rv += '0'; - } - } - rv += cc.toString(16).toUpperCase(); - } - - return goog.string.jsEscapeCache_[c] = rv; -}; - - -/** - * Determines whether a string contains a substring. - * @param {string} str The string to search. - * @param {string} subString The substring to search for. - * @return {boolean} Whether {@code str} contains {@code subString}. - */ -goog.string.contains = function(str, subString) { - return str.indexOf(subString) != -1; -}; - - -/** - * Determines whether a string contains a substring, ignoring case. - * @param {string} str The string to search. - * @param {string} subString The substring to search for. - * @return {boolean} Whether {@code str} contains {@code subString}. - */ -goog.string.caseInsensitiveContains = function(str, subString) { - return goog.string.contains(str.toLowerCase(), subString.toLowerCase()); -}; - - -/** - * Returns the non-overlapping occurrences of ss in s. - * If either s or ss evalutes to false, then returns zero. - * @param {string} s The string to look in. - * @param {string} ss The string to look for. - * @return {number} Number of occurrences of ss in s. - */ -goog.string.countOf = function(s, ss) { - return s && ss ? s.split(ss).length - 1 : 0; -}; - - -/** - * Removes a substring of a specified length at a specific - * index in a string. - * @param {string} s The base string from which to remove. - * @param {number} index The index at which to remove the substring. - * @param {number} stringLength The length of the substring to remove. - * @return {string} A copy of {@code s} with the substring removed or the full - * string if nothing is removed or the input is invalid. - */ -goog.string.removeAt = function(s, index, stringLength) { - var resultStr = s; - // If the index is greater or equal to 0 then remove substring - if (index >= 0 && index < s.length && stringLength > 0) { - resultStr = s.substr(0, index) + - s.substr(index + stringLength, s.length - index - stringLength); - } - return resultStr; -}; - - -/** - * Removes the first occurrence of a substring from a string. - * @param {string} s The base string from which to remove. - * @param {string} ss The string to remove. - * @return {string} A copy of {@code s} with {@code ss} removed or the full - * string if nothing is removed. - */ -goog.string.remove = function(s, ss) { - var re = new RegExp(goog.string.regExpEscape(ss), ''); - return s.replace(re, ''); -}; - - -/** - * Removes all occurrences of a substring from a string. - * @param {string} s The base string from which to remove. - * @param {string} ss The string to remove. - * @return {string} A copy of {@code s} with {@code ss} removed or the full - * string if nothing is removed. - */ -goog.string.removeAll = function(s, ss) { - var re = new RegExp(goog.string.regExpEscape(ss), 'g'); - return s.replace(re, ''); -}; - - -/** - * Escapes characters in the string that are not safe to use in a RegExp. - * @param {*} s The string to escape. If not a string, it will be casted - * to one. - * @return {string} A RegExp safe, escaped copy of {@code s}. - */ -goog.string.regExpEscape = function(s) { - return String(s).replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1'). - replace(/\x08/g, '\\x08'); -}; - - -/** - * Repeats a string n times. - * @param {string} string The string to repeat. - * @param {number} length The number of times to repeat. - * @return {string} A string containing {@code length} repetitions of - * {@code string}. - */ -goog.string.repeat = (String.prototype.repeat) ? - function(string, length) { - // The native method is over 100 times faster than the alternative. - return string.repeat(length); - } : - function(string, length) { - return new Array(length + 1).join(string); - }; - - -/** - * Pads number to given length and optionally rounds it to a given precision. - * For example: - * <pre>padNumber(1.25, 2, 3) -> '01.250' - * padNumber(1.25, 2) -> '01.25' - * padNumber(1.25, 2, 1) -> '01.3' - * padNumber(1.25, 0) -> '1.25'</pre> - * - * @param {number} num The number to pad. - * @param {number} length The desired length. - * @param {number=} opt_precision The desired precision. - * @return {string} {@code num} as a string with the given options. - */ -goog.string.padNumber = function(num, length, opt_precision) { - var s = goog.isDef(opt_precision) ? num.toFixed(opt_precision) : String(num); - var index = s.indexOf('.'); - if (index == -1) { - index = s.length; - } - return goog.string.repeat('0', Math.max(0, length - index)) + s; -}; - - -/** - * Returns a string representation of the given object, with - * null and undefined being returned as the empty string. - * - * @param {*} obj The object to convert. - * @return {string} A string representation of the {@code obj}. - */ -goog.string.makeSafe = function(obj) { - return obj == null ? '' : String(obj); -}; - - -/** - * Concatenates string expressions. This is useful - * since some browsers are very inefficient when it comes to using plus to - * concat strings. Be careful when using null and undefined here since - * these will not be included in the result. If you need to represent these - * be sure to cast the argument to a String first. - * For example: - * <pre>buildString('a', 'b', 'c', 'd') -> 'abcd' - * buildString(null, undefined) -> '' - * </pre> - * @param {...*} var_args A list of strings to concatenate. If not a string, - * it will be casted to one. - * @return {string} The concatenation of {@code var_args}. - */ -goog.string.buildString = function(var_args) { - return Array.prototype.join.call(arguments, ''); -}; - - -/** - * Returns a string with at least 64-bits of randomness. - * - * Doesn't trust Javascript's random function entirely. Uses a combination of - * random and current timestamp, and then encodes the string in base-36 to - * make it shorter. - * - * @return {string} A random string, e.g. sn1s7vb4gcic. - */ -goog.string.getRandomString = function() { - var x = 2147483648; - return Math.floor(Math.random() * x).toString(36) + - Math.abs(Math.floor(Math.random() * x) ^ goog.now()).toString(36); -}; - - -/** - * Compares two version numbers. - * - * @param {string|number} version1 Version of first item. - * @param {string|number} version2 Version of second item. - * - * @return {number} 1 if {@code version1} is higher. - * 0 if arguments are equal. - * -1 if {@code version2} is higher. - */ -goog.string.compareVersions = function(version1, version2) { - var order = 0; - // Trim leading and trailing whitespace and split the versions into - // subversions. - var v1Subs = goog.string.trim(String(version1)).split('.'); - var v2Subs = goog.string.trim(String(version2)).split('.'); - var subCount = Math.max(v1Subs.length, v2Subs.length); - - // Iterate over the subversions, as long as they appear to be equivalent. - for (var subIdx = 0; order == 0 && subIdx < subCount; subIdx++) { - var v1Sub = v1Subs[subIdx] || ''; - var v2Sub = v2Subs[subIdx] || ''; - - // Split the subversions into pairs of numbers and qualifiers (like 'b'). - // Two different RegExp objects are needed because they are both using - // the 'g' flag. - var v1CompParser = new RegExp('(\\d*)(\\D*)', 'g'); - var v2CompParser = new RegExp('(\\d*)(\\D*)', 'g'); - do { - var v1Comp = v1CompParser.exec(v1Sub) || ['', '', '']; - var v2Comp = v2CompParser.exec(v2Sub) || ['', '', '']; - // Break if there are no more matches. - if (v1Comp[0].length == 0 && v2Comp[0].length == 0) { - break; - } - - // Parse the numeric part of the subversion. A missing number is - // equivalent to 0. - var v1CompNum = v1Comp[1].length == 0 ? 0 : parseInt(v1Comp[1], 10); - var v2CompNum = v2Comp[1].length == 0 ? 0 : parseInt(v2Comp[1], 10); - - // Compare the subversion components. The number has the highest - // precedence. Next, if the numbers are equal, a subversion without any - // qualifier is always higher than a subversion with any qualifier. Next, - // the qualifiers are compared as strings. - order = goog.string.compareElements_(v1CompNum, v2CompNum) || - goog.string.compareElements_(v1Comp[2].length == 0, - v2Comp[2].length == 0) || - goog.string.compareElements_(v1Comp[2], v2Comp[2]); - // Stop as soon as an inequality is discovered. - } while (order == 0); - } - - return order; -}; - - -/** - * Compares elements of a version number. - * - * @param {string|number|boolean} left An element from a version number. - * @param {string|number|boolean} right An element from a version number. - * - * @return {number} 1 if {@code left} is higher. - * 0 if arguments are equal. - * -1 if {@code right} is higher. - * @private - */ -goog.string.compareElements_ = function(left, right) { - if (left < right) { - return -1; - } else if (left > right) { - return 1; - } - return 0; -}; - - -/** - * String hash function similar to java.lang.String.hashCode(). - * The hash code for a string is computed as - * s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1], - * where s[i] is the ith character of the string and n is the length of - * the string. We mod the result to make it between 0 (inclusive) and 2^32 - * (exclusive). - * @param {string} str A string. - * @return {number} Hash value for {@code str}, between 0 (inclusive) and 2^32 - * (exclusive). The empty string returns 0. - */ -goog.string.hashCode = function(str) { - var result = 0; - for (var i = 0; i < str.length; ++i) { - // Normalize to 4 byte range, 0 ... 2^32. - result = (31 * result + str.charCodeAt(i)) >>> 0; - } - return result; -}; - - -/** - * The most recent unique ID. |0 is equivalent to Math.floor in this case. - * @type {number} - * @private - */ -goog.string.uniqueStringCounter_ = Math.random() * 0x80000000 | 0; - - -/** - * Generates and returns a string which is unique in the current document. - * This is useful, for example, to create unique IDs for DOM elements. - * @return {string} A unique id. - */ -goog.string.createUniqueString = function() { - return 'goog_' + goog.string.uniqueStringCounter_++; -}; - - -/** - * Converts the supplied string to a number, which may be Infinity or NaN. - * This function strips whitespace: (toNumber(' 123') === 123) - * This function accepts scientific notation: (toNumber('1e1') === 10) - * - * This is better than Javascript's built-in conversions because, sadly: - * (Number(' ') === 0) and (parseFloat('123a') === 123) - * - * @param {string} str The string to convert. - * @return {number} The number the supplied string represents, or NaN. - */ -goog.string.toNumber = function(str) { - var num = Number(str); - if (num == 0 && goog.string.isEmptyOrWhitespace(str)) { - return NaN; - } - return num; -}; - - -/** - * Returns whether the given string is lower camel case (e.g. "isFooBar"). - * - * Note that this assumes the string is entirely letters. - * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms - * - * @param {string} str String to test. - * @return {boolean} Whether the string is lower camel case. - */ -goog.string.isLowerCamelCase = function(str) { - return /^[a-z]+([A-Z][a-z]*)*$/.test(str); -}; - - -/** - * Returns whether the given string is upper camel case (e.g. "FooBarBaz"). - * - * Note that this assumes the string is entirely letters. - * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms - * - * @param {string} str String to test. - * @return {boolean} Whether the string is upper camel case. - */ -goog.string.isUpperCamelCase = function(str) { - return /^([A-Z][a-z]*)+$/.test(str); -}; - - -/** - * Converts a string from selector-case to camelCase (e.g. from - * "multi-part-string" to "multiPartString"), useful for converting - * CSS selectors and HTML dataset keys to their equivalent JS properties. - * @param {string} str The string in selector-case form. - * @return {string} The string in camelCase form. - */ -goog.string.toCamelCase = function(str) { - return String(str).replace(/\-([a-z])/g, function(all, match) { - return match.toUpperCase(); - }); -}; - - -/** - * Converts a string from camelCase to selector-case (e.g. from - * "multiPartString" to "multi-part-string"), useful for converting JS - * style and dataset properties to equivalent CSS selectors and HTML keys. - * @param {string} str The string in camelCase form. - * @return {string} The string in selector-case form. - */ -goog.string.toSelectorCase = function(str) { - return String(str).replace(/([A-Z])/g, '-$1').toLowerCase(); -}; - - -/** - * Converts a string into TitleCase. First character of the string is always - * capitalized in addition to the first letter of every subsequent word. - * Words are delimited by one or more whitespaces by default. Custom delimiters - * can optionally be specified to replace the default, which doesn't preserve - * whitespace delimiters and instead must be explicitly included if needed. - * - * Default delimiter => " ": - * goog.string.toTitleCase('oneTwoThree') => 'OneTwoThree' - * goog.string.toTitleCase('one two three') => 'One Two Three' - * goog.string.toTitleCase(' one two ') => ' One Two ' - * goog.string.toTitleCase('one_two_three') => 'One_two_three' - * goog.string.toTitleCase('one-two-three') => 'One-two-three' - * - * Custom delimiter => "_-.": - * goog.string.toTitleCase('oneTwoThree', '_-.') => 'OneTwoThree' - * goog.string.toTitleCase('one two three', '_-.') => 'One two three' - * goog.string.toTitleCase(' one two ', '_-.') => ' one two ' - * goog.string.toTitleCase('one_two_three', '_-.') => 'One_Two_Three' - * goog.string.toTitleCase('one-two-three', '_-.') => 'One-Two-Three' - * goog.string.toTitleCase('one...two...three', '_-.') => 'One...Two...Three' - * goog.string.toTitleCase('one. two. three', '_-.') => 'One. two. three' - * goog.string.toTitleCase('one-two.three', '_-.') => 'One-Two.Three' - * - * @param {string} str String value in camelCase form. - * @param {string=} opt_delimiters Custom delimiter character set used to - * distinguish words in the string value. Each character represents a - * single delimiter. When provided, default whitespace delimiter is - * overridden and must be explicitly included if needed. - * @return {string} String value in TitleCase form. - */ -goog.string.toTitleCase = function(str, opt_delimiters) { - var delimiters = goog.isString(opt_delimiters) ? - goog.string.regExpEscape(opt_delimiters) : '\\s'; - - // For IE8, we need to prevent using an empty character set. Otherwise, - // incorrect matching will occur. - delimiters = delimiters ? '|[' + delimiters + ']+' : ''; - - var regexp = new RegExp('(^' + delimiters + ')([a-z])', 'g'); - return str.replace(regexp, function(all, p1, p2) { - return p1 + p2.toUpperCase(); - }); -}; - - -/** - * Capitalizes a string, i.e. converts the first letter to uppercase - * and all other letters to lowercase, e.g.: - * - * goog.string.capitalize('one') => 'One' - * goog.string.capitalize('ONE') => 'One' - * goog.string.capitalize('one two') => 'One two' - * - * Note that this function does not trim initial whitespace. - * - * @param {string} str String value to capitalize. - * @return {string} String value with first letter in uppercase. - */ -goog.string.capitalize = function(str) { - return String(str.charAt(0)).toUpperCase() + - String(str.substr(1)).toLowerCase(); -}; - - -/** - * Parse a string in decimal or hexidecimal ('0xFFFF') form. - * - * To parse a particular radix, please use parseInt(string, radix) directly. See - * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt - * - * This is a wrapper for the built-in parseInt function that will only parse - * numbers as base 10 or base 16. Some JS implementations assume strings - * starting with "0" are intended to be octal. ES3 allowed but discouraged - * this behavior. ES5 forbids it. This function emulates the ES5 behavior. - * - * For more information, see Mozilla JS Reference: http://goo.gl/8RiFj - * - * @param {string|number|null|undefined} value The value to be parsed. - * @return {number} The number, parsed. If the string failed to parse, this - * will be NaN. - */ -goog.string.parseInt = function(value) { - // Force finite numbers to strings. - if (isFinite(value)) { - value = String(value); - } - - if (goog.isString(value)) { - // If the string starts with '0x' or '-0x', parse as hex. - return /^\s*-?0x/i.test(value) ? - parseInt(value, 16) : parseInt(value, 10); - } - - return NaN; -}; - - -/** - * Splits a string on a separator a limited number of times. - * - * This implementation is more similar to Python or Java, where the limit - * parameter specifies the maximum number of splits rather than truncating - * the number of results. - * - * See http://docs.python.org/2/library/stdtypes.html#str.split - * See JavaDoc: http://goo.gl/F2AsY - * See Mozilla reference: http://goo.gl/dZdZs - * - * @param {string} str String to split. - * @param {string} separator The separator. - * @param {number} limit The limit to the number of splits. The resulting array - * will have a maximum length of limit+1. Negative numbers are the same - * as zero. - * @return {!Array<string>} The string, split. - */ - -goog.string.splitLimit = function(str, separator, limit) { - var parts = str.split(separator); - var returnVal = []; - - // Only continue doing this while we haven't hit the limit and we have - // parts left. - while (limit > 0 && parts.length) { - returnVal.push(parts.shift()); - limit--; - } - - // If there are remaining parts, append them to the end. - if (parts.length) { - returnVal.push(parts.join(separator)); - } - - return returnVal; -}; - - -/** - * Computes the Levenshtein edit distance between two strings. - * @param {string} a - * @param {string} b - * @return {number} The edit distance between the two strings. - */ -goog.string.editDistance = function(a, b) { - var v0 = []; - var v1 = []; - - if (a == b) { - return 0; - } - - if (!a.length || !b.length) { - return Math.max(a.length, b.length); - } - - for (var i = 0; i < b.length + 1; i++) { - v0[i] = i; - } - - for (var i = 0; i < a.length; i++) { - v1[0] = i + 1; - - for (var j = 0; j < b.length; j++) { - var cost = a[i] != b[j]; - // Cost for the substring is the minimum of adding one character, removing - // one character, or a swap. - v1[j + 1] = Math.min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost); - } - - for (var j = 0; j < v0.length; j++) { - v0[j] = v1[j]; - } - } - - return v1[b.length]; -}; - -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities to check the preconditions, postconditions and - * invariants runtime. - * - * Methods in this package should be given special treatment by the compiler - * for type-inference. For example, <code>goog.asserts.assert(foo)</code> - * will restrict <code>foo</code> to a truthy value. - * - * The compiler has an option to disable asserts. So code like: - * <code> - * var x = goog.asserts.assert(foo()); goog.asserts.assert(bar()); - * </code> - * will be transformed into: - * <code> - * var x = foo(); - * </code> - * The compiler will leave in foo() (because its return value is used), - * but it will remove bar() because it assumes it does not have side-effects. - * - * @author agrieve@google.com (Andrew Grieve) - */ - -goog.provide('goog.asserts'); -goog.provide('goog.asserts.AssertionError'); - -goog.require('goog.debug.Error'); -goog.require('goog.dom.NodeType'); -goog.require('goog.string'); - - -/** - * @define {boolean} Whether to strip out asserts or to leave them in. - */ -goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG); - - - -/** - * Error object for failed assertions. - * @param {string} messagePattern The pattern that was used to form message. - * @param {!Array<*>} messageArgs The items to substitute into the pattern. - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.asserts.AssertionError = function(messagePattern, messageArgs) { - messageArgs.unshift(messagePattern); - goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs)); - // Remove the messagePattern afterwards to avoid permanently modifying the - // passed in array. - messageArgs.shift(); - - /** - * The message pattern used to format the error message. Error handlers can - * use this to uniquely identify the assertion. - * @type {string} - */ - this.messagePattern = messagePattern; -}; -goog.inherits(goog.asserts.AssertionError, goog.debug.Error); - - -/** @override */ -goog.asserts.AssertionError.prototype.name = 'AssertionError'; - - -/** - * The default error handler. - * @param {!goog.asserts.AssertionError} e The exception to be handled. - */ -goog.asserts.DEFAULT_ERROR_HANDLER = function(e) { throw e; }; - - -/** - * The handler responsible for throwing or logging assertion errors. - * @private {function(!goog.asserts.AssertionError)} - */ -goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER; - - -/** - * Throws an exception with the given message and "Assertion failed" prefixed - * onto it. - * @param {string} defaultMessage The message to use if givenMessage is empty. - * @param {Array<*>} defaultArgs The substitution arguments for defaultMessage. - * @param {string|undefined} givenMessage Message supplied by the caller. - * @param {Array<*>} givenArgs The substitution arguments for givenMessage. - * @throws {goog.asserts.AssertionError} When the value is not a number. - * @private - */ -goog.asserts.doAssertFailure_ = - function(defaultMessage, defaultArgs, givenMessage, givenArgs) { - var message = 'Assertion failed'; - if (givenMessage) { - message += ': ' + givenMessage; - var args = givenArgs; - } else if (defaultMessage) { - message += ': ' + defaultMessage; - args = defaultArgs; - } - // The '' + works around an Opera 10 bug in the unit tests. Without it, - // a stack trace is added to var message above. With this, a stack trace is - // not added until this line (it causes the extra garbage to be added after - // the assertion message instead of in the middle of it). - var e = new goog.asserts.AssertionError('' + message, args || []); - goog.asserts.errorHandler_(e); -}; - - -/** - * Sets a custom error handler that can be used to customize the behavior of - * assertion failures, for example by turning all assertion failures into log - * messages. - * @param {function(!goog.asserts.AssertionError)} errorHandler - */ -goog.asserts.setErrorHandler = function(errorHandler) { - if (goog.asserts.ENABLE_ASSERTS) { - goog.asserts.errorHandler_ = errorHandler; - } -}; - - -/** - * Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is - * true. - * @template T - * @param {T} condition The condition to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {T} The value of the condition. - * @throws {goog.asserts.AssertionError} When the condition evaluates to false. - */ -goog.asserts.assert = function(condition, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !condition) { - goog.asserts.doAssertFailure_('', null, opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return condition; -}; - - -/** - * Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case - * when we want to add a check in the unreachable area like switch-case - * statement: - * - * <pre> - * switch(type) { - * case FOO: doSomething(); break; - * case BAR: doSomethingElse(); break; - * default: goog.assert.fail('Unrecognized type: ' + type); - * // We have only 2 types - "default:" section is unreachable code. - * } - * </pre> - * - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @throws {goog.asserts.AssertionError} Failure. - */ -goog.asserts.fail = function(opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS) { - goog.asserts.errorHandler_(new goog.asserts.AssertionError( - 'Failure' + (opt_message ? ': ' + opt_message : ''), - Array.prototype.slice.call(arguments, 1))); - } -}; - - -/** - * Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {number} The value, guaranteed to be a number when asserts enabled. - * @throws {goog.asserts.AssertionError} When the value is not a number. - */ -goog.asserts.assertNumber = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isNumber(value)) { - goog.asserts.doAssertFailure_('Expected number but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {number} */ (value); -}; - - -/** - * Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {string} The value, guaranteed to be a string when asserts enabled. - * @throws {goog.asserts.AssertionError} When the value is not a string. - */ -goog.asserts.assertString = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isString(value)) { - goog.asserts.doAssertFailure_('Expected string but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {string} */ (value); -}; - - -/** - * Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Function} The value, guaranteed to be a function when asserts - * enabled. - * @throws {goog.asserts.AssertionError} When the value is not a function. - */ -goog.asserts.assertFunction = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isFunction(value)) { - goog.asserts.doAssertFailure_('Expected function but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {!Function} */ (value); -}; - - -/** - * Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Object} The value, guaranteed to be a non-null object. - * @throws {goog.asserts.AssertionError} When the value is not an object. - */ -goog.asserts.assertObject = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) { - goog.asserts.doAssertFailure_('Expected object but got %s: %s.', - [goog.typeOf(value), value], - opt_message, Array.prototype.slice.call(arguments, 2)); - } - return /** @type {!Object} */ (value); -}; - - -/** - * Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Array<?>} The value, guaranteed to be a non-null array. - * @throws {goog.asserts.AssertionError} When the value is not an array. - */ -goog.asserts.assertArray = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isArray(value)) { - goog.asserts.doAssertFailure_('Expected array but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {!Array<?>} */ (value); -}; - - -/** - * Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {boolean} The value, guaranteed to be a boolean when asserts are - * enabled. - * @throws {goog.asserts.AssertionError} When the value is not a boolean. - */ -goog.asserts.assertBoolean = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isBoolean(value)) { - goog.asserts.doAssertFailure_('Expected boolean but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {boolean} */ (value); -}; - - -/** - * Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Element} The value, likely to be a DOM Element when asserts are - * enabled. - * @throws {goog.asserts.AssertionError} When the value is not an Element. - */ -goog.asserts.assertElement = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && (!goog.isObject(value) || - value.nodeType != goog.dom.NodeType.ELEMENT)) { - goog.asserts.doAssertFailure_('Expected Element but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {!Element} */ (value); -}; - - -/** - * Checks if the value is an instance of the user-defined type if - * goog.asserts.ENABLE_ASSERTS is true. - * - * The compiler may tighten the type returned by this function. - * - * @param {*} value The value to check. - * @param {function(new: T, ...)} type A user-defined constructor. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @throws {goog.asserts.AssertionError} When the value is not an instance of - * type. - * @return {T} - * @template T - */ -goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) { - goog.asserts.doAssertFailure_('Expected instanceof %s but got %s.', - [goog.asserts.getType_(type), goog.asserts.getType_(value)], - opt_message, Array.prototype.slice.call(arguments, 3)); - } - return value; -}; - - -/** - * Checks that no enumerable keys are present in Object.prototype. Such keys - * would break most code that use {@code for (var ... in ...)} loops. - */ -goog.asserts.assertObjectPrototypeIsIntact = function() { - for (var key in Object.prototype) { - goog.asserts.fail(key + ' should not be enumerable in Object.prototype.'); - } -}; - - -/** - * Returns the type of a value. If a constructor is passed, and a suitable - * string cannot be found, 'unknown type name' will be returned. - * @param {*} value A constructor, object, or primitive. - * @return {string} The best display name for the value, or 'unknown type name'. - * @private - */ -goog.asserts.getType_ = function(value) { - if (value instanceof Function) { - return value.displayName || value.name || 'unknown type name'; - } else if (value instanceof Object) { - return value.constructor.displayName || value.constructor.name || - Object.prototype.toString.call(value); - } else { - return value === null ? 'null' : typeof value; - } -}; - -goog.provide('ol.math'); - -goog.require('goog.asserts'); - - -/** - * Takes a number and clamps it to within the provided bounds. - * @param {number} value The input number. - * @param {number} min The minimum value to return. - * @param {number} max The maximum value to return. - * @return {number} The input number if it is within bounds, or the nearest - * number within the bounds. - */ -ol.math.clamp = function(value, min, max) { - return Math.min(Math.max(value, min), max); -}; - - -/** - * Return the hyperbolic cosine of a given number. The method will use the - * native `Math.cosh` function if it is available, otherwise the hyperbolic - * cosine will be calculated via the reference implementation of the Mozilla - * developer network. - * - * @param {number} x X. - * @return {number} Hyperbolic cosine of x. - */ -ol.math.cosh = (function() { - // Wrapped in a iife, to save the overhead of checking for the native - // implementation on every invocation. - var cosh; - if ('cosh' in Math) { - // The environment supports the native Math.cosh function, use it… - cosh = Math.cosh; - } else { - // … else, use the reference implementation of MDN: - cosh = function(x) { - var y = Math.exp(x); - return (y + 1 / y) / 2; - }; - } - return cosh; -}()); - - -/** - * @param {number} x X. - * @return {number} The smallest power of two greater than or equal to x. - */ -ol.math.roundUpToPowerOfTwo = function(x) { - goog.asserts.assert(0 < x, 'x should be larger than 0'); - return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2)); -}; - - -/** - * Returns the square of the closest distance between the point (x, y) and the - * line segment (x1, y1) to (x2, y2). - * @param {number} x X. - * @param {number} y Y. - * @param {number} x1 X1. - * @param {number} y1 Y1. - * @param {number} x2 X2. - * @param {number} y2 Y2. - * @return {number} Squared distance. - */ -ol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) { - var dx = x2 - x1; - var dy = y2 - y1; - if (dx !== 0 || dy !== 0) { - var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); - if (t > 1) { - x1 = x2; - y1 = y2; - } else if (t > 0) { - x1 += dx * t; - y1 += dy * t; - } - } - return ol.math.squaredDistance(x, y, x1, y1); -}; - - -/** - * Returns the square of the distance between the points (x1, y1) and (x2, y2). - * @param {number} x1 X1. - * @param {number} y1 Y1. - * @param {number} x2 X2. - * @param {number} y2 Y2. - * @return {number} Squared distance. - */ -ol.math.squaredDistance = function(x1, y1, x2, y2) { - var dx = x2 - x1; - var dy = y2 - y1; - return dx * dx + dy * dy; -}; - - -/** - * Solves system of linear equations using Gaussian elimination method. - * - * @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column) - * in row-major order. - * @return {Array.<number>} The resulting vector. - */ -ol.math.solveLinearSystem = function(mat) { - var n = mat.length; - - if (goog.asserts.ENABLE_ASSERTS) { - for (var row = 0; row < n; row++) { - goog.asserts.assert(mat[row].length == n + 1, - 'every row should have correct number of columns'); - } - } - - for (var i = 0; i < n; i++) { - // Find max in the i-th column (ignoring i - 1 first rows) - var maxRow = i; - var maxEl = Math.abs(mat[i][i]); - for (var r = i + 1; r < n; r++) { - var absValue = Math.abs(mat[r][i]); - if (absValue > maxEl) { - maxEl = absValue; - maxRow = r; - } - } - - if (maxEl === 0) { - return null; // matrix is singular - } - - // Swap max row with i-th (current) row - var tmp = mat[maxRow]; - mat[maxRow] = mat[i]; - mat[i] = tmp; - - // Subtract the i-th row to make all the remaining rows 0 in the i-th column - for (var j = i + 1; j < n; j++) { - var coef = -mat[j][i] / mat[i][i]; - for (var k = i; k < n + 1; k++) { - if (i == k) { - mat[j][k] = 0; - } else { - mat[j][k] += coef * mat[i][k]; - } - } - } - } - - // Solve Ax=b for upper triangular matrix A (mat) - var x = new Array(n); - for (var l = n - 1; l >= 0; l--) { - x[l] = mat[l][n] / mat[l][l]; - for (var m = l - 1; m >= 0; m--) { - mat[m][n] -= mat[m][l] * x[l]; - } - } - return x; -}; - - -/** - * Converts radians to to degrees. - * - * @param {number} angleInRadians Angle in radians. - * @return {number} Angle in degrees. - */ -ol.math.toDegrees = function(angleInRadians) { - return angleInRadians * 180 / Math.PI; -}; - - -/** - * Converts degrees to radians. - * - * @param {number} angleInDegrees Angle in degrees. - * @return {number} Angle in radians. - */ -ol.math.toRadians = function(angleInDegrees) { - return angleInDegrees * Math.PI / 180; -}; - -goog.provide('ol.CenterConstraint'); -goog.provide('ol.CenterConstraintType'); - -goog.require('ol.math'); - - -/** - * @typedef {function((ol.Coordinate|undefined)): (ol.Coordinate|undefined)} - */ -ol.CenterConstraintType; - - -/** - * @param {ol.Extent} extent Extent. - * @return {ol.CenterConstraintType} - */ -ol.CenterConstraint.createExtent = function(extent) { - return ( - /** - * @param {ol.Coordinate|undefined} center Center. - * @return {ol.Coordinate|undefined} Center. - */ - function(center) { - if (center) { - return [ - ol.math.clamp(center[0], extent[0], extent[2]), - ol.math.clamp(center[1], extent[1], extent[3]) - ]; - } else { - return undefined; - } - }); -}; - - -/** - * @param {ol.Coordinate|undefined} center Center. - * @return {ol.Coordinate|undefined} Center. - */ -ol.CenterConstraint.none = function(center) { - return center; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for manipulating arrays. - * - * @author arv@google.com (Erik Arvidsson) - */ - - -goog.provide('goog.array'); -goog.provide('goog.array.ArrayLike'); - -goog.require('goog.asserts'); - - -/** - * @define {boolean} NATIVE_ARRAY_PROTOTYPES indicates whether the code should - * rely on Array.prototype functions, if available. - * - * The Array.prototype functions can be defined by external libraries like - * Prototype and setting this flag to false forces closure to use its own - * goog.array implementation. - * - * If your javascript can be loaded by a third party site and you are wary about - * relying on the prototype functions, specify - * "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler. - * - * Setting goog.TRUSTED_SITE to false will automatically set - * NATIVE_ARRAY_PROTOTYPES to false. - */ -goog.define('goog.NATIVE_ARRAY_PROTOTYPES', goog.TRUSTED_SITE); - - -/** - * @define {boolean} If true, JSCompiler will use the native implementation of - * array functions where appropriate (e.g., {@code Array#filter}) and remove the - * unused pure JS implementation. - */ -goog.define('goog.array.ASSUME_NATIVE_FUNCTIONS', false); - - -/** - * @typedef {Array|NodeList|Arguments|{length: number}} - */ -goog.array.ArrayLike; - - -/** - * Returns the last element in an array without removing it. - * Same as goog.array.last. - * @param {Array<T>|goog.array.ArrayLike} array The array. - * @return {T} Last item in array. - * @template T - */ -goog.array.peek = function(array) { - return array[array.length - 1]; -}; - - -/** - * Returns the last element in an array without removing it. - * Same as goog.array.peek. - * @param {Array<T>|goog.array.ArrayLike} array The array. - * @return {T} Last item in array. - * @template T - */ -goog.array.last = goog.array.peek; - - -/** - * Reference to the original {@code Array.prototype}. - * @private - */ -goog.array.ARRAY_PROTOTYPE_ = Array.prototype; - - -// NOTE(arv): Since most of the array functions are generic it allows you to -// pass an array-like object. Strings have a length and are considered array- -// like. However, the 'in' operator does not work on strings so we cannot just -// use the array path even if the browser supports indexing into strings. We -// therefore end up splitting the string. - - -/** - * Returns the index of the first element of an array with a specified value, or - * -1 if the element is not present in the array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-indexof} - * - * @param {Array<T>|goog.array.ArrayLike} arr The array to be searched. - * @param {T} obj The object for which we are searching. - * @param {number=} opt_fromIndex The index at which to start the search. If - * omitted the search starts at index 0. - * @return {number} The index of the first matching array element. - * @template T - */ -goog.array.indexOf = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.indexOf) ? - function(arr, obj, opt_fromIndex) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.indexOf.call(arr, obj, opt_fromIndex); - } : - function(arr, obj, opt_fromIndex) { - var fromIndex = opt_fromIndex == null ? - 0 : (opt_fromIndex < 0 ? - Math.max(0, arr.length + opt_fromIndex) : opt_fromIndex); - - if (goog.isString(arr)) { - // Array.prototype.indexOf uses === so only strings should be found. - if (!goog.isString(obj) || obj.length != 1) { - return -1; - } - return arr.indexOf(obj, fromIndex); - } - - for (var i = fromIndex; i < arr.length; i++) { - if (i in arr && arr[i] === obj) - return i; - } - return -1; - }; - - -/** - * Returns the index of the last element of an array with a specified value, or - * -1 if the element is not present in the array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-lastindexof} - * - * @param {!Array<T>|!goog.array.ArrayLike} arr The array to be searched. - * @param {T} obj The object for which we are searching. - * @param {?number=} opt_fromIndex The index at which to start the search. If - * omitted the search starts at the end of the array. - * @return {number} The index of the last matching array element. - * @template T - */ -goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.lastIndexOf) ? - function(arr, obj, opt_fromIndex) { - goog.asserts.assert(arr.length != null); - - // Firefox treats undefined and null as 0 in the fromIndex argument which - // leads it to always return -1 - var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex; - return goog.array.ARRAY_PROTOTYPE_.lastIndexOf.call(arr, obj, fromIndex); - } : - function(arr, obj, opt_fromIndex) { - var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex; - - if (fromIndex < 0) { - fromIndex = Math.max(0, arr.length + fromIndex); - } - - if (goog.isString(arr)) { - // Array.prototype.lastIndexOf uses === so only strings should be found. - if (!goog.isString(obj) || obj.length != 1) { - return -1; - } - return arr.lastIndexOf(obj, fromIndex); - } - - for (var i = fromIndex; i >= 0; i--) { - if (i in arr && arr[i] === obj) - return i; - } - return -1; - }; - - -/** - * Calls a function for each element in an array. Skips holes in the array. - * See {@link http://tinyurl.com/developer-mozilla-org-array-foreach} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over - * which to iterate. - * @param {?function(this: S, T, number, ?): ?} f The function to call for every - * element. This function takes 3 arguments (the element, the index and the - * array). The return value is ignored. - * @param {S=} opt_obj The object to be used as the value of 'this' within f. - * @template T,S - */ -goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.forEach) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - goog.array.ARRAY_PROTOTYPE_.forEach.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2) { - f.call(opt_obj, arr2[i], i, arr); - } - } - }; - - -/** - * Calls a function for each element in an array, starting from the last - * element rather than the first. - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this: S, T, number, ?): ?} f The function to call for every - * element. This function - * takes 3 arguments (the element, the index and the array). The return - * value is ignored. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @template T,S - */ -goog.array.forEachRight = function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = l - 1; i >= 0; --i) { - if (i in arr2) { - f.call(opt_obj, arr2[i], i, arr); - } - } -}; - - -/** - * Calls a function for each element in an array, and if the function returns - * true adds the element to a new array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-filter} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?):boolean} f The function to call for - * every element. This function - * takes 3 arguments (the element, the index and the array) and must - * return a Boolean. If the return value is true the element is added to the - * result array. If it is false the element is not included. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {!Array<T>} a new array in which only elements that passed the test - * are present. - * @template T,S - */ -goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.filter) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.filter.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var res = []; - var resLength = 0; - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2) { - var val = arr2[i]; // in case f mutates arr2 - if (f.call(opt_obj, val, i, arr)) { - res[resLength++] = val; - } - } - } - return res; - }; - - -/** - * Calls a function for each element in an array and inserts the result into a - * new array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-map} - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr Array or array like object - * over which to iterate. - * @param {function(this:THIS, VALUE, number, ?): RESULT} f The function to call - * for every element. This function takes 3 arguments (the element, - * the index and the array) and should return something. The result will be - * inserted into a new array. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within f. - * @return {!Array<RESULT>} a new array with the results from f. - * @template THIS, VALUE, RESULT - */ -goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.map) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.map.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var res = new Array(l); - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2) { - res[i] = f.call(opt_obj, arr2[i], i, arr); - } - } - return res; - }; - - -/** - * Passes every element of an array into a function and accumulates the result. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-reduce} - * - * For example: - * var a = [1, 2, 3, 4]; - * goog.array.reduce(a, function(r, v, i, arr) {return r + v;}, 0); - * returns 10 - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {function(this:S, R, T, number, ?) : R} f The function to call for - * every element. This function - * takes 4 arguments (the function's previous result or the initial value, - * the value of the current array element, the current array index, and the - * array itself) - * function(previousValue, currentValue, index, array). - * @param {?} val The initial value to pass into the function on the first call. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {R} Result of evaluating f repeatedly across the values of the array. - * @template T,S,R - */ -goog.array.reduce = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.reduce) ? - function(arr, f, val, opt_obj) { - goog.asserts.assert(arr.length != null); - if (opt_obj) { - f = goog.bind(f, opt_obj); - } - return goog.array.ARRAY_PROTOTYPE_.reduce.call(arr, f, val); - } : - function(arr, f, val, opt_obj) { - var rval = val; - goog.array.forEach(arr, function(val, index) { - rval = f.call(opt_obj, rval, val, index, arr); - }); - return rval; - }; - - -/** - * Passes every element of an array into a function and accumulates the result, - * starting from the last element and working towards the first. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-reduceright} - * - * For example: - * var a = ['a', 'b', 'c']; - * goog.array.reduceRight(a, function(r, v, i, arr) {return r + v;}, ''); - * returns 'cba' - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, R, T, number, ?) : R} f The function to call for - * every element. This function - * takes 4 arguments (the function's previous result or the initial value, - * the value of the current array element, the current array index, and the - * array itself) - * function(previousValue, currentValue, index, array). - * @param {?} val The initial value to pass into the function on the first call. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {R} Object returned as a result of evaluating f repeatedly across the - * values of the array. - * @template T,S,R - */ -goog.array.reduceRight = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.reduceRight) ? - function(arr, f, val, opt_obj) { - goog.asserts.assert(arr.length != null); - if (opt_obj) { - f = goog.bind(f, opt_obj); - } - return goog.array.ARRAY_PROTOTYPE_.reduceRight.call(arr, f, val); - } : - function(arr, f, val, opt_obj) { - var rval = val; - goog.array.forEachRight(arr, function(val, index) { - rval = f.call(opt_obj, rval, val, index, arr); - }); - return rval; - }; - - -/** - * Calls f for each element of an array. If any call returns true, some() - * returns true (without checking the remaining elements). If all calls - * return false, some() returns false. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-some} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call for - * for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a boolean. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {boolean} true if any element passes the test. - * @template T,S - */ -goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.some) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.some.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { - return true; - } - } - return false; - }; - - -/** - * Call f for each element of an array. If all calls return true, every() - * returns true. If any call returns false, every() returns false and - * does not continue to check the remaining elements. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-every} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call for - * for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a boolean. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {boolean} false if any element fails the test. - * @template T,S - */ -goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.every) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.every.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2 && !f.call(opt_obj, arr2[i], i, arr)) { - return false; - } - } - return true; - }; - - -/** - * Counts the array elements that fulfill the predicate, i.e. for which the - * callback function returns true. Skips holes in the array. - * - * @param {!(Array<T>|goog.array.ArrayLike)} arr Array or array like object - * over which to iterate. - * @param {function(this: S, T, number, ?): boolean} f The function to call for - * every element. Takes 3 arguments (the element, the index and the array). - * @param {S=} opt_obj The object to be used as the value of 'this' within f. - * @return {number} The number of the matching elements. - * @template T,S - */ -goog.array.count = function(arr, f, opt_obj) { - var count = 0; - goog.array.forEach(arr, function(element, index, arr) { - if (f.call(opt_obj, element, index, arr)) { - ++count; - } - }, opt_obj); - return count; -}; - - -/** - * Search an array for the first element that satisfies a given condition and - * return that element. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {T|null} The first array element that passes the test, or null if no - * element is found. - * @template T,S - */ -goog.array.find = function(arr, f, opt_obj) { - var i = goog.array.findIndex(arr, f, opt_obj); - return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i]; -}; - - -/** - * Search an array for the first element that satisfies a given condition and - * return its index. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call for - * every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {number} The index of the first array element that passes the test, - * or -1 if no element is found. - * @template T,S - */ -goog.array.findIndex = function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { - return i; - } - } - return -1; -}; - - -/** - * Search an array (in reverse order) for the last element that satisfies a - * given condition and return that element. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {T|null} The last array element that passes the test, or null if no - * element is found. - * @template T,S - */ -goog.array.findRight = function(arr, f, opt_obj) { - var i = goog.array.findIndexRight(arr, f, opt_obj); - return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i]; -}; - - -/** - * Search an array (in reverse order) for the last element that satisfies a - * given condition and return its index. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {number} The index of the last array element that passes the test, - * or -1 if no element is found. - * @template T,S - */ -goog.array.findIndexRight = function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = l - 1; i >= 0; i--) { - if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { - return i; - } - } - return -1; -}; - - -/** - * Whether the array contains the given object. - * @param {goog.array.ArrayLike} arr The array to test for the presence of the - * element. - * @param {*} obj The object for which to test. - * @return {boolean} true if obj is present. - */ -goog.array.contains = function(arr, obj) { - return goog.array.indexOf(arr, obj) >= 0; -}; - - -/** - * Whether the array is empty. - * @param {goog.array.ArrayLike} arr The array to test. - * @return {boolean} true if empty. - */ -goog.array.isEmpty = function(arr) { - return arr.length == 0; -}; - - -/** - * Clears the array. - * @param {goog.array.ArrayLike} arr Array or array like object to clear. - */ -goog.array.clear = function(arr) { - // For non real arrays we don't have the magic length so we delete the - // indices. - if (!goog.isArray(arr)) { - for (var i = arr.length - 1; i >= 0; i--) { - delete arr[i]; - } - } - arr.length = 0; -}; - - -/** - * Pushes an item into an array, if it's not already in the array. - * @param {Array<T>} arr Array into which to insert the item. - * @param {T} obj Value to add. - * @template T - */ -goog.array.insert = function(arr, obj) { - if (!goog.array.contains(arr, obj)) { - arr.push(obj); - } -}; - - -/** - * Inserts an object at the given index of the array. - * @param {goog.array.ArrayLike} arr The array to modify. - * @param {*} obj The object to insert. - * @param {number=} opt_i The index at which to insert the object. If omitted, - * treated as 0. A negative index is counted from the end of the array. - */ -goog.array.insertAt = function(arr, obj, opt_i) { - goog.array.splice(arr, opt_i, 0, obj); -}; - - -/** - * Inserts at the given index of the array, all elements of another array. - * @param {goog.array.ArrayLike} arr The array to modify. - * @param {goog.array.ArrayLike} elementsToAdd The array of elements to add. - * @param {number=} opt_i The index at which to insert the object. If omitted, - * treated as 0. A negative index is counted from the end of the array. - */ -goog.array.insertArrayAt = function(arr, elementsToAdd, opt_i) { - goog.partial(goog.array.splice, arr, opt_i, 0).apply(null, elementsToAdd); -}; - - -/** - * Inserts an object into an array before a specified object. - * @param {Array<T>} arr The array to modify. - * @param {T} obj The object to insert. - * @param {T=} opt_obj2 The object before which obj should be inserted. If obj2 - * is omitted or not found, obj is inserted at the end of the array. - * @template T - */ -goog.array.insertBefore = function(arr, obj, opt_obj2) { - var i; - if (arguments.length == 2 || (i = goog.array.indexOf(arr, opt_obj2)) < 0) { - arr.push(obj); - } else { - goog.array.insertAt(arr, obj, i); - } -}; - - -/** - * Removes the first occurrence of a particular value from an array. - * @param {Array<T>|goog.array.ArrayLike} arr Array from which to remove - * value. - * @param {T} obj Object to remove. - * @return {boolean} True if an element was removed. - * @template T - */ -goog.array.remove = function(arr, obj) { - var i = goog.array.indexOf(arr, obj); - var rv; - if ((rv = i >= 0)) { - goog.array.removeAt(arr, i); - } - return rv; -}; - - -/** - * Removes from an array the element at index i - * @param {goog.array.ArrayLike} arr Array or array like object from which to - * remove value. - * @param {number} i The index to remove. - * @return {boolean} True if an element was removed. - */ -goog.array.removeAt = function(arr, i) { - goog.asserts.assert(arr.length != null); - - // use generic form of splice - // splice returns the removed items and if successful the length of that - // will be 1 - return goog.array.ARRAY_PROTOTYPE_.splice.call(arr, i, 1).length == 1; -}; - - -/** - * Removes the first value that satisfies the given condition. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {boolean} True if an element was removed. - * @template T,S - */ -goog.array.removeIf = function(arr, f, opt_obj) { - var i = goog.array.findIndex(arr, f, opt_obj); - if (i >= 0) { - goog.array.removeAt(arr, i); - return true; - } - return false; -}; - - -/** - * Removes all values that satisfy the given condition. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {number} The number of items removed - * @template T,S - */ -goog.array.removeAllIf = function(arr, f, opt_obj) { - var removedCount = 0; - goog.array.forEachRight(arr, function(val, index) { - if (f.call(opt_obj, val, index, arr)) { - if (goog.array.removeAt(arr, index)) { - removedCount++; - } - } - }); - return removedCount; -}; - - -/** - * Returns a new array that is the result of joining the arguments. If arrays - * are passed then their items are added, however, if non-arrays are passed they - * will be added to the return array as is. - * - * Note that ArrayLike objects will be added as is, rather than having their - * items added. - * - * goog.array.concat([1, 2], [3, 4]) -> [1, 2, 3, 4] - * goog.array.concat(0, [1, 2]) -> [0, 1, 2] - * goog.array.concat([1, 2], null) -> [1, 2, null] - * - * There is bug in all current versions of IE (6, 7 and 8) where arrays created - * in an iframe become corrupted soon (not immediately) after the iframe is - * destroyed. This is common if loading data via goog.net.IframeIo, for example. - * This corruption only affects the concat method which will start throwing - * Catastrophic Errors (#-2147418113). - * - * See http://endoflow.com/scratch/corrupted-arrays.html for a test case. - * - * Internally goog.array should use this, so that all methods will continue to - * work on these broken array objects. - * - * @param {...*} var_args Items to concatenate. Arrays will have each item - * added, while primitives and objects will be added as is. - * @return {!Array<?>} The new resultant array. - */ -goog.array.concat = function(var_args) { - return goog.array.ARRAY_PROTOTYPE_.concat.apply( - goog.array.ARRAY_PROTOTYPE_, arguments); -}; - - -/** - * Returns a new array that contains the contents of all the arrays passed. - * @param {...!Array<T>} var_args - * @return {!Array<T>} - * @template T - */ -goog.array.join = function(var_args) { - return goog.array.ARRAY_PROTOTYPE_.concat.apply( - goog.array.ARRAY_PROTOTYPE_, arguments); -}; - - -/** - * Converts an object to an array. - * @param {Array<T>|goog.array.ArrayLike} object The object to convert to an - * array. - * @return {!Array<T>} The object converted into an array. If object has a - * length property, every property indexed with a non-negative number - * less than length will be included in the result. If object does not - * have a length property, an empty array will be returned. - * @template T - */ -goog.array.toArray = function(object) { - var length = object.length; - - // If length is not a number the following it false. This case is kept for - // backwards compatibility since there are callers that pass objects that are - // not array like. - if (length > 0) { - var rv = new Array(length); - for (var i = 0; i < length; i++) { - rv[i] = object[i]; - } - return rv; - } - return []; -}; - - -/** - * Does a shallow copy of an array. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array-like object to - * clone. - * @return {!Array<T>} Clone of the input array. - * @template T - */ -goog.array.clone = goog.array.toArray; - - -/** - * Extends an array with another array, element, or "array like" object. - * This function operates 'in-place', it does not create a new Array. - * - * Example: - * var a = []; - * goog.array.extend(a, [0, 1]); - * a; // [0, 1] - * goog.array.extend(a, 2); - * a; // [0, 1, 2] - * - * @param {Array<VALUE>} arr1 The array to modify. - * @param {...(Array<VALUE>|VALUE)} var_args The elements or arrays of elements - * to add to arr1. - * @template VALUE - */ -goog.array.extend = function(arr1, var_args) { - for (var i = 1; i < arguments.length; i++) { - var arr2 = arguments[i]; - if (goog.isArrayLike(arr2)) { - var len1 = arr1.length || 0; - var len2 = arr2.length || 0; - arr1.length = len1 + len2; - for (var j = 0; j < len2; j++) { - arr1[len1 + j] = arr2[j]; - } - } else { - arr1.push(arr2); - } - } -}; - - -/** - * Adds or removes elements from an array. This is a generic version of Array - * splice. This means that it might work on other objects similar to arrays, - * such as the arguments object. - * - * @param {Array<T>|goog.array.ArrayLike} arr The array to modify. - * @param {number|undefined} index The index at which to start changing the - * array. If not defined, treated as 0. - * @param {number} howMany How many elements to remove (0 means no removal. A - * value below 0 is treated as zero and so is any other non number. Numbers - * are floored). - * @param {...T} var_args Optional, additional elements to insert into the - * array. - * @return {!Array<T>} the removed elements. - * @template T - */ -goog.array.splice = function(arr, index, howMany, var_args) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.splice.apply( - arr, goog.array.slice(arguments, 1)); -}; - - -/** - * Returns a new array from a segment of an array. This is a generic version of - * Array slice. This means that it might work on other objects similar to - * arrays, such as the arguments object. - * - * @param {Array<T>|goog.array.ArrayLike} arr The array from - * which to copy a segment. - * @param {number} start The index of the first element to copy. - * @param {number=} opt_end The index after the last element to copy. - * @return {!Array<T>} A new array containing the specified segment of the - * original array. - * @template T - */ -goog.array.slice = function(arr, start, opt_end) { - goog.asserts.assert(arr.length != null); - - // passing 1 arg to slice is not the same as passing 2 where the second is - // null or undefined (in that case the second argument is treated as 0). - // we could use slice on the arguments object and then use apply instead of - // testing the length - if (arguments.length <= 2) { - return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start); - } else { - return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start, opt_end); - } -}; - - -/** - * Removes all duplicates from an array (retaining only the first - * occurrence of each array element). This function modifies the - * array in place and doesn't change the order of the non-duplicate items. - * - * For objects, duplicates are identified as having the same unique ID as - * defined by {@link goog.getUid}. - * - * Alternatively you can specify a custom hash function that returns a unique - * value for each item in the array it should consider unique. - * - * Runtime: N, - * Worstcase space: 2N (no dupes) - * - * @param {Array<T>|goog.array.ArrayLike} arr The array from which to remove - * duplicates. - * @param {Array=} opt_rv An optional array in which to return the results, - * instead of performing the removal inplace. If specified, the original - * array will remain unchanged. - * @param {function(T):string=} opt_hashFn An optional function to use to - * apply to every item in the array. This function should return a unique - * value for each item in the array it should consider unique. - * @template T - */ -goog.array.removeDuplicates = function(arr, opt_rv, opt_hashFn) { - var returnArray = opt_rv || arr; - var defaultHashFn = function(item) { - // Prefix each type with a single character representing the type to - // prevent conflicting keys (e.g. true and 'true'). - return goog.isObject(item) ? 'o' + goog.getUid(item) : - (typeof item).charAt(0) + item; - }; - var hashFn = opt_hashFn || defaultHashFn; - - var seen = {}, cursorInsert = 0, cursorRead = 0; - while (cursorRead < arr.length) { - var current = arr[cursorRead++]; - var key = hashFn(current); - if (!Object.prototype.hasOwnProperty.call(seen, key)) { - seen[key] = true; - returnArray[cursorInsert++] = current; - } - } - returnArray.length = cursorInsert; -}; - - -/** - * Searches the specified array for the specified target using the binary - * search algorithm. If no opt_compareFn is specified, elements are compared - * using <code>goog.array.defaultCompare</code>, which compares the elements - * using the built in < and > operators. This will produce the expected - * behavior for homogeneous arrays of String(s) and Number(s). The array - * specified <b>must</b> be sorted in ascending order (as defined by the - * comparison function). If the array is not sorted, results are undefined. - * If the array contains multiple instances of the specified target value, any - * of these instances may be found. - * - * Runtime: O(log n) - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. - * @param {TARGET} target The sought value. - * @param {function(TARGET, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {number} Lowest index of the target value if found, otherwise - * (-(insertion point) - 1). The insertion point is where the value should - * be inserted into arr to preserve the sorted property. Return value >= 0 - * iff target is found. - * @template TARGET, VALUE - */ -goog.array.binarySearch = function(arr, target, opt_compareFn) { - return goog.array.binarySearch_(arr, - opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */, - target); -}; - - -/** - * Selects an index in the specified array using the binary search algorithm. - * The evaluator receives an element and determines whether the desired index - * is before, at, or after it. The evaluator must be consistent (formally, - * goog.array.map(goog.array.map(arr, evaluator, opt_obj), goog.math.sign) - * must be monotonically non-increasing). - * - * Runtime: O(log n) - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. - * @param {function(this:THIS, VALUE, number, ?): number} evaluator - * Evaluator function that receives 3 arguments (the element, the index and - * the array). Should return a negative number, zero, or a positive number - * depending on whether the desired index is before, at, or after the - * element passed to it. - * @param {THIS=} opt_obj The object to be used as the value of 'this' - * within evaluator. - * @return {number} Index of the leftmost element matched by the evaluator, if - * such exists; otherwise (-(insertion point) - 1). The insertion point is - * the index of the first element for which the evaluator returns negative, - * or arr.length if no such element exists. The return value is non-negative - * iff a match is found. - * @template THIS, VALUE - */ -goog.array.binarySelect = function(arr, evaluator, opt_obj) { - return goog.array.binarySearch_(arr, evaluator, true /* isEvaluator */, - undefined /* opt_target */, opt_obj); -}; - - -/** - * Implementation of a binary search algorithm which knows how to use both - * comparison functions and evaluators. If an evaluator is provided, will call - * the evaluator with the given optional data object, conforming to the - * interface defined in binarySelect. Otherwise, if a comparison function is - * provided, will call the comparison function against the given data object. - * - * This implementation purposefully does not use goog.bind or goog.partial for - * performance reasons. - * - * Runtime: O(log n) - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. - * @param {function(TARGET, VALUE): number| - * function(this:THIS, VALUE, number, ?): number} compareFn Either an - * evaluator or a comparison function, as defined by binarySearch - * and binarySelect above. - * @param {boolean} isEvaluator Whether the function is an evaluator or a - * comparison function. - * @param {TARGET=} opt_target If the function is a comparison function, then - * this is the target to binary search for. - * @param {THIS=} opt_selfObj If the function is an evaluator, this is an - * optional this object for the evaluator. - * @return {number} Lowest index of the target value if found, otherwise - * (-(insertion point) - 1). The insertion point is where the value should - * be inserted into arr to preserve the sorted property. Return value >= 0 - * iff target is found. - * @template THIS, VALUE, TARGET - * @private - */ -goog.array.binarySearch_ = function(arr, compareFn, isEvaluator, opt_target, - opt_selfObj) { - var left = 0; // inclusive - var right = arr.length; // exclusive - var found; - while (left < right) { - var middle = (left + right) >> 1; - var compareResult; - if (isEvaluator) { - compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr); - } else { - compareResult = compareFn(opt_target, arr[middle]); - } - if (compareResult > 0) { - left = middle + 1; - } else { - right = middle; - // We are looking for the lowest index so we can't return immediately. - found = !compareResult; - } - } - // left is the index if found, or the insertion point otherwise. - // ~left is a shorthand for -left - 1. - return found ? left : ~left; -}; - - -/** - * Sorts the specified array into ascending order. If no opt_compareFn is - * specified, elements are compared using - * <code>goog.array.defaultCompare</code>, which compares the elements using - * the built in < and > operators. This will produce the expected behavior - * for homogeneous arrays of String(s) and Number(s), unlike the native sort, - * but will give unpredictable results for heterogenous lists of strings and - * numbers with different numbers of digits. - * - * This sort is not guaranteed to be stable. - * - * Runtime: Same as <code>Array.prototype.sort</code> - * - * @param {Array<T>} arr The array to be sorted. - * @param {?function(T,T):number=} opt_compareFn Optional comparison - * function by which the - * array is to be ordered. Should take 2 arguments to compare, and return a - * negative number, zero, or a positive number depending on whether the - * first argument is less than, equal to, or greater than the second. - * @template T - */ -goog.array.sort = function(arr, opt_compareFn) { - // TODO(arv): Update type annotation since null is not accepted. - arr.sort(opt_compareFn || goog.array.defaultCompare); -}; - - -/** - * Sorts the specified array into ascending order in a stable way. If no - * opt_compareFn is specified, elements are compared using - * <code>goog.array.defaultCompare</code>, which compares the elements using - * the built in < and > operators. This will produce the expected behavior - * for homogeneous arrays of String(s) and Number(s). - * - * Runtime: Same as <code>Array.prototype.sort</code>, plus an additional - * O(n) overhead of copying the array twice. - * - * @param {Array<T>} arr The array to be sorted. - * @param {?function(T, T): number=} opt_compareFn Optional comparison function - * by which the array is to be ordered. Should take 2 arguments to compare, - * and return a negative number, zero, or a positive number depending on - * whether the first argument is less than, equal to, or greater than the - * second. - * @template T - */ -goog.array.stableSort = function(arr, opt_compareFn) { - for (var i = 0; i < arr.length; i++) { - arr[i] = {index: i, value: arr[i]}; - } - var valueCompareFn = opt_compareFn || goog.array.defaultCompare; - function stableCompareFn(obj1, obj2) { - return valueCompareFn(obj1.value, obj2.value) || obj1.index - obj2.index; - }; - goog.array.sort(arr, stableCompareFn); - for (var i = 0; i < arr.length; i++) { - arr[i] = arr[i].value; - } -}; - - -/** - * Sort the specified array into ascending order based on item keys - * returned by the specified key function. - * If no opt_compareFn is specified, the keys are compared in ascending order - * using <code>goog.array.defaultCompare</code>. - * - * Runtime: O(S(f(n)), where S is runtime of <code>goog.array.sort</code> - * and f(n) is runtime of the key function. - * - * @param {Array<T>} arr The array to be sorted. - * @param {function(T): K} keyFn Function taking array element and returning - * a key used for sorting this element. - * @param {?function(K, K): number=} opt_compareFn Optional comparison function - * by which the keys are to be ordered. Should take 2 arguments to compare, - * and return a negative number, zero, or a positive number depending on - * whether the first argument is less than, equal to, or greater than the - * second. - * @template T,K - */ -goog.array.sortByKey = function(arr, keyFn, opt_compareFn) { - var keyCompareFn = opt_compareFn || goog.array.defaultCompare; - goog.array.sort(arr, function(a, b) { - return keyCompareFn(keyFn(a), keyFn(b)); - }); -}; - - -/** - * Sorts an array of objects by the specified object key and compare - * function. If no compare function is provided, the key values are - * compared in ascending order using <code>goog.array.defaultCompare</code>. - * This won't work for keys that get renamed by the compiler. So use - * {'foo': 1, 'bar': 2} rather than {foo: 1, bar: 2}. - * @param {Array<Object>} arr An array of objects to sort. - * @param {string} key The object key to sort by. - * @param {Function=} opt_compareFn The function to use to compare key - * values. - */ -goog.array.sortObjectsByKey = function(arr, key, opt_compareFn) { - goog.array.sortByKey(arr, - function(obj) { return obj[key]; }, - opt_compareFn); -}; - - -/** - * Tells if the array is sorted. - * @param {!Array<T>} arr The array. - * @param {?function(T,T):number=} opt_compareFn Function to compare the - * array elements. - * Should take 2 arguments to compare, and return a negative number, zero, - * or a positive number depending on whether the first argument is less - * than, equal to, or greater than the second. - * @param {boolean=} opt_strict If true no equal elements are allowed. - * @return {boolean} Whether the array is sorted. - * @template T - */ -goog.array.isSorted = function(arr, opt_compareFn, opt_strict) { - var compare = opt_compareFn || goog.array.defaultCompare; - for (var i = 1; i < arr.length; i++) { - var compareResult = compare(arr[i - 1], arr[i]); - if (compareResult > 0 || compareResult == 0 && opt_strict) { - return false; - } - } - return true; -}; - - -/** - * Compares two arrays for equality. Two arrays are considered equal if they - * have the same length and their corresponding elements are equal according to - * the comparison function. - * - * @param {goog.array.ArrayLike} arr1 The first array to compare. - * @param {goog.array.ArrayLike} arr2 The second array to compare. - * @param {Function=} opt_equalsFn Optional comparison function. - * Should take 2 arguments to compare, and return true if the arguments - * are equal. Defaults to {@link goog.array.defaultCompareEquality} which - * compares the elements using the built-in '===' operator. - * @return {boolean} Whether the two arrays are equal. - */ -goog.array.equals = function(arr1, arr2, opt_equalsFn) { - if (!goog.isArrayLike(arr1) || !goog.isArrayLike(arr2) || - arr1.length != arr2.length) { - return false; - } - var l = arr1.length; - var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality; - for (var i = 0; i < l; i++) { - if (!equalsFn(arr1[i], arr2[i])) { - return false; - } - } - return true; -}; - - -/** - * 3-way array compare function. - * @param {!Array<VALUE>|!goog.array.ArrayLike} arr1 The first array to - * compare. - * @param {!Array<VALUE>|!goog.array.ArrayLike} arr2 The second array to - * compare. - * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is to be ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {number} Negative number, zero, or a positive number depending on - * whether the first argument is less than, equal to, or greater than the - * second. - * @template VALUE - */ -goog.array.compare3 = function(arr1, arr2, opt_compareFn) { - var compare = opt_compareFn || goog.array.defaultCompare; - var l = Math.min(arr1.length, arr2.length); - for (var i = 0; i < l; i++) { - var result = compare(arr1[i], arr2[i]); - if (result != 0) { - return result; - } - } - return goog.array.defaultCompare(arr1.length, arr2.length); -}; - - -/** - * Compares its two arguments for order, using the built in < and > - * operators. - * @param {VALUE} a The first object to be compared. - * @param {VALUE} b The second object to be compared. - * @return {number} A negative number, zero, or a positive number as the first - * argument is less than, equal to, or greater than the second, - * respectively. - * @template VALUE - */ -goog.array.defaultCompare = function(a, b) { - return a > b ? 1 : a < b ? -1 : 0; -}; - - -/** - * Compares its two arguments for inverse order, using the built in < and > - * operators. - * @param {VALUE} a The first object to be compared. - * @param {VALUE} b The second object to be compared. - * @return {number} A negative number, zero, or a positive number as the first - * argument is greater than, equal to, or less than the second, - * respectively. - * @template VALUE - */ -goog.array.inverseDefaultCompare = function(a, b) { - return -goog.array.defaultCompare(a, b); -}; - - -/** - * Compares its two arguments for equality, using the built in === operator. - * @param {*} a The first object to compare. - * @param {*} b The second object to compare. - * @return {boolean} True if the two arguments are equal, false otherwise. - */ -goog.array.defaultCompareEquality = function(a, b) { - return a === b; -}; - - -/** - * Inserts a value into a sorted array. The array is not modified if the - * value is already present. - * @param {Array<VALUE>|goog.array.ArrayLike} array The array to modify. - * @param {VALUE} value The object to insert. - * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {boolean} True if an element was inserted. - * @template VALUE - */ -goog.array.binaryInsert = function(array, value, opt_compareFn) { - var index = goog.array.binarySearch(array, value, opt_compareFn); - if (index < 0) { - goog.array.insertAt(array, value, -(index + 1)); - return true; - } - return false; -}; - - -/** - * Removes a value from a sorted array. - * @param {!Array<VALUE>|!goog.array.ArrayLike} array The array to modify. - * @param {VALUE} value The object to remove. - * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {boolean} True if an element was removed. - * @template VALUE - */ -goog.array.binaryRemove = function(array, value, opt_compareFn) { - var index = goog.array.binarySearch(array, value, opt_compareFn); - return (index >= 0) ? goog.array.removeAt(array, index) : false; -}; - - -/** - * Splits an array into disjoint buckets according to a splitting function. - * @param {Array<T>} array The array. - * @param {function(this:S, T,number,Array<T>):?} sorter Function to call for - * every element. This takes 3 arguments (the element, the index and the - * array) and must return a valid object key (a string, number, etc), or - * undefined, if that object should not be placed in a bucket. - * @param {S=} opt_obj The object to be used as the value of 'this' within - * sorter. - * @return {!Object} An object, with keys being all of the unique return values - * of sorter, and values being arrays containing the items for - * which the splitter returned that key. - * @template T,S - */ -goog.array.bucket = function(array, sorter, opt_obj) { - var buckets = {}; - - for (var i = 0; i < array.length; i++) { - var value = array[i]; - var key = sorter.call(opt_obj, value, i, array); - if (goog.isDef(key)) { - // Push the value to the right bucket, creating it if necessary. - var bucket = buckets[key] || (buckets[key] = []); - bucket.push(value); - } - } - - return buckets; -}; - - -/** - * Creates a new object built from the provided array and the key-generation - * function. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over - * which to iterate whose elements will be the values in the new object. - * @param {?function(this:S, T, number, ?) : string} keyFunc The function to - * call for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a string that will be used as the - * key for the element in the new object. If the function returns the same - * key for more than one element, the value for that key is - * implementation-defined. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within keyFunc. - * @return {!Object<T>} The new object. - * @template T,S - */ -goog.array.toObject = function(arr, keyFunc, opt_obj) { - var ret = {}; - goog.array.forEach(arr, function(element, index) { - ret[keyFunc.call(opt_obj, element, index, arr)] = element; - }); - return ret; -}; - - -/** - * Creates a range of numbers in an arithmetic progression. - * - * Range takes 1, 2, or 3 arguments: - * <pre> - * range(5) is the same as range(0, 5, 1) and produces [0, 1, 2, 3, 4] - * range(2, 5) is the same as range(2, 5, 1) and produces [2, 3, 4] - * range(-2, -5, -1) produces [-2, -3, -4] - * range(-2, -5, 1) produces [], since stepping by 1 wouldn't ever reach -5. - * </pre> - * - * @param {number} startOrEnd The starting value of the range if an end argument - * is provided. Otherwise, the start value is 0, and this is the end value. - * @param {number=} opt_end The optional end value of the range. - * @param {number=} opt_step The step size between range values. Defaults to 1 - * if opt_step is undefined or 0. - * @return {!Array<number>} An array of numbers for the requested range. May be - * an empty array if adding the step would not converge toward the end - * value. - */ -goog.array.range = function(startOrEnd, opt_end, opt_step) { - var array = []; - var start = 0; - var end = startOrEnd; - var step = opt_step || 1; - if (opt_end !== undefined) { - start = startOrEnd; - end = opt_end; - } - - if (step * (end - start) < 0) { - // Sign mismatch: start + step will never reach the end value. - return []; - } - - if (step > 0) { - for (var i = start; i < end; i += step) { - array.push(i); - } - } else { - for (var i = start; i > end; i += step) { - array.push(i); - } - } - return array; -}; - - -/** - * Returns an array consisting of the given value repeated N times. - * - * @param {VALUE} value The value to repeat. - * @param {number} n The repeat count. - * @return {!Array<VALUE>} An array with the repeated value. - * @template VALUE - */ -goog.array.repeat = function(value, n) { - var array = []; - for (var i = 0; i < n; i++) { - array[i] = value; - } - return array; -}; - - -/** - * Returns an array consisting of every argument with all arrays - * expanded in-place recursively. - * - * @param {...*} var_args The values to flatten. - * @return {!Array<?>} An array containing the flattened values. - */ -goog.array.flatten = function(var_args) { - var CHUNK_SIZE = 8192; - - var result = []; - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (goog.isArray(element)) { - for (var c = 0; c < element.length; c += CHUNK_SIZE) { - var chunk = goog.array.slice(element, c, c + CHUNK_SIZE); - var recurseResult = goog.array.flatten.apply(null, chunk); - for (var r = 0; r < recurseResult.length; r++) { - result.push(recurseResult[r]); - } - } - } else { - result.push(element); - } - } - return result; -}; - - -/** - * Rotates an array in-place. After calling this method, the element at - * index i will be the element previously at index (i - n) % - * array.length, for all values of i between 0 and array.length - 1, - * inclusive. - * - * For example, suppose list comprises [t, a, n, k, s]. After invoking - * rotate(array, 1) (or rotate(array, -4)), array will comprise [s, t, a, n, k]. - * - * @param {!Array<T>} array The array to rotate. - * @param {number} n The amount to rotate. - * @return {!Array<T>} The array. - * @template T - */ -goog.array.rotate = function(array, n) { - goog.asserts.assert(array.length != null); - - if (array.length) { - n %= array.length; - if (n > 0) { - goog.array.ARRAY_PROTOTYPE_.unshift.apply(array, array.splice(-n, n)); - } else if (n < 0) { - goog.array.ARRAY_PROTOTYPE_.push.apply(array, array.splice(0, -n)); - } - } - return array; -}; - - -/** - * Moves one item of an array to a new position keeping the order of the rest - * of the items. Example use case: keeping a list of JavaScript objects - * synchronized with the corresponding list of DOM elements after one of the - * elements has been dragged to a new position. - * @param {!(Array|Arguments|{length:number})} arr The array to modify. - * @param {number} fromIndex Index of the item to move between 0 and - * {@code arr.length - 1}. - * @param {number} toIndex Target index between 0 and {@code arr.length - 1}. - */ -goog.array.moveItem = function(arr, fromIndex, toIndex) { - goog.asserts.assert(fromIndex >= 0 && fromIndex < arr.length); - goog.asserts.assert(toIndex >= 0 && toIndex < arr.length); - // Remove 1 item at fromIndex. - var removedItems = goog.array.ARRAY_PROTOTYPE_.splice.call(arr, fromIndex, 1); - // Insert the removed item at toIndex. - goog.array.ARRAY_PROTOTYPE_.splice.call(arr, toIndex, 0, removedItems[0]); - // We don't use goog.array.insertAt and goog.array.removeAt, because they're - // significantly slower than splice. -}; - - -/** - * Creates a new array for which the element at position i is an array of the - * ith element of the provided arrays. The returned array will only be as long - * as the shortest array provided; additional values are ignored. For example, - * the result of zipping [1, 2] and [3, 4, 5] is [[1,3], [2, 4]]. - * - * This is similar to the zip() function in Python. See {@link - * http://docs.python.org/library/functions.html#zip} - * - * @param {...!goog.array.ArrayLike} var_args Arrays to be combined. - * @return {!Array<!Array<?>>} A new array of arrays created from - * provided arrays. - */ -goog.array.zip = function(var_args) { - if (!arguments.length) { - return []; - } - var result = []; - for (var i = 0; true; i++) { - var value = []; - for (var j = 0; j < arguments.length; j++) { - var arr = arguments[j]; - // If i is larger than the array length, this is the shortest array. - if (i >= arr.length) { - return result; - } - value.push(arr[i]); - } - result.push(value); - } -}; - - -/** - * Shuffles the values in the specified array using the Fisher-Yates in-place - * shuffle (also known as the Knuth Shuffle). By default, calls Math.random() - * and so resets the state of that random number generator. Similarly, may reset - * the state of the any other specified random number generator. - * - * Runtime: O(n) - * - * @param {!Array<?>} arr The array to be shuffled. - * @param {function():number=} opt_randFn Optional random function to use for - * shuffling. - * Takes no arguments, and returns a random number on the interval [0, 1). - * Defaults to Math.random() using JavaScript's built-in Math library. - */ -goog.array.shuffle = function(arr, opt_randFn) { - var randFn = opt_randFn || Math.random; - - for (var i = arr.length - 1; i > 0; i--) { - // Choose a random array index in [0, i] (inclusive with i). - var j = Math.floor(randFn() * (i + 1)); - - var tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } -}; - - -/** - * Returns a new array of elements from arr, based on the indexes of elements - * provided by index_arr. For example, the result of index copying - * ['a', 'b', 'c'] with index_arr [1,0,0,2] is ['b', 'a', 'a', 'c']. - * - * @param {!Array<T>} arr The array to get a indexed copy from. - * @param {!Array<number>} index_arr An array of indexes to get from arr. - * @return {!Array<T>} A new array of elements from arr in index_arr order. - * @template T - */ -goog.array.copyByIndex = function(arr, index_arr) { - var result = []; - goog.array.forEach(index_arr, function(index) { - result.push(arr[index]); - }); - return result; -}; - -goog.provide('ol.array'); - -goog.require('goog.array'); -goog.require('goog.asserts'); - - -/** - * @param {Array.<number>} arr Array. - * @param {number} target Target. - * @return {number} Index. - */ -ol.array.binaryFindNearest = function(arr, target) { - var index = goog.array.binarySearch(arr, target, - /** - * @param {number} a A. - * @param {number} b B. - * @return {number} b minus a. - */ - function(a, b) { - return b - a; - }); - if (index >= 0) { - return index; - } else if (index == -1) { - return 0; - } else if (index == -arr.length - 1) { - return arr.length - 1; - } else { - var left = -index - 2; - var right = -index - 1; - if (arr[left] - target < target - arr[right]) { - return left; - } else { - return right; - } - } -}; - - -/** - * Whether the array contains the given object. - * @param {Array.<*>} arr The array to test for the presence of the element. - * @param {*} obj The object for which to test. - * @return {boolean} The object is in the array. - */ -ol.array.includes = function(arr, obj) { - return arr.indexOf(obj) >= 0; -}; - - -/** - * @param {Array.<number>} arr Array. - * @param {number} target Target. - * @param {number} direction 0 means return the nearest, > 0 - * means return the largest nearest, < 0 means return the - * smallest nearest. - * @return {number} Index. - */ -ol.array.linearFindNearest = function(arr, target, direction) { - var n = arr.length; - if (arr[0] <= target) { - return 0; - } else if (target <= arr[n - 1]) { - return n - 1; - } else { - var i; - if (direction > 0) { - for (i = 1; i < n; ++i) { - if (arr[i] < target) { - return i - 1; - } - } - } else if (direction < 0) { - for (i = 1; i < n; ++i) { - if (arr[i] <= target) { - return i; - } - } - } else { - for (i = 1; i < n; ++i) { - if (arr[i] == target) { - return i; - } else if (arr[i] < target) { - if (arr[i - 1] - target < target - arr[i]) { - return i - 1; - } else { - return i; - } - } - } - } - // We should never get here, but the compiler complains - // if it finds a path for which no number is returned. - goog.asserts.fail(); - return n - 1; - } -}; - - -/** - * @param {Array.<*>} arr Array. - * @param {number} begin Begin index. - * @param {number} end End index. - */ -ol.array.reverseSubArray = function(arr, begin, end) { - goog.asserts.assert(begin >= 0, - 'Array begin index should be equal to or greater than 0'); - goog.asserts.assert(end < arr.length, - 'Array end index should be less than the array length'); - while (begin < end) { - var tmp = arr[begin]; - arr[begin] = arr[end]; - arr[end] = tmp; - ++begin; - --end; - } -}; - -goog.provide('ol.ResolutionConstraint'); -goog.provide('ol.ResolutionConstraintType'); - -goog.require('ol.array'); -goog.require('ol.math'); - - -/** - * @typedef {function((number|undefined), number, number): (number|undefined)} - */ -ol.ResolutionConstraintType; - - -/** - * @param {Array.<number>} resolutions Resolutions. - * @return {ol.ResolutionConstraintType} Zoom function. - */ -ol.ResolutionConstraint.createSnapToResolutions = - function(resolutions) { - return ( - /** - * @param {number|undefined} resolution Resolution. - * @param {number} delta Delta. - * @param {number} direction Direction. - * @return {number|undefined} Resolution. - */ - function(resolution, delta, direction) { - if (resolution !== undefined) { - var z = - ol.array.linearFindNearest(resolutions, resolution, direction); - z = ol.math.clamp(z + delta, 0, resolutions.length - 1); - return resolutions[z]; - } else { - return undefined; - } - }); -}; - - -/** - * @param {number} power Power. - * @param {number} maxResolution Maximum resolution. - * @param {number=} opt_maxLevel Maximum level. - * @return {ol.ResolutionConstraintType} Zoom function. - */ -ol.ResolutionConstraint.createSnapToPower = - function(power, maxResolution, opt_maxLevel) { - return ( - /** - * @param {number|undefined} resolution Resolution. - * @param {number} delta Delta. - * @param {number} direction Direction. - * @return {number|undefined} Resolution. - */ - function(resolution, delta, direction) { - if (resolution !== undefined) { - var offset; - if (direction > 0) { - offset = 0; - } else if (direction < 0) { - offset = 1; - } else { - offset = 0.5; - } - var oldLevel = Math.floor( - Math.log(maxResolution / resolution) / Math.log(power) + offset); - var newLevel = Math.max(oldLevel + delta, 0); - if (opt_maxLevel !== undefined) { - newLevel = Math.min(newLevel, opt_maxLevel); - } - return maxResolution / Math.pow(power, newLevel); - } else { - return undefined; - } - }); -}; - -goog.provide('ol.RotationConstraint'); -goog.provide('ol.RotationConstraintType'); - -goog.require('ol.math'); - - -/** - * @typedef {function((number|undefined), number): (number|undefined)} - */ -ol.RotationConstraintType; - - -/** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. - */ -ol.RotationConstraint.disable = function(rotation, delta) { - if (rotation !== undefined) { - return 0; - } else { - return undefined; - } -}; - - -/** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. - */ -ol.RotationConstraint.none = function(rotation, delta) { - if (rotation !== undefined) { - return rotation + delta; - } else { - return undefined; - } -}; - - -/** - * @param {number} n N. - * @return {ol.RotationConstraintType} Rotation constraint. - */ -ol.RotationConstraint.createSnapToN = function(n) { - var theta = 2 * Math.PI / n; - return ( - /** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. - */ - function(rotation, delta) { - if (rotation !== undefined) { - rotation = Math.floor((rotation + delta) / theta + 0.5) * theta; - return rotation; - } else { - return undefined; - } - }); -}; - - -/** - * @param {number=} opt_tolerance Tolerance. - * @return {ol.RotationConstraintType} Rotation constraint. - */ -ol.RotationConstraint.createSnapToZero = function(opt_tolerance) { - var tolerance = opt_tolerance || ol.math.toRadians(5); - return ( - /** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. - */ - function(rotation, delta) { - if (rotation !== undefined) { - if (Math.abs(rotation + delta) <= tolerance) { - return 0; - } else { - return rotation + delta; - } - } else { - return undefined; - } - }); -}; - -goog.provide('ol.Constraints'); - -goog.require('ol.CenterConstraintType'); -goog.require('ol.ResolutionConstraintType'); -goog.require('ol.RotationConstraintType'); - - - -/** - * @constructor - * @param {ol.CenterConstraintType} centerConstraint Center constraint. - * @param {ol.ResolutionConstraintType} resolutionConstraint - * Resolution constraint. - * @param {ol.RotationConstraintType} rotationConstraint - * Rotation constraint. - */ -ol.Constraints = - function(centerConstraint, resolutionConstraint, rotationConstraint) { - - /** - * @type {ol.CenterConstraintType} - */ - this.center = centerConstraint; - - /** - * @type {ol.ResolutionConstraintType} - */ - this.resolution = resolutionConstraint; - - /** - * @type {ol.RotationConstraintType} - */ - this.rotation = rotationConstraint; - -}; - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A global registry for entry points into a program, - * so that they can be instrumented. Each module should register their - * entry points with this registry. Designed to be compiled out - * if no instrumentation is requested. - * - * Entry points may be registered before or after a call to - * goog.debug.entryPointRegistry.monitorAll. If an entry point is registered - * later, the existing monitor will instrument the new entry point. - * - * @author nicksantos@google.com (Nick Santos) - */ - -goog.provide('goog.debug.EntryPointMonitor'); -goog.provide('goog.debug.entryPointRegistry'); - -goog.require('goog.asserts'); - - - -/** - * @interface - */ -goog.debug.EntryPointMonitor = function() {}; - - -/** - * Instruments a function. - * - * @param {!Function} fn A function to instrument. - * @return {!Function} The instrumented function. - */ -goog.debug.EntryPointMonitor.prototype.wrap; - - -/** - * Try to remove an instrumentation wrapper created by this monitor. - * If the function passed to unwrap is not a wrapper created by this - * monitor, then we will do nothing. - * - * Notice that some wrappers may not be unwrappable. For example, if other - * monitors have applied their own wrappers, then it will be impossible to - * unwrap them because their wrappers will have captured our wrapper. - * - * So it is important that entry points are unwrapped in the reverse - * order that they were wrapped. - * - * @param {!Function} fn A function to unwrap. - * @return {!Function} The unwrapped function, or {@code fn} if it was not - * a wrapped function created by this monitor. - */ -goog.debug.EntryPointMonitor.prototype.unwrap; - - -/** - * An array of entry point callbacks. - * @type {!Array<function(!Function)>} - * @private - */ -goog.debug.entryPointRegistry.refList_ = []; - - -/** - * Monitors that should wrap all the entry points. - * @type {!Array<!goog.debug.EntryPointMonitor>} - * @private - */ -goog.debug.entryPointRegistry.monitors_ = []; - - -/** - * Whether goog.debug.entryPointRegistry.monitorAll has ever been called. - * Checking this allows the compiler to optimize out the registrations. - * @type {boolean} - * @private - */ -goog.debug.entryPointRegistry.monitorsMayExist_ = false; - - -/** - * Register an entry point with this module. - * - * The entry point will be instrumented when a monitor is passed to - * goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the - * entry point is instrumented immediately. - * - * @param {function(!Function)} callback A callback function which is called - * with a transforming function to instrument the entry point. The callback - * is responsible for wrapping the relevant entry point with the - * transforming function. - */ -goog.debug.entryPointRegistry.register = function(callback) { - // Don't use push(), so that this can be compiled out. - goog.debug.entryPointRegistry.refList_[ - goog.debug.entryPointRegistry.refList_.length] = callback; - // If no one calls monitorAll, this can be compiled out. - if (goog.debug.entryPointRegistry.monitorsMayExist_) { - var monitors = goog.debug.entryPointRegistry.monitors_; - for (var i = 0; i < monitors.length; i++) { - callback(goog.bind(monitors[i].wrap, monitors[i])); - } - } -}; - - -/** - * Configures a monitor to wrap all entry points. - * - * Entry points that have already been registered are immediately wrapped by - * the monitor. When an entry point is registered in the future, it will also - * be wrapped by the monitor when it is registered. - * - * @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor. - */ -goog.debug.entryPointRegistry.monitorAll = function(monitor) { - goog.debug.entryPointRegistry.monitorsMayExist_ = true; - var transformer = goog.bind(monitor.wrap, monitor); - for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) { - goog.debug.entryPointRegistry.refList_[i](transformer); - } - goog.debug.entryPointRegistry.monitors_.push(monitor); -}; - - -/** - * Try to unmonitor all the entry points that have already been registered. If - * an entry point is registered in the future, it will not be wrapped by the - * monitor when it is registered. Note that this may fail if the entry points - * have additional wrapping. - * - * @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap - * the entry points. - * @throws {Error} If the monitor is not the most recently configured monitor. - */ -goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) { - var monitors = goog.debug.entryPointRegistry.monitors_; - goog.asserts.assert(monitor == monitors[monitors.length - 1], - 'Only the most recent monitor can be unwrapped.'); - var transformer = goog.bind(monitor.unwrap, monitor); - for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) { - goog.debug.entryPointRegistry.refList_[i](transformer); - } - monitors.length--; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities used by goog.labs.userAgent tools. These functions - * should not be used outside of goog.labs.userAgent.*. - * - * - * @author nnaze@google.com (Nathan Naze) - */ - -goog.provide('goog.labs.userAgent.util'); - -goog.require('goog.string'); - - -/** - * Gets the native userAgent string from navigator if it exists. - * If navigator or navigator.userAgent string is missing, returns an empty - * string. - * @return {string} - * @private - */ -goog.labs.userAgent.util.getNativeUserAgentString_ = function() { - var navigator = goog.labs.userAgent.util.getNavigator_(); - if (navigator) { - var userAgent = navigator.userAgent; - if (userAgent) { - return userAgent; - } - } - return ''; -}; - - -/** - * Getter for the native navigator. - * This is a separate function so it can be stubbed out in testing. - * @return {Navigator} - * @private - */ -goog.labs.userAgent.util.getNavigator_ = function() { - return goog.global.navigator; -}; - - -/** - * A possible override for applications which wish to not check - * navigator.userAgent but use a specified value for detection instead. - * @private {string} - */ -goog.labs.userAgent.util.userAgent_ = - goog.labs.userAgent.util.getNativeUserAgentString_(); - - -/** - * Applications may override browser detection on the built in - * navigator.userAgent object by setting this string. Set to null to use the - * browser object instead. - * @param {?string=} opt_userAgent The User-Agent override. - */ -goog.labs.userAgent.util.setUserAgent = function(opt_userAgent) { - goog.labs.userAgent.util.userAgent_ = opt_userAgent || - goog.labs.userAgent.util.getNativeUserAgentString_(); -}; - - -/** - * @return {string} The user agent string. - */ -goog.labs.userAgent.util.getUserAgent = function() { - return goog.labs.userAgent.util.userAgent_; -}; - - -/** - * @param {string} str - * @return {boolean} Whether the user agent contains the given string, ignoring - * case. - */ -goog.labs.userAgent.util.matchUserAgent = function(str) { - var userAgent = goog.labs.userAgent.util.getUserAgent(); - return goog.string.contains(userAgent, str); -}; - - -/** - * @param {string} str - * @return {boolean} Whether the user agent contains the given string. - */ -goog.labs.userAgent.util.matchUserAgentIgnoreCase = function(str) { - var userAgent = goog.labs.userAgent.util.getUserAgent(); - return goog.string.caseInsensitiveContains(userAgent, str); -}; - - -/** - * Parses the user agent into tuples for each section. - * @param {string} userAgent - * @return {!Array<!Array<string>>} Tuples of key, version, and the contents - * of the parenthetical. - */ -goog.labs.userAgent.util.extractVersionTuples = function(userAgent) { - // Matches each section of a user agent string. - // Example UA: - // Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) - // AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405 - // This has three version tuples: Mozilla, AppleWebKit, and Mobile. - - var versionRegExp = new RegExp( - // Key. Note that a key may have a space. - // (i.e. 'Mobile Safari' in 'Mobile Safari/5.0') - '(\\w[\\w ]+)' + - - '/' + // slash - '([^\\s]+)' + // version (i.e. '5.0b') - '\\s*' + // whitespace - '(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched. - 'g'); - - var data = []; - var match; - - // Iterate and collect the version tuples. Each iteration will be the - // next regex match. - while (match = versionRegExp.exec(userAgent)) { - data.push([ - match[1], // key - match[2], // value - // || undefined as this is not undefined in IE7 and IE8 - match[3] || undefined // info - ]); - } - - return data; -}; - - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for manipulating objects/maps/hashes. - * @author arv@google.com (Erik Arvidsson) - */ - -goog.provide('goog.object'); - - -/** - * Calls a function for each element in an object/map/hash. - * - * @param {Object<K,V>} obj The object over which to iterate. - * @param {function(this:T,V,?,Object<K,V>):?} f The function to call - * for every element. This function takes 3 arguments (the value, the - * key and the object) and the return value is ignored. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @template T,K,V - */ -goog.object.forEach = function(obj, f, opt_obj) { - for (var key in obj) { - f.call(opt_obj, obj[key], key, obj); - } -}; - - -/** - * Calls a function for each element in an object/map/hash. If that call returns - * true, adds the element to a new object. - * - * @param {Object<K,V>} obj The object over which to iterate. - * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to call - * for every element. This - * function takes 3 arguments (the value, the key and the object) - * and should return a boolean. If the return value is true the - * element is added to the result object. If it is false the - * element is not included. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {!Object<K,V>} a new object in which only elements that passed the - * test are present. - * @template T,K,V - */ -goog.object.filter = function(obj, f, opt_obj) { - var res = {}; - for (var key in obj) { - if (f.call(opt_obj, obj[key], key, obj)) { - res[key] = obj[key]; - } - } - return res; -}; - - -/** - * For every element in an object/map/hash calls a function and inserts the - * result into a new object. - * - * @param {Object<K,V>} obj The object over which to iterate. - * @param {function(this:T,V,?,Object<K,V>):R} f The function to call - * for every element. This function - * takes 3 arguments (the value, the key and the object) - * and should return something. The result will be inserted - * into a new object. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {!Object<K,R>} a new object with the results from f. - * @template T,K,V,R - */ -goog.object.map = function(obj, f, opt_obj) { - var res = {}; - for (var key in obj) { - res[key] = f.call(opt_obj, obj[key], key, obj); - } - return res; -}; - - -/** - * Calls a function for each element in an object/map/hash. If any - * call returns true, returns true (without checking the rest). If - * all calls return false, returns false. - * - * @param {Object<K,V>} obj The object to check. - * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to - * call for every element. This function - * takes 3 arguments (the value, the key and the object) and should - * return a boolean. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {boolean} true if any element passes the test. - * @template T,K,V - */ -goog.object.some = function(obj, f, opt_obj) { - for (var key in obj) { - if (f.call(opt_obj, obj[key], key, obj)) { - return true; - } - } - return false; -}; - - -/** - * Calls a function for each element in an object/map/hash. If - * all calls return true, returns true. If any call returns false, returns - * false at this point and does not continue to check the remaining elements. - * - * @param {Object<K,V>} obj The object to check. - * @param {?function(this:T,V,?,Object<K,V>):boolean} f The function to - * call for every element. This function - * takes 3 arguments (the value, the key and the object) and should - * return a boolean. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {boolean} false if any element fails the test. - * @template T,K,V - */ -goog.object.every = function(obj, f, opt_obj) { - for (var key in obj) { - if (!f.call(opt_obj, obj[key], key, obj)) { - return false; - } - } - return true; -}; - - -/** - * Returns the number of key-value pairs in the object map. - * - * @param {Object} obj The object for which to get the number of key-value - * pairs. - * @return {number} The number of key-value pairs in the object map. - */ -goog.object.getCount = function(obj) { - // JS1.5 has __count__ but it has been deprecated so it raises a warning... - // in other words do not use. Also __count__ only includes the fields on the - // actual object and not in the prototype chain. - var rv = 0; - for (var key in obj) { - rv++; - } - return rv; -}; - - -/** - * Returns one key from the object map, if any exists. - * For map literals the returned key will be the first one in most of the - * browsers (a know exception is Konqueror). - * - * @param {Object} obj The object to pick a key from. - * @return {string|undefined} The key or undefined if the object is empty. - */ -goog.object.getAnyKey = function(obj) { - for (var key in obj) { - return key; - } -}; - - -/** - * Returns one value from the object map, if any exists. - * For map literals the returned value will be the first one in most of the - * browsers (a know exception is Konqueror). - * - * @param {Object<K,V>} obj The object to pick a value from. - * @return {V|undefined} The value or undefined if the object is empty. - * @template K,V - */ -goog.object.getAnyValue = function(obj) { - for (var key in obj) { - return obj[key]; - } -}; - - -/** - * Whether the object/hash/map contains the given object as a value. - * An alias for goog.object.containsValue(obj, val). - * - * @param {Object<K,V>} obj The object in which to look for val. - * @param {V} val The object for which to check. - * @return {boolean} true if val is present. - * @template K,V - */ -goog.object.contains = function(obj, val) { - return goog.object.containsValue(obj, val); -}; - - -/** - * Returns the values of the object/map/hash. - * - * @param {Object<K,V>} obj The object from which to get the values. - * @return {!Array<V>} The values in the object/map/hash. - * @template K,V - */ -goog.object.getValues = function(obj) { - var res = []; - var i = 0; - for (var key in obj) { - res[i++] = obj[key]; - } - return res; -}; - - -/** - * Returns the keys of the object/map/hash. - * - * @param {Object} obj The object from which to get the keys. - * @return {!Array<string>} Array of property keys. - */ -goog.object.getKeys = function(obj) { - var res = []; - var i = 0; - for (var key in obj) { - res[i++] = key; - } - return res; -}; - - -/** - * Get a value from an object multiple levels deep. This is useful for - * pulling values from deeply nested objects, such as JSON responses. - * Example usage: getValueByKeys(jsonObj, 'foo', 'entries', 3) - * - * @param {!Object} obj An object to get the value from. Can be array-like. - * @param {...(string|number|!Array<number|string>)} var_args A number of keys - * (as strings, or numbers, for array-like objects). Can also be - * specified as a single array of keys. - * @return {*} The resulting value. If, at any point, the value for a key - * is undefined, returns undefined. - */ -goog.object.getValueByKeys = function(obj, var_args) { - var isArrayLike = goog.isArrayLike(var_args); - var keys = isArrayLike ? var_args : arguments; - - // Start with the 2nd parameter for the variable parameters syntax. - for (var i = isArrayLike ? 0 : 1; i < keys.length; i++) { - obj = obj[keys[i]]; - if (!goog.isDef(obj)) { - break; - } - } - - return obj; -}; - - -/** - * Whether the object/map/hash contains the given key. - * - * @param {Object} obj The object in which to look for key. - * @param {*} key The key for which to check. - * @return {boolean} true If the map contains the key. - */ -goog.object.containsKey = function(obj, key) { - return key in obj; -}; - - -/** - * Whether the object/map/hash contains the given value. This is O(n). - * - * @param {Object<K,V>} obj The object in which to look for val. - * @param {V} val The value for which to check. - * @return {boolean} true If the map contains the value. - * @template K,V - */ -goog.object.containsValue = function(obj, val) { - for (var key in obj) { - if (obj[key] == val) { - return true; - } - } - return false; -}; - - -/** - * Searches an object for an element that satisfies the given condition and - * returns its key. - * @param {Object<K,V>} obj The object to search in. - * @param {function(this:T,V,string,Object<K,V>):boolean} f The - * function to call for every element. Takes 3 arguments (the value, - * the key and the object) and should return a boolean. - * @param {T=} opt_this An optional "this" context for the function. - * @return {string|undefined} The key of an element for which the function - * returns true or undefined if no such element is found. - * @template T,K,V - */ -goog.object.findKey = function(obj, f, opt_this) { - for (var key in obj) { - if (f.call(opt_this, obj[key], key, obj)) { - return key; - } - } - return undefined; -}; - - -/** - * Searches an object for an element that satisfies the given condition and - * returns its value. - * @param {Object<K,V>} obj The object to search in. - * @param {function(this:T,V,string,Object<K,V>):boolean} f The function - * to call for every element. Takes 3 arguments (the value, the key - * and the object) and should return a boolean. - * @param {T=} opt_this An optional "this" context for the function. - * @return {V} The value of an element for which the function returns true or - * undefined if no such element is found. - * @template T,K,V - */ -goog.object.findValue = function(obj, f, opt_this) { - var key = goog.object.findKey(obj, f, opt_this); - return key && obj[key]; -}; - - -/** - * Whether the object/map/hash is empty. - * - * @param {Object} obj The object to test. - * @return {boolean} true if obj is empty. - */ -goog.object.isEmpty = function(obj) { - for (var key in obj) { - return false; - } - return true; -}; - - -/** - * Removes all key value pairs from the object/map/hash. - * - * @param {Object} obj The object to clear. - */ -goog.object.clear = function(obj) { - for (var i in obj) { - delete obj[i]; - } -}; - - -/** - * Removes a key-value pair based on the key. - * - * @param {Object} obj The object from which to remove the key. - * @param {*} key The key to remove. - * @return {boolean} Whether an element was removed. - */ -goog.object.remove = function(obj, key) { - var rv; - if ((rv = key in obj)) { - delete obj[key]; - } - return rv; -}; - - -/** - * Adds a key-value pair to the object. Throws an exception if the key is - * already in use. Use set if you want to change an existing pair. - * - * @param {Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {V} val The value to add. - * @template K,V - */ -goog.object.add = function(obj, key, val) { - if (key in obj) { - throw Error('The object already contains the key "' + key + '"'); - } - goog.object.set(obj, key, val); -}; - - -/** - * Returns the value for the given key. - * - * @param {Object<K,V>} obj The object from which to get the value. - * @param {string} key The key for which to get the value. - * @param {R=} opt_val The value to return if no item is found for the given - * key (default is undefined). - * @return {V|R|undefined} The value for the given key. - * @template K,V,R - */ -goog.object.get = function(obj, key, opt_val) { - if (key in obj) { - return obj[key]; - } - return opt_val; -}; - - -/** - * Adds a key-value pair to the object/map/hash. - * - * @param {Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {V} value The value to add. - * @template K,V - */ -goog.object.set = function(obj, key, value) { - obj[key] = value; -}; - - -/** - * Adds a key-value pair to the object/map/hash if it doesn't exist yet. - * - * @param {Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {V} value The value to add if the key wasn't present. - * @return {V} The value of the entry at the end of the function. - * @template K,V - */ -goog.object.setIfUndefined = function(obj, key, value) { - return key in obj ? obj[key] : (obj[key] = value); -}; - - -/** - * Sets a key and value to an object if the key is not set. The value will be - * the return value of the given function. If the key already exists, the - * object will not be changed and the function will not be called (the function - * will be lazily evaluated -- only called if necessary). - * - * This function is particularly useful for use with a map used a as a cache. - * - * @param {!Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {function():V} f The value to add if the key wasn't present. - * @return {V} The value of the entry at the end of the function. - * @template K,V - */ -goog.object.setWithReturnValueIfNotSet = function(obj, key, f) { - if (key in obj) { - return obj[key]; - } - - var val = f(); - obj[key] = val; - return val; -}; - - -/** - * Compares two objects for equality using === on the values. - * - * @param {!Object<K,V>} a - * @param {!Object<K,V>} b - * @return {boolean} - * @template K,V - */ -goog.object.equals = function(a, b) { - for (var k in a) { - if (!(k in b) || a[k] !== b[k]) { - return false; - } - } - for (var k in b) { - if (!(k in a)) { - return false; - } - } - return true; -}; - - -/** - * Does a flat clone of the object. - * - * @param {Object<K,V>} obj Object to clone. - * @return {!Object<K,V>} Clone of the input object. - * @template K,V - */ -goog.object.clone = function(obj) { - // We cannot use the prototype trick because a lot of methods depend on where - // the actual key is set. - - var res = {}; - for (var key in obj) { - res[key] = obj[key]; - } - return res; - // We could also use goog.mixin but I wanted this to be independent from that. -}; - - -/** - * Clones a value. The input may be an Object, Array, or basic type. Objects and - * arrays will be cloned recursively. - * - * WARNINGS: - * <code>goog.object.unsafeClone</code> does not detect reference loops. Objects - * that refer to themselves will cause infinite recursion. - * - * <code>goog.object.unsafeClone</code> is unaware of unique identifiers, and - * copies UIDs created by <code>getUid</code> into cloned results. - * - * @param {*} obj The value to clone. - * @return {*} A clone of the input value. - */ -goog.object.unsafeClone = function(obj) { - var type = goog.typeOf(obj); - if (type == 'object' || type == 'array') { - if (goog.isFunction(obj.clone)) { - return obj.clone(); - } - var clone = type == 'array' ? [] : {}; - for (var key in obj) { - clone[key] = goog.object.unsafeClone(obj[key]); - } - return clone; - } - - return obj; -}; - - -/** - * Returns a new object in which all the keys and values are interchanged - * (keys become values and values become keys). If multiple keys map to the - * same value, the chosen transposed value is implementation-dependent. - * - * @param {Object} obj The object to transpose. - * @return {!Object} The transposed object. - */ -goog.object.transpose = function(obj) { - var transposed = {}; - for (var key in obj) { - transposed[obj[key]] = key; - } - return transposed; -}; - - -/** - * The names of the fields that are defined on Object.prototype. - * @type {Array<string>} - * @private - */ -goog.object.PROTOTYPE_FIELDS_ = [ - 'constructor', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'toLocaleString', - 'toString', - 'valueOf' -]; - - -/** - * Extends an object with another object. - * This operates 'in-place'; it does not create a new Object. - * - * Example: - * var o = {}; - * goog.object.extend(o, {a: 0, b: 1}); - * o; // {a: 0, b: 1} - * goog.object.extend(o, {b: 2, c: 3}); - * o; // {a: 0, b: 2, c: 3} - * - * @param {Object} target The object to modify. Existing properties will be - * overwritten if they are also present in one of the objects in - * {@code var_args}. - * @param {...Object} var_args The objects from which values will be copied. - */ -goog.object.extend = function(target, var_args) { - var key, source; - for (var i = 1; i < arguments.length; i++) { - source = arguments[i]; - for (key in source) { - target[key] = source[key]; - } - - // For IE the for-in-loop does not contain any properties that are not - // enumerable on the prototype object (for example isPrototypeOf from - // Object.prototype) and it will also not include 'replace' on objects that - // extend String and change 'replace' (not that it is common for anyone to - // extend anything except Object). - - for (var j = 0; j < goog.object.PROTOTYPE_FIELDS_.length; j++) { - key = goog.object.PROTOTYPE_FIELDS_[j]; - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } -}; - - -/** - * Creates a new object built from the key-value pairs provided as arguments. - * @param {...*} var_args If only one argument is provided and it is an array - * then this is used as the arguments, otherwise even arguments are used as - * the property names and odd arguments are used as the property values. - * @return {!Object} The new object. - * @throws {Error} If there are uneven number of arguments or there is only one - * non array argument. - */ -goog.object.create = function(var_args) { - var argLength = arguments.length; - if (argLength == 1 && goog.isArray(arguments[0])) { - return goog.object.create.apply(null, arguments[0]); - } - - if (argLength % 2) { - throw Error('Uneven number of arguments'); - } - - var rv = {}; - for (var i = 0; i < argLength; i += 2) { - rv[arguments[i]] = arguments[i + 1]; - } - return rv; -}; - - -/** - * Creates a new object where the property names come from the arguments but - * the value is always set to true - * @param {...*} var_args If only one argument is provided and it is an array - * then this is used as the arguments, otherwise the arguments are used - * as the property names. - * @return {!Object} The new object. - */ -goog.object.createSet = function(var_args) { - var argLength = arguments.length; - if (argLength == 1 && goog.isArray(arguments[0])) { - return goog.object.createSet.apply(null, arguments[0]); - } - - var rv = {}; - for (var i = 0; i < argLength; i++) { - rv[arguments[i]] = true; - } - return rv; -}; - - -/** - * Creates an immutable view of the underlying object, if the browser - * supports immutable objects. - * - * In default mode, writes to this view will fail silently. In strict mode, - * they will throw an error. - * - * @param {!Object<K,V>} obj An object. - * @return {!Object<K,V>} An immutable view of that object, or the - * original object if this browser does not support immutables. - * @template K,V - */ -goog.object.createImmutableView = function(obj) { - var result = obj; - if (Object.isFrozen && !Object.isFrozen(obj)) { - result = Object.create(obj); - Object.freeze(result); - } - return result; -}; - - -/** - * @param {!Object} obj An object. - * @return {boolean} Whether this is an immutable view of the object. - */ -goog.object.isImmutableView = function(obj) { - return !!Object.isFrozen && Object.isFrozen(obj); -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Closure user agent detection (Browser). - * @see <a href="http://www.useragentstring.com/">User agent strings</a> - * For more information on rendering engine, platform, or device see the other - * sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform, - * goog.labs.userAgent.device respectively.) - * - * @author martone@google.com (Andy Martone) - */ - -goog.provide('goog.labs.userAgent.browser'); - -goog.require('goog.array'); -goog.require('goog.labs.userAgent.util'); -goog.require('goog.object'); -goog.require('goog.string'); - - -// TODO(nnaze): Refactor to remove excessive exclusion logic in matching -// functions. - - -/** - * @return {boolean} Whether the user's browser is Opera. - * @private - */ -goog.labs.userAgent.browser.matchOpera_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Opera') || - goog.labs.userAgent.util.matchUserAgent('OPR'); -}; - - -/** - * @return {boolean} Whether the user's browser is IE. - * @private - */ -goog.labs.userAgent.browser.matchIE_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Trident') || - goog.labs.userAgent.util.matchUserAgent('MSIE'); -}; - - -/** - * @return {boolean} Whether the user's browser is Edge. - * @private - */ -goog.labs.userAgent.browser.matchEdge_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Edge'); -}; - - -/** - * @return {boolean} Whether the user's browser is Firefox. - * @private - */ -goog.labs.userAgent.browser.matchFirefox_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Firefox'); -}; - - -/** - * @return {boolean} Whether the user's browser is Safari. - * @private - */ -goog.labs.userAgent.browser.matchSafari_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Safari') && - !(goog.labs.userAgent.browser.matchChrome_() || - goog.labs.userAgent.browser.matchCoast_() || - goog.labs.userAgent.browser.matchOpera_() || - goog.labs.userAgent.browser.matchEdge_() || - goog.labs.userAgent.browser.isSilk() || - goog.labs.userAgent.util.matchUserAgent('Android')); -}; - - -/** - * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based - * iOS browser). - * @private - */ -goog.labs.userAgent.browser.matchCoast_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Coast'); -}; - - -/** - * @return {boolean} Whether the user's browser is iOS Webview. - * @private - */ -goog.labs.userAgent.browser.matchIosWebview_ = function() { - // iOS Webview does not show up as Chrome or Safari. Also check for Opera's - // WebKit-based iOS browser, Coast. - return (goog.labs.userAgent.util.matchUserAgent('iPad') || - goog.labs.userAgent.util.matchUserAgent('iPhone')) && - !goog.labs.userAgent.browser.matchSafari_() && - !goog.labs.userAgent.browser.matchChrome_() && - !goog.labs.userAgent.browser.matchCoast_() && - goog.labs.userAgent.util.matchUserAgent('AppleWebKit'); -}; - - -/** - * @return {boolean} Whether the user's browser is Chrome. - * @private - */ -goog.labs.userAgent.browser.matchChrome_ = function() { - return (goog.labs.userAgent.util.matchUserAgent('Chrome') || - goog.labs.userAgent.util.matchUserAgent('CriOS')) && - !goog.labs.userAgent.browser.matchOpera_() && - !goog.labs.userAgent.browser.matchEdge_(); -}; - - -/** - * @return {boolean} Whether the user's browser is the Android browser. - * @private - */ -goog.labs.userAgent.browser.matchAndroidBrowser_ = function() { - // Android can appear in the user agent string for Chrome on Android. - // This is not the Android standalone browser if it does. - return goog.labs.userAgent.util.matchUserAgent('Android') && - !(goog.labs.userAgent.browser.isChrome() || - goog.labs.userAgent.browser.isFirefox() || - goog.labs.userAgent.browser.isOpera() || - goog.labs.userAgent.browser.isSilk()); -}; - - -/** - * @return {boolean} Whether the user's browser is Opera. - */ -goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_; - - -/** - * @return {boolean} Whether the user's browser is IE. - */ -goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_; - - -/** - * @return {boolean} Whether the user's browser is Edge. - */ -goog.labs.userAgent.browser.isEdge = goog.labs.userAgent.browser.matchEdge_; - - -/** - * @return {boolean} Whether the user's browser is Firefox. - */ -goog.labs.userAgent.browser.isFirefox = - goog.labs.userAgent.browser.matchFirefox_; - - -/** - * @return {boolean} Whether the user's browser is Safari. - */ -goog.labs.userAgent.browser.isSafari = - goog.labs.userAgent.browser.matchSafari_; - - -/** - * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based - * iOS browser). - */ -goog.labs.userAgent.browser.isCoast = - goog.labs.userAgent.browser.matchCoast_; - - -/** - * @return {boolean} Whether the user's browser is iOS Webview. - */ -goog.labs.userAgent.browser.isIosWebview = - goog.labs.userAgent.browser.matchIosWebview_; - - -/** - * @return {boolean} Whether the user's browser is Chrome. - */ -goog.labs.userAgent.browser.isChrome = - goog.labs.userAgent.browser.matchChrome_; - - -/** - * @return {boolean} Whether the user's browser is the Android browser. - */ -goog.labs.userAgent.browser.isAndroidBrowser = - goog.labs.userAgent.browser.matchAndroidBrowser_; - - -/** - * For more information, see: - * http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html - * @return {boolean} Whether the user's browser is Silk. - */ -goog.labs.userAgent.browser.isSilk = function() { - return goog.labs.userAgent.util.matchUserAgent('Silk'); -}; - - -/** - * @return {string} The browser version or empty string if version cannot be - * determined. Note that for Internet Explorer, this returns the version of - * the browser, not the version of the rendering engine. (IE 8 in - * compatibility mode will return 8.0 rather than 7.0. To determine the - * rendering engine version, look at document.documentMode instead. See - * http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more - * details.) - */ -goog.labs.userAgent.browser.getVersion = function() { - var userAgentString = goog.labs.userAgent.util.getUserAgent(); - // Special case IE since IE's version is inside the parenthesis and - // without the '/'. - if (goog.labs.userAgent.browser.isIE()) { - return goog.labs.userAgent.browser.getIEVersion_(userAgentString); - } - - var versionTuples = goog.labs.userAgent.util.extractVersionTuples( - userAgentString); - - // Construct a map for easy lookup. - var versionMap = {}; - goog.array.forEach(versionTuples, function(tuple) { - // Note that the tuple is of length three, but we only care about the - // first two. - var key = tuple[0]; - var value = tuple[1]; - versionMap[key] = value; - }); - - var versionMapHasKey = goog.partial(goog.object.containsKey, versionMap); - - // Gives the value with the first key it finds, otherwise empty string. - function lookUpValueWithKeys(keys) { - var key = goog.array.find(keys, versionMapHasKey); - return versionMap[key] || ''; - } - - // Check Opera before Chrome since Opera 15+ has "Chrome" in the string. - // See - // http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond - if (goog.labs.userAgent.browser.isOpera()) { - // Opera 10 has Version/10.0 but Opera/9.8, so look for "Version" first. - // Opera uses 'OPR' for more recent UAs. - return lookUpValueWithKeys(['Version', 'Opera', 'OPR']); - } - - // Check Edge before Chrome since it has Chrome in the string. - if (goog.labs.userAgent.browser.isEdge()) { - return lookUpValueWithKeys(['Edge']); - } - - if (goog.labs.userAgent.browser.isChrome()) { - return lookUpValueWithKeys(['Chrome', 'CriOS']); - } - - // Usually products browser versions are in the third tuple after "Mozilla" - // and the engine. - var tuple = versionTuples[2]; - return tuple && tuple[1] || ''; -}; - - -/** - * @param {string|number} version The version to check. - * @return {boolean} Whether the browser version is higher or the same as the - * given version. - */ -goog.labs.userAgent.browser.isVersionOrHigher = function(version) { - return goog.string.compareVersions(goog.labs.userAgent.browser.getVersion(), - version) >= 0; -}; - - -/** - * Determines IE version. More information: - * http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString - * http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx - * http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx - * http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx - * - * @param {string} userAgent the User-Agent. - * @return {string} - * @private - */ -goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) { - // IE11 may identify itself as MSIE 9.0 or MSIE 10.0 due to an IE 11 upgrade - // bug. Example UA: - // Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) - // like Gecko. - // See http://www.whatismybrowser.com/developers/unknown-user-agent-fragments. - var rv = /rv: *([\d\.]*)/.exec(userAgent); - if (rv && rv[1]) { - return rv[1]; - } - - var version = ''; - var msie = /MSIE +([\d\.]+)/.exec(userAgent); - if (msie && msie[1]) { - // IE in compatibility mode usually identifies itself as MSIE 7.0; in this - // case, use the Trident version to determine the version of IE. For more - // details, see the links above. - var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent); - if (msie[1] == '7.0') { - if (tridentVersion && tridentVersion[1]) { - switch (tridentVersion[1]) { - case '4.0': - version = '8.0'; - break; - case '5.0': - version = '9.0'; - break; - case '6.0': - version = '10.0'; - break; - case '7.0': - version = '11.0'; - break; - } - } else { - version = '7.0'; - } - } else { - version = msie[1]; - } - } - return version; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Closure user agent detection. - * @see http://en.wikipedia.org/wiki/User_agent - * For more information on browser brand, platform, or device see the other - * sub-namespaces in goog.labs.userAgent (browser, platform, and device). - * - */ - -goog.provide('goog.labs.userAgent.engine'); - -goog.require('goog.array'); -goog.require('goog.labs.userAgent.util'); -goog.require('goog.string'); - - -/** - * @return {boolean} Whether the rendering engine is Presto. - */ -goog.labs.userAgent.engine.isPresto = function() { - return goog.labs.userAgent.util.matchUserAgent('Presto'); -}; - - -/** - * @return {boolean} Whether the rendering engine is Trident. - */ -goog.labs.userAgent.engine.isTrident = function() { - // IE only started including the Trident token in IE8. - return goog.labs.userAgent.util.matchUserAgent('Trident') || - goog.labs.userAgent.util.matchUserAgent('MSIE'); -}; - - -/** - * @return {boolean} Whether the rendering engine is Edge. - */ -goog.labs.userAgent.engine.isEdge = function() { - return goog.labs.userAgent.util.matchUserAgent('Edge'); -}; - - -/** - * @return {boolean} Whether the rendering engine is WebKit. - */ -goog.labs.userAgent.engine.isWebKit = function() { - return goog.labs.userAgent.util.matchUserAgentIgnoreCase('WebKit') && - !goog.labs.userAgent.engine.isEdge(); -}; - - -/** - * @return {boolean} Whether the rendering engine is Gecko. - */ -goog.labs.userAgent.engine.isGecko = function() { - return goog.labs.userAgent.util.matchUserAgent('Gecko') && - !goog.labs.userAgent.engine.isWebKit() && - !goog.labs.userAgent.engine.isTrident() && - !goog.labs.userAgent.engine.isEdge(); -}; - - -/** - * @return {string} The rendering engine's version or empty string if version - * can't be determined. - */ -goog.labs.userAgent.engine.getVersion = function() { - var userAgentString = goog.labs.userAgent.util.getUserAgent(); - if (userAgentString) { - var tuples = goog.labs.userAgent.util.extractVersionTuples( - userAgentString); - - var engineTuple = goog.labs.userAgent.engine.getEngineTuple_(tuples); - if (engineTuple) { - // In Gecko, the version string is either in the browser info or the - // Firefox version. See Gecko user agent string reference: - // http://goo.gl/mULqa - if (engineTuple[0] == 'Gecko') { - return goog.labs.userAgent.engine.getVersionForKey_( - tuples, 'Firefox'); - } - - return engineTuple[1]; - } - - // MSIE has only one version identifier, and the Trident version is - // specified in the parenthetical. IE Edge is covered in the engine tuple - // detection. - var browserTuple = tuples[0]; - var info; - if (browserTuple && (info = browserTuple[2])) { - var match = /Trident\/([^\s;]+)/.exec(info); - if (match) { - return match[1]; - } - } - } - return ''; -}; - - -/** - * @param {!Array<!Array<string>>} tuples Extracted version tuples. - * @return {!Array<string>|undefined} The engine tuple or undefined if not - * found. - * @private - */ -goog.labs.userAgent.engine.getEngineTuple_ = function(tuples) { - if (!goog.labs.userAgent.engine.isEdge()) { - return tuples[1]; - } - for (var i = 0; i < tuples.length; i++) { - var tuple = tuples[i]; - if (tuple[0] == 'Edge') { - return tuple; - } - } -}; - - -/** - * @param {string|number} version The version to check. - * @return {boolean} Whether the rendering engine version is higher or the same - * as the given version. - */ -goog.labs.userAgent.engine.isVersionOrHigher = function(version) { - return goog.string.compareVersions(goog.labs.userAgent.engine.getVersion(), - version) >= 0; -}; - - -/** - * @param {!Array<!Array<string>>} tuples Version tuples. - * @param {string} key The key to look for. - * @return {string} The version string of the given key, if present. - * Otherwise, the empty string. - * @private - */ -goog.labs.userAgent.engine.getVersionForKey_ = function(tuples, key) { - // TODO(nnaze): Move to util if useful elsewhere. - - var pair = goog.array.find(tuples, function(pair) { - return key == pair[0]; - }); - - return pair && pair[1] || ''; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Closure user agent platform detection. - * @see <a href="http://www.useragentstring.com/">User agent strings</a> - * For more information on browser brand, rendering engine, or device see the - * other sub-namespaces in goog.labs.userAgent (browser, engine, and device - * respectively). - * - */ - -goog.provide('goog.labs.userAgent.platform'); - -goog.require('goog.labs.userAgent.util'); -goog.require('goog.string'); - - -/** - * @return {boolean} Whether the platform is Android. - */ -goog.labs.userAgent.platform.isAndroid = function() { - return goog.labs.userAgent.util.matchUserAgent('Android'); -}; - - -/** - * @return {boolean} Whether the platform is iPod. - */ -goog.labs.userAgent.platform.isIpod = function() { - return goog.labs.userAgent.util.matchUserAgent('iPod'); -}; - - -/** - * @return {boolean} Whether the platform is iPhone. - */ -goog.labs.userAgent.platform.isIphone = function() { - return goog.labs.userAgent.util.matchUserAgent('iPhone') && - !goog.labs.userAgent.util.matchUserAgent('iPod') && - !goog.labs.userAgent.util.matchUserAgent('iPad'); -}; - - -/** - * @return {boolean} Whether the platform is iPad. - */ -goog.labs.userAgent.platform.isIpad = function() { - return goog.labs.userAgent.util.matchUserAgent('iPad'); -}; - - -/** - * @return {boolean} Whether the platform is iOS. - */ -goog.labs.userAgent.platform.isIos = function() { - return goog.labs.userAgent.platform.isIphone() || - goog.labs.userAgent.platform.isIpad() || - goog.labs.userAgent.platform.isIpod(); -}; - - -/** - * @return {boolean} Whether the platform is Mac. - */ -goog.labs.userAgent.platform.isMacintosh = function() { - return goog.labs.userAgent.util.matchUserAgent('Macintosh'); -}; - - -/** - * Note: ChromeOS is not considered to be Linux as it does not report itself - * as Linux in the user agent string. - * @return {boolean} Whether the platform is Linux. - */ -goog.labs.userAgent.platform.isLinux = function() { - return goog.labs.userAgent.util.matchUserAgent('Linux'); -}; - - -/** - * @return {boolean} Whether the platform is Windows. - */ -goog.labs.userAgent.platform.isWindows = function() { - return goog.labs.userAgent.util.matchUserAgent('Windows'); -}; - - -/** - * @return {boolean} Whether the platform is ChromeOS. - */ -goog.labs.userAgent.platform.isChromeOS = function() { - return goog.labs.userAgent.util.matchUserAgent('CrOS'); -}; - - -/** - * The version of the platform. We only determine the version for Windows, - * Mac, and Chrome OS. It doesn't make much sense on Linux. For Windows, we only - * look at the NT version. Non-NT-based versions (e.g. 95, 98, etc.) are given - * version 0.0. - * - * @return {string} The platform version or empty string if version cannot be - * determined. - */ -goog.labs.userAgent.platform.getVersion = function() { - var userAgentString = goog.labs.userAgent.util.getUserAgent(); - var version = '', re; - if (goog.labs.userAgent.platform.isWindows()) { - re = /Windows (?:NT|Phone) ([0-9.]+)/; - var match = re.exec(userAgentString); - if (match) { - version = match[1]; - } else { - version = '0.0'; - } - } else if (goog.labs.userAgent.platform.isIos()) { - re = /(?:iPhone|iPod|iPad|CPU)\s+OS\s+(\S+)/; - var match = re.exec(userAgentString); - // Report the version as x.y.z and not x_y_z - version = match && match[1].replace(/_/g, '.'); - } else if (goog.labs.userAgent.platform.isMacintosh()) { - re = /Mac OS X ([0-9_.]+)/; - var match = re.exec(userAgentString); - // Note: some old versions of Camino do not report an OSX version. - // Default to 10. - version = match ? match[1].replace(/_/g, '.') : '10'; - } else if (goog.labs.userAgent.platform.isAndroid()) { - re = /Android\s+([^\);]+)(\)|;)/; - var match = re.exec(userAgentString); - version = match && match[1]; - } else if (goog.labs.userAgent.platform.isChromeOS()) { - re = /(?:CrOS\s+(?:i686|x86_64)\s+([0-9.]+))/; - var match = re.exec(userAgentString); - version = match && match[1]; - } - return version || ''; -}; - - -/** - * @param {string|number} version The version to check. - * @return {boolean} Whether the browser version is higher or the same as the - * given version. - */ -goog.labs.userAgent.platform.isVersionOrHigher = function(version) { - return goog.string.compareVersions(goog.labs.userAgent.platform.getVersion(), - version) >= 0; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Rendering engine detection. - * @see <a href="http://www.useragentstring.com/">User agent strings</a> - * For information on the browser brand (such as Safari versus Chrome), see - * goog.userAgent.product. - * @author arv@google.com (Erik Arvidsson) - * @see ../demos/useragent.html - */ - -goog.provide('goog.userAgent'); - -goog.require('goog.labs.userAgent.browser'); -goog.require('goog.labs.userAgent.engine'); -goog.require('goog.labs.userAgent.platform'); -goog.require('goog.labs.userAgent.util'); -goog.require('goog.string'); - - -/** - * @define {boolean} Whether we know at compile-time that the browser is IE. - */ -goog.define('goog.userAgent.ASSUME_IE', false); - - -/** - * @define {boolean} Whether we know at compile-time that the browser is EDGE. - */ -goog.define('goog.userAgent.ASSUME_EDGE', false); - - -/** - * @define {boolean} Whether we know at compile-time that the browser is GECKO. - */ -goog.define('goog.userAgent.ASSUME_GECKO', false); - - -/** - * @define {boolean} Whether we know at compile-time that the browser is WEBKIT. - */ -goog.define('goog.userAgent.ASSUME_WEBKIT', false); - - -/** - * @define {boolean} Whether we know at compile-time that the browser is a - * mobile device running WebKit e.g. iPhone or Android. - */ -goog.define('goog.userAgent.ASSUME_MOBILE_WEBKIT', false); - - -/** - * @define {boolean} Whether we know at compile-time that the browser is OPERA. - */ -goog.define('goog.userAgent.ASSUME_OPERA', false); - - -/** - * @define {boolean} Whether the - * {@code goog.userAgent.isVersionOrHigher} - * function will return true for any version. - */ -goog.define('goog.userAgent.ASSUME_ANY_VERSION', false); - - -/** - * Whether we know the browser engine at compile-time. - * @type {boolean} - * @private - */ -goog.userAgent.BROWSER_KNOWN_ = - goog.userAgent.ASSUME_IE || - goog.userAgent.ASSUME_EDGE || - goog.userAgent.ASSUME_GECKO || - goog.userAgent.ASSUME_MOBILE_WEBKIT || - goog.userAgent.ASSUME_WEBKIT || - goog.userAgent.ASSUME_OPERA; - - -/** - * Returns the userAgent string for the current browser. - * - * @return {string} The userAgent string. - */ -goog.userAgent.getUserAgentString = function() { - return goog.labs.userAgent.util.getUserAgent(); -}; - - -/** - * TODO(nnaze): Change type to "Navigator" and update compilation targets. - * @return {Object} The native navigator object. - */ -goog.userAgent.getNavigator = function() { - // Need a local navigator reference instead of using the global one, - // to avoid the rare case where they reference different objects. - // (in a WorkerPool, for example). - return goog.global['navigator'] || null; -}; - - -/** - * Whether the user agent is Opera. - * @type {boolean} - */ -goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_OPERA : - goog.labs.userAgent.browser.isOpera(); - - -/** - * Whether the user agent is Internet Explorer. - * @type {boolean} - */ -goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_IE : - goog.labs.userAgent.browser.isIE(); - - -/** - * Whether the user agent is Microsoft Edge. - * @type {boolean} - */ -goog.userAgent.EDGE = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_EDGE : - goog.labs.userAgent.engine.isEdge(); - - -/** - * Whether the user agent is MS Internet Explorer or MS Edge. - * @type {boolean} - */ -goog.userAgent.EDGE_OR_IE = goog.userAgent.EDGE || goog.userAgent.IE; - - -/** - * Whether the user agent is Gecko. Gecko is the rendering engine used by - * Mozilla, Firefox, and others. - * @type {boolean} - */ -goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_GECKO : - goog.labs.userAgent.engine.isGecko(); - - -/** - * Whether the user agent is WebKit. WebKit is the rendering engine that - * Safari, Android and others use. - * @type {boolean} - */ -goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT : - goog.labs.userAgent.engine.isWebKit(); - - -/** - * Whether the user agent is running on a mobile device. - * - * This is a separate function so that the logic can be tested. - * - * TODO(nnaze): Investigate swapping in goog.labs.userAgent.device.isMobile(). - * - * @return {boolean} Whether the user agent is running on a mobile device. - * @private - */ -goog.userAgent.isMobile_ = function() { - return goog.userAgent.WEBKIT && - goog.labs.userAgent.util.matchUserAgent('Mobile'); -}; - - -/** - * Whether the user agent is running on a mobile device. - * - * TODO(nnaze): Consider deprecating MOBILE when labs.userAgent - * is promoted as the gecko/webkit logic is likely inaccurate. - * - * @type {boolean} - */ -goog.userAgent.MOBILE = goog.userAgent.ASSUME_MOBILE_WEBKIT || - goog.userAgent.isMobile_(); - - -/** - * Used while transitioning code to use WEBKIT instead. - * @type {boolean} - * @deprecated Use {@link goog.userAgent.product.SAFARI} instead. - * TODO(nicksantos): Delete this from goog.userAgent. - */ -goog.userAgent.SAFARI = goog.userAgent.WEBKIT; - - -/** - * @return {string} the platform (operating system) the user agent is running - * on. Default to empty string because navigator.platform may not be defined - * (on Rhino, for example). - * @private - */ -goog.userAgent.determinePlatform_ = function() { - var navigator = goog.userAgent.getNavigator(); - return navigator && navigator.platform || ''; -}; - - -/** - * The platform (operating system) the user agent is running on. Default to - * empty string because navigator.platform may not be defined (on Rhino, for - * example). - * @type {string} - */ -goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_(); - - -/** - * @define {boolean} Whether the user agent is running on a Macintosh operating - * system. - */ -goog.define('goog.userAgent.ASSUME_MAC', false); - - -/** - * @define {boolean} Whether the user agent is running on a Windows operating - * system. - */ -goog.define('goog.userAgent.ASSUME_WINDOWS', false); - - -/** - * @define {boolean} Whether the user agent is running on a Linux operating - * system. - */ -goog.define('goog.userAgent.ASSUME_LINUX', false); - - -/** - * @define {boolean} Whether the user agent is running on a X11 windowing - * system. - */ -goog.define('goog.userAgent.ASSUME_X11', false); - - -/** - * @define {boolean} Whether the user agent is running on Android. - */ -goog.define('goog.userAgent.ASSUME_ANDROID', false); - - -/** - * @define {boolean} Whether the user agent is running on an iPhone. - */ -goog.define('goog.userAgent.ASSUME_IPHONE', false); - - -/** - * @define {boolean} Whether the user agent is running on an iPad. - */ -goog.define('goog.userAgent.ASSUME_IPAD', false); - - -/** - * @type {boolean} - * @private - */ -goog.userAgent.PLATFORM_KNOWN_ = - goog.userAgent.ASSUME_MAC || - goog.userAgent.ASSUME_WINDOWS || - goog.userAgent.ASSUME_LINUX || - goog.userAgent.ASSUME_X11 || - goog.userAgent.ASSUME_ANDROID || - goog.userAgent.ASSUME_IPHONE || - goog.userAgent.ASSUME_IPAD; - - -/** - * Whether the user agent is running on a Macintosh operating system. - * @type {boolean} - */ -goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_MAC : goog.labs.userAgent.platform.isMacintosh(); - - -/** - * Whether the user agent is running on a Windows operating system. - * @type {boolean} - */ -goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_WINDOWS : - goog.labs.userAgent.platform.isWindows(); - - -/** - * Whether the user agent is Linux per the legacy behavior of - * goog.userAgent.LINUX, which considered ChromeOS to also be - * Linux. - * @return {boolean} - * @private - */ -goog.userAgent.isLegacyLinux_ = function() { - return goog.labs.userAgent.platform.isLinux() || - goog.labs.userAgent.platform.isChromeOS(); -}; - - -/** - * Whether the user agent is running on a Linux operating system. - * - * Note that goog.userAgent.LINUX considers ChromeOS to be Linux, - * while goog.labs.userAgent.platform considers ChromeOS and - * Linux to be different OSes. - * - * @type {boolean} - */ -goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_LINUX : - goog.userAgent.isLegacyLinux_(); - - -/** - * @return {boolean} Whether the user agent is an X11 windowing system. - * @private - */ -goog.userAgent.isX11_ = function() { - var navigator = goog.userAgent.getNavigator(); - return !!navigator && - goog.string.contains(navigator['appVersion'] || '', 'X11'); -}; - - -/** - * Whether the user agent is running on a X11 windowing system. - * @type {boolean} - */ -goog.userAgent.X11 = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_X11 : - goog.userAgent.isX11_(); - - -/** - * Whether the user agent is running on Android. - * @type {boolean} - */ -goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_ANDROID : - goog.labs.userAgent.platform.isAndroid(); - - -/** - * Whether the user agent is running on an iPhone. - * @type {boolean} - */ -goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_IPHONE : - goog.labs.userAgent.platform.isIphone(); - - -/** - * Whether the user agent is running on an iPad. - * @type {boolean} - */ -goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_IPAD : - goog.labs.userAgent.platform.isIpad(); - - -/** - * @return {string} The string that describes the version number of the user - * agent. - * Assumes user agent is opera. - * @private - */ -goog.userAgent.operaVersion_ = function() { - var version = goog.global.opera.version; - try { - return version(); - } catch (e) { - return version; - } -}; - - -/** - * @return {string} The string that describes the version number of the user - * agent. - * @private - */ -goog.userAgent.determineVersion_ = function() { - // All browsers have different ways to detect the version and they all have - // different naming schemes. - - if (goog.userAgent.OPERA && goog.global['opera']) { - return goog.userAgent.operaVersion_(); - } - - // version is a string rather than a number because it may contain 'b', 'a', - // and so on. - var version = ''; - var arr = goog.userAgent.getVersionRegexResult_(); - if (arr) { - version = arr ? arr[1] : ''; - } - - if (goog.userAgent.IE) { - // IE9 can be in document mode 9 but be reporting an inconsistent user agent - // version. If it is identifying as a version lower than 9 we take the - // documentMode as the version instead. IE8 has similar behavior. - // It is recommended to set the X-UA-Compatible header to ensure that IE9 - // uses documentMode 9. - var docMode = goog.userAgent.getDocumentMode_(); - if (docMode > parseFloat(version)) { - return String(docMode); - } - } - - return version; -}; - - -/** - * @return {Array|undefined} The version regex matches from parsing the user - * agent string. These regex statements must be executed inline so they can - * be compiled out by the closure compiler with the rest of the useragent - * detection logic when ASSUME_* is specified. - * @private - */ -goog.userAgent.getVersionRegexResult_ = function() { - var userAgent = goog.userAgent.getUserAgentString(); - if (goog.userAgent.GECKO) { - return /rv\:([^\);]+)(\)|;)/.exec(userAgent); - } - if (goog.userAgent.EDGE) { - return /Edge\/([\d\.]+)/.exec(userAgent); - } - if (goog.userAgent.IE) { - return /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(userAgent); - } - if (goog.userAgent.WEBKIT) { - // WebKit/125.4 - return /WebKit\/(\S+)/.exec(userAgent); - } -}; - - -/** - * @return {number|undefined} Returns the document mode (for testing). - * @private - */ -goog.userAgent.getDocumentMode_ = function() { - // NOTE(user): goog.userAgent may be used in context where there is no DOM. - var doc = goog.global['document']; - return doc ? doc['documentMode'] : undefined; -}; - - -/** - * The version of the user agent. This is a string because it might contain - * 'b' (as in beta) as well as multiple dots. - * @type {string} - */ -goog.userAgent.VERSION = goog.userAgent.determineVersion_(); - - -/** - * Compares two version numbers. - * - * @param {string} v1 Version of first item. - * @param {string} v2 Version of second item. - * - * @return {number} 1 if first argument is higher - * 0 if arguments are equal - * -1 if second argument is higher. - * @deprecated Use goog.string.compareVersions. - */ -goog.userAgent.compare = function(v1, v2) { - return goog.string.compareVersions(v1, v2); -}; - - -/** - * Cache for {@link goog.userAgent.isVersionOrHigher}. - * Calls to compareVersions are surprisingly expensive and, as a browser's - * version number is unlikely to change during a session, we cache the results. - * @const - * @private - */ -goog.userAgent.isVersionOrHigherCache_ = {}; - - -/** - * Whether the user agent version is higher or the same as the given version. - * NOTE: When checking the version numbers for Firefox and Safari, be sure to - * use the engine's version, not the browser's version number. For example, - * Firefox 3.0 corresponds to Gecko 1.9 and Safari 3.0 to Webkit 522.11. - * Opera and Internet Explorer versions match the product release number.<br> - * @see <a href="http://en.wikipedia.org/wiki/Safari_version_history"> - * Webkit</a> - * @see <a href="http://en.wikipedia.org/wiki/Gecko_engine">Gecko</a> - * - * @param {string|number} version The version to check. - * @return {boolean} Whether the user agent version is higher or the same as - * the given version. - */ -goog.userAgent.isVersionOrHigher = function(version) { - return goog.userAgent.ASSUME_ANY_VERSION || - goog.userAgent.isVersionOrHigherCache_[version] || - (goog.userAgent.isVersionOrHigherCache_[version] = - goog.string.compareVersions(goog.userAgent.VERSION, version) >= 0); -}; - - -/** - * Deprecated alias to {@code goog.userAgent.isVersionOrHigher}. - * @param {string|number} version The version to check. - * @return {boolean} Whether the user agent version is higher or the same as - * the given version. - * @deprecated Use goog.userAgent.isVersionOrHigher(). - */ -goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher; - - -/** - * Whether the IE effective document mode is higher or the same as the given - * document mode version. - * NOTE: Only for IE, return false for another browser. - * - * @param {number} documentMode The document mode version to check. - * @return {boolean} Whether the IE effective document mode is higher or the - * same as the given version. - */ -goog.userAgent.isDocumentModeOrHigher = function(documentMode) { - return goog.userAgent.DOCUMENT_MODE >= documentMode; -}; - - -/** - * Deprecated alias to {@code goog.userAgent.isDocumentModeOrHigher}. - * @param {number} version The version to check. - * @return {boolean} Whether the IE effective document mode is higher or the - * same as the given version. - * @deprecated Use goog.userAgent.isDocumentModeOrHigher(). - */ -goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher; - - -/** - * For IE version < 7, documentMode is undefined, so attempt to use the - * CSS1Compat property to see if we are in standards mode. If we are in - * standards mode, treat the browser version as the document mode. Otherwise, - * IE is emulating version 5. - * @type {number|undefined} - * @const - */ -goog.userAgent.DOCUMENT_MODE = (function() { - var doc = goog.global['document']; - var mode = goog.userAgent.getDocumentMode_(); - if (!doc || !goog.userAgent.IE) { - return undefined; - } - return mode || (doc['compatMode'] == 'CSS1Compat' ? - parseInt(goog.userAgent.VERSION, 10) : 5); -})(); - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Browser capability checks for the events package. - * - */ - - -goog.provide('goog.events.BrowserFeature'); - -goog.require('goog.userAgent'); - - -/** - * Enum of browser capabilities. - * @enum {boolean} - */ -goog.events.BrowserFeature = { - /** - * Whether the button attribute of the event is W3C compliant. False in - * Internet Explorer prior to version 9; document-version dependent. - */ - HAS_W3C_BUTTON: !goog.userAgent.IE || - goog.userAgent.isDocumentModeOrHigher(9), - - /** - * Whether the browser supports full W3C event model. - */ - HAS_W3C_EVENT_SUPPORT: !goog.userAgent.IE || - goog.userAgent.isDocumentModeOrHigher(9), - - /** - * To prevent default in IE7-8 for certain keydown events we need set the - * keyCode to -1. - */ - SET_KEY_CODE_TO_PREVENT_DEFAULT: goog.userAgent.IE && - !goog.userAgent.isVersionOrHigher('9'), - - /** - * Whether the {@code navigator.onLine} property is supported. - */ - HAS_NAVIGATOR_ONLINE_PROPERTY: !goog.userAgent.WEBKIT || - goog.userAgent.isVersionOrHigher('528'), - - /** - * Whether HTML5 network online/offline events are supported. - */ - HAS_HTML5_NETWORK_EVENT_SUPPORT: - goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9b') || - goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8') || - goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('9.5') || - goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('528'), - - /** - * Whether HTML5 network events fire on document.body, or otherwise the - * window. - */ - HTML5_NETWORK_EVENTS_FIRE_ON_BODY: - goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('8') || - goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'), - - /** - * Whether touch is enabled in the browser. - */ - TOUCH_ENABLED: - ('ontouchstart' in goog.global || - !!(goog.global['document'] && - document.documentElement && - 'ontouchstart' in document.documentElement) || - // IE10 uses non-standard touch events, so it has a different check. - !!(goog.global['navigator'] && - goog.global['navigator']['msMaxTouchPoints'])) -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the disposable interface. A disposable object - * has a dispose method to to clean up references and resources. - * @author nnaze@google.com (Nathan Naze) - */ - - -goog.provide('goog.disposable.IDisposable'); - - - -/** - * Interface for a disposable object. If a instance requires cleanup - * (references COM objects, DOM notes, or other disposable objects), it should - * implement this interface (it may subclass goog.Disposable). - * @interface - */ -goog.disposable.IDisposable = function() {}; - - -/** - * Disposes of the object and its resources. - * @return {void} Nothing. - */ -goog.disposable.IDisposable.prototype.dispose = goog.abstractMethod; - - -/** - * @return {boolean} Whether the object has been disposed of. - */ -goog.disposable.IDisposable.prototype.isDisposed = goog.abstractMethod; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Implements the disposable interface. The dispose method is used - * to clean up references and resources. - * @author arv@google.com (Erik Arvidsson) - */ - - -goog.provide('goog.Disposable'); -/** @suppress {extraProvide} */ -goog.provide('goog.dispose'); -/** @suppress {extraProvide} */ -goog.provide('goog.disposeAll'); - -goog.require('goog.disposable.IDisposable'); - - - -/** - * Class that provides the basic implementation for disposable objects. If your - * class holds one or more references to COM objects, DOM nodes, or other - * disposable objects, it should extend this class or implement the disposable - * interface (defined in goog.disposable.IDisposable). - * @constructor - * @implements {goog.disposable.IDisposable} - */ -goog.Disposable = function() { - if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) { - if (goog.Disposable.INCLUDE_STACK_ON_CREATION) { - this.creationStack = new Error().stack; - } - goog.Disposable.instances_[goog.getUid(this)] = this; - } - // Support sealing - this.disposed_ = this.disposed_; - this.onDisposeCallbacks_ = this.onDisposeCallbacks_; -}; - - -/** - * @enum {number} Different monitoring modes for Disposable. - */ -goog.Disposable.MonitoringMode = { - /** - * No monitoring. - */ - OFF: 0, - /** - * Creating and disposing the goog.Disposable instances is monitored. All - * disposable objects need to call the {@code goog.Disposable} base - * constructor. The PERMANENT mode must be switched on before creating any - * goog.Disposable instances. - */ - PERMANENT: 1, - /** - * INTERACTIVE mode can be switched on and off on the fly without producing - * errors. It also doesn't warn if the disposable objects don't call the - * {@code goog.Disposable} base constructor. - */ - INTERACTIVE: 2 -}; - - -/** - * @define {number} The monitoring mode of the goog.Disposable - * instances. Default is OFF. Switching on the monitoring is only - * recommended for debugging because it has a significant impact on - * performance and memory usage. If switched off, the monitoring code - * compiles down to 0 bytes. - */ -goog.define('goog.Disposable.MONITORING_MODE', 0); - - -/** - * @define {boolean} Whether to attach creation stack to each created disposable - * instance; This is only relevant for when MonitoringMode != OFF. - */ -goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true); - - -/** - * Maps the unique ID of every undisposed {@code goog.Disposable} object to - * the object itself. - * @type {!Object<number, !goog.Disposable>} - * @private - */ -goog.Disposable.instances_ = {}; - - -/** - * @return {!Array<!goog.Disposable>} All {@code goog.Disposable} objects that - * haven't been disposed of. - */ -goog.Disposable.getUndisposedObjects = function() { - var ret = []; - for (var id in goog.Disposable.instances_) { - if (goog.Disposable.instances_.hasOwnProperty(id)) { - ret.push(goog.Disposable.instances_[Number(id)]); - } - } - return ret; -}; - - -/** - * Clears the registry of undisposed objects but doesn't dispose of them. - */ -goog.Disposable.clearUndisposedObjects = function() { - goog.Disposable.instances_ = {}; -}; - - -/** - * Whether the object has been disposed of. - * @type {boolean} - * @private - */ -goog.Disposable.prototype.disposed_ = false; - - -/** - * Callbacks to invoke when this object is disposed. - * @type {Array<!Function>} - * @private - */ -goog.Disposable.prototype.onDisposeCallbacks_; - - -/** - * If monitoring the goog.Disposable instances is enabled, stores the creation - * stack trace of the Disposable instance. - * @const {string} - */ -goog.Disposable.prototype.creationStack; - - -/** - * @return {boolean} Whether the object has been disposed of. - * @override - */ -goog.Disposable.prototype.isDisposed = function() { - return this.disposed_; -}; - - -/** - * @return {boolean} Whether the object has been disposed of. - * @deprecated Use {@link #isDisposed} instead. - */ -goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed; - - -/** - * Disposes of the object. If the object hasn't already been disposed of, calls - * {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should - * override {@link #disposeInternal} in order to delete references to COM - * objects, DOM nodes, and other disposable objects. Reentrant. - * - * @return {void} Nothing. - * @override - */ -goog.Disposable.prototype.dispose = function() { - if (!this.disposed_) { - // Set disposed_ to true first, in case during the chain of disposal this - // gets disposed recursively. - this.disposed_ = true; - this.disposeInternal(); - if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) { - var uid = goog.getUid(this); - if (goog.Disposable.MONITORING_MODE == - goog.Disposable.MonitoringMode.PERMANENT && - !goog.Disposable.instances_.hasOwnProperty(uid)) { - throw Error(this + ' did not call the goog.Disposable base ' + - 'constructor or was disposed of after a clearUndisposedObjects ' + - 'call'); - } - delete goog.Disposable.instances_[uid]; - } - } -}; - - -/** - * Associates a disposable object with this object so that they will be disposed - * together. - * @param {goog.disposable.IDisposable} disposable that will be disposed when - * this object is disposed. - */ -goog.Disposable.prototype.registerDisposable = function(disposable) { - this.addOnDisposeCallback(goog.partial(goog.dispose, disposable)); -}; - - -/** - * Invokes a callback function when this object is disposed. Callbacks are - * invoked in the order in which they were added. If a callback is added to - * an already disposed Disposable, it will be called immediately. - * @param {function(this:T):?} callback The callback function. - * @param {T=} opt_scope An optional scope to call the callback in. - * @template T - */ -goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) { - if (this.disposed_) { - callback.call(opt_scope); - return; - } - if (!this.onDisposeCallbacks_) { - this.onDisposeCallbacks_ = []; - } - - this.onDisposeCallbacks_.push( - goog.isDef(opt_scope) ? goog.bind(callback, opt_scope) : callback); -}; - - -/** - * Deletes or nulls out any references to COM objects, DOM nodes, or other - * disposable objects. Classes that extend {@code goog.Disposable} should - * override this method. - * Not reentrant. To avoid calling it twice, it must only be called from the - * subclass' {@code disposeInternal} method. Everywhere else the public - * {@code dispose} method must be used. - * For example: - * <pre> - * mypackage.MyClass = function() { - * mypackage.MyClass.base(this, 'constructor'); - * // Constructor logic specific to MyClass. - * ... - * }; - * goog.inherits(mypackage.MyClass, goog.Disposable); - * - * mypackage.MyClass.prototype.disposeInternal = function() { - * // Dispose logic specific to MyClass. - * ... - * // Call superclass's disposeInternal at the end of the subclass's, like - * // in C++, to avoid hard-to-catch issues. - * mypackage.MyClass.base(this, 'disposeInternal'); - * }; - * </pre> - * @protected - */ -goog.Disposable.prototype.disposeInternal = function() { - if (this.onDisposeCallbacks_) { - while (this.onDisposeCallbacks_.length) { - this.onDisposeCallbacks_.shift()(); - } - } -}; - - -/** - * Returns True if we can verify the object is disposed. - * Calls {@code isDisposed} on the argument if it supports it. If obj - * is not an object with an isDisposed() method, return false. - * @param {*} obj The object to investigate. - * @return {boolean} True if we can verify the object is disposed. - */ -goog.Disposable.isDisposed = function(obj) { - if (obj && typeof obj.isDisposed == 'function') { - return obj.isDisposed(); - } - return false; -}; - - -/** - * Calls {@code dispose} on the argument if it supports it. If obj is not an - * object with a dispose() method, this is a no-op. - * @param {*} obj The object to dispose of. - */ -goog.dispose = function(obj) { - if (obj && typeof obj.dispose == 'function') { - obj.dispose(); - } -}; - - -/** - * Calls {@code dispose} on each member of the list that supports it. (If the - * member is an ArrayLike, then {@code goog.disposeAll()} will be called - * recursively on each of its members.) If the member is not an object with a - * {@code dispose()} method, then it is ignored. - * @param {...*} var_args The list. - */ -goog.disposeAll = function(var_args) { - for (var i = 0, len = arguments.length; i < len; ++i) { - var disposable = arguments[i]; - if (goog.isArrayLike(disposable)) { - goog.disposeAll.apply(null, disposable); - } else { - goog.dispose(disposable); - } - } -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.events.EventId'); - - - -/** - * A templated class that is used when registering for events. Typical usage: - * <code> - * /** @type {goog.events.EventId<MyEventObj>} - * var myEventId = new goog.events.EventId( - * goog.events.getUniqueId(('someEvent')); - * - * // No need to cast or declare here since the compiler knows the correct - * // type of 'evt' (MyEventObj). - * something.listen(myEventId, function(evt) {}); - * </code> - * - * @param {string} eventId - * @template T - * @constructor - * @struct - * @final - */ -goog.events.EventId = function(eventId) { - /** @const */ this.id = eventId; -}; - - -/** - * @override - */ -goog.events.EventId.prototype.toString = function() { - return this.id; -}; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A base class for event objects. - * - */ - - -goog.provide('goog.events.Event'); -goog.provide('goog.events.EventLike'); - -/** - * goog.events.Event no longer depends on goog.Disposable. Keep requiring - * goog.Disposable here to not break projects which assume this dependency. - * @suppress {extraRequire} - */ -goog.require('goog.Disposable'); -goog.require('goog.events.EventId'); - - -/** - * A typedef for event like objects that are dispatchable via the - * goog.events.dispatchEvent function. strings are treated as the type for a - * goog.events.Event. Objects are treated as an extension of a new - * goog.events.Event with the type property of the object being used as the type - * of the Event. - * @typedef {string|Object|goog.events.Event|goog.events.EventId} - */ -goog.events.EventLike; - - - -/** - * A base class for event objects, so that they can support preventDefault and - * stopPropagation. - * - * @param {string|!goog.events.EventId} type Event Type. - * @param {Object=} opt_target Reference to the object that is the target of - * this event. It has to implement the {@code EventTarget} interface - * declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}. - * @constructor - */ -goog.events.Event = function(type, opt_target) { - /** - * Event type. - * @type {string} - */ - this.type = type instanceof goog.events.EventId ? String(type) : type; - - /** - * TODO(tbreisacher): The type should probably be - * EventTarget|goog.events.EventTarget. - * - * Target of the event. - * @type {Object|undefined} - */ - this.target = opt_target; - - /** - * Object that had the listener attached. - * @type {Object|undefined} - */ - this.currentTarget = this.target; - - /** - * Whether to cancel the event in internal capture/bubble processing for IE. - * @type {boolean} - * @public - * @suppress {underscore|visibility} Technically public, but referencing this - * outside this package is strongly discouraged. - */ - this.propagationStopped_ = false; - - /** - * Whether the default action has been prevented. - * This is a property to match the W3C specification at - * {@link http://www.w3.org/TR/DOM-Level-3-Events/ - * #events-event-type-defaultPrevented}. - * Must be treated as read-only outside the class. - * @type {boolean} - */ - this.defaultPrevented = false; - - /** - * Return value for in internal capture/bubble processing for IE. - * @type {boolean} - * @public - * @suppress {underscore|visibility} Technically public, but referencing this - * outside this package is strongly discouraged. - */ - this.returnValue_ = true; -}; - - -/** - * Stops event propagation. - */ -goog.events.Event.prototype.stopPropagation = function() { - this.propagationStopped_ = true; -}; - - -/** - * Prevents the default action, for example a link redirecting to a url. - */ -goog.events.Event.prototype.preventDefault = function() { - this.defaultPrevented = true; - this.returnValue_ = false; -}; - - -/** - * Stops the propagation of the event. It is equivalent to - * {@code e.stopPropagation()}, but can be used as the callback argument of - * {@link goog.events.listen} without declaring another function. - * @param {!goog.events.Event} e An event. - */ -goog.events.Event.stopPropagation = function(e) { - e.stopPropagation(); -}; - - -/** - * Prevents the default action. It is equivalent to - * {@code e.preventDefault()}, but can be used as the callback argument of - * {@link goog.events.listen} without declaring another function. - * @param {!goog.events.Event} e An event. - */ -goog.events.Event.preventDefault = function(e) { - e.preventDefault(); -}; - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Event Types. - * - * @author arv@google.com (Erik Arvidsson) - */ - - -goog.provide('goog.events.EventType'); - -goog.require('goog.userAgent'); - - -/** - * Returns a prefixed event name for the current browser. - * @param {string} eventName The name of the event. - * @return {string} The prefixed event name. - * @suppress {missingRequire|missingProvide} - * @private - */ -goog.events.getVendorPrefixedName_ = function(eventName) { - return goog.userAgent.WEBKIT ? 'webkit' + eventName : - (goog.userAgent.OPERA ? 'o' + eventName.toLowerCase() : - eventName.toLowerCase()); -}; - - -/** - * Constants for event names. - * @enum {string} - */ -goog.events.EventType = { - // Mouse events - CLICK: 'click', - RIGHTCLICK: 'rightclick', - DBLCLICK: 'dblclick', - MOUSEDOWN: 'mousedown', - MOUSEUP: 'mouseup', - MOUSEOVER: 'mouseover', - MOUSEOUT: 'mouseout', - MOUSEMOVE: 'mousemove', - MOUSEENTER: 'mouseenter', - MOUSELEAVE: 'mouseleave', - // Select start is non-standard. - // See http://msdn.microsoft.com/en-us/library/ie/ms536969(v=vs.85).aspx. - SELECTSTART: 'selectstart', // IE, Safari, Chrome - - // Wheel events - // http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents - WHEEL: 'wheel', - - // Key events - KEYPRESS: 'keypress', - KEYDOWN: 'keydown', - KEYUP: 'keyup', - - // Focus - BLUR: 'blur', - FOCUS: 'focus', - DEACTIVATE: 'deactivate', // IE only - // NOTE: The following two events are not stable in cross-browser usage. - // WebKit and Opera implement DOMFocusIn/Out. - // IE implements focusin/out. - // Gecko implements neither see bug at - // https://bugzilla.mozilla.org/show_bug.cgi?id=396927. - // The DOM Events Level 3 Draft deprecates DOMFocusIn in favor of focusin: - // http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html - // You can use FOCUS in Capture phase until implementations converge. - FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn', - FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut', - - // Forms - CHANGE: 'change', - RESET: 'reset', - SELECT: 'select', - SUBMIT: 'submit', - INPUT: 'input', - PROPERTYCHANGE: 'propertychange', // IE only - - // Drag and drop - DRAGSTART: 'dragstart', - DRAG: 'drag', - DRAGENTER: 'dragenter', - DRAGOVER: 'dragover', - DRAGLEAVE: 'dragleave', - DROP: 'drop', - DRAGEND: 'dragend', - - // Touch events - // Note that other touch events exist, but we should follow the W3C list here. - // http://www.w3.org/TR/touch-events/#list-of-touchevent-types - TOUCHSTART: 'touchstart', - TOUCHMOVE: 'touchmove', - TOUCHEND: 'touchend', - TOUCHCANCEL: 'touchcancel', - - // Misc - BEFOREUNLOAD: 'beforeunload', - CONSOLEMESSAGE: 'consolemessage', - CONTEXTMENU: 'contextmenu', - DOMCONTENTLOADED: 'DOMContentLoaded', - ERROR: 'error', - HELP: 'help', - LOAD: 'load', - LOSECAPTURE: 'losecapture', - ORIENTATIONCHANGE: 'orientationchange', - READYSTATECHANGE: 'readystatechange', - RESIZE: 'resize', - SCROLL: 'scroll', - UNLOAD: 'unload', - - // HTML 5 History events - // See http://www.w3.org/TR/html5/browsers.html#event-definitions-0 - HASHCHANGE: 'hashchange', - PAGEHIDE: 'pagehide', - PAGESHOW: 'pageshow', - POPSTATE: 'popstate', - - // Copy and Paste - // Support is limited. Make sure it works on your favorite browser - // before using. - // http://www.quirksmode.org/dom/events/cutcopypaste.html - COPY: 'copy', - PASTE: 'paste', - CUT: 'cut', - BEFORECOPY: 'beforecopy', - BEFORECUT: 'beforecut', - BEFOREPASTE: 'beforepaste', - - // HTML5 online/offline events. - // http://www.w3.org/TR/offline-webapps/#related - ONLINE: 'online', - OFFLINE: 'offline', - - // HTML 5 worker events - MESSAGE: 'message', - CONNECT: 'connect', - - // CSS animation events. - /** @suppress {missingRequire} */ - ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'), - /** @suppress {missingRequire} */ - ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'), - /** @suppress {missingRequire} */ - ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'), - - // CSS transition events. Based on the browser support described at: - // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility - /** @suppress {missingRequire} */ - TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'), - - // W3C Pointer Events - // http://www.w3.org/TR/pointerevents/ - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTERCANCEL: 'pointercancel', - POINTERMOVE: 'pointermove', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - GOTPOINTERCAPTURE: 'gotpointercapture', - LOSTPOINTERCAPTURE: 'lostpointercapture', - - // IE specific events. - // See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx - // Note: these events will be supplanted in IE11. - MSGESTURECHANGE: 'MSGestureChange', - MSGESTUREEND: 'MSGestureEnd', - MSGESTUREHOLD: 'MSGestureHold', - MSGESTURESTART: 'MSGestureStart', - MSGESTURETAP: 'MSGestureTap', - MSGOTPOINTERCAPTURE: 'MSGotPointerCapture', - MSINERTIASTART: 'MSInertiaStart', - MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture', - MSPOINTERCANCEL: 'MSPointerCancel', - MSPOINTERDOWN: 'MSPointerDown', - MSPOINTERENTER: 'MSPointerEnter', - MSPOINTERHOVER: 'MSPointerHover', - MSPOINTERLEAVE: 'MSPointerLeave', - MSPOINTERMOVE: 'MSPointerMove', - MSPOINTEROUT: 'MSPointerOut', - MSPOINTEROVER: 'MSPointerOver', - MSPOINTERUP: 'MSPointerUp', - - // Native IMEs/input tools events. - TEXT: 'text', - TEXTINPUT: 'textInput', - COMPOSITIONSTART: 'compositionstart', - COMPOSITIONUPDATE: 'compositionupdate', - COMPOSITIONEND: 'compositionend', - - // Webview tag events - // See http://developer.chrome.com/dev/apps/webview_tag.html - EXIT: 'exit', - LOADABORT: 'loadabort', - LOADCOMMIT: 'loadcommit', - LOADREDIRECT: 'loadredirect', - LOADSTART: 'loadstart', - LOADSTOP: 'loadstop', - RESPONSIVE: 'responsive', - SIZECHANGED: 'sizechanged', - UNRESPONSIVE: 'unresponsive', - - // HTML5 Page Visibility API. See details at - // {@code goog.labs.dom.PageVisibilityMonitor}. - VISIBILITYCHANGE: 'visibilitychange', - - // LocalStorage event. - STORAGE: 'storage', - - // DOM Level 2 mutation events (deprecated). - DOMSUBTREEMODIFIED: 'DOMSubtreeModified', - DOMNODEINSERTED: 'DOMNodeInserted', - DOMNODEREMOVED: 'DOMNodeRemoved', - DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument', - DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument', - DOMATTRMODIFIED: 'DOMAttrModified', - DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified', - - // Print events. - BEFOREPRINT: 'beforeprint', - AFTERPRINT: 'afterprint' -}; - -// Copyright 2009 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Useful compiler idioms. - * - * @author johnlenz@google.com (John Lenz) - */ - -goog.provide('goog.reflect'); - - -/** - * Syntax for object literal casts. - * @see http://go/jscompiler-renaming - * @see https://github.com/google/closure-compiler/wiki/Type-Based-Property-Renaming - * - * Use this if you have an object literal whose keys need to have the same names - * as the properties of some class even after they are renamed by the compiler. - * - * @param {!Function} type Type to cast to. - * @param {Object} object Object literal to cast. - * @return {Object} The object literal. - */ -goog.reflect.object = function(type, object) { - return object; -}; - - -/** - * To assert to the compiler that an operation is needed when it would - * otherwise be stripped. For example: - * <code> - * // Force a layout - * goog.reflect.sinkValue(dialog.offsetHeight); - * </code> - * @type {!Function} - */ -goog.reflect.sinkValue = function(x) { - goog.reflect.sinkValue[' '](x); - return x; -}; - - -/** - * The compiler should optimize this function away iff no one ever uses - * goog.reflect.sinkValue. - */ -goog.reflect.sinkValue[' '] = goog.nullFunction; - - -/** - * Check if a property can be accessed without throwing an exception. - * @param {Object} obj The owner of the property. - * @param {string} prop The property name. - * @return {boolean} Whether the property is accessible. Will also return true - * if obj is null. - */ -goog.reflect.canAccessProperty = function(obj, prop) { - /** @preserveTry */ - try { - goog.reflect.sinkValue(obj[prop]); - return true; - } catch (e) {} - return false; -}; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A patched, standardized event object for browser events. - * - * <pre> - * The patched event object contains the following members: - * - type {string} Event type, e.g. 'click' - * - target {Object} The element that actually triggered the event - * - currentTarget {Object} The element the listener is attached to - * - relatedTarget {Object} For mouseover and mouseout, the previous object - * - offsetX {number} X-coordinate relative to target - * - offsetY {number} Y-coordinate relative to target - * - clientX {number} X-coordinate relative to viewport - * - clientY {number} Y-coordinate relative to viewport - * - screenX {number} X-coordinate relative to the edge of the screen - * - screenY {number} Y-coordinate relative to the edge of the screen - * - button {number} Mouse button. Use isButton() to test. - * - keyCode {number} Key-code - * - ctrlKey {boolean} Was ctrl key depressed - * - altKey {boolean} Was alt key depressed - * - shiftKey {boolean} Was shift key depressed - * - metaKey {boolean} Was meta key depressed - * - defaultPrevented {boolean} Whether the default action has been prevented - * - state {Object} History state object - * - * NOTE: The keyCode member contains the raw browser keyCode. For normalized - * key and character code use {@link goog.events.KeyHandler}. - * </pre> - * - * @author arv@google.com (Erik Arvidsson) - */ - -goog.provide('goog.events.BrowserEvent'); -goog.provide('goog.events.BrowserEvent.MouseButton'); - -goog.require('goog.events.BrowserFeature'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.reflect'); -goog.require('goog.userAgent'); - - - -/** - * Accepts a browser event object and creates a patched, cross browser event - * object. - * The content of this object will not be initialized if no event object is - * provided. If this is the case, init() needs to be invoked separately. - * @param {Event=} opt_e Browser event object. - * @param {EventTarget=} opt_currentTarget Current target for event. - * @constructor - * @extends {goog.events.Event} - */ -goog.events.BrowserEvent = function(opt_e, opt_currentTarget) { - goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : ''); - - /** - * Target that fired the event. - * @override - * @type {Node} - */ - this.target = null; - - /** - * Node that had the listener attached. - * @override - * @type {Node|undefined} - */ - this.currentTarget = null; - - /** - * For mouseover and mouseout events, the related object for the event. - * @type {Node} - */ - this.relatedTarget = null; - - /** - * X-coordinate relative to target. - * @type {number} - */ - this.offsetX = 0; - - /** - * Y-coordinate relative to target. - * @type {number} - */ - this.offsetY = 0; - - /** - * X-coordinate relative to the window. - * @type {number} - */ - this.clientX = 0; - - /** - * Y-coordinate relative to the window. - * @type {number} - */ - this.clientY = 0; - - /** - * X-coordinate relative to the monitor. - * @type {number} - */ - this.screenX = 0; - - /** - * Y-coordinate relative to the monitor. - * @type {number} - */ - this.screenY = 0; - - /** - * Which mouse button was pressed. - * @type {number} - */ - this.button = 0; - - /** - * Keycode of key press. - * @type {number} - */ - this.keyCode = 0; - - /** - * Keycode of key press. - * @type {number} - */ - this.charCode = 0; - - /** - * Whether control was pressed at time of event. - * @type {boolean} - */ - this.ctrlKey = false; - - /** - * Whether alt was pressed at time of event. - * @type {boolean} - */ - this.altKey = false; - - /** - * Whether shift was pressed at time of event. - * @type {boolean} - */ - this.shiftKey = false; - - /** - * Whether the meta key was pressed at time of event. - * @type {boolean} - */ - this.metaKey = false; - - /** - * History state object, only set for PopState events where it's a copy of the - * state object provided to pushState or replaceState. - * @type {Object} - */ - this.state = null; - - /** - * Whether the default platform modifier key was pressed at time of event. - * (This is control for all platforms except Mac, where it's Meta.) - * @type {boolean} - */ - this.platformModifierKey = false; - - /** - * The browser event object. - * @private {Event} - */ - this.event_ = null; - - if (opt_e) { - this.init(opt_e, opt_currentTarget); - } -}; -goog.inherits(goog.events.BrowserEvent, goog.events.Event); - - -/** - * Normalized button constants for the mouse. - * @enum {number} - */ -goog.events.BrowserEvent.MouseButton = { - LEFT: 0, - MIDDLE: 1, - RIGHT: 2 -}; - - -/** - * Static data for mapping mouse buttons. - * @type {!Array<number>} - */ -goog.events.BrowserEvent.IEButtonMap = [ - 1, // LEFT - 4, // MIDDLE - 2 // RIGHT -]; - - -/** - * Accepts a browser event object and creates a patched, cross browser event - * object. - * @param {Event} e Browser event object. - * @param {EventTarget=} opt_currentTarget Current target for event. - */ -goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) { - var type = this.type = e.type; - - /** - * On touch devices use the first "changed touch" as the relevant touch. - * @type {Touch} - */ - var relevantTouch = e.changedTouches ? e.changedTouches[0] : null; - - // TODO(nicksantos): Change this.target to type EventTarget. - this.target = /** @type {Node} */ (e.target) || e.srcElement; - - // TODO(nicksantos): Change this.currentTarget to type EventTarget. - this.currentTarget = /** @type {Node} */ (opt_currentTarget); - - var relatedTarget = /** @type {Node} */ (e.relatedTarget); - if (relatedTarget) { - // There's a bug in FireFox where sometimes, relatedTarget will be a - // chrome element, and accessing any property of it will get a permission - // denied exception. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=497780 - if (goog.userAgent.GECKO) { - if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) { - relatedTarget = null; - } - } - // TODO(arv): Use goog.events.EventType when it has been refactored into its - // own file. - } else if (type == goog.events.EventType.MOUSEOVER) { - relatedTarget = e.fromElement; - } else if (type == goog.events.EventType.MOUSEOUT) { - relatedTarget = e.toElement; - } - - this.relatedTarget = relatedTarget; - - if (!goog.isNull(relevantTouch)) { - this.clientX = relevantTouch.clientX !== undefined ? - relevantTouch.clientX : relevantTouch.pageX; - this.clientY = relevantTouch.clientY !== undefined ? - relevantTouch.clientY : relevantTouch.pageY; - this.screenX = relevantTouch.screenX || 0; - this.screenY = relevantTouch.screenY || 0; - } else { - // Webkit emits a lame warning whenever layerX/layerY is accessed. - // http://code.google.com/p/chromium/issues/detail?id=101733 - this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ? - e.offsetX : e.layerX; - this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ? - e.offsetY : e.layerY; - this.clientX = e.clientX !== undefined ? e.clientX : e.pageX; - this.clientY = e.clientY !== undefined ? e.clientY : e.pageY; - this.screenX = e.screenX || 0; - this.screenY = e.screenY || 0; - } - - this.button = e.button; - - this.keyCode = e.keyCode || 0; - this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0); - this.ctrlKey = e.ctrlKey; - this.altKey = e.altKey; - this.shiftKey = e.shiftKey; - this.metaKey = e.metaKey; - this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey; - this.state = e.state; - this.event_ = e; - if (e.defaultPrevented) { - this.preventDefault(); - } -}; - - -/** - * Tests to see which button was pressed during the event. This is really only - * useful in IE and Gecko browsers. And in IE, it's only useful for - * mousedown/mouseup events, because click only fires for the left mouse button. - * - * Safari 2 only reports the left button being clicked, and uses the value '1' - * instead of 0. Opera only reports a mousedown event for the middle button, and - * no mouse events for the right button. Opera has default behavior for left and - * middle click that can only be overridden via a configuration setting. - * - * There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html. - * - * @param {goog.events.BrowserEvent.MouseButton} button The button - * to test for. - * @return {boolean} True if button was pressed. - */ -goog.events.BrowserEvent.prototype.isButton = function(button) { - if (!goog.events.BrowserFeature.HAS_W3C_BUTTON) { - if (this.type == 'click') { - return button == goog.events.BrowserEvent.MouseButton.LEFT; - } else { - return !!(this.event_.button & - goog.events.BrowserEvent.IEButtonMap[button]); - } - } else { - return this.event_.button == button; - } -}; - - -/** - * Whether this has an "action"-producing mouse button. - * - * By definition, this includes left-click on windows/linux, and left-click - * without the ctrl key on Macs. - * - * @return {boolean} The result. - */ -goog.events.BrowserEvent.prototype.isMouseActionButton = function() { - // Webkit does not ctrl+click to be a right-click, so we - // normalize it to behave like Gecko and Opera. - return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) && - !(goog.userAgent.WEBKIT && goog.userAgent.MAC && this.ctrlKey); -}; - - -/** - * @override - */ -goog.events.BrowserEvent.prototype.stopPropagation = function() { - goog.events.BrowserEvent.superClass_.stopPropagation.call(this); - if (this.event_.stopPropagation) { - this.event_.stopPropagation(); - } else { - this.event_.cancelBubble = true; - } -}; - - -/** - * @override - */ -goog.events.BrowserEvent.prototype.preventDefault = function() { - goog.events.BrowserEvent.superClass_.preventDefault.call(this); - var be = this.event_; - if (!be.preventDefault) { - be.returnValue = false; - if (goog.events.BrowserFeature.SET_KEY_CODE_TO_PREVENT_DEFAULT) { - /** @preserveTry */ - try { - // Most keys can be prevented using returnValue. Some special keys - // require setting the keyCode to -1 as well: - // - // In IE7: - // F3, F5, F10, F11, Ctrl+P, Crtl+O, Ctrl+F (these are taken from IE6) - // - // In IE8: - // Ctrl+P, Crtl+O, Ctrl+F (F1-F12 cannot be stopped through the event) - // - // We therefore do this for all function keys as well as when Ctrl key - // is pressed. - var VK_F1 = 112; - var VK_F12 = 123; - if (be.ctrlKey || be.keyCode >= VK_F1 && be.keyCode <= VK_F12) { - be.keyCode = -1; - } - } catch (ex) { - // IE throws an 'access denied' exception when trying to change - // keyCode in some situations (e.g. srcElement is input[type=file], - // or srcElement is an anchor tag rewritten by parent's innerHTML). - // Do nothing in this case. - } - } - } else { - be.preventDefault(); - } -}; - - -/** - * @return {Event} The underlying browser event object. - */ -goog.events.BrowserEvent.prototype.getBrowserEvent = function() { - return this.event_; -}; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview An interface for a listenable JavaScript object. - * @author chrishenry@google.com (Chris Henry) - */ - -goog.provide('goog.events.Listenable'); -goog.provide('goog.events.ListenableKey'); - -/** @suppress {extraRequire} */ -goog.require('goog.events.EventId'); - - - -/** - * A listenable interface. A listenable is an object with the ability - * to dispatch/broadcast events to "event listeners" registered via - * listen/listenOnce. - * - * The interface allows for an event propagation mechanism similar - * to one offered by native browser event targets, such as - * capture/bubble mechanism, stopping propagation, and preventing - * default actions. Capture/bubble mechanism depends on the ancestor - * tree constructed via {@code #getParentEventTarget}; this tree - * must be directed acyclic graph. The meaning of default action(s) - * in preventDefault is specific to a particular use case. - * - * Implementations that do not support capture/bubble or can not have - * a parent listenable can simply not implement any ability to set the - * parent listenable (and have {@code #getParentEventTarget} return - * null). - * - * Implementation of this class can be used with or independently from - * goog.events. - * - * Implementation must call {@code #addImplementation(implClass)}. - * - * @interface - * @see goog.events - * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html - */ -goog.events.Listenable = function() {}; - - -/** - * An expando property to indicate that an object implements - * goog.events.Listenable. - * - * See addImplementation/isImplementedBy. - * - * @type {string} - * @const - */ -goog.events.Listenable.IMPLEMENTED_BY_PROP = - 'closure_listenable_' + ((Math.random() * 1e6) | 0); - - -/** - * Marks a given class (constructor) as an implementation of - * Listenable, do that we can query that fact at runtime. The class - * must have already implemented the interface. - * @param {!Function} cls The class constructor. The corresponding - * class must have already implemented the interface. - */ -goog.events.Listenable.addImplementation = function(cls) { - cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true; -}; - - -/** - * @param {Object} obj The object to check. - * @return {boolean} Whether a given instance implements Listenable. The - * class/superclass of the instance must call addImplementation. - */ -goog.events.Listenable.isImplementedBy = function(obj) { - return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]); -}; - - -/** - * Adds an event listener. A listener can only be added once to an - * object and if it is added again the key for the listener is - * returned. Note that if the existing listener is a one-off listener - * (registered via listenOnce), it will no longer be a one-off - * listener after a call to listen(). - * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @template SCOPE,EVENTOBJ - */ -goog.events.Listenable.prototype.listen; - - -/** - * Adds an event listener that is removed automatically after the - * listener fired once. - * - * If an existing listener already exists, listenOnce will do - * nothing. In particular, if the listener was previously registered - * via listen(), listenOnce() will not turn the listener into a - * one-off listener. Similarly, if there is already an existing - * one-off listener, listenOnce does not modify the listeners (it is - * still a once listener). - * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @template SCOPE,EVENTOBJ - */ -goog.events.Listenable.prototype.listenOnce; - - -/** - * Removes an event listener which was added with listen() or listenOnce(). - * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call - * the listener. - * @return {boolean} Whether any listener was removed. - * @template SCOPE,EVENTOBJ - */ -goog.events.Listenable.prototype.unlisten; - - -/** - * Removes an event listener which was added with listen() by the key - * returned by listen(). - * - * @param {goog.events.ListenableKey} key The key returned by - * listen() or listenOnce(). - * @return {boolean} Whether any listener was removed. - */ -goog.events.Listenable.prototype.unlistenByKey; - - -/** - * Dispatches an event (or event like object) and calls all listeners - * listening for events of this type. The type of the event is decided by the - * type property on the event object. - * - * If any of the listeners returns false OR calls preventDefault then this - * function will return false. If one of the capture listeners calls - * stopPropagation, then the bubble listeners won't fire. - * - * @param {goog.events.EventLike} e Event object. - * @return {boolean} If anyone called preventDefault on the event object (or - * if any of the listeners returns false) this will also return false. - */ -goog.events.Listenable.prototype.dispatchEvent; - - -/** - * Removes all listeners from this listenable. If type is specified, - * it will only remove listeners of the particular type. otherwise all - * registered listeners will be removed. - * - * @param {string=} opt_type Type of event to remove, default is to - * remove all types. - * @return {number} Number of listeners removed. - */ -goog.events.Listenable.prototype.removeAllListeners; - - -/** - * Returns the parent of this event target to use for capture/bubble - * mechanism. - * - * NOTE(chrishenry): The name reflects the original implementation of - * custom event target ({@code goog.events.EventTarget}). We decided - * that changing the name is not worth it. - * - * @return {goog.events.Listenable} The parent EventTarget or null if - * there is no parent. - */ -goog.events.Listenable.prototype.getParentEventTarget; - - -/** - * Fires all registered listeners in this listenable for the given - * type and capture mode, passing them the given eventObject. This - * does not perform actual capture/bubble. Only implementors of the - * interface should be using this. - * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the - * listeners to fire. - * @param {boolean} capture The capture mode of the listeners to fire. - * @param {EVENTOBJ} eventObject The event object to fire. - * @return {boolean} Whether all listeners succeeded without - * attempting to prevent default behavior. If any listener returns - * false or called goog.events.Event#preventDefault, this returns - * false. - * @template EVENTOBJ - */ -goog.events.Listenable.prototype.fireListeners; - - -/** - * Gets all listeners in this listenable for the given type and - * capture mode. - * - * @param {string|!goog.events.EventId} type The type of the listeners to fire. - * @param {boolean} capture The capture mode of the listeners to fire. - * @return {!Array<goog.events.ListenableKey>} An array of registered - * listeners. - * @template EVENTOBJ - */ -goog.events.Listenable.prototype.getListeners; - - -/** - * Gets the goog.events.ListenableKey for the event or null if no such - * listener is in use. - * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event - * without the 'on' prefix. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The - * listener function to get. - * @param {boolean} capture Whether the listener is a capturing listener. - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} the found listener or null if not found. - * @template SCOPE,EVENTOBJ - */ -goog.events.Listenable.prototype.getListener; - - -/** - * Whether there is any active listeners matching the specified - * signature. If either the type or capture parameters are - * unspecified, the function will match on the remaining criteria. - * - * @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type. - * @param {boolean=} opt_capture Whether to check for capture or bubble - * listeners. - * @return {boolean} Whether there is any active listeners matching - * the requested type and/or capture phase. - * @template EVENTOBJ - */ -goog.events.Listenable.prototype.hasListener; - - - -/** - * An interface that describes a single registered listener. - * @interface - */ -goog.events.ListenableKey = function() {}; - - -/** - * Counter used to create a unique key - * @type {number} - * @private - */ -goog.events.ListenableKey.counter_ = 0; - - -/** - * Reserves a key to be used for ListenableKey#key field. - * @return {number} A number to be used to fill ListenableKey#key - * field. - */ -goog.events.ListenableKey.reserveKey = function() { - return ++goog.events.ListenableKey.counter_; -}; - - -/** - * The source event target. - * @type {!(Object|goog.events.Listenable|goog.events.EventTarget)} - */ -goog.events.ListenableKey.prototype.src; - - -/** - * The event type the listener is listening to. - * @type {string} - */ -goog.events.ListenableKey.prototype.type; - - -/** - * The listener function. - * @type {function(?):?|{handleEvent:function(?):?}|null} - */ -goog.events.ListenableKey.prototype.listener; - - -/** - * Whether the listener works on capture phase. - * @type {boolean} - */ -goog.events.ListenableKey.prototype.capture; - - -/** - * The 'this' object for the listener function's scope. - * @type {Object} - */ -goog.events.ListenableKey.prototype.handler; - - -/** - * A globally unique number to identify the key. - * @type {number} - */ -goog.events.ListenableKey.prototype.key; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Listener object. - * @see ../demos/events.html - */ - -goog.provide('goog.events.Listener'); - -goog.require('goog.events.ListenableKey'); - - - -/** - * Simple class that stores information about a listener - * @param {!Function} listener Callback function. - * @param {Function} proxy Wrapper for the listener that patches the event. - * @param {EventTarget|goog.events.Listenable} src Source object for - * the event. - * @param {string} type Event type. - * @param {boolean} capture Whether in capture or bubble phase. - * @param {Object=} opt_handler Object in whose context to execute the callback. - * @implements {goog.events.ListenableKey} - * @constructor - */ -goog.events.Listener = function( - listener, proxy, src, type, capture, opt_handler) { - if (goog.events.Listener.ENABLE_MONITORING) { - this.creationStack = new Error().stack; - } - - /** - * Callback function. - * @type {Function} - */ - this.listener = listener; - - /** - * A wrapper over the original listener. This is used solely to - * handle native browser events (it is used to simulate the capture - * phase and to patch the event object). - * @type {Function} - */ - this.proxy = proxy; - - /** - * Object or node that callback is listening to - * @type {EventTarget|goog.events.Listenable} - */ - this.src = src; - - /** - * The event type. - * @const {string} - */ - this.type = type; - - /** - * Whether the listener is being called in the capture or bubble phase - * @const {boolean} - */ - this.capture = !!capture; - - /** - * Optional object whose context to execute the listener in - * @type {Object|undefined} - */ - this.handler = opt_handler; - - /** - * The key of the listener. - * @const {number} - * @override - */ - this.key = goog.events.ListenableKey.reserveKey(); - - /** - * Whether to remove the listener after it has been called. - * @type {boolean} - */ - this.callOnce = false; - - /** - * Whether the listener has been removed. - * @type {boolean} - */ - this.removed = false; -}; - - -/** - * @define {boolean} Whether to enable the monitoring of the - * goog.events.Listener instances. Switching on the monitoring is only - * recommended for debugging because it has a significant impact on - * performance and memory usage. If switched off, the monitoring code - * compiles down to 0 bytes. - */ -goog.define('goog.events.Listener.ENABLE_MONITORING', false); - - -/** - * If monitoring the goog.events.Listener instances is enabled, stores the - * creation stack trace of the Disposable instance. - * @type {string} - */ -goog.events.Listener.prototype.creationStack; - - -/** - * Marks this listener as removed. This also remove references held by - * this listener object (such as listener and event source). - */ -goog.events.Listener.prototype.markAsRemoved = function() { - this.removed = true; - this.listener = null; - this.proxy = null; - this.src = null; - this.handler = null; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A map of listeners that provides utility functions to - * deal with listeners on an event target. Used by - * {@code goog.events.EventTarget}. - * - * WARNING: Do not use this class from outside goog.events package. - * - * @visibility {//closure/goog/bin/sizetests:__pkg__} - * @visibility {//closure/goog/events:__pkg__} - * @visibility {//closure/goog/labs/events:__pkg__} - */ - -goog.provide('goog.events.ListenerMap'); - -goog.require('goog.array'); -goog.require('goog.events.Listener'); -goog.require('goog.object'); - - - -/** - * Creates a new listener map. - * @param {EventTarget|goog.events.Listenable} src The src object. - * @constructor - * @final - */ -goog.events.ListenerMap = function(src) { - /** @type {EventTarget|goog.events.Listenable} */ - this.src = src; - - /** - * Maps of event type to an array of listeners. - * @type {Object<string, !Array<!goog.events.Listener>>} - */ - this.listeners = {}; - - /** - * The count of types in this map that have registered listeners. - * @private {number} - */ - this.typeCount_ = 0; -}; - - -/** - * @return {number} The count of event types in this map that actually - * have registered listeners. - */ -goog.events.ListenerMap.prototype.getTypeCount = function() { - return this.typeCount_; -}; - - -/** - * @return {number} Total number of registered listeners. - */ -goog.events.ListenerMap.prototype.getListenerCount = function() { - var count = 0; - for (var type in this.listeners) { - count += this.listeners[type].length; - } - return count; -}; - - -/** - * Adds an event listener. A listener can only be added once to an - * object and if it is added again the key for the listener is - * returned. - * - * Note that a one-off listener will not change an existing listener, - * if any. On the other hand a normal listener will change existing - * one-off listener to become a normal listener. - * - * @param {string|!goog.events.EventId} type The listener event type. - * @param {!Function} listener This listener callback method. - * @param {boolean} callOnce Whether the listener is a one-off - * listener. - * @param {boolean=} opt_useCapture The capture mode of the listener. - * @param {Object=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - */ -goog.events.ListenerMap.prototype.add = function( - type, listener, callOnce, opt_useCapture, opt_listenerScope) { - var typeStr = type.toString(); - var listenerArray = this.listeners[typeStr]; - if (!listenerArray) { - listenerArray = this.listeners[typeStr] = []; - this.typeCount_++; - } - - var listenerObj; - var index = goog.events.ListenerMap.findListenerIndex_( - listenerArray, listener, opt_useCapture, opt_listenerScope); - if (index > -1) { - listenerObj = listenerArray[index]; - if (!callOnce) { - // Ensure that, if there is an existing callOnce listener, it is no - // longer a callOnce listener. - listenerObj.callOnce = false; - } - } else { - listenerObj = new goog.events.Listener( - listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope); - listenerObj.callOnce = callOnce; - listenerArray.push(listenerObj); - } - return listenerObj; -}; - - -/** - * Removes a matching listener. - * @param {string|!goog.events.EventId} type The listener event type. - * @param {!Function} listener This listener callback method. - * @param {boolean=} opt_useCapture The capture mode of the listener. - * @param {Object=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {boolean} Whether any listener was removed. - */ -goog.events.ListenerMap.prototype.remove = function( - type, listener, opt_useCapture, opt_listenerScope) { - var typeStr = type.toString(); - if (!(typeStr in this.listeners)) { - return false; - } - - var listenerArray = this.listeners[typeStr]; - var index = goog.events.ListenerMap.findListenerIndex_( - listenerArray, listener, opt_useCapture, opt_listenerScope); - if (index > -1) { - var listenerObj = listenerArray[index]; - listenerObj.markAsRemoved(); - goog.array.removeAt(listenerArray, index); - if (listenerArray.length == 0) { - delete this.listeners[typeStr]; - this.typeCount_--; - } - return true; - } - return false; -}; - - -/** - * Removes the given listener object. - * @param {goog.events.ListenableKey} listener The listener to remove. - * @return {boolean} Whether the listener is removed. - */ -goog.events.ListenerMap.prototype.removeByKey = function(listener) { - var type = listener.type; - if (!(type in this.listeners)) { - return false; - } - - var removed = goog.array.remove(this.listeners[type], listener); - if (removed) { - listener.markAsRemoved(); - if (this.listeners[type].length == 0) { - delete this.listeners[type]; - this.typeCount_--; - } - } - return removed; -}; - - -/** - * Removes all listeners from this map. If opt_type is provided, only - * listeners that match the given type are removed. - * @param {string|!goog.events.EventId=} opt_type Type of event to remove. - * @return {number} Number of listeners removed. - */ -goog.events.ListenerMap.prototype.removeAll = function(opt_type) { - var typeStr = opt_type && opt_type.toString(); - var count = 0; - for (var type in this.listeners) { - if (!typeStr || type == typeStr) { - var listenerArray = this.listeners[type]; - for (var i = 0; i < listenerArray.length; i++) { - ++count; - listenerArray[i].markAsRemoved(); - } - delete this.listeners[type]; - this.typeCount_--; - } - } - return count; -}; - - -/** - * Gets all listeners that match the given type and capture mode. The - * returned array is a copy (but the listener objects are not). - * @param {string|!goog.events.EventId} type The type of the listeners - * to retrieve. - * @param {boolean} capture The capture mode of the listeners to retrieve. - * @return {!Array<goog.events.ListenableKey>} An array of matching - * listeners. - */ -goog.events.ListenerMap.prototype.getListeners = function(type, capture) { - var listenerArray = this.listeners[type.toString()]; - var rv = []; - if (listenerArray) { - for (var i = 0; i < listenerArray.length; ++i) { - var listenerObj = listenerArray[i]; - if (listenerObj.capture == capture) { - rv.push(listenerObj); - } - } - } - return rv; -}; - - -/** - * Gets the goog.events.ListenableKey for the event or null if no such - * listener is in use. - * - * @param {string|!goog.events.EventId} type The type of the listener - * to retrieve. - * @param {!Function} listener The listener function to get. - * @param {boolean} capture Whether the listener is a capturing listener. - * @param {Object=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} the found listener or null if not found. - */ -goog.events.ListenerMap.prototype.getListener = function( - type, listener, capture, opt_listenerScope) { - var listenerArray = this.listeners[type.toString()]; - var i = -1; - if (listenerArray) { - i = goog.events.ListenerMap.findListenerIndex_( - listenerArray, listener, capture, opt_listenerScope); - } - return i > -1 ? listenerArray[i] : null; -}; - - -/** - * Whether there is a matching listener. If either the type or capture - * parameters are unspecified, the function will match on the - * remaining criteria. - * - * @param {string|!goog.events.EventId=} opt_type The type of the listener. - * @param {boolean=} opt_capture The capture mode of the listener. - * @return {boolean} Whether there is an active listener matching - * the requested type and/or capture phase. - */ -goog.events.ListenerMap.prototype.hasListener = function( - opt_type, opt_capture) { - var hasType = goog.isDef(opt_type); - var typeStr = hasType ? opt_type.toString() : ''; - var hasCapture = goog.isDef(opt_capture); - - return goog.object.some( - this.listeners, function(listenerArray, type) { - for (var i = 0; i < listenerArray.length; ++i) { - if ((!hasType || listenerArray[i].type == typeStr) && - (!hasCapture || listenerArray[i].capture == opt_capture)) { - return true; - } - } - - return false; - }); -}; - - -/** - * Finds the index of a matching goog.events.Listener in the given - * listenerArray. - * @param {!Array<!goog.events.Listener>} listenerArray Array of listener. - * @param {!Function} listener The listener function. - * @param {boolean=} opt_useCapture The capture flag for the listener. - * @param {Object=} opt_listenerScope The listener scope. - * @return {number} The index of the matching listener within the - * listenerArray. - * @private - */ -goog.events.ListenerMap.findListenerIndex_ = function( - listenerArray, listener, opt_useCapture, opt_listenerScope) { - for (var i = 0; i < listenerArray.length; ++i) { - var listenerObj = listenerArray[i]; - if (!listenerObj.removed && - listenerObj.listener == listener && - listenerObj.capture == !!opt_useCapture && - listenerObj.handler == opt_listenerScope) { - return i; - } - } - return -1; -}; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview An event manager for both native browser event - * targets and custom JavaScript event targets - * ({@code goog.events.Listenable}). This provides an abstraction - * over browsers' event systems. - * - * It also provides a simulation of W3C event model's capture phase in - * Internet Explorer (IE 8 and below). Caveat: the simulation does not - * interact well with listeners registered directly on the elements - * (bypassing goog.events) or even with listeners registered via - * goog.events in a separate JS binary. In these cases, we provide - * no ordering guarantees. - * - * The listeners will receive a "patched" event object. Such event object - * contains normalized values for certain event properties that differs in - * different browsers. - * - * Example usage: - * <pre> - * goog.events.listen(myNode, 'click', function(e) { alert('woo') }); - * goog.events.listen(myNode, 'mouseover', mouseHandler, true); - * goog.events.unlisten(myNode, 'mouseover', mouseHandler, true); - * goog.events.removeAll(myNode); - * </pre> - * - * in IE and event object patching] - * @author arv@google.com (Erik Arvidsson) - * - * @see ../demos/events.html - * @see ../demos/event-propagation.html - * @see ../demos/stopevent.html - */ - -// IMPLEMENTATION NOTES: -// goog.events stores an auxiliary data structure on each EventTarget -// source being listened on. This allows us to take advantage of GC, -// having the data structure GC'd when the EventTarget is GC'd. This -// GC behavior is equivalent to using W3C DOM Events directly. - -goog.provide('goog.events'); -goog.provide('goog.events.CaptureSimulationMode'); -goog.provide('goog.events.Key'); -goog.provide('goog.events.ListenableType'); - -goog.require('goog.asserts'); -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.BrowserFeature'); -goog.require('goog.events.Listenable'); -goog.require('goog.events.ListenerMap'); - -goog.forwardDeclare('goog.debug.ErrorHandler'); -goog.forwardDeclare('goog.events.EventWrapper'); - - -/** - * @typedef {number|goog.events.ListenableKey} - */ -goog.events.Key; - - -/** - * @typedef {EventTarget|goog.events.Listenable} - */ -goog.events.ListenableType; - - -/** - * Property name on a native event target for the listener map - * associated with the event target. - * @private @const {string} - */ -goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0); - - -/** - * String used to prepend to IE event types. - * @const - * @private - */ -goog.events.onString_ = 'on'; - - -/** - * Map of computed "on<eventname>" strings for IE event types. Caching - * this removes an extra object allocation in goog.events.listen which - * improves IE6 performance. - * @const - * @dict - * @private - */ -goog.events.onStringMap_ = {}; - - -/** - * @enum {number} Different capture simulation mode for IE8-. - */ -goog.events.CaptureSimulationMode = { - /** - * Does not perform capture simulation. Will asserts in IE8- when you - * add capture listeners. - */ - OFF_AND_FAIL: 0, - - /** - * Does not perform capture simulation, silently ignore capture - * listeners. - */ - OFF_AND_SILENT: 1, - - /** - * Performs capture simulation. - */ - ON: 2 -}; - - -/** - * @define {number} The capture simulation mode for IE8-. By default, - * this is ON. - */ -goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2); - - -/** - * Estimated count of total native listeners. - * @private {number} - */ -goog.events.listenerCountEstimate_ = 0; - - -/** - * Adds an event listener for a specific event on a native event - * target (such as a DOM element) or an object that has implemented - * {@link goog.events.Listenable}. A listener can only be added once - * to an object and if it is added again the key for the listener is - * returned. Note that if the existing listener is a one-off listener - * (registered via listenOnce), it will no longer be a one-off - * listener after a call to listen(). - * - * @param {EventTarget|goog.events.Listenable} src The node to listen - * to events on. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} - * listener Callback method, or an object with a handleEvent function. - * WARNING: passing an Object is now softly deprecated. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {T=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.Key} Unique key for the listener. - * @template T,EVENTOBJ - */ -goog.events.listen = function(src, type, listener, opt_capt, opt_handler) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - goog.events.listen(src, type[i], listener, opt_capt, opt_handler); - } - return null; - } - - listener = goog.events.wrapListener(listener); - if (goog.events.Listenable.isImplementedBy(src)) { - return src.listen( - /** @type {string|!goog.events.EventId} */ (type), - listener, opt_capt, opt_handler); - } else { - return goog.events.listen_( - /** @type {!EventTarget} */ (src), - /** @type {string|!goog.events.EventId} */ (type), - listener, /* callOnce */ false, opt_capt, opt_handler); - } -}; - - -/** - * Adds an event listener for a specific event on a native event - * target. A listener can only be added once to an object and if it - * is added again the key for the listener is returned. - * - * Note that a one-off listener will not change an existing listener, - * if any. On the other hand a normal listener will change existing - * one-off listener to become a normal listener. - * - * @param {EventTarget} src The node to listen to events on. - * @param {string|!goog.events.EventId} type Event type. - * @param {!Function} listener Callback function. - * @param {boolean} callOnce Whether the listener is a one-off - * listener or otherwise. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {Object=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @private - */ -goog.events.listen_ = function( - src, type, listener, callOnce, opt_capt, opt_handler) { - if (!type) { - throw Error('Invalid event type'); - } - - var capture = !!opt_capt; - if (capture && !goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { - if (goog.events.CAPTURE_SIMULATION_MODE == - goog.events.CaptureSimulationMode.OFF_AND_FAIL) { - goog.asserts.fail('Can not register capture listener in IE8-.'); - return null; - } else if (goog.events.CAPTURE_SIMULATION_MODE == - goog.events.CaptureSimulationMode.OFF_AND_SILENT) { - return null; - } - } - - var listenerMap = goog.events.getListenerMap_(src); - if (!listenerMap) { - src[goog.events.LISTENER_MAP_PROP_] = listenerMap = - new goog.events.ListenerMap(src); - } - - var listenerObj = listenerMap.add( - type, listener, callOnce, opt_capt, opt_handler); - - // If the listenerObj already has a proxy, it has been set up - // previously. We simply return. - if (listenerObj.proxy) { - return listenerObj; - } - - var proxy = goog.events.getProxy(); - listenerObj.proxy = proxy; - - proxy.src = src; - proxy.listener = listenerObj; - - // Attach the proxy through the browser's API - if (src.addEventListener) { - src.addEventListener(type.toString(), proxy, capture); - } else if (src.attachEvent) { - // The else if above used to be an unconditional else. It would call - // exception on IE11, spoiling the day of some callers. The previous - // incarnation of this code, from 2007, indicates that it replaced an - // earlier still version that caused excess allocations on IE6. - src.attachEvent(goog.events.getOnString_(type.toString()), proxy); - } else { - throw Error('addEventListener and attachEvent are unavailable.'); - } - - goog.events.listenerCountEstimate_++; - return listenerObj; -}; - - -/** - * Helper function for returning a proxy function. - * @return {!Function} A new or reused function object. - */ -goog.events.getProxy = function() { - var proxyCallbackFunction = goog.events.handleBrowserEvent_; - // Use a local var f to prevent one allocation. - var f = goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT ? - function(eventObject) { - return proxyCallbackFunction.call(f.src, f.listener, eventObject); - } : - function(eventObject) { - var v = proxyCallbackFunction.call(f.src, f.listener, eventObject); - // NOTE(chrishenry): In IE, we hack in a capture phase. However, if - // there is inline event handler which tries to prevent default (for - // example <a href="..." onclick="return false">...</a>) in a - // descendant element, the prevent default will be overridden - // by this listener if this listener were to return true. Hence, we - // return undefined. - if (!v) return v; - }; - return f; -}; - - -/** - * Adds an event listener for a specific event on a native event - * target (such as a DOM element) or an object that has implemented - * {@link goog.events.Listenable}. After the event has fired the event - * listener is removed from the target. - * - * If an existing listener already exists, listenOnce will do - * nothing. In particular, if the listener was previously registered - * via listen(), listenOnce() will not turn the listener into a - * one-off listener. Similarly, if there is already an existing - * one-off listener, listenOnce does not modify the listeners (it is - * still a once listener). - * - * @param {EventTarget|goog.events.Listenable} src The node to listen - * to events on. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} - * listener Callback method. - * @param {boolean=} opt_capt Fire in capture phase?. - * @param {T=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.Key} Unique key for the listener. - * @template T,EVENTOBJ - */ -goog.events.listenOnce = function(src, type, listener, opt_capt, opt_handler) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - goog.events.listenOnce(src, type[i], listener, opt_capt, opt_handler); - } - return null; - } - - listener = goog.events.wrapListener(listener); - if (goog.events.Listenable.isImplementedBy(src)) { - return src.listenOnce( - /** @type {string|!goog.events.EventId} */ (type), - listener, opt_capt, opt_handler); - } else { - return goog.events.listen_( - /** @type {!EventTarget} */ (src), - /** @type {string|!goog.events.EventId} */ (type), - listener, /* callOnce */ true, opt_capt, opt_handler); - } -}; - - -/** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.Listenable}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.Listenable} src The target to - * listen to events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener - * Callback method, or an object with a handleEvent function. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {T=} opt_handler Element in whose scope to call the listener. - * @template T - */ -goog.events.listenWithWrapper = function(src, wrapper, listener, opt_capt, - opt_handler) { - wrapper.listen(src, listener, opt_capt, opt_handler); -}; - - -/** - * Removes an event listener which was added with listen(). - * - * @param {EventTarget|goog.events.Listenable} src The target to stop - * listening to events on. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types to unlisten to. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener The - * listener function to remove. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase of the - * event. - * @param {Object=} opt_handler Element in whose scope to call the listener. - * @return {?boolean} indicating whether the listener was there to remove. - * @template EVENTOBJ - */ -goog.events.unlisten = function(src, type, listener, opt_capt, opt_handler) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - goog.events.unlisten(src, type[i], listener, opt_capt, opt_handler); - } - return null; - } - - listener = goog.events.wrapListener(listener); - if (goog.events.Listenable.isImplementedBy(src)) { - return src.unlisten( - /** @type {string|!goog.events.EventId} */ (type), - listener, opt_capt, opt_handler); - } - - if (!src) { - // TODO(chrishenry): We should tighten the API to only accept - // non-null objects, or add an assertion here. - return false; - } - - var capture = !!opt_capt; - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (src)); - if (listenerMap) { - var listenerObj = listenerMap.getListener( - /** @type {string|!goog.events.EventId} */ (type), - listener, capture, opt_handler); - if (listenerObj) { - return goog.events.unlistenByKey(listenerObj); - } - } - - return false; -}; - - -/** - * Removes an event listener which was added with listen() by the key - * returned by listen(). - * - * @param {goog.events.Key} key The key returned by listen() for this - * event listener. - * @return {boolean} indicating whether the listener was there to remove. - */ -goog.events.unlistenByKey = function(key) { - // TODO(chrishenry): Remove this check when tests that rely on this - // are fixed. - if (goog.isNumber(key)) { - return false; - } - - var listener = key; - if (!listener || listener.removed) { - return false; - } - - var src = listener.src; - if (goog.events.Listenable.isImplementedBy(src)) { - return src.unlistenByKey(listener); - } - - var type = listener.type; - var proxy = listener.proxy; - if (src.removeEventListener) { - src.removeEventListener(type, proxy, listener.capture); - } else if (src.detachEvent) { - src.detachEvent(goog.events.getOnString_(type), proxy); - } - goog.events.listenerCountEstimate_--; - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (src)); - // TODO(chrishenry): Try to remove this conditional and execute the - // first branch always. This should be safe. - if (listenerMap) { - listenerMap.removeByKey(listener); - if (listenerMap.getTypeCount() == 0) { - // Null the src, just because this is simple to do (and useful - // for IE <= 7). - listenerMap.src = null; - // We don't use delete here because IE does not allow delete - // on a window object. - src[goog.events.LISTENER_MAP_PROP_] = null; - } - } else { - listener.markAsRemoved(); - } - - return true; -}; - - -/** - * Removes an event listener which was added with listenWithWrapper(). - * - * @param {EventTarget|goog.events.Listenable} src The target to stop - * listening to events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener The - * listener function to remove. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase of the - * event. - * @param {Object=} opt_handler Element in whose scope to call the listener. - */ -goog.events.unlistenWithWrapper = function(src, wrapper, listener, opt_capt, - opt_handler) { - wrapper.unlisten(src, listener, opt_capt, opt_handler); -}; - - -/** - * Removes all listeners from an object. You can also optionally - * remove listeners of a particular type. - * - * @param {Object|undefined} obj Object to remove listeners from. Must be an - * EventTarget or a goog.events.Listenable. - * @param {string|!goog.events.EventId=} opt_type Type of event to remove. - * Default is all types. - * @return {number} Number of listeners removed. - */ -goog.events.removeAll = function(obj, opt_type) { - // TODO(chrishenry): Change the type of obj to - // (!EventTarget|!goog.events.Listenable). - - if (!obj) { - return 0; - } - - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.removeAllListeners(opt_type); - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (obj)); - if (!listenerMap) { - return 0; - } - - var count = 0; - var typeStr = opt_type && opt_type.toString(); - for (var type in listenerMap.listeners) { - if (!typeStr || type == typeStr) { - // Clone so that we don't need to worry about unlistenByKey - // changing the content of the ListenerMap. - var listeners = listenerMap.listeners[type].concat(); - for (var i = 0; i < listeners.length; ++i) { - if (goog.events.unlistenByKey(listeners[i])) { - ++count; - } - } - } - } - return count; -}; - - -/** - * Gets the listeners for a given object, type and capture phase. - * - * @param {Object} obj Object to get listeners for. - * @param {string|!goog.events.EventId} type Event type. - * @param {boolean} capture Capture phase?. - * @return {Array<goog.events.Listener>} Array of listener objects. - */ -goog.events.getListeners = function(obj, type, capture) { - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.getListeners(type, capture); - } else { - if (!obj) { - // TODO(chrishenry): We should tighten the API to accept - // !EventTarget|goog.events.Listenable, and add an assertion here. - return []; - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (obj)); - return listenerMap ? listenerMap.getListeners(type, capture) : []; - } -}; - - -/** - * Gets the goog.events.Listener for the event or null if no such listener is - * in use. - * - * @param {EventTarget|goog.events.Listenable} src The target from - * which to get listeners. - * @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The - * listener function to get. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the - * capture or bubble phase of the event. - * @param {Object=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.ListenableKey} the found listener or null if not found. - * @template EVENTOBJ - */ -goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) { - // TODO(chrishenry): Change type from ?string to string, or add assertion. - type = /** @type {string} */ (type); - listener = goog.events.wrapListener(listener); - var capture = !!opt_capt; - if (goog.events.Listenable.isImplementedBy(src)) { - return src.getListener(type, listener, capture, opt_handler); - } - - if (!src) { - // TODO(chrishenry): We should tighten the API to only accept - // non-null objects, or add an assertion here. - return null; - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (src)); - if (listenerMap) { - return listenerMap.getListener(type, listener, capture, opt_handler); - } - return null; -}; - - -/** - * Returns whether an event target has any active listeners matching the - * specified signature. If either the type or capture parameters are - * unspecified, the function will match on the remaining criteria. - * - * @param {EventTarget|goog.events.Listenable} obj Target to get - * listeners for. - * @param {string|!goog.events.EventId=} opt_type Event type. - * @param {boolean=} opt_capture Whether to check for capture or bubble-phase - * listeners. - * @return {boolean} Whether an event target has one or more listeners matching - * the requested type and/or capture phase. - */ -goog.events.hasListener = function(obj, opt_type, opt_capture) { - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.hasListener(opt_type, opt_capture); - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (obj)); - return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture); -}; - - -/** - * Provides a nice string showing the normalized event objects public members - * @param {Object} e Event Object. - * @return {string} String of the public members of the normalized event object. - */ -goog.events.expose = function(e) { - var str = []; - for (var key in e) { - if (e[key] && e[key].id) { - str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')'); - } else { - str.push(key + ' = ' + e[key]); - } - } - return str.join('\n'); -}; - - -/** - * Returns a string with on prepended to the specified type. This is used for IE - * which expects "on" to be prepended. This function caches the string in order - * to avoid extra allocations in steady state. - * @param {string} type Event type. - * @return {string} The type string with 'on' prepended. - * @private - */ -goog.events.getOnString_ = function(type) { - if (type in goog.events.onStringMap_) { - return goog.events.onStringMap_[type]; - } - return goog.events.onStringMap_[type] = goog.events.onString_ + type; -}; - - -/** - * Fires an object's listeners of a particular type and phase - * - * @param {Object} obj Object whose listeners to call. - * @param {string|!goog.events.EventId} type Event type. - * @param {boolean} capture Which event phase. - * @param {Object} eventObject Event object to be passed to listener. - * @return {boolean} True if all listeners returned true else false. - */ -goog.events.fireListeners = function(obj, type, capture, eventObject) { - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.fireListeners(type, capture, eventObject); - } - - return goog.events.fireListeners_(obj, type, capture, eventObject); -}; - - -/** - * Fires an object's listeners of a particular type and phase. - * @param {Object} obj Object whose listeners to call. - * @param {string|!goog.events.EventId} type Event type. - * @param {boolean} capture Which event phase. - * @param {Object} eventObject Event object to be passed to listener. - * @return {boolean} True if all listeners returned true else false. - * @private - */ -goog.events.fireListeners_ = function(obj, type, capture, eventObject) { - /** @type {boolean} */ - var retval = true; - - var listenerMap = goog.events.getListenerMap_( - /** @type {EventTarget} */ (obj)); - if (listenerMap) { - // TODO(chrishenry): Original code avoids array creation when there - // is no listener, so we do the same. If this optimization turns - // out to be not required, we can replace this with - // listenerMap.getListeners(type, capture) instead, which is simpler. - var listenerArray = listenerMap.listeners[type.toString()]; - if (listenerArray) { - listenerArray = listenerArray.concat(); - for (var i = 0; i < listenerArray.length; i++) { - var listener = listenerArray[i]; - // We might not have a listener if the listener was removed. - if (listener && listener.capture == capture && !listener.removed) { - var result = goog.events.fireListener(listener, eventObject); - retval = retval && (result !== false); - } - } - } - } - return retval; -}; - - -/** - * Fires a listener with a set of arguments - * - * @param {goog.events.Listener} listener The listener object to call. - * @param {Object} eventObject The event object to pass to the listener. - * @return {boolean} Result of listener. - */ -goog.events.fireListener = function(listener, eventObject) { - var listenerFn = listener.listener; - var listenerHandler = listener.handler || listener.src; - - if (listener.callOnce) { - goog.events.unlistenByKey(listener); - } - return listenerFn.call(listenerHandler, eventObject); -}; - - -/** - * Gets the total number of listeners currently in the system. - * @return {number} Number of listeners. - * @deprecated This returns estimated count, now that Closure no longer - * stores a central listener registry. We still return an estimation - * to keep existing listener-related tests passing. In the near future, - * this function will be removed. - */ -goog.events.getTotalListenerCount = function() { - return goog.events.listenerCountEstimate_; -}; - - -/** - * Dispatches an event (or event like object) and calls all listeners - * listening for events of this type. The type of the event is decided by the - * type property on the event object. - * - * If any of the listeners returns false OR calls preventDefault then this - * function will return false. If one of the capture listeners calls - * stopPropagation, then the bubble listeners won't fire. - * - * @param {goog.events.Listenable} src The event target. - * @param {goog.events.EventLike} e Event object. - * @return {boolean} If anyone called preventDefault on the event object (or - * if any of the handlers returns false) this will also return false. - * If there are no handlers, or if all handlers return true, this returns - * true. - */ -goog.events.dispatchEvent = function(src, e) { - goog.asserts.assert( - goog.events.Listenable.isImplementedBy(src), - 'Can not use goog.events.dispatchEvent with ' + - 'non-goog.events.Listenable instance.'); - return src.dispatchEvent(e); -}; - - -/** - * Installs exception protection for the browser event entry point using the - * given error handler. - * - * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry point. - */ -goog.events.protectBrowserEventEntryPoint = function(errorHandler) { - goog.events.handleBrowserEvent_ = errorHandler.protectEntryPoint( - goog.events.handleBrowserEvent_); -}; - - -/** - * Handles an event and dispatches it to the correct listeners. This - * function is a proxy for the real listener the user specified. - * - * @param {goog.events.Listener} listener The listener object. - * @param {Event=} opt_evt Optional event object that gets passed in via the - * native event handlers. - * @return {boolean} Result of the event handler. - * @this {EventTarget} The object or Element that fired the event. - * @private - */ -goog.events.handleBrowserEvent_ = function(listener, opt_evt) { - if (listener.removed) { - return true; - } - - // Synthesize event propagation if the browser does not support W3C - // event model. - if (!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { - var ieEvent = opt_evt || - /** @type {Event} */ (goog.getObjectByName('window.event')); - var evt = new goog.events.BrowserEvent(ieEvent, this); - /** @type {boolean} */ - var retval = true; - - if (goog.events.CAPTURE_SIMULATION_MODE == - goog.events.CaptureSimulationMode.ON) { - // If we have not marked this event yet, we should perform capture - // simulation. - if (!goog.events.isMarkedIeEvent_(ieEvent)) { - goog.events.markIeEvent_(ieEvent); - - var ancestors = []; - for (var parent = evt.currentTarget; parent; - parent = parent.parentNode) { - ancestors.push(parent); - } - - // Fire capture listeners. - var type = listener.type; - for (var i = ancestors.length - 1; !evt.propagationStopped_ && i >= 0; - i--) { - evt.currentTarget = ancestors[i]; - var result = goog.events.fireListeners_(ancestors[i], type, true, evt); - retval = retval && result; - } - - // Fire bubble listeners. - // - // We can technically rely on IE to perform bubble event - // propagation. However, it turns out that IE fires events in - // opposite order of attachEvent registration, which broke - // some code and tests that rely on the order. (While W3C DOM - // Level 2 Events TR leaves the event ordering unspecified, - // modern browsers and W3C DOM Level 3 Events Working Draft - // actually specify the order as the registration order.) - for (var i = 0; !evt.propagationStopped_ && i < ancestors.length; i++) { - evt.currentTarget = ancestors[i]; - var result = goog.events.fireListeners_(ancestors[i], type, false, evt); - retval = retval && result; - } - } - } else { - retval = goog.events.fireListener(listener, evt); - } - return retval; - } - - // Otherwise, simply fire the listener. - return goog.events.fireListener( - listener, new goog.events.BrowserEvent(opt_evt, this)); -}; - - -/** - * This is used to mark the IE event object so we do not do the Closure pass - * twice for a bubbling event. - * @param {Event} e The IE browser event. - * @private - */ -goog.events.markIeEvent_ = function(e) { - // Only the keyCode and the returnValue can be changed. We use keyCode for - // non keyboard events. - // event.returnValue is a bit more tricky. It is undefined by default. A - // boolean false prevents the default action. In a window.onbeforeunload and - // the returnValue is non undefined it will be alerted. However, we will only - // modify the returnValue for keyboard events. We can get a problem if non - // closure events sets the keyCode or the returnValue - - var useReturnValue = false; - - if (e.keyCode == 0) { - // We cannot change the keyCode in case that srcElement is input[type=file]. - // We could test that that is the case but that would allocate 3 objects. - // If we use try/catch we will only allocate extra objects in the case of a - // failure. - /** @preserveTry */ - try { - e.keyCode = -1; - return; - } catch (ex) { - useReturnValue = true; - } - } - - if (useReturnValue || - /** @type {boolean|undefined} */ (e.returnValue) == undefined) { - e.returnValue = true; - } -}; - - -/** - * This is used to check if an IE event has already been handled by the Closure - * system so we do not do the Closure pass twice for a bubbling event. - * @param {Event} e The IE browser event. - * @return {boolean} True if the event object has been marked. - * @private - */ -goog.events.isMarkedIeEvent_ = function(e) { - return e.keyCode < 0 || e.returnValue != undefined; -}; - - -/** - * Counter to create unique event ids. - * @private {number} - */ -goog.events.uniqueIdCounter_ = 0; - - -/** - * Creates a unique event id. - * - * @param {string} identifier The identifier. - * @return {string} A unique identifier. - * @idGenerator - */ -goog.events.getUniqueId = function(identifier) { - return identifier + '_' + goog.events.uniqueIdCounter_++; -}; - - -/** - * @param {EventTarget} src The source object. - * @return {goog.events.ListenerMap} A listener map for the given - * source object, or null if none exists. - * @private - */ -goog.events.getListenerMap_ = function(src) { - var listenerMap = src[goog.events.LISTENER_MAP_PROP_]; - // IE serializes the property as well (e.g. when serializing outer - // HTML). So we must check that the value is of the correct type. - return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null; -}; - - -/** - * Expando property for listener function wrapper for Object with - * handleEvent. - * @private @const {string} - */ -goog.events.LISTENER_WRAPPER_PROP_ = '__closure_events_fn_' + - ((Math.random() * 1e9) >>> 0); - - -/** - * @param {Object|Function} listener The listener function or an - * object that contains handleEvent method. - * @return {!Function} Either the original function or a function that - * calls obj.handleEvent. If the same listener is passed to this - * function more than once, the same function is guaranteed to be - * returned. - */ -goog.events.wrapListener = function(listener) { - goog.asserts.assert(listener, 'Listener can not be null.'); - - if (goog.isFunction(listener)) { - return listener; - } - - goog.asserts.assert( - listener.handleEvent, 'An object listener must have handleEvent method.'); - if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) { - listener[goog.events.LISTENER_WRAPPER_PROP_] = - function(e) { return listener.handleEvent(e); }; - } - return listener[goog.events.LISTENER_WRAPPER_PROP_]; -}; - - -// Register the browser event handler as an entry point, so that -// it can be monitored for exception handling, etc. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.events.handleBrowserEvent_ = transformer( - goog.events.handleBrowserEvent_); - }); - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A disposable implementation of a custom - * listenable/event target. See also: documentation for - * {@code goog.events.Listenable}. - * - * @author arv@google.com (Erik Arvidsson) [Original implementation] - * @see ../demos/eventtarget.html - * @see goog.events.Listenable - */ - -goog.provide('goog.events.EventTarget'); - -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.Listenable'); -goog.require('goog.events.ListenerMap'); -goog.require('goog.object'); - - - -/** - * An implementation of {@code goog.events.Listenable} with full W3C - * EventTarget-like support (capture/bubble mechanism, stopping event - * propagation, preventing default actions). - * - * You may subclass this class to turn your class into a Listenable. - * - * Unless propagation is stopped, an event dispatched by an - * EventTarget will bubble to the parent returned by - * {@code getParentEventTarget}. To set the parent, call - * {@code setParentEventTarget}. Subclasses that don't support - * changing the parent can override the setter to throw an error. - * - * Example usage: - * <pre> - * var source = new goog.events.EventTarget(); - * function handleEvent(e) { - * alert('Type: ' + e.type + '; Target: ' + e.target); - * } - * source.listen('foo', handleEvent); - * // Or: goog.events.listen(source, 'foo', handleEvent); - * ... - * source.dispatchEvent('foo'); // will call handleEvent - * ... - * source.unlisten('foo', handleEvent); - * // Or: goog.events.unlisten(source, 'foo', handleEvent); - * </pre> - * - * @constructor - * @extends {goog.Disposable} - * @implements {goog.events.Listenable} - */ -goog.events.EventTarget = function() { - goog.Disposable.call(this); - - /** - * Maps of event type to an array of listeners. - * @private {!goog.events.ListenerMap} - */ - this.eventTargetListeners_ = new goog.events.ListenerMap(this); - - /** - * The object to use for event.target. Useful when mixing in an - * EventTarget to another object. - * @private {!Object} - */ - this.actualEventTarget_ = this; - - /** - * Parent event target, used during event bubbling. - * - * TODO(chrishenry): Change this to goog.events.Listenable. This - * currently breaks people who expect getParentEventTarget to return - * goog.events.EventTarget. - * - * @private {goog.events.EventTarget} - */ - this.parentEventTarget_ = null; -}; -goog.inherits(goog.events.EventTarget, goog.Disposable); -goog.events.Listenable.addImplementation(goog.events.EventTarget); - - -/** - * An artificial cap on the number of ancestors you can have. This is mainly - * for loop detection. - * @const {number} - * @private - */ -goog.events.EventTarget.MAX_ANCESTORS_ = 1000; - - -/** - * Returns the parent of this event target to use for bubbling. - * - * @return {goog.events.EventTarget} The parent EventTarget or null if - * there is no parent. - * @override - */ -goog.events.EventTarget.prototype.getParentEventTarget = function() { - return this.parentEventTarget_; -}; - - -/** - * Sets the parent of this event target to use for capture/bubble - * mechanism. - * @param {goog.events.EventTarget} parent Parent listenable (null if none). - */ -goog.events.EventTarget.prototype.setParentEventTarget = function(parent) { - this.parentEventTarget_ = parent; -}; - - -/** - * Adds an event listener to the event target. The same handler can only be - * added once per the type. Even if you add the same handler multiple times - * using the same type then it will only be called once when the event is - * dispatched. - * - * @param {string} type The type of the event to listen for. - * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function - * to handle the event. The handler can also be an object that implements - * the handleEvent method which takes the event object as argument. - * @param {boolean=} opt_capture In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase - * of the event. - * @param {Object=} opt_handlerScope Object in whose scope to call - * the listener. - * @deprecated Use {@code #listen} instead, when possible. Otherwise, use - * {@code goog.events.listen} if you are passing Object - * (instead of Function) as handler. - */ -goog.events.EventTarget.prototype.addEventListener = function( - type, handler, opt_capture, opt_handlerScope) { - goog.events.listen(this, type, handler, opt_capture, opt_handlerScope); -}; - - -/** - * Removes an event listener from the event target. The handler must be the - * same object as the one added. If the handler has not been added then - * nothing is done. - * - * @param {string} type The type of the event to listen for. - * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function - * to handle the event. The handler can also be an object that implements - * the handleEvent method which takes the event object as argument. - * @param {boolean=} opt_capture In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase - * of the event. - * @param {Object=} opt_handlerScope Object in whose scope to call - * the listener. - * @deprecated Use {@code #unlisten} instead, when possible. Otherwise, use - * {@code goog.events.unlisten} if you are passing Object - * (instead of Function) as handler. - */ -goog.events.EventTarget.prototype.removeEventListener = function( - type, handler, opt_capture, opt_handlerScope) { - goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.dispatchEvent = function(e) { - this.assertInitialized_(); - - var ancestorsTree, ancestor = this.getParentEventTarget(); - if (ancestor) { - ancestorsTree = []; - var ancestorCount = 1; - for (; ancestor; ancestor = ancestor.getParentEventTarget()) { - ancestorsTree.push(ancestor); - goog.asserts.assert( - (++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_), - 'infinite loop'); - } - } - - return goog.events.EventTarget.dispatchEventInternal_( - this.actualEventTarget_, e, ancestorsTree); -}; - - -/** - * Removes listeners from this object. Classes that extend EventTarget may - * need to override this method in order to remove references to DOM Elements - * and additional listeners. - * @override - */ -goog.events.EventTarget.prototype.disposeInternal = function() { - goog.events.EventTarget.superClass_.disposeInternal.call(this); - - this.removeAllListeners(); - this.parentEventTarget_ = null; -}; - - -/** @override */ -goog.events.EventTarget.prototype.listen = function( - type, listener, opt_useCapture, opt_listenerScope) { - this.assertInitialized_(); - return this.eventTargetListeners_.add( - String(type), listener, false /* callOnce */, opt_useCapture, - opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.listenOnce = function( - type, listener, opt_useCapture, opt_listenerScope) { - return this.eventTargetListeners_.add( - String(type), listener, true /* callOnce */, opt_useCapture, - opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.unlisten = function( - type, listener, opt_useCapture, opt_listenerScope) { - return this.eventTargetListeners_.remove( - String(type), listener, opt_useCapture, opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.unlistenByKey = function(key) { - return this.eventTargetListeners_.removeByKey(key); -}; - - -/** @override */ -goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) { - // TODO(chrishenry): Previously, removeAllListeners can be called on - // uninitialized EventTarget, so we preserve that behavior. We - // should remove this when usages that rely on that fact are purged. - if (!this.eventTargetListeners_) { - return 0; - } - return this.eventTargetListeners_.removeAll(opt_type); -}; - - -/** @override */ -goog.events.EventTarget.prototype.fireListeners = function( - type, capture, eventObject) { - // TODO(chrishenry): Original code avoids array creation when there - // is no listener, so we do the same. If this optimization turns - // out to be not required, we can replace this with - // getListeners(type, capture) instead, which is simpler. - var listenerArray = this.eventTargetListeners_.listeners[String(type)]; - if (!listenerArray) { - return true; - } - listenerArray = listenerArray.concat(); - - var rv = true; - for (var i = 0; i < listenerArray.length; ++i) { - var listener = listenerArray[i]; - // We might not have a listener if the listener was removed. - if (listener && !listener.removed && listener.capture == capture) { - var listenerFn = listener.listener; - var listenerHandler = listener.handler || listener.src; - - if (listener.callOnce) { - this.unlistenByKey(listener); - } - rv = listenerFn.call(listenerHandler, eventObject) !== false && rv; - } - } - - return rv && eventObject.returnValue_ != false; -}; - - -/** @override */ -goog.events.EventTarget.prototype.getListeners = function(type, capture) { - return this.eventTargetListeners_.getListeners(String(type), capture); -}; - - -/** @override */ -goog.events.EventTarget.prototype.getListener = function( - type, listener, capture, opt_listenerScope) { - return this.eventTargetListeners_.getListener( - String(type), listener, capture, opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.hasListener = function( - opt_type, opt_capture) { - var id = goog.isDef(opt_type) ? String(opt_type) : undefined; - return this.eventTargetListeners_.hasListener(id, opt_capture); -}; - - -/** - * Sets the target to be used for {@code event.target} when firing - * event. Mainly used for testing. For example, see - * {@code goog.testing.events.mixinListenable}. - * @param {!Object} target The target. - */ -goog.events.EventTarget.prototype.setTargetForTesting = function(target) { - this.actualEventTarget_ = target; -}; - - -/** - * Asserts that the event target instance is initialized properly. - * @private - */ -goog.events.EventTarget.prototype.assertInitialized_ = function() { - goog.asserts.assert( - this.eventTargetListeners_, - 'Event target is not initialized. Did you call the superclass ' + - '(goog.events.EventTarget) constructor?'); -}; - - -/** - * Dispatches the given event on the ancestorsTree. - * - * @param {!Object} target The target to dispatch on. - * @param {goog.events.Event|Object|string} e The event object. - * @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors - * tree of the target, in reverse order from the closest ancestor - * to the root event target. May be null if the target has no ancestor. - * @return {boolean} If anyone called preventDefault on the event object (or - * if any of the listeners returns false) this will also return false. - * @private - */ -goog.events.EventTarget.dispatchEventInternal_ = function( - target, e, opt_ancestorsTree) { - var type = e.type || /** @type {string} */ (e); - - // If accepting a string or object, create a custom event object so that - // preventDefault and stopPropagation work with the event. - if (goog.isString(e)) { - e = new goog.events.Event(e, target); - } else if (!(e instanceof goog.events.Event)) { - var oldEvent = e; - e = new goog.events.Event(type, target); - goog.object.extend(e, oldEvent); - } else { - e.target = e.target || target; - } - - var rv = true, currentTarget; - - // Executes all capture listeners on the ancestors, if any. - if (opt_ancestorsTree) { - for (var i = opt_ancestorsTree.length - 1; !e.propagationStopped_ && i >= 0; - i--) { - currentTarget = e.currentTarget = opt_ancestorsTree[i]; - rv = currentTarget.fireListeners(type, true, e) && rv; - } - } - - // Executes capture and bubble listeners on the target. - if (!e.propagationStopped_) { - currentTarget = e.currentTarget = target; - rv = currentTarget.fireListeners(type, true, e) && rv; - if (!e.propagationStopped_) { - rv = currentTarget.fireListeners(type, false, e) && rv; - } - } - - // Executes all bubble listeners on the ancestors, if any. - if (opt_ancestorsTree) { - for (i = 0; !e.propagationStopped_ && i < opt_ancestorsTree.length; i++) { - currentTarget = e.currentTarget = opt_ancestorsTree[i]; - rv = currentTarget.fireListeners(type, false, e) && rv; - } - } - - return rv; -}; - -goog.provide('ol.Observable'); - -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * An event target providing convenient methods for listener registration - * and unregistration. A generic `change` event is always available through - * {@link ol.Observable#changed}. - * - * @constructor - * @extends {goog.events.EventTarget} - * @fires change - * @struct - * @api stable - */ -ol.Observable = function() { - - goog.base(this); - - /** - * @private - * @type {number} - */ - this.revision_ = 0; - -}; -goog.inherits(ol.Observable, goog.events.EventTarget); - - -/** - * Removes an event listener using the key returned by `on()` or `once()`. - * @param {goog.events.Key} key The key returned by `on()` or `once()`. - * @api stable - */ -ol.Observable.unByKey = function(key) { - goog.events.unlistenByKey(key); -}; - - -/** - * Increases the revision counter and dispatches a 'change' event. - * @api - */ -ol.Observable.prototype.changed = function() { - ++this.revision_; - this.dispatchEvent(goog.events.EventType.CHANGE); -}; - - -/** - * Triggered when the revision counter is increased. - * @event change - * @api - */ - - -/** - * Dispatches an event and calls all listeners listening for events - * of this type. The event parameter can either be a string or an - * Object with a `type` property. - * - * @param {goog.events.EventLike} event Event object. - * @function - * @api - */ -ol.Observable.prototype.dispatchEvent; - - -/** - * Get the version number for this object. Each time the object is modified, - * its version number will be incremented. - * @return {number} Revision. - * @api - */ -ol.Observable.prototype.getRevision = function() { - return this.revision_; -}; - - -/** - * Listen for a certain type of event. - * @param {string|Array.<string>} type The event type or array of event types. - * @param {function(?): ?} listener The listener function. - * @param {Object=} opt_this The object to use as `this` in `listener`. - * @return {goog.events.Key} Unique key for the listener. - * @api stable - */ -ol.Observable.prototype.on = function(type, listener, opt_this) { - return goog.events.listen(this, type, listener, false, opt_this); -}; - - -/** - * Listen once for a certain type of event. - * @param {string|Array.<string>} type The event type or array of event types. - * @param {function(?): ?} listener The listener function. - * @param {Object=} opt_this The object to use as `this` in `listener`. - * @return {goog.events.Key} Unique key for the listener. - * @api stable - */ -ol.Observable.prototype.once = function(type, listener, opt_this) { - return goog.events.listenOnce(this, type, listener, false, opt_this); -}; - - -/** - * Unlisten for a certain type of event. - * @param {string|Array.<string>} type The event type or array of event types. - * @param {function(?): ?} listener The listener function. - * @param {Object=} opt_this The object which was used as `this` by the - * `listener`. - * @api stable - */ -ol.Observable.prototype.un = function(type, listener, opt_this) { - goog.events.unlisten(this, type, listener, false, opt_this); -}; - - -/** - * Removes an event listener using the key returned by `on()` or `once()`. - * Note that using the {@link ol.Observable.unByKey} static function is to - * be preferred. - * @param {goog.events.Key} key The key returned by `on()` or `once()`. - * @function - * @api stable - */ -ol.Observable.prototype.unByKey = ol.Observable.unByKey; - -goog.provide('ol.Object'); -goog.provide('ol.ObjectEvent'); -goog.provide('ol.ObjectEventType'); - -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('ol.Observable'); - - -/** - * @enum {string} - */ -ol.ObjectEventType = { - /** - * Triggered when a property is changed. - * @event ol.ObjectEvent#propertychange - * @api stable - */ - PROPERTYCHANGE: 'propertychange' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.Object} instances are instances of this type. - * - * @param {string} type The event type. - * @param {string} key The property name. - * @param {*} oldValue The old value for `key`. - * @extends {goog.events.Event} - * @implements {oli.ObjectEvent} - * @constructor - */ -ol.ObjectEvent = function(type, key, oldValue) { - goog.base(this, type); - - /** - * The name of the property whose value is changing. - * @type {string} - * @api stable - */ - this.key = key; - - /** - * The old value. To get the new value use `e.target.get(e.key)` where - * `e` is the event object. - * @type {*} - * @api stable - */ - this.oldValue = oldValue; - -}; -goog.inherits(ol.ObjectEvent, goog.events.Event); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Most non-trivial classes inherit from this. - * - * This extends {@link ol.Observable} with observable properties, where each - * property is observable as well as the object as a whole. - * - * Classes that inherit from this have pre-defined properties, to which you can - * add your owns. The pre-defined properties are listed in this documentation as - * 'Observable Properties', and have their own accessors; for example, - * {@link ol.Map} has a `target` property, accessed with `getTarget()` and - * changed with `setTarget()`. Not all properties are however settable. There - * are also general-purpose accessors `get()` and `set()`. For example, - * `get('target')` is equivalent to `getTarget()`. - * - * The `set` accessors trigger a change event, and you can monitor this by - * registering a listener. For example, {@link ol.View} has a `center` - * property, so `view.on('change:center', function(evt) {...});` would call the - * function whenever the value of the center property changes. Within the - * function, `evt.target` would be the view, so `evt.target.getCenter()` would - * return the new center. - * - * You can add your own observable properties with - * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`. - * You can listen for changes on that property value with - * `object.on('change:prop', listener)`. You can get a list of all - * properties with {@link ol.Object#getProperties object.getProperties()}. - * - * Note that the observable properties are separate from standard JS properties. - * You can, for example, give your map object a title with - * `map.title='New title'` and with `map.set('title', 'Another title')`. The - * first will be a `hasOwnProperty`; the second will appear in - * `getProperties()`. Only the second is observable. - * - * Properties can be deleted by using the unset method. E.g. - * object.unset('foo'). - * - * @constructor - * @extends {ol.Observable} - * @param {Object.<string, *>=} opt_values An object with key-value pairs. - * @fires ol.ObjectEvent - * @api - */ -ol.Object = function(opt_values) { - goog.base(this); - - // Call goog.getUid to ensure that the order of objects' ids is the same as - // the order in which they were created. This also helps to ensure that - // object properties are always added in the same order, which helps many - // JavaScript engines generate faster code. - goog.getUid(this); - - /** - * @private - * @type {!Object.<string, *>} - */ - this.values_ = {}; - - if (opt_values !== undefined) { - this.setProperties(opt_values); - } -}; -goog.inherits(ol.Object, ol.Observable); - - -/** - * @private - * @type {Object.<string, string>} - */ -ol.Object.changeEventTypeCache_ = {}; - - -/** - * @param {string} key Key name. - * @return {string} Change name. - */ -ol.Object.getChangeEventType = function(key) { - return ol.Object.changeEventTypeCache_.hasOwnProperty(key) ? - ol.Object.changeEventTypeCache_[key] : - (ol.Object.changeEventTypeCache_[key] = 'change:' + key); -}; - - -/** - * Gets a value. - * @param {string} key Key name. - * @return {*} Value. - * @api stable - */ -ol.Object.prototype.get = function(key) { - var value; - if (this.values_.hasOwnProperty(key)) { - value = this.values_[key]; - } - return value; -}; - - -/** - * Get a list of object property names. - * @return {Array.<string>} List of property names. - * @api stable - */ -ol.Object.prototype.getKeys = function() { - return Object.keys(this.values_); -}; - - -/** - * Get an object of all property names and values. - * @return {Object.<string, *>} Object. - * @api stable - */ -ol.Object.prototype.getProperties = function() { - var properties = {}; - var key; - for (key in this.values_) { - properties[key] = this.values_[key]; - } - return properties; -}; - - -/** - * @param {string} key Key name. - * @param {*} oldValue Old value. - */ -ol.Object.prototype.notify = function(key, oldValue) { - var eventType; - eventType = ol.Object.getChangeEventType(key); - this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue)); - eventType = ol.ObjectEventType.PROPERTYCHANGE; - this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue)); -}; - - -/** - * Sets a value. - * @param {string} key Key name. - * @param {*} value Value. - * @param {boolean=} opt_silent Update without triggering an event. - * @api stable - */ -ol.Object.prototype.set = function(key, value, opt_silent) { - if (opt_silent) { - this.values_[key] = value; - } else { - var oldValue = this.values_[key]; - this.values_[key] = value; - if (oldValue !== value) { - this.notify(key, oldValue); - } - } -}; - - -/** - * Sets a collection of key-value pairs. Note that this changes any existing - * properties and adds new ones (it does not remove any existing properties). - * @param {Object.<string, *>} values Values. - * @param {boolean=} opt_silent Update without triggering an event. - * @api stable - */ -ol.Object.prototype.setProperties = function(values, opt_silent) { - var key; - for (key in values) { - this.set(key, values[key], opt_silent); - } -}; - - -/** - * Unsets a property. - * @param {string} key Key name. - * @param {boolean=} opt_silent Unset without triggering an event. - * @api stable - */ -ol.Object.prototype.unset = function(key, opt_silent) { - if (key in this.values_) { - var oldValue = this.values_[key]; - delete this.values_[key]; - if (!opt_silent) { - this.notify(key, oldValue); - } - } -}; - -goog.provide('ol.Size'); -goog.provide('ol.size'); - - -goog.require('goog.asserts'); - - -/** - * An array of numbers representing a size: `[width, height]`. - * @typedef {Array.<number>} - * @api stable - */ -ol.Size; - - -/** - * Returns a buffered size. - * @param {ol.Size} size Size. - * @param {number} buffer Buffer. - * @param {ol.Size=} opt_size Optional reusable size array. - * @return {ol.Size} - */ -ol.size.buffer = function(size, buffer, opt_size) { - if (opt_size === undefined) { - opt_size = [0, 0]; - } - opt_size[0] = size[0] + 2 * buffer; - opt_size[1] = size[1] + 2 * buffer; - return opt_size; -}; - - -/** - * Compares sizes for equality. - * @param {ol.Size} a Size. - * @param {ol.Size} b Size. - * @return {boolean} Equals. - */ -ol.size.equals = function(a, b) { - return a[0] == b[0] && a[1] == b[1]; -}; - - -/** - * Determines if a size has a positive area. - * @param {ol.Size} size The size to test. - * @return {boolean} The size has a positive area. - */ -ol.size.hasArea = function(size) { - return size[0] > 0 && size[1] > 0; -}; - - -/** - * Returns a size scaled by a ratio. The result will be an array of integers. - * @param {ol.Size} size Size. - * @param {number} ratio Ratio. - * @param {ol.Size=} opt_size Optional reusable size array. - * @return {ol.Size} - */ -ol.size.scale = function(size, ratio, opt_size) { - if (opt_size === undefined) { - opt_size = [0, 0]; - } - opt_size[0] = (size[0] * ratio + 0.5) | 0; - opt_size[1] = (size[1] * ratio + 0.5) | 0; - return opt_size; -}; - - -/** - * Returns an `ol.Size` array for the passed in number (meaning: square) or - * `ol.Size` array. - * (meaning: non-square), - * @param {number|ol.Size} size Width and height. - * @param {ol.Size=} opt_size Optional reusable size array. - * @return {ol.Size} Size. - * @api stable - */ -ol.size.toSize = function(size, opt_size) { - if (goog.isArray(size)) { - return size; - } else { - goog.asserts.assert(goog.isNumber(size)); - if (opt_size === undefined) { - opt_size = [size, size]; - } else { - opt_size[0] = size; - opt_size[1] = size; - } - return opt_size; - } -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Additional mathematical functions. - */ - -goog.provide('goog.math'); - -goog.require('goog.array'); -goog.require('goog.asserts'); - - -/** - * Returns a random integer greater than or equal to 0 and less than {@code a}. - * @param {number} a The upper bound for the random integer (exclusive). - * @return {number} A random integer N such that 0 <= N < a. - */ -goog.math.randomInt = function(a) { - return Math.floor(Math.random() * a); -}; - - -/** - * Returns a random number greater than or equal to {@code a} and less than - * {@code b}. - * @param {number} a The lower bound for the random number (inclusive). - * @param {number} b The upper bound for the random number (exclusive). - * @return {number} A random number N such that a <= N < b. - */ -goog.math.uniformRandom = function(a, b) { - return a + Math.random() * (b - a); -}; - - -/** - * Takes a number and clamps it to within the provided bounds. - * @param {number} value The input number. - * @param {number} min The minimum value to return. - * @param {number} max The maximum value to return. - * @return {number} The input number if it is within bounds, or the nearest - * number within the bounds. - */ -goog.math.clamp = function(value, min, max) { - return Math.min(Math.max(value, min), max); -}; - - -/** - * The % operator in JavaScript returns the remainder of a / b, but differs from - * some other languages in that the result will have the same sign as the - * dividend. For example, -1 % 8 == -1, whereas in some other languages - * (such as Python) the result would be 7. This function emulates the more - * correct modulo behavior, which is useful for certain applications such as - * calculating an offset index in a circular list. - * - * @param {number} a The dividend. - * @param {number} b The divisor. - * @return {number} a % b where the result is between 0 and b (either 0 <= x < b - * or b < x <= 0, depending on the sign of b). - */ -goog.math.modulo = function(a, b) { - var r = a % b; - // If r and b differ in sign, add b to wrap the result to the correct sign. - return (r * b < 0) ? r + b : r; -}; - - -/** - * Performs linear interpolation between values a and b. Returns the value - * between a and b proportional to x (when x is between 0 and 1. When x is - * outside this range, the return value is a linear extrapolation). - * @param {number} a A number. - * @param {number} b A number. - * @param {number} x The proportion between a and b. - * @return {number} The interpolated value between a and b. - */ -goog.math.lerp = function(a, b, x) { - return a + x * (b - a); -}; - - -/** - * Tests whether the two values are equal to each other, within a certain - * tolerance to adjust for floating point errors. - * @param {number} a A number. - * @param {number} b A number. - * @param {number=} opt_tolerance Optional tolerance range. Defaults - * to 0.000001. If specified, should be greater than 0. - * @return {boolean} Whether {@code a} and {@code b} are nearly equal. - */ -goog.math.nearlyEquals = function(a, b, opt_tolerance) { - return Math.abs(a - b) <= (opt_tolerance || 0.000001); -}; - - -// TODO(user): Rename to normalizeAngle, retaining old name as deprecated -// alias. -/** - * Normalizes an angle to be in range [0-360). Angles outside this range will - * be normalized to be the equivalent angle with that range. - * @param {number} angle Angle in degrees. - * @return {number} Standardized angle. - */ -goog.math.standardAngle = function(angle) { - return goog.math.modulo(angle, 360); -}; - - -/** - * Normalizes an angle to be in range [0-2*PI). Angles outside this range will - * be normalized to be the equivalent angle with that range. - * @param {number} angle Angle in radians. - * @return {number} Standardized angle. - */ -goog.math.standardAngleInRadians = function(angle) { - return goog.math.modulo(angle, 2 * Math.PI); -}; - - -/** - * Converts degrees to radians. - * @param {number} angleDegrees Angle in degrees. - * @return {number} Angle in radians. - */ -goog.math.toRadians = function(angleDegrees) { - return angleDegrees * Math.PI / 180; -}; - - -/** - * Converts radians to degrees. - * @param {number} angleRadians Angle in radians. - * @return {number} Angle in degrees. - */ -goog.math.toDegrees = function(angleRadians) { - return angleRadians * 180 / Math.PI; -}; - - -/** - * For a given angle and radius, finds the X portion of the offset. - * @param {number} degrees Angle in degrees (zero points in +X direction). - * @param {number} radius Radius. - * @return {number} The x-distance for the angle and radius. - */ -goog.math.angleDx = function(degrees, radius) { - return radius * Math.cos(goog.math.toRadians(degrees)); -}; - - -/** - * For a given angle and radius, finds the Y portion of the offset. - * @param {number} degrees Angle in degrees (zero points in +X direction). - * @param {number} radius Radius. - * @return {number} The y-distance for the angle and radius. - */ -goog.math.angleDy = function(degrees, radius) { - return radius * Math.sin(goog.math.toRadians(degrees)); -}; - - -/** - * Computes the angle between two points (x1,y1) and (x2,y2). - * Angle zero points in the +X direction, 90 degrees points in the +Y - * direction (down) and from there we grow clockwise towards 360 degrees. - * @param {number} x1 x of first point. - * @param {number} y1 y of first point. - * @param {number} x2 x of second point. - * @param {number} y2 y of second point. - * @return {number} Standardized angle in degrees of the vector from - * x1,y1 to x2,y2. - */ -goog.math.angle = function(x1, y1, x2, y2) { - return goog.math.standardAngle(goog.math.toDegrees(Math.atan2(y2 - y1, - x2 - x1))); -}; - - -/** - * Computes the difference between startAngle and endAngle (angles in degrees). - * @param {number} startAngle Start angle in degrees. - * @param {number} endAngle End angle in degrees. - * @return {number} The number of degrees that when added to - * startAngle will result in endAngle. Positive numbers mean that the - * direction is clockwise. Negative numbers indicate a counter-clockwise - * direction. - * The shortest route (clockwise vs counter-clockwise) between the angles - * is used. - * When the difference is 180 degrees, the function returns 180 (not -180) - * angleDifference(30, 40) is 10, and angleDifference(40, 30) is -10. - * angleDifference(350, 10) is 20, and angleDifference(10, 350) is -20. - */ -goog.math.angleDifference = function(startAngle, endAngle) { - var d = goog.math.standardAngle(endAngle) - - goog.math.standardAngle(startAngle); - if (d > 180) { - d = d - 360; - } else if (d <= -180) { - d = 360 + d; - } - return d; -}; - - -/** - * Returns the sign of a number as per the "sign" or "signum" function. - * @param {number} x The number to take the sign of. - * @return {number} -1 when negative, 1 when positive, 0 when 0. Preserves - * signed zeros and NaN. - */ -goog.math.sign = Math.sign || function(x) { - if (x > 0) { - return 1; - } - if (x < 0) { - return -1; - } - return x; // Preserves signed zeros and NaN. -}; - - -/** - * JavaScript implementation of Longest Common Subsequence problem. - * http://en.wikipedia.org/wiki/Longest_common_subsequence - * - * Returns the longest possible array that is subarray of both of given arrays. - * - * @param {Array<Object>} array1 First array of objects. - * @param {Array<Object>} array2 Second array of objects. - * @param {Function=} opt_compareFn Function that acts as a custom comparator - * for the array ojects. Function should return true if objects are equal, - * otherwise false. - * @param {Function=} opt_collectorFn Function used to decide what to return - * as a result subsequence. It accepts 2 arguments: index of common element - * in the first array and index in the second. The default function returns - * element from the first array. - * @return {!Array<Object>} A list of objects that are common to both arrays - * such that there is no common subsequence with size greater than the - * length of the list. - */ -goog.math.longestCommonSubsequence = function( - array1, array2, opt_compareFn, opt_collectorFn) { - - var compare = opt_compareFn || function(a, b) { - return a == b; - }; - - var collect = opt_collectorFn || function(i1, i2) { - return array1[i1]; - }; - - var length1 = array1.length; - var length2 = array2.length; - - var arr = []; - for (var i = 0; i < length1 + 1; i++) { - arr[i] = []; - arr[i][0] = 0; - } - - for (var j = 0; j < length2 + 1; j++) { - arr[0][j] = 0; - } - - for (i = 1; i <= length1; i++) { - for (j = 1; j <= length2; j++) { - if (compare(array1[i - 1], array2[j - 1])) { - arr[i][j] = arr[i - 1][j - 1] + 1; - } else { - arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]); - } - } - } - - // Backtracking - var result = []; - var i = length1, j = length2; - while (i > 0 && j > 0) { - if (compare(array1[i - 1], array2[j - 1])) { - result.unshift(collect(i - 1, j - 1)); - i--; - j--; - } else { - if (arr[i - 1][j] > arr[i][j - 1]) { - i--; - } else { - j--; - } - } - } - - return result; -}; - - -/** - * Returns the sum of the arguments. - * @param {...number} var_args Numbers to add. - * @return {number} The sum of the arguments (0 if no arguments were provided, - * {@code NaN} if any of the arguments is not a valid number). - */ -goog.math.sum = function(var_args) { - return /** @type {number} */ (goog.array.reduce(arguments, - function(sum, value) { - return sum + value; - }, 0)); -}; - - -/** - * Returns the arithmetic mean of the arguments. - * @param {...number} var_args Numbers to average. - * @return {number} The average of the arguments ({@code NaN} if no arguments - * were provided or any of the arguments is not a valid number). - */ -goog.math.average = function(var_args) { - return goog.math.sum.apply(null, arguments) / arguments.length; -}; - - -/** - * Returns the unbiased sample variance of the arguments. For a definition, - * see e.g. http://en.wikipedia.org/wiki/Variance - * @param {...number} var_args Number samples to analyze. - * @return {number} The unbiased sample variance of the arguments (0 if fewer - * than two samples were provided, or {@code NaN} if any of the samples is - * not a valid number). - */ -goog.math.sampleVariance = function(var_args) { - var sampleSize = arguments.length; - if (sampleSize < 2) { - return 0; - } - - var mean = goog.math.average.apply(null, arguments); - var variance = goog.math.sum.apply(null, goog.array.map(arguments, - function(val) { - return Math.pow(val - mean, 2); - })) / (sampleSize - 1); - - return variance; -}; - - -/** - * Returns the sample standard deviation of the arguments. For a definition of - * sample standard deviation, see e.g. - * http://en.wikipedia.org/wiki/Standard_deviation - * @param {...number} var_args Number samples to analyze. - * @return {number} The sample standard deviation of the arguments (0 if fewer - * than two samples were provided, or {@code NaN} if any of the samples is - * not a valid number). - */ -goog.math.standardDeviation = function(var_args) { - return Math.sqrt(goog.math.sampleVariance.apply(null, arguments)); -}; - - -/** - * Returns whether the supplied number represents an integer, i.e. that is has - * no fractional component. No range-checking is performed on the number. - * @param {number} num The number to test. - * @return {boolean} Whether {@code num} is an integer. - */ -goog.math.isInt = function(num) { - return isFinite(num) && num % 1 == 0; -}; - - -/** - * Returns whether the supplied number is finite and not NaN. - * @param {number} num The number to test. - * @return {boolean} Whether {@code num} is a finite number. - */ -goog.math.isFiniteNumber = function(num) { - return isFinite(num) && !isNaN(num); -}; - - -/** - * @param {number} num The number to test. - * @return {boolean} Whether it is negative zero. - */ -goog.math.isNegativeZero = function(num) { - return num == 0 && 1 / num < 0; -}; - - -/** - * Returns the precise value of floor(log10(num)). - * Simpler implementations didn't work because of floating point rounding - * errors. For example - * <ul> - * <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3. - * <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15. - * <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1. - * </ul> - * @param {number} num A floating point number. - * @return {number} Its logarithm to base 10 rounded down to the nearest - * integer if num > 0. -Infinity if num == 0. NaN if num < 0. - */ -goog.math.log10Floor = function(num) { - if (num > 0) { - var x = Math.round(Math.log(num) * Math.LOG10E); - return x - (parseFloat('1e' + x) > num); - } - return num == 0 ? -Infinity : NaN; -}; - - -/** - * A tweaked variant of {@code Math.floor} which tolerates if the passed number - * is infinitesimally smaller than the closest integer. It often happens with - * the results of floating point calculations because of the finite precision - * of the intermediate results. For example {@code Math.floor(Math.log(1000) / - * Math.LN10) == 2}, not 3 as one would expect. - * @param {number} num A number. - * @param {number=} opt_epsilon An infinitesimally small positive number, the - * rounding error to tolerate. - * @return {number} The largest integer less than or equal to {@code num}. - */ -goog.math.safeFloor = function(num, opt_epsilon) { - goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0); - return Math.floor(num + (opt_epsilon || 2e-15)); -}; - - -/** - * A tweaked variant of {@code Math.ceil}. See {@code goog.math.safeFloor} for - * details. - * @param {number} num A number. - * @param {number=} opt_epsilon An infinitesimally small positive number, the - * rounding error to tolerate. - * @return {number} The smallest integer greater than or equal to {@code num}. - */ -goog.math.safeCeil = function(num, opt_epsilon) { - goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0); - return Math.ceil(num - (opt_epsilon || 2e-15)); -}; - -goog.provide('ol.Coordinate'); -goog.provide('ol.CoordinateFormatType'); -goog.provide('ol.coordinate'); - -goog.require('goog.math'); -goog.require('goog.string'); - - -/** - * A function that takes a {@link ol.Coordinate} and transforms it into a - * `{string}`. - * - * @typedef {function((ol.Coordinate|undefined)): string} - * @api stable - */ -ol.CoordinateFormatType; - - -/** - * An array of numbers representing an xy coordinate. Example: `[16, 48]`. - * @typedef {Array.<number>} ol.Coordinate - * @api stable - */ -ol.Coordinate; - - -/** - * Add `delta` to `coordinate`. `coordinate` is modified in place and returned - * by the function. - * - * Example: - * - * var coord = [7.85, 47.983333]; - * ol.coordinate.add(coord, [-2, 4]); - * // coord is now [5.85, 51.983333] - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.Coordinate} delta Delta. - * @return {ol.Coordinate} The input coordinate adjusted by the given delta. - * @api stable - */ -ol.coordinate.add = function(coordinate, delta) { - coordinate[0] += delta[0]; - coordinate[1] += delta[1]; - return coordinate; -}; - - -/** - * Calculates the point closest to the passed coordinate on the passed segment. - * This is the foot of the perpendicular of the coordinate to the segment when - * the foot is on the segment, or the closest segment coordinate when the foot - * is outside the segment. - * - * @param {ol.Coordinate} coordinate The coordinate. - * @param {Array.<ol.Coordinate>} segment The two coordinates of the segment. - * @return {ol.Coordinate} The foot of the perpendicular of the coordinate to - * the segment. - */ -ol.coordinate.closestOnSegment = function(coordinate, segment) { - var x0 = coordinate[0]; - var y0 = coordinate[1]; - var start = segment[0]; - var end = segment[1]; - var x1 = start[0]; - var y1 = start[1]; - var x2 = end[0]; - var y2 = end[1]; - var dx = x2 - x1; - var dy = y2 - y1; - var along = (dx === 0 && dy === 0) ? 0 : - ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0); - var x, y; - if (along <= 0) { - x = x1; - y = y1; - } else if (along >= 1) { - x = x2; - y = y2; - } else { - x = x1 + along * dx; - y = y1 + along * dy; - } - return [x, y]; -}; - - -/** - * Returns a {@link ol.CoordinateFormatType} function that can be used to format - * a {ol.Coordinate} to a string. - * - * Example without specifying the fractional digits: - * - * var coord = [7.85, 47.983333]; - * var stringifyFunc = ol.coordinate.createStringXY(); - * var out = stringifyFunc(coord); - * // out is now '8, 48' - * - * Example with explicitly specifying 2 fractional digits: - * - * var coord = [7.85, 47.983333]; - * var stringifyFunc = ol.coordinate.createStringXY(2); - * var out = stringifyFunc(coord); - * // out is now '7.85, 47.98' - * - * @param {number=} opt_fractionDigits The number of digits to include - * after the decimal point. Default is `0`. - * @return {ol.CoordinateFormatType} Coordinate format. - * @api stable - */ -ol.coordinate.createStringXY = function(opt_fractionDigits) { - return ( - /** - * @param {ol.Coordinate|undefined} coordinate Coordinate. - * @return {string} String XY. - */ - function(coordinate) { - return ol.coordinate.toStringXY(coordinate, opt_fractionDigits); - }); -}; - - -/** - * @private - * @param {number} degrees Degrees. - * @param {string} hemispheres Hemispheres. - * @return {string} String. - */ -ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres) { - var normalizedDegrees = goog.math.modulo(degrees + 180, 360) - 180; - var x = Math.abs(Math.round(3600 * normalizedDegrees)); - return Math.floor(x / 3600) + '\u00b0 ' + - goog.string.padNumber(Math.floor((x / 60) % 60), 2) + '\u2032 ' + - goog.string.padNumber(Math.floor(x % 60), 2) + '\u2033 ' + - hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0); -}; - - -/** - * Transforms the given {@link ol.Coordinate} to a string using the given string - * template. The strings `{x}` and `{y}` in the template will be replaced with - * the first and second coordinate values respectively. - * - * Example without specifying the fractional digits: - * - * var coord = [7.85, 47.983333]; - * var template = 'Coordinate is ({x}|{y}).'; - * var out = ol.coordinate.format(coord, template); - * // out is now 'Coordinate is (8|48).' - * - * Example explicitly specifying the fractional digits: - * - * var coord = [7.85, 47.983333]; - * var template = 'Coordinate is ({x}|{y}).'; - * var out = ol.coordinate.format(coord, template, 2); - * // out is now 'Coordinate is (7.85|47.98).' - * - * @param {ol.Coordinate|undefined} coordinate Coordinate. - * @param {string} template A template string with `{x}` and `{y}` placeholders - * that will be replaced by first and second coordinate values. - * @param {number=} opt_fractionDigits The number of digits to include - * after the decimal point. Default is `0`. - * @return {string} Formatted coordinate. - * @api stable - */ -ol.coordinate.format = function(coordinate, template, opt_fractionDigits) { - if (coordinate) { - return template - .replace('{x}', coordinate[0].toFixed(opt_fractionDigits)) - .replace('{y}', coordinate[1].toFixed(opt_fractionDigits)); - } else { - return ''; - } -}; - - -/** - * @param {ol.Coordinate} coordinate1 First coordinate. - * @param {ol.Coordinate} coordinate2 Second coordinate. - * @return {boolean} Whether the passed coordinates are equal. - */ -ol.coordinate.equals = function(coordinate1, coordinate2) { - var equals = true; - for (var i = coordinate1.length - 1; i >= 0; --i) { - if (coordinate1[i] != coordinate2[i]) { - equals = false; - break; - } - } - return equals; -}; - - -/** - * Rotate `coordinate` by `angle`. `coordinate` is modified in place and - * returned by the function. - * - * Example: - * - * var coord = [7.85, 47.983333]; - * var rotateRadians = Math.PI / 2; // 90 degrees - * ol.coordinate.rotate(coord, rotateRadians); - * // coord is now [-47.983333, 7.85] - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} angle Angle in radian. - * @return {ol.Coordinate} Coordinate. - * @api stable - */ -ol.coordinate.rotate = function(coordinate, angle) { - var cosAngle = Math.cos(angle); - var sinAngle = Math.sin(angle); - var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle; - var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle; - coordinate[0] = x; - coordinate[1] = y; - return coordinate; -}; - - -/** - * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned - * by the function. - * - * Example: - * - * var coord = [7.85, 47.983333]; - * var scale = 1.2; - * ol.coordinate.scale(coord, scale); - * // coord is now [9.42, 57.5799996] - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} scale Scale factor. - * @return {ol.Coordinate} Coordinate. - */ -ol.coordinate.scale = function(coordinate, scale) { - coordinate[0] *= scale; - coordinate[1] *= scale; - return coordinate; -}; - - -/** - * Subtract `delta` to `coordinate`. `coordinate` is modified in place and - * returned by the function. - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.Coordinate} delta Delta. - * @return {ol.Coordinate} Coordinate. - */ -ol.coordinate.sub = function(coordinate, delta) { - coordinate[0] -= delta[0]; - coordinate[1] -= delta[1]; - return coordinate; -}; - - -/** - * @param {ol.Coordinate} coord1 First coordinate. - * @param {ol.Coordinate} coord2 Second coordinate. - * @return {number} Squared distance between coord1 and coord2. - */ -ol.coordinate.squaredDistance = function(coord1, coord2) { - var dx = coord1[0] - coord2[0]; - var dy = coord1[1] - coord2[1]; - return dx * dx + dy * dy; -}; - - -/** - * Calculate the squared distance from a coordinate to a line segment. - * - * @param {ol.Coordinate} coordinate Coordinate of the point. - * @param {Array.<ol.Coordinate>} segment Line segment (2 coordinates). - * @return {number} Squared distance from the point to the line segment. - */ -ol.coordinate.squaredDistanceToSegment = function(coordinate, segment) { - return ol.coordinate.squaredDistance(coordinate, - ol.coordinate.closestOnSegment(coordinate, segment)); -}; - - -/** - * Format a geographic coordinate with the hemisphere, degrees, minutes, and - * seconds. - * - * Example: - * - * var coord = [7.85, 47.983333]; - * var out = ol.coordinate.toStringHDMS(coord); - * // out is now '47° 59′ 0″ N 7° 51′ 0″ E' - * - * @param {ol.Coordinate|undefined} coordinate Coordinate. - * @return {string} Hemisphere, degrees, minutes and seconds. - * @api stable - */ -ol.coordinate.toStringHDMS = function(coordinate) { - if (coordinate) { - return ol.coordinate.degreesToStringHDMS_(coordinate[1], 'NS') + ' ' + - ol.coordinate.degreesToStringHDMS_(coordinate[0], 'EW'); - } else { - return ''; - } -}; - - -/** - * Format a coordinate as a comma delimited string. - * - * Example without specifying fractional digits: - * - * var coord = [7.85, 47.983333]; - * var out = ol.coordinate.toStringXY(coord); - * // out is now '8, 48' - * - * Example explicitly specifying 1 fractional digit: - * - * var coord = [7.85, 47.983333]; - * var out = ol.coordinate.toStringXY(coord, 1); - * // out is now '7.8, 48.0' - * - * @param {ol.Coordinate|undefined} coordinate Coordinate. - * @param {number=} opt_fractionDigits The number of digits to include - * after the decimal point. Default is `0`. - * @return {string} XY. - * @api stable - */ -ol.coordinate.toStringXY = function(coordinate, opt_fractionDigits) { - return ol.coordinate.format(coordinate, '{x}, {y}', opt_fractionDigits); -}; - - -/** - * Create an ol.Coordinate from an Array and take into account axis order. - * - * Examples: - * - * var northCoord = ol.coordinate.fromProjectedArray([1, 2], 'n'); - * // northCoord is now [2, 1] - * - * var eastCoord = ol.coordinate.fromProjectedArray([1, 2], 'e'); - * // eastCoord is now [1, 2] - * - * @param {Array} array The array with coordinates. - * @param {string} axis the axis info. - * @return {ol.Coordinate} The coordinate created. - */ -ol.coordinate.fromProjectedArray = function(array, axis) { - var firstAxis = axis.charAt(0); - if (firstAxis === 'n' || firstAxis === 's') { - return [array[1], array[0]]; - } else { - return array; - } -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Supplies a Float32Array implementation that implements - * most of the Float32Array spec and that can be used when a built-in - * implementation is not available. - * - * Note that if no existing Float32Array implementation is found then - * this class and all its public properties are exported as Float32Array. - * - * Adding support for the other TypedArray classes here does not make sense - * since this vector math library only needs Float32Array. - * - */ -goog.provide('goog.vec.Float32Array'); - - - -/** - * Constructs a new Float32Array. The new array is initialized to all zeros. - * - * @param {goog.vec.Float32Array|Array|ArrayBuffer|number} p0 - * The length of the array, or an array to initialize the contents of the - * new Float32Array. - * @constructor - * @final - */ -goog.vec.Float32Array = function(p0) { - this.length = /** @type {number} */ (p0.length || p0); - for (var i = 0; i < this.length; i++) { - this[i] = p0[i] || 0; - } -}; - - -/** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} - */ -goog.vec.Float32Array.BYTES_PER_ELEMENT = 4; - - -/** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} - */ -goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT = 4; - - -/** - * Sets elements of the array. - * @param {Array<number>|Float32Array} values The array of values. - * @param {number=} opt_offset The offset in this array to start. - */ -goog.vec.Float32Array.prototype.set = function(values, opt_offset) { - opt_offset = opt_offset || 0; - for (var i = 0; i < values.length && opt_offset + i < this.length; i++) { - this[opt_offset + i] = values[i]; - } -}; - - -/** - * Creates a string representation of this array. - * @return {string} The string version of this array. - * @override - */ -goog.vec.Float32Array.prototype.toString = Array.prototype.join; - - -/** - * Note that we cannot implement the subarray() or (deprecated) slice() - * methods properly since doing so would require being able to overload - * the [] operator which is not possible in javascript. So we leave - * them unimplemented. Any attempt to call these methods will just result - * in a javascript error since we leave them undefined. - */ - - -/** - * If no existing Float32Array implementation is found then we export - * goog.vec.Float32Array as Float32Array. - */ -if (typeof Float32Array == 'undefined') { - goog.exportProperty(goog.vec.Float32Array, 'BYTES_PER_ELEMENT', - goog.vec.Float32Array.BYTES_PER_ELEMENT); - goog.exportProperty(goog.vec.Float32Array.prototype, 'BYTES_PER_ELEMENT', - goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT); - goog.exportProperty(goog.vec.Float32Array.prototype, 'set', - goog.vec.Float32Array.prototype.set); - goog.exportProperty(goog.vec.Float32Array.prototype, 'toString', - goog.vec.Float32Array.prototype.toString); - goog.exportSymbol('Float32Array', goog.vec.Float32Array); -} - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Supplies a Float64Array implementation that implements - * most of the Float64Array spec and that can be used when a built-in - * implementation is not available. - * - * Note that if no existing Float64Array implementation is found then this - * class and all its public properties are exported as Float64Array. - * - * Adding support for the other TypedArray classes here does not make sense - * since this vector math library only needs Float32Array and Float64Array. - * - */ -goog.provide('goog.vec.Float64Array'); - - - -/** - * Constructs a new Float64Array. The new array is initialized to all zeros. - * - * @param {goog.vec.Float64Array|Array|ArrayBuffer|number} p0 - * The length of the array, or an array to initialize the contents of the - * new Float64Array. - * @constructor - * @final - */ -goog.vec.Float64Array = function(p0) { - this.length = /** @type {number} */ (p0.length || p0); - for (var i = 0; i < this.length; i++) { - this[i] = p0[i] || 0; - } -}; - - -/** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} - */ -goog.vec.Float64Array.BYTES_PER_ELEMENT = 8; - - -/** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} - */ -goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT = 8; - - -/** - * Sets elements of the array. - * @param {Array<number>|Float64Array} values The array of values. - * @param {number=} opt_offset The offset in this array to start. - */ -goog.vec.Float64Array.prototype.set = function(values, opt_offset) { - opt_offset = opt_offset || 0; - for (var i = 0; i < values.length && opt_offset + i < this.length; i++) { - this[opt_offset + i] = values[i]; - } -}; - - -/** - * Creates a string representation of this array. - * @return {string} The string version of this array. - * @override - */ -goog.vec.Float64Array.prototype.toString = Array.prototype.join; - - -/** - * Note that we cannot implement the subarray() or (deprecated) slice() - * methods properly since doing so would require being able to overload - * the [] operator which is not possible in javascript. So we leave - * them unimplemented. Any attempt to call these methods will just result - * in a javascript error since we leave them undefined. - */ - - -/** - * If no existing Float64Array implementation is found then we export - * goog.vec.Float64Array as Float64Array. - */ -if (typeof Float64Array == 'undefined') { - try { - goog.exportProperty(goog.vec.Float64Array, 'BYTES_PER_ELEMENT', - goog.vec.Float64Array.BYTES_PER_ELEMENT); - } catch (float64ArrayError) { - // Do nothing. This code is in place to fix b/7225850, in which an error - // is incorrectly thrown for Google TV on an old Chrome. - // TODO(user): remove after that version is retired. - } - - goog.exportProperty(goog.vec.Float64Array.prototype, 'BYTES_PER_ELEMENT', - goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT); - goog.exportProperty(goog.vec.Float64Array.prototype, 'set', - goog.vec.Float64Array.prototype.set); - goog.exportProperty(goog.vec.Float64Array.prototype, 'toString', - goog.vec.Float64Array.prototype.toString); - goog.exportSymbol('Float64Array', goog.vec.Float64Array); -} - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Supplies global data types and constants for the vector math - * library. - */ -goog.provide('goog.vec'); -goog.provide('goog.vec.AnyType'); -goog.provide('goog.vec.ArrayType'); -goog.provide('goog.vec.Float32'); -goog.provide('goog.vec.Float64'); -goog.provide('goog.vec.Number'); - - -/** - * On platforms that don't have native Float32Array or Float64Array support we - * use a javascript implementation so that this math library can be used on all - * platforms. - * @suppress {extraRequire} - */ -goog.require('goog.vec.Float32Array'); -/** @suppress {extraRequire} */ -goog.require('goog.vec.Float64Array'); - -// All vector and matrix operations are based upon arrays of numbers using -// either Float32Array, Float64Array, or a standard Javascript Array of -// Numbers. - - -/** @typedef {!Float32Array} */ -goog.vec.Float32; - - -/** @typedef {!Float64Array} */ -goog.vec.Float64; - - -/** @typedef {!Array<number>} */ -goog.vec.Number; - - -/** @typedef {!goog.vec.Float32|!goog.vec.Float64|!goog.vec.Number} */ -goog.vec.AnyType; - - -/** - * @deprecated Use AnyType. - * @typedef {!Float32Array|!Array<number>} - */ -goog.vec.ArrayType; - - -/** - * For graphics work, 6 decimal places of accuracy are typically all that is - * required. - * - * @type {number} - * @const - */ -goog.vec.EPSILON = 1e-6; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Supplies 3 element vectors that are compatible with WebGL. - * Each element is a float32 since that is typically the desired size of a - * 3-vector in the GPU. The API is structured to avoid unnecessary memory - * allocations. The last parameter will typically be the output vector and - * an object can be both an input and output parameter to all methods except - * where noted. - * - */ -goog.provide('goog.vec.Vec3'); - -/** @suppress {extraRequire} */ -goog.require('goog.vec'); - -/** @typedef {goog.vec.Float32} */ goog.vec.Vec3.Float32; -/** @typedef {goog.vec.Float64} */ goog.vec.Vec3.Float64; -/** @typedef {goog.vec.Number} */ goog.vec.Vec3.Number; -/** @typedef {goog.vec.AnyType} */ goog.vec.Vec3.AnyType; - -// The following two types are deprecated - use the above types instead. -/** @typedef {Float32Array} */ goog.vec.Vec3.Type; -/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec3.Vec3Like; - - -/** - * Creates a 3 element vector of Float32. The array is initialized to zero. - * - * @return {!goog.vec.Vec3.Float32} The new 3 element array. - */ -goog.vec.Vec3.createFloat32 = function() { - return new Float32Array(3); -}; - - -/** - * Creates a 3 element vector of Float64. The array is initialized to zero. - * - * @return {!goog.vec.Vec3.Float64} The new 3 element array. - */ -goog.vec.Vec3.createFloat64 = function() { - return new Float64Array(3); -}; - - -/** - * Creates a 3 element vector of Number. The array is initialized to zero. - * - * @return {!goog.vec.Vec3.Number} The new 3 element array. - */ -goog.vec.Vec3.createNumber = function() { - var a = new Array(3); - goog.vec.Vec3.setFromValues(a, 0, 0, 0); - return a; -}; - - -/** - * Creates a 3 element vector of Float32Array. The array is initialized to zero. - * - * @deprecated Use createFloat32. - * @return {!goog.vec.Vec3.Type} The new 3 element array. - */ -goog.vec.Vec3.create = function() { - return new Float32Array(3); -}; - - -/** - * Creates a new 3 element FLoat32 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec3.AnyType} vec The source 3 element array. - * @return {!goog.vec.Vec3.Float32} The new 3 element array. - */ -goog.vec.Vec3.createFloat32FromArray = function(vec) { - var newVec = goog.vec.Vec3.createFloat32(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; -}; - - -/** - * Creates a new 3 element Float32 vector initialized with the supplied values. - * - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @return {!goog.vec.Vec3.Float32} The new vector. - */ -goog.vec.Vec3.createFloat32FromValues = function(v0, v1, v2) { - var a = goog.vec.Vec3.createFloat32(); - goog.vec.Vec3.setFromValues(a, v0, v1, v2); - return a; -}; - - -/** - * Creates a clone of the given 3 element Float32 vector. - * - * @param {goog.vec.Vec3.Float32} vec The source 3 element vector. - * @return {!goog.vec.Vec3.Float32} The new cloned vector. - */ -goog.vec.Vec3.cloneFloat32 = goog.vec.Vec3.createFloat32FromArray; - - -/** - * Creates a new 3 element Float64 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec3.AnyType} vec The source 3 element array. - * @return {!goog.vec.Vec3.Float64} The new 3 element array. - */ -goog.vec.Vec3.createFloat64FromArray = function(vec) { - var newVec = goog.vec.Vec3.createFloat64(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; -}; - - -/** -* Creates a new 3 element Float64 vector initialized with the supplied values. -* -* @param {number} v0 The value for element at index 0. -* @param {number} v1 The value for element at index 1. -* @param {number} v2 The value for element at index 2. -* @return {!goog.vec.Vec3.Float64} The new vector. -*/ -goog.vec.Vec3.createFloat64FromValues = function(v0, v1, v2) { - var vec = goog.vec.Vec3.createFloat64(); - goog.vec.Vec3.setFromValues(vec, v0, v1, v2); - return vec; -}; - - -/** - * Creates a clone of the given 3 element vector. - * - * @param {goog.vec.Vec3.Float64} vec The source 3 element vector. - * @return {!goog.vec.Vec3.Float64} The new cloned vector. - */ -goog.vec.Vec3.cloneFloat64 = goog.vec.Vec3.createFloat64FromArray; - - -/** - * Creates a new 3 element vector initialized with the value from the given - * array. - * - * @deprecated Use createFloat32FromArray. - * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element array. - * @return {!goog.vec.Vec3.Type} The new 3 element array. - */ -goog.vec.Vec3.createFromArray = function(vec) { - var newVec = goog.vec.Vec3.create(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; -}; - - -/** - * Creates a new 3 element vector initialized with the supplied values. - * - * @deprecated Use createFloat32FromValues. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @return {!goog.vec.Vec3.Type} The new vector. - */ -goog.vec.Vec3.createFromValues = function(v0, v1, v2) { - var vec = goog.vec.Vec3.create(); - goog.vec.Vec3.setFromValues(vec, v0, v1, v2); - return vec; -}; - - -/** - * Creates a clone of the given 3 element vector. - * - * @deprecated Use cloneFloat32. - * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element vector. - * @return {!goog.vec.Vec3.Type} The new cloned vector. - */ -goog.vec.Vec3.clone = function(vec) { - var newVec = goog.vec.Vec3.create(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; -}; - - -/** - * Initializes the vector with the given values. - * - * @param {goog.vec.Vec3.AnyType} vec The vector to receive the values. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be - * chained together. - */ -goog.vec.Vec3.setFromValues = function(vec, v0, v1, v2) { - vec[0] = v0; - vec[1] = v1; - vec[2] = v2; - return vec; -}; - - -/** - * Initializes the vector with the given array of values. - * - * @param {goog.vec.Vec3.AnyType} vec The vector to receive the - * values. - * @param {goog.vec.Vec3.AnyType} values The array of values. - * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be - * chained together. - */ -goog.vec.Vec3.setFromArray = function(vec, values) { - vec[0] = values[0]; - vec[1] = values[1]; - vec[2] = values[2]; - return vec; -}; - - -/** - * Performs a component-wise addition of vec0 and vec1 together storing the - * result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The first addend. - * @param {goog.vec.Vec3.AnyType} vec1 The second addend. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.add = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] + vec1[0]; - resultVec[1] = vec0[1] + vec1[1]; - resultVec[2] = vec0[2] + vec1[2]; - return resultVec; -}; - - -/** - * Performs a component-wise subtraction of vec1 from vec0 storing the - * result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The minuend. - * @param {goog.vec.Vec3.AnyType} vec1 The subtrahend. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.subtract = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] - vec1[0]; - resultVec[1] = vec0[1] - vec1[1]; - resultVec[2] = vec0[2] - vec1[2]; - return resultVec; -}; - - -/** - * Negates vec0, storing the result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector to negate. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.negate = function(vec0, resultVec) { - resultVec[0] = -vec0[0]; - resultVec[1] = -vec0[1]; - resultVec[2] = -vec0[2]; - return resultVec; -}; - - -/** - * Takes the absolute value of each component of vec0 storing the result in - * resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the result. - * May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.abs = function(vec0, resultVec) { - resultVec[0] = Math.abs(vec0[0]); - resultVec[1] = Math.abs(vec0[1]); - resultVec[2] = Math.abs(vec0[2]); - return resultVec; -}; - - -/** - * Multiplies each component of vec0 with scalar storing the product into - * resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {number} scalar The value to multiply with each component of vec0. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.scale = function(vec0, scalar, resultVec) { - resultVec[0] = vec0[0] * scalar; - resultVec[1] = vec0[1] * scalar; - resultVec[2] = vec0[2] * scalar; - return resultVec; -}; - - -/** - * Returns the magnitudeSquared of the given vector. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. - */ -goog.vec.Vec3.magnitudeSquared = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2]; - return x * x + y * y + z * z; -}; - - -/** - * Returns the magnitude of the given vector. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. - */ -goog.vec.Vec3.magnitude = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2]; - return Math.sqrt(x * x + y * y + z * z); -}; - - -/** - * Normalizes the given vector storing the result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector to normalize. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.normalize = function(vec0, resultVec) { - var ilen = 1 / goog.vec.Vec3.magnitude(vec0); - resultVec[0] = vec0[0] * ilen; - resultVec[1] = vec0[1] * ilen; - resultVec[2] = vec0[2] * ilen; - return resultVec; -}; - - -/** - * Returns the scalar product of vectors v0 and v1. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @return {number} The scalar product. - */ -goog.vec.Vec3.dot = function(v0, v1) { - return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]; -}; - - -/** - * Computes the vector (cross) product of v0 and v1 storing the result into - * resultVec. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results. May be either v0 or v1. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.cross = function(v0, v1, resultVec) { - var x0 = v0[0], y0 = v0[1], z0 = v0[2]; - var x1 = v1[0], y1 = v1[1], z1 = v1[2]; - resultVec[0] = y0 * z1 - z0 * y1; - resultVec[1] = z0 * x1 - x0 * z1; - resultVec[2] = x0 * y1 - y0 * x1; - return resultVec; -}; - - -/** - * Returns the squared distance between two points. - * - * @param {goog.vec.Vec3.AnyType} vec0 First point. - * @param {goog.vec.Vec3.AnyType} vec1 Second point. - * @return {number} The squared distance between the points. - */ -goog.vec.Vec3.distanceSquared = function(vec0, vec1) { - var x = vec0[0] - vec1[0]; - var y = vec0[1] - vec1[1]; - var z = vec0[2] - vec1[2]; - return x * x + y * y + z * z; -}; - - -/** - * Returns the distance between two points. - * - * @param {goog.vec.Vec3.AnyType} vec0 First point. - * @param {goog.vec.Vec3.AnyType} vec1 Second point. - * @return {number} The distance between the points. - */ -goog.vec.Vec3.distance = function(vec0, vec1) { - return Math.sqrt(goog.vec.Vec3.distanceSquared(vec0, vec1)); -}; - - -/** - * Returns a unit vector pointing from one point to another. - * If the input points are equal then the result will be all zeros. - * - * @param {goog.vec.Vec3.AnyType} vec0 Origin point. - * @param {goog.vec.Vec3.AnyType} vec1 Target point. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be vec0 or vec1). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.direction = function(vec0, vec1, resultVec) { - var x = vec1[0] - vec0[0]; - var y = vec1[1] - vec0[1]; - var z = vec1[2] - vec0[2]; - var d = Math.sqrt(x * x + y * y + z * z); - if (d) { - d = 1 / d; - resultVec[0] = x * d; - resultVec[1] = y * d; - resultVec[2] = z * d; - } else { - resultVec[0] = resultVec[1] = resultVec[2] = 0; - } - return resultVec; -}; - - -/** - * Linearly interpolate from vec0 to v1 according to f. The value of f should be - * in the range [0..1] otherwise the results are undefined. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @param {number} f The interpolation factor. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be v0 or v1). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.lerp = function(v0, v1, f, resultVec) { - var x = v0[0], y = v0[1], z = v0[2]; - resultVec[0] = (v1[0] - x) * f + x; - resultVec[1] = (v1[1] - y) * f + y; - resultVec[2] = (v1[2] - z) * f + z; - return resultVec; -}; - - -/** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the larger values in resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.max = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.max(vec0[0], limit); - resultVec[1] = Math.max(vec0[1], limit); - resultVec[2] = Math.max(vec0[2], limit); - } else { - resultVec[0] = Math.max(vec0[0], limit[0]); - resultVec[1] = Math.max(vec0[1], limit[1]); - resultVec[2] = Math.max(vec0[2], limit[2]); - } - return resultVec; -}; - - -/** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the smaller values in resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec3.min = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.min(vec0[0], limit); - resultVec[1] = Math.min(vec0[1], limit); - resultVec[2] = Math.min(vec0[2], limit); - } else { - resultVec[0] = Math.min(vec0[0], limit[0]); - resultVec[1] = Math.min(vec0[1], limit[1]); - resultVec[2] = Math.min(vec0[2], limit[2]); - } - return resultVec; -}; - - -/** - * Returns true if the components of v0 are equal to the components of v1. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @return {boolean} True if the vectors are equal, false otherwise. - */ -goog.vec.Vec3.equals = function(v0, v1) { - return v0.length == v1.length && - v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2]; -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Supplies 4 element vectors that are compatible with WebGL. - * Each element is a float32 since that is typically the desired size of a - * 4-vector in the GPU. The API is structured to avoid unnecessary memory - * allocations. The last parameter will typically be the output vector and - * an object can be both an input and output parameter to all methods except - * where noted. - * - */ -goog.provide('goog.vec.Vec4'); - -/** @suppress {extraRequire} */ -goog.require('goog.vec'); - -/** @typedef {goog.vec.Float32} */ goog.vec.Vec4.Float32; -/** @typedef {goog.vec.Float64} */ goog.vec.Vec4.Float64; -/** @typedef {goog.vec.Number} */ goog.vec.Vec4.Number; -/** @typedef {goog.vec.AnyType} */ goog.vec.Vec4.AnyType; - -// The following two types are deprecated - use the above types instead. -/** @typedef {Float32Array} */ goog.vec.Vec4.Type; -/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec4.Vec4Like; - - -/** - * Creates a 4 element vector of Float32. The array is initialized to zero. - * - * @return {!goog.vec.Vec4.Float32} The new 3 element array. - */ -goog.vec.Vec4.createFloat32 = function() { - return new Float32Array(4); -}; - - -/** - * Creates a 4 element vector of Float64. The array is initialized to zero. - * - * @return {!goog.vec.Vec4.Float64} The new 4 element array. - */ -goog.vec.Vec4.createFloat64 = function() { - return new Float64Array(4); -}; - - -/** - * Creates a 4 element vector of Number. The array is initialized to zero. - * - * @return {!goog.vec.Vec4.Number} The new 4 element array. - */ -goog.vec.Vec4.createNumber = function() { - var v = new Array(4); - goog.vec.Vec4.setFromValues(v, 0, 0, 0, 0); - return v; -}; - - -/** - * Creates a 4 element vector of Float32Array. The array is initialized to zero. - * - * @deprecated Use createFloat32. - * @return {!goog.vec.Vec4.Type} The new 4 element array. - */ -goog.vec.Vec4.create = function() { - return new Float32Array(4); -}; - - -/** - * Creates a new 4 element vector initialized with the value from the given - * array. - * - * @deprecated Use createFloat32FromArray. - * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element array. - * @return {!goog.vec.Vec4.Type} The new 4 element array. - */ -goog.vec.Vec4.createFromArray = function(vec) { - var newVec = goog.vec.Vec4.create(); - goog.vec.Vec4.setFromArray(newVec, vec); - return newVec; -}; - - -/** - * Creates a new 4 element FLoat32 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec4.AnyType} vec The source 3 element array. - * @return {!goog.vec.Vec4.Float32} The new 3 element array. - */ -goog.vec.Vec4.createFloat32FromArray = function(vec) { - var newVec = goog.vec.Vec4.createFloat32(); - goog.vec.Vec4.setFromArray(newVec, vec); - return newVec; -}; - - -/** - * Creates a new 4 element Float32 vector initialized with the supplied values. - * - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @param {number} v3 The value for element at index 3. - * @return {!goog.vec.Vec4.Float32} The new vector. - */ -goog.vec.Vec4.createFloat32FromValues = function(v0, v1, v2, v3) { - var vec = goog.vec.Vec4.createFloat32(); - goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); - return vec; -}; - - -/** - * Creates a clone of the given 4 element Float32 vector. - * - * @param {goog.vec.Vec4.Float32} vec The source 3 element vector. - * @return {!goog.vec.Vec4.Float32} The new cloned vector. - */ -goog.vec.Vec4.cloneFloat32 = goog.vec.Vec4.createFloat32FromArray; - - -/** - * Creates a new 4 element Float64 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec4.AnyType} vec The source 4 element array. - * @return {!goog.vec.Vec4.Float64} The new 4 element array. - */ -goog.vec.Vec4.createFloat64FromArray = function(vec) { - var newVec = goog.vec.Vec4.createFloat64(); - goog.vec.Vec4.setFromArray(newVec, vec); - return newVec; -}; - - -/** -* Creates a new 4 element Float64 vector initialized with the supplied values. -* -* @param {number} v0 The value for element at index 0. -* @param {number} v1 The value for element at index 1. -* @param {number} v2 The value for element at index 2. -* @param {number} v3 The value for element at index 3. -* @return {!goog.vec.Vec4.Float64} The new vector. -*/ -goog.vec.Vec4.createFloat64FromValues = function(v0, v1, v2, v3) { - var vec = goog.vec.Vec4.createFloat64(); - goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); - return vec; -}; - - -/** - * Creates a clone of the given 4 element vector. - * - * @param {goog.vec.Vec4.Float64} vec The source 4 element vector. - * @return {!goog.vec.Vec4.Float64} The new cloned vector. - */ -goog.vec.Vec4.cloneFloat64 = goog.vec.Vec4.createFloat64FromArray; - - -/** - * Creates a new 4 element vector initialized with the supplied values. - * - * @deprecated Use createFloat32FromValues. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @param {number} v3 The value for element at index 3. - * @return {!goog.vec.Vec4.Type} The new vector. - */ -goog.vec.Vec4.createFromValues = function(v0, v1, v2, v3) { - var vec = goog.vec.Vec4.create(); - goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); - return vec; -}; - - -/** - * Creates a clone of the given 4 element vector. - * - * @deprecated Use cloneFloat32. - * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element vector. - * @return {!goog.vec.Vec4.Type} The new cloned vector. - */ -goog.vec.Vec4.clone = goog.vec.Vec4.createFromArray; - - -/** - * Initializes the vector with the given values. - * - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @param {number} v3 The value for element at index 3. - * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be - * chained together. - */ -goog.vec.Vec4.setFromValues = function(vec, v0, v1, v2, v3) { - vec[0] = v0; - vec[1] = v1; - vec[2] = v2; - vec[3] = v3; - return vec; -}; - - -/** - * Initializes the vector with the given array of values. - * - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the - * values. - * @param {goog.vec.Vec4.AnyType} values The array of values. - * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be - * chained together. - */ -goog.vec.Vec4.setFromArray = function(vec, values) { - vec[0] = values[0]; - vec[1] = values[1]; - vec[2] = values[2]; - vec[3] = values[3]; - return vec; -}; - - -/** - * Performs a component-wise addition of vec0 and vec1 together storing the - * result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The first addend. - * @param {goog.vec.Vec4.AnyType} vec1 The second addend. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.add = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] + vec1[0]; - resultVec[1] = vec0[1] + vec1[1]; - resultVec[2] = vec0[2] + vec1[2]; - resultVec[3] = vec0[3] + vec1[3]; - return resultVec; -}; - - -/** - * Performs a component-wise subtraction of vec1 from vec0 storing the - * result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The minuend. - * @param {goog.vec.Vec4.AnyType} vec1 The subtrahend. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.subtract = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] - vec1[0]; - resultVec[1] = vec0[1] - vec1[1]; - resultVec[2] = vec0[2] - vec1[2]; - resultVec[3] = vec0[3] - vec1[3]; - return resultVec; -}; - - -/** - * Negates vec0, storing the result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector to negate. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.negate = function(vec0, resultVec) { - resultVec[0] = -vec0[0]; - resultVec[1] = -vec0[1]; - resultVec[2] = -vec0[2]; - resultVec[3] = -vec0[3]; - return resultVec; -}; - - -/** - * Takes the absolute value of each component of vec0 storing the result in - * resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the result. - * May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.abs = function(vec0, resultVec) { - resultVec[0] = Math.abs(vec0[0]); - resultVec[1] = Math.abs(vec0[1]); - resultVec[2] = Math.abs(vec0[2]); - resultVec[3] = Math.abs(vec0[3]); - return resultVec; -}; - - -/** - * Multiplies each component of vec0 with scalar storing the product into - * resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {number} scalar The value to multiply with each component of vec0. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.scale = function(vec0, scalar, resultVec) { - resultVec[0] = vec0[0] * scalar; - resultVec[1] = vec0[1] * scalar; - resultVec[2] = vec0[2] * scalar; - resultVec[3] = vec0[3] * scalar; - return resultVec; -}; - - -/** - * Returns the magnitudeSquared of the given vector. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. - */ -goog.vec.Vec4.magnitudeSquared = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3]; - return x * x + y * y + z * z + w * w; -}; - - -/** - * Returns the magnitude of the given vector. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. - */ -goog.vec.Vec4.magnitude = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3]; - return Math.sqrt(x * x + y * y + z * z + w * w); -}; - - -/** - * Normalizes the given vector storing the result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector to normalize. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.normalize = function(vec0, resultVec) { - var ilen = 1 / goog.vec.Vec4.magnitude(vec0); - resultVec[0] = vec0[0] * ilen; - resultVec[1] = vec0[1] * ilen; - resultVec[2] = vec0[2] * ilen; - resultVec[3] = vec0[3] * ilen; - return resultVec; -}; - - -/** - * Returns the scalar product of vectors v0 and v1. - * - * @param {goog.vec.Vec4.AnyType} v0 The first vector. - * @param {goog.vec.Vec4.AnyType} v1 The second vector. - * @return {number} The scalar product. - */ -goog.vec.Vec4.dot = function(v0, v1) { - return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2] + v0[3] * v1[3]; -}; - - -/** - * Linearly interpolate from v0 to v1 according to f. The value of f should be - * in the range [0..1] otherwise the results are undefined. - * - * @param {goog.vec.Vec4.AnyType} v0 The first vector. - * @param {goog.vec.Vec4.AnyType} v1 The second vector. - * @param {number} f The interpolation factor. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the - * results (may be v0 or v1). - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.lerp = function(v0, v1, f, resultVec) { - var x = v0[0], y = v0[1], z = v0[2], w = v0[3]; - resultVec[0] = (v1[0] - x) * f + x; - resultVec[1] = (v1[1] - y) * f + y; - resultVec[2] = (v1[2] - z) * f + z; - resultVec[3] = (v1[3] - w) * f + w; - return resultVec; -}; - - -/** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the larger values in resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.max = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.max(vec0[0], limit); - resultVec[1] = Math.max(vec0[1], limit); - resultVec[2] = Math.max(vec0[2], limit); - resultVec[3] = Math.max(vec0[3], limit); - } else { - resultVec[0] = Math.max(vec0[0], limit[0]); - resultVec[1] = Math.max(vec0[1], limit[1]); - resultVec[2] = Math.max(vec0[2], limit[2]); - resultVec[3] = Math.max(vec0[3], limit[3]); - } - return resultVec; -}; - - -/** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the smaller values in resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. - */ -goog.vec.Vec4.min = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.min(vec0[0], limit); - resultVec[1] = Math.min(vec0[1], limit); - resultVec[2] = Math.min(vec0[2], limit); - resultVec[3] = Math.min(vec0[3], limit); - } else { - resultVec[0] = Math.min(vec0[0], limit[0]); - resultVec[1] = Math.min(vec0[1], limit[1]); - resultVec[2] = Math.min(vec0[2], limit[2]); - resultVec[3] = Math.min(vec0[3], limit[3]); - } - return resultVec; -}; - - -/** - * Returns true if the components of v0 are equal to the components of v1. - * - * @param {goog.vec.Vec4.AnyType} v0 The first vector. - * @param {goog.vec.Vec4.AnyType} v1 The second vector. - * @return {boolean} True if the vectors are equal, false otherwise. - */ -goog.vec.Vec4.equals = function(v0, v1) { - return v0.length == v1.length && - v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2] && v0[3] == v1[3]; -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Implements 4x4 matrices and their related functions which are - * compatible with WebGL. The API is structured to avoid unnecessary memory - * allocations. The last parameter will typically be the output vector and - * an object can be both an input and output parameter to all methods except - * where noted. Matrix operations follow the mathematical form when multiplying - * vectors as follows: resultVec = matrix * vec. - * - * The matrices are stored in column-major order. - * - */ -goog.provide('goog.vec.Mat4'); - -goog.require('goog.vec'); -goog.require('goog.vec.Vec3'); -goog.require('goog.vec.Vec4'); - - -/** @typedef {goog.vec.Float32} */ goog.vec.Mat4.Float32; -/** @typedef {goog.vec.Float64} */ goog.vec.Mat4.Float64; -/** @typedef {goog.vec.Number} */ goog.vec.Mat4.Number; -/** @typedef {goog.vec.AnyType} */ goog.vec.Mat4.AnyType; - -// The following two types are deprecated - use the above types instead. -/** @typedef {!Float32Array} */ goog.vec.Mat4.Type; -/** @typedef {goog.vec.ArrayType} */ goog.vec.Mat4.Mat4Like; - - -/** - * Creates the array representation of a 4x4 matrix of Float32. - * The use of the array directly instead of a class reduces overhead. - * The returned matrix is cleared to all zeros. - * - * @return {!goog.vec.Mat4.Float32} The new matrix. - */ -goog.vec.Mat4.createFloat32 = function() { - return new Float32Array(16); -}; - - -/** - * Creates the array representation of a 4x4 matrix of Float64. - * The returned matrix is cleared to all zeros. - * - * @return {!goog.vec.Mat4.Float64} The new matrix. - */ -goog.vec.Mat4.createFloat64 = function() { - return new Float64Array(16); -}; - - -/** - * Creates the array representation of a 4x4 matrix of Number. - * The returned matrix is cleared to all zeros. - * - * @return {!goog.vec.Mat4.Number} The new matrix. - */ -goog.vec.Mat4.createNumber = function() { - var a = new Array(16); - goog.vec.Mat4.setFromValues(a, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0); - return a; -}; - - -/** - * Creates the array representation of a 4x4 matrix of Float32. - * The returned matrix is cleared to all zeros. - * - * @deprecated Use createFloat32. - * @return {!goog.vec.Mat4.Type} The new matrix. - */ -goog.vec.Mat4.create = function() { - return goog.vec.Mat4.createFloat32(); -}; - - -/** - * Creates a 4x4 identity matrix of Float32. - * - * @return {!goog.vec.Mat4.Float32} The new 16 element array. - */ -goog.vec.Mat4.createFloat32Identity = function() { - var mat = goog.vec.Mat4.createFloat32(); - mat[0] = mat[5] = mat[10] = mat[15] = 1; - return mat; -}; - - -/** - * Creates a 4x4 identity matrix of Float64. - * - * @return {!goog.vec.Mat4.Float64} The new 16 element array. - */ -goog.vec.Mat4.createFloat64Identity = function() { - var mat = goog.vec.Mat4.createFloat64(); - mat[0] = mat[5] = mat[10] = mat[15] = 1; - return mat; -}; - - -/** - * Creates a 4x4 identity matrix of Number. - * The returned matrix is cleared to all zeros. - * - * @return {!goog.vec.Mat4.Number} The new 16 element array. - */ -goog.vec.Mat4.createNumberIdentity = function() { - var a = new Array(16); - goog.vec.Mat4.setFromValues(a, - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - return a; -}; - - -/** - * Creates the array representation of a 4x4 matrix of Float32. - * The returned matrix is cleared to all zeros. - * - * @deprecated Use createFloat32Identity. - * @return {!goog.vec.Mat4.Type} The new 16 element array. - */ -goog.vec.Mat4.createIdentity = function() { - return goog.vec.Mat4.createFloat32Identity(); -}; - - -/** - * Creates a 4x4 matrix of Float32 initialized from the given array. - * - * @param {goog.vec.Mat4.AnyType} matrix The array containing the - * matrix values in column major order. - * @return {!goog.vec.Mat4.Float32} The new, 16 element array. - */ -goog.vec.Mat4.createFloat32FromArray = function(matrix) { - var newMatrix = goog.vec.Mat4.createFloat32(); - goog.vec.Mat4.setFromArray(newMatrix, matrix); - return newMatrix; -}; - - -/** - * Creates a 4x4 matrix of Float32 initialized from the given values. - * - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {!goog.vec.Mat4.Float32} The new, 16 element array. - */ -goog.vec.Mat4.createFloat32FromValues = function( - v00, v10, v20, v30, - v01, v11, v21, v31, - v02, v12, v22, v32, - v03, v13, v23, v33) { - var newMatrix = goog.vec.Mat4.createFloat32(); - goog.vec.Mat4.setFromValues( - newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33); - return newMatrix; -}; - - -/** - * Creates a clone of a 4x4 matrix of Float32. - * - * @param {goog.vec.Mat4.Float32} matrix The source 4x4 matrix. - * @return {!goog.vec.Mat4.Float32} The new 4x4 element matrix. - */ -goog.vec.Mat4.cloneFloat32 = goog.vec.Mat4.createFloat32FromArray; - - -/** - * Creates a 4x4 matrix of Float64 initialized from the given array. - * - * @param {goog.vec.Mat4.AnyType} matrix The array containing the - * matrix values in column major order. - * @return {!goog.vec.Mat4.Float64} The new, nine element array. - */ -goog.vec.Mat4.createFloat64FromArray = function(matrix) { - var newMatrix = goog.vec.Mat4.createFloat64(); - goog.vec.Mat4.setFromArray(newMatrix, matrix); - return newMatrix; -}; - - -/** - * Creates a 4x4 matrix of Float64 initialized from the given values. - * - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {!goog.vec.Mat4.Float64} The new, 16 element array. - */ -goog.vec.Mat4.createFloat64FromValues = function( - v00, v10, v20, v30, - v01, v11, v21, v31, - v02, v12, v22, v32, - v03, v13, v23, v33) { - var newMatrix = goog.vec.Mat4.createFloat64(); - goog.vec.Mat4.setFromValues( - newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33); - return newMatrix; -}; - - -/** - * Creates a clone of a 4x4 matrix of Float64. - * - * @param {goog.vec.Mat4.Float64} matrix The source 4x4 matrix. - * @return {!goog.vec.Mat4.Float64} The new 4x4 element matrix. - */ -goog.vec.Mat4.cloneFloat64 = goog.vec.Mat4.createFloat64FromArray; - - -/** - * Creates a 4x4 matrix of Float32 initialized from the given array. - * - * @deprecated Use createFloat32FromArray. - * @param {goog.vec.Mat4.Mat4Like} matrix The array containing the - * matrix values in column major order. - * @return {!goog.vec.Mat4.Type} The new, nine element array. - */ -goog.vec.Mat4.createFromArray = function(matrix) { - var newMatrix = goog.vec.Mat4.createFloat32(); - goog.vec.Mat4.setFromArray(newMatrix, matrix); - return newMatrix; -}; - - -/** - * Creates a 4x4 matrix of Float32 initialized from the given values. - * - * @deprecated Use createFloat32FromValues. - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {!goog.vec.Mat4.Type} The new, 16 element array. - */ -goog.vec.Mat4.createFromValues = function( - v00, v10, v20, v30, - v01, v11, v21, v31, - v02, v12, v22, v32, - v03, v13, v23, v33) { - return goog.vec.Mat4.createFloat32FromValues( - v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33); -}; - - -/** - * Creates a clone of a 4x4 matrix of Float32. - * - * @deprecated Use cloneFloat32. - * @param {goog.vec.Mat4.Mat4Like} matrix The source 4x4 matrix. - * @return {!goog.vec.Mat4.Type} The new 4x4 element matrix. - */ -goog.vec.Mat4.clone = goog.vec.Mat4.createFromArray; - - -/** - * Retrieves the element at the requested row and column. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix containing the - * value to retrieve. - * @param {number} row The row index. - * @param {number} column The column index. - * @return {number} The element value at the requested row, column indices. - */ -goog.vec.Mat4.getElement = function(mat, row, column) { - return mat[row + column * 4]; -}; - - -/** - * Sets the element at the requested row and column. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to set the value on. - * @param {number} row The row index. - * @param {number} column The column index. - * @param {number} value The value to set at the requested row, column. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setElement = function(mat, row, column, value) { - mat[row + column * 4] = value; - return mat; -}; - - -/** - * Initializes the matrix from the set of values. Note the values supplied are - * in column major order. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the - * values. - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setFromValues = function( - mat, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33) { - mat[0] = v00; - mat[1] = v10; - mat[2] = v20; - mat[3] = v30; - mat[4] = v01; - mat[5] = v11; - mat[6] = v21; - mat[7] = v31; - mat[8] = v02; - mat[9] = v12; - mat[10] = v22; - mat[11] = v32; - mat[12] = v03; - mat[13] = v13; - mat[14] = v23; - mat[15] = v33; - return mat; -}; - - -/** - * Sets the matrix from the array of values stored in column major order. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Mat4.AnyType} values The column major ordered - * array of values to store in the matrix. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setFromArray = function(mat, values) { - mat[0] = values[0]; - mat[1] = values[1]; - mat[2] = values[2]; - mat[3] = values[3]; - mat[4] = values[4]; - mat[5] = values[5]; - mat[6] = values[6]; - mat[7] = values[7]; - mat[8] = values[8]; - mat[9] = values[9]; - mat[10] = values[10]; - mat[11] = values[11]; - mat[12] = values[12]; - mat[13] = values[13]; - mat[14] = values[14]; - mat[15] = values[15]; - return mat; -}; - - -/** - * Sets the matrix from the array of values stored in row major order. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Mat4.AnyType} values The row major ordered array of - * values to store in the matrix. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setFromRowMajorArray = function(mat, values) { - mat[0] = values[0]; - mat[1] = values[4]; - mat[2] = values[8]; - mat[3] = values[12]; - - mat[4] = values[1]; - mat[5] = values[5]; - mat[6] = values[9]; - mat[7] = values[13]; - - mat[8] = values[2]; - mat[9] = values[6]; - mat[10] = values[10]; - mat[11] = values[14]; - - mat[12] = values[3]; - mat[13] = values[7]; - mat[14] = values[11]; - mat[15] = values[15]; - - return mat; -}; - - -/** - * Sets the diagonal values of the matrix from the given values. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {number} v00 The values for (0, 0). - * @param {number} v11 The values for (1, 1). - * @param {number} v22 The values for (2, 2). - * @param {number} v33 The values for (3, 3). - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setDiagonalValues = function(mat, v00, v11, v22, v33) { - mat[0] = v00; - mat[5] = v11; - mat[10] = v22; - mat[15] = v33; - return mat; -}; - - -/** - * Sets the diagonal values of the matrix from the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Vec4.AnyType} vec The vector containing the values. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setDiagonal = function(mat, vec) { - mat[0] = vec[0]; - mat[5] = vec[1]; - mat[10] = vec[2]; - mat[15] = vec[3]; - return mat; -}; - - -/** - * Gets the diagonal values of the matrix into the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix containing the values. - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values. - * @param {number=} opt_diagonal Which diagonal to get. A value of 0 selects the - * main diagonal, a positive number selects a super diagonal and a negative - * number selects a sub diagonal. - * @return {goog.vec.Vec4.AnyType} return vec so that operations can be - * chained together. - */ -goog.vec.Mat4.getDiagonal = function(mat, vec, opt_diagonal) { - if (!opt_diagonal) { - // This is the most common case, so we avoid the for loop. - vec[0] = mat[0]; - vec[1] = mat[5]; - vec[2] = mat[10]; - vec[3] = mat[15]; - } else { - var offset = opt_diagonal > 0 ? 4 * opt_diagonal : -opt_diagonal; - for (var i = 0; i < 4 - Math.abs(opt_diagonal); i++) { - vec[i] = mat[offset + 5 * i]; - } - } - return vec; -}; - - -/** - * Sets the specified column with the supplied values. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to recieve the values. - * @param {number} column The column index to set the values on. - * @param {number} v0 The value for row 0. - * @param {number} v1 The value for row 1. - * @param {number} v2 The value for row 2. - * @param {number} v3 The value for row 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setColumnValues = function(mat, column, v0, v1, v2, v3) { - var i = column * 4; - mat[i] = v0; - mat[i + 1] = v1; - mat[i + 2] = v2; - mat[i + 3] = v3; - return mat; -}; - - -/** - * Sets the specified column with the value from the supplied vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {number} column The column index to set the values on. - * @param {goog.vec.Vec4.AnyType} vec The vector of elements for the column. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setColumn = function(mat, column, vec) { - var i = column * 4; - mat[i] = vec[0]; - mat[i + 1] = vec[1]; - mat[i + 2] = vec[2]; - mat[i + 3] = vec[3]; - return mat; -}; - - -/** - * Retrieves the specified column from the matrix into the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values. - * @param {number} column The column to get the values from. - * @param {goog.vec.Vec4.AnyType} vec The vector of elements to - * receive the column. - * @return {goog.vec.Vec4.AnyType} return vec so that operations can be - * chained together. - */ -goog.vec.Mat4.getColumn = function(mat, column, vec) { - var i = column * 4; - vec[0] = mat[i]; - vec[1] = mat[i + 1]; - vec[2] = mat[i + 2]; - vec[3] = mat[i + 3]; - return vec; -}; - - -/** - * Sets the columns of the matrix from the given vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Vec4.AnyType} vec0 The values for column 0. - * @param {goog.vec.Vec4.AnyType} vec1 The values for column 1. - * @param {goog.vec.Vec4.AnyType} vec2 The values for column 2. - * @param {goog.vec.Vec4.AnyType} vec3 The values for column 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setColumns = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.setColumn(mat, 0, vec0); - goog.vec.Mat4.setColumn(mat, 1, vec1); - goog.vec.Mat4.setColumn(mat, 2, vec2); - goog.vec.Mat4.setColumn(mat, 3, vec3); - return mat; -}; - - -/** - * Retrieves the column values from the given matrix into the given vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the columns. - * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive column 0. - * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive column 1. - * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive column 2. - * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive column 3. - */ -goog.vec.Mat4.getColumns = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.getColumn(mat, 0, vec0); - goog.vec.Mat4.getColumn(mat, 1, vec1); - goog.vec.Mat4.getColumn(mat, 2, vec2); - goog.vec.Mat4.getColumn(mat, 3, vec3); -}; - - -/** - * Sets the row values from the supplied values. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {number} row The index of the row to receive the values. - * @param {number} v0 The value for column 0. - * @param {number} v1 The value for column 1. - * @param {number} v2 The value for column 2. - * @param {number} v3 The value for column 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setRowValues = function(mat, row, v0, v1, v2, v3) { - mat[row] = v0; - mat[row + 4] = v1; - mat[row + 8] = v2; - mat[row + 12] = v3; - return mat; -}; - - -/** - * Sets the row values from the supplied vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the row values. - * @param {number} row The index of the row. - * @param {goog.vec.Vec4.AnyType} vec The vector containing the values. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setRow = function(mat, row, vec) { - mat[row] = vec[0]; - mat[row + 4] = vec[1]; - mat[row + 8] = vec[2]; - mat[row + 12] = vec[3]; - return mat; -}; - - -/** - * Retrieves the row values into the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values. - * @param {number} row The index of the row supplying the values. - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the row. - * @return {goog.vec.Vec4.AnyType} return vec so that operations can be - * chained together. - */ -goog.vec.Mat4.getRow = function(mat, row, vec) { - vec[0] = mat[row]; - vec[1] = mat[row + 4]; - vec[2] = mat[row + 8]; - vec[3] = mat[row + 12]; - return vec; -}; - - -/** - * Sets the rows of the matrix from the supplied vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Vec4.AnyType} vec0 The values for row 0. - * @param {goog.vec.Vec4.AnyType} vec1 The values for row 1. - * @param {goog.vec.Vec4.AnyType} vec2 The values for row 2. - * @param {goog.vec.Vec4.AnyType} vec3 The values for row 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setRows = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.setRow(mat, 0, vec0); - goog.vec.Mat4.setRow(mat, 1, vec1); - goog.vec.Mat4.setRow(mat, 2, vec2); - goog.vec.Mat4.setRow(mat, 3, vec3); - return mat; -}; - - -/** - * Retrieves the rows of the matrix into the supplied vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to supply the values. - * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive row 0. - * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive row 1. - * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive row 2. - * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive row 3. - */ -goog.vec.Mat4.getRows = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.getRow(mat, 0, vec0); - goog.vec.Mat4.getRow(mat, 1, vec1); - goog.vec.Mat4.getRow(mat, 2, vec2); - goog.vec.Mat4.getRow(mat, 3, vec3); -}; - - -/** - * Makes the given 4x4 matrix the zero matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @return {!goog.vec.Mat4.AnyType} return mat so operations can be chained. - */ -goog.vec.Mat4.makeZero = function(mat) { - mat[0] = 0; - mat[1] = 0; - mat[2] = 0; - mat[3] = 0; - mat[4] = 0; - mat[5] = 0; - mat[6] = 0; - mat[7] = 0; - mat[8] = 0; - mat[9] = 0; - mat[10] = 0; - mat[11] = 0; - mat[12] = 0; - mat[13] = 0; - mat[14] = 0; - mat[15] = 0; - return mat; -}; - - -/** - * Makes the given 4x4 matrix the identity matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @return {goog.vec.Mat4.AnyType} return mat so operations can be chained. - */ -goog.vec.Mat4.makeIdentity = function(mat) { - mat[0] = 1; - mat[1] = 0; - mat[2] = 0; - mat[3] = 0; - mat[4] = 0; - mat[5] = 1; - mat[6] = 0; - mat[7] = 0; - mat[8] = 0; - mat[9] = 0; - mat[10] = 1; - mat[11] = 0; - mat[12] = 0; - mat[13] = 0; - mat[14] = 0; - mat[15] = 1; - return mat; -}; - - -/** - * Performs a per-component addition of the matrix mat0 and mat1, storing - * the result into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat0 The first addend. - * @param {goog.vec.Mat4.AnyType} mat1 The second addend. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to - * receive the results (may be either mat0 or mat1). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. - */ -goog.vec.Mat4.addMat = function(mat0, mat1, resultMat) { - resultMat[0] = mat0[0] + mat1[0]; - resultMat[1] = mat0[1] + mat1[1]; - resultMat[2] = mat0[2] + mat1[2]; - resultMat[3] = mat0[3] + mat1[3]; - resultMat[4] = mat0[4] + mat1[4]; - resultMat[5] = mat0[5] + mat1[5]; - resultMat[6] = mat0[6] + mat1[6]; - resultMat[7] = mat0[7] + mat1[7]; - resultMat[8] = mat0[8] + mat1[8]; - resultMat[9] = mat0[9] + mat1[9]; - resultMat[10] = mat0[10] + mat1[10]; - resultMat[11] = mat0[11] + mat1[11]; - resultMat[12] = mat0[12] + mat1[12]; - resultMat[13] = mat0[13] + mat1[13]; - resultMat[14] = mat0[14] + mat1[14]; - resultMat[15] = mat0[15] + mat1[15]; - return resultMat; -}; - - -/** - * Performs a per-component subtraction of the matrix mat0 and mat1, - * storing the result into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat0 The minuend. - * @param {goog.vec.Mat4.AnyType} mat1 The subtrahend. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be either mat0 or mat1). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. - */ -goog.vec.Mat4.subMat = function(mat0, mat1, resultMat) { - resultMat[0] = mat0[0] - mat1[0]; - resultMat[1] = mat0[1] - mat1[1]; - resultMat[2] = mat0[2] - mat1[2]; - resultMat[3] = mat0[3] - mat1[3]; - resultMat[4] = mat0[4] - mat1[4]; - resultMat[5] = mat0[5] - mat1[5]; - resultMat[6] = mat0[6] - mat1[6]; - resultMat[7] = mat0[7] - mat1[7]; - resultMat[8] = mat0[8] - mat1[8]; - resultMat[9] = mat0[9] - mat1[9]; - resultMat[10] = mat0[10] - mat1[10]; - resultMat[11] = mat0[11] - mat1[11]; - resultMat[12] = mat0[12] - mat1[12]; - resultMat[13] = mat0[13] - mat1[13]; - resultMat[14] = mat0[14] - mat1[14]; - resultMat[15] = mat0[15] - mat1[15]; - return resultMat; -}; - - -/** - * Multiplies matrix mat with the given scalar, storing the result - * into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} scalar The scalar value to multiply to each element of mat. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be mat). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. - */ -goog.vec.Mat4.multScalar = function(mat, scalar, resultMat) { - resultMat[0] = mat[0] * scalar; - resultMat[1] = mat[1] * scalar; - resultMat[2] = mat[2] * scalar; - resultMat[3] = mat[3] * scalar; - resultMat[4] = mat[4] * scalar; - resultMat[5] = mat[5] * scalar; - resultMat[6] = mat[6] * scalar; - resultMat[7] = mat[7] * scalar; - resultMat[8] = mat[8] * scalar; - resultMat[9] = mat[9] * scalar; - resultMat[10] = mat[10] * scalar; - resultMat[11] = mat[11] * scalar; - resultMat[12] = mat[12] * scalar; - resultMat[13] = mat[13] * scalar; - resultMat[14] = mat[14] * scalar; - resultMat[15] = mat[15] * scalar; - return resultMat; -}; - - -/** - * Multiplies the two matrices mat0 and mat1 using matrix multiplication, - * storing the result into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat0 The first (left hand) matrix. - * @param {goog.vec.Mat4.AnyType} mat1 The second (right hand) matrix. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be either mat0 or mat1). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. - */ -goog.vec.Mat4.multMat = function(mat0, mat1, resultMat) { - var a00 = mat0[0], a10 = mat0[1], a20 = mat0[2], a30 = mat0[3]; - var a01 = mat0[4], a11 = mat0[5], a21 = mat0[6], a31 = mat0[7]; - var a02 = mat0[8], a12 = mat0[9], a22 = mat0[10], a32 = mat0[11]; - var a03 = mat0[12], a13 = mat0[13], a23 = mat0[14], a33 = mat0[15]; - - var b00 = mat1[0], b10 = mat1[1], b20 = mat1[2], b30 = mat1[3]; - var b01 = mat1[4], b11 = mat1[5], b21 = mat1[6], b31 = mat1[7]; - var b02 = mat1[8], b12 = mat1[9], b22 = mat1[10], b32 = mat1[11]; - var b03 = mat1[12], b13 = mat1[13], b23 = mat1[14], b33 = mat1[15]; - - resultMat[0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30; - resultMat[1] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30; - resultMat[2] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30; - resultMat[3] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30; - - resultMat[4] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31; - resultMat[5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31; - resultMat[6] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31; - resultMat[7] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31; - - resultMat[8] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32; - resultMat[9] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32; - resultMat[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32; - resultMat[11] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32; - - resultMat[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33; - resultMat[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33; - resultMat[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33; - resultMat[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33; - return resultMat; -}; - - -/** - * Transposes the given matrix mat storing the result into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to transpose. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be mat). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. - */ -goog.vec.Mat4.transpose = function(mat, resultMat) { - if (resultMat == mat) { - var a10 = mat[1], a20 = mat[2], a30 = mat[3]; - var a21 = mat[6], a31 = mat[7]; - var a32 = mat[11]; - resultMat[1] = mat[4]; - resultMat[2] = mat[8]; - resultMat[3] = mat[12]; - resultMat[4] = a10; - resultMat[6] = mat[9]; - resultMat[7] = mat[13]; - resultMat[8] = a20; - resultMat[9] = a21; - resultMat[11] = mat[14]; - resultMat[12] = a30; - resultMat[13] = a31; - resultMat[14] = a32; - } else { - resultMat[0] = mat[0]; - resultMat[1] = mat[4]; - resultMat[2] = mat[8]; - resultMat[3] = mat[12]; - - resultMat[4] = mat[1]; - resultMat[5] = mat[5]; - resultMat[6] = mat[9]; - resultMat[7] = mat[13]; - - resultMat[8] = mat[2]; - resultMat[9] = mat[6]; - resultMat[10] = mat[10]; - resultMat[11] = mat[14]; - - resultMat[12] = mat[3]; - resultMat[13] = mat[7]; - resultMat[14] = mat[11]; - resultMat[15] = mat[15]; - } - return resultMat; -}; - - -/** - * Computes the determinant of the matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to compute the matrix for. - * @return {number} The determinant of the matrix. - */ -goog.vec.Mat4.determinant = function(mat) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; - - var a0 = m00 * m11 - m10 * m01; - var a1 = m00 * m21 - m20 * m01; - var a2 = m00 * m31 - m30 * m01; - var a3 = m10 * m21 - m20 * m11; - var a4 = m10 * m31 - m30 * m11; - var a5 = m20 * m31 - m30 * m21; - var b0 = m02 * m13 - m12 * m03; - var b1 = m02 * m23 - m22 * m03; - var b2 = m02 * m33 - m32 * m03; - var b3 = m12 * m23 - m22 * m13; - var b4 = m12 * m33 - m32 * m13; - var b5 = m22 * m33 - m32 * m23; - - return a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; -}; - - -/** - * Computes the inverse of mat storing the result into resultMat. If the - * inverse is defined, this function returns true, false otherwise. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to invert. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the result (may be mat). - * @return {boolean} True if the inverse is defined. If false is returned, - * resultMat is not modified. - */ -goog.vec.Mat4.invert = function(mat, resultMat) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; - - var a0 = m00 * m11 - m10 * m01; - var a1 = m00 * m21 - m20 * m01; - var a2 = m00 * m31 - m30 * m01; - var a3 = m10 * m21 - m20 * m11; - var a4 = m10 * m31 - m30 * m11; - var a5 = m20 * m31 - m30 * m21; - var b0 = m02 * m13 - m12 * m03; - var b1 = m02 * m23 - m22 * m03; - var b2 = m02 * m33 - m32 * m03; - var b3 = m12 * m23 - m22 * m13; - var b4 = m12 * m33 - m32 * m13; - var b5 = m22 * m33 - m32 * m23; - - var det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; - if (det == 0) { - return false; - } - - var idet = 1.0 / det; - resultMat[0] = (m11 * b5 - m21 * b4 + m31 * b3) * idet; - resultMat[1] = (-m10 * b5 + m20 * b4 - m30 * b3) * idet; - resultMat[2] = (m13 * a5 - m23 * a4 + m33 * a3) * idet; - resultMat[3] = (-m12 * a5 + m22 * a4 - m32 * a3) * idet; - resultMat[4] = (-m01 * b5 + m21 * b2 - m31 * b1) * idet; - resultMat[5] = (m00 * b5 - m20 * b2 + m30 * b1) * idet; - resultMat[6] = (-m03 * a5 + m23 * a2 - m33 * a1) * idet; - resultMat[7] = (m02 * a5 - m22 * a2 + m32 * a1) * idet; - resultMat[8] = (m01 * b4 - m11 * b2 + m31 * b0) * idet; - resultMat[9] = (-m00 * b4 + m10 * b2 - m30 * b0) * idet; - resultMat[10] = (m03 * a4 - m13 * a2 + m33 * a0) * idet; - resultMat[11] = (-m02 * a4 + m12 * a2 - m32 * a0) * idet; - resultMat[12] = (-m01 * b3 + m11 * b1 - m21 * b0) * idet; - resultMat[13] = (m00 * b3 - m10 * b1 + m20 * b0) * idet; - resultMat[14] = (-m03 * a3 + m13 * a1 - m23 * a0) * idet; - resultMat[15] = (m02 * a3 - m12 * a1 + m22 * a0) * idet; - return true; -}; - - -/** - * Returns true if the components of mat0 are equal to the components of mat1. - * - * @param {goog.vec.Mat4.AnyType} mat0 The first matrix. - * @param {goog.vec.Mat4.AnyType} mat1 The second matrix. - * @return {boolean} True if the the two matrices are equivalent. - */ -goog.vec.Mat4.equals = function(mat0, mat1) { - return mat0.length == mat1.length && - mat0[0] == mat1[0] && - mat0[1] == mat1[1] && - mat0[2] == mat1[2] && - mat0[3] == mat1[3] && - mat0[4] == mat1[4] && - mat0[5] == mat1[5] && - mat0[6] == mat1[6] && - mat0[7] == mat1[7] && - mat0[8] == mat1[8] && - mat0[9] == mat1[9] && - mat0[10] == mat1[10] && - mat0[11] == mat1[11] && - mat0[12] == mat1[12] && - mat0[13] == mat1[13] && - mat0[14] == mat1[14] && - mat0[15] == mat1[15]; -}; - - -/** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * upper 3x4 matrix omitting the projective component. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. - * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to - * receive the results (may be vec). - * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be - * chained together. - */ -goog.vec.Mat4.multVec3 = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2]; - resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + mat[12]; - resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + mat[13]; - resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + mat[14]; - return resultVec; -}; - - -/** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * upper 3x3 matrix omitting the projective component and translation - * components. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. - * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to - * receive the results (may be vec). - * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be - * chained together. - */ -goog.vec.Mat4.multVec3NoTranslate = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2]; - resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8]; - resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9]; - resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10]; - return resultVec; -}; - - -/** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * full 4x4 matrix with the homogeneous divide applied to reduce the 4 element - * vector to a 3 element vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. - * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector - * to receive the results (may be vec). - * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be - * chained together. - */ -goog.vec.Mat4.multVec3Projective = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2]; - var invw = 1 / (x * mat[3] + y * mat[7] + z * mat[11] + mat[15]); - resultVec[0] = (x * mat[0] + y * mat[4] + z * mat[8] + mat[12]) * invw; - resultVec[1] = (x * mat[1] + y * mat[5] + z * mat[9] + mat[13]) * invw; - resultVec[2] = (x * mat[2] + y * mat[6] + z * mat[10] + mat[14]) * invw; - return resultVec; -}; - - -/** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec4.AnyType} vec The vector to transform. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the results (may be vec). - * @return {goog.vec.Vec4.AnyType} return resultVec so that operations can be - * chained together. - */ -goog.vec.Mat4.multVec4 = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; - resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + w * mat[12]; - resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + w * mat[13]; - resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + w * mat[14]; - resultVec[3] = x * mat[3] + y * mat[7] + z * mat[11] + w * mat[15]; - return resultVec; -}; - - -/** - * Makes the given 4x4 matrix a translation matrix with x, y and z - * translation factors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The translation along the x axis. - * @param {number} y The translation along the y axis. - * @param {number} z The translation along the z axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeTranslate = function(mat, x, y, z) { - goog.vec.Mat4.makeIdentity(mat); - return goog.vec.Mat4.setColumnValues(mat, 3, x, y, z, 1); -}; - - -/** - * Makes the given 4x4 matrix as a scale matrix with x, y and z scale factors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The scale along the x axis. - * @param {number} y The scale along the y axis. - * @param {number} z The scale along the z axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeScale = function(mat, x, y, z) { - goog.vec.Mat4.makeIdentity(mat); - return goog.vec.Mat4.setDiagonalValues(mat, x, y, z, 1); -}; - - -/** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the axis defined by the vector (ax, ay, az). - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @param {number} ax The x component of the rotation axis. - * @param {number} ay The y component of the rotation axis. - * @param {number} az The z component of the rotation axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeRotate = function(mat, angle, ax, ay, az) { - var c = Math.cos(angle); - var d = 1 - c; - var s = Math.sin(angle); - - return goog.vec.Mat4.setFromValues(mat, - ax * ax * d + c, - ax * ay * d + az * s, - ax * az * d - ay * s, - 0, - - ax * ay * d - az * s, - ay * ay * d + c, - ay * az * d + ax * s, - 0, - - ax * az * d + ay * s, - ay * az * d - ax * s, - az * az * d + c, - 0, - - 0, 0, 0, 1); -}; - - -/** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the X axis. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeRotateX = function(mat, angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - return goog.vec.Mat4.setFromValues( - mat, 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1); -}; - - -/** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the Y axis. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeRotateY = function(mat, angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - return goog.vec.Mat4.setFromValues( - mat, c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1); -}; - - -/** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the Z axis. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeRotateZ = function(mat, angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - return goog.vec.Mat4.setFromValues( - mat, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); -}; - - -/** - * Makes the given 4x4 matrix a perspective projection matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} left The coordinate of the left clipping plane. - * @param {number} right The coordinate of the right clipping plane. - * @param {number} bottom The coordinate of the bottom clipping plane. - * @param {number} top The coordinate of the top clipping plane. - * @param {number} near The distance to the near clipping plane. - * @param {number} far The distance to the far clipping plane. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeFrustum = function(mat, left, right, bottom, top, near, far) { - var x = (2 * near) / (right - left); - var y = (2 * near) / (top - bottom); - var a = (right + left) / (right - left); - var b = (top + bottom) / (top - bottom); - var c = -(far + near) / (far - near); - var d = -(2 * far * near) / (far - near); - - return goog.vec.Mat4.setFromValues(mat, - x, 0, 0, 0, - 0, y, 0, 0, - a, b, c, -1, - 0, 0, d, 0 - ); -}; - - -/** - * Makse the given 4x4 matrix perspective projection matrix given a - * field of view and aspect ratio. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} fovy The field of view along the y (vertical) axis in - * radians. - * @param {number} aspect The x (width) to y (height) aspect ratio. - * @param {number} near The distance to the near clipping plane. - * @param {number} far The distance to the far clipping plane. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makePerspective = function(mat, fovy, aspect, near, far) { - var angle = fovy / 2; - var dz = far - near; - var sinAngle = Math.sin(angle); - if (dz == 0 || sinAngle == 0 || aspect == 0) { - return mat; - } - - var cot = Math.cos(angle) / sinAngle; - return goog.vec.Mat4.setFromValues(mat, - cot / aspect, 0, 0, 0, - 0, cot, 0, 0, - 0, 0, -(far + near) / dz, -1, - 0, 0, -(2 * near * far) / dz, 0 - ); -}; - - -/** - * Makes the given 4x4 matrix an orthographic projection matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} left The coordinate of the left clipping plane. - * @param {number} right The coordinate of the right clipping plane. - * @param {number} bottom The coordinate of the bottom clipping plane. - * @param {number} top The coordinate of the top clipping plane. - * @param {number} near The distance to the near clipping plane. - * @param {number} far The distance to the far clipping plane. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeOrtho = function(mat, left, right, bottom, top, near, far) { - var x = 2 / (right - left); - var y = 2 / (top - bottom); - var z = -2 / (far - near); - var a = -(right + left) / (right - left); - var b = -(top + bottom) / (top - bottom); - var c = -(far + near) / (far - near); - - return goog.vec.Mat4.setFromValues(mat, - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - a, b, c, 1 - ); -}; - - -/** - * Makes the given 4x4 matrix a modelview matrix of a camera so that - * the camera is 'looking at' the given center point. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point - * (camera origin). - * @param {goog.vec.Vec3.AnyType} centerPt The point to aim the camera at. - * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that identifies - * the up direction for the camera. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeLookAt = function(mat, eyePt, centerPt, worldUpVec) { - // Compute the direction vector from the eye point to the center point and - // normalize. - var fwdVec = goog.vec.Mat4.tmpVec4_[0]; - goog.vec.Vec3.subtract(centerPt, eyePt, fwdVec); - goog.vec.Vec3.normalize(fwdVec, fwdVec); - fwdVec[3] = 0; - - // Compute the side vector from the forward vector and the input up vector. - var sideVec = goog.vec.Mat4.tmpVec4_[1]; - goog.vec.Vec3.cross(fwdVec, worldUpVec, sideVec); - goog.vec.Vec3.normalize(sideVec, sideVec); - sideVec[3] = 0; - - // Now the up vector to form the orthonormal basis. - var upVec = goog.vec.Mat4.tmpVec4_[2]; - goog.vec.Vec3.cross(sideVec, fwdVec, upVec); - goog.vec.Vec3.normalize(upVec, upVec); - upVec[3] = 0; - - // Update the view matrix with the new orthonormal basis and position the - // camera at the given eye point. - goog.vec.Vec3.negate(fwdVec, fwdVec); - goog.vec.Mat4.setRow(mat, 0, sideVec); - goog.vec.Mat4.setRow(mat, 1, upVec); - goog.vec.Mat4.setRow(mat, 2, fwdVec); - goog.vec.Mat4.setRowValues(mat, 3, 0, 0, 0, 1); - goog.vec.Mat4.translate( - mat, -eyePt[0], -eyePt[1], -eyePt[2]); - - return mat; -}; - - -/** - * Decomposes a matrix into the lookAt vectors eyePt, fwdVec and worldUpVec. - * The matrix represents the modelview matrix of a camera. It is the inverse - * of lookAt except for the output of the fwdVec instead of centerPt. - * The centerPt itself cannot be recovered from a modelview matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point - * (camera origin). - * @param {goog.vec.Vec3.AnyType} fwdVec The vector describing where - * the camera points to. - * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that - * identifies the up direction for the camera. - * @return {boolean} True if the method succeeds, false otherwise. - * The method can only fail if the inverse of viewMatrix is not defined. - */ -goog.vec.Mat4.toLookAt = function(mat, eyePt, fwdVec, worldUpVec) { - // Get eye of the camera. - var matInverse = goog.vec.Mat4.tmpMat4_[0]; - if (!goog.vec.Mat4.invert(mat, matInverse)) { - // The input matrix does not have a valid inverse. - return false; - } - - if (eyePt) { - eyePt[0] = matInverse[12]; - eyePt[1] = matInverse[13]; - eyePt[2] = matInverse[14]; - } - - // Get forward vector from the definition of lookAt. - if (fwdVec || worldUpVec) { - if (!fwdVec) { - fwdVec = goog.vec.Mat4.tmpVec3_[0]; - } - fwdVec[0] = -mat[2]; - fwdVec[1] = -mat[6]; - fwdVec[2] = -mat[10]; - // Normalize forward vector. - goog.vec.Vec3.normalize(fwdVec, fwdVec); - } - - if (worldUpVec) { - // Get side vector from the definition of gluLookAt. - var side = goog.vec.Mat4.tmpVec3_[1]; - side[0] = mat[0]; - side[1] = mat[4]; - side[2] = mat[8]; - // Compute up vector as a up = side x forward. - goog.vec.Vec3.cross(side, fwdVec, worldUpVec); - // Normalize up vector. - goog.vec.Vec3.normalize(worldUpVec, worldUpVec); - } - return true; -}; - - -/** - * Makes the given 4x4 matrix a rotation matrix given Euler angles using - * the ZXZ convention. - * Given the euler angles [theta1, theta2, theta3], the rotation is defined as - * rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3), - * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi]. - * rotation_x(theta) means rotation around the X axis of theta radians, - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} theta1 The angle of rotation around the Z axis in radians. - * @param {number} theta2 The angle of rotation around the X axis in radians. - * @param {number} theta3 The angle of rotation around the Z axis in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeEulerZXZ = function(mat, theta1, theta2, theta3) { - var c1 = Math.cos(theta1); - var s1 = Math.sin(theta1); - - var c2 = Math.cos(theta2); - var s2 = Math.sin(theta2); - - var c3 = Math.cos(theta3); - var s3 = Math.sin(theta3); - - mat[0] = c1 * c3 - c2 * s1 * s3; - mat[1] = c2 * c1 * s3 + c3 * s1; - mat[2] = s3 * s2; - mat[3] = 0; - - mat[4] = -c1 * s3 - c3 * c2 * s1; - mat[5] = c1 * c2 * c3 - s1 * s3; - mat[6] = c3 * s2; - mat[7] = 0; - - mat[8] = s2 * s1; - mat[9] = -c1 * s2; - mat[10] = c2; - mat[11] = 0; - - mat[12] = 0; - mat[13] = 0; - mat[14] = 0; - mat[15] = 1; - - return mat; -}; - - -/** - * Decomposes a rotation matrix into Euler angles using the ZXZ convention so - * that rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3), - * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi]. - * rotation_x(theta) means rotation around the X axis of theta radians. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {goog.vec.Vec3.AnyType} euler The ZXZ Euler angles in - * radians as [theta1, theta2, theta3]. - * @param {boolean=} opt_theta2IsNegative Whether theta2 is in [-pi, 0] instead - * of the default [0, pi]. - * @return {goog.vec.Vec4.AnyType} return euler so that operations can be - * chained together. - */ -goog.vec.Mat4.toEulerZXZ = function(mat, euler, opt_theta2IsNegative) { - // There is an ambiguity in the sign of sinTheta2 because of the sqrt. - var sinTheta2 = Math.sqrt(mat[2] * mat[2] + mat[6] * mat[6]); - - // By default we explicitely constrain theta2 to be in [0, pi], - // so sinTheta2 is always positive. We can change the behavior and specify - // theta2 to be negative in [-pi, 0] with opt_Theta2IsNegative. - var signTheta2 = opt_theta2IsNegative ? -1 : 1; - - if (sinTheta2 > goog.vec.EPSILON) { - euler[2] = Math.atan2(mat[2] * signTheta2, mat[6] * signTheta2); - euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]); - euler[0] = Math.atan2(mat[8] * signTheta2, -mat[9] * signTheta2); - } else { - // There is also an arbitrary choice for theta1 = 0 or theta2 = 0 here. - // We assume theta1 = 0 as some applications do not allow the camera to roll - // (i.e. have theta1 != 0). - euler[0] = 0; - euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]); - euler[2] = Math.atan2(mat[1], mat[0]); - } - - // Atan2 outputs angles in [-pi, pi] so we bring them back to [0, 2 * pi]. - euler[0] = (euler[0] + Math.PI * 2) % (Math.PI * 2); - euler[2] = (euler[2] + Math.PI * 2) % (Math.PI * 2); - // For theta2 we want the angle to be in [0, pi] or [-pi, 0] depending on - // signTheta2. - euler[1] = ((euler[1] * signTheta2 + Math.PI * 2) % (Math.PI * 2)) * - signTheta2; - - return euler; -}; - - -/** - * Translates the given matrix by x,y,z. Equvialent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeTranslate(goog.vec.Mat4.create(), x, y, z), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The translation along the x axis. - * @param {number} y The translation along the y axis. - * @param {number} z The translation along the z axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.translate = function(mat, x, y, z) { - return goog.vec.Mat4.setColumnValues( - mat, 3, - mat[0] * x + mat[4] * y + mat[8] * z + mat[12], - mat[1] * x + mat[5] * y + mat[9] * z + mat[13], - mat[2] * x + mat[6] * y + mat[10] * z + mat[14], - mat[3] * x + mat[7] * y + mat[11] * z + mat[15]); -}; - - -/** - * Scales the given matrix by x,y,z. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeScale(goog.vec.Mat4.create(), x, y, z), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The x scale factor. - * @param {number} y The y scale factor. - * @param {number} z The z scale factor. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.scale = function(mat, x, y, z) { - return goog.vec.Mat4.setFromValues( - mat, - mat[0] * x, mat[1] * x, mat[2] * x, mat[3] * x, - mat[4] * y, mat[5] * y, mat[6] * y, mat[7] * y, - mat[8] * z, mat[9] * z, mat[10] * z, mat[11] * z, - mat[12], mat[13], mat[14], mat[15]); -}; - - -/** - * Rotate the given matrix by angle about the x,y,z axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotate(goog.vec.Mat4.create(), angle, x, y, z), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @param {number} x The x component of the rotation axis. - * @param {number} y The y component of the rotation axis. - * @param {number} z The z component of the rotation axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.rotate = function(mat, angle, x, y, z) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; - - var cosAngle = Math.cos(angle); - var sinAngle = Math.sin(angle); - var diffCosAngle = 1 - cosAngle; - var r00 = x * x * diffCosAngle + cosAngle; - var r10 = x * y * diffCosAngle + z * sinAngle; - var r20 = x * z * diffCosAngle - y * sinAngle; - - var r01 = x * y * diffCosAngle - z * sinAngle; - var r11 = y * y * diffCosAngle + cosAngle; - var r21 = y * z * diffCosAngle + x * sinAngle; - - var r02 = x * z * diffCosAngle + y * sinAngle; - var r12 = y * z * diffCosAngle - x * sinAngle; - var r22 = z * z * diffCosAngle + cosAngle; - - return goog.vec.Mat4.setFromValues( - mat, - m00 * r00 + m01 * r10 + m02 * r20, - m10 * r00 + m11 * r10 + m12 * r20, - m20 * r00 + m21 * r10 + m22 * r20, - m30 * r00 + m31 * r10 + m32 * r20, - - m00 * r01 + m01 * r11 + m02 * r21, - m10 * r01 + m11 * r11 + m12 * r21, - m20 * r01 + m21 * r11 + m22 * r21, - m30 * r01 + m31 * r11 + m32 * r21, - - m00 * r02 + m01 * r12 + m02 * r22, - m10 * r02 + m11 * r12 + m12 * r22, - m20 * r02 + m21 * r12 + m22 * r22, - m30 * r02 + m31 * r12 + m32 * r22, - - m03, m13, m23, m33); -}; - - -/** - * Rotate the given matrix by angle about the x axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotateX(goog.vec.Mat4.create(), angle), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.rotateX = function(mat, angle) { - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - - var c = Math.cos(angle); - var s = Math.sin(angle); - - mat[4] = m01 * c + m02 * s; - mat[5] = m11 * c + m12 * s; - mat[6] = m21 * c + m22 * s; - mat[7] = m31 * c + m32 * s; - mat[8] = m01 * -s + m02 * c; - mat[9] = m11 * -s + m12 * c; - mat[10] = m21 * -s + m22 * c; - mat[11] = m31 * -s + m32 * c; - - return mat; -}; - - -/** - * Rotate the given matrix by angle about the y axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotateY(goog.vec.Mat4.create(), angle), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.rotateY = function(mat, angle) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - - var c = Math.cos(angle); - var s = Math.sin(angle); - - mat[0] = m00 * c + m02 * -s; - mat[1] = m10 * c + m12 * -s; - mat[2] = m20 * c + m22 * -s; - mat[3] = m30 * c + m32 * -s; - mat[8] = m00 * s + m02 * c; - mat[9] = m10 * s + m12 * c; - mat[10] = m20 * s + m22 * c; - mat[11] = m30 * s + m32 * c; - - return mat; -}; - - -/** - * Rotate the given matrix by angle about the z axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotateZ(goog.vec.Mat4.create(), angle), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.rotateZ = function(mat, angle) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - - var c = Math.cos(angle); - var s = Math.sin(angle); - - mat[0] = m00 * c + m01 * s; - mat[1] = m10 * c + m11 * s; - mat[2] = m20 * c + m21 * s; - mat[3] = m30 * c + m31 * s; - mat[4] = m00 * -s + m01 * c; - mat[5] = m10 * -s + m11 * c; - mat[6] = m20 * -s + m21 * c; - mat[7] = m30 * -s + m31 * c; - - return mat; -}; - - -/** - * Retrieves the translation component of the transformation matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The transformation matrix. - * @param {goog.vec.Vec3.AnyType} translation The vector for storing the - * result. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.getTranslation = function(mat, translation) { - translation[0] = mat[12]; - translation[1] = mat[13]; - translation[2] = mat[14]; - return translation; -}; - - -/** - * @type {!Array<!goog.vec.Vec3.Type>} - * @private - */ -goog.vec.Mat4.tmpVec3_ = [ - goog.vec.Vec3.createFloat64(), - goog.vec.Vec3.createFloat64() -]; - - -/** - * @type {!Array<!goog.vec.Vec4.Type>} - * @private - */ -goog.vec.Mat4.tmpVec4_ = [ - goog.vec.Vec4.createFloat64(), - goog.vec.Vec4.createFloat64(), - goog.vec.Vec4.createFloat64() -]; - - -/** - * @type {!Array<!goog.vec.Mat4.Type>} - * @private - */ -goog.vec.Mat4.tmpMat4_ = [ - goog.vec.Mat4.createFloat64() -]; - -goog.provide('ol.TransformFunction'); - - -/** - * A transform function accepts an array of input coordinate values, an optional - * output array, and an optional dimension (default should be 2). The function - * transforms the input coordinate values, populates the output array, and - * returns the output array. - * - * @typedef {function(Array.<number>, Array.<number>=, number=): Array.<number>} - * @api stable - */ -ol.TransformFunction; - -goog.provide('ol.Extent'); -goog.provide('ol.extent'); -goog.provide('ol.extent.Corner'); -goog.provide('ol.extent.Relationship'); - -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Coordinate'); -goog.require('ol.Size'); -goog.require('ol.TransformFunction'); - - -/** - * An array of numbers representing an extent: `[minx, miny, maxx, maxy]`. - * @typedef {Array.<number>} - * @api stable - */ -ol.Extent; - - -/** - * Extent corner. - * @enum {string} - */ -ol.extent.Corner = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_RIGHT: 'bottom-right', - TOP_LEFT: 'top-left', - TOP_RIGHT: 'top-right' -}; - - -/** - * Relationship to an extent. - * @enum {number} - */ -ol.extent.Relationship = { - UNKNOWN: 0, - INTERSECTING: 1, - ABOVE: 2, - RIGHT: 4, - BELOW: 8, - LEFT: 16 -}; - - -/** - * Build an extent that includes all given coordinates. - * - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @return {ol.Extent} Bounding extent. - * @api stable - */ -ol.extent.boundingExtent = function(coordinates) { - var extent = ol.extent.createEmpty(); - for (var i = 0, ii = coordinates.length; i < ii; ++i) { - ol.extent.extendCoordinate(extent, coordinates[i]); - } - return extent; -}; - - -/** - * @param {Array.<number>} xs Xs. - * @param {Array.<number>} ys Ys. - * @param {ol.Extent=} opt_extent Destination extent. - * @private - * @return {ol.Extent} Extent. - */ -ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) { - goog.asserts.assert(xs.length > 0, 'xs length should be larger than 0'); - goog.asserts.assert(ys.length > 0, 'ys length should be larger than 0'); - var minX = Math.min.apply(null, xs); - var minY = Math.min.apply(null, ys); - var maxX = Math.max.apply(null, xs); - var maxY = Math.max.apply(null, ys); - return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); -}; - - -/** - * Return extent increased by the provided value. - * @param {ol.Extent} extent Extent. - * @param {number} value The amount by which the extent should be buffered. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - * @api stable - */ -ol.extent.buffer = function(extent, value, opt_extent) { - if (opt_extent) { - opt_extent[0] = extent[0] - value; - opt_extent[1] = extent[1] - value; - opt_extent[2] = extent[2] + value; - opt_extent[3] = extent[3] + value; - return opt_extent; - } else { - return [ - extent[0] - value, - extent[1] - value, - extent[2] + value, - extent[3] + value - ]; - } -}; - - -/** - * Creates a clone of an extent. - * - * @param {ol.Extent} extent Extent to clone. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} The clone. - */ -ol.extent.clone = function(extent, opt_extent) { - if (opt_extent) { - opt_extent[0] = extent[0]; - opt_extent[1] = extent[1]; - opt_extent[2] = extent[2]; - opt_extent[3] = extent[3]; - return opt_extent; - } else { - return extent.slice(); - } -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} x X. - * @param {number} y Y. - * @return {number} Closest squared distance. - */ -ol.extent.closestSquaredDistanceXY = function(extent, x, y) { - var dx, dy; - if (x < extent[0]) { - dx = extent[0] - x; - } else if (extent[2] < x) { - dx = x - extent[2]; - } else { - dx = 0; - } - if (y < extent[1]) { - dy = extent[1] - y; - } else if (extent[3] < y) { - dy = y - extent[3]; - } else { - dy = 0; - } - return dx * dx + dy * dy; -}; - - -/** - * Check if the passed coordinate is contained or on the edge of the extent. - * - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {boolean} The coordinate is contained in the extent. - * @api stable - */ -ol.extent.containsCoordinate = function(extent, coordinate) { - return ol.extent.containsXY(extent, coordinate[0], coordinate[1]); -}; - - -/** - * Check if one extent contains another. - * - * An extent is deemed contained if it lies completely within the other extent, - * including if they share one or more edges. - * - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} The second extent is contained by or on the edge of the - * first. - * @api stable - */ -ol.extent.containsExtent = function(extent1, extent2) { - return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] && - extent1[1] <= extent2[1] && extent2[3] <= extent1[3]; -}; - - -/** - * Check if the passed coordinate is contained or on the edge of the extent. - * - * @param {ol.Extent} extent Extent. - * @param {number} x X coordinate. - * @param {number} y Y coordinate. - * @return {boolean} The x, y values are contained in the extent. - * @api stable - */ -ol.extent.containsXY = function(extent, x, y) { - return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3]; -}; - - -/** - * Get the relationship between a coordinate and extent. - * @param {ol.Extent} extent The extent. - * @param {ol.Coordinate} coordinate The coordinate. - * @return {number} The relationship (bitwise compare with - * ol.extent.Relationship). - */ -ol.extent.coordinateRelationship = function(extent, coordinate) { - var minX = extent[0]; - var minY = extent[1]; - var maxX = extent[2]; - var maxY = extent[3]; - var x = coordinate[0]; - var y = coordinate[1]; - var relationship = ol.extent.Relationship.UNKNOWN; - if (x < minX) { - relationship = relationship | ol.extent.Relationship.LEFT; - } else if (x > maxX) { - relationship = relationship | ol.extent.Relationship.RIGHT; - } - if (y < minY) { - relationship = relationship | ol.extent.Relationship.BELOW; - } else if (y > maxY) { - relationship = relationship | ol.extent.Relationship.ABOVE; - } - if (relationship === ol.extent.Relationship.UNKNOWN) { - relationship = ol.extent.Relationship.INTERSECTING; - } - return relationship; -}; - - -/** - * Create an empty extent. - * @return {ol.Extent} Empty extent. - * @api stable - */ -ol.extent.createEmpty = function() { - return [Infinity, Infinity, -Infinity, -Infinity]; -}; - - -/** - * Create a new extent or update the provided extent. - * @param {number} minX Minimum X. - * @param {number} minY Minimum Y. - * @param {number} maxX Maximum X. - * @param {number} maxY Maximum Y. - * @param {ol.Extent=} opt_extent Destination extent. - * @return {ol.Extent} Extent. - */ -ol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) { - if (opt_extent) { - opt_extent[0] = minX; - opt_extent[1] = minY; - opt_extent[2] = maxX; - opt_extent[3] = maxY; - return opt_extent; - } else { - return [minX, minY, maxX, maxY]; - } -}; - - -/** - * Create a new empty extent or make the provided one empty. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.createOrUpdateEmpty = function(opt_extent) { - return ol.extent.createOrUpdate( - Infinity, Infinity, -Infinity, -Infinity, opt_extent); -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) { - var x = coordinate[0]; - var y = coordinate[1]; - return ol.extent.createOrUpdate(x, y, x, y, opt_extent); -}; - - -/** - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) { - var extent = ol.extent.createOrUpdateEmpty(opt_extent); - return ol.extent.extendCoordinates(extent, coordinates); -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.createOrUpdateFromFlatCoordinates = - function(flatCoordinates, offset, end, stride, opt_extent) { - var extent = ol.extent.createOrUpdateEmpty(opt_extent); - return ol.extent.extendFlatCoordinates( - extent, flatCoordinates, offset, end, stride); -}; - - -/** - * @param {Array.<Array.<ol.Coordinate>>} rings Rings. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.createOrUpdateFromRings = function(rings, opt_extent) { - var extent = ol.extent.createOrUpdateEmpty(opt_extent); - return ol.extent.extendRings(extent, rings); -}; - - -/** - * Empty an extent in place. - * @param {ol.Extent} extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.empty = function(extent) { - extent[0] = extent[1] = Infinity; - extent[2] = extent[3] = -Infinity; - return extent; -}; - - -/** - * Determine if two extents are equivalent. - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} The two extents are equivalent. - * @api stable - */ -ol.extent.equals = function(extent1, extent2) { - return extent1[0] == extent2[0] && extent1[2] == extent2[2] && - extent1[1] == extent2[1] && extent1[3] == extent2[3]; -}; - - -/** - * Modify an extent to include another extent. - * @param {ol.Extent} extent1 The extent to be modified. - * @param {ol.Extent} extent2 The extent that will be included in the first. - * @return {ol.Extent} A reference to the first (extended) extent. - * @api stable - */ -ol.extent.extend = function(extent1, extent2) { - if (extent2[0] < extent1[0]) { - extent1[0] = extent2[0]; - } - if (extent2[2] > extent1[2]) { - extent1[2] = extent2[2]; - } - if (extent2[1] < extent1[1]) { - extent1[1] = extent2[1]; - } - if (extent2[3] > extent1[3]) { - extent1[3] = extent2[3]; - } - return extent1; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} coordinate Coordinate. - */ -ol.extent.extendCoordinate = function(extent, coordinate) { - if (coordinate[0] < extent[0]) { - extent[0] = coordinate[0]; - } - if (coordinate[0] > extent[2]) { - extent[2] = coordinate[0]; - } - if (coordinate[1] < extent[1]) { - extent[1] = coordinate[1]; - } - if (coordinate[1] > extent[3]) { - extent[3] = coordinate[1]; - } -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @return {ol.Extent} Extent. - */ -ol.extent.extendCoordinates = function(extent, coordinates) { - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - ol.extent.extendCoordinate(extent, coordinates[i]); - } - return extent; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {ol.Extent} Extent. - */ -ol.extent.extendFlatCoordinates = - function(extent, flatCoordinates, offset, end, stride) { - for (; offset < end; offset += stride) { - ol.extent.extendXY( - extent, flatCoordinates[offset], flatCoordinates[offset + 1]); - } - return extent; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {Array.<Array.<ol.Coordinate>>} rings Rings. - * @return {ol.Extent} Extent. - */ -ol.extent.extendRings = function(extent, rings) { - var i, ii; - for (i = 0, ii = rings.length; i < ii; ++i) { - ol.extent.extendCoordinates(extent, rings[i]); - } - return extent; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} x X. - * @param {number} y Y. - */ -ol.extent.extendXY = function(extent, x, y) { - extent[0] = Math.min(extent[0], x); - extent[1] = Math.min(extent[1], y); - extent[2] = Math.max(extent[2], x); - extent[3] = Math.max(extent[3], y); -}; - - -/** - * This function calls `callback` for each corner of the extent. If the - * callback returns a truthy value the function returns that value - * immediately. Otherwise the function returns `false`. - * @param {ol.Extent} extent Extent. - * @param {function(this:T, ol.Coordinate): S} callback Callback. - * @param {T=} opt_this Value to use as `this` when executing `callback`. - * @return {S|boolean} Value. - * @template S, T - */ -ol.extent.forEachCorner = function(extent, callback, opt_this) { - var val; - val = callback.call(opt_this, ol.extent.getBottomLeft(extent)); - if (val) { - return val; - } - val = callback.call(opt_this, ol.extent.getBottomRight(extent)); - if (val) { - return val; - } - val = callback.call(opt_this, ol.extent.getTopRight(extent)); - if (val) { - return val; - } - val = callback.call(opt_this, ol.extent.getTopLeft(extent)); - if (val) { - return val; - } - return false; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @return {number} Area. - */ -ol.extent.getArea = function(extent) { - var area = 0; - if (!ol.extent.isEmpty(extent)) { - area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent); - } - return area; -}; - - -/** - * Get the bottom left coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Bottom left coordinate. - * @api stable - */ -ol.extent.getBottomLeft = function(extent) { - return [extent[0], extent[1]]; -}; - - -/** - * Get the bottom right coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Bottom right coordinate. - * @api stable - */ -ol.extent.getBottomRight = function(extent) { - return [extent[2], extent[1]]; -}; - - -/** - * Get the center coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Center. - * @api stable - */ -ol.extent.getCenter = function(extent) { - return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2]; -}; - - -/** - * Get a corner coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @param {ol.extent.Corner} corner Corner. - * @return {ol.Coordinate} Corner coordinate. - */ -ol.extent.getCorner = function(extent, corner) { - var coordinate; - if (corner === ol.extent.Corner.BOTTOM_LEFT) { - coordinate = ol.extent.getBottomLeft(extent); - } else if (corner === ol.extent.Corner.BOTTOM_RIGHT) { - coordinate = ol.extent.getBottomRight(extent); - } else if (corner === ol.extent.Corner.TOP_LEFT) { - coordinate = ol.extent.getTopLeft(extent); - } else if (corner === ol.extent.Corner.TOP_RIGHT) { - coordinate = ol.extent.getTopRight(extent); - } else { - goog.asserts.fail('Invalid corner: %s', corner); - } - goog.asserts.assert(coordinate, 'coordinate should be defined'); - return coordinate; -}; - - -/** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {number} Enlarged area. - */ -ol.extent.getEnlargedArea = function(extent1, extent2) { - var minX = Math.min(extent1[0], extent2[0]); - var minY = Math.min(extent1[1], extent2[1]); - var maxX = Math.max(extent1[2], extent2[2]); - var maxY = Math.max(extent1[3], extent2[3]); - return (maxX - minX) * (maxY - minY); -}; - - -/** - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {ol.Extent=} opt_extent Destination extent. - * @return {ol.Extent} Extent. - */ -ol.extent.getForViewAndSize = - function(center, resolution, rotation, size, opt_extent) { - var dx = resolution * size[0] / 2; - var dy = resolution * size[1] / 2; - var cosRotation = Math.cos(rotation); - var sinRotation = Math.sin(rotation); - /** @type {Array.<number>} */ - var xs = [-dx, -dx, dx, dx]; - /** @type {Array.<number>} */ - var ys = [-dy, dy, -dy, dy]; - var i, x, y; - for (i = 0; i < 4; ++i) { - x = xs[i]; - y = ys[i]; - xs[i] = center[0] + x * cosRotation - y * sinRotation; - ys[i] = center[1] + x * sinRotation + y * cosRotation; - } - return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); -}; - - -/** - * Get the height of an extent. - * @param {ol.Extent} extent Extent. - * @return {number} Height. - * @api stable - */ -ol.extent.getHeight = function(extent) { - return extent[3] - extent[1]; -}; - - -/** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {number} Intersection area. - */ -ol.extent.getIntersectionArea = function(extent1, extent2) { - var intersection = ol.extent.getIntersection(extent1, extent2); - return ol.extent.getArea(intersection); -}; - - -/** - * Get the intersection of two extents. - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @param {ol.Extent=} opt_extent Optional extent to populate with intersection. - * @return {ol.Extent} Intersecting extent. - * @api stable - */ -ol.extent.getIntersection = function(extent1, extent2, opt_extent) { - var intersection = opt_extent ? opt_extent : ol.extent.createEmpty(); - if (ol.extent.intersects(extent1, extent2)) { - if (extent1[0] > extent2[0]) { - intersection[0] = extent1[0]; - } else { - intersection[0] = extent2[0]; - } - if (extent1[1] > extent2[1]) { - intersection[1] = extent1[1]; - } else { - intersection[1] = extent2[1]; - } - if (extent1[2] < extent2[2]) { - intersection[2] = extent1[2]; - } else { - intersection[2] = extent2[2]; - } - if (extent1[3] < extent2[3]) { - intersection[3] = extent1[3]; - } else { - intersection[3] = extent2[3]; - } - } - return intersection; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @return {number} Margin. - */ -ol.extent.getMargin = function(extent) { - return ol.extent.getWidth(extent) + ol.extent.getHeight(extent); -}; - - -/** - * Get the size (width, height) of an extent. - * @param {ol.Extent} extent The extent. - * @return {ol.Size} The extent size. - * @api stable - */ -ol.extent.getSize = function(extent) { - return [extent[2] - extent[0], extent[3] - extent[1]]; -}; - - -/** - * Get the top left coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Top left coordinate. - * @api stable - */ -ol.extent.getTopLeft = function(extent) { - return [extent[0], extent[3]]; -}; - - -/** - * Get the top right coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Top right coordinate. - * @api stable - */ -ol.extent.getTopRight = function(extent) { - return [extent[2], extent[3]]; -}; - - -/** - * Get the width of an extent. - * @param {ol.Extent} extent Extent. - * @return {number} Width. - * @api stable - */ -ol.extent.getWidth = function(extent) { - return extent[2] - extent[0]; -}; - - -/** - * Determine if one extent intersects another. - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent. - * @return {boolean} The two extents intersect. - * @api stable - */ -ol.extent.intersects = function(extent1, extent2) { - return extent1[0] <= extent2[2] && - extent1[2] >= extent2[0] && - extent1[1] <= extent2[3] && - extent1[3] >= extent2[1]; -}; - - -/** - * Determine if an extent is empty. - * @param {ol.Extent} extent Extent. - * @return {boolean} Is empty. - * @api stable - */ -ol.extent.isEmpty = function(extent) { - return extent[2] < extent[0] || extent[3] < extent[1]; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @return {boolean} Is infinite. - */ -ol.extent.isInfinite = function(extent) { - return extent[0] == -Infinity || extent[1] == -Infinity || - extent[2] == Infinity || extent[3] == Infinity; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate} Coordinate. - */ -ol.extent.normalize = function(extent, coordinate) { - return [ - (coordinate[0] - extent[0]) / (extent[2] - extent[0]), - (coordinate[1] - extent[1]) / (extent[3] - extent[1]) - ]; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.returnOrUpdate = function(extent, opt_extent) { - if (opt_extent) { - opt_extent[0] = extent[0]; - opt_extent[1] = extent[1]; - opt_extent[2] = extent[2]; - opt_extent[3] = extent[3]; - return opt_extent; - } else { - return extent; - } -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} value Value. - */ -ol.extent.scaleFromCenter = function(extent, value) { - var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1); - var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1); - extent[0] -= deltaX; - extent[2] += deltaX; - extent[1] -= deltaY; - extent[3] += deltaY; -}; - - -/** - * Determine if the segment between two coordinates intersects (crosses, - * touches, or is contained by) the provided extent. - * @param {ol.Extent} extent The extent. - * @param {ol.Coordinate} start Segment start coordinate. - * @param {ol.Coordinate} end Segment end coordinate. - * @return {boolean} The segment intersects the extent. - */ -ol.extent.intersectsSegment = function(extent, start, end) { - var intersects = false; - var startRel = ol.extent.coordinateRelationship(extent, start); - var endRel = ol.extent.coordinateRelationship(extent, end); - if (startRel === ol.extent.Relationship.INTERSECTING || - endRel === ol.extent.Relationship.INTERSECTING) { - intersects = true; - } else { - var minX = extent[0]; - var minY = extent[1]; - var maxX = extent[2]; - var maxY = extent[3]; - var startX = start[0]; - var startY = start[1]; - var endX = end[0]; - var endY = end[1]; - var slope = (endY - startY) / (endX - startX); - var x, y; - if (!!(endRel & ol.extent.Relationship.ABOVE) && - !(startRel & ol.extent.Relationship.ABOVE)) { - // potentially intersects top - x = endX - ((endY - maxY) / slope); - intersects = x >= minX && x <= maxX; - } - if (!intersects && !!(endRel & ol.extent.Relationship.RIGHT) && - !(startRel & ol.extent.Relationship.RIGHT)) { - // potentially intersects right - y = endY - ((endX - maxX) * slope); - intersects = y >= minY && y <= maxY; - } - if (!intersects && !!(endRel & ol.extent.Relationship.BELOW) && - !(startRel & ol.extent.Relationship.BELOW)) { - // potentially intersects bottom - x = endX - ((endY - minY) / slope); - intersects = x >= minX && x <= maxX; - } - if (!intersects && !!(endRel & ol.extent.Relationship.LEFT) && - !(startRel & ol.extent.Relationship.LEFT)) { - // potentially intersects left - y = endY - ((endX - minX) * slope); - intersects = y >= minY && y <= maxY; - } - - } - return intersects; -}; - - -/** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} Touches. - */ -ol.extent.touches = function(extent1, extent2) { - var intersects = ol.extent.intersects(extent1, extent2); - return intersects && - (extent1[0] == extent2[2] || extent1[2] == extent2[0] || - extent1[1] == extent2[3] || extent1[3] == extent2[1]); -}; - - -/** - * Apply a transform function to the extent. - * @param {ol.Extent} extent Extent. - * @param {ol.TransformFunction} transformFn Transform function. Called with - * [minX, minY, maxX, maxY] extent coordinates. - * @param {ol.Extent=} opt_extent Destination extent. - * @return {ol.Extent} Extent. - * @api stable - */ -ol.extent.applyTransform = function(extent, transformFn, opt_extent) { - var coordinates = [ - extent[0], extent[1], - extent[0], extent[3], - extent[2], extent[1], - extent[2], extent[3] - ]; - transformFn(coordinates, coordinates, 2); - var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]]; - var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]]; - return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); -}; - - -/** - * Apply a 2d transform to an extent. - * @param {ol.Extent} extent Input extent. - * @param {goog.vec.Mat4.Number} transform The transform matrix. - * @param {ol.Extent=} opt_extent Optional extent for return values. - * @return {ol.Extent} The transformed extent. - */ -ol.extent.transform2D = function(extent, transform, opt_extent) { - var dest = opt_extent ? opt_extent : []; - var m00 = goog.vec.Mat4.getElement(transform, 0, 0); - var m10 = goog.vec.Mat4.getElement(transform, 1, 0); - var m01 = goog.vec.Mat4.getElement(transform, 0, 1); - var m11 = goog.vec.Mat4.getElement(transform, 1, 1); - var m03 = goog.vec.Mat4.getElement(transform, 0, 3); - var m13 = goog.vec.Mat4.getElement(transform, 1, 3); - var xi = [0, 2, 0, 2]; - var yi = [1, 1, 3, 3]; - var xs = []; - var ys = []; - var i, x, y; - for (i = 0; i < 4; ++i) { - x = extent[xi[i]]; - y = extent[yi[i]]; - xs[i] = m00 * x + m01 * y + m03; - ys[i] = m10 * x + m11 * y + m13; - } - dest[0] = Math.min.apply(null, xs); - dest[1] = Math.min.apply(null, ys); - dest[2] = Math.max.apply(null, xs); - dest[3] = Math.max.apply(null, ys); - return dest; -}; - -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for creating functions. Loosely inspired by the - * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8. - * - * @author nicksantos@google.com (Nick Santos) - */ - - -goog.provide('goog.functions'); - - -/** - * Creates a function that always returns the same value. - * @param {T} retValue The value to return. - * @return {function():T} The new function. - * @template T - */ -goog.functions.constant = function(retValue) { - return function() { - return retValue; - }; -}; - - -/** - * Always returns false. - * @type {function(...): boolean} - */ -goog.functions.FALSE = goog.functions.constant(false); - - -/** - * Always returns true. - * @type {function(...): boolean} - */ -goog.functions.TRUE = goog.functions.constant(true); - - -/** - * Always returns NULL. - * @type {function(...): null} - */ -goog.functions.NULL = goog.functions.constant(null); - - -/** - * A simple function that returns the first argument of whatever is passed - * into it. - * @param {T=} opt_returnValue The single value that will be returned. - * @param {...*} var_args Optional trailing arguments. These are ignored. - * @return {T} The first argument passed in, or undefined if nothing was passed. - * @template T - */ -goog.functions.identity = function(opt_returnValue, var_args) { - return opt_returnValue; -}; - - -/** - * Creates a function that always throws an error with the given message. - * @param {string} message The error message. - * @return {!Function} The error-throwing function. - */ -goog.functions.error = function(message) { - return function() { - throw Error(message); - }; -}; - - -/** - * Creates a function that throws the given object. - * @param {*} err An object to be thrown. - * @return {!Function} The error-throwing function. - */ -goog.functions.fail = function(err) { - return function() { - throw err; - } -}; - - -/** - * Given a function, create a function that keeps opt_numArgs arguments and - * silently discards all additional arguments. - * @param {Function} f The original function. - * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0. - * @return {!Function} A version of f that only keeps the first opt_numArgs - * arguments. - */ -goog.functions.lock = function(f, opt_numArgs) { - opt_numArgs = opt_numArgs || 0; - return function() { - return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs)); - }; -}; - - -/** - * Creates a function that returns its nth argument. - * @param {number} n The position of the return argument. - * @return {!Function} A new function. - */ -goog.functions.nth = function(n) { - return function() { - return arguments[n]; - }; -}; - - -/** - * Given a function, create a new function that swallows its return value - * and replaces it with a new one. - * @param {Function} f A function. - * @param {T} retValue A new return value. - * @return {function(...?):T} A new function. - * @template T - */ -goog.functions.withReturnValue = function(f, retValue) { - return goog.functions.sequence(f, goog.functions.constant(retValue)); -}; - - -/** - * Creates a function that returns whether its arguement equals the given value. - * - * Example: - * var key = goog.object.findKey(obj, goog.functions.equalTo('needle')); - * - * @param {*} value The value to compare to. - * @param {boolean=} opt_useLooseComparison Whether to use a loose (==) - * comparison rather than a strict (===) one. Defaults to false. - * @return {function(*):boolean} The new function. - */ -goog.functions.equalTo = function(value, opt_useLooseComparison) { - return function(other) { - return opt_useLooseComparison ? (value == other) : (value === other); - }; -}; - - -/** - * Creates the composition of the functions passed in. - * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)). - * @param {function(...?):T} fn The final function. - * @param {...Function} var_args A list of functions. - * @return {function(...?):T} The composition of all inputs. - * @template T - */ -goog.functions.compose = function(fn, var_args) { - var functions = arguments; - var length = functions.length; - return function() { - var result; - if (length) { - result = functions[length - 1].apply(this, arguments); - } - - for (var i = length - 2; i >= 0; i--) { - result = functions[i].call(this, result); - } - return result; - }; -}; - - -/** - * Creates a function that calls the functions passed in in sequence, and - * returns the value of the last function. For example, - * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x). - * @param {...Function} var_args A list of functions. - * @return {!Function} A function that calls all inputs in sequence. - */ -goog.functions.sequence = function(var_args) { - var functions = arguments; - var length = functions.length; - return function() { - var result; - for (var i = 0; i < length; i++) { - result = functions[i].apply(this, arguments); - } - return result; - }; -}; - - -/** - * Creates a function that returns true if each of its components evaluates - * to true. The components are evaluated in order, and the evaluation will be - * short-circuited as soon as a function returns false. - * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x). - * @param {...Function} var_args A list of functions. - * @return {function(...?):boolean} A function that ANDs its component - * functions. - */ -goog.functions.and = function(var_args) { - var functions = arguments; - var length = functions.length; - return function() { - for (var i = 0; i < length; i++) { - if (!functions[i].apply(this, arguments)) { - return false; - } - } - return true; - }; -}; - - -/** - * Creates a function that returns true if any of its components evaluates - * to true. The components are evaluated in order, and the evaluation will be - * short-circuited as soon as a function returns true. - * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x). - * @param {...Function} var_args A list of functions. - * @return {function(...?):boolean} A function that ORs its component - * functions. - */ -goog.functions.or = function(var_args) { - var functions = arguments; - var length = functions.length; - return function() { - for (var i = 0; i < length; i++) { - if (functions[i].apply(this, arguments)) { - return true; - } - } - return false; - }; -}; - - -/** - * Creates a function that returns the Boolean opposite of a provided function. - * For example, (goog.functions.not(f))(x) is equivalent to !f(x). - * @param {!Function} f The original function. - * @return {function(...?):boolean} A function that delegates to f and returns - * opposite. - */ -goog.functions.not = function(f) { - return function() { - return !f.apply(this, arguments); - }; -}; - - -/** - * Generic factory function to construct an object given the constructor - * and the arguments. Intended to be bound to create object factories. - * - * Example: - * - * var factory = goog.partial(goog.functions.create, Class); - * - * @param {function(new:T, ...)} constructor The constructor for the Object. - * @param {...*} var_args The arguments to be passed to the constructor. - * @return {T} A new instance of the class given in {@code constructor}. - * @template T - */ -goog.functions.create = function(constructor, var_args) { - /** - * @constructor - * @final - */ - var temp = function() {}; - temp.prototype = constructor.prototype; - - // obj will have constructor's prototype in its chain and - // 'obj instanceof constructor' will be true. - var obj = new temp(); - - // obj is initialized by constructor. - // arguments is only array-like so lacks shift(), but can be used with - // the Array prototype function. - constructor.apply(obj, Array.prototype.slice.call(arguments, 1)); - return obj; -}; - - -/** - * @define {boolean} Whether the return value cache should be used. - * This should only be used to disable caches when testing. - */ -goog.define('goog.functions.CACHE_RETURN_VALUE', true); - - -/** - * Gives a wrapper function that caches the return value of a parameterless - * function when first called. - * - * When called for the first time, the given function is called and its - * return value is cached (thus this is only appropriate for idempotent - * functions). Subsequent calls will return the cached return value. This - * allows the evaluation of expensive functions to be delayed until first used. - * - * To cache the return values of functions with parameters, see goog.memoize. - * - * @param {!function():T} fn A function to lazily evaluate. - * @return {!function():T} A wrapped version the function. - * @template T - */ -goog.functions.cacheReturnValue = function(fn) { - var called = false; - var value; - - return function() { - if (!goog.functions.CACHE_RETURN_VALUE) { - return fn(); - } - - if (!called) { - value = fn(); - called = true; - } - - return value; - } -}; - - -/** - * Wraps a function to allow it to be called, at most, once. All - * additional calls are no-ops. - * - * This is particularly useful for initialization functions - * that should be called, at most, once. - * - * @param {function():*} f Function to call. - * @return {function():undefined} Wrapped function. - */ -goog.functions.once = function(f) { - // Keep a reference to the function that we null out when we're done with - // it -- that way, the function can be GC'd when we're done with it. - var inner = f; - return function() { - if (inner) { - var tmp = inner; - inner = null; - tmp(); - } - }; -}; - - -/** - * Wraps a function to allow it to be called, at most, once for each sequence of - * calls fired repeatedly so long as they are fired less than a specified - * interval apart (in milliseconds). Whether it receives one signal or multiple, - * it will always wait until a full interval has elapsed since the last signal - * before performing the action. - * - * This is particularly useful for bulking up repeated user actions (e.g. only - * refreshing a view once a user finishes typing rather than updating with every - * keystroke). For more stateful debouncing with support for pausing, resuming, - * and canceling debounced actions, use {@code goog.async.Debouncer}. - * - * @param {function(this:SCOPE):*} f Function to call. - * @param {number} interval Interval over which to debounce. The function will - * only be called after the full interval has elapsed since the last call. - * @param {SCOPE=} opt_scope Object in whose scope to call the function. - * @return {function():undefined} Wrapped function. - * @template SCOPE - */ -goog.functions.debounce = function(f, interval, opt_scope) { - if (opt_scope) { - f = goog.bind(f, opt_scope); - } - var timeout = null; - return function() { - goog.global.clearTimeout(timeout); - timeout = goog.global.setTimeout(f, interval); - }; -}; - - -/** - * Wraps a function to allow it to be called, at most, once per interval - * (specified in milliseconds). If it is called multiple times while it is - * waiting, it will only perform the action once at the end of the interval. - * - * This is particularly useful for limiting repeated user requests (e.g. - * preventing a user from spamming a server with frequent view refreshes). For - * more stateful throttling with support for pausing, resuming, and canceling - * throttled actions, use {@code goog.async.Throttle}. - * - * @param {function(this:SCOPE):*} f Function to call. - * @param {number} interval Interval over which to throttle. The function can - * only be called once per interval. - * @param {SCOPE=} opt_scope Object in whose scope to call the function. - * @return {function():undefined} Wrapped function. - * @template SCOPE - */ -goog.functions.throttle = function(f, interval, opt_scope) { - if (opt_scope) { - f = goog.bind(f, opt_scope); - } - var timeout = null; - var shouldFire = false; - var fire = function() { - timeout = goog.global.setTimeout(handleTimeout, interval); - f(); - }; - var handleTimeout = function() { - timeout = null; - if (shouldFire) { - shouldFire = false; - fire(); - } - }; - - return function() { - if (!timeout) { - fire(); - } else { - shouldFire = true; - } - }; -}; - -/** - * @license - * Latitude/longitude spherical geodesy formulae taken from - * http://www.movable-type.co.uk/scripts/latlong.html - * Licensed under CC-BY-3.0. - */ - -goog.provide('ol.Sphere'); - -goog.require('ol.math'); - - - -/** - * @classdesc - * Class to create objects that can be used with {@link - * ol.geom.Polygon.circular}. - * - * For example to create a sphere whose radius is equal to the semi-major - * axis of the WGS84 ellipsoid: - * - * ```js - * var wgs84Sphere= new ol.Sphere(6378137); - * ``` - * - * @constructor - * @param {number} radius Radius. - * @api - */ -ol.Sphere = function(radius) { - - /** - * @type {number} - */ - this.radius = radius; - -}; - - -/** - * Returns the geodesic area for a list of coordinates. - * - * [Reference](http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409) - * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for - * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion - * Laboratory, Pasadena, CA, June 2007 - * - * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear - * ring. If the ring is oriented clockwise, the area will be positive, - * otherwise it will be negative. - * @return {number} Area. - * @api - */ -ol.Sphere.prototype.geodesicArea = function(coordinates) { - var area = 0, len = coordinates.length; - var x1 = coordinates[len - 1][0]; - var y1 = coordinates[len - 1][1]; - for (var i = 0; i < len; i++) { - var x2 = coordinates[i][0], y2 = coordinates[i][1]; - area += ol.math.toRadians(x2 - x1) * - (2 + Math.sin(ol.math.toRadians(y1)) + - Math.sin(ol.math.toRadians(y2))); - x1 = x2; - y1 = y2; - } - return area * this.radius * this.radius / 2.0; -}; - - -/** - * Returns the distance from c1 to c2 using the haversine formula. - * - * @param {ol.Coordinate} c1 Coordinate 1. - * @param {ol.Coordinate} c2 Coordinate 2. - * @return {number} Haversine distance. - * @api - */ -ol.Sphere.prototype.haversineDistance = function(c1, c2) { - var lat1 = ol.math.toRadians(c1[1]); - var lat2 = ol.math.toRadians(c2[1]); - var deltaLatBy2 = (lat2 - lat1) / 2; - var deltaLonBy2 = ol.math.toRadians(c2[0] - c1[0]) / 2; - var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + - Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * - Math.cos(lat1) * Math.cos(lat2); - return 2 * this.radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); -}; - - -/** - * Returns the coordinate at the given distance and bearing from `c1`. - * - * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees). - * @param {number} distance The great-circle distance between the origin - * point and the target point. - * @param {number} bearing The bearing (in radians). - * @return {ol.Coordinate} The target point. - */ -ol.Sphere.prototype.offset = function(c1, distance, bearing) { - var lat1 = ol.math.toRadians(c1[1]); - var lon1 = ol.math.toRadians(c1[0]); - var dByR = distance / this.radius; - var lat = Math.asin( - Math.sin(lat1) * Math.cos(dByR) + - Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing)); - var lon = lon1 + Math.atan2( - Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), - Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat)); - return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)]; -}; - -goog.provide('ol.sphere.NORMAL'); - -goog.require('ol.Sphere'); - - -/** - * The normal sphere. - * @const - * @type {ol.Sphere} - */ -ol.sphere.NORMAL = new ol.Sphere(6370997); - -goog.provide('ol.proj'); -goog.provide('ol.proj.METERS_PER_UNIT'); -goog.provide('ol.proj.Projection'); -goog.provide('ol.proj.ProjectionLike'); -goog.provide('ol.proj.Units'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Extent'); -goog.require('ol.TransformFunction'); -goog.require('ol.extent'); -goog.require('ol.sphere.NORMAL'); - - -/** - * A projection as {@link ol.proj.Projection}, SRS identifier string or - * undefined. - * @typedef {ol.proj.Projection|string|undefined} ol.proj.ProjectionLike - * @api stable - */ -ol.proj.ProjectionLike; - - -/** - * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or - * `'us-ft'`. - * @enum {string} - * @api stable - */ -ol.proj.Units = { - DEGREES: 'degrees', - FEET: 'ft', - METERS: 'm', - PIXELS: 'pixels', - TILE_PIXELS: 'tile-pixels', - USFEET: 'us-ft' -}; - - -/** - * Meters per unit lookup table. - * @const - * @type {Object.<ol.proj.Units, number>} - * @api stable - */ -ol.proj.METERS_PER_UNIT = {}; -ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] = - 2 * Math.PI * ol.sphere.NORMAL.radius / 360; -ol.proj.METERS_PER_UNIT[ol.proj.Units.FEET] = 0.3048; -ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1; -ol.proj.METERS_PER_UNIT[ol.proj.Units.USFEET] = 1200 / 3937; - - - -/** - * @classdesc - * Projection definition class. One of these is created for each projection - * supported in the application and stored in the {@link ol.proj} namespace. - * You can use these in applications, but this is not required, as API params - * and options use {@link ol.proj.ProjectionLike} which means the simple string - * code will suffice. - * - * You can use {@link ol.proj.get} to retrieve the object for a particular - * projection. - * - * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together - * with the following aliases: - * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, - * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84, - * http://www.opengis.net/gml/srs/epsg.xml#4326, - * urn:x-ogc:def:crs:EPSG:4326 - * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913, - * urn:ogc:def:crs:EPSG:6.18:3:3857, - * http://www.opengis.net/gml/srs/epsg.xml#3857 - * - * If you use proj4js, aliases can be added using `proj4.defs()`; see - * [documentation](https://github.com/proj4js/proj4js). - * - * @constructor - * @param {olx.ProjectionOptions} options Projection options. - * @struct - * @api stable - */ -ol.proj.Projection = function(options) { - - /** - * @private - * @type {string} - */ - this.code_ = options.code; - - /** - * @private - * @type {ol.proj.Units} - */ - this.units_ = /** @type {ol.proj.Units} */ (options.units); - - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = options.extent !== undefined ? options.extent : null; - - /** - * @private - * @type {ol.Extent} - */ - this.worldExtent_ = options.worldExtent !== undefined ? - options.worldExtent : null; - - /** - * @private - * @type {string} - */ - this.axisOrientation_ = options.axisOrientation !== undefined ? - options.axisOrientation : 'enu'; - - /** - * @private - * @type {boolean} - */ - this.global_ = options.global !== undefined ? options.global : false; - - - /** - * @private - * @type {boolean} - */ - this.canWrapX_ = !!(this.global_ && this.extent_); - - /** - * @private - * @type {function(number, ol.Coordinate):number} - */ - this.getPointResolutionFunc_ = options.getPointResolution !== undefined ? - options.getPointResolution : this.getPointResolution_; - - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.defaultTileGrid_ = null; - - var projections = ol.proj.projections_; - var code = options.code; - goog.asserts.assert(code !== undefined, - 'Option "code" is required for constructing instance'); - if (ol.ENABLE_PROJ4JS && typeof proj4 == 'function' && - projections[code] === undefined) { - var def = proj4.defs(code); - if (def !== undefined) { - if (def.axis !== undefined && options.axisOrientation === undefined) { - this.axisOrientation_ = def.axis; - } - if (options.units === undefined) { - var units = def.units; - if (def.to_meter !== undefined) { - if (units === undefined || - ol.proj.METERS_PER_UNIT[units] === undefined) { - units = def.to_meter.toString(); - ol.proj.METERS_PER_UNIT[units] = def.to_meter; - } - } - this.units_ = units; - } - var currentCode, currentDef, currentProj, proj4Transform; - for (currentCode in projections) { - currentDef = proj4.defs(currentCode); - if (currentDef !== undefined) { - currentProj = ol.proj.get(currentCode); - if (currentDef === def) { - ol.proj.addEquivalentProjections([currentProj, this]); - } else { - proj4Transform = proj4(currentCode, code); - ol.proj.addCoordinateTransforms(currentProj, this, - proj4Transform.forward, proj4Transform.inverse); - } - } - } - } - } - -}; - - -/** - * @return {boolean} The projection is suitable for wrapping the x-axis - */ -ol.proj.Projection.prototype.canWrapX = function() { - return this.canWrapX_; -}; - - -/** - * Get the code for this projection, e.g. 'EPSG:4326'. - * @return {string} Code. - * @api stable - */ -ol.proj.Projection.prototype.getCode = function() { - return this.code_; -}; - - -/** - * Get the validity extent for this projection. - * @return {ol.Extent} Extent. - * @api stable - */ -ol.proj.Projection.prototype.getExtent = function() { - return this.extent_; -}; - - -/** - * Get the units of this projection. - * @return {ol.proj.Units} Units. - * @api stable - */ -ol.proj.Projection.prototype.getUnits = function() { - return this.units_; -}; - - -/** - * Get the amount of meters per unit of this projection. If the projection is - * not configured with a units identifier, the return is `undefined`. - * @return {number|undefined} Meters. - * @api stable - */ -ol.proj.Projection.prototype.getMetersPerUnit = function() { - return ol.proj.METERS_PER_UNIT[this.units_]; -}; - - -/** - * Get the world extent for this projection. - * @return {ol.Extent} Extent. - * @api - */ -ol.proj.Projection.prototype.getWorldExtent = function() { - return this.worldExtent_; -}; - - -/** - * Get the axis orientation of this projection. - * Example values are: - * enu - the default easting, northing, elevation. - * neu - northing, easting, up - useful for "lat/long" geographic coordinates, - * or south orientated transverse mercator. - * wnu - westing, northing, up - some planetary coordinate systems have - * "west positive" coordinate systems - * @return {string} Axis orientation. - */ -ol.proj.Projection.prototype.getAxisOrientation = function() { - return this.axisOrientation_; -}; - - -/** - * Is this projection a global projection which spans the whole world? - * @return {boolean} Whether the projection is global. - * @api stable - */ -ol.proj.Projection.prototype.isGlobal = function() { - return this.global_; -}; - - -/** -* Set if the projection is a global projection which spans the whole world -* @param {boolean} global Whether the projection is global. -* @api stable -*/ -ol.proj.Projection.prototype.setGlobal = function(global) { - this.global_ = global; - this.canWrapX_ = !!(global && this.extent_); -}; - - -/** - * @return {ol.tilegrid.TileGrid} The default tile grid. - */ -ol.proj.Projection.prototype.getDefaultTileGrid = function() { - return this.defaultTileGrid_; -}; - - -/** - * @param {ol.tilegrid.TileGrid} tileGrid The default tile grid. - */ -ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) { - this.defaultTileGrid_ = tileGrid; -}; - - -/** - * Set the validity extent for this projection. - * @param {ol.Extent} extent Extent. - * @api stable - */ -ol.proj.Projection.prototype.setExtent = function(extent) { - this.extent_ = extent; - this.canWrapX_ = !!(this.global_ && extent); -}; - - -/** - * Set the world extent for this projection. - * @param {ol.Extent} worldExtent World extent - * [minlon, minlat, maxlon, maxlat]. - * @api - */ -ol.proj.Projection.prototype.setWorldExtent = function(worldExtent) { - this.worldExtent_ = worldExtent; -}; - - -/** -* Set the getPointResolution function for this projection. -* @param {function(number, ol.Coordinate):number} func Function -* @api -*/ -ol.proj.Projection.prototype.setGetPointResolution = function(func) { - this.getPointResolutionFunc_ = func; -}; - - -/** -* Default version. -* Get the resolution of the point in degrees or distance units. -* For projections with degrees as the unit this will simply return the -* provided resolution. For other projections the point resolution is -* estimated by transforming the 'point' pixel to EPSG:4326, -* measuring its width and height on the normal sphere, -* and taking the average of the width and height. -* @param {number} resolution Nominal resolution in projection units. -* @param {ol.Coordinate} point Point to find adjusted resolution at. -* @return {number} Point resolution at point in projection units. -* @private -*/ -ol.proj.Projection.prototype.getPointResolution_ = function(resolution, point) { - var units = this.getUnits(); - if (units == ol.proj.Units.DEGREES) { - return resolution; - } else { - // Estimate point resolution by transforming the center pixel to EPSG:4326, - // measuring its width and height on the normal sphere, and taking the - // average of the width and height. - var toEPSG4326 = ol.proj.getTransformFromProjections( - this, ol.proj.get('EPSG:4326')); - var vertices = [ - point[0] - resolution / 2, point[1], - point[0] + resolution / 2, point[1], - point[0], point[1] - resolution / 2, - point[0], point[1] + resolution / 2 - ]; - vertices = toEPSG4326(vertices, vertices, 2); - var width = ol.sphere.NORMAL.haversineDistance( - vertices.slice(0, 2), vertices.slice(2, 4)); - var height = ol.sphere.NORMAL.haversineDistance( - vertices.slice(4, 6), vertices.slice(6, 8)); - var pointResolution = (width + height) / 2; - var metersPerUnit = this.getMetersPerUnit(); - if (metersPerUnit !== undefined) { - pointResolution /= metersPerUnit; - } - return pointResolution; - } -}; - - -/** - * Get the resolution of the point in degrees or distance units. - * For projections with degrees as the unit this will simply return the - * provided resolution. The default for other projections is to estimate - * the point resolution by transforming the 'point' pixel to EPSG:4326, - * measuring its width and height on the normal sphere, - * and taking the average of the width and height. - * An alternative implementation may be given when constructing a - * projection. For many local projections, - * such a custom function will return the resolution unchanged. - * @param {number} resolution Resolution in projection units. - * @param {ol.Coordinate} point Point. - * @return {number} Point resolution in projection units. - * @api - */ -ol.proj.Projection.prototype.getPointResolution = function(resolution, point) { - return this.getPointResolutionFunc_(resolution, point); -}; - - -/** - * @private - * @type {Object.<string, ol.proj.Projection>} - */ -ol.proj.projections_ = {}; - - -/** - * @private - * @type {Object.<string, Object.<string, ol.TransformFunction>>} - */ -ol.proj.transforms_ = {}; - - -/** - * Registers transformation functions that don't alter coordinates. Those allow - * to transform between projections with equal meaning. - * - * @param {Array.<ol.proj.Projection>} projections Projections. - * @api - */ -ol.proj.addEquivalentProjections = function(projections) { - ol.proj.addProjections(projections); - projections.forEach(function(source) { - projections.forEach(function(destination) { - if (source !== destination) { - ol.proj.addTransform(source, destination, ol.proj.cloneTransform); - } - }); - }); -}; - - -/** - * Registers transformation functions to convert coordinates in any projection - * in projection1 to any projection in projection2. - * - * @param {Array.<ol.proj.Projection>} projections1 Projections with equal - * meaning. - * @param {Array.<ol.proj.Projection>} projections2 Projections with equal - * meaning. - * @param {ol.TransformFunction} forwardTransform Transformation from any - * projection in projection1 to any projection in projection2. - * @param {ol.TransformFunction} inverseTransform Transform from any projection - * in projection2 to any projection in projection1.. - */ -ol.proj.addEquivalentTransforms = - function(projections1, projections2, forwardTransform, inverseTransform) { - projections1.forEach(function(projection1) { - projections2.forEach(function(projection2) { - ol.proj.addTransform(projection1, projection2, forwardTransform); - ol.proj.addTransform(projection2, projection1, inverseTransform); - }); - }); -}; - - -/** - * Add a Projection object to the list of supported projections that can be - * looked up by their code. - * - * @param {ol.proj.Projection} projection Projection instance. - * @api stable - */ -ol.proj.addProjection = function(projection) { - ol.proj.projections_[projection.getCode()] = projection; - ol.proj.addTransform(projection, projection, ol.proj.cloneTransform); -}; - - -/** - * @param {Array.<ol.proj.Projection>} projections Projections. - */ -ol.proj.addProjections = function(projections) { - var addedProjections = []; - projections.forEach(function(projection) { - addedProjections.push(ol.proj.addProjection(projection)); - }); -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.proj.clearAllProjections = function() { - ol.proj.projections_ = {}; - ol.proj.transforms_ = {}; -}; - - -/** - * @param {ol.proj.Projection|string|undefined} projection Projection. - * @param {string} defaultCode Default code. - * @return {ol.proj.Projection} Projection. - */ -ol.proj.createProjection = function(projection, defaultCode) { - if (!projection) { - return ol.proj.get(defaultCode); - } else if (goog.isString(projection)) { - return ol.proj.get(projection); - } else { - goog.asserts.assertInstanceof(projection, ol.proj.Projection, - 'projection should be an ol.proj.Projection'); - return projection; - } -}; - - -/** - * Registers a conversion function to convert coordinates from the source - * projection to the destination projection. - * - * @param {ol.proj.Projection} source Source. - * @param {ol.proj.Projection} destination Destination. - * @param {ol.TransformFunction} transformFn Transform. - */ -ol.proj.addTransform = function(source, destination, transformFn) { - var sourceCode = source.getCode(); - var destinationCode = destination.getCode(); - var transforms = ol.proj.transforms_; - if (!goog.object.containsKey(transforms, sourceCode)) { - transforms[sourceCode] = {}; - } - transforms[sourceCode][destinationCode] = transformFn; -}; - - -/** - * Registers coordinate transform functions to convert coordinates between the - * source projection and the destination projection. - * The forward and inverse functions convert coordinate pairs; this function - * converts these into the functions used internally which also handle - * extents and coordinate arrays. - * - * @param {ol.proj.ProjectionLike} source Source projection. - * @param {ol.proj.ProjectionLike} destination Destination projection. - * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform - * function (that is, from the source projection to the destination - * projection) that takes a {@link ol.Coordinate} as argument and returns - * the transformed {@link ol.Coordinate}. - * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform - * function (that is, from the destination projection to the source - * projection) that takes a {@link ol.Coordinate} as argument and returns - * the transformed {@link ol.Coordinate}. - * @api stable - */ -ol.proj.addCoordinateTransforms = - function(source, destination, forward, inverse) { - var sourceProj = ol.proj.get(source); - var destProj = ol.proj.get(destination); - ol.proj.addTransform(sourceProj, destProj, - ol.proj.createTransformFromCoordinateTransform(forward)); - ol.proj.addTransform(destProj, sourceProj, - ol.proj.createTransformFromCoordinateTransform(inverse)); -}; - - -/** - * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform - * function. - * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate - * transform. - * @return {ol.TransformFunction} Transform function. - */ -ol.proj.createTransformFromCoordinateTransform = function(transform) { - return ( - /** - * @param {Array.<number>} input Input. - * @param {Array.<number>=} opt_output Output. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Output. - */ - function(input, opt_output, opt_dimension) { - var length = input.length; - var dimension = opt_dimension !== undefined ? opt_dimension : 2; - var output = opt_output !== undefined ? opt_output : new Array(length); - var point, i, j; - for (i = 0; i < length; i += dimension) { - point = transform([input[i], input[i + 1]]); - output[i] = point[0]; - output[i + 1] = point[1]; - for (j = dimension - 1; j >= 2; --j) { - output[i + j] = input[i + j]; - } - } - return output; - }); -}; - - -/** - * Unregisters the conversion function to convert coordinates from the source - * projection to the destination projection. This method is used to clean up - * cached transforms during testing. - * - * @param {ol.proj.Projection} source Source projection. - * @param {ol.proj.Projection} destination Destination projection. - * @return {ol.TransformFunction} transformFn The unregistered transform. - */ -ol.proj.removeTransform = function(source, destination) { - var sourceCode = source.getCode(); - var destinationCode = destination.getCode(); - var transforms = ol.proj.transforms_; - goog.asserts.assert(sourceCode in transforms, - 'sourceCode should be in transforms'); - goog.asserts.assert(destinationCode in transforms[sourceCode], - 'destinationCode should be in transforms of sourceCode'); - var transform = transforms[sourceCode][destinationCode]; - delete transforms[sourceCode][destinationCode]; - if (goog.object.isEmpty(transforms[sourceCode])) { - delete transforms[sourceCode]; - } - return transform; -}; - - -/** - * Transforms a coordinate from longitude/latitude to a different projection. - * @param {ol.Coordinate} coordinate Coordinate as longitude and latitude, i.e. - * an array with longitude as 1st and latitude as 2nd element. - * @param {ol.proj.ProjectionLike=} opt_projection Target projection. The - * default is Web Mercator, i.e. 'EPSG:3857'. - * @return {ol.Coordinate} Coordinate projected to the target projection. - * @api stable - */ -ol.proj.fromLonLat = function(coordinate, opt_projection) { - return ol.proj.transform(coordinate, 'EPSG:4326', - opt_projection !== undefined ? opt_projection : 'EPSG:3857'); -}; - - -/** - * Transforms a coordinate to longitude/latitude. - * @param {ol.Coordinate} coordinate Projected coordinate. - * @param {ol.proj.ProjectionLike=} opt_projection Projection of the coordinate. - * The default is Web Mercator, i.e. 'EPSG:3857'. - * @return {ol.Coordinate} Coordinate as longitude and latitude, i.e. an array - * with longitude as 1st and latitude as 2nd element. - * @api stable - */ -ol.proj.toLonLat = function(coordinate, opt_projection) { - return ol.proj.transform(coordinate, - opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326'); -}; - - -/** - * Fetches a Projection object for the code specified. - * - * @param {ol.proj.ProjectionLike} projectionLike Either a code string which is - * a combination of authority and identifier such as "EPSG:4326", or an - * existing projection object, or undefined. - * @return {ol.proj.Projection} Projection object, or null if not in list. - * @api stable - */ -ol.proj.get = function(projectionLike) { - var projection; - if (projectionLike instanceof ol.proj.Projection) { - projection = projectionLike; - } else if (goog.isString(projectionLike)) { - var code = projectionLike; - projection = ol.proj.projections_[code]; - if (ol.ENABLE_PROJ4JS && projection === undefined && - typeof proj4 == 'function' && proj4.defs(code) !== undefined) { - projection = new ol.proj.Projection({code: code}); - ol.proj.addProjection(projection); - } - } else { - projection = null; - } - return projection; -}; - - -/** - * Checks if two projections are the same, that is every coordinate in one - * projection does represent the same geographic point as the same coordinate in - * the other projection. - * - * @param {ol.proj.Projection} projection1 Projection 1. - * @param {ol.proj.Projection} projection2 Projection 2. - * @return {boolean} Equivalent. - */ -ol.proj.equivalent = function(projection1, projection2) { - if (projection1 === projection2) { - return true; - } else if (projection1.getCode() === projection2.getCode()) { - return projection1.getUnits() === projection2.getUnits(); - } else { - var transformFn = ol.proj.getTransformFromProjections( - projection1, projection2); - return transformFn === ol.proj.cloneTransform; - } -}; - - -/** - * Given the projection-like objects, searches for a transformation - * function to convert a coordinates array from the source projection to the - * destination projection. - * - * @param {ol.proj.ProjectionLike} source Source. - * @param {ol.proj.ProjectionLike} destination Destination. - * @return {ol.TransformFunction} Transform function. - * @api stable - */ -ol.proj.getTransform = function(source, destination) { - var sourceProjection = ol.proj.get(source); - var destinationProjection = ol.proj.get(destination); - return ol.proj.getTransformFromProjections( - sourceProjection, destinationProjection); -}; - - -/** - * Searches in the list of transform functions for the function for converting - * coordinates from the source projection to the destination projection. - * - * @param {ol.proj.Projection} sourceProjection Source Projection object. - * @param {ol.proj.Projection} destinationProjection Destination Projection - * object. - * @return {ol.TransformFunction} Transform function. - */ -ol.proj.getTransformFromProjections = - function(sourceProjection, destinationProjection) { - var transforms = ol.proj.transforms_; - var sourceCode = sourceProjection.getCode(); - var destinationCode = destinationProjection.getCode(); - var transform; - if (goog.object.containsKey(transforms, sourceCode) && - goog.object.containsKey(transforms[sourceCode], destinationCode)) { - transform = transforms[sourceCode][destinationCode]; - } - if (transform === undefined) { - goog.asserts.assert(transform !== undefined, 'transform should be defined'); - transform = ol.proj.identityTransform; - } - return transform; -}; - - -/** - * @param {Array.<number>} input Input coordinate array. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Input coordinate array (same array as input). - */ -ol.proj.identityTransform = function(input, opt_output, opt_dimension) { - if (opt_output !== undefined && input !== opt_output) { - // TODO: consider making this a warning instead - goog.asserts.fail('This should not be used internally.'); - for (var i = 0, ii = input.length; i < ii; ++i) { - opt_output[i] = input[i]; - } - input = opt_output; - } - return input; -}; - - -/** - * @param {Array.<number>} input Input coordinate array. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Output coordinate array (new array, same coordinate - * values). - */ -ol.proj.cloneTransform = function(input, opt_output, opt_dimension) { - var output; - if (opt_output !== undefined) { - for (var i = 0, ii = input.length; i < ii; ++i) { - opt_output[i] = input[i]; - } - output = opt_output; - } else { - output = input.slice(); - } - return output; -}; - - -/** - * Transforms a coordinate from source projection to destination projection. - * This returns a new coordinate (and does not modify the original). - * - * See {@link ol.proj.transformExtent} for extent transformation. - * See the transform method of {@link ol.geom.Geometry} and its subclasses for - * geometry transforms. - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.proj.ProjectionLike} source Source projection-like. - * @param {ol.proj.ProjectionLike} destination Destination projection-like. - * @return {ol.Coordinate} Coordinate. - * @api stable - */ -ol.proj.transform = function(coordinate, source, destination) { - var transformFn = ol.proj.getTransform(source, destination); - return transformFn(coordinate, undefined, coordinate.length); -}; - - -/** - * Transforms an extent from source projection to destination projection. This - * returns a new extent (and does not modify the original). - * - * @param {ol.Extent} extent The extent to transform. - * @param {ol.proj.ProjectionLike} source Source projection-like. - * @param {ol.proj.ProjectionLike} destination Destination projection-like. - * @return {ol.Extent} The transformed extent. - * @api stable - */ -ol.proj.transformExtent = function(extent, source, destination) { - var transformFn = ol.proj.getTransform(source, destination); - return ol.extent.applyTransform(extent, transformFn); -}; - - -/** - * Transforms the given point to the destination projection. - * - * @param {ol.Coordinate} point Point. - * @param {ol.proj.Projection} sourceProjection Source projection. - * @param {ol.proj.Projection} destinationProjection Destination projection. - * @return {ol.Coordinate} Point. - */ -ol.proj.transformWithProjections = - function(point, sourceProjection, destinationProjection) { - var transformFn = ol.proj.getTransformFromProjections( - sourceProjection, destinationProjection); - return transformFn(point); -}; - -goog.provide('ol.geom.Geometry'); -goog.provide('ol.geom.GeometryLayout'); -goog.provide('ol.geom.GeometryType'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('ol.Object'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.proj.Units'); - - -/** - * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`, - * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`, - * `'GeometryCollection'`, `'Circle'`. - * @enum {string} - * @api stable - */ -ol.geom.GeometryType = { - POINT: 'Point', - LINE_STRING: 'LineString', - LINEAR_RING: 'LinearRing', - POLYGON: 'Polygon', - MULTI_POINT: 'MultiPoint', - MULTI_LINE_STRING: 'MultiLineString', - MULTI_POLYGON: 'MultiPolygon', - GEOMETRY_COLLECTION: 'GeometryCollection', - CIRCLE: 'Circle' -}; - - -/** - * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z') - * or measure ('M') coordinate is available. Supported values are `'XY'`, - * `'XYZ'`, `'XYM'`, `'XYZM'`. - * @enum {string} - * @api stable - */ -ol.geom.GeometryLayout = { - XY: 'XY', - XYZ: 'XYZ', - XYM: 'XYM', - XYZM: 'XYZM' -}; - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for vector geometries. - * - * To get notified of changes to the geometry, register a listener for the - * generic `change` event on your geometry instance. - * - * @constructor - * @extends {ol.Object} - * @api stable - */ -ol.geom.Geometry = function() { - - goog.base(this); - - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {number} - */ - this.extentRevision_ = -1; - - /** - * @protected - * @type {Object.<string, ol.geom.Geometry>} - */ - this.simplifiedGeometryCache = {}; - - /** - * @protected - * @type {number} - */ - this.simplifiedGeometryMaxMinSquaredTolerance = 0; - - /** - * @protected - * @type {number} - */ - this.simplifiedGeometryRevision = 0; - -}; -goog.inherits(ol.geom.Geometry, ol.Object); - - -/** - * Make a complete copy of the geometry. - * @function - * @return {!ol.geom.Geometry} Clone. - */ -ol.geom.Geometry.prototype.clone = goog.abstractMethod; - - -/** - * @param {number} x X. - * @param {number} y Y. - * @param {ol.Coordinate} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @return {number} Minimum squared distance. - */ -ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod; - - -/** - * Return the closest point of the geometry to the passed point as - * {@link ol.Coordinate coordinate}. - * @param {ol.Coordinate} point Point. - * @param {ol.Coordinate=} opt_closestPoint Closest point. - * @return {ol.Coordinate} Closest point. - * @api stable - */ -ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) { - var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN]; - this.closestPointXY(point[0], point[1], closestPoint, Infinity); - return closestPoint; -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @return {boolean} Contains coordinate. - */ -ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) { - return this.containsXY(coordinate[0], coordinate[1]); -}; - - -/** - * @param {ol.Extent} extent Extent. - * @protected - * @return {ol.Extent} extent Extent. - */ -ol.geom.Geometry.prototype.computeExtent = goog.abstractMethod; - - -/** - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.Geometry.prototype.containsXY = goog.functions.FALSE; - - -/** - * Get the extent of the geometry. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} extent Extent. - * @api stable - */ -ol.geom.Geometry.prototype.getExtent = function(opt_extent) { - if (this.extentRevision_ != this.getRevision()) { - this.extent_ = this.computeExtent(this.extent_); - this.extentRevision_ = this.getRevision(); - } - return ol.extent.returnOrUpdate(this.extent_, opt_extent); -}; - - -/** - * Create a simplified version of this geometry. For linestrings, this uses - * the the {@link - * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm - * Douglas Peucker} algorithm. For polygons, a quantization-based - * simplification is used to preserve topology. - * @function - * @param {number} tolerance The tolerance distance for simplification. - * @return {ol.geom.Geometry} A new, simplified version of the original - * geometry. - * @api - */ -ol.geom.Geometry.prototype.simplify = function(tolerance) { - return this.getSimplifiedGeometry(tolerance * tolerance); -}; - - -/** - * Create a simplified version of this geometry using the Douglas Peucker - * algorithm. - * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm - * @function - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.Geometry} Simplified geometry. - */ -ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod; - - -/** - * Get the type of this geometry. - * @function - * @return {ol.geom.GeometryType} Geometry type. - */ -ol.geom.Geometry.prototype.getType = goog.abstractMethod; - - -/** - * Apply a transform function to each coordinate of the geometry. - * The geometry is modified in place. - * If you do not want the geometry modified in place, first clone() it and - * then use this function on the clone. - * @function - * @param {ol.TransformFunction} transformFn Transform. - */ -ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod; - - -/** - * Test if the geometry and the passed extent intersect. - * @param {ol.Extent} extent Extent. - * @return {boolean} `true` if the geometry and the extent intersect. - * @function - */ -ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod; - - -/** - * Translate the geometry. This modifies the geometry coordinates in place. If - * instead you want a new geometry, first `clone()` this geometry. - * @param {number} deltaX Delta X. - * @param {number} deltaY Delta Y. - * @function - */ -ol.geom.Geometry.prototype.translate = goog.abstractMethod; - - -/** - * Transform each coordinate of the geometry from one coordinate reference - * system to another. The geometry is modified in place. - * For example, a line will be transformed to a line and a circle to a circle. - * If you do not want the geometry modified in place, first clone() it and - * then use this function on the clone. - * - * @param {ol.proj.ProjectionLike} source The current projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @param {ol.proj.ProjectionLike} destination The desired projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @return {ol.geom.Geometry} This geometry. Note that original geometry is - * modified in place. - * @api stable - */ -ol.geom.Geometry.prototype.transform = function(source, destination) { - goog.asserts.assert( - ol.proj.get(source).getUnits() !== ol.proj.Units.TILE_PIXELS && - ol.proj.get(destination).getUnits() !== ol.proj.Units.TILE_PIXELS, - 'cannot transform geometries with TILE_PIXELS units'); - this.applyTransform(ol.proj.getTransform(source, destination)); - return this; -}; - -goog.provide('ol.geom.flat.transform'); - -goog.require('goog.vec.Mat4'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Transformed coordinates. - */ -ol.geom.flat.transform.transform2D = - function(flatCoordinates, offset, end, stride, transform, opt_dest) { - var m00 = goog.vec.Mat4.getElement(transform, 0, 0); - var m10 = goog.vec.Mat4.getElement(transform, 1, 0); - var m01 = goog.vec.Mat4.getElement(transform, 0, 1); - var m11 = goog.vec.Mat4.getElement(transform, 1, 1); - var m03 = goog.vec.Mat4.getElement(transform, 0, 3); - var m13 = goog.vec.Mat4.getElement(transform, 1, 3); - var dest = opt_dest ? opt_dest : []; - var i = 0; - var j; - for (j = offset; j < end; j += stride) { - var x = flatCoordinates[j]; - var y = flatCoordinates[j + 1]; - dest[i++] = m00 * x + m01 * y + m03; - dest[i++] = m10 * x + m11 * y + m13; - } - if (opt_dest && dest.length != i) { - dest.length = i; - } - return dest; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} deltaX Delta X. - * @param {number} deltaY Delta Y. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Transformed coordinates. - */ -ol.geom.flat.transform.translate = - function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) { - var dest = opt_dest ? opt_dest : []; - var i = 0; - var j, k; - for (j = offset; j < end; j += stride) { - dest[i++] = flatCoordinates[j] + deltaX; - dest[i++] = flatCoordinates[j + 1] + deltaY; - for (k = j + 2; k < j + stride; ++k) { - dest[i++] = flatCoordinates[k]; - } - } - if (opt_dest && dest.length != i) { - dest.length = i; - } - return dest; -}; - -goog.provide('ol.geom.SimpleGeometry'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.flat.transform'); - - - -/** - * @classdesc - * Abstract base class; only used for creating subclasses; do not instantiate - * in apps, as cannot be rendered. - * - * @constructor - * @extends {ol.geom.Geometry} - * @api stable - */ -ol.geom.SimpleGeometry = function() { - - goog.base(this); - - /** - * @protected - * @type {ol.geom.GeometryLayout} - */ - this.layout = ol.geom.GeometryLayout.XY; - - /** - * @protected - * @type {number} - */ - this.stride = 2; - - /** - * @protected - * @type {Array.<number>} - */ - this.flatCoordinates = null; - -}; -goog.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry); - - -/** - * @param {number} stride Stride. - * @private - * @return {ol.geom.GeometryLayout} layout Layout. - */ -ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) { - if (stride == 2) { - return ol.geom.GeometryLayout.XY; - } else if (stride == 3) { - return ol.geom.GeometryLayout.XYZ; - } else if (stride == 4) { - return ol.geom.GeometryLayout.XYZM; - } else { - goog.asserts.fail('unsupported stride: ' + stride); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @return {number} Stride. - */ -ol.geom.SimpleGeometry.getStrideForLayout = function(layout) { - if (layout == ol.geom.GeometryLayout.XY) { - return 2; - } else if (layout == ol.geom.GeometryLayout.XYZ) { - return 3; - } else if (layout == ol.geom.GeometryLayout.XYM) { - return 3; - } else if (layout == ol.geom.GeometryLayout.XYZM) { - return 4; - } else { - goog.asserts.fail('unsupported layout: ' + layout); - } -}; - - -/** - * @inheritDoc - */ -ol.geom.SimpleGeometry.prototype.containsXY = goog.functions.FALSE; - - -/** - * @inheritDoc - */ -ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) { - return ol.extent.createOrUpdateFromFlatCoordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - extent); -}; - - -/** - * @return {Array} Coordinates. - */ -ol.geom.SimpleGeometry.prototype.getCoordinates = goog.abstractMethod; - - -/** - * Return the first coordinate of the geometry. - * @return {ol.Coordinate} First coordinate. - * @api stable - */ -ol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() { - return this.flatCoordinates.slice(0, this.stride); -}; - - -/** - * @return {Array.<number>} Flat coordinates. - */ -ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() { - return this.flatCoordinates; -}; - - -/** - * Return the last coordinate of the geometry. - * @return {ol.Coordinate} Last point. - * @api stable - */ -ol.geom.SimpleGeometry.prototype.getLastCoordinate = function() { - return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride); -}; - - -/** - * Return the {@link ol.geom.GeometryLayout layout} of the geometry. - * @return {ol.geom.GeometryLayout} Layout. - * @api stable - */ -ol.geom.SimpleGeometry.prototype.getLayout = function() { - return this.layout; -}; - - -/** - * @inheritDoc - */ -ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = - function(squaredTolerance) { - if (this.simplifiedGeometryRevision != this.getRevision()) { - goog.object.clear(this.simplifiedGeometryCache); - this.simplifiedGeometryMaxMinSquaredTolerance = 0; - this.simplifiedGeometryRevision = this.getRevision(); - } - // If squaredTolerance is negative or if we know that simplification will not - // have any effect then just return this. - if (squaredTolerance < 0 || - (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && - squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) { - return this; - } - var key = squaredTolerance.toString(); - if (this.simplifiedGeometryCache.hasOwnProperty(key)) { - return this.simplifiedGeometryCache[key]; - } else { - var simplifiedGeometry = - this.getSimplifiedGeometryInternal(squaredTolerance); - var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates(); - if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) { - this.simplifiedGeometryCache[key] = simplifiedGeometry; - return simplifiedGeometry; - } else { - // Simplification did not actually remove any coordinates. We now know - // that any calls to getSimplifiedGeometry with a squaredTolerance less - // than or equal to the current squaredTolerance will also not have any - // effect. This allows us to short circuit simplification (saving CPU - // cycles) and prevents the cache of simplified geometries from filling - // up with useless identical copies of this geometry (saving memory). - this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; - return this; - } - } -}; - - -/** - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.SimpleGeometry} Simplified geometry. - * @protected - */ -ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - return this; -}; - - -/** - * @return {number} Stride. - */ -ol.geom.SimpleGeometry.prototype.getStride = function() { - return this.stride; -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @protected - */ -ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = - function(layout, flatCoordinates) { - this.stride = ol.geom.SimpleGeometry.getStrideForLayout(layout); - this.layout = layout; - this.flatCoordinates = flatCoordinates; -}; - - -/** - * @param {Array} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - */ -ol.geom.SimpleGeometry.prototype.setCoordinates = goog.abstractMethod; - - -/** - * @param {ol.geom.GeometryLayout|undefined} layout Layout. - * @param {Array} coordinates Coordinates. - * @param {number} nesting Nesting. - * @protected - */ -ol.geom.SimpleGeometry.prototype.setLayout = - function(layout, coordinates, nesting) { - /** @type {number} */ - var stride; - if (layout) { - stride = ol.geom.SimpleGeometry.getStrideForLayout(layout); - } else { - var i; - for (i = 0; i < nesting; ++i) { - if (coordinates.length === 0) { - this.layout = ol.geom.GeometryLayout.XY; - this.stride = 2; - return; - } else { - coordinates = /** @type {Array} */ (coordinates[0]); - } - } - stride = (/** @type {Array} */ (coordinates)).length; - layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride); - } - this.layout = layout; - this.stride = stride; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) { - if (this.flatCoordinates) { - transformFn(this.flatCoordinates, this.flatCoordinates, this.stride); - this.changed(); - } -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) { - var flatCoordinates = this.getFlatCoordinates(); - if (flatCoordinates) { - var stride = this.getStride(); - ol.geom.flat.transform.translate( - flatCoordinates, 0, flatCoordinates.length, stride, - deltaX, deltaY, flatCoordinates); - this.changed(); - } -}; - - -/** - * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Transformed flat coordinates. - */ -ol.geom.transformSimpleGeometry2D = - function(simpleGeometry, transform, opt_dest) { - var flatCoordinates = simpleGeometry.getFlatCoordinates(); - if (!flatCoordinates) { - return null; - } else { - var stride = simpleGeometry.getStride(); - return ol.geom.flat.transform.transform2D( - flatCoordinates, 0, flatCoordinates.length, stride, - transform, opt_dest); - } -}; - -goog.provide('ol.geom.flat.area'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Area. - */ -ol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) { - var twiceArea = 0; - var x1 = flatCoordinates[end - stride]; - var y1 = flatCoordinates[end - stride + 1]; - for (; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - twiceArea += y1 * x2 - x1 * y2; - x1 = x2; - y1 = y2; - } - return twiceArea / 2; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @return {number} Area. - */ -ol.geom.flat.area.linearRings = - function(flatCoordinates, offset, ends, stride) { - var area = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride); - offset = end; - } - return area; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @return {number} Area. - */ -ol.geom.flat.area.linearRingss = - function(flatCoordinates, offset, endss, stride) { - var area = 0; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - area += - ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride); - offset = ends[ends.length - 1]; - } - return area; -}; - -goog.provide('ol.geom.flat.closest'); - -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol.math'); - - -/** - * Returns the point on the 2D line segment flatCoordinates[offset1] to - * flatCoordinates[offset2] that is closest to the point (x, y). Extra - * dimensions are linearly interpolated. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset1 Offset 1. - * @param {number} offset2 Offset 2. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - */ -ol.geom.flat.closest.point = - function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) { - var x1 = flatCoordinates[offset1]; - var y1 = flatCoordinates[offset1 + 1]; - var dx = flatCoordinates[offset2] - x1; - var dy = flatCoordinates[offset2 + 1] - y1; - var i, offset; - if (dx === 0 && dy === 0) { - offset = offset1; - } else { - var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); - if (t > 1) { - offset = offset2; - } else if (t > 0) { - for (i = 0; i < stride; ++i) { - closestPoint[i] = goog.math.lerp(flatCoordinates[offset1 + i], - flatCoordinates[offset2 + i], t); - } - closestPoint.length = stride; - return; - } else { - offset = offset1; - } - } - for (i = 0; i < stride; ++i) { - closestPoint[i] = flatCoordinates[offset + i]; - } - closestPoint.length = stride; -}; - - -/** - * Return the squared of the largest distance between any pair of consecutive - * coordinates. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} maxSquaredDelta Max squared delta. - * @return {number} Max squared delta. - */ -ol.geom.flat.closest.getMaxSquaredDelta = - function(flatCoordinates, offset, end, stride, maxSquaredDelta) { - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - for (offset += stride; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2); - if (squaredDelta > maxSquaredDelta) { - maxSquaredDelta = squaredDelta; - } - x1 = x2; - y1 = y2; - } - return maxSquaredDelta; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} maxSquaredDelta Max squared delta. - * @return {number} Max squared delta. - */ -ol.geom.flat.closest.getsMaxSquaredDelta = - function(flatCoordinates, offset, ends, stride, maxSquaredDelta) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta( - flatCoordinates, offset, end, stride, maxSquaredDelta); - offset = end; - } - return maxSquaredDelta; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} maxSquaredDelta Max squared delta. - * @return {number} Max squared delta. - */ -ol.geom.flat.closest.getssMaxSquaredDelta = - function(flatCoordinates, offset, endss, stride, maxSquaredDelta) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta( - flatCoordinates, offset, ends, stride, maxSquaredDelta); - offset = ends[ends.length - 1]; - } - return maxSquaredDelta; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} maxDelta Max delta. - * @param {boolean} isRing Is ring. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @param {Array.<number>=} opt_tmpPoint Temporary point object. - * @return {number} Minimum squared distance. - */ -ol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end, - stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, - opt_tmpPoint) { - if (offset == end) { - return minSquaredDistance; - } - var i, squaredDistance; - if (maxDelta === 0) { - // All points are identical, so just test the first point. - squaredDistance = ol.math.squaredDistance( - x, y, flatCoordinates[offset], flatCoordinates[offset + 1]); - if (squaredDistance < minSquaredDistance) { - for (i = 0; i < stride; ++i) { - closestPoint[i] = flatCoordinates[offset + i]; - } - closestPoint.length = stride; - return squaredDistance; - } else { - return minSquaredDistance; - } - } - goog.asserts.assert(maxDelta > 0, 'maxDelta should be larger than 0'); - var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; - var index = offset + stride; - while (index < end) { - ol.geom.flat.closest.point( - flatCoordinates, index - stride, index, stride, x, y, tmpPoint); - squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); - if (squaredDistance < minSquaredDistance) { - minSquaredDistance = squaredDistance; - for (i = 0; i < stride; ++i) { - closestPoint[i] = tmpPoint[i]; - } - closestPoint.length = stride; - index += stride; - } else { - // Skip ahead multiple points, because we know that all the skipped - // points cannot be any closer than the closest point we have found so - // far. We know this because we know how close the current point is, how - // close the closest point we have found so far is, and the maximum - // distance between consecutive points. For example, if we're currently - // at distance 10, the best we've found so far is 3, and that the maximum - // distance between consecutive points is 2, then we'll need to skip at - // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of - // finding a closer point. We use Math.max(..., 1) to ensure that we - // always advance at least one point, to avoid an infinite loop. - index += stride * Math.max( - ((Math.sqrt(squaredDistance) - - Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1); - } - } - if (isRing) { - // Check the closing segment. - ol.geom.flat.closest.point( - flatCoordinates, end - stride, offset, stride, x, y, tmpPoint); - squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); - if (squaredDistance < minSquaredDistance) { - minSquaredDistance = squaredDistance; - for (i = 0; i < stride; ++i) { - closestPoint[i] = tmpPoint[i]; - } - closestPoint.length = stride; - } - } - return minSquaredDistance; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} maxDelta Max delta. - * @param {boolean} isRing Is ring. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @param {Array.<number>=} opt_tmpPoint Temporary point object. - * @return {number} Minimum squared distance. - */ -ol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends, - stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, - opt_tmpPoint) { - var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - minSquaredDistance = ol.geom.flat.closest.getClosestPoint( - flatCoordinates, offset, end, stride, - maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint); - offset = end; - } - return minSquaredDistance; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} maxDelta Max delta. - * @param {boolean} isRing Is ring. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @param {Array.<number>=} opt_tmpPoint Temporary point object. - * @return {number} Minimum squared distance. - */ -ol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset, - endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, - opt_tmpPoint) { - var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - minSquaredDistance = ol.geom.flat.closest.getsClosestPoint( - flatCoordinates, offset, ends, stride, - maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint); - offset = ends[ends.length - 1]; - } - return minSquaredDistance; -}; - -goog.provide('ol.geom.flat.deflate'); - -goog.require('goog.asserts'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} stride Stride. - * @return {number} offset Offset. - */ -ol.geom.flat.deflate.coordinate = - function(flatCoordinates, offset, coordinate, stride) { - goog.asserts.assert(coordinate.length == stride, - 'length of the coordinate array should match stride'); - var i, ii; - for (i = 0, ii = coordinate.length; i < ii; ++i) { - flatCoordinates[offset++] = coordinate[i]; - } - return offset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {number} stride Stride. - * @return {number} offset Offset. - */ -ol.geom.flat.deflate.coordinates = - function(flatCoordinates, offset, coordinates, stride) { - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - var coordinate = coordinates[i]; - goog.asserts.assert(coordinate.length == stride, - 'length of coordinate array should match stride'); - var j; - for (j = 0; j < stride; ++j) { - flatCoordinates[offset++] = coordinate[j]; - } - } - return offset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess. - * @param {number} stride Stride. - * @param {Array.<number>=} opt_ends Ends. - * @return {Array.<number>} Ends. - */ -ol.geom.flat.deflate.coordinatess = - function(flatCoordinates, offset, coordinatess, stride, opt_ends) { - var ends = opt_ends ? opt_ends : []; - var i = 0; - var j, jj; - for (j = 0, jj = coordinatess.length; j < jj; ++j) { - var end = ol.geom.flat.deflate.coordinates( - flatCoordinates, offset, coordinatess[j], stride); - ends[i++] = end; - offset = end; - } - ends.length = i; - return ends; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss. - * @param {number} stride Stride. - * @param {Array.<Array.<number>>=} opt_endss Endss. - * @return {Array.<Array.<number>>} Endss. - */ -ol.geom.flat.deflate.coordinatesss = - function(flatCoordinates, offset, coordinatesss, stride, opt_endss) { - var endss = opt_endss ? opt_endss : []; - var i = 0; - var j, jj; - for (j = 0, jj = coordinatesss.length; j < jj; ++j) { - var ends = ol.geom.flat.deflate.coordinatess( - flatCoordinates, offset, coordinatesss[j], stride, endss[i]); - endss[i++] = ends; - offset = ends[ends.length - 1]; - } - endss.length = i; - return endss; -}; - -goog.provide('ol.geom.flat.inflate'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates. - * @return {Array.<ol.Coordinate>} Coordinates. - */ -ol.geom.flat.inflate.coordinates = - function(flatCoordinates, offset, end, stride, opt_coordinates) { - var coordinates = opt_coordinates !== undefined ? opt_coordinates : []; - var i = 0; - var j; - for (j = offset; j < end; j += stride) { - coordinates[i++] = flatCoordinates.slice(j, j + stride); - } - coordinates.length = i; - return coordinates; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess. - * @return {Array.<Array.<ol.Coordinate>>} Coordinatess. - */ -ol.geom.flat.inflate.coordinatess = - function(flatCoordinates, offset, ends, stride, opt_coordinatess) { - var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : []; - var i = 0; - var j, jj; - for (j = 0, jj = ends.length; j < jj; ++j) { - var end = ends[j]; - coordinatess[i++] = ol.geom.flat.inflate.coordinates( - flatCoordinates, offset, end, stride, coordinatess[i]); - offset = end; - } - coordinatess.length = i; - return coordinatess; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss - * Coordinatesss. - * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss. - */ -ol.geom.flat.inflate.coordinatesss = - function(flatCoordinates, offset, endss, stride, opt_coordinatesss) { - var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : []; - var i = 0; - var j, jj; - for (j = 0, jj = endss.length; j < jj; ++j) { - var ends = endss[j]; - coordinatesss[i++] = ol.geom.flat.inflate.coordinatess( - flatCoordinates, offset, ends, stride, coordinatesss[i]); - offset = ends[ends.length - 1]; - } - coordinatesss.length = i; - return coordinatesss; -}; - -// Based on simplify-js https://github.com/mourner/simplify-js -// Copyright (c) 2012, Vladimir Agafonkin -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.geom.flat.simplify'); - -goog.require('ol.math'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {boolean} highQuality Highest quality. - * @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat - * coordinates. - * @return {Array.<number>} Simplified line string. - */ -ol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end, - stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) { - var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ? - opt_simplifiedFlatCoordinates : []; - if (!highQuality) { - end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end, - stride, squaredTolerance, - simplifiedFlatCoordinates, 0); - flatCoordinates = simplifiedFlatCoordinates; - offset = 0; - stride = 2; - } - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( - flatCoordinates, offset, end, stride, squaredTolerance, - simplifiedFlatCoordinates, 0); - return simplifiedFlatCoordinates; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end, - stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) { - var n = (end - offset) / stride; - if (n < 3) { - for (; offset < end; offset += stride) { - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset]; - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + 1]; - } - return simplifiedOffset; - } - /** @type {Array.<number>} */ - var markers = new Array(n); - markers[0] = 1; - markers[n - 1] = 1; - /** @type {Array.<number>} */ - var stack = [offset, end - stride]; - var index = 0; - var i; - while (stack.length > 0) { - var last = stack.pop(); - var first = stack.pop(); - var maxSquaredDistance = 0; - var x1 = flatCoordinates[first]; - var y1 = flatCoordinates[first + 1]; - var x2 = flatCoordinates[last]; - var y2 = flatCoordinates[last + 1]; - for (i = first + stride; i < last; i += stride) { - var x = flatCoordinates[i]; - var y = flatCoordinates[i + 1]; - var squaredDistance = ol.math.squaredSegmentDistance( - x, y, x1, y1, x2, y2); - if (squaredDistance > maxSquaredDistance) { - index = i; - maxSquaredDistance = squaredDistance; - } - } - if (maxSquaredDistance > squaredTolerance) { - markers[(index - offset) / stride] = 1; - if (first + stride < index) { - stack.push(first, index); - } - if (index + stride < last) { - stack.push(index, last); - } - } - } - for (i = 0; i < n; ++i) { - if (markers[i]) { - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + i * stride]; - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + i * stride + 1]; - } - } - return simplifiedOffset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<number>} simplifiedEnds Simplified ends. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset, - ends, stride, squaredTolerance, simplifiedFlatCoordinates, - simplifiedOffset, simplifiedEnds) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - simplifiedOffset = ol.geom.flat.simplify.douglasPeucker( - flatCoordinates, offset, end, stride, squaredTolerance, - simplifiedFlatCoordinates, simplifiedOffset); - simplifiedEnds.push(simplifiedOffset); - offset = end; - } - return simplifiedOffset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.douglasPeuckerss = function( - flatCoordinates, offset, endss, stride, squaredTolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - var simplifiedEnds = []; - simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers( - flatCoordinates, offset, ends, stride, squaredTolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds); - simplifiedEndss.push(simplifiedEnds); - offset = ends[ends.length - 1]; - } - return simplifiedOffset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end, - stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) { - if (end <= offset + stride) { - // zero or one point, no simplification possible, so copy and return - for (; offset < end; offset += stride) { - simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset]; - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + 1]; - } - return simplifiedOffset; - } - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - // copy first point - simplifiedFlatCoordinates[simplifiedOffset++] = x1; - simplifiedFlatCoordinates[simplifiedOffset++] = y1; - var x2 = x1; - var y2 = y1; - for (offset += stride; offset < end; offset += stride) { - x2 = flatCoordinates[offset]; - y2 = flatCoordinates[offset + 1]; - if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) { - // copy point at offset - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - x1 = x2; - y1 = y2; - } - } - if (x2 != x1 || y2 != y1) { - // copy last point - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - } - return simplifiedOffset; -}; - - -/** - * @param {number} value Value. - * @param {number} tolerance Tolerance. - * @return {number} Rounded value. - */ -ol.geom.flat.simplify.snap = function(value, tolerance) { - return tolerance * Math.round(value / tolerance); -}; - - -/** - * Simplifies a line string using an algorithm designed by Tim Schaub. - * Coordinates are snapped to the nearest value in a virtual grid and - * consecutive duplicate coordinates are discarded. This effectively preserves - * topology as the simplification of any subsection of a line string is - * independent of the rest of the line string. This means that, for examples, - * the common edge between two polygons will be simplified to the same line - * string independently in both polygons. This implementation uses a single - * pass over the coordinates and eliminates intermediate collinear points. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} tolerance Tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride, - tolerance, simplifiedFlatCoordinates, simplifiedOffset) { - // do nothing if the line is empty - if (offset == end) { - return simplifiedOffset; - } - // snap the first coordinate (P1) - var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); - var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); - offset += stride; - // add the first coordinate to the output - simplifiedFlatCoordinates[simplifiedOffset++] = x1; - simplifiedFlatCoordinates[simplifiedOffset++] = y1; - // find the next coordinate that does not snap to the same value as the first - // coordinate (P2) - var x2, y2; - do { - x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); - y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); - offset += stride; - if (offset == end) { - // all coordinates snap to the same value, the line collapses to a point - // push the last snapped value anyway to ensure that the output contains - // at least two points - // FIXME should we really return at least two points anyway? - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - return simplifiedOffset; - } - } while (x2 == x1 && y2 == y1); - while (offset < end) { - var x3, y3; - // snap the next coordinate (P3) - x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); - y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); - offset += stride; - // skip P3 if it is equal to P2 - if (x3 == x2 && y3 == y2) { - continue; - } - // calculate the delta between P1 and P2 - var dx1 = x2 - x1; - var dy1 = y2 - y1; - // calculate the delta between P3 and P1 - var dx2 = x3 - x1; - var dy2 = y3 - y1; - // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from - // P1 in the same direction then P2 is on the straight line between P1 and - // P3 - if ((dx1 * dy2 == dy1 * dx2) && - ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) && - ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) { - // discard P2 and set P2 = P3 - x2 = x3; - y2 = y3; - continue; - } - // either P1, P2, and P3 are not colinear, or they are colinear but P3 is - // between P3 and P1 or on the opposite half of the line to P2. add P2, - // and continue with P1 = P2 and P2 = P3 - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - x1 = x2; - y1 = y2; - x2 = x3; - y2 = y3; - } - // add the last point (P2) - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - return simplifiedOffset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} tolerance Tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<number>} simplifiedEnds Simplified ends. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.quantizes = function( - flatCoordinates, offset, ends, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - simplifiedOffset = ol.geom.flat.simplify.quantize( - flatCoordinates, offset, end, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset); - simplifiedEnds.push(simplifiedOffset); - offset = end; - } - return simplifiedOffset; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} tolerance Tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss. - * @return {number} Simplified offset. - */ -ol.geom.flat.simplify.quantizess = function( - flatCoordinates, offset, endss, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - var simplifiedEnds = []; - simplifiedOffset = ol.geom.flat.simplify.quantizes( - flatCoordinates, offset, ends, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds); - simplifiedEndss.push(simplifiedEnds); - offset = ends[ends.length - 1]; - } - return simplifiedOffset; -}; - -goog.provide('ol.geom.LinearRing'); - -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.area'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.simplify'); - - - -/** - * @classdesc - * Linear ring geometry. Only used as part of polygon; cannot be rendered - * on its own. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.LinearRing = function(coordinates, opt_layout) { - - goog.base(this); - - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; - - this.setCoordinates(coordinates, opt_layout); - -}; -goog.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry); - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.LinearRing} Clone. - * @api stable - */ -ol.geom.LinearRing.prototype.clone = function() { - var linearRing = new ol.geom.LinearRing(null); - linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return linearRing; -}; - - -/** - * @inheritDoc - */ -ol.geom.LinearRing.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getClosestPoint( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); -}; - - -/** - * Return the area of the linear ring on projected plane. - * @return {number} Area (on projected plane). - * @api stable - */ -ol.geom.LinearRing.prototype.getArea = function() { - return ol.geom.flat.area.linearRing( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; - - -/** - * Return the coordinates of the linear ring. - * @return {Array.<ol.Coordinate>} Coordinates. - * @api stable - */ -ol.geom.LinearRing.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; - - -/** - * @inheritDoc - */ -ol.geom.LinearRing.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - squaredTolerance, simplifiedFlatCoordinates, 0); - var simplifiedLinearRing = new ol.geom.LinearRing(null); - simplifiedLinearRing.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates); - return simplifiedLinearRing; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.LinearRing.prototype.getType = function() { - return ol.geom.GeometryType.LINEAR_RING; -}; - - -/** - * Set the coordinates of the linear ring. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.LinearRing.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 1); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - */ -ol.geom.LinearRing.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; - -goog.provide('ol.geom.Point'); - -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.math'); - - - -/** - * @classdesc - * Point geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {ol.Coordinate} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.Point = function(coordinates, opt_layout) { - goog.base(this); - this.setCoordinates(coordinates, opt_layout); -}; -goog.inherits(ol.geom.Point, ol.geom.SimpleGeometry); - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.Point} Clone. - * @api stable - */ -ol.geom.Point.prototype.clone = function() { - var point = new ol.geom.Point(null); - point.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return point; -}; - - -/** - * @inheritDoc - */ -ol.geom.Point.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - var flatCoordinates = this.flatCoordinates; - var squaredDistance = ol.math.squaredDistance( - x, y, flatCoordinates[0], flatCoordinates[1]); - if (squaredDistance < minSquaredDistance) { - var stride = this.stride; - var i; - for (i = 0; i < stride; ++i) { - closestPoint[i] = flatCoordinates[i]; - } - closestPoint.length = stride; - return squaredDistance; - } else { - return minSquaredDistance; - } -}; - - -/** - * Return the coordinate of the point. - * @return {ol.Coordinate} Coordinates. - * @api stable - */ -ol.geom.Point.prototype.getCoordinates = function() { - return !this.flatCoordinates ? [] : this.flatCoordinates.slice(); -}; - - -/** - * @inheritDoc - */ -ol.geom.Point.prototype.computeExtent = function(extent) { - return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent); -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.Point.prototype.getType = function() { - return ol.geom.GeometryType.POINT; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.Point.prototype.intersectsExtent = function(extent) { - return ol.extent.containsXY(extent, - this.flatCoordinates[0], this.flatCoordinates[1]); -}; - - -/** - * Set the coordinate of the point. - * @param {ol.Coordinate} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 0); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinate( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - */ -ol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; - -goog.provide('ol.geom.flat.contains'); - -goog.require('goog.asserts'); -goog.require('ol.extent'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} Contains extent. - */ -ol.geom.flat.contains.linearRingContainsExtent = - function(flatCoordinates, offset, end, stride, extent) { - var outside = ol.extent.forEachCorner(extent, - /** - * @param {ol.Coordinate} coordinate Coordinate. - */ - function(coordinate) { - return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates, - offset, end, stride, coordinate[0], coordinate[1]); - }); - return !outside; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.flat.contains.linearRingContainsXY = - function(flatCoordinates, offset, end, stride, x, y) { - // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html - var contains = false; - var x1 = flatCoordinates[end - stride]; - var y1 = flatCoordinates[end - stride + 1]; - for (; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - var intersect = ((y1 > y) != (y2 > y)) && - (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1); - if (intersect) { - contains = !contains; - } - x1 = x2; - y1 = y2; - } - return contains; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.flat.contains.linearRingsContainsXY = - function(flatCoordinates, offset, ends, stride, x, y) { - goog.asserts.assert(ends.length > 0, 'ends should not be an empty array'); - if (ends.length === 0) { - return false; - } - if (!ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, ends[0], stride, x, y)) { - return false; - } - var i, ii; - for (i = 1, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, ends[i - 1], ends[i], stride, x, y)) { - return false; - } - } - return true; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.flat.contains.linearRingssContainsXY = - function(flatCoordinates, offset, endss, stride, x, y) { - goog.asserts.assert(endss.length > 0, 'endss should not be an empty array'); - if (endss.length === 0) { - return false; - } - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - if (ol.geom.flat.contains.linearRingsContainsXY( - flatCoordinates, offset, ends, stride, x, y)) { - return true; - } - offset = ends[ends.length - 1]; - } - return false; -}; - -goog.provide('ol.geom.flat.interiorpoint'); - -goog.require('goog.asserts'); -goog.require('ol.geom.flat.contains'); - - -/** - * Calculates a point that is likely to lie in the interior of the linear rings. - * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {Array.<number>} flatCenters Flat centers. - * @param {number} flatCentersOffset Flat center offset. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Destination. - */ -ol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset, - ends, stride, flatCenters, flatCentersOffset, opt_dest) { - var i, ii, x, x1, x2, y1, y2; - var y = flatCenters[flatCentersOffset + 1]; - /** @type {Array.<number>} */ - var intersections = []; - // Calculate intersections with the horizontal line - var end = ends[0]; - x1 = flatCoordinates[end - stride]; - y1 = flatCoordinates[end - stride + 1]; - for (i = offset; i < end; i += stride) { - x2 = flatCoordinates[i]; - y2 = flatCoordinates[i + 1]; - if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { - x = (y - y1) / (y2 - y1) * (x2 - x1) + x1; - intersections.push(x); - } - x1 = x2; - y1 = y2; - } - // Find the longest segment of the horizontal line that has its center point - // inside the linear ring. - var pointX = NaN; - var maxSegmentLength = -Infinity; - intersections.sort(); - x1 = intersections[0]; - for (i = 1, ii = intersections.length; i < ii; ++i) { - x2 = intersections[i]; - var segmentLength = Math.abs(x2 - x1); - if (segmentLength > maxSegmentLength) { - x = (x1 + x2) / 2; - if (ol.geom.flat.contains.linearRingsContainsXY( - flatCoordinates, offset, ends, stride, x, y)) { - pointX = x; - maxSegmentLength = segmentLength; - } - } - x1 = x2; - } - if (isNaN(pointX)) { - // There is no horizontal line that has its center point inside the linear - // ring. Use the center of the the linear ring's extent. - pointX = flatCenters[flatCentersOffset]; - } - if (opt_dest) { - opt_dest.push(pointX, y); - return opt_dest; - } else { - return [pointX, y]; - } -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {Array.<number>} flatCenters Flat centers. - * @return {Array.<number>} Interior points. - */ -ol.geom.flat.interiorpoint.linearRingss = - function(flatCoordinates, offset, endss, stride, flatCenters) { - goog.asserts.assert(2 * endss.length == flatCenters.length, - 'endss.length times 2 should be flatCenters.length'); - var interiorPoints = []; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates, - offset, ends, stride, flatCenters, 2 * i, interiorPoints); - offset = ends[ends.length - 1]; - } - return interiorPoints; -}; - -goog.provide('ol.geom.flat.segments'); - - -/** - * This function calls `callback` for each segment of the flat coordinates - * array. If the callback returns a truthy value the function returns that - * value immediately. Otherwise the function returns `false`. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function - * called for each segment. - * @param {S=} opt_this The object to be used as the value of 'this' - * within callback. - * @return {T|boolean} Value. - * @template T,S - */ -ol.geom.flat.segments.forEach = - function(flatCoordinates, offset, end, stride, callback, opt_this) { - var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]]; - var point2 = []; - var ret; - for (; (offset + stride) < end; offset += stride) { - point2[0] = flatCoordinates[offset + stride]; - point2[1] = flatCoordinates[offset + stride + 1]; - ret = callback.call(opt_this, point1, point2); - if (ret) { - return ret; - } - point1[0] = point2[0]; - point1[1] = point2[1]; - } - return false; -}; - -goog.provide('ol.geom.flat.intersectsextent'); - -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.flat.contains'); -goog.require('ol.geom.flat.segments'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. - */ -ol.geom.flat.intersectsextent.lineString = - function(flatCoordinates, offset, end, stride, extent) { - var coordinatesExtent = ol.extent.extendFlatCoordinates( - ol.extent.createEmpty(), flatCoordinates, offset, end, stride); - if (!ol.extent.intersects(extent, coordinatesExtent)) { - return false; - } - if (ol.extent.containsExtent(extent, coordinatesExtent)) { - return true; - } - if (coordinatesExtent[0] >= extent[0] && - coordinatesExtent[2] <= extent[2]) { - return true; - } - if (coordinatesExtent[1] >= extent[1] && - coordinatesExtent[3] <= extent[3]) { - return true; - } - return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride, - /** - * @param {ol.Coordinate} point1 Start point. - * @param {ol.Coordinate} point2 End point. - * @return {boolean} `true` if the segment and the extent intersect, - * `false` otherwise. - */ - function(point1, point2) { - return ol.extent.intersectsSegment(extent, point1, point2); - }); -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. - */ -ol.geom.flat.intersectsextent.lineStrings = - function(flatCoordinates, offset, ends, stride, extent) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.intersectsextent.lineString( - flatCoordinates, offset, ends[i], stride, extent)) { - return true; - } - offset = ends[i]; - } - return false; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. - */ -ol.geom.flat.intersectsextent.linearRing = - function(flatCoordinates, offset, end, stride, extent) { - if (ol.geom.flat.intersectsextent.lineString( - flatCoordinates, offset, end, stride, extent)) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[0], extent[1])) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[0], extent[3])) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[2], extent[1])) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[2], extent[3])) { - return true; - } - return false; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. - */ -ol.geom.flat.intersectsextent.linearRings = - function(flatCoordinates, offset, ends, stride, extent) { - goog.asserts.assert(ends.length > 0, 'ends should not be an empty array'); - if (!ol.geom.flat.intersectsextent.linearRing( - flatCoordinates, offset, ends[0], stride, extent)) { - return false; - } - if (ends.length === 1) { - return true; - } - var i, ii; - for (i = 1, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.contains.linearRingContainsExtent( - flatCoordinates, ends[i - 1], ends[i], stride, extent)) { - return false; - } - } - return true; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. - */ -ol.geom.flat.intersectsextent.linearRingss = - function(flatCoordinates, offset, endss, stride, extent) { - goog.asserts.assert(endss.length > 0, 'endss should not be an empty array'); - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - if (ol.geom.flat.intersectsextent.linearRings( - flatCoordinates, offset, ends, stride, extent)) { - return true; - } - offset = ends[ends.length - 1]; - } - return false; -}; - -goog.provide('ol.geom.flat.reverse'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - */ -ol.geom.flat.reverse.coordinates = - function(flatCoordinates, offset, end, stride) { - while (offset < end - stride) { - var i; - for (i = 0; i < stride; ++i) { - var tmp = flatCoordinates[offset + i]; - flatCoordinates[offset + i] = flatCoordinates[end - stride + i]; - flatCoordinates[end - stride + i] = tmp; - } - offset += stride; - end -= stride; - } -}; - -goog.provide('ol.geom.flat.orient'); - -goog.require('ol'); -goog.require('ol.geom.flat.reverse'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {boolean} Is clockwise. - */ -ol.geom.flat.orient.linearRingIsClockwise = - function(flatCoordinates, offset, end, stride) { - // http://tinyurl.com/clockwise-method - // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp - var edge = 0; - var x1 = flatCoordinates[end - stride]; - var y1 = flatCoordinates[end - stride + 1]; - for (; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - edge += (x2 - x1) * (y2 + y1); - x1 = x2; - y1 = y2; - } - return edge > 0; -}; - - -/** - * Determines if linear rings are oriented. By default, left-hand orientation - * is tested (first ring must be clockwise, remaining rings counter-clockwise). - * To test for right-hand orientation, use the `opt_right` argument. - * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Array of end indexes. - * @param {number} stride Stride. - * @param {boolean=} opt_right Test for right-hand orientation - * (counter-clockwise exterior ring and clockwise interior rings). - * @return {boolean} Rings are correctly oriented. - */ -ol.geom.flat.orient.linearRingsAreOriented = - function(flatCoordinates, offset, ends, stride, opt_right) { - var right = opt_right !== undefined ? opt_right : false; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( - flatCoordinates, offset, end, stride); - if (i === 0) { - if ((right && isClockwise) || (!right && !isClockwise)) { - return false; - } - } else { - if ((right && !isClockwise) || (!right && isClockwise)) { - return false; - } - } - offset = end; - } - return true; -}; - - -/** - * Determines if linear rings are oriented. By default, left-hand orientation - * is tested (first ring must be clockwise, remaining rings counter-clockwise). - * To test for right-hand orientation, use the `opt_right` argument. - * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Array of array of end indexes. - * @param {number} stride Stride. - * @param {boolean=} opt_right Test for right-hand orientation - * (counter-clockwise exterior ring and clockwise interior rings). - * @return {boolean} Rings are correctly oriented. - */ -ol.geom.flat.orient.linearRingssAreOriented = - function(flatCoordinates, offset, endss, stride, opt_right) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - if (!ol.geom.flat.orient.linearRingsAreOriented( - flatCoordinates, offset, endss[i], stride, opt_right)) { - return false; - } - } - return true; -}; - - -/** - * Orient coordinates in a flat array of linear rings. By default, rings - * are oriented following the left-hand rule (clockwise for exterior and - * counter-clockwise for interior rings). To orient according to the - * right-hand rule, use the `opt_right` argument. - * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {boolean=} opt_right Follow the right-hand rule for orientation. - * @return {number} End. - */ -ol.geom.flat.orient.orientLinearRings = - function(flatCoordinates, offset, ends, stride, opt_right) { - var right = opt_right !== undefined ? opt_right : false; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( - flatCoordinates, offset, end, stride); - var reverse = i === 0 ? - (right && isClockwise) || (!right && !isClockwise) : - (right && !isClockwise) || (!right && isClockwise); - if (reverse) { - ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride); - } - offset = end; - } - return offset; -}; - - -/** - * Orient coordinates in a flat array of linear rings. By default, rings - * are oriented following the left-hand rule (clockwise for exterior and - * counter-clockwise for interior rings). To orient according to the - * right-hand rule, use the `opt_right` argument. - * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Array of array of end indexes. - * @param {number} stride Stride. - * @param {boolean=} opt_right Follow the right-hand rule for orientation. - * @return {number} End. - */ -ol.geom.flat.orient.orientLinearRingss = - function(flatCoordinates, offset, endss, stride, opt_right) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - offset = ol.geom.flat.orient.orientLinearRings( - flatCoordinates, offset, endss[i], stride, opt_right); - } - return offset; -}; - -goog.provide('ol.geom.Polygon'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.area'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.contains'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interiorpoint'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.orient'); -goog.require('ol.geom.flat.simplify'); - - - -/** - * @classdesc - * Polygon geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.Polygon = function(coordinates, opt_layout) { - - goog.base(this); - - /** - * @type {Array.<number>} - * @private - */ - this.ends_ = []; - - /** - * @private - * @type {number} - */ - this.flatInteriorPointRevision_ = -1; - - /** - * @private - * @type {ol.Coordinate} - */ - this.flatInteriorPoint_ = null; - - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.orientedRevision_ = -1; - - /** - * @private - * @type {Array.<number>} - */ - this.orientedFlatCoordinates_ = null; - - this.setCoordinates(coordinates, opt_layout); - -}; -goog.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry); - - -/** - * Append the passed linear ring to this polygon. - * @param {ol.geom.LinearRing} linearRing Linear ring. - * @api stable - */ -ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) { - goog.asserts.assert(linearRing.getLayout() == this.layout, - 'layout of linearRing should match layout'); - if (!this.flatCoordinates) { - this.flatCoordinates = linearRing.getFlatCoordinates().slice(); - } else { - goog.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates()); - } - this.ends_.push(this.flatCoordinates.length); - this.changed(); -}; - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.Polygon} Clone. - * @api stable - */ -ol.geom.Polygon.prototype.clone = function() { - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(), this.ends_.slice()); - return polygon; -}; - - -/** - * @inheritDoc - */ -ol.geom.Polygon.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta( - this.flatCoordinates, 0, this.ends_, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getsClosestPoint( - this.flatCoordinates, 0, this.ends_, this.stride, - this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); -}; - - -/** - * @inheritDoc - */ -ol.geom.Polygon.prototype.containsXY = function(x, y) { - return ol.geom.flat.contains.linearRingsContainsXY( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y); -}; - - -/** - * Return the area of the polygon on projected plane. - * @return {number} Area (on projected plane). - * @api stable - */ -ol.geom.Polygon.prototype.getArea = function() { - return ol.geom.flat.area.linearRings( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride); -}; - - -/** - * Get the coordinate array for this geometry. This array has the structure - * of a GeoJSON coordinate array for polygons. - * - * @param {boolean=} opt_right Orient coordinates according to the right-hand - * rule (counter-clockwise for exterior and clockwise for interior rings). - * If `false`, coordinates will be oriented according to the left-hand rule - * (clockwise for exterior and counter-clockwise for interior rings). - * By default, coordinate orientation will depend on how the geometry was - * constructed. - * @return {Array.<Array.<ol.Coordinate>>} Coordinates. - * @api stable - */ -ol.geom.Polygon.prototype.getCoordinates = function(opt_right) { - var flatCoordinates; - if (opt_right !== undefined) { - flatCoordinates = this.getOrientedFlatCoordinates().slice(); - ol.geom.flat.orient.orientLinearRings( - flatCoordinates, 0, this.ends_, this.stride, opt_right); - } else { - flatCoordinates = this.flatCoordinates; - } - - return ol.geom.flat.inflate.coordinatess( - flatCoordinates, 0, this.ends_, this.stride); -}; - - -/** - * @return {Array.<number>} Ends. - */ -ol.geom.Polygon.prototype.getEnds = function() { - return this.ends_; -}; - - -/** - * @return {Array.<number>} Interior point. - */ -ol.geom.Polygon.prototype.getFlatInteriorPoint = function() { - if (this.flatInteriorPointRevision_ != this.getRevision()) { - var flatCenter = ol.extent.getCenter(this.getExtent()); - this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, - flatCenter, 0); - this.flatInteriorPointRevision_ = this.getRevision(); - } - return this.flatInteriorPoint_; -}; - - -/** - * Return an interior point of the polygon. - * @return {ol.geom.Point} Interior point. - * @api stable - */ -ol.geom.Polygon.prototype.getInteriorPoint = function() { - return new ol.geom.Point(this.getFlatInteriorPoint()); -}; - - -/** - * Return the number of rings of the polygon, this includes the exterior - * ring and any interior rings. - * - * @return {number} Number of rings. - * @api - */ -ol.geom.Polygon.prototype.getLinearRingCount = function() { - return this.ends_.length; -}; - - -/** - * Return the Nth linear ring of the polygon geometry. Return `null` if the - * given index is out of range. - * The exterior linear ring is available at index `0` and the interior rings - * at index `1` and beyond. - * - * @param {number} index Index. - * @return {ol.geom.LinearRing} Linear ring. - * @api stable - */ -ol.geom.Polygon.prototype.getLinearRing = function(index) { - goog.asserts.assert(0 <= index && index < this.ends_.length, - 'index should be in between 0 and and length of this.ends_'); - if (index < 0 || this.ends_.length <= index) { - return null; - } - var linearRing = new ol.geom.LinearRing(null); - linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice( - index === 0 ? 0 : this.ends_[index - 1], this.ends_[index])); - return linearRing; -}; - - -/** - * Return the linear rings of the polygon. - * @return {Array.<ol.geom.LinearRing>} Linear rings. - * @api stable - */ -ol.geom.Polygon.prototype.getLinearRings = function() { - var layout = this.layout; - var flatCoordinates = this.flatCoordinates; - var ends = this.ends_; - var linearRings = []; - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var linearRing = new ol.geom.LinearRing(null); - linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end)); - linearRings.push(linearRing); - offset = end; - } - return linearRings; -}; - - -/** - * @return {Array.<number>} Oriented flat coordinates. - */ -ol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() { - if (this.orientedRevision_ != this.getRevision()) { - var flatCoordinates = this.flatCoordinates; - if (ol.geom.flat.orient.linearRingsAreOriented( - flatCoordinates, 0, this.ends_, this.stride)) { - this.orientedFlatCoordinates_ = flatCoordinates; - } else { - this.orientedFlatCoordinates_ = flatCoordinates.slice(); - this.orientedFlatCoordinates_.length = - ol.geom.flat.orient.orientLinearRings( - this.orientedFlatCoordinates_, 0, this.ends_, this.stride); - } - this.orientedRevision_ = this.getRevision(); - } - return this.orientedFlatCoordinates_; -}; - - -/** - * @inheritDoc - */ -ol.geom.Polygon.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - var simplifiedEnds = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes( - this.flatCoordinates, 0, this.ends_, this.stride, - Math.sqrt(squaredTolerance), - simplifiedFlatCoordinates, 0, simplifiedEnds); - var simplifiedPolygon = new ol.geom.Polygon(null); - simplifiedPolygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds); - return simplifiedPolygon; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.Polygon.prototype.getType = function() { - return ol.geom.GeometryType.POLYGON; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.Polygon.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.linearRings( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent); -}; - - -/** - * Set the coordinates of the polygon. - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_); - } else { - this.setLayout(opt_layout, coordinates, 2); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - var ends = ol.geom.flat.deflate.coordinatess( - this.flatCoordinates, 0, coordinates, this.stride, this.ends_); - this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Array.<number>} ends Ends. - */ -ol.geom.Polygon.prototype.setFlatCoordinates = - function(layout, flatCoordinates, ends) { - if (!flatCoordinates) { - goog.asserts.assert(ends && ends.length === 0, - 'ends must be an empty array'); - } else if (ends.length === 0) { - goog.asserts.assert(flatCoordinates.length === 0, - 'flatCoordinates should be an empty array'); - } else { - goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], - 'the length of flatCoordinates should be the last entry of ends'); - } - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.ends_ = ends; - this.changed(); -}; - - -/** - * Create an approximation of a circle on the surface of a sphere. - * @param {ol.Sphere} sphere The sphere. - * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees). - * @param {number} radius The great-circle distance from the center to - * the polygon vertices. - * @param {number=} opt_n Optional number of vertices for the resulting - * polygon. Default is `32`. - * @return {ol.geom.Polygon} The "circular" polygon. - * @api stable - */ -ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) { - var n = opt_n ? opt_n : 32; - /** @type {Array.<number>} */ - var flatCoordinates = []; - var i; - for (i = 0; i < n; ++i) { - goog.array.extend( - flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n)); - } - flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]); - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); - return polygon; -}; - - -/** - * Create a polygon from an extent. The layout used is `XY`. - * @param {ol.Extent} extent The extent. - * @return {ol.geom.Polygon} The polygon. - * @api - */ -ol.geom.Polygon.fromExtent = function(extent) { - var minX = extent[0]; - var minY = extent[1]; - var maxX = extent[2]; - var maxY = extent[3]; - var flatCoordinates = - [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY]; - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); - return polygon; -}; - - -/** - * Create a regular polygon from a circle. - * @param {ol.geom.Circle} circle Circle geometry. - * @param {number=} opt_sides Number of sides of the polygon. Default is 32. - * @param {number=} opt_angle Start angle for the first vertex of the polygon in - * radians. Default is 0. - * @return {ol.geom.Polygon} Polygon geometry. - * @api - */ -ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) { - var sides = opt_sides ? opt_sides : 32; - var stride = circle.getStride(); - var layout = circle.getLayout(); - var polygon = new ol.geom.Polygon(null, layout); - var flatCoordinates = goog.array.repeat(0, stride * (sides + 1)); - var ends = [flatCoordinates.length]; - polygon.setFlatCoordinates(layout, flatCoordinates, ends); - ol.geom.Polygon.makeRegular( - polygon, circle.getCenter(), circle.getRadius(), opt_angle); - return polygon; -}; - - -/** - * Modify the coordinates of a polygon to make it a regular polygon. - * @param {ol.geom.Polygon} polygon Polygon geometry. - * @param {ol.Coordinate} center Center of the regular polygon. - * @param {number} radius Radius of the regular polygon. - * @param {number=} opt_angle Start angle for the first vertex of the polygon in - * radians. Default is 0. - */ -ol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) { - var flatCoordinates = polygon.getFlatCoordinates(); - var layout = polygon.getLayout(); - var stride = polygon.getStride(); - var ends = polygon.getEnds(); - goog.asserts.assert(ends.length === 1, 'only 1 ring is supported'); - var sides = flatCoordinates.length / stride - 1; - var startAngle = opt_angle ? opt_angle : 0; - var angle, offset; - for (var i = 0; i <= sides; ++i) { - offset = i * stride; - angle = startAngle + (goog.math.modulo(i, sides) * 2 * Math.PI / sides); - flatCoordinates[offset] = center[0] + (radius * Math.cos(angle)); - flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle)); - } - polygon.setFlatCoordinates(layout, flatCoordinates, ends); -}; - -goog.provide('ol.View'); -goog.provide('ol.ViewHint'); -goog.provide('ol.ViewProperty'); - -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.CenterConstraint'); -goog.require('ol.Constraints'); -goog.require('ol.Object'); -goog.require('ol.ResolutionConstraint'); -goog.require('ol.RotationConstraint'); -goog.require('ol.RotationConstraintType'); -goog.require('ol.Size'); -goog.require('ol.coordinate'); -goog.require('ol.extent'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); - - -/** - * @enum {string} - */ -ol.ViewProperty = { - CENTER: 'center', - RESOLUTION: 'resolution', - ROTATION: 'rotation' -}; - - -/** - * @enum {number} - */ -ol.ViewHint = { - ANIMATING: 0, - INTERACTING: 1 -}; - - - -/** - * @classdesc - * An ol.View object represents a simple 2D view of the map. - * - * This is the object to act upon to change the center, resolution, - * and rotation of the map. - * - * ### The view states - * - * An `ol.View` is determined by three states: `center`, `resolution`, - * and `rotation`. Each state has a corresponding getter and setter, e.g. - * `getCenter` and `setCenter` for the `center` state. - * - * An `ol.View` has a `projection`. The projection determines the - * coordinate system of the center, and its units determine the units of the - * resolution (projection units per pixel). The default projection is - * Spherical Mercator (EPSG:3857). - * - * ### The constraints - * - * `setCenter`, `setResolution` and `setRotation` can be used to change the - * states of the view. Any value can be passed to the setters. And the value - * that is passed to a setter will effectively be the value set in the view, - * and returned by the corresponding getter. - * - * But an `ol.View` object also has a *resolution constraint*, a - * *rotation constraint* and a *center constraint*. - * - * As said above, no constraints are applied when the setters are used to set - * new states for the view. Applying constraints is done explicitly through - * the use of the `constrain*` functions (`constrainResolution` and - * `constrainRotation` and `constrainCenter`). - * - * The main users of the constraints are the interactions and the - * controls. For example, double-clicking on the map changes the view to - * the "next" resolution. And releasing the fingers after pinch-zooming - * snaps to the closest resolution (with an animation). - * - * The *resolution constraint* snaps to specific resolutions. It is - * determined by the following options: `resolutions`, `maxResolution`, - * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three - * options are ignored. See documentation for each option for more - * information. - * - * The *rotation constraint* snaps to specific angles. It is determined - * by the following options: `enableRotation` and `constrainRotation`. - * By default the rotation value is snapped to zero when approaching the - * horizontal. - * - * The *center constraint* is determined by the `extent` option. By - * default the center is not constrained at all. - * - * @constructor - * @extends {ol.Object} - * @param {olx.ViewOptions=} opt_options View options. - * @api stable - */ -ol.View = function(opt_options) { - goog.base(this); - var options = opt_options || {}; - - /** - * @private - * @type {Array.<number>} - */ - this.hints_ = [0, 0]; - - /** - * @type {Object.<string, *>} - */ - var properties = {}; - properties[ol.ViewProperty.CENTER] = options.center !== undefined ? - options.center : null; - - /** - * @private - * @const - * @type {ol.proj.Projection} - */ - this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857'); - - var resolutionConstraintInfo = ol.View.createResolutionConstraint_( - options); - - /** - * @private - * @type {number} - */ - this.maxResolution_ = resolutionConstraintInfo.maxResolution; - - /** - * @private - * @type {number} - */ - this.minResolution_ = resolutionConstraintInfo.minResolution; - - /** - * @private - * @type {number} - */ - this.minZoom_ = resolutionConstraintInfo.minZoom; - - var centerConstraint = ol.View.createCenterConstraint_(options); - var resolutionConstraint = resolutionConstraintInfo.constraint; - var rotationConstraint = ol.View.createRotationConstraint_(options); - - /** - * @private - * @type {ol.Constraints} - */ - this.constraints_ = new ol.Constraints( - centerConstraint, resolutionConstraint, rotationConstraint); - - if (options.resolution !== undefined) { - properties[ol.ViewProperty.RESOLUTION] = options.resolution; - } else if (options.zoom !== undefined) { - properties[ol.ViewProperty.RESOLUTION] = this.constrainResolution( - this.maxResolution_, options.zoom - this.minZoom_); - } - properties[ol.ViewProperty.ROTATION] = - options.rotation !== undefined ? options.rotation : 0; - this.setProperties(properties); -}; -goog.inherits(ol.View, ol.Object); - - -/** - * @param {number} rotation Target rotation. - * @param {ol.Coordinate} anchor Rotation anchor. - * @return {ol.Coordinate|undefined} Center for rotation and anchor. - */ -ol.View.prototype.calculateCenterRotate = function(rotation, anchor) { - var center; - var currentCenter = this.getCenter(); - if (currentCenter !== undefined) { - center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]]; - ol.coordinate.rotate(center, rotation - this.getRotation()); - ol.coordinate.add(center, anchor); - } - return center; -}; - - -/** - * @param {number} resolution Target resolution. - * @param {ol.Coordinate} anchor Zoom anchor. - * @return {ol.Coordinate|undefined} Center for resolution and anchor. - */ -ol.View.prototype.calculateCenterZoom = function(resolution, anchor) { - var center; - var currentCenter = this.getCenter(); - var currentResolution = this.getResolution(); - if (currentCenter !== undefined && currentResolution !== undefined) { - var x = anchor[0] - - resolution * (anchor[0] - currentCenter[0]) / currentResolution; - var y = anchor[1] - - resolution * (anchor[1] - currentCenter[1]) / currentResolution; - center = [x, y]; - } - return center; -}; - - -/** - * Get the constrained center of this view. - * @param {ol.Coordinate|undefined} center Center. - * @return {ol.Coordinate|undefined} Constrained center. - * @api - */ -ol.View.prototype.constrainCenter = function(center) { - return this.constraints_.center(center); -}; - - -/** - * Get the constrained resolution of this view. - * @param {number|undefined} resolution Resolution. - * @param {number=} opt_delta Delta. Default is `0`. - * @param {number=} opt_direction Direction. Default is `0`. - * @return {number|undefined} Constrained resolution. - * @api - */ -ol.View.prototype.constrainResolution = function( - resolution, opt_delta, opt_direction) { - var delta = opt_delta || 0; - var direction = opt_direction || 0; - return this.constraints_.resolution(resolution, delta, direction); -}; - - -/** - * Get the constrained rotation of this view. - * @param {number|undefined} rotation Rotation. - * @param {number=} opt_delta Delta. Default is `0`. - * @return {number|undefined} Constrained rotation. - * @api - */ -ol.View.prototype.constrainRotation = function(rotation, opt_delta) { - var delta = opt_delta || 0; - return this.constraints_.rotation(rotation, delta); -}; - - -/** - * Get the view center. - * @return {ol.Coordinate|undefined} The center of the view. - * @observable - * @api stable - */ -ol.View.prototype.getCenter = function() { - return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.ViewProperty.CENTER)); -}; - - -/** - * @return {Array.<number>} Hint. - */ -ol.View.prototype.getHints = function() { - return this.hints_.slice(); -}; - - -/** - * Calculate the extent for the current view state and the passed size. - * The size is the pixel dimensions of the box into which the calculated extent - * should fit. In most cases you want to get the extent of the entire map, - * that is `map.getSize()`. - * @param {ol.Size} size Box pixel size. - * @return {ol.Extent} Extent. - * @api stable - */ -ol.View.prototype.calculateExtent = function(size) { - var center = this.getCenter(); - goog.asserts.assert(center, 'The view center is not defined'); - var resolution = this.getResolution(); - goog.asserts.assert(resolution !== undefined, - 'The view resolution is not defined'); - var rotation = this.getRotation(); - goog.asserts.assert(rotation !== undefined, - 'The view rotation is not defined'); - - return ol.extent.getForViewAndSize(center, resolution, rotation, size); -}; - - -/** - * Get the view projection. - * @return {ol.proj.Projection} The projection of the view. - * @api stable - */ -ol.View.prototype.getProjection = function() { - return this.projection_; -}; - - -/** - * Get the view resolution. - * @return {number|undefined} The resolution of the view. - * @observable - * @api stable - */ -ol.View.prototype.getResolution = function() { - return /** @type {number|undefined} */ ( - this.get(ol.ViewProperty.RESOLUTION)); -}; - - -/** - * Get the resolution for a provided extent (in map units) and size (in pixels). - * @param {ol.Extent} extent Extent. - * @param {ol.Size} size Box pixel size. - * @return {number} The resolution at which the provided extent will render at - * the given size. - */ -ol.View.prototype.getResolutionForExtent = function(extent, size) { - var xResolution = ol.extent.getWidth(extent) / size[0]; - var yResolution = ol.extent.getHeight(extent) / size[1]; - return Math.max(xResolution, yResolution); -}; - - -/** - * Return a function that returns a value between 0 and 1 for a - * resolution. Exponential scaling is assumed. - * @param {number=} opt_power Power. - * @return {function(number): number} Resolution for value function. - */ -ol.View.prototype.getResolutionForValueFunction = function(opt_power) { - var power = opt_power || 2; - var maxResolution = this.maxResolution_; - var minResolution = this.minResolution_; - var max = Math.log(maxResolution / minResolution) / Math.log(power); - return ( - /** - * @param {number} value Value. - * @return {number} Resolution. - */ - function(value) { - var resolution = maxResolution / Math.pow(power, value * max); - goog.asserts.assert(resolution >= minResolution && - resolution <= maxResolution, - 'calculated resolution outside allowed bounds (%s <= %s <= %s)', - minResolution, resolution, maxResolution); - return resolution; - }); -}; - - -/** - * Get the view rotation. - * @return {number} The rotation of the view in radians. - * @observable - * @api stable - */ -ol.View.prototype.getRotation = function() { - return /** @type {number} */ (this.get(ol.ViewProperty.ROTATION)); -}; - - -/** - * Return a function that returns a resolution for a value between - * 0 and 1. Exponential scaling is assumed. - * @param {number=} opt_power Power. - * @return {function(number): number} Value for resolution function. - */ -ol.View.prototype.getValueForResolutionFunction = function(opt_power) { - var power = opt_power || 2; - var maxResolution = this.maxResolution_; - var minResolution = this.minResolution_; - var max = Math.log(maxResolution / minResolution) / Math.log(power); - return ( - /** - * @param {number} resolution Resolution. - * @return {number} Value. - */ - function(resolution) { - var value = - (Math.log(maxResolution / resolution) / Math.log(power)) / max; - goog.asserts.assert(value >= 0 && value <= 1, - 'calculated value (%s) ouside allowed range (0-1)', value); - return value; - }); -}; - - -/** - * @return {olx.ViewState} View state. - */ -ol.View.prototype.getState = function() { - goog.asserts.assert(this.isDef(), - 'the view was not defined (had no center and/or resolution)'); - var center = /** @type {ol.Coordinate} */ (this.getCenter()); - var projection = this.getProjection(); - var resolution = /** @type {number} */ (this.getResolution()); - var rotation = this.getRotation(); - return /** @type {olx.ViewState} */ ({ - // Snap center to closest pixel - center: [ - Math.round(center[0] / resolution) * resolution, - Math.round(center[1] / resolution) * resolution - ], - projection: projection !== undefined ? projection : null, - resolution: resolution, - rotation: rotation - }); -}; - - -/** - * Get the current zoom level. Return undefined if the current - * resolution is undefined or not a "constrained resolution". - * @return {number|undefined} Zoom. - * @api stable - */ -ol.View.prototype.getZoom = function() { - var offset; - var resolution = this.getResolution(); - - if (resolution !== undefined) { - var res, z = 0; - do { - res = this.constrainResolution(this.maxResolution_, z); - if (res == resolution) { - offset = z; - break; - } - ++z; - } while (res > this.minResolution_); - } - - return offset !== undefined ? this.minZoom_ + offset : offset; -}; - - -/** - * Fit the given geometry or extent based on the given map size and border. - * The size is pixel dimensions of the box to fit the extent into. - * In most cases you will want to use the map size, that is `map.getSize()`. - * Takes care of the map angle. - * @param {ol.geom.SimpleGeometry|ol.Extent} geometry Geometry. - * @param {ol.Size} size Box pixel size. - * @param {olx.view.FitOptions=} opt_options Options. - * @api - */ -ol.View.prototype.fit = function(geometry, size, opt_options) { - if (!(geometry instanceof ol.geom.SimpleGeometry)) { - goog.asserts.assert(goog.isArray(geometry), - 'invalid extent or geometry'); - goog.asserts.assert(!ol.extent.isEmpty(geometry), - 'cannot fit empty extent'); - geometry = ol.geom.Polygon.fromExtent(geometry); - } - - var options = opt_options || {}; - - var padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0]; - var constrainResolution = options.constrainResolution !== undefined ? - options.constrainResolution : true; - var nearest = options.nearest !== undefined ? options.nearest : false; - var minResolution; - if (options.minResolution !== undefined) { - minResolution = options.minResolution; - } else if (options.maxZoom !== undefined) { - minResolution = this.constrainResolution( - this.maxResolution_, options.maxZoom - this.minZoom_, 0); - } else { - minResolution = 0; - } - var coords = geometry.getFlatCoordinates(); - - // calculate rotated extent - var rotation = this.getRotation(); - goog.asserts.assert(rotation !== undefined, 'rotation was not defined'); - var cosAngle = Math.cos(-rotation); - var sinAngle = Math.sin(-rotation); - var minRotX = +Infinity; - var minRotY = +Infinity; - var maxRotX = -Infinity; - var maxRotY = -Infinity; - var stride = geometry.getStride(); - for (var i = 0, ii = coords.length; i < ii; i += stride) { - var rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle; - var rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle; - minRotX = Math.min(minRotX, rotX); - minRotY = Math.min(minRotY, rotY); - maxRotX = Math.max(maxRotX, rotX); - maxRotY = Math.max(maxRotY, rotY); - } - - // calculate resolution - var resolution = this.getResolutionForExtent( - [minRotX, minRotY, maxRotX, maxRotY], - [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]); - resolution = isNaN(resolution) ? minResolution : - Math.max(resolution, minResolution); - if (constrainResolution) { - var constrainedResolution = this.constrainResolution(resolution, 0, 0); - if (!nearest && constrainedResolution < resolution) { - constrainedResolution = this.constrainResolution( - constrainedResolution, -1, 0); - } - resolution = constrainedResolution; - } - this.setResolution(resolution); - - // calculate center - sinAngle = -sinAngle; // go back to original rotation - var centerRotX = (minRotX + maxRotX) / 2; - var centerRotY = (minRotY + maxRotY) / 2; - centerRotX += (padding[1] - padding[3]) / 2 * resolution; - centerRotY += (padding[0] - padding[2]) / 2 * resolution; - var centerX = centerRotX * cosAngle - centerRotY * sinAngle; - var centerY = centerRotY * cosAngle + centerRotX * sinAngle; - - this.setCenter([centerX, centerY]); -}; - - -/** - * Center on coordinate and view position. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.Size} size Box pixel size. - * @param {ol.Pixel} position Position on the view to center on. - * @api - */ -ol.View.prototype.centerOn = function(coordinate, size, position) { - // calculate rotated position - var rotation = this.getRotation(); - var cosAngle = Math.cos(-rotation); - var sinAngle = Math.sin(-rotation); - var rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle; - var rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle; - var resolution = this.getResolution(); - rotX += (size[0] / 2 - position[0]) * resolution; - rotY += (position[1] - size[1] / 2) * resolution; - - // go back to original angle - sinAngle = -sinAngle; // go back to original rotation - var centerX = rotX * cosAngle - rotY * sinAngle; - var centerY = rotY * cosAngle + rotX * sinAngle; - - this.setCenter([centerX, centerY]); -}; - - -/** - * @return {boolean} Is defined. - */ -ol.View.prototype.isDef = function() { - return !!this.getCenter() && this.getResolution() !== undefined; -}; - - -/** - * Rotate the view around a given coordinate. - * @param {number} rotation New rotation value for the view. - * @param {ol.Coordinate=} opt_anchor The rotation center. - * @api stable - */ -ol.View.prototype.rotate = function(rotation, opt_anchor) { - if (opt_anchor !== undefined) { - var center = this.calculateCenterRotate(rotation, opt_anchor); - this.setCenter(center); - } - this.setRotation(rotation); -}; - - -/** - * Set the center of the current view. - * @param {ol.Coordinate|undefined} center The center of the view. - * @observable - * @api stable - */ -ol.View.prototype.setCenter = function(center) { - this.set(ol.ViewProperty.CENTER, center); -}; - - -/** - * @param {ol.ViewHint} hint Hint. - * @param {number} delta Delta. - * @return {number} New value. - */ -ol.View.prototype.setHint = function(hint, delta) { - goog.asserts.assert(0 <= hint && hint < this.hints_.length, - 'illegal hint (%s), must be between 0 and %s', hint, this.hints_.length); - this.hints_[hint] += delta; - goog.asserts.assert(this.hints_[hint] >= 0, - 'Hint at %s must be positive, was %s', hint, this.hints_[hint]); - return this.hints_[hint]; -}; - - -/** - * Set the resolution for this view. - * @param {number|undefined} resolution The resolution of the view. - * @observable - * @api stable - */ -ol.View.prototype.setResolution = function(resolution) { - this.set(ol.ViewProperty.RESOLUTION, resolution); -}; - - -/** - * Set the rotation for this view. - * @param {number} rotation The rotation of the view in radians. - * @observable - * @api stable - */ -ol.View.prototype.setRotation = function(rotation) { - this.set(ol.ViewProperty.ROTATION, rotation); -}; - - -/** - * Zoom to a specific zoom level. - * @param {number} zoom Zoom level. - * @api stable - */ -ol.View.prototype.setZoom = function(zoom) { - var resolution = this.constrainResolution( - this.maxResolution_, zoom - this.minZoom_, 0); - this.setResolution(resolution); -}; - - -/** - * @param {olx.ViewOptions} options View options. - * @private - * @return {ol.CenterConstraintType} - */ -ol.View.createCenterConstraint_ = function(options) { - if (options.extent !== undefined) { - return ol.CenterConstraint.createExtent(options.extent); - } else { - return ol.CenterConstraint.none; - } -}; - - -/** - * @private - * @param {olx.ViewOptions} options View options. - * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number, - * minResolution: number}} - */ -ol.View.createResolutionConstraint_ = function(options) { - var resolutionConstraint; - var maxResolution; - var minResolution; - - // TODO: move these to be ol constants - // see https://github.com/openlayers/ol3/issues/2076 - var defaultMaxZoom = 28; - var defaultZoomFactor = 2; - - var minZoom = options.minZoom !== undefined ? - options.minZoom : ol.DEFAULT_MIN_ZOOM; - - var maxZoom = options.maxZoom !== undefined ? - options.maxZoom : defaultMaxZoom; - - var zoomFactor = options.zoomFactor !== undefined ? - options.zoomFactor : defaultZoomFactor; - - if (options.resolutions !== undefined) { - var resolutions = options.resolutions; - maxResolution = resolutions[0]; - minResolution = resolutions[resolutions.length - 1]; - resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions( - resolutions); - } else { - // calculate the default min and max resolution - var projection = ol.proj.createProjection(options.projection, 'EPSG:3857'); - var extent = projection.getExtent(); - var size = !extent ? - // use an extent that can fit the whole world if need be - 360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] / - ol.proj.METERS_PER_UNIT[projection.getUnits()] : - Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent)); - - var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow( - defaultZoomFactor, ol.DEFAULT_MIN_ZOOM); - - var defaultMinResolution = defaultMaxResolution / Math.pow( - defaultZoomFactor, defaultMaxZoom - ol.DEFAULT_MIN_ZOOM); - - // user provided maxResolution takes precedence - maxResolution = options.maxResolution; - if (maxResolution !== undefined) { - minZoom = 0; - } else { - maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom); - } - - // user provided minResolution takes precedence - minResolution = options.minResolution; - if (minResolution === undefined) { - if (options.maxZoom !== undefined) { - if (options.maxResolution !== undefined) { - minResolution = maxResolution / Math.pow(zoomFactor, maxZoom); - } else { - minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom); - } - } else { - minResolution = defaultMinResolution; - } - } - - // given discrete zoom levels, minResolution may be different than provided - maxZoom = minZoom + Math.floor( - Math.log(maxResolution / minResolution) / Math.log(zoomFactor)); - minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom); - - resolutionConstraint = ol.ResolutionConstraint.createSnapToPower( - zoomFactor, maxResolution, maxZoom - minZoom); - } - return {constraint: resolutionConstraint, maxResolution: maxResolution, - minResolution: minResolution, minZoom: minZoom}; -}; - - -/** - * @private - * @param {olx.ViewOptions} options View options. - * @return {ol.RotationConstraintType} Rotation constraint. - */ -ol.View.createRotationConstraint_ = function(options) { - var enableRotation = options.enableRotation !== undefined ? - options.enableRotation : true; - if (enableRotation) { - var constrainRotation = options.constrainRotation; - if (constrainRotation === undefined || constrainRotation === true) { - return ol.RotationConstraint.createSnapToZero(); - } else if (constrainRotation === false) { - return ol.RotationConstraint.none; - } else if (goog.isNumber(constrainRotation)) { - return ol.RotationConstraint.createSnapToN(constrainRotation); - } else { - goog.asserts.fail( - 'illegal option for constrainRotation (%s)', constrainRotation); - return ol.RotationConstraint.none; - } - } else { - return ol.RotationConstraint.disable; - } -}; -goog.exportProperty(ol.View.prototype, 'getResolutionForExtent', - ol.View.prototype.getResolutionForExtent); - - -goog.provide('ol.easing'); - - -/** - * Start slow and speed up. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api - */ -ol.easing.easeIn = function(t) { - return Math.pow(t, 3); -}; - - -/** - * Start fast and slow down. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api - */ -ol.easing.easeOut = function(t) { - return 1 - ol.easing.easeIn(1 - t); -}; - - -/** - * Start slow, speed up, and then slow down again. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api - */ -ol.easing.inAndOut = function(t) { - return 3 * t * t - 2 * t * t * t; -}; - - -/** - * Maintain a constant speed over time. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api - */ -ol.easing.linear = function(t) { - return t; -}; - - -/** - * Start slow, speed up, and at the very end slow down again. This has the - * same general behavior as {@link ol.easing.inAndOut}, but the final slowdown - * is delayed. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api - */ -ol.easing.upAndDown = function(t) { - if (t < 0.5) { - return ol.easing.inAndOut(2 * t); - } else { - return 1 - ol.easing.inAndOut(2 * (t - 0.5)); - } -}; - -goog.provide('ol.animation'); - -goog.require('ol'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.ViewHint'); -goog.require('ol.coordinate'); -goog.require('ol.easing'); - - -/** - * Generate an animated transition that will "bounce" the resolution as it - * approaches the final value. - * @param {olx.animation.BounceOptions} options Bounce options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api - */ -ol.animation.bounce = function(options) { - var resolution = options.resolution; - var start = options.start ? options.start : Date.now(); - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.upAndDown; - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = easing((frameState.time - start) / duration); - var deltaResolution = resolution - frameState.viewState.resolution; - frameState.animate = true; - frameState.viewState.resolution += delta * deltaResolution; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; - - -/** - * Generate an animated transition while updating the view center. - * @param {olx.animation.PanOptions} options Pan options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api - */ -ol.animation.pan = function(options) { - var source = options.source; - var start = options.start ? options.start : Date.now(); - var sourceX = source[0]; - var sourceY = source[1]; - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.inAndOut; - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = 1 - easing((frameState.time - start) / duration); - var deltaX = sourceX - frameState.viewState.center[0]; - var deltaY = sourceY - frameState.viewState.center[1]; - frameState.animate = true; - frameState.viewState.center[0] += delta * deltaX; - frameState.viewState.center[1] += delta * deltaY; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; - - -/** - * Generate an animated transition while updating the view rotation. - * @param {olx.animation.RotateOptions} options Rotate options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api - */ -ol.animation.rotate = function(options) { - var sourceRotation = options.rotation ? options.rotation : 0; - var start = options.start ? options.start : Date.now(); - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.inAndOut; - var anchor = options.anchor ? - options.anchor : null; - - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = 1 - easing((frameState.time - start) / duration); - var deltaRotation = - (sourceRotation - frameState.viewState.rotation) * delta; - frameState.animate = true; - frameState.viewState.rotation += deltaRotation; - if (anchor) { - var center = frameState.viewState.center; - ol.coordinate.sub(center, anchor); - ol.coordinate.rotate(center, deltaRotation); - ol.coordinate.add(center, anchor); - } - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; - - -/** - * Generate an animated transition while updating the view resolution. - * @param {olx.animation.ZoomOptions} options Zoom options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api - */ -ol.animation.zoom = function(options) { - var sourceResolution = options.resolution; - var start = options.start ? options.start : Date.now(); - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.inAndOut; - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = 1 - easing((frameState.time - start) / duration); - var deltaResolution = - sourceResolution - frameState.viewState.resolution; - frameState.animate = true; - frameState.viewState.resolution += delta * deltaResolution; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; - -goog.provide('ol.TileCoord'); -goog.provide('ol.tilecoord'); - -goog.require('goog.asserts'); -goog.require('ol.extent'); - - -/** - * An array of three numbers representing the location of a tile in a tile - * grid. The order is `z`, `x`, and `y`. `z` is the zoom level. - * @typedef {Array.<number>} ol.TileCoord - * @api - */ -ol.TileCoord; - - -/** - * @enum {number} - */ -ol.QuadKeyCharCode = { - ZERO: '0'.charCodeAt(0), - ONE: '1'.charCodeAt(0), - TWO: '2'.charCodeAt(0), - THREE: '3'.charCodeAt(0) -}; - - -/** - * @param {string} str String that follows pattern “z/x/y” where x, y and z are - * numbers. - * @return {ol.TileCoord} Tile coord. - */ -ol.tilecoord.createFromString = function(str) { - var v = str.split('/'); - goog.asserts.assert(v.length === 3, - 'must provide a string in "z/x/y" format, got "%s"', str); - return v.map(function(e) { - return parseInt(e, 10); - }); -}; - - -/** - * @param {number} z Z. - * @param {number} x X. - * @param {number} y Y. - * @param {ol.TileCoord=} opt_tileCoord Tile coordinate. - * @return {ol.TileCoord} Tile coordinate. - */ -ol.tilecoord.createOrUpdate = function(z, x, y, opt_tileCoord) { - if (opt_tileCoord !== undefined) { - opt_tileCoord[0] = z; - opt_tileCoord[1] = x; - opt_tileCoord[2] = y; - return opt_tileCoord; - } else { - return [z, x, y]; - } -}; - - -/** - * @param {number} z Z. - * @param {number} x X. - * @param {number} y Y. - * @return {string} Key. - */ -ol.tilecoord.getKeyZXY = function(z, x, y) { - return z + '/' + x + '/' + y; -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coord. - * @return {number} Hash. - */ -ol.tilecoord.hash = function(tileCoord) { - return (tileCoord[1] << tileCoord[0]) + tileCoord[2]; -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coord. - * @return {string} Quad key. - */ -ol.tilecoord.quadKey = function(tileCoord) { - var z = tileCoord[0]; - var digits = new Array(z); - var mask = 1 << (z - 1); - var i, charCode; - for (i = 0; i < z; ++i) { - charCode = ol.QuadKeyCharCode.ZERO; - if (tileCoord[1] & mask) { - charCode += 1; - } - if (tileCoord[2] & mask) { - charCode += 2; - } - digits[i] = String.fromCharCode(charCode); - mask >>= 1; - } - return digits.join(''); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coord. - * @return {string} String. - */ -ol.tilecoord.toString = function(tileCoord) { - return ol.tilecoord.getKeyZXY(tileCoord[0], tileCoord[1], tileCoord[2]); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.TileCoord} Tile coordinate. - */ -ol.tilecoord.wrapX = function(tileCoord, tileGrid, projection) { - var z = tileCoord[0]; - var center = tileGrid.getTileCoordCenter(tileCoord); - var projectionExtent = ol.tilegrid.extentFromProjection(projection); - if (!ol.extent.containsCoordinate(projectionExtent, center)) { - var worldWidth = ol.extent.getWidth(projectionExtent); - var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth); - center[0] += worldWidth * worldsAway; - return tileGrid.getTileCoordForCoordAndZ(center, z); - } else { - return tileCoord; - } -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {boolean} Tile coordinate is within extent and zoom level range. - */ -ol.tilecoord.withinExtentAndZ = function(tileCoord, tileGrid) { - var z = tileCoord[0]; - var x = tileCoord[1]; - var y = tileCoord[2]; - - if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) { - return false; - } - var extent = tileGrid.getExtent(); - var tileRange; - if (!extent) { - tileRange = tileGrid.getFullTileRange(z); - } else { - tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - } - if (!tileRange) { - return true; - } else { - return tileRange.containsXY(x, y); - } -}; - -goog.provide('ol.TileRange'); - -goog.require('goog.asserts'); -goog.require('ol.Size'); -goog.require('ol.TileCoord'); - - - -/** - * A representation of a contiguous block of tiles. A tile range is specified - * by its min/max tile coordinates and is inclusive of coordinates. - * - * @constructor - * @param {number} minX Minimum X. - * @param {number} maxX Maximum X. - * @param {number} minY Minimum Y. - * @param {number} maxY Maximum Y. - * @struct - */ -ol.TileRange = function(minX, maxX, minY, maxY) { - - /** - * @type {number} - */ - this.minX = minX; - - /** - * @type {number} - */ - this.maxX = maxX; - - /** - * @type {number} - */ - this.minY = minY; - - /** - * @type {number} - */ - this.maxY = maxY; - -}; - - -/** - * @param {...ol.TileCoord} var_args Tile coordinates. - * @return {!ol.TileRange} Bounding tile box. - */ -ol.TileRange.boundingTileRange = function(var_args) { - var tileCoord0 = /** @type {ol.TileCoord} */ (arguments[0]); - var tileCoord0Z = tileCoord0[0]; - var tileCoord0X = tileCoord0[1]; - var tileCoord0Y = tileCoord0[2]; - var tileRange = new ol.TileRange(tileCoord0X, tileCoord0X, - tileCoord0Y, tileCoord0Y); - var i, ii, tileCoord, tileCoordX, tileCoordY, tileCoordZ; - for (i = 1, ii = arguments.length; i < ii; ++i) { - tileCoord = /** @type {ol.TileCoord} */ (arguments[i]); - tileCoordZ = tileCoord[0]; - tileCoordX = tileCoord[1]; - tileCoordY = tileCoord[2]; - goog.asserts.assert(tileCoordZ == tileCoord0Z, - 'passed tilecoords all have the same Z-value'); - tileRange.minX = Math.min(tileRange.minX, tileCoordX); - tileRange.maxX = Math.max(tileRange.maxX, tileCoordX); - tileRange.minY = Math.min(tileRange.minY, tileCoordY); - tileRange.maxY = Math.max(tileRange.maxY, tileCoordY); - } - return tileRange; -}; - - -/** - * @param {number} minX Minimum X. - * @param {number} maxX Maximum X. - * @param {number} minY Minimum Y. - * @param {number} maxY Maximum Y. - * @param {ol.TileRange|undefined} tileRange TileRange. - * @return {ol.TileRange} Tile range. - */ -ol.TileRange.createOrUpdate = function(minX, maxX, minY, maxY, tileRange) { - if (tileRange !== undefined) { - tileRange.minX = minX; - tileRange.maxX = maxX; - tileRange.minY = minY; - tileRange.maxY = maxY; - return tileRange; - } else { - return new ol.TileRange(minX, maxX, minY, maxY); - } -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @return {boolean} Contains tile coordinate. - */ -ol.TileRange.prototype.contains = function(tileCoord) { - return this.containsXY(tileCoord[1], tileCoord[2]); -}; - - -/** - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} Contains. - */ -ol.TileRange.prototype.containsTileRange = function(tileRange) { - return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX && - this.minY <= tileRange.minY && tileRange.maxY <= this.maxY; -}; - - -/** - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @return {boolean} Contains coordinate. - */ -ol.TileRange.prototype.containsXY = function(x, y) { - return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY; -}; - - -/** - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} Equals. - */ -ol.TileRange.prototype.equals = function(tileRange) { - return this.minX == tileRange.minX && this.minY == tileRange.minY && - this.maxX == tileRange.maxX && this.maxY == tileRange.maxY; -}; - - -/** - * @param {ol.TileRange} tileRange Tile range. - */ -ol.TileRange.prototype.extend = function(tileRange) { - if (tileRange.minX < this.minX) { - this.minX = tileRange.minX; - } - if (tileRange.maxX > this.maxX) { - this.maxX = tileRange.maxX; - } - if (tileRange.minY < this.minY) { - this.minY = tileRange.minY; - } - if (tileRange.maxY > this.maxY) { - this.maxY = tileRange.maxY; - } -}; - - -/** - * @return {number} Height. - */ -ol.TileRange.prototype.getHeight = function() { - return this.maxY - this.minY + 1; -}; - - -/** - * @return {ol.Size} Size. - */ -ol.TileRange.prototype.getSize = function() { - return [this.getWidth(), this.getHeight()]; -}; - - -/** - * @return {number} Width. - */ -ol.TileRange.prototype.getWidth = function() { - return this.maxX - this.minX + 1; -}; - - -/** - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} Intersects. - */ -ol.TileRange.prototype.intersects = function(tileRange) { - return this.minX <= tileRange.maxX && - this.maxX >= tileRange.minX && - this.minY <= tileRange.maxY && - this.maxY >= tileRange.minY; -}; -/** - * @return {number} Min X - */ -ol.TileRange.prototype.getMinX = function() { - return this.minX; -} -goog.exportProperty(ol.TileRange.prototype, 'getMinX', - ol.TileRange.prototype.getMinX); - - -/** - * @return {number} Max X - */ -ol.TileRange.prototype.getMaxX = function() { - return this.maxX; -} -goog.exportProperty(ol.TileRange.prototype, 'getMaxX', - ol.TileRange.prototype.getMaxX); - - -/** - * @return {number} Min Y - */ -ol.TileRange.prototype.getMinY = function() { - return this.minY; -} -goog.exportProperty(ol.TileRange.prototype, 'getMinY', - ol.TileRange.prototype.getMinY); - - -/** - * @return {number} Max Y - */ -ol.TileRange.prototype.getMaxY = function() { - return this.maxY; -} -goog.exportProperty(ol.TileRange.prototype, 'getMaxY', - ol.TileRange.prototype.getMaxY); - - -goog.provide('ol.Attribution'); - -goog.require('goog.math'); -goog.require('ol.TileRange'); - - - -/** - * @classdesc - * An attribution for a layer source. - * - * Example: - * - * source: new ol.source.OSM({ - * attributions: [ - * new ol.Attribution({ - * html: 'All maps © ' + - * '<a href="http://www.opencyclemap.org/">OpenCycleMap</a>' - * }), - * ol.source.OSM.ATTRIBUTION - * ], - * .. - * - * @constructor - * @param {olx.AttributionOptions} options Attribution options. - * @struct - * @api stable - */ -ol.Attribution = function(options) { - - /** - * @private - * @type {string} - */ - this.html_ = options.html; - - /** - * @private - * @type {Object.<string, Array.<ol.TileRange>>} - */ - this.tileRanges_ = options.tileRanges ? options.tileRanges : null; - -}; - - -/** - * Get the attribution markup. - * @return {string} The attribution HTML. - * @api stable - */ -ol.Attribution.prototype.getHTML = function() { - return this.html_; -}; - - -/** - * @param {Object.<string, ol.TileRange>} tileRanges Tile ranges. - * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {!ol.proj.Projection} projection Projection. - * @return {boolean} Intersects any tile range. - */ -ol.Attribution.prototype.intersectsAnyTileRange = - function(tileRanges, tileGrid, projection) { - if (!this.tileRanges_) { - return true; - } - var i, ii, tileRange, zKey; - for (zKey in tileRanges) { - if (!(zKey in this.tileRanges_)) { - continue; - } - tileRange = tileRanges[zKey]; - var testTileRange; - for (i = 0, ii = this.tileRanges_[zKey].length; i < ii; ++i) { - testTileRange = this.tileRanges_[zKey][i]; - if (testTileRange.intersects(tileRange)) { - return true; - } - var extentTileRange = tileGrid.getTileRangeForExtentAndZ( - projection.getExtent(), parseInt(zKey, 10)); - var width = extentTileRange.getWidth(); - if (tileRange.minX < extentTileRange.minX || - tileRange.maxX > extentTileRange.maxX) { - if (testTileRange.intersects(new ol.TileRange( - goog.math.modulo(tileRange.minX, width), - goog.math.modulo(tileRange.maxX, width), - tileRange.minY, tileRange.maxY))) { - return true; - } - if (tileRange.getWidth() > width && - testTileRange.intersects(extentTileRange)) { - return true; - } - } - } - } - return false; -}; - -goog.provide('ol.CanvasFunctionType'); - - -/** - * A function returning the canvas element (`{HTMLCanvasElement}`) - * used by the source as an image. The arguments passed to the function are: - * {@link ol.Extent} the image extent, `{number}` the image resolution, - * `{number}` the device pixel ratio, {@link ol.Size} the image size, and - * {@link ol.proj.Projection} the image projection. The canvas returned by - * this function is cached by the source. The this keyword inside the function - * references the {@link ol.source.ImageCanvas}. - * - * @typedef {function(this:ol.source.ImageCanvas, ol.Extent, number, - * number, ol.Size, ol.proj.Projection): HTMLCanvasElement} - * @api - */ -ol.CanvasFunctionType; - -/** - * An implementation of Google Maps' MVCArray. - * @see https://developers.google.com/maps/documentation/javascript/reference - */ - -goog.provide('ol.Collection'); -goog.provide('ol.CollectionEvent'); -goog.provide('ol.CollectionEventType'); - -goog.require('goog.array'); -goog.require('goog.events.Event'); -goog.require('ol.Object'); - - -/** - * @enum {string} - */ -ol.CollectionEventType = { - /** - * Triggered when an item is added to the collection. - * @event ol.CollectionEvent#add - * @api stable - */ - ADD: 'add', - /** - * Triggered when an item is removed from the collection. - * @event ol.CollectionEvent#remove - * @api stable - */ - REMOVE: 'remove' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.Collection} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.CollectionEvent} - * @param {ol.CollectionEventType} type Type. - * @param {*=} opt_element Element. - * @param {Object=} opt_target Target. - */ -ol.CollectionEvent = function(type, opt_element, opt_target) { - - goog.base(this, type, opt_target); - - /** - * The element that is added to or removed from the collection. - * @type {*} - * @api stable - */ - this.element = opt_element; - -}; -goog.inherits(ol.CollectionEvent, goog.events.Event); - - -/** - * @enum {string} - */ -ol.CollectionProperty = { - LENGTH: 'length' -}; - - - -/** - * @classdesc - * An expanded version of standard JS Array, adding convenience methods for - * manipulation. Add and remove changes to the Collection trigger a Collection - * event. Note that this does not cover changes to the objects _within_ the - * Collection; they trigger events on the appropriate object, not on the - * Collection as a whole. - * - * @constructor - * @extends {ol.Object} - * @fires ol.CollectionEvent - * @param {!Array.<T>=} opt_array Array. - * @template T - * @api stable - */ -ol.Collection = function(opt_array) { - - goog.base(this); - - /** - * @private - * @type {!Array.<T>} - */ - this.array_ = opt_array ? opt_array : []; - - this.updateLength_(); - -}; -goog.inherits(ol.Collection, ol.Object); - - -/** - * Remove all elements from the collection. - * @api stable - */ -ol.Collection.prototype.clear = function() { - while (this.getLength() > 0) { - this.pop(); - } -}; - - -/** - * Add elements to the collection. This pushes each item in the provided array - * to the end of the collection. - * @param {!Array.<T>} arr Array. - * @return {ol.Collection.<T>} This collection. - * @api stable - */ -ol.Collection.prototype.extend = function(arr) { - var i, ii; - for (i = 0, ii = arr.length; i < ii; ++i) { - this.push(arr[i]); - } - return this; -}; - - -/** - * Iterate over each element, calling the provided callback. - * @param {function(this: S, T, number, Array.<T>): *} f The function to call - * for every element. This function takes 3 arguments (the element, the - * index and the array). The return value is ignored. - * @param {S=} opt_this The object to use as `this` in `f`. - * @template S - * @api stable - */ -ol.Collection.prototype.forEach = function(f, opt_this) { - this.array_.forEach(f, opt_this); -}; - - -/** - * Get a reference to the underlying Array object. Warning: if the array - * is mutated, no events will be dispatched by the collection, and the - * collection's "length" property won't be in sync with the actual length - * of the array. - * @return {!Array.<T>} Array. - * @api stable - */ -ol.Collection.prototype.getArray = function() { - return this.array_; -}; - - -/** - * Get the element at the provided index. - * @param {number} index Index. - * @return {T} Element. - * @api stable - */ -ol.Collection.prototype.item = function(index) { - return this.array_[index]; -}; - - -/** - * Get the length of this collection. - * @return {number} The length of the array. - * @observable - * @api stable - */ -ol.Collection.prototype.getLength = function() { - return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH)); -}; - - -/** - * Insert an element at the provided index. - * @param {number} index Index. - * @param {T} elem Element. - * @api stable - */ -ol.Collection.prototype.insertAt = function(index, elem) { - goog.array.insertAt(this.array_, elem, index); - this.updateLength_(); - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); -}; - - -/** - * Remove the last element of the collection and return it. - * Return `undefined` if the collection is empty. - * @return {T|undefined} Element. - * @api stable - */ -ol.Collection.prototype.pop = function() { - return this.removeAt(this.getLength() - 1); -}; - - -/** - * Insert the provided element at the end of the collection. - * @param {T} elem Element. - * @return {number} Length. - * @api stable - */ -ol.Collection.prototype.push = function(elem) { - var n = this.array_.length; - this.insertAt(n, elem); - return n; -}; - - -/** - * Remove the first occurrence of an element from the collection. - * @param {T} elem Element. - * @return {T|undefined} The removed element or undefined if none found. - * @api stable - */ -ol.Collection.prototype.remove = function(elem) { - var arr = this.array_; - var i, ii; - for (i = 0, ii = arr.length; i < ii; ++i) { - if (arr[i] === elem) { - return this.removeAt(i); - } - } - return undefined; -}; - - -/** - * Remove the element at the provided index and return it. - * Return `undefined` if the collection does not contain this index. - * @param {number} index Index. - * @return {T|undefined} Value. - * @api stable - */ -ol.Collection.prototype.removeAt = function(index) { - var prev = this.array_[index]; - goog.array.removeAt(this.array_, index); - this.updateLength_(); - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); - return prev; -}; - - -/** - * Set the element at the provided index. - * @param {number} index Index. - * @param {T} elem Element. - * @api stable - */ -ol.Collection.prototype.setAt = function(index, elem) { - var n = this.getLength(); - if (index < n) { - var prev = this.array_[index]; - this.array_[index] = elem; - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); - } else { - var j; - for (j = n; j < index; ++j) { - this.insertAt(j, undefined); - } - this.insertAt(index, elem); - } -}; - - -/** - * @private - */ -ol.Collection.prototype.updateLength_ = function() { - this.set(ol.CollectionProperty.LENGTH, this.array_.length); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Names of standard colors with their associated hex values. - */ - -goog.provide('goog.color.names'); - - -/** - * A map that contains a lot of colors that are recognised by various browsers. - * This list is way larger than the minimal one dictated by W3C. - * The keys of this map are the lowercase "readable" names of the colors, while - * the values are the "hex" values. - * - * @type {!Object<string, string>} - */ -goog.color.names = { - 'aliceblue': '#f0f8ff', - 'antiquewhite': '#faebd7', - 'aqua': '#00ffff', - 'aquamarine': '#7fffd4', - 'azure': '#f0ffff', - 'beige': '#f5f5dc', - 'bisque': '#ffe4c4', - 'black': '#000000', - 'blanchedalmond': '#ffebcd', - 'blue': '#0000ff', - 'blueviolet': '#8a2be2', - 'brown': '#a52a2a', - 'burlywood': '#deb887', - 'cadetblue': '#5f9ea0', - 'chartreuse': '#7fff00', - 'chocolate': '#d2691e', - 'coral': '#ff7f50', - 'cornflowerblue': '#6495ed', - 'cornsilk': '#fff8dc', - 'crimson': '#dc143c', - 'cyan': '#00ffff', - 'darkblue': '#00008b', - 'darkcyan': '#008b8b', - 'darkgoldenrod': '#b8860b', - 'darkgray': '#a9a9a9', - 'darkgreen': '#006400', - 'darkgrey': '#a9a9a9', - 'darkkhaki': '#bdb76b', - 'darkmagenta': '#8b008b', - 'darkolivegreen': '#556b2f', - 'darkorange': '#ff8c00', - 'darkorchid': '#9932cc', - 'darkred': '#8b0000', - 'darksalmon': '#e9967a', - 'darkseagreen': '#8fbc8f', - 'darkslateblue': '#483d8b', - 'darkslategray': '#2f4f4f', - 'darkslategrey': '#2f4f4f', - 'darkturquoise': '#00ced1', - 'darkviolet': '#9400d3', - 'deeppink': '#ff1493', - 'deepskyblue': '#00bfff', - 'dimgray': '#696969', - 'dimgrey': '#696969', - 'dodgerblue': '#1e90ff', - 'firebrick': '#b22222', - 'floralwhite': '#fffaf0', - 'forestgreen': '#228b22', - 'fuchsia': '#ff00ff', - 'gainsboro': '#dcdcdc', - 'ghostwhite': '#f8f8ff', - 'gold': '#ffd700', - 'goldenrod': '#daa520', - 'gray': '#808080', - 'green': '#008000', - 'greenyellow': '#adff2f', - 'grey': '#808080', - 'honeydew': '#f0fff0', - 'hotpink': '#ff69b4', - 'indianred': '#cd5c5c', - 'indigo': '#4b0082', - 'ivory': '#fffff0', - 'khaki': '#f0e68c', - 'lavender': '#e6e6fa', - 'lavenderblush': '#fff0f5', - 'lawngreen': '#7cfc00', - 'lemonchiffon': '#fffacd', - 'lightblue': '#add8e6', - 'lightcoral': '#f08080', - 'lightcyan': '#e0ffff', - 'lightgoldenrodyellow': '#fafad2', - 'lightgray': '#d3d3d3', - 'lightgreen': '#90ee90', - 'lightgrey': '#d3d3d3', - 'lightpink': '#ffb6c1', - 'lightsalmon': '#ffa07a', - 'lightseagreen': '#20b2aa', - 'lightskyblue': '#87cefa', - 'lightslategray': '#778899', - 'lightslategrey': '#778899', - 'lightsteelblue': '#b0c4de', - 'lightyellow': '#ffffe0', - 'lime': '#00ff00', - 'limegreen': '#32cd32', - 'linen': '#faf0e6', - 'magenta': '#ff00ff', - 'maroon': '#800000', - 'mediumaquamarine': '#66cdaa', - 'mediumblue': '#0000cd', - 'mediumorchid': '#ba55d3', - 'mediumpurple': '#9370db', - 'mediumseagreen': '#3cb371', - 'mediumslateblue': '#7b68ee', - 'mediumspringgreen': '#00fa9a', - 'mediumturquoise': '#48d1cc', - 'mediumvioletred': '#c71585', - 'midnightblue': '#191970', - 'mintcream': '#f5fffa', - 'mistyrose': '#ffe4e1', - 'moccasin': '#ffe4b5', - 'navajowhite': '#ffdead', - 'navy': '#000080', - 'oldlace': '#fdf5e6', - 'olive': '#808000', - 'olivedrab': '#6b8e23', - 'orange': '#ffa500', - 'orangered': '#ff4500', - 'orchid': '#da70d6', - 'palegoldenrod': '#eee8aa', - 'palegreen': '#98fb98', - 'paleturquoise': '#afeeee', - 'palevioletred': '#db7093', - 'papayawhip': '#ffefd5', - 'peachpuff': '#ffdab9', - 'peru': '#cd853f', - 'pink': '#ffc0cb', - 'plum': '#dda0dd', - 'powderblue': '#b0e0e6', - 'purple': '#800080', - 'red': '#ff0000', - 'rosybrown': '#bc8f8f', - 'royalblue': '#4169e1', - 'saddlebrown': '#8b4513', - 'salmon': '#fa8072', - 'sandybrown': '#f4a460', - 'seagreen': '#2e8b57', - 'seashell': '#fff5ee', - 'sienna': '#a0522d', - 'silver': '#c0c0c0', - 'skyblue': '#87ceeb', - 'slateblue': '#6a5acd', - 'slategray': '#708090', - 'slategrey': '#708090', - 'snow': '#fffafa', - 'springgreen': '#00ff7f', - 'steelblue': '#4682b4', - 'tan': '#d2b48c', - 'teal': '#008080', - 'thistle': '#d8bfd8', - 'tomato': '#ff6347', - 'turquoise': '#40e0d0', - 'violet': '#ee82ee', - 'wheat': '#f5deb3', - 'white': '#ffffff', - 'whitesmoke': '#f5f5f5', - 'yellow': '#ffff00', - 'yellowgreen': '#9acd32' -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities related to color and color conversion. - */ - -goog.provide('goog.color'); -goog.provide('goog.color.Hsl'); -goog.provide('goog.color.Hsv'); -goog.provide('goog.color.Rgb'); - -goog.require('goog.color.names'); -goog.require('goog.math'); - - -/** - * RGB color representation. An array containing three elements [r, g, b], - * each an integer in [0, 255], representing the red, green, and blue components - * of the color respectively. - * @typedef {Array<number>} - */ -goog.color.Rgb; - - -/** - * HSV color representation. An array containing three elements [h, s, v]: - * h (hue) must be an integer in [0, 360], cyclic. - * s (saturation) must be a number in [0, 1]. - * v (value/brightness) must be an integer in [0, 255]. - * @typedef {Array<number>} - */ -goog.color.Hsv; - - -/** - * HSL color representation. An array containing three elements [h, s, l]: - * h (hue) must be an integer in [0, 360], cyclic. - * s (saturation) must be a number in [0, 1]. - * l (lightness) must be a number in [0, 1]. - * @typedef {Array<number>} - */ -goog.color.Hsl; - - -/** - * Parses a color out of a string. - * @param {string} str Color in some format. - * @return {{hex: string, type: string}} 'hex' is a string containing a hex - * representation of the color, 'type' is a string containing the type - * of color format passed in ('hex', 'rgb', 'named'). - */ -goog.color.parse = function(str) { - var result = {}; - str = String(str); - - var maybeHex = goog.color.prependHashIfNecessaryHelper(str); - if (goog.color.isValidHexColor_(maybeHex)) { - result.hex = goog.color.normalizeHex(maybeHex); - result.type = 'hex'; - return result; - } else { - var rgb = goog.color.isValidRgbColor_(str); - if (rgb.length) { - result.hex = goog.color.rgbArrayToHex(rgb); - result.type = 'rgb'; - return result; - } else if (goog.color.names) { - var hex = goog.color.names[str.toLowerCase()]; - if (hex) { - result.hex = hex; - result.type = 'named'; - return result; - } - } - } - throw Error(str + ' is not a valid color string'); -}; - - -/** - * Determines if the given string can be parsed as a color. - * {@see goog.color.parse}. - * @param {string} str Potential color string. - * @return {boolean} True if str is in a format that can be parsed to a color. - */ -goog.color.isValidColor = function(str) { - var maybeHex = goog.color.prependHashIfNecessaryHelper(str); - return !!(goog.color.isValidHexColor_(maybeHex) || - goog.color.isValidRgbColor_(str).length || - goog.color.names && goog.color.names[str.toLowerCase()]); -}; - - -/** - * Parses red, green, blue components out of a valid rgb color string. - * Throws Error if the color string is invalid. - * @param {string} str RGB representation of a color. - * {@see goog.color.isValidRgbColor_}. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.parseRgb = function(str) { - var rgb = goog.color.isValidRgbColor_(str); - if (!rgb.length) { - throw Error(str + ' is not a valid RGB color'); - } - return rgb; -}; - - -/** - * Converts a hex representation of a color to RGB. - * @param {string} hexColor Color to convert. - * @return {string} string of the form 'rgb(R,G,B)' which can be used in - * styles. - */ -goog.color.hexToRgbStyle = function(hexColor) { - return goog.color.rgbStyle_(goog.color.hexToRgb(hexColor)); -}; - - -/** - * Regular expression for extracting the digits in a hex color triplet. - * @type {RegExp} - * @private - */ -goog.color.hexTripletRe_ = /#(.)(.)(.)/; - - -/** - * Normalize an hex representation of a color - * @param {string} hexColor an hex color string. - * @return {string} hex color in the format '#rrggbb' with all lowercase - * literals. - */ -goog.color.normalizeHex = function(hexColor) { - if (!goog.color.isValidHexColor_(hexColor)) { - throw Error("'" + hexColor + "' is not a valid hex color"); - } - if (hexColor.length == 4) { // of the form #RGB - hexColor = hexColor.replace(goog.color.hexTripletRe_, '#$1$1$2$2$3$3'); - } - return hexColor.toLowerCase(); -}; - - -/** - * Converts a hex representation of a color to RGB. - * @param {string} hexColor Color to convert. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.hexToRgb = function(hexColor) { - hexColor = goog.color.normalizeHex(hexColor); - var r = parseInt(hexColor.substr(1, 2), 16); - var g = parseInt(hexColor.substr(3, 2), 16); - var b = parseInt(hexColor.substr(5, 2), 16); - - return [r, g, b]; -}; - - -/** - * Converts a color from RGB to hex representation. - * @param {number} r Amount of red, int between 0 and 255. - * @param {number} g Amount of green, int between 0 and 255. - * @param {number} b Amount of blue, int between 0 and 255. - * @return {string} hex representation of the color. - */ -goog.color.rgbToHex = function(r, g, b) { - r = Number(r); - g = Number(g); - b = Number(b); - if (isNaN(r) || r < 0 || r > 255 || - isNaN(g) || g < 0 || g > 255 || - isNaN(b) || b < 0 || b > 255) { - throw Error('"(' + r + ',' + g + ',' + b + '") is not a valid RGB color'); - } - var hexR = goog.color.prependZeroIfNecessaryHelper(r.toString(16)); - var hexG = goog.color.prependZeroIfNecessaryHelper(g.toString(16)); - var hexB = goog.color.prependZeroIfNecessaryHelper(b.toString(16)); - return '#' + hexR + hexG + hexB; -}; - - -/** - * Converts a color from RGB to hex representation. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {string} hex representation of the color. - */ -goog.color.rgbArrayToHex = function(rgb) { - return goog.color.rgbToHex(rgb[0], rgb[1], rgb[2]); -}; - - -/** - * Converts a color from RGB color space to HSL color space. - * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}. - * @param {number} r Value of red, in [0, 255]. - * @param {number} g Value of green, in [0, 255]. - * @param {number} b Value of blue, in [0, 255]. - * @return {!goog.color.Hsl} hsl representation of the color. - */ -goog.color.rgbToHsl = function(r, g, b) { - // First must normalize r, g, b to be between 0 and 1. - var normR = r / 255; - var normG = g / 255; - var normB = b / 255; - var max = Math.max(normR, normG, normB); - var min = Math.min(normR, normG, normB); - var h = 0; - var s = 0; - - // Luminosity is the average of the max and min rgb color intensities. - var l = 0.5 * (max + min); - - // The hue and saturation are dependent on which color intensity is the max. - // If max and min are equal, the color is gray and h and s should be 0. - if (max != min) { - if (max == normR) { - h = 60 * (normG - normB) / (max - min); - } else if (max == normG) { - h = 60 * (normB - normR) / (max - min) + 120; - } else if (max == normB) { - h = 60 * (normR - normG) / (max - min) + 240; - } - - if (0 < l && l <= 0.5) { - s = (max - min) / (2 * l); - } else { - s = (max - min) / (2 - 2 * l); - } - } - - // Make sure the hue falls between 0 and 360. - return [Math.round(h + 360) % 360, s, l]; -}; - - -/** - * Converts a color from RGB color space to HSL color space. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {!goog.color.Hsl} hsl representation of the color. - */ -goog.color.rgbArrayToHsl = function(rgb) { - return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]); -}; - - -/** - * Helper for hslToRgb. - * @param {number} v1 Helper variable 1. - * @param {number} v2 Helper variable 2. - * @param {number} vH Helper variable 3. - * @return {number} Appropriate RGB value, given the above. - * @private - */ -goog.color.hueToRgb_ = function(v1, v2, vH) { - if (vH < 0) { - vH += 1; - } else if (vH > 1) { - vH -= 1; - } - if ((6 * vH) < 1) { - return (v1 + (v2 - v1) * 6 * vH); - } else if (2 * vH < 1) { - return v2; - } else if (3 * vH < 2) { - return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6); - } - return v1; -}; - - -/** - * Converts a color from HSL color space to RGB color space. - * Modified from {@link http://www.easyrgb.com/math.html} - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} l Luminosity, in [0, 1]. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.hslToRgb = function(h, s, l) { - var r = 0; - var g = 0; - var b = 0; - var normH = h / 360; // normalize h to fall in [0, 1] - - if (s == 0) { - r = g = b = l * 255; - } else { - var temp1 = 0; - var temp2 = 0; - if (l < 0.5) { - temp2 = l * (1 + s); - } else { - temp2 = l + s - (s * l); - } - temp1 = 2 * l - temp2; - r = 255 * goog.color.hueToRgb_(temp1, temp2, normH + (1 / 3)); - g = 255 * goog.color.hueToRgb_(temp1, temp2, normH); - b = 255 * goog.color.hueToRgb_(temp1, temp2, normH - (1 / 3)); - } - - return [Math.round(r), Math.round(g), Math.round(b)]; -}; - - -/** - * Converts a color from HSL color space to RGB color space. - * @param {goog.color.Hsl} hsl hsl representation of the color. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.hslArrayToRgb = function(hsl) { - return goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]); -}; - - -/** - * Helper for isValidHexColor_. - * @type {RegExp} - * @private - */ -goog.color.validHexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; - - -/** - * Checks if a string is a valid hex color. We expect strings of the format - * #RRGGBB (ex: #1b3d5f) or #RGB (ex: #3CA == #33CCAA). - * @param {string} str String to check. - * @return {boolean} Whether the string is a valid hex color. - * @private - */ -goog.color.isValidHexColor_ = function(str) { - return goog.color.validHexColorRe_.test(str); -}; - - -/** - * Helper for isNormalizedHexColor_. - * @type {RegExp} - * @private - */ -goog.color.normalizedHexColorRe_ = /^#[0-9a-f]{6}$/; - - -/** - * Checks if a string is a normalized hex color. - * We expect strings of the format #RRGGBB (ex: #1b3d5f) - * using only lowercase letters. - * @param {string} str String to check. - * @return {boolean} Whether the string is a normalized hex color. - * @private - */ -goog.color.isNormalizedHexColor_ = function(str) { - return goog.color.normalizedHexColorRe_.test(str); -}; - - -/** - * Regular expression for matching and capturing RGB style strings. Helper for - * isValidRgbColor_. - * @type {RegExp} - * @private - */ -goog.color.rgbColorRe_ = - /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; - - -/** - * Checks if a string is a valid rgb color. We expect strings of the format - * '(r, g, b)', or 'rgb(r, g, b)', where each color component is an int in - * [0, 255]. - * @param {string} str String to check. - * @return {!goog.color.Rgb} the rgb representation of the color if it is - * a valid color, or the empty array otherwise. - * @private - */ -goog.color.isValidRgbColor_ = function(str) { - // Each component is separate (rather than using a repeater) so we can - // capture the match. Also, we explicitly set each component to be either 0, - // or start with a non-zero, to prevent octal numbers from slipping through. - var regExpResultArray = str.match(goog.color.rgbColorRe_); - if (regExpResultArray) { - var r = Number(regExpResultArray[1]); - var g = Number(regExpResultArray[2]); - var b = Number(regExpResultArray[3]); - if (r >= 0 && r <= 255 && - g >= 0 && g <= 255 && - b >= 0 && b <= 255) { - return [r, g, b]; - } - } - return []; -}; - - -/** - * Takes a hex value and prepends a zero if it's a single digit. - * Small helper method for use by goog.color and friends. - * @param {string} hex Hex value to prepend if single digit. - * @return {string} hex value prepended with zero if it was single digit, - * otherwise the same value that was passed in. - */ -goog.color.prependZeroIfNecessaryHelper = function(hex) { - return hex.length == 1 ? '0' + hex : hex; -}; - - -/** - * Takes a string a prepends a '#' sign if one doesn't exist. - * Small helper method for use by goog.color and friends. - * @param {string} str String to check. - * @return {string} The value passed in, prepended with a '#' if it didn't - * already have one. - */ -goog.color.prependHashIfNecessaryHelper = function(str) { - return str.charAt(0) == '#' ? str : '#' + str; -}; - - -/** - * Takes an array of [r, g, b] and converts it into a string appropriate for - * CSS styles. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {string} string of the form 'rgb(r,g,b)'. - * @private - */ -goog.color.rgbStyle_ = function(rgb) { - return 'rgb(' + rgb.join(',') + ')'; -}; - - -/** - * Converts an HSV triplet to an RGB array. V is brightness because b is - * reserved for blue in RGB. - * @param {number} h Hue value in [0, 360]. - * @param {number} s Saturation value in [0, 1]. - * @param {number} brightness brightness in [0, 255]. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.hsvToRgb = function(h, s, brightness) { - var red = 0; - var green = 0; - var blue = 0; - if (s == 0) { - red = brightness; - green = brightness; - blue = brightness; - } else { - var sextant = Math.floor(h / 60); - var remainder = (h / 60) - sextant; - var val1 = brightness * (1 - s); - var val2 = brightness * (1 - (s * remainder)); - var val3 = brightness * (1 - (s * (1 - remainder))); - switch (sextant) { - case 1: - red = val2; - green = brightness; - blue = val1; - break; - case 2: - red = val1; - green = brightness; - blue = val3; - break; - case 3: - red = val1; - green = val2; - blue = brightness; - break; - case 4: - red = val3; - green = val1; - blue = brightness; - break; - case 5: - red = brightness; - green = val1; - blue = val2; - break; - case 6: - case 0: - red = brightness; - green = val3; - blue = val1; - break; - } - } - - return [Math.floor(red), Math.floor(green), Math.floor(blue)]; -}; - - -/** - * Converts from RGB values to an array of HSV values. - * @param {number} red Red value in [0, 255]. - * @param {number} green Green value in [0, 255]. - * @param {number} blue Blue value in [0, 255]. - * @return {!goog.color.Hsv} hsv representation of the color. - */ -goog.color.rgbToHsv = function(red, green, blue) { - - var max = Math.max(Math.max(red, green), blue); - var min = Math.min(Math.min(red, green), blue); - var hue; - var saturation; - var value = max; - if (min == max) { - hue = 0; - saturation = 0; - } else { - var delta = (max - min); - saturation = delta / max; - - if (red == max) { - hue = (green - blue) / delta; - } else if (green == max) { - hue = 2 + ((blue - red) / delta); - } else { - hue = 4 + ((red - green) / delta); - } - hue *= 60; - if (hue < 0) { - hue += 360; - } - if (hue > 360) { - hue -= 360; - } - } - - return [hue, saturation, value]; -}; - - -/** - * Converts from an array of RGB values to an array of HSV values. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {!goog.color.Hsv} hsv representation of the color. - */ -goog.color.rgbArrayToHsv = function(rgb) { - return goog.color.rgbToHsv(rgb[0], rgb[1], rgb[2]); -}; - - -/** - * Converts an HSV triplet to an RGB array. - * @param {goog.color.Hsv} hsv hsv representation of the color. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.hsvArrayToRgb = function(hsv) { - return goog.color.hsvToRgb(hsv[0], hsv[1], hsv[2]); -}; - - -/** - * Converts a hex representation of a color to HSL. - * @param {string} hex Color to convert. - * @return {!goog.color.Hsv} hsv representation of the color. - */ -goog.color.hexToHsl = function(hex) { - var rgb = goog.color.hexToRgb(hex); - return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]); -}; - - -/** - * Converts from h,s,l values to a hex string - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} l Luminosity, in [0, 1]. - * @return {string} hex representation of the color. - */ -goog.color.hslToHex = function(h, s, l) { - return goog.color.rgbArrayToHex(goog.color.hslToRgb(h, s, l)); -}; - - -/** - * Converts from an hsl array to a hex string - * @param {goog.color.Hsl} hsl hsl representation of the color. - * @return {string} hex representation of the color. - */ -goog.color.hslArrayToHex = function(hsl) { - return goog.color.rgbArrayToHex(goog.color.hslToRgb(hsl[0], hsl[1], hsl[2])); -}; - - -/** - * Converts a hex representation of a color to HSV - * @param {string} hex Color to convert. - * @return {!goog.color.Hsv} hsv representation of the color. - */ -goog.color.hexToHsv = function(hex) { - return goog.color.rgbArrayToHsv(goog.color.hexToRgb(hex)); -}; - - -/** - * Converts from h,s,v values to a hex string - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} v Value, in [0, 255]. - * @return {string} hex representation of the color. - */ -goog.color.hsvToHex = function(h, s, v) { - return goog.color.rgbArrayToHex(goog.color.hsvToRgb(h, s, v)); -}; - - -/** - * Converts from an HSV array to a hex string - * @param {goog.color.Hsv} hsv hsv representation of the color. - * @return {string} hex representation of the color. - */ -goog.color.hsvArrayToHex = function(hsv) { - return goog.color.hsvToHex(hsv[0], hsv[1], hsv[2]); -}; - - -/** - * Calculates the Euclidean distance between two color vectors on an HSL sphere. - * A demo of the sphere can be found at: - * http://en.wikipedia.org/wiki/HSL_color_space - * In short, a vector for color (H, S, L) in this system can be expressed as - * (S*L'*cos(2*PI*H), S*L'*sin(2*PI*H), L), where L' = abs(L - 0.5), and we - * simply calculate the 1-2 distance using these coordinates - * @param {goog.color.Hsl} hsl1 First color in hsl representation. - * @param {goog.color.Hsl} hsl2 Second color in hsl representation. - * @return {number} Distance between the two colors, in the range [0, 1]. - */ -goog.color.hslDistance = function(hsl1, hsl2) { - var sl1, sl2; - if (hsl1[2] <= 0.5) { - sl1 = hsl1[1] * hsl1[2]; - } else { - sl1 = hsl1[1] * (1.0 - hsl1[2]); - } - - if (hsl2[2] <= 0.5) { - sl2 = hsl2[1] * hsl2[2]; - } else { - sl2 = hsl2[1] * (1.0 - hsl2[2]); - } - - var h1 = hsl1[0] / 360.0; - var h2 = hsl2[0] / 360.0; - var dh = (h1 - h2) * 2.0 * Math.PI; - return (hsl1[2] - hsl2[2]) * (hsl1[2] - hsl2[2]) + - sl1 * sl1 + sl2 * sl2 - 2 * sl1 * sl2 * Math.cos(dh); -}; - - -/** - * Blend two colors together, using the specified factor to indicate the weight - * given to the first color - * @param {goog.color.Rgb} rgb1 First color represented in rgb. - * @param {goog.color.Rgb} rgb2 Second color represented in rgb. - * @param {number} factor The weight to be given to rgb1 over rgb2. Values - * should be in the range [0, 1]. If less than 0, factor will be set to 0. - * If greater than 1, factor will be set to 1. - * @return {!goog.color.Rgb} Combined color represented in rgb. - */ -goog.color.blend = function(rgb1, rgb2, factor) { - factor = goog.math.clamp(factor, 0, 1); - - return [ - Math.round(factor * rgb1[0] + (1.0 - factor) * rgb2[0]), - Math.round(factor * rgb1[1] + (1.0 - factor) * rgb2[1]), - Math.round(factor * rgb1[2] + (1.0 - factor) * rgb2[2]) - ]; -}; - - -/** - * Adds black to the specified color, darkening it - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while - * 1 will return black. If less than 0, factor will be set to 0. If greater - * than 1, factor will be set to 1. - * @return {!goog.color.Rgb} Combined rgb color. - */ -goog.color.darken = function(rgb, factor) { - var black = [0, 0, 0]; - return goog.color.blend(black, rgb, factor); -}; - - -/** - * Adds white to the specified color, lightening it - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while - * 1 will return white. If less than 0, factor will be set to 0. If greater - * than 1, factor will be set to 1. - * @return {!goog.color.Rgb} Combined rgb color. - */ -goog.color.lighten = function(rgb, factor) { - var white = [255, 255, 255]; - return goog.color.blend(white, rgb, factor); -}; - - -/** - * Find the "best" (highest-contrast) of the suggested colors for the prime - * color. Uses W3C formula for judging readability and visual accessibility: - * http://www.w3.org/TR/AERT#color-contrast - * @param {goog.color.Rgb} prime Color represented as a rgb array. - * @param {Array<goog.color.Rgb>} suggestions Array of colors, - * each representing a rgb array. - * @return {!goog.color.Rgb} Highest-contrast color represented by an array.. - */ -goog.color.highContrast = function(prime, suggestions) { - var suggestionsWithDiff = []; - for (var i = 0; i < suggestions.length; i++) { - suggestionsWithDiff.push({ - color: suggestions[i], - diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) + - goog.color.colorDiff_(suggestions[i], prime) - }); - } - suggestionsWithDiff.sort(function(a, b) { - return b.diff - a.diff; - }); - return suggestionsWithDiff[0].color; -}; - - -/** - * Calculate brightness of a color according to YIQ formula (brightness is Y). - * More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for - * goog.color.highContrast() - * @param {goog.color.Rgb} rgb Color represented by a rgb array. - * @return {number} brightness (Y). - * @private - */ -goog.color.yiqBrightness_ = function(rgb) { - return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000); -}; - - -/** - * Calculate difference in brightness of two colors. Helper method for - * goog.color.highContrast() - * @param {goog.color.Rgb} rgb1 Color represented by a rgb array. - * @param {goog.color.Rgb} rgb2 Color represented by a rgb array. - * @return {number} Brightness difference. - * @private - */ -goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) { - return Math.abs(goog.color.yiqBrightness_(rgb1) - - goog.color.yiqBrightness_(rgb2)); -}; - - -/** - * Calculate color difference between two colors. Helper method for - * goog.color.highContrast() - * @param {goog.color.Rgb} rgb1 Color represented by a rgb array. - * @param {goog.color.Rgb} rgb2 Color represented by a rgb array. - * @return {number} Color difference. - * @private - */ -goog.color.colorDiff_ = function(rgb1, rgb2) { - return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) + - Math.abs(rgb1[2] - rgb2[2]); -}; - -// We can't use goog.color or goog.color.alpha because they interally use a hex -// string representation that encodes each channel in a single byte. This -// causes occasional loss of precision and rounding errors, especially in the -// alpha channel. - -goog.provide('ol.Color'); -goog.provide('ol.color'); - -goog.require('goog.asserts'); -goog.require('goog.color'); -goog.require('goog.color.names'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.math'); - - -/** - * A color represented as a short array [red, green, blue, alpha]. - * red, green, and blue should be integers in the range 0..255 inclusive. - * alpha should be a float in the range 0..1 inclusive. - * @typedef {Array.<number>} - * @api - */ -ol.Color; - - -/** - * This RegExp matches # followed by 3 or 6 hex digits. - * @const - * @type {RegExp} - * @private - */ -ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; - - -/** - * @see goog.color.rgbColorRe_ - * @const - * @type {RegExp} - * @private - */ -ol.color.rgbColorRe_ = - /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; - - -/** - * @see goog.color.alpha.rgbaColorRe_ - * @const - * @type {RegExp} - * @private - */ -ol.color.rgbaColorRe_ = - /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i; - - -/** - * @param {ol.Color} dst Destination. - * @param {ol.Color} src Source. - * @param {ol.Color=} opt_color Color. - * @return {ol.Color} Color. - */ -ol.color.blend = function(dst, src, opt_color) { - // http://en.wikipedia.org/wiki/Alpha_compositing - // FIXME do we need to scale by 255? - var out = opt_color ? opt_color : []; - var dstA = dst[3]; - var srcA = src[3]; - if (dstA == 1) { - out[0] = (src[0] * srcA + dst[0] * (1 - srcA) + 0.5) | 0; - out[1] = (src[1] * srcA + dst[1] * (1 - srcA) + 0.5) | 0; - out[2] = (src[2] * srcA + dst[2] * (1 - srcA) + 0.5) | 0; - out[3] = 1; - } else if (srcA === 0) { - out[0] = dst[0]; - out[1] = dst[1]; - out[2] = dst[2]; - out[3] = dstA; - } else { - var outA = srcA + dstA * (1 - srcA); - if (outA === 0) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; - } else { - out[0] = ((src[0] * srcA + dst[0] * dstA * (1 - srcA)) / outA + 0.5) | 0; - out[1] = ((src[1] * srcA + dst[1] * dstA * (1 - srcA)) / outA + 0.5) | 0; - out[2] = ((src[2] * srcA + dst[2] * dstA * (1 - srcA)) / outA + 0.5) | 0; - out[3] = outA; - } - } - goog.asserts.assert(ol.color.isValid(out), - 'Output color of blend should be a valid color'); - return out; -}; - - -/** - * Return the color as an array. This function maintains a cache of calculated - * arrays which means the result should not be modified. - * @param {ol.Color|string} color Color. - * @return {ol.Color} Color. - * @api - */ -ol.color.asArray = function(color) { - if (goog.isArray(color)) { - return color; - } else { - goog.asserts.assert(goog.isString(color), 'Color should be a string'); - return ol.color.fromString(color); - } -}; - - -/** - * Return the color as an rgba string. - * @param {ol.Color|string} color Color. - * @return {string} Rgba string. - * @api - */ -ol.color.asString = function(color) { - if (goog.isString(color)) { - return color; - } else { - goog.asserts.assert(goog.isArray(color), 'Color should be an array'); - return ol.color.toString(color); - } -}; - - -/** - * @param {ol.Color} color1 Color1. - * @param {ol.Color} color2 Color2. - * @return {boolean} Equals. - */ -ol.color.equals = function(color1, color2) { - return color1 === color2 || ( - color1[0] == color2[0] && color1[1] == color2[1] && - color1[2] == color2[2] && color1[3] == color2[3]); -}; - - -/** - * @param {string} s String. - * @return {ol.Color} Color. - */ -ol.color.fromString = ( - /** - * @return {function(string): ol.Color} - */ - function() { - - // We maintain a small cache of parsed strings. To provide cheap LRU-like - // semantics, whenever the cache grows too large we simply delete an - // arbitrary 25% of the entries. - - /** - * @const - * @type {number} - */ - var MAX_CACHE_SIZE = 1024; - - /** - * @type {Object.<string, ol.Color>} - */ - var cache = {}; - - /** - * @type {number} - */ - var cacheSize = 0; - - return ( - /** - * @param {string} s String. - * @return {ol.Color} Color. - */ - function(s) { - var color; - if (cache.hasOwnProperty(s)) { - color = cache[s]; - } else { - if (cacheSize >= MAX_CACHE_SIZE) { - var i = 0; - var key; - for (key in cache) { - if ((i++ & 3) === 0) { - delete cache[key]; - --cacheSize; - } - } - } - color = ol.color.fromStringInternal_(s); - cache[s] = color; - ++cacheSize; - } - return color; - }); - - })(); - - -/** - * @param {string} s String. - * @private - * @return {ol.Color} Color. - */ -ol.color.fromStringInternal_ = function(s) { - - var isHex = false; - if (ol.ENABLE_NAMED_COLORS && goog.color.names.hasOwnProperty(s)) { - s = goog.color.names[s]; - isHex = true; - } - - var r, g, b, a, color, match; - if (isHex || (match = ol.color.hexColorRe_.exec(s))) { // hex - var n = s.length - 1; // number of hex digits - goog.asserts.assert(n == 3 || n == 6, - 'Color string length should be 3 or 6'); - var d = n == 3 ? 1 : 2; // number of digits per channel - r = parseInt(s.substr(1 + 0 * d, d), 16); - g = parseInt(s.substr(1 + 1 * d, d), 16); - b = parseInt(s.substr(1 + 2 * d, d), 16); - if (d == 1) { - r = (r << 4) + r; - g = (g << 4) + g; - b = (b << 4) + b; - } - a = 1; - color = [r, g, b, a]; - goog.asserts.assert(ol.color.isValid(color), - 'Color should be a valid color'); - return color; - } else if ((match = ol.color.rgbaColorRe_.exec(s))) { // rgba() - r = Number(match[1]); - g = Number(match[2]); - b = Number(match[3]); - a = Number(match[4]); - color = [r, g, b, a]; - return ol.color.normalize(color, color); - } else if ((match = ol.color.rgbColorRe_.exec(s))) { // rgb() - r = Number(match[1]); - g = Number(match[2]); - b = Number(match[3]); - color = [r, g, b, 1]; - return ol.color.normalize(color, color); - } else { - goog.asserts.fail(s + ' is not a valid color'); - } - -}; - - -/** - * @param {ol.Color} color Color. - * @return {boolean} Is valid. - */ -ol.color.isValid = function(color) { - return 0 <= color[0] && color[0] < 256 && - 0 <= color[1] && color[1] < 256 && - 0 <= color[2] && color[2] < 256 && - 0 <= color[3] && color[3] <= 1; -}; - - -/** - * @param {ol.Color} color Color. - * @param {ol.Color=} opt_color Color. - * @return {ol.Color} Clamped color. - */ -ol.color.normalize = function(color, opt_color) { - var result = opt_color || []; - result[0] = ol.math.clamp((color[0] + 0.5) | 0, 0, 255); - result[1] = ol.math.clamp((color[1] + 0.5) | 0, 0, 255); - result[2] = ol.math.clamp((color[2] + 0.5) | 0, 0, 255); - result[3] = ol.math.clamp(color[3], 0, 1); - return result; -}; - - -/** - * @param {ol.Color} color Color. - * @return {string} String. - */ -ol.color.toString = function(color) { - var r = color[0]; - if (r != (r | 0)) { - r = (r + 0.5) | 0; - } - var g = color[1]; - if (g != (g | 0)) { - g = (g + 0.5) | 0; - } - var b = color[2]; - if (b != (b | 0)) { - b = (b + 0.5) | 0; - } - var a = color[3]; - return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; -}; - - -/** - * @param {!ol.Color} color Color. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {!ol.Color=} opt_color Color. - * @return {ol.Color} Transformed color. - */ -ol.color.transform = function(color, transform, opt_color) { - var result = opt_color ? opt_color : []; - result = goog.vec.Mat4.multVec3(transform, color, result); - goog.asserts.assert(goog.isArray(result), 'result should be an array'); - result[3] = color[3]; - return ol.color.normalize(result, result); -}; - - -/** - * @param {ol.Color|string} color1 Color2. - * @param {ol.Color|string} color2 Color2. - * @return {boolean} Equals. - */ -ol.color.stringOrColorEquals = function(color1, color2) { - if (color1 === color2 || color1 == color2) { - return true; - } - if (goog.isString(color1)) { - color1 = ol.color.fromString(color1); - } - if (goog.isString(color2)) { - color2 = ol.color.fromString(color2); - } - return ol.color.equals(color1, color2); -}; - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Browser capability checks for the dom package. - * - */ - - -goog.provide('goog.dom.BrowserFeature'); - -goog.require('goog.userAgent'); - - -/** - * Enum of browser capabilities. - * @enum {boolean} - */ -goog.dom.BrowserFeature = { - /** - * Whether attributes 'name' and 'type' can be added to an element after it's - * created. False in Internet Explorer prior to version 9. - */ - CAN_ADD_NAME_OR_TYPE_ATTRIBUTES: !goog.userAgent.IE || - goog.userAgent.isDocumentModeOrHigher(9), - - /** - * Whether we can use element.children to access an element's Element - * children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment - * nodes in the collection.) - */ - CAN_USE_CHILDREN_ATTRIBUTE: !goog.userAgent.GECKO && !goog.userAgent.IE || - goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9) || - goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'), - - /** - * Opera, Safari 3, and Internet Explorer 9 all support innerText but they - * include text nodes in script and style tags. Not document-mode-dependent. - */ - CAN_USE_INNER_TEXT: ( - goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')), - - /** - * MSIE, Opera, and Safari>=4 support element.parentElement to access an - * element's parent if it is an Element. - */ - CAN_USE_PARENT_ELEMENT_PROPERTY: goog.userAgent.IE || goog.userAgent.OPERA || - goog.userAgent.WEBKIT, - - /** - * Whether NoScope elements need a scoped element written before them in - * innerHTML. - * MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1 - */ - INNER_HTML_NEEDS_SCOPED_ELEMENT: goog.userAgent.IE, - - /** - * Whether we use legacy IE range API. - */ - LEGACY_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Defines the goog.dom.TagName enum. This enumerates - * all HTML tag names specified in either the the W3C HTML 4.01 index of - * elements or the HTML5 draft specification. - * - * References: - * http://www.w3.org/TR/html401/index/elements.html - * http://dev.w3.org/html5/spec/section-index.html - * - */ -goog.provide('goog.dom.TagName'); - - -/** - * Enum of all html tag names specified by the W3C HTML4.01 and HTML5 - * specifications. - * @enum {string} - */ -goog.dom.TagName = { - A: 'A', - ABBR: 'ABBR', - ACRONYM: 'ACRONYM', - ADDRESS: 'ADDRESS', - APPLET: 'APPLET', - AREA: 'AREA', - ARTICLE: 'ARTICLE', - ASIDE: 'ASIDE', - AUDIO: 'AUDIO', - B: 'B', - BASE: 'BASE', - BASEFONT: 'BASEFONT', - BDI: 'BDI', - BDO: 'BDO', - BIG: 'BIG', - BLOCKQUOTE: 'BLOCKQUOTE', - BODY: 'BODY', - BR: 'BR', - BUTTON: 'BUTTON', - CANVAS: 'CANVAS', - CAPTION: 'CAPTION', - CENTER: 'CENTER', - CITE: 'CITE', - CODE: 'CODE', - COL: 'COL', - COLGROUP: 'COLGROUP', - COMMAND: 'COMMAND', - DATA: 'DATA', - DATALIST: 'DATALIST', - DD: 'DD', - DEL: 'DEL', - DETAILS: 'DETAILS', - DFN: 'DFN', - DIALOG: 'DIALOG', - DIR: 'DIR', - DIV: 'DIV', - DL: 'DL', - DT: 'DT', - EM: 'EM', - EMBED: 'EMBED', - FIELDSET: 'FIELDSET', - FIGCAPTION: 'FIGCAPTION', - FIGURE: 'FIGURE', - FONT: 'FONT', - FOOTER: 'FOOTER', - FORM: 'FORM', - FRAME: 'FRAME', - FRAMESET: 'FRAMESET', - H1: 'H1', - H2: 'H2', - H3: 'H3', - H4: 'H4', - H5: 'H5', - H6: 'H6', - HEAD: 'HEAD', - HEADER: 'HEADER', - HGROUP: 'HGROUP', - HR: 'HR', - HTML: 'HTML', - I: 'I', - IFRAME: 'IFRAME', - IMG: 'IMG', - INPUT: 'INPUT', - INS: 'INS', - ISINDEX: 'ISINDEX', - KBD: 'KBD', - KEYGEN: 'KEYGEN', - LABEL: 'LABEL', - LEGEND: 'LEGEND', - LI: 'LI', - LINK: 'LINK', - MAP: 'MAP', - MARK: 'MARK', - MATH: 'MATH', - MENU: 'MENU', - META: 'META', - METER: 'METER', - NAV: 'NAV', - NOFRAMES: 'NOFRAMES', - NOSCRIPT: 'NOSCRIPT', - OBJECT: 'OBJECT', - OL: 'OL', - OPTGROUP: 'OPTGROUP', - OPTION: 'OPTION', - OUTPUT: 'OUTPUT', - P: 'P', - PARAM: 'PARAM', - PRE: 'PRE', - PROGRESS: 'PROGRESS', - Q: 'Q', - RP: 'RP', - RT: 'RT', - RUBY: 'RUBY', - S: 'S', - SAMP: 'SAMP', - SCRIPT: 'SCRIPT', - SECTION: 'SECTION', - SELECT: 'SELECT', - SMALL: 'SMALL', - SOURCE: 'SOURCE', - SPAN: 'SPAN', - STRIKE: 'STRIKE', - STRONG: 'STRONG', - STYLE: 'STYLE', - SUB: 'SUB', - SUMMARY: 'SUMMARY', - SUP: 'SUP', - SVG: 'SVG', - TABLE: 'TABLE', - TBODY: 'TBODY', - TD: 'TD', - TEMPLATE: 'TEMPLATE', - TEXTAREA: 'TEXTAREA', - TFOOT: 'TFOOT', - TH: 'TH', - THEAD: 'THEAD', - TIME: 'TIME', - TITLE: 'TITLE', - TR: 'TR', - TRACK: 'TRACK', - TT: 'TT', - U: 'U', - UL: 'UL', - VAR: 'VAR', - VIDEO: 'VIDEO', - WBR: 'WBR' -}; - -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for HTML element tag names. - */ -goog.provide('goog.dom.tags'); - -goog.require('goog.object'); - - -/** - * The void elements specified by - * http://www.w3.org/TR/html-markup/syntax.html#void-elements. - * @const @private {!Object<string, boolean>} - */ -goog.dom.tags.VOID_TAGS_ = goog.object.createSet( - 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', - 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'); - - -/** - * Checks whether the tag is void (with no contents allowed and no legal end - * tag), for example 'br'. - * @param {string} tagName The tag name in lower case. - * @return {boolean} - */ -goog.dom.tags.isVoidTag = function(tagName) { - return goog.dom.tags.VOID_TAGS_[tagName] === true; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.string.TypedString'); - - - -/** - * Wrapper for strings that conform to a data type or language. - * - * Implementations of this interface are wrappers for strings, and typically - * associate a type contract with the wrapped string. Concrete implementations - * of this interface may choose to implement additional run-time type checking, - * see for example {@code goog.html.SafeHtml}. If available, client code that - * needs to ensure type membership of an object should use the type's function - * to assert type membership, such as {@code goog.html.SafeHtml.unwrap}. - * @interface - */ -goog.string.TypedString = function() {}; - - -/** - * Interface marker of the TypedString interface. - * - * This property can be used to determine at runtime whether or not an object - * implements this interface. All implementations of this interface set this - * property to {@code true}. - * @type {boolean} - */ -goog.string.TypedString.prototype.implementsGoogStringTypedString; - - -/** - * Retrieves this wrapped string's value. - * @return {!string} The wrapped string's value. - */ -goog.string.TypedString.prototype.getTypedStringValue; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.string.Const'); - -goog.require('goog.asserts'); -goog.require('goog.string.TypedString'); - - - -/** - * Wrapper for compile-time-constant strings. - * - * Const is a wrapper for strings that can only be created from program - * constants (i.e., string literals). This property relies on a custom Closure - * compiler check that {@code goog.string.Const.from} is only invoked on - * compile-time-constant expressions. - * - * Const is useful in APIs whose correct and secure use requires that certain - * arguments are not attacker controlled: Compile-time constants are inherently - * under the control of the application and not under control of external - * attackers, and hence are safe to use in such contexts. - * - * Instances of this type must be created via its factory method - * {@code goog.string.Const.from} and not by invoking its constructor. The - * constructor intentionally takes no parameters and the type is immutable; - * hence only a default instance corresponding to the empty string can be - * obtained via constructor invocation. - * - * @see goog.string.Const#from - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} - */ -goog.string.Const = function() { - /** - * The wrapped value of this Const object. The field has a purposely ugly - * name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.string.Const#unwrap - * @const - * @private - */ - this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ = - goog.string.Const.TYPE_MARKER_; -}; - - -/** - * @override - * @const - */ -goog.string.Const.prototype.implementsGoogStringTypedString = true; - - -/** - * Returns this Const's value a string. - * - * IMPORTANT: In code where it is security-relevant that an object's type is - * indeed {@code goog.string.Const}, use {@code goog.string.Const.unwrap} - * instead of this method. - * - * @see goog.string.Const#unwrap - * @override - */ -goog.string.Const.prototype.getTypedStringValue = function() { - return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_; -}; - - -/** - * Returns a debug-string representation of this value. - * - * To obtain the actual string value wrapped inside an object of this type, - * use {@code goog.string.Const.unwrap}. - * - * @see goog.string.Const#unwrap - * @override - */ -goog.string.Const.prototype.toString = function() { - return 'Const{' + - this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ + - '}'; -}; - - -/** - * Performs a runtime check that the provided object is indeed an instance - * of {@code goog.string.Const}, and returns its value. - * @param {!goog.string.Const} stringConst The object to extract from. - * @return {string} The Const object's contained string, unless the run-time - * type check fails. In that case, {@code unwrap} returns an innocuous - * string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.string.Const.unwrap = function(stringConst) { - // Perform additional run-time type-checking to ensure that stringConst is - // indeed an instance of the expected type. This provides some additional - // protection against security bugs due to application code that disables type - // checks. - if (stringConst instanceof goog.string.Const && - stringConst.constructor === goog.string.Const && - stringConst.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ === - goog.string.Const.TYPE_MARKER_) { - return stringConst. - stringConstValueWithSecurityContract__googStringSecurityPrivate_; - } else { - goog.asserts.fail('expected object of type Const, got \'' + - stringConst + '\''); - return 'type_error:Const'; - } -}; - - -/** - * Creates a Const object from a compile-time constant string. - * - * It is illegal to invoke this function on an expression whose - * compile-time-contant value cannot be determined by the Closure compiler. - * - * Correct invocations include, - * <pre> - * var s = goog.string.Const.from('hello'); - * var t = goog.string.Const.from('hello' + 'world'); - * </pre> - * - * In contrast, the following are illegal: - * <pre> - * var s = goog.string.Const.from(getHello()); - * var t = goog.string.Const.from('hello' + world); - * </pre> - * - * TODO(xtof): Compile-time checks that this function is only called - * with compile-time constant expressions. - * - * @param {string} s A constant string from which to create a Const. - * @return {!goog.string.Const} A Const object initialized to stringConst. - */ -goog.string.Const.from = function(s) { - return goog.string.Const.create__googStringSecurityPrivate_(s); -}; - - -/** - * Type marker for the Const type, used to implement additional run-time - * type checking. - * @const {!Object} - * @private - */ -goog.string.Const.TYPE_MARKER_ = {}; - - -/** - * Utility method to create Const instances. - * @param {string} s The string to initialize the Const object with. - * @return {!goog.string.Const} The initialized Const object. - * @private - */ -goog.string.Const.create__googStringSecurityPrivate_ = function(s) { - var stringConst = new goog.string.Const(); - stringConst.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = - s; - return stringConst; -}; - -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview The SafeStyle type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ - -goog.provide('goog.html.SafeStyle'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - - - -/** - * A string-like object which represents a sequence of CSS declarations - * ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...}) - * and that carries the security type contract that its value, as a string, - * will not cause untrusted script execution (XSS) when evaluated as CSS in a - * browser. - * - * Instances of this type must be created via the factory methods - * ({@code goog.html.SafeStyle.create} or - * {@code goog.html.SafeStyle.fromConstant}) and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty string - * can be obtained via constructor invocation. - * - * A SafeStyle's string representation ({@link #getTypedStringValue()}) can - * safely: - * <ul> - * <li>Be interpolated as the entire content of a *quoted* HTML style - * attribute, or before already existing properties. The SafeStyle string - * *must be HTML-attribute-escaped* (where " and ' are escaped) before - * interpolation. - * <li>Be interpolated as the entire content of a {}-wrapped block within a - * stylesheet, or before already existing properties. The SafeStyle string - * should not be escaped before interpolation. SafeStyle's contract also - * guarantees that the string will not be able to introduce new properties - * or elide existing ones. - * <li>Be assigned to the style property of a DOM node. The SafeStyle string - * should not be escaped before being assigned to the property. - * </ul> - * - * A SafeStyle may never contain literal angle brackets. Otherwise, it could - * be unsafe to place a SafeStyle into a <style> tag (where it can't - * be HTML escaped). For example, if the SafeStyle containing - * "{@code font: 'foo <style/><script>evil</script>'}" were - * interpolated within a <style> tag, this would then break out of the - * style context into HTML. - * - * A SafeStyle may contain literal single or double quotes, and as such the - * entire style string must be escaped when used in a style attribute (if - * this were not the case, the string could contain a matching quote that - * would escape from the style attribute). - * - * Values of this type must be composable, i.e. for any two values - * {@code style1} and {@code style2} of this type, - * {@code goog.html.SafeStyle.unwrap(style1) + - * goog.html.SafeStyle.unwrap(style2)} must itself be a value that satisfies - * the SafeStyle type constraint. This requirement implies that for any value - * {@code style} of this type, {@code goog.html.SafeStyle.unwrap(style)} must - * not end in a "property value" or "property name" context. For example, - * a value of {@code background:url("} or {@code font-} would not satisfy the - * SafeStyle contract. This is because concatenating such strings with a - * second value that itself does not contain unsafe CSS can result in an - * overall string that does. For example, if {@code javascript:evil())"} is - * appended to {@code background:url("}, the resulting string may result in - * the execution of a malicious script. - * - * TODO(user): Consider whether we should implement UTF-8 interchange - * validity checks and blacklisting of newlines (including Unicode ones) and - * other whitespace characters (\t, \f). Document here if so and also update - * SafeStyle.fromConstant(). - * - * The following example values comply with this type's contract: - * <ul> - * <li><pre>width: 1em;</pre> - * <li><pre>height:1em;</pre> - * <li><pre>width: 1em;height: 1em;</pre> - * <li><pre>background:url('http://url');</pre> - * </ul> - * In addition, the empty string is safe for use in a CSS attribute. - * - * The following example values do NOT comply with this type's contract: - * <ul> - * <li><pre>background: red</pre> (missing a trailing semi-colon) - * <li><pre>background:</pre> (missing a value and a trailing semi-colon) - * <li><pre>1em</pre> (missing an attribute name, which provides context for - * the value) - * </ul> - * - * @see goog.html.SafeStyle#create - * @see goog.html.SafeStyle#fromConstant - * @see http://www.w3.org/TR/css3-syntax/ - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} - */ -goog.html.SafeStyle = function() { - /** - * The contained value of this SafeStyle. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeStyle#unwrap - * @const - * @private - */ - this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; -}; - - -/** - * @override - * @const - */ -goog.html.SafeStyle.prototype.implementsGoogStringTypedString = true; - - -/** - * Type marker for the SafeStyle type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private - */ -goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; - - -/** - * Creates a SafeStyle object from a compile-time constant string. - * - * {@code style} should be in the format - * {@code name: value; [name: value; ...]} and must not have any < or > - * characters in it. This is so that SafeStyle's contract is preserved, - * allowing the SafeStyle to correctly be interpreted as a sequence of CSS - * declarations and without affecting the syntactic structure of any - * surrounding CSS and HTML. - * - * This method performs basic sanity checks on the format of {@code style} - * but does not constrain the format of {@code name} and {@code value}, except - * for disallowing tag characters. - * - * @param {!goog.string.Const} style A compile-time-constant string from which - * to create a SafeStyle. - * @return {!goog.html.SafeStyle} A SafeStyle object initialized to - * {@code style}. - */ -goog.html.SafeStyle.fromConstant = function(style) { - var styleString = goog.string.Const.unwrap(style); - if (styleString.length === 0) { - return goog.html.SafeStyle.EMPTY; - } - goog.html.SafeStyle.checkStyle_(styleString); - goog.asserts.assert(goog.string.endsWith(styleString, ';'), - 'Last character of style string is not \';\': ' + styleString); - goog.asserts.assert(goog.string.contains(styleString, ':'), - 'Style string must contain at least one \':\', to ' + - 'specify a "name: value" pair: ' + styleString); - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - styleString); -}; - - -/** - * Checks if the style definition is valid. - * @param {string} style - * @private - */ -goog.html.SafeStyle.checkStyle_ = function(style) { - goog.asserts.assert(!/[<>]/.test(style), - 'Forbidden characters in style string: ' + style); -}; - - -/** - * Returns this SafeStyle's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeStyle}, use {@code goog.html.SafeStyle.unwrap} instead of - * this method. If in doubt, assume that it's security relevant. In particular, - * note that goog.html functions which return a goog.html type do not guarantee - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> - * - * @see goog.html.SafeStyle#unwrap - * @override - */ -goog.html.SafeStyle.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeStyleWrappedValue_; -}; - - -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeStyle, use - * {@code goog.html.SafeStyle.unwrap}. - * - * @see goog.html.SafeStyle#unwrap - * @override - */ - goog.html.SafeStyle.prototype.toString = function() { - return 'SafeStyle{' + - this.privateDoNotAccessOrElseSafeStyleWrappedValue_ + '}'; - }; -} - - -/** - * Performs a runtime check that the provided object is indeed a - * SafeStyle object, and returns its value. - * - * @param {!goog.html.SafeStyle} safeStyle The object to extract from. - * @return {string} The safeStyle object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.html.SafeStyle.unwrap = function(safeStyle) { - // Perform additional Run-time type-checking to ensure that - // safeStyle is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeStyle instanceof goog.html.SafeStyle && - safeStyle.constructor === goog.html.SafeStyle && - safeStyle.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_; - } else { - goog.asserts.fail( - 'expected object of type SafeStyle, got \'' + safeStyle + '\''); - return 'type_error:SafeStyle'; - } -}; - - -/** - * Package-internal utility method to create SafeStyle instances. - * - * @param {string} style The string to initialize the SafeStyle object with. - * @return {!goog.html.SafeStyle} The initialized SafeStyle object. - * @package - */ -goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse = - function(style) { - return new goog.html.SafeStyle().initSecurityPrivateDoNotAccessOrElse_(style); -}; - - -/** - * Called from createSafeStyleSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} style - * @return {!goog.html.SafeStyle} - * @private - */ -goog.html.SafeStyle.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( - style) { - this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = style; - return this; -}; - - -/** - * A SafeStyle instance corresponding to the empty string. - * @const {!goog.html.SafeStyle} - */ -goog.html.SafeStyle.EMPTY = - goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(''); - - -/** - * The innocuous string generated by goog.html.SafeUrl.create when passed - * an unsafe value. - * @const {string} - */ -goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez'; - - -/** - * Mapping of property names to their values. - * @typedef {!Object<string, goog.string.Const|string>} - */ -goog.html.SafeStyle.PropertyMap; - - -/** - * Creates a new SafeStyle object from the properties specified in the map. - * @param {goog.html.SafeStyle.PropertyMap} map Mapping of property names to - * their values, for example {'margin': '1px'}. Names must consist of - * [-_a-zA-Z0-9]. Values might be strings consisting of - * [-,.'"%_!# a-zA-Z0-9], where " and ' must be properly balanced. - * Other values must be wrapped in goog.string.Const. Null value causes - * skipping the property. - * @return {!goog.html.SafeStyle} - * @throws {Error} If invalid name is provided. - * @throws {goog.asserts.AssertionError} If invalid value is provided. With - * disabled assertions, invalid value is replaced by - * goog.html.SafeStyle.INNOCUOUS_STRING. - */ -goog.html.SafeStyle.create = function(map) { - var style = ''; - for (var name in map) { - if (!/^[-_a-zA-Z0-9]+$/.test(name)) { - throw Error('Name allows only [-_a-zA-Z0-9], got: ' + name); - } - var value = map[name]; - if (value == null) { - continue; - } - if (value instanceof goog.string.Const) { - value = goog.string.Const.unwrap(value); - // These characters can be used to change context and we don't want that - // even with const values. - goog.asserts.assert(!/[{;}]/.test(value), 'Value does not allow [{;}].'); - } else if (!goog.html.SafeStyle.VALUE_RE_.test(value)) { - goog.asserts.fail( - 'String value allows only [-,."\'%_!# a-zA-Z0-9], got: ' + value); - value = goog.html.SafeStyle.INNOCUOUS_STRING; - } else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) { - goog.asserts.fail('String value requires balanced quotes, got: ' + value); - value = goog.html.SafeStyle.INNOCUOUS_STRING; - } - style += name + ':' + value + ';'; - } - if (!style) { - return goog.html.SafeStyle.EMPTY; - } - goog.html.SafeStyle.checkStyle_(style); - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - style); -}; - - -/** - * Checks that quotes (" and ') are properly balanced inside a string. Assumes - * that neither escape (\) nor any other character that could result in - * breaking out of a string parsing context are allowed; - * see http://www.w3.org/TR/css3-syntax/#string-token-diagram. - * @param {string} value Untrusted CSS property value. - * @return {boolean} True if property value is safe with respect to quote - * balancedness. - * @private - */ -goog.html.SafeStyle.hasBalancedQuotes_ = function(value) { - var outsideSingle = true; - var outsideDouble = true; - for (var i = 0; i < value.length; i++) { - var c = value.charAt(i); - if (c == "'" && outsideDouble) { - outsideSingle = !outsideSingle; - } else if (c == '"' && outsideSingle) { - outsideDouble = !outsideDouble; - } - } - return outsideSingle && outsideDouble; -}; - - -// Keep in sync with the error string in create(). -/** - * Regular expression for safe values. - * - * Quotes (" and ') are allowed, but a check must be done elsewhere to ensure - * they're balanced. - * - * ',' allows multiple values to be assigned to the same property - * (e.g. background-attachment or font-family) and hence could allow - * multiple values to get injected, but that should pose no risk of XSS. - * @const {!RegExp} - * @private - */ -goog.html.SafeStyle.VALUE_RE_ = /^[-,."'%_!# a-zA-Z0-9]+$/; - - -/** - * Creates a new SafeStyle object by concatenating the values. - * @param {...(!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>)} var_args - * SafeStyles to concatenate. - * @return {!goog.html.SafeStyle} - */ -goog.html.SafeStyle.concat = function(var_args) { - var style = ''; - - /** - * @param {!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>} argument - */ - var addArgument = function(argument) { - if (goog.isArray(argument)) { - goog.array.forEach(argument, addArgument); - } else { - style += goog.html.SafeStyle.unwrap(argument); - } - }; - - goog.array.forEach(arguments, addArgument); - if (!style) { - return goog.html.SafeStyle.EMPTY; - } - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - style); -}; - -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview The SafeStyleSheet type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ - -goog.provide('goog.html.SafeStyleSheet'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - - - -/** - * A string-like object which represents a CSS style sheet and that carries the - * security type contract that its value, as a string, will not cause untrusted - * script execution (XSS) when evaluated as CSS in a browser. - * - * Instances of this type must be created via the factory method - * {@code goog.html.SafeStyleSheet.fromConstant} and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty string - * can be obtained via constructor invocation. - * - * A SafeStyleSheet's string representation can safely be interpolated as the - * content of a style element within HTML. The SafeStyleSheet string should - * not be escaped before interpolation. - * - * Values of this type must be composable, i.e. for any two values - * {@code styleSheet1} and {@code styleSheet2} of this type, - * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1) + - * goog.html.SafeStyleSheet.unwrap(styleSheet2)} must itself be a value that - * satisfies the SafeStyleSheet type constraint. This requirement implies that - * for any value {@code styleSheet} of this type, - * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1)} must end in - * "beginning of rule" context. - - * A SafeStyleSheet can be constructed via security-reviewed unchecked - * conversions. In this case producers of SafeStyleSheet must ensure themselves - * that the SafeStyleSheet does not contain unsafe script. Note in particular - * that {@code <} is dangerous, even when inside CSS strings, and so should - * always be forbidden or CSS-escaped in user controlled input. For example, if - * {@code </style><script>evil</script>"} were interpolated - * inside a CSS string, it would break out of the context of the original - * style element and {@code evil} would execute. Also note that within an HTML - * style (raw text) element, HTML character references, such as - * {@code &lt;}, are not allowed. See - * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements - * (similar considerations apply to the style element). - * - * @see goog.html.SafeStyleSheet#fromConstant - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} - */ -goog.html.SafeStyleSheet = function() { - /** - * The contained value of this SafeStyleSheet. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeStyleSheet#unwrap - * @const - * @private - */ - this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; -}; - - -/** - * @override - * @const - */ -goog.html.SafeStyleSheet.prototype.implementsGoogStringTypedString = true; - - -/** - * Type marker for the SafeStyleSheet type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private - */ -goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; - - -/** - * Creates a new SafeStyleSheet object by concatenating values. - * @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)} - * var_args Values to concatenate. - * @return {!goog.html.SafeStyleSheet} - */ -goog.html.SafeStyleSheet.concat = function(var_args) { - var result = ''; - - /** - * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>} - * argument - */ - var addArgument = function(argument) { - if (goog.isArray(argument)) { - goog.array.forEach(argument, addArgument); - } else { - result += goog.html.SafeStyleSheet.unwrap(argument); - } - }; - - goog.array.forEach(arguments, addArgument); - return goog.html.SafeStyleSheet - .createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(result); -}; - - -/** - * Creates a SafeStyleSheet object from a compile-time constant string. - * - * {@code styleSheet} must not have any < characters in it, so that - * the syntactic structure of the surrounding HTML is not affected. - * - * @param {!goog.string.Const} styleSheet A compile-time-constant string from - * which to create a SafeStyleSheet. - * @return {!goog.html.SafeStyleSheet} A SafeStyleSheet object initialized to - * {@code styleSheet}. - */ -goog.html.SafeStyleSheet.fromConstant = function(styleSheet) { - var styleSheetString = goog.string.Const.unwrap(styleSheet); - if (styleSheetString.length === 0) { - return goog.html.SafeStyleSheet.EMPTY; - } - // > is a valid character in CSS selectors and there's no strict need to - // block it if we already block <. - goog.asserts.assert(!goog.string.contains(styleSheetString, '<'), - "Forbidden '<' character in style sheet string: " + styleSheetString); - return goog.html.SafeStyleSheet. - createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheetString); -}; - - -/** - * Returns this SafeStyleSheet's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeStyleSheet}, use {@code goog.html.SafeStyleSheet.unwrap} - * instead of this method. If in doubt, assume that it's security relevant. In - * particular, note that goog.html functions which return a goog.html type do - * not guarantee the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> - * - * @see goog.html.SafeStyleSheet#unwrap - * @override - */ -goog.html.SafeStyleSheet.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_; -}; - - -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeStyleSheet, use - * {@code goog.html.SafeStyleSheet.unwrap}. - * - * @see goog.html.SafeStyleSheet#unwrap - * @override - */ - goog.html.SafeStyleSheet.prototype.toString = function() { - return 'SafeStyleSheet{' + - this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ + '}'; - }; -} - - -/** - * Performs a runtime check that the provided object is indeed a - * SafeStyleSheet object, and returns its value. - * - * @param {!goog.html.SafeStyleSheet} safeStyleSheet The object to extract from. - * @return {string} The safeStyleSheet object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.html.SafeStyleSheet.unwrap = function(safeStyleSheet) { - // Perform additional Run-time type-checking to ensure that - // safeStyleSheet is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeStyleSheet instanceof goog.html.SafeStyleSheet && - safeStyleSheet.constructor === goog.html.SafeStyleSheet && - safeStyleSheet.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_; - } else { - goog.asserts.fail( - "expected object of type SafeStyleSheet, got '" + safeStyleSheet + - "'"); - return 'type_error:SafeStyleSheet'; - } -}; - - -/** - * Package-internal utility method to create SafeStyleSheet instances. - * - * @param {string} styleSheet The string to initialize the SafeStyleSheet - * object with. - * @return {!goog.html.SafeStyleSheet} The initialized SafeStyleSheet object. - * @package - */ -goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse = - function(styleSheet) { - return new goog.html.SafeStyleSheet().initSecurityPrivateDoNotAccessOrElse_( - styleSheet); -}; - - -/** - * Called from createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} styleSheet - * @return {!goog.html.SafeStyleSheet} - * @private - */ -goog.html.SafeStyleSheet.prototype.initSecurityPrivateDoNotAccessOrElse_ = - function(styleSheet) { - this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = styleSheet; - return this; -}; - - -/** - * A SafeStyleSheet instance corresponding to the empty string. - * @const {!goog.html.SafeStyleSheet} - */ -goog.html.SafeStyleSheet.EMPTY = - goog.html.SafeStyleSheet. - createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(''); - -// Copyright 2015 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Wrapper for URL and its createObjectUrl and revokeObjectUrl - * methods that are part of the HTML5 File API. - */ - -goog.provide('goog.fs.url'); - - -/** - * Creates a blob URL for a blob object. - * Throws an error if the browser does not support Object Urls. - * - * @param {!Blob} blob The object for which to create the URL. - * @return {string} The URL for the object. - */ -goog.fs.url.createObjectUrl = function(blob) { - return goog.fs.url.getUrlObject_().createObjectURL(blob); -}; - - -/** - * Revokes a URL created by {@link goog.fs.url.createObjectUrl}. - * Throws an error if the browser does not support Object Urls. - * - * @param {string} url The URL to revoke. - */ -goog.fs.url.revokeObjectUrl = function(url) { - goog.fs.url.getUrlObject_().revokeObjectURL(url); -}; - - -/** - * @typedef {{createObjectURL: (function(!Blob): string), - * revokeObjectURL: function(string): void}} - */ -goog.fs.url.UrlObject_; - - -/** - * Get the object that has the createObjectURL and revokeObjectURL functions for - * this browser. - * - * @return {goog.fs.url.UrlObject_} The object for this browser. - * @private - */ -goog.fs.url.getUrlObject_ = function() { - var urlObject = goog.fs.url.findUrlObject_(); - if (urlObject != null) { - return urlObject; - } else { - throw Error('This browser doesn\'t seem to support blob URLs'); - } -}; - - -/** - * Finds the object that has the createObjectURL and revokeObjectURL functions - * for this browser. - * - * @return {?goog.fs.url.UrlObject_} The object for this browser or null if the - * browser does not support Object Urls. - * @suppress {unnecessaryCasts} Depending on how the code is compiled, casting - * goog.global to UrlObject_ may result in unnecessary cast warning. - * However, the cast cannot be removed because with different set of - * compiler flags, the cast is indeed necessary. As such, silencing it. - * @private - */ -goog.fs.url.findUrlObject_ = function() { - // This is what the spec says to do - // http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL - if (goog.isDef(goog.global.URL) && - goog.isDef(goog.global.URL.createObjectURL)) { - return /** @type {goog.fs.url.UrlObject_} */ (goog.global.URL); - // This is what Chrome does (as of 10.0.648.6 dev) - } else if (goog.isDef(goog.global.webkitURL) && - goog.isDef(goog.global.webkitURL.createObjectURL)) { - return /** @type {goog.fs.url.UrlObject_} */ (goog.global.webkitURL); - // This is what the spec used to say to do - } else if (goog.isDef(goog.global.createObjectURL)) { - return /** @type {goog.fs.url.UrlObject_} */ (goog.global); - } else { - return null; - } -}; - - -/** - * Checks whether this browser supports Object Urls. If not, calls to - * createObjectUrl and revokeObjectUrl will result in an error. - * - * @return {boolean} True if this browser supports Object Urls. - */ -goog.fs.url.browserSupportsObjectUrls = function() { - return goog.fs.url.findUrlObject_() != null; -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utility functions for supporting Bidi issues. - */ - - -/** - * Namespace for bidi supporting functions. - */ -goog.provide('goog.i18n.bidi'); -goog.provide('goog.i18n.bidi.Dir'); -goog.provide('goog.i18n.bidi.DirectionalString'); -goog.provide('goog.i18n.bidi.Format'); - - -/** - * @define {boolean} FORCE_RTL forces the {@link goog.i18n.bidi.IS_RTL} constant - * to say that the current locale is a RTL locale. This should only be used - * if you want to override the default behavior for deciding whether the - * current locale is RTL or not. - * - * {@see goog.i18n.bidi.IS_RTL} - */ -goog.define('goog.i18n.bidi.FORCE_RTL', false); - - -/** - * Constant that defines whether or not the current locale is a RTL locale. - * If {@link goog.i18n.bidi.FORCE_RTL} is not true, this constant will default - * to check that {@link goog.LOCALE} is one of a few major RTL locales. - * - * <p>This is designed to be a maximally efficient compile-time constant. For - * example, for the default goog.LOCALE, compiling - * "if (goog.i18n.bidi.IS_RTL) alert('rtl') else {}" should produce no code. It - * is this design consideration that limits the implementation to only - * supporting a few major RTL locales, as opposed to the broader repertoire of - * something like goog.i18n.bidi.isRtlLanguage. - * - * <p>Since this constant refers to the directionality of the locale, it is up - * to the caller to determine if this constant should also be used for the - * direction of the UI. - * - * {@see goog.LOCALE} - * - * @type {boolean} - * - * TODO(user): write a test that checks that this is a compile-time constant. - */ -goog.i18n.bidi.IS_RTL = goog.i18n.bidi.FORCE_RTL || - ( - (goog.LOCALE.substring(0, 2).toLowerCase() == 'ar' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'fa' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'he' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'iw' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'ps' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'sd' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'ug' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'ur' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'yi') && - (goog.LOCALE.length == 2 || - goog.LOCALE.substring(2, 3) == '-' || - goog.LOCALE.substring(2, 3) == '_') - ) || ( - goog.LOCALE.length >= 3 && - goog.LOCALE.substring(0, 3).toLowerCase() == 'ckb' && - (goog.LOCALE.length == 3 || - goog.LOCALE.substring(3, 4) == '-' || - goog.LOCALE.substring(3, 4) == '_') - ); - - -/** - * Unicode formatting characters and directionality string constants. - * @enum {string} - */ -goog.i18n.bidi.Format = { - /** Unicode "Left-To-Right Embedding" (LRE) character. */ - LRE: '\u202A', - /** Unicode "Right-To-Left Embedding" (RLE) character. */ - RLE: '\u202B', - /** Unicode "Pop Directional Formatting" (PDF) character. */ - PDF: '\u202C', - /** Unicode "Left-To-Right Mark" (LRM) character. */ - LRM: '\u200E', - /** Unicode "Right-To-Left Mark" (RLM) character. */ - RLM: '\u200F' -}; - - -/** - * Directionality enum. - * @enum {number} - */ -goog.i18n.bidi.Dir = { - /** - * Left-to-right. - */ - LTR: 1, - - /** - * Right-to-left. - */ - RTL: -1, - - /** - * Neither left-to-right nor right-to-left. - */ - NEUTRAL: 0 -}; - - -/** - * 'right' string constant. - * @type {string} - */ -goog.i18n.bidi.RIGHT = 'right'; - - -/** - * 'left' string constant. - * @type {string} - */ -goog.i18n.bidi.LEFT = 'left'; - - -/** - * 'left' if locale is RTL, 'right' if not. - * @type {string} - */ -goog.i18n.bidi.I18N_RIGHT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.LEFT : - goog.i18n.bidi.RIGHT; - - -/** - * 'right' if locale is RTL, 'left' if not. - * @type {string} - */ -goog.i18n.bidi.I18N_LEFT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.RIGHT : - goog.i18n.bidi.LEFT; - - -/** - * Convert a directionality given in various formats to a goog.i18n.bidi.Dir - * constant. Useful for interaction with different standards of directionality - * representation. - * - * @param {goog.i18n.bidi.Dir|number|boolean|null} givenDir Directionality given - * in one of the following formats: - * 1. A goog.i18n.bidi.Dir constant. - * 2. A number (positive = LTR, negative = RTL, 0 = neutral). - * 3. A boolean (true = RTL, false = LTR). - * 4. A null for unknown directionality. - * @param {boolean=} opt_noNeutral Whether a givenDir of zero or - * goog.i18n.bidi.Dir.NEUTRAL should be treated as null, i.e. unknown, in - * order to preserve legacy behavior. - * @return {?goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the - * given directionality. If given null, returns null (i.e. unknown). - */ -goog.i18n.bidi.toDir = function(givenDir, opt_noNeutral) { - if (typeof givenDir == 'number') { - // This includes the non-null goog.i18n.bidi.Dir case. - return givenDir > 0 ? goog.i18n.bidi.Dir.LTR : - givenDir < 0 ? goog.i18n.bidi.Dir.RTL : - opt_noNeutral ? null : goog.i18n.bidi.Dir.NEUTRAL; - } else if (givenDir == null) { - return null; - } else { - // Must be typeof givenDir == 'boolean'. - return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR; - } -}; - - -/** - * A practical pattern to identify strong LTR characters. This pattern is not - * theoretically correct according to the Unicode standard. It is simplified for - * performance and small code size. - * @type {string} - * @private - */ -goog.i18n.bidi.ltrChars_ = - 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' + - '\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF'; - - -/** - * A practical pattern to identify strong RTL character. This pattern is not - * theoretically correct according to the Unicode standard. It is simplified - * for performance and small code size. - * @type {string} - * @private - */ -goog.i18n.bidi.rtlChars_ = - '\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC'; - - -/** - * Simplified regular expression for an HTML tag (opening or closing) or an HTML - * escape. We might want to skip over such expressions when estimating the text - * directionality. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g; - - -/** - * Returns the input text with spaces instead of HTML tags or HTML escapes, if - * opt_isStripNeeded is true. Else returns the input as is. - * Useful for text directionality estimation. - * Note: the function should not be used in other contexts; it is not 100% - * correct, but rather a good-enough implementation for directionality - * estimation purposes. - * @param {string} str The given string. - * @param {boolean=} opt_isStripNeeded Whether to perform the stripping. - * Default: false (to retain consistency with calling functions). - * @return {string} The given string cleaned of HTML tags / escapes. - * @private - */ -goog.i18n.bidi.stripHtmlIfNeeded_ = function(str, opt_isStripNeeded) { - return opt_isStripNeeded ? str.replace(goog.i18n.bidi.htmlSkipReg_, '') : - str; -}; - - -/** - * Regular expression to check for RTL characters. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']'); - - -/** - * Regular expression to check for LTR characters. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']'); - - -/** - * Test whether the given string has any RTL characters in it. - * @param {string} str The given string that need to be tested. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether the string contains RTL characters. - */ -goog.i18n.bidi.hasAnyRtl = function(str, opt_isHtml) { - return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); -}; - - -/** - * Test whether the given string has any RTL characters in it. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the string contains RTL characters. - * @deprecated Use hasAnyRtl. - */ -goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl; - - -/** - * Test whether the given string has any LTR characters in it. - * @param {string} str The given string that need to be tested. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether the string contains LTR characters. - */ -goog.i18n.bidi.hasAnyLtr = function(str, opt_isHtml) { - return goog.i18n.bidi.ltrCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); -}; - - -/** - * Regular expression pattern to check if the first character in the string - * is LTR. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']'); - - -/** - * Regular expression pattern to check if the first character in the string - * is RTL. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']'); - - -/** - * Check if the first character in the string is RTL or not. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the first character in str is an RTL char. - */ -goog.i18n.bidi.isRtlChar = function(str) { - return goog.i18n.bidi.rtlRe_.test(str); -}; - - -/** - * Check if the first character in the string is LTR or not. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the first character in str is an LTR char. - */ -goog.i18n.bidi.isLtrChar = function(str) { - return goog.i18n.bidi.ltrRe_.test(str); -}; - - -/** - * Check if the first character in the string is neutral or not. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the first character in str is a neutral char. - */ -goog.i18n.bidi.isNeutralChar = function(str) { - return !goog.i18n.bidi.isLtrChar(str) && !goog.i18n.bidi.isRtlChar(str); -}; - - -/** - * Regular expressions to check if a piece of text is of LTR directionality - * on first character with strong directionality. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.ltrDirCheckRe_ = new RegExp( - '^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']'); - - -/** - * Regular expressions to check if a piece of text is of RTL directionality - * on first character with strong directionality. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rtlDirCheckRe_ = new RegExp( - '^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']'); - - -/** - * Check whether the first strongly directional character (if any) is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL directionality is detected using the first - * strongly-directional character method. - */ -goog.i18n.bidi.startsWithRtl = function(str, opt_isHtml) { - return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); -}; - - -/** - * Check whether the first strongly directional character (if any) is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL directionality is detected using the first - * strongly-directional character method. - * @deprecated Use startsWithRtl. - */ -goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl; - - -/** - * Check whether the first strongly directional character (if any) is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR directionality is detected using the first - * strongly-directional character method. - */ -goog.i18n.bidi.startsWithLtr = function(str, opt_isHtml) { - return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); -}; - - -/** - * Check whether the first strongly directional character (if any) is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR directionality is detected using the first - * strongly-directional character method. - * @deprecated Use startsWithLtr. - */ -goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr; - - -/** - * Regular expression to check if a string looks like something that must - * always be LTR even in RTL text, e.g. a URL. When estimating the - * directionality of text containing these, we treat these as weakly LTR, - * like numbers. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/; - - -/** - * Check whether the input string either contains no strongly directional - * characters or looks like a url. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether neutral directionality is detected. - */ -goog.i18n.bidi.isNeutralText = function(str, opt_isHtml) { - str = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml); - return goog.i18n.bidi.isRequiredLtrRe_.test(str) || - !goog.i18n.bidi.hasAnyLtr(str) && !goog.i18n.bidi.hasAnyRtl(str); -}; - - -/** - * Regular expressions to check if the last strongly-directional character in a - * piece of text is LTR. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp( - '[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$'); - - -/** - * Regular expressions to check if the last strongly-directional character in a - * piece of text is RTL. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp( - '[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$'); - - -/** - * Check if the exit directionality a piece of text is LTR, i.e. if the last - * strongly-directional character in the string is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR exit directionality was detected. - */ -goog.i18n.bidi.endsWithLtr = function(str, opt_isHtml) { - return goog.i18n.bidi.ltrExitDirCheckRe_.test( - goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)); -}; - - -/** - * Check if the exit directionality a piece of text is LTR, i.e. if the last - * strongly-directional character in the string is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR exit directionality was detected. - * @deprecated Use endsWithLtr. - */ -goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr; - - -/** - * Check if the exit directionality a piece of text is RTL, i.e. if the last - * strongly-directional character in the string is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL exit directionality was detected. - */ -goog.i18n.bidi.endsWithRtl = function(str, opt_isHtml) { - return goog.i18n.bidi.rtlExitDirCheckRe_.test( - goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)); -}; - - -/** - * Check if the exit directionality a piece of text is RTL, i.e. if the last - * strongly-directional character in the string is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL exit directionality was detected. - * @deprecated Use endsWithRtl. - */ -goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl; - - -/** - * A regular expression for matching right-to-left language codes. - * See {@link #isRtlLanguage} for the design. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rtlLocalesRe_ = new RegExp( - '^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|' + - '.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))' + - '(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)', - 'i'); - - -/** - * Check if a BCP 47 / III language code indicates an RTL language, i.e. either: - * - a language code explicitly specifying one of the right-to-left scripts, - * e.g. "az-Arab", or<p> - * - a language code specifying one of the languages normally written in a - * right-to-left script, e.g. "fa" (Farsi), except ones explicitly specifying - * Latin or Cyrillic script (which are the usual LTR alternatives).<p> - * The list of right-to-left scripts appears in the 100-199 range in - * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and - * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and - * Tifinagh, which also have significant modern usage. The rest (Syriac, - * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage - * and are not recognized to save on code size. - * The languages usually written in a right-to-left script are taken as those - * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in - * http://www.iana.org/assignments/language-subtag-registry, - * as well as Central (or Sorani) Kurdish (ckb), Sindhi (sd) and Uyghur (ug). - * Other subtags of the language code, e.g. regions like EG (Egypt), are - * ignored. - * @param {string} lang BCP 47 (a.k.a III) language code. - * @return {boolean} Whether the language code is an RTL language. - */ -goog.i18n.bidi.isRtlLanguage = function(lang) { - return goog.i18n.bidi.rtlLocalesRe_.test(lang); -}; - - -/** - * Regular expression for bracket guard replacement in html. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.bracketGuardHtmlRe_ = - /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?(>)+)/g; - - -/** - * Regular expression for bracket guard replacement in text. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.bracketGuardTextRe_ = - /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; - - -/** - * Apply bracket guard using html span tag. This is to address the problem of - * messy bracket display frequently happens in RTL layout. - * @param {string} s The string that need to be processed. - * @param {boolean=} opt_isRtlContext specifies default direction (usually - * direction of the UI). - * @return {string} The processed string, with all bracket guarded. - */ -goog.i18n.bidi.guardBracketInHtml = function(s, opt_isRtlContext) { - var useRtl = opt_isRtlContext === undefined ? - goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext; - if (useRtl) { - return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_, - '<span dir=rtl>$&</span>'); - } - return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_, - '<span dir=ltr>$&</span>'); -}; - - -/** - * Apply bracket guard using LRM and RLM. This is to address the problem of - * messy bracket display frequently happens in RTL layout. - * This version works for both plain text and html. But it does not work as - * good as guardBracketInHtml in some cases. - * @param {string} s The string that need to be processed. - * @param {boolean=} opt_isRtlContext specifies default direction (usually - * direction of the UI). - * @return {string} The processed string, with all bracket guarded. - */ -goog.i18n.bidi.guardBracketInText = function(s, opt_isRtlContext) { - var useRtl = opt_isRtlContext === undefined ? - goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext; - var mark = useRtl ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM; - return s.replace(goog.i18n.bidi.bracketGuardTextRe_, mark + '$&' + mark); -}; - - -/** - * Enforce the html snippet in RTL directionality regardless overall context. - * If the html piece was enclosed by tag, dir will be applied to existing - * tag, otherwise a span tag will be added as wrapper. For this reason, if - * html snippet start with with tag, this tag must enclose the whole piece. If - * the tag already has a dir specified, this new one will override existing - * one in behavior (tested on FF and IE). - * @param {string} html The string that need to be processed. - * @return {string} The processed string, with directionality enforced to RTL. - */ -goog.i18n.bidi.enforceRtlInHtml = function(html) { - if (html.charAt(0) == '<') { - return html.replace(/<\w+/, '$& dir=rtl'); - } - // '\n' is important for FF so that it won't incorrectly merge span groups - return '\n<span dir=rtl>' + html + '</span>'; -}; - - -/** - * Enforce RTL on both end of the given text piece using unicode BiDi formatting - * characters RLE and PDF. - * @param {string} text The piece of text that need to be wrapped. - * @return {string} The wrapped string after process. - */ -goog.i18n.bidi.enforceRtlInText = function(text) { - return goog.i18n.bidi.Format.RLE + text + goog.i18n.bidi.Format.PDF; -}; - - -/** - * Enforce the html snippet in RTL directionality regardless overall context. - * If the html piece was enclosed by tag, dir will be applied to existing - * tag, otherwise a span tag will be added as wrapper. For this reason, if - * html snippet start with with tag, this tag must enclose the whole piece. If - * the tag already has a dir specified, this new one will override existing - * one in behavior (tested on FF and IE). - * @param {string} html The string that need to be processed. - * @return {string} The processed string, with directionality enforced to RTL. - */ -goog.i18n.bidi.enforceLtrInHtml = function(html) { - if (html.charAt(0) == '<') { - return html.replace(/<\w+/, '$& dir=ltr'); - } - // '\n' is important for FF so that it won't incorrectly merge span groups - return '\n<span dir=ltr>' + html + '</span>'; -}; - - -/** - * Enforce LTR on both end of the given text piece using unicode BiDi formatting - * characters LRE and PDF. - * @param {string} text The piece of text that need to be wrapped. - * @return {string} The wrapped string after process. - */ -goog.i18n.bidi.enforceLtrInText = function(text) { - return goog.i18n.bidi.Format.LRE + text + goog.i18n.bidi.Format.PDF; -}; - - -/** - * Regular expression to find dimensions such as "padding: .3 0.4ex 5px 6;" - * @type {RegExp} - * @private - */ -goog.i18n.bidi.dimensionsRe_ = - /:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g; - - -/** - * Regular expression for left. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.leftRe_ = /left/gi; - - -/** - * Regular expression for right. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rightRe_ = /right/gi; - - -/** - * Placeholder regular expression for swapping. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.tempRe_ = /%%%%/g; - - -/** - * Swap location parameters and 'left'/'right' in CSS specification. The - * processed string will be suited for RTL layout. Though this function can - * cover most cases, there are always exceptions. It is suggested to put - * those exceptions in separate group of CSS string. - * @param {string} cssStr CSS spefication string. - * @return {string} Processed CSS specification string. - */ -goog.i18n.bidi.mirrorCSS = function(cssStr) { - return cssStr. - // reverse dimensions - replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2'). - replace(goog.i18n.bidi.leftRe_, '%%%%'). // swap left and right - replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT). - replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT); -}; - - -/** - * Regular expression for hebrew double quote substitution, finding quote - * directly after hebrew characters. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g; - - -/** - * Regular expression for hebrew single quote substitution, finding quote - * directly after hebrew characters. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g; - - -/** - * Replace the double and single quote directly after a Hebrew character with - * GERESH and GERSHAYIM. In such case, most likely that's user intention. - * @param {string} str String that need to be processed. - * @return {string} Processed string with double/single quote replaced. - */ -goog.i18n.bidi.normalizeHebrewQuote = function(str) { - return str. - replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1\u05f4'). - replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1\u05f3'); -}; - - -/** - * Regular expression to split a string into "words" for directionality - * estimation based on relative word counts. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.wordSeparatorRe_ = /\s+/; - - -/** - * Regular expression to check if a string contains any numerals. Used to - * differentiate between completely neutral strings and those containing - * numbers, which are weakly LTR. - * - * Native Arabic digits (\u0660 - \u0669) are not included because although they - * do flow left-to-right inside a number, this is the case even if the overall - * directionality is RTL, and a mathematical expression using these digits is - * supposed to flow right-to-left overall, including unary plus and minus - * appearing to the right of a number, and this does depend on the overall - * directionality being RTL. The digits used in Farsi (\u06F0 - \u06F9), on the - * other hand, are included, since Farsi math (including unary plus and minus) - * does flow left-to-right. - * - * @type {RegExp} - * @private - */ -goog.i18n.bidi.hasNumeralsRe_ = /[\d\u06f0-\u06f9]/; - - -/** - * This constant controls threshold of RTL directionality. - * @type {number} - * @private - */ -goog.i18n.bidi.rtlDetectionThreshold_ = 0.40; - - -/** - * Estimates the directionality of a string based on relative word counts. - * If the number of RTL words is above a certain percentage of the total number - * of strongly directional words, returns RTL. - * Otherwise, if any words are strongly or weakly LTR, returns LTR. - * Otherwise, returns UNKNOWN, which is used to mean "neutral". - * Numbers are counted as weakly LTR. - * @param {string} str The string to be checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}. - */ -goog.i18n.bidi.estimateDirection = function(str, opt_isHtml) { - var rtlCount = 0; - var totalCount = 0; - var hasWeaklyLtr = false; - var tokens = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml). - split(goog.i18n.bidi.wordSeparatorRe_); - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i]; - if (goog.i18n.bidi.startsWithRtl(token)) { - rtlCount++; - totalCount++; - } else if (goog.i18n.bidi.isRequiredLtrRe_.test(token)) { - hasWeaklyLtr = true; - } else if (goog.i18n.bidi.hasAnyLtr(token)) { - totalCount++; - } else if (goog.i18n.bidi.hasNumeralsRe_.test(token)) { - hasWeaklyLtr = true; - } - } - - return totalCount == 0 ? - (hasWeaklyLtr ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL) : - (rtlCount / totalCount > goog.i18n.bidi.rtlDetectionThreshold_ ? - goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR); -}; - - -/** - * Check the directionality of a piece of text, return true if the piece of - * text should be laid out in RTL direction. - * @param {string} str The piece of text that need to be detected. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether this piece of text should be laid out in RTL. - */ -goog.i18n.bidi.detectRtlDirectionality = function(str, opt_isHtml) { - return goog.i18n.bidi.estimateDirection(str, opt_isHtml) == - goog.i18n.bidi.Dir.RTL; -}; - - -/** - * Sets text input element's directionality and text alignment based on a - * given directionality. Does nothing if the given directionality is unknown or - * neutral. - * @param {Element} element Input field element to set directionality to. - * @param {goog.i18n.bidi.Dir|number|boolean|null} dir Desired directionality, - * given in one of the following formats: - * 1. A goog.i18n.bidi.Dir constant. - * 2. A number (positive = LRT, negative = RTL, 0 = neutral). - * 3. A boolean (true = RTL, false = LTR). - * 4. A null for unknown directionality. - */ -goog.i18n.bidi.setElementDirAndAlign = function(element, dir) { - if (element) { - dir = goog.i18n.bidi.toDir(dir); - if (dir) { - element.style.textAlign = - dir == goog.i18n.bidi.Dir.RTL ? - goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT; - element.dir = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr'; - } - } -}; - - -/** - * Sets element dir based on estimated directionality of the given text. - * @param {!Element} element - * @param {string} text - */ -goog.i18n.bidi.setElementDirByTextDirectionality = function(element, text) { - switch (goog.i18n.bidi.estimateDirection(text)) { - case (goog.i18n.bidi.Dir.LTR): - element.dir = 'ltr'; - break; - case (goog.i18n.bidi.Dir.RTL): - element.dir = 'rtl'; - break; - default: - // Default for no direction, inherit from document. - element.removeAttribute('dir'); - } -}; - - - -/** - * Strings that have an (optional) known direction. - * - * Implementations of this interface are string-like objects that carry an - * attached direction, if known. - * @interface - */ -goog.i18n.bidi.DirectionalString = function() {}; - - -/** - * Interface marker of the DirectionalString interface. - * - * This property can be used to determine at runtime whether or not an object - * implements this interface. All implementations of this interface set this - * property to {@code true}. - * @type {boolean} - */ -goog.i18n.bidi.DirectionalString.prototype. - implementsGoogI18nBidiDirectionalString; - - -/** - * Retrieves this object's known direction (if any). - * @return {?goog.i18n.bidi.Dir} The known direction. Null if unknown. - */ -goog.i18n.bidi.DirectionalString.prototype.getDirection; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview The SafeUrl type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ - -goog.provide('goog.html.SafeUrl'); - -goog.require('goog.asserts'); -goog.require('goog.fs.url'); -goog.require('goog.i18n.bidi.Dir'); -goog.require('goog.i18n.bidi.DirectionalString'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - - - -/** - * A string that is safe to use in URL context in DOM APIs and HTML documents. - * - * A SafeUrl is a string-like object that carries the security type contract - * that its value as a string will not cause untrusted script execution - * when evaluated as a hyperlink URL in a browser. - * - * Values of this type are guaranteed to be safe to use in URL/hyperlink - * contexts, such as, assignment to URL-valued DOM properties, or - * interpolation into a HTML template in URL context (e.g., inside a href - * attribute), in the sense that the use will not result in a - * Cross-Site-Scripting vulnerability. - * - * Note that, as documented in {@code goog.html.SafeUrl.unwrap}, this type's - * contract does not guarantee that instances are safe to interpolate into HTML - * without appropriate escaping. - * - * Note also that this type's contract does not imply any guarantees regarding - * the resource the URL refers to. In particular, SafeUrls are <b>not</b> - * safe to use in a context where the referred-to resource is interpreted as - * trusted code, e.g., as the src of a script tag. - * - * Instances of this type must be created via the factory methods - * ({@code goog.html.SafeUrl.fromConstant}, {@code goog.html.SafeUrl.sanitize}), - * etc and not by invoking its constructor. The constructor intentionally - * takes no parameters and the type is immutable; hence only a default instance - * corresponding to the empty string can be obtained via constructor invocation. - * - * @see goog.html.SafeUrl#fromConstant - * @see goog.html.SafeUrl#from - * @see goog.html.SafeUrl#sanitize - * @constructor - * @final - * @struct - * @implements {goog.i18n.bidi.DirectionalString} - * @implements {goog.string.TypedString} - */ -goog.html.SafeUrl = function() { - /** - * The contained value of this SafeUrl. The field has a purposely ugly - * name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeUrl#unwrap - * @const - * @private - */ - this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; -}; - - -/** - * The innocuous string generated by goog.html.SafeUrl.sanitize when passed - * an unsafe URL. - * - * about:invalid is registered in - * http://www.w3.org/TR/css3-values/#about-invalid. - * http://tools.ietf.org/html/rfc6694#section-2.2.1 permits about URLs to - * contain a fragment, which is not to be considered when determining if an - * about URL is well-known. - * - * Using about:invalid seems preferable to using a fixed data URL, since - * browsers might choose to not report CSP violations on it, as legitimate - * CSS function calls to attr() can result in this URL being produced. It is - * also a standard URL which matches exactly the semantics we need: - * "The about:invalid URI references a non-existent document with a generic - * error condition. It can be used when a URI is necessary, but the default - * value shouldn't be resolveable as any type of document". - * - * @const {string} - */ -goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez'; - - -/** - * @override - * @const - */ -goog.html.SafeUrl.prototype.implementsGoogStringTypedString = true; - - -/** - * Returns this SafeUrl's value a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeUrl}, use {@code goog.html.SafeUrl.unwrap} instead of this - * method. If in doubt, assume that it's security relevant. In particular, note - * that goog.html functions which return a goog.html type do not guarantee that - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof - * // goog.html.SafeHtml. - * </pre> - * - * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the - * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST - * be appropriately escaped before embedding in a HTML document. Note that the - * required escaping is context-sensitive (e.g. a different escaping is - * required for embedding a URL in a style property within a style - * attribute, as opposed to embedding in a href attribute). - * - * @see goog.html.SafeUrl#unwrap - * @override - */ -goog.html.SafeUrl.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_; -}; - - -/** - * @override - * @const - */ -goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = true; - - -/** - * Returns this URLs directionality, which is always {@code LTR}. - * @override - */ -goog.html.SafeUrl.prototype.getDirection = function() { - return goog.i18n.bidi.Dir.LTR; -}; - - -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeUrl, use - * {@code goog.html.SafeUrl.unwrap}. - * - * @see goog.html.SafeUrl#unwrap - * @override - */ - goog.html.SafeUrl.prototype.toString = function() { - return 'SafeUrl{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ + - '}'; - }; -} - - -/** - * Performs a runtime check that the provided object is indeed a SafeUrl - * object, and returns its value. - * - * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the - * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST - * be appropriately escaped before embedding in a HTML document. Note that the - * required escaping is context-sensitive (e.g. a different escaping is - * required for embedding a URL in a style property within a style - * attribute, as opposed to embedding in a href attribute). - * - * @param {!goog.html.SafeUrl} safeUrl The object to extract from. - * @return {string} The SafeUrl object's contained string, unless the run-time - * type check fails. In that case, {@code unwrap} returns an innocuous - * string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.html.SafeUrl.unwrap = function(safeUrl) { - // Perform additional Run-time type-checking to ensure that safeUrl is indeed - // an instance of the expected type. This provides some additional protection - // against security bugs due to application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeUrl instanceof goog.html.SafeUrl && - safeUrl.constructor === goog.html.SafeUrl && - safeUrl.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_; - } else { - goog.asserts.fail('expected object of type SafeUrl, got \'' + - safeUrl + '\''); - return 'type_error:SafeUrl'; - - } -}; - - -/** - * Creates a SafeUrl object from a compile-time constant string. - * - * Compile-time constant strings are inherently program-controlled and hence - * trusted. - * - * @param {!goog.string.Const} url A compile-time-constant string from which to - * create a SafeUrl. - * @return {!goog.html.SafeUrl} A SafeUrl object initialized to {@code url}. - */ -goog.html.SafeUrl.fromConstant = function(url) { - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( - goog.string.Const.unwrap(url)); -}; - - -/** - * A pattern that matches Blob or data types that can have SafeUrls created - * from URL.createObjectURL(blob) or via a data: URI. Only matches image and - * video types, currently. - * @const - * @private - */ -goog.html.SAFE_MIME_TYPE_PATTERN_ = - /^(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm))$/i; - - -/** - * Creates a SafeUrl wrapping a blob URL for the given {@code blob}. - * - * The blob URL is created with {@code URL.createObjectURL}. If the MIME type - * for {@code blob} is not of a known safe image or video MIME type, then the - * SafeUrl will wrap {@link #INNOCUOUS_STRING}. - * - * @see http://www.w3.org/TR/FileAPI/#url - * @param {!Blob} blob - * @return {!goog.html.SafeUrl} The blob URL, or an innocuous string wrapped - * as a SafeUrl. - */ -goog.html.SafeUrl.fromBlob = function(blob) { - var url = goog.html.SAFE_MIME_TYPE_PATTERN_.test(blob.type) ? - goog.fs.url.createObjectUrl(blob) : goog.html.SafeUrl.INNOCUOUS_STRING; - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); -}; - - -/** - * Matches a base-64 data URL, with the first match group being the MIME type. - * @const - * @private - */ -goog.html.DATA_URL_PATTERN_ = /^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; - - -/** - * Creates a SafeUrl wrapping a data: URL, after validating it matches a - * known-safe image or video MIME type. - * - * @param {string} dataUrl A valid base64 data URL with one of the whitelisted - * image or video MIME types. - * @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING} - * wrapped as a SafeUrl if it does not pass. - */ -goog.html.SafeUrl.fromDataUrl = function(dataUrl) { - // There's a slight risk here that a browser sniffs the content type if it - // doesn't know the MIME type and executes HTML within the data: URL. For this - // to cause XSS it would also have to execute the HTML in the same origin - // of the page with the link. It seems unlikely that both of these will - // happen, particularly in not really old IEs. - var match = dataUrl.match(goog.html.DATA_URL_PATTERN_); - var valid = match && goog.html.SAFE_MIME_TYPE_PATTERN_.test(match[1]); - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( - valid ? dataUrl : goog.html.SafeUrl.INNOCUOUS_STRING); -}; - - -/** - * A pattern that recognizes a commonly useful subset of URLs that satisfy - * the SafeUrl contract. - * - * This regular expression matches a subset of URLs that will not cause script - * execution if used in URL context within a HTML document. Specifically, this - * regular expression matches if (comment from here on and regex copied from - * Soy's EscapingConventions): - * (1) Either a protocol in a whitelist (http, https, mailto or ftp). - * (2) or no protocol. A protocol must be followed by a colon. The below - * allows that by allowing colons only after one of the characters [/?#]. - * A colon after a hash (#) must be in the fragment. - * Otherwise, a colon after a (?) must be in a query. - * Otherwise, a colon after a single solidus (/) must be in a path. - * Otherwise, a colon after a double solidus (//) must be in the authority - * (before port). - * - * The pattern disallows &, used in HTML entity declarations before - * one of the characters in [/?#]. This disallows HTML entities used in the - * protocol name, which should never happen, e.g. "http" for "http". - * It also disallows HTML entities in the first path part of a relative path, - * e.g. "foo<bar/baz". Our existing escaping functions should not produce - * that. More importantly, it disallows masking of a colon, - * e.g. "javascript:...". - * - * @private - * @const {!RegExp} - */ -goog.html.SAFE_URL_PATTERN_ = - /^(?:(?:https?|mailto|ftp):|[^&:/?#]*(?:[/?#]|$))/i; - - -/** - * Creates a SafeUrl object from {@code url}. If {@code url} is a - * goog.html.SafeUrl then it is simply returned. Otherwise the input string is - * validated to match a pattern of commonly used safe URLs. The string is - * converted to UTF-8 and non-whitelisted characters are percent-encoded. The - * string wrapped by the created SafeUrl will thus contain only ASCII printable - * characters. - * - * {@code url} may be a URL with the http, https, mailto or ftp scheme, - * or a relative URL (i.e., a URL without a scheme; specifically, a - * scheme-relative, absolute-path-relative, or path-relative URL). - * - * {@code url} is converted to UTF-8 and non-whitelisted characters are - * percent-encoded. Whitelisted characters are '%' and, from RFC 3986, - * unreserved characters and reserved characters, with the exception of '\'', - * '(' and ')'. This ensures the the SafeUrl contains only ASCII-printable - * characters and reduces the chance of security bugs were it to be - * interpolated into a specific context without the necessary escaping. - * - * If {@code url} fails validation or does not UTF-16 decode correctly - * (JavaScript strings are UTF-16 encoded), this function returns a SafeUrl - * object containing an innocuous string, goog.html.SafeUrl.INNOCUOUS_STRING. - * - * @see http://url.spec.whatwg.org/#concept-relative-url - * @param {string|!goog.string.TypedString} url The URL to validate. - * @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl. - */ -goog.html.SafeUrl.sanitize = function(url) { - if (url instanceof goog.html.SafeUrl) { - return url; - } - else if (url.implementsGoogStringTypedString) { - url = url.getTypedStringValue(); - } else { - url = String(url); - } - if (!goog.html.SAFE_URL_PATTERN_.test(url)) { - url = goog.html.SafeUrl.INNOCUOUS_STRING; - } - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); -}; - - -/** - * Type marker for the SafeUrl type, used to implement additional run-time - * type checking. - * @const {!Object} - * @private - */ -goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; - - -/** - * Package-internal utility method to create SafeUrl instances. - * - * @param {string} url The string to initialize the SafeUrl object with. - * @return {!goog.html.SafeUrl} The initialized SafeUrl object. - * @package - */ -goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function( - url) { - var safeUrl = new goog.html.SafeUrl(); - safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = url; - return safeUrl; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview The TrustedResourceUrl type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ - -goog.provide('goog.html.TrustedResourceUrl'); - -goog.require('goog.asserts'); -goog.require('goog.i18n.bidi.Dir'); -goog.require('goog.i18n.bidi.DirectionalString'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - - - -/** - * A URL which is under application control and from which script, CSS, and - * other resources that represent executable code, can be fetched. - * - * Given that the URL can only be constructed from strings under application - * control and is used to load resources, bugs resulting in a malformed URL - * should not have a security impact and are likely to be easily detectable - * during testing. Given the wide number of non-RFC compliant URLs in use, - * stricter validation could prevent some applications from being able to use - * this type. - * - * Instances of this type must be created via the factory method, - * ({@code goog.html.TrustedResourceUrl.fromConstant}), and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty - * string can be obtained via constructor invocation. - * - * @see goog.html.TrustedResourceUrl#fromConstant - * @constructor - * @final - * @struct - * @implements {goog.i18n.bidi.DirectionalString} - * @implements {goog.string.TypedString} - */ -goog.html.TrustedResourceUrl = function() { - /** - * The contained value of this TrustedResourceUrl. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.TrustedResourceUrl#unwrap - * @const - * @private - */ - this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; -}; - - -/** - * @override - * @const - */ -goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true; - - -/** - * Returns this TrustedResourceUrl's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code TrustedResourceUrl}, use - * {@code goog.html.TrustedResourceUrl.unwrap} instead of this method. If in - * doubt, assume that it's security relevant. In particular, note that - * goog.html functions which return a goog.html type do not guarantee that - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof - * // goog.html.SafeHtml. - * </pre> - * - * @see goog.html.TrustedResourceUrl#unwrap - * @override - */ -goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_; -}; - - -/** - * @override - * @const - */ -goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString = - true; - - -/** - * Returns this URLs directionality, which is always {@code LTR}. - * @override - */ -goog.html.TrustedResourceUrl.prototype.getDirection = function() { - return goog.i18n.bidi.Dir.LTR; -}; - - -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a TrustedResourceUrl, use - * {@code goog.html.TrustedResourceUrl.unwrap}. - * - * @see goog.html.TrustedResourceUrl#unwrap - * @override - */ - goog.html.TrustedResourceUrl.prototype.toString = function() { - return 'TrustedResourceUrl{' + - this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}'; - }; -} - - -/** - * Performs a runtime check that the provided object is indeed a - * TrustedResourceUrl object, and returns its value. - * - * @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to - * extract from. - * @return {string} The trustedResourceUrl object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) { - // Perform additional Run-time type-checking to ensure that - // trustedResourceUrl is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl && - trustedResourceUrl.constructor === goog.html.TrustedResourceUrl && - trustedResourceUrl - .TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.TrustedResourceUrl - .TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return trustedResourceUrl - .privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_; - } else { - goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' + - trustedResourceUrl + '\''); - return 'type_error:TrustedResourceUrl'; - - } -}; - - -/** - * Creates a TrustedResourceUrl object from a compile-time constant string. - * - * Compile-time constant strings are inherently program-controlled and hence - * trusted. - * - * @param {!goog.string.Const} url A compile-time-constant string from which to - * create a TrustedResourceUrl. - * @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object - * initialized to {@code url}. - */ -goog.html.TrustedResourceUrl.fromConstant = function(url) { - return goog.html.TrustedResourceUrl - .createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( - goog.string.Const.unwrap(url)); -}; - - -/** - * Type marker for the TrustedResourceUrl type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private - */ -goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; - - -/** - * Package-internal utility method to create TrustedResourceUrl instances. - * - * @param {string} url The string to initialize the TrustedResourceUrl object - * with. - * @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl - * object. - * @package - */ -goog.html.TrustedResourceUrl. - createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) { - var trustedResourceUrl = new goog.html.TrustedResourceUrl(); - trustedResourceUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = - url; - return trustedResourceUrl; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview The SafeHtml type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ - -goog.provide('goog.html.SafeHtml'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.tags'); -goog.require('goog.html.SafeStyle'); -goog.require('goog.html.SafeStyleSheet'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.TrustedResourceUrl'); -goog.require('goog.i18n.bidi.Dir'); -goog.require('goog.i18n.bidi.DirectionalString'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - - - -/** - * A string that is safe to use in HTML context in DOM APIs and HTML documents. - * - * A SafeHtml is a string-like object that carries the security type contract - * that its value as a string will not cause untrusted script execution when - * evaluated as HTML in a browser. - * - * Values of this type are guaranteed to be safe to use in HTML contexts, - * such as, assignment to the innerHTML DOM property, or interpolation into - * a HTML template in HTML PC_DATA context, in the sense that the use will not - * result in a Cross-Site-Scripting vulnerability. - * - * Instances of this type must be created via the factory methods - * ({@code goog.html.SafeHtml.create}, {@code goog.html.SafeHtml.htmlEscape}), - * etc and not by invoking its constructor. The constructor intentionally - * takes no parameters and the type is immutable; hence only a default instance - * corresponding to the empty string can be obtained via constructor invocation. - * - * @see goog.html.SafeHtml#create - * @see goog.html.SafeHtml#htmlEscape - * @constructor - * @final - * @struct - * @implements {goog.i18n.bidi.DirectionalString} - * @implements {goog.string.TypedString} - */ -goog.html.SafeHtml = function() { - /** - * The contained value of this SafeHtml. The field has a purposely ugly - * name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeHtml#unwrap - * @const - * @private - */ - this.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; - - /** - * This SafeHtml's directionality, or null if unknown. - * @private {?goog.i18n.bidi.Dir} - */ - this.dir_ = null; -}; - - -/** - * @override - * @const - */ -goog.html.SafeHtml.prototype.implementsGoogI18nBidiDirectionalString = true; - - -/** @override */ -goog.html.SafeHtml.prototype.getDirection = function() { - return this.dir_; -}; - - -/** - * @override - * @const - */ -goog.html.SafeHtml.prototype.implementsGoogStringTypedString = true; - - -/** - * Returns this SafeHtml's value a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeHtml}, use {@code goog.html.SafeHtml.unwrap} instead of - * this method. If in doubt, assume that it's security relevant. In particular, - * note that goog.html functions which return a goog.html type do not guarantee - * that the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> - * - * @see goog.html.SafeHtml#unwrap - * @override - */ -goog.html.SafeHtml.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_; -}; - - -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeHtml, use - * {@code goog.html.SafeHtml.unwrap}. - * - * @see goog.html.SafeHtml#unwrap - * @override - */ - goog.html.SafeHtml.prototype.toString = function() { - return 'SafeHtml{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ + - '}'; - }; -} - - -/** - * Performs a runtime check that the provided object is indeed a SafeHtml - * object, and returns its value. - * @param {!goog.html.SafeHtml} safeHtml The object to extract from. - * @return {string} The SafeHtml object's contained string, unless the run-time - * type check fails. In that case, {@code unwrap} returns an innocuous - * string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.html.SafeHtml.unwrap = function(safeHtml) { - // Perform additional run-time type-checking to ensure that safeHtml is indeed - // an instance of the expected type. This provides some additional protection - // against security bugs due to application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeHtml instanceof goog.html.SafeHtml && - safeHtml.constructor === goog.html.SafeHtml && - safeHtml.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeHtml.privateDoNotAccessOrElseSafeHtmlWrappedValue_; - } else { - goog.asserts.fail('expected object of type SafeHtml, got \'' + - safeHtml + '\''); - return 'type_error:SafeHtml'; - } -}; - - -/** - * Shorthand for union of types that can sensibly be converted to strings - * or might already be SafeHtml (as SafeHtml is a goog.string.TypedString). - * @private - * @typedef {string|number|boolean|!goog.string.TypedString| - * !goog.i18n.bidi.DirectionalString} - */ -goog.html.SafeHtml.TextOrHtml_; - - -/** - * Returns HTML-escaped text as a SafeHtml object. - * - * If text is of a type that implements - * {@code goog.i18n.bidi.DirectionalString}, the directionality of the new - * {@code SafeHtml} object is set to {@code text}'s directionality, if known. - * Otherwise, the directionality of the resulting SafeHtml is unknown (i.e., - * {@code null}). - * - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If - * the parameter is of type SafeHtml it is returned directly (no escaping - * is done). - * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. - */ -goog.html.SafeHtml.htmlEscape = function(textOrHtml) { - if (textOrHtml instanceof goog.html.SafeHtml) { - return textOrHtml; - } - var dir = null; - if (textOrHtml.implementsGoogI18nBidiDirectionalString) { - dir = textOrHtml.getDirection(); - } - var textAsString; - if (textOrHtml.implementsGoogStringTypedString) { - textAsString = textOrHtml.getTypedStringValue(); - } else { - textAsString = String(textOrHtml); - } - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - goog.string.htmlEscape(textAsString), dir); -}; - - -/** - * Returns HTML-escaped text as a SafeHtml object, with newlines changed to - * <br>. - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If - * the parameter is of type SafeHtml it is returned directly (no escaping - * is done). - * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. - */ -goog.html.SafeHtml.htmlEscapePreservingNewlines = function(textOrHtml) { - if (textOrHtml instanceof goog.html.SafeHtml) { - return textOrHtml; - } - var html = goog.html.SafeHtml.htmlEscape(textOrHtml); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - goog.string.newLineToBr(goog.html.SafeHtml.unwrap(html)), - html.getDirection()); -}; - - -/** - * Returns HTML-escaped text as a SafeHtml object, with newlines changed to - * <br> and escaping whitespace to preserve spatial formatting. Character - * entity #160 is used to make it safer for XML. - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If - * the parameter is of type SafeHtml it is returned directly (no escaping - * is done). - * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. - */ -goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces = function( - textOrHtml) { - if (textOrHtml instanceof goog.html.SafeHtml) { - return textOrHtml; - } - var html = goog.html.SafeHtml.htmlEscape(textOrHtml); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - goog.string.whitespaceEscape(goog.html.SafeHtml.unwrap(html)), - html.getDirection()); -}; - - -/** - * Coerces an arbitrary object into a SafeHtml object. - * - * If {@code textOrHtml} is already of type {@code goog.html.SafeHtml}, the same - * object is returned. Otherwise, {@code textOrHtml} is coerced to string, and - * HTML-escaped. If {@code textOrHtml} is of a type that implements - * {@code goog.i18n.bidi.DirectionalString}, its directionality, if known, is - * preserved. - * - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text or SafeHtml to - * coerce. - * @return {!goog.html.SafeHtml} The resulting SafeHtml object. - * @deprecated Use goog.html.SafeHtml.htmlEscape. - */ -goog.html.SafeHtml.from = goog.html.SafeHtml.htmlEscape; - - -/** - * @const - * @private - */ -goog.html.SafeHtml.VALID_NAMES_IN_TAG_ = /^[a-zA-Z0-9-]+$/; - - -/** - * Set of attributes containing URL as defined at - * http://www.w3.org/TR/html5/index.html#attributes-1. - * @private @const {!Object<string,boolean>} - */ -goog.html.SafeHtml.URL_ATTRIBUTES_ = goog.object.createSet('action', 'cite', - 'data', 'formaction', 'href', 'manifest', 'poster', 'src'); - - -/** - * Tags which are unsupported via create(). They might be supported via a - * tag-specific create method. These are tags which might require a - * TrustedResourceUrl in one of their attributes or a restricted type for - * their content. - * @private @const {!Object<string,boolean>} - */ -goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_ = goog.object.createSet( - goog.dom.TagName.EMBED, goog.dom.TagName.IFRAME, goog.dom.TagName.LINK, - goog.dom.TagName.OBJECT, goog.dom.TagName.SCRIPT, goog.dom.TagName.STYLE, - goog.dom.TagName.TEMPLATE); - - -/** - * @typedef {string|number|goog.string.TypedString| - * goog.html.SafeStyle.PropertyMap} - * @private - */ -goog.html.SafeHtml.AttributeValue_; - - -/** - * Creates a SafeHtml content consisting of a tag with optional attributes and - * optional content. - * - * For convenience tag names and attribute names are accepted as regular - * strings, instead of goog.string.Const. Nevertheless, you should not pass - * user-controlled values to these parameters. Note that these parameters are - * syntactically validated at runtime, and invalid values will result in - * an exception. - * - * Example usage: - * - * goog.html.SafeHtml.create('br'); - * goog.html.SafeHtml.create('div', {'class': 'a'}); - * goog.html.SafeHtml.create('p', {}, 'a'); - * goog.html.SafeHtml.create('p', {}, goog.html.SafeHtml.create('br')); - * - * goog.html.SafeHtml.create('span', { - * 'style': {'margin': '0'} - * }); - * - * To guarantee SafeHtml's type contract is upheld there are restrictions on - * attribute values and tag names. - * - * - For attributes which contain script code (on*), a goog.string.Const is - * required. - * - For attributes which contain style (style), a goog.html.SafeStyle or a - * goog.html.SafeStyle.PropertyMap is required. - * - For attributes which are interpreted as URLs (e.g. src, href) a - * goog.html.SafeUrl, goog.string.Const or string is required. If a string - * is passed, it will be sanitized with SafeUrl.sanitize(). - * - For tags which can load code, more specific goog.html.SafeHtml.create*() - * functions must be used. Tags which can load code and are not supported by - * this function are embed, iframe, link, object, script, style, and template. - * - * @param {string} tagName The name of the tag. Only tag names consisting of - * [a-zA-Z0-9-] are allowed. Tag names documented above are disallowed. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Mapping from attribute names to their values. Only - * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or - * undefined causes the attribute to be omitted. - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to - * HTML-escape and put inside the tag. This must be empty for void tags - * like <br>. Array elements are concatenated. - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - * @throws {Error} If invalid tag name, attribute name, or attribute value is - * provided. - * @throws {goog.asserts.AssertionError} If content for void tag is provided. - */ -goog.html.SafeHtml.create = function(tagName, opt_attributes, opt_content) { - if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(tagName)) { - throw Error('Invalid tag name <' + tagName + '>.'); - } - if (tagName.toUpperCase() in goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_) { - throw Error('Tag name <' + tagName + '> is not allowed for SafeHtml.'); - } - return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( - tagName, opt_attributes, opt_content); -}; - - -/** - * Creates a SafeHtml representing an iframe tag. - * - * By default the sandbox attribute is set to an empty value, which is the most - * secure option, as it confers the iframe the least privileges. If this - * is too restrictive then granting individual privileges is the preferable - * option. Unsetting the attribute entirely is the least secure option and - * should never be done unless it's stricly necessary. - * - * @param {goog.html.TrustedResourceUrl=} opt_src The value of the src - * attribute. If null or undefined src will not be set. - * @param {goog.html.SafeHtml=} opt_srcdoc The value of the srcdoc attribute. - * If null or undefined srcdoc will not be set. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Mapping from attribute names to their values. Only - * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or - * undefined causes the attribute to be omitted. - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to - * HTML-escape and put inside the tag. Array elements are concatenated. - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - * @throws {Error} If invalid tag name, attribute name, or attribute value is - * provided. If opt_attributes contains the src or srcdoc attributes. - */ -goog.html.SafeHtml.createIframe = function( - opt_src, opt_srcdoc, opt_attributes, opt_content) { - var fixedAttributes = {}; - fixedAttributes['src'] = opt_src || null; - fixedAttributes['srcdoc'] = opt_srcdoc || null; - var defaultAttributes = {'sandbox': ''}; - var attributes = goog.html.SafeHtml.combineAttributes( - fixedAttributes, defaultAttributes, opt_attributes); - return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( - 'iframe', attributes, opt_content); -}; - - -/** - * Creates a SafeHtml representing a style tag. The type attribute is set - * to "text/css". - * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>} - * styleSheet Content to put inside the tag. Array elements are - * concatenated. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Mapping from attribute names to their values. Only - * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or - * undefined causes the attribute to be omitted. - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - * @throws {Error} If invalid attribute name or attribute value is provided. If - * opt_attributes contains the type attribute. - */ -goog.html.SafeHtml.createStyle = function(styleSheet, opt_attributes) { - var fixedAttributes = {'type': 'text/css'}; - var defaultAttributes = {}; - var attributes = goog.html.SafeHtml.combineAttributes( - fixedAttributes, defaultAttributes, opt_attributes); - - var content = ''; - styleSheet = goog.array.concat(styleSheet); - for (var i = 0; i < styleSheet.length; i++) { - content += goog.html.SafeStyleSheet.unwrap(styleSheet[i]); - } - // Convert to SafeHtml so that it's not HTML-escaped. - var htmlContent = goog.html.SafeHtml - .createSafeHtmlSecurityPrivateDoNotAccessOrElse( - content, goog.i18n.bidi.Dir.NEUTRAL); - return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( - 'style', attributes, htmlContent); -}; - - -/** - * @param {string} tagName The tag name. - * @param {string} name The attribute name. - * @param {!goog.html.SafeHtml.AttributeValue_} value The attribute value. - * @return {string} A "name=value" string. - * @throws {Error} If attribute value is unsafe for the given tag and attribute. - * @private - */ -goog.html.SafeHtml.getAttrNameAndValue_ = function(tagName, name, value) { - // If it's goog.string.Const, allow any valid attribute name. - if (value instanceof goog.string.Const) { - value = goog.string.Const.unwrap(value); - } else if (name.toLowerCase() == 'style') { - value = goog.html.SafeHtml.getStyleValue_(value); - } else if (/^on/i.test(name)) { - // TODO(jakubvrana): Disallow more attributes with a special meaning. - throw Error('Attribute "' + name + - '" requires goog.string.Const value, "' + value + '" given.'); - // URL attributes handled differently accroding to tag. - } else if (name.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) { - if (value instanceof goog.html.TrustedResourceUrl) { - value = goog.html.TrustedResourceUrl.unwrap(value); - } else if (value instanceof goog.html.SafeUrl) { - value = goog.html.SafeUrl.unwrap(value); - } else if (goog.isString(value)) { - value = goog.html.SafeUrl.sanitize(value).getTypedStringValue(); - } else { - throw Error('Attribute "' + name + '" on tag "' + tagName + - '" requires goog.html.SafeUrl, goog.string.Const, or string,' + - ' value "' + value + '" given.'); - } - } - - // Accept SafeUrl, TrustedResourceUrl, etc. for attributes which only require - // HTML-escaping. - if (value.implementsGoogStringTypedString) { - // Ok to call getTypedStringValue() since there's no reliance on the type - // contract for security here. - value = value.getTypedStringValue(); - } - - goog.asserts.assert(goog.isString(value) || goog.isNumber(value), - 'String or number value expected, got ' + - (typeof value) + ' with value: ' + value); - return name + '="' + goog.string.htmlEscape(String(value)) + '"'; -}; - - -/** - * Gets value allowed in "style" attribute. - * @param {goog.html.SafeHtml.AttributeValue_} value It could be SafeStyle or a - * map which will be passed to goog.html.SafeStyle.create. - * @return {string} Unwrapped value. - * @throws {Error} If string value is given. - * @private - */ -goog.html.SafeHtml.getStyleValue_ = function(value) { - if (!goog.isObject(value)) { - throw Error('The "style" attribute requires goog.html.SafeStyle or map ' + - 'of style properties, ' + (typeof value) + ' given: ' + value); - } - if (!(value instanceof goog.html.SafeStyle)) { - // Process the property bag into a style object. - value = goog.html.SafeStyle.create(value); - } - return goog.html.SafeStyle.unwrap(value); -}; - - -/** - * Creates a SafeHtml content with known directionality consisting of a tag with - * optional attributes and optional content. - * @param {!goog.i18n.bidi.Dir} dir Directionality. - * @param {string} tagName - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - */ -goog.html.SafeHtml.createWithDir = function(dir, tagName, opt_attributes, - opt_content) { - var html = goog.html.SafeHtml.create(tagName, opt_attributes, opt_content); - html.dir_ = dir; - return html; -}; - - -/** - * Creates a new SafeHtml object by concatenating values. - * @param {...(!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Values to concatenate. - * @return {!goog.html.SafeHtml} - */ -goog.html.SafeHtml.concat = function(var_args) { - var dir = goog.i18n.bidi.Dir.NEUTRAL; - var content = ''; - - /** - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>} argument - */ - var addArgument = function(argument) { - if (goog.isArray(argument)) { - goog.array.forEach(argument, addArgument); - } else { - var html = goog.html.SafeHtml.htmlEscape(argument); - content += goog.html.SafeHtml.unwrap(html); - var htmlDir = html.getDirection(); - if (dir == goog.i18n.bidi.Dir.NEUTRAL) { - dir = htmlDir; - } else if (htmlDir != goog.i18n.bidi.Dir.NEUTRAL && dir != htmlDir) { - dir = null; - } - } - }; - - goog.array.forEach(arguments, addArgument); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - content, dir); -}; - - -/** - * Creates a new SafeHtml object with known directionality by concatenating the - * values. - * @param {!goog.i18n.bidi.Dir} dir Directionality. - * @param {...(!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Elements of array - * arguments would be processed recursively. - * @return {!goog.html.SafeHtml} - */ -goog.html.SafeHtml.concatWithDir = function(dir, var_args) { - var html = goog.html.SafeHtml.concat(goog.array.slice(arguments, 1)); - html.dir_ = dir; - return html; -}; - - -/** - * Type marker for the SafeHtml type, used to implement additional run-time - * type checking. - * @const {!Object} - * @private - */ -goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; - - -/** - * Package-internal utility method to create SafeHtml instances. - * - * @param {string} html The string to initialize the SafeHtml object with. - * @param {?goog.i18n.bidi.Dir} dir The directionality of the SafeHtml to be - * constructed, or null if unknown. - * @return {!goog.html.SafeHtml} The initialized SafeHtml object. - * @package - */ -goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse = function( - html, dir) { - return new goog.html.SafeHtml().initSecurityPrivateDoNotAccessOrElse_( - html, dir); -}; - - -/** - * Called from createSafeHtmlSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} html - * @param {?goog.i18n.bidi.Dir} dir - * @return {!goog.html.SafeHtml} - * @private - */ -goog.html.SafeHtml.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( - html, dir) { - this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = html; - this.dir_ = dir; - return this; -}; - - -/** - * Like create() but does not restrict which tags can be constructed. - * - * @param {string} tagName Tag name. Set or validated by caller. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes - * @param {(!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>)=} opt_content - * @return {!goog.html.SafeHtml} - * @throws {Error} If invalid or unsafe attribute name or value is provided. - * @throws {goog.asserts.AssertionError} If content for void tag is provided. - * @package - */ -goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse = - function(tagName, opt_attributes, opt_content) { - var dir = null; - var result = '<' + tagName; - - if (opt_attributes) { - for (var name in opt_attributes) { - if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(name)) { - throw Error('Invalid attribute name "' + name + '".'); - } - var value = opt_attributes[name]; - if (!goog.isDefAndNotNull(value)) { - continue; - } - result += ' ' + - goog.html.SafeHtml.getAttrNameAndValue_(tagName, name, value); - } - } - - var content = opt_content; - if (!goog.isDefAndNotNull(content)) { - content = []; - } else if (!goog.isArray(content)) { - content = [content]; - } - - if (goog.dom.tags.isVoidTag(tagName.toLowerCase())) { - goog.asserts.assert(!content.length, - 'Void tag <' + tagName + '> does not allow content.'); - result += '>'; - } else { - var html = goog.html.SafeHtml.concat(content); - result += '>' + goog.html.SafeHtml.unwrap(html) + '</' + tagName + '>'; - dir = html.getDirection(); - } - - var dirAttribute = opt_attributes && opt_attributes['dir']; - if (dirAttribute) { - if (/^(ltr|rtl|auto)$/i.test(dirAttribute)) { - // If the tag has the "dir" attribute specified then its direction is - // neutral because it can be safely used in any context. - dir = goog.i18n.bidi.Dir.NEUTRAL; - } else { - dir = null; - } - } - - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - result, dir); -}; - - -/** - * @param {!Object<string, string>} fixedAttributes - * @param {!Object<string, string>} defaultAttributes - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Optional attributes passed to create*(). - * @return {!Object<string, goog.html.SafeHtml.AttributeValue_>} - * @throws {Error} If opt_attributes contains an attribute with the same name - * as an attribute in fixedAttributes. - * @package - */ -goog.html.SafeHtml.combineAttributes = function( - fixedAttributes, defaultAttributes, opt_attributes) { - var combinedAttributes = {}; - var name; - - for (name in fixedAttributes) { - goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case'); - combinedAttributes[name] = fixedAttributes[name]; - } - for (name in defaultAttributes) { - goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case'); - combinedAttributes[name] = defaultAttributes[name]; - } - - for (name in opt_attributes) { - var nameLower = name.toLowerCase(); - if (nameLower in fixedAttributes) { - throw Error('Cannot override "' + nameLower + '" attribute, got "' + - name + '" with value "' + opt_attributes[name] + '"'); - } - if (nameLower in defaultAttributes) { - delete combinedAttributes[nameLower]; - } - combinedAttributes[name] = opt_attributes[name]; - } - - return combinedAttributes; -}; - - -/** - * A SafeHtml instance corresponding to the HTML doctype: "<!DOCTYPE html>". - * @const {!goog.html.SafeHtml} - */ -goog.html.SafeHtml.DOCTYPE_HTML = - goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - '<!DOCTYPE html>', goog.i18n.bidi.Dir.NEUTRAL); - - -/** - * A SafeHtml instance corresponding to the empty string. - * @const {!goog.html.SafeHtml} - */ -goog.html.SafeHtml.EMPTY = - goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - '', goog.i18n.bidi.Dir.NEUTRAL); - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Type-safe wrappers for unsafe DOM APIs. - * - * This file provides type-safe wrappers for DOM APIs that can result in - * cross-site scripting (XSS) vulnerabilities, if the API is supplied with - * untrusted (attacker-controlled) input. Instead of plain strings, the type - * safe wrappers consume values of types from the goog.html package whose - * contract promises that values are safe to use in the corresponding context. - * - * Hence, a program that exclusively uses the wrappers in this file (i.e., whose - * only reference to security-sensitive raw DOM APIs are in this file) is - * guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo - * correctness of code that produces values of the respective goog.html types, - * and absent code that violates type safety). - * - * For example, assigning to an element's .innerHTML property a string that is - * derived (even partially) from untrusted input typically results in an XSS - * vulnerability. The type-safe wrapper goog.html.setInnerHtml consumes a value - * of type goog.html.SafeHtml, whose contract states that using its values in a - * HTML context will not result in XSS. Hence a program that is free of direct - * assignments to any element's innerHTML property (with the exception of the - * assignment to .innerHTML in this file) is guaranteed to be free of XSS due to - * assignment of untrusted strings to the innerHTML property. - */ - -goog.provide('goog.dom.safe'); -goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition'); - -goog.require('goog.asserts'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.TrustedResourceUrl'); -goog.require('goog.string'); -goog.require('goog.string.Const'); - - -/** @enum {string} */ -goog.dom.safe.InsertAdjacentHtmlPosition = { - AFTERBEGIN: 'afterbegin', - AFTEREND: 'afterend', - BEFOREBEGIN: 'beforebegin', - BEFOREEND: 'beforeend' -}; - - -/** - * Inserts known-safe HTML into a Node, at the specified position. - * @param {!Node} node The node on which to call insertAdjacentHTML. - * @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where - * to insert the HTML. - * @param {!goog.html.SafeHtml} html The known-safe HTML to insert. - */ -goog.dom.safe.insertAdjacentHtml = function(node, position, html) { - node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrap(html)); -}; - - -/** - * Assigns known-safe HTML to an element's innerHTML property. - * @param {!Element} elem The element whose innerHTML is to be assigned to. - * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. - */ -goog.dom.safe.setInnerHtml = function(elem, html) { - elem.innerHTML = goog.html.SafeHtml.unwrap(html); -}; - - -/** - * Assigns known-safe HTML to an element's outerHTML property. - * @param {!Element} elem The element whose outerHTML is to be assigned to. - * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. - */ -goog.dom.safe.setOuterHtml = function(elem, html) { - elem.outerHTML = goog.html.SafeHtml.unwrap(html); -}; - - -/** - * Writes known-safe HTML to a document. - * @param {!Document} doc The document to be written to. - * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. - */ -goog.dom.safe.documentWrite = function(doc, html) { - doc.write(goog.html.SafeHtml.unwrap(html)); -}; - - -/** - * Safely assigns a URL to an anchor element's href property. - * - * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to - * anchor's href property. If url is of type string however, it is first - * sanitized using goog.html.SafeUrl.sanitize. - * - * Example usage: - * goog.dom.safe.setAnchorHref(anchorEl, url); - * which is a safe alternative to - * anchorEl.href = url; - * The latter can result in XSS vulnerabilities if url is a - * user-/attacker-controlled value. - * - * @param {!HTMLAnchorElement} anchor The anchor element whose href property - * is to be assigned to. - * @param {string|!goog.html.SafeUrl} url The URL to assign. - * @see goog.html.SafeUrl#sanitize - */ -goog.dom.safe.setAnchorHref = function(anchor, url) { - /** @type {!goog.html.SafeUrl} */ - var safeUrl; - if (url instanceof goog.html.SafeUrl) { - safeUrl = url; - } else { - safeUrl = goog.html.SafeUrl.sanitize(url); - } - anchor.href = goog.html.SafeUrl.unwrap(safeUrl); -}; - - -/** - * Safely assigns a URL to an embed element's src property. - * - * Example usage: - * goog.dom.safe.setEmbedSrc(embedEl, url); - * which is a safe alternative to - * embedEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLEmbedElement} embed The embed element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setEmbedSrc = function(embed, url) { - embed.src = goog.html.TrustedResourceUrl.unwrap(url); -}; - - -/** - * Safely assigns a URL to a frame element's src property. - * - * Example usage: - * goog.dom.safe.setFrameSrc(frameEl, url); - * which is a safe alternative to - * frameEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLFrameElement} frame The frame element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setFrameSrc = function(frame, url) { - frame.src = goog.html.TrustedResourceUrl.unwrap(url); -}; - - -/** - * Safely assigns a URL to an iframe element's src property. - * - * Example usage: - * goog.dom.safe.setIframeSrc(iframeEl, url); - * which is a safe alternative to - * iframeEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLIFrameElement} iframe The iframe element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setIframeSrc = function(iframe, url) { - iframe.src = goog.html.TrustedResourceUrl.unwrap(url); -}; - - -/** - * Safely sets a link element's href and rel properties. Whether or not - * the URL assigned to href has to be a goog.html.TrustedResourceUrl - * depends on the value of the rel property. If rel contains "stylesheet" - * then a TrustedResourceUrl is required. - * - * Example usage: - * goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet'); - * which is a safe alternative to - * linkEl.rel = 'stylesheet'; - * linkEl.href = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLLinkElement} link The link element whose href property - * is to be assigned to. - * @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL - * to assign to the href property. Must be a TrustedResourceUrl if the - * value assigned to rel contains "stylesheet". A string value is - * sanitized with goog.html.SafeUrl.sanitize. - * @param {string} rel The value to assign to the rel property. - * @throws {Error} if rel contains "stylesheet" and url is not a - * TrustedResourceUrl - * @see goog.html.SafeUrl#sanitize - */ -goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) { - link.rel = rel; - if (goog.string.caseInsensitiveContains(rel, 'stylesheet')) { - goog.asserts.assert( - url instanceof goog.html.TrustedResourceUrl, - 'URL must be TrustedResourceUrl because "rel" contains "stylesheet"'); - link.href = goog.html.TrustedResourceUrl.unwrap(url); - } else if (url instanceof goog.html.TrustedResourceUrl) { - link.href = goog.html.TrustedResourceUrl.unwrap(url); - } else if (url instanceof goog.html.SafeUrl) { - link.href = goog.html.SafeUrl.unwrap(url); - } else { // string - // SafeUrl.sanitize must return legitimate SafeUrl when passed a string. - link.href = goog.html.SafeUrl.sanitize(url).getTypedStringValue(); - } -}; - - -/** - * Safely assigns a URL to an object element's data property. - * - * Example usage: - * goog.dom.safe.setObjectData(objectEl, url); - * which is a safe alternative to - * objectEl.data = url; - * The latter can result in loading untrusted code unless setit is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLObjectElement} object The object element whose data property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setObjectData = function(object, url) { - object.data = goog.html.TrustedResourceUrl.unwrap(url); -}; - - -/** - * Safely assigns a URL to an iframe element's src property. - * - * Example usage: - * goog.dom.safe.setScriptSrc(scriptEl, url); - * which is a safe alternative to - * scriptEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLScriptElement} script The script element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setScriptSrc = function(script, url) { - script.src = goog.html.TrustedResourceUrl.unwrap(url); -}; - - -/** - * Safely assigns a URL to a Location object's href property. - * - * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to - * loc's href property. If url is of type string however, it is first sanitized - * using goog.html.SafeUrl.sanitize. - * - * Example usage: - * goog.dom.safe.setLocationHref(document.location, redirectUrl); - * which is a safe alternative to - * document.location.href = redirectUrl; - * The latter can result in XSS vulnerabilities if redirectUrl is a - * user-/attacker-controlled value. - * - * @param {!Location} loc The Location object whose href property is to be - * assigned to. - * @param {string|!goog.html.SafeUrl} url The URL to assign. - * @see goog.html.SafeUrl#sanitize - */ -goog.dom.safe.setLocationHref = function(loc, url) { - /** @type {!goog.html.SafeUrl} */ - var safeUrl; - if (url instanceof goog.html.SafeUrl) { - safeUrl = url; - } else { - safeUrl = goog.html.SafeUrl.sanitize(url); - } - loc.href = goog.html.SafeUrl.unwrap(safeUrl); -}; - - -/** - * Safely opens a URL in a new window (via window.open). - * - * If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to - * window.open. If url is of type string however, it is first sanitized - * using goog.html.SafeUrl.sanitize. - * - * Note that this function does not prevent leakages via the referer that is - * sent by window.open. It is advised to only use this to open 1st party URLs. - * - * Example usage: - * goog.dom.safe.openInWindow(url); - * which is a safe alternative to - * window.open(url); - * The latter can result in XSS vulnerabilities if redirectUrl is a - * user-/attacker-controlled value. - * - * @param {string|!goog.html.SafeUrl} url The URL to open. - * @param {Window=} opt_openerWin Window of which to call the .open() method. - * Defaults to the global window. - * @param {!goog.string.Const=} opt_name Name of the window to open in. Can be - * _top, etc as allowed by window.open(). - * @param {string=} opt_specs Comma-separated list of specifications, same as - * in window.open(). - * @param {boolean=} opt_replace Whether to replace the current entry in browser - * history, same as in window.open(). - * @return {Window} Window the url was opened in. - */ -goog.dom.safe.openInWindow = function( - url, opt_openerWin, opt_name, opt_specs, opt_replace) { - /** @type {!goog.html.SafeUrl} */ - var safeUrl; - if (url instanceof goog.html.SafeUrl) { - safeUrl = url; - } else { - safeUrl = goog.html.SafeUrl.sanitize(url); - } - var win = opt_openerWin || window; - return win.open(goog.html.SafeUrl.unwrap(safeUrl), - // If opt_name is undefined, simply passing that in to open() causes IE to - // reuse the current window instead of opening a new one. Thus we pass '' - // in instead, which according to spec opens a new window. See - // https://html.spec.whatwg.org/multipage/browsers.html#dom-open . - opt_name ? goog.string.Const.unwrap(opt_name) : '', - opt_specs, opt_replace); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A utility class for representing two-dimensional positions. - */ - - -goog.provide('goog.math.Coordinate'); - -goog.require('goog.math'); - - - -/** - * Class for representing coordinates and positions. - * @param {number=} opt_x Left, defaults to 0. - * @param {number=} opt_y Top, defaults to 0. - * @struct - * @constructor - */ -goog.math.Coordinate = function(opt_x, opt_y) { - /** - * X-value - * @type {number} - */ - this.x = goog.isDef(opt_x) ? opt_x : 0; - - /** - * Y-value - * @type {number} - */ - this.y = goog.isDef(opt_y) ? opt_y : 0; -}; - - -/** - * Returns a new copy of the coordinate. - * @return {!goog.math.Coordinate} A clone of this coordinate. - */ -goog.math.Coordinate.prototype.clone = function() { - return new goog.math.Coordinate(this.x, this.y); -}; - - -if (goog.DEBUG) { - /** - * Returns a nice string representing the coordinate. - * @return {string} In the form (50, 73). - * @override - */ - goog.math.Coordinate.prototype.toString = function() { - return '(' + this.x + ', ' + this.y + ')'; - }; -} - - -/** - * Compares coordinates for equality. - * @param {goog.math.Coordinate} a A Coordinate. - * @param {goog.math.Coordinate} b A Coordinate. - * @return {boolean} True iff the coordinates are equal, or if both are null. - */ -goog.math.Coordinate.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.x == b.x && a.y == b.y; -}; - - -/** - * Returns the distance between two coordinates. - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {number} The distance between {@code a} and {@code b}. - */ -goog.math.Coordinate.distance = function(a, b) { - var dx = a.x - b.x; - var dy = a.y - b.y; - return Math.sqrt(dx * dx + dy * dy); -}; - - -/** - * Returns the magnitude of a coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @return {number} The distance between the origin and {@code a}. - */ -goog.math.Coordinate.magnitude = function(a) { - return Math.sqrt(a.x * a.x + a.y * a.y); -}; - - -/** - * Returns the angle from the origin to a coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @return {number} The angle, in degrees, clockwise from the positive X - * axis to {@code a}. - */ -goog.math.Coordinate.azimuth = function(a) { - return goog.math.angle(0, 0, a.x, a.y); -}; - - -/** - * Returns the squared distance between two coordinates. Squared distances can - * be used for comparisons when the actual value is not required. - * - * Performance note: eliminating the square root is an optimization often used - * in lower-level languages, but the speed difference is not nearly as - * pronounced in JavaScript (only a few percent.) - * - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {number} The squared distance between {@code a} and {@code b}. - */ -goog.math.Coordinate.squaredDistance = function(a, b) { - var dx = a.x - b.x; - var dy = a.y - b.y; - return dx * dx + dy * dy; -}; - - -/** - * Returns the difference between two coordinates as a new - * goog.math.Coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {!goog.math.Coordinate} A Coordinate representing the difference - * between {@code a} and {@code b}. - */ -goog.math.Coordinate.difference = function(a, b) { - return new goog.math.Coordinate(a.x - b.x, a.y - b.y); -}; - - -/** - * Returns the sum of two coordinates as a new goog.math.Coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {!goog.math.Coordinate} A Coordinate representing the sum of the two - * coordinates. - */ -goog.math.Coordinate.sum = function(a, b) { - return new goog.math.Coordinate(a.x + b.x, a.y + b.y); -}; - - -/** - * Rounds the x and y fields to the next larger integer values. - * @return {!goog.math.Coordinate} This coordinate with ceil'd fields. - */ -goog.math.Coordinate.prototype.ceil = function() { - this.x = Math.ceil(this.x); - this.y = Math.ceil(this.y); - return this; -}; - - -/** - * Rounds the x and y fields to the next smaller integer values. - * @return {!goog.math.Coordinate} This coordinate with floored fields. - */ -goog.math.Coordinate.prototype.floor = function() { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - return this; -}; - - -/** - * Rounds the x and y fields to the nearest integer values. - * @return {!goog.math.Coordinate} This coordinate with rounded fields. - */ -goog.math.Coordinate.prototype.round = function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; -}; - - -/** - * Translates this box by the given offsets. If a {@code goog.math.Coordinate} - * is given, then the x and y values are translated by the coordinate's x and y. - * Otherwise, x and y are translated by {@code tx} and {@code opt_ty} - * respectively. - * @param {number|goog.math.Coordinate} tx The value to translate x by or the - * the coordinate to translate this coordinate by. - * @param {number=} opt_ty The value to translate y by. - * @return {!goog.math.Coordinate} This coordinate after translating. - */ -goog.math.Coordinate.prototype.translate = function(tx, opt_ty) { - if (tx instanceof goog.math.Coordinate) { - this.x += tx.x; - this.y += tx.y; - } else { - this.x += tx; - if (goog.isNumber(opt_ty)) { - this.y += opt_ty; - } - } - return this; -}; - - -/** - * Scales this coordinate by the given scale factors. The x and y values are - * scaled by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} - * is not given, then {@code sx} is used for both x and y. - * @param {number} sx The scale factor to use for the x dimension. - * @param {number=} opt_sy The scale factor to use for the y dimension. - * @return {!goog.math.Coordinate} This coordinate after scaling. - */ -goog.math.Coordinate.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.x *= sx; - this.y *= sy; - return this; -}; - - -/** - * Rotates this coordinate clockwise about the origin (or, optionally, the given - * center) by the given angle, in radians. - * @param {number} radians The angle by which to rotate this coordinate - * clockwise about the given center, in radians. - * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults - * to (0, 0) if not given. - */ -goog.math.Coordinate.prototype.rotateRadians = function(radians, opt_center) { - var center = opt_center || new goog.math.Coordinate(0, 0); - - var x = this.x; - var y = this.y; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - - this.x = (x - center.x) * cos - (y - center.y) * sin + center.x; - this.y = (x - center.x) * sin + (y - center.y) * cos + center.y; -}; - - -/** - * Rotates this coordinate clockwise about the origin (or, optionally, the given - * center) by the given angle, in degrees. - * @param {number} degrees The angle by which to rotate this coordinate - * clockwise about the given center, in degrees. - * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults - * to (0, 0) if not given. - */ -goog.math.Coordinate.prototype.rotateDegrees = function(degrees, opt_center) { - this.rotateRadians(goog.math.toRadians(degrees), opt_center); -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A utility class for representing two-dimensional sizes. - * @author brenneman@google.com (Shawn Brenneman) - */ - - -goog.provide('goog.math.Size'); - - - -/** - * Class for representing sizes consisting of a width and height. Undefined - * width and height support is deprecated and results in compiler warning. - * @param {number} width Width. - * @param {number} height Height. - * @struct - * @constructor - */ -goog.math.Size = function(width, height) { - /** - * Width - * @type {number} - */ - this.width = width; - - /** - * Height - * @type {number} - */ - this.height = height; -}; - - -/** - * Compares sizes for equality. - * @param {goog.math.Size} a A Size. - * @param {goog.math.Size} b A Size. - * @return {boolean} True iff the sizes have equal widths and equal - * heights, or if both are null. - */ -goog.math.Size.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.width == b.width && a.height == b.height; -}; - - -/** - * @return {!goog.math.Size} A new copy of the Size. - */ -goog.math.Size.prototype.clone = function() { - return new goog.math.Size(this.width, this.height); -}; - - -if (goog.DEBUG) { - /** - * Returns a nice string representing size. - * @return {string} In the form (50 x 73). - * @override - */ - goog.math.Size.prototype.toString = function() { - return '(' + this.width + ' x ' + this.height + ')'; - }; -} - - -/** - * @return {number} The longer of the two dimensions in the size. - */ -goog.math.Size.prototype.getLongest = function() { - return Math.max(this.width, this.height); -}; - - -/** - * @return {number} The shorter of the two dimensions in the size. - */ -goog.math.Size.prototype.getShortest = function() { - return Math.min(this.width, this.height); -}; - - -/** - * @return {number} The area of the size (width * height). - */ -goog.math.Size.prototype.area = function() { - return this.width * this.height; -}; - - -/** - * @return {number} The perimeter of the size (width + height) * 2. - */ -goog.math.Size.prototype.perimeter = function() { - return (this.width + this.height) * 2; -}; - - -/** - * @return {number} The ratio of the size's width to its height. - */ -goog.math.Size.prototype.aspectRatio = function() { - return this.width / this.height; -}; - - -/** - * @return {boolean} True if the size has zero area, false if both dimensions - * are non-zero numbers. - */ -goog.math.Size.prototype.isEmpty = function() { - return !this.area(); -}; - - -/** - * Clamps the width and height parameters upward to integer values. - * @return {!goog.math.Size} This size with ceil'd components. - */ -goog.math.Size.prototype.ceil = function() { - this.width = Math.ceil(this.width); - this.height = Math.ceil(this.height); - return this; -}; - - -/** - * @param {!goog.math.Size} target The target size. - * @return {boolean} True if this Size is the same size or smaller than the - * target size in both dimensions. - */ -goog.math.Size.prototype.fitsInside = function(target) { - return this.width <= target.width && this.height <= target.height; -}; - - -/** - * Clamps the width and height parameters downward to integer values. - * @return {!goog.math.Size} This size with floored components. - */ -goog.math.Size.prototype.floor = function() { - this.width = Math.floor(this.width); - this.height = Math.floor(this.height); - return this; -}; - - -/** - * Rounds the width and height parameters to integer values. - * @return {!goog.math.Size} This size with rounded components. - */ -goog.math.Size.prototype.round = function() { - this.width = Math.round(this.width); - this.height = Math.round(this.height); - return this; -}; - - -/** - * Scales this size by the given scale factors. The width and height are scaled - * by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} is not - * given, then {@code sx} is used for both the width and height. - * @param {number} sx The scale factor to use for the width. - * @param {number=} opt_sy The scale factor to use for the height. - * @return {!goog.math.Size} This Size object after scaling. - */ -goog.math.Size.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.width *= sx; - this.height *= sy; - return this; -}; - - -/** - * Uniformly scales the size to perfectly cover the dimensions of a given size. - * If the size is already larger than the target, it will be scaled down to the - * minimum size at which it still covers the entire target. The original aspect - * ratio will be preserved. - * - * This function assumes that both Sizes contain strictly positive dimensions. - * @param {!goog.math.Size} target The target size. - * @return {!goog.math.Size} This Size object, after optional scaling. - */ -goog.math.Size.prototype.scaleToCover = function(target) { - var s = this.aspectRatio() <= target.aspectRatio() ? - target.width / this.width : - target.height / this.height; - - return this.scale(s); -}; - - -/** - * Uniformly scales the size to fit inside the dimensions of a given size. The - * original aspect ratio will be preserved. - * - * This function assumes that both Sizes contain strictly positive dimensions. - * @param {!goog.math.Size} target The target size. - * @return {!goog.math.Size} This Size object, after optional scaling. - */ -goog.math.Size.prototype.scaleToFit = function(target) { - var s = this.aspectRatio() > target.aspectRatio() ? - target.width / this.width : - target.height / this.height; - - return this.scale(s); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for manipulating the browser's Document Object Model - * Inspiration taken *heavily* from mochikit (http://mochikit.com/). - * - * You can use {@link goog.dom.DomHelper} to create new dom helpers that refer - * to a different document object. This is useful if you are working with - * frames or multiple windows. - * - * @author arv@google.com (Erik Arvidsson) - */ - - -// TODO(arv): Rename/refactor getTextContent and getRawTextContent. The problem -// is that getTextContent should mimic the DOM3 textContent. We should add a -// getInnerText (or getText) which tries to return the visible text, innerText. - - -goog.provide('goog.dom'); -goog.provide('goog.dom.Appendable'); -goog.provide('goog.dom.DomHelper'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.BrowserFeature'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.safe'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Size'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.string.Unicode'); -goog.require('goog.userAgent'); - - -/** - * @define {boolean} Whether we know at compile time that the browser is in - * quirks mode. - */ -goog.define('goog.dom.ASSUME_QUIRKS_MODE', false); - - -/** - * @define {boolean} Whether we know at compile time that the browser is in - * standards compliance mode. - */ -goog.define('goog.dom.ASSUME_STANDARDS_MODE', false); - - -/** - * Whether we know the compatibility mode at compile time. - * @type {boolean} - * @private - */ -goog.dom.COMPAT_MODE_KNOWN_ = - goog.dom.ASSUME_QUIRKS_MODE || goog.dom.ASSUME_STANDARDS_MODE; - - -/** - * Gets the DomHelper object for the document where the element resides. - * @param {(Node|Window)=} opt_element If present, gets the DomHelper for this - * element. - * @return {!goog.dom.DomHelper} The DomHelper. - */ -goog.dom.getDomHelper = function(opt_element) { - return opt_element ? - new goog.dom.DomHelper(goog.dom.getOwnerDocument(opt_element)) : - (goog.dom.defaultDomHelper_ || - (goog.dom.defaultDomHelper_ = new goog.dom.DomHelper())); -}; - - -/** - * Cached default DOM helper. - * @type {goog.dom.DomHelper} - * @private - */ -goog.dom.defaultDomHelper_; - - -/** - * Gets the document object being used by the dom library. - * @return {!Document} Document object. - */ -goog.dom.getDocument = function() { - return document; -}; - - -/** - * Gets an element from the current document by element id. - * - * If an Element is passed in, it is returned. - * - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. - */ -goog.dom.getElement = function(element) { - return goog.dom.getElementHelper_(document, element); -}; - - -/** - * Gets an element by id from the given document (if present). - * If an element is given, it is returned. - * @param {!Document} doc - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The resulting element. - * @private - */ -goog.dom.getElementHelper_ = function(doc, element) { - return goog.isString(element) ? - doc.getElementById(element) : - element; -}; - - -/** - * Gets an element by id, asserting that the element is found. - * - * This is used when an element is expected to exist, and should fail with - * an assertion error if it does not (if assertions are enabled). - * - * @param {string} id Element ID. - * @return {!Element} The element with the given ID, if it exists. - */ -goog.dom.getRequiredElement = function(id) { - return goog.dom.getRequiredElementHelper_(document, id); -}; - - -/** - * Helper function for getRequiredElementHelper functions, both static and - * on DomHelper. Asserts the element with the given id exists. - * @param {!Document} doc - * @param {string} id - * @return {!Element} The element with the given ID, if it exists. - * @private - */ -goog.dom.getRequiredElementHelper_ = function(doc, id) { - // To prevent users passing in Elements as is permitted in getElement(). - goog.asserts.assertString(id); - var element = goog.dom.getElementHelper_(doc, id); - element = goog.asserts.assertElement(element, - 'No element found with id: ' + id); - return element; -}; - - -/** - * Alias for getElement. - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. - * @deprecated Use {@link goog.dom.getElement} instead. - */ -goog.dom.$ = goog.dom.getElement; - - -/** - * Looks up elements by both tag and class name, using browser native functions - * ({@code querySelectorAll}, {@code getElementsByTagName} or - * {@code getElementsByClassName}) where possible. This function - * is a useful, if limited, way of collecting a list of DOM elements - * with certain characteristics. {@code goog.dom.query} offers a - * more powerful and general solution which allows matching on CSS3 - * selector expressions, but at increased cost in code size. If all you - * need is particular tags belonging to a single class, this function - * is fast and sleek. - * - * Note that tag names are case sensitive in the SVG namespace, and this - * function converts opt_tag to uppercase for comparisons. For queries in the - * SVG namespace you should use querySelector or querySelectorAll instead. - * https://bugzilla.mozilla.org/show_bug.cgi?id=963870 - * https://bugs.webkit.org/show_bug.cgi?id=83438 - * - * @see {goog.dom.query} - * - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - */ -goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) { - return goog.dom.getElementsByTagNameAndClass_(document, opt_tag, opt_class, - opt_el); -}; - - -/** - * Returns a static, array-like list of the elements with the provided - * className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } The items found with the class name provided. - */ -goog.dom.getElementsByClass = function(className, opt_el) { - var parent = opt_el || document; - if (goog.dom.canUseQuerySelector_(parent)) { - return parent.querySelectorAll('.' + className); - } - return goog.dom.getElementsByTagNameAndClass_( - document, '*', className, opt_el); -}; - - -/** - * Returns the first element with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {Element|Document=} opt_el Optional element to look in. - * @return {Element} The first item with the class name provided. - */ -goog.dom.getElementByClass = function(className, opt_el) { - var parent = opt_el || document; - var retVal = null; - if (parent.getElementsByClassName) { - retVal = parent.getElementsByClassName(className)[0]; - } else if (goog.dom.canUseQuerySelector_(parent)) { - retVal = parent.querySelector('.' + className); - } else { - retVal = goog.dom.getElementsByTagNameAndClass_( - document, '*', className, opt_el)[0]; - } - return retVal || null; -}; - - -/** - * Ensures an element with the given className exists, and then returns the - * first element with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {!Element|!Document=} opt_root Optional element or document to look - * in. - * @return {!Element} The first item with the class name provided. - * @throws {goog.asserts.AssertionError} Thrown if no element is found. - */ -goog.dom.getRequiredElementByClass = function(className, opt_root) { - var retValue = goog.dom.getElementByClass(className, opt_root); - return goog.asserts.assert(retValue, - 'No element found with className: ' + className); -}; - - -/** - * Prefer the standardized (http://www.w3.org/TR/selectors-api/), native and - * fast W3C Selectors API. - * @param {!(Element|Document)} parent The parent document object. - * @return {boolean} whether or not we can use parent.querySelector* APIs. - * @private - */ -goog.dom.canUseQuerySelector_ = function(parent) { - return !!(parent.querySelectorAll && parent.querySelector); -}; - - -/** - * Helper for {@code getElementsByTagNameAndClass}. - * @param {!Document} doc The document to get the elements in. - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - * @private - */ -goog.dom.getElementsByTagNameAndClass_ = function(doc, opt_tag, opt_class, - opt_el) { - var parent = opt_el || doc; - var tagName = (opt_tag && opt_tag != '*') ? opt_tag.toUpperCase() : ''; - - if (goog.dom.canUseQuerySelector_(parent) && - (tagName || opt_class)) { - var query = tagName + (opt_class ? '.' + opt_class : ''); - return parent.querySelectorAll(query); - } - - // Use the native getElementsByClassName if available, under the assumption - // that even when the tag name is specified, there will be fewer elements to - // filter through when going by class than by tag name - if (opt_class && parent.getElementsByClassName) { - var els = parent.getElementsByClassName(opt_class); - - if (tagName) { - var arrayLike = {}; - var len = 0; - - // Filter for specific tags if requested. - for (var i = 0, el; el = els[i]; i++) { - if (tagName == el.nodeName) { - arrayLike[len++] = el; - } - } - arrayLike.length = len; - - return arrayLike; - } else { - return els; - } - } - - var els = parent.getElementsByTagName(tagName || '*'); - - if (opt_class) { - var arrayLike = {}; - var len = 0; - for (var i = 0, el; el = els[i]; i++) { - var className = el.className; - // Check if className has a split function since SVG className does not. - if (typeof className.split == 'function' && - goog.array.contains(className.split(/\s+/), opt_class)) { - arrayLike[len++] = el; - } - } - arrayLike.length = len; - return arrayLike; - } else { - return els; - } -}; - - -/** - * Alias for {@code getElementsByTagNameAndClass}. - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {Element=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - * @deprecated Use {@link goog.dom.getElementsByTagNameAndClass} instead. - */ -goog.dom.$$ = goog.dom.getElementsByTagNameAndClass; - - -/** - * Sets multiple properties on a node. - * @param {Element} element DOM node to set properties on. - * @param {Object} properties Hash of property:value pairs. - */ -goog.dom.setProperties = function(element, properties) { - goog.object.forEach(properties, function(val, key) { - if (key == 'style') { - element.style.cssText = val; - } else if (key == 'class') { - element.className = val; - } else if (key == 'for') { - element.htmlFor = val; - } else if (goog.dom.DIRECT_ATTRIBUTE_MAP_.hasOwnProperty(key)) { - element.setAttribute(goog.dom.DIRECT_ATTRIBUTE_MAP_[key], val); - } else if (goog.string.startsWith(key, 'aria-') || - goog.string.startsWith(key, 'data-')) { - element.setAttribute(key, val); - } else { - element[key] = val; - } - }); -}; - - -/** - * Map of attributes that should be set using - * element.setAttribute(key, val) instead of element[key] = val. Used - * by goog.dom.setProperties. - * - * @private {!Object<string, string>} - * @const - */ -goog.dom.DIRECT_ATTRIBUTE_MAP_ = { - 'cellpadding': 'cellPadding', - 'cellspacing': 'cellSpacing', - 'colspan': 'colSpan', - 'frameborder': 'frameBorder', - 'height': 'height', - 'maxlength': 'maxLength', - 'role': 'role', - 'rowspan': 'rowSpan', - 'type': 'type', - 'usemap': 'useMap', - 'valign': 'vAlign', - 'width': 'width' -}; - - -/** - * Gets the dimensions of the viewport. - * - * Gecko Standards mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Width of viewport including scrollbar. - * body.clientWidth Width of body element. - * - * docEl.clientHeight Height of viewport excluding scrollbar. - * win.innerHeight Height of viewport including scrollbar. - * body.clientHeight Height of document. - * - * Gecko Backwards compatible mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Width of viewport including scrollbar. - * body.clientWidth Width of viewport excluding scrollbar. - * - * docEl.clientHeight Height of document. - * win.innerHeight Height of viewport including scrollbar. - * body.clientHeight Height of viewport excluding scrollbar. - * - * IE6/7 Standards mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Undefined. - * body.clientWidth Width of body element. - * - * docEl.clientHeight Height of viewport excluding scrollbar. - * win.innerHeight Undefined. - * body.clientHeight Height of document element. - * - * IE5 + IE6/7 Backwards compatible mode: - * docEl.clientWidth 0. - * win.innerWidth Undefined. - * body.clientWidth Width of viewport excluding scrollbar. - * - * docEl.clientHeight 0. - * win.innerHeight Undefined. - * body.clientHeight Height of viewport excluding scrollbar. - * - * Opera 9 Standards and backwards compatible mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Width of viewport including scrollbar. - * body.clientWidth Width of viewport excluding scrollbar. - * - * docEl.clientHeight Height of document. - * win.innerHeight Height of viewport including scrollbar. - * body.clientHeight Height of viewport excluding scrollbar. - * - * WebKit: - * Safari 2 - * docEl.clientHeight Same as scrollHeight. - * docEl.clientWidth Same as innerWidth. - * win.innerWidth Width of viewport excluding scrollbar. - * win.innerHeight Height of the viewport including scrollbar. - * frame.innerHeight Height of the viewport exluding scrollbar. - * - * Safari 3 (tested in 522) - * - * docEl.clientWidth Width of viewport excluding scrollbar. - * docEl.clientHeight Height of viewport excluding scrollbar in strict mode. - * body.clientHeight Height of viewport excluding scrollbar in quirks mode. - * - * @param {Window=} opt_window Optional window element to test. - * @return {!goog.math.Size} Object with values 'width' and 'height'. - */ -goog.dom.getViewportSize = function(opt_window) { - // TODO(arv): This should not take an argument - return goog.dom.getViewportSize_(opt_window || window); -}; - - -/** - * Helper for {@code getViewportSize}. - * @param {Window} win The window to get the view port size for. - * @return {!goog.math.Size} Object with values 'width' and 'height'. - * @private - */ -goog.dom.getViewportSize_ = function(win) { - var doc = win.document; - var el = goog.dom.isCss1CompatMode_(doc) ? doc.documentElement : doc.body; - return new goog.math.Size(el.clientWidth, el.clientHeight); -}; - - -/** - * Calculates the height of the document. - * - * @return {number} The height of the current document. - */ -goog.dom.getDocumentHeight = function() { - return goog.dom.getDocumentHeight_(window); -}; - - -/** - * Calculates the height of the document of the given window. - * - * Function code copied from the opensocial gadget api: - * gadgets.window.adjustHeight(opt_height) - * - * @private - * @param {!Window} win The window whose document height to retrieve. - * @return {number} The height of the document of the given window. - */ -goog.dom.getDocumentHeight_ = function(win) { - // NOTE(eae): This method will return the window size rather than the document - // size in webkit quirks mode. - var doc = win.document; - var height = 0; - - if (doc) { - // Calculating inner content height is hard and different between - // browsers rendering in Strict vs. Quirks mode. We use a combination of - // three properties within document.body and document.documentElement: - // - scrollHeight - // - offsetHeight - // - clientHeight - // These values differ significantly between browsers and rendering modes. - // But there are patterns. It just takes a lot of time and persistence - // to figure out. - - var body = doc.body; - var docEl = /** @type {!HTMLElement} */ (doc.documentElement); - if (!(docEl && body)) { - return 0; - } - - // Get the height of the viewport - var vh = goog.dom.getViewportSize_(win).height; - if (goog.dom.isCss1CompatMode_(doc) && docEl.scrollHeight) { - // In Strict mode: - // The inner content height is contained in either: - // document.documentElement.scrollHeight - // document.documentElement.offsetHeight - // Based on studying the values output by different browsers, - // use the value that's NOT equal to the viewport height found above. - height = docEl.scrollHeight != vh ? - docEl.scrollHeight : docEl.offsetHeight; - } else { - // In Quirks mode: - // documentElement.clientHeight is equal to documentElement.offsetHeight - // except in IE. In most browsers, document.documentElement can be used - // to calculate the inner content height. - // However, in other browsers (e.g. IE), document.body must be used - // instead. How do we know which one to use? - // If document.documentElement.clientHeight does NOT equal - // document.documentElement.offsetHeight, then use document.body. - var sh = docEl.scrollHeight; - var oh = docEl.offsetHeight; - if (docEl.clientHeight != oh) { - sh = body.scrollHeight; - oh = body.offsetHeight; - } - - // Detect whether the inner content height is bigger or smaller - // than the bounding box (viewport). If bigger, take the larger - // value. If smaller, take the smaller value. - if (sh > vh) { - // Content is larger - height = sh > oh ? sh : oh; - } else { - // Content is smaller - height = sh < oh ? sh : oh; - } - } - } - - return height; -}; - - -/** - * Gets the page scroll distance as a coordinate object. - * - * @param {Window=} opt_window Optional window element to test. - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. - * @deprecated Use {@link goog.dom.getDocumentScroll} instead. - */ -goog.dom.getPageScroll = function(opt_window) { - var win = opt_window || goog.global || window; - return goog.dom.getDomHelper(win.document).getDocumentScroll(); -}; - - -/** - * Gets the document scroll distance as a coordinate object. - * - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. - */ -goog.dom.getDocumentScroll = function() { - return goog.dom.getDocumentScroll_(document); -}; - - -/** - * Helper for {@code getDocumentScroll}. - * - * @param {!Document} doc The document to get the scroll for. - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. - * @private - */ -goog.dom.getDocumentScroll_ = function(doc) { - var el = goog.dom.getDocumentScrollElement_(doc); - var win = goog.dom.getWindow_(doc); - if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('10') && - win.pageYOffset != el.scrollTop) { - // The keyboard on IE10 touch devices shifts the page using the pageYOffset - // without modifying scrollTop. For this case, we want the body scroll - // offsets. - return new goog.math.Coordinate(el.scrollLeft, el.scrollTop); - } - return new goog.math.Coordinate(win.pageXOffset || el.scrollLeft, - win.pageYOffset || el.scrollTop); -}; - - -/** - * Gets the document scroll element. - * @return {!Element} Scrolling element. - */ -goog.dom.getDocumentScrollElement = function() { - return goog.dom.getDocumentScrollElement_(document); -}; - - -/** - * Helper for {@code getDocumentScrollElement}. - * @param {!Document} doc The document to get the scroll element for. - * @return {!Element} Scrolling element. - * @private - */ -goog.dom.getDocumentScrollElement_ = function(doc) { - // Old WebKit needs body.scrollLeft in both quirks mode and strict mode. We - // also default to the documentElement if the document does not have a body - // (e.g. a SVG document). - // Uses http://dev.w3.org/csswg/cssom-view/#dom-document-scrollingelement to - // avoid trying to guess about browser behavior from the UA string. - if (doc.scrollingElement) { - return doc.scrollingElement; - } - if (!goog.userAgent.WEBKIT && goog.dom.isCss1CompatMode_(doc)) { - return doc.documentElement; - } - return doc.body || doc.documentElement; -}; - - -/** - * Gets the window object associated with the given document. - * - * @param {Document=} opt_doc Document object to get window for. - * @return {!Window} The window associated with the given document. - */ -goog.dom.getWindow = function(opt_doc) { - // TODO(arv): This should not take an argument. - return opt_doc ? goog.dom.getWindow_(opt_doc) : window; -}; - - -/** - * Helper for {@code getWindow}. - * - * @param {!Document} doc Document object to get window for. - * @return {!Window} The window associated with the given document. - * @private - */ -goog.dom.getWindow_ = function(doc) { - return doc.parentWindow || doc.defaultView; -}; - - -/** - * Returns a dom node with a set of attributes. This function accepts varargs - * for subsequent nodes to be added. Subsequent nodes will be added to the - * first node as childNodes. - * - * So: - * <code>createDom('div', null, createDom('p'), createDom('p'));</code> - * would return a div with two child paragraphs - * - * @param {string} tagName Tag to create. - * @param {(Object|Array<string>|string)=} opt_attributes If object, then a map - * of name-value pairs for attributes. If a string, then this is the - * className of the new element. If an array, the elements will be joined - * together as the className of the new element. - * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or - * strings for text nodes. If one of the var_args is an array or NodeList, - * its elements will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. - */ -goog.dom.createDom = function(tagName, opt_attributes, var_args) { - return goog.dom.createDom_(document, arguments); -}; - - -/** - * Helper for {@code createDom}. - * @param {!Document} doc The document to create the DOM in. - * @param {!Arguments} args Argument object passed from the callers. See - * {@code goog.dom.createDom} for details. - * @return {!Element} Reference to a DOM node. - * @private - */ -goog.dom.createDom_ = function(doc, args) { - var tagName = args[0]; - var attributes = args[1]; - - // Internet Explorer is dumb: - // name: https://msdn.microsoft.com/en-us/library/ms534184(v=vs.85).aspx - // type: https://msdn.microsoft.com/en-us/library/ms534700(v=vs.85).aspx - // Also does not allow setting of 'type' attribute on 'input' or 'button'. - if (!goog.dom.BrowserFeature.CAN_ADD_NAME_OR_TYPE_ATTRIBUTES && attributes && - (attributes.name || attributes.type)) { - var tagNameArr = ['<', tagName]; - if (attributes.name) { - tagNameArr.push(' name="', goog.string.htmlEscape(attributes.name), '"'); - } - if (attributes.type) { - tagNameArr.push(' type="', goog.string.htmlEscape(attributes.type), '"'); - - // Clone attributes map to remove 'type' without mutating the input. - var clone = {}; - goog.object.extend(clone, attributes); - - // JSCompiler can't see how goog.object.extend added this property, - // because it was essentially added by reflection. - // So it needs to be quoted. - delete clone['type']; - - attributes = clone; - } - tagNameArr.push('>'); - tagName = tagNameArr.join(''); - } - - var element = doc.createElement(tagName); - - if (attributes) { - if (goog.isString(attributes)) { - element.className = attributes; - } else if (goog.isArray(attributes)) { - element.className = attributes.join(' '); - } else { - goog.dom.setProperties(element, attributes); - } - } - - if (args.length > 2) { - goog.dom.append_(doc, element, args, 2); - } - - return element; -}; - - -/** - * Appends a node with text or other nodes. - * @param {!Document} doc The document to create new nodes in. - * @param {!Node} parent The node to append nodes to. - * @param {!Arguments} args The values to add. See {@code goog.dom.append}. - * @param {number} startIndex The index of the array to start from. - * @private - */ -goog.dom.append_ = function(doc, parent, args, startIndex) { - function childHandler(child) { - // TODO(user): More coercion, ala MochiKit? - if (child) { - parent.appendChild(goog.isString(child) ? - doc.createTextNode(child) : child); - } - } - - for (var i = startIndex; i < args.length; i++) { - var arg = args[i]; - // TODO(attila): Fix isArrayLike to return false for a text node. - if (goog.isArrayLike(arg) && !goog.dom.isNodeLike(arg)) { - // If the argument is a node list, not a real array, use a clone, - // because forEach can't be used to mutate a NodeList. - goog.array.forEach(goog.dom.isNodeList(arg) ? - goog.array.toArray(arg) : arg, - childHandler); - } else { - childHandler(arg); - } - } -}; - - -/** - * Alias for {@code createDom}. - * @param {string} tagName Tag to create. - * @param {(string|Object)=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. - * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or - * strings for text nodes. If one of the var_args is an array, its - * children will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. - * @deprecated Use {@link goog.dom.createDom} instead. - */ -goog.dom.$dom = goog.dom.createDom; - - -/** - * Creates a new element. - * @param {string} name Tag name. - * @return {!Element} The new element. - */ -goog.dom.createElement = function(name) { - return document.createElement(name); -}; - - -/** - * Creates a new text node. - * @param {number|string} content Content. - * @return {!Text} The new text node. - */ -goog.dom.createTextNode = function(content) { - return document.createTextNode(String(content)); -}; - - -/** - * Create a table. - * @param {number} rows The number of rows in the table. Must be >= 1. - * @param {number} columns The number of columns in the table. Must be >= 1. - * @param {boolean=} opt_fillWithNbsp If true, fills table entries with - * {@code goog.string.Unicode.NBSP} characters. - * @return {!Element} The created table. - */ -goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) { - // TODO(user): Return HTMLTableElement, also in prototype function. - // Callers need to be updated to e.g. not assign numbers to table.cellSpacing. - return goog.dom.createTable_(document, rows, columns, !!opt_fillWithNbsp); -}; - - -/** - * Create a table. - * @param {!Document} doc Document object to use to create the table. - * @param {number} rows The number of rows in the table. Must be >= 1. - * @param {number} columns The number of columns in the table. Must be >= 1. - * @param {boolean} fillWithNbsp If true, fills table entries with - * {@code goog.string.Unicode.NBSP} characters. - * @return {!HTMLTableElement} The created table. - * @private - */ -goog.dom.createTable_ = function(doc, rows, columns, fillWithNbsp) { - var table = /** @type {!HTMLTableElement} */ - (doc.createElement(goog.dom.TagName.TABLE)); - var tbody = table.appendChild(doc.createElement(goog.dom.TagName.TBODY)); - for (var i = 0; i < rows; i++) { - var tr = doc.createElement(goog.dom.TagName.TR); - for (var j = 0; j < columns; j++) { - var td = doc.createElement(goog.dom.TagName.TD); - // IE <= 9 will create a text node if we set text content to the empty - // string, so we avoid doing it unless necessary. This ensures that the - // same DOM tree is returned on all browsers. - if (fillWithNbsp) { - goog.dom.setTextContent(td, goog.string.Unicode.NBSP); - } - tr.appendChild(td); - } - tbody.appendChild(tr); - } - return table; -}; - - -/** - * Converts HTML markup into a node. - * @param {!goog.html.SafeHtml} html The HTML markup to convert. - * @return {!Node} The resulting node. - */ -goog.dom.safeHtmlToNode = function(html) { - return goog.dom.safeHtmlToNode_(document, html); -}; - - -/** - * Helper for {@code safeHtmlToNode}. - * @param {!Document} doc The document. - * @param {!goog.html.SafeHtml} html The HTML markup to convert. - * @return {!Node} The resulting node. - * @private - */ -goog.dom.safeHtmlToNode_ = function(doc, html) { - var tempDiv = doc.createElement(goog.dom.TagName.DIV); - if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { - goog.dom.safe.setInnerHtml(tempDiv, - goog.html.SafeHtml.concat(goog.html.SafeHtml.create('br'), html)); - tempDiv.removeChild(tempDiv.firstChild); - } else { - goog.dom.safe.setInnerHtml(tempDiv, html); - } - return goog.dom.childrenToNode_(doc, tempDiv); -}; - - -/** - * Converts an HTML string into a document fragment. The string must be - * sanitized in order to avoid cross-site scripting. For example - * {@code goog.dom.htmlToDocumentFragment('<img src=x onerror=alert(0)>')} - * triggers an alert in all browsers, even if the returned document fragment - * is thrown away immediately. - * - * NOTE: This method doesn't work if your htmlString contains elements that - * can't be contained in a <div>. For example, <tr>. - * - * @param {string} htmlString The HTML string to convert. - * @return {!Node} The resulting document fragment. - */ -goog.dom.htmlToDocumentFragment = function(htmlString) { - return goog.dom.htmlToDocumentFragment_(document, htmlString); -}; - - -// TODO(jakubvrana): Merge with {@code safeHtmlToNode_}. -/** - * Helper for {@code htmlToDocumentFragment}. - * - * @param {!Document} doc The document. - * @param {string} htmlString The HTML string to convert. - * @return {!Node} The resulting document fragment. - * @private - */ -goog.dom.htmlToDocumentFragment_ = function(doc, htmlString) { - var tempDiv = doc.createElement(goog.dom.TagName.DIV); - if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { - tempDiv.innerHTML = '<br>' + htmlString; - tempDiv.removeChild(tempDiv.firstChild); - } else { - tempDiv.innerHTML = htmlString; - } - return goog.dom.childrenToNode_(doc, tempDiv); -}; - - -/** - * Helper for {@code htmlToDocumentFragment_}. - * @param {!Document} doc The document. - * @param {!Node} tempDiv The input node. - * @return {!Node} The resulting node. - * @private - */ -goog.dom.childrenToNode_ = function(doc, tempDiv) { - if (tempDiv.childNodes.length == 1) { - return tempDiv.removeChild(tempDiv.firstChild); - } else { - var fragment = doc.createDocumentFragment(); - while (tempDiv.firstChild) { - fragment.appendChild(tempDiv.firstChild); - } - return fragment; - } -}; - - -/** - * Returns true if the browser is in "CSS1-compatible" (standards-compliant) - * mode, false otherwise. - * @return {boolean} True if in CSS1-compatible mode. - */ -goog.dom.isCss1CompatMode = function() { - return goog.dom.isCss1CompatMode_(document); -}; - - -/** - * Returns true if the browser is in "CSS1-compatible" (standards-compliant) - * mode, false otherwise. - * @param {!Document} doc The document to check. - * @return {boolean} True if in CSS1-compatible mode. - * @private - */ -goog.dom.isCss1CompatMode_ = function(doc) { - if (goog.dom.COMPAT_MODE_KNOWN_) { - return goog.dom.ASSUME_STANDARDS_MODE; - } - - return doc.compatMode == 'CSS1Compat'; -}; - - -/** - * Determines if the given node can contain children, intended to be used for - * HTML generation. - * - * IE natively supports node.canHaveChildren but has inconsistent behavior. - * Prior to IE8 the base tag allows children and in IE9 all nodes return true - * for canHaveChildren. - * - * In practice all non-IE browsers allow you to add children to any node, but - * the behavior is inconsistent: - * - * <pre> - * var a = document.createElement(goog.dom.TagName.BR); - * a.appendChild(document.createTextNode('foo')); - * a.appendChild(document.createTextNode('bar')); - * console.log(a.childNodes.length); // 2 - * console.log(a.innerHTML); // Chrome: "", IE9: "foobar", FF3.5: "foobar" - * </pre> - * - * For more information, see: - * http://dev.w3.org/html5/markup/syntax.html#syntax-elements - * - * TODO(user): Rename shouldAllowChildren() ? - * - * @param {Node} node The node to check. - * @return {boolean} Whether the node can contain children. - */ -goog.dom.canHaveChildren = function(node) { - if (node.nodeType != goog.dom.NodeType.ELEMENT) { - return false; - } - switch (/** @type {!Element} */ (node).tagName) { - case goog.dom.TagName.APPLET: - case goog.dom.TagName.AREA: - case goog.dom.TagName.BASE: - case goog.dom.TagName.BR: - case goog.dom.TagName.COL: - case goog.dom.TagName.COMMAND: - case goog.dom.TagName.EMBED: - case goog.dom.TagName.FRAME: - case goog.dom.TagName.HR: - case goog.dom.TagName.IMG: - case goog.dom.TagName.INPUT: - case goog.dom.TagName.IFRAME: - case goog.dom.TagName.ISINDEX: - case goog.dom.TagName.KEYGEN: - case goog.dom.TagName.LINK: - case goog.dom.TagName.NOFRAMES: - case goog.dom.TagName.NOSCRIPT: - case goog.dom.TagName.META: - case goog.dom.TagName.OBJECT: - case goog.dom.TagName.PARAM: - case goog.dom.TagName.SCRIPT: - case goog.dom.TagName.SOURCE: - case goog.dom.TagName.STYLE: - case goog.dom.TagName.TRACK: - case goog.dom.TagName.WBR: - return false; - } - return true; -}; - - -/** - * Appends a child to a node. - * @param {Node} parent Parent. - * @param {Node} child Child. - */ -goog.dom.appendChild = function(parent, child) { - parent.appendChild(child); -}; - - -/** - * Appends a node with text or other nodes. - * @param {!Node} parent The node to append nodes to. - * @param {...goog.dom.Appendable} var_args The things to append to the node. - * If this is a Node it is appended as is. - * If this is a string then a text node is appended. - * If this is an array like object then fields 0 to length - 1 are appended. - */ -goog.dom.append = function(parent, var_args) { - goog.dom.append_(goog.dom.getOwnerDocument(parent), parent, arguments, 1); -}; - - -/** - * Removes all the child nodes on a DOM node. - * @param {Node} node Node to remove children from. - */ -goog.dom.removeChildren = function(node) { - // Note: Iterations over live collections can be slow, this is the fastest - // we could find. The double parenthesis are used to prevent JsCompiler and - // strict warnings. - var child; - while ((child = node.firstChild)) { - node.removeChild(child); - } -}; - - -/** - * Inserts a new node before an existing reference node (i.e. as the previous - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert before. - */ -goog.dom.insertSiblingBefore = function(newNode, refNode) { - if (refNode.parentNode) { - refNode.parentNode.insertBefore(newNode, refNode); - } -}; - - -/** - * Inserts a new node after an existing reference node (i.e. as the next - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert after. - */ -goog.dom.insertSiblingAfter = function(newNode, refNode) { - if (refNode.parentNode) { - refNode.parentNode.insertBefore(newNode, refNode.nextSibling); - } -}; - - -/** - * Insert a child at a given index. If index is larger than the number of child - * nodes that the parent currently has, the node is inserted as the last child - * node. - * @param {Element} parent The element into which to insert the child. - * @param {Node} child The element to insert. - * @param {number} index The index at which to insert the new child node. Must - * not be negative. - */ -goog.dom.insertChildAt = function(parent, child, index) { - // Note that if the second argument is null, insertBefore - // will append the child at the end of the list of children. - parent.insertBefore(child, parent.childNodes[index] || null); -}; - - -/** - * Removes a node from its parent. - * @param {Node} node The node to remove. - * @return {Node} The node removed if removed; else, null. - */ -goog.dom.removeNode = function(node) { - return node && node.parentNode ? node.parentNode.removeChild(node) : null; -}; - - -/** - * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no - * parent. - * @param {Node} newNode Node to insert. - * @param {Node} oldNode Node to replace. - */ -goog.dom.replaceNode = function(newNode, oldNode) { - var parent = oldNode.parentNode; - if (parent) { - parent.replaceChild(newNode, oldNode); - } -}; - - -/** - * Flattens an element. That is, removes it and replace it with its children. - * Does nothing if the element is not in the document. - * @param {Element} element The element to flatten. - * @return {Element|undefined} The original element, detached from the document - * tree, sans children; or undefined, if the element was not in the document - * to begin with. - */ -goog.dom.flattenElement = function(element) { - var child, parent = element.parentNode; - if (parent && parent.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT) { - // Use IE DOM method (supported by Opera too) if available - if (element.removeNode) { - return /** @type {Element} */ (element.removeNode(false)); - } else { - // Move all children of the original node up one level. - while ((child = element.firstChild)) { - parent.insertBefore(child, element); - } - - // Detach the original element. - return /** @type {Element} */ (goog.dom.removeNode(element)); - } - } -}; - - -/** - * Returns an array containing just the element children of the given element. - * @param {Element} element The element whose element children we want. - * @return {!(Array|NodeList)} An array or array-like list of just the element - * children of the given element. - */ -goog.dom.getChildren = function(element) { - // We check if the children attribute is supported for child elements - // since IE8 misuses the attribute by also including comments. - if (goog.dom.BrowserFeature.CAN_USE_CHILDREN_ATTRIBUTE && - element.children != undefined) { - return element.children; - } - // Fall back to manually filtering the element's child nodes. - return goog.array.filter(element.childNodes, function(node) { - return node.nodeType == goog.dom.NodeType.ELEMENT; - }); -}; - - -/** - * Returns the first child node that is an element. - * @param {Node} node The node to get the first child element of. - * @return {Element} The first child node of {@code node} that is an element. - */ -goog.dom.getFirstElementChild = function(node) { - if (goog.isDef(node.firstElementChild)) { - return /** @type {!Element} */(node).firstElementChild; - } - return goog.dom.getNextElementNode_(node.firstChild, true); -}; - - -/** - * Returns the last child node that is an element. - * @param {Node} node The node to get the last child element of. - * @return {Element} The last child node of {@code node} that is an element. - */ -goog.dom.getLastElementChild = function(node) { - if (goog.isDef(node.lastElementChild)) { - return /** @type {!Element} */(node).lastElementChild; - } - return goog.dom.getNextElementNode_(node.lastChild, false); -}; - - -/** - * Returns the first next sibling that is an element. - * @param {Node} node The node to get the next sibling element of. - * @return {Element} The next sibling of {@code node} that is an element. - */ -goog.dom.getNextElementSibling = function(node) { - if (goog.isDef(node.nextElementSibling)) { - return /** @type {!Element} */(node).nextElementSibling; - } - return goog.dom.getNextElementNode_(node.nextSibling, true); -}; - - -/** - * Returns the first previous sibling that is an element. - * @param {Node} node The node to get the previous sibling element of. - * @return {Element} The first previous sibling of {@code node} that is - * an element. - */ -goog.dom.getPreviousElementSibling = function(node) { - if (goog.isDef(node.previousElementSibling)) { - return /** @type {!Element} */(node).previousElementSibling; - } - return goog.dom.getNextElementNode_(node.previousSibling, false); -}; - - -/** - * Returns the first node that is an element in the specified direction, - * starting with {@code node}. - * @param {Node} node The node to get the next element from. - * @param {boolean} forward Whether to look forwards or backwards. - * @return {Element} The first element. - * @private - */ -goog.dom.getNextElementNode_ = function(node, forward) { - while (node && node.nodeType != goog.dom.NodeType.ELEMENT) { - node = forward ? node.nextSibling : node.previousSibling; - } - - return /** @type {Element} */ (node); -}; - - -/** - * Returns the next node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The next node in the DOM tree, or null if this was the last - * node. - */ -goog.dom.getNextNode = function(node) { - if (!node) { - return null; - } - - if (node.firstChild) { - return node.firstChild; - } - - while (node && !node.nextSibling) { - node = node.parentNode; - } - - return node ? node.nextSibling : null; -}; - - -/** - * Returns the previous node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The previous node in the DOM tree, or null if this was the - * first node. - */ -goog.dom.getPreviousNode = function(node) { - if (!node) { - return null; - } - - if (!node.previousSibling) { - return node.parentNode; - } - - node = node.previousSibling; - while (node && node.lastChild) { - node = node.lastChild; - } - - return node; -}; - - -/** - * Whether the object looks like a DOM node. - * @param {?} obj The object being tested for node likeness. - * @return {boolean} Whether the object looks like a DOM node. - */ -goog.dom.isNodeLike = function(obj) { - return goog.isObject(obj) && obj.nodeType > 0; -}; - - -/** - * Whether the object looks like an Element. - * @param {?} obj The object being tested for Element likeness. - * @return {boolean} Whether the object looks like an Element. - */ -goog.dom.isElement = function(obj) { - return goog.isObject(obj) && obj.nodeType == goog.dom.NodeType.ELEMENT; -}; - - -/** - * Returns true if the specified value is a Window object. This includes the - * global window for HTML pages, and iframe windows. - * @param {?} obj Variable to test. - * @return {boolean} Whether the variable is a window. - */ -goog.dom.isWindow = function(obj) { - return goog.isObject(obj) && obj['window'] == obj; -}; - - -/** - * Returns an element's parent, if it's an Element. - * @param {Element} element The DOM element. - * @return {Element} The parent, or null if not an Element. - */ -goog.dom.getParentElement = function(element) { - var parent; - if (goog.dom.BrowserFeature.CAN_USE_PARENT_ELEMENT_PROPERTY) { - var isIe9 = goog.userAgent.IE && - goog.userAgent.isVersionOrHigher('9') && - !goog.userAgent.isVersionOrHigher('10'); - // SVG elements in IE9 can't use the parentElement property. - // goog.global['SVGElement'] is not defined in IE9 quirks mode. - if (!(isIe9 && goog.global['SVGElement'] && - element instanceof goog.global['SVGElement'])) { - parent = element.parentElement; - if (parent) { - return parent; - } - } - } - parent = element.parentNode; - return goog.dom.isElement(parent) ? /** @type {!Element} */ (parent) : null; -}; - - -/** - * Whether a node contains another node. - * @param {Node} parent The node that should contain the other node. - * @param {Node} descendant The node to test presence of. - * @return {boolean} Whether the parent node contains the descendent node. - */ -goog.dom.contains = function(parent, descendant) { - // We use browser specific methods for this if available since it is faster - // that way. - - // IE DOM - if (parent.contains && descendant.nodeType == goog.dom.NodeType.ELEMENT) { - return parent == descendant || parent.contains(descendant); - } - - // W3C DOM Level 3 - if (typeof parent.compareDocumentPosition != 'undefined') { - return parent == descendant || - Boolean(parent.compareDocumentPosition(descendant) & 16); - } - - // W3C DOM Level 1 - while (descendant && parent != descendant) { - descendant = descendant.parentNode; - } - return descendant == parent; -}; - - -/** - * Compares the document order of two nodes, returning 0 if they are the same - * node, a negative number if node1 is before node2, and a positive number if - * node2 is before node1. Note that we compare the order the tags appear in the - * document so in the tree <b><i>text</i></b> the B node is considered to be - * before the I node. - * - * @param {Node} node1 The first node to compare. - * @param {Node} node2 The second node to compare. - * @return {number} 0 if the nodes are the same node, a negative number if node1 - * is before node2, and a positive number if node2 is before node1. - */ -goog.dom.compareNodeOrder = function(node1, node2) { - // Fall out quickly for equality. - if (node1 == node2) { - return 0; - } - - // Use compareDocumentPosition where available - if (node1.compareDocumentPosition) { - // 4 is the bitmask for FOLLOWS. - return node1.compareDocumentPosition(node2) & 2 ? 1 : -1; - } - - // Special case for document nodes on IE 7 and 8. - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { - if (node1.nodeType == goog.dom.NodeType.DOCUMENT) { - return -1; - } - if (node2.nodeType == goog.dom.NodeType.DOCUMENT) { - return 1; - } - } - - // Process in IE using sourceIndex - we check to see if the first node has - // a source index or if its parent has one. - if ('sourceIndex' in node1 || - (node1.parentNode && 'sourceIndex' in node1.parentNode)) { - var isElement1 = node1.nodeType == goog.dom.NodeType.ELEMENT; - var isElement2 = node2.nodeType == goog.dom.NodeType.ELEMENT; - - if (isElement1 && isElement2) { - return node1.sourceIndex - node2.sourceIndex; - } else { - var parent1 = node1.parentNode; - var parent2 = node2.parentNode; - - if (parent1 == parent2) { - return goog.dom.compareSiblingOrder_(node1, node2); - } - - if (!isElement1 && goog.dom.contains(parent1, node2)) { - return -1 * goog.dom.compareParentsDescendantNodeIe_(node1, node2); - } - - - if (!isElement2 && goog.dom.contains(parent2, node1)) { - return goog.dom.compareParentsDescendantNodeIe_(node2, node1); - } - - return (isElement1 ? node1.sourceIndex : parent1.sourceIndex) - - (isElement2 ? node2.sourceIndex : parent2.sourceIndex); - } - } - - // For Safari, we compare ranges. - var doc = goog.dom.getOwnerDocument(node1); - - var range1, range2; - range1 = doc.createRange(); - range1.selectNode(node1); - range1.collapse(true); - - range2 = doc.createRange(); - range2.selectNode(node2); - range2.collapse(true); - - return range1.compareBoundaryPoints(goog.global['Range'].START_TO_END, - range2); -}; - - -/** - * Utility function to compare the position of two nodes, when - * {@code textNode}'s parent is an ancestor of {@code node}. If this entry - * condition is not met, this function will attempt to reference a null object. - * @param {!Node} textNode The textNode to compare. - * @param {Node} node The node to compare. - * @return {number} -1 if node is before textNode, +1 otherwise. - * @private - */ -goog.dom.compareParentsDescendantNodeIe_ = function(textNode, node) { - var parent = textNode.parentNode; - if (parent == node) { - // If textNode is a child of node, then node comes first. - return -1; - } - var sibling = node; - while (sibling.parentNode != parent) { - sibling = sibling.parentNode; - } - return goog.dom.compareSiblingOrder_(sibling, textNode); -}; - - -/** - * Utility function to compare the position of two nodes known to be non-equal - * siblings. - * @param {Node} node1 The first node to compare. - * @param {!Node} node2 The second node to compare. - * @return {number} -1 if node1 is before node2, +1 otherwise. - * @private - */ -goog.dom.compareSiblingOrder_ = function(node1, node2) { - var s = node2; - while ((s = s.previousSibling)) { - if (s == node1) { - // We just found node1 before node2. - return -1; - } - } - - // Since we didn't find it, node1 must be after node2. - return 1; -}; - - -/** - * Find the deepest common ancestor of the given nodes. - * @param {...Node} var_args The nodes to find a common ancestor of. - * @return {Node} The common ancestor of the nodes, or null if there is none. - * null will only be returned if two or more of the nodes are from different - * documents. - */ -goog.dom.findCommonAncestor = function(var_args) { - var i, count = arguments.length; - if (!count) { - return null; - } else if (count == 1) { - return arguments[0]; - } - - var paths = []; - var minLength = Infinity; - for (i = 0; i < count; i++) { - // Compute the list of ancestors. - var ancestors = []; - var node = arguments[i]; - while (node) { - ancestors.unshift(node); - node = node.parentNode; - } - - // Save the list for comparison. - paths.push(ancestors); - minLength = Math.min(minLength, ancestors.length); - } - var output = null; - for (i = 0; i < minLength; i++) { - var first = paths[0][i]; - for (var j = 1; j < count; j++) { - if (first != paths[j][i]) { - return output; - } - } - output = first; - } - return output; -}; - - -/** - * Returns the owner document for a node. - * @param {Node|Window} node The node to get the document for. - * @return {!Document} The document owning the node. - */ -goog.dom.getOwnerDocument = function(node) { - // TODO(nnaze): Update param signature to be non-nullable. - goog.asserts.assert(node, 'Node cannot be null or undefined.'); - return /** @type {!Document} */ ( - node.nodeType == goog.dom.NodeType.DOCUMENT ? node : - node.ownerDocument || node.document); -}; - - -/** - * Cross-browser function for getting the document element of a frame or iframe. - * @param {Element} frame Frame element. - * @return {!Document} The frame content document. - */ -goog.dom.getFrameContentDocument = function(frame) { - var doc = frame.contentDocument || frame.contentWindow.document; - return doc; -}; - - -/** - * Cross-browser function for getting the window of a frame or iframe. - * @param {Element} frame Frame element. - * @return {Window} The window associated with the given frame. - */ -goog.dom.getFrameContentWindow = function(frame) { - return frame.contentWindow || - goog.dom.getWindow(goog.dom.getFrameContentDocument(frame)); -}; - - -/** - * Sets the text content of a node, with cross-browser support. - * @param {Node} node The node to change the text content of. - * @param {string|number} text The value that should replace the node's content. - */ -goog.dom.setTextContent = function(node, text) { - goog.asserts.assert(node != null, - 'goog.dom.setTextContent expects a non-null value for node'); - - if ('textContent' in node) { - node.textContent = text; - } else if (node.nodeType == goog.dom.NodeType.TEXT) { - node.data = text; - } else if (node.firstChild && - node.firstChild.nodeType == goog.dom.NodeType.TEXT) { - // If the first child is a text node we just change its data and remove the - // rest of the children. - while (node.lastChild != node.firstChild) { - node.removeChild(node.lastChild); - } - node.firstChild.data = text; - } else { - goog.dom.removeChildren(node); - var doc = goog.dom.getOwnerDocument(node); - node.appendChild(doc.createTextNode(String(text))); - } -}; - - -/** - * Gets the outerHTML of a node, which islike innerHTML, except that it - * actually contains the HTML of the node itself. - * @param {Element} element The element to get the HTML of. - * @return {string} The outerHTML of the given element. - */ -goog.dom.getOuterHtml = function(element) { - // IE, Opera and WebKit all have outerHTML. - if ('outerHTML' in element) { - return element.outerHTML; - } else { - var doc = goog.dom.getOwnerDocument(element); - var div = doc.createElement(goog.dom.TagName.DIV); - div.appendChild(element.cloneNode(true)); - return div.innerHTML; - } -}; - - -/** - * Finds the first descendant node that matches the filter function, using - * a depth first search. This function offers the most general purpose way - * of finding a matching element. You may also wish to consider - * {@code goog.dom.query} which can express many matching criteria using - * CSS selector expressions. These expressions often result in a more - * compact representation of the desired result. - * @see goog.dom.query - * - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {Node|undefined} The found node or undefined if none is found. - */ -goog.dom.findNode = function(root, p) { - var rv = []; - var found = goog.dom.findNodes_(root, p, rv, true); - return found ? rv[0] : undefined; -}; - - -/** - * Finds all the descendant nodes that match the filter function, using a - * a depth first search. This function offers the most general-purpose way - * of finding a set of matching elements. You may also wish to consider - * {@code goog.dom.query} which can express many matching criteria using - * CSS selector expressions. These expressions often result in a more - * compact representation of the desired result. - - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {!Array<!Node>} The found nodes or an empty array if none are found. - */ -goog.dom.findNodes = function(root, p) { - var rv = []; - goog.dom.findNodes_(root, p, rv, false); - return rv; -}; - - -/** - * Finds the first or all the descendant nodes that match the filter function, - * using a depth first search. - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @param {!Array<!Node>} rv The found nodes are added to this array. - * @param {boolean} findOne If true we exit after the first found node. - * @return {boolean} Whether the search is complete or not. True in case findOne - * is true and the node is found. False otherwise. - * @private - */ -goog.dom.findNodes_ = function(root, p, rv, findOne) { - if (root != null) { - var child = root.firstChild; - while (child) { - if (p(child)) { - rv.push(child); - if (findOne) { - return true; - } - } - if (goog.dom.findNodes_(child, p, rv, findOne)) { - return true; - } - child = child.nextSibling; - } - } - return false; -}; - - -/** - * Map of tags whose content to ignore when calculating text length. - * @private {!Object<string, number>} - * @const - */ -goog.dom.TAGS_TO_IGNORE_ = { - 'SCRIPT': 1, - 'STYLE': 1, - 'HEAD': 1, - 'IFRAME': 1, - 'OBJECT': 1 -}; - - -/** - * Map of tags which have predefined values with regard to whitespace. - * @private {!Object<string, string>} - * @const - */ -goog.dom.PREDEFINED_TAG_VALUES_ = {'IMG': ' ', 'BR': '\n'}; - - -/** - * Returns true if the element has a tab index that allows it to receive - * keyboard focus (tabIndex >= 0), false otherwise. Note that some elements - * natively support keyboard focus, even if they have no tab index. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a tab index that allows keyboard - * focus. - * @see http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - */ -goog.dom.isFocusableTabIndex = function(element) { - return goog.dom.hasSpecifiedTabIndex_(element) && - goog.dom.isTabIndexFocusable_(element); -}; - - -/** - * Enables or disables keyboard focus support on the element via its tab index. - * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true - * (or elements that natively support keyboard focus, like form elements) can - * receive keyboard focus. See http://go/tabindex for more info. - * @param {Element} element Element whose tab index is to be changed. - * @param {boolean} enable Whether to set or remove a tab index on the element - * that supports keyboard focus. - */ -goog.dom.setFocusableTabIndex = function(element, enable) { - if (enable) { - element.tabIndex = 0; - } else { - // Set tabIndex to -1 first, then remove it. This is a workaround for - // Safari (confirmed in version 4 on Windows). When removing the attribute - // without setting it to -1 first, the element remains keyboard focusable - // despite not having a tabIndex attribute anymore. - element.tabIndex = -1; - element.removeAttribute('tabIndex'); // Must be camelCase! - } -}; - - -/** - * Returns true if the element can be focused, i.e. it has a tab index that - * allows it to receive keyboard focus (tabIndex >= 0), or it is an element - * that natively supports keyboard focus. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element allows keyboard focus. - */ -goog.dom.isFocusable = function(element) { - var focusable; - // Some elements can have unspecified tab index and still receive focus. - if (goog.dom.nativelySupportsFocus_(element)) { - // Make sure the element is not disabled ... - focusable = !element.disabled && - // ... and if a tab index is specified, it allows focus. - (!goog.dom.hasSpecifiedTabIndex_(element) || - goog.dom.isTabIndexFocusable_(element)); - } else { - focusable = goog.dom.isFocusableTabIndex(element); - } - - // IE requires elements to be visible in order to focus them. - return focusable && goog.userAgent.IE ? - goog.dom.hasNonZeroBoundingRect_(element) : focusable; -}; - - -/** - * Returns true if the element has a specified tab index. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a specified tab index. - * @private - */ -goog.dom.hasSpecifiedTabIndex_ = function(element) { - // IE returns 0 for an unset tabIndex, so we must use getAttributeNode(), - // which returns an object with a 'specified' property if tabIndex is - // specified. This works on other browsers, too. - var attrNode = element.getAttributeNode('tabindex'); // Must be lowercase! - return goog.isDefAndNotNull(attrNode) && attrNode.specified; -}; - - -/** - * Returns true if the element's tab index allows the element to be focused. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element's tab index allows focus. - * @private - */ -goog.dom.isTabIndexFocusable_ = function(element) { - var index = element.tabIndex; - // NOTE: IE9 puts tabIndex in 16-bit int, e.g. -2 is 65534. - return goog.isNumber(index) && index >= 0 && index < 32768; -}; - - -/** - * Returns true if the element is focusable even when tabIndex is not set. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element natively supports focus. - * @private - */ -goog.dom.nativelySupportsFocus_ = function(element) { - return element.tagName == goog.dom.TagName.A || - element.tagName == goog.dom.TagName.INPUT || - element.tagName == goog.dom.TagName.TEXTAREA || - element.tagName == goog.dom.TagName.SELECT || - element.tagName == goog.dom.TagName.BUTTON; -}; - - -/** - * Returns true if the element has a bounding rectangle that would be visible - * (i.e. its width and height are greater than zero). - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a non-zero bounding rectangle. - * @private - */ -goog.dom.hasNonZeroBoundingRect_ = function(element) { - var rect = goog.isFunction(element['getBoundingClientRect']) ? - element.getBoundingClientRect() : - {'height': element.offsetHeight, 'width': element.offsetWidth}; - return goog.isDefAndNotNull(rect) && rect.height > 0 && rect.width > 0; -}; - - -/** - * Returns the text content of the current node, without markup and invisible - * symbols. New lines are stripped and whitespace is collapsed, - * such that each character would be visible. - * - * In browsers that support it, innerText is used. Other browsers attempt to - * simulate it via node traversal. Line breaks are canonicalized in IE. - * - * @param {Node} node The node from which we are getting content. - * @return {string} The text content. - */ -goog.dom.getTextContent = function(node) { - var textContent; - // Note(arv): IE9, Opera, and Safari 3 support innerText but they include - // text nodes in script tags. So we revert to use a user agent test here. - if (goog.dom.BrowserFeature.CAN_USE_INNER_TEXT && ('innerText' in node)) { - textContent = goog.string.canonicalizeNewlines(node.innerText); - // Unfortunately .innerText() returns text with ­ symbols - // We need to filter it out and then remove duplicate whitespaces - } else { - var buf = []; - goog.dom.getTextContent_(node, buf, true); - textContent = buf.join(''); - } - - // Strip ­ entities. goog.format.insertWordBreaks inserts them in Opera. - textContent = textContent.replace(/ \xAD /g, ' ').replace(/\xAD/g, ''); - // Strip ​ entities. goog.format.insertWordBreaks inserts them in IE8. - textContent = textContent.replace(/\u200B/g, ''); - - // Skip this replacement on old browsers with working innerText, which - // automatically turns   into ' ' and / +/ into ' ' when reading - // innerText. - if (!goog.dom.BrowserFeature.CAN_USE_INNER_TEXT) { - textContent = textContent.replace(/ +/g, ' '); - } - if (textContent != ' ') { - textContent = textContent.replace(/^\s*/, ''); - } - - return textContent; -}; - - -/** - * Returns the text content of the current node, without markup. - * - * Unlike {@code getTextContent} this method does not collapse whitespaces - * or normalize lines breaks. - * - * @param {Node} node The node from which we are getting content. - * @return {string} The raw text content. - */ -goog.dom.getRawTextContent = function(node) { - var buf = []; - goog.dom.getTextContent_(node, buf, false); - - return buf.join(''); -}; - - -/** - * Recursive support function for text content retrieval. - * - * @param {Node} node The node from which we are getting content. - * @param {Array<string>} buf string buffer. - * @param {boolean} normalizeWhitespace Whether to normalize whitespace. - * @private - */ -goog.dom.getTextContent_ = function(node, buf, normalizeWhitespace) { - if (node.nodeName in goog.dom.TAGS_TO_IGNORE_) { - // ignore certain tags - } else if (node.nodeType == goog.dom.NodeType.TEXT) { - if (normalizeWhitespace) { - buf.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, '')); - } else { - buf.push(node.nodeValue); - } - } else if (node.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) { - buf.push(goog.dom.PREDEFINED_TAG_VALUES_[node.nodeName]); - } else { - var child = node.firstChild; - while (child) { - goog.dom.getTextContent_(child, buf, normalizeWhitespace); - child = child.nextSibling; - } - } -}; - - -/** - * Returns the text length of the text contained in a node, without markup. This - * is equivalent to the selection length if the node was selected, or the number - * of cursor movements to traverse the node. Images & BRs take one space. New - * lines are ignored. - * - * @param {Node} node The node whose text content length is being calculated. - * @return {number} The length of {@code node}'s text content. - */ -goog.dom.getNodeTextLength = function(node) { - return goog.dom.getTextContent(node).length; -}; - - -/** - * Returns the text offset of a node relative to one of its ancestors. The text - * length is the same as the length calculated by goog.dom.getNodeTextLength. - * - * @param {Node} node The node whose offset is being calculated. - * @param {Node=} opt_offsetParent The node relative to which the offset will - * be calculated. Defaults to the node's owner document's body. - * @return {number} The text offset. - */ -goog.dom.getNodeTextOffset = function(node, opt_offsetParent) { - var root = opt_offsetParent || goog.dom.getOwnerDocument(node).body; - var buf = []; - while (node && node != root) { - var cur = node; - while ((cur = cur.previousSibling)) { - buf.unshift(goog.dom.getTextContent(cur)); - } - node = node.parentNode; - } - // Trim left to deal with FF cases when there might be line breaks and empty - // nodes at the front of the text - return goog.string.trimLeft(buf.join('')).replace(/ +/g, ' ').length; -}; - - -/** - * Returns the node at a given offset in a parent node. If an object is - * provided for the optional third parameter, the node and the remainder of the - * offset will stored as properties of this object. - * @param {Node} parent The parent node. - * @param {number} offset The offset into the parent node. - * @param {Object=} opt_result Object to be used to store the return value. The - * return value will be stored in the form {node: Node, remainder: number} - * if this object is provided. - * @return {Node} The node at the given offset. - */ -goog.dom.getNodeAtOffset = function(parent, offset, opt_result) { - var stack = [parent], pos = 0, cur = null; - while (stack.length > 0 && pos < offset) { - cur = stack.pop(); - if (cur.nodeName in goog.dom.TAGS_TO_IGNORE_) { - // ignore certain tags - } else if (cur.nodeType == goog.dom.NodeType.TEXT) { - var text = cur.nodeValue.replace(/(\r\n|\r|\n)/g, '').replace(/ +/g, ' '); - pos += text.length; - } else if (cur.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) { - pos += goog.dom.PREDEFINED_TAG_VALUES_[cur.nodeName].length; - } else { - for (var i = cur.childNodes.length - 1; i >= 0; i--) { - stack.push(cur.childNodes[i]); - } - } - } - if (goog.isObject(opt_result)) { - opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0; - opt_result.node = cur; - } - - return cur; -}; - - -/** - * Returns true if the object is a {@code NodeList}. To qualify as a NodeList, - * the object must have a numeric length property and an item function (which - * has type 'string' on IE for some reason). - * @param {Object} val Object to test. - * @return {boolean} Whether the object is a NodeList. - */ -goog.dom.isNodeList = function(val) { - // TODO(attila): Now the isNodeList is part of goog.dom we can use - // goog.userAgent to make this simpler. - // A NodeList must have a length property of type 'number' on all platforms. - if (val && typeof val.length == 'number') { - // A NodeList is an object everywhere except Safari, where it's a function. - if (goog.isObject(val)) { - // A NodeList must have an item function (on non-IE platforms) or an item - // property of type 'string' (on IE). - return typeof val.item == 'function' || typeof val.item == 'string'; - } else if (goog.isFunction(val)) { - // On Safari, a NodeList is a function with an item property that is also - // a function. - return typeof val.item == 'function'; - } - } - - // Not a NodeList. - return false; -}; - - -/** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * tag name and/or class name. If the passed element matches the specified - * criteria, the element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or - * null/undefined to match only based on class name). - * @param {?string=} opt_class The class name to match (or null/undefined to - * match only based on tag name). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if no match is found. - */ -goog.dom.getAncestorByTagNameAndClass = function(element, opt_tag, opt_class, - opt_maxSearchSteps) { - if (!opt_tag && !opt_class) { - return null; - } - var tagName = opt_tag ? opt_tag.toUpperCase() : null; - return /** @type {Element} */ (goog.dom.getAncestor(element, - function(node) { - return (!tagName || node.nodeName == tagName) && - (!opt_class || goog.isString(node.className) && - goog.array.contains(node.className.split(/\s+/), opt_class)); - }, true, opt_maxSearchSteps)); -}; - - -/** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * class name. If the passed element matches the specified criteria, the - * element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {string} className The class name to match. - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if none match. - */ -goog.dom.getAncestorByClass = function(element, className, opt_maxSearchSteps) { - return goog.dom.getAncestorByTagNameAndClass(element, null, className, - opt_maxSearchSteps); -}; - - -/** - * Walks up the DOM hierarchy returning the first ancestor that passes the - * matcher function. - * @param {Node} element The DOM node to start with. - * @param {function(Node) : boolean} matcher A function that returns true if the - * passed node matches the desired criteria. - * @param {boolean=} opt_includeNode If true, the node itself is included in - * the search (the first call to the matcher will pass startElement as - * the node to test). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Node} DOM node that matched the matcher, or null if there was - * no match. - */ -goog.dom.getAncestor = function( - element, matcher, opt_includeNode, opt_maxSearchSteps) { - if (!opt_includeNode) { - element = element.parentNode; - } - var ignoreSearchSteps = opt_maxSearchSteps == null; - var steps = 0; - while (element && (ignoreSearchSteps || steps <= opt_maxSearchSteps)) { - goog.asserts.assert(element.name != 'parentNode'); - if (matcher(element)) { - return element; - } - element = element.parentNode; - steps++; - } - // Reached the root of the DOM without a match - return null; -}; - - -/** - * Determines the active element in the given document. - * @param {Document} doc The document to look in. - * @return {Element} The active element. - */ -goog.dom.getActiveElement = function(doc) { - try { - return doc && doc.activeElement; - } catch (e) { - // NOTE(nicksantos): Sometimes, evaluating document.activeElement in IE - // throws an exception. I'm not 100% sure why, but I suspect it chokes - // on document.activeElement if the activeElement has been recently - // removed from the DOM by a JS operation. - // - // We assume that an exception here simply means - // "there is no active element." - } - - return null; -}; - - -/** - * Gives the current devicePixelRatio. - * - * By default, this is the value of window.devicePixelRatio (which should be - * preferred if present). - * - * If window.devicePixelRatio is not present, the ratio is calculated with - * window.matchMedia, if present. Otherwise, gives 1.0. - * - * Some browsers (including Chrome) consider the browser zoom level in the pixel - * ratio, so the value may change across multiple calls. - * - * @return {number} The number of actual pixels per virtual pixel. - */ -goog.dom.getPixelRatio = function() { - var win = goog.dom.getWindow(); - if (goog.isDef(win.devicePixelRatio)) { - return win.devicePixelRatio; - } else if (win.matchMedia) { - return goog.dom.matchesPixelRatio_(.75) || - goog.dom.matchesPixelRatio_(1.5) || - goog.dom.matchesPixelRatio_(2) || - goog.dom.matchesPixelRatio_(3) || 1; - } - return 1; -}; - - -/** - * Calculates a mediaQuery to check if the current device supports the - * given actual to virtual pixel ratio. - * @param {number} pixelRatio The ratio of actual pixels to virtual pixels. - * @return {number} pixelRatio if applicable, otherwise 0. - * @private - */ -goog.dom.matchesPixelRatio_ = function(pixelRatio) { - var win = goog.dom.getWindow(); - var query = ('(-webkit-min-device-pixel-ratio: ' + pixelRatio + '),' + - '(min--moz-device-pixel-ratio: ' + pixelRatio + '),' + - '(min-resolution: ' + pixelRatio + 'dppx)'); - return win.matchMedia(query).matches ? pixelRatio : 0; -}; - - - -/** - * Create an instance of a DOM helper with a new document object. - * @param {Document=} opt_document Document object to associate with this - * DOM helper. - * @constructor - */ -goog.dom.DomHelper = function(opt_document) { - /** - * Reference to the document object to use - * @type {!Document} - * @private - */ - this.document_ = opt_document || goog.global.document || document; -}; - - -/** - * Gets the dom helper object for the document where the element resides. - * @param {Node=} opt_node If present, gets the DomHelper for this node. - * @return {!goog.dom.DomHelper} The DomHelper. - */ -goog.dom.DomHelper.prototype.getDomHelper = goog.dom.getDomHelper; - - -/** - * Sets the document object. - * @param {!Document} document Document object. - */ -goog.dom.DomHelper.prototype.setDocument = function(document) { - this.document_ = document; -}; - - -/** - * Gets the document object being used by the dom library. - * @return {!Document} Document object. - */ -goog.dom.DomHelper.prototype.getDocument = function() { - return this.document_; -}; - - -/** - * Alias for {@code getElementById}. If a DOM node is passed in then we just - * return that. - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. - */ -goog.dom.DomHelper.prototype.getElement = function(element) { - return goog.dom.getElementHelper_(this.document_, element); -}; - - -/** - * Gets an element by id, asserting that the element is found. - * - * This is used when an element is expected to exist, and should fail with - * an assertion error if it does not (if assertions are enabled). - * - * @param {string} id Element ID. - * @return {!Element} The element with the given ID, if it exists. - */ -goog.dom.DomHelper.prototype.getRequiredElement = function(id) { - return goog.dom.getRequiredElementHelper_(this.document_, id); -}; - - -/** - * Alias for {@code getElement}. - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. - * @deprecated Use {@link goog.dom.DomHelper.prototype.getElement} instead. - */ -goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement; - - -/** - * Looks up elements by both tag and class name, using browser native functions - * ({@code querySelectorAll}, {@code getElementsByTagName} or - * {@code getElementsByClassName}) where possible. The returned array is a live - * NodeList or a static list depending on the code path taken. - * - * @see goog.dom.query - * - * @param {?string=} opt_tag Element tag name or * for all tags. - * @param {?string=} opt_class Optional class name. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - */ -goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(opt_tag, - opt_class, - opt_el) { - return goog.dom.getElementsByTagNameAndClass_(this.document_, opt_tag, - opt_class, opt_el); -}; - - -/** - * Returns an array of all the elements with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {Element|Document=} opt_el Optional element to look in. - * @return { {length: number} } The items found with the class name provided. - */ -goog.dom.DomHelper.prototype.getElementsByClass = function(className, opt_el) { - var doc = opt_el || this.document_; - return goog.dom.getElementsByClass(className, doc); -}; - - -/** - * Returns the first element we find matching the provided class name. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {(Element|Document)=} opt_el Optional element to look in. - * @return {Element} The first item found with the class name provided. - */ -goog.dom.DomHelper.prototype.getElementByClass = function(className, opt_el) { - var doc = opt_el || this.document_; - return goog.dom.getElementByClass(className, doc); -}; - - -/** - * Ensures an element with the given className exists, and then returns the - * first element with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {(!Element|!Document)=} opt_root Optional element or document to look - * in. - * @return {!Element} The first item found with the class name provided. - * @throws {goog.asserts.AssertionError} Thrown if no element is found. - */ -goog.dom.DomHelper.prototype.getRequiredElementByClass = function(className, - opt_root) { - var root = opt_root || this.document_; - return goog.dom.getRequiredElementByClass(className, root); -}; - - -/** - * Alias for {@code getElementsByTagNameAndClass}. - * @deprecated Use DomHelper getElementsByTagNameAndClass. - * @see goog.dom.query - * - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {Element=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - */ -goog.dom.DomHelper.prototype.$$ = - goog.dom.DomHelper.prototype.getElementsByTagNameAndClass; - - -/** - * Sets a number of properties on a node. - * @param {Element} element DOM node to set properties on. - * @param {Object} properties Hash of property:value pairs. - */ -goog.dom.DomHelper.prototype.setProperties = goog.dom.setProperties; - - -/** - * Gets the dimensions of the viewport. - * @param {Window=} opt_window Optional window element to test. Defaults to - * the window of the Dom Helper. - * @return {!goog.math.Size} Object with values 'width' and 'height'. - */ -goog.dom.DomHelper.prototype.getViewportSize = function(opt_window) { - // TODO(arv): This should not take an argument. That breaks the rule of a - // a DomHelper representing a single frame/window/document. - return goog.dom.getViewportSize(opt_window || this.getWindow()); -}; - - -/** - * Calculates the height of the document. - * - * @return {number} The height of the document. - */ -goog.dom.DomHelper.prototype.getDocumentHeight = function() { - return goog.dom.getDocumentHeight_(this.getWindow()); -}; - - -/** - * Typedef for use with goog.dom.createDom and goog.dom.append. - * @typedef {Object|string|Array|NodeList} - */ -goog.dom.Appendable; - - -/** - * Returns a dom node with a set of attributes. This function accepts varargs - * for subsequent nodes to be added. Subsequent nodes will be added to the - * first node as childNodes. - * - * So: - * <code>createDom('div', null, createDom('p'), createDom('p'));</code> - * would return a div with two child paragraphs - * - * An easy way to move all child nodes of an existing element to a new parent - * element is: - * <code>createDom('div', null, oldElement.childNodes);</code> - * which will remove all child nodes from the old element and add them as - * child nodes of the new DIV. - * - * @param {string} tagName Tag to create. - * @param {Object|string=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. - * @param {...goog.dom.Appendable} var_args Further DOM nodes or - * strings for text nodes. If one of the var_args is an array or - * NodeList, its elements will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. - */ -goog.dom.DomHelper.prototype.createDom = function(tagName, - opt_attributes, - var_args) { - return goog.dom.createDom_(this.document_, arguments); -}; - - -/** - * Alias for {@code createDom}. - * @param {string} tagName Tag to create. - * @param {(Object|string)=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. - * @param {...goog.dom.Appendable} var_args Further DOM nodes or strings for - * text nodes. If one of the var_args is an array, its children will be - * added as childNodes instead. - * @return {!Element} Reference to a DOM node. - * @deprecated Use {@link goog.dom.DomHelper.prototype.createDom} instead. - */ -goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom; - - -/** - * Creates a new element. - * @param {string} name Tag name. - * @return {!Element} The new element. - */ -goog.dom.DomHelper.prototype.createElement = function(name) { - return this.document_.createElement(name); -}; - - -/** - * Creates a new text node. - * @param {number|string} content Content. - * @return {!Text} The new text node. - */ -goog.dom.DomHelper.prototype.createTextNode = function(content) { - return this.document_.createTextNode(String(content)); -}; - - -/** - * Create a table. - * @param {number} rows The number of rows in the table. Must be >= 1. - * @param {number} columns The number of columns in the table. Must be >= 1. - * @param {boolean=} opt_fillWithNbsp If true, fills table entries with - * {@code goog.string.Unicode.NBSP} characters. - * @return {!HTMLElement} The created table. - */ -goog.dom.DomHelper.prototype.createTable = function(rows, columns, - opt_fillWithNbsp) { - return goog.dom.createTable_(this.document_, rows, columns, - !!opt_fillWithNbsp); -}; - - -/** - * Converts an HTML into a node or a document fragment. A single Node is used if - * {@code html} only generates a single node. If {@code html} generates multiple - * nodes then these are put inside a {@code DocumentFragment}. - * @param {!goog.html.SafeHtml} html The HTML markup to convert. - * @return {!Node} The resulting node. - */ -goog.dom.DomHelper.prototype.safeHtmlToNode = function(html) { - return goog.dom.safeHtmlToNode_(this.document_, html); -}; - - -/** - * Converts an HTML string into a node or a document fragment. A single Node - * is used if the {@code htmlString} only generates a single node. If the - * {@code htmlString} generates multiple nodes then these are put inside a - * {@code DocumentFragment}. - * - * @param {string} htmlString The HTML string to convert. - * @return {!Node} The resulting node. - */ -goog.dom.DomHelper.prototype.htmlToDocumentFragment = function(htmlString) { - return goog.dom.htmlToDocumentFragment_(this.document_, htmlString); -}; - - -/** - * Returns true if the browser is in "CSS1-compatible" (standards-compliant) - * mode, false otherwise. - * @return {boolean} True if in CSS1-compatible mode. - */ -goog.dom.DomHelper.prototype.isCss1CompatMode = function() { - return goog.dom.isCss1CompatMode_(this.document_); -}; - - -/** - * Gets the window object associated with the document. - * @return {!Window} The window associated with the given document. - */ -goog.dom.DomHelper.prototype.getWindow = function() { - return goog.dom.getWindow_(this.document_); -}; - - -/** - * Gets the document scroll element. - * @return {!Element} Scrolling element. - */ -goog.dom.DomHelper.prototype.getDocumentScrollElement = function() { - return goog.dom.getDocumentScrollElement_(this.document_); -}; - - -/** - * Gets the document scroll distance as a coordinate object. - * @return {!goog.math.Coordinate} Object with properties 'x' and 'y'. - */ -goog.dom.DomHelper.prototype.getDocumentScroll = function() { - return goog.dom.getDocumentScroll_(this.document_); -}; - - -/** - * Determines the active element in the given document. - * @param {Document=} opt_doc The document to look in. - * @return {Element} The active element. - */ -goog.dom.DomHelper.prototype.getActiveElement = function(opt_doc) { - return goog.dom.getActiveElement(opt_doc || this.document_); -}; - - -/** - * Appends a child to a node. - * @param {Node} parent Parent. - * @param {Node} child Child. - */ -goog.dom.DomHelper.prototype.appendChild = goog.dom.appendChild; - - -/** - * Appends a node with text or other nodes. - * @param {!Node} parent The node to append nodes to. - * @param {...goog.dom.Appendable} var_args The things to append to the node. - * If this is a Node it is appended as is. - * If this is a string then a text node is appended. - * If this is an array like object then fields 0 to length - 1 are appended. - */ -goog.dom.DomHelper.prototype.append = goog.dom.append; - - -/** - * Determines if the given node can contain children, intended to be used for - * HTML generation. - * - * @param {Node} node The node to check. - * @return {boolean} Whether the node can contain children. - */ -goog.dom.DomHelper.prototype.canHaveChildren = goog.dom.canHaveChildren; - - -/** - * Removes all the child nodes on a DOM node. - * @param {Node} node Node to remove children from. - */ -goog.dom.DomHelper.prototype.removeChildren = goog.dom.removeChildren; - - -/** - * Inserts a new node before an existing reference node (i.e., as the previous - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert before. - */ -goog.dom.DomHelper.prototype.insertSiblingBefore = goog.dom.insertSiblingBefore; - - -/** - * Inserts a new node after an existing reference node (i.e., as the next - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert after. - */ -goog.dom.DomHelper.prototype.insertSiblingAfter = goog.dom.insertSiblingAfter; - - -/** - * Insert a child at a given index. If index is larger than the number of child - * nodes that the parent currently has, the node is inserted as the last child - * node. - * @param {Element} parent The element into which to insert the child. - * @param {Node} child The element to insert. - * @param {number} index The index at which to insert the new child node. Must - * not be negative. - */ -goog.dom.DomHelper.prototype.insertChildAt = goog.dom.insertChildAt; - - -/** - * Removes a node from its parent. - * @param {Node} node The node to remove. - * @return {Node} The node removed if removed; else, null. - */ -goog.dom.DomHelper.prototype.removeNode = goog.dom.removeNode; - - -/** - * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no - * parent. - * @param {Node} newNode Node to insert. - * @param {Node} oldNode Node to replace. - */ -goog.dom.DomHelper.prototype.replaceNode = goog.dom.replaceNode; - - -/** - * Flattens an element. That is, removes it and replace it with its children. - * @param {Element} element The element to flatten. - * @return {Element|undefined} The original element, detached from the document - * tree, sans children, or undefined if the element was already not in the - * document. - */ -goog.dom.DomHelper.prototype.flattenElement = goog.dom.flattenElement; - - -/** - * Returns an array containing just the element children of the given element. - * @param {Element} element The element whose element children we want. - * @return {!(Array|NodeList)} An array or array-like list of just the element - * children of the given element. - */ -goog.dom.DomHelper.prototype.getChildren = goog.dom.getChildren; - - -/** - * Returns the first child node that is an element. - * @param {Node} node The node to get the first child element of. - * @return {Element} The first child node of {@code node} that is an element. - */ -goog.dom.DomHelper.prototype.getFirstElementChild = - goog.dom.getFirstElementChild; - - -/** - * Returns the last child node that is an element. - * @param {Node} node The node to get the last child element of. - * @return {Element} The last child node of {@code node} that is an element. - */ -goog.dom.DomHelper.prototype.getLastElementChild = goog.dom.getLastElementChild; - - -/** - * Returns the first next sibling that is an element. - * @param {Node} node The node to get the next sibling element of. - * @return {Element} The next sibling of {@code node} that is an element. - */ -goog.dom.DomHelper.prototype.getNextElementSibling = - goog.dom.getNextElementSibling; - - -/** - * Returns the first previous sibling that is an element. - * @param {Node} node The node to get the previous sibling element of. - * @return {Element} The first previous sibling of {@code node} that is - * an element. - */ -goog.dom.DomHelper.prototype.getPreviousElementSibling = - goog.dom.getPreviousElementSibling; - - -/** - * Returns the next node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The next node in the DOM tree, or null if this was the last - * node. - */ -goog.dom.DomHelper.prototype.getNextNode = goog.dom.getNextNode; - - -/** - * Returns the previous node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The previous node in the DOM tree, or null if this was the - * first node. - */ -goog.dom.DomHelper.prototype.getPreviousNode = goog.dom.getPreviousNode; - - -/** - * Whether the object looks like a DOM node. - * @param {?} obj The object being tested for node likeness. - * @return {boolean} Whether the object looks like a DOM node. - */ -goog.dom.DomHelper.prototype.isNodeLike = goog.dom.isNodeLike; - - -/** - * Whether the object looks like an Element. - * @param {?} obj The object being tested for Element likeness. - * @return {boolean} Whether the object looks like an Element. - */ -goog.dom.DomHelper.prototype.isElement = goog.dom.isElement; - - -/** - * Returns true if the specified value is a Window object. This includes the - * global window for HTML pages, and iframe windows. - * @param {?} obj Variable to test. - * @return {boolean} Whether the variable is a window. - */ -goog.dom.DomHelper.prototype.isWindow = goog.dom.isWindow; - - -/** - * Returns an element's parent, if it's an Element. - * @param {Element} element The DOM element. - * @return {Element} The parent, or null if not an Element. - */ -goog.dom.DomHelper.prototype.getParentElement = goog.dom.getParentElement; - - -/** - * Whether a node contains another node. - * @param {Node} parent The node that should contain the other node. - * @param {Node} descendant The node to test presence of. - * @return {boolean} Whether the parent node contains the descendent node. - */ -goog.dom.DomHelper.prototype.contains = goog.dom.contains; - - -/** - * Compares the document order of two nodes, returning 0 if they are the same - * node, a negative number if node1 is before node2, and a positive number if - * node2 is before node1. Note that we compare the order the tags appear in the - * document so in the tree <b><i>text</i></b> the B node is considered to be - * before the I node. - * - * @param {Node} node1 The first node to compare. - * @param {Node} node2 The second node to compare. - * @return {number} 0 if the nodes are the same node, a negative number if node1 - * is before node2, and a positive number if node2 is before node1. - */ -goog.dom.DomHelper.prototype.compareNodeOrder = goog.dom.compareNodeOrder; - - -/** - * Find the deepest common ancestor of the given nodes. - * @param {...Node} var_args The nodes to find a common ancestor of. - * @return {Node} The common ancestor of the nodes, or null if there is none. - * null will only be returned if two or more of the nodes are from different - * documents. - */ -goog.dom.DomHelper.prototype.findCommonAncestor = goog.dom.findCommonAncestor; - - -/** - * Returns the owner document for a node. - * @param {Node} node The node to get the document for. - * @return {!Document} The document owning the node. - */ -goog.dom.DomHelper.prototype.getOwnerDocument = goog.dom.getOwnerDocument; - - -/** - * Cross browser function for getting the document element of an iframe. - * @param {Element} iframe Iframe element. - * @return {!Document} The frame content document. - */ -goog.dom.DomHelper.prototype.getFrameContentDocument = - goog.dom.getFrameContentDocument; - - -/** - * Cross browser function for getting the window of a frame or iframe. - * @param {Element} frame Frame element. - * @return {Window} The window associated with the given frame. - */ -goog.dom.DomHelper.prototype.getFrameContentWindow = - goog.dom.getFrameContentWindow; - - -/** - * Sets the text content of a node, with cross-browser support. - * @param {Node} node The node to change the text content of. - * @param {string|number} text The value that should replace the node's content. - */ -goog.dom.DomHelper.prototype.setTextContent = goog.dom.setTextContent; - - -/** - * Gets the outerHTML of a node, which islike innerHTML, except that it - * actually contains the HTML of the node itself. - * @param {Element} element The element to get the HTML of. - * @return {string} The outerHTML of the given element. - */ -goog.dom.DomHelper.prototype.getOuterHtml = goog.dom.getOuterHtml; - - -/** - * Finds the first descendant node that matches the filter function. This does - * a depth first search. - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {Node|undefined} The found node or undefined if none is found. - */ -goog.dom.DomHelper.prototype.findNode = goog.dom.findNode; - - -/** - * Finds all the descendant nodes that matches the filter function. This does a - * depth first search. - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {Array<Node>} The found nodes or an empty array if none are found. - */ -goog.dom.DomHelper.prototype.findNodes = goog.dom.findNodes; - - -/** - * Returns true if the element has a tab index that allows it to receive - * keyboard focus (tabIndex >= 0), false otherwise. Note that some elements - * natively support keyboard focus, even if they have no tab index. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a tab index that allows keyboard - * focus. - */ -goog.dom.DomHelper.prototype.isFocusableTabIndex = goog.dom.isFocusableTabIndex; - - -/** - * Enables or disables keyboard focus support on the element via its tab index. - * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true - * (or elements that natively support keyboard focus, like form elements) can - * receive keyboard focus. See http://go/tabindex for more info. - * @param {Element} element Element whose tab index is to be changed. - * @param {boolean} enable Whether to set or remove a tab index on the element - * that supports keyboard focus. - */ -goog.dom.DomHelper.prototype.setFocusableTabIndex = - goog.dom.setFocusableTabIndex; - - -/** - * Returns true if the element can be focused, i.e. it has a tab index that - * allows it to receive keyboard focus (tabIndex >= 0), or it is an element - * that natively supports keyboard focus. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element allows keyboard focus. - */ -goog.dom.DomHelper.prototype.isFocusable = goog.dom.isFocusable; - - -/** - * Returns the text contents of the current node, without markup. New lines are - * stripped and whitespace is collapsed, such that each character would be - * visible. - * - * In browsers that support it, innerText is used. Other browsers attempt to - * simulate it via node traversal. Line breaks are canonicalized in IE. - * - * @param {Node} node The node from which we are getting content. - * @return {string} The text content. - */ -goog.dom.DomHelper.prototype.getTextContent = goog.dom.getTextContent; - - -/** - * Returns the text length of the text contained in a node, without markup. This - * is equivalent to the selection length if the node was selected, or the number - * of cursor movements to traverse the node. Images & BRs take one space. New - * lines are ignored. - * - * @param {Node} node The node whose text content length is being calculated. - * @return {number} The length of {@code node}'s text content. - */ -goog.dom.DomHelper.prototype.getNodeTextLength = goog.dom.getNodeTextLength; - - -/** - * Returns the text offset of a node relative to one of its ancestors. The text - * length is the same as the length calculated by - * {@code goog.dom.getNodeTextLength}. - * - * @param {Node} node The node whose offset is being calculated. - * @param {Node=} opt_offsetParent Defaults to the node's owner document's body. - * @return {number} The text offset. - */ -goog.dom.DomHelper.prototype.getNodeTextOffset = goog.dom.getNodeTextOffset; - - -/** - * Returns the node at a given offset in a parent node. If an object is - * provided for the optional third parameter, the node and the remainder of the - * offset will stored as properties of this object. - * @param {Node} parent The parent node. - * @param {number} offset The offset into the parent node. - * @param {Object=} opt_result Object to be used to store the return value. The - * return value will be stored in the form {node: Node, remainder: number} - * if this object is provided. - * @return {Node} The node at the given offset. - */ -goog.dom.DomHelper.prototype.getNodeAtOffset = goog.dom.getNodeAtOffset; - - -/** - * Returns true if the object is a {@code NodeList}. To qualify as a NodeList, - * the object must have a numeric length property and an item function (which - * has type 'string' on IE for some reason). - * @param {Object} val Object to test. - * @return {boolean} Whether the object is a NodeList. - */ -goog.dom.DomHelper.prototype.isNodeList = goog.dom.isNodeList; - - -/** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * tag name and/or class name. If the passed element matches the specified - * criteria, the element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or - * null/undefined to match only based on class name). - * @param {?string=} opt_class The class name to match (or null/undefined to - * match only based on tag name). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if no match is found. - */ -goog.dom.DomHelper.prototype.getAncestorByTagNameAndClass = - goog.dom.getAncestorByTagNameAndClass; - - -/** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * class name. If the passed element matches the specified criteria, the - * element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {string} class The class name to match. - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if none match. - */ -goog.dom.DomHelper.prototype.getAncestorByClass = - goog.dom.getAncestorByClass; - - -/** - * Walks up the DOM hierarchy returning the first ancestor that passes the - * matcher function. - * @param {Node} element The DOM node to start with. - * @param {function(Node) : boolean} matcher A function that returns true if the - * passed node matches the desired criteria. - * @param {boolean=} opt_includeNode If true, the node itself is included in - * the search (the first call to the matcher will pass startElement as - * the node to test). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Node} DOM node that matched the matcher, or null if there was - * no match. - */ -goog.dom.DomHelper.prototype.getAncestor = goog.dom.getAncestor; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for detecting, adding and removing classes. Prefer - * this over goog.dom.classes for new code since it attempts to use classList - * (DOMTokenList: http://dom.spec.whatwg.org/#domtokenlist) which is faster - * and requires less code. - * - * Note: these utilities are meant to operate on HTMLElements - * and may have unexpected behavior on elements with differing interfaces - * (such as SVGElements). - */ - - -goog.provide('goog.dom.classlist'); - -goog.require('goog.array'); - - -/** - * Override this define at build-time if you know your target supports it. - * @define {boolean} Whether to use the classList property (DOMTokenList). - */ -goog.define('goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST', false); - - -/** - * Gets an array-like object of class names on an element. - * @param {Element} element DOM node to get the classes of. - * @return {!goog.array.ArrayLike} Class names on {@code element}. - */ -goog.dom.classlist.get = function(element) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - return element.classList; - } - - var className = element.className; - // Some types of elements don't have a className in IE (e.g. iframes). - // Furthermore, in Firefox, className is not a string when the element is - // an SVG element. - return goog.isString(className) && className.match(/\S+/g) || []; -}; - - -/** - * Sets the entire class name of an element. - * @param {Element} element DOM node to set class of. - * @param {string} className Class name(s) to apply to element. - */ -goog.dom.classlist.set = function(element, className) { - element.className = className; -}; - - -/** - * Returns true if an element has a class. This method may throw a DOM - * exception for an invalid or empty class name if DOMTokenList is used. - * @param {Element} element DOM node to test. - * @param {string} className Class name to test for. - * @return {boolean} Whether element has the class. - */ -goog.dom.classlist.contains = function(element, className) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - return element.classList.contains(className); - } - return goog.array.contains(goog.dom.classlist.get(element), className); -}; - - -/** - * Adds a class to an element. Does not add multiples of class names. This - * method may throw a DOM exception for an invalid or empty class name if - * DOMTokenList is used. - * @param {Element} element DOM node to add class to. - * @param {string} className Class name to add. - */ -goog.dom.classlist.add = function(element, className) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - element.classList.add(className); - return; - } - - if (!goog.dom.classlist.contains(element, className)) { - // Ensure we add a space if this is not the first class name added. - element.className += element.className.length > 0 ? - (' ' + className) : className; - } -}; - - -/** - * Convenience method to add a number of class names at once. - * @param {Element} element The element to which to add classes. - * @param {goog.array.ArrayLike<string>} classesToAdd An array-like object - * containing a collection of class names to add to the element. - * This method may throw a DOM exception if classesToAdd contains invalid - * or empty class names. - */ -goog.dom.classlist.addAll = function(element, classesToAdd) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - goog.array.forEach(classesToAdd, function(className) { - goog.dom.classlist.add(element, className); - }); - return; - } - - var classMap = {}; - - // Get all current class names into a map. - goog.array.forEach(goog.dom.classlist.get(element), - function(className) { - classMap[className] = true; - }); - - // Add new class names to the map. - goog.array.forEach(classesToAdd, - function(className) { - classMap[className] = true; - }); - - // Flatten the keys of the map into the className. - element.className = ''; - for (var className in classMap) { - element.className += element.className.length > 0 ? - (' ' + className) : className; - } -}; - - -/** - * Removes a class from an element. This method may throw a DOM exception - * for an invalid or empty class name if DOMTokenList is used. - * @param {Element} element DOM node to remove class from. - * @param {string} className Class name to remove. - */ -goog.dom.classlist.remove = function(element, className) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - element.classList.remove(className); - return; - } - - if (goog.dom.classlist.contains(element, className)) { - // Filter out the class name. - element.className = goog.array.filter( - goog.dom.classlist.get(element), - function(c) { - return c != className; - }).join(' '); - } -}; - - -/** - * Removes a set of classes from an element. Prefer this call to - * repeatedly calling {@code goog.dom.classlist.remove} if you want to remove - * a large set of class names at once. - * @param {Element} element The element from which to remove classes. - * @param {goog.array.ArrayLike<string>} classesToRemove An array-like object - * containing a collection of class names to remove from the element. - * This method may throw a DOM exception if classesToRemove contains invalid - * or empty class names. - */ -goog.dom.classlist.removeAll = function(element, classesToRemove) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - goog.array.forEach(classesToRemove, function(className) { - goog.dom.classlist.remove(element, className); - }); - return; - } - // Filter out those classes in classesToRemove. - element.className = goog.array.filter( - goog.dom.classlist.get(element), - function(className) { - // If this class is not one we are trying to remove, - // add it to the array of new class names. - return !goog.array.contains(classesToRemove, className); - }).join(' '); -}; - - -/** - * Adds or removes a class depending on the enabled argument. This method - * may throw a DOM exception for an invalid or empty class name if DOMTokenList - * is used. - * @param {Element} element DOM node to add or remove the class on. - * @param {string} className Class name to add or remove. - * @param {boolean} enabled Whether to add or remove the class (true adds, - * false removes). - */ -goog.dom.classlist.enable = function(element, className, enabled) { - if (enabled) { - goog.dom.classlist.add(element, className); - } else { - goog.dom.classlist.remove(element, className); - } -}; - - -/** - * Adds or removes a set of classes depending on the enabled argument. This - * method may throw a DOM exception for an invalid or empty class name if - * DOMTokenList is used. - * @param {!Element} element DOM node to add or remove the class on. - * @param {goog.array.ArrayLike<string>} classesToEnable An array-like object - * containing a collection of class names to add or remove from the element. - * @param {boolean} enabled Whether to add or remove the classes (true adds, - * false removes). - */ -goog.dom.classlist.enableAll = function(element, classesToEnable, enabled) { - var f = enabled ? goog.dom.classlist.addAll : - goog.dom.classlist.removeAll; - f(element, classesToEnable); -}; - - -/** - * Switches a class on an element from one to another without disturbing other - * classes. If the fromClass isn't removed, the toClass won't be added. This - * method may throw a DOM exception if the class names are empty or invalid. - * @param {Element} element DOM node to swap classes on. - * @param {string} fromClass Class to remove. - * @param {string} toClass Class to add. - * @return {boolean} Whether classes were switched. - */ -goog.dom.classlist.swap = function(element, fromClass, toClass) { - if (goog.dom.classlist.contains(element, fromClass)) { - goog.dom.classlist.remove(element, fromClass); - goog.dom.classlist.add(element, toClass); - return true; - } - return false; -}; - - -/** - * Removes a class if an element has it, and adds it the element doesn't have - * it. Won't affect other classes on the node. This method may throw a DOM - * exception if the class name is empty or invalid. - * @param {Element} element DOM node to toggle class on. - * @param {string} className Class to toggle. - * @return {boolean} True if class was added, false if it was removed - * (in other words, whether element has the class after this function has - * been called). - */ -goog.dom.classlist.toggle = function(element, className) { - var add = !goog.dom.classlist.contains(element, className); - goog.dom.classlist.enable(element, className, add); - return add; -}; - - -/** - * Adds and removes a class of an element. Unlike - * {@link goog.dom.classlist.swap}, this method adds the classToAdd regardless - * of whether the classToRemove was present and had been removed. This method - * may throw a DOM exception if the class names are empty or invalid. - * - * @param {Element} element DOM node to swap classes on. - * @param {string} classToRemove Class to remove. - * @param {string} classToAdd Class to add. - */ -goog.dom.classlist.addRemove = function(element, classToRemove, classToAdd) { - goog.dom.classlist.remove(element, classToRemove); - goog.dom.classlist.add(element, classToAdd); -}; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Vendor prefix getters. - */ - -goog.provide('goog.dom.vendor'); - -goog.require('goog.string'); -goog.require('goog.userAgent'); - - -/** - * Returns the JS vendor prefix used in CSS properties. Different vendors - * use different methods of changing the case of the property names. - * - * @return {?string} The JS vendor prefix or null if there is none. - */ -goog.dom.vendor.getVendorJsPrefix = function() { - if (goog.userAgent.WEBKIT) { - return 'Webkit'; - } else if (goog.userAgent.GECKO) { - return 'Moz'; - } else if (goog.userAgent.IE) { - return 'ms'; - } else if (goog.userAgent.OPERA) { - return 'O'; - } - - return null; -}; - - -/** - * Returns the vendor prefix used in CSS properties. - * - * @return {?string} The vendor prefix or null if there is none. - */ -goog.dom.vendor.getVendorPrefix = function() { - if (goog.userAgent.WEBKIT) { - return '-webkit'; - } else if (goog.userAgent.GECKO) { - return '-moz'; - } else if (goog.userAgent.IE) { - return '-ms'; - } else if (goog.userAgent.OPERA) { - return '-o'; - } - - return null; -}; - - -/** - * @param {string} propertyName A property name. - * @param {!Object=} opt_object If provided, we verify if the property exists in - * the object. - * @return {?string} A vendor prefixed property name, or null if it does not - * exist. - */ -goog.dom.vendor.getPrefixedPropertyName = function(propertyName, opt_object) { - // We first check for a non-prefixed property, if available. - if (opt_object && propertyName in opt_object) { - return propertyName; - } - var prefix = goog.dom.vendor.getVendorJsPrefix(); - if (prefix) { - prefix = prefix.toLowerCase(); - var prefixedPropertyName = prefix + goog.string.toTitleCase(propertyName); - return (!goog.isDef(opt_object) || prefixedPropertyName in opt_object) ? - prefixedPropertyName : null; - } - return null; -}; - - -/** - * @param {string} eventType An event type. - * @return {string} A lower-cased vendor prefixed event type. - */ -goog.dom.vendor.getPrefixedEventType = function(eventType) { - var prefix = goog.dom.vendor.getVendorJsPrefix() || ''; - return (prefix + eventType).toLowerCase(); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A utility class for representing a numeric box. - */ - - -goog.provide('goog.math.Box'); - -goog.require('goog.math.Coordinate'); - - - -/** - * Class for representing a box. A box is specified as a top, right, bottom, - * and left. A box is useful for representing margins and padding. - * - * This class assumes 'screen coordinates': larger Y coordinates are further - * from the top of the screen. - * - * @param {number} top Top. - * @param {number} right Right. - * @param {number} bottom Bottom. - * @param {number} left Left. - * @struct - * @constructor - */ -goog.math.Box = function(top, right, bottom, left) { - /** - * Top - * @type {number} - */ - this.top = top; - - /** - * Right - * @type {number} - */ - this.right = right; - - /** - * Bottom - * @type {number} - */ - this.bottom = bottom; - - /** - * Left - * @type {number} - */ - this.left = left; -}; - - -/** - * Creates a Box by bounding a collection of goog.math.Coordinate objects - * @param {...goog.math.Coordinate} var_args Coordinates to be included inside - * the box. - * @return {!goog.math.Box} A Box containing all the specified Coordinates. - */ -goog.math.Box.boundingBox = function(var_args) { - var box = new goog.math.Box(arguments[0].y, arguments[0].x, - arguments[0].y, arguments[0].x); - for (var i = 1; i < arguments.length; i++) { - box.expandToIncludeCoordinate(arguments[i]); - } - return box; -}; - - -/** - * @return {number} width The width of this Box. - */ -goog.math.Box.prototype.getWidth = function() { - return this.right - this.left; -}; - - -/** - * @return {number} height The height of this Box. - */ -goog.math.Box.prototype.getHeight = function() { - return this.bottom - this.top; -}; - - -/** - * Creates a copy of the box with the same dimensions. - * @return {!goog.math.Box} A clone of this Box. - */ -goog.math.Box.prototype.clone = function() { - return new goog.math.Box(this.top, this.right, this.bottom, this.left); -}; - - -if (goog.DEBUG) { - /** - * Returns a nice string representing the box. - * @return {string} In the form (50t, 73r, 24b, 13l). - * @override - */ - goog.math.Box.prototype.toString = function() { - return '(' + this.top + 't, ' + this.right + 'r, ' + this.bottom + 'b, ' + - this.left + 'l)'; - }; -} - - -/** - * Returns whether the box contains a coordinate or another box. - * - * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box. - * @return {boolean} Whether the box contains the coordinate or other box. - */ -goog.math.Box.prototype.contains = function(other) { - return goog.math.Box.contains(this, other); -}; - - -/** - * Expands box with the given margins. - * - * @param {number|goog.math.Box} top Top margin or box with all margins. - * @param {number=} opt_right Right margin. - * @param {number=} opt_bottom Bottom margin. - * @param {number=} opt_left Left margin. - * @return {!goog.math.Box} A reference to this Box. - */ -goog.math.Box.prototype.expand = function(top, opt_right, opt_bottom, - opt_left) { - if (goog.isObject(top)) { - this.top -= top.top; - this.right += top.right; - this.bottom += top.bottom; - this.left -= top.left; - } else { - this.top -= top; - this.right += opt_right; - this.bottom += opt_bottom; - this.left -= opt_left; - } - - return this; -}; - - -/** - * Expand this box to include another box. - * NOTE(user): This is used in code that needs to be very fast, please don't - * add functionality to this function at the expense of speed (variable - * arguments, accepting multiple argument types, etc). - * @param {goog.math.Box} box The box to include in this one. - */ -goog.math.Box.prototype.expandToInclude = function(box) { - this.left = Math.min(this.left, box.left); - this.top = Math.min(this.top, box.top); - this.right = Math.max(this.right, box.right); - this.bottom = Math.max(this.bottom, box.bottom); -}; - - -/** - * Expand this box to include the coordinate. - * @param {!goog.math.Coordinate} coord The coordinate to be included - * inside the box. - */ -goog.math.Box.prototype.expandToIncludeCoordinate = function(coord) { - this.top = Math.min(this.top, coord.y); - this.right = Math.max(this.right, coord.x); - this.bottom = Math.max(this.bottom, coord.y); - this.left = Math.min(this.left, coord.x); -}; - - -/** - * Compares boxes for equality. - * @param {goog.math.Box} a A Box. - * @param {goog.math.Box} b A Box. - * @return {boolean} True iff the boxes are equal, or if both are null. - */ -goog.math.Box.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.top == b.top && a.right == b.right && - a.bottom == b.bottom && a.left == b.left; -}; - - -/** - * Returns whether a box contains a coordinate or another box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box. - * @return {boolean} Whether the box contains the coordinate or other box. - */ -goog.math.Box.contains = function(box, other) { - if (!box || !other) { - return false; - } - - if (other instanceof goog.math.Box) { - return other.left >= box.left && other.right <= box.right && - other.top >= box.top && other.bottom <= box.bottom; - } - - // other is a Coordinate. - return other.x >= box.left && other.x <= box.right && - other.y >= box.top && other.y <= box.bottom; -}; - - -/** - * Returns the relative x position of a coordinate compared to a box. Returns - * zero if the coordinate is inside the box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate} coord A Coordinate. - * @return {number} The x position of {@code coord} relative to the nearest - * side of {@code box}, or zero if {@code coord} is inside {@code box}. - */ -goog.math.Box.relativePositionX = function(box, coord) { - if (coord.x < box.left) { - return coord.x - box.left; - } else if (coord.x > box.right) { - return coord.x - box.right; - } - return 0; -}; - - -/** - * Returns the relative y position of a coordinate compared to a box. Returns - * zero if the coordinate is inside the box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate} coord A Coordinate. - * @return {number} The y position of {@code coord} relative to the nearest - * side of {@code box}, or zero if {@code coord} is inside {@code box}. - */ -goog.math.Box.relativePositionY = function(box, coord) { - if (coord.y < box.top) { - return coord.y - box.top; - } else if (coord.y > box.bottom) { - return coord.y - box.bottom; - } - return 0; -}; - - -/** - * Returns the distance between a coordinate and the nearest corner/side of a - * box. Returns zero if the coordinate is inside the box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate} coord A Coordinate. - * @return {number} The distance between {@code coord} and the nearest - * corner/side of {@code box}, or zero if {@code coord} is inside - * {@code box}. - */ -goog.math.Box.distance = function(box, coord) { - var x = goog.math.Box.relativePositionX(box, coord); - var y = goog.math.Box.relativePositionY(box, coord); - return Math.sqrt(x * x + y * y); -}; - - -/** - * Returns whether two boxes intersect. - * - * @param {goog.math.Box} a A Box. - * @param {goog.math.Box} b A second Box. - * @return {boolean} Whether the boxes intersect. - */ -goog.math.Box.intersects = function(a, b) { - return (a.left <= b.right && b.left <= a.right && - a.top <= b.bottom && b.top <= a.bottom); -}; - - -/** - * Returns whether two boxes would intersect with additional padding. - * - * @param {goog.math.Box} a A Box. - * @param {goog.math.Box} b A second Box. - * @param {number} padding The additional padding. - * @return {boolean} Whether the boxes intersect. - */ -goog.math.Box.intersectsWithPadding = function(a, b, padding) { - return (a.left <= b.right + padding && b.left <= a.right + padding && - a.top <= b.bottom + padding && b.top <= a.bottom + padding); -}; - - -/** - * Rounds the fields to the next larger integer values. - * - * @return {!goog.math.Box} This box with ceil'd fields. - */ -goog.math.Box.prototype.ceil = function() { - this.top = Math.ceil(this.top); - this.right = Math.ceil(this.right); - this.bottom = Math.ceil(this.bottom); - this.left = Math.ceil(this.left); - return this; -}; - - -/** - * Rounds the fields to the next smaller integer values. - * - * @return {!goog.math.Box} This box with floored fields. - */ -goog.math.Box.prototype.floor = function() { - this.top = Math.floor(this.top); - this.right = Math.floor(this.right); - this.bottom = Math.floor(this.bottom); - this.left = Math.floor(this.left); - return this; -}; - - -/** - * Rounds the fields to nearest integer values. - * - * @return {!goog.math.Box} This box with rounded fields. - */ -goog.math.Box.prototype.round = function() { - this.top = Math.round(this.top); - this.right = Math.round(this.right); - this.bottom = Math.round(this.bottom); - this.left = Math.round(this.left); - return this; -}; - - -/** - * Translates this box by the given offsets. If a {@code goog.math.Coordinate} - * is given, then the left and right values are translated by the coordinate's - * x value and the top and bottom values are translated by the coordinate's y - * value. Otherwise, {@code tx} and {@code opt_ty} are used to translate the x - * and y dimension values. - * - * @param {number|goog.math.Coordinate} tx The value to translate the x - * dimension values by or the the coordinate to translate this box by. - * @param {number=} opt_ty The value to translate y dimension values by. - * @return {!goog.math.Box} This box after translating. - */ -goog.math.Box.prototype.translate = function(tx, opt_ty) { - if (tx instanceof goog.math.Coordinate) { - this.left += tx.x; - this.right += tx.x; - this.top += tx.y; - this.bottom += tx.y; - } else { - this.left += tx; - this.right += tx; - if (goog.isNumber(opt_ty)) { - this.top += opt_ty; - this.bottom += opt_ty; - } - } - return this; -}; - - -/** - * Scales this coordinate by the given scale factors. The x and y dimension - * values are scaled by {@code sx} and {@code opt_sy} respectively. - * If {@code opt_sy} is not given, then {@code sx} is used for both x and y. - * - * @param {number} sx The scale factor to use for the x dimension. - * @param {number=} opt_sy The scale factor to use for the y dimension. - * @return {!goog.math.Box} This box after scaling. - */ -goog.math.Box.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.left *= sx; - this.right *= sx; - this.top *= sy; - this.bottom *= sy; - return this; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A utility class for representing rectangles. - */ - -goog.provide('goog.math.Rect'); - -goog.require('goog.math.Box'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Size'); - - - -/** - * Class for representing rectangular regions. - * @param {number} x Left. - * @param {number} y Top. - * @param {number} w Width. - * @param {number} h Height. - * @struct - * @constructor - */ -goog.math.Rect = function(x, y, w, h) { - /** @type {number} */ - this.left = x; - - /** @type {number} */ - this.top = y; - - /** @type {number} */ - this.width = w; - - /** @type {number} */ - this.height = h; -}; - - -/** - * @return {!goog.math.Rect} A new copy of this Rectangle. - */ -goog.math.Rect.prototype.clone = function() { - return new goog.math.Rect(this.left, this.top, this.width, this.height); -}; - - -/** - * Returns a new Box object with the same position and dimensions as this - * rectangle. - * @return {!goog.math.Box} A new Box representation of this Rectangle. - */ -goog.math.Rect.prototype.toBox = function() { - var right = this.left + this.width; - var bottom = this.top + this.height; - return new goog.math.Box(this.top, - right, - bottom, - this.left); -}; - - -/** - * Creates a new Rect object with the position and size given. - * @param {!goog.math.Coordinate} position The top-left coordinate of the Rect - * @param {!goog.math.Size} size The size of the Rect - * @return {!goog.math.Rect} A new Rect initialized with the given position and - * size. - */ -goog.math.Rect.createFromPositionAndSize = function(position, size) { - return new goog.math.Rect(position.x, position.y, size.width, size.height); -}; - - -/** - * Creates a new Rect object with the same position and dimensions as a given - * Box. Note that this is only the inverse of toBox if left/top are defined. - * @param {goog.math.Box} box A box. - * @return {!goog.math.Rect} A new Rect initialized with the box's position - * and size. - */ -goog.math.Rect.createFromBox = function(box) { - return new goog.math.Rect(box.left, box.top, - box.right - box.left, box.bottom - box.top); -}; - - -if (goog.DEBUG) { - /** - * Returns a nice string representing size and dimensions of rectangle. - * @return {string} In the form (50, 73 - 75w x 25h). - * @override - */ - goog.math.Rect.prototype.toString = function() { - return '(' + this.left + ', ' + this.top + ' - ' + this.width + 'w x ' + - this.height + 'h)'; - }; -} - - -/** - * Compares rectangles for equality. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {boolean} True iff the rectangles have the same left, top, width, - * and height, or if both are null. - */ -goog.math.Rect.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.left == b.left && a.width == b.width && - a.top == b.top && a.height == b.height; -}; - - -/** - * Computes the intersection of this rectangle and the rectangle parameter. If - * there is no intersection, returns false and leaves this rectangle as is. - * @param {goog.math.Rect} rect A Rectangle. - * @return {boolean} True iff this rectangle intersects with the parameter. - */ -goog.math.Rect.prototype.intersection = function(rect) { - var x0 = Math.max(this.left, rect.left); - var x1 = Math.min(this.left + this.width, rect.left + rect.width); - - if (x0 <= x1) { - var y0 = Math.max(this.top, rect.top); - var y1 = Math.min(this.top + this.height, rect.top + rect.height); - - if (y0 <= y1) { - this.left = x0; - this.top = y0; - this.width = x1 - x0; - this.height = y1 - y0; - - return true; - } - } - return false; -}; - - -/** - * Returns the intersection of two rectangles. Two rectangles intersect if they - * touch at all, for example, two zero width and height rectangles would - * intersect if they had the same top and left. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {goog.math.Rect} A new intersection rect (even if width and height - * are 0), or null if there is no intersection. - */ -goog.math.Rect.intersection = function(a, b) { - // There is no nice way to do intersection via a clone, because any such - // clone might be unnecessary if this function returns null. So, we duplicate - // code from above. - - var x0 = Math.max(a.left, b.left); - var x1 = Math.min(a.left + a.width, b.left + b.width); - - if (x0 <= x1) { - var y0 = Math.max(a.top, b.top); - var y1 = Math.min(a.top + a.height, b.top + b.height); - - if (y0 <= y1) { - return new goog.math.Rect(x0, y0, x1 - x0, y1 - y0); - } - } - return null; -}; - - -/** - * Returns whether two rectangles intersect. Two rectangles intersect if they - * touch at all, for example, two zero width and height rectangles would - * intersect if they had the same top and left. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {boolean} Whether a and b intersect. - */ -goog.math.Rect.intersects = function(a, b) { - return (a.left <= b.left + b.width && b.left <= a.left + a.width && - a.top <= b.top + b.height && b.top <= a.top + a.height); -}; - - -/** - * Returns whether a rectangle intersects this rectangle. - * @param {goog.math.Rect} rect A rectangle. - * @return {boolean} Whether rect intersects this rectangle. - */ -goog.math.Rect.prototype.intersects = function(rect) { - return goog.math.Rect.intersects(this, rect); -}; - - -/** - * Computes the difference regions between two rectangles. The return value is - * an array of 0 to 4 rectangles defining the remaining regions of the first - * rectangle after the second has been subtracted. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {!Array<!goog.math.Rect>} An array with 0 to 4 rectangles which - * together define the difference area of rectangle a minus rectangle b. - */ -goog.math.Rect.difference = function(a, b) { - var intersection = goog.math.Rect.intersection(a, b); - if (!intersection || !intersection.height || !intersection.width) { - return [a.clone()]; - } - - var result = []; - - var top = a.top; - var height = a.height; - - var ar = a.left + a.width; - var ab = a.top + a.height; - - var br = b.left + b.width; - var bb = b.top + b.height; - - // Subtract off any area on top where A extends past B - if (b.top > a.top) { - result.push(new goog.math.Rect(a.left, a.top, a.width, b.top - a.top)); - top = b.top; - // If we're moving the top down, we also need to subtract the height diff. - height -= b.top - a.top; - } - // Subtract off any area on bottom where A extends past B - if (bb < ab) { - result.push(new goog.math.Rect(a.left, bb, a.width, ab - bb)); - height = bb - top; - } - // Subtract any area on left where A extends past B - if (b.left > a.left) { - result.push(new goog.math.Rect(a.left, top, b.left - a.left, height)); - } - // Subtract any area on right where A extends past B - if (br < ar) { - result.push(new goog.math.Rect(br, top, ar - br, height)); - } - - return result; -}; - - -/** - * Computes the difference regions between this rectangle and {@code rect}. The - * return value is an array of 0 to 4 rectangles defining the remaining regions - * of this rectangle after the other has been subtracted. - * @param {goog.math.Rect} rect A Rectangle. - * @return {!Array<!goog.math.Rect>} An array with 0 to 4 rectangles which - * together define the difference area of rectangle a minus rectangle b. - */ -goog.math.Rect.prototype.difference = function(rect) { - return goog.math.Rect.difference(this, rect); -}; - - -/** - * Expand this rectangle to also include the area of the given rectangle. - * @param {goog.math.Rect} rect The other rectangle. - */ -goog.math.Rect.prototype.boundingRect = function(rect) { - // We compute right and bottom before we change left and top below. - var right = Math.max(this.left + this.width, rect.left + rect.width); - var bottom = Math.max(this.top + this.height, rect.top + rect.height); - - this.left = Math.min(this.left, rect.left); - this.top = Math.min(this.top, rect.top); - - this.width = right - this.left; - this.height = bottom - this.top; -}; - - -/** - * Returns a new rectangle which completely contains both input rectangles. - * @param {goog.math.Rect} a A rectangle. - * @param {goog.math.Rect} b A rectangle. - * @return {goog.math.Rect} A new bounding rect, or null if either rect is - * null. - */ -goog.math.Rect.boundingRect = function(a, b) { - if (!a || !b) { - return null; - } - - var clone = a.clone(); - clone.boundingRect(b); - - return clone; -}; - - -/** - * Tests whether this rectangle entirely contains another rectangle or - * coordinate. - * - * @param {goog.math.Rect|goog.math.Coordinate} another The rectangle or - * coordinate to test for containment. - * @return {boolean} Whether this rectangle contains given rectangle or - * coordinate. - */ -goog.math.Rect.prototype.contains = function(another) { - if (another instanceof goog.math.Rect) { - return this.left <= another.left && - this.left + this.width >= another.left + another.width && - this.top <= another.top && - this.top + this.height >= another.top + another.height; - } else { // (another instanceof goog.math.Coordinate) - return another.x >= this.left && - another.x <= this.left + this.width && - another.y >= this.top && - another.y <= this.top + this.height; - } -}; - - -/** - * @param {!goog.math.Coordinate} point A coordinate. - * @return {number} The squared distance between the point and the closest - * point inside the rectangle. Returns 0 if the point is inside the - * rectangle. - */ -goog.math.Rect.prototype.squaredDistance = function(point) { - var dx = point.x < this.left ? - this.left - point.x : Math.max(point.x - (this.left + this.width), 0); - var dy = point.y < this.top ? - this.top - point.y : Math.max(point.y - (this.top + this.height), 0); - return dx * dx + dy * dy; -}; - - -/** - * @param {!goog.math.Coordinate} point A coordinate. - * @return {number} The distance between the point and the closest point - * inside the rectangle. Returns 0 if the point is inside the rectangle. - */ -goog.math.Rect.prototype.distance = function(point) { - return Math.sqrt(this.squaredDistance(point)); -}; - - -/** - * @return {!goog.math.Size} The size of this rectangle. - */ -goog.math.Rect.prototype.getSize = function() { - return new goog.math.Size(this.width, this.height); -}; - - -/** - * @return {!goog.math.Coordinate} A new coordinate for the top-left corner of - * the rectangle. - */ -goog.math.Rect.prototype.getTopLeft = function() { - return new goog.math.Coordinate(this.left, this.top); -}; - - -/** - * @return {!goog.math.Coordinate} A new coordinate for the center of the - * rectangle. - */ -goog.math.Rect.prototype.getCenter = function() { - return new goog.math.Coordinate( - this.left + this.width / 2, this.top + this.height / 2); -}; - - -/** - * @return {!goog.math.Coordinate} A new coordinate for the bottom-right corner - * of the rectangle. - */ -goog.math.Rect.prototype.getBottomRight = function() { - return new goog.math.Coordinate( - this.left + this.width, this.top + this.height); -}; - - -/** - * Rounds the fields to the next larger integer values. - * @return {!goog.math.Rect} This rectangle with ceil'd fields. - */ -goog.math.Rect.prototype.ceil = function() { - this.left = Math.ceil(this.left); - this.top = Math.ceil(this.top); - this.width = Math.ceil(this.width); - this.height = Math.ceil(this.height); - return this; -}; - - -/** - * Rounds the fields to the next smaller integer values. - * @return {!goog.math.Rect} This rectangle with floored fields. - */ -goog.math.Rect.prototype.floor = function() { - this.left = Math.floor(this.left); - this.top = Math.floor(this.top); - this.width = Math.floor(this.width); - this.height = Math.floor(this.height); - return this; -}; - - -/** - * Rounds the fields to nearest integer values. - * @return {!goog.math.Rect} This rectangle with rounded fields. - */ -goog.math.Rect.prototype.round = function() { - this.left = Math.round(this.left); - this.top = Math.round(this.top); - this.width = Math.round(this.width); - this.height = Math.round(this.height); - return this; -}; - - -/** - * Translates this rectangle by the given offsets. If a - * {@code goog.math.Coordinate} is given, then the left and top values are - * translated by the coordinate's x and y values. Otherwise, top and left are - * translated by {@code tx} and {@code opt_ty} respectively. - * @param {number|goog.math.Coordinate} tx The value to translate left by or the - * the coordinate to translate this rect by. - * @param {number=} opt_ty The value to translate top by. - * @return {!goog.math.Rect} This rectangle after translating. - */ -goog.math.Rect.prototype.translate = function(tx, opt_ty) { - if (tx instanceof goog.math.Coordinate) { - this.left += tx.x; - this.top += tx.y; - } else { - this.left += tx; - if (goog.isNumber(opt_ty)) { - this.top += opt_ty; - } - } - return this; -}; - - -/** - * Scales this rectangle by the given scale factors. The left and width values - * are scaled by {@code sx} and the top and height values are scaled by - * {@code opt_sy}. If {@code opt_sy} is not given, then all fields are scaled - * by {@code sx}. - * @param {number} sx The scale factor to use for the x dimension. - * @param {number=} opt_sy The scale factor to use for the y dimension. - * @return {!goog.math.Rect} This rectangle after scaling. - */ -goog.math.Rect.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.left *= sx; - this.width *= sx; - this.top *= sy; - this.height *= sy; - return this; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for element styles. - * - * @author arv@google.com (Erik Arvidsson) - * @author eae@google.com (Emil A Eklund) - * @see ../demos/inline_block_quirks.html - * @see ../demos/inline_block_standards.html - * @see ../demos/style_viewport.html - */ - -goog.provide('goog.style'); - - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.vendor'); -goog.require('goog.math.Box'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Rect'); -goog.require('goog.math.Size'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.userAgent'); - -goog.forwardDeclare('goog.events.BrowserEvent'); -goog.forwardDeclare('goog.events.Event'); - - -/** - * Sets a style value on an element. - * - * This function is not indended to patch issues in the browser's style - * handling, but to allow easy programmatic access to setting dash-separated - * style properties. An example is setting a batch of properties from a data - * object without overwriting old styles. When possible, use native APIs: - * elem.style.propertyKey = 'value' or (if obliterating old styles is fine) - * elem.style.cssText = 'property1: value1; property2: value2'. - * - * @param {Element} element The element to change. - * @param {string|Object} style If a string, a style name. If an object, a hash - * of style names to style values. - * @param {string|number|boolean=} opt_value If style was a string, then this - * should be the value. - */ -goog.style.setStyle = function(element, style, opt_value) { - if (goog.isString(style)) { - goog.style.setStyle_(element, opt_value, style); - } else { - for (var key in style) { - goog.style.setStyle_(element, style[key], key); - } - } -}; - - -/** - * Sets a style value on an element, with parameters swapped to work with - * {@code goog.object.forEach()}. Prepends a vendor-specific prefix when - * necessary. - * @param {Element} element The element to change. - * @param {string|number|boolean|undefined} value Style value. - * @param {string} style Style name. - * @private - */ -goog.style.setStyle_ = function(element, value, style) { - var propertyName = goog.style.getVendorJsStyleName_(element, style); - - if (propertyName) { - element.style[propertyName] = value; - } -}; - - -/** - * Style name cache that stores previous property name lookups. - * - * This is used by setStyle to speed up property lookups, entries look like: - * { StyleName: ActualPropertyName } - * - * @private {!Object<string, string>} - */ -goog.style.styleNameCache_ = {}; - - -/** - * Returns the style property name in camel-case. If it does not exist and a - * vendor-specific version of the property does exist, then return the vendor- - * specific property name instead. - * @param {Element} element The element to change. - * @param {string} style Style name. - * @return {string} Vendor-specific style. - * @private - */ -goog.style.getVendorJsStyleName_ = function(element, style) { - var propertyName = goog.style.styleNameCache_[style]; - if (!propertyName) { - var camelStyle = goog.string.toCamelCase(style); - propertyName = camelStyle; - - if (element.style[camelStyle] === undefined) { - var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() + - goog.string.toTitleCase(camelStyle); - - if (element.style[prefixedStyle] !== undefined) { - propertyName = prefixedStyle; - } - } - goog.style.styleNameCache_[style] = propertyName; - } - - return propertyName; -}; - - -/** - * Returns the style property name in CSS notation. If it does not exist and a - * vendor-specific version of the property does exist, then return the vendor- - * specific property name instead. - * @param {Element} element The element to change. - * @param {string} style Style name. - * @return {string} Vendor-specific style. - * @private - */ -goog.style.getVendorStyleName_ = function(element, style) { - var camelStyle = goog.string.toCamelCase(style); - - if (element.style[camelStyle] === undefined) { - var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() + - goog.string.toTitleCase(camelStyle); - - if (element.style[prefixedStyle] !== undefined) { - return goog.dom.vendor.getVendorPrefix() + '-' + style; - } - } - - return style; -}; - - -/** - * Retrieves an explicitly-set style value of a node. This returns '' if there - * isn't a style attribute on the element or if this style property has not been - * explicitly set in script. - * - * @param {Element} element Element to get style of. - * @param {string} property Property to get, css-style (if you have a camel-case - * property, use element.style[style]). - * @return {string} Style value. - */ -goog.style.getStyle = function(element, property) { - // element.style is '' for well-known properties which are unset. - // For for browser specific styles as 'filter' is undefined - // so we need to return '' explicitly to make it consistent across - // browsers. - var styleValue = element.style[goog.string.toCamelCase(property)]; - - // Using typeof here because of a bug in Safari 5.1, where this value - // was undefined, but === undefined returned false. - if (typeof(styleValue) !== 'undefined') { - return styleValue; - } - - return element.style[goog.style.getVendorJsStyleName_(element, property)] || - ''; -}; - - -/** - * Retrieves a computed style value of a node. It returns empty string if the - * value cannot be computed (which will be the case in Internet Explorer) or - * "none" if the property requested is an SVG one and it has not been - * explicitly set (firefox and webkit). - * - * @param {Element} element Element to get style of. - * @param {string} property Property to get (camel-case). - * @return {string} Style value. - */ -goog.style.getComputedStyle = function(element, property) { - var doc = goog.dom.getOwnerDocument(element); - if (doc.defaultView && doc.defaultView.getComputedStyle) { - var styles = doc.defaultView.getComputedStyle(element, null); - if (styles) { - // element.style[..] is undefined for browser specific styles - // as 'filter'. - return styles[property] || styles.getPropertyValue(property) || ''; - } - } - - return ''; -}; - - -/** - * Gets the cascaded style value of a node, or null if the value cannot be - * computed (only Internet Explorer can do this). - * - * @param {Element} element Element to get style of. - * @param {string} style Property to get (camel-case). - * @return {string} Style value. - */ -goog.style.getCascadedStyle = function(element, style) { - // TODO(nicksantos): This should be documented to return null. #fixTypes - return element.currentStyle ? element.currentStyle[style] : null; -}; - - -/** - * Cross-browser pseudo get computed style. It returns the computed style where - * available. If not available it tries the cascaded style value (IE - * currentStyle) and in worst case the inline style value. It shouldn't be - * called directly, see http://wiki/Main/ComputedStyleVsCascadedStyle for - * discussion. - * - * @param {Element} element Element to get style of. - * @param {string} style Property to get (must be camelCase, not css-style.). - * @return {string} Style value. - * @private - */ -goog.style.getStyle_ = function(element, style) { - return goog.style.getComputedStyle(element, style) || - goog.style.getCascadedStyle(element, style) || - (element.style && element.style[style]); -}; - - -/** - * Retrieves the computed value of the box-sizing CSS attribute. - * Browser support: http://caniuse.com/css3-boxsizing. - * @param {!Element} element The element whose box-sizing to get. - * @return {?string} 'content-box', 'border-box' or 'padding-box'. null if - * box-sizing is not supported (IE7 and below). - */ -goog.style.getComputedBoxSizing = function(element) { - return goog.style.getStyle_(element, 'boxSizing') || - goog.style.getStyle_(element, 'MozBoxSizing') || - goog.style.getStyle_(element, 'WebkitBoxSizing') || null; -}; - - -/** - * Retrieves the computed value of the position CSS attribute. - * @param {Element} element The element to get the position of. - * @return {string} Position value. - */ -goog.style.getComputedPosition = function(element) { - return goog.style.getStyle_(element, 'position'); -}; - - -/** - * Retrieves the computed background color string for a given element. The - * string returned is suitable for assigning to another element's - * background-color, but is not guaranteed to be in any particular string - * format. Accessing the color in a numeric form may not be possible in all - * browsers or with all input. - * - * If the background color for the element is defined as a hexadecimal value, - * the resulting string can be parsed by goog.color.parse in all supported - * browsers. - * - * Whether named colors like "red" or "lightblue" get translated into a - * format which can be parsed is browser dependent. Calling this function on - * transparent elements will return "transparent" in most browsers or - * "rgba(0, 0, 0, 0)" in WebKit. - * @param {Element} element The element to get the background color of. - * @return {string} The computed string value of the background color. - */ -goog.style.getBackgroundColor = function(element) { - return goog.style.getStyle_(element, 'backgroundColor'); -}; - - -/** - * Retrieves the computed value of the overflow-x CSS attribute. - * @param {Element} element The element to get the overflow-x of. - * @return {string} The computed string value of the overflow-x attribute. - */ -goog.style.getComputedOverflowX = function(element) { - return goog.style.getStyle_(element, 'overflowX'); -}; - - -/** - * Retrieves the computed value of the overflow-y CSS attribute. - * @param {Element} element The element to get the overflow-y of. - * @return {string} The computed string value of the overflow-y attribute. - */ -goog.style.getComputedOverflowY = function(element) { - return goog.style.getStyle_(element, 'overflowY'); -}; - - -/** - * Retrieves the computed value of the z-index CSS attribute. - * @param {Element} element The element to get the z-index of. - * @return {string|number} The computed value of the z-index attribute. - */ -goog.style.getComputedZIndex = function(element) { - return goog.style.getStyle_(element, 'zIndex'); -}; - - -/** - * Retrieves the computed value of the text-align CSS attribute. - * @param {Element} element The element to get the text-align of. - * @return {string} The computed string value of the text-align attribute. - */ -goog.style.getComputedTextAlign = function(element) { - return goog.style.getStyle_(element, 'textAlign'); -}; - - -/** - * Retrieves the computed value of the cursor CSS attribute. - * @param {Element} element The element to get the cursor of. - * @return {string} The computed string value of the cursor attribute. - */ -goog.style.getComputedCursor = function(element) { - return goog.style.getStyle_(element, 'cursor'); -}; - - -/** - * Retrieves the computed value of the CSS transform attribute. - * @param {Element} element The element to get the transform of. - * @return {string} The computed string representation of the transform matrix. - */ -goog.style.getComputedTransform = function(element) { - var property = goog.style.getVendorStyleName_(element, 'transform'); - return goog.style.getStyle_(element, property) || - goog.style.getStyle_(element, 'transform'); -}; - - -/** - * Sets the top/left values of an element. If no unit is specified in the - * argument then it will add px. The second argument is required if the first - * argument is a string or number and is ignored if the first argument - * is a coordinate. - * @param {Element} el Element to move. - * @param {string|number|goog.math.Coordinate} arg1 Left position or coordinate. - * @param {string|number=} opt_arg2 Top position. - */ -goog.style.setPosition = function(el, arg1, opt_arg2) { - var x, y; - - if (arg1 instanceof goog.math.Coordinate) { - x = arg1.x; - y = arg1.y; - } else { - x = arg1; - y = opt_arg2; - } - - el.style.left = goog.style.getPixelStyleValue_( - /** @type {number|string} */ (x), false); - el.style.top = goog.style.getPixelStyleValue_( - /** @type {number|string} */ (y), false); -}; - - -/** - * Gets the offsetLeft and offsetTop properties of an element and returns them - * in a Coordinate object - * @param {Element} element Element. - * @return {!goog.math.Coordinate} The position. - */ -goog.style.getPosition = function(element) { - return new goog.math.Coordinate( - /** @type {!HTMLElement} */ (element).offsetLeft, - /** @type {!HTMLElement} */ (element).offsetTop); -}; - - -/** - * Returns the viewport element for a particular document - * @param {Node=} opt_node DOM node (Document is OK) to get the viewport element - * of. - * @return {Element} document.documentElement or document.body. - */ -goog.style.getClientViewportElement = function(opt_node) { - var doc; - if (opt_node) { - doc = goog.dom.getOwnerDocument(opt_node); - } else { - doc = goog.dom.getDocument(); - } - - // In old IE versions the document.body represented the viewport - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) && - !goog.dom.getDomHelper(doc).isCss1CompatMode()) { - return doc.body; - } - return doc.documentElement; -}; - - -/** - * Calculates the viewport coordinates relative to the page/document - * containing the node. The viewport may be the browser viewport for - * non-iframe document, or the iframe container for iframe'd document. - * @param {!Document} doc The document to use as the reference point. - * @return {!goog.math.Coordinate} The page offset of the viewport. - */ -goog.style.getViewportPageOffset = function(doc) { - var body = doc.body; - var documentElement = doc.documentElement; - var scrollLeft = body.scrollLeft || documentElement.scrollLeft; - var scrollTop = body.scrollTop || documentElement.scrollTop; - return new goog.math.Coordinate(scrollLeft, scrollTop); -}; - - -/** - * Gets the client rectangle of the DOM element. - * - * getBoundingClientRect is part of a new CSS object model draft (with a - * long-time presence in IE), replacing the error-prone parent offset - * computation and the now-deprecated Gecko getBoxObjectFor. - * - * This utility patches common browser bugs in getBoundingClientRect. It - * will fail if getBoundingClientRect is unsupported. - * - * If the element is not in the DOM, the result is undefined, and an error may - * be thrown depending on user agent. - * - * @param {!Element} el The element whose bounding rectangle is being queried. - * @return {Object} A native bounding rectangle with numerical left, top, - * right, and bottom. Reported by Firefox to be of object type ClientRect. - * @private - */ -goog.style.getBoundingClientRect_ = function(el) { - var rect; - try { - rect = el.getBoundingClientRect(); - } catch (e) { - // In IE < 9, calling getBoundingClientRect on an orphan element raises an - // "Unspecified Error". All other browsers return zeros. - return {'left': 0, 'top': 0, 'right': 0, 'bottom': 0}; - } - - // Patch the result in IE only, so that this function can be inlined if - // compiled for non-IE. - if (goog.userAgent.IE && el.ownerDocument.body) { - - // In IE, most of the time, 2 extra pixels are added to the top and left - // due to the implicit 2-pixel inset border. In IE6/7 quirks mode and - // IE6 standards mode, this border can be overridden by setting the - // document element's border to zero -- thus, we cannot rely on the - // offset always being 2 pixels. - - // In quirks mode, the offset can be determined by querying the body's - // clientLeft/clientTop, but in standards mode, it is found by querying - // the document element's clientLeft/clientTop. Since we already called - // getBoundingClientRect we have already forced a reflow, so it is not - // too expensive just to query them all. - - // See: http://msdn.microsoft.com/en-us/library/ms536433(VS.85).aspx - var doc = el.ownerDocument; - rect.left -= doc.documentElement.clientLeft + doc.body.clientLeft; - rect.top -= doc.documentElement.clientTop + doc.body.clientTop; - } - return rect; -}; - - -/** - * Returns the first parent that could affect the position of a given element. - * @param {Element} element The element to get the offset parent for. - * @return {Element} The first offset parent or null if one cannot be found. - */ -goog.style.getOffsetParent = function(element) { - // element.offsetParent does the right thing in IE7 and below. In other - // browsers it only includes elements with position absolute, relative or - // fixed, not elements with overflow set to auto or scroll. - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(8)) { - return element.offsetParent; - } - - var doc = goog.dom.getOwnerDocument(element); - var positionStyle = goog.style.getStyle_(element, 'position'); - var skipStatic = positionStyle == 'fixed' || positionStyle == 'absolute'; - for (var parent = element.parentNode; parent && parent != doc; - parent = parent.parentNode) { - // Skip shadowDOM roots. - if (parent.nodeType == goog.dom.NodeType.DOCUMENT_FRAGMENT && - parent.host) { - parent = parent.host; - } - positionStyle = - goog.style.getStyle_(/** @type {!Element} */ (parent), 'position'); - skipStatic = skipStatic && positionStyle == 'static' && - parent != doc.documentElement && parent != doc.body; - if (!skipStatic && (parent.scrollWidth > parent.clientWidth || - parent.scrollHeight > parent.clientHeight || - positionStyle == 'fixed' || - positionStyle == 'absolute' || - positionStyle == 'relative')) { - return /** @type {!Element} */ (parent); - } - } - return null; -}; - - -/** - * Calculates and returns the visible rectangle for a given element. Returns a - * box describing the visible portion of the nearest scrollable offset ancestor. - * Coordinates are given relative to the document. - * - * @param {Element} element Element to get the visible rect for. - * @return {goog.math.Box} Bounding elementBox describing the visible rect or - * null if scrollable ancestor isn't inside the visible viewport. - */ -goog.style.getVisibleRectForElement = function(element) { - var visibleRect = new goog.math.Box(0, Infinity, Infinity, 0); - var dom = goog.dom.getDomHelper(element); - var body = dom.getDocument().body; - var documentElement = dom.getDocument().documentElement; - var scrollEl = dom.getDocumentScrollElement(); - - // Determine the size of the visible rect by climbing the dom accounting for - // all scrollable containers. - for (var el = element; el = goog.style.getOffsetParent(el); ) { - // clientWidth is zero for inline block elements in IE. - // on WEBKIT, body element can have clientHeight = 0 and scrollHeight > 0 - if ((!goog.userAgent.IE || el.clientWidth != 0) && - (!goog.userAgent.WEBKIT || el.clientHeight != 0 || el != body) && - // body may have overflow set on it, yet we still get the entire - // viewport. In some browsers, el.offsetParent may be - // document.documentElement, so check for that too. - (el != body && el != documentElement && - goog.style.getStyle_(el, 'overflow') != 'visible')) { - var pos = goog.style.getPageOffset(el); - var client = goog.style.getClientLeftTop(el); - pos.x += client.x; - pos.y += client.y; - - visibleRect.top = Math.max(visibleRect.top, pos.y); - visibleRect.right = Math.min(visibleRect.right, - pos.x + el.clientWidth); - visibleRect.bottom = Math.min(visibleRect.bottom, - pos.y + el.clientHeight); - visibleRect.left = Math.max(visibleRect.left, pos.x); - } - } - - // Clip by window's viewport. - var scrollX = scrollEl.scrollLeft, scrollY = scrollEl.scrollTop; - visibleRect.left = Math.max(visibleRect.left, scrollX); - visibleRect.top = Math.max(visibleRect.top, scrollY); - var winSize = dom.getViewportSize(); - visibleRect.right = Math.min(visibleRect.right, scrollX + winSize.width); - visibleRect.bottom = Math.min(visibleRect.bottom, scrollY + winSize.height); - return visibleRect.top >= 0 && visibleRect.left >= 0 && - visibleRect.bottom > visibleRect.top && - visibleRect.right > visibleRect.left ? - visibleRect : null; -}; - - -/** - * Calculate the scroll position of {@code container} with the minimum amount so - * that the content and the borders of the given {@code element} become visible. - * If the element is bigger than the container, its top left corner will be - * aligned as close to the container's top left corner as possible. - * - * @param {Element} element The element to make visible. - * @param {Element=} opt_container The container to scroll. If not set, then the - * document scroll element will be used. - * @param {boolean=} opt_center Whether to center the element in the container. - * Defaults to false. - * @return {!goog.math.Coordinate} The new scroll position of the container, - * in form of goog.math.Coordinate(scrollLeft, scrollTop). - */ -goog.style.getContainerOffsetToScrollInto = - function(element, opt_container, opt_center) { - var container = opt_container || goog.dom.getDocumentScrollElement(); - // Absolute position of the element's border's top left corner. - var elementPos = goog.style.getPageOffset(element); - // Absolute position of the container's border's top left corner. - var containerPos = goog.style.getPageOffset(container); - var containerBorder = goog.style.getBorderBox(container); - if (container == goog.dom.getDocumentScrollElement()) { - // The element position is calculated based on the page offset, and the - // document scroll element holds the scroll position within the page. We can - // use the scroll position to calculate the relative position from the - // element. - var relX = elementPos.x - container.scrollLeft; - var relY = elementPos.y - container.scrollTop; - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) { - // In older versions of IE getPageOffset(element) does not include the - // container border so it has to be added to accomodate. - relX += containerBorder.left; - relY += containerBorder.top; - } - } else { - // Relative pos. of the element's border box to the container's content box. - var relX = elementPos.x - containerPos.x - containerBorder.left; - var relY = elementPos.y - containerPos.y - containerBorder.top; - } - // How much the element can move in the container, i.e. the difference between - // the element's bottom-right-most and top-left-most position where it's - // fully visible. - var spaceX = container.clientWidth - - /** @type {HTMLElement} */ (element).offsetWidth; - var spaceY = container.clientHeight - - /** @type {HTMLElement} */ (element).offsetHeight; - - var scrollLeft = container.scrollLeft; - var scrollTop = container.scrollTop; - if (opt_center) { - // All browsers round non-integer scroll positions down. - scrollLeft += relX - spaceX / 2; - scrollTop += relY - spaceY / 2; - } else { - // This formula was designed to give the correct scroll values in the - // following cases: - // - element is higher than container (spaceY < 0) => scroll down by relY - // - element is not higher that container (spaceY >= 0): - // - it is above container (relY < 0) => scroll up by abs(relY) - // - it is below container (relY > spaceY) => scroll down by relY - spaceY - // - it is in the container => don't scroll - scrollLeft += Math.min(relX, Math.max(relX - spaceX, 0)); - scrollTop += Math.min(relY, Math.max(relY - spaceY, 0)); - } - return new goog.math.Coordinate(scrollLeft, scrollTop); -}; - - -/** - * Changes the scroll position of {@code container} with the minimum amount so - * that the content and the borders of the given {@code element} become visible. - * If the element is bigger than the container, its top left corner will be - * aligned as close to the container's top left corner as possible. - * - * @param {Element} element The element to make visible. - * @param {Element=} opt_container The container to scroll. If not set, then the - * document scroll element will be used. - * @param {boolean=} opt_center Whether to center the element in the container. - * Defaults to false. - */ -goog.style.scrollIntoContainerView = - function(element, opt_container, opt_center) { - var container = opt_container || goog.dom.getDocumentScrollElement(); - var offset = - goog.style.getContainerOffsetToScrollInto(element, container, opt_center); - container.scrollLeft = offset.x; - container.scrollTop = offset.y; -}; - - -/** - * Returns clientLeft (width of the left border and, if the directionality is - * right to left, the vertical scrollbar) and clientTop as a coordinate object. - * - * @param {Element} el Element to get clientLeft for. - * @return {!goog.math.Coordinate} Client left and top. - */ -goog.style.getClientLeftTop = function(el) { - return new goog.math.Coordinate(el.clientLeft, el.clientTop); -}; - - -/** - * Returns a Coordinate object relative to the top-left of the HTML document. - * Implemented as a single function to save having to do two recursive loops in - * opera and safari just to get both coordinates. If you just want one value do - * use goog.style.getPageOffsetLeft() and goog.style.getPageOffsetTop(), but - * note if you call both those methods the tree will be analysed twice. - * - * @param {Element} el Element to get the page offset for. - * @return {!goog.math.Coordinate} The page offset. - */ -goog.style.getPageOffset = function(el) { - var doc = goog.dom.getOwnerDocument(el); - // TODO(gboyer): Update the jsdoc in a way that doesn't break the universe. - goog.asserts.assertObject(el, 'Parameter is required'); - - // NOTE(arv): If element is hidden (display none or disconnected or any the - // ancestors are hidden) we get (0,0) by default but we still do the - // accumulation of scroll position. - - // TODO(arv): Should we check if the node is disconnected and in that case - // return (0,0)? - - var pos = new goog.math.Coordinate(0, 0); - var viewportElement = goog.style.getClientViewportElement(doc); - if (el == viewportElement) { - // viewport is always at 0,0 as that defined the coordinate system for this - // function - this avoids special case checks in the code below - return pos; - } - - var box = goog.style.getBoundingClientRect_(el); - // Must add the scroll coordinates in to get the absolute page offset - // of element since getBoundingClientRect returns relative coordinates to - // the viewport. - var scrollCoord = goog.dom.getDomHelper(doc).getDocumentScroll(); - pos.x = box.left + scrollCoord.x; - pos.y = box.top + scrollCoord.y; - - return pos; -}; - - -/** - * Returns the left coordinate of an element relative to the HTML document - * @param {Element} el Elements. - * @return {number} The left coordinate. - */ -goog.style.getPageOffsetLeft = function(el) { - return goog.style.getPageOffset(el).x; -}; - - -/** - * Returns the top coordinate of an element relative to the HTML document - * @param {Element} el Elements. - * @return {number} The top coordinate. - */ -goog.style.getPageOffsetTop = function(el) { - return goog.style.getPageOffset(el).y; -}; - - -/** - * Returns a Coordinate object relative to the top-left of an HTML document - * in an ancestor frame of this element. Used for measuring the position of - * an element inside a frame relative to a containing frame. - * - * @param {Element} el Element to get the page offset for. - * @param {Window} relativeWin The window to measure relative to. If relativeWin - * is not in the ancestor frame chain of the element, we measure relative to - * the top-most window. - * @return {!goog.math.Coordinate} The page offset. - */ -goog.style.getFramedPageOffset = function(el, relativeWin) { - var position = new goog.math.Coordinate(0, 0); - - // Iterate up the ancestor frame chain, keeping track of the current window - // and the current element in that window. - var currentWin = goog.dom.getWindow(goog.dom.getOwnerDocument(el)); - var currentEl = el; - do { - // if we're at the top window, we want to get the page offset. - // if we're at an inner frame, we only want to get the window position - // so that we can determine the actual page offset in the context of - // the outer window. - var offset = currentWin == relativeWin ? - goog.style.getPageOffset(currentEl) : - goog.style.getClientPositionForElement_( - goog.asserts.assert(currentEl)); - - position.x += offset.x; - position.y += offset.y; - } while (currentWin && currentWin != relativeWin && - currentWin != currentWin.parent && - (currentEl = currentWin.frameElement) && - (currentWin = currentWin.parent)); - - return position; -}; - - -/** - * Translates the specified rect relative to origBase page, for newBase page. - * If origBase and newBase are the same, this function does nothing. - * - * @param {goog.math.Rect} rect The source rectangle relative to origBase page, - * and it will have the translated result. - * @param {goog.dom.DomHelper} origBase The DomHelper for the input rectangle. - * @param {goog.dom.DomHelper} newBase The DomHelper for the resultant - * coordinate. This must be a DOM for an ancestor frame of origBase - * or the same as origBase. - */ -goog.style.translateRectForAnotherFrame = function(rect, origBase, newBase) { - if (origBase.getDocument() != newBase.getDocument()) { - var body = origBase.getDocument().body; - var pos = goog.style.getFramedPageOffset(body, newBase.getWindow()); - - // Adjust Body's margin. - pos = goog.math.Coordinate.difference(pos, goog.style.getPageOffset(body)); - - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) && - !origBase.isCss1CompatMode()) { - pos = goog.math.Coordinate.difference(pos, origBase.getDocumentScroll()); - } - - rect.left += pos.x; - rect.top += pos.y; - } -}; - - -/** - * Returns the position of an element relative to another element in the - * document. A relative to B - * @param {Element|Event|goog.events.Event} a Element or mouse event whose - * position we're calculating. - * @param {Element|Event|goog.events.Event} b Element or mouse event position - * is relative to. - * @return {!goog.math.Coordinate} The relative position. - */ -goog.style.getRelativePosition = function(a, b) { - var ap = goog.style.getClientPosition(a); - var bp = goog.style.getClientPosition(b); - return new goog.math.Coordinate(ap.x - bp.x, ap.y - bp.y); -}; - - -/** - * Returns the position of the event or the element's border box relative to - * the client viewport. - * @param {!Element} el Element whose position to get. - * @return {!goog.math.Coordinate} The position. - * @private - */ -goog.style.getClientPositionForElement_ = function(el) { - var box = goog.style.getBoundingClientRect_(el); - return new goog.math.Coordinate(box.left, box.top); -}; - - -/** - * Returns the position of the event or the element's border box relative to - * the client viewport. If an event is passed, and if this event is a "touch" - * event, then the position of the first changedTouches will be returned. - * @param {Element|Event|goog.events.Event} el Element or a mouse / touch event. - * @return {!goog.math.Coordinate} The position. - */ -goog.style.getClientPosition = function(el) { - goog.asserts.assert(el); - if (el.nodeType == goog.dom.NodeType.ELEMENT) { - return goog.style.getClientPositionForElement_( - /** @type {!Element} */ (el)); - } else { - var targetEvent = el.changedTouches ? el.changedTouches[0] : el; - return new goog.math.Coordinate( - targetEvent.clientX, - targetEvent.clientY); - } -}; - - -/** - * Moves an element to the given coordinates relative to the client viewport. - * @param {Element} el Absolutely positioned element to set page offset for. - * It must be in the document. - * @param {number|goog.math.Coordinate} x Left position of the element's margin - * box or a coordinate object. - * @param {number=} opt_y Top position of the element's margin box. - */ -goog.style.setPageOffset = function(el, x, opt_y) { - // Get current pageoffset - var cur = goog.style.getPageOffset(el); - - if (x instanceof goog.math.Coordinate) { - opt_y = x.y; - x = x.x; - } - - // NOTE(arv): We cannot allow strings for x and y. We could but that would - // require us to manually transform between different units - - // Work out deltas - var dx = x - cur.x; - var dy = opt_y - cur.y; - - // Set position to current left/top + delta - goog.style.setPosition(el, /** @type {!HTMLElement} */ (el).offsetLeft + dx, - /** @type {!HTMLElement} */ (el).offsetTop + dy); -}; - - -/** - * Sets the width/height values of an element. If an argument is numeric, - * or a goog.math.Size is passed, it is assumed to be pixels and will add - * 'px' after converting it to an integer in string form. (This just sets the - * CSS width and height properties so it might set content-box or border-box - * size depending on the box model the browser is using.) - * - * @param {Element} element Element to set the size of. - * @param {string|number|goog.math.Size} w Width of the element, or a - * size object. - * @param {string|number=} opt_h Height of the element. Required if w is not a - * size object. - */ -goog.style.setSize = function(element, w, opt_h) { - var h; - if (w instanceof goog.math.Size) { - h = w.height; - w = w.width; - } else { - if (opt_h == undefined) { - throw Error('missing height argument'); - } - h = opt_h; - } - - goog.style.setWidth(element, /** @type {string|number} */ (w)); - goog.style.setHeight(element, h); -}; - - -/** - * Helper function to create a string to be set into a pixel-value style - * property of an element. Can round to the nearest integer value. - * - * @param {string|number} value The style value to be used. If a number, - * 'px' will be appended, otherwise the value will be applied directly. - * @param {boolean} round Whether to round the nearest integer (if property - * is a number). - * @return {string} The string value for the property. - * @private - */ -goog.style.getPixelStyleValue_ = function(value, round) { - if (typeof value == 'number') { - value = (round ? Math.round(value) : value) + 'px'; - } - - return value; -}; - - -/** - * Set the height of an element. Sets the element's style property. - * @param {Element} element Element to set the height of. - * @param {string|number} height The height value to set. If a number, 'px' - * will be appended, otherwise the value will be applied directly. - */ -goog.style.setHeight = function(element, height) { - element.style.height = goog.style.getPixelStyleValue_(height, true); -}; - - -/** - * Set the width of an element. Sets the element's style property. - * @param {Element} element Element to set the width of. - * @param {string|number} width The width value to set. If a number, 'px' - * will be appended, otherwise the value will be applied directly. - */ -goog.style.setWidth = function(element, width) { - element.style.width = goog.style.getPixelStyleValue_(width, true); -}; - - -/** - * Gets the height and width of an element, even if its display is none. - * - * Specifically, this returns the height and width of the border box, - * irrespective of the box model in effect. - * - * Note that this function does not take CSS transforms into account. Please see - * {@code goog.style.getTransformedSize}. - * @param {Element} element Element to get size of. - * @return {!goog.math.Size} Object with width/height properties. - */ -goog.style.getSize = function(element) { - return goog.style.evaluateWithTemporaryDisplay_( - goog.style.getSizeWithDisplay_, /** @type {!Element} */ (element)); -}; - - -/** - * Call {@code fn} on {@code element} such that {@code element}'s dimensions are - * accurate when it's passed to {@code fn}. - * @param {function(!Element): T} fn Function to call with {@code element} as - * an argument after temporarily changing {@code element}'s display such - * that its dimensions are accurate. - * @param {!Element} element Element (which may have display none) to use as - * argument to {@code fn}. - * @return {T} Value returned by calling {@code fn} with {@code element}. - * @template T - * @private - */ -goog.style.evaluateWithTemporaryDisplay_ = function(fn, element) { - if (goog.style.getStyle_(element, 'display') != 'none') { - return fn(element); - } - - var style = element.style; - var originalDisplay = style.display; - var originalVisibility = style.visibility; - var originalPosition = style.position; - - style.visibility = 'hidden'; - style.position = 'absolute'; - style.display = 'inline'; - - var retVal = fn(element); - - style.display = originalDisplay; - style.position = originalPosition; - style.visibility = originalVisibility; - - return retVal; -}; - - -/** - * Gets the height and width of an element when the display is not none. - * @param {Element} element Element to get size of. - * @return {!goog.math.Size} Object with width/height properties. - * @private - */ -goog.style.getSizeWithDisplay_ = function(element) { - var offsetWidth = /** @type {!HTMLElement} */ (element).offsetWidth; - var offsetHeight = /** @type {!HTMLElement} */ (element).offsetHeight; - var webkitOffsetsZero = - goog.userAgent.WEBKIT && !offsetWidth && !offsetHeight; - if ((!goog.isDef(offsetWidth) || webkitOffsetsZero) && - element.getBoundingClientRect) { - // Fall back to calling getBoundingClientRect when offsetWidth or - // offsetHeight are not defined, or when they are zero in WebKit browsers. - // This makes sure that we return for the correct size for SVG elements, but - // will still return 0 on Webkit prior to 534.8, see - // http://trac.webkit.org/changeset/67252. - var clientRect = goog.style.getBoundingClientRect_(element); - return new goog.math.Size(clientRect.right - clientRect.left, - clientRect.bottom - clientRect.top); - } - return new goog.math.Size(offsetWidth, offsetHeight); -}; - - -/** - * Gets the height and width of an element, post transform, even if its display - * is none. - * - * This is like {@code goog.style.getSize}, except: - * <ol> - * <li>Takes webkitTransforms such as rotate and scale into account. - * <li>Will return null if {@code element} doesn't respond to - * {@code getBoundingClientRect}. - * <li>Currently doesn't make sense on non-WebKit browsers which don't support - * webkitTransforms. - * </ol> - * @param {!Element} element Element to get size of. - * @return {goog.math.Size} Object with width/height properties. - */ -goog.style.getTransformedSize = function(element) { - if (!element.getBoundingClientRect) { - return null; - } - - var clientRect = goog.style.evaluateWithTemporaryDisplay_( - goog.style.getBoundingClientRect_, element); - return new goog.math.Size(clientRect.right - clientRect.left, - clientRect.bottom - clientRect.top); -}; - - -/** - * Returns a bounding rectangle for a given element in page space. - * @param {Element} element Element to get bounds of. Must not be display none. - * @return {!goog.math.Rect} Bounding rectangle for the element. - */ -goog.style.getBounds = function(element) { - var o = goog.style.getPageOffset(element); - var s = goog.style.getSize(element); - return new goog.math.Rect(o.x, o.y, s.width, s.height); -}; - - -/** - * Converts a CSS selector in the form style-property to styleProperty. - * @param {*} selector CSS Selector. - * @return {string} Camel case selector. - * @deprecated Use goog.string.toCamelCase instead. - */ -goog.style.toCamelCase = function(selector) { - return goog.string.toCamelCase(String(selector)); -}; - - -/** - * Converts a CSS selector in the form styleProperty to style-property. - * @param {string} selector Camel case selector. - * @return {string} Selector cased. - * @deprecated Use goog.string.toSelectorCase instead. - */ -goog.style.toSelectorCase = function(selector) { - return goog.string.toSelectorCase(selector); -}; - - -/** - * Gets the opacity of a node (x-browser). This gets the inline style opacity - * of the node, and does not take into account the cascaded or the computed - * style for this node. - * @param {Element} el Element whose opacity has to be found. - * @return {number|string} Opacity between 0 and 1 or an empty string {@code ''} - * if the opacity is not set. - */ -goog.style.getOpacity = function(el) { - var style = el.style; - var result = ''; - if ('opacity' in style) { - result = style.opacity; - } else if ('MozOpacity' in style) { - result = style.MozOpacity; - } else if ('filter' in style) { - var match = style.filter.match(/alpha\(opacity=([\d.]+)\)/); - if (match) { - result = String(match[1] / 100); - } - } - return result == '' ? result : Number(result); -}; - - -/** - * Sets the opacity of a node (x-browser). - * @param {Element} el Elements whose opacity has to be set. - * @param {number|string} alpha Opacity between 0 and 1 or an empty string - * {@code ''} to clear the opacity. - */ -goog.style.setOpacity = function(el, alpha) { - var style = el.style; - if ('opacity' in style) { - style.opacity = alpha; - } else if ('MozOpacity' in style) { - style.MozOpacity = alpha; - } else if ('filter' in style) { - // TODO(arv): Overwriting the filter might have undesired side effects. - if (alpha === '') { - style.filter = ''; - } else { - style.filter = 'alpha(opacity=' + alpha * 100 + ')'; - } - } -}; - - -/** - * Sets the background of an element to a transparent image in a browser- - * independent manner. - * - * This function does not support repeating backgrounds or alternate background - * positions to match the behavior of Internet Explorer. It also does not - * support sizingMethods other than crop since they cannot be replicated in - * browsers other than Internet Explorer. - * - * @param {Element} el The element to set background on. - * @param {string} src The image source URL. - */ -goog.style.setTransparentBackgroundImage = function(el, src) { - var style = el.style; - // It is safe to use the style.filter in IE only. In Safari 'filter' is in - // style object but access to style.filter causes it to throw an exception. - // Note: IE8 supports images with an alpha channel. - if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { - // See TODO in setOpacity. - style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(' + - 'src="' + src + '", sizingMethod="crop")'; - } else { - // Set style properties individually instead of using background shorthand - // to prevent overwriting a pre-existing background color. - style.backgroundImage = 'url(' + src + ')'; - style.backgroundPosition = 'top left'; - style.backgroundRepeat = 'no-repeat'; - } -}; - - -/** - * Clears the background image of an element in a browser independent manner. - * @param {Element} el The element to clear background image for. - */ -goog.style.clearTransparentBackgroundImage = function(el) { - var style = el.style; - if ('filter' in style) { - // See TODO in setOpacity. - style.filter = ''; - } else { - // Set style properties individually instead of using background shorthand - // to prevent overwriting a pre-existing background color. - style.backgroundImage = 'none'; - } -}; - - -/** - * Shows or hides an element from the page. Hiding the element is done by - * setting the display property to "none", removing the element from the - * rendering hierarchy so it takes up no space. To show the element, the default - * inherited display property is restored (defined either in stylesheets or by - * the browser's default style rules.) - * - * Caveat 1: if the inherited display property for the element is set to "none" - * by the stylesheets, that is the property that will be restored by a call to - * showElement(), effectively toggling the display between "none" and "none". - * - * Caveat 2: if the element display style is set inline (by setting either - * element.style.display or a style attribute in the HTML), a call to - * showElement will clear that setting and defer to the inherited style in the - * stylesheet. - * @param {Element} el Element to show or hide. - * @param {*} display True to render the element in its default style, - * false to disable rendering the element. - * @deprecated Use goog.style.setElementShown instead. - */ -goog.style.showElement = function(el, display) { - goog.style.setElementShown(el, display); -}; - - -/** - * Shows or hides an element from the page. Hiding the element is done by - * setting the display property to "none", removing the element from the - * rendering hierarchy so it takes up no space. To show the element, the default - * inherited display property is restored (defined either in stylesheets or by - * the browser's default style rules). - * - * Caveat 1: if the inherited display property for the element is set to "none" - * by the stylesheets, that is the property that will be restored by a call to - * setElementShown(), effectively toggling the display between "none" and - * "none". - * - * Caveat 2: if the element display style is set inline (by setting either - * element.style.display or a style attribute in the HTML), a call to - * setElementShown will clear that setting and defer to the inherited style in - * the stylesheet. - * @param {Element} el Element to show or hide. - * @param {*} isShown True to render the element in its default style, - * false to disable rendering the element. - */ -goog.style.setElementShown = function(el, isShown) { - el.style.display = isShown ? '' : 'none'; -}; - - -/** - * Test whether the given element has been shown or hidden via a call to - * {@link #setElementShown}. - * - * Note this is strictly a companion method for a call - * to {@link #setElementShown} and the same caveats apply; in particular, this - * method does not guarantee that the return value will be consistent with - * whether or not the element is actually visible. - * - * @param {Element} el The element to test. - * @return {boolean} Whether the element has been shown. - * @see #setElementShown - */ -goog.style.isElementShown = function(el) { - return el.style.display != 'none'; -}; - - -/** - * Installs the styles string into the window that contains opt_element. If - * opt_element is null, the main window is used. - * @param {string} stylesString The style string to install. - * @param {Node=} opt_node Node whose parent document should have the - * styles installed. - * @return {Element|StyleSheet} The style element created. - */ -goog.style.installStyles = function(stylesString, opt_node) { - var dh = goog.dom.getDomHelper(opt_node); - var styleSheet = null; - - // IE < 11 requires createStyleSheet. Note that doc.createStyleSheet will be - // undefined as of IE 11. - var doc = dh.getDocument(); - if (goog.userAgent.IE && doc.createStyleSheet) { - styleSheet = doc.createStyleSheet(); - goog.style.setStyles(styleSheet, stylesString); - } else { - var head = dh.getElementsByTagNameAndClass(goog.dom.TagName.HEAD)[0]; - - // In opera documents are not guaranteed to have a head element, thus we - // have to make sure one exists before using it. - if (!head) { - var body = dh.getElementsByTagNameAndClass(goog.dom.TagName.BODY)[0]; - head = dh.createDom(goog.dom.TagName.HEAD); - body.parentNode.insertBefore(head, body); - } - styleSheet = dh.createDom(goog.dom.TagName.STYLE); - // NOTE(user): Setting styles after the style element has been appended - // to the head results in a nasty Webkit bug in certain scenarios. Please - // refer to https://bugs.webkit.org/show_bug.cgi?id=26307 for additional - // details. - goog.style.setStyles(styleSheet, stylesString); - dh.appendChild(head, styleSheet); - } - return styleSheet; -}; - - -/** - * Removes the styles added by {@link #installStyles}. - * @param {Element|StyleSheet} styleSheet The value returned by - * {@link #installStyles}. - */ -goog.style.uninstallStyles = function(styleSheet) { - var node = styleSheet.ownerNode || styleSheet.owningElement || - /** @type {Element} */ (styleSheet); - goog.dom.removeNode(node); -}; - - -/** - * Sets the content of a style element. The style element can be any valid - * style element. This element will have its content completely replaced by - * the new stylesString. - * @param {Element|StyleSheet} element A stylesheet element as returned by - * installStyles. - * @param {string} stylesString The new content of the stylesheet. - */ -goog.style.setStyles = function(element, stylesString) { - if (goog.userAgent.IE && goog.isDef(element.cssText)) { - // Adding the selectors individually caused the browser to hang if the - // selector was invalid or there were CSS comments. Setting the cssText of - // the style node works fine and ignores CSS that IE doesn't understand. - // However IE >= 11 doesn't support cssText any more, so we make sure that - // cssText is a defined property and otherwise fall back to innerHTML. - element.cssText = stylesString; - } else { - element.innerHTML = stylesString; - } -}; - - -/** - * Sets 'white-space: pre-wrap' for a node (x-browser). - * - * There are as many ways of specifying pre-wrap as there are browsers. - * - * CSS3/IE8: white-space: pre-wrap; - * Mozilla: white-space: -moz-pre-wrap; - * Opera: white-space: -o-pre-wrap; - * IE6/7: white-space: pre; word-wrap: break-word; - * - * @param {Element} el Element to enable pre-wrap for. - */ -goog.style.setPreWrap = function(el) { - var style = el.style; - if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { - style.whiteSpace = 'pre'; - style.wordWrap = 'break-word'; - } else if (goog.userAgent.GECKO) { - style.whiteSpace = '-moz-pre-wrap'; - } else { - style.whiteSpace = 'pre-wrap'; - } -}; - - -/** - * Sets 'display: inline-block' for an element (cross-browser). - * @param {Element} el Element to which the inline-block display style is to be - * applied. - * @see ../demos/inline_block_quirks.html - * @see ../demos/inline_block_standards.html - */ -goog.style.setInlineBlock = function(el) { - var style = el.style; - // Without position:relative, weirdness ensues. Just accept it and move on. - style.position = 'relative'; - - if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { - // IE8 supports inline-block so fall through to the else - // Zoom:1 forces hasLayout, display:inline gives inline behavior. - style.zoom = '1'; - style.display = 'inline'; - } else { - // Opera, Webkit, and Safari seem to do OK with the standard inline-block - // style. - style.display = 'inline-block'; - } -}; - - -/** - * Returns true if the element is using right to left (rtl) direction. - * @param {Element} el The element to test. - * @return {boolean} True for right to left, false for left to right. - */ -goog.style.isRightToLeft = function(el) { - return 'rtl' == goog.style.getStyle_(el, 'direction'); -}; - - -/** - * The CSS style property corresponding to an element being - * unselectable on the current browser platform (null if none). - * Opera and IE instead use a DOM attribute 'unselectable'. - * @type {?string} - * @private - */ -goog.style.unselectableStyle_ = - goog.userAgent.GECKO ? 'MozUserSelect' : - goog.userAgent.WEBKIT ? 'WebkitUserSelect' : - null; - - -/** - * Returns true if the element is set to be unselectable, false otherwise. - * Note that on some platforms (e.g. Mozilla), even if an element isn't set - * to be unselectable, it will behave as such if any of its ancestors is - * unselectable. - * @param {Element} el Element to check. - * @return {boolean} Whether the element is set to be unselectable. - */ -goog.style.isUnselectable = function(el) { - if (goog.style.unselectableStyle_) { - return el.style[goog.style.unselectableStyle_].toLowerCase() == 'none'; - } else if (goog.userAgent.IE || goog.userAgent.OPERA) { - return el.getAttribute('unselectable') == 'on'; - } - return false; -}; - - -/** - * Makes the element and its descendants selectable or unselectable. Note - * that on some platforms (e.g. Mozilla), even if an element isn't set to - * be unselectable, it will behave as such if any of its ancestors is - * unselectable. - * @param {Element} el The element to alter. - * @param {boolean} unselectable Whether the element and its descendants - * should be made unselectable. - * @param {boolean=} opt_noRecurse Whether to only alter the element's own - * selectable state, and leave its descendants alone; defaults to false. - */ -goog.style.setUnselectable = function(el, unselectable, opt_noRecurse) { - // TODO(attila): Do we need all of TR_DomUtil.makeUnselectable() in Closure? - var descendants = !opt_noRecurse ? el.getElementsByTagName('*') : null; - var name = goog.style.unselectableStyle_; - if (name) { - // Add/remove the appropriate CSS style to/from the element and its - // descendants. - var value = unselectable ? 'none' : ''; - // MathML elements do not have a style property. Verify before setting. - if (el.style) { - el.style[name] = value; - } - if (descendants) { - for (var i = 0, descendant; descendant = descendants[i]; i++) { - if (descendant.style) { - descendant.style[name] = value; - } - } - } - } else if (goog.userAgent.IE || goog.userAgent.OPERA) { - // Toggle the 'unselectable' attribute on the element and its descendants. - var value = unselectable ? 'on' : ''; - el.setAttribute('unselectable', value); - if (descendants) { - for (var i = 0, descendant; descendant = descendants[i]; i++) { - descendant.setAttribute('unselectable', value); - } - } - } -}; - - -/** - * Gets the border box size for an element. - * @param {Element} element The element to get the size for. - * @return {!goog.math.Size} The border box size. - */ -goog.style.getBorderBoxSize = function(element) { - return new goog.math.Size( - /** @type {!HTMLElement} */ (element).offsetWidth, - /** @type {!HTMLElement} */ (element).offsetHeight); -}; - - -/** - * Sets the border box size of an element. This is potentially expensive in IE - * if the document is CSS1Compat mode - * @param {Element} element The element to set the size on. - * @param {goog.math.Size} size The new size. - */ -goog.style.setBorderBoxSize = function(element, size) { - var doc = goog.dom.getOwnerDocument(element); - var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode(); - - if (goog.userAgent.IE && - !goog.userAgent.isVersionOrHigher('10') && - (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) { - var style = element.style; - if (isCss1CompatMode) { - var paddingBox = goog.style.getPaddingBox(element); - var borderBox = goog.style.getBorderBox(element); - style.pixelWidth = size.width - borderBox.left - paddingBox.left - - paddingBox.right - borderBox.right; - style.pixelHeight = size.height - borderBox.top - paddingBox.top - - paddingBox.bottom - borderBox.bottom; - } else { - style.pixelWidth = size.width; - style.pixelHeight = size.height; - } - } else { - goog.style.setBoxSizingSize_(element, size, 'border-box'); - } -}; - - -/** - * Gets the content box size for an element. This is potentially expensive in - * all browsers. - * @param {Element} element The element to get the size for. - * @return {!goog.math.Size} The content box size. - */ -goog.style.getContentBoxSize = function(element) { - var doc = goog.dom.getOwnerDocument(element); - var ieCurrentStyle = goog.userAgent.IE && element.currentStyle; - if (ieCurrentStyle && - goog.dom.getDomHelper(doc).isCss1CompatMode() && - ieCurrentStyle.width != 'auto' && ieCurrentStyle.height != 'auto' && - !ieCurrentStyle.boxSizing) { - // If IE in CSS1Compat mode than just use the width and height. - // If we have a boxSizing then fall back on measuring the borders etc. - var width = goog.style.getIePixelValue_(element, ieCurrentStyle.width, - 'width', 'pixelWidth'); - var height = goog.style.getIePixelValue_(element, ieCurrentStyle.height, - 'height', 'pixelHeight'); - return new goog.math.Size(width, height); - } else { - var borderBoxSize = goog.style.getBorderBoxSize(element); - var paddingBox = goog.style.getPaddingBox(element); - var borderBox = goog.style.getBorderBox(element); - return new goog.math.Size(borderBoxSize.width - - borderBox.left - paddingBox.left - - paddingBox.right - borderBox.right, - borderBoxSize.height - - borderBox.top - paddingBox.top - - paddingBox.bottom - borderBox.bottom); - } -}; - - -/** - * Sets the content box size of an element. This is potentially expensive in IE - * if the document is BackCompat mode. - * @param {Element} element The element to set the size on. - * @param {goog.math.Size} size The new size. - */ -goog.style.setContentBoxSize = function(element, size) { - var doc = goog.dom.getOwnerDocument(element); - var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode(); - if (goog.userAgent.IE && - !goog.userAgent.isVersionOrHigher('10') && - (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) { - var style = element.style; - if (isCss1CompatMode) { - style.pixelWidth = size.width; - style.pixelHeight = size.height; - } else { - var paddingBox = goog.style.getPaddingBox(element); - var borderBox = goog.style.getBorderBox(element); - style.pixelWidth = size.width + borderBox.left + paddingBox.left + - paddingBox.right + borderBox.right; - style.pixelHeight = size.height + borderBox.top + paddingBox.top + - paddingBox.bottom + borderBox.bottom; - } - } else { - goog.style.setBoxSizingSize_(element, size, 'content-box'); - } -}; - - -/** - * Helper function that sets the box sizing as well as the width and height - * @param {Element} element The element to set the size on. - * @param {goog.math.Size} size The new size to set. - * @param {string} boxSizing The box-sizing value. - * @private - */ -goog.style.setBoxSizingSize_ = function(element, size, boxSizing) { - var style = element.style; - if (goog.userAgent.GECKO) { - style.MozBoxSizing = boxSizing; - } else if (goog.userAgent.WEBKIT) { - style.WebkitBoxSizing = boxSizing; - } else { - // Includes IE8 and Opera 9.50+ - style.boxSizing = boxSizing; - } - - // Setting this to a negative value will throw an exception on IE - // (and doesn't do anything different than setting it to 0). - style.width = Math.max(size.width, 0) + 'px'; - style.height = Math.max(size.height, 0) + 'px'; -}; - - -/** - * IE specific function that converts a non pixel unit to pixels. - * @param {Element} element The element to convert the value for. - * @param {string} value The current value as a string. The value must not be - * ''. - * @param {string} name The CSS property name to use for the converstion. This - * should be 'left', 'top', 'width' or 'height'. - * @param {string} pixelName The CSS pixel property name to use to get the - * value in pixels. - * @return {number} The value in pixels. - * @private - */ -goog.style.getIePixelValue_ = function(element, value, name, pixelName) { - // Try if we already have a pixel value. IE does not do half pixels so we - // only check if it matches a number followed by 'px'. - if (/^\d+px?$/.test(value)) { - return parseInt(value, 10); - } else { - var oldStyleValue = element.style[name]; - var oldRuntimeValue = element.runtimeStyle[name]; - // set runtime style to prevent changes - element.runtimeStyle[name] = element.currentStyle[name]; - element.style[name] = value; - var pixelValue = element.style[pixelName]; - // restore - element.style[name] = oldStyleValue; - element.runtimeStyle[name] = oldRuntimeValue; - return pixelValue; - } -}; - - -/** - * Helper function for getting the pixel padding or margin for IE. - * @param {Element} element The element to get the padding for. - * @param {string} propName The property name. - * @return {number} The pixel padding. - * @private - */ -goog.style.getIePixelDistance_ = function(element, propName) { - var value = goog.style.getCascadedStyle(element, propName); - return value ? - goog.style.getIePixelValue_(element, value, 'left', 'pixelLeft') : 0; -}; - - -/** - * Gets the computed paddings or margins (on all sides) in pixels. - * @param {Element} element The element to get the padding for. - * @param {string} stylePrefix Pass 'padding' to retrieve the padding box, - * or 'margin' to retrieve the margin box. - * @return {!goog.math.Box} The computed paddings or margins. - * @private - */ -goog.style.getBox_ = function(element, stylePrefix) { - if (goog.userAgent.IE) { - var left = goog.style.getIePixelDistance_(element, stylePrefix + 'Left'); - var right = goog.style.getIePixelDistance_(element, stylePrefix + 'Right'); - var top = goog.style.getIePixelDistance_(element, stylePrefix + 'Top'); - var bottom = goog.style.getIePixelDistance_( - element, stylePrefix + 'Bottom'); - return new goog.math.Box(top, right, bottom, left); - } else { - // On non-IE browsers, getComputedStyle is always non-null. - var left = goog.style.getComputedStyle(element, stylePrefix + 'Left'); - var right = goog.style.getComputedStyle(element, stylePrefix + 'Right'); - var top = goog.style.getComputedStyle(element, stylePrefix + 'Top'); - var bottom = goog.style.getComputedStyle(element, stylePrefix + 'Bottom'); - - // NOTE(arv): Gecko can return floating point numbers for the computed - // style values. - return new goog.math.Box(parseFloat(top), - parseFloat(right), - parseFloat(bottom), - parseFloat(left)); - } -}; - - -/** - * Gets the computed paddings (on all sides) in pixels. - * @param {Element} element The element to get the padding for. - * @return {!goog.math.Box} The computed paddings. - */ -goog.style.getPaddingBox = function(element) { - return goog.style.getBox_(element, 'padding'); -}; - - -/** - * Gets the computed margins (on all sides) in pixels. - * @param {Element} element The element to get the margins for. - * @return {!goog.math.Box} The computed margins. - */ -goog.style.getMarginBox = function(element) { - return goog.style.getBox_(element, 'margin'); -}; - - -/** - * A map used to map the border width keywords to a pixel width. - * @type {Object} - * @private - */ -goog.style.ieBorderWidthKeywords_ = { - 'thin': 2, - 'medium': 4, - 'thick': 6 -}; - - -/** - * Helper function for IE to get the pixel border. - * @param {Element} element The element to get the pixel border for. - * @param {string} prop The part of the property name. - * @return {number} The value in pixels. - * @private - */ -goog.style.getIePixelBorder_ = function(element, prop) { - if (goog.style.getCascadedStyle(element, prop + 'Style') == 'none') { - return 0; - } - var width = goog.style.getCascadedStyle(element, prop + 'Width'); - if (width in goog.style.ieBorderWidthKeywords_) { - return goog.style.ieBorderWidthKeywords_[width]; - } - return goog.style.getIePixelValue_(element, width, 'left', 'pixelLeft'); -}; - - -/** - * Gets the computed border widths (on all sides) in pixels - * @param {Element} element The element to get the border widths for. - * @return {!goog.math.Box} The computed border widths. - */ -goog.style.getBorderBox = function(element) { - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { - var left = goog.style.getIePixelBorder_(element, 'borderLeft'); - var right = goog.style.getIePixelBorder_(element, 'borderRight'); - var top = goog.style.getIePixelBorder_(element, 'borderTop'); - var bottom = goog.style.getIePixelBorder_(element, 'borderBottom'); - return new goog.math.Box(top, right, bottom, left); - } else { - // On non-IE browsers, getComputedStyle is always non-null. - var left = goog.style.getComputedStyle(element, 'borderLeftWidth'); - var right = goog.style.getComputedStyle(element, 'borderRightWidth'); - var top = goog.style.getComputedStyle(element, 'borderTopWidth'); - var bottom = goog.style.getComputedStyle(element, 'borderBottomWidth'); - - return new goog.math.Box(parseFloat(top), - parseFloat(right), - parseFloat(bottom), - parseFloat(left)); - } -}; - - -/** - * Returns the font face applied to a given node. Opera and IE should return - * the font actually displayed. Firefox returns the author's most-preferred - * font (whether the browser is capable of displaying it or not.) - * @param {Element} el The element whose font family is returned. - * @return {string} The font family applied to el. - */ -goog.style.getFontFamily = function(el) { - var doc = goog.dom.getOwnerDocument(el); - var font = ''; - // The moveToElementText method from the TextRange only works if the element - // is attached to the owner document. - if (doc.body.createTextRange && goog.dom.contains(doc, el)) { - var range = doc.body.createTextRange(); - range.moveToElementText(el); - /** @preserveTry */ - try { - font = range.queryCommandValue('FontName'); - } catch (e) { - // This is a workaround for a awkward exception. - // On some IE, there is an exception coming from it. - // The error description from this exception is: - // This window has already been registered as a drop target - // This is bogus description, likely due to a bug in ie. - font = ''; - } - } - if (!font) { - // Note if for some reason IE can't derive FontName with a TextRange, we - // fallback to using currentStyle - font = goog.style.getStyle_(el, 'fontFamily'); - } - - // Firefox returns the applied font-family string (author's list of - // preferred fonts.) We want to return the most-preferred font, in lieu of - // the *actually* applied font. - var fontsArray = font.split(','); - if (fontsArray.length > 1) font = fontsArray[0]; - - // Sanitize for x-browser consistency: - // Strip quotes because browsers aren't consistent with how they're - // applied; Opera always encloses, Firefox sometimes, and IE never. - return goog.string.stripQuotes(font, '"\''); -}; - - -/** - * Regular expression used for getLengthUnits. - * @type {RegExp} - * @private - */ -goog.style.lengthUnitRegex_ = /[^\d]+$/; - - -/** - * Returns the units used for a CSS length measurement. - * @param {string} value A CSS length quantity. - * @return {?string} The units of measurement. - */ -goog.style.getLengthUnits = function(value) { - var units = value.match(goog.style.lengthUnitRegex_); - return units && units[0] || null; -}; - - -/** - * Map of absolute CSS length units - * @type {Object} - * @private - */ -goog.style.ABSOLUTE_CSS_LENGTH_UNITS_ = { - 'cm' : 1, - 'in' : 1, - 'mm' : 1, - 'pc' : 1, - 'pt' : 1 -}; - - -/** - * Map of relative CSS length units that can be accurately converted to px - * font-size values using getIePixelValue_. Only units that are defined in - * relation to a font size are convertible (%, small, etc. are not). - * @type {Object} - * @private - */ -goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_ = { - 'em' : 1, - 'ex' : 1 -}; - - -/** - * Returns the font size, in pixels, of text in an element. - * @param {Element} el The element whose font size is returned. - * @return {number} The font size (in pixels). - */ -goog.style.getFontSize = function(el) { - var fontSize = goog.style.getStyle_(el, 'fontSize'); - var sizeUnits = goog.style.getLengthUnits(fontSize); - if (fontSize && 'px' == sizeUnits) { - // NOTE(user): This could be parseFloat instead, but IE doesn't return - // decimal fractions in getStyle_ and Firefox reports the fractions, but - // ignores them when rendering. Interestingly enough, when we force the - // issue and size something to e.g., 50% of 25px, the browsers round in - // opposite directions with Firefox reporting 12px and IE 13px. I punt. - return parseInt(fontSize, 10); - } - - // In IE, we can convert absolute length units to a px value using - // goog.style.getIePixelValue_. Units defined in relation to a font size - // (em, ex) are applied relative to the element's parentNode and can also - // be converted. - if (goog.userAgent.IE) { - if (sizeUnits in goog.style.ABSOLUTE_CSS_LENGTH_UNITS_) { - return goog.style.getIePixelValue_(el, - fontSize, - 'left', - 'pixelLeft'); - } else if (el.parentNode && - el.parentNode.nodeType == goog.dom.NodeType.ELEMENT && - sizeUnits in goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_) { - // Check the parent size - if it is the same it means the relative size - // value is inherited and we therefore don't want to count it twice. If - // it is different, this element either has explicit style or has a CSS - // rule applying to it. - var parentElement = /** @type {!Element} */ (el.parentNode); - var parentSize = goog.style.getStyle_(parentElement, 'fontSize'); - return goog.style.getIePixelValue_(parentElement, - fontSize == parentSize ? - '1em' : fontSize, - 'left', - 'pixelLeft'); - } - } - - // Sometimes we can't cleanly find the font size (some units relative to a - // node's parent's font size are difficult: %, smaller et al), so we create - // an invisible, absolutely-positioned span sized to be the height of an 'M' - // rendered in its parent's (i.e., our target element's) font size. This is - // the definition of CSS's font size attribute. - var sizeElement = goog.dom.createDom( - goog.dom.TagName.SPAN, - {'style': 'visibility:hidden;position:absolute;' + - 'line-height:0;padding:0;margin:0;border:0;height:1em;'}); - goog.dom.appendChild(el, sizeElement); - fontSize = sizeElement.offsetHeight; - goog.dom.removeNode(sizeElement); - - return fontSize; -}; - - -/** - * Parses a style attribute value. Converts CSS property names to camel case. - * @param {string} value The style attribute value. - * @return {!Object} Map of CSS properties to string values. - */ -goog.style.parseStyleAttribute = function(value) { - var result = {}; - goog.array.forEach(value.split(/\s*;\s*/), function(pair) { - var keyValue = pair.match(/\s*([\w-]+)\s*\:(.+)/); - if (keyValue) { - var styleName = keyValue[1]; - var styleValue = goog.string.trim(keyValue[2]); - result[goog.string.toCamelCase(styleName.toLowerCase())] = styleValue; - } - }); - return result; -}; - - -/** - * Reverse of parseStyleAttribute; that is, takes a style object and returns the - * corresponding attribute value. Converts camel case property names to proper - * CSS selector names. - * @param {Object} obj Map of CSS properties to values. - * @return {string} The style attribute value. - */ -goog.style.toStyleAttribute = function(obj) { - var buffer = []; - goog.object.forEach(obj, function(value, key) { - buffer.push(goog.string.toSelectorCase(key), ':', value, ';'); - }); - return buffer.join(''); -}; - - -/** - * Sets CSS float property on an element. - * @param {Element} el The element to set float property on. - * @param {string} value The value of float CSS property to set on this element. - */ -goog.style.setFloat = function(el, value) { - el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] = value; -}; - - -/** - * Gets value of explicitly-set float CSS property on an element. - * @param {Element} el The element to get float property of. - * @return {string} The value of explicitly-set float CSS property on this - * element. - */ -goog.style.getFloat = function(el) { - return el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] || ''; -}; - - -/** - * Returns the scroll bar width (represents the width of both horizontal - * and vertical scroll). - * - * @param {string=} opt_className An optional class name (or names) to apply - * to the invisible div created to measure the scrollbar. This is necessary - * if some scrollbars are styled differently than others. - * @return {number} The scroll bar width in px. - */ -goog.style.getScrollbarWidth = function(opt_className) { - // Add two hidden divs. The child div is larger than the parent and - // forces scrollbars to appear on it. - // Using overflow:scroll does not work consistently with scrollbars that - // are styled with ::-webkit-scrollbar. - var outerDiv = goog.dom.createElement(goog.dom.TagName.DIV); - if (opt_className) { - outerDiv.className = opt_className; - } - outerDiv.style.cssText = 'overflow:auto;' + - 'position:absolute;top:0;width:100px;height:100px'; - var innerDiv = goog.dom.createElement(goog.dom.TagName.DIV); - goog.style.setSize(innerDiv, '200px', '200px'); - outerDiv.appendChild(innerDiv); - goog.dom.appendChild(goog.dom.getDocument().body, outerDiv); - var width = outerDiv.offsetWidth - outerDiv.clientWidth; - goog.dom.removeNode(outerDiv); - return width; -}; - - -/** - * Regular expression to extract x and y translation components from a CSS - * transform Matrix representation. - * - * @type {!RegExp} - * @const - * @private - */ -goog.style.MATRIX_TRANSLATION_REGEX_ = - new RegExp('matrix\\([0-9\\.\\-]+, [0-9\\.\\-]+, ' + - '[0-9\\.\\-]+, [0-9\\.\\-]+, ' + - '([0-9\\.\\-]+)p?x?, ([0-9\\.\\-]+)p?x?\\)'); - - -/** - * Returns the x,y translation component of any CSS transforms applied to the - * element, in pixels. - * - * @param {!Element} element The element to get the translation of. - * @return {!goog.math.Coordinate} The CSS translation of the element in px. - */ -goog.style.getCssTranslation = function(element) { - var transform = goog.style.getComputedTransform(element); - if (!transform) { - return new goog.math.Coordinate(0, 0); - } - var matches = transform.match(goog.style.MATRIX_TRANSLATION_REGEX_); - if (!matches) { - return new goog.math.Coordinate(0, 0); - } - return new goog.math.Coordinate(parseFloat(matches[1]), - parseFloat(matches[2])); -}; - -goog.provide('ol.MapEvent'); -goog.provide('ol.MapEventType'); - -goog.require('goog.events.Event'); - - -/** - * @enum {string} - */ -ol.MapEventType = { - - /** - * Triggered after a map frame is rendered. - * @event ol.MapEvent#postrender - * @api - */ - POSTRENDER: 'postrender', - - /** - * Triggered after the map is moved. - * @event ol.MapEvent#moveend - * @api stable - */ - MOVEEND: 'moveend' - -}; - - - -/** - * @classdesc - * Events emitted as map events are instances of this type. - * See {@link ol.Map} for which events trigger a map event. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.MapEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {?olx.FrameState=} opt_frameState Frame state. - */ -ol.MapEvent = function(type, map, opt_frameState) { - - goog.base(this, type); - - /** - * The map where the event occurred. - * @type {ol.Map} - * @api stable - */ - this.map = map; - - /** - * The frame state at the time of the event. - * @type {?olx.FrameState} - * @api - */ - this.frameState = opt_frameState !== undefined ? opt_frameState : null; - -}; -goog.inherits(ol.MapEvent, goog.events.Event); - -goog.provide('ol.control.Control'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('ol'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); - - - -/** - * @classdesc - * A control is a visible widget with a DOM element in a fixed position on the - * screen. They can involve user input (buttons), or be informational only; - * the position is determined using CSS. By default these are placed in the - * container with CSS class name `ol-overlaycontainer-stopevent`, but can use - * any outside DOM element. - * - * This is the base class for controls. You can use it for simple custom - * controls by creating the element with listeners, creating an instance: - * ```js - * var myControl = new ol.control.Control({element: myElement}); - * ``` - * and then adding this to the map. - * - * The main advantage of having this as a control rather than a simple separate - * DOM element is that preventing propagation is handled for you. Controls - * will also be `ol.Object`s in a `ol.Collection`, so you can use their - * methods. - * - * You can also extend this base for your own control class. See - * examples/custom-controls for an example of how to do this. - * - * @constructor - * @extends {ol.Object} - * @implements {oli.control.Control} - * @param {olx.control.ControlOptions} options Control options. - * @api stable - */ -ol.control.Control = function(options) { - - goog.base(this); - - /** - * @protected - * @type {Element} - */ - this.element = options.element ? options.element : null; - - /** - * @private - * @type {Element} - */ - this.target_ = null; - - /** - * @private - * @type {ol.Map} - */ - this.map_ = null; - - /** - * @protected - * @type {!Array.<?number>} - */ - this.listenerKeys = []; - - /** - * @type {function(ol.MapEvent)} - */ - this.render = options.render ? options.render : ol.nullFunction; - - if (options.target) { - this.setTarget(options.target); - } - -}; -goog.inherits(ol.control.Control, ol.Object); - - -/** - * @inheritDoc - */ -ol.control.Control.prototype.disposeInternal = function() { - goog.dom.removeNode(this.element); - goog.base(this, 'disposeInternal'); -}; - - -/** - * Get the map associated with this control. - * @return {ol.Map} Map. - * @api stable - */ -ol.control.Control.prototype.getMap = function() { - return this.map_; -}; - - -/** - * Remove the control from its current map and attach it to the new map. - * Subclasses may set up event handlers to get notified about changes to - * the map here. - * @param {ol.Map} map Map. - * @api stable - */ -ol.control.Control.prototype.setMap = function(map) { - if (this.map_) { - goog.dom.removeNode(this.element); - } - if (this.listenerKeys.length > 0) { - this.listenerKeys.forEach(goog.events.unlistenByKey); - this.listenerKeys.length = 0; - } - this.map_ = map; - if (this.map_) { - var target = this.target_ ? - this.target_ : map.getOverlayContainerStopEvent(); - target.appendChild(this.element); - if (this.render !== ol.nullFunction) { - this.listenerKeys.push(goog.events.listen(map, - ol.MapEventType.POSTRENDER, this.render, false, this)); - } - map.render(); - } -}; - - -/** - * This function is used to set a target element for the control. It has no - * effect if it is called after the control has been added to the map (i.e. - * after `setMap` is called on the control). If no `target` is set in the - * options passed to the control constructor and if `setTarget` is not called - * then the control is added to the map's overlay container. - * @param {Element|string} target Target. - * @api - */ -ol.control.Control.prototype.setTarget = function(target) { - this.target_ = goog.dom.getElement(target); -}; - -goog.provide('ol.css'); - - -/** - * The CSS class for hidden feature. - * - * @const - * @type {string} - */ -ol.css.CLASS_HIDDEN = 'ol-hidden'; - - -/** - * The CSS class that we'll give the DOM elements to have them unselectable. - * - * @const - * @type {string} - */ -ol.css.CLASS_UNSELECTABLE = 'ol-unselectable'; - - -/** - * The CSS class for unsupported feature. - * - * @const - * @type {string} - */ -ol.css.CLASS_UNSUPPORTED = 'ol-unsupported'; - - -/** - * The CSS class for controls. - * - * @const - * @type {string} - */ -ol.css.CLASS_CONTROL = 'ol-control'; - -goog.provide('ol.structs.LRUCache'); - -goog.require('goog.asserts'); -goog.require('goog.object'); - - - -/** - * Implements a Least-Recently-Used cache where the keys do not conflict with - * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring - * items from the cache is the responsibility of the user. - * @constructor - * @struct - * @template T - */ -ol.structs.LRUCache = function() { - - /** - * @private - * @type {number} - */ - this.count_ = 0; - - /** - * @private - * @type {Object.<string, ol.structs.LRUCacheEntry>} - */ - this.entries_ = {}; - - /** - * @private - * @type {?ol.structs.LRUCacheEntry} - */ - this.oldest_ = null; - - /** - * @private - * @type {?ol.structs.LRUCacheEntry} - */ - this.newest_ = null; - -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.structs.LRUCache.prototype.assertValid = function() { - if (this.count_ === 0) { - goog.asserts.assert(goog.object.isEmpty(this.entries_), - 'entries must be an empty object (count = 0)'); - goog.asserts.assert(!this.oldest_, - 'oldest must be null (count = 0)'); - goog.asserts.assert(!this.newest_, - 'newest must be null (count = 0)'); - } else { - goog.asserts.assert(goog.object.getCount(this.entries_) == this.count_, - 'number of entries matches count'); - goog.asserts.assert(this.oldest_, - 'we have an oldest entry'); - goog.asserts.assert(!this.oldest_.older, - 'no entry is older than oldest'); - goog.asserts.assert(this.newest_, - 'we have a newest entry'); - goog.asserts.assert(!this.newest_.newer, - 'no entry is newer than newest'); - var i, entry; - var older = null; - i = 0; - for (entry = this.oldest_; entry; entry = entry.newer) { - goog.asserts.assert(entry.older === older, - 'entry.older links to correct older'); - older = entry; - ++i; - } - goog.asserts.assert(i == this.count_, 'iterated correct amount of times'); - var newer = null; - i = 0; - for (entry = this.newest_; entry; entry = entry.older) { - goog.asserts.assert(entry.newer === newer, - 'entry.newer links to correct newer'); - newer = entry; - ++i; - } - goog.asserts.assert(i == this.count_, 'iterated correct amount of times'); - } -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.structs.LRUCache.prototype.clear = function() { - this.count_ = 0; - this.entries_ = {}; - this.oldest_ = null; - this.newest_ = null; -}; - - -/** - * @param {string} key Key. - * @return {boolean} Contains key. - */ -ol.structs.LRUCache.prototype.containsKey = function(key) { - return this.entries_.hasOwnProperty(key); -}; - - -/** - * @param {function(this: S, T, string, ol.structs.LRUCache): ?} f The function - * to call for every entry from the oldest to the newer. This function takes - * 3 arguments (the entry value, the entry key and the LRUCache object). - * The return value is ignored. - * @param {S=} opt_this The object to use as `this` in `f`. - * @template S - */ -ol.structs.LRUCache.prototype.forEach = function(f, opt_this) { - var entry = this.oldest_; - while (entry) { - f.call(opt_this, entry.value_, entry.key_, this); - entry = entry.newer; - } -}; - - -/** - * @param {string} key Key. - * @return {T} Value. - */ -ol.structs.LRUCache.prototype.get = function(key) { - var entry = this.entries_[key]; - goog.asserts.assert(entry !== undefined, 'an entry exists for key %s', key); - if (entry === this.newest_) { - return entry.value_; - } else if (entry === this.oldest_) { - this.oldest_ = this.oldest_.newer; - this.oldest_.older = null; - } else { - entry.newer.older = entry.older; - entry.older.newer = entry.newer; - } - entry.newer = null; - entry.older = this.newest_; - this.newest_.newer = entry; - this.newest_ = entry; - return entry.value_; -}; - - -/** - * @return {number} Count. - */ -ol.structs.LRUCache.prototype.getCount = function() { - return this.count_; -}; - - -/** - * @return {Array.<string>} Keys. - */ -ol.structs.LRUCache.prototype.getKeys = function() { - var keys = new Array(this.count_); - var i = 0; - var entry; - for (entry = this.newest_; entry; entry = entry.older) { - keys[i++] = entry.key_; - } - goog.asserts.assert(i == this.count_, 'iterated correct number of times'); - return keys; -}; - - -/** - * @return {Array.<T>} Values. - */ -ol.structs.LRUCache.prototype.getValues = function() { - var values = new Array(this.count_); - var i = 0; - var entry; - for (entry = this.newest_; entry; entry = entry.older) { - values[i++] = entry.value_; - } - goog.asserts.assert(i == this.count_, 'iterated correct number of times'); - return values; -}; - - -/** - * @return {T} Last value. - */ -ol.structs.LRUCache.prototype.peekLast = function() { - goog.asserts.assert(this.oldest_, 'oldest must not be null'); - return this.oldest_.value_; -}; - - -/** - * @return {string} Last key. - */ -ol.structs.LRUCache.prototype.peekLastKey = function() { - goog.asserts.assert(this.oldest_, 'oldest must not be null'); - return this.oldest_.key_; -}; - - -/** - * @return {T} value Value. - */ -ol.structs.LRUCache.prototype.pop = function() { - goog.asserts.assert(this.oldest_, 'oldest must not be null'); - goog.asserts.assert(this.newest_, 'newest must not be null'); - var entry = this.oldest_; - goog.asserts.assert(entry.key_ in this.entries_, - 'oldest is indexed in entries'); - delete this.entries_[entry.key_]; - if (entry.newer) { - entry.newer.older = null; - } - this.oldest_ = entry.newer; - if (!this.oldest_) { - this.newest_ = null; - } - --this.count_; - return entry.value_; -}; - - -/** - * @param {string} key Key. - * @param {T} value Value. - */ -ol.structs.LRUCache.prototype.replace = function(key, value) { - this.get(key); // update `newest_` - this.entries_[key].value_ = value; -}; - - -/** - * @param {string} key Key. - * @param {T} value Value. - */ -ol.structs.LRUCache.prototype.set = function(key, value) { - goog.asserts.assert(!(key in {}), - 'key is not a standard property of objects (e.g. "__proto__")'); - goog.asserts.assert(!(key in this.entries_), - 'key is not used already'); - var entry = { - key_: key, - newer: null, - older: this.newest_, - value_: value - }; - if (!this.newest_) { - this.oldest_ = entry; - } else { - this.newest_.newer = entry; - } - this.newest_ = entry; - this.entries_[key] = entry; - ++this.count_; -}; - - -/** - * @typedef {{key_: string, - * newer: ol.structs.LRUCacheEntry, - * older: ol.structs.LRUCacheEntry, - * value_: *}} - */ -ol.structs.LRUCacheEntry; - -goog.provide('ol.TileCache'); - -goog.require('ol'); -goog.require('ol.TileRange'); -goog.require('ol.structs.LRUCache'); -goog.require('ol.tilecoord'); - - - -/** - * @constructor - * @extends {ol.structs.LRUCache.<ol.Tile>} - * @param {number=} opt_highWaterMark High water mark. - * @struct - */ -ol.TileCache = function(opt_highWaterMark) { - - goog.base(this); - - /** - * @private - * @type {number} - */ - this.highWaterMark_ = opt_highWaterMark !== undefined ? - opt_highWaterMark : ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK; - -}; -goog.inherits(ol.TileCache, ol.structs.LRUCache); - - -/** - * @return {boolean} Can expire cache. - */ -ol.TileCache.prototype.canExpireCache = function() { - return this.getCount() > this.highWaterMark_; -}; - - -/** - * @param {Object.<string, ol.TileRange>} usedTiles Used tiles. - */ -ol.TileCache.prototype.expireCache = function(usedTiles) { - var tile, zKey; - while (this.canExpireCache()) { - tile = this.peekLast(); - zKey = tile.tileCoord[0].toString(); - if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) { - break; - } else { - this.pop().dispose(); - } - } -}; - - -/** - * Remove a tile range from the cache, e.g. to invalidate tiles. - * @param {ol.TileRange} tileRange The tile range to prune. - */ -ol.TileCache.prototype.pruneTileRange = function(tileRange) { - var i = this.getCount(), - key; - while (i--) { - key = this.peekLastKey(); - if (tileRange.contains(ol.tilecoord.createFromString(key))) { - this.pop().dispose(); - } else { - this.get(key); - } - } -}; - -goog.provide('ol.Tile'); -goog.provide('ol.TileState'); - -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('ol.TileCoord'); - - -/** - * @enum {number} - */ -ol.TileState = { - IDLE: 0, - LOADING: 1, - LOADED: 2, - ERROR: 3, - EMPTY: 4 -}; - - - -/** - * @classdesc - * Base class for tiles. - * - * @constructor - * @extends {goog.events.EventTarget} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - */ -ol.Tile = function(tileCoord, state) { - - goog.base(this); - - /** - * @type {ol.TileCoord} - */ - this.tileCoord = tileCoord; - - /** - * @protected - * @type {ol.TileState} - */ - this.state = state; - - /** - * An "interim" tile for this tile. The interim tile may be used while this - * one is loading, for "smooth" transitions when changing params/dimensions - * on the source. - * @type {ol.Tile} - */ - this.interimTile = null; - - /** - * A key assigned to the tile. This is used by the tile source to determine - * if this tile can effectively be used, or if a new tile should be created - * and this one be used as an interim tile for this new tile. - * @type {string} - */ - this.key = ''; - -}; -goog.inherits(ol.Tile, goog.events.EventTarget); - - -/** - * @protected - */ -ol.Tile.prototype.changed = function() { - this.dispatchEvent(goog.events.EventType.CHANGE); -}; - - -/** - * Get the HTML image element for this tile (may be a Canvas, Image, or Video). - * @function - * @param {Object=} opt_context Object. - * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image. - */ -ol.Tile.prototype.getImage = goog.abstractMethod; - - -/** - * @return {string} Key. - */ -ol.Tile.prototype.getKey = function() { - return goog.getUid(this).toString(); -}; - - -/** - * Get the tile coordinate for this tile. - * @return {ol.TileCoord} - * @api - */ -ol.Tile.prototype.getTileCoord = function() { - return this.tileCoord; -}; - - -/** - * @return {ol.TileState} State. - */ -ol.Tile.prototype.getState = function() { - return this.state; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.Tile.prototype.load = goog.abstractMethod; - -goog.provide('ol.source.Source'); -goog.provide('ol.source.State'); - -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.Object'); -goog.require('ol.proj'); - - -/** - * State of the source, one of 'undefined', 'loading', 'ready' or 'error'. - * @enum {string} - * @api - */ -ol.source.State = { - UNDEFINED: 'undefined', - LOADING: 'loading', - READY: 'ready', - ERROR: 'error' -}; - - -/** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * logo: (string|olx.LogoOptions|undefined), - * projection: ol.proj.ProjectionLike, - * state: (ol.source.State|undefined), - * wrapX: (boolean|undefined)}} - */ -ol.source.SourceOptions; - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for {@link ol.layer.Layer} sources. - * - * A generic `change` event is triggered when the state of the source changes. - * - * @constructor - * @extends {ol.Object} - * @param {ol.source.SourceOptions} options Source options. - * @api stable - */ -ol.source.Source = function(options) { - - goog.base(this); - - /** - * @private - * @type {ol.proj.Projection} - */ - this.projection_ = ol.proj.get(options.projection); - - /** - * @private - * @type {Array.<ol.Attribution>} - */ - this.attributions_ = options.attributions !== undefined ? - options.attributions : null; - - /** - * @private - * @type {string|olx.LogoOptions|undefined} - */ - this.logo_ = options.logo; - - /** - * @private - * @type {ol.source.State} - */ - this.state_ = options.state !== undefined ? - options.state : ol.source.State.READY; - - /** - * @private - * @type {boolean} - */ - this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false; - -}; -goog.inherits(ol.source.Source, ol.Object); - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {Object.<string, boolean>} skippedFeatureUids Skipped feature uids. - * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature - * callback. - * @return {T|undefined} Callback result. - * @template T - */ -ol.source.Source.prototype.forEachFeatureAtCoordinate = ol.nullFunction; - - -/** - * Get the attributions of the source. - * @return {Array.<ol.Attribution>} Attributions. - * @api stable - */ -ol.source.Source.prototype.getAttributions = function() { - return this.attributions_; -}; - - -/** - * Get the logo of the source. - * @return {string|olx.LogoOptions|undefined} Logo. - * @api stable - */ -ol.source.Source.prototype.getLogo = function() { - return this.logo_; -}; - - -/** - * Get the projection of the source. - * @return {ol.proj.Projection} Projection. - * @api - */ -ol.source.Source.prototype.getProjection = function() { - return this.projection_; -}; - - -/** - * @return {Array.<number>|undefined} Resolutions. - */ -ol.source.Source.prototype.getResolutions = goog.abstractMethod; - - -/** - * Get the state of the source, see {@link ol.source.State} for possible states. - * @return {ol.source.State} State. - * @api - */ -ol.source.Source.prototype.getState = function() { - return this.state_; -}; - - -/** - * @return {boolean|undefined} Wrap X. - */ -ol.source.Source.prototype.getWrapX = function() { - return this.wrapX_; -}; - - -/** - * Set the attributions of the source. - * @param {Array.<ol.Attribution>} attributions Attributions. - * @api - */ -ol.source.Source.prototype.setAttributions = function(attributions) { - this.attributions_ = attributions; - this.changed(); -}; - - -/** - * Set the logo of the source. - * @param {string|olx.LogoOptions|undefined} logo Logo. - */ -ol.source.Source.prototype.setLogo = function(logo) { - this.logo_ = logo; -}; - - -/** - * Set the state of the source. - * @param {ol.source.State} state State. - * @protected - */ -ol.source.Source.prototype.setState = function(state) { - this.state_ = state; - this.changed(); -}; - - -/** - * Set the projection of the source. - * @param {ol.proj.Projection} projection Projection. - */ -ol.source.Source.prototype.setProjection = function(projection) { - this.projection_ = projection; -}; - -goog.provide('ol.tilegrid.TileGrid'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.TileCoord'); -goog.require('ol.TileRange'); -goog.require('ol.array'); -goog.require('ol.extent'); -goog.require('ol.extent.Corner'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); - - - -/** - * @classdesc - * Base class for setting the grid pattern for sources accessing tiled-image - * servers. - * - * @constructor - * @param {olx.tilegrid.TileGridOptions} options Tile grid options. - * @struct - * @api stable - */ -ol.tilegrid.TileGrid = function(options) { - - /** - * @protected - * @type {number} - */ - this.minZoom = options.minZoom !== undefined ? options.minZoom : 0; - - /** - * @private - * @type {!Array.<number>} - */ - this.resolutions_ = options.resolutions; - goog.asserts.assert(goog.array.isSorted(this.resolutions_, function(a, b) { - return b - a; - }, true), 'resolutions must be sorted in descending order'); - - /** - * @protected - * @type {number} - */ - this.maxZoom = this.resolutions_.length - 1; - - /** - * @private - * @type {ol.Coordinate} - */ - this.origin_ = options.origin !== undefined ? options.origin : null; - - /** - * @private - * @type {Array.<ol.Coordinate>} - */ - this.origins_ = null; - if (options.origins !== undefined) { - this.origins_ = options.origins; - goog.asserts.assert(this.origins_.length == this.resolutions_.length, - 'number of origins and resolutions must be equal'); - } - - var extent = options.extent; - - if (extent !== undefined && - !this.origin_ && !this.origins_) { - this.origin_ = ol.extent.getTopLeft(extent); - } - - goog.asserts.assert( - (!this.origin_ && this.origins_) || - (this.origin_ && !this.origins_), - 'either origin or origins must be configured, never both'); - - /** - * @private - * @type {Array.<number|ol.Size>} - */ - this.tileSizes_ = null; - if (options.tileSizes !== undefined) { - this.tileSizes_ = options.tileSizes; - goog.asserts.assert(this.tileSizes_.length == this.resolutions_.length, - 'number of tileSizes and resolutions must be equal'); - } - - /** - * @private - * @type {number|ol.Size} - */ - this.tileSize_ = options.tileSize !== undefined ? - options.tileSize : - !this.tileSizes_ ? ol.DEFAULT_TILE_SIZE : null; - goog.asserts.assert( - (!this.tileSize_ && this.tileSizes_) || - (this.tileSize_ && !this.tileSizes_), - 'either tileSize or tileSizes must be configured, never both'); - - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = extent !== undefined ? extent : null; - - - /** - * @private - * @type {Array.<ol.TileRange>} - */ - this.fullTileRanges_ = null; - - if (options.sizes !== undefined) { - goog.asserts.assert(options.sizes.length == this.resolutions_.length, - 'number of sizes and resolutions must be equal'); - this.fullTileRanges_ = options.sizes.map(function(size, z) { - goog.asserts.assert(size[0] !== 0, 'width must not be 0'); - goog.asserts.assert(size[1] !== 0, 'height must not be 0'); - var tileRange = new ol.TileRange( - Math.min(0, size[0]), Math.max(size[0] - 1, -1), - Math.min(0, size[1]), Math.max(size[1] - 1, -1)); - if (this.minZoom <= z && z <= this.maxZoom && extent !== undefined) { - goog.asserts.assert(tileRange.containsTileRange( - this.getTileRangeForExtentAndZ(extent, z)), - 'extent tile range must not exceed tilegrid width and height'); - } - return tileRange; - }, this); - } else if (extent) { - this.calculateTileRanges_(extent); - } - - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; - -}; - - -/** - * @private - * @type {ol.TileCoord} - */ -ol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0]; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {function(this: T, number, ol.TileRange): boolean} callback Callback. - * @param {T=} opt_this The object to use as `this` in `callback`. - * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. - * @param {ol.Extent=} opt_extent Temporary ol.Extent object. - * @return {boolean} Callback succeeded. - * @template T - */ -ol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange = - function(tileCoord, callback, opt_this, opt_tileRange, opt_extent) { - var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); - var z = tileCoord[0] - 1; - while (z >= this.minZoom) { - if (callback.call(opt_this, z, - this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange))) { - return true; - } - --z; - } - return false; -}; - - -/** - * Get the extent for this tile grid, if it was configured. - * @return {ol.Extent} Extent. - */ -ol.tilegrid.TileGrid.prototype.getExtent = function() { - return this.extent_; -}; - - -/** - * Get the maximum zoom level for the grid. - * @return {number} Max zoom. - * @api - */ -ol.tilegrid.TileGrid.prototype.getMaxZoom = function() { - return this.maxZoom; -}; - - -/** - * Get the minimum zoom level for the grid. - * @return {number} Min zoom. - * @api - */ -ol.tilegrid.TileGrid.prototype.getMinZoom = function() { - return this.minZoom; -}; - - -/** - * Get the origin for the grid at the given zoom level. - * @param {number} z Z. - * @return {ol.Coordinate} Origin. - * @api stable - */ -ol.tilegrid.TileGrid.prototype.getOrigin = function(z) { - if (this.origin_) { - return this.origin_; - } else { - goog.asserts.assert(this.origins_, - 'origins cannot be null if origin is null'); - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'given z is not in allowed range (%s <= %s <= %s)', - this.minZoom, z, this.maxZoom); - return this.origins_[z]; - } -}; - - -/** - * Get the resolution for the given zoom level. - * @param {number} z Z. - * @return {number} Resolution. - * @api stable - */ -ol.tilegrid.TileGrid.prototype.getResolution = function(z) { - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'given z is not in allowed range (%s <= %s <= %s)', - this.minZoom, z, this.maxZoom); - return this.resolutions_[z]; -}; - - -/** - * Get the list of resolutions for the tile grid. - * @return {Array.<number>} Resolutions. - * @api stable - */ -ol.tilegrid.TileGrid.prototype.getResolutions = function() { - return this.resolutions_; -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. - * @param {ol.Extent=} opt_extent Temporary ol.Extent object. - * @return {ol.TileRange} Tile range. - */ -ol.tilegrid.TileGrid.prototype.getTileCoordChildTileRange = - function(tileCoord, opt_tileRange, opt_extent) { - if (tileCoord[0] < this.maxZoom) { - var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); - return this.getTileRangeForExtentAndZ( - tileCoordExtent, tileCoord[0] + 1, opt_tileRange); - } else { - return null; - } -}; - - -/** - * @param {number} z Z. - * @param {ol.TileRange} tileRange Tile range. - * @param {ol.Extent=} opt_extent Temporary ol.Extent object. - * @return {ol.Extent} Extent. - */ -ol.tilegrid.TileGrid.prototype.getTileRangeExtent = - function(z, tileRange, opt_extent) { - var origin = this.getOrigin(z); - var resolution = this.getResolution(z); - var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_); - var minX = origin[0] + tileRange.minX * tileSize[0] * resolution; - var maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution; - var minY = origin[1] + tileRange.minY * tileSize[1] * resolution; - var maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution; - return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {ol.TileRange=} opt_tileRange Temporary tile range object. - * @return {ol.TileRange} Tile range. - */ -ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = - function(extent, resolution, opt_tileRange) { - var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_; - this.getTileCoordForXYAndResolution_( - extent[0], extent[1], resolution, false, tileCoord); - var minX = tileCoord[1]; - var minY = tileCoord[2]; - this.getTileCoordForXYAndResolution_( - extent[2], extent[3], resolution, true, tileCoord); - return ol.TileRange.createOrUpdate( - minX, tileCoord[1], minY, tileCoord[2], opt_tileRange); -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} z Z. - * @param {ol.TileRange=} opt_tileRange Temporary tile range object. - * @return {ol.TileRange} Tile range. - */ -ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = - function(extent, z, opt_tileRange) { - var resolution = this.getResolution(z); - return this.getTileRangeForExtentAndResolution( - extent, resolution, opt_tileRange); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @return {ol.Coordinate} Tile center. - */ -ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) { - var origin = this.getOrigin(tileCoord[0]); - var resolution = this.getResolution(tileCoord[0]); - var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); - return [ - origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution, - origin[1] + (tileCoord[2] + 0.5) * tileSize[1] * resolution - ]; -}; - - -/** - * Get the extent of a tile coordinate. - * - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Extent=} opt_extent Temporary extent object. - * @return {ol.Extent} Extent. - * @api - */ -ol.tilegrid.TileGrid.prototype.getTileCoordExtent = - function(tileCoord, opt_extent) { - var origin = this.getOrigin(tileCoord[0]); - var resolution = this.getResolution(tileCoord[0]); - var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); - var minX = origin[0] + tileCoord[1] * tileSize[0] * resolution; - var minY = origin[1] + tileCoord[2] * tileSize[1] * resolution; - var maxX = minX + tileSize[0] * resolution; - var maxY = minY + tileSize[1] * resolution; - return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); -}; - - -/** - * Get the tile coordinate for the given map coordinate and resolution. This - * method considers that coordinates that intersect tile boundaries should be - * assigned the higher tile coordinate. - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object. - * @return {ol.TileCoord} Tile coordinate. - * @api - */ -ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = - function(coordinate, resolution, opt_tileCoord) { - return this.getTileCoordForXYAndResolution_( - coordinate[0], coordinate[1], resolution, false, opt_tileCoord); -}; - - -/** - * @param {number} x X. - * @param {number} y Y. - * @param {number} resolution Resolution. - * @param {boolean} reverseIntersectionPolicy Instead of letting edge - * intersections go to the higher tile coordinate, let edge intersections - * go to the lower tile coordinate. - * @param {ol.TileCoord=} opt_tileCoord Temporary ol.TileCoord object. - * @return {ol.TileCoord} Tile coordinate. - * @private - */ -ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function( - x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) { - var z = this.getZForResolution(resolution); - var scale = resolution / this.getResolution(z); - var origin = this.getOrigin(z); - var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_); - - var adjustX = reverseIntersectionPolicy ? 0.5 : 0; - var adjustY = reverseIntersectionPolicy ? 0 : 0.5; - var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX); - var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY); - var tileCoordX = scale * xFromOrigin / tileSize[0]; - var tileCoordY = scale * yFromOrigin / tileSize[1]; - - if (reverseIntersectionPolicy) { - tileCoordX = Math.ceil(tileCoordX) - 1; - tileCoordY = Math.ceil(tileCoordY) - 1; - } else { - tileCoordX = Math.floor(tileCoordX); - tileCoordY = Math.floor(tileCoordY); - } - - return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord); -}; - - -/** - * Get a tile coordinate given a map coordinate and zoom level. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} z Zoom level. - * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object. - * @return {ol.TileCoord} Tile coordinate. - * @api - */ -ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ = - function(coordinate, z, opt_tileCoord) { - var resolution = this.getResolution(z); - return this.getTileCoordForXYAndResolution_( - coordinate[0], coordinate[1], resolution, false, opt_tileCoord); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @return {number} Tile resolution. - */ -ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) { - goog.asserts.assert( - this.minZoom <= tileCoord[0] && tileCoord[0] <= this.maxZoom, - 'z of given tilecoord is not in allowed range (%s <= %s <= %s', - this.minZoom, tileCoord[0], this.maxZoom); - return this.resolutions_[tileCoord[0]]; -}; - - -/** - * Get the tile size for a zoom level. The type of the return value matches the - * `tileSize` or `tileSizes` that the tile grid was configured with. To always - * get an `ol.Size`, run the result through `ol.size.toSize()`. - * @param {number} z Z. - * @return {number|ol.Size} Tile size. - * @api stable - */ -ol.tilegrid.TileGrid.prototype.getTileSize = function(z) { - if (this.tileSize_) { - return this.tileSize_; - } else { - goog.asserts.assert(this.tileSizes_, - 'tileSizes cannot be null if tileSize is null'); - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'z is not in allowed range (%s <= %s <= %s', - this.minZoom, z, this.maxZoom); - return this.tileSizes_[z]; - } -}; - - -/** - * @param {number} z Zoom level. - * @return {ol.TileRange} Extent tile range for the specified zoom level. - */ -ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) { - if (!this.fullTileRanges_) { - return null; - } else { - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'z is not in allowed range (%s <= %s <= %s', - this.minZoom, z, this.maxZoom); - return this.fullTileRanges_[z]; - } -}; - - -/** - * @param {number} resolution Resolution. - * @return {number} Z. - */ -ol.tilegrid.TileGrid.prototype.getZForResolution = function(resolution) { - var z = ol.array.linearFindNearest(this.resolutions_, resolution, 0); - return ol.math.clamp(z, this.minZoom, this.maxZoom); -}; - - -/** - * @param {!ol.Extent} extent Extent for this tile grid. - * @private - */ -ol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) { - var length = this.resolutions_.length; - var fullTileRanges = new Array(length); - for (var z = this.minZoom; z < length; ++z) { - fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z); - } - this.fullTileRanges_ = fullTileRanges; -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - * @return {ol.tilegrid.TileGrid} Default tile grid for the passed projection. - */ -ol.tilegrid.getForProjection = function(projection) { - var tileGrid = projection.getDefaultTileGrid(); - if (!tileGrid) { - tileGrid = ol.tilegrid.createForProjection(projection); - projection.setDefaultTileGrid(tileGrid); - } - return tileGrid; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number=} opt_maxZoom Maximum zoom level (default is - * ol.DEFAULT_MAX_ZOOM). - * @param {number|ol.Size=} opt_tileSize Tile size (default uses - * ol.DEFAULT_TILE_SIZE). - * @param {ol.extent.Corner=} opt_corner Extent corner (default is - * ol.extent.Corner.TOP_LEFT). - * @return {ol.tilegrid.TileGrid} TileGrid instance. - */ -ol.tilegrid.createForExtent = - function(extent, opt_maxZoom, opt_tileSize, opt_corner) { - var corner = opt_corner !== undefined ? - opt_corner : ol.extent.Corner.TOP_LEFT; - - var resolutions = ol.tilegrid.resolutionsFromExtent( - extent, opt_maxZoom, opt_tileSize); - - return new ol.tilegrid.TileGrid({ - extent: extent, - origin: ol.extent.getCorner(extent, corner), - resolutions: resolutions, - tileSize: opt_tileSize - }); -}; - - -/** - * Creates a tile grid with a standard XYZ tiling scheme. - * @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options. - * @return {ol.tilegrid.TileGrid} Tile grid instance. - * @api - */ -ol.tilegrid.createXYZ = function(opt_options) { - var options = /** @type {olx.tilegrid.TileGridOptions} */ ({}); - goog.object.extend(options, opt_options !== undefined ? - opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({})); - if (options.extent === undefined) { - options.extent = ol.proj.get('EPSG:3857').getExtent(); - } - options.resolutions = ol.tilegrid.resolutionsFromExtent( - options.extent, options.maxZoom, options.tileSize); - delete options.maxZoom; - - return new ol.tilegrid.TileGrid(options); -}; - - -/** - * Create a resolutions array from an extent. A zoom factor of 2 is assumed. - * @param {ol.Extent} extent Extent. - * @param {number=} opt_maxZoom Maximum zoom level (default is - * ol.DEFAULT_MAX_ZOOM). - * @param {number|ol.Size=} opt_tileSize Tile size (default uses - * ol.DEFAULT_TILE_SIZE). - * @return {!Array.<number>} Resolutions array. - */ -ol.tilegrid.resolutionsFromExtent = - function(extent, opt_maxZoom, opt_tileSize) { - var maxZoom = opt_maxZoom !== undefined ? - opt_maxZoom : ol.DEFAULT_MAX_ZOOM; - - var height = ol.extent.getHeight(extent); - var width = ol.extent.getWidth(extent); - - var tileSize = ol.size.toSize(opt_tileSize !== undefined ? - opt_tileSize : ol.DEFAULT_TILE_SIZE); - var maxResolution = Math.max( - width / tileSize[0], height / tileSize[1]); - - var length = maxZoom + 1; - var resolutions = new Array(length); - for (var z = 0; z < length; ++z) { - resolutions[z] = maxResolution / Math.pow(2, z); - } - return resolutions; -}; - - -/** - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {number=} opt_maxZoom Maximum zoom level (default is - * ol.DEFAULT_MAX_ZOOM). - * @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE). - * @param {ol.extent.Corner=} opt_corner Extent corner (default is - * ol.extent.Corner.BOTTOM_LEFT). - * @return {ol.tilegrid.TileGrid} TileGrid instance. - */ -ol.tilegrid.createForProjection = - function(projection, opt_maxZoom, opt_tileSize, opt_corner) { - var extent = ol.tilegrid.extentFromProjection(projection); - return ol.tilegrid.createForExtent( - extent, opt_maxZoom, opt_tileSize, opt_corner); -}; - - -/** - * Generate a tile grid extent from a projection. If the projection has an - * extent, it is used. If not, a global extent is assumed. - * @param {ol.proj.ProjectionLike} projection Projection. - * @return {ol.Extent} Extent. - */ -ol.tilegrid.extentFromProjection = function(projection) { - projection = ol.proj.get(projection); - var extent = projection.getExtent(); - if (!extent) { - var half = 180 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] / - projection.getMetersPerUnit(); - extent = ol.extent.createOrUpdate(-half, -half, half, half); - } - return extent; -}; -goog.exportProperty(ol.tilegrid.TileGrid.prototype, 'getTileRangeForExtentAndZ', - ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ); - - -goog.provide('ol.source.Tile'); -goog.provide('ol.source.TileEvent'); -goog.provide('ol.source.TileOptions'); - -goog.require('goog.asserts'); -goog.require('goog.events.Event'); -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.Extent'); -goog.require('ol.TileCache'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.proj'); -goog.require('ol.size'); -goog.require('ol.source.Source'); -goog.require('ol.tilecoord'); -goog.require('ol.tilegrid.TileGrid'); - - -/** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * cacheSize: (number|undefined), - * extent: (ol.Extent|undefined), - * logo: (string|olx.LogoOptions|undefined), - * opaque: (boolean|undefined), - * tilePixelRatio: (number|undefined), - * projection: ol.proj.ProjectionLike, - * state: (ol.source.State|undefined), - * tileGrid: (ol.tilegrid.TileGrid|undefined), - * wrapX: (boolean|undefined)}} - */ -ol.source.TileOptions; - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for sources providing images divided into a tile grid. - * - * @constructor - * @extends {ol.source.Source} - * @param {ol.source.TileOptions} options Tile source options. - * @api - */ -ol.source.Tile = function(options) { - - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection, - state: options.state, - wrapX: options.wrapX - }); - - /** - * @private - * @type {boolean} - */ - this.opaque_ = options.opaque !== undefined ? options.opaque : false; - - /** - * @private - * @type {number} - */ - this.tilePixelRatio_ = options.tilePixelRatio !== undefined ? - options.tilePixelRatio : 1; - - /** - * @protected - * @type {ol.tilegrid.TileGrid} - */ - this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null; - - /** - * @protected - * @type {ol.TileCache} - */ - this.tileCache = new ol.TileCache(options.cacheSize); - - /** - * @protected - * @type {ol.Size} - */ - this.tmpSize = [0, 0]; - -}; -goog.inherits(ol.source.Tile, ol.source.Source); - - -/** - * @return {boolean} Can expire cache. - */ -ol.source.Tile.prototype.canExpireCache = function() { - return this.tileCache.canExpireCache(); -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - * @param {Object.<string, ol.TileRange>} usedTiles Used tiles. - */ -ol.source.Tile.prototype.expireCache = function(projection, usedTiles) { - var tileCache = this.getTileCacheForProjection(projection); - if (tileCache) { - tileCache.expireCache(usedTiles); - } -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - * @param {number} z Zoom level. - * @param {ol.TileRange} tileRange Tile range. - * @param {function(ol.Tile):(boolean|undefined)} callback Called with each - * loaded tile. If the callback returns `false`, the tile will not be - * considered loaded. - * @return {boolean} The tile range is fully covered with loaded tiles. - */ -ol.source.Tile.prototype.forEachLoadedTile = - function(projection, z, tileRange, callback) { - var tileCache = this.getTileCacheForProjection(projection); - if (!tileCache) { - return false; - } - - var covered = true; - var tile, tileCoordKey, loaded; - for (var x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (var y = tileRange.minY; y <= tileRange.maxY; ++y) { - tileCoordKey = this.getKeyZXY(z, x, y); - loaded = false; - if (tileCache.containsKey(tileCoordKey)) { - tile = /** @type {!ol.Tile} */ (tileCache.get(tileCoordKey)); - loaded = tile.getState() === ol.TileState.LOADED; - if (loaded) { - loaded = (callback(tile) !== false); - } - } - if (!loaded) { - covered = false; - } - } - } - return covered; -}; - - -/** - * @return {number} Gutter. - */ -ol.source.Tile.prototype.getGutter = function() { - return 0; -}; - - -/** - * Return the "parameters" key, a string composed of the source's - * parameters/dimensions. - * @return {string} The parameters key. - * @protected - */ -ol.source.Tile.prototype.getKeyParams = function() { - return ''; -}; - - -/** - * @param {number} z Z. - * @param {number} x X. - * @param {number} y Y. - * @return {string} Key. - * @protected - */ -ol.source.Tile.prototype.getKeyZXY = ol.tilecoord.getKeyZXY; - - -/** - * @return {boolean} Opaque. - */ -ol.source.Tile.prototype.getOpaque = function() { - return this.opaque_; -}; - - -/** - * @inheritDoc - */ -ol.source.Tile.prototype.getResolutions = function() { - return this.tileGrid.getResolutions(); -}; - - -/** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {!ol.Tile} Tile. - */ -ol.source.Tile.prototype.getTile = goog.abstractMethod; - - -/** - * Return the tile grid of the tile source. - * @return {ol.tilegrid.TileGrid} Tile grid. - * @api stable - */ -ol.source.Tile.prototype.getTileGrid = function() { - return this.tileGrid; -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - * @return {ol.tilegrid.TileGrid} Tile grid. - */ -ol.source.Tile.prototype.getTileGridForProjection = function(projection) { - if (!this.tileGrid) { - return ol.tilegrid.getForProjection(projection); - } else { - return this.tileGrid; - } -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - * @return {ol.TileCache} Tile cache. - * @protected - */ -ol.source.Tile.prototype.getTileCacheForProjection = function(projection) { - var thisProj = this.getProjection(); - if (thisProj && !ol.proj.equivalent(thisProj, projection)) { - return null; - } else { - return this.tileCache; - } -}; - - -/** - * @return {number} Tile pixel ratio. - */ -ol.source.Tile.prototype.getTilePixelRatio = function() { - return this.tilePixelRatio_; -}; - - -/** - * @param {number} z Z. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.Size} Tile size. - */ -ol.source.Tile.prototype.getTilePixelSize = - function(z, pixelRatio, projection) { - var tileGrid = this.getTileGridForProjection(projection); - return ol.size.scale(ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize), - this.tilePixelRatio_, this.tmpSize); -}; - - -/** - * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate - * is outside the resolution and extent range of the tile grid, `null` will be - * returned. - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.proj.Projection=} opt_projection Projection. - * @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or - * null if no tile URL should be created for the passed `tileCoord`. - */ -ol.source.Tile.prototype.getTileCoordForTileUrlFunction = - function(tileCoord, opt_projection) { - var projection = opt_projection !== undefined ? - opt_projection : this.getProjection(); - var tileGrid = this.getTileGridForProjection(projection); - goog.asserts.assert(tileGrid, 'tile grid needed'); - if (this.getWrapX() && projection.isGlobal()) { - tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection); - } - return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null; -}; - - -/** - * Marks a tile coord as being used, without triggering a load. - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {ol.proj.Projection} projection Projection. - */ -ol.source.Tile.prototype.useTile = ol.nullFunction; - - - -/** - * @classdesc - * Events emitted by {@link ol.source.Tile} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.TileEvent} - * @param {string} type Type. - * @param {ol.Tile} tile The tile. - */ -ol.source.TileEvent = function(type, tile) { - - goog.base(this, type); - - /** - * The tile related to the event. - * @type {ol.Tile} - * @api - */ - this.tile = tile; - -}; -goog.inherits(ol.source.TileEvent, goog.events.Event); - - -/** - * @enum {string} - */ -ol.source.TileEventType = { - - /** - * Triggered when a tile starts loading. - * @event ol.source.TileEvent#tileloadstart - * @api stable - */ - TILELOADSTART: 'tileloadstart', - - /** - * Triggered when a tile finishes loading. - * @event ol.source.TileEvent#tileloadend - * @api stable - */ - TILELOADEND: 'tileloadend', - - /** - * Triggered if tile loading results in an error. - * @event ol.source.TileEvent#tileloaderror - * @api stable - */ - TILELOADERROR: 'tileloaderror' - -}; - -// FIXME handle date line wrap - -goog.provide('ol.control.Attribution'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.source.Tile'); - - - -/** - * @classdesc - * Control to show all the attributions associated with the layer sources - * in the map. This control is one of the default controls included in maps. - * By default it will show in the bottom right portion of the map, but this can - * be changed by using a css selector for `.ol-attribution`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.AttributionOptions=} opt_options Attribution options. - * @api stable - */ -ol.control.Attribution = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {Element} - */ - this.ulElement_ = goog.dom.createElement('UL'); - - /** - * @private - * @type {Element} - */ - this.logoLi_ = goog.dom.createElement('LI'); - - this.ulElement_.appendChild(this.logoLi_); - goog.style.setElementShown(this.logoLi_, false); - - /** - * @private - * @type {boolean} - */ - this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true; - - /** - * @private - * @type {boolean} - */ - this.collapsible_ = options.collapsible !== undefined ? - options.collapsible : true; - - if (!this.collapsible_) { - this.collapsed_ = false; - } - - var className = options.className ? options.className : 'ol-attribution'; - - var tipLabel = options.tipLabel ? options.tipLabel : 'Attributions'; - - var collapseLabel = options.collapseLabel ? options.collapseLabel : '\u00BB'; - - /** - * @private - * @type {Node} - */ - this.collapseLabel_ = goog.isString(collapseLabel) ? - goog.dom.createDom('SPAN', {}, collapseLabel) : - collapseLabel; - - var label = options.label ? options.label : 'i'; - - /** - * @private - * @type {Node} - */ - this.label_ = goog.isString(label) ? - goog.dom.createDom('SPAN', {}, label) : - label; - - var activeLabel = (this.collapsible_ && !this.collapsed_) ? - this.collapseLabel_ : this.label_; - var button = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'title': tipLabel - }, activeLabel); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - - goog.events.listen(button, [ - goog.events.EventType.MOUSEOUT, - goog.events.EventType.FOCUSOUT - ], function() { - this.blur(); - }, false); - - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL + - (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') + - (this.collapsible_ ? '' : ' ol-uncollapsible'); - var element = goog.dom.createDom('DIV', - cssClasses, this.ulElement_, button); - - var render = options.render ? options.render : ol.control.Attribution.render; - - goog.base(this, { - element: element, - render: render, - target: options.target - }); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - - /** - * @private - * @type {Object.<string, Element>} - */ - this.attributionElements_ = {}; - - /** - * @private - * @type {Object.<string, boolean>} - */ - this.attributionElementRenderedVisible_ = {}; - - /** - * @private - * @type {Object.<string, Element>} - */ - this.logoElements_ = {}; - -}; -goog.inherits(ol.control.Attribution, ol.control.Control); - - -/** - * @param {?olx.FrameState} frameState Frame state. - * @return {Array.<Object.<string, ol.Attribution>>} Attributions. - */ -ol.control.Attribution.prototype.getSourceAttributions = function(frameState) { - var i, ii, j, jj, tileRanges, source, sourceAttribution, - sourceAttributionKey, sourceAttributions, sourceKey; - var intersectsTileRange; - var layerStatesArray = frameState.layerStatesArray; - /** @type {Object.<string, ol.Attribution>} */ - var attributions = goog.object.clone(frameState.attributions); - /** @type {Object.<string, ol.Attribution>} */ - var hiddenAttributions = {}; - var projection = frameState.viewState.projection; - goog.asserts.assert(projection, 'projection of viewState required'); - for (i = 0, ii = layerStatesArray.length; i < ii; i++) { - source = layerStatesArray[i].layer.getSource(); - if (!source) { - continue; - } - sourceKey = goog.getUid(source).toString(); - sourceAttributions = source.getAttributions(); - if (!sourceAttributions) { - continue; - } - for (j = 0, jj = sourceAttributions.length; j < jj; j++) { - sourceAttribution = sourceAttributions[j]; - sourceAttributionKey = goog.getUid(sourceAttribution).toString(); - if (sourceAttributionKey in attributions) { - continue; - } - tileRanges = frameState.usedTiles[sourceKey]; - if (tileRanges) { - goog.asserts.assertInstanceof(source, ol.source.Tile, - 'source should be an ol.source.Tile'); - var tileGrid = source.getTileGridForProjection(projection); - goog.asserts.assert(tileGrid, 'tileGrid required for projection'); - intersectsTileRange = sourceAttribution.intersectsAnyTileRange( - tileRanges, tileGrid, projection); - } else { - intersectsTileRange = false; - } - if (intersectsTileRange) { - if (sourceAttributionKey in hiddenAttributions) { - delete hiddenAttributions[sourceAttributionKey]; - } - attributions[sourceAttributionKey] = sourceAttribution; - } else { - hiddenAttributions[sourceAttributionKey] = sourceAttribution; - } - } - } - return [attributions, hiddenAttributions]; -}; - - -/** - * Update the attribution element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.Attribution} - * @api - */ -ol.control.Attribution.render = function(mapEvent) { - this.updateElement_(mapEvent.frameState); -}; - - -/** - * @private - * @param {?olx.FrameState} frameState Frame state. - */ -ol.control.Attribution.prototype.updateElement_ = function(frameState) { - - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.element, false); - this.renderedVisible_ = false; - } - return; - } - - var attributions = this.getSourceAttributions(frameState); - /** @type {Object.<string, ol.Attribution>} */ - var visibleAttributions = attributions[0]; - /** @type {Object.<string, ol.Attribution>} */ - var hiddenAttributions = attributions[1]; - - var attributionElement, attributionKey; - for (attributionKey in this.attributionElements_) { - if (attributionKey in visibleAttributions) { - if (!this.attributionElementRenderedVisible_[attributionKey]) { - goog.style.setElementShown( - this.attributionElements_[attributionKey], true); - this.attributionElementRenderedVisible_[attributionKey] = true; - } - delete visibleAttributions[attributionKey]; - } - else if (attributionKey in hiddenAttributions) { - if (this.attributionElementRenderedVisible_[attributionKey]) { - goog.style.setElementShown( - this.attributionElements_[attributionKey], false); - delete this.attributionElementRenderedVisible_[attributionKey]; - } - delete hiddenAttributions[attributionKey]; - } - else { - goog.dom.removeNode(this.attributionElements_[attributionKey]); - delete this.attributionElements_[attributionKey]; - delete this.attributionElementRenderedVisible_[attributionKey]; - } - } - for (attributionKey in visibleAttributions) { - attributionElement = goog.dom.createElement('LI'); - attributionElement.innerHTML = - visibleAttributions[attributionKey].getHTML(); - this.ulElement_.appendChild(attributionElement); - this.attributionElements_[attributionKey] = attributionElement; - this.attributionElementRenderedVisible_[attributionKey] = true; - } - for (attributionKey in hiddenAttributions) { - attributionElement = goog.dom.createElement('LI'); - attributionElement.innerHTML = - hiddenAttributions[attributionKey].getHTML(); - goog.style.setElementShown(attributionElement, false); - this.ulElement_.appendChild(attributionElement); - this.attributionElements_[attributionKey] = attributionElement; - } - - var renderVisible = - !goog.object.isEmpty(this.attributionElementRenderedVisible_) || - !goog.object.isEmpty(frameState.logos); - if (this.renderedVisible_ != renderVisible) { - goog.style.setElementShown(this.element, renderVisible); - this.renderedVisible_ = renderVisible; - } - if (renderVisible && - goog.object.isEmpty(this.attributionElementRenderedVisible_)) { - goog.dom.classlist.add(this.element, 'ol-logo-only'); - } else { - goog.dom.classlist.remove(this.element, 'ol-logo-only'); - } - - this.insertLogos_(frameState); - -}; - - -/** - * @param {?olx.FrameState} frameState Frame state. - * @private - */ -ol.control.Attribution.prototype.insertLogos_ = function(frameState) { - - var logo; - var logos = frameState.logos; - var logoElements = this.logoElements_; - - for (logo in logoElements) { - if (!(logo in logos)) { - goog.dom.removeNode(logoElements[logo]); - delete logoElements[logo]; - } - } - - var image, logoElement, logoKey; - for (logoKey in logos) { - if (!(logoKey in logoElements)) { - image = new Image(); - image.src = logoKey; - var logoValue = logos[logoKey]; - if (logoValue === '') { - logoElement = image; - } else { - logoElement = goog.dom.createDom('A', { - 'href': logoValue - }); - logoElement.appendChild(image); - } - this.logoLi_.appendChild(logoElement); - logoElements[logoKey] = logoElement; - } - } - - goog.style.setElementShown(this.logoLi_, !goog.object.isEmpty(logos)); - -}; - - -/** - * @param {goog.events.BrowserEvent} event The event to handle - * @private - */ -ol.control.Attribution.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleToggle_(); -}; - - -/** - * @private - */ -ol.control.Attribution.prototype.handleToggle_ = function() { - goog.dom.classlist.toggle(this.element, 'ol-collapsed'); - if (this.collapsed_) { - goog.dom.replaceNode(this.collapseLabel_, this.label_); - } else { - goog.dom.replaceNode(this.label_, this.collapseLabel_); - } - this.collapsed_ = !this.collapsed_; -}; - - -/** - * Return `true` if the attribution is collapsible, `false` otherwise. - * @return {boolean} True if the widget is collapsible. - * @api stable - */ -ol.control.Attribution.prototype.getCollapsible = function() { - return this.collapsible_; -}; - - -/** - * Set whether the attribution should be collapsible. - * @param {boolean} collapsible True if the widget is collapsible. - * @api stable - */ -ol.control.Attribution.prototype.setCollapsible = function(collapsible) { - if (this.collapsible_ === collapsible) { - return; - } - this.collapsible_ = collapsible; - goog.dom.classlist.toggle(this.element, 'ol-uncollapsible'); - if (!collapsible && this.collapsed_) { - this.handleToggle_(); - } -}; - - -/** - * Collapse or expand the attribution according to the passed parameter. Will - * not do anything if the attribution isn't collapsible or if the current - * collapsed state is already the one requested. - * @param {boolean} collapsed True if the widget is collapsed. - * @api stable - */ -ol.control.Attribution.prototype.setCollapsed = function(collapsed) { - if (!this.collapsible_ || this.collapsed_ === collapsed) { - return; - } - this.handleToggle_(); -}; - - -/** - * Return `true` when the attribution is currently collapsed or `false` - * otherwise. - * @return {boolean} True if the widget is collapsed. - * @api stable - */ -ol.control.Attribution.prototype.getCollapsed = function() { - return this.collapsed_; -}; - -goog.provide('ol.control.Rotate'); - -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol'); -goog.require('ol.animation'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.easing'); - - - -/** - * @classdesc - * A button control to reset rotation to 0. - * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css - * selector is added to the button when the rotation is 0. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.RotateOptions=} opt_options Rotate options. - * @api stable - */ -ol.control.Rotate = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var className = options.className ? - options.className : 'ol-rotate'; - - var label = options.label ? options.label : '\u21E7'; - - /** - * @type {Element} - * @private - */ - this.label_ = null; - - if (goog.isString(label)) { - this.label_ = goog.dom.createDom('SPAN', - 'ol-compass', label); - } else { - this.label_ = label; - goog.dom.classlist.add(this.label_, 'ol-compass'); - } - - var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation'; - - var button = goog.dom.createDom('BUTTON', { - 'class': className + '-reset', - 'type' : 'button', - 'title': tipLabel - }, this.label_); - - goog.events.listen(button, goog.events.EventType.CLICK, - ol.control.Rotate.prototype.handleClick_, false, this); - - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL; - var element = goog.dom.createDom('DIV', cssClasses, button); - - var render = options.render ? options.render : ol.control.Rotate.render; - - this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined; - - goog.base(this, { - element: element, - render: render, - target: options.target - }); - - /** - * @type {number} - * @private - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; - - /** - * @type {boolean} - * @private - */ - this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true; - - /** - * @private - * @type {number|undefined} - */ - this.rotation_ = undefined; - - if (this.autoHide_) { - goog.dom.classlist.add(this.element, ol.css.CLASS_HIDDEN); - } - -}; -goog.inherits(ol.control.Rotate, ol.control.Control); - - -/** - * @param {goog.events.BrowserEvent} event The event to handle - * @private - */ -ol.control.Rotate.prototype.handleClick_ = function(event) { - event.preventDefault(); - if (this.callResetNorth_ !== undefined) { - this.callResetNorth_(); - } else { - this.resetNorth_(); - } -}; - - -/** - * @private - */ -ol.control.Rotate.prototype.resetNorth_ = function() { - var map = this.getMap(); - var view = map.getView(); - if (!view) { - // the map does not have a view, so we can't act - // upon it - return; - } - var currentRotation = view.getRotation(); - if (currentRotation !== undefined) { - if (this.duration_ > 0) { - currentRotation = currentRotation % (2 * Math.PI); - if (currentRotation < -Math.PI) { - currentRotation += 2 * Math.PI; - } - if (currentRotation > Math.PI) { - currentRotation -= 2 * Math.PI; - } - map.beforeRender(ol.animation.rotate({ - rotation: currentRotation, - duration: this.duration_, - easing: ol.easing.easeOut - })); - } - view.setRotation(0); - } -}; - - -/** - * Update the rotate control element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.Rotate} - * @api - */ -ol.control.Rotate.render = function(mapEvent) { - var frameState = mapEvent.frameState; - if (!frameState) { - return; - } - var rotation = frameState.viewState.rotation; - if (rotation != this.rotation_) { - var transform = 'rotate(' + rotation + 'rad)'; - if (this.autoHide_) { - goog.dom.classlist.enable( - this.element, ol.css.CLASS_HIDDEN, rotation === 0); - } - this.label_.style.msTransform = transform; - this.label_.style.webkitTransform = transform; - this.label_.style.transform = transform; - } - this.rotation_ = rotation; -}; - -goog.provide('ol.control.Zoom'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.animation'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.easing'); - - - -/** - * @classdesc - * A control with 2 buttons, one for zoom in and one for zoom out. - * This control is one of the default controls of a map. To style this control - * use css selectors `.ol-zoom-in` and `.ol-zoom-out`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ZoomOptions=} opt_options Zoom options. - * @api stable - */ -ol.control.Zoom = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var className = options.className ? options.className : 'ol-zoom'; - - var delta = options.delta ? options.delta : 1; - - var zoomInLabel = options.zoomInLabel ? options.zoomInLabel : '+'; - var zoomOutLabel = options.zoomOutLabel ? options.zoomOutLabel : '\u2212'; - - var zoomInTipLabel = options.zoomInTipLabel ? - options.zoomInTipLabel : 'Zoom in'; - var zoomOutTipLabel = options.zoomOutTipLabel ? - options.zoomOutTipLabel : 'Zoom out'; - - var inElement = goog.dom.createDom('BUTTON', { - 'class': className + '-in', - 'type' : 'button', - 'title': zoomInTipLabel - }, zoomInLabel); - - goog.events.listen(inElement, - goog.events.EventType.CLICK, goog.partial( - ol.control.Zoom.prototype.handleClick_, delta), false, this); - - var outElement = goog.dom.createDom('BUTTON', { - 'class': className + '-out', - 'type' : 'button', - 'title': zoomOutTipLabel - }, zoomOutLabel); - - goog.events.listen(outElement, - goog.events.EventType.CLICK, goog.partial( - ol.control.Zoom.prototype.handleClick_, -delta), false, this); - - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL; - var element = goog.dom.createDom('DIV', cssClasses, inElement, - outElement); - - goog.base(this, { - element: element, - target: options.target - }); - - /** - * @type {number} - * @private - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; - -}; -goog.inherits(ol.control.Zoom, ol.control.Control); - - -/** - * @param {number} delta Zoom delta. - * @param {goog.events.BrowserEvent} event The event to handle - * @private - */ -ol.control.Zoom.prototype.handleClick_ = function(delta, event) { - event.preventDefault(); - this.zoomByDelta_(delta); -}; - - -/** - * @param {number} delta Zoom delta. - * @private - */ -ol.control.Zoom.prototype.zoomByDelta_ = function(delta) { - var map = this.getMap(); - var view = map.getView(); - if (!view) { - // the map does not have a view, so we can't act - // upon it - return; - } - var currentResolution = view.getResolution(); - if (currentResolution) { - if (this.duration_ > 0) { - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: this.duration_, - easing: ol.easing.easeOut - })); - } - var newResolution = view.constrainResolution(currentResolution, delta); - view.setResolution(newResolution); - } -}; - -goog.provide('ol.control'); - -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.control.Attribution'); -goog.require('ol.control.Rotate'); -goog.require('ol.control.Zoom'); - - -/** - * Set of controls included in maps by default. Unless configured otherwise, - * this returns a collection containing an instance of each of the following - * controls: - * * {@link ol.control.Zoom} - * * {@link ol.control.Rotate} - * * {@link ol.control.Attribution} - * - * @param {olx.control.DefaultsOptions=} opt_options Defaults options. - * @return {ol.Collection.<ol.control.Control>} Controls. - * @api stable - */ -ol.control.defaults = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var controls = new ol.Collection(); - - var zoomControl = options.zoom !== undefined ? options.zoom : true; - if (zoomControl) { - controls.push(new ol.control.Zoom(options.zoomOptions)); - } - - var rotateControl = options.rotate !== undefined ? options.rotate : true; - if (rotateControl) { - controls.push(new ol.control.Rotate(options.rotateOptions)); - } - - var attributionControl = options.attribution !== undefined ? - options.attribution : true; - if (attributionControl) { - controls.push(new ol.control.Attribution(options.attributionOptions)); - } - - return controls; - -}; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Functions for managing full screen status of the DOM. - * - */ - -goog.provide('goog.dom.fullscreen'); -goog.provide('goog.dom.fullscreen.EventType'); - -goog.require('goog.dom'); -goog.require('goog.userAgent'); - - -/** - * Event types for full screen. - * @enum {string} - */ -goog.dom.fullscreen.EventType = { - /** Dispatched by the Document when the fullscreen status changes. */ - CHANGE: (function() { - if (goog.userAgent.WEBKIT) { - return 'webkitfullscreenchange'; - } - if (goog.userAgent.GECKO) { - return 'mozfullscreenchange'; - } - if (goog.userAgent.IE) { - return 'MSFullscreenChange'; - } - // Opera 12-14, and W3C standard (Draft): - // https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html - return 'fullscreenchange'; - })() -}; - - -/** - * Determines if full screen is supported. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {boolean} True iff full screen is supported. - */ -goog.dom.fullscreen.isSupported = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - var body = doc.body; - return !!(body.webkitRequestFullscreen || - (body.mozRequestFullScreen && doc.mozFullScreenEnabled) || - (body.msRequestFullscreen && doc.msFullscreenEnabled) || - (body.requestFullscreen && doc.fullscreenEnabled)); -}; - - -/** - * Requests putting the element in full screen. - * @param {!Element} element The element to put full screen. - */ -goog.dom.fullscreen.requestFullScreen = function(element) { - if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else if (element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if (element.msRequestFullscreen) { - element.msRequestFullscreen(); - } else if (element.requestFullscreen) { - element.requestFullscreen(); - } -}; - - -/** - * Requests putting the element in full screen with full keyboard access. - * @param {!Element} element The element to put full screen. - */ -goog.dom.fullscreen.requestFullScreenWithKeys = function( - element) { - if (element.mozRequestFullScreenWithKeys) { - element.mozRequestFullScreenWithKeys(); - } else if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else { - goog.dom.fullscreen.requestFullScreen(element); - } -}; - - -/** - * Exits full screen. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - */ -goog.dom.fullscreen.exitFullScreen = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - if (doc.webkitCancelFullScreen) { - doc.webkitCancelFullScreen(); - } else if (doc.mozCancelFullScreen) { - doc.mozCancelFullScreen(); - } else if (doc.msExitFullscreen) { - doc.msExitFullscreen(); - } else if (doc.exitFullscreen) { - doc.exitFullscreen(); - } -}; - - -/** - * Determines if the document is full screen. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {boolean} Whether the document is full screen. - */ -goog.dom.fullscreen.isFullScreen = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - // IE 11 doesn't have similar boolean property, so check whether - // document.msFullscreenElement is null instead. - return !!(doc.webkitIsFullScreen || doc.mozFullScreen || - doc.msFullscreenElement || doc.fullscreenElement); -}; - - -/** - * Get the root element in full screen mode. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {?Element} The root element in full screen mode. - */ -goog.dom.fullscreen.getFullScreenElement = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - var element_list = [ - doc.webkitFullscreenElement, - doc.mozFullScreenElement, - doc.msFullscreenElement, - doc.fullscreenElement - ]; - for (var i = 0; i < element_list.length; i++) { - if (element_list[i] != null) { - return element_list[i]; - } - } - return null; -}; - - -/** - * Gets the document object of the dom. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {!Document} The dom document. - * @private - */ -goog.dom.fullscreen.getDocument_ = function(opt_domHelper) { - return opt_domHelper ? - opt_domHelper.getDocument() : - goog.dom.getDomHelper().getDocument(); -}; - -goog.provide('ol.control.FullScreen'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.dom.fullscreen'); -goog.require('goog.dom.fullscreen.EventType'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol'); -goog.require('ol.control.Control'); -goog.require('ol.css'); - - - -/** - * @classdesc - * Provides a button that when clicked fills up the full screen with the map. - * When in full screen mode, a close button is shown to exit full screen mode. - * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to - * toggle the map in full screen mode. - * - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.FullScreenOptions=} opt_options Options. - * @api stable - */ -ol.control.FullScreen = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {string} - */ - this.cssClassName_ = options.className ? options.className : 'ol-full-screen'; - - var label = options.label ? options.label : '\u2922'; - - /** - * @private - * @type {Node} - */ - this.labelNode_ = goog.isString(label) ? - goog.dom.createTextNode(label) : label; - - var labelActive = options.labelActive ? options.labelActive : '\u00d7'; - - /** - * @private - * @type {Node} - */ - this.labelActiveNode_ = goog.isString(labelActive) ? - goog.dom.createTextNode(labelActive) : labelActive; - - var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen'; - var button = goog.dom.createDom('BUTTON', { - 'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen(), - 'type': 'button', - 'title': tipLabel - }, this.labelNode_); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - - goog.events.listen(goog.global.document, - goog.dom.fullscreen.EventType.CHANGE, - this.handleFullScreenChange_, false, this); - - var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE + - ' ' + ol.css.CLASS_CONTROL + ' ' + - (!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : ''); - var element = goog.dom.createDom('DIV', cssClasses, button); - - goog.base(this, { - element: element, - target: options.target - }); - - /** - * @private - * @type {boolean} - */ - this.keys_ = options.keys !== undefined ? options.keys : false; - -}; -goog.inherits(ol.control.FullScreen, ol.control.Control); - - -/** - * @param {goog.events.BrowserEvent} event The event to handle - * @private - */ -ol.control.FullScreen.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleFullScreen_(); -}; - - -/** - * @private - */ -ol.control.FullScreen.prototype.handleFullScreen_ = function() { - if (!goog.dom.fullscreen.isSupported()) { - return; - } - var map = this.getMap(); - if (!map) { - return; - } - if (goog.dom.fullscreen.isFullScreen()) { - goog.dom.fullscreen.exitFullScreen(); - } else { - var target = map.getTarget(); - goog.asserts.assert(target, 'target should be defined'); - var element = goog.dom.getElement(target); - goog.asserts.assert(element, 'element should be defined'); - if (this.keys_) { - goog.dom.fullscreen.requestFullScreenWithKeys(element); - } else { - goog.dom.fullscreen.requestFullScreen(element); - } - } -}; - - -/** - * @private - */ -ol.control.FullScreen.prototype.handleFullScreenChange_ = function() { - var opened = this.cssClassName_ + '-true'; - var closed = this.cssClassName_ + '-false'; - var button = goog.dom.getFirstElementChild(this.element); - var map = this.getMap(); - if (goog.dom.fullscreen.isFullScreen()) { - goog.dom.classlist.swap(button, closed, opened); - goog.dom.replaceNode(this.labelActiveNode_, this.labelNode_); - } else { - goog.dom.classlist.swap(button, opened, closed); - goog.dom.replaceNode(this.labelNode_, this.labelActiveNode_); - } - if (map) { - map.updateSize(); - } -}; - -goog.provide('ol.Pixel'); - - -/** - * An array with two elements, representing a pixel. The first element is the - * x-coordinate, the second the y-coordinate of the pixel. - * @typedef {Array.<number>} - * @api stable - */ -ol.Pixel; - -// FIXME should listen on appropriate pane, once it is defined - -goog.provide('ol.control.MousePosition'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.CoordinateFormatType'); -goog.require('ol.Object'); -goog.require('ol.Pixel'); -goog.require('ol.TransformFunction'); -goog.require('ol.control.Control'); -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); - - -/** - * @enum {string} - */ -ol.control.MousePositionProperty = { - PROJECTION: 'projection', - COORDINATE_FORMAT: 'coordinateFormat' -}; - - - -/** - * @classdesc - * A control to show the 2D coordinates of the mouse cursor. By default, these - * are in the view projection, but can be in any supported projection. - * By default the control is shown in the top right corner of the map, but this - * can be changed by using the css selector `.ol-mouse-position`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.MousePositionOptions=} opt_options Mouse position - * options. - * @api stable - */ -ol.control.MousePosition = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var className = options.className ? options.className : 'ol-mouse-position'; - - var element = goog.dom.createDom('DIV', className); - - var render = options.render ? - options.render : ol.control.MousePosition.render; - - goog.base(this, { - element: element, - render: render, - target: options.target - }); - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION), - this.handleProjectionChanged_, false, this); - - if (options.coordinateFormat) { - this.setCoordinateFormat(options.coordinateFormat); - } - if (options.projection) { - this.setProjection(ol.proj.get(options.projection)); - } - - /** - * @private - * @type {string} - */ - this.undefinedHTML_ = options.undefinedHTML ? options.undefinedHTML : ''; - - /** - * @private - * @type {string} - */ - this.renderedHTML_ = element.innerHTML; - - /** - * @private - * @type {ol.proj.Projection} - */ - this.mapProjection_ = null; - - /** - * @private - * @type {?ol.TransformFunction} - */ - this.transform_ = null; - - /** - * @private - * @type {ol.Pixel} - */ - this.lastMouseMovePixel_ = null; - -}; -goog.inherits(ol.control.MousePosition, ol.control.Control); - - -/** - * Update the mouseposition element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.MousePosition} - * @api - */ -ol.control.MousePosition.render = function(mapEvent) { - var frameState = mapEvent.frameState; - if (!frameState) { - this.mapProjection_ = null; - } else { - if (this.mapProjection_ != frameState.viewState.projection) { - this.mapProjection_ = frameState.viewState.projection; - this.transform_ = null; - } - } - this.updateHTML_(this.lastMouseMovePixel_); -}; - - -/** - * @private - */ -ol.control.MousePosition.prototype.handleProjectionChanged_ = function() { - this.transform_ = null; -}; - - -/** - * Return the coordinate format type used to render the current position or - * undefined. - * @return {ol.CoordinateFormatType|undefined} The format to render the current - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.getCoordinateFormat = function() { - return /** @type {ol.CoordinateFormatType|undefined} */ ( - this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT)); -}; - - -/** - * Return the projection that is used to report the mouse position. - * @return {ol.proj.Projection|undefined} The projection to report mouse - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.getProjection = function() { - return /** @type {ol.proj.Projection|undefined} */ ( - this.get(ol.control.MousePositionProperty.PROJECTION)); -}; - - -/** - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @protected - */ -ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) { - var map = this.getMap(); - this.lastMouseMovePixel_ = map.getEventPixel(browserEvent.getBrowserEvent()); - this.updateHTML_(this.lastMouseMovePixel_); -}; - - -/** - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @protected - */ -ol.control.MousePosition.prototype.handleMouseOut = function(browserEvent) { - this.updateHTML_(null); - this.lastMouseMovePixel_ = null; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.control.MousePosition.prototype.setMap = function(map) { - goog.base(this, 'setMap', map); - if (map) { - var viewport = map.getViewport(); - this.listenerKeys.push( - goog.events.listen(viewport, goog.events.EventType.MOUSEMOVE, - this.handleMouseMove, false, this), - goog.events.listen(viewport, goog.events.EventType.MOUSEOUT, - this.handleMouseOut, false, this) - ); - } -}; - - -/** - * Set the coordinate format type used to render the current position. - * @param {ol.CoordinateFormatType} format The format to render the current - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.setCoordinateFormat = function(format) { - this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format); -}; - - -/** - * Set the projection that is used to report the mouse position. - * @param {ol.proj.Projection} projection The projection to report mouse - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.setProjection = function(projection) { - this.set(ol.control.MousePositionProperty.PROJECTION, projection); -}; - - -/** - * @param {?ol.Pixel} pixel Pixel. - * @private - */ -ol.control.MousePosition.prototype.updateHTML_ = function(pixel) { - var html = this.undefinedHTML_; - if (pixel && this.mapProjection_) { - if (!this.transform_) { - var projection = this.getProjection(); - if (projection) { - this.transform_ = ol.proj.getTransformFromProjections( - this.mapProjection_, projection); - } else { - this.transform_ = ol.proj.identityTransform; - } - } - var map = this.getMap(); - var coordinate = map.getCoordinateFromPixel(pixel); - if (coordinate) { - this.transform_(coordinate, coordinate); - var coordinateFormat = this.getCoordinateFormat(); - if (coordinateFormat) { - html = coordinateFormat(coordinate); - } else { - html = coordinate.toString(); - } - } - } - if (!this.renderedHTML_ || html != this.renderedHTML_) { - this.element.innerHTML = html; - this.renderedHTML_ = html; - } -}; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A delayed callback that pegs to the next animation frame - * instead of a user-configurable timeout. - * - * @author nicksantos@google.com (Nick Santos) - */ - -goog.provide('goog.async.AnimationDelay'); - -goog.require('goog.Disposable'); -goog.require('goog.events'); -goog.require('goog.functions'); - - - -// TODO(nicksantos): Should we factor out the common code between this and -// goog.async.Delay? I'm not sure if there's enough code for this to really -// make sense. Subclassing seems like the wrong approach for a variety of -// reasons. Maybe there should be a common interface? - - - -/** - * A delayed callback that pegs to the next animation frame - * instead of a user configurable timeout. By design, this should have - * the same interface as goog.async.Delay. - * - * Uses requestAnimationFrame and friends when available, but falls - * back to a timeout of goog.async.AnimationDelay.TIMEOUT. - * - * For more on requestAnimationFrame and how you can use it to create smoother - * animations, see: - * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - * - * @param {function(number)} listener Function to call when the delay completes. - * Will be passed the timestamp when it's called, in unix ms. - * @param {Window=} opt_window The window object to execute the delay in. - * Defaults to the global object. - * @param {Object=} opt_handler The object scope to invoke the function in. - * @constructor - * @struct - * @extends {goog.Disposable} - * @final - */ -goog.async.AnimationDelay = function(listener, opt_window, opt_handler) { - goog.async.AnimationDelay.base(this, 'constructor'); - - /** - * Identifier of the active delay timeout, or event listener, - * or null when inactive. - * @private {goog.events.Key|number} - */ - this.id_ = null; - - /** - * If we're using dom listeners. - * @private {?boolean} - */ - this.usingListeners_ = false; - - /** - * The function that will be invoked after a delay. - * @private {function(number)} - */ - this.listener_ = listener; - - /** - * The object context to invoke the callback in. - * @private {Object|undefined} - */ - this.handler_ = opt_handler; - - /** - * @private {Window} - */ - this.win_ = opt_window || window; - - /** - * Cached callback function invoked when the delay finishes. - * @private {function()} - */ - this.callback_ = goog.bind(this.doAction_, this); -}; -goog.inherits(goog.async.AnimationDelay, goog.Disposable); - - -/** - * Default wait timeout for animations (in milliseconds). Only used for timed - * animation, which uses a timer (setTimeout) to schedule animation. - * - * @type {number} - * @const - */ -goog.async.AnimationDelay.TIMEOUT = 20; - - -/** - * Name of event received from the requestAnimationFrame in Firefox. - * - * @type {string} - * @const - * @private - */ -goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_ = 'MozBeforePaint'; - - -/** - * Starts the delay timer. The provided listener function will be called - * before the next animation frame. - */ -goog.async.AnimationDelay.prototype.start = function() { - this.stop(); - this.usingListeners_ = false; - - var raf = this.getRaf_(); - var cancelRaf = this.getCancelRaf_(); - if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { - // Because Firefox (Gecko) runs animation in separate threads, it also saves - // time by running the requestAnimationFrame callbacks in that same thread. - // Sadly this breaks the assumption of implicit thread-safety in JS, and can - // thus create thread-based inconsistencies on counters etc. - // - // Calling cycleAnimations_ using the MozBeforePaint event instead of as - // callback fixes this. - // - // Trigger this condition only if the mozRequestAnimationFrame is available, - // but not the W3C requestAnimationFrame function (as in draft) or the - // equivalent cancel functions. - this.id_ = goog.events.listen( - this.win_, - goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_, - this.callback_); - this.win_.mozRequestAnimationFrame(null); - this.usingListeners_ = true; - } else if (raf && cancelRaf) { - this.id_ = raf.call(this.win_, this.callback_); - } else { - this.id_ = this.win_.setTimeout( - // Prior to Firefox 13, Gecko passed a non-standard parameter - // to the callback that we want to ignore. - goog.functions.lock(this.callback_), - goog.async.AnimationDelay.TIMEOUT); - } -}; - - -/** - * Stops the delay timer if it is active. No action is taken if the timer is not - * in use. - */ -goog.async.AnimationDelay.prototype.stop = function() { - if (this.isActive()) { - var raf = this.getRaf_(); - var cancelRaf = this.getCancelRaf_(); - if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { - goog.events.unlistenByKey(this.id_); - } else if (raf && cancelRaf) { - cancelRaf.call(this.win_, /** @type {number} */ (this.id_)); - } else { - this.win_.clearTimeout(/** @type {number} */ (this.id_)); - } - } - this.id_ = null; -}; - - -/** - * Fires delay's action even if timer has already gone off or has not been - * started yet; guarantees action firing. Stops the delay timer. - */ -goog.async.AnimationDelay.prototype.fire = function() { - this.stop(); - this.doAction_(); -}; - - -/** - * Fires delay's action only if timer is currently active. Stops the delay - * timer. - */ -goog.async.AnimationDelay.prototype.fireIfActive = function() { - if (this.isActive()) { - this.fire(); - } -}; - - -/** - * @return {boolean} True if the delay is currently active, false otherwise. - */ -goog.async.AnimationDelay.prototype.isActive = function() { - return this.id_ != null; -}; - - -/** - * Invokes the callback function after the delay successfully completes. - * @private - */ -goog.async.AnimationDelay.prototype.doAction_ = function() { - if (this.usingListeners_ && this.id_) { - goog.events.unlistenByKey(this.id_); - } - this.id_ = null; - - // We are not using the timestamp returned by requestAnimationFrame - // because it may be either a Date.now-style time or a - // high-resolution time (depending on browser implementation). Using - // goog.now() will ensure that the timestamp used is consistent and - // compatible with goog.fx.Animation. - this.listener_.call(this.handler_, goog.now()); -}; - - -/** @override */ -goog.async.AnimationDelay.prototype.disposeInternal = function() { - this.stop(); - goog.async.AnimationDelay.base(this, 'disposeInternal'); -}; - - -/** - * @return {?function(function(number)): number} The requestAnimationFrame - * function, or null if not available on this browser. - * @private - */ -goog.async.AnimationDelay.prototype.getRaf_ = function() { - var win = this.win_; - return win.requestAnimationFrame || - win.webkitRequestAnimationFrame || - win.mozRequestAnimationFrame || - win.oRequestAnimationFrame || - win.msRequestAnimationFrame || - null; -}; - - -/** - * @return {?function(number): number} The cancelAnimationFrame function, - * or null if not available on this browser. - * @private - */ -goog.async.AnimationDelay.prototype.getCancelRaf_ = function() { - var win = this.win_; - return win.cancelAnimationFrame || - win.cancelRequestAnimationFrame || - win.webkitCancelRequestAnimationFrame || - win.mozCancelRequestAnimationFrame || - win.oCancelRequestAnimationFrame || - win.msCancelRequestAnimationFrame || - null; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Provides a function to schedule running a function as soon - * as possible after the current JS execution stops and yields to the event - * loop. - * - */ - -goog.provide('goog.async.nextTick'); -goog.provide('goog.async.throwException'); - -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.dom.TagName'); -goog.require('goog.functions'); -goog.require('goog.labs.userAgent.browser'); -goog.require('goog.labs.userAgent.engine'); - - -/** - * Throw an item without interrupting the current execution context. For - * example, if processing a group of items in a loop, sometimes it is useful - * to report an error while still allowing the rest of the batch to be - * processed. - * @param {*} exception - */ -goog.async.throwException = function(exception) { - // Each throw needs to be in its own context. - goog.global.setTimeout(function() { throw exception; }, 0); -}; - - -/** - * Fires the provided callbacks as soon as possible after the current JS - * execution context. setTimeout(…, 0) takes at least 4ms when called from - * within another setTimeout(…, 0) for legacy reasons. - * - * This will not schedule the callback as a microtask (i.e. a task that can - * preempt user input or networking callbacks). It is meant to emulate what - * setTimeout(_, 0) would do if it were not throttled. If you desire microtask - * behavior, use {@see goog.Promise} instead. - * - * @param {function(this:SCOPE)} callback Callback function to fire as soon as - * possible. - * @param {SCOPE=} opt_context Object in whose scope to call the listener. - * @param {boolean=} opt_useSetImmediate Avoid the IE workaround that - * ensures correctness at the cost of speed. See comments for details. - * @template SCOPE - */ -goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) { - var cb = callback; - if (opt_context) { - cb = goog.bind(callback, opt_context); - } - cb = goog.async.nextTick.wrapCallback_(cb); - // window.setImmediate was introduced and currently only supported by IE10+, - // but due to a bug in the implementation it is not guaranteed that - // setImmediate is faster than setTimeout nor that setImmediate N is before - // setImmediate N+1. That is why we do not use the native version if - // available. We do, however, call setImmediate if it is a normal function - // because that indicates that it has been replaced by goog.testing.MockClock - // which we do want to support. - // See - // http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10 - // - // Note we do allow callers to also request setImmediate if they are willing - // to accept the possible tradeoffs of incorrectness in exchange for speed. - // The IE fallback of readystate change is much slower. - if (goog.isFunction(goog.global.setImmediate) && - // Opt in. - (opt_useSetImmediate || - // or it isn't a browser or the environment is weird - !goog.global.Window || !goog.global.Window.prototype || - // or something redefined setImmediate in which case we (YOLO) decide - // to use it (This is so that we use the mockClock setImmediate. sigh). - goog.global.Window.prototype.setImmediate != goog.global.setImmediate)) { - goog.global.setImmediate(cb); - return; - } - - // Look for and cache the custom fallback version of setImmediate. - if (!goog.async.nextTick.setImmediate_) { - goog.async.nextTick.setImmediate_ = - goog.async.nextTick.getSetImmediateEmulator_(); - } - goog.async.nextTick.setImmediate_(cb); -}; - - -/** - * Cache for the setImmediate implementation. - * @type {function(function())} - * @private - */ -goog.async.nextTick.setImmediate_; - - -/** - * Determines the best possible implementation to run a function as soon as - * the JS event loop is idle. - * @return {function(function())} The "setImmediate" implementation. - * @private - */ -goog.async.nextTick.getSetImmediateEmulator_ = function() { - // Create a private message channel and use it to postMessage empty messages - // to ourselves. - var Channel = goog.global['MessageChannel']; - // If MessageChannel is not available and we are in a browser, implement - // an iframe based polyfill in browsers that have postMessage and - // document.addEventListener. The latter excludes IE8 because it has a - // synchronous postMessage implementation. - if (typeof Channel === 'undefined' && typeof window !== 'undefined' && - window.postMessage && window.addEventListener && - // Presto (The old pre-blink Opera engine) has problems with iframes - // and contentWindow. - !goog.labs.userAgent.engine.isPresto()) { - /** @constructor */ - Channel = function() { - // Make an empty, invisible iframe. - var iframe = document.createElement(goog.dom.TagName.IFRAME); - iframe.style.display = 'none'; - iframe.src = ''; - document.documentElement.appendChild(iframe); - var win = iframe.contentWindow; - var doc = win.document; - doc.open(); - doc.write(''); - doc.close(); - // Do not post anything sensitive over this channel, as the workaround for - // pages with file: origin could allow that information to be modified or - // intercepted. - var message = 'callImmediate' + Math.random(); - // The same origin policy rejects attempts to postMessage from file: urls - // unless the origin is '*'. - // TODO(b/16335441): Use '*' origin for data: and other similar protocols. - var origin = win.location.protocol == 'file:' ? - '*' : win.location.protocol + '//' + win.location.host; - var onmessage = goog.bind(function(e) { - // Validate origin and message to make sure that this message was - // intended for us. If the origin is set to '*' (see above) only the - // message needs to match since, for example, '*' != 'file://'. Allowing - // the wildcard is ok, as we are not concerned with security here. - if ((origin != '*' && e.origin != origin) || e.data != message) { - return; - } - this['port1'].onmessage(); - }, this); - win.addEventListener('message', onmessage, false); - this['port1'] = {}; - this['port2'] = { - postMessage: function() { - win.postMessage(message, origin); - } - }; - }; - } - if (typeof Channel !== 'undefined' && - (!goog.labs.userAgent.browser.isIE())) { - // Exclude all of IE due to - // http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/ - // which allows starving postMessage with a busy setTimeout loop. - // This currently affects IE10 and IE11 which would otherwise be able - // to use the postMessage based fallbacks. - var channel = new Channel(); - // Use a fifo linked list to call callbacks in the right order. - var head = {}; - var tail = head; - channel['port1'].onmessage = function() { - if (goog.isDef(head.next)) { - head = head.next; - var cb = head.cb; - head.cb = null; - cb(); - } - }; - return function(cb) { - tail.next = { - cb: cb - }; - tail = tail.next; - channel['port2'].postMessage(0); - }; - } - // Implementation for IE6+: Script elements fire an asynchronous - // onreadystatechange event when inserted into the DOM. - if (typeof document !== 'undefined' && 'onreadystatechange' in - document.createElement(goog.dom.TagName.SCRIPT)) { - return function(cb) { - var script = document.createElement(goog.dom.TagName.SCRIPT); - script.onreadystatechange = function() { - // Clean up and call the callback. - script.onreadystatechange = null; - script.parentNode.removeChild(script); - script = null; - cb(); - cb = null; - }; - document.documentElement.appendChild(script); - }; - } - // Fall back to setTimeout with 0. In browsers this creates a delay of 5ms - // or more. - return function(cb) { - goog.global.setTimeout(cb, 0); - }; -}; - - -/** - * Helper function that is overrided to protect callbacks with entry point - * monitor if the application monitors entry points. - * @param {function()} callback Callback function to fire as soon as possible. - * @return {function()} The wrapped callback. - * @private - */ -goog.async.nextTick.wrapCallback_ = goog.functions.identity; - - -// Register the callback function as an entry point, so that it can be -// monitored for exception handling, etc. This has to be done in this file -// since it requires special code to handle all browsers. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.async.nextTick.wrapCallback_ = transformer; - }); - -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview The SafeScript type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ - -goog.provide('goog.html.SafeScript'); - -goog.require('goog.asserts'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - - - -/** - * A string-like object which represents JavaScript code and that carries the - * security type contract that its value, as a string, will not cause execution - * of unconstrained attacker controlled code (XSS) when evaluated as JavaScript - * in a browser. - * - * Instances of this type must be created via the factory method - * {@code goog.html.SafeScript.fromConstant} and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty string - * can be obtained via constructor invocation. - * - * A SafeScript's string representation can safely be interpolated as the - * content of a script element within HTML. The SafeScript string should not be - * escaped before interpolation. - * - * Note that the SafeScript might contain text that is attacker-controlled but - * that text should have been interpolated with appropriate escaping, - * sanitization and/or validation into the right location in the script, such - * that it is highly constrained in its effect (for example, it had to match a - * set of whitelisted words). - * - * A SafeScript can be constructed via security-reviewed unchecked - * conversions. In this case producers of SafeScript must ensure themselves that - * the SafeScript does not contain unsafe script. Note in particular that - * {@code <} is dangerous, even when inside JavaScript strings, and so should - * always be forbidden or JavaScript escaped in user controlled input. For - * example, if {@code </script><script>evil</script>"} were - * interpolated inside a JavaScript string, it would break out of the context - * of the original script element and {@code evil} would execute. Also note - * that within an HTML script (raw text) element, HTML character references, - * such as "<" are not allowed. See - * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements. - * - * @see goog.html.SafeScript#fromConstant - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} - */ -goog.html.SafeScript = function() { - /** - * The contained value of this SafeScript. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeScript#unwrap - * @const - * @private - */ - this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; -}; - - -/** - * @override - * @const - */ -goog.html.SafeScript.prototype.implementsGoogStringTypedString = true; - - -/** - * Type marker for the SafeScript type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private - */ -goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; - - -/** - * Creates a SafeScript object from a compile-time constant string. - * - * @param {!goog.string.Const} script A compile-time-constant string from which - * to create a SafeScript. - * @return {!goog.html.SafeScript} A SafeScript object initialized to - * {@code script}. - */ -goog.html.SafeScript.fromConstant = function(script) { - var scriptString = goog.string.Const.unwrap(script); - if (scriptString.length === 0) { - return goog.html.SafeScript.EMPTY; - } - return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( - scriptString); -}; - - -/** - * Returns this SafeScript's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeScript}, use {@code goog.html.SafeScript.unwrap} instead of - * this method. If in doubt, assume that it's security relevant. In particular, - * note that goog.html functions which return a goog.html type do not guarantee - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> - * - * @see goog.html.SafeScript#unwrap - * @override - */ -goog.html.SafeScript.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeScriptWrappedValue_; -}; - - -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeScript, use - * {@code goog.html.SafeScript.unwrap}. - * - * @see goog.html.SafeScript#unwrap - * @override - */ - goog.html.SafeScript.prototype.toString = function() { - return 'SafeScript{' + - this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}'; - }; -} - - -/** - * Performs a runtime check that the provided object is indeed a - * SafeScript object, and returns its value. - * - * @param {!goog.html.SafeScript} safeScript The object to extract from. - * @return {string} The safeScript object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. - */ -goog.html.SafeScript.unwrap = function(safeScript) { - // Perform additional Run-time type-checking to ensure that - // safeScript is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeScript instanceof goog.html.SafeScript && - safeScript.constructor === goog.html.SafeScript && - safeScript.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_; - } else { - goog.asserts.fail( - 'expected object of type SafeScript, got \'' + safeScript + '\''); - return 'type_error:SafeScript'; - } -}; - - -/** - * Package-internal utility method to create SafeScript instances. - * - * @param {string} script The string to initialize the SafeScript object with. - * @return {!goog.html.SafeScript} The initialized SafeScript object. - * @package - */ -goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse = - function(script) { - return new goog.html.SafeScript().initSecurityPrivateDoNotAccessOrElse_( - script); -}; - - -/** - * Called from createSafeScriptSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} script - * @return {!goog.html.SafeScript} - * @private - */ -goog.html.SafeScript.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( - script) { - this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = script; - return this; -}; - - -/** - * A SafeScript instance corresponding to the empty string. - * @const {!goog.html.SafeScript} - */ -goog.html.SafeScript.EMPTY = - goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(''); - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Unchecked conversions to create values of goog.html types from - * plain strings. Use of these functions could potentially result in instances - * of goog.html types that violate their type contracts, and hence result in - * security vulnerabilties. - * - * Therefore, all uses of the methods herein must be carefully security - * reviewed. Avoid use of the methods in this file whenever possible; instead - * prefer to create instances of goog.html types using inherently safe builders - * or template systems. - * - * - * - * @visibility {//closure/goog/html:approved_for_unchecked_conversion} - * @visibility {//closure/goog/bin/sizetests:__pkg__} - */ - - -goog.provide('goog.html.uncheckedconversions'); - -goog.require('goog.asserts'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeScript'); -goog.require('goog.html.SafeStyle'); -goog.require('goog.html.SafeStyleSheet'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.TrustedResourceUrl'); -goog.require('goog.string'); -goog.require('goog.string.Const'); - - -/** - * Performs an "unchecked conversion" to SafeHtml from a plain string that is - * known to satisfy the SafeHtml type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code html} satisfies the SafeHtml type contract in all - * possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} html A string that is claimed to adhere to the SafeHtml - * contract. - * @param {?goog.i18n.bidi.Dir=} opt_dir The optional directionality of the - * SafeHtml to be constructed. A null or undefined value signifies an - * unknown directionality. - * @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml - * object. - * @suppress {visibility} For access to SafeHtml.create... Note that this - * use is appropriate since this method is intended to be "package private" - * withing goog.html. DO NOT call SafeHtml.create... from outside this - * package; use appropriate wrappers instead. - */ -goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract = - function(justification, html, opt_dir) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - html, opt_dir || null); -}; - - -/** - * Performs an "unchecked conversion" to SafeScript from a plain string that is - * known to satisfy the SafeScript type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code script} satisfies the SafeScript type contract in - * all possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} script The string to wrap as a SafeScript. - * @return {!goog.html.SafeScript} The value of {@code script}, wrapped in a - * SafeScript object. - */ -goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract = - function(justification, script) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmpty(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( - script); -}; - - -/** - * Performs an "unchecked conversion" to SafeStyle from a plain string that is - * known to satisfy the SafeStyle type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code style} satisfies the SafeUrl type contract in all - * possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} style The string to wrap as a SafeStyle. - * @return {!goog.html.SafeStyle} The value of {@code style}, wrapped in a - * SafeStyle object. - */ -goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract = - function(justification, style) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - style); -}; - - -/** - * Performs an "unchecked conversion" to SafeStyleSheet from a plain string - * that is known to satisfy the SafeStyleSheet type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code styleSheet} satisfies the SafeUrl type contract in - * all possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} styleSheet The string to wrap as a SafeStyleSheet. - * @return {!goog.html.SafeStyleSheet} The value of {@code styleSheet}, wrapped - * in a SafeStyleSheet object. - */ -goog.html.uncheckedconversions. - safeStyleSheetFromStringKnownToSatisfyTypeContract = - function(justification, styleSheet) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeStyleSheet. - createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet); -}; - - -/** - * Performs an "unchecked conversion" to SafeUrl from a plain string that is - * known to satisfy the SafeUrl type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code url} satisfies the SafeUrl type contract in all - * possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} url The string to wrap as a SafeUrl. - * @return {!goog.html.SafeUrl} The value of {@code url}, wrapped in a SafeUrl - * object. - */ -goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract = - function(justification, url) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); -}; - - -/** - * Performs an "unchecked conversion" to TrustedResourceUrl from a plain string - * that is known to satisfy the TrustedResourceUrl type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code url} satisfies the TrustedResourceUrl type contract - * in all possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} url The string to wrap as a TrustedResourceUrl. - * @return {!goog.html.TrustedResourceUrl} The value of {@code url}, wrapped in - * a TrustedResourceUrl object. - */ -goog.html.uncheckedconversions. - trustedResourceUrlFromStringKnownToSatisfyTypeContract = - function(justification, url) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.TrustedResourceUrl. - createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Generics method for collection-like classes and objects. - * - * @author arv@google.com (Erik Arvidsson) - * - * This file contains functions to work with collections. It supports using - * Map, Set, Array and Object and other classes that implement collection-like - * methods. - */ - - -goog.provide('goog.structs'); - -goog.require('goog.array'); -goog.require('goog.object'); - - -// We treat an object as a dictionary if it has getKeys or it is an object that -// isn't arrayLike. - - -/** - * Returns the number of values in the collection-like object. - * @param {Object} col The collection-like object. - * @return {number} The number of values in the collection-like object. - */ -goog.structs.getCount = function(col) { - if (typeof col.getCount == 'function') { - return col.getCount(); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return col.length; - } - return goog.object.getCount(col); -}; - - -/** - * Returns the values of the collection-like object. - * @param {Object} col The collection-like object. - * @return {!Array<?>} The values in the collection-like object. - */ -goog.structs.getValues = function(col) { - if (typeof col.getValues == 'function') { - return col.getValues(); - } - if (goog.isString(col)) { - return col.split(''); - } - if (goog.isArrayLike(col)) { - var rv = []; - var l = col.length; - for (var i = 0; i < l; i++) { - rv.push(col[i]); - } - return rv; - } - return goog.object.getValues(col); -}; - - -/** - * Returns the keys of the collection. Some collections have no notion of - * keys/indexes and this function will return undefined in those cases. - * @param {Object} col The collection-like object. - * @return {!Array|undefined} The keys in the collection. - */ -goog.structs.getKeys = function(col) { - if (typeof col.getKeys == 'function') { - return col.getKeys(); - } - // if we have getValues but no getKeys we know this is a key-less collection - if (typeof col.getValues == 'function') { - return undefined; - } - if (goog.isArrayLike(col) || goog.isString(col)) { - var rv = []; - var l = col.length; - for (var i = 0; i < l; i++) { - rv.push(i); - } - return rv; - } - - return goog.object.getKeys(col); -}; - - -/** - * Whether the collection contains the given value. This is O(n) and uses - * equals (==) to test the existence. - * @param {Object} col The collection-like object. - * @param {*} val The value to check for. - * @return {boolean} True if the map contains the value. - */ -goog.structs.contains = function(col, val) { - if (typeof col.contains == 'function') { - return col.contains(val); - } - if (typeof col.containsValue == 'function') { - return col.containsValue(val); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.contains(/** @type {!Array<?>} */ (col), val); - } - return goog.object.containsValue(col, val); -}; - - -/** - * Whether the collection is empty. - * @param {Object} col The collection-like object. - * @return {boolean} True if empty. - */ -goog.structs.isEmpty = function(col) { - if (typeof col.isEmpty == 'function') { - return col.isEmpty(); - } - - // We do not use goog.string.isEmptyOrWhitespace because here we treat the string as - // collection and as such even whitespace matters - - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.isEmpty(/** @type {!Array<?>} */ (col)); - } - return goog.object.isEmpty(col); -}; - - -/** - * Removes all the elements from the collection. - * @param {Object} col The collection-like object. - */ -goog.structs.clear = function(col) { - // NOTE(arv): This should not contain strings because strings are immutable - if (typeof col.clear == 'function') { - col.clear(); - } else if (goog.isArrayLike(col)) { - goog.array.clear(/** @type {goog.array.ArrayLike} */ (col)); - } else { - goog.object.clear(col); - } -}; - - -/** - * Calls a function for each value in a collection. The function takes - * three arguments; the value, the key and the collection. - * - * NOTE: This will be deprecated soon! Please use a more specific method if - * possible, e.g. goog.array.forEach, goog.object.forEach, etc. - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):?} f The function to call for every value. - * This function takes - * 3 arguments (the value, the key or undefined if the collection has no - * notion of keys, and the collection) and the return value is irrelevant. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @template T,S - */ -goog.structs.forEach = function(col, f, opt_obj) { - if (typeof col.forEach == 'function') { - col.forEach(f, opt_obj); - } else if (goog.isArrayLike(col) || goog.isString(col)) { - goog.array.forEach(/** @type {!Array<?>} */ (col), f, opt_obj); - } else { - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - f.call(opt_obj, values[i], keys && keys[i], col); - } - } -}; - - -/** - * Calls a function for every value in the collection. When a call returns true, - * adds the value to a new collection (Array is returned by default). - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):boolean} f The function to call for every - * value. This function takes - * 3 arguments (the value, the key or undefined if the collection has no - * notion of keys, and the collection) and should return a Boolean. If the - * return value is true the value is added to the result collection. If it - * is false the value is not included. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {!Object|!Array<?>} A new collection where the passed values are - * present. If col is a key-less collection an array is returned. If col - * has keys and values a plain old JS object is returned. - * @template T,S - */ -goog.structs.filter = function(col, f, opt_obj) { - if (typeof col.filter == 'function') { - return col.filter(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.filter(/** @type {!Array<?>} */ (col), f, opt_obj); - } - - var rv; - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - if (keys) { - rv = {}; - for (var i = 0; i < l; i++) { - if (f.call(opt_obj, values[i], keys[i], col)) { - rv[keys[i]] = values[i]; - } - } - } else { - // We should not use goog.array.filter here since we want to make sure that - // the index is undefined as well as make sure that col is passed to the - // function. - rv = []; - for (var i = 0; i < l; i++) { - if (f.call(opt_obj, values[i], undefined, col)) { - rv.push(values[i]); - } - } - } - return rv; -}; - - -/** - * Calls a function for every value in the collection and adds the result into a - * new collection (defaults to creating a new Array). - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):V} f The function to call for every value. - * This function takes 3 arguments (the value, the key or undefined if the - * collection has no notion of keys, and the collection) and should return - * something. The result will be used as the value in the new collection. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {!Object<V>|!Array<V>} A new collection with the new values. If - * col is a key-less collection an array is returned. If col has keys and - * values a plain old JS object is returned. - * @template T,S,V - */ -goog.structs.map = function(col, f, opt_obj) { - if (typeof col.map == 'function') { - return col.map(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.map(/** @type {!Array<?>} */ (col), f, opt_obj); - } - - var rv; - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - if (keys) { - rv = {}; - for (var i = 0; i < l; i++) { - rv[keys[i]] = f.call(opt_obj, values[i], keys[i], col); - } - } else { - // We should not use goog.array.map here since we want to make sure that - // the index is undefined as well as make sure that col is passed to the - // function. - rv = []; - for (var i = 0; i < l; i++) { - rv[i] = f.call(opt_obj, values[i], undefined, col); - } - } - return rv; -}; - - -/** - * Calls f for each value in a collection. If any call returns true this returns - * true (without checking the rest). If all returns false this returns false. - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):boolean} f The function to call for every - * value. This function takes 3 arguments (the value, the key or undefined - * if the collection has no notion of keys, and the collection) and should - * return a boolean. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {boolean} True if any value passes the test. - * @template T,S - */ -goog.structs.some = function(col, f, opt_obj) { - if (typeof col.some == 'function') { - return col.some(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.some(/** @type {!Array<?>} */ (col), f, opt_obj); - } - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - if (f.call(opt_obj, values[i], keys && keys[i], col)) { - return true; - } - } - return false; -}; - - -/** - * Calls f for each value in a collection. If all calls return true this return - * true this returns true. If any returns false this returns false at this point - * and does not continue to check the remaining values. - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):boolean} f The function to call for every - * value. This function takes 3 arguments (the value, the key or - * undefined if the collection has no notion of keys, and the collection) - * and should return a boolean. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {boolean} True if all key-value pairs pass the test. - * @template T,S - */ -goog.structs.every = function(col, f, opt_obj) { - if (typeof col.every == 'function') { - return col.every(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.every(/** @type {!Array<?>} */ (col), f, opt_obj); - } - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - if (!f.call(opt_obj, values[i], keys && keys[i], col)) { - return false; - } - } - return true; -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Defines the collection interface. - * - * @author nnaze@google.com (Nathan Naze) - */ - -goog.provide('goog.structs.Collection'); - - - -/** - * An interface for a collection of values. - * @interface - * @template T - */ -goog.structs.Collection = function() {}; - - -/** - * @param {T} value Value to add to the collection. - */ -goog.structs.Collection.prototype.add; - - -/** - * @param {T} value Value to remove from the collection. - */ -goog.structs.Collection.prototype.remove; - - -/** - * @param {T} value Value to find in the collection. - * @return {boolean} Whether the collection contains the specified value. - */ -goog.structs.Collection.prototype.contains; - - -/** - * @return {number} The number of values stored in the collection. - */ -goog.structs.Collection.prototype.getCount; - - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Python style iteration utilities. - * @author arv@google.com (Erik Arvidsson) - */ - - -goog.provide('goog.iter'); -goog.provide('goog.iter.Iterable'); -goog.provide('goog.iter.Iterator'); -goog.provide('goog.iter.StopIteration'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.math'); - - -/** - * @typedef {goog.iter.Iterator|{length:number}|{__iterator__}} - */ -goog.iter.Iterable; - - -/** - * Singleton Error object that is used to terminate iterations. - * @const {!Error} - */ -goog.iter.StopIteration = ('StopIteration' in goog.global) ? - // For script engines that support legacy iterators. - goog.global['StopIteration'] : - { message: 'StopIteration', stack: ''}; - - - -/** - * Class/interface for iterators. An iterator needs to implement a {@code next} - * method and it needs to throw a {@code goog.iter.StopIteration} when the - * iteration passes beyond the end. Iterators have no {@code hasNext} method. - * It is recommended to always use the helper functions to iterate over the - * iterator or in case you are only targeting JavaScript 1.7 for in loops. - * @constructor - * @template VALUE - */ -goog.iter.Iterator = function() {}; - - -/** - * Returns the next value of the iteration. This will throw the object - * {@see goog.iter#StopIteration} when the iteration passes the end. - * @return {VALUE} Any object or value. - */ -goog.iter.Iterator.prototype.next = function() { - throw goog.iter.StopIteration; -}; - - -/** - * Returns the {@code Iterator} object itself. This is used to implement - * the iterator protocol in JavaScript 1.7 - * @param {boolean=} opt_keys Whether to return the keys or values. Default is - * to only return the values. This is being used by the for-in loop (true) - * and the for-each-in loop (false). Even though the param gives a hint - * about what the iterator will return there is no guarantee that it will - * return the keys when true is passed. - * @return {!goog.iter.Iterator<VALUE>} The object itself. - */ -goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) { - return this; -}; - - -/** - * Returns an iterator that knows how to iterate over the values in the object. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable If the - * object is an iterator it will be returned as is. If the object has an - * {@code __iterator__} method that will be called to get the value - * iterator. If the object is an array-like object we create an iterator - * for that. - * @return {!goog.iter.Iterator<VALUE>} An iterator that knows how to iterate - * over the values in {@code iterable}. - * @template VALUE - */ -goog.iter.toIterator = function(iterable) { - if (iterable instanceof goog.iter.Iterator) { - return iterable; - } - if (typeof iterable.__iterator__ == 'function') { - return iterable.__iterator__(false); - } - if (goog.isArrayLike(iterable)) { - var i = 0; - var newIter = new goog.iter.Iterator; - newIter.next = function() { - while (true) { - if (i >= iterable.length) { - throw goog.iter.StopIteration; - } - // Don't include deleted elements. - if (!(i in iterable)) { - i++; - continue; - } - return iterable[i++]; - } - }; - return newIter; - } - - - // TODO(arv): Should we fall back on goog.structs.getValues()? - throw Error('Not implemented'); -}; - - -/** - * Calls a function for each element in the iterator with the element of the - * iterator passed as argument. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. If the iterable is an object {@code toIterator} will be - * called on it. - * @param {function(this:THIS,VALUE,?,!goog.iter.Iterator<VALUE>)} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and the return value is - * irrelevant. The reason for passing undefined as the second argument is - * so that the same function can be used in {@see goog.array#forEach} as - * well as others. The third parameter is of type "number" for - * arraylike objects, undefined, otherwise. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @template THIS, VALUE - */ -goog.iter.forEach = function(iterable, f, opt_obj) { - if (goog.isArrayLike(iterable)) { - /** @preserveTry */ - try { - // NOTES: this passes the index number to the second parameter - // of the callback contrary to the documentation above. - goog.array.forEach(/** @type {goog.array.ArrayLike} */(iterable), f, - opt_obj); - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - } else { - iterable = goog.iter.toIterator(iterable); - /** @preserveTry */ - try { - while (true) { - f.call(opt_obj, iterable.next(), undefined, iterable); - } - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - } -}; - - -/** - * Calls a function for every element in the iterator, and if the function - * returns true adds the element to a new iterator. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and should return a boolean. - * If the return value is true the element will be included in the returned - * iterator. If it is false the element is not included. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements - * that passed the test are present. - * @template THIS, VALUE - */ -goog.iter.filter = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var newIter = new goog.iter.Iterator; - newIter.next = function() { - while (true) { - var val = iterator.next(); - if (f.call(opt_obj, val, undefined, iterator)) { - return val; - } - } - }; - return newIter; -}; - - -/** - * Calls a function for every element in the iterator, and if the function - * returns false adds the element to a new iterator. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and should return a boolean. - * If the return value is false the element will be included in the returned - * iterator. If it is true the element is not included. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements - * that did not pass the test are present. - * @template THIS, VALUE - */ -goog.iter.filterFalse = function(iterable, f, opt_obj) { - return goog.iter.filter(iterable, goog.functions.not(f), opt_obj); -}; - - -/** - * Creates a new iterator that returns the values in a range. This function - * can take 1, 2 or 3 arguments: - * <pre> - * range(5) same as range(0, 5, 1) - * range(2, 5) same as range(2, 5, 1) - * </pre> - * - * @param {number} startOrStop The stop value if only one argument is provided. - * The start value if 2 or more arguments are provided. If only one - * argument is used the start value is 0. - * @param {number=} opt_stop The stop value. If left out then the first - * argument is used as the stop value. - * @param {number=} opt_step The number to increment with between each call to - * next. This can be negative. - * @return {!goog.iter.Iterator<number>} A new iterator that returns the values - * in the range. - */ -goog.iter.range = function(startOrStop, opt_stop, opt_step) { - var start = 0; - var stop = startOrStop; - var step = opt_step || 1; - if (arguments.length > 1) { - start = startOrStop; - stop = opt_stop; - } - if (step == 0) { - throw Error('Range step argument must not be zero'); - } - - var newIter = new goog.iter.Iterator; - newIter.next = function() { - if (step > 0 && start >= stop || step < 0 && start <= stop) { - throw goog.iter.StopIteration; - } - var rv = start; - start += step; - return rv; - }; - return newIter; -}; - - -/** - * Joins the values in a iterator with a delimiter. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to get the values from. - * @param {string} deliminator The text to put between the values. - * @return {string} The joined value string. - * @template VALUE - */ -goog.iter.join = function(iterable, deliminator) { - return goog.iter.toArray(iterable).join(deliminator); -}; - - -/** - * For every element in the iterator call a function and return a new iterator - * with that value. - * - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterator to iterate over. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):RESULT} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and should return a new value. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the - * results of applying the function to each element in the original - * iterator. - * @template THIS, VALUE, RESULT - */ -goog.iter.map = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var newIter = new goog.iter.Iterator; - newIter.next = function() { - var val = iterator.next(); - return f.call(opt_obj, val, undefined, iterator); - }; - return newIter; -}; - - -/** - * Passes every element of an iterator into a function and accumulates the - * result. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. - * @param {function(this:THIS,VALUE,VALUE):VALUE} f The function to call for - * every element. This function takes 2 arguments (the function's previous - * result or the initial value, and the value of the current element). - * function(previousValue, currentElement) : newValue. - * @param {VALUE} val The initial value to pass into the function on the first - * call. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * f. - * @return {VALUE} Result of evaluating f repeatedly across the values of - * the iterator. - * @template THIS, VALUE - */ -goog.iter.reduce = function(iterable, f, val, opt_obj) { - var rval = val; - goog.iter.forEach(iterable, function(val) { - rval = f.call(opt_obj, rval, val); - }); - return rval; -}; - - -/** - * Goes through the values in the iterator. Calls f for each of these, and if - * any of them returns true, this returns true (without checking the rest). If - * all return false this will return false. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {boolean} true if any value passes the test. - * @template THIS, VALUE - */ -goog.iter.some = function(iterable, f, opt_obj) { - iterable = goog.iter.toIterator(iterable); - /** @preserveTry */ - try { - while (true) { - if (f.call(opt_obj, iterable.next(), undefined, iterable)) { - return true; - } - } - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - return false; -}; - - -/** - * Goes through the values in the iterator. Calls f for each of these and if any - * of them returns false this returns false (without checking the rest). If all - * return true this will return true. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {boolean} true if every value passes the test. - * @template THIS, VALUE - */ -goog.iter.every = function(iterable, f, opt_obj) { - iterable = goog.iter.toIterator(iterable); - /** @preserveTry */ - try { - while (true) { - if (!f.call(opt_obj, iterable.next(), undefined, iterable)) { - return false; - } - } - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - return true; -}; - - -/** - * Takes zero or more iterables and returns one iterator that will iterate over - * them in the order chained. - * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any - * number of iterable objects. - * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will - * iterate over all the given iterables' contents. - * @template VALUE - */ -goog.iter.chain = function(var_args) { - return goog.iter.chainFromIterable(arguments); -}; - - -/** - * Takes a single iterable containing zero or more iterables and returns one - * iterator that will iterate over each one in the order given. - * @see http://docs.python.org/2/library/itertools.html#itertools.chain.from_iterable - * @param {goog.iter.Iterable} iterable The iterable of iterables to chain. - * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will - * iterate over all the contents of the iterables contained within - * {@code iterable}. - * @template VALUE - */ -goog.iter.chainFromIterable = function(iterable) { - var iterator = goog.iter.toIterator(iterable); - var iter = new goog.iter.Iterator(); - var current = null; - - iter.next = function() { - while (true) { - if (current == null) { - var it = iterator.next(); - current = goog.iter.toIterator(it); - } - try { - return current.next(); - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - current = null; - } - } - }; - - return iter; -}; - - -/** - * Builds a new iterator that iterates over the original, but skips elements as - * long as a supplied function returns true. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that drops elements from - * the original iterator as long as {@code f} is true. - * @template THIS, VALUE - */ -goog.iter.dropWhile = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var newIter = new goog.iter.Iterator; - var dropping = true; - newIter.next = function() { - while (true) { - var val = iterator.next(); - if (dropping && f.call(opt_obj, val, undefined, iterator)) { - continue; - } else { - dropping = false; - } - return val; - } - }; - return newIter; -}; - - -/** - * Builds a new iterator that iterates over the original, but only as long as a - * supplied function returns true. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj This is used as the 'this' object in f when called. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that keeps elements in - * the original iterator as long as the function is true. - * @template THIS, VALUE - */ -goog.iter.takeWhile = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var iter = new goog.iter.Iterator(); - iter.next = function() { - var val = iterator.next(); - if (f.call(opt_obj, val, undefined, iterator)) { - return val; - } - throw goog.iter.StopIteration; - }; - return iter; -}; - - -/** - * Converts the iterator to an array - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to convert to an array. - * @return {!Array<VALUE>} An array of the elements the iterator iterates over. - * @template VALUE - */ -goog.iter.toArray = function(iterable) { - // Fast path for array-like. - if (goog.isArrayLike(iterable)) { - return goog.array.toArray(/** @type {!goog.array.ArrayLike} */(iterable)); - } - iterable = goog.iter.toIterator(iterable); - var array = []; - goog.iter.forEach(iterable, function(val) { - array.push(val); - }); - return array; -}; - - -/** - * Iterates over two iterables and returns true if they contain the same - * sequence of elements and have the same length. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable1 The first - * iterable object. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable2 The second - * iterable object. - * @param {function(VALUE,VALUE):boolean=} opt_equalsFn Optional comparison - * function. - * Should take two arguments to compare, and return true if the arguments - * are equal. Defaults to {@link goog.array.defaultCompareEquality} which - * compares the elements using the built-in '===' operator. - * @return {boolean} true if the iterables contain the same sequence of elements - * and have the same length. - * @template VALUE - */ -goog.iter.equals = function(iterable1, iterable2, opt_equalsFn) { - var fillValue = {}; - var pairs = goog.iter.zipLongest(fillValue, iterable1, iterable2); - var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality; - return goog.iter.every(pairs, function(pair) { - return equalsFn(pair[0], pair[1]); - }); -}; - - -/** - * Advances the iterator to the next position, returning the given default value - * instead of throwing an exception if the iterator has no more entries. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterable - * object. - * @param {VALUE} defaultValue The value to return if the iterator is empty. - * @return {VALUE} The next item in the iteration, or defaultValue if the - * iterator was empty. - * @template VALUE - */ -goog.iter.nextOrValue = function(iterable, defaultValue) { - try { - return goog.iter.toIterator(iterable).next(); - } catch (e) { - if (e != goog.iter.StopIteration) { - throw e; - } - return defaultValue; - } -}; - - -/** - * Cartesian product of zero or more sets. Gives an iterator that gives every - * combination of one element chosen from each set. For example, - * ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]). - * @see http://docs.python.org/library/itertools.html#itertools.product - * @param {...!goog.array.ArrayLike<VALUE>} var_args Zero or more sets, as - * arrays. - * @return {!goog.iter.Iterator<!Array<VALUE>>} An iterator that gives each - * n-tuple (as an array). - * @template VALUE - */ -goog.iter.product = function(var_args) { - var someArrayEmpty = goog.array.some(arguments, function(arr) { - return !arr.length; - }); - - // An empty set in a cartesian product gives an empty set. - if (someArrayEmpty || !arguments.length) { - return new goog.iter.Iterator(); - } - - var iter = new goog.iter.Iterator(); - var arrays = arguments; - - // The first indices are [0, 0, ...] - var indicies = goog.array.repeat(0, arrays.length); - - iter.next = function() { - - if (indicies) { - var retVal = goog.array.map(indicies, function(valueIndex, arrayIndex) { - return arrays[arrayIndex][valueIndex]; - }); - - // Generate the next-largest indices for the next call. - // Increase the rightmost index. If it goes over, increase the next - // rightmost (like carry-over addition). - for (var i = indicies.length - 1; i >= 0; i--) { - // Assertion prevents compiler warning below. - goog.asserts.assert(indicies); - if (indicies[i] < arrays[i].length - 1) { - indicies[i]++; - break; - } - - // We're at the last indices (the last element of every array), so - // the iteration is over on the next call. - if (i == 0) { - indicies = null; - break; - } - // Reset the index in this column and loop back to increment the - // next one. - indicies[i] = 0; - } - return retVal; - } - - throw goog.iter.StopIteration; - }; - - return iter; -}; - - -/** - * Create an iterator to cycle over the iterable's elements indefinitely. - * For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ... - * @see: http://docs.python.org/library/itertools.html#itertools.cycle. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable object. - * @return {!goog.iter.Iterator<VALUE>} An iterator that iterates indefinitely - * over the values in {@code iterable}. - * @template VALUE - */ -goog.iter.cycle = function(iterable) { - var baseIterator = goog.iter.toIterator(iterable); - - // We maintain a cache to store the iterable elements as we iterate - // over them. The cache is used to return elements once we have - // iterated over the iterable once. - var cache = []; - var cacheIndex = 0; - - var iter = new goog.iter.Iterator(); - - // This flag is set after the iterable is iterated over once - var useCache = false; - - iter.next = function() { - var returnElement = null; - - // Pull elements off the original iterator if not using cache - if (!useCache) { - try { - // Return the element from the iterable - returnElement = baseIterator.next(); - cache.push(returnElement); - return returnElement; - } catch (e) { - // If an exception other than StopIteration is thrown - // or if there are no elements to iterate over (the iterable was empty) - // throw an exception - if (e != goog.iter.StopIteration || goog.array.isEmpty(cache)) { - throw e; - } - // set useCache to true after we know that a 'StopIteration' exception - // was thrown and the cache is not empty (to handle the 'empty iterable' - // use case) - useCache = true; - } - } - - returnElement = cache[cacheIndex]; - cacheIndex = (cacheIndex + 1) % cache.length; - - return returnElement; - }; - - return iter; -}; - - -/** - * Creates an iterator that counts indefinitely from a starting value. - * @see http://docs.python.org/2/library/itertools.html#itertools.count - * @param {number=} opt_start The starting value. Default is 0. - * @param {number=} opt_step The number to increment with between each call to - * next. Negative and floating point numbers are allowed. Default is 1. - * @return {!goog.iter.Iterator<number>} A new iterator that returns the values - * in the series. - */ -goog.iter.count = function(opt_start, opt_step) { - var counter = opt_start || 0; - var step = goog.isDef(opt_step) ? opt_step : 1; - var iter = new goog.iter.Iterator(); - - iter.next = function() { - var returnValue = counter; - counter += step; - return returnValue; - }; - - return iter; -}; - - -/** - * Creates an iterator that returns the same object or value repeatedly. - * @param {VALUE} value Any object or value to repeat. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the - * repeated value. - * @template VALUE - */ -goog.iter.repeat = function(value) { - var iter = new goog.iter.Iterator(); - - iter.next = goog.functions.constant(value); - - return iter; -}; - - -/** - * Creates an iterator that returns running totals from the numbers in - * {@code iterable}. For example, the array {@code [1, 2, 3, 4, 5]} yields - * {@code 1 -> 3 -> 6 -> 10 -> 15}. - * @see http://docs.python.org/3.2/library/itertools.html#itertools.accumulate - * @param {!goog.iter.Iterable<number>} iterable The iterable of numbers to - * accumulate. - * @return {!goog.iter.Iterator<number>} A new iterator that returns the - * numbers in the series. - */ -goog.iter.accumulate = function(iterable) { - var iterator = goog.iter.toIterator(iterable); - var total = 0; - var iter = new goog.iter.Iterator(); - - iter.next = function() { - total += iterator.next(); - return total; - }; - - return iter; -}; - - -/** - * Creates an iterator that returns arrays containing the ith elements from the - * provided iterables. The returned arrays will be the same size as the number - * of iterables given in {@code var_args}. Once the shortest iterable is - * exhausted, subsequent calls to {@code next()} will throw - * {@code goog.iter.StopIteration}. - * @see http://docs.python.org/2/library/itertools.html#itertools.izip - * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any - * number of iterable objects. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns - * arrays of elements from the provided iterables. - * @template VALUE - */ -goog.iter.zip = function(var_args) { - var args = arguments; - var iter = new goog.iter.Iterator(); - - if (args.length > 0) { - var iterators = goog.array.map(args, goog.iter.toIterator); - iter.next = function() { - var arr = goog.array.map(iterators, function(it) { - return it.next(); - }); - return arr; - }; - } - - return iter; -}; - - -/** - * Creates an iterator that returns arrays containing the ith elements from the - * provided iterables. The returned arrays will be the same size as the number - * of iterables given in {@code var_args}. Shorter iterables will be extended - * with {@code fillValue}. Once the longest iterable is exhausted, subsequent - * calls to {@code next()} will throw {@code goog.iter.StopIteration}. - * @see http://docs.python.org/2/library/itertools.html#itertools.izip_longest - * @param {VALUE} fillValue The object or value used to fill shorter iterables. - * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any - * number of iterable objects. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns - * arrays of elements from the provided iterables. - * @template VALUE - */ -goog.iter.zipLongest = function(fillValue, var_args) { - var args = goog.array.slice(arguments, 1); - var iter = new goog.iter.Iterator(); - - if (args.length > 0) { - var iterators = goog.array.map(args, goog.iter.toIterator); - - iter.next = function() { - var iteratorsHaveValues = false; // false when all iterators are empty. - var arr = goog.array.map(iterators, function(it) { - var returnValue; - try { - returnValue = it.next(); - // Iterator had a value, so we've not exhausted the iterators. - // Set flag accordingly. - iteratorsHaveValues = true; - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - returnValue = fillValue; - } - return returnValue; - }); - - if (!iteratorsHaveValues) { - throw goog.iter.StopIteration; - } - return arr; - }; - } - - return iter; -}; - - -/** - * Creates an iterator that filters {@code iterable} based on a series of - * {@code selectors}. On each call to {@code next()}, one item is taken from - * both the {@code iterable} and {@code selectors} iterators. If the item from - * {@code selectors} evaluates to true, the item from {@code iterable} is given. - * Otherwise, it is skipped. Once either {@code iterable} or {@code selectors} - * is exhausted, subsequent calls to {@code next()} will throw - * {@code goog.iter.StopIteration}. - * @see http://docs.python.org/2/library/itertools.html#itertools.compress - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to filter. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} selectors An - * iterable of items to be evaluated in a boolean context to determine if - * the corresponding element in {@code iterable} should be included in the - * result. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the - * filtered values. - * @template VALUE - */ -goog.iter.compress = function(iterable, selectors) { - var selectorIterator = goog.iter.toIterator(selectors); - - return goog.iter.filter(iterable, function() { - return !!selectorIterator.next(); - }); -}; - - - -/** - * Implements the {@code goog.iter.groupBy} iterator. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to group. - * @param {function(...VALUE): KEY=} opt_keyFunc Optional function for - * determining the key value for each group in the {@code iterable}. Default - * is the identity function. - * @constructor - * @extends {goog.iter.Iterator<!Array<?>>} - * @template KEY, VALUE - * @private - */ -goog.iter.GroupByIterator_ = function(iterable, opt_keyFunc) { - - /** - * The iterable to group, coerced to an iterator. - * @type {!goog.iter.Iterator} - */ - this.iterator = goog.iter.toIterator(iterable); - - /** - * A function for determining the key value for each element in the iterable. - * If no function is provided, the identity function is used and returns the - * element unchanged. - * @type {function(...VALUE): KEY} - */ - this.keyFunc = opt_keyFunc || goog.functions.identity; - - /** - * The target key for determining the start of a group. - * @type {KEY} - */ - this.targetKey; - - /** - * The current key visited during iteration. - * @type {KEY} - */ - this.currentKey; - - /** - * The current value being added to the group. - * @type {VALUE} - */ - this.currentValue; -}; -goog.inherits(goog.iter.GroupByIterator_, goog.iter.Iterator); - - -/** @override */ -goog.iter.GroupByIterator_.prototype.next = function() { - while (this.currentKey == this.targetKey) { - this.currentValue = this.iterator.next(); // Exits on StopIteration - this.currentKey = this.keyFunc(this.currentValue); - } - this.targetKey = this.currentKey; - return [this.currentKey, this.groupItems_(this.targetKey)]; -}; - - -/** - * Performs the grouping of objects using the given key. - * @param {KEY} targetKey The target key object for the group. - * @return {!Array<VALUE>} An array of grouped objects. - * @private - */ -goog.iter.GroupByIterator_.prototype.groupItems_ = function(targetKey) { - var arr = []; - while (this.currentKey == targetKey) { - arr.push(this.currentValue); - try { - this.currentValue = this.iterator.next(); - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - break; - } - this.currentKey = this.keyFunc(this.currentValue); - } - return arr; -}; - - -/** - * Creates an iterator that returns arrays containing elements from the - * {@code iterable} grouped by a key value. For iterables with repeated - * elements (i.e. sorted according to a particular key function), this function - * has a {@code uniq}-like effect. For example, grouping the array: - * {@code [A, B, B, C, C, A]} produces - * {@code [A, [A]], [B, [B, B]], [C, [C, C]], [A, [A]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.groupby - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to group. - * @param {function(...VALUE): KEY=} opt_keyFunc Optional function for - * determining the key value for each group in the {@code iterable}. Default - * is the identity function. - * @return {!goog.iter.Iterator<!Array<?>>} A new iterator that returns - * arrays of consecutive key and groups. - * @template KEY, VALUE - */ -goog.iter.groupBy = function(iterable, opt_keyFunc) { - return new goog.iter.GroupByIterator_(iterable, opt_keyFunc); -}; - - -/** - * Gives an iterator that gives the result of calling the given function - * <code>f</code> with the arguments taken from the next element from - * <code>iterable</code> (the elements are expected to also be iterables). - * - * Similar to {@see goog.iter#map} but allows the function to accept multiple - * arguments from the iterable. - * - * @param {!goog.iter.Iterable<!goog.iter.Iterable>} iterable The iterable of - * iterables to iterate over. - * @param {function(this:THIS,...*):RESULT} f The function to call for every - * element. This function takes N+2 arguments, where N represents the - * number of items from the next element of the iterable. The two - * additional arguments passed to the function are undefined and the - * iterator itself. The function should return a new value. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the - * results of applying the function to each element in the original - * iterator. - * @template THIS, RESULT - */ -goog.iter.starMap = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var iter = new goog.iter.Iterator(); - - iter.next = function() { - var args = goog.iter.toArray(iterator.next()); - return f.apply(opt_obj, goog.array.concat(args, undefined, iterator)); - }; - - return iter; -}; - - -/** - * Returns an array of iterators each of which can iterate over the values in - * {@code iterable} without advancing the others. - * @see http://docs.python.org/2/library/itertools.html#itertools.tee - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to tee. - * @param {number=} opt_num The number of iterators to create. Default is 2. - * @return {!Array<goog.iter.Iterator<VALUE>>} An array of iterators. - * @template VALUE - */ -goog.iter.tee = function(iterable, opt_num) { - var iterator = goog.iter.toIterator(iterable); - var num = goog.isNumber(opt_num) ? opt_num : 2; - var buffers = goog.array.map(goog.array.range(num), function() { - return []; - }); - - var addNextIteratorValueToBuffers = function() { - var val = iterator.next(); - goog.array.forEach(buffers, function(buffer) { - buffer.push(val); - }); - }; - - var createIterator = function(buffer) { - // Each tee'd iterator has an associated buffer (initially empty). When a - // tee'd iterator's buffer is empty, it calls - // addNextIteratorValueToBuffers(), adding the next value to all tee'd - // iterators' buffers, and then returns that value. This allows each - // iterator to be advanced independently. - var iter = new goog.iter.Iterator(); - - iter.next = function() { - if (goog.array.isEmpty(buffer)) { - addNextIteratorValueToBuffers(); - } - goog.asserts.assert(!goog.array.isEmpty(buffer)); - return buffer.shift(); - }; - - return iter; - }; - - return goog.array.map(buffers, createIterator); -}; - - -/** - * Creates an iterator that returns arrays containing a count and an element - * obtained from the given {@code iterable}. - * @see http://docs.python.org/2/library/functions.html#enumerate - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to enumerate. - * @param {number=} opt_start Optional starting value. Default is 0. - * @return {!goog.iter.Iterator<!Array<?>>} A new iterator containing - * count/item pairs. - * @template VALUE - */ -goog.iter.enumerate = function(iterable, opt_start) { - return goog.iter.zip(goog.iter.count(opt_start), iterable); -}; - - -/** - * Creates an iterator that returns the first {@code limitSize} elements from an - * iterable. If this number is greater than the number of elements in the - * iterable, all the elements are returned. - * @see http://goo.gl/V0sihp Inspired by the limit iterator in Guava. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to limit. - * @param {number} limitSize The maximum number of elements to return. - * @return {!goog.iter.Iterator<VALUE>} A new iterator containing - * {@code limitSize} elements. - * @template VALUE - */ -goog.iter.limit = function(iterable, limitSize) { - goog.asserts.assert(goog.math.isInt(limitSize) && limitSize >= 0); - - var iterator = goog.iter.toIterator(iterable); - - var iter = new goog.iter.Iterator(); - var remaining = limitSize; - - iter.next = function() { - if (remaining-- > 0) { - return iterator.next(); - } - throw goog.iter.StopIteration; - }; - - return iter; -}; - - -/** - * Creates an iterator that is advanced {@code count} steps ahead. Consumed - * values are silently discarded. If {@code count} is greater than the number - * of elements in {@code iterable}, an empty iterator is returned. Subsequent - * calls to {@code next()} will throw {@code goog.iter.StopIteration}. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to consume. - * @param {number} count The number of elements to consume from the iterator. - * @return {!goog.iter.Iterator<VALUE>} An iterator advanced zero or more steps - * ahead. - * @template VALUE - */ -goog.iter.consume = function(iterable, count) { - goog.asserts.assert(goog.math.isInt(count) && count >= 0); - - var iterator = goog.iter.toIterator(iterable); - - while (count-- > 0) { - goog.iter.nextOrValue(iterator, null); - } - - return iterator; -}; - - -/** - * Creates an iterator that returns a range of elements from an iterable. - * Similar to {@see goog.array#slice} but does not support negative indexes. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to slice. - * @param {number} start The index of the first element to return. - * @param {number=} opt_end The index after the last element to return. If - * defined, must be greater than or equal to {@code start}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator containing a slice of - * the original. - * @template VALUE - */ -goog.iter.slice = function(iterable, start, opt_end) { - goog.asserts.assert(goog.math.isInt(start) && start >= 0); - - var iterator = goog.iter.consume(iterable, start); - - if (goog.isNumber(opt_end)) { - goog.asserts.assert(goog.math.isInt(opt_end) && opt_end >= start); - iterator = goog.iter.limit(iterator, opt_end - start /* limitSize */); - } - - return iterator; -}; - - -/** - * Checks an array for duplicate elements. - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to check for - * duplicates. - * @return {boolean} True, if the array contains duplicates, false otherwise. - * @private - * @template VALUE - */ -// TODO(user): Consider moving this into goog.array as a public function. -goog.iter.hasDuplicates_ = function(arr) { - var deduped = []; - goog.array.removeDuplicates(arr, deduped); - return arr.length != deduped.length; -}; - - -/** - * Creates an iterator that returns permutations of elements in - * {@code iterable}. - * - * Permutations are obtained by taking the Cartesian product of - * {@code opt_length} iterables and filtering out those with repeated - * elements. For example, the permutations of {@code [1,2,3]} are - * {@code [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.permutations - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable from which to generate permutations. - * @param {number=} opt_length Length of each permutation. If omitted, defaults - * to the length of {@code iterable}. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing the - * permutations of {@code iterable}. - * @template VALUE - */ -goog.iter.permutations = function(iterable, opt_length) { - var elements = goog.iter.toArray(iterable); - var length = goog.isNumber(opt_length) ? opt_length : elements.length; - - var sets = goog.array.repeat(elements, length); - var product = goog.iter.product.apply(undefined, sets); - - return goog.iter.filter(product, function(arr) { - return !goog.iter.hasDuplicates_(arr); - }); -}; - - -/** - * Creates an iterator that returns combinations of elements from - * {@code iterable}. - * - * Combinations are obtained by taking the {@see goog.iter#permutations} of - * {@code iterable} and filtering those whose elements appear in the order they - * are encountered in {@code iterable}. For example, the 3-length combinations - * of {@code [0,1,2,3]} are {@code [[0,1,2], [0,1,3], [0,2,3], [1,2,3]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.combinations - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable from which to generate combinations. - * @param {number} length The length of each combination. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing - * combinations from the {@code iterable}. - * @template VALUE - */ -goog.iter.combinations = function(iterable, length) { - var elements = goog.iter.toArray(iterable); - var indexes = goog.iter.range(elements.length); - var indexIterator = goog.iter.permutations(indexes, length); - // sortedIndexIterator will now give arrays of with the given length that - // indicate what indexes into "elements" should be returned on each iteration. - var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { - return goog.array.isSorted(arr); - }); - - var iter = new goog.iter.Iterator(); - - function getIndexFromElements(index) { - return elements[index]; - } - - iter.next = function() { - return goog.array.map(sortedIndexIterator.next(), getIndexFromElements); - }; - - return iter; -}; - - -/** - * Creates an iterator that returns combinations of elements from - * {@code iterable}, with repeated elements possible. - * - * Combinations are obtained by taking the Cartesian product of {@code length} - * iterables and filtering those whose elements appear in the order they are - * encountered in {@code iterable}. For example, the 2-length combinations of - * {@code [1,2,3]} are {@code [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.combinations_with_replacement - * @see http://en.wikipedia.org/wiki/Combination#Number_of_combinations_with_repetition - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to combine. - * @param {number} length The length of each combination. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing - * combinations from the {@code iterable}. - * @template VALUE - */ -goog.iter.combinationsWithReplacement = function(iterable, length) { - var elements = goog.iter.toArray(iterable); - var indexes = goog.array.range(elements.length); - var sets = goog.array.repeat(indexes, length); - var indexIterator = goog.iter.product.apply(undefined, sets); - // sortedIndexIterator will now give arrays of with the given length that - // indicate what indexes into "elements" should be returned on each iteration. - var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { - return goog.array.isSorted(arr); - }); - - var iter = new goog.iter.Iterator(); - - function getIndexFromElements(index) { - return elements[index]; - } - - iter.next = function() { - return goog.array.map( - /** @type {!Array<number>} */ - (sortedIndexIterator.next()), getIndexFromElements); - }; - - return iter; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Datastructure: Hash Map. - * - * @author arv@google.com (Erik Arvidsson) - * - * This file contains an implementation of a Map structure. It implements a lot - * of the methods used in goog.structs so those functions work on hashes. This - * is best suited for complex key types. For simple keys such as numbers and - * strings consider using the lighter-weight utilities in goog.object. - */ - - -goog.provide('goog.structs.Map'); - -goog.require('goog.iter.Iterator'); -goog.require('goog.iter.StopIteration'); -goog.require('goog.object'); - - - -/** - * Class for Hash Map datastructure. - * @param {*=} opt_map Map or Object to initialize the map with. - * @param {...*} var_args If 2 or more arguments are present then they - * will be used as key-value pairs. - * @constructor - * @template K, V - */ -goog.structs.Map = function(opt_map, var_args) { - - /** - * Underlying JS object used to implement the map. - * @private {!Object} - */ - this.map_ = {}; - - /** - * An array of keys. This is necessary for two reasons: - * 1. Iterating the keys using for (var key in this.map_) allocates an - * object for every key in IE which is really bad for IE6 GC perf. - * 2. Without a side data structure, we would need to escape all the keys - * as that would be the only way we could tell during iteration if the - * key was an internal key or a property of the object. - * - * This array can contain deleted keys so it's necessary to check the map - * as well to see if the key is still in the map (this doesn't require a - * memory allocation in IE). - * @private {!Array<string>} - */ - this.keys_ = []; - - /** - * The number of key value pairs in the map. - * @private {number} - */ - this.count_ = 0; - - /** - * Version used to detect changes while iterating. - * @private {number} - */ - this.version_ = 0; - - var argLength = arguments.length; - - if (argLength > 1) { - if (argLength % 2) { - throw Error('Uneven number of arguments'); - } - for (var i = 0; i < argLength; i += 2) { - this.set(arguments[i], arguments[i + 1]); - } - } else if (opt_map) { - this.addAll(/** @type {Object} */ (opt_map)); - } -}; - - -/** - * @return {number} The number of key-value pairs in the map. - */ -goog.structs.Map.prototype.getCount = function() { - return this.count_; -}; - - -/** - * Returns the values of the map. - * @return {!Array<V>} The values in the map. - */ -goog.structs.Map.prototype.getValues = function() { - this.cleanupKeysArray_(); - - var rv = []; - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - rv.push(this.map_[key]); - } - return rv; -}; - - -/** - * Returns the keys of the map. - * @return {!Array<string>} Array of string values. - */ -goog.structs.Map.prototype.getKeys = function() { - this.cleanupKeysArray_(); - return /** @type {!Array<string>} */ (this.keys_.concat()); -}; - - -/** - * Whether the map contains the given key. - * @param {*} key The key to check for. - * @return {boolean} Whether the map contains the key. - */ -goog.structs.Map.prototype.containsKey = function(key) { - return goog.structs.Map.hasKey_(this.map_, key); -}; - - -/** - * Whether the map contains the given value. This is O(n). - * @param {V} val The value to check for. - * @return {boolean} Whether the map contains the value. - */ -goog.structs.Map.prototype.containsValue = function(val) { - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) { - return true; - } - } - return false; -}; - - -/** - * Whether this map is equal to the argument map. - * @param {goog.structs.Map} otherMap The map against which to test equality. - * @param {function(V, V): boolean=} opt_equalityFn Optional equality function - * to test equality of values. If not specified, this will test whether - * the values contained in each map are identical objects. - * @return {boolean} Whether the maps are equal. - */ -goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) { - if (this === otherMap) { - return true; - } - - if (this.count_ != otherMap.getCount()) { - return false; - } - - var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals; - - this.cleanupKeysArray_(); - for (var key, i = 0; key = this.keys_[i]; i++) { - if (!equalityFn(this.get(key), otherMap.get(key))) { - return false; - } - } - - return true; -}; - - -/** - * Default equality test for values. - * @param {*} a The first value. - * @param {*} b The second value. - * @return {boolean} Whether a and b reference the same object. - */ -goog.structs.Map.defaultEquals = function(a, b) { - return a === b; -}; - - -/** - * @return {boolean} Whether the map is empty. - */ -goog.structs.Map.prototype.isEmpty = function() { - return this.count_ == 0; -}; - - -/** - * Removes all key-value pairs from the map. - */ -goog.structs.Map.prototype.clear = function() { - this.map_ = {}; - this.keys_.length = 0; - this.count_ = 0; - this.version_ = 0; -}; - - -/** - * Removes a key-value pair based on the key. This is O(logN) amortized due to - * updating the keys array whenever the count becomes half the size of the keys - * in the keys array. - * @param {*} key The key to remove. - * @return {boolean} Whether object was removed. - */ -goog.structs.Map.prototype.remove = function(key) { - if (goog.structs.Map.hasKey_(this.map_, key)) { - delete this.map_[key]; - this.count_--; - this.version_++; - - // clean up the keys array if the threshhold is hit - if (this.keys_.length > 2 * this.count_) { - this.cleanupKeysArray_(); - } - - return true; - } - return false; -}; - - -/** - * Cleans up the temp keys array by removing entries that are no longer in the - * map. - * @private - */ -goog.structs.Map.prototype.cleanupKeysArray_ = function() { - if (this.count_ != this.keys_.length) { - // First remove keys that are no longer in the map. - var srcIndex = 0; - var destIndex = 0; - while (srcIndex < this.keys_.length) { - var key = this.keys_[srcIndex]; - if (goog.structs.Map.hasKey_(this.map_, key)) { - this.keys_[destIndex++] = key; - } - srcIndex++; - } - this.keys_.length = destIndex; - } - - if (this.count_ != this.keys_.length) { - // If the count still isn't correct, that means we have duplicates. This can - // happen when the same key is added and removed multiple times. Now we have - // to allocate one extra Object to remove the duplicates. This could have - // been done in the first pass, but in the common case, we can avoid - // allocating an extra object by only doing this when necessary. - var seen = {}; - var srcIndex = 0; - var destIndex = 0; - while (srcIndex < this.keys_.length) { - var key = this.keys_[srcIndex]; - if (!(goog.structs.Map.hasKey_(seen, key))) { - this.keys_[destIndex++] = key; - seen[key] = 1; - } - srcIndex++; - } - this.keys_.length = destIndex; - } -}; - - -/** - * Returns the value for the given key. If the key is not found and the default - * value is not given this will return {@code undefined}. - * @param {*} key The key to get the value for. - * @param {DEFAULT=} opt_val The value to return if no item is found for the - * given key, defaults to undefined. - * @return {V|DEFAULT} The value for the given key. - * @template DEFAULT - */ -goog.structs.Map.prototype.get = function(key, opt_val) { - if (goog.structs.Map.hasKey_(this.map_, key)) { - return this.map_[key]; - } - return opt_val; -}; - - -/** - * Adds a key-value pair to the map. - * @param {*} key The key. - * @param {V} value The value to add. - * @return {*} Some subclasses return a value. - */ -goog.structs.Map.prototype.set = function(key, value) { - if (!(goog.structs.Map.hasKey_(this.map_, key))) { - this.count_++; - this.keys_.push(key); - // Only change the version if we add a new key. - this.version_++; - } - this.map_[key] = value; -}; - - -/** - * Adds multiple key-value pairs from another goog.structs.Map or Object. - * @param {Object} map Object containing the data to add. - */ -goog.structs.Map.prototype.addAll = function(map) { - var keys, values; - if (map instanceof goog.structs.Map) { - keys = map.getKeys(); - values = map.getValues(); - } else { - keys = goog.object.getKeys(map); - values = goog.object.getValues(map); - } - // we could use goog.array.forEach here but I don't want to introduce that - // dependency just for this. - for (var i = 0; i < keys.length; i++) { - this.set(keys[i], values[i]); - } -}; - - -/** - * Calls the given function on each entry in the map. - * @param {function(this:T, V, K, goog.structs.Map<K,V>)} f - * @param {T=} opt_obj The value of "this" inside f. - * @template T - */ -goog.structs.Map.prototype.forEach = function(f, opt_obj) { - var keys = this.getKeys(); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = this.get(key); - f.call(opt_obj, value, key, this); - } -}; - - -/** - * Clones a map and returns a new map. - * @return {!goog.structs.Map} A new map with the same key-value pairs. - */ -goog.structs.Map.prototype.clone = function() { - return new goog.structs.Map(this); -}; - - -/** - * Returns a new map in which all the keys and values are interchanged - * (keys become values and values become keys). If multiple keys map to the - * same value, the chosen transposed value is implementation-dependent. - * - * It acts very similarly to {goog.object.transpose(Object)}. - * - * @return {!goog.structs.Map} The transposed map. - */ -goog.structs.Map.prototype.transpose = function() { - var transposed = new goog.structs.Map(); - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - var value = this.map_[key]; - transposed.set(value, key); - } - - return transposed; -}; - - -/** - * @return {!Object} Object representation of the map. - */ -goog.structs.Map.prototype.toObject = function() { - this.cleanupKeysArray_(); - var obj = {}; - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - obj[key] = this.map_[key]; - } - return obj; -}; - - -/** - * Returns an iterator that iterates over the keys in the map. Removal of keys - * while iterating might have undesired side effects. - * @return {!goog.iter.Iterator} An iterator over the keys in the map. - */ -goog.structs.Map.prototype.getKeyIterator = function() { - return this.__iterator__(true); -}; - - -/** - * Returns an iterator that iterates over the values in the map. Removal of - * keys while iterating might have undesired side effects. - * @return {!goog.iter.Iterator} An iterator over the values in the map. - */ -goog.structs.Map.prototype.getValueIterator = function() { - return this.__iterator__(false); -}; - - -/** - * Returns an iterator that iterates over the values or the keys in the map. - * This throws an exception if the map was mutated since the iterator was - * created. - * @param {boolean=} opt_keys True to iterate over the keys. False to iterate - * over the values. The default value is false. - * @return {!goog.iter.Iterator} An iterator over the values or keys in the map. - */ -goog.structs.Map.prototype.__iterator__ = function(opt_keys) { - // Clean up keys to minimize the risk of iterating over dead keys. - this.cleanupKeysArray_(); - - var i = 0; - var version = this.version_; - var selfObj = this; - - var newIter = new goog.iter.Iterator; - newIter.next = function() { - if (version != selfObj.version_) { - throw Error('The map has changed since the iterator was created'); - } - if (i >= selfObj.keys_.length) { - throw goog.iter.StopIteration; - } - var key = selfObj.keys_[i++]; - return opt_keys ? key : selfObj.map_[key]; - }; - return newIter; -}; - - -/** - * Safe way to test for hasOwnProperty. It even allows testing for - * 'hasOwnProperty'. - * @param {Object} obj The object to test for presence of the given key. - * @param {*} key The key to check for. - * @return {boolean} Whether the object has the key. - * @private - */ -goog.structs.Map.hasKey_ = function(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Datastructure: Set. - * - * @author arv@google.com (Erik Arvidsson) - * - * This class implements a set data structure. Adding and removing is O(1). It - * supports both object and primitive values. Be careful because you can add - * both 1 and new Number(1), because these are not the same. You can even add - * multiple new Number(1) because these are not equal. - */ - - -goog.provide('goog.structs.Set'); - -goog.require('goog.structs'); -goog.require('goog.structs.Collection'); -goog.require('goog.structs.Map'); - - - -/** - * A set that can contain both primitives and objects. Adding and removing - * elements is O(1). Primitives are treated as identical if they have the same - * type and convert to the same string. Objects are treated as identical only - * if they are references to the same object. WARNING: A goog.structs.Set can - * contain both 1 and (new Number(1)), because they are not the same. WARNING: - * Adding (new Number(1)) twice will yield two distinct elements, because they - * are two different objects. WARNING: Any object that is added to a - * goog.structs.Set will be modified! Because goog.getUid() is used to - * identify objects, every object in the set will be mutated. - * @param {Array<T>|Object<?,T>=} opt_values Initial values to start with. - * @constructor - * @implements {goog.structs.Collection<T>} - * @final - * @template T - */ -goog.structs.Set = function(opt_values) { - this.map_ = new goog.structs.Map; - if (opt_values) { - this.addAll(opt_values); - } -}; - - -/** - * Obtains a unique key for an element of the set. Primitives will yield the - * same key if they have the same type and convert to the same string. Object - * references will yield the same key only if they refer to the same object. - * @param {*} val Object or primitive value to get a key for. - * @return {string} A unique key for this value/object. - * @private - */ -goog.structs.Set.getKey_ = function(val) { - var type = typeof val; - if (type == 'object' && val || type == 'function') { - return 'o' + goog.getUid(/** @type {Object} */ (val)); - } else { - return type.substr(0, 1) + val; - } -}; - - -/** - * @return {number} The number of elements in the set. - * @override - */ -goog.structs.Set.prototype.getCount = function() { - return this.map_.getCount(); -}; - - -/** - * Add a primitive or an object to the set. - * @param {T} element The primitive or object to add. - * @override - */ -goog.structs.Set.prototype.add = function(element) { - this.map_.set(goog.structs.Set.getKey_(element), element); -}; - - -/** - * Adds all the values in the given collection to this set. - * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection - * containing the elements to add. - */ -goog.structs.Set.prototype.addAll = function(col) { - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - this.add(values[i]); - } -}; - - -/** - * Removes all values in the given collection from this set. - * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection - * containing the elements to remove. - */ -goog.structs.Set.prototype.removeAll = function(col) { - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - this.remove(values[i]); - } -}; - - -/** - * Removes the given element from this set. - * @param {T} element The primitive or object to remove. - * @return {boolean} Whether the element was found and removed. - * @override - */ -goog.structs.Set.prototype.remove = function(element) { - return this.map_.remove(goog.structs.Set.getKey_(element)); -}; - - -/** - * Removes all elements from this set. - */ -goog.structs.Set.prototype.clear = function() { - this.map_.clear(); -}; - - -/** - * Tests whether this set is empty. - * @return {boolean} True if there are no elements in this set. - */ -goog.structs.Set.prototype.isEmpty = function() { - return this.map_.isEmpty(); -}; - - -/** - * Tests whether this set contains the given element. - * @param {T} element The primitive or object to test for. - * @return {boolean} True if this set contains the given element. - * @override - */ -goog.structs.Set.prototype.contains = function(element) { - return this.map_.containsKey(goog.structs.Set.getKey_(element)); -}; - - -/** - * Tests whether this set contains all the values in a given collection. - * Repeated elements in the collection are ignored, e.g. (new - * goog.structs.Set([1, 2])).containsAll([1, 1]) is True. - * @param {goog.structs.Collection<T>|Object} col A collection-like object. - * @return {boolean} True if the set contains all elements. - */ -goog.structs.Set.prototype.containsAll = function(col) { - return goog.structs.every(col, this.contains, this); -}; - - -/** - * Finds all values that are present in both this set and the given collection. - * @param {Array<S>|Object<?,S>} col A collection. - * @return {!goog.structs.Set<T|S>} A new set containing all the values - * (primitives or objects) present in both this set and the given - * collection. - * @template S - */ -goog.structs.Set.prototype.intersection = function(col) { - var result = new goog.structs.Set(); - - var values = goog.structs.getValues(col); - for (var i = 0; i < values.length; i++) { - var value = values[i]; - if (this.contains(value)) { - result.add(value); - } - } - - return result; -}; - - -/** - * Finds all values that are present in this set and not in the given - * collection. - * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection. - * @return {!goog.structs.Set} A new set containing all the values - * (primitives or objects) present in this set but not in the given - * collection. - */ -goog.structs.Set.prototype.difference = function(col) { - var result = this.clone(); - result.removeAll(col); - return result; -}; - - -/** - * Returns an array containing all the elements in this set. - * @return {!Array<T>} An array containing all the elements in this set. - */ -goog.structs.Set.prototype.getValues = function() { - return this.map_.getValues(); -}; - - -/** - * Creates a shallow clone of this set. - * @return {!goog.structs.Set<T>} A new set containing all the same elements as - * this set. - */ -goog.structs.Set.prototype.clone = function() { - return new goog.structs.Set(this); -}; - - -/** - * Tests whether the given collection consists of the same elements as this set, - * regardless of order, without repetition. Primitives are treated as equal if - * they have the same type and convert to the same string; objects are treated - * as equal if they are references to the same object. This operation is O(n). - * @param {goog.structs.Collection<T>|Object} col A collection. - * @return {boolean} True if the given collection consists of the same elements - * as this set, regardless of order, without repetition. - */ -goog.structs.Set.prototype.equals = function(col) { - return this.getCount() == goog.structs.getCount(col) && this.isSubsetOf(col); -}; - - -/** - * Tests whether the given collection contains all the elements in this set. - * Primitives are treated as equal if they have the same type and convert to the - * same string; objects are treated as equal if they are references to the same - * object. This operation is O(n). - * @param {goog.structs.Collection<T>|Object} col A collection. - * @return {boolean} True if this set is a subset of the given collection. - */ -goog.structs.Set.prototype.isSubsetOf = function(col) { - var colCount = goog.structs.getCount(col); - if (this.getCount() > colCount) { - return false; - } - // TODO(user) Find the minimal collection size where the conversion makes - // the contains() method faster. - if (!(col instanceof goog.structs.Set) && colCount > 5) { - // Convert to a goog.structs.Set so that goog.structs.contains runs in - // O(1) time instead of O(n) time. - col = new goog.structs.Set(col); - } - return goog.structs.every(this, function(value) { - return goog.structs.contains(col, value); - }); -}; - - -/** - * Returns an iterator that iterates over the elements in this set. - * @param {boolean=} opt_keys This argument is ignored. - * @return {!goog.iter.Iterator} An iterator over the elements in this set. - */ -goog.structs.Set.prototype.__iterator__ = function(opt_keys) { - return this.map_.__iterator__(false); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Logging and debugging utilities. - * - * @see ../demos/debug.html - */ - -goog.provide('goog.debug'); - -goog.require('goog.array'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.uncheckedconversions'); -goog.require('goog.string.Const'); -goog.require('goog.structs.Set'); -goog.require('goog.userAgent'); - - -/** @define {boolean} Whether logging should be enabled. */ -goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG); - - -/** - * Catches onerror events fired by windows and similar objects. - * @param {function(Object)} logFunc The function to call with the error - * information. - * @param {boolean=} opt_cancel Whether to stop the error from reaching the - * browser. - * @param {Object=} opt_target Object that fires onerror events. - */ -goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) { - var target = opt_target || goog.global; - var oldErrorHandler = target.onerror; - var retVal = !!opt_cancel; - - // Chrome interprets onerror return value backwards (http://crbug.com/92062) - // until it was fixed in webkit revision r94061 (Webkit 535.3). This - // workaround still needs to be skipped in Safari after the webkit change - // gets pushed out in Safari. - // See https://bugs.webkit.org/show_bug.cgi?id=67119 - if (goog.userAgent.WEBKIT && - !goog.userAgent.isVersionOrHigher('535.3')) { - retVal = !retVal; - } - - /** - * New onerror handler for this target. This onerror handler follows the spec - * according to - * http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors - * The spec was changed in August 2013 to support receiving column information - * and an error object for all scripts on the same origin or cross origin - * scripts with the proper headers. See - * https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror - * - * @param {string} message The error message. For cross-origin errors, this - * will be scrubbed to just "Script error.". For new browsers that have - * updated to follow the latest spec, errors that come from origins that - * have proper cross origin headers will not be scrubbed. - * @param {string} url The URL of the script that caused the error. The URL - * will be scrubbed to "" for cross origin scripts unless the script has - * proper cross origin headers and the browser has updated to the latest - * spec. - * @param {number} line The line number in the script that the error - * occurred on. - * @param {number=} opt_col The optional column number that the error - * occurred on. Only browsers that have updated to the latest spec will - * include this. - * @param {Error=} opt_error The optional actual error object for this - * error that should include the stack. Only browsers that have updated - * to the latest spec will inlude this parameter. - * @return {boolean} Whether to prevent the error from reaching the browser. - */ - target.onerror = function(message, url, line, opt_col, opt_error) { - if (oldErrorHandler) { - oldErrorHandler(message, url, line, opt_col, opt_error); - } - logFunc({ - message: message, - fileName: url, - line: line, - col: opt_col, - error: opt_error - }); - return retVal; - }; -}; - - -/** - * Creates a string representing an object and all its properties. - * @param {Object|null|undefined} obj Object to expose. - * @param {boolean=} opt_showFn Show the functions as well as the properties, - * default is false. - * @return {string} The string representation of {@code obj}. - */ -goog.debug.expose = function(obj, opt_showFn) { - if (typeof obj == 'undefined') { - return 'undefined'; - } - if (obj == null) { - return 'NULL'; - } - var str = []; - - for (var x in obj) { - if (!opt_showFn && goog.isFunction(obj[x])) { - continue; - } - var s = x + ' = '; - /** @preserveTry */ - try { - s += obj[x]; - } catch (e) { - s += '*** ' + e + ' ***'; - } - str.push(s); - } - return str.join('\n'); -}; - - -/** - * Creates a string representing a given primitive or object, and for an - * object, all its properties and nested objects. WARNING: If an object is - * given, it and all its nested objects will be modified. To detect reference - * cycles, this method identifies objects using goog.getUid() which mutates the - * object. - * @param {*} obj Object to expose. - * @param {boolean=} opt_showFn Also show properties that are functions (by - * default, functions are omitted). - * @return {string} A string representation of {@code obj}. - */ -goog.debug.deepExpose = function(obj, opt_showFn) { - var str = []; - - var helper = function(obj, space, parentSeen) { - var nestspace = space + ' '; - var seen = new goog.structs.Set(parentSeen); - - var indentMultiline = function(str) { - return str.replace(/\n/g, '\n' + space); - }; - - /** @preserveTry */ - try { - if (!goog.isDef(obj)) { - str.push('undefined'); - } else if (goog.isNull(obj)) { - str.push('NULL'); - } else if (goog.isString(obj)) { - str.push('"' + indentMultiline(obj) + '"'); - } else if (goog.isFunction(obj)) { - str.push(indentMultiline(String(obj))); - } else if (goog.isObject(obj)) { - if (seen.contains(obj)) { - str.push('*** reference loop detected ***'); - } else { - seen.add(obj); - str.push('{'); - for (var x in obj) { - if (!opt_showFn && goog.isFunction(obj[x])) { - continue; - } - str.push('\n'); - str.push(nestspace); - str.push(x + ' = '); - helper(obj[x], nestspace, seen); - } - str.push('\n' + space + '}'); - } - } else { - str.push(obj); - } - } catch (e) { - str.push('*** ' + e + ' ***'); - } - }; - - helper(obj, '', new goog.structs.Set()); - return str.join(''); -}; - - -/** - * Recursively outputs a nested array as a string. - * @param {Array<?>} arr The array. - * @return {string} String representing nested array. - */ -goog.debug.exposeArray = function(arr) { - var str = []; - for (var i = 0; i < arr.length; i++) { - if (goog.isArray(arr[i])) { - str.push(goog.debug.exposeArray(arr[i])); - } else { - str.push(arr[i]); - } - } - return '[ ' + str.join(', ') + ' ]'; -}; - - -/** - * Exposes an exception that has been caught by a try...catch and outputs the - * error as HTML with a stack trace. - * @param {Object} err Error object or string. - * @param {Function=} opt_fn Optional function to start stack trace from. - * @return {string} Details of exception, as HTML. - */ -goog.debug.exposeException = function(err, opt_fn) { - var html = goog.debug.exposeExceptionAsHtml(err, opt_fn); - return goog.html.SafeHtml.unwrap(html); -}; - - -/** - * Exposes an exception that has been caught by a try...catch and outputs the - * error with a stack trace. - * @param {Object} err Error object or string. - * @param {Function=} opt_fn Optional function to start stack trace from. - * @return {!goog.html.SafeHtml} Details of exception. - */ -goog.debug.exposeExceptionAsHtml = function(err, opt_fn) { - /** @preserveTry */ - try { - var e = goog.debug.normalizeErrorObject(err); - // Create the error message - var viewSourceUrl = goog.debug.createViewSourceUrl_(e.fileName); - var error = goog.html.SafeHtml.concat( - goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - 'Message: ' + e.message + '\nUrl: '), - goog.html.SafeHtml.create('a', - {href: viewSourceUrl, target: '_new'}, e.fileName), - goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - '\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' + - e.stack + '-> ' + '[end]\n\nJS stack traversal:\n' + - goog.debug.getStacktrace(opt_fn) + '-> ')); - return error; - } catch (e2) { - return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - 'Exception trying to expose exception! You win, we lose. ' + e2); - } -}; - - -/** - * @param {?string=} opt_fileName - * @return {!goog.html.SafeUrl} SafeUrl with view-source scheme, pointing at - * fileName. - * @private - */ -goog.debug.createViewSourceUrl_ = function(opt_fileName) { - if (!goog.isDefAndNotNull(opt_fileName)) { - opt_fileName = ''; - } - if (!/^https?:\/\//i.test(opt_fileName)) { - return goog.html.SafeUrl.fromConstant( - goog.string.Const.from('sanitizedviewsrc')); - } - var sanitizedFileName = goog.html.SafeUrl.sanitize(opt_fileName); - return goog.html.uncheckedconversions. - safeUrlFromStringKnownToSatisfyTypeContract( - goog.string.Const.from('view-source scheme plus HTTP/HTTPS URL'), - 'view-source:' + goog.html.SafeUrl.unwrap(sanitizedFileName)); -}; - - -/** - * Normalizes the error/exception object between browsers. - * @param {Object} err Raw error object. - * @return {!Object} Normalized error object. - */ -goog.debug.normalizeErrorObject = function(err) { - var href = goog.getObjectByName('window.location.href'); - if (goog.isString(err)) { - return { - 'message': err, - 'name': 'Unknown error', - 'lineNumber': 'Not available', - 'fileName': href, - 'stack': 'Not available' - }; - } - - var lineNumber, fileName; - var threwError = false; - - try { - lineNumber = err.lineNumber || err.line || 'Not available'; - } catch (e) { - // Firefox 2 sometimes throws an error when accessing 'lineNumber': - // Message: Permission denied to get property UnnamedClass.lineNumber - lineNumber = 'Not available'; - threwError = true; - } - - try { - fileName = err.fileName || err.filename || err.sourceURL || - // $googDebugFname may be set before a call to eval to set the filename - // that the eval is supposed to present. - goog.global['$googDebugFname'] || href; - } catch (e) { - // Firefox 2 may also throw an error when accessing 'filename'. - fileName = 'Not available'; - threwError = true; - } - - // The IE Error object contains only the name and the message. - // The Safari Error object uses the line and sourceURL fields. - if (threwError || !err.lineNumber || !err.fileName || !err.stack || - !err.message || !err.name) { - return { - 'message': err.message || 'Not available', - 'name': err.name || 'UnknownError', - 'lineNumber': lineNumber, - 'fileName': fileName, - 'stack': err.stack || 'Not available' - }; - } - - // Standards error object - return err; -}; - - -/** - * Converts an object to an Error if it's a String, - * adds a stacktrace if there isn't one, - * and optionally adds an extra message. - * @param {Error|string} err the original thrown object or string. - * @param {string=} opt_message optional additional message to add to the - * error. - * @return {!Error} If err is a string, it is used to create a new Error, - * which is enhanced and returned. Otherwise err itself is enhanced - * and returned. - */ -goog.debug.enhanceError = function(err, opt_message) { - var error; - if (typeof err == 'string') { - error = Error(err); - if (Error.captureStackTrace) { - // Trim this function off the call stack, if we can. - Error.captureStackTrace(error, goog.debug.enhanceError); - } - } else { - error = err; - } - - if (!error.stack) { - error.stack = goog.debug.getStacktrace(goog.debug.enhanceError); - } - if (opt_message) { - // find the first unoccupied 'messageX' property - var x = 0; - while (error['message' + x]) { - ++x; - } - error['message' + x] = String(opt_message); - } - return error; -}; - - -/** - * Gets the current stack trace. Simple and iterative - doesn't worry about - * catching circular references or getting the args. - * @param {number=} opt_depth Optional maximum depth to trace back to. - * @return {string} A string with the function names of all functions in the - * stack, separated by \n. - * @suppress {es5Strict} - */ -goog.debug.getStacktraceSimple = function(opt_depth) { - if (goog.STRICT_MODE_COMPATIBLE) { - var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple); - if (stack) { - return stack; - } - // NOTE: browsers that have strict mode support also have native "stack" - // properties. Fall-through for legacy browser support. - } - - var sb = []; - var fn = arguments.callee.caller; - var depth = 0; - - while (fn && (!opt_depth || depth < opt_depth)) { - sb.push(goog.debug.getFunctionName(fn)); - sb.push('()\n'); - /** @preserveTry */ - try { - fn = fn.caller; - } catch (e) { - sb.push('[exception trying to get caller]\n'); - break; - } - depth++; - if (depth >= goog.debug.MAX_STACK_DEPTH) { - sb.push('[...long stack...]'); - break; - } - } - if (opt_depth && depth >= opt_depth) { - sb.push('[...reached max depth limit...]'); - } else { - sb.push('[end]'); - } - - return sb.join(''); -}; - - -/** - * Max length of stack to try and output - * @type {number} - */ -goog.debug.MAX_STACK_DEPTH = 50; - - -/** - * @param {Function} fn The function to start getting the trace from. - * @return {?string} - * @private - */ -goog.debug.getNativeStackTrace_ = function(fn) { - var tempErr = new Error(); - if (Error.captureStackTrace) { - Error.captureStackTrace(tempErr, fn); - return String(tempErr.stack); - } else { - // IE10, only adds stack traces when an exception is thrown. - try { - throw tempErr; - } catch (e) { - tempErr = e; - } - var stack = tempErr.stack; - if (stack) { - return String(stack); - } - } - return null; -}; - - -/** - * Gets the current stack trace, either starting from the caller or starting - * from a specified function that's currently on the call stack. - * @param {Function=} opt_fn Optional function to start getting the trace from. - * If not provided, defaults to the function that called this. - * @return {string} Stack trace. - * @suppress {es5Strict} - */ -goog.debug.getStacktrace = function(opt_fn) { - var stack; - if (goog.STRICT_MODE_COMPATIBLE) { - // Try to get the stack trace from the environment if it is available. - var contextFn = opt_fn || goog.debug.getStacktrace; - stack = goog.debug.getNativeStackTrace_(contextFn); - } - if (!stack) { - // NOTE: browsers that have strict mode support also have native "stack" - // properties. This function will throw in strict mode. - stack = goog.debug.getStacktraceHelper_( - opt_fn || arguments.callee.caller, []); - } - return stack; -}; - - -/** - * Private helper for getStacktrace(). - * @param {Function} fn Function to start getting the trace from. - * @param {Array<!Function>} visited List of functions visited so far. - * @return {string} Stack trace starting from function fn. - * @suppress {es5Strict} - * @private - */ -goog.debug.getStacktraceHelper_ = function(fn, visited) { - var sb = []; - - // Circular reference, certain functions like bind seem to cause a recursive - // loop so we need to catch circular references - if (goog.array.contains(visited, fn)) { - sb.push('[...circular reference...]'); - - // Traverse the call stack until function not found or max depth is reached - } else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) { - sb.push(goog.debug.getFunctionName(fn) + '('); - var args = fn.arguments; - // Args may be null for some special functions such as host objects or eval. - for (var i = 0; args && i < args.length; i++) { - if (i > 0) { - sb.push(', '); - } - var argDesc; - var arg = args[i]; - switch (typeof arg) { - case 'object': - argDesc = arg ? 'object' : 'null'; - break; - - case 'string': - argDesc = arg; - break; - - case 'number': - argDesc = String(arg); - break; - - case 'boolean': - argDesc = arg ? 'true' : 'false'; - break; - - case 'function': - argDesc = goog.debug.getFunctionName(arg); - argDesc = argDesc ? argDesc : '[fn]'; - break; - - case 'undefined': - default: - argDesc = typeof arg; - break; - } - - if (argDesc.length > 40) { - argDesc = argDesc.substr(0, 40) + '...'; - } - sb.push(argDesc); - } - visited.push(fn); - sb.push(')\n'); - /** @preserveTry */ - try { - sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited)); - } catch (e) { - sb.push('[exception trying to get caller]\n'); - } - - } else if (fn) { - sb.push('[...long stack...]'); - } else { - sb.push('[end]'); - } - return sb.join(''); -}; - - -/** - * Set a custom function name resolver. - * @param {function(Function): string} resolver Resolves functions to their - * names. - */ -goog.debug.setFunctionResolver = function(resolver) { - goog.debug.fnNameResolver_ = resolver; -}; - - -/** - * Gets a function name - * @param {Function} fn Function to get name of. - * @return {string} Function's name. - */ -goog.debug.getFunctionName = function(fn) { - if (goog.debug.fnNameCache_[fn]) { - return goog.debug.fnNameCache_[fn]; - } - if (goog.debug.fnNameResolver_) { - var name = goog.debug.fnNameResolver_(fn); - if (name) { - goog.debug.fnNameCache_[fn] = name; - return name; - } - } - - // Heuristically determine function name based on code. - var functionSource = String(fn); - if (!goog.debug.fnNameCache_[functionSource]) { - var matches = /function ([^\(]+)/.exec(functionSource); - if (matches) { - var method = matches[1]; - goog.debug.fnNameCache_[functionSource] = method; - } else { - goog.debug.fnNameCache_[functionSource] = '[Anonymous]'; - } - } - - return goog.debug.fnNameCache_[functionSource]; -}; - - -/** - * Makes whitespace visible by replacing it with printable characters. - * This is useful in finding diffrences between the expected and the actual - * output strings of a testcase. - * @param {string} string whose whitespace needs to be made visible. - * @return {string} string whose whitespace is made visible. - */ -goog.debug.makeWhitespaceVisible = function(string) { - return string.replace(/ /g, '[_]') - .replace(/\f/g, '[f]') - .replace(/\n/g, '[n]\n') - .replace(/\r/g, '[r]') - .replace(/\t/g, '[t]'); -}; - - -/** - * Returns the type of a value. If a constructor is passed, and a suitable - * string cannot be found, 'unknown type name' will be returned. - * - * <p>Forked rather than moved from {@link goog.asserts.getType_} - * to avoid adding a dependency to goog.asserts. - * @param {*} value A constructor, object, or primitive. - * @return {string} The best display name for the value, or 'unknown type name'. - */ -goog.debug.runtimeType = function(value) { - if (value instanceof Function) { - return value.displayName || value.name || 'unknown type name'; - } else if (value instanceof Object) { - return value.constructor.displayName || value.constructor.name || - Object.prototype.toString.call(value); - } else { - return value === null ? 'null' : typeof value; - } -}; - - -/** - * Hash map for storing function names that have already been looked up. - * @type {Object} - * @private - */ -goog.debug.fnNameCache_ = {}; - - -/** - * Resolves functions to their names. Resolved function names will be cached. - * @type {function(Function):string} - * @private - */ -goog.debug.fnNameResolver_; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the LogRecord class. Please minimize - * dependencies this file has on other closure classes as any dependency it - * takes won't be able to use the logging infrastructure. - * - */ - -goog.provide('goog.debug.LogRecord'); - - - -/** - * LogRecord objects are used to pass logging requests between - * the logging framework and individual log Handlers. - * @constructor - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {string} loggerName The name of the source logger. - * @param {number=} opt_time Time this log record was created if other than now. - * If 0, we use #goog.now. - * @param {number=} opt_sequenceNumber Sequence number of this log record. This - * should only be passed in when restoring a log record from persistence. - */ -goog.debug.LogRecord = function(level, msg, loggerName, - opt_time, opt_sequenceNumber) { - this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber); -}; - - -/** - * Time the LogRecord was created. - * @type {number} - * @private - */ -goog.debug.LogRecord.prototype.time_; - - -/** - * Level of the LogRecord - * @type {goog.debug.Logger.Level} - * @private - */ -goog.debug.LogRecord.prototype.level_; - - -/** - * Message associated with the record - * @type {string} - * @private - */ -goog.debug.LogRecord.prototype.msg_; - - -/** - * Name of the logger that created the record. - * @type {string} - * @private - */ -goog.debug.LogRecord.prototype.loggerName_; - - -/** - * Sequence number for the LogRecord. Each record has a unique sequence number - * that is greater than all log records created before it. - * @type {number} - * @private - */ -goog.debug.LogRecord.prototype.sequenceNumber_ = 0; - - -/** - * Exception associated with the record - * @type {Object} - * @private - */ -goog.debug.LogRecord.prototype.exception_ = null; - - -/** - * @define {boolean} Whether to enable log sequence numbers. - */ -goog.define('goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS', true); - - -/** - * A sequence counter for assigning increasing sequence numbers to LogRecord - * objects. - * @type {number} - * @private - */ -goog.debug.LogRecord.nextSequenceNumber_ = 0; - - -/** - * Sets all fields of the log record. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {string} loggerName The name of the source logger. - * @param {number=} opt_time Time this log record was created if other than now. - * If 0, we use #goog.now. - * @param {number=} opt_sequenceNumber Sequence number of this log record. This - * should only be passed in when restoring a log record from persistence. - */ -goog.debug.LogRecord.prototype.reset = function(level, msg, loggerName, - opt_time, opt_sequenceNumber) { - if (goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) { - this.sequenceNumber_ = typeof opt_sequenceNumber == 'number' ? - opt_sequenceNumber : goog.debug.LogRecord.nextSequenceNumber_++; - } - - this.time_ = opt_time || goog.now(); - this.level_ = level; - this.msg_ = msg; - this.loggerName_ = loggerName; - delete this.exception_; -}; - - -/** - * Get the source Logger's name. - * - * @return {string} source logger name (may be null). - */ -goog.debug.LogRecord.prototype.getLoggerName = function() { - return this.loggerName_; -}; - - -/** - * Get the exception that is part of the log record. - * - * @return {Object} the exception. - */ -goog.debug.LogRecord.prototype.getException = function() { - return this.exception_; -}; - - -/** - * Set the exception that is part of the log record. - * - * @param {Object} exception the exception. - */ -goog.debug.LogRecord.prototype.setException = function(exception) { - this.exception_ = exception; -}; - - -/** - * Get the source Logger's name. - * - * @param {string} loggerName source logger name (may be null). - */ -goog.debug.LogRecord.prototype.setLoggerName = function(loggerName) { - this.loggerName_ = loggerName; -}; - - -/** - * Get the logging message level, for example Level.SEVERE. - * @return {goog.debug.Logger.Level} the logging message level. - */ -goog.debug.LogRecord.prototype.getLevel = function() { - return this.level_; -}; - - -/** - * Set the logging message level, for example Level.SEVERE. - * @param {goog.debug.Logger.Level} level the logging message level. - */ -goog.debug.LogRecord.prototype.setLevel = function(level) { - this.level_ = level; -}; - - -/** - * Get the "raw" log message, before localization or formatting. - * - * @return {string} the raw message string. - */ -goog.debug.LogRecord.prototype.getMessage = function() { - return this.msg_; -}; - - -/** - * Set the "raw" log message, before localization or formatting. - * - * @param {string} msg the raw message string. - */ -goog.debug.LogRecord.prototype.setMessage = function(msg) { - this.msg_ = msg; -}; - - -/** - * Get event time in milliseconds since 1970. - * - * @return {number} event time in millis since 1970. - */ -goog.debug.LogRecord.prototype.getMillis = function() { - return this.time_; -}; - - -/** - * Set event time in milliseconds since 1970. - * - * @param {number} time event time in millis since 1970. - */ -goog.debug.LogRecord.prototype.setMillis = function(time) { - this.time_ = time; -}; - - -/** - * Get the sequence number. - * <p> - * Sequence numbers are normally assigned in the LogRecord - * constructor, which assigns unique sequence numbers to - * each new LogRecord in increasing order. - * @return {number} the sequence number. - */ -goog.debug.LogRecord.prototype.getSequenceNumber = function() { - return this.sequenceNumber_; -}; - - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A buffer for log records. The purpose of this is to improve - * logging performance by re-using old objects when the buffer becomes full and - * to eliminate the need for each app to implement their own log buffer. The - * disadvantage to doing this is that log handlers cannot maintain references to - * log records and expect that they are not overwriten at a later point. - * - * @author agrieve@google.com (Andrew Grieve) - */ - -goog.provide('goog.debug.LogBuffer'); - -goog.require('goog.asserts'); -goog.require('goog.debug.LogRecord'); - - - -/** - * Creates the log buffer. - * @constructor - * @final - */ -goog.debug.LogBuffer = function() { - goog.asserts.assert(goog.debug.LogBuffer.isBufferingEnabled(), - 'Cannot use goog.debug.LogBuffer without defining ' + - 'goog.debug.LogBuffer.CAPACITY.'); - this.clear(); -}; - - -/** - * A static method that always returns the same instance of LogBuffer. - * @return {!goog.debug.LogBuffer} The LogBuffer singleton instance. - */ -goog.debug.LogBuffer.getInstance = function() { - if (!goog.debug.LogBuffer.instance_) { - // This function is written with the return statement after the assignment - // to avoid the jscompiler StripCode bug described in http://b/2608064. - // After that bug is fixed this can be refactored. - goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer(); - } - return goog.debug.LogBuffer.instance_; -}; - - -/** - * @define {number} The number of log records to buffer. 0 means disable - * buffering. - */ -goog.define('goog.debug.LogBuffer.CAPACITY', 0); - - -/** - * The array to store the records. - * @type {!Array<!goog.debug.LogRecord|undefined>} - * @private - */ -goog.debug.LogBuffer.prototype.buffer_; - - -/** - * The index of the most recently added record or -1 if there are no records. - * @type {number} - * @private - */ -goog.debug.LogBuffer.prototype.curIndex_; - - -/** - * Whether the buffer is at capacity. - * @type {boolean} - * @private - */ -goog.debug.LogBuffer.prototype.isFull_; - - -/** - * Adds a log record to the buffer, possibly overwriting the oldest record. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {string} loggerName The name of the source logger. - * @return {!goog.debug.LogRecord} The log record. - */ -goog.debug.LogBuffer.prototype.addRecord = function(level, msg, loggerName) { - var curIndex = (this.curIndex_ + 1) % goog.debug.LogBuffer.CAPACITY; - this.curIndex_ = curIndex; - if (this.isFull_) { - var ret = this.buffer_[curIndex]; - ret.reset(level, msg, loggerName); - return ret; - } - this.isFull_ = curIndex == goog.debug.LogBuffer.CAPACITY - 1; - return this.buffer_[curIndex] = - new goog.debug.LogRecord(level, msg, loggerName); -}; - - -/** - * @return {boolean} Whether the log buffer is enabled. - */ -goog.debug.LogBuffer.isBufferingEnabled = function() { - return goog.debug.LogBuffer.CAPACITY > 0; -}; - - -/** - * Removes all buffered log records. - */ -goog.debug.LogBuffer.prototype.clear = function() { - this.buffer_ = new Array(goog.debug.LogBuffer.CAPACITY); - this.curIndex_ = -1; - this.isFull_ = false; -}; - - -/** - * Calls the given function for each buffered log record, starting with the - * oldest one. - * @param {function(!goog.debug.LogRecord)} func The function to call. - */ -goog.debug.LogBuffer.prototype.forEachRecord = function(func) { - var buffer = this.buffer_; - // Corner case: no records. - if (!buffer[0]) { - return; - } - var curIndex = this.curIndex_; - var i = this.isFull_ ? curIndex : -1; - do { - i = (i + 1) % goog.debug.LogBuffer.CAPACITY; - func(/** @type {!goog.debug.LogRecord} */ (buffer[i])); - } while (i != curIndex); -}; - - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the Logger class. Please minimize dependencies - * this file has on other closure classes as any dependency it takes won't be - * able to use the logging infrastructure. - * - * @see ../demos/debug.html - */ - -goog.provide('goog.debug.LogManager'); -goog.provide('goog.debug.Loggable'); -goog.provide('goog.debug.Logger'); -goog.provide('goog.debug.Logger.Level'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.debug'); -goog.require('goog.debug.LogBuffer'); -goog.require('goog.debug.LogRecord'); - - -/** - * A message value that can be handled by a Logger. - * - * Functions are treated like callbacks, but are only called when the event's - * log level is enabled. This is useful for logging messages that are expensive - * to construct. - * - * @typedef {string|function(): string} - */ -goog.debug.Loggable; - - - -/** - * The Logger is an object used for logging debug messages. Loggers are - * normally named, using a hierarchical dot-separated namespace. Logger names - * can be arbitrary strings, but they should normally be based on the package - * name or class name of the logged component, such as goog.net.BrowserChannel. - * - * The Logger object is loosely based on the java class - * java.util.logging.Logger. It supports different levels of filtering for - * different loggers. - * - * The logger object should never be instantiated by application code. It - * should always use the goog.debug.Logger.getLogger function. - * - * @constructor - * @param {string} name The name of the Logger. - * @final - */ -goog.debug.Logger = function(name) { - /** - * Name of the Logger. Generally a dot-separated namespace - * @private {string} - */ - this.name_ = name; - - /** - * Parent Logger. - * @private {goog.debug.Logger} - */ - this.parent_ = null; - - /** - * Level that this logger only filters above. Null indicates it should - * inherit from the parent. - * @private {goog.debug.Logger.Level} - */ - this.level_ = null; - - /** - * Map of children loggers. The keys are the leaf names of the children and - * the values are the child loggers. - * @private {Object} - */ - this.children_ = null; - - /** - * Handlers that are listening to this logger. - * @private {Array<Function>} - */ - this.handlers_ = null; -}; - - -/** @const */ -goog.debug.Logger.ROOT_LOGGER_NAME = ''; - - -/** - * @define {boolean} Toggles whether loggers other than the root logger can have - * log handlers attached to them and whether they can have their log level - * set. Logging is a bit faster when this is set to false. - */ -goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true); - - -if (!goog.debug.Logger.ENABLE_HIERARCHY) { - /** - * @type {!Array<Function>} - * @private - */ - goog.debug.Logger.rootHandlers_ = []; - - - /** - * @type {goog.debug.Logger.Level} - * @private - */ - goog.debug.Logger.rootLevel_; -} - - - -/** - * The Level class defines a set of standard logging levels that - * can be used to control logging output. The logging Level objects - * are ordered and are specified by ordered integers. Enabling logging - * at a given level also enables logging at all higher levels. - * <p> - * Clients should normally use the predefined Level constants such - * as Level.SEVERE. - * <p> - * The levels in descending order are: - * <ul> - * <li>SEVERE (highest value) - * <li>WARNING - * <li>INFO - * <li>CONFIG - * <li>FINE - * <li>FINER - * <li>FINEST (lowest value) - * </ul> - * In addition there is a level OFF that can be used to turn - * off logging, and a level ALL that can be used to enable - * logging of all messages. - * - * @param {string} name The name of the level. - * @param {number} value The numeric value of the level. - * @constructor - * @final - */ -goog.debug.Logger.Level = function(name, value) { - /** - * The name of the level - * @type {string} - */ - this.name = name; - - /** - * The numeric value of the level - * @type {number} - */ - this.value = value; -}; - - -/** - * @return {string} String representation of the logger level. - * @override - */ -goog.debug.Logger.Level.prototype.toString = function() { - return this.name; -}; - - -/** - * OFF is a special level that can be used to turn off logging. - * This level is initialized to <CODE>Infinity</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.OFF = - new goog.debug.Logger.Level('OFF', Infinity); - - -/** - * SHOUT is a message level for extra debugging loudness. - * This level is initialized to <CODE>1200</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200); - - -/** - * SEVERE is a message level indicating a serious failure. - * This level is initialized to <CODE>1000</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000); - - -/** - * WARNING is a message level indicating a potential problem. - * This level is initialized to <CODE>900</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900); - - -/** - * INFO is a message level for informational messages. - * This level is initialized to <CODE>800</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800); - - -/** - * CONFIG is a message level for static configuration messages. - * This level is initialized to <CODE>700</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700); - - -/** - * FINE is a message level providing tracing information. - * This level is initialized to <CODE>500</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500); - - -/** - * FINER indicates a fairly detailed tracing message. - * This level is initialized to <CODE>400</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400); - -/** - * FINEST indicates a highly detailed tracing message. - * This level is initialized to <CODE>300</CODE>. - * @type {!goog.debug.Logger.Level} - */ - -goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300); - - -/** - * ALL indicates that all messages should be logged. - * This level is initialized to <CODE>0</CODE>. - * @type {!goog.debug.Logger.Level} - */ -goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0); - - -/** - * The predefined levels. - * @type {!Array<!goog.debug.Logger.Level>} - * @final - */ -goog.debug.Logger.Level.PREDEFINED_LEVELS = [ - goog.debug.Logger.Level.OFF, - goog.debug.Logger.Level.SHOUT, - goog.debug.Logger.Level.SEVERE, - goog.debug.Logger.Level.WARNING, - goog.debug.Logger.Level.INFO, - goog.debug.Logger.Level.CONFIG, - goog.debug.Logger.Level.FINE, - goog.debug.Logger.Level.FINER, - goog.debug.Logger.Level.FINEST, - goog.debug.Logger.Level.ALL]; - - -/** - * A lookup map used to find the level object based on the name or value of - * the level object. - * @type {Object} - * @private - */ -goog.debug.Logger.Level.predefinedLevelsCache_ = null; - - -/** - * Creates the predefined levels cache and populates it. - * @private - */ -goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() { - goog.debug.Logger.Level.predefinedLevelsCache_ = {}; - for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i]; - i++) { - goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level; - goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level; - } -}; - - -/** - * Gets the predefined level with the given name. - * @param {string} name The name of the level. - * @return {goog.debug.Logger.Level} The level, or null if none found. - */ -goog.debug.Logger.Level.getPredefinedLevel = function(name) { - if (!goog.debug.Logger.Level.predefinedLevelsCache_) { - goog.debug.Logger.Level.createPredefinedLevelsCache_(); - } - - return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null; -}; - - -/** - * Gets the highest predefined level <= #value. - * @param {number} value Level value. - * @return {goog.debug.Logger.Level} The level, or null if none found. - */ -goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) { - if (!goog.debug.Logger.Level.predefinedLevelsCache_) { - goog.debug.Logger.Level.createPredefinedLevelsCache_(); - } - - if (value in goog.debug.Logger.Level.predefinedLevelsCache_) { - return goog.debug.Logger.Level.predefinedLevelsCache_[value]; - } - - for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) { - var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i]; - if (level.value <= value) { - return level; - } - } - return null; -}; - - -/** - * Finds or creates a logger for a named subsystem. If a logger has already been - * created with the given name it is returned. Otherwise a new logger is - * created. If a new logger is created its log level will be configured based - * on the LogManager configuration and it will configured to also send logging - * output to its parent's handlers. It will be registered in the LogManager - * global namespace. - * - * @param {string} name A name for the logger. This should be a dot-separated - * name and should normally be based on the package name or class name of the - * subsystem, such as goog.net.BrowserChannel. - * @return {!goog.debug.Logger} The named logger. - * @deprecated use goog.log instead. http://go/goog-debug-logger-deprecated - */ -goog.debug.Logger.getLogger = function(name) { - return goog.debug.LogManager.getLogger(name); -}; - - -/** - * Logs a message to profiling tools, if available. - * {@see https://developers.google.com/web-toolkit/speedtracer/logging-api} - * {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx} - * @param {string} msg The message to log. - */ -goog.debug.Logger.logToProfilers = function(msg) { - // Using goog.global, as loggers might be used in window-less contexts. - if (goog.global['console']) { - if (goog.global['console']['timeStamp']) { - // Logs a message to Firebug, Web Inspector, SpeedTracer, etc. - goog.global['console']['timeStamp'](msg); - } else if (goog.global['console']['markTimeline']) { - // TODO(user): markTimeline is deprecated. Drop this else clause entirely - // after Chrome M14 hits stable. - goog.global['console']['markTimeline'](msg); - } - } - - if (goog.global['msWriteProfilerMark']) { - // Logs a message to the Microsoft profiler - goog.global['msWriteProfilerMark'](msg); - } -}; - - -/** - * Gets the name of this logger. - * @return {string} The name of this logger. - */ -goog.debug.Logger.prototype.getName = function() { - return this.name_; -}; - - -/** - * Adds a handler to the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {Function} handler Handler function to add. - */ -goog.debug.Logger.prototype.addHandler = function(handler) { - if (goog.debug.LOGGING_ENABLED) { - if (goog.debug.Logger.ENABLE_HIERARCHY) { - if (!this.handlers_) { - this.handlers_ = []; - } - this.handlers_.push(handler); - } else { - goog.asserts.assert(!this.name_, - 'Cannot call addHandler on a non-root logger when ' + - 'goog.debug.Logger.ENABLE_HIERARCHY is false.'); - goog.debug.Logger.rootHandlers_.push(handler); - } - } -}; - - -/** - * Removes a handler from the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {Function} handler Handler function to remove. - * @return {boolean} Whether the handler was removed. - */ -goog.debug.Logger.prototype.removeHandler = function(handler) { - if (goog.debug.LOGGING_ENABLED) { - var handlers = goog.debug.Logger.ENABLE_HIERARCHY ? this.handlers_ : - goog.debug.Logger.rootHandlers_; - return !!handlers && goog.array.remove(handlers, handler); - } else { - return false; - } -}; - - -/** - * Returns the parent of this logger. - * @return {goog.debug.Logger} The parent logger or null if this is the root. - */ -goog.debug.Logger.prototype.getParent = function() { - return this.parent_; -}; - - -/** - * Returns the children of this logger as a map of the child name to the logger. - * @return {!Object} The map where the keys are the child leaf names and the - * values are the Logger objects. - */ -goog.debug.Logger.prototype.getChildren = function() { - if (!this.children_) { - this.children_ = {}; - } - return this.children_; -}; - - -/** - * Set the log level specifying which message levels will be logged by this - * logger. Message levels lower than this value will be discarded. - * The level value Level.OFF can be used to turn off logging. If the new level - * is null, it means that this node should inherit its level from its nearest - * ancestor with a specific (non-null) level value. - * - * @param {goog.debug.Logger.Level} level The new level. - */ -goog.debug.Logger.prototype.setLevel = function(level) { - if (goog.debug.LOGGING_ENABLED) { - if (goog.debug.Logger.ENABLE_HIERARCHY) { - this.level_ = level; - } else { - goog.asserts.assert(!this.name_, - 'Cannot call setLevel() on a non-root logger when ' + - 'goog.debug.Logger.ENABLE_HIERARCHY is false.'); - goog.debug.Logger.rootLevel_ = level; - } - } -}; - - -/** - * Gets the log level specifying which message levels will be logged by this - * logger. Message levels lower than this value will be discarded. - * The level value Level.OFF can be used to turn off logging. If the level - * is null, it means that this node should inherit its level from its nearest - * ancestor with a specific (non-null) level value. - * - * @return {goog.debug.Logger.Level} The level. - */ -goog.debug.Logger.prototype.getLevel = function() { - return goog.debug.LOGGING_ENABLED ? - this.level_ : goog.debug.Logger.Level.OFF; -}; - - -/** - * Returns the effective level of the logger based on its ancestors' levels. - * @return {goog.debug.Logger.Level} The level. - */ -goog.debug.Logger.prototype.getEffectiveLevel = function() { - if (!goog.debug.LOGGING_ENABLED) { - return goog.debug.Logger.Level.OFF; - } - - if (!goog.debug.Logger.ENABLE_HIERARCHY) { - return goog.debug.Logger.rootLevel_; - } - if (this.level_) { - return this.level_; - } - if (this.parent_) { - return this.parent_.getEffectiveLevel(); - } - goog.asserts.fail('Root logger has no level set.'); - return null; -}; - - -/** - * Checks if a message of the given level would actually be logged by this - * logger. This check is based on the Loggers effective level, which may be - * inherited from its parent. - * @param {goog.debug.Logger.Level} level The level to check. - * @return {boolean} Whether the message would be logged. - */ -goog.debug.Logger.prototype.isLoggable = function(level) { - return goog.debug.LOGGING_ENABLED && - level.value >= this.getEffectiveLevel().value; -}; - - -/** - * Logs a message. If the logger is currently enabled for the - * given message level then the given message is forwarded to all the - * registered output Handler objects. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error|Object=} opt_exception An exception associated with the - * message. - */ -goog.debug.Logger.prototype.log = function(level, msg, opt_exception) { - // java caches the effective level, not sure it's necessary here - if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) { - // Message callbacks can be useful when a log message is expensive to build. - if (goog.isFunction(msg)) { - msg = msg(); - } - - this.doLogRecord_(this.getLogRecord(level, msg, opt_exception)); - } -}; - - -/** - * Creates a new log record and adds the exception (if present) to it. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {Error|Object=} opt_exception An exception associated with the - * message. - * @return {!goog.debug.LogRecord} A log record. - * @suppress {es5Strict} - */ -goog.debug.Logger.prototype.getLogRecord = function( - level, msg, opt_exception) { - if (goog.debug.LogBuffer.isBufferingEnabled()) { - var logRecord = - goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_); - } else { - logRecord = new goog.debug.LogRecord(level, String(msg), this.name_); - } - if (opt_exception) { - logRecord.setException(opt_exception); - } - return logRecord; -}; - - -/** - * Logs a message at the Logger.Level.SHOUT level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.shout = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.SEVERE level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.severe = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.WARNING level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.warning = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.INFO level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.info = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.INFO, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.CONFIG level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.config = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.FINE level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.fine = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.FINE, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.FINER level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.finer = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.FINER, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Logger.Level.FINEST level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.finest = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception); - } -}; - - -/** - * Logs a LogRecord. If the logger is currently enabled for the - * given message level then the given message is forwarded to all the - * registered output Handler objects. - * @param {goog.debug.LogRecord} logRecord A log record to log. - */ -goog.debug.Logger.prototype.logRecord = function(logRecord) { - if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) { - this.doLogRecord_(logRecord); - } -}; - - -/** - * Logs a LogRecord. - * @param {goog.debug.LogRecord} logRecord A log record to log. - * @private - */ -goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) { - goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage()); - if (goog.debug.Logger.ENABLE_HIERARCHY) { - var target = this; - while (target) { - target.callPublish_(logRecord); - target = target.getParent(); - } - } else { - for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++]; ) { - handler(logRecord); - } - } -}; - - -/** - * Calls the handlers for publish. - * @param {goog.debug.LogRecord} logRecord The log record to publish. - * @private - */ -goog.debug.Logger.prototype.callPublish_ = function(logRecord) { - if (this.handlers_) { - for (var i = 0, handler; handler = this.handlers_[i]; i++) { - handler(logRecord); - } - } -}; - - -/** - * Sets the parent of this logger. This is used for setting up the logger tree. - * @param {goog.debug.Logger} parent The parent logger. - * @private - */ -goog.debug.Logger.prototype.setParent_ = function(parent) { - this.parent_ = parent; -}; - - -/** - * Adds a child to this logger. This is used for setting up the logger tree. - * @param {string} name The leaf name of the child. - * @param {goog.debug.Logger} logger The child logger. - * @private - */ -goog.debug.Logger.prototype.addChild_ = function(name, logger) { - this.getChildren()[name] = logger; -}; - - -/** - * There is a single global LogManager object that is used to maintain a set of - * shared state about Loggers and log services. This is loosely based on the - * java class java.util.logging.LogManager. - * @const - */ -goog.debug.LogManager = {}; - - -/** - * Map of logger names to logger objects. - * - * @type {!Object<string, !goog.debug.Logger>} - * @private - */ -goog.debug.LogManager.loggers_ = {}; - - -/** - * The root logger which is the root of the logger tree. - * @type {goog.debug.Logger} - * @private - */ -goog.debug.LogManager.rootLogger_ = null; - - -/** - * Initializes the LogManager if not already initialized. - */ -goog.debug.LogManager.initialize = function() { - if (!goog.debug.LogManager.rootLogger_) { - goog.debug.LogManager.rootLogger_ = new goog.debug.Logger( - goog.debug.Logger.ROOT_LOGGER_NAME); - goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] = - goog.debug.LogManager.rootLogger_; - goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG); - } -}; - - -/** - * Returns all the loggers. - * @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger - * objects. - */ -goog.debug.LogManager.getLoggers = function() { - return goog.debug.LogManager.loggers_; -}; - - -/** - * Returns the root of the logger tree namespace, the logger with the empty - * string as its name. - * - * @return {!goog.debug.Logger} The root logger. - */ -goog.debug.LogManager.getRoot = function() { - goog.debug.LogManager.initialize(); - return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_); -}; - - -/** - * Finds a named logger. - * - * @param {string} name A name for the logger. This should be a dot-separated - * name and should normally be based on the package name or class name of the - * subsystem, such as goog.net.BrowserChannel. - * @return {!goog.debug.Logger} The named logger. - */ -goog.debug.LogManager.getLogger = function(name) { - goog.debug.LogManager.initialize(); - var ret = goog.debug.LogManager.loggers_[name]; - return ret || goog.debug.LogManager.createLogger_(name); -}; - - -/** - * Creates a function that can be passed to goog.debug.catchErrors. The function - * will log all reported errors using the given logger. - * @param {goog.debug.Logger=} opt_logger The logger to log the errors to. - * Defaults to the root logger. - * @return {function(Object)} The created function. - */ -goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) { - return function(info) { - var logger = opt_logger || goog.debug.LogManager.getRoot(); - logger.severe('Error: ' + info.message + ' (' + info.fileName + - ' @ Line: ' + info.line + ')'); - }; -}; - - -/** - * Creates the named logger. Will also create the parents of the named logger - * if they don't yet exist. - * @param {string} name The name of the logger. - * @return {!goog.debug.Logger} The named logger. - * @private - */ -goog.debug.LogManager.createLogger_ = function(name) { - // find parent logger - var logger = new goog.debug.Logger(name); - if (goog.debug.Logger.ENABLE_HIERARCHY) { - var lastDotIndex = name.lastIndexOf('.'); - var parentName = name.substr(0, lastDotIndex); - var leafName = name.substr(lastDotIndex + 1); - var parentLogger = goog.debug.LogManager.getLogger(parentName); - - // tell the parent about the child and the child about the parent - parentLogger.addChild_(leafName, logger); - logger.setParent_(parentLogger); - } - - goog.debug.LogManager.loggers_[name] = logger; - return logger; -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition the goog.debug.RelativeTimeProvider class. - * - */ - -goog.provide('goog.debug.RelativeTimeProvider'); - - - -/** - * A simple object to keep track of a timestamp considered the start of - * something. The main use is for the logger system to maintain a start time - * that is occasionally reset. For example, in Gmail, we reset this relative - * time at the start of a user action so that timings are offset from the - * beginning of the action. This class also provides a singleton as the default - * behavior for most use cases is to share the same start time. - * - * @constructor - * @final - */ -goog.debug.RelativeTimeProvider = function() { - /** - * The start time. - * @type {number} - * @private - */ - this.relativeTimeStart_ = goog.now(); -}; - - -/** - * Default instance. - * @type {goog.debug.RelativeTimeProvider} - * @private - */ -goog.debug.RelativeTimeProvider.defaultInstance_ = - new goog.debug.RelativeTimeProvider(); - - -/** - * Sets the start time to the specified time. - * @param {number} timeStamp The start time. - */ -goog.debug.RelativeTimeProvider.prototype.set = function(timeStamp) { - this.relativeTimeStart_ = timeStamp; -}; - - -/** - * Resets the start time to now. - */ -goog.debug.RelativeTimeProvider.prototype.reset = function() { - this.set(goog.now()); -}; - - -/** - * @return {number} The start time. - */ -goog.debug.RelativeTimeProvider.prototype.get = function() { - return this.relativeTimeStart_; -}; - - -/** - * @return {goog.debug.RelativeTimeProvider} The default instance. - */ -goog.debug.RelativeTimeProvider.getDefaultInstance = function() { - return goog.debug.RelativeTimeProvider.defaultInstance_; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of various formatters for logging. Please minimize - * dependencies this file has on other closure classes as any dependency it - * takes won't be able to use the logging infrastructure. - * - */ - -goog.provide('goog.debug.Formatter'); -goog.provide('goog.debug.HtmlFormatter'); -goog.provide('goog.debug.TextFormatter'); - -goog.require('goog.debug'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.RelativeTimeProvider'); -goog.require('goog.html.SafeHtml'); - - - -/** - * Base class for Formatters. A Formatter is used to format a LogRecord into - * something that can be displayed to the user. - * - * @param {string=} opt_prefix The prefix to place before text records. - * @constructor - */ -goog.debug.Formatter = function(opt_prefix) { - this.prefix_ = opt_prefix || ''; - - /** - * A provider that returns the relative start time. - * @type {goog.debug.RelativeTimeProvider} - * @private - */ - this.startTimeProvider_ = - goog.debug.RelativeTimeProvider.getDefaultInstance(); -}; - - -/** - * Whether to append newlines to the end of formatted log records. - * @type {boolean} - */ -goog.debug.Formatter.prototype.appendNewline = true; - - -/** - * Whether to show absolute time in the DebugWindow. - * @type {boolean} - */ -goog.debug.Formatter.prototype.showAbsoluteTime = true; - - -/** - * Whether to show relative time in the DebugWindow. - * @type {boolean} - */ -goog.debug.Formatter.prototype.showRelativeTime = true; - - -/** - * Whether to show the logger name in the DebugWindow. - * @type {boolean} - */ -goog.debug.Formatter.prototype.showLoggerName = true; - - -/** - * Whether to show the logger exception text. - * @type {boolean} - */ -goog.debug.Formatter.prototype.showExceptionText = false; - - -/** - * Whether to show the severity level. - * @type {boolean} - */ -goog.debug.Formatter.prototype.showSeverityLevel = false; - - -/** - * Formats a record. - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {string} The formatted string. - */ -goog.debug.Formatter.prototype.formatRecord = goog.abstractMethod; - - -/** - * Formats a record as SafeHtml. - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. - */ -goog.debug.Formatter.prototype.formatRecordAsHtml = goog.abstractMethod; - - -/** - * Sets the start time provider. By default, this is the default instance - * but can be changed. - * @param {goog.debug.RelativeTimeProvider} provider The provider to use. - */ -goog.debug.Formatter.prototype.setStartTimeProvider = function(provider) { - this.startTimeProvider_ = provider; -}; - - -/** - * Returns the start time provider. By default, this is the default instance - * but can be changed. - * @return {goog.debug.RelativeTimeProvider} The start time provider. - */ -goog.debug.Formatter.prototype.getStartTimeProvider = function() { - return this.startTimeProvider_; -}; - - -/** - * Resets the start relative time. - */ -goog.debug.Formatter.prototype.resetRelativeTimeStart = function() { - this.startTimeProvider_.reset(); -}; - - -/** - * Returns a string for the time/date of the LogRecord. - * @param {goog.debug.LogRecord} logRecord The record to get a time stamp for. - * @return {string} A string representation of the time/date of the LogRecord. - * @private - */ -goog.debug.Formatter.getDateTimeStamp_ = function(logRecord) { - var time = new Date(logRecord.getMillis()); - return goog.debug.Formatter.getTwoDigitString_((time.getFullYear() - 2000)) + - goog.debug.Formatter.getTwoDigitString_((time.getMonth() + 1)) + - goog.debug.Formatter.getTwoDigitString_(time.getDate()) + ' ' + - goog.debug.Formatter.getTwoDigitString_(time.getHours()) + ':' + - goog.debug.Formatter.getTwoDigitString_(time.getMinutes()) + ':' + - goog.debug.Formatter.getTwoDigitString_(time.getSeconds()) + '.' + - goog.debug.Formatter.getTwoDigitString_( - Math.floor(time.getMilliseconds() / 10)); -}; - - -/** - * Returns the number as a two-digit string, meaning it prepends a 0 if the - * number if less than 10. - * @param {number} n The number to format. - * @return {string} A two-digit string representation of {@code n}. - * @private - */ -goog.debug.Formatter.getTwoDigitString_ = function(n) { - if (n < 10) { - return '0' + n; - } - return String(n); -}; - - -/** - * Returns a string for the number of seconds relative to the start time. - * Prepads with spaces so that anything less than 1000 seconds takes up the - * same number of characters for better formatting. - * @param {goog.debug.LogRecord} logRecord The log to compare time to. - * @param {number} relativeTimeStart The start time to compare to. - * @return {string} The number of seconds of the LogRecord relative to the - * start time. - * @private - */ -goog.debug.Formatter.getRelativeTime_ = function(logRecord, - relativeTimeStart) { - var ms = logRecord.getMillis() - relativeTimeStart; - var sec = ms / 1000; - var str = sec.toFixed(3); - - var spacesToPrepend = 0; - if (sec < 1) { - spacesToPrepend = 2; - } else { - while (sec < 100) { - spacesToPrepend++; - sec *= 10; - } - } - while (spacesToPrepend-- > 0) { - str = ' ' + str; - } - return str; -}; - - - -/** - * Formatter that returns formatted html. See formatRecord for the classes - * it uses for various types of formatted output. - * - * @param {string=} opt_prefix The prefix to place before text records. - * @constructor - * @extends {goog.debug.Formatter} - */ -goog.debug.HtmlFormatter = function(opt_prefix) { - goog.debug.Formatter.call(this, opt_prefix); -}; -goog.inherits(goog.debug.HtmlFormatter, goog.debug.Formatter); - - -/** - * Whether to show the logger exception text - * @type {boolean} - * @override - */ -goog.debug.HtmlFormatter.prototype.showExceptionText = true; - - -/** - * Formats a record - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {string} The formatted string as html. - * @override - */ -goog.debug.HtmlFormatter.prototype.formatRecord = function(logRecord) { - if (!logRecord) { - return ''; - } - // OK not to use goog.html.SafeHtml.unwrap() here. - return this.formatRecordAsHtml(logRecord).getTypedStringValue(); -}; - - -/** - * Formats a record. - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. - * @override - */ -goog.debug.HtmlFormatter.prototype.formatRecordAsHtml = function(logRecord) { - if (!logRecord) { - return goog.html.SafeHtml.EMPTY; - } - - var className; - switch (logRecord.getLevel().value) { - case goog.debug.Logger.Level.SHOUT.value: - className = 'dbg-sh'; - break; - case goog.debug.Logger.Level.SEVERE.value: - className = 'dbg-sev'; - break; - case goog.debug.Logger.Level.WARNING.value: - className = 'dbg-w'; - break; - case goog.debug.Logger.Level.INFO.value: - className = 'dbg-i'; - break; - case goog.debug.Logger.Level.FINE.value: - default: - className = 'dbg-f'; - break; - } - - // HTML for user defined prefix, time, logger name, and severity. - var sb = []; - sb.push(this.prefix_, ' '); - if (this.showAbsoluteTime) { - sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] '); - } - if (this.showRelativeTime) { - sb.push('[', - goog.debug.Formatter.getRelativeTime_( - logRecord, this.startTimeProvider_.get()), - 's] '); - } - if (this.showLoggerName) { - sb.push('[', logRecord.getLoggerName(), '] '); - } - if (this.showSeverityLevel) { - sb.push('[', logRecord.getLevel().name, '] '); - } - var fullPrefixHtml = - goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(sb.join('')); - - // HTML for exception text and log record. - var exceptionHtml = goog.html.SafeHtml.EMPTY; - if (this.showExceptionText && logRecord.getException()) { - exceptionHtml = goog.html.SafeHtml.concat( - goog.html.SafeHtml.create('br'), - goog.debug.exposeExceptionAsHtml(logRecord.getException())); - } - var logRecordHtml = goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - logRecord.getMessage()); - var recordAndExceptionHtml = goog.html.SafeHtml.create( - 'span', - {'class': className}, - goog.html.SafeHtml.concat(logRecordHtml, exceptionHtml)); - - - // Combine both pieces of HTML and, if needed, append a final newline. - var html; - if (this.appendNewline) { - html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml, - goog.html.SafeHtml.create('br')); - } else { - html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml); - } - return html; -}; - - - -/** - * Formatter that returns formatted plain text - * - * @param {string=} opt_prefix The prefix to place before text records. - * @constructor - * @extends {goog.debug.Formatter} - * @final - */ -goog.debug.TextFormatter = function(opt_prefix) { - goog.debug.Formatter.call(this, opt_prefix); -}; -goog.inherits(goog.debug.TextFormatter, goog.debug.Formatter); - - -/** - * Formats a record as text - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {string} The formatted string. - * @override - */ -goog.debug.TextFormatter.prototype.formatRecord = function(logRecord) { - var sb = []; - sb.push(this.prefix_, ' '); - if (this.showAbsoluteTime) { - sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] '); - } - if (this.showRelativeTime) { - sb.push('[', goog.debug.Formatter.getRelativeTime_(logRecord, - this.startTimeProvider_.get()), 's] '); - } - - if (this.showLoggerName) { - sb.push('[', logRecord.getLoggerName(), '] '); - } - if (this.showSeverityLevel) { - sb.push('[', logRecord.getLevel().name, '] '); - } - sb.push(logRecord.getMessage()); - if (this.showExceptionText) { - var exception = logRecord.getException(); - if (exception) { - var exceptionText = exception instanceof Error ? - exception.message : - exception.toString(); - sb.push('\n', exceptionText); - } - } - if (this.appendNewline) { - sb.push('\n'); - } - return sb.join(''); -}; - - -/** - * Formats a record as text - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. This is - * just an HTML-escaped version of the text obtained from formatRecord(). - * @override - */ -goog.debug.TextFormatter.prototype.formatRecordAsHtml = function(logRecord) { - return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - goog.debug.TextFormatter.prototype.formatRecord(logRecord)); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Simple logger that logs to the window console if available. - * - * Has an autoInstall option which can be put into initialization code, which - * will start logging if "Debug=true" is in document.location.href - * - */ - -goog.provide('goog.debug.Console'); - -goog.require('goog.debug.LogManager'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.TextFormatter'); - - - -/** - * Create and install a log handler that logs to window.console if available - * @constructor - */ -goog.debug.Console = function() { - this.publishHandler_ = goog.bind(this.addLogRecord, this); - - /** - * Formatter for formatted output. - * @type {!goog.debug.TextFormatter} - * @private - */ - this.formatter_ = new goog.debug.TextFormatter(); - this.formatter_.showAbsoluteTime = false; - this.formatter_.showExceptionText = false; - // The console logging methods automatically append a newline. - this.formatter_.appendNewline = false; - - this.isCapturing_ = false; - this.logBuffer_ = ''; - - /** - * Loggers that we shouldn't output. - * @type {!Object<boolean>} - * @private - */ - this.filteredLoggers_ = {}; -}; - - -/** - * Returns the text formatter used by this console - * @return {!goog.debug.TextFormatter} The text formatter. - */ -goog.debug.Console.prototype.getFormatter = function() { - return this.formatter_; -}; - - -/** - * Sets whether we are currently capturing logger output. - * @param {boolean} capturing Whether to capture logger output. - */ -goog.debug.Console.prototype.setCapturing = function(capturing) { - if (capturing == this.isCapturing_) { - return; - } - - // attach or detach handler from the root logger - var rootLogger = goog.debug.LogManager.getRoot(); - if (capturing) { - rootLogger.addHandler(this.publishHandler_); - } else { - rootLogger.removeHandler(this.publishHandler_); - this.logBuffer = ''; - } - this.isCapturing_ = capturing; -}; - - -/** - * Adds a log record. - * @param {goog.debug.LogRecord} logRecord The log entry. - */ -goog.debug.Console.prototype.addLogRecord = function(logRecord) { - - // Check to see if the log record is filtered or not. - if (this.filteredLoggers_[logRecord.getLoggerName()]) { - return; - } - - var record = this.formatter_.formatRecord(logRecord); - var console = goog.debug.Console.console_; - if (console) { - switch (logRecord.getLevel()) { - case goog.debug.Logger.Level.SHOUT: - goog.debug.Console.logToConsole_(console, 'info', record); - break; - case goog.debug.Logger.Level.SEVERE: - goog.debug.Console.logToConsole_(console, 'error', record); - break; - case goog.debug.Logger.Level.WARNING: - goog.debug.Console.logToConsole_(console, 'warn', record); - break; - default: - goog.debug.Console.logToConsole_(console, 'debug', record); - break; - } - } else { - this.logBuffer_ += record; - } -}; - - -/** - * Adds a logger name to be filtered. - * @param {string} loggerName the logger name to add. - */ -goog.debug.Console.prototype.addFilter = function(loggerName) { - this.filteredLoggers_[loggerName] = true; -}; - - -/** - * Removes a logger name to be filtered. - * @param {string} loggerName the logger name to remove. - */ -goog.debug.Console.prototype.removeFilter = function(loggerName) { - delete this.filteredLoggers_[loggerName]; -}; - - -/** - * Global console logger instance - * @type {goog.debug.Console} - */ -goog.debug.Console.instance = null; - - -/** - * The console to which to log. This is a property so it can be mocked out in - * this unit test for goog.debug.Console. Using goog.global, as console might be - * used in window-less contexts. - * @type {Object} - * @private - */ -goog.debug.Console.console_ = goog.global['console']; - - -/** - * Sets the console to which to log. - * @param {!Object} console The console to which to log. - */ -goog.debug.Console.setConsole = function(console) { - goog.debug.Console.console_ = console; -}; - - -/** - * Install the console and start capturing if "Debug=true" is in the page URL - */ -goog.debug.Console.autoInstall = function() { - if (!goog.debug.Console.instance) { - goog.debug.Console.instance = new goog.debug.Console(); - } - - if (goog.global.location && - goog.global.location.href.indexOf('Debug=true') != -1) { - goog.debug.Console.instance.setCapturing(true); - } -}; - - -/** - * Show an alert with all of the captured debug information. - * Information is only captured if console is not available - */ -goog.debug.Console.show = function() { - alert(goog.debug.Console.instance.logBuffer_); -}; - - -/** - * Logs the record to the console using the given function. If the function is - * not available on the console object, the log function is used instead. - * @param {!Object} console The console object. - * @param {string} fnName The name of the function to use. - * @param {string} record The record to log. - * @private - */ -goog.debug.Console.logToConsole_ = function(console, fnName, record) { - if (console[fnName]) { - console[fnName](record); - } else { - console.log(record); - } -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utility class that monitors viewport size changes. - * - * @author attila@google.com (Attila Bodis) - * @see ../demos/viewportsizemonitor.html - */ - -goog.provide('goog.dom.ViewportSizeMonitor'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.math.Size'); - - - -/** - * This class can be used to monitor changes in the viewport size. Instances - * dispatch a {@link goog.events.EventType.RESIZE} event when the viewport size - * changes. Handlers can call {@link goog.dom.ViewportSizeMonitor#getSize} to - * get the new viewport size. - * - * Use this class if you want to execute resize/reflow logic each time the - * user resizes the browser window. This class is guaranteed to only dispatch - * {@code RESIZE} events when the pixel dimensions of the viewport change. - * (Internet Explorer fires resize events if any element on the page is resized, - * even if the viewport dimensions are unchanged, which can lead to infinite - * resize loops.) - * - * Example usage: - * <pre> - * var vsm = new goog.dom.ViewportSizeMonitor(); - * goog.events.listen(vsm, goog.events.EventType.RESIZE, function(e) { - * alert('Viewport size changed to ' + vsm.getSize()); - * }); - * </pre> - * - * Manually verified on IE6, IE7, FF2, Opera 11, Safari 4 and Chrome. - * - * @param {Window=} opt_window The window to monitor; defaults to the window in - * which this code is executing. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.dom.ViewportSizeMonitor = function(opt_window) { - goog.dom.ViewportSizeMonitor.base(this, 'constructor'); - - /** - * The window to monitor. Defaults to the window in which the code is running. - * @private {Window} - */ - this.window_ = opt_window || window; - - /** - * Event listener key for window the window resize handler, as returned by - * {@link goog.events.listen}. - * @private {goog.events.Key} - */ - this.listenerKey_ = goog.events.listen(this.window_, - goog.events.EventType.RESIZE, this.handleResize_, false, this); - - /** - * The most recently recorded size of the viewport, in pixels. - * @private {goog.math.Size} - */ - this.size_ = goog.dom.getViewportSize(this.window_); -}; -goog.inherits(goog.dom.ViewportSizeMonitor, goog.events.EventTarget); - - -/** - * Returns a viewport size monitor for the given window. A new one is created - * if it doesn't exist already. This prevents the unnecessary creation of - * multiple spooling monitors for a window. - * @param {Window=} opt_window The window to monitor; defaults to the window in - * which this code is executing. - * @return {!goog.dom.ViewportSizeMonitor} Monitor for the given window. - */ -goog.dom.ViewportSizeMonitor.getInstanceForWindow = function(opt_window) { - var currentWindow = opt_window || window; - var uid = goog.getUid(currentWindow); - - return goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] = - goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] || - new goog.dom.ViewportSizeMonitor(currentWindow); -}; - - -/** - * Removes and disposes a viewport size monitor for the given window if one - * exists. - * @param {Window=} opt_window The window whose monitor should be removed; - * defaults to the window in which this code is executing. - */ -goog.dom.ViewportSizeMonitor.removeInstanceForWindow = function(opt_window) { - var uid = goog.getUid(opt_window || window); - - goog.dispose(goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]); - delete goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]; -}; - - -/** - * Map of window hash code to viewport size monitor for that window, if - * created. - * @type {Object<number,goog.dom.ViewportSizeMonitor>} - * @private - */ -goog.dom.ViewportSizeMonitor.windowInstanceMap_ = {}; - - -/** - * Returns the most recently recorded size of the viewport, in pixels. May - * return null if no window resize event has been handled yet. - * @return {goog.math.Size} The viewport dimensions, in pixels. - */ -goog.dom.ViewportSizeMonitor.prototype.getSize = function() { - // Return a clone instead of the original to preserve encapsulation. - return this.size_ ? this.size_.clone() : null; -}; - - -/** @override */ -goog.dom.ViewportSizeMonitor.prototype.disposeInternal = function() { - goog.dom.ViewportSizeMonitor.superClass_.disposeInternal.call(this); - - if (this.listenerKey_) { - goog.events.unlistenByKey(this.listenerKey_); - this.listenerKey_ = null; - } - - this.window_ = null; - this.size_ = null; -}; - - -/** - * Handles window resize events by measuring the dimensions of the - * viewport and dispatching a {@link goog.events.EventType.RESIZE} event if the - * current dimensions are different from the previous ones. - * @param {goog.events.Event} event The window resize event to handle. - * @private - */ -goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) { - var size = goog.dom.getViewportSize(this.window_); - if (!goog.math.Size.equals(size, this.size_)) { - this.size_ = size; - this.dispatchEvent(goog.events.EventType.RESIZE); - } -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Constant declarations for common key codes. - * - * @author eae@google.com (Emil A Eklund) - * @see ../demos/keyhandler.html - */ - -goog.provide('goog.events.KeyCodes'); - -goog.require('goog.userAgent'); - -goog.forwardDeclare('goog.events.BrowserEvent'); - - -/** - * Key codes for common characters. - * - * This list is not localized and therefore some of the key codes are not - * correct for non US keyboard layouts. See comments below. - * - * @enum {number} - */ -goog.events.KeyCodes = { - WIN_KEY_FF_LINUX: 0, - MAC_ENTER: 3, - BACKSPACE: 8, - TAB: 9, - NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac - ENTER: 13, - SHIFT: 16, - CTRL: 17, - ALT: 18, - PAUSE: 19, - CAPS_LOCK: 20, - ESC: 27, - SPACE: 32, - PAGE_UP: 33, // also NUM_NORTH_EAST - PAGE_DOWN: 34, // also NUM_SOUTH_EAST - END: 35, // also NUM_SOUTH_WEST - HOME: 36, // also NUM_NORTH_WEST - LEFT: 37, // also NUM_WEST - UP: 38, // also NUM_NORTH - RIGHT: 39, // also NUM_EAST - DOWN: 40, // also NUM_SOUTH - PLUS_SIGN: 43, // NOT numpad plus - PRINT_SCREEN: 44, - INSERT: 45, // also NUM_INSERT - DELETE: 46, // also NUM_DELETE - ZERO: 48, - ONE: 49, - TWO: 50, - THREE: 51, - FOUR: 52, - FIVE: 53, - SIX: 54, - SEVEN: 55, - EIGHT: 56, - NINE: 57, - FF_SEMICOLON: 59, // Firefox (Gecko) fires this for semicolon instead of 186 - FF_EQUALS: 61, // Firefox (Gecko) fires this for equals instead of 187 - FF_DASH: 173, // Firefox (Gecko) fires this for dash instead of 189 - QUESTION_MARK: 63, // needs localization - AT_SIGN: 64, - A: 65, - B: 66, - C: 67, - D: 68, - E: 69, - F: 70, - G: 71, - H: 72, - I: 73, - J: 74, - K: 75, - L: 76, - M: 77, - N: 78, - O: 79, - P: 80, - Q: 81, - R: 82, - S: 83, - T: 84, - U: 85, - V: 86, - W: 87, - X: 88, - Y: 89, - Z: 90, - META: 91, // WIN_KEY_LEFT - WIN_KEY_RIGHT: 92, - CONTEXT_MENU: 93, - NUM_ZERO: 96, - NUM_ONE: 97, - NUM_TWO: 98, - NUM_THREE: 99, - NUM_FOUR: 100, - NUM_FIVE: 101, - NUM_SIX: 102, - NUM_SEVEN: 103, - NUM_EIGHT: 104, - NUM_NINE: 105, - NUM_MULTIPLY: 106, - NUM_PLUS: 107, - NUM_MINUS: 109, - NUM_PERIOD: 110, - NUM_DIVISION: 111, - F1: 112, - F2: 113, - F3: 114, - F4: 115, - F5: 116, - F6: 117, - F7: 118, - F8: 119, - F9: 120, - F10: 121, - F11: 122, - F12: 123, - NUMLOCK: 144, - SCROLL_LOCK: 145, - - // OS-specific media keys like volume controls and browser controls. - FIRST_MEDIA_KEY: 166, - LAST_MEDIA_KEY: 183, - - SEMICOLON: 186, // needs localization - DASH: 189, // needs localization - EQUALS: 187, // needs localization - COMMA: 188, // needs localization - PERIOD: 190, // needs localization - SLASH: 191, // needs localization - APOSTROPHE: 192, // needs localization - TILDE: 192, // needs localization - SINGLE_QUOTE: 222, // needs localization - OPEN_SQUARE_BRACKET: 219, // needs localization - BACKSLASH: 220, // needs localization - CLOSE_SQUARE_BRACKET: 221, // needs localization - WIN_KEY: 224, - MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91 - MAC_WK_CMD_LEFT: 91, // WebKit Left Command key fired, same as META - MAC_WK_CMD_RIGHT: 93, // WebKit Right Command key fired, different from META - WIN_IME: 229, - - // "Reserved for future use". Some programs (e.g. the SlingPlayer 2.4 ActiveX - // control) fire this as a hacky way to disable screensavers. - VK_NONAME: 252, - - // We've seen users whose machines fire this keycode at regular one - // second intervals. The common thread among these users is that - // they're all using Dell Inspiron laptops, so we suspect that this - // indicates a hardware/bios problem. - // http://en.community.dell.com/support-forums/laptop/f/3518/p/19285957/19523128.aspx - PHANTOM: 255 -}; - - -/** - * Returns true if the event contains a text modifying key. - * @param {goog.events.BrowserEvent} e A key event. - * @return {boolean} Whether it's a text modifying key. - */ -goog.events.KeyCodes.isTextModifyingKeyEvent = function(e) { - if (e.altKey && !e.ctrlKey || - e.metaKey || - // Function keys don't generate text - e.keyCode >= goog.events.KeyCodes.F1 && - e.keyCode <= goog.events.KeyCodes.F12) { - return false; - } - - // The following keys are quite harmless, even in combination with - // CTRL, ALT or SHIFT. - switch (e.keyCode) { - case goog.events.KeyCodes.ALT: - case goog.events.KeyCodes.CAPS_LOCK: - case goog.events.KeyCodes.CONTEXT_MENU: - case goog.events.KeyCodes.CTRL: - case goog.events.KeyCodes.DOWN: - case goog.events.KeyCodes.END: - case goog.events.KeyCodes.ESC: - case goog.events.KeyCodes.HOME: - case goog.events.KeyCodes.INSERT: - case goog.events.KeyCodes.LEFT: - case goog.events.KeyCodes.MAC_FF_META: - case goog.events.KeyCodes.META: - case goog.events.KeyCodes.NUMLOCK: - case goog.events.KeyCodes.NUM_CENTER: - case goog.events.KeyCodes.PAGE_DOWN: - case goog.events.KeyCodes.PAGE_UP: - case goog.events.KeyCodes.PAUSE: - case goog.events.KeyCodes.PHANTOM: - case goog.events.KeyCodes.PRINT_SCREEN: - case goog.events.KeyCodes.RIGHT: - case goog.events.KeyCodes.SCROLL_LOCK: - case goog.events.KeyCodes.SHIFT: - case goog.events.KeyCodes.UP: - case goog.events.KeyCodes.VK_NONAME: - case goog.events.KeyCodes.WIN_KEY: - case goog.events.KeyCodes.WIN_KEY_RIGHT: - return false; - case goog.events.KeyCodes.WIN_KEY_FF_LINUX: - return !goog.userAgent.GECKO; - default: - return e.keyCode < goog.events.KeyCodes.FIRST_MEDIA_KEY || - e.keyCode > goog.events.KeyCodes.LAST_MEDIA_KEY; - } -}; - - -/** - * Returns true if the key fires a keypress event in the current browser. - * - * Accoridng to MSDN [1] IE only fires keypress events for the following keys: - * - Letters: A - Z (uppercase and lowercase) - * - Numerals: 0 - 9 - * - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ - * - System: ESC, SPACEBAR, ENTER - * - * That's not entirely correct though, for instance there's no distinction - * between upper and lower case letters. - * - * [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx) - * - * Safari is similar to IE, but does not fire keypress for ESC. - * - * Additionally, IE6 does not fire keydown or keypress events for letters when - * the control or alt keys are held down and the shift key is not. IE7 does - * fire keydown in these cases, though, but not keypress. - * - * @param {number} keyCode A key code. - * @param {number=} opt_heldKeyCode Key code of a currently-held key. - * @param {boolean=} opt_shiftKey Whether the shift key is held down. - * @param {boolean=} opt_ctrlKey Whether the control key is held down. - * @param {boolean=} opt_altKey Whether the alt key is held down. - * @return {boolean} Whether it's a key that fires a keypress event. - */ -goog.events.KeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode, - opt_shiftKey, opt_ctrlKey, opt_altKey) { - if (!goog.userAgent.IE && !goog.userAgent.EDGE && - !(goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'))) { - return true; - } - - if (goog.userAgent.MAC && opt_altKey) { - return goog.events.KeyCodes.isCharacterKey(keyCode); - } - - // Alt but not AltGr which is represented as Alt+Ctrl. - if (opt_altKey && !opt_ctrlKey) { - return false; - } - - // Saves Ctrl or Alt + key for IE and WebKit 525+, which won't fire keypress. - // Non-IE browsers and WebKit prior to 525 won't get this far so no need to - // check the user agent. - if (goog.isNumber(opt_heldKeyCode)) { - opt_heldKeyCode = goog.events.KeyCodes.normalizeKeyCode(opt_heldKeyCode); - } - if (!opt_shiftKey && - (opt_heldKeyCode == goog.events.KeyCodes.CTRL || - opt_heldKeyCode == goog.events.KeyCodes.ALT || - goog.userAgent.MAC && - opt_heldKeyCode == goog.events.KeyCodes.META)) { - return false; - } - - // Some keys with Ctrl/Shift do not issue keypress in WEBKIT. - if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && - opt_ctrlKey && opt_shiftKey) { - switch (keyCode) { - case goog.events.KeyCodes.BACKSLASH: - case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: - case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: - case goog.events.KeyCodes.TILDE: - case goog.events.KeyCodes.SEMICOLON: - case goog.events.KeyCodes.DASH: - case goog.events.KeyCodes.EQUALS: - case goog.events.KeyCodes.COMMA: - case goog.events.KeyCodes.PERIOD: - case goog.events.KeyCodes.SLASH: - case goog.events.KeyCodes.APOSTROPHE: - case goog.events.KeyCodes.SINGLE_QUOTE: - return false; - } - } - - // When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it - // continues to fire keydown events as the event repeats. - if (goog.userAgent.IE && opt_ctrlKey && opt_heldKeyCode == keyCode) { - return false; - } - - switch (keyCode) { - case goog.events.KeyCodes.ENTER: - return true; - case goog.events.KeyCodes.ESC: - return !(goog.userAgent.WEBKIT || goog.userAgent.EDGE); - } - - return goog.events.KeyCodes.isCharacterKey(keyCode); -}; - - -/** - * Returns true if the key produces a character. - * This does not cover characters on non-US keyboards (Russian, Hebrew, etc.). - * - * @param {number} keyCode A key code. - * @return {boolean} Whether it's a character key. - */ -goog.events.KeyCodes.isCharacterKey = function(keyCode) { - if (keyCode >= goog.events.KeyCodes.ZERO && - keyCode <= goog.events.KeyCodes.NINE) { - return true; - } - - if (keyCode >= goog.events.KeyCodes.NUM_ZERO && - keyCode <= goog.events.KeyCodes.NUM_MULTIPLY) { - return true; - } - - if (keyCode >= goog.events.KeyCodes.A && - keyCode <= goog.events.KeyCodes.Z) { - return true; - } - - // Safari sends zero key code for non-latin characters. - if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && keyCode == 0) { - return true; - } - - switch (keyCode) { - case goog.events.KeyCodes.SPACE: - case goog.events.KeyCodes.PLUS_SIGN: - case goog.events.KeyCodes.QUESTION_MARK: - case goog.events.KeyCodes.AT_SIGN: - case goog.events.KeyCodes.NUM_PLUS: - case goog.events.KeyCodes.NUM_MINUS: - case goog.events.KeyCodes.NUM_PERIOD: - case goog.events.KeyCodes.NUM_DIVISION: - case goog.events.KeyCodes.SEMICOLON: - case goog.events.KeyCodes.FF_SEMICOLON: - case goog.events.KeyCodes.DASH: - case goog.events.KeyCodes.EQUALS: - case goog.events.KeyCodes.FF_EQUALS: - case goog.events.KeyCodes.COMMA: - case goog.events.KeyCodes.PERIOD: - case goog.events.KeyCodes.SLASH: - case goog.events.KeyCodes.APOSTROPHE: - case goog.events.KeyCodes.SINGLE_QUOTE: - case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: - case goog.events.KeyCodes.BACKSLASH: - case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: - return true; - default: - return false; - } -}; - - -/** - * Normalizes key codes from OS/Browser-specific value to the general one. - * @param {number} keyCode The native key code. - * @return {number} The normalized key code. - */ -goog.events.KeyCodes.normalizeKeyCode = function(keyCode) { - if (goog.userAgent.GECKO) { - return goog.events.KeyCodes.normalizeGeckoKeyCode(keyCode); - } else if (goog.userAgent.MAC && goog.userAgent.WEBKIT) { - return goog.events.KeyCodes.normalizeMacWebKitKeyCode(keyCode); - } else { - return keyCode; - } -}; - - -/** - * Normalizes key codes from their Gecko-specific value to the general one. - * @param {number} keyCode The native key code. - * @return {number} The normalized key code. - */ -goog.events.KeyCodes.normalizeGeckoKeyCode = function(keyCode) { - switch (keyCode) { - case goog.events.KeyCodes.FF_EQUALS: - return goog.events.KeyCodes.EQUALS; - case goog.events.KeyCodes.FF_SEMICOLON: - return goog.events.KeyCodes.SEMICOLON; - case goog.events.KeyCodes.FF_DASH: - return goog.events.KeyCodes.DASH; - case goog.events.KeyCodes.MAC_FF_META: - return goog.events.KeyCodes.META; - case goog.events.KeyCodes.WIN_KEY_FF_LINUX: - return goog.events.KeyCodes.WIN_KEY; - default: - return keyCode; - } -}; - - -/** - * Normalizes key codes from their Mac WebKit-specific value to the general one. - * @param {number} keyCode The native key code. - * @return {number} The normalized key code. - */ -goog.events.KeyCodes.normalizeMacWebKitKeyCode = function(keyCode) { - switch (keyCode) { - case goog.events.KeyCodes.MAC_WK_CMD_RIGHT: // 93 - return goog.events.KeyCodes.META; // 91 - default: - return keyCode; - } -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview This file contains a class for working with keyboard events - * that repeat consistently across browsers and platforms. It also unifies the - * key code so that it is the same in all browsers and platforms. - * - * Different web browsers have very different keyboard event handling. Most - * importantly is that only certain browsers repeat keydown events: - * IE, Opera, FF/Win32, and Safari 3 repeat keydown events. - * FF/Mac and Safari 2 do not. - * - * For the purposes of this code, "Safari 3" means WebKit 525+, when WebKit - * decided that they should try to match IE's key handling behavior. - * Safari 3.0.4, which shipped with Leopard (WebKit 523), has the - * Safari 2 behavior. - * - * Firefox, Safari, Opera prevent on keypress - * - * IE prevents on keydown - * - * Firefox does not fire keypress for shift, ctrl, alt - * Firefox does fire keydown for shift, ctrl, alt, meta - * Firefox does not repeat keydown for shift, ctrl, alt, meta - * - * Firefox does not fire keypress for up and down in an input - * - * Opera fires keypress for shift, ctrl, alt, meta - * Opera does not repeat keypress for shift, ctrl, alt, meta - * - * Safari 2 and 3 do not fire keypress for shift, ctrl, alt - * Safari 2 does not fire keydown for shift, ctrl, alt - * Safari 3 *does* fire keydown for shift, ctrl, alt - * - * IE provides the keycode for keyup/down events and the charcode (in the - * keycode field) for keypress. - * - * Mozilla provides the keycode for keyup/down and the charcode for keypress - * unless it's a non text modifying key in which case the keycode is provided. - * - * Safari 3 provides the keycode and charcode for all events. - * - * Opera provides the keycode for keyup/down event and either the charcode or - * the keycode (in the keycode field) for keypress events. - * - * Firefox x11 doesn't fire keydown events if a another key is already held down - * until the first key is released. This can cause a key event to be fired with - * a keyCode for the first key and a charCode for the second key. - * - * Safari in keypress - * - * charCode keyCode which - * ENTER: 13 13 13 - * F1: 63236 63236 63236 - * F8: 63243 63243 63243 - * ... - * p: 112 112 112 - * P: 80 80 80 - * - * Firefox, keypress: - * - * charCode keyCode which - * ENTER: 0 13 13 - * F1: 0 112 0 - * F8: 0 119 0 - * ... - * p: 112 0 112 - * P: 80 0 80 - * - * Opera, Mac+Win32, keypress: - * - * charCode keyCode which - * ENTER: undefined 13 13 - * F1: undefined 112 0 - * F8: undefined 119 0 - * ... - * p: undefined 112 112 - * P: undefined 80 80 - * - * IE7, keydown - * - * charCode keyCode which - * ENTER: undefined 13 undefined - * F1: undefined 112 undefined - * F8: undefined 119 undefined - * ... - * p: undefined 80 undefined - * P: undefined 80 undefined - * - * @author arv@google.com (Erik Arvidsson) - * @author eae@google.com (Emil A Eklund) - * @see ../demos/keyhandler.html - */ - -goog.provide('goog.events.KeyEvent'); -goog.provide('goog.events.KeyHandler'); -goog.provide('goog.events.KeyHandler.EventType'); - -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.events.KeyCodes'); -goog.require('goog.userAgent'); - - - -/** - * A wrapper around an element that you want to listen to keyboard events on. - * @param {Element|Document=} opt_element The element or document to listen on. - * @param {boolean=} opt_capture Whether to listen for browser events in - * capture phase (defaults to false). - * @constructor - * @extends {goog.events.EventTarget} - * @final - */ -goog.events.KeyHandler = function(opt_element, opt_capture) { - goog.events.EventTarget.call(this); - - if (opt_element) { - this.attach(opt_element, opt_capture); - } -}; -goog.inherits(goog.events.KeyHandler, goog.events.EventTarget); - - -/** - * This is the element that we will listen to the real keyboard events on. - * @type {Element|Document|null} - * @private - */ -goog.events.KeyHandler.prototype.element_ = null; - - -/** - * The key for the key press listener. - * @type {goog.events.Key} - * @private - */ -goog.events.KeyHandler.prototype.keyPressKey_ = null; - - -/** - * The key for the key down listener. - * @type {goog.events.Key} - * @private - */ -goog.events.KeyHandler.prototype.keyDownKey_ = null; - - -/** - * The key for the key up listener. - * @type {goog.events.Key} - * @private - */ -goog.events.KeyHandler.prototype.keyUpKey_ = null; - - -/** - * Used to detect keyboard repeat events. - * @private - * @type {number} - */ -goog.events.KeyHandler.prototype.lastKey_ = -1; - - -/** - * Keycode recorded for key down events. As most browsers don't report the - * keycode in the key press event we need to record it in the key down phase. - * @private - * @type {number} - */ -goog.events.KeyHandler.prototype.keyCode_ = -1; - - -/** - * Alt key recorded for key down events. FF on Mac does not report the alt key - * flag in the key press event, we need to record it in the key down phase. - * @type {boolean} - * @private - */ -goog.events.KeyHandler.prototype.altKey_ = false; - - -/** - * Enum type for the events fired by the key handler - * @enum {string} - */ -goog.events.KeyHandler.EventType = { - KEY: 'key' -}; - - -/** - * An enumeration of key codes that Safari 2 does incorrectly - * @type {Object} - * @private - */ -goog.events.KeyHandler.safariKey_ = { - '3': goog.events.KeyCodes.ENTER, // 13 - '12': goog.events.KeyCodes.NUMLOCK, // 144 - '63232': goog.events.KeyCodes.UP, // 38 - '63233': goog.events.KeyCodes.DOWN, // 40 - '63234': goog.events.KeyCodes.LEFT, // 37 - '63235': goog.events.KeyCodes.RIGHT, // 39 - '63236': goog.events.KeyCodes.F1, // 112 - '63237': goog.events.KeyCodes.F2, // 113 - '63238': goog.events.KeyCodes.F3, // 114 - '63239': goog.events.KeyCodes.F4, // 115 - '63240': goog.events.KeyCodes.F5, // 116 - '63241': goog.events.KeyCodes.F6, // 117 - '63242': goog.events.KeyCodes.F7, // 118 - '63243': goog.events.KeyCodes.F8, // 119 - '63244': goog.events.KeyCodes.F9, // 120 - '63245': goog.events.KeyCodes.F10, // 121 - '63246': goog.events.KeyCodes.F11, // 122 - '63247': goog.events.KeyCodes.F12, // 123 - '63248': goog.events.KeyCodes.PRINT_SCREEN, // 44 - '63272': goog.events.KeyCodes.DELETE, // 46 - '63273': goog.events.KeyCodes.HOME, // 36 - '63275': goog.events.KeyCodes.END, // 35 - '63276': goog.events.KeyCodes.PAGE_UP, // 33 - '63277': goog.events.KeyCodes.PAGE_DOWN, // 34 - '63289': goog.events.KeyCodes.NUMLOCK, // 144 - '63302': goog.events.KeyCodes.INSERT // 45 -}; - - -/** - * An enumeration of key identifiers currently part of the W3C draft for DOM3 - * and their mappings to keyCodes. - * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set - * This is currently supported in Safari and should be platform independent. - * @type {Object} - * @private - */ -goog.events.KeyHandler.keyIdentifier_ = { - 'Up': goog.events.KeyCodes.UP, // 38 - 'Down': goog.events.KeyCodes.DOWN, // 40 - 'Left': goog.events.KeyCodes.LEFT, // 37 - 'Right': goog.events.KeyCodes.RIGHT, // 39 - 'Enter': goog.events.KeyCodes.ENTER, // 13 - 'F1': goog.events.KeyCodes.F1, // 112 - 'F2': goog.events.KeyCodes.F2, // 113 - 'F3': goog.events.KeyCodes.F3, // 114 - 'F4': goog.events.KeyCodes.F4, // 115 - 'F5': goog.events.KeyCodes.F5, // 116 - 'F6': goog.events.KeyCodes.F6, // 117 - 'F7': goog.events.KeyCodes.F7, // 118 - 'F8': goog.events.KeyCodes.F8, // 119 - 'F9': goog.events.KeyCodes.F9, // 120 - 'F10': goog.events.KeyCodes.F10, // 121 - 'F11': goog.events.KeyCodes.F11, // 122 - 'F12': goog.events.KeyCodes.F12, // 123 - 'U+007F': goog.events.KeyCodes.DELETE, // 46 - 'Home': goog.events.KeyCodes.HOME, // 36 - 'End': goog.events.KeyCodes.END, // 35 - 'PageUp': goog.events.KeyCodes.PAGE_UP, // 33 - 'PageDown': goog.events.KeyCodes.PAGE_DOWN, // 34 - 'Insert': goog.events.KeyCodes.INSERT // 45 -}; - - -/** - * If true, the KeyEvent fires on keydown. Otherwise, it fires on keypress. - * - * @type {boolean} - * @private - */ -goog.events.KeyHandler.USES_KEYDOWN_ = goog.userAgent.IE || - goog.userAgent.EDGE || - goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'); - - -/** - * If true, the alt key flag is saved during the key down and reused when - * handling the key press. FF on Mac does not set the alt flag in the key press - * event. - * @type {boolean} - * @private - */ -goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_ = goog.userAgent.MAC && - goog.userAgent.GECKO; - - -/** - * Records the keycode for browsers that only returns the keycode for key up/ - * down events. For browser/key combinations that doesn't trigger a key pressed - * event it also fires the patched key event. - * @param {goog.events.BrowserEvent} e The key down event. - * @private - */ -goog.events.KeyHandler.prototype.handleKeyDown_ = function(e) { - // Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window - // before we've caught a key-up event. If the last-key was one of these we - // reset the state. - if (goog.userAgent.WEBKIT || goog.userAgent.EDGE) { - if (this.lastKey_ == goog.events.KeyCodes.CTRL && !e.ctrlKey || - this.lastKey_ == goog.events.KeyCodes.ALT && !e.altKey || - goog.userAgent.MAC && - this.lastKey_ == goog.events.KeyCodes.META && !e.metaKey) { - this.resetState(); - } - } - - if (this.lastKey_ == -1) { - if (e.ctrlKey && e.keyCode != goog.events.KeyCodes.CTRL) { - this.lastKey_ = goog.events.KeyCodes.CTRL; - } else if (e.altKey && e.keyCode != goog.events.KeyCodes.ALT) { - this.lastKey_ = goog.events.KeyCodes.ALT; - } else if (e.metaKey && e.keyCode != goog.events.KeyCodes.META) { - this.lastKey_ = goog.events.KeyCodes.META; - } - } - - if (goog.events.KeyHandler.USES_KEYDOWN_ && - !goog.events.KeyCodes.firesKeyPressEvent(e.keyCode, - this.lastKey_, e.shiftKey, e.ctrlKey, e.altKey)) { - this.handleEvent(e); - } else { - this.keyCode_ = goog.events.KeyCodes.normalizeKeyCode(e.keyCode); - if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) { - this.altKey_ = e.altKey; - } - } -}; - - -/** - * Resets the stored previous values. Needed to be called for webkit which will - * not generate a key up for meta key operations. This should only be called - * when having finished with repeat key possiblities. - */ -goog.events.KeyHandler.prototype.resetState = function() { - this.lastKey_ = -1; - this.keyCode_ = -1; -}; - - -/** - * Clears the stored previous key value, resetting the key repeat status. Uses - * -1 because the Safari 3 Windows beta reports 0 for certain keys (like Home - * and End.) - * @param {goog.events.BrowserEvent} e The keyup event. - * @private - */ -goog.events.KeyHandler.prototype.handleKeyup_ = function(e) { - this.resetState(); - this.altKey_ = e.altKey; -}; - - -/** - * Handles the events on the element. - * @param {goog.events.BrowserEvent} e The keyboard event sent from the - * browser. - */ -goog.events.KeyHandler.prototype.handleEvent = function(e) { - var be = e.getBrowserEvent(); - var keyCode, charCode; - var altKey = be.altKey; - - // IE reports the character code in the keyCode field for keypress events. - // There are two exceptions however, Enter and Escape. - if (goog.userAgent.IE && e.type == goog.events.EventType.KEYPRESS) { - keyCode = this.keyCode_; - charCode = keyCode != goog.events.KeyCodes.ENTER && - keyCode != goog.events.KeyCodes.ESC ? - be.keyCode : 0; - - // Safari reports the character code in the keyCode field for keypress - // events but also has a charCode field. - } else if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && - e.type == goog.events.EventType.KEYPRESS) { - keyCode = this.keyCode_; - charCode = be.charCode >= 0 && be.charCode < 63232 && - goog.events.KeyCodes.isCharacterKey(keyCode) ? - be.charCode : 0; - - // Opera reports the keycode or the character code in the keyCode field. - } else if (goog.userAgent.OPERA && !goog.userAgent.WEBKIT) { - keyCode = this.keyCode_; - charCode = goog.events.KeyCodes.isCharacterKey(keyCode) ? - be.keyCode : 0; - - // Mozilla reports the character code in the charCode field. - } else { - keyCode = be.keyCode || this.keyCode_; - charCode = be.charCode || 0; - if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) { - altKey = this.altKey_; - } - // On the Mac, shift-/ triggers a question mark char code and no key code - // (normalized to WIN_KEY), so we synthesize the latter. - if (goog.userAgent.MAC && - charCode == goog.events.KeyCodes.QUESTION_MARK && - keyCode == goog.events.KeyCodes.WIN_KEY) { - keyCode = goog.events.KeyCodes.SLASH; - } - } - - keyCode = goog.events.KeyCodes.normalizeKeyCode(keyCode); - var key = keyCode; - var keyIdentifier = be.keyIdentifier; - - // Correct the key value for certain browser-specific quirks. - if (keyCode) { - if (keyCode >= 63232 && keyCode in goog.events.KeyHandler.safariKey_) { - // NOTE(nicksantos): Safari 3 has fixed this problem, - // this is only needed for Safari 2. - key = goog.events.KeyHandler.safariKey_[keyCode]; - } else { - - // Safari returns 25 for Shift+Tab instead of 9. - if (keyCode == 25 && e.shiftKey) { - key = 9; - } - } - } else if (keyIdentifier && - keyIdentifier in goog.events.KeyHandler.keyIdentifier_) { - // This is needed for Safari Windows because it currently doesn't give a - // keyCode/which for non printable keys. - key = goog.events.KeyHandler.keyIdentifier_[keyIdentifier]; - } - - // If we get the same keycode as a keydown/keypress without having seen a - // keyup event, then this event was caused by key repeat. - var repeat = key == this.lastKey_; - this.lastKey_ = key; - - var event = new goog.events.KeyEvent(key, charCode, repeat, be); - event.altKey = altKey; - this.dispatchEvent(event); -}; - - -/** - * Returns the element listened on for the real keyboard events. - * @return {Element|Document|null} The element listened on for the real - * keyboard events. - */ -goog.events.KeyHandler.prototype.getElement = function() { - return this.element_; -}; - - -/** - * Adds the proper key event listeners to the element. - * @param {Element|Document} element The element to listen on. - * @param {boolean=} opt_capture Whether to listen for browser events in - * capture phase (defaults to false). - */ -goog.events.KeyHandler.prototype.attach = function(element, opt_capture) { - if (this.keyUpKey_) { - this.detach(); - } - - this.element_ = element; - - this.keyPressKey_ = goog.events.listen(this.element_, - goog.events.EventType.KEYPRESS, - this, - opt_capture); - - // Most browsers (Safari 2 being the notable exception) doesn't include the - // keyCode in keypress events (IE has the char code in the keyCode field and - // Mozilla only included the keyCode if there's no charCode). Thus we have to - // listen for keydown to capture the keycode. - this.keyDownKey_ = goog.events.listen(this.element_, - goog.events.EventType.KEYDOWN, - this.handleKeyDown_, - opt_capture, - this); - - - this.keyUpKey_ = goog.events.listen(this.element_, - goog.events.EventType.KEYUP, - this.handleKeyup_, - opt_capture, - this); -}; - - -/** - * Removes the listeners that may exist. - */ -goog.events.KeyHandler.prototype.detach = function() { - if (this.keyPressKey_) { - goog.events.unlistenByKey(this.keyPressKey_); - goog.events.unlistenByKey(this.keyDownKey_); - goog.events.unlistenByKey(this.keyUpKey_); - this.keyPressKey_ = null; - this.keyDownKey_ = null; - this.keyUpKey_ = null; - } - this.element_ = null; - this.lastKey_ = -1; - this.keyCode_ = -1; -}; - - -/** @override */ -goog.events.KeyHandler.prototype.disposeInternal = function() { - goog.events.KeyHandler.superClass_.disposeInternal.call(this); - this.detach(); -}; - - - -/** - * This class is used for the goog.events.KeyHandler.EventType.KEY event and - * it overrides the key code with the fixed key code. - * @param {number} keyCode The adjusted key code. - * @param {number} charCode The unicode character code. - * @param {boolean} repeat Whether this event was generated by keyboard repeat. - * @param {Event} browserEvent Browser event object. - * @constructor - * @extends {goog.events.BrowserEvent} - * @final - */ -goog.events.KeyEvent = function(keyCode, charCode, repeat, browserEvent) { - goog.events.BrowserEvent.call(this, browserEvent); - this.type = goog.events.KeyHandler.EventType.KEY; - - /** - * Keycode of key press. - * @type {number} - */ - this.keyCode = keyCode; - - /** - * Unicode character code. - * @type {number} - */ - this.charCode = charCode; - - /** - * True if this event was generated by keyboard auto-repeat (i.e., the user is - * holding the key down.) - * @type {boolean} - */ - this.repeat = repeat; -}; -goog.inherits(goog.events.KeyEvent, goog.events.BrowserEvent); - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview This event wrapper will dispatch an event when the user uses - * the mouse wheel to scroll an element. You can get the direction by checking - * the deltaX and deltaY properties of the event. - * - * This class aims to smooth out inconsistencies between browser platforms with - * regards to mousewheel events, but we do not cover every possible - * software/hardware combination out there, some of which occasionally produce - * very large deltas in mousewheel events. If your application wants to guard - * against extremely large deltas, use the setMaxDeltaX and setMaxDeltaY APIs - * to set maximum values that make sense for your application. - * - * @author arv@google.com (Erik Arvidsson) - * @see ../demos/mousewheelhandler.html - */ - -goog.provide('goog.events.MouseWheelEvent'); -goog.provide('goog.events.MouseWheelHandler'); -goog.provide('goog.events.MouseWheelHandler.EventType'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); -goog.require('goog.math'); -goog.require('goog.style'); -goog.require('goog.userAgent'); - - - -/** - * This event handler allows you to catch mouse wheel events in a consistent - * manner. - * @param {Element|Document} element The element to listen to the mouse wheel - * event on. - * @param {boolean=} opt_capture Whether to handle the mouse wheel event in - * capture phase. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.events.MouseWheelHandler = function(element, opt_capture) { - goog.events.EventTarget.call(this); - - /** - * This is the element that we will listen to the real mouse wheel events on. - * @type {Element|Document} - * @private - */ - this.element_ = element; - - var rtlElement = goog.dom.isElement(this.element_) ? - /** @type {Element} */ (this.element_) : - (this.element_ ? /** @type {Document} */ (this.element_).body : null); - - /** - * True if the element exists and is RTL, false otherwise. - * @type {boolean} - * @private - */ - this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement); - - var type = goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel'; - - /** - * The key returned from the goog.events.listen. - * @type {goog.events.Key} - * @private - */ - this.listenKey_ = goog.events.listen(this.element_, type, this, opt_capture); -}; -goog.inherits(goog.events.MouseWheelHandler, goog.events.EventTarget); - - -/** - * Enum type for the events fired by the mouse wheel handler. - * @enum {string} - */ -goog.events.MouseWheelHandler.EventType = { - MOUSEWHEEL: 'mousewheel' -}; - - -/** - * Optional maximum magnitude for x delta on each mousewheel event. - * @type {number|undefined} - * @private - */ -goog.events.MouseWheelHandler.prototype.maxDeltaX_; - - -/** - * Optional maximum magnitude for y delta on each mousewheel event. - * @type {number|undefined} - * @private - */ -goog.events.MouseWheelHandler.prototype.maxDeltaY_; - - -/** - * @param {number} maxDeltaX Maximum magnitude for x delta on each mousewheel - * event. Should be non-negative. - */ -goog.events.MouseWheelHandler.prototype.setMaxDeltaX = function(maxDeltaX) { - this.maxDeltaX_ = maxDeltaX; -}; - - -/** - * @param {number} maxDeltaY Maximum magnitude for y delta on each mousewheel - * event. Should be non-negative. - */ -goog.events.MouseWheelHandler.prototype.setMaxDeltaY = function(maxDeltaY) { - this.maxDeltaY_ = maxDeltaY; -}; - - -/** - * Handles the events on the element. - * @param {goog.events.BrowserEvent} e The underlying browser event. - */ -goog.events.MouseWheelHandler.prototype.handleEvent = function(e) { - var deltaX = 0; - var deltaY = 0; - var detail = 0; - var be = e.getBrowserEvent(); - if (be.type == 'mousewheel') { - var wheelDeltaScaleFactor = 1; - if (goog.userAgent.IE || - goog.userAgent.WEBKIT && - (goog.userAgent.WINDOWS || goog.userAgent.isVersionOrHigher('532.0'))) { - // In IE we get a multiple of 120; we adjust to a multiple of 3 to - // represent number of lines scrolled (like Gecko). - // Newer versions of Webkit match IE behavior, and WebKit on - // Windows also matches IE behavior. - // See bug https://bugs.webkit.org/show_bug.cgi?id=24368 - wheelDeltaScaleFactor = 40; - } - - detail = goog.events.MouseWheelHandler.smartScale_( - -be.wheelDelta, wheelDeltaScaleFactor); - if (goog.isDef(be.wheelDeltaX)) { - // Webkit has two properties to indicate directional scroll, and - // can scroll both directions at once. - deltaX = goog.events.MouseWheelHandler.smartScale_( - -be.wheelDeltaX, wheelDeltaScaleFactor); - deltaY = goog.events.MouseWheelHandler.smartScale_( - -be.wheelDeltaY, wheelDeltaScaleFactor); - } else { - deltaY = detail; - } - - // Historical note: Opera (pre 9.5) used to negate the detail value. - } else { // Gecko - // Gecko returns multiple of 3 (representing the number of lines scrolled) - detail = be.detail; - - // Gecko sometimes returns really big values if the user changes settings to - // scroll a whole page per scroll - if (detail > 100) { - detail = 3; - } else if (detail < -100) { - detail = -3; - } - - // Firefox 3.1 adds an axis field to the event to indicate direction of - // scroll. See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events - if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) { - deltaX = detail; - } else { - deltaY = detail; - } - } - - if (goog.isNumber(this.maxDeltaX_)) { - deltaX = goog.math.clamp(deltaX, -this.maxDeltaX_, this.maxDeltaX_); - } - if (goog.isNumber(this.maxDeltaY_)) { - deltaY = goog.math.clamp(deltaY, -this.maxDeltaY_, this.maxDeltaY_); - } - // Don't clamp 'detail', since it could be ambiguous which axis it refers to - // and because it's informally deprecated anyways. - - // For horizontal scrolling we need to flip the value for RTL grids. - if (this.isRtl_) { - deltaX = -deltaX; - } - var newEvent = new goog.events.MouseWheelEvent(detail, be, deltaX, deltaY); - this.dispatchEvent(newEvent); -}; - - -/** - * Helper for scaling down a mousewheel delta by a scale factor, if appropriate. - * @param {number} mouseWheelDelta Delta from a mouse wheel event. Expected to - * be an integer. - * @param {number} scaleFactor Factor to scale the delta down by. Expected to - * be an integer. - * @return {number} Scaled-down delta value, or the original delta if the - * scaleFactor does not appear to be applicable. - * @private - */ -goog.events.MouseWheelHandler.smartScale_ = function(mouseWheelDelta, - scaleFactor) { - // The basic problem here is that in Webkit on Mac and Linux, we can get two - // very different types of mousewheel events: from continuous devices - // (touchpads, Mighty Mouse) or non-continuous devices (normal wheel mice). - // - // Non-continuous devices in Webkit get their wheel deltas scaled up to - // behave like IE. Continuous devices return much smaller unscaled values - // (which most of the time will not be cleanly divisible by the IE scale - // factor), so we should not try to normalize them down. - // - // Detailed discussion: - // https://bugs.webkit.org/show_bug.cgi?id=29601 - // http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063 - if (goog.userAgent.WEBKIT && - (goog.userAgent.MAC || goog.userAgent.LINUX) && - (mouseWheelDelta % scaleFactor) != 0) { - return mouseWheelDelta; - } else { - return mouseWheelDelta / scaleFactor; - } -}; - - -/** @override */ -goog.events.MouseWheelHandler.prototype.disposeInternal = function() { - goog.events.MouseWheelHandler.superClass_.disposeInternal.call(this); - goog.events.unlistenByKey(this.listenKey_); - this.listenKey_ = null; -}; - - - -/** - * A base class for mouse wheel events. This is used with the - * MouseWheelHandler. - * - * @param {number} detail The number of rows the user scrolled. - * @param {Event} browserEvent Browser event object. - * @param {number} deltaX The number of rows the user scrolled in the X - * direction. - * @param {number} deltaY The number of rows the user scrolled in the Y - * direction. - * @constructor - * @extends {goog.events.BrowserEvent} - * @final - */ -goog.events.MouseWheelEvent = function(detail, browserEvent, deltaX, deltaY) { - goog.events.BrowserEvent.call(this, browserEvent); - - this.type = goog.events.MouseWheelHandler.EventType.MOUSEWHEEL; - - /** - * The number of lines the user scrolled - * @type {number} - * NOTE: Informally deprecated. Use deltaX and deltaY instead, they provide - * more information. - */ - this.detail = detail; - - /** - * The number of "lines" scrolled in the X direction. - * - * Note that not all browsers provide enough information to distinguish - * horizontal and vertical scroll events, so for these unsupported browsers, - * we will always have a deltaX of 0, even if the user scrolled their mouse - * wheel or trackpad sideways. - * - * Currently supported browsers are Webkit and Firefox 3.1 or later. - * - * @type {number} - */ - this.deltaX = deltaX; - - /** - * The number of lines scrolled in the Y direction. - * @type {number} - */ - this.deltaY = deltaY; -}; -goog.inherits(goog.events.MouseWheelEvent, goog.events.BrowserEvent); - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Basic strippable logging definitions. - * @see http://go/closurelogging - * - * @author johnlenz@google.com (John Lenz) - */ - -goog.provide('goog.log'); -goog.provide('goog.log.Level'); -goog.provide('goog.log.LogRecord'); -goog.provide('goog.log.Logger'); - -goog.require('goog.debug'); -goog.require('goog.debug.LogManager'); -goog.require('goog.debug.LogRecord'); -goog.require('goog.debug.Logger'); - - -/** @define {boolean} Whether logging is enabled. */ -goog.define('goog.log.ENABLED', goog.debug.LOGGING_ENABLED); - - -/** @const */ -goog.log.ROOT_LOGGER_NAME = goog.debug.Logger.ROOT_LOGGER_NAME; - - - -/** - * @constructor - * @final - */ -goog.log.Logger = goog.debug.Logger; - - - -/** - * @constructor - * @final - */ -goog.log.Level = goog.debug.Logger.Level; - - - -/** - * @constructor - * @final - */ -goog.log.LogRecord = goog.debug.LogRecord; - - -/** - * Finds or creates a logger for a named subsystem. If a logger has already been - * created with the given name it is returned. Otherwise a new logger is - * created. If a new logger is created its log level will be configured based - * on the goog.debug.LogManager configuration and it will configured to also - * send logging output to its parent's handlers. - * @see goog.debug.LogManager - * - * @param {string} name A name for the logger. This should be a dot-separated - * name and should normally be based on the package name or class name of - * the subsystem, such as goog.net.BrowserChannel. - * @param {goog.log.Level=} opt_level If provided, override the - * default logging level with the provided level. - * @return {goog.log.Logger} The named logger or null if logging is disabled. - */ -goog.log.getLogger = function(name, opt_level) { - if (goog.log.ENABLED) { - var logger = goog.debug.LogManager.getLogger(name); - if (opt_level && logger) { - logger.setLevel(opt_level); - } - return logger; - } else { - return null; - } -}; - - -// TODO(johnlenz): try to tighten the types to these functions. -/** - * Adds a handler to the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {goog.log.Logger} logger - * @param {Function} handler Handler function to add. - */ -goog.log.addHandler = function(logger, handler) { - if (goog.log.ENABLED && logger) { - logger.addHandler(handler); - } -}; - - -/** - * Removes a handler from the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {goog.log.Logger} logger - * @param {Function} handler Handler function to remove. - * @return {boolean} Whether the handler was removed. - */ -goog.log.removeHandler = function(logger, handler) { - if (goog.log.ENABLED && logger) { - return logger.removeHandler(handler); - } else { - return false; - } -}; - - -/** - * Logs a message. If the logger is currently enabled for the - * given message level then the given message is forwarded to all the - * registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.log.Level} level One of the level identifiers. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error|Object=} opt_exception An exception associated with the - * message. - */ -goog.log.log = function(logger, level, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.log(level, msg, opt_exception); - } -}; - - -/** - * Logs a message at the Level.SEVERE level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.log.error = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.severe(msg, opt_exception); - } -}; - - -/** - * Logs a message at the Level.WARNING level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.log.warning = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.warning(msg, opt_exception); - } -}; - - -/** - * Logs a message at the Level.INFO level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.log.info = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.info(msg, opt_exception); - } -}; - - -/** - * Logs a message at the Level.Fine level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.log.fine = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.fine(msg, opt_exception); - } -}; - -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.PointerEvent'); - - -goog.require('goog.events'); -goog.require('goog.events.Event'); - - - -/** - * A class for pointer events. - * - * This class is used as an abstraction for mouse events, - * touch events and even native pointer events. - * - * @constructor - * @extends {goog.events.Event} - * @param {string} type The type of the event to create. - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object.<string, ?>=} opt_eventDict An optional dictionary of - * initial event properties. - */ -ol.pointer.PointerEvent = function(type, browserEvent, opt_eventDict) { - goog.base(this, type); - - /** - * @const - * @type {goog.events.BrowserEvent} - */ - this.browserEvent = browserEvent; - - var eventDict = opt_eventDict ? opt_eventDict : {}; - - /** - * @type {number} - */ - this.buttons = this.getButtons_(eventDict); - - /** - * @type {number} - */ - this.pressure = this.getPressure_(eventDict, this.buttons); - - // MouseEvent related properties - - /** - * @type {boolean} - */ - this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false; - - /** - * @type {boolean} - */ - this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false; - - /** - * @type {Object} - */ - this.view = 'view' in eventDict ? eventDict['view'] : null; - - /** - * @type {number} - */ - this.detail = 'detail' in eventDict ? eventDict['detail'] : null; - - /** - * @type {number} - */ - this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0; - - /** - * @type {number} - */ - this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0; - - /** - * @type {number} - */ - this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0; - - /** - * @type {number} - */ - this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0; - - /** - * @type {boolean} - */ - this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false; - - /** - * @type {boolean} - */ - this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false; - - /** - * @type {boolean} - */ - this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false; - - /** - * @type {boolean} - */ - this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false; - - /** - * @type {number} - */ - this.button = 'button' in eventDict ? eventDict['button'] : 0; - - /** - * @type {Node} - */ - this.relatedTarget = 'relatedTarget' in eventDict ? - eventDict['relatedTarget'] : null; - - // PointerEvent related properties - - /** - * @const - * @type {number} - */ - this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0; - - /** - * @type {number} - */ - this.width = 'width' in eventDict ? eventDict['width'] : 0; - - /** - * @type {number} - */ - this.height = 'height' in eventDict ? eventDict['height'] : 0; - - /** - * @type {number} - */ - this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0; - - /** - * @type {number} - */ - this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0; - - /** - * @type {string} - */ - this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : ''; - - /** - * @type {number} - */ - this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0; - - /** - * @type {boolean} - */ - this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false; - - // keep the semantics of preventDefault - if (browserEvent.preventDefault) { - this.preventDefault = function() { - browserEvent.preventDefault(); - }; - } -}; -goog.inherits(ol.pointer.PointerEvent, goog.events.Event); - - -/** - * @private - * @param {Object.<string, ?>} eventDict - * @return {number} - */ -ol.pointer.PointerEvent.prototype.getButtons_ = function(eventDict) { - // According to the w3c spec, - // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button - // MouseEvent.button == 0 can mean either no mouse button depressed, or the - // left mouse button depressed. - // - // As of now, the only way to distinguish between the two states of - // MouseEvent.button is by using the deprecated MouseEvent.which property, as - // this maps mouse buttons to positive integers > 0, and uses 0 to mean that - // no mouse button is held. - // - // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation, - // but initMouseEvent does not expose an argument with which to set - // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set - // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations - // of app developers. - // - // The only way to propagate the correct state of MouseEvent.which and - // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0 - // is to call initMouseEvent with a buttonArg value of -1. - // - // This is fixed with DOM Level 4's use of buttons - var buttons; - if (eventDict.buttons || ol.pointer.PointerEvent.HAS_BUTTONS) { - buttons = eventDict.buttons; - } else { - switch (eventDict.which) { - case 1: buttons = 1; break; - case 2: buttons = 4; break; - case 3: buttons = 2; break; - default: buttons = 0; - } - } - return buttons; -}; - - -/** - * @private - * @param {Object.<string, ?>} eventDict - * @param {number} buttons - * @return {number} - */ -ol.pointer.PointerEvent.prototype.getPressure_ = function(eventDict, buttons) { - // Spec requires that pointers without pressure specified use 0.5 for down - // state and 0 for up state. - var pressure = 0; - if (eventDict.pressure) { - pressure = eventDict.pressure; - } else { - pressure = buttons ? 0.5 : 0; - } - return pressure; -}; - - -/** - * Is the `buttons` property supported? - * @type {boolean} - */ -ol.pointer.PointerEvent.HAS_BUTTONS = false; - - -/** - * Checks if the `buttons` property is supported. - */ -(function() { - try { - var ev = new MouseEvent('click', {buttons: 1}); - ol.pointer.PointerEvent.HAS_BUTTONS = ev.buttons === 1; - } catch (e) { - } -})(); - -// FIXME add tests for browser features (Modernizr?) - -goog.provide('ol.dom'); -goog.provide('ol.dom.BrowserFeature'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.userAgent'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); - - -/** - * Create an html canvas element and returns its 2d context. - * @param {number=} opt_width Canvas width. - * @param {number=} opt_height Canvas height. - * @return {CanvasRenderingContext2D} - */ -ol.dom.createCanvasContext2D = function(opt_width, opt_height) { - var canvas = goog.dom.createElement('CANVAS'); - if (opt_width) { - canvas.width = opt_width; - } - if (opt_height) { - canvas.height = opt_height; - } - return canvas.getContext('2d'); -}; - - -/** - * Detect 2d transform. - * Adapted from http://stackoverflow.com/q/5661671/130442 - * http://caniuse.com/#feat=transforms2d - * @return {boolean} - */ -ol.dom.canUseCssTransform = (function() { - var canUseCssTransform; - return function() { - if (canUseCssTransform === undefined) { - goog.asserts.assert(document.body, - 'document.body should not be null'); - if (!goog.global.getComputedStyle) { - // this browser is ancient - canUseCssTransform = false; - } else { - var el = goog.dom.createElement('P'), - has2d, - transforms = { - 'webkitTransform': '-webkit-transform', - 'OTransform': '-o-transform', - 'msTransform': '-ms-transform', - 'MozTransform': '-moz-transform', - 'transform': 'transform' - }; - document.body.appendChild(el); - for (var t in transforms) { - if (t in el.style) { - el.style[t] = 'translate(1px,1px)'; - has2d = goog.global.getComputedStyle(el).getPropertyValue( - transforms[t]); - } - } - goog.dom.removeNode(el); - - canUseCssTransform = (has2d && has2d !== 'none'); - } - } - return canUseCssTransform; - }; -}()); - - -/** - * Detect 3d transform. - * Adapted from http://stackoverflow.com/q/5661671/130442 - * http://caniuse.com/#feat=transforms3d - * @return {boolean} - */ -ol.dom.canUseCssTransform3D = (function() { - var canUseCssTransform3D; - return function() { - if (canUseCssTransform3D === undefined) { - goog.asserts.assert(document.body, - 'document.body should not be null'); - if (!goog.global.getComputedStyle) { - // this browser is ancient - canUseCssTransform3D = false; - } else { - var el = goog.dom.createElement('P'), - has3d, - transforms = { - 'webkitTransform': '-webkit-transform', - 'OTransform': '-o-transform', - 'msTransform': '-ms-transform', - 'MozTransform': '-moz-transform', - 'transform': 'transform' - }; - document.body.appendChild(el); - for (var t in transforms) { - if (t in el.style) { - el.style[t] = 'translate3d(1px,1px,1px)'; - has3d = goog.global.getComputedStyle(el).getPropertyValue( - transforms[t]); - } - } - goog.dom.removeNode(el); - - canUseCssTransform3D = (has3d && has3d !== 'none'); - } - } - return canUseCssTransform3D; - }; -}()); - - -/** - * @param {Element} element Element. - * @param {string} value Value. - */ -ol.dom.setTransform = function(element, value) { - var style = element.style; - style.WebkitTransform = value; - style.MozTransform = value; - style.OTransform = value; - style.msTransform = value; - style.transform = value; - - // IE 9+ seems to assume transform-origin: 100% 100%; for some unknown reason - if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9.0')) { - element.style.transformOrigin = '0 0'; - } -}; - - -/** - * @param {!Element} element Element. - * @param {goog.vec.Mat4.Number} transform Matrix. - * @param {number=} opt_precision Precision. - */ -ol.dom.transformElement2D = function(element, transform, opt_precision) { - // using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer - // matrix3d() - var i; - if (ol.dom.canUseCssTransform3D()) { - var value3D; - - if (opt_precision !== undefined) { - /** @type {Array.<string>} */ - var strings3D = new Array(16); - for (i = 0; i < 16; ++i) { - strings3D[i] = transform[i].toFixed(opt_precision); - } - value3D = strings3D.join(','); - } else { - value3D = transform.join(','); - } - ol.dom.setTransform(element, 'matrix3d(' + value3D + ')'); - } else if (ol.dom.canUseCssTransform()) { - /** @type {Array.<number>} */ - var transform2D = [ - goog.vec.Mat4.getElement(transform, 0, 0), - goog.vec.Mat4.getElement(transform, 1, 0), - goog.vec.Mat4.getElement(transform, 0, 1), - goog.vec.Mat4.getElement(transform, 1, 1), - goog.vec.Mat4.getElement(transform, 0, 3), - goog.vec.Mat4.getElement(transform, 1, 3) - ]; - var value2D; - if (opt_precision !== undefined) { - /** @type {Array.<string>} */ - var strings2D = new Array(6); - for (i = 0; i < 6; ++i) { - strings2D[i] = transform2D[i].toFixed(opt_precision); - } - value2D = strings2D.join(','); - } else { - value2D = transform2D.join(','); - } - ol.dom.setTransform(element, 'matrix(' + value2D + ')'); - } else { - element.style.left = - Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px'; - element.style.top = - Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px'; - - // TODO: Add scaling here. This isn't quite as simple as multiplying - // width/height, because that only changes the container size, not the - // content size. - } -}; - - -/** - * Get the current computed width for the given element including margin, - * padding and border. - * Equivalent to jQuery's `$(el).outerWidth(true)`. - * @param {!Element} element Element. - * @return {number} - */ -ol.dom.outerWidth = function(element) { - var width = element.offsetWidth; - var style = element.currentStyle || window.getComputedStyle(element); - width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); - - return width; -}; - - -/** - * Get the current computed height for the given element including margin, - * padding and border. - * Equivalent to jQuery's `$(el).outerHeight(true)`. - * @param {!Element} element Element. - * @return {number} - */ -ol.dom.outerHeight = function(element) { - var height = element.offsetHeight; - var style = element.currentStyle || window.getComputedStyle(element); - height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10); - - return height; -}; - -goog.provide('ol.webgl'); -goog.provide('ol.webgl.WebGLContextEventType'); - - -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.webgl.CONTEXT_IDS_ = [ - 'experimental-webgl', - 'webgl', - 'webkit-3d', - 'moz-webgl' -]; - - -/** - * @enum {string} - */ -ol.webgl.WebGLContextEventType = { - LOST: 'webglcontextlost', - RESTORED: 'webglcontextrestored' -}; - - -/** - * @param {HTMLCanvasElement} canvas Canvas. - * @param {Object=} opt_attributes Attributes. - * @return {WebGLRenderingContext} WebGL rendering context. - */ -ol.webgl.getContext = function(canvas, opt_attributes) { - var context, i, ii = ol.webgl.CONTEXT_IDS_.length; - for (i = 0; i < ii; ++i) { - try { - context = canvas.getContext(ol.webgl.CONTEXT_IDS_[i], opt_attributes); - if (context) { - return /** @type {!WebGLRenderingContext} */ (context); - } - } catch (e) { - } - } - return null; -}; - -goog.provide('ol.has'); - -goog.require('goog.dom'); -goog.require('ol'); -goog.require('ol.dom'); -goog.require('ol.webgl'); - - -/** - * The ratio between physical pixels and device-independent pixels - * (dips) on the device (`window.devicePixelRatio`). - * @const - * @type {number} - * @api stable - */ -ol.has.DEVICE_PIXEL_RATIO = goog.global.devicePixelRatio || 1; - - -/** - * True if the browser's Canvas implementation implements {get,set}LineDash. - * @type {boolean} - */ -ol.has.CANVAS_LINE_DASH = false; - - -/** - * True if both the library and browser support Canvas. Always `false` - * if `ol.ENABLE_CANVAS` is set to `false` at compile time. - * @const - * @type {boolean} - * @api stable - */ -ol.has.CANVAS = ol.ENABLE_CANVAS && ( - /** - * @return {boolean} Canvas supported. - */ - function() { - if (!('HTMLCanvasElement' in goog.global)) { - return false; - } - try { - var context = ol.dom.createCanvasContext2D(); - if (!context) { - return false; - } else { - if (context.setLineDash !== undefined) { - ol.has.CANVAS_LINE_DASH = true; - } - return true; - } - } catch (e) { - return false; - } - })(); - - -/** - * Indicates if DeviceOrientation is supported in the user's browser. - * @const - * @type {boolean} - * @api stable - */ -ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in goog.global; - - -/** - * True if `ol.ENABLE_DOM` is set to `true` at compile time. - * @const - * @type {boolean} - */ -ol.has.DOM = ol.ENABLE_DOM; - - -/** - * Is HTML5 geolocation supported in the current browser? - * @const - * @type {boolean} - * @api stable - */ -ol.has.GEOLOCATION = 'geolocation' in goog.global.navigator; - - -/** - * True if browser supports touch events. - * @const - * @type {boolean} - * @api stable - */ -ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in goog.global; - - -/** - * True if browser supports pointer events. - * @const - * @type {boolean} - */ -ol.has.POINTER = 'PointerEvent' in goog.global; - - -/** - * True if browser supports ms pointer events (IE 10). - * @const - * @type {boolean} - */ -ol.has.MSPOINTER = !!(goog.global.navigator.msPointerEnabled); - - -/** - * True if both OpenLayers and browser support WebGL. Always `false` - * if `ol.ENABLE_WEBGL` is set to `false` at compile time. - * @const - * @type {boolean} - * @api stable - */ -ol.has.WEBGL; - - -(function() { - if (ol.ENABLE_WEBGL) { - var hasWebGL = false; - var textureSize; - var /** @type {Array.<string>} */ extensions = []; - - if ('WebGLRenderingContext' in goog.global) { - try { - var canvas = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - var gl = ol.webgl.getContext(canvas, { - failIfMajorPerformanceCaveat: true - }); - if (gl) { - hasWebGL = true; - textureSize = /** @type {number} */ - (gl.getParameter(gl.MAX_TEXTURE_SIZE)); - extensions = gl.getSupportedExtensions(); - } - } catch (e) {} - } - ol.has.WEBGL = hasWebGL; - ol.WEBGL_EXTENSIONS = extensions; - ol.WEBGL_MAX_TEXTURE_SIZE = textureSize; - } -})(); - -goog.provide('ol.pointer.EventSource'); - -goog.require('goog.events.BrowserEvent'); - - - -/** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @param {!Object.<string, function(goog.events.BrowserEvent)>} mapping - * @constructor - */ -ol.pointer.EventSource = function(dispatcher, mapping) { - /** - * @type {ol.pointer.PointerEventHandler} - */ - this.dispatcher = dispatcher; - - /** - * @private - * @const - * @type {!Object.<string, function(goog.events.BrowserEvent)>} - */ - this.mapping_ = mapping; -}; - - -/** - * List of events supported by this source. - * @return {Array.<string>} Event names - */ -ol.pointer.EventSource.prototype.getEvents = function() { - return Object.keys(this.mapping_); -}; - - -/** - * Returns a mapping between the supported event types and - * the handlers that should handle an event. - * @return {Object.<string, function(goog.events.BrowserEvent)>} - * Event/Handler mapping - */ -ol.pointer.EventSource.prototype.getMapping = function() { - return this.mapping_; -}; - - -/** - * Returns the handler that should handle a given event type. - * @param {string} eventType - * @return {function(goog.events.BrowserEvent)} Handler - */ -ol.pointer.EventSource.prototype.getHandlerForEvent = function(eventType) { - return this.mapping_[eventType]; -}; - -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.MouseSource'); - -goog.require('ol.pointer.EventSource'); - - - -/** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @constructor - * @extends {ol.pointer.EventSource} - */ -ol.pointer.MouseSource = function(dispatcher) { - var mapping = { - 'mousedown': this.mousedown, - 'mousemove': this.mousemove, - 'mouseup': this.mouseup, - 'mouseover': this.mouseover, - 'mouseout': this.mouseout - }; - goog.base(this, dispatcher, mapping); - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = dispatcher.pointerMap; - - /** - * @const - * @type {Array.<ol.Pixel>} - */ - this.lastTouches = []; -}; -goog.inherits(ol.pointer.MouseSource, ol.pointer.EventSource); - - -/** - * @const - * @type {number} - */ -ol.pointer.MouseSource.POINTER_ID = 1; - - -/** - * @const - * @type {string} - */ -ol.pointer.MouseSource.POINTER_TYPE = 'mouse'; - - -/** - * Radius around touchend that swallows mouse events. - * - * @const - * @type {number} - */ -ol.pointer.MouseSource.DEDUP_DIST = 25; - - -/** - * Detect if a mouse event was simulated from a touch by - * checking if previously there was a touch event at the - * same position. - * - * FIXME - Known problem with the native Android browser on - * Samsung GT-I9100 (Android 4.1.2): - * In case the page is scrolled, this function does not work - * correctly when a canvas is used (WebGL or canvas renderer). - * Mouse listeners on canvas elements (for this browser), create - * two mouse events: One 'good' and one 'bad' one (on other browsers or - * when a div is used, there is only one event). For the 'bad' one, - * clientX/clientY and also pageX/pageY are wrong when the page - * is scrolled. Because of that, this function can not detect if - * the events were simulated from a touch event. As result, a - * pointer event at a wrong position is dispatched, which confuses - * the map interactions. - * It is unclear, how one can get the correct position for the event - * or detect that the positions are invalid. - * - * @private - * @param {goog.events.BrowserEvent} inEvent - * @return {boolean} True, if the event was generated by a touch. - */ -ol.pointer.MouseSource.prototype.isEventSimulatedFromTouch_ = - function(inEvent) { - var lts = this.lastTouches; - var x = inEvent.clientX, y = inEvent.clientY; - for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) { - // simulated mouse events will be swallowed near a primary touchend - var dx = Math.abs(x - t[0]), dy = Math.abs(y - t[1]); - if (dx <= ol.pointer.MouseSource.DEDUP_DIST && - dy <= ol.pointer.MouseSource.DEDUP_DIST) { - return true; - } - } - return false; -}; - - -/** - * Creates a copy of the original event that will be used - * for the fake pointer event. - * - * @param {goog.events.BrowserEvent} inEvent - * @param {ol.pointer.PointerEventHandler} dispatcher - * @return {Object} - */ -ol.pointer.MouseSource.prepareEvent = function(inEvent, dispatcher) { - var e = dispatcher.cloneEvent(inEvent, inEvent.getBrowserEvent()); - - // forward mouse preventDefault - var pd = e.preventDefault; - e.preventDefault = function() { - inEvent.preventDefault(); - pd(); - }; - - e.pointerId = ol.pointer.MouseSource.POINTER_ID; - e.isPrimary = true; - e.pointerType = ol.pointer.MouseSource.POINTER_TYPE; - - return e; -}; - - -/** - * Handler for `mousedown`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.mousedown = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - // TODO(dfreedman) workaround for some elements not sending mouseup - // http://crbug/149091 - if (ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap) { - this.cancel(inEvent); - } - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()] = inEvent; - this.dispatcher.down(e, inEvent); - } -}; - - -/** - * Handler for `mousemove`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.mousemove = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.move(e, inEvent); - } -}; - - -/** - * Handler for `mouseup`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.mouseup = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var p = this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()]; - - if (p && p.button === inEvent.button) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.up(e, inEvent); - this.cleanupMouse(); - } - } -}; - - -/** - * Handler for `mouseover`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.mouseover = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.enterOver(e, inEvent); - } -}; - - -/** - * Handler for `mouseout`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.mouseout = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.leaveOut(e, inEvent); - } -}; - - -/** - * Dispatches a `pointercancel` event. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.cancel = function(inEvent) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.cancel(e, inEvent); - this.cleanupMouse(); -}; - - -/** - * Remove the mouse from the list of active pointers. - */ -ol.pointer.MouseSource.prototype.cleanupMouse = function() { - delete this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()]; -}; - -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.MsSource'); - -goog.require('ol.pointer.EventSource'); - - - -/** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @constructor - * @extends {ol.pointer.EventSource} - */ -ol.pointer.MsSource = function(dispatcher) { - var mapping = { - 'MSPointerDown': this.msPointerDown, - 'MSPointerMove': this.msPointerMove, - 'MSPointerUp': this.msPointerUp, - 'MSPointerOut': this.msPointerOut, - 'MSPointerOver': this.msPointerOver, - 'MSPointerCancel': this.msPointerCancel, - 'MSGotPointerCapture': this.msGotPointerCapture, - 'MSLostPointerCapture': this.msLostPointerCapture - }; - goog.base(this, dispatcher, mapping); - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = dispatcher.pointerMap; - - /** - * @const - * @type {Array.<string>} - */ - this.POINTER_TYPES = [ - '', - 'unavailable', - 'touch', - 'pen', - 'mouse' - ]; -}; -goog.inherits(ol.pointer.MsSource, ol.pointer.EventSource); - - -/** - * Creates a copy of the original event that will be used - * for the fake pointer event. - * - * @private - * @param {goog.events.BrowserEvent} inEvent - * @return {Object} - */ -ol.pointer.MsSource.prototype.prepareEvent_ = function(inEvent) { - var e = inEvent; - if (goog.isNumber(inEvent.getBrowserEvent().pointerType)) { - e = this.dispatcher.cloneEvent(inEvent, inEvent.getBrowserEvent()); - e.pointerType = this.POINTER_TYPES[inEvent.getBrowserEvent().pointerType]; - } - - return e; -}; - - -/** - * Remove this pointer from the list of active pointers. - * @param {number} pointerId - */ -ol.pointer.MsSource.prototype.cleanup = function(pointerId) { - delete this.pointerMap[pointerId.toString()]; -}; - - -/** - * Handler for `msPointerDown`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerDown = function(inEvent) { - this.pointerMap[inEvent.getBrowserEvent().pointerId.toString()] = inEvent; - var e = this.prepareEvent_(inEvent); - this.dispatcher.down(e, inEvent); -}; - - -/** - * Handler for `msPointerMove`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerMove = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.move(e, inEvent); -}; - - -/** - * Handler for `msPointerUp`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerUp = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.up(e, inEvent); - this.cleanup(inEvent.getBrowserEvent().pointerId); -}; - - -/** - * Handler for `msPointerOut`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerOut = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.leaveOut(e, inEvent); -}; - - -/** - * Handler for `msPointerOver`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerOver = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.enterOver(e, inEvent); -}; - - -/** - * Handler for `msPointerCancel`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerCancel = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.cancel(e, inEvent); - this.cleanup(inEvent.getBrowserEvent().pointerId); -}; - - -/** - * Handler for `msLostPointerCapture`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msLostPointerCapture = function(inEvent) { - var e = this.dispatcher.makeEvent('lostpointercapture', - inEvent.getBrowserEvent(), inEvent); - this.dispatcher.dispatchEvent(e); -}; - - -/** - * Handler for `msGotPointerCapture`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msGotPointerCapture = function(inEvent) { - var e = this.dispatcher.makeEvent('gotpointercapture', - inEvent.getBrowserEvent(), inEvent); - this.dispatcher.dispatchEvent(e); -}; - -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.NativeSource'); - -goog.require('ol.pointer.EventSource'); - - - -/** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @constructor - * @extends {ol.pointer.EventSource} - */ -ol.pointer.NativeSource = function(dispatcher) { - var mapping = { - 'pointerdown': this.pointerDown, - 'pointermove': this.pointerMove, - 'pointerup': this.pointerUp, - 'pointerout': this.pointerOut, - 'pointerover': this.pointerOver, - 'pointercancel': this.pointerCancel, - 'gotpointercapture': this.gotPointerCapture, - 'lostpointercapture': this.lostPointerCapture - }; - goog.base(this, dispatcher, mapping); -}; -goog.inherits(ol.pointer.NativeSource, ol.pointer.EventSource); - - -/** - * Handler for `pointerdown`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerDown = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `pointermove`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerMove = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `pointerup`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerUp = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `pointerout`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerOut = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `pointerover`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerOver = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `pointercancel`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerCancel = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `lostpointercapture`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.lostPointerCapture = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `gotpointercapture`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.gotPointerCapture = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.TouchSource'); - -goog.require('goog.array'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.pointer.EventSource'); -goog.require('ol.pointer.MouseSource'); - - - -/** - * @constructor - * @param {ol.pointer.PointerEventHandler} dispatcher - * @param {ol.pointer.MouseSource} mouseSource - * @extends {ol.pointer.EventSource} - */ -ol.pointer.TouchSource = function(dispatcher, mouseSource) { - var mapping = { - 'touchstart': this.touchstart, - 'touchmove': this.touchmove, - 'touchend': this.touchend, - 'touchcancel': this.touchcancel - }; - goog.base(this, dispatcher, mapping); - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = dispatcher.pointerMap; - - /** - * @const - * @type {ol.pointer.MouseSource} - */ - this.mouseSource = mouseSource; - - /** - * @private - * @type {number|undefined} - */ - this.firstTouchId_ = undefined; - - /** - * @private - * @type {number} - */ - this.clickCount_ = 0; - - /** - * @private - * @type {number|undefined} - */ - this.resetId_ = undefined; -}; -goog.inherits(ol.pointer.TouchSource, ol.pointer.EventSource); - - -/** - * Mouse event timeout: This should be long enough to - * ignore compat mouse events made by touch. - * @const - * @type {number} - */ -ol.pointer.TouchSource.DEDUP_TIMEOUT = 2500; - - -/** - * @const - * @type {number} - */ -ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT = 200; - - -/** - * @const - * @type {string} - */ -ol.pointer.TouchSource.POINTER_TYPE = 'touch'; - - -/** - * @private - * @param {Touch} inTouch - * @return {boolean} True, if this is the primary touch. - */ -ol.pointer.TouchSource.prototype.isPrimaryTouch_ = function(inTouch) { - return this.firstTouchId_ === inTouch.identifier; -}; - - -/** - * Set primary touch if there are no pointers, or the only pointer is the mouse. - * @param {Touch} inTouch - * @private - */ -ol.pointer.TouchSource.prototype.setPrimaryTouch_ = function(inTouch) { - var count = goog.object.getCount(this.pointerMap); - if (count === 0 || (count === 1 && goog.object.containsKey(this.pointerMap, - ol.pointer.MouseSource.POINTER_ID.toString()))) { - this.firstTouchId_ = inTouch.identifier; - this.cancelResetClickCount_(); - } -}; - - -/** - * @private - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.removePrimaryPointer_ = function(inPointer) { - if (inPointer.isPrimary) { - this.firstTouchId_ = undefined; - this.resetClickCount_(); - } -}; - - -/** - * @private - */ -ol.pointer.TouchSource.prototype.resetClickCount_ = function() { - this.resetId_ = goog.global.setTimeout( - goog.bind(this.resetClickCountHandler_, this), - ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT); -}; - - -/** - * @private - */ -ol.pointer.TouchSource.prototype.resetClickCountHandler_ = function() { - this.clickCount_ = 0; - this.resetId_ = undefined; -}; - - -/** - * @private - */ -ol.pointer.TouchSource.prototype.cancelResetClickCount_ = function() { - if (this.resetId_ !== undefined) { - goog.global.clearTimeout(this.resetId_); - } -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent Browser event - * @param {Touch} inTouch Touch event - * @return {Object} - */ -ol.pointer.TouchSource.prototype.touchToPointer_ = - function(browserEvent, inTouch) { - var e = this.dispatcher.cloneEvent(browserEvent, inTouch); - // Spec specifies that pointerId 1 is reserved for Mouse. - // Touch identifiers can start at 0. - // Add 2 to the touch identifier for compatibility. - e.pointerId = inTouch.identifier + 2; - // TODO: check if this is necessary? - //e.target = findTarget(e); - e.bubbles = true; - e.cancelable = true; - e.detail = this.clickCount_; - e.button = 0; - e.buttons = 1; - e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; - e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; - e.pressure = inTouch.webkitForce || inTouch.force || 0.5; - e.isPrimary = this.isPrimaryTouch_(inTouch); - e.pointerType = ol.pointer.TouchSource.POINTER_TYPE; - - // make sure that the properties that are different for - // each `Touch` object are not copied from the BrowserEvent object - e.clientX = inTouch.clientX; - e.clientY = inTouch.clientY; - e.screenX = inTouch.screenX; - e.screenY = inTouch.screenY; - - return e; -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} inEvent Touch event - * @param {function(goog.events.BrowserEvent, Object)} inFunction - */ -ol.pointer.TouchSource.prototype.processTouches_ = - function(inEvent, inFunction) { - var touches = Array.prototype.slice.call( - inEvent.getBrowserEvent().changedTouches); - var count = touches.length; - function preventDefault() { - inEvent.preventDefault(); - } - var i, pointer; - for (i = 0; i < count; ++i) { - pointer = this.touchToPointer_(inEvent, touches[i]); - // forward touch preventDefaults - pointer.preventDefault = preventDefault; - inFunction.call(this, inEvent, pointer); - } -}; - - -/** - * @private - * @param {TouchList} touchList - * @param {number} searchId - * @return {boolean} True, if the `Touch` with the given id is in the list. - */ -ol.pointer.TouchSource.prototype.findTouch_ = function(touchList, searchId) { - var l = touchList.length; - var touch; - for (var i = 0; i < l; i++) { - touch = touchList[i]; - if (touch.identifier === searchId) { - return true; - } - } - return false; -}; - - -/** - * In some instances, a touchstart can happen without a touchend. This - * leaves the pointermap in a broken state. - * Therefore, on every touchstart, we remove the touches that did not fire a - * touchend event. - * To keep state globally consistent, we fire a pointercancel for - * this "abandoned" touch - * - * @private - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.vacuumTouches_ = function(inEvent) { - var touchList = inEvent.getBrowserEvent().touches; - // pointerMap.getCount() should be < touchList.length here, - // as the touchstart has not been processed yet. - var keys = goog.object.getKeys(this.pointerMap); - var count = keys.length; - if (count >= touchList.length) { - var d = []; - var i, key, value; - for (i = 0; i < count; ++i) { - key = keys[i]; - value = this.pointerMap[key]; - // Never remove pointerId == 1, which is mouse. - // Touch identifiers are 2 smaller than their pointerId, which is the - // index in pointermap. - if (key != ol.pointer.MouseSource.POINTER_ID && - !this.findTouch_(touchList, key - 2)) { - d.push(value.out); - } - } - for (i = 0; i < d.length; ++i) { - this.cancelOut_(inEvent, d[i]); - } - } -}; - - -/** - * Handler for `touchstart`, triggers `pointerover`, - * `pointerenter` and `pointerdown` events. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.touchstart = function(inEvent) { - this.vacuumTouches_(inEvent); - this.setPrimaryTouch_(inEvent.getBrowserEvent().changedTouches[0]); - this.dedupSynthMouse_(inEvent); - this.clickCount_++; - this.processTouches_(inEvent, this.overDown_); -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.overDown_ = function(browserEvent, inPointer) { - this.pointerMap[inPointer.pointerId] = { - target: inPointer.target, - out: inPointer, - outTarget: inPointer.target - }; - this.dispatcher.over(inPointer, browserEvent); - this.dispatcher.enter(inPointer, browserEvent); - this.dispatcher.down(inPointer, browserEvent); -}; - - -/** - * Handler for `touchmove`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.touchmove = function(inEvent) { - inEvent.preventDefault(); - this.processTouches_(inEvent, this.moveOverOut_); -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.moveOverOut_ = - function(browserEvent, inPointer) { - var event = inPointer; - var pointer = this.pointerMap[event.pointerId]; - // a finger drifted off the screen, ignore it - if (!pointer) { - return; - } - var outEvent = pointer.out; - var outTarget = pointer.outTarget; - this.dispatcher.move(event, browserEvent); - if (outEvent && outTarget !== event.target) { - outEvent.relatedTarget = event.target; - event.relatedTarget = outTarget; - // recover from retargeting by shadow - outEvent.target = outTarget; - if (event.target) { - this.dispatcher.leaveOut(outEvent, browserEvent); - this.dispatcher.enterOver(event, browserEvent); - } else { - // clean up case when finger leaves the screen - event.target = outTarget; - event.relatedTarget = null; - this.cancelOut_(browserEvent, event); - } - } - pointer.out = event; - pointer.outTarget = event.target; -}; - - -/** - * Handler for `touchend`, triggers `pointerup`, - * `pointerout` and `pointerleave` events. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.touchend = function(inEvent) { - this.dedupSynthMouse_(inEvent); - this.processTouches_(inEvent, this.upOut_); -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.upOut_ = function(browserEvent, inPointer) { - this.dispatcher.up(inPointer, browserEvent); - this.dispatcher.out(inPointer, browserEvent); - this.dispatcher.leave(inPointer, browserEvent); - this.cleanUpPointer_(inPointer); -}; - - -/** - * Handler for `touchcancel`, triggers `pointercancel`, - * `pointerout` and `pointerleave` events. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.touchcancel = function(inEvent) { - this.processTouches_(inEvent, this.cancelOut_); -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.cancelOut_ = - function(browserEvent, inPointer) { - this.dispatcher.cancel(inPointer, browserEvent); - this.dispatcher.out(inPointer, browserEvent); - this.dispatcher.leave(inPointer, browserEvent); - this.cleanUpPointer_(inPointer); -}; - - -/** - * @private - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.cleanUpPointer_ = function(inPointer) { - delete this.pointerMap[inPointer.pointerId]; - this.removePrimaryPointer_(inPointer); -}; - - -/** - * Prevent synth mouse events from creating pointer events. - * - * @private - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) { - var lts = this.mouseSource.lastTouches; - var t = inEvent.getBrowserEvent().changedTouches[0]; - // only the primary finger will synth mouse events - if (this.isPrimaryTouch_(t)) { - // remember x/y of last touch - var lt = /** @type {ol.Pixel} */ ([t.clientX, t.clientY]); - lts.push(lt); - - goog.global.setTimeout(function() { - // remove touch after timeout - goog.array.remove(lts, lt); - }, ol.pointer.TouchSource.DEDUP_TIMEOUT); - } -}; - -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.PointerEventHandler'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); - -goog.require('ol.has'); -goog.require('ol.pointer.MouseSource'); -goog.require('ol.pointer.MsSource'); -goog.require('ol.pointer.NativeSource'); -goog.require('ol.pointer.PointerEvent'); -goog.require('ol.pointer.TouchSource'); - - - -/** - * @constructor - * @extends {goog.events.EventTarget} - * @param {Element|HTMLDocument} element Viewport element. - */ -ol.pointer.PointerEventHandler = function(element) { - goog.base(this); - - /** - * @const - * @private - * @type {Element|HTMLDocument} - */ - this.element_ = element; - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = {}; - - /** - * @type {Object.<string, function(goog.events.BrowserEvent)>} - * @private - */ - this.eventMap_ = {}; - - /** - * @type {Array.<ol.pointer.EventSource>} - * @private - */ - this.eventSourceList_ = []; - - this.registerSources(); -}; -goog.inherits(ol.pointer.PointerEventHandler, goog.events.EventTarget); - - -/** - * Set up the event sources (mouse, touch and native pointers) - * that generate pointer events. - */ -ol.pointer.PointerEventHandler.prototype.registerSources = function() { - if (ol.has.POINTER) { - this.registerSource('native', new ol.pointer.NativeSource(this)); - } else if (ol.has.MSPOINTER) { - this.registerSource('ms', new ol.pointer.MsSource(this)); - } else { - var mouseSource = new ol.pointer.MouseSource(this); - this.registerSource('mouse', mouseSource); - - if (ol.has.TOUCH) { - this.registerSource('touch', - new ol.pointer.TouchSource(this, mouseSource)); - } - } - - // register events on the viewport element - this.register_(); -}; - - -/** - * Add a new event source that will generate pointer events. - * - * @param {string} name A name for the event source - * @param {ol.pointer.EventSource} source - */ -ol.pointer.PointerEventHandler.prototype.registerSource = - function(name, source) { - var s = source; - var newEvents = s.getEvents(); - - if (newEvents) { - newEvents.forEach(function(e) { - var handler = s.getHandlerForEvent(e); - - if (handler) { - this.eventMap_[e] = goog.bind(handler, s); - } - }, this); - this.eventSourceList_.push(s); - } -}; - - -/** - * Set up the events for all registered event sources. - * @private - */ -ol.pointer.PointerEventHandler.prototype.register_ = function() { - var l = this.eventSourceList_.length; - var eventSource; - for (var i = 0; i < l; i++) { - eventSource = this.eventSourceList_[i]; - this.addEvents_(eventSource.getEvents()); - } -}; - - -/** - * Remove all registered events. - * @private - */ -ol.pointer.PointerEventHandler.prototype.unregister_ = function() { - var l = this.eventSourceList_.length; - var eventSource; - for (var i = 0; i < l; i++) { - eventSource = this.eventSourceList_[i]; - this.removeEvents_(eventSource.getEvents()); - } -}; - - -/** - * Calls the right handler for a new event. - * @private - * @param {goog.events.BrowserEvent} inEvent Browser event. - */ -ol.pointer.PointerEventHandler.prototype.eventHandler_ = function(inEvent) { - var type = inEvent.type; - var handler = this.eventMap_[type]; - if (handler) { - handler(inEvent); - } -}; - - -/** - * Setup listeners for the given events. - * @private - * @param {Array.<string>} events List of events. - */ -ol.pointer.PointerEventHandler.prototype.addEvents_ = function(events) { - events.forEach(function(eventName) { - goog.events.listen(this.element_, eventName, - this.eventHandler_, false, this); - }, this); -}; - - -/** - * Unregister listeners for the given events. - * @private - * @param {Array.<string>} events List of events. - */ -ol.pointer.PointerEventHandler.prototype.removeEvents_ = function(events) { - events.forEach(function(e) { - goog.events.unlisten(this.element_, e, - this.eventHandler_, false, this); - }, this); -}; - - -/** - * Returns a snapshot of inEvent, with writable properties. - * - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @param {Event|Touch} inEvent An event that contains - * properties to copy. - * @return {Object} An object containing shallow copies of - * `inEvent`'s properties. - */ -ol.pointer.PointerEventHandler.prototype.cloneEvent = - function(browserEvent, inEvent) { - var eventCopy = {}, p; - for (var i = 0, ii = ol.pointer.CLONE_PROPS.length; i < ii; i++) { - p = ol.pointer.CLONE_PROPS[i][0]; - eventCopy[p] = - browserEvent[p] || - inEvent[p] || - ol.pointer.CLONE_PROPS[i][1]; - } - - return eventCopy; -}; - - -// EVENTS - - -/** - * Triggers a 'pointerdown' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.down = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERDOWN, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointermove' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.move = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERMOVE, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointerup' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.up = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERUP, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointerenter' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.enter = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = false; - this.fireEvent(ol.pointer.EventType.POINTERENTER, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointerleave' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.leave = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = false; - this.fireEvent(ol.pointer.EventType.POINTERLEAVE, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointerover' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.over = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = true; - this.fireEvent(ol.pointer.EventType.POINTEROVER, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointerout' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.out = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = true; - this.fireEvent(ol.pointer.EventType.POINTEROUT, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a 'pointercancel' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.cancel = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERCANCEL, - pointerEventData, browserEvent); -}; - - -/** - * Triggers a combination of 'pointerout' and 'pointerleave' events. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.leaveOut = - function(pointerEventData, browserEvent) { - this.out(pointerEventData, browserEvent); - if (!this.contains_( - pointerEventData.target, - pointerEventData.relatedTarget)) { - this.leave(pointerEventData, browserEvent); - } -}; - - -/** - * Triggers a combination of 'pointerover' and 'pointerevents' events. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.enterOver = - function(pointerEventData, browserEvent) { - this.over(pointerEventData, browserEvent); - if (!this.contains_( - pointerEventData.target, - pointerEventData.relatedTarget)) { - this.enter(pointerEventData, browserEvent); - } -}; - - -/** - * @private - * @param {Element} container - * @param {Element} contained - * @return {boolean} Returns true if the container element - * contains the other element. - */ -ol.pointer.PointerEventHandler.prototype.contains_ = - function(container, contained) { - if (!contained) { - return false; - } - return goog.dom.contains(container, contained); -}; - - -// EVENT CREATION AND TRACKING -/** - * Creates a new Event of type `inType`, based on the information in - * `pointerEventData`. - * - * @param {string} inType A string representing the type of event to create. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - * @return {ol.pointer.PointerEvent} A PointerEvent of type `inType`. - */ -ol.pointer.PointerEventHandler.prototype.makeEvent = - function(inType, pointerEventData, browserEvent) { - return new ol.pointer.PointerEvent(inType, browserEvent, pointerEventData); -}; - - -/** - * Make and dispatch an event in one call. - * @param {string} inType A string representing the type of event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.fireEvent = - function(inType, pointerEventData, browserEvent) { - var e = this.makeEvent(inType, pointerEventData, browserEvent); - this.dispatchEvent(e); -}; - - -/** - * Creates a pointer event from a native pointer event - * and dispatches this event. - * @param {goog.events.BrowserEvent} nativeEvent A platform event with a target. - */ -ol.pointer.PointerEventHandler.prototype.fireNativeEvent = - function(nativeEvent) { - var e = this.makeEvent(nativeEvent.type, nativeEvent.getBrowserEvent(), - nativeEvent); - this.dispatchEvent(e); -}; - - -/** - * Wrap a native mouse event into a pointer event. - * This proxy method is required for the legacy IE support. - * @param {string} eventType The pointer event type. - * @param {goog.events.BrowserEvent} browserEvent - * @return {ol.pointer.PointerEvent} - */ -ol.pointer.PointerEventHandler.prototype.wrapMouseEvent = - function(eventType, browserEvent) { - var pointerEvent = this.makeEvent( - eventType, - ol.pointer.MouseSource.prepareEvent(browserEvent, this), - browserEvent - ); - return pointerEvent; -}; - - -/** - * @inheritDoc - */ -ol.pointer.PointerEventHandler.prototype.disposeInternal = function() { - this.unregister_(); - goog.base(this, 'disposeInternal'); -}; - - -/** - * Constants for event names. - * @enum {string} - */ -ol.pointer.EventType = { - POINTERMOVE: 'pointermove', - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - POINTERCANCEL: 'pointercancel' -}; - - -/** - * Properties to copy when cloning an event, with default values. - * @type {Array.<Array>} - */ -ol.pointer.CLONE_PROPS = [ - // MouseEvent - ['bubbles', false], - ['cancelable', false], - ['view', null], - ['detail', null], - ['screenX', 0], - ['screenY', 0], - ['clientX', 0], - ['clientY', 0], - ['ctrlKey', false], - ['altKey', false], - ['shiftKey', false], - ['metaKey', false], - ['button', 0], - ['relatedTarget', null], - // DOM Level 3 - ['buttons', 0], - // PointerEvent - ['pointerId', 0], - ['width', 0], - ['height', 0], - ['pressure', 0], - ['tiltX', 0], - ['tiltY', 0], - ['pointerType', ''], - ['hwTimestamp', 0], - ['isPrimary', false], - // event instance - ['type', ''], - ['target', null], - ['currentTarget', null], - ['which', 0] -]; - -goog.provide('ol.MapBrowserEvent'); -goog.provide('ol.MapBrowserEvent.EventType'); -goog.provide('ol.MapBrowserEventHandler'); -goog.provide('ol.MapBrowserPointerEvent'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.MapEvent'); -goog.require('ol.Pixel'); -goog.require('ol.pointer.PointerEvent'); -goog.require('ol.pointer.PointerEventHandler'); - - - -/** - * @classdesc - * Events emitted as map browser events are instances of this type. - * See {@link ol.Map} for which events trigger a map browser event. - * - * @constructor - * @extends {ol.MapEvent} - * @implements {oli.MapBrowserEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @param {boolean=} opt_dragging Is the map currently being dragged? - * @param {?olx.FrameState=} opt_frameState Frame state. - */ -ol.MapBrowserEvent = function(type, map, browserEvent, opt_dragging, - opt_frameState) { - - goog.base(this, type, map, opt_frameState); - - /** - * @const - * @type {goog.events.BrowserEvent} - */ - this.browserEvent = browserEvent; - - /** - * The original browser event. - * @const - * @type {Event} - * @api stable - */ - this.originalEvent = browserEvent.getBrowserEvent(); - - /** - * The pixel of the original browser event. - * @type {ol.Pixel} - * @api stable - */ - this.pixel = map.getEventPixel(this.originalEvent); - - /** - * The coordinate of the original browser event. - * @type {ol.Coordinate} - * @api stable - */ - this.coordinate = map.getCoordinateFromPixel(this.pixel); - - /** - * Indicates if the map is currently being dragged. Only set for - * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`. - * - * @type {boolean} - * @api stable - */ - this.dragging = opt_dragging !== undefined ? opt_dragging : false; - -}; -goog.inherits(ol.MapBrowserEvent, ol.MapEvent); - - -/** - * Prevents the default browser action. - * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault - * @override - * @api stable - */ -ol.MapBrowserEvent.prototype.preventDefault = function() { - goog.base(this, 'preventDefault'); - this.browserEvent.preventDefault(); -}; - - -/** - * Prevents further propagation of the current event. - * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation - * @override - * @api stable - */ -ol.MapBrowserEvent.prototype.stopPropagation = function() { - goog.base(this, 'stopPropagation'); - this.browserEvent.stopPropagation(); -}; - - - -/** - * @constructor - * @extends {ol.MapBrowserEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @param {boolean=} opt_dragging Is the map currently being dragged? - * @param {?olx.FrameState=} opt_frameState Frame state. - */ -ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging, - opt_frameState) { - - goog.base(this, type, map, pointerEvent.browserEvent, opt_dragging, - opt_frameState); - - /** - * @const - * @type {ol.pointer.PointerEvent} - */ - this.pointerEvent = pointerEvent; - -}; -goog.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent); - - - -/** - * @param {ol.Map} map The map with the viewport to listen to events on. - * @constructor - * @extends {goog.events.EventTarget} - */ -ol.MapBrowserEventHandler = function(map) { - - goog.base(this); - - /** - * This is the element that we will listen to the real events on. - * @type {ol.Map} - * @private - */ - this.map_ = map; - - /** - * @type {number} - * @private - */ - this.clickTimeoutId_ = 0; - - /** - * @type {boolean} - * @private - */ - this.dragging_ = false; - - /** - * @type {Array.<goog.events.Key>} - * @private - */ - this.dragListenerKeys_ = null; - - /** - * @type {goog.events.Key} - * @private - */ - this.pointerdownListenerKey_ = null; - - /** - * The most recent "down" type event (or null if none have occurred). - * Set on pointerdown. - * @type {ol.pointer.PointerEvent} - * @private - */ - this.down_ = null; - - var element = this.map_.getViewport(); - - /** - * @type {number} - * @private - */ - this.activePointers_ = 0; - - /** - * @type {Object.<number, boolean>} - * @private - */ - this.trackedTouches_ = {}; - - /** - * Event handler which generates pointer events for - * the viewport element. - * - * @type {ol.pointer.PointerEventHandler} - * @private - */ - this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element); - - /** - * Event handler which generates pointer events for - * the document (used when dragging). - * - * @type {ol.pointer.PointerEventHandler} - * @private - */ - this.documentPointerEventHandler_ = null; - - this.pointerdownListenerKey_ = goog.events.listen(this.pointerEventHandler_, - ol.pointer.EventType.POINTERDOWN, - this.handlePointerDown_, false, this); - - this.relayedListenerKey_ = goog.events.listen(this.pointerEventHandler_, - ol.pointer.EventType.POINTERMOVE, - this.relayEvent_, false, this); - -}; -goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget); - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) { - var newEvent; - newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - if (this.clickTimeoutId_ !== 0) { - // double-click - goog.global.clearTimeout(this.clickTimeoutId_); - this.clickTimeoutId_ = 0; - newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - } else { - // click - this.clickTimeoutId_ = goog.global.setTimeout(goog.bind(function() { - this.clickTimeoutId_ = 0; - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - }, this), 250); - } -}; - - -/** - * Keeps track on how many pointers are currently active. - * - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.updateActivePointers_ = - function(pointerEvent) { - var event = pointerEvent; - - if (event.type == ol.MapBrowserEvent.EventType.POINTERUP || - event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) { - delete this.trackedTouches_[event.pointerId]; - } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { - this.trackedTouches_[event.pointerId] = true; - } - this.activePointers_ = goog.object.getCount(this.trackedTouches_); -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) { - this.updateActivePointers_(pointerEvent); - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - - // We emulate click events on left mouse button click, touch contact, and pen - // contact. isMouseActionButton returns true in these cases (evt.button is set - // to 0). - // See http://www.w3.org/TR/pointerevents/#button-states - if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) { - goog.asserts.assert(this.down_, 'this.down_ must be truthy'); - this.emulateClick_(this.down_); - } - - goog.asserts.assert(this.activePointers_ >= 0, - 'this.activePointers_ should be equal to or larger than 0'); - if (this.activePointers_ === 0) { - this.dragListenerKeys_.forEach(goog.events.unlistenByKey); - this.dragListenerKeys_ = null; - this.dragging_ = false; - this.down_ = null; - goog.dispose(this.documentPointerEventHandler_); - this.documentPointerEventHandler_ = null; - } -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @return {boolean} If the left mouse button was pressed. - * @private - */ -ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = - function(pointerEvent) { - return pointerEvent.button === 0; -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.handlePointerDown_ = - function(pointerEvent) { - this.updateActivePointers_(pointerEvent); - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - - this.down_ = pointerEvent; - - if (!this.dragListenerKeys_) { - /* Set up a pointer event handler on the `document`, - * which is required when the pointer is moved outside - * the viewport when dragging. - */ - this.documentPointerEventHandler_ = - new ol.pointer.PointerEventHandler(document); - - this.dragListenerKeys_ = [ - goog.events.listen(this.documentPointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERMOVE, - this.handlePointerMove_, false, this), - goog.events.listen(this.documentPointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERUP, - this.handlePointerUp_, false, this), - /* Note that the listener for `pointercancel is set up on - * `pointerEventHandler_` and not `documentPointerEventHandler_` like - * the `pointerup` and `pointermove` listeners. - * - * The reason for this is the following: `TouchSource.vacuumTouches_()` - * issues `pointercancel` events, when there was no `touchend` for a - * `touchstart`. Now, let's say a first `touchstart` is registered on - * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. - * But `documentPointerEventHandler_` doesn't know about the first - * `touchstart`. If there is no `touchend` for the `touchstart`, we can - * only receive a `touchcancel` from `pointerEventHandler_`, because it is - * only registered there. - */ - goog.events.listen(this.pointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERCANCEL, - this.handlePointerUp_, false, this) - ]; - } -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.handlePointerMove_ = - function(pointerEvent) { - // Fix IE10 on windows Surface : When you tap the tablet, it triggers - // multiple pointermove events between pointerdown and pointerup with - // the exact same coordinates of the pointerdown event. To avoid a - // 'false' touchmove event to be dispatched , we test if the pointer - // effectively moved. - if (this.isMoving_(pointerEvent)) { - this.dragging_ = true; - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent, - this.dragging_); - this.dispatchEvent(newEvent); - } - - // Some native android browser triggers mousemove events during small period - // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or - // https://code.google.com/p/android/issues/detail?id=19827 - // ex: Galaxy Tab P3110 + Android 4.1.1 - pointerEvent.preventDefault(); -}; - - -/** - * Wrap and relay a pointer event. Note that this requires that the type - * string for the MapBrowserPointerEvent matches the PointerEvent type. - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) { - var dragging = !!(this.down_ && this.isMoving_(pointerEvent)); - this.dispatchEvent(new ol.MapBrowserPointerEvent( - pointerEvent.type, this.map_, pointerEvent, dragging)); -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @return {boolean} - * @private - */ -ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) { - return pointerEvent.clientX != this.down_.clientX || - pointerEvent.clientY != this.down_.clientY; -}; - - -/** - * @inheritDoc - */ -ol.MapBrowserEventHandler.prototype.disposeInternal = function() { - if (this.relayedListenerKey_) { - goog.events.unlistenByKey(this.relayedListenerKey_); - this.relayedListenerKey_ = null; - } - if (this.pointerdownListenerKey_) { - goog.events.unlistenByKey(this.pointerdownListenerKey_); - this.pointerdownListenerKey_ = null; - } - if (this.dragListenerKeys_) { - this.dragListenerKeys_.forEach(goog.events.unlistenByKey); - this.dragListenerKeys_ = null; - } - if (this.documentPointerEventHandler_) { - goog.dispose(this.documentPointerEventHandler_); - this.documentPointerEventHandler_ = null; - } - if (this.pointerEventHandler_) { - goog.dispose(this.pointerEventHandler_); - this.pointerEventHandler_ = null; - } - goog.base(this, 'disposeInternal'); -}; - - -/** - * Constants for event names. - * @enum {string} - */ -ol.MapBrowserEvent.EventType = { - - /** - * A true single click with no dragging and no double click. Note that this - * event is delayed by 250 ms to ensure that it is not a double click. - * @event ol.MapBrowserEvent#singleclick - * @api stable - */ - SINGLECLICK: 'singleclick', - - /** - * A click with no dragging. A double click will fire two of this. - * @event ol.MapBrowserEvent#click - * @api stable - */ - CLICK: goog.events.EventType.CLICK, - - /** - * A true double click, with no dragging. - * @event ol.MapBrowserEvent#dblclick - * @api stable - */ - DBLCLICK: goog.events.EventType.DBLCLICK, - - /** - * Triggered when a pointer is dragged. - * @event ol.MapBrowserEvent#pointerdrag - * @api - */ - POINTERDRAG: 'pointerdrag', - - /** - * Triggered when a pointer is moved. Note that on touch devices this is - * triggered when the map is panned, so is not the same as mousemove. - * @event ol.MapBrowserEvent#pointermove - * @api stable - */ - POINTERMOVE: 'pointermove', - - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - POINTERCANCEL: 'pointercancel' -}; - -goog.provide('ol.layer.Base'); -goog.provide('ol.layer.LayerProperty'); -goog.provide('ol.layer.LayerState'); - -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.math'); -goog.require('ol.source.State'); - - -/** - * @enum {string} - */ -ol.layer.LayerProperty = { - OPACITY: 'opacity', - VISIBLE: 'visible', - EXTENT: 'extent', - Z_INDEX: 'zIndex', - MAX_RESOLUTION: 'maxResolution', - MIN_RESOLUTION: 'minResolution', - SOURCE: 'source' -}; - - -/** - * @typedef {{layer: ol.layer.Layer, - * opacity: number, - * sourceState: ol.source.State, - * visible: boolean, - * managed: boolean, - * extent: (ol.Extent|undefined), - * zIndex: number, - * maxResolution: number, - * minResolution: number}} - */ -ol.layer.LayerState; - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Note that with `ol.layer.Base` and all its subclasses, any property set in - * the options is set as a {@link ol.Object} property on the layer object, so - * is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.Object} - * @param {olx.layer.BaseOptions} options Layer options. - * @api stable - */ -ol.layer.Base = function(options) { - - goog.base(this); - - /** - * @type {Object.<string, *>} - */ - var properties = goog.object.clone(options); - properties[ol.layer.LayerProperty.OPACITY] = - options.opacity !== undefined ? options.opacity : 1; - properties[ol.layer.LayerProperty.VISIBLE] = - options.visible !== undefined ? options.visible : true; - properties[ol.layer.LayerProperty.Z_INDEX] = - options.zIndex !== undefined ? options.zIndex : 0; - properties[ol.layer.LayerProperty.MAX_RESOLUTION] = - options.maxResolution !== undefined ? options.maxResolution : Infinity; - properties[ol.layer.LayerProperty.MIN_RESOLUTION] = - options.minResolution !== undefined ? options.minResolution : 0; - - this.setProperties(properties); -}; -goog.inherits(ol.layer.Base, ol.Object); - - -/** - * @return {ol.layer.LayerState} Layer state. - */ -ol.layer.Base.prototype.getLayerState = function() { - var opacity = this.getOpacity(); - var sourceState = this.getSourceState(); - var visible = this.getVisible(); - var extent = this.getExtent(); - var zIndex = this.getZIndex(); - var maxResolution = this.getMaxResolution(); - var minResolution = this.getMinResolution(); - return { - layer: /** @type {ol.layer.Layer} */ (this), - opacity: ol.math.clamp(opacity, 0, 1), - sourceState: sourceState, - visible: visible, - managed: true, - extent: extent, - zIndex: zIndex, - maxResolution: maxResolution, - minResolution: Math.max(minResolution, 0) - }; -}; - - -/** - * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be - * modified in place). - * @return {Array.<ol.layer.Layer>} Array of layers. - */ -ol.layer.Base.prototype.getLayersArray = goog.abstractMethod; - - -/** - * @param {Array.<ol.layer.LayerState>=} opt_states Optional list of layer - * states (to be modified in place). - * @return {Array.<ol.layer.LayerState>} List of layer states. - */ -ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod; - - -/** - * Return the {@link ol.Extent extent} of the layer or `undefined` if it - * will be visible regardless of extent. - * @return {ol.Extent|undefined} The layer extent. - * @observable - * @api stable - */ -ol.layer.Base.prototype.getExtent = function() { - return /** @type {ol.Extent|undefined} */ ( - this.get(ol.layer.LayerProperty.EXTENT)); -}; - - -/** - * Return the maximum resolution of the layer. - * @return {number} The maximum resolution of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.getMaxResolution = function() { - return /** @type {number} */ ( - this.get(ol.layer.LayerProperty.MAX_RESOLUTION)); -}; - - -/** - * Return the minimum resolution of the layer. - * @return {number} The minimum resolution of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.getMinResolution = function() { - return /** @type {number} */ ( - this.get(ol.layer.LayerProperty.MIN_RESOLUTION)); -}; - - -/** - * Return the opacity of the layer (between 0 and 1). - * @return {number} The opacity of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.getOpacity = function() { - return /** @type {number} */ (this.get(ol.layer.LayerProperty.OPACITY)); -}; - - -/** - * @return {ol.source.State} Source state. - */ -ol.layer.Base.prototype.getSourceState = goog.abstractMethod; - - -/** - * Return the visibility of the layer (`true` or `false`). - * @return {boolean} The visibility of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.getVisible = function() { - return /** @type {boolean} */ (this.get(ol.layer.LayerProperty.VISIBLE)); -}; - - -/** - * Return the Z-index of the layer, which is used to order layers before - * rendering. The default Z-index is 0. - * @return {number} The Z-index of the layer. - * @observable - * @api - */ -ol.layer.Base.prototype.getZIndex = function() { - return /** @type {number} */ (this.get(ol.layer.LayerProperty.Z_INDEX)); -}; - - -/** - * Set the extent at which the layer is visible. If `undefined`, the layer - * will be visible at all extents. - * @param {ol.Extent|undefined} extent The extent of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.setExtent = function(extent) { - this.set(ol.layer.LayerProperty.EXTENT, extent); -}; - - -/** - * Set the maximum resolution at which the layer is visible. - * @param {number} maxResolution The maximum resolution of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.setMaxResolution = function(maxResolution) { - this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution); -}; - - -/** - * Set the minimum resolution at which the layer is visible. - * @param {number} minResolution The minimum resolution of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.setMinResolution = function(minResolution) { - this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution); -}; - - -/** - * Set the opacity of the layer, allowed values range from 0 to 1. - * @param {number} opacity The opacity of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.setOpacity = function(opacity) { - this.set(ol.layer.LayerProperty.OPACITY, opacity); -}; - - -/** - * Set the visibility of the layer (`true` or `false`). - * @param {boolean} visible The visibility of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.setVisible = function(visible) { - this.set(ol.layer.LayerProperty.VISIBLE, visible); -}; - - -/** - * Set Z-index of the layer, which is used to order layers before rendering. - * The default Z-index is 0. - * @param {number} zindex The z-index of the layer. - * @observable - * @api - */ -ol.layer.Base.prototype.setZIndex = function(zindex) { - this.set(ol.layer.LayerProperty.Z_INDEX, zindex); -}; - -goog.provide('ol.render.VectorContext'); - - - -/** - * Context for drawing geometries. A vector context is available on render - * events and does not need to be constructed directly. - * @constructor - * @struct - * @api - */ -ol.render.VectorContext = function() { -}; - - -/** - * @param {number} zIndex Z index. - * @param {function(ol.render.VectorContext)} callback Callback. - */ -ol.render.VectorContext.prototype.drawAsync = goog.abstractMethod; - - -/** - * @param {ol.geom.Circle} circleGeometry Circle geometry. - * @param {ol.Feature} feature Feature, - */ -ol.render.VectorContext.prototype.drawCircleGeometry = goog.abstractMethod; - - -/** - * @param {ol.Feature} feature Feature. - * @param {ol.style.Style} style Style. - */ -ol.render.VectorContext.prototype.drawFeature = goog.abstractMethod; - - -/** - * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry - * collection. - * @param {ol.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawGeometryCollectionGeometry = - goog.abstractMethod; - - -/** - * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line - * string geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawLineStringGeometry = - goog.abstractMethod; - - -/** - * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry - * MultiLineString geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawMultiLineStringGeometry = - goog.abstractMethod; - - -/** - * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawMultiPointGeometry = goog.abstractMethod; - - -/** - * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry. - * @param {ol.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawMultiPolygonGeometry = - goog.abstractMethod; - - -/** - * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawPointGeometry = goog.abstractMethod; - - -/** - * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawPolygonGeometry = goog.abstractMethod; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawText = goog.abstractMethod; - - -/** - * @param {ol.style.Fill} fillStyle Fill style. - * @param {ol.style.Stroke} strokeStyle Stroke style. - */ -ol.render.VectorContext.prototype.setFillStrokeStyle = goog.abstractMethod; - - -/** - * @param {ol.style.Image} imageStyle Image style. - */ -ol.render.VectorContext.prototype.setImageStyle = goog.abstractMethod; - - -/** - * @param {ol.style.Text} textStyle Text style. - */ -ol.render.VectorContext.prototype.setTextStyle = goog.abstractMethod; - -goog.provide('ol.render.Event'); -goog.provide('ol.render.EventType'); - -goog.require('goog.events.Event'); -goog.require('ol.render.VectorContext'); - - -/** - * @enum {string} - */ -ol.render.EventType = { - /** - * @event ol.render.Event#postcompose - * @api - */ - POSTCOMPOSE: 'postcompose', - /** - * @event ol.render.Event#precompose - * @api - */ - PRECOMPOSE: 'precompose', - /** - * @event ol.render.Event#render - * @api - */ - RENDER: 'render' -}; - - - -/** - * @constructor - * @extends {goog.events.Event} - * @implements {oli.render.Event} - * @param {ol.render.EventType} type Type. - * @param {Object=} opt_target Target. - * @param {ol.render.VectorContext=} opt_vectorContext Vector context. - * @param {olx.FrameState=} opt_frameState Frame state. - * @param {?CanvasRenderingContext2D=} opt_context Context. - * @param {?ol.webgl.Context=} opt_glContext WebGL Context. - */ -ol.render.Event = function( - type, opt_target, opt_vectorContext, opt_frameState, opt_context, - opt_glContext) { - - goog.base(this, type, opt_target); - - /** - * For canvas, this is an instance of {@link ol.render.canvas.Immediate}. - * @type {ol.render.VectorContext|undefined} - * @api - */ - this.vectorContext = opt_vectorContext; - - /** - * An object representing the current render frame state. - * @type {olx.FrameState|undefined} - * @api - */ - this.frameState = opt_frameState; - - /** - * Canvas context. Only available when a Canvas renderer is used, null - * otherwise. - * @type {CanvasRenderingContext2D|null|undefined} - * @api - */ - this.context = opt_context; - - /** - * WebGL context. Only available when a WebGL renderer is used, null - * otherwise. - * @type {ol.webgl.Context|null|undefined} - * @api - */ - this.glContext = opt_glContext; - -}; -goog.inherits(ol.render.Event, goog.events.Event); - -goog.provide('ol.layer.Layer'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.layer.Base'); -goog.require('ol.layer.LayerProperty'); -goog.require('ol.render.EventType'); -goog.require('ol.source.State'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * A visual representation of raster or vector map data. - * Layers group together those properties that pertain to how the data is to be - * displayed, irrespective of the source of that data. - * - * Layers are usually added to a map with {@link ol.Map#addLayer}. Components - * like {@link ol.interaction.Select} use unmanaged layers internally. These - * unmanaged layers are associated with the map using - * {@link ol.layer.Layer#setMap} instead. - * - * A generic `change` event is fired when the state of the source changes. - * - * @constructor - * @extends {ol.layer.Base} - * @fires ol.render.Event - * @param {olx.layer.LayerOptions} options Layer options. - * @api stable - */ -ol.layer.Layer = function(options) { - - var baseOptions = goog.object.clone(options); - delete baseOptions.source; - - goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); - - /** - * @private - * @type {goog.events.Key} - */ - this.mapPrecomposeKey_ = null; - - /** - * @private - * @type {goog.events.Key} - */ - this.mapRenderKey_ = null; - - /** - * @private - * @type {goog.events.Key} - */ - this.sourceChangeKey_ = null; - - if (options.map) { - this.setMap(options.map); - } - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.layer.LayerProperty.SOURCE), - this.handleSourcePropertyChange_, false, this); - - var source = options.source ? options.source : null; - this.setSource(source); -}; -goog.inherits(ol.layer.Layer, ol.layer.Base); - - -/** - * Return `true` if the layer is visible, and if the passed resolution is - * between the layer's minResolution and maxResolution. The comparison is - * inclusive for `minResolution` and exclusive for `maxResolution`. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {number} resolution Resolution. - * @return {boolean} The layer is visible at the given resolution. - */ -ol.layer.Layer.visibleAtResolution = function(layerState, resolution) { - return layerState.visible && resolution >= layerState.minResolution && - resolution < layerState.maxResolution; -}; - - -/** - * @inheritDoc - */ -ol.layer.Layer.prototype.getLayersArray = function(opt_array) { - var array = opt_array ? opt_array : []; - array.push(this); - return array; -}; - - -/** - * @inheritDoc - */ -ol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) { - var states = opt_states ? opt_states : []; - states.push(this.getLayerState()); - return states; -}; - - -/** - * Get the layer source. - * @return {ol.source.Source} The layer source (or `null` if not yet set). - * @observable - * @api stable - */ -ol.layer.Layer.prototype.getSource = function() { - var source = this.get(ol.layer.LayerProperty.SOURCE); - return /** @type {ol.source.Source} */ (source) || null; -}; - - -/** - * @inheritDoc - */ -ol.layer.Layer.prototype.getSourceState = function() { - var source = this.getSource(); - return !source ? ol.source.State.UNDEFINED : source.getState(); -}; - - -/** - * @private - */ -ol.layer.Layer.prototype.handleSourceChange_ = function() { - this.changed(); -}; - - -/** - * @private - */ -ol.layer.Layer.prototype.handleSourcePropertyChange_ = function() { - if (this.sourceChangeKey_) { - goog.events.unlistenByKey(this.sourceChangeKey_); - this.sourceChangeKey_ = null; - } - var source = this.getSource(); - if (source) { - this.sourceChangeKey_ = goog.events.listen(source, - goog.events.EventType.CHANGE, this.handleSourceChange_, false, this); - } - this.changed(); -}; - - -/** - * Sets the layer to be rendered on a map. The map will not manage this layer in - * its layers collection, layer filters in {@link ol.Map#forEachLayerAtPixel} - * will not filter the layer, and it will be rendered on top. This is useful for - * temporary layers. To remove an unmanaged layer from the map, use - * `#setMap(null)`. - * - * To add the layer to a map and have it managed by the map, use - * {@link ol.Map#addLayer} instead. - * @param {ol.Map} map Map. - * @api - */ -ol.layer.Layer.prototype.setMap = function(map) { - goog.events.unlistenByKey(this.mapPrecomposeKey_); - this.mapPrecomposeKey_ = null; - if (!map) { - this.changed(); - } - goog.events.unlistenByKey(this.mapRenderKey_); - this.mapRenderKey_ = null; - if (map) { - this.mapPrecomposeKey_ = goog.events.listen( - map, ol.render.EventType.PRECOMPOSE, function(evt) { - var layerState = this.getLayerState(); - layerState.managed = false; - layerState.zIndex = Infinity; - evt.frameState.layerStatesArray.push(layerState); - evt.frameState.layerStates[goog.getUid(this)] = layerState; - }, false, this); - this.mapRenderKey_ = goog.events.listen( - this, goog.events.EventType.CHANGE, map.render, false, map); - this.changed(); - } -}; - - -/** - * Set the layer source. - * @param {ol.source.Source} source The layer source. - * @observable - * @api stable - */ -ol.layer.Layer.prototype.setSource = function(source) { - this.set(ol.layer.LayerProperty.SOURCE, source); -}; - -goog.provide('ol.ImageBase'); -goog.provide('ol.ImageState'); - -goog.require('goog.asserts'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('ol.Attribution'); -goog.require('ol.Extent'); - - -/** - * @enum {number} - */ -ol.ImageState = { - IDLE: 0, - LOADING: 1, - LOADED: 2, - ERROR: 3 -}; - - - -/** - * @constructor - * @extends {goog.events.EventTarget} - * @param {ol.Extent} extent Extent. - * @param {number|undefined} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.ImageState} state State. - * @param {Array.<ol.Attribution>} attributions Attributions. - */ -ol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) { - - goog.base(this); - - /** - * @private - * @type {Array.<ol.Attribution>} - */ - this.attributions_ = attributions; - - /** - * @protected - * @type {ol.Extent} - */ - this.extent = extent; - - /** - * @private - * @type {number} - */ - this.pixelRatio_ = pixelRatio; - - /** - * @protected - * @type {number|undefined} - */ - this.resolution = resolution; - - /** - * @protected - * @type {ol.ImageState} - */ - this.state = state; - -}; -goog.inherits(ol.ImageBase, goog.events.EventTarget); - - -/** - * @protected - */ -ol.ImageBase.prototype.changed = function() { - this.dispatchEvent(goog.events.EventType.CHANGE); -}; - - -/** - * @return {Array.<ol.Attribution>} Attributions. - */ -ol.ImageBase.prototype.getAttributions = function() { - return this.attributions_; -}; - - -/** - * @return {ol.Extent} Extent. - */ -ol.ImageBase.prototype.getExtent = function() { - return this.extent; -}; - - -/** - * @param {Object=} opt_context Object. - * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image. - */ -ol.ImageBase.prototype.getImage = goog.abstractMethod; - - -/** - * @return {number} PixelRatio. - */ -ol.ImageBase.prototype.getPixelRatio = function() { - return this.pixelRatio_; -}; - - -/** - * @return {number} Resolution. - */ -ol.ImageBase.prototype.getResolution = function() { - goog.asserts.assert(this.resolution !== undefined, 'resolution not yet set'); - return this.resolution; -}; - - -/** - * @return {ol.ImageState} State. - */ -ol.ImageBase.prototype.getState = function() { - return this.state; -}; - - -/** - * Load not yet loaded URI. - */ -ol.ImageBase.prototype.load = goog.abstractMethod; - -goog.provide('ol.vec.Mat4'); -goog.provide('ol.vec.Mat4.Number'); - -goog.require('goog.vec.Mat4'); - - -/** - * A alias for the goog.vec.Number type. - * @typedef {goog.vec.Number} - */ -ol.vec.Mat4.Number; - - -/** - * @param {!goog.vec.Mat4.Number} mat Matrix. - * @param {number} translateX1 Translate X1. - * @param {number} translateY1 Translate Y1. - * @param {number} scaleX Scale X. - * @param {number} scaleY Scale Y. - * @param {number} rotation Rotation. - * @param {number} translateX2 Translate X2. - * @param {number} translateY2 Translate Y2. - * @return {!goog.vec.Mat4.Number} Matrix. - */ -ol.vec.Mat4.makeTransform2D = function(mat, translateX1, translateY1, - scaleX, scaleY, rotation, translateX2, translateY2) { - goog.vec.Mat4.makeIdentity(mat); - if (translateX1 !== 0 || translateY1 !== 0) { - goog.vec.Mat4.translate(mat, translateX1, translateY1, 0); - } - if (scaleX != 1 || scaleY != 1) { - goog.vec.Mat4.scale(mat, scaleX, scaleY, 1); - } - if (rotation !== 0) { - goog.vec.Mat4.rotateZ(mat, rotation); - } - if (translateX2 !== 0 || translateY2 !== 0) { - goog.vec.Mat4.translate(mat, translateX2, translateY2, 0); - } - return mat; -}; - - -/** - * Returns true if mat1 and mat2 represent the same 2D transformation. - * @param {goog.vec.Mat4.Number} mat1 Matrix 1. - * @param {goog.vec.Mat4.Number} mat2 Matrix 2. - * @return {boolean} Equal 2D. - */ -ol.vec.Mat4.equals2D = function(mat1, mat2) { - return ( - goog.vec.Mat4.getElement(mat1, 0, 0) == - goog.vec.Mat4.getElement(mat2, 0, 0) && - goog.vec.Mat4.getElement(mat1, 1, 0) == - goog.vec.Mat4.getElement(mat2, 1, 0) && - goog.vec.Mat4.getElement(mat1, 0, 1) == - goog.vec.Mat4.getElement(mat2, 0, 1) && - goog.vec.Mat4.getElement(mat1, 1, 1) == - goog.vec.Mat4.getElement(mat2, 1, 1) && - goog.vec.Mat4.getElement(mat1, 0, 3) == - goog.vec.Mat4.getElement(mat2, 0, 3) && - goog.vec.Mat4.getElement(mat1, 1, 3) == - goog.vec.Mat4.getElement(mat2, 1, 3)); -}; - - -/** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * upper 2x4 matrix omitting the projective component. - * - * @param {goog.vec.Mat4.Number} mat The matrix supplying the transformation. - * @param {Array.<number>} vec The 3 element vector to transform. - * @param {Array.<number>} resultVec The 3 element vector to receive the results - * (may be vec). - * @return {Array.<number>} return resultVec so that operations can be - * chained together. - */ -ol.vec.Mat4.multVec2 = function(mat, vec, resultVec) { - var m00 = goog.vec.Mat4.getElement(mat, 0, 0); - var m10 = goog.vec.Mat4.getElement(mat, 1, 0); - var m01 = goog.vec.Mat4.getElement(mat, 0, 1); - var m11 = goog.vec.Mat4.getElement(mat, 1, 1); - var m03 = goog.vec.Mat4.getElement(mat, 0, 3); - var m13 = goog.vec.Mat4.getElement(mat, 1, 3); - var x = vec[0], y = vec[1]; - resultVec[0] = m00 * x + m01 * y + m03; - resultVec[1] = m10 * x + m11 * y + m13; - return resultVec; -}; - -goog.provide('ol.renderer.Layer'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.functions'); -goog.require('ol'); -goog.require('ol.ImageState'); -goog.require('ol.Observable'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.layer.Layer'); -goog.require('ol.source.Source'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.Observable} - * @param {ol.layer.Layer} layer Layer. - * @struct - */ -ol.renderer.Layer = function(layer) { - - goog.base(this); - - /** - * @private - * @type {ol.layer.Layer} - */ - this.layer_ = layer; - - -}; -goog.inherits(ol.renderer.Layer, ol.Observable); - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState Frame state. - * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T} - * callback Feature callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @return {T|undefined} Callback result. - * @template S,T - */ -ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction; - - -/** - * @param {ol.Pixel} pixel Pixel. - * @param {olx.FrameState} frameState Frame state. - * @param {function(this: S, ol.layer.Layer): T} callback Layer callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @return {T|undefined} Callback result. - * @template S,T - */ -ol.renderer.Layer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); - - if (hasFeature) { - return callback.call(thisArg, this.layer_); - } else { - return undefined; - } -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState Frame state. - * @return {boolean} Is there a feature at the given coordinate? - */ -ol.renderer.Layer.prototype.hasFeatureAtCoordinate = goog.functions.FALSE; - - -/** - * Create a function that adds loaded tiles to the tile lookup. - * @param {ol.source.Tile} source Tile source. - * @param {ol.proj.Projection} projection Projection of the tiles. - * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded - * tiles by zoom level. - * @return {function(number, ol.TileRange):boolean} A function that can be - * called with a zoom level and a tile range to add loaded tiles to the - * lookup. - * @protected - */ -ol.renderer.Layer.prototype.createLoadedTileFinder = - function(source, projection, tiles) { - return ( - /** - * @param {number} zoom Zoom level. - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} The tile range is fully loaded. - */ - function(zoom, tileRange) { - return source.forEachLoadedTile(projection, zoom, - tileRange, function(tile) { - if (!tiles[zoom]) { - tiles[zoom] = {}; - } - tiles[zoom][tile.tileCoord.toString()] = tile; - }); - }); -}; - - -/** - * @return {ol.layer.Layer} Layer. - */ -ol.renderer.Layer.prototype.getLayer = function() { - return this.layer_; -}; - - -/** - * Handle changes in image state. - * @param {goog.events.Event} event Image change event. - * @private - */ -ol.renderer.Layer.prototype.handleImageChange_ = function(event) { - var image = /** @type {ol.Image} */ (event.target); - if (image.getState() === ol.ImageState.LOADED) { - this.renderIfReadyAndVisible(); - } -}; - - -/** - * Load the image if not already loaded, and register the image change - * listener if needed. - * @param {ol.ImageBase} image Image. - * @return {boolean} `true` if the image is already loaded, `false` - * otherwise. - * @protected - */ -ol.renderer.Layer.prototype.loadImage = function(image) { - var imageState = image.getState(); - if (imageState != ol.ImageState.LOADED && - imageState != ol.ImageState.ERROR) { - // the image is either "idle" or "loading", register the change - // listener (a noop if the listener was already registered) - goog.asserts.assert(imageState == ol.ImageState.IDLE || - imageState == ol.ImageState.LOADING, - 'imageState is "idle" or "loading"'); - goog.events.listen(image, goog.events.EventType.CHANGE, - this.handleImageChange_, false, this); - } - if (imageState == ol.ImageState.IDLE) { - image.load(); - imageState = image.getState(); - goog.asserts.assert(imageState == ol.ImageState.LOADING || - imageState == ol.ImageState.LOADED, - 'imageState is "loading" or "loaded"'); - } - return imageState == ol.ImageState.LOADED; -}; - - -/** - * @protected - */ -ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() { - var layer = this.getLayer(); - if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) { - this.changed(); - } -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.source.Tile} tileSource Tile source. - * @protected - */ -ol.renderer.Layer.prototype.scheduleExpireCache = - function(frameState, tileSource) { - if (tileSource.canExpireCache()) { - frameState.postRenderFunctions.push( - goog.partial( - /** - * @param {ol.source.Tile} tileSource Tile source. - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. - */ - function(tileSource, map, frameState) { - var tileSourceKey = goog.getUid(tileSource).toString(); - tileSource.expireCache(frameState.viewState.projection, - frameState.usedTiles[tileSourceKey]); - }, tileSource)); - } -}; - - -/** - * @param {Object.<string, ol.Attribution>} attributionsSet Attributions - * set (target). - * @param {Array.<ol.Attribution>} attributions Attributions (source). - * @protected - */ -ol.renderer.Layer.prototype.updateAttributions = - function(attributionsSet, attributions) { - if (attributions) { - var attribution, i, ii; - for (i = 0, ii = attributions.length; i < ii; ++i) { - attribution = attributions[i]; - attributionsSet[goog.getUid(attribution).toString()] = attribution; - } - } -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.source.Source} source Source. - * @protected - */ -ol.renderer.Layer.prototype.updateLogos = function(frameState, source) { - var logo = source.getLogo(); - if (logo !== undefined) { - if (goog.isString(logo)) { - frameState.logos[logo] = ''; - } else if (goog.isObject(logo)) { - goog.asserts.assertString(logo.href, 'logo.href is a string'); - goog.asserts.assertString(logo.src, 'logo.src is a string'); - frameState.logos[logo.src] = logo.href; - } - } -}; - - -/** - * @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles. - * @param {ol.source.Tile} tileSource Tile source. - * @param {number} z Z. - * @param {ol.TileRange} tileRange Tile range. - * @protected - */ -ol.renderer.Layer.prototype.updateUsedTiles = - function(usedTiles, tileSource, z, tileRange) { - // FIXME should we use tilesToDrawByZ instead? - var tileSourceKey = goog.getUid(tileSource).toString(); - var zKey = z.toString(); - if (tileSourceKey in usedTiles) { - if (zKey in usedTiles[tileSourceKey]) { - usedTiles[tileSourceKey][zKey].extend(tileRange); - } else { - usedTiles[tileSourceKey][zKey] = tileRange; - } - } else { - usedTiles[tileSourceKey] = {}; - usedTiles[tileSourceKey][zKey] = tileRange; - } -}; - - -/** - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {ol.Size} size Size. - * @protected - * @return {ol.Coordinate} Snapped center. - */ -ol.renderer.Layer.prototype.snapCenterToPixel = - function(center, resolution, size) { - return [ - resolution * (Math.round(center[0] / resolution) + (size[0] % 2) / 2), - resolution * (Math.round(center[1] / resolution) + (size[1] % 2) / 2) - ]; -}; - - -/** - * Manage tile pyramid. - * This function performs a number of functions related to the tiles at the - * current zoom and lower zoom levels: - * - registers idle tiles in frameState.wantedTiles so that they are not - * discarded by the tile queue - * - enqueues missing tiles - * @param {olx.FrameState} frameState Frame state. - * @param {ol.source.Tile} tileSource Tile source. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {ol.Extent} extent Extent. - * @param {number} currentZ Current Z. - * @param {number} preload Load low resolution tiles up to 'preload' levels. - * @param {function(this: T, ol.Tile)=} opt_tileCallback Tile callback. - * @param {T=} opt_this Object to use as `this` in `opt_tileCallback`. - * @protected - * @template T - */ -ol.renderer.Layer.prototype.manageTilePyramid = function( - frameState, tileSource, tileGrid, pixelRatio, projection, extent, - currentZ, preload, opt_tileCallback, opt_this) { - var tileSourceKey = goog.getUid(tileSource).toString(); - if (!(tileSourceKey in frameState.wantedTiles)) { - frameState.wantedTiles[tileSourceKey] = {}; - } - var wantedTiles = frameState.wantedTiles[tileSourceKey]; - var tileQueue = frameState.tileQueue; - var minZoom = tileGrid.getMinZoom(); - var tile, tileRange, tileResolution, x, y, z; - for (z = currentZ; z >= minZoom; --z) { - tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange); - tileResolution = tileGrid.getResolution(z); - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - if (currentZ - z <= preload) { - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - if (tile.getState() == ol.TileState.IDLE) { - wantedTiles[ol.tilecoord.toString(tile.tileCoord)] = true; - if (!tileQueue.isKeyQueued(tile.getKey())) { - tileQueue.enqueue([tile, tileSourceKey, - tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]); - } - } - if (opt_tileCallback !== undefined) { - opt_tileCallback.call(opt_this, tile); - } - } else { - tileSource.useTile(z, x, y, projection); - } - } - } - } -}; - -goog.provide('ol.style.Image'); -goog.provide('ol.style.ImageState'); - - -/** - * @enum {number} - */ -ol.style.ImageState = { - IDLE: 0, - LOADING: 1, - LOADED: 2, - ERROR: 3 -}; - - -/** - * @typedef {{opacity: number, - * rotateWithView: boolean, - * rotation: number, - * scale: number, - * snapToPixel: boolean}} - */ -ol.style.ImageOptions; - - - -/** - * @classdesc - * A base class used for creating subclasses and not instantiated in - * apps. Base class for {@link ol.style.Icon} and {@link ol.style.Circle}. - * - * @constructor - * @param {ol.style.ImageOptions} options Options. - * @api - */ -ol.style.Image = function(options) { - - /** - * @private - * @type {number} - */ - this.opacity_ = options.opacity; - - /** - * @private - * @type {boolean} - */ - this.rotateWithView_ = options.rotateWithView; - - /** - * @private - * @type {number} - */ - this.rotation_ = options.rotation; - - /** - * @private - * @type {number} - */ - this.scale_ = options.scale; - - /** - * @private - * @type {boolean} - */ - this.snapToPixel_ = options.snapToPixel; - -}; - - -/** - * Get the symbolizer opacity. - * @return {number} Opacity. - * @api - */ -ol.style.Image.prototype.getOpacity = function() { - return this.opacity_; -}; - - -/** - * Determine whether the symbolizer rotates with the map. - * @return {boolean} Rotate with map. - * @api - */ -ol.style.Image.prototype.getRotateWithView = function() { - return this.rotateWithView_; -}; - - -/** - * Get the symoblizer rotation. - * @return {number} Rotation. - * @api - */ -ol.style.Image.prototype.getRotation = function() { - return this.rotation_; -}; - - -/** - * Get the symbolizer scale. - * @return {number} Scale. - * @api - */ -ol.style.Image.prototype.getScale = function() { - return this.scale_; -}; - - -/** - * Determine whether the symbolizer should be snapped to a pixel. - * @return {boolean} The symbolizer should snap to a pixel. - * @api - */ -ol.style.Image.prototype.getSnapToPixel = function() { - return this.snapToPixel_; -}; - - -/** - * Get the anchor point. The anchor determines the center point for the - * symbolizer. Its units are determined by `anchorXUnits` and `anchorYUnits`. - * @function - * @return {Array.<number>} Anchor. - */ -ol.style.Image.prototype.getAnchor = goog.abstractMethod; - - -/** - * Get the image element for the symbolizer. - * @function - * @param {number} pixelRatio Pixel ratio. - * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element. - */ -ol.style.Image.prototype.getImage = goog.abstractMethod; - - -/** - * @param {number} pixelRatio Pixel ratio. - * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element. - */ -ol.style.Image.prototype.getHitDetectionImage = goog.abstractMethod; - - -/** - * @return {ol.style.ImageState} Image state. - */ -ol.style.Image.prototype.getImageState = goog.abstractMethod; - - -/** - * @return {ol.Size} Image size. - */ -ol.style.Image.prototype.getImageSize = goog.abstractMethod; - - -/** - * @return {ol.Size} Size of the hit-detection image. - */ -ol.style.Image.prototype.getHitDetectionImageSize = goog.abstractMethod; - - -/** - * Get the origin of the symbolizer. - * @function - * @return {Array.<number>} Origin. - */ -ol.style.Image.prototype.getOrigin = goog.abstractMethod; - - -/** - * Get the size of the symbolizer (in pixels). - * @function - * @return {ol.Size} Size. - */ -ol.style.Image.prototype.getSize = goog.abstractMethod; - - -/** - * Set the opacity. - * - * @param {number} opacity Opacity. - * @api - */ -ol.style.Image.prototype.setOpacity = function(opacity) { - this.opacity_ = opacity; -}; - - -/** - * Set whether to rotate the style with the view. - * - * @param {boolean} rotateWithView Rotate with map. - */ -ol.style.Image.prototype.setRotateWithView = function(rotateWithView) { - this.rotateWithView_ = rotateWithView; -}; - - -/** - * Set the rotation. - * - * @param {number} rotation Rotation. - * @api - */ -ol.style.Image.prototype.setRotation = function(rotation) { - this.rotation_ = rotation; -}; - - -/** - * Set the scale. - * - * @param {number} scale Scale. - * @api - */ -ol.style.Image.prototype.setScale = function(scale) { - this.scale_ = scale; -}; - - -/** - * Set whether to snap the image to the closest pixel. - * - * @param {boolean} snapToPixel Snap to pixel? - */ -ol.style.Image.prototype.setSnapToPixel = function(snapToPixel) { - this.snapToPixel_ = snapToPixel; -}; - - -/** - * @param {function(this: T, goog.events.Event)} listener Listener function. - * @param {T} thisArg Value to use as `this` when executing `listener`. - * @return {goog.events.Key|undefined} Listener key. - * @template T - */ -ol.style.Image.prototype.listenImageChange = goog.abstractMethod; - - -/** - * Load not yet loaded URI. - */ -ol.style.Image.prototype.load = goog.abstractMethod; - - -/** - * @param {function(this: T, goog.events.Event)} listener Listener function. - * @param {T} thisArg Value to use as `this` when executing `listener`. - * @template T - */ -ol.style.Image.prototype.unlistenImageChange = goog.abstractMethod; - -goog.provide('ol.style.Icon'); -goog.provide('ol.style.IconAnchorUnits'); -goog.provide('ol.style.IconImageCache'); -goog.provide('ol.style.IconOrigin'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('ol.dom'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); - - -/** - * Icon anchor units. One of 'fraction', 'pixels'. - * @enum {string} - * @api - */ -ol.style.IconAnchorUnits = { - FRACTION: 'fraction', - PIXELS: 'pixels' -}; - - -/** - * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'. - * @enum {string} - * @api - */ -ol.style.IconOrigin = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_RIGHT: 'bottom-right', - TOP_LEFT: 'top-left', - TOP_RIGHT: 'top-right' -}; - - - -/** - * @classdesc - * Set icon style for vector features. - * - * @constructor - * @param {olx.style.IconOptions=} opt_options Options. - * @extends {ol.style.Image} - * @api - */ -ol.style.Icon = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {Array.<number>} - */ - this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5]; - - /** - * @private - * @type {Array.<number>} - */ - this.normalizedAnchor_ = null; - - /** - * @private - * @type {ol.style.IconOrigin} - */ - this.anchorOrigin_ = options.anchorOrigin !== undefined ? - options.anchorOrigin : ol.style.IconOrigin.TOP_LEFT; - - /** - * @private - * @type {ol.style.IconAnchorUnits} - */ - this.anchorXUnits_ = options.anchorXUnits !== undefined ? - options.anchorXUnits : ol.style.IconAnchorUnits.FRACTION; - - /** - * @private - * @type {ol.style.IconAnchorUnits} - */ - this.anchorYUnits_ = options.anchorYUnits !== undefined ? - options.anchorYUnits : ol.style.IconAnchorUnits.FRACTION; - - /** - * @type {?string} - */ - var crossOrigin = - options.crossOrigin !== undefined ? options.crossOrigin : null; - - /** - * @type {Image} - */ - var image = options.img !== undefined ? options.img : null; - - /** - * @type {ol.Size} - */ - var imgSize = options.imgSize !== undefined ? options.imgSize : null; - - /** - * @type {string|undefined} - */ - var src = options.src; - - goog.asserts.assert(!(src !== undefined && image), - 'image and src can not provided at the same time'); - goog.asserts.assert( - src === undefined || (src !== undefined && !imgSize), - 'imgSize should not be set when src is provided'); - goog.asserts.assert( - !image || (image && imgSize), - 'imgSize must be set when image is provided'); - - if ((src === undefined || src.length === 0) && image) { - src = image.src; - } - goog.asserts.assert(src !== undefined && src.length > 0, - 'must provide a defined and non-empty src or image'); - - /** - * @type {ol.style.ImageState} - */ - var imageState = options.src !== undefined ? - ol.style.ImageState.IDLE : ol.style.ImageState.LOADED; - - /** - * @private - * @type {ol.style.IconImage_} - */ - this.iconImage_ = ol.style.IconImage_.get( - image, src, imgSize, crossOrigin, imageState); - - /** - * @private - * @type {Array.<number>} - */ - this.offset_ = options.offset !== undefined ? options.offset : [0, 0]; - - /** - * @private - * @type {ol.style.IconOrigin} - */ - this.offsetOrigin_ = options.offsetOrigin !== undefined ? - options.offsetOrigin : ol.style.IconOrigin.TOP_LEFT; - - /** - * @private - * @type {Array.<number>} - */ - this.origin_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.size_ = options.size !== undefined ? options.size : null; - - /** - * @type {number} - */ - var opacity = options.opacity !== undefined ? options.opacity : 1; - - /** - * @type {boolean} - */ - var rotateWithView = options.rotateWithView !== undefined ? - options.rotateWithView : false; - - /** - * @type {number} - */ - var rotation = options.rotation !== undefined ? options.rotation : 0; - - /** - * @type {number} - */ - var scale = options.scale !== undefined ? options.scale : 1; - - /** - * @type {boolean} - */ - var snapToPixel = options.snapToPixel !== undefined ? - options.snapToPixel : true; - - goog.base(this, { - opacity: opacity, - rotation: rotation, - scale: scale, - snapToPixel: snapToPixel, - rotateWithView: rotateWithView - }); - -}; -goog.inherits(ol.style.Icon, ol.style.Image); - - -/** - * @inheritDoc - * @api - */ -ol.style.Icon.prototype.getAnchor = function() { - if (this.normalizedAnchor_) { - return this.normalizedAnchor_; - } - var anchor = this.anchor_; - var size = this.getSize(); - if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION || - this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { - if (!size) { - return null; - } - anchor = this.anchor_.slice(); - if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION) { - anchor[0] *= size[0]; - } - if (this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { - anchor[1] *= size[1]; - } - } - - if (this.anchorOrigin_ != ol.style.IconOrigin.TOP_LEFT) { - if (!size) { - return null; - } - if (anchor === this.anchor_) { - anchor = this.anchor_.slice(); - } - if (this.anchorOrigin_ == ol.style.IconOrigin.TOP_RIGHT || - this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - anchor[0] = -anchor[0] + size[0]; - } - if (this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || - this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - anchor[1] = -anchor[1] + size[1]; - } - } - this.normalizedAnchor_ = anchor; - return this.normalizedAnchor_; -}; - - -/** - * Get the image icon. - * @param {number} pixelRatio Pixel ratio. - * @return {Image} Image element. - * @api - */ -ol.style.Icon.prototype.getImage = function(pixelRatio) { - return this.iconImage_.getImage(pixelRatio); -}; - - -/** - * Real Image size used. - * @return {ol.Size} Size. - */ -ol.style.Icon.prototype.getImageSize = function() { - return this.iconImage_.getSize(); -}; - - -/** - * @inheritDoc - */ -ol.style.Icon.prototype.getHitDetectionImageSize = function() { - return this.getImageSize(); -}; - - -/** - * @inheritDoc - */ -ol.style.Icon.prototype.getImageState = function() { - return this.iconImage_.getImageState(); -}; - - -/** - * @inheritDoc - */ -ol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) { - return this.iconImage_.getHitDetectionImage(pixelRatio); -}; - - -/** - * @inheritDoc - * @api - */ -ol.style.Icon.prototype.getOrigin = function() { - if (this.origin_) { - return this.origin_; - } - var offset = this.offset_; - - if (this.offsetOrigin_ != ol.style.IconOrigin.TOP_LEFT) { - var size = this.getSize(); - var iconImageSize = this.iconImage_.getSize(); - if (!size || !iconImageSize) { - return null; - } - offset = offset.slice(); - if (this.offsetOrigin_ == ol.style.IconOrigin.TOP_RIGHT || - this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - offset[0] = iconImageSize[0] - size[0] - offset[0]; - } - if (this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || - this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - offset[1] = iconImageSize[1] - size[1] - offset[1]; - } - } - this.origin_ = offset; - return this.origin_; -}; - - -/** - * Get the image URL. - * @return {string|undefined} Image src. - * @api - */ -ol.style.Icon.prototype.getSrc = function() { - return this.iconImage_.getSrc(); -}; - - -/** - * @inheritDoc - * @api - */ -ol.style.Icon.prototype.getSize = function() { - return !this.size_ ? this.iconImage_.getSize() : this.size_; -}; - - -/** - * @inheritDoc - */ -ol.style.Icon.prototype.listenImageChange = function(listener, thisArg) { - return goog.events.listen(this.iconImage_, goog.events.EventType.CHANGE, - listener, false, thisArg); -}; - - -/** - * Load not yet loaded URI. - * When rendering a feature with an icon style, the vector renderer will - * automatically call this method. However, you might want to call this - * method yourself for preloading or other purposes. - * @api - */ -ol.style.Icon.prototype.load = function() { - this.iconImage_.load(); -}; - - -/** - * @inheritDoc - */ -ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) { - goog.events.unlisten(this.iconImage_, goog.events.EventType.CHANGE, - listener, false, thisArg); -}; - - - -/** - * @constructor - * @param {Image} image Image. - * @param {string|undefined} src Src. - * @param {ol.Size} size Size. - * @param {?string} crossOrigin Cross origin. - * @param {ol.style.ImageState} imageState Image state. - * @extends {goog.events.EventTarget} - * @private - */ -ol.style.IconImage_ = function(image, src, size, crossOrigin, imageState) { - - goog.base(this); - - /** - * @private - * @type {Image|HTMLCanvasElement} - */ - this.hitDetectionImage_ = null; - - /** - * @private - * @type {Image} - */ - this.image_ = !image ? new Image() : image; - - if (crossOrigin !== null) { - this.image_.crossOrigin = crossOrigin; - } - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.imageListenerKeys_ = null; - - /** - * @private - * @type {ol.style.ImageState} - */ - this.imageState_ = imageState; - - /** - * @private - * @type {ol.Size} - */ - this.size_ = size; - - /** - * @private - * @type {string|undefined} - */ - this.src_ = src; - - /** - * @private - * @type {boolean} - */ - this.tainting_ = false; - if (this.imageState_ == ol.style.ImageState.LOADED) { - this.determineTainting_(); - } - -}; -goog.inherits(ol.style.IconImage_, goog.events.EventTarget); - - -/** - * @param {Image} image Image. - * @param {string} src Src. - * @param {ol.Size} size Size. - * @param {?string} crossOrigin Cross origin. - * @param {ol.style.ImageState} imageState Image state. - * @return {ol.style.IconImage_} Icon image. - */ -ol.style.IconImage_.get = function(image, src, size, crossOrigin, imageState) { - var iconImageCache = ol.style.IconImageCache.getInstance(); - var iconImage = iconImageCache.get(src, crossOrigin); - if (!iconImage) { - iconImage = new ol.style.IconImage_( - image, src, size, crossOrigin, imageState); - iconImageCache.set(src, crossOrigin, iconImage); - } - return iconImage; -}; - - -/** - * @private - */ -ol.style.IconImage_.prototype.determineTainting_ = function() { - var context = ol.dom.createCanvasContext2D(1, 1); - try { - context.drawImage(this.image_, 0, 0); - context.getImageData(0, 0, 1, 1); - } catch (e) { - this.tainting_ = true; - } -}; - - -/** - * @private - */ -ol.style.IconImage_.prototype.dispatchChangeEvent_ = function() { - this.dispatchEvent(goog.events.EventType.CHANGE); -}; - - -/** - * @private - */ -ol.style.IconImage_.prototype.handleImageError_ = function() { - this.imageState_ = ol.style.ImageState.ERROR; - this.unlistenImage_(); - this.dispatchChangeEvent_(); -}; - - -/** - * @private - */ -ol.style.IconImage_.prototype.handleImageLoad_ = function() { - this.imageState_ = ol.style.ImageState.LOADED; - this.size_ = [this.image_.width, this.image_.height]; - this.unlistenImage_(); - this.determineTainting_(); - this.dispatchChangeEvent_(); -}; - - -/** - * @param {number} pixelRatio Pixel ratio. - * @return {Image} Image element. - */ -ol.style.IconImage_.prototype.getImage = function(pixelRatio) { - return this.image_; -}; - - -/** - * @return {ol.style.ImageState} Image state. - */ -ol.style.IconImage_.prototype.getImageState = function() { - return this.imageState_; -}; - - -/** - * @param {number} pixelRatio Pixel ratio. - * @return {Image|HTMLCanvasElement} Image element. - */ -ol.style.IconImage_.prototype.getHitDetectionImage = function(pixelRatio) { - if (!this.hitDetectionImage_) { - if (this.tainting_) { - var width = this.size_[0]; - var height = this.size_[1]; - var context = ol.dom.createCanvasContext2D(width, height); - context.fillRect(0, 0, width, height); - this.hitDetectionImage_ = context.canvas; - } else { - this.hitDetectionImage_ = this.image_; - } - } - return this.hitDetectionImage_; -}; - - -/** - * @return {ol.Size} Image size. - */ -ol.style.IconImage_.prototype.getSize = function() { - return this.size_; -}; - - -/** - * @return {string|undefined} Image src. - */ -ol.style.IconImage_.prototype.getSrc = function() { - return this.src_; -}; - - -/** - * Load not yet loaded URI. - */ -ol.style.IconImage_.prototype.load = function() { - if (this.imageState_ == ol.style.ImageState.IDLE) { - goog.asserts.assert(this.src_ !== undefined, - 'this.src_ must not be undefined'); - goog.asserts.assert(!this.imageListenerKeys_, - 'no listener keys existing'); - this.imageState_ = ol.style.ImageState.LOADING; - this.imageListenerKeys_ = [ - goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, - this.handleImageError_, false, this), - goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, - this.handleImageLoad_, false, this) - ]; - try { - this.image_.src = this.src_; - } catch (e) { - this.handleImageError_(); - } - } -}; - - -/** - * Discards event handlers which listen for load completion or errors. - * - * @private - */ -ol.style.IconImage_.prototype.unlistenImage_ = function() { - goog.asserts.assert(this.imageListenerKeys_, - 'we must have listeners registered'); - this.imageListenerKeys_.forEach(goog.events.unlistenByKey); - this.imageListenerKeys_ = null; -}; - - - -/** - * @constructor - */ -ol.style.IconImageCache = function() { - - /** - * @type {Object.<string, ol.style.IconImage_>} - * @private - */ - this.cache_ = {}; - - /** - * @type {number} - * @private - */ - this.cacheSize_ = 0; - - /** - * @const - * @type {number} - * @private - */ - this.maxCacheSize_ = 32; -}; -goog.addSingletonGetter(ol.style.IconImageCache); - - -/** - * @param {string} src Src. - * @param {?string} crossOrigin Cross origin. - * @return {string} Cache key. - */ -ol.style.IconImageCache.getKey = function(src, crossOrigin) { - goog.asserts.assert(crossOrigin !== undefined, - 'argument crossOrigin must be defined'); - return crossOrigin + ':' + src; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.style.IconImageCache.prototype.clear = function() { - this.cache_ = {}; - this.cacheSize_ = 0; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.style.IconImageCache.prototype.expire = function() { - if (this.cacheSize_ > this.maxCacheSize_) { - var i = 0; - var key, iconImage; - for (key in this.cache_) { - iconImage = this.cache_[key]; - if ((i++ & 3) === 0 && !goog.events.hasListener(iconImage)) { - delete this.cache_[key]; - --this.cacheSize_; - } - } - } -}; - - -/** - * @param {string} src Src. - * @param {?string} crossOrigin Cross origin. - * @return {ol.style.IconImage_} Icon image. - */ -ol.style.IconImageCache.prototype.get = function(src, crossOrigin) { - var key = ol.style.IconImageCache.getKey(src, crossOrigin); - return key in this.cache_ ? this.cache_[key] : null; -}; - - -/** - * @param {string} src Src. - * @param {?string} crossOrigin Cross origin. - * @param {ol.style.IconImage_} iconImage Icon image. - */ -ol.style.IconImageCache.prototype.set = function(src, crossOrigin, iconImage) { - var key = ol.style.IconImageCache.getKey(src, crossOrigin); - this.cache_[key] = iconImage; - ++this.cacheSize_; -}; - -goog.provide('ol.RendererType'); -goog.provide('ol.renderer.Map'); - -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('goog.dispose'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.layer.Layer'); -goog.require('ol.renderer.Layer'); -goog.require('ol.style.IconImageCache'); -goog.require('ol.vec.Mat4'); - - -/** - * Available renderers: `'canvas'`, `'dom'` or `'webgl'`. - * @enum {string} - * @api stable - */ -ol.RendererType = { - CANVAS: 'canvas', - DOM: 'dom', - WEBGL: 'webgl' -}; - - - -/** - * @constructor - * @extends {goog.Disposable} - * @param {Element} container Container. - * @param {ol.Map} map Map. - * @struct - */ -ol.renderer.Map = function(container, map) { - - goog.base(this); - - - /** - * @private - * @type {ol.Map} - */ - this.map_ = map; - - /** - * @private - * @type {Object.<string, ol.renderer.Layer>} - */ - this.layerRenderers_ = {}; - - /** - * @private - * @type {Object.<string, goog.events.Key>} - */ - this.layerRendererListeners_ = {}; - -}; -goog.inherits(ol.renderer.Map, goog.Disposable); - - -/** - * @param {olx.FrameState} frameState FrameState. - * @protected - */ -ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) { - var viewState = frameState.viewState; - var coordinateToPixelMatrix = frameState.coordinateToPixelMatrix; - goog.asserts.assert(coordinateToPixelMatrix, - 'frameState has a coordinateToPixelMatrix'); - ol.vec.Mat4.makeTransform2D(coordinateToPixelMatrix, - frameState.size[0] / 2, frameState.size[1] / 2, - 1 / viewState.resolution, -1 / viewState.resolution, - -viewState.rotation, - -viewState.center[0], -viewState.center[1]); - var inverted = goog.vec.Mat4.invert( - coordinateToPixelMatrix, frameState.pixelToCoordinateMatrix); - goog.asserts.assert(inverted, 'matrix could be inverted'); -}; - - -/** - * @param {ol.layer.Layer} layer Layer. - * @protected - * @return {ol.renderer.Layer} layerRenderer Layer renderer. - */ -ol.renderer.Map.prototype.createLayerRenderer = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.renderer.Map.prototype.disposeInternal = function() { - goog.object.forEach(this.layerRenderers_, goog.dispose); - goog.base(this, 'disposeInternal'); -}; - - -/** - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.Map.expireIconCache_ = function(map, frameState) { - ol.style.IconImageCache.getInstance().expire(); -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState FrameState. - * @param {function(this: S, (ol.Feature|ol.render.Feature), - * ol.layer.Layer): T} callback Feature callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result. - * @template S,T,U - */ -ol.renderer.Map.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg, - layerFilter, thisArg2) { - var result; - var viewState = frameState.viewState; - var viewResolution = viewState.resolution; - - /** @type {Object.<string, boolean>} */ - var features = {}; - - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function forEachFeatureAtCoordinate(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, null); - } - } - - var projection = viewState.projection; - - var translatedCoordinate = coordinate; - if (projection.canWrapX()) { - var projectionExtent = projection.getExtent(); - var worldWidth = ol.extent.getWidth(projectionExtent); - var x = coordinate[0]; - if (x < projectionExtent[0] || x > projectionExtent[2]) { - var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth); - translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]]; - } - } - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (!layerState.managed || - (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerFilter.call(thisArg2, layer))) { - var layerRenderer = this.getLayerRenderer(layer); - if (layer.getSource()) { - result = layerRenderer.forEachFeatureAtCoordinate( - layer.getSource().getWrapX() ? translatedCoordinate : coordinate, - frameState, - layerState.managed ? callback : forEachFeatureAtCoordinate, - thisArg); - } - if (result) { - return result; - } - } - } - return undefined; -}; - - -/** - * @param {ol.Pixel} pixel Pixel. - * @param {olx.FrameState} frameState FrameState. - * @param {function(this: S, ol.layer.Layer): T} callback Layer - * callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result. - * @template S,T,U - */ -ol.renderer.Map.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg, - layerFilter, thisArg2) { - var result; - var viewState = frameState.viewState; - var viewResolution = viewState.resolution; - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerFilter.call(thisArg2, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - result = layerRenderer.forEachLayerAtPixel( - pixel, frameState, callback, thisArg); - if (result) { - return result; - } - } - } - return undefined; -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState FrameState. - * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @param {U} thisArg Value to use as `this` when executing `layerFilter`. - * @return {boolean} Is there a feature at the given coordinate? - * @template U - */ -ol.renderer.Map.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState, layerFilter, thisArg) { - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this, layerFilter, thisArg); - - return hasFeature !== undefined; -}; - - -/** - * @param {ol.layer.Layer} layer Layer. - * @protected - * @return {ol.renderer.Layer} Layer renderer. - */ -ol.renderer.Map.prototype.getLayerRenderer = function(layer) { - var layerKey = goog.getUid(layer).toString(); - if (layerKey in this.layerRenderers_) { - return this.layerRenderers_[layerKey]; - } else { - var layerRenderer = this.createLayerRenderer(layer); - this.layerRenderers_[layerKey] = layerRenderer; - this.layerRendererListeners_[layerKey] = goog.events.listen(layerRenderer, - goog.events.EventType.CHANGE, this.handleLayerRendererChange_, - false, this); - - return layerRenderer; - } -}; - - -/** - * @param {string} layerKey Layer key. - * @protected - * @return {ol.renderer.Layer} Layer renderer. - */ -ol.renderer.Map.prototype.getLayerRendererByKey = function(layerKey) { - goog.asserts.assert(layerKey in this.layerRenderers_, - 'given layerKey (%s) exists in layerRenderers', layerKey); - return this.layerRenderers_[layerKey]; -}; - - -/** - * @protected - * @return {Object.<number, ol.renderer.Layer>} Layer renderers. - */ -ol.renderer.Map.prototype.getLayerRenderers = function() { - return this.layerRenderers_; -}; - - -/** - * @return {ol.Map} Map. - */ -ol.renderer.Map.prototype.getMap = function() { - return this.map_; -}; - - -/** - * @return {string} Type - */ -ol.renderer.Map.prototype.getType = goog.abstractMethod; - - -/** - * Handle changes in a layer renderer. - * @private - */ -ol.renderer.Map.prototype.handleLayerRendererChange_ = function() { - this.map_.render(); -}; - - -/** - * @param {string} layerKey Layer key. - * @return {ol.renderer.Layer} Layer renderer. - * @private - */ -ol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) { - goog.asserts.assert(layerKey in this.layerRenderers_, - 'given layerKey (%s) exists in layerRenderers', layerKey); - var layerRenderer = this.layerRenderers_[layerKey]; - delete this.layerRenderers_[layerKey]; - - goog.asserts.assert(layerKey in this.layerRendererListeners_, - 'given layerKey (%s) exists in layerRendererListeners', layerKey); - goog.events.unlistenByKey(this.layerRendererListeners_[layerKey]); - delete this.layerRendererListeners_[layerKey]; - - return layerRenderer; -}; - - -/** - * Render. - * @param {?olx.FrameState} frameState Frame state. - */ -ol.renderer.Map.prototype.renderFrame = ol.nullFunction; - - -/** - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.Map.prototype.removeUnusedLayerRenderers_ = - function(map, frameState) { - var layerKey; - for (layerKey in this.layerRenderers_) { - if (!frameState || !(layerKey in frameState.layerStates)) { - goog.dispose(this.removeLayerRendererByKey_(layerKey)); - } - } -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @protected - */ -ol.renderer.Map.prototype.scheduleExpireIconCache = function(frameState) { - frameState.postRenderFunctions.push(ol.renderer.Map.expireIconCache_); -}; - - -/** - * @param {!olx.FrameState} frameState Frame state. - * @protected - */ -ol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers = - function(frameState) { - var layerKey; - for (layerKey in this.layerRenderers_) { - if (!(layerKey in frameState.layerStates)) { - frameState.postRenderFunctions.push( - goog.bind(this.removeUnusedLayerRenderers_, this)); - return; - } - } -}; - - -/** - * @param {ol.layer.LayerState} state1 - * @param {ol.layer.LayerState} state2 - * @return {number} - */ -ol.renderer.Map.sortByZIndex = function(state1, state2) { - return state1.zIndex - state2.zIndex; -}; - -goog.provide('ol.structs.PriorityQueue'); - -goog.require('goog.asserts'); -goog.require('goog.object'); - - - -/** - * Priority queue. - * - * The implementation is inspired from the Closure Library's Heap class and - * Python's heapq module. - * - * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html - * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py - * - * @constructor - * @param {function(T): number} priorityFunction Priority function. - * @param {function(T): string} keyFunction Key function. - * @struct - * @template T - */ -ol.structs.PriorityQueue = function(priorityFunction, keyFunction) { - - /** - * @type {function(T): number} - * @private - */ - this.priorityFunction_ = priorityFunction; - - /** - * @type {function(T): string} - * @private - */ - this.keyFunction_ = keyFunction; - - /** - * @type {Array.<T>} - * @private - */ - this.elements_ = []; - - /** - * @type {Array.<number>} - * @private - */ - this.priorities_ = []; - - /** - * @type {Object.<string, boolean>} - * @private - */ - this.queuedElements_ = {}; - -}; - - -/** - * @const - * @type {number} - */ -ol.structs.PriorityQueue.DROP = Infinity; - - -/** - * FIXME empty description for jsdoc - */ -ol.structs.PriorityQueue.prototype.assertValid = function() { - var elements = this.elements_; - var priorities = this.priorities_; - var n = elements.length; - goog.asserts.assert(priorities.length == n); - var i, priority; - for (i = 0; i < (n >> 1) - 1; ++i) { - priority = priorities[i]; - goog.asserts.assert(priority <= priorities[this.getLeftChildIndex_(i)], - 'priority smaller than or equal to priority of left child (%s <= %s)', - priority, priorities[this.getLeftChildIndex_(i)]); - goog.asserts.assert(priority <= priorities[this.getRightChildIndex_(i)], - 'priority smaller than or equal to priority of right child (%s <= %s)', - priority, priorities[this.getRightChildIndex_(i)]); - } -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.structs.PriorityQueue.prototype.clear = function() { - this.elements_.length = 0; - this.priorities_.length = 0; - goog.object.clear(this.queuedElements_); -}; - - -/** - * Remove and return the highest-priority element. O(log N). - * @return {T} Element. - */ -ol.structs.PriorityQueue.prototype.dequeue = function() { - var elements = this.elements_; - goog.asserts.assert(elements.length > 0, - 'must have elements in order to be able to dequeue'); - var priorities = this.priorities_; - var element = elements[0]; - if (elements.length == 1) { - elements.length = 0; - priorities.length = 0; - } else { - elements[0] = elements.pop(); - priorities[0] = priorities.pop(); - this.siftUp_(0); - } - var elementKey = this.keyFunction_(element); - goog.asserts.assert(elementKey in this.queuedElements_, - 'key %s is not listed as queued', elementKey); - delete this.queuedElements_[elementKey]; - return element; -}; - - -/** - * Enqueue an element. O(log N). - * @param {T} element Element. - */ -ol.structs.PriorityQueue.prototype.enqueue = function(element) { - goog.asserts.assert(!(this.keyFunction_(element) in this.queuedElements_), - 'key %s is already listed as queued', this.keyFunction_(element)); - var priority = this.priorityFunction_(element); - if (priority != ol.structs.PriorityQueue.DROP) { - this.elements_.push(element); - this.priorities_.push(priority); - this.queuedElements_[this.keyFunction_(element)] = true; - this.siftDown_(0, this.elements_.length - 1); - } -}; - - -/** - * @return {number} Count. - */ -ol.structs.PriorityQueue.prototype.getCount = function() { - return this.elements_.length; -}; - - -/** - * Gets the index of the left child of the node at the given index. - * @param {number} index The index of the node to get the left child for. - * @return {number} The index of the left child. - * @private - */ -ol.structs.PriorityQueue.prototype.getLeftChildIndex_ = function(index) { - return index * 2 + 1; -}; - - -/** - * Gets the index of the right child of the node at the given index. - * @param {number} index The index of the node to get the right child for. - * @return {number} The index of the right child. - * @private - */ -ol.structs.PriorityQueue.prototype.getRightChildIndex_ = function(index) { - return index * 2 + 2; -}; - - -/** - * Gets the index of the parent of the node at the given index. - * @param {number} index The index of the node to get the parent for. - * @return {number} The index of the parent. - * @private - */ -ol.structs.PriorityQueue.prototype.getParentIndex_ = function(index) { - return (index - 1) >> 1; -}; - - -/** - * Make this a heap. O(N). - * @private - */ -ol.structs.PriorityQueue.prototype.heapify_ = function() { - var i; - for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) { - this.siftUp_(i); - } -}; - - -/** - * @return {boolean} Is empty. - */ -ol.structs.PriorityQueue.prototype.isEmpty = function() { - return this.elements_.length === 0; -}; - - -/** - * @param {string} key Key. - * @return {boolean} Is key queued. - */ -ol.structs.PriorityQueue.prototype.isKeyQueued = function(key) { - return key in this.queuedElements_; -}; - - -/** - * @param {T} element Element. - * @return {boolean} Is queued. - */ -ol.structs.PriorityQueue.prototype.isQueued = function(element) { - return this.isKeyQueued(this.keyFunction_(element)); -}; - - -/** - * @param {number} index The index of the node to move down. - * @private - */ -ol.structs.PriorityQueue.prototype.siftUp_ = function(index) { - var elements = this.elements_; - var priorities = this.priorities_; - var count = elements.length; - var element = elements[index]; - var priority = priorities[index]; - var startIndex = index; - - while (index < (count >> 1)) { - var lIndex = this.getLeftChildIndex_(index); - var rIndex = this.getRightChildIndex_(index); - - var smallerChildIndex = rIndex < count && - priorities[rIndex] < priorities[lIndex] ? - rIndex : lIndex; - - elements[index] = elements[smallerChildIndex]; - priorities[index] = priorities[smallerChildIndex]; - index = smallerChildIndex; - } - - elements[index] = element; - priorities[index] = priority; - this.siftDown_(startIndex, index); -}; - - -/** - * @param {number} startIndex The index of the root. - * @param {number} index The index of the node to move up. - * @private - */ -ol.structs.PriorityQueue.prototype.siftDown_ = function(startIndex, index) { - var elements = this.elements_; - var priorities = this.priorities_; - var element = elements[index]; - var priority = priorities[index]; - - while (index > startIndex) { - var parentIndex = this.getParentIndex_(index); - if (priorities[parentIndex] > priority) { - elements[index] = elements[parentIndex]; - priorities[index] = priorities[parentIndex]; - index = parentIndex; - } else { - break; - } - } - elements[index] = element; - priorities[index] = priority; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.structs.PriorityQueue.prototype.reprioritize = function() { - var priorityFunction = this.priorityFunction_; - var elements = this.elements_; - var priorities = this.priorities_; - var index = 0; - var n = elements.length; - var element, i, priority; - for (i = 0; i < n; ++i) { - element = elements[i]; - priority = priorityFunction(element); - if (priority == ol.structs.PriorityQueue.DROP) { - delete this.queuedElements_[this.keyFunction_(element)]; - } else { - priorities[index] = priority; - elements[index++] = element; - } - } - elements.length = index; - priorities.length = index; - this.heapify_(); -}; - -goog.provide('ol.TilePriorityFunction'); -goog.provide('ol.TileQueue'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.Coordinate'); -goog.require('ol.TileState'); -goog.require('ol.structs.PriorityQueue'); - - -/** - * @typedef {function(ol.Tile, string, ol.Coordinate, number): number} - */ -ol.TilePriorityFunction; - - - -/** - * @constructor - * @extends {ol.structs.PriorityQueue.<Array>} - * @param {ol.TilePriorityFunction} tilePriorityFunction - * Tile priority function. - * @param {function(): ?} tileChangeCallback - * Function called on each tile change event. - * @struct - */ -ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) { - - goog.base( - this, - /** - * @param {Array} element Element. - * @return {number} Priority. - */ - function(element) { - return tilePriorityFunction.apply(null, element); - }, - /** - * @param {Array} element Element. - * @return {string} Key. - */ - function(element) { - return /** @type {ol.Tile} */ (element[0]).getKey(); - }); - - /** - * @private - * @type {function(): ?} - */ - this.tileChangeCallback_ = tileChangeCallback; - - /** - * @private - * @type {number} - */ - this.tilesLoading_ = 0; - -}; -goog.inherits(ol.TileQueue, ol.structs.PriorityQueue); - - -/** - * @return {number} Number of tiles loading. - */ -ol.TileQueue.prototype.getTilesLoading = function() { - return this.tilesLoading_; -}; - - -/** - * @param {goog.events.Event} event Event. - * @protected - */ -ol.TileQueue.prototype.handleTileChange = function(event) { - var tile = /** @type {ol.Tile} */ (event.target); - var state = tile.getState(); - if (state === ol.TileState.LOADED || state === ol.TileState.ERROR || - state === ol.TileState.EMPTY) { - goog.events.unlisten(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - --this.tilesLoading_; - this.tileChangeCallback_(); - } -}; - - -/** - * @param {number} maxTotalLoading Maximum number tiles to load simultaneously. - * @param {number} maxNewLoads Maximum number of new tiles to load. - */ -ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { - var newLoads = 0; - var tile; - while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads && - this.getCount() > 0) { - tile = /** @type {ol.Tile} */ (this.dequeue()[0]); - if (tile.getState() === ol.TileState.IDLE) { - goog.events.listen(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - tile.load(); - ++this.tilesLoading_; - ++newLoads; - } - } -}; - -goog.provide('ol.Kinetic'); - -goog.require('ol.Coordinate'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.animation'); - - - -/** - * @classdesc - * Implementation of inertial deceleration for map movement. - * - * @constructor - * @param {number} decay Rate of decay (must be negative). - * @param {number} minVelocity Minimum velocity (pixels/millisecond). - * @param {number} delay Delay to consider to calculate the kinetic - * initial values (milliseconds). - * @struct - * @api - */ -ol.Kinetic = function(decay, minVelocity, delay) { - - /** - * @private - * @type {number} - */ - this.decay_ = decay; - - /** - * @private - * @type {number} - */ - this.minVelocity_ = minVelocity; - - /** - * @private - * @type {number} - */ - this.delay_ = delay; - - /** - * @private - * @type {Array.<number>} - */ - this.points_ = []; - - /** - * @private - * @type {number} - */ - this.angle_ = 0; - - /** - * @private - * @type {number} - */ - this.initialVelocity_ = 0; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.Kinetic.prototype.begin = function() { - this.points_.length = 0; - this.angle_ = 0; - this.initialVelocity_ = 0; -}; - - -/** - * @param {number} x X. - * @param {number} y Y. - */ -ol.Kinetic.prototype.update = function(x, y) { - this.points_.push(x, y, Date.now()); -}; - - -/** - * @return {boolean} Whether we should do kinetic animation. - */ -ol.Kinetic.prototype.end = function() { - if (this.points_.length < 6) { - // at least 2 points are required (i.e. there must be at least 6 elements - // in the array) - return false; - } - var delay = Date.now() - this.delay_; - var lastIndex = this.points_.length - 3; - if (this.points_[lastIndex + 2] < delay) { - // the last tracked point is too old, which means that the user stopped - // panning before releasing the map - return false; - } - - // get the first point which still falls into the delay time - var firstIndex = lastIndex - 3; - while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) { - firstIndex -= 3; - } - var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2]; - var dx = this.points_[lastIndex] - this.points_[firstIndex]; - var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1]; - this.angle_ = Math.atan2(dy, dx); - this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration; - return this.initialVelocity_ > this.minVelocity_; -}; - - -/** - * @param {ol.Coordinate} source Source coordinate for the animation. - * @return {ol.PreRenderFunction} Pre-render function for kinetic animation. - */ -ol.Kinetic.prototype.pan = function(source) { - var decay = this.decay_; - var initialVelocity = this.initialVelocity_; - var velocity = this.minVelocity_ - initialVelocity; - var duration = this.getDuration_(); - var easingFunction = ( - /** - * @param {number} t T. - * @return {number} Easing. - */ - function(t) { - return initialVelocity * (Math.exp((decay * t) * duration) - 1) / - velocity; - }); - return ol.animation.pan({ - source: source, - duration: duration, - easing: easingFunction - }); -}; - - -/** - * @private - * @return {number} Duration of animation (milliseconds). - */ -ol.Kinetic.prototype.getDuration_ = function() { - return Math.log(this.minVelocity_ / this.initialVelocity_) / this.decay_; -}; - - -/** - * @return {number} Total distance travelled (pixels). - */ -ol.Kinetic.prototype.getDistance = function() { - return (this.minVelocity_ - this.initialVelocity_) / this.decay_; -}; - - -/** - * @return {number} Angle of the kinetic panning animation (radians). - */ -ol.Kinetic.prototype.getAngle = function() { - return this.angle_; -}; - -// FIXME factor out key precondition (shift et. al) - -goog.provide('ol.interaction.Interaction'); -goog.provide('ol.interaction.InteractionProperty'); - -goog.require('ol'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.Object'); -goog.require('ol.animation'); -goog.require('ol.easing'); - - -/** - * @enum {string} - */ -ol.interaction.InteractionProperty = { - ACTIVE: 'active' -}; - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * User actions that change the state of the map. Some are similar to controls, - * but are not associated with a DOM element. - * For example, {@link ol.interaction.KeyboardZoom} is functionally the same as - * {@link ol.control.Zoom}, but triggered by a keyboard event not a button - * element event. - * Although interactions do not have a DOM element, some of them do render - * vectors and so are visible on the screen. - * - * @constructor - * @param {olx.interaction.InteractionOptions} options Options. - * @extends {ol.Object} - * @api - */ -ol.interaction.Interaction = function(options) { - - goog.base(this); - - /** - * @private - * @type {ol.Map} - */ - this.map_ = null; - - this.setActive(true); - - /** - * @type {function(ol.MapBrowserEvent):boolean} - */ - this.handleEvent = options.handleEvent; - -}; -goog.inherits(ol.interaction.Interaction, ol.Object); - - -/** - * Return whether the interaction is currently active. - * @return {boolean} `true` if the interaction is active, `false` otherwise. - * @observable - * @api - */ -ol.interaction.Interaction.prototype.getActive = function() { - return /** @type {boolean} */ ( - this.get(ol.interaction.InteractionProperty.ACTIVE)); -}; - - -/** - * Get the map associated with this interaction. - * @return {ol.Map} Map. - */ -ol.interaction.Interaction.prototype.getMap = function() { - return this.map_; -}; - - -/** - * Activate or deactivate the interaction. - * @param {boolean} active Active. - * @observable - * @api - */ -ol.interaction.Interaction.prototype.setActive = function(active) { - this.set(ol.interaction.InteractionProperty.ACTIVE, active); -}; - - -/** - * Remove the interaction from its current map and attach it to the new map. - * Subclasses may set up event handlers to get notified about changes to - * the map here. - * @param {ol.Map} map Map. - */ -ol.interaction.Interaction.prototype.setMap = function(map) { - this.map_ = map; -}; - - -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {ol.Coordinate} delta Delta. - * @param {number=} opt_duration Duration. - */ -ol.interaction.Interaction.pan = function(map, view, delta, opt_duration) { - var currentCenter = view.getCenter(); - if (currentCenter) { - if (opt_duration && opt_duration > 0) { - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: opt_duration, - easing: ol.easing.linear - })); - } - var center = view.constrainCenter( - [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]); - view.setCenter(center); - } -}; - - -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} rotation Rotation. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - */ -ol.interaction.Interaction.rotate = - function(map, view, rotation, opt_anchor, opt_duration) { - rotation = view.constrainRotation(rotation, 0); - ol.interaction.Interaction.rotateWithoutConstraints( - map, view, rotation, opt_anchor, opt_duration); -}; - - -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} rotation Rotation. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - */ -ol.interaction.Interaction.rotateWithoutConstraints = - function(map, view, rotation, opt_anchor, opt_duration) { - if (rotation !== undefined) { - var currentRotation = view.getRotation(); - var currentCenter = view.getCenter(); - if (currentRotation !== undefined && currentCenter && - opt_duration && opt_duration > 0) { - map.beforeRender(ol.animation.rotate({ - rotation: currentRotation, - duration: opt_duration, - easing: ol.easing.easeOut - })); - if (opt_anchor) { - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: opt_duration, - easing: ol.easing.easeOut - })); - } - } - view.rotate(rotation, opt_anchor); - } -}; - - -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} resolution Resolution to go to. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - * @param {number=} opt_direction Zooming direction; > 0 indicates - * zooming out, in which case the constraints system will select - * the largest nearest resolution; < 0 indicates zooming in, in - * which case the constraints system will select the smallest - * nearest resolution; == 0 indicates that the zooming direction - * is unknown/not relevant, in which case the constraints system - * will select the nearest resolution. If not defined 0 is - * assumed. - */ -ol.interaction.Interaction.zoom = - function(map, view, resolution, opt_anchor, opt_duration, opt_direction) { - resolution = view.constrainResolution(resolution, 0, opt_direction); - ol.interaction.Interaction.zoomWithoutConstraints( - map, view, resolution, opt_anchor, opt_duration); -}; - - -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number} delta Delta from previous zoom level. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - */ -ol.interaction.Interaction.zoomByDelta = - function(map, view, delta, opt_anchor, opt_duration) { - var currentResolution = view.getResolution(); - var resolution = view.constrainResolution(currentResolution, delta, 0); - ol.interaction.Interaction.zoomWithoutConstraints( - map, view, resolution, opt_anchor, opt_duration); -}; - - -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} resolution Resolution to go to. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - */ -ol.interaction.Interaction.zoomWithoutConstraints = - function(map, view, resolution, opt_anchor, opt_duration) { - if (resolution) { - var currentResolution = view.getResolution(); - var currentCenter = view.getCenter(); - if (currentResolution !== undefined && currentCenter && - resolution !== currentResolution && - opt_duration && opt_duration > 0) { - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: opt_duration, - easing: ol.easing.easeOut - })); - if (opt_anchor) { - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: opt_duration, - easing: ol.easing.easeOut - })); - } - } - if (opt_anchor) { - var center = view.calculateCenterZoom(resolution, opt_anchor); - view.setCenter(center); - } - view.setResolution(resolution); - } -}; - -goog.provide('ol.interaction.DoubleClickZoom'); - -goog.require('goog.asserts'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.interaction.Interaction'); - - - -/** - * @classdesc - * Allows the user to zoom by double-clicking on the map. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.DoubleClickZoomOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DoubleClickZoom = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {number} - */ - this.delta_ = options.delta ? options.delta : 1; - - goog.base(this, { - handleEvent: ol.interaction.DoubleClickZoom.handleEvent - }); - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; - -}; -goog.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction); - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a - * doubleclick) and eventually zooms the map. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.DoubleClickZoom} - * @api - */ -ol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - var browserEvent = mapBrowserEvent.browserEvent; - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK) { - var map = mapBrowserEvent.map; - var anchor = mapBrowserEvent.coordinate; - var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_; - var view = map.getView(); - goog.asserts.assert(view, 'map must have a view'); - ol.interaction.Interaction.zoomByDelta( - map, view, delta, anchor, this.duration_); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - return !stopEvent; -}; - -goog.provide('ol.events.ConditionType'); -goog.provide('ol.events.condition'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserPointerEvent'); - - -/** - * A function that takes an {@link ol.MapBrowserEvent} and returns a - * `{boolean}`. If the condition is met, true should be returned. - * - * @typedef {function(ol.MapBrowserEvent): boolean} - * @api stable - */ -ol.events.ConditionType; - - -/** - * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when - * additionally the shift-key is pressed). - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the alt key is pressed. - * @api stable - */ -ol.events.condition.altKeyOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - browserEvent.altKey && - !browserEvent.platformModifierKey && - !browserEvent.shiftKey); -}; - - -/** - * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise - * (e.g. when additionally the platform-modifier-key is pressed). - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the alt and shift keys are pressed. - * @api stable - */ -ol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - browserEvent.altKey && - !browserEvent.platformModifierKey && - browserEvent.shiftKey); -}; - - -/** - * Return always true. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True. - * @function - * @api stable - */ -ol.events.condition.always = goog.functions.TRUE; - - -/** - * Return `true` if the event is a `click` event, `false` otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event is a map `click` event. - * @api stable - */ -ol.events.condition.click = function(mapBrowserEvent) { - return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.CLICK; -}; - - -/** - * Return always false. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} False. - * @function - * @api stable - */ -ol.events.condition.never = goog.functions.FALSE; - - -/** - * Return `true` if the browser event is a `pointermove` event, `false` - * otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the browser event is a `pointermove` event. - * @api - */ -ol.events.condition.pointerMove = function(mapBrowserEvent) { - return mapBrowserEvent.type == 'pointermove'; -}; - - -/** - * Return `true` if the event is a map `singleclick` event, `false` otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event is a map `singleclick` event. - * @api stable - */ -ol.events.condition.singleClick = function(mapBrowserEvent) { - return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK; -}; - - -/** - * Return `true` if the event is a map `dblclick` event, `false` otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event is a map `dblclick` event. - * @api stable - */ -ol.events.condition.doubleClick = function(mapBrowserEvent) { - return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK; -}; - - -/** - * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is - * pressed. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True only if there no modifier keys are pressed. - * @api stable - */ -ol.events.condition.noModifierKeys = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - !browserEvent.altKey && - !browserEvent.platformModifierKey && - !browserEvent.shiftKey); -}; - - -/** - * Return `true` if only the platform-modifier-key (the meta-key on Mac, - * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally - * the shift-key is pressed). - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the platform modifier key is pressed. - * @api stable - */ -ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - !browserEvent.altKey && - browserEvent.platformModifierKey && - !browserEvent.shiftKey); -}; - - -/** - * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when - * additionally the alt-key is pressed). - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the shift key is pressed. - * @api stable - */ -ol.events.condition.shiftKeyOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - !browserEvent.altKey && - !browserEvent.platformModifierKey && - browserEvent.shiftKey); -}; - - -/** - * Return `true` if the target element is not editable, i.e. not a `<input>`-, - * `<select>`- or `<textarea>`-element, `false` otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True only if the target element is not editable. - * @api - */ -ol.events.condition.targetNotEditable = function(mapBrowserEvent) { - var target = mapBrowserEvent.browserEvent.target; - goog.asserts.assertInstanceof(target, Element, - 'target should be an Element'); - var tagName = target.tagName; - return ( - tagName !== 'INPUT' && - tagName !== 'SELECT' && - tagName !== 'TEXTAREA'); -}; - - -/** - * Return `true` if the event originates from a mouse device. - * - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event originates from a mouse device. - * @api stable - */ -ol.events.condition.mouseOnly = function(mapBrowserEvent) { - // see http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType - return mapBrowserEvent.pointerEvent.pointerType == 'mouse'; -}; - -goog.provide('ol.interaction.Pointer'); - -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserPointerEvent'); -goog.require('ol.Pixel'); -goog.require('ol.interaction.Interaction'); - - - -/** - * @classdesc - * Base class that calls user-defined functions on `down`, `move` and `up` - * events. This class also manages "drag sequences". - * - * When the `handleDownEvent` user function returns `true` a drag sequence is - * started. During a drag sequence the `handleDragEvent` user function is - * called on `move` events. The drag sequence ends when the `handleUpEvent` - * user function is called and returns `false`. - * - * @constructor - * @param {olx.interaction.PointerOptions=} opt_options Options. - * @extends {ol.interaction.Interaction} - * @api - */ -ol.interaction.Pointer = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var handleEvent = options.handleEvent ? - options.handleEvent : ol.interaction.Pointer.handleEvent; - - goog.base(this, { - handleEvent: handleEvent - }); - - /** - * @type {function(ol.MapBrowserPointerEvent):boolean} - * @private - */ - this.handleDownEvent_ = options.handleDownEvent ? - options.handleDownEvent : ol.interaction.Pointer.handleDownEvent; - - /** - * @type {function(ol.MapBrowserPointerEvent)} - * @private - */ - this.handleDragEvent_ = options.handleDragEvent ? - options.handleDragEvent : ol.interaction.Pointer.handleDragEvent; - - /** - * @type {function(ol.MapBrowserPointerEvent)} - * @private - */ - this.handleMoveEvent_ = options.handleMoveEvent ? - options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent; - - /** - * @type {function(ol.MapBrowserPointerEvent):boolean} - * @private - */ - this.handleUpEvent_ = options.handleUpEvent ? - options.handleUpEvent : ol.interaction.Pointer.handleUpEvent; - - /** - * @type {boolean} - * @protected - */ - this.handlingDownUpSequence = false; - - /** - * @type {Object.<number, ol.pointer.PointerEvent>} - * @private - */ - this.trackedPointers_ = {}; - - /** - * @type {Array.<ol.pointer.PointerEvent>} - * @protected - */ - this.targetPointers = []; - -}; -goog.inherits(ol.interaction.Pointer, ol.interaction.Interaction); - - -/** - * @param {Array.<ol.pointer.PointerEvent>} pointerEvents - * @return {ol.Pixel} Centroid pixel. - */ -ol.interaction.Pointer.centroid = function(pointerEvents) { - var length = pointerEvents.length; - var clientX = 0; - var clientY = 0; - for (var i = 0; i < length; i++) { - clientX += pointerEvents[i].clientX; - clientY += pointerEvents[i].clientY; - } - return [clientX / length, clientY / length]; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Whether the event is a pointerdown, pointerdrag - * or pointerup event. - * @private - */ -ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = - function(mapBrowserEvent) { - var type = mapBrowserEvent.type; - return ( - type === ol.MapBrowserEvent.EventType.POINTERDOWN || - type === ol.MapBrowserEvent.EventType.POINTERDRAG || - type === ol.MapBrowserEvent.EventType.POINTERUP); -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @private - */ -ol.interaction.Pointer.prototype.updateTrackedPointers_ = - function(mapBrowserEvent) { - if (this.isPointerDraggingEvent_(mapBrowserEvent)) { - var event = mapBrowserEvent.pointerEvent; - - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { - delete this.trackedPointers_[event.pointerId]; - } else if (mapBrowserEvent.type == - ol.MapBrowserEvent.EventType.POINTERDOWN) { - this.trackedPointers_[event.pointerId] = event; - } else if (event.pointerId in this.trackedPointers_) { - // update only when there was a pointerdown event for this pointer - this.trackedPointers_[event.pointerId] = event; - } - this.targetPointers = goog.object.getValues(this.trackedPointers_); - } -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.Pointer} - */ -ol.interaction.Pointer.handleDragEvent = ol.nullFunction; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Capture dragging. - * @this {ol.interaction.Pointer} - */ -ol.interaction.Pointer.handleUpEvent = goog.functions.FALSE; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Capture dragging. - * @this {ol.interaction.Pointer} - */ -ol.interaction.Pointer.handleDownEvent = goog.functions.FALSE; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.Pointer} - */ -ol.interaction.Pointer.handleMoveEvent = ol.nullFunction; - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may call into - * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are - * detected. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Pointer} - * @api - */ -ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) { - if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) { - return true; - } - - var stopEvent = false; - this.updateTrackedPointers_(mapBrowserEvent); - if (this.handlingDownUpSequence) { - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDRAG) { - this.handleDragEvent_(mapBrowserEvent); - } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { - this.handlingDownUpSequence = this.handleUpEvent_(mapBrowserEvent); - } - } - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { - var handled = this.handleDownEvent_(mapBrowserEvent); - this.handlingDownUpSequence = handled; - stopEvent = this.shouldStopEvent(handled); - } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE) { - this.handleMoveEvent_(mapBrowserEvent); - } - return !stopEvent; -}; - - -/** - * This method is used to determine if "down" events should be propagated to - * other interactions or should be stopped. - * - * The method receives the return code of the "handleDownEvent" function. - * - * By default this function is the "identity" function. It's overidden in - * child classes. - * - * @param {boolean} handled Was the event handled by the interaction? - * @return {boolean} Should the event be stopped? - * @protected - */ -ol.interaction.Pointer.prototype.shouldStopEvent = goog.functions.identity; - -goog.provide('ol.interaction.DragPan'); - -goog.require('goog.asserts'); -goog.require('ol.Kinetic'); -goog.require('ol.Pixel'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.ViewHint'); -goog.require('ol.coordinate'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Pointer'); - - - -/** - * @classdesc - * Allows the user to pan the map by dragging the map. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.DragPanOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragPan = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.DragPan.handleDownEvent_, - handleDragEvent: ol.interaction.DragPan.handleDragEvent_, - handleUpEvent: ol.interaction.DragPan.handleUpEvent_ - }); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {ol.Kinetic|undefined} - */ - this.kinetic_ = options.kinetic; - - /** - * @private - * @type {?ol.PreRenderFunction} - */ - this.kineticPreRenderFn_ = null; - - /** - * @type {ol.Pixel} - */ - this.lastCentroid = null; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.noModifierKeys; - - /** - * @private - * @type {boolean} - */ - this.noKinetic_ = false; - -}; -goog.inherits(ol.interaction.DragPan, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragPan} - * @private - */ -ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) { - goog.asserts.assert(this.targetPointers.length >= 1, - 'the length of this.targetPointers should be more than 1'); - var centroid = - ol.interaction.Pointer.centroid(this.targetPointers); - if (this.kinetic_) { - this.kinetic_.update(centroid[0], centroid[1]); - } - if (this.lastCentroid) { - var deltaX = this.lastCentroid[0] - centroid[0]; - var deltaY = centroid[1] - this.lastCentroid[1]; - var map = mapBrowserEvent.map; - var view = map.getView(); - var viewState = view.getState(); - var center = [deltaX, deltaY]; - ol.coordinate.scale(center, viewState.resolution); - ol.coordinate.rotate(center, viewState.rotation); - ol.coordinate.add(center, viewState.center); - center = view.constrainCenter(center); - map.render(); - view.setCenter(center); - } - this.lastCentroid = centroid; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragPan} - * @private - */ -ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) { - var map = mapBrowserEvent.map; - var view = map.getView(); - if (this.targetPointers.length === 0) { - if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) { - var distance = this.kinetic_.getDistance(); - var angle = this.kinetic_.getAngle(); - var center = view.getCenter(); - goog.asserts.assert(center !== undefined, 'center should be defined'); - this.kineticPreRenderFn_ = this.kinetic_.pan(center); - map.beforeRender(this.kineticPreRenderFn_); - var centerpx = map.getPixelFromCoordinate(center); - var dest = map.getCoordinateFromPixel([ - centerpx[0] - distance * Math.cos(angle), - centerpx[1] - distance * Math.sin(angle) - ]); - dest = view.constrainCenter(dest); - view.setCenter(dest); - } - view.setHint(ol.ViewHint.INTERACTING, -1); - map.render(); - return false; - } else { - this.lastCentroid = null; - return true; - } -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragPan} - * @private - */ -ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) { - var map = mapBrowserEvent.map; - var view = map.getView(); - this.lastCentroid = null; - if (!this.handlingDownUpSequence) { - view.setHint(ol.ViewHint.INTERACTING, 1); - } - map.render(); - if (this.kineticPreRenderFn_ && - map.removePreRenderFunction(this.kineticPreRenderFn_)) { - view.setCenter(mapBrowserEvent.frameState.viewState.center); - this.kineticPreRenderFn_ = null; - } - if (this.kinetic_) { - this.kinetic_.begin(); - } - // No kinetic as soon as more than one pointer on the screen is - // detected. This is to prevent nasty pans after pinch. - this.noKinetic_ = this.targetPointers.length > 1; - return true; - } else { - return false; - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.DragPan.prototype.shouldStopEvent = goog.functions.FALSE; - -goog.provide('ol.interaction.DragRotate'); - -goog.require('ol'); -goog.require('ol.ViewHint'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); - - - -/** - * @classdesc - * Allows the user to rotate the map by clicking and dragging on the map, - * normally combined with an {@link ol.events.condition} that limits - * it to when the alt and shift keys are held down. - * - * This interaction is only supported for mouse devices. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.DragRotateOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragRotate = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this, { - handleDownEvent: ol.interaction.DragRotate.handleDownEvent_, - handleDragEvent: ol.interaction.DragRotate.handleDragEvent_, - handleUpEvent: ol.interaction.DragRotate.handleUpEvent_ - }); - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.altShiftKeysOnly; - - /** - * @private - * @type {number|undefined} - */ - this.lastAngle_ = undefined; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; -}; -goog.inherits(ol.interaction.DragRotate, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragRotate} - * @private - */ -ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return; - } - - var map = mapBrowserEvent.map; - var size = map.getSize(); - var offset = mapBrowserEvent.pixel; - var theta = - Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2); - if (this.lastAngle_ !== undefined) { - var delta = theta - this.lastAngle_; - var view = map.getView(); - var rotation = view.getRotation(); - map.render(); - ol.interaction.Interaction.rotateWithoutConstraints( - map, view, rotation - delta); - } - this.lastAngle_ = theta; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragRotate} - * @private - */ -ol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return true; - } - - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - var rotation = view.getRotation(); - ol.interaction.Interaction.rotate(map, view, rotation, - undefined, this.duration_); - return false; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragRotate} - * @private - */ -ol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return false; - } - - var browserEvent = mapBrowserEvent.browserEvent; - if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) { - var map = mapBrowserEvent.map; - map.getView().setHint(ol.ViewHint.INTERACTING, 1); - map.render(); - this.lastAngle_ = undefined; - return true; - } else { - return false; - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.DragRotate.prototype.shouldStopEvent = goog.functions.FALSE; - -// FIXME add rotation - -goog.provide('ol.render.Box'); - -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('ol.geom.Polygon'); - - - -/** - * @constructor - * @extends {goog.Disposable} - * @param {string} className CSS class name. - */ -ol.render.Box = function(className) { - - /** - * @type {ol.geom.Polygon} - * @private - */ - this.geometry_ = null; - - /** - * @type {HTMLDivElement} - * @private - */ - this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div')); - this.element_.style.position = 'absolute'; - this.element_.className = 'ol-box ' + className; - - /** - * @private - * @type {ol.Map} - */ - this.map_ = null; - - /** - * @private - * @type {ol.Pixel} - */ - this.startPixel_ = null; - - /** - * @private - * @type {ol.Pixel} - */ - this.endPixel_ = null; - -}; -goog.inherits(ol.render.Box, goog.Disposable); - - -/** - * @inheritDoc - */ -ol.render.Box.prototype.disposeInternal = function() { - this.setMap(null); - goog.base(this, 'disposeInternal'); -}; - - -/** - * @private - */ -ol.render.Box.prototype.render_ = function() { - var startPixel = this.startPixel_; - var endPixel = this.endPixel_; - goog.asserts.assert(startPixel, 'this.startPixel_ must be truthy'); - goog.asserts.assert(endPixel, 'this.endPixel_ must be truthy'); - var px = 'px'; - var style = this.element_.style; - style.left = Math.min(startPixel[0], endPixel[0]) + px; - style.top = Math.min(startPixel[1], endPixel[1]) + px; - style.width = Math.abs(endPixel[0] - startPixel[0]) + px; - style.height = Math.abs(endPixel[1] - startPixel[1]) + px; -}; - - -/** - * @param {ol.Map} map Map. - */ -ol.render.Box.prototype.setMap = function(map) { - if (this.map_) { - this.map_.getOverlayContainer().removeChild(this.element_); - var style = this.element_.style; - style.left = style.top = style.width = style.height = 'inherit'; - } - this.map_ = map; - if (this.map_) { - this.map_.getOverlayContainer().appendChild(this.element_); - } -}; - - -/** - * @param {ol.Pixel} startPixel Start pixel. - * @param {ol.Pixel} endPixel End pixel. - */ -ol.render.Box.prototype.setPixels = function(startPixel, endPixel) { - this.startPixel_ = startPixel; - this.endPixel_ = endPixel; - this.createOrUpdateGeometry(); - this.render_(); -}; - - -/** - * Creates or updates the cached geometry. - */ -ol.render.Box.prototype.createOrUpdateGeometry = function() { - goog.asserts.assert(this.startPixel_, - 'this.startPixel_ must be truthy'); - goog.asserts.assert(this.endPixel_, - 'this.endPixel_ must be truthy'); - goog.asserts.assert(this.map_, 'this.map_ must be truthy'); - var startPixel = this.startPixel_; - var endPixel = this.endPixel_; - var pixels = [ - startPixel, - [startPixel[0], endPixel[1]], - endPixel, - [endPixel[0], startPixel[1]] - ]; - var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_); - // close the polygon - coordinates[4] = coordinates[0].slice(); - if (!this.geometry_) { - this.geometry_ = new ol.geom.Polygon([coordinates]); - } else { - this.geometry_.setCoordinates([coordinates]); - } -}; - - -/** - * @return {ol.geom.Polygon} Geometry. - */ -ol.render.Box.prototype.getGeometry = function() { - return this.geometry_; -}; - -// FIXME draw drag box -goog.provide('ol.DragBoxEvent'); -goog.provide('ol.interaction.DragBox'); - -goog.require('goog.events.Event'); -goog.require('ol'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.render.Box'); - - -/** - * @const - * @type {number} - */ -ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED = - ol.DRAG_BOX_HYSTERESIS_PIXELS * - ol.DRAG_BOX_HYSTERESIS_PIXELS; - - -/** - * @enum {string} - */ -ol.DragBoxEventType = { - /** - * Triggered upon drag box start. - * @event ol.DragBoxEvent#boxstart - * @api stable - */ - BOXSTART: 'boxstart', - /** - * Triggered upon drag box end. - * @event ol.DragBoxEvent#boxend - * @api stable - */ - BOXEND: 'boxend' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.interaction.DragBox} instances are instances of - * this type. - * - * @param {string} type The event type. - * @param {ol.Coordinate} coordinate The event coordinate. - * @extends {goog.events.Event} - * @constructor - * @implements {oli.DragBoxEvent} - */ -ol.DragBoxEvent = function(type, coordinate) { - goog.base(this, type); - - /** - * The coordinate of the drag event. - * @const - * @type {ol.Coordinate} - * @api stable - */ - this.coordinate = coordinate; - -}; -goog.inherits(ol.DragBoxEvent, goog.events.Event); - - - -/** - * @classdesc - * Allows the user to draw a vector box by clicking and dragging on the map, - * normally combined with an {@link ol.events.condition} that limits - * it to when the shift or other key is held down. This is used, for example, - * for zooming to a specific area of the map - * (see {@link ol.interaction.DragZoom} and - * {@link ol.interaction.DragRotateAndZoom}). - * - * This interaction is only supported for mouse devices. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @fires ol.DragBoxEvent - * @param {olx.interaction.DragBoxOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragBox = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.DragBox.handleDownEvent_, - handleDragEvent: ol.interaction.DragBox.handleDragEvent_, - handleUpEvent: ol.interaction.DragBox.handleUpEvent_ - }); - - var options = opt_options ? opt_options : {}; - - /** - * @type {ol.render.Box} - * @private - */ - this.box_ = new ol.render.Box(options.className || 'ol-dragbox'); - - /** - * @type {ol.Pixel} - * @private - */ - this.startPixel_ = null; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.always; - -}; -goog.inherits(ol.interaction.DragBox, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragBox} - * @private - */ -ol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return; - } - - this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel); -}; - - -/** - * Returns geometry of last drawn box. - * @return {ol.geom.Polygon} Geometry. - * @api stable - */ -ol.interaction.DragBox.prototype.getGeometry = function() { - return this.box_.getGeometry(); -}; - - -/** - * To be overriden by child classes. - * FIXME: use constructor option instead of relying on overridding. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @protected - */ -ol.interaction.DragBox.prototype.onBoxEnd = ol.nullFunction; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragBox} - * @private - */ -ol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return true; - } - - this.box_.setMap(null); - - var deltaX = mapBrowserEvent.pixel[0] - this.startPixel_[0]; - var deltaY = mapBrowserEvent.pixel[1] - this.startPixel_[1]; - - if (deltaX * deltaX + deltaY * deltaY >= - ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED) { - this.onBoxEnd(mapBrowserEvent); - this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXEND, - mapBrowserEvent.coordinate)); - } - return false; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragBox} - * @private - */ -ol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return false; - } - - var browserEvent = mapBrowserEvent.browserEvent; - if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) { - this.startPixel_ = mapBrowserEvent.pixel; - this.box_.setMap(mapBrowserEvent.map); - this.box_.setPixels(this.startPixel_, this.startPixel_); - this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXSTART, - mapBrowserEvent.coordinate)); - return true; - } else { - return false; - } -}; - -goog.provide('ol.interaction.DragZoom'); - -goog.require('goog.asserts'); -goog.require('ol.animation'); -goog.require('ol.easing'); -goog.require('ol.events.condition'); -goog.require('ol.extent'); -goog.require('ol.interaction.DragBox'); - - - -/** - * @classdesc - * Allows the user to zoom the map by clicking and dragging on the map, - * normally combined with an {@link ol.events.condition} that limits - * it to when a key, shift by default, is held down. - * - * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or - * your custom one configured with `className`. - * - * @constructor - * @extends {ol.interaction.DragBox} - * @param {olx.interaction.DragZoomOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragZoom = function(opt_options) { - var options = opt_options ? opt_options : {}; - - var condition = options.condition ? - options.condition : ol.events.condition.shiftKeyOnly; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 200; - - goog.base(this, { - condition: condition, - className: options.className || 'ol-dragzoom' - }); - -}; -goog.inherits(ol.interaction.DragZoom, ol.interaction.DragBox); - - -/** - * @inheritDoc - */ -ol.interaction.DragZoom.prototype.onBoxEnd = function() { - var map = this.getMap(); - - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - - var size = map.getSize(); - goog.asserts.assert(size !== undefined, 'size should be defined'); - - var extent = this.getGeometry().getExtent(); - - var resolution = view.constrainResolution( - view.getResolutionForExtent(extent, size)); - - var currentResolution = view.getResolution(); - goog.asserts.assert(currentResolution !== undefined, 'res should be defined'); - - var currentCenter = view.getCenter(); - goog.asserts.assert(currentCenter !== undefined, 'center should be defined'); - - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: this.duration_, - easing: ol.easing.easeOut - })); - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: this.duration_, - easing: ol.easing.easeOut - })); - - view.setCenter(ol.extent.getCenter(extent)); - view.setResolution(resolution); -}; - -goog.provide('ol.interaction.KeyboardPan'); - -goog.require('goog.asserts'); -goog.require('goog.events.KeyCodes'); -goog.require('goog.events.KeyHandler.EventType'); -goog.require('goog.functions'); -goog.require('ol'); -goog.require('ol.coordinate'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); - - - -/** - * @classdesc - * Allows the user to pan the map using keyboard arrows. - * Note that, although this interaction is by default included in maps, - * the keys can only be used when browser focus is on the element to which - * the keyboard events are attached. By default, this is the map div, - * though you can change this with the `keyboardEventTarget` in - * {@link ol.Map}. `document` never loses focus but, for any other element, - * focus will have to be on, and returned to, this element if the keys are to - * function. - * See also {@link ol.interaction.KeyboardZoom}. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.KeyboardPanOptions=} opt_options Options. - * @api stable - */ -ol.interaction.KeyboardPan = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.KeyboardPan.handleEvent - }); - - var options = opt_options || {}; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition !== undefined ? - options.condition : - goog.functions.and(ol.events.condition.noModifierKeys, - ol.events.condition.targetNotEditable); - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 100; - - /** - * @private - * @type {number} - */ - this.pixelDelta_ = options.pixelDelta !== undefined ? - options.pixelDelta : 128; - -}; -goog.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction); - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} if it was a - * `KeyEvent`, and decides the direction to pan to (if an arrow key was - * pressed). - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.KeyboardPan} - * @api - */ -ol.interaction.KeyboardPan.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) { - var keyEvent = /** @type {goog.events.KeyEvent} */ - (mapBrowserEvent.browserEvent); - var keyCode = keyEvent.keyCode; - if (this.condition_(mapBrowserEvent) && - (keyCode == goog.events.KeyCodes.DOWN || - keyCode == goog.events.KeyCodes.LEFT || - keyCode == goog.events.KeyCodes.RIGHT || - keyCode == goog.events.KeyCodes.UP)) { - var map = mapBrowserEvent.map; - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - var mapUnitsDelta = view.getResolution() * this.pixelDelta_; - var deltaX = 0, deltaY = 0; - if (keyCode == goog.events.KeyCodes.DOWN) { - deltaY = -mapUnitsDelta; - } else if (keyCode == goog.events.KeyCodes.LEFT) { - deltaX = -mapUnitsDelta; - } else if (keyCode == goog.events.KeyCodes.RIGHT) { - deltaX = mapUnitsDelta; - } else { - deltaY = mapUnitsDelta; - } - var delta = [deltaX, deltaY]; - ol.coordinate.rotate(delta, view.getRotation()); - ol.interaction.Interaction.pan(map, view, delta, this.duration_); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - } - return !stopEvent; -}; - -goog.provide('ol.interaction.KeyboardZoom'); - -goog.require('goog.asserts'); -goog.require('goog.events.KeyHandler.EventType'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); - - - -/** - * @classdesc - * Allows the user to zoom the map using keyboard + and -. - * Note that, although this interaction is by default included in maps, - * the keys can only be used when browser focus is on the element to which - * the keyboard events are attached. By default, this is the map div, - * though you can change this with the `keyboardEventTarget` in - * {@link ol.Map}. `document` never loses focus but, for any other element, - * focus will have to be on, and returned to, this element if the keys are to - * function. - * See also {@link ol.interaction.KeyboardPan}. - * - * @constructor - * @param {olx.interaction.KeyboardZoomOptions=} opt_options Options. - * @extends {ol.interaction.Interaction} - * @api stable - */ -ol.interaction.KeyboardZoom = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.KeyboardZoom.handleEvent - }); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? options.condition : - ol.events.condition.targetNotEditable; - - /** - * @private - * @type {number} - */ - this.delta_ = options.delta ? options.delta : 1; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 100; - -}; -goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction); - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} if it was a - * `KeyEvent`, and decides whether to zoom in or out (depending on whether the - * key pressed was '+' or '-'). - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.KeyboardZoom} - * @api - */ -ol.interaction.KeyboardZoom.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) { - var keyEvent = /** @type {goog.events.KeyEvent} */ - (mapBrowserEvent.browserEvent); - var charCode = keyEvent.charCode; - if (this.condition_(mapBrowserEvent) && - (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) { - var map = mapBrowserEvent.map; - var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_; - map.render(); - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - ol.interaction.Interaction.zoomByDelta( - map, view, delta, undefined, this.duration_); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - } - return !stopEvent; -}; - -goog.provide('ol.interaction.MouseWheelZoom'); - -goog.require('goog.asserts'); -goog.require('goog.events.MouseWheelEvent'); -goog.require('goog.events.MouseWheelHandler.EventType'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.math'); - - - -/** - * @classdesc - * Allows the user to zoom the map by scrolling the mouse wheel. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.MouseWheelZoomOptions=} opt_options Options. - * @api stable - */ -ol.interaction.MouseWheelZoom = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.MouseWheelZoom.handleEvent - }); - - var options = opt_options || {}; - - /** - * @private - * @type {number} - */ - this.delta_ = 0; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; - - /** - * @private - * @type {boolean} - */ - this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true; - - /** - * @private - * @type {?ol.Coordinate} - */ - this.lastAnchor_ = null; - - /** - * @private - * @type {number|undefined} - */ - this.startTime_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.timeoutId_ = undefined; - -}; -goog.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction); - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a - * mousewheel-event) and eventually zooms the map. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.MouseWheelZoom} - * @api - */ -ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - if (mapBrowserEvent.type == - goog.events.MouseWheelHandler.EventType.MOUSEWHEEL) { - var map = mapBrowserEvent.map; - var mouseWheelEvent = mapBrowserEvent.browserEvent; - goog.asserts.assertInstanceof(mouseWheelEvent, goog.events.MouseWheelEvent, - 'mouseWheelEvent should be of type MouseWheelEvent'); - - if (this.useAnchor_) { - this.lastAnchor_ = mapBrowserEvent.coordinate; - } - - this.delta_ += mouseWheelEvent.deltaY; - - if (this.startTime_ === undefined) { - this.startTime_ = Date.now(); - } - - var duration = ol.MOUSEWHEELZOOM_TIMEOUT_DURATION; - var timeLeft = Math.max(duration - (Date.now() - this.startTime_), 0); - - goog.global.clearTimeout(this.timeoutId_); - this.timeoutId_ = goog.global.setTimeout( - goog.bind(this.doZoom_, this, map), timeLeft); - - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - return !stopEvent; -}; - - -/** - * @private - * @param {ol.Map} map Map. - */ -ol.interaction.MouseWheelZoom.prototype.doZoom_ = function(map) { - var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA; - var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta); - - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - - map.render(); - ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_, - this.duration_); - - this.delta_ = 0; - this.lastAnchor_ = null; - this.startTime_ = undefined; - this.timeoutId_ = undefined; -}; - - -/** - * Enable or disable using the mouse's location as an anchor when zooming - * @param {boolean} useAnchor true to zoom to the mouse's location, false - * to zoom to the center of the map - * @api - */ -ol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) { - this.useAnchor_ = useAnchor; - if (!useAnchor) { - this.lastAnchor_ = null; - } -}; - -goog.provide('ol.interaction.PinchRotate'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.ViewHint'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); - - - -/** - * @classdesc - * Allows the user to rotate the map by twisting with two fingers - * on a touch screen. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.PinchRotateOptions=} opt_options Options. - * @api stable - */ -ol.interaction.PinchRotate = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_, - handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_, - handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_ - }); - - var options = opt_options || {}; - - /** - * @private - * @type {ol.Coordinate} - */ - this.anchor_ = null; - - /** - * @private - * @type {number|undefined} - */ - this.lastAngle_ = undefined; - - /** - * @private - * @type {boolean} - */ - this.rotating_ = false; - - /** - * @private - * @type {number} - */ - this.rotationDelta_ = 0.0; - - /** - * @private - * @type {number} - */ - this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; - -}; -goog.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.PinchRotate} - * @private - */ -ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) { - goog.asserts.assert(this.targetPointers.length >= 2, - 'length of this.targetPointers should be greater than or equal to 2'); - var rotationDelta = 0.0; - - var touch0 = this.targetPointers[0]; - var touch1 = this.targetPointers[1]; - - // angle between touches - var angle = Math.atan2( - touch1.clientY - touch0.clientY, - touch1.clientX - touch0.clientX); - - if (this.lastAngle_ !== undefined) { - var delta = angle - this.lastAngle_; - this.rotationDelta_ += delta; - if (!this.rotating_ && - Math.abs(this.rotationDelta_) > this.threshold_) { - this.rotating_ = true; - } - rotationDelta = delta; - } - this.lastAngle_ = angle; - - var map = mapBrowserEvent.map; - - // rotate anchor point. - // FIXME: should be the intersection point between the lines: - // touch0,touch1 and previousTouch0,previousTouch1 - var viewportPosition = goog.style.getClientPosition(map.getViewport()); - var centroid = - ol.interaction.Pointer.centroid(this.targetPointers); - centroid[0] -= viewportPosition.x; - centroid[1] -= viewportPosition.y; - this.anchor_ = map.getCoordinateFromPixel(centroid); - - // rotate - if (this.rotating_) { - var view = map.getView(); - var rotation = view.getRotation(); - map.render(); - ol.interaction.Interaction.rotateWithoutConstraints(map, view, - rotation + rotationDelta, this.anchor_); - } -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.PinchRotate} - * @private - */ -ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length < 2) { - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - if (this.rotating_) { - var rotation = view.getRotation(); - ol.interaction.Interaction.rotate( - map, view, rotation, this.anchor_, this.duration_); - } - return false; - } else { - return true; - } -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.PinchRotate} - * @private - */ -ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length >= 2) { - var map = mapBrowserEvent.map; - this.anchor_ = null; - this.lastAngle_ = undefined; - this.rotating_ = false; - this.rotationDelta_ = 0.0; - if (!this.handlingDownUpSequence) { - map.getView().setHint(ol.ViewHint.INTERACTING, 1); - } - map.render(); - return true; - } else { - return false; - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.PinchRotate.prototype.shouldStopEvent = goog.functions.FALSE; - -goog.provide('ol.interaction.PinchZoom'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.ViewHint'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); - - - -/** - * @classdesc - * Allows the user to zoom the map by pinching with two fingers - * on a touch screen. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.PinchZoomOptions=} opt_options Options. - * @api stable - */ -ol.interaction.PinchZoom = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_, - handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_, - handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_ - }); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {ol.Coordinate} - */ - this.anchor_ = null; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 400; - - /** - * @private - * @type {number|undefined} - */ - this.lastDistance_ = undefined; - - /** - * @private - * @type {number} - */ - this.lastScaleDelta_ = 1; - -}; -goog.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.PinchZoom} - * @private - */ -ol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) { - goog.asserts.assert(this.targetPointers.length >= 2, - 'length of this.targetPointers should be 2 or more'); - var scaleDelta = 1.0; - - var touch0 = this.targetPointers[0]; - var touch1 = this.targetPointers[1]; - var dx = touch0.clientX - touch1.clientX; - var dy = touch0.clientY - touch1.clientY; - - // distance between touches - var distance = Math.sqrt(dx * dx + dy * dy); - - if (this.lastDistance_ !== undefined) { - scaleDelta = this.lastDistance_ / distance; - } - this.lastDistance_ = distance; - if (scaleDelta != 1.0) { - this.lastScaleDelta_ = scaleDelta; - } - - var map = mapBrowserEvent.map; - var view = map.getView(); - var resolution = view.getResolution(); - - // scale anchor point. - var viewportPosition = goog.style.getClientPosition(map.getViewport()); - var centroid = - ol.interaction.Pointer.centroid(this.targetPointers); - centroid[0] -= viewportPosition.x; - centroid[1] -= viewportPosition.y; - this.anchor_ = map.getCoordinateFromPixel(centroid); - - // scale, bypass the resolution constraint - map.render(); - ol.interaction.Interaction.zoomWithoutConstraints( - map, view, resolution * scaleDelta, this.anchor_); - -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.PinchZoom} - * @private - */ -ol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length < 2) { - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - var resolution = view.getResolution(); - // Zoom to final resolution, with an animation, and provide a - // direction not to zoom out/in if user was pinching in/out. - // Direction is > 0 if pinching out, and < 0 if pinching in. - var direction = this.lastScaleDelta_ - 1; - ol.interaction.Interaction.zoom(map, view, resolution, - this.anchor_, this.duration_, direction); - return false; - } else { - return true; - } -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.PinchZoom} - * @private - */ -ol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length >= 2) { - var map = mapBrowserEvent.map; - this.anchor_ = null; - this.lastDistance_ = undefined; - this.lastScaleDelta_ = 1; - if (!this.handlingDownUpSequence) { - map.getView().setHint(ol.ViewHint.INTERACTING, 1); - } - map.render(); - return true; - } else { - return false; - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.PinchZoom.prototype.shouldStopEvent = goog.functions.FALSE; - -goog.provide('ol.interaction'); - -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.Kinetic'); -goog.require('ol.interaction.DoubleClickZoom'); -goog.require('ol.interaction.DragPan'); -goog.require('ol.interaction.DragRotate'); -goog.require('ol.interaction.DragZoom'); -goog.require('ol.interaction.KeyboardPan'); -goog.require('ol.interaction.KeyboardZoom'); -goog.require('ol.interaction.MouseWheelZoom'); -goog.require('ol.interaction.PinchRotate'); -goog.require('ol.interaction.PinchZoom'); - - -/** - * Set of interactions included in maps by default. Specific interactions can be - * excluded by setting the appropriate option to false in the constructor - * options, but the order of the interactions is fixed. If you want to specify - * a different order for interactions, you will need to create your own - * {@link ol.interaction.Interaction} instances and insert them into a - * {@link ol.Collection} in the order you want before creating your - * {@link ol.Map} instance. The default set of interactions, in sequence, is: - * * {@link ol.interaction.DragRotate} - * * {@link ol.interaction.DoubleClickZoom} - * * {@link ol.interaction.DragPan} - * * {@link ol.interaction.PinchRotate} - * * {@link ol.interaction.PinchZoom} - * * {@link ol.interaction.KeyboardPan} - * * {@link ol.interaction.KeyboardZoom} - * * {@link ol.interaction.MouseWheelZoom} - * * {@link ol.interaction.DragZoom} - * - * Note that DragZoom renders a box as a vector polygon, so this interaction - * should be excluded if you want a build with no vector support. - * - * @param {olx.interaction.DefaultsOptions=} opt_options Defaults options. - * @return {ol.Collection.<ol.interaction.Interaction>} A collection of - * interactions to be used with the ol.Map constructor's interactions option. - * @api stable - */ -ol.interaction.defaults = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var interactions = new ol.Collection(); - - var kinetic = new ol.Kinetic(-0.005, 0.05, 100); - - var altShiftDragRotate = options.altShiftDragRotate !== undefined ? - options.altShiftDragRotate : true; - if (altShiftDragRotate) { - interactions.push(new ol.interaction.DragRotate()); - } - - var doubleClickZoom = options.doubleClickZoom !== undefined ? - options.doubleClickZoom : true; - if (doubleClickZoom) { - interactions.push(new ol.interaction.DoubleClickZoom({ - delta: options.zoomDelta, - duration: options.zoomDuration - })); - } - - var dragPan = options.dragPan !== undefined ? options.dragPan : true; - if (dragPan) { - interactions.push(new ol.interaction.DragPan({ - kinetic: kinetic - })); - } - - var pinchRotate = options.pinchRotate !== undefined ? options.pinchRotate : - true; - if (pinchRotate) { - interactions.push(new ol.interaction.PinchRotate()); - } - - var pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true; - if (pinchZoom) { - interactions.push(new ol.interaction.PinchZoom({ - duration: options.zoomDuration - })); - } - - var keyboard = options.keyboard !== undefined ? options.keyboard : true; - if (keyboard) { - interactions.push(new ol.interaction.KeyboardPan()); - interactions.push(new ol.interaction.KeyboardZoom({ - delta: options.zoomDelta, - duration: options.zoomDuration - })); - } - - var mouseWheelZoom = options.mouseWheelZoom !== undefined ? - options.mouseWheelZoom : true; - if (mouseWheelZoom) { - interactions.push(new ol.interaction.MouseWheelZoom({ - duration: options.zoomDuration - })); - } - - var shiftDragZoom = options.shiftDragZoom !== undefined ? - options.shiftDragZoom : true; - if (shiftDragZoom) { - interactions.push(new ol.interaction.DragZoom({ - duration: options.zoomDuration - })); - } - - return interactions; - -}; - -goog.provide('ol.layer.Group'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEvent'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Object'); -goog.require('ol.ObjectEventType'); -goog.require('ol.extent'); -goog.require('ol.layer.Base'); -goog.require('ol.source.State'); - - -/** - * @enum {string} - */ -ol.layer.GroupProperty = { - LAYERS: 'layers' -}; - - - -/** - * @classdesc - * A {@link ol.Collection} of layers that are handled together. - * - * A generic `change` event is triggered when the group/Collection changes. - * - * @constructor - * @extends {ol.layer.Base} - * @param {olx.layer.GroupOptions=} opt_options Layer options. - * @api stable - */ -ol.layer.Group = function(opt_options) { - - var options = opt_options || {}; - var baseOptions = /** @type {olx.layer.GroupOptions} */ - (goog.object.clone(options)); - delete baseOptions.layers; - - var layers = options.layers; - - goog.base(this, baseOptions); - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.layersListenerKeys_ = []; - - /** - * @private - * @type {Object.<string, Array.<goog.events.Key>>} - */ - this.listenerKeys_ = {}; - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.layer.GroupProperty.LAYERS), - this.handleLayersChanged_, false, this); - - if (layers) { - if (goog.isArray(layers)) { - layers = new ol.Collection(layers.slice()); - } else { - goog.asserts.assertInstanceof(layers, ol.Collection, - 'layers should be an ol.Collection'); - layers = layers; - } - } else { - layers = new ol.Collection(); - } - - this.setLayers(layers); - -}; -goog.inherits(ol.layer.Group, ol.layer.Base); - - -/** - * @private - */ -ol.layer.Group.prototype.handleLayerChange_ = function() { - if (this.getVisible()) { - this.changed(); - } -}; - - -/** - * @param {goog.events.Event} event Event. - * @private - */ -ol.layer.Group.prototype.handleLayersChanged_ = function(event) { - this.layersListenerKeys_.forEach(goog.events.unlistenByKey); - this.layersListenerKeys_.length = 0; - - var layers = this.getLayers(); - this.layersListenerKeys_.push( - goog.events.listen(layers, ol.CollectionEventType.ADD, - this.handleLayersAdd_, false, this), - goog.events.listen(layers, ol.CollectionEventType.REMOVE, - this.handleLayersRemove_, false, this)); - - goog.object.forEach(this.listenerKeys_, function(keys) { - keys.forEach(goog.events.unlistenByKey); - }); - goog.object.clear(this.listenerKeys_); - - var layersArray = layers.getArray(); - var i, ii, layer; - for (i = 0, ii = layersArray.length; i < ii; i++) { - layer = layersArray[i]; - this.listenerKeys_[goog.getUid(layer).toString()] = [ - goog.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE, - this.handleLayerChange_, false, this), - goog.events.listen(layer, goog.events.EventType.CHANGE, - this.handleLayerChange_, false, this) - ]; - } - - this.changed(); -}; - - -/** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @private - */ -ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) { - var layer = /** @type {ol.layer.Base} */ (collectionEvent.element); - var key = goog.getUid(layer).toString(); - goog.asserts.assert(!(key in this.listenerKeys_), - 'listeners already registered'); - this.listenerKeys_[key] = [ - goog.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE, - this.handleLayerChange_, false, this), - goog.events.listen(layer, goog.events.EventType.CHANGE, - this.handleLayerChange_, false, this) - ]; - this.changed(); -}; - - -/** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @private - */ -ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) { - var layer = /** @type {ol.layer.Base} */ (collectionEvent.element); - var key = goog.getUid(layer).toString(); - goog.asserts.assert(key in this.listenerKeys_, 'no listeners to unregister'); - this.listenerKeys_[key].forEach(goog.events.unlistenByKey); - delete this.listenerKeys_[key]; - this.changed(); -}; - - -/** - * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers} - * in this group. - * @return {!ol.Collection.<ol.layer.Base>} Collection of - * {@link ol.layer.Base layers} that are part of this group. - * @observable - * @api stable - */ -ol.layer.Group.prototype.getLayers = function() { - return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get( - ol.layer.GroupProperty.LAYERS)); -}; - - -/** - * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers} - * in this group. - * @param {!ol.Collection.<ol.layer.Base>} layers Collection of - * {@link ol.layer.Base layers} that are part of this group. - * @observable - * @api stable - */ -ol.layer.Group.prototype.setLayers = function(layers) { - this.set(ol.layer.GroupProperty.LAYERS, layers); -}; - - -/** - * @inheritDoc - */ -ol.layer.Group.prototype.getLayersArray = function(opt_array) { - var array = opt_array !== undefined ? opt_array : []; - this.getLayers().forEach(function(layer) { - layer.getLayersArray(array); - }); - return array; -}; - - -/** - * @inheritDoc - */ -ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) { - var states = opt_states !== undefined ? opt_states : []; - - var pos = states.length; - - this.getLayers().forEach(function(layer) { - layer.getLayerStatesArray(states); - }); - - var ownLayerState = this.getLayerState(); - var i, ii, layerState; - for (i = pos, ii = states.length; i < ii; i++) { - layerState = states[i]; - layerState.opacity *= ownLayerState.opacity; - layerState.visible = layerState.visible && ownLayerState.visible; - layerState.maxResolution = Math.min( - layerState.maxResolution, ownLayerState.maxResolution); - layerState.minResolution = Math.max( - layerState.minResolution, ownLayerState.minResolution); - if (ownLayerState.extent !== undefined) { - if (layerState.extent !== undefined) { - layerState.extent = ol.extent.getIntersection( - layerState.extent, ownLayerState.extent); - } else { - layerState.extent = ownLayerState.extent; - } - } - } - - return states; -}; - - -/** - * @inheritDoc - */ -ol.layer.Group.prototype.getSourceState = function() { - return ol.source.State.READY; -}; - -goog.provide('ol.proj.EPSG3857'); - -goog.require('goog.asserts'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); - - - -/** - * @classdesc - * Projection object for web/spherical Mercator (EPSG:3857). - * - * @constructor - * @extends {ol.proj.Projection} - * @param {string} code Code. - * @private - */ -ol.proj.EPSG3857_ = function(code) { - goog.base(this, { - code: code, - units: ol.proj.Units.METERS, - extent: ol.proj.EPSG3857.EXTENT, - global: true, - worldExtent: ol.proj.EPSG3857.WORLD_EXTENT - }); -}; -goog.inherits(ol.proj.EPSG3857_, ol.proj.Projection); - - -/** - * @inheritDoc - */ -ol.proj.EPSG3857_.prototype.getPointResolution = function(resolution, point) { - return resolution / ol.math.cosh(point[1] / ol.proj.EPSG3857.RADIUS); -}; - - -/** - * @const - * @type {number} - */ -ol.proj.EPSG3857.RADIUS = 6378137; - - -/** - * @const - * @type {number} - */ -ol.proj.EPSG3857.HALF_SIZE = Math.PI * ol.proj.EPSG3857.RADIUS; - - -/** - * @const - * @type {ol.Extent} - */ -ol.proj.EPSG3857.EXTENT = [ - -ol.proj.EPSG3857.HALF_SIZE, -ol.proj.EPSG3857.HALF_SIZE, - ol.proj.EPSG3857.HALF_SIZE, ol.proj.EPSG3857.HALF_SIZE -]; - - -/** - * @const - * @type {ol.Extent} - */ -ol.proj.EPSG3857.WORLD_EXTENT = [-180, -85, 180, 85]; - - -/** - * Lists several projection codes with the same meaning as EPSG:3857. - * - * @type {Array.<string>} - */ -ol.proj.EPSG3857.CODES = [ - 'EPSG:3857', - 'EPSG:102100', - 'EPSG:102113', - 'EPSG:900913', - 'urn:ogc:def:crs:EPSG:6.18:3:3857', - 'urn:ogc:def:crs:EPSG::3857', - 'http://www.opengis.net/gml/srs/epsg.xml#3857' -]; - - -/** - * Projections equal to EPSG:3857. - * - * @const - * @type {Array.<ol.proj.Projection>} - */ -ol.proj.EPSG3857.PROJECTIONS = ol.proj.EPSG3857.CODES.map(function(code) { - return new ol.proj.EPSG3857_(code); -}); - - -/** - * Transformation from EPSG:4326 to EPSG:3857. - * - * @param {Array.<number>} input Input array of coordinate values. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension (default is `2`). - * @return {Array.<number>} Output array of coordinate values. - */ -ol.proj.EPSG3857.fromEPSG4326 = function(input, opt_output, opt_dimension) { - var length = input.length, - dimension = opt_dimension > 1 ? opt_dimension : 2, - output = opt_output; - if (output === undefined) { - if (dimension > 2) { - // preserve values beyond second dimension - output = input.slice(); - } else { - output = new Array(length); - } - } - goog.asserts.assert(output.length % dimension === 0, - 'modulus of output.length with dimension should be 0'); - for (var i = 0; i < length; i += dimension) { - output[i] = ol.proj.EPSG3857.RADIUS * Math.PI * input[i] / 180; - output[i + 1] = ol.proj.EPSG3857.RADIUS * - Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360)); - } - return output; -}; - - -/** - * Transformation from EPSG:3857 to EPSG:4326. - * - * @param {Array.<number>} input Input array of coordinate values. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension (default is `2`). - * @return {Array.<number>} Output array of coordinate values. - */ -ol.proj.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) { - var length = input.length, - dimension = opt_dimension > 1 ? opt_dimension : 2, - output = opt_output; - if (output === undefined) { - if (dimension > 2) { - // preserve values beyond second dimension - output = input.slice(); - } else { - output = new Array(length); - } - } - goog.asserts.assert(output.length % dimension === 0, - 'modulus of output.length with dimension should be 0'); - for (var i = 0; i < length; i += dimension) { - output[i] = 180 * input[i] / (ol.proj.EPSG3857.RADIUS * Math.PI); - output[i + 1] = 360 * Math.atan( - Math.exp(input[i + 1] / ol.proj.EPSG3857.RADIUS)) / Math.PI - 90; - } - return output; -}; - -goog.provide('ol.proj.EPSG4326'); - -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); - - - -/** - * @classdesc - * Projection object for WGS84 geographic coordinates (EPSG:4326). - * - * Note that OpenLayers does not strictly comply with the EPSG definition. - * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x). - * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates. - * - * @constructor - * @extends {ol.proj.Projection} - * @param {string} code Code. - * @param {string=} opt_axisOrientation Axis orientation. - * @private - */ -ol.proj.EPSG4326_ = function(code, opt_axisOrientation) { - goog.base(this, { - code: code, - units: ol.proj.Units.DEGREES, - extent: ol.proj.EPSG4326.EXTENT, - axisOrientation: opt_axisOrientation, - global: true, - worldExtent: ol.proj.EPSG4326.EXTENT - }); -}; -goog.inherits(ol.proj.EPSG4326_, ol.proj.Projection); - - -/** - * @inheritDoc - */ -ol.proj.EPSG4326_.prototype.getPointResolution = function(resolution, point) { - return resolution; -}; - - -/** - * Extent of the EPSG:4326 projection which is the whole world. - * - * @const - * @type {ol.Extent} - */ -ol.proj.EPSG4326.EXTENT = [-180, -90, 180, 90]; - - -/** - * Projections equal to EPSG:4326. - * - * @const - * @type {Array.<ol.proj.Projection>} - */ -ol.proj.EPSG4326.PROJECTIONS = [ - new ol.proj.EPSG4326_('CRS:84'), - new ol.proj.EPSG4326_('EPSG:4326', 'neu'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG::4326', 'neu'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:1.3:CRS84'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:2:84'), - new ol.proj.EPSG4326_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'), - new ol.proj.EPSG4326_('urn:x-ogc:def:crs:EPSG:4326', 'neu') -]; - -goog.provide('ol.proj.common'); - -goog.require('ol.proj'); -goog.require('ol.proj.EPSG3857'); -goog.require('ol.proj.EPSG4326'); - - -/** - * FIXME empty description for jsdoc - * @api - */ -ol.proj.common.add = function() { - // Add transformations that don't alter coordinates to convert within set of - // projections with equal meaning. - ol.proj.addEquivalentProjections(ol.proj.EPSG3857.PROJECTIONS); - ol.proj.addEquivalentProjections(ol.proj.EPSG4326.PROJECTIONS); - // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like - // coordinates and back. - ol.proj.addEquivalentTransforms( - ol.proj.EPSG4326.PROJECTIONS, - ol.proj.EPSG3857.PROJECTIONS, - ol.proj.EPSG3857.fromEPSG4326, - ol.proj.EPSG3857.toEPSG4326); -}; - -goog.provide('ol.layer.Image'); - -goog.require('ol.layer.Layer'); - - - -/** - * @classdesc - * Server-rendered images that are available for arbitrary extents and - * resolutions. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Layer} - * @fires ol.render.Event - * @param {olx.layer.ImageOptions=} opt_options Layer options. - * @api stable - */ -ol.layer.Image = function(opt_options) { - var options = opt_options ? opt_options : {}; - goog.base(this, /** @type {olx.layer.LayerOptions} */ (options)); -}; -goog.inherits(ol.layer.Image, ol.layer.Layer); - - -/** - * Return the associated {@link ol.source.Image source} of the image layer. - * @function - * @return {ol.source.Image} Source. - * @api stable - */ -ol.layer.Image.prototype.getSource; - -goog.provide('ol.layer.Tile'); - -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.layer.Layer'); - - -/** - * @enum {string} - */ -ol.layer.TileProperty = { - PRELOAD: 'preload', - USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError' -}; - - - -/** - * @classdesc - * For layer sources that provide pre-rendered, tiled images in grids that are - * organized by zoom levels for specific resolutions. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Layer} - * @fires ol.render.Event - * @param {olx.layer.TileOptions=} opt_options Tile layer options. - * @api stable - */ -ol.layer.Tile = function(opt_options) { - var options = opt_options ? opt_options : {}; - - var baseOptions = goog.object.clone(options); - - delete baseOptions.preload; - delete baseOptions.useInterimTilesOnError; - goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); - - this.setPreload(options.preload !== undefined ? options.preload : 0); - this.setUseInterimTilesOnError(options.useInterimTilesOnError !== undefined ? - options.useInterimTilesOnError : true); -}; -goog.inherits(ol.layer.Tile, ol.layer.Layer); - - -/** - * Return the level as number to which we will preload tiles up to. - * @return {number} The level to preload tiles up to. - * @observable - * @api - */ -ol.layer.Tile.prototype.getPreload = function() { - return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD)); -}; - - -/** - * Return the associated {@link ol.source.Tile tilesource} of the layer. - * @function - * @return {ol.source.Tile} Source. - * @api stable - */ -ol.layer.Tile.prototype.getSource; - - -/** - * Set the level as number to which we will preload tiles up to. - * @param {number} preload The level to preload tiles up to. - * @observable - * @api - */ -ol.layer.Tile.prototype.setPreload = function(preload) { - this.set(ol.layer.TileProperty.PRELOAD, preload); -}; - - -/** - * Whether we use interim tiles on error. - * @return {boolean} Use interim tiles on error. - * @observable - * @api - */ -ol.layer.Tile.prototype.getUseInterimTilesOnError = function() { - return /** @type {boolean} */ ( - this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR)); -}; - - -/** - * Set whether we use interim tiles on error. - * @param {boolean} useInterimTilesOnError Use interim tiles on error. - * @observable - * @api - */ -ol.layer.Tile.prototype.setUseInterimTilesOnError = - function(useInterimTilesOnError) { - this.set( - ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); -}; - -goog.provide('ol.render.canvas'); - - -/** - * @typedef {{fillStyle: string}} - */ -ol.render.canvas.FillState; - - -/** - * @typedef {{lineCap: string, - * lineDash: Array.<number>, - * lineJoin: string, - * lineWidth: number, - * miterLimit: number, - * strokeStyle: string}} - */ -ol.render.canvas.StrokeState; - - -/** - * @typedef {{font: string, - * textAlign: string, - * textBaseline: string}} - */ -ol.render.canvas.TextState; - - -/** - * @const - * @type {string} - */ -ol.render.canvas.defaultFont = '10px sans-serif'; - - -/** - * @const - * @type {ol.Color} - */ -ol.render.canvas.defaultFillStyle = [0, 0, 0, 1]; - - -/** - * @const - * @type {string} - */ -ol.render.canvas.defaultLineCap = 'round'; - - -/** - * @const - * @type {Array.<number>} - */ -ol.render.canvas.defaultLineDash = []; - - -/** - * @const - * @type {string} - */ -ol.render.canvas.defaultLineJoin = 'round'; - - -/** - * @const - * @type {number} - */ -ol.render.canvas.defaultMiterLimit = 10; - - -/** - * @const - * @type {ol.Color} - */ -ol.render.canvas.defaultStrokeStyle = [0, 0, 0, 1]; - - -/** - * @const - * @type {string} - */ -ol.render.canvas.defaultTextAlign = 'center'; - - -/** - * @const - * @type {string} - */ -ol.render.canvas.defaultTextBaseline = 'middle'; - - -/** - * @const - * @type {number} - */ -ol.render.canvas.defaultLineWidth = 1; - -goog.provide('ol.structs.IHasChecksum'); - - - -/** - * @interface - */ -ol.structs.IHasChecksum = function() { -}; - - -/** - * @return {string} The checksum. - */ -ol.structs.IHasChecksum.prototype.getChecksum = function() { -}; - -goog.provide('ol.style.Fill'); - -goog.require('ol.color'); -goog.require('ol.structs.IHasChecksum'); - - - -/** - * @classdesc - * Set fill style for vector features. - * - * @constructor - * @param {olx.style.FillOptions=} opt_options Options. - * @implements {ol.structs.IHasChecksum} - * @api - */ -ol.style.Fill = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {ol.Color|string} - */ - this.color_ = options.color !== undefined ? options.color : null; - - /** - * @private - * @type {string|undefined} - */ - this.checksum_ = undefined; -}; - - -/** - * Get the fill color. - * @return {ol.Color|string} Color. - * @api - */ -ol.style.Fill.prototype.getColor = function() { - return this.color_; -}; - - -/** - * Set the color. - * - * @param {ol.Color|string} color Color. - * @api - */ -ol.style.Fill.prototype.setColor = function(color) { - this.color_ = color; - this.checksum_ = undefined; -}; - - -/** - * @inheritDoc - */ -ol.style.Fill.prototype.getChecksum = function() { - if (this.checksum_ === undefined) { - this.checksum_ = 'f' + (this.color_ ? - ol.color.asString(this.color_) : '-'); - } - - return this.checksum_; -}; - -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Namespace with crypto related helper functions. - */ - -goog.provide('goog.crypt'); - -goog.require('goog.array'); -goog.require('goog.asserts'); - - -/** - * Turns a string into an array of bytes; a "byte" being a JS number in the - * range 0-255. - * @param {string} str String value to arrify. - * @return {!Array<number>} Array of numbers corresponding to the - * UCS character codes of each character in str. - */ -goog.crypt.stringToByteArray = function(str) { - var output = [], p = 0; - for (var i = 0; i < str.length; i++) { - var c = str.charCodeAt(i); - while (c > 0xff) { - output[p++] = c & 0xff; - c >>= 8; - } - output[p++] = c; - } - return output; -}; - - -/** - * Turns an array of numbers into the string given by the concatenation of the - * characters to which the numbers correspond. - * @param {Array<number>} bytes Array of numbers representing characters. - * @return {string} Stringification of the array. - */ -goog.crypt.byteArrayToString = function(bytes) { - var CHUNK_SIZE = 8192; - - // Special-case the simple case for speed's sake. - if (bytes.length <= CHUNK_SIZE) { - return String.fromCharCode.apply(null, bytes); - } - - // The remaining logic splits conversion by chunks since - // Function#apply() has a maximum parameter count. - // See discussion: http://goo.gl/LrWmZ9 - - var str = ''; - for (var i = 0; i < bytes.length; i += CHUNK_SIZE) { - var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE); - str += String.fromCharCode.apply(null, chunk); - } - return str; -}; - - -/** - * Turns an array of numbers into the hex string given by the concatenation of - * the hex values to which the numbers correspond. - * @param {Uint8Array|Array<number>} array Array of numbers representing - * characters. - * @return {string} Hex string. - */ -goog.crypt.byteArrayToHex = function(array) { - return goog.array.map(array, function(numByte) { - var hexByte = numByte.toString(16); - return hexByte.length > 1 ? hexByte : '0' + hexByte; - }).join(''); -}; - - -/** - * Converts a hex string into an integer array. - * @param {string} hexString Hex string of 16-bit integers (two characters - * per integer). - * @return {!Array<number>} Array of {0,255} integers for the given string. - */ -goog.crypt.hexToByteArray = function(hexString) { - goog.asserts.assert(hexString.length % 2 == 0, - 'Key string length must be multiple of 2'); - var arr = []; - for (var i = 0; i < hexString.length; i += 2) { - arr.push(parseInt(hexString.substring(i, i + 2), 16)); - } - return arr; -}; - - -/** - * Converts a JS string to a UTF-8 "byte" array. - * @param {string} str 16-bit unicode string. - * @return {!Array<number>} UTF-8 byte array. - */ -goog.crypt.stringToUtf8ByteArray = function(str) { - // TODO(user): Use native implementations if/when available - var out = [], p = 0; - for (var i = 0; i < str.length; i++) { - var c = str.charCodeAt(i); - if (c < 128) { - out[p++] = c; - } else if (c < 2048) { - out[p++] = (c >> 6) | 192; - out[p++] = (c & 63) | 128; - } else { - out[p++] = (c >> 12) | 224; - out[p++] = ((c >> 6) & 63) | 128; - out[p++] = (c & 63) | 128; - } - } - return out; -}; - - -/** - * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode. - * @param {Uint8Array|Array<number>} bytes UTF-8 byte array. - * @return {string} 16-bit Unicode string. - */ -goog.crypt.utf8ByteArrayToString = function(bytes) { - // TODO(user): Use native implementations if/when available - var out = [], pos = 0, c = 0; - while (pos < bytes.length) { - var c1 = bytes[pos++]; - if (c1 < 128) { - out[c++] = String.fromCharCode(c1); - } else if (c1 > 191 && c1 < 224) { - var c2 = bytes[pos++]; - out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63); - } else { - var c2 = bytes[pos++]; - var c3 = bytes[pos++]; - out[c++] = String.fromCharCode( - (c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63); - } - } - return out.join(''); -}; - - -/** - * XOR two byte arrays. - * @param {!ArrayBufferView|!Array<number>} bytes1 Byte array 1. - * @param {!ArrayBufferView|!Array<number>} bytes2 Byte array 2. - * @return {!Array<number>} Resulting XOR of the two byte arrays. - */ -goog.crypt.xorByteArray = function(bytes1, bytes2) { - goog.asserts.assert( - bytes1.length == bytes2.length, - 'XOR array lengths must match'); - - var result = []; - for (var i = 0; i < bytes1.length; i++) { - result.push(bytes1[i] ^ bytes2[i]); - } - return result; -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Abstract cryptographic hash interface. - * - * See goog.crypt.Sha1 and goog.crypt.Md5 for sample implementations. - * - */ - -goog.provide('goog.crypt.Hash'); - - - -/** - * Create a cryptographic hash instance. - * - * @constructor - * @struct - */ -goog.crypt.Hash = function() { - /** - * The block size for the hasher. - * @type {number} - */ - this.blockSize = -1; -}; - - -/** - * Resets the internal accumulator. - */ -goog.crypt.Hash.prototype.reset = goog.abstractMethod; - - -/** - * Adds a byte array (array with values in [0-255] range) or a string (might - * only contain 8-bit, i.e., Latin1 characters) to the internal accumulator. - * - * Many hash functions operate on blocks of data and implement optimizations - * when a full chunk of data is readily available. Hence it is often preferable - * to provide large chunks of data (a kilobyte or more) than to repeatedly - * call the update method with few tens of bytes. If this is not possible, or - * not feasible, it might be good to provide data in multiplies of hash block - * size (often 64 bytes). Please see the implementation and performance tests - * of your favourite hash. - * - * @param {Array<number>|Uint8Array|string} bytes Data used for the update. - * @param {number=} opt_length Number of bytes to use. - */ -goog.crypt.Hash.prototype.update = goog.abstractMethod; - - -/** - * @return {!Array<number>} The finalized hash computed - * from the internal accumulator. - */ -goog.crypt.Hash.prototype.digest = goog.abstractMethod; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview MD5 cryptographic hash. - * Implementation of http://tools.ietf.org/html/rfc1321 with common - * optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5). - * - * Usage: - * var md5 = new goog.crypt.Md5(); - * md5.update(bytes); - * var hash = md5.digest(); - * - * Performance: - * Chrome 23 ~680 Mbit/s - * Chrome 13 (in a VM) ~250 Mbit/s - * Firefox 6.0 (in a VM) ~100 Mbit/s - * IE9 (in a VM) ~27 Mbit/s - * Firefox 3.6 ~15 Mbit/s - * IE8 (in a VM) ~13 Mbit/s - * - */ - -goog.provide('goog.crypt.Md5'); - -goog.require('goog.crypt.Hash'); - - - -/** - * MD5 cryptographic hash constructor. - * @constructor - * @extends {goog.crypt.Hash} - * @final - * @struct - */ -goog.crypt.Md5 = function() { - goog.crypt.Md5.base(this, 'constructor'); - - this.blockSize = 512 / 8; - - /** - * Holds the current values of accumulated A-D variables (MD buffer). - * @type {!Array<number>} - * @private - */ - this.chain_ = new Array(4); - - /** - * A buffer holding the data until the whole block can be processed. - * @type {!Array<number>} - * @private - */ - this.block_ = new Array(this.blockSize); - - /** - * The length of yet-unprocessed data as collected in the block. - * @type {number} - * @private - */ - this.blockLength_ = 0; - - /** - * The total length of the message so far. - * @type {number} - * @private - */ - this.totalLength_ = 0; - - this.reset(); -}; -goog.inherits(goog.crypt.Md5, goog.crypt.Hash); - - -/** - * Integer rotation constants used by the abbreviated implementation. - * They are hardcoded in the unrolled implementation, so it is left - * here commented out. - * @type {Array<number>} - * @private - * -goog.crypt.Md5.S_ = [ - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 -]; - */ - -/** - * Sine function constants used by the abbreviated implementation. - * They are hardcoded in the unrolled implementation, so it is left - * here commented out. - * @type {Array<number>} - * @private - * -goog.crypt.Md5.T_ = [ - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 -]; - */ - - -/** @override */ -goog.crypt.Md5.prototype.reset = function() { - this.chain_[0] = 0x67452301; - this.chain_[1] = 0xefcdab89; - this.chain_[2] = 0x98badcfe; - this.chain_[3] = 0x10325476; - - this.blockLength_ = 0; - this.totalLength_ = 0; -}; - - -/** - * Internal compress helper function. It takes a block of data (64 bytes) - * and updates the accumulator. - * @param {Array<number>|Uint8Array|string} buf The block to compress. - * @param {number=} opt_offset Offset of the block in the buffer. - * @private - */ -goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) { - if (!opt_offset) { - opt_offset = 0; - } - - // We allocate the array every time, but it's cheap in practice. - var X = new Array(16); - - // Get 16 little endian words. It is not worth unrolling this for Chrome 11. - if (goog.isString(buf)) { - for (var i = 0; i < 16; ++i) { - X[i] = (buf.charCodeAt(opt_offset++)) | - (buf.charCodeAt(opt_offset++) << 8) | - (buf.charCodeAt(opt_offset++) << 16) | - (buf.charCodeAt(opt_offset++) << 24); - } - } else { - for (var i = 0; i < 16; ++i) { - X[i] = (buf[opt_offset++]) | - (buf[opt_offset++] << 8) | - (buf[opt_offset++] << 16) | - (buf[opt_offset++] << 24); - } - } - - var A = this.chain_[0]; - var B = this.chain_[1]; - var C = this.chain_[2]; - var D = this.chain_[3]; - var sum = 0; - - /* - * This is an abbreviated implementation, it is left here commented out for - * reference purposes. See below for an unrolled version in use. - * - var f, n, tmp; - for (var i = 0; i < 64; ++i) { - - if (i < 16) { - f = (D ^ (B & (C ^ D))); - n = i; - } else if (i < 32) { - f = (C ^ (D & (B ^ C))); - n = (5 * i + 1) % 16; - } else if (i < 48) { - f = (B ^ C ^ D); - n = (3 * i + 5) % 16; - } else { - f = (C ^ (B | (~D))); - n = (7 * i) % 16; - } - - tmp = D; - D = C; - C = B; - sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff; - B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) | - (sum >>> (32 - goog.crypt.Md5.S_[i])); - A = tmp; - } - */ - - /* - * This is an unrolled MD5 implementation, which gives ~30% speedup compared - * to the abbreviated implementation above, as measured on Chrome 11. It is - * important to keep 32-bit croppings to minimum and inline the integer - * rotation. - */ - sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - - this.chain_[0] = (this.chain_[0] + A) & 0xffffffff; - this.chain_[1] = (this.chain_[1] + B) & 0xffffffff; - this.chain_[2] = (this.chain_[2] + C) & 0xffffffff; - this.chain_[3] = (this.chain_[3] + D) & 0xffffffff; -}; - - -/** @override */ -goog.crypt.Md5.prototype.update = function(bytes, opt_length) { - if (!goog.isDef(opt_length)) { - opt_length = bytes.length; - } - var lengthMinusBlock = opt_length - this.blockSize; - - // Copy some object properties to local variables in order to save on access - // time from inside the loop (~10% speedup was observed on Chrome 11). - var block = this.block_; - var blockLength = this.blockLength_; - var i = 0; - - // The outer while loop should execute at most twice. - while (i < opt_length) { - // When we have no data in the block to top up, we can directly process the - // input buffer (assuming it contains sufficient data). This gives ~30% - // speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that - // the data is provided in large chunks (or in multiples of 64 bytes). - if (blockLength == 0) { - while (i <= lengthMinusBlock) { - this.compress_(bytes, i); - i += this.blockSize; - } - } - - if (goog.isString(bytes)) { - while (i < opt_length) { - block[blockLength++] = bytes.charCodeAt(i++); - if (blockLength == this.blockSize) { - this.compress_(block); - blockLength = 0; - // Jump to the outer loop so we use the full-block optimization. - break; - } - } - } else { - while (i < opt_length) { - block[blockLength++] = bytes[i++]; - if (blockLength == this.blockSize) { - this.compress_(block); - blockLength = 0; - // Jump to the outer loop so we use the full-block optimization. - break; - } - } - } - } - - this.blockLength_ = blockLength; - this.totalLength_ += opt_length; -}; - - -/** @override */ -goog.crypt.Md5.prototype.digest = function() { - // This must accommodate at least 1 padding byte (0x80), 8 bytes of - // total bitlength, and must end at a 64-byte boundary. - var pad = new Array((this.blockLength_ < 56 ? - this.blockSize : - this.blockSize * 2) - this.blockLength_); - - // Add padding: 0x80 0x00* - pad[0] = 0x80; - for (var i = 1; i < pad.length - 8; ++i) { - pad[i] = 0; - } - // Add the total number of bits, little endian 64-bit integer. - var totalBits = this.totalLength_ * 8; - for (var i = pad.length - 8; i < pad.length; ++i) { - pad[i] = totalBits & 0xff; - totalBits /= 0x100; // Don't use bit-shifting here! - } - this.update(pad); - - var digest = new Array(16); - var n = 0; - for (var i = 0; i < 4; ++i) { - for (var j = 0; j < 32; j += 8) { - digest[n++] = (this.chain_[i] >>> j) & 0xff; - } - } - return digest; -}; - -goog.provide('ol.style.Stroke'); - -goog.require('goog.crypt'); -goog.require('goog.crypt.Md5'); -goog.require('ol.color'); -goog.require('ol.structs.IHasChecksum'); - - - -/** - * @classdesc - * Set stroke style for vector features. - * Note that the defaults given are the Canvas defaults, which will be used if - * option is not defined. The `get` functions return whatever was entered in - * the options; they will not return the default. - * - * @constructor - * @param {olx.style.StrokeOptions=} opt_options Options. - * @implements {ol.structs.IHasChecksum} - * @api - */ -ol.style.Stroke = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {ol.Color|string} - */ - this.color_ = options.color !== undefined ? options.color : null; - - /** - * @private - * @type {string|undefined} - */ - this.lineCap_ = options.lineCap; - - /** - * @private - * @type {Array.<number>} - */ - this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null; - - /** - * @private - * @type {string|undefined} - */ - this.lineJoin_ = options.lineJoin; - - /** - * @private - * @type {number|undefined} - */ - this.miterLimit_ = options.miterLimit; - - /** - * @private - * @type {number|undefined} - */ - this.width_ = options.width; - - /** - * @private - * @type {string|undefined} - */ - this.checksum_ = undefined; -}; - - -/** - * Get the stroke color. - * @return {ol.Color|string} Color. - * @api - */ -ol.style.Stroke.prototype.getColor = function() { - return this.color_; -}; - - -/** - * Get the line cap type for the stroke. - * @return {string|undefined} Line cap. - * @api - */ -ol.style.Stroke.prototype.getLineCap = function() { - return this.lineCap_; -}; - - -/** - * Get the line dash style for the stroke. - * @return {Array.<number>} Line dash. - * @api - */ -ol.style.Stroke.prototype.getLineDash = function() { - return this.lineDash_; -}; - - -/** - * Get the line join type for the stroke. - * @return {string|undefined} Line join. - * @api - */ -ol.style.Stroke.prototype.getLineJoin = function() { - return this.lineJoin_; -}; - - -/** - * Get the miter limit for the stroke. - * @return {number|undefined} Miter limit. - * @api - */ -ol.style.Stroke.prototype.getMiterLimit = function() { - return this.miterLimit_; -}; - - -/** - * Get the stroke width. - * @return {number|undefined} Width. - * @api - */ -ol.style.Stroke.prototype.getWidth = function() { - return this.width_; -}; - - -/** - * Set the color. - * - * @param {ol.Color|string} color Color. - * @api - */ -ol.style.Stroke.prototype.setColor = function(color) { - this.color_ = color; - this.checksum_ = undefined; -}; - - -/** - * Set the line cap. - * - * @param {string|undefined} lineCap Line cap. - * @api - */ -ol.style.Stroke.prototype.setLineCap = function(lineCap) { - this.lineCap_ = lineCap; - this.checksum_ = undefined; -}; - - -/** - * Set the line dash. - * - * @param {Array.<number>} lineDash Line dash. - * @api - */ -ol.style.Stroke.prototype.setLineDash = function(lineDash) { - this.lineDash_ = lineDash; - this.checksum_ = undefined; -}; - - -/** - * Set the line join. - * - * @param {string|undefined} lineJoin Line join. - * @api - */ -ol.style.Stroke.prototype.setLineJoin = function(lineJoin) { - this.lineJoin_ = lineJoin; - this.checksum_ = undefined; -}; - - -/** - * Set the miter limit. - * - * @param {number|undefined} miterLimit Miter limit. - * @api - */ -ol.style.Stroke.prototype.setMiterLimit = function(miterLimit) { - this.miterLimit_ = miterLimit; - this.checksum_ = undefined; -}; - - -/** - * Set the width. - * - * @param {number|undefined} width Width. - * @api - */ -ol.style.Stroke.prototype.setWidth = function(width) { - this.width_ = width; - this.checksum_ = undefined; -}; - - -/** - * @inheritDoc - */ -ol.style.Stroke.prototype.getChecksum = function() { - if (this.checksum_ === undefined) { - var raw = 's' + - (this.color_ ? - ol.color.asString(this.color_) : '-') + ',' + - (this.lineCap_ !== undefined ? - this.lineCap_.toString() : '-') + ',' + - (this.lineDash_ ? - this.lineDash_.toString() : '-') + ',' + - (this.lineJoin_ !== undefined ? - this.lineJoin_ : '-') + ',' + - (this.miterLimit_ !== undefined ? - this.miterLimit_.toString() : '-') + ',' + - (this.width_ !== undefined ? - this.width_.toString() : '-'); - - var md5 = new goog.crypt.Md5(); - md5.update(raw); - this.checksum_ = goog.crypt.byteArrayToString(md5.digest()); - } - - return this.checksum_; -}; - -goog.provide('ol.style.Circle'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('ol'); -goog.require('ol.color'); -goog.require('ol.has'); -goog.require('ol.render.canvas'); -goog.require('ol.structs.IHasChecksum'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.Stroke'); - - - -/** - * @classdesc - * Set circle style for vector features. - * - * @constructor - * @param {olx.style.CircleOptions=} opt_options Options. - * @extends {ol.style.Image} - * @implements {ol.structs.IHasChecksum} - * @api - */ -ol.style.Circle = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {Array.<string>} - */ - this.checksums_ = null; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.hitDetectionCanvas_ = null; - - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : null; - - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; - - /** - * @private - * @type {number} - */ - this.radius_ = options.radius; - - /** - * @private - * @type {Array.<number>} - */ - this.origin_ = [0, 0]; - - /** - * @private - * @type {Array.<number>} - */ - this.anchor_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.size_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.hitDetectionImageSize_ = null; - - this.render_(options.atlasManager); - - /** - * @type {boolean} - */ - var snapToPixel = options.snapToPixel !== undefined ? - options.snapToPixel : true; - - goog.base(this, { - opacity: 1, - rotateWithView: false, - rotation: 0, - scale: 1, - snapToPixel: snapToPixel - }); - -}; -goog.inherits(ol.style.Circle, ol.style.Image); - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getAnchor = function() { - return this.anchor_; -}; - - -/** - * Get the fill style for the circle. - * @return {ol.style.Fill} Fill style. - * @api - */ -ol.style.Circle.prototype.getFill = function() { - return this.fill_; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getHitDetectionImage = function(pixelRatio) { - return this.hitDetectionCanvas_; -}; - - -/** - * Get the image used to render the circle. - * @param {number} pixelRatio Pixel ratio. - * @return {HTMLCanvasElement} Canvas element. - * @api - */ -ol.style.Circle.prototype.getImage = function(pixelRatio) { - return this.canvas_; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getImageState = function() { - return ol.style.ImageState.LOADED; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getImageSize = function() { - return this.imageSize_; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getHitDetectionImageSize = function() { - return this.hitDetectionImageSize_; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getOrigin = function() { - return this.origin_; -}; - - -/** - * Get the circle radius. - * @return {number} Radius. - * @api - */ -ol.style.Circle.prototype.getRadius = function() { - return this.radius_; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getSize = function() { - return this.size_; -}; - - -/** - * Get the stroke style for the circle. - * @return {ol.style.Stroke} Stroke style. - * @api - */ -ol.style.Circle.prototype.getStroke = function() { - return this.stroke_; -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.listenImageChange = ol.nullFunction; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.load = ol.nullFunction; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.unlistenImageChange = ol.nullFunction; - - -/** - * @typedef {{strokeStyle: (string|undefined), strokeWidth: number, - * size: number, lineDash: Array.<number>}} - */ -ol.style.Circle.RenderOptions; - - -/** - * @private - * @param {ol.style.AtlasManager|undefined} atlasManager - */ -ol.style.Circle.prototype.render_ = function(atlasManager) { - var imageSize; - var lineDash = null; - var strokeStyle; - var strokeWidth = 0; - - if (this.stroke_) { - strokeStyle = ol.color.asString(this.stroke_.getColor()); - strokeWidth = this.stroke_.getWidth(); - if (strokeWidth === undefined) { - strokeWidth = ol.render.canvas.defaultLineWidth; - } - lineDash = this.stroke_.getLineDash(); - if (!ol.has.CANVAS_LINE_DASH) { - lineDash = null; - } - } - - - var size = 2 * (this.radius_ + strokeWidth) + 1; - - /** @type {ol.style.Circle.RenderOptions} */ - var renderOptions = { - strokeStyle: strokeStyle, - strokeWidth: strokeWidth, - size: size, - lineDash: lineDash - }; - - if (atlasManager === undefined) { - // no atlas manager is used, create a new canvas - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - this.canvas_.height = size; - this.canvas_.width = size; - - // canvas.width and height are rounded to the closest integer - size = this.canvas_.width; - imageSize = size; - - // draw the circle on the canvas - var context = /** @type {CanvasRenderingContext2D} */ - (this.canvas_.getContext('2d')); - this.draw_(renderOptions, context, 0, 0); - - this.createHitDetectionCanvas_(renderOptions); - } else { - // an atlas manager is used, add the symbol to an atlas - size = Math.round(size); - - var hasCustomHitDetectionImage = !this.fill_; - var renderHitDetectionCallback; - if (hasCustomHitDetectionImage) { - // render the hit-detection image into a separate atlas image - renderHitDetectionCallback = - goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); - } - - var id = this.getChecksum(); - var info = atlasManager.add( - id, size, size, goog.bind(this.draw_, this, renderOptions), - renderHitDetectionCallback); - goog.asserts.assert(info, 'circle radius is too large'); - - this.canvas_ = info.image; - this.origin_ = [info.offsetX, info.offsetY]; - imageSize = info.image.width; - - if (hasCustomHitDetectionImage) { - this.hitDetectionCanvas_ = info.hitImage; - this.hitDetectionImageSize_ = - [info.hitImage.width, info.hitImage.height]; - } else { - this.hitDetectionCanvas_ = this.canvas_; - this.hitDetectionImageSize_ = [imageSize, imageSize]; - } - } - - this.anchor_ = [size / 2, size / 2]; - this.size_ = [size, size]; - this.imageSize_ = [imageSize, imageSize]; -}; - - -/** - * @private - * @param {ol.style.Circle.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). - */ -ol.style.Circle.prototype.draw_ = function(renderOptions, context, x, y) { - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); - - // then move to (x, y) - context.translate(x, y); - - context.beginPath(); - context.arc( - renderOptions.size / 2, renderOptions.size / 2, - this.radius_, 0, 2 * Math.PI, true); - - if (this.fill_) { - context.fillStyle = ol.color.asString(this.fill_.getColor()); - context.fill(); - } - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); - } - context.stroke(); - } - context.closePath(); -}; - - -/** - * @private - * @param {ol.style.Circle.RenderOptions} renderOptions - */ -ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) { - this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; - if (this.fill_) { - this.hitDetectionCanvas_ = this.canvas_; - return; - } - - // if no fill style is set, create an extra hit-detection image with a - // default fill style - this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - var canvas = this.hitDetectionCanvas_; - - canvas.height = renderOptions.size; - canvas.width = renderOptions.size; - - var context = /** @type {CanvasRenderingContext2D} */ - (canvas.getContext('2d')); - this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); -}; - - -/** - * @private - * @param {ol.style.Circle.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). - */ -ol.style.Circle.prototype.drawHitDetectionCanvas_ = - function(renderOptions, context, x, y) { - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); - - // then move to (x, y) - context.translate(x, y); - - context.beginPath(); - context.arc( - renderOptions.size / 2, renderOptions.size / 2, - this.radius_, 0, 2 * Math.PI, true); - - context.fillStyle = ol.color.asString(ol.render.canvas.defaultFillStyle); - context.fill(); - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); - } - context.stroke(); - } - context.closePath(); -}; - - -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getChecksum = function() { - var strokeChecksum = this.stroke_ ? - this.stroke_.getChecksum() : '-'; - var fillChecksum = this.fill_ ? - this.fill_.getChecksum() : '-'; - - var recalculate = !this.checksums_ || - (strokeChecksum != this.checksums_[1] || - fillChecksum != this.checksums_[2] || - this.radius_ != this.checksums_[3]); - - if (recalculate) { - var checksum = 'c' + strokeChecksum + fillChecksum + - (this.radius_ !== undefined ? this.radius_.toString() : '-'); - this.checksums_ = [checksum, strokeChecksum, fillChecksum, this.radius_]; - } - - return this.checksums_[0]; -}; - -goog.provide('ol.style.GeometryFunction'); -goog.provide('ol.style.Style'); -goog.provide('ol.style.StyleFunction'); -goog.provide('ol.style.defaultGeometryFunction'); - -goog.require('goog.asserts'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.style.Circle'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Image'); -goog.require('ol.style.Stroke'); - - - -/** - * @classdesc - * Container for vector feature rendering styles. Any changes made to the style - * or its children through `set*()` methods will not take effect until the - * feature or layer that uses the style is re-rendered. - * - * @constructor - * @param {olx.style.StyleOptions=} opt_options Style options. - * @api - */ -ol.style.Style = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {string|ol.geom.Geometry|ol.style.GeometryFunction} - */ - this.geometry_ = null; - - /** - * @private - * @type {!ol.style.GeometryFunction} - */ - this.geometryFunction_ = ol.style.defaultGeometryFunction; - - if (options.geometry !== undefined) { - this.setGeometry(options.geometry); - } - - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : null; - - /** - * @private - * @type {ol.style.Image} - */ - this.image_ = options.image !== undefined ? options.image : null; - - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; - - /** - * @private - * @type {ol.style.Text} - */ - this.text_ = options.text !== undefined ? options.text : null; - - /** - * @private - * @type {number|undefined} - */ - this.zIndex_ = options.zIndex; - -}; - - -/** - * Get the geometry to be rendered. - * @return {string|ol.geom.Geometry|ol.style.GeometryFunction} - * Feature property or geometry or function that returns the geometry that will - * be rendered with this style. - * @api - */ -ol.style.Style.prototype.getGeometry = function() { - return this.geometry_; -}; - - -/** - * Get the function used to generate a geometry for rendering. - * @return {!ol.style.GeometryFunction} Function that is called with a feature - * and returns the geometry to render instead of the feature's geometry. - * @api - */ -ol.style.Style.prototype.getGeometryFunction = function() { - return this.geometryFunction_; -}; - - -/** - * Get the fill style. - * @return {ol.style.Fill} Fill style. - * @api - */ -ol.style.Style.prototype.getFill = function() { - return this.fill_; -}; - - -/** - * Get the image style. - * @return {ol.style.Image} Image style. - * @api - */ -ol.style.Style.prototype.getImage = function() { - return this.image_; -}; - - -/** - * Get the stroke style. - * @return {ol.style.Stroke} Stroke style. - * @api - */ -ol.style.Style.prototype.getStroke = function() { - return this.stroke_; -}; - - -/** - * Get the text style. - * @return {ol.style.Text} Text style. - * @api - */ -ol.style.Style.prototype.getText = function() { - return this.text_; -}; - - -/** - * Get the z-index for the style. - * @return {number|undefined} ZIndex. - * @api - */ -ol.style.Style.prototype.getZIndex = function() { - return this.zIndex_; -}; - - -/** - * Set a geometry that is rendered instead of the feature's geometry. - * - * @param {string|ol.geom.Geometry|ol.style.GeometryFunction} geometry - * Feature property or geometry or function returning a geometry to render - * for this style. - * @api - */ -ol.style.Style.prototype.setGeometry = function(geometry) { - if (goog.isFunction(geometry)) { - this.geometryFunction_ = geometry; - } else if (goog.isString(geometry)) { - this.geometryFunction_ = function(feature) { - var result = feature.get(geometry); - if (result) { - goog.asserts.assertInstanceof(result, ol.geom.Geometry, - 'feature geometry must be an ol.geom.Geometry instance'); - } - return result; - }; - } else if (!geometry) { - this.geometryFunction_ = ol.style.defaultGeometryFunction; - } else if (geometry !== undefined) { - goog.asserts.assertInstanceof(geometry, ol.geom.Geometry, - 'geometry must be an ol.geom.Geometry instance'); - this.geometryFunction_ = function() { - return geometry; - }; - } - this.geometry_ = geometry; -}; - - -/** - * Set the z-index. - * - * @param {number|undefined} zIndex ZIndex. - * @api - */ -ol.style.Style.prototype.setZIndex = function(zIndex) { - this.zIndex_ = zIndex; -}; - - -/** - * A function that takes an {@link ol.Feature} and a `{number}` representing - * the view's resolution. The function should return an array of - * {@link ol.style.Style}. This way e.g. a vector layer can be styled. - * - * @typedef {function((ol.Feature|ol.render.Feature), number): - * (ol.style.Style|Array.<ol.style.Style>)} - * @api - */ -ol.style.StyleFunction; - - -/** - * Convert the provided object into a style function. Functions passed through - * unchanged. Arrays of ol.style.Style or single style objects wrapped in a - * new style function. - * @param {ol.style.StyleFunction|Array.<ol.style.Style>|ol.style.Style} obj - * A style function, a single style, or an array of styles. - * @return {ol.style.StyleFunction} A style function. - */ -ol.style.createStyleFunction = function(obj) { - var styleFunction; - - if (goog.isFunction(obj)) { - styleFunction = obj; - } else { - /** - * @type {Array.<ol.style.Style>} - */ - var styles; - if (goog.isArray(obj)) { - styles = obj; - } else { - goog.asserts.assertInstanceof(obj, ol.style.Style, - 'obj geometry must be an ol.style.Style instance'); - styles = [obj]; - } - styleFunction = function() { - return styles; - }; - } - return styleFunction; -}; - - -/** - * @type {Array.<ol.style.Style>} - * @private - */ -ol.style.defaultStyle_ = null; - - -/** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {number} resolution Resolution. - * @return {Array.<ol.style.Style>} Style. - */ -ol.style.defaultStyleFunction = function(feature, resolution) { - // We don't use an immediately-invoked function - // and a closure so we don't get an error at script evaluation time in - // browsers that do not support Canvas. (ol.style.Circle does - // canvas.getContext('2d') at construction time, which will cause an.error - // in such browsers.) - if (!ol.style.defaultStyle_) { - var fill = new ol.style.Fill({ - color: 'rgba(255,255,255,0.4)' - }); - var stroke = new ol.style.Stroke({ - color: '#3399CC', - width: 1.25 - }); - ol.style.defaultStyle_ = [ - new ol.style.Style({ - image: new ol.style.Circle({ - fill: fill, - stroke: stroke, - radius: 5 - }), - fill: fill, - stroke: stroke - }) - ]; - } - return ol.style.defaultStyle_; -}; - - -/** - * Default styles for editing features. - * @return {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} Styles - */ -ol.style.createDefaultEditingStyles = function() { - /** @type {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} */ - var styles = {}; - var white = [255, 255, 255, 1]; - var blue = [0, 153, 255, 1]; - var width = 3; - styles[ol.geom.GeometryType.POLYGON] = [ - new ol.style.Style({ - fill: new ol.style.Fill({ - color: [255, 255, 255, 0.5] - }) - }) - ]; - styles[ol.geom.GeometryType.MULTI_POLYGON] = - styles[ol.geom.GeometryType.POLYGON]; - - styles[ol.geom.GeometryType.LINE_STRING] = [ - new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: white, - width: width + 2 - }) - }), - new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: blue, - width: width - }) - }) - ]; - styles[ol.geom.GeometryType.MULTI_LINE_STRING] = - styles[ol.geom.GeometryType.LINE_STRING]; - - styles[ol.geom.GeometryType.CIRCLE] = - styles[ol.geom.GeometryType.POLYGON].concat( - styles[ol.geom.GeometryType.LINE_STRING] - ); - - - styles[ol.geom.GeometryType.POINT] = [ - new ol.style.Style({ - image: new ol.style.Circle({ - radius: width * 2, - fill: new ol.style.Fill({ - color: blue - }), - stroke: new ol.style.Stroke({ - color: white, - width: width / 2 - }) - }), - zIndex: Infinity - }) - ]; - styles[ol.geom.GeometryType.MULTI_POINT] = - styles[ol.geom.GeometryType.POINT]; - - styles[ol.geom.GeometryType.GEOMETRY_COLLECTION] = - styles[ol.geom.GeometryType.POLYGON].concat( - styles[ol.geom.GeometryType.LINE_STRING], - styles[ol.geom.GeometryType.POINT] - ); - - return styles; -}; - - -/** - * A function that takes an {@link ol.Feature} as argument and returns an - * {@link ol.geom.Geometry} that will be rendered and styled for the feature. - * - * @typedef {function((ol.Feature|ol.render.Feature)): - * (ol.geom.Geometry|ol.render.Feature|undefined)} - * @api - */ -ol.style.GeometryFunction; - - -/** - * Function that is called with a feature and returns its default geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry - * for. - * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render. - */ -ol.style.defaultGeometryFunction = function(feature) { - goog.asserts.assert(feature, 'feature must not be null'); - return feature.getGeometry(); -}; -goog.exportSymbol('ol.style.defaultStyleFunction', ol.style.defaultStyleFunction); - -goog.provide('ol.layer.Vector'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.layer.Layer'); -goog.require('ol.style.Style'); - - -/** - * @enum {string} - */ -ol.layer.VectorProperty = { - RENDER_ORDER: 'renderOrder' -}; - - - -/** - * @classdesc - * Vector data that is rendered client-side. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Layer} - * @fires ol.render.Event - * @param {olx.layer.VectorOptions=} opt_options Options. - * @api stable - */ -ol.layer.Vector = function(opt_options) { - - var options = opt_options ? - opt_options : /** @type {olx.layer.VectorOptions} */ ({}); - - goog.asserts.assert( - options.renderOrder === undefined || !options.renderOrder || - goog.isFunction(options.renderOrder), - 'renderOrder must be a comparator function'); - - var baseOptions = goog.object.clone(options); - - delete baseOptions.style; - delete baseOptions.renderBuffer; - delete baseOptions.updateWhileAnimating; - delete baseOptions.updateWhileInteracting; - goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); - - /** - * @type {number} - * @private - */ - this.renderBuffer_ = options.renderBuffer !== undefined ? - options.renderBuffer : 100; - - /** - * User provided style. - * @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * @private - */ - this.style_ = null; - - /** - * Style function for use within the library. - * @type {ol.style.StyleFunction|undefined} - * @private - */ - this.styleFunction_ = undefined; - - this.setStyle(options.style); - - /** - * @type {boolean} - * @private - */ - this.updateWhileAnimating_ = options.updateWhileAnimating !== undefined ? - options.updateWhileAnimating : false; - - /** - * @type {boolean} - * @private - */ - this.updateWhileInteracting_ = options.updateWhileInteracting !== undefined ? - options.updateWhileInteracting : false; - -}; -goog.inherits(ol.layer.Vector, ol.layer.Layer); - - -/** - * @return {number|undefined} Render buffer. - */ -ol.layer.Vector.prototype.getRenderBuffer = function() { - return this.renderBuffer_; -}; - - -/** - * @return {function(ol.Feature, ol.Feature): number|null|undefined} Render - * order. - */ -ol.layer.Vector.prototype.getRenderOrder = function() { - return /** @type {function(ol.Feature, ol.Feature):number|null|undefined} */ ( - this.get(ol.layer.VectorProperty.RENDER_ORDER)); -}; - - -/** - * Return the associated {@link ol.source.Vector vectorsource} of the layer. - * @function - * @return {ol.source.Vector} Source. - * @api stable - */ -ol.layer.Vector.prototype.getSource; - - -/** - * Get the style for features. This returns whatever was passed to the `style` - * option at construction or to the `setStyle` method. - * @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * Layer style. - * @api stable - */ -ol.layer.Vector.prototype.getStyle = function() { - return this.style_; -}; - - -/** - * Get the style function. - * @return {ol.style.StyleFunction|undefined} Layer style function. - * @api stable - */ -ol.layer.Vector.prototype.getStyleFunction = function() { - return this.styleFunction_; -}; - - -/** - * @return {boolean} Whether the rendered layer should be updated while - * animating. - */ -ol.layer.Vector.prototype.getUpdateWhileAnimating = function() { - return this.updateWhileAnimating_; -}; - - -/** - * @return {boolean} Whether the rendered layer should be updated while - * interacting. - */ -ol.layer.Vector.prototype.getUpdateWhileInteracting = function() { - return this.updateWhileInteracting_; -}; - - -/** - * @param {function(ol.Feature, ol.Feature):number|null|undefined} renderOrder - * Render order. - */ -ol.layer.Vector.prototype.setRenderOrder = function(renderOrder) { - goog.asserts.assert( - renderOrder === undefined || !renderOrder || - goog.isFunction(renderOrder), - 'renderOrder must be a comparator function'); - this.set(ol.layer.VectorProperty.RENDER_ORDER, renderOrder); -}; - - -/** - * Set the style for features. This can be a single style object, an array - * of styles, or a function that takes a feature and resolution and returns - * an array of styles. If it is `undefined` the default style is used. If - * it is `null` the layer has no style (a `null` style), so only features - * that have their own styles will be rendered in the layer. See - * {@link ol.style} for information on the default style. - * @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|null|undefined} - * style Layer style. - * @api stable - */ -ol.layer.Vector.prototype.setStyle = function(style) { - this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction; - this.styleFunction_ = style === null ? - undefined : ol.style.createStyleFunction(this.style_); - this.changed(); -}; - -goog.provide('ol.layer.VectorTile'); - -goog.require('goog.object'); -goog.require('ol.layer.Vector'); - - -/** - * @enum {string} - */ -ol.layer.VectorTileProperty = { - PRELOAD: 'preload', - USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError' -}; - - - -/** - * @classdesc - * Layer for vector tile data that is rendered client-side. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Vector} - * @param {olx.layer.VectorTileOptions=} opt_options Options. - * @api - */ -ol.layer.VectorTile = function(opt_options) { - var options = opt_options ? opt_options : {}; - - var baseOptions = goog.object.clone(options); - - delete baseOptions.preload; - delete baseOptions.useInterimTilesOnError; - goog.base(this, /** @type {olx.layer.VectorOptions} */ (baseOptions)); - - this.setPreload(options.preload ? options.preload : 0); - this.setUseInterimTilesOnError(options.useInterimTilesOnError ? - options.useInterimTilesOnError : true); - -}; -goog.inherits(ol.layer.VectorTile, ol.layer.Vector); - - -/** - * Return the level as number to which we will preload tiles up to. - * @return {number} The level to preload tiles up to. - * @observable - * @api - */ -ol.layer.VectorTile.prototype.getPreload = function() { - return /** @type {number} */ (this.get(ol.layer.VectorTileProperty.PRELOAD)); -}; - - -/** - * Return the associated {@link ol.source.VectorTile source} of the layer. - * @function - * @return {ol.source.VectorTile} Source. - * @api - */ -ol.layer.VectorTile.prototype.getSource; - - -/** - * Whether we use interim tiles on error. - * @return {boolean} Use interim tiles on error. - * @observable - * @api - */ -ol.layer.VectorTile.prototype.getUseInterimTilesOnError = function() { - return /** @type {boolean} */ ( - this.get(ol.layer.VectorTileProperty.USE_INTERIM_TILES_ON_ERROR)); -}; - - -/** - * Set the level as number to which we will preload tiles up to. - * @param {number} preload The level to preload tiles up to. - * @observable - * @api - */ -ol.layer.VectorTile.prototype.setPreload = function(preload) { - this.set(ol.layer.TileProperty.PRELOAD, preload); -}; - - -/** - * Set whether we use interim tiles on error. - * @param {boolean} useInterimTilesOnError Use interim tiles on error. - * @observable - * @api - */ -ol.layer.VectorTile.prototype.setUseInterimTilesOnError = - function(useInterimTilesOnError) { - this.set( - ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); -}; - -// FIXME test, especially polygons with holes and multipolygons -// FIXME need to handle large thick features (where pixel size matters) -// FIXME add offset and end to ol.geom.flat.transform.transform2D? - -goog.provide('ol.render.canvas.Immediate'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.color'); -goog.require('ol.extent'); -goog.require('ol.geom.flat.transform'); -goog.require('ol.has'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.canvas'); -goog.require('ol.vec.Mat4'); - - - -/** - * @classdesc - * A concrete subclass of {@link ol.render.VectorContext} that implements - * direct rendering of features and geometries to an HTML5 Canvas context. - * Instances of this class are created internally by the library and - * provided to application code as vectorContext member of the - * {@link ol.render.Event} object associated with postcompose, precompose and - * render events emitted by layers and maps. - * - * @constructor - * @extends {ol.render.VectorContext} - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Extent} extent Extent. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @struct - */ -ol.render.canvas.Immediate = - function(context, pixelRatio, extent, transform, viewRotation) { - - /** - * @private - * @type {!Object.<string, - * Array.<function(ol.render.canvas.Immediate)>>} - */ - this.callbacksByZIndex_ = {}; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = context; - - /** - * @private - * @type {number} - */ - this.pixelRatio_ = pixelRatio; - - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = extent; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = transform; - - /** - * @private - * @type {number} - */ - this.viewRotation_ = viewRotation; - - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.contextFillState_ = null; - - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.contextStrokeState_ = null; - - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.contextTextState_ = null; - - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.fillState_ = null; - - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.strokeState_ = null; - - /** - * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} - */ - this.image_ = null; - - /** - * @private - * @type {number} - */ - this.imageAnchorX_ = 0; - - /** - * @private - * @type {number} - */ - this.imageAnchorY_ = 0; - - /** - * @private - * @type {number} - */ - this.imageHeight_ = 0; - - /** - * @private - * @type {number} - */ - this.imageOpacity_ = 0; - - /** - * @private - * @type {number} - */ - this.imageOriginX_ = 0; - - /** - * @private - * @type {number} - */ - this.imageOriginY_ = 0; - - /** - * @private - * @type {boolean} - */ - this.imageRotateWithView_ = false; - - /** - * @private - * @type {number} - */ - this.imageRotation_ = 0; - - /** - * @private - * @type {number} - */ - this.imageScale_ = 0; - - /** - * @private - * @type {boolean} - */ - this.imageSnapToPixel_ = false; - - /** - * @private - * @type {number} - */ - this.imageWidth_ = 0; - - /** - * @private - * @type {string} - */ - this.text_ = ''; - - /** - * @private - * @type {number} - */ - this.textOffsetX_ = 0; - - /** - * @private - * @type {number} - */ - this.textOffsetY_ = 0; - - /** - * @private - * @type {number} - */ - this.textRotation_ = 0; - - /** - * @private - * @type {number} - */ - this.textScale_ = 0; - - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.textFillState_ = null; - - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.textStrokeState_ = null; - - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.textState_ = null; - - /** - * @private - * @type {Array.<number>} - */ - this.pixelCoordinates_ = []; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); - -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - */ -ol.render.canvas.Immediate.prototype.drawImages_ = - function(flatCoordinates, offset, end, stride) { - if (!this.image_) { - return; - } - goog.asserts.assert(offset === 0, 'offset should be 0'); - goog.asserts.assert(end == flatCoordinates.length, - 'end should be equal to the length of flatCoordinates'); - var pixelCoordinates = ol.geom.flat.transform.transform2D( - flatCoordinates, offset, end, 2, this.transform_, - this.pixelCoordinates_); - var context = this.context_; - var localTransform = this.tmpLocalTransform_; - var alpha = context.globalAlpha; - if (this.imageOpacity_ != 1) { - context.globalAlpha = alpha * this.imageOpacity_; - } - var rotation = this.imageRotation_; - if (this.imageRotateWithView_) { - rotation += this.viewRotation_; - } - var i, ii; - for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { - var x = pixelCoordinates[i] - this.imageAnchorX_; - var y = pixelCoordinates[i + 1] - this.imageAnchorY_; - if (this.imageSnapToPixel_) { - x = (x + 0.5) | 0; - y = (y + 0.5) | 0; - } - if (rotation !== 0 || this.imageScale_ != 1) { - var centerX = x + this.imageAnchorX_; - var centerY = y + this.imageAnchorY_; - ol.vec.Mat4.makeTransform2D(localTransform, - centerX, centerY, this.imageScale_, this.imageScale_, - rotation, -centerX, -centerY); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - context.drawImage(this.image_, this.imageOriginX_, this.imageOriginY_, - this.imageWidth_, this.imageHeight_, x, y, - this.imageWidth_, this.imageHeight_); - } - if (rotation !== 0 || this.imageScale_ != 1) { - context.setTransform(1, 0, 0, 1, 0, 0); - } - if (this.imageOpacity_ != 1) { - context.globalAlpha = alpha; - } -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - */ -ol.render.canvas.Immediate.prototype.drawText_ = - function(flatCoordinates, offset, end, stride) { - if (!this.textState_ || this.text_ === '') { - return; - } - if (this.textFillState_) { - this.setContextFillState_(this.textFillState_); - } - if (this.textStrokeState_) { - this.setContextStrokeState_(this.textStrokeState_); - } - this.setContextTextState_(this.textState_); - goog.asserts.assert(offset === 0, 'offset should be 0'); - goog.asserts.assert(end == flatCoordinates.length, - 'end should be equal to the length of flatCoordinates'); - var pixelCoordinates = ol.geom.flat.transform.transform2D( - flatCoordinates, offset, end, stride, this.transform_, - this.pixelCoordinates_); - var context = this.context_; - for (; offset < end; offset += stride) { - var x = pixelCoordinates[offset] + this.textOffsetX_; - var y = pixelCoordinates[offset + 1] + this.textOffsetY_; - if (this.textRotation_ !== 0 || this.textScale_ != 1) { - var localTransform = ol.vec.Mat4.makeTransform2D(this.tmpLocalTransform_, - x, y, this.textScale_, this.textScale_, this.textRotation_, -x, -y); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - if (this.textStrokeState_) { - context.strokeText(this.text_, x, y); - } - if (this.textFillState_) { - context.fillText(this.text_, x, y); - } - } - if (this.textRotation_ !== 0 || this.textScale_ != 1) { - context.setTransform(1, 0, 0, 1, 0, 0); - } -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {boolean} close Close. - * @private - * @return {number} end End. - */ -ol.render.canvas.Immediate.prototype.moveToLineTo_ = - function(flatCoordinates, offset, end, stride, close) { - var context = this.context_; - var pixelCoordinates = ol.geom.flat.transform.transform2D( - flatCoordinates, offset, end, stride, this.transform_, - this.pixelCoordinates_); - context.moveTo(pixelCoordinates[0], pixelCoordinates[1]); - var i; - for (i = 2; i < pixelCoordinates.length; i += 2) { - context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]); - } - if (close) { - context.lineTo(pixelCoordinates[0], pixelCoordinates[1]); - } - return end; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @private - * @return {number} End. - */ -ol.render.canvas.Immediate.prototype.drawRings_ = - function(flatCoordinates, offset, ends, stride) { - var context = this.context_; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.moveToLineTo_( - flatCoordinates, offset, ends[i], stride, true); - context.closePath(); // FIXME is this needed here? - } - return offset; -}; - - -/** - * Register a function to be called for rendering at a given zIndex. The - * function will be called asynchronously. The callback will receive a - * reference to {@link ol.render.canvas.Immediate} context for drawing. - * - * @param {number} zIndex Z index. - * @param {function(ol.render.canvas.Immediate)} callback Callback. - * @api - */ -ol.render.canvas.Immediate.prototype.drawAsync = function(zIndex, callback) { - var zIndexKey = zIndex.toString(); - var callbacks = this.callbacksByZIndex_[zIndexKey]; - if (callbacks !== undefined) { - callbacks.push(callback); - } else { - this.callbacksByZIndex_[zIndexKey] = [callback]; - } -}; - - -/** - * Render a circle geometry into the canvas. Rendering is immediate and uses - * the current fill and stroke styles. - * - * @param {ol.geom.Circle} circleGeometry Circle geometry. - * @param {ol.Feature} feature Feature, - * @api - */ -ol.render.canvas.Immediate.prototype.drawCircleGeometry = - function(circleGeometry, feature) { - if (!ol.extent.intersects(this.extent_, circleGeometry.getExtent())) { - return; - } - if (this.fillState_ || this.strokeState_) { - if (this.fillState_) { - this.setContextFillState_(this.fillState_); - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - } - var pixelCoordinates = ol.geom.transformSimpleGeometry2D( - circleGeometry, this.transform_, this.pixelCoordinates_); - var dx = pixelCoordinates[2] - pixelCoordinates[0]; - var dy = pixelCoordinates[3] - pixelCoordinates[1]; - var radius = Math.sqrt(dx * dx + dy * dy); - var context = this.context_; - context.beginPath(); - context.arc( - pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI); - if (this.fillState_) { - context.fill(); - } - if (this.strokeState_) { - context.stroke(); - } - } - if (this.text_ !== '') { - this.drawText_(circleGeometry.getCenter(), 0, 2, 2); - } -}; - - -/** - * Render a feature into the canvas. In order to respect the zIndex of the - * style this method draws asynchronously and thus *after* calls to - * drawXxxxGeometry have been finished, effectively drawing the feature - * *on top* of everything else. You probably should be using an - * {@link ol.layer.Vector} instead of calling this method directly. - * - * @param {ol.Feature} feature Feature. - * @param {ol.style.Style} style Style. - * @api - */ -ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) { - var geometry = style.getGeometryFunction()(feature); - if (!geometry || - !ol.extent.intersects(this.extent_, geometry.getExtent())) { - return; - } - var zIndex = style.getZIndex(); - if (zIndex === undefined) { - zIndex = 0; - } - this.drawAsync(zIndex, function(render) { - render.setFillStrokeStyle(style.getFill(), style.getStroke()); - render.setImageStyle(style.getImage()); - render.setTextStyle(style.getText()); - var renderGeometry = - ol.render.canvas.Immediate.GEOMETRY_RENDERERS_[geometry.getType()]; - goog.asserts.assert(renderGeometry !== undefined, - 'renderGeometry should be defined'); - renderGeometry.call(render, geometry, null); - }); -}; - - -/** - * Render a GeometryCollection to the canvas. Rendering is immediate and - * uses the current styles appropriate for each geometry in the collection. - * - * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry - * collection. - * @param {ol.Feature} feature Feature. - */ -ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry = - function(geometryCollectionGeometry, feature) { - var geometries = geometryCollectionGeometry.getGeometriesArray(); - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometry = geometries[i]; - var geometryRenderer = - ol.render.canvas.Immediate.GEOMETRY_RENDERERS_[geometry.getType()]; - goog.asserts.assert(geometryRenderer !== undefined, - 'geometryRenderer should be defined'); - geometryRenderer.call(this, geometry, feature); - } -}; - - -/** - * Render a Point geometry into the canvas. Rendering is immediate and uses - * the current style. - * - * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api - */ -ol.render.canvas.Immediate.prototype.drawPointGeometry = - function(pointGeometry, feature) { - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - if (this.image_) { - this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); - } - if (this.text_ !== '') { - this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); - } -}; - - -/** - * Render a MultiPoint geometry into the canvas. Rendering is immediate and - * uses the current style. - * - * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api - */ -ol.render.canvas.Immediate.prototype.drawMultiPointGeometry = - function(multiPointGeometry, feature) { - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - if (this.image_) { - this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); - } - if (this.text_ !== '') { - this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); - } -}; - - -/** - * Render a LineString into the canvas. Rendering is immediate and uses - * the current style. - * - * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line - * string geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api - */ -ol.render.canvas.Immediate.prototype.drawLineStringGeometry = - function(lineStringGeometry, feature) { - if (!ol.extent.intersects(this.extent_, lineStringGeometry.getExtent())) { - return; - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - var context = this.context_; - var flatCoordinates = lineStringGeometry.getFlatCoordinates(); - context.beginPath(); - this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length, - lineStringGeometry.getStride(), false); - context.stroke(); - } - if (this.text_ !== '') { - var flatMidpoint = lineStringGeometry.getFlatMidpoint(); - this.drawText_(flatMidpoint, 0, 2, 2); - } -}; - - -/** - * Render a MultiLineString geometry into the canvas. Rendering is immediate - * and uses the current style. - * - * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry - * MultiLineString geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api - */ -ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry = - function(multiLineStringGeometry, feature) { - var geometryExtent = multiLineStringGeometry.getExtent(); - if (!ol.extent.intersects(this.extent_, geometryExtent)) { - return; - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - var context = this.context_; - var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); - var offset = 0; - var ends = multiLineStringGeometry.getEnds(); - var stride = multiLineStringGeometry.getStride(); - context.beginPath(); - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.moveToLineTo_( - flatCoordinates, offset, ends[i], stride, false); - } - context.stroke(); - } - if (this.text_ !== '') { - var flatMidpoints = multiLineStringGeometry.getFlatMidpoints(); - this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2); - } -}; - - -/** - * Render a Polygon geometry into the canvas. Rendering is immediate and uses - * the current style. - * - * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api - */ -ol.render.canvas.Immediate.prototype.drawPolygonGeometry = - function(polygonGeometry, feature) { - if (!ol.extent.intersects(this.extent_, polygonGeometry.getExtent())) { - return; - } - if (this.strokeState_ || this.fillState_) { - if (this.fillState_) { - this.setContextFillState_(this.fillState_); - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - } - var context = this.context_; - context.beginPath(); - this.drawRings_(polygonGeometry.getOrientedFlatCoordinates(), - 0, polygonGeometry.getEnds(), polygonGeometry.getStride()); - if (this.fillState_) { - context.fill(); - } - if (this.strokeState_) { - context.stroke(); - } - } - if (this.text_ !== '') { - var flatInteriorPoint = polygonGeometry.getFlatInteriorPoint(); - this.drawText_(flatInteriorPoint, 0, 2, 2); - } -}; - - -/** - * Render MultiPolygon geometry into the canvas. Rendering is immediate and - * uses the current style. - * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry. - * @param {ol.Feature} feature Feature. - * @api - */ -ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry = - function(multiPolygonGeometry, feature) { - if (!ol.extent.intersects(this.extent_, multiPolygonGeometry.getExtent())) { - return; - } - if (this.strokeState_ || this.fillState_) { - if (this.fillState_) { - this.setContextFillState_(this.fillState_); - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - } - var context = this.context_; - var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); - var offset = 0; - var endss = multiPolygonGeometry.getEndss(); - var stride = multiPolygonGeometry.getStride(); - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - context.beginPath(); - offset = this.drawRings_(flatCoordinates, offset, ends, stride); - if (this.fillState_) { - context.fill(); - } - if (this.strokeState_) { - context.stroke(); - } - } - } - if (this.text_ !== '') { - var flatInteriorPoints = multiPolygonGeometry.getFlatInteriorPoints(); - this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2); - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.Immediate.prototype.drawText = goog.abstractMethod; - - -/** - * FIXME: empty description for jsdoc - */ -ol.render.canvas.Immediate.prototype.flush = function() { - /** @type {Array.<number>} */ - var zs = Object.keys(this.callbacksByZIndex_).map(Number); - goog.array.sort(zs); - var i, ii, callbacks, j, jj; - for (i = 0, ii = zs.length; i < ii; ++i) { - callbacks = this.callbacksByZIndex_[zs[i].toString()]; - for (j = 0, jj = callbacks.length; j < jj; ++j) { - callbacks[j](this); - } - } -}; - - -/** - * @param {ol.render.canvas.FillState} fillState Fill state. - * @private - */ -ol.render.canvas.Immediate.prototype.setContextFillState_ = - function(fillState) { - var context = this.context_; - var contextFillState = this.contextFillState_; - if (!contextFillState) { - context.fillStyle = fillState.fillStyle; - this.contextFillState_ = { - fillStyle: fillState.fillStyle - }; - } else { - if (contextFillState.fillStyle != fillState.fillStyle) { - contextFillState.fillStyle = context.fillStyle = fillState.fillStyle; - } - } -}; - - -/** - * @param {ol.render.canvas.StrokeState} strokeState Stroke state. - * @private - */ -ol.render.canvas.Immediate.prototype.setContextStrokeState_ = - function(strokeState) { - var context = this.context_; - var contextStrokeState = this.contextStrokeState_; - if (!contextStrokeState) { - context.lineCap = strokeState.lineCap; - if (ol.has.CANVAS_LINE_DASH) { - context.setLineDash(strokeState.lineDash); - } - context.lineJoin = strokeState.lineJoin; - context.lineWidth = strokeState.lineWidth; - context.miterLimit = strokeState.miterLimit; - context.strokeStyle = strokeState.strokeStyle; - this.contextStrokeState_ = { - lineCap: strokeState.lineCap, - lineDash: strokeState.lineDash, - lineJoin: strokeState.lineJoin, - lineWidth: strokeState.lineWidth, - miterLimit: strokeState.miterLimit, - strokeStyle: strokeState.strokeStyle - }; - } else { - if (contextStrokeState.lineCap != strokeState.lineCap) { - contextStrokeState.lineCap = context.lineCap = strokeState.lineCap; - } - if (ol.has.CANVAS_LINE_DASH) { - if (!goog.array.equals( - contextStrokeState.lineDash, strokeState.lineDash)) { - context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash); - } - } - if (contextStrokeState.lineJoin != strokeState.lineJoin) { - contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin; - } - if (contextStrokeState.lineWidth != strokeState.lineWidth) { - contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth; - } - if (contextStrokeState.miterLimit != strokeState.miterLimit) { - contextStrokeState.miterLimit = context.miterLimit = - strokeState.miterLimit; - } - if (contextStrokeState.strokeStyle != strokeState.strokeStyle) { - contextStrokeState.strokeStyle = context.strokeStyle = - strokeState.strokeStyle; - } - } -}; - - -/** - * @param {ol.render.canvas.TextState} textState Text state. - * @private - */ -ol.render.canvas.Immediate.prototype.setContextTextState_ = - function(textState) { - var context = this.context_; - var contextTextState = this.contextTextState_; - if (!contextTextState) { - context.font = textState.font; - context.textAlign = textState.textAlign; - context.textBaseline = textState.textBaseline; - this.contextTextState_ = { - font: textState.font, - textAlign: textState.textAlign, - textBaseline: textState.textBaseline - }; - } else { - if (contextTextState.font != textState.font) { - contextTextState.font = context.font = textState.font; - } - if (contextTextState.textAlign != textState.textAlign) { - contextTextState.textAlign = context.textAlign = textState.textAlign; - } - if (contextTextState.textBaseline != textState.textBaseline) { - contextTextState.textBaseline = context.textBaseline = - textState.textBaseline; - } - } -}; - - -/** - * Set the fill and stroke style for subsequent draw operations. To clear - * either fill or stroke styles, pass null for the appropriate parameter. - * - * @param {ol.style.Fill} fillStyle Fill style. - * @param {ol.style.Stroke} strokeStyle Stroke style. - * @api - */ -ol.render.canvas.Immediate.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { - if (!fillStyle) { - this.fillState_ = null; - } else { - var fillStyleColor = fillStyle.getColor(); - this.fillState_ = { - fillStyle: ol.color.asString(fillStyleColor ? - fillStyleColor : ol.render.canvas.defaultFillStyle) - }; - } - if (!strokeStyle) { - this.strokeState_ = null; - } else { - var strokeStyleColor = strokeStyle.getColor(); - var strokeStyleLineCap = strokeStyle.getLineCap(); - var strokeStyleLineDash = strokeStyle.getLineDash(); - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - var strokeStyleWidth = strokeStyle.getWidth(); - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - this.strokeState_ = { - lineCap: strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap, - lineDash: strokeStyleLineDash ? - strokeStyleLineDash : ol.render.canvas.defaultLineDash, - lineJoin: strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin, - lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth), - miterLimit: strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit, - strokeStyle: ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle) - }; - } -}; - - -/** - * Set the image style for subsequent draw operations. Pass null to remove - * the image style. - * - * @param {ol.style.Image} imageStyle Image style. - * @api - */ -ol.render.canvas.Immediate.prototype.setImageStyle = function(imageStyle) { - if (!imageStyle) { - this.image_ = null; - } else { - var imageAnchor = imageStyle.getAnchor(); - // FIXME pixel ratio - var imageImage = imageStyle.getImage(1); - var imageOrigin = imageStyle.getOrigin(); - var imageSize = imageStyle.getSize(); - goog.asserts.assert(imageAnchor, 'imageAnchor must be truthy'); - goog.asserts.assert(imageImage, 'imageImage must be truthy'); - goog.asserts.assert(imageOrigin, 'imageOrigin must be truthy'); - goog.asserts.assert(imageSize, 'imageSize must be truthy'); - this.imageAnchorX_ = imageAnchor[0]; - this.imageAnchorY_ = imageAnchor[1]; - this.imageHeight_ = imageSize[1]; - this.image_ = imageImage; - this.imageOpacity_ = imageStyle.getOpacity(); - this.imageOriginX_ = imageOrigin[0]; - this.imageOriginY_ = imageOrigin[1]; - this.imageRotateWithView_ = imageStyle.getRotateWithView(); - this.imageRotation_ = imageStyle.getRotation(); - this.imageScale_ = imageStyle.getScale(); - this.imageSnapToPixel_ = imageStyle.getSnapToPixel(); - this.imageWidth_ = imageSize[0]; - } -}; - - -/** - * Set the text style for subsequent draw operations. Pass null to - * remove the text style. - * - * @param {ol.style.Text} textStyle Text style. - * @api - */ -ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) { - if (!textStyle) { - this.text_ = ''; - } else { - var textFillStyle = textStyle.getFill(); - if (!textFillStyle) { - this.textFillState_ = null; - } else { - var textFillStyleColor = textFillStyle.getColor(); - this.textFillState_ = { - fillStyle: ol.color.asString(textFillStyleColor ? - textFillStyleColor : ol.render.canvas.defaultFillStyle) - }; - } - var textStrokeStyle = textStyle.getStroke(); - if (!textStrokeStyle) { - this.textStrokeState_ = null; - } else { - var textStrokeStyleColor = textStrokeStyle.getColor(); - var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); - var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); - var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); - var textStrokeStyleWidth = textStrokeStyle.getWidth(); - var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); - this.textStrokeState_ = { - lineCap: textStrokeStyleLineCap !== undefined ? - textStrokeStyleLineCap : ol.render.canvas.defaultLineCap, - lineDash: textStrokeStyleLineDash ? - textStrokeStyleLineDash : ol.render.canvas.defaultLineDash, - lineJoin: textStrokeStyleLineJoin !== undefined ? - textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin, - lineWidth: textStrokeStyleWidth !== undefined ? - textStrokeStyleWidth : ol.render.canvas.defaultLineWidth, - miterLimit: textStrokeStyleMiterLimit !== undefined ? - textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit, - strokeStyle: ol.color.asString(textStrokeStyleColor ? - textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle) - }; - } - var textFont = textStyle.getFont(); - var textOffsetX = textStyle.getOffsetX(); - var textOffsetY = textStyle.getOffsetY(); - var textRotation = textStyle.getRotation(); - var textScale = textStyle.getScale(); - var textText = textStyle.getText(); - var textTextAlign = textStyle.getTextAlign(); - var textTextBaseline = textStyle.getTextBaseline(); - this.textState_ = { - font: textFont !== undefined ? - textFont : ol.render.canvas.defaultFont, - textAlign: textTextAlign !== undefined ? - textTextAlign : ol.render.canvas.defaultTextAlign, - textBaseline: textTextBaseline !== undefined ? - textTextBaseline : ol.render.canvas.defaultTextBaseline - }; - this.text_ = textText !== undefined ? textText : ''; - this.textOffsetX_ = - textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0; - this.textOffsetY_ = - textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0; - this.textRotation_ = textRotation !== undefined ? textRotation : 0; - this.textScale_ = this.pixelRatio_ * (textScale !== undefined ? - textScale : 1); - } -}; - - -/** - * @const - * @private - * @type {Object.<ol.geom.GeometryType, - * function(this: ol.render.canvas.Immediate, - * (ol.geom.Geometry|ol.render.Feature), Object)>} - */ -ol.render.canvas.Immediate.GEOMETRY_RENDERERS_ = { - 'Point': ol.render.canvas.Immediate.prototype.drawPointGeometry, - 'LineString': ol.render.canvas.Immediate.prototype.drawLineStringGeometry, - 'Polygon': ol.render.canvas.Immediate.prototype.drawPolygonGeometry, - 'MultiPoint': ol.render.canvas.Immediate.prototype.drawMultiPointGeometry, - 'MultiLineString': - ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry, - 'MultiPolygon': ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry, - 'GeometryCollection': - ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry, - 'Circle': ol.render.canvas.Immediate.prototype.drawCircleGeometry -}; - -goog.provide('ol.renderer.canvas.Layer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Layer'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.renderer.Layer'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.Layer} - * @param {ol.layer.Layer} layer Layer. - */ -ol.renderer.canvas.Layer = function(layer) { - - goog.base(this, layer); - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - -}; -goog.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer); - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {CanvasRenderingContext2D} context Context. - */ -ol.renderer.canvas.Layer.prototype.composeFrame = - function(frameState, layerState, context) { - - this.dispatchPreComposeEvent(context, frameState); - - var image = this.getImage(); - if (image) { - - // clipped rendering if layer extent is set - var extent = layerState.extent; - var clipped = extent !== undefined; - if (clipped) { - goog.asserts.assert(extent !== undefined, - 'layerState extent is defined'); - var pixelRatio = frameState.pixelRatio; - var topLeft = ol.extent.getTopLeft(extent); - var topRight = ol.extent.getTopRight(extent); - var bottomRight = ol.extent.getBottomRight(extent); - var bottomLeft = ol.extent.getBottomLeft(extent); - - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - topLeft, topLeft); - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - topRight, topRight); - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - bottomRight, bottomRight); - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - bottomLeft, bottomLeft); - - context.save(); - context.beginPath(); - context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio); - context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio); - context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio); - context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio); - context.clip(); - } - - var imageTransform = this.getImageTransform(); - // for performance reasons, context.save / context.restore is not used - // to save and restore the transformation matrix and the opacity. - // see http://jsperf.com/context-save-restore-versus-variable - var alpha = context.globalAlpha; - context.globalAlpha = layerState.opacity; - - // for performance reasons, context.setTransform is only used - // when the view is rotated. see http://jsperf.com/canvas-transform - if (frameState.viewState.rotation === 0) { - var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3); - var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3); - var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0); - var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1); - context.drawImage(image, 0, 0, +image.width, +image.height, - Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh)); - } else { - context.setTransform( - goog.vec.Mat4.getElement(imageTransform, 0, 0), - goog.vec.Mat4.getElement(imageTransform, 1, 0), - goog.vec.Mat4.getElement(imageTransform, 0, 1), - goog.vec.Mat4.getElement(imageTransform, 1, 1), - goog.vec.Mat4.getElement(imageTransform, 0, 3), - goog.vec.Mat4.getElement(imageTransform, 1, 3)); - context.drawImage(image, 0, 0); - context.setTransform(1, 0, 0, 1, 0, 0); - } - context.globalAlpha = alpha; - - if (clipped) { - context.restore(); - } - } - - this.dispatchPostComposeEvent(context, frameState); - -}; - - -/** - * @param {ol.render.EventType} type Event type. - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @private - */ -ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = - function(type, context, frameState, opt_transform) { - var layer = this.getLayer(); - if (layer.hasListener(type)) { - var transform = opt_transform !== undefined ? - opt_transform : this.getTransform(frameState, 0); - var render = new ol.render.canvas.Immediate( - context, frameState.pixelRatio, frameState.extent, transform, - frameState.viewState.rotation); - var composeEvent = new ol.render.Event(type, layer, render, frameState, - context, null); - layer.dispatchEvent(composeEvent); - render.flush(); - } -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @protected - */ -ol.renderer.canvas.Layer.prototype.dispatchPostComposeEvent = - function(context, frameState, opt_transform) { - this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, context, - frameState, opt_transform); -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @protected - */ -ol.renderer.canvas.Layer.prototype.dispatchPreComposeEvent = - function(context, frameState, opt_transform) { - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, context, - frameState, opt_transform); -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @protected - */ -ol.renderer.canvas.Layer.prototype.dispatchRenderEvent = - function(context, frameState, opt_transform) { - this.dispatchComposeEvent_(ol.render.EventType.RENDER, context, - frameState, opt_transform); -}; - - -/** - * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas. - */ -ol.renderer.canvas.Layer.prototype.getImage = goog.abstractMethod; - - -/** - * @return {!goog.vec.Mat4.Number} Image transform. - */ -ol.renderer.canvas.Layer.prototype.getImageTransform = goog.abstractMethod; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {number} offsetX Offset on the x-axis in view coordinates. - * @protected - * @return {!goog.vec.Mat4.Number} Transform. - */ -ol.renderer.canvas.Layer.prototype.getTransform = - function(frameState, offsetX) { - var viewState = frameState.viewState; - var pixelRatio = frameState.pixelRatio; - return ol.vec.Mat4.makeTransform2D(this.transform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio / viewState.resolution, - -pixelRatio / viewState.resolution, - -viewState.rotation, - -viewState.center[0] + offsetX, - -viewState.center[1]); -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @return {boolean} whether composeFrame should be called. - */ -ol.renderer.canvas.Layer.prototype.prepareFrame = goog.abstractMethod; - - -/** - * @param {ol.Pixel} pixelOnMap Pixel. - * @param {goog.vec.Mat4.Number} imageTransformInv The transformation matrix - * to convert from a map pixel to a canvas pixel. - * @return {ol.Pixel} - * @protected - */ -ol.renderer.canvas.Layer.prototype.getPixelOnCanvas = - function(pixelOnMap, imageTransformInv) { - var pixelOnCanvas = [0, 0]; - ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas); - return pixelOnCanvas; -}; - - -/** - * @param {ol.Size} size Size. - * @return {boolean} True when the canvas with the current size does not exceed - * the maximum dimensions. - */ -ol.renderer.canvas.Layer.testCanvasSize = (function() { - - /** - * @type {CanvasRenderingContext2D} - */ - var context = null; - - /** - * @type {ImageData} - */ - var imageData = null; - - return function(size) { - if (!context) { - context = ol.dom.createCanvasContext2D(1, 1); - imageData = context.createImageData(1, 1); - var data = imageData.data; - data[0] = 42; - data[1] = 84; - data[2] = 126; - data[3] = 255; - } - var canvas = context.canvas; - var good = size[0] <= canvas.width && size[1] <= canvas.height; - if (!good) { - canvas.width = size[0]; - canvas.height = size[1]; - var x = size[0] - 1; - var y = size[1] - 1; - context.putImageData(imageData, x, y); - var result = context.getImageData(x, y, 1, 1); - good = goog.array.equals(imageData.data, result.data); - } - return good; - }; -})(); - -goog.provide('ol.render.IReplayGroup'); - -goog.require('ol.render.VectorContext'); - - -/** - * @enum {string} - */ -ol.render.ReplayType = { - IMAGE: 'Image', - LINE_STRING: 'LineString', - POLYGON: 'Polygon', - TEXT: 'Text' -}; - - -/** - * @const - * @type {Array.<ol.render.ReplayType>} - */ -ol.render.REPLAY_ORDER = [ - ol.render.ReplayType.POLYGON, - ol.render.ReplayType.LINE_STRING, - ol.render.ReplayType.IMAGE, - ol.render.ReplayType.TEXT -]; - - - -/** - * @interface - */ -ol.render.IReplayGroup = function() { -}; - - -/** - * @param {number|undefined} zIndex Z index. - * @param {ol.render.ReplayType} replayType Replay type. - * @return {ol.render.VectorContext} Replay. - */ -ol.render.IReplayGroup.prototype.getReplay = function(zIndex, replayType) { -}; - - -/** - * @return {boolean} Is empty. - */ -ol.render.IReplayGroup.prototype.isEmpty = function() { -}; - -// FIXME add option to apply snapToPixel to all coordinates? -// FIXME can eliminate empty set styles and strokes (when all geoms skipped) - -goog.provide('ol.render.canvas.ImageReplay'); -goog.provide('ol.render.canvas.LineStringReplay'); -goog.provide('ol.render.canvas.PolygonReplay'); -goog.provide('ol.render.canvas.Replay'); -goog.provide('ol.render.canvas.ReplayGroup'); -goog.provide('ol.render.canvas.TextReplay'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.array'); -goog.require('ol.color'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.extent.Relationship'); -goog.require('ol.geom.flat.simplify'); -goog.require('ol.geom.flat.transform'); -goog.require('ol.has'); -goog.require('ol.render.IReplayGroup'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.canvas'); -goog.require('ol.vec.Mat4'); - - -/** - * @enum {number} - */ -ol.render.canvas.Instruction = { - BEGIN_GEOMETRY: 0, - BEGIN_PATH: 1, - CIRCLE: 2, - CLOSE_PATH: 3, - DRAW_IMAGE: 4, - DRAW_TEXT: 5, - END_GEOMETRY: 6, - FILL: 7, - MOVE_TO_LINE_TO: 8, - SET_FILL_STYLE: 9, - SET_STROKE_STYLE: 10, - SET_TEXT_STYLE: 11, - STROKE: 12 -}; - - - -/** - * @constructor - * @extends {ol.render.VectorContext} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct - */ -ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) { - goog.base(this); - - /** - * @protected - * @type {number} - */ - this.tolerance = tolerance; - - /** - * @protected - * @const - * @type {ol.Extent} - */ - this.maxExtent = maxExtent; - - /** - * @private - * @type {ol.Extent} - */ - this.bufferedMaxExtent_ = null; - - /** - * @protected - * @type {number} - */ - this.maxLineWidth = 0; - - /** - * @protected - * @const - * @type {number} - */ - this.resolution = resolution; - - /** - * @private - * @type {Array.<*>} - */ - this.beginGeometryInstruction1_ = null; - - /** - * @private - * @type {Array.<*>} - */ - this.beginGeometryInstruction2_ = null; - - /** - * @protected - * @type {Array.<*>} - */ - this.instructions = []; - - /** - * @protected - * @type {Array.<number>} - */ - this.coordinates = []; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.renderedTransform_ = goog.vec.Mat4.createNumber(); - - /** - * @protected - * @type {Array.<*>} - */ - this.hitDetectionInstructions = []; - - /** - * @private - * @type {Array.<number>} - */ - this.pixelCoordinates_ = []; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); -}; -goog.inherits(ol.render.canvas.Replay, ol.render.VectorContext); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {boolean} close Close. - * @protected - * @return {number} My end. - */ -ol.render.canvas.Replay.prototype.appendFlatCoordinates = - function(flatCoordinates, offset, end, stride, close) { - - var myEnd = this.coordinates.length; - var extent = this.getBufferedMaxExtent(); - var lastCoord = [flatCoordinates[offset], flatCoordinates[offset + 1]]; - var nextCoord = [NaN, NaN]; - var skipped = true; - - var i, lastRel, nextRel; - for (i = offset + stride; i < end; i += stride) { - nextCoord[0] = flatCoordinates[i]; - nextCoord[1] = flatCoordinates[i + 1]; - nextRel = ol.extent.coordinateRelationship(extent, nextCoord); - if (nextRel !== lastRel) { - if (skipped) { - this.coordinates[myEnd++] = lastCoord[0]; - this.coordinates[myEnd++] = lastCoord[1]; - } - this.coordinates[myEnd++] = nextCoord[0]; - this.coordinates[myEnd++] = nextCoord[1]; - skipped = false; - } else if (nextRel === ol.extent.Relationship.INTERSECTING) { - this.coordinates[myEnd++] = nextCoord[0]; - this.coordinates[myEnd++] = nextCoord[1]; - skipped = false; - } else { - skipped = true; - } - lastCoord[0] = nextCoord[0]; - lastCoord[1] = nextCoord[1]; - lastRel = nextRel; - } - - // handle case where there is only one point to append - if (i === offset + stride) { - this.coordinates[myEnd++] = lastCoord[0]; - this.coordinates[myEnd++] = lastCoord[1]; - } - - if (close) { - this.coordinates[myEnd++] = flatCoordinates[offset]; - this.coordinates[myEnd++] = flatCoordinates[offset + 1]; - } - return myEnd; -}; - - -/** - * @protected - * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) { - this.beginGeometryInstruction1_ = - [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0]; - this.instructions.push(this.beginGeometryInstruction1_); - this.beginGeometryInstruction2_ = - [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0]; - this.hitDetectionInstructions.push(this.beginGeometryInstruction2_); -}; - - -/** - * @private - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.<*>} instructions Instructions array. - * @param {function((ol.Feature|ol.render.Feature)): T|undefined} - * featureCallback Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.canvas.Replay.prototype.replay_ = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash, - instructions, featureCallback, opt_hitExtent) { - /** @type {Array.<number>} */ - var pixelCoordinates; - if (ol.vec.Mat4.equals2D(transform, this.renderedTransform_)) { - pixelCoordinates = this.pixelCoordinates_; - } else { - pixelCoordinates = ol.geom.flat.transform.transform2D( - this.coordinates, 0, this.coordinates.length, 2, - transform, this.pixelCoordinates_); - goog.vec.Mat4.setFromArray(this.renderedTransform_, transform); - goog.asserts.assert(pixelCoordinates === this.pixelCoordinates_, - 'pixelCoordinates should be the same as this.pixelCoordinates_'); - } - var skipFeatures = !goog.object.isEmpty(skippedFeaturesHash); - var i = 0; // instruction index - var ii = instructions.length; // end of instructions - var d = 0; // data index - var dd; // end of per-instruction data - var localTransform = this.tmpLocalTransform_; - var prevX, prevY, roundX, roundY; - while (i < ii) { - var instruction = instructions[i]; - var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]); - var feature, fill, stroke, text, x, y; - switch (type) { - case ol.render.canvas.Instruction.BEGIN_GEOMETRY: - feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); - if ((skipFeatures && - skippedFeaturesHash[goog.getUid(feature).toString()]) || - !feature.getGeometry()) { - i = /** @type {number} */ (instruction[2]); - } else if (opt_hitExtent !== undefined && !ol.extent.intersects( - /** @type {Array<number>} */ (opt_hitExtent), - feature.getGeometry().getExtent())) { - i = /** @type {number} */ (instruction[2]); - } else { - ++i; - } - break; - case ol.render.canvas.Instruction.BEGIN_PATH: - context.beginPath(); - ++i; - break; - case ol.render.canvas.Instruction.CIRCLE: - goog.asserts.assert(goog.isNumber(instruction[1]), - 'second instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - var x1 = pixelCoordinates[d]; - var y1 = pixelCoordinates[d + 1]; - var x2 = pixelCoordinates[d + 2]; - var y2 = pixelCoordinates[d + 3]; - var dx = x2 - x1; - var dy = y2 - y1; - var r = Math.sqrt(dx * dx + dy * dy); - context.arc(x1, y1, r, 0, 2 * Math.PI, true); - ++i; - break; - case ol.render.canvas.Instruction.CLOSE_PATH: - context.closePath(); - ++i; - break; - case ol.render.canvas.Instruction.DRAW_IMAGE: - goog.asserts.assert(goog.isNumber(instruction[1]), - 'second instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - goog.asserts.assert(goog.isNumber(instruction[2]), - 'third instruction should be a number'); - dd = /** @type {number} */ (instruction[2]); - var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */ - (instruction[3]); - // Remaining arguments in DRAW_IMAGE are in alphabetical order - var anchorX = /** @type {number} */ (instruction[4]) * pixelRatio; - var anchorY = /** @type {number} */ (instruction[5]) * pixelRatio; - var height = /** @type {number} */ (instruction[6]); - var opacity = /** @type {number} */ (instruction[7]); - var originX = /** @type {number} */ (instruction[8]); - var originY = /** @type {number} */ (instruction[9]); - var rotateWithView = /** @type {boolean} */ (instruction[10]); - var rotation = /** @type {number} */ (instruction[11]); - var scale = /** @type {number} */ (instruction[12]); - var snapToPixel = /** @type {boolean} */ (instruction[13]); - var width = /** @type {number} */ (instruction[14]); - if (rotateWithView) { - rotation += viewRotation; - } - for (; d < dd; d += 2) { - x = pixelCoordinates[d] - anchorX; - y = pixelCoordinates[d + 1] - anchorY; - if (snapToPixel) { - x = (x + 0.5) | 0; - y = (y + 0.5) | 0; - } - if (scale != 1 || rotation !== 0) { - var centerX = x + anchorX; - var centerY = y + anchorY; - ol.vec.Mat4.makeTransform2D( - localTransform, centerX, centerY, scale, scale, - rotation, -centerX, -centerY); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - var alpha = context.globalAlpha; - if (opacity != 1) { - context.globalAlpha = alpha * opacity; - } - - context.drawImage(image, originX, originY, width, height, - x, y, width * pixelRatio, height * pixelRatio); - - if (opacity != 1) { - context.globalAlpha = alpha; - } - if (scale != 1 || rotation !== 0) { - context.setTransform(1, 0, 0, 1, 0, 0); - } - } - ++i; - break; - case ol.render.canvas.Instruction.DRAW_TEXT: - goog.asserts.assert(goog.isNumber(instruction[1]), - '2nd instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - goog.asserts.assert(goog.isNumber(instruction[2]), - '3rd instruction should be a number'); - dd = /** @type {number} */ (instruction[2]); - goog.asserts.assert(goog.isString(instruction[3]), - '4th instruction should be a string'); - text = /** @type {string} */ (instruction[3]); - goog.asserts.assert(goog.isNumber(instruction[4]), - '5th instruction should be a number'); - var offsetX = /** @type {number} */ (instruction[4]) * pixelRatio; - goog.asserts.assert(goog.isNumber(instruction[5]), - '6th instruction should be a number'); - var offsetY = /** @type {number} */ (instruction[5]) * pixelRatio; - goog.asserts.assert(goog.isNumber(instruction[6]), - '7th instruction should be a number'); - rotation = /** @type {number} */ (instruction[6]); - goog.asserts.assert(goog.isNumber(instruction[7]), - '8th instruction should be a number'); - scale = /** @type {number} */ (instruction[7]) * pixelRatio; - goog.asserts.assert(goog.isBoolean(instruction[8]), - '9th instruction should be a boolean'); - fill = /** @type {boolean} */ (instruction[8]); - goog.asserts.assert(goog.isBoolean(instruction[9]), - '10th instruction should be a boolean'); - stroke = /** @type {boolean} */ (instruction[9]); - for (; d < dd; d += 2) { - x = pixelCoordinates[d] + offsetX; - y = pixelCoordinates[d + 1] + offsetY; - if (scale != 1 || rotation !== 0) { - ol.vec.Mat4.makeTransform2D( - localTransform, x, y, scale, scale, rotation, -x, -y); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - if (stroke) { - context.strokeText(text, x, y); - } - if (fill) { - context.fillText(text, x, y); - } - if (scale != 1 || rotation !== 0) { - context.setTransform(1, 0, 0, 1, 0, 0); - } - } - ++i; - break; - case ol.render.canvas.Instruction.END_GEOMETRY: - if (featureCallback !== undefined) { - feature = - /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); - var result = featureCallback(feature); - if (result) { - return result; - } - } - ++i; - break; - case ol.render.canvas.Instruction.FILL: - context.fill(); - ++i; - break; - case ol.render.canvas.Instruction.MOVE_TO_LINE_TO: - goog.asserts.assert(goog.isNumber(instruction[1]), - '2nd instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - goog.asserts.assert(goog.isNumber(instruction[2]), - '3rd instruction should be a number'); - dd = /** @type {number} */ (instruction[2]); - x = pixelCoordinates[d]; - y = pixelCoordinates[d + 1]; - roundX = (x + 0.5) | 0; - roundY = (y + 0.5) | 0; - if (roundX !== prevX || roundY !== prevY) { - context.moveTo(x, y); - prevX = roundX; - prevY = roundY; - } - for (d += 2; d < dd; d += 2) { - x = pixelCoordinates[d]; - y = pixelCoordinates[d + 1]; - roundX = (x + 0.5) | 0; - roundY = (y + 0.5) | 0; - if (roundX !== prevX || roundY !== prevY) { - context.lineTo(x, y); - prevX = roundX; - prevY = roundY; - } - } - ++i; - break; - case ol.render.canvas.Instruction.SET_FILL_STYLE: - goog.asserts.assert(goog.isString(instruction[1]), - '2nd instruction should be a string'); - context.fillStyle = /** @type {string} */ (instruction[1]); - ++i; - break; - case ol.render.canvas.Instruction.SET_STROKE_STYLE: - goog.asserts.assert(goog.isString(instruction[1]), - '2nd instruction should be a string'); - goog.asserts.assert(goog.isNumber(instruction[2]), - '3rd instruction should be a number'); - goog.asserts.assert(goog.isString(instruction[3]), - '4rd instruction should be a string'); - goog.asserts.assert(goog.isString(instruction[4]), - '5th instruction should be a string'); - goog.asserts.assert(goog.isNumber(instruction[5]), - '6th instruction should be a number'); - goog.asserts.assert(instruction[6], - '7th instruction should not be null'); - var usePixelRatio = instruction[7] !== undefined ? - instruction[7] : true; - var lineWidth = /** @type {number} */ (instruction[2]); - context.strokeStyle = /** @type {string} */ (instruction[1]); - context.lineWidth = usePixelRatio ? lineWidth * pixelRatio : lineWidth; - context.lineCap = /** @type {string} */ (instruction[3]); - context.lineJoin = /** @type {string} */ (instruction[4]); - context.miterLimit = /** @type {number} */ (instruction[5]); - if (ol.has.CANVAS_LINE_DASH) { - context.setLineDash(/** @type {Array.<number>} */ (instruction[6])); - } - prevX = NaN; - prevY = NaN; - ++i; - break; - case ol.render.canvas.Instruction.SET_TEXT_STYLE: - goog.asserts.assert(goog.isString(instruction[1]), - '2nd instruction should be a string'); - goog.asserts.assert(goog.isString(instruction[2]), - '3rd instruction should be a string'); - goog.asserts.assert(goog.isString(instruction[3]), - '4th instruction should be a string'); - context.font = /** @type {string} */ (instruction[1]); - context.textAlign = /** @type {string} */ (instruction[2]); - context.textBaseline = /** @type {string} */ (instruction[3]); - ++i; - break; - case ol.render.canvas.Instruction.STROKE: - context.stroke(); - ++i; - break; - default: - goog.asserts.fail('Unknown canvas render instruction'); - ++i; // consume the instruction anyway, to avoid an infinite loop - break; - } - } - // assert that all instructions were consumed - goog.asserts.assert(i == instructions.length, - 'all instructions should be consumed'); - return undefined; -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - */ -ol.render.canvas.Replay.prototype.replay = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { - var instructions = this.instructions; - this.replay_(context, pixelRatio, transform, viewRotation, - skippedFeaturesHash, instructions, undefined); -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback - * Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.canvas.Replay.prototype.replayHitDetection = function( - context, transform, viewRotation, skippedFeaturesHash, - opt_featureCallback, opt_hitExtent) { - var instructions = this.hitDetectionInstructions; - return this.replay_(context, 1, transform, viewRotation, - skippedFeaturesHash, instructions, opt_featureCallback, opt_hitExtent); -}; - - -/** - * @private - */ -ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions_ = - function() { - var hitDetectionInstructions = this.hitDetectionInstructions; - // step 1 - reverse array - hitDetectionInstructions.reverse(); - // step 2 - reverse instructions within geometry blocks - var i; - var n = hitDetectionInstructions.length; - var instruction; - var type; - var begin = -1; - for (i = 0; i < n; ++i) { - instruction = hitDetectionInstructions[i]; - type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]); - if (type == ol.render.canvas.Instruction.END_GEOMETRY) { - goog.asserts.assert(begin == -1, 'begin should be -1'); - begin = i; - } else if (type == ol.render.canvas.Instruction.BEGIN_GEOMETRY) { - instruction[2] = i; - goog.asserts.assert(begin >= 0, - 'begin should be larger than or equal to 0'); - ol.array.reverseSubArray(this.hitDetectionInstructions, begin, i); - begin = -1; - } - } -}; - - -/** - * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) { - goog.asserts.assert(this.beginGeometryInstruction1_, - 'this.beginGeometryInstruction1_ should not be null'); - this.beginGeometryInstruction1_[2] = this.instructions.length; - this.beginGeometryInstruction1_ = null; - goog.asserts.assert(this.beginGeometryInstruction2_, - 'this.beginGeometryInstruction2_ should not be null'); - this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length; - this.beginGeometryInstruction2_ = null; - var endGeometryInstruction = - [ol.render.canvas.Instruction.END_GEOMETRY, feature]; - this.instructions.push(endGeometryInstruction); - this.hitDetectionInstructions.push(endGeometryInstruction); -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.render.canvas.Replay.prototype.finish = ol.nullFunction; - - -/** - * Get the buffered rendering extent. Rendering will be clipped to the extent - * provided to the constructor. To account for symbolizers that may intersect - * this extent, we calculate a buffered extent (e.g. based on stroke width). - * @return {ol.Extent} The buffered rendering extent. - * @protected - */ -ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() { - return this.maxExtent; -}; - - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct - */ -ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution) { - goog.base(this, tolerance, maxExtent, resolution); - - /** - * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} - */ - this.hitDetectionImage_ = null; - - /** - * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} - */ - this.image_ = null; - - /** - * @private - * @type {number|undefined} - */ - this.anchorX_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.anchorY_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.height_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.opacity_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.originX_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.originY_ = undefined; - - /** - * @private - * @type {boolean|undefined} - */ - this.rotateWithView_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.rotation_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.scale_ = undefined; - - /** - * @private - * @type {boolean|undefined} - */ - this.snapToPixel_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.width_ = undefined; - -}; -goog.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - * @return {number} My end. - */ -ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = - function(flatCoordinates, offset, end, stride) { - return this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.drawPointGeometry = - function(pointGeometry, feature) { - if (!this.image_) { - return; - } - goog.asserts.assert(this.anchorX_ !== undefined, - 'this.anchorX_ should be defined'); - goog.asserts.assert(this.anchorY_ !== undefined, - 'this.anchorY_ should be defined'); - goog.asserts.assert(this.height_ !== undefined, - 'this.height_ should be defined'); - goog.asserts.assert(this.opacity_ !== undefined, - 'this.opacity_ should be defined'); - goog.asserts.assert(this.originX_ !== undefined, - 'this.originX_ should be defined'); - goog.asserts.assert(this.originY_ !== undefined, - 'this.originY_ should be defined'); - goog.asserts.assert(this.rotateWithView_ !== undefined, - 'this.rotateWithView_ should be defined'); - goog.asserts.assert(this.rotation_ !== undefined, - 'this.rotation_ should be defined'); - goog.asserts.assert(this.scale_ !== undefined, - 'this.scale_ should be defined'); - goog.asserts.assert(this.width_ !== undefined, - 'this.width_ should be defined'); - this.beginGeometry(pointGeometry, feature); - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - var myBegin = this.coordinates.length; - var myEnd = this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.instructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.hitDetectionInstructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, - this.hitDetectionImage_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.endGeometry(pointGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.drawMultiPointGeometry = - function(multiPointGeometry, feature) { - if (!this.image_) { - return; - } - goog.asserts.assert(this.anchorX_ !== undefined, - 'this.anchorX_ should be defined'); - goog.asserts.assert(this.anchorY_ !== undefined, - 'this.anchorY_ should be defined'); - goog.asserts.assert(this.height_ !== undefined, - 'this.height_ should be defined'); - goog.asserts.assert(this.opacity_ !== undefined, - 'this.opacity_ should be defined'); - goog.asserts.assert(this.originX_ !== undefined, - 'this.originX_ should be defined'); - goog.asserts.assert(this.originY_ !== undefined, - 'this.originY_ should be defined'); - goog.asserts.assert(this.rotateWithView_ !== undefined, - 'this.rotateWithView_ should be defined'); - goog.asserts.assert(this.rotation_ !== undefined, - 'this.rotation_ should be defined'); - goog.asserts.assert(this.scale_ !== undefined, - 'this.scale_ should be defined'); - goog.asserts.assert(this.width_ !== undefined, - 'this.width_ should be defined'); - this.beginGeometry(multiPointGeometry, feature); - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - var myBegin = this.coordinates.length; - var myEnd = this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.instructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.hitDetectionInstructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, - this.hitDetectionImage_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.endGeometry(multiPointGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.finish = function() { - this.reverseHitDetectionInstructions_(); - // FIXME this doesn't really protect us against further calls to draw*Geometry - this.anchorX_ = undefined; - this.anchorY_ = undefined; - this.hitDetectionImage_ = null; - this.image_ = null; - this.height_ = undefined; - this.scale_ = undefined; - this.opacity_ = undefined; - this.originX_ = undefined; - this.originY_ = undefined; - this.rotateWithView_ = undefined; - this.rotation_ = undefined; - this.snapToPixel_ = undefined; - this.width_ = undefined; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) { - goog.asserts.assert(imageStyle, 'imageStyle should not be null'); - var anchor = imageStyle.getAnchor(); - goog.asserts.assert(anchor, 'anchor should not be null'); - var size = imageStyle.getSize(); - goog.asserts.assert(size, 'size should not be null'); - var hitDetectionImage = imageStyle.getHitDetectionImage(1); - goog.asserts.assert(hitDetectionImage, - 'hitDetectionImage should not be null'); - var image = imageStyle.getImage(1); - goog.asserts.assert(image, 'image should not be null'); - var origin = imageStyle.getOrigin(); - goog.asserts.assert(origin, 'origin should not be null'); - this.anchorX_ = anchor[0]; - this.anchorY_ = anchor[1]; - this.hitDetectionImage_ = hitDetectionImage; - this.image_ = image; - this.height_ = size[1]; - this.opacity_ = imageStyle.getOpacity(); - this.originX_ = origin[0]; - this.originY_ = origin[1]; - this.rotateWithView_ = imageStyle.getRotateWithView(); - this.rotation_ = imageStyle.getRotation(); - this.scale_ = imageStyle.getScale(); - this.snapToPixel_ = imageStyle.getSnapToPixel(); - this.width_ = size[0]; -}; - - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct - */ -ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution) { - - goog.base(this, tolerance, maxExtent, resolution); - - /** - * @private - * @type {{currentStrokeStyle: (string|undefined), - * currentLineCap: (string|undefined), - * currentLineDash: Array.<number>, - * currentLineJoin: (string|undefined), - * currentLineWidth: (number|undefined), - * currentMiterLimit: (number|undefined), - * lastStroke: number, - * strokeStyle: (string|undefined), - * lineCap: (string|undefined), - * lineDash: Array.<number>, - * lineJoin: (string|undefined), - * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} - */ - this.state_ = { - currentStrokeStyle: undefined, - currentLineCap: undefined, - currentLineDash: null, - currentLineJoin: undefined, - currentLineWidth: undefined, - currentMiterLimit: undefined, - lastStroke: 0, - strokeStyle: undefined, - lineCap: undefined, - lineDash: null, - lineJoin: undefined, - lineWidth: undefined, - miterLimit: undefined - }; - -}; -goog.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - * @return {number} end. - */ -ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = - function(flatCoordinates, offset, end, stride) { - var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); - var moveToLineToInstruction = - [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; - this.instructions.push(moveToLineToInstruction); - this.hitDetectionInstructions.push(moveToLineToInstruction); - return end; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() { - if (!this.bufferedMaxExtent_) { - this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); - if (this.maxLineWidth > 0) { - var width = this.resolution * (this.maxLineWidth + 1) / 2; - ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); - } - } - return this.bufferedMaxExtent_; -}; - - -/** - * @private - */ -ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() { - var state = this.state_; - var strokeStyle = state.strokeStyle; - var lineCap = state.lineCap; - var lineDash = state.lineDash; - var lineJoin = state.lineJoin; - var lineWidth = state.lineWidth; - var miterLimit = state.miterLimit; - goog.asserts.assert(strokeStyle !== undefined, - 'strokeStyle should be defined'); - goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined'); - goog.asserts.assert(lineDash, 'lineDash should not be null'); - goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined'); - goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined'); - goog.asserts.assert(miterLimit !== undefined, 'miterLimit should be defined'); - if (state.currentStrokeStyle != strokeStyle || - state.currentLineCap != lineCap || - !goog.array.equals(state.currentLineDash, lineDash) || - state.currentLineJoin != lineJoin || - state.currentLineWidth != lineWidth || - state.currentMiterLimit != miterLimit) { - if (state.lastStroke != this.coordinates.length) { - this.instructions.push( - [ol.render.canvas.Instruction.STROKE]); - state.lastStroke = this.coordinates.length; - } - this.instructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - state.currentStrokeStyle = strokeStyle; - state.currentLineCap = lineCap; - state.currentLineDash = lineDash; - state.currentLineJoin = lineJoin; - state.currentLineWidth = lineWidth; - state.currentMiterLimit = miterLimit; - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.drawLineStringGeometry = - function(lineStringGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var strokeStyle = state.strokeStyle; - var lineWidth = state.lineWidth; - if (strokeStyle === undefined || lineWidth === undefined) { - return; - } - this.setStrokeStyle_(); - this.beginGeometry(lineStringGeometry, feature); - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - var flatCoordinates = lineStringGeometry.getFlatCoordinates(); - var stride = lineStringGeometry.getStride(); - this.drawFlatCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); - this.endGeometry(lineStringGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.drawMultiLineStringGeometry = - function(multiLineStringGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var strokeStyle = state.strokeStyle; - var lineWidth = state.lineWidth; - if (strokeStyle === undefined || lineWidth === undefined) { - return; - } - this.setStrokeStyle_(); - this.beginGeometry(multiLineStringGeometry, feature); - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - var ends = multiLineStringGeometry.getEnds(); - var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); - var stride = multiLineStringGeometry.getStride(); - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.drawFlatCoordinates_( - flatCoordinates, offset, ends[i], stride); - } - this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); - this.endGeometry(multiLineStringGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.finish = function() { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - if (state.lastStroke != this.coordinates.length) { - this.instructions.push([ol.render.canvas.Instruction.STROKE]); - } - this.reverseHitDetectionInstructions_(); - this.state_ = null; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { - goog.asserts.assert(this.state_, 'this.state_ should not be null'); - goog.asserts.assert(!fillStyle, 'fillStyle should be null'); - goog.asserts.assert(strokeStyle, 'strokeStyle should not be null'); - var strokeStyleColor = strokeStyle.getColor(); - this.state_.strokeStyle = ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle); - var strokeStyleLineCap = strokeStyle.getLineCap(); - this.state_.lineCap = strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap; - var strokeStyleLineDash = strokeStyle.getLineDash(); - this.state_.lineDash = strokeStyleLineDash ? - strokeStyleLineDash : ol.render.canvas.defaultLineDash; - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - this.state_.lineJoin = strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var strokeStyleWidth = strokeStyle.getWidth(); - this.state_.lineWidth = strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth; - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - this.state_.miterLimit = strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - - if (this.state_.lineWidth > this.maxLineWidth) { - this.maxLineWidth = this.state_.lineWidth; - // invalidate the buffered max extent cache - this.bufferedMaxExtent_ = null; - } -}; - - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct - */ -ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) { - - goog.base(this, tolerance, maxExtent, resolution); - - /** - * @private - * @type {{currentFillStyle: (string|undefined), - * currentStrokeStyle: (string|undefined), - * currentLineCap: (string|undefined), - * currentLineDash: Array.<number>, - * currentLineJoin: (string|undefined), - * currentLineWidth: (number|undefined), - * currentMiterLimit: (number|undefined), - * fillStyle: (string|undefined), - * strokeStyle: (string|undefined), - * lineCap: (string|undefined), - * lineDash: Array.<number>, - * lineJoin: (string|undefined), - * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} - */ - this.state_ = { - currentFillStyle: undefined, - currentStrokeStyle: undefined, - currentLineCap: undefined, - currentLineDash: null, - currentLineJoin: undefined, - currentLineWidth: undefined, - currentMiterLimit: undefined, - fillStyle: undefined, - strokeStyle: undefined, - lineCap: undefined, - lineDash: null, - lineJoin: undefined, - lineWidth: undefined, - miterLimit: undefined - }; - -}; -goog.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @private - * @return {number} End. - */ -ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = - function(flatCoordinates, offset, ends, stride) { - var state = this.state_; - var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - this.instructions.push(beginPathInstruction); - this.hitDetectionInstructions.push(beginPathInstruction); - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, true); - var moveToLineToInstruction = - [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; - var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH]; - this.instructions.push(moveToLineToInstruction, closePathInstruction); - this.hitDetectionInstructions.push(moveToLineToInstruction, - closePathInstruction); - offset = end; - } - // FIXME is it quicker to fill and stroke each polygon individually, - // FIXME or all polygons together? - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); - if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); - } - if (state.strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); - } - return offset; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.drawCircleGeometry = - function(circleGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(circleGeometry, feature); - // always fill the circle for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var flatCoordinates = circleGeometry.getFlatCoordinates(); - var stride = circleGeometry.getStride(); - var myBegin = this.coordinates.length; - this.appendFlatCoordinates( - flatCoordinates, 0, flatCoordinates.length, stride, false); - var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin]; - this.instructions.push(beginPathInstruction, circleInstruction); - this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction); - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); - if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); - } - if (state.strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); - } - this.endGeometry(circleGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.drawPolygonGeometry = - function(polygonGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(polygonGeometry, feature); - // always fill the polygon for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var ends = polygonGeometry.getEnds(); - var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates(); - var stride = polygonGeometry.getStride(); - this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride); - this.endGeometry(polygonGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.drawMultiPolygonGeometry = - function(multiPolygonGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(multiPolygonGeometry, feature); - // always fill the multi-polygon for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var endss = multiPolygonGeometry.getEndss(); - var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); - var stride = multiPolygonGeometry.getStride(); - var offset = 0; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - offset = this.drawFlatCoordinatess_( - flatCoordinates, offset, endss[i], stride); - } - this.endGeometry(multiPolygonGeometry, feature); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.finish = function() { - goog.asserts.assert(this.state_, 'this.state_ should not be null'); - this.reverseHitDetectionInstructions_(); - this.state_ = null; - // We want to preserve topology when drawing polygons. Polygons are - // simplified using quantization and point elimination. However, we might - // have received a mix of quantized and non-quantized geometries, so ensure - // that all are quantized by quantizing all coordinates in the batch. - var tolerance = this.tolerance; - if (tolerance !== 0) { - var coordinates = this.coordinates; - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance); - } - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() { - if (!this.bufferedMaxExtent_) { - this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); - if (this.maxLineWidth > 0) { - var width = this.resolution * (this.maxLineWidth + 1) / 2; - ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); - } - } - return this.bufferedMaxExtent_; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { - goog.asserts.assert(this.state_, 'this.state_ should not be null'); - goog.asserts.assert(fillStyle || strokeStyle, - 'fillStyle or strokeStyle should not be null'); - var state = this.state_; - if (fillStyle) { - var fillStyleColor = fillStyle.getColor(); - state.fillStyle = ol.color.asString(fillStyleColor ? - fillStyleColor : ol.render.canvas.defaultFillStyle); - } else { - state.fillStyle = undefined; - } - if (strokeStyle) { - var strokeStyleColor = strokeStyle.getColor(); - state.strokeStyle = ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle); - var strokeStyleLineCap = strokeStyle.getLineCap(); - state.lineCap = strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap; - var strokeStyleLineDash = strokeStyle.getLineDash(); - state.lineDash = strokeStyleLineDash ? - strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - state.lineJoin = strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var strokeStyleWidth = strokeStyle.getWidth(); - state.lineWidth = strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth; - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - state.miterLimit = strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - - if (state.lineWidth > this.maxLineWidth) { - this.maxLineWidth = state.lineWidth; - // invalidate the buffered max extent cache - this.bufferedMaxExtent_ = null; - } - } else { - state.strokeStyle = undefined; - state.lineCap = undefined; - state.lineDash = null; - state.lineJoin = undefined; - state.lineWidth = undefined; - state.miterLimit = undefined; - } -}; - - -/** - * @private - */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { - var state = this.state_; - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - var lineCap = state.lineCap; - var lineDash = state.lineDash; - var lineJoin = state.lineJoin; - var lineWidth = state.lineWidth; - var miterLimit = state.miterLimit; - if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]); - state.currentFillStyle = state.fillStyle; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined'); - goog.asserts.assert(lineDash, 'lineDash should not be null'); - goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined'); - goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined'); - goog.asserts.assert(miterLimit !== undefined, - 'miterLimit should be defined'); - if (state.currentStrokeStyle != strokeStyle || - state.currentLineCap != lineCap || - state.currentLineDash != lineDash || - state.currentLineJoin != lineJoin || - state.currentLineWidth != lineWidth || - state.currentMiterLimit != miterLimit) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]); - state.currentStrokeStyle = strokeStyle; - state.currentLineCap = lineCap; - state.currentLineDash = lineDash; - state.currentLineJoin = lineJoin; - state.currentLineWidth = lineWidth; - state.currentMiterLimit = miterLimit; - } - } -}; - - - -/** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct - */ -ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution) { - - goog.base(this, tolerance, maxExtent, resolution); - - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.replayFillState_ = null; - - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.replayStrokeState_ = null; - - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.replayTextState_ = null; - - /** - * @private - * @type {string} - */ - this.text_ = ''; - - /** - * @private - * @type {number} - */ - this.textOffsetX_ = 0; - - /** - * @private - * @type {number} - */ - this.textOffsetY_ = 0; - - /** - * @private - * @type {number} - */ - this.textRotation_ = 0; - - /** - * @private - * @type {number} - */ - this.textScale_ = 0; - - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.textFillState_ = null; - - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.textStrokeState_ = null; - - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.textState_ = null; - -}; -goog.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay); - - -/** - * @inheritDoc - */ -ol.render.canvas.TextReplay.prototype.drawText = - function(flatCoordinates, offset, end, stride, geometry, feature) { - if (this.text_ === '' || !this.textState_ || - (!this.textFillState_ && !this.textStrokeState_)) { - return; - } - if (this.textFillState_) { - this.setReplayFillState_(this.textFillState_); - } - if (this.textStrokeState_) { - this.setReplayStrokeState_(this.textStrokeState_); - } - this.setReplayTextState_(this.textState_); - this.beginGeometry(geometry, feature); - var myBegin = this.coordinates.length; - var myEnd = - this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false); - var fill = !!this.textFillState_; - var stroke = !!this.textStrokeState_; - var drawTextInstruction = [ - ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_, - this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_, - fill, stroke]; - this.instructions.push(drawTextInstruction); - this.hitDetectionInstructions.push(drawTextInstruction); - this.endGeometry(geometry, feature); -}; - - -/** - * @param {ol.render.canvas.FillState} fillState Fill state. - * @private - */ -ol.render.canvas.TextReplay.prototype.setReplayFillState_ = - function(fillState) { - var replayFillState = this.replayFillState_; - if (replayFillState && - replayFillState.fillStyle == fillState.fillStyle) { - return; - } - var setFillStyleInstruction = - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle]; - this.instructions.push(setFillStyleInstruction); - this.hitDetectionInstructions.push(setFillStyleInstruction); - if (!replayFillState) { - this.replayFillState_ = { - fillStyle: fillState.fillStyle - }; - } else { - replayFillState.fillStyle = fillState.fillStyle; - } -}; - - -/** - * @param {ol.render.canvas.StrokeState} strokeState Stroke state. - * @private - */ -ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = - function(strokeState) { - var replayStrokeState = this.replayStrokeState_; - if (replayStrokeState && - replayStrokeState.lineCap == strokeState.lineCap && - replayStrokeState.lineDash == strokeState.lineDash && - replayStrokeState.lineJoin == strokeState.lineJoin && - replayStrokeState.lineWidth == strokeState.lineWidth && - replayStrokeState.miterLimit == strokeState.miterLimit && - replayStrokeState.strokeStyle == strokeState.strokeStyle) { - return; - } - var setStrokeStyleInstruction = [ - ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle, - strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin, - strokeState.miterLimit, strokeState.lineDash, false - ]; - this.instructions.push(setStrokeStyleInstruction); - this.hitDetectionInstructions.push(setStrokeStyleInstruction); - if (!replayStrokeState) { - this.replayStrokeState_ = { - lineCap: strokeState.lineCap, - lineDash: strokeState.lineDash, - lineJoin: strokeState.lineJoin, - lineWidth: strokeState.lineWidth, - miterLimit: strokeState.miterLimit, - strokeStyle: strokeState.strokeStyle - }; - } else { - replayStrokeState.lineCap = strokeState.lineCap; - replayStrokeState.lineDash = strokeState.lineDash; - replayStrokeState.lineJoin = strokeState.lineJoin; - replayStrokeState.lineWidth = strokeState.lineWidth; - replayStrokeState.miterLimit = strokeState.miterLimit; - replayStrokeState.strokeStyle = strokeState.strokeStyle; - } -}; - - -/** - * @param {ol.render.canvas.TextState} textState Text state. - * @private - */ -ol.render.canvas.TextReplay.prototype.setReplayTextState_ = - function(textState) { - var replayTextState = this.replayTextState_; - if (replayTextState && - replayTextState.font == textState.font && - replayTextState.textAlign == textState.textAlign && - replayTextState.textBaseline == textState.textBaseline) { - return; - } - var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE, - textState.font, textState.textAlign, textState.textBaseline]; - this.instructions.push(setTextStyleInstruction); - this.hitDetectionInstructions.push(setTextStyleInstruction); - if (!replayTextState) { - this.replayTextState_ = { - font: textState.font, - textAlign: textState.textAlign, - textBaseline: textState.textBaseline - }; - } else { - replayTextState.font = textState.font; - replayTextState.textAlign = textState.textAlign; - replayTextState.textBaseline = textState.textBaseline; - } -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { - if (!textStyle) { - this.text_ = ''; - } else { - var textFillStyle = textStyle.getFill(); - if (!textFillStyle) { - this.textFillState_ = null; - } else { - var textFillStyleColor = textFillStyle.getColor(); - var fillStyle = ol.color.asString(textFillStyleColor ? - textFillStyleColor : ol.render.canvas.defaultFillStyle); - if (!this.textFillState_) { - this.textFillState_ = { - fillStyle: fillStyle - }; - } else { - var textFillState = this.textFillState_; - textFillState.fillStyle = fillStyle; - } - } - var textStrokeStyle = textStyle.getStroke(); - if (!textStrokeStyle) { - this.textStrokeState_ = null; - } else { - var textStrokeStyleColor = textStrokeStyle.getColor(); - var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); - var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); - var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); - var textStrokeStyleWidth = textStrokeStyle.getWidth(); - var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); - var lineCap = textStrokeStyleLineCap !== undefined ? - textStrokeStyleLineCap : ol.render.canvas.defaultLineCap; - var lineDash = textStrokeStyleLineDash ? - textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; - var lineJoin = textStrokeStyleLineJoin !== undefined ? - textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var lineWidth = textStrokeStyleWidth !== undefined ? - textStrokeStyleWidth : ol.render.canvas.defaultLineWidth; - var miterLimit = textStrokeStyleMiterLimit !== undefined ? - textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - var strokeStyle = ol.color.asString(textStrokeStyleColor ? - textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle); - if (!this.textStrokeState_) { - this.textStrokeState_ = { - lineCap: lineCap, - lineDash: lineDash, - lineJoin: lineJoin, - lineWidth: lineWidth, - miterLimit: miterLimit, - strokeStyle: strokeStyle - }; - } else { - var textStrokeState = this.textStrokeState_; - textStrokeState.lineCap = lineCap; - textStrokeState.lineDash = lineDash; - textStrokeState.lineJoin = lineJoin; - textStrokeState.lineWidth = lineWidth; - textStrokeState.miterLimit = miterLimit; - textStrokeState.strokeStyle = strokeStyle; - } - } - var textFont = textStyle.getFont(); - var textOffsetX = textStyle.getOffsetX(); - var textOffsetY = textStyle.getOffsetY(); - var textRotation = textStyle.getRotation(); - var textScale = textStyle.getScale(); - var textText = textStyle.getText(); - var textTextAlign = textStyle.getTextAlign(); - var textTextBaseline = textStyle.getTextBaseline(); - var font = textFont !== undefined ? - textFont : ol.render.canvas.defaultFont; - var textAlign = textTextAlign !== undefined ? - textTextAlign : ol.render.canvas.defaultTextAlign; - var textBaseline = textTextBaseline !== undefined ? - textTextBaseline : ol.render.canvas.defaultTextBaseline; - if (!this.textState_) { - this.textState_ = { - font: font, - textAlign: textAlign, - textBaseline: textBaseline - }; - } else { - var textState = this.textState_; - textState.font = font; - textState.textAlign = textAlign; - textState.textBaseline = textBaseline; - } - this.text_ = textText !== undefined ? textText : ''; - this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0; - this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0; - this.textRotation_ = textRotation !== undefined ? textRotation : 0; - this.textScale_ = textScale !== undefined ? textScale : 1; - } -}; - - - -/** - * @constructor - * @implements {ol.render.IReplayGroup} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @param {number} resolution Resolution. - * @param {number=} opt_renderBuffer Optional rendering buffer. - * @struct - */ -ol.render.canvas.ReplayGroup = function( - tolerance, maxExtent, resolution, opt_renderBuffer) { - - /** - * @private - * @type {number} - */ - this.tolerance_ = tolerance; - - /** - * @private - * @type {ol.Extent} - */ - this.maxExtent_ = maxExtent; - - /** - * @private - * @type {number} - */ - this.resolution_ = resolution; - - /** - * @private - * @type {number|undefined} - */ - this.renderBuffer_ = opt_renderBuffer; - - /** - * @private - * @type {!Object.<string, - * Object.<ol.render.ReplayType, ol.render.canvas.Replay>>} - */ - this.replaysByZIndex_ = {}; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1); - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.hitDetectionTransform_ = goog.vec.Mat4.createNumber(); - -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.render.canvas.ReplayGroup.prototype.finish = function() { - var zKey; - for (zKey in this.replaysByZIndex_) { - var replays = this.replaysByZIndex_[zKey]; - var replayKey; - for (replayKey in replays) { - replays[replayKey].finish(); - } - } -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature - * callback. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( - coordinate, resolution, rotation, skippedFeaturesHash, callback) { - - var transform = this.hitDetectionTransform_; - ol.vec.Mat4.makeTransform2D(transform, 0.5, 0.5, - 1 / resolution, -1 / resolution, -rotation, - -coordinate[0], -coordinate[1]); - - var context = this.hitDetectionContext_; - context.clearRect(0, 0, 1, 1); - - /** - * @type {ol.Extent} - */ - var hitExtent; - if (this.renderBuffer_ !== undefined) { - hitExtent = ol.extent.createEmpty(); - ol.extent.extendCoordinate(hitExtent, coordinate); - ol.extent.buffer(hitExtent, resolution * this.renderBuffer_, hitExtent); - } - - return this.replayHitDetection_(context, transform, rotation, - skippedFeaturesHash, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - var imageData = context.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - var result = callback(feature); - if (result) { - return result; - } - context.clearRect(0, 0, 1, 1); - } - }, hitExtent); -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ReplayGroup.prototype.getReplay = - function(zIndex, replayType) { - var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0'; - var replays = this.replaysByZIndex_[zIndexKey]; - if (replays === undefined) { - replays = {}; - this.replaysByZIndex_[zIndexKey] = replays; - } - var replay = replays[replayType]; - if (replay === undefined) { - var Constructor = ol.render.canvas.BATCH_CONSTRUCTORS_[replayType]; - goog.asserts.assert(Constructor !== undefined, - replayType + - ' constructor missing from ol.render.canvas.BATCH_CONSTRUCTORS_'); - replay = new Constructor(this.tolerance_, this.maxExtent_, - this.resolution_); - replays[replayType] = replay; - } - return replay; -}; - - -/** - * @inheritDoc - */ -ol.render.canvas.ReplayGroup.prototype.isEmpty = function() { - return goog.object.isEmpty(this.replaysByZIndex_); -}; - - -/** - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - */ -ol.render.canvas.ReplayGroup.prototype.replay = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { - - /** @type {Array.<number>} */ - var zs = Object.keys(this.replaysByZIndex_).map(Number); - goog.array.sort(zs); - - // setup clipping so that the parts of over-simplified geometries are not - // visible outside the current extent when panning - var maxExtent = this.maxExtent_; - var minX = maxExtent[0]; - var minY = maxExtent[1]; - var maxX = maxExtent[2]; - var maxY = maxExtent[3]; - var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; - ol.geom.flat.transform.transform2D( - flatClipCoords, 0, 8, 2, transform, flatClipCoords); - context.save(); - context.beginPath(); - context.moveTo(flatClipCoords[0], flatClipCoords[1]); - context.lineTo(flatClipCoords[2], flatClipCoords[3]); - context.lineTo(flatClipCoords[4], flatClipCoords[5]); - context.lineTo(flatClipCoords[6], flatClipCoords[7]); - context.closePath(); - context.clip(); - - var i, ii, j, jj, replays, replay; - for (i = 0, ii = zs.length; i < ii; ++i) { - replays = this.replaysByZIndex_[zs[i].toString()]; - for (j = 0, jj = ol.render.REPLAY_ORDER.length; j < jj; ++j) { - replay = replays[ol.render.REPLAY_ORDER[j]]; - if (replay !== undefined) { - replay.replay(context, pixelRatio, transform, viewRotation, - skippedFeaturesHash); - } - } - } - - context.restore(); -}; - - -/** - * @private - * @param {CanvasRenderingContext2D} context Context. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback - * Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( - context, transform, viewRotation, skippedFeaturesHash, - featureCallback, opt_hitExtent) { - /** @type {Array.<number>} */ - var zs = Object.keys(this.replaysByZIndex_).map(Number); - goog.array.sort(zs, function(a, b) { return b - a; }); - - var i, ii, j, replays, replay, result; - for (i = 0, ii = zs.length; i < ii; ++i) { - replays = this.replaysByZIndex_[zs[i].toString()]; - for (j = ol.render.REPLAY_ORDER.length - 1; j >= 0; --j) { - replay = replays[ol.render.REPLAY_ORDER[j]]; - if (replay !== undefined) { - result = replay.replayHitDetection(context, transform, viewRotation, - skippedFeaturesHash, featureCallback, opt_hitExtent); - if (result) { - return result; - } - } - } - } - return undefined; -}; - - -/** - * @const - * @private - * @type {Object.<ol.render.ReplayType, - * function(new: ol.render.canvas.Replay, number, ol.Extent, - * number)>} - */ -ol.render.canvas.BATCH_CONSTRUCTORS_ = { - 'Image': ol.render.canvas.ImageReplay, - 'LineString': ol.render.canvas.LineStringReplay, - 'Polygon': ol.render.canvas.PolygonReplay, - 'Text': ol.render.canvas.TextReplay -}; - -goog.provide('ol.render.Feature'); - - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryType'); - - - -/** - * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like - * structure, optimized for rendering and styling. Geometry access through the - * API is limited to getting the type and extent of the geometry. - * - * @constructor - * @param {ol.geom.GeometryType} type Geometry type. - * @param {Array.<number>} flatCoordinates Flat coordinates. These always need - * to be right-handed for polygons. - * @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss. - * @param {Object.<string, *>} properties Properties. - */ -ol.render.Feature = function(type, flatCoordinates, ends, properties) { - - /** - * @private - * @type {ol.Extent|undefined} - */ - this.extent_; - - goog.asserts.assert(type === ol.geom.GeometryType.POINT || - type === ol.geom.GeometryType.MULTI_POINT || - type === ol.geom.GeometryType.LINE_STRING || - type === ol.geom.GeometryType.MULTI_LINE_STRING || - type === ol.geom.GeometryType.POLYGON, - 'Need a Point, MultiPoint, LineString, MultiLineString or Polygon type'); - - /** - * @private - * @type {ol.geom.GeometryType} - */ - this.type_ = type; - - /** - * @private - * @type {Array.<number>} - */ - this.flatCoordinates_ = flatCoordinates; - - /** - * @private - * @type {Array.<number>|Array.<Array.<number>>} - */ - this.ends_ = ends; - - /** - * @private - * @type {Object.<string, *>} - */ - this.properties_ = properties; - -}; - - -/** - * Get a feature property by its key. - * @param {string} key Key - * @return {*} Value for the requested key. - * @api - */ -ol.render.Feature.prototype.get = function(key) { - return this.properties_[key]; -}; - - -/** - * @return {Array.<number>|Array.<Array.<number>>} Ends or endss. - */ -ol.render.Feature.prototype.getEnds = function() { - return this.ends_; -}; - - -/** - * Get the extent of this feature's geometry. - * @return {ol.Extent} Extent. - * @api - */ -ol.render.Feature.prototype.getExtent = function() { - if (!this.extent_) { - this.extent_ = this.type_ === ol.geom.GeometryType.POINT ? - ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) : - ol.extent.createOrUpdateFromFlatCoordinates( - this.flatCoordinates_, 0, this.flatCoordinates_.length, 2); - - } - return this.extent_; -}; - - -/** - * @return {Array.<number>} Flat coordinates. - */ -ol.render.Feature.prototype.getFlatCoordinates = - ol.render.Feature.prototype.getOrientedFlatCoordinates = function() { - return this.flatCoordinates_; -}; - - -/** - * Get the feature for working with its geometry. - * @return {ol.render.Feature} Feature. - * @api - */ -ol.render.Feature.prototype.getGeometry = function() { - return this; -}; - - -/** - * Get the feature properties. - * @return {Object.<string, *>} Feature properties. - * @api - */ -ol.render.Feature.prototype.getProperties = function() { - return this.properties_; -}; - - -/** - * Get the feature for working with its geometry. - * @return {ol.render.Feature} Feature. - */ -ol.render.Feature.prototype.getSimplifiedGeometry = - ol.render.Feature.prototype.getGeometry; - - -/** - * @return {number} Stride. - */ -ol.render.Feature.prototype.getStride = goog.functions.constant(2); - - -/** - * @return {undefined} - */ -ol.render.Feature.prototype.getStyleFunction = ol.nullFunction; - - -/** - * Get the type of this feature's geometry. - * @return {ol.geom.GeometryType} Geometry type. - * @api - */ -ol.render.Feature.prototype.getType = function() { - return this.type_; -}; - -goog.provide('ol.renderer.vector'); - -goog.require('goog.asserts'); -goog.require('ol.render.Feature'); -goog.require('ol.render.IReplayGroup'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.Style'); - - -/** - * @param {ol.Feature|ol.render.Feature} feature1 Feature 1. - * @param {ol.Feature|ol.render.Feature} feature2 Feature 2. - * @return {number} Order. - */ -ol.renderer.vector.defaultOrder = function(feature1, feature2) { - return goog.getUid(feature1) - goog.getUid(feature2); -}; - - -/** - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @return {number} Squared pixel tolerance. - */ -ol.renderer.vector.getSquaredTolerance = function(resolution, pixelRatio) { - var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio); - return tolerance * tolerance; -}; - - -/** - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @return {number} Pixel tolerance. - */ -ol.renderer.vector.getTolerance = function(resolution, pixelRatio) { - return ol.SIMPLIFY_TOLERANCE * resolution / pixelRatio; -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Circle} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderCircleGeometry_ = - function(replayGroup, geometry, style, feature) { - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - if (fillStyle || strokeStyle) { - var polygonReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.POLYGON); - polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); - polygonReplay.drawCircleGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.style.Style} style Style. - * @param {number} squaredTolerance Squared tolerance. - * @param {function(this: T, goog.events.Event)} listener Listener function. - * @param {T} thisArg Value to use as `this` when executing `listener`. - * @return {boolean} `true` if style is loading. - * @template T - */ -ol.renderer.vector.renderFeature = function( - replayGroup, feature, style, squaredTolerance, listener, thisArg) { - var loading = false; - var imageStyle, imageState; - imageStyle = style.getImage(); - if (imageStyle) { - imageState = imageStyle.getImageState(); - if (imageState == ol.style.ImageState.LOADED || - imageState == ol.style.ImageState.ERROR) { - imageStyle.unlistenImageChange(listener, thisArg); - } else { - if (imageState == ol.style.ImageState.IDLE) { - imageStyle.load(); - } - imageState = imageStyle.getImageState(); - goog.asserts.assert(imageState == ol.style.ImageState.LOADING, - 'imageState should be LOADING'); - imageStyle.listenImageChange(listener, thisArg); - loading = true; - } - } - ol.renderer.vector.renderFeature_(replayGroup, feature, style, - squaredTolerance); - return loading; -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.style.Style} style Style. - * @param {number} squaredTolerance Squared tolerance. - * @private - */ -ol.renderer.vector.renderFeature_ = function( - replayGroup, feature, style, squaredTolerance) { - var geometry = style.getGeometryFunction()(feature); - if (!geometry) { - return; - } - var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); - var geometryRenderer = - ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()]; - goog.asserts.assert(geometryRenderer !== undefined, - 'geometryRenderer should be defined'); - geometryRenderer(replayGroup, simplifiedGeometry, style, feature); -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.GeometryCollection} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderGeometryCollectionGeometry_ = - function(replayGroup, geometry, style, feature) { - var geometries = geometry.getGeometriesArray(); - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometryRenderer = - ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()]; - goog.asserts.assert(geometryRenderer !== undefined, - 'geometryRenderer should be defined'); - geometryRenderer(replayGroup, geometries[i], style, feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.LineString|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderLineStringGeometry_ = - function(replayGroup, geometry, style, feature) { - var strokeStyle = style.getStroke(); - if (strokeStyle) { - var lineStringReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.LINE_STRING); - lineStringReplay.setFillStrokeStyle(null, strokeStyle); - lineStringReplay.drawLineStringGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.MultiLineString|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderMultiLineStringGeometry_ = - function(replayGroup, geometry, style, feature) { - var strokeStyle = style.getStroke(); - if (strokeStyle) { - var lineStringReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.LINE_STRING); - lineStringReplay.setFillStrokeStyle(null, strokeStyle); - lineStringReplay.drawMultiLineStringGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - var flatMidpointCoordinates = geometry.getFlatMidpoints(); - textReplay.drawText(flatMidpointCoordinates, 0, - flatMidpointCoordinates.length, 2, geometry, feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.MultiPolygon} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderMultiPolygonGeometry_ = - function(replayGroup, geometry, style, feature) { - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - if (strokeStyle || fillStyle) { - var polygonReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.POLYGON); - polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); - polygonReplay.drawMultiPolygonGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints(); - textReplay.drawText(flatInteriorPointCoordinates, 0, - flatInteriorPointCoordinates.length, 2, geometry, feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Point|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderPointGeometry_ = - function(replayGroup, geometry, style, feature) { - var imageStyle = style.getImage(); - if (imageStyle) { - if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { - return; - } - var imageReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.IMAGE); - imageReplay.setImageStyle(imageStyle); - imageReplay.drawPointGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry, - feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.MultiPoint|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderMultiPointGeometry_ = - function(replayGroup, geometry, style, feature) { - var imageStyle = style.getImage(); - if (imageStyle) { - if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { - return; - } - var imageReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.IMAGE); - imageReplay.setImageStyle(imageStyle); - imageReplay.drawMultiPointGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - var flatCoordinates = geometry.getFlatCoordinates(); - textReplay.drawText(flatCoordinates, 0, flatCoordinates.length, - geometry.getStride(), geometry, feature); - } -}; - - -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Polygon|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderPolygonGeometry_ = - function(replayGroup, geometry, style, feature) { - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - if (fillStyle || strokeStyle) { - var polygonReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.POLYGON); - polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); - polygonReplay.drawPolygonGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText( - geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature); - } -}; - - -/** - * @const - * @private - * @type {Object.<ol.geom.GeometryType, - * function(ol.render.IReplayGroup, ol.geom.Geometry, - * ol.style.Style, Object)>} - */ -ol.renderer.vector.GEOMETRY_RENDERERS_ = { - 'Point': ol.renderer.vector.renderPointGeometry_, - 'LineString': ol.renderer.vector.renderLineStringGeometry_, - 'Polygon': ol.renderer.vector.renderPolygonGeometry_, - 'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_, - 'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_, - 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_, - 'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_, - 'Circle': ol.renderer.vector.renderCircleGeometry_ -}; - -goog.provide('ol.ImageCanvas'); - -goog.require('goog.asserts'); -goog.require('ol.ImageBase'); -goog.require('ol.ImageState'); - - - -/** - * @constructor - * @extends {ol.ImageBase} - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {Array.<ol.Attribution>} attributions Attributions. - * @param {HTMLCanvasElement} canvas Canvas. - * @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to - * support asynchronous canvas drawing. - */ -ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions, - canvas, opt_loader) { - - /** - * Optional canvas loader function. - * @type {?ol.ImageCanvasLoader} - * @private - */ - this.loader_ = opt_loader !== undefined ? opt_loader : null; - - var state = opt_loader !== undefined ? - ol.ImageState.IDLE : ol.ImageState.LOADED; - - goog.base(this, extent, resolution, pixelRatio, state, attributions); - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = canvas; - - /** - * @private - * @type {Error} - */ - this.error_ = null; - -}; -goog.inherits(ol.ImageCanvas, ol.ImageBase); - - -/** - * Get any error associated with asynchronous rendering. - * @return {Error} Any error that occurred during rendering. - */ -ol.ImageCanvas.prototype.getError = function() { - return this.error_; -}; - - -/** - * Handle async drawing complete. - * @param {Error} err Any error during drawing. - * @private - */ -ol.ImageCanvas.prototype.handleLoad_ = function(err) { - if (err) { - this.error_ = err; - this.state = ol.ImageState.ERROR; - } else { - this.state = ol.ImageState.LOADED; - } - this.changed(); -}; - - -/** - * Trigger drawing on canvas. - */ -ol.ImageCanvas.prototype.load = function() { - if (this.state == ol.ImageState.IDLE) { - goog.asserts.assert(this.loader_, 'this.loader_ must be set'); - this.state = ol.ImageState.LOADING; - this.changed(); - this.loader_(goog.bind(this.handleLoad_, this)); - } -}; - - -/** - * @inheritDoc - */ -ol.ImageCanvas.prototype.getImage = function(opt_context) { - return this.canvas_; -}; - - -/** - * A function that is called to trigger asynchronous canvas drawing. It is - * called with a "done" callback that should be called when drawing is done. - * If any error occurs during drawing, the "done" callback should be called with - * that error. - * - * @typedef {function(function(Error))} - */ -ol.ImageCanvasLoader; - -goog.provide('ol.reproj'); - -goog.require('goog.labs.userAgent.browser'); -goog.require('goog.labs.userAgent.platform'); -goog.require('goog.math'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.math'); -goog.require('ol.proj'); - - -/** - * We need to employ more sophisticated solution - * if the web browser antialiases clipping edges on canvas. - * - * Currently only Chrome does not antialias the edges, but this is probably - * going to be "fixed" in the future: http://crbug.com/424291 - * - * @type {boolean} - * @private - */ -ol.reproj.browserAntialiasesClip_ = !goog.labs.userAgent.browser.isChrome() || - goog.labs.userAgent.platform.isIos(); - - -/** - * Calculates ideal resolution to use from the source in order to achieve - * pixel mapping as close as possible to 1:1 during reprojection. - * The resolution is calculated regardless of what resolutions - * are actually available in the dataset (TileGrid, Image, ...). - * - * @param {ol.proj.Projection} sourceProj Source projection. - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.Coordinate} targetCenter Target center. - * @param {number} targetResolution Target resolution. - * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0. - */ -ol.reproj.calculateSourceResolution = function(sourceProj, targetProj, - targetCenter, targetResolution) { - - var sourceCenter = ol.proj.transform(targetCenter, targetProj, sourceProj); - - // calculate the ideal resolution of the source data - var sourceResolution = - targetProj.getPointResolution(targetResolution, targetCenter); - - var targetMetersPerUnit = targetProj.getMetersPerUnit(); - if (targetMetersPerUnit !== undefined) { - sourceResolution *= targetMetersPerUnit; - } - var sourceMetersPerUnit = sourceProj.getMetersPerUnit(); - if (sourceMetersPerUnit !== undefined) { - sourceResolution /= sourceMetersPerUnit; - } - - // Based on the projection properties, the point resolution at the specified - // coordinates may be slightly different. We need to reverse-compensate this - // in order to achieve optimal results. - - var compensationFactor = - sourceProj.getPointResolution(sourceResolution, sourceCenter) / - sourceResolution; - - if (goog.math.isFiniteNumber(compensationFactor) && compensationFactor > 0) { - sourceResolution /= compensationFactor; - } - - return sourceResolution; -}; - - -/** - * Enlarge the clipping triangle point by 1 pixel to ensure the edges overlap - * in order to mask gaps caused by antialiasing. - * - * @param {number} centroidX Centroid of the triangle (x coordinate in pixels). - * @param {number} centroidY Centroid of the triangle (y coordinate in pixels). - * @param {number} x X coordinate of the point (in pixels). - * @param {number} y Y coordinate of the point (in pixels). - * @return {ol.Coordinate} New point 1 px farther from the centroid. - * @private - */ -ol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) { - var dX = x - centroidX, dY = y - centroidY; - var distance = Math.sqrt(dX * dX + dY * dY); - return [Math.round(x + dX / distance), Math.round(y + dY / distance)]; -}; - - -/** - * Renders the source data into new canvas based on the triangulation. - * - * @param {number} width Width of the canvas. - * @param {number} height Height of the canvas. - * @param {number} pixelRatio Pixel ratio. - * @param {number} sourceResolution Source resolution. - * @param {ol.Extent} sourceExtent Extent of the data source. - * @param {number} targetResolution Target resolution. - * @param {ol.Extent} targetExtent Target extent. - * @param {ol.reproj.Triangulation} triangulation Calculated triangulation. - * @param {Array.<{extent: ol.Extent, - * image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources - * Array of sources. - * @param {boolean=} opt_renderEdges Render reprojection edges. - * @return {HTMLCanvasElement} Canvas with reprojected data. - */ -ol.reproj.render = function(width, height, pixelRatio, - sourceResolution, sourceExtent, targetResolution, targetExtent, - triangulation, sources, opt_renderEdges) { - - var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width), - Math.round(pixelRatio * height)); - - if (sources.length === 0) { - return context.canvas; - } - - context.scale(pixelRatio, pixelRatio); - - var sourceDataExtent = ol.extent.createEmpty(); - sources.forEach(function(src, i, arr) { - ol.extent.extend(sourceDataExtent, src.extent); - }); - - var canvasWidthInUnits = ol.extent.getWidth(sourceDataExtent); - var canvasHeightInUnits = ol.extent.getHeight(sourceDataExtent); - var stitchContext = ol.dom.createCanvasContext2D( - Math.round(pixelRatio * canvasWidthInUnits / sourceResolution), - Math.round(pixelRatio * canvasHeightInUnits / sourceResolution)); - - stitchContext.scale(pixelRatio / sourceResolution, - pixelRatio / sourceResolution); - stitchContext.translate(-sourceDataExtent[0], sourceDataExtent[3]); - - sources.forEach(function(src, i, arr) { - var xPos = src.extent[0]; - var yPos = -src.extent[3]; - var srcWidth = ol.extent.getWidth(src.extent); - var srcHeight = ol.extent.getHeight(src.extent); - - stitchContext.drawImage(src.image, xPos, yPos, srcWidth, srcHeight); - }); - - var targetTopLeft = ol.extent.getTopLeft(targetExtent); - - triangulation.getTriangles().forEach(function(triangle, i, arr) { - /* Calculate affine transform (src -> dst) - * Resulting matrix can be used to transform coordinate - * from `sourceProjection` to destination pixels. - * - * To optimize number of context calls and increase numerical stability, - * we also do the following operations: - * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1) - * here before solving the linear system so [ui, vi] are pixel coordinates. - * - * Src points: xi, yi - * Dst points: ui, vi - * Affine coefficients: aij - * - * | x0 y0 1 0 0 0 | |a00| |u0| - * | x1 y1 1 0 0 0 | |a01| |u1| - * | x2 y2 1 0 0 0 | x |a02| = |u2| - * | 0 0 0 x0 y0 1 | |a10| |v0| - * | 0 0 0 x1 y1 1 | |a11| |v1| - * | 0 0 0 x2 y2 1 | |a12| |v2| - */ - var source = triangle.source, target = triangle.target; - var x0 = source[0][0], y0 = source[0][1], - x1 = source[1][0], y1 = source[1][1], - x2 = source[2][0], y2 = source[2][1]; - var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution, - v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; - var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution, - v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; - var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution, - v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; - - // Shift all the source points to improve numerical stability - // of all the subsequent calculations. The [x0, y0] is used here. - // This is also used to simplify the linear system. - var sourceNumericalShiftX = x0, sourceNumericalShiftY = y0; - x0 = 0; - y0 = 0; - x1 -= sourceNumericalShiftX; - y1 -= sourceNumericalShiftY; - x2 -= sourceNumericalShiftX; - y2 -= sourceNumericalShiftY; - - var augmentedMatrix = [ - [x1, y1, 0, 0, u1 - u0], - [x2, y2, 0, 0, u2 - u0], - [0, 0, x1, y1, v1 - v0], - [0, 0, x2, y2, v2 - v0] - ]; - var affineCoefs = ol.math.solveLinearSystem(augmentedMatrix); - if (!affineCoefs) { - return; - } - - context.save(); - context.beginPath(); - if (ol.reproj.browserAntialiasesClip_) { - var centroidX = (u0 + u1 + u2) / 3, centroidY = (v0 + v1 + v2) / 3; - var p0 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u0, v0); - var p1 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u1, v1); - var p2 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u2, v2); - - context.moveTo(p0[0], p0[1]); - context.lineTo(p1[0], p1[1]); - context.lineTo(p2[0], p2[1]); - } else { - context.moveTo(u0, v0); - context.lineTo(u1, v1); - context.lineTo(u2, v2); - } - context.closePath(); - context.clip(); - - context.transform( - affineCoefs[0], affineCoefs[2], affineCoefs[1], affineCoefs[3], u0, v0); - - context.translate(sourceDataExtent[0] - sourceNumericalShiftX, - sourceDataExtent[3] - sourceNumericalShiftY); - - context.scale(sourceResolution / pixelRatio, - -sourceResolution / pixelRatio); - - context.drawImage(stitchContext.canvas, 0, 0); - context.restore(); - }); - - if (opt_renderEdges) { - context.save(); - - context.strokeStyle = 'black'; - context.lineWidth = 1; - - triangulation.getTriangles().forEach(function(triangle, i, arr) { - var target = triangle.target; - var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution, - v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; - var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution, - v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; - var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution, - v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; - - context.beginPath(); - context.moveTo(u0, v0); - context.lineTo(u1, v1); - context.lineTo(u2, v2); - context.closePath(); - context.stroke(); - }); - - context.restore(); - } - return context.canvas; -}; - -goog.provide('ol.reproj.Triangulation'); - -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol.extent'); -goog.require('ol.proj'); - - -/** - * Single triangle; consists of 3 source points and 3 target points. - * - * @typedef {{source: Array.<ol.Coordinate>, - * target: Array.<ol.Coordinate>}} - */ -ol.reproj.Triangle; - - - -/** - * @classdesc - * Class containing triangulation of the given target extent. - * Used for determining source data and the reprojection itself. - * - * @param {ol.proj.Projection} sourceProj Source projection. - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.Extent} targetExtent Target extent to triangulate. - * @param {ol.Extent} maxSourceExtent Maximal source extent that can be used. - * @param {number} errorThreshold Acceptable error (in source units). - * @constructor - */ -ol.reproj.Triangulation = function(sourceProj, targetProj, targetExtent, - maxSourceExtent, errorThreshold) { - - /** - * @type {ol.proj.Projection} - * @private - */ - this.sourceProj_ = sourceProj; - - /** - * @type {ol.proj.Projection} - * @private - */ - this.targetProj_ = targetProj; - - /** @type {!Object.<string, ol.Coordinate>} */ - var transformInvCache = {}; - var transformInv = ol.proj.getTransform(this.targetProj_, this.sourceProj_); - - /** - * @param {ol.Coordinate} c - * @return {ol.Coordinate} - * @private - */ - this.transformInv_ = function(c) { - var key = c[0] + '/' + c[1]; - if (!transformInvCache[key]) { - transformInvCache[key] = transformInv(c); - } - return transformInvCache[key]; - }; - - /** - * @type {ol.Extent} - * @private - */ - this.maxSourceExtent_ = maxSourceExtent; - - /** - * @type {number} - * @private - */ - this.errorThresholdSquared_ = errorThreshold * errorThreshold; - - /** - * @type {Array.<ol.reproj.Triangle>} - * @private - */ - this.triangles_ = []; - - /** - * Indicates that the triangulation crosses edge of the source projection. - * @type {boolean} - * @private - */ - this.wrapsXInSource_ = false; - - /** - * @type {boolean} - * @private - */ - this.canWrapXInSource_ = this.sourceProj_.canWrapX() && - !!maxSourceExtent && - !!this.sourceProj_.getExtent() && - (ol.extent.getWidth(maxSourceExtent) == - ol.extent.getWidth(this.sourceProj_.getExtent())); - - /** - * @type {?number} - * @private - */ - this.sourceWorldWidth_ = this.sourceProj_.getExtent() ? - ol.extent.getWidth(this.sourceProj_.getExtent()) : null; - - /** - * @type {?number} - * @private - */ - this.targetWorldWidth_ = this.targetProj_.getExtent() ? - ol.extent.getWidth(this.targetProj_.getExtent()) : null; - - var destinationTopLeft = ol.extent.getTopLeft(targetExtent); - var destinationTopRight = ol.extent.getTopRight(targetExtent); - var destinationBottomRight = ol.extent.getBottomRight(targetExtent); - var destinationBottomLeft = ol.extent.getBottomLeft(targetExtent); - var sourceTopLeft = this.transformInv_(destinationTopLeft); - var sourceTopRight = this.transformInv_(destinationTopRight); - var sourceBottomRight = this.transformInv_(destinationBottomRight); - var sourceBottomLeft = this.transformInv_(destinationBottomLeft); - - this.addQuad_( - destinationTopLeft, destinationTopRight, - destinationBottomRight, destinationBottomLeft, - sourceTopLeft, sourceTopRight, sourceBottomRight, sourceBottomLeft, - ol.RASTER_REPROJECTION_MAX_SUBDIVISION); - - if (this.wrapsXInSource_) { - // Fix coordinates (ol.proj returns wrapped coordinates, "unwrap" here). - // This significantly simplifies the rest of the reprojection process. - - goog.asserts.assert(this.sourceWorldWidth_ !== null); - var leftBound = Infinity; - this.triangles_.forEach(function(triangle, i, arr) { - leftBound = Math.min(leftBound, - triangle.source[0][0], triangle.source[1][0], triangle.source[2][0]); - }); - - // Shift triangles to be as close to `leftBound` as possible - // (if the distance is more than `worldWidth / 2` it can be closer. - this.triangles_.forEach(function(triangle) { - if (Math.max(triangle.source[0][0], triangle.source[1][0], - triangle.source[2][0]) - leftBound > this.sourceWorldWidth_ / 2) { - var newTriangle = [[triangle.source[0][0], triangle.source[0][1]], - [triangle.source[1][0], triangle.source[1][1]], - [triangle.source[2][0], triangle.source[2][1]]]; - if ((newTriangle[0][0] - leftBound) > this.sourceWorldWidth_ / 2) { - newTriangle[0][0] -= this.sourceWorldWidth_; - } - if ((newTriangle[1][0] - leftBound) > this.sourceWorldWidth_ / 2) { - newTriangle[1][0] -= this.sourceWorldWidth_; - } - if ((newTriangle[2][0] - leftBound) > this.sourceWorldWidth_ / 2) { - newTriangle[2][0] -= this.sourceWorldWidth_; - } - - // Rarely (if the extent contains both the dateline and prime meridian) - // the shift can in turn break some triangles. - // Detect this here and don't shift in such cases. - var minX = Math.min( - newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]); - var maxX = Math.max( - newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]); - if ((maxX - minX) < this.sourceWorldWidth_ / 2) { - triangle.source = newTriangle; - } - } - }, this); - } - - transformInvCache = {}; -}; - - -/** - * Adds triangle to the triangulation. - * @param {ol.Coordinate} a - * @param {ol.Coordinate} b - * @param {ol.Coordinate} c - * @param {ol.Coordinate} aSrc - * @param {ol.Coordinate} bSrc - * @param {ol.Coordinate} cSrc - * @private - */ -ol.reproj.Triangulation.prototype.addTriangle_ = function(a, b, c, - aSrc, bSrc, cSrc) { - this.triangles_.push({ - source: [aSrc, bSrc, cSrc], - target: [a, b, c] - }); -}; - - -/** - * Adds quad (points in clock-wise order) to the triangulation - * (and reprojects the vertices) if valid. - * Performs quad subdivision if needed to increase precision. - * - * @param {ol.Coordinate} a - * @param {ol.Coordinate} b - * @param {ol.Coordinate} c - * @param {ol.Coordinate} d - * @param {ol.Coordinate} aSrc - * @param {ol.Coordinate} bSrc - * @param {ol.Coordinate} cSrc - * @param {ol.Coordinate} dSrc - * @param {number} maxSubdivision Maximal allowed subdivision of the quad. - * @private - */ -ol.reproj.Triangulation.prototype.addQuad_ = function(a, b, c, d, - aSrc, bSrc, cSrc, dSrc, maxSubdivision) { - - var sourceQuadExtent = ol.extent.boundingExtent([aSrc, bSrc, cSrc, dSrc]); - var sourceCoverageX = this.sourceWorldWidth_ ? - ol.extent.getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null; - - // when the quad is wrapped in the source projection - // it covers most of the projection extent, but not fully - var wrapsX = this.sourceProj_.canWrapX() && - sourceCoverageX > 0.5 && sourceCoverageX < 1; - - var needsSubdivision = false; - - if (maxSubdivision > 0) { - if (this.targetProj_.isGlobal() && this.targetWorldWidth_) { - var targetQuadExtent = ol.extent.boundingExtent([a, b, c, d]); - var targetCoverageX = - ol.extent.getWidth(targetQuadExtent) / this.targetWorldWidth_; - needsSubdivision |= - targetCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH; - } - if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) { - needsSubdivision |= - sourceCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH; - } - } - - if (!needsSubdivision && this.maxSourceExtent_) { - if (!ol.extent.intersects(sourceQuadExtent, this.maxSourceExtent_)) { - // whole quad outside source projection extent -> ignore - return; - } - } - - if (!needsSubdivision) { - if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) || - !isFinite(bSrc[0]) || !isFinite(bSrc[1]) || - !isFinite(cSrc[0]) || !isFinite(cSrc[1]) || - !isFinite(dSrc[0]) || !isFinite(dSrc[1])) { - if (maxSubdivision > 0) { - needsSubdivision = true; - } else { - return; - } - } - } - - if (maxSubdivision > 0) { - if (!needsSubdivision) { - var center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2]; - var centerSrc = this.transformInv_(center); - - var dx; - if (wrapsX) { - goog.asserts.assert(this.sourceWorldWidth_); - var centerSrcEstimX = - (goog.math.modulo(aSrc[0], this.sourceWorldWidth_) + - goog.math.modulo(cSrc[0], this.sourceWorldWidth_)) / 2; - dx = centerSrcEstimX - - goog.math.modulo(centerSrc[0], this.sourceWorldWidth_); - } else { - dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0]; - } - var dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1]; - var centerSrcErrorSquared = dx * dx + dy * dy; - needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_; - } - if (needsSubdivision) { - if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) { - // split horizontally (top & bottom) - var bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2]; - var bcSrc = this.transformInv_(bc); - var da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2]; - var daSrc = this.transformInv_(da); - - this.addQuad_( - a, b, bc, da, aSrc, bSrc, bcSrc, daSrc, maxSubdivision - 1); - this.addQuad_( - da, bc, c, d, daSrc, bcSrc, cSrc, dSrc, maxSubdivision - 1); - } else { - // split vertically (left & right) - var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]; - var abSrc = this.transformInv_(ab); - var cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2]; - var cdSrc = this.transformInv_(cd); - - this.addQuad_( - a, ab, cd, d, aSrc, abSrc, cdSrc, dSrc, maxSubdivision - 1); - this.addQuad_( - ab, b, c, cd, abSrc, bSrc, cSrc, cdSrc, maxSubdivision - 1); - } - return; - } - } - - if (wrapsX) { - if (!this.canWrapXInSource_) { - return; - } - this.wrapsXInSource_ = true; - } - - this.addTriangle_(a, c, d, aSrc, cSrc, dSrc); - this.addTriangle_(a, b, c, aSrc, bSrc, cSrc); -}; - - -/** - * Calculates extent of the 'source' coordinates from all the triangles. - * - * @return {ol.Extent} Calculated extent. - */ -ol.reproj.Triangulation.prototype.calculateSourceExtent = function() { - var extent = ol.extent.createEmpty(); - - this.triangles_.forEach(function(triangle, i, arr) { - var src = triangle.source; - ol.extent.extendCoordinate(extent, src[0]); - ol.extent.extendCoordinate(extent, src[1]); - ol.extent.extendCoordinate(extent, src[2]); - }); - - return extent; -}; - - -/** - * @return {Array.<ol.reproj.Triangle>} Array of the calculated triangles. - */ -ol.reproj.Triangulation.prototype.getTriangles = function() { - return this.triangles_; -}; - -goog.provide('ol.reproj.Image'); -goog.provide('ol.reproj.ImageFunctionType'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.ImageBase'); -goog.require('ol.ImageState'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.reproj'); -goog.require('ol.reproj.Triangulation'); - - -/** - * @typedef {function(ol.Extent, number, number) : ol.ImageBase} - */ -ol.reproj.ImageFunctionType; - - - -/** - * @classdesc - * Class encapsulating single reprojected image. - * See {@link ol.source.Image}. - * - * @constructor - * @extends {ol.ImageBase} - * @param {ol.proj.Projection} sourceProj Source projection (of the data). - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.Extent} targetExtent Target extent. - * @param {number} targetResolution Target resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.reproj.ImageFunctionType} getImageFunction - * Function returning source images (extent, resolution, pixelRatio). - */ -ol.reproj.Image = function(sourceProj, targetProj, - targetExtent, targetResolution, pixelRatio, getImageFunction) { - - /** - * @private - * @type {ol.proj.Projection} - */ - this.targetProj_ = targetProj; - - /** - * @private - * @type {ol.Extent} - */ - this.maxSourceExtent_ = sourceProj.getExtent(); - var maxTargetExtent = targetProj.getExtent(); - - var limitedTargetExtent = maxTargetExtent ? - ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent; - - var targetCenter = ol.extent.getCenter(limitedTargetExtent); - var sourceResolution = ol.reproj.calculateSourceResolution( - sourceProj, targetProj, targetCenter, targetResolution); - - var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD; - - /** - * @private - * @type {!ol.reproj.Triangulation} - */ - this.triangulation_ = new ol.reproj.Triangulation( - sourceProj, targetProj, limitedTargetExtent, this.maxSourceExtent_, - sourceResolution * errorThresholdInPixels); - - /** - * @private - * @type {number} - */ - this.targetResolution_ = targetResolution; - - /** - * @private - * @type {ol.Extent} - */ - this.targetExtent_ = targetExtent; - - var sourceExtent = this.triangulation_.calculateSourceExtent(); - - /** - * @private - * @type {ol.ImageBase} - */ - this.sourceImage_ = - getImageFunction(sourceExtent, sourceResolution, pixelRatio); - - /** - * @private - * @type {number} - */ - this.sourcePixelRatio_ = - this.sourceImage_ ? this.sourceImage_.getPixelRatio() : 1; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; - - /** - * @private - * @type {goog.events.Key} - */ - this.sourceListenerKey_ = null; - - - var state = ol.ImageState.LOADED; - var attributions = []; - - if (this.sourceImage_) { - state = ol.ImageState.IDLE; - attributions = this.sourceImage_.getAttributions(); - } - - goog.base(this, targetExtent, targetResolution, this.sourcePixelRatio_, - state, attributions); -}; -goog.inherits(ol.reproj.Image, ol.ImageBase); - - -/** - * @inheritDoc - */ -ol.reproj.Image.prototype.disposeInternal = function() { - if (this.state == ol.ImageState.LOADING) { - this.unlistenSource_(); - } - goog.base(this, 'disposeInternal'); -}; - - -/** - * @inheritDoc - */ -ol.reproj.Image.prototype.getImage = function(opt_context) { - return this.canvas_; -}; - - -/** - * @return {ol.proj.Projection} Projection. - */ -ol.reproj.Image.prototype.getProjection = function() { - return this.targetProj_; -}; - - -/** - * @private - */ -ol.reproj.Image.prototype.reproject_ = function() { - var sourceState = this.sourceImage_.getState(); - if (sourceState == ol.ImageState.LOADED) { - var width = ol.extent.getWidth(this.targetExtent_) / this.targetResolution_; - var height = - ol.extent.getHeight(this.targetExtent_) / this.targetResolution_; - - this.canvas_ = ol.reproj.render(width, height, this.sourcePixelRatio_, - this.sourceImage_.getResolution(), this.maxSourceExtent_, - this.targetResolution_, this.targetExtent_, this.triangulation_, [{ - extent: this.sourceImage_.getExtent(), - image: this.sourceImage_.getImage() - }]); - } - this.state = sourceState; - this.changed(); -}; - - -/** - * @inheritDoc - */ -ol.reproj.Image.prototype.load = function() { - if (this.state == ol.ImageState.IDLE) { - this.state = ol.ImageState.LOADING; - this.changed(); - - var sourceState = this.sourceImage_.getState(); - if (sourceState == ol.ImageState.LOADED || - sourceState == ol.ImageState.ERROR) { - this.reproject_(); - } else { - this.sourceListenerKey_ = this.sourceImage_.listen( - goog.events.EventType.CHANGE, function(e) { - var sourceState = this.sourceImage_.getState(); - if (sourceState == ol.ImageState.LOADED || - sourceState == ol.ImageState.ERROR) { - this.unlistenSource_(); - this.reproject_(); - } - }, false, this); - this.sourceImage_.load(); - } - } -}; - - -/** - * @private - */ -ol.reproj.Image.prototype.unlistenSource_ = function() { - goog.asserts.assert(this.sourceListenerKey_, - 'this.sourceListenerKey_ should not be null'); - goog.events.unlistenByKey(this.sourceListenerKey_); - this.sourceListenerKey_ = null; -}; - -goog.provide('ol.source.Image'); -goog.provide('ol.source.ImageEvent'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events.Event'); -goog.require('ol.Attribution'); -goog.require('ol.ImageState'); -goog.require('ol.array'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.reproj.Image'); -goog.require('ol.source.Source'); - - -/** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * extent: (null|ol.Extent|undefined), - * logo: (string|olx.LogoOptions|undefined), - * projection: ol.proj.ProjectionLike, - * resolutions: (Array.<number>|undefined), - * state: (ol.source.State|undefined)}} - */ -ol.source.ImageOptions; - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for sources providing a single image. - * - * @constructor - * @extends {ol.source.Source} - * @param {ol.source.ImageOptions} options Single image source options. - * @api - */ -ol.source.Image = function(options) { - - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection, - state: options.state - }); - - /** - * @private - * @type {Array.<number>} - */ - this.resolutions_ = options.resolutions !== undefined ? - options.resolutions : null; - goog.asserts.assert(!this.resolutions_ || - goog.array.isSorted(this.resolutions_, - function(a, b) { - return b - a; - }, true), 'resolutions must be null or sorted in descending order'); - - - /** - * @private - * @type {ol.reproj.Image} - */ - this.reprojectedImage_ = null; - - - /** - * @private - * @type {number} - */ - this.reprojectedRevision_ = 0; - -}; -goog.inherits(ol.source.Image, ol.source.Source); - - -/** - * @return {Array.<number>} Resolutions. - */ -ol.source.Image.prototype.getResolutions = function() { - return this.resolutions_; -}; - - -/** - * @protected - * @param {number} resolution Resolution. - * @return {number} Resolution. - */ -ol.source.Image.prototype.findNearestResolution = - function(resolution) { - if (this.resolutions_) { - var idx = ol.array.linearFindNearest(this.resolutions_, resolution, 0); - resolution = this.resolutions_[idx]; - } - return resolution; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.ImageBase} Single image. - */ -ol.source.Image.prototype.getImage = - function(extent, resolution, pixelRatio, projection) { - var sourceProjection = this.getProjection(); - if (!ol.ENABLE_RASTER_REPROJECTION || - !sourceProjection || - !projection || - ol.proj.equivalent(sourceProjection, projection)) { - if (sourceProjection) { - projection = sourceProjection; - } - return this.getImageInternal(extent, resolution, pixelRatio, projection); - } else { - if (this.reprojectedImage_) { - if (this.reprojectedRevision_ == this.getRevision() && - ol.proj.equivalent( - this.reprojectedImage_.getProjection(), projection) && - this.reprojectedImage_.getResolution() == resolution && - this.reprojectedImage_.getPixelRatio() == pixelRatio && - ol.extent.equals(this.reprojectedImage_.getExtent(), extent)) { - return this.reprojectedImage_; - } - this.reprojectedImage_.dispose(); - this.reprojectedImage_ = null; - } - - this.reprojectedImage_ = new ol.reproj.Image( - sourceProjection, projection, extent, resolution, pixelRatio, - goog.bind(function(extent, resolution, pixelRatio) { - return this.getImageInternal(extent, resolution, - pixelRatio, sourceProjection); - }, this)); - this.reprojectedRevision_ = this.getRevision(); - - return this.reprojectedImage_; - } -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.ImageBase} Single image. - * @protected - */ -ol.source.Image.prototype.getImageInternal = goog.abstractMethod; - - -/** - * Handle image change events. - * @param {goog.events.Event} event Event. - * @protected - */ -ol.source.Image.prototype.handleImageChange = function(event) { - var image = /** @type {ol.Image} */ (event.target); - switch (image.getState()) { - case ol.ImageState.LOADING: - this.dispatchEvent( - new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADSTART, - image)); - break; - case ol.ImageState.LOADED: - this.dispatchEvent( - new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADEND, - image)); - break; - case ol.ImageState.ERROR: - this.dispatchEvent( - new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADERROR, - image)); - break; - } -}; - - -/** - * Default image load function for image sources that use ol.Image image - * instances. - * @param {ol.Image} image Image. - * @param {string} src Source. - */ -ol.source.Image.defaultImageLoadFunction = function(image, src) { - image.getImage().src = src; -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.source.Image} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.ImageEvent} - * @param {string} type Type. - * @param {ol.Image} image The image. - */ -ol.source.ImageEvent = function(type, image) { - - goog.base(this, type); - - /** - * The image related to the event. - * @type {ol.Image} - * @api - */ - this.image = image; - -}; -goog.inherits(ol.source.ImageEvent, goog.events.Event); - - -/** - * @enum {string} - */ -ol.source.ImageEventType = { - - /** - * Triggered when an image starts loading. - * @event ol.source.ImageEvent#imageloadstart - * @api - */ - IMAGELOADSTART: 'imageloadstart', - - /** - * Triggered when an image finishes loading. - * @event ol.source.ImageEvent#imageloadend - * @api - */ - IMAGELOADEND: 'imageloadend', - - /** - * Triggered if image loading results in an error. - * @event ol.source.ImageEvent#imageloaderror - * @api - */ - IMAGELOADERROR: 'imageloaderror' - -}; - -goog.provide('ol.source.ImageCanvas'); - -goog.require('ol.CanvasFunctionType'); -goog.require('ol.ImageCanvas'); -goog.require('ol.extent'); -goog.require('ol.source.Image'); - - - -/** - * @classdesc - * Base class for image sources where a canvas element is the image. - * - * @constructor - * @extends {ol.source.Image} - * @param {olx.source.ImageCanvasOptions} options - * @api - */ -ol.source.ImageCanvas = function(options) { - - goog.base(this, { - attributions: options.attributions, - logo: options.logo, - projection: options.projection, - resolutions: options.resolutions, - state: options.state !== undefined ? - /** @type {ol.source.State} */ (options.state) : undefined - }); - - /** - * @private - * @type {ol.CanvasFunctionType} - */ - this.canvasFunction_ = options.canvasFunction; - - /** - * @private - * @type {ol.ImageCanvas} - */ - this.canvas_ = null; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; - - /** - * @private - * @type {number} - */ - this.ratio_ = options.ratio !== undefined ? - options.ratio : 1.5; - -}; -goog.inherits(ol.source.ImageCanvas, ol.source.Image); - - -/** - * @inheritDoc - */ -ol.source.ImageCanvas.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - resolution = this.findNearestResolution(resolution); - - var canvas = this.canvas_; - if (canvas && - this.renderedRevision_ == this.getRevision() && - canvas.getResolution() == resolution && - canvas.getPixelRatio() == pixelRatio && - ol.extent.containsExtent(canvas.getExtent(), extent)) { - return canvas; - } - - extent = extent.slice(); - ol.extent.scaleFromCenter(extent, this.ratio_); - var width = ol.extent.getWidth(extent) / resolution; - var height = ol.extent.getHeight(extent) / resolution; - var size = [width * pixelRatio, height * pixelRatio]; - - var canvasElement = this.canvasFunction_( - extent, resolution, pixelRatio, size, projection); - if (canvasElement) { - canvas = new ol.ImageCanvas(extent, resolution, pixelRatio, - this.getAttributions(), canvasElement); - } - this.canvas_ = canvas; - this.renderedRevision_ = this.getRevision(); - - return canvas; -}; - -goog.provide('ol.Feature'); -goog.provide('ol.FeatureStyleFunction'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.geom.Geometry'); -goog.require('ol.style.Style'); - - - -/** - * @classdesc - * A vector object for geographic features with a geometry and other - * attribute properties, similar to the features in vector file formats like - * GeoJSON. - * - * Features can be styled individually with `setStyle`; otherwise they use the - * style of their vector layer. - * - * Note that attribute properties are set as {@link ol.Object} properties on - * the feature object, so they are observable, and have get/set accessors. - * - * Typically, a feature has a single geometry property. You can set the - * geometry using the `setGeometry` method and get it with `getGeometry`. - * It is possible to store more than one geometry on a feature using attribute - * properties. By default, the geometry used for rendering is identified by - * the property name `geometry`. If you want to use another geometry property - * for rendering, use the `setGeometryName` method to change the attribute - * property associated with the geometry for the feature. For example: - * - * ```js - * var feature = new ol.Feature({ - * geometry: new ol.geom.Polygon(polyCoords), - * labelPoint: new ol.geom.Point(labelCoords), - * name: 'My Polygon' - * }); - * - * // get the polygon geometry - * var poly = feature.getGeometry(); - * - * // Render the feature as a point using the coordinates from labelPoint - * feature.setGeometryName('labelPoint'); - * - * // get the point geometry - * var point = feature.getGeometry(); - * ``` - * - * @constructor - * @extends {ol.Object} - * @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties - * You may pass a Geometry object directly, or an object literal - * containing properties. If you pass an object literal, you may - * include a Geometry associated with a `geometry` key. - * @api stable - */ -ol.Feature = function(opt_geometryOrProperties) { - - goog.base(this); - - /** - * @private - * @type {number|string|undefined} - */ - this.id_ = undefined; - - /** - * @type {string} - * @private - */ - this.geometryName_ = 'geometry'; - - /** - * User provided style. - * @private - * @type {ol.style.Style|Array.<ol.style.Style>| - * ol.FeatureStyleFunction} - */ - this.style_ = null; - - /** - * @private - * @type {ol.FeatureStyleFunction|undefined} - */ - this.styleFunction_ = undefined; - - /** - * @private - * @type {goog.events.Key} - */ - this.geometryChangeKey_ = null; - - goog.events.listen( - this, ol.Object.getChangeEventType(this.geometryName_), - this.handleGeometryChanged_, false, this); - - if (opt_geometryOrProperties !== undefined) { - if (opt_geometryOrProperties instanceof ol.geom.Geometry || - !opt_geometryOrProperties) { - var geometry = /** @type {ol.geom.Geometry} */ (opt_geometryOrProperties); - this.setGeometry(geometry); - } else { - goog.asserts.assert(goog.isObject(opt_geometryOrProperties), - 'opt_geometryOrProperties should be an Object'); - var properties = /** @type {Object.<string, *>} */ - (opt_geometryOrProperties); - this.setProperties(properties); - } - } -}; -goog.inherits(ol.Feature, ol.Object); - - -/** - * Clone this feature. If the original feature has a geometry it - * is also cloned. The feature id is not set in the clone. - * @return {ol.Feature} The clone. - * @api stable - */ -ol.Feature.prototype.clone = function() { - var clone = new ol.Feature(this.getProperties()); - clone.setGeometryName(this.getGeometryName()); - var geometry = this.getGeometry(); - if (geometry) { - clone.setGeometry(geometry.clone()); - } - var style = this.getStyle(); - if (style) { - clone.setStyle(style); - } - return clone; -}; - - -/** - * Get the feature's default geometry. A feature may have any number of named - * geometries. The "default" geometry (the one that is rendered by default) is - * set when calling {@link ol.Feature#setGeometry}. - * @return {ol.geom.Geometry|undefined} The default geometry for the feature. - * @api stable - * @observable - */ -ol.Feature.prototype.getGeometry = function() { - return /** @type {ol.geom.Geometry|undefined} */ ( - this.get(this.geometryName_)); -}; - - -/** - * Get the feature identifier. This is a stable identifier for the feature and - * is either set when reading data from a remote source or set explicitly by - * calling {@link ol.Feature#setId}. - * @return {number|string|undefined} Id. - * @api stable - * @observable - */ -ol.Feature.prototype.getId = function() { - return this.id_; -}; - - -/** - * Get the name of the feature's default geometry. By default, the default - * geometry is named `geometry`. - * @return {string} Get the property name associated with the default geometry - * for this feature. - * @api stable - */ -ol.Feature.prototype.getGeometryName = function() { - return this.geometryName_; -}; - - -/** - * Get the feature's style. This return for this method depends on what was - * provided to the {@link ol.Feature#setStyle} method. - * @return {ol.style.Style|Array.<ol.style.Style>| - * ol.FeatureStyleFunction} The feature style. - * @api stable - * @observable - */ -ol.Feature.prototype.getStyle = function() { - return this.style_; -}; - - -/** - * Get the feature's style function. - * @return {ol.FeatureStyleFunction|undefined} Return a function - * representing the current style of this feature. - * @api stable - */ -ol.Feature.prototype.getStyleFunction = function() { - return this.styleFunction_; -}; - - -/** - * @private - */ -ol.Feature.prototype.handleGeometryChange_ = function() { - this.changed(); -}; - - -/** - * @private - */ -ol.Feature.prototype.handleGeometryChanged_ = function() { - if (this.geometryChangeKey_) { - goog.events.unlistenByKey(this.geometryChangeKey_); - this.geometryChangeKey_ = null; - } - var geometry = this.getGeometry(); - if (geometry) { - this.geometryChangeKey_ = goog.events.listen(geometry, - goog.events.EventType.CHANGE, this.handleGeometryChange_, false, this); - } - this.changed(); -}; - - -/** - * Set the default geometry for the feature. This will update the property - * with the name returned by {@link ol.Feature#getGeometryName}. - * @param {ol.geom.Geometry|undefined} geometry The new geometry. - * @api stable - * @observable - */ -ol.Feature.prototype.setGeometry = function(geometry) { - this.set(this.geometryName_, geometry); -}; - - -/** - * Set the style for the feature. This can be a single style object, an array - * of styles, or a function that takes a resolution and returns an array of - * styles. If it is `null` the feature has no style (a `null` style). - * @param {ol.style.Style|Array.<ol.style.Style>| - * ol.FeatureStyleFunction} style Style for this feature. - * @api stable - * @observable - */ -ol.Feature.prototype.setStyle = function(style) { - this.style_ = style; - this.styleFunction_ = !style ? - undefined : ol.Feature.createStyleFunction(style); - this.changed(); -}; - - -/** - * Set the feature id. The feature id is considered stable and may be used when - * requesting features or comparing identifiers returned from a remote source. - * The feature id can be used with the {@link ol.source.Vector#getFeatureById} - * method. - * @param {number|string|undefined} id The feature id. - * @api stable - * @observable - */ -ol.Feature.prototype.setId = function(id) { - this.id_ = id; - this.changed(); -}; - - -/** - * Set the property name to be used when getting the feature's default geometry. - * When calling {@link ol.Feature#getGeometry}, the value of the property with - * this name will be returned. - * @param {string} name The property name of the default geometry. - * @api stable - */ -ol.Feature.prototype.setGeometryName = function(name) { - goog.events.unlisten( - this, ol.Object.getChangeEventType(this.geometryName_), - this.handleGeometryChanged_, false, this); - this.geometryName_ = name; - goog.events.listen( - this, ol.Object.getChangeEventType(this.geometryName_), - this.handleGeometryChanged_, false, this); - this.handleGeometryChanged_(); -}; - - -/** - * A function that returns an array of {@link ol.style.Style styles} given a - * resolution. The `this` keyword inside the function references the - * {@link ol.Feature} to be styled. - * - * @typedef {function(this: ol.Feature, number): - * (ol.style.Style|Array.<ol.style.Style>)} - * @api stable - */ -ol.FeatureStyleFunction; - - -/** - * Convert the provided object into a feature style function. Functions passed - * through unchanged. Arrays of ol.style.Style or single style objects wrapped - * in a new feature style function. - * @param {ol.FeatureStyleFunction|!Array.<ol.style.Style>|!ol.style.Style} obj - * A feature style function, a single style, or an array of styles. - * @return {ol.FeatureStyleFunction} A style function. - */ -ol.Feature.createStyleFunction = function(obj) { - var styleFunction; - - if (goog.isFunction(obj)) { - styleFunction = obj; - } else { - /** - * @type {Array.<ol.style.Style>} - */ - var styles; - if (goog.isArray(obj)) { - styles = obj; - } else { - goog.asserts.assertInstanceof(obj, ol.style.Style, - 'obj should be an ol.style.Style'); - styles = [obj]; - } - styleFunction = function() { - return styles; - }; - } - return styleFunction; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Common events for the network classes. - */ - - -goog.provide('goog.net.EventType'); - - -/** - * Event names for network events - * @enum {string} - */ -goog.net.EventType = { - COMPLETE: 'complete', - SUCCESS: 'success', - ERROR: 'error', - ABORT: 'abort', - READY: 'ready', - READY_STATE_CHANGE: 'readystatechange', - TIMEOUT: 'timeout', - INCREMENTAL_DATA: 'incrementaldata', - PROGRESS: 'progress' -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.Thenable'); - - - -/** - * Provides a more strict interface for Thenables in terms of - * http://promisesaplus.com for interop with {@see goog.Promise}. - * - * @interface - * @extends {IThenable<TYPE>} - * @template TYPE - */ -goog.Thenable = function() {}; - - -/** - * Adds callbacks that will operate on the result of the Thenable, returning a - * new child Promise. - * - * If the Thenable is fulfilled, the {@code onFulfilled} callback will be - * invoked with the fulfillment value as argument, and the child Promise will - * be fulfilled with the return value of the callback. If the callback throws - * an exception, the child Promise will be rejected with the thrown value - * instead. - * - * If the Thenable is rejected, the {@code onRejected} callback will be invoked - * with the rejection reason as argument, and the child Promise will be rejected - * with the return value of the callback or thrown value. - * - * @param {?(function(this:THIS, TYPE): VALUE)=} opt_onFulfilled A - * function that will be invoked with the fulfillment value if the Promise - * is fullfilled. - * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will - * be invoked with the rejection reason if the Promise is rejected. - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * with the default this. - * - * @return {RESULT} A new Promise that will receive the result - * of the fulfillment or rejection callback. - * @template VALUE - * @template THIS - * - * When a Promise (or thenable) is returned from the fulfilled callback, - * the result is the payload of that promise, not the promise itself. - * - * @template RESULT := type('goog.Promise', - * cond(isUnknown(VALUE), unknown(), - * mapunion(VALUE, (V) => - * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), - * templateTypeOf(V, 0), - * cond(sub(V, 'Thenable'), - * unknown(), - * V))))) - * =: - * - */ -goog.Thenable.prototype.then = function(opt_onFulfilled, opt_onRejected, - opt_context) {}; - - -/** - * An expando property to indicate that an object implements - * {@code goog.Thenable}. - * - * {@see addImplementation}. - * - * @const - */ -goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable'; - - -/** - * Marks a given class (constructor) as an implementation of Thenable, so - * that we can query that fact at runtime. The class must have already - * implemented the interface. - * Exports a 'then' method on the constructor prototype, so that the objects - * also implement the extern {@see goog.Thenable} interface for interop with - * other Promise implementations. - * @param {function(new:goog.Thenable,...?)} ctor The class constructor. The - * corresponding class must have already implemented the interface. - */ -goog.Thenable.addImplementation = function(ctor) { - goog.exportProperty(ctor.prototype, 'then', ctor.prototype.then); - if (COMPILED) { - ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true; - } else { - // Avoids dictionary access in uncompiled mode. - ctor.prototype.$goog_Thenable = true; - } -}; - - -/** - * @param {*} object - * @return {boolean} Whether a given instance implements {@code goog.Thenable}. - * The class/superclass of the instance must call {@code addImplementation}. - */ -goog.Thenable.isImplementedBy = function(object) { - if (!object) { - return false; - } - try { - if (COMPILED) { - return !!object[goog.Thenable.IMPLEMENTED_BY_PROP]; - } - return !!object.$goog_Thenable; - } catch (e) { - // Property access seems to be forbidden. - return false; - } -}; - -// Copyright 2015 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Simple freelist. - * - * An anterative to goog.structs.SimplePool, it imposes the requirement that the - * objects in the list contain a "next" property that can be used to maintain - * the pool. - */ - -goog.provide('goog.async.FreeList'); - - -/** - * @template ITEM - */ -goog.async.FreeList = goog.defineClass(null, { - /** - * @param {function():ITEM} create - * @param {function(ITEM):void} reset - * @param {number} limit - */ - constructor: function(create, reset, limit) { - /** @const {number} */ - this.limit_ = limit; - /** @const {function()} */ - this.create_ = create; - /** @const {function(ITEM):void} */ - this.reset_ = reset; - - /** @type {number} */ - this.occupants_ = 0; - /** @type {ITEM} */ - this.head_ = null; - }, - - /** - * @return {ITEM} - */ - get: function() { - var item; - if (this.occupants_ > 0) { - this.occupants_--; - item = this.head_; - this.head_ = item.next; - item.next = null; - } else { - item = this.create_(); - } - return item; - }, - - /** - * @param {ITEM} item An item available for possible future reuse. - */ - put: function(item) { - this.reset_(item); - if (this.occupants_ < this.limit_) { - this.occupants_++; - item.next = this.head_; - this.head_ = item; - } - }, - - /** - * Visible for testing. - * @package - * @return {number} - */ - occupants: function() { - return this.occupants_; - } -}); - - - - -// Copyright 2015 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.async.WorkItem'); -goog.provide('goog.async.WorkQueue'); - -goog.require('goog.asserts'); -goog.require('goog.async.FreeList'); - - -// TODO(johnlenz): generalize the WorkQueue if this is used by more -// than goog.async.run. - - - -/** - * A low GC workqueue. The key elements of this design: - * - avoids the need for goog.bind or equivalent by carrying scope - * - avoids the need for array reallocation by using a linked list - * - minimizes work entry objects allocation by recycling objects - * @constructor - * @final - * @struct - */ -goog.async.WorkQueue = function() { - this.workHead_ = null; - this.workTail_ = null; -}; - - -/** @define {number} The maximum number of entries to keep for recycling. */ -goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100); - - -/** @const @private {goog.async.FreeList<goog.async.WorkItem>} */ -goog.async.WorkQueue.freelist_ = new goog.async.FreeList( - function() {return new goog.async.WorkItem(); }, - function(item) {item.reset()}, - goog.async.WorkQueue.DEFAULT_MAX_UNUSED); - - -/** - * @param {function()} fn - * @param {Object|null|undefined} scope - */ -goog.async.WorkQueue.prototype.add = function(fn, scope) { - var item = this.getUnusedItem_(); - item.set(fn, scope); - - if (this.workTail_) { - this.workTail_.next = item; - this.workTail_ = item; - } else { - goog.asserts.assert(!this.workHead_); - this.workHead_ = item; - this.workTail_ = item; - } -}; - - -/** - * @return {goog.async.WorkItem} - */ -goog.async.WorkQueue.prototype.remove = function() { - var item = null; - - if (this.workHead_) { - item = this.workHead_; - this.workHead_ = this.workHead_.next; - if (!this.workHead_) { - this.workTail_ = null; - } - item.next = null; - } - return item; -}; - - -/** - * @param {goog.async.WorkItem} item - */ -goog.async.WorkQueue.prototype.returnUnused = function(item) { - goog.async.WorkQueue.freelist_.put(item); -}; - - -/** - * @return {goog.async.WorkItem} - * @private - */ -goog.async.WorkQueue.prototype.getUnusedItem_ = function() { - return goog.async.WorkQueue.freelist_.get(); -}; - - - -/** - * @constructor - * @final - * @struct - */ -goog.async.WorkItem = function() { - /** @type {?function()} */ - this.fn = null; - /** @type {Object|null|undefined} */ - this.scope = null; - /** @type {?goog.async.WorkItem} */ - this.next = null; -}; - - -/** - * @param {function()} fn - * @param {Object|null|undefined} scope - */ -goog.async.WorkItem.prototype.set = function(fn, scope) { - this.fn = fn; - this.scope = scope; - this.next = null; -}; - - -/** Reset the work item so they don't prevent GC before reuse */ -goog.async.WorkItem.prototype.reset = function() { - this.fn = null; - this.scope = null; - this.next = null; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Simple notifiers for the Closure testing framework. - * - * @author johnlenz@google.com (John Lenz) - */ - -goog.provide('goog.testing.watchers'); - - -/** @private {!Array<function()>} */ -goog.testing.watchers.resetWatchers_ = []; - - -/** - * Fires clock reset watching functions. - */ -goog.testing.watchers.signalClockReset = function() { - var watchers = goog.testing.watchers.resetWatchers_; - for (var i = 0; i < watchers.length; i++) { - goog.testing.watchers.resetWatchers_[i](); - } -}; - - -/** - * Enqueues a function to be called when the clock used for setTimeout is reset. - * @param {function()} fn - */ -goog.testing.watchers.watchClockReset = function(fn) { - goog.testing.watchers.resetWatchers_.push(fn); -}; - - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.async.run'); - -goog.require('goog.async.WorkQueue'); -goog.require('goog.async.nextTick'); -goog.require('goog.async.throwException'); -goog.require('goog.testing.watchers'); - - -/** - * Fires the provided callback just before the current callstack unwinds, or as - * soon as possible after the current JS execution context. - * @param {function(this:THIS)} callback - * @param {THIS=} opt_context Object to use as the "this value" when calling - * the provided function. - * @template THIS - */ -goog.async.run = function(callback, opt_context) { - if (!goog.async.run.schedule_) { - goog.async.run.initializeRunner_(); - } - if (!goog.async.run.workQueueScheduled_) { - // Nothing is currently scheduled, schedule it now. - goog.async.run.schedule_(); - goog.async.run.workQueueScheduled_ = true; - } - - goog.async.run.workQueue_.add(callback, opt_context); -}; - - -/** - * Initializes the function to use to process the work queue. - * @private - */ -goog.async.run.initializeRunner_ = function() { - // If native Promises are available in the browser, just schedule the callback - // on a fulfilled promise, which is specified to be async, but as fast as - // possible. - if (goog.global.Promise && goog.global.Promise.resolve) { - var promise = goog.global.Promise.resolve(undefined); - goog.async.run.schedule_ = function() { - promise.then(goog.async.run.processWorkQueue); - }; - } else { - goog.async.run.schedule_ = function() { - goog.async.nextTick(goog.async.run.processWorkQueue); - }; - } -}; - - -/** - * Forces goog.async.run to use nextTick instead of Promise. - * - * This should only be done in unit tests. It's useful because MockClock - * replaces nextTick, but not the browser Promise implementation, so it allows - * Promise-based code to be tested with MockClock. - * - * However, we also want to run promises if the MockClock is no longer in - * control so we schedule a backup "setTimeout" to the unmocked timeout if - * provided. - * - * @param {function(function())=} opt_realSetTimeout - */ -goog.async.run.forceNextTick = function(opt_realSetTimeout) { - goog.async.run.schedule_ = function() { - goog.async.nextTick(goog.async.run.processWorkQueue); - if (opt_realSetTimeout) { - opt_realSetTimeout(goog.async.run.processWorkQueue); - } - }; -}; - - -/** - * The function used to schedule work asynchronousely. - * @private {function()} - */ -goog.async.run.schedule_; - - -/** @private {boolean} */ -goog.async.run.workQueueScheduled_ = false; - - -/** @private {!goog.async.WorkQueue} */ -goog.async.run.workQueue_ = new goog.async.WorkQueue(); - - -if (goog.DEBUG) { - /** - * Reset the work queue. - * @private - */ - goog.async.run.resetQueue_ = function() { - goog.async.run.workQueueScheduled_ = false; - goog.async.run.workQueue_ = new goog.async.WorkQueue(); - }; - - // If there is a clock implemenation in use for testing - // and it is reset, reset the queue. - goog.testing.watchers.watchClockReset(goog.async.run.resetQueue_); -} - - -/** - * Run any pending goog.async.run work items. This function is not intended - * for general use, but for use by entry point handlers to run items ahead of - * goog.async.nextTick. - */ -goog.async.run.processWorkQueue = function() { - // NOTE: additional work queue items may be added while processing. - var item = null; - while (item = goog.async.run.workQueue_.remove()) { - try { - item.fn.call(item.scope); - } catch (e) { - goog.async.throwException(e); - } - goog.async.run.workQueue_.returnUnused(item); - } - - // There are no more work items, allow processing to be scheduled again. - goog.async.run.workQueueScheduled_ = false; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.promise.Resolver'); - - - -/** - * Resolver interface for promises. The resolver is a convenience interface that - * bundles the promise and its associated resolve and reject functions together, - * for cases where the resolver needs to be persisted internally. - * - * @interface - * @template TYPE - */ -goog.promise.Resolver = function() {}; - - -/** - * The promise that created this resolver. - * @type {!goog.Promise<TYPE>} - */ -goog.promise.Resolver.prototype.promise; - - -/** - * Resolves this resolver with the specified value. - * @type {function((TYPE|goog.Promise<TYPE>|Thenable)=)} - */ -goog.promise.Resolver.prototype.resolve; - - -/** - * Rejects this resolver with the specified reason. - * @type {function(*=): void} - */ -goog.promise.Resolver.prototype.reject; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.Promise'); - -goog.require('goog.Thenable'); -goog.require('goog.asserts'); -goog.require('goog.async.FreeList'); -goog.require('goog.async.run'); -goog.require('goog.async.throwException'); -goog.require('goog.debug.Error'); -goog.require('goog.promise.Resolver'); - - - -/** - * Promises provide a result that may be resolved asynchronously. A Promise may - * be resolved by being fulfilled with a fulfillment value, rejected with a - * rejection reason, or blocked by another Promise. A Promise is said to be - * settled if it is either fulfilled or rejected. Once settled, the Promise - * result is immutable. - * - * Promises may represent results of any type, including undefined. Rejection - * reasons are typically Errors, but may also be of any type. Closure Promises - * allow for optional type annotations that enforce that fulfillment values are - * of the appropriate types at compile time. - * - * The result of a Promise is accessible by calling {@code then} and registering - * {@code onFulfilled} and {@code onRejected} callbacks. Once the Promise - * is settled, the relevant callbacks are invoked with the fulfillment value or - * rejection reason as argument. Callbacks are always invoked in the order they - * were registered, even when additional {@code then} calls are made from inside - * another callback. A callback is always run asynchronously sometime after the - * scope containing the registering {@code then} invocation has returned. - * - * If a Promise is resolved with another Promise, the first Promise will block - * until the second is settled, and then assumes the same result as the second - * Promise. This allows Promises to depend on the results of other Promises, - * linking together multiple asynchronous operations. - * - * This implementation is compatible with the Promises/A+ specification and - * passes that specification's conformance test suite. A Closure Promise may be - * resolved with a Promise instance (or sufficiently compatible Promise-like - * object) created by other Promise implementations. From the specification, - * Promise-like objects are known as "Thenables". - * - * @see http://promisesaplus.com/ - * - * @param {function( - * this:RESOLVER_CONTEXT, - * function((TYPE|IThenable<TYPE>|Thenable)=), - * function(*=)): void} resolver - * Initialization function that is invoked immediately with {@code resolve} - * and {@code reject} functions as arguments. The Promise is resolved or - * rejected with the first argument passed to either function. - * @param {RESOLVER_CONTEXT=} opt_context An optional context for executing the - * resolver function. If unspecified, the resolver function will be executed - * in the default scope. - * @constructor - * @struct - * @final - * @implements {goog.Thenable<TYPE>} - * @template TYPE,RESOLVER_CONTEXT - */ -goog.Promise = function(resolver, opt_context) { - /** - * The internal state of this Promise. Either PENDING, FULFILLED, REJECTED, or - * BLOCKED. - * @private {goog.Promise.State_} - */ - this.state_ = goog.Promise.State_.PENDING; - - /** - * The settled result of the Promise. Immutable once set with either a - * fulfillment value or rejection reason. - * @private {*} - */ - this.result_ = undefined; - - /** - * For Promises created by calling {@code then()}, the originating parent. - * @private {goog.Promise} - */ - this.parent_ = null; - - /** - * The linked list of {@code onFulfilled} and {@code onRejected} callbacks - * added to this Promise by calls to {@code then()}. - * @private {?goog.Promise.CallbackEntry_} - */ - this.callbackEntries_ = null; - - /** - * The tail of the linked list of {@code onFulfilled} and {@code onRejected} - * callbacks added to this Promise by calls to {@code then()}. - * @private {?goog.Promise.CallbackEntry_} - */ - this.callbackEntriesTail_ = null; - - /** - * Whether the Promise is in the queue of Promises to execute. - * @private {boolean} - */ - this.executing_ = false; - - if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { - /** - * A timeout ID used when the {@code UNHANDLED_REJECTION_DELAY} is greater - * than 0 milliseconds. The ID is set when the Promise is rejected, and - * cleared only if an {@code onRejected} callback is invoked for the - * Promise (or one of its descendants) before the delay is exceeded. - * - * If the rejection is not handled before the timeout completes, the - * rejection reason is passed to the unhandled rejection handler. - * @private {number} - */ - this.unhandledRejectionId_ = 0; - } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { - /** - * When the {@code UNHANDLED_REJECTION_DELAY} is set to 0 milliseconds, a - * boolean that is set if the Promise is rejected, and reset to false if an - * {@code onRejected} callback is invoked for the Promise (or one of its - * descendants). If the rejection is not handled before the next timestep, - * the rejection reason is passed to the unhandled rejection handler. - * @private {boolean} - */ - this.hadUnhandledRejection_ = false; - } - - if (goog.Promise.LONG_STACK_TRACES) { - /** - * A list of stack trace frames pointing to the locations where this Promise - * was created or had callbacks added to it. Saved to add additional context - * to stack traces when an exception is thrown. - * @private {!Array<string>} - */ - this.stack_ = []; - this.addStackTrace_(new Error('created')); - - /** - * Index of the most recently executed stack frame entry. - * @private {number} - */ - this.currentStep_ = 0; - } - - // As an optimization, we can skip this if resolver is goog.nullFunction. - // This value is passed internally when creating a promise which will be - // resolved through a more optimized path. - if (resolver != goog.nullFunction) { - try { - var self = this; - resolver.call( - opt_context, - function(value) { - self.resolve_(goog.Promise.State_.FULFILLED, value); - }, - function(reason) { - if (goog.DEBUG && - !(reason instanceof goog.Promise.CancellationError)) { - try { - // Promise was rejected. Step up one call frame to see why. - if (reason instanceof Error) { - throw reason; - } else { - throw new Error('Promise rejected.'); - } - } catch (e) { - // Only thrown so browser dev tools can catch rejections of - // promises when the option to break on caught exceptions is - // activated. - } - } - self.resolve_(goog.Promise.State_.REJECTED, reason); - }); - } catch (e) { - this.resolve_(goog.Promise.State_.REJECTED, e); - } - } -}; - - -/** - * @define {boolean} Whether traces of {@code then} calls should be included in - * exceptions thrown - */ -goog.define('goog.Promise.LONG_STACK_TRACES', false); - - -/** - * @define {number} The delay in milliseconds before a rejected Promise's reason - * is passed to the rejection handler. By default, the rejection handler - * rethrows the rejection reason so that it appears in the developer console or - * {@code window.onerror} handler. - * - * Rejections are rethrown as quickly as possible by default. A negative value - * disables rejection handling entirely. - */ -goog.define('goog.Promise.UNHANDLED_REJECTION_DELAY', 0); - - -/** - * The possible internal states for a Promise. These states are not directly - * observable to external callers. - * @enum {number} - * @private - */ -goog.Promise.State_ = { - /** The Promise is waiting for resolution. */ - PENDING: 0, - - /** The Promise is blocked waiting for the result of another Thenable. */ - BLOCKED: 1, - - /** The Promise has been resolved with a fulfillment value. */ - FULFILLED: 2, - - /** The Promise has been resolved with a rejection reason. */ - REJECTED: 3 -}; - - - -/** - * Entries in the callback chain. Each call to {@code then}, - * {@code thenCatch}, or {@code thenAlways} creates an entry containing the - * functions that may be invoked once the Promise is settled. - * - * @private @final @struct @constructor - */ -goog.Promise.CallbackEntry_ = function() { - /** @type {?goog.Promise} */ - this.child = null; - /** @type {Function} */ - this.onFulfilled = null; - /** @type {Function} */ - this.onRejected = null; - /** @type {?} */ - this.context = null; - /** @type {?goog.Promise.CallbackEntry_} */ - this.next = null; - - /** - * A boolean value to indicate this is a "thenAlways" callback entry. - * Unlike a normal "then/thenVoid" a "thenAlways doesn't participate - * in "cancel" considerations but is simply an observer and requires - * special handling. - * @type {boolean} - */ - this.always = false; -}; - - -/** clear the object prior to reuse */ -goog.Promise.CallbackEntry_.prototype.reset = function() { - this.child = null; - this.onFulfilled = null; - this.onRejected = null; - this.context = null; - this.always = false; -}; - - -/** - * @define {number} The number of currently unused objects to keep around for - * reuse. - */ -goog.define('goog.Promise.DEFAULT_MAX_UNUSED', 100); - - -/** @const @private {goog.async.FreeList<!goog.Promise.CallbackEntry_>} */ -goog.Promise.freelist_ = new goog.async.FreeList( - function() { - return new goog.Promise.CallbackEntry_(); - }, - function(item) { - item.reset(); - }, - goog.Promise.DEFAULT_MAX_UNUSED); - - -/** - * @param {Function} onFulfilled - * @param {Function} onRejected - * @param {?} context - * @return {!goog.Promise.CallbackEntry_} - * @private - */ -goog.Promise.getCallbackEntry_ = function(onFulfilled, onRejected, context) { - var entry = goog.Promise.freelist_.get(); - entry.onFulfilled = onFulfilled; - entry.onRejected = onRejected; - entry.context = context; - return entry; -}; - - -/** - * @param {!goog.Promise.CallbackEntry_} entry - * @private - */ -goog.Promise.returnEntry_ = function(entry) { - goog.Promise.freelist_.put(entry); -}; - - -// NOTE: this is the same template expression as is used for -// goog.IThenable.prototype.then - - -/** - * @param {VALUE=} opt_value - * @return {RESULT} A new Promise that is immediately resolved - * with the given value. If the input value is already a goog.Promise, it - * will be returned immediately without creating a new instance. - * @template VALUE - * @template RESULT := type('goog.Promise', - * cond(isUnknown(VALUE), unknown(), - * mapunion(VALUE, (V) => - * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), - * templateTypeOf(V, 0), - * cond(sub(V, 'Thenable'), - * unknown(), - * V))))) - * =: - */ -goog.Promise.resolve = function(opt_value) { - if (opt_value instanceof goog.Promise) { - // Avoid creating a new object if we already have a promise object - // of the correct type. - return opt_value; - } - - // Passing goog.nullFunction will cause the constructor to take an optimized - // path that skips calling the resolver function. - var promise = new goog.Promise(goog.nullFunction); - promise.resolve_(goog.Promise.State_.FULFILLED, opt_value); - return promise; -}; - - -/** - * @param {*=} opt_reason - * @return {!goog.Promise} A new Promise that is immediately rejected with the - * given reason. - */ -goog.Promise.reject = function(opt_reason) { - return new goog.Promise(function(resolve, reject) { - reject(opt_reason); - }); -}; - - -/** - * This is identical to - * {@code goog.Promise.resolve(value).then(onFulfilled, onRejected)}, but it - * avoids creating an unnecessary wrapper Promise when {@code value} is already - * thenable. - * - * @param {?(goog.Thenable<TYPE>|Thenable|TYPE)} value - * @param {function(TYPE): ?} onFulfilled - * @param {function(*): *} onRejected - * @template TYPE - * @private - */ -goog.Promise.resolveThen_ = function(value, onFulfilled, onRejected) { - var isThenable = goog.Promise.maybeThen_( - value, onFulfilled, onRejected, null); - if (!isThenable) { - goog.async.run(goog.partial(onFulfilled, value)); - } -}; - - -/** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<TYPE>} A Promise that receives the result of the - * first Promise (or Promise-like) input to settle immediately after it - * settles. - * @template TYPE - */ -goog.Promise.race = function(promises) { - return new goog.Promise(function(resolve, reject) { - if (!promises.length) { - resolve(undefined); - } - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_(promise, resolve, reject); - } - }); -}; - - -/** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<!Array<TYPE>>} A Promise that receives a list of - * every fulfilled value once every input Promise (or Promise-like) is - * successfully fulfilled, or is rejected with the first rejection reason - * immediately after it is rejected. - * @template TYPE - */ -goog.Promise.all = function(promises) { - return new goog.Promise(function(resolve, reject) { - var toFulfill = promises.length; - var values = []; - - if (!toFulfill) { - resolve(values); - return; - } - - var onFulfill = function(index, value) { - toFulfill--; - values[index] = value; - if (toFulfill == 0) { - resolve(values); - } - }; - - var onReject = function(reason) { - reject(reason); - }; - - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_( - promise, goog.partial(onFulfill, i), onReject); - } - }); -}; - - -/** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<!Array<{ - * fulfilled: boolean, - * value: (TYPE|undefined), - * reason: (*|undefined)}>>} A Promise that resolves with a list of - * result objects once all input Promises (or Promise-like) have - * settled. Each result object contains a 'fulfilled' boolean indicating - * whether an input Promise was fulfilled or rejected. For fulfilled - * Promises, the resulting value is stored in the 'value' field. For - * rejected Promises, the rejection reason is stored in the 'reason' - * field. - * @template TYPE - */ -goog.Promise.allSettled = function(promises) { - return new goog.Promise(function(resolve, reject) { - var toSettle = promises.length; - var results = []; - - if (!toSettle) { - resolve(results); - return; - } - - var onSettled = function(index, fulfilled, result) { - toSettle--; - results[index] = fulfilled ? - {fulfilled: true, value: result} : - {fulfilled: false, reason: result}; - if (toSettle == 0) { - resolve(results); - } - }; - - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_(promise, - goog.partial(onSettled, i, true /* fulfilled */), - goog.partial(onSettled, i, false /* fulfilled */)); - } - }); -}; - - -/** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<TYPE>} A Promise that receives the value of the first - * input to be fulfilled, or is rejected with a list of every rejection - * reason if all inputs are rejected. - * @template TYPE - */ -goog.Promise.firstFulfilled = function(promises) { - return new goog.Promise(function(resolve, reject) { - var toReject = promises.length; - var reasons = []; - - if (!toReject) { - resolve(undefined); - return; - } - - var onFulfill = function(value) { - resolve(value); - }; - - var onReject = function(index, reason) { - toReject--; - reasons[index] = reason; - if (toReject == 0) { - reject(reasons); - } - }; - - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_( - promise, onFulfill, goog.partial(onReject, i)); - } - }); -}; - - -/** - * @return {!goog.promise.Resolver<TYPE>} Resolver wrapping the promise and its - * resolve / reject functions. Resolving or rejecting the resolver - * resolves or rejects the promise. - * @template TYPE - */ -goog.Promise.withResolver = function() { - var resolve, reject; - var promise = new goog.Promise(function(rs, rj) { - resolve = rs; - reject = rj; - }); - return new goog.Promise.Resolver_(promise, resolve, reject); -}; - - -/** - * Adds callbacks that will operate on the result of the Promise, returning a - * new child Promise. - * - * If the Promise is fulfilled, the {@code onFulfilled} callback will be invoked - * with the fulfillment value as argument, and the child Promise will be - * fulfilled with the return value of the callback. If the callback throws an - * exception, the child Promise will be rejected with the thrown value instead. - * - * If the Promise is rejected, the {@code onRejected} callback will be invoked - * with the rejection reason as argument, and the child Promise will be resolved - * with the return value or rejected with the thrown value of the callback. - * - * @override - */ -goog.Promise.prototype.then = function( - opt_onFulfilled, opt_onRejected, opt_context) { - - if (opt_onFulfilled != null) { - goog.asserts.assertFunction(opt_onFulfilled, - 'opt_onFulfilled should be a function.'); - } - if (opt_onRejected != null) { - goog.asserts.assertFunction(opt_onRejected, - 'opt_onRejected should be a function. Did you pass opt_context ' + - 'as the second argument instead of the third?'); - } - - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('then')); - } - - return this.addChildPromise_( - goog.isFunction(opt_onFulfilled) ? opt_onFulfilled : null, - goog.isFunction(opt_onRejected) ? opt_onRejected : null, - opt_context); -}; -goog.Thenable.addImplementation(goog.Promise); - - -/** - * Adds callbacks that will operate on the result of the Promise without - * returning a child Promise (unlike "then"). - * - * If the Promise is fulfilled, the {@code onFulfilled} callback will be invoked - * with the fulfillment value as argument. - * - * If the Promise is rejected, the {@code onRejected} callback will be invoked - * with the rejection reason as argument. - * - * @param {?(function(this:THIS, TYPE):?)=} opt_onFulfilled A - * function that will be invoked with the fulfillment value if the Promise - * is fulfilled. - * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will - * be invoked with the rejection reason if the Promise is rejected. - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * with the default this. - * @package - * @template THIS - */ -goog.Promise.prototype.thenVoid = function( - opt_onFulfilled, opt_onRejected, opt_context) { - - if (opt_onFulfilled != null) { - goog.asserts.assertFunction(opt_onFulfilled, - 'opt_onFulfilled should be a function.'); - } - if (opt_onRejected != null) { - goog.asserts.assertFunction(opt_onRejected, - 'opt_onRejected should be a function. Did you pass opt_context ' + - 'as the second argument instead of the third?'); - } - - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('then')); - } - - // Note: no default rejection handler is provided here as we need to - // distinguish unhandled rejections. - this.addCallbackEntry_(goog.Promise.getCallbackEntry_( - opt_onFulfilled || goog.nullFunction, - opt_onRejected || null, - opt_context)); -}; - - -/** - * Adds a callback that will be invoked when the Promise is settled (fulfilled - * or rejected). The callback receives no argument, and no new child Promise is - * created. This is useful for ensuring that cleanup takes place after certain - * asynchronous operations. Callbacks added with {@code thenAlways} will be - * executed in the same order with other calls to {@code then}, - * {@code thenAlways}, or {@code thenCatch}. - * - * Since it does not produce a new child Promise, cancellation propagation is - * not prevented by adding callbacks with {@code thenAlways}. A Promise that has - * a cleanup handler added with {@code thenAlways} will be canceled if all of - * its children created by {@code then} (or {@code thenCatch}) are canceled. - * Additionally, since any rejections are not passed to the callback, it does - * not stop the unhandled rejection handler from running. - * - * @param {function(this:THIS): void} onSettled A function that will be invoked - * when the Promise is settled (fulfilled or rejected). - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * in the global scope. - * @return {!goog.Promise<TYPE>} This Promise, for chaining additional calls. - * @template THIS - */ -goog.Promise.prototype.thenAlways = function(onSettled, opt_context) { - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('thenAlways')); - } - - var entry = goog.Promise.getCallbackEntry_(onSettled, onSettled, opt_context); - entry.always = true; - this.addCallbackEntry_(entry); - return this; -}; - - -/** - * Adds a callback that will be invoked only if the Promise is rejected. This - * is equivalent to {@code then(null, onRejected)}. - * - * @param {!function(this:THIS, *): *} onRejected A function that will be - * invoked with the rejection reason if the Promise is rejected. - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * in the global scope. - * @return {!goog.Promise} A new Promise that will receive the result of the - * callback. - * @template THIS - */ -goog.Promise.prototype.thenCatch = function(onRejected, opt_context) { - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('thenCatch')); - } - return this.addChildPromise_(null, onRejected, opt_context); -}; - - -/** - * Cancels the Promise if it is still pending by rejecting it with a cancel - * Error. No action is performed if the Promise is already resolved. - * - * All child Promises of the canceled Promise will be rejected with the same - * cancel error, as with normal Promise rejection. If the Promise to be canceled - * is the only child of a pending Promise, the parent Promise will also be - * canceled. Cancellation may propagate upward through multiple generations. - * - * @param {string=} opt_message An optional debugging message for describing the - * cancellation reason. - */ -goog.Promise.prototype.cancel = function(opt_message) { - if (this.state_ == goog.Promise.State_.PENDING) { - goog.async.run(function() { - var err = new goog.Promise.CancellationError(opt_message); - this.cancelInternal_(err); - }, this); - } -}; - - -/** - * Cancels this Promise with the given error. - * - * @param {!Error} err The cancellation error. - * @private - */ -goog.Promise.prototype.cancelInternal_ = function(err) { - if (this.state_ == goog.Promise.State_.PENDING) { - if (this.parent_) { - // Cancel the Promise and remove it from the parent's child list. - this.parent_.cancelChild_(this, err); - this.parent_ = null; - } else { - this.resolve_(goog.Promise.State_.REJECTED, err); - } - } -}; - - -/** - * Cancels a child Promise from the list of callback entries. If the Promise has - * not already been resolved, reject it with a cancel error. If there are no - * other children in the list of callback entries, propagate the cancellation - * by canceling this Promise as well. - * - * @param {!goog.Promise} childPromise The Promise to cancel. - * @param {!Error} err The cancel error to use for rejecting the Promise. - * @private - */ -goog.Promise.prototype.cancelChild_ = function(childPromise, err) { - if (!this.callbackEntries_) { - return; - } - var childCount = 0; - var childEntry = null; - var beforeChildEntry = null; - - // Find the callback entry for the childPromise, and count whether there are - // additional child Promises. - for (var entry = this.callbackEntries_; entry; entry = entry.next) { - if (!entry.always) { - childCount++; - if (entry.child == childPromise) { - childEntry = entry; - } - if (childEntry && childCount > 1) { - break; - } - } - if (!childEntry) { - beforeChildEntry = entry; - } - } - - // Can a child entry be missing? - - // If the child Promise was the only child, cancel this Promise as well. - // Otherwise, reject only the child Promise with the cancel error. - if (childEntry) { - if (this.state_ == goog.Promise.State_.PENDING && childCount == 1) { - this.cancelInternal_(err); - } else { - if (beforeChildEntry) { - this.removeEntryAfter_(beforeChildEntry); - } else { - this.popEntry_(); - } - - this.executeCallback_( - childEntry, goog.Promise.State_.REJECTED, err); - } - } -}; - - -/** - * Adds a callback entry to the current Promise, and schedules callback - * execution if the Promise has already been settled. - * - * @param {goog.Promise.CallbackEntry_} callbackEntry Record containing - * {@code onFulfilled} and {@code onRejected} callbacks to execute after - * the Promise is settled. - * @private - */ -goog.Promise.prototype.addCallbackEntry_ = function(callbackEntry) { - if (!this.hasEntry_() && - (this.state_ == goog.Promise.State_.FULFILLED || - this.state_ == goog.Promise.State_.REJECTED)) { - this.scheduleCallbacks_(); - } - this.queueEntry_(callbackEntry); -}; - - -/** - * Creates a child Promise and adds it to the callback entry list. The result of - * the child Promise is determined by the state of the parent Promise and the - * result of the {@code onFulfilled} or {@code onRejected} callbacks as - * specified in the Promise resolution procedure. - * - * @see http://promisesaplus.com/#the__method - * - * @param {?function(this:THIS, TYPE): - * (RESULT|goog.Promise<RESULT>|Thenable)} onFulfilled A callback that - * will be invoked if the Promise is fullfilled, or null. - * @param {?function(this:THIS, *): *} onRejected A callback that will be - * invoked if the Promise is rejected, or null. - * @param {THIS=} opt_context An optional execution context for the callbacks. - * in the default calling context. - * @return {!goog.Promise} The child Promise. - * @template RESULT,THIS - * @private - */ -goog.Promise.prototype.addChildPromise_ = function( - onFulfilled, onRejected, opt_context) { - - /** @type {goog.Promise.CallbackEntry_} */ - var callbackEntry = goog.Promise.getCallbackEntry_(null, null, null); - - callbackEntry.child = new goog.Promise(function(resolve, reject) { - // Invoke onFulfilled, or resolve with the parent's value if absent. - callbackEntry.onFulfilled = onFulfilled ? function(value) { - try { - var result = onFulfilled.call(opt_context, value); - resolve(result); - } catch (err) { - reject(err); - } - } : resolve; - - // Invoke onRejected, or reject with the parent's reason if absent. - callbackEntry.onRejected = onRejected ? function(reason) { - try { - var result = onRejected.call(opt_context, reason); - if (!goog.isDef(result) && - reason instanceof goog.Promise.CancellationError) { - // Propagate cancellation to children if no other result is returned. - reject(reason); - } else { - resolve(result); - } - } catch (err) { - reject(err); - } - } : reject; - }); - - callbackEntry.child.parent_ = this; - this.addCallbackEntry_(callbackEntry); - return callbackEntry.child; -}; - - -/** - * Unblocks the Promise and fulfills it with the given value. - * - * @param {TYPE} value - * @private - */ -goog.Promise.prototype.unblockAndFulfill_ = function(value) { - goog.asserts.assert(this.state_ == goog.Promise.State_.BLOCKED); - this.state_ = goog.Promise.State_.PENDING; - this.resolve_(goog.Promise.State_.FULFILLED, value); -}; - - -/** - * Unblocks the Promise and rejects it with the given rejection reason. - * - * @param {*} reason - * @private - */ -goog.Promise.prototype.unblockAndReject_ = function(reason) { - goog.asserts.assert(this.state_ == goog.Promise.State_.BLOCKED); - this.state_ = goog.Promise.State_.PENDING; - this.resolve_(goog.Promise.State_.REJECTED, reason); -}; - - -/** - * Attempts to resolve a Promise with a given resolution state and value. This - * is a no-op if the given Promise has already been resolved. - * - * If the given result is a Thenable (such as another Promise), the Promise will - * be settled with the same state and result as the Thenable once it is itself - * settled. - * - * If the given result is not a Thenable, the Promise will be settled (fulfilled - * or rejected) with that result based on the given state. - * - * @see http://promisesaplus.com/#the_promise_resolution_procedure - * - * @param {goog.Promise.State_} state - * @param {*} x The result to apply to the Promise. - * @private - */ -goog.Promise.prototype.resolve_ = function(state, x) { - if (this.state_ != goog.Promise.State_.PENDING) { - return; - } - - if (this == x) { - state = goog.Promise.State_.REJECTED; - x = new TypeError('Promise cannot resolve to itself'); - } - - this.state_ = goog.Promise.State_.BLOCKED; - var isThenable = goog.Promise.maybeThen_( - x, this.unblockAndFulfill_, this.unblockAndReject_, this); - if (isThenable) { - return; - } - - this.result_ = x; - this.state_ = state; - // Since we can no longer be canceled, remove link to parent, so that the - // child promise does not keep the parent promise alive. - this.parent_ = null; - this.scheduleCallbacks_(); - - if (state == goog.Promise.State_.REJECTED && - !(x instanceof goog.Promise.CancellationError)) { - goog.Promise.addUnhandledRejection_(this, x); - } -}; - - -/** - * Invokes the "then" method of an input value if that value is a Thenable. This - * is a no-op if the value is not thenable. - * - * @param {*} value A potentially thenable value. - * @param {!Function} onFulfilled - * @param {!Function} onRejected - * @param {*} context - * @return {boolean} Whether the input value was thenable. - * @private - */ -goog.Promise.maybeThen_ = function(value, onFulfilled, onRejected, context) { - if (value instanceof goog.Promise) { - value.thenVoid(onFulfilled, onRejected, context); - return true; - } else if (goog.Thenable.isImplementedBy(value)) { - value = /** @type {!goog.Thenable} */ (value); - value.then(onFulfilled, onRejected, context); - return true; - } else if (goog.isObject(value)) { - try { - var then = value['then']; - if (goog.isFunction(then)) { - goog.Promise.tryThen_( - value, then, onFulfilled, onRejected, context); - return true; - } - } catch (e) { - onRejected.call(context, e); - return true; - } - } - - return false; -}; - - -/** - * Attempts to call the {@code then} method on an object in the hopes that it is - * a Promise-compatible instance. This allows interoperation between different - * Promise implementations, however a non-compliant object may cause a Promise - * to hang indefinitely. If the {@code then} method throws an exception, the - * dependent Promise will be rejected with the thrown value. - * - * @see http://promisesaplus.com/#point-70 - * - * @param {Thenable} thenable An object with a {@code then} method that may be - * compatible with the Promise/A+ specification. - * @param {!Function} then The {@code then} method of the Thenable object. - * @param {!Function} onFulfilled - * @param {!Function} onRejected - * @param {*} context - * @private - */ -goog.Promise.tryThen_ = function( - thenable, then, onFulfilled, onRejected, context) { - - var called = false; - var resolve = function(value) { - if (!called) { - called = true; - onFulfilled.call(context, value); - } - }; - - var reject = function(reason) { - if (!called) { - called = true; - onRejected.call(context, reason); - } - }; - - try { - then.call(thenable, resolve, reject); - } catch (e) { - reject(e); - } -}; - - -/** - * Executes the pending callbacks of a settled Promise after a timeout. - * - * Section 2.2.4 of the Promises/A+ specification requires that Promise - * callbacks must only be invoked from a call stack that only contains Promise - * implementation code, which we accomplish by invoking callback execution after - * a timeout. If {@code startExecution_} is called multiple times for the same - * Promise, the callback chain will be evaluated only once. Additional callbacks - * may be added during the evaluation phase, and will be executed in the same - * event loop. - * - * All Promises added to the waiting list during the same browser event loop - * will be executed in one batch to avoid using a separate timeout per Promise. - * - * @private - */ -goog.Promise.prototype.scheduleCallbacks_ = function() { - if (!this.executing_) { - this.executing_ = true; - goog.async.run(this.executeCallbacks_, this); - } -}; - - -/** - * @return {boolean} Whether there are any pending callbacks queued. - * @private - */ -goog.Promise.prototype.hasEntry_ = function() { - return !!this.callbackEntries_; -}; - - -/** - * @param {goog.Promise.CallbackEntry_} entry - * @private - */ -goog.Promise.prototype.queueEntry_ = function(entry) { - goog.asserts.assert(entry.onFulfilled != null); - - if (this.callbackEntriesTail_) { - this.callbackEntriesTail_.next = entry; - this.callbackEntriesTail_ = entry; - } else { - // It the work queue was empty set the head too. - this.callbackEntries_ = entry; - this.callbackEntriesTail_ = entry; - } -}; - - -/** - * @return {goog.Promise.CallbackEntry_} entry - * @private - */ -goog.Promise.prototype.popEntry_ = function() { - var entry = null; - if (this.callbackEntries_) { - entry = this.callbackEntries_; - this.callbackEntries_ = entry.next; - entry.next = null; - } - // It the work queue is empty clear the tail too. - if (!this.callbackEntries_) { - this.callbackEntriesTail_ = null; - } - - if (entry != null) { - goog.asserts.assert(entry.onFulfilled != null); - } - return entry; -}; - - -/** - * @param {goog.Promise.CallbackEntry_} previous - * @private - */ -goog.Promise.prototype.removeEntryAfter_ = function(previous) { - goog.asserts.assert(this.callbackEntries_); - goog.asserts.assert(previous != null); - // If the last entry is being removed, update the tail - if (previous.next == this.callbackEntriesTail_) { - this.callbackEntriesTail_ = previous; - } - - previous.next = previous.next.next; -}; - - -/** - * Executes all pending callbacks for this Promise. - * - * @private - */ -goog.Promise.prototype.executeCallbacks_ = function() { - var entry = null; - while (entry = this.popEntry_()) { - if (goog.Promise.LONG_STACK_TRACES) { - this.currentStep_++; - } - this.executeCallback_(entry, this.state_, this.result_); - } - this.executing_ = false; -}; - - -/** - * Executes a pending callback for this Promise. Invokes an {@code onFulfilled} - * or {@code onRejected} callback based on the settled state of the Promise. - * - * @param {!goog.Promise.CallbackEntry_} callbackEntry An entry containing the - * onFulfilled and/or onRejected callbacks for this step. - * @param {goog.Promise.State_} state The resolution status of the Promise, - * either FULFILLED or REJECTED. - * @param {*} result The settled result of the Promise. - * @private - */ -goog.Promise.prototype.executeCallback_ = function( - callbackEntry, state, result) { - // Cancel an unhandled rejection if the then/thenVoid call had an onRejected. - if (state == goog.Promise.State_.REJECTED && - callbackEntry.onRejected && !callbackEntry.always) { - this.removeUnhandledRejection_(); - } - - if (callbackEntry.child) { - // When the parent is settled, the child no longer needs to hold on to it, - // as the parent can no longer be canceled. - callbackEntry.child.parent_ = null; - goog.Promise.invokeCallback_(callbackEntry, state, result); - } else { - // Callbacks created with thenAlways or thenVoid do not have the rejection - // handling code normally set up in the child Promise. - try { - callbackEntry.always ? - callbackEntry.onFulfilled.call(callbackEntry.context) : - goog.Promise.invokeCallback_(callbackEntry, state, result); - } catch (err) { - goog.Promise.handleRejection_.call(null, err); - } - } - goog.Promise.returnEntry_(callbackEntry); -}; - - -/** - * Executes the onFulfilled or onRejected callback for a callbackEntry. - * - * @param {!goog.Promise.CallbackEntry_} callbackEntry - * @param {goog.Promise.State_} state - * @param {*} result - * @private - */ -goog.Promise.invokeCallback_ = function(callbackEntry, state, result) { - if (state == goog.Promise.State_.FULFILLED) { - callbackEntry.onFulfilled.call(callbackEntry.context, result); - } else if (callbackEntry.onRejected) { - callbackEntry.onRejected.call(callbackEntry.context, result); - } -}; - - -/** - * Records a stack trace entry for functions that call {@code then} or the - * Promise constructor. May be disabled by unsetting {@code LONG_STACK_TRACES}. - * - * @param {!Error} err An Error object created by the calling function for - * providing a stack trace. - * @private - */ -goog.Promise.prototype.addStackTrace_ = function(err) { - if (goog.Promise.LONG_STACK_TRACES && goog.isString(err.stack)) { - // Extract the third line of the stack trace, which is the entry for the - // user function that called into Promise code. - var trace = err.stack.split('\n', 4)[3]; - var message = err.message; - - // Pad the message to align the traces. - message += Array(11 - message.length).join(' '); - this.stack_.push(message + trace); - } -}; - - -/** - * Adds extra stack trace information to an exception for the list of - * asynchronous {@code then} calls that have been run for this Promise. Stack - * trace information is recorded in {@see #addStackTrace_}, and appended to - * rethrown errors when {@code LONG_STACK_TRACES} is enabled. - * - * @param {*} err An unhandled exception captured during callback execution. - * @private - */ -goog.Promise.prototype.appendLongStack_ = function(err) { - if (goog.Promise.LONG_STACK_TRACES && - err && goog.isString(err.stack) && this.stack_.length) { - var longTrace = ['Promise trace:']; - - for (var promise = this; promise; promise = promise.parent_) { - for (var i = this.currentStep_; i >= 0; i--) { - longTrace.push(promise.stack_[i]); - } - longTrace.push('Value: ' + - '[' + (promise.state_ == goog.Promise.State_.REJECTED ? - 'REJECTED' : 'FULFILLED') + '] ' + - '<' + String(promise.result_) + '>'); - } - err.stack += '\n\n' + longTrace.join('\n'); - } -}; - - -/** - * Marks this rejected Promise as having being handled. Also marks any parent - * Promises in the rejected state as handled. The rejection handler will no - * longer be invoked for this Promise (if it has not been called already). - * - * @private - */ -goog.Promise.prototype.removeUnhandledRejection_ = function() { - if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { - for (var p = this; p && p.unhandledRejectionId_; p = p.parent_) { - goog.global.clearTimeout(p.unhandledRejectionId_); - p.unhandledRejectionId_ = 0; - } - } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { - for (var p = this; p && p.hadUnhandledRejection_; p = p.parent_) { - p.hadUnhandledRejection_ = false; - } - } -}; - - -/** - * Marks this rejected Promise as unhandled. If no {@code onRejected} callback - * is called for this Promise before the {@code UNHANDLED_REJECTION_DELAY} - * expires, the reason will be passed to the unhandled rejection handler. The - * handler typically rethrows the rejection reason so that it becomes visible in - * the developer console. - * - * @param {!goog.Promise} promise The rejected Promise. - * @param {*} reason The Promise rejection reason. - * @private - */ -goog.Promise.addUnhandledRejection_ = function(promise, reason) { - if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { - promise.unhandledRejectionId_ = goog.global.setTimeout(function() { - promise.appendLongStack_(reason); - goog.Promise.handleRejection_.call(null, reason); - }, goog.Promise.UNHANDLED_REJECTION_DELAY); - - } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { - promise.hadUnhandledRejection_ = true; - goog.async.run(function() { - if (promise.hadUnhandledRejection_) { - promise.appendLongStack_(reason); - goog.Promise.handleRejection_.call(null, reason); - } - }); - } -}; - - -/** - * A method that is invoked with the rejection reasons for Promises that are - * rejected but have no {@code onRejected} callbacks registered yet. - * @type {function(*)} - * @private - */ -goog.Promise.handleRejection_ = goog.async.throwException; - - -/** - * Sets a handler that will be called with reasons from unhandled rejected - * Promises. If the rejected Promise (or one of its descendants) has an - * {@code onRejected} callback registered, the rejection will be considered - * handled, and the rejection handler will not be called. - * - * By default, unhandled rejections are rethrown so that the error may be - * captured by the developer console or a {@code window.onerror} handler. - * - * @param {function(*)} handler A function that will be called with reasons from - * rejected Promises. Defaults to {@code goog.async.throwException}. - */ -goog.Promise.setUnhandledRejectionHandler = function(handler) { - goog.Promise.handleRejection_ = handler; -}; - - - -/** - * Error used as a rejection reason for canceled Promises. - * - * @param {string=} opt_message - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.Promise.CancellationError = function(opt_message) { - goog.Promise.CancellationError.base(this, 'constructor', opt_message); -}; -goog.inherits(goog.Promise.CancellationError, goog.debug.Error); - - -/** @override */ -goog.Promise.CancellationError.prototype.name = 'cancel'; - - - -/** - * Internal implementation of the resolver interface. - * - * @param {!goog.Promise<TYPE>} promise - * @param {function((TYPE|goog.Promise<TYPE>|Thenable)=)} resolve - * @param {function(*=): void} reject - * @implements {goog.promise.Resolver<TYPE>} - * @final @struct - * @constructor - * @private - * @template TYPE - */ -goog.Promise.Resolver_ = function(promise, resolve, reject) { - /** @const */ - this.promise = promise; - - /** @const */ - this.resolve = resolve; - - /** @const */ - this.reject = reject; -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A timer class to which other classes and objects can - * listen on. This is only an abstraction above setInterval. - * - * @see ../demos/timers.html - */ - -goog.provide('goog.Timer'); - -goog.require('goog.Promise'); -goog.require('goog.events.EventTarget'); - - - -/** - * Class for handling timing events. - * - * @param {number=} opt_interval Number of ms between ticks (Default: 1ms). - * @param {Object=} opt_timerObject An object that has setTimeout, setInterval, - * clearTimeout and clearInterval (eg Window). - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.Timer = function(opt_interval, opt_timerObject) { - goog.events.EventTarget.call(this); - - /** - * Number of ms between ticks - * @type {number} - * @private - */ - this.interval_ = opt_interval || 1; - - /** - * An object that implements setTimeout, setInterval, clearTimeout and - * clearInterval. We default to the window object. Changing this on - * goog.Timer.prototype changes the object for all timer instances which can - * be useful if your environment has some other implementation of timers than - * the window object. - * @type {Object} - * @private - */ - this.timerObject_ = opt_timerObject || goog.Timer.defaultTimerObject; - - /** - * Cached tick_ bound to the object for later use in the timer. - * @type {Function} - * @private - */ - this.boundTick_ = goog.bind(this.tick_, this); - - /** - * Firefox browser often fires the timer event sooner - * (sometimes MUCH sooner) than the requested timeout. So we - * compare the time to when the event was last fired, and - * reschedule if appropriate. See also goog.Timer.intervalScale - * @type {number} - * @private - */ - this.last_ = goog.now(); -}; -goog.inherits(goog.Timer, goog.events.EventTarget); - - -/** - * Maximum timeout value. - * - * Timeout values too big to fit into a signed 32-bit integer may cause - * overflow in FF, Safari, and Chrome, resulting in the timeout being - * scheduled immediately. It makes more sense simply not to schedule these - * timeouts, since 24.8 days is beyond a reasonable expectation for the - * browser to stay open. - * - * @type {number} - * @private - */ -goog.Timer.MAX_TIMEOUT_ = 2147483647; - - -/** - * A timer ID that cannot be returned by any known implmentation of - * Window.setTimeout. Passing this value to window.clearTimeout should - * therefore be a no-op. - * - * @const {number} - * @private - */ -goog.Timer.INVALID_TIMEOUT_ID_ = -1; - - -/** - * Whether this timer is enabled - * @type {boolean} - */ -goog.Timer.prototype.enabled = false; - - -/** - * An object that implements setTimout, setInterval, clearTimeout and - * clearInterval. We default to the global object. Changing - * goog.Timer.defaultTimerObject changes the object for all timer instances - * which can be useful if your environment has some other implementation of - * timers you'd like to use. - * @type {Object} - */ -goog.Timer.defaultTimerObject = goog.global; - - -/** - * A variable that controls the timer error correction. If the - * timer is called before the requested interval times - * intervalScale, which often happens on mozilla, the timer is - * rescheduled. See also this.last_ - * @type {number} - */ -goog.Timer.intervalScale = 0.8; - - -/** - * Variable for storing the result of setInterval - * @type {?number} - * @private - */ -goog.Timer.prototype.timer_ = null; - - -/** - * Gets the interval of the timer. - * @return {number} interval Number of ms between ticks. - */ -goog.Timer.prototype.getInterval = function() { - return this.interval_; -}; - - -/** - * Sets the interval of the timer. - * @param {number} interval Number of ms between ticks. - */ -goog.Timer.prototype.setInterval = function(interval) { - this.interval_ = interval; - if (this.timer_ && this.enabled) { - // Stop and then start the timer to reset the interval. - this.stop(); - this.start(); - } else if (this.timer_) { - this.stop(); - } -}; - - -/** - * Callback for the setTimeout used by the timer - * @private - */ -goog.Timer.prototype.tick_ = function() { - if (this.enabled) { - var elapsed = goog.now() - this.last_; - if (elapsed > 0 && - elapsed < this.interval_ * goog.Timer.intervalScale) { - this.timer_ = this.timerObject_.setTimeout(this.boundTick_, - this.interval_ - elapsed); - return; - } - - // Prevents setInterval from registering a duplicate timeout when called - // in the timer event handler. - if (this.timer_) { - this.timerObject_.clearTimeout(this.timer_); - this.timer_ = null; - } - - this.dispatchTick(); - // The timer could be stopped in the timer event handler. - if (this.enabled) { - this.timer_ = this.timerObject_.setTimeout(this.boundTick_, - this.interval_); - this.last_ = goog.now(); - } - } -}; - - -/** - * Dispatches the TICK event. This is its own method so subclasses can override. - */ -goog.Timer.prototype.dispatchTick = function() { - this.dispatchEvent(goog.Timer.TICK); -}; - - -/** - * Starts the timer. - */ -goog.Timer.prototype.start = function() { - this.enabled = true; - - // If there is no interval already registered, start it now - if (!this.timer_) { - // IMPORTANT! - // window.setInterval in FireFox has a bug - it fires based on - // absolute time, rather than on relative time. What this means - // is that if a computer is sleeping/hibernating for 24 hours - // and the timer interval was configured to fire every 1000ms, - // then after the PC wakes up the timer will fire, in rapid - // succession, 3600*24 times. - // This bug is described here and is already fixed, but it will - // take time to propagate, so for now I am switching this over - // to setTimeout logic. - // https://bugzilla.mozilla.org/show_bug.cgi?id=376643 - // - this.timer_ = this.timerObject_.setTimeout(this.boundTick_, - this.interval_); - this.last_ = goog.now(); - } -}; - - -/** - * Stops the timer. - */ -goog.Timer.prototype.stop = function() { - this.enabled = false; - if (this.timer_) { - this.timerObject_.clearTimeout(this.timer_); - this.timer_ = null; - } -}; - - -/** @override */ -goog.Timer.prototype.disposeInternal = function() { - goog.Timer.superClass_.disposeInternal.call(this); - this.stop(); - delete this.timerObject_; -}; - - -/** - * Constant for the timer's event type - * @type {string} - */ -goog.Timer.TICK = 'tick'; - - -/** - * Calls the given function once, after the optional pause. - * - * The function is always called asynchronously, even if the delay is 0. This - * is a common trick to schedule a function to run after a batch of browser - * event processing. - * - * @param {function(this:SCOPE)|{handleEvent:function()}|null} listener Function - * or object that has a handleEvent method. - * @param {number=} opt_delay Milliseconds to wait; default is 0. - * @param {SCOPE=} opt_handler Object in whose scope to call the listener. - * @return {number} A handle to the timer ID. - * @template SCOPE - */ -goog.Timer.callOnce = function(listener, opt_delay, opt_handler) { - if (goog.isFunction(listener)) { - if (opt_handler) { - listener = goog.bind(listener, opt_handler); - } - } else if (listener && typeof listener.handleEvent == 'function') { - // using typeof to prevent strict js warning - listener = goog.bind(listener.handleEvent, listener); - } else { - throw Error('Invalid listener argument'); - } - - if (opt_delay > goog.Timer.MAX_TIMEOUT_) { - // Timeouts greater than MAX_INT return immediately due to integer - // overflow in many browsers. Since MAX_INT is 24.8 days, just don't - // schedule anything at all. - return goog.Timer.INVALID_TIMEOUT_ID_; - } else { - return goog.Timer.defaultTimerObject.setTimeout( - listener, opt_delay || 0); - } -}; - - -/** - * Clears a timeout initiated by callOnce - * @param {?number} timerId a timer ID. - */ -goog.Timer.clear = function(timerId) { - goog.Timer.defaultTimerObject.clearTimeout(timerId); -}; - - -/** - * @param {number} delay Milliseconds to wait. - * @param {(RESULT|goog.Thenable<RESULT>|Thenable)=} opt_result The value - * with which the promise will be resolved. - * @return {!goog.Promise<RESULT>} A promise that will be resolved after - * the specified delay, unless it is canceled first. - * @template RESULT - */ -goog.Timer.promise = function(delay, opt_result) { - var timerKey = null; - return new goog.Promise(function(resolve, reject) { - timerKey = goog.Timer.callOnce(function() { - resolve(opt_result); - }, delay); - if (timerKey == goog.Timer.INVALID_TIMEOUT_ID_) { - reject(new Error('Failed to schedule timer.')); - } - }).thenCatch(function(error) { - // Clear the timer. The most likely reason is "cancel" signal. - goog.Timer.clear(timerKey); - throw error; - }); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview JSON utility functions. - * @author arv@google.com (Erik Arvidsson) - */ - - -goog.provide('goog.json'); -goog.provide('goog.json.Replacer'); -goog.provide('goog.json.Reviver'); -goog.provide('goog.json.Serializer'); - - -/** - * @define {boolean} If true, use the native JSON parsing API. - * NOTE(ruilopes): EXPERIMENTAL, handle with care. Setting this to true might - * break your code. The default {@code goog.json.parse} implementation is able - * to handle invalid JSON, such as JSPB. - */ -goog.define('goog.json.USE_NATIVE_JSON', false); - - -/** - * Tests if a string is an invalid JSON string. This only ensures that we are - * not using any invalid characters - * @param {string} s The string to test. - * @return {boolean} True if the input is a valid JSON string. - */ -goog.json.isValid = function(s) { - // All empty whitespace is not valid. - if (/^\s*$/.test(s)) { - return false; - } - - // This is taken from http://www.json.org/json2.js which is released to the - // public domain. - // Changes: We dissallow \u2028 Line separator and \u2029 Paragraph separator - // inside strings. We also treat \u2028 and \u2029 as whitespace which they - // are in the RFC but IE and Safari does not match \s to these so we need to - // include them in the reg exps in all places where whitespace is allowed. - // We allowed \x7f inside strings because some tools don't escape it, - // e.g. http://www.json.org/java/org/json/JSONObject.java - - // Parsing happens in three stages. In the first stage, we run the text - // against regular expressions that look for non-JSON patterns. We are - // especially concerned with '()' and 'new' because they can cause invocation, - // and '=' because it can cause mutation. But just to be safe, we want to - // reject all unexpected forms. - - // We split the first stage into 4 regexp operations in order to work around - // crippling inefficiencies in IE's and Safari's regexp engines. First we - // replace all backslash pairs with '@' (a non-JSON character). Second, we - // replace all simple value tokens with ']' characters. Third, we delete all - // open brackets that follow a colon or comma or that begin the text. Finally, - // we look to see that the remaining characters are only whitespace or ']' or - // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - // Don't make these static since they have the global flag. - var backslashesRe = /\\["\\\/bfnrtu]/g; - var simpleValuesRe = - /"[^"\\\n\r\u2028\u2029\x00-\x08\x0a-\x1f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; - var openBracketsRe = /(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g; - var remainderRe = /^[\],:{}\s\u2028\u2029]*$/; - - return remainderRe.test(s.replace(backslashesRe, '@'). - replace(simpleValuesRe, ']'). - replace(openBracketsRe, '')); -}; - - -/** - * Parses a JSON string and returns the result. This throws an exception if - * the string is an invalid JSON string. - * - * Note that this is very slow on large strings. If you trust the source of - * the string then you should use unsafeParse instead. - * - * @param {*} s The JSON string to parse. - * @throws Error if s is invalid JSON. - * @return {Object} The object generated from the JSON string, or null. - */ -goog.json.parse = goog.json.USE_NATIVE_JSON ? - /** @type {function(*):Object} */ (goog.global['JSON']['parse']) : - function(s) { - var o = String(s); - if (goog.json.isValid(o)) { - /** @preserveTry */ - try { - return /** @type {Object} */ (eval('(' + o + ')')); - } catch (ex) { - } - } - throw Error('Invalid JSON string: ' + o); - }; - - -/** - * Parses a JSON string and returns the result. This uses eval so it is open - * to security issues and it should only be used if you trust the source. - * - * @param {string} s The JSON string to parse. - * @return {Object} The object generated from the JSON string. - */ -goog.json.unsafeParse = goog.json.USE_NATIVE_JSON ? - /** @type {function(string):Object} */ (goog.global['JSON']['parse']) : - function(s) { - return /** @type {Object} */ (eval('(' + s + ')')); - }; - - -/** - * JSON replacer, as defined in Section 15.12.3 of the ES5 spec. - * @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3 - * - * TODO(nicksantos): Array should also be a valid replacer. - * - * @typedef {function(this:Object, string, *): *} - */ -goog.json.Replacer; - - -/** - * JSON reviver, as defined in Section 15.12.2 of the ES5 spec. - * @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3 - * - * @typedef {function(this:Object, string, *): *} - */ -goog.json.Reviver; - - -/** - * Serializes an object or a value to a JSON string. - * - * @param {*} object The object to serialize. - * @param {?goog.json.Replacer=} opt_replacer A replacer function - * called for each (key, value) pair that determines how the value - * should be serialized. By defult, this just returns the value - * and allows default serialization to kick in. - * @throws Error if there are loops in the object graph. - * @return {string} A JSON string representation of the input. - */ -goog.json.serialize = goog.json.USE_NATIVE_JSON ? - /** @type {function(*, ?goog.json.Replacer=):string} */ - (goog.global['JSON']['stringify']) : - function(object, opt_replacer) { - // NOTE(nicksantos): Currently, we never use JSON.stringify. - // - // The last time I evaluated this, JSON.stringify had subtle bugs and - // behavior differences on all browsers, and the performance win was not - // large enough to justify all the issues. This may change in the future - // as browser implementations get better. - // - // assertSerialize in json_test contains if branches for the cases - // that fail. - return new goog.json.Serializer(opt_replacer).serialize(object); - }; - - - -/** - * Class that is used to serialize JSON objects to a string. - * @param {?goog.json.Replacer=} opt_replacer Replacer. - * @constructor - */ -goog.json.Serializer = function(opt_replacer) { - /** - * @type {goog.json.Replacer|null|undefined} - * @private - */ - this.replacer_ = opt_replacer; -}; - - -/** - * Serializes an object or a value to a JSON string. - * - * @param {*} object The object to serialize. - * @throws Error if there are loops in the object graph. - * @return {string} A JSON string representation of the input. - */ -goog.json.Serializer.prototype.serialize = function(object) { - var sb = []; - this.serializeInternal(object, sb); - return sb.join(''); -}; - - -/** - * Serializes a generic value to a JSON string - * @protected - * @param {*} object The object to serialize. - * @param {Array<string>} sb Array used as a string builder. - * @throws Error if there are loops in the object graph. - */ -goog.json.Serializer.prototype.serializeInternal = function(object, sb) { - if (object == null) { - // undefined == null so this branch covers undefined as well as null - sb.push('null'); - return; - } - - if (typeof object == 'object') { - if (goog.isArray(object)) { - this.serializeArray(object, sb); - return; - } else if (object instanceof String || - object instanceof Number || - object instanceof Boolean) { - object = object.valueOf(); - // Fall through to switch below. - } else { - this.serializeObject_(/** @type {Object} */ (object), sb); - return; - } - } - - switch (typeof object) { - case 'string': - this.serializeString_(object, sb); - break; - case 'number': - this.serializeNumber_(object, sb); - break; - case 'boolean': - sb.push(object); - break; - case 'function': - sb.push('null'); - break; - default: - throw Error('Unknown type: ' + typeof object); - } -}; - - -/** - * Character mappings used internally for goog.string.quote - * @private - * @type {!Object} - */ -goog.json.Serializer.charToJsonCharCache_ = { - '\"': '\\"', - '\\': '\\\\', - '/': '\\/', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', - - '\x0B': '\\u000b' // '\v' is not supported in JScript -}; - - -/** - * Regular expression used to match characters that need to be replaced. - * The S60 browser has a bug where unicode characters are not matched by - * regular expressions. The condition below detects such behaviour and - * adjusts the regular expression accordingly. - * @private - * @type {!RegExp} - */ -goog.json.Serializer.charsToReplace_ = /\uffff/.test('\uffff') ? - /[\\\"\x00-\x1f\x7f-\uffff]/g : /[\\\"\x00-\x1f\x7f-\xff]/g; - - -/** - * Serializes a string to a JSON string - * @private - * @param {string} s The string to serialize. - * @param {Array<string>} sb Array used as a string builder. - */ -goog.json.Serializer.prototype.serializeString_ = function(s, sb) { - // The official JSON implementation does not work with international - // characters. - sb.push('"', s.replace(goog.json.Serializer.charsToReplace_, function(c) { - // caching the result improves performance by a factor 2-3 - var rv = goog.json.Serializer.charToJsonCharCache_[c]; - if (!rv) { - rv = '\\u' + (c.charCodeAt(0) | 0x10000).toString(16).substr(1); - goog.json.Serializer.charToJsonCharCache_[c] = rv; - } - return rv; - }), '"'); -}; - - -/** - * Serializes a number to a JSON string - * @private - * @param {number} n The number to serialize. - * @param {Array<string>} sb Array used as a string builder. - */ -goog.json.Serializer.prototype.serializeNumber_ = function(n, sb) { - sb.push(isFinite(n) && !isNaN(n) ? n : 'null'); -}; - - -/** - * Serializes an array to a JSON string - * @param {Array<string>} arr The array to serialize. - * @param {Array<string>} sb Array used as a string builder. - * @protected - */ -goog.json.Serializer.prototype.serializeArray = function(arr, sb) { - var l = arr.length; - sb.push('['); - var sep = ''; - for (var i = 0; i < l; i++) { - sb.push(sep); - - var value = arr[i]; - this.serializeInternal( - this.replacer_ ? this.replacer_.call(arr, String(i), value) : value, - sb); - - sep = ','; - } - sb.push(']'); -}; - - -/** - * Serializes an object to a JSON string - * @private - * @param {Object} obj The object to serialize. - * @param {Array<string>} sb Array used as a string builder. - */ -goog.json.Serializer.prototype.serializeObject_ = function(obj, sb) { - sb.push('{'); - var sep = ''; - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - var value = obj[key]; - // Skip functions. - if (typeof value != 'function') { - sb.push(sep); - this.serializeString_(key, sb); - sb.push(':'); - - this.serializeInternal( - this.replacer_ ? this.replacer_.call(obj, key, value) : value, - sb); - - sep = ','; - } - } - } - sb.push('}'); -}; - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Error codes shared between goog.net.IframeIo and - * goog.net.XhrIo. - */ - -goog.provide('goog.net.ErrorCode'); - - -/** - * Error codes - * @enum {number} - */ -goog.net.ErrorCode = { - - /** - * There is no error condition. - */ - NO_ERROR: 0, - - /** - * The most common error from iframeio, unfortunately, is that the browser - * responded with an error page that is classed as a different domain. The - * situations, are when a browser error page is shown -- 404, access denied, - * DNS failure, connection reset etc.) - * - */ - ACCESS_DENIED: 1, - - /** - * Currently the only case where file not found will be caused is when the - * code is running on the local file system and a non-IE browser makes a - * request to a file that doesn't exist. - */ - FILE_NOT_FOUND: 2, - - /** - * If Firefox shows a browser error page, such as a connection reset by - * server or access denied, then it will fail silently without the error or - * load handlers firing. - */ - FF_SILENT_ERROR: 3, - - /** - * Custom error provided by the client through the error check hook. - */ - CUSTOM_ERROR: 4, - - /** - * Exception was thrown while processing the request. - */ - EXCEPTION: 5, - - /** - * The Http response returned a non-successful http status code. - */ - HTTP_ERROR: 6, - - /** - * The request was aborted. - */ - ABORT: 7, - - /** - * The request timed out. - */ - TIMEOUT: 8, - - /** - * The resource is not available offline. - */ - OFFLINE: 9 -}; - - -/** - * Returns a friendly error message for an error code. These messages are for - * debugging and are not localized. - * @param {goog.net.ErrorCode} errorCode An error code. - * @return {string} A message for debugging. - */ -goog.net.ErrorCode.getDebugMessage = function(errorCode) { - switch (errorCode) { - case goog.net.ErrorCode.NO_ERROR: - return 'No Error'; - - case goog.net.ErrorCode.ACCESS_DENIED: - return 'Access denied to content document'; - - case goog.net.ErrorCode.FILE_NOT_FOUND: - return 'File not found'; - - case goog.net.ErrorCode.FF_SILENT_ERROR: - return 'Firefox silently errored'; - - case goog.net.ErrorCode.CUSTOM_ERROR: - return 'Application custom error'; - - case goog.net.ErrorCode.EXCEPTION: - return 'An exception occurred'; - - case goog.net.ErrorCode.HTTP_ERROR: - return 'Http response at 400 or 500 level'; - - case goog.net.ErrorCode.ABORT: - return 'Request was aborted'; - - case goog.net.ErrorCode.TIMEOUT: - return 'Request timed out'; - - case goog.net.ErrorCode.OFFLINE: - return 'The resource is not available offline'; - - default: - return 'Unrecognized error code'; - } -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Constants for HTTP status codes. - */ - -goog.provide('goog.net.HttpStatus'); - - -/** - * HTTP Status Codes defined in RFC 2616 and RFC 6585. - * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html - * @see http://tools.ietf.org/html/rfc6585 - * @enum {number} - */ -goog.net.HttpStatus = { - // Informational 1xx - CONTINUE: 100, - SWITCHING_PROTOCOLS: 101, - - // Successful 2xx - OK: 200, - CREATED: 201, - ACCEPTED: 202, - NON_AUTHORITATIVE_INFORMATION: 203, - NO_CONTENT: 204, - RESET_CONTENT: 205, - PARTIAL_CONTENT: 206, - - // Redirection 3xx - MULTIPLE_CHOICES: 300, - MOVED_PERMANENTLY: 301, - FOUND: 302, - SEE_OTHER: 303, - NOT_MODIFIED: 304, - USE_PROXY: 305, - TEMPORARY_REDIRECT: 307, - - // Client Error 4xx - BAD_REQUEST: 400, - UNAUTHORIZED: 401, - PAYMENT_REQUIRED: 402, - FORBIDDEN: 403, - NOT_FOUND: 404, - METHOD_NOT_ALLOWED: 405, - NOT_ACCEPTABLE: 406, - PROXY_AUTHENTICATION_REQUIRED: 407, - REQUEST_TIMEOUT: 408, - CONFLICT: 409, - GONE: 410, - LENGTH_REQUIRED: 411, - PRECONDITION_FAILED: 412, - REQUEST_ENTITY_TOO_LARGE: 413, - REQUEST_URI_TOO_LONG: 414, - UNSUPPORTED_MEDIA_TYPE: 415, - REQUEST_RANGE_NOT_SATISFIABLE: 416, - EXPECTATION_FAILED: 417, - PRECONDITION_REQUIRED: 428, - TOO_MANY_REQUESTS: 429, - REQUEST_HEADER_FIELDS_TOO_LARGE: 431, - - // Server Error 5xx - INTERNAL_SERVER_ERROR: 500, - NOT_IMPLEMENTED: 501, - BAD_GATEWAY: 502, - SERVICE_UNAVAILABLE: 503, - GATEWAY_TIMEOUT: 504, - HTTP_VERSION_NOT_SUPPORTED: 505, - NETWORK_AUTHENTICATION_REQUIRED: 511, - - /* - * IE returns this code for 204 due to its use of URLMon, which returns this - * code for 'Operation Aborted'. The status text is 'Unknown', the response - * headers are ''. Known to occur on IE 6 on XP through IE9 on Win7. - */ - QUIRK_IE_NO_CONTENT: 1223 -}; - - -/** - * Returns whether the given status should be considered successful. - * - * Successful codes are OK (200), CREATED (201), ACCEPTED (202), - * NO CONTENT (204), PARTIAL CONTENT (206), NOT MODIFIED (304), - * and IE's no content code (1223). - * - * @param {number} status The status code to test. - * @return {boolean} Whether the status code should be considered successful. - */ -goog.net.HttpStatus.isSuccess = function(status) { - switch (status) { - case goog.net.HttpStatus.OK: - case goog.net.HttpStatus.CREATED: - case goog.net.HttpStatus.ACCEPTED: - case goog.net.HttpStatus.NO_CONTENT: - case goog.net.HttpStatus.PARTIAL_CONTENT: - case goog.net.HttpStatus.NOT_MODIFIED: - case goog.net.HttpStatus.QUIRK_IE_NO_CONTENT: - return true; - - default: - return false; - } -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.net.XhrLike'); - - - -/** - * Interface for the common parts of XMLHttpRequest. - * - * Mostly copied from externs/w3c_xml.js. - * - * @interface - * @see http://www.w3.org/TR/XMLHttpRequest/ - */ -goog.net.XhrLike = function() {}; - - -/** - * Typedef that refers to either native or custom-implemented XHR objects. - * @typedef {!goog.net.XhrLike|!XMLHttpRequest} - */ -goog.net.XhrLike.OrNative; - - -/** - * @type {function()|null|undefined} - * @see http://www.w3.org/TR/XMLHttpRequest/#handler-xhr-onreadystatechange - */ -goog.net.XhrLike.prototype.onreadystatechange; - - -/** - * @type {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute - */ -goog.net.XhrLike.prototype.responseText; - - -/** - * @type {Document} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsexml-attribute - */ -goog.net.XhrLike.prototype.responseXML; - - -/** - * @type {number} - * @see http://www.w3.org/TR/XMLHttpRequest/#readystate - */ -goog.net.XhrLike.prototype.readyState; - - -/** - * @type {number} - * @see http://www.w3.org/TR/XMLHttpRequest/#status - */ -goog.net.XhrLike.prototype.status; - - -/** - * @type {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#statustext - */ -goog.net.XhrLike.prototype.statusText; - - -/** - * @param {string} method - * @param {string} url - * @param {?boolean=} opt_async - * @param {?string=} opt_user - * @param {?string=} opt_password - * @see http://www.w3.org/TR/XMLHttpRequest/#the-open()-method - */ -goog.net.XhrLike.prototype.open = function(method, url, opt_async, opt_user, - opt_password) {}; - - -/** - * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} opt_data - * @see http://www.w3.org/TR/XMLHttpRequest/#the-send()-method - */ -goog.net.XhrLike.prototype.send = function(opt_data) {}; - - -/** - * @see http://www.w3.org/TR/XMLHttpRequest/#the-abort()-method - */ -goog.net.XhrLike.prototype.abort = function() {}; - - -/** - * @param {string} header - * @param {string} value - * @see http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method - */ -goog.net.XhrLike.prototype.setRequestHeader = function(header, value) {}; - - -/** - * @param {string} header - * @return {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method - */ -goog.net.XhrLike.prototype.getResponseHeader = function(header) {}; - - -/** - * @return {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method - */ -goog.net.XhrLike.prototype.getAllResponseHeaders = function() {}; - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Interface for a factory for creating XMLHttpRequest objects - * and metadata about them. - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.XmlHttpFactory'); - -/** @suppress {extraRequire} Typedef. */ -goog.require('goog.net.XhrLike'); - - - -/** - * Abstract base class for an XmlHttpRequest factory. - * @constructor - */ -goog.net.XmlHttpFactory = function() { -}; - - -/** - * Cache of options - we only actually call internalGetOptions once. - * @type {Object} - * @private - */ -goog.net.XmlHttpFactory.prototype.cachedOptions_ = null; - - -/** - * @return {!goog.net.XhrLike.OrNative} A new XhrLike instance. - */ -goog.net.XmlHttpFactory.prototype.createInstance = goog.abstractMethod; - - -/** - * @return {Object} Options describing how xhr objects obtained from this - * factory should be used. - */ -goog.net.XmlHttpFactory.prototype.getOptions = function() { - return this.cachedOptions_ || - (this.cachedOptions_ = this.internalGetOptions()); -}; - - -/** - * Override this method in subclasses to preserve the caching offered by - * getOptions(). - * @return {Object} Options describing how xhr objects obtained from this - * factory should be used. - * @protected - */ -goog.net.XmlHttpFactory.prototype.internalGetOptions = goog.abstractMethod; - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Implementation of XmlHttpFactory which allows construction from - * simple factory methods. - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.WrapperXmlHttpFactory'); - -/** @suppress {extraRequire} Typedef. */ -goog.require('goog.net.XhrLike'); -goog.require('goog.net.XmlHttpFactory'); - - - -/** - * An xhr factory subclass which can be constructed using two factory methods. - * This exists partly to allow the preservation of goog.net.XmlHttp.setFactory() - * with an unchanged signature. - * @param {function():!goog.net.XhrLike.OrNative} xhrFactory - * A function which returns a new XHR object. - * @param {function():!Object} optionsFactory A function which returns the - * options associated with xhr objects from this factory. - * @extends {goog.net.XmlHttpFactory} - * @constructor - * @final - */ -goog.net.WrapperXmlHttpFactory = function(xhrFactory, optionsFactory) { - goog.net.XmlHttpFactory.call(this); - - /** - * XHR factory method. - * @type {function() : !goog.net.XhrLike.OrNative} - * @private - */ - this.xhrFactory_ = xhrFactory; - - /** - * Options factory method. - * @type {function() : !Object} - * @private - */ - this.optionsFactory_ = optionsFactory; -}; -goog.inherits(goog.net.WrapperXmlHttpFactory, goog.net.XmlHttpFactory); - - -/** @override */ -goog.net.WrapperXmlHttpFactory.prototype.createInstance = function() { - return this.xhrFactory_(); -}; - - -/** @override */ -goog.net.WrapperXmlHttpFactory.prototype.getOptions = function() { - return this.optionsFactory_(); -}; - - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Low level handling of XMLHttpRequest. - * @author arv@google.com (Erik Arvidsson) - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.DefaultXmlHttpFactory'); -goog.provide('goog.net.XmlHttp'); -goog.provide('goog.net.XmlHttp.OptionType'); -goog.provide('goog.net.XmlHttp.ReadyState'); -goog.provide('goog.net.XmlHttpDefines'); - -goog.require('goog.asserts'); -goog.require('goog.net.WrapperXmlHttpFactory'); -goog.require('goog.net.XmlHttpFactory'); - - -/** - * Static class for creating XMLHttpRequest objects. - * @return {!goog.net.XhrLike.OrNative} A new XMLHttpRequest object. - */ -goog.net.XmlHttp = function() { - return goog.net.XmlHttp.factory_.createInstance(); -}; - - -/** - * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to - * true bypasses the ActiveX probing code. - * NOTE(ruilopes): Due to the way JSCompiler works, this define *will not* strip - * out the ActiveX probing code from binaries. To achieve this, use - * {@code goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR} instead. - * TODO(ruilopes): Collapse both defines. - */ -goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false); - - -/** @const */ -goog.net.XmlHttpDefines = {}; - - -/** - * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to - * true eliminates the ActiveX probing code. - */ -goog.define('goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR', false); - - -/** - * Gets the options to use with the XMLHttpRequest objects obtained using - * the static methods. - * @return {Object} The options. - */ -goog.net.XmlHttp.getOptions = function() { - return goog.net.XmlHttp.factory_.getOptions(); -}; - - -/** - * Type of options that an XmlHttp object can have. - * @enum {number} - */ -goog.net.XmlHttp.OptionType = { - /** - * Whether a goog.nullFunction should be used to clear the onreadystatechange - * handler instead of null. - */ - USE_NULL_FUNCTION: 0, - - /** - * NOTE(user): In IE if send() errors on a *local* request the readystate - * is still changed to COMPLETE. We need to ignore it and allow the - * try/catch around send() to pick up the error. - */ - LOCAL_REQUEST_ERROR: 1 -}; - - -/** - * Status constants for XMLHTTP, matches: - * http://msdn.microsoft.com/library/default.asp?url=/library/ - * en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp - * @enum {number} - */ -goog.net.XmlHttp.ReadyState = { - /** - * Constant for when xmlhttprequest.readyState is uninitialized - */ - UNINITIALIZED: 0, - - /** - * Constant for when xmlhttprequest.readyState is loading. - */ - LOADING: 1, - - /** - * Constant for when xmlhttprequest.readyState is loaded. - */ - LOADED: 2, - - /** - * Constant for when xmlhttprequest.readyState is in an interactive state. - */ - INTERACTIVE: 3, - - /** - * Constant for when xmlhttprequest.readyState is completed - */ - COMPLETE: 4 -}; - - -/** - * The global factory instance for creating XMLHttpRequest objects. - * @type {goog.net.XmlHttpFactory} - * @private - */ -goog.net.XmlHttp.factory_; - - -/** - * Sets the factories for creating XMLHttpRequest objects and their options. - * @param {Function} factory The factory for XMLHttpRequest objects. - * @param {Function} optionsFactory The factory for options. - * @deprecated Use setGlobalFactory instead. - */ -goog.net.XmlHttp.setFactory = function(factory, optionsFactory) { - goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( - goog.asserts.assert(factory), - goog.asserts.assert(optionsFactory))); -}; - - -/** - * Sets the global factory object. - * @param {!goog.net.XmlHttpFactory} factory New global factory object. - */ -goog.net.XmlHttp.setGlobalFactory = function(factory) { - goog.net.XmlHttp.factory_ = factory; -}; - - - -/** - * Default factory to use when creating xhr objects. You probably shouldn't be - * instantiating this directly, but rather using it via goog.net.XmlHttp. - * @extends {goog.net.XmlHttpFactory} - * @constructor - */ -goog.net.DefaultXmlHttpFactory = function() { - goog.net.XmlHttpFactory.call(this); -}; -goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory); - - -/** @override */ -goog.net.DefaultXmlHttpFactory.prototype.createInstance = function() { - var progId = this.getProgId_(); - if (progId) { - return new ActiveXObject(progId); - } else { - return new XMLHttpRequest(); - } -}; - - -/** @override */ -goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() { - var progId = this.getProgId_(); - var options = {}; - if (progId) { - options[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] = true; - options[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] = true; - } - return options; -}; - - -/** - * The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized. - * @type {string|undefined} - * @private - */ -goog.net.DefaultXmlHttpFactory.prototype.ieProgId_; - - -/** - * Initialize the private state used by other functions. - * @return {string} The ActiveX PROG ID string to use to create xhr's in IE. - * @private - */ -goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() { - if (goog.net.XmlHttp.ASSUME_NATIVE_XHR || - goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR) { - return ''; - } - - // The following blog post describes what PROG IDs to use to create the - // XMLHTTP object in Internet Explorer: - // http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx - // However we do not (yet) fully trust that this will be OK for old versions - // of IE on Win9x so we therefore keep the last 2. - if (!this.ieProgId_ && typeof XMLHttpRequest == 'undefined' && - typeof ActiveXObject != 'undefined') { - // Candidate Active X types. - var ACTIVE_X_IDENTS = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', - 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP']; - for (var i = 0; i < ACTIVE_X_IDENTS.length; i++) { - var candidate = ACTIVE_X_IDENTS[i]; - /** @preserveTry */ - try { - new ActiveXObject(candidate); - // NOTE(user): cannot assign progid and return candidate in one line - // because JSCompiler complaings: BUG 658126 - this.ieProgId_ = candidate; - return candidate; - } catch (e) { - // do nothing; try next choice - } - } - - // couldn't find any matches - throw Error('Could not create ActiveXObject. ActiveX might be disabled,' + - ' or MSXML might not be installed'); - } - - return /** @type {string} */ (this.ieProgId_); -}; - - -//Set the global factory to an instance of the default factory. -goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory()); - -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Simple utilities for dealing with URI strings. - * - * This is intended to be a lightweight alternative to constructing goog.Uri - * objects. Whereas goog.Uri adds several kilobytes to the binary regardless - * of how much of its functionality you use, this is designed to be a set of - * mostly-independent utilities so that the compiler includes only what is - * necessary for the task. Estimated savings of porting is 5k pre-gzip and - * 1.5k post-gzip. To ensure the savings remain, future developers should - * avoid adding new functionality to existing functions, but instead create - * new ones and factor out shared code. - * - * Many of these utilities have limited functionality, tailored to common - * cases. The query parameter utilities assume that the parameter keys are - * already encoded, since most keys are compile-time alphanumeric strings. The - * query parameter mutation utilities also do not tolerate fragment identifiers. - * - * By design, these functions can be slower than goog.Uri equivalents. - * Repeated calls to some of functions may be quadratic in behavior for IE, - * although the effect is somewhat limited given the 2kb limit. - * - * One advantage of the limited functionality here is that this approach is - * less sensitive to differences in URI encodings than goog.Uri, since these - * functions operate on strings directly, rather than decoding them and - * then re-encoding. - * - * Uses features of RFC 3986 for parsing/formatting URIs: - * http://www.ietf.org/rfc/rfc3986.txt - * - * @author gboyer@google.com (Garrett Boyer) - The "lightened" design. - */ - -goog.provide('goog.uri.utils'); -goog.provide('goog.uri.utils.ComponentIndex'); -goog.provide('goog.uri.utils.QueryArray'); -goog.provide('goog.uri.utils.QueryValue'); -goog.provide('goog.uri.utils.StandardQueryParam'); - -goog.require('goog.asserts'); -goog.require('goog.string'); - - -/** - * Character codes inlined to avoid object allocations due to charCode. - * @enum {number} - * @private - */ -goog.uri.utils.CharCode_ = { - AMPERSAND: 38, - EQUAL: 61, - HASH: 35, - QUESTION: 63 -}; - - -/** - * Builds a URI string from already-encoded parts. - * - * No encoding is performed. Any component may be omitted as either null or - * undefined. - * - * @param {?string=} opt_scheme The scheme such as 'http'. - * @param {?string=} opt_userInfo The user name before the '@'. - * @param {?string=} opt_domain The domain such as 'www.google.com', already - * URI-encoded. - * @param {(string|number|null)=} opt_port The port number. - * @param {?string=} opt_path The path, already URI-encoded. If it is not - * empty, it must begin with a slash. - * @param {?string=} opt_queryData The URI-encoded query data. - * @param {?string=} opt_fragment The URI-encoded fragment identifier. - * @return {string} The fully combined URI. - */ -goog.uri.utils.buildFromEncodedParts = function(opt_scheme, opt_userInfo, - opt_domain, opt_port, opt_path, opt_queryData, opt_fragment) { - var out = ''; - - if (opt_scheme) { - out += opt_scheme + ':'; - } - - if (opt_domain) { - out += '//'; - - if (opt_userInfo) { - out += opt_userInfo + '@'; - } - - out += opt_domain; - - if (opt_port) { - out += ':' + opt_port; - } - } - - if (opt_path) { - out += opt_path; - } - - if (opt_queryData) { - out += '?' + opt_queryData; - } - - if (opt_fragment) { - out += '#' + opt_fragment; - } - - return out; -}; - - -/** - * A regular expression for breaking a URI into its component parts. - * - * {@link http://www.ietf.org/rfc/rfc3986.txt} says in Appendix B - * As the "first-match-wins" algorithm is identical to the "greedy" - * disambiguation method used by POSIX regular expressions, it is natural and - * commonplace to use a regular expression for parsing the potential five - * components of a URI reference. - * - * The following line is the regular expression for breaking-down a - * well-formed URI reference into its components. - * - * <pre> - * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? - * 12 3 4 5 6 7 8 9 - * </pre> - * - * The numbers in the second line above are only to assist readability; they - * indicate the reference points for each subexpression (i.e., each paired - * parenthesis). We refer to the value matched for subexpression <n> as $<n>. - * For example, matching the above expression to - * <pre> - * http://www.ics.uci.edu/pub/ietf/uri/#Related - * </pre> - * results in the following subexpression matches: - * <pre> - * $1 = http: - * $2 = http - * $3 = //www.ics.uci.edu - * $4 = www.ics.uci.edu - * $5 = /pub/ietf/uri/ - * $6 = <undefined> - * $7 = <undefined> - * $8 = #Related - * $9 = Related - * </pre> - * where <undefined> indicates that the component is not present, as is the - * case for the query component in the above example. Therefore, we can - * determine the value of the five components as - * <pre> - * scheme = $2 - * authority = $4 - * path = $5 - * query = $7 - * fragment = $9 - * </pre> - * - * The regular expression has been modified slightly to expose the - * userInfo, domain, and port separately from the authority. - * The modified version yields - * <pre> - * $1 = http scheme - * $2 = <undefined> userInfo -\ - * $3 = www.ics.uci.edu domain | authority - * $4 = <undefined> port -/ - * $5 = /pub/ietf/uri/ path - * $6 = <undefined> query without ? - * $7 = Related fragment without # - * </pre> - * @type {!RegExp} - * @private - */ -goog.uri.utils.splitRe_ = new RegExp( - '^' + - '(?:' + - '([^:/?#.]+)' + // scheme - ignore special characters - // used by other URL parts such as :, - // ?, /, #, and . - ':)?' + - '(?://' + - '(?:([^/?#]*)@)?' + // userInfo - '([^/#?]*?)' + // domain - '(?::([0-9]+))?' + // port - '(?=[/#?]|$)' + // authority-terminating character - ')?' + - '([^?#]+)?' + // path - '(?:\\?([^#]*))?' + // query - '(?:#(.*))?' + // fragment - '$'); - - -/** - * The index of each URI component in the return value of goog.uri.utils.split. - * @enum {number} - */ -goog.uri.utils.ComponentIndex = { - SCHEME: 1, - USER_INFO: 2, - DOMAIN: 3, - PORT: 4, - PATH: 5, - QUERY_DATA: 6, - FRAGMENT: 7 -}; - - -/** - * Splits a URI into its component parts. - * - * Each component can be accessed via the component indices; for example: - * <pre> - * goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA]; - * </pre> - * - * @param {string} uri The URI string to examine. - * @return {!Array<string|undefined>} Each component still URI-encoded. - * Each component that is present will contain the encoded value, whereas - * components that are not present will be undefined or empty, depending - * on the browser's regular expression implementation. Never null, since - * arbitrary strings may still look like path names. - */ -goog.uri.utils.split = function(uri) { - // See @return comment -- never null. - return /** @type {!Array<string|undefined>} */ ( - uri.match(goog.uri.utils.splitRe_)); -}; - - -/** - * @param {?string} uri A possibly null string. - * @param {boolean=} opt_preserveReserved If true, percent-encoding of RFC-3986 - * reserved characters will not be removed. - * @return {?string} The string URI-decoded, or null if uri is null. - * @private - */ -goog.uri.utils.decodeIfPossible_ = function(uri, opt_preserveReserved) { - if (!uri) { - return uri; - } - - return opt_preserveReserved ? decodeURI(uri) : decodeURIComponent(uri); -}; - - -/** - * Gets a URI component by index. - * - * It is preferred to use the getPathEncoded() variety of functions ahead, - * since they are more readable. - * - * @param {goog.uri.utils.ComponentIndex} componentIndex The component index. - * @param {string} uri The URI to examine. - * @return {?string} The still-encoded component, or null if the component - * is not present. - * @private - */ -goog.uri.utils.getComponentByIndex_ = function(componentIndex, uri) { - // Convert undefined, null, and empty string into null. - return goog.uri.utils.split(uri)[componentIndex] || null; -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The protocol or scheme, or null if none. Does not - * include trailing colons or slashes. - */ -goog.uri.utils.getScheme = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.SCHEME, uri); -}; - - -/** - * Gets the effective scheme for the URL. If the URL is relative then the - * scheme is derived from the page's location. - * @param {string} uri The URI to examine. - * @return {string} The protocol or scheme, always lower case. - */ -goog.uri.utils.getEffectiveScheme = function(uri) { - var scheme = goog.uri.utils.getScheme(uri); - if (!scheme && goog.global.self && goog.global.self.location) { - var protocol = goog.global.self.location.protocol; - scheme = protocol.substr(0, protocol.length - 1); - } - // NOTE: When called from a web worker in Firefox 3.5, location maybe null. - // All other browsers with web workers support self.location from the worker. - return scheme ? scheme.toLowerCase() : ''; -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The user name still encoded, or null if none. - */ -goog.uri.utils.getUserInfoEncoded = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.USER_INFO, uri); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The decoded user info, or null if none. - */ -goog.uri.utils.getUserInfo = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getUserInfoEncoded(uri)); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The domain name still encoded, or null if none. - */ -goog.uri.utils.getDomainEncoded = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.DOMAIN, uri); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The decoded domain, or null if none. - */ -goog.uri.utils.getDomain = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getDomainEncoded(uri), true /* opt_preserveReserved */); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?number} The port number, or null if none. - */ -goog.uri.utils.getPort = function(uri) { - // Coerce to a number. If the result of getComponentByIndex_ is null or - // non-numeric, the number coersion yields NaN. This will then return - // null for all non-numeric cases (though also zero, which isn't a relevant - // port number). - return Number(goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.PORT, uri)) || null; -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The path still encoded, or null if none. Includes the - * leading slash, if any. - */ -goog.uri.utils.getPathEncoded = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.PATH, uri); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The decoded path, or null if none. Includes the leading - * slash, if any. - */ -goog.uri.utils.getPath = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getPathEncoded(uri), true /* opt_preserveReserved */); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The query data still encoded, or null if none. Does not - * include the question mark itself. - */ -goog.uri.utils.getQueryData = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.QUERY_DATA, uri); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The fragment identifier, or null if none. Does not - * include the hash mark itself. - */ -goog.uri.utils.getFragmentEncoded = function(uri) { - // The hash mark may not appear in any other part of the URL. - var hashIndex = uri.indexOf('#'); - return hashIndex < 0 ? null : uri.substr(hashIndex + 1); -}; - - -/** - * @param {string} uri The URI to examine. - * @param {?string} fragment The encoded fragment identifier, or null if none. - * Does not include the hash mark itself. - * @return {string} The URI with the fragment set. - */ -goog.uri.utils.setFragmentEncoded = function(uri, fragment) { - return goog.uri.utils.removeFragment(uri) + (fragment ? '#' + fragment : ''); -}; - - -/** - * @param {string} uri The URI to examine. - * @return {?string} The decoded fragment identifier, or null if none. Does - * not include the hash mark. - */ -goog.uri.utils.getFragment = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getFragmentEncoded(uri)); -}; - - -/** - * Extracts everything up to the port of the URI. - * @param {string} uri The URI string. - * @return {string} Everything up to and including the port. - */ -goog.uri.utils.getHost = function(uri) { - var pieces = goog.uri.utils.split(uri); - return goog.uri.utils.buildFromEncodedParts( - pieces[goog.uri.utils.ComponentIndex.SCHEME], - pieces[goog.uri.utils.ComponentIndex.USER_INFO], - pieces[goog.uri.utils.ComponentIndex.DOMAIN], - pieces[goog.uri.utils.ComponentIndex.PORT]); -}; - - -/** - * Extracts the path of the URL and everything after. - * @param {string} uri The URI string. - * @return {string} The URI, starting at the path and including the query - * parameters and fragment identifier. - */ -goog.uri.utils.getPathAndAfter = function(uri) { - var pieces = goog.uri.utils.split(uri); - return goog.uri.utils.buildFromEncodedParts(null, null, null, null, - pieces[goog.uri.utils.ComponentIndex.PATH], - pieces[goog.uri.utils.ComponentIndex.QUERY_DATA], - pieces[goog.uri.utils.ComponentIndex.FRAGMENT]); -}; - - -/** - * Gets the URI with the fragment identifier removed. - * @param {string} uri The URI to examine. - * @return {string} Everything preceding the hash mark. - */ -goog.uri.utils.removeFragment = function(uri) { - // The hash mark may not appear in any other part of the URL. - var hashIndex = uri.indexOf('#'); - return hashIndex < 0 ? uri : uri.substr(0, hashIndex); -}; - - -/** - * Ensures that two URI's have the exact same domain, scheme, and port. - * - * Unlike the version in goog.Uri, this checks protocol, and therefore is - * suitable for checking against the browser's same-origin policy. - * - * @param {string} uri1 The first URI. - * @param {string} uri2 The second URI. - * @return {boolean} Whether they have the same scheme, domain and port. - */ -goog.uri.utils.haveSameDomain = function(uri1, uri2) { - var pieces1 = goog.uri.utils.split(uri1); - var pieces2 = goog.uri.utils.split(uri2); - return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] == - pieces2[goog.uri.utils.ComponentIndex.DOMAIN] && - pieces1[goog.uri.utils.ComponentIndex.SCHEME] == - pieces2[goog.uri.utils.ComponentIndex.SCHEME] && - pieces1[goog.uri.utils.ComponentIndex.PORT] == - pieces2[goog.uri.utils.ComponentIndex.PORT]; -}; - - -/** - * Asserts that there are no fragment or query identifiers, only in uncompiled - * mode. - * @param {string} uri The URI to examine. - * @private - */ -goog.uri.utils.assertNoFragmentsOrQueries_ = function(uri) { - // NOTE: would use goog.asserts here, but jscompiler doesn't know that - // indexOf has no side effects. - if (goog.DEBUG && (uri.indexOf('#') >= 0 || uri.indexOf('?') >= 0)) { - throw Error('goog.uri.utils: Fragment or query identifiers are not ' + - 'supported: [' + uri + ']'); - } -}; - - -/** - * Supported query parameter values by the parameter serializing utilities. - * - * If a value is null or undefined, the key-value pair is skipped, as an easy - * way to omit parameters conditionally. Non-array parameters are converted - * to a string and URI encoded. Array values are expanded into multiple - * &key=value pairs, with each element stringized and URI-encoded. - * - * @typedef {*} - */ -goog.uri.utils.QueryValue; - - -/** - * An array representing a set of query parameters with alternating keys - * and values. - * - * Keys are assumed to be URI encoded already and live at even indices. See - * goog.uri.utils.QueryValue for details on how parameter values are encoded. - * - * Example: - * <pre> - * var data = [ - * // Simple param: ?name=BobBarker - * 'name', 'BobBarker', - * // Conditional param -- may be omitted entirely. - * 'specialDietaryNeeds', hasDietaryNeeds() ? getDietaryNeeds() : null, - * // Multi-valued param: &house=LosAngeles&house=NewYork&house=null - * 'house', ['LosAngeles', 'NewYork', null] - * ]; - * </pre> - * - * @typedef {!Array<string|goog.uri.utils.QueryValue>} - */ -goog.uri.utils.QueryArray; - - -/** - * Parses encoded query parameters and calls callback function for every - * parameter found in the string. - * - * Missing value of parameter (e.g. “…&key&…”) is treated as if the value was an - * empty string. Keys may be empty strings (e.g. “…&=value&…”) which also means - * that “…&=&…” and “…&&…” will result in an empty key and value. - * - * @param {string} encodedQuery Encoded query string excluding question mark at - * the beginning. - * @param {function(string, string)} callback Function called for every - * parameter found in query string. The first argument (name) will not be - * urldecoded (so the function is consistent with buildQueryData), but the - * second will. If the parameter has no value (i.e. “=” was not present) - * the second argument (value) will be an empty string. - */ -goog.uri.utils.parseQueryData = function(encodedQuery, callback) { - if (!encodedQuery) { - return; - } - var pairs = encodedQuery.split('&'); - for (var i = 0; i < pairs.length; i++) { - var indexOfEquals = pairs[i].indexOf('='); - var name = null; - var value = null; - if (indexOfEquals >= 0) { - name = pairs[i].substring(0, indexOfEquals); - value = pairs[i].substring(indexOfEquals + 1); - } else { - name = pairs[i]; - } - callback(name, value ? goog.string.urlDecode(value) : ''); - } -}; - - -/** - * Appends a URI and query data in a string buffer with special preconditions. - * - * Internal implementation utility, performing very few object allocations. - * - * @param {!Array<string|undefined>} buffer A string buffer. The first element - * must be the base URI, and may have a fragment identifier. If the array - * contains more than one element, the second element must be an ampersand, - * and may be overwritten, depending on the base URI. Undefined elements - * are treated as empty-string. - * @return {string} The concatenated URI and query data. - * @private - */ -goog.uri.utils.appendQueryData_ = function(buffer) { - if (buffer[1]) { - // At least one query parameter was added. We need to check the - // punctuation mark, which is currently an ampersand, and also make sure - // there aren't any interfering fragment identifiers. - var baseUri = /** @type {string} */ (buffer[0]); - var hashIndex = baseUri.indexOf('#'); - if (hashIndex >= 0) { - // Move the fragment off the base part of the URI into the end. - buffer.push(baseUri.substr(hashIndex)); - buffer[0] = baseUri = baseUri.substr(0, hashIndex); - } - var questionIndex = baseUri.indexOf('?'); - if (questionIndex < 0) { - // No question mark, so we need a question mark instead of an ampersand. - buffer[1] = '?'; - } else if (questionIndex == baseUri.length - 1) { - // Question mark is the very last character of the existing URI, so don't - // append an additional delimiter. - buffer[1] = undefined; - } - } - - return buffer.join(''); -}; - - -/** - * Appends key=value pairs to an array, supporting multi-valued objects. - * @param {string} key The key prefix. - * @param {goog.uri.utils.QueryValue} value The value to serialize. - * @param {!Array<string>} pairs The array to which the 'key=value' strings - * should be appended. - * @private - */ -goog.uri.utils.appendKeyValuePairs_ = function(key, value, pairs) { - if (goog.isArray(value)) { - // Convince the compiler it's an array. - goog.asserts.assertArray(value); - for (var j = 0; j < value.length; j++) { - // Convert to string explicitly, to short circuit the null and array - // logic in this function -- this ensures that null and undefined get - // written as literal 'null' and 'undefined', and arrays don't get - // expanded out but instead encoded in the default way. - goog.uri.utils.appendKeyValuePairs_(key, String(value[j]), pairs); - } - } else if (value != null) { - // Skip a top-level null or undefined entirely. - pairs.push('&', key, - // Check for empty string. Zero gets encoded into the url as literal - // strings. For empty string, skip the equal sign, to be consistent - // with UriBuilder.java. - value === '' ? '' : '=', - goog.string.urlEncode(value)); - } -}; - - -/** - * Builds a buffer of query data from a sequence of alternating keys and values. - * - * @param {!Array<string|undefined>} buffer A string buffer to append to. The - * first element appended will be an '&', and may be replaced by the caller. - * @param {!goog.uri.utils.QueryArray|!Arguments} keysAndValues An array with - * alternating keys and values -- see the typedef. - * @param {number=} opt_startIndex A start offset into the arary, defaults to 0. - * @return {!Array<string|undefined>} The buffer argument. - * @private - */ -goog.uri.utils.buildQueryDataBuffer_ = function( - buffer, keysAndValues, opt_startIndex) { - goog.asserts.assert(Math.max(keysAndValues.length - (opt_startIndex || 0), - 0) % 2 == 0, 'goog.uri.utils: Key/value lists must be even in length.'); - - for (var i = opt_startIndex || 0; i < keysAndValues.length; i += 2) { - goog.uri.utils.appendKeyValuePairs_( - keysAndValues[i], keysAndValues[i + 1], buffer); - } - - return buffer; -}; - - -/** - * Builds a query data string from a sequence of alternating keys and values. - * Currently generates "&key&" for empty args. - * - * @param {goog.uri.utils.QueryArray} keysAndValues Alternating keys and - * values. See the typedef. - * @param {number=} opt_startIndex A start offset into the arary, defaults to 0. - * @return {string} The encoded query string, in the form 'a=1&b=2'. - */ -goog.uri.utils.buildQueryData = function(keysAndValues, opt_startIndex) { - var buffer = goog.uri.utils.buildQueryDataBuffer_( - [], keysAndValues, opt_startIndex); - buffer[0] = ''; // Remove the leading ampersand. - return buffer.join(''); -}; - - -/** - * Builds a buffer of query data from a map. - * - * @param {!Array<string|undefined>} buffer A string buffer to append to. The - * first element appended will be an '&', and may be replaced by the caller. - * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys - * are URI-encoded parameter keys, and the values conform to the contract - * specified in the goog.uri.utils.QueryValue typedef. - * @return {!Array<string|undefined>} The buffer argument. - * @private - */ -goog.uri.utils.buildQueryDataBufferFromMap_ = function(buffer, map) { - for (var key in map) { - goog.uri.utils.appendKeyValuePairs_(key, map[key], buffer); - } - - return buffer; -}; - - -/** - * Builds a query data string from a map. - * Currently generates "&key&" for empty args. - * - * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys - * are URI-encoded parameter keys, and the values are arbitrary types - * or arrays. Keys with a null value are dropped. - * @return {string} The encoded query string, in the form 'a=1&b=2'. - */ -goog.uri.utils.buildQueryDataFromMap = function(map) { - var buffer = goog.uri.utils.buildQueryDataBufferFromMap_([], map); - buffer[0] = ''; - return buffer.join(''); -}; - - -/** - * Appends URI parameters to an existing URI. - * - * The variable arguments may contain alternating keys and values. Keys are - * assumed to be already URI encoded. The values should not be URI-encoded, - * and will instead be encoded by this function. - * <pre> - * appendParams('http://www.foo.com?existing=true', - * 'key1', 'value1', - * 'key2', 'value?willBeEncoded', - * 'key3', ['valueA', 'valueB', 'valueC'], - * 'key4', null); - * result: 'http://www.foo.com?existing=true&' + - * 'key1=value1&' + - * 'key2=value%3FwillBeEncoded&' + - * 'key3=valueA&key3=valueB&key3=valueC' - * </pre> - * - * A single call to this function will not exhibit quadratic behavior in IE, - * whereas multiple repeated calls may, although the effect is limited by - * fact that URL's generally can't exceed 2kb. - * - * @param {string} uri The original URI, which may already have query data. - * @param {...(goog.uri.utils.QueryArray|string|goog.uri.utils.QueryValue)} var_args - * An array or argument list conforming to goog.uri.utils.QueryArray. - * @return {string} The URI with all query parameters added. - */ -goog.uri.utils.appendParams = function(uri, var_args) { - return goog.uri.utils.appendQueryData_( - arguments.length == 2 ? - goog.uri.utils.buildQueryDataBuffer_([uri], arguments[1], 0) : - goog.uri.utils.buildQueryDataBuffer_([uri], arguments, 1)); -}; - - -/** - * Appends query parameters from a map. - * - * @param {string} uri The original URI, which may already have query data. - * @param {!Object<goog.uri.utils.QueryValue>} map An object where keys are - * URI-encoded parameter keys, and the values are arbitrary types or arrays. - * Keys with a null value are dropped. - * @return {string} The new parameters. - */ -goog.uri.utils.appendParamsFromMap = function(uri, map) { - return goog.uri.utils.appendQueryData_( - goog.uri.utils.buildQueryDataBufferFromMap_([uri], map)); -}; - - -/** - * Appends a single URI parameter. - * - * Repeated calls to this can exhibit quadratic behavior in IE6 due to the - * way string append works, though it should be limited given the 2kb limit. - * - * @param {string} uri The original URI, which may already have query data. - * @param {string} key The key, which must already be URI encoded. - * @param {*=} opt_value The value, which will be stringized and encoded - * (assumed not already to be encoded). If omitted, undefined, or null, the - * key will be added as a valueless parameter. - * @return {string} The URI with the query parameter added. - */ -goog.uri.utils.appendParam = function(uri, key, opt_value) { - var paramArr = [uri, '&', key]; - if (goog.isDefAndNotNull(opt_value)) { - paramArr.push('=', goog.string.urlEncode(opt_value)); - } - return goog.uri.utils.appendQueryData_(paramArr); -}; - - -/** - * Finds the next instance of a query parameter with the specified name. - * - * Does not instantiate any objects. - * - * @param {string} uri The URI to search. May contain a fragment identifier - * if opt_hashIndex is specified. - * @param {number} startIndex The index to begin searching for the key at. A - * match may be found even if this is one character after the ampersand. - * @param {string} keyEncoded The URI-encoded key. - * @param {number} hashOrEndIndex Index to stop looking at. If a hash - * mark is present, it should be its index, otherwise it should be the - * length of the string. - * @return {number} The position of the first character in the key's name, - * immediately after either a question mark or a dot. - * @private - */ -goog.uri.utils.findParam_ = function( - uri, startIndex, keyEncoded, hashOrEndIndex) { - var index = startIndex; - var keyLength = keyEncoded.length; - - // Search for the key itself and post-filter for surronuding punctuation, - // rather than expensively building a regexp. - while ((index = uri.indexOf(keyEncoded, index)) >= 0 && - index < hashOrEndIndex) { - var precedingChar = uri.charCodeAt(index - 1); - // Ensure that the preceding character is '&' or '?'. - if (precedingChar == goog.uri.utils.CharCode_.AMPERSAND || - precedingChar == goog.uri.utils.CharCode_.QUESTION) { - // Ensure the following character is '&', '=', '#', or NaN - // (end of string). - var followingChar = uri.charCodeAt(index + keyLength); - if (!followingChar || - followingChar == goog.uri.utils.CharCode_.EQUAL || - followingChar == goog.uri.utils.CharCode_.AMPERSAND || - followingChar == goog.uri.utils.CharCode_.HASH) { - return index; - } - } - index += keyLength + 1; - } - - return -1; -}; - - -/** - * Regular expression for finding a hash mark or end of string. - * @type {RegExp} - * @private - */ -goog.uri.utils.hashOrEndRe_ = /#|$/; - - -/** - * Determines if the URI contains a specific key. - * - * Performs no object instantiations. - * - * @param {string} uri The URI to process. May contain a fragment - * identifier. - * @param {string} keyEncoded The URI-encoded key. Case-sensitive. - * @return {boolean} Whether the key is present. - */ -goog.uri.utils.hasParam = function(uri, keyEncoded) { - return goog.uri.utils.findParam_(uri, 0, keyEncoded, - uri.search(goog.uri.utils.hashOrEndRe_)) >= 0; -}; - - -/** - * Gets the first value of a query parameter. - * @param {string} uri The URI to process. May contain a fragment. - * @param {string} keyEncoded The URI-encoded key. Case-sensitive. - * @return {?string} The first value of the parameter (URI-decoded), or null - * if the parameter is not found. - */ -goog.uri.utils.getParamValue = function(uri, keyEncoded) { - var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); - var foundIndex = goog.uri.utils.findParam_( - uri, 0, keyEncoded, hashOrEndIndex); - - if (foundIndex < 0) { - return null; - } else { - var endPosition = uri.indexOf('&', foundIndex); - if (endPosition < 0 || endPosition > hashOrEndIndex) { - endPosition = hashOrEndIndex; - } - // Progress forth to the end of the "key=" or "key&" substring. - foundIndex += keyEncoded.length + 1; - // Use substr, because it (unlike substring) will return empty string - // if foundIndex > endPosition. - return goog.string.urlDecode( - uri.substr(foundIndex, endPosition - foundIndex)); - } -}; - - -/** - * Gets all values of a query parameter. - * @param {string} uri The URI to process. May contain a fragment. - * @param {string} keyEncoded The URI-encoded key. Case-sensitive. - * @return {!Array<string>} All URI-decoded values with the given key. - * If the key is not found, this will have length 0, but never be null. - */ -goog.uri.utils.getParamValues = function(uri, keyEncoded) { - var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); - var position = 0; - var foundIndex; - var result = []; - - while ((foundIndex = goog.uri.utils.findParam_( - uri, position, keyEncoded, hashOrEndIndex)) >= 0) { - // Find where this parameter ends, either the '&' or the end of the - // query parameters. - position = uri.indexOf('&', foundIndex); - if (position < 0 || position > hashOrEndIndex) { - position = hashOrEndIndex; - } - - // Progress forth to the end of the "key=" or "key&" substring. - foundIndex += keyEncoded.length + 1; - // Use substr, because it (unlike substring) will return empty string - // if foundIndex > position. - result.push(goog.string.urlDecode(uri.substr( - foundIndex, position - foundIndex))); - } - - return result; -}; - - -/** - * Regexp to find trailing question marks and ampersands. - * @type {RegExp} - * @private - */ -goog.uri.utils.trailingQueryPunctuationRe_ = /[?&]($|#)/; - - -/** - * Removes all instances of a query parameter. - * @param {string} uri The URI to process. Must not contain a fragment. - * @param {string} keyEncoded The URI-encoded key. - * @return {string} The URI with all instances of the parameter removed. - */ -goog.uri.utils.removeParam = function(uri, keyEncoded) { - var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); - var position = 0; - var foundIndex; - var buffer = []; - - // Look for a query parameter. - while ((foundIndex = goog.uri.utils.findParam_( - uri, position, keyEncoded, hashOrEndIndex)) >= 0) { - // Get the portion of the query string up to, but not including, the ? - // or & starting the parameter. - buffer.push(uri.substring(position, foundIndex)); - // Progress to immediately after the '&'. If not found, go to the end. - // Avoid including the hash mark. - position = Math.min((uri.indexOf('&', foundIndex) + 1) || hashOrEndIndex, - hashOrEndIndex); - } - - // Append everything that is remaining. - buffer.push(uri.substr(position)); - - // Join the buffer, and remove trailing punctuation that remains. - return buffer.join('').replace( - goog.uri.utils.trailingQueryPunctuationRe_, '$1'); -}; - - -/** - * Replaces all existing definitions of a parameter with a single definition. - * - * Repeated calls to this can exhibit quadratic behavior due to the need to - * find existing instances and reconstruct the string, though it should be - * limited given the 2kb limit. Consider using appendParams to append multiple - * parameters in bulk. - * - * @param {string} uri The original URI, which may already have query data. - * @param {string} keyEncoded The key, which must already be URI encoded. - * @param {*} value The value, which will be stringized and encoded (assumed - * not already to be encoded). - * @return {string} The URI with the query parameter added. - */ -goog.uri.utils.setParam = function(uri, keyEncoded, value) { - return goog.uri.utils.appendParam( - goog.uri.utils.removeParam(uri, keyEncoded), keyEncoded, value); -}; - - -/** - * Generates a URI path using a given URI and a path with checks to - * prevent consecutive "//". The baseUri passed in must not contain - * query or fragment identifiers. The path to append may not contain query or - * fragment identifiers. - * - * @param {string} baseUri URI to use as the base. - * @param {string} path Path to append. - * @return {string} Updated URI. - */ -goog.uri.utils.appendPath = function(baseUri, path) { - goog.uri.utils.assertNoFragmentsOrQueries_(baseUri); - - // Remove any trailing '/' - if (goog.string.endsWith(baseUri, '/')) { - baseUri = baseUri.substr(0, baseUri.length - 1); - } - // Remove any leading '/' - if (goog.string.startsWith(path, '/')) { - path = path.substr(1); - } - return goog.string.buildString(baseUri, '/', path); -}; - - -/** - * Replaces the path. - * @param {string} uri URI to use as the base. - * @param {string} path New path. - * @return {string} Updated URI. - */ -goog.uri.utils.setPath = function(uri, path) { - // Add any missing '/'. - if (!goog.string.startsWith(path, '/')) { - path = '/' + path; - } - var parts = goog.uri.utils.split(uri); - return goog.uri.utils.buildFromEncodedParts( - parts[goog.uri.utils.ComponentIndex.SCHEME], - parts[goog.uri.utils.ComponentIndex.USER_INFO], - parts[goog.uri.utils.ComponentIndex.DOMAIN], - parts[goog.uri.utils.ComponentIndex.PORT], - path, - parts[goog.uri.utils.ComponentIndex.QUERY_DATA], - parts[goog.uri.utils.ComponentIndex.FRAGMENT]); -}; - - -/** - * Standard supported query parameters. - * @enum {string} - */ -goog.uri.utils.StandardQueryParam = { - - /** Unused parameter for unique-ifying. */ - RANDOM: 'zx' -}; - - -/** - * Sets the zx parameter of a URI to a random value. - * @param {string} uri Any URI. - * @return {string} That URI with the "zx" parameter added or replaced to - * contain a random string. - */ -goog.uri.utils.makeUnique = function(uri) { - return goog.uri.utils.setParam(uri, - goog.uri.utils.StandardQueryParam.RANDOM, goog.string.getRandomString()); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Wrapper class for handling XmlHttpRequests. - * - * One off requests can be sent through goog.net.XhrIo.send() or an - * instance can be created to send multiple requests. Each request uses its - * own XmlHttpRequest object and handles clearing of the event callback to - * ensure no leaks. - * - * XhrIo is event based, it dispatches events on success, failure, finishing, - * ready-state change, or progress. - * - * The ready-state or timeout event fires first, followed by - * a generic completed event. Then the abort, error, or success event - * is fired as appropriate. Progress events are fired as they are - * received. Lastly, the ready event will fire to indicate that the - * object may be used to make another request. - * - * The error event may also be called before completed and - * ready-state-change if the XmlHttpRequest.open() or .send() methods throw. - * - * This class does not support multiple requests, queuing, or prioritization. - * - * When progress events are supported by the browser, and progress is - * enabled via .setProgressEventsEnabled(true), the - * goog.net.EventType.PROGRESS event will be the re-dispatched browser - * progress event. - * - * Tested = IE6, FF1.5, Safari, Opera 8.5 - * - * TODO(user): Error cases aren't playing nicely in Safari. - * - */ - - -goog.provide('goog.net.XhrIo'); -goog.provide('goog.net.XhrIo.ResponseType'); - -goog.require('goog.Timer'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.events.EventTarget'); -goog.require('goog.json'); -goog.require('goog.log'); -goog.require('goog.net.ErrorCode'); -goog.require('goog.net.EventType'); -goog.require('goog.net.HttpStatus'); -goog.require('goog.net.XmlHttp'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.structs'); -goog.require('goog.structs.Map'); -goog.require('goog.uri.utils'); -goog.require('goog.userAgent'); - -goog.forwardDeclare('goog.Uri'); - - - -/** - * Basic class for handling XMLHttpRequests. - * @param {goog.net.XmlHttpFactory=} opt_xmlHttpFactory Factory to use when - * creating XMLHttpRequest objects. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.XhrIo = function(opt_xmlHttpFactory) { - goog.net.XhrIo.base(this, 'constructor'); - - /** - * Map of default headers to add to every request, use: - * XhrIo.headers.set(name, value) - * @type {!goog.structs.Map} - */ - this.headers = new goog.structs.Map(); - - /** - * Optional XmlHttpFactory - * @private {goog.net.XmlHttpFactory} - */ - this.xmlHttpFactory_ = opt_xmlHttpFactory || null; - - /** - * Whether XMLHttpRequest is active. A request is active from the time send() - * is called until onReadyStateChange() is complete, or error() or abort() - * is called. - * @private {boolean} - */ - this.active_ = false; - - /** - * The XMLHttpRequest object that is being used for the transfer. - * @private {?goog.net.XhrLike.OrNative} - */ - this.xhr_ = null; - - /** - * The options to use with the current XMLHttpRequest object. - * @private {Object} - */ - this.xhrOptions_ = null; - - /** - * Last URL that was requested. - * @private {string|goog.Uri} - */ - this.lastUri_ = ''; - - /** - * Method for the last request. - * @private {string} - */ - this.lastMethod_ = ''; - - /** - * Last error code. - * @private {!goog.net.ErrorCode} - */ - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - - /** - * Last error message. - * @private {Error|string} - */ - this.lastError_ = ''; - - /** - * Used to ensure that we don't dispatch an multiple ERROR events. This can - * happen in IE when it does a synchronous load and one error is handled in - * the ready statte change and one is handled due to send() throwing an - * exception. - * @private {boolean} - */ - this.errorDispatched_ = false; - - /** - * Used to make sure we don't fire the complete event from inside a send call. - * @private {boolean} - */ - this.inSend_ = false; - - /** - * Used in determining if a call to {@link #onReadyStateChange_} is from - * within a call to this.xhr_.open. - * @private {boolean} - */ - this.inOpen_ = false; - - /** - * Used in determining if a call to {@link #onReadyStateChange_} is from - * within a call to this.xhr_.abort. - * @private {boolean} - */ - this.inAbort_ = false; - - /** - * Number of milliseconds after which an incomplete request will be aborted - * and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no timeout - * is set. - * @private {number} - */ - this.timeoutInterval_ = 0; - - /** - * Timer to track request timeout. - * @private {?number} - */ - this.timeoutId_ = null; - - /** - * The requested type for the response. The empty string means use the default - * XHR behavior. - * @private {goog.net.XhrIo.ResponseType} - */ - this.responseType_ = goog.net.XhrIo.ResponseType.DEFAULT; - - /** - * Whether a "credentialed" request is to be sent (one that is aware of - * cookies and authentication). This is applicable only for cross-domain - * requests and more recent browsers that support this part of the HTTP Access - * Control standard. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-withcredentials-attribute - * - * @private {boolean} - */ - this.withCredentials_ = false; - - /** - * Whether progress events are enabled for this request. This is - * disabled by default because setting a progress event handler - * causes pre-flight OPTIONS requests to be sent for CORS requests, - * even in cases where a pre-flight request would not otherwise be - * sent. - * - * @see http://xhr.spec.whatwg.org/#security-considerations - * - * Note that this can cause problems for Firefox 22 and below, as an - * older "LSProgressEvent" will be dispatched by the browser. That - * progress event is no longer supported, and can lead to failures, - * including throwing exceptions. - * - * @see http://bugzilla.mozilla.org/show_bug.cgi?id=845631 - * @see b/23469793 - * - * @private {boolean} - */ - this.progressEventsEnabled_ = false; - - /** - * True if we can use XMLHttpRequest's timeout directly. - * @private {boolean} - */ - this.useXhr2Timeout_ = false; -}; -goog.inherits(goog.net.XhrIo, goog.events.EventTarget); - - -/** - * Response types that may be requested for XMLHttpRequests. - * @enum {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute - */ -goog.net.XhrIo.ResponseType = { - DEFAULT: '', - TEXT: 'text', - DOCUMENT: 'document', - // Not supported as of Chrome 10.0.612.1 dev - BLOB: 'blob', - ARRAY_BUFFER: 'arraybuffer' -}; - - -/** - * A reference to the XhrIo logger - * @private {goog.debug.Logger} - * @const - */ -goog.net.XhrIo.prototype.logger_ = - goog.log.getLogger('goog.net.XhrIo'); - - -/** - * The Content-Type HTTP header name - * @type {string} - */ -goog.net.XhrIo.CONTENT_TYPE_HEADER = 'Content-Type'; - - -/** - * The pattern matching the 'http' and 'https' URI schemes - * @type {!RegExp} - */ -goog.net.XhrIo.HTTP_SCHEME_PATTERN = /^https?$/i; - - -/** - * The methods that typically come along with form data. We set different - * headers depending on whether the HTTP action is one of these. - */ -goog.net.XhrIo.METHODS_WITH_FORM_DATA = ['POST', 'PUT']; - - -/** - * The Content-Type HTTP header value for a url-encoded form - * @type {string} - */ -goog.net.XhrIo.FORM_CONTENT_TYPE = - 'application/x-www-form-urlencoded;charset=utf-8'; - - -/** - * The XMLHttpRequest Level two timeout delay ms property name. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - * - * @private {string} - * @const - */ -goog.net.XhrIo.XHR2_TIMEOUT_ = 'timeout'; - - -/** - * The XMLHttpRequest Level two ontimeout handler property name. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - * - * @private {string} - * @const - */ -goog.net.XhrIo.XHR2_ON_TIMEOUT_ = 'ontimeout'; - - -/** - * All non-disposed instances of goog.net.XhrIo created - * by {@link goog.net.XhrIo.send} are in this Array. - * @see goog.net.XhrIo.cleanup - * @private {!Array<!goog.net.XhrIo>} - */ -goog.net.XhrIo.sendInstances_ = []; - - -/** - * Static send that creates a short lived instance of XhrIo to send the - * request. - * @see goog.net.XhrIo.cleanup - * @param {string|goog.Uri} url Uri to make request to. - * @param {?function(this:goog.net.XhrIo, ?)=} opt_callback Callback function - * for when request is complete. - * @param {string=} opt_method Send method, default: GET. - * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} - * opt_content Body data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - * @param {number=} opt_timeoutInterval Number of milliseconds after which an - * incomplete request will be aborted; 0 means no timeout is set. - * @param {boolean=} opt_withCredentials Whether to send credentials with the - * request. Default to false. See {@link goog.net.XhrIo#setWithCredentials}. - * @return {!goog.net.XhrIo} The sent XhrIo. - */ -goog.net.XhrIo.send = function(url, opt_callback, opt_method, opt_content, - opt_headers, opt_timeoutInterval, - opt_withCredentials) { - var x = new goog.net.XhrIo(); - goog.net.XhrIo.sendInstances_.push(x); - if (opt_callback) { - x.listen(goog.net.EventType.COMPLETE, opt_callback); - } - x.listenOnce(goog.net.EventType.READY, x.cleanupSend_); - if (opt_timeoutInterval) { - x.setTimeoutInterval(opt_timeoutInterval); - } - if (opt_withCredentials) { - x.setWithCredentials(opt_withCredentials); - } - x.send(url, opt_method, opt_content, opt_headers); - return x; -}; - - -/** - * Disposes all non-disposed instances of goog.net.XhrIo created by - * {@link goog.net.XhrIo.send}. - * {@link goog.net.XhrIo.send} cleans up the goog.net.XhrIo instance - * it creates when the request completes or fails. However, if - * the request never completes, then the goog.net.XhrIo is not disposed. - * This can occur if the window is unloaded before the request completes. - * We could have {@link goog.net.XhrIo.send} return the goog.net.XhrIo - * it creates and make the client of {@link goog.net.XhrIo.send} be - * responsible for disposing it in this case. However, this makes things - * significantly more complicated for the client, and the whole point - * of {@link goog.net.XhrIo.send} is that it's simple and easy to use. - * Clients of {@link goog.net.XhrIo.send} should call - * {@link goog.net.XhrIo.cleanup} when doing final - * cleanup on window unload. - */ -goog.net.XhrIo.cleanup = function() { - var instances = goog.net.XhrIo.sendInstances_; - while (instances.length) { - instances.pop().dispose(); - } -}; - - -/** - * Installs exception protection for all entry point introduced by - * goog.net.XhrIo instances which are not protected by - * {@link goog.debug.ErrorHandler#protectWindowSetTimeout}, - * {@link goog.debug.ErrorHandler#protectWindowSetInterval}, or - * {@link goog.events.protectBrowserEventEntryPoint}. - * - * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry point(s). - */ -goog.net.XhrIo.protectEntryPoints = function(errorHandler) { - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = - errorHandler.protectEntryPoint( - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); -}; - - -/** - * Disposes of the specified goog.net.XhrIo created by - * {@link goog.net.XhrIo.send} and removes it from - * {@link goog.net.XhrIo.pendingStaticSendInstances_}. - * @private - */ -goog.net.XhrIo.prototype.cleanupSend_ = function() { - this.dispose(); - goog.array.remove(goog.net.XhrIo.sendInstances_, this); -}; - - -/** - * Returns the number of milliseconds after which an incomplete request will be - * aborted, or 0 if no timeout is set. - * @return {number} Timeout interval in milliseconds. - */ -goog.net.XhrIo.prototype.getTimeoutInterval = function() { - return this.timeoutInterval_; -}; - - -/** - * Sets the number of milliseconds after which an incomplete request will be - * aborted and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no - * timeout is set. - * @param {number} ms Timeout interval in milliseconds; 0 means none. - */ -goog.net.XhrIo.prototype.setTimeoutInterval = function(ms) { - this.timeoutInterval_ = Math.max(0, ms); -}; - - -/** - * Sets the desired type for the response. At time of writing, this is only - * supported in very recent versions of WebKit (10.0.612.1 dev and later). - * - * If this is used, the response may only be accessed via {@link #getResponse}. - * - * @param {goog.net.XhrIo.ResponseType} type The desired type for the response. - */ -goog.net.XhrIo.prototype.setResponseType = function(type) { - this.responseType_ = type; -}; - - -/** - * Gets the desired type for the response. - * @return {goog.net.XhrIo.ResponseType} The desired type for the response. - */ -goog.net.XhrIo.prototype.getResponseType = function() { - return this.responseType_; -}; - - -/** - * Sets whether a "credentialed" request that is aware of cookie and - * authentication information should be made. This option is only supported by - * browsers that support HTTP Access Control. As of this writing, this option - * is not supported in IE. - * - * @param {boolean} withCredentials Whether this should be a "credentialed" - * request. - */ -goog.net.XhrIo.prototype.setWithCredentials = function(withCredentials) { - this.withCredentials_ = withCredentials; -}; - - -/** - * Gets whether a "credentialed" request is to be sent. - * @return {boolean} The desired type for the response. - */ -goog.net.XhrIo.prototype.getWithCredentials = function() { - return this.withCredentials_; -}; - - -/** - * Sets whether progress events are enabled for this request. Note - * that progress events require pre-flight OPTIONS request handling - * for CORS requests, and may cause trouble with older browsers. See - * progressEventsEnabled_ for details. - * @param {boolean} enabled Whether progress events should be enabled. - */ -goog.net.XhrIo.prototype.setProgressEventsEnabled = function(enabled) { - this.progressEventsEnabled_ = enabled; -}; - - -/** - * Gets whether progress events are enabled. - * @return {boolean} Whether progress events are enabled for this request. - */ -goog.net.XhrIo.prototype.getProgressEventsEnabled = function() { - return this.progressEventsEnabled_; -}; - - -/** - * Instance send that actually uses XMLHttpRequest to make a server call. - * @param {string|goog.Uri} url Uri to make request to. - * @param {string=} opt_method Send method, default: GET. - * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} - * opt_content Body data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - */ -goog.net.XhrIo.prototype.send = function(url, opt_method, opt_content, - opt_headers) { - if (this.xhr_) { - throw Error('[goog.net.XhrIo] Object is active with another request=' + - this.lastUri_ + '; newUri=' + url); - } - - var method = opt_method ? opt_method.toUpperCase() : 'GET'; - - this.lastUri_ = url; - this.lastError_ = ''; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - this.lastMethod_ = method; - this.errorDispatched_ = false; - this.active_ = true; - - // Use the factory to create the XHR object and options - this.xhr_ = this.createXhr(); - this.xhrOptions_ = this.xmlHttpFactory_ ? - this.xmlHttpFactory_.getOptions() : goog.net.XmlHttp.getOptions(); - - // Set up the onreadystatechange callback - this.xhr_.onreadystatechange = goog.bind(this.onReadyStateChange_, this); - - // Set up upload/download progress events, if progress events are supported. - if (this.getProgressEventsEnabled() && 'onprogress' in this.xhr_) { - this.xhr_.onprogress = goog.bind(this.onProgressHandler_, this); - if (this.xhr_.upload) { - this.xhr_.upload.onprogress = goog.bind(this.onProgressHandler_, this); - } - } - - /** - * Try to open the XMLHttpRequest (always async), if an error occurs here it - * is generally permission denied - * @preserveTry - */ - try { - goog.log.fine(this.logger_, this.formatMsg_('Opening Xhr')); - this.inOpen_ = true; - this.xhr_.open(method, String(url), true); // Always async! - this.inOpen_ = false; - } catch (err) { - goog.log.fine(this.logger_, - this.formatMsg_('Error opening Xhr: ' + err.message)); - this.error_(goog.net.ErrorCode.EXCEPTION, err); - return; - } - - // We can't use null since this won't allow requests with form data to have a - // content length specified which will cause some proxies to return a 411 - // error. - var content = opt_content || ''; - - var headers = this.headers.clone(); - - // Add headers specific to this request - if (opt_headers) { - goog.structs.forEach(opt_headers, function(value, key) { - headers.set(key, value); - }); - } - - // Find whether a content type header is set, ignoring case. - // HTTP header names are case-insensitive. See: - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 - var contentTypeKey = goog.array.find(headers.getKeys(), - goog.net.XhrIo.isContentTypeHeader_); - - var contentIsFormData = (goog.global['FormData'] && - (content instanceof goog.global['FormData'])); - if (goog.array.contains(goog.net.XhrIo.METHODS_WITH_FORM_DATA, method) && - !contentTypeKey && !contentIsFormData) { - // For requests typically with form data, default to the url-encoded form - // content type unless this is a FormData request. For FormData, - // the browser will automatically add a multipart/form-data content type - // with an appropriate multipart boundary. - headers.set(goog.net.XhrIo.CONTENT_TYPE_HEADER, - goog.net.XhrIo.FORM_CONTENT_TYPE); - } - - // Add the headers to the Xhr object - headers.forEach(function(value, key) { - this.xhr_.setRequestHeader(key, value); - }, this); - - if (this.responseType_) { - this.xhr_.responseType = this.responseType_; - } - - if (goog.object.containsKey(this.xhr_, 'withCredentials')) { - this.xhr_.withCredentials = this.withCredentials_; - } - - /** - * Try to send the request, or other wise report an error (404 not found). - * @preserveTry - */ - try { - this.cleanUpTimeoutTimer_(); // Paranoid, should never be running. - if (this.timeoutInterval_ > 0) { - this.useXhr2Timeout_ = goog.net.XhrIo.shouldUseXhr2Timeout_(this.xhr_); - goog.log.fine(this.logger_, this.formatMsg_('Will abort after ' + - this.timeoutInterval_ + 'ms if incomplete, xhr2 ' + - this.useXhr2Timeout_)); - if (this.useXhr2Timeout_) { - this.xhr_[goog.net.XhrIo.XHR2_TIMEOUT_] = this.timeoutInterval_; - this.xhr_[goog.net.XhrIo.XHR2_ON_TIMEOUT_] = - goog.bind(this.timeout_, this); - } else { - this.timeoutId_ = goog.Timer.callOnce(this.timeout_, - this.timeoutInterval_, this); - } - } - goog.log.fine(this.logger_, this.formatMsg_('Sending request')); - this.inSend_ = true; - this.xhr_.send(content); - this.inSend_ = false; - - } catch (err) { - goog.log.fine(this.logger_, this.formatMsg_('Send error: ' + err.message)); - this.error_(goog.net.ErrorCode.EXCEPTION, err); - } -}; - - -/** - * Determines if the argument is an XMLHttpRequest that supports the level 2 - * timeout value and event. - * - * Currently, FF 21.0 OS X has the fields but won't actually call the timeout - * handler. Perhaps the confusion in the bug referenced below hasn't - * entirely been resolved. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - * @see https://bugzilla.mozilla.org/show_bug.cgi?id=525816 - * - * @param {!goog.net.XhrLike.OrNative} xhr The request. - * @return {boolean} True if the request supports level 2 timeout. - * @private - */ -goog.net.XhrIo.shouldUseXhr2Timeout_ = function(xhr) { - return goog.userAgent.IE && - goog.userAgent.isVersionOrHigher(9) && - goog.isNumber(xhr[goog.net.XhrIo.XHR2_TIMEOUT_]) && - goog.isDef(xhr[goog.net.XhrIo.XHR2_ON_TIMEOUT_]); -}; - - -/** - * @param {string} header An HTTP header key. - * @return {boolean} Whether the key is a content type header (ignoring - * case. - * @private - */ -goog.net.XhrIo.isContentTypeHeader_ = function(header) { - return goog.string.caseInsensitiveEquals( - goog.net.XhrIo.CONTENT_TYPE_HEADER, header); -}; - - -/** - * Creates a new XHR object. - * @return {!goog.net.XhrLike.OrNative} The newly created XHR object. - * @protected - */ -goog.net.XhrIo.prototype.createXhr = function() { - return this.xmlHttpFactory_ ? - this.xmlHttpFactory_.createInstance() : goog.net.XmlHttp(); -}; - - -/** - * The request didn't complete after {@link goog.net.XhrIo#timeoutInterval_} - * milliseconds; raises a {@link goog.net.EventType.TIMEOUT} event and aborts - * the request. - * @private - */ -goog.net.XhrIo.prototype.timeout_ = function() { - if (typeof goog == 'undefined') { - // If goog is undefined then the callback has occurred as the application - // is unloading and will error. Thus we let it silently fail. - } else if (this.xhr_) { - this.lastError_ = 'Timed out after ' + this.timeoutInterval_ + - 'ms, aborting'; - this.lastErrorCode_ = goog.net.ErrorCode.TIMEOUT; - goog.log.fine(this.logger_, this.formatMsg_(this.lastError_)); - this.dispatchEvent(goog.net.EventType.TIMEOUT); - this.abort(goog.net.ErrorCode.TIMEOUT); - } -}; - - -/** - * Something errorred, so inactivate, fire error callback and clean up - * @param {goog.net.ErrorCode} errorCode The error code. - * @param {Error} err The error object. - * @private - */ -goog.net.XhrIo.prototype.error_ = function(errorCode, err) { - this.active_ = false; - if (this.xhr_) { - this.inAbort_ = true; - this.xhr_.abort(); // Ensures XHR isn't hung (FF) - this.inAbort_ = false; - } - this.lastError_ = err; - this.lastErrorCode_ = errorCode; - this.dispatchErrors_(); - this.cleanUpXhr_(); -}; - - -/** - * Dispatches COMPLETE and ERROR in case of an error. This ensures that we do - * not dispatch multiple error events. - * @private - */ -goog.net.XhrIo.prototype.dispatchErrors_ = function() { - if (!this.errorDispatched_) { - this.errorDispatched_ = true; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ERROR); - } -}; - - -/** - * Abort the current XMLHttpRequest - * @param {goog.net.ErrorCode=} opt_failureCode Optional error code to use - - * defaults to ABORT. - */ -goog.net.XhrIo.prototype.abort = function(opt_failureCode) { - if (this.xhr_ && this.active_) { - goog.log.fine(this.logger_, this.formatMsg_('Aborting')); - this.active_ = false; - this.inAbort_ = true; - this.xhr_.abort(); - this.inAbort_ = false; - this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ABORT); - this.cleanUpXhr_(); - } -}; - - -/** - * Nullifies all callbacks to reduce risks of leaks. - * @override - * @protected - */ -goog.net.XhrIo.prototype.disposeInternal = function() { - if (this.xhr_) { - // We explicitly do not call xhr_.abort() unless active_ is still true. - // This is to avoid unnecessarily aborting a successful request when - // dispose() is called in a callback triggered by a complete response, but - // in which browser cleanup has not yet finished. - // (See http://b/issue?id=1684217.) - if (this.active_) { - this.active_ = false; - this.inAbort_ = true; - this.xhr_.abort(); - this.inAbort_ = false; - } - this.cleanUpXhr_(true); - } - - goog.net.XhrIo.base(this, 'disposeInternal'); -}; - - -/** - * Internal handler for the XHR object's readystatechange event. This method - * checks the status and the readystate and fires the correct callbacks. - * If the request has ended, the handlers are cleaned up and the XHR object is - * nullified. - * @private - */ -goog.net.XhrIo.prototype.onReadyStateChange_ = function() { - if (this.isDisposed()) { - // This method is the target of an untracked goog.Timer.callOnce(). - return; - } - if (!this.inOpen_ && !this.inSend_ && !this.inAbort_) { - // Were not being called from within a call to this.xhr_.send - // this.xhr_.abort, or this.xhr_.open, so this is an entry point - this.onReadyStateChangeEntryPoint_(); - } else { - this.onReadyStateChangeHelper_(); - } -}; - - -/** - * Used to protect the onreadystatechange handler entry point. Necessary - * as {#onReadyStateChange_} maybe called from within send or abort, this - * method is only called when {#onReadyStateChange_} is called as an - * entry point. - * {@see #protectEntryPoints} - * @private - */ -goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = function() { - this.onReadyStateChangeHelper_(); -}; - - -/** - * Helper for {@link #onReadyStateChange_}. This is used so that - * entry point calls to {@link #onReadyStateChange_} can be routed through - * {@link #onReadyStateChangeEntryPoint_}. - * @private - */ -goog.net.XhrIo.prototype.onReadyStateChangeHelper_ = function() { - if (!this.active_) { - // can get called inside abort call - return; - } - - if (typeof goog == 'undefined') { - // NOTE(user): If goog is undefined then the callback has occurred as the - // application is unloading and will error. Thus we let it silently fail. - - } else if ( - this.xhrOptions_[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] && - this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE && - this.getStatus() == 2) { - // NOTE(user): In IE if send() errors on a *local* request the readystate - // is still changed to COMPLETE. We need to ignore it and allow the - // try/catch around send() to pick up the error. - goog.log.fine(this.logger_, this.formatMsg_( - 'Local request error detected and ignored')); - - } else { - - // In IE when the response has been cached we sometimes get the callback - // from inside the send call and this usually breaks code that assumes that - // XhrIo is asynchronous. If that is the case we delay the callback - // using a timer. - if (this.inSend_ && - this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE) { - goog.Timer.callOnce(this.onReadyStateChange_, 0, this); - return; - } - - this.dispatchEvent(goog.net.EventType.READY_STATE_CHANGE); - - // readyState indicates the transfer has finished - if (this.isComplete()) { - goog.log.fine(this.logger_, this.formatMsg_('Request complete')); - - this.active_ = false; - - try { - // Call the specific callbacks for success or failure. Only call the - // success if the status is 200 (HTTP_OK) or 304 (HTTP_CACHED) - if (this.isSuccess()) { - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.SUCCESS); - } else { - this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; - this.lastError_ = - this.getStatusText() + ' [' + this.getStatus() + ']'; - this.dispatchErrors_(); - } - } finally { - this.cleanUpXhr_(); - } - } - } -}; - - -/** - * Internal handler for the XHR object's onprogress event. - * @param {!ProgressEvent} e XHR progress event. - * @private - */ -goog.net.XhrIo.prototype.onProgressHandler_ = function(e) { - goog.asserts.assert(e.type === goog.net.EventType.PROGRESS, - 'goog.net.EventType.PROGRESS is of the same type as raw XHR progress.'); - // Redispatch the progress event. - this.dispatchEvent(e); -}; - - -/** - * Remove the listener to protect against leaks, and nullify the XMLHttpRequest - * object. - * @param {boolean=} opt_fromDispose If this is from the dispose (don't want to - * fire any events). - * @private - */ -goog.net.XhrIo.prototype.cleanUpXhr_ = function(opt_fromDispose) { - if (this.xhr_) { - // Cancel any pending timeout event handler. - this.cleanUpTimeoutTimer_(); - - // Save reference so we can mark it as closed after the READY event. The - // READY event may trigger another request, thus we must nullify this.xhr_ - var xhr = this.xhr_; - var clearedOnReadyStateChange = - this.xhrOptions_[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] ? - goog.nullFunction : null; - this.xhr_ = null; - this.xhrOptions_ = null; - - if (!opt_fromDispose) { - this.dispatchEvent(goog.net.EventType.READY); - } - - try { - // NOTE(user): Not nullifying in FireFox can still leak if the callbacks - // are defined in the same scope as the instance of XhrIo. But, IE doesn't - // allow you to set the onreadystatechange to NULL so nullFunction is - // used. - xhr.onreadystatechange = clearedOnReadyStateChange; - } catch (e) { - // This seems to occur with a Gears HTTP request. Delayed the setting of - // this onreadystatechange until after READY is sent out and catching the - // error to see if we can track down the problem. - goog.log.error(this.logger_, - 'Problem encountered resetting onreadystatechange: ' + e.message); - } - } -}; - - -/** - * Make sure the timeout timer isn't running. - * @private - */ -goog.net.XhrIo.prototype.cleanUpTimeoutTimer_ = function() { - if (this.xhr_ && this.useXhr2Timeout_) { - this.xhr_[goog.net.XhrIo.XHR2_ON_TIMEOUT_] = null; - } - if (goog.isNumber(this.timeoutId_)) { - goog.Timer.clear(this.timeoutId_); - this.timeoutId_ = null; - } -}; - - -/** - * @return {boolean} Whether there is an active request. - */ -goog.net.XhrIo.prototype.isActive = function() { - return !!this.xhr_; -}; - - -/** - * @return {boolean} Whether the request has completed. - */ -goog.net.XhrIo.prototype.isComplete = function() { - return this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE; -}; - - -/** - * @return {boolean} Whether the request completed with a success. - */ -goog.net.XhrIo.prototype.isSuccess = function() { - var status = this.getStatus(); - // A zero status code is considered successful for local files. - return goog.net.HttpStatus.isSuccess(status) || - status === 0 && !this.isLastUriEffectiveSchemeHttp_(); -}; - - -/** - * @return {boolean} whether the effective scheme of the last URI that was - * fetched was 'http' or 'https'. - * @private - */ -goog.net.XhrIo.prototype.isLastUriEffectiveSchemeHttp_ = function() { - var scheme = goog.uri.utils.getEffectiveScheme(String(this.lastUri_)); - return goog.net.XhrIo.HTTP_SCHEME_PATTERN.test(scheme); -}; - - -/** - * Get the readystate from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {goog.net.XmlHttp.ReadyState} goog.net.XmlHttp.ReadyState.*. - */ -goog.net.XhrIo.prototype.getReadyState = function() { - return this.xhr_ ? - /** @type {goog.net.XmlHttp.ReadyState} */ (this.xhr_.readyState) : - goog.net.XmlHttp.ReadyState.UNINITIALIZED; -}; - - -/** - * Get the status from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {number} Http status. - */ -goog.net.XhrIo.prototype.getStatus = function() { - /** - * IE doesn't like you checking status until the readystate is greater than 2 - * (i.e. it is receiving or complete). The try/catch is used for when the - * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. - * @preserveTry - */ - try { - return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? - this.xhr_.status : -1; - } catch (e) { - return -1; - } -}; - - -/** - * Get the status text from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {string} Status text. - */ -goog.net.XhrIo.prototype.getStatusText = function() { - /** - * IE doesn't like you checking status until the readystate is greater than 2 - * (i.e. it is recieving or complete). The try/catch is used for when the - * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. - * @preserveTry - */ - try { - return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? - this.xhr_.statusText : ''; - } catch (e) { - goog.log.fine(this.logger_, 'Can not get status: ' + e.message); - return ''; - } -}; - - -/** - * Get the last Uri that was requested - * @return {string} Last Uri. - */ -goog.net.XhrIo.prototype.getLastUri = function() { - return String(this.lastUri_); -}; - - -/** - * Get the response text from the Xhr object - * Will only return correct result when called from the context of a callback. - * @return {string} Result from the server, or '' if no result available. - */ -goog.net.XhrIo.prototype.getResponseText = function() { - /** @preserveTry */ - try { - return this.xhr_ ? this.xhr_.responseText : ''; - } catch (e) { - // http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute - // states that responseText should return '' (and responseXML null) - // when the state is not LOADING or DONE. Instead, IE can - // throw unexpected exceptions, for example when a request is aborted - // or no data is available yet. - goog.log.fine(this.logger_, 'Can not get responseText: ' + e.message); - return ''; - } -}; - - -/** - * Get the response body from the Xhr object. This property is only available - * in IE since version 7 according to MSDN: - * http://msdn.microsoft.com/en-us/library/ie/ms534368(v=vs.85).aspx - * Will only return correct result when called from the context of a callback. - * - * One option is to construct a VBArray from the returned object and convert - * it to a JavaScript array using the toArray method: - * {@code (new window['VBArray'](xhrIo.getResponseBody())).toArray()} - * This will result in an array of numbers in the range of [0..255] - * - * Another option is to use the VBScript CStr method to convert it into a - * string as outlined in http://stackoverflow.com/questions/1919972 - * - * @return {Object} Binary result from the server or null if not available. - */ -goog.net.XhrIo.prototype.getResponseBody = function() { - /** @preserveTry */ - try { - if (this.xhr_ && 'responseBody' in this.xhr_) { - return this.xhr_['responseBody']; - } - } catch (e) { - // IE can throw unexpected exceptions, for example when a request is aborted - // or no data is yet available. - goog.log.fine(this.logger_, 'Can not get responseBody: ' + e.message); - } - return null; -}; - - -/** - * Get the response XML from the Xhr object - * Will only return correct result when called from the context of a callback. - * @return {Document} The DOM Document representing the XML file, or null - * if no result available. - */ -goog.net.XhrIo.prototype.getResponseXml = function() { - /** @preserveTry */ - try { - return this.xhr_ ? this.xhr_.responseXML : null; - } catch (e) { - goog.log.fine(this.logger_, 'Can not get responseXML: ' + e.message); - return null; - } -}; - - -/** - * Get the response and evaluates it as JSON from the Xhr object - * Will only return correct result when called from the context of a callback - * @param {string=} opt_xssiPrefix Optional XSSI prefix string to use for - * stripping of the response before parsing. This needs to be set only if - * your backend server prepends the same prefix string to the JSON response. - * @return {Object|undefined} JavaScript object. - */ -goog.net.XhrIo.prototype.getResponseJson = function(opt_xssiPrefix) { - if (!this.xhr_) { - return undefined; - } - - var responseText = this.xhr_.responseText; - if (opt_xssiPrefix && responseText.indexOf(opt_xssiPrefix) == 0) { - responseText = responseText.substring(opt_xssiPrefix.length); - } - - return goog.json.parse(responseText); -}; - - -/** - * Get the response as the type specificed by {@link #setResponseType}. At time - * of writing, this is only directly supported in very recent versions of WebKit - * (10.0.612.1 dev and later). If the field is not supported directly, we will - * try to emulate it. - * - * Emulating the response means following the rules laid out at - * http://www.w3.org/TR/XMLHttpRequest/#the-response-attribute - * - * On browsers with no support for this (Chrome < 10, Firefox < 4, etc), only - * response types of DEFAULT or TEXT may be used, and the response returned will - * be the text response. - * - * On browsers with Mozilla's draft support for array buffers (Firefox 4, 5), - * only response types of DEFAULT, TEXT, and ARRAY_BUFFER may be used, and the - * response returned will be either the text response or the Mozilla - * implementation of the array buffer response. - * - * On browsers will full support, any valid response type supported by the - * browser may be used, and the response provided by the browser will be - * returned. - * - * @return {*} The response. - */ -goog.net.XhrIo.prototype.getResponse = function() { - /** @preserveTry */ - try { - if (!this.xhr_) { - return null; - } - if ('response' in this.xhr_) { - return this.xhr_.response; - } - switch (this.responseType_) { - case goog.net.XhrIo.ResponseType.DEFAULT: - case goog.net.XhrIo.ResponseType.TEXT: - return this.xhr_.responseText; - // DOCUMENT and BLOB don't need to be handled here because they are - // introduced in the same spec that adds the .response field, and would - // have been caught above. - // ARRAY_BUFFER needs an implementation for Firefox 4, where it was - // implemented using a draft spec rather than the final spec. - case goog.net.XhrIo.ResponseType.ARRAY_BUFFER: - if ('mozResponseArrayBuffer' in this.xhr_) { - return this.xhr_.mozResponseArrayBuffer; - } - } - // Fell through to a response type that is not supported on this browser. - goog.log.error(this.logger_, - 'Response type ' + this.responseType_ + ' is not ' + - 'supported on this browser'); - return null; - } catch (e) { - goog.log.fine(this.logger_, 'Can not get response: ' + e.message); - return null; - } -}; - - -/** - * Get the value of the response-header with the given name from the Xhr object - * Will only return correct result when called from the context of a callback - * and the request has completed - * @param {string} key The name of the response-header to retrieve. - * @return {string|undefined} The value of the response-header named key. - */ -goog.net.XhrIo.prototype.getResponseHeader = function(key) { - return this.xhr_ && this.isComplete() ? - this.xhr_.getResponseHeader(key) : undefined; -}; - - -/** - * Gets the text of all the headers in the response. - * Will only return correct result when called from the context of a callback - * and the request has completed. - * @return {string} The value of the response headers or empty string. - */ -goog.net.XhrIo.prototype.getAllResponseHeaders = function() { - return this.xhr_ && this.isComplete() ? - this.xhr_.getAllResponseHeaders() : ''; -}; - - -/** - * Returns all response headers as a key-value map. - * Multiple values for the same header key can be combined into one, - * separated by a comma and a space. - * Note that the native getResponseHeader method for retrieving a single header - * does a case insensitive match on the header name. This method does not - * include any case normalization logic, it will just return a key-value - * representation of the headers. - * See: http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method - * @return {!Object<string, string>} An object with the header keys as keys - * and header values as values. - */ -goog.net.XhrIo.prototype.getResponseHeaders = function() { - var headersObject = {}; - var headersArray = this.getAllResponseHeaders().split('\r\n'); - for (var i = 0; i < headersArray.length; i++) { - if (goog.string.isEmptyOrWhitespace(headersArray[i])) { - continue; - } - var keyValue = goog.string.splitLimit(headersArray[i], ': ', 2); - if (headersObject[keyValue[0]]) { - headersObject[keyValue[0]] += ', ' + keyValue[1]; - } else { - headersObject[keyValue[0]] = keyValue[1]; - } - } - return headersObject; -}; - - -/** - * Get the last error message - * @return {goog.net.ErrorCode} Last error code. - */ -goog.net.XhrIo.prototype.getLastErrorCode = function() { - return this.lastErrorCode_; -}; - - -/** - * Get the last error message - * @return {string} Last error message. - */ -goog.net.XhrIo.prototype.getLastError = function() { - return goog.isString(this.lastError_) ? this.lastError_ : - String(this.lastError_); -}; - - -/** - * Adds the last method, status and URI to the message. This is used to add - * this information to the logging calls. - * @param {string} msg The message text that we want to add the extra text to. - * @return {string} The message with the extra text appended. - * @private - */ -goog.net.XhrIo.prototype.formatMsg_ = function(msg) { - return msg + ' [' + this.lastMethod_ + ' ' + this.lastUri_ + ' ' + - this.getStatus() + ']'; -}; - - -// Register the xhr handler as an entry point, so that -// it can be monitored for exception handling, etc. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = - transformer(goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); - }); - -goog.provide('ol.format.FormatType'); - - -/** - * @enum {string} - */ -ol.format.FormatType = { - ARRAY_BUFFER: 'arraybuffer', - JSON: 'json', - TEXT: 'text', - XML: 'xml' -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview - * XML utilities. - * - */ - -goog.provide('goog.dom.xml'); - -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); -goog.require('goog.userAgent'); - - -/** - * Max XML size for MSXML2. Used to prevent potential DoS attacks. - * @type {number} - */ -goog.dom.xml.MAX_XML_SIZE_KB = 2 * 1024; // In kB - - -/** - * Max XML size for MSXML2. Used to prevent potential DoS attacks. - * @type {number} - */ -goog.dom.xml.MAX_ELEMENT_DEPTH = 256; // Same default as MSXML6. - - -/** - * Check for ActiveXObject support by the browser. - * @return {boolean} true if browser has ActiveXObject support. - * @private - */ -goog.dom.xml.hasActiveXObjectSupport_ = function() { - if (!goog.userAgent.IE) { - // Avoid raising useless exception in case code is not compiled - // and browser is not MSIE. - return false; - } - try { - // Due to lot of changes in IE 9, 10 & 11 behaviour and ActiveX being - // totally disableable using MSIE's security level, trying to create the - // ActiveXOjbect is a lot more reliable than testing for the existance of - // window.ActiveXObject - new ActiveXObject('MSXML2.DOMDocument'); - return true; - } catch (e) { - return false; - } -}; - - -/** - * True if browser has ActiveXObject support. - * Possible override if this test become wrong in coming IE versions. - * @type {boolean} - */ -goog.dom.xml.ACTIVEX_SUPPORT = - goog.userAgent.IE && goog.dom.xml.hasActiveXObjectSupport_(); - - -/** - * Creates an XML document appropriate for the current JS runtime - * @param {string=} opt_rootTagName The root tag name. - * @param {string=} opt_namespaceUri Namespace URI of the document element. - * @param {boolean=} opt_preferActiveX Whether to default to ActiveXObject to - * create Document in IE. Use this if you need xpath support in IE (e.g., - * selectSingleNode or selectNodes), but be aware that the ActiveXObject does - * not support various DOM-specific Document methods and attributes. - * @return {Document} The new document. - * @throws {Error} if browser does not support creating new documents or - * namespace is provided without a root tag name. - */ -goog.dom.xml.createDocument = function(opt_rootTagName, opt_namespaceUri, - opt_preferActiveX) { - if (opt_namespaceUri && !opt_rootTagName) { - throw Error("Can't create document with namespace and no root tag"); - } - // If document.implementation.createDocument is available and they haven't - // explicitly opted to use ActiveXObject when possible. - if (document.implementation && document.implementation.createDocument && - !(goog.dom.xml.ACTIVEX_SUPPORT && opt_preferActiveX)) { - return document.implementation.createDocument(opt_namespaceUri || '', - opt_rootTagName || '', null); - } else if (goog.dom.xml.ACTIVEX_SUPPORT) { - var doc = goog.dom.xml.createMsXmlDocument_(); - if (doc) { - if (opt_rootTagName) { - doc.appendChild(doc.createNode(goog.dom.NodeType.ELEMENT, - opt_rootTagName, - opt_namespaceUri || '')); - } - return doc; - } - } - throw Error('Your browser does not support creating new documents'); -}; - - -/** - * Creates an XML document from a string - * @param {string} xml The text. - * @param {boolean=} opt_preferActiveX Whether to default to ActiveXObject to - * create Document in IE. Use this if you need xpath support in IE (e.g., - * selectSingleNode or selectNodes), but be aware that the ActiveXObject does - * not support various DOM-specific Document methods and attributes. - * @return {Document} XML document from the text. - * @throws {Error} if browser does not support loading XML documents. - */ -goog.dom.xml.loadXml = function(xml, opt_preferActiveX) { - if (typeof DOMParser != 'undefined' && - !(goog.dom.xml.ACTIVEX_SUPPORT && opt_preferActiveX)) { - return new DOMParser().parseFromString(xml, 'application/xml'); - } else if (goog.dom.xml.ACTIVEX_SUPPORT) { - var doc = goog.dom.xml.createMsXmlDocument_(); - doc.loadXML(xml); - return doc; - } - throw Error('Your browser does not support loading xml documents'); -}; - - -/** - * Serializes an XML document or subtree to string. - * @param {Document|Element} xml The document or the root node of the subtree. - * @return {string} The serialized XML. - * @throws {Error} if browser does not support XML serialization. - */ -goog.dom.xml.serialize = function(xml) { - // Compatible with IE/ActiveXObject. - var text = xml.xml; - if (text) { - return text; - } - // Compatible with Firefox, Opera and WebKit. - if (typeof XMLSerializer != 'undefined') { - return new XMLSerializer().serializeToString(xml); - } - throw Error('Your browser does not support serializing XML documents'); -}; - - -/** - * Selects a single node using an Xpath expression and a root node - * @param {Node} node The root node. - * @param {string} path Xpath selector. - * @return {Node} The selected node, or null if no matching node. - */ -goog.dom.xml.selectSingleNode = function(node, path) { - if (typeof node.selectSingleNode != 'undefined') { - var doc = goog.dom.getOwnerDocument(node); - if (typeof doc.setProperty != 'undefined') { - doc.setProperty('SelectionLanguage', 'XPath'); - } - return node.selectSingleNode(path); - } else if (document.implementation.hasFeature('XPath', '3.0')) { - var doc = goog.dom.getOwnerDocument(node); - var resolver = doc.createNSResolver(doc.documentElement); - var result = doc.evaluate(path, node, resolver, - XPathResult.FIRST_ORDERED_NODE_TYPE, null); - return result.singleNodeValue; - } - // This browser does not support xpath for the given node. If IE, ensure XML - // Document was created using ActiveXObject - // TODO(joeltine): This should throw instead of return null. - return null; -}; - - -/** - * Selects multiple nodes using an Xpath expression and a root node - * @param {Node} node The root node. - * @param {string} path Xpath selector. - * @return {(NodeList|Array<Node>)} The selected nodes, or empty array if no - * matching nodes. - */ -goog.dom.xml.selectNodes = function(node, path) { - if (typeof node.selectNodes != 'undefined') { - var doc = goog.dom.getOwnerDocument(node); - if (typeof doc.setProperty != 'undefined') { - doc.setProperty('SelectionLanguage', 'XPath'); - } - return node.selectNodes(path); - } else if (document.implementation.hasFeature('XPath', '3.0')) { - var doc = goog.dom.getOwnerDocument(node); - var resolver = doc.createNSResolver(doc.documentElement); - var nodes = doc.evaluate(path, node, resolver, - XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - var results = []; - var count = nodes.snapshotLength; - for (var i = 0; i < count; i++) { - results.push(nodes.snapshotItem(i)); - } - return results; - } else { - // This browser does not support xpath for the given node. If IE, ensure XML - // Document was created using ActiveXObject. - // TODO(joeltine): This should throw instead of return empty array. - return []; - } -}; - - -/** - * Sets multiple attributes on an element. Differs from goog.dom.setProperties - * in that it exclusively uses the element's setAttributes method. Use this - * when you need to ensure that the exact property is available as an attribute - * and can be read later by the native getAttribute method. - * @param {!Element} element XML or DOM element to set attributes on. - * @param {!Object<string, string>} attributes Map of property:value pairs. - */ -goog.dom.xml.setAttributes = function(element, attributes) { - for (var key in attributes) { - if (attributes.hasOwnProperty(key)) { - element.setAttribute(key, attributes[key]); - } - } -}; - - -/** - * Creates an instance of the MSXML2.DOMDocument. - * @return {Document} The new document. - * @private - */ -goog.dom.xml.createMsXmlDocument_ = function() { - var doc = new ActiveXObject('MSXML2.DOMDocument'); - if (doc) { - // Prevent potential vulnerabilities exposed by MSXML2, see - // http://b/1707300 and http://wiki/Main/ISETeamXMLAttacks for details. - doc.resolveExternals = false; - doc.validateOnParse = false; - // Add a try catch block because accessing these properties will throw an - // error on unsupported MSXML versions. This affects Windows machines - // running IE6 or IE7 that are on XP SP2 or earlier without MSXML updates. - // See http://msdn.microsoft.com/en-us/library/ms766391(VS.85).aspx for - // specific details on which MSXML versions support these properties. - try { - doc.setProperty('ProhibitDTD', true); - doc.setProperty('MaxXMLSize', goog.dom.xml.MAX_XML_SIZE_KB); - doc.setProperty('MaxElementDepth', goog.dom.xml.MAX_ELEMENT_DEPTH); - } catch (e) { - // No-op. - } - } - return doc; -}; - -goog.provide('ol.xml'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.xml'); -goog.require('goog.object'); -goog.require('goog.userAgent'); - - -/** - * When using {@link ol.xml.makeChildAppender} or - * {@link ol.xml.makeSimpleNodeFactory}, the top `objectStack` item needs to - * have this structure. - * @typedef {{node:Node}} - */ -ol.xml.NodeStackItem; - - -/** - * @typedef {function(Node, Array.<*>)} - */ -ol.xml.Parser; - - -/** - * @typedef {function(Node, *, Array.<*>)} - */ -ol.xml.Serializer; - - -/** - * This document should be used when creating nodes for XML serializations. This - * document is also used by {@link ol.xml.createElementNS} and - * {@link ol.xml.setAttributeNS} - * @const - * @type {Document} - */ -ol.xml.DOCUMENT = goog.dom.xml.createDocument(); - - -/** - * @param {string} namespaceURI Namespace URI. - * @param {string} qualifiedName Qualified name. - * @return {Node} Node. - * @private - */ -ol.xml.createElementNS_ = function(namespaceURI, qualifiedName) { - return ol.xml.DOCUMENT.createElementNS(namespaceURI, qualifiedName); -}; - - -/** - * @param {string} namespaceURI Namespace URI. - * @param {string} qualifiedName Qualified name. - * @return {Node} Node. - * @private - */ -ol.xml.createElementNSActiveX_ = function(namespaceURI, qualifiedName) { - if (!namespaceURI) { - namespaceURI = ''; - } - return ol.xml.DOCUMENT.createNode(1, qualifiedName, namespaceURI); -}; - - -/** - * @param {string} namespaceURI Namespace URI. - * @param {string} qualifiedName Qualified name. - * @return {Node} Node. - */ -ol.xml.createElementNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.createElementNS_ : ol.xml.createElementNSActiveX_; - - -/** - * Recursively grab all text content of child nodes into a single string. - * @param {Node} node Node. - * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line - * breaks. - * @return {string} All text content. - * @api - */ -ol.xml.getAllTextContent = function(node, normalizeWhitespace) { - return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join(''); -}; - - -/** - * Recursively grab all text content of child nodes into a single string. - * @param {Node} node Node. - * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line - * breaks. - * @param {Array.<String|string>} accumulator Accumulator. - * @private - * @return {Array.<String|string>} Accumulator. - */ -ol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) { - if (node.nodeType == goog.dom.NodeType.CDATA_SECTION || - node.nodeType == goog.dom.NodeType.TEXT) { - if (normalizeWhitespace) { - // FIXME understand why goog.dom.getTextContent_ uses String here - accumulator.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, '')); - } else { - accumulator.push(node.nodeValue); - } - } else { - var n; - for (n = node.firstChild; n; n = n.nextSibling) { - ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator); - } - } - return accumulator; -}; - - -/** - * @param {Node} node Node. - * @private - * @return {string} Local name. - */ -ol.xml.getLocalName_ = function(node) { - return node.localName; -}; - - -/** - * @param {Node} node Node. - * @private - * @return {string} Local name. - */ -ol.xml.getLocalNameIE_ = function(node) { - var localName = node.localName; - if (localName !== undefined) { - return localName; - } - var baseName = node.baseName; - goog.asserts.assert(baseName, - 'Failed to get localName/baseName of node %s', node); - return baseName; -}; - - -/** - * @param {Node} node Node. - * @return {string} Local name. - */ -ol.xml.getLocalName = goog.userAgent.IE ? - ol.xml.getLocalNameIE_ : ol.xml.getLocalName_; - - -/** - * @param {?} value Value. - * @private - * @return {boolean} Is document. - */ -ol.xml.isDocument_ = function(value) { - return value instanceof Document; -}; - - -/** - * @param {?} value Value. - * @private - * @return {boolean} Is document. - */ -ol.xml.isDocumentIE_ = function(value) { - return goog.isObject(value) && value.nodeType == goog.dom.NodeType.DOCUMENT; -}; - - -/** - * @param {?} value Value. - * @return {boolean} Is document. - */ -ol.xml.isDocument = goog.userAgent.IE ? - ol.xml.isDocumentIE_ : ol.xml.isDocument_; - - -/** - * @param {?} value Value. - * @private - * @return {boolean} Is node. - */ -ol.xml.isNode_ = function(value) { - return value instanceof Node; -}; - - -/** - * @param {?} value Value. - * @private - * @return {boolean} Is node. - */ -ol.xml.isNodeIE_ = function(value) { - return goog.isObject(value) && value.nodeType !== undefined; -}; - - -/** - * @param {?} value Value. - * @return {boolean} Is node. - */ -ol.xml.isNode = goog.userAgent.IE ? ol.xml.isNodeIE_ : ol.xml.isNode_; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {string} Value - * @private - */ -ol.xml.getAttributeNS_ = function(node, namespaceURI, name) { - return node.getAttributeNS(namespaceURI, name) || ''; -}; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {string} Value - * @private - */ -ol.xml.getAttributeNSActiveX_ = function(node, namespaceURI, name) { - var attributeValue = ''; - var attributeNode = ol.xml.getAttributeNodeNS(node, namespaceURI, name); - if (attributeNode !== undefined) { - attributeValue = attributeNode.nodeValue; - } - return attributeValue; -}; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {string} Value - */ -ol.xml.getAttributeNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.getAttributeNS_ : ol.xml.getAttributeNSActiveX_; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {?Node} Attribute node or null if none found. - * @private - */ -ol.xml.getAttributeNodeNS_ = function(node, namespaceURI, name) { - return node.getAttributeNodeNS(namespaceURI, name); -}; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {?Node} Attribute node or null if none found. - * @private - */ -ol.xml.getAttributeNodeNSActiveX_ = function(node, namespaceURI, name) { - var attributeNode = null; - var attributes = node.attributes; - var potentialNode, fullName; - for (var i = 0, len = attributes.length; i < len; ++i) { - potentialNode = attributes[i]; - if (potentialNode.namespaceURI == namespaceURI) { - fullName = (potentialNode.prefix) ? - (potentialNode.prefix + ':' + name) : name; - if (fullName == potentialNode.nodeName) { - attributeNode = potentialNode; - break; - } - } - } - return attributeNode; -}; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {?Node} Attribute node or null if none found. - */ -ol.xml.getAttributeNodeNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.getAttributeNodeNS_ : ol.xml.getAttributeNodeNSActiveX_; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @param {string|number} value Value. - * @private - */ -ol.xml.setAttributeNS_ = function(node, namespaceURI, name, value) { - node.setAttributeNS(namespaceURI, name, value); -}; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @param {string|number} value Value. - * @private - */ -ol.xml.setAttributeNSActiveX_ = function(node, namespaceURI, name, value) { - if (namespaceURI) { - var attribute = node.ownerDocument.createNode(2, name, namespaceURI); - attribute.nodeValue = value; - node.setAttributeNode(attribute); - } else { - node.setAttribute(name, value); - } -}; - - -/** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @param {string|number} value Value. - */ -ol.xml.setAttributeNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.setAttributeNS_ : ol.xml.setAttributeNSActiveX_; - - -/** - * Parse an XML string to an XML Document. - * @param {string} xml XML. - * @return {Document} Document. - * @api - */ -ol.xml.parse = function(xml) { - return new DOMParser().parseFromString(xml, 'application/xml'); -}; - - -/** - * Make an array extender function for extending the array at the top of the - * object stack. - * @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)} - * valueReader Value reader. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T - */ -ol.xml.makeArrayExtender = function(valueReader, opt_this) { - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this, node, objectStack); - if (value !== undefined) { - goog.asserts.assert(goog.isArray(value), - 'valueReader function is expected to return an array of values'); - var array = /** @type {Array.<*>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(array), - 'objectStack is supposed to be an array of arrays'); - goog.array.extend(array, value); - } - }); -}; - - -/** - * Make an array pusher function for pushing to the array at the top of the - * object stack. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T - */ -ol.xml.makeArrayPusher = function(valueReader, opt_this) { - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - var array = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isArray(array), - 'objectStack is supposed to be an array of arrays'); - array.push(value); - } - }); -}; - - -/** - * Make an object stack replacer function for replacing the object at the - * top of the stack. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T - */ -ol.xml.makeReplacer = function(valueReader, opt_this) { - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - objectStack[objectStack.length - 1] = value; - } - }); -}; - - -/** - * Make an object property pusher function for adding a property to the - * object at the top of the stack. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {string=} opt_property Property. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T - */ -ol.xml.makeObjectPropertyPusher = - function(valueReader, opt_property, opt_this) { - goog.asserts.assert(valueReader !== undefined, - 'undefined valueReader, expected function(this: T, Node, Array.<*>)'); - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - var object = /** @type {Object} */ - (objectStack[objectStack.length - 1]); - var property = opt_property !== undefined ? - opt_property : node.localName; - goog.asserts.assert(goog.isObject(object), - 'entity from stack was not an object'); - var array = goog.object.setIfUndefined(object, property, []); - array.push(value); - } - }); -}; - - -/** - * Make an object property setter function. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {string=} opt_property Property. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T - */ -ol.xml.makeObjectPropertySetter = - function(valueReader, opt_property, opt_this) { - goog.asserts.assert(valueReader !== undefined, - 'undefined valueReader, expected function(this: T, Node, Array.<*>)'); - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - var object = /** @type {Object} */ - (objectStack[objectStack.length - 1]); - var property = opt_property !== undefined ? - opt_property : node.localName; - goog.asserts.assert(goog.isObject(object), - 'entity from stack was not an object'); - object[property] = value; - } - }); -}; - - -/** - * Create a serializer that appends nodes written by its `nodeWriter` to its - * designated parent. The parent is the `node` of the - * {@link ol.xml.NodeStackItem} at the top of the `objectStack`. - * @param {function(this: T, Node, V, Array.<*>)} - * nodeWriter Node writer. - * @param {T=} opt_this The object to use as `this` in `nodeWriter`. - * @return {ol.xml.Serializer} Serializer. - * @template T, V - */ -ol.xml.makeChildAppender = function(nodeWriter, opt_this) { - return function(node, value, objectStack) { - nodeWriter.call(opt_this !== undefined ? opt_this : this, - node, value, objectStack); - var parent = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(parent), - 'entity from stack was not an object'); - var parentNode = parent.node; - goog.asserts.assert(ol.xml.isNode(parentNode) || - ol.xml.isDocument(parentNode), - 'expected parentNode %s to be a Node or a Document', parentNode); - parentNode.appendChild(node); - }; -}; - - -/** - * Create a serializer that calls the provided `nodeWriter` from - * {@link ol.xml.serialize}. This can be used by the parent writer to have the - * 'nodeWriter' called with an array of values when the `nodeWriter` was - * designed to serialize a single item. An example would be a LineString - * geometry writer, which could be reused for writing MultiLineString - * geometries. - * @param {function(this: T, Node, V, Array.<*>)} - * nodeWriter Node writer. - * @param {T=} opt_this The object to use as `this` in `nodeWriter`. - * @return {ol.xml.Serializer} Serializer. - * @template T, V - */ -ol.xml.makeArraySerializer = function(nodeWriter, opt_this) { - var serializersNS, nodeFactory; - return function(node, value, objectStack) { - if (serializersNS === undefined) { - serializersNS = {}; - var serializers = {}; - serializers[node.localName] = nodeWriter; - serializersNS[node.namespaceURI] = serializers; - nodeFactory = ol.xml.makeSimpleNodeFactory(node.localName); - } - ol.xml.serialize(serializersNS, nodeFactory, value, objectStack); - }; -}; - - -/** - * Create a node factory which can use the `opt_keys` passed to - * {@link ol.xml.serialize} or {@link ol.xml.pushSerializeAndPop} as node names, - * or a fixed node name. The namespace of the created nodes can either be fixed, - * or the parent namespace will be used. - * @param {string=} opt_nodeName Fixed node name which will be used for all - * created nodes. If not provided, the 3rd argument to the resulting node - * factory needs to be provided and will be the nodeName. - * @param {string=} opt_namespaceURI Fixed namespace URI which will be used for - * all created nodes. If not provided, the namespace of the parent node will - * be used. - * @return {function(*, Array.<*>, string=): (Node|undefined)} Node factory. - */ -ol.xml.makeSimpleNodeFactory = function(opt_nodeName, opt_namespaceURI) { - var fixedNodeName = opt_nodeName; - return ( - /** - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node} Node. - */ - function(value, objectStack, opt_nodeName) { - var context = objectStack[objectStack.length - 1]; - var node = context.node; - goog.asserts.assert(ol.xml.isNode(node) || ol.xml.isDocument(node), - 'expected node %s to be a Node or a Document', node); - var nodeName = fixedNodeName; - if (nodeName === undefined) { - nodeName = opt_nodeName; - } - var namespaceURI = opt_namespaceURI; - if (opt_namespaceURI === undefined) { - namespaceURI = node.namespaceURI; - } - goog.asserts.assert(nodeName !== undefined, 'nodeName was undefined'); - return ol.xml.createElementNS(namespaceURI, nodeName); - } - ); -}; - - -/** - * A node factory that creates a node using the parent's `namespaceURI` and the - * `nodeName` passed by {@link ol.xml.serialize} or - * {@link ol.xml.pushSerializeAndPop} to the node factory. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - */ -ol.xml.OBJECT_PROPERTY_NODE_FACTORY = ol.xml.makeSimpleNodeFactory(); - - -/** - * Create an array of `values` to be used with {@link ol.xml.serialize} or - * {@link ol.xml.pushSerializeAndPop}, where `orderedKeys` has to be provided as - * `opt_key` argument. - * @param {Object.<string, V>} object Key-value pairs for the sequence. Keys can - * be a subset of the `orderedKeys`. - * @param {Array.<string>} orderedKeys Keys in the order of the sequence. - * @return {Array.<V>} Values in the order of the sequence. The resulting array - * has the same length as the `orderedKeys` array. Values that are not - * present in `object` will be `undefined` in the resulting array. - * @template V - */ -ol.xml.makeSequence = function(object, orderedKeys) { - var length = orderedKeys.length; - var sequence = new Array(length); - for (var i = 0; i < length; ++i) { - sequence[i] = object[orderedKeys[i]]; - } - return sequence; -}; - - -/** - * Create a namespaced structure, using the same values for each namespace. - * This can be used as a starting point for versioned parsers, when only a few - * values are version specific. - * @param {Array.<string>} namespaceURIs Namespace URIs. - * @param {T} structure Structure. - * @param {Object.<string, T>=} opt_structureNS Namespaced structure to add to. - * @return {Object.<string, T>} Namespaced structure. - * @template T - */ -ol.xml.makeStructureNS = function(namespaceURIs, structure, opt_structureNS) { - /** - * @type {Object.<string, *>} - */ - var structureNS = opt_structureNS !== undefined ? opt_structureNS : {}; - var i, ii; - for (i = 0, ii = namespaceURIs.length; i < ii; ++i) { - structureNS[namespaceURIs[i]] = structure; - } - return structureNS; -}; - - -/** - * Parse a node using the parsers and object stack. - * @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS - * Parsers by namespace. - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @param {*=} opt_this The object to use as `this`. - */ -ol.xml.parseNode = function(parsersNS, node, objectStack, opt_this) { - var n; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var parsers = parsersNS[n.namespaceURI]; - if (parsers !== undefined) { - var parser = parsers[n.localName]; - if (parser !== undefined) { - parser.call(opt_this, n, objectStack); - } - } - } -}; - - -/** - * Push an object on top of the stack, parse and return the popped object. - * @param {T} object Object. - * @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS - * Parsers by namespace. - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @param {*=} opt_this The object to use as `this`. - * @return {T} Object. - * @template T - */ -ol.xml.pushParseAndPop = function( - object, parsersNS, node, objectStack, opt_this) { - objectStack.push(object); - ol.xml.parseNode(parsersNS, node, objectStack, opt_this); - return objectStack.pop(); -}; - - -/** - * Walk through an array of `values` and call a serializer for each value. - * @param {Object.<string, Object.<string, ol.xml.Serializer>>} serializersNS - * Namespaced serializers. - * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory - * Node factory. The `nodeFactory` creates the node whose namespace and name - * will be used to choose a node writer from `serializersNS`. This - * separation allows us to decide what kind of node to create, depending on - * the value we want to serialize. An example for this would be different - * geometry writers based on the geometry type. - * @param {Array.<*>} values Values to serialize. An example would be an array - * of {@link ol.Feature} instances. - * @param {Array.<*>} objectStack Node stack. - * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the - * `nodeFactory`. This is used for serializing object literals where the - * node name relates to the property key. The array length of `opt_keys` has - * to match the length of `values`. For serializing a sequence, `opt_keys` - * determines the order of the sequence. - * @param {T=} opt_this The object to use as `this` for the node factory and - * serializers. - * @template T - */ -ol.xml.serialize = function( - serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) { - var length = (opt_keys !== undefined ? opt_keys : values).length; - var value, node; - for (var i = 0; i < length; ++i) { - value = values[i]; - if (value !== undefined) { - node = nodeFactory.call(opt_this, value, objectStack, - opt_keys !== undefined ? opt_keys[i] : undefined); - if (node !== undefined) { - serializersNS[node.namespaceURI][node.localName] - .call(opt_this, node, value, objectStack); - } - } - } -}; - - -/** - * @param {O} object Object. - * @param {Object.<string, Object.<string, ol.xml.Serializer>>} serializersNS - * Namespaced serializers. - * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory - * Node factory. The `nodeFactory` creates the node whose namespace and name - * will be used to choose a node writer from `serializersNS`. This - * separation allows us to decide what kind of node to create, depending on - * the value we want to serialize. An example for this would be different - * geometry writers based on the geometry type. - * @param {Array.<*>} values Values to serialize. An example would be an array - * of {@link ol.Feature} instances. - * @param {Array.<*>} objectStack Node stack. - * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the - * `nodeFactory`. This is used for serializing object literals where the - * node name relates to the property key. The array length of `opt_keys` has - * to match the length of `values`. For serializing a sequence, `opt_keys` - * determines the order of the sequence. - * @param {T=} opt_this The object to use as `this` for the node factory and - * serializers. - * @return {O|undefined} Object. - * @template O, T - */ -ol.xml.pushSerializeAndPop = function(object, - serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) { - objectStack.push(object); - ol.xml.serialize( - serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this); - return objectStack.pop(); -}; - -goog.provide('ol.FeatureLoader'); -goog.provide('ol.FeatureUrlFunction'); -goog.provide('ol.featureloader'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo'); -goog.require('goog.net.XhrIo.ResponseType'); -goog.require('ol.TileState'); -goog.require('ol.format.FormatType'); -goog.require('ol.xml'); - - -/** - * {@link ol.source.Vector} sources use a function of this type to load - * features. - * - * This function takes an {@link ol.Extent} representing the area to be loaded, - * a `{number}` representing the resolution (map units per pixel) and an - * {@link ol.proj.Projection} for the projection as arguments. `this` within - * the function is bound to the {@link ol.source.Vector} it's called from. - * - * The function is responsible for loading the features and adding them to the - * source. - * @api - * @typedef {function(this:ol.source.Vector, ol.Extent, number, - * ol.proj.Projection)} - */ -ol.FeatureLoader; - - -/** - * {@link ol.source.Vector} sources use a function of this type to get the url - * to load features from. - * - * This function takes an {@link ol.Extent} representing the area to be loaded, - * a `{number}` representing the resolution (map units per pixel) and an - * {@link ol.proj.Projection} for the projection as arguments and returns a - * `{string}` representing the URL. - * @api - * @typedef {function(ol.Extent, number, ol.proj.Projection) : string} - */ -ol.FeatureUrlFunction; - - -/** - * @param {string|ol.FeatureUrlFunction} url Feature URL service. - * @param {ol.format.Feature} format Feature format. - * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection)|function(this:ol.source.Vector, Array.<ol.Feature>)} success - * Function called with the loaded features and optionally with the data - * projection. Called with the vector tile or source as `this`. - * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure - * Function called when loading failed. Called with the vector tile or - * source as `this`. - * @return {ol.FeatureLoader} The feature loader. - */ -ol.featureloader.loadFeaturesXhr = function(url, format, success, failure) { - return ( - /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {ol.proj.Projection} projection Projection. - * @this {ol.source.Vector|ol.VectorTile} - */ - function(extent, resolution, projection) { - var xhrIo = new goog.net.XhrIo(); - xhrIo.setResponseType( - format.getType() == ol.format.FormatType.ARRAY_BUFFER ? - goog.net.XhrIo.ResponseType.ARRAY_BUFFER : - goog.net.XhrIo.ResponseType.TEXT); - goog.events.listen(xhrIo, goog.net.EventType.COMPLETE, - /** - * @param {Event} event Event. - * @private - * @this {ol.source.Vector} - */ - function(event) { - var xhrIo = event.target; - goog.asserts.assertInstanceof(xhrIo, goog.net.XhrIo, - 'event.target/xhrIo is an instance of goog.net.XhrIo'); - if (xhrIo.isSuccess()) { - var type = format.getType(); - /** @type {Document|Node|Object|string|undefined} */ - var source; - if (type == ol.format.FormatType.JSON) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.TEXT) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.XML) { - if (!goog.userAgent.IE) { - source = xhrIo.getResponseXml(); - } - if (!source) { - source = ol.xml.parse(xhrIo.getResponseText()); - } - } else if (type == ol.format.FormatType.ARRAY_BUFFER) { - source = xhrIo.getResponse(); - } else { - goog.asserts.fail('unexpected format type'); - } - if (source) { - var features = format.readFeatures(source, - {featureProjection: projection}); - if (ol.ENABLE_VECTOR_TILE && success.length == 2) { - success.call(this, features, format.readProjection(source)); - } else { - success.call(this, features); - } - } else { - goog.asserts.fail('undefined or null source'); - } - } else { - failure.call(this); - } - goog.dispose(xhrIo); - }, false, this); - if (goog.isFunction(url)) { - xhrIo.send(url(extent, resolution, projection)); - } else { - xhrIo.send(url); - } - - }); -}; - - -/** - * Create an XHR feature loader for a `url` and `format`. The feature loader - * loads features (with XHR), parses the features, and adds them to the - * vector tile. - * @param {string|ol.FeatureUrlFunction} url Feature URL service. - * @param {ol.format.Feature} format Feature format. - * @return {ol.FeatureLoader} The feature loader. - * @api - */ -ol.featureloader.tile = function(url, format) { - return ol.featureloader.loadFeaturesXhr(url, format, - /** - * @param {Array.<ol.Feature>} features The loaded features. - * @param {ol.proj.Projection} projection Data projection. - * @this {ol.VectorTile} - */ - function(features, projection) { - this.setProjection(projection); - this.setFeatures(features); - }, - /** - * @this {ol.VectorTile} - */ - function() { - this.setState(ol.TileState.ERROR); - }); -}; - - -/** - * Create an XHR feature loader for a `url` and `format`. The feature loader - * loads features (with XHR), parses the features, and adds them to the - * vector source. - * @param {string|ol.FeatureUrlFunction} url Feature URL service. - * @param {ol.format.Feature} format Feature format. - * @return {ol.FeatureLoader} The feature loader. - * @api - */ -ol.featureloader.xhr = function(url, format) { - return ol.featureloader.loadFeaturesXhr(url, format, - /** - * @param {Array.<ol.Feature>} features The loaded features. - * @this {ol.source.Vector} - */ - function(features) { - this.addFeatures(features); - }, /* FIXME handle error */ ol.nullFunction); -}; - -goog.provide('ol.LoadingStrategy'); -goog.provide('ol.loadingstrategy'); - -goog.require('ol.TileCoord'); - - -/** - * @typedef {function(ol.Extent, number): Array.<ol.Extent>} - * @api - */ -ol.LoadingStrategy; - - -/** - * Strategy function for loading all features with a single request. - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {Array.<ol.Extent>} Extents. - * @api - */ -ol.loadingstrategy.all = function(extent, resolution) { - return [[-Infinity, -Infinity, Infinity, Infinity]]; -}; - - -/** - * Strategy function for loading features based on the view's extent and - * resolution. - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {Array.<ol.Extent>} Extents. - * @api - */ -ol.loadingstrategy.bbox = function(extent, resolution) { - return [extent]; -}; - - -/** - * Creates a strategy function for loading features based on a tile grid. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {function(ol.Extent, number): Array.<ol.Extent>} Loading strategy. - * @api - */ -ol.loadingstrategy.tile = function(tileGrid) { - return ( - /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {Array.<ol.Extent>} Extents. - */ - function(extent, resolution) { - var z = tileGrid.getZForResolution(resolution); - var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - /** @type {Array.<ol.Extent>} */ - var extents = []; - /** @type {ol.TileCoord} */ - var tileCoord = [z, 0, 0]; - for (tileCoord[1] = tileRange.minX; tileCoord[1] <= tileRange.maxX; - ++tileCoord[1]) { - for (tileCoord[2] = tileRange.minY; tileCoord[2] <= tileRange.maxY; - ++tileCoord[2]) { - extents.push(tileGrid.getTileCoordExtent(tileCoord)); - } - } - return extents; - }); -}; - -goog.provide('ol.ext.rbush'); -/** @typedef {function(*)} */ -ol.ext.rbush; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; -/** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} - */ -/* - (c) 2015, Vladimir Agafonkin - RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles. - https://github.com/mourner/rbush -*/ - -(function () { 'use strict'; - -function rbush(maxEntries, format) { - - // jshint newcap: false, validthis: true - if (!(this instanceof rbush)) return new rbush(maxEntries, format); - - // max entries in a node is 9 by default; min node fill is 40% for best performance - this._maxEntries = Math.max(4, maxEntries || 9); - this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); - - if (format) { - this._initFormat(format); - } - - this.clear(); -} - -rbush.prototype = { - - all: function () { - return this._all(this.data, []); - }, - - search: function (bbox) { - - var node = this.data, - result = [], - toBBox = this.toBBox; - - if (!intersects(bbox, node.bbox)) return result; - - var nodesToSearch = [], - i, len, child, childBBox; - - while (node) { - for (i = 0, len = node.children.length; i < len; i++) { - - child = node.children[i]; - childBBox = node.leaf ? toBBox(child) : child.bbox; - - if (intersects(bbox, childBBox)) { - if (node.leaf) result.push(child); - else if (contains(bbox, childBBox)) this._all(child, result); - else nodesToSearch.push(child); - } - } - node = nodesToSearch.pop(); - } - - return result; - }, - - collides: function (bbox) { - - var node = this.data, - toBBox = this.toBBox; - - if (!intersects(bbox, node.bbox)) return false; - - var nodesToSearch = [], - i, len, child, childBBox; - - while (node) { - for (i = 0, len = node.children.length; i < len; i++) { - - child = node.children[i]; - childBBox = node.leaf ? toBBox(child) : child.bbox; - - if (intersects(bbox, childBBox)) { - if (node.leaf || contains(bbox, childBBox)) return true; - nodesToSearch.push(child); - } - } - node = nodesToSearch.pop(); - } - - return false; - }, - - load: function (data) { - if (!(data && data.length)) return this; - - if (data.length < this._minEntries) { - for (var i = 0, len = data.length; i < len; i++) { - this.insert(data[i]); - } - return this; - } - - // recursively build the tree with the given data from stratch using OMT algorithm - var node = this._build(data.slice(), 0, data.length - 1, 0); - - if (!this.data.children.length) { - // save as is if tree is empty - this.data = node; - - } else if (this.data.height === node.height) { - // split root if trees have the same height - this._splitRoot(this.data, node); - - } else { - if (this.data.height < node.height) { - // swap trees if inserted one is bigger - var tmpNode = this.data; - this.data = node; - node = tmpNode; - } - - // insert the small tree into the large tree at appropriate level - this._insert(node, this.data.height - node.height - 1, true); - } - - return this; - }, - - insert: function (item) { - if (item) this._insert(item, this.data.height - 1); - return this; - }, - - clear: function () { - this.data = { - children: [], - height: 1, - bbox: empty(), - leaf: true - }; - return this; - }, - - remove: function (item) { - if (!item) return this; - - var node = this.data, - bbox = this.toBBox(item), - path = [], - indexes = [], - i, parent, index, goingUp; - - // depth-first iterative tree traversal - while (node || path.length) { - - if (!node) { // go up - node = path.pop(); - parent = path[path.length - 1]; - i = indexes.pop(); - goingUp = true; - } - - if (node.leaf) { // check current node - index = node.children.indexOf(item); - - if (index !== -1) { - // item found, remove the item and condense tree upwards - node.children.splice(index, 1); - path.push(node); - this._condense(path); - return this; - } - } - - if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down - path.push(node); - indexes.push(i); - i = 0; - parent = node; - node = node.children[0]; - - } else if (parent) { // go right - i++; - node = parent.children[i]; - goingUp = false; - - } else node = null; // nothing found - } - - return this; - }, - - toBBox: function (item) { return item; }, - - compareMinX: function (a, b) { return a[0] - b[0]; }, - compareMinY: function (a, b) { return a[1] - b[1]; }, - - toJSON: function () { return this.data; }, - - fromJSON: function (data) { - this.data = data; - return this; - }, - - _all: function (node, result) { - var nodesToSearch = []; - while (node) { - if (node.leaf) result.push.apply(result, node.children); - else nodesToSearch.push.apply(nodesToSearch, node.children); - - node = nodesToSearch.pop(); - } - return result; - }, - - _build: function (items, left, right, height) { - - var N = right - left + 1, - M = this._maxEntries, - node; - - if (N <= M) { - // reached leaf level; return leaf - node = { - children: items.slice(left, right + 1), - height: 1, - bbox: null, - leaf: true - }; - calcBBox(node, this.toBBox); - return node; - } - - if (!height) { - // target height of the bulk-loaded tree - height = Math.ceil(Math.log(N) / Math.log(M)); - - // target number of root entries to maximize storage utilization - M = Math.ceil(N / Math.pow(M, height - 1)); - } - - // TODO eliminate recursion? - - node = { - children: [], - height: height, - bbox: null - }; - - // split the items into M mostly square tiles - - var N2 = Math.ceil(N / M), - N1 = N2 * Math.ceil(Math.sqrt(M)), - i, j, right2, right3; - - multiSelect(items, left, right, N1, this.compareMinX); - - for (i = left; i <= right; i += N1) { - - right2 = Math.min(i + N1 - 1, right); - - multiSelect(items, i, right2, N2, this.compareMinY); - - for (j = i; j <= right2; j += N2) { - - right3 = Math.min(j + N2 - 1, right2); - - // pack each entry recursively - node.children.push(this._build(items, j, right3, height - 1)); - } - } - - calcBBox(node, this.toBBox); - - return node; - }, - - _chooseSubtree: function (bbox, node, level, path) { - - var i, len, child, targetNode, area, enlargement, minArea, minEnlargement; - - while (true) { - path.push(node); - - if (node.leaf || path.length - 1 === level) break; - - minArea = minEnlargement = Infinity; - - for (i = 0, len = node.children.length; i < len; i++) { - child = node.children[i]; - area = bboxArea(child.bbox); - enlargement = enlargedArea(bbox, child.bbox) - area; - - // choose entry with the least area enlargement - if (enlargement < minEnlargement) { - minEnlargement = enlargement; - minArea = area < minArea ? area : minArea; - targetNode = child; - - } else if (enlargement === minEnlargement) { - // otherwise choose one with the smallest area - if (area < minArea) { - minArea = area; - targetNode = child; - } - } - } - - node = targetNode; - } - - return node; - }, - - _insert: function (item, level, isNode) { - - var toBBox = this.toBBox, - bbox = isNode ? item.bbox : toBBox(item), - insertPath = []; - - // find the best node for accommodating the item, saving all nodes along the path too - var node = this._chooseSubtree(bbox, this.data, level, insertPath); - - // put the item into the node - node.children.push(item); - extend(node.bbox, bbox); - - // split on node overflow; propagate upwards if necessary - while (level >= 0) { - if (insertPath[level].children.length > this._maxEntries) { - this._split(insertPath, level); - level--; - } else break; - } - - // adjust bboxes along the insertion path - this._adjustParentBBoxes(bbox, insertPath, level); - }, - - // split overflowed node into two - _split: function (insertPath, level) { - - var node = insertPath[level], - M = node.children.length, - m = this._minEntries; - - this._chooseSplitAxis(node, m, M); - - var splitIndex = this._chooseSplitIndex(node, m, M); - - var newNode = { - children: node.children.splice(splitIndex, node.children.length - splitIndex), - height: node.height - }; - - if (node.leaf) newNode.leaf = true; - - calcBBox(node, this.toBBox); - calcBBox(newNode, this.toBBox); - - if (level) insertPath[level - 1].children.push(newNode); - else this._splitRoot(node, newNode); - }, - - _splitRoot: function (node, newNode) { - // split root node - this.data = { - children: [node, newNode], - height: node.height + 1 - }; - calcBBox(this.data, this.toBBox); - }, - - _chooseSplitIndex: function (node, m, M) { - - var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index; - - minOverlap = minArea = Infinity; - - for (i = m; i <= M - m; i++) { - bbox1 = distBBox(node, 0, i, this.toBBox); - bbox2 = distBBox(node, i, M, this.toBBox); - - overlap = intersectionArea(bbox1, bbox2); - area = bboxArea(bbox1) + bboxArea(bbox2); - - // choose distribution with minimum overlap - if (overlap < minOverlap) { - minOverlap = overlap; - index = i; - - minArea = area < minArea ? area : minArea; - - } else if (overlap === minOverlap) { - // otherwise choose distribution with minimum area - if (area < minArea) { - minArea = area; - index = i; - } - } - } - - return index; - }, - - // sorts node children by the best axis for split - _chooseSplitAxis: function (node, m, M) { - - var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX, - compareMinY = node.leaf ? this.compareMinY : compareNodeMinY, - xMargin = this._allDistMargin(node, m, M, compareMinX), - yMargin = this._allDistMargin(node, m, M, compareMinY); - - // if total distributions margin value is minimal for x, sort by minX, - // otherwise it's already sorted by minY - if (xMargin < yMargin) node.children.sort(compareMinX); - }, - - // total margin of all possible split distributions where each node is at least m full - _allDistMargin: function (node, m, M, compare) { - - node.children.sort(compare); - - var toBBox = this.toBBox, - leftBBox = distBBox(node, 0, m, toBBox), - rightBBox = distBBox(node, M - m, M, toBBox), - margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), - i, child; - - for (i = m; i < M - m; i++) { - child = node.children[i]; - extend(leftBBox, node.leaf ? toBBox(child) : child.bbox); - margin += bboxMargin(leftBBox); - } - - for (i = M - m - 1; i >= m; i--) { - child = node.children[i]; - extend(rightBBox, node.leaf ? toBBox(child) : child.bbox); - margin += bboxMargin(rightBBox); - } - - return margin; - }, - - _adjustParentBBoxes: function (bbox, path, level) { - // adjust bboxes along the given tree path - for (var i = level; i >= 0; i--) { - extend(path[i].bbox, bbox); - } - }, - - _condense: function (path) { - // go through the path, removing empty nodes and updating bboxes - for (var i = path.length - 1, siblings; i >= 0; i--) { - if (path[i].children.length === 0) { - if (i > 0) { - siblings = path[i - 1].children; - siblings.splice(siblings.indexOf(path[i]), 1); - - } else this.clear(); - - } else calcBBox(path[i], this.toBBox); - } - }, - - _initFormat: function (format) { - // data format (minX, minY, maxX, maxY accessors) - - // uses eval-type function compilation instead of just accepting a toBBox function - // because the algorithms are very sensitive to sorting functions performance, - // so they should be dead simple and without inner calls - - // jshint evil: true - - var compareArr = ['return a', ' - b', ';']; - - this.compareMinX = new Function('a', 'b', compareArr.join(format[0])); - this.compareMinY = new Function('a', 'b', compareArr.join(format[1])); - - this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];'); - } -}; - - -// calculate node's bbox from bboxes of its children -function calcBBox(node, toBBox) { - node.bbox = distBBox(node, 0, node.children.length, toBBox); -} - -// min bounding rectangle of node children from k to p-1 -function distBBox(node, k, p, toBBox) { - var bbox = empty(); - - for (var i = k, child; i < p; i++) { - child = node.children[i]; - extend(bbox, node.leaf ? toBBox(child) : child.bbox); - } - - return bbox; -} - -function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; } - -function extend(a, b) { - a[0] = Math.min(a[0], b[0]); - a[1] = Math.min(a[1], b[1]); - a[2] = Math.max(a[2], b[2]); - a[3] = Math.max(a[3], b[3]); - return a; -} - -function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; } -function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; } - -function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); } -function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); } - -function enlargedArea(a, b) { - return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) * - (Math.max(b[3], a[3]) - Math.min(b[1], a[1])); -} - -function intersectionArea(a, b) { - var minX = Math.max(a[0], b[0]), - minY = Math.max(a[1], b[1]), - maxX = Math.min(a[2], b[2]), - maxY = Math.min(a[3], b[3]); - - return Math.max(0, maxX - minX) * - Math.max(0, maxY - minY); -} - -function contains(a, b) { - return a[0] <= b[0] && - a[1] <= b[1] && - b[2] <= a[2] && - b[3] <= a[3]; -} - -function intersects(a, b) { - return b[0] <= a[2] && - b[1] <= a[3] && - b[2] >= a[0] && - b[3] >= a[1]; -} - -// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; -// combines selection algorithm with binary divide & conquer approach - -function multiSelect(arr, left, right, n, compare) { - var stack = [left, right], - mid; - - while (stack.length) { - right = stack.pop(); - left = stack.pop(); - - if (right - left <= n) continue; - - mid = left + Math.ceil((right - left) / n / 2) * n; - select(arr, left, right, mid, compare); - - stack.push(left, mid, mid, right); - } -} - -// Floyd-Rivest selection algorithm: -// sort an array between left and right (inclusive) so that the smallest k elements come first (unordered) -function select(arr, left, right, k, compare) { - var n, i, z, s, sd, newLeft, newRight, t, j; - - while (right > left) { - if (right - left > 600) { - n = right - left + 1; - i = k - left + 1; - z = Math.log(n); - s = 0.5 * Math.exp(2 * z / 3); - sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1); - newLeft = Math.max(left, Math.floor(k - i * s / n + sd)); - newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd)); - select(arr, newLeft, newRight, k, compare); - } - - t = arr[k]; - i = left; - j = right; - - swap(arr, left, k); - if (compare(arr[right], t) > 0) swap(arr, left, right); - - while (i < j) { - swap(arr, i, j); - i++; - j--; - while (compare(arr[i], t) < 0) i++; - while (compare(arr[j], t) > 0) j--; - } - - if (compare(arr[left], t) === 0) swap(arr, left, j); - else { - j++; - swap(arr, j, right); - } - - if (j <= k) left = j + 1; - if (k <= j) right = j - 1; - } -} - -function swap(arr, i, j) { - var tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; -} - - -// export as AMD/CommonJS module or global variable -if (typeof define === 'function' && define.amd) define('rbush', function() { return rbush; }); -else if (typeof module !== 'undefined') module.exports = rbush; -else if (typeof self !== 'undefined') self.rbush = rbush; -else window.rbush = rbush; - -})(); - -ol.ext.rbush = module.exports; -})(); - -goog.provide('ol.structs.RBush'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.ext.rbush'); -goog.require('ol.extent'); - - - -/** - * Wrapper around the RBush by Vladimir Agafonkin. - * - * @constructor - * @param {number=} opt_maxEntries Max entries. - * @see https://github.com/mourner/rbush - * @struct - * @template T - */ -ol.structs.RBush = function(opt_maxEntries) { - - /** - * @private - */ - this.rbush_ = ol.ext.rbush(opt_maxEntries); - - /** - * A mapping between the objects added to this rbush wrapper - * and the objects that are actually added to the internal rbush. - * @private - * @type {Object.<number, Object>} - */ - this.items_ = {}; - - if (goog.DEBUG) { - /** - * @private - * @type {number} - */ - this.readers_ = 0; - } -}; - - -/** - * Insert a value into the RBush. - * @param {ol.Extent} extent Extent. - * @param {T} value Value. - */ -ol.structs.RBush.prototype.insert = function(extent, value) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not insert value while reading'); - } - var item = [ - extent[0], - extent[1], - extent[2], - extent[3], - value - ]; - this.rbush_.insert(item); - // remember the object that was added to the internal rbush - goog.asserts.assert( - !goog.object.containsKey(this.items_, goog.getUid(value)), - 'uid (%s) of value (%s) already exists', goog.getUid(value), value); - this.items_[goog.getUid(value)] = item; -}; - - -/** - * Bulk-insert values into the RBush. - * @param {Array.<ol.Extent>} extents Extents. - * @param {Array.<T>} values Values. - */ -ol.structs.RBush.prototype.load = function(extents, values) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not insert values while reading'); - } - goog.asserts.assert(extents.length === values.length, - 'extens and values must have same length (%s === %s)', - extents.length, values.length); - - var items = new Array(values.length); - for (var i = 0, l = values.length; i < l; i++) { - var extent = extents[i]; - var value = values[i]; - - var item = [ - extent[0], - extent[1], - extent[2], - extent[3], - value - ]; - items[i] = item; - goog.asserts.assert( - !goog.object.containsKey(this.items_, goog.getUid(value)), - 'uid (%s) of value (%s) already exists', goog.getUid(value), value); - this.items_[goog.getUid(value)] = item; - } - this.rbush_.load(items); -}; - - -/** - * Remove a value from the RBush. - * @param {T} value Value. - * @return {boolean} Removed. - */ -ol.structs.RBush.prototype.remove = function(value) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not remove value while reading'); - } - var uid = goog.getUid(value); - goog.asserts.assert(goog.object.containsKey(this.items_, uid), - 'uid (%s) of value (%s) does not exist', uid, value); - - // get the object in which the value was wrapped when adding to the - // internal rbush. then use that object to do the removal. - var item = this.items_[uid]; - delete this.items_[uid]; - return this.rbush_.remove(item) !== null; -}; - - -/** - * Update the extent of a value in the RBush. - * @param {ol.Extent} extent Extent. - * @param {T} value Value. - */ -ol.structs.RBush.prototype.update = function(extent, value) { - var uid = goog.getUid(value); - goog.asserts.assert(goog.object.containsKey(this.items_, uid), - 'uid (%s) of value (%s) does not exist', uid, value); - - var item = this.items_[uid]; - if (!ol.extent.equals(item.slice(0, 4), extent)) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not update extent while reading'); - } - this.remove(value); - this.insert(extent, value); - } -}; - - -/** - * Return all values in the RBush. - * @return {Array.<T>} All. - */ -ol.structs.RBush.prototype.getAll = function() { - var items = this.rbush_.all(); - return items.map(function(item) { - return item[4]; - }); -}; - - -/** - * Return all values in the given extent. - * @param {ol.Extent} extent Extent. - * @return {Array.<T>} All in extent. - */ -ol.structs.RBush.prototype.getInExtent = function(extent) { - var items = this.rbush_.search(extent); - return items.map(function(item) { - return item[4]; - }); -}; - - -/** - * Calls a callback function with each value in the tree. - * If the callback returns a truthy value, this value is returned without - * checking the rest of the tree. - * @param {function(this: S, T): *} callback Callback. - * @param {S=} opt_this The object to use as `this` in `callback`. - * @return {*} Callback return value. - * @template S - */ -ol.structs.RBush.prototype.forEach = function(callback, opt_this) { - if (goog.DEBUG) { - ++this.readers_; - try { - return this.forEach_(this.getAll(), callback, opt_this); - } finally { - --this.readers_; - } - } else { - return this.forEach_(this.getAll(), callback, opt_this); - } -}; - - -/** - * Calls a callback function with each value in the provided extent. - * @param {ol.Extent} extent Extent. - * @param {function(this: S, T): *} callback Callback. - * @param {S=} opt_this The object to use as `this` in `callback`. - * @return {*} Callback return value. - * @template S - */ -ol.structs.RBush.prototype.forEachInExtent = - function(extent, callback, opt_this) { - if (goog.DEBUG) { - ++this.readers_; - try { - return this.forEach_(this.getInExtent(extent), callback, opt_this); - } finally { - --this.readers_; - } - } else { - return this.forEach_(this.getInExtent(extent), callback, opt_this); - } -}; - - -/** - * @param {Array.<T>} values Values. - * @param {function(this: S, T): *} callback Callback. - * @param {S=} opt_this The object to use as `this` in `callback`. - * @private - * @return {*} Callback return value. - * @template S - */ -ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) { - var result; - for (var i = 0, l = values.length; i < l; i++) { - result = callback.call(opt_this, values[i]); - if (result) { - return result; - } - } - return result; -}; - - -/** - * @return {boolean} Is empty. - */ -ol.structs.RBush.prototype.isEmpty = function() { - return goog.object.isEmpty(this.items_); -}; - - -/** - * Remove all values from the RBush. - */ -ol.structs.RBush.prototype.clear = function() { - this.rbush_.clear(); - this.items_ = {}; -}; - - -/** - * @param {ol.Extent=} opt_extent Extent. - * @return {!ol.Extent} Extent. - */ -ol.structs.RBush.prototype.getExtent = function(opt_extent) { - // FIXME add getExtent() to rbush - return this.rbush_.data.bbox; -}; - -// FIXME bulk feature upload - suppress events -// FIXME make change-detection more refined (notably, geometry hint) - -goog.provide('ol.source.Vector'); -goog.provide('ol.source.VectorEvent'); -goog.provide('ol.source.VectorEventType'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Extent'); -goog.require('ol.Feature'); -goog.require('ol.FeatureLoader'); -goog.require('ol.LoadingStrategy'); -goog.require('ol.ObjectEventType'); -goog.require('ol.extent'); -goog.require('ol.featureloader'); -goog.require('ol.loadingstrategy'); -goog.require('ol.proj'); -goog.require('ol.source.Source'); -goog.require('ol.source.State'); -goog.require('ol.structs.RBush'); - - -/** - * @enum {string} - */ -ol.source.VectorEventType = { - /** - * Triggered when a feature is added to the source. - * @event ol.source.VectorEvent#addfeature - * @api stable - */ - ADDFEATURE: 'addfeature', - - /** - * Triggered when a feature is updated. - * @event ol.source.VectorEvent#changefeature - * @api - */ - CHANGEFEATURE: 'changefeature', - - /** - * Triggered when the clear method is called on the source. - * @event ol.source.VectorEvent#clear - * @api - */ - CLEAR: 'clear', - - /** - * Triggered when a feature is removed from the source. - * See {@link ol.source.Vector#clear source.clear()} for exceptions. - * @event ol.source.VectorEvent#removefeature - * @api stable - */ - REMOVEFEATURE: 'removefeature' -}; - - - -/** - * @classdesc - * Provides a source of features for vector layers. Vector features provided - * by this source are suitable for editing. See {@link ol.source.VectorTile} for - * vector data that is optimized for rendering. - * - * @constructor - * @extends {ol.source.Source} - * @fires ol.source.VectorEvent - * @param {olx.source.VectorOptions=} opt_options Vector source options. - * @api stable - */ -ol.source.Vector = function(opt_options) { - - var options = opt_options || {}; - - goog.base(this, { - attributions: options.attributions, - logo: options.logo, - projection: undefined, - state: ol.source.State.READY, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - - /** - * @private - * @type {ol.FeatureLoader} - */ - this.loader_ = ol.nullFunction; - - if (options.loader !== undefined) { - this.loader_ = options.loader; - } else if (options.url !== undefined) { - goog.asserts.assert(options.format !== undefined, - 'format must be set when url is set'); - // create a XHR feature loader for "url" and "format" - this.loader_ = ol.featureloader.xhr(options.url, options.format); - } - - /** - * @private - * @type {ol.LoadingStrategy} - */ - this.strategy_ = options.strategy !== undefined ? options.strategy : - ol.loadingstrategy.all; - - var useSpatialIndex = - options.useSpatialIndex !== undefined ? options.useSpatialIndex : true; - - /** - * @private - * @type {ol.structs.RBush.<ol.Feature>} - */ - this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null; - - /** - * @private - * @type {ol.structs.RBush.<{extent: ol.Extent}>} - */ - this.loadedExtentsRtree_ = new ol.structs.RBush(); - - /** - * @private - * @type {Object.<string, ol.Feature>} - */ - this.nullGeometryFeatures_ = {}; - - /** - * A lookup of features by id (the return from feature.getId()). - * @private - * @type {Object.<string, ol.Feature>} - */ - this.idIndex_ = {}; - - /** - * A lookup of features without id (keyed by goog.getUid(feature)). - * @private - * @type {Object.<string, ol.Feature>} - */ - this.undefIdIndex_ = {}; - - /** - * @private - * @type {Object.<string, Array.<goog.events.Key>>} - */ - this.featureChangeKeys_ = {}; - - /** - * @private - * @type {ol.Collection.<ol.Feature>} - */ - this.featuresCollection_ = null; - - var collection, features; - if (options.features instanceof ol.Collection) { - collection = options.features; - features = collection.getArray(); - } else if (goog.isArray(options.features)) { - features = options.features; - } - if (!useSpatialIndex && collection === undefined) { - collection = new ol.Collection(features); - } - if (features !== undefined) { - this.addFeaturesInternal(features); - } - if (collection !== undefined) { - this.bindFeaturesCollection_(collection); - } - -}; -goog.inherits(ol.source.Vector, ol.source.Source); - - -/** - * Add a single feature to the source. If you want to add a batch of features - * at once, call {@link ol.source.Vector#addFeatures source.addFeatures()} - * instead. - * @param {ol.Feature} feature Feature to add. - * @api stable - */ -ol.source.Vector.prototype.addFeature = function(feature) { - this.addFeatureInternal(feature); - this.changed(); -}; - - -/** - * Add a feature without firing a `change` event. - * @param {ol.Feature} feature Feature. - * @protected - */ -ol.source.Vector.prototype.addFeatureInternal = function(feature) { - var featureKey = goog.getUid(feature).toString(); - - if (!this.addToIndex_(featureKey, feature)) { - return; - } - - this.setupChangeEvents_(featureKey, feature); - - var geometry = feature.getGeometry(); - if (geometry) { - var extent = geometry.getExtent(); - if (this.featuresRtree_) { - this.featuresRtree_.insert(extent, feature); - } - } else { - this.nullGeometryFeatures_[featureKey] = feature; - } - - this.dispatchEvent( - new ol.source.VectorEvent(ol.source.VectorEventType.ADDFEATURE, feature)); -}; - - -/** - * @param {string} featureKey - * @param {ol.Feature} feature - * @private - */ -ol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) { - goog.asserts.assert(!(featureKey in this.featureChangeKeys_), - 'key (%s) not yet registered in featureChangeKey', featureKey); - this.featureChangeKeys_[featureKey] = [ - goog.events.listen(feature, - goog.events.EventType.CHANGE, - this.handleFeatureChange_, false, this), - goog.events.listen(feature, - ol.ObjectEventType.PROPERTYCHANGE, - this.handleFeatureChange_, false, this) - ]; -}; - - -/** - * @param {string} featureKey - * @param {ol.Feature} feature - * @return {boolean} `true` if the feature is "valid", in the sense that it is - * also a candidate for insertion into the Rtree, otherwise `false`. - * @private - */ -ol.source.Vector.prototype.addToIndex_ = function(featureKey, feature) { - var valid = true; - var id = feature.getId(); - if (id !== undefined) { - if (!(id.toString() in this.idIndex_)) { - this.idIndex_[id.toString()] = feature; - } else { - valid = false; - } - } else { - goog.asserts.assert(!(featureKey in this.undefIdIndex_), - 'Feature already added to the source'); - this.undefIdIndex_[featureKey] = feature; - } - return valid; -}; - - -/** - * Add a batch of features to the source. - * @param {Array.<ol.Feature>} features Features to add. - * @api stable - */ -ol.source.Vector.prototype.addFeatures = function(features) { - this.addFeaturesInternal(features); - this.changed(); -}; - - -/** - * Add features without firing a `change` event. - * @param {Array.<ol.Feature>} features Features. - * @protected - */ -ol.source.Vector.prototype.addFeaturesInternal = function(features) { - var featureKey, i, length, feature; - - var extents = []; - var newFeatures = []; - var geometryFeatures = []; - - for (i = 0, length = features.length; i < length; i++) { - feature = features[i]; - featureKey = goog.getUid(feature).toString(); - if (this.addToIndex_(featureKey, feature)) { - newFeatures.push(feature); - } - } - - for (i = 0, length = newFeatures.length; i < length; i++) { - feature = newFeatures[i]; - featureKey = goog.getUid(feature).toString(); - this.setupChangeEvents_(featureKey, feature); - - var geometry = feature.getGeometry(); - if (geometry) { - var extent = geometry.getExtent(); - extents.push(extent); - geometryFeatures.push(feature); - } else { - this.nullGeometryFeatures_[featureKey] = feature; - } - } - if (this.featuresRtree_) { - this.featuresRtree_.load(extents, geometryFeatures); - } - - for (i = 0, length = newFeatures.length; i < length; i++) { - this.dispatchEvent(new ol.source.VectorEvent( - ol.source.VectorEventType.ADDFEATURE, newFeatures[i])); - } -}; - - -/** - * @param {!ol.Collection.<ol.Feature>} collection Collection. - * @private - */ -ol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) { - goog.asserts.assert(!this.featuresCollection_, - 'bindFeaturesCollection can only be called once'); - var modifyingCollection = false; - goog.events.listen(this, ol.source.VectorEventType.ADDFEATURE, - function(evt) { - if (!modifyingCollection) { - modifyingCollection = true; - collection.push(evt.feature); - modifyingCollection = false; - } - }); - goog.events.listen(this, ol.source.VectorEventType.REMOVEFEATURE, - function(evt) { - if (!modifyingCollection) { - modifyingCollection = true; - collection.remove(evt.feature); - modifyingCollection = false; - } - }); - goog.events.listen(collection, ol.CollectionEventType.ADD, - function(evt) { - if (!modifyingCollection) { - var feature = evt.element; - goog.asserts.assertInstanceof(feature, ol.Feature); - modifyingCollection = true; - this.addFeature(feature); - modifyingCollection = false; - } - }, false, this); - goog.events.listen(collection, ol.CollectionEventType.REMOVE, - function(evt) { - if (!modifyingCollection) { - var feature = evt.element; - goog.asserts.assertInstanceof(feature, ol.Feature); - modifyingCollection = true; - this.removeFeature(feature); - modifyingCollection = false; - } - }, false, this); - this.featuresCollection_ = collection; -}; - - -/** - * Remove all features from the source. - * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events. - * @api stable - */ -ol.source.Vector.prototype.clear = function(opt_fast) { - if (opt_fast) { - for (var featureId in this.featureChangeKeys_) { - var keys = this.featureChangeKeys_[featureId]; - keys.forEach(goog.events.unlistenByKey); - } - if (!this.featuresCollection_) { - this.featureChangeKeys_ = {}; - this.idIndex_ = {}; - this.undefIdIndex_ = {}; - } - } else { - var rmFeatureInternal = this.removeFeatureInternal; - if (this.featuresRtree_) { - this.featuresRtree_.forEach(rmFeatureInternal, this); - goog.object.forEach(this.nullGeometryFeatures_, rmFeatureInternal, this); - } - } - if (this.featuresCollection_) { - this.featuresCollection_.clear(); - } - goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_), - 'featureChangeKeys is an empty object now'); - goog.asserts.assert(goog.object.isEmpty(this.idIndex_), - 'idIndex is an empty object now'); - goog.asserts.assert(goog.object.isEmpty(this.undefIdIndex_), - 'undefIdIndex is an empty object now'); - - if (this.featuresRtree_) { - this.featuresRtree_.clear(); - } - this.loadedExtentsRtree_.clear(); - this.nullGeometryFeatures_ = {}; - - var clearEvent = new ol.source.VectorEvent(ol.source.VectorEventType.CLEAR); - this.dispatchEvent(clearEvent); - this.changed(); -}; - - -/** - * Iterate through all features on the source, calling the provided callback - * with each one. If the callback returns any "truthy" value, iteration will - * stop and the function will return the same value. - * - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * on the source. Return a truthy value to stop iteration. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - * @api stable - */ -ol.source.Vector.prototype.forEachFeature = function(callback, opt_this) { - if (this.featuresRtree_) { - return this.featuresRtree_.forEach(callback, opt_this); - } else if (this.featuresCollection_) { - return this.featuresCollection_.forEach(callback, opt_this); - } -}; - - -/** - * Iterate through all features whose geometries contain the provided - * coordinate, calling the callback with each feature. If the callback returns - * a "truthy" value, iteration will stop and the function will return the same - * value. - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * whose goemetry contains the provided coordinate. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - */ -ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect = - function(coordinate, callback, opt_this) { - var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]]; - return this.forEachFeatureInExtent(extent, function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, 'feature geometry is defined and not null'); - if (geometry.containsCoordinate(coordinate)) { - return callback.call(opt_this, feature); - } else { - return undefined; - } - }); -}; - - -/** - * Iterate through all features whose bounding box intersects the provided - * extent (note that the feature's geometry may not intersect the extent), - * calling the callback with each feature. If the callback returns a "truthy" - * value, iteration will stop and the function will return the same value. - * - * If you are interested in features whose geometry intersects an extent, call - * the {@link ol.source.Vector#forEachFeatureIntersectingExtent - * source.forEachFeatureIntersectingExtent()} method instead. - * - * When `useSpatialIndex` is set to false, this method will loop through all - * features, equivalent to {@link ol.source.Vector#forEachFeature}. - * - * @param {ol.Extent} extent Extent. - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * whose bounding box intersects the provided extent. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - * @api - */ -ol.source.Vector.prototype.forEachFeatureInExtent = - function(extent, callback, opt_this) { - if (this.featuresRtree_) { - return this.featuresRtree_.forEachInExtent(extent, callback, opt_this); - } else if (this.featuresCollection_) { - return this.featuresCollection_.forEach(callback, opt_this); - } -}; - - -/** - * Iterate through all features whose geometry intersects the provided extent, - * calling the callback with each feature. If the callback returns a "truthy" - * value, iteration will stop and the function will return the same value. - * - * If you only want to test for bounding box intersection, call the - * {@link ol.source.Vector#forEachFeatureInExtent - * source.forEachFeatureInExtent()} method instead. - * - * @param {ol.Extent} extent Extent. - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * whose geometry intersects the provided extent. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - * @api - */ -ol.source.Vector.prototype.forEachFeatureIntersectingExtent = - function(extent, callback, opt_this) { - return this.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - * @return {S|undefined} - * @template S - */ - function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, - 'feature geometry is defined and not null'); - if (geometry.intersectsExtent(extent)) { - var result = callback.call(opt_this, feature); - if (result) { - return result; - } - } - }); -}; - - -/** - * Get the features collection associated with this source. Will be `null` - * unless the source was configured with `useSpatialIndex` set to `false`, or - * with an {@link ol.Collection} as `features`. - * @return {ol.Collection.<ol.Feature>} - * @api - */ -ol.source.Vector.prototype.getFeaturesCollection = function() { - return this.featuresCollection_; -}; - - -/** - * Get all features on the source. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.source.Vector.prototype.getFeatures = function() { - var features; - if (this.featuresCollection_) { - features = this.featuresCollection_.getArray(); - } else if (this.featuresRtree_) { - features = this.featuresRtree_.getAll(); - if (!goog.object.isEmpty(this.nullGeometryFeatures_)) { - goog.array.extend( - features, goog.object.getValues(this.nullGeometryFeatures_)); - } - } - goog.asserts.assert(features !== undefined, - 'Neither featuresRtree_ nor featuresCollection_ are available'); - return features; -}; - - -/** - * Get all features whose geometry intersects the provided coordinate. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) { - var features = []; - this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) { - features.push(feature); - }); - return features; -}; - - -/** - * Get all features in the provided extent. Note that this returns all features - * whose bounding boxes intersect the given extent (so it may include features - * whose geometries do not intersect the extent). - * - * This method is not available when the source is configured with - * `useSpatialIndex` set to `false`. - * @param {ol.Extent} extent Extent. - * @return {Array.<ol.Feature>} Features. - * @api - */ -ol.source.Vector.prototype.getFeaturesInExtent = function(extent) { - goog.asserts.assert(this.featuresRtree_, - 'getFeaturesInExtent does not work when useSpatialIndex is set to false'); - return this.featuresRtree_.getInExtent(extent); -}; - - -/** - * Get the closest feature to the provided coordinate. - * - * This method is not available when the source is configured with - * `useSpatialIndex` set to `false`. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Feature} Closest feature. - * @api stable - */ -ol.source.Vector.prototype.getClosestFeatureToCoordinate = - function(coordinate) { - // Find the closest feature using branch and bound. We start searching an - // infinite extent, and find the distance from the first feature found. This - // becomes the closest feature. We then compute a smaller extent which any - // closer feature must intersect. We continue searching with this smaller - // extent, trying to find a closer feature. Every time we find a closer - // feature, we update the extent being searched so that any even closer - // feature must intersect it. We continue until we run out of features. - var x = coordinate[0]; - var y = coordinate[1]; - var closestFeature = null; - var closestPoint = [NaN, NaN]; - var minSquaredDistance = Infinity; - var extent = [-Infinity, -Infinity, Infinity, Infinity]; - goog.asserts.assert(this.featuresRtree_, - 'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' + - 'to false'); - this.featuresRtree_.forEachInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, - 'feature geometry is defined and not null'); - var previousMinSquaredDistance = minSquaredDistance; - minSquaredDistance = geometry.closestPointXY( - x, y, closestPoint, minSquaredDistance); - if (minSquaredDistance < previousMinSquaredDistance) { - closestFeature = feature; - // This is sneaky. Reduce the extent that it is currently being - // searched while the R-Tree traversal using this same extent object - // is still in progress. This is safe because the new extent is - // strictly contained by the old extent. - var minDistance = Math.sqrt(minSquaredDistance); - extent[0] = x - minDistance; - extent[1] = y - minDistance; - extent[2] = x + minDistance; - extent[3] = y + minDistance; - } - }); - return closestFeature; -}; - - -/** - * Get the extent of the features currently in the source. - * - * This method is not available when the source is configured with - * `useSpatialIndex` set to `false`. - * @return {!ol.Extent} Extent. - * @api stable - */ -ol.source.Vector.prototype.getExtent = function() { - goog.asserts.assert(this.featuresRtree_, - 'getExtent does not work when useSpatialIndex is set to false'); - return this.featuresRtree_.getExtent(); -}; - - -/** - * Get a feature by its identifier (the value returned by feature.getId()). - * Note that the index treats string and numeric identifiers as the same. So - * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`. - * - * @param {string|number} id Feature identifier. - * @return {ol.Feature} The feature (or `null` if not found). - * @api stable - */ -ol.source.Vector.prototype.getFeatureById = function(id) { - var feature = this.idIndex_[id.toString()]; - return feature !== undefined ? feature : null; -}; - - -/** - * @param {goog.events.Event} event Event. - * @private - */ -ol.source.Vector.prototype.handleFeatureChange_ = function(event) { - var feature = /** @type {ol.Feature} */ (event.target); - var featureKey = goog.getUid(feature).toString(); - var geometry = feature.getGeometry(); - if (!geometry) { - if (!(featureKey in this.nullGeometryFeatures_)) { - if (this.featuresRtree_) { - this.featuresRtree_.remove(feature); - } - this.nullGeometryFeatures_[featureKey] = feature; - } - } else { - var extent = geometry.getExtent(); - if (featureKey in this.nullGeometryFeatures_) { - delete this.nullGeometryFeatures_[featureKey]; - if (this.featuresRtree_) { - this.featuresRtree_.insert(extent, feature); - } - } else { - if (this.featuresRtree_) { - this.featuresRtree_.update(extent, feature); - } - } - } - var id = feature.getId(); - var removed; - if (id !== undefined) { - var sid = id.toString(); - if (featureKey in this.undefIdIndex_) { - delete this.undefIdIndex_[featureKey]; - this.idIndex_[sid] = feature; - } else { - if (this.idIndex_[sid] !== feature) { - removed = this.removeFromIdIndex_(feature); - goog.asserts.assert(removed, - 'Expected feature to be removed from index'); - this.idIndex_[sid] = feature; - } - } - } else { - if (!(featureKey in this.undefIdIndex_)) { - removed = this.removeFromIdIndex_(feature); - goog.asserts.assert(removed, - 'Expected feature to be removed from index'); - this.undefIdIndex_[featureKey] = feature; - } else { - goog.asserts.assert(this.undefIdIndex_[featureKey] === feature, - 'feature keyed under %s in undefIdKeys', featureKey); - } - } - this.changed(); - this.dispatchEvent(new ol.source.VectorEvent( - ol.source.VectorEventType.CHANGEFEATURE, feature)); -}; - - -/** - * @return {boolean} Is empty. - */ -ol.source.Vector.prototype.isEmpty = function() { - return this.featuresRtree_.isEmpty() && - goog.object.isEmpty(this.nullGeometryFeatures_); -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {ol.proj.Projection} projection Projection. - */ -ol.source.Vector.prototype.loadFeatures = function( - extent, resolution, projection) { - var loadedExtentsRtree = this.loadedExtentsRtree_; - var extentsToLoad = this.strategy_(extent, resolution); - var i, ii; - for (i = 0, ii = extentsToLoad.length; i < ii; ++i) { - var extentToLoad = extentsToLoad[i]; - var alreadyLoaded = loadedExtentsRtree.forEachInExtent(extentToLoad, - /** - * @param {{extent: ol.Extent}} object Object. - * @return {boolean} Contains. - */ - function(object) { - return ol.extent.containsExtent(object.extent, extentToLoad); - }); - if (!alreadyLoaded) { - this.loader_.call(this, extentToLoad, resolution, projection); - loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()}); - } - } -}; - - -/** - * Remove a single feature from the source. If you want to remove all features - * at once, use the {@link ol.source.Vector#clear source.clear()} method - * instead. - * @param {ol.Feature} feature Feature to remove. - * @api stable - */ -ol.source.Vector.prototype.removeFeature = function(feature) { - var featureKey = goog.getUid(feature).toString(); - if (featureKey in this.nullGeometryFeatures_) { - delete this.nullGeometryFeatures_[featureKey]; - } else { - if (this.featuresRtree_) { - this.featuresRtree_.remove(feature); - } - } - this.removeFeatureInternal(feature); - this.changed(); -}; - - -/** - * Remove feature without firing a `change` event. - * @param {ol.Feature} feature Feature. - * @protected - */ -ol.source.Vector.prototype.removeFeatureInternal = function(feature) { - var featureKey = goog.getUid(feature).toString(); - goog.asserts.assert(featureKey in this.featureChangeKeys_, - 'featureKey exists in featureChangeKeys'); - this.featureChangeKeys_[featureKey].forEach(goog.events.unlistenByKey); - delete this.featureChangeKeys_[featureKey]; - var id = feature.getId(); - if (id !== undefined) { - delete this.idIndex_[id.toString()]; - } else { - delete this.undefIdIndex_[featureKey]; - } - this.dispatchEvent(new ol.source.VectorEvent( - ol.source.VectorEventType.REMOVEFEATURE, feature)); -}; - - -/** - * Remove a feature from the id index. Called internally when the feature id - * may have changed. - * @param {ol.Feature} feature The feature. - * @return {boolean} Removed the feature from the index. - * @private - */ -ol.source.Vector.prototype.removeFromIdIndex_ = function(feature) { - var removed = false; - for (var id in this.idIndex_) { - if (this.idIndex_[id] === feature) { - delete this.idIndex_[id]; - removed = true; - break; - } - } - return removed; -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.source.Vector} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.VectorEvent} - * @param {string} type Type. - * @param {ol.Feature=} opt_feature Feature. - */ -ol.source.VectorEvent = function(type, opt_feature) { - - goog.base(this, type); - - /** - * The feature being added or removed. - * @type {ol.Feature|undefined} - * @api stable - */ - this.feature = opt_feature; - -}; -goog.inherits(ol.source.VectorEvent, goog.events.Event); - -goog.provide('ol.source.ImageVector'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.vec.Mat4'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.vector'); -goog.require('ol.source.ImageCanvas'); -goog.require('ol.source.Vector'); -goog.require('ol.style.Style'); -goog.require('ol.vec.Mat4'); - - - -/** - * @classdesc - * An image source whose images are canvas elements into which vector features - * read from a vector source (`ol.source.Vector`) are drawn. An - * `ol.source.ImageVector` object is to be used as the `source` of an image - * layer (`ol.layer.Image`). Image layers are rotated, scaled, and translated, - * as opposed to being re-rendered, during animations and interactions. So, like - * any other image layer, an image layer configured with an - * `ol.source.ImageVector` will exhibit this behaviour. This is in contrast to a - * vector layer, where vector features are re-drawn during animations and - * interactions. - * - * @constructor - * @extends {ol.source.ImageCanvas} - * @param {olx.source.ImageVectorOptions} options Options. - * @api - */ -ol.source.ImageVector = function(options) { - - /** - * @private - * @type {ol.source.Vector} - */ - this.source_ = options.source; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.canvasContext_ = ol.dom.createCanvasContext2D(); - - /** - * @private - * @type {ol.Size} - */ - this.canvasSize_ = [0, 0]; - - /** - * @private - * @type {ol.render.canvas.ReplayGroup} - */ - this.replayGroup_ = null; - - goog.base(this, { - attributions: options.attributions, - canvasFunction: goog.bind(this.canvasFunctionInternal_, this), - logo: options.logo, - projection: options.projection, - ratio: options.ratio, - resolutions: options.resolutions, - state: this.source_.getState() - }); - - /** - * User provided style. - * @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * @private - */ - this.style_ = null; - - /** - * Style function for use within the library. - * @type {ol.style.StyleFunction|undefined} - * @private - */ - this.styleFunction_ = undefined; - - this.setStyle(options.style); - - goog.events.listen(this.source_, goog.events.EventType.CHANGE, - this.handleSourceChange_, undefined, this); - -}; -goog.inherits(ol.source.ImageVector, ol.source.ImageCanvas); - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Size} size Size. - * @param {ol.proj.Projection} projection Projection; - * @return {HTMLCanvasElement} Canvas element. - * @private - */ -ol.source.ImageVector.prototype.canvasFunctionInternal_ = - function(extent, resolution, pixelRatio, size, projection) { - - var replayGroup = new ol.render.canvas.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, - resolution); - - this.source_.loadFeatures(extent, resolution, projection); - - var loading = false; - this.source_.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - loading = loading || - this.renderFeature_(feature, resolution, pixelRatio, replayGroup); - }, this); - replayGroup.finish(); - - if (loading) { - return null; - } - - if (this.canvasSize_[0] != size[0] || this.canvasSize_[1] != size[1]) { - this.canvasContext_.canvas.width = size[0]; - this.canvasContext_.canvas.height = size[1]; - this.canvasSize_[0] = size[0]; - this.canvasSize_[1] = size[1]; - } else { - this.canvasContext_.clearRect(0, 0, size[0], size[1]); - } - - var transform = this.getTransform_(ol.extent.getCenter(extent), - resolution, pixelRatio, size); - replayGroup.replay(this.canvasContext_, pixelRatio, transform, 0, {}); - - this.replayGroup_ = replayGroup; - - return this.canvasContext_.canvas; -}; - - -/** - * @inheritDoc - */ -ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function( - coordinate, resolution, rotation, skippedFeatureUids, callback) { - if (!this.replayGroup_) { - return undefined; - } else { - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate( - coordinate, resolution, 0, skippedFeatureUids, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'passed a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback(feature); - } - }); - } -}; - - -/** - * Get a reference to the wrapped source. - * @return {ol.source.Vector} Source. - * @api - */ -ol.source.ImageVector.prototype.getSource = function() { - return this.source_; -}; - - -/** - * Get the style for features. This returns whatever was passed to the `style` - * option at construction or to the `setStyle` method. - * @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * Layer style. - * @api stable - */ -ol.source.ImageVector.prototype.getStyle = function() { - return this.style_; -}; - - -/** - * Get the style function. - * @return {ol.style.StyleFunction|undefined} Layer style function. - * @api stable - */ -ol.source.ImageVector.prototype.getStyleFunction = function() { - return this.styleFunction_; -}; - - -/** - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Size} size Size. - * @return {!goog.vec.Mat4.Number} Transform. - * @private - */ -ol.source.ImageVector.prototype.getTransform_ = - function(center, resolution, pixelRatio, size) { - return ol.vec.Mat4.makeTransform2D(this.transform_, - size[0] / 2, size[1] / 2, - pixelRatio / resolution, -pixelRatio / resolution, - 0, - -center[0], -center[1]); -}; - - -/** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. - * @private - */ -ol.source.ImageVector.prototype.handleImageChange_ = - function(event) { - this.changed(); -}; - - -/** - * @private - */ -ol.source.ImageVector.prototype.handleSourceChange_ = function() { - // setState will trigger a CHANGE event, so we always rely - // change events by calling setState. - this.setState(this.source_.getState()); -}; - - -/** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - * @private - */ -ol.source.ImageVector.prototype.renderFeature_ = - function(feature, resolution, pixelRatio, replayGroup) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else if (this.styleFunction_) { - styles = this.styleFunction_(feature, resolution); - } - if (!styles) { - return false; - } - var i, ii, loading = false; - for (i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleImageChange_, this) || loading; - } - return loading; -}; - - -/** - * Set the style for features. This can be a single style object, an array - * of styles, or a function that takes a feature and resolution and returns - * an array of styles. If it is `undefined` the default style is used. If - * it is `null` the layer has no style (a `null` style), so only features - * that have their own styles will be rendered in the layer. See - * {@link ol.style} for information on the default style. - * @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined} - * style Layer style. - * @api stable - */ -ol.source.ImageVector.prototype.setStyle = function(style) { - this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction; - this.styleFunction_ = !style ? - undefined : ol.style.createStyleFunction(this.style_); - this.changed(); -}; - -goog.provide('ol.renderer.canvas.ImageLayer'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ImageBase'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.proj'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.source.ImageVector'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.Image} imageLayer Single image layer. - */ -ol.renderer.canvas.ImageLayer = function(imageLayer) { - - goog.base(this, imageLayer); - - /** - * @private - * @type {?ol.ImageBase} - */ - this.image_ = null; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.imageTransform_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {?goog.vec.Mat4.Number} - */ - this.imageTransformInv_ = null; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.hitCanvasContext_ = null; - -}; -goog.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var layer = this.getLayer(); - var source = layer.getSource(); - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var skippedFeatureUids = frameState.skippedFeatureUids; - return source.forEachFeatureAtCoordinate( - coordinate, resolution, rotation, skippedFeatureUids, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - return callback.call(thisArg, feature, layer); - }); -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.getImage()) { - return undefined; - } - - if (this.getLayer().getSource() instanceof ol.source.ImageVector) { - // for ImageVector sources use the original hit-detection logic, - // so that for example also transparent polygons are detected - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); - - if (hasFeature) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } else { - // for all other image sources directly check the image - if (!this.imageTransformInv_) { - this.imageTransformInv_ = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); - } - - var pixelOnCanvas = - this.getPixelOnCanvas(pixel, this.imageTransformInv_); - - if (!this.hitCanvasContext_) { - this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); - } - - this.hitCanvasContext_.clearRect(0, 0, 1, 1); - this.hitCanvasContext_.drawImage( - this.getImage(), pixelOnCanvas[0], pixelOnCanvas[1], 1, 1, 0, 0, 1, 1); - - var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.ImageLayer.prototype.getImage = function() { - return !this.image_ ? null : this.image_.getImage(); -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() { - return this.imageTransform_; -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.ImageLayer.prototype.prepareFrame = - function(frameState, layerState) { - - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewResolution = viewState.resolution; - var viewRotation = viewState.rotation; - - var image; - var imageLayer = this.getLayer(); - goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, - 'layer is an instance of ol.layer.Image'); - var imageSource = imageLayer.getSource(); - - var hints = frameState.viewHints; - - var renderedExtent = frameState.extent; - if (layerState.extent !== undefined) { - renderedExtent = ol.extent.getIntersection( - renderedExtent, layerState.extent); - } - - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && - !ol.extent.isEmpty(renderedExtent)) { - var projection = viewState.projection; - if (!ol.ENABLE_RASTER_REPROJECTION) { - var sourceProjection = imageSource.getProjection(); - if (sourceProjection) { - goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), - 'projection and sourceProjection are equivalent'); - projection = sourceProjection; - } - } - image = imageSource.getImage( - renderedExtent, viewResolution, pixelRatio, projection); - if (image) { - var loaded = this.loadImage(image); - if (loaded) { - this.image_ = image; - } - } - } - - if (this.image_) { - image = this.image_; - var imageExtent = image.getExtent(); - var imageResolution = image.getResolution(); - var imagePixelRatio = image.getPixelRatio(); - var scale = pixelRatio * imageResolution / - (viewResolution * imagePixelRatio); - ol.vec.Mat4.makeTransform2D(this.imageTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - scale, scale, - viewRotation, - imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution, - imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution); - this.imageTransformInv_ = null; - this.updateAttributions(frameState.attributions, image.getAttributions()); - this.updateLogos(frameState, imageSource); - } - - return true; -}; - -// FIXME find correct globalCompositeOperation -// FIXME optimize :-) - -goog.provide('ol.renderer.canvas.TileLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Size'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Tile'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.Tile} tileLayer Tile layer. - */ -ol.renderer.canvas.TileLayer = function(tileLayer) { - - goog.base(this, tileLayer); - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.canvasSize_ = null; - - /** - * @private - * @type {boolean} - */ - this.canvasTooBig_ = false; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = null; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.imageTransform_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {?goog.vec.Mat4.Number} - */ - this.imageTransformInv_ = null; - - /** - * @private - * @type {number} - */ - this.renderedCanvasZ_ = NaN; - - /** - * @private - * @type {number} - */ - this.renderedTileWidth_ = NaN; - - /** - * @private - * @type {number} - */ - this.renderedTileHeight_ = NaN; - - /** - * @private - * @type {ol.TileRange} - */ - this.renderedCanvasTileRange_ = null; - - /** - * @private - * @type {Array.<ol.Tile|undefined>} - */ - this.renderedTiles_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; - -}; -goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.canvas.TileLayer.prototype.getImage = function() { - return this.canvas_; -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.TileLayer.prototype.getImageTransform = function() { - return this.imageTransform_; -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.TileLayer.prototype.prepareFrame = - function(frameState, layerState) { - - // - // Warning! You're entering a dangerous zone! - // - // The canvas tile layer renderering is highly optimized, hence - // the complexity of this function. For best performance we try - // to minimize the number of pixels to update on the canvas. This - // includes: - // - // - Only drawing pixels that will be visible. - // - Not re-drawing pixels/tiles that are already correct. - // - Minimizing calls to clearRect. - // - Never shrink the canvas. Just make it bigger when necessary. - // Re-sizing the canvas also clears it, which further means - // re-creating it (expensive). - // - // The various steps performed by this functions: - // - // - Create a canvas element if none has been created yet. - // - // - Make the canvas bigger if it's too small. Note that we never shrink - // the canvas, we just make it bigger when necessary, when rotating for - // example. Note also that the canvas always contains a whole number - // of tiles. - // - // - Invalidate the canvas tile range (renderedCanvasTileRange_ = null) - // if (1) the canvas has been enlarged, or (2) the zoom level changes, - // or (3) the canvas tile range doesn't contain the required tile - // range. This canvas tile range invalidation thing is related to - // an optimization where we attempt to redraw as few pixels as - // possible on each prepareFrame call. - // - // - If the canvas tile range has been invalidated we reset - // renderedCanvasTileRange_ and reset the renderedTiles_ array. - // The renderedTiles_ array is the structure used to determine - // the canvas pixels that need not be redrawn from one prepareFrame - // call to another. It records while tile has been rendered at - // which position in the canvas. - // - // - We then determine the tiles to draw on the canvas. Tiles for - // the target resolution may not be loaded yet. In that case we - // use low-resolution/interim tiles if loaded already. And, if - // for a non-yet-loaded tile we haven't found a corresponding - // low-resolution tile we indicate that the pixels for that - // tile must be cleared on the canvas. Note: determining the - // interim tiles is based on tile extents instead of tile - // coords, this is to be able to handler irregular tile grids. - // - // - We're now ready to render. We start by calling clearRect - // for the tiles that aren't loaded yet and are not fully covered - // by a low-resolution tile (if they're loaded, we'll draw them; - // if they're fully covered by a low-resolution tile then there's - // no need to clear). We then render the tiles "back to front", - // i.e. starting with the low-resolution tiles. - // - // - After rendering some bookkeeping is performed (updateUsedTiles, - // etc.). manageTilePyramid is what enqueue tiles in the tile - // queue for loading. - // - // - The last step involves updating the image transform matrix, - // which will be used by the map renderer for the final - // composition and positioning. - // - - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var projection = viewState.projection; - - var tileLayer = this.getLayer(); - goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, - 'layer is an instance of ol.layer.Tile'); - var tileSource = tileLayer.getSource(); - var tileGrid = tileSource.getTileGridForProjection(projection); - var tileGutter = tileSource.getGutter(); - var z = tileGrid.getZForResolution(viewState.resolution); - var tilePixelSize = - tileSource.getTilePixelSize(z, frameState.pixelRatio, projection); - var tilePixelRatio = tilePixelSize[0] / - ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; - var tileResolution = tileGrid.getResolution(z); - var tilePixelResolution = tileResolution / tilePixelRatio; - var center = viewState.center; - var extent; - if (tileResolution == viewState.resolution) { - center = this.snapCenterToPixel(center, tileResolution, frameState.size); - extent = ol.extent.getForViewAndSize( - center, tileResolution, viewState.rotation, frameState.size); - } else { - extent = frameState.extent; - } - - if (layerState.extent !== undefined) { - extent = ol.extent.getIntersection(extent, layerState.extent); - } - if (ol.extent.isEmpty(extent)) { - // Return false to prevent the rendering of the layer. - return false; - } - - var tileRange = tileGrid.getTileRangeForExtentAndResolution( - extent, tileResolution); - - var canvasWidth = tilePixelSize[0] * tileRange.getWidth(); - var canvasHeight = tilePixelSize[1] * tileRange.getHeight(); - - var canvas, context; - if (!this.canvas_) { - goog.asserts.assert(!this.canvasSize_, - 'canvasSize is null (because canvas is null)'); - goog.asserts.assert(!this.context_, - 'context is null (because canvas is null)'); - goog.asserts.assert(!this.renderedCanvasTileRange_, - 'renderedCanvasTileRange is null (because canvas is null)'); - context = ol.dom.createCanvasContext2D(canvasWidth, canvasHeight); - this.canvas_ = context.canvas; - this.canvasSize_ = [canvasWidth, canvasHeight]; - this.context_ = context; - this.canvasTooBig_ = - !ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_); - } else { - goog.asserts.assert(this.canvasSize_, - 'non-null canvasSize (because canvas is not null)'); - goog.asserts.assert(this.context_, - 'non-null context (because canvas is not null)'); - canvas = this.canvas_; - context = this.context_; - if (this.canvasSize_[0] < canvasWidth || - this.canvasSize_[1] < canvasHeight || - this.renderedTileWidth_ !== tilePixelSize[0] || - this.renderedTileHeight_ !== tilePixelSize[1] || - (this.canvasTooBig_ && (this.canvasSize_[0] > canvasWidth || - this.canvasSize_[1] > canvasHeight))) { - // Canvas is too small or tileSize has changed, resize it. - // We never shrink the canvas, unless - // we know that the current canvas size exceeds the maximum size - canvas.width = canvasWidth; - canvas.height = canvasHeight; - this.canvasSize_ = [canvasWidth, canvasHeight]; - this.canvasTooBig_ = - !ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_); - this.renderedCanvasTileRange_ = null; - } else { - canvasWidth = this.canvasSize_[0]; - canvasHeight = this.canvasSize_[1]; - if (z != this.renderedCanvasZ_ || - !this.renderedCanvasTileRange_.containsTileRange(tileRange)) { - this.renderedCanvasTileRange_ = null; - } - } - } - - var canvasTileRange, canvasTileRangeWidth, minX, minY; - if (!this.renderedCanvasTileRange_) { - canvasTileRangeWidth = canvasWidth / tilePixelSize[0]; - var canvasTileRangeHeight = canvasHeight / tilePixelSize[1]; - minX = tileRange.minX - - Math.floor((canvasTileRangeWidth - tileRange.getWidth()) / 2); - minY = tileRange.minY - - Math.floor((canvasTileRangeHeight - tileRange.getHeight()) / 2); - this.renderedCanvasZ_ = z; - this.renderedTileWidth_ = tilePixelSize[0]; - this.renderedTileHeight_ = tilePixelSize[1]; - this.renderedCanvasTileRange_ = new ol.TileRange( - minX, minX + canvasTileRangeWidth - 1, - minY, minY + canvasTileRangeHeight - 1); - this.renderedTiles_ = - new Array(canvasTileRangeWidth * canvasTileRangeHeight); - canvasTileRange = this.renderedCanvasTileRange_; - } else { - canvasTileRange = this.renderedCanvasTileRange_; - canvasTileRangeWidth = canvasTileRange.getWidth(); - } - - goog.asserts.assert(canvasTileRange.containsTileRange(tileRange), - 'tileRange is contained in canvasTileRange'); - - /** - * @type {Object.<number, Object.<string, ol.Tile>>} - */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - /** @type {Array.<ol.Tile>} */ - var tilesToClear = []; - - var findLoadedTiles = this.createLoadedTileFinder( - tileSource, projection, tilesToDrawByZ); - - var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); - - var tmpExtent = ol.extent.createEmpty(); - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, fullyLoaded, tile, x, y; - var drawableTile = ( - /** - * @param {!ol.Tile} tile Tile. - * @return {boolean} Tile is selected. - */ - function(tile) { - var tileState = tile.getState(); - return tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - tileState == ol.TileState.ERROR && !useInterimTilesOnError; - }); - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - if (!drawableTile(tile) && tile.interimTile) { - tile = tile.interimTile; - } - goog.asserts.assert(tile); - if (drawableTile(tile)) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - // FIXME we do not need to clear the tile if it is fully covered by its - // children - tilesToClear.push(tile); - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } - - } - } - - var i, ii; - for (i = 0, ii = tilesToClear.length; i < ii; ++i) { - tile = tilesToClear[i]; - x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX); - y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]); - context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]); - } - - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - goog.array.sort(zs); - var opaque = tileSource.getOpaque(); - var origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( - [z, canvasTileRange.minX, canvasTileRange.maxY], - tmpExtent)); - var currentZ, index, scale, tileCoordKey, tileExtent, tileState, tilesToDraw; - var ix, iy, interimTileRange, maxX, maxY; - var height, width; - for (i = 0, ii = zs.length; i < ii; ++i) { - currentZ = zs[i]; - tilePixelSize = - tileSource.getTilePixelSize(currentZ, pixelRatio, projection); - tilesToDraw = tilesToDrawByZ[currentZ]; - if (currentZ == z) { - for (tileCoordKey in tilesToDraw) { - tile = tilesToDraw[tileCoordKey]; - index = - (tile.tileCoord[2] - canvasTileRange.minY) * canvasTileRangeWidth + - (tile.tileCoord[1] - canvasTileRange.minX); - if (this.renderedTiles_[index] != tile) { - x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX); - y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]); - tileState = tile.getState(); - if (tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && !useInterimTilesOnError) || - !opaque) { - context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]); - } - if (tileState == ol.TileState.LOADED) { - context.drawImage(tile.getImage(), - tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1], - x, y, tilePixelSize[0], tilePixelSize[1]); - } - this.renderedTiles_[index] = tile; - } - } - } else { - scale = tileGrid.getResolution(currentZ) / tileResolution; - for (tileCoordKey in tilesToDraw) { - tile = tilesToDraw[tileCoordKey]; - tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); - x = (tileExtent[0] - origin[0]) / tilePixelResolution; - y = (origin[1] - tileExtent[3]) / tilePixelResolution; - width = scale * tilePixelSize[0]; - height = scale * tilePixelSize[1]; - tileState = tile.getState(); - if (tileState == ol.TileState.EMPTY || !opaque) { - context.clearRect(x, y, width, height); - } - if (tileState == ol.TileState.LOADED) { - context.drawImage(tile.getImage(), - tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1], - x, y, width, height); - } - interimTileRange = - tileGrid.getTileRangeForExtentAndZ(tileExtent, z, tmpTileRange); - minX = Math.max(interimTileRange.minX, canvasTileRange.minX); - maxX = Math.min(interimTileRange.maxX, canvasTileRange.maxX); - minY = Math.max(interimTileRange.minY, canvasTileRange.minY); - maxY = Math.min(interimTileRange.maxY, canvasTileRange.maxY); - for (ix = minX; ix <= maxX; ++ix) { - for (iy = minY; iy <= maxY; ++iy) { - index = (iy - canvasTileRange.minY) * canvasTileRangeWidth + - (ix - canvasTileRange.minX); - this.renderedTiles_[index] = undefined; - } - } - } - } - } - - this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); - this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, - projection, extent, z, tileLayer.getPreload()); - this.scheduleExpireCache(frameState, tileSource); - this.updateLogos(frameState, tileSource); - - ol.vec.Mat4.makeTransform2D(this.imageTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio * tilePixelResolution / viewState.resolution, - pixelRatio * tilePixelResolution / viewState.resolution, - viewState.rotation, - (origin[0] - center[0]) / tilePixelResolution, - (center[1] - origin[1]) / tilePixelResolution); - this.imageTransformInv_ = null; - - return true; -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.context_) { - return undefined; - } - - if (!this.imageTransformInv_) { - this.imageTransformInv_ = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); - } - - var pixelOnCanvas = - this.getPixelOnCanvas(pixel, this.imageTransformInv_); - - var imageData = this.context_.getImageData( - pixelOnCanvas[0], pixelOnCanvas[1], 1, 1).data; - - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } -}; - -goog.provide('ol.renderer.canvas.VectorLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.renderer.vector'); -goog.require('ol.source.Vector'); - - - -/** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.Vector} vectorLayer Vector layer. - */ -ol.renderer.canvas.VectorLayer = function(vectorLayer) { - - goog.base(this, vectorLayer); - - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.renderedResolution_ = NaN; - - /** - * @private - * @type {ol.Extent} - */ - this.renderedExtent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {function(ol.Feature, ol.Feature): number|null} - */ - this.renderedRenderOrder_ = null; - - /** - * @private - * @type {ol.render.canvas.ReplayGroup} - */ - this.replayGroup_ = null; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - -}; -goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorLayer.prototype.composeFrame = - function(frameState, layerState, context) { - - var extent = frameState.extent; - var pixelRatio = frameState.pixelRatio; - var skippedFeatureUids = layerState.managed ? - frameState.skippedFeatureUids : {}; - var viewState = frameState.viewState; - var projection = viewState.projection; - var rotation = viewState.rotation; - var projectionExtent = projection.getExtent(); - var vectorSource = this.getLayer().getSource(); - goog.asserts.assertInstanceof(vectorSource, ol.source.Vector); - - var transform = this.getTransform(frameState, 0); - - this.dispatchPreComposeEvent(context, frameState, transform); - - var replayGroup = this.replayGroup_; - if (replayGroup && !replayGroup.isEmpty()) { - var layer = this.getLayer(); - var replayContext; - if (layer.hasListener(ol.render.EventType.RENDER)) { - // resize and clear - this.context_.canvas.width = context.canvas.width; - this.context_.canvas.height = context.canvas.height; - replayContext = this.context_; - } else { - replayContext = context; - } - // for performance reasons, context.save / context.restore is not used - // to save and restore the transformation matrix and the opacity. - // see http://jsperf.com/context-save-restore-versus-variable - var alpha = replayContext.globalAlpha; - replayContext.globalAlpha = layerState.opacity; - - replayGroup.replay(replayContext, pixelRatio, transform, rotation, - skippedFeatureUids); - if (vectorSource.getWrapX() && projection.canWrapX() && - !ol.extent.containsExtent(projectionExtent, extent)) { - var startX = extent[0]; - var worldWidth = ol.extent.getWidth(projectionExtent); - var world = 0; - var offsetX; - while (startX < projectionExtent[0]) { - --world; - offsetX = worldWidth * world; - transform = this.getTransform(frameState, offsetX); - replayGroup.replay(replayContext, pixelRatio, transform, rotation, - skippedFeatureUids); - startX += worldWidth; - } - world = 0; - startX = extent[2]; - while (startX > projectionExtent[2]) { - ++world; - offsetX = worldWidth * world; - transform = this.getTransform(frameState, offsetX); - replayGroup.replay(replayContext, pixelRatio, transform, rotation, - skippedFeatureUids); - startX -= worldWidth; - } - // restore original transform for render and compose events - transform = this.getTransform(frameState, 0); - } - - if (replayContext != context) { - this.dispatchRenderEvent(replayContext, frameState, transform); - context.drawImage(replayContext.canvas, 0, 0); - } - replayContext.globalAlpha = alpha; - } - - this.dispatchPostComposeEvent(context, frameState, transform); - -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - if (!this.replayGroup_) { - return undefined; - } else { - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var layer = this.getLayer(); - var layerState = frameState.layerStates[goog.getUid(layer)]; - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, - rotation, layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); - } -}; - - -/** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. - * @private - */ -ol.renderer.canvas.VectorLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorLayer.prototype.prepareFrame = - function(frameState, layerState) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - var vectorSource = vectorLayer.getSource(); - - this.updateAttributions( - frameState.attributions, vectorSource.getAttributions()); - this.updateLogos(frameState, vectorSource); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); - var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - - var frameStateExtent = frameState.extent; - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var vectorLayerRevision = vectorLayer.getRevision(); - var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); - var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); - - if (vectorLayerRenderOrder === undefined) { - vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; - } - - var extent = ol.extent.buffer(frameStateExtent, - vectorLayerRenderBuffer * resolution); - var projectionExtent = viewState.projection.getExtent(); - - if (vectorSource.getWrapX() && viewState.projection.canWrapX() && - !ol.extent.containsExtent(projectionExtent, frameState.extent)) { - // For the replay group, we need an extent that intersects the real world - // (-180° to +180°). To support geometries in a coordinate range from -540° - // to +540°, we add at least 1 world width on each side of the projection - // extent. If the viewport is wider than the world, we need to add half of - // the viewport width to make sure we cover the whole viewport. - var worldWidth = ol.extent.getWidth(projectionExtent); - var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth); - extent[0] = projectionExtent[0] - buffer; - extent[2] = projectionExtent[2] + buffer; - } - - if (!this.dirty_ && - this.renderedResolution_ == resolution && - this.renderedRevision_ == vectorLayerRevision && - this.renderedRenderOrder_ == vectorLayerRenderOrder && - ol.extent.containsExtent(this.renderedExtent_, extent)) { - return true; - } - - // FIXME dispose of old replayGroup in post render - goog.dispose(this.replayGroup_); - this.replayGroup_ = null; - - this.dirty_ = false; - - var replayGroup = - new ol.render.canvas.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, - resolution, vectorLayer.getRenderBuffer()); - vectorSource.loadFeatures(extent, resolution, projection); - var renderFeature = - /** - * @param {ol.Feature} feature Feature. - * @this {ol.renderer.canvas.VectorLayer} - */ - function(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = vectorLayer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - var dirty = this.renderFeature( - feature, resolution, pixelRatio, styles, replayGroup); - this.dirty_ = this.dirty_ || dirty; - } - }; - if (vectorLayerRenderOrder) { - /** @type {Array.<ol.Feature>} */ - var features = []; - vectorSource.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - features.push(feature); - }, this); - goog.array.sort(features, vectorLayerRenderOrder); - features.forEach(renderFeature, this); - } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); - } - replayGroup.finish(); - - this.renderedResolution_ = resolution; - this.renderedRevision_ = vectorLayerRevision; - this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; - this.replayGroup_ = replayGroup; - - return true; -}; - - -/** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - */ -ol.renderer.canvas.VectorLayer.prototype.renderFeature = - function(feature, resolution, pixelRatio, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - return loading; -}; - -goog.provide('ol.TileLoadFunctionType'); -goog.provide('ol.TileVectorLoadFunctionType'); - - -/** - * A function that takes an {@link ol.Tile} for the tile and a - * `{string}` for the url as arguments. - * - * @typedef {function(ol.Tile, string)} - * @api - */ -ol.TileLoadFunctionType; - - -/** - * A function that is called with a tile url for the features to load and - * a callback that takes the loaded features as argument. - * - * @typedef {function(string, function(Array.<ol.Feature>))} - * @api - */ -ol.TileVectorLoadFunctionType; - -goog.provide('ol.VectorTile'); - -goog.require('ol.Tile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileLoadFunctionType'); -goog.require('ol.TileState'); - - -/** - * @typedef {{ - * dirty: boolean, - * renderedRenderOrder: (null|function(ol.Feature, ol.Feature):number), - * renderedRevision: number, - * replayGroup: ol.render.IReplayGroup}} - */ -ol.TileReplayState; - - - -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Data source url. - * @param {ol.format.Feature} format Feature format. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - */ -ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) { - - goog.base(this, tileCoord, state); - - /** - * @private - * @type {ol.format.Feature} - */ - this.format_ = format; - - /** - * @private - * @type {Array.<ol.Feature>} - */ - this.features_ = null; - - /** - * @private - * @type {ol.FeatureLoader} - */ - this.loader_; - - /** - * @private - * @type {ol.proj.Projection} - */ - this.projection_ = null; - - /** - * @private - * @type {ol.TileReplayState} - */ - this.replayState_ = { - dirty: false, - renderedRenderOrder: null, - renderedRevision: -1, - replayGroup: null - }; - - /** - * @private - * @type {ol.TileLoadFunctionType} - */ - this.tileLoadFunction_ = tileLoadFunction; - - /** - * @private - * @type {string} - */ - this.url_ = src; - -}; -goog.inherits(ol.VectorTile, ol.Tile); - - -/** - * @inheritDoc - */ -ol.VectorTile.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); -}; - - -/** - * Get the feature format assigned for reading this tile's features. - * @return {ol.format.Feature} Feature format. - * @api - */ -ol.VectorTile.prototype.getFormat = function() { - return this.format_; -}; - - -/** - * @return {Array.<ol.Feature>} Features. - */ -ol.VectorTile.prototype.getFeatures = function() { - return this.features_; -}; - - -/** - * @return {ol.TileReplayState} - */ -ol.VectorTile.prototype.getReplayState = function() { - return this.replayState_; -}; - - -/** - * @inheritDoc - */ -ol.VectorTile.prototype.getKey = function() { - return this.url_; -}; - - -/** - * @return {ol.proj.Projection} Projection. - */ -ol.VectorTile.prototype.getProjection = function() { - return this.projection_; -}; - - -/** - * Load the tile. - */ -ol.VectorTile.prototype.load = function() { - if (this.state == ol.TileState.IDLE) { - this.setState(ol.TileState.LOADING); - this.tileLoadFunction_(this, this.url_); - this.loader_(null, NaN, null); - } -}; - - -/** - * @param {Array.<ol.Feature>} features Features. - */ -ol.VectorTile.prototype.setFeatures = function(features) { - this.features_ = features; - this.setState(ol.TileState.LOADED); -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - */ -ol.VectorTile.prototype.setProjection = function(projection) { - this.projection_ = projection; -}; - - -/** - * @param {ol.TileState} tileState Tile state. - */ -ol.VectorTile.prototype.setState = function(tileState) { - this.state = tileState; - this.changed(); -}; - - -/** - * Set the feature loader for reading this tile's features. - * @param {ol.FeatureLoader} loader Feature loader. - * @api - */ -ol.VectorTile.prototype.setLoader = function(loader) { - this.loader_ = loader; -}; - -goog.provide('ol.TileUrlFunction'); -goog.provide('ol.TileUrlFunctionType'); - -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol.TileCoord'); -goog.require('ol.tilecoord'); - - -/** - * {@link ol.source.Tile} sources use a function of this type to get the url - * that provides a tile for a given tile coordinate. - * - * This function takes an {@link ol.TileCoord} for the tile coordinate, a - * `{number}` representing the pixel ratio and an {@link ol.proj.Projection} for - * the projection as arguments and returns a `{string}` representing the tile - * URL, or undefined if no tile should be requested for the passed tile - * coordinate. - * - * @typedef {function(ol.TileCoord, number, - * ol.proj.Projection): (string|undefined)} - * @api - */ -ol.TileUrlFunctionType; - - -/** - * @typedef {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=): - * ol.TileCoord} - */ -ol.TileCoordTransformType; - - -/** - * @param {string} template Template. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {ol.TileUrlFunctionType} Tile URL function. - */ -ol.TileUrlFunction.createFromTemplate = function(template, tileGrid) { - var zRegEx = /\{z\}/g; - var xRegEx = /\{x\}/g; - var yRegEx = /\{y\}/g; - var dashYRegEx = /\{-y\}/g; - return ( - /** - * @param {ol.TileCoord} tileCoord Tile Coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - return template.replace(zRegEx, tileCoord[0].toString()) - .replace(xRegEx, tileCoord[1].toString()) - .replace(yRegEx, function() { - var y = -tileCoord[2] - 1; - return y.toString(); - }) - .replace(dashYRegEx, function() { - var z = tileCoord[0]; - var range = tileGrid.getFullTileRange(z); - goog.asserts.assert(range, - 'The {-y} template requires a tile grid with extent'); - var y = range.getHeight() + tileCoord[2]; - return y.toString(); - }); - } - }); -}; - - -/** - * @param {Array.<string>} templates Templates. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {ol.TileUrlFunctionType} Tile URL function. - */ -ol.TileUrlFunction.createFromTemplates = function(templates, tileGrid) { - var len = templates.length; - var tileUrlFunctions = new Array(len); - for (var i = 0; i < len; ++i) { - tileUrlFunctions[i] = ol.TileUrlFunction.createFromTemplate( - templates[i], tileGrid); - } - return ol.TileUrlFunction.createFromTileUrlFunctions(tileUrlFunctions); -}; - - -/** - * @param {Array.<ol.TileUrlFunctionType>} tileUrlFunctions Tile URL Functions. - * @return {ol.TileUrlFunctionType} Tile URL function. - */ -ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) { - goog.asserts.assert(tileUrlFunctions.length > 0, - 'Length of tile url functions should be greater than 0'); - if (tileUrlFunctions.length === 1) { - return tileUrlFunctions[0]; - } - return ( - /** - * @param {ol.TileCoord} tileCoord Tile Coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - var h = ol.tilecoord.hash(tileCoord); - var index = goog.math.modulo(h, tileUrlFunctions.length); - return tileUrlFunctions[index](tileCoord, pixelRatio, projection); - } - }); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ -ol.TileUrlFunction.nullTileUrlFunction = - function(tileCoord, pixelRatio, projection) { - return undefined; -}; - - -/** - * @param {string} url URL. - * @return {Array.<string>} Array of urls. - */ -ol.TileUrlFunction.expandUrl = function(url) { - var urls = []; - var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url); - if (match) { - var startCharCode = match[1].charCodeAt(0); - var stopCharCode = match[2].charCodeAt(0); - var charCode; - for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) { - urls.push(url.replace(match[0], String.fromCharCode(charCode))); - } - } else { - urls.push(url); - } - return urls; -}; - -goog.provide('ol.source.UrlTile'); - -goog.require('goog.events'); -goog.require('ol.TileLoadFunctionType'); -goog.require('ol.TileState'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.TileUrlFunctionType'); -goog.require('ol.proj'); -goog.require('ol.source.Tile'); -goog.require('ol.source.TileEvent'); - - -/** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * extent: (ol.Extent|undefined), - * logo: (string|olx.LogoOptions|undefined), - * opaque: (boolean|undefined), - * projection: ol.proj.ProjectionLike, - * state: (ol.source.State|string|undefined), - * tileGrid: (ol.tilegrid.TileGrid|undefined), - * tileLoadFunction: ol.TileLoadFunctionType, - * tilePixelRatio: (number|undefined), - * tileUrlFunction: (ol.TileUrlFunctionType|undefined), - * url: (string|undefined), - * urls: (Array.<string>|undefined), - * wrapX: (boolean|undefined)}} - */ -ol.source.UrlTileOptions; - - - -/** - * @classdesc - * Base class for sources providing tiles divided into a tile grid over http. - * - * @constructor - * @fires ol.source.TileEvent - * @extends {ol.source.Tile} - * @param {ol.source.UrlTileOptions} options Image tile options. - */ -ol.source.UrlTile = function(options) { - - goog.base(this, { - attributions: options.attributions, - cacheSize: options.cacheSize, - extent: options.extent, - logo: options.logo, - opaque: options.opaque, - projection: options.projection, - state: options.state ? - /** @type {ol.source.State} */ (options.state) : undefined, - tileGrid: options.tileGrid, - tilePixelRatio: options.tilePixelRatio, - wrapX: options.wrapX - }); - - /** - * @protected - * @type {ol.TileLoadFunctionType} - */ - this.tileLoadFunction = options.tileLoadFunction; - - /** - * @protected - * @type {ol.TileUrlFunctionType} - */ - this.tileUrlFunction = options.tileUrlFunction ? - options.tileUrlFunction : - ol.TileUrlFunction.nullTileUrlFunction; - - /** - * @protected - * @type {!Array.<string>|null} - */ - this.urls = null; - - if (options.urls) { - if (options.tileUrlFunction) { - this.urls = options.urls; - } else { - this.setUrls(options.urls); - } - } else if (options.url) { - this.setUrl(options.url); - } - if (options.tileUrlFunction) { - this.setTileUrlFunction(options.tileUrlFunction); - } - -}; -goog.inherits(ol.source.UrlTile, ol.source.Tile); - - -/** - * Return the tile load function of the source. - * @return {ol.TileLoadFunctionType} TileLoadFunction - * @api - */ -ol.source.UrlTile.prototype.getTileLoadFunction = function() { - return this.tileLoadFunction; -}; - - -/** - * Return the tile URL function of the source. - * @return {ol.TileUrlFunctionType} TileUrlFunction - * @api - */ -ol.source.UrlTile.prototype.getTileUrlFunction = function() { - return this.tileUrlFunction; -}; - - -/** - * Return the URLs used for this source. - * When a tileUrlFunction is used instead of url or urls, - * null will be returned. - * @return {!Array.<string>|null} URLs. - * @api - */ -ol.source.UrlTile.prototype.getUrls = function() { - return this.urls; -}; - - -/** - * Handle tile change events. - * @param {goog.events.Event} event Event. - * @protected - */ -ol.source.UrlTile.prototype.handleTileChange = function(event) { - var tile = /** @type {ol.Tile} */ (event.target); - switch (tile.getState()) { - case ol.TileState.LOADING: - this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADSTART, tile)); - break; - case ol.TileState.LOADED: - this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADEND, tile)); - break; - case ol.TileState.ERROR: - this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADERROR, tile)); - break; - } -}; - - -/** - * Set the tile load function of the source. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - * @api - */ -ol.source.UrlTile.prototype.setTileLoadFunction = function(tileLoadFunction) { - this.tileCache.clear(); - this.tileLoadFunction = tileLoadFunction; - this.changed(); -}; - - -/** - * Set the tile URL function of the source. - * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function. - * @api - */ -ol.source.UrlTile.prototype.setTileUrlFunction = function(tileUrlFunction) { - // FIXME It should be possible to be more intelligent and avoid clearing the - // FIXME cache. The tile URL function would need to be incorporated into the - // FIXME cache key somehow. - this.tileCache.clear(); - this.tileUrlFunction = tileUrlFunction; - this.changed(); -}; - - -/** - * Set the URL to use for requests. - * @param {string} url URL. - * @api stable - */ -ol.source.UrlTile.prototype.setUrl = function(url) { - this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( - ol.TileUrlFunction.expandUrl(url), this.tileGrid)); - this.urls = [url]; -}; - - -/** - * Set the URLs to use for requests. - * @param {Array.<string>} urls URLs. - * @api stable - */ -ol.source.UrlTile.prototype.setUrls = function(urls) { - this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( - urls, this.tileGrid)); - this.urls = urls; -}; - - -/** - * @inheritDoc - */ -ol.source.UrlTile.prototype.useTile = function(z, x, y) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - this.tileCache.get(tileCoordKey); - } -}; - -goog.provide('ol.source.VectorTile'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.TileState'); -goog.require('ol.VectorTile'); -goog.require('ol.featureloader'); -goog.require('ol.source.UrlTile'); - - - -/** - * @classdesc - * Class for layer sources providing vector data divided into a tile grid, to be - * used with {@link ol.layer.VectorTile}. Although this source receives tiles - * with vector features from the server, it is not meant for feature editing. - * Features are optimized for rendering, their geometries are clipped at or near - * tile boundaries and simplified for a view resolution. See - * {@link ol.source.Vector} for vector sources that are suitable for feature - * editing. - * - * @constructor - * @fires ol.source.TileEvent - * @extends {ol.source.UrlTile} - * @param {olx.source.VectorTileOptions} options Vector tile options. - * @api - */ -ol.source.VectorTile = function(options) { - - goog.base(this, { - attributions: options.attributions, - cacheSize: ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK / 16, - extent: options.extent, - logo: options.logo, - opaque: options.opaque, - projection: options.projection, - state: options.state ? - /** @type {ol.source.State} */ (options.state) : undefined, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction ? - options.tileLoadFunction : ol.source.VectorTile.defaultTileLoadFunction, - tileUrlFunction: options.tileUrlFunction, - tilePixelRatio: options.tilePixelRatio, - url: options.url, - urls: options.urls, - wrapX: options.wrapX === undefined ? true : options.wrapX - }); - - /** - * @private - * @type {ol.format.Feature} - */ - this.format_ = options.format ? options.format : null; - - /** - * @protected - * @type {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string, - * ol.format.Feature, ol.TileLoadFunctionType)} - */ - this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile; - -}; -goog.inherits(ol.source.VectorTile, ol.source.UrlTile); - - -/** - * @inheritDoc - */ -ol.source.VectorTile.prototype.getTile = - function(z, x, y, pixelRatio, projection) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); - } else { - goog.asserts.assert(projection, 'argument projection is truthy'); - var tileCoord = [z, x, y]; - var urlTileCoord = this.getTileCoordForTileUrlFunction( - tileCoord, projection); - var tileUrl = urlTileCoord ? - this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined; - var tile = new this.tileClass( - tileCoord, - tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, - tileUrl !== undefined ? tileUrl : '', - this.format_, - this.tileLoadFunction); - goog.events.listen(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - - this.tileCache.set(tileCoordKey, tile); - return tile; - } -}; - - -/** - * @param {ol.VectorTile} vectorTile Vector tile. - * @param {string} url URL. - */ -ol.source.VectorTile.defaultTileLoadFunction = function(vectorTile, url) { - vectorTile.setLoader(ol.featureloader.tile(url, vectorTile.getFormat())); -}; - -goog.provide('ol.renderer.canvas.VectorTileLayer'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Feature'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.VectorTile'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.VectorTile'); -goog.require('ol.proj.Units'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.renderer.vector'); -goog.require('ol.size'); -goog.require('ol.source.VectorTile'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.VectorTile} layer VectorTile layer. - */ -ol.renderer.canvas.VectorTileLayer = function(layer) { - - goog.base(this, layer); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - - /** - * @private - * @type {Array.<ol.VectorTile>} - */ - this.renderedTiles_ = []; - - /** - * @private - * @type {ol.Extent} - */ - this.tmpExtent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [NaN, NaN]; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.tmpTransform_ = goog.vec.Mat4.createNumber(); - -}; -goog.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = - function(frameState, layerState, context) { - - var pixelRatio = frameState.pixelRatio; - var skippedFeatureUids = layerState.managed ? - frameState.skippedFeatureUids : {}; - var viewState = frameState.viewState; - var center = viewState.center; - var projection = viewState.projection; - var resolution = viewState.resolution; - var rotation = viewState.rotation; - var layer = this.getLayer(); - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - - var transform = this.getTransform(frameState, 0); - - this.dispatchPreComposeEvent(context, frameState, transform); - - var replayContext; - if (layer.hasListener(ol.render.EventType.RENDER)) { - // resize and clear - this.context_.canvas.width = context.canvas.width; - this.context_.canvas.height = context.canvas.height; - replayContext = this.context_; - } else { - replayContext = context; - } - // for performance reasons, context.save / context.restore is not used - // to save and restore the transformation matrix and the opacity. - // see http://jsperf.com/context-save-restore-versus-variable - var alpha = replayContext.globalAlpha; - replayContext.globalAlpha = layerState.opacity; - - var tilesToDraw = this.renderedTiles_; - var tileGrid = source.getTileGrid(); - - var currentZ, i, ii, origin, tile, tileSize; - var tilePixelRatio, tilePixelResolution, tilePixelSize, tileResolution; - for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { - tile = tilesToDraw[i]; - currentZ = tile.getTileCoord()[0]; - tileSize = tileGrid.getTileSize(currentZ); - tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); - tilePixelRatio = tilePixelSize[0] / - ol.size.toSize(tileSize, this.tmpSize_)[0]; - tileResolution = tileGrid.getResolution(currentZ); - tilePixelResolution = tileResolution / tilePixelRatio; - if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) { - origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( - tile.getTileCoord(), this.tmpExtent_)); - transform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio * tilePixelResolution / resolution, - pixelRatio * tilePixelResolution / resolution, - viewState.rotation, - (origin[0] - center[0]) / tilePixelResolution, - (center[1] - origin[1]) / tilePixelResolution); - } - tile.getReplayState().replayGroup.replay(replayContext, pixelRatio, - transform, rotation, skippedFeatureUids); - } - - transform = this.getTransform(frameState, 0); - - if (replayContext != context) { - this.dispatchRenderEvent(replayContext, frameState, transform); - context.drawImage(replayContext.canvas, 0, 0); - } - replayContext.globalAlpha = alpha; - - this.dispatchPostComposeEvent(context, frameState, transform); -}; - - -/** - * @param {ol.VectorTile} tile Tile. - * @param {ol.layer.VectorTile} layer Vector tile layer. - * @param {number} pixelRatio Pixel ratio. - */ -ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, - layer, pixelRatio) { - var revision = layer.getRevision(); - var renderOrder = layer.getRenderOrder() || null; - - var replayState = tile.getReplayState(); - if (!replayState.dirty && replayState.renderedRevision == revision && - replayState.renderedRenderOrder == renderOrder) { - return; - } - - // FIXME dispose of old replayGroup in post render - goog.dispose(replayState.replayGroup); - replayState.replayGroup = null; - replayState.dirty = false; - - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - var tileGrid = source.getTileGrid(); - var tileCoord = tile.getTileCoord(); - var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; - var extent; - if (pixelSpace) { - var tilePixelSize = source.getTilePixelSize(tileCoord[0], pixelRatio, - tile.getProjection()); - extent = [0, 0, tilePixelSize[0], tilePixelSize[1]]; - } else { - extent = tileGrid.getTileCoordExtent(tileCoord); - } - var resolution = tileGrid.getResolution(tileCoord[0]); - var tileResolution = pixelSpace ? source.getTilePixelRatio() : resolution; - replayState.dirty = false; - var replayGroup = new ol.render.canvas.ReplayGroup(0, extent, - tileResolution, layer.getRenderBuffer()); - var squaredTolerance = ol.renderer.vector.getSquaredTolerance( - tileResolution, pixelRatio); - - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @this {ol.renderer.canvas.VectorTileLayer} - */ - function renderFeature(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - goog.asserts.assertInstanceof(feature, ol.Feature, 'Got an ol.Feature'); - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = layer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - if (!goog.isArray(styles)) { - styles = [styles]; - } - var dirty = this.renderFeature(feature, squaredTolerance, styles, - replayGroup); - this.dirty_ = this.dirty_ || dirty; - replayState.dirty = replayState.dirty || dirty; - } - } - - var features = tile.getFeatures(); - if (renderOrder && renderOrder !== replayState.renderedRenderOrder) { - features.sort(renderOrder); - } - features.forEach(renderFeature, this); - - replayGroup.finish(); - - replayState.renderedRevision = revision; - replayState.renderedRenderOrder = renderOrder; - replayState.replayGroup = replayGroup; -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var layer = this.getLayer(); - var layerState = frameState.layerStates[goog.getUid(layer)]; - /** @type {Object.<string, boolean>} */ - var features = {}; - - var replayables = this.renderedTiles_; - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - var tileGrid = source.getTileGrid(); - var found, tileSpaceCoordinate; - var i, ii, origin, replayGroup; - var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution; - for (i = 0, ii = replayables.length; i < ii; ++i) { - tile = replayables[i]; - tileCoord = tile.getTileCoord(); - tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord, - this.tmpExtent_); - if (!ol.extent.containsCoordinate(tileExtent, coordinate)) { - continue; - } - if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) { - origin = ol.extent.getTopLeft(tileExtent); - tilePixelRatio = source.getTilePixelRatio(); - tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio; - tileSpaceCoordinate = [ - (coordinate[0] - origin[0]) / tileResolution, - (origin[1] - coordinate[1]) / tileResolution - ]; - resolution = tilePixelRatio; - } else { - tileSpaceCoordinate = coordinate; - } - replayGroup = tile.getReplayState().replayGroup; - found = found || replayGroup.forEachFeatureAtCoordinate( - tileSpaceCoordinate, resolution, rotation, - layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); - } - return found; -}; - - -/** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. - * @private - */ -ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = - function(frameState, layerState) { - var layer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(layer, ol.layer.VectorTile, - 'layer is an instance of ol.layer.VectorTile'); - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - - this.updateAttributions( - frameState.attributions, source.getAttributions()); - this.updateLogos(frameState, source); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = layer.getUpdateWhileAnimating(); - var updateWhileInteracting = layer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - - var extent = frameState.extent; - if (layerState.extent) { - extent = ol.extent.getIntersection(extent, layerState.extent); - } - if (ol.extent.isEmpty(extent)) { - // Return false to prevent the rendering of the layer. - return false; - } - - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - - var tileGrid = source.getTileGrid(); - var resolutions = tileGrid.getResolutions(); - var z = resolutions.length - 1; - while (z > 0 && resolutions[z] < resolution) { - --z; - } - var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - this.updateUsedTiles(frameState.usedTiles, source, z, tileRange); - this.manageTilePyramid(frameState, source, tileGrid, pixelRatio, - projection, extent, z, layer.getPreload()); - this.scheduleExpireCache(frameState, source); - - /** - * @type {Object.<number, Object.<string, ol.VectorTile>>} - */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - - var findLoadedTiles = this.createLoadedTileFinder(source, projection, - tilesToDrawByZ); - - var useInterimTilesOnError = layer.getUseInterimTilesOnError(); - - var tmpExtent = this.tmpExtent_; - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, fullyLoaded, tile, tileState, x, y; - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - - tile = source.getTile(z, x, y, pixelRatio, projection); - goog.asserts.assertInstanceof(tile, ol.VectorTile, - 'Tile is an ol.VectorTile'); - tileState = tile.getState(); - if (tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && !useInterimTilesOnError)) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } - - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } - - } - } - - this.dirty_ = false; - - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - zs.sort(); - var replayables = []; - var i, ii, currentZ, tileCoordKey, tilesToDraw; - for (i = 0, ii = zs.length; i < ii; ++i) { - currentZ = zs[i]; - tilesToDraw = tilesToDrawByZ[currentZ]; - for (tileCoordKey in tilesToDraw) { - tile = tilesToDraw[tileCoordKey]; - if (tile.getState() == ol.TileState.LOADED) { - replayables.push(tile); - this.createReplayGroup(tile, layer, pixelRatio); - } - } - } - - this.renderedTiles_ = replayables; - - return true; -}; - - -/** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {number} squaredTolerance Squared tolerance. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - */ -ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = - function(feature, squaredTolerance, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], squaredTolerance, - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, squaredTolerance, - this.handleStyleImageChange_, this) || loading; - } - return loading; -}; - -// FIXME offset panning - -goog.provide('ol.renderer.canvas.Map'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.RendererType'); -goog.require('ol.css'); -goog.require('ol.dom'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.layer.VectorTile'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.canvas.ImageLayer'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.renderer.canvas.TileLayer'); -goog.require('ol.renderer.canvas.VectorLayer'); -goog.require('ol.renderer.canvas.VectorTileLayer'); -goog.require('ol.source.State'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.Map} - * @param {Element} container Container. - * @param {ol.Map} map Map. - */ -ol.renderer.canvas.Map = function(container, map) { - - goog.base(this, container, map); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = this.context_.canvas; - - this.canvas_.style.width = '100%'; - this.canvas_.style.height = '100%'; - this.canvas_.className = ol.css.CLASS_UNSELECTABLE; - goog.dom.insertChildAt(container, this.canvas_, 0); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - -}; -goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map); - - -/** - * @inheritDoc - */ -ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) { - if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { - return new ol.renderer.canvas.ImageLayer(layer); - } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { - return new ol.renderer.canvas.TileLayer(layer); - } else if (ol.ENABLE_VECTOR_TILE && layer instanceof ol.layer.VectorTile) { - return new ol.renderer.canvas.VectorTileLayer(layer); - } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { - return new ol.renderer.canvas.VectorLayer(layer); - } else { - goog.asserts.fail('unexpected layer configuration'); - return null; - } -}; - - -/** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ = - function(type, frameState) { - var map = this.getMap(); - var context = this.context_; - if (map.hasListener(type)) { - var extent = frameState.extent; - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var rotation = viewState.rotation; - - var transform = this.getTransform(frameState); - - var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio, - extent, transform, rotation); - var composeEvent = new ol.render.Event(type, map, vectorContext, - frameState, context, null); - map.dispatchEvent(composeEvent); - - vectorContext.flush(); - } -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @protected - * @return {!goog.vec.Mat4.Number} Transform. - */ -ol.renderer.canvas.Map.prototype.getTransform = function(frameState) { - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var resolution = viewState.resolution; - return ol.vec.Mat4.makeTransform2D(this.transform_, - this.canvas_.width / 2, this.canvas_.height / 2, - pixelRatio / resolution, -pixelRatio / resolution, - -viewState.rotation, - -viewState.center[0], -viewState.center[1]); -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.Map.prototype.getType = function() { - return ol.RendererType.CANVAS; -}; - - -/** - * @inheritDoc - */ -ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { - - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, false); - this.renderedVisible_ = false; - } - return; - } - - var context = this.context_; - var width = frameState.size[0] * frameState.pixelRatio; - var height = frameState.size[1] * frameState.pixelRatio; - if (this.canvas_.width != width || this.canvas_.height != height) { - this.canvas_.width = width; - this.canvas_.height = height; - } else { - context.clearRect(0, 0, this.canvas_.width, this.canvas_.height); - } - - this.calculateMatrices2D(frameState); - - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); - - var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - - var viewResolution = frameState.viewState.resolution; - var i, ii, layer, layerRenderer, layerState; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerState = layerStatesArray[i]; - layer = layerState.layer; - layerRenderer = this.getLayerRenderer(layer); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.canvas.Layer, - 'layerRenderer is an instance of ol.renderer.canvas.Layer'); - if (!ol.layer.Layer.visibleAtResolution(layerState, viewResolution) || - layerState.sourceState != ol.source.State.READY) { - continue; - } - if (layerRenderer.prepareFrame(frameState, layerState)) { - layerRenderer.composeFrame(frameState, layerState, context); - } - } - - this.dispatchComposeEvent_( - ol.render.EventType.POSTCOMPOSE, frameState); - - if (!this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, true); - this.renderedVisible_ = true; - } - - this.scheduleRemoveUnusedLayerRenderers(frameState); - this.scheduleExpireIconCache(frameState); -}; - -goog.provide('ol.renderer.dom.Layer'); - -goog.require('ol'); -goog.require('ol.layer.Layer'); -goog.require('ol.renderer.Layer'); - - - -/** - * @constructor - * @extends {ol.renderer.Layer} - * @param {ol.layer.Layer} layer Layer. - * @param {!Element} target Target. - */ -ol.renderer.dom.Layer = function(layer, target) { - - goog.base(this, layer); - - /** - * @type {!Element} - * @protected - */ - this.target = target; - -}; -goog.inherits(ol.renderer.dom.Layer, ol.renderer.Layer); - - -/** - * Clear rendered elements. - */ -ol.renderer.dom.Layer.prototype.clearFrame = ol.nullFunction; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - */ -ol.renderer.dom.Layer.prototype.composeFrame = ol.nullFunction; - - -/** - * @return {!Element} Target. - */ -ol.renderer.dom.Layer.prototype.getTarget = function() { - return this.target; -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @return {boolean} whether composeFrame should be called. - */ -ol.renderer.dom.Layer.prototype.prepareFrame = goog.abstractMethod; - -goog.provide('ol.renderer.dom.ImageLayer'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ImageBase'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.proj'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.dom.Layer} - * @param {ol.layer.Image} imageLayer Image layer. - */ -ol.renderer.dom.ImageLayer = function(imageLayer) { - var target = goog.dom.createElement('DIV'); - target.style.position = 'absolute'; - - goog.base(this, imageLayer, target); - - /** - * The last rendered image. - * @private - * @type {?ol.ImageBase} - */ - this.image_ = null; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumberIdentity(); - -}; -goog.inherits(ol.renderer.dom.ImageLayer, ol.renderer.dom.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.dom.ImageLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var layer = this.getLayer(); - var source = layer.getSource(); - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var skippedFeatureUids = frameState.skippedFeatureUids; - return source.forEachFeatureAtCoordinate( - coordinate, resolution, rotation, skippedFeatureUids, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - return callback.call(thisArg, feature, layer); - }); -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.ImageLayer.prototype.clearFrame = function() { - goog.dom.removeChildren(this.target); - this.image_ = null; -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.ImageLayer.prototype.prepareFrame = - function(frameState, layerState) { - - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewResolution = viewState.resolution; - var viewRotation = viewState.rotation; - - var image = this.image_; - var imageLayer = this.getLayer(); - goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, - 'layer is an instance of ol.layer.Image'); - var imageSource = imageLayer.getSource(); - - var hints = frameState.viewHints; - - var renderedExtent = frameState.extent; - if (layerState.extent !== undefined) { - renderedExtent = ol.extent.getIntersection( - renderedExtent, layerState.extent); - } - - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && - !ol.extent.isEmpty(renderedExtent)) { - var projection = viewState.projection; - if (!ol.ENABLE_RASTER_REPROJECTION) { - var sourceProjection = imageSource.getProjection(); - if (sourceProjection) { - goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), - 'projection and sourceProjection are equivalent'); - projection = sourceProjection; - } - } - var image_ = imageSource.getImage(renderedExtent, viewResolution, - frameState.pixelRatio, projection); - if (image_) { - var loaded = this.loadImage(image_); - if (loaded) { - image = image_; - } - } - } - - if (image) { - var imageExtent = image.getExtent(); - var imageResolution = image.getResolution(); - var transform = goog.vec.Mat4.createNumber(); - ol.vec.Mat4.makeTransform2D(transform, - frameState.size[0] / 2, frameState.size[1] / 2, - imageResolution / viewResolution, imageResolution / viewResolution, - viewRotation, - (imageExtent[0] - viewCenter[0]) / imageResolution, - (viewCenter[1] - imageExtent[3]) / imageResolution); - if (image != this.image_) { - var imageElement = image.getImage(this); - // Bootstrap sets the style max-width: 100% for all images, which breaks - // prevents the image from being displayed in FireFox. Workaround by - // overriding the max-width style. - imageElement.style.maxWidth = 'none'; - imageElement.style.position = 'absolute'; - goog.dom.removeChildren(this.target); - this.target.appendChild(imageElement); - this.image_ = image; - } - this.setTransform_(transform); - this.updateAttributions(frameState.attributions, image.getAttributions()); - this.updateLogos(frameState, imageSource); - } - - return true; -}; - - -/** - * @param {goog.vec.Mat4.Number} transform Transform. - * @private - */ -ol.renderer.dom.ImageLayer.prototype.setTransform_ = function(transform) { - if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { - ol.dom.transformElement2D(this.target, transform, 6); - goog.vec.Mat4.setFromArray(this.transform_, transform); - } -}; - -// FIXME probably need to reset TileLayerZ if offsets get too large -// FIXME when zooming out, preserve higher Z divs to avoid white flash - -goog.provide('ol.renderer.dom.TileLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.TileCoord'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Tile'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); -goog.require('ol.tilegrid.TileGrid'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.dom.Layer} - * @param {ol.layer.Tile} tileLayer Tile layer. - */ -ol.renderer.dom.TileLayer = function(tileLayer) { - - var target = goog.dom.createElement('DIV'); - target.style.position = 'absolute'; - - goog.base(this, tileLayer, target); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - - /** - * @private - * @type {number} - */ - this.renderedOpacity_ = 1; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; - - /** - * @private - * @type {!Object.<number, ol.renderer.dom.TileLayerZ_>} - */ - this.tileLayerZs_ = {}; - -}; -goog.inherits(ol.renderer.dom.TileLayer, ol.renderer.dom.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.dom.TileLayer.prototype.clearFrame = function() { - goog.dom.removeChildren(this.target); - this.renderedRevision_ = 0; -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.TileLayer.prototype.prepareFrame = - function(frameState, layerState) { - - if (!layerState.visible) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.target, false); - this.renderedVisible_ = false; - } - return true; - } - - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var projection = viewState.projection; - - var tileLayer = this.getLayer(); - goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, - 'layer is an instance of ol.layer.Tile'); - var tileSource = tileLayer.getSource(); - var tileGrid = tileSource.getTileGridForProjection(projection); - var tileGutter = tileSource.getGutter(); - var z = tileGrid.getZForResolution(viewState.resolution); - var tileResolution = tileGrid.getResolution(z); - var center = viewState.center; - var extent; - if (tileResolution == viewState.resolution) { - center = this.snapCenterToPixel(center, tileResolution, frameState.size); - extent = ol.extent.getForViewAndSize( - center, tileResolution, viewState.rotation, frameState.size); - } else { - extent = frameState.extent; - } - - if (layerState.extent !== undefined) { - extent = ol.extent.getIntersection(extent, layerState.extent); - } - - var tileRange = tileGrid.getTileRangeForExtentAndResolution( - extent, tileResolution); - - /** @type {Object.<number, Object.<string, ol.Tile>>} */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - - var findLoadedTiles = this.createLoadedTileFinder( - tileSource, projection, tilesToDrawByZ); - - var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); - - var tmpExtent = ol.extent.createEmpty(); - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, drawable, fullyLoaded, tile, tileState, x, y; - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - tileState = tile.getState(); - drawable = tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - tileState == ol.TileState.ERROR && !useInterimTilesOnError; - if (!drawable && tile.interimTile) { - tile = tile.interimTile; - } - goog.asserts.assert(tile); - tileState = tile.getState(); - if (tileState == ol.TileState.LOADED) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } else if (tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && - !useInterimTilesOnError)) { - continue; - } - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } - - } - - } - - // If the tile source revision changes, we destroy the existing DOM structure - // so that a new one will be created. It would be more efficient to modify - // the existing structure. - var tileLayerZ, tileLayerZKey; - if (this.renderedRevision_ != tileSource.getRevision()) { - for (tileLayerZKey in this.tileLayerZs_) { - tileLayerZ = this.tileLayerZs_[+tileLayerZKey]; - goog.dom.removeNode(tileLayerZ.target); - } - this.tileLayerZs_ = {}; - this.renderedRevision_ = tileSource.getRevision(); - } - - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - goog.array.sort(zs); - - /** @type {Object.<number, boolean>} */ - var newTileLayerZKeys = {}; - - var iz, iziz, tileCoordKey, tileCoordOrigin, tilesToDraw; - for (iz = 0, iziz = zs.length; iz < iziz; ++iz) { - tileLayerZKey = zs[iz]; - if (tileLayerZKey in this.tileLayerZs_) { - tileLayerZ = this.tileLayerZs_[tileLayerZKey]; - } else { - tileCoordOrigin = - tileGrid.getTileCoordForCoordAndZ(center, tileLayerZKey); - tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin); - newTileLayerZKeys[tileLayerZKey] = true; - this.tileLayerZs_[tileLayerZKey] = tileLayerZ; - } - tilesToDraw = tilesToDrawByZ[tileLayerZKey]; - for (tileCoordKey in tilesToDraw) { - tileLayerZ.addTile(tilesToDraw[tileCoordKey], tileGutter); - } - tileLayerZ.finalizeAddTiles(); - } - - /** @type {Array.<number>} */ - var tileLayerZKeys = Object.keys(this.tileLayerZs_).map(Number); - goog.array.sort(tileLayerZKeys); - - var i, ii, j, origin, resolution; - var transform = goog.vec.Mat4.createNumber(); - for (i = 0, ii = tileLayerZKeys.length; i < ii; ++i) { - tileLayerZKey = tileLayerZKeys[i]; - tileLayerZ = this.tileLayerZs_[tileLayerZKey]; - if (!(tileLayerZKey in tilesToDrawByZ)) { - goog.dom.removeNode(tileLayerZ.target); - delete this.tileLayerZs_[tileLayerZKey]; - continue; - } - resolution = tileLayerZ.getResolution(); - origin = tileLayerZ.getOrigin(); - ol.vec.Mat4.makeTransform2D(transform, - frameState.size[0] / 2, frameState.size[1] / 2, - resolution / viewState.resolution, - resolution / viewState.resolution, - viewState.rotation, - (origin[0] - center[0]) / resolution, - (center[1] - origin[1]) / resolution); - tileLayerZ.setTransform(transform); - if (tileLayerZKey in newTileLayerZKeys) { - for (j = tileLayerZKey - 1; j >= 0; --j) { - if (j in this.tileLayerZs_) { - goog.dom.insertSiblingAfter( - tileLayerZ.target, this.tileLayerZs_[j].target); - break; - } - } - if (j < 0) { - goog.dom.insertChildAt(this.target, tileLayerZ.target, 0); - } - } else { - if (!frameState.viewHints[ol.ViewHint.ANIMATING] && - !frameState.viewHints[ol.ViewHint.INTERACTING]) { - tileLayerZ.removeTilesOutsideExtent(extent, tmpTileRange); - } - } - } - - if (layerState.opacity != this.renderedOpacity_) { - this.target.style.opacity = layerState.opacity; - this.renderedOpacity_ = layerState.opacity; - } - - if (layerState.visible && !this.renderedVisible_) { - goog.style.setElementShown(this.target, true); - this.renderedVisible_ = true; - } - - this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); - this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, - projection, extent, z, tileLayer.getPreload()); - this.scheduleExpireCache(frameState, tileSource); - this.updateLogos(frameState, tileSource); - - return true; -}; - - - -/** - * @constructor - * @private - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {ol.TileCoord} tileCoordOrigin Tile coord origin. - */ -ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) { - - /** - * @type {!Element} - */ - this.target = goog.dom.createElement('DIV'); - this.target.style.position = 'absolute'; - this.target.style.width = '100%'; - this.target.style.height = '100%'; - - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.tileGrid_ = tileGrid; - - /** - * @private - * @type {ol.TileCoord} - */ - this.tileCoordOrigin_ = tileCoordOrigin; - - /** - * @private - * @type {ol.Coordinate} - */ - this.origin_ = - ol.extent.getTopLeft(tileGrid.getTileCoordExtent(tileCoordOrigin)); - - /** - * @private - * @type {number} - */ - this.resolution_ = tileGrid.getResolution(tileCoordOrigin[0]); - - /** - * @private - * @type {Object.<string, ol.Tile>} - */ - this.tiles_ = {}; - - /** - * @private - * @type {DocumentFragment} - */ - this.documentFragment_ = null; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumberIdentity(); - - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; - -}; - - -/** - * @param {ol.Tile} tile Tile. - * @param {number} tileGutter Tile gutter. - */ -ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile, tileGutter) { - var tileCoord = tile.tileCoord; - var tileCoordZ = tileCoord[0]; - var tileCoordX = tileCoord[1]; - var tileCoordY = tileCoord[2]; - goog.asserts.assert(tileCoordZ == this.tileCoordOrigin_[0], - 'tileCoordZ matches z of tileCoordOrigin'); - var tileCoordKey = ol.tilecoord.toString(tileCoord); - if (tileCoordKey in this.tiles_) { - return; - } - var tileSize = ol.size.toSize( - this.tileGrid_.getTileSize(tileCoordZ), this.tmpSize_); - var image = tile.getImage(this); - var imageStyle = image.style; - // Bootstrap sets the style max-width: 100% for all images, which - // prevents the tile from being displayed in FireFox. Workaround - // by overriding the max-width style. - imageStyle.maxWidth = 'none'; - var tileElement; - var tileElementStyle; - if (tileGutter > 0) { - tileElement = goog.dom.createElement('DIV'); - tileElementStyle = tileElement.style; - tileElementStyle.overflow = 'hidden'; - tileElementStyle.width = tileSize[0] + 'px'; - tileElementStyle.height = tileSize[1] + 'px'; - imageStyle.position = 'absolute'; - imageStyle.left = -tileGutter + 'px'; - imageStyle.top = -tileGutter + 'px'; - imageStyle.width = (tileSize[0] + 2 * tileGutter) + 'px'; - imageStyle.height = (tileSize[1] + 2 * tileGutter) + 'px'; - tileElement.appendChild(image); - } else { - imageStyle.width = tileSize[0] + 'px'; - imageStyle.height = tileSize[1] + 'px'; - tileElement = image; - tileElementStyle = imageStyle; - } - tileElementStyle.position = 'absolute'; - tileElementStyle.left = - ((tileCoordX - this.tileCoordOrigin_[1]) * tileSize[0]) + 'px'; - tileElementStyle.top = - ((this.tileCoordOrigin_[2] - tileCoordY) * tileSize[1]) + 'px'; - if (!this.documentFragment_) { - this.documentFragment_ = document.createDocumentFragment(); - } - this.documentFragment_.appendChild(tileElement); - this.tiles_[tileCoordKey] = tile; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() { - if (this.documentFragment_) { - this.target.appendChild(this.documentFragment_); - this.documentFragment_ = null; - } -}; - - -/** - * @return {ol.Coordinate} Origin. - */ -ol.renderer.dom.TileLayerZ_.prototype.getOrigin = function() { - return this.origin_; -}; - - -/** - * @return {number} Resolution. - */ -ol.renderer.dom.TileLayerZ_.prototype.getResolution = function() { - return this.resolution_; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. - */ -ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent = - function(extent, opt_tileRange) { - var tileRange = this.tileGrid_.getTileRangeForExtentAndZ( - extent, this.tileCoordOrigin_[0], opt_tileRange); - /** @type {Array.<ol.Tile>} */ - var tilesToRemove = []; - var tile, tileCoordKey; - for (tileCoordKey in this.tiles_) { - tile = this.tiles_[tileCoordKey]; - if (!tileRange.contains(tile.tileCoord)) { - tilesToRemove.push(tile); - } - } - var i, ii; - for (i = 0, ii = tilesToRemove.length; i < ii; ++i) { - tile = tilesToRemove[i]; - tileCoordKey = ol.tilecoord.toString(tile.tileCoord); - goog.dom.removeNode(tile.getImage(this)); - delete this.tiles_[tileCoordKey]; - } -}; - - -/** - * @param {goog.vec.Mat4.Number} transform Transform. - */ -ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) { - if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { - ol.dom.transformElement2D(this.target, transform, 6); - goog.vec.Mat4.setFromArray(this.transform_, transform); - } -}; - -goog.provide('ol.renderer.dom.VectorLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.renderer.vector'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.dom.Layer} - * @param {ol.layer.Vector} vectorLayer Vector layer. - */ -ol.renderer.dom.VectorLayer = function(vectorLayer) { - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - - var target = this.context_.canvas; - // Bootstrap sets the style max-width: 100% for all images, which breaks - // prevents the image from being displayed in FireFox. Workaround by - // overriding the max-width style. - target.style.maxWidth = 'none'; - target.style.position = 'absolute'; - - goog.base(this, vectorLayer, target); - - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.renderedResolution_ = NaN; - - /** - * @private - * @type {ol.Extent} - */ - this.renderedExtent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {function(ol.Feature, ol.Feature): number|null} - */ - this.renderedRenderOrder_ = null; - - /** - * @private - * @type {ol.render.canvas.ReplayGroup} - */ - this.replayGroup_ = null; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.elementTransform_ = goog.vec.Mat4.createNumber(); - -}; -goog.inherits(ol.renderer.dom.VectorLayer, ol.renderer.dom.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.dom.VectorLayer.prototype.composeFrame = - function(frameState, layerState) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewRotation = viewState.rotation; - var viewResolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var viewWidth = frameState.size[0]; - var viewHeight = frameState.size[1]; - var imageWidth = viewWidth * pixelRatio; - var imageHeight = viewHeight * pixelRatio; - - var transform = ol.vec.Mat4.makeTransform2D(this.transform_, - pixelRatio * viewWidth / 2, - pixelRatio * viewHeight / 2, - pixelRatio / viewResolution, - -pixelRatio / viewResolution, - -viewRotation, - -viewCenter[0], -viewCenter[1]); - - var context = this.context_; - - // Clear the canvas and set the correct size - context.canvas.width = imageWidth; - context.canvas.height = imageHeight; - - var elementTransform = ol.vec.Mat4.makeTransform2D(this.elementTransform_, - 0, 0, - 1 / pixelRatio, 1 / pixelRatio, - 0, - -(imageWidth - viewWidth) / 2 * pixelRatio, - -(imageHeight - viewHeight) / 2 * pixelRatio); - ol.dom.transformElement2D(context.canvas, elementTransform, 6); - - this.dispatchEvent_(ol.render.EventType.PRECOMPOSE, frameState, transform); - - var replayGroup = this.replayGroup_; - - if (replayGroup && !replayGroup.isEmpty()) { - - context.globalAlpha = layerState.opacity; - replayGroup.replay(context, pixelRatio, transform, viewRotation, - layerState.managed ? frameState.skippedFeatureUids : {}); - - this.dispatchEvent_(ol.render.EventType.RENDER, frameState, transform); - } - - this.dispatchEvent_(ol.render.EventType.POSTCOMPOSE, frameState, transform); -}; - - -/** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number} transform Transform. - * @private - */ -ol.renderer.dom.VectorLayer.prototype.dispatchEvent_ = - function(type, frameState, transform) { - var context = this.context_; - var layer = this.getLayer(); - if (layer.hasListener(type)) { - var render = new ol.render.canvas.Immediate( - context, frameState.pixelRatio, frameState.extent, transform, - frameState.viewState.rotation); - var event = new ol.render.Event(type, layer, render, frameState, - context, null); - layer.dispatchEvent(event); - render.flush(); - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.VectorLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - if (!this.replayGroup_) { - return undefined; - } else { - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var layer = this.getLayer(); - var layerState = frameState.layerStates[goog.getUid(layer)]; - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, - rotation, layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); - } -}; - - -/** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. - * @private - */ -ol.renderer.dom.VectorLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.VectorLayer.prototype.prepareFrame = - function(frameState, layerState) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - var vectorSource = vectorLayer.getSource(); - - this.updateAttributions( - frameState.attributions, vectorSource.getAttributions()); - this.updateLogos(frameState, vectorSource); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); - var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - - var frameStateExtent = frameState.extent; - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var vectorLayerRevision = vectorLayer.getRevision(); - var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); - var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); - - if (vectorLayerRenderOrder === undefined) { - vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; - } - - var extent = ol.extent.buffer(frameStateExtent, - vectorLayerRenderBuffer * resolution); - - if (!this.dirty_ && - this.renderedResolution_ == resolution && - this.renderedRevision_ == vectorLayerRevision && - this.renderedRenderOrder_ == vectorLayerRenderOrder && - ol.extent.containsExtent(this.renderedExtent_, extent)) { - return true; - } - - // FIXME dispose of old replayGroup in post render - goog.dispose(this.replayGroup_); - this.replayGroup_ = null; - - this.dirty_ = false; - - var replayGroup = - new ol.render.canvas.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, - resolution, vectorLayer.getRenderBuffer()); - vectorSource.loadFeatures(extent, resolution, projection); - var renderFeature = - /** - * @param {ol.Feature} feature Feature. - * @this {ol.renderer.dom.VectorLayer} - */ - function(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = vectorLayer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - var dirty = this.renderFeature( - feature, resolution, pixelRatio, styles, replayGroup); - this.dirty_ = this.dirty_ || dirty; - } - }; - if (vectorLayerRenderOrder) { - /** @type {Array.<ol.Feature>} */ - var features = []; - vectorSource.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - features.push(feature); - }, this); - goog.array.sort(features, vectorLayerRenderOrder); - features.forEach(renderFeature, this); - } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); - } - replayGroup.finish(); - - this.renderedResolution_ = resolution; - this.renderedRevision_ = vectorLayerRevision; - this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; - this.replayGroup_ = replayGroup; - - return true; -}; - - -/** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - */ -ol.renderer.dom.VectorLayer.prototype.renderFeature = - function(feature, resolution, pixelRatio, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - return loading; -}; - -goog.provide('ol.renderer.dom.Map'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.RendererType'); -goog.require('ol.css'); -goog.require('ol.dom'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.dom.ImageLayer'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.renderer.dom.TileLayer'); -goog.require('ol.renderer.dom.VectorLayer'); -goog.require('ol.source.State'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.Map} - * @param {Element} container Container. - * @param {ol.Map} map Map. - */ -ol.renderer.dom.Map = function(container, map) { - - goog.base(this, container, map); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - var canvas = this.context_.canvas; - canvas.style.position = 'absolute'; - canvas.style.width = '100%'; - canvas.style.height = '100%'; - canvas.className = ol.css.CLASS_UNSELECTABLE; - goog.dom.insertChildAt(container, canvas, 0); - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - - /** - * @type {!Element} - * @private - */ - this.layersPane_ = goog.dom.createElement('DIV'); - this.layersPane_.className = ol.css.CLASS_UNSELECTABLE; - var style = this.layersPane_.style; - style.position = 'absolute'; - style.width = '100%'; - style.height = '100%'; - - // prevent the img context menu on mobile devices - goog.events.listen(this.layersPane_, goog.events.EventType.TOUCHSTART, - goog.events.Event.preventDefault); - - goog.dom.insertChildAt(container, this.layersPane_, 0); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - -}; -goog.inherits(ol.renderer.dom.Map, ol.renderer.Map); - - -/** - * @inheritDoc - */ -ol.renderer.dom.Map.prototype.disposeInternal = function() { - goog.dom.removeNode(this.layersPane_); - goog.base(this, 'disposeInternal'); -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { - var layerRenderer; - if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { - layerRenderer = new ol.renderer.dom.ImageLayer(layer); - } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { - layerRenderer = new ol.renderer.dom.TileLayer(layer); - } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { - layerRenderer = new ol.renderer.dom.VectorLayer(layer); - } else { - goog.asserts.fail('unexpected layer configuration'); - return null; - } - return layerRenderer; -}; - - -/** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.dom.Map.prototype.dispatchComposeEvent_ = - function(type, frameState) { - var map = this.getMap(); - if (map.hasListener(type)) { - var extent = frameState.extent; - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var rotation = viewState.rotation; - var context = this.context_; - var canvas = context.canvas; - - ol.vec.Mat4.makeTransform2D(this.transform_, - canvas.width / 2, - canvas.height / 2, - pixelRatio / viewState.resolution, - -pixelRatio / viewState.resolution, - -viewState.rotation, - -viewState.center[0], -viewState.center[1]); - var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio, - extent, this.transform_, rotation); - var composeEvent = new ol.render.Event(type, map, vectorContext, - frameState, context, null); - map.dispatchEvent(composeEvent); - vectorContext.flush(); - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.Map.prototype.getType = function() { - return ol.RendererType.DOM; -}; - - -/** - * @inheritDoc - */ -ol.renderer.dom.Map.prototype.renderFrame = function(frameState) { - - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.layersPane_, false); - this.renderedVisible_ = false; - } - return; - } - - var map = this.getMap(); - if (map.hasListener(ol.render.EventType.PRECOMPOSE) || - map.hasListener(ol.render.EventType.POSTCOMPOSE)) { - var canvas = this.context_.canvas; - var pixelRatio = frameState.pixelRatio; - canvas.width = frameState.size[0] * pixelRatio; - canvas.height = frameState.size[1] * pixelRatio; - } - - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); - - var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - - var viewResolution = frameState.viewState.resolution; - var i, ii, layer, layerRenderer, layerState; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerState = layerStatesArray[i]; - layer = layerState.layer; - layerRenderer = /** @type {ol.renderer.dom.Layer} */ ( - this.getLayerRenderer(layer)); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer, - 'renderer is an instance of ol.renderer.dom.Layer'); - goog.dom.insertChildAt(this.layersPane_, layerRenderer.getTarget(), i); - if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerState.sourceState == ol.source.State.READY) { - if (layerRenderer.prepareFrame(frameState, layerState)) { - layerRenderer.composeFrame(frameState, layerState); - } - } else { - layerRenderer.clearFrame(); - } - } - - var layerStates = frameState.layerStates; - var layerKey; - for (layerKey in this.getLayerRenderers()) { - if (!(layerKey in layerStates)) { - layerRenderer = this.getLayerRendererByKey(layerKey); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer, - 'renderer is an instance of ol.renderer.dom.Layer'); - goog.dom.removeNode(layerRenderer.getTarget()); - } - } - - if (!this.renderedVisible_) { - goog.style.setElementShown(this.layersPane_, true); - this.renderedVisible_ = true; - } - - this.calculateMatrices2D(frameState); - this.scheduleRemoveUnusedLayerRenderers(frameState); - this.scheduleExpireIconCache(frameState); - - this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState); -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Constants used by the WebGL rendering, including all of the - * constants used from the WebGL context. For example, instead of using - * context.ARRAY_BUFFER, your code can use - * goog.webgl.ARRAY_BUFFER. The benefits for doing this include allowing - * the compiler to optimize your code so that the compiled code does not have to - * contain large strings to reference these properties, and reducing runtime - * property access. - * - * Values are taken from the WebGL Spec: - * https://www.khronos.org/registry/webgl/specs/1.0/#WEBGLRENDERINGCONTEXT - */ - -goog.provide('goog.webgl'); - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_BUFFER_BIT = 0x00000100; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BUFFER_BIT = 0x00000400; - - -/** - * @const - * @type {number} - */ -goog.webgl.COLOR_BUFFER_BIT = 0x00004000; - - -/** - * @const - * @type {number} - */ -goog.webgl.POINTS = 0x0000; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINES = 0x0001; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINE_LOOP = 0x0002; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINE_STRIP = 0x0003; - - -/** - * @const - * @type {number} - */ -goog.webgl.TRIANGLES = 0x0004; - - -/** - * @const - * @type {number} - */ -goog.webgl.TRIANGLE_STRIP = 0x0005; - - -/** - * @const - * @type {number} - */ -goog.webgl.TRIANGLE_FAN = 0x0006; - - -/** - * @const - * @type {number} - */ -goog.webgl.ZERO = 0; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE = 1; - - -/** - * @const - * @type {number} - */ -goog.webgl.SRC_COLOR = 0x0300; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_SRC_COLOR = 0x0301; - - -/** - * @const - * @type {number} - */ -goog.webgl.SRC_ALPHA = 0x0302; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_SRC_ALPHA = 0x0303; - - -/** - * @const - * @type {number} - */ -goog.webgl.DST_ALPHA = 0x0304; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_DST_ALPHA = 0x0305; - - -/** - * @const - * @type {number} - */ -goog.webgl.DST_COLOR = 0x0306; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_DST_COLOR = 0x0307; - - -/** - * @const - * @type {number} - */ -goog.webgl.SRC_ALPHA_SATURATE = 0x0308; - - -/** - * @const - * @type {number} - */ -goog.webgl.FUNC_ADD = 0x8006; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_EQUATION = 0x8009; - - -/** - * Same as BLEND_EQUATION - * @const - * @type {number} - */ -goog.webgl.BLEND_EQUATION_RGB = 0x8009; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_EQUATION_ALPHA = 0x883D; - - -/** - * @const - * @type {number} - */ -goog.webgl.FUNC_SUBTRACT = 0x800A; - - -/** - * @const - * @type {number} - */ -goog.webgl.FUNC_REVERSE_SUBTRACT = 0x800B; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_DST_RGB = 0x80C8; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_SRC_RGB = 0x80C9; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_DST_ALPHA = 0x80CA; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_SRC_ALPHA = 0x80CB; - - -/** - * @const - * @type {number} - */ -goog.webgl.CONSTANT_COLOR = 0x8001; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_CONSTANT_COLOR = 0x8002; - - -/** - * @const - * @type {number} - */ -goog.webgl.CONSTANT_ALPHA = 0x8003; - - -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_CONSTANT_ALPHA = 0x8004; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_COLOR = 0x8005; - - -/** - * @const - * @type {number} - */ -goog.webgl.ARRAY_BUFFER = 0x8892; - - -/** - * @const - * @type {number} - */ -goog.webgl.ELEMENT_ARRAY_BUFFER = 0x8893; - - -/** - * @const - * @type {number} - */ -goog.webgl.ARRAY_BUFFER_BINDING = 0x8894; - - -/** - * @const - * @type {number} - */ -goog.webgl.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; - - -/** - * @const - * @type {number} - */ -goog.webgl.STREAM_DRAW = 0x88E0; - - -/** - * @const - * @type {number} - */ -goog.webgl.STATIC_DRAW = 0x88E4; - - -/** - * @const - * @type {number} - */ -goog.webgl.DYNAMIC_DRAW = 0x88E8; - - -/** - * @const - * @type {number} - */ -goog.webgl.BUFFER_SIZE = 0x8764; - - -/** - * @const - * @type {number} - */ -goog.webgl.BUFFER_USAGE = 0x8765; - - -/** - * @const - * @type {number} - */ -goog.webgl.CURRENT_VERTEX_ATTRIB = 0x8626; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRONT = 0x0404; - - -/** - * @const - * @type {number} - */ -goog.webgl.BACK = 0x0405; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRONT_AND_BACK = 0x0408; - - -/** - * @const - * @type {number} - */ -goog.webgl.CULL_FACE = 0x0B44; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLEND = 0x0BE2; - - -/** - * @const - * @type {number} - */ -goog.webgl.DITHER = 0x0BD0; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_TEST = 0x0B90; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_TEST = 0x0B71; - - -/** - * @const - * @type {number} - */ -goog.webgl.SCISSOR_TEST = 0x0C11; - - -/** - * @const - * @type {number} - */ -goog.webgl.POLYGON_OFFSET_FILL = 0x8037; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_ALPHA_TO_COVERAGE = 0x809E; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_COVERAGE = 0x80A0; - - -/** - * @const - * @type {number} - */ -goog.webgl.NO_ERROR = 0; - - -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_ENUM = 0x0500; - - -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_VALUE = 0x0501; - - -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_OPERATION = 0x0502; - - -/** - * @const - * @type {number} - */ -goog.webgl.OUT_OF_MEMORY = 0x0505; - - -/** - * @const - * @type {number} - */ -goog.webgl.CW = 0x0900; - - -/** - * @const - * @type {number} - */ -goog.webgl.CCW = 0x0901; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINE_WIDTH = 0x0B21; - - -/** - * @const - * @type {number} - */ -goog.webgl.ALIASED_POINT_SIZE_RANGE = 0x846D; - - -/** - * @const - * @type {number} - */ -goog.webgl.ALIASED_LINE_WIDTH_RANGE = 0x846E; - - -/** - * @const - * @type {number} - */ -goog.webgl.CULL_FACE_MODE = 0x0B45; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRONT_FACE = 0x0B46; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_RANGE = 0x0B70; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_WRITEMASK = 0x0B72; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_CLEAR_VALUE = 0x0B73; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_FUNC = 0x0B74; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_CLEAR_VALUE = 0x0B91; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_FUNC = 0x0B92; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_FAIL = 0x0B94; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_PASS_DEPTH_FAIL = 0x0B95; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_PASS_DEPTH_PASS = 0x0B96; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_REF = 0x0B97; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_VALUE_MASK = 0x0B93; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_WRITEMASK = 0x0B98; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_FUNC = 0x8800; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_FAIL = 0x8801; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_REF = 0x8CA3; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_VALUE_MASK = 0x8CA4; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_WRITEMASK = 0x8CA5; - - -/** - * @const - * @type {number} - */ -goog.webgl.VIEWPORT = 0x0BA2; - - -/** - * @const - * @type {number} - */ -goog.webgl.SCISSOR_BOX = 0x0C10; - - -/** - * @const - * @type {number} - */ -goog.webgl.COLOR_CLEAR_VALUE = 0x0C22; - - -/** - * @const - * @type {number} - */ -goog.webgl.COLOR_WRITEMASK = 0x0C23; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_ALIGNMENT = 0x0CF5; - - -/** - * @const - * @type {number} - */ -goog.webgl.PACK_ALIGNMENT = 0x0D05; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_TEXTURE_SIZE = 0x0D33; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VIEWPORT_DIMS = 0x0D3A; - - -/** - * @const - * @type {number} - */ -goog.webgl.SUBPIXEL_BITS = 0x0D50; - - -/** - * @const - * @type {number} - */ -goog.webgl.RED_BITS = 0x0D52; - - -/** - * @const - * @type {number} - */ -goog.webgl.GREEN_BITS = 0x0D53; - - -/** - * @const - * @type {number} - */ -goog.webgl.BLUE_BITS = 0x0D54; - - -/** - * @const - * @type {number} - */ -goog.webgl.ALPHA_BITS = 0x0D55; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_BITS = 0x0D56; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BITS = 0x0D57; - - -/** - * @const - * @type {number} - */ -goog.webgl.POLYGON_OFFSET_UNITS = 0x2A00; - - -/** - * @const - * @type {number} - */ -goog.webgl.POLYGON_OFFSET_FACTOR = 0x8038; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_BINDING_2D = 0x8069; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_BUFFERS = 0x80A8; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLES = 0x80A9; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_COVERAGE_VALUE = 0x80AA; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_COVERAGE_INVERT = 0x80AB; - - -/** - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_TEXTURE_FORMATS = 0x86A3; - - -/** - * @const - * @type {number} - */ -goog.webgl.DONT_CARE = 0x1100; - - -/** - * @const - * @type {number} - */ -goog.webgl.FASTEST = 0x1101; - - -/** - * @const - * @type {number} - */ -goog.webgl.NICEST = 0x1102; - - -/** - * @const - * @type {number} - */ -goog.webgl.GENERATE_MIPMAP_HINT = 0x8192; - - -/** - * @const - * @type {number} - */ -goog.webgl.BYTE = 0x1400; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_BYTE = 0x1401; - - -/** - * @const - * @type {number} - */ -goog.webgl.SHORT = 0x1402; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT = 0x1403; - - -/** - * @const - * @type {number} - */ -goog.webgl.INT = 0x1404; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_INT = 0x1405; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT = 0x1406; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_COMPONENT = 0x1902; - - -/** - * @const - * @type {number} - */ -goog.webgl.ALPHA = 0x1906; - - -/** - * @const - * @type {number} - */ -goog.webgl.RGB = 0x1907; - - -/** - * @const - * @type {number} - */ -goog.webgl.RGBA = 0x1908; - - -/** - * @const - * @type {number} - */ -goog.webgl.LUMINANCE = 0x1909; - - -/** - * @const - * @type {number} - */ -goog.webgl.LUMINANCE_ALPHA = 0x190A; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT_4_4_4_4 = 0x8033; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT_5_5_5_1 = 0x8034; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT_5_6_5 = 0x8363; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAGMENT_SHADER = 0x8B30; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_SHADER = 0x8B31; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VERTEX_ATTRIBS = 0x8869; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VARYING_VECTORS = 0x8DFC; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_TEXTURE_IMAGE_UNITS = 0x8872; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; - - -/** - * @const - * @type {number} - */ -goog.webgl.SHADER_TYPE = 0x8B4F; - - -/** - * @const - * @type {number} - */ -goog.webgl.DELETE_STATUS = 0x8B80; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINK_STATUS = 0x8B82; - - -/** - * @const - * @type {number} - */ -goog.webgl.VALIDATE_STATUS = 0x8B83; - - -/** - * @const - * @type {number} - */ -goog.webgl.ATTACHED_SHADERS = 0x8B85; - - -/** - * @const - * @type {number} - */ -goog.webgl.ACTIVE_UNIFORMS = 0x8B86; - - -/** - * @const - * @type {number} - */ -goog.webgl.ACTIVE_ATTRIBUTES = 0x8B89; - - -/** - * @const - * @type {number} - */ -goog.webgl.SHADING_LANGUAGE_VERSION = 0x8B8C; - - -/** - * @const - * @type {number} - */ -goog.webgl.CURRENT_PROGRAM = 0x8B8D; - - -/** - * @const - * @type {number} - */ -goog.webgl.NEVER = 0x0200; - - -/** - * @const - * @type {number} - */ -goog.webgl.LESS = 0x0201; - - -/** - * @const - * @type {number} - */ -goog.webgl.EQUAL = 0x0202; - - -/** - * @const - * @type {number} - */ -goog.webgl.LEQUAL = 0x0203; - - -/** - * @const - * @type {number} - */ -goog.webgl.GREATER = 0x0204; - - -/** - * @const - * @type {number} - */ -goog.webgl.NOTEQUAL = 0x0205; - - -/** - * @const - * @type {number} - */ -goog.webgl.GEQUAL = 0x0206; - - -/** - * @const - * @type {number} - */ -goog.webgl.ALWAYS = 0x0207; - - -/** - * @const - * @type {number} - */ -goog.webgl.KEEP = 0x1E00; - - -/** - * @const - * @type {number} - */ -goog.webgl.REPLACE = 0x1E01; - - -/** - * @const - * @type {number} - */ -goog.webgl.INCR = 0x1E02; - - -/** - * @const - * @type {number} - */ -goog.webgl.DECR = 0x1E03; - - -/** - * @const - * @type {number} - */ -goog.webgl.INVERT = 0x150A; - - -/** - * @const - * @type {number} - */ -goog.webgl.INCR_WRAP = 0x8507; - - -/** - * @const - * @type {number} - */ -goog.webgl.DECR_WRAP = 0x8508; - - -/** - * @const - * @type {number} - */ -goog.webgl.VENDOR = 0x1F00; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERER = 0x1F01; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERSION = 0x1F02; - - -/** - * @const - * @type {number} - */ -goog.webgl.NEAREST = 0x2600; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINEAR = 0x2601; - - -/** - * @const - * @type {number} - */ -goog.webgl.NEAREST_MIPMAP_NEAREST = 0x2700; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINEAR_MIPMAP_NEAREST = 0x2701; - - -/** - * @const - * @type {number} - */ -goog.webgl.NEAREST_MIPMAP_LINEAR = 0x2702; - - -/** - * @const - * @type {number} - */ -goog.webgl.LINEAR_MIPMAP_LINEAR = 0x2703; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_MAG_FILTER = 0x2800; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_MIN_FILTER = 0x2801; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_WRAP_S = 0x2802; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_WRAP_T = 0x2803; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_2D = 0x0DE1; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE = 0x1702; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP = 0x8513; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_BINDING_CUBE_MAP = 0x8514; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE0 = 0x84C0; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE1 = 0x84C1; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE2 = 0x84C2; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE3 = 0x84C3; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE4 = 0x84C4; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE5 = 0x84C5; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE6 = 0x84C6; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE7 = 0x84C7; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE8 = 0x84C8; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE9 = 0x84C9; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE10 = 0x84CA; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE11 = 0x84CB; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE12 = 0x84CC; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE13 = 0x84CD; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE14 = 0x84CE; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE15 = 0x84CF; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE16 = 0x84D0; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE17 = 0x84D1; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE18 = 0x84D2; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE19 = 0x84D3; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE20 = 0x84D4; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE21 = 0x84D5; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE22 = 0x84D6; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE23 = 0x84D7; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE24 = 0x84D8; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE25 = 0x84D9; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE26 = 0x84DA; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE27 = 0x84DB; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE28 = 0x84DC; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE29 = 0x84DD; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE30 = 0x84DE; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE31 = 0x84DF; - - -/** - * @const - * @type {number} - */ -goog.webgl.ACTIVE_TEXTURE = 0x84E0; - - -/** - * @const - * @type {number} - */ -goog.webgl.REPEAT = 0x2901; - - -/** - * @const - * @type {number} - */ -goog.webgl.CLAMP_TO_EDGE = 0x812F; - - -/** - * @const - * @type {number} - */ -goog.webgl.MIRRORED_REPEAT = 0x8370; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_VEC2 = 0x8B50; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_VEC3 = 0x8B51; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_VEC4 = 0x8B52; - - -/** - * @const - * @type {number} - */ -goog.webgl.INT_VEC2 = 0x8B53; - - -/** - * @const - * @type {number} - */ -goog.webgl.INT_VEC3 = 0x8B54; - - -/** - * @const - * @type {number} - */ -goog.webgl.INT_VEC4 = 0x8B55; - - -/** - * @const - * @type {number} - */ -goog.webgl.BOOL = 0x8B56; - - -/** - * @const - * @type {number} - */ -goog.webgl.BOOL_VEC2 = 0x8B57; - - -/** - * @const - * @type {number} - */ -goog.webgl.BOOL_VEC3 = 0x8B58; - - -/** - * @const - * @type {number} - */ -goog.webgl.BOOL_VEC4 = 0x8B59; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_MAT2 = 0x8B5A; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_MAT3 = 0x8B5B; - - -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_MAT4 = 0x8B5C; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLER_2D = 0x8B5E; - - -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLER_CUBE = 0x8B60; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; - - -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; - - -/** - * @const - * @type {number} - */ -goog.webgl.COMPILE_STATUS = 0x8B81; - - -/** - * @const - * @type {number} - */ -goog.webgl.LOW_FLOAT = 0x8DF0; - - -/** - * @const - * @type {number} - */ -goog.webgl.MEDIUM_FLOAT = 0x8DF1; - - -/** - * @const - * @type {number} - */ -goog.webgl.HIGH_FLOAT = 0x8DF2; - - -/** - * @const - * @type {number} - */ -goog.webgl.LOW_INT = 0x8DF3; - - -/** - * @const - * @type {number} - */ -goog.webgl.MEDIUM_INT = 0x8DF4; - - -/** - * @const - * @type {number} - */ -goog.webgl.HIGH_INT = 0x8DF5; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER = 0x8D40; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER = 0x8D41; - - -/** - * @const - * @type {number} - */ -goog.webgl.RGBA4 = 0x8056; - - -/** - * @const - * @type {number} - */ -goog.webgl.RGB5_A1 = 0x8057; - - -/** - * @const - * @type {number} - */ -goog.webgl.RGB565 = 0x8D62; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_COMPONENT16 = 0x81A5; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_INDEX = 0x1901; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_INDEX8 = 0x8D48; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_STENCIL = 0x84F9; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_WIDTH = 0x8D42; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_HEIGHT = 0x8D43; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_RED_SIZE = 0x8D50; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_GREEN_SIZE = 0x8D51; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_BLUE_SIZE = 0x8D52; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_ALPHA_SIZE = 0x8D53; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_DEPTH_SIZE = 0x8D54; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_STENCIL_SIZE = 0x8D55; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3; - - -/** - * @const - * @type {number} - */ -goog.webgl.COLOR_ATTACHMENT0 = 0x8CE0; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_ATTACHMENT = 0x8D00; - - -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_ATTACHMENT = 0x8D20; - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_STENCIL_ATTACHMENT = 0x821A; - - -/** - * @const - * @type {number} - */ -goog.webgl.NONE = 0; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_COMPLETE = 0x8CD5; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_UNSUPPORTED = 0x8CDD; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_BINDING = 0x8CA6; - - -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_BINDING = 0x8CA7; - - -/** - * @const - * @type {number} - */ -goog.webgl.MAX_RENDERBUFFER_SIZE = 0x84E8; - - -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_FRAMEBUFFER_OPERATION = 0x0506; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_FLIP_Y_WEBGL = 0x9240; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; - - -/** - * @const - * @type {number} - */ -goog.webgl.CONTEXT_LOST_WEBGL = 0x9242; - - -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; - - -/** - * @const - * @type {number} - */ -goog.webgl.BROWSER_DEFAULT_WEBGL = 0x9244; - - -/** - * From the OES_texture_half_float extension. - * http://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/ - * @const - * @type {number} - */ -goog.webgl.HALF_FLOAT_OES = 0x8D61; - - -/** - * From the OES_standard_derivatives extension. - * http://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/ - * @const - * @type {number} - */ -goog.webgl.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B; - - -/** - * From the OES_vertex_array_object extension. - * http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ - * @const - * @type {number} - */ -goog.webgl.VERTEX_ARRAY_BINDING_OES = 0x85B5; - - -/** - * From the WEBGL_debug_renderer_info extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/ - * @const - * @type {number} - */ -goog.webgl.UNMASKED_VENDOR_WEBGL = 0x9245; - - -/** - * From the WEBGL_debug_renderer_info extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/ - * @const - * @type {number} - */ -goog.webgl.UNMASKED_RENDERER_WEBGL = 0x9246; - - -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; - - -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; - - -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; - - -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; - - -/** - * From the EXT_texture_filter_anisotropic extension. - * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/ - * @const - * @type {number} - */ -goog.webgl.TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; - - -/** - * From the EXT_texture_filter_anisotropic extension. - * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/ - * @const - * @type {number} - */ -goog.webgl.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; - -goog.provide('ol.webgl.Fragment'); -goog.provide('ol.webgl.Shader'); -goog.provide('ol.webgl.Vertex'); -goog.provide('ol.webgl.shader'); - -goog.require('goog.functions'); -goog.require('goog.webgl'); -goog.require('ol.webgl'); - - - -/** - * @constructor - * @param {string} source Source. - * @struct - */ -ol.webgl.Shader = function(source) { - - /** - * @private - * @type {string} - */ - this.source_ = source; - -}; - - -/** - * @return {number} Type. - */ -ol.webgl.Shader.prototype.getType = goog.abstractMethod; - - -/** - * @return {string} Source. - */ -ol.webgl.Shader.prototype.getSource = function() { - return this.source_; -}; - - -/** - * @return {boolean} Is animated? - */ -ol.webgl.Shader.prototype.isAnimated = goog.functions.FALSE; - - - -/** - * @constructor - * @extends {ol.webgl.Shader} - * @param {string} source Source. - * @struct - */ -ol.webgl.shader.Fragment = function(source) { - goog.base(this, source); -}; -goog.inherits(ol.webgl.shader.Fragment, ol.webgl.Shader); - - -/** - * @inheritDoc - */ -ol.webgl.shader.Fragment.prototype.getType = function() { - return goog.webgl.FRAGMENT_SHADER; -}; - - - -/** - * @constructor - * @extends {ol.webgl.Shader} - * @param {string} source Source. - * @struct - */ -ol.webgl.shader.Vertex = function(source) { - goog.base(this, source); -}; -goog.inherits(ol.webgl.shader.Vertex, ol.webgl.Shader); - - -/** - * @inheritDoc - */ -ol.webgl.shader.Vertex.prototype.getType = function() { - return goog.webgl.VERTEX_SHADER; -}; - -// This file is automatically generated, do not edit -goog.provide('ol.render.webgl.imagereplay.shader.Default'); -goog.provide('ol.render.webgl.imagereplay.shader.Default.Locations'); -goog.provide('ol.render.webgl.imagereplay.shader.DefaultFragment'); -goog.provide('ol.render.webgl.imagereplay.shader.DefaultVertex'); - -goog.require('ol.webgl.shader'); - - - -/** - * @constructor - * @extends {ol.webgl.shader.Fragment} - * @struct - */ -ol.render.webgl.imagereplay.shader.DefaultFragment = function() { - goog.base(this, ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE); -}; -goog.inherits(ol.render.webgl.imagereplay.shader.DefaultFragment, ol.webgl.shader.Fragment); -goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultFragment); - - -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultFragment.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'; - - -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultFragment.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;}'; - - -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE = goog.DEBUG ? - ol.render.webgl.imagereplay.shader.DefaultFragment.DEBUG_SOURCE : - ol.render.webgl.imagereplay.shader.DefaultFragment.OPTIMIZED_SOURCE; - - - -/** - * @constructor - * @extends {ol.webgl.shader.Vertex} - * @struct - */ -ol.render.webgl.imagereplay.shader.DefaultVertex = function() { - goog.base(this, ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE); -}; -goog.inherits(ol.render.webgl.imagereplay.shader.DefaultVertex, ol.webgl.shader.Vertex); -goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultVertex); - - -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultVertex.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.);\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + offsets;\n v_texCoord = a_texCoord;\n v_opacity = a_opacity;\n}\n\n\n'; - - -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultVertex.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.);gl_Position=h*vec4(c,0.,1.)+offsets;a=d;b=f;}'; - - -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE = goog.DEBUG ? - ol.render.webgl.imagereplay.shader.DefaultVertex.DEBUG_SOURCE : - ol.render.webgl.imagereplay.shader.DefaultVertex.OPTIMIZED_SOURCE; - - - -/** - * @constructor - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLProgram} program Program. - * @struct - */ -ol.render.webgl.imagereplay.shader.Default.Locations = function(gl, program) { - - /** - * @type {WebGLUniformLocation} - */ - this.u_image = gl.getUniformLocation( - program, goog.DEBUG ? 'u_image' : 'l'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_offsetRotateMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_offsetRotateMatrix' : 'j'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_offsetScaleMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_offsetScaleMatrix' : 'i'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_opacity = gl.getUniformLocation( - program, goog.DEBUG ? 'u_opacity' : 'k'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_projectionMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_projectionMatrix' : 'h'); - - /** - * @type {number} - */ - this.a_offsets = gl.getAttribLocation( - program, goog.DEBUG ? 'a_offsets' : 'e'); - - /** - * @type {number} - */ - this.a_opacity = gl.getAttribLocation( - program, goog.DEBUG ? 'a_opacity' : 'f'); - - /** - * @type {number} - */ - this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'c'); - - /** - * @type {number} - */ - this.a_rotateWithView = gl.getAttribLocation( - program, goog.DEBUG ? 'a_rotateWithView' : 'g'); - - /** - * @type {number} - */ - this.a_texCoord = gl.getAttribLocation( - program, goog.DEBUG ? 'a_texCoord' : 'd'); -}; - -goog.provide('ol.webgl.Buffer'); - -goog.require('goog.webgl'); -goog.require('ol'); - - -/** - * @enum {number} - */ -ol.webgl.BufferUsage = { - STATIC_DRAW: goog.webgl.STATIC_DRAW, - STREAM_DRAW: goog.webgl.STREAM_DRAW, - DYNAMIC_DRAW: goog.webgl.DYNAMIC_DRAW -}; - - - -/** - * @constructor - * @param {Array.<number>=} opt_arr Array. - * @param {number=} opt_usage Usage. - * @struct - */ -ol.webgl.Buffer = function(opt_arr, opt_usage) { - - /** - * @private - * @type {Array.<number>} - */ - this.arr_ = opt_arr !== undefined ? opt_arr : []; - - /** - * @private - * @type {number} - */ - this.usage_ = opt_usage !== undefined ? - opt_usage : ol.webgl.BufferUsage.STATIC_DRAW; - -}; - - -/** - * @return {Array.<number>} Array. - */ -ol.webgl.Buffer.prototype.getArray = function() { - return this.arr_; -}; - - -/** - * @return {number} Usage. - */ -ol.webgl.Buffer.prototype.getUsage = function() { - return this.usage_; -}; - -goog.provide('ol.webgl.Context'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.log'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.array'); -goog.require('ol.webgl.Buffer'); -goog.require('ol.webgl.WebGLContextEventType'); - - -/** - * @typedef {{buf: ol.webgl.Buffer, - * buffer: WebGLBuffer}} - */ -ol.webgl.BufferCacheEntry; - - - -/** - * @classdesc - * A WebGL context for accessing low-level WebGL capabilities. - * - * @constructor - * @extends {goog.events.EventTarget} - * @param {HTMLCanvasElement} canvas Canvas. - * @param {WebGLRenderingContext} gl GL. - */ -ol.webgl.Context = function(canvas, gl) { - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = canvas; - - /** - * @private - * @type {WebGLRenderingContext} - */ - this.gl_ = gl; - - /** - * @private - * @type {Object.<number, ol.webgl.BufferCacheEntry>} - */ - this.bufferCache_ = {}; - - /** - * @private - * @type {Object.<number, WebGLShader>} - */ - this.shaderCache_ = {}; - - /** - * @private - * @type {Object.<string, WebGLProgram>} - */ - this.programCache_ = {}; - - /** - * @private - * @type {WebGLProgram} - */ - this.currentProgram_ = null; - - /** - * @private - * @type {WebGLFramebuffer} - */ - this.hitDetectionFramebuffer_ = null; - - /** - * @private - * @type {WebGLTexture} - */ - this.hitDetectionTexture_ = null; - - /** - * @private - * @type {WebGLRenderbuffer} - */ - this.hitDetectionRenderbuffer_ = null; - - /** - * @type {boolean} - */ - this.hasOESElementIndexUint = ol.array.includes( - ol.WEBGL_EXTENSIONS, 'OES_element_index_uint'); - - // use the OES_element_index_uint extension if available - if (this.hasOESElementIndexUint) { - var ext = gl.getExtension('OES_element_index_uint'); - goog.asserts.assert(ext, - 'Failed to get extension "OES_element_index_uint"'); - } - - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST, - this.handleWebGLContextLost, false, this); - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED, - this.handleWebGLContextRestored, false, this); - -}; - - -/** - * Just bind the buffer if it's in the cache. Otherwise create - * the WebGL buffer, bind it, populate it, and add an entry to - * the cache. - * @param {number} target Target. - * @param {ol.webgl.Buffer} buf Buffer. - */ -ol.webgl.Context.prototype.bindBuffer = function(target, buf) { - var gl = this.getGL(); - var arr = buf.getArray(); - var bufferKey = goog.getUid(buf); - if (bufferKey in this.bufferCache_) { - var bufferCacheEntry = this.bufferCache_[bufferKey]; - gl.bindBuffer(target, bufferCacheEntry.buffer); - } else { - var buffer = gl.createBuffer(); - gl.bindBuffer(target, buffer); - goog.asserts.assert(target == goog.webgl.ARRAY_BUFFER || - target == goog.webgl.ELEMENT_ARRAY_BUFFER, - 'target is supposed to be an ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER'); - var /** @type {ArrayBufferView} */ arrayBuffer; - if (target == goog.webgl.ARRAY_BUFFER) { - arrayBuffer = new Float32Array(arr); - } else if (target == goog.webgl.ELEMENT_ARRAY_BUFFER) { - arrayBuffer = this.hasOESElementIndexUint ? - new Uint32Array(arr) : new Uint16Array(arr); - } else { - goog.asserts.fail(); - } - gl.bufferData(target, arrayBuffer, buf.getUsage()); - this.bufferCache_[bufferKey] = { - buf: buf, - buffer: buffer - }; - } -}; - - -/** - * @param {ol.webgl.Buffer} buf Buffer. - */ -ol.webgl.Context.prototype.deleteBuffer = function(buf) { - var gl = this.getGL(); - var bufferKey = goog.getUid(buf); - goog.asserts.assert(bufferKey in this.bufferCache_, - 'attempted to delete uncached buffer'); - var bufferCacheEntry = this.bufferCache_[bufferKey]; - if (!gl.isContextLost()) { - gl.deleteBuffer(bufferCacheEntry.buffer); - } - delete this.bufferCache_[bufferKey]; -}; - - -/** - * @inheritDoc - */ -ol.webgl.Context.prototype.disposeInternal = function() { - var gl = this.getGL(); - if (!gl.isContextLost()) { - goog.object.forEach(this.bufferCache_, function(bufferCacheEntry) { - gl.deleteBuffer(bufferCacheEntry.buffer); - }); - goog.object.forEach(this.programCache_, function(program) { - gl.deleteProgram(program); - }); - goog.object.forEach(this.shaderCache_, function(shader) { - gl.deleteShader(shader); - }); - // delete objects for hit-detection - gl.deleteFramebuffer(this.hitDetectionFramebuffer_); - gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_); - gl.deleteTexture(this.hitDetectionTexture_); - } -}; - - -/** - * @return {HTMLCanvasElement} Canvas. - */ -ol.webgl.Context.prototype.getCanvas = function() { - return this.canvas_; -}; - - -/** - * Get the WebGL rendering context - * @return {WebGLRenderingContext} The rendering context. - * @api - */ -ol.webgl.Context.prototype.getGL = function() { - return this.gl_; -}; - - -/** - * Get the frame buffer for hit detection. - * @return {WebGLFramebuffer} The hit detection frame buffer. - */ -ol.webgl.Context.prototype.getHitDetectionFramebuffer = function() { - if (!this.hitDetectionFramebuffer_) { - this.initHitDetectionFramebuffer_(); - } - return this.hitDetectionFramebuffer_; -}; - - -/** - * Get shader from the cache if it's in the cache. Otherwise, create - * the WebGL shader, compile it, and add entry to cache. - * @param {ol.webgl.Shader} shaderObject Shader object. - * @return {WebGLShader} Shader. - */ -ol.webgl.Context.prototype.getShader = function(shaderObject) { - var shaderKey = goog.getUid(shaderObject); - if (shaderKey in this.shaderCache_) { - return this.shaderCache_[shaderKey]; - } else { - var gl = this.getGL(); - var shader = gl.createShader(shaderObject.getType()); - gl.shaderSource(shader, shaderObject.getSource()); - gl.compileShader(shader); - if (goog.DEBUG) { - if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) && - !gl.isContextLost()) { - goog.log.error(this.logger_, gl.getShaderInfoLog(shader)); - } - } - goog.asserts.assert( - gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) || - gl.isContextLost(), - 'illegal state, shader not compiled or context lost'); - this.shaderCache_[shaderKey] = shader; - return shader; - } -}; - - -/** - * Get the program from the cache if it's in the cache. Otherwise create - * the WebGL program, attach the shaders to it, and add an entry to the - * cache. - * @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader. - * @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader. - * @return {WebGLProgram} Program. - */ -ol.webgl.Context.prototype.getProgram = function( - fragmentShaderObject, vertexShaderObject) { - var programKey = - goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject); - if (programKey in this.programCache_) { - return this.programCache_[programKey]; - } else { - var gl = this.getGL(); - var program = gl.createProgram(); - gl.attachShader(program, this.getShader(fragmentShaderObject)); - gl.attachShader(program, this.getShader(vertexShaderObject)); - gl.linkProgram(program); - if (goog.DEBUG) { - if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) && - !gl.isContextLost()) { - goog.log.error(this.logger_, gl.getProgramInfoLog(program)); - } - } - goog.asserts.assert( - gl.getProgramParameter(program, goog.webgl.LINK_STATUS) || - gl.isContextLost(), - 'illegal state, shader not linked or context lost'); - this.programCache_[programKey] = program; - return program; - } -}; - - -/** - * FIXME empy description for jsdoc - */ -ol.webgl.Context.prototype.handleWebGLContextLost = function() { - goog.object.clear(this.bufferCache_); - goog.object.clear(this.shaderCache_); - goog.object.clear(this.programCache_); - this.currentProgram_ = null; - this.hitDetectionFramebuffer_ = null; - this.hitDetectionTexture_ = null; - this.hitDetectionRenderbuffer_ = null; -}; - - -/** - * FIXME empy description for jsdoc - */ -ol.webgl.Context.prototype.handleWebGLContextRestored = function() { -}; - - -/** - * Creates a 1x1 pixel framebuffer for the hit-detection. - * @private - */ -ol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() { - var gl = this.gl_; - var framebuffer = gl.createFramebuffer(); - gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); - - var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1); - var renderbuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1); - gl.framebufferTexture2D( - gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, - gl.RENDERBUFFER, renderbuffer); - - gl.bindTexture(gl.TEXTURE_2D, null); - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - this.hitDetectionFramebuffer_ = framebuffer; - this.hitDetectionTexture_ = texture; - this.hitDetectionRenderbuffer_ = renderbuffer; -}; - - -/** - * Use a program. If the program is already in use, this will return `false`. - * @param {WebGLProgram} program Program. - * @return {boolean} Changed. - * @api - */ -ol.webgl.Context.prototype.useProgram = function(program) { - if (program == this.currentProgram_) { - return false; - } else { - var gl = this.getGL(); - gl.useProgram(program); - this.currentProgram_ = program; - return true; - } -}; - - -/** - * @private - * @type {goog.log.Logger} - */ -ol.webgl.Context.prototype.logger_ = goog.log.getLogger('ol.webgl.Context'); - - -/** - * @param {WebGLRenderingContext} gl WebGL rendering context. - * @param {number=} opt_wrapS wrapS. - * @param {number=} opt_wrapT wrapT. - * @return {WebGLTexture} - * @private - */ -ol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) { - var texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - - if (opt_wrapS !== undefined) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, opt_wrapS); - } - if (opt_wrapT !== undefined) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, opt_wrapT); - } - - return texture; -}; - - -/** - * @param {WebGLRenderingContext} gl WebGL rendering context. - * @param {number} width Width. - * @param {number} height Height. - * @param {number=} opt_wrapS wrapS. - * @param {number=} opt_wrapT wrapT. - * @return {WebGLTexture} - */ -ol.webgl.Context.createEmptyTexture = function( - gl, width, height, opt_wrapS, opt_wrapT) { - var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT); - gl.texImage2D( - gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, - null); - - return texture; -}; - - -/** - * @param {WebGLRenderingContext} gl WebGL rendering context. - * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image. - * @param {number=} opt_wrapS wrapS. - * @param {number=} opt_wrapT wrapT. - * @return {WebGLTexture} - */ -ol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) { - var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT); - gl.texImage2D( - gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - - return texture; -}; - -goog.provide('ol.render.webgl.ImageReplay'); -goog.provide('ol.render.webgl.ReplayGroup'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('goog.vec.Mat4'); -goog.require('ol.extent'); -goog.require('ol.render.IReplayGroup'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.webgl.imagereplay.shader.Default'); -goog.require('ol.render.webgl.imagereplay.shader.Default.Locations'); -goog.require('ol.render.webgl.imagereplay.shader.DefaultFragment'); -goog.require('ol.render.webgl.imagereplay.shader.DefaultVertex'); -goog.require('ol.vec.Mat4'); -goog.require('ol.webgl.Buffer'); -goog.require('ol.webgl.Context'); - - - -/** - * @constructor - * @extends {ol.render.VectorContext} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @protected - * @struct - */ -ol.render.webgl.ImageReplay = function(tolerance, maxExtent) { - goog.base(this); - - /** - * @type {number|undefined} - * @private - */ - this.anchorX_ = undefined; - - /** - * @type {number|undefined} - * @private - */ - this.anchorY_ = undefined; - - /** - * The origin of the coordinate system for the point coordinates sent to - * the GPU. To eliminate jitter caused by precision problems in the GPU - * we use the "Rendering Relative to Eye" technique described in the "3D - * Engine Design for Virtual Globes" book. - * @private - * @type {ol.Coordinate} - */ - this.origin_ = ol.extent.getCenter(maxExtent); - - /** - * @type {Array.<number>} - * @private - */ - this.groupIndices_ = []; - - /** - * @type {Array.<number>} - * @private - */ - this.hitDetectionGroupIndices_ = []; - - /** - * @type {number|undefined} - * @private - */ - this.height_ = undefined; - - /** - * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} - * @private - */ - this.images_ = []; - - /** - * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} - * @private - */ - this.hitDetectionImages_ = []; - - /** - * @type {number|undefined} - * @private - */ - this.imageHeight_ = undefined; - - /** - * @type {number|undefined} - * @private - */ - this.imageWidth_ = undefined; - - /** - * @type {Array.<number>} - * @private - */ - this.indices_ = []; - - /** - * @type {ol.webgl.Buffer} - * @private - */ - this.indicesBuffer_ = null; - - /** - * @private - * @type {ol.render.webgl.imagereplay.shader.Default.Locations} - */ - this.defaultLocations_ = null; - - /** - * @private - * @type {number|undefined} - */ - this.opacity_ = undefined; - - /** - * @type {!goog.vec.Mat4.Number} - * @private - */ - this.offsetRotateMatrix_ = goog.vec.Mat4.createNumberIdentity(); - - /** - * @type {!goog.vec.Mat4.Number} - * @private - */ - this.offsetScaleMatrix_ = goog.vec.Mat4.createNumberIdentity(); - - /** - * @type {number|undefined} - * @private - */ - this.originX_ = undefined; - - /** - * @type {number|undefined} - * @private - */ - this.originY_ = undefined; - - /** - * @type {!goog.vec.Mat4.Number} - * @private - */ - this.projectionMatrix_ = goog.vec.Mat4.createNumberIdentity(); - - /** - * @private - * @type {boolean|undefined} - */ - this.rotateWithView_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.rotation_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.scale_ = undefined; - - /** - * @type {Array.<WebGLTexture>} - * @private - */ - this.textures_ = []; - - /** - * @type {Array.<WebGLTexture>} - * @private - */ - this.hitDetectionTextures_ = []; - - /** - * @type {Array.<number>} - * @private - */ - this.vertices_ = []; - - /** - * @type {ol.webgl.Buffer} - * @private - */ - this.verticesBuffer_ = null; - - /** - * Start index per feature (the index). - * @type {Array.<number>} - * @private - */ - this.startIndices_ = []; - - /** - * Start index per feature (the feature). - * @type {Array.<ol.Feature>} - * @private - */ - this.startIndicesFeature_ = []; - - /** - * @type {number|undefined} - * @private - */ - this.width_ = undefined; -}; -goog.inherits(ol.render.webgl.ImageReplay, ol.render.VectorContext); - - -/** - * @param {ol.webgl.Context} context WebGL context. - * @return {function()} Delete resources function. - */ -ol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction = - function(context) { - // We only delete our stuff here. The shaders and the program may - // be used by other ImageReplay instances (for other layers). And - // they will be deleted when disposing of the ol.webgl.Context - // object. - goog.asserts.assert(this.verticesBuffer_, - 'verticesBuffer must not be null'); - goog.asserts.assert(this.indicesBuffer_, - 'indicesBuffer must not be null'); - var verticesBuffer = this.verticesBuffer_; - var indicesBuffer = this.indicesBuffer_; - var textures = this.textures_; - var hitDetectionTextures = this.hitDetectionTextures_; - var gl = context.getGL(); - return function() { - if (!gl.isContextLost()) { - var i, ii; - for (i = 0, ii = textures.length; i < ii; ++i) { - gl.deleteTexture(textures[i]); - } - for (i = 0, ii = hitDetectionTextures.length; i < ii; ++i) { - gl.deleteTexture(hitDetectionTextures[i]); - } - } - context.deleteBuffer(verticesBuffer); - context.deleteBuffer(indicesBuffer); - }; -}; - - -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.drawAsync = goog.abstractMethod; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} My end. - * @private - */ -ol.render.webgl.ImageReplay.prototype.drawCoordinates_ = - function(flatCoordinates, offset, end, stride) { - goog.asserts.assert(this.anchorX_ !== undefined, 'anchorX is defined'); - goog.asserts.assert(this.anchorY_ !== undefined, 'anchorY is defined'); - goog.asserts.assert(this.height_ !== undefined, 'height is defined'); - goog.asserts.assert(this.imageHeight_ !== undefined, - 'imageHeight is defined'); - goog.asserts.assert(this.imageWidth_ !== undefined, 'imageWidth is defined'); - goog.asserts.assert(this.opacity_ !== undefined, 'opacity is defined'); - goog.asserts.assert(this.originX_ !== undefined, 'originX is defined'); - goog.asserts.assert(this.originY_ !== undefined, 'originY is defined'); - goog.asserts.assert(this.rotateWithView_ !== undefined, - 'rotateWithView is defined'); - goog.asserts.assert(this.rotation_ !== undefined, 'rotation is defined'); - goog.asserts.assert(this.scale_ !== undefined, 'scale is defined'); - goog.asserts.assert(this.width_ !== undefined, 'width is defined'); - var anchorX = this.anchorX_; - var anchorY = this.anchorY_; - var height = this.height_; - var imageHeight = this.imageHeight_; - var imageWidth = this.imageWidth_; - var opacity = this.opacity_; - var originX = this.originX_; - var originY = this.originY_; - var rotateWithView = this.rotateWithView_ ? 1.0 : 0.0; - var rotation = this.rotation_; - var scale = this.scale_; - var width = this.width_; - var cos = Math.cos(rotation); - var sin = Math.sin(rotation); - var numIndices = this.indices_.length; - var numVertices = this.vertices_.length; - var i, n, offsetX, offsetY, x, y; - for (i = offset; i < end; i += stride) { - x = flatCoordinates[i] - this.origin_[0]; - y = flatCoordinates[i + 1] - this.origin_[1]; - - // There are 4 vertices per [x, y] point, one for each corner of the - // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if - // WebGL supported Geometry Shaders (which can emit new vertices), but that - // is not currently the case. - // - // And each vertex includes 8 values: the x and y coordinates, the x and - // y offsets used to calculate the position of the corner, the u and - // v texture coordinates for the corner, the opacity, and whether the - // the image should be rotated with the view (rotateWithView). - - n = numVertices / 8; - - // bottom-left corner - offsetX = -scale * anchorX; - offsetY = -scale * (height - anchorY); - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = originX / imageWidth; - this.vertices_[numVertices++] = (originY + height) / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; - - // bottom-right corner - offsetX = scale * (width - anchorX); - offsetY = -scale * (height - anchorY); - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = (originX + width) / imageWidth; - this.vertices_[numVertices++] = (originY + height) / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; - - // top-right corner - offsetX = scale * (width - anchorX); - offsetY = scale * anchorY; - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = (originX + width) / imageWidth; - this.vertices_[numVertices++] = originY / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; - - // top-left corner - offsetX = -scale * anchorX; - offsetY = scale * anchorY; - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = originX / imageWidth; - this.vertices_[numVertices++] = originY / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; - - this.indices_[numIndices++] = n; - this.indices_[numIndices++] = n + 1; - this.indices_[numIndices++] = n + 2; - this.indices_[numIndices++] = n; - this.indices_[numIndices++] = n + 2; - this.indices_[numIndices++] = n + 3; - } - - return numVertices; -}; - - -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.drawMultiPointGeometry = - function(multiPointGeometry, feature) { - this.startIndices_.push(this.indices_.length); - this.startIndicesFeature_.push(feature); - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); -}; - - -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.drawPointGeometry = - function(pointGeometry, feature) { - this.startIndices_.push(this.indices_.length); - this.startIndicesFeature_.push(feature); - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); -}; - - -/** - * @param {ol.webgl.Context} context Context. - */ -ol.render.webgl.ImageReplay.prototype.finish = function(context) { - var gl = context.getGL(); - - this.groupIndices_.push(this.indices_.length); - goog.asserts.assert(this.images_.length === this.groupIndices_.length, - 'number of images and groupIndices match'); - this.hitDetectionGroupIndices_.push(this.indices_.length); - goog.asserts.assert(this.hitDetectionImages_.length === - this.hitDetectionGroupIndices_.length, - 'number of hitDetectionImages and hitDetectionGroupIndices match'); - - // create, bind, and populate the vertices buffer - this.verticesBuffer_ = new ol.webgl.Buffer(this.vertices_); - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); - - var indices = this.indices_; - var bits = context.hasOESElementIndexUint ? 32 : 16; - goog.asserts.assert(indices[indices.length - 1] < Math.pow(2, bits), - 'Too large element index detected [%s] (OES_element_index_uint "%s")', - indices[indices.length - 1], context.hasOESElementIndexUint); - - // create, bind, and populate the indices buffer - this.indicesBuffer_ = new ol.webgl.Buffer(indices); - context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); - - // create textures - /** @type {Object.<string, WebGLTexture>} */ - var texturePerImage = {}; - - this.createTextures_(this.textures_, this.images_, texturePerImage, gl); - goog.asserts.assert(this.textures_.length === this.groupIndices_.length, - 'number of textures and groupIndices match'); - - this.createTextures_(this.hitDetectionTextures_, this.hitDetectionImages_, - texturePerImage, gl); - goog.asserts.assert(this.hitDetectionTextures_.length === - this.hitDetectionGroupIndices_.length, - 'number of hitDetectionTextures and hitDetectionGroupIndices match'); - - this.anchorX_ = undefined; - this.anchorY_ = undefined; - this.height_ = undefined; - this.images_ = null; - this.hitDetectionImages_ = null; - this.imageHeight_ = undefined; - this.imageWidth_ = undefined; - this.indices_ = null; - this.opacity_ = undefined; - this.originX_ = undefined; - this.originY_ = undefined; - this.rotateWithView_ = undefined; - this.rotation_ = undefined; - this.scale_ = undefined; - this.vertices_ = null; - this.width_ = undefined; -}; - - -/** - * @private - * @param {Array.<WebGLTexture>} textures Textures. - * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images - * Images. - * @param {Object.<string, WebGLTexture>} texturePerImage Texture cache. - * @param {WebGLRenderingContext} gl Gl. - */ -ol.render.webgl.ImageReplay.prototype.createTextures_ = - function(textures, images, texturePerImage, gl) { - goog.asserts.assert(textures.length === 0, - 'upon creation, textures is empty'); - - var texture, image, uid, i; - var ii = images.length; - for (i = 0; i < ii; ++i) { - image = images[i]; - - uid = goog.getUid(image).toString(); - if (goog.object.containsKey(texturePerImage, uid)) { - texture = texturePerImage[uid]; - } else { - texture = ol.webgl.Context.createTexture( - gl, image, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); - texturePerImage[uid] = texture; - } - textures[i] = texture; - } -}; - - -/** - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ImageReplay.prototype.replay = function(context, - center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash, - featureCallback, oneByOne, opt_hitExtent) { - var gl = context.getGL(); - - // bind the vertices buffer - goog.asserts.assert(this.verticesBuffer_, - 'verticesBuffer must not be null'); - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); - - // bind the indices buffer - goog.asserts.assert(this.indicesBuffer_, - 'indecesBuffer must not be null'); - context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); - - // get the program - var fragmentShader = - ol.render.webgl.imagereplay.shader.DefaultFragment.getInstance(); - var vertexShader = - ol.render.webgl.imagereplay.shader.DefaultVertex.getInstance(); - var program = context.getProgram(fragmentShader, vertexShader); - - // get the locations - var locations; - if (!this.defaultLocations_) { - locations = - new ol.render.webgl.imagereplay.shader.Default.Locations(gl, program); - this.defaultLocations_ = locations; - } else { - locations = this.defaultLocations_; - } - - // use the program (FIXME: use the return value) - context.useProgram(program); - - // enable the vertex attrib arrays - gl.enableVertexAttribArray(locations.a_position); - gl.vertexAttribPointer(locations.a_position, 2, goog.webgl.FLOAT, - false, 32, 0); - - gl.enableVertexAttribArray(locations.a_offsets); - gl.vertexAttribPointer(locations.a_offsets, 2, goog.webgl.FLOAT, - false, 32, 8); - - gl.enableVertexAttribArray(locations.a_texCoord); - gl.vertexAttribPointer(locations.a_texCoord, 2, goog.webgl.FLOAT, - false, 32, 16); - - gl.enableVertexAttribArray(locations.a_opacity); - gl.vertexAttribPointer(locations.a_opacity, 1, goog.webgl.FLOAT, - false, 32, 24); - - gl.enableVertexAttribArray(locations.a_rotateWithView); - gl.vertexAttribPointer(locations.a_rotateWithView, 1, goog.webgl.FLOAT, - false, 32, 28); - - // set the "uniform" values - var projectionMatrix = this.projectionMatrix_; - ol.vec.Mat4.makeTransform2D(projectionMatrix, - 0.0, 0.0, - 2 / (resolution * size[0]), - 2 / (resolution * size[1]), - -rotation, - -(center[0] - this.origin_[0]), -(center[1] - this.origin_[1])); - - var offsetScaleMatrix = this.offsetScaleMatrix_; - goog.vec.Mat4.makeScale(offsetScaleMatrix, 2 / size[0], 2 / size[1], 1); - - var offsetRotateMatrix = this.offsetRotateMatrix_; - goog.vec.Mat4.makeIdentity(offsetRotateMatrix); - if (rotation !== 0) { - goog.vec.Mat4.rotateZ(offsetRotateMatrix, -rotation); - } - - gl.uniformMatrix4fv(locations.u_projectionMatrix, false, projectionMatrix); - gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false, offsetScaleMatrix); - gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false, - offsetRotateMatrix); - gl.uniform1f(locations.u_opacity, opacity); - - // draw! - var result; - if (featureCallback === undefined) { - this.drawReplay_(gl, context, skippedFeaturesHash, - this.textures_, this.groupIndices_); - } else { - // draw feature by feature for the hit-detection - result = this.drawHitDetectionReplay_(gl, context, skippedFeaturesHash, - featureCallback, oneByOne, opt_hitExtent); - } - - // disable the vertex attrib arrays - gl.disableVertexAttribArray(locations.a_position); - gl.disableVertexAttribArray(locations.a_offsets); - gl.disableVertexAttribArray(locations.a_texCoord); - gl.disableVertexAttribArray(locations.a_opacity); - gl.disableVertexAttribArray(locations.a_rotateWithView); - - return result; -}; - - -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.<WebGLTexture>} textures Textures. - * @param {Array.<number>} groupIndices Texture group indices. - */ -ol.render.webgl.ImageReplay.prototype.drawReplay_ = - function(gl, context, skippedFeaturesHash, textures, groupIndices) { - goog.asserts.assert(textures.length === groupIndices.length, - 'number of textures and groupIndeces match'); - var elementType = context.hasOESElementIndexUint ? - goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; - var elementSize = context.hasOESElementIndexUint ? 4 : 2; - - if (!goog.object.isEmpty(skippedFeaturesHash)) { - this.drawReplaySkipping_( - gl, skippedFeaturesHash, textures, groupIndices, - elementType, elementSize); - } else { - var i, ii, start; - for (i = 0, ii = textures.length, start = 0; i < ii; ++i) { - gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]); - var end = groupIndices[i]; - this.drawElements_(gl, start, end, elementType, elementSize); - start = end; - } - } -}; - - -/** - * Draw the replay while paying attention to skipped features. - * - * This functions creates groups of features that can be drawn to together, - * so that the number of `drawElements` calls is minimized. - * - * For example given the following texture groups: - * - * Group 1: A B C - * Group 2: D [E] F G - * - * If feature E should be skipped, the following `drawElements` calls will be - * made: - * - * drawElements with feature A, B and C - * drawElements with feature D - * drawElements with feature F and G - * - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.<WebGLTexture>} textures Textures. - * @param {Array.<number>} groupIndices Texture group indices. - * @param {number} elementType Element type. - * @param {number} elementSize Element Size. - */ -ol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ = - function(gl, skippedFeaturesHash, textures, groupIndices, - elementType, elementSize) { - var featureIndex = 0; - - var i, ii; - for (i = 0, ii = textures.length; i < ii; ++i) { - gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]); - var groupStart = (i > 0) ? groupIndices[i - 1] : 0; - var groupEnd = groupIndices[i]; - - var start = groupStart; - var end = groupStart; - while (featureIndex < this.startIndices_.length && - this.startIndices_[featureIndex] <= groupEnd) { - var feature = this.startIndicesFeature_[featureIndex]; - - var featureUid = goog.getUid(feature).toString(); - if (skippedFeaturesHash[featureUid] !== undefined) { - // feature should be skipped - if (start !== end) { - // draw the features so far - this.drawElements_(gl, start, end, elementType, elementSize); - } - // continue with the next feature - start = (featureIndex === this.startIndices_.length - 1) ? - groupEnd : this.startIndices_[featureIndex + 1]; - end = start; - } else { - // the feature is not skipped, augment the end index - end = (featureIndex === this.startIndices_.length - 1) ? - groupEnd : this.startIndices_[featureIndex + 1]; - } - featureIndex++; - } - - if (start !== end) { - // draw the remaining features (in case there was no skipped feature - // in this texture group, all features of a group are drawn together) - this.drawElements_(gl, start, end, elementType, elementSize); - } - } -}; - - -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {number} start Start index. - * @param {number} end End index. - * @param {number} elementType Element type. - * @param {number} elementSize Element Size. - */ -ol.render.webgl.ImageReplay.prototype.drawElements_ = function( - gl, start, end, elementType, elementSize) { - var numItems = end - start; - var offsetInBytes = start * elementSize; - gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes); -}; - - -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplay_ = - function(gl, context, skippedFeaturesHash, featureCallback, oneByOne, - opt_hitExtent) { - if (!oneByOne) { - // draw all hit-detection features in "once" (by texture group) - return this.drawHitDetectionReplayAll_(gl, context, - skippedFeaturesHash, featureCallback); - } else { - // draw hit-detection features one by one - return this.drawHitDetectionReplayOneByOne_(gl, context, - skippedFeaturesHash, featureCallback, opt_hitExtent); - } -}; - - -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayAll_ = - function(gl, context, skippedFeaturesHash, featureCallback) { - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - this.drawReplay_(gl, context, skippedFeaturesHash, - this.hitDetectionTextures_, this.hitDetectionGroupIndices_); - - var result = featureCallback(null); - if (result) { - return result; - } else { - return undefined; - } -}; - - -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne_ = - function(gl, context, skippedFeaturesHash, featureCallback, - opt_hitExtent) { - goog.asserts.assert(this.hitDetectionTextures_.length === - this.hitDetectionGroupIndices_.length, - 'number of hitDetectionTextures and hitDetectionGroupIndices match'); - var elementType = context.hasOESElementIndexUint ? - goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; - var elementSize = context.hasOESElementIndexUint ? 4 : 2; - - var i, groupStart, start, end, feature, featureUid; - var featureIndex = this.startIndices_.length - 1; - for (i = this.hitDetectionTextures_.length - 1; i >= 0; --i) { - gl.bindTexture(goog.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]); - groupStart = (i > 0) ? this.hitDetectionGroupIndices_[i - 1] : 0; - end = this.hitDetectionGroupIndices_[i]; - - // draw all features for this texture group - while (featureIndex >= 0 && - this.startIndices_[featureIndex] >= groupStart) { - start = this.startIndices_[featureIndex]; - feature = this.startIndicesFeature_[featureIndex]; - featureUid = goog.getUid(feature).toString(); - - if (skippedFeaturesHash[featureUid] === undefined && - feature.getGeometry() && - (opt_hitExtent === undefined || ol.extent.intersects( - /** @type {Array<number>} */ (opt_hitExtent), - feature.getGeometry().getExtent()))) { - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - this.drawElements_(gl, start, end, elementType, elementSize); - - var result = featureCallback(feature); - if (result) { - return result; - } - } - - end = start; - featureIndex--; - } - } - return undefined; -}; - - -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.setFillStrokeStyle = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) { - var anchor = imageStyle.getAnchor(); - var image = imageStyle.getImage(1); - var imageSize = imageStyle.getImageSize(); - var hitDetectionImage = imageStyle.getHitDetectionImage(1); - var hitDetectionImageSize = imageStyle.getHitDetectionImageSize(); - var opacity = imageStyle.getOpacity(); - var origin = imageStyle.getOrigin(); - var rotateWithView = imageStyle.getRotateWithView(); - var rotation = imageStyle.getRotation(); - var size = imageStyle.getSize(); - var scale = imageStyle.getScale(); - goog.asserts.assert(anchor, 'imageStyle anchor is not null'); - goog.asserts.assert(image, 'imageStyle image is not null'); - goog.asserts.assert(imageSize, - 'imageStyle imageSize is not null'); - goog.asserts.assert(hitDetectionImage, - 'imageStyle hitDetectionImage is not null'); - goog.asserts.assert(hitDetectionImageSize, - 'imageStyle hitDetectionImageSize is not null'); - goog.asserts.assert(opacity !== undefined, 'imageStyle opacity is defined'); - goog.asserts.assert(origin, 'imageStyle origin is not null'); - goog.asserts.assert(rotateWithView !== undefined, - 'imageStyle rotateWithView is defined'); - goog.asserts.assert(rotation !== undefined, 'imageStyle rotation is defined'); - goog.asserts.assert(size, 'imageStyle size is not null'); - goog.asserts.assert(scale !== undefined, 'imageStyle scale is defined'); - - var currentImage; - if (this.images_.length === 0) { - this.images_.push(image); - } else { - currentImage = this.images_[this.images_.length - 1]; - if (goog.getUid(currentImage) != goog.getUid(image)) { - this.groupIndices_.push(this.indices_.length); - goog.asserts.assert(this.groupIndices_.length === this.images_.length, - 'number of groupIndices and images match'); - this.images_.push(image); - } - } - - if (this.hitDetectionImages_.length === 0) { - this.hitDetectionImages_.push(hitDetectionImage); - } else { - currentImage = - this.hitDetectionImages_[this.hitDetectionImages_.length - 1]; - if (goog.getUid(currentImage) != goog.getUid(hitDetectionImage)) { - this.hitDetectionGroupIndices_.push(this.indices_.length); - goog.asserts.assert(this.hitDetectionGroupIndices_.length === - this.hitDetectionImages_.length, - 'number of hitDetectionGroupIndices and hitDetectionImages match'); - this.hitDetectionImages_.push(hitDetectionImage); - } - } - - this.anchorX_ = anchor[0]; - this.anchorY_ = anchor[1]; - this.height_ = size[1]; - this.imageHeight_ = imageSize[1]; - this.imageWidth_ = imageSize[0]; - this.opacity_ = opacity; - this.originX_ = origin[0]; - this.originY_ = origin[1]; - this.rotation_ = rotation; - this.rotateWithView_ = rotateWithView; - this.scale_ = scale; - this.width_ = size[0]; -}; - - - -/** - * @constructor - * @implements {ol.render.IReplayGroup} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @param {number=} opt_renderBuffer Render buffer. - * @struct - */ -ol.render.webgl.ReplayGroup = function( - tolerance, maxExtent, opt_renderBuffer) { - - /** - * @type {ol.Extent} - * @private - */ - this.maxExtent_ = maxExtent; - - /** - * @type {number} - * @private - */ - this.tolerance_ = tolerance; - - /** - * @type {number|undefined} - * @private - */ - this.renderBuffer_ = opt_renderBuffer; - - /** - * ImageReplay only is supported at this point. - * @type {Object.<ol.render.ReplayType, ol.render.webgl.ImageReplay>} - * @private - */ - this.replays_ = {}; - -}; - - -/** - * @param {ol.webgl.Context} context WebGL context. - * @return {function()} Delete resources function. - */ -ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = - function(context) { - var functions = []; - var replayKey; - for (replayKey in this.replays_) { - functions.push( - this.replays_[replayKey].getDeleteResourcesFunction(context)); - } - return goog.functions.sequence.apply(null, functions); -}; - - -/** - * @param {ol.webgl.Context} context Context. - */ -ol.render.webgl.ReplayGroup.prototype.finish = function(context) { - var replayKey; - for (replayKey in this.replays_) { - this.replays_[replayKey].finish(context); - } -}; - - -/** - * @inheritDoc - */ -ol.render.webgl.ReplayGroup.prototype.getReplay = - function(zIndex, replayType) { - var replay = this.replays_[replayType]; - if (replay === undefined) { - var constructor = ol.render.webgl.BATCH_CONSTRUCTORS_[replayType]; - goog.asserts.assert(constructor !== undefined, - replayType + - ' constructor missing from ol.render.webgl.BATCH_CONSTRUCTORS_'); - replay = new constructor(this.tolerance_, this.maxExtent_); - this.replays_[replayType] = replay; - } - return replay; -}; - - -/** - * @inheritDoc - */ -ol.render.webgl.ReplayGroup.prototype.isEmpty = function() { - return goog.object.isEmpty(this.replays_); -}; - - -/** - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - */ -ol.render.webgl.ReplayGroup.prototype.replay = function(context, - center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash) { - var i, ii, replay; - for (i = 0, ii = ol.render.REPLAY_ORDER.length; i < ii; ++i) { - replay = this.replays_[ol.render.REPLAY_ORDER[i]]; - if (replay !== undefined) { - replay.replay(context, - center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash, - undefined, false); - } - } -}; - - -/** - * @private - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context, - center, resolution, rotation, size, pixelRatio, opacity, - skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) { - var i, replay, result; - for (i = ol.render.REPLAY_ORDER.length - 1; i >= 0; --i) { - replay = this.replays_[ol.render.REPLAY_ORDER[i]]; - if (replay !== undefined) { - result = replay.replay(context, - center, resolution, rotation, size, pixelRatio, opacity, - skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent); - if (result) { - return result; - } - } - } - return undefined; -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} callback Feature callback. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( - coordinate, context, center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash, - callback) { - var gl = context.getGL(); - gl.bindFramebuffer( - gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); - - - /** - * @type {ol.Extent} - */ - var hitExtent; - if (this.renderBuffer_ !== undefined) { - // build an extent around the coordinate, so that only features that - // intersect this extent are checked - hitExtent = ol.extent.buffer( - ol.extent.createOrUpdateFromCoordinate(coordinate), - resolution * this.renderBuffer_); - } - - return this.replayHitDetection_(context, - coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_, - pixelRatio, opacity, skippedFeaturesHash, - /** - * @param {ol.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - var imageData = new Uint8Array(4); - gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData); - - if (imageData[3] > 0) { - var result = callback(feature); - if (result) { - return result; - } - } - }, true, hitExtent); -}; - - -/** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @return {boolean} Is there a feature at the given coordinate? - */ -ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function( - coordinate, context, center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash) { - var gl = context.getGL(); - gl.bindFramebuffer( - gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); - - var hasFeature = this.replayHitDetection_(context, - coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_, - pixelRatio, opacity, skippedFeaturesHash, - /** - * @param {ol.Feature} feature Feature. - * @return {boolean} Is there a feature? - */ - function(feature) { - var imageData = new Uint8Array(4); - gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData); - return imageData[3] > 0; - }, false); - - return hasFeature !== undefined; -}; - - -/** - * @const - * @private - * @type {Object.<ol.render.ReplayType, - * function(new: ol.render.webgl.ImageReplay, number, - * ol.Extent)>} - */ -ol.render.webgl.BATCH_CONSTRUCTORS_ = { - 'Image': ol.render.webgl.ImageReplay -}; - - -/** - * @const - * @private - * @type {Array.<number>} - */ -ol.render.webgl.HIT_DETECTION_SIZE_ = [1, 1]; - -goog.provide('ol.render.webgl.Immediate'); -goog.require('goog.array'); -goog.require('ol.extent'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.webgl.ImageReplay'); -goog.require('ol.render.webgl.ReplayGroup'); - - - -/** - * @constructor - * @extends {ol.render.VectorContext} - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {ol.Extent} extent Extent. - * @param {number} pixelRatio Pixel ratio. - * @struct - */ -ol.render.webgl.Immediate = function(context, - center, resolution, rotation, size, extent, pixelRatio) { - goog.base(this); - - /** - * @private - */ - this.context_ = context; - - /** - * @private - */ - this.center_ = center; - - /** - * @private - */ - this.extent_ = extent; - - /** - * @private - */ - this.pixelRatio_ = pixelRatio; - - /** - * @private - */ - this.size_ = size; - - /** - * @private - */ - this.rotation_ = rotation; - - /** - * @private - */ - this.resolution_ = resolution; - - /** - * @private - * @type {ol.style.Image} - */ - this.imageStyle_ = null; - - /** - * @private - * @type {!Object.<string, - * Array.<function(ol.render.webgl.Immediate)>>} - */ - this.callbacksByZIndex_ = {}; -}; -goog.inherits(ol.render.webgl.Immediate, ol.render.VectorContext); - - -/** - * FIXME: empty description for jsdoc - */ -ol.render.webgl.Immediate.prototype.flush = function() { - /** @type {Array.<number>} */ - var zs = Object.keys(this.callbacksByZIndex_).map(Number); - goog.array.sort(zs); - var i, ii, callbacks, j, jj; - for (i = 0, ii = zs.length; i < ii; ++i) { - callbacks = this.callbacksByZIndex_[zs[i].toString()]; - for (j = 0, jj = callbacks.length; j < jj; ++j) { - callbacks[j](this); - } - } -}; - - -/** - * Register a function to be called for rendering at a given zIndex. The - * function will be called asynchronously. The callback will receive a - * reference to {@link ol.render.canvas.Immediate} context for drawing. - * @param {number} zIndex Z index. - * @param {function(ol.render.webgl.Immediate)} callback Callback. - * @api - */ -ol.render.webgl.Immediate.prototype.drawAsync = function(zIndex, callback) { - var zIndexKey = zIndex.toString(); - var callbacks = this.callbacksByZIndex_[zIndexKey]; - if (callbacks !== undefined) { - callbacks.push(callback); - } else { - this.callbacksByZIndex_[zIndexKey] = [callback]; - } -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawCircleGeometry = - function(circleGeometry, data) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) { - var geometry = style.getGeometryFunction()(feature); - if (!geometry || - !ol.extent.intersects(this.extent_, geometry.getExtent())) { - return; - } - var zIndex = style.getZIndex(); - if (zIndex === undefined) { - zIndex = 0; - } - this.drawAsync(zIndex, function(render) { - render.setFillStrokeStyle(style.getFill(), style.getStroke()); - render.setImageStyle(style.getImage()); - render.setTextStyle(style.getText()); - var type = geometry.getType(); - var renderGeometry = ol.render.webgl.Immediate.GEOMETRY_RENDERERS_[type]; - // Do not assert since all kinds of geometries are not handled yet. - // In spite, render what we support. - if (renderGeometry) { - renderGeometry.call(render, geometry, null); - } - }); -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry = - function(geometryCollectionGeometry, data) { - var geometries = geometryCollectionGeometry.getGeometriesArray(); - var renderers = ol.render.webgl.Immediate.GEOMETRY_RENDERERS_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometry = geometries[i]; - var geometryRenderer = renderers[geometry.getType()]; - // Do not assert since all kinds of geometries are not handled yet. - // In order to support hierarchies, delegate instead what we can to - // valid renderers. - if (geometryRenderer) { - geometryRenderer.call(this, geometry, data); - } - } -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawPointGeometry = - function(pointGeometry, data) { - var context = this.context_; - var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_); - var replay = /** @type {ol.render.webgl.ImageReplay} */ ( - replayGroup.getReplay(0, ol.render.ReplayType.IMAGE)); - replay.setImageStyle(this.imageStyle_); - replay.drawPointGeometry(pointGeometry, data); - replay.finish(context); - // default colors - var opacity = 1; - var skippedFeatures = {}; - var featureCallback; - var oneByOne = false; - replay.replay(this.context_, this.center_, this.resolution_, this.rotation_, - this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback, - oneByOne); - replay.getDeleteResourcesFunction(context)(); -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawLineStringGeometry = - function(lineStringGeometry, data) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawMultiLineStringGeometry = - function(multiLineStringGeometry, data) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawMultiPointGeometry = - function(multiPointGeometry, data) { - var context = this.context_; - var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_); - var replay = /** @type {ol.render.webgl.ImageReplay} */ ( - replayGroup.getReplay(0, ol.render.ReplayType.IMAGE)); - replay.setImageStyle(this.imageStyle_); - replay.drawMultiPointGeometry(multiPointGeometry, data); - replay.finish(context); - var opacity = 1; - var skippedFeatures = {}; - var featureCallback; - var oneByOne = false; - replay.replay(this.context_, this.center_, this.resolution_, this.rotation_, - this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback, - oneByOne); - replay.getDeleteResourcesFunction(context)(); -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawMultiPolygonGeometry = - function(multiPolygonGeometry, data) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawPolygonGeometry = - function(polygonGeometry, data) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.drawText = - function(flatCoordinates, offset, end, stride, geometry, data) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) { - this.imageStyle_ = imageStyle; -}; - - -/** - * @inheritDoc - * @api - */ -ol.render.webgl.Immediate.prototype.setTextStyle = function(textStyle) { -}; - - -/** - * @const - * @private - * @type {Object.<ol.geom.GeometryType, - * function(this: ol.render.webgl.Immediate, - * (ol.geom.Geometry|ol.render.Feature), Object)>} - */ -ol.render.webgl.Immediate.GEOMETRY_RENDERERS_ = { - 'Point': ol.render.webgl.Immediate.prototype.drawPointGeometry, - 'MultiPoint': ol.render.webgl.Immediate.prototype.drawMultiPointGeometry, - 'GeometryCollection': - ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry -}; - -// This file is automatically generated, do not edit -goog.provide('ol.renderer.webgl.map.shader.Default'); -goog.provide('ol.renderer.webgl.map.shader.Default.Locations'); -goog.provide('ol.renderer.webgl.map.shader.DefaultFragment'); -goog.provide('ol.renderer.webgl.map.shader.DefaultVertex'); - -goog.require('ol.webgl.shader'); - - - -/** - * @constructor - * @extends {ol.webgl.shader.Fragment} - * @struct - */ -ol.renderer.webgl.map.shader.DefaultFragment = function() { - goog.base(this, ol.renderer.webgl.map.shader.DefaultFragment.SOURCE); -}; -goog.inherits(ol.renderer.webgl.map.shader.DefaultFragment, ol.webgl.shader.Fragment); -goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultFragment); - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.map.shader.DefaultFragment.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'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.map.shader.DefaultFragment.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;}'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.map.shader.DefaultFragment.SOURCE = goog.DEBUG ? - ol.renderer.webgl.map.shader.DefaultFragment.DEBUG_SOURCE : - ol.renderer.webgl.map.shader.DefaultFragment.OPTIMIZED_SOURCE; - - - -/** - * @constructor - * @extends {ol.webgl.shader.Vertex} - * @struct - */ -ol.renderer.webgl.map.shader.DefaultVertex = function() { - goog.base(this, ol.renderer.webgl.map.shader.DefaultVertex.SOURCE); -}; -goog.inherits(ol.renderer.webgl.map.shader.DefaultVertex, ol.webgl.shader.Vertex); -goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultVertex); - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.map.shader.DefaultVertex.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'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.map.shader.DefaultVertex.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;}'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.map.shader.DefaultVertex.SOURCE = goog.DEBUG ? - ol.renderer.webgl.map.shader.DefaultVertex.DEBUG_SOURCE : - ol.renderer.webgl.map.shader.DefaultVertex.OPTIMIZED_SOURCE; - - - -/** - * @constructor - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLProgram} program Program. - * @struct - */ -ol.renderer.webgl.map.shader.Default.Locations = function(gl, program) { - - /** - * @type {WebGLUniformLocation} - */ - this.u_opacity = gl.getUniformLocation( - program, goog.DEBUG ? 'u_opacity' : 'f'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_projectionMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_projectionMatrix' : 'e'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_texCoordMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_texCoordMatrix' : 'd'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_texture = gl.getUniformLocation( - program, goog.DEBUG ? 'u_texture' : 'g'); - - /** - * @type {number} - */ - this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'b'); - - /** - * @type {number} - */ - this.a_texCoord = gl.getAttribLocation( - program, goog.DEBUG ? 'a_texCoord' : 'c'); -}; - -goog.provide('ol.renderer.webgl.Layer'); - -goog.require('goog.vec.Mat4'); -goog.require('goog.webgl'); -goog.require('ol.layer.Layer'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.webgl.Immediate'); -goog.require('ol.renderer.Layer'); -goog.require('ol.renderer.webgl.map.shader.Default'); -goog.require('ol.renderer.webgl.map.shader.Default.Locations'); -goog.require('ol.renderer.webgl.map.shader.DefaultFragment'); -goog.require('ol.renderer.webgl.map.shader.DefaultVertex'); -goog.require('ol.webgl.Buffer'); -goog.require('ol.webgl.Context'); - - - -/** - * @constructor - * @extends {ol.renderer.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Layer} layer Layer. - */ -ol.renderer.webgl.Layer = function(mapRenderer, layer) { - - goog.base(this, layer); - - /** - * @protected - * @type {ol.renderer.webgl.Map} - */ - this.mapRenderer = mapRenderer; - - /** - * @private - * @type {ol.webgl.Buffer} - */ - this.arrayBuffer_ = new ol.webgl.Buffer([ - -1, -1, 0, 0, - 1, -1, 1, 0, - -1, 1, 0, 1, - 1, 1, 1, 1 - ]); - - /** - * @protected - * @type {WebGLTexture} - */ - this.texture = null; - - /** - * @protected - * @type {WebGLFramebuffer} - */ - this.framebuffer = null; - - /** - * @protected - * @type {number|undefined} - */ - this.framebufferDimension = undefined; - - /** - * @protected - * @type {!goog.vec.Mat4.Number} - */ - this.texCoordMatrix = goog.vec.Mat4.createNumber(); - - /** - * @protected - * @type {!goog.vec.Mat4.Number} - */ - this.projectionMatrix = goog.vec.Mat4.createNumberIdentity(); - - /** - * @private - * @type {ol.renderer.webgl.map.shader.Default.Locations} - */ - this.defaultLocations_ = null; - -}; -goog.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer); - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {number} framebufferDimension Framebuffer dimension. - * @protected - */ -ol.renderer.webgl.Layer.prototype.bindFramebuffer = - function(frameState, framebufferDimension) { - - var gl = this.mapRenderer.getGL(); - - if (this.framebufferDimension === undefined || - this.framebufferDimension != framebufferDimension) { - - frameState.postRenderFunctions.push( - goog.partial( - /** - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLFramebuffer} framebuffer Framebuffer. - * @param {WebGLTexture} texture Texture. - */ - function(gl, framebuffer, texture) { - if (!gl.isContextLost()) { - gl.deleteFramebuffer(framebuffer); - gl.deleteTexture(texture); - } - }, gl, this.framebuffer, this.texture)); - - var texture = ol.webgl.Context.createEmptyTexture( - gl, framebufferDimension, framebufferDimension); - - var framebuffer = gl.createFramebuffer(); - gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer); - gl.framebufferTexture2D(goog.webgl.FRAMEBUFFER, - goog.webgl.COLOR_ATTACHMENT0, goog.webgl.TEXTURE_2D, texture, 0); - - this.texture = texture; - this.framebuffer = framebuffer; - this.framebufferDimension = framebufferDimension; - - } else { - gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, this.framebuffer); - } - -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {ol.webgl.Context} context Context. - */ -ol.renderer.webgl.Layer.prototype.composeFrame = - function(frameState, layerState, context) { - - this.dispatchComposeEvent_( - ol.render.EventType.PRECOMPOSE, context, frameState); - - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.arrayBuffer_); - - var gl = context.getGL(); - - var fragmentShader = - ol.renderer.webgl.map.shader.DefaultFragment.getInstance(); - var vertexShader = ol.renderer.webgl.map.shader.DefaultVertex.getInstance(); - - var program = context.getProgram(fragmentShader, vertexShader); - - var locations; - if (!this.defaultLocations_) { - locations = - new ol.renderer.webgl.map.shader.Default.Locations(gl, program); - this.defaultLocations_ = locations; - } else { - locations = this.defaultLocations_; - } - - if (context.useProgram(program)) { - gl.enableVertexAttribArray(locations.a_position); - gl.vertexAttribPointer( - locations.a_position, 2, goog.webgl.FLOAT, false, 16, 0); - gl.enableVertexAttribArray(locations.a_texCoord); - gl.vertexAttribPointer( - locations.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); - gl.uniform1i(locations.u_texture, 0); - } - - gl.uniformMatrix4fv( - locations.u_texCoordMatrix, false, this.getTexCoordMatrix()); - gl.uniformMatrix4fv(locations.u_projectionMatrix, false, - this.getProjectionMatrix()); - gl.uniform1f(locations.u_opacity, layerState.opacity); - gl.bindTexture(goog.webgl.TEXTURE_2D, this.getTexture()); - gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); - - this.dispatchComposeEvent_( - ol.render.EventType.POSTCOMPOSE, context, frameState); - -}; - - -/** - * @param {ol.render.EventType} type Event type. - * @param {ol.webgl.Context} context WebGL context. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ = - function(type, context, frameState) { - var layer = this.getLayer(); - if (layer.hasListener(type)) { - var viewState = frameState.viewState; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var extent = frameState.extent; - var center = viewState.center; - var rotation = viewState.rotation; - var size = frameState.size; - - var render = new ol.render.webgl.Immediate( - context, center, resolution, rotation, size, extent, pixelRatio); - var composeEvent = new ol.render.Event( - type, layer, render, frameState, null, context); - layer.dispatchEvent(composeEvent); - } -}; - - -/** - * @return {!goog.vec.Mat4.Number} Matrix. - */ -ol.renderer.webgl.Layer.prototype.getTexCoordMatrix = function() { - return this.texCoordMatrix; -}; - - -/** - * @return {WebGLTexture} Texture. - */ -ol.renderer.webgl.Layer.prototype.getTexture = function() { - return this.texture; -}; - - -/** - * @return {!goog.vec.Mat4.Number} Matrix. - */ -ol.renderer.webgl.Layer.prototype.getProjectionMatrix = function() { - return this.projectionMatrix; -}; - - -/** - * Handle webglcontextlost. - */ -ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() { - this.texture = null; - this.framebuffer = null; - this.framebufferDimension = undefined; -}; - - -/** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {ol.webgl.Context} context Context. - * @return {boolean} whether composeFrame should be called. - */ -ol.renderer.webgl.Layer.prototype.prepareFrame = goog.abstractMethod; - -goog.provide('ol.renderer.webgl.ImageLayer'); - -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.vec.Mat4'); -goog.require('goog.webgl'); -goog.require('ol.Coordinate'); -goog.require('ol.Extent'); -goog.require('ol.ImageBase'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.proj'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.source.ImageVector'); -goog.require('ol.vec.Mat4'); -goog.require('ol.webgl.Context'); - - - -/** - * @constructor - * @extends {ol.renderer.webgl.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Image} imageLayer Tile layer. - */ -ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) { - - goog.base(this, mapRenderer, imageLayer); - - /** - * The last rendered image. - * @private - * @type {?ol.ImageBase} - */ - this.image_ = null; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.hitCanvasContext_ = null; - - /** - * @private - * @type {?goog.vec.Mat4.Number} - */ - this.hitTransformationMatrix_ = null; - -}; -goog.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer); - - -/** - * @param {ol.ImageBase} image Image. - * @private - * @return {WebGLTexture} Texture. - */ -ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) { - - // We meet the conditions to work with non-power of two textures. - // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support - // http://learningwebgl.com/blog/?p=2101 - - var imageElement = image.getImage(); - var gl = this.mapRenderer.getGL(); - - return ol.webgl.Context.createTexture( - gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var layer = this.getLayer(); - var source = layer.getSource(); - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var skippedFeatureUids = frameState.skippedFeatureUids; - return source.forEachFeatureAtCoordinate( - coordinate, resolution, rotation, skippedFeatureUids, - - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - return callback.call(thisArg, feature, layer); - }); -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.ImageLayer.prototype.prepareFrame = - function(frameState, layerState, context) { - - var gl = this.mapRenderer.getGL(); - - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewResolution = viewState.resolution; - var viewRotation = viewState.rotation; - - var image = this.image_; - var texture = this.texture; - var imageLayer = this.getLayer(); - goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, - 'layer is an instance of ol.layer.Image'); - var imageSource = imageLayer.getSource(); - - var hints = frameState.viewHints; - - var renderedExtent = frameState.extent; - if (layerState.extent !== undefined) { - renderedExtent = ol.extent.getIntersection( - renderedExtent, layerState.extent); - } - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && - !ol.extent.isEmpty(renderedExtent)) { - var projection = viewState.projection; - if (!ol.ENABLE_RASTER_REPROJECTION) { - var sourceProjection = imageSource.getProjection(); - if (sourceProjection) { - goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), - 'projection and sourceProjection are equivalent'); - projection = sourceProjection; - } - } - var image_ = imageSource.getImage(renderedExtent, viewResolution, - pixelRatio, projection); - if (image_) { - var loaded = this.loadImage(image_); - if (loaded) { - image = image_; - texture = this.createTexture_(image_); - if (this.texture) { - frameState.postRenderFunctions.push( - goog.partial( - /** - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLTexture} texture Texture. - */ - function(gl, texture) { - if (!gl.isContextLost()) { - gl.deleteTexture(texture); - } - }, gl, this.texture)); - } - } - } - } - - if (image) { - goog.asserts.assert(texture, 'texture is truthy'); - - var canvas = this.mapRenderer.getContext().getCanvas(); - - this.updateProjectionMatrix_(canvas.width, canvas.height, - pixelRatio, viewCenter, viewResolution, viewRotation, - image.getExtent()); - this.hitTransformationMatrix_ = null; - - // Translate and scale to flip the Y coord. - var texCoordMatrix = this.texCoordMatrix; - goog.vec.Mat4.makeIdentity(texCoordMatrix); - goog.vec.Mat4.scale(texCoordMatrix, 1, -1, 1); - goog.vec.Mat4.translate(texCoordMatrix, 0, -1, 0); - - this.image_ = image; - this.texture = texture; - - this.updateAttributions(frameState.attributions, image.getAttributions()); - this.updateLogos(frameState, imageSource); - } - - return true; -}; - - -/** - * @param {number} canvasWidth Canvas width. - * @param {number} canvasHeight Canvas height. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Coordinate} viewCenter View center. - * @param {number} viewResolution View resolution. - * @param {number} viewRotation View rotation. - * @param {ol.Extent} imageExtent Image extent. - * @private - */ -ol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = - function(canvasWidth, canvasHeight, pixelRatio, - viewCenter, viewResolution, viewRotation, imageExtent) { - - var canvasExtentWidth = canvasWidth * viewResolution; - var canvasExtentHeight = canvasHeight * viewResolution; - - var projectionMatrix = this.projectionMatrix; - goog.vec.Mat4.makeIdentity(projectionMatrix); - goog.vec.Mat4.scale(projectionMatrix, - pixelRatio * 2 / canvasExtentWidth, - pixelRatio * 2 / canvasExtentHeight, 1); - goog.vec.Mat4.rotateZ(projectionMatrix, -viewRotation); - goog.vec.Mat4.translate(projectionMatrix, - imageExtent[0] - viewCenter[0], - imageExtent[1] - viewCenter[1], - 0); - goog.vec.Mat4.scale(projectionMatrix, - (imageExtent[2] - imageExtent[0]) / 2, - (imageExtent[3] - imageExtent[1]) / 2, - 1); - goog.vec.Mat4.translate(projectionMatrix, 1, 1, 0); - -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState) { - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); - return hasFeature !== undefined; -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.image_ || !this.image_.getImage()) { - return undefined; - } - - if (this.getLayer().getSource() instanceof ol.source.ImageVector) { - // for ImageVector sources use the original hit-detection logic, - // so that for example also transparent polygons are detected - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); - - if (hasFeature) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } else { - var imageSize = - [this.image_.getImage().width, this.image_.getImage().height]; - - if (!this.hitTransformationMatrix_) { - this.hitTransformationMatrix_ = this.getHitTransformationMatrix_( - frameState.size, imageSize); - } - - var pixelOnFrameBuffer = [0, 0]; - ol.vec.Mat4.multVec2( - this.hitTransformationMatrix_, pixel, pixelOnFrameBuffer); - - if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] || - pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) { - // outside the image, no need to check - return undefined; - } - - if (!this.hitCanvasContext_) { - this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); - } - - this.hitCanvasContext_.clearRect(0, 0, 1, 1); - this.hitCanvasContext_.drawImage(this.image_.getImage(), - pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1); - - var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } -}; - - -/** - * The transformation matrix to get the pixel on the image for a - * pixel on the map. - * @param {ol.Size} mapSize - * @param {ol.Size} imageSize - * @return {goog.vec.Mat4.Number} - * @private - */ -ol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ = - function(mapSize, imageSize) { - // the first matrix takes a map pixel, flips the y-axis and scales to - // a range between -1 ... 1 - var mapCoordMatrix = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.makeIdentity(mapCoordMatrix); - goog.vec.Mat4.translate(mapCoordMatrix, -1, -1, 0); - goog.vec.Mat4.scale(mapCoordMatrix, 2 / mapSize[0], 2 / mapSize[1], 1); - goog.vec.Mat4.translate(mapCoordMatrix, 0, mapSize[1], 0); - goog.vec.Mat4.scale(mapCoordMatrix, 1, -1, 1); - - // the second matrix is the inverse of the projection matrix used in the - // shader for drawing - var projectionMatrixInv = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.invert(this.projectionMatrix, projectionMatrixInv); - - // the third matrix scales to the image dimensions and flips the y-axis again - var imageCoordMatrix = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.makeIdentity(imageCoordMatrix); - goog.vec.Mat4.translate(imageCoordMatrix, 0, imageSize[1], 0); - goog.vec.Mat4.scale(imageCoordMatrix, 1, -1, 1); - goog.vec.Mat4.scale(imageCoordMatrix, imageSize[0] / 2, imageSize[1] / 2, 1); - goog.vec.Mat4.translate(imageCoordMatrix, 1, 1, 0); - - var transformMatrix = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.multMat( - imageCoordMatrix, projectionMatrixInv, transformMatrix); - goog.vec.Mat4.multMat( - transformMatrix, mapCoordMatrix, transformMatrix); - - return transformMatrix; -}; - -// This file is automatically generated, do not edit -goog.provide('ol.renderer.webgl.tilelayer.shader'); -goog.provide('ol.renderer.webgl.tilelayer.shader.Locations'); -goog.provide('ol.renderer.webgl.tilelayer.shader.Fragment'); -goog.provide('ol.renderer.webgl.tilelayer.shader.Vertex'); - -goog.require('ol.webgl.shader'); - - - -/** - * @constructor - * @extends {ol.webgl.shader.Fragment} - * @struct - */ -ol.renderer.webgl.tilelayer.shader.Fragment = function() { - goog.base(this, ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE); -}; -goog.inherits(ol.renderer.webgl.tilelayer.shader.Fragment, ol.webgl.shader.Fragment); -goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Fragment); - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.tilelayer.shader.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'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE = goog.DEBUG ? - ol.renderer.webgl.tilelayer.shader.Fragment.DEBUG_SOURCE : - ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE; - - - -/** - * @constructor - * @extends {ol.webgl.shader.Vertex} - * @struct - */ -ol.renderer.webgl.tilelayer.shader.Vertex = function() { - goog.base(this, ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE); -}; -goog.inherits(ol.renderer.webgl.tilelayer.shader.Vertex, ol.webgl.shader.Vertex); -goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Vertex); - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.tilelayer.shader.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'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.tilelayer.shader.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;}'; - - -/** - * @const - * @type {string} - */ -ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE = goog.DEBUG ? - ol.renderer.webgl.tilelayer.shader.Vertex.DEBUG_SOURCE : - ol.renderer.webgl.tilelayer.shader.Vertex.OPTIMIZED_SOURCE; - - - -/** - * @constructor - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLProgram} program Program. - * @struct - */ -ol.renderer.webgl.tilelayer.shader.Locations = function(gl, program) { - - /** - * @type {WebGLUniformLocation} - */ - this.u_texture = gl.getUniformLocation( - program, goog.DEBUG ? 'u_texture' : 'e'); - - /** - * @type {WebGLUniformLocation} - */ - this.u_tileOffset = gl.getUniformLocation( - program, goog.DEBUG ? 'u_tileOffset' : 'd'); - - /** - * @type {number} - */ - this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'b'); - - /** - * @type {number} - */ - this.a_texCoord = gl.getAttribLocation( - program, goog.DEBUG ? 'a_texCoord' : 'c'); -}; - -// FIXME large resolutions lead to too large framebuffers :-( -// FIXME animated shaders! check in redraw - -goog.provide('ol.renderer.webgl.TileLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('goog.vec.Vec4'); -goog.require('goog.webgl'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.extent'); -goog.require('ol.layer.Tile'); -goog.require('ol.math'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.renderer.webgl.tilelayer.shader.Fragment'); -goog.require('ol.renderer.webgl.tilelayer.shader.Locations'); -goog.require('ol.renderer.webgl.tilelayer.shader.Vertex'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); -goog.require('ol.webgl.Buffer'); - - - -/** - * @constructor - * @extends {ol.renderer.webgl.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Tile} tileLayer Tile layer. - */ -ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) { - - goog.base(this, mapRenderer, tileLayer); - - /** - * @private - * @type {ol.webgl.shader.Fragment} - */ - this.fragmentShader_ = - ol.renderer.webgl.tilelayer.shader.Fragment.getInstance(); - - /** - * @private - * @type {ol.webgl.shader.Vertex} - */ - this.vertexShader_ = ol.renderer.webgl.tilelayer.shader.Vertex.getInstance(); - - /** - * @private - * @type {ol.renderer.webgl.tilelayer.shader.Locations} - */ - this.locations_ = null; - - /** - * @private - * @type {ol.webgl.Buffer} - */ - this.renderArrayBuffer_ = new ol.webgl.Buffer([ - 0, 0, 0, 1, - 1, 0, 1, 1, - 0, 1, 0, 0, - 1, 1, 1, 0 - ]); - - /** - * @private - * @type {ol.TileRange} - */ - this.renderedTileRange_ = null; - - /** - * @private - * @type {ol.Extent} - */ - this.renderedFramebufferExtent_ = null; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; - - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; - -}; -goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() { - var context = this.mapRenderer.getContext(); - context.deleteBuffer(this.renderArrayBuffer_); - goog.base(this, 'disposeInternal'); -}; - - -/** - * Create a function that adds loaded tiles to the tile lookup. - * @param {ol.source.Tile} source Tile source. - * @param {ol.proj.Projection} projection Projection of the tiles. - * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded - * tiles by zoom level. - * @return {function(number, ol.TileRange):boolean} A function that can be - * called with a zoom level and a tile range to add loaded tiles to the - * lookup. - * @protected - */ -ol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder = - function(source, projection, tiles) { - var mapRenderer = this.mapRenderer; - - return ( - /** - * @param {number} zoom Zoom level. - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} The tile range is fully loaded. - */ - function(zoom, tileRange) { - return source.forEachLoadedTile(projection, zoom, - tileRange, function(tile) { - var loaded = mapRenderer.isTileTextureLoaded(tile); - if (loaded) { - if (!tiles[zoom]) { - tiles[zoom] = {}; - } - tiles[zoom][tile.tileCoord.toString()] = tile; - } - return loaded; - }); - }); -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() { - goog.base(this, 'handleWebGLContextLost'); - this.locations_ = null; -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.TileLayer.prototype.prepareFrame = - function(frameState, layerState, context) { - - var mapRenderer = this.mapRenderer; - var gl = context.getGL(); - - var viewState = frameState.viewState; - var projection = viewState.projection; - - var tileLayer = this.getLayer(); - goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, - 'layer is an instance of ol.layer.Tile'); - var tileSource = tileLayer.getSource(); - var tileGrid = tileSource.getTileGridForProjection(projection); - var z = tileGrid.getZForResolution(viewState.resolution); - var tileResolution = tileGrid.getResolution(z); - - var tilePixelSize = - tileSource.getTilePixelSize(z, frameState.pixelRatio, projection); - var pixelRatio = tilePixelSize[0] / - ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; - var tilePixelResolution = tileResolution / pixelRatio; - var tileGutter = tileSource.getGutter(); - - var center = viewState.center; - var extent; - if (tileResolution == viewState.resolution) { - center = this.snapCenterToPixel(center, tileResolution, frameState.size); - extent = ol.extent.getForViewAndSize( - center, tileResolution, viewState.rotation, frameState.size); - } else { - extent = frameState.extent; - } - var tileRange = tileGrid.getTileRangeForExtentAndResolution( - extent, tileResolution); - - var framebufferExtent; - if (this.renderedTileRange_ && - this.renderedTileRange_.equals(tileRange) && - this.renderedRevision_ == tileSource.getRevision()) { - framebufferExtent = this.renderedFramebufferExtent_; - } else { - - var tileRangeSize = tileRange.getSize(); - - var maxDimension = Math.max( - tileRangeSize[0] * tilePixelSize[0], - tileRangeSize[1] * tilePixelSize[1]); - var framebufferDimension = ol.math.roundUpToPowerOfTwo(maxDimension); - var framebufferExtentDimension = tilePixelResolution * framebufferDimension; - var origin = tileGrid.getOrigin(z); - var minX = origin[0] + - tileRange.minX * tilePixelSize[0] * tilePixelResolution; - var minY = origin[1] + - tileRange.minY * tilePixelSize[1] * tilePixelResolution; - framebufferExtent = [ - minX, minY, - minX + framebufferExtentDimension, minY + framebufferExtentDimension - ]; - - this.bindFramebuffer(frameState, framebufferDimension); - gl.viewport(0, 0, framebufferDimension, framebufferDimension); - - gl.clearColor(0, 0, 0, 0); - gl.clear(goog.webgl.COLOR_BUFFER_BIT); - gl.disable(goog.webgl.BLEND); - - var program = context.getProgram(this.fragmentShader_, this.vertexShader_); - context.useProgram(program); - if (!this.locations_) { - this.locations_ = - new ol.renderer.webgl.tilelayer.shader.Locations(gl, program); - } - - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.renderArrayBuffer_); - gl.enableVertexAttribArray(this.locations_.a_position); - gl.vertexAttribPointer( - this.locations_.a_position, 2, goog.webgl.FLOAT, false, 16, 0); - gl.enableVertexAttribArray(this.locations_.a_texCoord); - gl.vertexAttribPointer( - this.locations_.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); - gl.uniform1i(this.locations_.u_texture, 0); - - /** - * @type {Object.<number, Object.<string, ol.Tile>>} - */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - - var findLoadedTiles = this.createLoadedTileFinder( - tileSource, projection, tilesToDrawByZ); - - var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); - var allTilesLoaded = true; - var tmpExtent = ol.extent.createEmpty(); - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, drawable, fullyLoaded, tile, tileState; - var x, y, tileExtent; - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - if (layerState.extent !== undefined) { - // ignore tiles outside layer extent - tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); - if (!ol.extent.intersects(tileExtent, layerState.extent)) { - continue; - } - } - tileState = tile.getState(); - drawable = tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - tileState == ol.TileState.ERROR && !useInterimTilesOnError; - if (!drawable && tile.interimTile) { - tile = tile.interimTile; - } - goog.asserts.assert(tile); - tileState = tile.getState(); - if (tileState == ol.TileState.LOADED) { - if (mapRenderer.isTileTextureLoaded(tile)) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } - } else if (tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && - !useInterimTilesOnError)) { - continue; - } - - allTilesLoaded = false; - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } - - } - - } - - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - goog.array.sort(zs); - var u_tileOffset = goog.vec.Vec4.createFloat32(); - var i, ii, sx, sy, tileKey, tilesToDraw, tx, ty; - for (i = 0, ii = zs.length; i < ii; ++i) { - tilesToDraw = tilesToDrawByZ[zs[i]]; - for (tileKey in tilesToDraw) { - tile = tilesToDraw[tileKey]; - tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); - sx = 2 * (tileExtent[2] - tileExtent[0]) / - framebufferExtentDimension; - sy = 2 * (tileExtent[3] - tileExtent[1]) / - framebufferExtentDimension; - tx = 2 * (tileExtent[0] - framebufferExtent[0]) / - framebufferExtentDimension - 1; - ty = 2 * (tileExtent[1] - framebufferExtent[1]) / - framebufferExtentDimension - 1; - goog.vec.Vec4.setFromValues(u_tileOffset, sx, sy, tx, ty); - gl.uniform4fv(this.locations_.u_tileOffset, u_tileOffset); - mapRenderer.bindTileTexture(tile, tilePixelSize, - tileGutter * pixelRatio, goog.webgl.LINEAR, goog.webgl.LINEAR); - gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); - } - } - - if (allTilesLoaded) { - this.renderedTileRange_ = tileRange; - this.renderedFramebufferExtent_ = framebufferExtent; - this.renderedRevision_ = tileSource.getRevision(); - } else { - this.renderedTileRange_ = null; - this.renderedFramebufferExtent_ = null; - this.renderedRevision_ = -1; - frameState.animate = true; - } - - } - - this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); - var tileTextureQueue = mapRenderer.getTileTextureQueue(); - this.manageTilePyramid( - frameState, tileSource, tileGrid, pixelRatio, projection, extent, z, - tileLayer.getPreload(), - /** - * @param {ol.Tile} tile Tile. - */ - function(tile) { - if (tile.getState() == ol.TileState.LOADED && - !mapRenderer.isTileTextureLoaded(tile) && - !tileTextureQueue.isKeyQueued(tile.getKey())) { - tileTextureQueue.enqueue([ - tile, - tileGrid.getTileCoordCenter(tile.tileCoord), - tileGrid.getResolution(tile.tileCoord[0]), - tilePixelSize, tileGutter * pixelRatio - ]); - } - }, this); - this.scheduleExpireCache(frameState, tileSource); - this.updateLogos(frameState, tileSource); - - var texCoordMatrix = this.texCoordMatrix; - goog.vec.Mat4.makeIdentity(texCoordMatrix); - goog.vec.Mat4.translate(texCoordMatrix, - (center[0] - framebufferExtent[0]) / - (framebufferExtent[2] - framebufferExtent[0]), - (center[1] - framebufferExtent[1]) / - (framebufferExtent[3] - framebufferExtent[1]), - 0); - if (viewState.rotation !== 0) { - goog.vec.Mat4.rotateZ(texCoordMatrix, viewState.rotation); - } - goog.vec.Mat4.scale(texCoordMatrix, - frameState.size[0] * viewState.resolution / - (framebufferExtent[2] - framebufferExtent[0]), - frameState.size[1] * viewState.resolution / - (framebufferExtent[3] - framebufferExtent[1]), - 1); - goog.vec.Mat4.translate(texCoordMatrix, - -0.5, - -0.5, - 0); - - return true; -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.framebuffer) { - return undefined; - } - - var pixelOnMapScaled = [ - pixel[0] / frameState.size[0], - (frameState.size[1] - pixel[1]) / frameState.size[1]]; - - var pixelOnFrameBufferScaled = [0, 0]; - ol.vec.Mat4.multVec2( - this.texCoordMatrix, pixelOnMapScaled, pixelOnFrameBufferScaled); - var pixelOnFrameBuffer = [ - pixelOnFrameBufferScaled[0] * this.framebufferDimension, - pixelOnFrameBufferScaled[1] * this.framebufferDimension]; - - var gl = this.mapRenderer.getContext().getGL(); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); - var imageData = new Uint8Array(4); - gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, - gl.RGBA, gl.UNSIGNED_BYTE, imageData); - - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } -}; - -goog.provide('ol.renderer.webgl.VectorLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('ol.ViewHint'); -goog.require('ol.extent'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.webgl.ReplayGroup'); -goog.require('ol.renderer.vector'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.vec.Mat4'); - - - -/** - * @constructor - * @extends {ol.renderer.webgl.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Vector} vectorLayer Vector layer. - */ -ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) { - - goog.base(this, mapRenderer, vectorLayer); - - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.renderedResolution_ = NaN; - - /** - * @private - * @type {ol.Extent} - */ - this.renderedExtent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {function(ol.Feature, ol.Feature): number|null} - */ - this.renderedRenderOrder_ = null; - - /** - * @private - * @type {ol.render.webgl.ReplayGroup} - */ - this.replayGroup_ = null; - - /** - * The last layer state. - * @private - * @type {?ol.layer.LayerState} - */ - this.layerState_ = null; - -}; -goog.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer); - - -/** - * @inheritDoc - */ -ol.renderer.webgl.VectorLayer.prototype.composeFrame = - function(frameState, layerState, context) { - this.layerState_ = layerState; - var viewState = frameState.viewState; - var replayGroup = this.replayGroup_; - if (replayGroup && !replayGroup.isEmpty()) { - replayGroup.replay(context, - viewState.center, viewState.resolution, viewState.rotation, - frameState.size, frameState.pixelRatio, layerState.opacity, - layerState.managed ? frameState.skippedFeatureUids : {}); - } - -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() { - var replayGroup = this.replayGroup_; - if (replayGroup) { - var context = this.mapRenderer.getContext(); - replayGroup.getDeleteResourcesFunction(context)(); - this.replayGroup_ = null; - } - goog.base(this, 'disposeInternal'); -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - if (!this.replayGroup_ || !this.layerState_) { - return undefined; - } else { - var context = this.mapRenderer.getContext(); - var viewState = frameState.viewState; - var layer = this.getLayer(); - var layerState = this.layerState_; - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, - context, viewState.center, viewState.resolution, viewState.rotation, - frameState.size, frameState.pixelRatio, layerState.opacity, - layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState) { - if (!this.replayGroup_ || !this.layerState_) { - return false; - } else { - var context = this.mapRenderer.getContext(); - var viewState = frameState.viewState; - var layerState = this.layerState_; - return this.replayGroup_.hasFeatureAtCoordinate(coordinate, - context, viewState.center, viewState.resolution, viewState.rotation, - frameState.size, frameState.pixelRatio, layerState.opacity, - frameState.skippedFeatureUids); - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState); - - if (hasFeature) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } -}; - - -/** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. - * @private - */ -ol.renderer.webgl.VectorLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.VectorLayer.prototype.prepareFrame = - function(frameState, layerState, context) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - var vectorSource = vectorLayer.getSource(); - - this.updateAttributions( - frameState.attributions, vectorSource.getAttributions()); - this.updateLogos(frameState, vectorSource); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); - var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - - var frameStateExtent = frameState.extent; - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var vectorLayerRevision = vectorLayer.getRevision(); - var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); - var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); - - if (vectorLayerRenderOrder === undefined) { - vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; - } - - var extent = ol.extent.buffer(frameStateExtent, - vectorLayerRenderBuffer * resolution); - - if (!this.dirty_ && - this.renderedResolution_ == resolution && - this.renderedRevision_ == vectorLayerRevision && - this.renderedRenderOrder_ == vectorLayerRenderOrder && - ol.extent.containsExtent(this.renderedExtent_, extent)) { - return true; - } - - if (this.replayGroup_) { - frameState.postRenderFunctions.push( - this.replayGroup_.getDeleteResourcesFunction(context)); - } - - this.dirty_ = false; - - var replayGroup = new ol.render.webgl.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), - extent, vectorLayer.getRenderBuffer()); - vectorSource.loadFeatures(extent, resolution, projection); - var renderFeature = - /** - * @param {ol.Feature} feature Feature. - * @this {ol.renderer.webgl.VectorLayer} - */ - function(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = vectorLayer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - var dirty = this.renderFeature( - feature, resolution, pixelRatio, styles, replayGroup); - this.dirty_ = this.dirty_ || dirty; - } - }; - if (vectorLayerRenderOrder) { - /** @type {Array.<ol.Feature>} */ - var features = []; - vectorSource.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - features.push(feature); - }, this); - goog.array.sort(features, vectorLayerRenderOrder); - features.forEach(renderFeature, this); - } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); - } - replayGroup.finish(context); - - this.renderedResolution_ = resolution; - this.renderedRevision_ = vectorLayerRevision; - this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; - this.replayGroup_ = replayGroup; - - return true; -}; - - -/** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - */ -ol.renderer.webgl.VectorLayer.prototype.renderFeature = - function(feature, resolution, pixelRatio, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - return loading; -}; - -// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE) - -goog.provide('ol.renderer.webgl.Map'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.log'); -goog.require('goog.log.Logger'); -goog.require('goog.object'); -goog.require('goog.style'); -goog.require('goog.webgl'); -goog.require('ol'); -goog.require('ol.RendererType'); -goog.require('ol.css'); -goog.require('ol.dom'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.webgl.Immediate'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.webgl.ImageLayer'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.renderer.webgl.TileLayer'); -goog.require('ol.renderer.webgl.VectorLayer'); -goog.require('ol.source.State'); -goog.require('ol.structs.LRUCache'); -goog.require('ol.structs.PriorityQueue'); -goog.require('ol.webgl'); -goog.require('ol.webgl.Context'); -goog.require('ol.webgl.WebGLContextEventType'); - - -/** - * @typedef {{magFilter: number, minFilter: number, texture: WebGLTexture}} - */ -ol.renderer.webgl.TextureCacheEntry; - - - -/** - * @constructor - * @extends {ol.renderer.Map} - * @param {Element} container Container. - * @param {ol.Map} map Map. - */ -ol.renderer.webgl.Map = function(container, map) { - - goog.base(this, container, map); - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - this.canvas_.style.width = '100%'; - this.canvas_.style.height = '100%'; - this.canvas_.className = ol.css.CLASS_UNSELECTABLE; - goog.dom.insertChildAt(container, this.canvas_, 0); - - /** - * @private - * @type {number} - */ - this.clipTileCanvasWidth_ = 0; - - /** - * @private - * @type {number} - */ - this.clipTileCanvasHeight_ = 0; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.clipTileContext_ = ol.dom.createCanvasContext2D(); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - - /** - * @private - * @type {WebGLRenderingContext} - */ - this.gl_ = ol.webgl.getContext(this.canvas_, { - antialias: true, - depth: false, - failIfMajorPerformanceCaveat: true, - preserveDrawingBuffer: false, - stencil: true - }); - goog.asserts.assert(this.gl_, 'got a WebGLRenderingContext'); - - /** - * @private - * @type {ol.webgl.Context} - */ - this.context_ = new ol.webgl.Context(this.canvas_, this.gl_); - - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST, - this.handleWebGLContextLost, false, this); - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED, - this.handleWebGLContextRestored, false, this); - - /** - * @private - * @type {ol.structs.LRUCache.<ol.renderer.webgl.TextureCacheEntry|null>} - */ - this.textureCache_ = new ol.structs.LRUCache(); - - /** - * @private - * @type {ol.Coordinate} - */ - this.focus_ = null; - - /** - * @private - * @type {ol.structs.PriorityQueue.<Array>} - */ - this.tileTextureQueue_ = new ol.structs.PriorityQueue( - goog.bind( - /** - * @param {Array.<*>} element Element. - * @return {number} Priority. - * @this {ol.renderer.webgl.Map} - */ - function(element) { - var tileCenter = /** @type {ol.Coordinate} */ (element[1]); - var tileResolution = /** @type {number} */ (element[2]); - var deltaX = tileCenter[0] - this.focus_[0]; - var deltaY = tileCenter[1] - this.focus_[1]; - return 65536 * Math.log(tileResolution) + - Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution; - }, this), - /** - * @param {Array.<*>} element Element. - * @return {string} Key. - */ - function(element) { - return /** @type {ol.Tile} */ (element[0]).getKey(); - }); - - /** - * @private - * @type {ol.PostRenderFunction} - */ - this.loadNextTileTexture_ = goog.bind( - function(map, frameState) { - if (!this.tileTextureQueue_.isEmpty()) { - this.tileTextureQueue_.reprioritize(); - var element = this.tileTextureQueue_.dequeue(); - var tile = /** @type {ol.Tile} */ (element[0]); - var tileSize = /** @type {ol.Size} */ (element[3]); - var tileGutter = /** @type {number} */ (element[4]); - this.bindTileTexture( - tile, tileSize, tileGutter, goog.webgl.LINEAR, goog.webgl.LINEAR); - } - }, this); - - /** - * @private - * @type {number} - */ - this.textureCacheFrameMarkerCount_ = 0; - - this.initializeGL_(); - -}; -goog.inherits(ol.renderer.webgl.Map, ol.renderer.Map); - - -/** - * @param {ol.Tile} tile Tile. - * @param {ol.Size} tileSize Tile size. - * @param {number} tileGutter Tile gutter. - * @param {number} magFilter Mag filter. - * @param {number} minFilter Min filter. - */ -ol.renderer.webgl.Map.prototype.bindTileTexture = - function(tile, tileSize, tileGutter, magFilter, minFilter) { - var gl = this.getGL(); - var tileKey = tile.getKey(); - if (this.textureCache_.containsKey(tileKey)) { - var textureCacheEntry = this.textureCache_.get(tileKey); - goog.asserts.assert(textureCacheEntry, - 'a texture cache entry exists for key %s', tileKey); - gl.bindTexture(goog.webgl.TEXTURE_2D, textureCacheEntry.texture); - if (textureCacheEntry.magFilter != magFilter) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter); - textureCacheEntry.magFilter = magFilter; - } - if (textureCacheEntry.minFilter != minFilter) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, minFilter); - textureCacheEntry.minFilter = minFilter; - } - } else { - var texture = gl.createTexture(); - gl.bindTexture(goog.webgl.TEXTURE_2D, texture); - if (tileGutter > 0) { - var clipTileCanvas = this.clipTileContext_.canvas; - var clipTileContext = this.clipTileContext_; - if (this.clipTileCanvasWidth_ !== tileSize[0] || - this.clipTileCanvasHeight_ !== tileSize[1]) { - clipTileCanvas.width = tileSize[0]; - clipTileCanvas.height = tileSize[1]; - this.clipTileCanvasWidth_ = tileSize[0]; - this.clipTileCanvasHeight_ = tileSize[1]; - } else { - clipTileContext.clearRect(0, 0, tileSize[0], tileSize[1]); - } - clipTileContext.drawImage(tile.getImage(), tileGutter, tileGutter, - tileSize[0], tileSize[1], 0, 0, tileSize[0], tileSize[1]); - gl.texImage2D(goog.webgl.TEXTURE_2D, 0, - goog.webgl.RGBA, goog.webgl.RGBA, - goog.webgl.UNSIGNED_BYTE, clipTileCanvas); - } else { - gl.texImage2D(goog.webgl.TEXTURE_2D, 0, - goog.webgl.RGBA, goog.webgl.RGBA, - goog.webgl.UNSIGNED_BYTE, tile.getImage()); - } - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter); - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER, minFilter); - gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, - goog.webgl.CLAMP_TO_EDGE); - gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, - goog.webgl.CLAMP_TO_EDGE); - this.textureCache_.set(tileKey, { - texture: texture, - magFilter: magFilter, - minFilter: minFilter - }); - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) { - if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { - return new ol.renderer.webgl.ImageLayer(this, layer); - } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { - return new ol.renderer.webgl.TileLayer(this, layer); - } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { - return new ol.renderer.webgl.VectorLayer(this, layer); - } else { - goog.asserts.fail('unexpected layer configuration'); - return null; - } -}; - - -/** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ = - function(type, frameState) { - var map = this.getMap(); - if (map.hasListener(type)) { - var context = this.context_; - - var extent = frameState.extent; - var size = frameState.size; - var viewState = frameState.viewState; - var pixelRatio = frameState.pixelRatio; - - var resolution = viewState.resolution; - var center = viewState.center; - var rotation = viewState.rotation; - - var vectorContext = new ol.render.webgl.Immediate(context, - center, resolution, rotation, size, extent, pixelRatio); - var composeEvent = new ol.render.Event(type, map, vectorContext, - frameState, null, context); - map.dispatchEvent(composeEvent); - - vectorContext.flush(); - } -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.disposeInternal = function() { - var gl = this.getGL(); - if (!gl.isContextLost()) { - this.textureCache_.forEach( - /** - * @param {?ol.renderer.webgl.TextureCacheEntry} textureCacheEntry - * Texture cache entry. - */ - function(textureCacheEntry) { - if (textureCacheEntry) { - gl.deleteTexture(textureCacheEntry.texture); - } - }); - } - goog.dispose(this.context_); - goog.base(this, 'disposeInternal'); -}; - - -/** - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. - * @private - */ -ol.renderer.webgl.Map.prototype.expireCache_ = function(map, frameState) { - var gl = this.getGL(); - var textureCacheEntry; - while (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ > - ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) { - textureCacheEntry = this.textureCache_.peekLast(); - if (!textureCacheEntry) { - if (+this.textureCache_.peekLastKey() == frameState.index) { - break; - } else { - --this.textureCacheFrameMarkerCount_; - } - } else { - gl.deleteTexture(textureCacheEntry.texture); - } - this.textureCache_.pop(); - } -}; - - -/** - * @return {ol.webgl.Context} - */ -ol.renderer.webgl.Map.prototype.getContext = function() { - return this.context_; -}; - - -/** - * @return {WebGLRenderingContext} GL. - */ -ol.renderer.webgl.Map.prototype.getGL = function() { - return this.gl_; -}; - - -/** - * @return {ol.structs.PriorityQueue.<Array>} Tile texture queue. - */ -ol.renderer.webgl.Map.prototype.getTileTextureQueue = function() { - return this.tileTextureQueue_; -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.getType = function() { - return ol.RendererType.WEBGL; -}; - - -/** - * @param {goog.events.Event} event Event. - * @protected - */ -ol.renderer.webgl.Map.prototype.handleWebGLContextLost = function(event) { - event.preventDefault(); - this.textureCache_.clear(); - this.textureCacheFrameMarkerCount_ = 0; - goog.object.forEach(this.getLayerRenderers(), - /** - * @param {ol.renderer.Layer} layerRenderer Layer renderer. - * @param {string} key Key. - * @param {Object.<string, ol.renderer.Layer>} object Object. - */ - function(layerRenderer, key, object) { - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, - 'renderer is an instance of ol.renderer.webgl.Layer'); - layerRenderer.handleWebGLContextLost(); - }); -}; - - -/** - * @protected - */ -ol.renderer.webgl.Map.prototype.handleWebGLContextRestored = function() { - this.initializeGL_(); - this.getMap().render(); -}; - - -/** - * @private - */ -ol.renderer.webgl.Map.prototype.initializeGL_ = function() { - var gl = this.gl_; - gl.activeTexture(goog.webgl.TEXTURE0); - gl.blendFuncSeparate( - goog.webgl.SRC_ALPHA, goog.webgl.ONE_MINUS_SRC_ALPHA, - goog.webgl.ONE, goog.webgl.ONE_MINUS_SRC_ALPHA); - gl.disable(goog.webgl.CULL_FACE); - gl.disable(goog.webgl.DEPTH_TEST); - gl.disable(goog.webgl.SCISSOR_TEST); - gl.disable(goog.webgl.STENCIL_TEST); -}; - - -/** - * @param {ol.Tile} tile Tile. - * @return {boolean} Is tile texture loaded. - */ -ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) { - return this.textureCache_.containsKey(tile.getKey()); -}; - - -/** - * @private - * @type {goog.log.Logger} - */ -ol.renderer.webgl.Map.prototype.logger_ = - goog.log.getLogger('ol.renderer.webgl.Map'); - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { - - var context = this.getContext(); - var gl = this.getGL(); - - if (gl.isContextLost()) { - return false; - } - - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, false); - this.renderedVisible_ = false; - } - return false; - } - - this.focus_ = frameState.focus; - - this.textureCache_.set((-frameState.index).toString(), null); - ++this.textureCacheFrameMarkerCount_; - - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); - - /** @type {Array.<ol.layer.LayerState>} */ - var layerStatesToDraw = []; - var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - - var viewResolution = frameState.viewState.resolution; - var i, ii, layerRenderer, layerState; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerState = layerStatesArray[i]; - if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerState.sourceState == ol.source.State.READY) { - layerRenderer = this.getLayerRenderer(layerState.layer); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, - 'renderer is an instance of ol.renderer.webgl.Layer'); - if (layerRenderer.prepareFrame(frameState, layerState, context)) { - layerStatesToDraw.push(layerState); - } - } - } - - var width = frameState.size[0] * frameState.pixelRatio; - var height = frameState.size[1] * frameState.pixelRatio; - if (this.canvas_.width != width || this.canvas_.height != height) { - this.canvas_.width = width; - this.canvas_.height = height; - } - - gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, null); - - gl.clearColor(0, 0, 0, 0); - gl.clear(goog.webgl.COLOR_BUFFER_BIT); - gl.enable(goog.webgl.BLEND); - gl.viewport(0, 0, this.canvas_.width, this.canvas_.height); - - for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) { - layerState = layerStatesToDraw[i]; - layerRenderer = this.getLayerRenderer(layerState.layer); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, - 'renderer is an instance of ol.renderer.webgl.Layer'); - layerRenderer.composeFrame(frameState, layerState, context); - } - - if (!this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, true); - this.renderedVisible_ = true; - } - - this.calculateMatrices2D(frameState); - - if (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ > - ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) { - frameState.postRenderFunctions.push(goog.bind(this.expireCache_, this)); - } - - if (!this.tileTextureQueue_.isEmpty()) { - frameState.postRenderFunctions.push(this.loadNextTileTexture_); - frameState.animate = true; - } - - this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState); - - this.scheduleRemoveUnusedLayerRenderers(frameState); - this.scheduleExpireIconCache(frameState); - -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg, - layerFilter, thisArg2) { - var result; - - if (this.getGL().isContextLost()) { - return false; - } - - var viewState = frameState.viewState; - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && - layerFilter.call(thisArg2, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - result = layerRenderer.forEachFeatureAtCoordinate( - coordinate, frameState, callback, thisArg); - if (result) { - return result; - } - } - } - return undefined; -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState, layerFilter, thisArg) { - var hasFeature = false; - - if (this.getGL().isContextLost()) { - return false; - } - - var viewState = frameState.viewState; - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && - layerFilter.call(thisArg, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - hasFeature = - layerRenderer.hasFeatureAtCoordinate(coordinate, frameState); - if (hasFeature) { - return true; - } - } - } - return hasFeature; -}; - - -/** - * @inheritDoc - */ -ol.renderer.webgl.Map.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg, - layerFilter, thisArg2) { - if (this.getGL().isContextLost()) { - return false; - } - - var viewState = frameState.viewState; - var result; - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && - layerFilter.call(thisArg, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - result = layerRenderer.forEachLayerAtPixel( - pixel, frameState, callback, thisArg); - if (result) { - return result; - } - } - } - return undefined; -}; - -// FIXME recheck layer/map projection compatibility when projection changes -// FIXME layer renderers should skip when they can't reproject -// FIXME add tilt and height? - -goog.provide('ol.Map'); -goog.provide('ol.MapProperty'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.async.AnimationDelay'); -goog.require('goog.async.nextTick'); -goog.require('goog.debug.Console'); -goog.require('goog.dom'); -goog.require('goog.dom.ViewportSizeMonitor'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.events.KeyHandler'); -goog.require('goog.events.KeyHandler.EventType'); -goog.require('goog.events.MouseWheelHandler'); -goog.require('goog.events.MouseWheelHandler.EventType'); -goog.require('goog.functions'); -goog.require('goog.log'); -goog.require('goog.log.Level'); -goog.require('goog.object'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEventType'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserEventHandler'); -goog.require('ol.MapEvent'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); -goog.require('ol.ObjectEvent'); -goog.require('ol.ObjectEventType'); -goog.require('ol.Pixel'); -goog.require('ol.PostRenderFunction'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.RendererType'); -goog.require('ol.Size'); -goog.require('ol.TileQueue'); -goog.require('ol.View'); -goog.require('ol.ViewHint'); -goog.require('ol.control'); -goog.require('ol.extent'); -goog.require('ol.has'); -goog.require('ol.interaction'); -goog.require('ol.layer.Base'); -goog.require('ol.layer.Group'); -goog.require('ol.proj'); -goog.require('ol.proj.common'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.canvas.Map'); -goog.require('ol.renderer.dom.Map'); -goog.require('ol.renderer.webgl.Map'); -goog.require('ol.size'); -goog.require('ol.structs.PriorityQueue'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); - - -/** - * @const - * @type {string} - */ -ol.OL3_URL = 'http://openlayers.org/'; - - -/** - * @const - * @type {string} - */ -ol.OL3_LOGO_URL = 'data:image/png;base64,' + - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBI' + - 'WXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAA' + - 'AhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszW' + - 'WMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvY' + - 'asvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvX' + - 'H1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1Vk' + - 'bMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW' + - '2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLP' + - 'VcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqT' + - 'acrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaar' + - 'ldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+Hi' + - 'zeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDn' + - 'BAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSF' + - 'hYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJ' + - 'REFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxC' + - 'Brb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe' + - '0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8' + - 'a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7a' + - 'hgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCn' + - 'B3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDg' + - 'q82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC'; - - -/** - * @type {Array.<ol.RendererType>} - * @const - */ -ol.DEFAULT_RENDERER_TYPES = [ - ol.RendererType.CANVAS, - ol.RendererType.WEBGL, - ol.RendererType.DOM -]; - - -/** - * @enum {string} - */ -ol.MapProperty = { - LAYERGROUP: 'layergroup', - SIZE: 'size', - TARGET: 'target', - VIEW: 'view' -}; - - - -/** - * @classdesc - * The map is the core component of OpenLayers. For a map to render, a view, - * one or more layers, and a target container are needed: - * - * var map = new ol.Map({ - * view: new ol.View({ - * center: [0, 0], - * zoom: 1 - * }), - * layers: [ - * new ol.layer.Tile({ - * source: new ol.source.MapQuest({layer: 'osm'}) - * }) - * ], - * target: 'map' - * }); - * - * The above snippet creates a map using a {@link ol.layer.Tile} to display - * {@link ol.source.MapQuest} OSM data and render it to a DOM element with the - * id `map`. - * - * The constructor places a viewport container (with CSS class name - * `ol-viewport`) in the target element (see `getViewport()`), and then two - * further elements within the viewport: one with CSS class name - * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with - * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent` - * option of {@link ol.Overlay} for the difference). The map itself is placed in - * a further element within the viewport, either DOM or Canvas, depending on the - * renderer. - * - * Layers are stored as a `ol.Collection` in layerGroups. A top-level group is - * provided by the library. This is what is accessed by `getLayerGroup` and - * `setLayerGroup`. Layers entered in the options are added to this group, and - * `addLayer` and `removeLayer` change the layer collection in the group. - * `getLayers` is a convenience function for `getLayerGroup().getLayers()`. - * Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers - * entered in the options or added with `addLayer` can be groups, which can - * contain further groups, and so on. - * - * @constructor - * @extends {ol.Object} - * @param {olx.MapOptions} options Map options. - * @fires ol.MapBrowserEvent - * @fires ol.MapEvent - * @fires ol.render.Event#postcompose - * @fires ol.render.Event#precompose - * @api stable - */ -ol.Map = function(options) { - - goog.base(this); - - var optionsInternal = ol.Map.createOptionsInternal(options); - - /** - * @type {boolean} - * @private - */ - this.loadTilesWhileAnimating_ = - options.loadTilesWhileAnimating !== undefined ? - options.loadTilesWhileAnimating : false; - - /** - * @type {boolean} - * @private - */ - this.loadTilesWhileInteracting_ = - options.loadTilesWhileInteracting !== undefined ? - options.loadTilesWhileInteracting : false; - - /** - * @private - * @type {number} - */ - this.pixelRatio_ = options.pixelRatio !== undefined ? - options.pixelRatio : ol.has.DEVICE_PIXEL_RATIO; - - /** - * @private - * @type {Object.<string, string>} - */ - this.logos_ = optionsInternal.logos; - - /** - * @private - * @type {goog.async.AnimationDelay} - */ - this.animationDelay_ = - new goog.async.AnimationDelay(this.renderFrame_, undefined, this); - this.registerDisposable(this.animationDelay_); - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {number} - */ - this.frameIndex_ = 0; - - /** - * @private - * @type {?olx.FrameState} - */ - this.frameState_ = null; - - /** - * The extent at the previous 'moveend' event. - * @private - * @type {ol.Extent} - */ - this.previousExtent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {goog.events.Key} - */ - this.viewPropertyListenerKey_ = null; - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.layerGroupPropertyListenerKeys_ = null; - - /** - * @private - * @type {Element} - */ - this.viewport_ = goog.dom.createDom('DIV', 'ol-viewport'); - this.viewport_.style.position = 'relative'; - this.viewport_.style.overflow = 'hidden'; - this.viewport_.style.width = '100%'; - this.viewport_.style.height = '100%'; - // prevent page zoom on IE >= 10 browsers - this.viewport_.style.msTouchAction = 'none'; - this.viewport_.style.touchAction = 'none'; - if (ol.has.TOUCH) { - goog.dom.classlist.add(this.viewport_, 'ol-touch'); - } - - /** - * @private - * @type {Element} - */ - this.overlayContainer_ = goog.dom.createDom('DIV', - 'ol-overlaycontainer'); - this.viewport_.appendChild(this.overlayContainer_); - - /** - * @private - * @type {Element} - */ - this.overlayContainerStopEvent_ = goog.dom.createDom('DIV', - 'ol-overlaycontainer-stopevent'); - goog.events.listen(this.overlayContainerStopEvent_, [ - goog.events.EventType.CLICK, - goog.events.EventType.DBLCLICK, - goog.events.EventType.MOUSEDOWN, - goog.events.EventType.TOUCHSTART, - goog.events.EventType.MSPOINTERDOWN, - ol.MapBrowserEvent.EventType.POINTERDOWN, - goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel' - ], goog.events.Event.stopPropagation); - this.viewport_.appendChild(this.overlayContainerStopEvent_); - - var mapBrowserEventHandler = new ol.MapBrowserEventHandler(this); - goog.events.listen(mapBrowserEventHandler, - goog.object.getValues(ol.MapBrowserEvent.EventType), - this.handleMapBrowserEvent, false, this); - this.registerDisposable(mapBrowserEventHandler); - - /** - * @private - * @type {Element|Document} - */ - this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget; - - /** - * @private - * @type {goog.events.KeyHandler} - */ - this.keyHandler_ = new goog.events.KeyHandler(); - goog.events.listen(this.keyHandler_, goog.events.KeyHandler.EventType.KEY, - this.handleBrowserEvent, false, this); - this.registerDisposable(this.keyHandler_); - - var mouseWheelHandler = new goog.events.MouseWheelHandler(this.viewport_); - goog.events.listen(mouseWheelHandler, - goog.events.MouseWheelHandler.EventType.MOUSEWHEEL, - this.handleBrowserEvent, false, this); - this.registerDisposable(mouseWheelHandler); - - /** - * @type {ol.Collection.<ol.control.Control>} - * @private - */ - this.controls_ = optionsInternal.controls; - - /** - * @type {ol.Collection.<ol.interaction.Interaction>} - * @private - */ - this.interactions_ = optionsInternal.interactions; - - /** - * @type {ol.Collection.<ol.Overlay>} - * @private - */ - this.overlays_ = optionsInternal.overlays; - - /** - * A lookup of overlays by id. - * @private - * @type {Object.<string, ol.Overlay>} - */ - this.overlayIdIndex_ = {}; - - /** - * @type {ol.renderer.Map} - * @private - */ - this.renderer_ = - new optionsInternal.rendererConstructor(this.viewport_, this); - this.registerDisposable(this.renderer_); - - /** - * @type {goog.dom.ViewportSizeMonitor} - * @private - */ - this.viewportSizeMonitor_ = new goog.dom.ViewportSizeMonitor(); - this.registerDisposable(this.viewportSizeMonitor_); - - /** - * @type {goog.events.Key} - * @private - */ - this.viewportResizeListenerKey_ = null; - - /** - * @private - * @type {ol.Coordinate} - */ - this.focus_ = null; - - /** - * @private - * @type {Array.<ol.PreRenderFunction>} - */ - this.preRenderFunctions_ = []; - - /** - * @private - * @type {Array.<ol.PostRenderFunction>} - */ - this.postRenderFunctions_ = []; - - /** - * @private - * @type {ol.TileQueue} - */ - this.tileQueue_ = new ol.TileQueue( - goog.bind(this.getTilePriority, this), - goog.bind(this.handleTileChange_, this)); - - /** - * Uids of features to skip at rendering time. - * @type {Object.<string, boolean>} - * @private - */ - this.skippedFeatureUids_ = {}; - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.MapProperty.LAYERGROUP), - this.handleLayerGroupChanged_, false, this); - goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.VIEW), - this.handleViewChanged_, false, this); - goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.SIZE), - this.handleSizeChanged_, false, this); - goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.TARGET), - this.handleTargetChanged_, false, this); - - // setProperties will trigger the rendering of the map if the map - // is "defined" already. - this.setProperties(optionsInternal.values); - - this.controls_.forEach( - /** - * @param {ol.control.Control} control Control. - * @this {ol.Map} - */ - function(control) { - control.setMap(this); - }, this); - - goog.events.listen(this.controls_, ol.CollectionEventType.ADD, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(this); - }, false, this); - - goog.events.listen(this.controls_, ol.CollectionEventType.REMOVE, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(null); - }, false, this); - - this.interactions_.forEach( - /** - * @param {ol.interaction.Interaction} interaction Interaction. - * @this {ol.Map} - */ - function(interaction) { - interaction.setMap(this); - }, this); - - goog.events.listen(this.interactions_, ol.CollectionEventType.ADD, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(this); - }, false, this); - - goog.events.listen(this.interactions_, ol.CollectionEventType.REMOVE, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(null); - }, false, this); - - this.overlays_.forEach(this.addOverlayInternal_, this); - - goog.events.listen(this.overlays_, ol.CollectionEventType.ADD, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - this.addOverlayInternal_(/** @type {ol.Overlay} */ (event.element)); - }, false, this); - - goog.events.listen(this.overlays_, ol.CollectionEventType.REMOVE, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - var id = event.element.getId(); - if (id !== undefined) { - delete this.overlayIdIndex_[id.toString()]; - } - event.element.setMap(null); - }, false, this); - -}; -goog.inherits(ol.Map, ol.Object); - - -/** - * Add the given control to the map. - * @param {ol.control.Control} control Control. - * @api stable - */ -ol.Map.prototype.addControl = function(control) { - var controls = this.getControls(); - goog.asserts.assert(controls !== undefined, 'controls should be defined'); - controls.push(control); -}; - - -/** - * Add the given interaction to the map. - * @param {ol.interaction.Interaction} interaction Interaction to add. - * @api stable - */ -ol.Map.prototype.addInteraction = function(interaction) { - var interactions = this.getInteractions(); - goog.asserts.assert(interactions !== undefined, - 'interactions should be defined'); - interactions.push(interaction); -}; - - -/** - * Adds the given layer to the top of this map. If you want to add a layer - * elsewhere in the stack, use `getLayers()` and the methods available on - * {@link ol.Collection}. - * @param {ol.layer.Base} layer Layer. - * @api stable - */ -ol.Map.prototype.addLayer = function(layer) { - var layers = this.getLayerGroup().getLayers(); - layers.push(layer); -}; - - -/** - * Add the given overlay to the map. - * @param {ol.Overlay} overlay Overlay. - * @api stable - */ -ol.Map.prototype.addOverlay = function(overlay) { - var overlays = this.getOverlays(); - goog.asserts.assert(overlays !== undefined, 'overlays should be defined'); - overlays.push(overlay); -}; - - -/** - * This deals with map's overlay collection changes. - * @param {ol.Overlay} overlay Overlay. - * @private - */ -ol.Map.prototype.addOverlayInternal_ = function(overlay) { - var id = overlay.getId(); - if (id !== undefined) { - this.overlayIdIndex_[id.toString()] = overlay; - } - overlay.setMap(this); -}; - - -/** - * Add functions to be called before rendering. This can be used for attaching - * animations before updating the map's view. The {@link ol.animation} - * namespace provides several static methods for creating prerender functions. - * @param {...ol.PreRenderFunction} var_args Any number of pre-render functions. - * @api - */ -ol.Map.prototype.beforeRender = function(var_args) { - this.render(); - Array.prototype.push.apply(this.preRenderFunctions_, arguments); -}; - - -/** - * @param {ol.PreRenderFunction} preRenderFunction Pre-render function. - * @return {boolean} Whether the preRenderFunction has been found and removed. - */ -ol.Map.prototype.removePreRenderFunction = function(preRenderFunction) { - return goog.array.remove(this.preRenderFunctions_, preRenderFunction); -}; - - -/** - * - * @inheritDoc - */ -ol.Map.prototype.disposeInternal = function() { - goog.dom.removeNode(this.viewport_); - goog.base(this, 'disposeInternal'); -}; - - -/** - * Detect features that intersect a pixel on the viewport, and execute a - * callback with each intersecting feature. Layers included in the detection can - * be configured through `opt_layerFilter`. - * @param {ol.Pixel} pixel Pixel. - * @param {function(this: S, (ol.Feature|ol.render.Feature), - * ol.layer.Layer): T} callback Feature callback. The callback will be - * called with two arguments. The first argument is one - * {@link ol.Feature feature} or - * {@link ol.render.Feature render feature} at the pixel, the second is - * the {@link ol.layer.Layer layer} of the feature and will be null for - * unmanaged layers. To stop detection, callback functions can return a - * truthy value. - * @param {S=} opt_this Value to use as `this` when executing `callback`. - * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer - * filter function. The filter function will receive one argument, the - * {@link ol.layer.Layer layer-candidate} and it should return a boolean - * value. Only layers which are visible and for which this function returns - * `true` will be tested for features. By default, all visible layers will - * be tested. - * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result, i.e. the return value of last - * callback execution, or the first truthy callback return value. - * @template S,T,U - * @api stable - */ -ol.Map.prototype.forEachFeatureAtPixel = - function(pixel, callback, opt_this, opt_layerFilter, opt_this2) { - if (!this.frameState_) { - return; - } - var coordinate = this.getCoordinateFromPixel(pixel); - var thisArg = opt_this !== undefined ? opt_this : null; - var layerFilter = opt_layerFilter !== undefined ? - opt_layerFilter : goog.functions.TRUE; - var thisArg2 = opt_this2 !== undefined ? opt_this2 : null; - return this.renderer_.forEachFeatureAtCoordinate( - coordinate, this.frameState_, callback, thisArg, - layerFilter, thisArg2); -}; - - -/** - * Detect layers that have a color value at a pixel on the viewport, and - * execute a callback with each matching layer. Layers included in the - * detection can be configured through `opt_layerFilter`. - * @param {ol.Pixel} pixel Pixel. - * @param {function(this: S, ol.layer.Layer): T} callback Layer - * callback. Will receive one argument, the {@link ol.layer.Layer layer} - * that contains the color pixel. To stop detection, callback functions can - * return a truthy value. - * @param {S=} opt_this Value to use as `this` when executing `callback`. - * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer - * filter function. The filter function will receive one argument, the - * {@link ol.layer.Layer layer-candidate} and it should return a boolean - * value. Only layers which are visible and for which this function returns - * `true` will be tested for features. By default, all visible layers will - * be tested. - * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result, i.e. the return value of last - * callback execution, or the first truthy callback return value. - * @template S,T,U - * @api stable - */ -ol.Map.prototype.forEachLayerAtPixel = - function(pixel, callback, opt_this, opt_layerFilter, opt_this2) { - if (!this.frameState_) { - return; - } - var thisArg = opt_this !== undefined ? opt_this : null; - var layerFilter = opt_layerFilter !== undefined ? - opt_layerFilter : goog.functions.TRUE; - var thisArg2 = opt_this2 !== undefined ? opt_this2 : null; - return this.renderer_.forEachLayerAtPixel( - pixel, this.frameState_, callback, thisArg, - layerFilter, thisArg2); -}; - - -/** - * Detect if features intersect a pixel on the viewport. Layers included in the - * detection can be configured through `opt_layerFilter`. - * @param {ol.Pixel} pixel Pixel. - * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer - * filter function. The filter function will receive one argument, the - * {@link ol.layer.Layer layer-candidate} and it should return a boolean - * value. Only layers which are visible and for which this function returns - * `true` will be tested for features. By default, all visible layers will - * be tested. - * @param {U=} opt_this Value to use as `this` when executing `layerFilter`. - * @return {boolean} Is there a feature at the given pixel? - * @template U - * @api - */ -ol.Map.prototype.hasFeatureAtPixel = - function(pixel, opt_layerFilter, opt_this) { - if (!this.frameState_) { - return false; - } - var coordinate = this.getCoordinateFromPixel(pixel); - var layerFilter = opt_layerFilter !== undefined ? - opt_layerFilter : goog.functions.TRUE; - var thisArg = opt_this !== undefined ? opt_this : null; - return this.renderer_.hasFeatureAtCoordinate( - coordinate, this.frameState_, layerFilter, thisArg); -}; - - -/** - * Returns the geographical coordinate for a browser event. - * @param {Event} event Event. - * @return {ol.Coordinate} Coordinate. - * @api stable - */ -ol.Map.prototype.getEventCoordinate = function(event) { - return this.getCoordinateFromPixel(this.getEventPixel(event)); -}; - - -/** - * Returns the map pixel position for a browser event relative to the viewport. - * @param {Event} event Event. - * @return {ol.Pixel} Pixel. - * @api stable - */ -ol.Map.prototype.getEventPixel = function(event) { - var eventPosition = goog.style.getRelativePosition(event, this.viewport_); - return [eventPosition.x, eventPosition.y]; -}; - - -/** - * Get the target in which this map is rendered. - * Note that this returns what is entered as an option or in setTarget: - * if that was an element, it returns an element; if a string, it returns that. - * @return {Element|string|undefined} The Element or id of the Element that the - * map is rendered in. - * @observable - * @api stable - */ -ol.Map.prototype.getTarget = function() { - return /** @type {Element|string|undefined} */ ( - this.get(ol.MapProperty.TARGET)); -}; - - -/** - * Get the DOM element into which this map is rendered. In contrast to - * `getTarget` this method always return an `Element`, or `null` if the - * map has no target. - * @return {Element} The element that the map is rendered in. - * @api - */ -ol.Map.prototype.getTargetElement = function() { - var target = this.getTarget(); - return target !== undefined ? goog.dom.getElement(target) : null; -}; - - -/** - * Get the coordinate for a given pixel. This returns a coordinate in the - * map view projection. - * @param {ol.Pixel} pixel Pixel position in the map viewport. - * @return {ol.Coordinate} The coordinate for the pixel position. - * @api stable - */ -ol.Map.prototype.getCoordinateFromPixel = function(pixel) { - var frameState = this.frameState_; - if (!frameState) { - return null; - } else { - var vec2 = pixel.slice(); - return ol.vec.Mat4.multVec2(frameState.pixelToCoordinateMatrix, vec2, vec2); - } -}; - - -/** - * Get the map controls. Modifying this collection changes the controls - * associated with the map. - * @return {ol.Collection.<ol.control.Control>} Controls. - * @api stable - */ -ol.Map.prototype.getControls = function() { - return this.controls_; -}; - - -/** - * Get the map overlays. Modifying this collection changes the overlays - * associated with the map. - * @return {ol.Collection.<ol.Overlay>} Overlays. - * @api stable - */ -ol.Map.prototype.getOverlays = function() { - return this.overlays_; -}; - - -/** - * Get an overlay by its identifier (the value returned by overlay.getId()). - * Note that the index treats string and numeric identifiers as the same. So - * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`. - * @param {string|number} id Overlay identifier. - * @return {ol.Overlay} Overlay. - * @api - */ -ol.Map.prototype.getOverlayById = function(id) { - var overlay = this.overlayIdIndex_[id.toString()]; - return overlay !== undefined ? overlay : null; -}; - - -/** - * Get the map interactions. Modifying this collection changes the interactions - * associated with the map. - * - * Interactions are used for e.g. pan, zoom and rotate. - * @return {ol.Collection.<ol.interaction.Interaction>} Interactions. - * @api stable - */ -ol.Map.prototype.getInteractions = function() { - return this.interactions_; -}; - - -/** - * Get the layergroup associated with this map. - * @return {ol.layer.Group} A layer group containing the layers in this map. - * @observable - * @api stable - */ -ol.Map.prototype.getLayerGroup = function() { - return /** @type {ol.layer.Group} */ (this.get(ol.MapProperty.LAYERGROUP)); -}; - - -/** - * Get the collection of layers associated with this map. - * @return {!ol.Collection.<ol.layer.Base>} Layers. - * @api stable - */ -ol.Map.prototype.getLayers = function() { - var layers = this.getLayerGroup().getLayers(); - return layers; -}; - - -/** - * Get the pixel for a coordinate. This takes a coordinate in the map view - * projection and returns the corresponding pixel. - * @param {ol.Coordinate} coordinate A map coordinate. - * @return {ol.Pixel} A pixel position in the map viewport. - * @api stable - */ -ol.Map.prototype.getPixelFromCoordinate = function(coordinate) { - var frameState = this.frameState_; - if (!frameState) { - return null; - } else { - var vec2 = coordinate.slice(0, 2); - return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2); - } -}; - - -/** - * Get the map renderer. - * @return {ol.renderer.Map} Renderer - */ -ol.Map.prototype.getRenderer = function() { - return this.renderer_; -}; - - -/** - * Get the size of this map. - * @return {ol.Size|undefined} The size in pixels of the map in the DOM. - * @observable - * @api stable - */ -ol.Map.prototype.getSize = function() { - return /** @type {ol.Size|undefined} */ (this.get(ol.MapProperty.SIZE)); -}; - - -/** - * Get the view associated with this map. A view manages properties such as - * center and resolution. - * @return {ol.View} The view that controls this map. - * @observable - * @api stable - */ -ol.Map.prototype.getView = function() { - return /** @type {ol.View} */ (this.get(ol.MapProperty.VIEW)); -}; - - -/** - * Get the element that serves as the map viewport. - * @return {Element} Viewport. - * @api stable - */ -ol.Map.prototype.getViewport = function() { - return this.viewport_; -}; - - -/** - * Get the element that serves as the container for overlays. Elements added to - * this container will let mousedown and touchstart events through to the map, - * so clicks and gestures on an overlay will trigger {@link ol.MapBrowserEvent} - * events. - * @return {Element} The map's overlay container. - */ -ol.Map.prototype.getOverlayContainer = function() { - return this.overlayContainer_; -}; - - -/** - * Get the element that serves as a container for overlays that don't allow - * event propagation. Elements added to this container won't let mousedown and - * touchstart events through to the map, so clicks and gestures on an overlay - * don't trigger any {@link ol.MapBrowserEvent}. - * @return {Element} The map's overlay container that stops events. - */ -ol.Map.prototype.getOverlayContainerStopEvent = function() { - return this.overlayContainerStopEvent_; -}; - - -/** - * @param {ol.Tile} tile Tile. - * @param {string} tileSourceKey Tile source key. - * @param {ol.Coordinate} tileCenter Tile center. - * @param {number} tileResolution Tile resolution. - * @return {number} Tile priority. - */ -ol.Map.prototype.getTilePriority = - function(tile, tileSourceKey, tileCenter, tileResolution) { - // Filter out tiles at higher zoom levels than the current zoom level, or that - // are outside the visible extent. - var frameState = this.frameState_; - if (!frameState || !(tileSourceKey in frameState.wantedTiles)) { - return ol.structs.PriorityQueue.DROP; - } - var coordKey = ol.tilecoord.toString(tile.tileCoord); - if (!frameState.wantedTiles[tileSourceKey][coordKey]) { - return ol.structs.PriorityQueue.DROP; - } - // Prioritize the highest zoom level tiles closest to the focus. - // Tiles at higher zoom levels are prioritized using Math.log(tileResolution). - // Within a zoom level, tiles are prioritized by the distance in pixels - // between the center of the tile and the focus. The factor of 65536 means - // that the prioritization should behave as desired for tiles up to - // 65536 * Math.log(2) = 45426 pixels from the focus. - var deltaX = tileCenter[0] - frameState.focus[0]; - var deltaY = tileCenter[1] - frameState.focus[1]; - return 65536 * Math.log(tileResolution) + - Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution; -}; - - -/** - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @param {string=} opt_type Type. - */ -ol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) { - var type = opt_type || browserEvent.type; - var mapBrowserEvent = new ol.MapBrowserEvent(type, this, browserEvent); - this.handleMapBrowserEvent(mapBrowserEvent); -}; - - -/** - * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle. - */ -ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) { - if (!this.frameState_) { - // With no view defined, we cannot translate pixels into geographical - // coordinates so interactions cannot be used. - return; - } - this.focus_ = mapBrowserEvent.coordinate; - mapBrowserEvent.frameState = this.frameState_; - var interactions = this.getInteractions(); - goog.asserts.assert(interactions !== undefined, - 'interactions should be defined'); - var interactionsArray = interactions.getArray(); - var i; - if (this.dispatchEvent(mapBrowserEvent) !== false) { - for (i = interactionsArray.length - 1; i >= 0; i--) { - var interaction = interactionsArray[i]; - if (!interaction.getActive()) { - continue; - } - var cont = interaction.handleEvent(mapBrowserEvent); - if (!cont) { - break; - } - } - } -}; - - -/** - * @protected - */ -ol.Map.prototype.handlePostRender = function() { - - var frameState = this.frameState_; - - // Manage the tile queue - // Image loads are expensive and a limited resource, so try to use them - // efficiently: - // * When the view is static we allow a large number of parallel tile loads - // to complete the frame as quickly as possible. - // * When animating or interacting, image loads can cause janks, so we reduce - // the maximum number of loads per frame and limit the number of parallel - // tile loads to remain reactive to view changes and to reduce the chance of - // loading tiles that will quickly disappear from view. - var tileQueue = this.tileQueue_; - if (!tileQueue.isEmpty()) { - var maxTotalLoading = 16; - var maxNewLoads = maxTotalLoading; - var tileSourceCount = 0; - if (frameState) { - var hints = frameState.viewHints; - if (hints[ol.ViewHint.ANIMATING]) { - maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0; - maxNewLoads = 2; - } - if (hints[ol.ViewHint.INTERACTING]) { - maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0; - maxNewLoads = 2; - } - tileSourceCount = goog.object.getCount(frameState.wantedTiles); - } - maxTotalLoading *= tileSourceCount; - maxNewLoads *= tileSourceCount; - if (tileQueue.getTilesLoading() < maxTotalLoading) { - tileQueue.reprioritize(); // FIXME only call if view has changed - tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); - } - } - - var postRenderFunctions = this.postRenderFunctions_; - var i, ii; - for (i = 0, ii = postRenderFunctions.length; i < ii; ++i) { - postRenderFunctions[i](this, frameState); - } - postRenderFunctions.length = 0; -}; - - -/** - * @private - */ -ol.Map.prototype.handleSizeChanged_ = function() { - this.render(); -}; - - -/** - * @private - */ -ol.Map.prototype.handleTargetChanged_ = function() { - // target may be undefined, null, a string or an Element. - // If it's a string we convert it to an Element before proceeding. - // If it's not now an Element we remove the viewport from the DOM. - // If it's an Element we append the viewport element to it. - - var targetElement = this.getTargetElement(); - - this.keyHandler_.detach(); - - if (!targetElement) { - goog.dom.removeNode(this.viewport_); - if (this.viewportResizeListenerKey_) { - goog.events.unlistenByKey(this.viewportResizeListenerKey_); - this.viewportResizeListenerKey_ = null; - } - } else { - targetElement.appendChild(this.viewport_); - - var keyboardEventTarget = !this.keyboardEventTarget_ ? - targetElement : this.keyboardEventTarget_; - this.keyHandler_.attach(keyboardEventTarget); - - if (!this.viewportResizeListenerKey_) { - this.viewportResizeListenerKey_ = goog.events.listen( - this.viewportSizeMonitor_, goog.events.EventType.RESIZE, - this.updateSize, false, this); - } - } - - this.updateSize(); - // updateSize calls setSize, so no need to call this.render - // ourselves here. -}; - - -/** - * @private - */ -ol.Map.prototype.handleTileChange_ = function() { - this.render(); -}; - - -/** - * @private - */ -ol.Map.prototype.handleViewPropertyChanged_ = function() { - this.render(); -}; - - -/** - * @private - */ -ol.Map.prototype.handleViewChanged_ = function() { - if (this.viewPropertyListenerKey_) { - goog.events.unlistenByKey(this.viewPropertyListenerKey_); - this.viewPropertyListenerKey_ = null; - } - var view = this.getView(); - if (view) { - this.viewPropertyListenerKey_ = goog.events.listen( - view, ol.ObjectEventType.PROPERTYCHANGE, - this.handleViewPropertyChanged_, false, this); - } - this.render(); -}; - - -/** - * @param {goog.events.Event} event Event. - * @private - */ -ol.Map.prototype.handleLayerGroupMemberChanged_ = function(event) { - goog.asserts.assertInstanceof(event, goog.events.Event, - 'event should be an Event'); - this.render(); -}; - - -/** - * @param {ol.ObjectEvent} event Event. - * @private - */ -ol.Map.prototype.handleLayerGroupPropertyChanged_ = function(event) { - goog.asserts.assertInstanceof(event, ol.ObjectEvent, - 'event should be an ol.ObjectEvent'); - this.render(); -}; - - -/** - * @private - */ -ol.Map.prototype.handleLayerGroupChanged_ = function() { - if (this.layerGroupPropertyListenerKeys_) { - this.layerGroupPropertyListenerKeys_.forEach(goog.events.unlistenByKey); - this.layerGroupPropertyListenerKeys_ = null; - } - var layerGroup = this.getLayerGroup(); - if (layerGroup) { - this.layerGroupPropertyListenerKeys_ = [ - goog.events.listen( - layerGroup, ol.ObjectEventType.PROPERTYCHANGE, - this.handleLayerGroupPropertyChanged_, false, this), - goog.events.listen( - layerGroup, goog.events.EventType.CHANGE, - this.handleLayerGroupMemberChanged_, false, this) - ]; - } - this.render(); -}; - - -/** - * Returns `true` if the map is defined, `false` otherwise. The map is defined - * if it is contained in `document`, visible, has non-zero height and width, and - * has a defined view. - * @return {boolean} Is defined. - */ -ol.Map.prototype.isDef = function() { - if (!goog.dom.contains(document, this.viewport_)) { - return false; - } - if (!goog.style.isElementShown(this.viewport_)) { - return false; - } - var size = this.getSize(); - if (!size || size[0] <= 0 || size[1] <= 0) { - return false; - } - var view = this.getView(); - if (!view || !view.isDef()) { - return false; - } - return true; -}; - - -/** - * @return {boolean} Is rendered. - */ -ol.Map.prototype.isRendered = function() { - return !!this.frameState_; -}; - - -/** - * Requests an immediate render in a synchronous manner. - * @api stable - */ -ol.Map.prototype.renderSync = function() { - this.animationDelay_.fire(); -}; - - -/** - * Request a map rendering (at the next animation frame). - * @api stable - */ -ol.Map.prototype.render = function() { - if (!this.animationDelay_.isActive()) { - this.animationDelay_.start(); - } -}; - - -/** - * Remove the given control from the map. - * @param {ol.control.Control} control Control. - * @return {ol.control.Control|undefined} The removed control (or undefined - * if the control was not found). - * @api stable - */ -ol.Map.prototype.removeControl = function(control) { - var controls = this.getControls(); - goog.asserts.assert(controls !== undefined, 'controls should be defined'); - return controls.remove(control); -}; - - -/** - * Remove the given interaction from the map. - * @param {ol.interaction.Interaction} interaction Interaction to remove. - * @return {ol.interaction.Interaction|undefined} The removed interaction (or - * undefined if the interaction was not found). - * @api stable - */ -ol.Map.prototype.removeInteraction = function(interaction) { - var interactions = this.getInteractions(); - goog.asserts.assert(interactions !== undefined, - 'interactions should be defined'); - return interactions.remove(interaction); -}; - - -/** - * Removes the given layer from the map. - * @param {ol.layer.Base} layer Layer. - * @return {ol.layer.Base|undefined} The removed layer (or undefined if the - * layer was not found). - * @api stable - */ -ol.Map.prototype.removeLayer = function(layer) { - var layers = this.getLayerGroup().getLayers(); - return layers.remove(layer); -}; - - -/** - * Remove the given overlay from the map. - * @param {ol.Overlay} overlay Overlay. - * @return {ol.Overlay|undefined} The removed overlay (or undefined - * if the overlay was not found). - * @api stable - */ -ol.Map.prototype.removeOverlay = function(overlay) { - var overlays = this.getOverlays(); - goog.asserts.assert(overlays !== undefined, 'overlays should be defined'); - return overlays.remove(overlay); -}; - - -/** - * @param {number} time Time. - * @private - */ -ol.Map.prototype.renderFrame_ = function(time) { - - var i, ii, viewState; - - var size = this.getSize(); - var view = this.getView(); - /** @type {?olx.FrameState} */ - var frameState = null; - if (size !== undefined && ol.size.hasArea(size) && - view && view.isDef()) { - var viewHints = view.getHints(); - var layerStatesArray = this.getLayerGroup().getLayerStatesArray(); - var layerStates = {}; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i]; - } - viewState = view.getState(); - frameState = /** @type {olx.FrameState} */ ({ - animate: false, - attributions: {}, - coordinateToPixelMatrix: this.coordinateToPixelMatrix_, - extent: null, - focus: !this.focus_ ? viewState.center : this.focus_, - index: this.frameIndex_++, - layerStates: layerStates, - layerStatesArray: layerStatesArray, - logos: goog.object.clone(this.logos_), - pixelRatio: this.pixelRatio_, - pixelToCoordinateMatrix: this.pixelToCoordinateMatrix_, - postRenderFunctions: [], - size: size, - skippedFeatureUids: this.skippedFeatureUids_, - tileQueue: this.tileQueue_, - time: time, - usedTiles: {}, - viewState: viewState, - viewHints: viewHints, - wantedTiles: {} - }); - } - - if (frameState) { - var preRenderFunctions = this.preRenderFunctions_; - var n = 0, preRenderFunction; - for (i = 0, ii = preRenderFunctions.length; i < ii; ++i) { - preRenderFunction = preRenderFunctions[i]; - if (preRenderFunction(this, frameState)) { - preRenderFunctions[n++] = preRenderFunction; - } - } - preRenderFunctions.length = n; - - frameState.extent = ol.extent.getForViewAndSize(viewState.center, - viewState.resolution, viewState.rotation, frameState.size); - } - - this.frameState_ = frameState; - this.renderer_.renderFrame(frameState); - - if (frameState) { - if (frameState.animate) { - this.render(); - } - Array.prototype.push.apply( - this.postRenderFunctions_, frameState.postRenderFunctions); - - var idle = this.preRenderFunctions_.length === 0 && - !frameState.viewHints[ol.ViewHint.ANIMATING] && - !frameState.viewHints[ol.ViewHint.INTERACTING] && - !ol.extent.equals(frameState.extent, this.previousExtent_); - - if (idle) { - this.dispatchEvent( - new ol.MapEvent(ol.MapEventType.MOVEEND, this, frameState)); - ol.extent.clone(frameState.extent, this.previousExtent_); - } - } - - this.dispatchEvent( - new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState)); - - goog.async.nextTick(this.handlePostRender, this); - -}; - - -/** - * Sets the layergroup of this map. - * @param {ol.layer.Group} layerGroup A layer group containing the layers in - * this map. - * @observable - * @api stable - */ -ol.Map.prototype.setLayerGroup = function(layerGroup) { - this.set(ol.MapProperty.LAYERGROUP, layerGroup); -}; - - -/** - * Set the size of this map. - * @param {ol.Size|undefined} size The size in pixels of the map in the DOM. - * @observable - * @api - */ -ol.Map.prototype.setSize = function(size) { - this.set(ol.MapProperty.SIZE, size); -}; - - -/** - * Set the target element to render this map into. - * @param {Element|string|undefined} target The Element or id of the Element - * that the map is rendered in. - * @observable - * @api stable - */ -ol.Map.prototype.setTarget = function(target) { - this.set(ol.MapProperty.TARGET, target); -}; - - -/** - * Set the view for this map. - * @param {ol.View} view The view that controls this map. - * @observable - * @api stable - */ -ol.Map.prototype.setView = function(view) { - this.set(ol.MapProperty.VIEW, view); -}; - - -/** - * @param {ol.Feature} feature Feature. - */ -ol.Map.prototype.skipFeature = function(feature) { - var featureUid = goog.getUid(feature).toString(); - this.skippedFeatureUids_[featureUid] = true; - this.render(); -}; - - -/** - * Force a recalculation of the map viewport size. This should be called when - * third-party code changes the size of the map viewport. - * @api stable - */ -ol.Map.prototype.updateSize = function() { - var targetElement = this.getTargetElement(); - - if (!targetElement) { - this.setSize(undefined); - } else { - var size = goog.style.getContentBoxSize(targetElement); - this.setSize([size.width, size.height]); - } -}; - - -/** - * @param {ol.Feature} feature Feature. - */ -ol.Map.prototype.unskipFeature = function(feature) { - var featureUid = goog.getUid(feature).toString(); - delete this.skippedFeatureUids_[featureUid]; - this.render(); -}; - - -/** - * @typedef {{controls: ol.Collection.<ol.control.Control>, - * interactions: ol.Collection.<ol.interaction.Interaction>, - * keyboardEventTarget: (Element|Document), - * logos: Object.<string, string>, - * overlays: ol.Collection.<ol.Overlay>, - * rendererConstructor: - * function(new: ol.renderer.Map, Element, ol.Map), - * values: Object.<string, *>}} - */ -ol.MapOptionsInternal; - - -/** - * @param {olx.MapOptions} options Map options. - * @return {ol.MapOptionsInternal} Internal map options. - */ -ol.Map.createOptionsInternal = function(options) { - - /** - * @type {Element|Document} - */ - var keyboardEventTarget = null; - if (options.keyboardEventTarget !== undefined) { - // cannot use goog.dom.getElement because its argument cannot be - // of type Document - keyboardEventTarget = goog.isString(options.keyboardEventTarget) ? - document.getElementById(options.keyboardEventTarget) : - options.keyboardEventTarget; - } - - /** - * @type {Object.<string, *>} - */ - var values = {}; - - var logos = {}; - if (options.logo === undefined || - (goog.isBoolean(options.logo) && options.logo)) { - logos[ol.OL3_LOGO_URL] = ol.OL3_URL; - } else { - var logo = options.logo; - if (goog.isString(logo)) { - logos[logo] = ''; - } else if (goog.isObject(logo)) { - goog.asserts.assertString(logo.href, 'logo.href should be a string'); - goog.asserts.assertString(logo.src, 'logo.src should be a string'); - logos[logo.src] = logo.href; - } - } - - var layerGroup = (options.layers instanceof ol.layer.Group) ? - options.layers : new ol.layer.Group({layers: options.layers}); - values[ol.MapProperty.LAYERGROUP] = layerGroup; - - values[ol.MapProperty.TARGET] = options.target; - - values[ol.MapProperty.VIEW] = options.view !== undefined ? - options.view : new ol.View(); - - /** - * @type {function(new: ol.renderer.Map, Element, ol.Map)} - */ - var rendererConstructor = ol.renderer.Map; - - /** - * @type {Array.<ol.RendererType>} - */ - var rendererTypes; - if (options.renderer !== undefined) { - if (goog.isArray(options.renderer)) { - rendererTypes = options.renderer; - } else if (goog.isString(options.renderer)) { - rendererTypes = [options.renderer]; - } else { - goog.asserts.fail('Incorrect format for renderer option'); - } - } else { - rendererTypes = ol.DEFAULT_RENDERER_TYPES; - } - - var i, ii; - for (i = 0, ii = rendererTypes.length; i < ii; ++i) { - /** @type {ol.RendererType} */ - var rendererType = rendererTypes[i]; - if (ol.ENABLE_CANVAS && rendererType == ol.RendererType.CANVAS) { - if (ol.has.CANVAS) { - rendererConstructor = ol.renderer.canvas.Map; - break; - } - } else if (ol.ENABLE_DOM && rendererType == ol.RendererType.DOM) { - if (ol.has.DOM) { - rendererConstructor = ol.renderer.dom.Map; - break; - } - } else if (ol.ENABLE_WEBGL && rendererType == ol.RendererType.WEBGL) { - if (ol.has.WEBGL) { - rendererConstructor = ol.renderer.webgl.Map; - break; - } - } - } - - var controls; - if (options.controls !== undefined) { - if (goog.isArray(options.controls)) { - controls = new ol.Collection(options.controls.slice()); - } else { - goog.asserts.assertInstanceof(options.controls, ol.Collection, - 'options.controls should be an ol.Collection'); - controls = options.controls; - } - } else { - controls = ol.control.defaults(); - } - - var interactions; - if (options.interactions !== undefined) { - if (goog.isArray(options.interactions)) { - interactions = new ol.Collection(options.interactions.slice()); - } else { - goog.asserts.assertInstanceof(options.interactions, ol.Collection, - 'options.interactions should be an ol.Collection'); - interactions = options.interactions; - } - } else { - interactions = ol.interaction.defaults(); - } - - var overlays; - if (options.overlays !== undefined) { - if (goog.isArray(options.overlays)) { - overlays = new ol.Collection(options.overlays.slice()); - } else { - goog.asserts.assertInstanceof(options.overlays, ol.Collection, - 'options.overlays should be an ol.Collection'); - overlays = options.overlays; - } - } else { - overlays = new ol.Collection(); - } - - return { - controls: controls, - interactions: interactions, - keyboardEventTarget: keyboardEventTarget, - logos: logos, - overlays: overlays, - rendererConstructor: rendererConstructor, - values: values - }; - -}; - - -ol.proj.common.add(); - - -if (goog.DEBUG) { - (function() { - goog.debug.Console.autoInstall(); - var logger = goog.log.getLogger('ol'); - logger.setLevel(goog.log.Level.FINEST); - })(); -} - -goog.provide('ol.Overlay'); -goog.provide('ol.OverlayPositioning'); -goog.provide('ol.OverlayProperty'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.style'); -goog.require('ol.Coordinate'); -goog.require('ol.Map'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); -goog.require('ol.animation'); -goog.require('ol.dom'); -goog.require('ol.extent'); - - -/** - * @enum {string} - */ -ol.OverlayProperty = { - ELEMENT: 'element', - MAP: 'map', - OFFSET: 'offset', - POSITION: 'position', - POSITIONING: 'positioning' -}; - - -/** - * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, - * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, - * `'top-center'`, `'top-right'` - * @enum {string} - * @api stable - */ -ol.OverlayPositioning = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_CENTER: 'bottom-center', - BOTTOM_RIGHT: 'bottom-right', - CENTER_LEFT: 'center-left', - CENTER_CENTER: 'center-center', - CENTER_RIGHT: 'center-right', - TOP_LEFT: 'top-left', - TOP_CENTER: 'top-center', - TOP_RIGHT: 'top-right' -}; - - - -/** - * @classdesc - * An element to be displayed over the map and attached to a single map - * location. Like {@link ol.control.Control}, Overlays are visible widgets. - * Unlike Controls, they are not in a fixed position on the screen, but are tied - * to a geographical coordinate, so panning the map will move an Overlay but not - * a Control. - * - * Example: - * - * var popup = new ol.Overlay({ - * element: document.getElementById('popup') - * }); - * popup.setPosition(coordinate); - * map.addOverlay(popup); - * - * @constructor - * @extends {ol.Object} - * @param {olx.OverlayOptions} options Overlay options. - * @api stable - */ -ol.Overlay = function(options) { - - goog.base(this); - - /** - * @private - * @type {number|string|undefined} - */ - this.id_ = options.id; - - /** - * @private - * @type {boolean} - */ - this.insertFirst_ = options.insertFirst !== undefined ? - options.insertFirst : true; - - /** - * @private - * @type {boolean} - */ - this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true; - - /** - * @private - * @type {Element} - */ - this.element_ = goog.dom.createDom('DIV', { - 'class': 'ol-overlay-container' - }); - this.element_.style.position = 'absolute'; - - /** - * @protected - * @type {boolean} - */ - this.autoPan = options.autoPan !== undefined ? options.autoPan : false; - - /** - * @private - * @type {olx.animation.PanOptions} - */ - this.autoPanAnimation_ = options.autoPanAnimation !== undefined ? - options.autoPanAnimation : /** @type {olx.animation.PanOptions} */ ({}); - - /** - * @private - * @type {number} - */ - this.autoPanMargin_ = options.autoPanMargin !== undefined ? - options.autoPanMargin : 20; - - /** - * @private - * @type {{bottom_: string, - * left_: string, - * right_: string, - * top_: string, - * visible: boolean}} - */ - this.rendered_ = { - bottom_: '', - left_: '', - right_: '', - top_: '', - visible: true - }; - - /** - * @private - * @type {goog.events.Key} - */ - this.mapPostrenderListenerKey_ = null; - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT), - this.handleElementChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP), - this.handleMapChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET), - this.handleOffsetChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION), - this.handlePositionChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING), - this.handlePositioningChanged, false, this); - - if (options.element !== undefined) { - this.setElement(options.element); - } - - this.setOffset(options.offset !== undefined ? options.offset : [0, 0]); - - this.setPositioning(options.positioning !== undefined ? - /** @type {ol.OverlayPositioning} */ (options.positioning) : - ol.OverlayPositioning.TOP_LEFT); - - if (options.position !== undefined) { - this.setPosition(options.position); - } - -}; -goog.inherits(ol.Overlay, ol.Object); - - -/** - * Get the DOM element of this overlay. - * @return {Element|undefined} The Element containing the overlay. - * @observable - * @api stable - */ -ol.Overlay.prototype.getElement = function() { - return /** @type {Element|undefined} */ ( - this.get(ol.OverlayProperty.ELEMENT)); -}; - - -/** - * Get the overlay identifier which is set on constructor. - * @return {number|string|undefined} Id. - * @api - */ -ol.Overlay.prototype.getId = function() { - return this.id_; -}; - - -/** - * Get the map associated with this overlay. - * @return {ol.Map|undefined} The map that the overlay is part of. - * @observable - * @api stable - */ -ol.Overlay.prototype.getMap = function() { - return /** @type {ol.Map|undefined} */ ( - this.get(ol.OverlayProperty.MAP)); -}; - - -/** - * Get the offset of this overlay. - * @return {Array.<number>} The offset. - * @observable - * @api stable - */ -ol.Overlay.prototype.getOffset = function() { - return /** @type {Array.<number>} */ ( - this.get(ol.OverlayProperty.OFFSET)); -}; - - -/** - * Get the current position of this overlay. - * @return {ol.Coordinate|undefined} The spatial point that the overlay is - * anchored at. - * @observable - * @api stable - */ -ol.Overlay.prototype.getPosition = function() { - return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.OverlayProperty.POSITION)); -}; - - -/** - * Get the current positioning of this overlay. - * @return {ol.OverlayPositioning} How the overlay is positioned - * relative to its point on the map. - * @observable - * @api stable - */ -ol.Overlay.prototype.getPositioning = function() { - return /** @type {ol.OverlayPositioning} */ ( - this.get(ol.OverlayProperty.POSITIONING)); -}; - - -/** - * @protected - */ -ol.Overlay.prototype.handleElementChanged = function() { - goog.dom.removeChildren(this.element_); - var element = this.getElement(); - if (element) { - goog.dom.append(/** @type {!Node} */ (this.element_), element); - } -}; - - -/** - * @protected - */ -ol.Overlay.prototype.handleMapChanged = function() { - if (this.mapPostrenderListenerKey_) { - goog.dom.removeNode(this.element_); - goog.events.unlistenByKey(this.mapPostrenderListenerKey_); - this.mapPostrenderListenerKey_ = null; - } - var map = this.getMap(); - if (map) { - this.mapPostrenderListenerKey_ = goog.events.listen(map, - ol.MapEventType.POSTRENDER, this.render, false, this); - this.updatePixelPosition(); - var container = this.stopEvent_ ? - map.getOverlayContainerStopEvent() : map.getOverlayContainer(); - if (this.insertFirst_) { - goog.dom.insertChildAt(/** @type {!Element} */ ( - container), this.element_, 0); - } else { - goog.dom.append(/** @type {!Node} */ (container), this.element_); - } - } -}; - - -/** - * @protected - */ -ol.Overlay.prototype.render = function() { - this.updatePixelPosition(); -}; - - -/** - * @protected - */ -ol.Overlay.prototype.handleOffsetChanged = function() { - this.updatePixelPosition(); -}; - - -/** - * @protected - */ -ol.Overlay.prototype.handlePositionChanged = function() { - this.updatePixelPosition(); - if (this.get(ol.OverlayProperty.POSITION) !== undefined && this.autoPan) { - this.panIntoView_(); - } -}; - - -/** - * @protected - */ -ol.Overlay.prototype.handlePositioningChanged = function() { - this.updatePixelPosition(); -}; - - -/** - * Set the DOM element to be associated with this overlay. - * @param {Element|undefined} element The Element containing the overlay. - * @observable - * @api stable - */ -ol.Overlay.prototype.setElement = function(element) { - this.set(ol.OverlayProperty.ELEMENT, element); -}; - - -/** - * Set the map to be associated with this overlay. - * @param {ol.Map|undefined} map The map that the overlay is part of. - * @observable - * @api stable - */ -ol.Overlay.prototype.setMap = function(map) { - this.set(ol.OverlayProperty.MAP, map); -}; - - -/** - * Set the offset for this overlay. - * @param {Array.<number>} offset Offset. - * @observable - * @api stable - */ -ol.Overlay.prototype.setOffset = function(offset) { - this.set(ol.OverlayProperty.OFFSET, offset); -}; - - -/** - * Set the position for this overlay. If the position is `undefined` the - * overlay is hidden. - * @param {ol.Coordinate|undefined} position The spatial point that the overlay - * is anchored at. - * @observable - * @api stable - */ -ol.Overlay.prototype.setPosition = function(position) { - this.set(ol.OverlayProperty.POSITION, position); -}; - - -/** - * Pan the map so that the overlay is entirely visible in the current viewport - * (if necessary). - * @private - */ -ol.Overlay.prototype.panIntoView_ = function() { - goog.asserts.assert(this.autoPan, 'this.autoPan should be true'); - var map = this.getMap(); - - if (map === undefined || !map.getTargetElement()) { - return; - } - - var mapRect = this.getRect_(map.getTargetElement(), map.getSize()); - var element = this.getElement(); - goog.asserts.assert(element, 'element should be defined'); - var overlayRect = this.getRect_(element, - [ol.dom.outerWidth(element), ol.dom.outerHeight(element)]); - - var margin = this.autoPanMargin_; - if (!ol.extent.containsExtent(mapRect, overlayRect)) { - // the overlay is not completely inside the viewport, so pan the map - var offsetLeft = overlayRect[0] - mapRect[0]; - var offsetRight = mapRect[2] - overlayRect[2]; - var offsetTop = overlayRect[1] - mapRect[1]; - var offsetBottom = mapRect[3] - overlayRect[3]; - - var delta = [0, 0]; - if (offsetLeft < 0) { - // move map to the left - delta[0] = offsetLeft - margin; - } else if (offsetRight < 0) { - // move map to the right - delta[0] = Math.abs(offsetRight) + margin; - } - if (offsetTop < 0) { - // move map up - delta[1] = offsetTop - margin; - } else if (offsetBottom < 0) { - // move map down - delta[1] = Math.abs(offsetBottom) + margin; - } - - if (delta[0] !== 0 || delta[1] !== 0) { - var center = map.getView().getCenter(); - goog.asserts.assert(center !== undefined, 'center should be defined'); - var centerPx = map.getPixelFromCoordinate(center); - var newCenterPx = [ - centerPx[0] + delta[0], - centerPx[1] + delta[1] - ]; - - if (this.autoPanAnimation_) { - this.autoPanAnimation_.source = center; - map.beforeRender(ol.animation.pan(this.autoPanAnimation_)); - } - map.getView().setCenter(map.getCoordinateFromPixel(newCenterPx)); - } - } -}; - - -/** - * Get the extent of an element relative to the document - * @param {Element|undefined} element The element. - * @param {ol.Size|undefined} size The size of the element. - * @return {ol.Extent} - * @private - */ -ol.Overlay.prototype.getRect_ = function(element, size) { - goog.asserts.assert(element, 'element should be defined'); - goog.asserts.assert(size !== undefined, 'size should be defined'); - - var offset = goog.style.getPageOffset(element); - return [ - offset.x, - offset.y, - offset.x + size[0], - offset.y + size[1] - ]; -}; - - -/** - * Set the positioning for this overlay. - * @param {ol.OverlayPositioning} positioning how the overlay is - * positioned relative to its point on the map. - * @observable - * @api stable - */ -ol.Overlay.prototype.setPositioning = function(positioning) { - this.set(ol.OverlayProperty.POSITIONING, positioning); -}; - - -/** - * Modify the visibility of the element. - * @param {boolean} visible - * @protected - */ -ol.Overlay.prototype.setVisible = function(visible) { - if (this.rendered_.visible !== visible) { - goog.style.setElementShown(this.element_, visible); - this.rendered_.visible = visible; - } -}; - - -/** - * Update pixel position. - * @protected - */ -ol.Overlay.prototype.updatePixelPosition = function() { - var map = this.getMap(); - var position = this.getPosition(); - if (map === undefined || !map.isRendered() || position === undefined) { - this.setVisible(false); - return; - } - - var pixel = map.getPixelFromCoordinate(position); - var mapSize = map.getSize(); - this.updateRenderedPosition(pixel, mapSize); -}; - - -/** - * @param {ol.Pixel} pixel - * @param {ol.Size|undefined} mapSize - * @protected - */ -ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { - goog.asserts.assert(pixel, 'pixel should not be null'); - goog.asserts.assert(mapSize !== undefined, 'mapSize should be defined'); - var style = this.element_.style; - var offset = this.getOffset(); - goog.asserts.assert(goog.isArray(offset), 'offset should be an array'); - - var positioning = this.getPositioning(); - goog.asserts.assert(positioning !== undefined, - 'positioning should be defined'); - - var offsetX = offset[0]; - var offsetY = offset[1]; - if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT || - positioning == ol.OverlayPositioning.CENTER_RIGHT || - positioning == ol.OverlayPositioning.TOP_RIGHT) { - if (this.rendered_.left_ !== '') { - this.rendered_.left_ = style.left = ''; - } - var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px'; - if (this.rendered_.right_ != right) { - this.rendered_.right_ = style.right = right; - } - } else { - if (this.rendered_.right_ !== '') { - this.rendered_.right_ = style.right = ''; - } - if (positioning == ol.OverlayPositioning.BOTTOM_CENTER || - positioning == ol.OverlayPositioning.CENTER_CENTER || - positioning == ol.OverlayPositioning.TOP_CENTER) { - offsetX -= goog.style.getSize(this.element_).width / 2; - } - var left = Math.round(pixel[0] + offsetX) + 'px'; - if (this.rendered_.left_ != left) { - this.rendered_.left_ = style.left = left; - } - } - if (positioning == ol.OverlayPositioning.BOTTOM_LEFT || - positioning == ol.OverlayPositioning.BOTTOM_CENTER || - positioning == ol.OverlayPositioning.BOTTOM_RIGHT) { - if (this.rendered_.top_ !== '') { - this.rendered_.top_ = style.top = ''; - } - var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px'; - if (this.rendered_.bottom_ != bottom) { - this.rendered_.bottom_ = style.bottom = bottom; - } - } else { - if (this.rendered_.bottom_ !== '') { - this.rendered_.bottom_ = style.bottom = ''; - } - if (positioning == ol.OverlayPositioning.CENTER_LEFT || - positioning == ol.OverlayPositioning.CENTER_CENTER || - positioning == ol.OverlayPositioning.CENTER_RIGHT) { - offsetY -= goog.style.getSize(this.element_).height / 2; - } - var top = Math.round(pixel[1] + offsetY) + 'px'; - if (this.rendered_.top_ != top) { - this.rendered_.top_ = style.top = top; - } - } - - this.setVisible(true); -}; - -goog.provide('ol.control.OverviewMap'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.math.Size'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.Map'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); -goog.require('ol.ObjectEventType'); -goog.require('ol.Overlay'); -goog.require('ol.OverlayPositioning'); -goog.require('ol.View'); -goog.require('ol.ViewProperty'); -goog.require('ol.control.Control'); -goog.require('ol.coordinate'); -goog.require('ol.css'); -goog.require('ol.extent'); - - - -/** - * Create a new control with a map acting as an overview map for an other - * defined map. - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options. - * @api - */ -ol.control.OverviewMap = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - /** - * @type {boolean} - * @private - */ - this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true; - - /** - * @private - * @type {boolean} - */ - this.collapsible_ = options.collapsible !== undefined ? - options.collapsible : true; - - if (!this.collapsible_) { - this.collapsed_ = false; - } - - var className = options.className ? options.className : 'ol-overviewmap'; - - var tipLabel = options.tipLabel ? options.tipLabel : 'Overview map'; - - var collapseLabel = options.collapseLabel ? options.collapseLabel : '\u00AB'; - - /** - * @private - * @type {Node} - */ - this.collapseLabel_ = goog.isString(collapseLabel) ? - goog.dom.createDom('SPAN', {}, collapseLabel) : - collapseLabel; - - var label = options.label ? options.label : '\u00BB'; - - /** - * @private - * @type {Node} - */ - this.label_ = goog.isString(label) ? - goog.dom.createDom('SPAN', {}, label) : - label; - - var activeLabel = (this.collapsible_ && !this.collapsed_) ? - this.collapseLabel_ : this.label_; - var button = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'title': tipLabel - }, activeLabel); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - - var ovmapDiv = goog.dom.createDom('DIV', 'ol-overviewmap-map'); - - /** - * @type {ol.Map} - * @private - */ - this.ovmap_ = new ol.Map({ - controls: new ol.Collection(), - interactions: new ol.Collection(), - target: ovmapDiv, - view: options.view - }); - var ovmap = this.ovmap_; - - if (options.layers) { - options.layers.forEach( - /** - * @param {ol.layer.Layer} layer Layer. - */ - function(layer) { - ovmap.addLayer(layer); - }, this); - } - - var box = goog.dom.createDom('DIV', 'ol-overviewmap-box'); - - /** - * @type {ol.Overlay} - * @private - */ - this.boxOverlay_ = new ol.Overlay({ - position: [0, 0], - positioning: ol.OverlayPositioning.BOTTOM_LEFT, - element: box - }); - this.ovmap_.addOverlay(this.boxOverlay_); - - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL + - (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') + - (this.collapsible_ ? '' : ' ol-uncollapsible'); - var element = goog.dom.createDom('DIV', - cssClasses, ovmapDiv, button); - - var render = options.render ? options.render : ol.control.OverviewMap.render; - - goog.base(this, { - element: element, - render: render, - target: options.target - }); -}; -goog.inherits(ol.control.OverviewMap, ol.control.Control); - - -/** - * @inheritDoc - * @api - */ -ol.control.OverviewMap.prototype.setMap = function(map) { - var oldMap = this.getMap(); - if (map === oldMap) { - return; - } - if (oldMap) { - var oldView = oldMap.getView(); - if (oldView) { - this.unbindView_(oldView); - } - } - goog.base(this, 'setMap', map); - - if (map) { - this.listenerKeys.push(goog.events.listen( - map, ol.ObjectEventType.PROPERTYCHANGE, - this.handleMapPropertyChange_, false, this)); - - // TODO: to really support map switching, this would need to be reworked - if (this.ovmap_.getLayers().getLength() === 0) { - this.ovmap_.setLayerGroup(map.getLayerGroup()); - } - - var view = map.getView(); - if (view) { - this.bindView_(view); - if (view.isDef()) { - this.ovmap_.updateSize(); - this.resetExtent_(); - } - } - } -}; - - -/** - * Handle map property changes. This only deals with changes to the map's view. - * @param {ol.ObjectEvent} event The propertychange event. - * @private - */ -ol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) { - if (event.key === ol.MapProperty.VIEW) { - var oldView = /** @type {ol.View} */ (event.oldValue); - if (oldView) { - this.unbindView_(oldView); - } - var newView = this.getMap().getView(); - this.bindView_(newView); - } -}; - - -/** - * Register listeners for view property changes. - * @param {ol.View} view The view. - * @private - */ -ol.control.OverviewMap.prototype.bindView_ = function(view) { - goog.events.listen(view, - ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), - this.handleRotationChanged_, false, this); -}; - - -/** - * Unregister listeners for view property changes. - * @param {ol.View} view The view. - * @private - */ -ol.control.OverviewMap.prototype.unbindView_ = function(view) { - goog.events.unlisten(view, - ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), - this.handleRotationChanged_, false, this); -}; - - -/** - * Handle rotation changes to the main map. - * TODO: This should rotate the extent rectrangle instead of the - * overview map's view. - * @private - */ -ol.control.OverviewMap.prototype.handleRotationChanged_ = function() { - this.ovmap_.getView().setRotation(this.getMap().getView().getRotation()); -}; - - -/** - * Update the overview map element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.OverviewMap} - * @api - */ -ol.control.OverviewMap.render = function(mapEvent) { - this.validateExtent_(); - this.updateBox_(); -}; - - -/** - * Reset the overview map extent if the box size (width or - * height) is less than the size of the overview map size times minRatio - * or is greater than the size of the overview size times maxRatio. - * - * If the map extent was not reset, the box size can fits in the defined - * ratio sizes. This method then checks if is contained inside the overview - * map current extent. If not, recenter the overview map to the current - * main map center location. - * @private - */ -ol.control.OverviewMap.prototype.validateExtent_ = function() { - var map = this.getMap(); - var ovmap = this.ovmap_; - - if (!map.isRendered() || !ovmap.isRendered()) { - return; - } - - var mapSize = map.getSize(); - goog.asserts.assertArray(mapSize, 'mapSize should be an array'); - - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - var extent = view.calculateExtent(mapSize); - - var ovmapSize = ovmap.getSize(); - goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - var ovextent = ovview.calculateExtent(ovmapSize); - - var topLeftPixel = - ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent)); - var bottomRightPixel = - ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent)); - var boxSize = new goog.math.Size( - Math.abs(topLeftPixel[0] - bottomRightPixel[0]), - Math.abs(topLeftPixel[1] - bottomRightPixel[1])); - - var ovmapWidth = ovmapSize[0]; - var ovmapHeight = ovmapSize[1]; - - if (boxSize.width < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO || - boxSize.height < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO || - boxSize.width > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO || - boxSize.height > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) { - this.resetExtent_(); - } else if (!ol.extent.containsExtent(ovextent, extent)) { - this.recenter_(); - } -}; - - -/** - * Reset the overview map extent to half calculated min and max ratio times - * the extent of the main map. - * @private - */ -ol.control.OverviewMap.prototype.resetExtent_ = function() { - if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) { - return; - } - - var map = this.getMap(); - var ovmap = this.ovmap_; - - var mapSize = map.getSize(); - goog.asserts.assertArray(mapSize, 'mapSize should be an array'); - - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - var extent = view.calculateExtent(mapSize); - - var ovmapSize = ovmap.getSize(); - goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - - // get how many times the current map overview could hold different - // box sizes using the min and max ratio, pick the step in the middle used - // to calculate the extent from the main map to set it to the overview map, - var steps = Math.log( - ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2; - var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO); - ol.extent.scaleFromCenter(extent, ratio); - ovview.fit(extent, ovmapSize); -}; - - -/** - * Set the center of the overview map to the map center without changing its - * resolution. - * @private - */ -ol.control.OverviewMap.prototype.recenter_ = function() { - var map = this.getMap(); - var ovmap = this.ovmap_; - - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - - ovview.setCenter(view.getCenter()); -}; - - -/** - * Update the box using the main map extent - * @private - */ -ol.control.OverviewMap.prototype.updateBox_ = function() { - var map = this.getMap(); - var ovmap = this.ovmap_; - - if (!map.isRendered() || !ovmap.isRendered()) { - return; - } - - var mapSize = map.getSize(); - goog.asserts.assertArray(mapSize, 'mapSize should be an array'); - - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - - var ovmapSize = ovmap.getSize(); - goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); - - var rotation = view.getRotation(); - goog.asserts.assert(rotation !== undefined, 'rotation should be defined'); - - var overlay = this.boxOverlay_; - var box = this.boxOverlay_.getElement(); - var extent = view.calculateExtent(mapSize); - var ovresolution = ovview.getResolution(); - var bottomLeft = ol.extent.getBottomLeft(extent); - var topRight = ol.extent.getTopRight(extent); - - // set position using bottom left coordinates - var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft); - overlay.setPosition(rotateBottomLeft); - - // set box size calculated from map extent size and overview map resolution - if (box) { - var boxWidth = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution); - var boxHeight = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution); - goog.style.setBorderBoxSize(box, new goog.math.Size( - boxWidth, boxHeight)); - } -}; - - -/** - * @param {number} rotation Target rotation. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor. - * @private - */ -ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function( - rotation, coordinate) { - var coordinateRotate; - - var map = this.getMap(); - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - - var currentCenter = view.getCenter(); - - if (currentCenter) { - coordinateRotate = [ - coordinate[0] - currentCenter[0], - coordinate[1] - currentCenter[1] - ]; - ol.coordinate.rotate(coordinateRotate, rotation); - ol.coordinate.add(coordinateRotate, currentCenter); - } - return coordinateRotate; -}; - - -/** - * @param {goog.events.BrowserEvent} event The event to handle - * @private - */ -ol.control.OverviewMap.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleToggle_(); -}; - - -/** - * @private - */ -ol.control.OverviewMap.prototype.handleToggle_ = function() { - goog.dom.classlist.toggle(this.element, 'ol-collapsed'); - if (this.collapsed_) { - goog.dom.replaceNode(this.collapseLabel_, this.label_); - } else { - goog.dom.replaceNode(this.label_, this.collapseLabel_); - } - this.collapsed_ = !this.collapsed_; - - // manage overview map if it had not been rendered before and control - // is expanded - var ovmap = this.ovmap_; - if (!this.collapsed_ && !ovmap.isRendered()) { - ovmap.updateSize(); - this.resetExtent_(); - goog.events.listenOnce(ovmap, ol.MapEventType.POSTRENDER, - function(event) { - this.updateBox_(); - }, - false, this); - } -}; - - -/** - * Return `true` if the overview map is collapsible, `false` otherwise. - * @return {boolean} True if the widget is collapsible. - * @api stable - */ -ol.control.OverviewMap.prototype.getCollapsible = function() { - return this.collapsible_; -}; - - -/** - * Set whether the overview map should be collapsible. - * @param {boolean} collapsible True if the widget is collapsible. - * @api stable - */ -ol.control.OverviewMap.prototype.setCollapsible = function(collapsible) { - if (this.collapsible_ === collapsible) { - return; - } - this.collapsible_ = collapsible; - goog.dom.classlist.toggle(this.element, 'ol-uncollapsible'); - if (!collapsible && this.collapsed_) { - this.handleToggle_(); - } -}; - - -/** - * Collapse or expand the overview map according to the passed parameter. Will - * not do anything if the overview map isn't collapsible or if the current - * collapsed state is already the one requested. - * @param {boolean} collapsed True if the widget is collapsed. - * @api stable - */ -ol.control.OverviewMap.prototype.setCollapsed = function(collapsed) { - if (!this.collapsible_ || this.collapsed_ === collapsed) { - return; - } - this.handleToggle_(); -}; - - -/** - * Determine if the overview map is collapsed. - * @return {boolean} The overview map is collapsed. - * @api stable - */ -ol.control.OverviewMap.prototype.getCollapsed = function() { - return this.collapsed_; -}; - - -/** - * Return the overview map. - * @return {ol.Map} Overview map. - * @api - */ -ol.control.OverviewMap.prototype.getOverviewMap = function() { - return this.ovmap_; -}; - -goog.provide('ol.control.ScaleLine'); -goog.provide('ol.control.ScaleLineProperty'); -goog.provide('ol.control.ScaleLineUnits'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.TransformFunction'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Units'); -goog.require('ol.sphere.NORMAL'); - - -/** - * @enum {string} - */ -ol.control.ScaleLineProperty = { - UNITS: 'units' -}; - - -/** - * Units for the scale line. Supported values are `'degrees'`, `'imperial'`, - * `'nautical'`, `'metric'`, `'us'`. - * @enum {string} - * @api stable - */ -ol.control.ScaleLineUnits = { - DEGREES: 'degrees', - IMPERIAL: 'imperial', - NAUTICAL: 'nautical', - METRIC: 'metric', - US: 'us' -}; - - - -/** - * @classdesc - * A control displaying rough x-axis distances, calculated for the center of the - * viewport. - * No scale line will be shown when the x-axis distance cannot be calculated in - * the view projection (e.g. at or beyond the poles in EPSG:4326). - * By default the scale line will show in the bottom left portion of the map, - * but this can be changed by using the css selector `.ol-scale-line`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ScaleLineOptions=} opt_options Scale line options. - * @api stable - */ -ol.control.ScaleLine = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var className = options.className ? options.className : 'ol-scale-line'; - - /** - * @private - * @type {Element} - */ - this.innerElement_ = goog.dom.createDom('DIV', - className + '-inner'); - - /** - * @private - * @type {Element} - */ - this.element_ = goog.dom.createDom('DIV', - className + ' ' + ol.css.CLASS_UNSELECTABLE, this.innerElement_); - - /** - * @private - * @type {?olx.ViewState} - */ - this.viewState_ = null; - - /** - * @private - * @type {number} - */ - this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64; - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = false; - - /** - * @private - * @type {number|undefined} - */ - this.renderedWidth_ = undefined; - - /** - * @private - * @type {string} - */ - this.renderedHTML_ = ''; - - /** - * @private - * @type {?ol.TransformFunction} - */ - this.toEPSG4326_ = null; - - var render = options.render ? options.render : ol.control.ScaleLine.render; - - goog.base(this, { - element: this.element_, - render: render, - target: options.target - }); - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.control.ScaleLineProperty.UNITS), - this.handleUnitsChanged_, false, this); - - this.setUnits(/** @type {ol.control.ScaleLineUnits} */ (options.units) || - ol.control.ScaleLineUnits.METRIC); - -}; -goog.inherits(ol.control.ScaleLine, ol.control.Control); - - -/** - * @const - * @type {Array.<number>} - */ -ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5]; - - -/** - * Return the units to use in the scale line. - * @return {ol.control.ScaleLineUnits|undefined} The units to use in the scale - * line. - * @observable - * @api stable - */ -ol.control.ScaleLine.prototype.getUnits = function() { - return /** @type {ol.control.ScaleLineUnits|undefined} */ ( - this.get(ol.control.ScaleLineProperty.UNITS)); -}; - - -/** - * Update the scale line element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.ScaleLine} - * @api - */ -ol.control.ScaleLine.render = function(mapEvent) { - var frameState = mapEvent.frameState; - if (!frameState) { - this.viewState_ = null; - } else { - this.viewState_ = frameState.viewState; - } - this.updateElement_(); -}; - - -/** - * @private - */ -ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() { - this.updateElement_(); -}; - - -/** - * Set the units to use in the scale line. - * @param {ol.control.ScaleLineUnits} units The units to use in the scale line. - * @observable - * @api stable - */ -ol.control.ScaleLine.prototype.setUnits = function(units) { - this.set(ol.control.ScaleLineProperty.UNITS, units); -}; - - -/** - * @private - */ -ol.control.ScaleLine.prototype.updateElement_ = function() { - var viewState = this.viewState_; - - if (!viewState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.element_, false); - this.renderedVisible_ = false; - } - return; - } - - var center = viewState.center; - var projection = viewState.projection; - var pointResolution = - projection.getPointResolution(viewState.resolution, center); - var projectionUnits = projection.getUnits(); - - var cosLatitude; - var units = this.getUnits(); - if (projectionUnits == ol.proj.Units.DEGREES && - (units == ol.control.ScaleLineUnits.METRIC || - units == ol.control.ScaleLineUnits.IMPERIAL || - units == ol.control.ScaleLineUnits.US || - units == ol.control.ScaleLineUnits.NAUTICAL)) { - - // Convert pointResolution from degrees to meters - this.toEPSG4326_ = null; - cosLatitude = Math.cos(ol.math.toRadians(center[1])); - pointResolution *= Math.PI * cosLatitude * ol.sphere.NORMAL.radius / 180; - projectionUnits = ol.proj.Units.METERS; - - } else if (projectionUnits != ol.proj.Units.DEGREES && - units == ol.control.ScaleLineUnits.DEGREES) { - - // Convert pointResolution from other units to degrees - if (!this.toEPSG4326_) { - this.toEPSG4326_ = ol.proj.getTransformFromProjections( - projection, ol.proj.get('EPSG:4326')); - } - cosLatitude = Math.cos(ol.math.toRadians(this.toEPSG4326_(center)[1])); - var radius = ol.sphere.NORMAL.radius; - goog.asserts.assert(ol.proj.METERS_PER_UNIT[projectionUnits], - 'Meters per unit should be defined for the projection unit'); - radius /= ol.proj.METERS_PER_UNIT[projectionUnits]; - pointResolution *= 180 / (Math.PI * cosLatitude * radius); - projectionUnits = ol.proj.Units.DEGREES; - - } else { - this.toEPSG4326_ = null; - } - - goog.asserts.assert( - ((units == ol.control.ScaleLineUnits.METRIC || - units == ol.control.ScaleLineUnits.IMPERIAL || - units == ol.control.ScaleLineUnits.US || - units == ol.control.ScaleLineUnits.NAUTICAL) && - projectionUnits == ol.proj.Units.METERS) || - (units == ol.control.ScaleLineUnits.DEGREES && - projectionUnits == ol.proj.Units.DEGREES), - 'Scale line units and projection units should match'); - - var nominalCount = this.minWidth_ * pointResolution; - var suffix = ''; - if (units == ol.control.ScaleLineUnits.DEGREES) { - if (nominalCount < 1 / 60) { - suffix = '\u2033'; // seconds - pointResolution *= 3600; - } else if (nominalCount < 1) { - suffix = '\u2032'; // minutes - pointResolution *= 60; - } else { - suffix = '\u00b0'; // degrees - } - } else if (units == ol.control.ScaleLineUnits.IMPERIAL) { - if (nominalCount < 0.9144) { - suffix = 'in'; - pointResolution /= 0.0254; - } else if (nominalCount < 1609.344) { - suffix = 'ft'; - pointResolution /= 0.3048; - } else { - suffix = 'mi'; - pointResolution /= 1609.344; - } - } else if (units == ol.control.ScaleLineUnits.NAUTICAL) { - pointResolution /= 1852; - suffix = 'nm'; - } else if (units == ol.control.ScaleLineUnits.METRIC) { - if (nominalCount < 1) { - suffix = 'mm'; - pointResolution *= 1000; - } else if (nominalCount < 1000) { - suffix = 'm'; - } else { - suffix = 'km'; - pointResolution /= 1000; - } - } else if (units == ol.control.ScaleLineUnits.US) { - if (nominalCount < 0.9144) { - suffix = 'in'; - pointResolution *= 39.37; - } else if (nominalCount < 1609.344) { - suffix = 'ft'; - pointResolution /= 0.30480061; - } else { - suffix = 'mi'; - pointResolution /= 1609.3472; - } - } else { - goog.asserts.fail('Scale line element cannot be updated'); - } - - var i = 3 * Math.floor( - Math.log(this.minWidth_ * pointResolution) / Math.log(10)); - var count, width; - while (true) { - count = ol.control.ScaleLine.LEADING_DIGITS[i % 3] * - Math.pow(10, Math.floor(i / 3)); - width = Math.round(count / pointResolution); - if (isNaN(width)) { - goog.style.setElementShown(this.element_, false); - this.renderedVisible_ = false; - return; - } else if (width >= this.minWidth_) { - break; - } - ++i; - } - - var html = count + ' ' + suffix; - if (this.renderedHTML_ != html) { - this.innerElement_.innerHTML = html; - this.renderedHTML_ = html; - } - - if (this.renderedWidth_ != width) { - this.innerElement_.style.width = width + 'px'; - this.renderedWidth_ = width; - } - - if (!this.renderedVisible_) { - goog.style.setElementShown(this.element_, true); - this.renderedVisible_ = true; - } - -}; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Class to create objects which want to handle multiple events - * and have their listeners easily cleaned up via a dispose method. - * - * Example: - * <pre> - * function Something() { - * Something.base(this); - * - * ... set up object ... - * - * // Add event listeners - * this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar); - * this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand); - * this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse); - * this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover); - * this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover); - * } - * goog.inherits(Something, goog.events.EventHandler); - * - * Something.prototype.disposeInternal = function() { - * Something.base(this, 'disposeInternal'); - * goog.dom.removeNode(this.container); - * }; - * - * - * // Then elsewhere: - * - * var activeSomething = null; - * function openSomething() { - * activeSomething = new Something(); - * } - * - * function closeSomething() { - * if (activeSomething) { - * activeSomething.dispose(); // Remove event listeners - * activeSomething = null; - * } - * } - * </pre> - * - */ - -goog.provide('goog.events.EventHandler'); - -goog.require('goog.Disposable'); -goog.require('goog.events'); -goog.require('goog.object'); - -goog.forwardDeclare('goog.events.EventWrapper'); - - - -/** - * Super class for objects that want to easily manage a number of event - * listeners. It allows a short cut to listen and also provides a quick way - * to remove all events listeners belonging to this object. - * @param {SCOPE=} opt_scope Object in whose scope to call the listeners. - * @constructor - * @extends {goog.Disposable} - * @template SCOPE - */ -goog.events.EventHandler = function(opt_scope) { - goog.Disposable.call(this); - // TODO(mknichel): Rename this to this.scope_ and fix the classes in google3 - // that access this private variable. :( - this.handler_ = opt_scope; - - /** - * Keys for events that are being listened to. - * @type {!Object<!goog.events.Key>} - * @private - */ - this.keys_ = {}; -}; -goog.inherits(goog.events.EventHandler, goog.Disposable); - - -/** - * Utility array used to unify the cases of listening for an array of types - * and listening for a single event, without using recursion or allocating - * an array each time. - * @type {!Array<string>} - * @const - * @private - */ -goog.events.EventHandler.typeArray_ = []; - - -/** - * Listen to an event on a Listenable. If the function is omitted then the - * EventHandler's handleEvent method will be used. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} - * opt_fn Optional callback function to be used as the listener or an object - * with handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ - */ -goog.events.EventHandler.prototype.listen = function( - src, type, opt_fn, opt_capture) { - return this.listen_(src, type, opt_fn, opt_capture); -}; - - -/** - * Listen to an event on a Listenable. If the function is omitted then the - * EventHandler's handleEvent method will be used. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| - * null|undefined} fn Optional callback function to be used as the - * listener or an object with handleEvent function. - * @param {boolean|undefined} capture Optional whether to use capture phase. - * @param {T} scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template T,EVENTOBJ - */ -goog.events.EventHandler.prototype.listenWithScope = function( - src, type, fn, capture, scope) { - // TODO(mknichel): Deprecate this function. - return this.listen_(src, type, fn, capture, scope); -}; - - -/** - * Listen to an event on a Listenable. If the function is omitted then the - * EventHandler's handleEvent method will be used. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @param {Object=} opt_scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ - * @private - */ -goog.events.EventHandler.prototype.listen_ = function(src, type, opt_fn, - opt_capture, - opt_scope) { - if (!goog.isArray(type)) { - if (type) { - goog.events.EventHandler.typeArray_[0] = type.toString(); - } - type = goog.events.EventHandler.typeArray_; - } - for (var i = 0; i < type.length; i++) { - var listenerObj = goog.events.listen( - src, type[i], opt_fn || this.handleEvent, - opt_capture || false, - opt_scope || this.handler_ || this); - - if (!listenerObj) { - // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT - // (goog.events.CaptureSimulationMode) in IE8-, it will return null - // value. - return this; - } - - var key = listenerObj.key; - this.keys_[key] = listenerObj; - } - - return this; -}; - - -/** - * Listen to an event on a Listenable. If the function is omitted, then the - * EventHandler's handleEvent method will be used. After the event has fired the - * event listener is removed from the target. If an array of event types is - * provided, each event type will be listened to once. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ - */ -goog.events.EventHandler.prototype.listenOnce = function( - src, type, opt_fn, opt_capture) { - return this.listenOnce_(src, type, opt_fn, opt_capture); -}; - - -/** - * Listen to an event on a Listenable. If the function is omitted, then the - * EventHandler's handleEvent method will be used. After the event has fired the - * event listener is removed from the target. If an array of event types is - * provided, each event type will be listened to once. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| - * null|undefined} fn Optional callback function to be used as the - * listener or an object with handleEvent function. - * @param {boolean|undefined} capture Optional whether to use capture phase. - * @param {T} scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template T,EVENTOBJ - */ -goog.events.EventHandler.prototype.listenOnceWithScope = function( - src, type, fn, capture, scope) { - // TODO(mknichel): Deprecate this function. - return this.listenOnce_(src, type, fn, capture, scope); -}; - - -/** - * Listen to an event on a Listenable. If the function is omitted, then the - * EventHandler's handleEvent method will be used. After the event has fired - * the event listener is removed from the target. If an array of event types is - * provided, each event type will be listened to once. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @param {Object=} opt_scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ - * @private - */ -goog.events.EventHandler.prototype.listenOnce_ = function( - src, type, opt_fn, opt_capture, opt_scope) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - this.listenOnce_(src, type[i], opt_fn, opt_capture, opt_scope); - } - } else { - var listenerObj = goog.events.listenOnce( - src, type, opt_fn || this.handleEvent, opt_capture, - opt_scope || this.handler_ || this); - if (!listenerObj) { - // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT - // (goog.events.CaptureSimulationMode) in IE8-, it will return null - // value. - return this; - } - - var key = listenerObj.key; - this.keys_[key] = listenerObj; - } - - return this; -}; - - -/** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.EventTarget}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.EventTarget} src The node to listen to - * events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener - * Callback method, or an object with a handleEvent function. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - */ -goog.events.EventHandler.prototype.listenWithWrapper = function( - src, wrapper, listener, opt_capt) { - // TODO(mknichel): Remove the opt_scope from this function and then - // templatize it. - return this.listenWithWrapper_(src, wrapper, listener, opt_capt); -}; - - -/** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.EventTarget}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.EventTarget} src The node to listen to - * events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null} - * listener Optional callback function to be used as the - * listener or an object with handleEvent function. - * @param {boolean|undefined} capture Optional whether to use capture phase. - * @param {T} scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template T - */ -goog.events.EventHandler.prototype.listenWithWrapperAndScope = function( - src, wrapper, listener, capture, scope) { - // TODO(mknichel): Deprecate this function. - return this.listenWithWrapper_(src, wrapper, listener, capture, scope); -}; - - -/** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.EventTarget}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.EventTarget} src The node to listen to - * events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback - * method, or an object with a handleEvent function. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {Object=} opt_scope Element in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @private - */ -goog.events.EventHandler.prototype.listenWithWrapper_ = function( - src, wrapper, listener, opt_capt, opt_scope) { - wrapper.listen(src, listener, opt_capt, opt_scope || this.handler_ || this, - this); - return this; -}; - - -/** - * @return {number} Number of listeners registered by this handler. - */ -goog.events.EventHandler.prototype.getListenerCount = function() { - var count = 0; - for (var key in this.keys_) { - if (Object.prototype.hasOwnProperty.call(this.keys_, key)) { - count++; - } - } - return count; -}; - - -/** - * Unlistens on an event. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types to unlisten to. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @param {Object=} opt_scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler} This object, allowing for chaining of - * calls. - * @template EVENTOBJ - */ -goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn, - opt_capture, - opt_scope) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - this.unlisten(src, type[i], opt_fn, opt_capture, opt_scope); - } - } else { - var listener = goog.events.getListener(src, type, - opt_fn || this.handleEvent, - opt_capture, opt_scope || this.handler_ || this); - - if (listener) { - goog.events.unlistenByKey(listener); - delete this.keys_[listener.key]; - } - } - - return this; -}; - - -/** - * Removes an event listener which was added with listenWithWrapper(). - * - * @param {EventTarget|goog.events.EventTarget} src The target to stop - * listening to events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener The - * listener function to remove. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase of the - * event. - * @param {Object=} opt_scope Element in whose scope to call the listener. - * @return {!goog.events.EventHandler} This object, allowing for chaining of - * calls. - */ -goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper, - listener, opt_capt, opt_scope) { - wrapper.unlisten(src, listener, opt_capt, - opt_scope || this.handler_ || this, this); - return this; -}; - - -/** - * Unlistens to all events. - */ -goog.events.EventHandler.prototype.removeAll = function() { - goog.object.forEach(this.keys_, function(listenerObj, key) { - if (this.keys_.hasOwnProperty(key)) { - goog.events.unlistenByKey(listenerObj); - } - }, this); - - this.keys_ = {}; -}; - - -/** - * Disposes of this EventHandler and removes all listeners that it registered. - * @override - * @protected - */ -goog.events.EventHandler.prototype.disposeInternal = function() { - goog.events.EventHandler.superClass_.disposeInternal.call(this); - this.removeAll(); -}; - - -/** - * Default event handler - * @param {goog.events.Event} e Event object. - */ -goog.events.EventHandler.prototype.handleEvent = function(e) { - throw Error('EventHandler.handleEvent not implemented'); -}; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Bidi utility functions. - * - */ - -goog.provide('goog.style.bidi'); - -goog.require('goog.dom'); -goog.require('goog.style'); -goog.require('goog.userAgent'); - - -/** - * Returns the normalized scrollLeft position for a scrolled element. - * @param {Element} element The scrolled element. - * @return {number} The number of pixels the element is scrolled. 0 indicates - * that the element is not scrolled at all (which, in general, is the - * left-most position in ltr and the right-most position in rtl). - */ -goog.style.bidi.getScrollLeft = function(element) { - var isRtl = goog.style.isRightToLeft(element); - if (isRtl && goog.userAgent.GECKO) { - // ScrollLeft starts at 0 and then goes negative as the element is scrolled - // towards the left. - return -element.scrollLeft; - } else if (isRtl && - !(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8'))) { - // ScrollLeft starts at the maximum positive value and decreases towards - // 0 as the element is scrolled towards the left. However, for overflow - // visible, there is no scrollLeft and the value always stays correctly at 0 - var overflowX = goog.style.getComputedOverflowX(element); - if (overflowX == 'visible') { - return element.scrollLeft; - } else { - return element.scrollWidth - element.clientWidth - element.scrollLeft; - } - } - // ScrollLeft behavior is identical in rtl and ltr, it starts at 0 and - // increases as the element is scrolled away from the start. - return element.scrollLeft; -}; - - -/** - * Returns the "offsetStart" of an element, analagous to offsetLeft but - * normalized for right-to-left environments and various browser - * inconsistencies. This value returned can always be passed to setScrollOffset - * to scroll to an element's left edge in a left-to-right offsetParent or - * right edge in a right-to-left offsetParent. - * - * For example, here offsetStart is 10px in an LTR environment and 5px in RTL: - * - * <pre> - * | xxxxxxxxxx | - * ^^^^^^^^^^ ^^^^ ^^^^^ - * 10px elem 5px - * </pre> - * - * If an element is positioned before the start of its offsetParent, the - * startOffset may be negative. This can be used with setScrollOffset to - * reliably scroll to an element: - * - * <pre> - * var scrollOffset = goog.style.bidi.getOffsetStart(element); - * goog.style.bidi.setScrollOffset(element.offsetParent, scrollOffset); - * </pre> - * - * @see setScrollOffset - * - * @param {Element} element The element for which we need to determine the - * offsetStart position. - * @return {number} The offsetStart for that element. - */ -goog.style.bidi.getOffsetStart = function(element) { - element = /** @type {!HTMLElement} */ (element); - var offsetLeftForReal = element.offsetLeft; - - // The element might not have an offsetParent. - // For example, the node might not be attached to the DOM tree, - // and position:fixed children do not have an offset parent. - // Just try to do the best we can with what we have. - var bestParent = element.offsetParent; - - if (!bestParent && goog.style.getComputedPosition(element) == 'fixed') { - bestParent = goog.dom.getOwnerDocument(element).documentElement; - } - - // Just give up in this case. - if (!bestParent) { - return offsetLeftForReal; - } - - if (goog.userAgent.GECKO) { - // When calculating an element's offsetLeft, Firefox erroneously subtracts - // the border width from the actual distance. So we need to add it back. - var borderWidths = goog.style.getBorderBox(bestParent); - offsetLeftForReal += borderWidths.left; - } else if (goog.userAgent.isDocumentModeOrHigher(8) && - !goog.userAgent.isDocumentModeOrHigher(9)) { - // When calculating an element's offsetLeft, IE8/9-Standards Mode - // erroneously adds the border width to the actual distance. So we need to - // subtract it. - var borderWidths = goog.style.getBorderBox(bestParent); - offsetLeftForReal -= borderWidths.left; - } - - if (goog.style.isRightToLeft(bestParent)) { - // Right edge of the element relative to the left edge of its parent. - var elementRightOffset = offsetLeftForReal + element.offsetWidth; - - // Distance from the parent's right edge to the element's right edge. - return bestParent.clientWidth - elementRightOffset; - } - - return offsetLeftForReal; -}; - - -/** - * Sets the element's scrollLeft attribute so it is correctly scrolled by - * offsetStart pixels. This takes into account whether the element is RTL and - * the nuances of different browsers. To scroll to the "beginning" of an - * element use getOffsetStart to obtain the element's offsetStart value and then - * pass the value to setScrollOffset. - * @see getOffsetStart - * @param {Element} element The element to set scrollLeft on. - * @param {number} offsetStart The number of pixels to scroll the element. - * If this value is < 0, 0 is used. - */ -goog.style.bidi.setScrollOffset = function(element, offsetStart) { - offsetStart = Math.max(offsetStart, 0); - // In LTR and in "mirrored" browser RTL (such as IE), we set scrollLeft to - // the number of pixels to scroll. - // Otherwise, in RTL, we need to account for different browser behavior. - if (!goog.style.isRightToLeft(element)) { - element.scrollLeft = offsetStart; - } else if (goog.userAgent.GECKO) { - // Negative scroll-left positions in RTL. - element.scrollLeft = -offsetStart; - } else if (!(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8'))) { - // Take the current scrollLeft value and move to the right by the - // offsetStart to get to the left edge of the element, and then by - // the clientWidth of the element to get to the right edge. - element.scrollLeft = - element.scrollWidth - offsetStart - element.clientWidth; - } else { - element.scrollLeft = offsetStart; - } -}; - - -/** - * Sets the element's left style attribute in LTR or right style attribute in - * RTL. Also clears the left attribute in RTL and the right attribute in LTR. - * @param {Element} elem The element to position. - * @param {number} left The left position in LTR; will be set as right in RTL. - * @param {?number} top The top position. If null only the left/right is set. - * @param {boolean} isRtl Whether we are in RTL mode. - */ -goog.style.bidi.setPosition = function(elem, left, top, isRtl) { - if (!goog.isNull(top)) { - elem.style.top = top + 'px'; - } - if (isRtl) { - elem.style.right = left + 'px'; - elem.style.left = ''; - } else { - elem.style.left = left + 'px'; - elem.style.right = ''; - } -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Drag Utilities. - * - * Provides extensible functionality for drag & drop behaviour. - * - * @see ../demos/drag.html - * @see ../demos/dragger.html - */ - - -goog.provide('goog.fx.DragEvent'); -goog.provide('goog.fx.Dragger'); -goog.provide('goog.fx.Dragger.EventType'); - -goog.require('goog.dom'); -goog.require('goog.dom.TagName'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Rect'); -goog.require('goog.style'); -goog.require('goog.style.bidi'); -goog.require('goog.userAgent'); - - - -/** - * A class that allows mouse or touch-based dragging (moving) of an element - * - * @param {Element} target The element that will be dragged. - * @param {Element=} opt_handle An optional handle to control the drag, if null - * the target is used. - * @param {goog.math.Rect=} opt_limits Object containing left, top, width, - * and height. - * - * @extends {goog.events.EventTarget} - * @constructor - * @struct - */ -goog.fx.Dragger = function(target, opt_handle, opt_limits) { - goog.fx.Dragger.base(this, 'constructor'); - - /** - * Reference to drag target element. - * @type {?Element} - */ - this.target = target; - - /** - * Reference to the handler that initiates the drag. - * @type {?Element} - */ - this.handle = opt_handle || target; - - /** - * Object representing the limits of the drag region. - * @type {goog.math.Rect} - */ - this.limits = opt_limits || new goog.math.Rect(NaN, NaN, NaN, NaN); - - /** - * Reference to a document object to use for the events. - * @private {Document} - */ - this.document_ = goog.dom.getOwnerDocument(target); - - /** @private {!goog.events.EventHandler} */ - this.eventHandler_ = new goog.events.EventHandler(this); - this.registerDisposable(this.eventHandler_); - - /** - * Whether the element is rendered right-to-left. We initialize this lazily. - * @private {boolean|undefined}} - */ - this.rightToLeft_; - - /** - * Current x position of mouse or touch relative to viewport. - * @type {number} - */ - this.clientX = 0; - - /** - * Current y position of mouse or touch relative to viewport. - * @type {number} - */ - this.clientY = 0; - - /** - * Current x position of mouse or touch relative to screen. Deprecated because - * it doesn't take into affect zoom level or pixel density. - * @type {number} - * @deprecated Consider switching to clientX instead. - */ - this.screenX = 0; - - /** - * Current y position of mouse or touch relative to screen. Deprecated because - * it doesn't take into affect zoom level or pixel density. - * @type {number} - * @deprecated Consider switching to clientY instead. - */ - this.screenY = 0; - - /** - * The x position where the first mousedown or touchstart occurred. - * @type {number} - */ - this.startX = 0; - - /** - * The y position where the first mousedown or touchstart occurred. - * @type {number} - */ - this.startY = 0; - - /** - * Current x position of drag relative to target's parent. - * @type {number} - */ - this.deltaX = 0; - - /** - * Current y position of drag relative to target's parent. - * @type {number} - */ - this.deltaY = 0; - - /** - * The current page scroll value. - * @type {?goog.math.Coordinate} - */ - this.pageScroll; - - /** - * Whether dragging is currently enabled. - * @private {boolean} - */ - this.enabled_ = true; - - /** - * Whether object is currently being dragged. - * @private {boolean} - */ - this.dragging_ = false; - - /** - * Whether mousedown should be default prevented. - * @private {boolean} - **/ - this.preventMouseDown_ = true; - - /** - * The amount of distance, in pixels, after which a mousedown or touchstart is - * considered a drag. - * @private {number} - */ - this.hysteresisDistanceSquared_ = 0; - - /** - * The SCROLL event target used to make drag element follow scrolling. - * @private {?EventTarget} - */ - this.scrollTarget_; - - /** - * Whether IE drag events cancelling is on. - * @private {boolean} - */ - this.ieDragStartCancellingOn_ = false; - - /** - * Whether the dragger implements the changes described in http://b/6324964, - * making it truly RTL. This is a temporary flag to allow clients to - * transition to the new behavior at their convenience. At some point it will - * be the default. - * @private {boolean} - */ - this.useRightPositioningForRtl_ = false; - - // Add listener. Do not use the event handler here since the event handler is - // used for listeners added and removed during the drag operation. - goog.events.listen(this.handle, - [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN], - this.startDrag, false, this); -}; -goog.inherits(goog.fx.Dragger, goog.events.EventTarget); -// Dragger is meant to be extended, but defines most properties on its -// prototype, thus making it unsuitable for sealing. -goog.tagUnsealableClass(goog.fx.Dragger); - - -/** - * Whether setCapture is supported by the browser. - * @type {boolean} - * @private - */ -goog.fx.Dragger.HAS_SET_CAPTURE_ = - // IE and Gecko after 1.9.3 has setCapture - // WebKit does not yet: https://bugs.webkit.org/show_bug.cgi?id=27330 - goog.userAgent.IE || - goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.3'); - - -/** - * Creates copy of node being dragged. This is a utility function to be used - * wherever it is inappropriate for the original source to follow the mouse - * cursor itself. - * - * @param {Element} sourceEl Element to copy. - * @return {!Element} The clone of {@code sourceEl}. - */ -goog.fx.Dragger.cloneNode = function(sourceEl) { - var clonedEl = /** @type {Element} */ (sourceEl.cloneNode(true)), - origTexts = sourceEl.getElementsByTagName(goog.dom.TagName.TEXTAREA), - dragTexts = clonedEl.getElementsByTagName(goog.dom.TagName.TEXTAREA); - // Cloning does not copy the current value of textarea elements, so correct - // this manually. - for (var i = 0; i < origTexts.length; i++) { - dragTexts[i].value = origTexts[i].value; - } - switch (sourceEl.tagName) { - case goog.dom.TagName.TR: - return goog.dom.createDom(goog.dom.TagName.TABLE, null, - goog.dom.createDom(goog.dom.TagName.TBODY, - null, clonedEl)); - case goog.dom.TagName.TD: - case goog.dom.TagName.TH: - return goog.dom.createDom( - goog.dom.TagName.TABLE, null, goog.dom.createDom( - goog.dom.TagName.TBODY, null, goog.dom.createDom( - goog.dom.TagName.TR, null, clonedEl))); - case goog.dom.TagName.TEXTAREA: - clonedEl.value = sourceEl.value; - default: - return clonedEl; - } -}; - - -/** - * Constants for event names. - * @enum {string} - */ -goog.fx.Dragger.EventType = { - // The drag action was canceled before the START event. Possible reasons: - // disabled dragger, dragging with the right mouse button or releasing the - // button before reaching the hysteresis distance. - EARLY_CANCEL: 'earlycancel', - START: 'start', - BEFOREDRAG: 'beforedrag', - DRAG: 'drag', - END: 'end' -}; - - -/** - * Turns on/off true RTL behavior. This should be called immediately after - * construction. This is a temporary flag to allow clients to transition - * to the new component at their convenience. At some point true will be the - * default. - * @param {boolean} useRightPositioningForRtl True if "right" should be used for - * positioning, false if "left" should be used for positioning. - */ -goog.fx.Dragger.prototype.enableRightPositioningForRtl = - function(useRightPositioningForRtl) { - this.useRightPositioningForRtl_ = useRightPositioningForRtl; -}; - - -/** - * Returns the event handler, intended for subclass use. - * @return {!goog.events.EventHandler<T>} The event handler. - * @this {T} - * @template T - */ -goog.fx.Dragger.prototype.getHandler = function() { - // TODO(user): templated "this" values currently result in "this" being - // "unknown" in the body of the function. - var self = /** @type {goog.fx.Dragger} */ (this); - return self.eventHandler_; -}; - - -/** - * Sets (or reset) the Drag limits after a Dragger is created. - * @param {goog.math.Rect?} limits Object containing left, top, width, - * height for new Dragger limits. If target is right-to-left and - * enableRightPositioningForRtl(true) is called, then rect is interpreted as - * right, top, width, and height. - */ -goog.fx.Dragger.prototype.setLimits = function(limits) { - this.limits = limits || new goog.math.Rect(NaN, NaN, NaN, NaN); -}; - - -/** - * Sets the distance the user has to drag the element before a drag operation is - * started. - * @param {number} distance The number of pixels after which a mousedown and - * move is considered a drag. - */ -goog.fx.Dragger.prototype.setHysteresis = function(distance) { - this.hysteresisDistanceSquared_ = Math.pow(distance, 2); -}; - - -/** - * Gets the distance the user has to drag the element before a drag operation is - * started. - * @return {number} distance The number of pixels after which a mousedown and - * move is considered a drag. - */ -goog.fx.Dragger.prototype.getHysteresis = function() { - return Math.sqrt(this.hysteresisDistanceSquared_); -}; - - -/** - * Sets the SCROLL event target to make drag element follow scrolling. - * - * @param {EventTarget} scrollTarget The event target that dispatches SCROLL - * events. - */ -goog.fx.Dragger.prototype.setScrollTarget = function(scrollTarget) { - this.scrollTarget_ = scrollTarget; -}; - - -/** - * Enables cancelling of built-in IE drag events. - * @param {boolean} cancelIeDragStart Whether to enable cancelling of IE - * dragstart event. - */ -goog.fx.Dragger.prototype.setCancelIeDragStart = function(cancelIeDragStart) { - this.ieDragStartCancellingOn_ = cancelIeDragStart; -}; - - -/** - * @return {boolean} Whether the dragger is enabled. - */ -goog.fx.Dragger.prototype.getEnabled = function() { - return this.enabled_; -}; - - -/** - * Set whether dragger is enabled - * @param {boolean} enabled Whether dragger is enabled. - */ -goog.fx.Dragger.prototype.setEnabled = function(enabled) { - this.enabled_ = enabled; -}; - - -/** - * Set whether mousedown should be default prevented. - * @param {boolean} preventMouseDown Whether mousedown should be default - * prevented. - */ -goog.fx.Dragger.prototype.setPreventMouseDown = function(preventMouseDown) { - this.preventMouseDown_ = preventMouseDown; -}; - - -/** @override */ -goog.fx.Dragger.prototype.disposeInternal = function() { - goog.fx.Dragger.superClass_.disposeInternal.call(this); - goog.events.unlisten(this.handle, - [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN], - this.startDrag, false, this); - this.cleanUpAfterDragging_(); - - this.target = null; - this.handle = null; -}; - - -/** - * Whether the DOM element being manipulated is rendered right-to-left. - * @return {boolean} True if the DOM element is rendered right-to-left, false - * otherwise. - * @private - */ -goog.fx.Dragger.prototype.isRightToLeft_ = function() { - if (!goog.isDef(this.rightToLeft_)) { - this.rightToLeft_ = goog.style.isRightToLeft(this.target); - } - return this.rightToLeft_; -}; - - -/** - * Event handler that is used to start the drag - * @param {goog.events.BrowserEvent} e Event object. - */ -goog.fx.Dragger.prototype.startDrag = function(e) { - var isMouseDown = e.type == goog.events.EventType.MOUSEDOWN; - - // Dragger.startDrag() can be called by AbstractDragDrop with a mousemove - // event and IE does not report pressed mouse buttons on mousemove. Also, - // it does not make sense to check for the button if the user is already - // dragging. - - if (this.enabled_ && !this.dragging_ && - (!isMouseDown || e.isMouseActionButton())) { - if (this.hysteresisDistanceSquared_ == 0) { - if (this.fireDragStart_(e)) { - this.dragging_ = true; - if (this.preventMouseDown_) { - e.preventDefault(); - } - } else { - // If the start drag is cancelled, don't setup for a drag. - return; - } - } else if (this.preventMouseDown_) { - // Need to preventDefault for hysteresis to prevent page getting selected. - e.preventDefault(); - } - this.setupDragHandlers(); - - this.clientX = this.startX = e.clientX; - this.clientY = this.startY = e.clientY; - this.screenX = e.screenX; - this.screenY = e.screenY; - this.computeInitialPosition(); - this.pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll(); - } else { - this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL); - } -}; - - -/** - * Sets up event handlers when dragging starts. - * @protected - */ -goog.fx.Dragger.prototype.setupDragHandlers = function() { - var doc = this.document_; - var docEl = doc.documentElement; - // Use bubbling when we have setCapture since we got reports that IE has - // problems with the capturing events in combination with setCapture. - var useCapture = !goog.fx.Dragger.HAS_SET_CAPTURE_; - - this.eventHandler_.listen(doc, - [goog.events.EventType.TOUCHMOVE, goog.events.EventType.MOUSEMOVE], - this.handleMove_, useCapture); - this.eventHandler_.listen(doc, - [goog.events.EventType.TOUCHEND, goog.events.EventType.MOUSEUP], - this.endDrag, useCapture); - - if (goog.fx.Dragger.HAS_SET_CAPTURE_) { - docEl.setCapture(false); - this.eventHandler_.listen(docEl, - goog.events.EventType.LOSECAPTURE, - this.endDrag); - } else { - // Make sure we stop the dragging if the window loses focus. - // Don't use capture in this listener because we only want to end the drag - // if the actual window loses focus. Since blur events do not bubble we use - // a bubbling listener on the window. - this.eventHandler_.listen(goog.dom.getWindow(doc), - goog.events.EventType.BLUR, - this.endDrag); - } - - if (goog.userAgent.IE && this.ieDragStartCancellingOn_) { - // Cancel IE's 'ondragstart' event. - this.eventHandler_.listen(doc, goog.events.EventType.DRAGSTART, - goog.events.Event.preventDefault); - } - - if (this.scrollTarget_) { - this.eventHandler_.listen(this.scrollTarget_, goog.events.EventType.SCROLL, - this.onScroll_, useCapture); - } -}; - - -/** - * Fires a goog.fx.Dragger.EventType.START event. - * @param {goog.events.BrowserEvent} e Browser event that triggered the drag. - * @return {boolean} False iff preventDefault was called on the DragEvent. - * @private - */ -goog.fx.Dragger.prototype.fireDragStart_ = function(e) { - return this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.START, this, e.clientX, e.clientY, e)); -}; - - -/** - * Unregisters the event handlers that are only active during dragging, and - * releases mouse capture. - * @private - */ -goog.fx.Dragger.prototype.cleanUpAfterDragging_ = function() { - this.eventHandler_.removeAll(); - if (goog.fx.Dragger.HAS_SET_CAPTURE_) { - this.document_.releaseCapture(); - } -}; - - -/** - * Event handler that is used to end the drag. - * @param {goog.events.BrowserEvent} e Event object. - * @param {boolean=} opt_dragCanceled Whether the drag has been canceled. - */ -goog.fx.Dragger.prototype.endDrag = function(e, opt_dragCanceled) { - this.cleanUpAfterDragging_(); - - if (this.dragging_) { - this.dragging_ = false; - - var x = this.limitX(this.deltaX); - var y = this.limitY(this.deltaY); - var dragCanceled = opt_dragCanceled || - e.type == goog.events.EventType.TOUCHCANCEL; - this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.END, this, e.clientX, e.clientY, e, x, y, - dragCanceled)); - } else { - this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL); - } -}; - - -/** - * Event handler that is used to end the drag by cancelling it. - * @param {goog.events.BrowserEvent} e Event object. - */ -goog.fx.Dragger.prototype.endDragCancel = function(e) { - this.endDrag(e, true); -}; - - -/** - * Event handler that is used on mouse / touch move to update the drag - * @param {goog.events.BrowserEvent} e Event object. - * @private - */ -goog.fx.Dragger.prototype.handleMove_ = function(e) { - if (this.enabled_) { - // dx in right-to-left cases is relative to the right. - var sign = this.useRightPositioningForRtl_ && - this.isRightToLeft_() ? -1 : 1; - var dx = sign * (e.clientX - this.clientX); - var dy = e.clientY - this.clientY; - this.clientX = e.clientX; - this.clientY = e.clientY; - this.screenX = e.screenX; - this.screenY = e.screenY; - - if (!this.dragging_) { - var diffX = this.startX - this.clientX; - var diffY = this.startY - this.clientY; - var distance = diffX * diffX + diffY * diffY; - if (distance > this.hysteresisDistanceSquared_) { - if (this.fireDragStart_(e)) { - this.dragging_ = true; - } else { - // DragListGroup disposes of the dragger if BEFOREDRAGSTART is - // canceled. - if (!this.isDisposed()) { - this.endDrag(e); - } - return; - } - } - } - - var pos = this.calculatePosition_(dx, dy); - var x = pos.x; - var y = pos.y; - - if (this.dragging_) { - - var rv = this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.BEFOREDRAG, this, e.clientX, e.clientY, - e, x, y)); - - // Only do the defaultAction and dispatch drag event if predrag didn't - // prevent default - if (rv) { - this.doDrag(e, x, y, false); - e.preventDefault(); - } - } - } -}; - - -/** - * Calculates the drag position. - * - * @param {number} dx The horizontal movement delta. - * @param {number} dy The vertical movement delta. - * @return {!goog.math.Coordinate} The newly calculated drag element position. - * @private - */ -goog.fx.Dragger.prototype.calculatePosition_ = function(dx, dy) { - // Update the position for any change in body scrolling - var pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll(); - dx += pageScroll.x - this.pageScroll.x; - dy += pageScroll.y - this.pageScroll.y; - this.pageScroll = pageScroll; - - this.deltaX += dx; - this.deltaY += dy; - - var x = this.limitX(this.deltaX); - var y = this.limitY(this.deltaY); - return new goog.math.Coordinate(x, y); -}; - - -/** - * Event handler for scroll target scrolling. - * @param {goog.events.BrowserEvent} e The event. - * @private - */ -goog.fx.Dragger.prototype.onScroll_ = function(e) { - var pos = this.calculatePosition_(0, 0); - e.clientX = this.clientX; - e.clientY = this.clientY; - this.doDrag(e, pos.x, pos.y, true); -}; - - -/** - * @param {goog.events.BrowserEvent} e The closure object - * representing the browser event that caused a drag event. - * @param {number} x The new horizontal position for the drag element. - * @param {number} y The new vertical position for the drag element. - * @param {boolean} dragFromScroll Whether dragging was caused by scrolling - * the associated scroll target. - * @protected - */ -goog.fx.Dragger.prototype.doDrag = function(e, x, y, dragFromScroll) { - this.defaultAction(x, y); - this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.DRAG, this, e.clientX, e.clientY, e, x, y)); -}; - - -/** - * Returns the 'real' x after limits are applied (allows for some - * limits to be undefined). - * @param {number} x X-coordinate to limit. - * @return {number} The 'real' X-coordinate after limits are applied. - */ -goog.fx.Dragger.prototype.limitX = function(x) { - var rect = this.limits; - var left = !isNaN(rect.left) ? rect.left : null; - var width = !isNaN(rect.width) ? rect.width : 0; - var maxX = left != null ? left + width : Infinity; - var minX = left != null ? left : -Infinity; - return Math.min(maxX, Math.max(minX, x)); -}; - - -/** - * Returns the 'real' y after limits are applied (allows for some - * limits to be undefined). - * @param {number} y Y-coordinate to limit. - * @return {number} The 'real' Y-coordinate after limits are applied. - */ -goog.fx.Dragger.prototype.limitY = function(y) { - var rect = this.limits; - var top = !isNaN(rect.top) ? rect.top : null; - var height = !isNaN(rect.height) ? rect.height : 0; - var maxY = top != null ? top + height : Infinity; - var minY = top != null ? top : -Infinity; - return Math.min(maxY, Math.max(minY, y)); -}; - - -/** - * Overridable function for computing the initial position of the target - * before dragging begins. - * @protected - */ -goog.fx.Dragger.prototype.computeInitialPosition = function() { - this.deltaX = this.useRightPositioningForRtl_ ? - goog.style.bidi.getOffsetStart(this.target) : - /** @type {!HTMLElement} */ (this.target).offsetLeft; - this.deltaY = /** @type {!HTMLElement} */ (this.target).offsetTop; -}; - - -/** - * Overridable function for handling the default action of the drag behaviour. - * Normally this is simply moving the element to x,y though in some cases it - * might be used to resize the layer. This is basically a shortcut to - * implementing a default ondrag event handler. - * @param {number} x X-coordinate for target element. In right-to-left, x this - * is the number of pixels the target should be moved to from the right. - * @param {number} y Y-coordinate for target element. - */ -goog.fx.Dragger.prototype.defaultAction = function(x, y) { - if (this.useRightPositioningForRtl_ && this.isRightToLeft_()) { - this.target.style.right = x + 'px'; - } else { - this.target.style.left = x + 'px'; - } - this.target.style.top = y + 'px'; -}; - - -/** - * @return {boolean} Whether the dragger is currently in the midst of a drag. - */ -goog.fx.Dragger.prototype.isDragging = function() { - return this.dragging_; -}; - - - -/** - * Object representing a drag event - * @param {string} type Event type. - * @param {goog.fx.Dragger} dragobj Drag object initiating event. - * @param {number} clientX X-coordinate relative to the viewport. - * @param {number} clientY Y-coordinate relative to the viewport. - * @param {goog.events.BrowserEvent} browserEvent The closure object - * representing the browser event that caused this drag event. - * @param {number=} opt_actX Optional actual x for drag if it has been limited. - * @param {number=} opt_actY Optional actual y for drag if it has been limited. - * @param {boolean=} opt_dragCanceled Whether the drag has been canceled. - * @constructor - * @struct - * @extends {goog.events.Event} - */ -goog.fx.DragEvent = function(type, dragobj, clientX, clientY, browserEvent, - opt_actX, opt_actY, opt_dragCanceled) { - goog.events.Event.call(this, type); - - /** - * X-coordinate relative to the viewport - * @type {number} - */ - this.clientX = clientX; - - /** - * Y-coordinate relative to the viewport - * @type {number} - */ - this.clientY = clientY; - - /** - * The closure object representing the browser event that caused this drag - * event. - * @type {goog.events.BrowserEvent} - */ - this.browserEvent = browserEvent; - - /** - * The real x-position of the drag if it has been limited - * @type {number} - */ - this.left = goog.isDef(opt_actX) ? opt_actX : dragobj.deltaX; - - /** - * The real y-position of the drag if it has been limited - * @type {number} - */ - this.top = goog.isDef(opt_actY) ? opt_actY : dragobj.deltaY; - - /** - * Reference to the drag object for this event - * @type {goog.fx.Dragger} - */ - this.dragger = dragobj; - - /** - * Whether drag was canceled with this event. Used to differentiate between - * a legitimate drag END that can result in an action and a drag END which is - * a result of a drag cancelation. For now it can happen 1) with drag END - * event on FireFox when user drags the mouse out of the window, 2) with - * drag END event on IE7 which is generated on MOUSEMOVE event when user - * moves the mouse into the document after the mouse button has been - * released, 3) when TOUCHCANCEL is raised instead of TOUCHEND (on touch - * events). - * @type {boolean} - */ - this.dragCanceled = !!opt_dragCanceled; -}; -goog.inherits(goog.fx.DragEvent, goog.events.Event); - -// FIXME should possibly show tooltip when dragging? - -goog.provide('ol.control.ZoomSlider'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.fx.DragEvent'); -goog.require('goog.fx.Dragger'); -goog.require('goog.fx.Dragger.EventType'); -goog.require('goog.math.Rect'); -goog.require('goog.style'); -goog.require('ol.Size'); -goog.require('ol.ViewHint'); -goog.require('ol.animation'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.easing'); -goog.require('ol.math'); - - - -/** - * @classdesc - * A slider type of control for zooming. - * - * Example: - * - * map.addControl(new ol.control.ZoomSlider()); - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options. - * @api stable - */ -ol.control.ZoomSlider = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - /** - * Will hold the current resolution of the view. - * - * @type {number|undefined} - * @private - */ - this.currentResolution_ = undefined; - - /** - * The direction of the slider. Will be determined from actual display of the - * container and defaults to ol.control.ZoomSlider.direction.VERTICAL. - * - * @type {ol.control.ZoomSlider.direction} - * @private - */ - this.direction_ = ol.control.ZoomSlider.direction.VERTICAL; - - /** - * The calculated thumb size (border box plus margins). Set when initSlider_ - * is called. - * @type {ol.Size} - * @private - */ - this.thumbSize_ = null; - - /** - * Whether the slider is initialized. - * @type {boolean} - * @private - */ - this.sliderInitialized_ = false; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 200; - - var className = options.className ? options.className : 'ol-zoomslider'; - var thumbElement = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'class': className + '-thumb ' + ol.css.CLASS_UNSELECTABLE - }); - var containerElement = goog.dom.createDom('DIV', - [className, ol.css.CLASS_UNSELECTABLE, ol.css.CLASS_CONTROL], - thumbElement); - - /** - * @type {goog.fx.Dragger} - * @private - */ - this.dragger_ = new goog.fx.Dragger(thumbElement); - this.registerDisposable(this.dragger_); - - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START, - this.handleDraggerStart_, false, this); - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG, - this.handleDraggerDrag_, false, this); - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END, - this.handleDraggerEnd_, false, this); - - goog.events.listen(containerElement, goog.events.EventType.CLICK, - this.handleContainerClick_, false, this); - goog.events.listen(thumbElement, goog.events.EventType.CLICK, - goog.events.Event.stopPropagation); - - var render = options.render ? options.render : ol.control.ZoomSlider.render; - - goog.base(this, { - element: containerElement, - render: render - }); -}; -goog.inherits(ol.control.ZoomSlider, ol.control.Control); - - -/** - * The enum for available directions. - * - * @enum {number} - */ -ol.control.ZoomSlider.direction = { - VERTICAL: 0, - HORIZONTAL: 1 -}; - - -/** - * @inheritDoc - */ -ol.control.ZoomSlider.prototype.setMap = function(map) { - goog.base(this, 'setMap', map); - if (map) { - map.render(); - } -}; - - -/** - * Initializes the slider element. This will determine and set this controls - * direction_ and also constrain the dragging of the thumb to always be within - * the bounds of the container. - * - * @private - */ -ol.control.ZoomSlider.prototype.initSlider_ = function() { - var container = this.element; - var containerSize = goog.style.getSize(container); - - var thumb = goog.dom.getFirstElementChild(container); - var thumbMargins = goog.style.getMarginBox(thumb); - var thumbBorderBoxSize = goog.style.getBorderBoxSize(thumb); - var thumbWidth = thumbBorderBoxSize.width + - thumbMargins.right + thumbMargins.left; - var thumbHeight = thumbBorderBoxSize.height + - thumbMargins.top + thumbMargins.bottom; - this.thumbSize_ = [thumbWidth, thumbHeight]; - - var width = containerSize.width - thumbWidth; - var height = containerSize.height - thumbHeight; - - var limits; - if (containerSize.width > containerSize.height) { - this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL; - limits = new goog.math.Rect(0, 0, width, 0); - } else { - this.direction_ = ol.control.ZoomSlider.direction.VERTICAL; - limits = new goog.math.Rect(0, 0, 0, height); - } - this.dragger_.setLimits(limits); - this.sliderInitialized_ = true; -}; - - -/** - * Update the zoomslider element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.ZoomSlider} - * @api - */ -ol.control.ZoomSlider.render = function(mapEvent) { - if (!mapEvent.frameState) { - return; - } - goog.asserts.assert(mapEvent.frameState.viewState, - 'viewState should be defined'); - if (!this.sliderInitialized_) { - this.initSlider_(); - } - var res = mapEvent.frameState.viewState.resolution; - if (res !== this.currentResolution_) { - this.currentResolution_ = res; - this.setThumbPosition_(res); - } -}; - - -/** - * @param {goog.events.BrowserEvent} browserEvent The browser event to handle. - * @private - */ -ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) { - var map = this.getMap(); - var view = map.getView(); - var currentResolution = view.getResolution(); - goog.asserts.assert(currentResolution, - 'currentResolution should be defined'); - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: this.duration_, - easing: ol.easing.easeOut - })); - var relativePosition = this.getRelativePosition_( - browserEvent.offsetX - this.thumbSize_[0] / 2, - browserEvent.offsetY - this.thumbSize_[1] / 2); - var resolution = this.getResolutionForPosition_(relativePosition); - view.setResolution(view.constrainResolution(resolution)); -}; - - -/** - * Handle dragger start events. - * @param {goog.fx.DragEvent} event The drag event. - * @private - */ -ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) { - this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1); -}; - - -/** - * Handle dragger drag events. - * - * @param {goog.fx.DragEvent} event The drag event. - * @private - */ -ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) { - var relativePosition = this.getRelativePosition_(event.left, event.top); - this.currentResolution_ = this.getResolutionForPosition_(relativePosition); - this.getMap().getView().setResolution(this.currentResolution_); -}; - - -/** - * Handle dragger end events. - * @param {goog.fx.DragEvent} event The drag event. - * @private - */ -ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) { - var map = this.getMap(); - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - goog.asserts.assert(this.currentResolution_, - 'this.currentResolution_ should be defined'); - map.beforeRender(ol.animation.zoom({ - resolution: this.currentResolution_, - duration: this.duration_, - easing: ol.easing.easeOut - })); - var resolution = view.constrainResolution(this.currentResolution_); - view.setResolution(resolution); -}; - - -/** - * Positions the thumb inside its container according to the given resolution. - * - * @param {number} res The res. - * @private - */ -ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) { - var position = this.getPositionForResolution_(res); - var dragger = this.dragger_; - var thumb = goog.dom.getFirstElementChild(this.element); - - if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) { - var left = dragger.limits.left + dragger.limits.width * position; - goog.style.setPosition(thumb, left); - } else { - var top = dragger.limits.top + dragger.limits.height * position; - goog.style.setPosition(thumb, dragger.limits.left, top); - } -}; - - -/** - * Calculates the relative position of the thumb given x and y offsets. The - * relative position scales from 0 to 1. The x and y offsets are assumed to be - * in pixel units within the dragger limits. - * - * @param {number} x Pixel position relative to the left of the slider. - * @param {number} y Pixel position relative to the top of the slider. - * @return {number} The relative position of the thumb. - * @private - */ -ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) { - var draggerLimits = this.dragger_.limits; - var amount; - if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) { - amount = (x - draggerLimits.left) / draggerLimits.width; - } else { - amount = (y - draggerLimits.top) / draggerLimits.height; - } - return ol.math.clamp(amount, 0, 1); -}; - - -/** - * Calculates the corresponding resolution of the thumb given its relative - * position (where 0 is the minimum and 1 is the maximum). - * - * @param {number} position The relative position of the thumb. - * @return {number} The corresponding resolution. - * @private - */ -ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) { - var fn = this.getMap().getView().getResolutionForValueFunction(); - return fn(1 - position); -}; - - -/** - * Determines the relative position of the slider for the given resolution. A - * relative position of 0 corresponds to the minimum view resolution. A - * relative position of 1 corresponds to the maximum view resolution. - * - * @param {number} res The resolution. - * @return {number} The relative position value (between 0 and 1). - * @private - */ -ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) { - var fn = this.getMap().getView().getValueForResolutionFunction(); - return 1 - fn(res); -}; - -goog.provide('ol.control.ZoomToExtent'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.control.Control'); -goog.require('ol.css'); - - - -/** - * @classdesc - * A button control which, when pressed, changes the map view to a specific - * extent. To style this control use the css selector `.ol-zoom-extent`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ZoomToExtentOptions=} opt_options Options. - * @api stable - */ -ol.control.ZoomToExtent = function(opt_options) { - var options = opt_options ? opt_options : {}; - - /** - * @type {ol.Extent} - * @private - */ - this.extent_ = options.extent ? options.extent : null; - - var className = options.className ? options.className : - 'ol-zoom-extent'; - - var label = options.label ? options.label : 'E'; - var tipLabel = options.tipLabel ? - options.tipLabel : 'Fit to extent'; - var button = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'title': tipLabel - }, label); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL; - var element = goog.dom.createDom('DIV', cssClasses, button); - - goog.base(this, { - element: element, - target: options.target - }); -}; -goog.inherits(ol.control.ZoomToExtent, ol.control.Control); - - -/** - * @param {goog.events.BrowserEvent} event The event to handle - * @private - */ -ol.control.ZoomToExtent.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleZoomToExtent_(); -}; - - -/** - * @private - */ -ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() { - var map = this.getMap(); - var view = map.getView(); - var extent = !this.extent_ ? - view.getProjection().getExtent() : this.extent_; - var size = map.getSize(); - goog.asserts.assert(size, 'size should be defined'); - view.fit(extent, size); -}; - -goog.provide('ol.DeviceOrientation'); -goog.provide('ol.DeviceOrientationProperty'); - -goog.require('goog.events'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.has'); -goog.require('ol.math'); - - -/** - * @enum {string} - */ -ol.DeviceOrientationProperty = { - ALPHA: 'alpha', - BETA: 'beta', - GAMMA: 'gamma', - HEADING: 'heading', - TRACKING: 'tracking' -}; - - - -/** - * @classdesc - * The ol.DeviceOrientation class provides access to information from - * DeviceOrientation events. See the [HTML 5 DeviceOrientation Specification]( - * http://www.w3.org/TR/orientation-event/) for more details. - * - * Many new computers, and especially mobile phones - * and tablets, provide hardware support for device orientation. Web - * developers targeting mobile devices will be especially interested in this - * class. - * - * Device orientation data are relative to a common starting point. For mobile - * devices, the starting point is to lay your phone face up on a table with the - * top of the phone pointing north. This represents the zero state. All - * angles are then relative to this state. For computers, it is the same except - * the screen is open at 90 degrees. - * - * Device orientation is reported as three angles - `alpha`, `beta`, and - * `gamma` - relative to the starting position along the three planar axes X, Y - * and Z. The X axis runs from the left edge to the right edge through the - * middle of the device. Similarly, the Y axis runs from the bottom to the top - * of the device through the middle. The Z axis runs from the back to the front - * through the middle. In the starting position, the X axis points to the - * right, the Y axis points away from you and the Z axis points straight up - * from the device lying flat. - * - * The three angles representing the device orientation are relative to the - * three axes. `alpha` indicates how much the device has been rotated around the - * Z axis, which is commonly interpreted as the compass heading (see note - * below). `beta` indicates how much the device has been rotated around the X - * axis, or how much it is tilted from front to back. `gamma` indicates how - * much the device has been rotated around the Y axis, or how much it is tilted - * from left to right. - * - * For most browsers, the `alpha` value returns the compass heading so if the - * device points north, it will be 0. With Safari on iOS, the 0 value of - * `alpha` is calculated from when device orientation was first requested. - * ol.DeviceOrientation provides the `heading` property which normalizes this - * behavior across all browsers for you. - * - * It is important to note that the HTML 5 DeviceOrientation specification - * indicates that `alpha`, `beta` and `gamma` are in degrees while the - * equivalent properties in ol.DeviceOrientation are in radians for consistency - * with all other uses of angles throughout OpenLayers. - * - * @see http://www.w3.org/TR/orientation-event/ - * - * To get notified of device orientation changes, register a listener for the - * generic `change` event on your `ol.DeviceOrientation` instance. - * - * @constructor - * @extends {ol.Object} - * @param {olx.DeviceOrientationOptions=} opt_options Options. - * @api - */ -ol.DeviceOrientation = function(opt_options) { - - goog.base(this); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {goog.events.Key} - */ - this.listenerKey_ = null; - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING), - this.handleTrackingChanged_, false, this); - - this.setTracking(options.tracking !== undefined ? options.tracking : false); - -}; -goog.inherits(ol.DeviceOrientation, ol.Object); - - -/** - * @inheritDoc - */ -ol.DeviceOrientation.prototype.disposeInternal = function() { - this.setTracking(false); - goog.base(this, 'disposeInternal'); -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent Event. - */ -ol.DeviceOrientation.prototype.orientationChange_ = function(browserEvent) { - var event = /** @type {DeviceOrientationEvent} */ - (browserEvent.getBrowserEvent()); - if (event.alpha !== null) { - var alpha = ol.math.toRadians(event.alpha); - this.set(ol.DeviceOrientationProperty.ALPHA, alpha); - // event.absolute is undefined in iOS. - if (goog.isBoolean(event.absolute) && event.absolute) { - this.set(ol.DeviceOrientationProperty.HEADING, alpha); - } else if (goog.isNumber(event.webkitCompassHeading) && - event.webkitCompassAccuracy != -1) { - var heading = ol.math.toRadians(event.webkitCompassHeading); - this.set(ol.DeviceOrientationProperty.HEADING, heading); - } - } - if (event.beta !== null) { - this.set(ol.DeviceOrientationProperty.BETA, - ol.math.toRadians(event.beta)); - } - if (event.gamma !== null) { - this.set(ol.DeviceOrientationProperty.GAMMA, - ol.math.toRadians(event.gamma)); - } - this.changed(); -}; - - -/** - * Rotation around the device z-axis (in radians). - * @return {number|undefined} The euler angle in radians of the device from the - * standard Z axis. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getAlpha = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.ALPHA)); -}; - - -/** - * Rotation around the device x-axis (in radians). - * @return {number|undefined} The euler angle in radians of the device from the - * planar X axis. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getBeta = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.BETA)); -}; - - -/** - * Rotation around the device y-axis (in radians). - * @return {number|undefined} The euler angle in radians of the device from the - * planar Y axis. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getGamma = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.GAMMA)); -}; - - -/** - * The heading of the device relative to north (in radians). - * @return {number|undefined} The heading of the device relative to north, in - * radians, normalizing for different browser behavior. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getHeading = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.HEADING)); -}; - - -/** - * Determine if orientation is being tracked. - * @return {boolean} Changes in device orientation are being tracked. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getTracking = function() { - return /** @type {boolean} */ ( - this.get(ol.DeviceOrientationProperty.TRACKING)); -}; - - -/** - * @private - */ -ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() { - if (ol.has.DEVICE_ORIENTATION) { - var tracking = this.getTracking(); - if (tracking && !this.listenerKey_) { - this.listenerKey_ = goog.events.listen(goog.global, 'deviceorientation', - this.orientationChange_, false, this); - } else if (!tracking && this.listenerKey_) { - goog.events.unlistenByKey(this.listenerKey_); - this.listenerKey_ = null; - } - } -}; - - -/** - * Enable or disable tracking of device orientation events. - * @param {boolean} tracking The status of tracking changes to alpha, beta and - * gamma. If true, changes are tracked and reported immediately. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.setTracking = function(tracking) { - this.set(ol.DeviceOrientationProperty.TRACKING, tracking); -}; - -goog.provide('ol.format.Feature'); - -goog.require('ol.geom.Geometry'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for feature formats. - * {ol.format.Feature} subclasses provide the ability to decode and encode - * {@link ol.Feature} objects from a variety of commonly used geospatial - * file formats. See the documentation for each format for more details. - * - * @constructor - * @api stable - */ -ol.format.Feature = function() { - - /** - * @protected - * @type {ol.proj.Projection} - */ - this.defaultDataProjection = null; - -}; - - -/** - * @return {Array.<string>} Extensions. - */ -ol.format.Feature.prototype.getExtensions = goog.abstractMethod; - - -/** - * Adds the data projection to the read options. - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {olx.format.ReadOptions|undefined} Options. - * @protected - */ -ol.format.Feature.prototype.getReadOptions = function(source, opt_options) { - var options; - if (opt_options) { - options = { - dataProjection: opt_options.dataProjection ? - opt_options.dataProjection : this.readProjection(source), - featureProjection: opt_options.featureProjection - }; - } - return this.adaptOptions(options); -}; - - -/** - * Sets the `defaultDataProjection` on the options, if no `dataProjection` - * is set. - * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options - * Options. - * @protected - * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined} - * Updated options. - */ -ol.format.Feature.prototype.adaptOptions = function(options) { - var updatedOptions; - if (options) { - updatedOptions = { - featureProjection: options.featureProjection, - dataProjection: options.dataProjection ? - options.dataProjection : this.defaultDataProjection, - rightHanded: options.rightHanded - }; - } - return updatedOptions; -}; - - -/** - * @return {ol.format.FormatType} Format. - */ -ol.format.Feature.prototype.getType = goog.abstractMethod; - - -/** - * Read a single feature from a source. - * - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - */ -ol.format.Feature.prototype.readFeature = goog.abstractMethod; - - -/** - * Read all features from a source. - * - * @param {Document|Node|ArrayBuffer|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - */ -ol.format.Feature.prototype.readFeatures = goog.abstractMethod; - - -/** - * Read a single geometry from a source. - * - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.Feature.prototype.readGeometry = goog.abstractMethod; - - -/** - * Read the projection from a source. - * - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - */ -ol.format.Feature.prototype.readProjection = goog.abstractMethod; - - -/** - * Encode a feature in this format. - * - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - */ -ol.format.Feature.prototype.writeFeature = goog.abstractMethod; - - -/** - * Encode an array of features in this format. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - */ -ol.format.Feature.prototype.writeFeatures = goog.abstractMethod; - - -/** - * Write a single geometry in this format. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - */ -ol.format.Feature.prototype.writeGeometry = goog.abstractMethod; - - -/** - * @param {ol.geom.Geometry|ol.Extent} geometry Geometry. - * @param {boolean} write Set to true for writing, false for reading. - * @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options - * Options. - * @return {ol.geom.Geometry|ol.Extent} Transformed geometry. - * @protected - */ -ol.format.Feature.transformWithOptions = function( - geometry, write, opt_options) { - var featureProjection = opt_options ? - ol.proj.get(opt_options.featureProjection) : null; - var dataProjection = opt_options ? - ol.proj.get(opt_options.dataProjection) : null; - if (featureProjection && dataProjection && - !ol.proj.equivalent(featureProjection, dataProjection)) { - if (geometry instanceof ol.geom.Geometry) { - return (write ? geometry.clone() : geometry).transform( - write ? featureProjection : dataProjection, - write ? dataProjection : featureProjection); - } else { - // FIXME this is necessary because ol.format.GML treats extents - // as geometries - return ol.proj.transformExtent( - write ? geometry.slice() : geometry, - write ? featureProjection : dataProjection, - write ? dataProjection : featureProjection); - } - } else { - return geometry; - } -}; - -goog.provide('ol.format.JSONFeature'); - -goog.require('goog.asserts'); -goog.require('goog.json'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for JSON feature formats. - * - * @constructor - * @extends {ol.format.Feature} - */ -ol.format.JSONFeature = function() { - goog.base(this); -}; -goog.inherits(ol.format.JSONFeature, ol.format.Feature); - - -/** - * @param {Document|Node|Object|string} source Source. - * @private - * @return {Object} Object. - */ -ol.format.JSONFeature.prototype.getObject_ = function(source) { - if (goog.isObject(source)) { - return source; - } else if (goog.isString(source)) { - var object = goog.json.parse(source); - return object ? object : null; - } else { - goog.asserts.fail(); - return null; - } -}; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.getType = function() { - return ol.format.FormatType.JSON; -}; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.readFeature = function(source, opt_options) { - return this.readFeatureFromObject( - this.getObject_(source), this.getReadOptions(source, opt_options)); -}; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) { - return this.readFeaturesFromObject( - this.getObject_(source), this.getReadOptions(source, opt_options)); -}; - - -/** - * @param {Object} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.Feature} Feature. - */ -ol.format.JSONFeature.prototype.readFeatureFromObject = goog.abstractMethod; - - -/** - * @param {Object} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {Array.<ol.Feature>} Features. - */ -ol.format.JSONFeature.prototype.readFeaturesFromObject = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) { - return this.readGeometryFromObject( - this.getObject_(source), this.getReadOptions(source, opt_options)); -}; - - -/** - * @param {Object} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.JSONFeature.prototype.readGeometryFromObject = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.readProjection = function(source) { - return this.readProjectionFromObject(this.getObject_(source)); -}; - - -/** - * @param {Object} object Object. - * @protected - * @return {ol.proj.Projection} Projection. - */ -ol.format.JSONFeature.prototype.readProjectionFromObject = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) { - return goog.json.serialize(this.writeFeatureObject(feature, opt_options)); -}; - - -/** - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - */ -ol.format.JSONFeature.prototype.writeFeatureObject = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.writeFeatures = function( - features, opt_options) { - return goog.json.serialize(this.writeFeaturesObject(features, opt_options)); -}; - - -/** - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - */ -ol.format.JSONFeature.prototype.writeFeaturesObject = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.writeGeometry = function( - geometry, opt_options) { - return goog.json.serialize(this.writeGeometryObject(geometry, opt_options)); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - */ -ol.format.JSONFeature.prototype.writeGeometryObject = goog.abstractMethod; - -goog.provide('ol.geom.flat.interpolate'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.math'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} fraction Fraction. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Destination. - */ -ol.geom.flat.interpolate.lineString = - function(flatCoordinates, offset, end, stride, fraction, opt_dest) { - // FIXME interpolate extra dimensions - goog.asserts.assert(0 <= fraction && fraction <= 1, - 'fraction should be in between 0 and 1'); - var pointX = NaN; - var pointY = NaN; - var n = (end - offset) / stride; - if (n === 0) { - goog.asserts.fail('n cannot be 0'); - } else if (n == 1) { - pointX = flatCoordinates[offset]; - pointY = flatCoordinates[offset + 1]; - } else if (n == 2) { - pointX = (1 - fraction) * flatCoordinates[offset] + - fraction * flatCoordinates[offset + stride]; - pointY = (1 - fraction) * flatCoordinates[offset + 1] + - fraction * flatCoordinates[offset + stride + 1]; - } else { - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - var length = 0; - var cumulativeLengths = [0]; - var i; - for (i = offset + stride; i < end; i += stride) { - var x2 = flatCoordinates[i]; - var y2 = flatCoordinates[i + 1]; - length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); - cumulativeLengths.push(length); - x1 = x2; - y1 = y2; - } - var target = fraction * length; - var index = goog.array.binarySearch(cumulativeLengths, target); - if (index < 0) { - var t = (target - cumulativeLengths[-index - 2]) / - (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]); - var o = offset + (-index - 2) * stride; - pointX = goog.math.lerp( - flatCoordinates[o], flatCoordinates[o + stride], t); - pointY = goog.math.lerp( - flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t); - } else { - pointX = flatCoordinates[offset + index * stride]; - pointY = flatCoordinates[offset + index * stride + 1]; - } - } - if (opt_dest) { - opt_dest[0] = pointX; - opt_dest[1] = pointY; - return opt_dest; - } else { - return [pointX, pointY]; - } -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} m M. - * @param {boolean} extrapolate Extrapolate. - * @return {ol.Coordinate} Coordinate. - */ -ol.geom.flat.lineStringCoordinateAtM = - function(flatCoordinates, offset, end, stride, m, extrapolate) { - if (end == offset) { - return null; - } - var coordinate; - if (m < flatCoordinates[offset + stride - 1]) { - if (extrapolate) { - coordinate = flatCoordinates.slice(offset, offset + stride); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } - } else if (flatCoordinates[end - 1] < m) { - if (extrapolate) { - coordinate = flatCoordinates.slice(end - stride, end); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } - } - // FIXME use O(1) search - if (m == flatCoordinates[offset + stride - 1]) { - return flatCoordinates.slice(offset, offset + stride); - } - var lo = offset / stride; - var hi = end / stride; - while (lo < hi) { - var mid = (lo + hi) >> 1; - if (m < flatCoordinates[(mid + 1) * stride - 1]) { - hi = mid; - } else { - lo = mid + 1; - } - } - var m0 = flatCoordinates[lo * stride - 1]; - if (m == m0) { - return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride); - } - var m1 = flatCoordinates[(lo + 1) * stride - 1]; - goog.asserts.assert(m0 < m, 'm0 should be less than m'); - goog.asserts.assert(m <= m1, 'm should be less than or equal to m1'); - var t = (m - m0) / (m1 - m0); - coordinate = []; - var i; - for (i = 0; i < stride - 1; ++i) { - coordinate.push(goog.math.lerp(flatCoordinates[(lo - 1) * stride + i], - flatCoordinates[lo * stride + i], t)); - } - coordinate.push(m); - goog.asserts.assert(coordinate.length == stride, - 'length of coordinate array should match stride'); - return coordinate; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} m M. - * @param {boolean} extrapolate Extrapolate. - * @param {boolean} interpolate Interpolate. - * @return {ol.Coordinate} Coordinate. - */ -ol.geom.flat.lineStringsCoordinateAtM = function( - flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) { - if (interpolate) { - return ol.geom.flat.lineStringCoordinateAtM( - flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate); - } - var coordinate; - if (m < flatCoordinates[stride - 1]) { - if (extrapolate) { - coordinate = flatCoordinates.slice(0, stride); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } - } - if (flatCoordinates[flatCoordinates.length - 1] < m) { - if (extrapolate) { - coordinate = flatCoordinates.slice(flatCoordinates.length - stride); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } - } - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - if (offset == end) { - continue; - } - if (m < flatCoordinates[offset + stride - 1]) { - return null; - } else if (m <= flatCoordinates[end - 1]) { - return ol.geom.flat.lineStringCoordinateAtM( - flatCoordinates, offset, end, stride, m, false); - } - offset = end; - } - goog.asserts.fail( - 'ol.geom.flat.lineStringsCoordinateAtM should have returned'); - return null; -}; - -goog.provide('ol.geom.flat.length'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Length. - */ -ol.geom.flat.length.lineString = - function(flatCoordinates, offset, end, stride) { - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - var length = 0; - var i; - for (i = offset + stride; i < end; i += stride) { - var x2 = flatCoordinates[i]; - var y2 = flatCoordinates[i + 1]; - length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); - x1 = x2; - y1 = y2; - } - return length; -}; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Perimeter. - */ -ol.geom.flat.length.linearRing = - function(flatCoordinates, offset, end, stride) { - var perimeter = - ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride); - var dx = flatCoordinates[end - stride] - flatCoordinates[offset]; - var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1]; - perimeter += Math.sqrt(dx * dx + dy * dy); - return perimeter; -}; - -goog.provide('ol.geom.LineString'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interpolate'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.length'); -goog.require('ol.geom.flat.segments'); -goog.require('ol.geom.flat.simplify'); - - - -/** - * @classdesc - * Linestring geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.LineString = function(coordinates, opt_layout) { - - goog.base(this); - - /** - * @private - * @type {ol.Coordinate} - */ - this.flatMidpoint_ = null; - - /** - * @private - * @type {number} - */ - this.flatMidpointRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; - - this.setCoordinates(coordinates, opt_layout); - -}; -goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry); - - -/** - * Append the passed coordinate to the coordinates of the linestring. - * @param {ol.Coordinate} coordinate Coordinate. - * @api stable - */ -ol.geom.LineString.prototype.appendCoordinate = function(coordinate) { - goog.asserts.assert(coordinate.length == this.stride, - 'length of coordinate array should match stride'); - if (!this.flatCoordinates) { - this.flatCoordinates = coordinate.slice(); - } else { - goog.array.extend(this.flatCoordinates, coordinate); - } - this.changed(); -}; - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.LineString} Clone. - * @api stable - */ -ol.geom.LineString.prototype.clone = function() { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return lineString; -}; - - -/** - * @inheritDoc - */ -ol.geom.LineString.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getClosestPoint( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - this.maxDelta_, false, x, y, closestPoint, minSquaredDistance); -}; - - -/** - * Iterate over each segment, calling the provided callback. - * If the callback returns a truthy value the function returns that - * value immediately. Otherwise the function returns `false`. - * - * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function - * called for each segment. - * @param {S=} opt_this The object to be used as the value of 'this' - * within callback. - * @return {T|boolean} Value. - * @template T,S - * @api - */ -ol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) { - return ol.geom.flat.segments.forEach(this.flatCoordinates, 0, - this.flatCoordinates.length, this.stride, callback, opt_this); -}; - - -/** - * Returns the coordinate at `m` using linear interpolation, or `null` if no - * such coordinate exists. - * - * `opt_extrapolate` controls extrapolation beyond the range of Ms in the - * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first - * M will return the first coordinate and Ms greater than the last M will - * return the last coordinate. - * - * @param {number} m M. - * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`. - * @return {ol.Coordinate} Coordinate. - * @api stable - */ -ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) { - if (this.layout != ol.geom.GeometryLayout.XYM && - this.layout != ol.geom.GeometryLayout.XYZM) { - return null; - } - var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false; - return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0, - this.flatCoordinates.length, this.stride, m, extrapolate); -}; - - -/** - * Return the coordinates of the linestring. - * @return {Array.<ol.Coordinate>} Coordinates. - * @api stable - */ -ol.geom.LineString.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; - - -/** - * Return the length of the linestring on projected plane. - * @return {number} Length (on projected plane). - * @api stable - */ -ol.geom.LineString.prototype.getLength = function() { - return ol.geom.flat.length.lineString( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; - - -/** - * @return {Array.<number>} Flat midpoint. - */ -ol.geom.LineString.prototype.getFlatMidpoint = function() { - if (this.flatMidpointRevision_ != this.getRevision()) { - this.flatMidpoint_ = ol.geom.flat.interpolate.lineString( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - 0.5, this.flatMidpoint_); - this.flatMidpointRevision_ = this.getRevision(); - } - return this.flatMidpoint_; -}; - - -/** - * @inheritDoc - */ -ol.geom.LineString.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - squaredTolerance, simplifiedFlatCoordinates, 0); - var simplifiedLineString = new ol.geom.LineString(null); - simplifiedLineString.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates); - return simplifiedLineString; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.LineString.prototype.getType = function() { - return ol.geom.GeometryType.LINE_STRING; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.LineString.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.lineString( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - extent); -}; - - -/** - * Set the coordinates of the linestring. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.LineString.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 1); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - */ -ol.geom.LineString.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; - -goog.provide('ol.geom.MultiLineString'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interpolate'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.simplify'); - - - -/** - * @classdesc - * Multi-linestring geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiLineString = function(coordinates, opt_layout) { - - goog.base(this); - - /** - * @type {Array.<number>} - * @private - */ - this.ends_ = []; - - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; - - this.setCoordinates(coordinates, opt_layout); - -}; -goog.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry); - - -/** - * Append the passed linestring to the multilinestring. - * @param {ol.geom.LineString} lineString LineString. - * @api stable - */ -ol.geom.MultiLineString.prototype.appendLineString = function(lineString) { - goog.asserts.assert(lineString.getLayout() == this.layout, - 'layout of lineString should match the layout'); - if (!this.flatCoordinates) { - this.flatCoordinates = lineString.getFlatCoordinates().slice(); - } else { - goog.array.extend( - this.flatCoordinates, lineString.getFlatCoordinates().slice()); - } - this.ends_.push(this.flatCoordinates.length); - this.changed(); -}; - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.MultiLineString} Clone. - * @api stable - */ -ol.geom.MultiLineString.prototype.clone = function() { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(), this.ends_.slice()); - return multiLineString; -}; - - -/** - * @inheritDoc - */ -ol.geom.MultiLineString.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta( - this.flatCoordinates, 0, this.ends_, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getsClosestPoint( - this.flatCoordinates, 0, this.ends_, this.stride, - this.maxDelta_, false, x, y, closestPoint, minSquaredDistance); -}; - - -/** - * Returns the coordinate at `m` using linear interpolation, or `null` if no - * such coordinate exists. - * - * `opt_extrapolate` controls extrapolation beyond the range of Ms in the - * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first - * M will return the first coordinate and Ms greater than the last M will - * return the last coordinate. - * - * `opt_interpolate` controls interpolation between consecutive LineStrings - * within the MultiLineString. If `opt_interpolate` is `true` the coordinates - * will be linearly interpolated between the last coordinate of one LineString - * and the first coordinate of the next LineString. If `opt_interpolate` is - * `false` then the function will return `null` for Ms falling between - * LineStrings. - * - * @param {number} m M. - * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`. - * @param {boolean=} opt_interpolate Interpolate. Default is `false`. - * @return {ol.Coordinate} Coordinate. - * @api stable - */ -ol.geom.MultiLineString.prototype.getCoordinateAtM = - function(m, opt_extrapolate, opt_interpolate) { - if ((this.layout != ol.geom.GeometryLayout.XYM && - this.layout != ol.geom.GeometryLayout.XYZM) || - this.flatCoordinates.length === 0) { - return null; - } - var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false; - var interpolate = opt_interpolate !== undefined ? opt_interpolate : false; - return ol.geom.flat.lineStringsCoordinateAtM(this.flatCoordinates, 0, - this.ends_, this.stride, m, extrapolate, interpolate); -}; - - -/** - * Return the coordinates of the multilinestring. - * @return {Array.<Array.<ol.Coordinate>>} Coordinates. - * @api stable - */ -ol.geom.MultiLineString.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinatess( - this.flatCoordinates, 0, this.ends_, this.stride); -}; - - -/** - * @return {Array.<number>} Ends. - */ -ol.geom.MultiLineString.prototype.getEnds = function() { - return this.ends_; -}; - - -/** - * Return the linestring at the specified index. - * @param {number} index Index. - * @return {ol.geom.LineString} LineString. - * @api stable - */ -ol.geom.MultiLineString.prototype.getLineString = function(index) { - goog.asserts.assert(0 <= index && index < this.ends_.length, - 'index should be in between 0 and length of the this.ends_ array'); - if (index < 0 || this.ends_.length <= index) { - return null; - } - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice( - index === 0 ? 0 : this.ends_[index - 1], this.ends_[index])); - return lineString; -}; - - -/** - * Return the linestrings of this multilinestring. - * @return {Array.<ol.geom.LineString>} LineStrings. - * @api stable - */ -ol.geom.MultiLineString.prototype.getLineStrings = function() { - var flatCoordinates = this.flatCoordinates; - var ends = this.ends_; - var layout = this.layout; - /** @type {Array.<ol.geom.LineString>} */ - var lineStrings = []; - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end)); - lineStrings.push(lineString); - offset = end; - } - return lineStrings; -}; - - -/** - * @return {Array.<number>} Flat midpoints. - */ -ol.geom.MultiLineString.prototype.getFlatMidpoints = function() { - var midpoints = []; - var flatCoordinates = this.flatCoordinates; - var offset = 0; - var ends = this.ends_; - var stride = this.stride; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var midpoint = ol.geom.flat.interpolate.lineString( - flatCoordinates, offset, end, stride, 0.5); - goog.array.extend(midpoints, midpoint); - offset = end; - } - return midpoints; -}; - - -/** - * @inheritDoc - */ -ol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - var simplifiedEnds = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers( - this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance, - simplifiedFlatCoordinates, 0, simplifiedEnds); - var simplifiedMultiLineString = new ol.geom.MultiLineString(null); - simplifiedMultiLineString.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds); - return simplifiedMultiLineString; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiLineString.prototype.getType = function() { - return ol.geom.GeometryType.MULTI_LINE_STRING; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.lineStrings( - this.flatCoordinates, 0, this.ends_, this.stride, extent); -}; - - -/** - * Set the coordinates of the multilinestring. - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiLineString.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_); - } else { - this.setLayout(opt_layout, coordinates, 2); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - var ends = ol.geom.flat.deflate.coordinatess( - this.flatCoordinates, 0, coordinates, this.stride, this.ends_); - this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Array.<number>} ends Ends. - */ -ol.geom.MultiLineString.prototype.setFlatCoordinates = - function(layout, flatCoordinates, ends) { - if (!flatCoordinates) { - goog.asserts.assert(ends && ends.length === 0, - 'ends must be truthy and ends.length should be 0'); - } else if (ends.length === 0) { - goog.asserts.assert(flatCoordinates.length === 0, - 'flatCoordinates should be an empty array'); - } else { - goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], - 'length of flatCoordinates array should match the last value of ends'); - } - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.ends_ = ends; - this.changed(); -}; - - -/** - * @param {Array.<ol.geom.LineString>} lineStrings LineStrings. - */ -ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) { - var layout = this.getLayout(); - var flatCoordinates = []; - var ends = []; - var i, ii; - for (i = 0, ii = lineStrings.length; i < ii; ++i) { - var lineString = lineStrings[i]; - if (i === 0) { - layout = lineString.getLayout(); - } else { - // FIXME better handle the case of non-matching layouts - goog.asserts.assert(lineString.getLayout() == layout, - 'layout of lineString should match layout'); - } - goog.array.extend(flatCoordinates, lineString.getFlatCoordinates()); - ends.push(flatCoordinates.length); - } - this.setFlatCoordinates(layout, flatCoordinates, ends); -}; - -goog.provide('ol.geom.MultiPoint'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.math'); - - - -/** - * @classdesc - * Multi-point geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPoint = function(coordinates, opt_layout) { - goog.base(this); - this.setCoordinates(coordinates, opt_layout); -}; -goog.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry); - - -/** - * Append the passed point to this multipoint. - * @param {ol.geom.Point} point Point. - * @api stable - */ -ol.geom.MultiPoint.prototype.appendPoint = function(point) { - goog.asserts.assert(point.getLayout() == this.layout, - 'the layout of point should match layout'); - if (!this.flatCoordinates) { - this.flatCoordinates = point.getFlatCoordinates().slice(); - } else { - goog.array.extend(this.flatCoordinates, point.getFlatCoordinates()); - } - this.changed(); -}; - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.MultiPoint} Clone. - * @api stable - */ -ol.geom.MultiPoint.prototype.clone = function() { - var multiPoint = new ol.geom.MultiPoint(null); - multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return multiPoint; -}; - - -/** - * @inheritDoc - */ -ol.geom.MultiPoint.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - var flatCoordinates = this.flatCoordinates; - var stride = this.stride; - var i, ii, j; - for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { - var squaredDistance = ol.math.squaredDistance( - x, y, flatCoordinates[i], flatCoordinates[i + 1]); - if (squaredDistance < minSquaredDistance) { - minSquaredDistance = squaredDistance; - for (j = 0; j < stride; ++j) { - closestPoint[j] = flatCoordinates[i + j]; - } - closestPoint.length = stride; - } - } - return minSquaredDistance; -}; - - -/** - * Return the coordinates of the multipoint. - * @return {Array.<ol.Coordinate>} Coordinates. - * @api stable - */ -ol.geom.MultiPoint.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; - - -/** - * Return the point at the specified index. - * @param {number} index Index. - * @return {ol.geom.Point} Point. - * @api stable - */ -ol.geom.MultiPoint.prototype.getPoint = function(index) { - var n = !this.flatCoordinates ? - 0 : this.flatCoordinates.length / this.stride; - goog.asserts.assert(0 <= index && index < n, - 'index should be in between 0 and n'); - if (index < 0 || n <= index) { - return null; - } - var point = new ol.geom.Point(null); - point.setFlatCoordinates(this.layout, this.flatCoordinates.slice( - index * this.stride, (index + 1) * this.stride)); - return point; -}; - - -/** - * Return the points of this multipoint. - * @return {Array.<ol.geom.Point>} Points. - * @api stable - */ -ol.geom.MultiPoint.prototype.getPoints = function() { - var flatCoordinates = this.flatCoordinates; - var layout = this.layout; - var stride = this.stride; - /** @type {Array.<ol.geom.Point>} */ - var points = []; - var i, ii; - for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { - var point = new ol.geom.Point(null); - point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride)); - points.push(point); - } - return points; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPoint.prototype.getType = function() { - return ol.geom.GeometryType.MULTI_POINT; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) { - var flatCoordinates = this.flatCoordinates; - var stride = this.stride; - var i, ii, x, y; - for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { - x = flatCoordinates[i]; - y = flatCoordinates[i + 1]; - if (ol.extent.containsXY(extent, x, y)) { - return true; - } - } - return false; -}; - - -/** - * Set the coordinates of the multipoint. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPoint.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 1); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - */ -ol.geom.MultiPoint.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; - -goog.provide('ol.geom.flat.center'); - -goog.require('ol.extent'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @return {Array.<number>} Flat centers. - */ -ol.geom.flat.center.linearRingss = - function(flatCoordinates, offset, endss, stride) { - var flatCenters = []; - var i, ii; - var extent = ol.extent.createEmpty(); - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - extent = ol.extent.createOrUpdateFromFlatCoordinates( - flatCoordinates, offset, ends[0], stride); - flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2); - offset = ends[ends.length - 1]; - } - return flatCenters; -}; - -goog.provide('ol.geom.MultiPolygon'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.area'); -goog.require('ol.geom.flat.center'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.contains'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interiorpoint'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.orient'); -goog.require('ol.geom.flat.simplify'); - - - -/** - * @classdesc - * Multi-polygon geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPolygon = function(coordinates, opt_layout) { - - goog.base(this); - - /** - * @type {Array.<Array.<number>>} - * @private - */ - this.endss_ = []; - - /** - * @private - * @type {number} - */ - this.flatInteriorPointsRevision_ = -1; - - /** - * @private - * @type {Array.<number>} - */ - this.flatInteriorPoints_ = null; - - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.orientedRevision_ = -1; - - /** - * @private - * @type {Array.<number>} - */ - this.orientedFlatCoordinates_ = null; - - this.setCoordinates(coordinates, opt_layout); - -}; -goog.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry); - - -/** - * Append the passed polygon to this multipolygon. - * @param {ol.geom.Polygon} polygon Polygon. - * @api stable - */ -ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) { - goog.asserts.assert(polygon.getLayout() == this.layout, - 'layout of polygon should match layout'); - /** @type {Array.<number>} */ - var ends; - if (!this.flatCoordinates) { - this.flatCoordinates = polygon.getFlatCoordinates().slice(); - ends = polygon.getEnds().slice(); - this.endss_.push(); - } else { - var offset = this.flatCoordinates.length; - goog.array.extend(this.flatCoordinates, polygon.getFlatCoordinates()); - ends = polygon.getEnds().slice(); - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - ends[i] += offset; - } - } - this.endss_.push(ends); - this.changed(); -}; - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.MultiPolygon} Clone. - * @api stable - */ -ol.geom.MultiPolygon.prototype.clone = function() { - var multiPolygon = new ol.geom.MultiPolygon(null); - var newEndss = /** @type {Array.<Array.<number>>} */ - (goog.object.unsafeClone(this.endss_)); - multiPolygon.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(), newEndss); - return multiPolygon; -}; - - -/** - * @inheritDoc - */ -ol.geom.MultiPolygon.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta( - this.flatCoordinates, 0, this.endss_, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getssClosestPoint( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, - this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); -}; - - -/** - * @inheritDoc - */ -ol.geom.MultiPolygon.prototype.containsXY = function(x, y) { - return ol.geom.flat.contains.linearRingssContainsXY( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y); -}; - - -/** - * Return the area of the multipolygon on projected plane. - * @return {number} Area (on projected plane). - * @api stable - */ -ol.geom.MultiPolygon.prototype.getArea = function() { - return ol.geom.flat.area.linearRingss( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride); -}; - - -/** - * Get the coordinate array for this geometry. This array has the structure - * of a GeoJSON coordinate array for multi-polygons. - * - * @param {boolean=} opt_right Orient coordinates according to the right-hand - * rule (counter-clockwise for exterior and clockwise for interior rings). - * If `false`, coordinates will be oriented according to the left-hand rule - * (clockwise for exterior and counter-clockwise for interior rings). - * By default, coordinate orientation will depend on how the geometry was - * constructed. - * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) { - var flatCoordinates; - if (opt_right !== undefined) { - flatCoordinates = this.getOrientedFlatCoordinates().slice(); - ol.geom.flat.orient.orientLinearRingss( - flatCoordinates, 0, this.endss_, this.stride, opt_right); - } else { - flatCoordinates = this.flatCoordinates; - } - - return ol.geom.flat.inflate.coordinatesss( - flatCoordinates, 0, this.endss_, this.stride); -}; - - -/** - * @return {Array.<Array.<number>>} Endss. - */ -ol.geom.MultiPolygon.prototype.getEndss = function() { - return this.endss_; -}; - - -/** - * @return {Array.<number>} Flat interior points. - */ -ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() { - if (this.flatInteriorPointsRevision_ != this.getRevision()) { - var flatCenters = ol.geom.flat.center.linearRingss( - this.flatCoordinates, 0, this.endss_, this.stride); - this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, - flatCenters); - this.flatInteriorPointsRevision_ = this.getRevision(); - } - return this.flatInteriorPoints_; -}; - - -/** - * Return the interior points as {@link ol.geom.MultiPoint multipoint}. - * @return {ol.geom.MultiPoint} Interior points. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getInteriorPoints = function() { - var interiorPoints = new ol.geom.MultiPoint(null); - interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY, - this.getFlatInteriorPoints().slice()); - return interiorPoints; -}; - - -/** - * @return {Array.<number>} Oriented flat coordinates. - */ -ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() { - if (this.orientedRevision_ != this.getRevision()) { - var flatCoordinates = this.flatCoordinates; - if (ol.geom.flat.orient.linearRingssAreOriented( - flatCoordinates, 0, this.endss_, this.stride)) { - this.orientedFlatCoordinates_ = flatCoordinates; - } else { - this.orientedFlatCoordinates_ = flatCoordinates.slice(); - this.orientedFlatCoordinates_.length = - ol.geom.flat.orient.orientLinearRingss( - this.orientedFlatCoordinates_, 0, this.endss_, this.stride); - } - this.orientedRevision_ = this.getRevision(); - } - return this.orientedFlatCoordinates_; -}; - - -/** - * @inheritDoc - */ -ol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - var simplifiedEndss = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess( - this.flatCoordinates, 0, this.endss_, this.stride, - Math.sqrt(squaredTolerance), - simplifiedFlatCoordinates, 0, simplifiedEndss); - var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null); - simplifiedMultiPolygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss); - return simplifiedMultiPolygon; -}; - - -/** - * Return the polygon at the specified index. - * @param {number} index Index. - * @return {ol.geom.Polygon} Polygon. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getPolygon = function(index) { - goog.asserts.assert(0 <= index && index < this.endss_.length, - 'index should be in between 0 and the length of this.endss_'); - if (index < 0 || this.endss_.length <= index) { - return null; - } - var offset; - if (index === 0) { - offset = 0; - } else { - var prevEnds = this.endss_[index - 1]; - offset = prevEnds[prevEnds.length - 1]; - } - var ends = this.endss_[index].slice(); - var end = ends[ends.length - 1]; - if (offset !== 0) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - ends[i] -= offset; - } - } - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(offset, end), ends); - return polygon; -}; - - -/** - * Return the polygons of this multipolygon. - * @return {Array.<ol.geom.Polygon>} Polygons. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getPolygons = function() { - var layout = this.layout; - var flatCoordinates = this.flatCoordinates; - var endss = this.endss_; - var polygons = []; - var offset = 0; - var i, ii, j, jj; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i].slice(); - var end = ends[ends.length - 1]; - if (offset !== 0) { - for (j = 0, jj = ends.length; j < jj; ++j) { - ends[j] -= offset; - } - } - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - layout, flatCoordinates.slice(offset, end), ends); - polygons.push(polygon); - offset = end; - } - return polygons; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPolygon.prototype.getType = function() { - return ol.geom.GeometryType.MULTI_POLYGON; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.linearRingss( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent); -}; - - -/** - * Set the coordinates of the multipolygon. - * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPolygon.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_); - } else { - this.setLayout(opt_layout, coordinates, 3); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - var endss = ol.geom.flat.deflate.coordinatesss( - this.flatCoordinates, 0, coordinates, this.stride, this.endss_); - if (endss.length === 0) { - this.flatCoordinates.length = 0; - } else { - var lastEnds = endss[endss.length - 1]; - this.flatCoordinates.length = lastEnds.length === 0 ? - 0 : lastEnds[lastEnds.length - 1]; - } - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Array.<Array.<number>>} endss Endss. - */ -ol.geom.MultiPolygon.prototype.setFlatCoordinates = - function(layout, flatCoordinates, endss) { - goog.asserts.assert(endss, 'endss must be truthy'); - if (!flatCoordinates || flatCoordinates.length === 0) { - goog.asserts.assert(endss.length === 0, 'the length of endss should be 0'); - } else { - goog.asserts.assert(endss.length > 0, 'endss cannot be an empty array'); - var ends = endss[endss.length - 1]; - goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], - 'the length of flatCoordinates should be the last value of ends'); - } - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.endss_ = endss; - this.changed(); -}; - - -/** - * @param {Array.<ol.geom.Polygon>} polygons Polygons. - */ -ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) { - var layout = this.getLayout(); - var flatCoordinates = []; - var endss = []; - var i, ii, ends; - for (i = 0, ii = polygons.length; i < ii; ++i) { - var polygon = polygons[i]; - if (i === 0) { - layout = polygon.getLayout(); - } else { - // FIXME better handle the case of non-matching layouts - goog.asserts.assert(polygon.getLayout() == layout, - 'layout of polygon should be layout'); - } - var offset = flatCoordinates.length; - ends = polygon.getEnds(); - var j, jj; - for (j = 0, jj = ends.length; j < jj; ++j) { - ends[j] += offset; - } - goog.array.extend(flatCoordinates, polygon.getFlatCoordinates()); - endss.push(ends); - } - this.setFlatCoordinates(layout, flatCoordinates, endss); -}; - -goog.provide('ol.format.EsriJSON'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.extent'); -goog.require('ol.format.Feature'); -goog.require('ol.format.JSONFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.flat.orient'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the EsriJSON format. - * - * @constructor - * @extends {ol.format.JSONFeature} - * @param {olx.format.EsriJSONOptions=} opt_options Options. - * @api - */ -ol.format.EsriJSON = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * Name of the geometry attribute for features. - * @type {string|undefined} - * @private - */ - this.geometryName_ = options.geometryName; - -}; -goog.inherits(ol.format.EsriJSON, ol.format.JSONFeature); - - -/** - * @param {EsriJSONGeometry} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @private - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.EsriJSON.readGeometry_ = function(object, opt_options) { - if (!object) { - return null; - } - var type; - if (goog.isNumber(object.x) && goog.isNumber(object.y)) { - type = ol.geom.GeometryType.POINT; - } else if (object.points) { - type = ol.geom.GeometryType.MULTI_POINT; - } else if (object.paths) { - if (object.paths.length === 1) { - type = ol.geom.GeometryType.LINE_STRING; - } else { - type = ol.geom.GeometryType.MULTI_LINE_STRING; - } - } else if (object.rings) { - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - var rings = ol.format.EsriJSON.convertRings_(object.rings, layout); - object = /** @type {EsriJSONGeometry} */(goog.object.clone(object)); - if (rings.length === 1) { - type = ol.geom.GeometryType.POLYGON; - object.rings = rings[0]; - } else { - type = ol.geom.GeometryType.MULTI_POLYGON; - object.rings = rings; - } - } - goog.asserts.assert(type, 'geometry type should be defined'); - var geometryReader = ol.format.EsriJSON.GEOMETRY_READERS_[type]; - goog.asserts.assert(geometryReader, - 'geometryReader should be defined'); - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions( - geometryReader(object), false, opt_options)); -}; - - -/** - * Determines inner and outer rings. - * Checks if any polygons in this array contain any other polygons in this - * array. It is used for checking for holes. - * Logic inspired by: https://github.com/Esri/terraformer-arcgis-parser - * @param {Array.<!Array.<!Array.<number>>>} rings Rings. - * @param {ol.geom.GeometryLayout} layout Geometry layout. - * @private - * @return {Array.<!Array.<!Array.<number>>>} Transoformed rings. - */ -ol.format.EsriJSON.convertRings_ = function(rings, layout) { - var outerRings = []; - var holes = []; - var i, ii; - for (i = 0, ii = rings.length; i < ii; ++i) { - var flatRing = goog.array.flatten(rings[i]); - // is this ring an outer ring? is it clockwise? - var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0, - flatRing.length, layout.length); - if (clockwise) { - outerRings.push([rings[i]]); - } else { - holes.push(rings[i]); - } - } - while (holes.length) { - var hole = holes.shift(); - var matched = false; - // loop over all outer rings and see if they contain our hole. - for (i = outerRings.length - 1; i >= 0; i--) { - var outerRing = outerRings[i][0]; - if (ol.extent.containsExtent(new ol.geom.LinearRing( - outerRing).getExtent(), - new ol.geom.LinearRing(hole).getExtent())) { - // the hole is contained push it into our polygon - outerRings[i].push(hole); - matched = true; - break; - } - } - if (!matched) { - // no outer rings contain this hole turn it into and outer - // ring (reverse it) - outerRings.push([hole.reverse()]); - } - } - return outerRings; -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} Point. - */ -ol.format.EsriJSON.readPointGeometry_ = function(object) { - goog.asserts.assert(goog.isNumber(object.x), 'object.x should be number'); - goog.asserts.assert(goog.isNumber(object.y), 'object.y should be number'); - var point; - if (object.m !== undefined && object.z !== undefined) { - point = new ol.geom.Point([object.x, object.y, object.z, object.m], - ol.geom.GeometryLayout.XYZM); - } else if (object.z !== undefined) { - point = new ol.geom.Point([object.x, object.y, object.z], - ol.geom.GeometryLayout.XYZ); - } else if (object.m !== undefined) { - point = new ol.geom.Point([object.x, object.y, object.m], - ol.geom.GeometryLayout.XYM); - } else { - point = new ol.geom.Point([object.x, object.y]); - } - return point; -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} LineString. - */ -ol.format.EsriJSON.readLineStringGeometry_ = function(object) { - goog.asserts.assert(goog.isArray(object.paths), - 'object.paths should be an array'); - goog.asserts.assert(object.paths.length === 1, - 'object.paths array length should be 1'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.LineString(object.paths[0], layout); -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} MultiLineString. - */ -ol.format.EsriJSON.readMultiLineStringGeometry_ = function(object) { - goog.asserts.assert(goog.isArray(object.paths), - 'object.paths should be an array'); - goog.asserts.assert(object.paths.length > 1, - 'object.paths array length should be more than 1'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.MultiLineString(object.paths, layout); -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.GeometryLayout} The geometry layout to use. - */ -ol.format.EsriJSON.getGeometryLayout_ = function(object) { - var layout = ol.geom.GeometryLayout.XY; - if (object.hasZ === true && object.hasM === true) { - layout = ol.geom.GeometryLayout.XYZM; - } else if (object.hasZ === true) { - layout = ol.geom.GeometryLayout.XYZ; - } else if (object.hasM === true) { - layout = ol.geom.GeometryLayout.XYM; - } - return layout; -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} MultiPoint. - */ -ol.format.EsriJSON.readMultiPointGeometry_ = function(object) { - goog.asserts.assert(object.points, 'object.points should be defined'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.MultiPoint(object.points, layout); -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} MultiPolygon. - */ -ol.format.EsriJSON.readMultiPolygonGeometry_ = function(object) { - goog.asserts.assert(object.rings); - goog.asserts.assert(object.rings.length > 1, - 'object.rings should have length larger than 1'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.MultiPolygon( - /** @type {Array.<Array.<Array.<Array.<number>>>>} */(object.rings), - layout); -}; - - -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} Polygon. - */ -ol.format.EsriJSON.readPolygonGeometry_ = function(object) { - goog.asserts.assert(object.rings); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.Polygon(object.rings, layout); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONGeometry} EsriJSON geometry. - */ -ol.format.EsriJSON.writePointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - var coordinates = geometry.getCoordinates(); - var layout = geometry.getLayout(); - if (layout === ol.geom.GeometryLayout.XYZ) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1], - z: coordinates[2] - }); - } else if (layout === ol.geom.GeometryLayout.XYM) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1], - m: coordinates[2] - }); - } else if (layout === ol.geom.GeometryLayout.XYZM) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1], - z: coordinates[2], - m: coordinates[3] - }); - } else if (layout === ol.geom.GeometryLayout.XY) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1] - }); - } else { - goog.asserts.fail('Unknown geometry layout'); - } -}; - - -/** - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @private - * @return {Object} Object with boolean hasZ and hasM keys. - */ -ol.format.EsriJSON.getHasZM_ = function(geometry) { - var layout = geometry.getLayout(); - return { - hasZ: (layout === ol.geom.GeometryLayout.XYZ || - layout === ol.geom.GeometryLayout.XYZM), - hasM: (layout === ol.geom.GeometryLayout.XYM || - layout === ol.geom.GeometryLayout.XYZM) - }; -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONPolyline} EsriJSON geometry. - */ -ol.format.EsriJSON.writeLineStringGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONPolyline} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - paths: [geometry.getCoordinates()] - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONPolygon} EsriJSON geometry. - */ -ol.format.EsriJSON.writePolygonGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - // Esri geometries use the left-hand rule - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONPolygon} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - rings: geometry.getCoordinates(false) - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONPolyline} EsriJSON geometry. - */ -ol.format.EsriJSON.writeMultiLineStringGeometry_ = - function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONPolyline} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - paths: geometry.getCoordinates() - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONMultipoint} EsriJSON geometry. - */ -ol.format.EsriJSON.writeMultiPointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, - 'geometry should be an ol.geom.MultiPoint'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONMultipoint} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - points: geometry.getCoordinates() - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONPolygon} EsriJSON geometry. - */ -ol.format.EsriJSON.writeMultiPolygonGeometry_ = function(geometry, - opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, - 'geometry should be an ol.geom.MultiPolygon'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - var coordinates = geometry.getCoordinates(false); - var output = []; - for (var i = 0; i < coordinates.length; i++) { - for (var x = coordinates[i].length - 1; x >= 0; x--) { - output.push(coordinates[i][x]); - } - } - return /** @type {EsriJSONPolygon} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - rings: output - }); -}; - - -/** - * @const - * @private - * @type {Object.<ol.geom.GeometryType, function(EsriJSONGeometry): ol.geom.Geometry>} - */ -ol.format.EsriJSON.GEOMETRY_READERS_ = {}; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POINT] = - ol.format.EsriJSON.readPointGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.LINE_STRING] = - ol.format.EsriJSON.readLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POLYGON] = - ol.format.EsriJSON.readPolygonGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POINT] = - ol.format.EsriJSON.readMultiPointGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_LINE_STRING] = - ol.format.EsriJSON.readMultiLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POLYGON] = - ol.format.EsriJSON.readMultiPolygonGeometry_; - - -/** - * @const - * @private - * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (EsriJSONGeometry)>} - */ -ol.format.EsriJSON.GEOMETRY_WRITERS_ = {}; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POINT] = - ol.format.EsriJSON.writePointGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.LINE_STRING] = - ol.format.EsriJSON.writeLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POLYGON] = - ol.format.EsriJSON.writePolygonGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POINT] = - ol.format.EsriJSON.writeMultiPointGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_LINE_STRING] = - ol.format.EsriJSON.writeMultiLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POLYGON] = - ol.format.EsriJSON.writeMultiPolygonGeometry_; - - -/** - * Read a feature from a EsriJSON Feature source. Only works for Feature, - * use `readFeatures` to read FeatureCollection source. - * - * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api - */ -ol.format.EsriJSON.prototype.readFeature; - - -/** - * Read all features from a EsriJSON source. Works with both Feature and - * FeatureCollection sources. - * - * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api - */ -ol.format.EsriJSON.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.EsriJSON.prototype.readFeatureFromObject = function( - object, opt_options) { - var esriJSONFeature = /** @type {EsriJSONFeature} */ (object); - goog.asserts.assert(esriJSONFeature.geometry || - esriJSONFeature.attributes, - 'geometry or attributes should be defined'); - var geometry = ol.format.EsriJSON.readGeometry_(esriJSONFeature.geometry, - opt_options); - var feature = new ol.Feature(); - if (this.geometryName_) { - feature.setGeometryName(this.geometryName_); - } - feature.setGeometry(geometry); - if (opt_options && opt_options.idField && - esriJSONFeature.attributes[opt_options.idField]) { - goog.asserts.assert( - goog.isNumber(esriJSONFeature.attributes[opt_options.idField]), - 'objectIdFieldName value should be a number'); - feature.setId(/** @type {number} */( - esriJSONFeature.attributes[opt_options.idField])); - } - if (esriJSONFeature.attributes) { - feature.setProperties(esriJSONFeature.attributes); - } - return feature; -}; - - -/** - * @inheritDoc - */ -ol.format.EsriJSON.prototype.readFeaturesFromObject = function( - object, opt_options) { - var esriJSONObject = /** @type {EsriJSONObject} */ (object); - var options = opt_options ? opt_options : {}; - if (esriJSONObject.features) { - var esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */ - (object); - /** @type {Array.<ol.Feature>} */ - var features = []; - var esriJSONFeatures = esriJSONFeatureCollection.features; - var i, ii; - options.idField = object.objectIdFieldName; - for (i = 0, ii = esriJSONFeatures.length; i < ii; ++i) { - features.push(this.readFeatureFromObject(esriJSONFeatures[i], - options)); - } - return features; - } else { - return [this.readFeatureFromObject(object, options)]; - } -}; - - -/** - * Read a geometry from a EsriJSON source. - * - * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api - */ -ol.format.EsriJSON.prototype.readGeometry; - - -/** - * @inheritDoc - */ -ol.format.EsriJSON.prototype.readGeometryFromObject = function( - object, opt_options) { - return ol.format.EsriJSON.readGeometry_( - /** @type {EsriJSONGeometry} */ (object), opt_options); -}; - - -/** - * Read the projection from a EsriJSON source. - * - * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api - */ -ol.format.EsriJSON.prototype.readProjection; - - -/** - * @inheritDoc - */ -ol.format.EsriJSON.prototype.readProjectionFromObject = function(object) { - var esriJSONObject = /** @type {EsriJSONObject} */ (object); - if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) { - var crs = esriJSONObject.spatialReference.wkid; - return ol.proj.get('EPSG:' + crs); - } else { - return null; - } -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONGeometry} EsriJSON geometry. - */ -ol.format.EsriJSON.writeGeometry_ = function(geometry, opt_options) { - var geometryWriter = ol.format.EsriJSON.GEOMETRY_WRITERS_[geometry.getType()]; - goog.asserts.assert(geometryWriter, 'geometryWriter should be defined'); - return geometryWriter(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, true, opt_options)), - opt_options); -}; - - -/** - * Encode a geometry as a EsriJSON string. - * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} EsriJSON. - * @api - */ -ol.format.EsriJSON.prototype.writeGeometry; - - -/** - * Encode a geometry as a EsriJSON object. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {EsriJSONGeometry} Object. - * @api - */ -ol.format.EsriJSON.prototype.writeGeometryObject = function(geometry, - opt_options) { - return ol.format.EsriJSON.writeGeometry_(geometry, - this.adaptOptions(opt_options)); -}; - - -/** - * Encode a feature as a EsriJSON Feature string. - * - * @function - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} EsriJSON. - * @api - */ -ol.format.EsriJSON.prototype.writeFeature; - - -/** - * Encode a feature as a esriJSON Feature object. - * - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - * @api - */ -ol.format.EsriJSON.prototype.writeFeatureObject = function( - feature, opt_options) { - opt_options = this.adaptOptions(opt_options); - var object = {}; - var geometry = feature.getGeometry(); - if (geometry) { - object['geometry'] = - ol.format.EsriJSON.writeGeometry_(geometry, opt_options); - } - var properties = feature.getProperties(); - delete properties[feature.getGeometryName()]; - if (!goog.object.isEmpty(properties)) { - object['attributes'] = properties; - } else { - object['attributes'] = {}; - } - if (opt_options && opt_options.featureProjection) { - object['spatialReference'] = /** @type {EsriJSONCRS} */({ - wkid: ol.proj.get( - opt_options.featureProjection).getCode().split(':').pop() - }); - } - return object; -}; - - -/** - * Encode an array of features as EsriJSON. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} EsriJSON. - * @api - */ -ol.format.EsriJSON.prototype.writeFeatures; - - -/** - * Encode an array of features as a EsriJSON object. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} EsriJSON Object. - * @api - */ -ol.format.EsriJSON.prototype.writeFeaturesObject = - function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var objects = []; - var i, ii; - for (i = 0, ii = features.length; i < ii; ++i) { - objects.push(this.writeFeatureObject(features[i], opt_options)); - } - return /** @type {EsriJSONFeatureCollection} */ ({ - 'features': objects - }); -}; - -goog.provide('ol.geom.GeometryCollection'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryType'); - - - -/** - * @classdesc - * An array of {@link ol.geom.Geometry} objects. - * - * @constructor - * @extends {ol.geom.Geometry} - * @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries. - * @api stable - */ -ol.geom.GeometryCollection = function(opt_geometries) { - - goog.base(this); - - /** - * @private - * @type {Array.<ol.geom.Geometry>} - */ - this.geometries_ = opt_geometries ? opt_geometries : null; - - this.listenGeometriesChange_(); -}; -goog.inherits(ol.geom.GeometryCollection, ol.geom.Geometry); - - -/** - * @param {Array.<ol.geom.Geometry>} geometries Geometries. - * @private - * @return {Array.<ol.geom.Geometry>} Cloned geometries. - */ -ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) { - var clonedGeometries = []; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - clonedGeometries.push(geometries[i].clone()); - } - return clonedGeometries; -}; - - -/** - * @private - */ -ol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() { - var i, ii; - if (!this.geometries_) { - return; - } - for (i = 0, ii = this.geometries_.length; i < ii; ++i) { - goog.events.unlisten( - this.geometries_[i], goog.events.EventType.CHANGE, - this.changed, false, this); - } -}; - - -/** - * @private - */ -ol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() { - var i, ii; - if (!this.geometries_) { - return; - } - for (i = 0, ii = this.geometries_.length; i < ii; ++i) { - goog.events.listen( - this.geometries_[i], goog.events.EventType.CHANGE, - this.changed, false, this); - } -}; - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.GeometryCollection} Clone. - * @api stable - */ -ol.geom.GeometryCollection.prototype.clone = function() { - var geometryCollection = new ol.geom.GeometryCollection(null); - geometryCollection.setGeometries(this.geometries_); - return geometryCollection; -}; - - -/** - * @inheritDoc - */ -ol.geom.GeometryCollection.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - minSquaredDistance = geometries[i].closestPointXY( - x, y, closestPoint, minSquaredDistance); - } - return minSquaredDistance; -}; - - -/** - * @inheritDoc - */ -ol.geom.GeometryCollection.prototype.containsXY = function(x, y) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - if (geometries[i].containsXY(x, y)) { - return true; - } - } - return false; -}; - - -/** - * @inheritDoc - */ -ol.geom.GeometryCollection.prototype.computeExtent = function(extent) { - ol.extent.createOrUpdateEmpty(extent); - var geometries = this.geometries_; - for (var i = 0, ii = geometries.length; i < ii; ++i) { - ol.extent.extend(extent, geometries[i].getExtent()); - } - return extent; -}; - - -/** - * Return the geometries that make up this geometry collection. - * @return {Array.<ol.geom.Geometry>} Geometries. - * @api stable - */ -ol.geom.GeometryCollection.prototype.getGeometries = function() { - return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_); -}; - - -/** - * @return {Array.<ol.geom.Geometry>} Geometries. - */ -ol.geom.GeometryCollection.prototype.getGeometriesArray = function() { - return this.geometries_; -}; - - -/** - * @inheritDoc - */ -ol.geom.GeometryCollection.prototype.getSimplifiedGeometry = - function(squaredTolerance) { - if (this.simplifiedGeometryRevision != this.getRevision()) { - goog.object.clear(this.simplifiedGeometryCache); - this.simplifiedGeometryMaxMinSquaredTolerance = 0; - this.simplifiedGeometryRevision = this.getRevision(); - } - if (squaredTolerance < 0 || - (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && - squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) { - return this; - } - var key = squaredTolerance.toString(); - if (this.simplifiedGeometryCache.hasOwnProperty(key)) { - return this.simplifiedGeometryCache[key]; - } else { - var simplifiedGeometries = []; - var geometries = this.geometries_; - var simplified = false; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometry = geometries[i]; - var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); - simplifiedGeometries.push(simplifiedGeometry); - if (simplifiedGeometry !== geometry) { - simplified = true; - } - } - if (simplified) { - var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null); - simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries); - this.simplifiedGeometryCache[key] = simplifiedGeometryCollection; - return simplifiedGeometryCollection; - } else { - this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; - return this; - } - } -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.GeometryCollection.prototype.getType = function() { - return ol.geom.GeometryType.GEOMETRY_COLLECTION; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - if (geometries[i].intersectsExtent(extent)) { - return true; - } - } - return false; -}; - - -/** - * @return {boolean} Is empty. - */ -ol.geom.GeometryCollection.prototype.isEmpty = function() { - return this.geometries_.length === 0; -}; - - -/** - * Set the geometries that make up this geometry collection. - * @param {Array.<ol.geom.Geometry>} geometries Geometries. - * @api stable - */ -ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) { - this.setGeometriesArray( - ol.geom.GeometryCollection.cloneGeometries_(geometries)); -}; - - -/** - * @param {Array.<ol.geom.Geometry>} geometries Geometries. - */ -ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) { - this.unlistenGeometriesChange_(); - this.geometries_ = geometries; - this.listenGeometriesChange_(); - this.changed(); -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - geometries[i].applyTransform(transformFn); - } - this.changed(); -}; - - -/** - * Translate the geometry. - * @param {number} deltaX Delta X. - * @param {number} deltaY Delta Y. - * @api - */ -ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - geometries[i].translate(deltaX, deltaY); - } - this.changed(); -}; - - -/** - * @inheritDoc - */ -ol.geom.GeometryCollection.prototype.disposeInternal = function() { - this.unlistenGeometriesChange_(); - goog.base(this, 'disposeInternal'); -}; - -// TODO: serialize dataProjection as crs member when writing -// see https://github.com/openlayers/ol3/issues/2078 - -goog.provide('ol.format.GeoJSON'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.JSONFeature'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the GeoJSON format. - * - * @constructor - * @extends {ol.format.JSONFeature} - * @param {olx.format.GeoJSONOptions=} opt_options Options. - * @api stable - */ -ol.format.GeoJSON = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get( - options.defaultDataProjection ? - options.defaultDataProjection : 'EPSG:4326'); - - - /** - * Name of the geometry attribute for features. - * @type {string|undefined} - * @private - */ - this.geometryName_ = options.geometryName; - -}; -goog.inherits(ol.format.GeoJSON, ol.format.JSONFeature); - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.GeoJSON.EXTENSIONS_ = ['.geojson']; - - -/** - * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @private - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.GeoJSON.readGeometry_ = function(object, opt_options) { - if (!object) { - return null; - } - var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type]; - goog.asserts.assert(geometryReader, 'geometryReader should be defined'); - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions( - geometryReader(object), false, opt_options)); -}; - - -/** - * @param {GeoJSONGeometryCollection} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @private - * @return {ol.geom.GeometryCollection} Geometry collection. - */ -ol.format.GeoJSON.readGeometryCollectionGeometry_ = function( - object, opt_options) { - goog.asserts.assert(object.type == 'GeometryCollection', - 'object.type should be GeometryCollection'); - var geometries = object.geometries.map( - /** - * @param {GeoJSONGeometry} geometry Geometry. - * @return {ol.geom.Geometry} geometry Geometry. - */ - function(geometry) { - return ol.format.GeoJSON.readGeometry_(geometry, opt_options); - }); - return new ol.geom.GeometryCollection(geometries); -}; - - -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.Point} Point. - */ -ol.format.GeoJSON.readPointGeometry_ = function(object) { - goog.asserts.assert(object.type == 'Point', - 'object.type should be Point'); - return new ol.geom.Point(object.coordinates); -}; - - -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.LineString} LineString. - */ -ol.format.GeoJSON.readLineStringGeometry_ = function(object) { - goog.asserts.assert(object.type == 'LineString', - 'object.type should be LineString'); - return new ol.geom.LineString(object.coordinates); -}; - - -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.MultiLineString} MultiLineString. - */ -ol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) { - goog.asserts.assert(object.type == 'MultiLineString', - 'object.type should be MultiLineString'); - return new ol.geom.MultiLineString(object.coordinates); -}; - - -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.MultiPoint} MultiPoint. - */ -ol.format.GeoJSON.readMultiPointGeometry_ = function(object) { - goog.asserts.assert(object.type == 'MultiPoint', - 'object.type should be MultiPoint'); - return new ol.geom.MultiPoint(object.coordinates); -}; - - -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.MultiPolygon} MultiPolygon. - */ -ol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) { - goog.asserts.assert(object.type == 'MultiPolygon', - 'object.type should be MultiPolygon'); - return new ol.geom.MultiPolygon(object.coordinates); -}; - - -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.Polygon} Polygon. - */ -ol.format.GeoJSON.readPolygonGeometry_ = function(object) { - goog.asserts.assert(object.type == 'Polygon', - 'object.type should be Polygon'); - return new ol.geom.Polygon(object.coordinates); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry. - */ -ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) { - var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()]; - goog.asserts.assert(geometryWriter, 'geometryWriter should be defined'); - return geometryWriter(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, true, opt_options)), - opt_options); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @private - * @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection. - */ -ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) { - return /** @type {GeoJSONGeometryCollection} */ ({ - type: 'GeometryCollection', - geometries: [] - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometryCollection} GeoJSON geometry collection. - */ -ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function( - geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection, - 'geometry should be an ol.geom.GeometryCollection'); - var geometries = geometry.getGeometriesArray().map(function(geometry) { - return ol.format.GeoJSON.writeGeometry_(geometry, opt_options); - }); - return /** @type {GeoJSONGeometryCollection} */ ({ - type: 'GeometryCollection', - geometries: geometries - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'LineString', - coordinates: geometry.getCoordinates() - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writeMultiLineStringGeometry_ = - function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'MultiLineString', - coordinates: geometry.getCoordinates() - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, - 'geometry should be an ol.geom.MultiPoint'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'MultiPoint', - coordinates: geometry.getCoordinates() - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, - 'geometry should be an ol.geom.MultiPolygon'); - var right; - if (opt_options) { - right = opt_options.rightHanded; - } - return /** @type {GeoJSONGeometry} */ ({ - type: 'MultiPolygon', - coordinates: geometry.getCoordinates(right) - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'Point', - coordinates: geometry.getCoordinates() - }); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - var right; - if (opt_options) { - right = opt_options.rightHanded; - } - return /** @type {GeoJSONGeometry} */ ({ - type: 'Polygon', - coordinates: geometry.getCoordinates(right) - }); -}; - - -/** - * @const - * @private - * @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>} - */ -ol.format.GeoJSON.GEOMETRY_READERS_ = { - 'Point': ol.format.GeoJSON.readPointGeometry_, - 'LineString': ol.format.GeoJSON.readLineStringGeometry_, - 'Polygon': ol.format.GeoJSON.readPolygonGeometry_, - 'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_, - 'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_, - 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_, - 'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_ -}; - - -/** - * @const - * @private - * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>} - */ -ol.format.GeoJSON.GEOMETRY_WRITERS_ = { - 'Point': ol.format.GeoJSON.writePointGeometry_, - 'LineString': ol.format.GeoJSON.writeLineStringGeometry_, - 'Polygon': ol.format.GeoJSON.writePolygonGeometry_, - 'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_, - 'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_, - 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_, - 'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_, - 'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ -}; - - -/** - * @inheritDoc - */ -ol.format.GeoJSON.prototype.getExtensions = function() { - return ol.format.GeoJSON.EXTENSIONS_; -}; - - -/** - * Read a feature from a GeoJSON Feature source. Only works for Feature, - * use `readFeatures` to read FeatureCollection source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.GeoJSON.prototype.readFeature; - - -/** - * Read all features from a GeoJSON source. Works with both Feature and - * FeatureCollection sources. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.GeoJSON.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.GeoJSON.prototype.readFeatureFromObject = function( - object, opt_options) { - var geoJSONFeature = /** @type {GeoJSONFeature} */ (object); - goog.asserts.assert(geoJSONFeature.type == 'Feature', - 'geoJSONFeature.type should be Feature'); - var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry, - opt_options); - var feature = new ol.Feature(); - if (this.geometryName_) { - feature.setGeometryName(this.geometryName_); - } - feature.setGeometry(geometry); - if (geoJSONFeature.id !== undefined) { - feature.setId(geoJSONFeature.id); - } - if (geoJSONFeature.properties) { - feature.setProperties(geoJSONFeature.properties); - } - return feature; -}; - - -/** - * @inheritDoc - */ -ol.format.GeoJSON.prototype.readFeaturesFromObject = function( - object, opt_options) { - var geoJSONObject = /** @type {GeoJSONObject} */ (object); - if (geoJSONObject.type == 'Feature') { - return [this.readFeatureFromObject(object, opt_options)]; - } else if (geoJSONObject.type == 'FeatureCollection') { - var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */ - (object); - /** @type {Array.<ol.Feature>} */ - var features = []; - var geoJSONFeatures = geoJSONFeatureCollection.features; - var i, ii; - for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) { - features.push(this.readFeatureFromObject(geoJSONFeatures[i], - opt_options)); - } - return features; - } else { - goog.asserts.fail('Unknown geoJSONObject.type: ' + geoJSONObject.type); - return []; - } -}; - - -/** - * Read a geometry from a GeoJSON source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api stable - */ -ol.format.GeoJSON.prototype.readGeometry; - - -/** - * @inheritDoc - */ -ol.format.GeoJSON.prototype.readGeometryFromObject = function( - object, opt_options) { - return ol.format.GeoJSON.readGeometry_( - /** @type {GeoJSONGeometry} */ (object), opt_options); -}; - - -/** - * Read the projection from a GeoJSON source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.GeoJSON.prototype.readProjection; - - -/** - * @inheritDoc - */ -ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) { - var geoJSONObject = /** @type {GeoJSONObject} */ (object); - var crs = geoJSONObject.crs; - if (crs) { - if (crs.type == 'name') { - return ol.proj.get(crs.properties.name); - } else if (crs.type == 'EPSG') { - // 'EPSG' is not part of the GeoJSON specification, but is generated by - // GeoServer. - // TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996 - // is fixed and widely deployed. - return ol.proj.get('EPSG:' + crs.properties.code); - } else { - goog.asserts.fail('Unknown crs.type: ' + crs.type); - return null; - } - } else { - return this.defaultDataProjection; - } -}; - - -/** - * Encode a feature as a GeoJSON Feature string. - * - * @function - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} GeoJSON. - * @api stable - */ -ol.format.GeoJSON.prototype.writeFeature; - - -/** - * Encode a feature as a GeoJSON Feature object. - * - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - * @api stable - */ -ol.format.GeoJSON.prototype.writeFeatureObject = function( - feature, opt_options) { - opt_options = this.adaptOptions(opt_options); - var object = { - 'type': 'Feature' - }; - var id = feature.getId(); - if (id !== undefined) { - object['id'] = id; - } - var geometry = feature.getGeometry(); - if (geometry) { - object['geometry'] = - ol.format.GeoJSON.writeGeometry_(geometry, opt_options); - } else { - object['geometry'] = null; - } - var properties = feature.getProperties(); - delete properties[feature.getGeometryName()]; - if (!goog.object.isEmpty(properties)) { - object['properties'] = properties; - } else { - object['properties'] = null; - } - return object; -}; - - -/** - * Encode an array of features as GeoJSON. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} GeoJSON. - * @api stable - */ -ol.format.GeoJSON.prototype.writeFeatures; - - -/** - * Encode an array of features as a GeoJSON object. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} GeoJSON Object. - * @api stable - */ -ol.format.GeoJSON.prototype.writeFeaturesObject = - function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var objects = []; - var i, ii; - for (i = 0, ii = features.length; i < ii; ++i) { - objects.push(this.writeFeatureObject(features[i], opt_options)); - } - return /** @type {GeoJSONFeatureCollection} */ ({ - type: 'FeatureCollection', - features: objects - }); -}; - - -/** - * Encode a geometry as a GeoJSON string. - * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} GeoJSON. - * @api stable - */ -ol.format.GeoJSON.prototype.writeGeometry; - - -/** - * Encode a geometry as a GeoJSON object. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object. - * @api stable - */ -ol.format.GeoJSON.prototype.writeGeometryObject = function(geometry, - opt_options) { - return ol.format.GeoJSON.writeGeometry_(geometry, - this.adaptOptions(opt_options)); -}; - -goog.provide('ol.format.XMLFeature'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.xml'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for XML feature formats. - * - * @constructor - * @extends {ol.format.Feature} - */ -ol.format.XMLFeature = function() { - goog.base(this); -}; -goog.inherits(ol.format.XMLFeature, ol.format.Feature); - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.getType = function() { - return ol.format.FormatType.XML; -}; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.readFeature = function(source, opt_options) { - if (ol.xml.isDocument(source)) { - return this.readFeatureFromDocument( - /** @type {Document} */ (source), opt_options); - } else if (ol.xml.isNode(source)) { - return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFeatureFromDocument(doc, opt_options); - } else { - goog.asserts.fail('Unknown source type'); - return null; - } -}; - - -/** - * @param {Document} doc Document. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {ol.Feature} Feature. - */ -ol.format.XMLFeature.prototype.readFeatureFromDocument = function( - doc, opt_options) { - var features = this.readFeaturesFromDocument(doc, opt_options); - if (features.length > 0) { - return features[0]; - } else { - return null; - } -}; - - -/** - * @param {Node} node Node. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {ol.Feature} Feature. - */ -ol.format.XMLFeature.prototype.readFeatureFromNode = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) { - if (ol.xml.isDocument(source)) { - return this.readFeaturesFromDocument( - /** @type {Document} */ (source), opt_options); - } else if (ol.xml.isNode(source)) { - return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFeaturesFromDocument(doc, opt_options); - } else { - goog.asserts.fail('Unknown source type'); - return []; - } -}; - - -/** - * @param {Document} doc Document. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {Array.<ol.Feature>} Features. - */ -ol.format.XMLFeature.prototype.readFeaturesFromDocument = function( - doc, opt_options) { - /** @type {Array.<ol.Feature>} */ - var features = []; - var n; - for (n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - goog.array.extend(features, this.readFeaturesFromNode(n, opt_options)); - } - } - return features; -}; - - -/** - * @param {Node} node Node. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {Array.<ol.Feature>} Features. - */ -ol.format.XMLFeature.prototype.readFeaturesFromNode = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) { - if (ol.xml.isDocument(source)) { - return this.readGeometryFromDocument( - /** @type {Document} */ (source), opt_options); - } else if (ol.xml.isNode(source)) { - return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readGeometryFromDocument(doc, opt_options); - } else { - goog.asserts.fail('Unknown source type'); - return null; - } -}; - - -/** - * @param {Document} doc Document. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.XMLFeature.prototype.readGeometryFromDocument = goog.abstractMethod; - - -/** - * @param {Node} node Node. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.XMLFeature.prototype.readGeometryFromNode = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.readProjection = function(source) { - if (ol.xml.isDocument(source)) { - return this.readProjectionFromDocument(/** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readProjectionFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readProjectionFromDocument(doc); - } else { - goog.asserts.fail('Unknown source type'); - return null; - } -}; - - -/** - * @param {Document} doc Document. - * @protected - * @return {ol.proj.Projection} Projection. - */ -ol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) { - return this.defaultDataProjection; -}; - - -/** - * @param {Node} node Node. - * @protected - * @return {ol.proj.Projection} Projection. - */ -ol.format.XMLFeature.prototype.readProjectionFromNode = function(node) { - return this.defaultDataProjection; -}; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) { - var node = this.writeFeatureNode(feature, opt_options); - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return goog.dom.xml.serialize(/** @type {Element} */(node)); -}; - - -/** - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Options. - * @protected - * @return {Node} Node. - */ -ol.format.XMLFeature.prototype.writeFeatureNode = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) { - var node = this.writeFeaturesNode(features, opt_options); - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return goog.dom.xml.serialize(/** @type {Element} */(node)); -}; - - -/** - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - */ -ol.format.XMLFeature.prototype.writeFeaturesNode = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) { - var node = this.writeGeometryNode(geometry, opt_options); - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return goog.dom.xml.serialize(/** @type {Element} */(node)); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - */ -ol.format.XMLFeature.prototype.writeGeometryNode = goog.abstractMethod; - -// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part -// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect -// envelopes/extents, only geometries! -goog.provide('ol.format.GMLBase'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Feature base format for reading and writing data in the GML format. - * This class cannot be instantiated, it contains only base content that - * is shared with versioned format classes ol.format.GML2 and - * ol.format.GML3. - * - * @constructor - * @param {olx.format.GMLOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.XMLFeature} - */ -ol.format.GMLBase = function(opt_options) { - var options = /** @type {olx.format.GMLOptions} */ - (opt_options ? opt_options : {}); - - /** - * @protected - * @type {Array.<string>|string|undefined} - */ - this.featureType = options.featureType; - - /** - * @protected - * @type {Object.<string, string>|string|undefined} - */ - this.featureNS = options.featureNS; - - /** - * @protected - * @type {string} - */ - this.srsName = options.srsName; - - /** - * @protected - * @type {string} - */ - this.schemaLocation = ''; - - /** - * @type {Object.<string, Object.<string, Object>>} - */ - this.FEATURE_COLLECTION_PARSERS = {}; - this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = { - 'featureMember': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readFeaturesInternal), - 'featureMembers': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readFeaturesInternal) - }; - - goog.base(this); -}; -goog.inherits(ol.format.GMLBase, ol.format.XMLFeature); - - -/** - * @const - * @type {string} - */ -ol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml'; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<ol.Feature>} Features. - */ -ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var localName = ol.xml.getLocalName(node); - var features; - if (localName == 'FeatureCollection') { - if (node.namespaceURI === 'http://www.opengis.net/wfs') { - features = ol.xml.pushParseAndPop([], - this.FEATURE_COLLECTION_PARSERS, node, - objectStack, this); - } else { - features = ol.xml.pushParseAndPop(null, - this.FEATURE_COLLECTION_PARSERS, node, - objectStack, this); - } - } else if (localName == 'featureMembers' || localName == 'featureMember') { - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featureNS = context['featureNS']; - var i, ii, prefix = 'p', defaultPrefix = 'p0'; - if (!featureType && node.childNodes) { - featureType = [], featureNS = {}; - for (i = 0, ii = node.childNodes.length; i < ii; ++i) { - var child = node.childNodes[i]; - if (child.nodeType === 1) { - var ft = child.nodeName.split(':').pop(); - if (featureType.indexOf(ft) === -1) { - var key; - if (!goog.object.contains(featureNS, child.namespaceURI)) { - key = prefix + goog.object.getCount(featureNS); - featureNS[key] = child.namespaceURI; - } else { - key = goog.object.findKey(featureNS, function(value) { - return value === child.namespaceURI; - }); - } - featureType.push(key + ':' + ft); - } - } - } - context['featureType'] = featureType; - context['featureNS'] = featureNS; - } - if (goog.isString(featureNS)) { - var ns = featureNS; - featureNS = {}; - featureNS[defaultPrefix] = ns; - } - var parsersNS = {}; - var featureTypes = goog.isArray(featureType) ? featureType : [featureType]; - for (var p in featureNS) { - var parsers = {}; - for (i = 0, ii = featureTypes.length; i < ii; ++i) { - var featurePrefix = featureTypes[i].indexOf(':') === -1 ? - defaultPrefix : featureTypes[i].split(':')[0]; - if (featurePrefix === p) { - parsers[featureTypes[i].split(':').pop()] = - (localName == 'featureMembers') ? - ol.xml.makeArrayPusher(this.readFeatureElement, this) : - ol.xml.makeReplacer(this.readFeatureElement, this); - } - } - parsersNS[featureNS[p]] = parsers; - } - features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack); - } - if (!features) { - features = []; - } - return features; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.Geometry|undefined} Geometry. - */ -ol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) { - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - context['srsName'] = node.firstElementChild.getAttribute('srsName'); - var geometry = ol.xml.pushParseAndPop(/** @type {ol.geom.Geometry} */(null), - this.GEOMETRY_PARSERS_, node, objectStack, this); - if (geometry) { - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, false, context)); - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.Feature} Feature. - */ -ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) { - var n; - var fid = node.getAttribute('fid') || - ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id'); - var values = {}, geometryName; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var localName = ol.xml.getLocalName(n); - // Assume attribute elements have one child node and that the child - // is a text or CDATA node (to be treated as text). - // Otherwise assume it is a geometry node. - if (n.childNodes.length === 0 || - (n.childNodes.length === 1 && - (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) { - var value = ol.xml.getAllTextContent(n, false); - if (goog.string.isEmpty(value)) { - value = undefined; - } - values[localName] = value; - } else { - // boundedBy is an extent and must not be considered as a geometry - if (localName !== 'boundedBy') { - geometryName = localName; - } - values[localName] = this.readGeometryElement(n, objectStack); - } - } - var feature = new ol.Feature(values); - if (geometryName) { - feature.setGeometryName(geometryName); - } - if (fid) { - feature.setId(fid); - } - return feature; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.Point|undefined} Point. - */ -ol.format.GMLBase.prototype.readPoint = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Point', 'localName should be Point'); - var flatCoordinates = - this.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var point = new ol.geom.Point(null); - goog.asserts.assert(flatCoordinates.length == 3, - 'flatCoordinates should have a length of 3'); - point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return point; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.MultiPoint|undefined} MultiPoint. - */ -ol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiPoint', - 'localName should be MultiPoint'); - var coordinates = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([]), - this.MULTIPOINT_PARSERS_, node, objectStack, this); - if (coordinates) { - return new ol.geom.MultiPoint(coordinates); - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.MultiLineString|undefined} MultiLineString. - */ -ol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiLineString', - 'localName should be MultiLineString'); - var lineStrings = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.LineString>} */ ([]), - this.MULTILINESTRING_PARSERS_, node, objectStack, this); - if (lineStrings) { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(lineStrings); - return multiLineString; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.MultiPolygon|undefined} MultiPolygon. - */ -ol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiPolygon', - 'localName should be MultiPolygon'); - var polygons = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.Polygon>} */ ([]), - this.MULTIPOLYGON_PARSERS_, node, objectStack, this); - if (polygons) { - var multiPolygon = new ol.geom.MultiPolygon(null); - multiPolygon.setPolygons(polygons); - return multiPolygon; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'pointMember' || - node.localName == 'pointMembers', - 'localName should be pointMember or pointMembers'); - ol.xml.parseNode(this.POINTMEMBER_PARSERS_, - node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GMLBase.prototype.lineStringMemberParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'lineStringMember' || - node.localName == 'lineStringMembers', - 'localName should be LineStringMember or LineStringMembers'); - ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_, - node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GMLBase.prototype.polygonMemberParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'polygonMember' || - node.localName == 'polygonMembers', - 'localName should be polygonMember or polygonMembers'); - ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node, - objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.LineString|undefined} LineString. - */ -ol.format.GMLBase.prototype.readLineString = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineString', - 'localName should be LineString'); - var flatCoordinates = - this.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return lineString; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} LinearRing flat coordinates. - */ -ol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - var ring = ol.xml.pushParseAndPop(/** @type {Array.<number>} */(null), - this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, - objectStack, this); - if (ring) { - return ring; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.LinearRing|undefined} LinearRing. - */ -ol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - var flatCoordinates = - this.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var ring = new ol.geom.LinearRing(null); - ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return ring; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.Polygon|undefined} Polygon. - */ -ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Polygon', - 'localName should be Polygon'); - var flatLinearRings = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this); - if (flatLinearRings && flatLinearRings[0]) { - var polygon = new ol.geom.Polygon(null); - var flatCoordinates = flatLinearRings[0]; - var ends = [flatCoordinates.length]; - var i, ii; - for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); - ends.push(flatCoordinates.length); - } - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); - return polygon; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>} Flat coordinates. - */ -ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop( - null, - this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, - objectStack, this)); -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'pointMember': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.pointMemberParser_), - 'pointMembers': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.pointMemberParser_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'lineStringMember': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.lineStringMemberParser_), - 'lineStringMembers': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.lineStringMemberParser_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'polygonMember': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.polygonMemberParser_), - 'polygonMembers': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.polygonMemberParser_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Point': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'LineString': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readLineString) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Polygon': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readPolygon) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @protected - */ -ol.format.GMLBase.prototype.RING_PARSERS = Object({ - 'http://www.opengis.net/gml' : { - 'LinearRing': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readFlatLinearRing_) - } -}); - - -/** - * @inheritDoc - */ -ol.format.GMLBase.prototype.readGeometryFromNode = - function(node, opt_options) { - var geometry = this.readGeometryElement(node, - [this.getReadOptions(node, opt_options ? opt_options : {})]); - return geometry ? geometry : null; -}; - - -/** - * Read all features from a GML FeatureCollection. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.GMLBase.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.GMLBase.prototype.readFeaturesFromNode = - function(node, opt_options) { - var options = { - featureType: this.featureType, - featureNS: this.featureNS - }; - if (opt_options) { - goog.object.extend(options, this.getReadOptions(node, opt_options)); - } - return this.readFeaturesInternal(node, [options]); -}; - - -/** - * @inheritDoc - */ -ol.format.GMLBase.prototype.readProjectionFromNode = function(node) { - return ol.proj.get(this.srsName_ ? this.srsName_ : - node.firstElementChild.getAttribute('srsName')); -}; - -goog.provide('ol.format.XSD'); - -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('ol'); -goog.require('ol.xml'); - - -/** - * @const - * @type {string} - */ -ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema'; - - -/** - * @param {Node} node Node. - * @return {boolean|undefined} Boolean. - */ -ol.format.XSD.readBoolean = function(node) { - var s = ol.xml.getAllTextContent(node, false); - return ol.format.XSD.readBooleanString(s); -}; - - -/** - * @param {string} string String. - * @return {boolean|undefined} Boolean. - */ -ol.format.XSD.readBooleanString = function(string) { - var m = /^\s*(true|1)|(false|0)\s*$/.exec(string); - if (m) { - return m[1] !== undefined || false; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @return {number|undefined} DateTime in seconds. - */ -ol.format.XSD.readDateTime = function(node) { - var s = ol.xml.getAllTextContent(node, false); - var re = - /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/; - var m = re.exec(s); - if (m) { - var year = parseInt(m[1], 10); - var month = parseInt(m[2], 10) - 1; - var day = parseInt(m[3], 10); - var hour = parseInt(m[4], 10); - var minute = parseInt(m[5], 10); - var second = parseInt(m[6], 10); - var dateTime = Date.UTC(year, month, day, hour, minute, second) / 1000; - if (m[7] != 'Z') { - var sign = m[8] == '-' ? -1 : 1; - dateTime += sign * 60 * parseInt(m[9], 10); - if (m[10] !== undefined) { - dateTime += sign * 60 * 60 * parseInt(m[10], 10); - } - } - return dateTime; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @return {number|undefined} Decimal. - */ -ol.format.XSD.readDecimal = function(node) { - var s = ol.xml.getAllTextContent(node, false); - return ol.format.XSD.readDecimalString(s); -}; - - -/** - * @param {string} string String. - * @return {number|undefined} Decimal. - */ -ol.format.XSD.readDecimalString = function(string) { - // FIXME check spec - var m = /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(string); - if (m) { - return parseFloat(m[1]); - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @return {number|undefined} Non negative integer. - */ -ol.format.XSD.readNonNegativeInteger = function(node) { - var s = ol.xml.getAllTextContent(node, false); - return ol.format.XSD.readNonNegativeIntegerString(s); -}; - - -/** - * @param {string} string String. - * @return {number|undefined} Non negative integer. - */ -ol.format.XSD.readNonNegativeIntegerString = function(string) { - var m = /^\s*(\d+)\s*$/.exec(string); - if (m) { - return parseInt(m[1], 10); - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @return {string|undefined} String. - */ -ol.format.XSD.readString = function(node) { - return ol.xml.getAllTextContent(node, false).trim(); -}; - - -/** - * @param {Node} node Node to append a TextNode with the boolean to. - * @param {boolean} bool Boolean. - */ -ol.format.XSD.writeBooleanTextNode = function(node, bool) { - ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0'); -}; - - -/** - * @param {Node} node Node to append a TextNode with the dateTime to. - * @param {number} dateTime DateTime in seconds. - */ -ol.format.XSD.writeDateTimeTextNode = function(node, dateTime) { - var date = new Date(dateTime * 1000); - var string = date.getUTCFullYear() + '-' + - goog.string.padNumber(date.getUTCMonth() + 1, 2) + '-' + - goog.string.padNumber(date.getUTCDate(), 2) + 'T' + - goog.string.padNumber(date.getUTCHours(), 2) + ':' + - goog.string.padNumber(date.getUTCMinutes(), 2) + ':' + - goog.string.padNumber(date.getUTCSeconds(), 2) + 'Z'; - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); -}; - - -/** - * @param {Node} node Node to append a TextNode with the decimal to. - * @param {number} decimal Decimal. - */ -ol.format.XSD.writeDecimalTextNode = function(node, decimal) { - var string = decimal.toPrecision(); - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); -}; - - -/** - * @param {Node} node Node to append a TextNode with the decimal to. - * @param {number} nonNegativeInteger Non negative integer. - */ -ol.format.XSD.writeNonNegativeIntegerTextNode = - function(node, nonNegativeInteger) { - goog.asserts.assert(nonNegativeInteger >= 0, 'value should be more than 0'); - goog.asserts.assert(nonNegativeInteger == (nonNegativeInteger | 0), - 'value should be an integer value'); - var string = nonNegativeInteger.toString(); - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); -}; - - -/** - * @param {Node} node Node to append a TextNode with the string to. - * @param {string} string String. - */ -ol.format.XSD.writeStringTextNode = function(node, string) { - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); -}; - -goog.provide('ol.format.GML2'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.extent'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.XSD'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the GML format, - * version 2.1.2. - * - * @constructor - * @param {olx.format.GMLOptions=} opt_options Optional configuration object. - * @extends {ol.format.GMLBase} - * @api - */ -ol.format.GML2 = function(opt_options) { - var options = /** @type {olx.format.GMLOptions} */ - (opt_options ? opt_options : {}); - - goog.base(this, options); - - this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][ - 'featureMember'] = - ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal); - - /** - * @inheritDoc - */ - this.schemaLocation = options.schemaLocation ? - options.schemaLocation : ol.format.GML2.schemaLocation_; - -}; -goog.inherits(ol.format.GML2, ol.format.GMLBase); - - -/** - * @const - * @type {string} - * @private - */ -ol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS + - ' http://schemas.opengis.net/gml/2.1.2/feature.xsd'; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} Flat coordinates. - */ -ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) { - var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, ''); - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var containerSrs = context['srsName']; - var containerDimension = node.parentNode.getAttribute('srsDimension'); - var axisOrientation = 'enu'; - if (containerSrs) { - var proj = ol.proj.get(containerSrs); - axisOrientation = proj.getAxisOrientation(); - } - var coords = s.split(/[\s,]+/); - // The "dimension" attribute is from the GML 3.0.1 spec. - var dim = 2; - if (node.getAttribute('srsDimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('srsDimension')); - } else if (node.getAttribute('dimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('dimension')); - } else if (containerDimension) { - dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); - } - var x, y, z; - var flatCoordinates = []; - for (var i = 0, ii = coords.length; i < ii; i += dim) { - x = parseFloat(coords[i]); - y = parseFloat(coords[i + 1]); - z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; - if (axisOrientation.substr(0, 2) === 'en') { - flatCoordinates.push(x, y, z); - } else { - flatCoordinates.push(y, x, z); - } - } - return flatCoordinates; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Extent|undefined} Envelope. - */ -ol.format.GML2.prototype.readBox_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Box', 'localName should be Box'); - var flatCoordinates = ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.BOX_PARSERS_, node, objectStack, this); - return ol.extent.createOrUpdate(flatCoordinates[1][0], - flatCoordinates[1][1], flatCoordinates[1][3], - flatCoordinates[1][4]); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GML2.prototype.innerBoundaryIsParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'innerBoundaryIs', - 'localName should be innerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length larger than 0'); - flatLinearRings.push(flatLinearRing); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GML2.prototype.outerBoundaryIsParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'outerBoundaryIs', - 'localName should be outerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length larger than 0'); - flatLinearRings[0] = flatLinearRing; - } -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'coordinates': ol.xml.makeReplacer( - ol.format.GML2.prototype.readFlatCoordinates_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_, - 'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_ - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML2.prototype.BOX_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'coordinates': ol.xml.makeArrayPusher( - ol.format.GML2.prototype.readFlatCoordinates_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML2.prototype.GEOMETRY_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint), - 'MultiPoint': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPoint), - 'LineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLineString), - 'MultiLineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiLineString), - 'LinearRing' : ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLinearRing), - 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon), - 'MultiPolygon': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPolygon), - 'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_) - } -}); - -goog.provide('ol.format.GML'); -goog.provide('ol.format.GML3'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Feature'); -goog.require('ol.extent'); -goog.require('ol.format.Feature'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the GML format - * version 3.1.1. - * Currently only supports GML 3.1.1 Simple Features profile. - * - * @constructor - * @param {olx.format.GMLOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.GMLBase} - * @api - */ -ol.format.GML3 = function(opt_options) { - var options = /** @type {olx.format.GMLOptions} */ - (opt_options ? opt_options : {}); - - goog.base(this, options); - - /** - * @private - * @type {boolean} - */ - this.surface_ = options.surface !== undefined ? options.surface : false; - - /** - * @private - * @type {boolean} - */ - this.curve_ = options.curve !== undefined ? options.curve : false; - - /** - * @private - * @type {boolean} - */ - this.multiCurve_ = options.multiCurve !== undefined ? - options.multiCurve : true; - - /** - * @private - * @type {boolean} - */ - this.multiSurface_ = options.multiSurface !== undefined ? - options.multiSurface : true; - - /** - * @inheritDoc - */ - this.schemaLocation = options.schemaLocation ? - options.schemaLocation : ol.format.GML3.schemaLocation_; - -}; -goog.inherits(ol.format.GML3, ol.format.GMLBase); - - -/** - * @const - * @type {string} - * @private - */ -ol.format.GML3.schemaLocation_ = ol.format.GMLBase.GMLNS + - ' http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + - '1.0.0/gmlsf.xsd'; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.MultiLineString|undefined} MultiLineString. - */ -ol.format.GML3.prototype.readMultiCurve_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiCurve', - 'localName should be MultiCurve'); - var lineStrings = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.LineString>} */ ([]), - this.MULTICURVE_PARSERS_, node, objectStack, this); - if (lineStrings) { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(lineStrings); - return multiLineString; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.MultiPolygon|undefined} MultiPolygon. - */ -ol.format.GML3.prototype.readMultiSurface_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiSurface', - 'localName should be MultiSurface'); - var polygons = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.Polygon>} */ ([]), - this.MULTISURFACE_PARSERS_, node, objectStack, this); - if (polygons) { - var multiPolygon = new ol.geom.MultiPolygon(null); - multiPolygon.setPolygons(polygons); - return multiPolygon; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GML3.prototype.curveMemberParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'curveMember' || - node.localName == 'curveMembers', - 'localName should be curveMember or curveMembers'); - ol.xml.parseNode(this.CURVEMEMBER_PARSERS_, node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GML3.prototype.surfaceMemberParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'surfaceMember' || - node.localName == 'surfaceMembers', - 'localName should be surfaceMember or surfaceMembers'); - ol.xml.parseNode(this.SURFACEMEMBER_PARSERS_, - node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<(Array.<number>)>|undefined} flat coordinates. - */ -ol.format.GML3.prototype.readPatch_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'patches', - 'localName should be patches'); - return ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.PATCHES_PARSERS_, node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} flat coordinates. - */ -ol.format.GML3.prototype.readSegment_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'segments', - 'localName should be segments'); - return ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.SEGMENTS_PARSERS_, node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<(Array.<number>)>|undefined} flat coordinates. - */ -ol.format.GML3.prototype.readPolygonPatch_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'npde.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'PolygonPatch', - 'localName should be PolygonPatch'); - return ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} flat coordinates. - */ -ol.format.GML3.prototype.readLineStringSegment_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineStringSegment', - 'localName should be LineStringSegment'); - return ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.GEOMETRY_FLAT_COORDINATES_PARSERS_, - node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GML3.prototype.interiorParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'interior', - 'localName should be interior'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length of 1 or more'); - flatLinearRings.push(flatLinearRing); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GML3.prototype.exteriorParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'exterior', - 'localName should be exterior'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length of 1 or more'); - flatLinearRings[0] = flatLinearRing; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Polygon|undefined} Polygon. - */ -ol.format.GML3.prototype.readSurface_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Surface', - 'localName should be Surface'); - var flatLinearRings = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.SURFACE_PARSERS_, node, objectStack, this); - if (flatLinearRings && flatLinearRings[0]) { - var polygon = new ol.geom.Polygon(null); - var flatCoordinates = flatLinearRings[0]; - var ends = [flatCoordinates.length]; - var i, ii; - for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); - ends.push(flatCoordinates.length); - } - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); - return polygon; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.LineString|undefined} LineString. - */ -ol.format.GML3.prototype.readCurve_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Curve', 'localName should be Curve'); - var flatCoordinates = ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.CURVE_PARSERS_, node, objectStack, this); - if (flatCoordinates) { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return lineString; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Extent|undefined} Envelope. - */ -ol.format.GML3.prototype.readEnvelope_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Envelope', - 'localName should be Envelope'); - var flatCoordinates = ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.ENVELOPE_PARSERS_, node, objectStack, this); - return ol.extent.createOrUpdate(flatCoordinates[1][0], - flatCoordinates[1][1], flatCoordinates[2][0], - flatCoordinates[2][1]); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} Flat coordinates. - */ -ol.format.GML3.prototype.readFlatPos_ = function(node, objectStack) { - var s = ol.xml.getAllTextContent(node, false); - var re = /^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/; - /** @type {Array.<number>} */ - var flatCoordinates = []; - var m; - while ((m = re.exec(s))) { - flatCoordinates.push(parseFloat(m[1])); - s = s.substr(m[0].length); - } - if (s !== '') { - return undefined; - } - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var containerSrs = context['srsName']; - var axisOrientation = 'enu'; - if (containerSrs) { - var proj = ol.proj.get(containerSrs); - axisOrientation = proj.getAxisOrientation(); - } - if (axisOrientation === 'neu') { - var i, ii; - for (i = 0, ii = flatCoordinates.length; i < ii; i += 3) { - var y = flatCoordinates[i]; - var x = flatCoordinates[i + 1]; - flatCoordinates[i] = x; - flatCoordinates[i + 1] = y; - } - } - var len = flatCoordinates.length; - if (len == 2) { - flatCoordinates.push(0); - } - if (len === 0) { - return undefined; - } - return flatCoordinates; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} Flat coordinates. - */ -ol.format.GML3.prototype.readFlatPosList_ = function(node, objectStack) { - var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, ''); - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var containerSrs = context['srsName']; - var containerDimension = node.parentNode.getAttribute('srsDimension'); - var axisOrientation = 'enu'; - if (containerSrs) { - var proj = ol.proj.get(containerSrs); - axisOrientation = proj.getAxisOrientation(); - } - var coords = s.split(/\s+/); - // The "dimension" attribute is from the GML 3.0.1 spec. - var dim = 2; - if (node.getAttribute('srsDimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('srsDimension')); - } else if (node.getAttribute('dimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('dimension')); - } else if (containerDimension) { - dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); - } - var x, y, z; - var flatCoordinates = []; - for (var i = 0, ii = coords.length; i < ii; i += dim) { - x = parseFloat(coords[i]); - y = parseFloat(coords[i + 1]); - z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; - if (axisOrientation.substr(0, 2) === 'en') { - flatCoordinates.push(x, y, z); - } else { - flatCoordinates.push(y, x, z); - } - } - return flatCoordinates; -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'pos': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPos_), - 'posList': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPosList_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'interior': ol.format.GML3.prototype.interiorParser_, - 'exterior': ol.format.GML3.prototype.exteriorParser_ - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.GEOMETRY_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint), - 'MultiPoint': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPoint), - 'LineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLineString), - 'MultiLineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiLineString), - 'LinearRing' : ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLinearRing), - 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon), - 'MultiPolygon': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPolygon), - 'Surface': ol.xml.makeReplacer(ol.format.GML3.prototype.readSurface_), - 'MultiSurface': ol.xml.makeReplacer( - ol.format.GML3.prototype.readMultiSurface_), - 'Curve': ol.xml.makeReplacer(ol.format.GML3.prototype.readCurve_), - 'MultiCurve': ol.xml.makeReplacer( - ol.format.GML3.prototype.readMultiCurve_), - 'Envelope': ol.xml.makeReplacer(ol.format.GML3.prototype.readEnvelope_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.MULTICURVE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'curveMember': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.curveMemberParser_), - 'curveMembers': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.curveMemberParser_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.MULTISURFACE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'surfaceMember': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.surfaceMemberParser_), - 'surfaceMembers': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.surfaceMemberParser_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.CURVEMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'LineString': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readLineString), - 'Curve': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readCurve_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.SURFACEMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Polygon': ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readPolygon), - 'Surface': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readSurface_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.SURFACE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'patches': ol.xml.makeReplacer(ol.format.GML3.prototype.readPatch_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.CURVE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'segments': ol.xml.makeReplacer(ol.format.GML3.prototype.readSegment_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.ENVELOPE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'lowerCorner': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.readFlatPosList_), - 'upperCorner': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.readFlatPosList_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.PATCHES_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'PolygonPatch': ol.xml.makeReplacer( - ol.format.GML3.prototype.readPolygonPatch_) - } -}); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GML3.prototype.SEGMENTS_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'LineStringSegment': ol.xml.makeReplacer( - ol.format.GML3.prototype.readLineStringSegment_) - } -}); - - -/** - * @param {Node} node Node. - * @param {ol.geom.Point} value Point geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writePos_ = function(node, value, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - var axisOrientation = 'enu'; - if (srsName) { - axisOrientation = ol.proj.get(srsName).getAxisOrientation(); - } - var point = value.getCoordinates(); - var coords; - // only 2d for simple features profile - if (axisOrientation.substr(0, 2) === 'en') { - coords = (point[0] + ' ' + point[1]); - } else { - coords = (point[1] + ' ' + point[0]); - } - ol.format.XSD.writeStringTextNode(node, coords); -}; - - -/** - * @param {Array.<number>} point Point geometry. - * @param {string=} opt_srsName Optional srsName - * @return {string} - * @private - */ -ol.format.GML3.prototype.getCoords_ = function(point, opt_srsName) { - var axisOrientation = 'enu'; - if (opt_srsName) { - axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation(); - } - return ((axisOrientation.substr(0, 2) === 'en') ? - point[0] + ' ' + point[1] : - point[1] + ' ' + point[0]); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writePosList_ = function(node, value, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - // only 2d for simple features profile - var points = value.getCoordinates(); - var len = points.length; - var parts = new Array(len); - var point; - for (var i = 0; i < len; ++i) { - point = points[i]; - parts[i] = this.getCoords_(point, srsName); - } - ol.format.XSD.writeStringTextNode(node, parts.join(' ')); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Point} geometry Point geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writePoint_ = function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); - } - var pos = ol.xml.createElementNS(node.namespaceURI, 'pos'); - node.appendChild(pos); - this.writePos_(pos, geometry, objectStack); -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GML3.ENVELOPE_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.Extent} extent Extent. - * @param {Array.<*>} objectStack Node stack. - */ -ol.format.GML3.prototype.writeEnvelope = function(node, extent, objectStack) { - goog.asserts.assert(extent.length == 4, 'extent should have 4 items'); - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); - } - var keys = ['lowerCorner', 'upperCorner']; - var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]]; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node}), ol.format.GML3.ENVELOPE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, - objectStack, keys, this); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LinearRing} geometry LinearRing geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeLinearRing_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); - } - var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); - node.appendChild(posList); - this.writePosList_(posList, geometry, objectStack); -}; - - -/** - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node} Node. - * @private - */ -ol.format.GML3.prototype.RING_NODE_FACTORY_ = - function(value, objectStack, opt_nodeName) { - var context = objectStack[objectStack.length - 1]; - var parentNode = context.node; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var exteriorWritten = context['exteriorWritten']; - if (exteriorWritten === undefined) { - context['exteriorWritten'] = true; - } - return ol.xml.createElementNS(parentNode.namespaceURI, - exteriorWritten !== undefined ? 'interior' : 'exterior'); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Polygon} geometry Polygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeSurfaceOrPolygon_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (node.nodeName !== 'PolygonPatch' && srsName) { - node.setAttribute('srsName', srsName); - } - if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') { - var rings = geometry.getLinearRings(); - ol.xml.pushSerializeAndPop( - {node: node, srsName: srsName}, - ol.format.GML3.RING_SERIALIZERS_, - this.RING_NODE_FACTORY_, - rings, objectStack, undefined, this); - } else if (node.nodeName === 'Surface') { - var patches = ol.xml.createElementNS(node.namespaceURI, 'patches'); - node.appendChild(patches); - this.writeSurfacePatches_( - patches, geometry, objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString} geometry LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeCurveOrLineString_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (node.nodeName !== 'LineStringSegment' && srsName) { - node.setAttribute('srsName', srsName); - } - if (node.nodeName === 'LineString' || - node.nodeName === 'LineStringSegment') { - var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); - node.appendChild(posList); - this.writePosList_(posList, geometry, objectStack); - } else if (node.nodeName === 'Curve') { - var segments = ol.xml.createElementNS(node.namespaceURI, 'segments'); - node.appendChild(segments); - this.writeCurveSegments_(segments, - geometry, objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - var surface = context['surface']; - if (srsName) { - node.setAttribute('srsName', srsName); - } - var polygons = geometry.getPolygons(); - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, - ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_, - this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons, - objectStack, undefined, this); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.MultiPoint} geometry MultiPoint geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeMultiPoint_ = function(node, geometry, - objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); - } - var points = geometry.getPoints(); - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML3.POINTMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('pointMember'), points, - objectStack, undefined, this); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.MultiLineString} geometry MultiLineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeMultiCurveOrLineString_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - var curve = context['curve']; - if (srsName) { - node.setAttribute('srsName', srsName); - } - var lines = geometry.getLineStrings(); - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, - ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_, - this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines, - objectStack, undefined, this); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LinearRing} ring LinearRing geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeRing_ = function(node, ring, objectStack) { - var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing'); - node.appendChild(linearRing); - this.writeLinearRing_(linearRing, ring, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Polygon} polygon Polygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeSurfaceOrPolygonMember_ = - function(node, polygon, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var child = this.GEOMETRY_NODE_FACTORY_( - polygon, objectStack); - if (child) { - node.appendChild(child); - this.writeSurfaceOrPolygon_(child, polygon, objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Point} point Point geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writePointMember_ = - function(node, point, objectStack) { - var child = ol.xml.createElementNS(node.namespaceURI, 'Point'); - node.appendChild(child); - this.writePoint_(child, point, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString} line LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeLineStringOrCurveMember_ = - function(node, line, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack); - if (child) { - node.appendChild(child); - this.writeCurveOrLineString_(child, line, objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Polygon} polygon Polygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeSurfacePatches_ = - function(node, polygon, objectStack) { - var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch'); - node.appendChild(child); - this.writeSurfaceOrPolygon_(child, polygon, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString} line LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeCurveSegments_ = - function(node, line, objectStack) { - var child = ol.xml.createElementNS(node.namespaceURI, - 'LineStringSegment'); - node.appendChild(child); - this.writeCurveOrLineString_(child, line, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Geometry|ol.Extent} geometry Geometry. - * @param {Array.<*>} objectStack Node stack. - */ -ol.format.GML3.prototype.writeGeometryElement = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var item = goog.object.clone(context); - item.node = node; - var value; - if (goog.isArray(geometry)) { - if (context.dataProjection) { - value = ol.proj.transformExtent( - geometry, context.featureProjection, context.dataProjection); - } else { - value = geometry; - } - } else { - goog.asserts.assertInstanceof(geometry, ol.geom.Geometry, - 'geometry should be an ol.geom.Geometry'); - value = - ol.format.Feature.transformWithOptions(geometry, true, context); - } - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), ol.format.GML3.GEOMETRY_SERIALIZERS_, - this.GEOMETRY_NODE_FACTORY_, [value], - objectStack, undefined, this); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - */ -ol.format.GML3.prototype.writeFeatureElement = - function(node, feature, objectStack) { - var fid = feature.getId(); - if (fid) { - node.setAttribute('fid', fid); - } - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureNS = context['featureNS']; - var geometryName = feature.getGeometryName(); - if (!context.serializers) { - context.serializers = {}; - context.serializers[featureNS] = {}; - } - var properties = feature.getProperties(); - var keys = [], values = []; - for (var key in properties) { - var value = properties[key]; - if (value !== null) { - keys.push(key); - values.push(value); - if (key == geometryName || value instanceof ol.geom.Geometry) { - if (!(key in context.serializers[featureNS])) { - context.serializers[featureNS][key] = ol.xml.makeChildAppender( - this.writeGeometryElement, this); - } - } else { - if (!(key in context.serializers[featureNS])) { - context.serializers[featureNS][key] = ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode); - } - } - } - } - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), context.serializers, - ol.xml.makeSimpleNodeFactory(undefined, featureNS), - values, - objectStack, keys); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<ol.Feature>} features Features. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeFeatureMembers_ = - function(node, features, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featureNS = context['featureNS']; - var serializers = {}; - serializers[featureNS] = {}; - serializers[featureNS][featureType] = ol.xml.makeChildAppender( - this.writeFeatureElement, this); - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), - serializers, - ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, - objectStack); -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'surfaceMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygonMember_), - 'polygonMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygonMember_) - } -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GML3.POINTMEMBER_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'pointMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writePointMember_) - } -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'lineStringMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeLineStringOrCurveMember_), - 'curveMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeLineStringOrCurveMember_) - } -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GML3.RING_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'exterior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_), - 'interior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_) - } -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GML3.GEOMETRY_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'Curve': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeCurveOrLineString_), - 'MultiCurve': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiCurveOrLineString_), - 'Point': ol.xml.makeChildAppender(ol.format.GML3.prototype.writePoint_), - 'MultiPoint': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiPoint_), - 'LineString': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeCurveOrLineString_), - 'MultiLineString': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiCurveOrLineString_), - 'LinearRing': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeLinearRing_), - 'Polygon': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygon_), - 'MultiPolygon': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_), - 'Surface': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygon_), - 'MultiSurface': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_), - 'Envelope': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeEnvelope) - } -}; - - -/** - * @const - * @type {Object.<string, string>} - * @private - */ -ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = { - 'MultiLineString': 'lineStringMember', - 'MultiCurve': 'curveMember', - 'MultiPolygon': 'polygonMember', - 'MultiSurface': 'surfaceMember' -}; - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.GML3.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = - function(value, objectStack, opt_nodeName) { - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be a node'); - return ol.xml.createElementNS('http://www.opengis.net/gml', - ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]); -}; - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.GML3.prototype.GEOMETRY_NODE_FACTORY_ = - function(value, objectStack, opt_nodeName) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var multiSurface = context['multiSurface']; - var surface = context['surface']; - var curve = context['curve']; - var multiCurve = context['multiCurve']; - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be a node'); - var nodeName; - if (!goog.isArray(value)) { - goog.asserts.assertInstanceof(value, ol.geom.Geometry, - 'value should be an ol.geom.Geometry'); - nodeName = value.getType(); - if (nodeName === 'MultiPolygon' && multiSurface === true) { - nodeName = 'MultiSurface'; - } else if (nodeName === 'Polygon' && surface === true) { - nodeName = 'Surface'; - } else if (nodeName === 'LineString' && curve === true) { - nodeName = 'Curve'; - } else if (nodeName === 'MultiLineString' && multiCurve === true) { - nodeName = 'MultiCurve'; - } - } else { - nodeName = 'Envelope'; - } - return ol.xml.createElementNS('http://www.opengis.net/gml', - nodeName); -}; - - -/** - * Encode a geometry in GML 3.1.1 Simple Features. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.GML3.prototype.writeGeometryNode = function(geometry, opt_options) { - opt_options = this.adaptOptions(opt_options); - var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); - var context = {node: geom, srsName: this.srsName, - curve: this.curve_, surface: this.surface_, - multiSurface: this.multiSurface_, multiCurve: this.multiCurve_}; - if (opt_options) { - goog.object.extend(context, opt_options); - } - this.writeGeometryElement(geom, geometry, [context]); - return geom; -}; - - -/** - * Encode an array of features in GML 3.1.1 Simple Features. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {string} Result. - * @api stable - */ -ol.format.GML3.prototype.writeFeatures; - - -/** - * Encode an array of features in the GML 3.1.1 format as an XML node. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.GML3.prototype.writeFeaturesNode = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var node = ol.xml.createElementNS('http://www.opengis.net/gml', - 'featureMembers'); - ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', this.schemaLocation); - var context = { - srsName: this.srsName, - curve: this.curve_, - surface: this.surface_, - multiSurface: this.multiSurface_, - multiCurve: this.multiCurve_, - featureNS: this.featureNS, - featureType: this.featureType - }; - if (opt_options) { - goog.object.extend(context, opt_options); - } - this.writeFeatureMembers_(node, features, [context]); - return node; -}; - - - -/** - * @classdesc - * Feature format for reading and writing data in the GML format - * version 3.1.1. - * Currently only supports GML 3.1.1 Simple Features profile. - * - * @constructor - * @param {olx.format.GMLOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.GMLBase} - * @api stable - */ -ol.format.GML = ol.format.GML3; - - -/** - * Encode an array of features in GML 3.1.1 Simple Features. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {string} Result. - * @api stable - */ -ol.format.GML.prototype.writeFeatures; - - -/** - * Encode an array of features in the GML 3.1.1 format as an XML node. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.GML.prototype.writeFeaturesNode; - -goog.provide('ol.format.GPX'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.Feature'); -goog.require('ol.array'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.Point'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the GPX format. - * - * @constructor - * @extends {ol.format.XMLFeature} - * @param {olx.format.GPXOptions=} opt_options Options. - * @api stable - */ -ol.format.GPX = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); - - /** - * @type {function(ol.Feature, Node)|undefined} - * @private - */ - this.readExtensions_ = options.readExtensions; -}; -goog.inherits(ol.format.GPX, ol.format.XMLFeature); - - -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.format.GPX.NAMESPACE_URIS_ = [ - null, - 'http://www.topografix.com/GPX/1/0', - 'http://www.topografix.com/GPX/1/1' -]; - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Node} node Node. - * @param {Object} values Values. - * @private - * @return {Array.<number>} Flat coordinates. - */ -ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - flatCoordinates.push( - parseFloat(node.getAttribute('lon')), - parseFloat(node.getAttribute('lat'))); - if ('ele' in values) { - flatCoordinates.push(/** @type {number} */ (values['ele'])); - delete values['ele']; - } else { - flatCoordinates.push(0); - } - if ('time' in values) { - flatCoordinates.push(/** @type {number} */ (values['time'])); - delete values['time']; - } else { - flatCoordinates.push(0); - } - return flatCoordinates; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.parseLink_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'link', 'localName should be link'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var href = node.getAttribute('href'); - if (href !== null) { - values['link'] = href; - } - ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.parseExtensions_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'extensions', - 'localName should be extensions'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - values['extensionsNode_'] = node; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.parseRtePt_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'rtept', 'localName should be rtept'); - var values = ol.xml.pushParseAndPop( - {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack); - if (values) { - var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var flatCoordinates = /** @type {Array.<number>} */ - (rteValues['flatCoordinates']); - ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.parseTrkPt_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'trkpt', 'localName should be trkpt'); - var values = ol.xml.pushParseAndPop( - {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack); - if (values) { - var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var flatCoordinates = /** @type {Array.<number>} */ - (trkValues['flatCoordinates']); - ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.parseTrkSeg_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'trkseg', - 'localName should be trkseg'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack); - var flatCoordinates = /** @type {Array.<number>} */ - (values['flatCoordinates']); - var ends = /** @type {Array.<number>} */ (values['ends']); - ends.push(flatCoordinates.length); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Track. - */ -ol.format.GPX.readRte_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'rte', 'localName should be rte'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var values = ol.xml.pushParseAndPop({ - 'flatCoordinates': [] - }, ol.format.GPX.RTE_PARSERS_, node, objectStack); - if (!values) { - return undefined; - } - var flatCoordinates = /** @type {Array.<number>} */ - (values['flatCoordinates']); - delete values['flatCoordinates']; - var geometry = new ol.geom.LineString(null); - geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setProperties(values); - return feature; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Track. - */ -ol.format.GPX.readTrk_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'trk', 'localName should be trk'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var values = ol.xml.pushParseAndPop({ - 'flatCoordinates': [], - 'ends': [] - }, ol.format.GPX.TRK_PARSERS_, node, objectStack); - if (!values) { - return undefined; - } - var flatCoordinates = /** @type {Array.<number>} */ - (values['flatCoordinates']); - delete values['flatCoordinates']; - var ends = /** @type {Array.<number>} */ (values['ends']); - delete values['ends']; - var geometry = new ol.geom.MultiLineString(null); - geometry.setFlatCoordinates( - ol.geom.GeometryLayout.XYZM, flatCoordinates, ends); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setProperties(values); - return feature; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Waypoint. - */ -ol.format.GPX.readWpt_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'wpt', 'localName should be wpt'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var values = ol.xml.pushParseAndPop( - {}, ol.format.GPX.WPT_PARSERS_, node, objectStack); - if (!values) { - return undefined; - } - var coordinates = ol.format.GPX.appendCoordinate_([], node, values); - var geometry = new ol.geom.Point( - coordinates, ol.geom.GeometryLayout.XYZM); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setProperties(values); - return feature; -}; - - -/** - * @const - * @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>} - * @private - */ -ol.format.GPX.FEATURE_READER_ = { - 'rte': ol.format.GPX.readRte_, - 'trk': ol.format.GPX.readTrk_, - 'wpt': ol.format.GPX.readWpt_ -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_), - 'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_), - 'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'text': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'), - 'type': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType') - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'link': ol.format.GPX.parseLink_, - 'number': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), - 'extensions': ol.format.GPX.parseExtensions_, - 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'rtept': ol.format.GPX.parseRtePt_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'link': ol.format.GPX.parseLink_, - 'number': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), - 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'extensions': ol.format.GPX.parseExtensions_, - 'trkseg': ol.format.GPX.parseTrkSeg_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'trkpt': ol.format.GPX.parseTrkPt_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.GPX.WPT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime), - 'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'link': ol.format.GPX.parseLink_, - 'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'sat': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'ageofdgpsdata': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'dgpsid': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), - 'extensions': ol.format.GPX.parseExtensions_ - }); - - -/** - * @param {Array.<ol.Feature>} features - * @private - */ -ol.format.GPX.prototype.handleReadExtensions_ = function(features) { - if (!features) { - features = []; - } - for (var i = 0, ii = features.length; i < ii; ++i) { - var feature = features[i]; - if (this.readExtensions_) { - var extensionsNode = feature.get('extensionsNode_') || null; - this.readExtensions_(feature, extensionsNode); - } - feature.set('extensionsNode_', undefined); - } -}; - - -/** - * Read the first feature from a GPX source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.GPX.prototype.readFeature; - - -/** - * @inheritDoc - */ -ol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) { - return null; - } - var featureReader = ol.format.GPX.FEATURE_READER_[node.localName]; - if (!featureReader) { - return null; - } - var feature = featureReader(node, [this.getReadOptions(node, opt_options)]); - if (!feature) { - return null; - } - this.handleReadExtensions_([feature]); - return feature; -}; - - -/** - * Read all features from a GPX source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.GPX.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) { - return []; - } - if (node.localName == 'gpx') { - var features = ol.xml.pushParseAndPop( - /** @type {Array.<ol.Feature>} */ ([]), ol.format.GPX.GPX_PARSERS_, - node, [this.getReadOptions(node, opt_options)]); - if (features) { - this.handleReadExtensions_(features); - return features; - } else { - return []; - } - } - return []; -}; - - -/** - * Read the projection from a GPX source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.GPX.prototype.readProjection; - - -/** - * @param {Node} node Node. - * @param {string} value Value for the link's `href` attribute. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GPX.writeLink_ = function(node, value, objectStack) { - node.setAttribute('href', value); - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var properties = context['properties']; - var link = [ - properties['linkText'], - properties['linkType'] - ]; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ ({node: node}), - ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - link, objectStack, ol.format.GPX.LINK_SEQUENCE_); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var parentNode = context.node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - var namespaceURI = parentNode.namespaceURI; - var properties = context['properties']; - //FIXME Projection handling - ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]); - ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]); - var geometryLayout = context['geometryLayout']; - /* jshint -W086 */ - switch (geometryLayout) { - case ol.geom.GeometryLayout.XYZM: - if (coordinate[3] !== 0) { - properties['time'] = coordinate[3]; - } - case ol.geom.GeometryLayout.XYZ: - if (coordinate[2] !== 0) { - properties['ele'] = coordinate[2]; - } - break; - case ol.geom.GeometryLayout.XYM: - if (coordinate[2] !== 0) { - properties['time'] = coordinate[2]; - } - } - /* jshint +W086 */ - var orderedKeys = ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, 'properties': properties}), - ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.writeRte_ = function(node, feature, objectStack) { - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var properties = feature.getProperties(); - var context = {node: node, 'properties': properties}; - var geometry = feature.getGeometry(); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - geometry = /** @type {ol.geom.LineString} */ - (ol.format.Feature.transformWithOptions(geometry, true, options)); - context['geometryLayout'] = geometry.getLayout(); - properties['rtept'] = geometry.getCoordinates(); - } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), - ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.writeTrk_ = function(node, feature, objectStack) { - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var properties = feature.getProperties(); - var context = {node: node, 'properties': properties}; - var geometry = feature.getGeometry(); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - geometry = /** @type {ol.geom.MultiLineString} */ - (ol.format.Feature.transformWithOptions(geometry, true, options)); - properties['trkseg'] = geometry.getLineStrings(); - } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), - ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LineString} lineString LineString. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) { - var context = {node: node, 'geometryLayout': lineString.getLayout(), - 'properties': {}}; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), - ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_, - lineString.getCoordinates(), objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GPX.writeWpt_ = function(node, feature, objectStack) { - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - context['properties'] = feature.getProperties(); - var geometry = feature.getGeometry(); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - geometry = /** @type {ol.geom.Point} */ - (ol.format.Feature.transformWithOptions(geometry, true, options)); - context['geometryLayout'] = geometry.getLayout(); - ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack); - } -}; - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.GPX.LINK_SEQUENCE_ = ['text', 'type']; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, [ - 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), - 'number': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender( - ol.format.GPX.writeWptType_)) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, [ - 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), - 'number': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender( - ol.format.GPX.writeTrkSeg_)) - }); - - -/** - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt'); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, [ - 'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src', - 'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop', - 'ageofdgpsdata', 'dgpsid' - ]); - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode), - 'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'geoidheight': ol.xml.makeChildAppender( - ol.format.XSD.writeDecimalTextNode), - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), - 'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'sat': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode), - 'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'ageofdgpsdata': ol.xml.makeChildAppender( - ol.format.XSD.writeDecimalTextNode), - 'dgpsid': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode) - }); - - -/** - * @const - * @type {Object.<string, string>} - * @private - */ -ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = { - 'Point': 'wpt', - 'LineString': 'rte', - 'MultiLineString': 'trk' -}; - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { - goog.asserts.assertInstanceof(value, ol.Feature, - 'value should be an ol.Feature'); - var geometry = value.getGeometry(); - if (geometry) { - var nodeName = ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()]; - if (nodeName) { - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - return ol.xml.createElementNS(parentNode.namespaceURI, nodeName); - } - } -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_), - 'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_), - 'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_) - }); - - -/** - * Encode an array of features in the GPX format. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - * @api stable - */ -ol.format.GPX.prototype.writeFeatures; - - -/** - * Encode an array of features in the GPX format as an XML node. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - //FIXME Serialize metadata - var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx'); - - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_, - ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]); - return gpx; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Utilities for string newlines. - * @author nnaze@google.com (Nathan Naze) - */ - - -/** - * Namespace for string utilities - */ -goog.provide('goog.string.newlines'); -goog.provide('goog.string.newlines.Line'); - -goog.require('goog.array'); - - -/** - * Splits a string into lines, properly handling universal newlines. - * @param {string} str String to split. - * @param {boolean=} opt_keepNewlines Whether to keep the newlines in the - * resulting strings. Defaults to false. - * @return {!Array<string>} String split into lines. - */ -goog.string.newlines.splitLines = function(str, opt_keepNewlines) { - var lines = goog.string.newlines.getLines(str); - return goog.array.map(lines, function(line) { - return opt_keepNewlines ? line.getFullLine() : line.getContent(); - }); -}; - - - -/** - * Line metadata class that records the start/end indicies of lines - * in a string. Can be used to implement common newline use cases such as - * splitLines() or determining line/column of an index in a string. - * Also implements methods to get line contents. - * - * Indexes are expressed as string indicies into string.substring(), inclusive - * at the start, exclusive at the end. - * - * Create an array of these with goog.string.newlines.getLines(). - * @param {string} string The original string. - * @param {number} startLineIndex The index of the start of the line. - * @param {number} endContentIndex The index of the end of the line, excluding - * newlines. - * @param {number} endLineIndex The index of the end of the line, index - * newlines. - * @constructor - * @struct - * @final - */ -goog.string.newlines.Line = function(string, startLineIndex, - endContentIndex, endLineIndex) { - /** - * The original string. - * @type {string} - */ - this.string = string; - - /** - * Index of the start of the line. - * @type {number} - */ - this.startLineIndex = startLineIndex; - - /** - * Index of the end of the line, excluding any newline characters. - * Index is the first character after the line, suitable for - * String.substring(). - * @type {number} - */ - this.endContentIndex = endContentIndex; - - /** - * Index of the end of the line, excluding any newline characters. - * Index is the first character after the line, suitable for - * String.substring(). - * @type {number} - */ - - this.endLineIndex = endLineIndex; -}; - - -/** - * @return {string} The content of the line, excluding any newline characters. - */ -goog.string.newlines.Line.prototype.getContent = function() { - return this.string.substring(this.startLineIndex, this.endContentIndex); -}; - - -/** - * @return {string} The full line, including any newline characters. - */ -goog.string.newlines.Line.prototype.getFullLine = function() { - return this.string.substring(this.startLineIndex, this.endLineIndex); -}; - - -/** - * @return {string} The newline characters, if any ('\n', \r', '\r\n', '', etc). - */ -goog.string.newlines.Line.prototype.getNewline = function() { - return this.string.substring(this.endContentIndex, this.endLineIndex); -}; - - -/** - * Splits a string into an array of line metadata. - * @param {string} str String to split. - * @return {!Array<!goog.string.newlines.Line>} Array of line metadata. - */ -goog.string.newlines.getLines = function(str) { - // We use the constructor because literals are evaluated only once in - // < ES 3.1. - // See http://www.mail-archive.com/es-discuss@mozilla.org/msg01796.html - var re = RegExp('\r\n|\r|\n', 'g'); - var sliceIndex = 0; - var result; - var lines = []; - - while (result = re.exec(str)) { - var line = new goog.string.newlines.Line( - str, sliceIndex, result.index, result.index + result[0].length); - lines.push(line); - - // remember where to start the slice from - sliceIndex = re.lastIndex; - } - - // If the string does not end with a newline, add the last line. - if (sliceIndex < str.length) { - var line = new goog.string.newlines.Line( - str, sliceIndex, str.length, str.length); - lines.push(line); - } - - return lines; -}; - -goog.provide('ol.format.TextFeature'); - -goog.require('goog.asserts'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); - - - -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for text feature formats. - * - * @constructor - * @extends {ol.format.Feature} - */ -ol.format.TextFeature = function() { - goog.base(this); -}; -goog.inherits(ol.format.TextFeature, ol.format.Feature); - - -/** - * @param {Document|Node|Object|string} source Source. - * @private - * @return {string} Text. - */ -ol.format.TextFeature.prototype.getText_ = function(source) { - if (goog.isString(source)) { - return source; - } else { - goog.asserts.fail(); - return ''; - } -}; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.getType = function() { - return ol.format.FormatType.TEXT; -}; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.readFeature = function(source, opt_options) { - return this.readFeatureFromText( - this.getText_(source), this.adaptOptions(opt_options)); -}; - - -/** - * @param {string} text Text. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.Feature} Feature. - */ -ol.format.TextFeature.prototype.readFeatureFromText = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) { - return this.readFeaturesFromText( - this.getText_(source), this.adaptOptions(opt_options)); -}; - - -/** - * @param {string} text Text. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {Array.<ol.Feature>} Features. - */ -ol.format.TextFeature.prototype.readFeaturesFromText = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) { - return this.readGeometryFromText( - this.getText_(source), this.adaptOptions(opt_options)); -}; - - -/** - * @param {string} text Text. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.TextFeature.prototype.readGeometryFromText = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.readProjection = function(source) { - return this.readProjectionFromText(this.getText_(source)); -}; - - -/** - * @param {string} text Text. - * @protected - * @return {ol.proj.Projection} Projection. - */ -ol.format.TextFeature.prototype.readProjectionFromText = function(text) { - return this.defaultDataProjection; -}; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) { - return this.writeFeatureText(feature, this.adaptOptions(opt_options)); -}; - - -/** - * @param {ol.Feature} feature Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @protected - * @return {string} Text. - */ -ol.format.TextFeature.prototype.writeFeatureText = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.writeFeatures = function( - features, opt_options) { - return this.writeFeaturesText(features, this.adaptOptions(opt_options)); -}; - - -/** - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @protected - * @return {string} Text. - */ -ol.format.TextFeature.prototype.writeFeaturesText = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.writeGeometry = function( - geometry, opt_options) { - return this.writeGeometryText(geometry, this.adaptOptions(opt_options)); -}; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @protected - * @return {string} Text. - */ -ol.format.TextFeature.prototype.writeGeometryText = goog.abstractMethod; - -goog.provide('ol.format.IGC'); -goog.provide('ol.format.IGCZ'); - -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.string.newlines'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.TextFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.proj'); - - -/** - * IGC altitude/z. One of 'barometric', 'gps', 'none'. - * @enum {string} - * @api - */ -ol.format.IGCZ = { - BAROMETRIC: 'barometric', - GPS: 'gps', - NONE: 'none' -}; - - - -/** - * @classdesc - * Feature format for `*.igc` flight recording files. - * - * @constructor - * @extends {ol.format.TextFeature} - * @param {olx.format.IGCOptions=} opt_options Options. - * @api - */ -ol.format.IGC = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); - - /** - * @private - * @type {ol.format.IGCZ} - */ - this.altitudeMode_ = options.altitudeMode ? - options.altitudeMode : ol.format.IGCZ.NONE; - -}; -goog.inherits(ol.format.IGC, ol.format.TextFeature); - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.IGC.EXTENSIONS_ = ['.igc']; - - -/** - * @const - * @type {RegExp} - * @private - */ -ol.format.IGC.B_RECORD_RE_ = - /^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/; - - -/** - * @const - * @type {RegExp} - * @private - */ -ol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/; - - -/** - * @const - * @type {RegExp} - * @private - */ -ol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\d{2})(\d{2})(\d{2})/; - - -/** - * @inheritDoc - */ -ol.format.IGC.prototype.getExtensions = function() { - return ol.format.IGC.EXTENSIONS_; -}; - - -/** - * Read the feature from the IGC source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api - */ -ol.format.IGC.prototype.readFeature; - - -/** - * @inheritDoc - */ -ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) { - var altitudeMode = this.altitudeMode_; - var lines = goog.string.newlines.splitLines(text); - /** @type {Object.<string, string>} */ - var properties = {}; - var flatCoordinates = []; - var year = 2000; - var month = 0; - var day = 1; - var i, ii; - for (i = 0, ii = lines.length; i < ii; ++i) { - var line = lines[i]; - var m; - if (line.charAt(0) == 'B') { - m = ol.format.IGC.B_RECORD_RE_.exec(line); - if (m) { - var hour = parseInt(m[1], 10); - var minute = parseInt(m[2], 10); - var second = parseInt(m[3], 10); - var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000; - if (m[6] == 'S') { - y = -y; - } - var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000; - if (m[9] == 'W') { - x = -x; - } - flatCoordinates.push(x, y); - if (altitudeMode != ol.format.IGCZ.NONE) { - var z; - if (altitudeMode == ol.format.IGCZ.GPS) { - z = parseInt(m[11], 10); - } else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) { - z = parseInt(m[12], 10); - } else { - goog.asserts.fail(); - z = 0; - } - flatCoordinates.push(z); - } - var dateTime = Date.UTC(year, month, day, hour, minute, second); - flatCoordinates.push(dateTime / 1000); - } - } else if (line.charAt(0) == 'H') { - m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line); - if (m) { - day = parseInt(m[1], 10); - month = parseInt(m[2], 10) - 1; - year = 2000 + parseInt(m[3], 10); - } else { - m = ol.format.IGC.H_RECORD_RE_.exec(line); - if (m) { - properties[m[1]] = m[2].trim(); - m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line); - } - } - } - } - if (flatCoordinates.length === 0) { - return null; - } - var lineString = new ol.geom.LineString(null); - var layout = altitudeMode == ol.format.IGCZ.NONE ? - ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM; - lineString.setFlatCoordinates(layout, flatCoordinates); - var feature = new ol.Feature(ol.format.Feature.transformWithOptions( - lineString, false, opt_options)); - feature.setProperties(properties); - return feature; -}; - - -/** - * Read the feature from the source. As IGC sources contain a single - * feature, this will return the feature in an array. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api - */ -ol.format.IGC.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) { - var feature = this.readFeatureFromText(text, opt_options); - if (feature) { - return [feature]; - } else { - return []; - } -}; - - -/** - * Read the projection from the IGC source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api - */ -ol.format.IGC.prototype.readProjection; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Class for parsing and formatting URIs. - * - * Use goog.Uri(string) to parse a URI string. Use goog.Uri.create(...) to - * create a new instance of the goog.Uri object from Uri parts. - * - * e.g: <code>var myUri = new goog.Uri(window.location);</code> - * - * Implements RFC 3986 for parsing/formatting URIs. - * http://www.ietf.org/rfc/rfc3986.txt - * - * Some changes have been made to the interface (more like .NETs), though the - * internal representation is now of un-encoded parts, this will change the - * behavior slightly. - * - */ - -goog.provide('goog.Uri'); -goog.provide('goog.Uri.QueryData'); - -goog.require('goog.array'); -goog.require('goog.string'); -goog.require('goog.structs'); -goog.require('goog.structs.Map'); -goog.require('goog.uri.utils'); -goog.require('goog.uri.utils.ComponentIndex'); -goog.require('goog.uri.utils.StandardQueryParam'); - - - -/** - * This class contains setters and getters for the parts of the URI. - * The <code>getXyz</code>/<code>setXyz</code> methods return the decoded part - * -- so<code>goog.Uri.parse('/foo%20bar').getPath()</code> will return the - * decoded path, <code>/foo bar</code>. - * - * Reserved characters (see RFC 3986 section 2.2) can be present in - * their percent-encoded form in scheme, domain, and path URI components and - * will not be auto-decoded. For example: - * <code>goog.Uri.parse('rel%61tive/path%2fto/resource').getPath()</code> will - * return <code>relative/path%2fto/resource</code>. - * - * The constructor accepts an optional unparsed, raw URI string. The parser - * is relaxed, so special characters that aren't escaped but don't cause - * ambiguities will not cause parse failures. - * - * All setters return <code>this</code> and so may be chained, a la - * <code>goog.Uri.parse('/foo').setFragment('part').toString()</code>. - * - * @param {*=} opt_uri Optional string URI to parse - * (use goog.Uri.create() to create a URI from parts), or if - * a goog.Uri is passed, a clone is created. - * @param {boolean=} opt_ignoreCase If true, #getParameterValue will ignore - * the case of the parameter name. - * - * @throws URIError If opt_uri is provided and URI is malformed (that is, - * if decodeURIComponent fails on any of the URI components). - * @constructor - * @struct - */ -goog.Uri = function(opt_uri, opt_ignoreCase) { - /** - * Scheme such as "http". - * @private {string} - */ - this.scheme_ = ''; - - /** - * User credentials in the form "username:password". - * @private {string} - */ - this.userInfo_ = ''; - - /** - * Domain part, e.g. "www.google.com". - * @private {string} - */ - this.domain_ = ''; - - /** - * Port, e.g. 8080. - * @private {?number} - */ - this.port_ = null; - - /** - * Path, e.g. "/tests/img.png". - * @private {string} - */ - this.path_ = ''; - - /** - * The fragment without the #. - * @private {string} - */ - this.fragment_ = ''; - - /** - * Whether or not this Uri should be treated as Read Only. - * @private {boolean} - */ - this.isReadOnly_ = false; - - /** - * Whether or not to ignore case when comparing query params. - * @private {boolean} - */ - this.ignoreCase_ = false; - - /** - * Object representing query data. - * @private {!goog.Uri.QueryData} - */ - this.queryData_; - - // Parse in the uri string - var m; - if (opt_uri instanceof goog.Uri) { - this.ignoreCase_ = goog.isDef(opt_ignoreCase) ? - opt_ignoreCase : opt_uri.getIgnoreCase(); - this.setScheme(opt_uri.getScheme()); - this.setUserInfo(opt_uri.getUserInfo()); - this.setDomain(opt_uri.getDomain()); - this.setPort(opt_uri.getPort()); - this.setPath(opt_uri.getPath()); - this.setQueryData(opt_uri.getQueryData().clone()); - this.setFragment(opt_uri.getFragment()); - } else if (opt_uri && (m = goog.uri.utils.split(String(opt_uri)))) { - this.ignoreCase_ = !!opt_ignoreCase; - - // Set the parts -- decoding as we do so. - // COMPATABILITY NOTE - In IE, unmatched fields may be empty strings, - // whereas in other browsers they will be undefined. - this.setScheme(m[goog.uri.utils.ComponentIndex.SCHEME] || '', true); - this.setUserInfo(m[goog.uri.utils.ComponentIndex.USER_INFO] || '', true); - this.setDomain(m[goog.uri.utils.ComponentIndex.DOMAIN] || '', true); - this.setPort(m[goog.uri.utils.ComponentIndex.PORT]); - this.setPath(m[goog.uri.utils.ComponentIndex.PATH] || '', true); - this.setQueryData(m[goog.uri.utils.ComponentIndex.QUERY_DATA] || '', true); - this.setFragment(m[goog.uri.utils.ComponentIndex.FRAGMENT] || '', true); - - } else { - this.ignoreCase_ = !!opt_ignoreCase; - this.queryData_ = new goog.Uri.QueryData(null, null, this.ignoreCase_); - } -}; - - -/** - * If true, we preserve the type of query parameters set programmatically. - * - * This means that if you set a parameter to a boolean, and then call - * getParameterValue, you will get a boolean back. - * - * If false, we will coerce parameters to strings, just as they would - * appear in real URIs. - * - * TODO(nicksantos): Remove this once people have time to fix all tests. - * - * @type {boolean} - */ -goog.Uri.preserveParameterTypesCompatibilityFlag = false; - - -/** - * Parameter name added to stop caching. - * @type {string} - */ -goog.Uri.RANDOM_PARAM = goog.uri.utils.StandardQueryParam.RANDOM; - - -/** - * @return {string} The string form of the url. - * @override - */ -goog.Uri.prototype.toString = function() { - var out = []; - - var scheme = this.getScheme(); - if (scheme) { - out.push(goog.Uri.encodeSpecialChars_( - scheme, goog.Uri.reDisallowedInSchemeOrUserInfo_, true), ':'); - } - - var domain = this.getDomain(); - if (domain || scheme == 'file') { - out.push('//'); - - var userInfo = this.getUserInfo(); - if (userInfo) { - out.push(goog.Uri.encodeSpecialChars_( - userInfo, goog.Uri.reDisallowedInSchemeOrUserInfo_, true), '@'); - } - - out.push(goog.Uri.removeDoubleEncoding_(goog.string.urlEncode(domain))); - - var port = this.getPort(); - if (port != null) { - out.push(':', String(port)); - } - } - - var path = this.getPath(); - if (path) { - if (this.hasDomain() && path.charAt(0) != '/') { - out.push('/'); - } - out.push(goog.Uri.encodeSpecialChars_( - path, - path.charAt(0) == '/' ? - goog.Uri.reDisallowedInAbsolutePath_ : - goog.Uri.reDisallowedInRelativePath_, - true)); - } - - var query = this.getEncodedQuery(); - if (query) { - out.push('?', query); - } - - var fragment = this.getFragment(); - if (fragment) { - out.push('#', goog.Uri.encodeSpecialChars_( - fragment, goog.Uri.reDisallowedInFragment_)); - } - return out.join(''); -}; - - -/** - * Resolves the given relative URI (a goog.Uri object), using the URI - * represented by this instance as the base URI. - * - * There are several kinds of relative URIs:<br> - * 1. foo - replaces the last part of the path, the whole query and fragment<br> - * 2. /foo - replaces the the path, the query and fragment<br> - * 3. //foo - replaces everything from the domain on. foo is a domain name<br> - * 4. ?foo - replace the query and fragment<br> - * 5. #foo - replace the fragment only - * - * Additionally, if relative URI has a non-empty path, all ".." and "." - * segments will be resolved, as described in RFC 3986. - * - * @param {!goog.Uri} relativeUri The relative URI to resolve. - * @return {!goog.Uri} The resolved URI. - */ -goog.Uri.prototype.resolve = function(relativeUri) { - - var absoluteUri = this.clone(); - - // we satisfy these conditions by looking for the first part of relativeUri - // that is not blank and applying defaults to the rest - - var overridden = relativeUri.hasScheme(); - - if (overridden) { - absoluteUri.setScheme(relativeUri.getScheme()); - } else { - overridden = relativeUri.hasUserInfo(); - } - - if (overridden) { - absoluteUri.setUserInfo(relativeUri.getUserInfo()); - } else { - overridden = relativeUri.hasDomain(); - } - - if (overridden) { - absoluteUri.setDomain(relativeUri.getDomain()); - } else { - overridden = relativeUri.hasPort(); - } - - var path = relativeUri.getPath(); - if (overridden) { - absoluteUri.setPort(relativeUri.getPort()); - } else { - overridden = relativeUri.hasPath(); - if (overridden) { - // resolve path properly - if (path.charAt(0) != '/') { - // path is relative - if (this.hasDomain() && !this.hasPath()) { - // RFC 3986, section 5.2.3, case 1 - path = '/' + path; - } else { - // RFC 3986, section 5.2.3, case 2 - var lastSlashIndex = absoluteUri.getPath().lastIndexOf('/'); - if (lastSlashIndex != -1) { - path = absoluteUri.getPath().substr(0, lastSlashIndex + 1) + path; - } - } - } - path = goog.Uri.removeDotSegments(path); - } - } - - if (overridden) { - absoluteUri.setPath(path); - } else { - overridden = relativeUri.hasQuery(); - } - - if (overridden) { - absoluteUri.setQueryData(relativeUri.getDecodedQuery()); - } else { - overridden = relativeUri.hasFragment(); - } - - if (overridden) { - absoluteUri.setFragment(relativeUri.getFragment()); - } - - return absoluteUri; -}; - - -/** - * Clones the URI instance. - * @return {!goog.Uri} New instance of the URI object. - */ -goog.Uri.prototype.clone = function() { - return new goog.Uri(this); -}; - - -/** - * @return {string} The encoded scheme/protocol for the URI. - */ -goog.Uri.prototype.getScheme = function() { - return this.scheme_; -}; - - -/** - * Sets the scheme/protocol. - * @throws URIError If opt_decode is true and newScheme is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newScheme New scheme value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setScheme = function(newScheme, opt_decode) { - this.enforceReadOnly(); - this.scheme_ = opt_decode ? goog.Uri.decodeOrEmpty_(newScheme, true) : - newScheme; - - // remove an : at the end of the scheme so somebody can pass in - // window.location.protocol - if (this.scheme_) { - this.scheme_ = this.scheme_.replace(/:$/, ''); - } - return this; -}; - - -/** - * @return {boolean} Whether the scheme has been set. - */ -goog.Uri.prototype.hasScheme = function() { - return !!this.scheme_; -}; - - -/** - * @return {string} The decoded user info. - */ -goog.Uri.prototype.getUserInfo = function() { - return this.userInfo_; -}; - - -/** - * Sets the userInfo. - * @throws URIError If opt_decode is true and newUserInfo is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newUserInfo New userInfo value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setUserInfo = function(newUserInfo, opt_decode) { - this.enforceReadOnly(); - this.userInfo_ = opt_decode ? goog.Uri.decodeOrEmpty_(newUserInfo) : - newUserInfo; - return this; -}; - - -/** - * @return {boolean} Whether the user info has been set. - */ -goog.Uri.prototype.hasUserInfo = function() { - return !!this.userInfo_; -}; - - -/** - * @return {string} The decoded domain. - */ -goog.Uri.prototype.getDomain = function() { - return this.domain_; -}; - - -/** - * Sets the domain. - * @throws URIError If opt_decode is true and newDomain is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newDomain New domain value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setDomain = function(newDomain, opt_decode) { - this.enforceReadOnly(); - this.domain_ = opt_decode ? goog.Uri.decodeOrEmpty_(newDomain, true) : - newDomain; - return this; -}; - - -/** - * @return {boolean} Whether the domain has been set. - */ -goog.Uri.prototype.hasDomain = function() { - return !!this.domain_; -}; - - -/** - * @return {?number} The port number. - */ -goog.Uri.prototype.getPort = function() { - return this.port_; -}; - - -/** - * Sets the port number. - * @param {*} newPort Port number. Will be explicitly casted to a number. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setPort = function(newPort) { - this.enforceReadOnly(); - - if (newPort) { - newPort = Number(newPort); - if (isNaN(newPort) || newPort < 0) { - throw Error('Bad port number ' + newPort); - } - this.port_ = newPort; - } else { - this.port_ = null; - } - - return this; -}; - - -/** - * @return {boolean} Whether the port has been set. - */ -goog.Uri.prototype.hasPort = function() { - return this.port_ != null; -}; - - -/** - * @return {string} The decoded path. - */ -goog.Uri.prototype.getPath = function() { - return this.path_; -}; - - -/** - * Sets the path. - * @throws URIError If opt_decode is true and newPath is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newPath New path value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setPath = function(newPath, opt_decode) { - this.enforceReadOnly(); - this.path_ = opt_decode ? goog.Uri.decodeOrEmpty_(newPath, true) : newPath; - return this; -}; - - -/** - * @return {boolean} Whether the path has been set. - */ -goog.Uri.prototype.hasPath = function() { - return !!this.path_; -}; - - -/** - * @return {boolean} Whether the query string has been set. - */ -goog.Uri.prototype.hasQuery = function() { - return this.queryData_.toString() !== ''; -}; - - -/** - * Sets the query data. - * @param {goog.Uri.QueryData|string|undefined} queryData QueryData object. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * Applies only if queryData is a string. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setQueryData = function(queryData, opt_decode) { - this.enforceReadOnly(); - - if (queryData instanceof goog.Uri.QueryData) { - this.queryData_ = queryData; - this.queryData_.setIgnoreCase(this.ignoreCase_); - } else { - if (!opt_decode) { - // QueryData accepts encoded query string, so encode it if - // opt_decode flag is not true. - queryData = goog.Uri.encodeSpecialChars_(queryData, - goog.Uri.reDisallowedInQuery_); - } - this.queryData_ = new goog.Uri.QueryData(queryData, null, this.ignoreCase_); - } - - return this; -}; - - -/** - * Sets the URI query. - * @param {string} newQuery New query value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setQuery = function(newQuery, opt_decode) { - return this.setQueryData(newQuery, opt_decode); -}; - - -/** - * @return {string} The encoded URI query, not including the ?. - */ -goog.Uri.prototype.getEncodedQuery = function() { - return this.queryData_.toString(); -}; - - -/** - * @return {string} The decoded URI query, not including the ?. - */ -goog.Uri.prototype.getDecodedQuery = function() { - return this.queryData_.toDecodedString(); -}; - - -/** - * Returns the query data. - * @return {!goog.Uri.QueryData} QueryData object. - */ -goog.Uri.prototype.getQueryData = function() { - return this.queryData_; -}; - - -/** - * @return {string} The encoded URI query, not including the ?. - * - * Warning: This method, unlike other getter methods, returns encoded - * value, instead of decoded one. - */ -goog.Uri.prototype.getQuery = function() { - return this.getEncodedQuery(); -}; - - -/** - * Sets the value of the named query parameters, clearing previous values for - * that key. - * - * @param {string} key The parameter to set. - * @param {*} value The new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setParameterValue = function(key, value) { - this.enforceReadOnly(); - this.queryData_.set(key, value); - return this; -}; - - -/** - * Sets the values of the named query parameters, clearing previous values for - * that key. Not new values will currently be moved to the end of the query - * string. - * - * So, <code>goog.Uri.parse('foo?a=b&c=d&e=f').setParameterValues('c', ['new']) - * </code> yields <tt>foo?a=b&e=f&c=new</tt>.</p> - * - * @param {string} key The parameter to set. - * @param {*} values The new values. If values is a single - * string then it will be treated as the sole value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setParameterValues = function(key, values) { - this.enforceReadOnly(); - - if (!goog.isArray(values)) { - values = [String(values)]; - } - - this.queryData_.setValues(key, values); - - return this; -}; - - -/** - * Returns the value<b>s</b> for a given cgi parameter as a list of decoded - * query parameter values. - * @param {string} name The parameter to get values for. - * @return {!Array<?>} The values for a given cgi parameter as a list of - * decoded query parameter values. - */ -goog.Uri.prototype.getParameterValues = function(name) { - return this.queryData_.getValues(name); -}; - - -/** - * Returns the first value for a given cgi parameter or undefined if the given - * parameter name does not appear in the query string. - * @param {string} paramName Unescaped parameter name. - * @return {string|undefined} The first value for a given cgi parameter or - * undefined if the given parameter name does not appear in the query - * string. - */ -goog.Uri.prototype.getParameterValue = function(paramName) { - // NOTE(nicksantos): This type-cast is a lie when - // preserveParameterTypesCompatibilityFlag is set to true. - // But this should only be set to true in tests. - return /** @type {string|undefined} */ (this.queryData_.get(paramName)); -}; - - -/** - * @return {string} The URI fragment, not including the #. - */ -goog.Uri.prototype.getFragment = function() { - return this.fragment_; -}; - - -/** - * Sets the URI fragment. - * @throws URIError If opt_decode is true and newFragment is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newFragment New fragment value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setFragment = function(newFragment, opt_decode) { - this.enforceReadOnly(); - this.fragment_ = opt_decode ? goog.Uri.decodeOrEmpty_(newFragment) : - newFragment; - return this; -}; - - -/** - * @return {boolean} Whether the URI has a fragment set. - */ -goog.Uri.prototype.hasFragment = function() { - return !!this.fragment_; -}; - - -/** - * Returns true if this has the same domain as that of uri2. - * @param {!goog.Uri} uri2 The URI object to compare to. - * @return {boolean} true if same domain; false otherwise. - */ -goog.Uri.prototype.hasSameDomainAs = function(uri2) { - return ((!this.hasDomain() && !uri2.hasDomain()) || - this.getDomain() == uri2.getDomain()) && - ((!this.hasPort() && !uri2.hasPort()) || - this.getPort() == uri2.getPort()); -}; - - -/** - * Adds a random parameter to the Uri. - * @return {!goog.Uri} Reference to this Uri object. - */ -goog.Uri.prototype.makeUnique = function() { - this.enforceReadOnly(); - this.setParameterValue(goog.Uri.RANDOM_PARAM, goog.string.getRandomString()); - - return this; -}; - - -/** - * Removes the named query parameter. - * - * @param {string} key The parameter to remove. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.removeParameter = function(key) { - this.enforceReadOnly(); - this.queryData_.remove(key); - return this; -}; - - -/** - * Sets whether Uri is read only. If this goog.Uri is read-only, - * enforceReadOnly_ will be called at the start of any function that may modify - * this Uri. - * @param {boolean} isReadOnly whether this goog.Uri should be read only. - * @return {!goog.Uri} Reference to this Uri object. - */ -goog.Uri.prototype.setReadOnly = function(isReadOnly) { - this.isReadOnly_ = isReadOnly; - return this; -}; - - -/** - * @return {boolean} Whether the URI is read only. - */ -goog.Uri.prototype.isReadOnly = function() { - return this.isReadOnly_; -}; - - -/** - * Checks if this Uri has been marked as read only, and if so, throws an error. - * This should be called whenever any modifying function is called. - */ -goog.Uri.prototype.enforceReadOnly = function() { - if (this.isReadOnly_) { - throw Error('Tried to modify a read-only Uri'); - } -}; - - -/** - * Sets whether to ignore case. - * NOTE: If there are already key/value pairs in the QueryData, and - * ignoreCase_ is set to false, the keys will all be lower-cased. - * @param {boolean} ignoreCase whether this goog.Uri should ignore case. - * @return {!goog.Uri} Reference to this Uri object. - */ -goog.Uri.prototype.setIgnoreCase = function(ignoreCase) { - this.ignoreCase_ = ignoreCase; - if (this.queryData_) { - this.queryData_.setIgnoreCase(ignoreCase); - } - return this; -}; - - -/** - * @return {boolean} Whether to ignore case. - */ -goog.Uri.prototype.getIgnoreCase = function() { - return this.ignoreCase_; -}; - - -//============================================================================== -// Static members -//============================================================================== - - -/** - * Creates a uri from the string form. Basically an alias of new goog.Uri(). - * If a Uri object is passed to parse then it will return a clone of the object. - * - * @throws URIError If parsing the URI is malformed. The passed URI components - * should all be parseable by decodeURIComponent. - * @param {*} uri Raw URI string or instance of Uri - * object. - * @param {boolean=} opt_ignoreCase Whether to ignore the case of parameter - * names in #getParameterValue. - * @return {!goog.Uri} The new URI object. - */ -goog.Uri.parse = function(uri, opt_ignoreCase) { - return uri instanceof goog.Uri ? - uri.clone() : new goog.Uri(uri, opt_ignoreCase); -}; - - -/** - * Creates a new goog.Uri object from unencoded parts. - * - * @param {?string=} opt_scheme Scheme/protocol or full URI to parse. - * @param {?string=} opt_userInfo username:password. - * @param {?string=} opt_domain www.google.com. - * @param {?number=} opt_port 9830. - * @param {?string=} opt_path /some/path/to/a/file.html. - * @param {string|goog.Uri.QueryData=} opt_query a=1&b=2. - * @param {?string=} opt_fragment The fragment without the #. - * @param {boolean=} opt_ignoreCase Whether to ignore parameter name case in - * #getParameterValue. - * - * @return {!goog.Uri} The new URI object. - */ -goog.Uri.create = function(opt_scheme, opt_userInfo, opt_domain, opt_port, - opt_path, opt_query, opt_fragment, opt_ignoreCase) { - - var uri = new goog.Uri(null, opt_ignoreCase); - - // Only set the parts if they are defined and not empty strings. - opt_scheme && uri.setScheme(opt_scheme); - opt_userInfo && uri.setUserInfo(opt_userInfo); - opt_domain && uri.setDomain(opt_domain); - opt_port && uri.setPort(opt_port); - opt_path && uri.setPath(opt_path); - opt_query && uri.setQueryData(opt_query); - opt_fragment && uri.setFragment(opt_fragment); - - return uri; -}; - - -/** - * Resolves a relative Uri against a base Uri, accepting both strings and - * Uri objects. - * - * @param {*} base Base Uri. - * @param {*} rel Relative Uri. - * @return {!goog.Uri} Resolved uri. - */ -goog.Uri.resolve = function(base, rel) { - if (!(base instanceof goog.Uri)) { - base = goog.Uri.parse(base); - } - - if (!(rel instanceof goog.Uri)) { - rel = goog.Uri.parse(rel); - } - - return base.resolve(rel); -}; - - -/** - * Removes dot segments in given path component, as described in - * RFC 3986, section 5.2.4. - * - * @param {string} path A non-empty path component. - * @return {string} Path component with removed dot segments. - */ -goog.Uri.removeDotSegments = function(path) { - if (path == '..' || path == '.') { - return ''; - - } else if (!goog.string.contains(path, './') && - !goog.string.contains(path, '/.')) { - // This optimization detects uris which do not contain dot-segments, - // and as a consequence do not require any processing. - return path; - - } else { - var leadingSlash = goog.string.startsWith(path, '/'); - var segments = path.split('/'); - var out = []; - - for (var pos = 0; pos < segments.length; ) { - var segment = segments[pos++]; - - if (segment == '.') { - if (leadingSlash && pos == segments.length) { - out.push(''); - } - } else if (segment == '..') { - if (out.length > 1 || out.length == 1 && out[0] != '') { - out.pop(); - } - if (leadingSlash && pos == segments.length) { - out.push(''); - } - } else { - out.push(segment); - leadingSlash = true; - } - } - - return out.join('/'); - } -}; - - -/** - * Decodes a value or returns the empty string if it isn't defined or empty. - * @throws URIError If decodeURIComponent fails to decode val. - * @param {string|undefined} val Value to decode. - * @param {boolean=} opt_preserveReserved If true, restricted characters will - * not be decoded. - * @return {string} Decoded value. - * @private - */ -goog.Uri.decodeOrEmpty_ = function(val, opt_preserveReserved) { - // Don't use UrlDecode() here because val is not a query parameter. - if (!val) { - return ''; - } - - // decodeURI has the same output for '%2f' and '%252f'. We double encode %25 - // so that we can distinguish between the 2 inputs. This is later undone by - // removeDoubleEncoding_. - return opt_preserveReserved ? - decodeURI(val.replace(/%25/g, '%2525')) : decodeURIComponent(val); -}; - - -/** - * If unescapedPart is non null, then escapes any characters in it that aren't - * valid characters in a url and also escapes any special characters that - * appear in extra. - * - * @param {*} unescapedPart The string to encode. - * @param {RegExp} extra A character set of characters in [\01-\177]. - * @param {boolean=} opt_removeDoubleEncoding If true, remove double percent - * encoding. - * @return {?string} null iff unescapedPart == null. - * @private - */ -goog.Uri.encodeSpecialChars_ = function(unescapedPart, extra, - opt_removeDoubleEncoding) { - if (goog.isString(unescapedPart)) { - var encoded = encodeURI(unescapedPart). - replace(extra, goog.Uri.encodeChar_); - if (opt_removeDoubleEncoding) { - // encodeURI double-escapes %XX sequences used to represent restricted - // characters in some URI components, remove the double escaping here. - encoded = goog.Uri.removeDoubleEncoding_(encoded); - } - return encoded; - } - return null; -}; - - -/** - * Converts a character in [\01-\177] to its unicode character equivalent. - * @param {string} ch One character string. - * @return {string} Encoded string. - * @private - */ -goog.Uri.encodeChar_ = function(ch) { - var n = ch.charCodeAt(0); - return '%' + ((n >> 4) & 0xf).toString(16) + (n & 0xf).toString(16); -}; - - -/** - * Removes double percent-encoding from a string. - * @param {string} doubleEncodedString String - * @return {string} String with double encoding removed. - * @private - */ -goog.Uri.removeDoubleEncoding_ = function(doubleEncodedString) { - return doubleEncodedString.replace(/%25([0-9a-fA-F]{2})/g, '%$1'); -}; - - -/** - * Regular expression for characters that are disallowed in the scheme or - * userInfo part of the URI. - * @type {RegExp} - * @private - */ -goog.Uri.reDisallowedInSchemeOrUserInfo_ = /[#\/\?@]/g; - - -/** - * Regular expression for characters that are disallowed in a relative path. - * Colon is included due to RFC 3986 3.3. - * @type {RegExp} - * @private - */ -goog.Uri.reDisallowedInRelativePath_ = /[\#\?:]/g; - - -/** - * Regular expression for characters that are disallowed in an absolute path. - * @type {RegExp} - * @private - */ -goog.Uri.reDisallowedInAbsolutePath_ = /[\#\?]/g; - - -/** - * Regular expression for characters that are disallowed in the query. - * @type {RegExp} - * @private - */ -goog.Uri.reDisallowedInQuery_ = /[\#\?@]/g; - - -/** - * Regular expression for characters that are disallowed in the fragment. - * @type {RegExp} - * @private - */ -goog.Uri.reDisallowedInFragment_ = /#/g; - - -/** - * Checks whether two URIs have the same domain. - * @param {string} uri1String First URI string. - * @param {string} uri2String Second URI string. - * @return {boolean} true if the two URIs have the same domain; false otherwise. - */ -goog.Uri.haveSameDomain = function(uri1String, uri2String) { - // Differs from goog.uri.utils.haveSameDomain, since this ignores scheme. - // TODO(gboyer): Have this just call goog.uri.util.haveSameDomain. - var pieces1 = goog.uri.utils.split(uri1String); - var pieces2 = goog.uri.utils.split(uri2String); - return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] == - pieces2[goog.uri.utils.ComponentIndex.DOMAIN] && - pieces1[goog.uri.utils.ComponentIndex.PORT] == - pieces2[goog.uri.utils.ComponentIndex.PORT]; -}; - - - -/** - * Class used to represent URI query parameters. It is essentially a hash of - * name-value pairs, though a name can be present more than once. - * - * Has the same interface as the collections in goog.structs. - * - * @param {?string=} opt_query Optional encoded query string to parse into - * the object. - * @param {goog.Uri=} opt_uri Optional uri object that should have its - * cache invalidated when this object updates. Deprecated -- this - * is no longer required. - * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter - * name in #get. - * @constructor - * @struct - * @final - */ -goog.Uri.QueryData = function(opt_query, opt_uri, opt_ignoreCase) { - /** - * The map containing name/value or name/array-of-values pairs. - * May be null if it requires parsing from the query string. - * - * We need to use a Map because we cannot guarantee that the key names will - * not be problematic for IE. - * - * @private {goog.structs.Map<string, !Array<*>>} - */ - this.keyMap_ = null; - - /** - * The number of params, or null if it requires computing. - * @private {?number} - */ - this.count_ = null; - - /** - * Encoded query string, or null if it requires computing from the key map. - * @private {?string} - */ - this.encodedQuery_ = opt_query || null; - - /** - * If true, ignore the case of the parameter name in #get. - * @private {boolean} - */ - this.ignoreCase_ = !!opt_ignoreCase; -}; - - -/** - * If the underlying key map is not yet initialized, it parses the - * query string and fills the map with parsed data. - * @private - */ -goog.Uri.QueryData.prototype.ensureKeyMapInitialized_ = function() { - if (!this.keyMap_) { - this.keyMap_ = new goog.structs.Map(); - this.count_ = 0; - if (this.encodedQuery_) { - var self = this; - goog.uri.utils.parseQueryData(this.encodedQuery_, function(name, value) { - self.add(goog.string.urlDecode(name), value); - }); - } - } -}; - - -/** - * Creates a new query data instance from a map of names and values. - * - * @param {!goog.structs.Map<string, ?>|!Object} map Map of string parameter - * names to parameter value. If parameter value is an array, it is - * treated as if the key maps to each individual value in the - * array. - * @param {goog.Uri=} opt_uri URI object that should have its cache - * invalidated when this object updates. - * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter - * name in #get. - * @return {!goog.Uri.QueryData} The populated query data instance. - */ -goog.Uri.QueryData.createFromMap = function(map, opt_uri, opt_ignoreCase) { - var keys = goog.structs.getKeys(map); - if (typeof keys == 'undefined') { - throw Error('Keys are undefined'); - } - - var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase); - var values = goog.structs.getValues(map); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = values[i]; - if (!goog.isArray(value)) { - queryData.add(key, value); - } else { - queryData.setValues(key, value); - } - } - return queryData; -}; - - -/** - * Creates a new query data instance from parallel arrays of parameter names - * and values. Allows for duplicate parameter names. Throws an error if the - * lengths of the arrays differ. - * - * @param {!Array<string>} keys Parameter names. - * @param {!Array<?>} values Parameter values. - * @param {goog.Uri=} opt_uri URI object that should have its cache - * invalidated when this object updates. - * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter - * name in #get. - * @return {!goog.Uri.QueryData} The populated query data instance. - */ -goog.Uri.QueryData.createFromKeysValues = function( - keys, values, opt_uri, opt_ignoreCase) { - if (keys.length != values.length) { - throw Error('Mismatched lengths for keys/values'); - } - var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase); - for (var i = 0; i < keys.length; i++) { - queryData.add(keys[i], values[i]); - } - return queryData; -}; - - -/** - * @return {?number} The number of parameters. - */ -goog.Uri.QueryData.prototype.getCount = function() { - this.ensureKeyMapInitialized_(); - return this.count_; -}; - - -/** - * Adds a key value pair. - * @param {string} key Name. - * @param {*} value Value. - * @return {!goog.Uri.QueryData} Instance of this object. - */ -goog.Uri.QueryData.prototype.add = function(key, value) { - this.ensureKeyMapInitialized_(); - this.invalidateCache_(); - - key = this.getKeyName_(key); - var values = this.keyMap_.get(key); - if (!values) { - this.keyMap_.set(key, (values = [])); - } - values.push(value); - this.count_++; - return this; -}; - - -/** - * Removes all the params with the given key. - * @param {string} key Name. - * @return {boolean} Whether any parameter was removed. - */ -goog.Uri.QueryData.prototype.remove = function(key) { - this.ensureKeyMapInitialized_(); - - key = this.getKeyName_(key); - if (this.keyMap_.containsKey(key)) { - this.invalidateCache_(); - - // Decrement parameter count. - this.count_ -= this.keyMap_.get(key).length; - return this.keyMap_.remove(key); - } - return false; -}; - - -/** - * Clears the parameters. - */ -goog.Uri.QueryData.prototype.clear = function() { - this.invalidateCache_(); - this.keyMap_ = null; - this.count_ = 0; -}; - - -/** - * @return {boolean} Whether we have any parameters. - */ -goog.Uri.QueryData.prototype.isEmpty = function() { - this.ensureKeyMapInitialized_(); - return this.count_ == 0; -}; - - -/** - * Whether there is a parameter with the given name - * @param {string} key The parameter name to check for. - * @return {boolean} Whether there is a parameter with the given name. - */ -goog.Uri.QueryData.prototype.containsKey = function(key) { - this.ensureKeyMapInitialized_(); - key = this.getKeyName_(key); - return this.keyMap_.containsKey(key); -}; - - -/** - * Whether there is a parameter with the given value. - * @param {*} value The value to check for. - * @return {boolean} Whether there is a parameter with the given value. - */ -goog.Uri.QueryData.prototype.containsValue = function(value) { - // NOTE(arv): This solution goes through all the params even if it was the - // first param. We can get around this by not reusing code or by switching to - // iterators. - var vals = this.getValues(); - return goog.array.contains(vals, value); -}; - - -/** - * Returns all the keys of the parameters. If a key is used multiple times - * it will be included multiple times in the returned array - * @return {!Array<string>} All the keys of the parameters. - */ -goog.Uri.QueryData.prototype.getKeys = function() { - this.ensureKeyMapInitialized_(); - // We need to get the values to know how many keys to add. - var vals = /** @type {!Array<*>} */ (this.keyMap_.getValues()); - var keys = this.keyMap_.getKeys(); - var rv = []; - for (var i = 0; i < keys.length; i++) { - var val = vals[i]; - for (var j = 0; j < val.length; j++) { - rv.push(keys[i]); - } - } - return rv; -}; - - -/** - * Returns all the values of the parameters with the given name. If the query - * data has no such key this will return an empty array. If no key is given - * all values wil be returned. - * @param {string=} opt_key The name of the parameter to get the values for. - * @return {!Array<?>} All the values of the parameters with the given name. - */ -goog.Uri.QueryData.prototype.getValues = function(opt_key) { - this.ensureKeyMapInitialized_(); - var rv = []; - if (goog.isString(opt_key)) { - if (this.containsKey(opt_key)) { - rv = goog.array.concat(rv, this.keyMap_.get(this.getKeyName_(opt_key))); - } - } else { - // Return all values. - var values = this.keyMap_.getValues(); - for (var i = 0; i < values.length; i++) { - rv = goog.array.concat(rv, values[i]); - } - } - return rv; -}; - - -/** - * Sets a key value pair and removes all other keys with the same value. - * - * @param {string} key Name. - * @param {*} value Value. - * @return {!goog.Uri.QueryData} Instance of this object. - */ -goog.Uri.QueryData.prototype.set = function(key, value) { - this.ensureKeyMapInitialized_(); - this.invalidateCache_(); - - // TODO(chrishenry): This could be better written as - // this.remove(key), this.add(key, value), but that would reorder - // the key (since the key is first removed and then added at the - // end) and we would have to fix unit tests that depend on key - // ordering. - key = this.getKeyName_(key); - if (this.containsKey(key)) { - this.count_ -= this.keyMap_.get(key).length; - } - this.keyMap_.set(key, [value]); - this.count_++; - return this; -}; - - -/** - * Returns the first value associated with the key. If the query data has no - * such key this will return undefined or the optional default. - * @param {string} key The name of the parameter to get the value for. - * @param {*=} opt_default The default value to return if the query data - * has no such key. - * @return {*} The first string value associated with the key, or opt_default - * if there's no value. - */ -goog.Uri.QueryData.prototype.get = function(key, opt_default) { - var values = key ? this.getValues(key) : []; - if (goog.Uri.preserveParameterTypesCompatibilityFlag) { - return values.length > 0 ? values[0] : opt_default; - } else { - return values.length > 0 ? String(values[0]) : opt_default; - } -}; - - -/** - * Sets the values for a key. If the key already exists, this will - * override all of the existing values that correspond to the key. - * @param {string} key The key to set values for. - * @param {!Array<?>} values The values to set. - */ -goog.Uri.QueryData.prototype.setValues = function(key, values) { - this.remove(key); - - if (values.length > 0) { - this.invalidateCache_(); - this.keyMap_.set(this.getKeyName_(key), goog.array.clone(values)); - this.count_ += values.length; - } -}; - - -/** - * @return {string} Encoded query string. - * @override - */ -goog.Uri.QueryData.prototype.toString = function() { - if (this.encodedQuery_) { - return this.encodedQuery_; - } - - if (!this.keyMap_) { - return ''; - } - - var sb = []; - - // In the past, we use this.getKeys() and this.getVals(), but that - // generates a lot of allocations as compared to simply iterating - // over the keys. - var keys = this.keyMap_.getKeys(); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var encodedKey = goog.string.urlEncode(key); - var val = this.getValues(key); - for (var j = 0; j < val.length; j++) { - var param = encodedKey; - // Ensure that null and undefined are encoded into the url as - // literal strings. - if (val[j] !== '') { - param += '=' + goog.string.urlEncode(val[j]); - } - sb.push(param); - } - } - - return this.encodedQuery_ = sb.join('&'); -}; - - -/** - * @throws URIError If URI is malformed (that is, if decodeURIComponent fails on - * any of the URI components). - * @return {string} Decoded query string. - */ -goog.Uri.QueryData.prototype.toDecodedString = function() { - return goog.Uri.decodeOrEmpty_(this.toString()); -}; - - -/** - * Invalidate the cache. - * @private - */ -goog.Uri.QueryData.prototype.invalidateCache_ = function() { - this.encodedQuery_ = null; -}; - - -/** - * Removes all keys that are not in the provided list. (Modifies this object.) - * @param {Array<string>} keys The desired keys. - * @return {!goog.Uri.QueryData} a reference to this object. - */ -goog.Uri.QueryData.prototype.filterKeys = function(keys) { - this.ensureKeyMapInitialized_(); - this.keyMap_.forEach( - function(value, key) { - if (!goog.array.contains(keys, key)) { - this.remove(key); - } - }, this); - return this; -}; - - -/** - * Clone the query data instance. - * @return {!goog.Uri.QueryData} New instance of the QueryData object. - */ -goog.Uri.QueryData.prototype.clone = function() { - var rv = new goog.Uri.QueryData(); - rv.encodedQuery_ = this.encodedQuery_; - if (this.keyMap_) { - rv.keyMap_ = this.keyMap_.clone(); - rv.count_ = this.count_; - } - return rv; -}; - - -/** - * Helper function to get the key name from a JavaScript object. Converts - * the object to a string, and to lower case if necessary. - * @private - * @param {*} arg The object to get a key name from. - * @return {string} valid key name which can be looked up in #keyMap_. - */ -goog.Uri.QueryData.prototype.getKeyName_ = function(arg) { - var keyName = String(arg); - if (this.ignoreCase_) { - keyName = keyName.toLowerCase(); - } - return keyName; -}; - - -/** - * Ignore case in parameter names. - * NOTE: If there are already key/value pairs in the QueryData, and - * ignoreCase_ is set to false, the keys will all be lower-cased. - * @param {boolean} ignoreCase whether this goog.Uri should ignore case. - */ -goog.Uri.QueryData.prototype.setIgnoreCase = function(ignoreCase) { - var resetKeys = ignoreCase && !this.ignoreCase_; - if (resetKeys) { - this.ensureKeyMapInitialized_(); - this.invalidateCache_(); - this.keyMap_.forEach( - function(value, key) { - var lowerCase = key.toLowerCase(); - if (key != lowerCase) { - this.remove(key); - this.setValues(lowerCase, value); - } - }, this); - } - this.ignoreCase_ = ignoreCase; -}; - - -/** - * Extends a query data object with another query data or map like object. This - * operates 'in-place', it does not create a new QueryData object. - * - * @param {...(goog.Uri.QueryData|goog.structs.Map<?, ?>|Object)} var_args - * The object from which key value pairs will be copied. - */ -goog.Uri.QueryData.prototype.extend = function(var_args) { - for (var i = 0; i < arguments.length; i++) { - var data = arguments[i]; - goog.structs.forEach(data, - /** @this {goog.Uri.QueryData} */ - function(value, key) { - this.add(key, value); - }, this); - } -}; - -goog.provide('ol.style.Text'); - - -goog.require('ol.style.Fill'); - - - -/** - * @classdesc - * Set text style for vector features. - * - * @constructor - * @param {olx.style.TextOptions=} opt_options Options. - * @api - */ -ol.style.Text = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {string|undefined} - */ - this.font_ = options.font; - - /** - * @private - * @type {number|undefined} - */ - this.rotation_ = options.rotation; - - /** - * @private - * @type {number|undefined} - */ - this.scale_ = options.scale; - - /** - * @private - * @type {string|undefined} - */ - this.text_ = options.text; - - /** - * @private - * @type {string|undefined} - */ - this.textAlign_ = options.textAlign; - - /** - * @private - * @type {string|undefined} - */ - this.textBaseline_ = options.textBaseline; - - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : - new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_}); - - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; - - /** - * @private - * @type {number} - */ - this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0; - - /** - * @private - * @type {number} - */ - this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0; -}; - - -/** - * The default fill color to use if no fill was set at construction time; a - * blackish `#333`. - * - * @const {string} - * @private - */ -ol.style.Text.DEFAULT_FILL_COLOR_ = '#333'; - - -/** - * Get the font name. - * @return {string|undefined} Font. - * @api - */ -ol.style.Text.prototype.getFont = function() { - return this.font_; -}; - - -/** - * Get the x-offset for the text. - * @return {number} Horizontal text offset. - * @api - */ -ol.style.Text.prototype.getOffsetX = function() { - return this.offsetX_; -}; - - -/** - * Get the y-offset for the text. - * @return {number} Vertical text offset. - * @api - */ -ol.style.Text.prototype.getOffsetY = function() { - return this.offsetY_; -}; - - -/** - * Get the fill style for the text. - * @return {ol.style.Fill} Fill style. - * @api - */ -ol.style.Text.prototype.getFill = function() { - return this.fill_; -}; - - -/** - * Get the text rotation. - * @return {number|undefined} Rotation. - * @api - */ -ol.style.Text.prototype.getRotation = function() { - return this.rotation_; -}; - - -/** - * Get the text scale. - * @return {number|undefined} Scale. - * @api - */ -ol.style.Text.prototype.getScale = function() { - return this.scale_; -}; - - -/** - * Get the stroke style for the text. - * @return {ol.style.Stroke} Stroke style. - * @api - */ -ol.style.Text.prototype.getStroke = function() { - return this.stroke_; -}; - - -/** - * Get the text to be rendered. - * @return {string|undefined} Text. - * @api - */ -ol.style.Text.prototype.getText = function() { - return this.text_; -}; - - -/** - * Get the text alignment. - * @return {string|undefined} Text align. - * @api - */ -ol.style.Text.prototype.getTextAlign = function() { - return this.textAlign_; -}; - - -/** - * Get the text baseline. - * @return {string|undefined} Text baseline. - * @api - */ -ol.style.Text.prototype.getTextBaseline = function() { - return this.textBaseline_; -}; - - -/** - * Set the font. - * - * @param {string|undefined} font Font. - * @api - */ -ol.style.Text.prototype.setFont = function(font) { - this.font_ = font; -}; - - -/** - * Set the x offset. - * - * @param {number} offsetX Horizontal text offset. - * @api - */ -ol.style.Text.prototype.setOffsetX = function(offsetX) { - this.offsetX_ = offsetX; -}; - - -/** - * Set the y offset. - * - * @param {number} offsetY Vertical text offset. - * @api - */ -ol.style.Text.prototype.setOffsetY = function(offsetY) { - this.offsetY_ = offsetY; -}; - - -/** - * Set the fill. - * - * @param {ol.style.Fill} fill Fill style. - * @api - */ -ol.style.Text.prototype.setFill = function(fill) { - this.fill_ = fill; -}; - - -/** - * Set the rotation. - * - * @param {number|undefined} rotation Rotation. - * @api - */ -ol.style.Text.prototype.setRotation = function(rotation) { - this.rotation_ = rotation; -}; - - -/** - * Set the scale. - * - * @param {number|undefined} scale Scale. - * @api - */ -ol.style.Text.prototype.setScale = function(scale) { - this.scale_ = scale; -}; - - -/** - * Set the stroke. - * - * @param {ol.style.Stroke} stroke Stroke style. - * @api - */ -ol.style.Text.prototype.setStroke = function(stroke) { - this.stroke_ = stroke; -}; - - -/** - * Set the text. - * - * @param {string|undefined} text Text. - * @api - */ -ol.style.Text.prototype.setText = function(text) { - this.text_ = text; -}; - - -/** - * Set the text alignment. - * - * @param {string|undefined} textAlign Text align. - * @api - */ -ol.style.Text.prototype.setTextAlign = function(textAlign) { - this.textAlign_ = textAlign; -}; - - -/** - * Set the text baseline. - * - * @param {string|undefined} textBaseline Text baseline. - * @api - */ -ol.style.Text.prototype.setTextBaseline = function(textBaseline) { - this.textBaseline_ = textBaseline; -}; - -// FIXME http://earth.google.com/kml/1.0 namespace? -// FIXME why does node.getAttribute return an unknown type? -// FIXME text -// FIXME serialize arbitrary feature properties -// FIXME don't parse style if extractStyles is false - -goog.provide('ol.format.KML'); - -goog.require('goog.Uri'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Feature'); -goog.require('ol.FeatureStyleFunction'); -goog.require('ol.array'); -goog.require('ol.color'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Icon'); -goog.require('ol.style.IconAnchorUnits'); -goog.require('ol.style.IconOrigin'); -goog.require('ol.style.Image'); -goog.require('ol.style.Stroke'); -goog.require('ol.style.Style'); -goog.require('ol.style.Text'); -goog.require('ol.xml'); - - -/** - * @typedef {{x: number, xunits: (ol.style.IconAnchorUnits|undefined), - * y: number, yunits: (ol.style.IconAnchorUnits|undefined)}} - */ -ol.format.KMLVec2_; - - -/** - * @typedef {{flatCoordinates: Array.<number>, - * whens: Array.<number>}} - */ -ol.format.KMLGxTrackObject_; - - - -/** - * @classdesc - * Feature format for reading and writing data in the KML format. - * - * @constructor - * @extends {ol.format.XMLFeature} - * @param {olx.format.KMLOptions=} opt_options Options. - * @api stable - */ -ol.format.KML = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); - - /** - * @private - * @type {Array.<ol.style.Style>} - */ - this.defaultStyle_ = options.defaultStyle ? - options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_; - - /** - * @private - * @type {boolean} - */ - this.extractStyles_ = options.extractStyles !== undefined ? - options.extractStyles : true; - - /** - * @private - * @type {boolean} - */ - this.writeStyles_ = options.writeStyles !== undefined ? - options.writeStyles : true; - - /** - * @private - * @type {Object.<string, (Array.<ol.style.Style>|string)>} - */ - this.sharedStyles_ = {}; - - /** - * @private - * @type {boolean} - */ - this.showPointNames_ = options.showPointNames !== undefined ? - options.showPointNames : true; - -}; -goog.inherits(ol.format.KML, ol.format.XMLFeature); - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.KML.EXTENSIONS_ = ['.kml']; - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.KML.GX_NAMESPACE_URIS_ = [ - 'http://www.google.com/kml/ext/2.2' -]; - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.KML.NAMESPACE_URIS_ = [ - null, - 'http://earth.google.com/kml/2.0', - 'http://earth.google.com/kml/2.1', - 'http://earth.google.com/kml/2.2', - 'http://www.opengis.net/kml/2.2' -]; - - -/** - * @const - * @type {string} - * @private - */ -ol.format.KML.SCHEMA_LOCATION_ = 'http://www.opengis.net/kml/2.2 ' + - 'https://developers.google.com/kml/schema/kml22gx.xsd'; - - -/** - * @const - * @type {ol.Color} - * @private - */ -ol.format.KML.DEFAULT_COLOR_ = [255, 255, 255, 1]; - - -/** - * @const - * @type {ol.style.Fill} - * @private - */ -ol.format.KML.DEFAULT_FILL_STYLE_ = new ol.style.Fill({ - color: ol.format.KML.DEFAULT_COLOR_ -}); - - -/** - * @const - * @type {ol.Size} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_ = [20, 2]; // FIXME maybe [8, 32] ? - - -/** - * @const - * @type {ol.style.IconAnchorUnits} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ = - ol.style.IconAnchorUnits.PIXELS; - - -/** - * @const - * @type {ol.style.IconAnchorUnits} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ = - ol.style.IconAnchorUnits.PIXELS; - - -/** - * @const - * @type {ol.Size} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_ = [64, 64]; - - -/** - * @const - * @type {string} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ = - 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png'; - - -/** - * @const - * @type {number} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_ = 0.5; - - -/** - * @const - * @type {ol.style.Image} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({ - anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_, - anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, - anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_, - anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_, - crossOrigin: 'anonymous', - rotation: 0, - scale: ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_, - size: ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_, - src: ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ -}); - - -/** - * @const - * @type {ol.style.Stroke} - * @private - */ -ol.format.KML.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({ - color: ol.format.KML.DEFAULT_COLOR_, - width: 1 -}); - - -/** - * @const - * @type {ol.style.Stroke} - * @private - */ -ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_ = new ol.style.Stroke({ - color: [51, 51, 51, 1], - width: 2 -}); - - -/** - * @const - * @type {ol.style.Text} - * @private - */ -ol.format.KML.DEFAULT_TEXT_STYLE_ = new ol.style.Text({ - font: 'bold 16px Helvetica', - fill: ol.format.KML.DEFAULT_FILL_STYLE_, - stroke: ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_, - scale: 0.8 -}); - - -/** - * @const - * @type {ol.style.Style} - * @private - */ -ol.format.KML.DEFAULT_STYLE_ = new ol.style.Style({ - fill: ol.format.KML.DEFAULT_FILL_STYLE_, - image: ol.format.KML.DEFAULT_IMAGE_STYLE_, - text: ol.format.KML.DEFAULT_TEXT_STYLE_, - stroke: ol.format.KML.DEFAULT_STROKE_STYLE_, - zIndex: 0 -}); - - -/** - * @const - * @type {Array.<ol.style.Style>} - * @private - */ -ol.format.KML.DEFAULT_STYLE_ARRAY_ = [ol.format.KML.DEFAULT_STYLE_]; - - -/** - * @const - * @type {Object.<string, ol.style.IconAnchorUnits>} - * @private - */ -ol.format.KML.ICON_ANCHOR_UNITS_MAP_ = { - 'fraction': ol.style.IconAnchorUnits.FRACTION, - 'pixels': ol.style.IconAnchorUnits.PIXELS -}; - - -/** - * @param {ol.style.Style|undefined} foundStyle Style. - * @param {string} name Name. - * @return {ol.style.Style} style Style. - * @private - */ -ol.format.KML.createNameStyleFunction_ = function(foundStyle, name) { - /** @type {?ol.style.Text} */ - var textStyle = null; - var textOffset = [0, 0]; - var textAlign = 'start'; - if (foundStyle.getImage()) { - var imageSize = foundStyle.getImage().getImageSize(); - if (imageSize && imageSize.length == 2) { - // Offset the label to be centered to the right of the icon, if there is - // one. - textOffset[0] = foundStyle.getImage().getScale() * imageSize[0] / 2; - textOffset[1] = -foundStyle.getImage().getScale() * imageSize[1] / 2; - textAlign = 'left'; - } - } - if (!goog.object.isEmpty(foundStyle.getText())) { - textStyle = /** @type {ol.style.Text} */ - (goog.object.clone(foundStyle.getText())); - textStyle.setText(name); - textStyle.setTextAlign(textAlign); - textStyle.setOffsetX(textOffset[0]); - textStyle.setOffsetY(textOffset[1]); - } else { - textStyle = new ol.style.Text({ - text: name, - offsetX: textOffset[0], - offsetY: textOffset[1], - textAlign: textAlign - }); - } - var nameStyle = new ol.style.Style({ - text: textStyle - }); - return nameStyle; -}; - - -/** - * @param {Array.<ol.style.Style>|undefined} style Style. - * @param {string} styleUrl Style URL. - * @param {Array.<ol.style.Style>} defaultStyle Default style. - * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles Shared - * styles. - * @param {boolean|undefined} showPointNames true to show names for point - * placemarks. - * @return {ol.FeatureStyleFunction} Feature style function. - * @private - */ -ol.format.KML.createFeatureStyleFunction_ = function(style, styleUrl, - defaultStyle, sharedStyles, showPointNames) { - - return ( - /** - * @param {number} resolution Resolution. - * @return {Array.<ol.style.Style>} Style. - * @this {ol.Feature} - */ - function(resolution) { - var drawName = showPointNames; - /** @type {ol.style.Style|undefined} */ - var nameStyle; - /** @type {string} */ - var name = ''; - if (drawName) { - if (this.getGeometry()) { - drawName = (this.getGeometry().getType() === - ol.geom.GeometryType.POINT); - } - } - - if (drawName) { - name = /** @type {string} */ (this.getProperties()['name']); - drawName = drawName && name; - } - - if (style) { - if (drawName) { - nameStyle = ol.format.KML.createNameStyleFunction_(style[0], - name); - return style.concat(nameStyle); - } - return style; - } - if (styleUrl) { - var foundStyle = ol.format.KML.findStyle_(styleUrl, defaultStyle, - sharedStyles); - if (drawName) { - nameStyle = ol.format.KML.createNameStyleFunction_(foundStyle[0], - name); - return foundStyle.concat(nameStyle); - } - return foundStyle; - } - if (drawName) { - nameStyle = ol.format.KML.createNameStyleFunction_(defaultStyle[0], - name); - return defaultStyle.concat(nameStyle); - } - return defaultStyle; - }); -}; - - -/** - * @param {Array.<ol.style.Style>|string|undefined} styleValue Style value. - * @param {Array.<ol.style.Style>} defaultStyle Default style. - * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles - * Shared styles. - * @return {Array.<ol.style.Style>} Style. - * @private - */ -ol.format.KML.findStyle_ = function(styleValue, defaultStyle, sharedStyles) { - if (goog.isArray(styleValue)) { - return styleValue; - } else if (goog.isString(styleValue)) { - // KML files in the wild occasionally forget the leading `#` on styleUrls - // defined in the same document. Add a leading `#` if it enables to find - // a style. - if (!(styleValue in sharedStyles) && ('#' + styleValue in sharedStyles)) { - styleValue = '#' + styleValue; - } - return ol.format.KML.findStyle_( - sharedStyles[styleValue], defaultStyle, sharedStyles); - } else { - return defaultStyle; - } -}; - - -/** - * @param {Node} node Node. - * @private - * @return {ol.Color|undefined} Color. - */ -ol.format.KML.readColor_ = function(node) { - var s = ol.xml.getAllTextContent(node, false); - // The KML specification states that colors should not include a leading `#` - // but we tolerate them. - var m = /^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(s); - if (m) { - var hexColor = m[1]; - return [ - parseInt(hexColor.substr(6, 2), 16), - parseInt(hexColor.substr(4, 2), 16), - parseInt(hexColor.substr(2, 2), 16), - parseInt(hexColor.substr(0, 2), 16) / 255 - ]; - - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @private - * @return {Array.<number>|undefined} Flat coordinates. - */ -ol.format.KML.readFlatCoordinates_ = function(node) { - var s = ol.xml.getAllTextContent(node, false); - var flatCoordinates = []; - // The KML specification states that coordinate tuples should not include - // spaces, but we tolerate them. - var re = - /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i; - var m; - while ((m = re.exec(s))) { - var x = parseFloat(m[1]); - var y = parseFloat(m[2]); - var z = m[3] ? parseFloat(m[3]) : 0; - flatCoordinates.push(x, y, z); - s = s.substr(m[0].length); - } - if (s !== '') { - return undefined; - } - return flatCoordinates; -}; - - -/** - * @param {Node} node Node. - * @private - * @return {string|undefined} Style URL. - */ -ol.format.KML.readStyleUrl_ = function(node) { - var s = ol.xml.getAllTextContent(node, false).trim(); - if (node.baseURI) { - return goog.Uri.resolve(node.baseURI, s).toString(); - } else { - return s; - } - -}; - - -/** - * @param {Node} node Node. - * @private - * @return {string} URI. - */ -ol.format.KML.readURI_ = function(node) { - var s = ol.xml.getAllTextContent(node, false); - if (node.baseURI) { - return goog.Uri.resolve(node.baseURI, s.trim()).toString(); - } else { - return s.trim(); - } -}; - - -/** - * @param {Node} node Node. - * @private - * @return {ol.format.KMLVec2_} Vec2. - */ -ol.format.KML.readVec2_ = function(node) { - var xunits = node.getAttribute('xunits'); - var yunits = node.getAttribute('yunits'); - return { - x: parseFloat(node.getAttribute('x')), - xunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[xunits], - y: parseFloat(node.getAttribute('y')), - yunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[yunits] - }; -}; - - -/** - * @param {Node} node Node. - * @private - * @return {number|undefined} Scale. - */ -ol.format.KML.readScale_ = function(node) { - var number = ol.format.XSD.readDecimal(node); - if (number !== undefined) { - return Math.sqrt(number); - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<ol.style.Style>|string|undefined} StyleMap. - */ -ol.format.KML.readStyleMapValue_ = function(node, objectStack) { - return ol.xml.pushParseAndPop( - /** @type {Array.<ol.style.Style>|string|undefined} */ (undefined), - ol.format.KML.STYLE_MAP_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.IconStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be an ELEMENT'); - goog.asserts.assert(node.localName == 'IconStyle', - 'localName should be IconStyle'); - // FIXME refreshMode - // FIXME refreshInterval - // FIXME viewRefreshTime - // FIXME viewBoundScale - // FIXME viewFormat - // FIXME httpQuery - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.ICON_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = /** @type {Object} */ (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var IconObject = 'Icon' in object ? object['Icon'] : {}; - var src; - var href = /** @type {string|undefined} */ - (IconObject['href']); - if (href) { - src = href; - } else { - src = ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_; - } - var anchor, anchorXUnits, anchorYUnits; - var hotSpot = /** @type {ol.format.KMLVec2_|undefined} */ - (object['hotSpot']); - if (hotSpot) { - anchor = [hotSpot.x, hotSpot.y]; - anchorXUnits = hotSpot.xunits; - anchorYUnits = hotSpot.yunits; - } else if (src === ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) { - anchor = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_; - anchorXUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_; - anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_; - } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) { - anchor = [0.5, 0]; - anchorXUnits = ol.style.IconAnchorUnits.FRACTION; - anchorYUnits = ol.style.IconAnchorUnits.FRACTION; - } - - var offset; - var x = /** @type {number|undefined} */ - (IconObject['x']); - var y = /** @type {number|undefined} */ - (IconObject['y']); - if (x !== undefined && y !== undefined) { - offset = [x, y]; - } - - var size; - var w = /** @type {number|undefined} */ - (IconObject['w']); - var h = /** @type {number|undefined} */ - (IconObject['h']); - if (w !== undefined && h !== undefined) { - size = [w, h]; - } - - var rotation; - var heading = /** @type {number} */ - (object['heading']); - if (heading !== undefined) { - rotation = ol.math.toRadians(heading); - } - - var scale = /** @type {number|undefined} */ - (object['scale']); - if (src == ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) { - size = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_; - if (scale === undefined) { - scale = ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_; - } - } - - var imageStyle = new ol.style.Icon({ - anchor: anchor, - anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, - anchorXUnits: anchorXUnits, - anchorYUnits: anchorYUnits, - crossOrigin: 'anonymous', // FIXME should this be configurable? - offset: offset, - offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT, - rotation: rotation, - scale: scale, - size: size, - src: src - }); - styleObject['imageStyle'] = imageStyle; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.LabelStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LabelStyle', - 'localName should be LabelStyle'); - // FIXME colorMode - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.LABEL_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var textStyle = new ol.style.Text({ - fill: new ol.style.Fill({ - color: /** @type {ol.Color} */ - ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_) - }), - scale: /** @type {number|undefined} */ - (object['scale']) - }); - styleObject['textStyle'] = textStyle; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.LineStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineStyle', - 'localName should be LineStyle'); - // FIXME colorMode - // FIXME gx:outerColor - // FIXME gx:outerWidth - // FIXME gx:physicalWidth - // FIXME gx:labelVisibility - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.LINE_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var strokeStyle = new ol.style.Stroke({ - color: /** @type {ol.Color} */ - ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_), - width: /** @type {number} */ ('width' in object ? object['width'] : 1) - }); - styleObject['strokeStyle'] = strokeStyle; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.PolyStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'PolyStyle', - 'localName should be PolyStyle'); - // FIXME colorMode - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.POLY_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var fillStyle = new ol.style.Fill({ - color: /** @type {ol.Color} */ - ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_) - }); - styleObject['fillStyle'] = fillStyle; - var fill = /** @type {boolean|undefined} */ (object['fill']); - if (fill !== undefined) { - styleObject['fill'] = fill; - } - var outline = - /** @type {boolean|undefined} */ (object['outline']); - if (outline !== undefined) { - styleObject['outline'] = outline; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>} LinearRing flat coordinates. - */ -ol.format.KML.readFlatLinearRing_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop( - null, ol.format.KML.FLAT_LINEAR_RING_PARSERS_, node, objectStack)); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.gxCoordParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(ol.array.includes( - ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), - 'namespaceURI of the node should be known to the KML parser'); - goog.asserts.assert(node.localName == 'coord', 'localName should be coord'); - var gxTrackObject = /** @type {ol.format.KMLGxTrackObject_} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(gxTrackObject), - 'gxTrackObject should be an Object'); - var flatCoordinates = gxTrackObject.flatCoordinates; - var s = ol.xml.getAllTextContent(node, false); - var re = - /^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i; - var m = re.exec(s); - if (m) { - var x = parseFloat(m[1]); - var y = parseFloat(m[2]); - var z = parseFloat(m[3]); - flatCoordinates.push(x, y, z, 0); - } else { - flatCoordinates.push(0, 0, 0, 0); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.MultiLineString|undefined} MultiLineString. - */ -ol.format.KML.readGxMultiTrack_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(ol.array.includes( - ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), - 'namespaceURI of the node should be known to the KML parser'); - goog.asserts.assert(node.localName == 'MultiTrack', - 'localName should be MultiTrack'); - var lineStrings = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.LineString>} */ ([]), - ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_, node, objectStack); - if (!lineStrings) { - return undefined; - } - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(lineStrings); - return multiLineString; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.LineString|undefined} LineString. - */ -ol.format.KML.readGxTrack_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(ol.array.includes( - ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), - 'namespaceURI of the node should be known to the KML parser'); - goog.asserts.assert(node.localName == 'Track', 'localName should be Track'); - var gxTrackObject = ol.xml.pushParseAndPop( - /** @type {ol.format.KMLGxTrackObject_} */ ({ - flatCoordinates: [], - whens: [] - }), ol.format.KML.GX_TRACK_PARSERS_, node, objectStack); - if (!gxTrackObject) { - return undefined; - } - var flatCoordinates = gxTrackObject.flatCoordinates; - var whens = gxTrackObject.whens; - goog.asserts.assert(flatCoordinates.length / 4 == whens.length, - 'the length of the flatCoordinates array divided by 4 should be the ' + - 'length of the whens array'); - var i, ii; - for (i = 0, ii = Math.min(flatCoordinates.length, whens.length); i < ii; - ++i) { - flatCoordinates[4 * i + 3] = whens[i]; - } - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); - return lineString; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object} Icon object. - */ -ol.format.KML.readIcon_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Icon', 'localName should be Icon'); - var iconObject = ol.xml.pushParseAndPop( - {}, ol.format.KML.ICON_PARSERS_, node, objectStack); - if (iconObject) { - return iconObject; - } else { - return null; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>} Flat coordinates. - */ -ol.format.KML.readFlatCoordinatesFromNode_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop(null, - ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack)); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.LineString|undefined} LineString. - */ -ol.format.KML.readLineString_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineString', - 'localName should be LineString'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatCoordinates = - ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - lineString.setProperties(properties); - return lineString; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Polygon|undefined} Polygon. - */ -ol.format.KML.readLinearRing_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatCoordinates = - ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates, - [flatCoordinates.length]); - polygon.setProperties(properties); - return polygon; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.KML.readMultiGeometry_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiGeometry', - 'localName should be MultiGeometry'); - var geometries = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.Geometry>} */ ([]), - ol.format.KML.MULTI_GEOMETRY_PARSERS_, node, objectStack); - if (!geometries) { - return null; - } - if (geometries.length === 0) { - return new ol.geom.GeometryCollection(geometries); - } - var homogeneous = true; - var type = geometries[0].getType(); - var geometry, i, ii; - for (i = 1, ii = geometries.length; i < ii; ++i) { - geometry = geometries[i]; - if (geometry.getType() != type) { - homogeneous = false; - break; - } - } - if (homogeneous) { - /** @type {ol.geom.GeometryLayout} */ - var layout; - /** @type {Array.<number>} */ - var flatCoordinates; - if (type == ol.geom.GeometryType.POINT) { - var point = geometries[0]; - goog.asserts.assertInstanceof(point, ol.geom.Point, - 'point should be an ol.geom.Point'); - layout = point.getLayout(); - flatCoordinates = point.getFlatCoordinates(); - for (i = 1, ii = geometries.length; i < ii; ++i) { - geometry = geometries[i]; - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - goog.asserts.assert(geometry.getLayout() == layout, - 'geometry layout should be consistent'); - goog.array.extend(flatCoordinates, geometry.getFlatCoordinates()); - } - var multiPoint = new ol.geom.MultiPoint(null); - multiPoint.setFlatCoordinates(layout, flatCoordinates); - ol.format.KML.setCommonGeometryProperties_(multiPoint, geometries); - return multiPoint; - } else if (type == ol.geom.GeometryType.LINE_STRING) { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(geometries); - ol.format.KML.setCommonGeometryProperties_(multiLineString, geometries); - return multiLineString; - } else if (type == ol.geom.GeometryType.POLYGON) { - var multiPolygon = new ol.geom.MultiPolygon(null); - multiPolygon.setPolygons(geometries); - ol.format.KML.setCommonGeometryProperties_(multiPolygon, geometries); - return multiPolygon; - } else if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) { - return new ol.geom.GeometryCollection(geometries); - } else { - goog.asserts.fail('Unexpected type: ' + type); - return null; - } - } else { - return new ol.geom.GeometryCollection(geometries); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Point|undefined} Point. - */ -ol.format.KML.readPoint_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Point', 'localName should be Point'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatCoordinates = - ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var point = new ol.geom.Point(null); - goog.asserts.assert(flatCoordinates.length == 3, - 'flatCoordinates should have a length of 3'); - point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - point.setProperties(properties); - return point; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Polygon|undefined} Polygon. - */ -ol.format.KML.readPolygon_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Polygon', - 'localName should be Polygon'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatLinearRings = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack); - if (flatLinearRings && flatLinearRings[0]) { - var polygon = new ol.geom.Polygon(null); - var flatCoordinates = flatLinearRings[0]; - var ends = [flatCoordinates.length]; - var i, ii; - for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); - ends.push(flatCoordinates.length); - } - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); - polygon.setProperties(properties); - return polygon; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<ol.style.Style>} Style. - */ -ol.format.KML.readStyle_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); - var styleObject = ol.xml.pushParseAndPop( - {}, ol.format.KML.STYLE_PARSERS_, node, objectStack); - if (!styleObject) { - return null; - } - var fillStyle = /** @type {ol.style.Fill} */ - ('fillStyle' in styleObject ? - styleObject['fillStyle'] : ol.format.KML.DEFAULT_FILL_STYLE_); - var fill = /** @type {boolean|undefined} */ (styleObject['fill']); - if (fill !== undefined && !fill) { - fillStyle = null; - } - var imageStyle = /** @type {ol.style.Image} */ - ('imageStyle' in styleObject ? - styleObject['imageStyle'] : ol.format.KML.DEFAULT_IMAGE_STYLE_); - var textStyle = /** @type {ol.style.Text} */ - ('textStyle' in styleObject ? - styleObject['textStyle'] : ol.format.KML.DEFAULT_TEXT_STYLE_); - var strokeStyle = /** @type {ol.style.Stroke} */ - ('strokeStyle' in styleObject ? - styleObject['strokeStyle'] : ol.format.KML.DEFAULT_STROKE_STYLE_); - var outline = /** @type {boolean|undefined} */ - (styleObject['outline']); - if (outline !== undefined && !outline) { - strokeStyle = null; - } - return [new ol.style.Style({ - fill: fillStyle, - image: imageStyle, - stroke: strokeStyle, - text: textStyle, - zIndex: undefined // FIXME - })]; -}; - - -/** - * Reads an array of geometries and creates arrays for common geometry - * properties. Then sets them to the multi geometry. - * @param {ol.geom.MultiPoint|ol.geom.MultiLineString|ol.geom.MultiPolygon} - * multiGeometry - * @param {Array.<ol.geom.Geometry>} geometries - * @private - */ -ol.format.KML.setCommonGeometryProperties_ = function(multiGeometry, - geometries) { - var ii = geometries.length; - var extrudes = new Array(geometries.length); - var altitudeModes = new Array(geometries.length); - var geometry, i, hasExtrude, hasAltitudeMode; - hasExtrude = hasAltitudeMode = false; - for (i = 0; i < ii; ++i) { - geometry = geometries[i]; - extrudes[i] = geometry.get('extrude'); - altitudeModes[i] = geometry.get('altitudeMode'); - hasExtrude = hasExtrude || extrudes[i] !== undefined; - hasAltitudeMode = hasAltitudeMode || altitudeModes[i]; - } - if (hasExtrude) { - multiGeometry.set('extrude', extrudes); - } - if (hasAltitudeMode) { - multiGeometry.set('altitudeMode', altitudeModes); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.DataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Data', 'localName should be Data'); - var name = node.getAttribute('name'); - if (name !== null) { - var data = ol.xml.pushParseAndPop( - undefined, ol.format.KML.DATA_PARSERS_, node, objectStack); - if (data) { - var featureObject = - /** @type {Object} */ (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(featureObject), - 'featureObject should be an Object'); - featureObject[name] = data; - } - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.ExtendedDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ExtendedData', - 'localName should be ExtendedData'); - ol.xml.parseNode(ol.format.KML.EXTENDED_DATA_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.PairDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Pair', 'localName should be Pair'); - var pairObject = ol.xml.pushParseAndPop( - {}, ol.format.KML.PAIR_PARSERS_, node, objectStack); - if (!pairObject) { - return; - } - var key = /** @type {string|undefined} */ - (pairObject['key']); - if (key && key == 'normal') { - var styleUrl = /** @type {string|undefined} */ - (pairObject['styleUrl']); - if (styleUrl) { - objectStack[objectStack.length - 1] = styleUrl; - } - var Style = /** @type {ol.style.Style} */ - (pairObject['Style']); - if (Style) { - objectStack[objectStack.length - 1] = Style; - } - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.PlacemarkStyleMapParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'StyleMap', - 'localName should be StyleMap'); - var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack); - if (!styleMapValue) { - return; - } - var placemarkObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(placemarkObject), - 'placemarkObject should be an Object'); - if (goog.isArray(styleMapValue)) { - placemarkObject['Style'] = styleMapValue; - } else if (goog.isString(styleMapValue)) { - placemarkObject['styleUrl'] = styleMapValue; - } else { - goog.asserts.fail('styleMapValue has an unknown type'); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.SchemaDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'SchemaData', - 'localName should be SchemaData'); - ol.xml.parseNode(ol.format.KML.SCHEMA_DATA_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.SimpleDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'SimpleData', - 'localName should be SimpleData'); - var name = node.getAttribute('name'); - if (name !== null) { - var data = ol.format.XSD.readString(node); - var featureObject = - /** @type {Object} */ (objectStack[objectStack.length - 1]); - featureObject[name] = data; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.innerBoundaryIsParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'innerBoundaryIs', - 'localName should be innerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - ol.format.KML.INNER_BOUNDARY_IS_PARSERS_, node, objectStack); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings array should not be empty'); - flatLinearRings.push(flatLinearRing); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.outerBoundaryIsParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'outerBoundaryIs', - 'localName should be outerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_, node, objectStack); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings array should not be empty'); - flatLinearRings[0] = flatLinearRing; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.LinkParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Link', 'localName should be Link'); - ol.xml.parseNode(ol.format.KML.LINK_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.whenParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'when', 'localName should be when'); - var gxTrackObject = /** @type {ol.format.KMLGxTrackObject_} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(gxTrackObject), - 'gxTrackObject should be an Object'); - var whens = gxTrackObject.whens; - var s = ol.xml.getAllTextContent(node, false); - var re = - /^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/; - var m = re.exec(s); - if (m) { - var year = parseInt(m[1], 10); - var month = m[3] ? parseInt(m[3], 10) - 1 : 0; - var day = m[5] ? parseInt(m[5], 10) : 1; - var hour = m[7] ? parseInt(m[7], 10) : 0; - var minute = m[8] ? parseInt(m[8], 10) : 0; - var second = m[9] ? parseInt(m[9], 10) : 0; - var when = Date.UTC(year, month, day, hour, minute, second); - if (m[10] && m[10] != 'Z') { - var sign = m[11] == '-' ? -1 : 1; - when += sign * 60 * parseInt(m[12], 10); - if (m[13]) { - when += sign * 60 * 60 * parseInt(m[13], 10); - } - } - whens.push(when); - } else { - whens.push(0); - } -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.DATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'value': ol.xml.makeReplacer(ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.EXTENDED_DATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Data': ol.format.KML.DataParser_, - 'SchemaData': ol.format.KML.SchemaDataParser_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'extrude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.FLAT_LINEAR_RING_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'innerBoundaryIs': ol.format.KML.innerBoundaryIsParser_, - 'outerBoundaryIs': ol.format.KML.outerBoundaryIsParser_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.GX_TRACK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'when': ol.format.KML.whenParser_ - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'coord': ol.format.KML.gxCoordParser_ - })); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.ICON_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_) - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'x': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'y': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'w': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'h': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal) - })); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.ICON_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Icon': ol.xml.makeObjectPropertySetter(ol.format.KML.readIcon_), - 'heading': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'hotSpot': ol.xml.makeObjectPropertySetter(ol.format.KML.readVec2_), - 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.INNER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.LABEL_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), - 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.LINE_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), - 'width': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.MULTI_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LineString': ol.xml.makeArrayPusher(ol.format.KML.readLineString_), - 'LinearRing': ol.xml.makeArrayPusher(ol.format.KML.readLinearRing_), - 'MultiGeometry': ol.xml.makeArrayPusher(ol.format.KML.readMultiGeometry_), - 'Point': ol.xml.makeArrayPusher(ol.format.KML.readPoint_), - 'Polygon': ol.xml.makeArrayPusher(ol.format.KML.readPolygon_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'Track': ol.xml.makeArrayPusher(ol.format.KML.readGxTrack_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.NETWORK_LINK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'ExtendedData': ol.format.KML.ExtendedDataParser_, - 'Link': ol.format.KML.LinkParser_, - 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.LINK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.PAIR_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_), - 'key': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyleUrl_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.PLACEMARK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'ExtendedData': ol.format.KML.ExtendedDataParser_, - 'MultiGeometry': ol.xml.makeObjectPropertySetter( - ol.format.KML.readMultiGeometry_, 'geometry'), - 'LineString': ol.xml.makeObjectPropertySetter( - ol.format.KML.readLineString_, 'geometry'), - 'LinearRing': ol.xml.makeObjectPropertySetter( - ol.format.KML.readLinearRing_, 'geometry'), - 'Point': ol.xml.makeObjectPropertySetter( - ol.format.KML.readPoint_, 'geometry'), - 'Polygon': ol.xml.makeObjectPropertySetter( - ol.format.KML.readPolygon_, 'geometry'), - 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_), - 'StyleMap': ol.format.KML.PlacemarkStyleMapParser_, - 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_), - 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'MultiTrack': ol.xml.makeObjectPropertySetter( - ol.format.KML.readGxMultiTrack_, 'geometry'), - 'Track': ol.xml.makeObjectPropertySetter( - ol.format.KML.readGxTrack_, 'geometry') - } - )); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.POLY_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), - 'fill': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'outline': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.SCHEMA_DATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'SimpleData': ol.format.KML.SimpleDataParser_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'IconStyle': ol.format.KML.IconStyleParser_, - 'LabelStyle': ol.format.KML.LabelStyleParser_, - 'LineStyle': ol.format.KML.LineStyleParser_, - 'PolyStyle': ol.format.KML.PolyStyleParser_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.STYLE_MAP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Pair': ol.format.KML.PairDataParser_ - }); - - -/** - * @inheritDoc - */ -ol.format.KML.prototype.getExtensions = function() { - return ol.format.KML.EXTENSIONS_; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<ol.Feature>|undefined} Features. - */ -ol.format.KML.prototype.readDocumentOrFolder_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var localName = ol.xml.getLocalName(node); - goog.asserts.assert(localName == 'Document' || localName == 'Folder', - 'localName should be Document or Folder'); - // FIXME use scope somehow - var parsersNS = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Document': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this), - 'Folder': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this), - 'Placemark': ol.xml.makeArrayPusher(this.readPlacemark_, this), - 'Style': goog.bind(this.readSharedStyle_, this), - 'StyleMap': goog.bind(this.readSharedStyleMap_, this) - }); - var features = ol.xml.pushParseAndPop(/** @type {Array.<ol.Feature>} */ ([]), - parsersNS, node, objectStack, this); - if (features) { - return features; - } else { - return undefined; - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Feature. - */ -ol.format.KML.prototype.readPlacemark_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Placemark', - 'localName should be Placemark'); - var object = ol.xml.pushParseAndPop({'geometry': null}, - ol.format.KML.PLACEMARK_PARSERS_, node, objectStack); - if (!object) { - return undefined; - } - var feature = new ol.Feature(); - var id = node.getAttribute('id'); - if (id !== null) { - feature.setId(id); - } - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - - var geometry = object['geometry']; - if (geometry) { - ol.format.Feature.transformWithOptions(geometry, false, options); - } - feature.setGeometry(geometry); - delete object['geometry']; - - if (this.extractStyles_) { - var style = object['Style']; - var styleUrl = object['styleUrl']; - var styleFunction = ol.format.KML.createFeatureStyleFunction_( - style, styleUrl, this.defaultStyle_, this.sharedStyles_, - this.showPointNames_); - feature.setStyle(styleFunction); - } - delete object['Style']; - // we do not remove the styleUrl property from the object, so it - // gets stored on feature when setProperties is called - - feature.setProperties(object); - - return feature; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); - var id = node.getAttribute('id'); - if (id !== null) { - var style = ol.format.KML.readStyle_(node, objectStack); - if (style) { - var styleUri; - if (node.baseURI) { - styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString(); - } else { - styleUri = '#' + id; - } - this.sharedStyles_[styleUri] = style; - } - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'StyleMap', - 'localName should be StyleMap'); - var id = node.getAttribute('id'); - if (id === null) { - return; - } - var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack); - if (!styleMapValue) { - return; - } - var styleUri; - if (node.baseURI) { - styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString(); - } else { - styleUri = '#' + id; - } - this.sharedStyles_[styleUri] = styleMapValue; -}; - - -/** - * Read the first feature from a KML source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.KML.prototype.readFeature; - - -/** - * @inheritDoc - */ -ol.format.KML.prototype.readFeatureFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) { - return null; - } - goog.asserts.assert(node.localName == 'Placemark', - 'localName should be Placemark'); - var feature = this.readPlacemark_( - node, [this.getReadOptions(node, opt_options)]); - if (feature) { - return feature; - } else { - return null; - } -}; - - -/** - * Read all features from a KML source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.KML.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) { - return []; - } - var features; - var localName = ol.xml.getLocalName(node); - if (localName == 'Document' || localName == 'Folder') { - features = this.readDocumentOrFolder_( - node, [this.getReadOptions(node, opt_options)]); - if (features) { - return features; - } else { - return []; - } - } else if (localName == 'Placemark') { - var feature = this.readPlacemark_( - node, [this.getReadOptions(node, opt_options)]); - if (feature) { - return [feature]; - } else { - return []; - } - } else if (localName == 'kml') { - features = []; - var n; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var fs = this.readFeaturesFromNode(n, opt_options); - if (fs) { - goog.array.extend(features, fs); - } - } - return features; - } else { - return []; - } -}; - - -/** - * Read the name of the KML. - * - * @param {Document|Node|string} source Souce. - * @return {string|undefined} Name. - * @api stable - */ -ol.format.KML.prototype.readName = function(source) { - if (ol.xml.isDocument(source)) { - return this.readNameFromDocument(/** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readNameFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readNameFromDocument(doc); - } else { - goog.asserts.fail('Unknown type for source'); - return undefined; - } -}; - - -/** - * @param {Document} doc Document. - * @return {string|undefined} Name. - */ -ol.format.KML.prototype.readNameFromDocument = function(doc) { - var n; - for (n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - var name = this.readNameFromNode(n); - if (name) { - return name; - } - } - } - return undefined; -}; - - -/** - * @param {Node} node Node. - * @return {string|undefined} Name. - */ -ol.format.KML.prototype.readNameFromNode = function(node) { - var n; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - n.localName == 'name') { - return ol.format.XSD.readString(n); - } - } - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var localName = ol.xml.getLocalName(n); - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - (localName == 'Document' || - localName == 'Folder' || - localName == 'Placemark' || - localName == 'kml')) { - var name = this.readNameFromNode(n); - if (name) { - return name; - } - } - } - return undefined; -}; - - -/** - * Read the network links of the KML. - * - * @param {Document|Node|string} source Source. - * @return {Array.<Object>} Network links. - * @api - */ -ol.format.KML.prototype.readNetworkLinks = function(source) { - var networkLinks = []; - if (ol.xml.isDocument(source)) { - goog.array.extend(networkLinks, this.readNetworkLinksFromDocument( - /** @type {Document} */ (source))); - } else if (ol.xml.isNode(source)) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode( - /** @type {Node} */ (source))); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - goog.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc)); - } else { - goog.asserts.fail('unknown type for source'); - } - return networkLinks; -}; - - -/** - * @param {Document} doc Document. - * @return {Array.<Object>} Network links. - */ -ol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) { - var n, networkLinks = []; - for (n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); - } - } - return networkLinks; -}; - - -/** - * @param {Node} node Node. - * @return {Array.<Object>} Network links. - */ -ol.format.KML.prototype.readNetworkLinksFromNode = function(node) { - var n, networkLinks = []; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - n.localName == 'NetworkLink') { - var obj = ol.xml.pushParseAndPop({}, ol.format.KML.NETWORK_LINK_PARSERS_, - n, []); - networkLinks.push(obj); - } - } - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var localName = ol.xml.getLocalName(n); - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - (localName == 'Document' || - localName == 'Folder' || - localName == 'kml')) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); - } - } - return networkLinks; -}; - - -/** - * Read the projection from a KML source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.KML.prototype.readProjection; - - -/** - * @param {Node} node Node to append a TextNode with the color to. - * @param {ol.Color|string} color Color. - * @private - */ -ol.format.KML.writeColorTextNode_ = function(node, color) { - var rgba = ol.color.asArray(color); - var opacity = (rgba.length == 4) ? rgba[3] : 1; - var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]]; - var i; - for (i = 0; i < 4; ++i) { - var hex = parseInt(abgr[i], 10).toString(16); - abgr[i] = (hex.length == 1) ? '0' + hex : hex; - } - ol.format.XSD.writeStringTextNode(node, abgr.join('')); -}; - - -/** - * @param {Node} node Node to append a TextNode with the coordinates to. - * @param {Array.<number>} coordinates Coordinates. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeCoordinatesTextNode_ = - function(node, coordinates, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - - var layout = context['layout']; - var stride = context['stride']; - - var dimension; - if (layout == ol.geom.GeometryLayout.XY || - layout == ol.geom.GeometryLayout.XYM) { - dimension = 2; - } else if (layout == ol.geom.GeometryLayout.XYZ || - layout == ol.geom.GeometryLayout.XYZM) { - dimension = 3; - } else { - goog.asserts.fail('Unknown geometry layout'); - } - - var d, i; - var ii = coordinates.length; - var text = ''; - if (ii > 0) { - text += coordinates[0]; - for (d = 1; d < dimension; ++d) { - text += ',' + coordinates[d]; - } - for (i = stride; i < ii; i += stride) { - text += ' ' + coordinates[i]; - for (d = 1; d < dimension; ++d) { - text += ',' + coordinates[i + d]; - } - } - } - ol.format.XSD.writeStringTextNode(node, text); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<ol.Feature>} features Features. - * @param {Array.<*>} objectStack Object stack. - * @this {ol.format.KML} - * @private - */ -ol.format.KML.writeDocument_ = function(node, features, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_, - ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack, undefined, - this); -}; - - -/** - * @param {Node} node Node. - * @param {Object} icon Icon object. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeIcon_ = function(node, icon, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(icon, orderedKeys); - ol.xml.pushSerializeAndPop(context, - ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); - orderedKeys = - ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]]; - values = ol.xml.makeSequence(icon, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_, - ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.style.Icon} style Icon style. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeIconStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = {}; - var src = style.getSrc(); - var size = style.getSize(); - var iconImageSize = style.getImageSize(); - var iconProperties = { - 'href': src - }; - - if (size) { - iconProperties['w'] = size[0]; - iconProperties['h'] = size[1]; - var anchor = style.getAnchor(); // top-left - var origin = style.getOrigin(); // top-left - - if (origin && iconImageSize && origin[0] !== 0 && origin[1] !== size[1]) { - iconProperties['x'] = origin[0]; - iconProperties['y'] = iconImageSize[1] - (origin[1] + size[1]); - } - - if (anchor && anchor[0] !== 0 && anchor[1] !== size[1]) { - var /** @type {ol.format.KMLVec2_} */ hotSpot = { - x: anchor[0], - xunits: ol.style.IconAnchorUnits.PIXELS, - y: size[1] - anchor[1], - yunits: ol.style.IconAnchorUnits.PIXELS - }; - properties['hotSpot'] = hotSpot; - } - } - - properties['Icon'] = iconProperties; - - var scale = style.getScale(); - if (scale !== 1) { - properties['scale'] = scale; - } - - var rotation = style.getRotation(); - if (rotation !== 0) { - properties['heading'] = rotation; // 0-360 - } - - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.style.Text} style style. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeLabelStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = {}; - var fill = style.getFill(); - if (fill) { - properties['color'] = fill.getColor(); - } - var scale = style.getScale(); - if (scale && scale !== 1) { - properties['scale'] = scale; - } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = - ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.style.Stroke} style style. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeLineStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = { - 'color': style.getColor(), - 'width': style.getWidth() - }; - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Geometry} geometry Geometry. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeMultiGeometry_ = - function(node, geometry, objectStack) { - goog.asserts.assert( - (geometry instanceof ol.geom.MultiPoint) || - (geometry instanceof ol.geom.MultiLineString) || - (geometry instanceof ol.geom.MultiPolygon), - 'geometry should be one of: ol.geom.MultiPoint, ' + - 'ol.geom.MultiLineString or ol.geom.MultiPolygon'); - /** @type {ol.xml.NodeStackItem} */ - var context = {node: node}; - var type = geometry.getType(); - /** @type {Array.<ol.geom.Geometry>} */ - var geometries; - /** @type {function(*, Array.<*>, string=): (Node|undefined)} */ - var factory; - if (type == ol.geom.GeometryType.MULTI_POINT) { - geometries = - (/** @type {ol.geom.MultiPoint} */ (geometry)).getPoints(); - factory = ol.format.KML.POINT_NODE_FACTORY_; - } else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) { - geometries = - (/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings(); - factory = ol.format.KML.LINE_STRING_NODE_FACTORY_; - } else if (type == ol.geom.GeometryType.MULTI_POLYGON) { - geometries = - (/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons(); - factory = ol.format.KML.POLYGON_NODE_FACTORY_; - } else { - goog.asserts.fail('Unknown geometry type: ' + type); - } - ol.xml.pushSerializeAndPop(context, - ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory, - geometries, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.LinearRing} linearRing Linear ring. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - ol.xml.pushSerializeAndPop(context, - ol.format.KML.BOUNDARY_IS_SERIALIZERS_, - ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack); -}; - - -/** - * FIXME currently we do serialize arbitrary/custom feature properties - * (ExtendedData). - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Object stack. - * @this {ol.format.KML} - * @private - */ -ol.format.KML.writePlacemark_ = function(node, feature, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - - // set id - if (feature.getId()) { - node.setAttribute('id', feature.getId()); - } - - // serialize properties (properties unknown to KML are not serialized) - var properties = feature.getProperties(); - - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - // FIXME the styles returned by the style function are supposed to be - // resolution-independent here - var styles = styleFunction.call(feature, 0); - if (styles && styles.length > 0) { - var style = styles[0]; - if (this.writeStyles_) { - properties['Style'] = styles[0]; - } - var textStyle = style.getText(); - if (textStyle) { - properties['name'] = textStyle.getText(); - } - } - } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); - - // serialize geometry - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var geometry = feature.getGeometry(); - if (geometry) { - geometry = - ol.format.Feature.transformWithOptions(geometry, true, options); - } - ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_, - ol.format.KML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) { - goog.asserts.assert( - (geometry instanceof ol.geom.Point) || - (geometry instanceof ol.geom.LineString) || - (geometry instanceof ol.geom.LinearRing), - 'geometry should be one of ol.geom.Point, ol.geom.LineString ' + - 'or ol.geom.LinearRing'); - var flatCoordinates = geometry.getFlatCoordinates(); - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - context['layout'] = geometry.getLayout(); - context['stride'] = geometry.getStride(); - ol.xml.pushSerializeAndPop(context, - ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_, - ol.format.KML.COORDINATES_NODE_FACTORY_, - [flatCoordinates], objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.geom.Polygon} polygon Polygon. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writePolygon_ = function(node, polygon, objectStack) { - goog.asserts.assertInstanceof(polygon, ol.geom.Polygon, - 'polygon should be an ol.geom.Polygon'); - var linearRings = polygon.getLinearRings(); - goog.asserts.assert(linearRings.length > 0, - 'linearRings should not be empty'); - var outerRing = linearRings.shift(); - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - // inner rings - ol.xml.pushSerializeAndPop(context, - ol.format.KML.POLYGON_SERIALIZERS_, - ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_, - linearRings, objectStack); - // outer ring - ol.xml.pushSerializeAndPop(context, - ol.format.KML.POLYGON_SERIALIZERS_, - ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_, - [outerRing], objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {ol.style.Fill} style Style. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writePolyStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_, - ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack); -}; - - -/** - * @param {Node} node Node to append a TextNode with the scale to. - * @param {number|undefined} scale Scale. - * @private - */ -ol.format.KML.writeScaleTextNode_ = function(node, scale) { - ol.format.XSD.writeDecimalTextNode(node, scale * scale); -}; - - -/** - * @param {Node} node Node. - * @param {ol.style.Style} style Style. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.writeStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = {}; - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - var imageStyle = style.getImage(); - var textStyle = style.getText(); - if (imageStyle instanceof ol.style.Icon) { - properties['IconStyle'] = imageStyle; - } - if (textStyle) { - properties['LabelStyle'] = textStyle; - } - if (strokeStyle) { - properties['LineStyle'] = strokeStyle; - } - if (fillStyle) { - properties['PolyStyle'] = fillStyle; - } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); -}; - - -/** - * @param {Node} node Node to append a TextNode with the Vec2 to. - * @param {ol.format.KMLVec2_} vec2 Vec2. - * @private - */ -ol.format.KML.writeVec2_ = function(node, vec2) { - node.setAttribute('x', vec2.x); - node.setAttribute('y', vec2.y); - node.setAttribute('xunits', vec2.xunits); - node.setAttribute('yunits', vec2.yunits); -}; - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'Document', 'Placemark' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_), - 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_) - }); - - -/** - * @const - * @type {Object.<string, string>} - * @private - */ -ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = { - 'Point': 'Point', - 'LineString': 'LineString', - 'LinearRing': 'LinearRing', - 'Polygon': 'Polygon', - 'MultiPoint': 'MultiGeometry', - 'MultiLineString': 'MultiGeometry', - 'MultiPolygon': 'MultiGeometry' -}; - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'href' - ], - ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, [ - 'x', 'y', 'w', 'h' - ])); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode) - })); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'scale', 'heading', 'Icon', 'hotSpot' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_), - 'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_), - 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'color', 'scale' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_), - 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'color', 'width' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_), - 'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LinearRing': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LineString': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Point': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'name', 'open', 'visibility', 'address', 'phoneNumber', 'description', - 'styleUrl', 'Style' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'MultiGeometry': ol.xml.makeChildAppender( - ol.format.KML.writeMultiGeometry_), - 'LineString': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'LinearRing': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Point': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_), - 'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_), - 'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'description': ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode), - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'open': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode), - 'phoneNumber': ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode), - 'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'visibility': ol.xml.makeChildAppender( - ol.format.XSD.writeBooleanTextNode) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'coordinates': ol.xml.makeChildAppender( - ol.format.KML.writeCoordinatesTextNode_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'outerBoundaryIs': ol.xml.makeChildAppender( - ol.format.KML.writeBoundaryIs_), - 'innerBoundaryIs': ol.xml.makeChildAppender( - ol.format.KML.writeBoundaryIs_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_) - }); - - -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle' - ]); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_), - 'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_), - 'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_), - 'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_) - }); - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { - return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0], - 'gx:' + opt_nodeName); -}; - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack, - opt_nodeName) { - goog.asserts.assertInstanceof(value, ol.Feature, - 'value should be an ol.Feature'); - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark'); -}; - - -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, - opt_nodeName) { - if (value) { - goog.asserts.assertInstanceof(value, ol.geom.Geometry, - 'value should be an ol.geom.Geometry'); - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - return ol.xml.createElementNS(parentNode.namespaceURI, - ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[value.getType()]); - } -}; - - -/** - * A factory for creating coordinates nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color'); - - -/** - * A factory for creating coordinates nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.COORDINATES_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('coordinates'); - - -/** - * A factory for creating innerBoundaryIs nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('innerBoundaryIs'); - - -/** - * A factory for creating Point nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.POINT_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('Point'); - - -/** - * A factory for creating LineString nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.LINE_STRING_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('LineString'); - - -/** - * A factory for creating LinearRing nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.LINEAR_RING_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('LinearRing'); - - -/** - * A factory for creating Polygon nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.POLYGON_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('Polygon'); - - -/** - * A factory for creating outerBoundaryIs nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('outerBoundaryIs'); - - -/** - * Encode an array of features in the KML format. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {string} Result. - * @api stable - */ -ol.format.KML.prototype.writeFeatures; - - -/** - * Encode an array of features in the KML format as an XML node. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var kml = ol.xml.createElementNS(ol.format.KML.NAMESPACE_URIS_[4], 'kml'); - var xmlnsUri = 'http://www.w3.org/2000/xmlns/'; - var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance'; - ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:gx', - ol.format.KML.GX_NAMESPACE_URIS_[0]); - ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri); - ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation', - ol.format.KML.SCHEMA_LOCATION_); - - var /** @type {ol.xml.NodeStackItem} */ context = {node: kml}; - var properties = {}; - if (features.length > 1) { - properties['Document'] = features; - } else if (features.length == 1) { - properties['Placemark'] = features[0]; - } - var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [opt_options], orderedKeys, - this); - return kml; -}; - -goog.provide('ol.ext.pbf'); -/** @typedef {function(*)} */ -ol.ext.pbf; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; -/** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pbf = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ -'use strict'; - -// lightweight Buffer shim for pbf browser build -// based on code from github.com/feross/buffer (MIT-licensed) - -module.exports = Buffer; - -var ieee754 = _dereq_('ieee754'); - -var BufferMethods; - -function Buffer(length) { - var arr; - if (length && length.length) { - arr = length; - length = arr.length; - } - var buf = new Uint8Array(length || 0); - if (arr) buf.set(arr); - - buf.readUInt32LE = BufferMethods.readUInt32LE; - buf.writeUInt32LE = BufferMethods.writeUInt32LE; - buf.readInt32LE = BufferMethods.readInt32LE; - buf.writeInt32LE = BufferMethods.writeInt32LE; - buf.readFloatLE = BufferMethods.readFloatLE; - buf.writeFloatLE = BufferMethods.writeFloatLE; - buf.readDoubleLE = BufferMethods.readDoubleLE; - buf.writeDoubleLE = BufferMethods.writeDoubleLE; - buf.toString = BufferMethods.toString; - buf.write = BufferMethods.write; - buf.slice = BufferMethods.slice; - buf.copy = BufferMethods.copy; - - buf._isBuffer = true; - return buf; -} - -var lastStr, lastStrEncoded; - -BufferMethods = { - readUInt32LE: function(pos) { - return ((this[pos]) | - (this[pos + 1] << 8) | - (this[pos + 2] << 16)) + - (this[pos + 3] * 0x1000000); - }, - - writeUInt32LE: function(val, pos) { - this[pos] = val; - this[pos + 1] = (val >>> 8); - this[pos + 2] = (val >>> 16); - this[pos + 3] = (val >>> 24); - }, - - readInt32LE: function(pos) { - return ((this[pos]) | - (this[pos + 1] << 8) | - (this[pos + 2] << 16)) + - (this[pos + 3] << 24); - }, - - readFloatLE: function(pos) { return ieee754.read(this, pos, true, 23, 4); }, - readDoubleLE: function(pos) { return ieee754.read(this, pos, true, 52, 8); }, - - writeFloatLE: function(val, pos) { return ieee754.write(this, val, pos, true, 23, 4); }, - writeDoubleLE: function(val, pos) { return ieee754.write(this, val, pos, true, 52, 8); }, - - toString: function(encoding, start, end) { - var str = '', - tmp = ''; - - start = start || 0; - end = Math.min(this.length, end || this.length); - - for (var i = start; i < end; i++) { - var ch = this[i]; - if (ch <= 0x7F) { - str += decodeURIComponent(tmp) + String.fromCharCode(ch); - tmp = ''; - } else { - tmp += '%' + ch.toString(16); - } - } - - str += decodeURIComponent(tmp); - - return str; - }, - - write: function(str, pos) { - var bytes = str === lastStr ? lastStrEncoded : encodeString(str); - for (var i = 0; i < bytes.length; i++) { - this[pos + i] = bytes[i]; - } - }, - - slice: function(start, end) { - return this.subarray(start, end); - }, - - copy: function(buf, pos) { - pos = pos || 0; - for (var i = 0; i < this.length; i++) { - buf[pos + i] = this[i]; - } - } -}; - -BufferMethods.writeInt32LE = BufferMethods.writeUInt32LE; - -Buffer.byteLength = function(str) { - lastStr = str; - lastStrEncoded = encodeString(str); - return lastStrEncoded.length; -}; - -Buffer.isBuffer = function(buf) { - return !!(buf && buf._isBuffer); -}; - -function encodeString(str) { - var length = str.length, - bytes = []; - - for (var i = 0, c, lead; i < length; i++) { - c = str.charCodeAt(i); // code point - - if (c > 0xD7FF && c < 0xE000) { - - if (lead) { - if (c < 0xDC00) { - bytes.push(0xEF, 0xBF, 0xBD); - lead = c; - continue; - - } else { - c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; - lead = null; - } - - } else { - if (c > 0xDBFF || (i + 1 === length)) bytes.push(0xEF, 0xBF, 0xBD); - else lead = c; - - continue; - } - - } else if (lead) { - bytes.push(0xEF, 0xBF, 0xBD); - lead = null; - } - - if (c < 0x80) bytes.push(c); - else if (c < 0x800) bytes.push(c >> 0x6 | 0xC0, c & 0x3F | 0x80); - else if (c < 0x10000) bytes.push(c >> 0xC | 0xE0, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); - else bytes.push(c >> 0x12 | 0xF0, c >> 0xC & 0x3F | 0x80, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); - } - return bytes; -} - -},{"ieee754":3}],2:[function(_dereq_,module,exports){ -(function (global){ -'use strict'; - -module.exports = Pbf; - -var Buffer = global.Buffer || _dereq_('./buffer'); - -function Pbf(buf) { - this.buf = !Buffer.isBuffer(buf) ? new Buffer(buf || 0) : buf; - this.pos = 0; - this.length = this.buf.length; -} - -Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum -Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 -Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields -Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 - -var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), - SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32, - POW_2_63 = Math.pow(2, 63); - -Pbf.prototype = { - - destroy: function() { - this.buf = null; - }, - - // === READING ================================================================= - - readFields: function(readField, result, end) { - end = end || this.length; - - while (this.pos < end) { - var val = this.readVarint(), - tag = val >> 3, - startPos = this.pos; - - readField(tag, result, this); - - if (this.pos === startPos) this.skip(val); - } - return result; - }, - - readMessage: function(readField, result) { - return this.readFields(readField, result, this.readVarint() + this.pos); - }, - - readFixed32: function() { - var val = this.buf.readUInt32LE(this.pos); - this.pos += 4; - return val; - }, - - readSFixed32: function() { - var val = this.buf.readInt32LE(this.pos); - this.pos += 4; - return val; - }, - - // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) - - readFixed64: function() { - var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readSFixed64: function() { - var val = this.buf.readUInt32LE(this.pos) + this.buf.readInt32LE(this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - - readFloat: function() { - var val = this.buf.readFloatLE(this.pos); - this.pos += 4; - return val; - }, - - readDouble: function() { - var val = this.buf.readDoubleLE(this.pos); - this.pos += 8; - return val; - }, - - readVarint: function() { - var buf = this.buf, - val, b, b0, b1, b2, b3; - - b0 = buf[this.pos++]; if (b0 < 0x80) return b0; b0 = b0 & 0x7f; - b1 = buf[this.pos++]; if (b1 < 0x80) return b0 | b1 << 7; b1 = (b1 & 0x7f) << 7; - b2 = buf[this.pos++]; if (b2 < 0x80) return b0 | b1 | b2 << 14; b2 = (b2 & 0x7f) << 14; - b3 = buf[this.pos++]; if (b3 < 0x80) return b0 | b1 | b2 | b3 << 21; - - val = b0 | b1 | b2 | (b3 & 0x7f) << 21; - - b = buf[this.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val; - - throw new Error('Expected varint not more than 10 bytes'); - }, - - readVarint64: function() { - var startPos = this.pos, - val = this.readVarint(); - - if (val < POW_2_63) return val; - - var pos = this.pos - 2; - while (this.buf[pos] === 0xff) pos--; - if (pos < startPos) pos = startPos; - - val = 0; - for (var i = 0; i < pos - startPos + 1; i++) { - var b = ~this.buf[startPos + i] & 0x7f; - val += i < 4 ? b << i * 7 : b * Math.pow(2, i * 7); - } - - return -val - 1; - }, - - readSVarint: function() { - var num = this.readVarint(); - return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding - }, - - readBoolean: function() { - return Boolean(this.readVarint()); - }, - - readString: function() { - var end = this.readVarint() + this.pos, - str = this.buf.toString('utf8', this.pos, end); - this.pos = end; - return str; - }, - - readBytes: function() { - var end = this.readVarint() + this.pos, - buffer = this.buf.slice(this.pos, end); - this.pos = end; - return buffer; - }, - - // verbose for performance reasons; doesn't affect gzipped size - - readPackedVarint: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readVarint()); - return arr; - }, - readPackedSVarint: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSVarint()); - return arr; - }, - readPackedBoolean: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readBoolean()); - return arr; - }, - readPackedFloat: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFloat()); - return arr; - }, - readPackedDouble: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readDouble()); - return arr; - }, - readPackedFixed32: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFixed32()); - return arr; - }, - readPackedSFixed32: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSFixed32()); - return arr; - }, - readPackedFixed64: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFixed64()); - return arr; - }, - readPackedSFixed64: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSFixed64()); - return arr; - }, - - skip: function(val) { - var type = val & 0x7; - if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} - else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; - else if (type === Pbf.Fixed32) this.pos += 4; - else if (type === Pbf.Fixed64) this.pos += 8; - else throw new Error('Unimplemented type: ' + type); - }, - - // === WRITING ================================================================= - - writeTag: function(tag, type) { - this.writeVarint((tag << 3) | type); - }, - - realloc: function(min) { - var length = this.length || 16; - - while (length < this.pos + min) length *= 2; - - if (length !== this.length) { - var buf = new Buffer(length); - this.buf.copy(buf); - this.buf = buf; - this.length = length; - } - }, - - finish: function() { - this.length = this.pos; - this.pos = 0; - return this.buf.slice(0, this.length); - }, - - writeFixed32: function(val) { - this.realloc(4); - this.buf.writeUInt32LE(val, this.pos); - this.pos += 4; - }, - - writeSFixed32: function(val) { - this.realloc(4); - this.buf.writeInt32LE(val, this.pos); - this.pos += 4; - }, - - writeFixed64: function(val) { - this.realloc(8); - this.buf.writeInt32LE(val & -1, this.pos); - this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeSFixed64: function(val) { - this.realloc(8); - this.buf.writeInt32LE(val & -1, this.pos); - this.buf.writeInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - - writeVarint: function(val) { - val = +val; - - if (val <= 0x7f) { - this.realloc(1); - this.buf[this.pos++] = val; - - } else if (val <= 0x3fff) { - this.realloc(2); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f); - - } else if (val <= 0x1fffff) { - this.realloc(3); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 14) & 0x7f); - - } else if (val <= 0xfffffff) { - this.realloc(4); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 14) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 21) & 0x7f); - - } else { - var pos = this.pos; - while (val >= 0x80) { - this.realloc(1); - this.buf[this.pos++] = (val & 0xff) | 0x80; - val /= 0x80; - } - this.realloc(1); - this.buf[this.pos++] = val | 0; - if (this.pos - pos > 10) throw new Error('Given varint doesn\'t fit into 10 bytes'); - } - }, - - writeSVarint: function(val) { - this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); - }, - - writeBoolean: function(val) { - this.writeVarint(Boolean(val)); - }, - - writeString: function(str) { - str = String(str); - var bytes = Buffer.byteLength(str); - this.writeVarint(bytes); - this.realloc(bytes); - this.buf.write(str, this.pos); - this.pos += bytes; - }, - - writeFloat: function(val) { - this.realloc(4); - this.buf.writeFloatLE(val, this.pos); - this.pos += 4; - }, - - writeDouble: function(val) { - this.realloc(8); - this.buf.writeDoubleLE(val, this.pos); - this.pos += 8; - }, - - writeBytes: function(buffer) { - var len = buffer.length; - this.writeVarint(len); - this.realloc(len); - for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; - }, - - writeRawMessage: function(fn, obj) { - this.pos++; // reserve 1 byte for short message length - - // write the message directly to the buffer and see how much was written - var startPos = this.pos; - fn(obj, this); - var len = this.pos - startPos; - - var varintLen = - len <= 0x7f ? 1 : - len <= 0x3fff ? 2 : - len <= 0x1fffff ? 3 : - len <= 0xfffffff ? 4 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); - - // if 1 byte isn't enough for encoding message length, shift the data to the right - if (varintLen > 1) { - this.realloc(varintLen - 1); - for (var i = this.pos - 1; i >= startPos; i--) this.buf[i + varintLen - 1] = this.buf[i]; - } - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeMessage: function(tag, fn, obj) { - this.writeTag(tag, Pbf.Bytes); - this.writeRawMessage(fn, obj); - }, - - writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, - writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, - writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, - writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, - writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, - writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, - writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, - writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, - writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, - - writeBytesField: function(tag, buffer) { - this.writeTag(tag, Pbf.Bytes); - this.writeBytes(buffer); - }, - writeFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFixed32(val); - }, - writeSFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeSFixed32(val); - }, - writeFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeFixed64(val); - }, - writeSFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeSFixed64(val); - }, - writeVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeVarint(val); - }, - writeSVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeSVarint(val); - }, - writeStringField: function(tag, str) { - this.writeTag(tag, Pbf.Bytes); - this.writeString(str); - }, - writeFloatField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFloat(val); - }, - writeDoubleField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeDouble(val); - }, - writeBooleanField: function(tag, val) { - this.writeVarintField(tag, Boolean(val)); - } -}; - -function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } -function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } -function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } -function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } -function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } -function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } -function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } -function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } -function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./buffer":1}],3:[function(_dereq_,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - -},{}]},{},[2])(2) -}); -ol.ext.pbf = module.exports; -})(); - -goog.provide('ol.ext.vectortile'); -/** @typedef {function(*)} */ -ol.ext.vectortile; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; -/** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vectortile = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ -module.exports.VectorTile = _dereq_('./lib/vectortile.js'); -module.exports.VectorTileFeature = _dereq_('./lib/vectortilefeature.js'); -module.exports.VectorTileLayer = _dereq_('./lib/vectortilelayer.js'); - -},{"./lib/vectortile.js":2,"./lib/vectortilefeature.js":3,"./lib/vectortilelayer.js":4}],2:[function(_dereq_,module,exports){ -'use strict'; - -var VectorTileLayer = _dereq_('./vectortilelayer'); - -module.exports = VectorTile; - -function VectorTile(pbf, end) { - this.layers = pbf.readFields(readTile, {}, end); -} - -function readTile(tag, layers, pbf) { - if (tag === 3) { - var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); - if (layer.length) layers[layer.name] = layer; - } -} - - -},{"./vectortilelayer":4}],3:[function(_dereq_,module,exports){ -'use strict'; - -var Point = _dereq_('point-geometry'); - -module.exports = VectorTileFeature; - -function VectorTileFeature(pbf, end, extent, keys, values) { - // Public - this.properties = {}; - this.extent = extent; - this.type = 0; - - // Private - this._pbf = pbf; - this._geometry = -1; - this._keys = keys; - this._values = values; - - pbf.readFields(readFeature, this, end); -} - -function readFeature(tag, feature, pbf) { - if (tag == 1) feature._id = pbf.readVarint(); - else if (tag == 2) readTag(pbf, feature); - else if (tag == 3) feature.type = pbf.readVarint(); - else if (tag == 4) feature._geometry = pbf.pos; -} - -function readTag(pbf, feature) { - var end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var key = feature._keys[pbf.readVarint()], - value = feature._values[pbf.readVarint()]; - feature.properties[key] = value; - } -} - -VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; - -VectorTileFeature.prototype.loadGeometry = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - lines = [], - line; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - - if (cmd === 1) { // moveTo - if (line) lines.push(line); - line = []; - } - - line.push(new Point(x, y)); - - } else if (cmd === 7) { - - // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 - if (line) { - line.push(line[0].clone()); // closePolygon - } - - } else { - throw new Error('unknown command ' + cmd); - } - } - - if (line) lines.push(line); - - return lines; -}; - -VectorTileFeature.prototype.bbox = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; - - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - - length--; - - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - if (x < x1) x1 = x; - if (x > x2) x2 = x; - if (y < y1) y1 = y; - if (y > y2) y2 = y; - - } else if (cmd !== 7) { - throw new Error('unknown command ' + cmd); - } - } - - return [x1, y1, x2, y2]; -}; - -VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { - var size = this.extent * Math.pow(2, z), - x0 = this.extent * x, - y0 = this.extent * y, - coords = this.loadGeometry(), - type = VectorTileFeature.types[this.type]; - - for (var i = 0; i < coords.length; i++) { - var line = coords[i]; - for (var j = 0; j < line.length; j++) { - var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; - line[j] = [ - (p.x + x0) * 360 / size - 180, - 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 - ]; - } - } - - if (type === 'Point' && coords.length === 1) { - coords = coords[0][0]; - } else if (type === 'Point') { - coords = coords[0]; - type = 'MultiPoint'; - } else if (type === 'LineString' && coords.length === 1) { - coords = coords[0]; - } else if (type === 'LineString') { - type = 'MultiLineString'; - } - - return { - type: "Feature", - geometry: { - type: type, - coordinates: coords - }, - properties: this.properties - }; -}; - -},{"point-geometry":5}],4:[function(_dereq_,module,exports){ -'use strict'; - -var VectorTileFeature = _dereq_('./vectortilefeature.js'); - -module.exports = VectorTileLayer; - -function VectorTileLayer(pbf, end) { - // Public - this.version = 1; - this.name = null; - this.extent = 4096; - this.length = 0; - - // Private - this._pbf = pbf; - this._keys = []; - this._values = []; - this._features = []; - - pbf.readFields(readLayer, this, end); - - this.length = this._features.length; -} - -function readLayer(tag, layer, pbf) { - if (tag === 15) layer.version = pbf.readVarint(); - else if (tag === 1) layer.name = pbf.readString(); - else if (tag === 5) layer.extent = pbf.readVarint(); - else if (tag === 2) layer._features.push(pbf.pos); - else if (tag === 3) layer._keys.push(pbf.readString()); - else if (tag === 4) layer._values.push(readValueMessage(pbf)); -} - -function readValueMessage(pbf) { - var value = null, - end = pbf.readVarint() + pbf.pos; - - while (pbf.pos < end) { - var tag = pbf.readVarint() >> 3; - - value = tag === 1 ? pbf.readString() : - tag === 2 ? pbf.readFloat() : - tag === 3 ? pbf.readDouble() : - tag === 4 ? pbf.readVarint64() : - tag === 5 ? pbf.readVarint() : - tag === 6 ? pbf.readSVarint() : - tag === 7 ? pbf.readBoolean() : null; - } - - return value; -} - -// return feature `i` from this layer as a `VectorTileFeature` -VectorTileLayer.prototype.feature = function(i) { - if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); - - this._pbf.pos = this._features[i]; - - var end = this._pbf.readVarint() + this._pbf.pos; - return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); -}; - -},{"./vectortilefeature.js":3}],5:[function(_dereq_,module,exports){ -'use strict'; - -module.exports = Point; - -function Point(x, y) { - this.x = x; - this.y = y; -} - -Point.prototype = { - clone: function() { return new Point(this.x, this.y); }, - - add: function(p) { return this.clone()._add(p); }, - sub: function(p) { return this.clone()._sub(p); }, - mult: function(k) { return this.clone()._mult(k); }, - div: function(k) { return this.clone()._div(k); }, - rotate: function(a) { return this.clone()._rotate(a); }, - matMult: function(m) { return this.clone()._matMult(m); }, - unit: function() { return this.clone()._unit(); }, - perp: function() { return this.clone()._perp(); }, - round: function() { return this.clone()._round(); }, - - mag: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, - - equals: function(p) { - return this.x === p.x && - this.y === p.y; - }, - - dist: function(p) { - return Math.sqrt(this.distSqr(p)); - }, - - distSqr: function(p) { - var dx = p.x - this.x, - dy = p.y - this.y; - return dx * dx + dy * dy; - }, - - angle: function() { - return Math.atan2(this.y, this.x); - }, - - angleTo: function(b) { - return Math.atan2(this.y - b.y, this.x - b.x); - }, - - angleWith: function(b) { - return this.angleWithSep(b.x, b.y); - }, - - // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ. - angleWithSep: function(x, y) { - return Math.atan2( - this.x * y - this.y * x, - this.x * x + this.y * y); - }, - - _matMult: function(m) { - var x = m[0] * this.x + m[1] * this.y, - y = m[2] * this.x + m[3] * this.y; - this.x = x; - this.y = y; - return this; - }, - - _add: function(p) { - this.x += p.x; - this.y += p.y; - return this; - }, - - _sub: function(p) { - this.x -= p.x; - this.y -= p.y; - return this; - }, - - _mult: function(k) { - this.x *= k; - this.y *= k; - return this; - }, - - _div: function(k) { - this.x /= k; - this.y /= k; - return this; - }, - - _unit: function() { - this._div(this.mag()); - return this; - }, - - _perp: function() { - var y = this.y; - this.y = this.x; - this.x = -y; - return this; - }, - - _rotate: function(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = cos * this.x - sin * this.y, - y = sin * this.x + cos * this.y; - this.x = x; - this.y = y; - return this; - }, - - _round: function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - } -}; - -// constructs Point from an array if necessary -Point.convert = function (a) { - if (a instanceof Point) { - return a; - } - if (Array.isArray(a)) { - return new Point(a[0], a[1]); - } - return a; -}; - -},{}]},{},[1])(1) -}); -ol.ext.vectortile = module.exports; -})(); - -//FIXME Implement projection handling - -goog.provide('ol.format.MVT'); - -goog.require('goog.asserts'); -goog.require('ol.Feature'); -goog.require('ol.ext.pbf'); -goog.require('ol.ext.vectortile'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); -goog.require('ol.render.Feature'); - - - -/** - * @classdesc - * Feature format for reading data in the Mapbox MVT format. - * - * @constructor - * @extends {ol.format.Feature} - * @param {olx.format.MVTOptions=} opt_options Options. - * @api - */ -ol.format.MVT = function(opt_options) { - - goog.base(this); - - var options = opt_options ? opt_options : {}; - - /** - * @type {ol.proj.Projection} - */ - this.defaultDataProjection = new ol.proj.Projection({ - code: 'EPSG:3857', - units: ol.proj.Units.TILE_PIXELS - }); - - /** - * @private - * @type {function((ol.geom.Geometry|Object.<string, *>)=)| - * function(ol.geom.GeometryType,Array.<number>, - * (Array.<number>|Array.<Array.<number>>),Object.<string, *>)} - */ - this.featureClass_ = options.featureClass ? - options.featureClass : ol.render.Feature; - - /** - * @private - * @type {string} - */ - this.geometryName_ = options.geometryName ? - options.geometryName : 'geometry'; - - /** - * @private - * @type {string} - */ - this.layerName_ = options.layerName ? options.layerName : 'layer'; - - /** - * @private - * @type {Array.<string>} - */ - this.layers_ = options.layers ? options.layers : null; - -}; -goog.inherits(ol.format.MVT, ol.format.Feature); - - -/** - * @inheritDoc - */ -ol.format.MVT.prototype.getType = function() { - return ol.format.FormatType.ARRAY_BUFFER; -}; - - -/** - * @private - * @param {Object} rawFeature Raw Mapbox feature. - * @param {string} layer Layer. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - */ -ol.format.MVT.prototype.readFeature_ = function( - rawFeature, layer, opt_options) { - var feature = new this.featureClass_(); - var values = rawFeature.properties; - values[this.layerName_] = layer; - var geometry = ol.format.Feature.transformWithOptions( - ol.format.MVT.readGeometry_(rawFeature), false, - this.adaptOptions(opt_options)); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.Geometry); - values[this.geometryName_] = geometry; - } - feature.setProperties(values); - feature.setGeometryName(this.geometryName_); - return feature; -}; - - -/** - * @private - * @param {Object} rawFeature Raw Mapbox feature. - * @param {string} layer Layer. - * @return {ol.render.Feature} Feature. - */ -ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) { - var coords = rawFeature.loadGeometry(); - var ends = []; - var flatCoordinates = []; - ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends); - - var type = rawFeature.type; - /** @type {ol.geom.GeometryType} */ - var geometryType; - if (type === 1) { - geometryType = coords.length === 1 ? - ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT; - } else if (type === 2) { - if (coords.length === 1) { - geometryType = ol.geom.GeometryType.LINE_STRING; - } else { - geometryType = ol.geom.GeometryType.MULTI_LINE_STRING; - } - } else if (type === 3) { - geometryType = ol.geom.GeometryType.POLYGON; - } - - var values = rawFeature.properties; - values[this.layerName_] = layer; - - return new this.featureClass_(geometryType, flatCoordinates, ends, values); -}; - - -/** - * @inheritDoc - */ -ol.format.MVT.prototype.readFeatures = function(source, opt_options) { - goog.asserts.assertInstanceof(source, ArrayBuffer); - - var layers = this.layers_; - - var pbf = new ol.ext.pbf(source); - var tile = new ol.ext.vectortile.VectorTile(pbf); - var features = []; - var featureClass = this.featureClass_; - var layer, feature; - for (var name in tile.layers) { - if (layers && layers.indexOf(name) == -1) { - continue; - } - layer = tile.layers[name]; - - for (var i = 0, ii = layer.length; i < ii; ++i) { - if (featureClass === ol.render.Feature) { - feature = this.readRenderFeature_(layer.feature(i), name); - } else { - feature = this.readFeature_(layer.feature(i), name, opt_options); - } - features.push(feature); - } - } - - return features; -}; - - -/** - * @inheritDoc - */ -ol.format.MVT.prototype.readProjection = function(source) { - return this.defaultDataProjection; -}; - - -/** - * Sets the layers that features will be read from. - * @param {Array.<string>} layers Layers. - * @api - */ -ol.format.MVT.prototype.setLayers = function(layers) { - this.layers_ = layers; -}; - - -/** - * @private - * @param {Object} coords Raw feature coordinates. - * @param {Array.<number>} flatCoordinates Flat coordinates to be populated by - * this function. - * @param {Array.<number>} ends Ends to be populated by this function. - */ -ol.format.MVT.calculateFlatCoordinates_ = function( - coords, flatCoordinates, ends) { - var end = 0; - var line, coord; - for (var i = 0, ii = coords.length; i < ii; ++i) { - line = coords[i]; - for (var j = 0, jj = line.length; j < jj; ++j) { - coord = line[j]; - // Non-tilespace coords can be calculated here when a TileGrid and - // TileCoord are known. - flatCoordinates.push(coord.x, coord.y); - } - end += 2 * j; - ends.push(end); - } -}; - - -/** - * @private - * @param {Object} rawFeature Raw Mapbox feature. - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.MVT.readGeometry_ = function(rawFeature) { - var type = rawFeature.type; - if (type === 0) { - return null; - } - - var coords = rawFeature.loadGeometry(); - var ends = []; - var flatCoordinates = []; - ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends); - - var geom; - if (type === 1) { - geom = coords.length === 1 ? - new ol.geom.Point(null) : new ol.geom.MultiPoint(null); - } else if (type === 2) { - if (coords.length === 1) { - geom = new ol.geom.LineString(null); - } else { - geom = new ol.geom.MultiLineString(null); - } - } else if (type === 3) { - geom = new ol.geom.Polygon(null); - } - - geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, - ends); - - return geom; -}; - -// FIXME add typedef for stack state objects -goog.provide('ol.format.OSMXML'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Feature format for reading data in the - * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML). - * - * @constructor - * @extends {ol.format.XMLFeature} - * @api stable - */ -ol.format.OSMXML = function() { - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); -}; -goog.inherits(ol.format.OSMXML, ol.format.XMLFeature); - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.OSMXML.EXTENSIONS_ = ['.osm']; - - -/** - * @inheritDoc - */ -ol.format.OSMXML.prototype.getExtensions = function() { - return ol.format.OSMXML.EXTENSIONS_; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.OSMXML.readNode_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'node', 'localName should be node'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var id = node.getAttribute('id'); - var coordinates = /** @type {Array.<number>} */ ([ - parseFloat(node.getAttribute('lon')), - parseFloat(node.getAttribute('lat')) - ]); - state.nodes[id] = coordinates; - - var values = ol.xml.pushParseAndPop({ - tags: {} - }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack); - if (!goog.object.isEmpty(values.tags)) { - var geometry = new ol.geom.Point(coordinates); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setId(id); - feature.setProperties(values.tags); - state.features.push(feature); - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.OSMXML.readWay_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'way', 'localName should be way'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var id = node.getAttribute('id'); - var values = ol.xml.pushParseAndPop({ - ndrefs: [], - tags: {} - }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack); - var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var flatCoordinates = /** @type {Array.<number>} */ ([]); - for (var i = 0, ii = values.ndrefs.length; i < ii; i++) { - var point = state.nodes[values.ndrefs[i]]; - goog.array.extend(flatCoordinates, point); - } - var geometry; - if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) { - // closed way - geometry = new ol.geom.Polygon(null); - geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, - [flatCoordinates.length]); - } else { - geometry = new ol.geom.LineString(null); - geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); - } - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setId(id); - feature.setProperties(values.tags); - state.features.push(feature); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Track. - */ -ol.format.OSMXML.readNd_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'nd', 'localName should be nd'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - values.ndrefs.push(node.getAttribute('ref')); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Track. - */ -ol.format.OSMXML.readTag_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'tag', 'localName should be tag'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - values.tags[node.getAttribute('k')] = node.getAttribute('v'); -}; - - -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.format.OSMXML.NAMESPACE_URIS_ = [ - null -]; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OSMXML.NAMESPACE_URIS_, { - 'nd': ol.format.OSMXML.readNd_, - 'tag': ol.format.OSMXML.readTag_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OSMXML.PARSERS_ = ol.xml.makeStructureNS( - ol.format.OSMXML.NAMESPACE_URIS_, { - 'node': ol.format.OSMXML.readNode_, - 'way': ol.format.OSMXML.readWay_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OSMXML.NAMESPACE_URIS_, { - 'tag': ol.format.OSMXML.readTag_ - }); - - -/** - * Read all features from an OSM source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.OSMXML.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var options = this.getReadOptions(node, opt_options); - if (node.localName == 'osm') { - var state = ol.xml.pushParseAndPop({ - nodes: {}, - features: [] - }, ol.format.OSMXML.PARSERS_, node, [options]); - if (state.features) { - return state.features; - } - } - return []; -}; - - -/** - * Read the projection from an OSM source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.OSMXML.prototype.readProjection; - -goog.provide('ol.format.XLink'); - - -/** - * @const - * @type {string} - */ -ol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink'; - - -/** - * @param {Node} node Node. - * @return {boolean|undefined} Boolean. - */ -ol.format.XLink.readHref = function(node) { - return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href'); -}; - -goog.provide('ol.format.XML'); - -goog.require('goog.asserts'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Generic format for reading non-feature XML data - * - * @constructor - */ -ol.format.XML = function() { -}; - - -/** - * @param {Document|Node|string} source Source. - * @return {Object} - */ -ol.format.XML.prototype.read = function(source) { - if (ol.xml.isDocument(source)) { - return this.readFromDocument(/** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFromDocument(doc); - } else { - goog.asserts.fail(); - return null; - } -}; - - -/** - * @param {Document} doc Document. - * @return {Object} - */ -ol.format.XML.prototype.readFromDocument = goog.abstractMethod; - - -/** - * @param {Node} node Node. - * @return {Object} - */ -ol.format.XML.prototype.readFromNode = goog.abstractMethod; - -goog.provide('ol.format.OWS'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.format.XLink'); -goog.require('ol.format.XML'); -goog.require('ol.format.XSD'); -goog.require('ol.xml'); - - - -/** - * @constructor - * @extends {ol.format.XML} - */ -ol.format.OWS = function() { - goog.base(this); -}; -goog.inherits(ol.format.OWS, ol.format.XML); - - -/** - * @param {Document} doc Document. - * @return {Object} OWS object. - */ -ol.format.OWS.prototype.readFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFromNode(n); - } - } - return null; -}; - - -/** - * @param {Node} node Node. - * @return {Object} OWS object. - */ -ol.format.OWS.prototype.readFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var owsObject = ol.xml.pushParseAndPop({}, - ol.format.OWS.PARSERS_, node, []); - return owsObject ? owsObject : null; -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readAddress_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Address', - 'localName should be Address'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.ADDRESS_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readAllowedValues_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'AllowedValues', - 'localName should be AllowedValues'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readConstraint_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Constraint', - 'localName should be Constraint'); - var name = node.getAttribute('name'); - if (!name) { - return undefined; - } - return ol.xml.pushParseAndPop({'name': name}, - ol.format.OWS.CONSTRAINT_PARSERS_, node, - objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readContactInfo_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactInfo', - 'localName should be ContactInfo'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readDcp_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'DCP', 'localName should be DCP'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.DCP_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readGet_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Get', 'localName should be Get'); - var href = ol.format.XLink.readHref(node); - if (!href) { - return undefined; - } - return ol.xml.pushParseAndPop({'href': href}, - ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readHttp_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP'); - return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_, - node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readOperation_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Operation', - 'localName should be Operation'); - var name = node.getAttribute('name'); - var value = ol.xml.pushParseAndPop({}, - ol.format.OWS.OPERATION_PARSERS_, node, objectStack); - if (!value) { - return undefined; - } - var object = /** @type {Object} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(object), 'object should be an Object'); - object[name] = value; - -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readOperationsMetadata_ = function(node, - objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'OperationsMetadata', - 'localName should be OperationsMetadata'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node, - objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readPhone_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Phone', 'localName should be Phone'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.PHONE_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readServiceIdentification_ = function(node, - objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ServiceIdentification', - 'localName should be ServiceIdentification'); - return ol.xml.pushParseAndPop( - {}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node, - objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readServiceContact_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ServiceContact', - 'localName should be ServiceContact'); - return ol.xml.pushParseAndPop( - {}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node, - objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readServiceProvider_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ServiceProvider', - 'localName should be ServiceProvider'); - return ol.xml.pushParseAndPop( - {}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node, - objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {string|undefined} - */ -ol.format.OWS.readValue_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Value', 'localName should be Value'); - return ol.format.XSD.readString(node); -}; - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.OWS.NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/ows/1.1' -]; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'ServiceIdentification': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readServiceIdentification_), - 'ServiceProvider': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readServiceProvider_), - 'OperationsMetadata': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readOperationsMetadata_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'DeliveryPoint': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'AdministrativeArea': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ElectronicMailAddress': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'AllowedValues': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readAllowedValues_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_), - 'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.DCP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.HTTP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_), - 'Post': undefined // TODO - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Operation': ol.format.OWS.readOperation_ - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.PHONE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Constraint': ol.xml.makeObjectPropertyPusher( - ol.format.OWS.readConstraint_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.SERVICE_CONTACT_PARSERS_ = - ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'IndividualName': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ContactInfo': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readContactInfo_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ = - ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ServiceTypeVersion': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.SERVICE_PROVIDER_PARSERS_ = - ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref), - 'ServiceContact': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readServiceContact_) - }); - -goog.provide('ol.geom.flat.flip'); - -goog.require('goog.asserts'); - - -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {Array.<number>=} opt_dest Destination. - * @param {number=} opt_destOffset Destination offset. - * @return {Array.<number>} Flat coordinates. - */ -ol.geom.flat.flip.flipXY = - function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) { - var dest, destOffset; - if (opt_dest !== undefined) { - dest = opt_dest; - destOffset = opt_destOffset !== undefined ? opt_destOffset : 0; - } else { - goog.asserts.assert(opt_destOffset === undefined, - 'opt_destOffSet should be defined'); - dest = []; - destOffset = 0; - } - var j, k; - for (j = offset; j < end; ) { - var x = flatCoordinates[j++]; - dest[destOffset++] = flatCoordinates[j++]; - dest[destOffset++] = x; - for (k = 2; k < stride; ++k) { - dest[destOffset++] = flatCoordinates[j++]; - } - } - dest.length = destOffset; - return dest; -}; - -goog.provide('ol.format.Polyline'); - -goog.require('goog.asserts'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.TextFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.flip'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the Encoded - * Polyline Algorithm Format. - * - * @constructor - * @extends {ol.format.TextFeature} - * @param {olx.format.PolylineOptions=} opt_options - * Optional configuration object. - * @api stable - */ -ol.format.Polyline = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); - - /** - * @private - * @type {number} - */ - this.factor_ = options.factor ? options.factor : 1e5; - - /** - * @private - * @type {ol.geom.GeometryLayout} - */ - this.geometryLayout_ = options.geometryLayout ? - options.geometryLayout : ol.geom.GeometryLayout.XY; -}; -goog.inherits(ol.format.Polyline, ol.format.TextFeature); - - -/** - * Encode a list of n-dimensional points and return an encoded string - * - * Attention: This function will modify the passed array! - * - * @param {Array.<number>} numbers A list of n-dimensional points. - * @param {number} stride The number of dimension of the points in the list. - * @param {number=} opt_factor The factor by which the numbers will be - * multiplied. The remaining decimal places will get rounded away. - * Default is `1e5`. - * @return {string} The encoded string. - * @api - */ -ol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var d; - - var lastNumbers = new Array(stride); - for (d = 0; d < stride; ++d) { - lastNumbers[d] = 0; - } - - var i, ii; - for (i = 0, ii = numbers.length; i < ii;) { - for (d = 0; d < stride; ++d, ++i) { - var num = numbers[i]; - var delta = num - lastNumbers[d]; - lastNumbers[d] = num; - - numbers[i] = delta; - } - } - - return ol.format.Polyline.encodeFloats(numbers, factor); -}; - - -/** - * Decode a list of n-dimensional points from an encoded string - * - * @param {string} encoded An encoded string. - * @param {number} stride The number of dimension of the points in the - * encoded string. - * @param {number=} opt_factor The factor by which the resulting numbers will - * be divided. Default is `1e5`. - * @return {Array.<number>} A list of n-dimensional points. - * @api - */ -ol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var d; - - /** @type {Array.<number>} */ - var lastNumbers = new Array(stride); - for (d = 0; d < stride; ++d) { - lastNumbers[d] = 0; - } - - var numbers = ol.format.Polyline.decodeFloats(encoded, factor); - - var i, ii; - for (i = 0, ii = numbers.length; i < ii;) { - for (d = 0; d < stride; ++d, ++i) { - lastNumbers[d] += numbers[i]; - - numbers[i] = lastNumbers[d]; - } - } - - return numbers; -}; - - -/** - * Encode a list of floating point numbers and return an encoded string - * - * Attention: This function will modify the passed array! - * - * @param {Array.<number>} numbers A list of floating point numbers. - * @param {number=} opt_factor The factor by which the numbers will be - * multiplied. The remaining decimal places will get rounded away. - * Default is `1e5`. - * @return {string} The encoded string. - * @api - */ -ol.format.Polyline.encodeFloats = function(numbers, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - numbers[i] = Math.round(numbers[i] * factor); - } - - return ol.format.Polyline.encodeSignedIntegers(numbers); -}; - - -/** - * Decode a list of floating point numbers from an encoded string - * - * @param {string} encoded An encoded string. - * @param {number=} opt_factor The factor by which the result will be divided. - * Default is `1e5`. - * @return {Array.<number>} A list of floating point numbers. - * @api - */ -ol.format.Polyline.decodeFloats = function(encoded, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var numbers = ol.format.Polyline.decodeSignedIntegers(encoded); - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - numbers[i] /= factor; - } - return numbers; -}; - - -/** - * Encode a list of signed integers and return an encoded string - * - * Attention: This function will modify the passed array! - * - * @param {Array.<number>} numbers A list of signed integers. - * @return {string} The encoded string. - */ -ol.format.Polyline.encodeSignedIntegers = function(numbers) { - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - var num = numbers[i]; - numbers[i] = (num < 0) ? ~(num << 1) : (num << 1); - } - return ol.format.Polyline.encodeUnsignedIntegers(numbers); -}; - - -/** - * Decode a list of signed integers from an encoded string - * - * @param {string} encoded An encoded string. - * @return {Array.<number>} A list of signed integers. - */ -ol.format.Polyline.decodeSignedIntegers = function(encoded) { - var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded); - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - var num = numbers[i]; - numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); - } - return numbers; -}; - - -/** - * Encode a list of unsigned integers and return an encoded string - * - * @param {Array.<number>} numbers A list of unsigned integers. - * @return {string} The encoded string. - */ -ol.format.Polyline.encodeUnsignedIntegers = function(numbers) { - var encoded = ''; - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]); - } - return encoded; -}; - - -/** - * Decode a list of unsigned integers from an encoded string - * - * @param {string} encoded An encoded string. - * @return {Array.<number>} A list of unsigned integers. - */ -ol.format.Polyline.decodeUnsignedIntegers = function(encoded) { - var numbers = []; - var current = 0; - var shift = 0; - var i, ii; - for (i = 0, ii = encoded.length; i < ii; ++i) { - var b = encoded.charCodeAt(i) - 63; - current |= (b & 0x1f) << shift; - if (b < 0x20) { - numbers.push(current); - current = 0; - shift = 0; - } else { - shift += 5; - } - } - return numbers; -}; - - -/** - * Encode one single unsigned integer and return an encoded string - * - * @param {number} num Unsigned integer that should be encoded. - * @return {string} The encoded string. - */ -ol.format.Polyline.encodeUnsignedInteger = function(num) { - var value, encoded = ''; - while (num >= 0x20) { - value = (0x20 | (num & 0x1f)) + 63; - encoded += String.fromCharCode(value); - num >>= 5; - } - value = num + 63; - encoded += String.fromCharCode(value); - return encoded; -}; - - -/** - * Read the feature from the Polyline source. The coordinates are assumed to be - * in two dimensions and in latitude, longitude order. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.Polyline.prototype.readFeature; - - -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) { - var geometry = this.readGeometryFromText(text, opt_options); - return new ol.Feature(geometry); -}; - - -/** - * Read the feature from the source. As Polyline sources contain a single - * feature, this will return the feature in an array. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.Polyline.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.readFeaturesFromText = - function(text, opt_options) { - var feature = this.readFeatureFromText(text, opt_options); - return [feature]; -}; - - -/** - * Read the geometry from the source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api stable - */ -ol.format.Polyline.prototype.readGeometry; - - -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.readGeometryFromText = - function(text, opt_options) { - var stride = ol.geom.SimpleGeometry.getStrideForLayout(this.geometryLayout_); - var flatCoordinates = ol.format.Polyline.decodeDeltas( - text, stride, this.factor_); - ol.geom.flat.flip.flipXY( - flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates); - var coordinates = ol.geom.flat.inflate.coordinates( - flatCoordinates, 0, flatCoordinates.length, stride); - - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions( - new ol.geom.LineString(coordinates, this.geometryLayout_), false, - this.adaptOptions(opt_options))); -}; - - -/** - * Read the projection from a Polyline source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.Polyline.prototype.readProjection; - - -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) { - var geometry = feature.getGeometry(); - if (geometry) { - return this.writeGeometryText(geometry, opt_options); - } else { - goog.asserts.fail('geometry needs to be defined'); - return ''; - } -}; - - -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.writeFeaturesText = - function(features, opt_options) { - goog.asserts.assert(features.length == 1, - 'features array should have 1 item'); - return this.writeFeatureText(features[0], opt_options); -}; - - -/** - * Write a single geometry in Polyline format. - * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Geometry. - * @api stable - */ -ol.format.Polyline.prototype.writeGeometry; - - -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.writeGeometryText = - function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - geometry = /** @type {ol.geom.LineString} */ - (ol.format.Feature.transformWithOptions( - geometry, true, this.adaptOptions(opt_options))); - var flatCoordinates = geometry.getFlatCoordinates(); - var stride = geometry.getStride(); - ol.geom.flat.flip.flipXY( - flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates); - return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_); -}; - -goog.provide('ol.format.TopoJSON'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.JSONFeature'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Feature format for reading data in the TopoJSON format. - * - * @constructor - * @extends {ol.format.JSONFeature} - * @param {olx.format.TopoJSONOptions=} opt_options Options. - * @api stable - */ -ol.format.TopoJSON = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get( - options.defaultDataProjection ? - options.defaultDataProjection : 'EPSG:4326'); - -}; -goog.inherits(ol.format.TopoJSON, ol.format.JSONFeature); - - -/** - * @const {Array.<string>} - * @private - */ -ol.format.TopoJSON.EXTENSIONS_ = ['.topojson']; - - -/** - * Concatenate arcs into a coordinate array. - * @param {Array.<number>} indices Indices of arcs to concatenate. Negative - * values indicate arcs need to be reversed. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already - * transformed). - * @return {Array.<ol.Coordinate>} Coordinates array. - * @private - */ -ol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) { - /** @type {Array.<ol.Coordinate>} */ - var coordinates = []; - var index, arc; - var i, ii; - var j, jj; - for (i = 0, ii = indices.length; i < ii; ++i) { - index = indices[i]; - if (i > 0) { - // splicing together arcs, discard last point - coordinates.pop(); - } - if (index >= 0) { - // forward arc - arc = arcs[index]; - } else { - // reverse arc - arc = arcs[~index].slice().reverse(); - } - coordinates.push.apply(coordinates, arc); - } - // provide fresh copies of coordinate arrays - for (j = 0, jj = coordinates.length; j < jj; ++j) { - coordinates[j] = coordinates[j].slice(); - } - return coordinates; -}; - - -/** - * Create a point from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @return {ol.geom.Point} Geometry. - * @private - */ -ol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) { - var coordinates = object.coordinates; - if (scale && translate) { - ol.format.TopoJSON.transformVertex_(coordinates, scale, translate); - } - return new ol.geom.Point(coordinates); -}; - - -/** - * Create a multi-point from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @return {ol.geom.MultiPoint} Geometry. - * @private - */ -ol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale, - translate) { - var coordinates = object.coordinates; - var i, ii; - if (scale && translate) { - for (i = 0, ii = coordinates.length; i < ii; ++i) { - ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate); - } - } - return new ol.geom.MultiPoint(coordinates); -}; - - -/** - * Create a linestring from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.LineString} Geometry. - * @private - */ -ol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) { - var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs); - return new ol.geom.LineString(coordinates); -}; - - -/** - * Create a multi-linestring from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.MultiLineString} Geometry. - * @private - */ -ol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) { - var coordinates = []; - var i, ii; - for (i = 0, ii = object.arcs.length; i < ii; ++i) { - coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs); - } - return new ol.geom.MultiLineString(coordinates); -}; - - -/** - * Create a polygon from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.Polygon} Geometry. - * @private - */ -ol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) { - var coordinates = []; - var i, ii; - for (i = 0, ii = object.arcs.length; i < ii; ++i) { - coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs); - } - return new ol.geom.Polygon(coordinates); -}; - - -/** - * Create a multi-polygon from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.MultiPolygon} Geometry. - * @private - */ -ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) { - var coordinates = []; - var polyArray, ringCoords, j, jj; - var i, ii; - for (i = 0, ii = object.arcs.length; i < ii; ++i) { - // for each polygon - polyArray = object.arcs[i]; - ringCoords = []; - for (j = 0, jj = polyArray.length; j < jj; ++j) { - // for each ring - ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs); - } - coordinates[i] = ringCoords; - } - return new ol.geom.MultiPolygon(coordinates); -}; - - -/** - * @inheritDoc - */ -ol.format.TopoJSON.prototype.getExtensions = function() { - return ol.format.TopoJSON.EXTENSIONS_; -}; - - -/** - * Create features from a TopoJSON GeometryCollection object. - * - * @param {TopoJSONGeometryCollection} collection TopoJSON Geometry - * object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Array of features. - * @private - */ -ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function( - collection, arcs, scale, translate, opt_options) { - var geometries = collection.geometries; - var features = []; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - features[i] = ol.format.TopoJSON.readFeatureFromGeometry_( - geometries[i], arcs, scale, translate, opt_options); - } - return features; -}; - - -/** - * Create a feature from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON geometry object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @private - */ -ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs, - scale, translate, opt_options) { - var geometry; - var type = object.type; - var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type]; - goog.asserts.assert(geometryReader, 'geometryReader should be defined'); - if ((type === 'Point') || (type === 'MultiPoint')) { - geometry = geometryReader(object, scale, translate); - } else { - geometry = geometryReader(object, arcs); - } - var feature = new ol.Feature(); - feature.setGeometry(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, false, opt_options))); - if (object.id !== undefined) { - feature.setId(object.id); - } - if (object.properties) { - feature.setProperties(object.properties); - } - return feature; -}; - - -/** - * Read all features from a TopoJSON source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.TopoJSON.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.TopoJSON.prototype.readFeaturesFromObject = function( - object, opt_options) { - if (object.type == 'Topology') { - var topoJSONTopology = /** @type {TopoJSONTopology} */ (object); - var transform, scale = null, translate = null; - if (topoJSONTopology.transform) { - transform = topoJSONTopology.transform; - scale = transform.scale; - translate = transform.translate; - } - var arcs = topoJSONTopology.arcs; - if (transform) { - ol.format.TopoJSON.transformArcs_(arcs, scale, translate); - } - /** @type {Array.<ol.Feature>} */ - var features = []; - var topoJSONFeatures = goog.object.getValues(topoJSONTopology.objects); - var i, ii; - var feature; - for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) { - if (topoJSONFeatures[i].type === 'GeometryCollection') { - feature = /** @type {TopoJSONGeometryCollection} */ - (topoJSONFeatures[i]); - features.push.apply(features, - ol.format.TopoJSON.readFeaturesFromGeometryCollection_( - feature, arcs, scale, translate, opt_options)); - } else { - feature = /** @type {TopoJSONGeometry} */ - (topoJSONFeatures[i]); - features.push(ol.format.TopoJSON.readFeatureFromGeometry_( - feature, arcs, scale, translate, opt_options)); - } - } - return features; - } else { - return []; - } -}; - - -/** - * Apply a linear transform to array of arcs. The provided array of arcs is - * modified in place. - * - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @private - */ -ol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) { - var i, ii; - for (i = 0, ii = arcs.length; i < ii; ++i) { - ol.format.TopoJSON.transformArc_(arcs[i], scale, translate); - } -}; - - -/** - * Apply a linear transform to an arc. The provided arc is modified in place. - * - * @param {Array.<ol.Coordinate>} arc Arc. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @private - */ -ol.format.TopoJSON.transformArc_ = function(arc, scale, translate) { - var x = 0; - var y = 0; - var vertex; - var i, ii; - for (i = 0, ii = arc.length; i < ii; ++i) { - vertex = arc[i]; - x += vertex[0]; - y += vertex[1]; - vertex[0] = x; - vertex[1] = y; - ol.format.TopoJSON.transformVertex_(vertex, scale, translate); - } -}; - - -/** - * Apply a linear transform to a vertex. The provided vertex is modified in - * place. - * - * @param {ol.Coordinate} vertex Vertex. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @private - */ -ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) { - vertex[0] = vertex[0] * scale[0] + translate[0]; - vertex[1] = vertex[1] * scale[1] + translate[1]; -}; - - -/** - * Read the projection from a TopoJSON source. - * - * @function - * @param {Document|Node|Object|string} object Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.TopoJSON.prototype.readProjection = function(object) { - return this.defaultDataProjection; -}; - - -/** - * @const - * @private - * @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>} - */ -ol.format.TopoJSON.GEOMETRY_READERS_ = { - 'Point': ol.format.TopoJSON.readPointGeometry_, - 'LineString': ol.format.TopoJSON.readLineStringGeometry_, - 'Polygon': ol.format.TopoJSON.readPolygonGeometry_, - 'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_, - 'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_, - 'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_ -}; - -goog.provide('ol.format.WFS'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.format.GML3'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.Geometry'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Feature format for reading and writing data in the WFS format. - * By default, supports WFS version 1.1.0. You can pass a GML format - * as option if you want to read a WFS that contains GML2 (WFS 1.0.0). - * Also see {@link ol.format.GMLBase} which is used by this format. - * - * @constructor - * @param {olx.format.WFSOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.XMLFeature} - * @api stable - */ -ol.format.WFS = function(opt_options) { - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {Array.<string>|string|undefined} - */ - this.featureType_ = options.featureType; - - /** - * @private - * @type {Object.<string, string>|string|undefined} - */ - this.featureNS_ = options.featureNS; - - /** - * @private - * @type {ol.format.GMLBase} - */ - this.gmlFormat_ = options.gmlFormat ? - options.gmlFormat : new ol.format.GML3(); - - /** - * @private - * @type {string} - */ - this.schemaLocation_ = options.schemaLocation ? - options.schemaLocation : ol.format.WFS.SCHEMA_LOCATION; - - goog.base(this); -}; -goog.inherits(ol.format.WFS, ol.format.XMLFeature); - - -/** - * @const - * @type {string} - */ -ol.format.WFS.FEATURE_PREFIX = 'feature'; - - -/** - * @const - * @type {string} - */ -ol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/'; - - -/** - * Number of features; bounds/extent. - * @typedef {{numberOfFeatures: number, - * bounds: ol.Extent}} - * @api stable - */ -ol.format.WFS.FeatureCollectionMetadata; - - -/** - * Total deleted; total inserted; total updated; array of insert ids. - * @typedef {{totalDeleted: number, - * totalInserted: number, - * totalUpdated: number, - * insertIds: Array.<string>}} - * @api stable - */ -ol.format.WFS.TransactionResponse; - - -/** - * @const - * @type {string} - */ -ol.format.WFS.SCHEMA_LOCATION = 'http://www.opengis.net/wfs ' + - 'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd'; - - -/** - * Read all features from a WFS FeatureCollection. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.WFS.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) { - var context = { - 'featureType': this.featureType_, - 'featureNS': this.featureNS_ - }; - goog.object.extend(context, this.getReadOptions(node, - opt_options ? opt_options : {})); - var objectStack = [context]; - this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][ - 'featureMember'] = - ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal); - var features = ol.xml.pushParseAndPop([], - this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node, - objectStack, this.gmlFormat_); - if (!features) { - features = []; - } - return features; -}; - - -/** - * Read transaction response of the source. - * - * @param {Document|Node|Object|string} source Source. - * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. - * @api stable - */ -ol.format.WFS.prototype.readTransactionResponse = function(source) { - if (ol.xml.isDocument(source)) { - return this.readTransactionResponseFromDocument( - /** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readTransactionResponseFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readTransactionResponseFromDocument(doc); - } else { - goog.asserts.fail('Unknown source type'); - return undefined; - } -}; - - -/** - * Read feature collection metadata of the source. - * - * @param {Document|Node|Object|string} source Source. - * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} - * FeatureCollection metadata. - * @api stable - */ -ol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) { - if (ol.xml.isDocument(source)) { - return this.readFeatureCollectionMetadataFromDocument( - /** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readFeatureCollectionMetadataFromNode( - /** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFeatureCollectionMetadataFromDocument(doc); - } else { - goog.asserts.fail('Unknown source type'); - return undefined; - } -}; - - -/** - * @param {Document} doc Document. - * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} - * FeatureCollection metadata. - */ -ol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument = - function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFeatureCollectionMetadataFromNode(n); - } - } - return undefined; -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.FEATURE_COLLECTION_PARSERS_ = { - 'http://www.opengis.net/gml': { - 'boundedBy': ol.xml.makeObjectPropertySetter( - ol.format.GMLBase.prototype.readGeometryElement, 'bounds') - } -}; - - -/** - * @param {Node} node Node. - * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} - * FeatureCollection metadata. - */ -ol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'FeatureCollection', - 'localName should be FeatureCollection'); - var result = {}; - var value = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('numberOfFeatures')); - result['numberOfFeatures'] = value; - return ol.xml.pushParseAndPop( - /** @type {ol.format.WFS.FeatureCollectionMetadata} */ (result), - ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_); -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = { - 'http://www.opengis.net/wfs': { - 'totalInserted': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'totalUpdated': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'totalDeleted': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger) - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Transaction Summary. - * @private - */ -ol.format.WFS.readTransactionSummary_ = function(node, objectStack) { - return ol.xml.pushParseAndPop( - {}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack); -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.OGC_FID_PARSERS_ = { - 'http://www.opengis.net/ogc': { - 'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) { - return node.getAttribute('fid'); - }) - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.WFS.fidParser_ = function(node, objectStack) { - ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack); -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.INSERT_RESULTS_PARSERS_ = { - 'http://www.opengis.net/wfs': { - 'Feature': ol.format.WFS.fidParser_ - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<string>|undefined} Insert results. - * @private - */ -ol.format.WFS.readInsertResults_ = function(node, objectStack) { - return ol.xml.pushParseAndPop( - [], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack); -}; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = { - 'http://www.opengis.net/wfs': { - 'TransactionSummary': ol.xml.makeObjectPropertySetter( - ol.format.WFS.readTransactionSummary_, 'transactionSummary'), - 'InsertResults': ol.xml.makeObjectPropertySetter( - ol.format.WFS.readInsertResults_, 'insertIds') - } -}; - - -/** - * @param {Document} doc Document. - * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. - */ -ol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readTransactionResponseFromNode(n); - } - } - return undefined; -}; - - -/** - * @param {Node} node Node. - * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. - */ -ol.format.WFS.prototype.readTransactionResponseFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'TransactionResponse', - 'localName should be TransactionResponse'); - return ol.xml.pushParseAndPop( - /** @type {ol.format.WFS.TransactionResponse} */({}), - ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []); -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.WFS.QUERY_SERIALIZERS_ = { - 'http://www.opengis.net/wfs': { - 'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeFeature_ = function(node, feature, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featureNS = context['featureNS']; - var child = ol.xml.createElementNS(featureNS, featureType); - node.appendChild(child); - ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {number|string} fid Feature identifier. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) { - var filter = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter'); - var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'FeatureId'); - filter.appendChild(child); - child.setAttribute('fid', fid); - node.appendChild(filter); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeDelete_ = function(node, feature, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featurePrefix = context['featurePrefix']; - featurePrefix = featurePrefix ? featurePrefix : - ol.format.WFS.FEATURE_PREFIX; - var featureNS = context['featureNS']; - node.setAttribute('typeName', featurePrefix + ':' + featureType); - ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, - featureNS); - var fid = feature.getId(); - if (fid) { - ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featurePrefix = context['featurePrefix']; - featurePrefix = featurePrefix ? featurePrefix : - ol.format.WFS.FEATURE_PREFIX; - var featureNS = context['featureNS']; - node.setAttribute('typeName', featurePrefix + ':' + featureType); - ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, - featureNS); - var fid = feature.getId(); - if (fid) { - var keys = feature.getKeys(); - var values = []; - for (var i = 0, ii = keys.length; i < ii; i++) { - var value = feature.get(keys[i]); - if (value !== undefined) { - values.push({name: keys[i], value: value}); - } - } - ol.xml.pushSerializeAndPop({node: node, srsName: - context['srsName']}, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Property'), values, - objectStack); - ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); - } -}; - - -/** - * @param {Node} node Node. - * @param {Object} pair Property name and value. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeProperty_ = function(node, pair, objectStack) { - var name = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Name'); - node.appendChild(name); - ol.format.XSD.writeStringTextNode(name, pair.name); - if (pair.value !== undefined && pair.value !== null) { - var value = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Value'); - node.appendChild(value); - if (pair.value instanceof ol.geom.Geometry) { - ol.format.GML3.prototype.writeGeometryElement(value, - pair.value, objectStack); - } else { - ol.format.XSD.writeStringTextNode(value, pair.value); - } - } -}; - - -/** - * @param {Node} node Node. - * @param {{vendorId: string, safeToIgnore: boolean, value: string}} - * nativeElement The native element. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) { - if (nativeElement.vendorId) { - node.setAttribute('vendorId', nativeElement.vendorId); - } - if (nativeElement.safeToIgnore !== undefined) { - node.setAttribute('safeToIgnore', nativeElement.safeToIgnore); - } - if (nativeElement.value !== undefined) { - ol.format.XSD.writeStringTextNode(node, nativeElement.value); - } -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.WFS.TRANSACTION_SERIALIZERS_ = { - 'http://www.opengis.net/wfs': { - 'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_), - 'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_), - 'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_), - 'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_), - 'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_) - } -}; - - -/** - * @param {Node} node Node. - * @param {string} featureType Feature type. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeQuery_ = function(node, featureType, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featurePrefix = context['featurePrefix']; - var featureNS = context['featureNS']; - var propertyNames = context['propertyNames']; - var srsName = context['srsName']; - var prefix = featurePrefix ? featurePrefix + ':' : ''; - node.setAttribute('typeName', prefix + featureType); - if (srsName) { - node.setAttribute('srsName', srsName); - } - if (featureNS) { - ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, - featureNS); - } - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(item, - ol.format.WFS.QUERY_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames, - objectStack); - var bbox = context['bbox']; - if (bbox) { - var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter'); - ol.format.WFS.writeOgcBBOX_(child, bbox, objectStack); - node.appendChild(child); - } -}; - - -/** - * @param {Node} node Node. - * @param {string} value PropertyName value. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeOgcPropertyName_ = function(node, value, objectStack) { - var property = ol.xml.createElementNS('http://www.opengis.net/ogc', - 'PropertyName'); - ol.format.XSD.writeStringTextNode(property, value); - node.appendChild(property); -}; - - -/** - * @param {Node} node Node. - * @param {ol.Extent} bbox Bounding box. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeOgcBBOX_ = function(node, bbox, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var geometryName = context['geometryName']; - var bboxNode = ol.xml.createElementNS('http://www.opengis.net/ogc', 'BBOX'); - node.appendChild(bboxNode); - ol.format.WFS.writeOgcPropertyName_(bboxNode, geometryName, objectStack); - ol.format.GML3.prototype.writeGeometryElement(bboxNode, bbox, objectStack); -}; - - -/** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.WFS.GETFEATURE_SERIALIZERS_ = { - 'http://www.opengis.net/wfs': { - 'Query': ol.xml.makeChildAppender( - ol.format.WFS.writeQuery_) - } -}; - - -/** - * @param {Node} node Node. - * @param {Array.<{string}>} featureTypes Feature types. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(item, - ol.format.WFS.GETFEATURE_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Query'), featureTypes, - objectStack); -}; - - -/** - * Encode format as WFS `GetFeature` and return the Node. - * - * @param {olx.format.WFSWriteGetFeatureOptions} options Options. - * @return {Node} Result. - * @api stable - */ -ol.format.WFS.prototype.writeGetFeature = function(options) { - var node = ol.xml.createElementNS('http://www.opengis.net/wfs', - 'GetFeature'); - node.setAttribute('service', 'WFS'); - node.setAttribute('version', '1.1.0'); - if (options) { - if (options.handle) { - node.setAttribute('handle', options.handle); - } - if (options.outputFormat) { - node.setAttribute('outputFormat', options.outputFormat); - } - if (options.maxFeatures !== undefined) { - node.setAttribute('maxFeatures', options.maxFeatures); - } - if (options.resultType) { - node.setAttribute('resultType', options.resultType); - } - if (options.startIndex !== undefined) { - node.setAttribute('startIndex', options.startIndex); - } - if (options.count !== undefined) { - node.setAttribute('count', options.count); - } - } - ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', this.schemaLocation_); - var context = { - node: node, - srsName: options.srsName, - featureNS: options.featureNS ? options.featureNS : this.featureNS_, - featurePrefix: options.featurePrefix, - geometryName: options.geometryName, - bbox: options.bbox, - propertyNames: options.propertyNames ? options.propertyNames : [] - }; - goog.asserts.assert(goog.isArray(options.featureTypes), - 'options.featureTypes should be an array'); - ol.format.WFS.writeGetFeature_(node, options.featureTypes, [context]); - return node; -}; - - -/** - * Encode format as WFS `Transaction` and return the Node. - * - * @param {Array.<ol.Feature>} inserts The features to insert. - * @param {Array.<ol.Feature>} updates The features to update. - * @param {Array.<ol.Feature>} deletes The features to delete. - * @param {olx.format.WFSWriteTransactionOptions} options Write options. - * @return {Node} Result. - * @api stable - */ -ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes, - options) { - var objectStack = []; - var node = ol.xml.createElementNS('http://www.opengis.net/wfs', - 'Transaction'); - node.setAttribute('service', 'WFS'); - node.setAttribute('version', '1.1.0'); - var baseObj, obj; - if (options) { - baseObj = options.gmlOptions ? options.gmlOptions : {}; - if (options.handle) { - node.setAttribute('handle', options.handle); - } - } - ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', this.schemaLocation_); - if (inserts) { - obj = {node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}; - goog.object.extend(obj, baseObj); - ol.xml.pushSerializeAndPop(obj, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Insert'), inserts, - objectStack); - } - if (updates) { - obj = {node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}; - goog.object.extend(obj, baseObj); - ol.xml.pushSerializeAndPop(obj, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Update'), updates, - objectStack); - } - if (deletes) { - ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Delete'), deletes, - objectStack); - } - if (options.nativeElements) { - ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements, - objectStack); - } - return node; -}; - - -/** - * Read the projection from a WFS source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {?ol.proj.Projection} Projection. - * @api stable - */ -ol.format.WFS.prototype.readProjection; - - -/** - * @inheritDoc - */ -ol.format.WFS.prototype.readProjectionFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be a DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readProjectionFromNode(n); - } - } - return null; -}; - - -/** - * @inheritDoc - */ -ol.format.WFS.prototype.readProjectionFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'FeatureCollection', - 'localName should be FeatureCollection'); - - if (node.firstElementChild && - node.firstElementChild.firstElementChild) { - node = node.firstElementChild.firstElementChild; - for (var n = node.firstElementChild; n; n = n.nextElementSibling) { - if (!(n.childNodes.length === 0 || - (n.childNodes.length === 1 && - n.firstChild.nodeType === 3))) { - var objectStack = [{}]; - this.gmlFormat_.readGeometryElement(n, objectStack); - return ol.proj.get(objectStack.pop().srsName); - } - } - } - - return null; -}; - -goog.provide('ol.format.WKT'); - -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.TextFeature'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); - - - -/** - * @classdesc - * Geometry format for reading and writing data in the `WellKnownText` (WKT) - * format. - * - * @constructor - * @extends {ol.format.TextFeature} - * @param {olx.format.WKTOptions=} opt_options Options. - * @api stable - */ -ol.format.WKT = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); - - /** - * Split GeometryCollection into multiple features. - * @type {boolean} - * @private - */ - this.splitCollection_ = options.splitCollection !== undefined ? - options.splitCollection : false; - -}; -goog.inherits(ol.format.WKT, ol.format.TextFeature); - - -/** - * @const - * @type {string} - */ -ol.format.WKT.EMPTY = 'EMPTY'; - - -/** - * @param {ol.geom.Point} geom Point geometry. - * @return {string} Coordinates part of Point as WKT. - * @private - */ -ol.format.WKT.encodePointGeometry_ = function(geom) { - var coordinates = geom.getCoordinates(); - if (coordinates.length === 0) { - return ''; - } - return coordinates[0] + ' ' + coordinates[1]; -}; - - -/** - * @param {ol.geom.MultiPoint} geom MultiPoint geometry. - * @return {string} Coordinates part of MultiPoint as WKT. - * @private - */ -ol.format.WKT.encodeMultiPointGeometry_ = function(geom) { - var array = []; - var components = geom.getPoints(); - for (var i = 0, ii = components.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')'); - } - return array.join(','); -}; - - -/** - * @param {ol.geom.GeometryCollection} geom GeometryCollection geometry. - * @return {string} Coordinates part of GeometryCollection as WKT. - * @private - */ -ol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) { - var array = []; - var geoms = geom.getGeometries(); - for (var i = 0, ii = geoms.length; i < ii; ++i) { - array.push(ol.format.WKT.encode_(geoms[i])); - } - return array.join(','); -}; - - -/** - * @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry. - * @return {string} Coordinates part of LineString as WKT. - * @private - */ -ol.format.WKT.encodeLineStringGeometry_ = function(geom) { - var coordinates = geom.getCoordinates(); - var array = []; - for (var i = 0, ii = coordinates.length; i < ii; ++i) { - array.push(coordinates[i][0] + ' ' + coordinates[i][1]); - } - return array.join(','); -}; - - -/** - * @param {ol.geom.MultiLineString} geom MultiLineString geometry. - * @return {string} Coordinates part of MultiLineString as WKT. - * @private - */ -ol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) { - var array = []; - var components = geom.getLineStrings(); - for (var i = 0, ii = components.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodeLineStringGeometry_( - components[i]) + ')'); - } - return array.join(','); -}; - - -/** - * @param {ol.geom.Polygon} geom Polygon geometry. - * @return {string} Coordinates part of Polygon as WKT. - * @private - */ -ol.format.WKT.encodePolygonGeometry_ = function(geom) { - var array = []; - var rings = geom.getLinearRings(); - for (var i = 0, ii = rings.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodeLineStringGeometry_( - rings[i]) + ')'); - } - return array.join(','); -}; - - -/** - * @param {ol.geom.MultiPolygon} geom MultiPolygon geometry. - * @return {string} Coordinates part of MultiPolygon as WKT. - * @private - */ -ol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) { - var array = []; - var components = geom.getPolygons(); - for (var i = 0, ii = components.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodePolygonGeometry_( - components[i]) + ')'); - } - return array.join(','); -}; - - -/** - * Encode a geometry as WKT. - * @param {ol.geom.Geometry} geom The geometry to encode. - * @return {string} WKT string for the geometry. - * @private - */ -ol.format.WKT.encode_ = function(geom) { - var type = geom.getType(); - var geometryEncoder = ol.format.WKT.GeometryEncoder_[type]; - goog.asserts.assert(geometryEncoder, 'geometryEncoder should be defined'); - var enc = geometryEncoder(geom); - type = type.toUpperCase(); - if (enc.length === 0) { - return type + ' ' + ol.format.WKT.EMPTY; - } - return type + '(' + enc + ')'; -}; - - -/** - * @const - * @type {Object.<string, function(ol.geom.Geometry): string>} - * @private - */ -ol.format.WKT.GeometryEncoder_ = { - 'Point': ol.format.WKT.encodePointGeometry_, - 'LineString': ol.format.WKT.encodeLineStringGeometry_, - 'Polygon': ol.format.WKT.encodePolygonGeometry_, - 'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_, - 'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_, - 'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_, - 'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_ -}; - - -/** - * Parse a WKT string. - * @param {string} wkt WKT string. - * @return {ol.geom.Geometry|ol.geom.GeometryCollection|undefined} - * The geometry created. - * @private - */ -ol.format.WKT.prototype.parse_ = function(wkt) { - var lexer = new ol.format.WKT.Lexer(wkt); - var parser = new ol.format.WKT.Parser(lexer); - return parser.parse(); -}; - - -/** - * Read a feature from a WKT source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.WKT.prototype.readFeature; - - -/** - * @inheritDoc - */ -ol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) { - var geom = this.readGeometryFromText(text, opt_options); - if (geom) { - var feature = new ol.Feature(); - feature.setGeometry(geom); - return feature; - } - return null; -}; - - -/** - * Read all features from a WKT source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.WKT.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) { - var geometries = []; - var geometry = this.readGeometryFromText(text, opt_options); - if (this.splitCollection_ && - geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) { - geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry)) - .getGeometriesArray(); - } else { - geometries = [geometry]; - } - var feature, features = []; - for (var i = 0, ii = geometries.length; i < ii; ++i) { - feature = new ol.Feature(); - feature.setGeometry(geometries[i]); - features.push(feature); - } - return features; -}; - - -/** - * Read a single geometry from a WKT source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api stable - */ -ol.format.WKT.prototype.readGeometry; - - -/** - * @inheritDoc - */ -ol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) { - var geometry = this.parse_(text); - if (geometry) { - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, false, opt_options)); - } else { - return null; - } -}; - - -/** - * Encode a feature as a WKT string. - * - * @function - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} WKT string. - * @api stable - */ -ol.format.WKT.prototype.writeFeature; - - -/** - * @inheritDoc - */ -ol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) { - var geometry = feature.getGeometry(); - if (geometry) { - return this.writeGeometryText(geometry, opt_options); - } - return ''; -}; - - -/** - * Encode an array of features as a WKT string. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} WKT string. - * @api stable - */ -ol.format.WKT.prototype.writeFeatures; - - -/** - * @inheritDoc - */ -ol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) { - if (features.length == 1) { - return this.writeFeatureText(features[0], opt_options); - } - var geometries = []; - for (var i = 0, ii = features.length; i < ii; ++i) { - geometries.push(features[i].getGeometry()); - } - var collection = new ol.geom.GeometryCollection(geometries); - return this.writeGeometryText(collection, opt_options); -}; - - -/** - * Write a single geometry as a WKT string. - * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @return {string} WKT string. - * @api stable - */ -ol.format.WKT.prototype.writeGeometry; - - -/** - * @inheritDoc - */ -ol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) { - return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, true, opt_options))); -}; - - -/** - * @typedef {{type: number, value: (number|string|undefined), position: number}} - */ -ol.format.WKT.Token; - - -/** - * @const - * @enum {number} - */ -ol.format.WKT.TokenType = { - TEXT: 1, - LEFT_PAREN: 2, - RIGHT_PAREN: 3, - NUMBER: 4, - COMMA: 5, - EOF: 6 -}; - - - -/** - * Class to tokenize a WKT string. - * @param {string} wkt WKT string. - * @constructor - * @protected - */ -ol.format.WKT.Lexer = function(wkt) { - - /** - * @type {string} - */ - this.wkt = wkt; - - /** - * @type {number} - * @private - */ - this.index_ = -1; -}; - - -/** - * @param {string} c Character. - * @return {boolean} Whether the character is alphabetic. - * @private - */ -ol.format.WKT.Lexer.prototype.isAlpha_ = function(c) { - return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; -}; - - -/** - * @param {string} c Character. - * @param {boolean=} opt_decimal Whether the string number - * contains a dot, i.e. is a decimal number. - * @return {boolean} Whether the character is numeric. - * @private - */ -ol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) { - var decimal = opt_decimal !== undefined ? opt_decimal : false; - return c >= '0' && c <= '9' || c == '.' && !decimal; -}; - - -/** - * @param {string} c Character. - * @return {boolean} Whether the character is whitespace. - * @private - */ -ol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) { - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; -}; - - -/** - * @return {string} Next string character. - * @private - */ -ol.format.WKT.Lexer.prototype.nextChar_ = function() { - return this.wkt.charAt(++this.index_); -}; - - -/** - * Fetch and return the next token. - * @return {!ol.format.WKT.Token} Next string token. - */ -ol.format.WKT.Lexer.prototype.nextToken = function() { - var c = this.nextChar_(); - var token = {position: this.index_, value: c}; - - if (c == '(') { - token.type = ol.format.WKT.TokenType.LEFT_PAREN; - } else if (c == ',') { - token.type = ol.format.WKT.TokenType.COMMA; - } else if (c == ')') { - token.type = ol.format.WKT.TokenType.RIGHT_PAREN; - } else if (this.isNumeric_(c) || c == '-') { - token.type = ol.format.WKT.TokenType.NUMBER; - token.value = this.readNumber_(); - } else if (this.isAlpha_(c)) { - token.type = ol.format.WKT.TokenType.TEXT; - token.value = this.readText_(); - } else if (this.isWhiteSpace_(c)) { - return this.nextToken(); - } else if (c === '') { - token.type = ol.format.WKT.TokenType.EOF; - } else { - throw new Error('Unexpected character: ' + c); - } - - return token; -}; - - -/** - * @return {number} Numeric token value. - * @private - */ -ol.format.WKT.Lexer.prototype.readNumber_ = function() { - var c, index = this.index_; - var decimal = false; - var scientificNotation = false; - do { - if (c == '.') { - decimal = true; - } else if (c == 'e' || c == 'E') { - scientificNotation = true; - } - c = this.nextChar_(); - } while ( - this.isNumeric_(c, decimal) || - // if we haven't detected a scientific number before, 'e' or 'E' - // hint that we should continue to read - !scientificNotation && (c == 'e' || c == 'E') || - // once we know that we have a scientific number, both '-' and '+' - // are allowed - scientificNotation && (c == '-' || c == '+') - ); - return parseFloat(this.wkt.substring(index, this.index_--)); -}; - - -/** - * @return {string} String token value. - * @private - */ -ol.format.WKT.Lexer.prototype.readText_ = function() { - var c, index = this.index_; - do { - c = this.nextChar_(); - } while (this.isAlpha_(c)); - return this.wkt.substring(index, this.index_--).toUpperCase(); -}; - - - -/** - * Class to parse the tokens from the WKT string. - * @param {ol.format.WKT.Lexer} lexer - * @constructor - * @protected - */ -ol.format.WKT.Parser = function(lexer) { - - /** - * @type {ol.format.WKT.Lexer} - * @private - */ - this.lexer_ = lexer; - - /** - * @type {ol.format.WKT.Token} - * @private - */ - this.token_; - - /** - * @type {number} - * @private - */ - this.dimension_ = 2; -}; - - -/** - * Fetch the next token form the lexer and replace the active token. - * @private - */ -ol.format.WKT.Parser.prototype.consume_ = function() { - this.token_ = this.lexer_.nextToken(); -}; - - -/** - * If the given type matches the current token, consume it. - * @param {ol.format.WKT.TokenType.<number>} type Token type. - * @return {boolean} Whether the token matches the given type. - */ -ol.format.WKT.Parser.prototype.match = function(type) { - var isMatch = this.token_.type == type; - if (isMatch) { - this.consume_(); - } - return isMatch; -}; - - -/** - * Try to parse the tokens provided by the lexer. - * @return {ol.geom.Geometry|ol.geom.GeometryCollection} The geometry. - */ -ol.format.WKT.Parser.prototype.parse = function() { - this.consume_(); - var geometry = this.parseGeometry_(); - goog.asserts.assert(this.token_.type == ol.format.WKT.TokenType.EOF, - 'token type should be end of file'); - return geometry; -}; - - -/** - * @return {!(ol.geom.Geometry|ol.geom.GeometryCollection)} The geometry. - * @private - */ -ol.format.WKT.Parser.prototype.parseGeometry_ = function() { - var token = this.token_; - if (this.match(ol.format.WKT.TokenType.TEXT)) { - var geomType = token.value; - if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) { - var geometries = this.parseGeometryCollectionText_(); - return new ol.geom.GeometryCollection(geometries); - } else { - var parser = ol.format.WKT.Parser.GeometryParser_[geomType]; - var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType]; - if (!parser || !ctor) { - throw new Error('Invalid geometry type: ' + geomType); - } - var coordinates = parser.call(this); - return new ctor(coordinates); - } - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<ol.geom.Geometry>} A collection of geometries. - * @private - */ -ol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var geometries = []; - do { - geometries.push(this.parseGeometry_()); - } while (this.match(ol.format.WKT.TokenType.COMMA)); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return geometries; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {Array.<number>} All values in a point. - * @private - */ -ol.format.WKT.Parser.prototype.parsePointText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parsePoint_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return null; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<!Array.<number>>} All points in a linestring. - * @private - */ -ol.format.WKT.Parser.prototype.parseLineStringText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parsePointList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<!Array.<number>>} All points in a polygon. - * @private - */ -ol.format.WKT.Parser.prototype.parsePolygonText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parseLineStringTextList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<!Array.<number>>} All points in a multipoint. - * @private - */ -ol.format.WKT.Parser.prototype.parseMultiPointText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates; - if (this.token_.type == ol.format.WKT.TokenType.LEFT_PAREN) { - coordinates = this.parsePointTextList_(); - } else { - coordinates = this.parsePointList_(); - } - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<!Array.<number>>} All linestring points - * in a multilinestring. - * @private - */ -ol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parseLineStringTextList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<!Array.<number>>} All polygon points in a multipolygon. - * @private - */ -ol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parsePolygonTextList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<number>} A point. - * @private - */ -ol.format.WKT.Parser.prototype.parsePoint_ = function() { - var coordinates = []; - for (var i = 0; i < this.dimension_; ++i) { - var token = this.token_; - if (this.match(ol.format.WKT.TokenType.NUMBER)) { - coordinates.push(token.value); - } else { - break; - } - } - if (coordinates.length == this.dimension_) { - return coordinates; - } - throw new Error(this.formatErrorMessage_()); -}; - - -/** - * @return {!Array.<!Array.<number>>} An array of points. - * @private - */ -ol.format.WKT.Parser.prototype.parsePointList_ = function() { - var coordinates = [this.parsePoint_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parsePoint_()); - } - return coordinates; -}; - - -/** - * @return {!Array.<!Array.<number>>} An array of points. - * @private - */ -ol.format.WKT.Parser.prototype.parsePointTextList_ = function() { - var coordinates = [this.parsePointText_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parsePointText_()); - } - return coordinates; -}; - - -/** - * @return {!Array.<!Array.<number>>} An array of points. - * @private - */ -ol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() { - var coordinates = [this.parseLineStringText_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parseLineStringText_()); - } - return coordinates; -}; - - -/** - * @return {!Array.<!Array.<number>>} An array of points. - * @private - */ -ol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() { - var coordinates = [this.parsePolygonText_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parsePolygonText_()); - } - return coordinates; -}; - - -/** - * @return {boolean} Whether the token implies an empty geometry. - * @private - */ -ol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() { - var isEmpty = this.token_.type == ol.format.WKT.TokenType.TEXT && - this.token_.value == ol.format.WKT.EMPTY; - if (isEmpty) { - this.consume_(); - } - return isEmpty; -}; - - -/** - * Create an error message for an unexpected token error. - * @return {string} Error message. - * @private - */ -ol.format.WKT.Parser.prototype.formatErrorMessage_ = function() { - return 'Unexpected `' + this.token_.value + '` at position ' + - this.token_.position + ' in `' + this.lexer_.wkt + '`'; -}; - - -/** - * @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout.<string>=)} - * @private - */ -ol.format.WKT.Parser.GeometryConstructor_ = { - 'POINT': ol.geom.Point, - 'LINESTRING': ol.geom.LineString, - 'POLYGON': ol.geom.Polygon, - 'MULTIPOINT': ol.geom.MultiPoint, - 'MULTILINESTRING': ol.geom.MultiLineString, - 'MULTIPOLYGON': ol.geom.MultiPolygon -}; - - -/** - * @enum {(function(): Array)} - * @private - */ -ol.format.WKT.Parser.GeometryParser_ = { - 'POINT': ol.format.WKT.Parser.prototype.parsePointText_, - 'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_, - 'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_, - 'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_, - 'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_, - 'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_ -}; - -goog.provide('ol.format.WMSCapabilities'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.format.XLink'); -goog.require('ol.format.XML'); -goog.require('ol.format.XSD'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Format for reading WMS capabilities data - * - * @constructor - * @extends {ol.format.XML} - * @api - */ -ol.format.WMSCapabilities = function() { - - goog.base(this); - - /** - * @type {string|undefined} - */ - this.version = undefined; -}; -goog.inherits(ol.format.WMSCapabilities, ol.format.XML); - - -/** - * Read a WMS capabilities document. - * - * @function - * @param {Document|Node|string} source The XML source. - * @return {Object} An object representing the WMS capabilities. - * @api - */ -ol.format.WMSCapabilities.prototype.read; - - -/** - * @param {Document} doc Document. - * @return {Object} WMS Capability object. - */ -ol.format.WMSCapabilities.prototype.readFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFromNode(n); - } - } - return null; -}; - - -/** - * @param {Node} node Node. - * @return {Object} WMS Capability object. - */ -ol.format.WMSCapabilities.prototype.readFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'WMS_Capabilities' || - node.localName == 'WMT_MS_Capabilities', - 'localName should be WMS_Capabilities or WMT_MS_Capabilities'); - this.version = node.getAttribute('version').trim(); - goog.asserts.assertString(this.version, 'this.version should be a string'); - var wmsCapabilityObject = ol.xml.pushParseAndPop({ - 'version': this.version - }, ol.format.WMSCapabilities.PARSERS_, node, []); - return wmsCapabilityObject ? wmsCapabilityObject : null; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Attribution object. - */ -ol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Attribution', - 'localName should be Attribution'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object} Bounding box object. - */ -ol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'BoundingBox', - 'localName should be BoundingBox'); - - var extent = [ - ol.format.XSD.readDecimalString(node.getAttribute('minx')), - ol.format.XSD.readDecimalString(node.getAttribute('miny')), - ol.format.XSD.readDecimalString(node.getAttribute('maxx')), - ol.format.XSD.readDecimalString(node.getAttribute('maxy')) - ]; - - var resolutions = [ - ol.format.XSD.readDecimalString(node.getAttribute('resx')), - ol.format.XSD.readDecimalString(node.getAttribute('resy')) - ]; - - return { - 'crs': node.getAttribute('CRS'), - 'extent': extent, - 'res': resolutions - }; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.Extent|undefined} Bounding box object. - */ -ol.format.WMSCapabilities.readEXGeographicBoundingBox_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'EX_GeographicBoundingBox', - 'localName should be EX_GeographicBoundingBox'); - var geographicBoundingBox = ol.xml.pushParseAndPop( - {}, - ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_, - node, objectStack); - if (!geographicBoundingBox) { - return undefined; - } - var westBoundLongitude = /** @type {number|undefined} */ - (geographicBoundingBox['westBoundLongitude']); - var southBoundLatitude = /** @type {number|undefined} */ - (geographicBoundingBox['southBoundLatitude']); - var eastBoundLongitude = /** @type {number|undefined} */ - (geographicBoundingBox['eastBoundLongitude']); - var northBoundLatitude = /** @type {number|undefined} */ - (geographicBoundingBox['northBoundLatitude']); - if (westBoundLongitude === undefined || southBoundLatitude === undefined || - eastBoundLongitude === undefined || northBoundLatitude === undefined) { - return undefined; - } - return /** @type {ol.Extent} */ ([ - westBoundLongitude, southBoundLatitude, - eastBoundLongitude, northBoundLatitude - ]); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Capability object. - */ -ol.format.WMSCapabilities.readCapability_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Capability', - 'localName should be Capability'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Service object. - */ -ol.format.WMSCapabilities.readService_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Service', - 'localName should be Service'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Contact information object. - */ -ol.format.WMSCapabilities.readContactInformation_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType shpuld be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactInformation', - 'localName should be ContactInformation'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_, - node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Contact person object. - */ -ol.format.WMSCapabilities.readContactPersonPrimary_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactPersonPrimary', - 'localName should be ContactPersonPrimary'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_, - node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Contact address object. - */ -ol.format.WMSCapabilities.readContactAddress_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactAddress', - 'localName should be ContactAddress'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_, - node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<string>|undefined} Format array. - */ -ol.format.WMSCapabilities.readException_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Exception', - 'localName should be Exception'); - return ol.xml.pushParseAndPop( - [], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Layer object. - */ -ol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Layer object. - */ -ol.format.WMSCapabilities.readLayer_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); - var parentLayerObject = /** @type {Object.<string,*>} */ - (objectStack[objectStack.length - 1]); - - var layerObject = /** @type {Object.<string,*>} */ (ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack)); - - if (!layerObject) { - return undefined; - } - var queryable = - ol.format.XSD.readBooleanString(node.getAttribute('queryable')); - if (queryable === undefined) { - queryable = parentLayerObject['queryable']; - } - layerObject['queryable'] = queryable !== undefined ? queryable : false; - - var cascaded = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('cascaded')); - if (cascaded === undefined) { - cascaded = parentLayerObject['cascaded']; - } - layerObject['cascaded'] = cascaded; - - var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque')); - if (opaque === undefined) { - opaque = parentLayerObject['opaque']; - } - layerObject['opaque'] = opaque !== undefined ? opaque : false; - - var noSubsets = - ol.format.XSD.readBooleanString(node.getAttribute('noSubsets')); - if (noSubsets === undefined) { - noSubsets = parentLayerObject['noSubsets']; - } - layerObject['noSubsets'] = noSubsets !== undefined ? noSubsets : false; - - var fixedWidth = - ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth')); - if (!fixedWidth) { - fixedWidth = parentLayerObject['fixedWidth']; - } - layerObject['fixedWidth'] = fixedWidth; - - var fixedHeight = - ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight')); - if (!fixedHeight) { - fixedHeight = parentLayerObject['fixedHeight']; - } - layerObject['fixedHeight'] = fixedHeight; - - // See 7.2.4.8 - var addKeys = ['Style', 'CRS', 'AuthorityURL']; - addKeys.forEach(function(key) { - if (key in parentLayerObject) { - var childValue = goog.object.setIfUndefined(layerObject, key, []); - childValue = childValue.concat(parentLayerObject[key]); - layerObject[key] = childValue; - } - }); - - var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension', - 'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator']; - replaceKeys.forEach(function(key) { - if (!(key in layerObject)) { - var parentValue = parentLayerObject[key]; - layerObject[key] = parentValue; - } - }); - - return layerObject; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object} Dimension object. - */ -ol.format.WMSCapabilities.readDimension_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Dimension', - 'localName should be Dimension'); - var dimensionObject = { - 'name': node.getAttribute('name'), - 'units': node.getAttribute('units'), - 'unitSymbol': node.getAttribute('unitSymbol'), - 'default': node.getAttribute('default'), - 'multipleValues': ol.format.XSD.readBooleanString( - node.getAttribute('multipleValues')), - 'nearestValue': ol.format.XSD.readBooleanString( - node.getAttribute('nearestValue')), - 'current': ol.format.XSD.readBooleanString(node.getAttribute('current')), - 'values': ol.format.XSD.readString(node) - }; - return dimensionObject; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Online resource object. - */ -ol.format.WMSCapabilities.readFormatOnlineresource_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_, - node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Request object. - */ -ol.format.WMSCapabilities.readRequest_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Request', - 'localName should be Request'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} DCP type object. - */ -ol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'DCPType', - 'localName should be DCPType'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} HTTP object. - */ -ol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Operation type object. - */ -ol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Online resource object. - */ -ol.format.WMSCapabilities.readSizedFormatOnlineresource_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var formatOnlineresource = - ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); - if (formatOnlineresource) { - var size = [ - ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')), - ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height')) - ]; - formatOnlineresource['size'] = size; - return formatOnlineresource; - } - return undefined; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Authority URL object. - */ -ol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'AuthorityURL', - 'localName should be AuthorityURL'); - var authorityObject = - ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); - if (authorityObject) { - authorityObject['name'] = node.getAttribute('name'); - return authorityObject; - } - return undefined; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Metadata URL object. - */ -ol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MetadataURL', - 'localName should be MetadataURL'); - var metadataObject = - ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); - if (metadataObject) { - metadataObject['type'] = node.getAttribute('type'); - return metadataObject; - } - return undefined; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Style object. - */ -ol.format.WMSCapabilities.readStyle_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<string>|undefined} Keyword list. - */ -ol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'KeywordList', - 'localName should be KeywordList'); - return ol.xml.pushParseAndPop( - [], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack); -}; - - -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.format.WMSCapabilities.NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/wms' -]; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Service': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readService_), - 'Capability': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readCapability_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Request': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readRequest_), - 'Exception': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readException_), - 'Layer': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readCapabilityLayer_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'KeywordList': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readKeywordList_), - 'OnlineResource': ol.xml.makeObjectPropertySetter( - ol.format.XLink.readHref), - 'ContactInformation': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readContactInformation_), - 'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'AccessConstraints': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'LayerLimit': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MaxWidth': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MaxHeight': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'ContactPersonPrimary': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readContactPersonPrimary_), - 'ContactPosition': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactAddress': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readContactAddress_), - 'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'ContactPerson': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactOrganization': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'StateOrProvince': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'KeywordList': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readKeywordList_), - 'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), - 'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readEXGeographicBoundingBox_), - 'BoundingBox': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readBoundingBox_), - 'Dimension': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readDimension_), - 'Attribution': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readAttribution_), - 'AuthorityURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readAuthorityURL_), - 'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), - 'MetadataURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readMetadataURL_), - 'DataURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'FeatureListURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'Style': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readStyle_), - 'MinScaleDenominator': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'MaxScaleDenominator': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'Layer': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readLayer_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'OnlineResource': ol.xml.makeObjectPropertySetter( - ol.format.XLink.readHref), - 'LogoURL': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readSizedFormatOnlineresource_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ = - ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'westBoundLongitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'eastBoundLongitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'southBoundLatitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'northBoundLatitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'GetCapabilities': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readOperationType_), - 'GetMap': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readOperationType_), - 'GetFeatureInfo': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readOperationType_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), - 'DCPType': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readDCPType_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'HTTP': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readHTTP_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Get': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'Post': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'LegendURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readSizedFormatOnlineresource_), - 'StyleSheetURL': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'StyleURL': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ = - ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'OnlineResource': ol.xml.makeObjectPropertySetter( - ol.format.XLink.readHref) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString) - }); - -goog.provide('ol.format.WMSGetFeatureInfo'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol.format.GML2'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Format for reading WMSGetFeatureInfo format. It uses - * {@link ol.format.GML2} to read features. - * - * @constructor - * @extends {ol.format.XMLFeature} - * @api - */ -ol.format.WMSGetFeatureInfo = function() { - - /** - * @private - * @type {string} - */ - this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver'; - - - /** - * @private - * @type {ol.format.GML2} - */ - this.gmlFormat_ = new ol.format.GML2(); - - goog.base(this); -}; -goog.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature); - - -/** - * @const - * @type {string} - * @private - */ -ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature'; - - -/** - * @const - * @type {string} - * @private - */ -ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer'; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<ol.Feature>} Features. - * @private - */ -ol.format.WMSGetFeatureInfo.prototype.readFeatures_ = - function(node, objectStack) { - - node.namespaceURI = this.featureNS_; - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var localName = ol.xml.getLocalName(node); - /** @type {Array.<ol.Feature>} */ - var features = []; - if (node.childNodes.length === 0) { - return features; - } - if (localName == 'msGMLOutput') { - for (var i = 0, ii = node.childNodes.length; i < ii; i++) { - var layer = node.childNodes[i]; - if (layer.nodeType !== goog.dom.NodeType.ELEMENT) { - continue; - } - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), - 'context should be an Object'); - - goog.asserts.assert(layer.localName.indexOf( - ol.format.WMSGetFeatureInfo.layerIdentifier_) >= 0, - 'localName of layer node should match layerIdentifier'); - - var toRemove = ol.format.WMSGetFeatureInfo.layerIdentifier_; - var featureType = layer.localName.replace(toRemove, '') + - ol.format.WMSGetFeatureInfo.featureIdentifier_; - - context['featureType'] = featureType; - context['featureNS'] = this.featureNS_; - - var parsers = {}; - parsers[featureType] = ol.xml.makeArrayPusher( - this.gmlFormat_.readFeatureElement, this.gmlFormat_); - var parsersNS = ol.xml.makeStructureNS( - [context['featureNS'], null], parsers); - layer.namespaceURI = this.featureNS_; - var layerFeatures = ol.xml.pushParseAndPop( - [], parsersNS, layer, objectStack, this.gmlFormat_); - if (layerFeatures) { - goog.array.extend(features, layerFeatures); - } - } - } - if (localName == 'FeatureCollection') { - var gmlFeatures = ol.xml.pushParseAndPop([], - this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node, - [{}], this.gmlFormat_); - if (gmlFeatures) { - features = gmlFeatures; - } - } - return features; -}; - - -/** - * Read all features from a WMSGetFeatureInfo response. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.WMSGetFeatureInfo.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode = - function(node, opt_options) { - var options = { - 'featureType': this.featureType, - 'featureNS': this.featureNS - }; - if (opt_options) { - goog.object.extend(options, this.getReadOptions(node, opt_options)); - } - return this.readFeatures_(node, [options]); -}; - -goog.provide('ol.format.WMTSCapabilities'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.extent'); -goog.require('ol.format.OWS'); -goog.require('ol.format.XLink'); -goog.require('ol.format.XML'); -goog.require('ol.format.XSD'); -goog.require('ol.xml'); - - - -/** - * @classdesc - * Format for reading WMTS capabilities data. - * - * @constructor - * @extends {ol.format.XML} - * @api - */ -ol.format.WMTSCapabilities = function() { - goog.base(this); - - /** - * @type {ol.format.OWS} - * @private - */ - this.owsParser_ = new ol.format.OWS(); -}; -goog.inherits(ol.format.WMTSCapabilities, ol.format.XML); - - -/** - * Read a WMTS capabilities document. - * - * @function - * @param {Document|Node|string} source The XML source. - * @return {Object} An object representing the WMTS capabilities. - * @api - */ -ol.format.WMTSCapabilities.prototype.read; - - -/** - * @param {Document} doc Document. - * @return {Object} WMTS Capability object. - */ -ol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFromNode(n); - } - } - return null; -}; - - -/** - * @param {Node} node Node. - * @return {Object} WMTS Capability object. - */ -ol.format.WMTSCapabilities.prototype.readFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Capabilities', - 'localName should be Capabilities'); - this.version = node.getAttribute('version').trim(); - goog.asserts.assertString(this.version, 'this.version should be a string'); - var WMTSCapabilityObject = this.owsParser_.readFromNode(node); - if (!WMTSCapabilityObject) { - return null; - } - WMTSCapabilityObject['version'] = this.version; - WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject, - ol.format.WMTSCapabilities.PARSERS_, node, []); - return WMTSCapabilityObject ? WMTSCapabilityObject : null; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Attribution object. - */ -ol.format.WMTSCapabilities.readContents_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Contents', - 'localName should be Contents'); - - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Layers object. - */ -ol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Tile Matrix Set object. - */ -ol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Style object. - */ -ol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) { - var style = ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack); - if (!style) { - return undefined; - } - var isDefault = node.getAttribute('isDefault') === 'true'; - style['isDefault'] = isDefault; - return style; - -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Tile Matrix Set Link object. - */ -ol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node, - objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Dimension object. - */ -ol.format.WMTSCapabilities.readDimensions_ = function(node, objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.DIMENSION_PARSERS_, node, objectStack); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Resource URL object. - */ -ol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) { - var format = node.getAttribute('format'); - var template = node.getAttribute('template'); - var resourceType = node.getAttribute('resourceType'); - var resource = {}; - if (format) { - resource['format'] = format; - } - if (template) { - resource['template'] = template; - } - if (resourceType) { - resource['resourceType'] = resourceType; - } - return resource; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} WGS84 BBox object. - */ -ol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) { - var coordinates = ol.xml.pushParseAndPop([], - ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack); - if (coordinates.length != 2) { - return undefined; - } - return ol.extent.boundingExtent(coordinates); -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Legend object. - */ -ol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) { - var legend = {}; - legend['format'] = node.getAttribute('format'); - legend['href'] = ol.format.XLink.readHref(node); - return legend; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Coordinates object. - */ -ol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) { - var coordinates = ol.format.XSD.readString(node).split(' '); - if (!coordinates || coordinates.length != 2) { - return undefined; - } - var x = +coordinates[0]; - var y = +coordinates[1]; - if (isNaN(x) || isNaN(y)) { - return undefined; - } - return [x, y]; -}; - - -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} TileMatrix object. - */ -ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack); -}; - - -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.format.WMTSCapabilities.NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/wmts/1.0' -]; - - -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/ows/1.1' -]; - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Contents': ol.xml.makeObjectPropertySetter( - ol.format.WMTSCapabilities.readContents_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Layer': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readLayer_), - 'TileMatrixSet': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readTileMatrixSet_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Style': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readStyle_), - 'Format': ol.xml.makeObjectPropertyPusher( - ol.format.XSD.readString), - 'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readTileMatrixSetLink_), - 'Dimension': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readDimensions_), - 'ResourceURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readResourceUrl_) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'WGS84BoundingBox': ol.xml.makeObjectPropertySetter( - ol.format.WMTSCapabilities.readWgs84BoundingBox_), - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'LegendURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readLegendUrl_) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'TileMatrixSet': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.DIMENSION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Default': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Value': ol.xml.makeObjectPropertyPusher( - ol.format.XSD.readString) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'LowerCorner': ol.xml.makeArrayPusher( - ol.format.WMTSCapabilities.readCoordinates_), - 'UpperCorner': ol.xml.makeArrayPusher( - ol.format.WMTSCapabilities.readCoordinates_) - }); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'WellKnownScaleSet': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'TileMatrix': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readTileMatrix_) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'SupportedCRS': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'TopLeftCorner': ol.xml.makeObjectPropertySetter( - ol.format.WMTSCapabilities.readCoordinates_), - 'ScaleDenominator': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'TileWidth': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'TileHeight': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MatrixWidth': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MatrixHeight': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); - -goog.provide('ol.sphere.WGS84'); - -goog.require('ol.Sphere'); - - -/** - * A sphere with radius equal to the semi-major axis of the WGS84 ellipsoid. - * @const - * @type {ol.Sphere} - */ -ol.sphere.WGS84 = new ol.Sphere(6378137); - -// FIXME handle geolocation not supported - -goog.provide('ol.Geolocation'); -goog.provide('ol.GeolocationProperty'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.Coordinate'); -goog.require('ol.Object'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.Polygon'); -goog.require('ol.has'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.sphere.WGS84'); - - -/** - * @enum {string} - */ -ol.GeolocationProperty = { - ACCURACY: 'accuracy', - ACCURACY_GEOMETRY: 'accuracyGeometry', - ALTITUDE: 'altitude', - ALTITUDE_ACCURACY: 'altitudeAccuracy', - HEADING: 'heading', - POSITION: 'position', - PROJECTION: 'projection', - SPEED: 'speed', - TRACKING: 'tracking', - TRACKING_OPTIONS: 'trackingOptions' -}; - - - -/** - * @classdesc - * Helper class for providing HTML5 Geolocation capabilities. - * The [Geolocation API](http://www.w3.org/TR/geolocation-API/) - * is used to locate a user's position. - * - * To get notified of position changes, register a listener for the generic - * `change` event on your instance of `ol.Geolocation`. - * - * Example: - * - * var geolocation = new ol.Geolocation({ - * // take the projection to use from the map's view - * projection: view.getProjection() - * }); - * // listen to changes in position - * geolocation.on('change', function(evt) { - * window.console.log(geolocation.getPosition()); - * }); - * - * @constructor - * @extends {ol.Object} - * @param {olx.GeolocationOptions=} opt_options Options. - * @api stable - */ -ol.Geolocation = function(opt_options) { - - goog.base(this); - - var options = opt_options || {}; - - /** - * The unprojected (EPSG:4326) device position. - * @private - * @type {ol.Coordinate} - */ - this.position_ = null; - - /** - * @private - * @type {ol.TransformFunction} - */ - this.transform_ = ol.proj.identityTransform; - - /** - * @private - * @type {number|undefined} - */ - this.watchId_ = undefined; - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION), - this.handleProjectionChanged_, false, this); - goog.events.listen( - this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING), - this.handleTrackingChanged_, false, this); - - if (options.projection !== undefined) { - this.setProjection(ol.proj.get(options.projection)); - } - if (options.trackingOptions !== undefined) { - this.setTrackingOptions(options.trackingOptions); - } - - this.setTracking(options.tracking !== undefined ? options.tracking : false); - -}; -goog.inherits(ol.Geolocation, ol.Object); - - -/** - * @inheritDoc - */ -ol.Geolocation.prototype.disposeInternal = function() { - this.setTracking(false); - goog.base(this, 'disposeInternal'); -}; - - -/** - * @private - */ -ol.Geolocation.prototype.handleProjectionChanged_ = function() { - var projection = this.getProjection(); - if (projection) { - this.transform_ = ol.proj.getTransformFromProjections( - ol.proj.get('EPSG:4326'), projection); - if (this.position_) { - this.set( - ol.GeolocationProperty.POSITION, this.transform_(this.position_)); - } - } -}; - - -/** - * @private - */ -ol.Geolocation.prototype.handleTrackingChanged_ = function() { - if (ol.has.GEOLOCATION) { - var tracking = this.getTracking(); - if (tracking && this.watchId_ === undefined) { - this.watchId_ = goog.global.navigator.geolocation.watchPosition( - goog.bind(this.positionChange_, this), - goog.bind(this.positionError_, this), - this.getTrackingOptions()); - } else if (!tracking && this.watchId_ !== undefined) { - goog.global.navigator.geolocation.clearWatch(this.watchId_); - this.watchId_ = undefined; - } - } -}; - - -/** - * @private - * @param {GeolocationPosition} position position event. - */ -ol.Geolocation.prototype.positionChange_ = function(position) { - var coords = position.coords; - this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy); - this.set(ol.GeolocationProperty.ALTITUDE, - coords.altitude === null ? undefined : coords.altitude); - this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY, - coords.altitudeAccuracy === null ? - undefined : coords.altitudeAccuracy); - this.set(ol.GeolocationProperty.HEADING, coords.heading === null ? - undefined : ol.math.toRadians(coords.heading)); - if (!this.position_) { - this.position_ = [coords.longitude, coords.latitude]; - } else { - this.position_[0] = coords.longitude; - this.position_[1] = coords.latitude; - } - var projectedPosition = this.transform_(this.position_); - this.set(ol.GeolocationProperty.POSITION, projectedPosition); - this.set(ol.GeolocationProperty.SPEED, - coords.speed === null ? undefined : coords.speed); - var geometry = ol.geom.Polygon.circular( - ol.sphere.WGS84, this.position_, coords.accuracy); - geometry.applyTransform(this.transform_); - this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry); - this.changed(); -}; - - -/** - * @private - * @param {GeolocationPositionError} error error object. - */ -ol.Geolocation.prototype.positionError_ = function(error) { - error.type = goog.events.EventType.ERROR; - this.setTracking(false); - this.dispatchEvent(error); -}; - - -/** - * Get the accuracy of the position in meters. - * @return {number|undefined} The accuracy of the position measurement in - * meters. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getAccuracy = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ACCURACY)); -}; - - -/** - * Get a geometry of the position accuracy. - * @return {?ol.geom.Geometry} A geometry of the position accuracy. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getAccuracyGeometry = function() { - return /** @type {?ol.geom.Geometry} */ ( - this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null); -}; - - -/** - * Get the altitude associated with the position. - * @return {number|undefined} The altitude of the position in meters above mean - * sea level. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getAltitude = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ALTITUDE)); -}; - - -/** - * Get the altitude accuracy of the position. - * @return {number|undefined} The accuracy of the altitude measurement in - * meters. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getAltitudeAccuracy = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY)); -}; - - -/** - * Get the heading as radians clockwise from North. - * @return {number|undefined} The heading of the device in radians from north. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getHeading = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.HEADING)); -}; - - -/** - * Get the position of the device. - * @return {ol.Coordinate|undefined} The current position of the device reported - * in the current projection. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getPosition = function() { - return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.GeolocationProperty.POSITION)); -}; - - -/** - * Get the projection associated with the position. - * @return {ol.proj.Projection|undefined} The projection the position is - * reported in. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getProjection = function() { - return /** @type {ol.proj.Projection|undefined} */ ( - this.get(ol.GeolocationProperty.PROJECTION)); -}; - - -/** - * Get the speed in meters per second. - * @return {number|undefined} The instantaneous speed of the device in meters - * per second. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getSpeed = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.SPEED)); -}; - - -/** - * Determine if the device location is being tracked. - * @return {boolean} The device location is being tracked. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getTracking = function() { - return /** @type {boolean} */ ( - this.get(ol.GeolocationProperty.TRACKING)); -}; - - -/** - * Get the tracking options. - * @see http://www.w3.org/TR/geolocation-API/#position-options - * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by - * the [HTML5 Geolocation spec - * ](http://www.w3.org/TR/geolocation-API/#position_options_interface). - * @observable - * @api stable - */ -ol.Geolocation.prototype.getTrackingOptions = function() { - return /** @type {GeolocationPositionOptions|undefined} */ ( - this.get(ol.GeolocationProperty.TRACKING_OPTIONS)); -}; - - -/** - * Set the projection to use for transforming the coordinates. - * @param {ol.proj.Projection} projection The projection the position is - * reported in. - * @observable - * @api stable - */ -ol.Geolocation.prototype.setProjection = function(projection) { - this.set(ol.GeolocationProperty.PROJECTION, projection); -}; - - -/** - * Enable or disable tracking. - * @param {boolean} tracking Enable tracking. - * @observable - * @api stable - */ -ol.Geolocation.prototype.setTracking = function(tracking) { - this.set(ol.GeolocationProperty.TRACKING, tracking); -}; - - -/** - * Set the tracking options. - * @see http://www.w3.org/TR/geolocation-API/#position-options - * @param {GeolocationPositionOptions} options PositionOptions as defined by the - * [HTML5 Geolocation spec - * ](http://www.w3.org/TR/geolocation-API/#position_options_interface). - * @observable - * @api stable - */ -ol.Geolocation.prototype.setTrackingOptions = function(options) { - this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options); -}; - -goog.provide('ol.geom.Circle'); - -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Circle geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {ol.Coordinate} center Center. - * @param {number=} opt_radius Radius. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api - */ -ol.geom.Circle = function(center, opt_radius, opt_layout) { - goog.base(this); - var radius = opt_radius ? opt_radius : 0; - this.setCenterAndRadius(center, radius, opt_layout); -}; -goog.inherits(ol.geom.Circle, ol.geom.SimpleGeometry); - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.Circle} Clone. - * @api - */ -ol.geom.Circle.prototype.clone = function() { - var circle = new ol.geom.Circle(null); - circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return circle; -}; - - -/** - * @inheritDoc - */ -ol.geom.Circle.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - var flatCoordinates = this.flatCoordinates; - var dx = x - flatCoordinates[0]; - var dy = y - flatCoordinates[1]; - var squaredDistance = dx * dx + dy * dy; - if (squaredDistance < minSquaredDistance) { - var i; - if (squaredDistance === 0) { - for (i = 0; i < this.stride; ++i) { - closestPoint[i] = flatCoordinates[i]; - } - } else { - var delta = this.getRadius() / Math.sqrt(squaredDistance); - closestPoint[0] = flatCoordinates[0] + delta * dx; - closestPoint[1] = flatCoordinates[1] + delta * dy; - for (i = 2; i < this.stride; ++i) { - closestPoint[i] = flatCoordinates[i]; - } - } - closestPoint.length = this.stride; - return squaredDistance; - } else { - return minSquaredDistance; - } -}; - - -/** - * @inheritDoc - */ -ol.geom.Circle.prototype.containsXY = function(x, y) { - var flatCoordinates = this.flatCoordinates; - var dx = x - flatCoordinates[0]; - var dy = y - flatCoordinates[1]; - return dx * dx + dy * dy <= this.getRadiusSquared_(); -}; - - -/** - * Return the center of the circle as {@link ol.Coordinate coordinate}. - * @return {ol.Coordinate} Center. - * @api - */ -ol.geom.Circle.prototype.getCenter = function() { - return this.flatCoordinates.slice(0, this.stride); -}; - - -/** - * @inheritDoc - */ -ol.geom.Circle.prototype.computeExtent = function(extent) { - var flatCoordinates = this.flatCoordinates; - var radius = flatCoordinates[this.stride] - flatCoordinates[0]; - return ol.extent.createOrUpdate( - flatCoordinates[0] - radius, flatCoordinates[1] - radius, - flatCoordinates[0] + radius, flatCoordinates[1] + radius, - extent); -}; - - -/** - * Return the radius of the circle. - * @return {number} Radius. - * @api - */ -ol.geom.Circle.prototype.getRadius = function() { - return Math.sqrt(this.getRadiusSquared_()); -}; - - -/** - * @private - * @return {number} Radius squared. - */ -ol.geom.Circle.prototype.getRadiusSquared_ = function() { - var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0]; - var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1]; - return dx * dx + dy * dy; -}; - - -/** - * @inheritDoc - * @api - */ -ol.geom.Circle.prototype.getType = function() { - return ol.geom.GeometryType.CIRCLE; -}; - - -/** - * @inheritDoc - * @api stable - */ -ol.geom.Circle.prototype.intersectsExtent = function(extent) { - var circleExtent = this.getExtent(); - if (ol.extent.intersects(extent, circleExtent)) { - var center = this.getCenter(); - - if (extent[0] <= center[0] && extent[2] >= center[0]) { - return true; - } - if (extent[1] <= center[1] && extent[3] >= center[1]) { - return true; - } - - return ol.extent.forEachCorner(extent, this.containsCoordinate, this); - } - return false; - -}; - - -/** - * Set the center of the circle as {@link ol.Coordinate coordinate}. - * @param {ol.Coordinate} center Center. - * @api - */ -ol.geom.Circle.prototype.setCenter = function(center) { - var stride = this.stride; - goog.asserts.assert(center.length == stride, - 'center array length should match stride'); - var radius = this.flatCoordinates[stride] - this.flatCoordinates[0]; - var flatCoordinates = center.slice(); - flatCoordinates[stride] = flatCoordinates[0] + radius; - var i; - for (i = 1; i < stride; ++i) { - flatCoordinates[stride + i] = center[i]; - } - this.setFlatCoordinates(this.layout, flatCoordinates); -}; - - -/** - * Set the center (as {@link ol.Coordinate coordinate}) and the radius (as - * number) of the circle. - * @param {ol.Coordinate} center Center. - * @param {number} radius Radius. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api - */ -ol.geom.Circle.prototype.setCenterAndRadius = - function(center, radius, opt_layout) { - if (!center) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, center, 0); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - /** @type {Array.<number>} */ - var flatCoordinates = this.flatCoordinates; - var offset = ol.geom.flat.deflate.coordinate( - flatCoordinates, 0, center, this.stride); - flatCoordinates[offset++] = flatCoordinates[0] + radius; - var i, ii; - for (i = 1, ii = this.stride; i < ii; ++i) { - flatCoordinates[offset++] = flatCoordinates[i]; - } - flatCoordinates.length = offset; - this.changed(); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - */ -ol.geom.Circle.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; - - -/** - * Set the radius of the circle. The radius is in the units of the projection. - * @param {number} radius Radius. - * @api - */ -ol.geom.Circle.prototype.setRadius = function(radius) { - goog.asserts.assert(this.flatCoordinates, - 'truthy this.flatCoordinates expected'); - this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius; - this.changed(); -}; - - -/** - * Transform each coordinate of the circle from one coordinate reference system - * to another. The geometry is modified in place. - * If you do not want the geometry modified in place, first clone() it and - * then use this function on the clone. - * - * Internally a circle is currently represented by two points: the center of - * the circle `[cx, cy]`, and the point to the right of the circle - * `[cx + r, cy]`. This `transform` function just transforms these two points. - * So the resulting geometry is also a circle, and that circle does not - * correspond to the shape that would be obtained by transforming every point - * of the original circle. - * - * @param {ol.proj.ProjectionLike} source The current projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @param {ol.proj.ProjectionLike} destination The desired projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @return {ol.geom.Circle} This geometry. Note that original geometry is - * modified in place. - * @function - * @api stable - */ -ol.geom.Circle.prototype.transform; - -goog.provide('ol.geom.flat.geodesic'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.TransformFunction'); -goog.require('ol.math'); -goog.require('ol.proj'); - - -/** - * @private - * @param {function(number): ol.Coordinate} interpolate Interpolate function. - * @param {ol.TransformFunction} transform Transform from longitude/latitude to - * projected coordinates. - * @param {number} squaredTolerance Squared tolerance. - * @return {Array.<number>} Flat coordinates. - */ -ol.geom.flat.geodesic.line_ = - function(interpolate, transform, squaredTolerance) { - // FIXME reduce garbage generation - // FIXME optimize stack operations - - /** @type {Array.<number>} */ - var flatCoordinates = []; - - var geoA = interpolate(0); - var geoB = interpolate(1); - - var a = transform(geoA); - var b = transform(geoB); - - /** @type {Array.<ol.Coordinate>} */ - var geoStack = [geoB, geoA]; - /** @type {Array.<ol.Coordinate>} */ - var stack = [b, a]; - /** @type {Array.<number>} */ - var fractionStack = [1, 0]; - - /** @type {Object.<string, boolean>} */ - var fractions = {}; - - var maxIterations = 1e5; - var geoM, m, fracA, fracB, fracM, key; - - while (--maxIterations > 0 && fractionStack.length > 0) { - // Pop the a coordinate off the stack - fracA = fractionStack.pop(); - geoA = geoStack.pop(); - a = stack.pop(); - // Add the a coordinate if it has not been added yet - key = fracA.toString(); - if (!goog.object.containsKey(fractions, key)) { - flatCoordinates.push(a[0], a[1]); - fractions[key] = true; - } - // Pop the b coordinate off the stack - fracB = fractionStack.pop(); - geoB = geoStack.pop(); - b = stack.pop(); - // Find the m point between the a and b coordinates - fracM = (fracA + fracB) / 2; - geoM = interpolate(fracM); - m = transform(geoM); - if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1], - b[0], b[1]) < squaredTolerance) { - // If the m point is sufficiently close to the straight line, then we - // discard it. Just use the b coordinate and move on to the next line - // segment. - flatCoordinates.push(b[0], b[1]); - key = fracB.toString(); - goog.asserts.assert(!goog.object.containsKey(fractions, key), - 'fractions object should contain key : ' + key); - fractions[key] = true; - } else { - // Otherwise, we need to subdivide the current line segment. Split it - // into two and push the two line segments onto the stack. - fractionStack.push(fracB, fracM, fracM, fracA); - stack.push(b, m, m, a); - geoStack.push(geoB, geoM, geoM, geoA); - } - } - goog.asserts.assert(maxIterations > 0, - 'maxIterations should be more than 0'); - - return flatCoordinates; -}; - - -/** -* Generate a great-circle arcs between two lat/lon points. -* @param {number} lon1 Longitude 1 in degrees. -* @param {number} lat1 Latitude 1 in degrees. -* @param {number} lon2 Longitude 2 in degrees. -* @param {number} lat2 Latitude 2 in degrees. - * @param {ol.proj.Projection} projection Projection. -* @param {number} squaredTolerance Squared tolerance. -* @return {Array.<number>} Flat coordinates. -*/ -ol.geom.flat.geodesic.greatCircleArc = function( - lon1, lat1, lon2, lat2, projection, squaredTolerance) { - - var geoProjection = ol.proj.get('EPSG:4326'); - - var cosLat1 = Math.cos(ol.math.toRadians(lat1)); - var sinLat1 = Math.sin(ol.math.toRadians(lat1)); - var cosLat2 = Math.cos(ol.math.toRadians(lat2)); - var sinLat2 = Math.sin(ol.math.toRadians(lat2)); - var cosDeltaLon = Math.cos(ol.math.toRadians(lon2 - lon1)); - var sinDeltaLon = Math.sin(ol.math.toRadians(lon2 - lon1)); - var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon; - - return ol.geom.flat.geodesic.line_( - /** - * @param {number} frac Fraction. - * @return {ol.Coordinate} Coordinate. - */ - function(frac) { - if (1 <= d) { - return [lon2, lat2]; - } - var D = frac * Math.acos(d); - var cosD = Math.cos(D); - var sinD = Math.sin(D); - var y = sinDeltaLon * cosLat2; - var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon; - var theta = Math.atan2(y, x); - var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta)); - var lon = ol.math.toRadians(lon1) + - Math.atan2(Math.sin(theta) * sinD * cosLat1, - cosD - sinLat1 * Math.sin(lat)); - return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)]; - }, ol.proj.getTransform(geoProjection, projection), squaredTolerance); -}; - - -/** - * Generate a meridian (line at constant longitude). - * @param {number} lon Longitude. - * @param {number} lat1 Latitude 1. - * @param {number} lat2 Latitude 2. - * @param {ol.proj.Projection} projection Projection. - * @param {number} squaredTolerance Squared tolerance. - * @return {Array.<number>} Flat coordinates. - */ -ol.geom.flat.geodesic.meridian = - function(lon, lat1, lat2, projection, squaredTolerance) { - var epsg4326Projection = ol.proj.get('EPSG:4326'); - return ol.geom.flat.geodesic.line_( - /** - * @param {number} frac Fraction. - * @return {ol.Coordinate} Coordinate. - */ - function(frac) { - return [lon, lat1 + ((lat2 - lat1) * frac)]; - }, - ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance); -}; - - -/** - * Generate a parallel (line at constant latitude). - * @param {number} lat Latitude. - * @param {number} lon1 Longitude 1. - * @param {number} lon2 Longitude 2. - * @param {ol.proj.Projection} projection Projection. - * @param {number} squaredTolerance Squared tolerance. - * @return {Array.<number>} Flat coordinates. - */ -ol.geom.flat.geodesic.parallel = - function(lat, lon1, lon2, projection, squaredTolerance) { - var epsg4326Projection = ol.proj.get('EPSG:4326'); - return ol.geom.flat.geodesic.line_( - /** - * @param {number} frac Fraction. - * @return {ol.Coordinate} Coordinate. - */ - function(frac) { - return [lon1 + ((lon2 - lon1) * frac), lat]; - }, - ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance); -}; - -goog.provide('ol.Graticule'); - -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.flat.geodesic'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.render.EventType'); -goog.require('ol.style.Stroke'); - - - -/** - * Render a grid for a coordinate system on a map. - * @constructor - * @param {olx.GraticuleOptions=} opt_options Options. - * @api - */ -ol.Graticule = function(opt_options) { - - var options = opt_options || {}; - - /** - * @type {ol.Map} - * @private - */ - this.map_ = null; - - /** - * @type {ol.proj.Projection} - * @private - */ - this.projection_ = null; - - /** - * @type {number} - * @private - */ - this.maxLat_ = Infinity; - - /** - * @type {number} - * @private - */ - this.maxLon_ = Infinity; - - /** - * @type {number} - * @private - */ - this.minLat_ = -Infinity; - - /** - * @type {number} - * @private - */ - this.minLon_ = -Infinity; - - /** - * @type {number} - * @private - */ - this.maxLatP_ = Infinity; - - /** - * @type {number} - * @private - */ - this.maxLonP_ = Infinity; - - /** - * @type {number} - * @private - */ - this.minLatP_ = -Infinity; - - /** - * @type {number} - * @private - */ - this.minLonP_ = -Infinity; - - /** - * @type {number} - * @private - */ - this.targetSize_ = options.targetSize !== undefined ? - options.targetSize : 100; - - /** - * @type {number} - * @private - */ - this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100; - goog.asserts.assert(this.maxLines_ > 0, - 'this.maxLines_ should be more than 0'); - - /** - * @type {Array.<ol.geom.LineString>} - * @private - */ - this.meridians_ = []; - - /** - * @type {Array.<ol.geom.LineString>} - * @private - */ - this.parallels_ = []; - - /** - * @type {ol.style.Stroke} - * @private - */ - this.strokeStyle_ = options.strokeStyle !== undefined ? - options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_; - - /** - * @type {ol.TransformFunction|undefined} - * @private - */ - this.fromLonLatTransform_ = undefined; - - /** - * @type {ol.TransformFunction|undefined} - * @private - */ - this.toLonLatTransform_ = undefined; - - /** - * @type {ol.Coordinate} - * @private - */ - this.projectionCenterLonLat_ = null; - - this.setMap(options.map !== undefined ? options.map : null); -}; - - -/** - * @type {ol.style.Stroke} - * @private - * @const - */ -ol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({ - color: 'rgba(0,0,0,0.2)' -}); - - -/** - * TODO can be configurable - * @type {Array.<number>} - * @private - */ -ol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, - 0.01, 0.005, 0.002, 0.001]; - - -/** - * @param {number} lon Longitude. - * @param {number} minLat Minimal latitude. - * @param {number} maxLat Maximal latitude. - * @param {number} squaredTolerance Squared tolerance. - * @param {ol.Extent} extent Extent. - * @param {number} index Index. - * @return {number} Index. - * @private - */ -ol.Graticule.prototype.addMeridian_ = - function(lon, minLat, maxLat, squaredTolerance, extent, index) { - var lineString = this.getMeridian_(lon, minLat, maxLat, - squaredTolerance, index); - if (ol.extent.intersects(lineString.getExtent(), extent)) { - this.meridians_[index++] = lineString; - } - return index; -}; - - -/** - * @param {number} lat Latitude. - * @param {number} minLon Minimal longitude. - * @param {number} maxLon Maximal longitude. - * @param {number} squaredTolerance Squared tolerance. - * @param {ol.Extent} extent Extent. - * @param {number} index Index. - * @return {number} Index. - * @private - */ -ol.Graticule.prototype.addParallel_ = - function(lat, minLon, maxLon, squaredTolerance, extent, index) { - var lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, - index); - if (ol.extent.intersects(lineString.getExtent(), extent)) { - this.parallels_[index++] = lineString; - } - return index; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} squaredTolerance Squared tolerance. - * @private - */ -ol.Graticule.prototype.createGraticule_ = - function(extent, center, resolution, squaredTolerance) { - - var interval = this.getInterval_(resolution); - if (interval == -1) { - this.meridians_.length = this.parallels_.length = 0; - return; - } - - var centerLonLat = this.toLonLatTransform_(center); - var centerLon = centerLonLat[0]; - var centerLat = centerLonLat[1]; - var maxLines = this.maxLines_; - var cnt, idx, lat, lon; - - var validExtent = [ - Math.max(extent[0], this.minLonP_), - Math.max(extent[1], this.minLatP_), - Math.min(extent[2], this.maxLonP_), - Math.min(extent[3], this.maxLatP_) - ]; - - validExtent = ol.proj.transformExtent(validExtent, this.projection_, - 'EPSG:4326'); - var maxLat = validExtent[3]; - var maxLon = validExtent[2]; - var minLat = validExtent[1]; - var minLon = validExtent[0]; - - // Create meridians - - centerLon = Math.floor(centerLon / interval) * interval; - lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_); - - idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0); - - cnt = 0; - while (lon != this.minLon_ && cnt++ < maxLines) { - lon = Math.max(lon - interval, this.minLon_); - idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx); - } - - lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_); - - cnt = 0; - while (lon != this.maxLon_ && cnt++ < maxLines) { - lon = Math.min(lon + interval, this.maxLon_); - idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx); - } - - this.meridians_.length = idx; - - // Create parallels - - centerLat = Math.floor(centerLat / interval) * interval; - lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_); - - idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0); - - cnt = 0; - while (lat != this.minLat_ && cnt++ < maxLines) { - lat = Math.max(lat - interval, this.minLat_); - idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx); - } - - lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_); - - cnt = 0; - while (lat != this.maxLat_ && cnt++ < maxLines) { - lat = Math.min(lat + interval, this.maxLat_); - idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx); - } - - this.parallels_.length = idx; - -}; - - -/** - * @param {number} resolution Resolution. - * @return {number} The interval in degrees. - * @private - */ -ol.Graticule.prototype.getInterval_ = function(resolution) { - var centerLon = this.projectionCenterLonLat_[0]; - var centerLat = this.projectionCenterLonLat_[1]; - var interval = -1; - var i, ii, delta, dist; - var target = Math.pow(this.targetSize_ * resolution, 2); - /** @type {Array.<number>} **/ - var p1 = []; - /** @type {Array.<number>} **/ - var p2 = []; - for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) { - delta = ol.Graticule.intervals_[i] / 2; - p1[0] = centerLon - delta; - p1[1] = centerLat - delta; - p2[0] = centerLon + delta; - p2[1] = centerLat + delta; - this.fromLonLatTransform_(p1, p1); - this.fromLonLatTransform_(p2, p2); - dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2); - if (dist <= target) { - break; - } - interval = ol.Graticule.intervals_[i]; - } - return interval; -}; - - -/** - * Get the map associated with this graticule. - * @return {ol.Map} The map. - * @api - */ -ol.Graticule.prototype.getMap = function() { - return this.map_; -}; - - -/** - * @param {number} lon Longitude. - * @param {number} minLat Minimal latitude. - * @param {number} maxLat Maximal latitude. - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.LineString} The meridian line string. - * @param {number} index Index. - * @private - */ -ol.Graticule.prototype.getMeridian_ = function(lon, minLat, maxLat, - squaredTolerance, index) { - goog.asserts.assert(lon >= this.minLon_, - 'lon should be larger than or equal to this.minLon_'); - goog.asserts.assert(lon <= this.maxLon_, - 'lon should be smaller than or equal to this.maxLon_'); - var flatCoordinates = ol.geom.flat.geodesic.meridian(lon, - minLat, maxLat, this.projection_, squaredTolerance); - goog.asserts.assert(flatCoordinates.length > 0, - 'flatCoordinates cannot be empty'); - var lineString = this.meridians_[index] !== undefined ? - this.meridians_[index] : new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); - return lineString; -}; - - -/** - * Get the list of meridians. Meridians are lines of equal longitude. - * @return {Array.<ol.geom.LineString>} The meridians. - * @api - */ -ol.Graticule.prototype.getMeridians = function() { - return this.meridians_; -}; - - -/** - * @param {number} lat Latitude. - * @param {number} minLon Minimal longitude. - * @param {number} maxLon Maximal longitude. - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.LineString} The parallel line string. - * @param {number} index Index. - * @private - */ -ol.Graticule.prototype.getParallel_ = function(lat, minLon, maxLon, - squaredTolerance, index) { - goog.asserts.assert(lat >= this.minLat_, - 'lat should be larger than or equal to this.minLat_'); - goog.asserts.assert(lat <= this.maxLat_, - 'lat should be smaller than or equal to this.maxLat_'); - var flatCoordinates = ol.geom.flat.geodesic.parallel(lat, - this.minLon_, this.maxLon_, this.projection_, squaredTolerance); - goog.asserts.assert(flatCoordinates.length > 0, - 'flatCoordinates cannot be empty'); - var lineString = this.parallels_[index] !== undefined ? - this.parallels_[index] : new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); - return lineString; -}; - - -/** - * Get the list of parallels. Pallels are lines of equal latitude. - * @return {Array.<ol.geom.LineString>} The parallels. - * @api - */ -ol.Graticule.prototype.getParallels = function() { - return this.parallels_; -}; - - -/** - * @param {ol.render.Event} e Event. - * @private - */ -ol.Graticule.prototype.handlePostCompose_ = function(e) { - var vectorContext = e.vectorContext; - var frameState = e.frameState; - var extent = frameState.extent; - var viewState = frameState.viewState; - var center = viewState.center; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var squaredTolerance = - resolution * resolution / (4 * pixelRatio * pixelRatio); - - var updateProjectionInfo = !this.projection_ || - !ol.proj.equivalent(this.projection_, projection); - - if (updateProjectionInfo) { - this.updateProjectionInfo_(projection); - } - - //Fix the extent if wrapped. - //(note: this is the same extent as vectorContext.extent_) - var offsetX = 0; - if (projection.canWrapX()) { - var projectionExtent = projection.getExtent(); - var worldWidth = ol.extent.getWidth(projectionExtent); - var x = frameState.focus[0]; - if (x < projectionExtent[0] || x > projectionExtent[2]) { - var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth); - offsetX = worldWidth * worldsAway; - extent = [ - extent[0] + offsetX, extent[1], - extent[2] + offsetX, extent[3] - ]; - } - } - - this.createGraticule_(extent, center, resolution, squaredTolerance); - - // Draw the lines - vectorContext.setFillStrokeStyle(null, this.strokeStyle_); - var i, l, line; - for (i = 0, l = this.meridians_.length; i < l; ++i) { - line = this.meridians_[i]; - vectorContext.drawLineStringGeometry(line, null); - } - for (i = 0, l = this.parallels_.length; i < l; ++i) { - line = this.parallels_[i]; - vectorContext.drawLineStringGeometry(line, null); - } -}; - - -/** - * @param {ol.proj.Projection} projection Projection. - * @private - */ -ol.Graticule.prototype.updateProjectionInfo_ = function(projection) { - goog.asserts.assert(projection, 'projection cannot be null'); - - var epsg4326Projection = ol.proj.get('EPSG:4326'); - - var extent = projection.getExtent(); - var worldExtent = projection.getWorldExtent(); - var worldExtentP = ol.proj.transformExtent(worldExtent, - epsg4326Projection, projection); - - var maxLat = worldExtent[3]; - var maxLon = worldExtent[2]; - var minLat = worldExtent[1]; - var minLon = worldExtent[0]; - - var maxLatP = worldExtentP[3]; - var maxLonP = worldExtentP[2]; - var minLatP = worldExtentP[1]; - var minLonP = worldExtentP[0]; - - goog.asserts.assert(extent, 'extent cannot be null'); - goog.asserts.assert(maxLat !== undefined, 'maxLat should be defined'); - goog.asserts.assert(maxLon !== undefined, 'maxLon should be defined'); - goog.asserts.assert(minLat !== undefined, 'minLat should be defined'); - goog.asserts.assert(minLon !== undefined, 'minLon should be defined'); - - goog.asserts.assert(maxLatP !== undefined, - 'projected maxLat should be defined'); - goog.asserts.assert(maxLonP !== undefined, - 'projected maxLon should be defined'); - goog.asserts.assert(minLatP !== undefined, - 'projected minLat should be defined'); - goog.asserts.assert(minLonP !== undefined, - 'projected minLon should be defined'); - - this.maxLat_ = maxLat; - this.maxLon_ = maxLon; - this.minLat_ = minLat; - this.minLon_ = minLon; - - this.maxLatP_ = maxLatP; - this.maxLonP_ = maxLonP; - this.minLatP_ = minLatP; - this.minLonP_ = minLonP; - - - this.fromLonLatTransform_ = ol.proj.getTransform( - epsg4326Projection, projection); - - this.toLonLatTransform_ = ol.proj.getTransform( - projection, epsg4326Projection); - - this.projectionCenterLonLat_ = this.toLonLatTransform_( - ol.extent.getCenter(extent)); - - this.projection_ = projection; -}; - - -/** - * Set the map for this graticule. The graticule will be rendered on the - * provided map. - * @param {ol.Map} map Map. - * @api - */ -ol.Graticule.prototype.setMap = function(map) { - if (this.map_) { - this.map_.un(ol.render.EventType.POSTCOMPOSE, - this.handlePostCompose_, this); - this.map_.render(); - } - if (map) { - map.on(ol.render.EventType.POSTCOMPOSE, - this.handlePostCompose_, this); - map.render(); - } - this.map_ = map; -}; - -goog.provide('ol.Image'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.ImageBase'); -goog.require('ol.ImageState'); -goog.require('ol.extent'); - - - -/** - * @constructor - * @extends {ol.ImageBase} - * @param {ol.Extent} extent Extent. - * @param {number|undefined} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {Array.<ol.Attribution>} attributions Attributions. - * @param {string} src Image source URI. - * @param {?string} crossOrigin Cross origin. - * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. - */ -ol.Image = function(extent, resolution, pixelRatio, attributions, src, - crossOrigin, imageLoadFunction) { - - goog.base(this, extent, resolution, pixelRatio, ol.ImageState.IDLE, - attributions); - - /** - * @private - * @type {string} - */ - this.src_ = src; - - /** - * @private - * @type {HTMLCanvasElement|Image|HTMLVideoElement} - */ - this.image_ = new Image(); - if (crossOrigin !== null) { - this.image_.crossOrigin = crossOrigin; - } - - /** - * @private - * @type {Object.<number, (HTMLCanvasElement|Image|HTMLVideoElement)>} - */ - this.imageByContext_ = {}; - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.imageListenerKeys_ = null; - - /** - * @protected - * @type {ol.ImageState} - */ - this.state = ol.ImageState.IDLE; - - /** - * @private - * @type {ol.ImageLoadFunctionType} - */ - this.imageLoadFunction_ = imageLoadFunction; - -}; -goog.inherits(ol.Image, ol.ImageBase); - - -/** - * Get the HTML image element (may be a Canvas, Image, or Video). - * @param {Object=} opt_context Object. - * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image. - * @api - */ -ol.Image.prototype.getImage = function(opt_context) { - if (opt_context !== undefined) { - var image; - var key = goog.getUid(opt_context); - if (key in this.imageByContext_) { - return this.imageByContext_[key]; - } else if (goog.object.isEmpty(this.imageByContext_)) { - image = this.image_; - } else { - image = /** @type {Image} */ (this.image_.cloneNode(false)); - } - this.imageByContext_[key] = image; - return image; - } else { - return this.image_; - } -}; - - -/** - * Tracks loading or read errors. - * - * @private - */ -ol.Image.prototype.handleImageError_ = function() { - this.state = ol.ImageState.ERROR; - this.unlistenImage_(); - this.changed(); -}; - - -/** - * Tracks successful image load. - * - * @private - */ -ol.Image.prototype.handleImageLoad_ = function() { - if (this.resolution === undefined) { - this.resolution = ol.extent.getHeight(this.extent) / this.image_.height; - } - this.state = ol.ImageState.LOADED; - this.unlistenImage_(); - this.changed(); -}; - - -/** - * Load not yet loaded URI. - */ -ol.Image.prototype.load = function() { - if (this.state == ol.ImageState.IDLE) { - this.state = ol.ImageState.LOADING; - this.changed(); - goog.asserts.assert(!this.imageListenerKeys_, - 'this.imageListenerKeys_ should be null'); - this.imageListenerKeys_ = [ - goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, - this.handleImageError_, false, this), - goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, - this.handleImageLoad_, false, this) - ]; - this.imageLoadFunction_(this, this.src_); - } -}; - - -/** - * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image. - */ -ol.Image.prototype.setImage = function(image) { - this.image_ = image; -}; - - -/** - * Discards event handlers which listen for load completion or errors. - * - * @private - */ -ol.Image.prototype.unlistenImage_ = function() { - goog.asserts.assert(this.imageListenerKeys_, - 'this.imageListenerKeys_ should not be null'); - this.imageListenerKeys_.forEach(goog.events.unlistenByKey); - this.imageListenerKeys_ = null; -}; - -goog.provide('ol.ImageLoadFunctionType'); - - -/** - * A function that takes an {@link ol.Image} for the image and a `{string}` for - * the src as arguments. It is supposed to make it so the underlying image - * {@link ol.Image#getImage} is assigned the content specified by the src. If - * not specified, the default is - * - * function(image, src) { - * image.getImage().src = src; - * } - * - * Providing a custom `imageLoadFunction` can be useful to load images with - * post requests or - in general - through XHR requests, where the src of the - * image element would be set to a data URI when the content is loaded. - * - * @typedef {function(ol.Image, string)} - * @api - */ -ol.ImageLoadFunctionType; - -goog.provide('ol.ImageTile'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.Tile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileLoadFunctionType'); -goog.require('ol.TileState'); - - - -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Image source URI. - * @param {?string} crossOrigin Cross origin. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - */ -ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) { - - goog.base(this, tileCoord, state); - - /** - * Image URI - * - * @private - * @type {string} - */ - this.src_ = src; - - /** - * @private - * @type {Image} - */ - this.image_ = new Image(); - if (crossOrigin !== null) { - this.image_.crossOrigin = crossOrigin; - } - - /** - * @private - * @type {Object.<number, Image>} - */ - this.imageByContext_ = {}; - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.imageListenerKeys_ = null; - - /** - * @private - * @type {ol.TileLoadFunctionType} - */ - this.tileLoadFunction_ = tileLoadFunction; - -}; -goog.inherits(ol.ImageTile, ol.Tile); - - -/** - * @inheritDoc - */ -ol.ImageTile.prototype.disposeInternal = function() { - if (this.state == ol.TileState.LOADING) { - this.unlistenImage_(); - } - if (this.interimTile) { - goog.dispose(this.interimTile); - } - goog.base(this, 'disposeInternal'); -}; - - -/** - * Get the image element for this tile. - * @inheritDoc - * @api - */ -ol.ImageTile.prototype.getImage = function(opt_context) { - if (opt_context !== undefined) { - var image; - var key = goog.getUid(opt_context); - if (key in this.imageByContext_) { - return this.imageByContext_[key]; - } else if (goog.object.isEmpty(this.imageByContext_)) { - image = this.image_; - } else { - image = /** @type {Image} */ (this.image_.cloneNode(false)); - } - this.imageByContext_[key] = image; - return image; - } else { - return this.image_; - } -}; - - -/** - * @inheritDoc - */ -ol.ImageTile.prototype.getKey = function() { - return this.src_; -}; - - -/** - * Tracks loading or read errors. - * - * @private - */ -ol.ImageTile.prototype.handleImageError_ = function() { - this.state = ol.TileState.ERROR; - this.unlistenImage_(); - this.changed(); -}; - - -/** - * Tracks successful image load. - * - * @private - */ -ol.ImageTile.prototype.handleImageLoad_ = function() { - if (this.image_.naturalWidth && this.image_.naturalHeight) { - this.state = ol.TileState.LOADED; - } else { - this.state = ol.TileState.EMPTY; - } - this.unlistenImage_(); - this.changed(); -}; - - -/** - * Load not yet loaded URI. - */ -ol.ImageTile.prototype.load = function() { - if (this.state == ol.TileState.IDLE) { - this.state = ol.TileState.LOADING; - this.changed(); - goog.asserts.assert(!this.imageListenerKeys_, - 'this.imageListenerKeys_ should be null'); - this.imageListenerKeys_ = [ - goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, - this.handleImageError_, false, this), - goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, - this.handleImageLoad_, false, this) - ]; - this.tileLoadFunction_(this, this.src_); - } -}; - - -/** - * Discards event handlers which listen for load completion or errors. - * - * @private - */ -ol.ImageTile.prototype.unlistenImage_ = function() { - goog.asserts.assert(this.imageListenerKeys_, - 'this.imageListenerKeys_ should not be null'); - this.imageListenerKeys_.forEach(goog.events.unlistenByKey); - this.imageListenerKeys_ = null; -}; - -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Provides a files drag and drop event detector. It works on - * HTML5 browsers. - * - * @see ../demos/filedrophandler.html - */ - -goog.provide('goog.events.FileDropHandler'); -goog.provide('goog.events.FileDropHandler.EventType'); - -goog.require('goog.array'); -goog.require('goog.dom'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.log'); -goog.require('goog.log.Level'); - - - -/** - * A files drag and drop event detector. Gets an {@code element} as parameter - * and fires {@code goog.events.FileDropHandler.EventType.DROP} event when files - * are dropped in the {@code element}. - * - * @param {Element|Document} element The element or document to listen on. - * @param {boolean=} opt_preventDropOutside Whether to prevent a drop on the - * area outside the {@code element}. Default false. - * @constructor - * @extends {goog.events.EventTarget} - * @final - */ -goog.events.FileDropHandler = function(element, opt_preventDropOutside) { - goog.events.EventTarget.call(this); - - /** - * Handler for drag/drop events. - * @type {!goog.events.EventHandler<!goog.events.FileDropHandler>} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); - - var doc = element; - if (opt_preventDropOutside) { - doc = goog.dom.getOwnerDocument(element); - } - - // Add dragenter listener to the owner document of the element. - this.eventHandler_.listen(doc, - goog.events.EventType.DRAGENTER, - this.onDocDragEnter_); - - // Add dragover listener to the owner document of the element only if the - // document is not the element itself. - if (doc != element) { - this.eventHandler_.listen(doc, - goog.events.EventType.DRAGOVER, - this.onDocDragOver_); - } - - // Add dragover and drop listeners to the element. - this.eventHandler_.listen(element, - goog.events.EventType.DRAGOVER, - this.onElemDragOver_); - this.eventHandler_.listen(element, - goog.events.EventType.DROP, - this.onElemDrop_); -}; -goog.inherits(goog.events.FileDropHandler, goog.events.EventTarget); - - -/** - * Whether the drag event contains files. It is initialized only in the - * dragenter event. It is used in all the drag events to prevent default actions - * only if the drag contains files. Preventing default actions is necessary to - * go from dragenter to dragover and from dragover to drop. However we do not - * always want to prevent default actions, e.g. when the user drags text or - * links on a text area we should not prevent the browser default action that - * inserts the text in the text area. It is also necessary to stop propagation - * when handling drag events on the element to prevent them from propagating - * to the document. - * @private - * @type {boolean} - */ -goog.events.FileDropHandler.prototype.dndContainsFiles_ = false; - - -/** - * A logger, used to help us debug the algorithm. - * @type {goog.log.Logger} - * @private - */ -goog.events.FileDropHandler.prototype.logger_ = - goog.log.getLogger('goog.events.FileDropHandler'); - - -/** - * The types of events fired by this class. - * @enum {string} - */ -goog.events.FileDropHandler.EventType = { - DROP: goog.events.EventType.DROP -}; - - -/** @override */ -goog.events.FileDropHandler.prototype.disposeInternal = function() { - goog.events.FileDropHandler.superClass_.disposeInternal.call(this); - this.eventHandler_.dispose(); -}; - - -/** - * Dispatches the DROP event. - * @param {goog.events.BrowserEvent} e The underlying browser event. - * @private - */ -goog.events.FileDropHandler.prototype.dispatch_ = function(e) { - goog.log.fine(this.logger_, 'Firing DROP event...'); - var event = new goog.events.BrowserEvent(e.getBrowserEvent()); - event.type = goog.events.FileDropHandler.EventType.DROP; - this.dispatchEvent(event); -}; - - -/** - * Handles dragenter on the document. - * @param {goog.events.BrowserEvent} e The dragenter event. - * @private - */ -goog.events.FileDropHandler.prototype.onDocDragEnter_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINER, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - var dt = e.getBrowserEvent().dataTransfer; - // Check whether the drag event contains files. - this.dndContainsFiles_ = !!(dt && - ((dt.types && - (goog.array.contains(dt.types, 'Files') || - goog.array.contains(dt.types, 'public.file-url'))) || - (dt.files && dt.files.length > 0))); - // If it does - if (this.dndContainsFiles_) { - // Prevent default actions. - e.preventDefault(); - } - goog.log.log(this.logger_, goog.log.Level.FINER, - 'dndContainsFiles_: ' + this.dndContainsFiles_); -}; - - -/** - * Handles dragging something over the document. - * @param {goog.events.BrowserEvent} e The dragover event. - * @private - */ -goog.events.FileDropHandler.prototype.onDocDragOver_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINEST, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - if (this.dndContainsFiles_) { - // Prevent default actions. - e.preventDefault(); - // Disable the drop on the document outside the drop zone. - var dt = e.getBrowserEvent().dataTransfer; - dt.dropEffect = 'none'; - } -}; - - -/** - * Handles dragging something over the element (drop zone). - * @param {goog.events.BrowserEvent} e The dragover event. - * @private - */ -goog.events.FileDropHandler.prototype.onElemDragOver_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINEST, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - if (this.dndContainsFiles_) { - // Prevent default actions and stop the event from propagating further to - // the document. Both lines are needed! (See comment above). - e.preventDefault(); - e.stopPropagation(); - // Allow the drop on the drop zone. - var dt = e.getBrowserEvent().dataTransfer; - - // IE bug #811625 (https://goo.gl/UWuxX0) will throw error SCRIPT65535 - // when attempting to set property effectAllowed on IE10+. - // See more: https://github.com/google/closure-library/issues/485. - try { - dt.effectAllowed = 'all'; - } catch (err) { - } - dt.dropEffect = 'copy'; - } -}; - - -/** - * Handles dropping something onto the element (drop zone). - * @param {goog.events.BrowserEvent} e The drop event. - * @private - */ -goog.events.FileDropHandler.prototype.onElemDrop_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINER, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - // If the drag and drop event contains files. - if (this.dndContainsFiles_) { - // Prevent default actions and stop the event from propagating further to - // the document. Both lines are needed! (See comment above). - e.preventDefault(); - e.stopPropagation(); - // Dispatch DROP event. - this.dispatch_(e); - } -}; - -// Copyright 2007 Bob Ippolito. All Rights Reserved. -// Modifications Copyright 2009 The Closure Library Authors. All Rights -// Reserved. - -/** - * @license Portions of this code are from MochiKit, received by - * The Closure Authors under the MIT license. All other code is Copyright - * 2005-2009 The Closure Authors. All Rights Reserved. - */ - -/** - * @fileoverview Classes for tracking asynchronous operations and handling the - * results. The Deferred object here is patterned after the Deferred object in - * the Twisted python networking framework. - * - * See: http://twistedmatrix.com/projects/core/documentation/howto/defer.html - * - * Based on the Dojo code which in turn is based on the MochiKit code. - * - * @author arv@google.com (Erik Arvidsson) - * @author brenneman@google.com (Shawn Brenneman) - */ - -goog.provide('goog.async.Deferred'); -goog.provide('goog.async.Deferred.AlreadyCalledError'); -goog.provide('goog.async.Deferred.CanceledError'); - -goog.require('goog.Promise'); -goog.require('goog.Thenable'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.debug.Error'); - - - -/** - * A Deferred represents the result of an asynchronous operation. A Deferred - * instance has no result when it is created, and is "fired" (given an initial - * result) by calling {@code callback} or {@code errback}. - * - * Once fired, the result is passed through a sequence of callback functions - * registered with {@code addCallback} or {@code addErrback}. The functions may - * mutate the result before it is passed to the next function in the sequence. - * - * Callbacks and errbacks may be added at any time, including after the Deferred - * has been "fired". If there are no pending actions in the execution sequence - * of a fired Deferred, any new callback functions will be called with the last - * computed result. Adding a callback function is the only way to access the - * result of the Deferred. - * - * If a Deferred operation is canceled, an optional user-provided cancellation - * function is invoked which may perform any special cleanup, followed by firing - * the Deferred's errback sequence with a {@code CanceledError}. If the - * Deferred has already fired, cancellation is ignored. - * - * Deferreds may be templated to a specific type they produce using generics - * with syntax such as: - * <code> - * /** @type {goog.async.Deferred<string>} */ - * var d = new goog.async.Deferred(); - * // Compiler can infer that foo is a string. - * d.addCallback(function(foo) {...}); - * d.callback('string'); // Checked to be passed a string - * </code> - * Since deferreds are often used to produce different values across a chain, - * the type information is not propagated across chains, but rather only - * associated with specifically cast objects. - * - * @param {Function=} opt_onCancelFunction A function that will be called if the - * Deferred is canceled. If provided, this function runs before the - * Deferred is fired with a {@code CanceledError}. - * @param {Object=} opt_defaultScope The default object context to call - * callbacks and errbacks in. - * @constructor - * @implements {goog.Thenable<VALUE>} - * @template VALUE - */ -goog.async.Deferred = function(opt_onCancelFunction, opt_defaultScope) { - /** - * Entries in the sequence are arrays containing a callback, an errback, and - * an optional scope. The callback or errback in an entry may be null. - * @type {!Array<!Array>} - * @private - */ - this.sequence_ = []; - - /** - * Optional function that will be called if the Deferred is canceled. - * @type {Function|undefined} - * @private - */ - this.onCancelFunction_ = opt_onCancelFunction; - - /** - * The default scope to execute callbacks and errbacks in. - * @type {Object} - * @private - */ - this.defaultScope_ = opt_defaultScope || null; - - /** - * Whether the Deferred has been fired. - * @type {boolean} - * @private - */ - this.fired_ = false; - - /** - * Whether the last result in the execution sequence was an error. - * @type {boolean} - * @private - */ - this.hadError_ = false; - - /** - * The current Deferred result, updated as callbacks and errbacks are - * executed. - * @type {*} - * @private - */ - this.result_ = undefined; - - /** - * Whether the Deferred is blocked waiting on another Deferred to fire. If a - * callback or errback returns a Deferred as a result, the execution sequence - * is blocked until that Deferred result becomes available. - * @type {boolean} - * @private - */ - this.blocked_ = false; - - /** - * Whether this Deferred is blocking execution of another Deferred. If this - * instance was returned as a result in another Deferred's execution - * sequence,that other Deferred becomes blocked until this instance's - * execution sequence completes. No additional callbacks may be added to a - * Deferred once it is blocking another instance. - * @type {boolean} - * @private - */ - this.blocking_ = false; - - /** - * Whether the Deferred has been canceled without having a custom cancel - * function. - * @type {boolean} - * @private - */ - this.silentlyCanceled_ = false; - - /** - * If an error is thrown during Deferred execution with no errback to catch - * it, the error is rethrown after a timeout. Reporting the error after a - * timeout allows execution to continue in the calling context (empty when - * no error is scheduled). - * @type {number} - * @private - */ - this.unhandledErrorId_ = 0; - - /** - * If this Deferred was created by branch(), this will be the "parent" - * Deferred. - * @type {goog.async.Deferred} - * @private - */ - this.parent_ = null; - - /** - * The number of Deferred objects that have been branched off this one. This - * will be decremented whenever a branch is fired or canceled. - * @type {number} - * @private - */ - this.branches_ = 0; - - if (goog.async.Deferred.LONG_STACK_TRACES) { - /** - * Holds the stack trace at time of deferred creation if the JS engine - * provides the Error.captureStackTrace API. - * @private {?string} - */ - this.constructorStack_ = null; - if (Error.captureStackTrace) { - var target = { stack: '' }; - Error.captureStackTrace(target, goog.async.Deferred); - // Check if Error.captureStackTrace worked. It fails in gjstest. - if (typeof target.stack == 'string') { - // Remove first line and force stringify to prevent memory leak due to - // holding on to actual stack frames. - this.constructorStack_ = target.stack.replace(/^[^\n]*\n/, ''); - } - } - } -}; - - -/** - * @define {boolean} Whether unhandled errors should always get rethrown to the - * global scope. Defaults to the value of goog.DEBUG. - */ -goog.define('goog.async.Deferred.STRICT_ERRORS', false); - - -/** - * @define {boolean} Whether to attempt to make stack traces long. Defaults to - * the value of goog.DEBUG. - */ -goog.define('goog.async.Deferred.LONG_STACK_TRACES', false); - - -/** - * Cancels a Deferred that has not yet been fired, or is blocked on another - * deferred operation. If this Deferred is waiting for a blocking Deferred to - * fire, the blocking Deferred will also be canceled. - * - * If this Deferred was created by calling branch() on a parent Deferred with - * opt_propagateCancel set to true, the parent may also be canceled. If - * opt_deepCancel is set, cancel() will be called on the parent (as well as any - * other ancestors if the parent is also a branch). If one or more branches were - * created with opt_propagateCancel set to true, the parent will be canceled if - * cancel() is called on all of those branches. - * - * @param {boolean=} opt_deepCancel If true, cancels this Deferred's parent even - * if cancel() hasn't been called on some of the parent's branches. Has no - * effect on a branch without opt_propagateCancel set to true. - */ -goog.async.Deferred.prototype.cancel = function(opt_deepCancel) { - if (!this.hasFired()) { - if (this.parent_) { - // Get rid of the parent reference before potentially running the parent's - // canceler function to ensure that this cancellation isn't - // double-counted. - var parent = this.parent_; - delete this.parent_; - if (opt_deepCancel) { - parent.cancel(opt_deepCancel); - } else { - parent.branchCancel_(); - } - } - - if (this.onCancelFunction_) { - // Call in user-specified scope. - this.onCancelFunction_.call(this.defaultScope_, this); - } else { - this.silentlyCanceled_ = true; - } - if (!this.hasFired()) { - this.errback(new goog.async.Deferred.CanceledError(this)); - } - } else if (this.result_ instanceof goog.async.Deferred) { - this.result_.cancel(); - } -}; - - -/** - * Handle a single branch being canceled. Once all branches are canceled, this - * Deferred will be canceled as well. - * - * @private - */ -goog.async.Deferred.prototype.branchCancel_ = function() { - this.branches_--; - if (this.branches_ <= 0) { - this.cancel(); - } -}; - - -/** - * Called after a blocking Deferred fires. Unblocks this Deferred and resumes - * its execution sequence. - * - * @param {boolean} isSuccess Whether the result is a success or an error. - * @param {*} res The result of the blocking Deferred. - * @private - */ -goog.async.Deferred.prototype.continue_ = function(isSuccess, res) { - this.blocked_ = false; - this.updateResult_(isSuccess, res); -}; - - -/** - * Updates the current result based on the success or failure of the last action - * in the execution sequence. - * - * @param {boolean} isSuccess Whether the new result is a success or an error. - * @param {*} res The result. - * @private - */ -goog.async.Deferred.prototype.updateResult_ = function(isSuccess, res) { - this.fired_ = true; - this.result_ = res; - this.hadError_ = !isSuccess; - this.fire_(); -}; - - -/** - * Verifies that the Deferred has not yet been fired. - * - * @private - * @throws {Error} If this has already been fired. - */ -goog.async.Deferred.prototype.check_ = function() { - if (this.hasFired()) { - if (!this.silentlyCanceled_) { - throw new goog.async.Deferred.AlreadyCalledError(this); - } - this.silentlyCanceled_ = false; - } -}; - - -/** - * Fire the execution sequence for this Deferred by passing the starting result - * to the first registered callback. - * @param {VALUE=} opt_result The starting result. - */ -goog.async.Deferred.prototype.callback = function(opt_result) { - this.check_(); - this.assertNotDeferred_(opt_result); - this.updateResult_(true /* isSuccess */, opt_result); -}; - - -/** - * Fire the execution sequence for this Deferred by passing the starting error - * result to the first registered errback. - * @param {*=} opt_result The starting error. - */ -goog.async.Deferred.prototype.errback = function(opt_result) { - this.check_(); - this.assertNotDeferred_(opt_result); - this.makeStackTraceLong_(opt_result); - this.updateResult_(false /* isSuccess */, opt_result); -}; - - -/** - * Attempt to make the error's stack trace be long in that it contains the - * stack trace from the point where the deferred was created on top of the - * current stack trace to give additional context. - * @param {*} error - * @private - */ -goog.async.Deferred.prototype.makeStackTraceLong_ = function(error) { - if (!goog.async.Deferred.LONG_STACK_TRACES) { - return; - } - if (this.constructorStack_ && goog.isObject(error) && error.stack && - // Stack looks like it was system generated. See - // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi - (/^[^\n]+(\n [^\n]+)+/).test(error.stack)) { - error.stack = error.stack + '\nDEFERRED OPERATION:\n' + - this.constructorStack_; - } -}; - - -/** - * Asserts that an object is not a Deferred. - * @param {*} obj The object to test. - * @throws {Error} Throws an exception if the object is a Deferred. - * @private - */ -goog.async.Deferred.prototype.assertNotDeferred_ = function(obj) { - goog.asserts.assert( - !(obj instanceof goog.async.Deferred), - 'An execution sequence may not be initiated with a blocking Deferred.'); -}; - - -/** - * Register a callback function to be called with a successful result. If no - * value is returned by the callback function, the result value is unchanged. If - * a new value is returned, it becomes the Deferred result and will be passed to - * the next callback in the execution sequence. - * - * If the function throws an error, the error becomes the new result and will be - * passed to the next errback in the execution chain. - * - * If the function returns a Deferred, the execution sequence will be blocked - * until that Deferred fires. Its result will be passed to the next callback (or - * errback if it is an error result) in this Deferred's execution sequence. - * - * @param {!function(this:T,VALUE):?} cb The function to be called with a - * successful result. - * @param {T=} opt_scope An optional scope to call the callback in. - * @return {!goog.async.Deferred} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addCallback = function(cb, opt_scope) { - return this.addCallbacks(cb, null, opt_scope); -}; - - -/** - * Register a callback function to be called with an error result. If no value - * is returned by the function, the error result is unchanged. If a new error - * value is returned or thrown, that error becomes the Deferred result and will - * be passed to the next errback in the execution sequence. - * - * If the errback function handles the error by returning a non-error value, - * that result will be passed to the next normal callback in the sequence. - * - * If the function returns a Deferred, the execution sequence will be blocked - * until that Deferred fires. Its result will be passed to the next callback (or - * errback if it is an error result) in this Deferred's execution sequence. - * - * @param {!function(this:T,?):?} eb The function to be called on an - * unsuccessful result. - * @param {T=} opt_scope An optional scope to call the errback in. - * @return {!goog.async.Deferred<VALUE>} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addErrback = function(eb, opt_scope) { - return this.addCallbacks(null, eb, opt_scope); -}; - - -/** - * Registers one function as both a callback and errback. - * - * @param {!function(this:T,?):?} f The function to be called on any result. - * @param {T=} opt_scope An optional scope to call the function in. - * @return {!goog.async.Deferred} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addBoth = function(f, opt_scope) { - return this.addCallbacks(f, f, opt_scope); -}; - - -/** - * Like addBoth, but propagates uncaught exceptions in the errback. - * - * @param {function(this:T,?):?} f The function to be called on any result. - * @param {T=} opt_scope An optional scope to call the function in. - * @return {!goog.async.Deferred<VALUE>} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addFinally = function(f, opt_scope) { - var self = this; - return this.addCallbacks(f, function(err) { - var result = f.call(self, err); - if (!goog.isDef(result)) { - throw err; - } - return result; - }, opt_scope); -}; - - -/** - * Registers a callback function and an errback function at the same position - * in the execution sequence. Only one of these functions will execute, - * depending on the error state during the execution sequence. - * - * NOTE: This is not equivalent to {@code def.addCallback().addErrback()}! If - * the callback is invoked, the errback will be skipped, and vice versa. - * - * @param {?(function(this:T,VALUE):?)} cb The function to be called on a - * successful result. - * @param {?(function(this:T,?):?)} eb The function to be called on an - * unsuccessful result. - * @param {T=} opt_scope An optional scope to call the functions in. - * @return {!goog.async.Deferred} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addCallbacks = function(cb, eb, opt_scope) { - goog.asserts.assert(!this.blocking_, 'Blocking Deferreds can not be re-used'); - this.sequence_.push([cb, eb, opt_scope]); - if (this.hasFired()) { - this.fire_(); - } - return this; -}; - - -/** - * Implements {@see goog.Thenable} for seamless integration with - * {@see goog.Promise}. - * Deferred results are mutable and may represent multiple values over - * their lifetime. Calling {@code then} on a Deferred returns a Promise - * with the result of the Deferred at that point in its callback chain. - * Note that if the Deferred result is never mutated, and only - * {@code then} calls are made, the Deferred will behave like a Promise. - * - * @override - */ -goog.async.Deferred.prototype.then = function(opt_onFulfilled, opt_onRejected, - opt_context) { - var resolve, reject; - var promise = new goog.Promise(function(res, rej) { - // Copying resolvers to outer scope, so that they are available when the - // deferred callback fires (which may be synchronous). - resolve = res; - reject = rej; - }); - this.addCallbacks(resolve, function(reason) { - if (reason instanceof goog.async.Deferred.CanceledError) { - promise.cancel(); - } else { - reject(reason); - } - }); - return promise.then(opt_onFulfilled, opt_onRejected, opt_context); -}; -goog.Thenable.addImplementation(goog.async.Deferred); - - -/** - * Links another Deferred to the end of this Deferred's execution sequence. The - * result of this execution sequence will be passed as the starting result for - * the chained Deferred, invoking either its first callback or errback. - * - * @param {!goog.async.Deferred} otherDeferred The Deferred to chain. - * @return {!goog.async.Deferred} This Deferred. - */ -goog.async.Deferred.prototype.chainDeferred = function(otherDeferred) { - this.addCallbacks( - otherDeferred.callback, otherDeferred.errback, otherDeferred); - return this; -}; - - -/** - * Makes this Deferred wait for another Deferred's execution sequence to - * complete before continuing. - * - * This is equivalent to adding a callback that returns {@code otherDeferred}, - * but doesn't prevent additional callbacks from being added to - * {@code otherDeferred}. - * - * @param {!goog.async.Deferred|!goog.Thenable} otherDeferred The Deferred - * to wait for. - * @return {!goog.async.Deferred} This Deferred. - */ -goog.async.Deferred.prototype.awaitDeferred = function(otherDeferred) { - if (!(otherDeferred instanceof goog.async.Deferred)) { - // The Thenable case. - return this.addCallback(function() { - return otherDeferred; - }); - } - return this.addCallback(goog.bind(otherDeferred.branch, otherDeferred)); -}; - - -/** - * Creates a branch off this Deferred's execution sequence, and returns it as a - * new Deferred. The branched Deferred's starting result will be shared with the - * parent at the point of the branch, even if further callbacks are added to the - * parent. - * - * All branches at the same stage in the execution sequence will receive the - * same starting value. - * - * @param {boolean=} opt_propagateCancel If cancel() is called on every child - * branch created with opt_propagateCancel, the parent will be canceled as - * well. - * @return {!goog.async.Deferred<VALUE>} A Deferred that will be started with - * the computed result from this stage in the execution sequence. - */ -goog.async.Deferred.prototype.branch = function(opt_propagateCancel) { - var d = new goog.async.Deferred(); - this.chainDeferred(d); - if (opt_propagateCancel) { - d.parent_ = this; - this.branches_++; - } - return d; -}; - - -/** - * @return {boolean} Whether the execution sequence has been started on this - * Deferred by invoking {@code callback} or {@code errback}. - */ -goog.async.Deferred.prototype.hasFired = function() { - return this.fired_; -}; - - -/** - * @param {*} res The latest result in the execution sequence. - * @return {boolean} Whether the current result is an error that should cause - * the next errback to fire. May be overridden by subclasses to handle - * special error types. - * @protected - */ -goog.async.Deferred.prototype.isError = function(res) { - return res instanceof Error; -}; - - -/** - * @return {boolean} Whether an errback exists in the remaining sequence. - * @private - */ -goog.async.Deferred.prototype.hasErrback_ = function() { - return goog.array.some(this.sequence_, function(sequenceRow) { - // The errback is the second element in the array. - return goog.isFunction(sequenceRow[1]); - }); -}; - - -/** - * Exhausts the execution sequence while a result is available. The result may - * be modified by callbacks or errbacks, and execution will block if the - * returned result is an incomplete Deferred. - * - * @private - */ -goog.async.Deferred.prototype.fire_ = function() { - if (this.unhandledErrorId_ && this.hasFired() && this.hasErrback_()) { - // It is possible to add errbacks after the Deferred has fired. If a new - // errback is added immediately after the Deferred encountered an unhandled - // error, but before that error is rethrown, the error is unscheduled. - goog.async.Deferred.unscheduleError_(this.unhandledErrorId_); - this.unhandledErrorId_ = 0; - } - - if (this.parent_) { - this.parent_.branches_--; - delete this.parent_; - } - - var res = this.result_; - var unhandledException = false; - var isNewlyBlocked = false; - - while (this.sequence_.length && !this.blocked_) { - var sequenceEntry = this.sequence_.shift(); - - var callback = sequenceEntry[0]; - var errback = sequenceEntry[1]; - var scope = sequenceEntry[2]; - - var f = this.hadError_ ? errback : callback; - if (f) { - /** @preserveTry */ - try { - var ret = f.call(scope || this.defaultScope_, res); - - // If no result, then use previous result. - if (goog.isDef(ret)) { - // Bubble up the error as long as the return value hasn't changed. - this.hadError_ = this.hadError_ && (ret == res || this.isError(ret)); - this.result_ = res = ret; - } - - if (goog.Thenable.isImplementedBy(res) || - (typeof goog.global['Promise'] === 'function' && - res instanceof goog.global['Promise'])) { - isNewlyBlocked = true; - this.blocked_ = true; - } - - } catch (ex) { - res = ex; - this.hadError_ = true; - this.makeStackTraceLong_(res); - - if (!this.hasErrback_()) { - // If an error is thrown with no additional errbacks in the queue, - // prepare to rethrow the error. - unhandledException = true; - } - } - } - } - - this.result_ = res; - - if (isNewlyBlocked) { - var onCallback = goog.bind(this.continue_, this, true /* isSuccess */); - var onErrback = goog.bind(this.continue_, this, false /* isSuccess */); - - if (res instanceof goog.async.Deferred) { - res.addCallbacks(onCallback, onErrback); - res.blocking_ = true; - } else { - res.then(onCallback, onErrback); - } - } else if (goog.async.Deferred.STRICT_ERRORS && this.isError(res) && - !(res instanceof goog.async.Deferred.CanceledError)) { - this.hadError_ = true; - unhandledException = true; - } - - if (unhandledException) { - // Rethrow the unhandled error after a timeout. Execution will continue, but - // the error will be seen by global handlers and the user. The throw will - // be canceled if another errback is appended before the timeout executes. - // The error's original stack trace is preserved where available. - this.unhandledErrorId_ = goog.async.Deferred.scheduleError_(res); - } -}; - - -/** - * Creates a Deferred that has an initial result. - * - * @param {*=} opt_result The result. - * @return {!goog.async.Deferred} The new Deferred. - */ -goog.async.Deferred.succeed = function(opt_result) { - var d = new goog.async.Deferred(); - d.callback(opt_result); - return d; -}; - - -/** - * Creates a Deferred that fires when the given promise resolves. - * Use only during migration to Promises. - * - * @param {!goog.Promise<T>} promise - * @return {!goog.async.Deferred<T>} The new Deferred. - * @template T - */ -goog.async.Deferred.fromPromise = function(promise) { - var d = new goog.async.Deferred(); - d.callback(); - d.addCallback(function() { - return promise; - }); - return d; -}; - - -/** - * Creates a Deferred that has an initial error result. - * - * @param {*} res The error result. - * @return {!goog.async.Deferred} The new Deferred. - */ -goog.async.Deferred.fail = function(res) { - var d = new goog.async.Deferred(); - d.errback(res); - return d; -}; - - -/** - * Creates a Deferred that has already been canceled. - * - * @return {!goog.async.Deferred} The new Deferred. - */ -goog.async.Deferred.canceled = function() { - var d = new goog.async.Deferred(); - d.cancel(); - return d; -}; - - -/** - * Normalizes values that may or may not be Deferreds. - * - * If the input value is a Deferred, the Deferred is branched (so the original - * execution sequence is not modified) and the input callback added to the new - * branch. The branch is returned to the caller. - * - * If the input value is not a Deferred, the callback will be executed - * immediately and an already firing Deferred will be returned to the caller. - * - * In the following (contrived) example, if <code>isImmediate</code> is true - * then 3 is alerted immediately, otherwise 6 is alerted after a 2-second delay. - * - * <pre> - * var value; - * if (isImmediate) { - * value = 3; - * } else { - * value = new goog.async.Deferred(); - * setTimeout(function() { value.callback(6); }, 2000); - * } - * - * var d = goog.async.Deferred.when(value, alert); - * </pre> - * - * @param {*} value Deferred or normal value to pass to the callback. - * @param {!function(this:T, ?):?} callback The callback to execute. - * @param {T=} opt_scope An optional scope to call the callback in. - * @return {!goog.async.Deferred} A new Deferred that will call the input - * callback with the input value. - * @template T - */ -goog.async.Deferred.when = function(value, callback, opt_scope) { - if (value instanceof goog.async.Deferred) { - return value.branch(true).addCallback(callback, opt_scope); - } else { - return goog.async.Deferred.succeed(value).addCallback(callback, opt_scope); - } -}; - - - -/** - * An error sub class that is used when a Deferred has already been called. - * @param {!goog.async.Deferred} deferred The Deferred. - * - * @constructor - * @extends {goog.debug.Error} - */ -goog.async.Deferred.AlreadyCalledError = function(deferred) { - goog.debug.Error.call(this); - - /** - * The Deferred that raised this error. - * @type {goog.async.Deferred} - */ - this.deferred = deferred; -}; -goog.inherits(goog.async.Deferred.AlreadyCalledError, goog.debug.Error); - - -/** @override */ -goog.async.Deferred.AlreadyCalledError.prototype.message = - 'Deferred has already fired'; - - -/** @override */ -goog.async.Deferred.AlreadyCalledError.prototype.name = 'AlreadyCalledError'; - - - -/** - * An error sub class that is used when a Deferred is canceled. - * - * @param {!goog.async.Deferred} deferred The Deferred object. - * @constructor - * @extends {goog.debug.Error} - */ -goog.async.Deferred.CanceledError = function(deferred) { - goog.debug.Error.call(this); - - /** - * The Deferred that raised this error. - * @type {goog.async.Deferred} - */ - this.deferred = deferred; -}; -goog.inherits(goog.async.Deferred.CanceledError, goog.debug.Error); - - -/** @override */ -goog.async.Deferred.CanceledError.prototype.message = 'Deferred was canceled'; - - -/** @override */ -goog.async.Deferred.CanceledError.prototype.name = 'CanceledError'; - - - -/** - * Wrapper around errors that are scheduled to be thrown by failing deferreds - * after a timeout. - * - * @param {*} error Error from a failing deferred. - * @constructor - * @final - * @private - * @struct - */ -goog.async.Deferred.Error_ = function(error) { - /** @const @private {number} */ - this.id_ = goog.global.setTimeout(goog.bind(this.throwError, this), 0); - - /** @const @private {*} */ - this.error_ = error; -}; - - -/** - * Actually throws the error and removes it from the list of pending - * deferred errors. - */ -goog.async.Deferred.Error_.prototype.throwError = function() { - goog.asserts.assert(goog.async.Deferred.errorMap_[this.id_], - 'Cannot throw an error that is not scheduled.'); - delete goog.async.Deferred.errorMap_[this.id_]; - throw this.error_; -}; - - -/** - * Resets the error throw timer. - */ -goog.async.Deferred.Error_.prototype.resetTimer = function() { - goog.global.clearTimeout(this.id_); -}; - - -/** - * Map of unhandled errors scheduled to be rethrown in a future timestep. - * @private {!Object<number|string, goog.async.Deferred.Error_>} - */ -goog.async.Deferred.errorMap_ = {}; - - -/** - * Schedules an error to be thrown after a delay. - * @param {*} error Error from a failing deferred. - * @return {number} Id of the error. - * @private - */ -goog.async.Deferred.scheduleError_ = function(error) { - var deferredError = new goog.async.Deferred.Error_(error); - goog.async.Deferred.errorMap_[deferredError.id_] = deferredError; - return deferredError.id_; -}; - - -/** - * Unschedules an error from being thrown. - * @param {number} id Id of the deferred error to unschedule. - * @private - */ -goog.async.Deferred.unscheduleError_ = function(id) { - var error = goog.async.Deferred.errorMap_[id]; - if (error) { - error.resetTimer(); - delete goog.async.Deferred.errorMap_[id]; - } -}; - - -/** - * Asserts that there are no pending deferred errors. If there are any - * scheduled errors, one will be thrown immediately to make this function fail. - */ -goog.async.Deferred.assertNoErrors = function() { - var map = goog.async.Deferred.errorMap_; - for (var key in map) { - var error = map[key]; - error.resetTimer(); - error.throwError(); - } -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A wrapper for the HTML5 FileError object. - * - */ - -goog.provide('goog.fs.Error'); -goog.provide('goog.fs.Error.ErrorCode'); - -goog.require('goog.debug.Error'); -goog.require('goog.object'); -goog.require('goog.string'); - - - -/** - * A filesystem error. Since the filesystem API is asynchronous, stack traces - * are less useful for identifying where errors come from, so this includes a - * large amount of metadata in the message. - * - * @param {!DOMError} error - * @param {string} action The action being undertaken when the error was raised. - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.fs.Error = function(error, action) { - /** @type {string} */ - this.name; - - /** - * @type {goog.fs.Error.ErrorCode} - * @deprecated Use the 'name' or 'message' field instead. - */ - this.code; - - if (goog.isDef(error.name)) { - this.name = error.name; - // TODO(user): Remove warning suppression after JSCompiler stops - // firing a spurious warning here. - /** @suppress {deprecated} */ - this.code = goog.fs.Error.getCodeFromName_(error.name); - } else { - this.code = error.code; - this.name = goog.fs.Error.getNameFromCode_(error.code); - } - goog.fs.Error.base(this, 'constructor', - goog.string.subs('%s %s', this.name, action)); -}; -goog.inherits(goog.fs.Error, goog.debug.Error); - - -/** - * Names of errors that may be thrown by the File API, the File System API, or - * the File Writer API. - * - * @see http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException - * @see http://www.w3.org/TR/file-system-api/#definitions - * @see http://dev.w3.org/2009/dap/file-system/file-writer.html#definitions - * @enum {string} - */ -goog.fs.Error.ErrorName = { - ABORT: 'AbortError', - ENCODING: 'EncodingError', - INVALID_MODIFICATION: 'InvalidModificationError', - INVALID_STATE: 'InvalidStateError', - NOT_FOUND: 'NotFoundError', - NOT_READABLE: 'NotReadableError', - NO_MODIFICATION_ALLOWED: 'NoModificationAllowedError', - PATH_EXISTS: 'PathExistsError', - QUOTA_EXCEEDED: 'QuotaExceededError', - SECURITY: 'SecurityError', - SYNTAX: 'SyntaxError', - TYPE_MISMATCH: 'TypeMismatchError' -}; - - -/** - * Error codes for file errors. - * @see http://www.w3.org/TR/file-system-api/#idl-def-FileException - * - * @enum {number} - * @deprecated Use the 'name' or 'message' attribute instead. - */ -goog.fs.Error.ErrorCode = { - NOT_FOUND: 1, - SECURITY: 2, - ABORT: 3, - NOT_READABLE: 4, - ENCODING: 5, - NO_MODIFICATION_ALLOWED: 6, - INVALID_STATE: 7, - SYNTAX: 8, - INVALID_MODIFICATION: 9, - QUOTA_EXCEEDED: 10, - TYPE_MISMATCH: 11, - PATH_EXISTS: 12 -}; - - -/** - * @param {goog.fs.Error.ErrorCode} code - * @return {string} name - * @private - */ -goog.fs.Error.getNameFromCode_ = function(code) { - var name = goog.object.findKey(goog.fs.Error.NameToCodeMap_, function(c) { - return code == c; - }); - if (!goog.isDef(name)) { - throw new Error('Invalid code: ' + code); - } - return name; -}; - - -/** - * Returns the code that corresponds to the given name. - * @param {string} name - * @return {goog.fs.Error.ErrorCode} code - * @private - */ -goog.fs.Error.getCodeFromName_ = function(name) { - return goog.fs.Error.NameToCodeMap_[name]; -}; - - -/** - * Mapping from error names to values from the ErrorCode enum. - * @see http://www.w3.org/TR/file-system-api/#definitions. - * @private {!Object<string, goog.fs.Error.ErrorCode>} - */ -goog.fs.Error.NameToCodeMap_ = goog.object.create( - goog.fs.Error.ErrorName.ABORT, - goog.fs.Error.ErrorCode.ABORT, - - goog.fs.Error.ErrorName.ENCODING, - goog.fs.Error.ErrorCode.ENCODING, - - goog.fs.Error.ErrorName.INVALID_MODIFICATION, - goog.fs.Error.ErrorCode.INVALID_MODIFICATION, - - goog.fs.Error.ErrorName.INVALID_STATE, - goog.fs.Error.ErrorCode.INVALID_STATE, - - goog.fs.Error.ErrorName.NOT_FOUND, - goog.fs.Error.ErrorCode.NOT_FOUND, - - goog.fs.Error.ErrorName.NOT_READABLE, - goog.fs.Error.ErrorCode.NOT_READABLE, - - goog.fs.Error.ErrorName.NO_MODIFICATION_ALLOWED, - goog.fs.Error.ErrorCode.NO_MODIFICATION_ALLOWED, - - goog.fs.Error.ErrorName.PATH_EXISTS, - goog.fs.Error.ErrorCode.PATH_EXISTS, - - goog.fs.Error.ErrorName.QUOTA_EXCEEDED, - goog.fs.Error.ErrorCode.QUOTA_EXCEEDED, - - goog.fs.Error.ErrorName.SECURITY, - goog.fs.Error.ErrorCode.SECURITY, - - goog.fs.Error.ErrorName.SYNTAX, - goog.fs.Error.ErrorCode.SYNTAX, - - goog.fs.Error.ErrorName.TYPE_MISMATCH, - goog.fs.Error.ErrorCode.TYPE_MISMATCH); - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A wrapper for the HTML5 File ProgressEvent objects. - * - */ -goog.provide('goog.fs.ProgressEvent'); - -goog.require('goog.events.Event'); - - - -/** - * A wrapper for the progress events emitted by the File APIs. - * - * @param {!ProgressEvent} event The underlying event object. - * @param {!Object} target The file access object emitting the event. - * @extends {goog.events.Event} - * @constructor - * @final - */ -goog.fs.ProgressEvent = function(event, target) { - goog.fs.ProgressEvent.base(this, 'constructor', event.type, target); - - /** - * The underlying event object. - * @type {!ProgressEvent} - * @private - */ - this.event_ = event; -}; -goog.inherits(goog.fs.ProgressEvent, goog.events.Event); - - -/** - * @return {boolean} Whether or not the total size of the of the file being - * saved is known. - */ -goog.fs.ProgressEvent.prototype.isLengthComputable = function() { - return this.event_.lengthComputable; -}; - - -/** - * @return {number} The number of bytes saved so far. - */ -goog.fs.ProgressEvent.prototype.getLoaded = function() { - return this.event_.loaded; -}; - - -/** - * @return {number} The total number of bytes in the file being saved. - */ -goog.fs.ProgressEvent.prototype.getTotal = function() { - return this.event_.total; -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A wrapper for the HTML5 FileReader object. - * - */ - -goog.provide('goog.fs.FileReader'); -goog.provide('goog.fs.FileReader.EventType'); -goog.provide('goog.fs.FileReader.ReadyState'); - -goog.require('goog.async.Deferred'); -goog.require('goog.events.EventTarget'); -goog.require('goog.fs.Error'); -goog.require('goog.fs.ProgressEvent'); - - - -/** - * An object for monitoring the reading of files. This emits ProgressEvents of - * the types listed in {@link goog.fs.FileReader.EventType}. - * - * @constructor - * @extends {goog.events.EventTarget} - * @final - */ -goog.fs.FileReader = function() { - goog.fs.FileReader.base(this, 'constructor'); - - /** - * The underlying FileReader object. - * - * @type {!FileReader} - * @private - */ - this.reader_ = new FileReader(); - - this.reader_.onloadstart = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onprogress = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onload = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onabort = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onerror = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onloadend = goog.bind(this.dispatchProgressEvent_, this); -}; -goog.inherits(goog.fs.FileReader, goog.events.EventTarget); - - -/** - * Possible states for a FileReader. - * - * @enum {number} - */ -goog.fs.FileReader.ReadyState = { - /** - * The object has been constructed, but there is no pending read. - */ - INIT: 0, - /** - * Data is being read. - */ - LOADING: 1, - /** - * The data has been read from the file, the read was aborted, or an error - * occurred. - */ - DONE: 2 -}; - - -/** - * Events emitted by a FileReader. - * - * @enum {string} - */ -goog.fs.FileReader.EventType = { - /** - * Emitted when the reading begins. readyState will be LOADING. - */ - LOAD_START: 'loadstart', - /** - * Emitted when progress has been made in reading the file. readyState will be - * LOADING. - */ - PROGRESS: 'progress', - /** - * Emitted when the data has been successfully read. readyState will be - * LOADING. - */ - LOAD: 'load', - /** - * Emitted when the reading has been aborted. readyState will be LOADING. - */ - ABORT: 'abort', - /** - * Emitted when an error is encountered or the reading has been aborted. - * readyState will be LOADING. - */ - ERROR: 'error', - /** - * Emitted when the reading is finished, whether successfully or not. - * readyState will be DONE. - */ - LOAD_END: 'loadend' -}; - - -/** - * Abort the reading of the file. - */ -goog.fs.FileReader.prototype.abort = function() { - try { - this.reader_.abort(); - } catch (e) { - throw new goog.fs.Error(e, 'aborting read'); - } -}; - - -/** - * @return {goog.fs.FileReader.ReadyState} The current state of the FileReader. - */ -goog.fs.FileReader.prototype.getReadyState = function() { - return /** @type {goog.fs.FileReader.ReadyState} */ (this.reader_.readyState); -}; - - -/** - * @return {*} The result of the file read. - */ -goog.fs.FileReader.prototype.getResult = function() { - return this.reader_.result; -}; - - -/** - * @return {goog.fs.Error} The error encountered while reading, if any. - */ -goog.fs.FileReader.prototype.getError = function() { - return this.reader_.error && - new goog.fs.Error(this.reader_.error, 'reading file'); -}; - - -/** - * Wrap a progress event emitted by the underlying file reader and re-emit it. - * - * @param {!ProgressEvent} event The underlying event. - * @private - */ -goog.fs.FileReader.prototype.dispatchProgressEvent_ = function(event) { - this.dispatchEvent(new goog.fs.ProgressEvent(event, this)); -}; - - -/** @override */ -goog.fs.FileReader.prototype.disposeInternal = function() { - goog.fs.FileReader.base(this, 'disposeInternal'); - delete this.reader_; -}; - - -/** - * Starts reading a blob as a binary string. - * @param {!Blob} blob The blob to read. - */ -goog.fs.FileReader.prototype.readAsBinaryString = function(blob) { - this.reader_.readAsBinaryString(blob); -}; - - -/** - * Reads a blob as a binary string. - * @param {!Blob} blob The blob to read. - * @return {!goog.async.Deferred} The deferred Blob contents as a binary string. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsBinaryString = function(blob) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsBinaryString(blob); - return d; -}; - - -/** - * Starts reading a blob as an array buffer. - * @param {!Blob} blob The blob to read. - */ -goog.fs.FileReader.prototype.readAsArrayBuffer = function(blob) { - this.reader_.readAsArrayBuffer(blob); -}; - - -/** - * Reads a blob as an array buffer. - * @param {!Blob} blob The blob to read. - * @return {!goog.async.Deferred} The deferred Blob contents as an array buffer. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsArrayBuffer = function(blob) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsArrayBuffer(blob); - return d; -}; - - -/** - * Starts reading a blob as text. - * @param {!Blob} blob The blob to read. - * @param {string=} opt_encoding The name of the encoding to use. - */ -goog.fs.FileReader.prototype.readAsText = function(blob, opt_encoding) { - this.reader_.readAsText(blob, opt_encoding); -}; - - -/** - * Reads a blob as text. - * @param {!Blob} blob The blob to read. - * @param {string=} opt_encoding The name of the encoding to use. - * @return {!goog.async.Deferred} The deferred Blob contents as text. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsText = function(blob, opt_encoding) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsText(blob, opt_encoding); - return d; -}; - - -/** - * Starts reading a blob as a data URL. - * @param {!Blob} blob The blob to read. - */ -goog.fs.FileReader.prototype.readAsDataUrl = function(blob) { - this.reader_.readAsDataURL(blob); -}; - - -/** - * Reads a blob as a data URL. - * @param {!Blob} blob The blob to read. - * @return {!goog.async.Deferred} The deferred Blob contents as a data URL. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsDataUrl = function(blob) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsDataUrl(blob); - return d; -}; - - -/** - * Creates a new deferred object for the results of a read method. - * @param {goog.fs.FileReader} reader The reader to create a deferred for. - * @return {!goog.async.Deferred} The deferred results. - * @private - */ -goog.fs.FileReader.createDeferred_ = function(reader) { - var deferred = new goog.async.Deferred(); - reader.listen(goog.fs.FileReader.EventType.LOAD_END, - goog.partial(function(d, r, e) { - var result = r.getResult(); - var error = r.getError(); - if (result != null && !error) { - d.callback(result); - } else { - d.errback(error); - } - r.dispose(); - }, deferred, reader)); - return deferred; -}; - -// FIXME should handle all geo-referenced data, not just vector data - -goog.provide('ol.interaction.DragAndDrop'); -goog.provide('ol.interaction.DragAndDropEvent'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.FileDropHandler'); -goog.require('goog.events.FileDropHandler.EventType'); -goog.require('goog.fs.FileReader'); -goog.require('goog.functions'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.proj'); - - - -/** - * @classdesc - * Handles input of vector data by drag and drop. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @fires ol.interaction.DragAndDropEvent - * @param {olx.interaction.DragAndDropOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragAndDrop = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this, { - handleEvent: ol.interaction.DragAndDrop.handleEvent - }); - - /** - * @private - * @type {Array.<function(new: ol.format.Feature)>} - */ - this.formatConstructors_ = options.formatConstructors ? - options.formatConstructors : []; - - /** - * @private - * @type {ol.proj.Projection} - */ - this.projection_ = options.projection ? - ol.proj.get(options.projection) : null; - - /** - * @private - * @type {goog.events.FileDropHandler} - */ - this.fileDropHandler_ = null; - - /** - * @private - * @type {goog.events.Key|undefined} - */ - this.dropListenKey_ = undefined; - -}; -goog.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction); - - -/** - * @inheritDoc - */ -ol.interaction.DragAndDrop.prototype.disposeInternal = function() { - if (this.dropListenKey_) { - goog.events.unlistenByKey(this.dropListenKey_); - } - goog.base(this, 'disposeInternal'); -}; - - -/** - * @param {goog.events.BrowserEvent} event Event. - * @private - */ -ol.interaction.DragAndDrop.prototype.handleDrop_ = function(event) { - var files = event.getBrowserEvent().dataTransfer.files; - var i, ii, file; - for (i = 0, ii = files.length; i < ii; ++i) { - file = files[i]; - // The empty string param is a workaround for - // https://code.google.com/p/closure-library/issues/detail?id=524 - var reader = goog.fs.FileReader.readAsText(file, ''); - reader.addCallback(goog.partial(this.handleResult_, file), this); - } -}; - - -/** - * @param {File} file File. - * @param {string} result Result. - * @private - */ -ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, result) { - var map = this.getMap(); - goog.asserts.assert(map, 'map must be set'); - var projection = this.projection_; - if (!projection) { - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - projection = view.getProjection(); - goog.asserts.assert(projection !== undefined, - 'projection should be defined'); - } - var formatConstructors = this.formatConstructors_; - var features = []; - var i, ii; - for (i = 0, ii = formatConstructors.length; i < ii; ++i) { - var formatConstructor = formatConstructors[i]; - var format = new formatConstructor(); - var readFeatures = this.tryReadFeatures_(format, result); - if (readFeatures) { - var featureProjection = format.readProjection(result); - var transform = ol.proj.getTransform(featureProjection, projection); - var j, jj; - for (j = 0, jj = readFeatures.length; j < jj; ++j) { - var feature = readFeatures[j]; - var geometry = feature.getGeometry(); - if (geometry) { - geometry.applyTransform(transform); - } - features.push(feature); - } - } - } - this.dispatchEvent( - new ol.interaction.DragAndDropEvent( - ol.interaction.DragAndDropEventType.ADD_FEATURES, this, file, - features, projection)); -}; - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and - * neither prevents the browser default nor stops event propagation. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.DragAndDrop} - * @api - */ -ol.interaction.DragAndDrop.handleEvent = goog.functions.TRUE; - - -/** - * @inheritDoc - */ -ol.interaction.DragAndDrop.prototype.setMap = function(map) { - if (this.dropListenKey_) { - goog.events.unlistenByKey(this.dropListenKey_); - this.dropListenKey_ = undefined; - } - if (this.fileDropHandler_) { - goog.dispose(this.fileDropHandler_); - this.fileDropHandler_ = null; - } - goog.asserts.assert(this.dropListenKey_ === undefined, - 'this.dropListenKey_ should be undefined'); - goog.base(this, 'setMap', map); - if (map) { - this.fileDropHandler_ = new goog.events.FileDropHandler(map.getViewport()); - this.dropListenKey_ = goog.events.listen( - this.fileDropHandler_, goog.events.FileDropHandler.EventType.DROP, - this.handleDrop_, false, this); - } -}; - - -/** - * @param {ol.format.Feature} format Format. - * @param {string} text Text. - * @private - * @return {Array.<ol.Feature>} Features. - */ -ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text) { - try { - return format.readFeatures(text); - } catch (e) { - return null; - } -}; - - -/** - * @enum {string} - */ -ol.interaction.DragAndDropEventType = { - /** - * Triggered when features are added - * @event ol.interaction.DragAndDropEvent#addfeatures - * @api stable - */ - ADD_FEATURES: 'addfeatures' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances - * of this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.interaction.DragAndDropEvent} - * @param {ol.interaction.DragAndDropEventType} type Type. - * @param {Object} target Target. - * @param {File} file File. - * @param {Array.<ol.Feature>=} opt_features Features. - * @param {ol.proj.Projection=} opt_projection Projection. - */ -ol.interaction.DragAndDropEvent = - function(type, target, file, opt_features, opt_projection) { - - goog.base(this, type, target); - - /** - * The features parsed from dropped data. - * @type {Array.<ol.Feature>|undefined} - * @api stable - */ - this.features = opt_features; - - /** - * The dropped file. - * @type {File} - * @api stable - */ - this.file = file; - - /** - * The feature projection. - * @type {ol.proj.Projection|undefined} - * @api - */ - this.projection = opt_projection; - -}; -goog.inherits(ol.interaction.DragAndDropEvent, goog.events.Event); - -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Defines a 2-element vector class that can be used for - * coordinate math, useful for animation systems and point manipulation. - * - * Vec2 objects inherit from goog.math.Coordinate and may be used wherever a - * Coordinate is required. Where appropriate, Vec2 functions accept both Vec2 - * and Coordinate objects as input. - * - * @author brenneman@google.com (Shawn Brenneman) - */ - -goog.provide('goog.math.Vec2'); - -goog.require('goog.math'); -goog.require('goog.math.Coordinate'); - - - -/** - * Class for a two-dimensional vector object and assorted functions useful for - * manipulating points. - * - * @param {number} x The x coordinate for the vector. - * @param {number} y The y coordinate for the vector. - * @struct - * @constructor - * @extends {goog.math.Coordinate} - */ -goog.math.Vec2 = function(x, y) { - /** - * X-value - * @type {number} - */ - this.x = x; - - /** - * Y-value - * @type {number} - */ - this.y = y; -}; -goog.inherits(goog.math.Vec2, goog.math.Coordinate); - - -/** - * @return {!goog.math.Vec2} A random unit-length vector. - */ -goog.math.Vec2.randomUnit = function() { - var angle = Math.random() * Math.PI * 2; - return new goog.math.Vec2(Math.cos(angle), Math.sin(angle)); -}; - - -/** - * @return {!goog.math.Vec2} A random vector inside the unit-disc. - */ -goog.math.Vec2.random = function() { - var mag = Math.sqrt(Math.random()); - var angle = Math.random() * Math.PI * 2; - - return new goog.math.Vec2(Math.cos(angle) * mag, Math.sin(angle) * mag); -}; - - -/** - * Returns a new Vec2 object from a given coordinate. - * @param {!goog.math.Coordinate} a The coordinate. - * @return {!goog.math.Vec2} A new vector object. - */ -goog.math.Vec2.fromCoordinate = function(a) { - return new goog.math.Vec2(a.x, a.y); -}; - - -/** - * @return {!goog.math.Vec2} A new vector with the same coordinates as this one. - * @override - */ -goog.math.Vec2.prototype.clone = function() { - return new goog.math.Vec2(this.x, this.y); -}; - - -/** - * Returns the magnitude of the vector measured from the origin. - * @return {number} The length of the vector. - */ -goog.math.Vec2.prototype.magnitude = function() { - return Math.sqrt(this.x * this.x + this.y * this.y); -}; - - -/** - * Returns the squared magnitude of the vector measured from the origin. - * NOTE(brenneman): Leaving out the square root is not a significant - * optimization in JavaScript. - * @return {number} The length of the vector, squared. - */ -goog.math.Vec2.prototype.squaredMagnitude = function() { - return this.x * this.x + this.y * this.y; -}; - - -/** - * @return {!goog.math.Vec2} This coordinate after scaling. - * @override - */ -goog.math.Vec2.prototype.scale = - /** @type {function(number, number=):!goog.math.Vec2} */ - (goog.math.Coordinate.prototype.scale); - - -/** - * Reverses the sign of the vector. Equivalent to scaling the vector by -1. - * @return {!goog.math.Vec2} The inverted vector. - */ -goog.math.Vec2.prototype.invert = function() { - this.x = -this.x; - this.y = -this.y; - return this; -}; - - -/** - * Normalizes the current vector to have a magnitude of 1. - * @return {!goog.math.Vec2} The normalized vector. - */ -goog.math.Vec2.prototype.normalize = function() { - return this.scale(1 / this.magnitude()); -}; - - -/** - * Adds another vector to this vector in-place. - * @param {!goog.math.Coordinate} b The vector to add. - * @return {!goog.math.Vec2} This vector with {@code b} added. - */ -goog.math.Vec2.prototype.add = function(b) { - this.x += b.x; - this.y += b.y; - return this; -}; - - -/** - * Subtracts another vector from this vector in-place. - * @param {!goog.math.Coordinate} b The vector to subtract. - * @return {!goog.math.Vec2} This vector with {@code b} subtracted. - */ -goog.math.Vec2.prototype.subtract = function(b) { - this.x -= b.x; - this.y -= b.y; - return this; -}; - - -/** - * Rotates this vector in-place by a given angle, specified in radians. - * @param {number} angle The angle, in radians. - * @return {!goog.math.Vec2} This vector rotated {@code angle} radians. - */ -goog.math.Vec2.prototype.rotate = function(angle) { - var cos = Math.cos(angle); - var sin = Math.sin(angle); - var newX = this.x * cos - this.y * sin; - var newY = this.y * cos + this.x * sin; - this.x = newX; - this.y = newY; - return this; -}; - - -/** - * Rotates a vector by a given angle, specified in radians, relative to a given - * axis rotation point. The returned vector is a newly created instance - no - * in-place changes are done. - * @param {!goog.math.Vec2} v A vector. - * @param {!goog.math.Vec2} axisPoint The rotation axis point. - * @param {number} angle The angle, in radians. - * @return {!goog.math.Vec2} The rotated vector in a newly created instance. - */ -goog.math.Vec2.rotateAroundPoint = function(v, axisPoint, angle) { - var res = v.clone(); - return res.subtract(axisPoint).rotate(angle).add(axisPoint); -}; - - -/** - * Compares this vector with another for equality. - * @param {!goog.math.Vec2} b The other vector. - * @return {boolean} Whether this vector has the same x and y as the given - * vector. - */ -goog.math.Vec2.prototype.equals = function(b) { - return this == b || !!b && this.x == b.x && this.y == b.y; -}; - - -/** - * Returns the distance between two vectors. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {number} The distance. - */ -goog.math.Vec2.distance = goog.math.Coordinate.distance; - - -/** - * Returns the squared distance between two vectors. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {number} The squared distance. - */ -goog.math.Vec2.squaredDistance = goog.math.Coordinate.squaredDistance; - - -/** - * Compares vectors for equality. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {boolean} Whether the vectors have the same x and y coordinates. - */ -goog.math.Vec2.equals = goog.math.Coordinate.equals; - - -/** - * Returns the sum of two vectors as a new Vec2. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {!goog.math.Vec2} The sum vector. - */ -goog.math.Vec2.sum = function(a, b) { - return new goog.math.Vec2(a.x + b.x, a.y + b.y); -}; - - -/** - * Returns the difference between two vectors as a new Vec2. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {!goog.math.Vec2} The difference vector. - */ -goog.math.Vec2.difference = function(a, b) { - return new goog.math.Vec2(a.x - b.x, a.y - b.y); -}; - - -/** - * Returns the dot-product of two vectors. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {number} The dot-product of the two vectors. - */ -goog.math.Vec2.dot = function(a, b) { - return a.x * b.x + a.y * b.y; -}; - - -/** - * Returns the determinant of two vectors. - * @param {!goog.math.Vec2} a The first vector. - * @param {!goog.math.Vec2} b The second vector. - * @return {number} The determinant of the two vectors. - */ -goog.math.Vec2.determinant = function(a, b) { - return a.x * b.y - a.y * b.x; -}; - - -/** - * Returns a new Vec2 that is the linear interpolant between vectors a and b at - * scale-value x. - * @param {!goog.math.Coordinate} a Vector a. - * @param {!goog.math.Coordinate} b Vector b. - * @param {number} x The proportion between a and b. - * @return {!goog.math.Vec2} The interpolated vector. - */ -goog.math.Vec2.lerp = function(a, b, x) { - return new goog.math.Vec2(goog.math.lerp(a.x, b.x, x), - goog.math.lerp(a.y, b.y, x)); -}; - -goog.provide('ol.interaction.DragRotateAndZoom'); - -goog.require('goog.math.Vec2'); -goog.require('ol'); -goog.require('ol.ViewHint'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); - - - -/** - * @classdesc - * Allows the user to zoom and rotate the map by clicking and dragging - * on the map. By default, this interaction is limited to when the shift - * key is held down. - * - * This interaction is only supported for mouse devices. - * - * And this interaction is not included in the default interactions. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.DragRotateAndZoomOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragRotateAndZoom = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this, { - handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_, - handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_, - handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_ - }); - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.shiftKeyOnly; - - /** - * @private - * @type {number|undefined} - */ - this.lastAngle_ = undefined; - - /** - * @private - * @type {number|undefined} - */ - this.lastMagnitude_ = undefined; - - /** - * @private - * @type {number} - */ - this.lastScaleDelta_ = 0; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 400; - -}; -goog.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragRotateAndZoom} - * @private - */ -ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return; - } - - var map = mapBrowserEvent.map; - var size = map.getSize(); - var offset = mapBrowserEvent.pixel; - var delta = new goog.math.Vec2( - offset[0] - size[0] / 2, - size[1] / 2 - offset[1]); - var theta = Math.atan2(delta.y, delta.x); - var magnitude = delta.magnitude(); - var view = map.getView(); - map.render(); - if (this.lastAngle_ !== undefined) { - var angleDelta = theta - this.lastAngle_; - ol.interaction.Interaction.rotateWithoutConstraints( - map, view, view.getRotation() - angleDelta); - } - this.lastAngle_ = theta; - if (this.lastMagnitude_ !== undefined) { - var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude); - ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution); - } - if (this.lastMagnitude_ !== undefined) { - this.lastScaleDelta_ = this.lastMagnitude_ / magnitude; - } - this.lastMagnitude_ = magnitude; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragRotateAndZoom} - * @private - */ -ol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return true; - } - - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - var direction = this.lastScaleDelta_ - 1; - ol.interaction.Interaction.rotate(map, view, view.getRotation()); - ol.interaction.Interaction.zoom(map, view, view.getResolution(), - undefined, this.duration_, direction); - this.lastScaleDelta_ = 0; - return false; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragRotateAndZoom} - * @private - */ -ol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return false; - } - - if (this.condition_(mapBrowserEvent)) { - mapBrowserEvent.map.getView().setHint(ol.ViewHint.INTERACTING, 1); - this.lastAngle_ = undefined; - this.lastMagnitude_ = undefined; - return true; - } else { - return false; - } -}; - -goog.provide('ol.interaction.Draw'); -goog.provide('ol.interaction.DrawEvent'); -goog.provide('ol.interaction.DrawEventType'); -goog.provide('ol.interaction.DrawGeometryFunctionType'); -goog.provide('ol.interaction.DrawMode'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('ol.Collection'); -goog.require('ol.Coordinate'); -goog.require('ol.Feature'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.Object'); -goog.require('ol.coordinate'); -goog.require('ol.events.condition'); -goog.require('ol.geom.Circle'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.interaction.InteractionProperty'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.layer.Vector'); -goog.require('ol.source.Vector'); - - -/** - * @enum {string} - */ -ol.interaction.DrawEventType = { - /** - * Triggered upon feature draw start - * @event ol.interaction.DrawEvent#drawstart - * @api stable - */ - DRAWSTART: 'drawstart', - /** - * Triggered upon feature draw end - * @event ol.interaction.DrawEvent#drawend - * @api stable - */ - DRAWEND: 'drawend' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.interaction.Draw} instances are instances of - * this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.DrawEvent} - * @param {ol.interaction.DrawEventType} type Type. - * @param {ol.Feature} feature The feature drawn. - */ -ol.interaction.DrawEvent = function(type, feature) { - - goog.base(this, type); - - /** - * The feature being drawn. - * @type {ol.Feature} - * @api stable - */ - this.feature = feature; - -}; -goog.inherits(ol.interaction.DrawEvent, goog.events.Event); - - - -/** - * @classdesc - * Interaction for drawing feature geometries. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @fires ol.interaction.DrawEvent - * @param {olx.interaction.DrawOptions} options Options. - * @api stable - */ -ol.interaction.Draw = function(options) { - - goog.base(this, { - handleDownEvent: ol.interaction.Draw.handleDownEvent_, - handleEvent: ol.interaction.Draw.handleEvent, - handleUpEvent: ol.interaction.Draw.handleUpEvent_ - }); - - /** - * @type {ol.Pixel} - * @private - */ - this.downPx_ = null; - - /** - * @type {boolean} - * @private - */ - this.freehand_ = false; - - /** - * Target source for drawn features. - * @type {ol.source.Vector} - * @private - */ - this.source_ = options.source ? options.source : null; - - /** - * Target collection for drawn features. - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features ? options.features : null; - - /** - * Pixel distance for snapping. - * @type {number} - * @private - */ - this.snapTolerance_ = options.snapTolerance ? options.snapTolerance : 12; - - /** - * Geometry type. - * @type {ol.geom.GeometryType} - * @private - */ - this.type_ = options.type; - - /** - * Drawing mode (derived from geometry type. - * @type {ol.interaction.DrawMode} - * @private - */ - this.mode_ = ol.interaction.Draw.getMode_(this.type_); - - /** - * The number of points that must be drawn before a polygon ring or line - * string can be finished. The default is 3 for polygon rings and 2 for - * line strings. - * @type {number} - * @private - */ - this.minPoints_ = options.minPoints ? - options.minPoints : - (this.mode_ === ol.interaction.DrawMode.POLYGON ? 3 : 2); - - /** - * The number of points that can be drawn before a polygon ring or line string - * is finished. The default is no restriction. - * @type {number} - * @private - */ - this.maxPoints_ = options.maxPoints ? options.maxPoints : Infinity; - - var geometryFunction = options.geometryFunction; - if (!geometryFunction) { - if (this.type_ === ol.geom.GeometryType.CIRCLE) { - /** - * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates - * @param {ol.geom.SimpleGeometry=} opt_geometry - * @return {ol.geom.SimpleGeometry} - */ - geometryFunction = function(coordinates, opt_geometry) { - var circle = opt_geometry ? opt_geometry : - new ol.geom.Circle([NaN, NaN]); - goog.asserts.assertInstanceof(circle, ol.geom.Circle, - 'geometry must be an ol.geom.Circle'); - var squaredLength = ol.coordinate.squaredDistance( - coordinates[0], coordinates[1]); - circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength)); - return circle; - }; - } else { - var Constructor; - var mode = this.mode_; - if (mode === ol.interaction.DrawMode.POINT) { - Constructor = ol.geom.Point; - } else if (mode === ol.interaction.DrawMode.LINE_STRING) { - Constructor = ol.geom.LineString; - } else if (mode === ol.interaction.DrawMode.POLYGON) { - Constructor = ol.geom.Polygon; - } - /** - * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates - * @param {ol.geom.SimpleGeometry=} opt_geometry - * @return {ol.geom.SimpleGeometry} - */ - geometryFunction = function(coordinates, opt_geometry) { - var geometry = opt_geometry; - if (geometry) { - geometry.setCoordinates(coordinates); - } else { - geometry = new Constructor(coordinates); - } - return geometry; - }; - } - } - - /** - * @type {ol.interaction.DrawGeometryFunctionType} - * @private - */ - this.geometryFunction_ = geometryFunction; - - /** - * Finish coordinate for the feature (first point for polygons, last point for - * linestrings). - * @type {ol.Coordinate} - * @private - */ - this.finishCoordinate_ = null; - - /** - * Sketch feature. - * @type {ol.Feature} - * @private - */ - this.sketchFeature_ = null; - - /** - * Sketch point. - * @type {ol.Feature} - * @private - */ - this.sketchPoint_ = null; - - /** - * Sketch coordinates. Used when drawing a line or polygon. - * @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} - * @private - */ - this.sketchCoords_ = null; - - /** - * Sketch line. Used when drawing polygon. - * @type {ol.Feature} - * @private - */ - this.sketchLine_ = null; - - /** - * Sketch line coordinates. Used when drawing a polygon or circle. - * @type {Array.<ol.Coordinate>} - * @private - */ - this.sketchLineCoords_ = null; - - /** - * Squared tolerance for handling up events. If the squared distance - * between a down and up event is greater than this tolerance, up events - * will not be handled. - * @type {number} - * @private - */ - this.squaredClickTolerance_ = options.clickTolerance ? - options.clickTolerance * options.clickTolerance : 36; - - /** - * Draw overlay where our sketch features are drawn. - * @type {ol.layer.Vector} - * @private - */ - this.overlay_ = new ol.layer.Vector({ - source: new ol.source.Vector({ - useSpatialIndex: false, - wrapX: options.wrapX ? options.wrapX : false - }), - style: options.style ? options.style : - ol.interaction.Draw.getDefaultStyleFunction() - }); - - /** - * Name of the geometry attribute for newly created features. - * @type {string|undefined} - * @private - */ - this.geometryName_ = options.geometryName; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.noModifierKeys; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.freehandCondition_ = options.freehandCondition ? - options.freehandCondition : ol.events.condition.shiftKeyOnly; - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.interaction.InteractionProperty.ACTIVE), - this.updateState_, false, this); - -}; -goog.inherits(ol.interaction.Draw, ol.interaction.Pointer); - - -/** - * @return {ol.style.StyleFunction} Styles. - */ -ol.interaction.Draw.getDefaultStyleFunction = function() { - var styles = ol.style.createDefaultEditingStyles(); - return function(feature, resolution) { - return styles[feature.getGeometry().getType()]; - }; -}; - - -/** - * @inheritDoc - */ -ol.interaction.Draw.prototype.setMap = function(map) { - goog.base(this, 'setMap', map); - this.updateState_(); -}; - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may actually - * draw or finish the drawing. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Draw} - * @api - */ -ol.interaction.Draw.handleEvent = function(mapBrowserEvent) { - var pass = !this.freehand_; - if (this.freehand_ && - mapBrowserEvent.type === ol.MapBrowserEvent.EventType.POINTERDRAG) { - this.addToDrawing_(mapBrowserEvent); - pass = false; - } else if (mapBrowserEvent.type === - ol.MapBrowserEvent.EventType.POINTERMOVE) { - pass = this.handlePointerMove_(mapBrowserEvent); - } else if (mapBrowserEvent.type === ol.MapBrowserEvent.EventType.DBLCLICK) { - pass = false; - } - return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && pass; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.Draw} - * @private - */ -ol.interaction.Draw.handleDownEvent_ = function(event) { - if (this.condition_(event)) { - this.downPx_ = event.pixel; - return true; - } else if ((this.mode_ === ol.interaction.DrawMode.LINE_STRING || - this.mode_ === ol.interaction.DrawMode.POLYGON) && - this.freehandCondition_(event)) { - this.downPx_ = event.pixel; - this.freehand_ = true; - if (!this.finishCoordinate_) { - this.startDrawing_(event); - } - return true; - } else { - return false; - } -}; - - -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Draw} - * @private - */ -ol.interaction.Draw.handleUpEvent_ = function(event) { - this.freehand_ = false; - var downPx = this.downPx_; - var clickPx = event.pixel; - var dx = downPx[0] - clickPx[0]; - var dy = downPx[1] - clickPx[1]; - var squaredDistance = dx * dx + dy * dy; - var pass = true; - if (squaredDistance <= this.squaredClickTolerance_) { - this.handlePointerMove_(event); - if (!this.finishCoordinate_) { - this.startDrawing_(event); - if (this.mode_ === ol.interaction.DrawMode.POINT) { - this.finishDrawing(); - } - } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - this.finishDrawing(); - } else if (this.atFinish_(event)) { - this.finishDrawing(); - } else { - this.addToDrawing_(event); - } - pass = false; - } - return pass; -}; - - -/** - * Handle move events. - * @param {ol.MapBrowserEvent} event A move event. - * @return {boolean} Pass the event to other interactions. - * @private - */ -ol.interaction.Draw.prototype.handlePointerMove_ = function(event) { - if (this.finishCoordinate_) { - this.modifyDrawing_(event); - } else { - this.createOrUpdateSketchPoint_(event); - } - return true; -}; - - -/** - * Determine if an event is within the snapping tolerance of the start coord. - * @param {ol.MapBrowserEvent} event Event. - * @return {boolean} The event is within the snapping tolerance of the start. - * @private - */ -ol.interaction.Draw.prototype.atFinish_ = function(event) { - var at = false; - if (this.sketchFeature_) { - var potentiallyDone = false; - var potentiallyFinishCoordinates = [this.finishCoordinate_]; - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - potentiallyDone = this.sketchCoords_.length > this.minPoints_; - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - potentiallyDone = this.sketchCoords_[0].length > - this.minPoints_; - potentiallyFinishCoordinates = [this.sketchCoords_[0][0], - this.sketchCoords_[0][this.sketchCoords_[0].length - 2]]; - } - if (potentiallyDone) { - var map = event.map; - for (var i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) { - var finishCoordinate = potentiallyFinishCoordinates[i]; - var finishPixel = map.getPixelFromCoordinate(finishCoordinate); - var pixel = event.pixel; - var dx = pixel[0] - finishPixel[0]; - var dy = pixel[1] - finishPixel[1]; - var freehand = this.freehand_ && this.freehandCondition_(event); - var snapTolerance = freehand ? 1 : this.snapTolerance_; - at = Math.sqrt(dx * dx + dy * dy) <= snapTolerance; - if (at) { - this.finishCoordinate_ = finishCoordinate; - break; - } - } - } - } - return at; -}; - - -/** - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) { - var coordinates = event.coordinate.slice(); - if (!this.sketchPoint_) { - this.sketchPoint_ = new ol.Feature(new ol.geom.Point(coordinates)); - this.updateSketchFeatures_(); - } else { - var sketchPointGeom = this.sketchPoint_.getGeometry(); - goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point, - 'sketchPointGeom should be an ol.geom.Point'); - sketchPointGeom.setCoordinates(coordinates); - } -}; - - -/** - * Start the drawing. - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.startDrawing_ = function(event) { - var start = event.coordinate; - this.finishCoordinate_ = start; - if (this.mode_ === ol.interaction.DrawMode.POINT) { - this.sketchCoords_ = start.slice(); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - this.sketchCoords_ = [[start.slice(), start.slice()]]; - this.sketchLineCoords_ = this.sketchCoords_[0]; - } else { - this.sketchCoords_ = [start.slice(), start.slice()]; - if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - this.sketchLineCoords_ = this.sketchCoords_; - } - } - if (this.sketchLineCoords_) { - this.sketchLine_ = new ol.Feature( - new ol.geom.LineString(this.sketchLineCoords_)); - } - var geometry = this.geometryFunction_(this.sketchCoords_); - goog.asserts.assert(geometry !== undefined, 'geometry should be defined'); - this.sketchFeature_ = new ol.Feature(); - if (this.geometryName_) { - this.sketchFeature_.setGeometryName(this.geometryName_); - } - this.sketchFeature_.setGeometry(geometry); - this.updateSketchFeatures_(); - this.dispatchEvent(new ol.interaction.DrawEvent( - ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_)); -}; - - -/** - * Modify the drawing. - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.modifyDrawing_ = function(event) { - var coordinate = event.coordinate; - var geometry = this.sketchFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry should be ol.geom.SimpleGeometry or subclass'); - var coordinates, last; - if (this.mode_ === ol.interaction.DrawMode.POINT) { - last = this.sketchCoords_; - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - coordinates = this.sketchCoords_[0]; - last = coordinates[coordinates.length - 1]; - if (this.atFinish_(event)) { - // snap to finish - coordinate = this.finishCoordinate_.slice(); - } - } else { - coordinates = this.sketchCoords_; - last = coordinates[coordinates.length - 1]; - } - last[0] = coordinate[0]; - last[1] = coordinate[1]; - goog.asserts.assert(this.sketchCoords_, 'sketchCoords_ expected'); - this.geometryFunction_(this.sketchCoords_, geometry); - if (this.sketchPoint_) { - var sketchPointGeom = this.sketchPoint_.getGeometry(); - goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point, - 'sketchPointGeom should be an ol.geom.Point'); - sketchPointGeom.setCoordinates(coordinate); - } - var sketchLineGeom; - if (geometry instanceof ol.geom.Polygon && - this.mode_ !== ol.interaction.DrawMode.POLYGON) { - if (!this.sketchLine_) { - this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null)); - } - var ring = geometry.getLinearRing(0); - sketchLineGeom = this.sketchLine_.getGeometry(); - goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, - 'sketchLineGeom must be an ol.geom.LineString'); - sketchLineGeom.setFlatCoordinates( - ring.getLayout(), ring.getFlatCoordinates()); - } else if (this.sketchLineCoords_) { - sketchLineGeom = this.sketchLine_.getGeometry(); - goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, - 'sketchLineGeom must be an ol.geom.LineString'); - sketchLineGeom.setCoordinates(this.sketchLineCoords_); - } - this.updateSketchFeatures_(); -}; - - -/** - * Add a new coordinate to the drawing. - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.addToDrawing_ = function(event) { - var coordinate = event.coordinate; - var geometry = this.sketchFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry must be an ol.geom.SimpleGeometry'); - var done; - var coordinates; - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - this.finishCoordinate_ = coordinate.slice(); - coordinates = this.sketchCoords_; - coordinates.push(coordinate.slice()); - done = coordinates.length > this.maxPoints_; - this.geometryFunction_(coordinates, geometry); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - coordinates = this.sketchCoords_[0]; - coordinates.push(coordinate.slice()); - done = coordinates.length > this.maxPoints_; - if (done) { - this.finishCoordinate_ = coordinates[0]; - } - this.geometryFunction_(this.sketchCoords_, geometry); - } - this.updateSketchFeatures_(); - if (done) { - this.finishDrawing(); - } -}; - - -/** - * Remove last point of the feature currently being drawn. - * @api - */ -ol.interaction.Draw.prototype.removeLastPoint = function() { - var geometry = this.sketchFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry must be an ol.geom.SimpleGeometry'); - var coordinates, sketchLineGeom; - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - coordinates = this.sketchCoords_; - coordinates.splice(-2, 1); - this.geometryFunction_(coordinates, geometry); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - coordinates = this.sketchCoords_[0]; - coordinates.splice(-2, 1); - sketchLineGeom = this.sketchLine_.getGeometry(); - goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, - 'sketchLineGeom must be an ol.geom.LineString'); - sketchLineGeom.setCoordinates(coordinates); - this.geometryFunction_(this.sketchCoords_, geometry); - } - - if (coordinates.length === 0) { - this.finishCoordinate_ = null; - } - - this.updateSketchFeatures_(); -}; - - -/** - * Stop drawing and add the sketch feature to the target layer. - * The {@link ol.interaction.DrawEventType.DRAWEND} event is dispatched before - * inserting the feature. - * @api - */ -ol.interaction.Draw.prototype.finishDrawing = function() { - var sketchFeature = this.abortDrawing_(); - goog.asserts.assert(sketchFeature, 'sketchFeature expected to be truthy'); - var coordinates = this.sketchCoords_; - var geometry = sketchFeature.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry must be an ol.geom.SimpleGeometry'); - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - // remove the redundant last point - coordinates.pop(); - this.geometryFunction_(coordinates, geometry); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - // When we finish drawing a polygon on the last point, - // the last coordinate is duplicated as for LineString - // we force the replacement by the first point - coordinates[0].pop(); - coordinates[0].push(coordinates[0][0]); - this.geometryFunction_(coordinates, geometry); - } - - // cast multi-part geometries - if (this.type_ === ol.geom.GeometryType.MULTI_POINT) { - sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates])); - } else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) { - sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates])); - } else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) { - sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates])); - } - - // First dispatch event to allow full set up of feature - this.dispatchEvent(new ol.interaction.DrawEvent( - ol.interaction.DrawEventType.DRAWEND, sketchFeature)); - - // Then insert feature - if (this.features_) { - this.features_.push(sketchFeature); - } - if (this.source_) { - this.source_.addFeature(sketchFeature); - } -}; - - -/** - * Stop drawing without adding the sketch feature to the target layer. - * @return {ol.Feature} The sketch feature (or null if none). - * @private - */ -ol.interaction.Draw.prototype.abortDrawing_ = function() { - this.finishCoordinate_ = null; - var sketchFeature = this.sketchFeature_; - if (sketchFeature) { - this.sketchFeature_ = null; - this.sketchPoint_ = null; - this.sketchLine_ = null; - this.overlay_.getSource().clear(true); - } - return sketchFeature; -}; - - -/** - * Extend an existing geometry by adding additional points. This only works - * on features with `LineString` geometries, where the interaction will - * extend lines by adding points to the end of the coordinates array. - * @param {!ol.Feature} feature Feature to be extended. - * @api - */ -ol.interaction.Draw.prototype.extend = function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(this.mode_ == ol.interaction.DrawMode.LINE_STRING, - 'interaction mode must be "line"'); - goog.asserts.assert(geometry, 'feature must have a geometry'); - goog.asserts.assert(geometry.getType() == ol.geom.GeometryType.LINE_STRING, - 'feature geometry must be a line string'); - var lineString = /** @type {ol.geom.LineString} */ (geometry); - this.sketchFeature_ = feature; - this.sketchCoords_ = lineString.getCoordinates(); - var last = this.sketchCoords_[this.sketchCoords_.length - 1]; - this.finishCoordinate_ = last.slice(); - this.sketchCoords_.push(last.slice()); - this.updateSketchFeatures_(); - this.dispatchEvent(new ol.interaction.DrawEvent( - ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_)); -}; - - -/** - * @inheritDoc - */ -ol.interaction.Draw.prototype.shouldStopEvent = goog.functions.FALSE; - - -/** - * Redraw the sketch features. - * @private - */ -ol.interaction.Draw.prototype.updateSketchFeatures_ = function() { - var sketchFeatures = []; - if (this.sketchFeature_) { - sketchFeatures.push(this.sketchFeature_); - } - if (this.sketchLine_) { - sketchFeatures.push(this.sketchLine_); - } - if (this.sketchPoint_) { - sketchFeatures.push(this.sketchPoint_); - } - var overlaySource = this.overlay_.getSource(); - overlaySource.clear(true); - overlaySource.addFeatures(sketchFeatures); -}; - - -/** - * @private - */ -ol.interaction.Draw.prototype.updateState_ = function() { - var map = this.getMap(); - var active = this.getActive(); - if (!map || !active) { - this.abortDrawing_(); - } - this.overlay_.setMap(active ? map : null); -}; - - -/** - * Create a `geometryFunction` for `mode: 'Circle'` that will create a regular - * polygon with a user specified number of sides and start angle instead of an - * `ol.geom.Circle` geometry. - * @param {number=} opt_sides Number of sides of the regular polygon. Default is - * 32. - * @param {number=} opt_angle Angle of the first point in radians. 0 means East. - * Default is the angle defined by the heading from the center of the - * regular polygon to the current pointer position. - * @return {ol.interaction.DrawGeometryFunctionType} Function that draws a - * polygon. - * @api - */ -ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) { - return ( - /** - * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates - * @param {ol.geom.SimpleGeometry=} opt_geometry - * @return {ol.geom.SimpleGeometry} - */ - function(coordinates, opt_geometry) { - var center = coordinates[0]; - var end = coordinates[1]; - var radius = Math.sqrt( - ol.coordinate.squaredDistance(center, end)); - var geometry = opt_geometry ? opt_geometry : - ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides); - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry must be a polygon'); - var angle = opt_angle ? opt_angle : - Math.atan((end[1] - center[1]) / (end[0] - center[0])); - ol.geom.Polygon.makeRegular(geometry, center, radius, angle); - return geometry; - } - ); -}; - - -/** - * Get the drawing mode. The mode for mult-part geometries is the same as for - * their single-part cousins. - * @param {ol.geom.GeometryType} type Geometry type. - * @return {ol.interaction.DrawMode} Drawing mode. - * @private - */ -ol.interaction.Draw.getMode_ = function(type) { - var mode; - if (type === ol.geom.GeometryType.POINT || - type === ol.geom.GeometryType.MULTI_POINT) { - mode = ol.interaction.DrawMode.POINT; - } else if (type === ol.geom.GeometryType.LINE_STRING || - type === ol.geom.GeometryType.MULTI_LINE_STRING) { - mode = ol.interaction.DrawMode.LINE_STRING; - } else if (type === ol.geom.GeometryType.POLYGON || - type === ol.geom.GeometryType.MULTI_POLYGON) { - mode = ol.interaction.DrawMode.POLYGON; - } else if (type === ol.geom.GeometryType.CIRCLE) { - mode = ol.interaction.DrawMode.CIRCLE; - } - goog.asserts.assert(mode !== undefined, 'mode should be defined'); - return mode; -}; - - -/** - * Function that takes coordinates and an optional existing geometry as - * arguments, and returns a geometry. The optional existing geometry is the - * geometry that is returned when the function is called without a second - * argument. - * @typedef {function(!(ol.Coordinate|Array.<ol.Coordinate>| - * Array.<Array.<ol.Coordinate>>), ol.geom.SimpleGeometry=): - * ol.geom.SimpleGeometry} - * @api - */ -ol.interaction.DrawGeometryFunctionType; - - -/** - * Draw mode. This collapses multi-part geometry types with their single-part - * cousins. - * @enum {string} - */ -ol.interaction.DrawMode = { - POINT: 'Point', - LINE_STRING: 'LineString', - POLYGON: 'Polygon', - CIRCLE: 'Circle' -}; - -goog.provide('ol.interaction.Modify'); -goog.provide('ol.interaction.ModifyEvent'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.functions'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Feature'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserPointerEvent'); -goog.require('ol.ViewHint'); -goog.require('ol.coordinate'); -goog.require('ol.events.condition'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.layer.Vector'); -goog.require('ol.source.Vector'); -goog.require('ol.structs.RBush'); - - -/** - * @enum {string} - */ -ol.ModifyEventType = { - /** - * Triggered upon feature modification start - * @event ol.interaction.ModifyEvent#modifystart - * @api - */ - MODIFYSTART: 'modifystart', - /** - * Triggered upon feature modification end - * @event ol.interaction.ModifyEvent#modifyend - * @api - */ - MODIFYEND: 'modifyend' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.interaction.Modify} instances are instances of - * this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.ModifyEvent} - * @param {ol.ModifyEventType} type Type. - * @param {ol.Collection.<ol.Feature>} features The features modified. - * @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated - * {@link ol.MapBrowserPointerEvent}. - */ -ol.interaction.ModifyEvent = function(type, features, mapBrowserPointerEvent) { - - goog.base(this, type); - - /** - * The features being modified. - * @type {ol.Collection.<ol.Feature>} - * @api - */ - this.features = features; - - /** - * Associated {@link ol.MapBrowserPointerEvent}. - * @type {ol.MapBrowserPointerEvent} - * @api - */ - this.mapBrowserPointerEvent = mapBrowserPointerEvent; -}; -goog.inherits(ol.interaction.ModifyEvent, goog.events.Event); - - -/** - * @typedef {{depth: (Array.<number>|undefined), - * feature: ol.Feature, - * geometry: ol.geom.SimpleGeometry, - * index: (number|undefined), - * segment: Array.<ol.Extent>}} - */ -ol.interaction.SegmentDataType; - - - -/** - * @classdesc - * Interaction for modifying feature geometries. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.ModifyOptions} options Options. - * @fires ol.interaction.ModifyEvent - * @api - */ -ol.interaction.Modify = function(options) { - - goog.base(this, { - handleDownEvent: ol.interaction.Modify.handleDownEvent_, - handleDragEvent: ol.interaction.Modify.handleDragEvent_, - handleEvent: ol.interaction.Modify.handleEvent, - handleUpEvent: ol.interaction.Modify.handleUpEvent_ - }); - - /** - * @type {ol.events.ConditionType} - * @private - */ - this.deleteCondition_ = options.deleteCondition ? - options.deleteCondition : - /** @type {ol.events.ConditionType} */ (goog.functions.and( - ol.events.condition.noModifierKeys, - ol.events.condition.singleClick)); - - /** - * Editing vertex. - * @type {ol.Feature} - * @private - */ - this.vertexFeature_ = null; - - /** - * Segments intersecting {@link this.vertexFeature_} by segment uid. - * @type {Object.<string, boolean>} - * @private - */ - this.vertexSegments_ = null; - - /** - * @type {ol.Pixel} - * @private - */ - this.lastPixel_ = [0, 0]; - - /** - * Tracks if the next `singleclick` event should be ignored to prevent - * accidental deletion right after vertex creation. - * @type {boolean} - * @private - */ - this.ignoreNextSingleClick_ = false; - - /** - * @type {boolean} - * @private - */ - this.modified_ = false; - - /** - * Segment RTree for each layer - * @type {ol.structs.RBush.<ol.interaction.SegmentDataType>} - * @private - */ - this.rBush_ = new ol.structs.RBush(); - - /** - * @type {number} - * @private - */ - this.pixelTolerance_ = options.pixelTolerance !== undefined ? - options.pixelTolerance : 10; - - /** - * @type {boolean} - * @private - */ - this.snappedToVertex_ = false; - - /** - * Indicate whether the interaction is currently changing a feature's - * coordinates. - * @type {boolean} - * @private - */ - this.changingFeature_ = false; - - /** - * @type {Array} - * @private - */ - this.dragSegments_ = null; - - /** - * Draw overlay where sketch features are drawn. - * @type {ol.layer.Vector} - * @private - */ - this.overlay_ = new ol.layer.Vector({ - source: new ol.source.Vector({ - useSpatialIndex: false, - wrapX: !!options.wrapX - }), - style: options.style ? options.style : - ol.interaction.Modify.getDefaultStyleFunction(), - updateWhileAnimating: true, - updateWhileInteracting: true - }); - - /** - * @const - * @private - * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>} - */ - this.SEGMENT_WRITERS_ = { - 'Point': this.writePointGeometry_, - 'LineString': this.writeLineStringGeometry_, - 'LinearRing': this.writeLineStringGeometry_, - 'Polygon': this.writePolygonGeometry_, - 'MultiPoint': this.writeMultiPointGeometry_, - 'MultiLineString': this.writeMultiLineStringGeometry_, - 'MultiPolygon': this.writeMultiPolygonGeometry_, - 'GeometryCollection': this.writeGeometryCollectionGeometry_ - }; - - /** - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features; - - this.features_.forEach(this.addFeature_, this); - goog.events.listen(this.features_, ol.CollectionEventType.ADD, - this.handleFeatureAdd_, false, this); - goog.events.listen(this.features_, ol.CollectionEventType.REMOVE, - this.handleFeatureRemove_, false, this); - -}; -goog.inherits(ol.interaction.Modify, ol.interaction.Pointer); - - -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Modify.prototype.addFeature_ = function(feature) { - var geometry = feature.getGeometry(); - if (geometry.getType() in this.SEGMENT_WRITERS_) { - this.SEGMENT_WRITERS_[geometry.getType()].call(this, feature, geometry); - } - var map = this.getMap(); - if (map) { - this.handlePointerAtPixel_(this.lastPixel_, map); - } - goog.events.listen(feature, goog.events.EventType.CHANGE, - this.handleFeatureChange_, false, this); -}; - - -/** - * @param {ol.MapBrowserPointerEvent} evt Map browser event - * @private - */ -ol.interaction.Modify.prototype.willModifyFeatures_ = function(evt) { - if (!this.modified_) { - this.modified_ = true; - this.dispatchEvent(new ol.interaction.ModifyEvent( - ol.ModifyEventType.MODIFYSTART, this.features_, evt)); - } -}; - - -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Modify.prototype.removeFeature_ = function(feature) { - this.removeFeatureSegmentData_(feature); - // Remove the vertex feature if the collection of canditate features - // is empty. - if (this.vertexFeature_ && this.features_.getLength() === 0) { - this.overlay_.getSource().removeFeature(this.vertexFeature_); - this.vertexFeature_ = null; - } - goog.events.unlisten(feature, goog.events.EventType.CHANGE, - this.handleFeatureChange_, false, this); -}; - - -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) { - var rBush = this.rBush_; - var /** @type {Array.<ol.interaction.SegmentDataType>} */ nodesToRemove = []; - rBush.forEach( - /** - * @param {ol.interaction.SegmentDataType} node RTree node. - */ - function(node) { - if (feature === node.feature) { - nodesToRemove.push(node); - } - }); - for (var i = nodesToRemove.length - 1; i >= 0; --i) { - rBush.remove(nodesToRemove[i]); - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.Modify.prototype.setMap = function(map) { - this.overlay_.setMap(map); - goog.base(this, 'setMap', map); -}; - - -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) { - var feature = evt.element; - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - this.addFeature_(feature); -}; - - -/** - * @param {goog.events.Event} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) { - if (!this.changingFeature_) { - var feature = /** @type {ol.Feature} */ (evt.target); - this.removeFeature_(feature); - this.addFeature_(feature); - } -}; - - -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) { - var feature = /** @type {ol.Feature} */ (evt.element); - this.removeFeature_(feature); -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Point} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writePointGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPoint} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeMultiPointGeometry_ = - function(feature, geometry) { - var points = geometry.getCoordinates(); - var coordinates, i, ii, segmentData; - for (i = 0, ii = points.length; i < ii; ++i) { - coordinates = points[i]; - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [i], - index: i, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.LineString} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeLineStringGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var i, ii, segment, segmentData; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiLineString} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeMultiLineStringGeometry_ = - function(feature, geometry) { - var lines = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = lines.length; j < jj; ++j) { - coordinates = lines[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [j], - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Polygon} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writePolygonGeometry_ = - function(feature, geometry) { - var rings = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [j], - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPolygon} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeMultiPolygonGeometry_ = - function(feature, geometry) { - var polygons = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData; - for (k = 0, kk = polygons.length; k < kk; ++k) { - rings = polygons[k]; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [j, k], - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.GeometryCollection} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeGeometryCollectionGeometry_ = - function(feature, geometry) { - var i, geometries = geometry.getGeometriesArray(); - for (i = 0; i < geometries.length; ++i) { - this.SEGMENT_WRITERS_[geometries[i].getType()].call( - this, feature, geometries[i]); - } -}; - - -/** - * @param {ol.Coordinate} coordinates Coordinates. - * @return {ol.Feature} Vertex feature. - * @private - */ -ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = - function(coordinates) { - var vertexFeature = this.vertexFeature_; - if (!vertexFeature) { - vertexFeature = new ol.Feature(new ol.geom.Point(coordinates)); - this.vertexFeature_ = vertexFeature; - this.overlay_.getSource().addFeature(vertexFeature); - } else { - var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry()); - geometry.setCoordinates(coordinates); - } - return vertexFeature; -}; - - -/** - * @param {ol.interaction.SegmentDataType} a - * @param {ol.interaction.SegmentDataType} b - * @return {number} - * @private - */ -ol.interaction.Modify.compareIndexes_ = function(a, b) { - return a.index - b.index; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.Modify} - * @private - */ -ol.interaction.Modify.handleDownEvent_ = function(evt) { - this.handlePointerAtPixel_(evt.pixel, evt.map); - this.dragSegments_ = []; - this.modified_ = false; - var vertexFeature = this.vertexFeature_; - if (vertexFeature) { - var insertVertices = []; - var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry()); - var vertex = geometry.getCoordinates(); - var vertexExtent = ol.extent.boundingExtent([vertex]); - var segmentDataMatches = this.rBush_.getInExtent(vertexExtent); - var componentSegments = {}; - segmentDataMatches.sort(ol.interaction.Modify.compareIndexes_); - for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) { - var segmentDataMatch = segmentDataMatches[i]; - var segment = segmentDataMatch.segment; - var uid = goog.getUid(segmentDataMatch.feature); - var depth = segmentDataMatch.depth; - if (depth) { - uid += '-' + depth.join('-'); // separate feature components - } - if (!componentSegments[uid]) { - componentSegments[uid] = new Array(2); - } - if (ol.coordinate.equals(segment[0], vertex) && - !componentSegments[uid][0]) { - this.dragSegments_.push([segmentDataMatch, 0]); - componentSegments[uid][0] = segmentDataMatch; - } else if (ol.coordinate.equals(segment[1], vertex) && - !componentSegments[uid][1]) { - - // prevent dragging closed linestrings by the connecting node - if ((segmentDataMatch.geometry.getType() === - ol.geom.GeometryType.LINE_STRING || - segmentDataMatch.geometry.getType() === - ol.geom.GeometryType.MULTI_LINE_STRING) && - componentSegments[uid][0] && - componentSegments[uid][0].index === 0) { - continue; - } - - this.dragSegments_.push([segmentDataMatch, 1]); - componentSegments[uid][1] = segmentDataMatch; - } else if (goog.getUid(segment) in this.vertexSegments_ && - (!componentSegments[uid][0] && !componentSegments[uid][1])) { - insertVertices.push([segmentDataMatch, vertex]); - } - } - if (insertVertices.length) { - this.willModifyFeatures_(evt); - } - for (i = insertVertices.length - 1; i >= 0; --i) { - this.insertVertex_.apply(this, insertVertices[i]); - } - } - return !!this.vertexFeature_; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @this {ol.interaction.Modify} - * @private - */ -ol.interaction.Modify.handleDragEvent_ = function(evt) { - this.ignoreNextSingleClick_ = false; - this.willModifyFeatures_(evt); - - var vertex = evt.coordinate; - for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) { - var dragSegment = this.dragSegments_[i]; - var segmentData = dragSegment[0]; - var depth = segmentData.depth; - var geometry = segmentData.geometry; - var coordinates = geometry.getCoordinates(); - var segment = segmentData.segment; - var index = dragSegment[1]; - - while (vertex.length < geometry.getStride()) { - vertex.push(0); - } - - switch (geometry.getType()) { - case ol.geom.GeometryType.POINT: - coordinates = vertex; - segment[0] = segment[1] = vertex; - break; - case ol.geom.GeometryType.MULTI_POINT: - coordinates[segmentData.index] = vertex; - segment[0] = segment[1] = vertex; - break; - case ol.geom.GeometryType.LINE_STRING: - coordinates[segmentData.index + index] = vertex; - segment[index] = vertex; - break; - case ol.geom.GeometryType.MULTI_LINE_STRING: - coordinates[depth[0]][segmentData.index + index] = vertex; - segment[index] = vertex; - break; - case ol.geom.GeometryType.POLYGON: - coordinates[depth[0]][segmentData.index + index] = vertex; - segment[index] = vertex; - break; - case ol.geom.GeometryType.MULTI_POLYGON: - coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex; - segment[index] = vertex; - break; - } - - this.setGeometryCoordinates_(geometry, coordinates); - } - this.createOrUpdateVertexFeature_(vertex); -}; - - -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Modify} - * @private - */ -ol.interaction.Modify.handleUpEvent_ = function(evt) { - var segmentData; - for (var i = this.dragSegments_.length - 1; i >= 0; --i) { - segmentData = this.dragSegments_[i][0]; - this.rBush_.update(ol.extent.boundingExtent(segmentData.segment), - segmentData); - } - if (this.modified_) { - this.dispatchEvent(new ol.interaction.ModifyEvent( - ol.ModifyEventType.MODIFYEND, this.features_, evt)); - this.modified_ = false; - } - return false; -}; - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may modify the - * geometry. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Modify} - * @api - */ -ol.interaction.Modify.handleEvent = function(mapBrowserEvent) { - if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) { - return true; - } - - var handled; - if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] && - mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE && - !this.handlingDownUpSequence) { - this.handlePointerMove_(mapBrowserEvent); - } - if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) { - if (mapBrowserEvent.type != ol.MapBrowserEvent.EventType.SINGLECLICK || - !this.ignoreNextSingleClick_) { - var geometry = this.vertexFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - this.willModifyFeatures_(mapBrowserEvent); - handled = this.removeVertex_(); - this.dispatchEvent(new ol.interaction.ModifyEvent( - ol.ModifyEventType.MODIFYEND, this.features_, mapBrowserEvent)); - this.modified_ = false; - } else { - handled = true; - } - } - - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK) { - this.ignoreNextSingleClick_ = false; - } - - return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && - !handled; -}; - - -/** - * @param {ol.MapBrowserEvent} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handlePointerMove_ = function(evt) { - this.lastPixel_ = evt.pixel; - this.handlePointerAtPixel_(evt.pixel, evt.map); -}; - - -/** - * @param {ol.Pixel} pixel Pixel - * @param {ol.Map} map Map. - * @private - */ -ol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) { - var pixelCoordinate = map.getCoordinateFromPixel(pixel); - var sortByDistance = function(a, b) { - return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a.segment) - - ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b.segment); - }; - - var lowerLeft = map.getCoordinateFromPixel( - [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]); - var upperRight = map.getCoordinateFromPixel( - [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]); - var box = ol.extent.boundingExtent([lowerLeft, upperRight]); - - var rBush = this.rBush_; - var nodes = rBush.getInExtent(box); - if (nodes.length > 0) { - nodes.sort(sortByDistance); - var node = nodes[0]; - var closestSegment = node.segment; - var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, - closestSegment)); - var vertexPixel = map.getPixelFromCoordinate(vertex); - if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= - this.pixelTolerance_) { - var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); - var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); - var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); - var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); - var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); - this.snappedToVertex_ = dist <= this.pixelTolerance_; - if (this.snappedToVertex_) { - vertex = squaredDist1 > squaredDist2 ? - closestSegment[1] : closestSegment[0]; - } - this.createOrUpdateVertexFeature_(vertex); - var vertexSegments = {}; - vertexSegments[goog.getUid(closestSegment)] = true; - var segment; - for (var i = 1, ii = nodes.length; i < ii; ++i) { - segment = nodes[i].segment; - if ((ol.coordinate.equals(closestSegment[0], segment[0]) && - ol.coordinate.equals(closestSegment[1], segment[1]) || - (ol.coordinate.equals(closestSegment[0], segment[1]) && - ol.coordinate.equals(closestSegment[1], segment[0])))) { - vertexSegments[goog.getUid(segment)] = true; - } else { - break; - } - } - this.vertexSegments_ = vertexSegments; - return; - } - } - if (this.vertexFeature_) { - this.overlay_.getSource().removeFeature(this.vertexFeature_); - this.vertexFeature_ = null; - } -}; - - -/** - * @param {ol.interaction.SegmentDataType} segmentData Segment data. - * @param {ol.Coordinate} vertex Vertex. - * @private - */ -ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) { - var segment = segmentData.segment; - var feature = segmentData.feature; - var geometry = segmentData.geometry; - var depth = segmentData.depth; - var index = segmentData.index; - var coordinates; - - while (vertex.length < geometry.getStride()) { - vertex.push(0); - } - - switch (geometry.getType()) { - case ol.geom.GeometryType.MULTI_LINE_STRING: - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - coordinates = geometry.getCoordinates(); - coordinates[depth[0]].splice(index + 1, 0, vertex); - break; - case ol.geom.GeometryType.POLYGON: - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - coordinates = geometry.getCoordinates(); - coordinates[depth[0]].splice(index + 1, 0, vertex); - break; - case ol.geom.GeometryType.MULTI_POLYGON: - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, - 'geometry should be an ol.geom.MultiPolygon'); - coordinates = geometry.getCoordinates(); - coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex); - break; - case ol.geom.GeometryType.LINE_STRING: - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - coordinates = geometry.getCoordinates(); - coordinates.splice(index + 1, 0, vertex); - break; - default: - return; - } - - this.setGeometryCoordinates_(geometry, coordinates); - var rTree = this.rBush_; - goog.asserts.assert(segment !== undefined, 'segment should be defined'); - rTree.remove(segmentData); - goog.asserts.assert(index !== undefined, 'index should be defined'); - this.updateSegmentIndices_(geometry, index, depth, 1); - var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - segment: [segment[0], vertex], - feature: feature, - geometry: geometry, - depth: depth, - index: index - }); - rTree.insert(ol.extent.boundingExtent(newSegmentData.segment), - newSegmentData); - this.dragSegments_.push([newSegmentData, 1]); - - var newSegmentData2 = /** @type {ol.interaction.SegmentDataType} */ ({ - segment: [vertex, segment[1]], - feature: feature, - geometry: geometry, - depth: depth, - index: index + 1 - }); - rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment), - newSegmentData2); - this.dragSegments_.push([newSegmentData2, 0]); - this.ignoreNextSingleClick_ = true; -}; - - -/** - * Removes a vertex from all matching features. - * @return {boolean} True when a vertex was removed. - * @private - */ -ol.interaction.Modify.prototype.removeVertex_ = function() { - var dragSegments = this.dragSegments_; - var segmentsByFeature = {}; - var component, coordinates, dragSegment, geometry, i, index, left; - var newIndex, newSegment, right, segmentData, uid, deleted; - for (i = dragSegments.length - 1; i >= 0; --i) { - dragSegment = dragSegments[i]; - segmentData = dragSegment[0]; - geometry = segmentData.geometry; - coordinates = geometry.getCoordinates(); - uid = goog.getUid(segmentData.feature); - if (segmentData.depth) { - // separate feature components - uid += '-' + segmentData.depth.join('-'); - } - left = right = index = undefined; - if (dragSegment[1] === 0) { - right = segmentData; - index = segmentData.index; - } else if (dragSegment[1] == 1) { - left = segmentData; - index = segmentData.index + 1; - } - if (!(uid in segmentsByFeature)) { - segmentsByFeature[uid] = [left, right, index]; - } - newSegment = segmentsByFeature[uid]; - if (left !== undefined) { - newSegment[0] = left; - } - if (right !== undefined) { - newSegment[1] = right; - } - if (newSegment[0] !== undefined && newSegment[1] !== undefined) { - component = coordinates; - deleted = false; - newIndex = index - 1; - switch (geometry.getType()) { - case ol.geom.GeometryType.MULTI_LINE_STRING: - coordinates[segmentData.depth[0]].splice(index, 1); - deleted = true; - break; - case ol.geom.GeometryType.LINE_STRING: - coordinates.splice(index, 1); - deleted = true; - break; - case ol.geom.GeometryType.MULTI_POLYGON: - component = component[segmentData.depth[1]]; - /* falls through */ - case ol.geom.GeometryType.POLYGON: - component = component[segmentData.depth[0]]; - if (component.length > 4) { - if (index == component.length - 1) { - index = 0; - } - component.splice(index, 1); - deleted = true; - if (index === 0) { - // close the ring again - component.pop(); - component.push(component[0]); - newIndex = component.length - 1; - } - } - break; - } - - if (deleted) { - this.rBush_.remove(newSegment[0]); - this.rBush_.remove(newSegment[1]); - this.setGeometryCoordinates_(geometry, coordinates); - goog.asserts.assert(newIndex >= 0, 'newIndex should be larger than 0'); - var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - depth: segmentData.depth, - feature: segmentData.feature, - geometry: segmentData.geometry, - index: newIndex, - segment: [newSegment[0].segment[0], newSegment[1].segment[1]] - }); - this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment), - newSegmentData); - this.updateSegmentIndices_(geometry, index, segmentData.depth, -1); - - if (this.vertexFeature_) { - this.overlay_.getSource().removeFeature(this.vertexFeature_); - this.vertexFeature_ = null; - } - } - } - } - return true; -}; - - -/** - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @param {Array} coordinates Coordinates. - * @private - */ -ol.interaction.Modify.prototype.setGeometryCoordinates_ = - function(geometry, coordinates) { - this.changingFeature_ = true; - geometry.setCoordinates(coordinates); - this.changingFeature_ = false; -}; - - -/** - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @param {number} index Index. - * @param {Array.<number>|undefined} depth Depth. - * @param {number} delta Delta (1 or -1). - * @private - */ -ol.interaction.Modify.prototype.updateSegmentIndices_ = function( - geometry, index, depth, delta) { - this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) { - if (segmentDataMatch.geometry === geometry && - (depth === undefined || segmentDataMatch.depth === undefined || - goog.array.equals( - /** @type {null|{length: number}} */ (segmentDataMatch.depth), - depth)) && - segmentDataMatch.index > index) { - segmentDataMatch.index += delta; - } - }); -}; - - -/** - * @return {ol.style.StyleFunction} Styles. - */ -ol.interaction.Modify.getDefaultStyleFunction = function() { - var style = ol.style.createDefaultEditingStyles(); - return function(feature, resolution) { - return style[ol.geom.GeometryType.POINT]; - }; -}; - -goog.provide('ol.interaction.Select'); -goog.provide('ol.interaction.SelectEvent'); -goog.provide('ol.interaction.SelectEventType'); -goog.provide('ol.interaction.SelectFilterFunction'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Feature'); -goog.require('ol.array'); -goog.require('ol.events.condition'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.layer.Vector'); -goog.require('ol.source.Vector'); - - -/** - * @enum {string} - */ -ol.interaction.SelectEventType = { - /** - * Triggered when feature(s) has been (de)selected. - * @event ol.interaction.SelectEvent#select - * @api - */ - SELECT: 'select' -}; - - -/** - * A function that takes an {@link ol.Feature} or {@link ol.render.Feature} and - * an {@link ol.layer.Layer} and returns `true` if the feature may be selected - * or `false` otherwise. - * @typedef {function((ol.Feature|ol.render.Feature), ol.layer.Layer): - * boolean} - * @api - */ -ol.interaction.SelectFilterFunction; - - - -/** - * @classdesc - * Events emitted by {@link ol.interaction.Select} instances are instances of - * this type. - * - * @param {string} type The event type. - * @param {Array.<ol.Feature>} selected Selected features. - * @param {Array.<ol.Feature>} deselected Deselected features. - * @param {ol.MapBrowserEvent} mapBrowserEvent Associated - * {@link ol.MapBrowserEvent}. - * @implements {oli.SelectEvent} - * @extends {goog.events.Event} - * @constructor - */ -ol.interaction.SelectEvent = - function(type, selected, deselected, mapBrowserEvent) { - goog.base(this, type); - - /** - * Selected features array. - * @type {Array.<ol.Feature>} - * @api - */ - this.selected = selected; - - /** - * Deselected features array. - * @type {Array.<ol.Feature>} - * @api - */ - this.deselected = deselected; - - /** - * Associated {@link ol.MapBrowserEvent}. - * @type {ol.MapBrowserEvent} - * @api - */ - this.mapBrowserEvent = mapBrowserEvent; -}; -goog.inherits(ol.interaction.SelectEvent, goog.events.Event); - - - -/** - * @classdesc - * Interaction for selecting vector features. By default, selected features are - * styled differently, so this interaction can be used for visual highlighting, - * as well as selecting features for other actions, such as modification or - * output. There are three ways of controlling which features are selected: - * using the browser event as defined by the `condition` and optionally the - * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a - * further feature filter using the `filter` option. - * - * Selected features are added to an internal unmanaged layer. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.SelectOptions=} opt_options Options. - * @fires ol.interaction.SelectEvent - * @api stable - */ -ol.interaction.Select = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.Select.handleEvent - }); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.singleClick; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.addCondition_ = options.addCondition ? - options.addCondition : ol.events.condition.never; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.removeCondition_ = options.removeCondition ? - options.removeCondition : ol.events.condition.never; - - /** - * @private - * @type {ol.events.ConditionType} - */ - this.toggleCondition_ = options.toggleCondition ? - options.toggleCondition : ol.events.condition.shiftKeyOnly; - - /** - * @private - * @type {boolean} - */ - this.multi_ = options.multi ? options.multi : false; - - /** - * @private - * @type {ol.interaction.SelectFilterFunction} - */ - this.filter_ = options.filter ? options.filter : - goog.functions.TRUE; - - var layerFilter; - if (options.layers) { - if (goog.isFunction(options.layers)) { - layerFilter = options.layers; - } else { - var layers = options.layers; - layerFilter = - /** - * @param {ol.layer.Layer} layer Layer. - * @return {boolean} Include. - */ - function(layer) { - return ol.array.includes(layers, layer); - }; - } - } else { - layerFilter = goog.functions.TRUE; - } - - /** - * @private - * @type {function(ol.layer.Layer): boolean} - */ - this.layerFilter_ = layerFilter; - - /** - * An association between selected feature (key) - * and layer (value) - * @private - * @type {Object.<number, ol.layer.Layer>} - */ - this.featureLayerAssociation_ = {}; - - /** - * @private - * @type {ol.layer.Vector} - */ - this.featureOverlay_ = new ol.layer.Vector({ - source: new ol.source.Vector({ - useSpatialIndex: false, - features: options.features, - wrapX: options.wrapX - }), - style: options.style ? options.style : - ol.interaction.Select.getDefaultStyleFunction(), - updateWhileAnimating: true, - updateWhileInteracting: true - }); - - var features = this.featureOverlay_.getSource().getFeaturesCollection(); - goog.events.listen(features, ol.CollectionEventType.ADD, - this.addFeature_, false, this); - goog.events.listen(features, ol.CollectionEventType.REMOVE, - this.removeFeature_, false, this); - -}; -goog.inherits(ol.interaction.Select, ol.interaction.Interaction); - - -/** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.layer.Layer} layer Layer. - * @private - */ -ol.interaction.Select.prototype.addFeatureLayerAssociation_ = - function(feature, layer) { - var key = goog.getUid(feature); - this.featureLayerAssociation_[key] = layer; -}; - - -/** - * Get the selected features. - * @return {ol.Collection.<ol.Feature>} Features collection. - * @api stable - */ -ol.interaction.Select.prototype.getFeatures = function() { - return this.featureOverlay_.getSource().getFeaturesCollection(); -}; - - -/** - * Returns the associated {@link ol.layer.Vector vectorlayer} of - * the (last) selected feature. Note that this will not work with any - * programmatic method like pushing features to - * {@link ol.interaction.Select#getFeatures collection}. - * @param {ol.Feature|ol.render.Feature} feature Feature - * @return {ol.layer.Vector} Layer. - * @api - */ -ol.interaction.Select.prototype.getLayer = function(feature) { - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - var key = goog.getUid(feature); - return /** @type {ol.layer.Vector} */ (this.featureLayerAssociation_[key]); -}; - - -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may change the - * selected state of features. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Select} - * @api - */ -ol.interaction.Select.handleEvent = function(mapBrowserEvent) { - if (!this.condition_(mapBrowserEvent)) { - return true; - } - var add = this.addCondition_(mapBrowserEvent); - var remove = this.removeCondition_(mapBrowserEvent); - var toggle = this.toggleCondition_(mapBrowserEvent); - var set = !add && !remove && !toggle; - var map = mapBrowserEvent.map; - var features = this.featureOverlay_.getSource().getFeaturesCollection(); - var /** @type {!Array.<ol.Feature>} */ deselected = []; - var /** @type {!Array.<ol.Feature>} */ selected = []; - var change = false; - if (set) { - // Replace the currently selected feature(s) with the feature(s) at the - // pixel, or clear the selected feature(s) if there is no feature at - // the pixel. - map.forEachFeatureAtPixel(mapBrowserEvent.pixel, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.layer.Layer} layer Layer. - */ - function(feature, layer) { - if (layer && this.filter_(feature, layer)) { - selected.push(feature); - this.addFeatureLayerAssociation_(feature, layer); - return !this.multi_; - } - }, this, this.layerFilter_); - if (selected.length > 0 && features.getLength() == 1 && - features.item(0) == selected[0]) { - // No change - } else { - change = true; - if (features.getLength() !== 0) { - deselected = Array.prototype.concat(features.getArray()); - features.clear(); - } - features.extend(selected); - // Modify object this.featureLayerAssociation_ - if (selected.length === 0) { - goog.object.clear(this.featureLayerAssociation_); - } else { - if (deselected.length > 0) { - deselected.forEach(function(feature) { - this.removeFeatureLayerAssociation_(feature); - }, this); - } - } - } - } else { - // Modify the currently selected feature(s). - map.forEachFeatureAtPixel(mapBrowserEvent.pixel, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.layer.Layer} layer Layer. - */ - function(feature, layer) { - if (!ol.array.includes(features.getArray(), feature)) { - if (add || toggle) { - if (this.filter_(feature, layer)) { - selected.push(feature); - this.addFeatureLayerAssociation_(feature, layer); - } - } - } else { - if (remove || toggle) { - deselected.push(feature); - this.removeFeatureLayerAssociation_(feature); - } - } - }, this, this.layerFilter_); - var i; - for (i = deselected.length - 1; i >= 0; --i) { - features.remove(deselected[i]); - } - features.extend(selected); - if (selected.length > 0 || deselected.length > 0) { - change = true; - } - } - if (change) { - this.dispatchEvent( - new ol.interaction.SelectEvent(ol.interaction.SelectEventType.SELECT, - selected, deselected, mapBrowserEvent)); - } - return ol.events.condition.pointerMove(mapBrowserEvent); -}; - - -/** - * Remove the interaction from its current map, if any, and attach it to a new - * map, if any. Pass `null` to just remove the interaction from the current map. - * @param {ol.Map} map Map. - * @api stable - */ -ol.interaction.Select.prototype.setMap = function(map) { - var currentMap = this.getMap(); - var selectedFeatures = - this.featureOverlay_.getSource().getFeaturesCollection(); - if (!goog.isNull(currentMap)) { - selectedFeatures.forEach(currentMap.unskipFeature, currentMap); - } - goog.base(this, 'setMap', map); - this.featureOverlay_.setMap(map); - if (!goog.isNull(map)) { - selectedFeatures.forEach(map.skipFeature, map); - } -}; - - -/** - * @return {ol.style.StyleFunction} Styles. - */ -ol.interaction.Select.getDefaultStyleFunction = function() { - var styles = ol.style.createDefaultEditingStyles(); - goog.array.extend(styles[ol.geom.GeometryType.POLYGON], - styles[ol.geom.GeometryType.LINE_STRING]); - goog.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION], - styles[ol.geom.GeometryType.LINE_STRING]); - - return function(feature, resolution) { - return styles[feature.getGeometry().getType()]; - }; -}; - - -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Select.prototype.addFeature_ = function(evt) { - var feature = evt.element; - var map = this.getMap(); - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - if (!goog.isNull(map)) { - map.skipFeature(feature); - } -}; - - -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Select.prototype.removeFeature_ = function(evt) { - var feature = evt.element; - var map = this.getMap(); - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - if (!goog.isNull(map)) { - map.unskipFeature(feature); - } -}; - - -/** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.interaction.Select.prototype.removeFeatureLayerAssociation_ = - function(feature) { - var key = goog.getUid(feature); - delete this.featureLayerAssociation_[key]; -}; - -goog.provide('ol.interaction.Snap'); -goog.provide('ol.interaction.SnapProperty'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEvent'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Extent'); -goog.require('ol.Feature'); -goog.require('ol.Object'); -goog.require('ol.Observable'); -goog.require('ol.coordinate'); -goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.source.Vector'); -goog.require('ol.source.VectorEvent'); -goog.require('ol.source.VectorEventType'); -goog.require('ol.structs.RBush'); - - - -/** - * @classdesc - * Handles snapping of vector features while modifying or drawing them. The - * features can come from a {@link ol.source.Vector} or {@link ol.Collection} - * Any interaction object that allows the user to interact - * with the features using the mouse can benefit from the snapping, as long - * as it is added before. - * - * The snap interaction modifies map browser event `coordinate` and `pixel` - * properties to force the snap to occur to any interaction that them. - * - * Example: - * - * var snap = new ol.interaction.Snap({ - * source: source - * }); - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.SnapOptions=} opt_options Options. - * @api - */ -ol.interaction.Snap = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.Snap.handleEvent_, - handleDownEvent: goog.functions.TRUE, - handleUpEvent: ol.interaction.Snap.handleUpEvent_ - }); - - var options = opt_options ? opt_options : {}; - - /** - * @type {ol.source.Vector} - * @private - */ - this.source_ = options.source ? options.source : null; - - /** - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features ? options.features : null; - - /** - * @type {Array.<goog.events.Key>} - * @private - */ - this.featuresListenerKeys_ = []; - - /** - * @type {Object.<number, goog.events.Key>} - * @private - */ - this.geometryChangeListenerKeys_ = {}; - - /** - * @type {Object.<number, goog.events.Key>} - * @private - */ - this.geometryModifyListenerKeys_ = {}; - - /** - * Extents are preserved so indexed segment can be quickly removed - * when its feature geometry changes - * @type {Object.<number, ol.Extent>} - * @private - */ - this.indexedFeaturesExtents_ = {}; - - /** - * If a feature geometry changes while a pointer drag|move event occurs, the - * feature doesn't get updated right away. It will be at the next 'pointerup' - * event fired. - * @type {Object.<number, ol.Feature>} - * @private - */ - this.pendingFeatures_ = {}; - - /** - * Used for distance sorting in sortByDistance_ - * @type {ol.Coordinate} - * @private - */ - this.pixelCoordinate_ = null; - - /** - * @type {number} - * @private - */ - this.pixelTolerance_ = options.pixelTolerance !== undefined ? - options.pixelTolerance : 10; - - /** - * @type {function(ol.interaction.Snap.SegmentDataType, ol.interaction.Snap.SegmentDataType): number} - * @private - */ - this.sortByDistance_ = goog.bind(ol.interaction.Snap.sortByDistance, this); - - - /** - * Segment RTree for each layer - * @type {ol.structs.RBush.<ol.interaction.Snap.SegmentDataType>} - * @private - */ - this.rBush_ = new ol.structs.RBush(); - - - /** - * @const - * @private - * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>} - */ - this.SEGMENT_WRITERS_ = { - 'Point': this.writePointGeometry_, - 'LineString': this.writeLineStringGeometry_, - 'LinearRing': this.writeLineStringGeometry_, - 'Polygon': this.writePolygonGeometry_, - 'MultiPoint': this.writeMultiPointGeometry_, - 'MultiLineString': this.writeMultiLineStringGeometry_, - 'MultiPolygon': this.writeMultiPolygonGeometry_, - 'GeometryCollection': this.writeGeometryCollectionGeometry_ - }; -}; -goog.inherits(ol.interaction.Snap, ol.interaction.Pointer); - - -/** - * Add a feature to the collection of features that we may snap to. - * @param {ol.Feature} feature Feature. - * @param {boolean=} opt_listen Whether to listen to the geometry change or not - * Defaults to `true`. - * @api - */ -ol.interaction.Snap.prototype.addFeature = function(feature, opt_listen) { - var listen = opt_listen !== undefined ? opt_listen : true; - var geometry = feature.getGeometry(); - var segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()]; - if (segmentWriter) { - var feature_uid = goog.getUid(feature); - this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent( - ol.extent.createEmpty()); - segmentWriter.call(this, feature, geometry); - - if (listen) { - this.geometryModifyListenerKeys_[feature_uid] = geometry.on( - goog.events.EventType.CHANGE, - goog.bind(this.handleGeometryModify_, this, feature), - this); - this.geometryChangeListenerKeys_[feature_uid] = feature.on( - ol.Object.getChangeEventType(feature.getGeometryName()), - this.handleGeometryChange_, this); - } - } -}; - - -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Snap.prototype.forEachFeatureAdd_ = function(feature) { - this.addFeature(feature); -}; - - -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Snap.prototype.forEachFeatureRemove_ = function(feature) { - this.removeFeature(feature); -}; - - -/** - * @return {ol.Collection.<ol.Feature>|Array.<ol.Feature>} - * @private - */ -ol.interaction.Snap.prototype.getFeatures_ = function() { - var features; - if (this.features_) { - features = this.features_; - } else if (this.source_) { - features = this.source_.getFeatures(); - } - goog.asserts.assert(features !== undefined, 'features should be defined'); - return features; -}; - - -/** - * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleFeatureAdd_ = function(evt) { - var feature; - if (evt instanceof ol.source.VectorEvent) { - feature = evt.feature; - } else if (evt instanceof ol.CollectionEvent) { - feature = evt.element; - } - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - this.addFeature(feature); -}; - - -/** - * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleFeatureRemove_ = function(evt) { - var feature; - if (evt instanceof ol.source.VectorEvent) { - feature = evt.feature; - } else if (evt instanceof ol.CollectionEvent) { - feature = evt.element; - } - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - this.removeFeature(feature); -}; - - -/** - * @param {goog.events.Event} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleGeometryChange_ = function(evt) { - var feature = evt.currentTarget; - goog.asserts.assertInstanceof(feature, ol.Feature); - this.removeFeature(feature, true); - this.addFeature(feature, true); -}; - - -/** - * @param {ol.Feature} feature Feature which geometry was modified. - * @param {goog.events.Event} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleGeometryModify_ = function(feature, evt) { - if (this.handlingDownUpSequence) { - var uid = goog.getUid(feature); - if (!(uid in this.pendingFeatures_)) { - this.pendingFeatures_[uid] = feature; - } - } else { - this.updateFeature_(feature); - } -}; - - -/** - * Remove a feature from the collection of features that we may snap to. - * @param {ol.Feature} feature Feature - * @param {boolean=} opt_unlisten Whether to unlisten to the geometry change - * or not. Defaults to `true`. - * @api - */ -ol.interaction.Snap.prototype.removeFeature = function(feature, opt_unlisten) { - var unlisten = opt_unlisten !== undefined ? opt_unlisten : true; - var feature_uid = goog.getUid(feature); - var extent = this.indexedFeaturesExtents_[feature_uid]; - if (extent) { - var rBush = this.rBush_; - var i, nodesToRemove = []; - rBush.forEachInExtent(extent, function(node) { - if (feature === node.feature) { - nodesToRemove.push(node); - } - }); - for (i = nodesToRemove.length - 1; i >= 0; --i) { - rBush.remove(nodesToRemove[i]); - } - if (unlisten) { - ol.Observable.unByKey(this.geometryModifyListenerKeys_[feature_uid]); - delete this.geometryModifyListenerKeys_[feature_uid]; - - ol.Observable.unByKey(this.geometryChangeListenerKeys_[feature_uid]); - delete this.geometryChangeListenerKeys_[feature_uid]; - } - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.Snap.prototype.setMap = function(map) { - var currentMap = this.getMap(); - var keys = this.featuresListenerKeys_; - var features = this.getFeatures_(); - - if (currentMap) { - keys.forEach(ol.Observable.unByKey); - keys.length = 0; - features.forEach(this.forEachFeatureRemove_, this); - } - - goog.base(this, 'setMap', map); - - if (map) { - if (this.features_) { - keys.push(this.features_.on(ol.CollectionEventType.ADD, - this.handleFeatureAdd_, this)); - keys.push(this.features_.on(ol.CollectionEventType.REMOVE, - this.handleFeatureRemove_, this)); - } else if (this.source_) { - keys.push(this.source_.on(ol.source.VectorEventType.ADDFEATURE, - this.handleFeatureAdd_, this)); - keys.push(this.source_.on(ol.source.VectorEventType.REMOVEFEATURE, - this.handleFeatureRemove_, this)); - } - features.forEach(this.forEachFeatureAdd_, this); - } -}; - - -/** - * @inheritDoc - */ -ol.interaction.Snap.prototype.shouldStopEvent = goog.functions.FALSE; - - -/** - * @param {ol.Pixel} pixel Pixel - * @param {ol.Coordinate} pixelCoordinate Coordinate - * @param {ol.Map} map Map. - * @return {ol.interaction.Snap.ResultType} Snap result - */ -ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) { - - var lowerLeft = map.getCoordinateFromPixel( - [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]); - var upperRight = map.getCoordinateFromPixel( - [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]); - var box = ol.extent.boundingExtent([lowerLeft, upperRight]); - - var segments = this.rBush_.getInExtent(box); - var snappedToVertex = false; - var snapped = false; - var vertex = null; - var vertexPixel = null; - if (segments.length > 0) { - this.pixelCoordinate_ = pixelCoordinate; - segments.sort(this.sortByDistance_); - var closestSegment = segments[0].segment; - vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, - closestSegment)); - vertexPixel = map.getPixelFromCoordinate(vertex); - if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= - this.pixelTolerance_) { - snapped = true; - var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); - var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); - var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); - var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); - var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); - snappedToVertex = dist <= this.pixelTolerance_; - if (snappedToVertex) { - vertex = squaredDist1 > squaredDist2 ? - closestSegment[1] : closestSegment[0]; - vertexPixel = map.getPixelFromCoordinate(vertex); - vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])]; - } - } - } - return /** @type {ol.interaction.Snap.ResultType} */ ({ - snapped: snapped, - vertex: vertex, - vertexPixel: vertexPixel - }); -}; - - -/** - * @param {ol.Feature} feature Feature - * @private - */ -ol.interaction.Snap.prototype.updateFeature_ = function(feature) { - this.removeFeature(feature, false); - this.addFeature(feature, false); -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.GeometryCollection} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeGeometryCollectionGeometry_ = - function(feature, geometry) { - var i, geometries = geometry.getGeometriesArray(); - for (i = 0; i < geometries.length; ++i) { - this.SEGMENT_WRITERS_[geometries[i].getType()].call( - this, feature, geometries[i]); - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.LineString} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeLineStringGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var i, ii, segment, segmentData; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiLineString} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeMultiLineStringGeometry_ = - function(feature, geometry) { - var lines = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = lines.length; j < jj; ++j) { - coordinates = lines[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPoint} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeMultiPointGeometry_ = - function(feature, geometry) { - var points = geometry.getCoordinates(); - var coordinates, i, ii, segmentData; - for (i = 0, ii = points.length; i < ii; ++i) { - coordinates = points[i]; - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPolygon} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeMultiPolygonGeometry_ = - function(feature, geometry) { - var polygons = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData; - for (k = 0, kk = polygons.length; k < kk; ++k) { - rings = polygons[k]; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } - } -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Point} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writePointGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); -}; - - -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Polygon} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writePolygonGeometry_ = - function(feature, geometry) { - var rings = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; - - -/** - * @typedef {{ - * snapped: {boolean}, - * vertex: (ol.Coordinate|null), - * vertexPixel: (ol.Pixel|null) - * }} - */ -ol.interaction.Snap.ResultType; - - -/** - * @typedef {{ - * feature: ol.Feature, - * segment: Array.<ol.Coordinate> - * }} - */ -ol.interaction.Snap.SegmentDataType; - - -/** - * Handle all pointer events events. - * @param {ol.MapBrowserEvent} evt A move event. - * @return {boolean} Pass the event to other interactions. - * @this {ol.interaction.Snap} - * @private - */ -ol.interaction.Snap.handleEvent_ = function(evt) { - var result = this.snapTo(evt.pixel, evt.coordinate, evt.map); - if (result.snapped) { - evt.coordinate = result.vertex.slice(0, 2); - evt.pixel = result.vertexPixel; - } - return ol.interaction.Pointer.handleEvent.call(this, evt); -}; - - -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Snap} - * @private - */ -ol.interaction.Snap.handleUpEvent_ = function(evt) { - var featuresToUpdate = goog.object.getValues(this.pendingFeatures_); - if (featuresToUpdate.length) { - featuresToUpdate.forEach(this.updateFeature_, this); - this.pendingFeatures_ = {}; - } - return false; -}; - - -/** - * Sort segments by distance, helper function - * @param {ol.interaction.Snap.SegmentDataType} a - * @param {ol.interaction.Snap.SegmentDataType} b - * @return {number} - * @this {ol.interaction.Snap} - */ -ol.interaction.Snap.sortByDistance = function(a, b) { - return ol.coordinate.squaredDistanceToSegment( - this.pixelCoordinate_, a.segment) - - ol.coordinate.squaredDistanceToSegment( - this.pixelCoordinate_, b.segment); -}; - -goog.provide('ol.interaction.Translate'); -goog.provide('ol.interaction.TranslateEvent'); - -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('ol.array'); -goog.require('ol.interaction.Pointer'); - - -/** - * @enum {string} - */ -ol.interaction.TranslateEventType = { - /** - * Triggered upon feature translation start. - * @event ol.interaction.TranslateEvent#translatestart - * @api - */ - TRANSLATESTART: 'translatestart', - /** - * Triggered upon feature translation. - * @event ol.interaction.TranslateEvent#translating - * @api - */ - TRANSLATING: 'translating', - /** - * Triggered upon feature translation end. - * @event ol.interaction.TranslateEvent#translateend - * @api - */ - TRANSLATEEND: 'translateend' -}; - - - -/** - * @classdesc - * Events emitted by {@link ol.interaction.Translate} instances are instances of - * this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.interaction.TranslateEvent} - * @param {ol.interaction.TranslateEventType} type Type. - * @param {ol.Collection.<ol.Feature>} features The features translated. - * @param {ol.Coordinate} coordinate The event coordinate. - */ -ol.interaction.TranslateEvent = function(type, features, coordinate) { - - goog.base(this, type); - - /** - * The features being translated. - * @type {ol.Collection.<ol.Feature>} - * @api - */ - this.features = features; - - /** - * The coordinate of the drag event. - * @const - * @type {ol.Coordinate} - * @api - */ - this.coordinate = coordinate; -}; -goog.inherits(ol.interaction.TranslateEvent, goog.events.Event); - - - -/** - * @classdesc - * Interaction for translating (moving) features. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @fires ol.interaction.TranslateEvent - * @param {olx.interaction.TranslateOptions} options Options. - * @api - */ -ol.interaction.Translate = function(options) { - goog.base(this, { - handleDownEvent: ol.interaction.Translate.handleDownEvent_, - handleDragEvent: ol.interaction.Translate.handleDragEvent_, - handleMoveEvent: ol.interaction.Translate.handleMoveEvent_, - handleUpEvent: ol.interaction.Translate.handleUpEvent_ - }); - - - /** - * @type {string|undefined} - * @private - */ - this.previousCursor_ = undefined; - - - /** - * The last position we translated to. - * @type {ol.Coordinate} - * @private - */ - this.lastCoordinate_ = null; - - - /** - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features !== undefined ? options.features : null; - - /** - * @type {ol.Feature} - * @private - */ - this.lastFeature_ = null; -}; -goog.inherits(ol.interaction.Translate, ol.interaction.Pointer); - - -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleDownEvent_ = function(event) { - this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map); - if (!this.lastCoordinate_ && this.lastFeature_) { - this.lastCoordinate_ = event.coordinate; - ol.interaction.Translate.handleMoveEvent_.call(this, event); - this.dispatchEvent( - new ol.interaction.TranslateEvent( - ol.interaction.TranslateEventType.TRANSLATESTART, this.features_, - event.coordinate)); - return true; - } - return false; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleUpEvent_ = function(event) { - if (this.lastCoordinate_) { - this.lastCoordinate_ = null; - ol.interaction.Translate.handleMoveEvent_.call(this, event); - this.dispatchEvent( - new ol.interaction.TranslateEvent( - ol.interaction.TranslateEventType.TRANSLATEEND, this.features_, - event.coordinate)); - return true; - } - return false; -}; - - -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleDragEvent_ = function(event) { - if (this.lastCoordinate_) { - var newCoordinate = event.coordinate; - var deltaX = newCoordinate[0] - this.lastCoordinate_[0]; - var deltaY = newCoordinate[1] - this.lastCoordinate_[1]; - - if (this.features_) { - this.features_.forEach(function(feature) { - var geom = feature.getGeometry(); - geom.translate(deltaX, deltaY); - feature.setGeometry(geom); - }); - } else if (this.lastFeature_) { - var geom = this.lastFeature_.getGeometry(); - geom.translate(deltaX, deltaY); - this.lastFeature_.setGeometry(geom); - } - - this.lastCoordinate_ = newCoordinate; - this.dispatchEvent( - new ol.interaction.TranslateEvent( - ol.interaction.TranslateEventType.TRANSLATING, this.features_, - newCoordinate)); - } -}; - - -/** - * @param {ol.MapBrowserEvent} event Event. - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleMoveEvent_ = function(event) - { - var elem = event.map.getTargetElement(); - var intersectingFeature = event.map.forEachFeatureAtPixel(event.pixel, - function(feature) { - return feature; - }); - - if (intersectingFeature) { - var isSelected = false; - - if (this.features_ && - ol.array.includes(this.features_.getArray(), intersectingFeature)) { - isSelected = true; - } - - this.previousCursor_ = elem.style.cursor; - - // WebKit browsers don't support the grab icons without a prefix - elem.style.cursor = this.lastCoordinate_ ? - '-webkit-grabbing' : (isSelected ? '-webkit-grab' : 'pointer'); - - // Thankfully, attempting to set the standard ones will silently fail, - // keeping the prefixed icons - elem.style.cursor = !this.lastCoordinate_ ? - 'grabbing' : (isSelected ? 'grab' : 'pointer'); - - } else { - elem.style.cursor = this.previousCursor_ !== undefined ? - this.previousCursor_ : ''; - this.previousCursor_ = undefined; - } -}; - - -/** - * Tests to see if the given coordinates intersects any of our selected - * features. - * @param {ol.Pixel} pixel Pixel coordinate to test for intersection. - * @param {ol.Map} map Map to test the intersection on. - * @return {ol.Feature} Returns the feature found at the specified pixel - * coordinates. - * @private - */ -ol.interaction.Translate.prototype.featuresAtPixel_ = function(pixel, map) { - var found = null; - - var intersectingFeature = map.forEachFeatureAtPixel(pixel, - function(feature) { - return feature; - }); - - if (this.features_ && - ol.array.includes(this.features_.getArray(), intersectingFeature)) { - found = intersectingFeature; - } - - return found; -}; - -goog.provide('ol.layer.Heatmap'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.dom'); -goog.require('ol.layer.Vector'); -goog.require('ol.math'); -goog.require('ol.render.EventType'); -goog.require('ol.style.Icon'); -goog.require('ol.style.Style'); - - -/** - * @enum {string} - */ -ol.layer.HeatmapLayerProperty = { - BLUR: 'blur', - GRADIENT: 'gradient', - RADIUS: 'radius' -}; - - - -/** - * @classdesc - * Layer for rendering vector data as a heatmap. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Vector} - * @fires ol.render.Event - * @param {olx.layer.HeatmapOptions=} opt_options Options. - * @api - */ -ol.layer.Heatmap = function(opt_options) { - var options = opt_options ? opt_options : {}; - - var baseOptions = goog.object.clone(options); - - delete baseOptions.gradient; - delete baseOptions.radius; - delete baseOptions.blur; - delete baseOptions.shadow; - delete baseOptions.weight; - goog.base(this, /** @type {olx.layer.VectorOptions} */ (baseOptions)); - - /** - * @private - * @type {Uint8ClampedArray} - */ - this.gradient_ = null; - - /** - * @private - * @type {number} - */ - this.shadow_ = options.shadow !== undefined ? options.shadow : 250; - - /** - * @private - * @type {string|undefined} - */ - this.circleImage_ = undefined; - - /** - * @private - * @type {Array.<Array.<ol.style.Style>>} - */ - this.styleCache_ = null; - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT), - this.handleGradientChanged_, false, this); - - this.setGradient(options.gradient ? - options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT); - - this.setBlur(options.blur !== undefined ? options.blur : 15); - - this.setRadius(options.radius !== undefined ? options.radius : 8); - - goog.events.listen(this, [ - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.BLUR), - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.RADIUS) - ], this.handleStyleChanged_, false, this); - - this.handleStyleChanged_(); - - var weight = options.weight ? options.weight : 'weight'; - var weightFunction; - if (goog.isString(weight)) { - weightFunction = function(feature) { - return feature.get(weight); - }; - } else { - weightFunction = weight; - } - goog.asserts.assert(goog.isFunction(weightFunction), - 'weightFunction should be a function'); - - this.setStyle(goog.bind(function(feature, resolution) { - goog.asserts.assert(this.styleCache_, 'this.styleCache_ expected'); - goog.asserts.assert(this.circleImage_ !== undefined, - 'this.circleImage_ should be defined'); - var weight = weightFunction(feature); - var opacity = weight !== undefined ? ol.math.clamp(weight, 0, 1) : 1; - // cast to 8 bits - var index = (255 * opacity) | 0; - var style = this.styleCache_[index]; - if (!style) { - style = [ - new ol.style.Style({ - image: new ol.style.Icon({ - opacity: opacity, - src: this.circleImage_ - }) - }) - ]; - this.styleCache_[index] = style; - } - return style; - }, this)); - - // For performance reasons, don't sort the features before rendering. - // The render order is not relevant for a heatmap representation. - this.setRenderOrder(null); - - goog.events.listen(this, ol.render.EventType.RENDER, - this.handleRender_, false, this); - -}; -goog.inherits(ol.layer.Heatmap, ol.layer.Vector); - - -/** - * @const - * @type {Array.<string>} - */ -ol.layer.Heatmap.DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00']; - - -/** - * @param {Array.<string>} colors - * @return {Uint8ClampedArray} - * @private - */ -ol.layer.Heatmap.createGradient_ = function(colors) { - var width = 1; - var height = 256; - var context = ol.dom.createCanvasContext2D(width, height); - - var gradient = context.createLinearGradient(0, 0, width, height); - var step = 1 / (colors.length - 1); - for (var i = 0, ii = colors.length; i < ii; ++i) { - gradient.addColorStop(i * step, colors[i]); - } - - context.fillStyle = gradient; - context.fillRect(0, 0, width, height); - - return context.getImageData(0, 0, width, height).data; -}; - - -/** - * @return {string} - * @private - */ -ol.layer.Heatmap.prototype.createCircle_ = function() { - var radius = this.getRadius(); - var blur = this.getBlur(); - goog.asserts.assert(radius !== undefined && blur !== undefined, - 'radius and blur should be defined'); - var halfSize = radius + blur + 1; - var size = 2 * halfSize; - var context = ol.dom.createCanvasContext2D(size, size); - context.shadowOffsetX = context.shadowOffsetY = this.shadow_; - context.shadowBlur = blur; - context.shadowColor = '#000'; - context.beginPath(); - var center = halfSize - this.shadow_; - context.arc(center, center, radius, 0, Math.PI * 2, true); - context.fill(); - return context.canvas.toDataURL(); -}; - - -/** - * Return the blur size in pixels. - * @return {number} Blur size in pixels. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.getBlur = function() { - return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.BLUR)); -}; - - -/** - * Return the gradient colors as array of strings. - * @return {Array.<string>} Colors. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.getGradient = function() { - return /** @type {Array.<string>} */ ( - this.get(ol.layer.HeatmapLayerProperty.GRADIENT)); -}; - - -/** - * Return the size of the radius in pixels. - * @return {number} Radius size in pixel. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.getRadius = function() { - return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.RADIUS)); -}; - - -/** - * @private - */ -ol.layer.Heatmap.prototype.handleGradientChanged_ = function() { - this.gradient_ = ol.layer.Heatmap.createGradient_(this.getGradient()); -}; - - -/** - * @private - */ -ol.layer.Heatmap.prototype.handleStyleChanged_ = function() { - this.circleImage_ = this.createCircle_(); - this.styleCache_ = new Array(256); - this.changed(); -}; - - -/** - * @param {ol.render.Event} event Post compose event - * @private - */ -ol.layer.Heatmap.prototype.handleRender_ = function(event) { - goog.asserts.assert(event.type == ol.render.EventType.RENDER, - 'event.type should be RENDER'); - goog.asserts.assert(this.gradient_, 'this.gradient_ expected'); - var context = event.context; - var canvas = context.canvas; - var image = context.getImageData(0, 0, canvas.width, canvas.height); - var view8 = image.data; - var i, ii, alpha; - for (i = 0, ii = view8.length; i < ii; i += 4) { - alpha = view8[i + 3] * 4; - if (alpha) { - view8[i] = this.gradient_[alpha]; - view8[i + 1] = this.gradient_[alpha + 1]; - view8[i + 2] = this.gradient_[alpha + 2]; - } - } - context.putImageData(image, 0, 0); -}; - - -/** - * Set the blur size in pixels. - * @param {number} blur Blur size in pixels. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.setBlur = function(blur) { - this.set(ol.layer.HeatmapLayerProperty.BLUR, blur); -}; - - -/** - * Set the gradient colors as array of strings. - * @param {Array.<string>} colors Gradient. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.setGradient = function(colors) { - this.set(ol.layer.HeatmapLayerProperty.GRADIENT, colors); -}; - - -/** - * Set the size of the radius in pixels. - * @param {number} radius Radius size in pixel. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.setRadius = function(radius) { - this.set(ol.layer.HeatmapLayerProperty.RADIUS, radius); -}; - -goog.provide('ol.raster.Operation'); -goog.provide('ol.raster.OperationType'); - - -/** - * Raster operation type. Supported values are `'pixel'` and `'image'`. - * @enum {string} - * @api - */ -ol.raster.OperationType = { - PIXEL: 'pixel', - IMAGE: 'image' -}; - - -/** - * A function that takes an array of input data, performs some operation, and - * returns an array of ouput data. For `'pixel'` type operations, functions - * will be called with an array of {@link ol.raster.Pixel} data and should - * return an array of the same. For `'image'` type operations, functions will - * be called with an array of {@link ImageData - * https://developer.mozilla.org/en-US/docs/Web/API/ImageData} and should return - * an array of the same. The operations are called with a second "data" - * argument, which can be used for storage. The data object is accessible - * from raster events, where it can be initialized in "beforeoperations" and - * accessed again in "afteroperations". - * - * @typedef {function((Array.<ol.raster.Pixel>|Array.<ImageData>), Object): - * (Array.<ol.raster.Pixel>|Array.<ImageData>)} - * @api - */ -ol.raster.Operation; - -goog.provide('ol.raster.Pixel'); - - -/** - * An array of numbers representing pixel values. - * @typedef {Array.<number>} ol.raster.Pixel - * @api - */ -ol.raster.Pixel; - -goog.provide('ol.reproj.Tile'); -goog.provide('ol.reproj.TileFunctionType'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.math'); -goog.require('goog.object'); -goog.require('ol.Tile'); -goog.require('ol.TileState'); -goog.require('ol.extent'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.reproj'); -goog.require('ol.reproj.Triangulation'); - - -/** - * @typedef {function(number, number, number, number) : ol.Tile} - */ -ol.reproj.TileFunctionType; - - - -/** - * @classdesc - * Class encapsulating single reprojected tile. - * See {@link ol.source.TileImage}. - * - * @constructor - * @extends {ol.Tile} - * @param {ol.proj.Projection} sourceProj Source projection. - * @param {ol.tilegrid.TileGrid} sourceTileGrid Source tile grid. - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.tilegrid.TileGrid} targetTileGrid Target tile grid. - * @param {number} z Zoom level. - * @param {number} x X. - * @param {number} y Y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.reproj.TileFunctionType} getTileFunction - * Function returning source tiles (z, x, y, pixelRatio). - * @param {number=} opt_errorThreshold Acceptable reprojection error (in px). - * @param {boolean=} opt_renderEdges Render reprojection edges. - */ -ol.reproj.Tile = function(sourceProj, sourceTileGrid, - targetProj, targetTileGrid, z, x, y, pixelRatio, getTileFunction, - opt_errorThreshold, - opt_renderEdges) { - goog.base(this, [z, x, y], ol.TileState.IDLE); - - /** - * @private - * @type {boolean} - */ - this.renderEdges_ = opt_renderEdges !== undefined ? opt_renderEdges : false; - - /** - * @private - * @type {number} - */ - this.pixelRatio_ = pixelRatio; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; - - /** - * @private - * @type {Object.<number, HTMLCanvasElement>} - */ - this.canvasByContext_ = {}; - - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.sourceTileGrid_ = sourceTileGrid; - - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.targetTileGrid_ = targetTileGrid; - - /** - * @private - * @type {!Array.<ol.Tile>} - */ - this.sourceTiles_ = []; - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.sourcesListenerKeys_ = null; - - /** - * @private - * @type {number} - */ - this.sourceZ_ = 0; - - var targetExtent = targetTileGrid.getTileCoordExtent(this.getTileCoord()); - var maxTargetExtent = this.targetTileGrid_.getExtent(); - var maxSourceExtent = this.sourceTileGrid_.getExtent(); - - var limitedTargetExtent = maxTargetExtent ? - ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent; - - if (ol.extent.getArea(limitedTargetExtent) === 0) { - // Tile is completely outside range -> EMPTY - // TODO: is it actually correct that the source even creates the tile ? - this.state = ol.TileState.EMPTY; - return; - } - - var sourceProjExtent = sourceProj.getExtent(); - if (sourceProjExtent) { - if (!maxSourceExtent) { - maxSourceExtent = sourceProjExtent; - } else { - maxSourceExtent = ol.extent.getIntersection( - maxSourceExtent, sourceProjExtent); - } - } - - var targetResolution = targetTileGrid.getResolution(z); - - var targetCenter = ol.extent.getCenter(limitedTargetExtent); - var sourceResolution = ol.reproj.calculateSourceResolution( - sourceProj, targetProj, targetCenter, targetResolution); - - if (!goog.math.isFiniteNumber(sourceResolution) || sourceResolution <= 0) { - // invalid sourceResolution -> EMPTY - // probably edges of the projections when no extent is defined - this.state = ol.TileState.EMPTY; - return; - } - - var errorThresholdInPixels = opt_errorThreshold !== undefined ? - opt_errorThreshold : ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD; - - /** - * @private - * @type {!ol.reproj.Triangulation} - */ - this.triangulation_ = new ol.reproj.Triangulation( - sourceProj, targetProj, limitedTargetExtent, maxSourceExtent, - sourceResolution * errorThresholdInPixels); - - if (this.triangulation_.getTriangles().length === 0) { - // no valid triangles -> EMPTY - this.state = ol.TileState.EMPTY; - return; - } - - this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution); - var sourceExtent = this.triangulation_.calculateSourceExtent(); - - if (maxSourceExtent) { - if (sourceProj.canWrapX()) { - sourceExtent[1] = ol.math.clamp( - sourceExtent[1], maxSourceExtent[1], maxSourceExtent[3]); - sourceExtent[3] = ol.math.clamp( - sourceExtent[3], maxSourceExtent[1], maxSourceExtent[3]); - } else { - sourceExtent = ol.extent.getIntersection(sourceExtent, maxSourceExtent); - } - } - - if (!ol.extent.getArea(sourceExtent)) { - this.state = ol.TileState.EMPTY; - } else { - var sourceRange = sourceTileGrid.getTileRangeForExtentAndZ( - sourceExtent, this.sourceZ_); - - var tilesRequired = sourceRange.getWidth() * sourceRange.getHeight(); - if (!goog.asserts.assert( - tilesRequired < ol.RASTER_REPROJECTION_MAX_SOURCE_TILES, - 'reasonable number of tiles is required')) { - this.state = ol.TileState.ERROR; - return; - } - for (var srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) { - for (var srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) { - var tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio); - if (tile) { - this.sourceTiles_.push(tile); - } - } - } - - if (this.sourceTiles_.length === 0) { - this.state = ol.TileState.EMPTY; - } - } -}; -goog.inherits(ol.reproj.Tile, ol.Tile); - - -/** - * @inheritDoc - */ -ol.reproj.Tile.prototype.disposeInternal = function() { - if (this.state == ol.TileState.LOADING) { - this.unlistenSources_(); - } - goog.base(this, 'disposeInternal'); -}; - - -/** - * @inheritDoc - */ -ol.reproj.Tile.prototype.getImage = function(opt_context) { - if (opt_context !== undefined) { - var image; - var key = goog.getUid(opt_context); - if (key in this.canvasByContext_) { - return this.canvasByContext_[key]; - } else if (goog.object.isEmpty(this.canvasByContext_)) { - image = this.canvas_; - } else { - image = /** @type {HTMLCanvasElement} */ (this.canvas_.cloneNode(false)); - } - this.canvasByContext_[key] = image; - return image; - } else { - return this.canvas_; - } -}; - - -/** - * @private - */ -ol.reproj.Tile.prototype.reproject_ = function() { - var sources = []; - this.sourceTiles_.forEach(function(tile, i, arr) { - if (tile && tile.getState() == ol.TileState.LOADED) { - sources.push({ - extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord), - image: tile.getImage() - }); - } - }, this); - this.sourceTiles_.length = 0; - - var tileCoord = this.getTileCoord(); - var z = tileCoord[0]; - var size = this.targetTileGrid_.getTileSize(z); - var width = goog.isNumber(size) ? size : size[0]; - var height = goog.isNumber(size) ? size : size[1]; - var targetResolution = this.targetTileGrid_.getResolution(z); - var sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_); - - var targetExtent = this.targetTileGrid_.getTileCoordExtent(tileCoord); - this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_, - sourceResolution, this.sourceTileGrid_.getExtent(), - targetResolution, targetExtent, this.triangulation_, sources, - this.renderEdges_); - - this.state = ol.TileState.LOADED; - this.changed(); -}; - - -/** - * @inheritDoc - */ -ol.reproj.Tile.prototype.load = function() { - if (this.state == ol.TileState.IDLE) { - this.state = ol.TileState.LOADING; - this.changed(); - - var leftToLoad = 0; - - goog.asserts.assert(!this.sourcesListenerKeys_, - 'this.sourcesListenerKeys_ should be null'); - - this.sourcesListenerKeys_ = []; - this.sourceTiles_.forEach(function(tile, i, arr) { - var state = tile.getState(); - if (state == ol.TileState.IDLE || state == ol.TileState.LOADING) { - leftToLoad++; - - var sourceListenKey; - sourceListenKey = tile.listen(goog.events.EventType.CHANGE, - function(e) { - var state = tile.getState(); - if (state == ol.TileState.LOADED || - state == ol.TileState.ERROR || - state == ol.TileState.EMPTY) { - goog.events.unlistenByKey(sourceListenKey); - leftToLoad--; - goog.asserts.assert(leftToLoad >= 0, - 'leftToLoad should not be negative'); - if (leftToLoad === 0) { - this.unlistenSources_(); - this.reproject_(); - } - } - }, false, this); - this.sourcesListenerKeys_.push(sourceListenKey); - } - }, this); - - this.sourceTiles_.forEach(function(tile, i, arr) { - var state = tile.getState(); - if (state == ol.TileState.IDLE) { - tile.load(); - } - }); - - if (leftToLoad === 0) { - this.reproject_(); - } - } -}; - - -/** - * @private - */ -ol.reproj.Tile.prototype.unlistenSources_ = function() { - goog.asserts.assert(this.sourcesListenerKeys_, - 'this.sourcesListenerKeys_ should not be null'); - this.sourcesListenerKeys_.forEach(goog.events.unlistenByKey); - this.sourcesListenerKeys_ = null; -}; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A utility to load JavaScript files via DOM script tags. - * Refactored from goog.net.Jsonp. Works cross-domain. - * - */ - -goog.provide('goog.net.jsloader'); -goog.provide('goog.net.jsloader.Error'); -goog.provide('goog.net.jsloader.ErrorCode'); -goog.provide('goog.net.jsloader.Options'); - -goog.require('goog.array'); -goog.require('goog.async.Deferred'); -goog.require('goog.debug.Error'); -goog.require('goog.dom'); -goog.require('goog.dom.TagName'); -goog.require('goog.object'); - - -/** - * The name of the property of goog.global under which the JavaScript - * verification object is stored by the loaded script. - * @private {string} - */ -goog.net.jsloader.GLOBAL_VERIFY_OBJS_ = 'closure_verification'; - - -/** - * The default length of time, in milliseconds, we are prepared to wait for a - * load request to complete. - * @type {number} - */ -goog.net.jsloader.DEFAULT_TIMEOUT = 5000; - - -/** - * Optional parameters for goog.net.jsloader.send. - * timeout: The length of time, in milliseconds, we are prepared to wait - * for a load request to complete. Default it 5 seconds. - * document: The HTML document under which to load the JavaScript. Default is - * the current document. - * cleanupWhenDone: If true clean up the script tag after script completes to - * load. This is important if you just want to read data from the JavaScript - * and then throw it away. Default is false. - * attributes: Additional attributes to set on the script tag. - * - * @typedef {{ - * timeout: (number|undefined), - * document: (HTMLDocument|undefined), - * cleanupWhenDone: (boolean|undefined), - * attributes: (!Object<string, string>|undefined) - * }} - */ -goog.net.jsloader.Options; - - -/** - * Scripts (URIs) waiting to be loaded. - * @private {!Array<string>} - */ -goog.net.jsloader.scriptsToLoad_ = []; - - -/** - * The deferred result of loading the URIs in scriptsToLoad_. - * We need to return this to a caller that wants to load URIs while - * a deferred is already working on them. - * @private {!goog.async.Deferred<null>} - */ -goog.net.jsloader.scriptLoadingDeferred_; - - -/** - * Loads and evaluates the JavaScript files at the specified URIs, guaranteeing - * the order of script loads. - * - * Because we have to load the scripts in serial (load script 1, exec script 1, - * load script 2, exec script 2, and so on), this will be slower than doing - * the network fetches in parallel. - * - * If you need to load a large number of scripts but dependency order doesn't - * matter, you should just call goog.net.jsloader.load N times. - * - * If you need to load a large number of scripts on the same domain, - * you may want to use goog.module.ModuleLoader. - * - * @param {Array<string>} uris The URIs to load. - * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See - * goog.net.jsloader.options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks - */ -goog.net.jsloader.loadMany = function(uris, opt_options) { - // Loading the scripts in serial introduces asynchronosity into the flow. - // Therefore, there are race conditions where client A can kick off the load - // sequence for client B, even though client A's scripts haven't all been - // loaded yet. - // - // To work around this issue, all module loads share a queue. - if (!uris.length) { - return goog.async.Deferred.succeed(null); - } - - var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length; - goog.array.extend(goog.net.jsloader.scriptsToLoad_, uris); - if (isAnotherModuleLoading) { - // jsloader is still loading some other scripts. - // In order to prevent the race condition noted above, we just add - // these URIs to the end of the scripts' queue and return the deferred - // result of the ongoing script load, so the caller knows when they - // finish loading. - return goog.net.jsloader.scriptLoadingDeferred_; - } - - uris = goog.net.jsloader.scriptsToLoad_; - var popAndLoadNextScript = function() { - var uri = uris.shift(); - var deferred = goog.net.jsloader.load(uri, opt_options); - if (uris.length) { - deferred.addBoth(popAndLoadNextScript); - } - return deferred; - }; - goog.net.jsloader.scriptLoadingDeferred_ = popAndLoadNextScript(); - return goog.net.jsloader.scriptLoadingDeferred_; -}; - - -/** - * Loads and evaluates a JavaScript file. - * When the script loads, a user callback is called. - * It is the client's responsibility to verify that the script ran successfully. - * - * @param {string} uri The URI of the JavaScript. - * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See - * goog.net.jsloader.Options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks and/or cancel the transmission. - * The error callback will be called with a single goog.net.jsloader.Error - * parameter. - */ -goog.net.jsloader.load = function(uri, opt_options) { - var options = opt_options || {}; - var doc = options.document || document; - - var script = goog.dom.createElement(goog.dom.TagName.SCRIPT); - var request = {script_: script, timeout_: undefined}; - var deferred = new goog.async.Deferred(goog.net.jsloader.cancel_, request); - - // Set a timeout. - var timeout = null; - var timeoutDuration = goog.isDefAndNotNull(options.timeout) ? - options.timeout : goog.net.jsloader.DEFAULT_TIMEOUT; - if (timeoutDuration > 0) { - timeout = window.setTimeout(function() { - goog.net.jsloader.cleanup_(script, true); - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.TIMEOUT, - 'Timeout reached for loading script ' + uri)); - }, timeoutDuration); - request.timeout_ = timeout; - } - - // Hang the user callback to be called when the script completes to load. - // NOTE(user): This callback will be called in IE even upon error. In any - // case it is the client's responsibility to verify that the script ran - // successfully. - script.onload = script.onreadystatechange = function() { - if (!script.readyState || script.readyState == 'loaded' || - script.readyState == 'complete') { - var removeScriptNode = options.cleanupWhenDone || false; - goog.net.jsloader.cleanup_(script, removeScriptNode, timeout); - deferred.callback(null); - } - }; - - // Add an error callback. - // NOTE(user): Not supported in IE. - script.onerror = function() { - goog.net.jsloader.cleanup_(script, true, timeout); - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.LOAD_ERROR, - 'Error while loading script ' + uri)); - }; - - var properties = options.attributes || {}; - goog.object.extend(properties, { - 'type': 'text/javascript', - 'charset': 'UTF-8', - // NOTE(user): Safari never loads the script if we don't set - // the src attribute before appending. - 'src': uri - }); - goog.dom.setProperties(script, properties); - var scriptParent = goog.net.jsloader.getScriptParentElement_(doc); - scriptParent.appendChild(script); - - return deferred; -}; - - -/** - * Loads a JavaScript file and verifies it was evaluated successfully, using a - * verification object. - * The verification object is set by the loaded JavaScript at the end of the - * script. - * We verify this object was set and return its value in the success callback. - * If the object is not defined we trigger an error callback. - * - * @param {string} uri The URI of the JavaScript. - * @param {string} verificationObjName The name of the verification object that - * the loaded script should set. - * @param {goog.net.jsloader.Options} options Optional parameters. See - * goog.net.jsloader.Options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks and/or cancel the transmission. - * The success callback will be called with a single parameter containing - * the value of the verification object. - * The error callback will be called with a single goog.net.jsloader.Error - * parameter. - */ -goog.net.jsloader.loadAndVerify = function(uri, verificationObjName, options) { - // Define the global objects variable. - if (!goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]) { - goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_] = {}; - } - var verifyObjs = goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]; - - // Verify that the expected object does not exist yet. - if (goog.isDef(verifyObjs[verificationObjName])) { - // TODO(user): Error or reset variable? - return goog.async.Deferred.fail(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.VERIFY_OBJECT_ALREADY_EXISTS, - 'Verification object ' + verificationObjName + ' already defined.')); - } - - // Send request to load the JavaScript. - var sendDeferred = goog.net.jsloader.load(uri, options); - - // Create a deferred object wrapping the send result. - var deferred = new goog.async.Deferred( - goog.bind(sendDeferred.cancel, sendDeferred)); - - // Call user back with object that was set by the script. - sendDeferred.addCallback(function() { - var result = verifyObjs[verificationObjName]; - if (goog.isDef(result)) { - deferred.callback(result); - delete verifyObjs[verificationObjName]; - } else { - // Error: script was not loaded properly. - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.VERIFY_ERROR, - 'Script ' + uri + ' loaded, but verification object ' + - verificationObjName + ' was not defined.')); - } - }); - - // Pass error to new deferred object. - sendDeferred.addErrback(function(error) { - if (goog.isDef(verifyObjs[verificationObjName])) { - delete verifyObjs[verificationObjName]; - } - deferred.errback(error); - }); - - return deferred; -}; - - -/** - * Gets the DOM element under which we should add new script elements. - * How? Take the first head element, and if not found take doc.documentElement, - * which always exists. - * - * @param {!HTMLDocument} doc The relevant document. - * @return {!Element} The script parent element. - * @private - */ -goog.net.jsloader.getScriptParentElement_ = function(doc) { - var headElements = doc.getElementsByTagName(goog.dom.TagName.HEAD); - if (!headElements || goog.array.isEmpty(headElements)) { - return doc.documentElement; - } else { - return headElements[0]; - } -}; - - -/** - * Cancels a given request. - * @this {{script_: Element, timeout_: number}} The request context. - * @private - */ -goog.net.jsloader.cancel_ = function() { - var request = this; - if (request && request.script_) { - var scriptNode = request.script_; - if (scriptNode && scriptNode.tagName == goog.dom.TagName.SCRIPT) { - goog.net.jsloader.cleanup_(scriptNode, true, request.timeout_); - } - } -}; - - -/** - * Removes the script node and the timeout. - * - * @param {Node} scriptNode The node to be cleaned up. - * @param {boolean} removeScriptNode If true completely remove the script node. - * @param {?number=} opt_timeout The timeout handler to cleanup. - * @private - */ -goog.net.jsloader.cleanup_ = function(scriptNode, removeScriptNode, - opt_timeout) { - if (goog.isDefAndNotNull(opt_timeout)) { - goog.global.clearTimeout(opt_timeout); - } - - scriptNode.onload = goog.nullFunction; - scriptNode.onerror = goog.nullFunction; - scriptNode.onreadystatechange = goog.nullFunction; - - // Do this after a delay (removing the script node of a running script can - // confuse older IEs). - if (removeScriptNode) { - window.setTimeout(function() { - goog.dom.removeNode(scriptNode); - }, 0); - } -}; - - -/** - * Possible error codes for jsloader. - * @enum {number} - */ -goog.net.jsloader.ErrorCode = { - LOAD_ERROR: 0, - TIMEOUT: 1, - VERIFY_ERROR: 2, - VERIFY_OBJECT_ALREADY_EXISTS: 3 -}; - - - -/** - * A jsloader error. - * - * @param {goog.net.jsloader.ErrorCode} code The error code. - * @param {string=} opt_message Additional message. - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.net.jsloader.Error = function(code, opt_message) { - var msg = 'Jsloader error (code #' + code + ')'; - if (opt_message) { - msg += ': ' + opt_message; - } - goog.net.jsloader.Error.base(this, 'constructor', msg); - - /** - * The code for this error. - * - * @type {goog.net.jsloader.ErrorCode} - */ - this.code = code; -}; -goog.inherits(goog.net.jsloader.Error, goog.debug.Error); - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The original file lives here: http://go/cross_domain_channel.js - -/** - * @fileoverview Implements a cross-domain communication channel. A - * typical web page is prevented by browser security from sending - * request, such as a XMLHttpRequest, to other servers than the ones - * from which it came. The Jsonp class provides a workaround by - * using dynamically generated script tags. Typical usage:. - * - * var jsonp = new goog.net.Jsonp(new goog.Uri('http://my.host.com/servlet')); - * var payload = { 'foo': 1, 'bar': true }; - * jsonp.send(payload, function(reply) { alert(reply) }); - * - * This script works in all browsers that are currently supported by - * the Google Maps API, which is IE 6.0+, Firefox 0.8+, Safari 1.2.4+, - * Netscape 7.1+, Mozilla 1.4+, Opera 8.02+. - * - */ - -goog.provide('goog.net.Jsonp'); - -goog.require('goog.Uri'); -goog.require('goog.net.jsloader'); - -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -// -// This class allows us (Google) to send data from non-Google and thus -// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return -// anything sensitive, such as session or cookie specific data. Return -// only data that you want parties external to Google to have. Also -// NEVER use this method to send data from web pages to untrusted -// servers, or redirects to unknown servers (www.google.com/cache, -// /q=xx&btnl, /url, www.googlepages.com, etc.) -// -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - - - -/** - * Creates a new cross domain channel that sends data to the specified - * host URL. By default, if no reply arrives within 5s, the channel - * assumes the call failed to complete successfully. - * - * @param {goog.Uri|string} uri The Uri of the server side code that receives - * data posted through this channel (e.g., - * "http://maps.google.com/maps/geo"). - * - * @param {string=} opt_callbackParamName The parameter name that is used to - * specify the callback. Defaults to "callback". - * - * @constructor - * @final - */ -goog.net.Jsonp = function(uri, opt_callbackParamName) { - /** - * The uri_ object will be used to encode the payload that is sent to the - * server. - * @type {goog.Uri} - * @private - */ - this.uri_ = new goog.Uri(uri); - - /** - * This is the callback parameter name that is added to the uri. - * @type {string} - * @private - */ - this.callbackParamName_ = opt_callbackParamName ? - opt_callbackParamName : 'callback'; - - /** - * The length of time, in milliseconds, this channel is prepared - * to wait for for a request to complete. The default value is 5 seconds. - * @type {number} - * @private - */ - this.timeout_ = 5000; -}; - - -/** - * The name of the property of goog.global under which the callback is - * stored. - */ -goog.net.Jsonp.CALLBACKS = '_callbacks_'; - - -/** - * Used to generate unique callback IDs. The counter must be global because - * all channels share a common callback object. - * @private - */ -goog.net.Jsonp.scriptCounter_ = 0; - - -/** - * Sets the length of time, in milliseconds, this channel is prepared - * to wait for for a request to complete. If the call is not competed - * within the set time span, it is assumed to have failed. To wait - * indefinitely for a request to complete set the timout to a negative - * number. - * - * @param {number} timeout The length of time before calls are - * interrupted. - */ -goog.net.Jsonp.prototype.setRequestTimeout = function(timeout) { - this.timeout_ = timeout; -}; - - -/** - * Returns the current timeout value, in milliseconds. - * - * @return {number} The timeout value. - */ -goog.net.Jsonp.prototype.getRequestTimeout = function() { - return this.timeout_; -}; - - -/** - * Sends the given payload to the URL specified at the construction - * time. The reply is delivered to the given replyCallback. If the - * errorCallback is specified and the reply does not arrive within the - * timeout period set on this channel, the errorCallback is invoked - * with the original payload. - * - * If no reply callback is specified, then the response is expected to - * consist of calls to globally registered functions. No &callback= - * URL parameter will be sent in the request, and the script element - * will be cleaned up after the timeout. - * - * @param {Object=} opt_payload Name-value pairs. If given, these will be - * added as parameters to the supplied URI as GET parameters to the - * given server URI. - * - * @param {Function=} opt_replyCallback A function expecting one - * argument, called when the reply arrives, with the response data. - * - * @param {Function=} opt_errorCallback A function expecting one - * argument, called on timeout, with the payload (if given), otherwise - * null. - * - * @param {string=} opt_callbackParamValue Value to be used as the - * parameter value for the callback parameter (callbackParamName). - * To be used when the value needs to be fixed by the client for a - * particular request, to make use of the cached responses for the request. - * NOTE: If multiple requests are made with the same - * opt_callbackParamValue, only the last call will work whenever the - * response comes back. - * - * @return {!Object} A request descriptor that may be used to cancel this - * transmission, or null, if the message may not be cancelled. - */ -goog.net.Jsonp.prototype.send = function(opt_payload, - opt_replyCallback, - opt_errorCallback, - opt_callbackParamValue) { - - var payload = opt_payload || null; - - var id = opt_callbackParamValue || - '_' + (goog.net.Jsonp.scriptCounter_++).toString(36) + - goog.now().toString(36); - - if (!goog.global[goog.net.Jsonp.CALLBACKS]) { - goog.global[goog.net.Jsonp.CALLBACKS] = {}; - } - - // Create a new Uri object onto which this payload will be added - var uri = this.uri_.clone(); - if (payload) { - goog.net.Jsonp.addPayloadToUri_(payload, uri); - } - - if (opt_replyCallback) { - var reply = goog.net.Jsonp.newReplyHandler_(id, opt_replyCallback); - goog.global[goog.net.Jsonp.CALLBACKS][id] = reply; - - uri.setParameterValues(this.callbackParamName_, - goog.net.Jsonp.CALLBACKS + '.' + id); - } - - var deferred = goog.net.jsloader.load(uri.toString(), - {timeout: this.timeout_, cleanupWhenDone: true}); - var error = goog.net.Jsonp.newErrorHandler_(id, payload, opt_errorCallback); - deferred.addErrback(error); - - return {id_: id, deferred_: deferred}; -}; - - -/** - * Cancels a given request. The request must be exactly the object returned by - * the send method. - * - * @param {Object} request The request object returned by the send method. - */ -goog.net.Jsonp.prototype.cancel = function(request) { - if (request) { - if (request.deferred_) { - request.deferred_.cancel(); - } - if (request.id_) { - goog.net.Jsonp.cleanup_(request.id_, false); - } - } -}; - - -/** - * Creates a timeout callback that calls the given timeoutCallback with the - * original payload. - * - * @param {string} id The id of the script node. - * @param {Object} payload The payload that was sent to the server. - * @param {Function=} opt_errorCallback The function called on timeout. - * @return {!Function} A zero argument function that handles callback duties. - * @private - */ -goog.net.Jsonp.newErrorHandler_ = function(id, - payload, - opt_errorCallback) { - /** - * When we call across domains with a request, this function is the - * timeout handler. Once it's done executing the user-specified - * error-handler, it removes the script node and original function. - */ - return function() { - goog.net.Jsonp.cleanup_(id, false); - if (opt_errorCallback) { - opt_errorCallback(payload); - } - }; -}; - - -/** - * Creates a reply callback that calls the given replyCallback with data - * returned by the server. - * - * @param {string} id The id of the script node. - * @param {Function} replyCallback The function called on reply. - * @return {!Function} A reply callback function. - * @private - */ -goog.net.Jsonp.newReplyHandler_ = function(id, replyCallback) { - /** - * This function is the handler for the all-is-well response. It - * clears the error timeout handler, calls the user's handler, then - * removes the script node and itself. - * - * @param {...Object} var_args The response data sent from the server. - */ - var handler = function(var_args) { - goog.net.Jsonp.cleanup_(id, true); - replyCallback.apply(undefined, arguments); - }; - return handler; -}; - - -/** - * Removes the script node and reply handler with the given id. - * - * @param {string} id The id of the script node to be removed. - * @param {boolean} deleteReplyHandler If true, delete the reply handler - * instead of setting it to nullFunction (if we know the callback could - * never be called again). - * @private - */ -goog.net.Jsonp.cleanup_ = function(id, deleteReplyHandler) { - if (goog.global[goog.net.Jsonp.CALLBACKS][id]) { - if (deleteReplyHandler) { - delete goog.global[goog.net.Jsonp.CALLBACKS][id]; - } else { - // Removing the script tag doesn't necessarily prevent the script - // from firing, so we make the callback a noop. - goog.global[goog.net.Jsonp.CALLBACKS][id] = goog.nullFunction; - } - } -}; - - -/** - * Returns URL encoded payload. The payload should be a map of name-value - * pairs, in the form {"foo": 1, "bar": true, ...}. If the map is empty, - * the URI will be unchanged. - * - * <p>The method uses hasOwnProperty() to assure the properties are on the - * object, not on its prototype. - * - * @param {!Object} payload A map of value name pairs to be encoded. - * A value may be specified as an array, in which case a query parameter - * will be created for each value, e.g.: - * {"foo": [1,2]} will encode to "foo=1&foo=2". - * - * @param {!goog.Uri} uri A Uri object onto which the payload key value pairs - * will be encoded. - * - * @return {!goog.Uri} A reference to the Uri sent as a parameter. - * @private - */ -goog.net.Jsonp.addPayloadToUri_ = function(payload, uri) { - for (var name in payload) { - // NOTE(user): Safari/1.3 doesn't have hasOwnProperty(). In that - // case, we iterate over all properties as a very lame workaround. - if (!payload.hasOwnProperty || payload.hasOwnProperty(name)) { - uri.setParameterValues(name, payload[name]); - } - } - return uri; -}; - - -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -// -// This class allows us (Google) to send data from non-Google and thus -// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return -// anything sensitive, such as session or cookie specific data. Return -// only data that you want parties external to Google to have. Also -// NEVER use this method to send data from web pages to untrusted -// servers, or redirects to unknown servers (www.google.com/cache, -// /q=xx&btnl, /url, www.googlepages.com, etc.) -// -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - -goog.provide('ol.source.TileImage'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.ImageTile'); -goog.require('ol.TileCache'); -goog.require('ol.TileState'); -goog.require('ol.proj'); -goog.require('ol.reproj.Tile'); -goog.require('ol.source.UrlTile'); - - - -/** - * @classdesc - * Base class for sources providing images divided into a tile grid. - * - * @constructor - * @fires ol.source.TileEvent - * @extends {ol.source.UrlTile} - * @param {olx.source.TileImageOptions} options Image tile options. - * @api - */ -ol.source.TileImage = function(options) { - - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - opaque: options.opaque, - projection: options.projection, - state: options.state !== undefined ? - /** @type {ol.source.State} */ (options.state) : undefined, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction ? - options.tileLoadFunction : ol.source.TileImage.defaultTileLoadFunction, - tilePixelRatio: options.tilePixelRatio, - tileUrlFunction: options.tileUrlFunction, - url: options.url, - urls: options.urls, - wrapX: options.wrapX - }); - - /** - * @protected - * @type {?string} - */ - this.crossOrigin = - options.crossOrigin !== undefined ? options.crossOrigin : null; - - /** - * @protected - * @type {function(new: ol.ImageTile, ol.TileCoord, ol.TileState, string, - * ?string, ol.TileLoadFunctionType)} - */ - this.tileClass = options.tileClass !== undefined ? - options.tileClass : ol.ImageTile; - - /** - * @protected - * @type {Object.<string, ol.TileCache>} - */ - this.tileCacheForProjection = {}; - - /** - * @protected - * @type {Object.<string, ol.tilegrid.TileGrid>} - */ - this.tileGridForProjection = {}; - - /** - * @private - * @type {number|undefined} - */ - this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold; - - /** - * @private - * @type {boolean} - */ - this.renderReprojectionEdges_ = false; -}; -goog.inherits(ol.source.TileImage, ol.source.UrlTile); - - -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.canExpireCache = function() { - if (!ol.ENABLE_RASTER_REPROJECTION) { - return goog.base(this, 'canExpireCache'); - } - var canExpire = this.tileCache.canExpireCache(); - if (canExpire) { - return true; - } else { - return goog.object.some(this.tileCacheForProjection, function(tileCache) { - return tileCache.canExpireCache(); - }); - } -}; - - -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.expireCache = function(projection, usedTiles) { - if (!ol.ENABLE_RASTER_REPROJECTION) { - goog.base(this, 'expireCache', projection, usedTiles); - return; - } - var usedTileCache = this.getTileCacheForProjection(projection); - - this.tileCache.expireCache(this.tileCache == usedTileCache ? usedTiles : {}); - goog.object.forEach(this.tileCacheForProjection, function(tileCache) { - tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {}); - }); -}; - - -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.getTileGridForProjection = function(projection) { - if (!ol.ENABLE_RASTER_REPROJECTION) { - return goog.base(this, 'getTileGridForProjection', projection); - } - var thisProj = this.getProjection(); - if (this.tileGrid && - (!thisProj || ol.proj.equivalent(thisProj, projection))) { - return this.tileGrid; - } else { - var projKey = goog.getUid(projection).toString(); - if (!(projKey in this.tileGridForProjection)) { - this.tileGridForProjection[projKey] = - ol.tilegrid.getForProjection(projection); - } - return this.tileGridForProjection[projKey]; - } -}; - - -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.getTileCacheForProjection = function(projection) { - if (!ol.ENABLE_RASTER_REPROJECTION) { - return goog.base(this, 'getTileCacheForProjection', projection); - } - var thisProj = this.getProjection(); - if (!thisProj || ol.proj.equivalent(thisProj, projection)) { - return this.tileCache; - } else { - var projKey = goog.getUid(projection).toString(); - if (!(projKey in this.tileCacheForProjection)) { - this.tileCacheForProjection[projKey] = new ol.TileCache(); - } - return this.tileCacheForProjection[projKey]; - } -}; - - -/** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {string} key The key set on the tile. - * @return {ol.Tile} Tile. - * @private - */ -ol.source.TileImage.prototype.createTile_ = - function(z, x, y, pixelRatio, projection, key) { - var tileCoord = [z, x, y]; - var urlTileCoord = this.getTileCoordForTileUrlFunction( - tileCoord, projection); - var tileUrl = urlTileCoord ? - this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined; - var tile = new this.tileClass( - tileCoord, - tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, - tileUrl !== undefined ? tileUrl : '', - this.crossOrigin, - this.tileLoadFunction); - tile.key = key; - goog.events.listen(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - return tile; -}; - - -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.getTile = - function(z, x, y, pixelRatio, projection) { - if (!ol.ENABLE_RASTER_REPROJECTION || - !this.getProjection() || - !projection || - ol.proj.equivalent(this.getProjection(), projection)) { - return this.getTileInternal(z, x, y, pixelRatio, projection); - } else { - var cache = this.getTileCacheForProjection(projection); - var tileCoordKey = this.getKeyZXY(z, x, y); - if (cache.containsKey(tileCoordKey)) { - return /** @type {!ol.Tile} */ (cache.get(tileCoordKey)); - } else { - var sourceProjection = this.getProjection(); - var sourceTileGrid = this.getTileGridForProjection(sourceProjection); - var targetTileGrid = this.getTileGridForProjection(projection); - var tile = new ol.reproj.Tile( - sourceProjection, sourceTileGrid, - projection, targetTileGrid, - z, x, y, this.getTilePixelRatio(), - goog.bind(function(z, x, y, pixelRatio) { - return this.getTileInternal(z, x, y, pixelRatio, sourceProjection); - }, this), this.reprojectionErrorThreshold_, - this.renderReprojectionEdges_); - - cache.set(tileCoordKey, tile); - return tile; - } - } -}; - - -/** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {!ol.Tile} Tile. - * @protected - */ -ol.source.TileImage.prototype.getTileInternal = - function(z, x, y, pixelRatio, projection) { - var /** @type {ol.Tile} */ tile = null; - var tileCoordKey = this.getKeyZXY(z, x, y); - var paramsKey = this.getKeyParams(); - if (!this.tileCache.containsKey(tileCoordKey)) { - goog.asserts.assert(projection, 'argument projection is truthy'); - tile = this.createTile_(z, x, y, pixelRatio, projection, paramsKey); - this.tileCache.set(tileCoordKey, tile); - } else { - tile = /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); - if (tile.key != paramsKey) { - // The source's params changed. If the tile has an interim tile and if we - // can use it then we use it. Otherwise we create a new tile. In both - // cases we attempt to assign an interim tile to the new tile. - var /** @type {ol.Tile} */ interimTile = tile; - if (tile.interimTile && tile.interimTile.key == paramsKey) { - goog.asserts.assert(tile.interimTile.getState() == ol.TileState.LOADED); - goog.asserts.assert(tile.interimTile.interimTile === null); - tile = tile.interimTile; - if (interimTile.getState() == ol.TileState.LOADED) { - tile.interimTile = interimTile; - } - } else { - tile = this.createTile_(z, x, y, pixelRatio, projection, paramsKey); - if (interimTile.getState() == ol.TileState.LOADED) { - tile.interimTile = interimTile; - } else if (interimTile.interimTile && - interimTile.interimTile.getState() == ol.TileState.LOADED) { - tile.interimTile = interimTile.interimTile; - interimTile.interimTile = null; - } - } - if (tile.interimTile) { - tile.interimTile.interimTile = null; - } - this.tileCache.replace(tileCoordKey, tile); - } - } - goog.asserts.assert(tile); - return tile; -}; - - -/** - * Sets whether to render reprojection edges or not (usually for debugging). - * @param {boolean} render Render the edges. - * @api - */ -ol.source.TileImage.prototype.setRenderReprojectionEdges = function(render) { - if (!ol.ENABLE_RASTER_REPROJECTION || - this.renderReprojectionEdges_ == render) { - return; - } - this.renderReprojectionEdges_ = render; - goog.object.forEach(this.tileCacheForProjection, function(tileCache) { - tileCache.clear(); - }); - this.changed(); -}; - - -/** - * Sets the tile grid to use when reprojecting the tiles to the given - * projection instead of the default tile grid for the projection. - * - * This can be useful when the default tile grid cannot be created - * (e.g. projection has no extent defined) or - * for optimization reasons (custom tile size, resolutions, ...). - * - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {ol.tilegrid.TileGrid} tilegrid Tile grid to use for the projection. - * @api - */ -ol.source.TileImage.prototype.setTileGridForProjection = - function(projection, tilegrid) { - if (ol.ENABLE_RASTER_REPROJECTION) { - var proj = ol.proj.get(projection); - if (proj) { - var projKey = goog.getUid(proj).toString(); - if (!(projKey in this.tileGridForProjection)) { - this.tileGridForProjection[projKey] = tilegrid; - } - } - } -}; - - -/** - * @param {ol.ImageTile} imageTile Image tile. - * @param {string} src Source. - */ -ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) { - imageTile.getImage().src = src; -}; - -goog.provide('ol.source.BingMaps'); - -goog.require('goog.Uri'); -goog.require('goog.asserts'); -goog.require('goog.net.Jsonp'); -goog.require('ol.Attribution'); -goog.require('ol.TileRange'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilecoord'); - - - -/** - * @classdesc - * Layer source for Bing Maps tile data. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.BingMapsOptions} options Bing Maps options. - * @api stable - */ -ol.source.BingMaps = function(options) { - - goog.base(this, { - crossOrigin: 'anonymous', - opaque: true, - projection: ol.proj.get('EPSG:3857'), - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - state: ol.source.State.LOADING, - tileLoadFunction: options.tileLoadFunction, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - - /** - * @private - * @type {string} - */ - this.culture_ = options.culture !== undefined ? options.culture : 'en-us'; - - /** - * @private - * @type {number} - */ - this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1; - - var uri = new goog.Uri( - 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + - options.imagerySet); - - var jsonp = new goog.net.Jsonp(uri, 'jsonp'); - jsonp.send({ - 'include': 'ImageryProviders', - 'uriScheme': 'https', - 'key': options.key - }, goog.bind(this.handleImageryMetadataResponse, this)); - -}; -goog.inherits(ol.source.BingMaps, ol.source.TileImage); - - -/** - * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’ - * Terms Of Use. - * @const - * @type {ol.Attribution} - * @api - */ -ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({ - html: '<a class="ol-attribution-bing-tos" ' + - 'href="http://www.microsoft.com/maps/product/terms.html">' + - 'Terms of Use</a>' -}); - - -/** - * @param {BingMapsImageryMetadataResponse} response Response. - */ -ol.source.BingMaps.prototype.handleImageryMetadataResponse = - function(response) { - - if (response.statusCode != 200 || - response.statusDescription != 'OK' || - response.authenticationResultCode != 'ValidCredentials' || - response.resourceSets.length != 1 || - response.resourceSets[0].resources.length != 1) { - this.setState(ol.source.State.ERROR); - return; - } - - var brandLogoUri = response.brandLogoUri; - if (brandLogoUri.indexOf('https') == -1) { - brandLogoUri = brandLogoUri.replace('http', 'https'); - } - //var copyright = response.copyright; // FIXME do we need to display this? - var resource = response.resourceSets[0].resources[0]; - goog.asserts.assert(resource.imageWidth == resource.imageHeight, - 'resource has imageWidth equal to imageHeight, i.e. is square'); - var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_; - - var sourceProjection = this.getProjection(); - var extent = ol.tilegrid.extentFromProjection(sourceProjection); - var tileSize = resource.imageWidth == resource.imageHeight ? - resource.imageWidth : [resource.imageWidth, resource.imageHeight]; - var tileGrid = ol.tilegrid.createXYZ({ - extent: extent, - minZoom: resource.zoomMin, - maxZoom: maxZoom, - tileSize: tileSize - }); - this.tileGrid = tileGrid; - - var culture = this.culture_; - this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( - resource.imageUrlSubdomains.map(function(subdomain) { - var quadKeyTileCoord = [0, 0, 0]; - var imageUrl = resource.imageUrl - .replace('{subdomain}', subdomain) - .replace('{culture}', culture); - return ( - /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - goog.asserts.assert(ol.proj.equivalent( - projection, sourceProjection), - 'projections are equivalent'); - if (!tileCoord) { - return undefined; - } else { - ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1], - -tileCoord[2] - 1, quadKeyTileCoord); - return imageUrl.replace('{quadkey}', ol.tilecoord.quadKey( - quadKeyTileCoord)); - } - }); - })); - - if (resource.imageryProviders) { - var transform = ol.proj.getTransformFromProjections( - ol.proj.get('EPSG:4326'), this.getProjection()); - - var attributions = resource.imageryProviders.map(function(imageryProvider) { - var html = imageryProvider.attribution; - /** @type {Object.<string, Array.<ol.TileRange>>} */ - var tileRanges = {}; - imageryProvider.coverageAreas.forEach(function(coverageArea) { - var minZ = coverageArea.zoomMin; - var maxZ = Math.min(coverageArea.zoomMax, maxZoom); - var bbox = coverageArea.bbox; - var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]]; - var extent = ol.extent.applyTransform(epsg4326Extent, transform); - var tileRange, z, zKey; - for (z = minZ; z <= maxZ; ++z) { - zKey = z.toString(); - tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - if (zKey in tileRanges) { - tileRanges[zKey].push(tileRange); - } else { - tileRanges[zKey] = [tileRange]; - } - } - }); - return new ol.Attribution({html: html, tileRanges: tileRanges}); - }); - attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION); - this.setAttributions(attributions); - } - - this.setLogo(brandLogoUri); - - this.setState(ol.source.State.READY); - -}; - -// FIXME keep cluster cache by resolution ? -// FIXME distance not respected because of the centroid - -goog.provide('ol.source.Cluster'); - -goog.require('goog.asserts'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.coordinate'); -goog.require('ol.extent'); -goog.require('ol.geom.Point'); -goog.require('ol.source.Vector'); - - - -/** - * @classdesc - * Layer source to cluster vector data. - * - * @constructor - * @param {olx.source.ClusterOptions} options - * @extends {ol.source.Vector} - * @api - */ -ol.source.Cluster = function(options) { - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection, - wrapX: options.wrapX - }); - - /** - * @type {number|undefined} - * @private - */ - this.resolution_ = undefined; - - /** - * @type {number} - * @private - */ - this.distance_ = options.distance !== undefined ? options.distance : 20; - - /** - * @type {Array.<ol.Feature>} - * @private - */ - this.features_ = []; - - /** - * @type {ol.source.Vector} - * @private - */ - this.source_ = options.source; - - this.source_.on(goog.events.EventType.CHANGE, - ol.source.Cluster.prototype.onSourceChange_, this); -}; -goog.inherits(ol.source.Cluster, ol.source.Vector); - - -/** - * Get a reference to the wrapped source. - * @return {ol.source.Vector} Source. - * @api - */ -ol.source.Cluster.prototype.getSource = function() { - return this.source_; -}; - - -/** - * @inheritDoc - */ -ol.source.Cluster.prototype.loadFeatures = function(extent, resolution, - projection) { - this.source_.loadFeatures(extent, resolution, projection); - if (resolution !== this.resolution_) { - this.clear(); - this.resolution_ = resolution; - this.cluster_(); - this.addFeatures(this.features_); - } -}; - - -/** - * handle the source changing - * @private - */ -ol.source.Cluster.prototype.onSourceChange_ = function() { - this.clear(); - this.cluster_(); - this.addFeatures(this.features_); - this.changed(); -}; - - -/** - * @private - */ -ol.source.Cluster.prototype.cluster_ = function() { - if (this.resolution_ === undefined) { - return; - } - this.features_.length = 0; - var extent = ol.extent.createEmpty(); - var mapDistance = this.distance_ * this.resolution_; - var features = this.source_.getFeatures(); - - /** - * @type {Object.<string, boolean>} - */ - var clustered = {}; - - for (var i = 0, ii = features.length; i < ii; i++) { - var feature = features[i]; - if (!goog.object.containsKey(clustered, goog.getUid(feature).toString())) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry instanceof ol.geom.Point, - 'feature geometry is a ol.geom.Point instance'); - var coordinates = geometry.getCoordinates(); - ol.extent.createOrUpdateFromCoordinate(coordinates, extent); - ol.extent.buffer(extent, mapDistance, extent); - - var neighbors = this.source_.getFeaturesInExtent(extent); - goog.asserts.assert(neighbors.length >= 1, 'at least one neighbor found'); - neighbors = neighbors.filter(function(neighbor) { - var uid = goog.getUid(neighbor).toString(); - if (!goog.object.containsKey(clustered, uid)) { - clustered[uid] = true; - return true; - } else { - return false; - } - }); - this.features_.push(this.createCluster_(neighbors)); - } - } - goog.asserts.assert( - goog.object.getCount(clustered) == this.source_.getFeatures().length, - 'number of clustered equals number of features in the source'); -}; - - -/** - * @param {Array.<ol.Feature>} features Features - * @return {ol.Feature} - * @private - */ -ol.source.Cluster.prototype.createCluster_ = function(features) { - var length = features.length; - var centroid = [0, 0]; - for (var i = 0; i < length; i++) { - var geometry = features[i].getGeometry(); - goog.asserts.assert(geometry instanceof ol.geom.Point, - 'feature geometry is a ol.geom.Point instance'); - var coordinates = geometry.getCoordinates(); - ol.coordinate.add(centroid, coordinates); - } - ol.coordinate.scale(centroid, 1 / length); - - var cluster = new ol.Feature(new ol.geom.Point(centroid)); - cluster.set('features', features); - return cluster; -}; - -goog.provide('ol.source.ImageMapGuide'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.uri.utils'); -goog.require('ol.Image'); -goog.require('ol.ImageLoadFunctionType'); -goog.require('ol.extent'); -goog.require('ol.source.Image'); - - - -/** - * @classdesc - * Source for images from Mapguide servers - * - * @constructor - * @fires ol.source.ImageEvent - * @extends {ol.source.Image} - * @param {olx.source.ImageMapGuideOptions} options Options. - * @api stable - */ -ol.source.ImageMapGuide = function(options) { - - goog.base(this, { - projection: options.projection, - resolutions: options.resolutions - }); - - /** - * @private - * @type {?string} - */ - this.crossOrigin_ = - options.crossOrigin !== undefined ? options.crossOrigin : null; - - /** - * @private - * @type {number} - */ - this.displayDpi_ = options.displayDpi !== undefined ? - options.displayDpi : 96; - - /** - * @private - * @type {Object} - */ - this.params_ = options.params !== undefined ? options.params : {}; - - /** - * @private - * @type {string|undefined} - */ - this.url_ = options.url; - - /** - * @private - * @type {ol.ImageLoadFunctionType} - */ - this.imageLoadFunction_ = options.imageLoadFunction !== undefined ? - options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; - - /** - * @private - * @type {boolean} - */ - this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; - - /** - * @private - * @type {number} - */ - this.metersPerUnit_ = options.metersPerUnit !== undefined ? - options.metersPerUnit : 1; - - /** - * @private - * @type {number} - */ - this.ratio_ = options.ratio !== undefined ? options.ratio : 1; - - /** - * @private - * @type {boolean} - */ - this.useOverlay_ = options.useOverlay !== undefined ? - options.useOverlay : false; - - /** - * @private - * @type {ol.Image} - */ - this.image_ = null; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; - -}; -goog.inherits(ol.source.ImageMapGuide, ol.source.Image); - - -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api stable - */ -ol.source.ImageMapGuide.prototype.getParams = function() { - return this.params_; -}; - - -/** - * @inheritDoc - */ -ol.source.ImageMapGuide.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - resolution = this.findNearestResolution(resolution); - pixelRatio = this.hidpi_ ? pixelRatio : 1; - - var image = this.image_; - if (image && - this.renderedRevision_ == this.getRevision() && - image.getResolution() == resolution && - image.getPixelRatio() == pixelRatio && - ol.extent.containsExtent(image.getExtent(), extent)) { - return image; - } - - if (this.ratio_ != 1) { - extent = extent.slice(); - ol.extent.scaleFromCenter(extent, this.ratio_); - } - var width = ol.extent.getWidth(extent) / resolution; - var height = ol.extent.getHeight(extent) / resolution; - var size = [width * pixelRatio, height * pixelRatio]; - - if (this.url_ !== undefined) { - var imageUrl = this.getUrl(this.url_, this.params_, extent, size, - projection); - image = new ol.Image(extent, resolution, pixelRatio, - this.getAttributions(), imageUrl, this.crossOrigin_, - this.imageLoadFunction_); - goog.events.listen(image, goog.events.EventType.CHANGE, - this.handleImageChange, false, this); - } else { - image = null; - } - this.image_ = image; - this.renderedRevision_ = this.getRevision(); - - return image; -}; - - -/** - * Return the image load function of the source. - * @return {ol.ImageLoadFunctionType} The image load function. - * @api - */ -ol.source.ImageMapGuide.prototype.getImageLoadFunction = function() { - return this.imageLoadFunction_; -}; - - -/** - * @param {ol.Extent} extent The map extents. - * @param {ol.Size} size The viewport size. - * @param {number} metersPerUnit The meters-per-unit value. - * @param {number} dpi The display resolution. - * @return {number} The computed map scale. - */ -ol.source.ImageMapGuide.getScale = function(extent, size, metersPerUnit, dpi) { - var mcsW = ol.extent.getWidth(extent); - var mcsH = ol.extent.getHeight(extent); - var devW = size[0]; - var devH = size[1]; - var mpp = 0.0254 / dpi; - if (devH * mcsW > devW * mcsH) { - return mcsW * metersPerUnit / (devW * mpp); // width limited - } else { - return mcsH * metersPerUnit / (devH * mpp); // height limited - } -}; - - -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.ImageMapGuide.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.changed(); -}; - - -/** - * @param {string} baseUrl The mapagent url. - * @param {Object.<string, string|number>} params Request parameters. - * @param {ol.Extent} extent Extent. - * @param {ol.Size} size Size. - * @param {ol.proj.Projection} projection Projection. - * @return {string} The mapagent map image request URL. - */ -ol.source.ImageMapGuide.prototype.getUrl = - function(baseUrl, params, extent, size, projection) { - var scale = ol.source.ImageMapGuide.getScale(extent, size, - this.metersPerUnit_, this.displayDpi_); - var center = ol.extent.getCenter(extent); - var baseParams = { - 'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE', - 'VERSION': '2.0.0', - 'LOCALE': 'en', - 'CLIENTAGENT': 'ol.source.ImageMapGuide source', - 'CLIP': '1', - 'SETDISPLAYDPI': this.displayDpi_, - 'SETDISPLAYWIDTH': Math.round(size[0]), - 'SETDISPLAYHEIGHT': Math.round(size[1]), - 'SETVIEWSCALE': scale, - 'SETVIEWCENTERX': center[0], - 'SETVIEWCENTERY': center[1] - }; - goog.object.extend(baseParams, params); - return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams); -}; - - -/** - * Set the image load function of the MapGuide source. - * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. - * @api - */ -ol.source.ImageMapGuide.prototype.setImageLoadFunction = function( - imageLoadFunction) { - this.image_ = null; - this.imageLoadFunction_ = imageLoadFunction; - this.changed(); -}; - -goog.provide('ol.source.ImageStatic'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.Image'); -goog.require('ol.ImageLoadFunctionType'); -goog.require('ol.ImageState'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.Image'); - - - -/** - * @classdesc - * A layer source for displaying a single, static image. - * - * @constructor - * @extends {ol.source.Image} - * @param {olx.source.ImageStaticOptions} options Options. - * @api stable - */ -ol.source.ImageStatic = function(options) { - - var attributions = options.attributions !== undefined ? - options.attributions : null; - - var imageExtent = options.imageExtent; - - var crossOrigin = options.crossOrigin !== undefined ? - options.crossOrigin : null; - - var /** @type {ol.ImageLoadFunctionType} */ imageLoadFunction = - options.imageLoadFunction !== undefined ? - options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; - - goog.base(this, { - attributions: attributions, - logo: options.logo, - projection: ol.proj.get(options.projection) - }); - - /** - * @private - * @type {ol.Image} - */ - this.image_ = new ol.Image(imageExtent, undefined, 1, attributions, - options.url, crossOrigin, imageLoadFunction); - - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = options.imageSize ? options.imageSize : null; - - goog.events.listen(this.image_, goog.events.EventType.CHANGE, - this.handleImageChange, false, this); - -}; -goog.inherits(ol.source.ImageStatic, ol.source.Image); - - -/** - * @inheritDoc - */ -ol.source.ImageStatic.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - if (ol.extent.intersects(extent, this.image_.getExtent())) { - return this.image_; - } - return null; -}; - - -/** - * @inheritDoc - */ -ol.source.ImageStatic.prototype.handleImageChange = function(evt) { - if (this.image_.getState() == ol.ImageState.LOADED) { - var imageExtent = this.image_.getExtent(); - var image = this.image_.getImage(); - var imageWidth, imageHeight; - if (this.imageSize_) { - imageWidth = this.imageSize_[0]; - imageHeight = this.imageSize_[1]; - } else { - imageWidth = image.width; - imageHeight = image.height; - } - var resolution = ol.extent.getHeight(imageExtent) / imageHeight; - var targetWidth = Math.ceil(ol.extent.getWidth(imageExtent) / resolution); - if (targetWidth != imageWidth) { - var canvas = /** @type {HTMLCanvasElement} */ - (document.createElement('canvas')); - canvas.width = targetWidth; - canvas.height = /** @type {number} */ (imageHeight); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0, imageWidth, imageHeight, - 0, 0, canvas.width, canvas.height); - this.image_.setImage(canvas); - } - } - goog.base(this, 'handleImageChange', evt); -}; - -goog.provide('ol.source.wms'); -goog.provide('ol.source.wms.ServerType'); - - -/** - * Available server types: `'carmentaserver'`, `'geoserver'`, `'mapserver'`, - * `'qgis'`. These are servers that have vendor parameters beyond the WMS - * specification that OpenLayers can make use of. - * @enum {string} - * @api - */ -ol.source.wms.ServerType = { - CARMENTA_SERVER: 'carmentaserver', - GEOSERVER: 'geoserver', - MAPSERVER: 'mapserver', - QGIS: 'qgis' -}; - -// FIXME cannot be shared between maps with different projections - -goog.provide('ol.source.ImageWMS'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.uri.utils'); -goog.require('ol'); -goog.require('ol.Image'); -goog.require('ol.ImageLoadFunctionType'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.Image'); -goog.require('ol.source.wms'); -goog.require('ol.source.wms.ServerType'); - - - -/** - * @classdesc - * Source for WMS servers providing single, untiled images. - * - * @constructor - * @fires ol.source.ImageEvent - * @extends {ol.source.Image} - * @param {olx.source.ImageWMSOptions=} opt_options Options. - * @api stable - */ -ol.source.ImageWMS = function(opt_options) { - - var options = opt_options || {}; - - goog.base(this, { - attributions: options.attributions, - logo: options.logo, - projection: options.projection, - resolutions: options.resolutions - }); - - /** - * @private - * @type {?string} - */ - this.crossOrigin_ = - options.crossOrigin !== undefined ? options.crossOrigin : null; - - /** - * @private - * @type {string|undefined} - */ - this.url_ = options.url; - - /** - * @private - * @type {ol.ImageLoadFunctionType} - */ - this.imageLoadFunction_ = options.imageLoadFunction !== undefined ? - options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; - - /** - * @private - * @type {Object} - */ - this.params_ = options.params; - - /** - * @private - * @type {boolean} - */ - this.v13_ = true; - this.updateV13_(); - - /** - * @private - * @type {ol.source.wms.ServerType|undefined} - */ - this.serverType_ = - /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType); - - /** - * @private - * @type {boolean} - */ - this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; - - /** - * @private - * @type {ol.Image} - */ - this.image_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = [0, 0]; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; - - /** - * @private - * @type {number} - */ - this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5; - -}; -goog.inherits(ol.source.ImageWMS, ol.source.Image); - - -/** - * @const - * @type {ol.Size} - * @private - */ -ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101]; - - -/** - * Return the GetFeatureInfo URL for the passed coordinate, resolution, and - * projection. Return `undefined` if the GetFeatureInfo URL cannot be - * constructed. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should - * be provided. If `QUERY_LAYERS` is not provided then the layers specified - * in the `LAYERS` parameter will be used. `VERSION` should not be - * specified here. - * @return {string|undefined} GetFeatureInfo URL. - * @api stable - */ -ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = - function(coordinate, resolution, projection, params) { - - goog.asserts.assert(!('VERSION' in params), - 'key VERSION is not allowed in params'); - - if (this.url_ === undefined) { - return undefined; - } - - var extent = ol.extent.getForViewAndSize( - coordinate, resolution, 0, - ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_); - - var baseParams = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetFeatureInfo', - 'FORMAT': 'image/png', - 'TRANSPARENT': true, - 'QUERY_LAYERS': this.params_['LAYERS'] - }; - goog.object.extend(baseParams, this.params_, params); - - var x = Math.floor((coordinate[0] - extent[0]) / resolution); - var y = Math.floor((extent[3] - coordinate[1]) / resolution); - baseParams[this.v13_ ? 'I' : 'X'] = x; - baseParams[this.v13_ ? 'J' : 'Y'] = y; - - return this.getRequestUrl_( - extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_, - 1, ol.proj.get(projection), baseParams); -}; - - -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api stable - */ -ol.source.ImageWMS.prototype.getParams = function() { - return this.params_; -}; - - -/** - * @inheritDoc - */ -ol.source.ImageWMS.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - - if (this.url_ === undefined) { - return null; - } - - resolution = this.findNearestResolution(resolution); - - if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) { - pixelRatio = 1; - } - - extent = extent.slice(); - var centerX = (extent[0] + extent[2]) / 2; - var centerY = (extent[1] + extent[3]) / 2; - - var imageResolution = resolution / pixelRatio; - var imageWidth = ol.extent.getWidth(extent) / imageResolution; - var imageHeight = ol.extent.getHeight(extent) / imageResolution; - - var image = this.image_; - if (image && - this.renderedRevision_ == this.getRevision() && - image.getResolution() == resolution && - image.getPixelRatio() == pixelRatio && - ol.extent.containsExtent(image.getExtent(), extent)) { - return image; - } - - if (this.ratio_ != 1) { - var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2; - var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2; - extent[0] = centerX - halfWidth; - extent[1] = centerY - halfHeight; - extent[2] = centerX + halfWidth; - extent[3] = centerY + halfHeight; - } - - var params = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetMap', - 'FORMAT': 'image/png', - 'TRANSPARENT': true - }; - goog.object.extend(params, this.params_); - - this.imageSize_[0] = Math.ceil(imageWidth * this.ratio_); - this.imageSize_[1] = Math.ceil(imageHeight * this.ratio_); - - var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio, - projection, params); - - this.image_ = new ol.Image(extent, resolution, pixelRatio, - this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_); - - this.renderedRevision_ = this.getRevision(); - - goog.events.listen(this.image_, goog.events.EventType.CHANGE, - this.handleImageChange, false, this); - - return this.image_; - -}; - - -/** - * Return the image load function of the source. - * @return {ol.ImageLoadFunctionType} The image load function. - * @api - */ -ol.source.ImageWMS.prototype.getImageLoadFunction = function() { - return this.imageLoadFunction_; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {Object} params Params. - * @return {string} Request URL. - * @private - */ -ol.source.ImageWMS.prototype.getRequestUrl_ = - function(extent, size, pixelRatio, projection, params) { - - goog.asserts.assert(this.url_ !== undefined, 'url is defined'); - - params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode(); - - if (!('STYLES' in this.params_)) { - /* jshint -W053 */ - params['STYLES'] = new String(''); - /* jshint +W053 */ - } - - if (pixelRatio != 1) { - switch (this.serverType_) { - case ol.source.wms.ServerType.GEOSERVER: - var dpi = (90 * pixelRatio + 0.5) | 0; - if ('FORMAT_OPTIONS' in params) { - params['FORMAT_OPTIONS'] += ';dpi:' + dpi; - } else { - params['FORMAT_OPTIONS'] = 'dpi:' + dpi; - } - break; - case ol.source.wms.ServerType.MAPSERVER: - params['MAP_RESOLUTION'] = 90 * pixelRatio; - break; - case ol.source.wms.ServerType.CARMENTA_SERVER: - case ol.source.wms.ServerType.QGIS: - params['DPI'] = 90 * pixelRatio; - break; - default: - goog.asserts.fail('unknown serverType configured'); - break; - } - } - - params['WIDTH'] = size[0]; - params['HEIGHT'] = size[1]; - - var axisOrientation = projection.getAxisOrientation(); - var bbox; - if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') { - bbox = [extent[1], extent[0], extent[3], extent[2]]; - } else { - bbox = extent; - } - params['BBOX'] = bbox.join(','); - - return goog.uri.utils.appendParamsFromMap(this.url_, params); -}; - - -/** - * Return the URL used for this WMS source. - * @return {string|undefined} URL. - * @api stable - */ -ol.source.ImageWMS.prototype.getUrl = function() { - return this.url_; -}; - - -/** - * Set the image load function of the source. - * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. - * @api - */ -ol.source.ImageWMS.prototype.setImageLoadFunction = function( - imageLoadFunction) { - this.image_ = null; - this.imageLoadFunction_ = imageLoadFunction; - this.changed(); -}; - - -/** - * Set the URL to use for requests. - * @param {string|undefined} url URL. - * @api stable - */ -ol.source.ImageWMS.prototype.setUrl = function(url) { - if (url != this.url_) { - this.url_ = url; - this.image_ = null; - this.changed(); - } -}; - - -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.ImageWMS.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.updateV13_(); - this.image_ = null; - this.changed(); -}; - - -/** - * @private - */ -ol.source.ImageWMS.prototype.updateV13_ = function() { - var version = - goog.object.get(this.params_, 'VERSION', ol.DEFAULT_WMS_VERSION); - this.v13_ = goog.string.compareVersions(version, '1.3') >= 0; -}; - -goog.provide('ol.source.XYZ'); - -goog.require('ol.source.TileImage'); - - - -/** - * @classdesc - * Layer source for tile data with URLs in a set XYZ format that are - * defined in a URL template. By default, this follows the widely-used - * Google grid where `x` 0 and `y` 0 are in the top left. Grids like - * TMS where `x` 0 and `y` 0 are in the bottom left can be used by - * using the `{-y}` placeholder in the URL template, so long as the - * source does not have a custom tile grid. In this case, - * {@link ol.source.TileImage} can be used with a `tileUrlFunction` - * such as: - * - * tileUrlFunction: function(coordinate) { - * return 'http://mapserver.com/' + coordinate[0] + '/' + - * coordinate[1] + '/' + coordinate[2] + '.png'; - * } - * - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.XYZOptions} options XYZ options. - * @api stable - */ -ol.source.XYZ = function(options) { - var projection = options.projection !== undefined ? - options.projection : 'EPSG:3857'; - - var tileGrid = options.tileGrid !== undefined ? options.tileGrid : - ol.tilegrid.createXYZ({ - extent: ol.tilegrid.extentFromProjection(projection), - maxZoom: options.maxZoom, - tileSize: options.tileSize - }); - - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - projection: projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileGrid: tileGrid, - tileLoadFunction: options.tileLoadFunction, - tilePixelRatio: options.tilePixelRatio, - tileUrlFunction: options.tileUrlFunction, - url: options.url, - urls: options.urls, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - -}; -goog.inherits(ol.source.XYZ, ol.source.TileImage); - -goog.provide('ol.source.OSM'); - -goog.require('ol.Attribution'); -goog.require('ol.source.XYZ'); - - - -/** - * @classdesc - * Layer source for the OpenStreetMap tile server. - * - * @constructor - * @extends {ol.source.XYZ} - * @param {olx.source.OSMOptions=} opt_options Open Street Map options. - * @api stable - */ -ol.source.OSM = function(opt_options) { - - var options = opt_options || {}; - - var attributions; - if (options.attributions !== undefined) { - attributions = options.attributions; - } else { - attributions = [ol.source.OSM.ATTRIBUTION]; - } - - var crossOrigin = options.crossOrigin !== undefined ? - options.crossOrigin : 'anonymous'; - - var url = options.url !== undefined ? - options.url : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'; - - goog.base(this, { - attributions: attributions, - crossOrigin: crossOrigin, - opaque: true, - maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileLoadFunction: options.tileLoadFunction, - url: url, - wrapX: options.wrapX - }); - -}; -goog.inherits(ol.source.OSM, ol.source.XYZ); - - -/** - * The attribution containing a link to the OpenStreetMap Copyright and License - * page. - * @const - * @type {ol.Attribution} - * @api - */ -ol.source.OSM.ATTRIBUTION = new ol.Attribution({ - html: '© ' + - '<a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' + - 'contributors.' -}); - -goog.provide('ol.source.MapQuest'); - -goog.require('goog.asserts'); -goog.require('ol.Attribution'); -goog.require('ol.source.OSM'); -goog.require('ol.source.XYZ'); - - - -/** - * @classdesc - * Layer source for the MapQuest tile server. - * - * @constructor - * @extends {ol.source.XYZ} - * @param {olx.source.MapQuestOptions=} opt_options MapQuest options. - * @api stable - */ -ol.source.MapQuest = function(opt_options) { - - var options = opt_options || {}; - goog.asserts.assert(options.layer in ol.source.MapQuestConfig, - 'known layer configured'); - - var layerConfig = ol.source.MapQuestConfig[options.layer]; - - /** - * Layer. Possible values are `osm`, `sat`, and `hyb`. - * @type {string} - * @private - */ - this.layer_ = options.layer; - - var url = options.url !== undefined ? options.url : - 'https://otile{1-4}-s.mqcdn.com/tiles/1.0.0/' + - this.layer_ + '/{z}/{x}/{y}.jpg'; - - goog.base(this, { - attributions: layerConfig.attributions, - crossOrigin: 'anonymous', - logo: 'https://developer.mapquest.com/content/osm/mq_logo.png', - maxZoom: layerConfig.maxZoom, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - opaque: true, - tileLoadFunction: options.tileLoadFunction, - url: url - }); - -}; -goog.inherits(ol.source.MapQuest, ol.source.XYZ); - - -/** - * @const - * @type {ol.Attribution} - */ -ol.source.MapQuest.TILE_ATTRIBUTION = new ol.Attribution({ - html: 'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a>' -}); - - -/** - * @type {Object.<string, {maxZoom: number, attributions: (Array.<ol.Attribution>)}>} - */ -ol.source.MapQuestConfig = { - 'osm': { - maxZoom: 19, - attributions: [ - ol.source.MapQuest.TILE_ATTRIBUTION, - ol.source.OSM.ATTRIBUTION - ] - }, - 'sat': { - maxZoom: 18, - attributions: [ - ol.source.MapQuest.TILE_ATTRIBUTION, - new ol.Attribution({ - html: 'Portions Courtesy NASA/JPL-Caltech and ' + - 'U.S. Depart. of Agriculture, Farm Service Agency' - }) - ] - }, - 'hyb': { - maxZoom: 18, - attributions: [ - ol.source.MapQuest.TILE_ATTRIBUTION, - ol.source.OSM.ATTRIBUTION - ] - } -}; - - -/** - * Get the layer of the source, either `osm`, `sat`, or `hyb`. - * @return {string} Layer. - * @api - */ -ol.source.MapQuest.prototype.getLayer = function() { - return this.layer_; -}; - -goog.provide('ol.ext.pixelworks'); -/** @typedef {function(*)} */ -ol.ext.pixelworks; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; -/** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixelworks = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ -var Processor = _dereq_('./processor'); - -exports.Processor = Processor; - -},{"./processor":2}],2:[function(_dereq_,module,exports){ -/* eslint-disable dot-notation */ - -/** - * Create a function for running operations. - * @param {function(Array, Object):*} operation The operation. - * @return {function(Object):ArrayBuffer} A function that takes an object with - * buffers, meta, imageOps, width, and height properties and returns an array - * buffer. - */ -function createMinion(operation) { - return function(data) { - // bracket notation for minification support - var buffers = data['buffers']; - var meta = data['meta']; - var imageOps = data['imageOps']; - var width = data['width']; - var height = data['height']; - - var numBuffers = buffers.length; - var numBytes = buffers[0].byteLength; - var output, b; - - if (imageOps) { - var images = new Array(numBuffers); - for (b = 0; b < numBuffers; ++b) { - images[b] = new ImageData( - new Uint8ClampedArray(buffers[b]), width, height); - } - output = operation(images, meta).data; - } else { - output = new Uint8ClampedArray(numBytes); - var arrays = new Array(numBuffers); - var pixels = new Array(numBuffers); - for (b = 0; b < numBuffers; ++b) { - arrays[b] = new Uint8ClampedArray(buffers[b]); - pixels[b] = [0, 0, 0, 0]; - } - for (var i = 0; i < numBytes; i += 4) { - for (var j = 0; j < numBuffers; ++j) { - var array = arrays[j]; - pixels[j][0] = array[i]; - pixels[j][1] = array[i + 1]; - pixels[j][2] = array[i + 2]; - pixels[j][3] = array[i + 3]; - } - var pixel = operation(pixels, meta); - output[i] = pixel[0]; - output[i + 1] = pixel[1]; - output[i + 2] = pixel[2]; - output[i + 3] = pixel[3]; - } - } - return output.buffer; - }; -} - -/** - * Create a worker for running operations. - * @param {Object} config Configuration. - * @param {function(Object)} onMessage Called with a message event. - * @return {Worker} The worker. - */ -function createWorker(config, onMessage) { - var lib = Object.keys(config.lib || {}).map(function(name) { - return 'var ' + name + ' = ' + config.lib[name].toString() + ';'; - }); - - var lines = lib.concat([ - 'var __minion__ = (' + createMinion.toString() + ')(', - config.operation.toString(), - ');', - 'self.addEventListener("message", function(__event__) {', - 'var buffer = __minion__(__event__.data);', - 'self.postMessage({buffer: buffer, meta: __event__.data.meta}, [buffer]);', - '});' - ]); - - var blob = new Blob(lines, {type: 'text/javascript'}); - var source = URL.createObjectURL(blob); - var worker = new Worker(source); - worker.addEventListener('message', onMessage); - return worker; -} - -/** - * Create a faux worker for running operations. - * @param {Object} config Configuration. - * @param {function(Object)} onMessage Called with a message event. - * @return {Object} The faux worker. - */ -function createFauxWorker(config, onMessage) { - var minion = createMinion(config.operation); - return { - postMessage: function(data) { - setTimeout(function() { - onMessage({data: {buffer: minion(data), meta: data.meta}}); - }, 0); - } - }; -} - -/** - * A processor runs pixel or image operations in workers. - * @param {Object} config Configuration. - */ -function Processor(config) { - this._imageOps = !!config.imageOps; - var threads; - if (config.threads === 0) { - threads = 0; - } else if (this._imageOps) { - threads = 1; - } else { - threads = config.threads || 1; - } - var workers = []; - if (threads) { - for (var i = 0; i < threads; ++i) { - workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i)); - } - } else { - workers[0] = createFauxWorker(config, this._onWorkerMessage.bind(this, 0)); - } - this._workers = workers; - this._queue = []; - this._maxQueueLength = config.queue || Infinity; - this._running = 0; - this._dataLookup = {}; - this._job = null; -} - -/** - * Run operation on input data. - * @param {Array.<Array|ImageData>} inputs Array of pixels or image data - * (depending on the operation type). - * @param {Object} meta A user data object. This is passed to all operations - * and must be serializable. - * @param {function(Error, ImageData, Object)} callback Called when work - * completes. The first argument is any error. The second is the ImageData - * generated by operations. The third is the user data object. - */ -Processor.prototype.process = function(inputs, meta, callback) { - this._enqueue({ - inputs: inputs, - meta: meta, - callback: callback - }); - this._dispatch(); -}; - -/** - * Stop responding to any completed work and destroy the processor. - */ -Processor.prototype.destroy = function() { - for (var key in this) { - this[key] = null; - } - this._destroyed = true; -}; - -/** - * Add a job to the queue. - * @param {Object} job The job. - */ -Processor.prototype._enqueue = function(job) { - this._queue.push(job); - while (this._queue.length > this._maxQueueLength) { - this._queue.shift().callback(null, null); - } -}; - -/** - * Dispatch a job. - */ -Processor.prototype._dispatch = function() { - if (this._running === 0 && this._queue.length > 0) { - var job = this._job = this._queue.shift(); - var width = job.inputs[0].width; - var height = job.inputs[0].height; - var buffers = job.inputs.map(function(input) { - return input.data.buffer; - }); - var threads = this._workers.length; - this._running = threads; - if (threads === 1) { - this._workers[0].postMessage({ - 'buffers': buffers, - 'meta': job.meta, - 'imageOps': this._imageOps, - 'width': width, - 'height': height - }, buffers); - } else { - var length = job.inputs[0].data.length; - var segmentLength = 4 * Math.ceil(length / 4 / threads); - for (var i = 0; i < threads; ++i) { - var offset = i * segmentLength; - var slices = []; - for (var j = 0, jj = buffers.length; j < jj; ++j) { - slices.push(buffers[i].slice(offset, offset + segmentLength)); - } - this._workers[i].postMessage({ - 'buffers': slices, - 'meta': job.meta, - 'imageOps': this._imageOps, - 'width': width, - 'height': height - }, slices); - } - } - } -}; - -/** - * Handle messages from the worker. - * @param {number} index The worker index. - * @param {Object} event The message event. - */ -Processor.prototype._onWorkerMessage = function(index, event) { - if (this._destroyed) { - return; - } - this._dataLookup[index] = event.data; - --this._running; - if (this._running === 0) { - this._resolveJob(); - } -}; - -/** - * Resolve a job. If there are no more worker threads, the processor callback - * will be called. - */ -Processor.prototype._resolveJob = function() { - var job = this._job; - var threads = this._workers.length; - var data, meta; - if (threads === 1) { - data = new Uint8ClampedArray(this._dataLookup[0]['buffer']); - meta = this._dataLookup[0]['meta']; - } else { - var length = job.inputs[0].data.length; - data = new Uint8ClampedArray(length); - meta = new Array(length); - var segmentLength = 4 * Math.ceil(length / 4 / threads); - for (var i = 0; i < threads; ++i) { - var buffer = this._dataLookup[i]['buffer']; - var offset = i * segmentLength; - data.set(new Uint8ClampedArray(buffer), offset); - meta[i] = this._dataLookup[i]['meta']; - } - } - this._job = null; - this._dataLookup = {}; - job.callback(null, - new ImageData(data, job.inputs[0].width, job.inputs[0].height), meta); - this._dispatch(); -}; - -module.exports = Processor; - -},{}]},{},[1])(1) -}); -ol.ext.pixelworks = module.exports; -})(); - -goog.provide('ol.source.Raster'); -goog.provide('ol.source.RasterEvent'); -goog.provide('ol.source.RasterEventType'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ImageCanvas'); -goog.require('ol.TileQueue'); -goog.require('ol.dom'); -goog.require('ol.ext.pixelworks'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Tile'); -goog.require('ol.raster.OperationType'); -goog.require('ol.renderer.canvas.ImageLayer'); -goog.require('ol.renderer.canvas.TileLayer'); -goog.require('ol.source.Image'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); - - - -/** - * @classdesc - * A source that transforms data from any number of input sources using an array - * of {@link ol.raster.Operation} functions to transform input pixel values into - * output pixel values. - * - * @constructor - * @extends {ol.source.Image} - * @param {olx.source.RasterOptions} options Options. - * @api - */ -ol.source.Raster = function(options) { - - /** - * @private - * @type {*} - */ - this.worker_ = null; - - /** - * @private - * @type {ol.raster.OperationType} - */ - this.operationType_ = options.operationType !== undefined ? - options.operationType : ol.raster.OperationType.PIXEL; - - /** - * @private - * @type {number} - */ - this.threads_ = options.threads !== undefined ? options.threads : 1; - - /** - * @private - * @type {Array.<ol.renderer.canvas.Layer>} - */ - this.renderers_ = ol.source.Raster.createRenderers_(options.sources); - - for (var r = 0, rr = this.renderers_.length; r < rr; ++r) { - goog.events.listen(this.renderers_[r], goog.events.EventType.CHANGE, - this.changed, false, this); - } - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.canvasContext_ = ol.dom.createCanvasContext2D(); - - /** - * @private - * @type {ol.TileQueue} - */ - this.tileQueue_ = new ol.TileQueue( - function() { return 1; }, - goog.bind(this.changed, this)); - - var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_); - var layerStates = {}; - for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i]; - } - - /** - * The most recently rendered state. - * @type {?ol.source.Raster.RenderedState} - * @private - */ - this.renderedState_ = null; - - /** - * The most recently rendered image canvas. - * @type {ol.ImageCanvas} - * @private - */ - this.renderedImageCanvas_ = null; - - /** - * @private - * @type {olx.FrameState} - */ - this.frameState_ = { - animate: false, - attributions: {}, - coordinateToPixelMatrix: goog.vec.Mat4.createNumber(), - extent: null, - focus: null, - index: 0, - layerStates: layerStates, - layerStatesArray: layerStatesArray, - logos: {}, - pixelRatio: 1, - pixelToCoordinateMatrix: goog.vec.Mat4.createNumber(), - postRenderFunctions: [], - size: [0, 0], - skippedFeatureUids: {}, - tileQueue: this.tileQueue_, - time: Date.now(), - usedTiles: {}, - viewState: /** @type {olx.ViewState} */ ({ - rotation: 0 - }), - viewHints: [], - wantedTiles: {} - }; - - goog.base(this, {}); - - if (options.operation !== undefined) { - this.setOperation(options.operation, options.lib); - } - -}; -goog.inherits(ol.source.Raster, ol.source.Image); - - -/** - * Set the operation. - * @param {ol.raster.Operation} operation New operation. - * @param {Object=} opt_lib Functions that will be available to operations run - * in a worker. - * @api - */ -ol.source.Raster.prototype.setOperation = function(operation, opt_lib) { - this.worker_ = new ol.ext.pixelworks.Processor({ - operation: operation, - imageOps: this.operationType_ === ol.raster.OperationType.IMAGE, - queue: 1, - lib: opt_lib, - threads: this.threads_ - }); - this.changed(); -}; - - -/** - * Update the stored frame state. - * @param {ol.Extent} extent The view extent (in map units). - * @param {number} resolution The view resolution. - * @param {ol.proj.Projection} projection The view projection. - * @return {olx.FrameState} The updated frame state. - * @private - */ -ol.source.Raster.prototype.updateFrameState_ = - function(extent, resolution, projection) { - - var frameState = /** @type {olx.FrameState} */ ( - goog.object.clone(this.frameState_)); - - frameState.viewState = /** @type {olx.ViewState} */ ( - goog.object.clone(frameState.viewState)); - - var center = ol.extent.getCenter(extent); - var width = Math.round(ol.extent.getWidth(extent) / resolution); - var height = Math.round(ol.extent.getHeight(extent) / resolution); - - frameState.extent = extent; - frameState.focus = ol.extent.getCenter(extent); - frameState.size[0] = width; - frameState.size[1] = height; - - var viewState = frameState.viewState; - viewState.center = center; - viewState.projection = projection; - viewState.resolution = resolution; - return frameState; -}; - - -/** - * Determine if the most recently rendered image canvas is dirty. - * @param {ol.Extent} extent The requested extent. - * @param {number} resolution The requested resolution. - * @return {boolean} The image is dirty. - * @private - */ -ol.source.Raster.prototype.isDirty_ = function(extent, resolution) { - var state = this.renderedState_; - return !state || - this.getRevision() !== state.revision || - resolution !== state.resolution || - !ol.extent.equals(extent, state.extent); -}; - - -/** - * @inheritDoc - */ -ol.source.Raster.prototype.getImage = - function(extent, resolution, pixelRatio, projection) { - - if (!this.allSourcesReady_()) { - return null; - } - - if (!this.isDirty_(extent, resolution)) { - return this.renderedImageCanvas_; - } - - var context = this.canvasContext_; - var canvas = context.canvas; - - var width = Math.round(ol.extent.getWidth(extent) / resolution); - var height = Math.round(ol.extent.getHeight(extent) / resolution); - - if (width !== canvas.width || - height !== canvas.height) { - canvas.width = width; - canvas.height = height; - } - - var frameState = this.updateFrameState_(extent, resolution, projection); - - var imageCanvas = new ol.ImageCanvas( - extent, resolution, 1, this.getAttributions(), canvas, - this.composeFrame_.bind(this, frameState)); - - this.renderedImageCanvas_ = imageCanvas; - - this.renderedState_ = { - extent: extent, - resolution: resolution, - revision: this.getRevision() - }; - - return imageCanvas; -}; - - -/** - * Determine if all sources are ready. - * @return {boolean} All sources are ready. - * @private - */ -ol.source.Raster.prototype.allSourcesReady_ = function() { - var ready = true; - var source; - for (var i = 0, ii = this.renderers_.length; i < ii; ++i) { - source = this.renderers_[i].getLayer().getSource(); - if (source.getState() !== ol.source.State.READY) { - ready = false; - break; - } - } - return ready; -}; - - -/** - * Compose the frame. This renders data from all sources, runs pixel-wise - * operations, and renders the result to the stored canvas context. - * @param {olx.FrameState} frameState The frame state. - * @param {function(Error)} callback Called when composition is complete. - * @private - */ -ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) { - var len = this.renderers_.length; - var imageDatas = new Array(len); - for (var i = 0; i < len; ++i) { - var imageData = ol.source.Raster.getImageData_( - this.renderers_[i], frameState, frameState.layerStatesArray[i]); - if (imageData) { - imageDatas[i] = imageData; - } else { - // image not yet ready - return; - } - } - - var data = {}; - this.dispatchEvent(new ol.source.RasterEvent( - ol.source.RasterEventType.BEFOREOPERATIONS, frameState, data)); - - this.worker_.process(imageDatas, data, - this.onWorkerComplete_.bind(this, frameState, callback)); - - frameState.tileQueue.loadMoreTiles(16, 16); -}; - - -/** - * Called when pixel processing is complete. - * @param {olx.FrameState} frameState The frame state. - * @param {function(Error)} callback Called when rendering is complete. - * @param {Error} err Any error during processing. - * @param {ImageData} output The output image data. - * @param {Object} data The user data. - * @private - */ -ol.source.Raster.prototype.onWorkerComplete_ = - function(frameState, callback, err, output, data) { - if (err) { - callback(err); - return; - } - if (!output) { - // job aborted - return; - } - - this.dispatchEvent(new ol.source.RasterEvent( - ol.source.RasterEventType.AFTEROPERATIONS, frameState, data)); - - var resolution = frameState.viewState.resolution / frameState.pixelRatio; - if (!this.isDirty_(frameState.extent, resolution)) { - this.canvasContext_.putImageData(output, 0, 0); - } - - callback(null); -}; - - -/** - * Get image data from a renderer. - * @param {ol.renderer.canvas.Layer} renderer Layer renderer. - * @param {olx.FrameState} frameState The frame state. - * @param {ol.layer.LayerState} layerState The layer state. - * @return {ImageData} The image data. - * @private - */ -ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) { - renderer.prepareFrame(frameState, layerState); - // We should be able to call renderer.composeFrame(), but this is inefficient - // for tiled sources (we've already rendered to an intermediate canvas in the - // prepareFrame call and we don't need to render again to the output canvas). - // TODO: make all canvas renderers render to a single canvas - var image = renderer.getImage(); - if (!image) { - return null; - } - var imageTransform = renderer.getImageTransform(); - var dx = Math.round(goog.vec.Mat4.getElement(imageTransform, 0, 3)); - var dy = Math.round(goog.vec.Mat4.getElement(imageTransform, 1, 3)); - var width = frameState.size[0]; - var height = frameState.size[1]; - if (image instanceof Image) { - if (!ol.source.Raster.context_) { - ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); - } else { - var canvas = ol.source.Raster.context_.canvas; - if (canvas.width !== width || canvas.height !== height) { - ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); - } else { - ol.source.Raster.context_.clearRect(0, 0, width, height); - } - } - var dw = Math.round( - image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0)); - var dh = Math.round( - image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1)); - ol.source.Raster.context_.drawImage(image, dx, dy, dw, dh); - return ol.source.Raster.context_.getImageData(0, 0, width, height); - } else { - return image.getContext('2d').getImageData(-dx, -dy, width, height); - } -}; - - -/** - * A reusable canvas context. - * @type {CanvasRenderingContext2D} - * @private - */ -ol.source.Raster.context_ = null; - - -/** - * Get a list of layer states from a list of renderers. - * @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers. - * @return {Array.<ol.layer.LayerState>} The layer states. - * @private - */ -ol.source.Raster.getLayerStatesArray_ = function(renderers) { - return renderers.map(function(renderer) { - return renderer.getLayer().getLayerState(); - }); -}; - - -/** - * Create renderers for all sources. - * @param {Array.<ol.source.Source>} sources The sources. - * @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers. - * @private - */ -ol.source.Raster.createRenderers_ = function(sources) { - var len = sources.length; - var renderers = new Array(len); - for (var i = 0; i < len; ++i) { - renderers[i] = ol.source.Raster.createRenderer_(sources[i]); - } - return renderers; -}; - - -/** - * Create a renderer for the provided source. - * @param {ol.source.Source} source The source. - * @return {ol.renderer.canvas.Layer} The renderer. - * @private - */ -ol.source.Raster.createRenderer_ = function(source) { - var renderer = null; - if (source instanceof ol.source.Tile) { - renderer = ol.source.Raster.createTileRenderer_(source); - } else if (source instanceof ol.source.Image) { - renderer = ol.source.Raster.createImageRenderer_(source); - } else { - goog.asserts.fail('Unsupported source type: ' + source); - } - return renderer; -}; - - -/** - * Create an image renderer for the provided source. - * @param {ol.source.Image} source The source. - * @return {ol.renderer.canvas.Layer} The renderer. - * @private - */ -ol.source.Raster.createImageRenderer_ = function(source) { - var layer = new ol.layer.Image({source: source}); - return new ol.renderer.canvas.ImageLayer(layer); -}; - - -/** - * Create a tile renderer for the provided source. - * @param {ol.source.Tile} source The source. - * @return {ol.renderer.canvas.Layer} The renderer. - * @private - */ -ol.source.Raster.createTileRenderer_ = function(source) { - var layer = new ol.layer.Tile({source: source}); - return new ol.renderer.canvas.TileLayer(layer); -}; - - -/** - * @typedef {{revision: number, - * resolution: number, - * extent: ol.Extent}} - */ -ol.source.Raster.RenderedState; - - - -/** - * @classdesc - * Events emitted by {@link ol.source.Raster} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.RasterEvent} - * @param {string} type Type. - * @param {olx.FrameState} frameState The frame state. - * @param {Object} data An object made available to operations. - */ -ol.source.RasterEvent = function(type, frameState, data) { - goog.base(this, type); - - /** - * The raster extent. - * @type {ol.Extent} - * @api - */ - this.extent = frameState.extent; - - /** - * The pixel resolution (map units per pixel). - * @type {number} - * @api - */ - this.resolution = frameState.viewState.resolution / frameState.pixelRatio; - - /** - * An object made available to all operations. This can be used by operations - * as a storage object (e.g. for calculating statistics). - * @type {Object} - * @api - */ - this.data = data; - -}; -goog.inherits(ol.source.RasterEvent, goog.events.Event); - - -/** - * @enum {string} - */ -ol.source.RasterEventType = { - /** - * Triggered before operations are run. - * @event ol.source.RasterEvent#beforeoperations - * @api - */ - BEFOREOPERATIONS: 'beforeoperations', - - /** - * Triggered after operations are run. - * @event ol.source.RasterEvent#afteroperations - * @api - */ - AFTEROPERATIONS: 'afteroperations' -}; - -goog.provide('ol.source.Stamen'); - -goog.require('goog.asserts'); -goog.require('ol.Attribution'); -goog.require('ol.source.OSM'); -goog.require('ol.source.XYZ'); - - -/** - * @type {Object.<string, {extension: string, opaque: boolean}>} - */ -ol.source.StamenLayerConfig = { - 'terrain': { - extension: 'jpg', - opaque: true - }, - 'terrain-background': { - extension: 'jpg', - opaque: true - }, - 'terrain-labels': { - extension: 'png', - opaque: false - }, - 'terrain-lines': { - extension: 'png', - opaque: false - }, - 'toner-background': { - extension: 'png', - opaque: true - }, - 'toner': { - extension: 'png', - opaque: true - }, - 'toner-hybrid': { - extension: 'png', - opaque: false - }, - 'toner-labels': { - extension: 'png', - opaque: false - }, - 'toner-lines': { - extension: 'png', - opaque: false - }, - 'toner-lite': { - extension: 'png', - opaque: true - }, - 'watercolor': { - extension: 'jpg', - opaque: true - } -}; - - -/** - * @type {Object.<string, {minZoom: number, maxZoom: number}>} - */ -ol.source.StamenProviderConfig = { - 'terrain': { - minZoom: 4, - maxZoom: 18 - }, - 'toner': { - minZoom: 0, - maxZoom: 20 - }, - 'watercolor': { - minZoom: 3, - maxZoom: 16 - } -}; - - - -/** - * @classdesc - * Layer source for the Stamen tile server. - * - * @constructor - * @extends {ol.source.XYZ} - * @param {olx.source.StamenOptions} options Stamen options. - * @api stable - */ -ol.source.Stamen = function(options) { - - var i = options.layer.indexOf('-'); - var provider = i == -1 ? options.layer : options.layer.slice(0, i); - goog.asserts.assert(provider in ol.source.StamenProviderConfig, - 'known provider configured'); - var providerConfig = ol.source.StamenProviderConfig[provider]; - - goog.asserts.assert(options.layer in ol.source.StamenLayerConfig, - 'known layer configured'); - var layerConfig = ol.source.StamenLayerConfig[options.layer]; - - var url = options.url !== undefined ? options.url : - 'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer + - '/{z}/{x}/{y}.' + layerConfig.extension; - - goog.base(this, { - attributions: ol.source.Stamen.ATTRIBUTIONS, - crossOrigin: 'anonymous', - maxZoom: providerConfig.maxZoom, - // FIXME uncomment the following when tilegrid supports minZoom - //minZoom: providerConfig.minZoom, - opaque: layerConfig.opaque, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileLoadFunction: options.tileLoadFunction, - url: url - }); - -}; -goog.inherits(ol.source.Stamen, ol.source.XYZ); - - -/** - * @const - * @type {Array.<ol.Attribution>} - */ -ol.source.Stamen.ATTRIBUTIONS = [ - new ol.Attribution({ - html: 'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, ' + - 'under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY' + - ' 3.0</a>.' - }), - ol.source.OSM.ATTRIBUTION -]; - -goog.provide('ol.source.TileArcGISRest'); - -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.uri.utils'); -goog.require('ol'); -goog.require('ol.TileCoord'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.size'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilecoord'); - - - -/** - * @classdesc - * Layer source for tile data from ArcGIS Rest services. Map and Image - * Services are supported. - * - * For cached ArcGIS services, better performance is available using the - * {@link ol.source.XYZ} data source. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.TileArcGISRestOptions=} opt_options Tile ArcGIS Rest - * options. - * @api - */ -ol.source.TileArcGISRest = function(opt_options) { - - var options = opt_options || {}; - - var params = options.params !== undefined ? options.params : {}; - - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - projection: options.projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction, - tileUrlFunction: goog.bind(this.tileUrlFunction_, this), - url: options.url, - urls: options.urls, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - - /** - * @private - * @type {Object} - */ - this.params_ = params; - - /** - * @private - * @type {ol.Extent} - */ - this.tmpExtent_ = ol.extent.createEmpty(); - -}; -goog.inherits(ol.source.TileArcGISRest, ol.source.TileImage); - - -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api - */ -ol.source.TileArcGISRest.prototype.getParams = function() { - return this.params_; -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {ol.Extent} tileExtent Tile extent. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {Object} params Params. - * @return {string|undefined} Request URL. - * @private - */ -ol.source.TileArcGISRest.prototype.getRequestUrl_ = - function(tileCoord, tileSize, tileExtent, - pixelRatio, projection, params) { - - var urls = this.urls; - if (!urls) { - return undefined; - } - - // ArcGIS Server only wants the numeric portion of the projection ID. - var srid = projection.getCode().split(':').pop(); - - params['SIZE'] = tileSize[0] + ',' + tileSize[1]; - params['BBOX'] = tileExtent.join(','); - params['BBOXSR'] = srid; - params['IMAGESR'] = srid; - params['DPI'] = Math.round(90 * pixelRatio); - - var url; - if (urls.length == 1) { - url = urls[0]; - } else { - var index = goog.math.modulo(ol.tilecoord.hash(tileCoord), urls.length); - url = urls[index]; - } - - if (!goog.string.endsWith(url, '/')) { - url = url + '/'; - } - - // If a MapServer, use export. If an ImageServer, use exportImage. - if (goog.string.endsWith(url, 'MapServer/')) { - url = url + 'export'; - } - else if (goog.string.endsWith(url, 'ImageServer/')) { - url = url + 'exportImage'; - } - else { - goog.asserts.fail('Unknown Rest Service', url); - } - - return goog.uri.utils.appendParamsFromMap(url, params); -}; - - -/** - * @param {number} z Z. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.Size} Size. - */ -ol.source.TileArcGISRest.prototype.getTilePixelSize = - function(z, pixelRatio, projection) { - var tileSize = goog.base(this, 'getTilePixelSize', z, pixelRatio, projection); - if (pixelRatio == 1) { - return tileSize; - } else { - return ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - * @private - */ -ol.source.TileArcGISRest.prototype.tileUrlFunction_ = - function(tileCoord, pixelRatio, projection) { - - var tileGrid = this.getTileGrid(); - if (!tileGrid) { - tileGrid = this.getTileGridForProjection(projection); - } - - if (tileGrid.getResolutions().length <= tileCoord[0]) { - return undefined; - } - - var tileExtent = tileGrid.getTileCoordExtent( - tileCoord, this.tmpExtent_); - var tileSize = ol.size.toSize( - tileGrid.getTileSize(tileCoord[0]), this.tmpSize); - - if (pixelRatio != 1) { - tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } - - // Apply default params and override with user specified values. - var baseParams = { - 'F': 'image', - 'FORMAT': 'PNG32', - 'TRANSPARENT': true - }; - goog.object.extend(baseParams, this.params_); - - return this.getRequestUrl_(tileCoord, tileSize, tileExtent, - pixelRatio, projection, baseParams); -}; - - -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.TileArcGISRest.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.changed(); -}; - -goog.provide('ol.source.TileDebug'); - -goog.require('ol.Tile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileState'); -goog.require('ol.dom'); -goog.require('ol.size'); -goog.require('ol.source.Tile'); -goog.require('ol.tilecoord'); - - - -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {string} text Text. - * @private - */ -ol.DebugTile_ = function(tileCoord, tileSize, text) { - - goog.base(this, tileCoord, ol.TileState.LOADED); - - /** - * @private - * @type {ol.Size} - */ - this.tileSize_ = tileSize; - - /** - * @private - * @type {string} - */ - this.text_ = text; - - /** - * @private - * @type {Object.<number, HTMLCanvasElement>} - */ - this.canvasByContext_ = {}; - -}; -goog.inherits(ol.DebugTile_, ol.Tile); - - -/** - * Get the image element for this tile. - * @param {Object=} opt_context Optional context. Only used by the DOM - * renderer. - * @return {HTMLCanvasElement} Image. - */ -ol.DebugTile_.prototype.getImage = function(opt_context) { - var key = opt_context !== undefined ? goog.getUid(opt_context) : -1; - if (key in this.canvasByContext_) { - return this.canvasByContext_[key]; - } else { - - var tileSize = this.tileSize_; - var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]); - - context.strokeStyle = 'black'; - context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); - - context.fillStyle = 'black'; - context.textAlign = 'center'; - context.textBaseline = 'middle'; - context.font = '24px sans-serif'; - context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2); - - this.canvasByContext_[key] = context.canvas; - return context.canvas; - - } -}; - - - -/** - * @classdesc - * A pseudo tile source, which does not fetch tiles from a server, but renders - * a grid outline for the tile grid/projection along with the coordinates for - * each tile. See examples/canvas-tiles for an example. - * - * Uses Canvas context2d, so requires Canvas support. - * - * @constructor - * @extends {ol.source.Tile} - * @param {olx.source.TileDebugOptions} options Debug tile options. - * @api - */ -ol.source.TileDebug = function(options) { - - goog.base(this, { - opaque: false, - projection: options.projection, - tileGrid: options.tileGrid, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - -}; -goog.inherits(ol.source.TileDebug, ol.source.Tile); - - -/** - * @inheritDoc - */ -ol.source.TileDebug.prototype.getTile = function(z, x, y) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey)); - } else { - var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z)); - var tileCoord = [z, x, y]; - var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord); - var text = !textTileCoord ? '' : ol.tilecoord.toString( - this.getTileCoordForTileUrlFunction(textTileCoord)); - var tile = new ol.DebugTile_(tileCoord, tileSize, text); - this.tileCache.set(tileCoordKey, tile); - return tile; - } -}; - -// FIXME check order of async callbacks - -/** - * @see http://mapbox.com/developers/api/ - */ - -goog.provide('ol.source.TileJSON'); -goog.provide('ol.tilejson'); - -goog.require('goog.asserts'); -goog.require('goog.net.Jsonp'); -goog.require('ol.Attribution'); -goog.require('ol.TileRange'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.TileImage'); - - - -/** - * @classdesc - * Layer source for tile data in TileJSON format. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.TileJSONOptions} options TileJSON options. - * @api stable - */ -ol.source.TileJSON = function(options) { - - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - projection: ol.proj.get('EPSG:3857'), - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - state: ol.source.State.LOADING, - tileLoadFunction: options.tileLoadFunction, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - - var request = new goog.net.Jsonp(options.url); - request.send(undefined, goog.bind(this.handleTileJSONResponse, this), - goog.bind(this.handleTileJSONError, this)); - -}; -goog.inherits(ol.source.TileJSON, ol.source.TileImage); - - -/** - * @protected - * @param {TileJSON} tileJSON Tile JSON. - */ -ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) { - - var epsg4326Projection = ol.proj.get('EPSG:4326'); - - var sourceProjection = this.getProjection(); - var extent; - if (tileJSON.bounds !== undefined) { - var transform = ol.proj.getTransformFromProjections( - epsg4326Projection, sourceProjection); - extent = ol.extent.applyTransform(tileJSON.bounds, transform); - } - - if (tileJSON.scheme !== undefined) { - goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"'); - } - var minZoom = tileJSON.minzoom || 0; - var maxZoom = tileJSON.maxzoom || 22; - var tileGrid = ol.tilegrid.createXYZ({ - extent: ol.tilegrid.extentFromProjection(sourceProjection), - maxZoom: maxZoom, - minZoom: minZoom - }); - this.tileGrid = tileGrid; - - this.tileUrlFunction = - ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid); - - if (tileJSON.attribution !== undefined && !this.getAttributions()) { - var attributionExtent = extent !== undefined ? - extent : epsg4326Projection.getExtent(); - /** @type {Object.<string, Array.<ol.TileRange>>} */ - var tileRanges = {}; - var z, zKey; - for (z = minZoom; z <= maxZoom; ++z) { - zKey = z.toString(); - tileRanges[zKey] = - [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; - } - this.setAttributions([ - new ol.Attribution({ - html: tileJSON.attribution, - tileRanges: tileRanges - }) - ]); - } - - this.setState(ol.source.State.READY); - -}; - - -/** - * @protected - */ -ol.source.TileJSON.prototype.handleTileJSONError = function() { - this.setState(ol.source.State.ERROR); -}; - -goog.provide('ol.source.TileUTFGrid'); - -goog.require('goog.asserts'); -goog.require('goog.async.nextTick'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.net.Jsonp'); -goog.require('ol.Attribution'); -goog.require('ol.Tile'); -goog.require('ol.TileState'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); - - - -/** - * @classdesc - * Layer source for UTFGrid interaction data loaded from TileJSON format. - * - * @constructor - * @extends {ol.source.Tile} - * @param {olx.source.TileUTFGridOptions} options Source options. - * @api - */ -ol.source.TileUTFGrid = function(options) { - goog.base(this, { - projection: ol.proj.get('EPSG:3857'), - state: ol.source.State.LOADING - }); - - /** - * @private - * @type {boolean} - */ - this.preemptive_ = options.preemptive !== undefined ? - options.preemptive : true; - - /** - * @private - * @type {!ol.TileUrlFunctionType} - */ - this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction; - - /** - * @private - * @type {string|undefined} - */ - this.template_ = undefined; - - var request = new goog.net.Jsonp(options.url); - request.send(undefined, goog.bind(this.handleTileJSONResponse, this)); -}; -goog.inherits(ol.source.TileUTFGrid, ol.source.Tile); - - -/** - * Return the template from TileJSON. - * @return {string|undefined} The template from TileJSON. - * @api - */ -ol.source.TileUTFGrid.prototype.getTemplate = function() { - return this.template_; -}; - - -/** - * Calls the callback (synchronously by default) with the available data - * for given coordinate and resolution (or `null` if not yet loaded or - * in case of an error). - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {function(this: T, Object)} callback Callback. - * @param {T=} opt_this The object to use as `this` in the callback. - * @param {boolean=} opt_request If `true` the callback is always async. - * The tile data is requested if not yet loaded. - * @template T - * @api - */ -ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function( - coordinate, resolution, callback, opt_this, opt_request) { - if (this.tileGrid) { - var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution( - coordinate, resolution); - var tile = /** @type {!ol.source.TileUTFGridTile_} */(this.getTile( - tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection())); - tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request); - } else { - if (opt_request === true) { - goog.async.nextTick(function() { - callback.call(opt_this, null); - }); - } else { - callback.call(opt_this, null); - } - } -}; - - -/** - * TODO: very similar to ol.source.TileJSON#handleTileJSONResponse - * @protected - * @param {TileJSON} tileJSON Tile JSON. - */ -ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) { - - var epsg4326Projection = ol.proj.get('EPSG:4326'); - - var sourceProjection = this.getProjection(); - var extent; - if (tileJSON.bounds !== undefined) { - var transform = ol.proj.getTransformFromProjections( - epsg4326Projection, sourceProjection); - extent = ol.extent.applyTransform(tileJSON.bounds, transform); - } - - if (tileJSON.scheme !== undefined) { - goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"'); - } - var minZoom = tileJSON.minzoom || 0; - var maxZoom = tileJSON.maxzoom || 22; - var tileGrid = ol.tilegrid.createXYZ({ - extent: ol.tilegrid.extentFromProjection(sourceProjection), - maxZoom: maxZoom, - minZoom: minZoom - }); - this.tileGrid = tileGrid; - - this.template_ = tileJSON.template; - - var grids = tileJSON.grids; - if (!grids) { - this.setState(ol.source.State.ERROR); - return; - } - - this.tileUrlFunction_ = - ol.TileUrlFunction.createFromTemplates(grids, tileGrid); - - if (tileJSON.attribution !== undefined) { - var attributionExtent = extent !== undefined ? - extent : epsg4326Projection.getExtent(); - /** @type {Object.<string, Array.<ol.TileRange>>} */ - var tileRanges = {}; - var z, zKey; - for (z = minZoom; z <= maxZoom; ++z) { - zKey = z.toString(); - tileRanges[zKey] = - [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; - } - this.setAttributions([ - new ol.Attribution({ - html: tileJSON.attribution, - tileRanges: tileRanges - }) - ]); - } - - this.setState(ol.source.State.READY); - -}; - - -/** - * @inheritDoc - */ -ol.source.TileUTFGrid.prototype.getTile = - function(z, x, y, pixelRatio, projection) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); - } else { - goog.asserts.assert(projection, 'argument projection is truthy'); - var tileCoord = [z, x, y]; - var urlTileCoord = - this.getTileCoordForTileUrlFunction(tileCoord, projection); - var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection); - var tile = new ol.source.TileUTFGridTile_( - tileCoord, - tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, - tileUrl !== undefined ? tileUrl : '', - this.tileGrid.getTileCoordExtent(tileCoord), - this.preemptive_); - this.tileCache.set(tileCoordKey, tile); - return tile; - } -}; - - -/** - * @inheritDoc - */ -ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - this.tileCache.get(tileCoordKey); - } -}; - - - -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Image source URI. - * @param {ol.Extent} extent Extent of the tile. - * @param {boolean} preemptive Load the tile when visible (before it's needed). - * @private - */ -ol.source.TileUTFGridTile_ = - function(tileCoord, state, src, extent, preemptive) { - - goog.base(this, tileCoord, state); - - /** - * @private - * @type {string} - */ - this.src_ = src; - - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = extent; - - /** - * @private - * @type {boolean} - */ - this.preemptive_ = preemptive; - - /** - * @private - * @type {Array.<string>} - */ - this.grid_ = null; - - /** - * @private - * @type {Array.<string>} - */ - this.keys_ = null; - - /** - * @private - * @type {Object.<string, Object>|undefined} - */ - this.data_ = null; -}; -goog.inherits(ol.source.TileUTFGridTile_, ol.Tile); - - -/** - * Get the image element for this tile. - * @param {Object=} opt_context Optional context. Only used for the DOM - * renderer. - * @return {Image} Image. - */ -ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) { - return null; -}; - - -/** - * Synchronously returns data at given coordinate (if available). - * @param {ol.Coordinate} coordinate Coordinate. - * @return {Object} - */ -ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) { - if (!this.grid_ || !this.keys_ || !this.data_) { - return null; - } - var xRelative = (coordinate[0] - this.extent_[0]) / - (this.extent_[2] - this.extent_[0]); - var yRelative = (coordinate[1] - this.extent_[1]) / - (this.extent_[3] - this.extent_[1]); - - var row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)]; - - if (!goog.isString(row)) { - return null; - } - - var code = row.charCodeAt(Math.floor(xRelative * row.length)); - if (code >= 93) { - code--; - } - if (code >= 35) { - code--; - } - code -= 32; - - return (code in this.keys_) ? this.data_[this.keys_[code]] : null; -}; - - -/** - * Calls the callback (synchronously by default) with the available data - * for given coordinate (or `null` if not yet loaded). - * @param {ol.Coordinate} coordinate Coordinate. - * @param {function(this: T, Object)} callback Callback. - * @param {T=} opt_this The object to use as `this` in the callback. - * @param {boolean=} opt_request If `true` the callback is always async. - * The tile data is requested if not yet loaded. - * @template T - */ -ol.source.TileUTFGridTile_.prototype.forDataAtCoordinate = - function(coordinate, callback, opt_this, opt_request) { - if (this.state == ol.TileState.IDLE && opt_request === true) { - goog.events.listenOnce(this, goog.events.EventType.CHANGE, function(e) { - callback.call(opt_this, this.getData(coordinate)); - }, false, this); - this.loadInternal_(); - } else { - if (opt_request === true) { - goog.async.nextTick(function() { - callback.call(opt_this, this.getData(coordinate)); - }, this); - } else { - callback.call(opt_this, this.getData(coordinate)); - } - } -}; - - -/** - * @inheritDoc - */ -ol.source.TileUTFGridTile_.prototype.getKey = function() { - return this.src_; -}; - - -/** - * @private - */ -ol.source.TileUTFGridTile_.prototype.handleError_ = function() { - this.state = ol.TileState.ERROR; - this.changed(); -}; - - -/** - * @param {!UTFGridJSON} json - * @private - */ -ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) { - this.grid_ = json.grid; - this.keys_ = json.keys; - this.data_ = json.data; - - this.state = ol.TileState.EMPTY; - this.changed(); -}; - - -/** - * @private - */ -ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() { - if (this.state == ol.TileState.IDLE) { - this.state = ol.TileState.LOADING; - var request = new goog.net.Jsonp(this.src_); - request.send(undefined, goog.bind(this.handleLoad_, this), - goog.bind(this.handleError_, this)); - } -}; - - -/** - * Load not yet loaded URI. - */ -ol.source.TileUTFGridTile_.prototype.load = function() { - if (this.preemptive_) { - this.loadInternal_(); - } -}; - -// FIXME add minZoom support -// FIXME add date line wrap (tile coord transform) -// FIXME cannot be shared between maps with different projections - -goog.provide('ol.source.TileWMS'); - -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.uri.utils'); -goog.require('ol'); -goog.require('ol.TileCoord'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.size'); -goog.require('ol.source.TileImage'); -goog.require('ol.source.wms'); -goog.require('ol.source.wms.ServerType'); -goog.require('ol.tilecoord'); - - - -/** - * @classdesc - * Layer source for tile data from WMS servers. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.TileWMSOptions=} opt_options Tile WMS options. - * @api stable - */ -ol.source.TileWMS = function(opt_options) { - - var options = opt_options || {}; - - var params = options.params !== undefined ? options.params : {}; - - var transparent = goog.object.get(params, 'TRANSPARENT', true); - - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - opaque: !transparent, - projection: options.projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction, - tileUrlFunction: goog.bind(this.tileUrlFunction_, this), - url: options.url, - urls: options.urls, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - - /** - * @private - * @type {number} - */ - this.gutter_ = options.gutter !== undefined ? options.gutter : 0; - - /** - * @private - * @type {Object} - */ - this.params_ = params; - - /** - * @private - * @type {boolean} - */ - this.v13_ = true; - - /** - * @private - * @type {ol.source.wms.ServerType|undefined} - */ - this.serverType_ = - /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType); - - /** - * @private - * @type {boolean} - */ - this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; - - /** - * @private - * @type {string} - */ - this.coordKeyPrefix_ = ''; - this.resetCoordKeyPrefix_(); - - /** - * @private - * @type {ol.Extent} - */ - this.tmpExtent_ = ol.extent.createEmpty(); - - this.updateV13_(); - -}; -goog.inherits(ol.source.TileWMS, ol.source.TileImage); - - -/** - * Return the GetFeatureInfo URL for the passed coordinate, resolution, and - * projection. Return `undefined` if the GetFeatureInfo URL cannot be - * constructed. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should - * be provided. If `QUERY_LAYERS` is not provided then the layers specified - * in the `LAYERS` parameter will be used. `VERSION` should not be - * specified here. - * @return {string|undefined} GetFeatureInfo URL. - * @api stable - */ -ol.source.TileWMS.prototype.getGetFeatureInfoUrl = - function(coordinate, resolution, projection, params) { - - goog.asserts.assert(!('VERSION' in params), - 'key VERSION is not allowed in params'); - - var projectionObj = ol.proj.get(projection); - - var tileGrid = this.getTileGrid(); - if (!tileGrid) { - tileGrid = this.getTileGridForProjection(projectionObj); - } - - var tileCoord = tileGrid.getTileCoordForCoordAndResolution( - coordinate, resolution); - - if (tileGrid.getResolutions().length <= tileCoord[0]) { - return undefined; - } - - var tileResolution = tileGrid.getResolution(tileCoord[0]); - var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_); - var tileSize = ol.size.toSize( - tileGrid.getTileSize(tileCoord[0]), this.tmpSize); - - var gutter = this.gutter_; - if (gutter !== 0) { - tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize); - tileExtent = ol.extent.buffer(tileExtent, - tileResolution * gutter, tileExtent); - } - - var baseParams = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetFeatureInfo', - 'FORMAT': 'image/png', - 'TRANSPARENT': true, - 'QUERY_LAYERS': this.params_['LAYERS'] - }; - goog.object.extend(baseParams, this.params_, params); - - var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution); - var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution); - - baseParams[this.v13_ ? 'I' : 'X'] = x; - baseParams[this.v13_ ? 'J' : 'Y'] = y; - - return this.getRequestUrl_(tileCoord, tileSize, tileExtent, - 1, projectionObj, baseParams); -}; - - -/** - * @inheritDoc - */ -ol.source.TileWMS.prototype.getGutter = function() { - return this.gutter_; -}; - - -/** - * @inheritDoc - */ -ol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) { - return this.coordKeyPrefix_ + goog.base(this, 'getKeyZXY', z, x, y); -}; - - -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api stable - */ -ol.source.TileWMS.prototype.getParams = function() { - return this.params_; -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {ol.Extent} tileExtent Tile extent. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {Object} params Params. - * @return {string|undefined} Request URL. - * @private - */ -ol.source.TileWMS.prototype.getRequestUrl_ = - function(tileCoord, tileSize, tileExtent, - pixelRatio, projection, params) { - - var urls = this.urls; - if (!urls) { - return undefined; - } - - params['WIDTH'] = tileSize[0]; - params['HEIGHT'] = tileSize[1]; - - params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode(); - - if (!('STYLES' in this.params_)) { - /* jshint -W053 */ - params['STYLES'] = new String(''); - /* jshint +W053 */ - } - - if (pixelRatio != 1) { - switch (this.serverType_) { - case ol.source.wms.ServerType.GEOSERVER: - var dpi = (90 * pixelRatio + 0.5) | 0; - if ('FORMAT_OPTIONS' in params) { - params['FORMAT_OPTIONS'] += ';dpi:' + dpi; - } else { - params['FORMAT_OPTIONS'] = 'dpi:' + dpi; - } - break; - case ol.source.wms.ServerType.MAPSERVER: - params['MAP_RESOLUTION'] = 90 * pixelRatio; - break; - case ol.source.wms.ServerType.CARMENTA_SERVER: - case ol.source.wms.ServerType.QGIS: - params['DPI'] = 90 * pixelRatio; - break; - default: - goog.asserts.fail('unknown serverType configured'); - break; - } - } - - var axisOrientation = projection.getAxisOrientation(); - var bbox = tileExtent; - if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') { - var tmp; - tmp = tileExtent[0]; - bbox[0] = tileExtent[1]; - bbox[1] = tmp; - tmp = tileExtent[2]; - bbox[2] = tileExtent[3]; - bbox[3] = tmp; - } - params['BBOX'] = bbox.join(','); - - var url; - if (urls.length == 1) { - url = urls[0]; - } else { - var index = goog.math.modulo(ol.tilecoord.hash(tileCoord), urls.length); - url = urls[index]; - } - return goog.uri.utils.appendParamsFromMap(url, params); -}; - - -/** - * @param {number} z Z. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.Size} Size. - */ -ol.source.TileWMS.prototype.getTilePixelSize = - function(z, pixelRatio, projection) { - var tileSize = goog.base(this, 'getTilePixelSize', z, pixelRatio, projection); - if (pixelRatio == 1 || !this.hidpi_ || this.serverType_ === undefined) { - return tileSize; - } else { - return ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } -}; - - -/** - * @private - */ -ol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() { - var i = 0; - var res = []; - - if (this.urls) { - var j, jj; - for (j = 0, jj = this.urls.length; j < jj; ++j) { - res[i++] = this.urls[j]; - } - } - - var key; - for (key in this.params_) { - res[i++] = key + '-' + this.params_[key]; - } - - this.coordKeyPrefix_ = res.join('#'); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - * @private - */ -ol.source.TileWMS.prototype.tileUrlFunction_ = - function(tileCoord, pixelRatio, projection) { - - var tileGrid = this.getTileGrid(); - if (!tileGrid) { - tileGrid = this.getTileGridForProjection(projection); - } - - if (tileGrid.getResolutions().length <= tileCoord[0]) { - return undefined; - } - - if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) { - pixelRatio = 1; - } - - var tileResolution = tileGrid.getResolution(tileCoord[0]); - var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_); - var tileSize = ol.size.toSize( - tileGrid.getTileSize(tileCoord[0]), this.tmpSize); - - var gutter = this.gutter_; - if (gutter !== 0) { - tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize); - tileExtent = ol.extent.buffer(tileExtent, - tileResolution * gutter, tileExtent); - } - - if (pixelRatio != 1) { - tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } - - var baseParams = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetMap', - 'FORMAT': 'image/png', - 'TRANSPARENT': true - }; - goog.object.extend(baseParams, this.params_); - - return this.getRequestUrl_(tileCoord, tileSize, tileExtent, - pixelRatio, projection, baseParams); -}; - - -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.TileWMS.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.resetCoordKeyPrefix_(); - this.updateV13_(); - this.changed(); -}; - - -/** - * @private - */ -ol.source.TileWMS.prototype.updateV13_ = function() { - var version = - goog.object.get(this.params_, 'VERSION', ol.DEFAULT_WMS_VERSION); - this.v13_ = goog.string.compareVersions(version, '1.3') >= 0; -}; - -goog.provide('ol.tilegrid.WMTS'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol.proj'); -goog.require('ol.tilegrid.TileGrid'); - - - -/** - * @classdesc - * Set the grid pattern for sources accessing WMTS tiled-image servers. - * - * @constructor - * @extends {ol.tilegrid.TileGrid} - * @param {olx.tilegrid.WMTSOptions} options WMTS options. - * @struct - * @api - */ -ol.tilegrid.WMTS = function(options) { - - goog.asserts.assert( - options.resolutions.length == options.matrixIds.length, - 'options resolutions and matrixIds must have equal length (%s == %s)', - options.resolutions.length, options.matrixIds.length); - - /** - * @private - * @type {!Array.<string>} - */ - this.matrixIds_ = options.matrixIds; - // FIXME: should the matrixIds become optionnal? - - goog.base(this, { - extent: options.extent, - origin: options.origin, - origins: options.origins, - resolutions: options.resolutions, - tileSize: options.tileSize, - tileSizes: options.tileSizes, - sizes: options.sizes - }); - -}; -goog.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid); - - -/** - * @param {number} z Z. - * @return {string} MatrixId.. - */ -ol.tilegrid.WMTS.prototype.getMatrixId = function(z) { - goog.asserts.assert(0 <= z && z < this.matrixIds_.length, - 'attempted to retrive matrixId for illegal z (%s)', z); - return this.matrixIds_[z]; -}; - - -/** - * Get the list of matrix identifiers. - * @return {Array.<string>} MatrixIds. - * @api - */ -ol.tilegrid.WMTS.prototype.getMatrixIds = function() { - return this.matrixIds_; -}; - - -/** - * Create a tile grid from a WMTS capabilities matrix set. - * @param {Object} matrixSet An object representing a matrixSet in the - * capabilities document. - * @param {ol.Extent=} opt_extent An optional extent to restrict the tile - * ranges the server provides. - * @return {ol.tilegrid.WMTS} WMTS tileGrid instance. - * @api - */ -ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = - function(matrixSet, opt_extent) { - - /** @type {!Array.<number>} */ - var resolutions = []; - /** @type {!Array.<string>} */ - var matrixIds = []; - /** @type {!Array.<ol.Coordinate>} */ - var origins = []; - /** @type {!Array.<ol.Size>} */ - var tileSizes = []; - /** @type {!Array.<ol.Size>} */ - var sizes = []; - - var supportedCRSPropName = 'SupportedCRS'; - var matrixIdsPropName = 'TileMatrix'; - var identifierPropName = 'Identifier'; - var scaleDenominatorPropName = 'ScaleDenominator'; - var topLeftCornerPropName = 'TopLeftCorner'; - var tileWidthPropName = 'TileWidth'; - var tileHeightPropName = 'TileHeight'; - - var projection; - projection = ol.proj.get(matrixSet[supportedCRSPropName].replace( - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3')); - var metersPerUnit = projection.getMetersPerUnit(); - // swap origin x and y coordinates if axis orientation is lat/long - var switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne'; - - goog.array.sort(matrixSet[matrixIdsPropName], function(a, b) { - return b[scaleDenominatorPropName] - a[scaleDenominatorPropName]; - }); - - matrixSet[matrixIdsPropName].forEach(function(elt, index, array) { - matrixIds.push(elt[identifierPropName]); - var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit; - var tileWidth = elt[tileWidthPropName]; - var tileHeight = elt[tileHeightPropName]; - if (switchOriginXY) { - origins.push([elt[topLeftCornerPropName][1], - elt[topLeftCornerPropName][0]]); - } else { - origins.push(elt[topLeftCornerPropName]); - } - resolutions.push(resolution); - tileSizes.push(tileWidth == tileHeight ? - tileWidth : [tileWidth, tileHeight]); - // top-left origin, so height is negative - sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]); - }); - - return new ol.tilegrid.WMTS({ - extent: opt_extent, - origins: origins, - resolutions: resolutions, - matrixIds: matrixIds, - tileSizes: tileSizes, - sizes: sizes - }); -}; - -goog.provide('ol.source.WMTS'); -goog.provide('ol.source.WMTSRequestEncoding'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('goog.uri.utils'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.TileUrlFunctionType'); -goog.require('ol.array'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilegrid.WMTS'); - - -/** - * Request encoding. One of 'KVP', 'REST'. - * @enum {string} - * @api - */ -ol.source.WMTSRequestEncoding = { - KVP: 'KVP', // see spec §8 - REST: 'REST' // see spec §10 -}; - - - -/** - * @classdesc - * Layer source for tile data from WMTS servers. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.WMTSOptions} options WMTS options. - * @api stable - */ -ol.source.WMTS = function(options) { - - // TODO: add support for TileMatrixLimits - - /** - * @private - * @type {string} - */ - this.version_ = options.version !== undefined ? options.version : '1.0.0'; - - /** - * @private - * @type {string} - */ - this.format_ = options.format !== undefined ? options.format : 'image/jpeg'; - - /** - * @private - * @type {Object} - */ - this.dimensions_ = options.dimensions !== undefined ? options.dimensions : {}; - - /** - * @private - * @type {string} - */ - this.dimensionsKey_ = ''; - this.resetDimensionsKey_(); - - /** - * @private - * @type {string} - */ - this.layer_ = options.layer; - - /** - * @private - * @type {string} - */ - this.matrixSet_ = options.matrixSet; - - /** - * @private - * @type {string} - */ - this.style_ = options.style; - - var urls = options.urls; - if (urls === undefined && options.url !== undefined) { - urls = ol.TileUrlFunction.expandUrl(options.url); - } - - // FIXME: should we guess this requestEncoding from options.url(s) - // structure? that would mean KVP only if a template is not provided. - - /** - * @private - * @type {ol.source.WMTSRequestEncoding} - */ - this.requestEncoding_ = options.requestEncoding !== undefined ? - /** @type {ol.source.WMTSRequestEncoding} */ (options.requestEncoding) : - ol.source.WMTSRequestEncoding.KVP; - - var requestEncoding = this.requestEncoding_; - - // FIXME: should we create a default tileGrid? - // we could issue a getCapabilities xhr to retrieve missing configuration - var tileGrid = options.tileGrid; - - // context property names are lower case to allow for a case insensitive - // replacement as some services use different naming conventions - var context = { - 'layer': this.layer_, - 'style': this.style_, - 'tilematrixset': this.matrixSet_ - }; - - if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { - goog.object.extend(context, { - 'Service': 'WMTS', - 'Request': 'GetTile', - 'Version': this.version_, - 'Format': this.format_ - }); - } - - var dimensions = this.dimensions_; - - /** - * @param {string} template Template. - * @return {ol.TileUrlFunctionType} Tile URL function. - */ - function createFromWMTSTemplate(template) { - - // TODO: we may want to create our own appendParams function so that params - // order conforms to wmts spec guidance, and so that we can avoid to escape - // special template params - - template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ? - goog.uri.utils.appendParamsFromMap(template, context) : - template.replace(/\{(\w+?)\}/g, function(m, p) { - return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m; - }); - - return ( - /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - var localContext = { - 'TileMatrix': tileGrid.getMatrixId(tileCoord[0]), - 'TileCol': tileCoord[1], - 'TileRow': -tileCoord[2] - 1 - }; - goog.object.extend(localContext, dimensions); - var url = template; - if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { - url = goog.uri.utils.appendParamsFromMap(url, localContext); - } else { - url = url.replace(/\{(\w+?)\}/g, function(m, p) { - return localContext[p]; - }); - } - return url; - } - }); - } - - var tileUrlFunction = (urls && urls.length > 0) ? - ol.TileUrlFunction.createFromTileUrlFunctions( - urls.map(createFromWMTSTemplate)) : - ol.TileUrlFunction.nullTileUrlFunction; - - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - projection: options.projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileClass: options.tileClass, - tileGrid: tileGrid, - tileLoadFunction: options.tileLoadFunction, - tilePixelRatio: options.tilePixelRatio, - tileUrlFunction: tileUrlFunction, - urls: urls, - wrapX: options.wrapX !== undefined ? options.wrapX : false - }); - -}; -goog.inherits(ol.source.WMTS, ol.source.TileImage); - - -/** - * Get the dimensions, i.e. those passed to the constructor through the - * "dimensions" option, and possibly updated using the updateDimensions - * method. - * @return {Object} Dimensions. - * @api - */ -ol.source.WMTS.prototype.getDimensions = function() { - return this.dimensions_; -}; - - -/** - * Return the image format of the WMTS source. - * @return {string} Format. - * @api - */ -ol.source.WMTS.prototype.getFormat = function() { - return this.format_; -}; - - -/** - * @inheritDoc - */ -ol.source.WMTS.prototype.getKeyParams = function() { - return this.dimensionsKey_; -}; - - -/** - * Return the layer of the WMTS source. - * @return {string} Layer. - * @api - */ -ol.source.WMTS.prototype.getLayer = function() { - return this.layer_; -}; - - -/** - * Return the matrix set of the WMTS source. - * @return {string} MatrixSet. - * @api - */ -ol.source.WMTS.prototype.getMatrixSet = function() { - return this.matrixSet_; -}; - - -/** - * Return the request encoding, either "KVP" or "REST". - * @return {ol.source.WMTSRequestEncoding} Request encoding. - * @api - */ -ol.source.WMTS.prototype.getRequestEncoding = function() { - return this.requestEncoding_; -}; - - -/** - * Return the style of the WMTS source. - * @return {string} Style. - * @api - */ -ol.source.WMTS.prototype.getStyle = function() { - return this.style_; -}; - - -/** - * Return the version of the WMTS source. - * @return {string} Version. - * @api - */ -ol.source.WMTS.prototype.getVersion = function() { - return this.version_; -}; - - -/** - * @private - */ -ol.source.WMTS.prototype.resetDimensionsKey_ = function() { - var i = 0; - var res = []; - for (var key in this.dimensions_) { - res[i++] = key + '-' + this.dimensions_[key]; - } - this.dimensionsKey_ = res.join('/'); -}; - - -/** - * Update the dimensions. - * @param {Object} dimensions Dimensions. - * @api - */ -ol.source.WMTS.prototype.updateDimensions = function(dimensions) { - goog.object.extend(this.dimensions_, dimensions); - this.resetDimensionsKey_(); - this.changed(); -}; - - -/** - * Generate source options from a capabilities object. - * @param {Object} wmtsCap An object representing the capabilities document. - * @param {Object} config Configuration properties for the layer. Defaults for - * the layer will apply if not provided. - * - * Required config properties: - * layer - {String} The layer identifier. - * - * Optional config properties: - * matrixSet - {String} The matrix set identifier, required if there is - * more than one matrix set in the layer capabilities. - * projection - {String} The desired CRS when no matrixSet is specified. - * eg: "EPSG:3857". If the desired projection is not available, - * an error is thrown. - * requestEncoding - {String} url encoding format for the layer. Default is the - * first tile url format found in the GetCapabilities response. - * style - {String} The name of the style - * format - {String} Image format for the layer. Default is the first - * format returned in the GetCapabilities response. - * @return {olx.source.WMTSOptions} WMTS source options object. - * @api - */ -ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { - - // TODO: add support for TileMatrixLimits - goog.asserts.assert(config['layer'], - 'config "layer" must not be null'); - - var layers = wmtsCap['Contents']['Layer']; - var l = goog.array.find(layers, function(elt, index, array) { - return elt['Identifier'] == config['layer']; - }); - goog.asserts.assert(l, 'found a matching layer in Contents/Layer'); - - goog.asserts.assert(l['TileMatrixSetLink'].length > 0, - 'layer has TileMatrixSetLink'); - var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet']; - var idx, matrixSet; - if (l['TileMatrixSetLink'].length > 1) { - if ('projection' in config) { - idx = goog.array.findIndex(l['TileMatrixSetLink'], - function(elt, index, array) { - var tileMatrixSet = goog.array.find(tileMatrixSets, function(el) { - return el['Identifier'] == elt['TileMatrixSet']; - }); - return tileMatrixSet['SupportedCRS'].replace( - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3' - ) == config['projection']; - }); - } else { - idx = goog.array.findIndex(l['TileMatrixSetLink'], - function(elt, index, array) { - return elt['TileMatrixSet'] == config['matrixSet']; - }); - } - } else { - idx = 0; - } - if (idx < 0) { - idx = 0; - } - matrixSet = /** @type {string} */ - (l['TileMatrixSetLink'][idx]['TileMatrixSet']); - - goog.asserts.assert(matrixSet, 'TileMatrixSet must not be null'); - - var format = /** @type {string} */ (l['Format'][0]); - if ('format' in config) { - format = config['format']; - } - idx = goog.array.findIndex(l['Style'], function(elt, index, array) { - if ('style' in config) { - return elt['Title'] == config['style']; - } else { - return elt['isDefault']; - } - }); - if (idx < 0) { - idx = 0; - } - var style = /** @type {string} */ (l['Style'][idx]['Identifier']); - - var dimensions = {}; - if ('Dimension' in l) { - l['Dimension'].forEach(function(elt, index, array) { - var key = elt['Identifier']; - var value = elt['Default']; - if (value !== undefined) { - goog.asserts.assert(ol.array.includes(elt['Value'], value), - 'default value contained in values'); - } else { - value = elt['Value'][0]; - } - goog.asserts.assert(value !== undefined, 'value could be found'); - dimensions[key] = value; - }); - } - - var matrixSets = wmtsCap['Contents']['TileMatrixSet']; - var matrixSetObj = goog.array.find(matrixSets, function(elt, index, array) { - return elt['Identifier'] == matrixSet; - }); - goog.asserts.assert(matrixSetObj, - 'found matrixSet in Contents/TileMatrixSet'); - - var projection; - if ('projection' in config) { - projection = ol.proj.get(config['projection']); - } else { - projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace( - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3')); - } - - var wgs84BoundingBox = l['WGS84BoundingBox']; - var extent, wrapX; - if (wgs84BoundingBox !== undefined) { - var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent(); - wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] && - wgs84BoundingBox[2] == wgs84ProjectionExtent[2]); - extent = ol.proj.transformExtent( - wgs84BoundingBox, 'EPSG:4326', projection); - var projectionExtent = projection.getExtent(); - if (projectionExtent) { - // If possible, do a sanity check on the extent - it should never be - // bigger than the validity extent of the projection of a matrix set. - if (!ol.extent.containsExtent(projectionExtent, extent)) { - extent = undefined; - } - } - } - - var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( - matrixSetObj, extent); - - /** @type {!Array.<string>} */ - var urls = []; - var requestEncoding = config['requestEncoding']; - requestEncoding = requestEncoding !== undefined ? requestEncoding : ''; - - goog.asserts.assert( - ol.array.includes(['REST', 'RESTful', 'KVP', ''], requestEncoding), - 'requestEncoding (%s) is one of "REST", "RESTful", "KVP" or ""', - requestEncoding); - - if (!wmtsCap.hasOwnProperty('OperationsMetadata') || - !wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') || - requestEncoding.indexOf('REST') === 0) { - // Add REST tile resource url - requestEncoding = ol.source.WMTSRequestEncoding.REST; - l['ResourceURL'].forEach(function(elt, index, array) { - if (elt['resourceType'] == 'tile') { - format = elt['format']; - urls.push(/** @type {string} */ (elt['template'])); - } - }); - } else { - var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get']; - - for (var i = 0, ii = gets.length; i < ii; ++i) { - var constraint = goog.array.find(gets[i]['Constraint'], - function(elt, index, array) { - return elt['name'] == 'GetEncoding'; - }); - var encodings = constraint['AllowedValues']['Value']; - if (encodings.length > 0 && ol.array.includes(encodings, 'KVP')) { - requestEncoding = ol.source.WMTSRequestEncoding.KVP; - urls.push(/** @type {string} */ (gets[i]['href'])); - } - } - } - goog.asserts.assert(urls.length > 0, 'At least one URL found'); - - return { - urls: urls, - layer: config['layer'], - matrixSet: matrixSet, - format: format, - projection: projection, - requestEncoding: requestEncoding, - tileGrid: tileGrid, - style: style, - dimensions: dimensions, - wrapX: wrapX - }; - -}; - -goog.provide('ol.source.Zoomify'); - -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.ImageTile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileState'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilegrid.TileGrid'); - - -/** - * @enum {string} - */ -ol.source.ZoomifyTierSizeCalculation = { - DEFAULT: 'default', - TRUNCATED: 'truncated' -}; - - - -/** - * @classdesc - * Layer source for tile data in Zoomify format. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.ZoomifyOptions=} opt_options Options. - * @api stable - */ -ol.source.Zoomify = function(opt_options) { - - var options = opt_options || {}; - - var size = options.size; - var tierSizeCalculation = options.tierSizeCalculation !== undefined ? - options.tierSizeCalculation : - ol.source.ZoomifyTierSizeCalculation.DEFAULT; - - var imageWidth = size[0]; - var imageHeight = size[1]; - var tierSizeInTiles = []; - var tileSize = ol.DEFAULT_TILE_SIZE; - - switch (tierSizeCalculation) { - case ol.source.ZoomifyTierSizeCalculation.DEFAULT: - while (imageWidth > tileSize || imageHeight > tileSize) { - tierSizeInTiles.push([ - Math.ceil(imageWidth / tileSize), - Math.ceil(imageHeight / tileSize) - ]); - tileSize += tileSize; - } - break; - case ol.source.ZoomifyTierSizeCalculation.TRUNCATED: - var width = imageWidth; - var height = imageHeight; - while (width > tileSize || height > tileSize) { - tierSizeInTiles.push([ - Math.ceil(width / tileSize), - Math.ceil(height / tileSize) - ]); - width >>= 1; - height >>= 1; - } - break; - default: - goog.asserts.fail(); - break; - } - - tierSizeInTiles.push([1, 1]); - tierSizeInTiles.reverse(); - - var resolutions = [1]; - var tileCountUpToTier = [0]; - var i, ii; - for (i = 1, ii = tierSizeInTiles.length; i < ii; i++) { - resolutions.push(1 << i); - tileCountUpToTier.push( - tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] + - tileCountUpToTier[i - 1] - ); - } - resolutions.reverse(); - - var extent = [0, -size[1], size[0], 0]; - var tileGrid = new ol.tilegrid.TileGrid({ - extent: extent, - origin: ol.extent.getTopLeft(extent), - resolutions: resolutions - }); - - var url = options.url; - - /** - * @this {ol.source.TileImage} - * @param {ol.TileCoord} tileCoord Tile Coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function tileUrlFunction(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - var tileCoordZ = tileCoord[0]; - var tileCoordX = tileCoord[1]; - var tileCoordY = -tileCoord[2] - 1; - var tileIndex = - tileCoordX + - tileCoordY * tierSizeInTiles[tileCoordZ][0] + - tileCountUpToTier[tileCoordZ]; - var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0; - return url + 'TileGroup' + tileGroup + '/' + - tileCoordZ + '-' + tileCoordX + '-' + tileCoordY + '.jpg'; - } - } - - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileClass: ol.source.ZoomifyTile_, - tileGrid: tileGrid, - tileUrlFunction: tileUrlFunction - }); - -}; -goog.inherits(ol.source.Zoomify, ol.source.TileImage); - - - -/** - * @constructor - * @extends {ol.ImageTile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Image source URI. - * @param {?string} crossOrigin Cross origin. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - * @private - */ -ol.source.ZoomifyTile_ = function( - tileCoord, state, src, crossOrigin, tileLoadFunction) { - - goog.base(this, tileCoord, state, src, crossOrigin, tileLoadFunction); - - /** - * @private - * @type {Object.<string, - * HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} - */ - this.zoomifyImageByContext_ = {}; - -}; -goog.inherits(ol.source.ZoomifyTile_, ol.ImageTile); - - -/** - * @inheritDoc - */ -ol.source.ZoomifyTile_.prototype.getImage = function(opt_context) { - var tileSize = ol.DEFAULT_TILE_SIZE; - var key = opt_context !== undefined ? - goog.getUid(opt_context).toString() : ''; - if (key in this.zoomifyImageByContext_) { - return this.zoomifyImageByContext_[key]; - } else { - var image = goog.base(this, 'getImage', opt_context); - if (this.state == ol.TileState.LOADED) { - if (image.width == tileSize && image.height == tileSize) { - this.zoomifyImageByContext_[key] = image; - return image; - } else { - var context = ol.dom.createCanvasContext2D(tileSize, tileSize); - context.drawImage(image, 0, 0); - this.zoomifyImageByContext_[key] = context.canvas; - return context.canvas; - } - } else { - return image; - } - } -}; - -goog.provide('ol.style.Atlas'); -goog.provide('ol.style.AtlasManager'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol'); - - -/** - * Provides information for an image inside an atlas manager. - * `offsetX` and `offsetY` is the position of the image inside - * the atlas image `image` and the position of the hit-detection image - * inside the hit-detection atlas image `hitImage`. - * @typedef {{offsetX: number, offsetY: number, image: HTMLCanvasElement, - * hitImage: HTMLCanvasElement}} - */ -ol.style.AtlasManagerInfo; - - - -/** - * Manages the creation of image atlases. - * - * Images added to this manager will be inserted into an atlas, which - * will be used for rendering. - * The `size` given in the constructor is the size for the first - * atlas. After that, when new atlases are created, they will have - * twice the size as the latest atlas (until `maxSize` is reached). - * - * If an application uses many images or very large images, it is recommended - * to set a higher `size` value to avoid the creation of too many atlases. - * - * @constructor - * @struct - * @api - * @param {olx.style.AtlasManagerOptions=} opt_options Options. - */ -ol.style.AtlasManager = function(opt_options) { - - var options = opt_options || {}; - - /** - * The size in pixels of the latest atlas image. - * @private - * @type {number} - */ - this.currentSize_ = options.initialSize !== undefined ? - options.initialSize : ol.INITIAL_ATLAS_SIZE; - - /** - * The maximum size in pixels of atlas images. - * @private - * @type {number} - */ - this.maxSize_ = options.maxSize !== undefined ? - options.maxSize : ol.MAX_ATLAS_SIZE != -1 ? - ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ? - ol.WEBGL_MAX_TEXTURE_SIZE : 2048; - - /** - * The size in pixels between images. - * @private - * @type {number} - */ - this.space_ = options.space !== undefined ? options.space : 1; - - /** - * @private - * @type {Array.<ol.style.Atlas>} - */ - this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)]; - - /** - * The size in pixels of the latest atlas image for hit-detection images. - * @private - * @type {number} - */ - this.currentHitSize_ = this.currentSize_; - - /** - * @private - * @type {Array.<ol.style.Atlas>} - */ - this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)]; -}; - - -/** - * @param {string} id The identifier of the entry to check. - * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the - * entry, or `null` if the entry is not part of the atlas manager. - */ -ol.style.AtlasManager.prototype.getInfo = function(id) { - /** @type {?ol.style.AtlasInfo} */ - var info = this.getInfo_(this.atlases_, id); - - if (!info) { - return null; - } - /** @type {?ol.style.AtlasInfo} */ - var hitInfo = this.getInfo_(this.hitAtlases_, id); - goog.asserts.assert(hitInfo, 'hitInfo must not be null'); - - return this.mergeInfos_(info, hitInfo); -}; - - -/** - * @private - * @param {Array.<ol.style.Atlas>} atlases The atlases to search. - * @param {string} id The identifier of the entry to check. - * @return {?ol.style.AtlasInfo} The position and atlas image for the entry, - * or `null` if the entry is not part of the atlases. - */ -ol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) { - var atlas, info, i, ii; - for (i = 0, ii = atlases.length; i < ii; ++i) { - atlas = atlases[i]; - info = atlas.get(id); - if (info) { - return info; - } - } - return null; -}; - - -/** - * @private - * @param {ol.style.AtlasInfo} info The info for the real image. - * @param {ol.style.AtlasInfo} hitInfo The info for the hit-detection - * image. - * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the - * entry, or `null` if the entry is not part of the atlases. - */ -ol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) { - goog.asserts.assert(info.offsetX === hitInfo.offsetX, - 'in order to merge, offsetX of info and hitInfo must be equal'); - goog.asserts.assert(info.offsetY === hitInfo.offsetY, - 'in order to merge, offsetY of info and hitInfo must be equal'); - return /** @type {ol.style.AtlasManagerInfo} */ ({ - offsetX: info.offsetX, - offsetY: info.offsetY, - image: info.image, - hitImage: hitInfo.image - }); -}; - - -/** - * Add an image to the atlas manager. - * - * If an entry for the given id already exists, the entry will - * be overridden (but the space on the atlas graphic will not be freed). - * - * If `renderHitCallback` is provided, the image (or the hit-detection version - * of the image) will be rendered into a separate hit-detection atlas image. - * - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {function(CanvasRenderingContext2D, number, number)=} - * opt_renderHitCallback Called to render a hit-detection image onto a hit - * detection atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback` and `renderHitCallback`. - * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the - * entry, or `null` if the image is too big. - */ -ol.style.AtlasManager.prototype.add = - function(id, width, height, - renderCallback, opt_renderHitCallback, opt_this) { - if (width + this.space_ > this.maxSize_ || - height + this.space_ > this.maxSize_) { - return null; - } - - /** @type {?ol.style.AtlasInfo} */ - var info = this.add_(false, - id, width, height, renderCallback, opt_this); - if (!info) { - return null; - } - - // even if no hit-detection entry is requested, we insert a fake entry into - // the hit-detection atlas, to make sure that the offset is the same for - // the original image and the hit-detection image. - var renderHitCallback = opt_renderHitCallback !== undefined ? - opt_renderHitCallback : goog.functions.NULL; - - /** @type {?ol.style.AtlasInfo} */ - var hitInfo = this.add_(true, - id, width, height, renderHitCallback, opt_this); - goog.asserts.assert(hitInfo, 'hitInfo must not be null'); - - return this.mergeInfos_(info, hitInfo); -}; - - -/** - * @private - * @param {boolean} isHitAtlas If the hit-detection atlases are used. - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback` and `renderHitCallback`. - * @return {?ol.style.AtlasInfo} The position and atlas image for the entry, - * or `null` if the image is too big. - */ -ol.style.AtlasManager.prototype.add_ = - function(isHitAtlas, id, width, height, - renderCallback, opt_this) { - var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_; - var atlas, info, i, ii; - for (i = 0, ii = atlases.length; i < ii; ++i) { - atlas = atlases[i]; - info = atlas.add(id, width, height, renderCallback, opt_this); - if (info) { - return info; - } else if (!info && i === ii - 1) { - // the entry could not be added to one of the existing atlases, - // create a new atlas that is twice as big and try to add to this one. - var size; - if (isHitAtlas) { - size = Math.min(this.currentHitSize_ * 2, this.maxSize_); - this.currentHitSize_ = size; - } else { - size = Math.min(this.currentSize_ * 2, this.maxSize_); - this.currentSize_ = size; - } - atlas = new ol.style.Atlas(size, this.space_); - atlases.push(atlas); - // run the loop another time - ++ii; - } - } - goog.asserts.fail('Failed to add to atlasmanager'); -}; - - -/** - * Provides information for an image inside an atlas. - * `offsetX` and `offsetY` are the position of the image inside - * the atlas image `image`. - * @typedef {{offsetX: number, offsetY: number, image: HTMLCanvasElement}} - */ -ol.style.AtlasInfo; - - - -/** - * This class facilitates the creation of image atlases. - * - * Images added to an atlas will be rendered onto a single - * atlas canvas. The distribution of images on the canvas is - * managed with the bin packing algorithm described in: - * http://www.blackpawn.com/texts/lightmaps/ - * - * @constructor - * @struct - * @param {number} size The size in pixels of the sprite image. - * @param {number} space The space in pixels between images. - * Because texture coordinates are float values, the edges of - * images might not be completely correct (in a way that the - * edges overlap when being rendered). To avoid this we add a - * padding around each image. - */ -ol.style.Atlas = function(size, space) { - - /** - * @private - * @type {number} - */ - this.space_ = space; - - /** - * @private - * @type {Array.<ol.style.Atlas.Block>} - */ - this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}]; - - /** - * @private - * @type {Object.<string, ol.style.AtlasInfo>} - */ - this.entries_ = {}; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - this.canvas_.width = size; - this.canvas_.height = size; - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = /** @type {CanvasRenderingContext2D} */ - (this.canvas_.getContext('2d')); -}; - - -/** - * @param {string} id The identifier of the entry to check. - * @return {?ol.style.AtlasInfo} - */ -ol.style.Atlas.prototype.get = function(id) { - return /** @type {?ol.style.AtlasInfo} */ ( - goog.object.get(this.entries_, id, null)); -}; - - -/** - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback`. - * @return {?ol.style.AtlasInfo} The position and atlas image for the entry. - */ -ol.style.Atlas.prototype.add = - function(id, width, height, renderCallback, opt_this) { - var block, i, ii; - for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) { - block = this.emptyBlocks_[i]; - if (block.width >= width + this.space_ && - block.height >= height + this.space_) { - // we found a block that is big enough for our entry - var entry = { - offsetX: block.x + this.space_, - offsetY: block.y + this.space_, - image: this.canvas_ - }; - this.entries_[id] = entry; - - // render the image on the atlas image - renderCallback.call(opt_this, this.context_, - block.x + this.space_, block.y + this.space_); - - // split the block after the insertion, either horizontally or vertically - this.split_(i, block, width + this.space_, height + this.space_); - - return entry; - } - } - - // there is no space for the new entry in this atlas - return null; -}; - - -/** - * @private - * @param {number} index The index of the block. - * @param {ol.style.Atlas.Block} block The block to split. - * @param {number} width The width of the entry to insert. - * @param {number} height The height of the entry to insert. - */ -ol.style.Atlas.prototype.split_ = - function(index, block, width, height) { - var deltaWidth = block.width - width; - var deltaHeight = block.height - height; - - /** @type {ol.style.Atlas.Block} */ - var newBlock1; - /** @type {ol.style.Atlas.Block} */ - var newBlock2; - - if (deltaWidth > deltaHeight) { - // split vertically - // block right of the inserted entry - newBlock1 = { - x: block.x + width, - y: block.y, - width: block.width - width, - height: block.height - }; - - // block below the inserted entry - newBlock2 = { - x: block.x, - y: block.y + height, - width: width, - height: block.height - height - }; - this.updateBlocks_(index, newBlock1, newBlock2); - } else { - // split horizontally - // block right of the inserted entry - newBlock1 = { - x: block.x + width, - y: block.y, - width: block.width - width, - height: height - }; - - // block below the inserted entry - newBlock2 = { - x: block.x, - y: block.y + height, - width: block.width, - height: block.height - height - }; - this.updateBlocks_(index, newBlock1, newBlock2); - } -}; - - -/** - * Remove the old block and insert new blocks at the same array position. - * The new blocks are inserted at the same position, so that splitted - * blocks (that are potentially smaller) are filled first. - * @private - * @param {number} index The index of the block to remove. - * @param {ol.style.Atlas.Block} newBlock1 The 1st block to add. - * @param {ol.style.Atlas.Block} newBlock2 The 2nd block to add. - */ -ol.style.Atlas.prototype.updateBlocks_ = - function(index, newBlock1, newBlock2) { - var args = [index, 1]; - if (newBlock1.width > 0 && newBlock1.height > 0) { - args.push(newBlock1); - } - if (newBlock2.width > 0 && newBlock2.height > 0) { - args.push(newBlock2); - } - this.emptyBlocks_.splice.apply(this.emptyBlocks_, args); -}; - - -/** - * @typedef {{x: number, y: number, width: number, height: number}} - */ -ol.style.Atlas.Block; - -goog.provide('ol.style.RegularShape'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('ol'); -goog.require('ol.color'); -goog.require('ol.has'); -goog.require('ol.render.canvas'); -goog.require('ol.structs.IHasChecksum'); -goog.require('ol.style.AtlasManager'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.Stroke'); - - - -/** - * @classdesc - * Set regular shape style for vector features. The resulting shape will be - * a regular polygon when `radius` is provided, or a star when `radius1` and - * `radius2` are provided. - * - * @constructor - * @param {olx.style.RegularShapeOptions} options Options. - * @extends {ol.style.Image} - * @implements {ol.structs.IHasChecksum} - * @api - */ -ol.style.RegularShape = function(options) { - - goog.asserts.assert( - options.radius !== undefined || options.radius1 !== undefined, - 'must provide either "radius" or "radius1"'); - - /** - * @private - * @type {Array.<string>} - */ - this.checksums_ = null; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.hitDetectionCanvas_ = null; - - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : null; - - /** - * @private - * @type {Array.<number>} - */ - this.origin_ = [0, 0]; - - /** - * @private - * @type {number} - */ - this.points_ = options.points; - - /** - * @private - * @type {number} - */ - this.radius_ = /** @type {number} */ (options.radius !== undefined ? - options.radius : options.radius1); - - /** - * @private - * @type {number} - */ - this.radius2_ = - options.radius2 !== undefined ? options.radius2 : this.radius_; - - /** - * @private - * @type {number} - */ - this.angle_ = options.angle !== undefined ? options.angle : 0; - - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; - - /** - * @private - * @type {Array.<number>} - */ - this.anchor_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.size_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = null; - - /** - * @private - * @type {ol.Size} - */ - this.hitDetectionImageSize_ = null; - - this.render_(options.atlasManager); - - /** - * @type {boolean} - */ - var snapToPixel = options.snapToPixel !== undefined ? - options.snapToPixel : true; - - goog.base(this, { - opacity: 1, - rotateWithView: false, - rotation: options.rotation !== undefined ? options.rotation : 0, - scale: 1, - snapToPixel: snapToPixel - }); - -}; -goog.inherits(ol.style.RegularShape, ol.style.Image); - - -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getAnchor = function() { - return this.anchor_; -}; - - -/** - * Get the angle used in generating the shape. - * @return {number} Shape's rotation in radians. - * @api - */ -ol.style.RegularShape.prototype.getAngle = function() { - return this.angle_; -}; - - -/** - * Get the fill style for the shape. - * @return {ol.style.Fill} Fill style. - * @api - */ -ol.style.RegularShape.prototype.getFill = function() { - return this.fill_; -}; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getHitDetectionImage = function(pixelRatio) { - return this.hitDetectionCanvas_; -}; - - -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getImage = function(pixelRatio) { - return this.canvas_; -}; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getImageSize = function() { - return this.imageSize_; -}; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getHitDetectionImageSize = function() { - return this.hitDetectionImageSize_; -}; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getImageState = function() { - return ol.style.ImageState.LOADED; -}; - - -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getOrigin = function() { - return this.origin_; -}; - - -/** - * Get the number of points for generating the shape. - * @return {number} Number of points for stars and regular polygons. - * @api - */ -ol.style.RegularShape.prototype.getPoints = function() { - return this.points_; -}; - - -/** - * Get the (primary) radius for the shape. - * @return {number} Radius. - * @api - */ -ol.style.RegularShape.prototype.getRadius = function() { - return this.radius_; -}; - - -/** - * Get the secondary radius for the shape. - * @return {number} Radius2. - * @api - */ -ol.style.RegularShape.prototype.getRadius2 = function() { - return this.radius2_; -}; - - -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getSize = function() { - return this.size_; -}; - - -/** - * Get the stroke style for the shape. - * @return {ol.style.Stroke} Stroke style. - * @api - */ -ol.style.RegularShape.prototype.getStroke = function() { - return this.stroke_; -}; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.listenImageChange = ol.nullFunction; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.load = ol.nullFunction; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.unlistenImageChange = ol.nullFunction; - - -/** - * @typedef {{ - * strokeStyle: (string|undefined), - * strokeWidth: number, - * size: number, - * lineCap: string, - * lineDash: Array.<number>, - * lineJoin: string, - * miterLimit: number - * }} - */ -ol.style.RegularShape.RenderOptions; - - -/** - * @private - * @param {ol.style.AtlasManager|undefined} atlasManager - */ -ol.style.RegularShape.prototype.render_ = function(atlasManager) { - var imageSize; - var lineCap = ''; - var lineJoin = ''; - var miterLimit = 0; - var lineDash = null; - var strokeStyle; - var strokeWidth = 0; - - if (this.stroke_) { - strokeStyle = ol.color.asString(this.stroke_.getColor()); - strokeWidth = this.stroke_.getWidth(); - if (strokeWidth === undefined) { - strokeWidth = ol.render.canvas.defaultLineWidth; - } - lineDash = this.stroke_.getLineDash(); - if (!ol.has.CANVAS_LINE_DASH) { - lineDash = null; - } - lineJoin = this.stroke_.getLineJoin(); - if (lineJoin === undefined) { - lineJoin = ol.render.canvas.defaultLineJoin; - } - lineCap = this.stroke_.getLineCap(); - if (lineCap === undefined) { - lineCap = ol.render.canvas.defaultLineCap; - } - miterLimit = this.stroke_.getMiterLimit(); - if (miterLimit === undefined) { - miterLimit = ol.render.canvas.defaultMiterLimit; - } - } - - var size = 2 * (this.radius_ + strokeWidth) + 1; - - /** @type {ol.style.RegularShape.RenderOptions} */ - var renderOptions = { - strokeStyle: strokeStyle, - strokeWidth: strokeWidth, - size: size, - lineCap: lineCap, - lineDash: lineDash, - lineJoin: lineJoin, - miterLimit: miterLimit - }; - - if (atlasManager === undefined) { - // no atlas manager is used, create a new canvas - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - - this.canvas_.height = size; - this.canvas_.width = size; - - // canvas.width and height are rounded to the closest integer - size = this.canvas_.width; - imageSize = size; - - var context = /** @type {CanvasRenderingContext2D} */ - (this.canvas_.getContext('2d')); - this.draw_(renderOptions, context, 0, 0); - - this.createHitDetectionCanvas_(renderOptions); - } else { - // an atlas manager is used, add the symbol to an atlas - size = Math.round(size); - - var hasCustomHitDetectionImage = !this.fill_; - var renderHitDetectionCallback; - if (hasCustomHitDetectionImage) { - // render the hit-detection image into a separate atlas image - renderHitDetectionCallback = - goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); - } - - var id = this.getChecksum(); - var info = atlasManager.add( - id, size, size, goog.bind(this.draw_, this, renderOptions), - renderHitDetectionCallback); - goog.asserts.assert(info, 'shape size is too large'); - - this.canvas_ = info.image; - this.origin_ = [info.offsetX, info.offsetY]; - imageSize = info.image.width; - - if (hasCustomHitDetectionImage) { - this.hitDetectionCanvas_ = info.hitImage; - this.hitDetectionImageSize_ = - [info.hitImage.width, info.hitImage.height]; - } else { - this.hitDetectionCanvas_ = this.canvas_; - this.hitDetectionImageSize_ = [imageSize, imageSize]; - } - } - - this.anchor_ = [size / 2, size / 2]; - this.size_ = [size, size]; - this.imageSize_ = [imageSize, imageSize]; -}; - - -/** - * @private - * @param {ol.style.RegularShape.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). - */ -ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) { - var i, angle0, radiusC; - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); - - // then move to (x, y) - context.translate(x, y); - - context.beginPath(); - if (this.radius2_ !== this.radius_) { - this.points_ = 2 * this.points_; - } - for (i = 0; i <= this.points_; i++) { - angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; - radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; - context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0), - renderOptions.size / 2 + radiusC * Math.sin(angle0)); - } - - if (this.fill_) { - context.fillStyle = ol.color.asString(this.fill_.getColor()); - context.fill(); - } - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); - } - context.lineCap = renderOptions.lineCap; - context.lineJoin = renderOptions.lineJoin; - context.miterLimit = renderOptions.miterLimit; - context.stroke(); - } - context.closePath(); -}; - - -/** - * @private - * @param {ol.style.RegularShape.RenderOptions} renderOptions - */ -ol.style.RegularShape.prototype.createHitDetectionCanvas_ = - function(renderOptions) { - this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; - if (this.fill_) { - this.hitDetectionCanvas_ = this.canvas_; - return; - } - - // if no fill style is set, create an extra hit-detection image with a - // default fill style - this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - var canvas = this.hitDetectionCanvas_; - - canvas.height = renderOptions.size; - canvas.width = renderOptions.size; - - var context = /** @type {CanvasRenderingContext2D} */ - (canvas.getContext('2d')); - this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); -}; - - -/** - * @private - * @param {ol.style.RegularShape.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). - */ -ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = - function(renderOptions, context, x, y) { - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); - - // then move to (x, y) - context.translate(x, y); - - context.beginPath(); - if (this.radius2_ !== this.radius_) { - this.points_ = 2 * this.points_; - } - var i, radiusC, angle0; - for (i = 0; i <= this.points_; i++) { - angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; - radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; - context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0), - renderOptions.size / 2 + radiusC * Math.sin(angle0)); - } - - context.fillStyle = ol.render.canvas.defaultFillStyle; - context.fill(); - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); - } - context.stroke(); - } - context.closePath(); -}; - - -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getChecksum = function() { - var strokeChecksum = this.stroke_ ? - this.stroke_.getChecksum() : '-'; - var fillChecksum = this.fill_ ? - this.fill_.getChecksum() : '-'; - - var recalculate = !this.checksums_ || - (strokeChecksum != this.checksums_[1] || - fillChecksum != this.checksums_[2] || - this.radius_ != this.checksums_[3] || - this.radius2_ != this.checksums_[4] || - this.angle_ != this.checksums_[5] || - this.points_ != this.checksums_[6]); - - if (recalculate) { - var checksum = 'r' + strokeChecksum + fillChecksum + - (this.radius_ !== undefined ? this.radius_.toString() : '-') + - (this.radius2_ !== undefined ? this.radius2_.toString() : '-') + - (this.angle_ !== undefined ? this.angle_.toString() : '-') + - (this.points_ !== undefined ? this.points_.toString() : '-'); - this.checksums_ = [checksum, strokeChecksum, fillChecksum, - this.radius_, this.radius2_, this.angle_, this.points_]; - } - - return this.checksums_[0]; -}; - -// Copyright 2009 The Closure Library Authors. -// All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file has been auto-generated by GenJsDeps, please do not edit. - -goog.addDependency('demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'], ['goog.ui.equation.EquationEditorDialog']); -goog.addDependency('demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'], ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']); -goog.addDependency('demos/editor/helloworlddialog.js', ['goog.demos.editor.HelloWorldDialog', 'goog.demos.editor.HelloWorldDialog.OkEvent'], ['goog.dom.TagName', 'goog.events.Event', 'goog.string', 'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder', 'goog.ui.editor.AbstractDialog.EventType']); -goog.addDependency('demos/editor/helloworlddialogplugin.js', ['goog.demos.editor.HelloWorldDialogPlugin', 'goog.demos.editor.HelloWorldDialogPlugin.Command'], ['goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName', 'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range', 'goog.functions', 'goog.ui.editor.AbstractDialog.EventType']); - -/** - * @fileoverview Custom exports file. - * @suppress {checkVars,extraRequire} - */ - -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEvent'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Color'); -goog.require('ol.Coordinate'); -goog.require('ol.CoordinateFormatType'); -goog.require('ol.DeviceOrientation'); -goog.require('ol.DeviceOrientationProperty'); -goog.require('ol.DragBoxEvent'); -goog.require('ol.Extent'); -goog.require('ol.Feature'); -goog.require('ol.FeatureLoader'); -goog.require('ol.FeatureStyleFunction'); -goog.require('ol.FeatureUrlFunction'); -goog.require('ol.Geolocation'); -goog.require('ol.GeolocationProperty'); -goog.require('ol.Graticule'); -goog.require('ol.Image'); -goog.require('ol.ImageTile'); -goog.require('ol.Kinetic'); -goog.require('ol.LoadingStrategy'); -goog.require('ol.Map'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserEventHandler'); -goog.require('ol.MapBrowserPointerEvent'); -goog.require('ol.MapEvent'); -goog.require('ol.MapEventType'); -goog.require('ol.MapProperty'); -goog.require('ol.Object'); -goog.require('ol.ObjectEvent'); -goog.require('ol.ObjectEventType'); -goog.require('ol.Observable'); -goog.require('ol.Overlay'); -goog.require('ol.OverlayPositioning'); -goog.require('ol.OverlayProperty'); -goog.require('ol.Size'); -goog.require('ol.Sphere'); -goog.require('ol.Tile'); -goog.require('ol.TileState'); -goog.require('ol.VectorTile'); -goog.require('ol.View'); -goog.require('ol.ViewHint'); -goog.require('ol.ViewProperty'); -goog.require('ol.animation'); -goog.require('ol.color'); -goog.require('ol.control'); -goog.require('ol.control.Attribution'); -goog.require('ol.control.Control'); -goog.require('ol.control.FullScreen'); -goog.require('ol.control.MousePosition'); -goog.require('ol.control.OverviewMap'); -goog.require('ol.control.Rotate'); -goog.require('ol.control.ScaleLine'); -goog.require('ol.control.ScaleLineProperty'); -goog.require('ol.control.ScaleLineUnits'); -goog.require('ol.control.Zoom'); -goog.require('ol.control.ZoomSlider'); -goog.require('ol.control.ZoomToExtent'); -goog.require('ol.coordinate'); -goog.require('ol.easing'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.extent'); -goog.require('ol.extent.Corner'); -goog.require('ol.extent.Relationship'); -goog.require('ol.featureloader'); -goog.require('ol.format.EsriJSON'); -goog.require('ol.format.Feature'); -goog.require('ol.format.GML'); -goog.require('ol.format.GML2'); -goog.require('ol.format.GML3'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.GPX'); -goog.require('ol.format.GeoJSON'); -goog.require('ol.format.IGC'); -goog.require('ol.format.IGCZ'); -goog.require('ol.format.KML'); -goog.require('ol.format.MVT'); -goog.require('ol.format.OSMXML'); -goog.require('ol.format.Polyline'); -goog.require('ol.format.TopoJSON'); -goog.require('ol.format.WFS'); -goog.require('ol.format.WKT'); -goog.require('ol.format.WMSCapabilities'); -goog.require('ol.format.WMSGetFeatureInfo'); -goog.require('ol.format.WMTSCapabilities'); -goog.require('ol.geom.Circle'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.has'); -goog.require('ol.interaction'); -goog.require('ol.interaction.DoubleClickZoom'); -goog.require('ol.interaction.DragAndDrop'); -goog.require('ol.interaction.DragAndDropEvent'); -goog.require('ol.interaction.DragBox'); -goog.require('ol.interaction.DragPan'); -goog.require('ol.interaction.DragRotate'); -goog.require('ol.interaction.DragRotateAndZoom'); -goog.require('ol.interaction.DragZoom'); -goog.require('ol.interaction.Draw'); -goog.require('ol.interaction.DrawEvent'); -goog.require('ol.interaction.DrawEventType'); -goog.require('ol.interaction.DrawGeometryFunctionType'); -goog.require('ol.interaction.DrawMode'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.InteractionProperty'); -goog.require('ol.interaction.KeyboardPan'); -goog.require('ol.interaction.KeyboardZoom'); -goog.require('ol.interaction.Modify'); -goog.require('ol.interaction.ModifyEvent'); -goog.require('ol.interaction.MouseWheelZoom'); -goog.require('ol.interaction.PinchRotate'); -goog.require('ol.interaction.PinchZoom'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.interaction.Select'); -goog.require('ol.interaction.SelectEvent'); -goog.require('ol.interaction.SelectEventType'); -goog.require('ol.interaction.SelectFilterFunction'); -goog.require('ol.interaction.Snap'); -goog.require('ol.interaction.SnapProperty'); -goog.require('ol.interaction.Translate'); -goog.require('ol.interaction.TranslateEvent'); -goog.require('ol.layer.Base'); -goog.require('ol.layer.Group'); -goog.require('ol.layer.Heatmap'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.LayerProperty'); -goog.require('ol.layer.LayerState'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.layer.VectorTile'); -goog.require('ol.loadingstrategy'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.ProjectionLike'); -goog.require('ol.proj.Units'); -goog.require('ol.proj.common'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.Feature'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.render.webgl.Immediate'); -goog.require('ol.size'); -goog.require('ol.source.BingMaps'); -goog.require('ol.source.Cluster'); -goog.require('ol.source.Image'); -goog.require('ol.source.ImageCanvas'); -goog.require('ol.source.ImageEvent'); -goog.require('ol.source.ImageMapGuide'); -goog.require('ol.source.ImageStatic'); -goog.require('ol.source.ImageVector'); -goog.require('ol.source.ImageWMS'); -goog.require('ol.source.MapQuest'); -goog.require('ol.source.OSM'); -goog.require('ol.source.Raster'); -goog.require('ol.source.RasterEvent'); -goog.require('ol.source.RasterEventType'); -goog.require('ol.source.Source'); -goog.require('ol.source.Stamen'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); -goog.require('ol.source.TileArcGISRest'); -goog.require('ol.source.TileDebug'); -goog.require('ol.source.TileEvent'); -goog.require('ol.source.TileImage'); -goog.require('ol.source.TileJSON'); -goog.require('ol.source.TileOptions'); -goog.require('ol.source.TileUTFGrid'); -goog.require('ol.source.TileWMS'); -goog.require('ol.source.UrlTile'); -goog.require('ol.source.Vector'); -goog.require('ol.source.VectorEvent'); -goog.require('ol.source.VectorEventType'); -goog.require('ol.source.VectorTile'); -goog.require('ol.source.WMTS'); -goog.require('ol.source.WMTSRequestEncoding'); -goog.require('ol.source.XYZ'); -goog.require('ol.source.Zoomify'); -goog.require('ol.style.Atlas'); -goog.require('ol.style.AtlasManager'); -goog.require('ol.style.Circle'); -goog.require('ol.style.Fill'); -goog.require('ol.style.GeometryFunction'); -goog.require('ol.style.Icon'); -goog.require('ol.style.IconAnchorUnits'); -goog.require('ol.style.IconImageCache'); -goog.require('ol.style.IconOrigin'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.RegularShape'); -goog.require('ol.style.Stroke'); -goog.require('ol.style.Style'); -goog.require('ol.style.StyleFunction'); -goog.require('ol.style.Text'); -goog.require('ol.style.defaultGeometryFunction'); -goog.require('ol.tilegrid.TileGrid'); -goog.require('ol.tilegrid.WMTS'); -goog.require('ol.tilejson'); -goog.require('ol.webgl.Context'); -goog.require('ol.xml'); - - -goog.exportSymbol( - 'ol.animation.bounce', - ol.animation.bounce, - OPENLAYERS); - -goog.exportSymbol( - 'ol.animation.pan', - ol.animation.pan, - OPENLAYERS); - -goog.exportSymbol( - 'ol.animation.rotate', - ol.animation.rotate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.animation.zoom', - ol.animation.zoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.Attribution', - ol.Attribution, - OPENLAYERS); - -goog.exportProperty( - ol.Attribution.prototype, - 'getHTML', - ol.Attribution.prototype.getHTML); - -goog.exportProperty( - ol.CollectionEvent.prototype, - 'element', - ol.CollectionEvent.prototype.element); - -goog.exportSymbol( - 'ol.Collection', - ol.Collection, - OPENLAYERS); - -goog.exportProperty( - ol.Collection.prototype, - 'clear', - ol.Collection.prototype.clear); - -goog.exportProperty( - ol.Collection.prototype, - 'extend', - ol.Collection.prototype.extend); - -goog.exportProperty( - ol.Collection.prototype, - 'forEach', - ol.Collection.prototype.forEach); - -goog.exportProperty( - ol.Collection.prototype, - 'getArray', - ol.Collection.prototype.getArray); - -goog.exportProperty( - ol.Collection.prototype, - 'item', - ol.Collection.prototype.item); - -goog.exportProperty( - ol.Collection.prototype, - 'getLength', - ol.Collection.prototype.getLength); - -goog.exportProperty( - ol.Collection.prototype, - 'insertAt', - ol.Collection.prototype.insertAt); - -goog.exportProperty( - ol.Collection.prototype, - 'pop', - ol.Collection.prototype.pop); - -goog.exportProperty( - ol.Collection.prototype, - 'push', - ol.Collection.prototype.push); - -goog.exportProperty( - ol.Collection.prototype, - 'remove', - ol.Collection.prototype.remove); - -goog.exportProperty( - ol.Collection.prototype, - 'removeAt', - ol.Collection.prototype.removeAt); - -goog.exportProperty( - ol.Collection.prototype, - 'setAt', - ol.Collection.prototype.setAt); - -goog.exportSymbol( - 'ol.coordinate.add', - ol.coordinate.add, - OPENLAYERS); - -goog.exportSymbol( - 'ol.coordinate.createStringXY', - ol.coordinate.createStringXY, - OPENLAYERS); - -goog.exportSymbol( - 'ol.coordinate.format', - ol.coordinate.format, - OPENLAYERS); - -goog.exportSymbol( - 'ol.coordinate.rotate', - ol.coordinate.rotate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.coordinate.toStringHDMS', - ol.coordinate.toStringHDMS, - OPENLAYERS); - -goog.exportSymbol( - 'ol.coordinate.toStringXY', - ol.coordinate.toStringXY, - OPENLAYERS); - -goog.exportSymbol( - 'ol.DeviceOrientation', - ol.DeviceOrientation, - OPENLAYERS); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getAlpha', - ol.DeviceOrientation.prototype.getAlpha); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getBeta', - ol.DeviceOrientation.prototype.getBeta); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getGamma', - ol.DeviceOrientation.prototype.getGamma); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getHeading', - ol.DeviceOrientation.prototype.getHeading); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getTracking', - ol.DeviceOrientation.prototype.getTracking); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'setTracking', - ol.DeviceOrientation.prototype.setTracking); - -goog.exportSymbol( - 'ol.easing.easeIn', - ol.easing.easeIn, - OPENLAYERS); - -goog.exportSymbol( - 'ol.easing.easeOut', - ol.easing.easeOut, - OPENLAYERS); - -goog.exportSymbol( - 'ol.easing.inAndOut', - ol.easing.inAndOut, - OPENLAYERS); - -goog.exportSymbol( - 'ol.easing.linear', - ol.easing.linear, - OPENLAYERS); - -goog.exportSymbol( - 'ol.easing.upAndDown', - ol.easing.upAndDown, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.boundingExtent', - ol.extent.boundingExtent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.buffer', - ol.extent.buffer, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.containsCoordinate', - ol.extent.containsCoordinate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.containsExtent', - ol.extent.containsExtent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.containsXY', - ol.extent.containsXY, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.createEmpty', - ol.extent.createEmpty, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.equals', - ol.extent.equals, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.extend', - ol.extent.extend, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getBottomLeft', - ol.extent.getBottomLeft, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getBottomRight', - ol.extent.getBottomRight, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getCenter', - ol.extent.getCenter, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getHeight', - ol.extent.getHeight, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getIntersection', - ol.extent.getIntersection, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getSize', - ol.extent.getSize, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getTopLeft', - ol.extent.getTopLeft, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getTopRight', - ol.extent.getTopRight, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.getWidth', - ol.extent.getWidth, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.intersects', - ol.extent.intersects, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.isEmpty', - ol.extent.isEmpty, - OPENLAYERS); - -goog.exportSymbol( - 'ol.extent.applyTransform', - ol.extent.applyTransform, - OPENLAYERS); - -goog.exportSymbol( - 'ol.Feature', - ol.Feature, - OPENLAYERS); - -goog.exportProperty( - ol.Feature.prototype, - 'clone', - ol.Feature.prototype.clone); - -goog.exportProperty( - ol.Feature.prototype, - 'getGeometry', - ol.Feature.prototype.getGeometry); - -goog.exportProperty( - ol.Feature.prototype, - 'getId', - ol.Feature.prototype.getId); - -goog.exportProperty( - ol.Feature.prototype, - 'getGeometryName', - ol.Feature.prototype.getGeometryName); - -goog.exportProperty( - ol.Feature.prototype, - 'getStyle', - ol.Feature.prototype.getStyle); - -goog.exportProperty( - ol.Feature.prototype, - 'getStyleFunction', - ol.Feature.prototype.getStyleFunction); - -goog.exportProperty( - ol.Feature.prototype, - 'setGeometry', - ol.Feature.prototype.setGeometry); - -goog.exportProperty( - ol.Feature.prototype, - 'setStyle', - ol.Feature.prototype.setStyle); - -goog.exportProperty( - ol.Feature.prototype, - 'setId', - ol.Feature.prototype.setId); - -goog.exportProperty( - ol.Feature.prototype, - 'setGeometryName', - ol.Feature.prototype.setGeometryName); - -goog.exportSymbol( - 'ol.featureloader.tile', - ol.featureloader.tile, - OPENLAYERS); - -goog.exportSymbol( - 'ol.featureloader.xhr', - ol.featureloader.xhr, - OPENLAYERS); - -goog.exportSymbol( - 'ol.Geolocation', - ol.Geolocation, - OPENLAYERS); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getAccuracy', - ol.Geolocation.prototype.getAccuracy); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getAccuracyGeometry', - ol.Geolocation.prototype.getAccuracyGeometry); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getAltitude', - ol.Geolocation.prototype.getAltitude); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getAltitudeAccuracy', - ol.Geolocation.prototype.getAltitudeAccuracy); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getHeading', - ol.Geolocation.prototype.getHeading); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getPosition', - ol.Geolocation.prototype.getPosition); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getProjection', - ol.Geolocation.prototype.getProjection); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getSpeed', - ol.Geolocation.prototype.getSpeed); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getTracking', - ol.Geolocation.prototype.getTracking); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getTrackingOptions', - ol.Geolocation.prototype.getTrackingOptions); - -goog.exportProperty( - ol.Geolocation.prototype, - 'setProjection', - ol.Geolocation.prototype.setProjection); - -goog.exportProperty( - ol.Geolocation.prototype, - 'setTracking', - ol.Geolocation.prototype.setTracking); - -goog.exportProperty( - ol.Geolocation.prototype, - 'setTrackingOptions', - ol.Geolocation.prototype.setTrackingOptions); - -goog.exportSymbol( - 'ol.Graticule', - ol.Graticule, - OPENLAYERS); - -goog.exportProperty( - ol.Graticule.prototype, - 'getMap', - ol.Graticule.prototype.getMap); - -goog.exportProperty( - ol.Graticule.prototype, - 'getMeridians', - ol.Graticule.prototype.getMeridians); - -goog.exportProperty( - ol.Graticule.prototype, - 'getParallels', - ol.Graticule.prototype.getParallels); - -goog.exportProperty( - ol.Graticule.prototype, - 'setMap', - ol.Graticule.prototype.setMap); - -goog.exportSymbol( - 'ol.has.DEVICE_PIXEL_RATIO', - ol.has.DEVICE_PIXEL_RATIO, - OPENLAYERS); - -goog.exportSymbol( - 'ol.has.CANVAS', - ol.has.CANVAS, - OPENLAYERS); - -goog.exportSymbol( - 'ol.has.DEVICE_ORIENTATION', - ol.has.DEVICE_ORIENTATION, - OPENLAYERS); - -goog.exportSymbol( - 'ol.has.GEOLOCATION', - ol.has.GEOLOCATION, - OPENLAYERS); - -goog.exportSymbol( - 'ol.has.TOUCH', - ol.has.TOUCH, - OPENLAYERS); - -goog.exportSymbol( - 'ol.has.WEBGL', - ol.has.WEBGL, - OPENLAYERS); - -goog.exportProperty( - ol.Image.prototype, - 'getImage', - ol.Image.prototype.getImage); - -goog.exportProperty( - ol.ImageTile.prototype, - 'getImage', - ol.ImageTile.prototype.getImage); - -goog.exportSymbol( - 'ol.Kinetic', - ol.Kinetic, - OPENLAYERS); - -goog.exportSymbol( - 'ol.loadingstrategy.all', - ol.loadingstrategy.all, - OPENLAYERS); - -goog.exportSymbol( - 'ol.loadingstrategy.bbox', - ol.loadingstrategy.bbox, - OPENLAYERS); - -goog.exportSymbol( - 'ol.loadingstrategy.tile', - ol.loadingstrategy.tile, - OPENLAYERS); - -goog.exportSymbol( - 'ol.Map', - ol.Map, - OPENLAYERS); - -goog.exportProperty( - ol.Map.prototype, - 'addControl', - ol.Map.prototype.addControl); - -goog.exportProperty( - ol.Map.prototype, - 'addInteraction', - ol.Map.prototype.addInteraction); - -goog.exportProperty( - ol.Map.prototype, - 'addLayer', - ol.Map.prototype.addLayer); - -goog.exportProperty( - ol.Map.prototype, - 'addOverlay', - ol.Map.prototype.addOverlay); - -goog.exportProperty( - ol.Map.prototype, - 'beforeRender', - ol.Map.prototype.beforeRender); - -goog.exportProperty( - ol.Map.prototype, - 'forEachFeatureAtPixel', - ol.Map.prototype.forEachFeatureAtPixel); - -goog.exportProperty( - ol.Map.prototype, - 'forEachLayerAtPixel', - ol.Map.prototype.forEachLayerAtPixel); - -goog.exportProperty( - ol.Map.prototype, - 'hasFeatureAtPixel', - ol.Map.prototype.hasFeatureAtPixel); - -goog.exportProperty( - ol.Map.prototype, - 'getEventCoordinate', - ol.Map.prototype.getEventCoordinate); - -goog.exportProperty( - ol.Map.prototype, - 'getEventPixel', - ol.Map.prototype.getEventPixel); - -goog.exportProperty( - ol.Map.prototype, - 'getTarget', - ol.Map.prototype.getTarget); - -goog.exportProperty( - ol.Map.prototype, - 'getTargetElement', - ol.Map.prototype.getTargetElement); - -goog.exportProperty( - ol.Map.prototype, - 'getCoordinateFromPixel', - ol.Map.prototype.getCoordinateFromPixel); - -goog.exportProperty( - ol.Map.prototype, - 'getControls', - ol.Map.prototype.getControls); - -goog.exportProperty( - ol.Map.prototype, - 'getOverlays', - ol.Map.prototype.getOverlays); - -goog.exportProperty( - ol.Map.prototype, - 'getOverlayById', - ol.Map.prototype.getOverlayById); - -goog.exportProperty( - ol.Map.prototype, - 'getInteractions', - ol.Map.prototype.getInteractions); - -goog.exportProperty( - ol.Map.prototype, - 'getLayerGroup', - ol.Map.prototype.getLayerGroup); - -goog.exportProperty( - ol.Map.prototype, - 'getLayers', - ol.Map.prototype.getLayers); - -goog.exportProperty( - ol.Map.prototype, - 'getPixelFromCoordinate', - ol.Map.prototype.getPixelFromCoordinate); - -goog.exportProperty( - ol.Map.prototype, - 'getSize', - ol.Map.prototype.getSize); - -goog.exportProperty( - ol.Map.prototype, - 'getView', - ol.Map.prototype.getView); - -goog.exportProperty( - ol.Map.prototype, - 'getViewport', - ol.Map.prototype.getViewport); - -goog.exportProperty( - ol.Map.prototype, - 'renderSync', - ol.Map.prototype.renderSync); - -goog.exportProperty( - ol.Map.prototype, - 'render', - ol.Map.prototype.render); - -goog.exportProperty( - ol.Map.prototype, - 'removeControl', - ol.Map.prototype.removeControl); - -goog.exportProperty( - ol.Map.prototype, - 'removeInteraction', - ol.Map.prototype.removeInteraction); - -goog.exportProperty( - ol.Map.prototype, - 'removeLayer', - ol.Map.prototype.removeLayer); - -goog.exportProperty( - ol.Map.prototype, - 'removeOverlay', - ol.Map.prototype.removeOverlay); - -goog.exportProperty( - ol.Map.prototype, - 'setLayerGroup', - ol.Map.prototype.setLayerGroup); - -goog.exportProperty( - ol.Map.prototype, - 'setSize', - ol.Map.prototype.setSize); - -goog.exportProperty( - ol.Map.prototype, - 'setTarget', - ol.Map.prototype.setTarget); - -goog.exportProperty( - ol.Map.prototype, - 'setView', - ol.Map.prototype.setView); - -goog.exportProperty( - ol.Map.prototype, - 'updateSize', - ol.Map.prototype.updateSize); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'originalEvent', - ol.MapBrowserEvent.prototype.originalEvent); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'pixel', - ol.MapBrowserEvent.prototype.pixel); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'coordinate', - ol.MapBrowserEvent.prototype.coordinate); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'dragging', - ol.MapBrowserEvent.prototype.dragging); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'preventDefault', - ol.MapBrowserEvent.prototype.preventDefault); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'stopPropagation', - ol.MapBrowserEvent.prototype.stopPropagation); - -goog.exportProperty( - ol.MapEvent.prototype, - 'map', - ol.MapEvent.prototype.map); - -goog.exportProperty( - ol.MapEvent.prototype, - 'frameState', - ol.MapEvent.prototype.frameState); - -goog.exportProperty( - ol.ObjectEvent.prototype, - 'key', - ol.ObjectEvent.prototype.key); - -goog.exportProperty( - ol.ObjectEvent.prototype, - 'oldValue', - ol.ObjectEvent.prototype.oldValue); - -goog.exportSymbol( - 'ol.Object', - ol.Object, - OPENLAYERS); - -goog.exportProperty( - ol.Object.prototype, - 'get', - ol.Object.prototype.get); - -goog.exportProperty( - ol.Object.prototype, - 'getKeys', - ol.Object.prototype.getKeys); - -goog.exportProperty( - ol.Object.prototype, - 'getProperties', - ol.Object.prototype.getProperties); - -goog.exportProperty( - ol.Object.prototype, - 'set', - ol.Object.prototype.set); - -goog.exportProperty( - ol.Object.prototype, - 'setProperties', - ol.Object.prototype.setProperties); - -goog.exportProperty( - ol.Object.prototype, - 'unset', - ol.Object.prototype.unset); - -goog.exportSymbol( - 'ol.Observable', - ol.Observable, - OPENLAYERS); - -goog.exportSymbol( - 'ol.Observable.unByKey', - ol.Observable.unByKey, - OPENLAYERS); - -goog.exportProperty( - ol.Observable.prototype, - 'changed', - ol.Observable.prototype.changed); - -goog.exportProperty( - ol.Observable.prototype, - 'dispatchEvent', - ol.Observable.prototype.dispatchEvent); - -goog.exportProperty( - ol.Observable.prototype, - 'getRevision', - ol.Observable.prototype.getRevision); - -goog.exportProperty( - ol.Observable.prototype, - 'on', - ol.Observable.prototype.on); - -goog.exportProperty( - ol.Observable.prototype, - 'once', - ol.Observable.prototype.once); - -goog.exportProperty( - ol.Observable.prototype, - 'un', - ol.Observable.prototype.un); - -goog.exportProperty( - ol.Observable.prototype, - 'unByKey', - ol.Observable.prototype.unByKey); - -goog.exportSymbol( - 'ol.inherits', - ol.inherits, - OPENLAYERS); - -goog.exportSymbol( - 'ol.Overlay', - ol.Overlay, - OPENLAYERS); - -goog.exportProperty( - ol.Overlay.prototype, - 'getElement', - ol.Overlay.prototype.getElement); - -goog.exportProperty( - ol.Overlay.prototype, - 'getId', - ol.Overlay.prototype.getId); - -goog.exportProperty( - ol.Overlay.prototype, - 'getMap', - ol.Overlay.prototype.getMap); - -goog.exportProperty( - ol.Overlay.prototype, - 'getOffset', - ol.Overlay.prototype.getOffset); - -goog.exportProperty( - ol.Overlay.prototype, - 'getPosition', - ol.Overlay.prototype.getPosition); - -goog.exportProperty( - ol.Overlay.prototype, - 'getPositioning', - ol.Overlay.prototype.getPositioning); - -goog.exportProperty( - ol.Overlay.prototype, - 'setElement', - ol.Overlay.prototype.setElement); - -goog.exportProperty( - ol.Overlay.prototype, - 'setMap', - ol.Overlay.prototype.setMap); - -goog.exportProperty( - ol.Overlay.prototype, - 'setOffset', - ol.Overlay.prototype.setOffset); - -goog.exportProperty( - ol.Overlay.prototype, - 'setPosition', - ol.Overlay.prototype.setPosition); - -goog.exportProperty( - ol.Overlay.prototype, - 'setPositioning', - ol.Overlay.prototype.setPositioning); - -goog.exportSymbol( - 'ol.size.toSize', - ol.size.toSize, - OPENLAYERS); - -goog.exportProperty( - ol.Tile.prototype, - 'getTileCoord', - ol.Tile.prototype.getTileCoord); - -goog.exportProperty( - ol.VectorTile.prototype, - 'getFormat', - ol.VectorTile.prototype.getFormat); - -goog.exportProperty( - ol.VectorTile.prototype, - 'setLoader', - ol.VectorTile.prototype.setLoader); - -goog.exportSymbol( - 'ol.View', - ol.View, - OPENLAYERS); - -goog.exportProperty( - ol.View.prototype, - 'constrainCenter', - ol.View.prototype.constrainCenter); - -goog.exportProperty( - ol.View.prototype, - 'constrainResolution', - ol.View.prototype.constrainResolution); - -goog.exportProperty( - ol.View.prototype, - 'constrainRotation', - ol.View.prototype.constrainRotation); - -goog.exportProperty( - ol.View.prototype, - 'getCenter', - ol.View.prototype.getCenter); - -goog.exportProperty( - ol.View.prototype, - 'calculateExtent', - ol.View.prototype.calculateExtent); - -goog.exportProperty( - ol.View.prototype, - 'getProjection', - ol.View.prototype.getProjection); - -goog.exportProperty( - ol.View.prototype, - 'getResolution', - ol.View.prototype.getResolution); - -goog.exportProperty( - ol.View.prototype, - 'getRotation', - ol.View.prototype.getRotation); - -goog.exportProperty( - ol.View.prototype, - 'getZoom', - ol.View.prototype.getZoom); - -goog.exportProperty( - ol.View.prototype, - 'fit', - ol.View.prototype.fit); - -goog.exportProperty( - ol.View.prototype, - 'centerOn', - ol.View.prototype.centerOn); - -goog.exportProperty( - ol.View.prototype, - 'rotate', - ol.View.prototype.rotate); - -goog.exportProperty( - ol.View.prototype, - 'setCenter', - ol.View.prototype.setCenter); - -goog.exportProperty( - ol.View.prototype, - 'setResolution', - ol.View.prototype.setResolution); - -goog.exportProperty( - ol.View.prototype, - 'setRotation', - ol.View.prototype.setRotation); - -goog.exportProperty( - ol.View.prototype, - 'setZoom', - ol.View.prototype.setZoom); - -goog.exportSymbol( - 'ol.xml.getAllTextContent', - ol.xml.getAllTextContent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.xml.parse', - ol.xml.parse, - OPENLAYERS); - -goog.exportProperty( - ol.webgl.Context.prototype, - 'getGL', - ol.webgl.Context.prototype.getGL); - -goog.exportProperty( - ol.webgl.Context.prototype, - 'useProgram', - ol.webgl.Context.prototype.useProgram); - -goog.exportSymbol( - 'ol.tilegrid.TileGrid', - ol.tilegrid.TileGrid, - OPENLAYERS); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getMaxZoom', - ol.tilegrid.TileGrid.prototype.getMaxZoom); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getMinZoom', - ol.tilegrid.TileGrid.prototype.getMinZoom); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getOrigin', - ol.tilegrid.TileGrid.prototype.getOrigin); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getResolution', - ol.tilegrid.TileGrid.prototype.getResolution); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getResolutions', - ol.tilegrid.TileGrid.prototype.getResolutions); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getTileCoordExtent', - ol.tilegrid.TileGrid.prototype.getTileCoordExtent); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getTileCoordForCoordAndResolution', - ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getTileCoordForCoordAndZ', - ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ); - -goog.exportProperty( - ol.tilegrid.TileGrid.prototype, - 'getTileSize', - ol.tilegrid.TileGrid.prototype.getTileSize); - -goog.exportSymbol( - 'ol.tilegrid.createXYZ', - ol.tilegrid.createXYZ, - OPENLAYERS); - -goog.exportSymbol( - 'ol.tilegrid.WMTS', - ol.tilegrid.WMTS, - OPENLAYERS); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getMatrixIds', - ol.tilegrid.WMTS.prototype.getMatrixIds); - -goog.exportSymbol( - 'ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet', - ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet, - OPENLAYERS); - -goog.exportSymbol( - 'ol.style.AtlasManager', - ol.style.AtlasManager, - OPENLAYERS); - -goog.exportSymbol( - 'ol.style.Circle', - ol.style.Circle, - OPENLAYERS); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getFill', - ol.style.Circle.prototype.getFill); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getImage', - ol.style.Circle.prototype.getImage); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getRadius', - ol.style.Circle.prototype.getRadius); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getStroke', - ol.style.Circle.prototype.getStroke); - -goog.exportSymbol( - 'ol.style.Fill', - ol.style.Fill, - OPENLAYERS); - -goog.exportProperty( - ol.style.Fill.prototype, - 'getColor', - ol.style.Fill.prototype.getColor); - -goog.exportProperty( - ol.style.Fill.prototype, - 'setColor', - ol.style.Fill.prototype.setColor); - -goog.exportSymbol( - 'ol.style.Icon', - ol.style.Icon, - OPENLAYERS); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getAnchor', - ol.style.Icon.prototype.getAnchor); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getImage', - ol.style.Icon.prototype.getImage); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getOrigin', - ol.style.Icon.prototype.getOrigin); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getSrc', - ol.style.Icon.prototype.getSrc); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getSize', - ol.style.Icon.prototype.getSize); - -goog.exportProperty( - ol.style.Icon.prototype, - 'load', - ol.style.Icon.prototype.load); - -goog.exportSymbol( - 'ol.style.Image', - ol.style.Image, - OPENLAYERS); - -goog.exportProperty( - ol.style.Image.prototype, - 'getOpacity', - ol.style.Image.prototype.getOpacity); - -goog.exportProperty( - ol.style.Image.prototype, - 'getRotateWithView', - ol.style.Image.prototype.getRotateWithView); - -goog.exportProperty( - ol.style.Image.prototype, - 'getRotation', - ol.style.Image.prototype.getRotation); - -goog.exportProperty( - ol.style.Image.prototype, - 'getScale', - ol.style.Image.prototype.getScale); - -goog.exportProperty( - ol.style.Image.prototype, - 'getSnapToPixel', - ol.style.Image.prototype.getSnapToPixel); - -goog.exportProperty( - ol.style.Image.prototype, - 'setOpacity', - ol.style.Image.prototype.setOpacity); - -goog.exportProperty( - ol.style.Image.prototype, - 'setRotation', - ol.style.Image.prototype.setRotation); - -goog.exportProperty( - ol.style.Image.prototype, - 'setScale', - ol.style.Image.prototype.setScale); - -goog.exportSymbol( - 'ol.style.RegularShape', - ol.style.RegularShape, - OPENLAYERS); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getAnchor', - ol.style.RegularShape.prototype.getAnchor); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getAngle', - ol.style.RegularShape.prototype.getAngle); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getFill', - ol.style.RegularShape.prototype.getFill); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getImage', - ol.style.RegularShape.prototype.getImage); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getOrigin', - ol.style.RegularShape.prototype.getOrigin); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getPoints', - ol.style.RegularShape.prototype.getPoints); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getRadius', - ol.style.RegularShape.prototype.getRadius); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getRadius2', - ol.style.RegularShape.prototype.getRadius2); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getSize', - ol.style.RegularShape.prototype.getSize); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getStroke', - ol.style.RegularShape.prototype.getStroke); - -goog.exportSymbol( - 'ol.style.Stroke', - ol.style.Stroke, - OPENLAYERS); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'getColor', - ol.style.Stroke.prototype.getColor); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'getLineCap', - ol.style.Stroke.prototype.getLineCap); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'getLineDash', - ol.style.Stroke.prototype.getLineDash); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'getLineJoin', - ol.style.Stroke.prototype.getLineJoin); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'getMiterLimit', - ol.style.Stroke.prototype.getMiterLimit); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'getWidth', - ol.style.Stroke.prototype.getWidth); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'setColor', - ol.style.Stroke.prototype.setColor); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'setLineCap', - ol.style.Stroke.prototype.setLineCap); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'setLineDash', - ol.style.Stroke.prototype.setLineDash); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'setLineJoin', - ol.style.Stroke.prototype.setLineJoin); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'setMiterLimit', - ol.style.Stroke.prototype.setMiterLimit); - -goog.exportProperty( - ol.style.Stroke.prototype, - 'setWidth', - ol.style.Stroke.prototype.setWidth); - -goog.exportSymbol( - 'ol.style.Style', - ol.style.Style, - OPENLAYERS); - -goog.exportProperty( - ol.style.Style.prototype, - 'getGeometry', - ol.style.Style.prototype.getGeometry); - -goog.exportProperty( - ol.style.Style.prototype, - 'getGeometryFunction', - ol.style.Style.prototype.getGeometryFunction); - -goog.exportProperty( - ol.style.Style.prototype, - 'getFill', - ol.style.Style.prototype.getFill); - -goog.exportProperty( - ol.style.Style.prototype, - 'getImage', - ol.style.Style.prototype.getImage); - -goog.exportProperty( - ol.style.Style.prototype, - 'getStroke', - ol.style.Style.prototype.getStroke); - -goog.exportProperty( - ol.style.Style.prototype, - 'getText', - ol.style.Style.prototype.getText); - -goog.exportProperty( - ol.style.Style.prototype, - 'getZIndex', - ol.style.Style.prototype.getZIndex); - -goog.exportProperty( - ol.style.Style.prototype, - 'setGeometry', - ol.style.Style.prototype.setGeometry); - -goog.exportProperty( - ol.style.Style.prototype, - 'setZIndex', - ol.style.Style.prototype.setZIndex); - -goog.exportSymbol( - 'ol.style.Text', - ol.style.Text, - OPENLAYERS); - -goog.exportProperty( - ol.style.Text.prototype, - 'getFont', - ol.style.Text.prototype.getFont); - -goog.exportProperty( - ol.style.Text.prototype, - 'getOffsetX', - ol.style.Text.prototype.getOffsetX); - -goog.exportProperty( - ol.style.Text.prototype, - 'getOffsetY', - ol.style.Text.prototype.getOffsetY); - -goog.exportProperty( - ol.style.Text.prototype, - 'getFill', - ol.style.Text.prototype.getFill); - -goog.exportProperty( - ol.style.Text.prototype, - 'getRotation', - ol.style.Text.prototype.getRotation); - -goog.exportProperty( - ol.style.Text.prototype, - 'getScale', - ol.style.Text.prototype.getScale); - -goog.exportProperty( - ol.style.Text.prototype, - 'getStroke', - ol.style.Text.prototype.getStroke); - -goog.exportProperty( - ol.style.Text.prototype, - 'getText', - ol.style.Text.prototype.getText); - -goog.exportProperty( - ol.style.Text.prototype, - 'getTextAlign', - ol.style.Text.prototype.getTextAlign); - -goog.exportProperty( - ol.style.Text.prototype, - 'getTextBaseline', - ol.style.Text.prototype.getTextBaseline); - -goog.exportProperty( - ol.style.Text.prototype, - 'setFont', - ol.style.Text.prototype.setFont); - -goog.exportProperty( - ol.style.Text.prototype, - 'setOffsetX', - ol.style.Text.prototype.setOffsetX); - -goog.exportProperty( - ol.style.Text.prototype, - 'setOffsetY', - ol.style.Text.prototype.setOffsetY); - -goog.exportProperty( - ol.style.Text.prototype, - 'setFill', - ol.style.Text.prototype.setFill); - -goog.exportProperty( - ol.style.Text.prototype, - 'setRotation', - ol.style.Text.prototype.setRotation); - -goog.exportProperty( - ol.style.Text.prototype, - 'setScale', - ol.style.Text.prototype.setScale); - -goog.exportProperty( - ol.style.Text.prototype, - 'setStroke', - ol.style.Text.prototype.setStroke); - -goog.exportProperty( - ol.style.Text.prototype, - 'setText', - ol.style.Text.prototype.setText); - -goog.exportProperty( - ol.style.Text.prototype, - 'setTextAlign', - ol.style.Text.prototype.setTextAlign); - -goog.exportProperty( - ol.style.Text.prototype, - 'setTextBaseline', - ol.style.Text.prototype.setTextBaseline); - -goog.exportSymbol( - 'ol.Sphere', - ol.Sphere, - OPENLAYERS); - -goog.exportProperty( - ol.Sphere.prototype, - 'geodesicArea', - ol.Sphere.prototype.geodesicArea); - -goog.exportProperty( - ol.Sphere.prototype, - 'haversineDistance', - ol.Sphere.prototype.haversineDistance); - -goog.exportSymbol( - 'ol.source.BingMaps', - ol.source.BingMaps, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.BingMaps.TOS_ATTRIBUTION', - ol.source.BingMaps.TOS_ATTRIBUTION, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.Cluster', - ol.source.Cluster, - OPENLAYERS); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getSource', - ol.source.Cluster.prototype.getSource); - -goog.exportSymbol( - 'ol.source.ImageCanvas', - ol.source.ImageCanvas, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.ImageMapGuide', - ol.source.ImageMapGuide, - OPENLAYERS); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getParams', - ol.source.ImageMapGuide.prototype.getParams); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getImageLoadFunction', - ol.source.ImageMapGuide.prototype.getImageLoadFunction); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'updateParams', - ol.source.ImageMapGuide.prototype.updateParams); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'setImageLoadFunction', - ol.source.ImageMapGuide.prototype.setImageLoadFunction); - -goog.exportSymbol( - 'ol.source.Image', - ol.source.Image, - OPENLAYERS); - -goog.exportProperty( - ol.source.ImageEvent.prototype, - 'image', - ol.source.ImageEvent.prototype.image); - -goog.exportSymbol( - 'ol.source.ImageStatic', - ol.source.ImageStatic, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.ImageVector', - ol.source.ImageVector, - OPENLAYERS); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getSource', - ol.source.ImageVector.prototype.getSource); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getStyle', - ol.source.ImageVector.prototype.getStyle); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getStyleFunction', - ol.source.ImageVector.prototype.getStyleFunction); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'setStyle', - ol.source.ImageVector.prototype.setStyle); - -goog.exportSymbol( - 'ol.source.ImageWMS', - ol.source.ImageWMS, - OPENLAYERS); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getGetFeatureInfoUrl', - ol.source.ImageWMS.prototype.getGetFeatureInfoUrl); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getParams', - ol.source.ImageWMS.prototype.getParams); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getImageLoadFunction', - ol.source.ImageWMS.prototype.getImageLoadFunction); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getUrl', - ol.source.ImageWMS.prototype.getUrl); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'setImageLoadFunction', - ol.source.ImageWMS.prototype.setImageLoadFunction); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'setUrl', - ol.source.ImageWMS.prototype.setUrl); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'updateParams', - ol.source.ImageWMS.prototype.updateParams); - -goog.exportSymbol( - 'ol.source.MapQuest', - ol.source.MapQuest, - OPENLAYERS); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getLayer', - ol.source.MapQuest.prototype.getLayer); - -goog.exportSymbol( - 'ol.source.OSM', - ol.source.OSM, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.OSM.ATTRIBUTION', - ol.source.OSM.ATTRIBUTION, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.Raster', - ol.source.Raster, - OPENLAYERS); - -goog.exportProperty( - ol.source.Raster.prototype, - 'setOperation', - ol.source.Raster.prototype.setOperation); - -goog.exportProperty( - ol.source.RasterEvent.prototype, - 'extent', - ol.source.RasterEvent.prototype.extent); - -goog.exportProperty( - ol.source.RasterEvent.prototype, - 'resolution', - ol.source.RasterEvent.prototype.resolution); - -goog.exportProperty( - ol.source.RasterEvent.prototype, - 'data', - ol.source.RasterEvent.prototype.data); - -goog.exportSymbol( - 'ol.source.Source', - ol.source.Source, - OPENLAYERS); - -goog.exportProperty( - ol.source.Source.prototype, - 'getAttributions', - ol.source.Source.prototype.getAttributions); - -goog.exportProperty( - ol.source.Source.prototype, - 'getLogo', - ol.source.Source.prototype.getLogo); - -goog.exportProperty( - ol.source.Source.prototype, - 'getProjection', - ol.source.Source.prototype.getProjection); - -goog.exportProperty( - ol.source.Source.prototype, - 'getState', - ol.source.Source.prototype.getState); - -goog.exportProperty( - ol.source.Source.prototype, - 'setAttributions', - ol.source.Source.prototype.setAttributions); - -goog.exportSymbol( - 'ol.source.Stamen', - ol.source.Stamen, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.TileArcGISRest', - ol.source.TileArcGISRest, - OPENLAYERS); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getParams', - ol.source.TileArcGISRest.prototype.getParams); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'updateParams', - ol.source.TileArcGISRest.prototype.updateParams); - -goog.exportSymbol( - 'ol.source.TileDebug', - ol.source.TileDebug, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.TileImage', - ol.source.TileImage, - OPENLAYERS); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setRenderReprojectionEdges', - ol.source.TileImage.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setTileGridForProjection', - ol.source.TileImage.prototype.setTileGridForProjection); - -goog.exportSymbol( - 'ol.source.TileJSON', - ol.source.TileJSON, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.Tile', - ol.source.Tile, - OPENLAYERS); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getTileGrid', - ol.source.Tile.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileEvent.prototype, - 'tile', - ol.source.TileEvent.prototype.tile); - -goog.exportSymbol( - 'ol.source.TileUTFGrid', - ol.source.TileUTFGrid, - OPENLAYERS); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getTemplate', - ol.source.TileUTFGrid.prototype.getTemplate); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'forDataAtCoordinateAndResolution', - ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution); - -goog.exportSymbol( - 'ol.source.TileWMS', - ol.source.TileWMS, - OPENLAYERS); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getGetFeatureInfoUrl', - ol.source.TileWMS.prototype.getGetFeatureInfoUrl); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getParams', - ol.source.TileWMS.prototype.getParams); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'updateParams', - ol.source.TileWMS.prototype.updateParams); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getTileLoadFunction', - ol.source.UrlTile.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getTileUrlFunction', - ol.source.UrlTile.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getUrls', - ol.source.UrlTile.prototype.getUrls); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'setTileLoadFunction', - ol.source.UrlTile.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'setTileUrlFunction', - ol.source.UrlTile.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'setUrl', - ol.source.UrlTile.prototype.setUrl); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'setUrls', - ol.source.UrlTile.prototype.setUrls); - -goog.exportSymbol( - 'ol.source.Vector', - ol.source.Vector, - OPENLAYERS); - -goog.exportProperty( - ol.source.Vector.prototype, - 'addFeature', - ol.source.Vector.prototype.addFeature); - -goog.exportProperty( - ol.source.Vector.prototype, - 'addFeatures', - ol.source.Vector.prototype.addFeatures); - -goog.exportProperty( - ol.source.Vector.prototype, - 'clear', - ol.source.Vector.prototype.clear); - -goog.exportProperty( - ol.source.Vector.prototype, - 'forEachFeature', - ol.source.Vector.prototype.forEachFeature); - -goog.exportProperty( - ol.source.Vector.prototype, - 'forEachFeatureInExtent', - ol.source.Vector.prototype.forEachFeatureInExtent); - -goog.exportProperty( - ol.source.Vector.prototype, - 'forEachFeatureIntersectingExtent', - ol.source.Vector.prototype.forEachFeatureIntersectingExtent); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getFeaturesCollection', - ol.source.Vector.prototype.getFeaturesCollection); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getFeatures', - ol.source.Vector.prototype.getFeatures); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getFeaturesAtCoordinate', - ol.source.Vector.prototype.getFeaturesAtCoordinate); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getFeaturesInExtent', - ol.source.Vector.prototype.getFeaturesInExtent); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getClosestFeatureToCoordinate', - ol.source.Vector.prototype.getClosestFeatureToCoordinate); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getExtent', - ol.source.Vector.prototype.getExtent); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getFeatureById', - ol.source.Vector.prototype.getFeatureById); - -goog.exportProperty( - ol.source.Vector.prototype, - 'removeFeature', - ol.source.Vector.prototype.removeFeature); - -goog.exportProperty( - ol.source.VectorEvent.prototype, - 'feature', - ol.source.VectorEvent.prototype.feature); - -goog.exportSymbol( - 'ol.source.VectorTile', - ol.source.VectorTile, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.WMTS', - ol.source.WMTS, - OPENLAYERS); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getDimensions', - ol.source.WMTS.prototype.getDimensions); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getFormat', - ol.source.WMTS.prototype.getFormat); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getLayer', - ol.source.WMTS.prototype.getLayer); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getMatrixSet', - ol.source.WMTS.prototype.getMatrixSet); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getRequestEncoding', - ol.source.WMTS.prototype.getRequestEncoding); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getStyle', - ol.source.WMTS.prototype.getStyle); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getVersion', - ol.source.WMTS.prototype.getVersion); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'updateDimensions', - ol.source.WMTS.prototype.updateDimensions); - -goog.exportSymbol( - 'ol.source.WMTS.optionsFromCapabilities', - ol.source.WMTS.optionsFromCapabilities, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.XYZ', - ol.source.XYZ, - OPENLAYERS); - -goog.exportSymbol( - 'ol.source.Zoomify', - ol.source.Zoomify, - OPENLAYERS); - -goog.exportProperty( - ol.render.Event.prototype, - 'vectorContext', - ol.render.Event.prototype.vectorContext); - -goog.exportProperty( - ol.render.Event.prototype, - 'frameState', - ol.render.Event.prototype.frameState); - -goog.exportProperty( - ol.render.Event.prototype, - 'context', - ol.render.Event.prototype.context); - -goog.exportProperty( - ol.render.Event.prototype, - 'glContext', - ol.render.Event.prototype.glContext); - -goog.exportProperty( - ol.render.Feature.prototype, - 'get', - ol.render.Feature.prototype.get); - -goog.exportProperty( - ol.render.Feature.prototype, - 'getExtent', - ol.render.Feature.prototype.getExtent); - -goog.exportProperty( - ol.render.Feature.prototype, - 'getGeometry', - ol.render.Feature.prototype.getGeometry); - -goog.exportProperty( - ol.render.Feature.prototype, - 'getProperties', - ol.render.Feature.prototype.getProperties); - -goog.exportProperty( - ol.render.Feature.prototype, - 'getType', - ol.render.Feature.prototype.getType); - -goog.exportSymbol( - 'ol.render.VectorContext', - ol.render.VectorContext, - OPENLAYERS); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawAsync', - ol.render.webgl.Immediate.prototype.drawAsync); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawCircleGeometry', - ol.render.webgl.Immediate.prototype.drawCircleGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawFeature', - ol.render.webgl.Immediate.prototype.drawFeature); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawGeometryCollectionGeometry', - ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawPointGeometry', - ol.render.webgl.Immediate.prototype.drawPointGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawLineStringGeometry', - ol.render.webgl.Immediate.prototype.drawLineStringGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawMultiLineStringGeometry', - ol.render.webgl.Immediate.prototype.drawMultiLineStringGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawMultiPointGeometry', - ol.render.webgl.Immediate.prototype.drawMultiPointGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawMultiPolygonGeometry', - ol.render.webgl.Immediate.prototype.drawMultiPolygonGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawPolygonGeometry', - ol.render.webgl.Immediate.prototype.drawPolygonGeometry); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'drawText', - ol.render.webgl.Immediate.prototype.drawText); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'setFillStrokeStyle', - ol.render.webgl.Immediate.prototype.setFillStrokeStyle); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'setImageStyle', - ol.render.webgl.Immediate.prototype.setImageStyle); - -goog.exportProperty( - ol.render.webgl.Immediate.prototype, - 'setTextStyle', - ol.render.webgl.Immediate.prototype.setTextStyle); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawAsync', - ol.render.canvas.Immediate.prototype.drawAsync); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawCircleGeometry', - ol.render.canvas.Immediate.prototype.drawCircleGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawFeature', - ol.render.canvas.Immediate.prototype.drawFeature); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawPointGeometry', - ol.render.canvas.Immediate.prototype.drawPointGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawMultiPointGeometry', - ol.render.canvas.Immediate.prototype.drawMultiPointGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawLineStringGeometry', - ol.render.canvas.Immediate.prototype.drawLineStringGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawMultiLineStringGeometry', - ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawPolygonGeometry', - ol.render.canvas.Immediate.prototype.drawPolygonGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'drawMultiPolygonGeometry', - ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'setFillStrokeStyle', - ol.render.canvas.Immediate.prototype.setFillStrokeStyle); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'setImageStyle', - ol.render.canvas.Immediate.prototype.setImageStyle); - -goog.exportProperty( - ol.render.canvas.Immediate.prototype, - 'setTextStyle', - ol.render.canvas.Immediate.prototype.setTextStyle); - -goog.exportSymbol( - 'ol.proj.common.add', - ol.proj.common.add, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.METERS_PER_UNIT', - ol.proj.METERS_PER_UNIT, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.Projection', - ol.proj.Projection, - OPENLAYERS); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'getCode', - ol.proj.Projection.prototype.getCode); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'getExtent', - ol.proj.Projection.prototype.getExtent); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'getUnits', - ol.proj.Projection.prototype.getUnits); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'getMetersPerUnit', - ol.proj.Projection.prototype.getMetersPerUnit); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'getWorldExtent', - ol.proj.Projection.prototype.getWorldExtent); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'isGlobal', - ol.proj.Projection.prototype.isGlobal); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'setGlobal', - ol.proj.Projection.prototype.setGlobal); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'setExtent', - ol.proj.Projection.prototype.setExtent); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'setWorldExtent', - ol.proj.Projection.prototype.setWorldExtent); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'setGetPointResolution', - ol.proj.Projection.prototype.setGetPointResolution); - -goog.exportProperty( - ol.proj.Projection.prototype, - 'getPointResolution', - ol.proj.Projection.prototype.getPointResolution); - -goog.exportSymbol( - 'ol.proj.addEquivalentProjections', - ol.proj.addEquivalentProjections, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.addProjection', - ol.proj.addProjection, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.addCoordinateTransforms', - ol.proj.addCoordinateTransforms, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.fromLonLat', - ol.proj.fromLonLat, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.toLonLat', - ol.proj.toLonLat, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.get', - ol.proj.get, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.getTransform', - ol.proj.getTransform, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.transform', - ol.proj.transform, - OPENLAYERS); - -goog.exportSymbol( - 'ol.proj.transformExtent', - ol.proj.transformExtent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.layer.Heatmap', - ol.layer.Heatmap, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getBlur', - ol.layer.Heatmap.prototype.getBlur); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getGradient', - ol.layer.Heatmap.prototype.getGradient); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getRadius', - ol.layer.Heatmap.prototype.getRadius); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setBlur', - ol.layer.Heatmap.prototype.setBlur); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setGradient', - ol.layer.Heatmap.prototype.setGradient); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setRadius', - ol.layer.Heatmap.prototype.setRadius); - -goog.exportSymbol( - 'ol.layer.Image', - ol.layer.Image, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getSource', - ol.layer.Image.prototype.getSource); - -goog.exportSymbol( - 'ol.layer.Layer', - ol.layer.Layer, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getSource', - ol.layer.Layer.prototype.getSource); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setMap', - ol.layer.Layer.prototype.setMap); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setSource', - ol.layer.Layer.prototype.setSource); - -goog.exportSymbol( - 'ol.layer.Base', - ol.layer.Base, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getExtent', - ol.layer.Base.prototype.getExtent); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getMaxResolution', - ol.layer.Base.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getMinResolution', - ol.layer.Base.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getOpacity', - ol.layer.Base.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getVisible', - ol.layer.Base.prototype.getVisible); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getZIndex', - ol.layer.Base.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setExtent', - ol.layer.Base.prototype.setExtent); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setMaxResolution', - ol.layer.Base.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setMinResolution', - ol.layer.Base.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setOpacity', - ol.layer.Base.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setVisible', - ol.layer.Base.prototype.setVisible); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setZIndex', - ol.layer.Base.prototype.setZIndex); - -goog.exportSymbol( - 'ol.layer.Group', - ol.layer.Group, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getLayers', - ol.layer.Group.prototype.getLayers); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setLayers', - ol.layer.Group.prototype.setLayers); - -goog.exportSymbol( - 'ol.layer.Tile', - ol.layer.Tile, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getPreload', - ol.layer.Tile.prototype.getPreload); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getSource', - ol.layer.Tile.prototype.getSource); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setPreload', - ol.layer.Tile.prototype.setPreload); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getUseInterimTilesOnError', - ol.layer.Tile.prototype.getUseInterimTilesOnError); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setUseInterimTilesOnError', - ol.layer.Tile.prototype.setUseInterimTilesOnError); - -goog.exportSymbol( - 'ol.layer.Vector', - ol.layer.Vector, - OPENLAYERS); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getSource', - ol.layer.Vector.prototype.getSource); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getStyle', - ol.layer.Vector.prototype.getStyle); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getStyleFunction', - ol.layer.Vector.prototype.getStyleFunction); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setStyle', - ol.layer.Vector.prototype.setStyle); - -goog.exportSymbol( - 'ol.layer.VectorTile', - ol.layer.VectorTile, - OPENLAYERS); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getPreload', - ol.layer.VectorTile.prototype.getPreload); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getSource', - ol.layer.VectorTile.prototype.getSource); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getUseInterimTilesOnError', - ol.layer.VectorTile.prototype.getUseInterimTilesOnError); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setPreload', - ol.layer.VectorTile.prototype.setPreload); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setUseInterimTilesOnError', - ol.layer.VectorTile.prototype.setUseInterimTilesOnError); - -goog.exportSymbol( - 'ol.interaction.DoubleClickZoom', - ol.interaction.DoubleClickZoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.DoubleClickZoom.handleEvent', - ol.interaction.DoubleClickZoom.handleEvent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.DragAndDrop', - ol.interaction.DragAndDrop, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.DragAndDrop.handleEvent', - ol.interaction.DragAndDrop.handleEvent, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.DragAndDropEvent.prototype, - 'features', - ol.interaction.DragAndDropEvent.prototype.features); - -goog.exportProperty( - ol.interaction.DragAndDropEvent.prototype, - 'file', - ol.interaction.DragAndDropEvent.prototype.file); - -goog.exportProperty( - ol.interaction.DragAndDropEvent.prototype, - 'projection', - ol.interaction.DragAndDropEvent.prototype.projection); - -goog.exportProperty( - ol.DragBoxEvent.prototype, - 'coordinate', - ol.DragBoxEvent.prototype.coordinate); - -goog.exportSymbol( - 'ol.interaction.DragBox', - ol.interaction.DragBox, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'getGeometry', - ol.interaction.DragBox.prototype.getGeometry); - -goog.exportSymbol( - 'ol.interaction.DragPan', - ol.interaction.DragPan, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.DragRotateAndZoom', - ol.interaction.DragRotateAndZoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.DragRotate', - ol.interaction.DragRotate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.DragZoom', - ol.interaction.DragZoom, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.DrawEvent.prototype, - 'feature', - ol.interaction.DrawEvent.prototype.feature); - -goog.exportSymbol( - 'ol.interaction.Draw', - ol.interaction.Draw, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.Draw.handleEvent', - ol.interaction.Draw.handleEvent, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'removeLastPoint', - ol.interaction.Draw.prototype.removeLastPoint); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'finishDrawing', - ol.interaction.Draw.prototype.finishDrawing); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'extend', - ol.interaction.Draw.prototype.extend); - -goog.exportSymbol( - 'ol.interaction.Draw.createRegularPolygon', - ol.interaction.Draw.createRegularPolygon, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.Interaction', - ol.interaction.Interaction, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'getActive', - ol.interaction.Interaction.prototype.getActive); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'setActive', - ol.interaction.Interaction.prototype.setActive); - -goog.exportSymbol( - 'ol.interaction.defaults', - ol.interaction.defaults, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.KeyboardPan', - ol.interaction.KeyboardPan, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.KeyboardPan.handleEvent', - ol.interaction.KeyboardPan.handleEvent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.KeyboardZoom', - ol.interaction.KeyboardZoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.KeyboardZoom.handleEvent', - ol.interaction.KeyboardZoom.handleEvent, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.ModifyEvent.prototype, - 'features', - ol.interaction.ModifyEvent.prototype.features); - -goog.exportProperty( - ol.interaction.ModifyEvent.prototype, - 'mapBrowserPointerEvent', - ol.interaction.ModifyEvent.prototype.mapBrowserPointerEvent); - -goog.exportSymbol( - 'ol.interaction.Modify', - ol.interaction.Modify, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.Modify.handleEvent', - ol.interaction.Modify.handleEvent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.MouseWheelZoom', - ol.interaction.MouseWheelZoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.MouseWheelZoom.handleEvent', - ol.interaction.MouseWheelZoom.handleEvent, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'setMouseAnchor', - ol.interaction.MouseWheelZoom.prototype.setMouseAnchor); - -goog.exportSymbol( - 'ol.interaction.PinchRotate', - ol.interaction.PinchRotate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.PinchZoom', - ol.interaction.PinchZoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.Pointer', - ol.interaction.Pointer, - OPENLAYERS); - -goog.exportSymbol( - 'ol.interaction.Pointer.handleEvent', - ol.interaction.Pointer.handleEvent, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.SelectEvent.prototype, - 'selected', - ol.interaction.SelectEvent.prototype.selected); - -goog.exportProperty( - ol.interaction.SelectEvent.prototype, - 'deselected', - ol.interaction.SelectEvent.prototype.deselected); - -goog.exportProperty( - ol.interaction.SelectEvent.prototype, - 'mapBrowserEvent', - ol.interaction.SelectEvent.prototype.mapBrowserEvent); - -goog.exportSymbol( - 'ol.interaction.Select', - ol.interaction.Select, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'getFeatures', - ol.interaction.Select.prototype.getFeatures); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'getLayer', - ol.interaction.Select.prototype.getLayer); - -goog.exportSymbol( - 'ol.interaction.Select.handleEvent', - ol.interaction.Select.handleEvent, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'setMap', - ol.interaction.Select.prototype.setMap); - -goog.exportSymbol( - 'ol.interaction.Snap', - ol.interaction.Snap, - OPENLAYERS); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'addFeature', - ol.interaction.Snap.prototype.addFeature); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'removeFeature', - ol.interaction.Snap.prototype.removeFeature); - -goog.exportProperty( - ol.interaction.TranslateEvent.prototype, - 'features', - ol.interaction.TranslateEvent.prototype.features); - -goog.exportProperty( - ol.interaction.TranslateEvent.prototype, - 'coordinate', - ol.interaction.TranslateEvent.prototype.coordinate); - -goog.exportSymbol( - 'ol.interaction.Translate', - ol.interaction.Translate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.geom.Circle', - ol.geom.Circle, - OPENLAYERS); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'clone', - ol.geom.Circle.prototype.clone); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getCenter', - ol.geom.Circle.prototype.getCenter); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getRadius', - ol.geom.Circle.prototype.getRadius); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getType', - ol.geom.Circle.prototype.getType); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'intersectsExtent', - ol.geom.Circle.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'setCenter', - ol.geom.Circle.prototype.setCenter); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'setCenterAndRadius', - ol.geom.Circle.prototype.setCenterAndRadius); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'setRadius', - ol.geom.Circle.prototype.setRadius); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'transform', - ol.geom.Circle.prototype.transform); - -goog.exportSymbol( - 'ol.geom.Geometry', - ol.geom.Geometry, - OPENLAYERS); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'getClosestPoint', - ol.geom.Geometry.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'getExtent', - ol.geom.Geometry.prototype.getExtent); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'simplify', - ol.geom.Geometry.prototype.simplify); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'transform', - ol.geom.Geometry.prototype.transform); - -goog.exportSymbol( - 'ol.geom.GeometryCollection', - ol.geom.GeometryCollection, - OPENLAYERS); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'clone', - ol.geom.GeometryCollection.prototype.clone); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getGeometries', - ol.geom.GeometryCollection.prototype.getGeometries); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getType', - ol.geom.GeometryCollection.prototype.getType); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'intersectsExtent', - ol.geom.GeometryCollection.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'setGeometries', - ol.geom.GeometryCollection.prototype.setGeometries); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'applyTransform', - ol.geom.GeometryCollection.prototype.applyTransform); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'translate', - ol.geom.GeometryCollection.prototype.translate); - -goog.exportSymbol( - 'ol.geom.LinearRing', - ol.geom.LinearRing, - OPENLAYERS); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'clone', - ol.geom.LinearRing.prototype.clone); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getArea', - ol.geom.LinearRing.prototype.getArea); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getCoordinates', - ol.geom.LinearRing.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getType', - ol.geom.LinearRing.prototype.getType); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'setCoordinates', - ol.geom.LinearRing.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.LineString', - ol.geom.LineString, - OPENLAYERS); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'appendCoordinate', - ol.geom.LineString.prototype.appendCoordinate); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'clone', - ol.geom.LineString.prototype.clone); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'forEachSegment', - ol.geom.LineString.prototype.forEachSegment); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getCoordinateAtM', - ol.geom.LineString.prototype.getCoordinateAtM); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getCoordinates', - ol.geom.LineString.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getLength', - ol.geom.LineString.prototype.getLength); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getType', - ol.geom.LineString.prototype.getType); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'intersectsExtent', - ol.geom.LineString.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'setCoordinates', - ol.geom.LineString.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.MultiLineString', - ol.geom.MultiLineString, - OPENLAYERS); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'appendLineString', - ol.geom.MultiLineString.prototype.appendLineString); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'clone', - ol.geom.MultiLineString.prototype.clone); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getCoordinateAtM', - ol.geom.MultiLineString.prototype.getCoordinateAtM); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getCoordinates', - ol.geom.MultiLineString.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getLineString', - ol.geom.MultiLineString.prototype.getLineString); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getLineStrings', - ol.geom.MultiLineString.prototype.getLineStrings); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getType', - ol.geom.MultiLineString.prototype.getType); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'intersectsExtent', - ol.geom.MultiLineString.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'setCoordinates', - ol.geom.MultiLineString.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.MultiPoint', - ol.geom.MultiPoint, - OPENLAYERS); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'appendPoint', - ol.geom.MultiPoint.prototype.appendPoint); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'clone', - ol.geom.MultiPoint.prototype.clone); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getCoordinates', - ol.geom.MultiPoint.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getPoint', - ol.geom.MultiPoint.prototype.getPoint); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getPoints', - ol.geom.MultiPoint.prototype.getPoints); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getType', - ol.geom.MultiPoint.prototype.getType); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'intersectsExtent', - ol.geom.MultiPoint.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'setCoordinates', - ol.geom.MultiPoint.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.MultiPolygon', - ol.geom.MultiPolygon, - OPENLAYERS); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'appendPolygon', - ol.geom.MultiPolygon.prototype.appendPolygon); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'clone', - ol.geom.MultiPolygon.prototype.clone); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getArea', - ol.geom.MultiPolygon.prototype.getArea); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getCoordinates', - ol.geom.MultiPolygon.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getInteriorPoints', - ol.geom.MultiPolygon.prototype.getInteriorPoints); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getPolygon', - ol.geom.MultiPolygon.prototype.getPolygon); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getPolygons', - ol.geom.MultiPolygon.prototype.getPolygons); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getType', - ol.geom.MultiPolygon.prototype.getType); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'intersectsExtent', - ol.geom.MultiPolygon.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'setCoordinates', - ol.geom.MultiPolygon.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.Point', - ol.geom.Point, - OPENLAYERS); - -goog.exportProperty( - ol.geom.Point.prototype, - 'clone', - ol.geom.Point.prototype.clone); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getCoordinates', - ol.geom.Point.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getType', - ol.geom.Point.prototype.getType); - -goog.exportProperty( - ol.geom.Point.prototype, - 'intersectsExtent', - ol.geom.Point.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.Point.prototype, - 'setCoordinates', - ol.geom.Point.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.Polygon', - ol.geom.Polygon, - OPENLAYERS); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'appendLinearRing', - ol.geom.Polygon.prototype.appendLinearRing); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'clone', - ol.geom.Polygon.prototype.clone); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getArea', - ol.geom.Polygon.prototype.getArea); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getCoordinates', - ol.geom.Polygon.prototype.getCoordinates); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getInteriorPoint', - ol.geom.Polygon.prototype.getInteriorPoint); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getLinearRingCount', - ol.geom.Polygon.prototype.getLinearRingCount); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getLinearRing', - ol.geom.Polygon.prototype.getLinearRing); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getLinearRings', - ol.geom.Polygon.prototype.getLinearRings); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getType', - ol.geom.Polygon.prototype.getType); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'intersectsExtent', - ol.geom.Polygon.prototype.intersectsExtent); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'setCoordinates', - ol.geom.Polygon.prototype.setCoordinates); - -goog.exportSymbol( - 'ol.geom.Polygon.circular', - ol.geom.Polygon.circular, - OPENLAYERS); - -goog.exportSymbol( - 'ol.geom.Polygon.fromExtent', - ol.geom.Polygon.fromExtent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.geom.Polygon.fromCircle', - ol.geom.Polygon.fromCircle, - OPENLAYERS); - -goog.exportSymbol( - 'ol.geom.SimpleGeometry', - ol.geom.SimpleGeometry, - OPENLAYERS); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getFirstCoordinate', - ol.geom.SimpleGeometry.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getLastCoordinate', - ol.geom.SimpleGeometry.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getLayout', - ol.geom.SimpleGeometry.prototype.getLayout); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'applyTransform', - ol.geom.SimpleGeometry.prototype.applyTransform); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'translate', - ol.geom.SimpleGeometry.prototype.translate); - -goog.exportSymbol( - 'ol.format.EsriJSON', - ol.format.EsriJSON, - OPENLAYERS); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'readFeature', - ol.format.EsriJSON.prototype.readFeature); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'readFeatures', - ol.format.EsriJSON.prototype.readFeatures); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'readGeometry', - ol.format.EsriJSON.prototype.readGeometry); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'readProjection', - ol.format.EsriJSON.prototype.readProjection); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'writeGeometry', - ol.format.EsriJSON.prototype.writeGeometry); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'writeGeometryObject', - ol.format.EsriJSON.prototype.writeGeometryObject); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'writeFeature', - ol.format.EsriJSON.prototype.writeFeature); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'writeFeatureObject', - ol.format.EsriJSON.prototype.writeFeatureObject); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'writeFeatures', - ol.format.EsriJSON.prototype.writeFeatures); - -goog.exportProperty( - ol.format.EsriJSON.prototype, - 'writeFeaturesObject', - ol.format.EsriJSON.prototype.writeFeaturesObject); - -goog.exportSymbol( - 'ol.format.Feature', - ol.format.Feature, - OPENLAYERS); - -goog.exportSymbol( - 'ol.format.GeoJSON', - ol.format.GeoJSON, - OPENLAYERS); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'readFeature', - ol.format.GeoJSON.prototype.readFeature); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'readFeatures', - ol.format.GeoJSON.prototype.readFeatures); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'readGeometry', - ol.format.GeoJSON.prototype.readGeometry); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'readProjection', - ol.format.GeoJSON.prototype.readProjection); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'writeFeature', - ol.format.GeoJSON.prototype.writeFeature); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'writeFeatureObject', - ol.format.GeoJSON.prototype.writeFeatureObject); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'writeFeatures', - ol.format.GeoJSON.prototype.writeFeatures); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'writeFeaturesObject', - ol.format.GeoJSON.prototype.writeFeaturesObject); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'writeGeometry', - ol.format.GeoJSON.prototype.writeGeometry); - -goog.exportProperty( - ol.format.GeoJSON.prototype, - 'writeGeometryObject', - ol.format.GeoJSON.prototype.writeGeometryObject); - -goog.exportSymbol( - 'ol.format.GPX', - ol.format.GPX, - OPENLAYERS); - -goog.exportProperty( - ol.format.GPX.prototype, - 'readFeature', - ol.format.GPX.prototype.readFeature); - -goog.exportProperty( - ol.format.GPX.prototype, - 'readFeatures', - ol.format.GPX.prototype.readFeatures); - -goog.exportProperty( - ol.format.GPX.prototype, - 'readProjection', - ol.format.GPX.prototype.readProjection); - -goog.exportProperty( - ol.format.GPX.prototype, - 'writeFeatures', - ol.format.GPX.prototype.writeFeatures); - -goog.exportProperty( - ol.format.GPX.prototype, - 'writeFeaturesNode', - ol.format.GPX.prototype.writeFeaturesNode); - -goog.exportSymbol( - 'ol.format.IGC', - ol.format.IGC, - OPENLAYERS); - -goog.exportProperty( - ol.format.IGC.prototype, - 'readFeature', - ol.format.IGC.prototype.readFeature); - -goog.exportProperty( - ol.format.IGC.prototype, - 'readFeatures', - ol.format.IGC.prototype.readFeatures); - -goog.exportProperty( - ol.format.IGC.prototype, - 'readProjection', - ol.format.IGC.prototype.readProjection); - -goog.exportSymbol( - 'ol.format.KML', - ol.format.KML, - OPENLAYERS); - -goog.exportProperty( - ol.format.KML.prototype, - 'readFeature', - ol.format.KML.prototype.readFeature); - -goog.exportProperty( - ol.format.KML.prototype, - 'readFeatures', - ol.format.KML.prototype.readFeatures); - -goog.exportProperty( - ol.format.KML.prototype, - 'readName', - ol.format.KML.prototype.readName); - -goog.exportProperty( - ol.format.KML.prototype, - 'readNetworkLinks', - ol.format.KML.prototype.readNetworkLinks); - -goog.exportProperty( - ol.format.KML.prototype, - 'readProjection', - ol.format.KML.prototype.readProjection); - -goog.exportProperty( - ol.format.KML.prototype, - 'writeFeatures', - ol.format.KML.prototype.writeFeatures); - -goog.exportProperty( - ol.format.KML.prototype, - 'writeFeaturesNode', - ol.format.KML.prototype.writeFeaturesNode); - -goog.exportSymbol( - 'ol.format.MVT', - ol.format.MVT, - OPENLAYERS); - -goog.exportProperty( - ol.format.MVT.prototype, - 'setLayers', - ol.format.MVT.prototype.setLayers); - -goog.exportSymbol( - 'ol.format.OSMXML', - ol.format.OSMXML, - OPENLAYERS); - -goog.exportProperty( - ol.format.OSMXML.prototype, - 'readFeatures', - ol.format.OSMXML.prototype.readFeatures); - -goog.exportProperty( - ol.format.OSMXML.prototype, - 'readProjection', - ol.format.OSMXML.prototype.readProjection); - -goog.exportSymbol( - 'ol.format.Polyline', - ol.format.Polyline, - OPENLAYERS); - -goog.exportSymbol( - 'ol.format.Polyline.encodeDeltas', - ol.format.Polyline.encodeDeltas, - OPENLAYERS); - -goog.exportSymbol( - 'ol.format.Polyline.decodeDeltas', - ol.format.Polyline.decodeDeltas, - OPENLAYERS); - -goog.exportSymbol( - 'ol.format.Polyline.encodeFloats', - ol.format.Polyline.encodeFloats, - OPENLAYERS); - -goog.exportSymbol( - 'ol.format.Polyline.decodeFloats', - ol.format.Polyline.decodeFloats, - OPENLAYERS); - -goog.exportProperty( - ol.format.Polyline.prototype, - 'readFeature', - ol.format.Polyline.prototype.readFeature); - -goog.exportProperty( - ol.format.Polyline.prototype, - 'readFeatures', - ol.format.Polyline.prototype.readFeatures); - -goog.exportProperty( - ol.format.Polyline.prototype, - 'readGeometry', - ol.format.Polyline.prototype.readGeometry); - -goog.exportProperty( - ol.format.Polyline.prototype, - 'readProjection', - ol.format.Polyline.prototype.readProjection); - -goog.exportProperty( - ol.format.Polyline.prototype, - 'writeGeometry', - ol.format.Polyline.prototype.writeGeometry); - -goog.exportSymbol( - 'ol.format.TopoJSON', - ol.format.TopoJSON, - OPENLAYERS); - -goog.exportProperty( - ol.format.TopoJSON.prototype, - 'readFeatures', - ol.format.TopoJSON.prototype.readFeatures); - -goog.exportProperty( - ol.format.TopoJSON.prototype, - 'readProjection', - ol.format.TopoJSON.prototype.readProjection); - -goog.exportSymbol( - 'ol.format.WFS', - ol.format.WFS, - OPENLAYERS); - -goog.exportProperty( - ol.format.WFS.prototype, - 'readFeatures', - ol.format.WFS.prototype.readFeatures); - -goog.exportProperty( - ol.format.WFS.prototype, - 'readTransactionResponse', - ol.format.WFS.prototype.readTransactionResponse); - -goog.exportProperty( - ol.format.WFS.prototype, - 'readFeatureCollectionMetadata', - ol.format.WFS.prototype.readFeatureCollectionMetadata); - -goog.exportProperty( - ol.format.WFS.prototype, - 'writeGetFeature', - ol.format.WFS.prototype.writeGetFeature); - -goog.exportProperty( - ol.format.WFS.prototype, - 'writeTransaction', - ol.format.WFS.prototype.writeTransaction); - -goog.exportProperty( - ol.format.WFS.prototype, - 'readProjection', - ol.format.WFS.prototype.readProjection); - -goog.exportSymbol( - 'ol.format.WKT', - ol.format.WKT, - OPENLAYERS); - -goog.exportProperty( - ol.format.WKT.prototype, - 'readFeature', - ol.format.WKT.prototype.readFeature); - -goog.exportProperty( - ol.format.WKT.prototype, - 'readFeatures', - ol.format.WKT.prototype.readFeatures); - -goog.exportProperty( - ol.format.WKT.prototype, - 'readGeometry', - ol.format.WKT.prototype.readGeometry); - -goog.exportProperty( - ol.format.WKT.prototype, - 'writeFeature', - ol.format.WKT.prototype.writeFeature); - -goog.exportProperty( - ol.format.WKT.prototype, - 'writeFeatures', - ol.format.WKT.prototype.writeFeatures); - -goog.exportProperty( - ol.format.WKT.prototype, - 'writeGeometry', - ol.format.WKT.prototype.writeGeometry); - -goog.exportSymbol( - 'ol.format.WMSCapabilities', - ol.format.WMSCapabilities, - OPENLAYERS); - -goog.exportProperty( - ol.format.WMSCapabilities.prototype, - 'read', - ol.format.WMSCapabilities.prototype.read); - -goog.exportSymbol( - 'ol.format.WMSGetFeatureInfo', - ol.format.WMSGetFeatureInfo, - OPENLAYERS); - -goog.exportProperty( - ol.format.WMSGetFeatureInfo.prototype, - 'readFeatures', - ol.format.WMSGetFeatureInfo.prototype.readFeatures); - -goog.exportSymbol( - 'ol.format.WMTSCapabilities', - ol.format.WMTSCapabilities, - OPENLAYERS); - -goog.exportProperty( - ol.format.WMTSCapabilities.prototype, - 'read', - ol.format.WMTSCapabilities.prototype.read); - -goog.exportSymbol( - 'ol.format.GML2', - ol.format.GML2, - OPENLAYERS); - -goog.exportSymbol( - 'ol.format.GML3', - ol.format.GML3, - OPENLAYERS); - -goog.exportProperty( - ol.format.GML3.prototype, - 'writeGeometryNode', - ol.format.GML3.prototype.writeGeometryNode); - -goog.exportProperty( - ol.format.GML3.prototype, - 'writeFeatures', - ol.format.GML3.prototype.writeFeatures); - -goog.exportProperty( - ol.format.GML3.prototype, - 'writeFeaturesNode', - ol.format.GML3.prototype.writeFeaturesNode); - -goog.exportSymbol( - 'ol.format.GML', - ol.format.GML, - OPENLAYERS); - -goog.exportProperty( - ol.format.GML.prototype, - 'writeFeatures', - ol.format.GML.prototype.writeFeatures); - -goog.exportProperty( - ol.format.GML.prototype, - 'writeFeaturesNode', - ol.format.GML.prototype.writeFeaturesNode); - -goog.exportProperty( - ol.format.GMLBase.prototype, - 'readFeatures', - ol.format.GMLBase.prototype.readFeatures); - -goog.exportSymbol( - 'ol.events.condition.altKeyOnly', - ol.events.condition.altKeyOnly, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.altShiftKeysOnly', - ol.events.condition.altShiftKeysOnly, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.always', - ol.events.condition.always, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.click', - ol.events.condition.click, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.never', - ol.events.condition.never, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.pointerMove', - ol.events.condition.pointerMove, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.singleClick', - ol.events.condition.singleClick, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.doubleClick', - ol.events.condition.doubleClick, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.noModifierKeys', - ol.events.condition.noModifierKeys, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.platformModifierKeyOnly', - ol.events.condition.platformModifierKeyOnly, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.shiftKeyOnly', - ol.events.condition.shiftKeyOnly, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.targetNotEditable', - ol.events.condition.targetNotEditable, - OPENLAYERS); - -goog.exportSymbol( - 'ol.events.condition.mouseOnly', - ol.events.condition.mouseOnly, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.Attribution', - ol.control.Attribution, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.Attribution.render', - ol.control.Attribution.render, - OPENLAYERS); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'getCollapsible', - ol.control.Attribution.prototype.getCollapsible); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'setCollapsible', - ol.control.Attribution.prototype.setCollapsible); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'setCollapsed', - ol.control.Attribution.prototype.setCollapsed); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'getCollapsed', - ol.control.Attribution.prototype.getCollapsed); - -goog.exportSymbol( - 'ol.control.Control', - ol.control.Control, - OPENLAYERS); - -goog.exportProperty( - ol.control.Control.prototype, - 'getMap', - ol.control.Control.prototype.getMap); - -goog.exportProperty( - ol.control.Control.prototype, - 'setMap', - ol.control.Control.prototype.setMap); - -goog.exportProperty( - ol.control.Control.prototype, - 'setTarget', - ol.control.Control.prototype.setTarget); - -goog.exportSymbol( - 'ol.control.defaults', - ol.control.defaults, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.FullScreen', - ol.control.FullScreen, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.MousePosition', - ol.control.MousePosition, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.MousePosition.render', - ol.control.MousePosition.render, - OPENLAYERS); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'getCoordinateFormat', - ol.control.MousePosition.prototype.getCoordinateFormat); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'getProjection', - ol.control.MousePosition.prototype.getProjection); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'setCoordinateFormat', - ol.control.MousePosition.prototype.setCoordinateFormat); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'setProjection', - ol.control.MousePosition.prototype.setProjection); - -goog.exportSymbol( - 'ol.control.OverviewMap', - ol.control.OverviewMap, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.OverviewMap.render', - ol.control.OverviewMap.render, - OPENLAYERS); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getCollapsible', - ol.control.OverviewMap.prototype.getCollapsible); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'setCollapsible', - ol.control.OverviewMap.prototype.setCollapsible); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'setCollapsed', - ol.control.OverviewMap.prototype.setCollapsed); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getCollapsed', - ol.control.OverviewMap.prototype.getCollapsed); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getOverviewMap', - ol.control.OverviewMap.prototype.getOverviewMap); - -goog.exportSymbol( - 'ol.control.Rotate', - ol.control.Rotate, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.Rotate.render', - ol.control.Rotate.render, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.ScaleLine', - ol.control.ScaleLine, - OPENLAYERS); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'getUnits', - ol.control.ScaleLine.prototype.getUnits); - -goog.exportSymbol( - 'ol.control.ScaleLine.render', - ol.control.ScaleLine.render, - OPENLAYERS); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'setUnits', - ol.control.ScaleLine.prototype.setUnits); - -goog.exportSymbol( - 'ol.control.Zoom', - ol.control.Zoom, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.ZoomSlider', - ol.control.ZoomSlider, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.ZoomSlider.render', - ol.control.ZoomSlider.render, - OPENLAYERS); - -goog.exportSymbol( - 'ol.control.ZoomToExtent', - ol.control.ZoomToExtent, - OPENLAYERS); - -goog.exportSymbol( - 'ol.color.asArray', - ol.color.asArray, - OPENLAYERS); - -goog.exportSymbol( - 'ol.color.asString', - ol.color.asString, - OPENLAYERS); - -goog.exportProperty( - ol.Object.prototype, - 'changed', - ol.Object.prototype.changed); - -goog.exportProperty( - ol.Object.prototype, - 'dispatchEvent', - ol.Object.prototype.dispatchEvent); - -goog.exportProperty( - ol.Object.prototype, - 'getRevision', - ol.Object.prototype.getRevision); - -goog.exportProperty( - ol.Object.prototype, - 'on', - ol.Object.prototype.on); - -goog.exportProperty( - ol.Object.prototype, - 'once', - ol.Object.prototype.once); - -goog.exportProperty( - ol.Object.prototype, - 'un', - ol.Object.prototype.un); - -goog.exportProperty( - ol.Object.prototype, - 'unByKey', - ol.Object.prototype.unByKey); - -goog.exportProperty( - ol.Collection.prototype, - 'get', - ol.Collection.prototype.get); - -goog.exportProperty( - ol.Collection.prototype, - 'getKeys', - ol.Collection.prototype.getKeys); - -goog.exportProperty( - ol.Collection.prototype, - 'getProperties', - ol.Collection.prototype.getProperties); - -goog.exportProperty( - ol.Collection.prototype, - 'set', - ol.Collection.prototype.set); - -goog.exportProperty( - ol.Collection.prototype, - 'setProperties', - ol.Collection.prototype.setProperties); - -goog.exportProperty( - ol.Collection.prototype, - 'unset', - ol.Collection.prototype.unset); - -goog.exportProperty( - ol.Collection.prototype, - 'changed', - ol.Collection.prototype.changed); - -goog.exportProperty( - ol.Collection.prototype, - 'dispatchEvent', - ol.Collection.prototype.dispatchEvent); - -goog.exportProperty( - ol.Collection.prototype, - 'getRevision', - ol.Collection.prototype.getRevision); - -goog.exportProperty( - ol.Collection.prototype, - 'on', - ol.Collection.prototype.on); - -goog.exportProperty( - ol.Collection.prototype, - 'once', - ol.Collection.prototype.once); - -goog.exportProperty( - ol.Collection.prototype, - 'un', - ol.Collection.prototype.un); - -goog.exportProperty( - ol.Collection.prototype, - 'unByKey', - ol.Collection.prototype.unByKey); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'get', - ol.DeviceOrientation.prototype.get); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getKeys', - ol.DeviceOrientation.prototype.getKeys); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getProperties', - ol.DeviceOrientation.prototype.getProperties); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'set', - ol.DeviceOrientation.prototype.set); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'setProperties', - ol.DeviceOrientation.prototype.setProperties); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'unset', - ol.DeviceOrientation.prototype.unset); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'changed', - ol.DeviceOrientation.prototype.changed); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'dispatchEvent', - ol.DeviceOrientation.prototype.dispatchEvent); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'getRevision', - ol.DeviceOrientation.prototype.getRevision); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'on', - ol.DeviceOrientation.prototype.on); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'once', - ol.DeviceOrientation.prototype.once); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'un', - ol.DeviceOrientation.prototype.un); - -goog.exportProperty( - ol.DeviceOrientation.prototype, - 'unByKey', - ol.DeviceOrientation.prototype.unByKey); - -goog.exportProperty( - ol.Feature.prototype, - 'get', - ol.Feature.prototype.get); - -goog.exportProperty( - ol.Feature.prototype, - 'getKeys', - ol.Feature.prototype.getKeys); - -goog.exportProperty( - ol.Feature.prototype, - 'getProperties', - ol.Feature.prototype.getProperties); - -goog.exportProperty( - ol.Feature.prototype, - 'set', - ol.Feature.prototype.set); - -goog.exportProperty( - ol.Feature.prototype, - 'setProperties', - ol.Feature.prototype.setProperties); - -goog.exportProperty( - ol.Feature.prototype, - 'unset', - ol.Feature.prototype.unset); - -goog.exportProperty( - ol.Feature.prototype, - 'changed', - ol.Feature.prototype.changed); - -goog.exportProperty( - ol.Feature.prototype, - 'dispatchEvent', - ol.Feature.prototype.dispatchEvent); - -goog.exportProperty( - ol.Feature.prototype, - 'getRevision', - ol.Feature.prototype.getRevision); - -goog.exportProperty( - ol.Feature.prototype, - 'on', - ol.Feature.prototype.on); - -goog.exportProperty( - ol.Feature.prototype, - 'once', - ol.Feature.prototype.once); - -goog.exportProperty( - ol.Feature.prototype, - 'un', - ol.Feature.prototype.un); - -goog.exportProperty( - ol.Feature.prototype, - 'unByKey', - ol.Feature.prototype.unByKey); - -goog.exportProperty( - ol.Geolocation.prototype, - 'get', - ol.Geolocation.prototype.get); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getKeys', - ol.Geolocation.prototype.getKeys); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getProperties', - ol.Geolocation.prototype.getProperties); - -goog.exportProperty( - ol.Geolocation.prototype, - 'set', - ol.Geolocation.prototype.set); - -goog.exportProperty( - ol.Geolocation.prototype, - 'setProperties', - ol.Geolocation.prototype.setProperties); - -goog.exportProperty( - ol.Geolocation.prototype, - 'unset', - ol.Geolocation.prototype.unset); - -goog.exportProperty( - ol.Geolocation.prototype, - 'changed', - ol.Geolocation.prototype.changed); - -goog.exportProperty( - ol.Geolocation.prototype, - 'dispatchEvent', - ol.Geolocation.prototype.dispatchEvent); - -goog.exportProperty( - ol.Geolocation.prototype, - 'getRevision', - ol.Geolocation.prototype.getRevision); - -goog.exportProperty( - ol.Geolocation.prototype, - 'on', - ol.Geolocation.prototype.on); - -goog.exportProperty( - ol.Geolocation.prototype, - 'once', - ol.Geolocation.prototype.once); - -goog.exportProperty( - ol.Geolocation.prototype, - 'un', - ol.Geolocation.prototype.un); - -goog.exportProperty( - ol.Geolocation.prototype, - 'unByKey', - ol.Geolocation.prototype.unByKey); - -goog.exportProperty( - ol.ImageTile.prototype, - 'getTileCoord', - ol.ImageTile.prototype.getTileCoord); - -goog.exportProperty( - ol.Map.prototype, - 'get', - ol.Map.prototype.get); - -goog.exportProperty( - ol.Map.prototype, - 'getKeys', - ol.Map.prototype.getKeys); - -goog.exportProperty( - ol.Map.prototype, - 'getProperties', - ol.Map.prototype.getProperties); - -goog.exportProperty( - ol.Map.prototype, - 'set', - ol.Map.prototype.set); - -goog.exportProperty( - ol.Map.prototype, - 'setProperties', - ol.Map.prototype.setProperties); - -goog.exportProperty( - ol.Map.prototype, - 'unset', - ol.Map.prototype.unset); - -goog.exportProperty( - ol.Map.prototype, - 'changed', - ol.Map.prototype.changed); - -goog.exportProperty( - ol.Map.prototype, - 'dispatchEvent', - ol.Map.prototype.dispatchEvent); - -goog.exportProperty( - ol.Map.prototype, - 'getRevision', - ol.Map.prototype.getRevision); - -goog.exportProperty( - ol.Map.prototype, - 'on', - ol.Map.prototype.on); - -goog.exportProperty( - ol.Map.prototype, - 'once', - ol.Map.prototype.once); - -goog.exportProperty( - ol.Map.prototype, - 'un', - ol.Map.prototype.un); - -goog.exportProperty( - ol.Map.prototype, - 'unByKey', - ol.Map.prototype.unByKey); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'map', - ol.MapBrowserEvent.prototype.map); - -goog.exportProperty( - ol.MapBrowserEvent.prototype, - 'frameState', - ol.MapBrowserEvent.prototype.frameState); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'originalEvent', - ol.MapBrowserPointerEvent.prototype.originalEvent); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'pixel', - ol.MapBrowserPointerEvent.prototype.pixel); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'coordinate', - ol.MapBrowserPointerEvent.prototype.coordinate); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'dragging', - ol.MapBrowserPointerEvent.prototype.dragging); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'preventDefault', - ol.MapBrowserPointerEvent.prototype.preventDefault); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'stopPropagation', - ol.MapBrowserPointerEvent.prototype.stopPropagation); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'map', - ol.MapBrowserPointerEvent.prototype.map); - -goog.exportProperty( - ol.MapBrowserPointerEvent.prototype, - 'frameState', - ol.MapBrowserPointerEvent.prototype.frameState); - -goog.exportProperty( - ol.Overlay.prototype, - 'get', - ol.Overlay.prototype.get); - -goog.exportProperty( - ol.Overlay.prototype, - 'getKeys', - ol.Overlay.prototype.getKeys); - -goog.exportProperty( - ol.Overlay.prototype, - 'getProperties', - ol.Overlay.prototype.getProperties); - -goog.exportProperty( - ol.Overlay.prototype, - 'set', - ol.Overlay.prototype.set); - -goog.exportProperty( - ol.Overlay.prototype, - 'setProperties', - ol.Overlay.prototype.setProperties); - -goog.exportProperty( - ol.Overlay.prototype, - 'unset', - ol.Overlay.prototype.unset); - -goog.exportProperty( - ol.Overlay.prototype, - 'changed', - ol.Overlay.prototype.changed); - -goog.exportProperty( - ol.Overlay.prototype, - 'dispatchEvent', - ol.Overlay.prototype.dispatchEvent); - -goog.exportProperty( - ol.Overlay.prototype, - 'getRevision', - ol.Overlay.prototype.getRevision); - -goog.exportProperty( - ol.Overlay.prototype, - 'on', - ol.Overlay.prototype.on); - -goog.exportProperty( - ol.Overlay.prototype, - 'once', - ol.Overlay.prototype.once); - -goog.exportProperty( - ol.Overlay.prototype, - 'un', - ol.Overlay.prototype.un); - -goog.exportProperty( - ol.Overlay.prototype, - 'unByKey', - ol.Overlay.prototype.unByKey); - -goog.exportProperty( - ol.VectorTile.prototype, - 'getTileCoord', - ol.VectorTile.prototype.getTileCoord); - -goog.exportProperty( - ol.View.prototype, - 'get', - ol.View.prototype.get); - -goog.exportProperty( - ol.View.prototype, - 'getKeys', - ol.View.prototype.getKeys); - -goog.exportProperty( - ol.View.prototype, - 'getProperties', - ol.View.prototype.getProperties); - -goog.exportProperty( - ol.View.prototype, - 'set', - ol.View.prototype.set); - -goog.exportProperty( - ol.View.prototype, - 'setProperties', - ol.View.prototype.setProperties); - -goog.exportProperty( - ol.View.prototype, - 'unset', - ol.View.prototype.unset); - -goog.exportProperty( - ol.View.prototype, - 'changed', - ol.View.prototype.changed); - -goog.exportProperty( - ol.View.prototype, - 'dispatchEvent', - ol.View.prototype.dispatchEvent); - -goog.exportProperty( - ol.View.prototype, - 'getRevision', - ol.View.prototype.getRevision); - -goog.exportProperty( - ol.View.prototype, - 'on', - ol.View.prototype.on); - -goog.exportProperty( - ol.View.prototype, - 'once', - ol.View.prototype.once); - -goog.exportProperty( - ol.View.prototype, - 'un', - ol.View.prototype.un); - -goog.exportProperty( - ol.View.prototype, - 'unByKey', - ol.View.prototype.unByKey); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getMaxZoom', - ol.tilegrid.WMTS.prototype.getMaxZoom); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getMinZoom', - ol.tilegrid.WMTS.prototype.getMinZoom); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getOrigin', - ol.tilegrid.WMTS.prototype.getOrigin); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getResolution', - ol.tilegrid.WMTS.prototype.getResolution); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getResolutions', - ol.tilegrid.WMTS.prototype.getResolutions); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getTileCoordExtent', - ol.tilegrid.WMTS.prototype.getTileCoordExtent); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getTileCoordForCoordAndResolution', - ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndResolution); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getTileCoordForCoordAndZ', - ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndZ); - -goog.exportProperty( - ol.tilegrid.WMTS.prototype, - 'getTileSize', - ol.tilegrid.WMTS.prototype.getTileSize); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getOpacity', - ol.style.Circle.prototype.getOpacity); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getRotateWithView', - ol.style.Circle.prototype.getRotateWithView); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getRotation', - ol.style.Circle.prototype.getRotation); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getScale', - ol.style.Circle.prototype.getScale); - -goog.exportProperty( - ol.style.Circle.prototype, - 'getSnapToPixel', - ol.style.Circle.prototype.getSnapToPixel); - -goog.exportProperty( - ol.style.Circle.prototype, - 'setOpacity', - ol.style.Circle.prototype.setOpacity); - -goog.exportProperty( - ol.style.Circle.prototype, - 'setRotation', - ol.style.Circle.prototype.setRotation); - -goog.exportProperty( - ol.style.Circle.prototype, - 'setScale', - ol.style.Circle.prototype.setScale); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getOpacity', - ol.style.Icon.prototype.getOpacity); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getRotateWithView', - ol.style.Icon.prototype.getRotateWithView); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getRotation', - ol.style.Icon.prototype.getRotation); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getScale', - ol.style.Icon.prototype.getScale); - -goog.exportProperty( - ol.style.Icon.prototype, - 'getSnapToPixel', - ol.style.Icon.prototype.getSnapToPixel); - -goog.exportProperty( - ol.style.Icon.prototype, - 'setOpacity', - ol.style.Icon.prototype.setOpacity); - -goog.exportProperty( - ol.style.Icon.prototype, - 'setRotation', - ol.style.Icon.prototype.setRotation); - -goog.exportProperty( - ol.style.Icon.prototype, - 'setScale', - ol.style.Icon.prototype.setScale); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getOpacity', - ol.style.RegularShape.prototype.getOpacity); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getRotateWithView', - ol.style.RegularShape.prototype.getRotateWithView); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getRotation', - ol.style.RegularShape.prototype.getRotation); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getScale', - ol.style.RegularShape.prototype.getScale); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'getSnapToPixel', - ol.style.RegularShape.prototype.getSnapToPixel); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'setOpacity', - ol.style.RegularShape.prototype.setOpacity); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'setRotation', - ol.style.RegularShape.prototype.setRotation); - -goog.exportProperty( - ol.style.RegularShape.prototype, - 'setScale', - ol.style.RegularShape.prototype.setScale); - -goog.exportProperty( - ol.source.Source.prototype, - 'get', - ol.source.Source.prototype.get); - -goog.exportProperty( - ol.source.Source.prototype, - 'getKeys', - ol.source.Source.prototype.getKeys); - -goog.exportProperty( - ol.source.Source.prototype, - 'getProperties', - ol.source.Source.prototype.getProperties); - -goog.exportProperty( - ol.source.Source.prototype, - 'set', - ol.source.Source.prototype.set); - -goog.exportProperty( - ol.source.Source.prototype, - 'setProperties', - ol.source.Source.prototype.setProperties); - -goog.exportProperty( - ol.source.Source.prototype, - 'unset', - ol.source.Source.prototype.unset); - -goog.exportProperty( - ol.source.Source.prototype, - 'changed', - ol.source.Source.prototype.changed); - -goog.exportProperty( - ol.source.Source.prototype, - 'dispatchEvent', - ol.source.Source.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Source.prototype, - 'getRevision', - ol.source.Source.prototype.getRevision); - -goog.exportProperty( - ol.source.Source.prototype, - 'on', - ol.source.Source.prototype.on); - -goog.exportProperty( - ol.source.Source.prototype, - 'once', - ol.source.Source.prototype.once); - -goog.exportProperty( - ol.source.Source.prototype, - 'un', - ol.source.Source.prototype.un); - -goog.exportProperty( - ol.source.Source.prototype, - 'unByKey', - ol.source.Source.prototype.unByKey); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getAttributions', - ol.source.Tile.prototype.getAttributions); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getLogo', - ol.source.Tile.prototype.getLogo); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getProjection', - ol.source.Tile.prototype.getProjection); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getState', - ol.source.Tile.prototype.getState); - -goog.exportProperty( - ol.source.Tile.prototype, - 'setAttributions', - ol.source.Tile.prototype.setAttributions); - -goog.exportProperty( - ol.source.Tile.prototype, - 'get', - ol.source.Tile.prototype.get); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getKeys', - ol.source.Tile.prototype.getKeys); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getProperties', - ol.source.Tile.prototype.getProperties); - -goog.exportProperty( - ol.source.Tile.prototype, - 'set', - ol.source.Tile.prototype.set); - -goog.exportProperty( - ol.source.Tile.prototype, - 'setProperties', - ol.source.Tile.prototype.setProperties); - -goog.exportProperty( - ol.source.Tile.prototype, - 'unset', - ol.source.Tile.prototype.unset); - -goog.exportProperty( - ol.source.Tile.prototype, - 'changed', - ol.source.Tile.prototype.changed); - -goog.exportProperty( - ol.source.Tile.prototype, - 'dispatchEvent', - ol.source.Tile.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Tile.prototype, - 'getRevision', - ol.source.Tile.prototype.getRevision); - -goog.exportProperty( - ol.source.Tile.prototype, - 'on', - ol.source.Tile.prototype.on); - -goog.exportProperty( - ol.source.Tile.prototype, - 'once', - ol.source.Tile.prototype.once); - -goog.exportProperty( - ol.source.Tile.prototype, - 'un', - ol.source.Tile.prototype.un); - -goog.exportProperty( - ol.source.Tile.prototype, - 'unByKey', - ol.source.Tile.prototype.unByKey); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getTileGrid', - ol.source.UrlTile.prototype.getTileGrid); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getAttributions', - ol.source.UrlTile.prototype.getAttributions); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getLogo', - ol.source.UrlTile.prototype.getLogo); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getProjection', - ol.source.UrlTile.prototype.getProjection); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getState', - ol.source.UrlTile.prototype.getState); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'setAttributions', - ol.source.UrlTile.prototype.setAttributions); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'get', - ol.source.UrlTile.prototype.get); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getKeys', - ol.source.UrlTile.prototype.getKeys); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getProperties', - ol.source.UrlTile.prototype.getProperties); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'set', - ol.source.UrlTile.prototype.set); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'setProperties', - ol.source.UrlTile.prototype.setProperties); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'unset', - ol.source.UrlTile.prototype.unset); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'changed', - ol.source.UrlTile.prototype.changed); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'dispatchEvent', - ol.source.UrlTile.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'getRevision', - ol.source.UrlTile.prototype.getRevision); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'on', - ol.source.UrlTile.prototype.on); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'once', - ol.source.UrlTile.prototype.once); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'un', - ol.source.UrlTile.prototype.un); - -goog.exportProperty( - ol.source.UrlTile.prototype, - 'unByKey', - ol.source.UrlTile.prototype.unByKey); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getTileLoadFunction', - ol.source.TileImage.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getTileUrlFunction', - ol.source.TileImage.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getUrls', - ol.source.TileImage.prototype.getUrls); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setTileLoadFunction', - ol.source.TileImage.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setTileUrlFunction', - ol.source.TileImage.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setUrl', - ol.source.TileImage.prototype.setUrl); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setUrls', - ol.source.TileImage.prototype.setUrls); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getTileGrid', - ol.source.TileImage.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getAttributions', - ol.source.TileImage.prototype.getAttributions); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getLogo', - ol.source.TileImage.prototype.getLogo); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getProjection', - ol.source.TileImage.prototype.getProjection); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getState', - ol.source.TileImage.prototype.getState); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setAttributions', - ol.source.TileImage.prototype.setAttributions); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'get', - ol.source.TileImage.prototype.get); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getKeys', - ol.source.TileImage.prototype.getKeys); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getProperties', - ol.source.TileImage.prototype.getProperties); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'set', - ol.source.TileImage.prototype.set); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'setProperties', - ol.source.TileImage.prototype.setProperties); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'unset', - ol.source.TileImage.prototype.unset); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'changed', - ol.source.TileImage.prototype.changed); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'dispatchEvent', - ol.source.TileImage.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'getRevision', - ol.source.TileImage.prototype.getRevision); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'on', - ol.source.TileImage.prototype.on); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'once', - ol.source.TileImage.prototype.once); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'un', - ol.source.TileImage.prototype.un); - -goog.exportProperty( - ol.source.TileImage.prototype, - 'unByKey', - ol.source.TileImage.prototype.unByKey); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setRenderReprojectionEdges', - ol.source.BingMaps.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setTileGridForProjection', - ol.source.BingMaps.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getTileLoadFunction', - ol.source.BingMaps.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getTileUrlFunction', - ol.source.BingMaps.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getUrls', - ol.source.BingMaps.prototype.getUrls); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setTileLoadFunction', - ol.source.BingMaps.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setTileUrlFunction', - ol.source.BingMaps.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setUrl', - ol.source.BingMaps.prototype.setUrl); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setUrls', - ol.source.BingMaps.prototype.setUrls); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getTileGrid', - ol.source.BingMaps.prototype.getTileGrid); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getAttributions', - ol.source.BingMaps.prototype.getAttributions); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getLogo', - ol.source.BingMaps.prototype.getLogo); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getProjection', - ol.source.BingMaps.prototype.getProjection); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getState', - ol.source.BingMaps.prototype.getState); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setAttributions', - ol.source.BingMaps.prototype.setAttributions); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'get', - ol.source.BingMaps.prototype.get); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getKeys', - ol.source.BingMaps.prototype.getKeys); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getProperties', - ol.source.BingMaps.prototype.getProperties); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'set', - ol.source.BingMaps.prototype.set); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'setProperties', - ol.source.BingMaps.prototype.setProperties); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'unset', - ol.source.BingMaps.prototype.unset); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'changed', - ol.source.BingMaps.prototype.changed); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'dispatchEvent', - ol.source.BingMaps.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'getRevision', - ol.source.BingMaps.prototype.getRevision); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'on', - ol.source.BingMaps.prototype.on); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'once', - ol.source.BingMaps.prototype.once); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'un', - ol.source.BingMaps.prototype.un); - -goog.exportProperty( - ol.source.BingMaps.prototype, - 'unByKey', - ol.source.BingMaps.prototype.unByKey); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getAttributions', - ol.source.Vector.prototype.getAttributions); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getLogo', - ol.source.Vector.prototype.getLogo); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getProjection', - ol.source.Vector.prototype.getProjection); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getState', - ol.source.Vector.prototype.getState); - -goog.exportProperty( - ol.source.Vector.prototype, - 'setAttributions', - ol.source.Vector.prototype.setAttributions); - -goog.exportProperty( - ol.source.Vector.prototype, - 'get', - ol.source.Vector.prototype.get); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getKeys', - ol.source.Vector.prototype.getKeys); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getProperties', - ol.source.Vector.prototype.getProperties); - -goog.exportProperty( - ol.source.Vector.prototype, - 'set', - ol.source.Vector.prototype.set); - -goog.exportProperty( - ol.source.Vector.prototype, - 'setProperties', - ol.source.Vector.prototype.setProperties); - -goog.exportProperty( - ol.source.Vector.prototype, - 'unset', - ol.source.Vector.prototype.unset); - -goog.exportProperty( - ol.source.Vector.prototype, - 'changed', - ol.source.Vector.prototype.changed); - -goog.exportProperty( - ol.source.Vector.prototype, - 'dispatchEvent', - ol.source.Vector.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Vector.prototype, - 'getRevision', - ol.source.Vector.prototype.getRevision); - -goog.exportProperty( - ol.source.Vector.prototype, - 'on', - ol.source.Vector.prototype.on); - -goog.exportProperty( - ol.source.Vector.prototype, - 'once', - ol.source.Vector.prototype.once); - -goog.exportProperty( - ol.source.Vector.prototype, - 'un', - ol.source.Vector.prototype.un); - -goog.exportProperty( - ol.source.Vector.prototype, - 'unByKey', - ol.source.Vector.prototype.unByKey); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'addFeature', - ol.source.Cluster.prototype.addFeature); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'addFeatures', - ol.source.Cluster.prototype.addFeatures); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'clear', - ol.source.Cluster.prototype.clear); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'forEachFeature', - ol.source.Cluster.prototype.forEachFeature); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'forEachFeatureInExtent', - ol.source.Cluster.prototype.forEachFeatureInExtent); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'forEachFeatureIntersectingExtent', - ol.source.Cluster.prototype.forEachFeatureIntersectingExtent); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getFeaturesCollection', - ol.source.Cluster.prototype.getFeaturesCollection); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getFeatures', - ol.source.Cluster.prototype.getFeatures); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getFeaturesAtCoordinate', - ol.source.Cluster.prototype.getFeaturesAtCoordinate); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getFeaturesInExtent', - ol.source.Cluster.prototype.getFeaturesInExtent); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getClosestFeatureToCoordinate', - ol.source.Cluster.prototype.getClosestFeatureToCoordinate); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getExtent', - ol.source.Cluster.prototype.getExtent); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getFeatureById', - ol.source.Cluster.prototype.getFeatureById); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'removeFeature', - ol.source.Cluster.prototype.removeFeature); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getAttributions', - ol.source.Cluster.prototype.getAttributions); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getLogo', - ol.source.Cluster.prototype.getLogo); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getProjection', - ol.source.Cluster.prototype.getProjection); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getState', - ol.source.Cluster.prototype.getState); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'setAttributions', - ol.source.Cluster.prototype.setAttributions); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'get', - ol.source.Cluster.prototype.get); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getKeys', - ol.source.Cluster.prototype.getKeys); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getProperties', - ol.source.Cluster.prototype.getProperties); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'set', - ol.source.Cluster.prototype.set); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'setProperties', - ol.source.Cluster.prototype.setProperties); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'unset', - ol.source.Cluster.prototype.unset); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'changed', - ol.source.Cluster.prototype.changed); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'dispatchEvent', - ol.source.Cluster.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'getRevision', - ol.source.Cluster.prototype.getRevision); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'on', - ol.source.Cluster.prototype.on); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'once', - ol.source.Cluster.prototype.once); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'un', - ol.source.Cluster.prototype.un); - -goog.exportProperty( - ol.source.Cluster.prototype, - 'unByKey', - ol.source.Cluster.prototype.unByKey); - -goog.exportProperty( - ol.source.Image.prototype, - 'getAttributions', - ol.source.Image.prototype.getAttributions); - -goog.exportProperty( - ol.source.Image.prototype, - 'getLogo', - ol.source.Image.prototype.getLogo); - -goog.exportProperty( - ol.source.Image.prototype, - 'getProjection', - ol.source.Image.prototype.getProjection); - -goog.exportProperty( - ol.source.Image.prototype, - 'getState', - ol.source.Image.prototype.getState); - -goog.exportProperty( - ol.source.Image.prototype, - 'setAttributions', - ol.source.Image.prototype.setAttributions); - -goog.exportProperty( - ol.source.Image.prototype, - 'get', - ol.source.Image.prototype.get); - -goog.exportProperty( - ol.source.Image.prototype, - 'getKeys', - ol.source.Image.prototype.getKeys); - -goog.exportProperty( - ol.source.Image.prototype, - 'getProperties', - ol.source.Image.prototype.getProperties); - -goog.exportProperty( - ol.source.Image.prototype, - 'set', - ol.source.Image.prototype.set); - -goog.exportProperty( - ol.source.Image.prototype, - 'setProperties', - ol.source.Image.prototype.setProperties); - -goog.exportProperty( - ol.source.Image.prototype, - 'unset', - ol.source.Image.prototype.unset); - -goog.exportProperty( - ol.source.Image.prototype, - 'changed', - ol.source.Image.prototype.changed); - -goog.exportProperty( - ol.source.Image.prototype, - 'dispatchEvent', - ol.source.Image.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Image.prototype, - 'getRevision', - ol.source.Image.prototype.getRevision); - -goog.exportProperty( - ol.source.Image.prototype, - 'on', - ol.source.Image.prototype.on); - -goog.exportProperty( - ol.source.Image.prototype, - 'once', - ol.source.Image.prototype.once); - -goog.exportProperty( - ol.source.Image.prototype, - 'un', - ol.source.Image.prototype.un); - -goog.exportProperty( - ol.source.Image.prototype, - 'unByKey', - ol.source.Image.prototype.unByKey); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getAttributions', - ol.source.ImageCanvas.prototype.getAttributions); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getLogo', - ol.source.ImageCanvas.prototype.getLogo); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getProjection', - ol.source.ImageCanvas.prototype.getProjection); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getState', - ol.source.ImageCanvas.prototype.getState); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'setAttributions', - ol.source.ImageCanvas.prototype.setAttributions); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'get', - ol.source.ImageCanvas.prototype.get); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getKeys', - ol.source.ImageCanvas.prototype.getKeys); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getProperties', - ol.source.ImageCanvas.prototype.getProperties); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'set', - ol.source.ImageCanvas.prototype.set); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'setProperties', - ol.source.ImageCanvas.prototype.setProperties); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'unset', - ol.source.ImageCanvas.prototype.unset); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'changed', - ol.source.ImageCanvas.prototype.changed); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'dispatchEvent', - ol.source.ImageCanvas.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'getRevision', - ol.source.ImageCanvas.prototype.getRevision); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'on', - ol.source.ImageCanvas.prototype.on); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'once', - ol.source.ImageCanvas.prototype.once); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'un', - ol.source.ImageCanvas.prototype.un); - -goog.exportProperty( - ol.source.ImageCanvas.prototype, - 'unByKey', - ol.source.ImageCanvas.prototype.unByKey); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getAttributions', - ol.source.ImageMapGuide.prototype.getAttributions); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getLogo', - ol.source.ImageMapGuide.prototype.getLogo); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getProjection', - ol.source.ImageMapGuide.prototype.getProjection); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getState', - ol.source.ImageMapGuide.prototype.getState); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'setAttributions', - ol.source.ImageMapGuide.prototype.setAttributions); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'get', - ol.source.ImageMapGuide.prototype.get); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getKeys', - ol.source.ImageMapGuide.prototype.getKeys); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getProperties', - ol.source.ImageMapGuide.prototype.getProperties); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'set', - ol.source.ImageMapGuide.prototype.set); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'setProperties', - ol.source.ImageMapGuide.prototype.setProperties); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'unset', - ol.source.ImageMapGuide.prototype.unset); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'changed', - ol.source.ImageMapGuide.prototype.changed); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'dispatchEvent', - ol.source.ImageMapGuide.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'getRevision', - ol.source.ImageMapGuide.prototype.getRevision); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'on', - ol.source.ImageMapGuide.prototype.on); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'once', - ol.source.ImageMapGuide.prototype.once); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'un', - ol.source.ImageMapGuide.prototype.un); - -goog.exportProperty( - ol.source.ImageMapGuide.prototype, - 'unByKey', - ol.source.ImageMapGuide.prototype.unByKey); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getAttributions', - ol.source.ImageStatic.prototype.getAttributions); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getLogo', - ol.source.ImageStatic.prototype.getLogo); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getProjection', - ol.source.ImageStatic.prototype.getProjection); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getState', - ol.source.ImageStatic.prototype.getState); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'setAttributions', - ol.source.ImageStatic.prototype.setAttributions); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'get', - ol.source.ImageStatic.prototype.get); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getKeys', - ol.source.ImageStatic.prototype.getKeys); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getProperties', - ol.source.ImageStatic.prototype.getProperties); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'set', - ol.source.ImageStatic.prototype.set); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'setProperties', - ol.source.ImageStatic.prototype.setProperties); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'unset', - ol.source.ImageStatic.prototype.unset); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'changed', - ol.source.ImageStatic.prototype.changed); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'dispatchEvent', - ol.source.ImageStatic.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'getRevision', - ol.source.ImageStatic.prototype.getRevision); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'on', - ol.source.ImageStatic.prototype.on); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'once', - ol.source.ImageStatic.prototype.once); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'un', - ol.source.ImageStatic.prototype.un); - -goog.exportProperty( - ol.source.ImageStatic.prototype, - 'unByKey', - ol.source.ImageStatic.prototype.unByKey); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getAttributions', - ol.source.ImageVector.prototype.getAttributions); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getLogo', - ol.source.ImageVector.prototype.getLogo); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getProjection', - ol.source.ImageVector.prototype.getProjection); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getState', - ol.source.ImageVector.prototype.getState); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'setAttributions', - ol.source.ImageVector.prototype.setAttributions); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'get', - ol.source.ImageVector.prototype.get); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getKeys', - ol.source.ImageVector.prototype.getKeys); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getProperties', - ol.source.ImageVector.prototype.getProperties); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'set', - ol.source.ImageVector.prototype.set); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'setProperties', - ol.source.ImageVector.prototype.setProperties); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'unset', - ol.source.ImageVector.prototype.unset); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'changed', - ol.source.ImageVector.prototype.changed); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'dispatchEvent', - ol.source.ImageVector.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'getRevision', - ol.source.ImageVector.prototype.getRevision); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'on', - ol.source.ImageVector.prototype.on); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'once', - ol.source.ImageVector.prototype.once); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'un', - ol.source.ImageVector.prototype.un); - -goog.exportProperty( - ol.source.ImageVector.prototype, - 'unByKey', - ol.source.ImageVector.prototype.unByKey); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getAttributions', - ol.source.ImageWMS.prototype.getAttributions); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getLogo', - ol.source.ImageWMS.prototype.getLogo); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getProjection', - ol.source.ImageWMS.prototype.getProjection); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getState', - ol.source.ImageWMS.prototype.getState); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'setAttributions', - ol.source.ImageWMS.prototype.setAttributions); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'get', - ol.source.ImageWMS.prototype.get); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getKeys', - ol.source.ImageWMS.prototype.getKeys); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getProperties', - ol.source.ImageWMS.prototype.getProperties); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'set', - ol.source.ImageWMS.prototype.set); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'setProperties', - ol.source.ImageWMS.prototype.setProperties); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'unset', - ol.source.ImageWMS.prototype.unset); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'changed', - ol.source.ImageWMS.prototype.changed); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'dispatchEvent', - ol.source.ImageWMS.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'getRevision', - ol.source.ImageWMS.prototype.getRevision); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'on', - ol.source.ImageWMS.prototype.on); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'once', - ol.source.ImageWMS.prototype.once); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'un', - ol.source.ImageWMS.prototype.un); - -goog.exportProperty( - ol.source.ImageWMS.prototype, - 'unByKey', - ol.source.ImageWMS.prototype.unByKey); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setRenderReprojectionEdges', - ol.source.XYZ.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setTileGridForProjection', - ol.source.XYZ.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getTileLoadFunction', - ol.source.XYZ.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getTileUrlFunction', - ol.source.XYZ.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getUrls', - ol.source.XYZ.prototype.getUrls); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setTileLoadFunction', - ol.source.XYZ.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setTileUrlFunction', - ol.source.XYZ.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setUrl', - ol.source.XYZ.prototype.setUrl); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setUrls', - ol.source.XYZ.prototype.setUrls); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getTileGrid', - ol.source.XYZ.prototype.getTileGrid); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getAttributions', - ol.source.XYZ.prototype.getAttributions); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getLogo', - ol.source.XYZ.prototype.getLogo); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getProjection', - ol.source.XYZ.prototype.getProjection); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getState', - ol.source.XYZ.prototype.getState); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setAttributions', - ol.source.XYZ.prototype.setAttributions); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'get', - ol.source.XYZ.prototype.get); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getKeys', - ol.source.XYZ.prototype.getKeys); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getProperties', - ol.source.XYZ.prototype.getProperties); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'set', - ol.source.XYZ.prototype.set); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'setProperties', - ol.source.XYZ.prototype.setProperties); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'unset', - ol.source.XYZ.prototype.unset); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'changed', - ol.source.XYZ.prototype.changed); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'dispatchEvent', - ol.source.XYZ.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'getRevision', - ol.source.XYZ.prototype.getRevision); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'on', - ol.source.XYZ.prototype.on); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'once', - ol.source.XYZ.prototype.once); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'un', - ol.source.XYZ.prototype.un); - -goog.exportProperty( - ol.source.XYZ.prototype, - 'unByKey', - ol.source.XYZ.prototype.unByKey); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setRenderReprojectionEdges', - ol.source.MapQuest.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setTileGridForProjection', - ol.source.MapQuest.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getTileLoadFunction', - ol.source.MapQuest.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getTileUrlFunction', - ol.source.MapQuest.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getUrls', - ol.source.MapQuest.prototype.getUrls); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setTileLoadFunction', - ol.source.MapQuest.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setTileUrlFunction', - ol.source.MapQuest.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setUrl', - ol.source.MapQuest.prototype.setUrl); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setUrls', - ol.source.MapQuest.prototype.setUrls); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getTileGrid', - ol.source.MapQuest.prototype.getTileGrid); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getAttributions', - ol.source.MapQuest.prototype.getAttributions); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getLogo', - ol.source.MapQuest.prototype.getLogo); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getProjection', - ol.source.MapQuest.prototype.getProjection); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getState', - ol.source.MapQuest.prototype.getState); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setAttributions', - ol.source.MapQuest.prototype.setAttributions); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'get', - ol.source.MapQuest.prototype.get); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getKeys', - ol.source.MapQuest.prototype.getKeys); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getProperties', - ol.source.MapQuest.prototype.getProperties); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'set', - ol.source.MapQuest.prototype.set); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'setProperties', - ol.source.MapQuest.prototype.setProperties); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'unset', - ol.source.MapQuest.prototype.unset); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'changed', - ol.source.MapQuest.prototype.changed); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'dispatchEvent', - ol.source.MapQuest.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'getRevision', - ol.source.MapQuest.prototype.getRevision); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'on', - ol.source.MapQuest.prototype.on); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'once', - ol.source.MapQuest.prototype.once); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'un', - ol.source.MapQuest.prototype.un); - -goog.exportProperty( - ol.source.MapQuest.prototype, - 'unByKey', - ol.source.MapQuest.prototype.unByKey); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setRenderReprojectionEdges', - ol.source.OSM.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setTileGridForProjection', - ol.source.OSM.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getTileLoadFunction', - ol.source.OSM.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getTileUrlFunction', - ol.source.OSM.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getUrls', - ol.source.OSM.prototype.getUrls); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setTileLoadFunction', - ol.source.OSM.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setTileUrlFunction', - ol.source.OSM.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setUrl', - ol.source.OSM.prototype.setUrl); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setUrls', - ol.source.OSM.prototype.setUrls); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getTileGrid', - ol.source.OSM.prototype.getTileGrid); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getAttributions', - ol.source.OSM.prototype.getAttributions); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getLogo', - ol.source.OSM.prototype.getLogo); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getProjection', - ol.source.OSM.prototype.getProjection); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getState', - ol.source.OSM.prototype.getState); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setAttributions', - ol.source.OSM.prototype.setAttributions); - -goog.exportProperty( - ol.source.OSM.prototype, - 'get', - ol.source.OSM.prototype.get); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getKeys', - ol.source.OSM.prototype.getKeys); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getProperties', - ol.source.OSM.prototype.getProperties); - -goog.exportProperty( - ol.source.OSM.prototype, - 'set', - ol.source.OSM.prototype.set); - -goog.exportProperty( - ol.source.OSM.prototype, - 'setProperties', - ol.source.OSM.prototype.setProperties); - -goog.exportProperty( - ol.source.OSM.prototype, - 'unset', - ol.source.OSM.prototype.unset); - -goog.exportProperty( - ol.source.OSM.prototype, - 'changed', - ol.source.OSM.prototype.changed); - -goog.exportProperty( - ol.source.OSM.prototype, - 'dispatchEvent', - ol.source.OSM.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.OSM.prototype, - 'getRevision', - ol.source.OSM.prototype.getRevision); - -goog.exportProperty( - ol.source.OSM.prototype, - 'on', - ol.source.OSM.prototype.on); - -goog.exportProperty( - ol.source.OSM.prototype, - 'once', - ol.source.OSM.prototype.once); - -goog.exportProperty( - ol.source.OSM.prototype, - 'un', - ol.source.OSM.prototype.un); - -goog.exportProperty( - ol.source.OSM.prototype, - 'unByKey', - ol.source.OSM.prototype.unByKey); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getAttributions', - ol.source.Raster.prototype.getAttributions); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getLogo', - ol.source.Raster.prototype.getLogo); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getProjection', - ol.source.Raster.prototype.getProjection); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getState', - ol.source.Raster.prototype.getState); - -goog.exportProperty( - ol.source.Raster.prototype, - 'setAttributions', - ol.source.Raster.prototype.setAttributions); - -goog.exportProperty( - ol.source.Raster.prototype, - 'get', - ol.source.Raster.prototype.get); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getKeys', - ol.source.Raster.prototype.getKeys); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getProperties', - ol.source.Raster.prototype.getProperties); - -goog.exportProperty( - ol.source.Raster.prototype, - 'set', - ol.source.Raster.prototype.set); - -goog.exportProperty( - ol.source.Raster.prototype, - 'setProperties', - ol.source.Raster.prototype.setProperties); - -goog.exportProperty( - ol.source.Raster.prototype, - 'unset', - ol.source.Raster.prototype.unset); - -goog.exportProperty( - ol.source.Raster.prototype, - 'changed', - ol.source.Raster.prototype.changed); - -goog.exportProperty( - ol.source.Raster.prototype, - 'dispatchEvent', - ol.source.Raster.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Raster.prototype, - 'getRevision', - ol.source.Raster.prototype.getRevision); - -goog.exportProperty( - ol.source.Raster.prototype, - 'on', - ol.source.Raster.prototype.on); - -goog.exportProperty( - ol.source.Raster.prototype, - 'once', - ol.source.Raster.prototype.once); - -goog.exportProperty( - ol.source.Raster.prototype, - 'un', - ol.source.Raster.prototype.un); - -goog.exportProperty( - ol.source.Raster.prototype, - 'unByKey', - ol.source.Raster.prototype.unByKey); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setRenderReprojectionEdges', - ol.source.Stamen.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setTileGridForProjection', - ol.source.Stamen.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getTileLoadFunction', - ol.source.Stamen.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getTileUrlFunction', - ol.source.Stamen.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getUrls', - ol.source.Stamen.prototype.getUrls); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setTileLoadFunction', - ol.source.Stamen.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setTileUrlFunction', - ol.source.Stamen.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setUrl', - ol.source.Stamen.prototype.setUrl); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setUrls', - ol.source.Stamen.prototype.setUrls); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getTileGrid', - ol.source.Stamen.prototype.getTileGrid); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getAttributions', - ol.source.Stamen.prototype.getAttributions); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getLogo', - ol.source.Stamen.prototype.getLogo); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getProjection', - ol.source.Stamen.prototype.getProjection); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getState', - ol.source.Stamen.prototype.getState); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setAttributions', - ol.source.Stamen.prototype.setAttributions); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'get', - ol.source.Stamen.prototype.get); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getKeys', - ol.source.Stamen.prototype.getKeys); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getProperties', - ol.source.Stamen.prototype.getProperties); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'set', - ol.source.Stamen.prototype.set); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'setProperties', - ol.source.Stamen.prototype.setProperties); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'unset', - ol.source.Stamen.prototype.unset); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'changed', - ol.source.Stamen.prototype.changed); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'dispatchEvent', - ol.source.Stamen.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'getRevision', - ol.source.Stamen.prototype.getRevision); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'on', - ol.source.Stamen.prototype.on); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'once', - ol.source.Stamen.prototype.once); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'un', - ol.source.Stamen.prototype.un); - -goog.exportProperty( - ol.source.Stamen.prototype, - 'unByKey', - ol.source.Stamen.prototype.unByKey); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setRenderReprojectionEdges', - ol.source.TileArcGISRest.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setTileGridForProjection', - ol.source.TileArcGISRest.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getTileLoadFunction', - ol.source.TileArcGISRest.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getTileUrlFunction', - ol.source.TileArcGISRest.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getUrls', - ol.source.TileArcGISRest.prototype.getUrls); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setTileLoadFunction', - ol.source.TileArcGISRest.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setTileUrlFunction', - ol.source.TileArcGISRest.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setUrl', - ol.source.TileArcGISRest.prototype.setUrl); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setUrls', - ol.source.TileArcGISRest.prototype.setUrls); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getTileGrid', - ol.source.TileArcGISRest.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getAttributions', - ol.source.TileArcGISRest.prototype.getAttributions); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getLogo', - ol.source.TileArcGISRest.prototype.getLogo); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getProjection', - ol.source.TileArcGISRest.prototype.getProjection); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getState', - ol.source.TileArcGISRest.prototype.getState); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setAttributions', - ol.source.TileArcGISRest.prototype.setAttributions); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'get', - ol.source.TileArcGISRest.prototype.get); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getKeys', - ol.source.TileArcGISRest.prototype.getKeys); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getProperties', - ol.source.TileArcGISRest.prototype.getProperties); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'set', - ol.source.TileArcGISRest.prototype.set); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'setProperties', - ol.source.TileArcGISRest.prototype.setProperties); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'unset', - ol.source.TileArcGISRest.prototype.unset); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'changed', - ol.source.TileArcGISRest.prototype.changed); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'dispatchEvent', - ol.source.TileArcGISRest.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'getRevision', - ol.source.TileArcGISRest.prototype.getRevision); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'on', - ol.source.TileArcGISRest.prototype.on); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'once', - ol.source.TileArcGISRest.prototype.once); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'un', - ol.source.TileArcGISRest.prototype.un); - -goog.exportProperty( - ol.source.TileArcGISRest.prototype, - 'unByKey', - ol.source.TileArcGISRest.prototype.unByKey); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getTileGrid', - ol.source.TileDebug.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getAttributions', - ol.source.TileDebug.prototype.getAttributions); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getLogo', - ol.source.TileDebug.prototype.getLogo); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getProjection', - ol.source.TileDebug.prototype.getProjection); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getState', - ol.source.TileDebug.prototype.getState); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'setAttributions', - ol.source.TileDebug.prototype.setAttributions); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'get', - ol.source.TileDebug.prototype.get); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getKeys', - ol.source.TileDebug.prototype.getKeys); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getProperties', - ol.source.TileDebug.prototype.getProperties); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'set', - ol.source.TileDebug.prototype.set); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'setProperties', - ol.source.TileDebug.prototype.setProperties); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'unset', - ol.source.TileDebug.prototype.unset); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'changed', - ol.source.TileDebug.prototype.changed); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'dispatchEvent', - ol.source.TileDebug.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'getRevision', - ol.source.TileDebug.prototype.getRevision); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'on', - ol.source.TileDebug.prototype.on); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'once', - ol.source.TileDebug.prototype.once); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'un', - ol.source.TileDebug.prototype.un); - -goog.exportProperty( - ol.source.TileDebug.prototype, - 'unByKey', - ol.source.TileDebug.prototype.unByKey); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setRenderReprojectionEdges', - ol.source.TileJSON.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setTileGridForProjection', - ol.source.TileJSON.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getTileLoadFunction', - ol.source.TileJSON.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getTileUrlFunction', - ol.source.TileJSON.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getUrls', - ol.source.TileJSON.prototype.getUrls); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setTileLoadFunction', - ol.source.TileJSON.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setTileUrlFunction', - ol.source.TileJSON.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setUrl', - ol.source.TileJSON.prototype.setUrl); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setUrls', - ol.source.TileJSON.prototype.setUrls); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getTileGrid', - ol.source.TileJSON.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getAttributions', - ol.source.TileJSON.prototype.getAttributions); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getLogo', - ol.source.TileJSON.prototype.getLogo); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getProjection', - ol.source.TileJSON.prototype.getProjection); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getState', - ol.source.TileJSON.prototype.getState); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setAttributions', - ol.source.TileJSON.prototype.setAttributions); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'get', - ol.source.TileJSON.prototype.get); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getKeys', - ol.source.TileJSON.prototype.getKeys); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getProperties', - ol.source.TileJSON.prototype.getProperties); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'set', - ol.source.TileJSON.prototype.set); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'setProperties', - ol.source.TileJSON.prototype.setProperties); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'unset', - ol.source.TileJSON.prototype.unset); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'changed', - ol.source.TileJSON.prototype.changed); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'dispatchEvent', - ol.source.TileJSON.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'getRevision', - ol.source.TileJSON.prototype.getRevision); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'on', - ol.source.TileJSON.prototype.on); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'once', - ol.source.TileJSON.prototype.once); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'un', - ol.source.TileJSON.prototype.un); - -goog.exportProperty( - ol.source.TileJSON.prototype, - 'unByKey', - ol.source.TileJSON.prototype.unByKey); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getTileGrid', - ol.source.TileUTFGrid.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getAttributions', - ol.source.TileUTFGrid.prototype.getAttributions); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getLogo', - ol.source.TileUTFGrid.prototype.getLogo); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getProjection', - ol.source.TileUTFGrid.prototype.getProjection); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getState', - ol.source.TileUTFGrid.prototype.getState); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'setAttributions', - ol.source.TileUTFGrid.prototype.setAttributions); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'get', - ol.source.TileUTFGrid.prototype.get); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getKeys', - ol.source.TileUTFGrid.prototype.getKeys); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getProperties', - ol.source.TileUTFGrid.prototype.getProperties); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'set', - ol.source.TileUTFGrid.prototype.set); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'setProperties', - ol.source.TileUTFGrid.prototype.setProperties); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'unset', - ol.source.TileUTFGrid.prototype.unset); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'changed', - ol.source.TileUTFGrid.prototype.changed); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'dispatchEvent', - ol.source.TileUTFGrid.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'getRevision', - ol.source.TileUTFGrid.prototype.getRevision); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'on', - ol.source.TileUTFGrid.prototype.on); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'once', - ol.source.TileUTFGrid.prototype.once); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'un', - ol.source.TileUTFGrid.prototype.un); - -goog.exportProperty( - ol.source.TileUTFGrid.prototype, - 'unByKey', - ol.source.TileUTFGrid.prototype.unByKey); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setRenderReprojectionEdges', - ol.source.TileWMS.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setTileGridForProjection', - ol.source.TileWMS.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getTileLoadFunction', - ol.source.TileWMS.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getTileUrlFunction', - ol.source.TileWMS.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getUrls', - ol.source.TileWMS.prototype.getUrls); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setTileLoadFunction', - ol.source.TileWMS.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setTileUrlFunction', - ol.source.TileWMS.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setUrl', - ol.source.TileWMS.prototype.setUrl); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setUrls', - ol.source.TileWMS.prototype.setUrls); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getTileGrid', - ol.source.TileWMS.prototype.getTileGrid); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getAttributions', - ol.source.TileWMS.prototype.getAttributions); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getLogo', - ol.source.TileWMS.prototype.getLogo); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getProjection', - ol.source.TileWMS.prototype.getProjection); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getState', - ol.source.TileWMS.prototype.getState); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setAttributions', - ol.source.TileWMS.prototype.setAttributions); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'get', - ol.source.TileWMS.prototype.get); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getKeys', - ol.source.TileWMS.prototype.getKeys); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getProperties', - ol.source.TileWMS.prototype.getProperties); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'set', - ol.source.TileWMS.prototype.set); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'setProperties', - ol.source.TileWMS.prototype.setProperties); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'unset', - ol.source.TileWMS.prototype.unset); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'changed', - ol.source.TileWMS.prototype.changed); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'dispatchEvent', - ol.source.TileWMS.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'getRevision', - ol.source.TileWMS.prototype.getRevision); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'on', - ol.source.TileWMS.prototype.on); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'once', - ol.source.TileWMS.prototype.once); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'un', - ol.source.TileWMS.prototype.un); - -goog.exportProperty( - ol.source.TileWMS.prototype, - 'unByKey', - ol.source.TileWMS.prototype.unByKey); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getTileLoadFunction', - ol.source.VectorTile.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getTileUrlFunction', - ol.source.VectorTile.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getUrls', - ol.source.VectorTile.prototype.getUrls); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'setTileLoadFunction', - ol.source.VectorTile.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'setTileUrlFunction', - ol.source.VectorTile.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'setUrl', - ol.source.VectorTile.prototype.setUrl); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'setUrls', - ol.source.VectorTile.prototype.setUrls); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getTileGrid', - ol.source.VectorTile.prototype.getTileGrid); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getAttributions', - ol.source.VectorTile.prototype.getAttributions); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getLogo', - ol.source.VectorTile.prototype.getLogo); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getProjection', - ol.source.VectorTile.prototype.getProjection); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getState', - ol.source.VectorTile.prototype.getState); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'setAttributions', - ol.source.VectorTile.prototype.setAttributions); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'get', - ol.source.VectorTile.prototype.get); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getKeys', - ol.source.VectorTile.prototype.getKeys); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getProperties', - ol.source.VectorTile.prototype.getProperties); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'set', - ol.source.VectorTile.prototype.set); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'setProperties', - ol.source.VectorTile.prototype.setProperties); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'unset', - ol.source.VectorTile.prototype.unset); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'changed', - ol.source.VectorTile.prototype.changed); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'dispatchEvent', - ol.source.VectorTile.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'getRevision', - ol.source.VectorTile.prototype.getRevision); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'on', - ol.source.VectorTile.prototype.on); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'once', - ol.source.VectorTile.prototype.once); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'un', - ol.source.VectorTile.prototype.un); - -goog.exportProperty( - ol.source.VectorTile.prototype, - 'unByKey', - ol.source.VectorTile.prototype.unByKey); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setRenderReprojectionEdges', - ol.source.WMTS.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setTileGridForProjection', - ol.source.WMTS.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getTileLoadFunction', - ol.source.WMTS.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getTileUrlFunction', - ol.source.WMTS.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getUrls', - ol.source.WMTS.prototype.getUrls); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setTileLoadFunction', - ol.source.WMTS.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setTileUrlFunction', - ol.source.WMTS.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setUrl', - ol.source.WMTS.prototype.setUrl); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setUrls', - ol.source.WMTS.prototype.setUrls); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getTileGrid', - ol.source.WMTS.prototype.getTileGrid); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getAttributions', - ol.source.WMTS.prototype.getAttributions); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getLogo', - ol.source.WMTS.prototype.getLogo); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getProjection', - ol.source.WMTS.prototype.getProjection); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getState', - ol.source.WMTS.prototype.getState); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setAttributions', - ol.source.WMTS.prototype.setAttributions); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'get', - ol.source.WMTS.prototype.get); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getKeys', - ol.source.WMTS.prototype.getKeys); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getProperties', - ol.source.WMTS.prototype.getProperties); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'set', - ol.source.WMTS.prototype.set); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'setProperties', - ol.source.WMTS.prototype.setProperties); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'unset', - ol.source.WMTS.prototype.unset); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'changed', - ol.source.WMTS.prototype.changed); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'dispatchEvent', - ol.source.WMTS.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'getRevision', - ol.source.WMTS.prototype.getRevision); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'on', - ol.source.WMTS.prototype.on); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'once', - ol.source.WMTS.prototype.once); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'un', - ol.source.WMTS.prototype.un); - -goog.exportProperty( - ol.source.WMTS.prototype, - 'unByKey', - ol.source.WMTS.prototype.unByKey); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setRenderReprojectionEdges', - ol.source.Zoomify.prototype.setRenderReprojectionEdges); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setTileGridForProjection', - ol.source.Zoomify.prototype.setTileGridForProjection); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getTileLoadFunction', - ol.source.Zoomify.prototype.getTileLoadFunction); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getTileUrlFunction', - ol.source.Zoomify.prototype.getTileUrlFunction); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getUrls', - ol.source.Zoomify.prototype.getUrls); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setTileLoadFunction', - ol.source.Zoomify.prototype.setTileLoadFunction); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setTileUrlFunction', - ol.source.Zoomify.prototype.setTileUrlFunction); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setUrl', - ol.source.Zoomify.prototype.setUrl); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setUrls', - ol.source.Zoomify.prototype.setUrls); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getTileGrid', - ol.source.Zoomify.prototype.getTileGrid); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getAttributions', - ol.source.Zoomify.prototype.getAttributions); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getLogo', - ol.source.Zoomify.prototype.getLogo); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getProjection', - ol.source.Zoomify.prototype.getProjection); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getState', - ol.source.Zoomify.prototype.getState); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setAttributions', - ol.source.Zoomify.prototype.setAttributions); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'get', - ol.source.Zoomify.prototype.get); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getKeys', - ol.source.Zoomify.prototype.getKeys); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getProperties', - ol.source.Zoomify.prototype.getProperties); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'set', - ol.source.Zoomify.prototype.set); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'setProperties', - ol.source.Zoomify.prototype.setProperties); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'unset', - ol.source.Zoomify.prototype.unset); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'changed', - ol.source.Zoomify.prototype.changed); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'dispatchEvent', - ol.source.Zoomify.prototype.dispatchEvent); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'getRevision', - ol.source.Zoomify.prototype.getRevision); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'on', - ol.source.Zoomify.prototype.on); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'once', - ol.source.Zoomify.prototype.once); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'un', - ol.source.Zoomify.prototype.un); - -goog.exportProperty( - ol.source.Zoomify.prototype, - 'unByKey', - ol.source.Zoomify.prototype.unByKey); - -goog.exportProperty( - ol.reproj.Tile.prototype, - 'getTileCoord', - ol.reproj.Tile.prototype.getTileCoord); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'changed', - ol.renderer.Layer.prototype.changed); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'dispatchEvent', - ol.renderer.Layer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'getRevision', - ol.renderer.Layer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'on', - ol.renderer.Layer.prototype.on); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'once', - ol.renderer.Layer.prototype.once); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'un', - ol.renderer.Layer.prototype.un); - -goog.exportProperty( - ol.renderer.Layer.prototype, - 'unByKey', - ol.renderer.Layer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'changed', - ol.renderer.webgl.Layer.prototype.changed); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'dispatchEvent', - ol.renderer.webgl.Layer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'getRevision', - ol.renderer.webgl.Layer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'on', - ol.renderer.webgl.Layer.prototype.on); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'once', - ol.renderer.webgl.Layer.prototype.once); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'un', - ol.renderer.webgl.Layer.prototype.un); - -goog.exportProperty( - ol.renderer.webgl.Layer.prototype, - 'unByKey', - ol.renderer.webgl.Layer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'changed', - ol.renderer.webgl.ImageLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'dispatchEvent', - ol.renderer.webgl.ImageLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'getRevision', - ol.renderer.webgl.ImageLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'on', - ol.renderer.webgl.ImageLayer.prototype.on); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'once', - ol.renderer.webgl.ImageLayer.prototype.once); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'un', - ol.renderer.webgl.ImageLayer.prototype.un); - -goog.exportProperty( - ol.renderer.webgl.ImageLayer.prototype, - 'unByKey', - ol.renderer.webgl.ImageLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'changed', - ol.renderer.webgl.TileLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'dispatchEvent', - ol.renderer.webgl.TileLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'getRevision', - ol.renderer.webgl.TileLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'on', - ol.renderer.webgl.TileLayer.prototype.on); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'once', - ol.renderer.webgl.TileLayer.prototype.once); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'un', - ol.renderer.webgl.TileLayer.prototype.un); - -goog.exportProperty( - ol.renderer.webgl.TileLayer.prototype, - 'unByKey', - ol.renderer.webgl.TileLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'changed', - ol.renderer.webgl.VectorLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'dispatchEvent', - ol.renderer.webgl.VectorLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'getRevision', - ol.renderer.webgl.VectorLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'on', - ol.renderer.webgl.VectorLayer.prototype.on); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'once', - ol.renderer.webgl.VectorLayer.prototype.once); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'un', - ol.renderer.webgl.VectorLayer.prototype.un); - -goog.exportProperty( - ol.renderer.webgl.VectorLayer.prototype, - 'unByKey', - ol.renderer.webgl.VectorLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'changed', - ol.renderer.dom.Layer.prototype.changed); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'dispatchEvent', - ol.renderer.dom.Layer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'getRevision', - ol.renderer.dom.Layer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'on', - ol.renderer.dom.Layer.prototype.on); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'once', - ol.renderer.dom.Layer.prototype.once); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'un', - ol.renderer.dom.Layer.prototype.un); - -goog.exportProperty( - ol.renderer.dom.Layer.prototype, - 'unByKey', - ol.renderer.dom.Layer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'changed', - ol.renderer.dom.ImageLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'dispatchEvent', - ol.renderer.dom.ImageLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'getRevision', - ol.renderer.dom.ImageLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'on', - ol.renderer.dom.ImageLayer.prototype.on); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'once', - ol.renderer.dom.ImageLayer.prototype.once); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'un', - ol.renderer.dom.ImageLayer.prototype.un); - -goog.exportProperty( - ol.renderer.dom.ImageLayer.prototype, - 'unByKey', - ol.renderer.dom.ImageLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'changed', - ol.renderer.dom.TileLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'dispatchEvent', - ol.renderer.dom.TileLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'getRevision', - ol.renderer.dom.TileLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'on', - ol.renderer.dom.TileLayer.prototype.on); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'once', - ol.renderer.dom.TileLayer.prototype.once); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'un', - ol.renderer.dom.TileLayer.prototype.un); - -goog.exportProperty( - ol.renderer.dom.TileLayer.prototype, - 'unByKey', - ol.renderer.dom.TileLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'changed', - ol.renderer.dom.VectorLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'dispatchEvent', - ol.renderer.dom.VectorLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'getRevision', - ol.renderer.dom.VectorLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'on', - ol.renderer.dom.VectorLayer.prototype.on); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'once', - ol.renderer.dom.VectorLayer.prototype.once); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'un', - ol.renderer.dom.VectorLayer.prototype.un); - -goog.exportProperty( - ol.renderer.dom.VectorLayer.prototype, - 'unByKey', - ol.renderer.dom.VectorLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'changed', - ol.renderer.canvas.Layer.prototype.changed); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'dispatchEvent', - ol.renderer.canvas.Layer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'getRevision', - ol.renderer.canvas.Layer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'on', - ol.renderer.canvas.Layer.prototype.on); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'once', - ol.renderer.canvas.Layer.prototype.once); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'un', - ol.renderer.canvas.Layer.prototype.un); - -goog.exportProperty( - ol.renderer.canvas.Layer.prototype, - 'unByKey', - ol.renderer.canvas.Layer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'changed', - ol.renderer.canvas.ImageLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'dispatchEvent', - ol.renderer.canvas.ImageLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'getRevision', - ol.renderer.canvas.ImageLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'on', - ol.renderer.canvas.ImageLayer.prototype.on); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'once', - ol.renderer.canvas.ImageLayer.prototype.once); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'un', - ol.renderer.canvas.ImageLayer.prototype.un); - -goog.exportProperty( - ol.renderer.canvas.ImageLayer.prototype, - 'unByKey', - ol.renderer.canvas.ImageLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'changed', - ol.renderer.canvas.TileLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'dispatchEvent', - ol.renderer.canvas.TileLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'getRevision', - ol.renderer.canvas.TileLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'on', - ol.renderer.canvas.TileLayer.prototype.on); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'once', - ol.renderer.canvas.TileLayer.prototype.once); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'un', - ol.renderer.canvas.TileLayer.prototype.un); - -goog.exportProperty( - ol.renderer.canvas.TileLayer.prototype, - 'unByKey', - ol.renderer.canvas.TileLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'changed', - ol.renderer.canvas.VectorLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'dispatchEvent', - ol.renderer.canvas.VectorLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'getRevision', - ol.renderer.canvas.VectorLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'on', - ol.renderer.canvas.VectorLayer.prototype.on); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'once', - ol.renderer.canvas.VectorLayer.prototype.once); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'un', - ol.renderer.canvas.VectorLayer.prototype.un); - -goog.exportProperty( - ol.renderer.canvas.VectorLayer.prototype, - 'unByKey', - ol.renderer.canvas.VectorLayer.prototype.unByKey); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'changed', - ol.renderer.canvas.VectorTileLayer.prototype.changed); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'dispatchEvent', - ol.renderer.canvas.VectorTileLayer.prototype.dispatchEvent); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'getRevision', - ol.renderer.canvas.VectorTileLayer.prototype.getRevision); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'on', - ol.renderer.canvas.VectorTileLayer.prototype.on); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'once', - ol.renderer.canvas.VectorTileLayer.prototype.once); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'un', - ol.renderer.canvas.VectorTileLayer.prototype.un); - -goog.exportProperty( - ol.renderer.canvas.VectorTileLayer.prototype, - 'unByKey', - ol.renderer.canvas.VectorTileLayer.prototype.unByKey); - -goog.exportProperty( - ol.layer.Base.prototype, - 'get', - ol.layer.Base.prototype.get); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getKeys', - ol.layer.Base.prototype.getKeys); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getProperties', - ol.layer.Base.prototype.getProperties); - -goog.exportProperty( - ol.layer.Base.prototype, - 'set', - ol.layer.Base.prototype.set); - -goog.exportProperty( - ol.layer.Base.prototype, - 'setProperties', - ol.layer.Base.prototype.setProperties); - -goog.exportProperty( - ol.layer.Base.prototype, - 'unset', - ol.layer.Base.prototype.unset); - -goog.exportProperty( - ol.layer.Base.prototype, - 'changed', - ol.layer.Base.prototype.changed); - -goog.exportProperty( - ol.layer.Base.prototype, - 'dispatchEvent', - ol.layer.Base.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Base.prototype, - 'getRevision', - ol.layer.Base.prototype.getRevision); - -goog.exportProperty( - ol.layer.Base.prototype, - 'on', - ol.layer.Base.prototype.on); - -goog.exportProperty( - ol.layer.Base.prototype, - 'once', - ol.layer.Base.prototype.once); - -goog.exportProperty( - ol.layer.Base.prototype, - 'un', - ol.layer.Base.prototype.un); - -goog.exportProperty( - ol.layer.Base.prototype, - 'unByKey', - ol.layer.Base.prototype.unByKey); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getExtent', - ol.layer.Layer.prototype.getExtent); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getMaxResolution', - ol.layer.Layer.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getMinResolution', - ol.layer.Layer.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getOpacity', - ol.layer.Layer.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getVisible', - ol.layer.Layer.prototype.getVisible); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getZIndex', - ol.layer.Layer.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setExtent', - ol.layer.Layer.prototype.setExtent); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setMaxResolution', - ol.layer.Layer.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setMinResolution', - ol.layer.Layer.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setOpacity', - ol.layer.Layer.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setVisible', - ol.layer.Layer.prototype.setVisible); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setZIndex', - ol.layer.Layer.prototype.setZIndex); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'get', - ol.layer.Layer.prototype.get); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getKeys', - ol.layer.Layer.prototype.getKeys); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getProperties', - ol.layer.Layer.prototype.getProperties); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'set', - ol.layer.Layer.prototype.set); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'setProperties', - ol.layer.Layer.prototype.setProperties); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'unset', - ol.layer.Layer.prototype.unset); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'changed', - ol.layer.Layer.prototype.changed); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'dispatchEvent', - ol.layer.Layer.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'getRevision', - ol.layer.Layer.prototype.getRevision); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'on', - ol.layer.Layer.prototype.on); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'once', - ol.layer.Layer.prototype.once); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'un', - ol.layer.Layer.prototype.un); - -goog.exportProperty( - ol.layer.Layer.prototype, - 'unByKey', - ol.layer.Layer.prototype.unByKey); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setMap', - ol.layer.Vector.prototype.setMap); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setSource', - ol.layer.Vector.prototype.setSource); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getExtent', - ol.layer.Vector.prototype.getExtent); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getMaxResolution', - ol.layer.Vector.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getMinResolution', - ol.layer.Vector.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getOpacity', - ol.layer.Vector.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getVisible', - ol.layer.Vector.prototype.getVisible); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getZIndex', - ol.layer.Vector.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setExtent', - ol.layer.Vector.prototype.setExtent); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setMaxResolution', - ol.layer.Vector.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setMinResolution', - ol.layer.Vector.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setOpacity', - ol.layer.Vector.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setVisible', - ol.layer.Vector.prototype.setVisible); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setZIndex', - ol.layer.Vector.prototype.setZIndex); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'get', - ol.layer.Vector.prototype.get); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getKeys', - ol.layer.Vector.prototype.getKeys); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getProperties', - ol.layer.Vector.prototype.getProperties); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'set', - ol.layer.Vector.prototype.set); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'setProperties', - ol.layer.Vector.prototype.setProperties); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'unset', - ol.layer.Vector.prototype.unset); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'changed', - ol.layer.Vector.prototype.changed); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'dispatchEvent', - ol.layer.Vector.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'getRevision', - ol.layer.Vector.prototype.getRevision); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'on', - ol.layer.Vector.prototype.on); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'once', - ol.layer.Vector.prototype.once); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'un', - ol.layer.Vector.prototype.un); - -goog.exportProperty( - ol.layer.Vector.prototype, - 'unByKey', - ol.layer.Vector.prototype.unByKey); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getSource', - ol.layer.Heatmap.prototype.getSource); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getStyle', - ol.layer.Heatmap.prototype.getStyle); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getStyleFunction', - ol.layer.Heatmap.prototype.getStyleFunction); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setStyle', - ol.layer.Heatmap.prototype.setStyle); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setMap', - ol.layer.Heatmap.prototype.setMap); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setSource', - ol.layer.Heatmap.prototype.setSource); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getExtent', - ol.layer.Heatmap.prototype.getExtent); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getMaxResolution', - ol.layer.Heatmap.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getMinResolution', - ol.layer.Heatmap.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getOpacity', - ol.layer.Heatmap.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getVisible', - ol.layer.Heatmap.prototype.getVisible); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getZIndex', - ol.layer.Heatmap.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setExtent', - ol.layer.Heatmap.prototype.setExtent); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setMaxResolution', - ol.layer.Heatmap.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setMinResolution', - ol.layer.Heatmap.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setOpacity', - ol.layer.Heatmap.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setVisible', - ol.layer.Heatmap.prototype.setVisible); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setZIndex', - ol.layer.Heatmap.prototype.setZIndex); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'get', - ol.layer.Heatmap.prototype.get); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getKeys', - ol.layer.Heatmap.prototype.getKeys); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getProperties', - ol.layer.Heatmap.prototype.getProperties); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'set', - ol.layer.Heatmap.prototype.set); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'setProperties', - ol.layer.Heatmap.prototype.setProperties); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'unset', - ol.layer.Heatmap.prototype.unset); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'changed', - ol.layer.Heatmap.prototype.changed); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'dispatchEvent', - ol.layer.Heatmap.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'getRevision', - ol.layer.Heatmap.prototype.getRevision); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'on', - ol.layer.Heatmap.prototype.on); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'once', - ol.layer.Heatmap.prototype.once); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'un', - ol.layer.Heatmap.prototype.un); - -goog.exportProperty( - ol.layer.Heatmap.prototype, - 'unByKey', - ol.layer.Heatmap.prototype.unByKey); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setMap', - ol.layer.Image.prototype.setMap); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setSource', - ol.layer.Image.prototype.setSource); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getExtent', - ol.layer.Image.prototype.getExtent); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getMaxResolution', - ol.layer.Image.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getMinResolution', - ol.layer.Image.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getOpacity', - ol.layer.Image.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getVisible', - ol.layer.Image.prototype.getVisible); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getZIndex', - ol.layer.Image.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setExtent', - ol.layer.Image.prototype.setExtent); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setMaxResolution', - ol.layer.Image.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setMinResolution', - ol.layer.Image.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setOpacity', - ol.layer.Image.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setVisible', - ol.layer.Image.prototype.setVisible); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setZIndex', - ol.layer.Image.prototype.setZIndex); - -goog.exportProperty( - ol.layer.Image.prototype, - 'get', - ol.layer.Image.prototype.get); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getKeys', - ol.layer.Image.prototype.getKeys); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getProperties', - ol.layer.Image.prototype.getProperties); - -goog.exportProperty( - ol.layer.Image.prototype, - 'set', - ol.layer.Image.prototype.set); - -goog.exportProperty( - ol.layer.Image.prototype, - 'setProperties', - ol.layer.Image.prototype.setProperties); - -goog.exportProperty( - ol.layer.Image.prototype, - 'unset', - ol.layer.Image.prototype.unset); - -goog.exportProperty( - ol.layer.Image.prototype, - 'changed', - ol.layer.Image.prototype.changed); - -goog.exportProperty( - ol.layer.Image.prototype, - 'dispatchEvent', - ol.layer.Image.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Image.prototype, - 'getRevision', - ol.layer.Image.prototype.getRevision); - -goog.exportProperty( - ol.layer.Image.prototype, - 'on', - ol.layer.Image.prototype.on); - -goog.exportProperty( - ol.layer.Image.prototype, - 'once', - ol.layer.Image.prototype.once); - -goog.exportProperty( - ol.layer.Image.prototype, - 'un', - ol.layer.Image.prototype.un); - -goog.exportProperty( - ol.layer.Image.prototype, - 'unByKey', - ol.layer.Image.prototype.unByKey); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getExtent', - ol.layer.Group.prototype.getExtent); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getMaxResolution', - ol.layer.Group.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getMinResolution', - ol.layer.Group.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getOpacity', - ol.layer.Group.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getVisible', - ol.layer.Group.prototype.getVisible); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getZIndex', - ol.layer.Group.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setExtent', - ol.layer.Group.prototype.setExtent); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setMaxResolution', - ol.layer.Group.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setMinResolution', - ol.layer.Group.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setOpacity', - ol.layer.Group.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setVisible', - ol.layer.Group.prototype.setVisible); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setZIndex', - ol.layer.Group.prototype.setZIndex); - -goog.exportProperty( - ol.layer.Group.prototype, - 'get', - ol.layer.Group.prototype.get); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getKeys', - ol.layer.Group.prototype.getKeys); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getProperties', - ol.layer.Group.prototype.getProperties); - -goog.exportProperty( - ol.layer.Group.prototype, - 'set', - ol.layer.Group.prototype.set); - -goog.exportProperty( - ol.layer.Group.prototype, - 'setProperties', - ol.layer.Group.prototype.setProperties); - -goog.exportProperty( - ol.layer.Group.prototype, - 'unset', - ol.layer.Group.prototype.unset); - -goog.exportProperty( - ol.layer.Group.prototype, - 'changed', - ol.layer.Group.prototype.changed); - -goog.exportProperty( - ol.layer.Group.prototype, - 'dispatchEvent', - ol.layer.Group.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Group.prototype, - 'getRevision', - ol.layer.Group.prototype.getRevision); - -goog.exportProperty( - ol.layer.Group.prototype, - 'on', - ol.layer.Group.prototype.on); - -goog.exportProperty( - ol.layer.Group.prototype, - 'once', - ol.layer.Group.prototype.once); - -goog.exportProperty( - ol.layer.Group.prototype, - 'un', - ol.layer.Group.prototype.un); - -goog.exportProperty( - ol.layer.Group.prototype, - 'unByKey', - ol.layer.Group.prototype.unByKey); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setMap', - ol.layer.Tile.prototype.setMap); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setSource', - ol.layer.Tile.prototype.setSource); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getExtent', - ol.layer.Tile.prototype.getExtent); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getMaxResolution', - ol.layer.Tile.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getMinResolution', - ol.layer.Tile.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getOpacity', - ol.layer.Tile.prototype.getOpacity); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getVisible', - ol.layer.Tile.prototype.getVisible); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getZIndex', - ol.layer.Tile.prototype.getZIndex); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setExtent', - ol.layer.Tile.prototype.setExtent); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setMaxResolution', - ol.layer.Tile.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setMinResolution', - ol.layer.Tile.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setOpacity', - ol.layer.Tile.prototype.setOpacity); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setVisible', - ol.layer.Tile.prototype.setVisible); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setZIndex', - ol.layer.Tile.prototype.setZIndex); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'get', - ol.layer.Tile.prototype.get); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getKeys', - ol.layer.Tile.prototype.getKeys); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getProperties', - ol.layer.Tile.prototype.getProperties); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'set', - ol.layer.Tile.prototype.set); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'setProperties', - ol.layer.Tile.prototype.setProperties); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'unset', - ol.layer.Tile.prototype.unset); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'changed', - ol.layer.Tile.prototype.changed); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'dispatchEvent', - ol.layer.Tile.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'getRevision', - ol.layer.Tile.prototype.getRevision); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'on', - ol.layer.Tile.prototype.on); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'once', - ol.layer.Tile.prototype.once); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'un', - ol.layer.Tile.prototype.un); - -goog.exportProperty( - ol.layer.Tile.prototype, - 'unByKey', - ol.layer.Tile.prototype.unByKey); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getStyle', - ol.layer.VectorTile.prototype.getStyle); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getStyleFunction', - ol.layer.VectorTile.prototype.getStyleFunction); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setStyle', - ol.layer.VectorTile.prototype.setStyle); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setMap', - ol.layer.VectorTile.prototype.setMap); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setSource', - ol.layer.VectorTile.prototype.setSource); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getExtent', - ol.layer.VectorTile.prototype.getExtent); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getMaxResolution', - ol.layer.VectorTile.prototype.getMaxResolution); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getMinResolution', - ol.layer.VectorTile.prototype.getMinResolution); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getOpacity', - ol.layer.VectorTile.prototype.getOpacity); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getVisible', - ol.layer.VectorTile.prototype.getVisible); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getZIndex', - ol.layer.VectorTile.prototype.getZIndex); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setExtent', - ol.layer.VectorTile.prototype.setExtent); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setMaxResolution', - ol.layer.VectorTile.prototype.setMaxResolution); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setMinResolution', - ol.layer.VectorTile.prototype.setMinResolution); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setOpacity', - ol.layer.VectorTile.prototype.setOpacity); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setVisible', - ol.layer.VectorTile.prototype.setVisible); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setZIndex', - ol.layer.VectorTile.prototype.setZIndex); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'get', - ol.layer.VectorTile.prototype.get); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getKeys', - ol.layer.VectorTile.prototype.getKeys); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getProperties', - ol.layer.VectorTile.prototype.getProperties); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'set', - ol.layer.VectorTile.prototype.set); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'setProperties', - ol.layer.VectorTile.prototype.setProperties); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'unset', - ol.layer.VectorTile.prototype.unset); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'changed', - ol.layer.VectorTile.prototype.changed); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'dispatchEvent', - ol.layer.VectorTile.prototype.dispatchEvent); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'getRevision', - ol.layer.VectorTile.prototype.getRevision); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'on', - ol.layer.VectorTile.prototype.on); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'once', - ol.layer.VectorTile.prototype.once); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'un', - ol.layer.VectorTile.prototype.un); - -goog.exportProperty( - ol.layer.VectorTile.prototype, - 'unByKey', - ol.layer.VectorTile.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'get', - ol.interaction.Interaction.prototype.get); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'getKeys', - ol.interaction.Interaction.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'getProperties', - ol.interaction.Interaction.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'set', - ol.interaction.Interaction.prototype.set); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'setProperties', - ol.interaction.Interaction.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'unset', - ol.interaction.Interaction.prototype.unset); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'changed', - ol.interaction.Interaction.prototype.changed); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'dispatchEvent', - ol.interaction.Interaction.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'getRevision', - ol.interaction.Interaction.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'on', - ol.interaction.Interaction.prototype.on); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'once', - ol.interaction.Interaction.prototype.once); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'un', - ol.interaction.Interaction.prototype.un); - -goog.exportProperty( - ol.interaction.Interaction.prototype, - 'unByKey', - ol.interaction.Interaction.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'getActive', - ol.interaction.DoubleClickZoom.prototype.getActive); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'setActive', - ol.interaction.DoubleClickZoom.prototype.setActive); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'get', - ol.interaction.DoubleClickZoom.prototype.get); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'getKeys', - ol.interaction.DoubleClickZoom.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'getProperties', - ol.interaction.DoubleClickZoom.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'set', - ol.interaction.DoubleClickZoom.prototype.set); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'setProperties', - ol.interaction.DoubleClickZoom.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'unset', - ol.interaction.DoubleClickZoom.prototype.unset); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'changed', - ol.interaction.DoubleClickZoom.prototype.changed); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'dispatchEvent', - ol.interaction.DoubleClickZoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'getRevision', - ol.interaction.DoubleClickZoom.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'on', - ol.interaction.DoubleClickZoom.prototype.on); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'once', - ol.interaction.DoubleClickZoom.prototype.once); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'un', - ol.interaction.DoubleClickZoom.prototype.un); - -goog.exportProperty( - ol.interaction.DoubleClickZoom.prototype, - 'unByKey', - ol.interaction.DoubleClickZoom.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'getActive', - ol.interaction.DragAndDrop.prototype.getActive); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'setActive', - ol.interaction.DragAndDrop.prototype.setActive); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'get', - ol.interaction.DragAndDrop.prototype.get); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'getKeys', - ol.interaction.DragAndDrop.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'getProperties', - ol.interaction.DragAndDrop.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'set', - ol.interaction.DragAndDrop.prototype.set); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'setProperties', - ol.interaction.DragAndDrop.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'unset', - ol.interaction.DragAndDrop.prototype.unset); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'changed', - ol.interaction.DragAndDrop.prototype.changed); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'dispatchEvent', - ol.interaction.DragAndDrop.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'getRevision', - ol.interaction.DragAndDrop.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'on', - ol.interaction.DragAndDrop.prototype.on); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'once', - ol.interaction.DragAndDrop.prototype.once); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'un', - ol.interaction.DragAndDrop.prototype.un); - -goog.exportProperty( - ol.interaction.DragAndDrop.prototype, - 'unByKey', - ol.interaction.DragAndDrop.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'getActive', - ol.interaction.Pointer.prototype.getActive); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'setActive', - ol.interaction.Pointer.prototype.setActive); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'get', - ol.interaction.Pointer.prototype.get); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'getKeys', - ol.interaction.Pointer.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'getProperties', - ol.interaction.Pointer.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'set', - ol.interaction.Pointer.prototype.set); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'setProperties', - ol.interaction.Pointer.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'unset', - ol.interaction.Pointer.prototype.unset); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'changed', - ol.interaction.Pointer.prototype.changed); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'dispatchEvent', - ol.interaction.Pointer.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'getRevision', - ol.interaction.Pointer.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'on', - ol.interaction.Pointer.prototype.on); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'once', - ol.interaction.Pointer.prototype.once); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'un', - ol.interaction.Pointer.prototype.un); - -goog.exportProperty( - ol.interaction.Pointer.prototype, - 'unByKey', - ol.interaction.Pointer.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'getActive', - ol.interaction.DragBox.prototype.getActive); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'setActive', - ol.interaction.DragBox.prototype.setActive); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'get', - ol.interaction.DragBox.prototype.get); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'getKeys', - ol.interaction.DragBox.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'getProperties', - ol.interaction.DragBox.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'set', - ol.interaction.DragBox.prototype.set); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'setProperties', - ol.interaction.DragBox.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'unset', - ol.interaction.DragBox.prototype.unset); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'changed', - ol.interaction.DragBox.prototype.changed); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'dispatchEvent', - ol.interaction.DragBox.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'getRevision', - ol.interaction.DragBox.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'on', - ol.interaction.DragBox.prototype.on); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'once', - ol.interaction.DragBox.prototype.once); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'un', - ol.interaction.DragBox.prototype.un); - -goog.exportProperty( - ol.interaction.DragBox.prototype, - 'unByKey', - ol.interaction.DragBox.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'getActive', - ol.interaction.DragPan.prototype.getActive); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'setActive', - ol.interaction.DragPan.prototype.setActive); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'get', - ol.interaction.DragPan.prototype.get); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'getKeys', - ol.interaction.DragPan.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'getProperties', - ol.interaction.DragPan.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'set', - ol.interaction.DragPan.prototype.set); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'setProperties', - ol.interaction.DragPan.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'unset', - ol.interaction.DragPan.prototype.unset); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'changed', - ol.interaction.DragPan.prototype.changed); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'dispatchEvent', - ol.interaction.DragPan.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'getRevision', - ol.interaction.DragPan.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'on', - ol.interaction.DragPan.prototype.on); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'once', - ol.interaction.DragPan.prototype.once); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'un', - ol.interaction.DragPan.prototype.un); - -goog.exportProperty( - ol.interaction.DragPan.prototype, - 'unByKey', - ol.interaction.DragPan.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'getActive', - ol.interaction.DragRotateAndZoom.prototype.getActive); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'setActive', - ol.interaction.DragRotateAndZoom.prototype.setActive); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'get', - ol.interaction.DragRotateAndZoom.prototype.get); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'getKeys', - ol.interaction.DragRotateAndZoom.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'getProperties', - ol.interaction.DragRotateAndZoom.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'set', - ol.interaction.DragRotateAndZoom.prototype.set); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'setProperties', - ol.interaction.DragRotateAndZoom.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'unset', - ol.interaction.DragRotateAndZoom.prototype.unset); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'changed', - ol.interaction.DragRotateAndZoom.prototype.changed); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'dispatchEvent', - ol.interaction.DragRotateAndZoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'getRevision', - ol.interaction.DragRotateAndZoom.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'on', - ol.interaction.DragRotateAndZoom.prototype.on); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'once', - ol.interaction.DragRotateAndZoom.prototype.once); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'un', - ol.interaction.DragRotateAndZoom.prototype.un); - -goog.exportProperty( - ol.interaction.DragRotateAndZoom.prototype, - 'unByKey', - ol.interaction.DragRotateAndZoom.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'getActive', - ol.interaction.DragRotate.prototype.getActive); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'setActive', - ol.interaction.DragRotate.prototype.setActive); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'get', - ol.interaction.DragRotate.prototype.get); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'getKeys', - ol.interaction.DragRotate.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'getProperties', - ol.interaction.DragRotate.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'set', - ol.interaction.DragRotate.prototype.set); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'setProperties', - ol.interaction.DragRotate.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'unset', - ol.interaction.DragRotate.prototype.unset); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'changed', - ol.interaction.DragRotate.prototype.changed); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'dispatchEvent', - ol.interaction.DragRotate.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'getRevision', - ol.interaction.DragRotate.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'on', - ol.interaction.DragRotate.prototype.on); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'once', - ol.interaction.DragRotate.prototype.once); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'un', - ol.interaction.DragRotate.prototype.un); - -goog.exportProperty( - ol.interaction.DragRotate.prototype, - 'unByKey', - ol.interaction.DragRotate.prototype.unByKey); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'getGeometry', - ol.interaction.DragZoom.prototype.getGeometry); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'getActive', - ol.interaction.DragZoom.prototype.getActive); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'setActive', - ol.interaction.DragZoom.prototype.setActive); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'get', - ol.interaction.DragZoom.prototype.get); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'getKeys', - ol.interaction.DragZoom.prototype.getKeys); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'getProperties', - ol.interaction.DragZoom.prototype.getProperties); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'set', - ol.interaction.DragZoom.prototype.set); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'setProperties', - ol.interaction.DragZoom.prototype.setProperties); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'unset', - ol.interaction.DragZoom.prototype.unset); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'changed', - ol.interaction.DragZoom.prototype.changed); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'dispatchEvent', - ol.interaction.DragZoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'getRevision', - ol.interaction.DragZoom.prototype.getRevision); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'on', - ol.interaction.DragZoom.prototype.on); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'once', - ol.interaction.DragZoom.prototype.once); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'un', - ol.interaction.DragZoom.prototype.un); - -goog.exportProperty( - ol.interaction.DragZoom.prototype, - 'unByKey', - ol.interaction.DragZoom.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'getActive', - ol.interaction.Draw.prototype.getActive); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'setActive', - ol.interaction.Draw.prototype.setActive); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'get', - ol.interaction.Draw.prototype.get); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'getKeys', - ol.interaction.Draw.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'getProperties', - ol.interaction.Draw.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'set', - ol.interaction.Draw.prototype.set); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'setProperties', - ol.interaction.Draw.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'unset', - ol.interaction.Draw.prototype.unset); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'changed', - ol.interaction.Draw.prototype.changed); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'dispatchEvent', - ol.interaction.Draw.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'getRevision', - ol.interaction.Draw.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'on', - ol.interaction.Draw.prototype.on); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'once', - ol.interaction.Draw.prototype.once); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'un', - ol.interaction.Draw.prototype.un); - -goog.exportProperty( - ol.interaction.Draw.prototype, - 'unByKey', - ol.interaction.Draw.prototype.unByKey); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'getActive', - ol.interaction.KeyboardPan.prototype.getActive); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'setActive', - ol.interaction.KeyboardPan.prototype.setActive); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'get', - ol.interaction.KeyboardPan.prototype.get); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'getKeys', - ol.interaction.KeyboardPan.prototype.getKeys); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'getProperties', - ol.interaction.KeyboardPan.prototype.getProperties); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'set', - ol.interaction.KeyboardPan.prototype.set); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'setProperties', - ol.interaction.KeyboardPan.prototype.setProperties); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'unset', - ol.interaction.KeyboardPan.prototype.unset); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'changed', - ol.interaction.KeyboardPan.prototype.changed); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'dispatchEvent', - ol.interaction.KeyboardPan.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'getRevision', - ol.interaction.KeyboardPan.prototype.getRevision); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'on', - ol.interaction.KeyboardPan.prototype.on); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'once', - ol.interaction.KeyboardPan.prototype.once); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'un', - ol.interaction.KeyboardPan.prototype.un); - -goog.exportProperty( - ol.interaction.KeyboardPan.prototype, - 'unByKey', - ol.interaction.KeyboardPan.prototype.unByKey); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'getActive', - ol.interaction.KeyboardZoom.prototype.getActive); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'setActive', - ol.interaction.KeyboardZoom.prototype.setActive); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'get', - ol.interaction.KeyboardZoom.prototype.get); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'getKeys', - ol.interaction.KeyboardZoom.prototype.getKeys); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'getProperties', - ol.interaction.KeyboardZoom.prototype.getProperties); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'set', - ol.interaction.KeyboardZoom.prototype.set); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'setProperties', - ol.interaction.KeyboardZoom.prototype.setProperties); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'unset', - ol.interaction.KeyboardZoom.prototype.unset); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'changed', - ol.interaction.KeyboardZoom.prototype.changed); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'dispatchEvent', - ol.interaction.KeyboardZoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'getRevision', - ol.interaction.KeyboardZoom.prototype.getRevision); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'on', - ol.interaction.KeyboardZoom.prototype.on); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'once', - ol.interaction.KeyboardZoom.prototype.once); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'un', - ol.interaction.KeyboardZoom.prototype.un); - -goog.exportProperty( - ol.interaction.KeyboardZoom.prototype, - 'unByKey', - ol.interaction.KeyboardZoom.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'getActive', - ol.interaction.Modify.prototype.getActive); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'setActive', - ol.interaction.Modify.prototype.setActive); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'get', - ol.interaction.Modify.prototype.get); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'getKeys', - ol.interaction.Modify.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'getProperties', - ol.interaction.Modify.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'set', - ol.interaction.Modify.prototype.set); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'setProperties', - ol.interaction.Modify.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'unset', - ol.interaction.Modify.prototype.unset); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'changed', - ol.interaction.Modify.prototype.changed); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'dispatchEvent', - ol.interaction.Modify.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'getRevision', - ol.interaction.Modify.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'on', - ol.interaction.Modify.prototype.on); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'once', - ol.interaction.Modify.prototype.once); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'un', - ol.interaction.Modify.prototype.un); - -goog.exportProperty( - ol.interaction.Modify.prototype, - 'unByKey', - ol.interaction.Modify.prototype.unByKey); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'getActive', - ol.interaction.MouseWheelZoom.prototype.getActive); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'setActive', - ol.interaction.MouseWheelZoom.prototype.setActive); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'get', - ol.interaction.MouseWheelZoom.prototype.get); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'getKeys', - ol.interaction.MouseWheelZoom.prototype.getKeys); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'getProperties', - ol.interaction.MouseWheelZoom.prototype.getProperties); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'set', - ol.interaction.MouseWheelZoom.prototype.set); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'setProperties', - ol.interaction.MouseWheelZoom.prototype.setProperties); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'unset', - ol.interaction.MouseWheelZoom.prototype.unset); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'changed', - ol.interaction.MouseWheelZoom.prototype.changed); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'dispatchEvent', - ol.interaction.MouseWheelZoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'getRevision', - ol.interaction.MouseWheelZoom.prototype.getRevision); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'on', - ol.interaction.MouseWheelZoom.prototype.on); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'once', - ol.interaction.MouseWheelZoom.prototype.once); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'un', - ol.interaction.MouseWheelZoom.prototype.un); - -goog.exportProperty( - ol.interaction.MouseWheelZoom.prototype, - 'unByKey', - ol.interaction.MouseWheelZoom.prototype.unByKey); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'getActive', - ol.interaction.PinchRotate.prototype.getActive); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'setActive', - ol.interaction.PinchRotate.prototype.setActive); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'get', - ol.interaction.PinchRotate.prototype.get); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'getKeys', - ol.interaction.PinchRotate.prototype.getKeys); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'getProperties', - ol.interaction.PinchRotate.prototype.getProperties); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'set', - ol.interaction.PinchRotate.prototype.set); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'setProperties', - ol.interaction.PinchRotate.prototype.setProperties); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'unset', - ol.interaction.PinchRotate.prototype.unset); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'changed', - ol.interaction.PinchRotate.prototype.changed); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'dispatchEvent', - ol.interaction.PinchRotate.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'getRevision', - ol.interaction.PinchRotate.prototype.getRevision); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'on', - ol.interaction.PinchRotate.prototype.on); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'once', - ol.interaction.PinchRotate.prototype.once); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'un', - ol.interaction.PinchRotate.prototype.un); - -goog.exportProperty( - ol.interaction.PinchRotate.prototype, - 'unByKey', - ol.interaction.PinchRotate.prototype.unByKey); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'getActive', - ol.interaction.PinchZoom.prototype.getActive); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'setActive', - ol.interaction.PinchZoom.prototype.setActive); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'get', - ol.interaction.PinchZoom.prototype.get); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'getKeys', - ol.interaction.PinchZoom.prototype.getKeys); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'getProperties', - ol.interaction.PinchZoom.prototype.getProperties); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'set', - ol.interaction.PinchZoom.prototype.set); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'setProperties', - ol.interaction.PinchZoom.prototype.setProperties); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'unset', - ol.interaction.PinchZoom.prototype.unset); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'changed', - ol.interaction.PinchZoom.prototype.changed); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'dispatchEvent', - ol.interaction.PinchZoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'getRevision', - ol.interaction.PinchZoom.prototype.getRevision); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'on', - ol.interaction.PinchZoom.prototype.on); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'once', - ol.interaction.PinchZoom.prototype.once); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'un', - ol.interaction.PinchZoom.prototype.un); - -goog.exportProperty( - ol.interaction.PinchZoom.prototype, - 'unByKey', - ol.interaction.PinchZoom.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'getActive', - ol.interaction.Select.prototype.getActive); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'setActive', - ol.interaction.Select.prototype.setActive); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'get', - ol.interaction.Select.prototype.get); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'getKeys', - ol.interaction.Select.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'getProperties', - ol.interaction.Select.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'set', - ol.interaction.Select.prototype.set); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'setProperties', - ol.interaction.Select.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'unset', - ol.interaction.Select.prototype.unset); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'changed', - ol.interaction.Select.prototype.changed); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'dispatchEvent', - ol.interaction.Select.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'getRevision', - ol.interaction.Select.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'on', - ol.interaction.Select.prototype.on); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'once', - ol.interaction.Select.prototype.once); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'un', - ol.interaction.Select.prototype.un); - -goog.exportProperty( - ol.interaction.Select.prototype, - 'unByKey', - ol.interaction.Select.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'getActive', - ol.interaction.Snap.prototype.getActive); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'setActive', - ol.interaction.Snap.prototype.setActive); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'get', - ol.interaction.Snap.prototype.get); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'getKeys', - ol.interaction.Snap.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'getProperties', - ol.interaction.Snap.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'set', - ol.interaction.Snap.prototype.set); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'setProperties', - ol.interaction.Snap.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'unset', - ol.interaction.Snap.prototype.unset); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'changed', - ol.interaction.Snap.prototype.changed); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'dispatchEvent', - ol.interaction.Snap.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'getRevision', - ol.interaction.Snap.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'on', - ol.interaction.Snap.prototype.on); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'once', - ol.interaction.Snap.prototype.once); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'un', - ol.interaction.Snap.prototype.un); - -goog.exportProperty( - ol.interaction.Snap.prototype, - 'unByKey', - ol.interaction.Snap.prototype.unByKey); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'getActive', - ol.interaction.Translate.prototype.getActive); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'setActive', - ol.interaction.Translate.prototype.setActive); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'get', - ol.interaction.Translate.prototype.get); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'getKeys', - ol.interaction.Translate.prototype.getKeys); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'getProperties', - ol.interaction.Translate.prototype.getProperties); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'set', - ol.interaction.Translate.prototype.set); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'setProperties', - ol.interaction.Translate.prototype.setProperties); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'unset', - ol.interaction.Translate.prototype.unset); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'changed', - ol.interaction.Translate.prototype.changed); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'dispatchEvent', - ol.interaction.Translate.prototype.dispatchEvent); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'getRevision', - ol.interaction.Translate.prototype.getRevision); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'on', - ol.interaction.Translate.prototype.on); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'once', - ol.interaction.Translate.prototype.once); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'un', - ol.interaction.Translate.prototype.un); - -goog.exportProperty( - ol.interaction.Translate.prototype, - 'unByKey', - ol.interaction.Translate.prototype.unByKey); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'get', - ol.geom.Geometry.prototype.get); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'getKeys', - ol.geom.Geometry.prototype.getKeys); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'getProperties', - ol.geom.Geometry.prototype.getProperties); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'set', - ol.geom.Geometry.prototype.set); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'setProperties', - ol.geom.Geometry.prototype.setProperties); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'unset', - ol.geom.Geometry.prototype.unset); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'changed', - ol.geom.Geometry.prototype.changed); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'dispatchEvent', - ol.geom.Geometry.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'getRevision', - ol.geom.Geometry.prototype.getRevision); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'on', - ol.geom.Geometry.prototype.on); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'once', - ol.geom.Geometry.prototype.once); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'un', - ol.geom.Geometry.prototype.un); - -goog.exportProperty( - ol.geom.Geometry.prototype, - 'unByKey', - ol.geom.Geometry.prototype.unByKey); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getClosestPoint', - ol.geom.SimpleGeometry.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getExtent', - ol.geom.SimpleGeometry.prototype.getExtent); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'simplify', - ol.geom.SimpleGeometry.prototype.simplify); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'transform', - ol.geom.SimpleGeometry.prototype.transform); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'get', - ol.geom.SimpleGeometry.prototype.get); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getKeys', - ol.geom.SimpleGeometry.prototype.getKeys); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getProperties', - ol.geom.SimpleGeometry.prototype.getProperties); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'set', - ol.geom.SimpleGeometry.prototype.set); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'setProperties', - ol.geom.SimpleGeometry.prototype.setProperties); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'unset', - ol.geom.SimpleGeometry.prototype.unset); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'changed', - ol.geom.SimpleGeometry.prototype.changed); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'dispatchEvent', - ol.geom.SimpleGeometry.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'getRevision', - ol.geom.SimpleGeometry.prototype.getRevision); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'on', - ol.geom.SimpleGeometry.prototype.on); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'once', - ol.geom.SimpleGeometry.prototype.once); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'un', - ol.geom.SimpleGeometry.prototype.un); - -goog.exportProperty( - ol.geom.SimpleGeometry.prototype, - 'unByKey', - ol.geom.SimpleGeometry.prototype.unByKey); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getFirstCoordinate', - ol.geom.Circle.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getLastCoordinate', - ol.geom.Circle.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getLayout', - ol.geom.Circle.prototype.getLayout); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getClosestPoint', - ol.geom.Circle.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getExtent', - ol.geom.Circle.prototype.getExtent); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'simplify', - ol.geom.Circle.prototype.simplify); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'get', - ol.geom.Circle.prototype.get); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getKeys', - ol.geom.Circle.prototype.getKeys); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getProperties', - ol.geom.Circle.prototype.getProperties); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'set', - ol.geom.Circle.prototype.set); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'setProperties', - ol.geom.Circle.prototype.setProperties); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'unset', - ol.geom.Circle.prototype.unset); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'changed', - ol.geom.Circle.prototype.changed); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'dispatchEvent', - ol.geom.Circle.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'getRevision', - ol.geom.Circle.prototype.getRevision); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'on', - ol.geom.Circle.prototype.on); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'once', - ol.geom.Circle.prototype.once); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'un', - ol.geom.Circle.prototype.un); - -goog.exportProperty( - ol.geom.Circle.prototype, - 'unByKey', - ol.geom.Circle.prototype.unByKey); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getClosestPoint', - ol.geom.GeometryCollection.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getExtent', - ol.geom.GeometryCollection.prototype.getExtent); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'simplify', - ol.geom.GeometryCollection.prototype.simplify); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'transform', - ol.geom.GeometryCollection.prototype.transform); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'get', - ol.geom.GeometryCollection.prototype.get); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getKeys', - ol.geom.GeometryCollection.prototype.getKeys); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getProperties', - ol.geom.GeometryCollection.prototype.getProperties); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'set', - ol.geom.GeometryCollection.prototype.set); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'setProperties', - ol.geom.GeometryCollection.prototype.setProperties); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'unset', - ol.geom.GeometryCollection.prototype.unset); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'changed', - ol.geom.GeometryCollection.prototype.changed); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'dispatchEvent', - ol.geom.GeometryCollection.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'getRevision', - ol.geom.GeometryCollection.prototype.getRevision); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'on', - ol.geom.GeometryCollection.prototype.on); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'once', - ol.geom.GeometryCollection.prototype.once); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'un', - ol.geom.GeometryCollection.prototype.un); - -goog.exportProperty( - ol.geom.GeometryCollection.prototype, - 'unByKey', - ol.geom.GeometryCollection.prototype.unByKey); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getFirstCoordinate', - ol.geom.LinearRing.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getLastCoordinate', - ol.geom.LinearRing.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getLayout', - ol.geom.LinearRing.prototype.getLayout); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getClosestPoint', - ol.geom.LinearRing.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getExtent', - ol.geom.LinearRing.prototype.getExtent); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'simplify', - ol.geom.LinearRing.prototype.simplify); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'transform', - ol.geom.LinearRing.prototype.transform); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'get', - ol.geom.LinearRing.prototype.get); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getKeys', - ol.geom.LinearRing.prototype.getKeys); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getProperties', - ol.geom.LinearRing.prototype.getProperties); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'set', - ol.geom.LinearRing.prototype.set); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'setProperties', - ol.geom.LinearRing.prototype.setProperties); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'unset', - ol.geom.LinearRing.prototype.unset); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'changed', - ol.geom.LinearRing.prototype.changed); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'dispatchEvent', - ol.geom.LinearRing.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'getRevision', - ol.geom.LinearRing.prototype.getRevision); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'on', - ol.geom.LinearRing.prototype.on); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'once', - ol.geom.LinearRing.prototype.once); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'un', - ol.geom.LinearRing.prototype.un); - -goog.exportProperty( - ol.geom.LinearRing.prototype, - 'unByKey', - ol.geom.LinearRing.prototype.unByKey); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getFirstCoordinate', - ol.geom.LineString.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getLastCoordinate', - ol.geom.LineString.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getLayout', - ol.geom.LineString.prototype.getLayout); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getClosestPoint', - ol.geom.LineString.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getExtent', - ol.geom.LineString.prototype.getExtent); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'simplify', - ol.geom.LineString.prototype.simplify); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'transform', - ol.geom.LineString.prototype.transform); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'get', - ol.geom.LineString.prototype.get); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getKeys', - ol.geom.LineString.prototype.getKeys); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getProperties', - ol.geom.LineString.prototype.getProperties); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'set', - ol.geom.LineString.prototype.set); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'setProperties', - ol.geom.LineString.prototype.setProperties); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'unset', - ol.geom.LineString.prototype.unset); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'changed', - ol.geom.LineString.prototype.changed); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'dispatchEvent', - ol.geom.LineString.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'getRevision', - ol.geom.LineString.prototype.getRevision); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'on', - ol.geom.LineString.prototype.on); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'once', - ol.geom.LineString.prototype.once); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'un', - ol.geom.LineString.prototype.un); - -goog.exportProperty( - ol.geom.LineString.prototype, - 'unByKey', - ol.geom.LineString.prototype.unByKey); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getFirstCoordinate', - ol.geom.MultiLineString.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getLastCoordinate', - ol.geom.MultiLineString.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getLayout', - ol.geom.MultiLineString.prototype.getLayout); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getClosestPoint', - ol.geom.MultiLineString.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getExtent', - ol.geom.MultiLineString.prototype.getExtent); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'simplify', - ol.geom.MultiLineString.prototype.simplify); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'transform', - ol.geom.MultiLineString.prototype.transform); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'get', - ol.geom.MultiLineString.prototype.get); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getKeys', - ol.geom.MultiLineString.prototype.getKeys); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getProperties', - ol.geom.MultiLineString.prototype.getProperties); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'set', - ol.geom.MultiLineString.prototype.set); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'setProperties', - ol.geom.MultiLineString.prototype.setProperties); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'unset', - ol.geom.MultiLineString.prototype.unset); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'changed', - ol.geom.MultiLineString.prototype.changed); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'dispatchEvent', - ol.geom.MultiLineString.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'getRevision', - ol.geom.MultiLineString.prototype.getRevision); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'on', - ol.geom.MultiLineString.prototype.on); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'once', - ol.geom.MultiLineString.prototype.once); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'un', - ol.geom.MultiLineString.prototype.un); - -goog.exportProperty( - ol.geom.MultiLineString.prototype, - 'unByKey', - ol.geom.MultiLineString.prototype.unByKey); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getFirstCoordinate', - ol.geom.MultiPoint.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getLastCoordinate', - ol.geom.MultiPoint.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getLayout', - ol.geom.MultiPoint.prototype.getLayout); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getClosestPoint', - ol.geom.MultiPoint.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getExtent', - ol.geom.MultiPoint.prototype.getExtent); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'simplify', - ol.geom.MultiPoint.prototype.simplify); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'transform', - ol.geom.MultiPoint.prototype.transform); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'get', - ol.geom.MultiPoint.prototype.get); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getKeys', - ol.geom.MultiPoint.prototype.getKeys); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getProperties', - ol.geom.MultiPoint.prototype.getProperties); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'set', - ol.geom.MultiPoint.prototype.set); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'setProperties', - ol.geom.MultiPoint.prototype.setProperties); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'unset', - ol.geom.MultiPoint.prototype.unset); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'changed', - ol.geom.MultiPoint.prototype.changed); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'dispatchEvent', - ol.geom.MultiPoint.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'getRevision', - ol.geom.MultiPoint.prototype.getRevision); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'on', - ol.geom.MultiPoint.prototype.on); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'once', - ol.geom.MultiPoint.prototype.once); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'un', - ol.geom.MultiPoint.prototype.un); - -goog.exportProperty( - ol.geom.MultiPoint.prototype, - 'unByKey', - ol.geom.MultiPoint.prototype.unByKey); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getFirstCoordinate', - ol.geom.MultiPolygon.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getLastCoordinate', - ol.geom.MultiPolygon.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getLayout', - ol.geom.MultiPolygon.prototype.getLayout); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getClosestPoint', - ol.geom.MultiPolygon.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getExtent', - ol.geom.MultiPolygon.prototype.getExtent); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'simplify', - ol.geom.MultiPolygon.prototype.simplify); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'transform', - ol.geom.MultiPolygon.prototype.transform); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'get', - ol.geom.MultiPolygon.prototype.get); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getKeys', - ol.geom.MultiPolygon.prototype.getKeys); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getProperties', - ol.geom.MultiPolygon.prototype.getProperties); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'set', - ol.geom.MultiPolygon.prototype.set); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'setProperties', - ol.geom.MultiPolygon.prototype.setProperties); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'unset', - ol.geom.MultiPolygon.prototype.unset); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'changed', - ol.geom.MultiPolygon.prototype.changed); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'dispatchEvent', - ol.geom.MultiPolygon.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'getRevision', - ol.geom.MultiPolygon.prototype.getRevision); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'on', - ol.geom.MultiPolygon.prototype.on); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'once', - ol.geom.MultiPolygon.prototype.once); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'un', - ol.geom.MultiPolygon.prototype.un); - -goog.exportProperty( - ol.geom.MultiPolygon.prototype, - 'unByKey', - ol.geom.MultiPolygon.prototype.unByKey); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getFirstCoordinate', - ol.geom.Point.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getLastCoordinate', - ol.geom.Point.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getLayout', - ol.geom.Point.prototype.getLayout); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getClosestPoint', - ol.geom.Point.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getExtent', - ol.geom.Point.prototype.getExtent); - -goog.exportProperty( - ol.geom.Point.prototype, - 'simplify', - ol.geom.Point.prototype.simplify); - -goog.exportProperty( - ol.geom.Point.prototype, - 'transform', - ol.geom.Point.prototype.transform); - -goog.exportProperty( - ol.geom.Point.prototype, - 'get', - ol.geom.Point.prototype.get); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getKeys', - ol.geom.Point.prototype.getKeys); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getProperties', - ol.geom.Point.prototype.getProperties); - -goog.exportProperty( - ol.geom.Point.prototype, - 'set', - ol.geom.Point.prototype.set); - -goog.exportProperty( - ol.geom.Point.prototype, - 'setProperties', - ol.geom.Point.prototype.setProperties); - -goog.exportProperty( - ol.geom.Point.prototype, - 'unset', - ol.geom.Point.prototype.unset); - -goog.exportProperty( - ol.geom.Point.prototype, - 'changed', - ol.geom.Point.prototype.changed); - -goog.exportProperty( - ol.geom.Point.prototype, - 'dispatchEvent', - ol.geom.Point.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.Point.prototype, - 'getRevision', - ol.geom.Point.prototype.getRevision); - -goog.exportProperty( - ol.geom.Point.prototype, - 'on', - ol.geom.Point.prototype.on); - -goog.exportProperty( - ol.geom.Point.prototype, - 'once', - ol.geom.Point.prototype.once); - -goog.exportProperty( - ol.geom.Point.prototype, - 'un', - ol.geom.Point.prototype.un); - -goog.exportProperty( - ol.geom.Point.prototype, - 'unByKey', - ol.geom.Point.prototype.unByKey); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getFirstCoordinate', - ol.geom.Polygon.prototype.getFirstCoordinate); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getLastCoordinate', - ol.geom.Polygon.prototype.getLastCoordinate); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getLayout', - ol.geom.Polygon.prototype.getLayout); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getClosestPoint', - ol.geom.Polygon.prototype.getClosestPoint); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getExtent', - ol.geom.Polygon.prototype.getExtent); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'simplify', - ol.geom.Polygon.prototype.simplify); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'transform', - ol.geom.Polygon.prototype.transform); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'get', - ol.geom.Polygon.prototype.get); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getKeys', - ol.geom.Polygon.prototype.getKeys); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getProperties', - ol.geom.Polygon.prototype.getProperties); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'set', - ol.geom.Polygon.prototype.set); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'setProperties', - ol.geom.Polygon.prototype.setProperties); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'unset', - ol.geom.Polygon.prototype.unset); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'changed', - ol.geom.Polygon.prototype.changed); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'dispatchEvent', - ol.geom.Polygon.prototype.dispatchEvent); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'getRevision', - ol.geom.Polygon.prototype.getRevision); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'on', - ol.geom.Polygon.prototype.on); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'once', - ol.geom.Polygon.prototype.once); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'un', - ol.geom.Polygon.prototype.un); - -goog.exportProperty( - ol.geom.Polygon.prototype, - 'unByKey', - ol.geom.Polygon.prototype.unByKey); - -goog.exportProperty( - ol.format.GML2.prototype, - 'readFeatures', - ol.format.GML2.prototype.readFeatures); - -goog.exportProperty( - ol.format.GML3.prototype, - 'readFeatures', - ol.format.GML3.prototype.readFeatures); - -goog.exportProperty( - ol.format.GML.prototype, - 'readFeatures', - ol.format.GML.prototype.readFeatures); - -goog.exportProperty( - ol.control.Control.prototype, - 'get', - ol.control.Control.prototype.get); - -goog.exportProperty( - ol.control.Control.prototype, - 'getKeys', - ol.control.Control.prototype.getKeys); - -goog.exportProperty( - ol.control.Control.prototype, - 'getProperties', - ol.control.Control.prototype.getProperties); - -goog.exportProperty( - ol.control.Control.prototype, - 'set', - ol.control.Control.prototype.set); - -goog.exportProperty( - ol.control.Control.prototype, - 'setProperties', - ol.control.Control.prototype.setProperties); - -goog.exportProperty( - ol.control.Control.prototype, - 'unset', - ol.control.Control.prototype.unset); - -goog.exportProperty( - ol.control.Control.prototype, - 'changed', - ol.control.Control.prototype.changed); - -goog.exportProperty( - ol.control.Control.prototype, - 'dispatchEvent', - ol.control.Control.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.Control.prototype, - 'getRevision', - ol.control.Control.prototype.getRevision); - -goog.exportProperty( - ol.control.Control.prototype, - 'on', - ol.control.Control.prototype.on); - -goog.exportProperty( - ol.control.Control.prototype, - 'once', - ol.control.Control.prototype.once); - -goog.exportProperty( - ol.control.Control.prototype, - 'un', - ol.control.Control.prototype.un); - -goog.exportProperty( - ol.control.Control.prototype, - 'unByKey', - ol.control.Control.prototype.unByKey); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'getMap', - ol.control.Attribution.prototype.getMap); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'setMap', - ol.control.Attribution.prototype.setMap); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'setTarget', - ol.control.Attribution.prototype.setTarget); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'get', - ol.control.Attribution.prototype.get); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'getKeys', - ol.control.Attribution.prototype.getKeys); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'getProperties', - ol.control.Attribution.prototype.getProperties); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'set', - ol.control.Attribution.prototype.set); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'setProperties', - ol.control.Attribution.prototype.setProperties); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'unset', - ol.control.Attribution.prototype.unset); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'changed', - ol.control.Attribution.prototype.changed); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'dispatchEvent', - ol.control.Attribution.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'getRevision', - ol.control.Attribution.prototype.getRevision); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'on', - ol.control.Attribution.prototype.on); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'once', - ol.control.Attribution.prototype.once); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'un', - ol.control.Attribution.prototype.un); - -goog.exportProperty( - ol.control.Attribution.prototype, - 'unByKey', - ol.control.Attribution.prototype.unByKey); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'getMap', - ol.control.FullScreen.prototype.getMap); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'setMap', - ol.control.FullScreen.prototype.setMap); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'setTarget', - ol.control.FullScreen.prototype.setTarget); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'get', - ol.control.FullScreen.prototype.get); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'getKeys', - ol.control.FullScreen.prototype.getKeys); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'getProperties', - ol.control.FullScreen.prototype.getProperties); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'set', - ol.control.FullScreen.prototype.set); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'setProperties', - ol.control.FullScreen.prototype.setProperties); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'unset', - ol.control.FullScreen.prototype.unset); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'changed', - ol.control.FullScreen.prototype.changed); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'dispatchEvent', - ol.control.FullScreen.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'getRevision', - ol.control.FullScreen.prototype.getRevision); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'on', - ol.control.FullScreen.prototype.on); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'once', - ol.control.FullScreen.prototype.once); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'un', - ol.control.FullScreen.prototype.un); - -goog.exportProperty( - ol.control.FullScreen.prototype, - 'unByKey', - ol.control.FullScreen.prototype.unByKey); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'getMap', - ol.control.MousePosition.prototype.getMap); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'setMap', - ol.control.MousePosition.prototype.setMap); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'setTarget', - ol.control.MousePosition.prototype.setTarget); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'get', - ol.control.MousePosition.prototype.get); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'getKeys', - ol.control.MousePosition.prototype.getKeys); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'getProperties', - ol.control.MousePosition.prototype.getProperties); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'set', - ol.control.MousePosition.prototype.set); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'setProperties', - ol.control.MousePosition.prototype.setProperties); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'unset', - ol.control.MousePosition.prototype.unset); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'changed', - ol.control.MousePosition.prototype.changed); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'dispatchEvent', - ol.control.MousePosition.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'getRevision', - ol.control.MousePosition.prototype.getRevision); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'on', - ol.control.MousePosition.prototype.on); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'once', - ol.control.MousePosition.prototype.once); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'un', - ol.control.MousePosition.prototype.un); - -goog.exportProperty( - ol.control.MousePosition.prototype, - 'unByKey', - ol.control.MousePosition.prototype.unByKey); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getMap', - ol.control.OverviewMap.prototype.getMap); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'setMap', - ol.control.OverviewMap.prototype.setMap); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'setTarget', - ol.control.OverviewMap.prototype.setTarget); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'get', - ol.control.OverviewMap.prototype.get); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getKeys', - ol.control.OverviewMap.prototype.getKeys); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getProperties', - ol.control.OverviewMap.prototype.getProperties); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'set', - ol.control.OverviewMap.prototype.set); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'setProperties', - ol.control.OverviewMap.prototype.setProperties); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'unset', - ol.control.OverviewMap.prototype.unset); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'changed', - ol.control.OverviewMap.prototype.changed); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'dispatchEvent', - ol.control.OverviewMap.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'getRevision', - ol.control.OverviewMap.prototype.getRevision); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'on', - ol.control.OverviewMap.prototype.on); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'once', - ol.control.OverviewMap.prototype.once); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'un', - ol.control.OverviewMap.prototype.un); - -goog.exportProperty( - ol.control.OverviewMap.prototype, - 'unByKey', - ol.control.OverviewMap.prototype.unByKey); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'getMap', - ol.control.Rotate.prototype.getMap); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'setMap', - ol.control.Rotate.prototype.setMap); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'setTarget', - ol.control.Rotate.prototype.setTarget); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'get', - ol.control.Rotate.prototype.get); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'getKeys', - ol.control.Rotate.prototype.getKeys); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'getProperties', - ol.control.Rotate.prototype.getProperties); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'set', - ol.control.Rotate.prototype.set); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'setProperties', - ol.control.Rotate.prototype.setProperties); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'unset', - ol.control.Rotate.prototype.unset); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'changed', - ol.control.Rotate.prototype.changed); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'dispatchEvent', - ol.control.Rotate.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'getRevision', - ol.control.Rotate.prototype.getRevision); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'on', - ol.control.Rotate.prototype.on); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'once', - ol.control.Rotate.prototype.once); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'un', - ol.control.Rotate.prototype.un); - -goog.exportProperty( - ol.control.Rotate.prototype, - 'unByKey', - ol.control.Rotate.prototype.unByKey); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'getMap', - ol.control.ScaleLine.prototype.getMap); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'setMap', - ol.control.ScaleLine.prototype.setMap); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'setTarget', - ol.control.ScaleLine.prototype.setTarget); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'get', - ol.control.ScaleLine.prototype.get); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'getKeys', - ol.control.ScaleLine.prototype.getKeys); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'getProperties', - ol.control.ScaleLine.prototype.getProperties); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'set', - ol.control.ScaleLine.prototype.set); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'setProperties', - ol.control.ScaleLine.prototype.setProperties); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'unset', - ol.control.ScaleLine.prototype.unset); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'changed', - ol.control.ScaleLine.prototype.changed); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'dispatchEvent', - ol.control.ScaleLine.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'getRevision', - ol.control.ScaleLine.prototype.getRevision); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'on', - ol.control.ScaleLine.prototype.on); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'once', - ol.control.ScaleLine.prototype.once); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'un', - ol.control.ScaleLine.prototype.un); - -goog.exportProperty( - ol.control.ScaleLine.prototype, - 'unByKey', - ol.control.ScaleLine.prototype.unByKey); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'getMap', - ol.control.Zoom.prototype.getMap); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'setMap', - ol.control.Zoom.prototype.setMap); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'setTarget', - ol.control.Zoom.prototype.setTarget); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'get', - ol.control.Zoom.prototype.get); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'getKeys', - ol.control.Zoom.prototype.getKeys); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'getProperties', - ol.control.Zoom.prototype.getProperties); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'set', - ol.control.Zoom.prototype.set); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'setProperties', - ol.control.Zoom.prototype.setProperties); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'unset', - ol.control.Zoom.prototype.unset); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'changed', - ol.control.Zoom.prototype.changed); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'dispatchEvent', - ol.control.Zoom.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'getRevision', - ol.control.Zoom.prototype.getRevision); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'on', - ol.control.Zoom.prototype.on); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'once', - ol.control.Zoom.prototype.once); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'un', - ol.control.Zoom.prototype.un); - -goog.exportProperty( - ol.control.Zoom.prototype, - 'unByKey', - ol.control.Zoom.prototype.unByKey); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'getMap', - ol.control.ZoomSlider.prototype.getMap); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'setMap', - ol.control.ZoomSlider.prototype.setMap); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'setTarget', - ol.control.ZoomSlider.prototype.setTarget); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'get', - ol.control.ZoomSlider.prototype.get); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'getKeys', - ol.control.ZoomSlider.prototype.getKeys); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'getProperties', - ol.control.ZoomSlider.prototype.getProperties); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'set', - ol.control.ZoomSlider.prototype.set); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'setProperties', - ol.control.ZoomSlider.prototype.setProperties); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'unset', - ol.control.ZoomSlider.prototype.unset); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'changed', - ol.control.ZoomSlider.prototype.changed); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'dispatchEvent', - ol.control.ZoomSlider.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'getRevision', - ol.control.ZoomSlider.prototype.getRevision); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'on', - ol.control.ZoomSlider.prototype.on); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'once', - ol.control.ZoomSlider.prototype.once); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'un', - ol.control.ZoomSlider.prototype.un); - -goog.exportProperty( - ol.control.ZoomSlider.prototype, - 'unByKey', - ol.control.ZoomSlider.prototype.unByKey); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'getMap', - ol.control.ZoomToExtent.prototype.getMap); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'setMap', - ol.control.ZoomToExtent.prototype.setMap); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'setTarget', - ol.control.ZoomToExtent.prototype.setTarget); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'get', - ol.control.ZoomToExtent.prototype.get); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'getKeys', - ol.control.ZoomToExtent.prototype.getKeys); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'getProperties', - ol.control.ZoomToExtent.prototype.getProperties); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'set', - ol.control.ZoomToExtent.prototype.set); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'setProperties', - ol.control.ZoomToExtent.prototype.setProperties); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'unset', - ol.control.ZoomToExtent.prototype.unset); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'changed', - ol.control.ZoomToExtent.prototype.changed); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'dispatchEvent', - ol.control.ZoomToExtent.prototype.dispatchEvent); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'getRevision', - ol.control.ZoomToExtent.prototype.getRevision); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'on', - ol.control.ZoomToExtent.prototype.on); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'once', - ol.control.ZoomToExtent.prototype.once); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'un', - ol.control.ZoomToExtent.prototype.un); - -goog.exportProperty( - ol.control.ZoomToExtent.prototype, - 'unByKey', - ol.control.ZoomToExtent.prototype.unByKey); -OPENLAYERS.ol = ol; - - return OPENLAYERS.ol; -})); diff --git a/src/lib/ol.js b/src/lib/ol.js deleted file mode 100644 index ed68c221a4..0000000000 --- a/src/lib/ol.js +++ /dev/null @@ -1,618 +0,0 @@ -// OpenLayers 3. See http://openlayers.org/ -// License: https://raw.githubusercontent.com/openlayers/ol3/master/LICENSE.md -// Version: v3.11.1-86-g627abaf - -(function (root, factory) { - if (typeof exports === "object") { - module.exports = factory(); - } else if (typeof define === "function" && define.amd) { - define([], factory); - } else { - root.ol = factory(); - } -}(this, function () { - var OPENLAYERS = {}; - var k,aa=aa||{},ba=this;function ca(a){return void 0!==a}function v(a,c,d){a=a.split(".");d=d||ba;a[0]in d||!d.execScript||d.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&ca(c)?d[e]=c:d[e]?d=d[e]:d=d[e]={}}function da(){} -function ea(a){var c=typeof a;if("object"==c)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return c;var d=Object.prototype.toString.call(a);if("[object Window]"==d)return"object";if("[object Array]"==d||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==d||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; -else if("function"==c&&"undefined"==typeof a.call)return"object";return c}function fa(a){return"array"==ea(a)}function ga(a){var c=ea(a);return"array"==c||"object"==c&&"number"==typeof a.length}function ha(a){return"string"==typeof a}function ka(a){return"number"==typeof a}function la(a){return"function"==ea(a)}function ma(a){var c=typeof a;return"object"==c&&null!=a||"function"==c}function na(a){return a[oa]||(a[oa]=++pa)}var oa="closure_uid_"+(1E9*Math.random()>>>0),pa=0; -function qa(a,c,d){return a.call.apply(a.bind,arguments)}function ra(a,c,d){if(!a)throw Error();if(2<arguments.length){var e=Array.prototype.slice.call(arguments,2);return function(){var d=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(d,e);return a.apply(c,d)}}return function(){return a.apply(c,arguments)}}function sa(a,c,d){sa=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?qa:ra;return sa.apply(null,arguments)} -function ta(a,c){var d=Array.prototype.slice.call(arguments,1);return function(){var c=d.slice();c.push.apply(c,arguments);return a.apply(this,c)}}var ua=Date.now||function(){return+new Date};function x(a,c){function d(){}d.prototype=c.prototype;a.fa=c.prototype;a.prototype=new d;a.prototype.constructor=a;a.Kk=function(a,d,g){for(var h=Array(arguments.length-2),l=2;l<arguments.length;l++)h[l-2]=arguments[l];return c.prototype[d].apply(a,h)}};function wa(){};var xa;var ya=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")};function Ba(a){if(!Da.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(Fa,"&"));-1!=a.indexOf("<")&&(a=a.replace(Ga,"<"));-1!=a.indexOf(">")&&(a=a.replace(Ha,">"));-1!=a.indexOf('"')&&(a=a.replace(Ia,"""));-1!=a.indexOf("'")&&(a=a.replace(Ja,"'"));-1!=a.indexOf("\x00")&&(a=a.replace(Ka,"�"));return a} -var Fa=/&/g,Ga=/</g,Ha=/>/g,Ia=/"/g,Ja=/'/g,Ka=/\x00/g,Da=/[\x00&<>"']/,La=String.prototype.repeat?function(a,c){return a.repeat(c)}:function(a,c){return Array(c+1).join(a)};function Ma(a){a=ca(void 0)?a.toFixed(void 0):String(a);var c=a.indexOf(".");-1==c&&(c=a.length);return La("0",Math.max(0,2-c))+a} -function Na(a,c){for(var d=0,e=ya(String(a)).split("."),f=ya(String(c)).split("."),g=Math.max(e.length,f.length),h=0;0==d&&h<g;h++){var l=e[h]||"",m=f[h]||"",n=RegExp("(\\d*)(\\D*)","g"),p=RegExp("(\\d*)(\\D*)","g");do{var q=n.exec(l)||["","",""],r=p.exec(m)||["","",""];if(0==q[0].length&&0==r[0].length)break;d=Oa(0==q[1].length?0:parseInt(q[1],10),0==r[1].length?0:parseInt(r[1],10))||Oa(0==q[2].length,0==r[2].length)||Oa(q[2],r[2])}while(0==d)}return d}function Oa(a,c){return a<c?-1:a>c?1:0};function Pa(a,c,d){return Math.min(Math.max(a,c),d)}var Qa=function(){var a;"cosh"in Math?a=Math.cosh:a=function(a){a=Math.exp(a);return(a+1/a)/2};return a}();function Ra(a,c,d,e){a=d-a;c=e-c;return a*a+c*c}function Sa(a){return a*Math.PI/180};function Ta(a){return function(c){if(c)return[Pa(c[0],a[0],a[2]),Pa(c[1],a[1],a[3])]}}function Va(a){return a};var Wa=Array.prototype;function Xa(a,c){Wa.forEach.call(a,c,void 0)}function Ya(a,c){return Wa.filter.call(a,c,void 0)}function Za(a){var c;a:{c=ab;for(var d=a.length,e=ha(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&c.call(void 0,e[f],f,a)){c=f;break a}c=-1}return 0>c?null:ha(a)?a.charAt(c):a[c]}function bb(a,c){var d=Wa.indexOf.call(a,c,void 0),e;(e=0<=d)&&Wa.splice.call(a,d,1);return e}function cb(a){return Wa.concat.apply(Wa,arguments)} -function db(a){var c=a.length;if(0<c){for(var d=Array(c),e=0;e<c;e++)d[e]=a[e];return d}return[]}function eb(a,c){for(var d=1;d<arguments.length;d++){var e=arguments[d];if(ga(e)){var f=a.length||0,g=e.length||0;a.length=f+g;for(var h=0;h<g;h++)a[f+h]=e[h]}else a.push(e)}}function hb(a,c,d,e){Wa.splice.apply(a,ib(arguments,1))}function ib(a,c,d){return 2>=arguments.length?Wa.slice.call(a,c):Wa.slice.call(a,c,d)}function jb(a,c){a.sort(c||kb)} -function lb(a){for(var c=mb,d=0;d<a.length;d++)a[d]={index:d,value:a[d]};var e=c||kb;jb(a,function(a,c){return e(a.value,c.value)||a.index-c.index});for(d=0;d<a.length;d++)a[d]=a[d].value}function nb(a,c){if(!ga(a)||!ga(c)||a.length!=c.length)return!1;for(var d=a.length,e=ob,f=0;f<d;f++)if(!e(a[f],c[f]))return!1;return!0}function kb(a,c){return a>c?1:a<c?-1:0}function ob(a,c){return a===c};function pb(a,c,d){var e=a.length;if(a[0]<=c)return 0;if(!(c<=a[e-1]))if(0<d)for(d=1;d<e;++d){if(a[d]<c)return d-1}else if(0>d)for(d=1;d<e;++d){if(a[d]<=c)return d}else for(d=1;d<e;++d){if(a[d]==c)return d;if(a[d]<c)return a[d-1]-c<c-a[d]?d-1:d}return e-1};function qb(a){return function(c,d,e){if(void 0!==c)return c=pb(a,c,e),c=Pa(c+d,0,a.length-1),a[c]}}function rb(a,c,d){return function(e,f,g){if(void 0!==e)return e=Math.max(Math.floor(Math.log(c/e)/Math.log(a)+(0<g?0:0>g?1:.5))+f,0),void 0!==d&&(e=Math.min(e,d)),c/Math.pow(a,e)}};function sb(a){if(void 0!==a)return 0}function tb(a,c){if(void 0!==a)return a+c}function ub(a){var c=2*Math.PI/a;return function(a,e){if(void 0!==a)return a=Math.floor((a+e)/c+.5)*c}}function vb(){var a=Sa(5);return function(c,d){if(void 0!==c)return Math.abs(c+d)<=a?0:c+d}};function wb(a,c,d){this.center=a;this.resolution=c;this.rotation=d};var xb;a:{var yb=ba.navigator;if(yb){var zb=yb.userAgent;if(zb){xb=zb;break a}}xb=""}function Ab(a){return-1!=xb.indexOf(a)};function Bb(a,c,d){for(var e in a)c.call(d,a[e],e,a)}function Cb(a,c){for(var d in a)if(c.call(void 0,a[d],d,a))return!0;return!1}function Db(a){var c=0,d;for(d in a)c++;return c}function Eb(a){var c=[],d=0,e;for(e in a)c[d++]=a[e];return c}function Fb(a){var c=[],d=0,e;for(e in a)c[d++]=e;return c}function Gb(a){for(var c in a)return!1;return!0}function Hb(a){for(var c in a)delete a[c]}function Ib(a,c,d){return c in a?a[c]:d}function Jb(a,c){var d=[];return c in a?a[c]:a[c]=d} -function Kb(a){var c={},d;for(d in a)c[d]=a[d];return c}function Lb(a){var c=ea(a);if("object"==c||"array"==c){if(la(a.clone))return a.clone();var c="array"==c?[]:{},d;for(d in a)c[d]=Lb(a[d]);return c}return a}var Mb="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "); -function Nb(a,c){for(var d,e,f=1;f<arguments.length;f++){e=arguments[f];for(d in e)a[d]=e[d];for(var g=0;g<Mb.length;g++)d=Mb[g],Object.prototype.hasOwnProperty.call(e,d)&&(a[d]=e[d])}};var Ob=Ab("Opera")||Ab("OPR"),Pb=Ab("Trident")||Ab("MSIE"),Qb=Ab("Edge"),Rb=Ab("Gecko")&&!(-1!=xb.toLowerCase().indexOf("webkit")&&!Ab("Edge"))&&!(Ab("Trident")||Ab("MSIE"))&&!Ab("Edge"),Sb=-1!=xb.toLowerCase().indexOf("webkit")&&!Ab("Edge"),Tb=Ab("Macintosh"),Ub=Ab("Windows"),Wb=Ab("Linux")||Ab("CrOS");function Xb(){var a=xb;if(Rb)return/rv\:([^\);]+)(\)|;)/.exec(a);if(Qb)return/Edge\/([\d\.]+)/.exec(a);if(Pb)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(Sb)return/WebKit\/(\S+)/.exec(a)} -function Yb(){var a=ba.document;return a?a.documentMode:void 0}var Zb=function(){if(Ob&&ba.opera){var a;var c=ba.opera.version;try{a=c()}catch(d){a=c}return a}a="";(c=Xb())&&(a=c?c[1]:"");return Pb&&(c=Yb(),c>parseFloat(a))?String(c):a}(),$b={};function ac(a){return $b[a]||($b[a]=0<=Na(Zb,a))}var bc=ba.document,cc=bc&&Pb?Yb()||("CSS1Compat"==bc.compatMode?parseInt(Zb,10):5):void 0;var dc=!Pb||9<=cc,ec=!Pb||9<=cc,fc=Pb&&!ac("9");!Sb||ac("528");Rb&&ac("1.9b")||Pb&&ac("8")||Ob&&ac("9.5")||Sb&&ac("528");Rb&&!ac("8")||Pb&&ac("9");function gc(){0!=hc&&(ic[na(this)]=this);this.ma=this.ma;this.ia=this.ia}var hc=0,ic={};gc.prototype.ma=!1;gc.prototype.rc=function(){if(!this.ma&&(this.ma=!0,this.Z(),0!=hc)){var a=na(this);delete ic[a]}};function jc(a,c){var d=ta(kc,c);a.ma?d.call(void 0):(a.ia||(a.ia=[]),a.ia.push(ca(void 0)?sa(d,void 0):d))}gc.prototype.Z=function(){if(this.ia)for(;this.ia.length;)this.ia.shift()()};function kc(a){a&&"function"==typeof a.rc&&a.rc()};function lc(a,c){this.type=a;this.g=this.target=c;this.j=!1;this.nf=!0}lc.prototype.i=function(){this.j=!0};lc.prototype.preventDefault=function(){this.nf=!1};function mc(a){a.i()};var nc=Pb?"focusout":"DOMFocusOut";function oc(a){oc[" "](a);return a}oc[" "]=da;function pc(a,c){lc.call(this,a?a.type:"");this.relatedTarget=this.g=this.target=null;this.s=this.c=this.button=this.screenY=this.screenX=this.clientY=this.clientX=this.offsetY=this.offsetX=0;this.u=this.f=this.a=this.A=!1;this.state=null;this.l=!1;this.b=null;if(a){var d=this.type=a.type,e=a.changedTouches?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.g=c;var f=a.relatedTarget;if(f){if(Rb){var g;a:{try{oc(f.nodeName);g=!0;break a}catch(h){}g=!1}g||(f=null)}}else"mouseover"==d? -f=a.fromElement:"mouseout"==d&&(f=a.toElement);this.relatedTarget=f;null===e?(this.offsetX=Sb||void 0!==a.offsetX?a.offsetX:a.layerX,this.offsetY=Sb||void 0!==a.offsetY?a.offsetY:a.layerY,this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0):(this.clientX=void 0!==e.clientX?e.clientX:e.pageX,this.clientY=void 0!==e.clientY?e.clientY:e.pageY,this.screenX=e.screenX||0,this.screenY=e.screenY||0);this.button= -a.button;this.c=a.keyCode||0;this.s=a.charCode||("keypress"==d?a.keyCode:0);this.A=a.ctrlKey;this.a=a.altKey;this.f=a.shiftKey;this.u=a.metaKey;this.l=Tb?a.metaKey:a.ctrlKey;this.state=a.state;this.b=a;a.defaultPrevented&&this.preventDefault()}}x(pc,lc);var qc=[1,4,2];function rc(a){return(dc?0==a.b.button:"click"==a.type?!0:!!(a.b.button&qc[0]))&&!(Sb&&Tb&&a.A)}pc.prototype.i=function(){pc.fa.i.call(this);this.b.stopPropagation?this.b.stopPropagation():this.b.cancelBubble=!0}; -pc.prototype.preventDefault=function(){pc.fa.preventDefault.call(this);var a=this.b;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,fc)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(c){}};var sc="closure_listenable_"+(1E6*Math.random()|0);function tc(a){return!(!a||!a[sc])}var uc=0;function vc(a,c,d,e,f){this.listener=a;this.b=null;this.src=c;this.type=d;this.Jb=!!e;this.zc=f;this.key=++uc;this.Eb=this.oc=!1}function wc(a){a.Eb=!0;a.listener=null;a.b=null;a.src=null;a.zc=null};function xc(a){this.src=a;this.b={};this.a=0}xc.prototype.add=function(a,c,d,e,f){var g=a.toString();a=this.b[g];a||(a=this.b[g]=[],this.a++);var h=yc(a,c,e,f);-1<h?(c=a[h],d||(c.oc=!1)):(c=new vc(c,this.src,g,!!e,f),c.oc=d,a.push(c));return c};xc.prototype.remove=function(a,c,d,e){a=a.toString();if(!(a in this.b))return!1;var f=this.b[a];c=yc(f,c,d,e);return-1<c?(wc(f[c]),Wa.splice.call(f,c,1),0==f.length&&(delete this.b[a],this.a--),!0):!1}; -function zc(a,c){var d=c.type;if(!(d in a.b))return!1;var e=bb(a.b[d],c);e&&(wc(c),0==a.b[d].length&&(delete a.b[d],a.a--));return e}function Ac(a,c,d){var e=ca(c),f=e?c.toString():"",g=ca(d);return Cb(a.b,function(a){for(var c=0;c<a.length;++c)if(!(e&&a[c].type!=f||g&&a[c].Jb!=d))return!0;return!1})}function yc(a,c,d,e){for(var f=0;f<a.length;++f){var g=a[f];if(!g.Eb&&g.listener==c&&g.Jb==!!d&&g.zc==e)return f}return-1};var Bc="closure_lm_"+(1E6*Math.random()|0),Cc={},Dc=0;function y(a,c,d,e,f){if(fa(c)){for(var g=0;g<c.length;g++)y(a,c[g],d,e,f);return null}d=Ec(d);return tc(a)?Fc(a,c,d,e,f):Gc(a,c,d,!1,e,f)} -function Gc(a,c,d,e,f,g){if(!c)throw Error("Invalid event type");var h=!!f,l=Hc(a);l||(a[Bc]=l=new xc(a));d=l.add(c,d,e,f,g);if(d.b)return d;e=Ic();d.b=e;e.src=a;e.listener=d;if(a.addEventListener)a.addEventListener(c.toString(),e,h);else if(a.attachEvent)a.attachEvent(Jc(c.toString()),e);else throw Error("addEventListener and attachEvent are unavailable.");Dc++;return d} -function Ic(){var a=Kc,c=ec?function(d){return a.call(c.src,c.listener,d)}:function(d){d=a.call(c.src,c.listener,d);if(!d)return d};return c}function Lc(a,c,d,e,f){if(fa(c)){for(var g=0;g<c.length;g++)Lc(a,c[g],d,e,f);return null}d=Ec(d);return tc(a)?a.La.add(String(c),d,!0,e,f):Gc(a,c,d,!0,e,f)} -function Mc(a,c,d,e,f){if(fa(c))for(var g=0;g<c.length;g++)Mc(a,c[g],d,e,f);else(d=Ec(d),tc(a))?a.La.remove(String(c),d,e,f):a&&(a=Hc(a))&&(c=a.b[c.toString()],a=-1,c&&(a=yc(c,d,!!e,f)),(d=-1<a?c[a]:null)&&Nc(d))}function Nc(a){if(ka(a)||!a||a.Eb)return!1;var c=a.src;if(tc(c))return zc(c.La,a);var d=a.type,e=a.b;c.removeEventListener?c.removeEventListener(d,e,a.Jb):c.detachEvent&&c.detachEvent(Jc(d),e);Dc--;(d=Hc(c))?(zc(d,a),0==d.a&&(d.src=null,c[Bc]=null)):wc(a);return!0} -function Jc(a){return a in Cc?Cc[a]:Cc[a]="on"+a}function Oc(a,c,d,e){var f=!0;if(a=Hc(a))if(c=a.b[c.toString()])for(c=c.concat(),a=0;a<c.length;a++){var g=c[a];g&&g.Jb==d&&!g.Eb&&(g=Pc(g,e),f=f&&!1!==g)}return f}function Pc(a,c){var d=a.listener,e=a.zc||a.src;a.oc&&Nc(a);return d.call(e,c)} -function Kc(a,c){if(a.Eb)return!0;if(!ec){var d;if(!(d=c))a:{d=["window","event"];for(var e=ba,f;f=d.shift();)if(null!=e[f])e=e[f];else{d=null;break a}d=e}f=d;d=new pc(f,this);e=!0;if(!(0>f.keyCode||void 0!=f.returnValue)){a:{var g=!1;if(0==f.keyCode)try{f.keyCode=-1;break a}catch(m){g=!0}if(g||void 0==f.returnValue)f.returnValue=!0}f=[];for(g=d.g;g;g=g.parentNode)f.push(g);for(var g=a.type,h=f.length-1;!d.j&&0<=h;h--){d.g=f[h];var l=Oc(f[h],g,!0,d),e=e&&l}for(h=0;!d.j&&h<f.length;h++)d.g=f[h],l= -Oc(f[h],g,!1,d),e=e&&l}return e}return Pc(a,new pc(c,this))}function Hc(a){a=a[Bc];return a instanceof xc?a:null}var Qc="__closure_events_fn_"+(1E9*Math.random()>>>0);function Ec(a){if(la(a))return a;a[Qc]||(a[Qc]=function(c){return a.handleEvent(c)});return a[Qc]};function Sc(){gc.call(this);this.La=new xc(this);this.mc=this;this.Ua=null}x(Sc,gc);Sc.prototype[sc]=!0;Sc.prototype.addEventListener=function(a,c,d,e){y(this,a,c,d,e)};Sc.prototype.removeEventListener=function(a,c,d,e){Mc(this,a,c,d,e)}; -Sc.prototype.b=function(a){var c,d=this.Ua;if(d)for(c=[];d;d=d.Ua)c.push(d);var d=this.mc,e=a.type||a;if(ha(a))a=new lc(a,d);else if(a instanceof lc)a.target=a.target||d;else{var f=a;a=new lc(e,d);Nb(a,f)}var f=!0,g;if(c)for(var h=c.length-1;!a.j&&0<=h;h--)g=a.g=c[h],f=Tc(g,e,!0,a)&&f;a.j||(g=a.g=d,f=Tc(g,e,!0,a)&&f,a.j||(f=Tc(g,e,!1,a)&&f));if(c)for(h=0;!a.j&&h<c.length;h++)g=a.g=c[h],f=Tc(g,e,!1,a)&&f;return f}; -Sc.prototype.Z=function(){Sc.fa.Z.call(this);if(this.La){var a=this.La,c=0,d;for(d in a.b){for(var e=a.b[d],f=0;f<e.length;f++)++c,wc(e[f]);delete a.b[d];a.a--}}this.Ua=null};function Fc(a,c,d,e,f){return a.La.add(String(c),d,!1,e,f)}function Tc(a,c,d,e){c=a.La.b[String(c)];if(!c)return!0;c=c.concat();for(var f=!0,g=0;g<c.length;++g){var h=c[g];if(h&&!h.Eb&&h.Jb==d){var l=h.listener,m=h.zc||h.src;h.oc&&zc(a.La,h);f=!1!==l.call(m,e)&&f}}return f&&0!=e.nf} -function Uc(a,c,d){return Ac(a.La,ca(c)?String(c):void 0,d)};function Vc(){Sc.call(this);this.g=0}x(Vc,Sc);function Wc(a){Nc(a)}k=Vc.prototype;k.v=function(){++this.g;this.b("change")};k.S=function(){return this.g};k.M=function(a,c,d){return y(this,a,c,!1,d)};k.T=function(a,c,d){return Lc(this,a,c,!1,d)};k.U=function(a,c,d){Mc(this,a,c,!1,d)};k.V=Wc;function Xc(a,c,d){lc.call(this,a);this.key=c;this.oldValue=d}x(Xc,lc);function Yc(a){Vc.call(this);na(this);this.A={};void 0!==a&&this.K(a)}x(Yc,Vc);var Zc={};function $c(a){return Zc.hasOwnProperty(a)?Zc[a]:Zc[a]="change:"+a}k=Yc.prototype;k.get=function(a){var c;this.A.hasOwnProperty(a)&&(c=this.A[a]);return c};k.L=function(){return Object.keys(this.A)};k.P=function(){var a={},c;for(c in this.A)a[c]=this.A[c];return a}; -function ad(a,c,d){var e;e=$c(c);a.b(new Xc(e,c,d));a.b(new Xc("propertychange",c,d))}k.C=function(a,c,d){d?this.A[a]=c:(d=this.A[a],this.A[a]=c,d!==c&&ad(this,a,d))};k.K=function(a,c){for(var d in a)this.C(d,a[d],c)};k.W=function(a,c){if(a in this.A){var d=this.A[a];delete this.A[a];c||ad(this,a,d)}};function bd(a,c,d){void 0===d&&(d=[0,0]);d[0]=a[0]+2*c;d[1]=a[1]+2*c;return d}function cd(a,c,d){void 0===d&&(d=[0,0]);d[0]=a[0]*c+.5|0;d[1]=a[1]*c+.5|0;return d}function dd(a,c){if(fa(a))return a;void 0===c?c=[a,a]:(c[0]=a,c[1]=a);return c};function ed(a,c){var d=a%c;return 0>d*c?d+c:d}function fd(a,c,d){return a+d*(c-a)};function gd(a,c){a[0]+=c[0];a[1]+=c[1]}function hd(a,c){var d=a[0],e=a[1],f=c[0],g=c[1],h=f[0],f=f[1],l=g[0],g=g[1],m=l-h,n=g-f,d=0===m&&0===n?0:(m*(d-h)+n*(e-f))/(m*m+n*n||0);0>=d||(1<=d?(h=l,f=g):(h+=d*m,f+=d*n));return[h,f]}function id(a,c){var d=ed(a+180,360)-180,e=Math.abs(Math.round(3600*d));return Math.floor(e/3600)+"\u00b0 "+Ma(Math.floor(e/60%60))+"\u2032 "+Ma(Math.floor(e%60))+"\u2033 "+c.charAt(0>d?1:0)} -function jd(a,c,d){return a?c.replace("{x}",a[0].toFixed(d)).replace("{y}",a[1].toFixed(d)):""}function kd(a,c){for(var d=!0,e=a.length-1;0<=e;--e)if(a[e]!=c[e]){d=!1;break}return d}function ld(a,c){var d=Math.cos(c),e=Math.sin(c),f=a[1]*d+a[0]*e;a[0]=a[0]*d-a[1]*e;a[1]=f}function md(a,c){var d=a[0]-c[0],e=a[1]-c[1];return d*d+e*e}function nd(a,c){return md(a,hd(a,c))};function od(a){this.length=a.length||a;for(var c=0;c<this.length;c++)this[c]=a[c]||0}od.prototype.b=4;od.prototype.a=function(a,c){c=c||0;for(var d=0;d<a.length&&c+d<this.length;d++)this[c+d]=a[d]};od.prototype.toString=Array.prototype.join;"undefined"==typeof Float32Array&&(od.BYTES_PER_ELEMENT=4,od.prototype.BYTES_PER_ELEMENT=od.prototype.b,od.prototype.set=od.prototype.a,od.prototype.toString=od.prototype.toString,v("Float32Array",od,void 0));function pd(a){this.length=a.length||a;for(var c=0;c<this.length;c++)this[c]=a[c]||0}pd.prototype.b=8;pd.prototype.a=function(a,c){c=c||0;for(var d=0;d<a.length&&c+d<this.length;d++)this[c+d]=a[d]};pd.prototype.toString=Array.prototype.join;if("undefined"==typeof Float64Array){try{pd.BYTES_PER_ELEMENT=8}catch(a){}pd.prototype.BYTES_PER_ELEMENT=pd.prototype.b;pd.prototype.set=pd.prototype.a;pd.prototype.toString=pd.prototype.toString;v("Float64Array",pd,void 0)};function qd(){var a=Array(16);a[0]=0;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=0;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=0;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=0;return a} -function sd(a,c){var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],l=a[5],m=a[6],n=a[7],p=a[8],q=a[9],r=a[10],t=a[11],B=a[12],V=a[13],w=a[14],E=a[15],u=d*l-e*h,Ca=d*m-f*h,Ea=d*n-g*h,ia=e*m-f*l,O=e*n-g*l,Aa=f*n-g*m,va=p*V-q*B,fb=p*w-r*B,Ua=p*E-t*B,$a=q*w-r*V,gb=q*E-t*V,ja=r*E-t*w,za=u*ja-Ca*gb+Ea*$a+ia*Ua-O*fb+Aa*va;0!=za&&(za=1/za,c[0]=(l*ja-m*gb+n*$a)*za,c[1]=(-e*ja+f*gb-g*$a)*za,c[2]=(V*Aa-w*O+E*ia)*za,c[3]=(-q*Aa+r*O-t*ia)*za,c[4]=(-h*ja+m*Ua-n*fb)*za,c[5]=(d*ja-f*Ua+g*fb)*za,c[6]=(-B*Aa+w*Ea-E*Ca)*za,c[7]= -(p*Aa-r*Ea+t*Ca)*za,c[8]=(h*gb-l*Ua+n*va)*za,c[9]=(-d*gb+e*Ua-g*va)*za,c[10]=(B*O-V*Ea+E*u)*za,c[11]=(-p*O+q*Ea-t*u)*za,c[12]=(-h*$a+l*fb-m*va)*za,c[13]=(d*$a-e*fb+f*va)*za,c[14]=(-B*ia+V*Ca-w*u)*za,c[15]=(p*ia-q*Ca+r*u)*za)}function td(a,c,d){var e=a[1]*c+a[5]*d+0*a[9]+a[13],f=a[2]*c+a[6]*d+0*a[10]+a[14],g=a[3]*c+a[7]*d+0*a[11]+a[15];a[12]=a[0]*c+a[4]*d+0*a[8]+a[12];a[13]=e;a[14]=f;a[15]=g}new Float64Array(3);new Float64Array(3);new Float64Array(4);new Float64Array(4);new Float64Array(4);new Float64Array(16);function ud(a){for(var c=vd(),d=0,e=a.length;d<e;++d)wd(c,a[d]);return c}function xd(a,c){var d=Math.min.apply(null,a),e=Math.min.apply(null,c),f=Math.max.apply(null,a),g=Math.max.apply(null,c);return yd(d,e,f,g,void 0)}function zd(a,c,d){return d?(d[0]=a[0]-c,d[1]=a[1]-c,d[2]=a[2]+c,d[3]=a[3]+c,d):[a[0]-c,a[1]-c,a[2]+c,a[3]+c]}function Ad(a,c){return c?(c[0]=a[0],c[1]=a[1],c[2]=a[2],c[3]=a[3],c):a.slice()} -function Bd(a,c,d){c=c<a[0]?a[0]-c:a[2]<c?c-a[2]:0;a=d<a[1]?a[1]-d:a[3]<d?d-a[3]:0;return c*c+a*a}function Cd(a,c){return Dd(a,c[0],c[1])}function Ed(a,c){return a[0]<=c[0]&&c[2]<=a[2]&&a[1]<=c[1]&&c[3]<=a[3]}function Dd(a,c,d){return a[0]<=c&&c<=a[2]&&a[1]<=d&&d<=a[3]}function Fd(a,c){var d=a[1],e=a[2],f=a[3],g=c[0],h=c[1],l=0;g<a[0]?l=l|16:g>e&&(l=l|4);h<d?l|=8:h>f&&(l|=2);0===l&&(l=1);return l}function vd(){return[Infinity,Infinity,-Infinity,-Infinity]} -function yd(a,c,d,e,f){return f?(f[0]=a,f[1]=c,f[2]=d,f[3]=e,f):[a,c,d,e]}function Gd(a,c){var d=a[0],e=a[1];return yd(d,e,d,e,c)}function Hd(a,c,d,e,f){f=yd(Infinity,Infinity,-Infinity,-Infinity,f);return Id(f,a,c,d,e)}function Jd(a,c){return a[0]==c[0]&&a[2]==c[2]&&a[1]==c[1]&&a[3]==c[3]}function Kd(a,c){c[0]<a[0]&&(a[0]=c[0]);c[2]>a[2]&&(a[2]=c[2]);c[1]<a[1]&&(a[1]=c[1]);c[3]>a[3]&&(a[3]=c[3])} -function wd(a,c){c[0]<a[0]&&(a[0]=c[0]);c[0]>a[2]&&(a[2]=c[0]);c[1]<a[1]&&(a[1]=c[1]);c[1]>a[3]&&(a[3]=c[1])}function Id(a,c,d,e,f){for(;d<e;d+=f){var g=a,h=c[d],l=c[d+1];g[0]=Math.min(g[0],h);g[1]=Math.min(g[1],l);g[2]=Math.max(g[2],h);g[3]=Math.max(g[3],l)}return a}function Ld(a,c,d){var e;return(e=c.call(d,[a[0],a[1]]))||(e=c.call(d,[a[2],a[1]]))||(e=c.call(d,[a[2],a[3]]))?e:(e=c.call(d,Md(a)))?e:!1}function Nd(a){var c=0;Od(a)||(c=Pd(a)*Qd(a));return c} -function Rd(a){return[(a[0]+a[2])/2,(a[1]+a[3])/2]}function Sd(a,c,d,e){var f=c*e[0]/2;e=c*e[1]/2;c=Math.cos(d);d=Math.sin(d);f=[-f,-f,f,f];e=[-e,e,-e,e];var g,h,l;for(g=0;4>g;++g)h=f[g],l=e[g],f[g]=a[0]+h*c-l*d,e[g]=a[1]+h*d+l*c;return xd(f,e)}function Qd(a){return a[3]-a[1]}function Td(a,c){var d=vd();Ud(a,c)&&(d[0]=a[0]>c[0]?a[0]:c[0],d[1]=a[1]>c[1]?a[1]:c[1],d[2]=a[2]<c[2]?a[2]:c[2],d[3]=a[3]<c[3]?a[3]:c[3]);return d}function Md(a){return[a[0],a[3]]}function Pd(a){return a[2]-a[0]} -function Ud(a,c){return a[0]<=c[2]&&a[2]>=c[0]&&a[1]<=c[3]&&a[3]>=c[1]}function Od(a){return a[2]<a[0]||a[3]<a[1]};function Vd(a){return function(){return a}}var Wd=Vd(!1),Xd=Vd(!0);function Yd(a){var c;c=c||0;return function(){return a.apply(this,Array.prototype.slice.call(arguments,0,c))}}function Zd(a){var c=arguments,d=c.length;return function(){for(var a=0;a<d;a++)if(!c[a].apply(this,arguments))return!1;return!0}};/* - - Latitude/longitude spherical geodesy formulae taken from - http://www.movable-type.co.uk/scripts/latlong.html - Licensed under CC-BY-3.0. -*/ -function $d(a){this.radius=a}function ae(a,c){var d=Sa(a[1]),e=Sa(c[1]),f=(e-d)/2,g=Sa(c[0]-a[0])/2,d=Math.sin(f)*Math.sin(f)+Math.sin(g)*Math.sin(g)*Math.cos(d)*Math.cos(e);return 2*be.radius*Math.atan2(Math.sqrt(d),Math.sqrt(1-d))}$d.prototype.offset=function(a,c,d){var e=Sa(a[1]);c/=this.radius;var f=Math.asin(Math.sin(e)*Math.cos(c)+Math.cos(e)*Math.sin(c)*Math.cos(d));return[180*(Sa(a[0])+Math.atan2(Math.sin(d)*Math.sin(c)*Math.cos(e),Math.cos(c)-Math.sin(e)*Math.sin(f)))/Math.PI,180*f/Math.PI]};var be=new $d(6370997);var ce={};ce.degrees=2*Math.PI*be.radius/360;ce.ft=.3048;ce.m=1;ce["us-ft"]=1200/3937; -function de(a){this.b=a.code;this.g=a.units;this.f=void 0!==a.extent?a.extent:null;this.l=void 0!==a.worldExtent?a.worldExtent:null;this.i=void 0!==a.axisOrientation?a.axisOrientation:"enu";this.c=void 0!==a.global?a.global:!1;this.a=!(!this.c||!this.f);this.A=void 0!==a.getPointResolution?a.getPointResolution:this.Rg;this.j=null;var c=ee,d=a.code;if("function"==typeof proj4&&void 0===c[d]){var e=proj4.defs(d);if(void 0!==e){void 0!==e.axis&&void 0===a.axisOrientation&&(this.i=e.axis);void 0===a.units&& -(a=e.units,void 0===e.to_meter||void 0!==a&&void 0!==ce[a]||(a=e.to_meter.toString(),ce[a]=e.to_meter),this.g=a);var f,g;for(f in c)if(c=proj4.defs(f),void 0!==c)if(a=fe(f),c===e)ge([a,this]);else{g=proj4(f,d);c=g.forward;g=g.inverse;a=fe(a);var h=fe(this);he(a,h,ie(c));he(h,a,ie(g))}}}}k=de.prototype;k.pg=function(){return this.b};k.F=function(){return this.f};k.Ni=function(){return this.g};k.Sb=function(){return ce[this.g]};k.bh=function(){return this.l};k.Eh=function(){return this.c}; -k.dk=function(a){this.c=a;this.a=!(!a||!this.f)};k.Oi=function(a){this.f=a;this.a=!(!this.c||!a)};k.pk=function(a){this.l=a};k.ck=function(a){this.A=a};k.Rg=function(a,c){if("degrees"==this.g)return a;var d=je(this,fe("EPSG:4326")),e=[c[0]-a/2,c[1],c[0]+a/2,c[1],c[0],c[1]-a/2,c[0],c[1]+a/2],e=d(e,e,2),d=(ae(e.slice(0,2),e.slice(2,4))+ae(e.slice(4,6),e.slice(6,8)))/2,e=this.Sb();void 0!==e&&(d/=e);return d};k.getPointResolution=function(a,c){return this.A(a,c)};var ee={},ke={}; -function ge(a){le(a);a.forEach(function(c){a.forEach(function(a){c!==a&&he(c,a,me)})})}function ne(a){ee[a.b]=a;he(a,a,me)}function le(a){var c=[];a.forEach(function(a){c.push(ne(a))})}function oe(a){return a?ha(a)?fe(a):a:fe("EPSG:3857")}function he(a,c,d){a=a.b;c=c.b;a in ke||(ke[a]={});ke[a][c]=d} -function ie(a){return function(c,d,e){var f=c.length;e=void 0!==e?e:2;d=void 0!==d?d:Array(f);var g,h;for(h=0;h<f;h+=e)for(g=a([c[h],c[h+1]]),d[h]=g[0],d[h+1]=g[1],g=e-1;2<=g;--g)d[h+g]=c[h+g];return d}}function fe(a){var c;a instanceof de?c=a:ha(a)?(c=ee[a],void 0===c&&"function"==typeof proj4&&void 0!==proj4.defs(a)&&(c=new de({code:a}),ne(c))):c=null;return c}function pe(a,c){return a===c?!0:a.b===c.b?a.g===c.g:je(a,c)===me}function qe(a,c){var d=fe(a),e=fe(c);return je(d,e)} -function je(a,c){var d=a.b,e=c.b,f;d in ke&&e in ke[d]&&(f=ke[d][e]);void 0===f&&(f=re);return f}function re(a,c){if(void 0!==c&&a!==c){for(var d=0,e=a.length;d<e;++d)c[d]=a[d];a=c}return a}function me(a,c){var d;if(void 0!==c){d=0;for(var e=a.length;d<e;++d)c[d]=a[d];d=c}else d=a.slice();return d}function se(a,c,d){return qe(c,d)(a,void 0,a.length)}function te(a,c,d){c=qe(c,d);a=[a[0],a[1],a[0],a[3],a[2],a[1],a[2],a[3]];c(a,a,2);return xd([a[0],a[2],a[4],a[6]],[a[1],a[3],a[5],a[7]])};function ue(){Yc.call(this);this.u=vd();this.H=-1;this.i={};this.s=this.j=0}x(ue,Yc);k=ue.prototype;k.Ha=function(a,c){var d=c?c:[NaN,NaN];this.Aa(a[0],a[1],d,Infinity);return d};k.le=function(a){return this.ib(a[0],a[1])};k.ib=Wd;k.F=function(a){this.H!=this.g&&(this.u=this.pc(this.u),this.H=this.g);var c=this.u;a?(a[0]=c[0],a[1]=c[1],a[2]=c[2],a[3]=c[3]):a=c;return a};k.Ka=function(a){return this.Tb(a*a)};k.Fa=function(a,c){this.pb(qe(a,c));return this};function ve(a,c,d,e,f,g){var h=f[0],l=f[1],m=f[4],n=f[5],p=f[12];f=f[13];for(var q=g?g:[],r=0;c<d;c+=e){var t=a[c],B=a[c+1];q[r++]=h*t+m*B+p;q[r++]=l*t+n*B+f}g&&q.length!=r&&(q.length=r);return q};function z(){ue.call(this);this.c="XY";this.a=2;this.o=null}x(z,ue);function we(a){if("XY"==a)return 2;if("XYZ"==a||"XYM"==a)return 3;if("XYZM"==a)return 4}k=z.prototype;k.ib=Wd;k.pc=function(a){return Hd(this.o,0,this.o.length,this.a,a)};k.Oa=function(){return this.o.slice(0,this.a)};k.ba=function(){return this.o};k.Pa=function(){return this.o.slice(this.o.length-this.a)};k.Qa=function(){return this.c}; -k.Tb=function(a){this.s!=this.g&&(Hb(this.i),this.j=0,this.s=this.g);if(0>a||0!==this.j&&a<=this.j)return this;var c=a.toString();if(this.i.hasOwnProperty(c))return this.i[c];var d=this.wb(a);if(d.ba().length<this.o.length)return this.i[c]=d;this.j=a;return this};k.wb=function(){return this};k.la=function(){return this.a};function xe(a,c,d){a.a=we(c);a.c=c;a.o=d} -function ye(a,c,d,e){if(c)d=we(c);else{for(c=0;c<e;++c){if(0===d.length){a.c="XY";a.a=2;return}d=d[0]}d=d.length;c=2==d?"XY":3==d?"XYZ":4==d?"XYZM":void 0}a.c=c;a.a=d}k.pb=function(a){this.o&&(a(this.o,this.o,this.a),this.v())};k.Hc=function(a,c){var d=this.ba();if(d){var e=this.la(),f=d.length,g=d?d:[],h=0,l,m;for(l=0;l<f;l+=e)for(g[h++]=d[l]+a,g[h++]=d[l+1]+c,m=l+2;m<l+e;++m)g[h++]=d[m];d&&g.length!=h&&(g.length=h);this.v()}};function ze(a,c,d,e){for(var f=0,g=a[d-e],h=a[d-e+1];c<d;c+=e)var l=a[c],m=a[c+1],f=f+(h*l-g*m),g=l,h=m;return f/2}function Ae(a,c,d,e){var f=0,g,h;g=0;for(h=d.length;g<h;++g){var l=d[g],f=f+ze(a,c,l,e);c=l}return f};function Be(a,c,d,e,f,g,h){var l=a[c],m=a[c+1],n=a[d]-l,p=a[d+1]-m;if(0!==n||0!==p)if(g=((f-l)*n+(g-m)*p)/(n*n+p*p),1<g)c=d;else if(0<g){for(f=0;f<e;++f)h[f]=fd(a[c+f],a[d+f],g);h.length=e;return}for(f=0;f<e;++f)h[f]=a[c+f];h.length=e}function Ce(a,c,d,e,f){var g=a[c],h=a[c+1];for(c+=e;c<d;c+=e){var l=a[c],m=a[c+1],g=Ra(g,h,l,m);g>f&&(f=g);g=l;h=m}return f}function De(a,c,d,e,f){var g,h;g=0;for(h=d.length;g<h;++g){var l=d[g];f=Ce(a,c,l,e,f);c=l}return f} -function Ee(a,c,d,e,f,g,h,l,m,n,p){if(c==d)return n;var q;if(0===f){q=Ra(h,l,a[c],a[c+1]);if(q<n){for(p=0;p<e;++p)m[p]=a[c+p];m.length=e;return q}return n}for(var r=p?p:[NaN,NaN],t=c+e;t<d;)if(Be(a,t-e,t,e,h,l,r),q=Ra(h,l,r[0],r[1]),q<n){n=q;for(p=0;p<e;++p)m[p]=r[p];m.length=e;t+=e}else t+=e*Math.max((Math.sqrt(q)-Math.sqrt(n))/f|0,1);if(g&&(Be(a,d-e,c,e,h,l,r),q=Ra(h,l,r[0],r[1]),q<n)){n=q;for(p=0;p<e;++p)m[p]=r[p];m.length=e}return n} -function Fe(a,c,d,e,f,g,h,l,m,n,p){p=p?p:[NaN,NaN];var q,r;q=0;for(r=d.length;q<r;++q){var t=d[q];n=Ee(a,c,t,e,f,g,h,l,m,n,p);c=t}return n};function Ge(a,c){var d=0,e,f;e=0;for(f=c.length;e<f;++e)a[d++]=c[e];return d}function He(a,c,d,e){var f,g;f=0;for(g=d.length;f<g;++f){var h=d[f],l;for(l=0;l<e;++l)a[c++]=h[l]}return c}function Ie(a,c,d,e,f){f=f?f:[];var g=0,h,l;h=0;for(l=d.length;h<l;++h)c=He(a,c,d[h],e),f[g++]=c;f.length=g;return f};function Je(a,c,d,e,f){f=void 0!==f?f:[];for(var g=0;c<d;c+=e)f[g++]=a.slice(c,c+e);f.length=g;return f}function Ke(a,c,d,e,f){f=void 0!==f?f:[];var g=0,h,l;h=0;for(l=d.length;h<l;++h){var m=d[h];f[g++]=Je(a,c,m,e,f[g]);c=m}f.length=g;return f};function Le(a,c,d,e,f,g,h){var l=(d-c)/e;if(3>l){for(;c<d;c+=e)g[h++]=a[c],g[h++]=a[c+1];return h}var m=Array(l);m[0]=1;m[l-1]=1;d=[c,d-e];for(var n=0,p;0<d.length;){var q=d.pop(),r=d.pop(),t=0,B=a[r],V=a[r+1],w=a[q],E=a[q+1];for(p=r+e;p<q;p+=e){var u;u=a[p];var Ca=a[p+1],Ea=B,ia=V,O=w-Ea,Aa=E-ia;if(0!==O||0!==Aa){var va=((u-Ea)*O+(Ca-ia)*Aa)/(O*O+Aa*Aa);1<va?(Ea=w,ia=E):0<va&&(Ea+=O*va,ia+=Aa*va)}u=Ra(u,Ca,Ea,ia);u>t&&(n=p,t=u)}t>f&&(m[(n-c)/e]=1,r+e<n&&d.push(r,n),n+e<q&&d.push(n,q))}for(p=0;p< -l;++p)m[p]&&(g[h++]=a[c+p*e],g[h++]=a[c+p*e+1]);return h} -function Me(a,c,d,e,f,g,h,l){var m,n;m=0;for(n=d.length;m<n;++m){var p=d[m];a:{var q=a,r=p,t=e,B=f,V=g;if(c!=r){var w=B*Math.round(q[c]/B),E=B*Math.round(q[c+1]/B);c+=t;V[h++]=w;V[h++]=E;var u=void 0,Ca=void 0;do if(u=B*Math.round(q[c]/B),Ca=B*Math.round(q[c+1]/B),c+=t,c==r){V[h++]=u;V[h++]=Ca;break a}while(u==w&&Ca==E);for(;c<r;){var Ea,ia;Ea=B*Math.round(q[c]/B);ia=B*Math.round(q[c+1]/B);c+=t;if(Ea!=u||ia!=Ca){var O=u-w,Aa=Ca-E,va=Ea-w,fb=ia-E;O*fb==Aa*va&&(0>O&&va<O||O==va||0<O&&va>O)&&(0>Aa&& -fb<Aa||Aa==fb||0<Aa&&fb>Aa)||(V[h++]=u,V[h++]=Ca,w=u,E=Ca);u=Ea;Ca=ia}}V[h++]=u;V[h++]=Ca}}l.push(h);c=p}return h};function Ne(a,c){z.call(this);this.f=this.l=-1;this.da(a,c)}x(Ne,z);k=Ne.prototype;k.clone=function(){var a=new Ne(null);xe(a,this.c,this.o.slice());a.v();return a};k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;this.f!=this.g&&(this.l=Math.sqrt(Ce(this.o,0,this.o.length,this.a,0)),this.f=this.g);return Ee(this.o,0,this.o.length,this.a,this.l,!0,a,c,d,e)};k.ni=function(){return ze(this.o,0,this.o.length,this.a)};k.R=function(){return Je(this.o,0,this.o.length,this.a)}; -k.wb=function(a){var c=[];c.length=Le(this.o,0,this.o.length,this.a,a,c,0);a=new Ne(null);xe(a,"XY",c);a.v();return a};k.N=function(){return"LinearRing"};k.da=function(a,c){a?(ye(this,c,a,1),this.o||(this.o=[]),this.o.length=He(this.o,0,a,this.a)):xe(this,"XY",null);this.v()};function A(a,c){z.call(this);this.da(a,c)}x(A,z);k=A.prototype;k.clone=function(){var a=new A(null);xe(a,this.c,this.o.slice());a.v();return a};k.Aa=function(a,c,d,e){var f=this.o;a=Ra(a,c,f[0],f[1]);if(a<e){e=this.a;for(c=0;c<e;++c)d[c]=f[c];d.length=e;return a}return e};k.R=function(){return this.o?this.o.slice():[]};k.pc=function(a){return Gd(this.o,a)};k.N=function(){return"Point"};k.pa=function(a){return Dd(a,this.o[0],this.o[1])}; -k.da=function(a,c){a?(ye(this,c,a,0),this.o||(this.o=[]),this.o.length=Ge(this.o,a)):xe(this,"XY",null);this.v()};function Oe(a,c,d,e,f){return!Ld(f,function(f){return!Pe(a,c,d,e,f[0],f[1])})}function Pe(a,c,d,e,f,g){for(var h=!1,l=a[d-e],m=a[d-e+1];c<d;c+=e){var n=a[c],p=a[c+1];m>g!=p>g&&f<(n-l)*(g-m)/(p-m)+l&&(h=!h);l=n;m=p}return h}function Qe(a,c,d,e,f,g){if(0===d.length||!Pe(a,c,d[0],e,f,g))return!1;var h;c=1;for(h=d.length;c<h;++c)if(Pe(a,d[c-1],d[c],e,f,g))return!1;return!0};function Se(a,c,d,e,f,g,h){var l,m,n,p,q,r=f[g+1],t=[],B=d[0];n=a[B-e];q=a[B-e+1];for(l=c;l<B;l+=e){p=a[l];m=a[l+1];if(r<=q&&m<=r||q<=r&&r<=m)n=(r-q)/(m-q)*(p-n)+n,t.push(n);n=p;q=m}B=NaN;q=-Infinity;t.sort();n=t[0];l=1;for(m=t.length;l<m;++l){p=t[l];var V=Math.abs(p-n);V>q&&(n=(n+p)/2,Qe(a,c,d,e,n,r)&&(B=n,q=V));n=p}isNaN(B)&&(B=f[g]);return h?(h.push(B,r),h):[B,r]};function Te(a,c,d,e,f,g){for(var h=[a[c],a[c+1]],l=[],m;c+e<d;c+=e){l[0]=a[c+e];l[1]=a[c+e+1];if(m=f.call(g,h,l))return m;h[0]=l[0];h[1]=l[1]}return!1};function Ue(a,c,d,e,f){var g=Id(vd(),a,c,d,e);return Ud(f,g)?Ed(f,g)||g[0]>=f[0]&&g[2]<=f[2]||g[1]>=f[1]&&g[3]<=f[3]?!0:Te(a,c,d,e,function(a,c){var d=!1,e=Fd(f,a),g=Fd(f,c);if(1===e||1===g)d=!0;else{var q=f[0],r=f[1],t=f[2],B=f[3],V=c[0],w=c[1],E=(w-a[1])/(V-a[0]);g&2&&!(e&2)&&(d=V-(w-B)/E,d=d>=q&&d<=t);d||!(g&4)||e&4||(d=w-(V-t)*E,d=d>=r&&d<=B);d||!(g&8)||e&8||(d=V-(w-r)/E,d=d>=q&&d<=t);d||!(g&16)||e&16||(d=w-(V-q)*E,d=d>=r&&d<=B)}return d}):!1} -function Ve(a,c,d,e,f){var g=d[0];if(!(Ue(a,c,g,e,f)||Pe(a,c,g,e,f[0],f[1])||Pe(a,c,g,e,f[0],f[3])||Pe(a,c,g,e,f[2],f[1])||Pe(a,c,g,e,f[2],f[3])))return!1;if(1===d.length)return!0;c=1;for(g=d.length;c<g;++c)if(Oe(a,d[c-1],d[c],e,f))return!1;return!0};function We(a,c,d,e){for(var f=0,g=a[d-e],h=a[d-e+1];c<d;c+=e)var l=a[c],m=a[c+1],f=f+(l-g)*(m+h),g=l,h=m;return 0<f}function Xe(a,c,d,e){var f=0;e=void 0!==e?e:!1;var g,h;g=0;for(h=c.length;g<h;++g){var l=c[g],f=We(a,f,l,d);if(0===g){if(e&&f||!e&&!f)return!1}else if(e&&!f||!e&&f)return!1;f=l}return!0} -function Ye(a,c,d,e,f){f=void 0!==f?f:!1;var g,h;g=0;for(h=d.length;g<h;++g){var l=d[g],m=We(a,c,l,e);if(0===g?f&&m||!f&&!m:f&&!m||!f&&m)for(var m=a,n=l,p=e;c<n-p;){var q;for(q=0;q<p;++q){var r=m[c+q];m[c+q]=m[n-p+q];m[n-p+q]=r}c+=p;n-=p}c=l}return c}function Ze(a,c,d,e){var f=0,g,h;g=0;for(h=c.length;g<h;++g)f=Ye(a,f,c[g],d,e);return f};function C(a,c){z.call(this);this.f=[];this.D=-1;this.G=null;this.J=this.B=this.I=-1;this.l=null;this.da(a,c)}x(C,z);k=C.prototype;k.Wf=function(a){this.o?eb(this.o,a.ba()):this.o=a.ba().slice();this.f.push(this.o.length);this.v()};k.clone=function(){var a=new C(null);$e(a,this.c,this.o.slice(),this.f.slice());return a}; -k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;this.B!=this.g&&(this.I=Math.sqrt(De(this.o,0,this.f,this.a,0)),this.B=this.g);return Fe(this.o,0,this.f,this.a,this.I,!0,a,c,d,e)};k.ib=function(a,c){return Qe(this.Za(),0,this.f,this.a,a,c)};k.ri=function(){return Ae(this.Za(),0,this.f,this.a)};k.R=function(a){var c;void 0!==a?(c=this.Za().slice(),Ye(c,0,this.f,this.a,a)):c=this.o;return Ke(c,0,this.f,this.a)};k.Na=function(){return this.f}; -function af(a){if(a.D!=a.g){var c=Rd(a.F());a.G=Se(a.Za(),0,a.f,a.a,c,0);a.D=a.g}return a.G}k.Eg=function(){return new A(af(this))};k.Jg=function(){return this.f.length};k.ve=function(a){if(0>a||this.f.length<=a)return null;var c=new Ne(null);xe(c,this.c,this.o.slice(0===a?0:this.f[a-1],this.f[a]));c.v();return c};k.we=function(){var a=this.c,c=this.o,d=this.f,e=[],f=0,g,h;g=0;for(h=d.length;g<h;++g){var l=d[g],m=new Ne(null),n=m;xe(n,a,c.slice(f,l));n.v();e.push(m);f=l}return e}; -k.Za=function(){if(this.J!=this.g){var a=this.o;Xe(a,this.f,this.a)?this.l=a:(this.l=a.slice(),this.l.length=Ye(this.l,0,this.f,this.a));this.J=this.g}return this.l};k.wb=function(a){var c=[],d=[];c.length=Me(this.o,0,this.f,this.a,Math.sqrt(a),c,0,d);a=new C(null);$e(a,"XY",c,d);return a};k.N=function(){return"Polygon"};k.pa=function(a){return Ve(this.Za(),0,this.f,this.a,a)}; -k.da=function(a,c){if(a){ye(this,c,a,2);this.o||(this.o=[]);var d=Ie(this.o,0,a,this.a,this.f);this.o.length=0===d.length?0:d[d.length-1];this.v()}else $e(this,"XY",null,this.f)};function $e(a,c,d,e){xe(a,c,d);a.f=e;a.v()};function D(a){Yc.call(this);a=a||{};this.a=[0,0];var c={};c.center=void 0!==a.center?a.center:null;this.j=oe(a.projection);var d,e,f,g=void 0!==a.minZoom?a.minZoom:0;d=void 0!==a.maxZoom?a.maxZoom:28;var h=void 0!==a.zoomFactor?a.zoomFactor:2;if(void 0!==a.resolutions)d=a.resolutions,e=d[0],f=d[d.length-1],d=qb(d);else{e=oe(a.projection);f=e.F();var l=(f?Math.max(Pd(f),Qd(f)):360*ce.degrees/ce[e.g])/256/Math.pow(2,0),m=l/Math.pow(2,28);e=a.maxResolution;void 0!==e?g=0:e=l/Math.pow(h,g);f=a.minResolution; -void 0===f&&(f=void 0!==a.maxZoom?void 0!==a.maxResolution?e/Math.pow(h,d):l/Math.pow(h,d):m);d=g+Math.floor(Math.log(e/f)/Math.log(h));f=e/Math.pow(h,d-g);d=rb(h,e,d-g)}this.c=e;this.l=f;this.f=g;g=void 0!==a.extent?Ta(a.extent):Va;(void 0!==a.enableRotation?a.enableRotation:1)?(e=a.constrainRotation,e=void 0===e||!0===e?vb():!1===e?tb:ka(e)?ub(e):tb):e=sb;this.i=new wb(g,d,e);void 0!==a.resolution?c.resolution=a.resolution:void 0!==a.zoom&&(c.resolution=this.constrainResolution(this.c,a.zoom-this.f)); -c.rotation=void 0!==a.rotation?a.rotation:0;this.K(c)}x(D,Yc);k=D.prototype;k.qc=function(a){return this.i.center(a)};k.constrainResolution=function(a,c,d){return this.i.resolution(a,c||0,d||0)};k.constrainRotation=function(a,c){return this.i.rotation(a,c||0)};k.za=function(){return this.get("center")};k.$f=function(a){var c=this.za(),d=this.$(),e=this.ua();return Sd(c,d,e,a)};k.ii=function(){return this.j};k.$=function(){return this.get("resolution")}; -k.rd=function(a,c){return Math.max(Pd(a)/c[0],Qd(a)/c[1])};k.ua=function(){return this.get("rotation")};function bf(a){var c=a.za(),d=a.j,e=a.$();a=a.ua();return{center:[Math.round(c[0]/e)*e,Math.round(c[1]/e)*e],projection:void 0!==d?d:null,resolution:e,rotation:a}}k.dh=function(){var a,c=this.$();if(void 0!==c){var d,e=0;do{d=this.constrainResolution(this.c,e);if(d==c){a=e;break}++e}while(d>this.l)}return void 0!==a?this.f+a:a}; -k.oe=function(a,c,d){if(!(a instanceof z)){var e=a[0],f=a[1],g=a[2],h=a[3],e=[e,f,e,h,g,h,g,f,e,f],f=new C(null);$e(f,"XY",e,[e.length]);a=f}e=d||{};d=void 0!==e.padding?e.padding:[0,0,0,0];var h=void 0!==e.constrainResolution?e.constrainResolution:!0,f=void 0!==e.nearest?e.nearest:!1,l;void 0!==e.minResolution?l=e.minResolution:void 0!==e.maxZoom?l=this.constrainResolution(this.c,e.maxZoom-this.f,0):l=0;var m=a.ba(),g=this.ua(),e=Math.cos(-g),g=Math.sin(-g),n=Infinity,p=Infinity,q=-Infinity,r=-Infinity; -a=a.la();for(var t=0,B=m.length;t<B;t+=a)var V=m[t]*e-m[t+1]*g,w=m[t]*g+m[t+1]*e,n=Math.min(n,V),p=Math.min(p,w),q=Math.max(q,V),r=Math.max(r,w);c=this.rd([n,p,q,r],[c[0]-d[1]-d[3],c[1]-d[0]-d[2]]);c=isNaN(c)?l:Math.max(c,l);h&&(l=this.constrainResolution(c,0,0),!f&&l<c&&(l=this.constrainResolution(l,-1,0)),c=l);this.Gb(c);g=-g;l=(n+q)/2+(d[1]-d[3])/2*c;c=(p+r)/2+(d[0]-d[2])/2*c;this.Ea([l*e-c*g,c*e+l*g])}; -k.bg=function(a,c,d){var e=this.ua(),f=Math.cos(-e),e=Math.sin(-e),g=a[0]*f-a[1]*e;a=a[1]*f+a[0]*e;var h=this.$(),g=g+(c[0]/2-d[0])*h;a+=(d[1]-c[1]/2)*h;e=-e;this.Ea([g*f-a*e,a*f+g*e])};k.rotate=function(a,c){if(void 0!==c){var d,e=this.za();void 0!==e&&(d=[e[0]-c[0],e[1]-c[1]],ld(d,a-this.ua()),gd(d,c));this.Ea(d)}this.Id(a)};k.Ea=function(a){this.C("center",a)};function cf(a,c){a.a[1]+=c}k.Gb=function(a){this.C("resolution",a)};k.Id=function(a){this.C("rotation",a)}; -k.qk=function(a){a=this.constrainResolution(this.c,a-this.f,0);this.Gb(a)};D.prototype.getResolutionForExtent=D.prototype.rd;function df(a){return 1-Math.pow(1-a,3)}function ef(a){return 3*a*a-2*a*a*a}function ff(a){return a}function gf(a){return.5>a?ef(2*a):1-ef(2*(a-.5))};function hf(a){var c=a.source,d=a.start?a.start:Date.now(),e=c[0],f=c[1],g=void 0!==a.duration?a.duration:1E3,h=a.easing?a.easing:ef;return function(a,c){if(c.time<d)return c.animate=!0,c.viewHints[0]+=1,!0;if(c.time<d+g){var n=1-h((c.time-d)/g),p=e-c.viewState.center[0],q=f-c.viewState.center[1];c.animate=!0;c.viewState.center[0]+=n*p;c.viewState.center[1]+=n*q;c.viewHints[0]+=1;return!0}return!1}} -function jf(a){var c=a.rotation?a.rotation:0,d=a.start?a.start:Date.now(),e=void 0!==a.duration?a.duration:1E3,f=a.easing?a.easing:ef,g=a.anchor?a.anchor:null;return function(a,l){if(l.time<d)return l.animate=!0,l.viewHints[0]+=1,!0;if(l.time<d+e){var m=1-f((l.time-d)/e),m=(c-l.viewState.rotation)*m;l.animate=!0;l.viewState.rotation+=m;if(g){var n=l.viewState.center;n[0]-=g[0];n[1]-=g[1];ld(n,m);gd(n,g)}l.viewHints[0]+=1;return!0}return!1}} -function kf(a){var c=a.resolution,d=a.start?a.start:Date.now(),e=void 0!==a.duration?a.duration:1E3,f=a.easing?a.easing:ef;return function(a,h){if(h.time<d)return h.animate=!0,h.viewHints[0]+=1,!0;if(h.time<d+e){var l=1-f((h.time-d)/e),m=c-h.viewState.resolution;h.animate=!0;h.viewState.resolution+=l*m;h.viewHints[0]+=1;return!0}return!1}};function lf(a,c,d){return a+"/"+c+"/"+d}function mf(a){return lf(a[0],a[1],a[2])};function nf(a,c,d,e){this.b=a;this.a=c;this.c=d;this.g=e}nf.prototype.contains=function(a){return of(this,a[1],a[2])};function pf(a,c){return a.b<=c.b&&c.a<=a.a&&a.c<=c.c&&c.g<=a.g}function of(a,c,d){return a.b<=c&&c<=a.a&&a.c<=d&&d<=a.g}function qf(a){return a.g-a.c+1}nf.prototype.j=function(){return this.b};nf.prototype.getMinX=nf.prototype.j;nf.prototype.f=function(){return this.a};nf.prototype.getMaxX=nf.prototype.f;nf.prototype.A=function(){return this.c};nf.prototype.getMinY=nf.prototype.A; -nf.prototype.i=function(){return this.g};nf.prototype.getMaxY=nf.prototype.i;function rf(a,c,d){lc.call(this,a,d);this.element=c}x(rf,lc);function F(a){Yc.call(this);this.a=a?a:[];sf(this)}x(F,Yc);k=F.prototype;k.clear=function(){for(;0<this.gb();)this.pop()};k.Dd=function(a){var c,d;c=0;for(d=a.length;c<d;++c)this.push(a[c]);return this};k.forEach=function(a,c){this.a.forEach(a,c)};k.Uh=function(){return this.a};k.item=function(a){return this.a[a]};k.gb=function(){return this.get("length")};k.Ac=function(a,c){hb(this.a,a,0,c);sf(this);this.b(new rf("add",c,this))}; -k.pop=function(){return this.Qd(this.gb()-1)};k.push=function(a){var c=this.a.length;this.Ac(c,a);return c};k.remove=function(a){var c=this.a,d,e;d=0;for(e=c.length;d<e;++d)if(c[d]===a)return this.Qd(d)};k.Qd=function(a){var c=this.a[a];Wa.splice.call(this.a,a,1);sf(this);this.b(new rf("remove",c,this));return c};k.$j=function(a,c){var d=this.gb();if(a<d)d=this.a[a],this.a[a]=c,this.b(new rf("remove",d,this)),this.b(new rf("add",c,this));else{for(;d<a;++d)this.Ac(d,void 0);this.Ac(a,c)}}; -function sf(a){a.C("length",a.a.length)};var tf=/^#(?:[0-9a-f]{3}){1,2}$/i,uf=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i,vf=/^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;function wf(a){return fa(a)?a:xf(a)}function yf(a){if(!ha(a)){var c=a[0];c!=(c|0)&&(c=c+.5|0);var d=a[1];d!=(d|0)&&(d=d+.5|0);var e=a[2];e!=(e|0)&&(e=e+.5|0);a="rgba("+c+","+d+","+e+","+a[3]+")"}return a} -var xf=function(){var a={},c=0;return function(d){var e;if(a.hasOwnProperty(d))e=a[d];else{if(1024<=c){e=0;for(var f in a)0===(e++&3)&&(delete a[f],--c)}var g,h;tf.exec(d)?(h=3==d.length-1?1:2,e=parseInt(d.substr(1+0*h,h),16),f=parseInt(d.substr(1+1*h,h),16),g=parseInt(d.substr(1+2*h,h),16),1==h&&(e=(e<<4)+e,f=(f<<4)+f,g=(g<<4)+g),e=[e,f,g,1]):(h=vf.exec(d))?(e=Number(h[1]),f=Number(h[2]),g=Number(h[3]),h=Number(h[4]),e=[e,f,g,h],e=zf(e,e)):(h=uf.exec(d))?(e=Number(h[1]),f=Number(h[2]),g=Number(h[3]), -e=[e,f,g,1],e=zf(e,e)):e=void 0;a[d]=e;++c}return e}}();function zf(a,c){var d=c||[];d[0]=Pa(a[0]+.5|0,0,255);d[1]=Pa(a[1]+.5|0,0,255);d[2]=Pa(a[2]+.5|0,0,255);d[3]=Pa(a[3],0,1);return d};var Af=!Pb||9<=cc;!Rb&&!Pb||Pb&&9<=cc||Rb&&ac("1.9.1");Pb&&ac("9");function Bf(a,c){this.x=ca(a)?a:0;this.y=ca(c)?c:0}k=Bf.prototype;k.clone=function(){return new Bf(this.x,this.y)};k.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};k.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};k.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};k.scale=function(a,c){var d=ka(c)?c:a;this.x*=a;this.y*=d;return this};function Cf(a,c){this.width=a;this.height=c}k=Cf.prototype;k.clone=function(){return new Cf(this.width,this.height)};k.Zf=function(){return this.width*this.height};k.Ja=function(){return!this.Zf()};k.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};k.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};k.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this}; -k.scale=function(a,c){var d=ka(c)?c:a;this.width*=a;this.height*=d;return this};function Df(a){return a?new Ef(Ff(a)):xa||(xa=new Ef)}function Gf(a){var c=document;return ha(a)?c.getElementById(a):a}function Hf(a,c){Bb(c,function(c,e){"style"==e?a.style.cssText=c:"class"==e?a.className=c:"for"==e?a.htmlFor=c:If.hasOwnProperty(e)?a.setAttribute(If[e],c):0==e.lastIndexOf("aria-",0)||0==e.lastIndexOf("data-",0)?a.setAttribute(e,c):a[e]=c})} -var If={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:"height",maxlength:"maxLength",role:"role",rowspan:"rowSpan",type:"type",usemap:"useMap",valign:"vAlign",width:"width"};function Jf(a){a=a.document.documentElement;return new Cf(a.clientWidth,a.clientHeight)} -function Kf(a,c,d){var e=arguments,f=document,g=e[0],h=e[1];if(!Af&&h&&(h.name||h.type)){g=["<",g];h.name&&g.push(' name="',Ba(h.name),'"');if(h.type){g.push(' type="',Ba(h.type),'"');var l={};Nb(l,h);delete l.type;h=l}g.push(">");g=g.join("")}g=f.createElement(g);h&&(ha(h)?g.className=h:fa(h)?g.className=h.join(" "):Hf(g,h));2<e.length&&Lf(f,g,e,2);return g} -function Lf(a,c,d,e){function f(d){d&&c.appendChild(ha(d)?a.createTextNode(d):d)}for(;e<d.length;e++){var g=d[e];!ga(g)||ma(g)&&0<g.nodeType?f(g):Xa(Mf(g)?db(g):g,f)}}function Nf(a,c){Lf(Ff(a),a,arguments,1)}function Of(a){a&&a.parentNode&&a.parentNode.removeChild(a)}function Pf(a,c){if(a.contains&&1==c.nodeType)return a==c||a.contains(c);if("undefined"!=typeof a.compareDocumentPosition)return a==c||Boolean(a.compareDocumentPosition(c)&16);for(;c&&a!=c;)c=c.parentNode;return c==a} -function Ff(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function Mf(a){if(a&&"number"==typeof a.length){if(ma(a))return"function"==typeof a.item||"string"==typeof a.item;if(la(a))return"function"==typeof a.item}return!1}function Ef(a){this.b=a||ba.document||document}Ef.prototype.appendChild=function(a,c){a.appendChild(c)};Ef.prototype.contains=Pf;function Qf(a){if(a.classList)return a.classList;a=a.className;return ha(a)&&a.match(/\S+/g)||[]}function Rf(a,c){var d;a.classList?d=a.classList.contains(c):(d=Qf(a),d=0<=Wa.indexOf.call(d,c,void 0));return d}function Sf(a,c){a.classList?a.classList.add(c):Rf(a,c)||(a.className+=0<a.className.length?" "+c:c)}function Tf(a,c){a.classList?a.classList.remove(c):Rf(a,c)&&(a.className=Ya(Qf(a),function(a){return a!=c}).join(" "))};function Uf(a,c,d,e){this.top=a;this.right=c;this.bottom=d;this.left=e}k=Uf.prototype;k.clone=function(){return new Uf(this.top,this.right,this.bottom,this.left)};k.contains=function(a){return this&&a?a instanceof Uf?a.left>=this.left&&a.right<=this.right&&a.top>=this.top&&a.bottom<=this.bottom:a.x>=this.left&&a.x<=this.right&&a.y>=this.top&&a.y<=this.bottom:!1}; -k.ceil=function(){this.top=Math.ceil(this.top);this.right=Math.ceil(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.ceil(this.left);return this};k.floor=function(){this.top=Math.floor(this.top);this.right=Math.floor(this.right);this.bottom=Math.floor(this.bottom);this.left=Math.floor(this.left);return this};k.round=function(){this.top=Math.round(this.top);this.right=Math.round(this.right);this.bottom=Math.round(this.bottom);this.left=Math.round(this.left);return this}; -k.scale=function(a,c){var d=ka(c)?c:a;this.left*=a;this.right*=a;this.top*=d;this.bottom*=d;return this};function Vf(a,c){var d=Ff(a);return d.defaultView&&d.defaultView.getComputedStyle&&(d=d.defaultView.getComputedStyle(a,null))?d[c]||d.getPropertyValue(c)||"":""}function Yf(a,c){return Vf(a,c)||(a.currentStyle?a.currentStyle[c]:null)||a.style&&a.style[c]} -function Zf(a){var c;try{c=a.getBoundingClientRect()}catch(d){return{left:0,top:0,right:0,bottom:0}}Pb&&a.ownerDocument.body&&(a=a.ownerDocument,c.left-=a.documentElement.clientLeft+a.body.clientLeft,c.top-=a.documentElement.clientTop+a.body.clientTop);return c}function $f(a){if(1==a.nodeType)return a=Zf(a),new Bf(a.left,a.top);a=a.changedTouches?a.changedTouches[0]:a;return new Bf(a.clientX,a.clientY)} -function ag(a){var c=bg;if("none"!=Yf(a,"display"))return c(a);var d=a.style,e=d.display,f=d.visibility,g=d.position;d.visibility="hidden";d.position="absolute";d.display="inline";a=c(a);d.display=e;d.position=g;d.visibility=f;return a}function bg(a){var c=a.offsetWidth,d=a.offsetHeight,e=Sb&&!c&&!d;return ca(c)&&!e||!a.getBoundingClientRect?new Cf(c,d):(a=Zf(a),new Cf(a.right-a.left,a.bottom-a.top))}function cg(a,c){a.style.display=c?"":"none"} -function dg(a,c,d,e){if(/^\d+px?$/.test(c))return parseInt(c,10);var f=a.style[d],g=a.runtimeStyle[d];a.runtimeStyle[d]=a.currentStyle[d];a.style[d]=c;c=a.style[e];a.style[d]=f;a.runtimeStyle[d]=g;return c}function eg(a,c){var d=a.currentStyle?a.currentStyle[c]:null;return d?dg(a,d,"left","pixelLeft"):0}var fg={thin:2,medium:4,thick:6}; -function gg(a,c){if("none"==(a.currentStyle?a.currentStyle[c+"Style"]:null))return 0;var d=a.currentStyle?a.currentStyle[c+"Width"]:null;return d in fg?fg[d]:dg(a,d,"left","pixelLeft")};function hg(a,c,d){lc.call(this,a);this.map=c;this.frameState=void 0!==d?d:null}x(hg,lc);function ig(a){Yc.call(this);this.element=a.element?a.element:null;this.a=this.J=null;this.j=[];this.render=a.render?a.render:wa;a.target&&this.H(a.target)}x(ig,Yc);ig.prototype.Z=function(){Of(this.element);ig.fa.Z.call(this)};ig.prototype.I=function(){return this.a}; -ig.prototype.setMap=function(a){this.a&&Of(this.element);0<this.j.length&&(this.j.forEach(Nc),this.j.length=0);if(this.a=a)(this.J?this.J:a.G).appendChild(this.element),this.render!==wa&&this.j.push(y(a,"postrender",this.render,!1,this)),a.render()};ig.prototype.H=function(a){this.J=Gf(a)};function jg(){this.c=0;this.g={};this.b=this.a=null}k=jg.prototype;k.clear=function(){this.c=0;this.g={};this.b=this.a=null};k.forEach=function(a,c){for(var d=this.a;d;)a.call(c,d.nb,d.Ad,this),d=d.Da};k.get=function(a){a=this.g[a];if(a===this.b)return a.nb;a===this.a?(this.a=this.a.Da,this.a.$a=null):(a.Da.$a=a.$a,a.$a.Da=a.Da);a.Da=null;a.$a=this.b;this.b=this.b.Da=a;return a.nb};k.Rb=function(){return this.c};k.L=function(){var a=Array(this.c),c=0,d;for(d=this.b;d;d=d.$a)a[c++]=d.Ad;return a}; -k.fb=function(){var a=Array(this.c),c=0,d;for(d=this.b;d;d=d.$a)a[c++]=d.nb;return a};k.pop=function(){var a=this.a;delete this.g[a.Ad];a.Da&&(a.Da.$a=null);this.a=a.Da;this.a||(this.b=null);--this.c;return a.nb};k.replace=function(a,c){this.get(a);this.g[a].nb=c};function kg(a,c,d){d={Ad:c,Da:null,$a:a.b,nb:d};a.b?a.b.Da=d:a.a=d;a.b=d;a.g[c]=d;++a.c};function lg(a){jg.call(this);this.f=void 0!==a?a:2048}x(lg,jg);function mg(a){return a.Rb()>a.f}function ng(a,c){for(var d,e;mg(a)&&!(d=a.a.nb,e=d.a[0].toString(),e in c&&c[e].contains(d.a));)a.pop().rc()};function og(a,c){Sc.call(this);this.a=a;this.state=c;this.g=null;this.key=""}x(og,Sc);function pg(a){a.b("change")}og.prototype.Hd=function(){return na(this).toString()};function qg(a){Yc.call(this);this.j=fe(a.projection);this.u=void 0!==a.attributions?a.attributions:null;this.Y=a.logo;this.H=void 0!==a.state?a.state:"ready";this.D=void 0!==a.wrapX?a.wrapX:!1}x(qg,Yc);k=qg.prototype;k.Ye=wa;k.Bb=function(){return this.u};k.tb=function(){return this.Y};k.Cb=function(){return this.j};k.Db=function(){return this.H};function rg(a){return a.D}k.Fb=function(a){this.u=a;this.v()};function sg(a){this.minZoom=void 0!==a.minZoom?a.minZoom:0;this.b=a.resolutions;this.maxZoom=this.b.length-1;this.g=void 0!==a.origin?a.origin:null;this.f=null;void 0!==a.origins&&(this.f=a.origins);var c=a.extent;void 0===c||this.g||this.f||(this.g=Md(c));this.i=null;void 0!==a.tileSizes&&(this.i=a.tileSizes);this.A=void 0!==a.tileSize?a.tileSize:this.i?null:256;this.s=void 0!==c?c:null;this.a=null;void 0!==a.sizes?this.a=a.sizes.map(function(a){return new nf(Math.min(0,a[0]),Math.max(a[0]-1,-1), -Math.min(0,a[1]),Math.max(a[1]-1,-1))},this):c&&tg(this,c);this.c=[0,0]}var ug=[0,0,0];function vg(a,c,d,e,f){f=a.Ca(c,f);for(c=c[0]-1;c>=a.minZoom;){if(d.call(null,c,a.Wa(f,c,e)))return!0;--c}return!1}k=sg.prototype;k.F=function(){return this.s};k.xe=function(){return this.maxZoom};k.ye=function(){return this.minZoom};k.ta=function(a){return this.g?this.g:this.f[a]};k.$=function(a){return this.b[a]};k.hf=function(){return this.b}; -function wg(a,c,d,e){return c[0]<a.maxZoom?(e=a.Ca(c,e),a.Wa(e,c[0]+1,d)):null}function xg(a,c,d,e){yg(a,c[0],c[1],d,!1,ug);var f=ug[1],g=ug[2];yg(a,c[2],c[3],d,!0,ug);a=ug[1];c=ug[2];void 0!==e?(e.b=f,e.a=a,e.c=g,e.g=c):e=new nf(f,a,g,c);return e}k.Wa=function(a,c,d){c=this.$(c);return xg(this,a,c,d)};function zg(a,c){var d=a.ta(c[0]),e=a.$(c[0]),f=dd(a.Ia(c[0]),a.c);return[d[0]+(c[1]+.5)*f[0]*e,d[1]+(c[2]+.5)*f[1]*e]} -k.Ca=function(a,c){var d=this.ta(a[0]),e=this.$(a[0]),f=dd(this.Ia(a[0]),this.c),g=d[0]+a[1]*f[0]*e,d=d[1]+a[2]*f[1]*e;return yd(g,d,g+f[0]*e,d+f[1]*e,c)};k.td=function(a,c,d){return yg(this,a[0],a[1],c,!1,d)};function yg(a,c,d,e,f,g){var h=Ag(a,e),l=e/a.$(h),m=a.ta(h);a=dd(a.Ia(h),a.c);c=l*Math.floor((c-m[0])/e+(f?.5:0))/a[0];d=l*Math.floor((d-m[1])/e+(f?0:.5))/a[1];f?(c=Math.ceil(c)-1,d=Math.ceil(d)-1):(c=Math.floor(c),d=Math.floor(d));f=c;void 0!==g?(g[0]=h,g[1]=f,g[2]=d):g=[h,f,d];return g} -k.ud=function(a,c,d){c=this.$(c);return yg(this,a[0],a[1],c,!1,d)};k.Ia=function(a){return this.A?this.A:this.i[a]};function Ag(a,c){var d=pb(a.b,c,0);return Pa(d,a.minZoom,a.maxZoom)}function tg(a,c){for(var d=a.b.length,e=Array(d),f=a.minZoom;f<d;++f)e[f]=a.Wa(c,f);a.a=e}function Bg(a){var c=a.j;if(!c){for(var c=Cg(a),d=Qd(c),e=Pd(c),f=dd(256),d=Math.max(e/f[0],d/f[1]),e=Array(43),f=0;43>f;++f)e[f]=d/Math.pow(2,f);c=new sg({extent:c,origin:Md(c),resolutions:e,tileSize:void 0});a.j=c}return c} -function Cg(a){a=fe(a);var c=a.F();c||(a=180*ce.degrees/a.Sb(),c=yd(-a,-a,a,a));return c}sg.prototype.getTileRangeForExtentAndZ=sg.prototype.Wa;function Dg(a){qg.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,state:a.state,wrapX:a.wrapX});this.qa=void 0!==a.opaque?a.opaque:!1;this.na=void 0!==a.tilePixelRatio?a.tilePixelRatio:1;this.tileGrid=void 0!==a.tileGrid?a.tileGrid:null;this.a=new lg(a.je);this.f=[0,0]}x(Dg,qg);k=Dg.prototype;k.Ze=function(){return mg(this.a)};k.$e=function(a,c){var d=this.Vb(a);d&&ng(d,c)}; -function Eg(a,c,d,e,f){c=a.Vb(c);if(!c)return!1;for(var g=!0,h,l,m=e.b;m<=e.a;++m)for(var n=e.c;n<=e.g;++n)h=a.rb(d,m,n),l=!1,c.g.hasOwnProperty(h)&&(h=c.get(h),(l=2===h.state)&&(l=!1!==f(h))),l||(g=!1);return g}k.qe=function(){return 0};k.te=function(){return""};k.rb=lf;k.vd=function(){return this.tileGrid};k.Ra=function(a){return this.tileGrid?this.tileGrid:Bg(a)};k.Vb=function(a){var c=this.j;return c&&!pe(c,a)?null:this.a}; -k.wc=function(a,c,d){c=this.Ra(d);return cd(dd(c.Ia(a),this.f),this.na,this.f)};k.Df=wa;function Fg(a,c){lc.call(this,a);this.tile=c}x(Fg,lc);function Gg(a){a=a?a:{};this.D=document.createElement("UL");this.s=document.createElement("LI");this.D.appendChild(this.s);cg(this.s,!1);this.i=void 0!==a.collapsed?a.collapsed:!0;this.l=void 0!==a.collapsible?a.collapsible:!0;this.l||(this.i=!1);var c=a.className?a.className:"ol-attribution",d=a.tipLabel?a.tipLabel:"Attributions",e=a.collapseLabel?a.collapseLabel:"\u00bb";this.G=ha(e)?Kf("SPAN",{},e):e;e=a.label?a.label:"i";this.B=ha(e)?Kf("SPAN",{},e):e;d=Kf("BUTTON",{type:"button",title:d},this.l&& -!this.i?this.G:this.B);y(d,"click",this.aa,!1,this);y(d,["mouseout",nc],function(){this.blur()},!1);c=Kf("DIV",c+" ol-unselectable ol-control"+(this.i&&this.l?" ol-collapsed":"")+(this.l?"":" ol-uncollapsible"),this.D,d);ig.call(this,{element:c,render:a.render?a.render:Hg,target:a.target});this.u=!0;this.f={};this.c={};this.Y={}}x(Gg,ig); -function Hg(a){if(a=a.frameState){var c,d,e,f,g,h,l,m,n,p,q=a.layerStatesArray,r=Kb(a.attributions),t={},B=a.viewState.projection;d=0;for(c=q.length;d<c;d++)if(h=q[d].layer.ha())if(p=na(h).toString(),n=h.u)for(e=0,f=n.length;e<f;e++)if(l=n[e],m=na(l).toString(),!(m in r)){if(g=a.usedTiles[p]){var V=h.Ra(B);g=l.a(g,V,B)}else g=!1;g?(m in t&&delete t[m],r[m]=l):t[m]=l}c=[r,t];d=c[0];c=c[1];for(var w in this.f)w in d?(this.c[w]||(cg(this.f[w],!0),this.c[w]=!0),delete d[w]):w in c?(this.c[w]&&(cg(this.f[w], -!1),delete this.c[w]),delete c[w]):(Of(this.f[w]),delete this.f[w],delete this.c[w]);for(w in d)e=document.createElement("LI"),e.innerHTML=d[w].b(),this.D.appendChild(e),this.f[w]=e,this.c[w]=!0;for(w in c)e=document.createElement("LI"),e.innerHTML=c[w].b(),cg(e,!1),this.D.appendChild(e),this.f[w]=e;w=!Gb(this.c)||!Gb(a.logos);this.u!=w&&(cg(this.element,w),this.u=w);w&&Gb(this.c)?Sf(this.element,"ol-logo-only"):Tf(this.element,"ol-logo-only");var E;a=a.logos;w=this.Y;for(E in w)E in a||(Of(w[E]), -delete w[E]);for(var u in a)u in w||(E=new Image,E.src=u,d=a[u],""===d?d=E:(d=Kf("A",{href:d}),d.appendChild(E)),this.s.appendChild(d),w[u]=d);cg(this.s,!Gb(a))}else this.u&&(cg(this.element,!1),this.u=!1)}Gg.prototype.aa=function(a){a.preventDefault();a=this.element;Rf(a,"ol-collapsed")?Tf(a,"ol-collapsed"):Sf(a,"ol-collapsed");if(this.i){a=this.B;var c=a.parentNode;c&&c.replaceChild(this.G,a)}else a=this.G,(c=a.parentNode)&&c.replaceChild(this.B,a);this.i=!this.i};function Ig(a){a=a?a:{};var c=a.className?a.className:"ol-rotate",d=a.label?a.label:"\u21e7";this.c=null;ha(d)?this.c=Kf("SPAN","ol-compass",d):(this.c=d,Sf(this.c,"ol-compass"));d=Kf("BUTTON",{"class":c+"-reset",type:"button",title:a.tipLabel?a.tipLabel:"Reset rotation"},this.c);y(d,"click",Ig.prototype.u,!1,this);c=Kf("DIV",c+" ol-unselectable ol-control",d);d=a.render?a.render:Jg;this.i=a.resetNorth?a.resetNorth:void 0;ig.call(this,{element:c,render:d,target:a.target});this.l=void 0!==a.duration? -a.duration:250;this.f=void 0!==a.autoHide?a.autoHide:!0;this.s=void 0;this.f&&Sf(this.element,"ol-hidden")}x(Ig,ig);Ig.prototype.u=function(a){a.preventDefault();if(void 0!==this.i)this.i();else{a=this.a;var c=a.ga();if(c){var d=c.ua();void 0!==d&&(0<this.l&&(d%=2*Math.PI,d<-Math.PI&&(d+=2*Math.PI),d>Math.PI&&(d-=2*Math.PI),a.wa(jf({rotation:d,duration:this.l,easing:df}))),c.Id(0))}}}; -function Jg(a){if(a=a.frameState){a=a.viewState.rotation;if(a!=this.s){var c="rotate("+a+"rad)";if(this.f){var d=this.element;0===a?Sf(d,"ol-hidden"):Tf(d,"ol-hidden")}this.c.style.msTransform=c;this.c.style.webkitTransform=c;this.c.style.transform=c}this.s=a}};function Kg(a){a=a?a:{};var c=a.className?a.className:"ol-zoom",d=a.delta?a.delta:1,e=a.zoomOutLabel?a.zoomOutLabel:"\u2212",f=a.zoomOutTipLabel?a.zoomOutTipLabel:"Zoom out",g=Kf("BUTTON",{"class":c+"-in",type:"button",title:a.zoomInTipLabel?a.zoomInTipLabel:"Zoom in"},a.zoomInLabel?a.zoomInLabel:"+");y(g,"click",ta(Kg.prototype.f,d),!1,this);e=Kf("BUTTON",{"class":c+"-out",type:"button",title:f},e);y(e,"click",ta(Kg.prototype.f,-d),!1,this);c=Kf("DIV",c+" ol-unselectable ol-control",g,e);ig.call(this, -{element:c,target:a.target});this.c=void 0!==a.duration?a.duration:250}x(Kg,ig);Kg.prototype.f=function(a,c){c.preventDefault();var d=this.a,e=d.ga();if(e){var f=e.$();f&&(0<this.c&&d.wa(kf({resolution:f,duration:this.c,easing:df})),d=e.constrainResolution(f,a),e.Gb(d))}};function Lg(a){a=a?a:{};var c=new F;(void 0!==a.zoom?a.zoom:1)&&c.push(new Kg(a.zoomOptions));(void 0!==a.rotate?a.rotate:1)&&c.push(new Ig(a.rotateOptions));(void 0!==a.attribution?a.attribution:1)&&c.push(new Gg(a.attributionOptions));return c};function Mg(a){a=a?a:{};var c=Kf("DIV",a.className?a.className:"ol-mouse-position");ig.call(this,{element:c,render:a.render?a.render:Ng,target:a.target});y(this,$c("projection"),this.ji,!1,this);a.coordinateFormat&&this.of(a.coordinateFormat);a.projection&&this.Pe(fe(a.projection));this.s=a.undefinedHTML?a.undefinedHTML:"";this.l=c.innerHTML;this.i=this.f=this.c=null}x(Mg,ig); -function Ng(a){a=a.frameState;a?this.c!=a.viewState.projection&&(this.c=a.viewState.projection,this.f=null):this.c=null;Og(this,this.i)}k=Mg.prototype;k.ji=function(){this.f=null};k.pe=function(){return this.get("coordinateFormat")};k.Oe=function(){return this.get("projection")};k.oh=function(a){this.i=this.a.sc(a.b);Og(this,this.i)};k.ph=function(){Og(this,null);this.i=null}; -k.setMap=function(a){Mg.fa.setMap.call(this,a);a&&(a=a.a,this.j.push(y(a,"mousemove",this.oh,!1,this),y(a,"mouseout",this.ph,!1,this)))};k.of=function(a){this.C("coordinateFormat",a)};k.Pe=function(a){this.C("projection",a)};function Og(a,c){var d=a.s;if(c&&a.c){if(!a.f){var e=a.Oe();a.f=e?je(a.c,e):re}if(e=a.a.ra(c))a.f(e,e),d=(d=a.pe())?d(e):e.toString()}a.l&&d==a.l||(a.element.innerHTML=d,a.l=d)};function Pg(a,c,d){gc.call(this);this.b=null;this.c=!1;this.j=a;this.i=d;this.a=c||window;this.g=sa(this.f,this)}x(Pg,gc);Pg.prototype.start=function(){Qg(this);this.c=!1;var a=Rg(this),c=Sg(this);a&&!c&&this.a.mozRequestAnimationFrame?(this.b=y(this.a,"MozBeforePaint",this.g),this.a.mozRequestAnimationFrame(null),this.c=!0):this.b=a&&c?a.call(this.a,this.g):this.a.setTimeout(Yd(this.g),20)}; -function Qg(a){if(null!=a.b){var c=Rg(a),d=Sg(a);c&&!d&&a.a.mozRequestAnimationFrame?Nc(a.b):c&&d?d.call(a.a,a.b):a.a.clearTimeout(a.b)}a.b=null}Pg.prototype.f=function(){this.c&&this.b&&Nc(this.b);this.b=null;this.j.call(this.i,ua())};Pg.prototype.Z=function(){Qg(this);Pg.fa.Z.call(this)};function Rg(a){a=a.a;return a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||null} -function Sg(a){a=a.a;return a.cancelAnimationFrame||a.cancelRequestAnimationFrame||a.webkitCancelRequestAnimationFrame||a.mozCancelRequestAnimationFrame||a.oCancelRequestAnimationFrame||a.msCancelRequestAnimationFrame||null};var Tg; -function Ug(){var a=ba.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!Ab("Presto")&&(a=function(){var a=document.createElement("IFRAME");a.style.display="none";a.src="";document.documentElement.appendChild(a);var c=a.contentWindow,a=c.document;a.open();a.write("");a.close();var d="callImmediate"+Math.random(),e="file:"==c.location.protocol?"*":c.location.protocol+"//"+c.location.host,a=sa(function(a){if(("*"==e||a.origin==e)&&a.data== -d)this.port1.onmessage()},this);c.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){c.postMessage(d,e)}}});if("undefined"!==typeof a&&!Ab("Trident")&&!Ab("MSIE")){var c=new a,d={},e=d;c.port1.onmessage=function(){if(ca(d.next)){d=d.next;var a=d.ke;d.ke=null;a()}};return function(a){e.next={ke:a};e=e.next;c.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?function(a){var c=document.createElement("SCRIPT"); -c.onreadystatechange=function(){c.onreadystatechange=null;c.parentNode.removeChild(c);c=null;a();a=null};document.documentElement.appendChild(c)}:function(a){ba.setTimeout(a,0)}};function Vg(a,c){this.a={};this.b=[];this.c=this.g=0;var d=arguments.length;if(1<d){if(d%2)throw Error("Uneven number of arguments");for(var e=0;e<d;e+=2)Wg(this,arguments[e],arguments[e+1])}else if(a){a instanceof Vg?(d=a.L(),e=a.fb()):(d=Fb(a),e=Eb(a));for(var f=0;f<d.length;f++)Wg(this,d[f],e[f])}}k=Vg.prototype;k.Rb=function(){return this.g};k.fb=function(){Xg(this);for(var a=[],c=0;c<this.b.length;c++)a.push(this.a[this.b[c]]);return a};k.L=function(){Xg(this);return this.b.concat()}; -k.Ja=function(){return 0==this.g};k.clear=function(){this.a={};this.c=this.g=this.b.length=0};k.remove=function(a){return Yg(this.a,a)?(delete this.a[a],this.g--,this.c++,this.b.length>2*this.g&&Xg(this),!0):!1};function Xg(a){if(a.g!=a.b.length){for(var c=0,d=0;c<a.b.length;){var e=a.b[c];Yg(a.a,e)&&(a.b[d++]=e);c++}a.b.length=d}if(a.g!=a.b.length){for(var f={},d=c=0;c<a.b.length;)e=a.b[c],Yg(f,e)||(a.b[d++]=e,f[e]=1),c++;a.b.length=d}}k.get=function(a,c){return Yg(this.a,a)?this.a[a]:c}; -function Wg(a,c,d){Yg(a.a,c)||(a.g++,a.b.push(c),a.c++);a.a[c]=d}k.forEach=function(a,c){for(var d=this.L(),e=0;e<d.length;e++){var f=d[e],g=this.get(f);a.call(c,g,f,this)}};k.clone=function(){return new Vg(this)};function Yg(a,c){return Object.prototype.hasOwnProperty.call(a,c)};function Zg(){this.b=ua()}new Zg;Zg.prototype.reset=function(){this.b=ua()};Zg.prototype.get=function(){return this.b};function $g(a){Sc.call(this);this.a=a||window;this.g=y(this.a,"resize",this.f,!1,this);this.c=Jf(this.a||window)}x($g,Sc);$g.prototype.Z=function(){$g.fa.Z.call(this);this.g&&(Nc(this.g),this.g=null);this.c=this.a=null};$g.prototype.f=function(){var a=Jf(this.a||window),c=this.c;a==c||a&&c&&a.width==c.width&&a.height==c.height||(this.c=a,this.b("resize"))};function ah(a,c,d,e,f){if(!(Pb||Qb||Sb&&ac("525")))return!0;if(Tb&&f)return bh(a);if(f&&!e)return!1;ka(c)&&(c=ch(c));if(!d&&(17==c||18==c||Tb&&91==c))return!1;if((Sb||Qb)&&e&&d)switch(a){case 220:case 219:case 221:case 192:case 186:case 189:case 187:case 188:case 190:case 191:case 192:case 222:return!1}if(Pb&&e&&c==a)return!1;switch(a){case 13:return!0;case 27:return!(Sb||Qb)}return bh(a)} -function bh(a){if(48<=a&&57>=a||96<=a&&106>=a||65<=a&&90>=a||(Sb||Qb)&&0==a)return!0;switch(a){case 32:case 43:case 63:case 64:case 107:case 109:case 110:case 111:case 186:case 59:case 189:case 187:case 61:case 188:case 190:case 191:case 192:case 222:case 219:case 220:case 221:return!0;default:return!1}}function ch(a){if(Rb)a=dh(a);else if(Tb&&Sb)a:switch(a){case 93:a=91;break a}return a} -function dh(a){switch(a){case 61:return 187;case 59:return 186;case 173:return 189;case 224:return 91;case 0:return 224;default:return a}};function eh(a,c){Sc.call(this);a&&fh(this,a,c)}x(eh,Sc);k=eh.prototype;k.Wb=null;k.Bc=null;k.zd=null;k.Cc=null;k.ya=-1;k.Ya=-1;k.bd=!1; -var gh={3:13,12:144,63232:38,63233:40,63234:37,63235:39,63236:112,63237:113,63238:114,63239:115,63240:116,63241:117,63242:118,63243:119,63244:120,63245:121,63246:122,63247:123,63248:44,63272:46,63273:36,63275:35,63276:33,63277:34,63289:144,63302:45},hh={Up:38,Down:40,Left:37,Right:39,Enter:13,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,"U+007F":46,Home:36,End:35,PageUp:33,PageDown:34,Insert:45},ih=Pb||Qb||Sb&&ac("525"),jh=Tb&&Rb; -eh.prototype.a=function(a){if(Sb||Qb)if(17==this.ya&&!a.A||18==this.ya&&!a.a||Tb&&91==this.ya&&!a.u)this.Ya=this.ya=-1;-1==this.ya&&(a.A&&17!=a.c?this.ya=17:a.a&&18!=a.c?this.ya=18:a.u&&91!=a.c&&(this.ya=91));ih&&!ah(a.c,this.ya,a.f,a.A,a.a)?this.handleEvent(a):(this.Ya=ch(a.c),jh&&(this.bd=a.a))};eh.prototype.g=function(a){this.Ya=this.ya=-1;this.bd=a.a}; -eh.prototype.handleEvent=function(a){var c=a.b,d,e,f=c.altKey;Pb&&"keypress"==a.type?(d=this.Ya,e=13!=d&&27!=d?c.keyCode:0):(Sb||Qb)&&"keypress"==a.type?(d=this.Ya,e=0<=c.charCode&&63232>c.charCode&&bh(d)?c.charCode:0):Ob&&!Sb?(d=this.Ya,e=bh(d)?c.keyCode:0):(d=c.keyCode||this.Ya,e=c.charCode||0,jh&&(f=this.bd),Tb&&63==e&&224==d&&(d=191));var g=d=ch(d),h=c.keyIdentifier;d?63232<=d&&d in gh?g=gh[d]:25==d&&a.f&&(g=9):h&&h in hh&&(g=hh[h]);this.ya=g;a=new kh(g,e,0,c);a.a=f;this.b(a)}; -function fh(a,c,d){a.Cc&&lh(a);a.Wb=c;a.Bc=y(a.Wb,"keypress",a,d);a.zd=y(a.Wb,"keydown",a.a,d,a);a.Cc=y(a.Wb,"keyup",a.g,d,a)}function lh(a){a.Bc&&(Nc(a.Bc),Nc(a.zd),Nc(a.Cc),a.Bc=null,a.zd=null,a.Cc=null);a.Wb=null;a.ya=-1;a.Ya=-1}eh.prototype.Z=function(){eh.fa.Z.call(this);lh(this)};function kh(a,c,d,e){pc.call(this,e);this.type="key";this.c=a;this.s=c}x(kh,pc);function mh(a,c){Sc.call(this);var d=this.a=a;(d=ma(d)&&1==d.nodeType?this.a:this.a?this.a.body:null)&&Yf(d,"direction");this.g=y(this.a,Rb?"DOMMouseScroll":"mousewheel",this,c)}x(mh,Sc); -mh.prototype.handleEvent=function(a){var c=0,d=0;a=a.b;if("mousewheel"==a.type){c=1;if(Pb||Sb&&(Ub||ac("532.0")))c=40;d=nh(-a.wheelDelta,c);c=ca(a.wheelDeltaX)?nh(-a.wheelDeltaY,c):d}else d=a.detail,100<d?d=3:-100>d&&(d=-3),ca(a.axis)&&a.axis===a.HORIZONTAL_AXIS||(c=d);ka(this.c)&&(c=Math.min(Math.max(c,-this.c),this.c));d=new oh(d,a,0,c);this.b(d)};function nh(a,c){return Sb&&(Tb||Wb)&&0!=a%c?a:a/c}mh.prototype.Z=function(){mh.fa.Z.call(this);Nc(this.g);this.g=null}; -function oh(a,c,d,e){pc.call(this,c);this.type="mousewheel";this.detail=a;this.H=e}x(oh,pc);function ph(a,c,d){lc.call(this,a);this.b=c;a=d?d:{};this.buttons=qh(a);this.pressure=rh(a,this.buttons);this.bubbles="bubbles"in a?a.bubbles:!1;this.cancelable="cancelable"in a?a.cancelable:!1;this.view="view"in a?a.view:null;this.detail="detail"in a?a.detail:null;this.screenX="screenX"in a?a.screenX:0;this.screenY="screenY"in a?a.screenY:0;this.clientX="clientX"in a?a.clientX:0;this.clientY="clientY"in a?a.clientY:0;this.button="button"in a?a.button:0;this.relatedTarget="relatedTarget"in a?a.relatedTarget: -null;this.pointerId="pointerId"in a?a.pointerId:0;this.width="width"in a?a.width:0;this.height="height"in a?a.height:0;this.pointerType="pointerType"in a?a.pointerType:"";this.isPrimary="isPrimary"in a?a.isPrimary:!1;c.preventDefault&&(this.preventDefault=function(){c.preventDefault()})}x(ph,lc);function qh(a){if(a.buttons||sh)a=a.buttons;else switch(a.which){case 1:a=1;break;case 2:a=4;break;case 3:a=2;break;default:a=0}return a} -function rh(a,c){var d=0;a.pressure?d=a.pressure:d=c?.5:0;return d}var sh=!1;try{sh=1===(new MouseEvent("click",{buttons:1})).buttons}catch(a){};function th(a,c){var d=document.createElement("CANVAS");a&&(d.width=a);c&&(d.height=c);return d.getContext("2d")};var uh=ba.devicePixelRatio||1,vh=!1,wh=function(){if(!("HTMLCanvasElement"in ba))return!1;try{var a=th();return a?(void 0!==a.setLineDash&&(vh=!0),!0):!1}catch(c){return!1}}(),xh="DeviceOrientationEvent"in ba,yh="geolocation"in ba.navigator,zh="ontouchstart"in ba,Ah="PointerEvent"in ba,Bh=!!ba.navigator.msPointerEnabled;function Ch(a,c){this.b=a;this.f=c};function Dh(a){Ch.call(this,a,{mousedown:this.Gh,mousemove:this.Hh,mouseup:this.Kh,mouseover:this.Jh,mouseout:this.Ih});this.a=a.g;this.g=[]}x(Dh,Ch);function Eh(a,c){for(var d=a.g,e=c.clientX,f=c.clientY,g=0,h=d.length,l;g<h&&(l=d[g]);g++){var m=Math.abs(f-l[1]);if(25>=Math.abs(e-l[0])&&25>=m)return!0}return!1}function Fh(a){var c=Gh(a,a.b),d=c.preventDefault;c.preventDefault=function(){a.preventDefault();d()};c.pointerId=1;c.isPrimary=!0;c.pointerType="mouse";return c}k=Dh.prototype; -k.Gh=function(a){if(!Eh(this,a)){if((1).toString()in this.a){var c=Fh(a);Hh(this.b,Ih,c,a);delete this.a[(1).toString()]}c=Fh(a);this.a[(1).toString()]=a;Hh(this.b,Jh,c,a)}};k.Hh=function(a){if(!Eh(this,a)){var c=Fh(a);Hh(this.b,Kh,c,a)}};k.Kh=function(a){if(!Eh(this,a)){var c=this.a[(1).toString()];c&&c.button===a.button&&(c=Fh(a),Hh(this.b,Lh,c,a),delete this.a[(1).toString()])}};k.Jh=function(a){if(!Eh(this,a)){var c=Fh(a);Mh(this.b,c,a)}}; -k.Ih=function(a){if(!Eh(this,a)){var c=Fh(a);Nh(this.b,c,a)}};function Oh(a){Ch.call(this,a,{MSPointerDown:this.Ph,MSPointerMove:this.Qh,MSPointerUp:this.Th,MSPointerOut:this.Rh,MSPointerOver:this.Sh,MSPointerCancel:this.Oh,MSGotPointerCapture:this.Mh,MSLostPointerCapture:this.Nh});this.a=a.g;this.g=["","unavailable","touch","pen","mouse"]}x(Oh,Ch);function Ph(a,c){var d=c;ka(c.b.pointerType)&&(d=Gh(c,c.b),d.pointerType=a.g[c.b.pointerType]);return d}k=Oh.prototype;k.Ph=function(a){this.a[a.b.pointerId.toString()]=a;var c=Ph(this,a);Hh(this.b,Jh,c,a)}; -k.Qh=function(a){var c=Ph(this,a);Hh(this.b,Kh,c,a)};k.Th=function(a){var c=Ph(this,a);Hh(this.b,Lh,c,a);delete this.a[a.b.pointerId.toString()]};k.Rh=function(a){var c=Ph(this,a);Nh(this.b,c,a)};k.Sh=function(a){var c=Ph(this,a);Mh(this.b,c,a)};k.Oh=function(a){var c=Ph(this,a);Hh(this.b,Ih,c,a);delete this.a[a.b.pointerId.toString()]};k.Nh=function(a){this.b.b(new ph("lostpointercapture",a,a.b))};k.Mh=function(a){this.b.b(new ph("gotpointercapture",a,a.b))};function Qh(a){Ch.call(this,a,{pointerdown:this.Gj,pointermove:this.Hj,pointerup:this.Kj,pointerout:this.Ij,pointerover:this.Jj,pointercancel:this.Fj,gotpointercapture:this.eh,lostpointercapture:this.Fh})}x(Qh,Ch);k=Qh.prototype;k.Gj=function(a){Rh(this.b,a)};k.Hj=function(a){Rh(this.b,a)};k.Kj=function(a){Rh(this.b,a)};k.Ij=function(a){Rh(this.b,a)};k.Jj=function(a){Rh(this.b,a)};k.Fj=function(a){Rh(this.b,a)};k.Fh=function(a){Rh(this.b,a)};k.eh=function(a){Rh(this.b,a)};function Sh(a,c){Ch.call(this,a,{touchstart:this.vk,touchmove:this.uk,touchend:this.tk,touchcancel:this.sk});this.a=a.g;this.j=c;this.g=void 0;this.i=0;this.c=void 0}x(Sh,Ch);k=Sh.prototype;k.mf=function(){this.i=0;this.c=void 0}; -function Th(a,c,d){c=Gh(c,d);c.pointerId=d.identifier+2;c.bubbles=!0;c.cancelable=!0;c.detail=a.i;c.button=0;c.buttons=1;c.width=d.webkitRadiusX||d.radiusX||0;c.height=d.webkitRadiusY||d.radiusY||0;c.pressure=d.webkitForce||d.force||.5;c.isPrimary=a.g===d.identifier;c.pointerType="touch";c.clientX=d.clientX;c.clientY=d.clientY;c.screenX=d.screenX;c.screenY=d.screenY;return c} -function Uh(a,c,d){function e(){c.preventDefault()}var f=Array.prototype.slice.call(c.b.changedTouches),g=f.length,h,l;for(h=0;h<g;++h)l=Th(a,c,f[h]),l.preventDefault=e,d.call(a,c,l)} -k.vk=function(a){var c=a.b.touches,d=Fb(this.a),e=d.length;if(e>=c.length){var f=[],g,h,l;for(g=0;g<e;++g){h=d[g];l=this.a[h];var m;if(!(m=1==h))a:{m=c.length;for(var n=void 0,p=0;p<m;p++)if(n=c[p],n.identifier===h-2){m=!0;break a}m=!1}m||f.push(l.kb)}for(g=0;g<f.length;++g)this.cd(a,f[g])}c=Db(this.a);if(!(d=0===c)){if(c=1===c)c=(1).toString()in this.a;d=c}d&&(this.g=a.b.changedTouches[0].identifier,void 0!==this.c&&ba.clearTimeout(this.c));Vh(this,a);this.i++;Uh(this,a,this.Ej)}; -k.Ej=function(a,c){this.a[c.pointerId]={target:c.target,kb:c,jf:c.target};var d=this.b;c.bubbles=!0;Hh(d,Wh,c,a);d=this.b;c.bubbles=!1;Hh(d,Xh,c,a);Hh(this.b,Jh,c,a)};k.uk=function(a){a.preventDefault();Uh(this,a,this.Lh)};k.Lh=function(a,c){var d=this.a[c.pointerId];if(d){var e=d.kb,f=d.jf;Hh(this.b,Kh,c,a);e&&f!==c.target&&(e.relatedTarget=c.target,c.relatedTarget=f,e.target=f,c.target?(Nh(this.b,e,a),Mh(this.b,c,a)):(c.target=f,c.relatedTarget=null,this.cd(a,c)));d.kb=c;d.jf=c.target}}; -k.tk=function(a){Vh(this,a);Uh(this,a,this.wk)};k.wk=function(a,c){Hh(this.b,Lh,c,a);this.b.kb(c,a);var d=this.b;c.bubbles=!1;Hh(d,Yh,c,a);delete this.a[c.pointerId];c.isPrimary&&(this.g=void 0,this.c=ba.setTimeout(sa(this.mf,this),200))};k.sk=function(a){Uh(this,a,this.cd)};k.cd=function(a,c){Hh(this.b,Ih,c,a);this.b.kb(c,a);var d=this.b;c.bubbles=!1;Hh(d,Yh,c,a);delete this.a[c.pointerId];c.isPrimary&&(this.g=void 0,this.c=ba.setTimeout(sa(this.mf,this),200))}; -function Vh(a,c){var d=a.j.g,e=c.b.changedTouches[0];if(a.g===e.identifier){var f=[e.clientX,e.clientY];d.push(f);ba.setTimeout(function(){bb(d,f)},2500)}};function Zh(a){Sc.call(this);this.i=a;this.g={};this.f={};this.a=[];Ah?$h(this,new Qh(this)):Bh?$h(this,new Oh(this)):(a=new Dh(this),$h(this,a),zh&&$h(this,new Sh(this,a)));a=this.a.length;for(var c,d=0;d<a;d++)c=this.a[d],ai(this,Object.keys(c.f))}x(Zh,Sc);function $h(a,c){var d=Object.keys(c.f);d&&(d.forEach(function(a){var d=c.f[a];d&&(this.f[a]=sa(d,c))},a),a.a.push(c))}Zh.prototype.c=function(a){var c=this.f[a.type];c&&c(a)}; -function ai(a,c){c.forEach(function(a){y(this.i,a,this.c,!1,this)},a)}function bi(a,c){c.forEach(function(a){Mc(this.i,a,this.c,!1,this)},a)}function Gh(a,c){for(var d={},e,f=0,g=ci.length;f<g;f++)e=ci[f][0],d[e]=a[e]||c[e]||ci[f][1];return d}Zh.prototype.kb=function(a,c){a.bubbles=!0;Hh(this,di,a,c)};function Nh(a,c,d){a.kb(c,d);var e=c.relatedTarget;e&&Pf(c.target,e)||(c.bubbles=!1,Hh(a,Yh,c,d))} -function Mh(a,c,d){c.bubbles=!0;Hh(a,Wh,c,d);var e=c.relatedTarget;e&&Pf(c.target,e)||(c.bubbles=!1,Hh(a,Xh,c,d))}function Hh(a,c,d,e){a.b(new ph(c,e,d))}function Rh(a,c){a.b(new ph(c.type,c,c.b))}Zh.prototype.Z=function(){for(var a=this.a.length,c,d=0;d<a;d++)c=this.a[d],bi(this,Object.keys(c.f));Zh.fa.Z.call(this)}; -var Kh="pointermove",Jh="pointerdown",Lh="pointerup",Wh="pointerover",di="pointerout",Xh="pointerenter",Yh="pointerleave",Ih="pointercancel",ci=[["bubbles",!1],["cancelable",!1],["view",null],["detail",null],["screenX",0],["screenY",0],["clientX",0],["clientY",0],["ctrlKey",!1],["altKey",!1],["shiftKey",!1],["metaKey",!1],["button",0],["relatedTarget",null],["buttons",0],["pointerId",0],["width",0],["height",0],["pressure",0],["tiltX",0],["tiltY",0],["pointerType",""],["hwTimestamp",0],["isPrimary", -!1],["type",""],["target",null],["currentTarget",null],["which",0]];function ei(a,c,d,e,f){hg.call(this,a,c,f);this.b=d;this.originalEvent=d.b;this.pixel=c.sc(this.originalEvent);this.coordinate=c.ra(this.pixel);this.dragging=void 0!==e?e:!1}x(ei,hg);ei.prototype.preventDefault=function(){ei.fa.preventDefault.call(this);this.b.preventDefault()};ei.prototype.i=function(){ei.fa.i.call(this);this.b.i()};function fi(a,c,d,e,f){ei.call(this,a,c,d.b,e,f);this.a=d}x(fi,ei); -function gi(a){Sc.call(this);this.c=a;this.j=0;this.A=!1;this.g=this.l=this.f=null;a=this.c.a;this.H=0;this.u={};this.i=new Zh(a);this.a=null;this.l=y(this.i,Jh,this.rh,!1,this);this.s=y(this.i,Kh,this.Rj,!1,this)}x(gi,Sc);function hi(a,c){var d;d=new fi(ii,a.c,c);a.b(d);0!==a.j?(ba.clearTimeout(a.j),a.j=0,d=new fi(ji,a.c,c),a.b(d)):a.j=ba.setTimeout(sa(function(){this.j=0;var a=new fi(ki,this.c,c);this.b(a)},a),250)} -function li(a,c){c.type==mi||c.type==ni?delete a.u[c.pointerId]:c.type==oi&&(a.u[c.pointerId]=!0);a.H=Db(a.u)}k=gi.prototype;k.Fe=function(a){li(this,a);var c=new fi(mi,this.c,a);this.b(c);!this.A&&0===a.button&&hi(this,this.g);0===this.H&&(this.f.forEach(Nc),this.f=null,this.A=!1,this.g=null,kc(this.a),this.a=null)}; -k.rh=function(a){li(this,a);var c=new fi(oi,this.c,a);this.b(c);this.g=a;this.f||(this.a=new Zh(document),this.f=[y(this.a,pi,this.ei,!1,this),y(this.a,mi,this.Fe,!1,this),y(this.i,ni,this.Fe,!1,this)])};k.ei=function(a){if(a.clientX!=this.g.clientX||a.clientY!=this.g.clientY){this.A=!0;var c=new fi(qi,this.c,a,this.A);this.b(c)}a.preventDefault()};k.Rj=function(a){this.b(new fi(a.type,this.c,a,!(!this.g||a.clientX==this.g.clientX&&a.clientY==this.g.clientY)))}; -k.Z=function(){this.s&&(Nc(this.s),this.s=null);this.l&&(Nc(this.l),this.l=null);this.f&&(this.f.forEach(Nc),this.f=null);this.a&&(kc(this.a),this.a=null);this.i&&(kc(this.i),this.i=null);gi.fa.Z.call(this)};var ki="singleclick",ii="click",ji="dblclick",qi="pointerdrag",pi="pointermove",oi="pointerdown",mi="pointerup",ni="pointercancel",ri={Jk:ki,yk:ii,zk:ji,Ck:qi,Fk:pi,Bk:oi,Ik:mi,Hk:"pointerover",Gk:"pointerout",Dk:"pointerenter",Ek:"pointerleave",Ak:ni};function si(a){Yc.call(this);var c=Kb(a);c.opacity=void 0!==a.opacity?a.opacity:1;c.visible=void 0!==a.visible?a.visible:!0;c.zIndex=void 0!==a.zIndex?a.zIndex:0;c.maxResolution=void 0!==a.maxResolution?a.maxResolution:Infinity;c.minResolution=void 0!==a.minResolution?a.minResolution:0;this.K(c)}x(si,Yc); -function ti(a){var c=a.yb(),d=a.sd(),e=a.Xa(),f=a.F(),g=a.zb(),h=a.ub(),l=a.vb();return{layer:a,opacity:Pa(c,0,1),D:d,visible:e,Xb:!0,extent:f,zIndex:g,maxResolution:h,minResolution:Math.max(l,0)}}k=si.prototype;k.F=function(){return this.get("extent")};k.ub=function(){return this.get("maxResolution")};k.vb=function(){return this.get("minResolution")};k.yb=function(){return this.get("opacity")};k.Xa=function(){return this.get("visible")};k.zb=function(){return this.get("zIndex")}; -k.ac=function(a){this.C("extent",a)};k.ic=function(a){this.C("maxResolution",a)};k.jc=function(a){this.C("minResolution",a)};k.bc=function(a){this.C("opacity",a)};k.cc=function(a){this.C("visible",a)};k.dc=function(a){this.C("zIndex",a)};function ui(){};function vi(a,c,d,e,f,g){lc.call(this,a,c);this.vectorContext=d;this.frameState=e;this.context=f;this.glContext=g}x(vi,lc);function G(a){var c=Kb(a);delete c.source;si.call(this,c);this.a=this.f=this.c=null;a.map&&this.setMap(a.map);y(this,$c("source"),this.wh,!1,this);this.kc(a.source?a.source:null)}x(G,si);k=G.prototype;k.qd=function(a){a=a?a:[];a.push(ti(this));return a};k.ha=function(){return this.get("source")||null};k.sd=function(){var a=this.ha();return a?a.H:"undefined"};k.Mi=function(){this.v()};k.wh=function(){this.a&&(Nc(this.a),this.a=null);var a=this.ha();a&&(this.a=y(a,"change",this.Mi,!1,this));this.v()}; -k.setMap=function(a){Nc(this.c);this.c=null;a||this.v();Nc(this.f);this.f=null;a&&(this.c=y(a,"precompose",function(a){var d=ti(this);d.Xb=!1;d.zIndex=Infinity;a.frameState.layerStatesArray.push(d);a.frameState.layerStates[na(this)]=d},!1,this),this.f=y(this,"change",a.render,!1,a),this.v())};k.kc=function(a){this.C("source",a)};function wi(a,c,d,e,f){Sc.call(this);this.A=f;this.extent=a;this.c=d;this.resolution=c;this.state=e}x(wi,Sc);function yi(a){a.b("change")}wi.prototype.F=function(){return this.extent};wi.prototype.$=function(){return this.resolution};function zi(a,c,d,e,f,g,h,l){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;0===c&&0===d||td(a,c,d);if(1!=e||1!=f){c=a[1]*e;d=a[2]*e;var m=a[3]*e,n=a[4]*f,p=a[5]*f,q=a[6]*f;f=a[7]*f;var r=1*a[8],t=1*a[9],B=1*a[10],V=1*a[11],w=a[12],E=a[13],u=a[14],Ca=a[15];a[0]*=e;a[1]=c;a[2]=d;a[3]=m;a[4]=n;a[5]=p;a[6]=q;a[7]=f;a[8]=r;a[9]=t;a[10]=B;a[11]=V;a[12]=w;a[13]=E;a[14]=u;a[15]=Ca}0!==g&&(e=a[0],c=a[1],d=a[2],m=a[3],n=a[4],p=a[5],q=a[6], -f=a[7],r=Math.cos(g),g=Math.sin(g),a[0]=e*r+n*g,a[1]=c*r+p*g,a[2]=d*r+q*g,a[3]=m*r+f*g,a[4]=e*-g+n*r,a[5]=c*-g+p*r,a[6]=d*-g+q*r,a[7]=m*-g+f*r);0===h&&0===l||td(a,h,l);return a}function Ai(a,c,d){var e=a[1],f=a[5],g=a[13],h=c[0];c=c[1];d[0]=a[0]*h+a[4]*c+a[12];d[1]=e*h+f*c+g;return d};function Bi(a){Vc.call(this);this.a=a}x(Bi,Vc);Bi.prototype.ec=wa;Bi.prototype.Kd=function(a,c,d,e){a=a.slice();Ai(c.pixelToCoordinateMatrix,a,a);if(this.ec(a,c,Xd,this))return d.call(e,this.a)};function Ci(a,c,d){return function(e,f){return Eg(a,c,e,f,function(a){d[e]||(d[e]={});d[e][a.a.toString()]=a})}}Bi.prototype.I=function(a){2===a.target.state&&Di(this)};function Di(a){var c=a.a;c.Xa()&&"ready"==c.sd()&&a.v()} -function Ei(a,c){c.Ze()&&a.postRenderFunctions.push(ta(function(a,c,f){c=na(a).toString();a.$e(f.viewState.projection,f.usedTiles[c])},c))}function Fi(a,c){if(c){var d,e,f;e=0;for(f=c.length;e<f;++e)d=c[e],a[na(d).toString()]=d}}function Gi(a,c){var d=c.Y;void 0!==d&&(ha(d)?a.logos[d]="":ma(d)&&(a.logos[d.src]=d.href))} -function Hi(a,c,d,e){c=na(c).toString();d=d.toString();c in a?d in a[c]?(a=a[c][d],e.b<a.b&&(a.b=e.b),e.a>a.a&&(a.a=e.a),e.c<a.c&&(a.c=e.c),e.g>a.g&&(a.g=e.g)):a[c][d]=e:(a[c]={},a[c][d]=e)}function Ii(a,c,d){return[c*(Math.round(a[0]/c)+d[0]%2/2),c*(Math.round(a[1]/c)+d[1]%2/2)]} -function Ji(a,c,d,e,f,g,h,l){var m=na(c).toString();m in a.wantedTiles||(a.wantedTiles[m]={});var n=a.wantedTiles[m];a=a.tileQueue;var p=d.minZoom,q,r,t,B,V,w;for(w=h;w>=p;--w)for(r=d.Wa(g,w,r),t=d.$(w),B=r.b;B<=r.a;++B)for(V=r.c;V<=r.g;++V)if(h-w<=l){if(q=Ki(c,w,B,V,e,f),0==q.state&&(n[mf(q.a)]=!0,!(q.Hd()in a.g))){var E=a;q=[q,m,zg(d,q.a),t];var u=E.j(q);Infinity!=u&&(E.b.push(q),E.a.push(u),E.g[E.f(q)]=!0,Li(E,0,E.b.length-1))}}else c.Df(w,B,V,f)};function Mi(a){this.H=a.opacity;this.D=a.rotateWithView;this.s=a.rotation;this.j=a.scale;this.G=a.snapToPixel}k=Mi.prototype;k.Mc=function(){return this.H};k.uc=function(){return this.D};k.Nc=function(){return this.s};k.Oc=function(){return this.j};k.vc=function(){return this.G};k.Pc=function(a){this.H=a};k.Qc=function(a){this.s=a};k.Rc=function(a){this.j=a};function Ni(a){a=a||{};this.f=void 0!==a.anchor?a.anchor:[.5,.5];this.c=null;this.a=void 0!==a.anchorOrigin?a.anchorOrigin:"top-left";this.A=void 0!==a.anchorXUnits?a.anchorXUnits:"fraction";this.l=void 0!==a.anchorYUnits?a.anchorYUnits:"fraction";var c=void 0!==a.crossOrigin?a.crossOrigin:null,d=void 0!==a.img?a.img:null,e=void 0!==a.imgSize?a.imgSize:null,f=a.src;void 0!==f&&0!==f.length||!d||(f=d.src);var g=void 0!==a.src?0:2,h=Oi.se(),l=h.get(f,c);l||(l=new Pi(d,f,e,c,g),h.b[c+":"+f]=l,++h.a); -this.b=l;this.B=void 0!==a.offset?a.offset:[0,0];this.g=void 0!==a.offsetOrigin?a.offsetOrigin:"top-left";this.i=null;this.u=void 0!==a.size?a.size:null;Mi.call(this,{opacity:void 0!==a.opacity?a.opacity:1,rotation:void 0!==a.rotation?a.rotation:0,scale:void 0!==a.scale?a.scale:1,snapToPixel:void 0!==a.snapToPixel?a.snapToPixel:!0,rotateWithView:void 0!==a.rotateWithView?a.rotateWithView:!1})}x(Ni,Mi);k=Ni.prototype; -k.eb=function(){if(this.c)return this.c;var a=this.f,c=this.Ta();if("fraction"==this.A||"fraction"==this.l){if(!c)return null;a=this.f.slice();"fraction"==this.A&&(a[0]*=c[0]);"fraction"==this.l&&(a[1]*=c[1])}if("top-left"!=this.a){if(!c)return null;a===this.f&&(a=this.f.slice());if("top-right"==this.a||"bottom-right"==this.a)a[0]=-a[0]+c[0];if("bottom-left"==this.a||"bottom-right"==this.a)a[1]=-a[1]+c[1]}return this.c=a};k.jb=function(){return this.b.a};k.tc=function(){return this.b.c};k.gc=function(){return this.b.g}; -k.Md=function(){var a=this.b;if(!a.i)if(a.l){var c=a.c[0],d=a.c[1],e=th(c,d);e.fillRect(0,0,c,d);a.i=e.canvas}else a.i=a.a;return a.i};k.ta=function(){if(this.i)return this.i;var a=this.B;if("top-left"!=this.g){var c=this.Ta(),d=this.b.c;if(!c||!d)return null;a=a.slice();if("top-right"==this.g||"bottom-right"==this.g)a[0]=d[0]-c[0]-a[0];if("bottom-left"==this.g||"bottom-right"==this.g)a[1]=d[1]-c[1]-a[1]}return this.i=a};k.hj=function(){return this.b.j};k.Ta=function(){return this.u?this.u:this.b.c}; -k.Cd=function(a,c){return y(this.b,"change",a,!1,c)};k.load=function(){this.b.load()};k.Yd=function(a,c){Mc(this.b,"change",a,!1,c)};function Pi(a,c,d,e,f){Sc.call(this);this.i=null;this.a=a?a:new Image;null!==e&&(this.a.crossOrigin=e);this.f=null;this.g=f;this.c=d;this.j=c;this.l=!1;2==this.g&&Qi(this)}x(Pi,Sc);function Qi(a){var c=th(1,1);try{c.drawImage(a.a,0,0),c.getImageData(0,0,1,1)}catch(d){a.l=!0}}Pi.prototype.A=function(){this.g=3;this.f.forEach(Nc);this.f=null;this.b("change")}; -Pi.prototype.s=function(){this.g=2;this.c=[this.a.width,this.a.height];this.f.forEach(Nc);this.f=null;Qi(this);this.b("change")};Pi.prototype.load=function(){if(0==this.g){this.g=1;this.f=[Lc(this.a,"error",this.A,!1,this),Lc(this.a,"load",this.s,!1,this)];try{this.a.src=this.j}catch(a){this.A()}}};function Oi(){this.b={};this.a=0}(function(){var a=Oi;a.se=function(){return a.Ge?a.Ge:a.Ge=new a}})();Oi.prototype.clear=function(){this.b={};this.a=0}; -Oi.prototype.get=function(a,c){var d=c+":"+a;return d in this.b?this.b[d]:null};function Ri(a,c){gc.call(this);this.i=c;this.a={};this.c={}}x(Ri,gc);Ri.prototype.Z=function(){Bb(this.a,kc);Ri.fa.Z.call(this)};function Si(){var a=Oi.se();if(32<a.a){var c=0,d,e;for(d in a.b){e=a.b[d];var f;if(f=0===(c++&3))tc(e)?e=Uc(e,void 0,void 0):(e=Hc(e),e=!!e&&Ac(e,void 0,void 0)),f=!e;f&&(delete a.b[d],--a.a)}}} -function Ti(a,c,d,e,f,g,h){function l(a){var c=na(a).toString();if(!(c in q))return q[c]=!0,e.call(f,a,null)}var m,n=d.viewState,p=n.resolution,q={},r=n.projection,n=c;if(r.a){var r=r.F(),t=Pd(r),B=c[0];if(B<r[0]||B>r[2])n=[B+t*Math.ceil((r[0]-B)/t),c[1]]}r=d.layerStatesArray;for(t=r.length-1;0<=t;--t){var B=r[t],V=B.layer;if(!B.Xb||B.visible&&p>=B.minResolution&&p<B.maxResolution&&g.call(h,V)){var w=Ui(a,V);V.ha()&&(m=w.ec(rg(V.ha())?n:c,d,B.Xb?e:l,f));if(m)return m}}} -function Ui(a,c){var d=na(c).toString();if(d in a.a)return a.a[d];var e;e=c instanceof H?new Vi(c):c instanceof I?new Wi(c):c instanceof J?new Xi(c):null;a.a[d]=e;a.c[d]=y(e,"change",a.A,!1,a);return e}Ri.prototype.A=function(){this.i.render()};Ri.prototype.j=wa;Ri.prototype.s=function(a,c){for(var d in this.a)if(!(c&&d in c.layerStates)){var e=d,f=this.a[e];delete this.a[e];Nc(this.c[e]);delete this.c[e];kc(f)}};function mb(a,c){return a.zIndex-c.zIndex};function Yi(a,c){this.j=a;this.f=c;this.b=[];this.a=[];this.g={}}Yi.prototype.clear=function(){this.b.length=0;this.a.length=0;Hb(this.g)};Yi.prototype.Rb=function(){return this.b.length};Yi.prototype.Ja=function(){return 0===this.b.length};function Zi(a,c){for(var d=a.b,e=a.a,f=d.length,g=d[c],h=e[c],l=c;c<f>>1;){var m=2*c+1,n=2*c+2,m=n<f&&e[n]<e[m]?n:m;d[c]=d[m];e[c]=e[m];c=m}d[c]=g;e[c]=h;Li(a,l,c)} -function Li(a,c,d){var e=a.b;a=a.a;for(var f=e[d],g=a[d];d>c;){var h=d-1>>1;if(a[h]>g)e[d]=e[h],a[d]=a[h],d=h;else break}e[d]=f;a[d]=g};function $i(a,c){Yi.call(this,function(c){return a.apply(null,c)},function(a){return a[0].Hd()});this.A=c;this.c=0}x($i,Yi);$i.prototype.i=function(a){a=a.target;var c=a.state;if(2===c||3===c||4===c)Mc(a,"change",this.i,!1,this),--this.c,this.A()};function aj(){this.b=[];this.a=this.g=0}function bj(a,c){var d=a.a,e=.05-d,f=Math.log(.05/a.a)/-.005;return hf({source:c,duration:f,easing:function(a){return d*(Math.exp(-.005*a*f)-1)/e}})};function cj(a){Yc.call(this);this.G=null;this.s(!0);this.handleEvent=a.handleEvent}x(cj,Yc);cj.prototype.l=function(){return this.get("active")};cj.prototype.s=function(a){this.C("active",a)};cj.prototype.setMap=function(a){this.G=a};function dj(a,c,d,e,f){if(void 0!==d){var g=c.ua(),h=c.za();void 0!==g&&h&&f&&0<f&&(a.wa(jf({rotation:g,duration:f,easing:df})),e&&a.wa(hf({source:h,duration:f,easing:df})));c.rotate(d,e)}} -function ej(a,c,d,e,f){var g=c.$();d=c.constrainResolution(g,d,0);fj(a,c,d,e,f)}function fj(a,c,d,e,f){if(d){var g=c.$(),h=c.za();void 0!==g&&h&&d!==g&&f&&0<f&&(a.wa(kf({resolution:g,duration:f,easing:df})),e&&a.wa(hf({source:h,duration:f,easing:df})));if(e){var l;a=c.za();f=c.$();void 0!==a&&void 0!==f&&(l=[e[0]-d*(e[0]-a[0])/f,e[1]-d*(e[1]-a[1])/f]);c.Ea(l)}c.Gb(d)}};function gj(a){a=a?a:{};this.a=a.delta?a.delta:1;cj.call(this,{handleEvent:hj});this.c=void 0!==a.duration?a.duration:250}x(gj,cj);function hj(a){var c=!1,d=a.b;if(a.type==ji){var c=a.map,e=a.coordinate,d=d.f?-this.a:this.a,f=c.ga();ej(c,f,d,e,this.c);a.preventDefault();c=!0}return!c};function ij(a){a=a.b;return a.a&&!a.l&&a.f}function jj(a){return a.type==ki}function kj(a){a=a.b;return!a.a&&!a.l&&!a.f}function lj(a){a=a.b;return!a.a&&!a.l&&a.f}function mj(a){a=a.b.target.tagName;return"INPUT"!==a&&"SELECT"!==a&&"TEXTAREA"!==a}function nj(a){return"mouse"==a.a.pointerType};function oj(a){a=a?a:{};cj.call(this,{handleEvent:a.handleEvent?a.handleEvent:pj});this.ob=a.handleDownEvent?a.handleDownEvent:Wd;this.Ib=a.handleDragEvent?a.handleDragEvent:wa;this.Xc=a.handleMoveEvent?a.handleMoveEvent:wa;this.Yc=a.handleUpEvent?a.handleUpEvent:Wd;this.H=!1;this.aa={};this.f=[]}x(oj,cj);function qj(a){for(var c=a.length,d=0,e=0,f=0;f<c;f++)d+=a[f].clientX,e+=a[f].clientY;return[d/c,e/c]} -function pj(a){if(!(a instanceof fi))return!0;var c=!1,d=a.type;if(d===oi||d===qi||d===mi)d=a.a,a.type==mi?delete this.aa[d.pointerId]:a.type==oi?this.aa[d.pointerId]=d:d.pointerId in this.aa&&(this.aa[d.pointerId]=d),this.f=Eb(this.aa);this.H&&(a.type==qi?this.Ib(a):a.type==mi&&(this.H=this.Yc(a)));a.type==oi?(this.H=a=this.ob(a),c=this.mb(a)):a.type==pi&&this.Xc(a);return!c}oj.prototype.mb=function(a){return a};function rj(a){oj.call(this,{handleDownEvent:sj,handleDragEvent:tj,handleUpEvent:uj});a=a?a:{};this.a=a.kinetic;this.c=this.i=null;this.u=a.condition?a.condition:kj;this.j=!1}x(rj,oj);function tj(a){var c=qj(this.f);this.a&&this.a.b.push(c[0],c[1],Date.now());if(this.c){var d=this.c[0]-c[0],e=c[1]-this.c[1];a=a.map;var f=a.ga(),g=bf(f),e=d=[d,e],h=g.resolution;e[0]*=h;e[1]*=h;ld(d,g.rotation);gd(d,g.center);d=f.qc(d);a.render();f.Ea(d)}this.c=c} -function uj(a){a=a.map;var c=a.ga();if(0===this.f.length){var d;if(d=!this.j&&this.a)if(d=this.a,6>d.b.length)d=!1;else{var e=Date.now()-100,f=d.b.length-3;if(d.b[f+2]<e)d=!1;else{for(var g=f-3;0<g&&d.b[g+2]>e;)g-=3;var e=d.b[f+2]-d.b[g+2],h=d.b[f]-d.b[g],f=d.b[f+1]-d.b[g+1];d.g=Math.atan2(f,h);d.a=Math.sqrt(h*h+f*f)/e;d=.05<d.a}}d&&(d=(.05-this.a.a)/-.005,f=this.a.g,g=c.za(),this.i=bj(this.a,g),a.wa(this.i),g=a.xa(g),d=a.ra([g[0]-d*Math.cos(f),g[1]-d*Math.sin(f)]),d=c.qc(d),c.Ea(d));cf(c,-1);a.render(); -return!1}this.c=null;return!0}function sj(a){if(0<this.f.length&&this.u(a)){var c=a.map,d=c.ga();this.c=null;this.H||cf(d,1);c.render();this.i&&bb(c.I,this.i)&&(d.Ea(a.frameState.viewState.center),this.i=null);this.a&&(a=this.a,a.b.length=0,a.g=0,a.a=0);this.j=1<this.f.length;return!0}return!1}rj.prototype.mb=Wd;function vj(a){a=a?a:{};oj.call(this,{handleDownEvent:wj,handleDragEvent:xj,handleUpEvent:yj});this.c=a.condition?a.condition:ij;this.a=void 0;this.i=void 0!==a.duration?a.duration:250}x(vj,oj);function xj(a){if(nj(a)){var c=a.map,d=c.hb();a=a.pixel;d=Math.atan2(d[1]/2-a[1],a[0]-d[0]/2);if(void 0!==this.a){a=d-this.a;var e=c.ga(),f=e.ua();c.render();dj(c,e,f-a)}this.a=d}} -function yj(a){if(!nj(a))return!0;a=a.map;var c=a.ga();cf(c,-1);var d=c.ua(),e=this.i,d=c.constrainRotation(d,0);dj(a,c,d,void 0,e);return!1}function wj(a){return nj(a)&&rc(a.b)&&this.c(a)?(a=a.map,cf(a.ga(),1),a.render(),this.a=void 0,!0):!1}vj.prototype.mb=Wd;function zj(a){this.c=null;this.a=document.createElement("div");this.a.style.position="absolute";this.a.className="ol-box "+a;this.g=this.f=this.b=null}x(zj,gc);zj.prototype.Z=function(){this.setMap(null);zj.fa.Z.call(this)};function Aj(a){var c=a.f,d=a.g;a=a.a.style;a.left=Math.min(c[0],d[0])+"px";a.top=Math.min(c[1],d[1])+"px";a.width=Math.abs(d[0]-c[0])+"px";a.height=Math.abs(d[1]-c[1])+"px"} -zj.prototype.setMap=function(a){if(this.b){this.b.B.removeChild(this.a);var c=this.a.style;c.left=c.top=c.width=c.height="inherit"}(this.b=a)&&this.b.B.appendChild(this.a)};function Bj(a){var c=a.f,d=a.g,c=[c,[c[0],d[1]],d,[d[0],c[1]]].map(a.b.ra,a.b);c[4]=c[0].slice();a.c?a.c.da([c]):a.c=new C([c])}zj.prototype.O=function(){return this.c};function Cj(a,c){lc.call(this,a);this.coordinate=c}x(Cj,lc);function Dj(a){oj.call(this,{handleDownEvent:Ej,handleDragEvent:Fj,handleUpEvent:Gj});a=a?a:{};this.c=new zj(a.className||"ol-dragbox");this.a=null;this.u=a.condition?a.condition:Xd}x(Dj,oj);function Fj(a){if(nj(a)){var c=this.c;a=a.pixel;c.f=this.a;c.g=a;Bj(c);Aj(c)}}Dj.prototype.O=function(){return this.c.O()};Dj.prototype.j=wa; -function Gj(a){if(!nj(a))return!0;this.c.setMap(null);var c=a.pixel[0]-this.a[0],d=a.pixel[1]-this.a[1];64<=c*c+d*d&&(this.j(a),this.b(new Cj("boxend",a.coordinate)));return!1}function Ej(a){if(nj(a)&&rc(a.b)&&this.u(a)){this.a=a.pixel;this.c.setMap(a.map);var c=this.c,d=this.a;c.f=this.a;c.g=d;Bj(c);Aj(c);this.b(new Cj("boxstart",a.coordinate));return!0}return!1};function Hj(a){a=a?a:{};var c=a.condition?a.condition:lj;this.i=void 0!==a.duration?a.duration:200;Dj.call(this,{condition:c,className:a.className||"ol-dragzoom"})}x(Hj,Dj);Hj.prototype.j=function(){var a=this.G,c=a.ga(),d=a.hb(),e=this.O().F(),d=c.constrainResolution(c.rd(e,d)),f=c.$(),g=c.za();a.wa(kf({resolution:f,duration:this.i,easing:df}));a.wa(hf({source:g,duration:this.i,easing:df}));c.Ea(Rd(e));c.Gb(d)};function Ij(a){cj.call(this,{handleEvent:Jj});a=a||{};this.a=void 0!==a.condition?a.condition:Zd(kj,mj);this.c=void 0!==a.duration?a.duration:100;this.f=void 0!==a.pixelDelta?a.pixelDelta:128}x(Ij,cj); -function Jj(a){var c=!1;if("key"==a.type){var d=a.b.c;if(this.a(a)&&(40==d||37==d||39==d||38==d)){var e=a.map,c=e.ga(),f=c.$()*this.f,g=0,h=0;40==d?h=-f:37==d?g=-f:39==d?g=f:h=f;d=[g,h];ld(d,c.ua());f=this.c;if(g=c.za())f&&0<f&&e.wa(hf({source:g,duration:f,easing:ff})),e=c.qc([g[0]+d[0],g[1]+d[1]]),c.Ea(e);a.preventDefault();c=!0}}return!c};function Kj(a){cj.call(this,{handleEvent:Lj});a=a?a:{};this.c=a.condition?a.condition:mj;this.a=a.delta?a.delta:1;this.f=void 0!==a.duration?a.duration:100}x(Kj,cj);function Lj(a){var c=!1;if("key"==a.type){var d=a.b.s;if(this.c(a)&&(43==d||45==d)){c=a.map;d=43==d?this.a:-this.a;c.render();var e=c.ga();ej(c,e,d,void 0,this.f);a.preventDefault();c=!0}}return!c};function Mj(a){cj.call(this,{handleEvent:Nj});a=a||{};this.a=0;this.u=void 0!==a.duration?a.duration:250;this.H=void 0!==a.useAnchor?a.useAnchor:!0;this.f=null;this.i=this.c=void 0}x(Mj,cj);function Nj(a){var c=!1;if("mousewheel"==a.type){var c=a.map,d=a.b;this.H&&(this.f=a.coordinate);this.a+=d.H;void 0===this.c&&(this.c=Date.now());d=Math.max(80-(Date.now()-this.c),0);ba.clearTimeout(this.i);this.i=ba.setTimeout(sa(this.j,this,c),d);a.preventDefault();c=!0}return!c} -Mj.prototype.j=function(a){var c=Pa(this.a,-1,1),d=a.ga();a.render();ej(a,d,-c,this.f,this.u);this.a=0;this.f=null;this.i=this.c=void 0};function Oj(a){oj.call(this,{handleDownEvent:Pj,handleDragEvent:Qj,handleUpEvent:Rj});a=a||{};this.c=null;this.i=void 0;this.a=!1;this.j=0;this.D=void 0!==a.threshold?a.threshold:.3;this.u=void 0!==a.duration?a.duration:250}x(Oj,oj); -function Qj(a){var c=0,d=this.f[0],e=this.f[1],d=Math.atan2(e.clientY-d.clientY,e.clientX-d.clientX);void 0!==this.i&&(c=d-this.i,this.j+=c,!this.a&&Math.abs(this.j)>this.D&&(this.a=!0));this.i=d;a=a.map;d=$f(a.a);e=qj(this.f);e[0]-=d.x;e[1]-=d.y;this.c=a.ra(e);this.a&&(d=a.ga(),e=d.ua(),a.render(),dj(a,d,e+c,this.c))}function Rj(a){if(2>this.f.length){a=a.map;var c=a.ga();cf(c,-1);if(this.a){var d=c.ua(),e=this.c,f=this.u,d=c.constrainRotation(d,0);dj(a,c,d,e,f)}return!1}return!0} -function Pj(a){return 2<=this.f.length?(a=a.map,this.c=null,this.i=void 0,this.a=!1,this.j=0,this.H||cf(a.ga(),1),a.render(),!0):!1}Oj.prototype.mb=Wd;function Sj(a){oj.call(this,{handleDownEvent:Tj,handleDragEvent:Uj,handleUpEvent:Vj});a=a?a:{};this.c=null;this.j=void 0!==a.duration?a.duration:400;this.a=void 0;this.i=1}x(Sj,oj);function Uj(a){var c=1,d=this.f[0],e=this.f[1],f=d.clientX-e.clientX,d=d.clientY-e.clientY,f=Math.sqrt(f*f+d*d);void 0!==this.a&&(c=this.a/f);this.a=f;1!=c&&(this.i=c);a=a.map;var f=a.ga(),d=f.$(),e=$f(a.a),g=qj(this.f);g[0]-=e.x;g[1]-=e.y;this.c=a.ra(g);a.render();fj(a,f,d*c,this.c)} -function Vj(a){if(2>this.f.length){a=a.map;var c=a.ga();cf(c,-1);var d=c.$(),e=this.c,f=this.j,d=c.constrainResolution(d,0,this.i-1);fj(a,c,d,e,f);return!1}return!0}function Tj(a){return 2<=this.f.length?(a=a.map,this.c=null,this.a=void 0,this.i=1,this.H||cf(a.ga(),1),a.render(),!0):!1}Sj.prototype.mb=Wd;function Wj(a){a=a?a:{};var c=new F,d=new aj;(void 0!==a.altShiftDragRotate?a.altShiftDragRotate:1)&&c.push(new vj);(void 0!==a.doubleClickZoom?a.doubleClickZoom:1)&&c.push(new gj({delta:a.zoomDelta,duration:a.zoomDuration}));(void 0!==a.dragPan?a.dragPan:1)&&c.push(new rj({kinetic:d}));(void 0!==a.pinchRotate?a.pinchRotate:1)&&c.push(new Oj);(void 0!==a.pinchZoom?a.pinchZoom:1)&&c.push(new Sj({duration:a.zoomDuration}));if(void 0!==a.keyboard?a.keyboard:1)c.push(new Ij),c.push(new Kj({delta:a.zoomDelta, -duration:a.zoomDuration}));(void 0!==a.mouseWheelZoom?a.mouseWheelZoom:1)&&c.push(new Mj({duration:a.zoomDuration}));(void 0!==a.shiftDragZoom?a.shiftDragZoom:1)&&c.push(new Hj({duration:a.zoomDuration}));return c};function K(a){var c=a||{};a=Kb(c);delete a.layers;c=c.layers;si.call(this,a);this.c=[];this.a={};y(this,$c("layers"),this.lh,!1,this);c?fa(c)&&(c=new F(c.slice())):c=new F;this.rf(c)}x(K,si);k=K.prototype;k.yc=function(){this.Xa()&&this.v()}; -k.lh=function(){this.c.forEach(Nc);this.c.length=0;var a=this.Ab();this.c.push(y(a,"add",this.kh,!1,this),y(a,"remove",this.mh,!1,this));Bb(this.a,function(a){a.forEach(Nc)});Hb(this.a);var a=a.a,c,d,e;c=0;for(d=a.length;c<d;c++)e=a[c],this.a[na(e).toString()]=[y(e,"propertychange",this.yc,!1,this),y(e,"change",this.yc,!1,this)];this.v()};k.kh=function(a){a=a.element;var c=na(a).toString();this.a[c]=[y(a,"propertychange",this.yc,!1,this),y(a,"change",this.yc,!1,this)];this.v()}; -k.mh=function(a){a=na(a.element).toString();this.a[a].forEach(Nc);delete this.a[a];this.v()};k.Ab=function(){return this.get("layers")};k.rf=function(a){this.C("layers",a)}; -k.qd=function(a){var c=void 0!==a?a:[],d=c.length;this.Ab().forEach(function(a){a.qd(c)});a=ti(this);var e,f;for(e=c.length;d<e;d++)f=c[d],f.opacity*=a.opacity,f.visible=f.visible&&a.visible,f.maxResolution=Math.min(f.maxResolution,a.maxResolution),f.minResolution=Math.max(f.minResolution,a.minResolution),void 0!==a.extent&&(f.extent=void 0!==f.extent?Td(f.extent,a.extent):a.extent);return c};k.sd=function(){return"ready"};function Xj(a){de.call(this,{code:a,units:"m",extent:Yj,global:!0,worldExtent:Zj})}x(Xj,de);Xj.prototype.getPointResolution=function(a,c){return a/Qa(c[1]/6378137)};var ak=6378137*Math.PI,Yj=[-ak,-ak,ak,ak],Zj=[-180,-85,180,85],bk="EPSG:3857 EPSG:102100 EPSG:102113 EPSG:900913 urn:ogc:def:crs:EPSG:6.18:3:3857 urn:ogc:def:crs:EPSG::3857 http://www.opengis.net/gml/srs/epsg.xml#3857".split(" ").map(function(a){return new Xj(a)}); -function ck(a,c,d){var e=a.length;d=1<d?d:2;void 0===c&&(2<d?c=a.slice():c=Array(e));for(var f=0;f<e;f+=d)c[f]=6378137*Math.PI*a[f]/180,c[f+1]=6378137*Math.log(Math.tan(Math.PI*(a[f+1]+90)/360));return c}function dk(a,c,d){var e=a.length;d=1<d?d:2;void 0===c&&(2<d?c=a.slice():c=Array(e));for(var f=0;f<e;f+=d)c[f]=180*a[f]/(6378137*Math.PI),c[f+1]=360*Math.atan(Math.exp(a[f+1]/6378137))/Math.PI-90;return c};function ek(a,c){de.call(this,{code:a,units:"degrees",extent:fk,axisOrientation:c,global:!0,worldExtent:fk})}x(ek,de);ek.prototype.getPointResolution=function(a){return a}; -var fk=[-180,-90,180,90],gk=[new ek("CRS:84"),new ek("EPSG:4326","neu"),new ek("urn:ogc:def:crs:EPSG::4326","neu"),new ek("urn:ogc:def:crs:EPSG:6.6:4326","neu"),new ek("urn:ogc:def:crs:OGC:1.3:CRS84"),new ek("urn:ogc:def:crs:OGC:2:84"),new ek("http://www.opengis.net/gml/srs/epsg.xml#4326","neu"),new ek("urn:x-ogc:def:crs:EPSG:4326","neu")];function H(a){G.call(this,a?a:{})}x(H,G);function I(a){a=a?a:{};var c=Kb(a);delete c.preload;delete c.useInterimTilesOnError;G.call(this,c);this.l(void 0!==a.preload?a.preload:0);this.s(void 0!==a.useInterimTilesOnError?a.useInterimTilesOnError:!0)}x(I,G);I.prototype.i=function(){return this.get("preload")};I.prototype.l=function(a){this.C("preload",a)};I.prototype.j=function(){return this.get("useInterimTilesOnError")};I.prototype.s=function(a){this.C("useInterimTilesOnError",a)};var hk=[0,0,0,1],ik=[],jk=[0,0,0,1];function kk(a){a=a||{};this.b=void 0!==a.color?a.color:null;this.a=void 0}kk.prototype.g=function(){return this.b};kk.prototype.c=function(a){this.b=a;this.a=void 0};kk.prototype.Ma=function(){void 0===this.a&&(this.a="f"+(this.b?yf(this.b):"-"));return this.a};function lk(){this.a=-1};function mk(){this.a=-1;this.a=64;this.b=Array(4);this.f=Array(this.a);this.c=this.g=0;this.reset()}x(mk,lk);mk.prototype.reset=function(){this.b[0]=1732584193;this.b[1]=4023233417;this.b[2]=2562383102;this.b[3]=271733878;this.c=this.g=0}; -function nk(a,c,d){d||(d=0);var e=Array(16);if(ha(c))for(var f=0;16>f;++f)e[f]=c.charCodeAt(d++)|c.charCodeAt(d++)<<8|c.charCodeAt(d++)<<16|c.charCodeAt(d++)<<24;else for(f=0;16>f;++f)e[f]=c[d++]|c[d++]<<8|c[d++]<<16|c[d++]<<24;c=a.b[0];d=a.b[1];var f=a.b[2],g=a.b[3],h=0,h=c+(g^d&(f^g))+e[0]+3614090360&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[1]+3905402710&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+(d^g&(c^d))+e[2]+606105819&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^ -c))+e[3]+3250441966&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(g^d&(f^g))+e[4]+4118548399&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[5]+1200080426&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+(d^g&(c^d))+e[6]+2821735955&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^c))+e[7]+4249261313&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(g^d&(f^g))+e[8]+1770035416&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[9]+2336552879&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+ -(d^g&(c^d))+e[10]+4294925233&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^c))+e[11]+2304563134&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(g^d&(f^g))+e[12]+1804603682&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[13]+4254626195&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+(d^g&(c^d))+e[14]+2792965006&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^c))+e[15]+1236535329&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(f^g&(d^f))+e[1]+4129170786&4294967295;c=d+(h<<5&4294967295| -h>>>27);h=g+(d^f&(c^d))+e[6]+3225465664&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[11]+643717713&4294967295;f=g+(h<<14&4294967295|h>>>18);h=d+(g^c&(f^g))+e[0]+3921069994&4294967295;d=f+(h<<20&4294967295|h>>>12);h=c+(f^g&(d^f))+e[5]+3593408605&4294967295;c=d+(h<<5&4294967295|h>>>27);h=g+(d^f&(c^d))+e[10]+38016083&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[15]+3634488961&4294967295;f=g+(h<<14&4294967295|h>>>18);h=d+(g^c&(f^g))+e[4]+3889429448&4294967295;d=f+(h<<20&4294967295| -h>>>12);h=c+(f^g&(d^f))+e[9]+568446438&4294967295;c=d+(h<<5&4294967295|h>>>27);h=g+(d^f&(c^d))+e[14]+3275163606&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[3]+4107603335&4294967295;f=g+(h<<14&4294967295|h>>>18);h=d+(g^c&(f^g))+e[8]+1163531501&4294967295;d=f+(h<<20&4294967295|h>>>12);h=c+(f^g&(d^f))+e[13]+2850285829&4294967295;c=d+(h<<5&4294967295|h>>>27);h=g+(d^f&(c^d))+e[2]+4243563512&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[7]+1735328473&4294967295;f=g+(h<<14&4294967295| -h>>>18);h=d+(g^c&(f^g))+e[12]+2368359562&4294967295;d=f+(h<<20&4294967295|h>>>12);h=c+(d^f^g)+e[5]+4294588738&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[8]+2272392833&4294967295;g=c+(h<<11&4294967295|h>>>21);h=f+(g^c^d)+e[11]+1839030562&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[14]+4259657740&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(d^f^g)+e[1]+2763975236&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[4]+1272893353&4294967295;g=c+(h<<11&4294967295|h>>>21);h=f+(g^ -c^d)+e[7]+4139469664&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[10]+3200236656&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(d^f^g)+e[13]+681279174&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[0]+3936430074&4294967295;g=c+(h<<11&4294967295|h>>>21);h=f+(g^c^d)+e[3]+3572445317&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[6]+76029189&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(d^f^g)+e[9]+3654602809&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[12]+3873151461&4294967295; -g=c+(h<<11&4294967295|h>>>21);h=f+(g^c^d)+e[15]+530742520&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[2]+3299628645&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(f^(d|~g))+e[0]+4096336452&4294967295;c=d+(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[7]+1126891415&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[14]+2878612391&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[5]+4237533241&4294967295;d=f+(h<<21&4294967295|h>>>11);h=c+(f^(d|~g))+e[12]+1700485571&4294967295;c=d+ -(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[3]+2399980690&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[10]+4293915773&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[1]+2240044497&4294967295;d=f+(h<<21&4294967295|h>>>11);h=c+(f^(d|~g))+e[8]+1873313359&4294967295;c=d+(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[15]+4264355552&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[6]+2734768916&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[13]+1309151649&4294967295; -d=f+(h<<21&4294967295|h>>>11);h=c+(f^(d|~g))+e[4]+4149444226&4294967295;c=d+(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[11]+3174756917&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[2]+718787259&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[9]+3951481745&4294967295;a.b[0]=a.b[0]+c&4294967295;a.b[1]=a.b[1]+(f+(h<<21&4294967295|h>>>11))&4294967295;a.b[2]=a.b[2]+f&4294967295;a.b[3]=a.b[3]+g&4294967295} -function ok(a,c){var d;ca(d)||(d=c.length);for(var e=d-a.a,f=a.f,g=a.g,h=0;h<d;){if(0==g)for(;h<=e;)nk(a,c,h),h+=a.a;if(ha(c))for(;h<d;){if(f[g++]=c.charCodeAt(h++),g==a.a){nk(a,f);g=0;break}}else for(;h<d;)if(f[g++]=c[h++],g==a.a){nk(a,f);g=0;break}}a.g=g;a.c+=d};function pk(a){a=a||{};this.b=void 0!==a.color?a.color:null;this.c=a.lineCap;this.g=void 0!==a.lineDash?a.lineDash:null;this.f=a.lineJoin;this.i=a.miterLimit;this.a=a.width;this.j=void 0}k=pk.prototype;k.nj=function(){return this.b};k.Gg=function(){return this.c};k.oj=function(){return this.g};k.Hg=function(){return this.f};k.Lg=function(){return this.i};k.pj=function(){return this.a};k.qj=function(a){this.b=a;this.j=void 0};k.gk=function(a){this.c=a;this.j=void 0}; -k.rj=function(a){this.g=a;this.j=void 0};k.hk=function(a){this.f=a;this.j=void 0};k.ik=function(a){this.i=a;this.j=void 0};k.nk=function(a){this.a=a;this.j=void 0}; -k.Ma=function(){if(void 0===this.j){var a="s"+(this.b?yf(this.b):"-")+","+(void 0!==this.c?this.c.toString():"-")+","+(this.g?this.g.toString():"-")+","+(void 0!==this.f?this.f:"-")+","+(void 0!==this.i?this.i.toString():"-")+","+(void 0!==this.a?this.a.toString():"-"),c=new mk;ok(c,a);var d=Array((56>c.g?c.a:2*c.a)-c.g);d[0]=128;for(a=1;a<d.length-8;++a)d[a]=0;for(var e=8*c.c,a=d.length-8;a<d.length;++a)d[a]=e&255,e/=256;ok(c,d);d=Array(16);for(a=e=0;4>a;++a)for(var f=0;32>f;f+=8)d[e++]=c.b[a]>>> -f&255;if(8192>=d.length)c=String.fromCharCode.apply(null,d);else for(c="",a=0;a<d.length;a+=8192)c+=String.fromCharCode.apply(null,ib(d,a,a+8192));this.j=c}return this.j};function qk(a){a=a||{};this.i=this.b=this.f=null;this.c=void 0!==a.fill?a.fill:null;this.a=void 0!==a.stroke?a.stroke:null;this.g=a.radius;this.u=[0,0];this.l=this.B=this.A=null;var c=a.atlasManager,d,e=null,f,g=0;this.a&&(f=yf(this.a.b),g=this.a.a,void 0===g&&(g=1),e=this.a.g,vh||(e=null));var h=2*(this.g+g)+1;f={strokeStyle:f,lc:g,size:h,lineDash:e};void 0===c?(this.b=document.createElement("CANVAS"),this.b.height=h,this.b.width=h,d=h=this.b.width,c=this.b.getContext("2d"),this.df(f,c,0,0),this.c? -this.i=this.b:(c=this.i=document.createElement("CANVAS"),c.height=f.size,c.width=f.size,c=c.getContext("2d"),this.cf(f,c,0,0))):(h=Math.round(h),(e=!this.c)&&(d=sa(this.cf,this,f)),g=this.Ma(),f=c.add(g,h,h,sa(this.df,this,f),d),this.b=f.image,this.u=[f.offsetX,f.offsetY],d=f.image.width,this.i=e?f.Ch:this.b);this.A=[h/2,h/2];this.B=[h,h];this.l=[d,d];Mi.call(this,{opacity:1,rotateWithView:!1,rotation:0,scale:1,snapToPixel:void 0!==a.snapToPixel?a.snapToPixel:!0})}x(qk,Mi);k=qk.prototype;k.eb=function(){return this.A}; -k.ej=function(){return this.c};k.Md=function(){return this.i};k.jb=function(){return this.b};k.gc=function(){return 2};k.tc=function(){return this.l};k.ta=function(){return this.u};k.fj=function(){return this.g};k.Ta=function(){return this.B};k.gj=function(){return this.a};k.Cd=wa;k.load=wa;k.Yd=wa; -k.df=function(a,c,d,e){c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();c.arc(a.size/2,a.size/2,this.g,0,2*Math.PI,!0);this.c&&(c.fillStyle=yf(this.c.b),c.fill());this.a&&(c.strokeStyle=a.strokeStyle,c.lineWidth=a.lc,a.lineDash&&c.setLineDash(a.lineDash),c.stroke());c.closePath()}; -k.cf=function(a,c,d,e){c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();c.arc(a.size/2,a.size/2,this.g,0,2*Math.PI,!0);c.fillStyle=yf(hk);c.fill();this.a&&(c.strokeStyle=a.strokeStyle,c.lineWidth=a.lc,a.lineDash&&c.setLineDash(a.lineDash),c.stroke());c.closePath()};k.Ma=function(){var a=this.a?this.a.Ma():"-",c=this.c?this.c.Ma():"-";this.f&&a==this.f[1]&&c==this.f[2]&&this.g==this.f[3]||(this.f=["c"+a+c+(void 0!==this.g?this.g.toString():"-"),a,c,this.g]);return this.f[0]};function rk(a){a=a||{};this.i=null;this.c=sk;void 0!==a.geometry&&this.gf(a.geometry);this.f=void 0!==a.fill?a.fill:null;this.a=void 0!==a.image?a.image:null;this.g=void 0!==a.stroke?a.stroke:null;this.j=void 0!==a.text?a.text:null;this.b=a.zIndex}k=rk.prototype;k.O=function(){return this.i};k.Ag=function(){return this.c};k.sj=function(){return this.f};k.tj=function(){return this.a};k.uj=function(){return this.g};k.oa=function(){return this.j};k.vj=function(){return this.b}; -k.gf=function(a){la(a)?this.c=a:ha(a)?this.c=function(c){return c.get(a)}:a?void 0!==a&&(this.c=function(){return a}):this.c=sk;this.i=a};k.wj=function(a){this.b=a};function tk(a){if(!la(a)){var c;c=fa(a)?a:[a];a=function(){return c}}return a}var uk=null;function vk(){if(!uk){var a=new kk({color:"rgba(255,255,255,0.4)"}),c=new pk({color:"#3399CC",width:1.25});uk=[new rk({image:new qk({fill:a,stroke:c,radius:5}),fill:a,stroke:c})]}return uk} -function wk(){var a={},c=[255,255,255,1],d=[0,153,255,1];a.Polygon=[new rk({fill:new kk({color:[255,255,255,.5]})})];a.MultiPolygon=a.Polygon;a.LineString=[new rk({stroke:new pk({color:c,width:5})}),new rk({stroke:new pk({color:d,width:3})})];a.MultiLineString=a.LineString;a.Circle=a.Polygon.concat(a.LineString);a.Point=[new rk({image:new qk({radius:6,fill:new kk({color:d}),stroke:new pk({color:c,width:1.5})}),zIndex:Infinity})];a.MultiPoint=a.Point;a.GeometryCollection=a.Polygon.concat(a.LineString, -a.Point);return a}function sk(a){return a.O()}v("ol.style.defaultStyleFunction",vk,void 0);function J(a){a=a?a:{};var c=Kb(a);delete c.style;delete c.renderBuffer;delete c.updateWhileAnimating;delete c.updateWhileInteracting;G.call(this,c);this.l=void 0!==a.renderBuffer?a.renderBuffer:100;this.j=null;this.i=void 0;this.s(a.style);this.G=void 0!==a.updateWhileAnimating?a.updateWhileAnimating:!1;this.B=void 0!==a.updateWhileInteracting?a.updateWhileInteracting:!1}x(J,G);J.prototype.u=function(){return this.j};J.prototype.H=function(){return this.i}; -J.prototype.s=function(a){this.j=void 0!==a?a:vk;this.i=null===a?void 0:tk(this.j);this.v()};function xk(a,c,d,e,f){this.bb={};this.g=a;this.D=c;this.j=d;this.B=e;this.Ib=f;this.f=this.b=this.a=this.ja=this.ea=this.aa=null;this.na=this.Ua=this.u=this.I=this.ma=this.ia=0;this.qa=!1;this.i=this.Ga=0;this.Va=!1;this.J=0;this.c="";this.l=this.G=this.mc=this.cb=0;this.Y=this.s=this.A=null;this.H=[];this.ob=qd()} -function yk(a,c,d){if(a.f){c=ve(c,0,d,2,a.B,a.H);d=a.g;var e=a.ob,f=d.globalAlpha;1!=a.u&&(d.globalAlpha=f*a.u);var g=a.Ga;a.qa&&(g+=a.Ib);var h,l;h=0;for(l=c.length;h<l;h+=2){var m=c[h]-a.ia,n=c[h+1]-a.ma;a.Va&&(m=m+.5|0,n=n+.5|0);if(0!==g||1!=a.i){var p=m+a.ia,q=n+a.ma;zi(e,p,q,a.i,a.i,g,-p,-q);d.setTransform(e[0],e[1],e[4],e[5],e[12],e[13])}d.drawImage(a.f,a.Ua,a.na,a.J,a.I,m,n,a.J,a.I)}0===g&&1==a.i||d.setTransform(1,0,0,1,0,0);1!=a.u&&(d.globalAlpha=f)}} -function zk(a,c,d,e){var f=0;if(a.Y&&""!==a.c){a.A&&Ak(a,a.A);a.s&&Bk(a,a.s);var g=a.Y,h=a.g,l=a.ja;l?(l.font!=g.font&&(l.font=h.font=g.font),l.textAlign!=g.textAlign&&(l.textAlign=h.textAlign=g.textAlign),l.textBaseline!=g.textBaseline&&(l.textBaseline=h.textBaseline=g.textBaseline)):(h.font=g.font,h.textAlign=g.textAlign,h.textBaseline=g.textBaseline,a.ja={font:g.font,textAlign:g.textAlign,textBaseline:g.textBaseline});c=ve(c,f,d,e,a.B,a.H);for(g=a.g;f<d;f+=e){h=c[f]+a.cb;l=c[f+1]+a.mc;if(0!==a.G|| -1!=a.l){var m=zi(a.ob,h,l,a.l,a.l,a.G,-h,-l);g.setTransform(m[0],m[1],m[4],m[5],m[12],m[13])}a.s&&g.strokeText(a.c,h,l);a.A&&g.fillText(a.c,h,l)}0===a.G&&1==a.l||g.setTransform(1,0,0,1,0,0)}}function Ck(a,c,d,e,f,g){var h=a.g;a=ve(c,d,e,f,a.B,a.H);h.moveTo(a[0],a[1]);for(c=2;c<a.length;c+=2)h.lineTo(a[c],a[c+1]);g&&h.lineTo(a[0],a[1]);return e}function Dk(a,c,d,e,f){var g=a.g,h,l;h=0;for(l=e.length;h<l;++h)d=Ck(a,c,d,e[h],f,!0),g.closePath();return d}k=xk.prototype; -k.fd=function(a){if(Ud(this.j,a.F())){if(this.a||this.b){this.a&&Ak(this,this.a);this.b&&Bk(this,this.b);var c;c=this.B;var d=this.H,e=a.ba();if(e){var f=a.la();c=ve(e,0,e.length,f,c,d)}else c=null;d=c[2]-c[0];e=c[3]-c[1];d=Math.sqrt(d*d+e*e);e=this.g;e.beginPath();e.arc(c[0],c[1],d,0,2*Math.PI);this.a&&e.fill();this.b&&e.stroke()}""!==this.c&&zk(this,a.Gc(),2,2)}};k.cg=function(a,c){var d=a.a,e,f;e=0;for(f=d.length;e<f;++e){var g=d[e];Ek[g.N()].call(this,g,c)}}; -k.ld=function(a){var c=a.ba();a=a.la();this.f&&yk(this,c,c.length);""!==this.c&&zk(this,c,c.length,a)};k.jd=function(a){var c=a.ba();a=a.la();this.f&&yk(this,c,c.length);""!==this.c&&zk(this,c,c.length,a)};k.gd=function(a){if(Ud(this.j,a.F())){if(this.b){Bk(this,this.b);var c=this.g,d=a.ba();c.beginPath();Ck(this,d,0,d.length,a.la(),!1);c.stroke()}""!==this.c&&(a=Fk(a),zk(this,a,2,2))}}; -k.hd=function(a){var c=a.F();if(Ud(this.j,c)){if(this.b){Bk(this,this.b);var c=this.g,d=a.ba(),e=0,f=a.Na(),g=a.la();c.beginPath();var h,l;h=0;for(l=f.length;h<l;++h)e=Ck(this,d,e,f[h],g,!1);c.stroke()}""!==this.c&&(a=Gk(a),zk(this,a,a.length,2))}};k.md=function(a){if(Ud(this.j,a.F())){if(this.b||this.a){this.a&&Ak(this,this.a);this.b&&Bk(this,this.b);var c=this.g;c.beginPath();Dk(this,a.Za(),0,a.Na(),a.la());this.a&&c.fill();this.b&&c.stroke()}""!==this.c&&(a=af(a),zk(this,a,2,2))}}; -k.kd=function(a){if(Ud(this.j,a.F())){if(this.b||this.a){this.a&&Ak(this,this.a);this.b&&Bk(this,this.b);var c=this.g,d=Hk(a),e=0,f=a.f,g=a.la(),h,l;h=0;for(l=f.length;h<l;++h){var m=f[h];c.beginPath();e=Dk(this,d,e,m,g);this.a&&c.fill();this.b&&c.stroke()}}""!==this.c&&(a=Ik(a),zk(this,a,a.length,2))}};function Jk(a){var c=Object.keys(a.bb).map(Number);jb(c);var d,e,f,g,h;d=0;for(e=c.length;d<e;++d)for(f=a.bb[c[d].toString()],g=0,h=f.length;g<h;++g)f[g](a)} -function Ak(a,c){var d=a.g,e=a.aa;e?e.fillStyle!=c.fillStyle&&(e.fillStyle=d.fillStyle=c.fillStyle):(d.fillStyle=c.fillStyle,a.aa={fillStyle:c.fillStyle})} -function Bk(a,c){var d=a.g,e=a.ea;e?(e.lineCap!=c.lineCap&&(e.lineCap=d.lineCap=c.lineCap),vh&&!nb(e.lineDash,c.lineDash)&&d.setLineDash(e.lineDash=c.lineDash),e.lineJoin!=c.lineJoin&&(e.lineJoin=d.lineJoin=c.lineJoin),e.lineWidth!=c.lineWidth&&(e.lineWidth=d.lineWidth=c.lineWidth),e.miterLimit!=c.miterLimit&&(e.miterLimit=d.miterLimit=c.miterLimit),e.strokeStyle!=c.strokeStyle&&(e.strokeStyle=d.strokeStyle=c.strokeStyle)):(d.lineCap=c.lineCap,vh&&d.setLineDash(c.lineDash),d.lineJoin=c.lineJoin,d.lineWidth= -c.lineWidth,d.miterLimit=c.miterLimit,d.strokeStyle=c.strokeStyle,a.ea={lineCap:c.lineCap,lineDash:c.lineDash,lineJoin:c.lineJoin,lineWidth:c.lineWidth,miterLimit:c.miterLimit,strokeStyle:c.strokeStyle})} -k.lb=function(a,c){if(a){var d=a.b;this.a={fillStyle:yf(d?d:hk)}}else this.a=null;if(c){var d=c.b,e=c.c,f=c.g,g=c.f,h=c.a,l=c.i;this.b={lineCap:void 0!==e?e:"round",lineDash:f?f:ik,lineJoin:void 0!==g?g:"round",lineWidth:this.D*(void 0!==h?h:1),miterLimit:void 0!==l?l:10,strokeStyle:yf(d?d:jk)}}else this.b=null}; -k.Td=function(a){if(a){var c=a.eb(),d=a.jb(1),e=a.ta(),f=a.Ta();this.ia=c[0];this.ma=c[1];this.I=f[1];this.f=d;this.u=a.H;this.Ua=e[0];this.na=e[1];this.qa=a.D;this.Ga=a.s;this.i=a.j;this.Va=a.G;this.J=f[0]}else this.f=null}; -k.ab=function(a){if(a){var c=a.b;c?(c=c.b,this.A={fillStyle:yf(c?c:hk)}):this.A=null;var d=a.j;if(d){var c=d.b,e=d.c,f=d.g,g=d.f,h=d.a,d=d.i;this.s={lineCap:void 0!==e?e:"round",lineDash:f?f:ik,lineJoin:void 0!==g?g:"round",lineWidth:void 0!==h?h:1,miterLimit:void 0!==d?d:10,strokeStyle:yf(c?c:jk)}}else this.s=null;var c=a.g,e=a.c,f=a.f,g=a.i,h=a.a,d=a.oa(),l=a.A;a=a.l;this.Y={font:void 0!==c?c:"10px sans-serif",textAlign:void 0!==l?l:"center",textBaseline:void 0!==a?a:"middle"};this.c=void 0!==d? -d:"";this.cb=void 0!==e?this.D*e:0;this.mc=void 0!==f?this.D*f:0;this.G=void 0!==g?g:0;this.l=this.D*(void 0!==h?h:1)}else this.c=""};var Ek={Point:xk.prototype.ld,LineString:xk.prototype.gd,Polygon:xk.prototype.md,MultiPoint:xk.prototype.jd,MultiLineString:xk.prototype.hd,MultiPolygon:xk.prototype.kd,GeometryCollection:xk.prototype.cg,Circle:xk.prototype.fd};function Kk(a){Bi.call(this,a);this.J=qd()}x(Kk,Bi); -Kk.prototype.H=function(a,c,d){Lk(this,"precompose",d,a,void 0);var e=this.Jc();if(e){var f=c.extent,g=void 0!==f;if(g){var h=a.pixelRatio,l=Md(f),m=[f[2],f[3]],n=[f[2],f[1]],f=[f[0],f[1]];Ai(a.coordinateToPixelMatrix,l,l);Ai(a.coordinateToPixelMatrix,m,m);Ai(a.coordinateToPixelMatrix,n,n);Ai(a.coordinateToPixelMatrix,f,f);d.save();d.beginPath();d.moveTo(l[0]*h,l[1]*h);d.lineTo(m[0]*h,m[1]*h);d.lineTo(n[0]*h,n[1]*h);d.lineTo(f[0]*h,f[1]*h);d.clip()}h=this.re();l=d.globalAlpha;d.globalAlpha=c.opacity; -0===a.viewState.rotation?d.drawImage(e,0,0,+e.width,+e.height,Math.round(h[12]),Math.round(h[13]),Math.round(e.width*h[0]),Math.round(e.height*h[5])):(d.setTransform(h[0],h[1],h[4],h[5],h[12],h[13]),d.drawImage(e,0,0),d.setTransform(1,0,0,1,0,0));d.globalAlpha=l;g&&d.restore()}Lk(this,"postcompose",d,a,void 0)};function Lk(a,c,d,e,f){var g=a.a;Uc(g,c)&&(a=void 0!==f?f:Mk(a,e,0),a=new xk(d,e.pixelRatio,e.extent,a,e.viewState.rotation),g.b(new vi(c,g,a,e,d,null)),Jk(a))} -function Mk(a,c,d){var e=c.viewState,f=c.pixelRatio;return zi(a.J,f*c.size[0]/2,f*c.size[1]/2,f/e.resolution,-f/e.resolution,-e.rotation,-e.center[0]+d,-e.center[1])}function Nk(a,c){var d=[0,0];Ai(c,a,d);return d} -var Ok=function(){var a=null,c=null;return function(d){if(!a){a=th(1,1);c=a.createImageData(1,1);var e=c.data;e[0]=42;e[1]=84;e[2]=126;e[3]=255}var e=a.canvas,f=d[0]<=e.width&&d[1]<=e.height;f||(e.width=d[0],e.height=d[1],e=d[0]-1,d=d[1]-1,a.putImageData(c,e,d),d=a.getImageData(e,d,1,1),f=nb(c.data,d.data));return f}}();var Pk=["Polygon","LineString","Image","Text"];function Qk(a,c,d){this.na=a;this.aa=c;this.f=null;this.i=0;this.resolution=d;this.J=this.I=null;this.a=[];this.g=[];this.ja=qd();this.b=[];this.ea=[];this.Ua=qd()}x(Qk,ui); -function Rk(a,c,d,e,f,g){var h=a.g.length,l=a.od(),m=[c[d],c[d+1]],n=[NaN,NaN],p=!0,q,r,t;for(q=d+f;q<e;q+=f)n[0]=c[q],n[1]=c[q+1],t=Fd(l,n),t!==r?(p&&(a.g[h++]=m[0],a.g[h++]=m[1]),a.g[h++]=n[0],a.g[h++]=n[1],p=!1):1===t?(a.g[h++]=n[0],a.g[h++]=n[1],p=!1):p=!0,m[0]=n[0],m[1]=n[1],r=t;q===d+f&&(a.g[h++]=m[0],a.g[h++]=m[1]);g&&(a.g[h++]=c[d],a.g[h++]=c[d+1]);return h}function Sk(a,c){a.I=[0,c,0];a.a.push(a.I);a.J=[0,c,0];a.b.push(a.J)} -function Tk(a,c,d,e,f,g,h,l,m){var n;n=a.ja;if(e[0]==n[0]&&e[1]==n[1]&&e[4]==n[4]&&e[5]==n[5]&&e[12]==n[12]&&e[13]==n[13])n=a.ea;else{n=ve(a.g,0,a.g.length,2,e,a.ea);var p=a.ja;p[0]=e[0];p[1]=e[1];p[2]=e[2];p[3]=e[3];p[4]=e[4];p[5]=e[5];p[6]=e[6];p[7]=e[7];p[8]=e[8];p[9]=e[9];p[10]=e[10];p[11]=e[11];p[12]=e[12];p[13]=e[13];p[14]=e[14];p[15]=e[15]}e=!Gb(g);var p=0,q=h.length,r=0,t;a=a.Ua;for(var B,V,w,E;p<q;){var u=h[p],Ca,Ea,ia,O;switch(u[0]){case 0:r=u[1];e&&g[na(r).toString()]||!r.O()?p=u[2]:void 0=== -m||Ud(m,r.O().F())?++p:p=u[2];break;case 1:c.beginPath();++p;break;case 2:r=u[1];t=n[r];u=n[r+1];O=n[r+2]-t;r=n[r+3]-u;c.arc(t,u,Math.sqrt(O*O+r*r),0,2*Math.PI,!0);++p;break;case 3:c.closePath();++p;break;case 4:r=u[1];t=u[2];Ca=u[3];ia=u[4]*d;var Aa=u[5]*d,va=u[6];Ea=u[7];var fb=u[8],Ua=u[9];w=u[11];E=u[12];var $a=u[13],gb=u[14];for(u[10]&&(w+=f);r<t;r+=2){u=n[r]-ia;O=n[r+1]-Aa;$a&&(u=u+.5|0,O=O+.5|0);if(1!=E||0!==w){var ja=u+ia,za=O+Aa;zi(a,ja,za,E,E,w,-ja,-za);c.setTransform(a[0],a[1],a[4],a[5], -a[12],a[13])}ja=c.globalAlpha;1!=Ea&&(c.globalAlpha=ja*Ea);c.drawImage(Ca,fb,Ua,gb,va,u,O,gb*d,va*d);1!=Ea&&(c.globalAlpha=ja);1==E&&0===w||c.setTransform(1,0,0,1,0,0)}++p;break;case 5:r=u[1];t=u[2];ia=u[3];Aa=u[4]*d;va=u[5]*d;w=u[6];E=u[7]*d;Ca=u[8];for(Ea=u[9];r<t;r+=2){u=n[r]+Aa;O=n[r+1]+va;if(1!=E||0!==w)zi(a,u,O,E,E,w,-u,-O),c.setTransform(a[0],a[1],a[4],a[5],a[12],a[13]);Ea&&c.strokeText(ia,u,O);Ca&&c.fillText(ia,u,O);1==E&&0===w||c.setTransform(1,0,0,1,0,0)}++p;break;case 6:if(void 0!==l&& -(r=u[1],r=l(r)))return r;++p;break;case 7:c.fill();++p;break;case 8:r=u[1];t=u[2];u=n[r];O=n[r+1];w=u+.5|0;E=O+.5|0;if(w!==B||E!==V)c.moveTo(u,O),B=w,V=E;for(r+=2;r<t;r+=2)if(u=n[r],O=n[r+1],w=u+.5|0,E=O+.5|0,w!==B||E!==V)c.lineTo(u,O),B=w,V=E;++p;break;case 9:c.fillStyle=u[1];++p;break;case 10:B=void 0!==u[7]?u[7]:!0;V=u[2];c.strokeStyle=u[1];c.lineWidth=B?V*d:V;c.lineCap=u[3];c.lineJoin=u[4];c.miterLimit=u[5];vh&&c.setLineDash(u[6]);V=B=NaN;++p;break;case 11:c.font=u[1];c.textAlign=u[2];c.textBaseline= -u[3];++p;break;case 12:c.stroke();++p;break;default:++p}}}function Uk(a){var c=a.b;c.reverse();var d,e=c.length,f,g,h=-1;for(d=0;d<e;++d)if(f=c[d],g=f[0],6==g)h=d;else if(0==g){f[2]=d;f=a.b;for(g=d;h<g;){var l=f[h];f[h]=f[g];f[g]=l;++h;--g}h=-1}}function Vk(a,c){a.I[2]=a.a.length;a.I=null;a.J[2]=a.b.length;a.J=null;var d=[6,c];a.a.push(d);a.b.push(d)}Qk.prototype.Ic=wa;Qk.prototype.od=function(){return this.aa}; -function Wk(a,c,d){Qk.call(this,a,c,d);this.l=this.Y=null;this.ma=this.ia=this.B=this.G=this.D=this.H=this.u=this.s=this.A=this.j=this.c=void 0}x(Wk,Qk);Wk.prototype.ld=function(a,c){if(this.l){Sk(this,c);var d=a.ba(),e=a.la(),f=this.g.length,d=Rk(this,d,0,d.length,e,!1);this.a.push([4,f,d,this.l,this.c,this.j,this.A,this.s,this.u,this.H,this.D,this.G,this.B,this.ia,this.ma]);this.b.push([4,f,d,this.Y,this.c,this.j,this.A,this.s,this.u,this.H,this.D,this.G,this.B,this.ia,this.ma]);Vk(this,c)}}; -Wk.prototype.jd=function(a,c){if(this.l){Sk(this,c);var d=a.ba(),e=a.la(),f=this.g.length,d=Rk(this,d,0,d.length,e,!1);this.a.push([4,f,d,this.l,this.c,this.j,this.A,this.s,this.u,this.H,this.D,this.G,this.B,this.ia,this.ma]);this.b.push([4,f,d,this.Y,this.c,this.j,this.A,this.s,this.u,this.H,this.D,this.G,this.B,this.ia,this.ma]);Vk(this,c)}};Wk.prototype.Ic=function(){Uk(this);this.j=this.c=void 0;this.l=this.Y=null;this.ma=this.ia=this.G=this.D=this.H=this.u=this.s=this.B=this.A=void 0}; -Wk.prototype.Td=function(a){var c=a.eb(),d=a.Ta(),e=a.Md(1),f=a.jb(1),g=a.ta();this.c=c[0];this.j=c[1];this.Y=e;this.l=f;this.A=d[1];this.s=a.H;this.u=g[0];this.H=g[1];this.D=a.D;this.G=a.s;this.B=a.j;this.ia=a.G;this.ma=d[0]};function Xk(a,c,d){Qk.call(this,a,c,d);this.c={Pb:void 0,Kb:void 0,Lb:null,Mb:void 0,Nb:void 0,Ob:void 0,Bd:0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}x(Xk,Qk); -function Yk(a,c,d,e,f){var g=a.g.length;c=Rk(a,c,d,e,f,!1);g=[8,g,c];a.a.push(g);a.b.push(g);return e}k=Xk.prototype;k.od=function(){this.f||(this.f=Ad(this.aa),0<this.i&&zd(this.f,this.resolution*(this.i+1)/2,this.f));return this.f}; -function Zk(a){var c=a.c,d=c.strokeStyle,e=c.lineCap,f=c.lineDash,g=c.lineJoin,h=c.lineWidth,l=c.miterLimit;c.Pb==d&&c.Kb==e&&nb(c.Lb,f)&&c.Mb==g&&c.Nb==h&&c.Ob==l||(c.Bd!=a.g.length&&(a.a.push([12]),c.Bd=a.g.length),a.a.push([10,d,h,e,g,l,f],[1]),c.Pb=d,c.Kb=e,c.Lb=f,c.Mb=g,c.Nb=h,c.Ob=l)} -k.gd=function(a,c){var d=this.c,e=d.lineWidth;void 0!==d.strokeStyle&&void 0!==e&&(Zk(this),Sk(this,c),this.b.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash],[1]),d=a.ba(),e=a.la(),Yk(this,d,0,d.length,e),this.b.push([12]),Vk(this,c))}; -k.hd=function(a,c){var d=this.c,e=d.lineWidth;if(void 0!==d.strokeStyle&&void 0!==e){Zk(this);Sk(this,c);this.b.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash],[1]);var d=a.Na(),e=a.ba(),f=a.la(),g=0,h,l;h=0;for(l=d.length;h<l;++h)g=Yk(this,e,g,d[h],f);this.b.push([12]);Vk(this,c)}};k.Ic=function(){this.c.Bd!=this.g.length&&this.a.push([12]);Uk(this);this.c=null}; -k.lb=function(a,c){var d=c.b;this.c.strokeStyle=yf(d?d:jk);d=c.c;this.c.lineCap=void 0!==d?d:"round";d=c.g;this.c.lineDash=d?d:ik;d=c.f;this.c.lineJoin=void 0!==d?d:"round";d=c.a;this.c.lineWidth=void 0!==d?d:1;d=c.i;this.c.miterLimit=void 0!==d?d:10;this.c.lineWidth>this.i&&(this.i=this.c.lineWidth,this.f=null)}; -function $k(a,c,d){Qk.call(this,a,c,d);this.c={me:void 0,Pb:void 0,Kb:void 0,Lb:null,Mb:void 0,Nb:void 0,Ob:void 0,fillStyle:void 0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}x($k,Qk); -function al(a,c,d,e,f){var g=a.c,h=[1];a.a.push(h);a.b.push(h);var l,h=0;for(l=e.length;h<l;++h){var m=e[h],n=a.g.length;d=Rk(a,c,d,m,f,!0);d=[8,n,d];n=[3];a.a.push(d,n);a.b.push(d,n);d=m}c=[7];a.b.push(c);void 0!==g.fillStyle&&a.a.push(c);void 0!==g.strokeStyle&&(g=[12],a.a.push(g),a.b.push(g));return d}k=$k.prototype; -k.fd=function(a,c){var d=this.c,e=d.strokeStyle;if(void 0!==d.fillStyle||void 0!==e){bl(this);Sk(this,c);this.b.push([9,yf(hk)]);void 0!==d.strokeStyle&&this.b.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash]);var f=a.ba(),g=a.la(),e=this.g.length;Rk(this,f,0,f.length,g,!1);f=[1];e=[2,e];this.a.push(f,e);this.b.push(f,e);e=[7];this.b.push(e);void 0!==d.fillStyle&&this.a.push(e);void 0!==d.strokeStyle&&(d=[12],this.a.push(d),this.b.push(d));Vk(this,c)}}; -k.md=function(a,c){var d=this.c,e=d.strokeStyle;if(void 0!==d.fillStyle||void 0!==e){bl(this);Sk(this,c);this.b.push([9,yf(hk)]);void 0!==d.strokeStyle&&this.b.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash]);var d=a.Na(),e=a.Za(),f=a.la();al(this,e,0,d,f);Vk(this,c)}}; -k.kd=function(a,c){var d=this.c,e=d.strokeStyle;if(void 0!==d.fillStyle||void 0!==e){bl(this);Sk(this,c);this.b.push([9,yf(hk)]);void 0!==d.strokeStyle&&this.b.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash]);var d=a.f,e=Hk(a),f=a.la(),g=0,h,l;h=0;for(l=d.length;h<l;++h)g=al(this,e,g,d[h],f);Vk(this,c)}};k.Ic=function(){Uk(this);this.c=null;var a=this.na;if(0!==a){var c=this.g,d,e;d=0;for(e=c.length;d<e;++d)c[d]=a*Math.round(c[d]/a)}}; -k.od=function(){this.f||(this.f=Ad(this.aa),0<this.i&&zd(this.f,this.resolution*(this.i+1)/2,this.f));return this.f}; -k.lb=function(a,c){var d=this.c;if(a){var e=a.b;d.fillStyle=yf(e?e:hk)}else d.fillStyle=void 0;c?(e=c.b,d.strokeStyle=yf(e?e:jk),e=c.c,d.lineCap=void 0!==e?e:"round",e=c.g,d.lineDash=e?e.slice():ik,e=c.f,d.lineJoin=void 0!==e?e:"round",e=c.a,d.lineWidth=void 0!==e?e:1,e=c.i,d.miterLimit=void 0!==e?e:10,d.lineWidth>this.i&&(this.i=d.lineWidth,this.f=null)):(d.strokeStyle=void 0,d.lineCap=void 0,d.lineDash=null,d.lineJoin=void 0,d.lineWidth=void 0,d.miterLimit=void 0)}; -function bl(a){var c=a.c,d=c.fillStyle,e=c.strokeStyle,f=c.lineCap,g=c.lineDash,h=c.lineJoin,l=c.lineWidth,m=c.miterLimit;void 0!==d&&c.me!=d&&(a.a.push([9,d]),c.me=c.fillStyle);void 0===e||c.Pb==e&&c.Kb==f&&c.Lb==g&&c.Mb==h&&c.Nb==l&&c.Ob==m||(a.a.push([10,e,l,f,h,m,g]),c.Pb=e,c.Kb=f,c.Lb=g,c.Mb=h,c.Nb=l,c.Ob=m)}function cl(a,c,d){Qk.call(this,a,c,d);this.ia=this.B=this.G=null;this.l="";this.D=this.H=this.u=this.s=0;this.A=this.j=this.c=null}x(cl,Qk); -function dl(a,c,d,e,f){if(""!==a.l&&a.A&&(a.c||a.j)){if(a.c){var g=a.c,h=a.G;if(!h||h.fillStyle!=g.fillStyle){var l=[9,g.fillStyle];a.a.push(l);a.b.push(l);h?h.fillStyle=g.fillStyle:a.G={fillStyle:g.fillStyle}}}a.j&&(g=a.j,h=a.B,h&&h.lineCap==g.lineCap&&h.lineDash==g.lineDash&&h.lineJoin==g.lineJoin&&h.lineWidth==g.lineWidth&&h.miterLimit==g.miterLimit&&h.strokeStyle==g.strokeStyle||(l=[10,g.strokeStyle,g.lineWidth,g.lineCap,g.lineJoin,g.miterLimit,g.lineDash,!1],a.a.push(l),a.b.push(l),h?(h.lineCap= -g.lineCap,h.lineDash=g.lineDash,h.lineJoin=g.lineJoin,h.lineWidth=g.lineWidth,h.miterLimit=g.miterLimit,h.strokeStyle=g.strokeStyle):a.B={lineCap:g.lineCap,lineDash:g.lineDash,lineJoin:g.lineJoin,lineWidth:g.lineWidth,miterLimit:g.miterLimit,strokeStyle:g.strokeStyle}));g=a.A;h=a.ia;h&&h.font==g.font&&h.textAlign==g.textAlign&&h.textBaseline==g.textBaseline||(l=[11,g.font,g.textAlign,g.textBaseline],a.a.push(l),a.b.push(l),h?(h.font=g.font,h.textAlign=g.textAlign,h.textBaseline=g.textBaseline):a.ia= -{font:g.font,textAlign:g.textAlign,textBaseline:g.textBaseline});Sk(a,f);g=a.g.length;c=Rk(a,c,0,d,e,!1);c=[5,g,c,a.l,a.s,a.u,a.H,a.D,!!a.c,!!a.j];a.a.push(c);a.b.push(c);Vk(a,f)}} -cl.prototype.ab=function(a){if(a){var c=a.b;c?(c=c.b,c=yf(c?c:hk),this.c?this.c.fillStyle=c:this.c={fillStyle:c}):this.c=null;var d=a.j;if(d){var c=d.b,e=d.c,f=d.g,g=d.f,h=d.a,d=d.i,e=void 0!==e?e:"round",f=f?f.slice():ik,g=void 0!==g?g:"round",h=void 0!==h?h:1,d=void 0!==d?d:10,c=yf(c?c:jk);if(this.j){var l=this.j;l.lineCap=e;l.lineDash=f;l.lineJoin=g;l.lineWidth=h;l.miterLimit=d;l.strokeStyle=c}else this.j={lineCap:e,lineDash:f,lineJoin:g,lineWidth:h,miterLimit:d,strokeStyle:c}}else this.j=null; -var m=a.g,c=a.c,e=a.f,f=a.i,h=a.a,d=a.oa(),g=a.A,l=a.l;a=void 0!==m?m:"10px sans-serif";g=void 0!==g?g:"center";l=void 0!==l?l:"middle";this.A?(m=this.A,m.font=a,m.textAlign=g,m.textBaseline=l):this.A={font:a,textAlign:g,textBaseline:l};this.l=void 0!==d?d:"";this.s=void 0!==c?c:0;this.u=void 0!==e?e:0;this.H=void 0!==f?f:0;this.D=void 0!==h?h:1}else this.l=""};function el(a,c,d,e){this.j=a;this.a=c;this.i=d;this.g=e;this.b={};this.c=th(1,1);this.f=qd()} -function fl(a){for(var c in a.b){var d=a.b[c],e;for(e in d)d[e].Ic()}}function gl(a,c,d,e,f,g){var h=a.f;zi(h,.5,.5,1/d,-1/d,-e,-c[0],-c[1]);var l=a.c;l.clearRect(0,0,1,1);var m;void 0!==a.g&&(m=vd(),wd(m,c),zd(m,d*a.g,m));return hl(a,l,h,e,f,function(a){if(0<l.getImageData(0,0,1,1).data[3]){if(a=g(a))return a;l.clearRect(0,0,1,1)}},m)}function il(a,c,d){var e=void 0!==c?c.toString():"0";c=a.b[e];void 0===c&&(c={},a.b[e]=c);e=c[d];void 0===e&&(e=new jl[d](a.j,a.a,a.i),c[d]=e);return e} -el.prototype.Ja=function(){return Gb(this.b)};function kl(a,c,d,e,f,g){var h=Object.keys(a.b).map(Number);jb(h);var l=a.a,m=l[0],n=l[1],p=l[2],l=l[3],m=[m,n,m,l,p,l,p,n];ve(m,0,8,2,e,m);c.save();c.beginPath();c.moveTo(m[0],m[1]);c.lineTo(m[2],m[3]);c.lineTo(m[4],m[5]);c.lineTo(m[6],m[7]);c.closePath();c.clip();for(var q,r,m=0,n=h.length;m<n;++m)for(q=a.b[h[m].toString()],p=0,l=Pk.length;p<l;++p)r=q[Pk[p]],void 0!==r&&Tk(r,c,d,e,f,g,r.a,void 0);c.restore()} -function hl(a,c,d,e,f,g,h){var l=Object.keys(a.b).map(Number);jb(l,function(a,c){return c-a});var m,n,p,q,r;m=0;for(n=l.length;m<n;++m)for(q=a.b[l[m].toString()],p=Pk.length-1;0<=p;--p)if(r=q[Pk[p]],void 0!==r&&(r=Tk(r,c,1,d,e,f,r.b,g,h)))return r}var jl={Image:Wk,LineString:Xk,Polygon:$k,Text:cl};function ll(a,c,d,e){this.g=a;this.b=c;this.c=d;this.f=e}k=ll.prototype;k.get=function(a){return this.f[a]};k.Na=function(){return this.c};k.F=function(){this.a||(this.a="Point"===this.g?Gd(this.b):Hd(this.b,0,this.b.length,2));return this.a};k.ba=ll.prototype.Za=function(){return this.b};k.O=function(){return this};k.Tb=ll.prototype.O;k.la=Vd(2);k.Yb=wa;k.N=function(){return this.g};function ml(a,c){return na(a)-na(c)}function nl(a,c){var d=.5*a/c;return d*d}function pl(a,c,d,e,f,g){var h=!1,l,m;if(l=d.a)m=l.gc(),2==m||3==m?l.Yd(f,g):(0==m&&l.load(),l.Cd(f,g),h=!0);if(f=(0,d.c)(c))e=f.Tb(e),(0,ql[e.N()])(a,e,d,c);return h} -var ql={Point:function(a,c,d,e){var f=d.a;if(f){if(2!=f.gc())return;var g=il(a,d.b,"Image");g.Td(f);g.ld(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),dl(a,c.ba(),2,2,e)},LineString:function(a,c,d,e){var f=d.g;if(f){var g=il(a,d.b,"LineString");g.lb(null,f);g.gd(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),dl(a,Fk(c),2,2,e)},Polygon:function(a,c,d,e){var f=d.f,g=d.g;if(f||g){var h=il(a,d.b,"Polygon");h.lb(f,g);h.md(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),dl(a,af(c),2,2,e)},MultiPoint:function(a, -c,d,e){var f=d.a;if(f){if(2!=f.gc())return;var g=il(a,d.b,"Image");g.Td(f);g.jd(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),d=c.ba(),dl(a,d,d.length,c.la(),e)},MultiLineString:function(a,c,d,e){var f=d.g;if(f){var g=il(a,d.b,"LineString");g.lb(null,f);g.hd(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),c=Gk(c),dl(a,c,c.length,2,e)},MultiPolygon:function(a,c,d,e){var f=d.f,g=d.g;if(g||f){var h=il(a,d.b,"Polygon");h.lb(f,g);h.kd(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),c=Ik(c),dl(a,c,c.length,2,e)}, -GeometryCollection:function(a,c,d,e){c=c.a;var f,g;f=0;for(g=c.length;f<g;++f)(0,ql[c[f].N()])(a,c[f],d,e)},Circle:function(a,c,d,e){var f=d.f,g=d.g;if(f||g){var h=il(a,d.b,"Polygon");h.lb(f,g);h.fd(c,e)}if(f=d.oa())a=il(a,d.b,"Text"),a.ab(f),dl(a,c.Gc(),2,2,e)}};function rl(a,c,d,e,f,g){this.i=void 0!==g?g:null;wi.call(this,a,c,d,void 0!==g?0:2,e);this.g=f}x(rl,wi);rl.prototype.a=function(a){this.state=a?3:2;yi(this)};rl.prototype.load=function(){0==this.state&&(this.state=1,yi(this),this.i(sa(this.a,this)))};rl.prototype.f=function(){return this.g};var sl=!((Ab("Chrome")||Ab("CriOS"))&&!Ab("Opera")&&!Ab("OPR")&&!Ab("Edge"))||Ab("iPhone")&&!Ab("iPod")&&!Ab("iPad")||Ab("iPad")||Ab("iPod");function tl(a,c,d,e){var f=se(d,c,a);d=c.getPointResolution(e,d);c=c.Sb();void 0!==c&&(d*=c);c=a.Sb();void 0!==c&&(d/=c);a=a.getPointResolution(d,f)/d;isFinite(a)&&!isNaN(a)&&0<a&&(d/=a);return d}function ul(a,c,d,e){a=d-a;c=e-c;var f=Math.sqrt(a*a+c*c);return[Math.round(d+a/f),Math.round(e+c/f)]} -function vl(a,c,d,e,f,g,h,l,m,n){var p=th(Math.round(d*a),Math.round(d*c));if(0===m.length)return p.canvas;p.scale(d,d);var q=vd();m.forEach(function(a){Kd(q,a.extent)});var r=th(Math.round(d*Pd(q)/e),Math.round(d*Qd(q)/e));r.scale(d/e,d/e);r.translate(-q[0],q[3]);m.forEach(function(a){r.drawImage(a.image,a.extent[0],-a.extent[3],Pd(a.extent),Qd(a.extent))});var t=Md(h);l.c.forEach(function(a){var c=a.source,f=a.target,h=c[1][0],l=c[1][1],m=c[2][0],n=c[2][1];a=(f[0][0]-t[0])/g;var ia=-(f[0][1]-t[1])/ -g,O=(f[1][0]-t[0])/g,Aa=-(f[1][1]-t[1])/g,va=(f[2][0]-t[0])/g,fb=-(f[2][1]-t[1])/g,f=c[0][0],c=c[0][1],h=h-f,l=l-c,m=m-f,n=n-c;a:{h=[[h,l,0,0,O-a],[m,n,0,0,va-a],[0,0,h,l,Aa-ia],[0,0,m,n,fb-ia]];l=h.length;for(m=0;m<l;m++){for(var n=m,Ua=Math.abs(h[m][m]),$a=m+1;$a<l;$a++){var gb=Math.abs(h[$a][m]);gb>Ua&&(Ua=gb,n=$a)}if(0===Ua){h=null;break a}Ua=h[n];h[n]=h[m];h[m]=Ua;for(n=m+1;n<l;n++)for(Ua=-h[n][m]/h[m][m],$a=m;$a<l+1;$a++)h[n][$a]=m==$a?0:h[n][$a]+Ua*h[m][$a]}m=Array(l);for(n=l-1;0<=n;n--)for(m[n]= -h[n][l]/h[n][n],Ua=n-1;0<=Ua;Ua--)h[Ua][l]-=h[Ua][n]*m[n];h=m}h&&(p.save(),p.beginPath(),sl?(m=(a+O+va)/3,n=(ia+Aa+fb)/3,l=ul(m,n,a,ia),O=ul(m,n,O,Aa),va=ul(m,n,va,fb),p.moveTo(l[0],l[1]),p.lineTo(O[0],O[1]),p.lineTo(va[0],va[1])):(p.moveTo(a,ia),p.lineTo(O,Aa),p.lineTo(va,fb)),p.closePath(),p.clip(),p.transform(h[0],h[2],h[1],h[3],a,ia),p.translate(q[0]-f,q[3]-c),p.scale(e/d,-e/d),p.drawImage(r.canvas,0,0),p.restore())});n&&(p.save(),p.strokeStyle="black",p.lineWidth=1,l.c.forEach(function(a){var c= -a.target;a=(c[0][0]-t[0])/g;var d=-(c[0][1]-t[1])/g,e=(c[1][0]-t[0])/g,f=-(c[1][1]-t[1])/g,h=(c[2][0]-t[0])/g,c=-(c[2][1]-t[1])/g;p.beginPath();p.moveTo(a,d);p.lineTo(e,f);p.lineTo(h,c);p.closePath();p.stroke()}),p.restore());return p.canvas};function wl(a,c,d,e,f){this.g=a;this.f=c;var g={},h=qe(this.f,this.g);this.a=function(a){var c=a[0]+"/"+a[1];g[c]||(g[c]=h(a));return g[c]};this.i=e;this.s=f*f;this.c=[];this.A=!1;this.l=this.g.a&&!!e&&!!this.g.F()&&Pd(e)==Pd(this.g.F());this.b=this.g.F()?Pd(this.g.F()):null;this.j=this.f.F()?Pd(this.f.F()):null;a=Md(d);c=[d[2],d[3]];e=[d[2],d[1]];d=[d[0],d[1]];f=this.a(a);var l=this.a(c),m=this.a(e),n=this.a(d);xl(this,a,c,e,d,f,l,m,n,10);if(this.A){var p=Infinity;this.c.forEach(function(a){p=Math.min(p, -a.source[0][0],a.source[1][0],a.source[2][0])});this.c.forEach(function(a){if(Math.max(a.source[0][0],a.source[1][0],a.source[2][0])-p>this.b/2){var c=[[a.source[0][0],a.source[0][1]],[a.source[1][0],a.source[1][1]],[a.source[2][0],a.source[2][1]]];c[0][0]-p>this.b/2&&(c[0][0]-=this.b);c[1][0]-p>this.b/2&&(c[1][0]-=this.b);c[2][0]-p>this.b/2&&(c[2][0]-=this.b);Math.max(c[0][0],c[1][0],c[2][0])-Math.min(c[0][0],c[1][0],c[2][0])<this.b/2&&(a.source=c)}},this)}g={}} -function xl(a,c,d,e,f,g,h,l,m,n){var p=ud([g,h,l,m]),q=a.b?Pd(p)/a.b:null,r=a.g.a&&.5<q&&1>q,t=!1;if(0<n){if(a.f.c&&a.j)var B=ud([c,d,e,f]),t=t|.25<Pd(B)/a.j;!r&&a.g.c&&q&&(t|=.25<q)}if(t||!a.i||Ud(p,a.i)){if(!(t||isFinite(g[0])&&isFinite(g[1])&&isFinite(h[0])&&isFinite(h[1])&&isFinite(l[0])&&isFinite(l[1])&&isFinite(m[0])&&isFinite(m[1])))if(0<n)t=!0;else return;if(0<n&&(t||(q=a.a([(c[0]+e[0])/2,(c[1]+e[1])/2]),p=r?(ed(g[0],a.b)+ed(l[0],a.b))/2-ed(q[0],a.b):(g[0]+l[0])/2-q[0],q=(g[1]+l[1])/2-q[1], -t=p*p+q*q>a.s),t)){Math.abs(c[0]-e[0])<=Math.abs(c[1]-e[1])?(r=[(d[0]+e[0])/2,(d[1]+e[1])/2],p=a.a(r),q=[(f[0]+c[0])/2,(f[1]+c[1])/2],t=a.a(q),xl(a,c,d,r,q,g,h,p,t,n-1),xl(a,q,r,e,f,t,p,l,m,n-1)):(r=[(c[0]+d[0])/2,(c[1]+d[1])/2],p=a.a(r),q=[(e[0]+f[0])/2,(e[1]+f[1])/2],t=a.a(q),xl(a,c,r,q,f,g,p,t,m,n-1),xl(a,r,d,e,q,p,h,l,t,n-1));return}if(r){if(!a.l)return;a.A=!0}a.c.push({source:[g,l,m],target:[c,e,f]});a.c.push({source:[g,h,l],target:[c,d,e]})}} -function yl(a){var c=vd();a.c.forEach(function(a){a=a.source;wd(c,a[0]);wd(c,a[1]);wd(c,a[2])});return c};function zl(a,c,d,e,f,g){this.D=c;this.H=a.F();var h=c.F(),l=h?Td(d,h):d,h=tl(a,c,Rd(l),e);this.s=new wl(a,c,l,this.H,.5*h);this.j=e;this.i=d;a=yl(this.s);this.u=(this.a=g(a,h,f))?this.a.c:1;this.g=this.l=null;f=2;g=[];this.a&&(f=0,g=this.a.A);wi.call(this,d,e,this.u,f,g)}x(zl,wi);zl.prototype.Z=function(){1==this.state&&(Nc(this.g),this.g=null);zl.fa.Z.call(this)};zl.prototype.f=function(){return this.l}; -function Al(a){var c=a.a.state;2==c&&(a.l=vl(Pd(a.i)/a.j,Qd(a.i)/a.j,a.u,a.a.$(),0,a.j,a.i,a.s,[{extent:a.a.F(),image:a.a.f()}]));a.state=c;yi(a)}zl.prototype.load=function(){if(0==this.state){this.state=1;yi(this);var a=this.a.state;2==a||3==a?Al(this):(this.g=Fc(this.a,"change",function(){var a=this.a.state;if(2==a||3==a)Nc(this.g),this.g=null,Al(this)},!1,this),this.a.load())}};function Bl(a){qg.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,state:a.state});this.G=void 0!==a.resolutions?a.resolutions:null;this.a=null;this.ea=0}x(Bl,qg);function Cl(a,c){if(a.G){var d=pb(a.G,c,0);c=a.G[d]}return c} -function Dl(a,c,d,e,f){var g=a.j;if(g&&f&&!pe(g,f)){if(a.a){if(a.ea==a.g&&pe(a.a.D,f)&&a.a.$()==d&&a.a.c==e&&Jd(a.a.F(),c))return a.a;a.a.rc();a.a=null}a.a=new zl(g,f,c,d,e,sa(function(a,c,d){return this.pd(a,c,d,g)},a));a.ea=a.g;return a.a}g&&(f=g);return a.pd(c,d,e,f)}Bl.prototype.na=function(a){a=a.target;switch(a.state){case 1:this.b(new El(Fl,a));break;case 2:this.b(new El(Gl,a));break;case 3:this.b(new El(Hl,a))}};function Il(a,c){a.f().src=c}function El(a,c){lc.call(this,a);this.image=c} -x(El,lc);var Fl="imageloadstart",Gl="imageloadend",Hl="imageloaderror";function Jl(a){Bl.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions,state:void 0!==a.state?a.state:void 0});this.aa=a.canvasFunction;this.I=null;this.J=0;this.ja=void 0!==a.ratio?a.ratio:1.5}x(Jl,Bl); -Jl.prototype.pd=function(a,c,d,e){c=Cl(this,c);var f=this.I;if(f&&this.J==this.g&&f.$()==c&&f.c==d&&Ed(f.F(),a))return f;var g=a=a.slice(),h=this.ja,l=(g[2]-g[0])/2*(h-1),h=(g[3]-g[1])/2*(h-1);g[0]-=l;g[2]+=l;g[1]-=h;g[3]+=h;(e=this.aa(a,c,d,[Pd(a)/c*d,Qd(a)/c*d],e))&&(f=new rl(a,c,d,this.u,e));this.I=f;this.J=this.g;return f};function Kl(a){Yc.call(this);this.i=void 0;this.a="geometry";this.f=null;this.j=void 0;this.c=null;y(this,$c(this.a),this.xc,!1,this);void 0!==a&&(a instanceof ue||!a?this.Sa(a):this.K(a))}x(Kl,Yc);k=Kl.prototype;k.clone=function(){var a=new Kl(this.P());a.Uc(this.a);var c=this.O();c&&a.Sa(c.clone());(c=this.f)&&a.Fd(c);return a};k.O=function(){return this.get(this.a)};k.Ba=function(){return this.i};k.Bg=function(){return this.a};k.Xh=function(){return this.f};k.Yb=function(){return this.j}; -k.Yh=function(){this.v()};k.xc=function(){this.c&&(Nc(this.c),this.c=null);var a=this.O();a&&(this.c=y(a,"change",this.Yh,!1,this));this.v()};k.Sa=function(a){this.C(this.a,a)};k.Fd=function(a){this.j=(this.f=a)?Ll(a):void 0;this.v()};k.Sd=function(a){this.i=a;this.v()};k.Uc=function(a){Mc(this,$c(this.a),this.xc,!1,this);this.a=a;y(this,$c(this.a),this.xc,!1,this);this.xc()};function Ll(a){if(!la(a)){var c;c=fa(a)?a:[a];a=function(){return c}}return a};function Ml(a,c,d){if(la(a))d&&(a=sa(a,d));else if(a&&"function"==typeof a.handleEvent)a=sa(a.handleEvent,a);else throw Error("Invalid listener argument");return 2147483647<c?-1:ba.setTimeout(a,c||0)};var Nl=ba.JSON.parse,Ol=ba.JSON.stringify;function Pl(){}Pl.prototype.b=null;function Ql(a){var c;(c=a.b)||(c={},Rl(a)&&(c[0]=!0,c[1]=!0),c=a.b=c);return c};var Sl;function Tl(){}x(Tl,Pl);function Ul(a){return(a=Rl(a))?new ActiveXObject(a):new XMLHttpRequest}function Rl(a){if(!a.a&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var c=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],d=0;d<c.length;d++){var e=c[d];try{return new ActiveXObject(e),a.a=e}catch(f){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.a}Sl=new Tl;var Vl=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;function Wl(a,c){if(a)for(var d=a.split("&"),e=0;e<d.length;e++){var f=d[e].indexOf("="),g=null,h=null;0<=f?(g=d[e].substring(0,f),h=d[e].substring(f+1)):g=d[e];c(g,h?decodeURIComponent(h.replace(/\+/g," ")):"")}} -function Xl(a){if(a[1]){var c=a[0],d=c.indexOf("#");0<=d&&(a.push(c.substr(d)),a[0]=c=c.substr(0,d));d=c.indexOf("?");0>d?a[1]="?":d==c.length-1&&(a[1]=void 0)}return a.join("")}function Yl(a,c,d){if(fa(c))for(var e=0;e<c.length;e++)Yl(a,String(c[e]),d);else null!=c&&d.push("&",a,""===c?"":"=",encodeURIComponent(String(c)))}function Zl(a,c){for(var d in c)Yl(d,c[d],a);return a};function $l(a){Sc.call(this);this.J=new Vg;this.s=a||null;this.a=!1;this.l=this.X=null;this.i=this.Y=this.D="";this.g=this.H=this.f=this.u=!1;this.A=0;this.c=null;this.j=am;this.G=this.ea=!1}x($l,Sc);var am="",bm=/^https?$/i,cm=["POST","PUT"]; -function dm(a,c){if(a.X)throw Error("[goog.net.XhrIo] Object is active with another request="+a.D+"; newUri="+c);a.D=c;a.i="";a.Y="GET";a.u=!1;a.a=!0;a.X=a.s?Ul(a.s):Ul(Sl);a.l=a.s?Ql(a.s):Ql(Sl);a.X.onreadystatechange=sa(a.B,a);try{a.H=!0,a.X.open("GET",String(c),!0),a.H=!1}catch(g){em(a,g);return}var d=a.J.clone(),e=Za(d.L()),f=ba.FormData&&!1;!(0<=Wa.indexOf.call(cm,"GET",void 0))||e||f||Wg(d,"Content-Type","application/x-www-form-urlencoded;charset=utf-8");d.forEach(function(a,c){this.X.setRequestHeader(c, -a)},a);a.j&&(a.X.responseType=a.j);"withCredentials"in a.X&&(a.X.withCredentials=a.ea);try{fm(a),0<a.A&&(a.G=gm(a.X),a.G?(a.X.timeout=a.A,a.X.ontimeout=sa(a.I,a)):a.c=Ml(a.I,a.A,a)),a.f=!0,a.X.send(""),a.f=!1}catch(g){em(a,g)}}function gm(a){return Pb&&ac(9)&&ka(a.timeout)&&ca(a.ontimeout)}function ab(a){return"content-type"==a.toLowerCase()} -$l.prototype.I=function(){"undefined"!=typeof aa&&this.X&&(this.i="Timed out after "+this.A+"ms, aborting",this.b("timeout"),this.X&&this.a&&(this.a=!1,this.g=!0,this.X.abort(),this.g=!1,this.b("complete"),this.b("abort"),hm(this)))};function em(a,c){a.a=!1;a.X&&(a.g=!0,a.X.abort(),a.g=!1);a.i=c;im(a);hm(a)}function im(a){a.u||(a.u=!0,a.b("complete"),a.b("error"))}$l.prototype.Z=function(){this.X&&(this.a&&(this.a=!1,this.g=!0,this.X.abort(),this.g=!1),hm(this,!0));$l.fa.Z.call(this)}; -$l.prototype.B=function(){this.ma||(this.H||this.f||this.g?jm(this):this.aa())};$l.prototype.aa=function(){jm(this)};function jm(a){if(a.a&&"undefined"!=typeof aa&&(!a.l[1]||4!=km(a)||2!=mm(a)))if(a.f&&4==km(a))Ml(a.B,0,a);else if(a.b("readystatechange"),4==km(a)){a.a=!1;try{if(nm(a))a.b("complete"),a.b("success");else{var c;try{c=2<km(a)?a.X.statusText:""}catch(d){c=""}a.i=c+" ["+mm(a)+"]";im(a)}}finally{hm(a)}}} -function hm(a,c){if(a.X){fm(a);var d=a.X,e=a.l[0]?da:null;a.X=null;a.l=null;c||a.b("ready");try{d.onreadystatechange=e}catch(f){}}}function fm(a){a.X&&a.G&&(a.X.ontimeout=null);ka(a.c)&&(ba.clearTimeout(a.c),a.c=null)} -function nm(a){var c=mm(a),d;a:switch(c){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:d=!0;break a;default:d=!1}if(!d){if(c=0===c)a=String(a.D).match(Vl)[1]||null,!a&&ba.self&&ba.self.location&&(a=ba.self.location.protocol,a=a.substr(0,a.length-1)),c=!bm.test(a?a.toLowerCase():"");d=c}return d}function km(a){return a.X?a.X.readyState:0}function mm(a){try{return 2<km(a)?a.X.status:-1}catch(c){return-1}}function om(a){try{return a.X?a.X.responseText:""}catch(c){return""}} -function pm(a){try{if(!a.X)return null;if("response"in a.X)return a.X.response;switch(a.j){case am:case "text":return a.X.responseText;case "arraybuffer":if("mozResponseArrayBuffer"in a.X)return a.X.mozResponseArrayBuffer}return null}catch(c){return null}};function qm(){if(!Pb)return!1;try{return new ActiveXObject("MSXML2.DOMDocument"),!0}catch(a){return!1}}var rm=Pb&&qm();function sm(a){var c=a.xml;if(c)return c;if("undefined"!=typeof XMLSerializer)return(new XMLSerializer).serializeToString(a);throw Error("Your browser does not support serializing XML documents");};var tm;a:if(document.implementation&&document.implementation.createDocument)tm=document.implementation.createDocument("","",null);else{if(rm){var um=new ActiveXObject("MSXML2.DOMDocument");if(um){um.resolveExternals=!1;um.validateOnParse=!1;try{um.setProperty("ProhibitDTD",!0),um.setProperty("MaxXMLSize",2048),um.setProperty("MaxElementDepth",256)}catch(a){}}if(um){tm=um;break a}}throw Error("Your browser does not support creating new documents");}var vm=tm; -function wm(a,c){return vm.createElementNS(a,c)}function xm(a,c){a||(a="");return vm.createNode(1,c,a)}var ym=document.implementation&&document.implementation.createDocument?wm:xm;function zm(a){return Am(a,!1,[]).join("")}function Am(a,c,d){if(4==a.nodeType||3==a.nodeType)c?d.push(String(a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):d.push(a.nodeValue);else for(a=a.firstChild;a;a=a.nextSibling)Am(a,c,d);return d}function Bm(a){return a.localName} -function Cm(a){var c=a.localName;return void 0!==c?c:a.baseName}var Dm=Pb?Cm:Bm;function Em(a){return a instanceof Document}function Fm(a){return ma(a)&&9==a.nodeType}var Gm=Pb?Fm:Em;function Hm(a){return a instanceof Node}function Im(a){return ma(a)&&void 0!==a.nodeType}var Jm=Pb?Im:Hm;function Km(a,c,d,e){a.setAttributeNS(c,d,e)}function Lm(a,c,d,e){c?(c=a.ownerDocument.createNode(2,d,c),c.nodeValue=e,a.setAttributeNode(c)):a.setAttribute(d,e)} -var Mm=document.implementation&&document.implementation.createDocument?Km:Lm;function Nm(a){return(new DOMParser).parseFromString(a,"application/xml")}function Om(a,c){return function(d,e){var f=a.call(c,d,e);void 0!==f&&eb(e[e.length-1],f)}}function Pm(a,c){return function(d,e){var f=a.call(void 0!==c?c:this,d,e);void 0!==f&&e[e.length-1].push(f)}}function Qm(a){return function(c,d){var e=a.call(this,c,d);void 0!==e&&(d[d.length-1]=e)}} -function Rm(a){return function(c,d){var e=a.call(this,c,d);void 0!==e&&Jb(d[d.length-1],c.localName).push(e)}}function L(a,c){return function(d,e){var f=a.call(this,d,e);void 0!==f&&(e[e.length-1][void 0!==c?c:d.localName]=f)}}function Sm(a){return function(c,d,e){a.call(this,c,d,e);e[e.length-1].node.appendChild(c)}}function Tm(a){return function(c,d,e){c=d[d.length-1].node;d=a;void 0===d&&(d=e);e=void 0;e=c.namespaceURI;return ym(e,d)}}var Um=Tm(); -function Vm(a,c){for(var d=c.length,e=Array(d),f=0;f<d;++f)e[f]=a[c[f]];return e}function M(a,c,d){d=void 0!==d?d:{};var e,f;e=0;for(f=a.length;e<f;++e)d[a[e]]=c;return d}function Wm(a,c,d,e){for(c=c.firstElementChild;c;c=c.nextElementSibling){var f=a[c.namespaceURI];void 0!==f&&(f=f[c.localName],void 0!==f&&f.call(e,c,d))}}function Xm(a,c,d,e,f){e.push(a);Wm(c,d,e,f);return e.pop()} -function Ym(a,c,d,e,f,g,h){f.push(a);a=(void 0!==g?g:e).length;for(var l,m,n=0;n<a;++n)l=e[n],void 0!==l&&(m=d.call(h,l,f,void 0!==g?g[n]:void 0),void 0!==m&&c[m.namespaceURI][m.localName].call(h,m,l,f));f.pop()};function Zm(a,c,d){return function(e,f,g){var h=new $l;h.j="arraybuffer"==c.N()?"arraybuffer":"text";y(h,"complete",function(a){a=a.target;if(nm(a)){var e=c.N(),f;if("json"==e)f=om(a);else if("text"==e)f=om(a);else if("xml"==e){if(!Pb)try{f=a.X?a.X.responseXML:null}catch(h){f=null}f||(f=Nm(om(a)))}else"arraybuffer"==e&&(f=pm(a));f&&(e=c.Sc(f,{featureProjection:g}),2==d.length?d.call(this,e,c.hc(f)):d.call(this,e))}kc(a)},!1,this);la(a)?dm(h,a(e,f,g)):dm(h,a)}} -function $m(a,c){return Zm(a,c,function(a){this.ad(a)})};function an(){return[[-Infinity,-Infinity,Infinity,Infinity]]};var bn; -(function(){var a={ne:{}};(function(){function c(a,d){if(!(this instanceof c))return new c(a,d);this.$c=Math.max(4,a||9);this.ge=Math.max(2,Math.ceil(.4*this.$c));d&&this.Nf(d);this.clear()}function d(a,c){a.bbox=e(a,0,a.children.length,c)}function e(a,c,d,e){for(var g=[Infinity,Infinity,-Infinity,-Infinity],h;c<d;c++)h=a.children[c],f(g,a.sa?e(h):h.bbox);return g}function f(a,c){a[0]=Math.min(a[0],c[0]);a[1]=Math.min(a[1],c[1]);a[2]=Math.max(a[2],c[2]);a[3]=Math.max(a[3],c[3])}function g(a,c){return a.bbox[0]- -c.bbox[0]}function h(a,c){return a.bbox[1]-c.bbox[1]}function l(a){return(a[2]-a[0])*(a[3]-a[1])}function m(a){return a[2]-a[0]+(a[3]-a[1])}function n(a,c){return a[0]<=c[0]&&a[1]<=c[1]&&c[2]<=a[2]&&c[3]<=a[3]}function p(a,c){return c[0]<=a[2]&&c[1]<=a[3]&&c[2]>=a[0]&&c[3]>=a[1]}function q(a,c,d,e,f){for(var g=[c,d],h;g.length;)d=g.pop(),c=g.pop(),d-c<=e||(h=c+Math.ceil((d-c)/e/2)*e,r(a,c,d,h,f),g.push(c,h,h,d))}function r(a,c,d,e,f){for(var g,h,l,m,n;d>c;){600<d-c&&(g=d-c+1,h=e-c+1,l=Math.log(g), -m=.5*Math.exp(2*l/3),n=.5*Math.sqrt(l*m*(g-m)/g)*(0>h-g/2?-1:1),l=Math.max(c,Math.floor(e-h*m/g+n)),h=Math.min(d,Math.floor(e+(g-h)*m/g+n)),r(a,l,h,e,f));g=a[e];h=c;m=d;t(a,c,e);for(0<f(a[d],g)&&t(a,c,d);h<m;){t(a,h,m);h++;for(m--;0>f(a[h],g);)h++;for(;0<f(a[m],g);)m--}0===f(a[c],g)?t(a,c,m):(m++,t(a,m,d));m<=e&&(c=m+1);e<=m&&(d=m-1)}}function t(a,c,d){var e=a[c];a[c]=a[d];a[d]=e}c.prototype={all:function(){return this.ce(this.data,[])},search:function(a){var c=this.data,d=[],e=this.va;if(!p(a,c.bbox))return d; -for(var f=[],g,h,l,m;c;){g=0;for(h=c.children.length;g<h;g++)l=c.children[g],m=c.sa?e(l):l.bbox,p(a,m)&&(c.sa?d.push(l):n(a,m)?this.ce(l,d):f.push(l));c=f.pop()}return d},load:function(a){if(!a||!a.length)return this;if(a.length<this.ge){for(var c=0,d=a.length;c<d;c++)this.ka(a[c]);return this}a=this.ee(a.slice(),0,a.length-1,0);this.data.children.length?this.data.height===a.height?this.he(this.data,a):(this.data.height<a.height&&(c=this.data,this.data=a,a=c),this.fe(a,this.data.height-a.height-1, -!0)):this.data=a;return this},ka:function(a){a&&this.fe(a,this.data.height-1);return this},clear:function(){this.data={children:[],height:1,bbox:[Infinity,Infinity,-Infinity,-Infinity],sa:!0};return this},remove:function(a){if(!a)return this;for(var c=this.data,d=this.va(a),e=[],f=[],g,h,l,m;c||e.length;){c||(c=e.pop(),h=e[e.length-1],g=f.pop(),m=!0);if(c.sa&&(l=c.children.indexOf(a),-1!==l)){c.children.splice(l,1);e.push(c);this.Mf(e);break}m||c.sa||!n(c.bbox,d)?h?(g++,c=h.children[g],m=!1):c=null: -(e.push(c),f.push(g),g=0,h=c,c=c.children[0])}return this},va:function(a){return a},dd:function(a,c){return a[0]-c[0]},ed:function(a,c){return a[1]-c[1]},toJSON:function(){return this.data},ce:function(a,c){for(var d=[];a;)a.sa?c.push.apply(c,a.children):d.push.apply(d,a.children),a=d.pop();return c},ee:function(a,c,e,f){var g=e-c+1,h=this.$c,l;if(g<=h)return l={children:a.slice(c,e+1),height:1,bbox:null,sa:!0},d(l,this.va),l;f||(f=Math.ceil(Math.log(g)/Math.log(h)),h=Math.ceil(g/Math.pow(h,f-1))); -l={children:[],height:f,bbox:null};var g=Math.ceil(g/h),h=g*Math.ceil(Math.sqrt(h)),m,n,p;for(q(a,c,e,h,this.dd);c<=e;c+=h)for(n=Math.min(c+h-1,e),q(a,c,n,g,this.ed),m=c;m<=n;m+=g)p=Math.min(m+g-1,n),l.children.push(this.ee(a,m,p,f-1));d(l,this.va);return l},Lf:function(a,c,d,e){for(var f,g,h,m,n,p,q,r;;){e.push(c);if(c.sa||e.length-1===d)break;q=r=Infinity;f=0;for(g=c.children.length;f<g;f++)h=c.children[f],n=l(h.bbox),p=h.bbox,p=(Math.max(p[2],a[2])-Math.min(p[0],a[0]))*(Math.max(p[3],a[3])-Math.min(p[1], -a[1]))-n,p<r?(r=p,q=n<q?n:q,m=h):p===r&&n<q&&(q=n,m=h);c=m}return c},fe:function(a,c,d){var e=this.va;d=d?a.bbox:e(a);var e=[],g=this.Lf(d,this.data,c,e);g.children.push(a);for(f(g.bbox,d);0<=c;)if(e[c].children.length>this.$c)this.Of(e,c),c--;else break;this.If(d,e,c)},Of:function(a,c){var e=a[c],f=e.children.length,g=this.ge;this.Jf(e,g,f);f=this.Kf(e,g,f);f={children:e.children.splice(f,e.children.length-f),height:e.height};e.sa&&(f.sa=!0);d(e,this.va);d(f,this.va);c?a[c-1].children.push(f):this.he(e, -f)},he:function(a,c){this.data={children:[a,c],height:a.height+1};d(this.data,this.va)},Kf:function(a,c,d){var f,g,h,m,n,p,q;n=p=Infinity;for(f=c;f<=d-c;f++)g=e(a,0,f,this.va),h=e(a,f,d,this.va),m=Math.max(0,Math.min(g[2],h[2])-Math.max(g[0],h[0]))*Math.max(0,Math.min(g[3],h[3])-Math.max(g[1],h[1])),g=l(g)+l(h),m<n?(n=m,q=f,p=g<p?g:p):m===n&&g<p&&(p=g,q=f);return q},Jf:function(a,c,d){var e=a.sa?this.dd:g,f=a.sa?this.ed:h,l=this.de(a,c,d,e);c=this.de(a,c,d,f);l<c&&a.children.sort(e)},de:function(a, -c,d,g){a.children.sort(g);g=this.va;var h=e(a,0,c,g),l=e(a,d-c,d,g),n=m(h)+m(l),p,q;for(p=c;p<d-c;p++)q=a.children[p],f(h,a.sa?g(q):q.bbox),n+=m(h);for(p=d-c-1;p>=c;p--)q=a.children[p],f(l,a.sa?g(q):q.bbox),n+=m(l);return n},If:function(a,c,d){for(;0<=d;d--)f(c[d].bbox,a)},Mf:function(a){for(var c=a.length-1,e;0<=c;c--)0===a[c].children.length?0<c?(e=a[c-1].children,e.splice(e.indexOf(a[c]),1)):this.clear():d(a[c],this.va)},Nf:function(a){var c=["return a"," - b",";"];this.dd=new Function("a","b", -c.join(a[0]));this.ed=new Function("a","b",c.join(a[1]));this.va=new Function("a","return [a"+a.join(", a")+"];")}};"undefined"!==typeof a?a.ne=c:"undefined"!==typeof self?self.b=c:window.b=c})();bn=a.ne})();function cn(a){this.a=bn(a);this.b={}}k=cn.prototype;k.ka=function(a,c){var d=[a[0],a[1],a[2],a[3],c];this.a.ka(d);this.b[na(c)]=d};k.load=function(a,c){for(var d=Array(c.length),e=0,f=c.length;e<f;e++){var g=a[e],h=c[e],g=[g[0],g[1],g[2],g[3],h];d[e]=g;this.b[na(h)]=g}this.a.load(d)};k.remove=function(a){a=na(a);var c=this.b[a];delete this.b[a];return null!==this.a.remove(c)};function dn(a,c,d){var e=na(d);Jd(a.b[e].slice(0,4),c)||(a.remove(d),a.ka(c,d))} -function en(a){return a.a.all().map(function(a){return a[4]})}function fn(a,c){return a.a.search(c).map(function(a){return a[4]})}k.forEach=function(a,c){return gn(en(this),a,c)};function hn(a,c,d,e){return gn(fn(a,c),d,e)}function gn(a,c,d){for(var e,f=0,g=a.length;f<g&&!(e=c.call(d,a[f]));f++);return e}k.Ja=function(){return Gb(this.b)};k.clear=function(){this.a.clear();this.b={}};k.F=function(){return this.a.data.bbox};function N(a){a=a||{};qg.call(this,{attributions:a.attributions,logo:a.logo,projection:void 0,state:"ready",wrapX:void 0!==a.wrapX?a.wrapX:!0});this.G=wa;void 0!==a.loader?this.G=a.loader:void 0!==a.url&&(this.G=$m(a.url,a.format));this.I=void 0!==a.strategy?a.strategy:an;var c=void 0!==a.useSpatialIndex?a.useSpatialIndex:!0;this.a=c?new cn:null;this.B=new cn;this.f={};this.i={};this.l={};this.s={};this.c=null;var d,e;a.features instanceof F?(d=a.features,e=d.a):fa(a.features)&&(e=a.features);c|| -void 0!==d||(d=new F(e));void 0!==e&&jn(this,e);void 0!==d&&kn(this,d)}x(N,qg);k=N.prototype;k.Lc=function(a){var c=na(a).toString();if(ln(this,c,a)){mn(this,c,a);var d=a.O();d?(c=d.F(),this.a&&this.a.ka(c,a)):this.f[c]=a;this.b(new nn("addfeature",a))}this.v()};function mn(a,c,d){a.s[c]=[y(d,"change",a.bf,!1,a),y(d,"propertychange",a.bf,!1,a)]}function ln(a,c,d){var e=!0,f=d.Ba();void 0!==f?f.toString()in a.i?e=!1:a.i[f.toString()]=d:a.l[c]=d;return e}k.ad=function(a){jn(this,a);this.v()}; -function jn(a,c){var d,e,f,g,h=[],l=[],m=[];e=0;for(f=c.length;e<f;e++)g=c[e],d=na(g).toString(),ln(a,d,g)&&l.push(g);e=0;for(f=l.length;e<f;e++){g=l[e];d=na(g).toString();mn(a,d,g);var n=g.O();n?(d=n.F(),h.push(d),m.push(g)):a.f[d]=g}a.a&&a.a.load(h,m);e=0;for(f=l.length;e<f;e++)a.b(new nn("addfeature",l[e]))} -function kn(a,c){var d=!1;y(a,"addfeature",function(a){d||(d=!0,c.push(a.feature),d=!1)});y(a,"removefeature",function(a){d||(d=!0,c.remove(a.feature),d=!1)});y(c,"add",function(a){d||(a=a.element,d=!0,this.Lc(a),d=!1)},!1,a);y(c,"remove",function(a){d||(a=a.element,d=!0,this.fc(a),d=!1)},!1,a);a.c=c} -k.clear=function(a){if(a){for(var c in this.s)this.s[c].forEach(Nc);this.c||(this.s={},this.i={},this.l={})}else a=this.lf,this.a&&(this.a.forEach(a,this),Bb(this.f,a,this));this.c&&this.c.clear();this.a&&this.a.clear();this.B.clear();this.f={};this.b(new nn("clear"));this.v()};k.dg=function(a,c){if(this.a)return this.a.forEach(a,c);if(this.c)return this.c.forEach(a,c)};function on(a,c,d){a.qb([c[0],c[1],c[0],c[1]],function(a){if(a.O().le(c))return d.call(void 0,a)})} -k.qb=function(a,c,d){if(this.a)return hn(this.a,a,c,d);if(this.c)return this.c.forEach(c,d)};k.fg=function(a,c,d){return this.qb(a,function(e){if(e.O().pa(a)&&(e=c.call(d,e)))return e})};k.vg=function(){return this.c};k.af=function(){var a;this.c?a=this.c.a:this.a&&(a=en(this.a),Gb(this.f)||eb(a,Eb(this.f)));return a};k.ug=function(a){var c=[];on(this,a,function(a){c.push(a)});return c};k.wg=function(a){return fn(this.a,a)}; -k.og=function(a){var c=a[0],d=a[1],e=null,f=[NaN,NaN],g=Infinity,h=[-Infinity,-Infinity,Infinity,Infinity];hn(this.a,h,function(a){var m=a.O(),n=g;g=m.Aa(c,d,f,g);g<n&&(e=a,a=Math.sqrt(g),h[0]=c-a,h[1]=d-a,h[2]=c+a,h[3]=d+a)});return e};k.F=function(){return this.a.F()};k.tg=function(a){a=this.i[a.toString()];return void 0!==a?a:null}; -k.bf=function(a){a=a.target;var c=na(a).toString(),d=a.O();d?(d=d.F(),c in this.f?(delete this.f[c],this.a&&this.a.ka(d,a)):this.a&&dn(this.a,d,a)):c in this.f||(this.a&&this.a.remove(a),this.f[c]=a);d=a.Ba();void 0!==d?(d=d.toString(),c in this.l?(delete this.l[c],this.i[d]=a):this.i[d]!==a&&(pn(this,a),this.i[d]=a)):c in this.l||(pn(this,a),this.l[c]=a);this.v();this.b(new nn("changefeature",a))};k.Ja=function(){return this.a.Ja()&&Gb(this.f)}; -function qn(a,c,d,e){var f=a.B;c=a.I(c,d);var g,h;g=0;for(h=c.length;g<h;++g){var l=c[g];hn(f,l,function(a){return Ed(a.extent,l)})||(a.G.call(a,l,d,e),f.ka(l,{extent:l.slice()}))}}k.fc=function(a){var c=na(a).toString();c in this.f?delete this.f[c]:this.a&&this.a.remove(a);this.lf(a);this.v()};k.lf=function(a){var c=na(a).toString();this.s[c].forEach(Nc);delete this.s[c];var d=a.Ba();void 0!==d?delete this.i[d.toString()]:delete this.l[c];this.b(new nn("removefeature",a))}; -function pn(a,c){for(var d in a.i)if(a.i[d]===c){delete a.i[d];break}}function nn(a,c){lc.call(this,a);this.feature=c}x(nn,lc);function rn(a){this.c=a.source;this.qa=qd();this.f=th();this.i=[0,0];this.s=null;Jl.call(this,{attributions:a.attributions,canvasFunction:sa(this.ag,this),logo:a.logo,projection:a.projection,ratio:a.ratio,resolutions:a.resolutions,state:this.c.H});this.B=null;this.l=void 0;this.Xe(a.style);y(this.c,"change",this.Ti,void 0,this)}x(rn,Jl);k=rn.prototype; -k.ag=function(a,c,d,e,f){var g=new el(.5*c/d,a,c);qn(this.c,a,c,f);var h=!1;this.c.qb(a,function(a){var e;if(!(e=h)){var f;(e=a.Yb())?f=e.call(a,c):this.l&&(f=this.l(a,c));if(f){var p,q=!1;e=0;for(p=f.length;e<p;++e)q=pl(g,a,f[e],nl(c,d),this.Si,this)||q;e=q}else e=!1}h=e},this);fl(g);if(h)return null;this.i[0]!=e[0]||this.i[1]!=e[1]?(this.f.canvas.width=e[0],this.f.canvas.height=e[1],this.i[0]=e[0],this.i[1]=e[1]):this.f.clearRect(0,0,e[0],e[1]);a=sn(this,Rd(a),c,d,e);kl(g,this.f,d,a,0,{});this.s= -g;return this.f.canvas};k.Ye=function(a,c,d,e,f){if(this.s){var g={};return gl(this.s,a,c,0,e,function(a){var c=na(a).toString();if(!(c in g))return g[c]=!0,f(a)})}};k.Pi=function(){return this.c};k.Qi=function(){return this.B};k.Ri=function(){return this.l};function sn(a,c,d,e,f){return zi(a.qa,f[0]/2,f[1]/2,e/d,-e/d,0,-c[0],-c[1])}k.Si=function(){this.v()};k.Ti=function(){this.H=this.c.H;this.v()};k.Xe=function(a){this.B=void 0!==a?a:vk;this.l=a?tk(this.B):void 0;this.v()};function Vi(a){Kk.call(this,a);this.i=null;this.j=qd();this.c=this.f=null}x(Vi,Kk);k=Vi.prototype;k.ec=function(a,c,d,e){var f=this.a;return f.ha().Ye(a,c.viewState.resolution,c.viewState.rotation,c.skippedFeatureUids,function(a){return d.call(e,a,f)})}; -k.Kd=function(a,c,d,e){if(this.Jc())if(this.a.ha()instanceof rn){if(a=a.slice(),Ai(c.pixelToCoordinateMatrix,a,a),this.ec(a,c,Xd,this))return d.call(e,this.a)}else if(this.f||(this.f=qd(),sd(this.j,this.f)),c=Nk(a,this.f),this.c||(this.c=th(1,1)),this.c.clearRect(0,0,1,1),this.c.drawImage(this.Jc(),c[0],c[1],1,1,0,0,1,1),0<this.c.getImageData(0,0,1,1).data[3])return d.call(e,this.a)};k.Jc=function(){return this.i?this.i.f():null};k.re=function(){return this.j}; -k.Ld=function(a,c){var d=a.pixelRatio,e=a.viewState,f=e.center,g=e.resolution,h=e.rotation,l=this.a.ha(),m=a.viewHints,n=a.extent;void 0!==c.extent&&(n=Td(n,c.extent));if(!m[0]&&!m[1]&&!Od(n)){if(m=e=Dl(l,n,g,d,e.projection))m=e,n=m.state,2!=n&&3!=n&&y(m,"change",this.I,!1,this),0==n&&(m.load(),n=m.state),m=2==n;m&&(this.i=e)}if(this.i){var e=this.i,m=e.F(),n=e.$(),p=e.c,g=d*n/(g*p);zi(this.j,d*a.size[0]/2,d*a.size[1]/2,g,g,h,p*(m[0]-f[0])/n,p*(f[1]-m[3])/n);this.f=null;Fi(a.attributions,e.A);Gi(a, -l)}return!0};function Wi(a){Kk.call(this,a);this.c=this.j=null;this.s=!1;this.A=null;this.u=qd();this.i=null;this.G=this.B=this.D=NaN;this.l=this.f=null;this.Y=[0,0]}x(Wi,Kk);Wi.prototype.Jc=function(){return this.j};Wi.prototype.re=function(){return this.u}; -Wi.prototype.Ld=function(a,c){function d(a){a=a.state;return 2==a||4==a||3==a&&!fb}var e=a.pixelRatio,f=a.viewState,g=f.projection,h=this.a,l=h.ha(),m=l.Ra(g),n=l.qe(),p=Ag(m,f.resolution),q=l.wc(p,a.pixelRatio,g),r=q[0]/dd(m.Ia(p),this.Y)[0],t=m.$(p),r=t/r,B=f.center,V;t==f.resolution?(B=Ii(B,t,a.size),V=Sd(B,t,f.rotation,a.size)):V=a.extent;void 0!==c.extent&&(V=Td(V,c.extent));if(Od(V))return!1;var w=xg(m,V,t),E=q[0]*(w.a-w.b+1),u=q[1]*qf(w),Ca,Ea;this.j?(Ca=this.j,Ea=this.A,this.c[0]<E||this.c[1]< -u||this.B!==q[0]||this.G!==q[1]||this.s&&(this.c[0]>E||this.c[1]>u)?(Ca.width=E,Ca.height=u,this.c=[E,u],this.s=!Ok(this.c),this.f=null):(E=this.c[0],u=this.c[1],p==this.D&&pf(this.f,w)||(this.f=null))):(Ea=th(E,u),this.j=Ea.canvas,this.c=[E,u],this.A=Ea,this.s=!Ok(this.c));var ia,O;this.f?(u=this.f,E=u.a-u.b+1):(E/=q[0],u/=q[1],ia=w.b-Math.floor((E-(w.a-w.b+1))/2),O=w.c-Math.floor((u-qf(w))/2),this.D=p,this.B=q[0],this.G=q[1],this.f=new nf(ia,ia+E-1,O,O+u-1),this.l=Array(E*u),u=this.f);Ca={};Ca[p]= -{};var Aa=[],va=Ci(l,g,Ca),fb=h.j(),Ua=vd(),$a=new nf(0,0,0,0),gb,ja,za;for(O=w.b;O<=w.a;++O)for(za=w.c;za<=w.g;++za)ja=Ki(l,p,O,za,e,g),!d(ja)&&ja.g&&(ja=ja.g),d(ja)?Ca[p][mf(ja.a)]=ja:(gb=vg(m,ja.a,va,$a,Ua),gb||(Aa.push(ja),(gb=wg(m,ja.a,$a,Ua))&&va(p+1,gb)));va=0;for(gb=Aa.length;va<gb;++va)ja=Aa[va],O=q[0]*(ja.a[1]-u.b),za=q[1]*(u.g-ja.a[2]),Ea.clearRect(O,za,q[0],q[1]);Aa=Object.keys(Ca).map(Number);jb(Aa);var lm=l.qa,Wf=Md(m.Ca([p,u.b,u.g],Ua)),Rc,Xf,Vb,Re,rd,xi,va=0;for(gb=Aa.length;va<gb;++va)if(Rc= -Aa[va],q=l.wc(Rc,e,g),Re=Ca[Rc],Rc==p)for(Xf in Re)ja=Re[Xf],ia=(ja.a[2]-u.c)*E+(ja.a[1]-u.b),this.l[ia]!=ja&&(O=q[0]*(ja.a[1]-u.b),za=q[1]*(u.g-ja.a[2]),Vb=ja.state,4!=Vb&&(3!=Vb||fb)&&lm||Ea.clearRect(O,za,q[0],q[1]),2==Vb&&Ea.drawImage(ja.xb(),n,n,q[0],q[1],O,za,q[0],q[1]),this.l[ia]=ja);else for(Xf in Rc=m.$(Rc)/t,Re)for(ja=Re[Xf],ia=m.Ca(ja.a,Ua),O=(ia[0]-Wf[0])/r,za=(Wf[1]-ia[3])/r,xi=Rc*q[0],rd=Rc*q[1],Vb=ja.state,4!=Vb&&lm||Ea.clearRect(O,za,xi,rd),2==Vb&&Ea.drawImage(ja.xb(),n,n,q[0],q[1], -O,za,xi,rd),ja=m.Wa(ia,p,$a),ia=Math.max(ja.b,u.b),za=Math.min(ja.a,u.a),O=Math.max(ja.c,u.c),ja=Math.min(ja.g,u.g),Vb=ia;Vb<=za;++Vb)for(rd=O;rd<=ja;++rd)ia=(rd-u.c)*E+(Vb-u.b),this.l[ia]=void 0;Hi(a.usedTiles,l,p,w);Ji(a,l,m,e,g,V,p,h.i());Ei(a,l);Gi(a,l);zi(this.u,e*a.size[0]/2,e*a.size[1]/2,e*r/f.resolution,e*r/f.resolution,f.rotation,(Wf[0]-B[0])/r,(B[1]-Wf[1])/r);this.i=null;return!0}; -Wi.prototype.Kd=function(a,c,d,e){if(this.A&&(this.i||(this.i=qd(),sd(this.u,this.i)),a=Nk(a,this.i),0<this.A.getImageData(a[0],a[1],1,1).data[3]))return d.call(e,this.a)};function Xi(a){Kk.call(this,a);this.f=!1;this.s=-1;this.l=NaN;this.j=vd();this.c=this.A=null;this.i=th()}x(Xi,Kk); -Xi.prototype.H=function(a,c,d){var e=a.extent,f=a.pixelRatio,g=c.Xb?a.skippedFeatureUids:{},h=a.viewState,l=h.projection,h=h.rotation,m=l.F(),n=this.a.ha(),p=Mk(this,a,0);Lk(this,"precompose",d,a,p);var q=this.c;if(q&&!q.Ja()){var r;Uc(this.a,"render")?(this.i.canvas.width=d.canvas.width,this.i.canvas.height=d.canvas.height,r=this.i):r=d;var t=r.globalAlpha;r.globalAlpha=c.opacity;kl(q,r,f,p,h,g);if(n.D&&l.a&&!Ed(m,e)){c=e[0];l=Pd(m);for(n=0;c<m[0];)--n,p=l*n,p=Mk(this,a,p),kl(q,r,f,p,h,g),c+=l;n= -0;for(c=e[2];c>m[2];)++n,p=l*n,p=Mk(this,a,p),kl(q,r,f,p,h,g),c-=l;p=Mk(this,a,0)}r!=d&&(Lk(this,"render",r,a,p),d.drawImage(r.canvas,0,0));r.globalAlpha=t}Lk(this,"postcompose",d,a,p)};Xi.prototype.ec=function(a,c,d,e){if(this.c){var f=c.viewState.resolution,g=c.viewState.rotation,h=this.a,l=c.layerStates[na(h)],m={};return gl(this.c,a,f,g,l.Xb?c.skippedFeatureUids:{},function(a){var c=na(a).toString();if(!(c in m))return m[c]=!0,d.call(e,a,h)})}};Xi.prototype.u=function(){Di(this)}; -Xi.prototype.Ld=function(a){function c(a){var c,e=a.Yb();e?c=e.call(a,n):(e=d.i)&&(c=e(a,n));if(c){if(c){e=!1;if(fa(c))for(var f=0,g=c.length;f<g;++f)e=pl(r,a,c[f],nl(n,p),this.u,this)||e;else e=pl(r,a,c,nl(n,p),this.u,this)||e;a=e}else a=!1;this.f=this.f||a}}var d=this.a,e=d.ha();Fi(a.attributions,e.u);Gi(a,e);var f=a.viewHints[0],g=a.viewHints[1],h=d.G,l=d.B;if(!this.f&&!h&&f||!l&&g)return!0;var m=a.extent,l=a.viewState,f=l.projection,n=l.resolution,p=a.pixelRatio,g=d.g,q=d.l,h=d.get("renderOrder"); -void 0===h&&(h=ml);m=zd(m,q*n);q=l.projection.F();e.D&&l.projection.a&&!Ed(q,a.extent)&&(a=Math.max(Pd(m)/2,Pd(q)),m[0]=q[0]-a,m[2]=q[2]+a);if(!this.f&&this.l==n&&this.s==g&&this.A==h&&Ed(this.j,m))return!0;kc(this.c);this.c=null;this.f=!1;var r=new el(.5*n/p,m,n,d.l);qn(e,m,n,f);if(h){var t=[];e.qb(m,function(a){t.push(a)},this);jb(t,h);t.forEach(c,this)}else e.qb(m,c,this);fl(r);this.l=n;this.s=g;this.A=h;this.j=m;this.c=r;return!0};function tn(a,c){var d=/\{z\}/g,e=/\{x\}/g,f=/\{y\}/g,g=/\{-y\}/g;return function(h){if(h)return a.replace(d,h[0].toString()).replace(e,h[1].toString()).replace(f,function(){return(-h[2]-1).toString()}).replace(g,function(){return(qf(c.a?c.a[h[0]]:null)+h[2]).toString()})}}function un(a,c){for(var d=a.length,e=Array(d),f=0;f<d;++f)e[f]=tn(a[f],c);return vn(e)}function vn(a){return 1===a.length?a[0]:function(c,d,e){if(c)return a[ed((c[1]<<c[0])+c[2],a.length)](c,d,e)}}function wn(){} -function xn(a){var c=[],d=/\{(\d)-(\d)\}/.exec(a)||/\{([a-z])-([a-z])\}/.exec(a);if(d){var e=d[2].charCodeAt(0),f;for(f=d[1].charCodeAt(0);f<=e;++f)c.push(a.replace(d[0],String.fromCharCode(f)))}else c.push(a);return c};function yn(a){Dg.call(this,{attributions:a.attributions,je:a.je,extent:a.extent,logo:a.logo,opaque:a.opaque,projection:a.projection,state:a.state?a.state:void 0,tileGrid:a.tileGrid,tilePixelRatio:a.tilePixelRatio,wrapX:a.wrapX});this.tileLoadFunction=a.tileLoadFunction;this.tileUrlFunction=a.tileUrlFunction?a.tileUrlFunction:wn;this.urls=null;a.urls?a.tileUrlFunction?this.urls=a.urls:this.Vc(a.urls):a.url&&this.Kc(a.url);a.tileUrlFunction&&this.Hb(a.tileUrlFunction)}x(yn,Dg);k=yn.prototype; -k.wd=function(){return this.tileLoadFunction};k.xd=function(){return this.tileUrlFunction};k.yd=function(){return this.urls};k.aj=function(a){a=a.target;switch(a.state){case 1:this.b(new Fg("tileloadstart",a));break;case 2:this.b(new Fg("tileloadend",a));break;case 3:this.b(new Fg("tileloaderror",a))}};k.Xd=function(a){this.a.clear();this.tileLoadFunction=a;this.v()};k.Hb=function(a){this.a.clear();this.tileUrlFunction=a;this.v()};k.Kc=function(a){this.Hb(un(xn(a),this.tileGrid));this.urls=[a]}; -k.Vc=function(a){this.Hb(un(a,this.tileGrid));this.urls=a};k.Df=function(a,c,d){a=this.rb(a,c,d);this.a.g.hasOwnProperty(a)&&this.a.get(a)};function zn(a,c){Ri.call(this,0,c);this.f=th();this.b=this.f.canvas;this.b.style.width="100%";this.b.style.height="100%";this.b.className="ol-unselectable";a.insertBefore(this.b,a.childNodes[0]||null);this.g=!0;this.l=qd()}x(zn,Ri); -function An(a,c,d){var e=a.i,f=a.f;if(Uc(e,c)){var g=d.extent,h=d.pixelRatio,l=d.viewState.rotation,m=d.pixelRatio,n=d.viewState,p=n.resolution;a=zi(a.l,a.b.width/2,a.b.height/2,m/p,-m/p,-n.rotation,-n.center[0],-n.center[1]);g=new xk(f,h,g,a,l);e.b(new vi(c,e,g,d,f,null));Jk(g)}}zn.prototype.N=function(){return"canvas"}; -zn.prototype.j=function(a){if(a){var c=this.f,d=a.size[0]*a.pixelRatio,e=a.size[1]*a.pixelRatio;this.b.width!=d||this.b.height!=e?(this.b.width=d,this.b.height=e):c.clearRect(0,0,this.b.width,this.b.height);d=a.viewState;e=a.coordinateToPixelMatrix;zi(e,a.size[0]/2,a.size[1]/2,1/d.resolution,-1/d.resolution,-d.rotation,-d.center[0],-d.center[1]);sd(e,a.pixelToCoordinateMatrix);An(this,"precompose",a);d=a.layerStatesArray;lb(d);var e=a.viewState.resolution,f,g,h,l;f=0;for(g=d.length;f<g;++f)l=d[f], -h=l.layer,h=Ui(this,h),l.visible&&e>=l.minResolution&&e<l.maxResolution&&"ready"==l.D&&h.Ld(a,l)&&h.H(a,l,c);An(this,"postcompose",a);this.g||(cg(this.b,!0),this.g=!0);for(var m in this.a)if(!(m in a.layerStates)){a.postRenderFunctions.push(sa(this.s,this));break}a.postRenderFunctions.push(Si)}else this.g&&(cg(this.b,!1),this.g=!1)};var Bn=["canvas","webgl","dom"]; -function P(a){Yc.call(this);var c=Cn(a);this.ob=void 0!==a.loadTilesWhileAnimating?a.loadTilesWhileAnimating:!1;this.Ib=void 0!==a.loadTilesWhileInteracting?a.loadTilesWhileInteracting:!1;this.Yc=void 0!==a.pixelRatio?a.pixelRatio:uh;this.Xc=c.logos;this.u=new Pg(this.Xj,void 0,this);jc(this,this.u);this.bb=qd();this.Zc=qd();this.cb=0;this.c=null;this.qa=vd();this.D=this.J=null;this.a=Kf("DIV","ol-viewport");this.a.style.position="relative";this.a.style.overflow="hidden";this.a.style.width="100%"; -this.a.style.height="100%";this.a.style.msTouchAction="none";this.a.style.touchAction="none";zh&&Sf(this.a,"ol-touch");this.B=Kf("DIV","ol-overlaycontainer");this.a.appendChild(this.B);this.G=Kf("DIV","ol-overlaycontainer-stopevent");y(this.G,["click","dblclick","mousedown","touchstart","MSPointerDown",oi,Rb?"DOMMouseScroll":"mousewheel"],mc);this.a.appendChild(this.G);a=new gi(this);y(a,Eb(ri),this.Ee,!1,this);jc(this,a);this.ja=c.keyboardEventTarget;this.H=new eh;y(this.H,"key",this.De,!1,this); -jc(this,this.H);a=new mh(this.a);y(a,"mousewheel",this.De,!1,this);jc(this,a);this.i=c.controls;this.f=c.interactions;this.j=c.overlays;this.aa={};this.l=new c.Zj(this.a,this);jc(this,this.l);this.Va=new $g;jc(this,this.Va);this.Y=this.s=null;this.I=[];this.na=[];this.Ga=new $i(sa(this.Yg,this),sa(this.yh,this));this.ea={};y(this,$c("layergroup"),this.hh,!1,this);y(this,$c("view"),this.zh,!1,this);y(this,$c("size"),this.vh,!1,this);y(this,$c("target"),this.xh,!1,this);this.K(c.values);this.i.forEach(function(a){a.setMap(this)}, -this);y(this.i,"add",function(a){a.element.setMap(this)},!1,this);y(this.i,"remove",function(a){a.element.setMap(null)},!1,this);this.f.forEach(function(a){a.setMap(this)},this);y(this.f,"add",function(a){a.element.setMap(this)},!1,this);y(this.f,"remove",function(a){a.element.setMap(null)},!1,this);this.j.forEach(this.ie,this);y(this.j,"add",function(a){this.ie(a.element)},!1,this);y(this.j,"remove",function(a){var c=a.element.Ba();void 0!==c&&delete this.aa[c.toString()];a.element.setMap(null)}, -!1,this)}x(P,Yc);k=P.prototype;k.Qf=function(a){this.i.push(a)};k.Rf=function(a){this.f.push(a)};k.Sf=function(a){this.sb().Ab().push(a)};k.Tf=function(a){this.j.push(a)};k.ie=function(a){var c=a.Ba();void 0!==c&&(this.aa[c.toString()]=a);a.setMap(this)};k.wa=function(a){this.render();Array.prototype.push.apply(this.I,arguments)};k.Z=function(){Of(this.a);P.fa.Z.call(this)};k.nd=function(a,c,d,e,f){if(this.c)return a=this.ra(a),Ti(this.l,a,this.c,c,void 0!==d?d:null,void 0!==e?e:Xd,void 0!==f?f:null)}; -k.fi=function(a,c,d,e,f){if(this.c){a:{var g=this.l,h=this.c;d=void 0!==d?d:null;e=void 0!==e?e:Xd;f=void 0!==f?f:null;var l,m=h.viewState.resolution,n=h.layerStatesArray,p;for(p=n.length-1;0<=p;--p){l=n[p];var q=l.layer;if(l.visible&&m>=l.minResolution&&m<l.maxResolution&&e.call(f,q)&&(l=Ui(g,q).Kd(a,h,c,d))){a=l;break a}}a=void 0}return a}};k.Bh=function(a,c,d){if(!this.c)return!1;a=this.ra(a);var e=this.l;return void 0!==Ti(e,a,this.c,Xd,e,void 0!==c?c:Xd,void 0!==d?d:null)};k.sg=function(a){return this.ra(this.sc(a))}; -k.sc=function(a){var c;c=this.a;a=$f(a);c=$f(c);c=new Bf(a.x-c.x,a.y-c.y);return[c.x,c.y]};k.Le=function(){return this.get("target")};k.Ub=function(){var a=this.Le();return void 0!==a?Gf(a):null};k.ra=function(a){var c=this.c;return c?(a=a.slice(),Ai(c.pixelToCoordinateMatrix,a,a)):null};k.qg=function(){return this.i};k.Pg=function(){return this.j};k.Og=function(a){a=this.aa[a.toString()];return void 0!==a?a:null};k.Dg=function(){return this.f};k.sb=function(){return this.get("layergroup")}; -k.gi=function(){return this.sb().Ab()};k.xa=function(a){var c=this.c;return c?(a=a.slice(0,2),Ai(c.coordinateToPixelMatrix,a,a)):null};k.hb=function(){return this.get("size")};k.ga=function(){return this.get("view")};k.ah=function(){return this.a};k.Yg=function(a,c,d,e){var f=this.c;if(!(f&&c in f.wantedTiles&&f.wantedTiles[c][mf(a.a)]))return Infinity;a=d[0]-f.focus[0];d=d[1]-f.focus[1];return 65536*Math.log(e)+Math.sqrt(a*a+d*d)/e};k.De=function(a,c){var d=new ei(c||a.type,this,a);this.Ee(d)}; -k.Ee=function(a){if(this.c){this.Y=a.coordinate;a.frameState=this.c;var c=this.f.a,d;if(!1!==this.b(a))for(d=c.length-1;0<=d;d--){var e=c[d];if(e.l()&&!e.handleEvent(a))break}}}; -k.uh=function(){var a=this.c,c=this.Ga;if(!c.Ja()){var d=16,e=d,f=0;a&&(f=a.viewHints,f[0]&&(d=this.ob?8:0,e=2),f[1]&&(d=this.Ib?8:0,e=2),f=Db(a.wantedTiles));d*=f;e*=f;if(c.c<d){var f=c.j,g=c.b,h=c.a,l=0,m=g.length,n,p,q;for(p=0;p<m;++p)n=g[p],q=f(n),Infinity==q?delete c.g[c.f(n)]:(h[l]=q,g[l++]=n);g.length=l;h.length=l;for(f=(c.b.length>>1)-1;0<=f;f--)Zi(c,f);for(f=0;c.c<d&&f<e&&0<c.Rb();)g=c,l=g.b,m=g.a,h=l[0],1==l.length?(l.length=0,m.length=0):(l[0]=l.pop(),m[0]=m.pop(),Zi(g,0)),l=g.f(h),delete g.g[l], -g=h[0],0===g.state&&(y(g,"change",c.i,!1,c),g.load(),++c.c,++f)}}c=this.na;e=0;for(d=c.length;e<d;++e)c[e](this,a);c.length=0};k.vh=function(){this.render()};k.xh=function(){var a=this.Ub();lh(this.H);a?(a.appendChild(this.a),fh(this.H,this.ja?this.ja:a),this.s||(this.s=y(this.Va,"resize",this.Zd,!1,this))):(Of(this.a),this.s&&(Nc(this.s),this.s=null));this.Zd()};k.yh=function(){this.render()};k.Ah=function(){this.render()}; -k.zh=function(){this.J&&(Nc(this.J),this.J=null);var a=this.ga();a&&(this.J=y(a,"propertychange",this.Ah,!1,this));this.render()};k.ih=function(){this.render()};k.jh=function(){this.render()};k.hh=function(){this.D&&(this.D.forEach(Nc),this.D=null);var a=this.sb();a&&(this.D=[y(a,"propertychange",this.jh,!1,this),y(a,"change",this.ih,!1,this)]);this.render()};k.Yj=function(){var a=this.u;Qg(a);a.f()};k.render=function(){null!=this.u.b||this.u.start()};k.Sj=function(a){return this.i.remove(a)}; -k.Tj=function(a){return this.f.remove(a)};k.Vj=function(a){return this.sb().Ab().remove(a)};k.Wj=function(a){return this.j.remove(a)}; -k.Xj=function(a){var c,d,e,f=this.hb(),g=this.ga(),h=null;if(c=void 0!==f&&0<f[0]&&0<f[1]&&g)c=!!g.za()&&void 0!==g.$();if(c){var h=g.a.slice(),l=this.sb().qd(),m={};c=0;for(d=l.length;c<d;++c)m[na(l[c].layer)]=l[c];e=bf(g);h={animate:!1,attributions:{},coordinateToPixelMatrix:this.bb,extent:null,focus:this.Y?this.Y:e.center,index:this.cb++,layerStates:m,layerStatesArray:l,logos:Kb(this.Xc),pixelRatio:this.Yc,pixelToCoordinateMatrix:this.Zc,postRenderFunctions:[],size:f,skippedFeatureUids:this.ea, -tileQueue:this.Ga,time:a,usedTiles:{},viewState:e,viewHints:h,wantedTiles:{}}}if(h){a=this.I;c=f=0;for(d=a.length;c<d;++c)g=a[c],g(this,h)&&(a[f++]=g);a.length=f;h.extent=Sd(e.center,e.resolution,e.rotation,h.size)}this.c=h;this.l.j(h);h&&(h.animate&&this.render(),Array.prototype.push.apply(this.na,h.postRenderFunctions),0!==this.I.length||h.viewHints[0]||h.viewHints[1]||Jd(h.extent,this.qa)||(this.b(new hg("moveend",this,h)),Ad(h.extent,this.qa)));this.b(new hg("postrender",this,h));c=e=this.uh; -this&&(c=sa(e,this));!la(ba.setImmediate)||ba.Window&&ba.Window.prototype&&ba.Window.prototype.setImmediate==ba.setImmediate?(Tg||(Tg=Ug()),Tg(c)):ba.setImmediate(c)};k.fk=function(a){this.C("layergroup",a)};k.Vd=function(a){this.C("size",a)};k.hi=function(a){this.C("target",a)};k.mk=function(a){this.C("view",a)};k.zf=function(a){a=na(a).toString();this.ea[a]=!0;this.render()}; -k.Zd=function(){var a=this.Ub();if(a){var c=Ff(a),d=Pb&&a.currentStyle,e;if(e=d)Df(c),e=!0;if(e&&"auto"!=d.width&&"auto"!=d.height&&!d.boxSizing)c=dg(a,d.width,"width","pixelWidth"),a=dg(a,d.height,"height","pixelHeight"),a=new Cf(c,a);else{d=new Cf(a.offsetWidth,a.offsetHeight);if(Pb){c=eg(a,"paddingLeft");e=eg(a,"paddingRight");var f=eg(a,"paddingTop"),g=eg(a,"paddingBottom"),c=new Uf(f,e,g,c)}else c=Vf(a,"paddingLeft"),e=Vf(a,"paddingRight"),f=Vf(a,"paddingTop"),g=Vf(a,"paddingBottom"),c=new Uf(parseFloat(f), -parseFloat(e),parseFloat(g),parseFloat(c));!Pb||9<=cc?(e=Vf(a,"borderLeftWidth"),f=Vf(a,"borderRightWidth"),g=Vf(a,"borderTopWidth"),a=Vf(a,"borderBottomWidth"),a=new Uf(parseFloat(g),parseFloat(f),parseFloat(a),parseFloat(e))):(e=gg(a,"borderLeft"),f=gg(a,"borderRight"),g=gg(a,"borderTop"),a=gg(a,"borderBottom"),a=new Uf(g,f,a,e));a=new Cf(d.width-a.left-c.left-c.right-a.right,d.height-a.top-c.top-c.bottom-a.bottom)}this.Vd([a.width,a.height])}else this.Vd(void 0)}; -k.Af=function(a){a=na(a).toString();delete this.ea[a];this.render()}; -function Cn(a){var c=null;void 0!==a.keyboardEventTarget&&(c=ha(a.keyboardEventTarget)?document.getElementById(a.keyboardEventTarget):a.keyboardEventTarget);var d={},e={};if(void 0===a.logo||"boolean"==typeof a.logo&&a.logo)e["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszWWMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvYasvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvXH1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1VkbMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLPVcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqTacrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaarldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+HizeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDnBAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSFhYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJREFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxCBrb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7ahgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCnB3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDgq82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC"]="http://openlayers.org/"; -else{var f=a.logo;ha(f)?e[f]="":ma(f)&&(e[f.src]=f.href)}f=a.layers instanceof K?a.layers:new K({layers:a.layers});d.layergroup=f;d.target=a.target;d.view=void 0!==a.view?a.view:new D;var f=Ri,g;void 0!==a.renderer?fa(a.renderer)?g=a.renderer:ha(a.renderer)&&(g=[a.renderer]):g=Bn;var h,l;h=0;for(l=g.length;h<l;++h)if("canvas"==g[h]&&wh){f=zn;break}var m;void 0!==a.controls?m=fa(a.controls)?new F(a.controls.slice()):a.controls:m=Lg();var n;void 0!==a.interactions?n=fa(a.interactions)?new F(a.interactions.slice()): -a.interactions:n=Wj();a=void 0!==a.overlays?fa(a.overlays)?new F(a.overlays.slice()):a.overlays:new F;return{controls:m,interactions:n,keyboardEventTarget:c,logos:e,overlays:a,Zj:f,values:d}}ge(bk);ge(gk);gk.forEach(function(a){bk.forEach(function(c){he(a,c,ck);he(c,a,dk)})});function Dn(a){Yc.call(this);this.s=a.id;this.l=void 0!==a.insertFirst?a.insertFirst:!0;this.u=void 0!==a.stopEvent?a.stopEvent:!0;this.c=Kf("DIV",{"class":"ol-overlay-container"});this.c.style.position="absolute";this.autoPan=void 0!==a.autoPan?a.autoPan:!1;this.i=void 0!==a.autoPanAnimation?a.autoPanAnimation:{};this.j=void 0!==a.autoPanMargin?a.autoPanMargin:20;this.a={nc:"",Dc:"",Tc:"",Wc:"",visible:!0};this.f=null;y(this,$c("element"),this.fh,!1,this);y(this,$c("map"),this.nh,!1,this);y(this, -$c("offset"),this.qh,!1,this);y(this,$c("position"),this.sh,!1,this);y(this,$c("positioning"),this.th,!1,this);void 0!==a.element&&this.pf(a.element);this.sf(void 0!==a.offset?a.offset:[0,0]);this.vf(void 0!==a.positioning?a.positioning:"top-left");void 0!==a.position&&this.Ne(a.position)}x(Dn,Yc);k=Dn.prototype;k.Gd=function(){return this.get("element")};k.Ba=function(){return this.s};k.Fc=function(){return this.get("map")};k.ze=function(){return this.get("offset")};k.Me=function(){return this.get("position")}; -k.Be=function(){return this.get("positioning")};k.fh=function(){for(var a=this.c,c;c=a.firstChild;)a.removeChild(c);(a=this.Gd())&&Nf(this.c,a)};k.nh=function(){this.f&&(Of(this.c),Nc(this.f),this.f=null);var a=this.Fc();a&&(this.f=y(a,"postrender",this.render,!1,this),En(this),a=this.u?a.G:a.B,this.l?a.insertBefore(this.c,a.childNodes[0]||null):Nf(a,this.c))};k.render=function(){En(this)};k.qh=function(){En(this)}; -k.sh=function(){En(this);if(void 0!==this.get("position")&&this.autoPan){var a=this.Fc();if(void 0!==a&&a.Ub()){var c=Fn(a.Ub(),a.hb()),d=this.Gd(),e=d.offsetWidth,f=d.currentStyle||window.getComputedStyle(d),e=e+(parseInt(f.marginLeft,10)+parseInt(f.marginRight,10)),f=d.offsetHeight,g=d.currentStyle||window.getComputedStyle(d),f=f+(parseInt(g.marginTop,10)+parseInt(g.marginBottom,10)),h=Fn(d,[e,f]),d=this.j;Ed(c,h)||(e=h[0]-c[0],f=c[2]-h[2],g=h[1]-c[1],h=c[3]-h[3],c=[0,0],0>e?c[0]=e-d:0>f&&(c[0]= -Math.abs(f)+d),0>g?c[1]=g-d:0>h&&(c[1]=Math.abs(h)+d),0===c[0]&&0===c[1])||(d=a.ga().za(),e=a.xa(d),c=[e[0]+c[0],e[1]+c[1]],this.i&&(this.i.source=d,a.wa(hf(this.i))),a.ga().Ea(a.ra(c)))}}};k.th=function(){En(this)};k.pf=function(a){this.C("element",a)};k.setMap=function(a){this.C("map",a)};k.sf=function(a){this.C("offset",a)};k.Ne=function(a){this.C("position",a)}; -function Fn(a,c){var d=Ff(a),e=new Bf(0,0),f;f=d?Ff(d):document;var g;(g=!Pb||9<=cc)||(Df(f),g=!0);a!=(g?f.documentElement:f.body)&&(f=Zf(a),g=Df(d).b,d=g.scrollingElement?g.scrollingElement:Sb?g.body||g.documentElement:g.documentElement,g=g.parentWindow||g.defaultView,d=Pb&&ac("10")&&g.pageYOffset!=d.scrollTop?new Bf(d.scrollLeft,d.scrollTop):new Bf(g.pageXOffset||d.scrollLeft,g.pageYOffset||d.scrollTop),e.x=f.left+d.x,e.y=f.top+d.y);return[e.x,e.y,e.x+c[0],e.y+c[1]]} -k.vf=function(a){this.C("positioning",a)};function Gn(a,c){a.a.visible!==c&&(cg(a.c,c),a.a.visible=c)} -function En(a){var c=a.Fc(),d=a.Me();if(void 0!==c&&c.c&&void 0!==d){var d=c.xa(d),e=c.hb(),c=a.c.style,f=a.ze(),g=a.Be(),h=f[0],f=f[1];if("bottom-right"==g||"center-right"==g||"top-right"==g)""!==a.a.Dc&&(a.a.Dc=c.left=""),h=Math.round(e[0]-d[0]-h)+"px",a.a.Tc!=h&&(a.a.Tc=c.right=h);else{""!==a.a.Tc&&(a.a.Tc=c.right="");if("bottom-center"==g||"center-center"==g||"top-center"==g)h-=ag(a.c).width/2;h=Math.round(d[0]+h)+"px";a.a.Dc!=h&&(a.a.Dc=c.left=h)}if("bottom-left"==g||"bottom-center"==g||"bottom-right"== -g)""!==a.a.Wc&&(a.a.Wc=c.top=""),d=Math.round(e[1]-d[1]-f)+"px",a.a.nc!=d&&(a.a.nc=c.bottom=d);else{""!==a.a.nc&&(a.a.nc=c.bottom="");if("center-left"==g||"center-center"==g||"center-right"==g)f-=ag(a.c).height/2;d=Math.round(d[1]+f)+"px";a.a.Wc!=d&&(a.a.Wc=c.top=d)}Gn(a,!0)}else Gn(a,!1)};function Hn(a){a=a?a:{};var c=a.className?a.className:"ol-scale-line";this.l=Kf("DIV",c+"-inner");this.i=Kf("DIV",c+" ol-unselectable",this.l);this.u=null;this.s=void 0!==a.minWidth?a.minWidth:64;this.c=!1;this.B=void 0;this.D="";this.f=null;ig.call(this,{element:this.i,render:a.render?a.render:In,target:a.target});y(this,$c("units"),this.aa,!1,this);this.Y(a.units||"metric")}x(Hn,ig);var Jn=[1,2,5];Hn.prototype.G=function(){return this.get("units")}; -function In(a){(a=a.frameState)?this.u=a.viewState:this.u=null;Kn(this)}Hn.prototype.aa=function(){Kn(this)};Hn.prototype.Y=function(a){this.C("units",a)}; -function Kn(a){var c=a.u;if(c){var d=c.center,e=c.projection,c=e.getPointResolution(c.resolution,d),f=e.g,g=a.G();"degrees"!=f||"metric"!=g&&"imperial"!=g&&"us"!=g&&"nautical"!=g?"degrees"!=f&&"degrees"==g?(a.f||(a.f=je(e,fe("EPSG:4326"))),d=Math.cos(Sa(a.f(d)[1])),e=be.radius,e/=ce[f],c*=180/(Math.PI*d*e)):a.f=null:(a.f=null,d=Math.cos(Sa(d[1])),c*=Math.PI*d*be.radius/180);d=a.s*c;f="";"degrees"==g?d<1/60?(f="\u2033",c*=3600):1>d?(f="\u2032",c*=60):f="\u00b0":"imperial"==g?.9144>d?(f="in",c/=.0254): -1609.344>d?(f="ft",c/=.3048):(f="mi",c/=1609.344):"nautical"==g?(c/=1852,f="nm"):"metric"==g?1>d?(f="mm",c*=1E3):1E3>d?f="m":(f="km",c/=1E3):"us"==g&&(.9144>d?(f="in",c*=39.37):1609.344>d?(f="ft",c/=.30480061):(f="mi",c/=1609.3472));for(d=3*Math.floor(Math.log(a.s*c)/Math.log(10));;){e=Jn[d%3]*Math.pow(10,Math.floor(d/3));g=Math.round(e/c);if(isNaN(g)){cg(a.i,!1);a.c=!1;return}if(g>=a.s)break;++d}c=e+" "+f;a.D!=c&&(a.l.innerHTML=c,a.D=c);a.B!=g&&(a.l.style.width=g+"px",a.B=g);a.c||(cg(a.i,!0),a.c= -!0)}else a.c&&(cg(a.i,!1),a.c=!1)};function Ln(a){a=a?a:{};this.c=a.extent?a.extent:null;var c=a.className?a.className:"ol-zoom-extent",d=Kf("BUTTON",{type:"button",title:a.tipLabel?a.tipLabel:"Fit to extent"},a.label?a.label:"E");y(d,"click",this.f,!1,this);c=Kf("DIV",c+" ol-unselectable ol-control",d);ig.call(this,{element:c,target:a.target})}x(Ln,ig);Ln.prototype.f=function(a){a.preventDefault();var c=this.a;a=c.ga();var d=this.c?this.c:a.j.F(),c=c.hb();a.oe(d,c)};function Mn(a){Yc.call(this);a=a?a:{};this.a=null;y(this,$c("tracking"),this.Wh,!1,this);this.Ed(void 0!==a.tracking?a.tracking:!1)}x(Mn,Yc);k=Mn.prototype;k.Z=function(){this.Ed(!1);Mn.fa.Z.call(this)}; -k.Dj=function(a){a=a.b;if(null!==a.alpha){var c=Sa(a.alpha);this.C("alpha",c);"boolean"==typeof a.absolute&&a.absolute?this.C("heading",c):ka(a.webkitCompassHeading)&&-1!=a.webkitCompassAccuracy&&this.C("heading",Sa(a.webkitCompassHeading))}null!==a.beta&&this.C("beta",Sa(a.beta));null!==a.gamma&&this.C("gamma",Sa(a.gamma));this.v()};k.kg=function(){return this.get("alpha")};k.ng=function(){return this.get("beta")};k.yg=function(){return this.get("gamma")};k.Vh=function(){return this.get("heading")}; -k.He=function(){return this.get("tracking")};k.Wh=function(){if(xh){var a=this.He();a&&!this.a?this.a=y(ba,"deviceorientation",this.Dj,!1,this):!a&&this.a&&(Nc(this.a),this.a=null)}};k.Ed=function(a){this.C("tracking",a)};function Nn(){this.defaultDataProjection=null}function On(a,c,d){var e;d&&(e={dataProjection:d.dataProjection?d.dataProjection:a.hc(c),featureProjection:d.featureProjection});return Pn(a,e)}function Pn(a,c){var d;c&&(d={featureProjection:c.featureProjection,dataProjection:c.dataProjection?c.dataProjection:a.defaultDataProjection,rightHanded:c.rightHanded});return d} -function Qn(a,c,d){var e=d?fe(d.featureProjection):null;d=d?fe(d.dataProjection):null;return e&&d&&!pe(e,d)?a instanceof ue?(c?a.clone():a).Fa(c?e:d,c?d:e):te(c?a.slice():a,c?e:d,c?d:e):a};function Rn(){this.defaultDataProjection=null}x(Rn,Nn);function Sn(a){return ma(a)?a:ha(a)?(a=Nl(a))?a:null:null}k=Rn.prototype;k.N=function(){return"json"};k.Od=function(a,c){return Tn(this,Sn(a),On(this,a,c))};k.Sc=function(a,c){var d;var e=Sn(a);d=On(this,a,c);if("Feature"==e.type)d=[Tn(this,e,d)];else if("FeatureCollection"==e.type){var f=[],e=e.features,g,h;g=0;for(h=e.length;g<h;++g)f.push(Tn(this,e[g],d));d=f}else d=[];return d};k.kf=function(a,c){var d=Sn(a),e=On(this,a,c);return Un(d,e)}; -k.hc=function(a){return(a=Sn(a).crs)?"name"==a.type?fe(a.properties.name):"EPSG"==a.type?fe("EPSG:"+a.properties.code):null:this.defaultDataProjection};k.Ff=function(a,c){return Ol(this.b(a,c))};k.$d=function(a,c){return Ol(this.g(a,c))};k.Gf=function(a,c){return Ol(this.c(a,c))};function Vn(a,c,d,e,f){var g=NaN,h=NaN,l=(d-c)/e;if(0!==l)if(1==l)g=a[c],h=a[c+1];else if(2==l)g=.5*a[c]+.5*a[c+e],h=.5*a[c+1]+.5*a[c+e+1];else{var h=a[c],l=a[c+1],m=0,g=[0],n;for(n=c+e;n<d;n+=e){var p=a[n],q=a[n+1],m=m+Math.sqrt((p-h)*(p-h)+(q-l)*(q-l));g.push(m);h=p;l=q}d=.5*m;for(var r,h=kb,l=0,m=g.length;l<m;)n=l+m>>1,p=h(d,g[n]),0<p?l=n+1:(m=n,r=!p);r=r?l:~l;0>r?(d=(d-g[-r-2])/(g[-r-1]-g[-r-2]),c+=(-r-2)*e,g=fd(a[c],a[c+e],d),h=fd(a[c+1],a[c+e+1],d)):(g=a[c+r*e],h=a[c+r*e+1])}return f?(f[0]= -g,f[1]=h,f):[g,h]}function Wn(a,c,d,e,f,g){if(d==c)return null;if(f<a[c+e-1])return g?(d=a.slice(c,c+e),d[e-1]=f,d):null;if(a[d-1]<f)return g?(d=a.slice(d-e,d),d[e-1]=f,d):null;if(f==a[c+e-1])return a.slice(c,c+e);c/=e;for(d/=e;c<d;)g=c+d>>1,f<a[(g+1)*e-1]?d=g:c=g+1;d=a[c*e-1];if(f==d)return a.slice((c-1)*e,(c-1)*e+e);g=(f-d)/(a[(c+1)*e-1]-d);d=[];var h;for(h=0;h<e-1;++h)d.push(fd(a[(c-1)*e+h],a[c*e+h],g));d.push(f);return d} -function Xn(a,c,d,e,f,g){var h=0;if(g)return Wn(a,h,c[c.length-1],d,e,f);if(e<a[d-1])return f?(a=a.slice(0,d),a[d-1]=e,a):null;if(a[a.length-1]<e)return f?(a=a.slice(a.length-d),a[d-1]=e,a):null;f=0;for(g=c.length;f<g;++f){var l=c[f];if(h!=l){if(e<a[h+d-1])break;if(e<=a[l-1])return Wn(a,h,l,d,e,!1);h=l}}return null};function Q(a,c){z.call(this);this.f=null;this.D=this.G=this.l=-1;this.da(a,c)}x(Q,z);k=Q.prototype;k.Uf=function(a){this.o?eb(this.o,a):this.o=a.slice();this.v()};k.clone=function(){var a=new Q(null);Yn(a,this.c,this.o.slice());return a};k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;this.D!=this.g&&(this.G=Math.sqrt(Ce(this.o,0,this.o.length,this.a,0)),this.D=this.g);return Ee(this.o,0,this.o.length,this.a,this.G,!1,a,c,d,e)};k.hg=function(a,c){return Te(this.o,0,this.o.length,this.a,a,c)}; -k.li=function(a,c){return"XYM"!=this.c&&"XYZM"!=this.c?null:Wn(this.o,0,this.o.length,this.a,a,void 0!==c?c:!1)};k.R=function(){return Je(this.o,0,this.o.length,this.a)};k.mi=function(){var a=this.o,c=this.a,d=a[0],e=a[1],f=0,g;for(g=0+c;g<this.o.length;g+=c)var h=a[g],l=a[g+1],f=f+Math.sqrt((h-d)*(h-d)+(l-e)*(l-e)),d=h,e=l;return f};function Fk(a){a.l!=a.g&&(a.f=Vn(a.o,0,a.o.length,a.a,a.f),a.l=a.g);return a.f} -k.wb=function(a){var c=[];c.length=Le(this.o,0,this.o.length,this.a,a,c,0);a=new Q(null);Yn(a,"XY",c);return a};k.N=function(){return"LineString"};k.pa=function(a){return Ue(this.o,0,this.o.length,this.a,a)};k.da=function(a,c){a?(ye(this,c,a,1),this.o||(this.o=[]),this.o.length=He(this.o,0,a,this.a),this.v()):Yn(this,"XY",null)};function Yn(a,c,d){xe(a,c,d);a.v()};function R(a,c){z.call(this);this.f=[];this.l=this.D=-1;this.da(a,c)}x(R,z);k=R.prototype;k.Vf=function(a){this.o?eb(this.o,a.ba().slice()):this.o=a.ba().slice();this.f.push(this.o.length);this.v()};k.clone=function(){var a=new R(null);Zn(a,this.c,this.o.slice(),this.f.slice());return a};k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;this.l!=this.g&&(this.D=Math.sqrt(De(this.o,0,this.f,this.a,0)),this.l=this.g);return Fe(this.o,0,this.f,this.a,this.D,!1,a,c,d,e)}; -k.oi=function(a,c,d){return"XYM"!=this.c&&"XYZM"!=this.c||0===this.o.length?null:Xn(this.o,this.f,this.a,a,void 0!==c?c:!1,void 0!==d?d:!1)};k.R=function(){return Ke(this.o,0,this.f,this.a)};k.Na=function(){return this.f};k.Ig=function(a){if(0>a||this.f.length<=a)return null;var c=new Q(null);Yn(c,this.c,this.o.slice(0===a?0:this.f[a-1],this.f[a]));return c}; -k.ue=function(){var a=this.o,c=this.f,d=this.c,e=[],f=0,g,h;g=0;for(h=c.length;g<h;++g){var l=c[g],m=new Q(null);Yn(m,d,a.slice(f,l));e.push(m);f=l}return e};function Gk(a){var c=[],d=a.o,e=0,f=a.f;a=a.a;var g,h;g=0;for(h=f.length;g<h;++g){var l=f[g],e=Vn(d,e,l,a);eb(c,e);e=l}return c}k.wb=function(a){var c=[],d=[],e=this.o,f=this.f,g=this.a,h=0,l=0,m,n;m=0;for(n=f.length;m<n;++m){var p=f[m],l=Le(e,h,p,g,a,c,l);d.push(l);h=p}c.length=l;a=new R(null);Zn(a,"XY",c,d);return a};k.N=function(){return"MultiLineString"}; -k.pa=function(a){a:{var c=this.o,d=this.f,e=this.a,f=0,g,h;g=0;for(h=d.length;g<h;++g){if(Ue(c,f,d[g],e,a)){a=!0;break a}f=d[g]}a=!1}return a};k.da=function(a,c){if(a){ye(this,c,a,2);this.o||(this.o=[]);var d=Ie(this.o,0,a,this.a,this.f);this.o.length=0===d.length?0:d[d.length-1];this.v()}else Zn(this,"XY",null,this.f)};function Zn(a,c,d,e){xe(a,c,d);a.f=e;a.v()} -function $n(a,c){var d=a.c,e=[],f=[],g,h;g=0;for(h=c.length;g<h;++g){var l=c[g];0===g&&(d=l.c);eb(e,l.ba());f.push(e.length)}Zn(a,d,e,f)};function S(a,c){z.call(this);this.da(a,c)}x(S,z);k=S.prototype;k.Xf=function(a){this.o?eb(this.o,a.ba()):this.o=a.ba().slice();this.v()};k.clone=function(){var a=new S(null);xe(a,this.c,this.o.slice());a.v();return a};k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;var f=this.o,g=this.a,h,l,m;h=0;for(l=f.length;h<l;h+=g)if(m=Ra(a,c,f[h],f[h+1]),m<e){e=m;for(m=0;m<g;++m)d[m]=f[h+m];d.length=g}return e};k.R=function(){return Je(this.o,0,this.o.length,this.a)}; -k.Qg=function(a){var c=this.o?this.o.length/this.a:0;if(0>a||c<=a)return null;c=new A(null);xe(c,this.c,this.o.slice(a*this.a,(a+1)*this.a));c.v();return c};k.Re=function(){var a=this.o,c=this.c,d=this.a,e=[],f,g;f=0;for(g=a.length;f<g;f+=d){var h=new A(null),l=h;xe(l,c,a.slice(f,f+d));l.v();e.push(h)}return e};k.N=function(){return"MultiPoint"};k.pa=function(a){var c=this.o,d=this.a,e,f,g,h;e=0;for(f=c.length;e<f;e+=d)if(g=c[e],h=c[e+1],Dd(a,g,h))return!0;return!1}; -k.da=function(a,c){a?(ye(this,c,a,1),this.o||(this.o=[]),this.o.length=He(this.o,0,a,this.a)):xe(this,"XY",null);this.v()};function T(a,c){z.call(this);this.f=[];this.D=-1;this.G=null;this.J=this.B=this.I=-1;this.l=null;this.da(a,c)}x(T,z);k=T.prototype;k.Yf=function(a){if(this.o){var c=this.o.length;eb(this.o,a.ba());a=a.Na().slice();var d,e;d=0;for(e=a.length;d<e;++d)a[d]+=c}else this.o=a.ba().slice(),a=a.Na().slice(),this.f.push();this.f.push(a);this.v()};k.clone=function(){var a=new T(null),c=Lb(this.f);ao(a,this.c,this.o.slice(),c);return a}; -k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;if(this.B!=this.g){var f=this.f,g=0,h=0,l,m;l=0;for(m=f.length;l<m;++l)var n=f[l],h=De(this.o,g,n,this.a,h),g=n[n.length-1];this.I=Math.sqrt(h);this.B=this.g}f=Hk(this);g=this.f;h=this.a;l=this.I;m=0;var n=[NaN,NaN],p,q;p=0;for(q=g.length;p<q;++p){var r=g[p];e=Fe(f,m,r,h,l,!0,a,c,d,e,n);m=r[r.length-1]}return e}; -k.ib=function(a,c){var d;a:{d=Hk(this);var e=this.f,f=0;if(0!==e.length){var g,h;g=0;for(h=e.length;g<h;++g){var l=e[g];if(Qe(d,f,l,this.a,a,c)){d=!0;break a}f=l[l.length-1]}}d=!1}return d};k.pi=function(){var a=Hk(this),c=this.f,d=0,e=0,f,g;f=0;for(g=c.length;f<g;++f)var h=c[f],e=e+Ae(a,d,h,this.a),d=h[h.length-1];return e}; -k.R=function(a){var c;void 0!==a?(c=Hk(this).slice(),Ze(c,this.f,this.a,a)):c=this.o;a=c;c=this.f;var d=this.a,e=0,f=[],g=0,h,l;h=0;for(l=c.length;h<l;++h){var m=c[h];f[g++]=Ke(a,e,m,d,f[g]);e=m[m.length-1]}f.length=g;return f}; -function Ik(a){if(a.D!=a.g){var c=a.o,d=a.f,e=a.a,f=0,g=[],h,l,m=vd();h=0;for(l=d.length;h<l;++h){var n=d[h],m=Hd(c,f,n[0],e);g.push((m[0]+m[2])/2,(m[1]+m[3])/2);f=n[n.length-1]}c=Hk(a);d=a.f;e=a.a;f=0;h=[];l=0;for(m=d.length;l<m;++l)n=d[l],h=Se(c,f,n,e,g,2*l,h),f=n[n.length-1];a.G=h;a.D=a.g}return a.G}k.Fg=function(){var a=new S(null),c=Ik(this).slice();xe(a,"XY",c);a.v();return a}; -function Hk(a){if(a.J!=a.g){var c=a.o,d;a:{d=a.f;var e,f;e=0;for(f=d.length;e<f;++e)if(!Xe(c,d[e],a.a,void 0)){d=!1;break a}d=!0}d?a.l=c:(a.l=c.slice(),a.l.length=Ze(a.l,a.f,a.a));a.J=a.g}return a.l}k.wb=function(a){var c=[],d=[],e=this.o,f=this.f,g=this.a;a=Math.sqrt(a);var h=0,l=0,m,n;m=0;for(n=f.length;m<n;++m){var p=f[m],q=[],l=Me(e,h,p,g,a,c,l,q);d.push(q);h=p[p.length-1]}c.length=l;e=new T(null);ao(e,"XY",c,d);return e}; -k.Sg=function(a){if(0>a||this.f.length<=a)return null;var c;0===a?c=0:(c=this.f[a-1],c=c[c.length-1]);a=this.f[a].slice();var d=a[a.length-1];if(0!==c){var e,f;e=0;for(f=a.length;e<f;++e)a[e]-=c}e=new C(null);$e(e,this.c,this.o.slice(c,d),a);return e};k.Ae=function(){var a=this.c,c=this.o,d=this.f,e=[],f=0,g,h,l,m;g=0;for(h=d.length;g<h;++g){var n=d[g].slice(),p=n[n.length-1];if(0!==f)for(l=0,m=n.length;l<m;++l)n[l]-=f;l=new C(null);$e(l,a,c.slice(f,p),n);e.push(l);f=p}return e};k.N=function(){return"MultiPolygon"}; -k.pa=function(a){a:{var c=Hk(this),d=this.f,e=this.a,f=0,g,h;g=0;for(h=d.length;g<h;++g){var l=d[g];if(Ve(c,f,l,e,a)){a=!0;break a}f=l[l.length-1]}a=!1}return a};k.da=function(a,c){if(a){ye(this,c,a,3);this.o||(this.o=[]);var d=this.o,e=this.a,f=this.f,g=0,f=f?f:[],h=0,l,m;l=0;for(m=a.length;l<m;++l)g=Ie(d,g,a[l],e,f[h]),f[h++]=g,g=g[g.length-1];f.length=h;0===f.length?this.o.length=0:(d=f[f.length-1],this.o.length=0===d.length?0:d[d.length-1]);this.v()}else ao(this,"XY",null,this.f)}; -function ao(a,c,d,e){xe(a,c,d);a.f=e;a.v()};function U(a){ue.call(this);this.a=a?a:null;bo(this)}x(U,ue);function co(a){var c=[],d,e;d=0;for(e=a.length;d<e;++d)c.push(a[d].clone());return c}function eo(a){var c,d;if(a.a)for(c=0,d=a.a.length;c<d;++c)Mc(a.a[c],"change",a.v,!1,a)}function bo(a){var c,d;if(a.a)for(c=0,d=a.a.length;c<d;++c)y(a.a[c],"change",a.v,!1,a)}k=U.prototype;k.clone=function(){var a=new U(null);a.qf(this.a);return a}; -k.Aa=function(a,c,d,e){if(e<Bd(this.F(),a,c))return e;var f=this.a,g,h;g=0;for(h=f.length;g<h;++g)e=f[g].Aa(a,c,d,e);return e};k.ib=function(a,c){var d=this.a,e,f;e=0;for(f=d.length;e<f;++e)if(d[e].ib(a,c))return!0;return!1};k.pc=function(a){yd(Infinity,Infinity,-Infinity,-Infinity,a);for(var c=this.a,d=0,e=c.length;d<e;++d)Kd(a,c[d].F());return a};k.zg=function(){return co(this.a)}; -k.Tb=function(a){this.s!=this.g&&(Hb(this.i),this.j=0,this.s=this.g);if(0>a||0!==this.j&&a<this.j)return this;var c=a.toString();if(this.i.hasOwnProperty(c))return this.i[c];var d=[],e=this.a,f=!1,g,h;g=0;for(h=e.length;g<h;++g){var l=e[g],m=l.Tb(a);d.push(m);m!==l&&(f=!0)}if(f)return a=new U(null),eo(a),a.a=d,bo(a),a.v(),this.i[c]=a;this.j=a;return this};k.N=function(){return"GeometryCollection"};k.pa=function(a){var c=this.a,d,e;d=0;for(e=c.length;d<e;++d)if(c[d].pa(a))return!0;return!1}; -k.Ja=function(){return 0===this.a.length};k.qf=function(a){a=co(a);eo(this);this.a=a;bo(this);this.v()};k.pb=function(a){var c=this.a,d,e;d=0;for(e=c.length;d<e;++d)c[d].pb(a);this.v()};k.Hc=function(a,c){var d=this.a,e,f;e=0;for(f=d.length;e<f;++e)d[e].Hc(a,c);this.v()};k.Z=function(){eo(this);U.fa.Z.call(this)};function fo(a){a=a?a:{};this.defaultDataProjection=null;this.defaultDataProjection=fe(a.defaultDataProjection?a.defaultDataProjection:"EPSG:4326");this.a=a.geometryName}x(fo,Rn);function Un(a,c){return a?Qn((0,go[a.type])(a),!1,c):null}function ho(a,c){return(0,io[a.N()])(Qn(a,!0,c),c)} -var go={Point:function(a){return new A(a.coordinates)},LineString:function(a){return new Q(a.coordinates)},Polygon:function(a){return new C(a.coordinates)},MultiPoint:function(a){return new S(a.coordinates)},MultiLineString:function(a){return new R(a.coordinates)},MultiPolygon:function(a){return new T(a.coordinates)},GeometryCollection:function(a,c){var d=a.geometries.map(function(a){return Un(a,c)});return new U(d)}},io={Point:function(a){return{type:"Point",coordinates:a.R()}},LineString:function(a){return{type:"LineString", -coordinates:a.R()}},Polygon:function(a,c){var d;c&&(d=c.rightHanded);return{type:"Polygon",coordinates:a.R(d)}},MultiPoint:function(a){return{type:"MultiPoint",coordinates:a.R()}},MultiLineString:function(a){return{type:"MultiLineString",coordinates:a.R()}},MultiPolygon:function(a,c){var d;c&&(d=c.rightHanded);return{type:"MultiPolygon",coordinates:a.R(d)}},GeometryCollection:function(a,c){return{type:"GeometryCollection",geometries:a.a.map(function(a){return ho(a,c)})}},Circle:function(){return{type:"GeometryCollection", -geometries:[]}}};function Tn(a,c,d){d=Un(c.geometry,d);var e=new Kl;a.a&&e.Uc(a.a);e.Sa(d);void 0!==c.id&&e.Sd(c.id);c.properties&&e.K(c.properties);return e}fo.prototype.b=function(a,c){c=Pn(this,c);var d={type:"Feature"},e=a.Ba();void 0!==e&&(d.id=e);e=a.O();d.geometry=e?ho(e,c):null;e=a.P();delete e[a.a];d.properties=Gb(e)?null:e;return d};fo.prototype.g=function(a,c){c=Pn(this,c);var d=[],e,f;e=0;for(f=a.length;e<f;++e)d.push(this.b(a[e],c));return{type:"FeatureCollection",features:d}}; -fo.prototype.c=function(a,c){return ho(a,Pn(this,c))};function jo(){this.defaultDataProjection=null}x(jo,Nn);k=jo.prototype;k.N=function(){return"xml"};k.Od=function(a,c){if(Gm(a))return ko(this,a,c);if(Jm(a)){var d;d=0<=lo.indexOf(a.namespaceURI)?(d=this.Pd(a,[On(this,a,c)]))?d:null:null;return d}return ha(a)?(d=Nm(a),ko(this,d,c)):null};function ko(a,c,d){a=mo(a,c,d);return 0<a.length?a[0]:null}k.Sc=function(a,c){if(Gm(a))return mo(this,a,c);if(Jm(a))return no(this,a,c);if(ha(a)){var d=Nm(a);return mo(this,d,c)}return[]}; -function mo(a,c,d){var e=[];for(c=c.firstChild;c;c=c.nextSibling)1==c.nodeType&&eb(e,no(a,c,d));return e}k.kf=function(a,c){if(Gm(a))return this.f(a,c);if(Jm(a))return this.A(a,c);if(ha(a)){var d=Nm(a);return this.f(d,c)}return null};k.hc=function(a){return Gm(a)||Jm(a)?this.defaultDataProjection:ha(a)?(Nm(a),this.defaultDataProjection):null};k.Ff=function(a,c){var d=this.l(a,c);return sm(d)};k.$d=function(a,c){var d=this.a(a,c);return sm(d)};k.Gf=function(a,c){var d=this.s(a,c);return sm(d)};function oo(a){a=zm(a);return po(a)}function po(a){if(a=/^\s*(true|1)|(false|0)\s*$/.exec(a))return void 0!==a[1]||!1}function qo(a){a=zm(a);return ro(a)}function ro(a){if(a=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(a))return parseFloat(a[1])}function so(a){a=zm(a);return to(a)}function to(a){if(a=/^\s*(\d+)\s*$/.exec(a))return parseInt(a[1],10)}function uo(a){return zm(a).trim()}function vo(a,c){wo(a,c?"1":"0")}function xo(a,c){a.appendChild(vm.createTextNode(c.toPrecision()))} -function wo(a,c){a.appendChild(vm.createTextNode(c))};function yo(a,c){this.a=this.j=this.g="";this.A=null;this.c=this.b="";this.f=!1;var d;a instanceof yo?(this.f=ca(c)?c:a.f,zo(this,a.g),this.j=a.j,this.a=a.a,Ao(this,a.A),this.b=a.b,Bo(this,a.i.clone()),this.c=a.c):a&&(d=String(a).match(Vl))?(this.f=!!c,zo(this,d[1]||"",!0),this.j=Co(d[2]||""),this.a=Co(d[3]||"",!0),Ao(this,d[4]),this.b=Co(d[5]||"",!0),Bo(this,d[6]||"",!0),this.c=Co(d[7]||"")):(this.f=!!c,this.i=new Do(null,0,this.f))} -yo.prototype.toString=function(){var a=[],c=this.g;c&&a.push(Eo(c,Fo,!0),":");var d=this.a;if(d||"file"==c)a.push("//"),(c=this.j)&&a.push(Eo(c,Fo,!0),"@"),a.push(encodeURIComponent(String(d)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),d=this.A,null!=d&&a.push(":",String(d));if(d=this.b)this.a&&"/"!=d.charAt(0)&&a.push("/"),a.push(Eo(d,"/"==d.charAt(0)?Go:Ho,!0));(d=this.i.toString())&&a.push("?",d);(d=this.c)&&a.push("#",Eo(d,Io));return a.join("")};yo.prototype.clone=function(){return new yo(this)}; -function zo(a,c,d){a.g=d?Co(c,!0):c;a.g&&(a.g=a.g.replace(/:$/,""))}function Ao(a,c){if(c){c=Number(c);if(isNaN(c)||0>c)throw Error("Bad port number "+c);a.A=c}else a.A=null}function Bo(a,c,d){c instanceof Do?(a.i=c,Jo(a.i,a.f)):(d||(c=Eo(c,Ko)),a.i=new Do(c,0,a.f))}function Lo(a){return a instanceof yo?a.clone():new yo(a,void 0)} -function Mo(a,c){a instanceof yo||(a=Lo(a));c instanceof yo||(c=Lo(c));var d=a,e=c,f=d.clone(),g=!!e.g;g?zo(f,e.g):g=!!e.j;g?f.j=e.j:g=!!e.a;g?f.a=e.a:g=null!=e.A;var h=e.b;if(g)Ao(f,e.A);else if(g=!!e.b)if("/"!=h.charAt(0)&&(d.a&&!d.b?h="/"+h:(d=f.b.lastIndexOf("/"),-1!=d&&(h=f.b.substr(0,d+1)+h))),d=h,".."==d||"."==d)h="";else if(-1!=d.indexOf("./")||-1!=d.indexOf("/.")){for(var h=0==d.lastIndexOf("/",0),d=d.split("/"),l=[],m=0;m<d.length;){var n=d[m++];"."==n?h&&m==d.length&&l.push(""):".."==n? -((1<l.length||1==l.length&&""!=l[0])&&l.pop(),h&&m==d.length&&l.push("")):(l.push(n),h=!0)}h=l.join("/")}else h=d;g?f.b=h:g=""!==e.i.toString();g?Bo(f,Co(e.i.toString())):g=!!e.c;g&&(f.c=e.c);return f}function Co(a,c){return a?c?decodeURI(a.replace(/%25/g,"%2525")):decodeURIComponent(a):""}function Eo(a,c,d){return ha(a)?(a=encodeURI(a).replace(c,No),d&&(a=a.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),a):null}function No(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)} -var Fo=/[#\/\?@]/g,Ho=/[\#\?:]/g,Go=/[\#\?]/g,Ko=/[\#\?@]/g,Io=/#/g;function Do(a,c,d){this.g=this.b=null;this.a=a||null;this.c=!!d}function Oo(a){a.b||(a.b=new Vg,a.g=0,a.a&&Wl(a.a,function(c,d){a.add(decodeURIComponent(c.replace(/\+/g," ")),d)}))}k=Do.prototype;k.Rb=function(){Oo(this);return this.g};k.add=function(a,c){Oo(this);this.a=null;a=Po(this,a);var d=this.b.get(a);d||Wg(this.b,a,d=[]);d.push(c);this.g++;return this}; -k.remove=function(a){Oo(this);a=Po(this,a);return Yg(this.b.a,a)?(this.a=null,this.g-=this.b.get(a).length,this.b.remove(a)):!1};k.clear=function(){this.b=this.a=null;this.g=0};k.Ja=function(){Oo(this);return 0==this.g};k.L=function(){Oo(this);for(var a=this.b.fb(),c=this.b.L(),d=[],e=0;e<c.length;e++)for(var f=a[e],g=0;g<f.length;g++)d.push(c[e]);return d}; -k.fb=function(a){Oo(this);var c=[];if(ha(a)){var d=a;Oo(this);d=Po(this,d);Yg(this.b.a,d)&&(c=cb(c,this.b.get(Po(this,a))))}else for(a=this.b.fb(),d=0;d<a.length;d++)c=cb(c,a[d]);return c};k.get=function(a,c){var d=a?this.fb(a):[];return 0<d.length?String(d[0]):c}; -k.toString=function(){if(this.a)return this.a;if(!this.b)return"";for(var a=[],c=this.b.L(),d=0;d<c.length;d++)for(var e=c[d],f=encodeURIComponent(String(e)),e=this.fb(e),g=0;g<e.length;g++){var h=f;""!==e[g]&&(h+="="+encodeURIComponent(String(e[g])));a.push(h)}return this.a=a.join("&")};k.clone=function(){var a=new Do;a.a=this.a;this.b&&(a.b=this.b.clone(),a.g=this.g);return a};function Po(a,c){var d=String(c);a.c&&(d=d.toLowerCase());return d} -function Jo(a,c){c&&!a.c&&(Oo(a),a.a=null,a.b.forEach(function(a,c){var f=c.toLowerCase();c!=f&&(this.remove(c),this.remove(f),0<a.length&&(this.a=null,Wg(this.b,Po(this,f),db(a)),this.g+=a.length))},a));a.c=c};function Qo(a){a=a||{};this.g=a.font;this.i=a.rotation;this.a=a.scale;this.s=a.text;this.A=a.textAlign;this.l=a.textBaseline;this.b=void 0!==a.fill?a.fill:new kk({color:"#333"});this.j=void 0!==a.stroke?a.stroke:null;this.c=void 0!==a.offsetX?a.offsetX:0;this.f=void 0!==a.offsetY?a.offsetY:0}k=Qo.prototype;k.xg=function(){return this.g};k.Mg=function(){return this.c};k.Ng=function(){return this.f};k.xj=function(){return this.b};k.yj=function(){return this.i};k.zj=function(){return this.a};k.Aj=function(){return this.j}; -k.oa=function(){return this.s};k.Wg=function(){return this.A};k.Xg=function(){return this.l};k.bk=function(a){this.g=a};k.tf=function(a){this.c=a};k.uf=function(a){this.f=a};k.ak=function(a){this.b=a};k.Bj=function(a){this.i=a};k.Cj=function(a){this.a=a};k.kk=function(a){this.j=a};k.wf=function(a){this.s=a};k.xf=function(a){this.A=a};k.lk=function(a){this.l=a};function Ro(a){a=a?a:{};this.defaultDataProjection=null;this.defaultDataProjection=fe("EPSG:4326");this.g=a.defaultStyle?a.defaultStyle:So;this.c=void 0!==a.extractStyles?a.extractStyles:!0;this.j=void 0!==a.writeStyles?a.writeStyles:!0;this.b={};this.i=void 0!==a.showPointNames?a.showPointNames:!0}x(Ro,jo); -var To=["http://www.google.com/kml/ext/2.2"],lo=[null,"http://earth.google.com/kml/2.0","http://earth.google.com/kml/2.1","http://earth.google.com/kml/2.2","http://www.opengis.net/kml/2.2"],Uo=[255,255,255,1],Vo=new kk({color:Uo}),Wo=[20,2],Xo=[64,64],Yo=new Ni({anchor:Wo,anchorOrigin:"bottom-left",anchorXUnits:"pixels",anchorYUnits:"pixels",crossOrigin:"anonymous",rotation:0,scale:.5,size:Xo,src:"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"}),Zo=new pk({color:Uo,width:1}),$o=new Qo({font:"bold 16px Helvetica", -fill:Vo,stroke:new pk({color:[51,51,51,1],width:2}),scale:.8}),So=[new rk({fill:Vo,image:Yo,text:$o,stroke:Zo,zIndex:0})],ap={fraction:"fraction",pixels:"pixels"};function bp(a,c){var d=null,e=[0,0],f="start";a.a&&(d=a.a.tc())&&2==d.length&&(e[0]=a.a.j*d[0]/2,e[1]=-a.a.j*d[1]/2,f="left");Gb(a.oa())?d=new Qo({text:c,offsetX:e[0],offsetY:e[1],textAlign:f}):(d=Kb(a.oa()),d.wf(c),d.xf(f),d.tf(e[0]),d.uf(e[1]));return new rk({text:d})} -function cp(a,c,d,e,f){return function(){var g=f,h="";g&&this.O()&&(g="Point"===this.O().N());g&&(h=this.P().name,g=g&&h);if(a)return g?(g=bp(a[0],h),a.concat(g)):a;if(c){var l=dp(c,d,e);return g?(g=bp(l[0],h),l.concat(g)):l}return g?(g=bp(d[0],h),d.concat(g)):d}}function dp(a,c,d){return fa(a)?a:ha(a)?(!(a in d)&&"#"+a in d&&(a="#"+a),dp(d[a],c,d)):c} -function ep(a){a=zm(a);if(a=/^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(a))return a=a[1],[parseInt(a.substr(6,2),16),parseInt(a.substr(4,2),16),parseInt(a.substr(2,2),16),parseInt(a.substr(0,2),16)/255]}function fp(a){a=zm(a);for(var c=[],d=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i,e;e=d.exec(a);)c.push(parseFloat(e[1]),parseFloat(e[2]),e[3]?parseFloat(e[3]):0),a=a.substr(e[0].length);return""!==a?void 0:c} -function gp(a){var c=zm(a);return a.baseURI?Mo(a.baseURI,c.trim()).toString():c.trim()}function hp(a){a=qo(a);if(void 0!==a)return Math.sqrt(a)}function ip(a,c){return Xm(null,jp,a,c)}function kp(a,c){var d=Xm({o:[],Ef:[]},lp,a,c);if(d){var e=d.o,d=d.Ef,f,g;f=0;for(g=Math.min(e.length,d.length);f<g;++f)e[4*f+3]=d[f];d=new Q(null);Yn(d,"XYZM",e);return d}}function mp(a,c){var d=Xm({},np,a,c),e=Xm(null,op,a,c);if(e){var f=new Q(null);Yn(f,"XYZ",e);f.K(d);return f}} -function pp(a,c){var d=Xm({},np,a,c),e=Xm(null,op,a,c);if(e){var f=new C(null);$e(f,"XYZ",e,[e.length]);f.K(d);return f}} -function qp(a,c){var d=Xm([],rp,a,c);if(!d)return null;if(0===d.length)return new U(d);var e=!0,f=d[0].N(),g,h,l;h=1;for(l=d.length;h<l;++h)if(g=d[h],g.N()!=f){e=!1;break}if(e){if("Point"==f){g=d[0];e=g.c;f=g.ba();h=1;for(l=d.length;h<l;++h)g=d[h],eb(f,g.ba());g=new S(null);xe(g,e,f);g.v();sp(g,d);return g}if("LineString"==f)return g=new R(null),$n(g,d),sp(g,d),g;if("Polygon"==f){g=new T(null);h=g.c;l=[];var e=[],m,n,f=0;for(m=d.length;f<m;++f){var p=d[f];0===f&&(h=p.c);var q=l.length;n=p.Na();var r, -t;r=0;for(t=n.length;r<t;++r)n[r]+=q;eb(l,p.ba());e.push(n)}ao(g,h,l,e);sp(g,d);return g}return"GeometryCollection"==f?new U(d):null}return new U(d)}function tp(a,c){var d=Xm({},np,a,c),e=Xm(null,op,a,c);if(e){var f=new A(null);xe(f,"XYZ",e);f.v();f.K(d);return f}}function up(a,c){var d=Xm({},np,a,c),e=Xm([null],vp,a,c);if(e&&e[0]){var f=new C(null),g=e[0],h=[g.length],l,m;l=1;for(m=e.length;l<m;++l)eb(g,e[l]),h.push(g.length);$e(f,"XYZ",g,h);f.K(d);return f}} -function wp(a,c){var d=Xm({},xp,a,c);if(!d)return null;var e="fillStyle"in d?d.fillStyle:Vo,f=d.fill;void 0===f||f||(e=null);var f="imageStyle"in d?d.imageStyle:Yo,g="textStyle"in d?d.textStyle:$o,h="strokeStyle"in d?d.strokeStyle:Zo,d=d.outline;void 0===d||d||(h=null);return[new rk({fill:e,image:f,stroke:h,text:g,zIndex:void 0})]} -function sp(a,c){var d=c.length,e=Array(c.length),f=Array(c.length),g,h,l,m;l=m=!1;for(h=0;h<d;++h)g=c[h],e[h]=g.get("extrude"),f[h]=g.get("altitudeMode"),l=l||void 0!==e[h],m=m||f[h];l&&a.C("extrude",e);m&&a.C("altitudeMode",f)}function yp(a,c){Wm(zp,a,c)} -var Ap=M(lo,{value:Qm(uo)}),zp=M(lo,{Data:function(a,c){var d=a.getAttribute("name");if(null!==d){var e=Xm(void 0,Ap,a,c);e&&(c[c.length-1][d]=e)}},SchemaData:function(a,c){Wm(Bp,a,c)}}),np=M(lo,{extrude:L(oo),altitudeMode:L(uo)}),jp=M(lo,{coordinates:Qm(fp)}),vp=M(lo,{innerBoundaryIs:function(a,c){var d=Xm(void 0,Cp,a,c);d&&c[c.length-1].push(d)},outerBoundaryIs:function(a,c){var d=Xm(void 0,Dp,a,c);d&&(c[c.length-1][0]=d)}}),lp=M(lo,{when:function(a,c){var d=c[c.length-1].Ef,e=zm(a);if(e=/^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/.exec(e)){var f= -Date.UTC(parseInt(e[1],10),e[3]?parseInt(e[3],10)-1:0,e[5]?parseInt(e[5],10):1,e[7]?parseInt(e[7],10):0,e[8]?parseInt(e[8],10):0,e[9]?parseInt(e[9],10):0);if(e[10]&&"Z"!=e[10]){var g="-"==e[11]?-1:1,f=f+60*g*parseInt(e[12],10);e[13]&&(f+=3600*g*parseInt(e[13],10))}d.push(f)}else d.push(0)}},M(To,{coord:function(a,c){var d=c[c.length-1].o,e=zm(a);(e=/^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i.exec(e))?d.push(parseFloat(e[1]), -parseFloat(e[2]),parseFloat(e[3]),0):d.push(0,0,0,0)}})),op=M(lo,{coordinates:Qm(fp)}),Ep=M(lo,{href:L(gp)},M(To,{x:L(qo),y:L(qo),w:L(qo),h:L(qo)})),Fp=M(lo,{Icon:L(function(a,c){var d=Xm({},Ep,a,c);return d?d:null}),heading:L(qo),hotSpot:L(function(a){var c=a.getAttribute("xunits"),d=a.getAttribute("yunits");return{x:parseFloat(a.getAttribute("x")),ae:ap[c],y:parseFloat(a.getAttribute("y")),be:ap[d]}}),scale:L(hp)}),Cp=M(lo,{LinearRing:Qm(ip)}),Gp=M(lo,{color:L(ep),scale:L(hp)}),Hp=M(lo,{color:L(ep), -width:L(qo)}),rp=M(lo,{LineString:Pm(mp),LinearRing:Pm(pp),MultiGeometry:Pm(qp),Point:Pm(tp),Polygon:Pm(up)}),Ip=M(To,{Track:Pm(kp)}),Kp=M(lo,{ExtendedData:yp,Link:function(a,c){Wm(Jp,a,c)},address:L(uo),description:L(uo),name:L(uo),open:L(oo),phoneNumber:L(uo),visibility:L(oo)}),Jp=M(lo,{href:L(gp)}),Dp=M(lo,{LinearRing:Qm(ip)}),Lp=M(lo,{Style:L(wp),key:L(uo),styleUrl:L(function(a){var c=zm(a).trim();return a.baseURI?Mo(a.baseURI,c).toString():c})}),Np=M(lo,{ExtendedData:yp,MultiGeometry:L(qp,"geometry"), -LineString:L(mp,"geometry"),LinearRing:L(pp,"geometry"),Point:L(tp,"geometry"),Polygon:L(up,"geometry"),Style:L(wp),StyleMap:function(a,c){var d=Xm(void 0,Mp,a,c);if(d){var e=c[c.length-1];fa(d)?e.Style=d:ha(d)&&(e.styleUrl=d)}},address:L(uo),description:L(uo),name:L(uo),open:L(oo),phoneNumber:L(uo),styleUrl:L(gp),visibility:L(oo)},M(To,{MultiTrack:L(function(a,c){var d=Xm([],Ip,a,c);if(d){var e=new R(null);$n(e,d);return e}},"geometry"),Track:L(kp,"geometry")})),Op=M(lo,{color:L(ep),fill:L(oo),outline:L(oo)}), -Bp=M(lo,{SimpleData:function(a,c){var d=a.getAttribute("name");if(null!==d){var e=uo(a);c[c.length-1][d]=e}}}),xp=M(lo,{IconStyle:function(a,c){var d=Xm({},Fp,a,c);if(d){var e=c[c.length-1],f="Icon"in d?d.Icon:{},g;g=(g=f.href)?g:"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png";var h,l,m,n=d.hotSpot;n?(h=[n.x,n.y],l=n.ae,m=n.be):"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"===g?(h=Wo,m=l="pixels"):/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(g)&&(h=[.5,0],m=l="fraction"); -var p,n=f.x,q=f.y;void 0!==n&&void 0!==q&&(p=[n,q]);var r,n=f.w,f=f.h;void 0!==n&&void 0!==f&&(r=[n,f]);var t,f=d.heading;void 0!==f&&(t=Sa(f));d=d.scale;"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"==g&&(r=Xo,void 0===d&&(d=.5));h=new Ni({anchor:h,anchorOrigin:"bottom-left",anchorXUnits:l,anchorYUnits:m,crossOrigin:"anonymous",offset:p,offsetOrigin:"bottom-left",rotation:t,scale:d,size:r,src:g});e.imageStyle=h}},LabelStyle:function(a,c){var d=Xm({},Gp,a,c);d&&(c[c.length-1].textStyle= -new Qo({fill:new kk({color:"color"in d?d.color:Uo}),scale:d.scale}))},LineStyle:function(a,c){var d=Xm({},Hp,a,c);d&&(c[c.length-1].strokeStyle=new pk({color:"color"in d?d.color:Uo,width:"width"in d?d.width:1}))},PolyStyle:function(a,c){var d=Xm({},Op,a,c);if(d){var e=c[c.length-1];e.fillStyle=new kk({color:"color"in d?d.color:Uo});var f=d.fill;void 0!==f&&(e.fill=f);d=d.outline;void 0!==d&&(e.outline=d)}}}),Mp=M(lo,{Pair:function(a,c){var d=Xm({},Lp,a,c);if(d){var e=d.key;e&&"normal"==e&&((e=d.styleUrl)&& -(c[c.length-1]=e),(d=d.Style)&&(c[c.length-1]=d))}}});k=Ro.prototype;k.Nd=function(a,c){Dm(a);var d=M(lo,{Document:Om(this.Nd,this),Folder:Om(this.Nd,this),Placemark:Pm(this.Pd,this),Style:sa(this.Qj,this),StyleMap:sa(this.Pj,this)});if(d=Xm([],d,a,c,this))return d}; -k.Pd=function(a,c){var d=Xm({geometry:null},Np,a,c);if(d){var e=new Kl,f=a.getAttribute("id");null!==f&&e.Sd(f);var f=c[0],g=d.geometry;g&&Qn(g,!1,f);e.Sa(g);delete d.geometry;this.c&&e.Fd(cp(d.Style,d.styleUrl,this.g,this.b,this.i));delete d.Style;e.K(d);return e}};k.Qj=function(a,c){var d=a.getAttribute("id");if(null!==d){var e=wp(a,c);e&&(d=a.baseURI?Mo(a.baseURI,"#"+d).toString():"#"+d,this.b[d]=e)}}; -k.Pj=function(a,c){var d=a.getAttribute("id");if(null!==d){var e=Xm(void 0,Mp,a,c);e&&(d=a.baseURI?Mo(a.baseURI,"#"+d).toString():"#"+d,this.b[d]=e)}};function no(a,c,d){if(!(0<=lo.indexOf(c.namespaceURI)))return[];var e;e=Dm(c);if("Document"==e||"Folder"==e)return(e=a.Nd(c,[On(a,c,d)]))?e:[];if("Placemark"==e)return(a=a.Pd(c,[On(a,c,d)]))?[a]:[];if("kml"==e){e=[];for(c=c.firstElementChild;c;c=c.nextElementSibling){var f=no(a,c,d);f&&eb(e,f)}return e}return[]} -k.Nj=function(a){if(Gm(a))return Pp(this,a);if(Jm(a))return Qp(this,a);if(ha(a))return a=Nm(a),Pp(this,a)};function Pp(a,c){var d;for(d=c.firstChild;d;d=d.nextSibling)if(1==d.nodeType){var e=Qp(a,d);if(e)return e}} -function Qp(a,c){var d;for(d=c.firstElementChild;d;d=d.nextElementSibling)if(0<=lo.indexOf(d.namespaceURI)&&"name"==d.localName)return uo(d);for(d=c.firstElementChild;d;d=d.nextElementSibling){var e=Dm(d);if(0<=lo.indexOf(d.namespaceURI)&&("Document"==e||"Folder"==e||"Placemark"==e||"kml"==e)&&(e=Qp(a,d)))return e}}k.Oj=function(a){var c=[];Gm(a)?eb(c,Rp(this,a)):Jm(a)?eb(c,Sp(this,a)):ha(a)&&(a=Nm(a),eb(c,Rp(this,a)));return c}; -function Rp(a,c){var d,e=[];for(d=c.firstChild;d;d=d.nextSibling)1==d.nodeType&&eb(e,Sp(a,d));return e}function Sp(a,c){var d,e=[];for(d=c.firstElementChild;d;d=d.nextElementSibling)if(0<=lo.indexOf(d.namespaceURI)&&"NetworkLink"==d.localName){var f=Xm({},Kp,d,[]);e.push(f)}for(d=c.firstElementChild;d;d=d.nextElementSibling)f=Dm(d),!(0<=lo.indexOf(d.namespaceURI))||"Document"!=f&&"Folder"!=f&&"kml"!=f||eb(e,Sp(a,d));return e} -function Tp(a,c){var d=wf(c),d=[255*(4==d.length?d[3]:1),d[2],d[1],d[0]],e;for(e=0;4>e;++e){var f=parseInt(d[e],10).toString(16);d[e]=1==f.length?"0"+f:f}wo(a,d.join(""))}function Up(a,c,d){Ym({node:a},Vp,Wp,[c],d)} -function Xp(a,c,d){var e={node:a};c.Ba()&&a.setAttribute("id",c.Ba());a=c.P();var f=c.Yb();if(f&&(f=f.call(c,0))&&0<f.length){var g=f[0];this.j&&(a.Style=f[0]);(f=g.oa())&&(a.name=f.oa())}f=Yp[d[d.length-1].node.namespaceURI];a=Vm(a,f);Ym(e,Zp,Um,a,d,f);a=d[0];(c=c.O())&&(c=Qn(c,!0,a));Ym(e,Zp,$p,[c],d)}function aq(a,c,d){var e=c.ba();a={node:a};a.layout=c.c;a.stride=c.la();Ym(a,bq,cq,[e],d)}function dq(a,c,d){c=c.we();var e=c.shift();a={node:a};Ym(a,eq,fq,c,d);Ym(a,eq,gq,[e],d)} -function hq(a,c){xo(a,c*c)} -var iq=M(lo,["Document","Placemark"]),lq=M(lo,{Document:Sm(function(a,c,d){Ym({node:a},jq,kq,c,d,void 0,this)}),Placemark:Sm(Xp)}),jq=M(lo,{Placemark:Sm(Xp)}),mq={Point:"Point",LineString:"LineString",LinearRing:"LinearRing",Polygon:"Polygon",MultiPoint:"MultiGeometry",MultiLineString:"MultiGeometry",MultiPolygon:"MultiGeometry"},nq=M(lo,["href"],M(To,["x","y","w","h"])),oq=M(lo,{href:Sm(wo)},M(To,{x:Sm(xo),y:Sm(xo),w:Sm(xo),h:Sm(xo)})),pq=M(lo,["scale","heading","Icon","hotSpot"]),rq=M(lo,{Icon:Sm(function(a, -c,d){a={node:a};var e=nq[d[d.length-1].node.namespaceURI],f=Vm(c,e);Ym(a,oq,Um,f,d,e);e=nq[To[0]];f=Vm(c,e);Ym(a,oq,qq,f,d,e)}),heading:Sm(xo),hotSpot:Sm(function(a,c){a.setAttribute("x",c.x);a.setAttribute("y",c.y);a.setAttribute("xunits",c.ae);a.setAttribute("yunits",c.be)}),scale:Sm(hq)}),sq=M(lo,["color","scale"]),tq=M(lo,{color:Sm(Tp),scale:Sm(hq)}),uq=M(lo,["color","width"]),vq=M(lo,{color:Sm(Tp),width:Sm(xo)}),Vp=M(lo,{LinearRing:Sm(aq)}),wq=M(lo,{LineString:Sm(aq),Point:Sm(aq),Polygon:Sm(dq)}), -Yp=M(lo,"name open visibility address phoneNumber description styleUrl Style".split(" ")),Zp=M(lo,{MultiGeometry:Sm(function(a,c,d){a={node:a};var e=c.N(),f,g;"MultiPoint"==e?(f=c.Re(),g=xq):"MultiLineString"==e?(f=c.ue(),g=yq):"MultiPolygon"==e&&(f=c.Ae(),g=zq);Ym(a,wq,g,f,d)}),LineString:Sm(aq),LinearRing:Sm(aq),Point:Sm(aq),Polygon:Sm(dq),Style:Sm(function(a,c,d){a={node:a};var e={},f=c.f,g=c.g,h=c.a;c=c.oa();h instanceof Ni&&(e.IconStyle=h);c&&(e.LabelStyle=c);g&&(e.LineStyle=g);f&&(e.PolyStyle= -f);c=Aq[d[d.length-1].node.namespaceURI];e=Vm(e,c);Ym(a,Bq,Um,e,d,c)}),address:Sm(wo),description:Sm(wo),name:Sm(wo),open:Sm(vo),phoneNumber:Sm(wo),styleUrl:Sm(wo),visibility:Sm(vo)}),bq=M(lo,{coordinates:Sm(function(a,c,d){d=d[d.length-1];var e=d.layout;d=d.stride;var f;"XY"==e||"XYM"==e?f=2:("XYZ"==e||"XYZM"==e)&&(f=3);var g,h=c.length,l="";if(0<h){l+=c[0];for(e=1;e<f;++e)l+=","+c[e];for(g=d;g<h;g+=d)for(l+=" "+c[g],e=1;e<f;++e)l+=","+c[g+e]}wo(a,l)})}),eq=M(lo,{outerBoundaryIs:Sm(Up),innerBoundaryIs:Sm(Up)}), -Cq=M(lo,{color:Sm(Tp)}),Aq=M(lo,["IconStyle","LabelStyle","LineStyle","PolyStyle"]),Bq=M(lo,{IconStyle:Sm(function(a,c,d){a={node:a};var e={},f=c.Ta(),g=c.tc(),h={href:c.b.j};if(f){h.w=f[0];h.h=f[1];var l=c.eb(),m=c.ta();m&&g&&0!==m[0]&&m[1]!==f[1]&&(h.x=m[0],h.y=g[1]-(m[1]+f[1]));l&&0!==l[0]&&l[1]!==f[1]&&(e.hotSpot={x:l[0],ae:"pixels",y:f[1]-l[1],be:"pixels"})}e.Icon=h;f=c.j;1!==f&&(e.scale=f);c=c.s;0!==c&&(e.heading=c);c=pq[d[d.length-1].node.namespaceURI];e=Vm(e,c);Ym(a,rq,Um,e,d,c)}),LabelStyle:Sm(function(a, -c,d){a={node:a};var e={},f=c.b;f&&(e.color=f.b);(c=c.a)&&1!==c&&(e.scale=c);c=sq[d[d.length-1].node.namespaceURI];e=Vm(e,c);Ym(a,tq,Um,e,d,c)}),LineStyle:Sm(function(a,c,d){a={node:a};var e=uq[d[d.length-1].node.namespaceURI];c=Vm({color:c.b,width:c.a},e);Ym(a,vq,Um,c,d,e)}),PolyStyle:Sm(function(a,c,d){Ym({node:a},Cq,Dq,[c.b],d)})});function qq(a,c,d){return ym(To[0],"gx:"+d)}function kq(a,c){return ym(c[c.length-1].node.namespaceURI,"Placemark")} -function $p(a,c){if(a)return ym(c[c.length-1].node.namespaceURI,mq[a.N()])}var Dq=Tm("color"),cq=Tm("coordinates"),fq=Tm("innerBoundaryIs"),xq=Tm("Point"),yq=Tm("LineString"),Wp=Tm("LinearRing"),zq=Tm("Polygon"),gq=Tm("outerBoundaryIs"); -Ro.prototype.a=function(a,c){c=Pn(this,c);var d=ym(lo[4],"kml");Mm(d,"http://www.w3.org/2000/xmlns/","xmlns:gx",To[0]);Mm(d,"http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");Mm(d,"http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation","http://www.opengis.net/kml/2.2 https://developers.google.com/kml/schema/kml22gx.xsd");var e={node:d},f={};1<a.length?f.Document=a:1==a.length&&(f.Placemark=a[0]);var g=iq[d.namespaceURI],f=Vm(f,g);Ym(e,lq,Um,f,[c],g,this); -return d};function Eq(a){return a.getAttributeNS("http://www.w3.org/1999/xlink","href")};function Fq(){}Fq.prototype.b=function(a){return Gm(a)?Gq(this,a):Jm(a)?Hq(this,a):ha(a)?(a=Nm(a),Gq(this,a)):null};function Iq(){this.version=void 0}x(Iq,Fq);function Gq(a,c){for(var d=c.firstChild;d;d=d.nextSibling)if(1==d.nodeType)return Hq(a,d);return null}function Hq(a,c){a.version=c.getAttribute("version").trim();var d=Xm({version:a.version},Jq,c,[]);return d?d:null}function Kq(a,c){return Xm({},Lq,a,c)}function Mq(a,c){return Xm({},Nq,a,c)}function Oq(a,c){var d=Kq(a,c);if(d){var e=[to(a.getAttribute("width")),to(a.getAttribute("height"))];d.size=e;return d}}function Pq(a,c){return Xm([],Qq,a,c)} -var Rq=[null,"http://www.opengis.net/wms"],Jq=M(Rq,{Service:L(function(a,c){return Xm({},Sq,a,c)}),Capability:L(function(a,c){return Xm({},Tq,a,c)})}),Tq=M(Rq,{Request:L(function(a,c){return Xm({},Uq,a,c)}),Exception:L(function(a,c){return Xm([],Vq,a,c)}),Layer:L(function(a,c){return Xm({},Wq,a,c)})}),Sq=M(Rq,{Name:L(uo),Title:L(uo),Abstract:L(uo),KeywordList:L(Pq),OnlineResource:L(Eq),ContactInformation:L(function(a,c){return Xm({},Xq,a,c)}),Fees:L(uo),AccessConstraints:L(uo),LayerLimit:L(so),MaxWidth:L(so), -MaxHeight:L(so)}),Xq=M(Rq,{ContactPersonPrimary:L(function(a,c){return Xm({},Yq,a,c)}),ContactPosition:L(uo),ContactAddress:L(function(a,c){return Xm({},Zq,a,c)}),ContactVoiceTelephone:L(uo),ContactFacsimileTelephone:L(uo),ContactElectronicMailAddress:L(uo)}),Yq=M(Rq,{ContactPerson:L(uo),ContactOrganization:L(uo)}),Zq=M(Rq,{AddressType:L(uo),Address:L(uo),City:L(uo),StateOrProvince:L(uo),PostCode:L(uo),Country:L(uo)}),Vq=M(Rq,{Format:Pm(uo)}),Wq=M(Rq,{Name:L(uo),Title:L(uo),Abstract:L(uo),KeywordList:L(Pq), -CRS:Rm(uo),EX_GeographicBoundingBox:L(function(a,c){var d=Xm({},$q,a,c);if(d){var e=d.westBoundLongitude,f=d.southBoundLatitude,g=d.eastBoundLongitude,d=d.northBoundLatitude;return void 0===e||void 0===f||void 0===g||void 0===d?void 0:[e,f,g,d]}}),BoundingBox:Rm(function(a){var c=[ro(a.getAttribute("minx")),ro(a.getAttribute("miny")),ro(a.getAttribute("maxx")),ro(a.getAttribute("maxy"))],d=[ro(a.getAttribute("resx")),ro(a.getAttribute("resy"))];return{crs:a.getAttribute("CRS"),extent:c,res:d}}),Dimension:Rm(function(a){return{name:a.getAttribute("name"), -units:a.getAttribute("units"),unitSymbol:a.getAttribute("unitSymbol"),"default":a.getAttribute("default"),multipleValues:po(a.getAttribute("multipleValues")),nearestValue:po(a.getAttribute("nearestValue")),current:po(a.getAttribute("current")),values:uo(a)}}),Attribution:L(function(a,c){return Xm({},ar,a,c)}),AuthorityURL:Rm(function(a,c){var d=Kq(a,c);if(d)return d.name=a.getAttribute("name"),d}),Identifier:Rm(uo),MetadataURL:Rm(function(a,c){var d=Kq(a,c);if(d)return d.type=a.getAttribute("type"), -d}),DataURL:Rm(Kq),FeatureListURL:Rm(Kq),Style:Rm(function(a,c){return Xm({},br,a,c)}),MinScaleDenominator:L(qo),MaxScaleDenominator:L(qo),Layer:Rm(function(a,c){var d=c[c.length-1],e=Xm({},Wq,a,c);if(e){var f=po(a.getAttribute("queryable"));void 0===f&&(f=d.queryable);e.queryable=void 0!==f?f:!1;f=to(a.getAttribute("cascaded"));void 0===f&&(f=d.cascaded);e.cascaded=f;f=po(a.getAttribute("opaque"));void 0===f&&(f=d.opaque);e.opaque=void 0!==f?f:!1;f=po(a.getAttribute("noSubsets"));void 0===f&&(f= -d.noSubsets);e.noSubsets=void 0!==f?f:!1;(f=ro(a.getAttribute("fixedWidth")))||(f=d.fixedWidth);e.fixedWidth=f;(f=ro(a.getAttribute("fixedHeight")))||(f=d.fixedHeight);e.fixedHeight=f;["Style","CRS","AuthorityURL"].forEach(function(a){if(a in d){var c=Jb(e,a),c=c.concat(d[a]);e[a]=c}});"EX_GeographicBoundingBox BoundingBox Dimension Attribution MinScaleDenominator MaxScaleDenominator".split(" ").forEach(function(a){a in e||(e[a]=d[a])});return e}})}),ar=M(Rq,{Title:L(uo),OnlineResource:L(Eq),LogoURL:L(Oq)}), -$q=M(Rq,{westBoundLongitude:L(qo),eastBoundLongitude:L(qo),southBoundLatitude:L(qo),northBoundLatitude:L(qo)}),Uq=M(Rq,{GetCapabilities:L(Mq),GetMap:L(Mq),GetFeatureInfo:L(Mq)}),Nq=M(Rq,{Format:Rm(uo),DCPType:Rm(function(a,c){return Xm({},cr,a,c)})}),cr=M(Rq,{HTTP:L(function(a,c){return Xm({},dr,a,c)})}),dr=M(Rq,{Get:L(Kq),Post:L(Kq)}),br=M(Rq,{Name:L(uo),Title:L(uo),Abstract:L(uo),LegendURL:Rm(Oq),StyleSheetURL:L(Kq),StyleURL:L(Kq)}),Lq=M(Rq,{Format:L(uo),OnlineResource:L(Eq)}),Qq=M(Rq,{Keyword:Pm(uo)});var er=new $d(6378137);function fr(a){Yc.call(this);a=a||{};this.a=null;this.f=re;this.c=void 0;y(this,$c("projection"),this.ai,!1,this);y(this,$c("tracking"),this.bi,!1,this);void 0!==a.projection&&this.Ke(fe(a.projection));void 0!==a.trackingOptions&&this.yf(a.trackingOptions);this.Ec(void 0!==a.tracking?a.tracking:!1)}x(fr,Yc);k=fr.prototype;k.Z=function(){this.Ec(!1);fr.fa.Z.call(this)};k.ai=function(){var a=this.Ie();a&&(this.f=je(fe("EPSG:4326"),a),this.a&&this.C("position",this.f(this.a)))}; -k.bi=function(){if(yh){var a=this.Je();a&&void 0===this.c?this.c=ba.navigator.geolocation.watchPosition(sa(this.Lj,this),sa(this.Mj,this),this.Ce()):a||void 0===this.c||(ba.navigator.geolocation.clearWatch(this.c),this.c=void 0)}}; -k.Lj=function(a){var c=a.coords;this.C("accuracy",c.accuracy);this.C("altitude",null===c.altitude?void 0:c.altitude);this.C("altitudeAccuracy",null===c.altitudeAccuracy?void 0:c.altitudeAccuracy);this.C("heading",null===c.heading?void 0:Sa(c.heading));this.a?(this.a[0]=c.longitude,this.a[1]=c.latitude):this.a=[c.longitude,c.latitude];a=this.f(this.a);this.C("position",a);this.C("speed",null===c.speed?void 0:c.speed);a=this.a;var d=c.accuracy,c=[],e;for(e=0;32>e;++e)eb(c,er.offset(a,d,2*Math.PI*e/ -32));c.push(c[0],c[1]);a=new C(null);$e(a,"XY",c,[c.length]);a.pb(this.f);this.C("accuracyGeometry",a);this.v()};k.Mj=function(a){a.type="error";this.Ec(!1);this.b(a)};k.ig=function(){return this.get("accuracy")};k.jg=function(){return this.get("accuracyGeometry")||null};k.lg=function(){return this.get("altitude")};k.mg=function(){return this.get("altitudeAccuracy")};k.Zh=function(){return this.get("heading")};k.$h=function(){return this.get("position")};k.Ie=function(){return this.get("projection")}; -k.Vg=function(){return this.get("speed")};k.Je=function(){return this.get("tracking")};k.Ce=function(){return this.get("trackingOptions")};k.Ke=function(a){this.C("projection",a)};k.Ec=function(a){this.C("tracking",a)};k.yf=function(a){this.C("trackingOptions",a)};function W(a,c,d){z.call(this);this.Rd(a,c?c:0,d)}x(W,z);k=W.prototype;k.clone=function(){var a=new W(null);xe(a,this.c,this.o.slice());a.v();return a};k.Aa=function(a,c,d,e){var f=this.o;a-=f[0];var g=c-f[1];c=a*a+g*g;if(c<e){if(0===c)for(e=0;e<this.a;++e)d[e]=f[e];else for(e=this.Qe()/Math.sqrt(c),d[0]=f[0]+e*a,d[1]=f[1]+e*g,e=2;e<this.a;++e)d[e]=f[e];d.length=this.a;return c}return e};k.ib=function(a,c){var d=this.o,e=a-d[0],d=c-d[1];return e*e+d*d<=gr(this)}; -k.Gc=function(){return this.o.slice(0,this.a)};k.pc=function(a){var c=this.o,d=c[this.a]-c[0];return yd(c[0]-d,c[1]-d,c[0]+d,c[1]+d,a)};k.Qe=function(){return Math.sqrt(gr(this))};function gr(a){var c=a.o[a.a]-a.o[0];a=a.o[a.a+1]-a.o[1];return c*c+a*a}k.N=function(){return"Circle"};k.pa=function(a){var c=this.F();return Ud(a,c)?(c=this.Gc(),a[0]<=c[0]&&a[2]>=c[0]||a[1]<=c[1]&&a[3]>=c[1]?!0:Ld(a,this.le,this)):!1}; -k.ki=function(a){var c=this.a,d=a.slice();d[c]=d[0]+(this.o[c]-this.o[0]);var e;for(e=1;e<c;++e)d[c+e]=a[e];xe(this,this.c,d);this.v()};k.Rd=function(a,c,d){if(a){ye(this,d,a,0);this.o||(this.o=[]);d=this.o;a=Ge(d,a);d[a++]=d[0]+c;var e;c=1;for(e=this.a;c<e;++c)d[a++]=d[c];d.length=a}else xe(this,"XY",null);this.v()};k.jk=function(a){this.o[this.a]=this.o[0]+a;this.v()};function hr(a,c,d,e,f,g,h){wi.call(this,a,c,d,0,e);this.l=f;this.a=new Image;null!==g&&(this.a.crossOrigin=g);this.i={};this.g=null;this.state=0;this.j=h}x(hr,wi);hr.prototype.f=function(a){if(void 0!==a){var c;a=na(a);if(a in this.i)return this.i[a];Gb(this.i)?c=this.a:c=this.a.cloneNode(!1);return this.i[a]=c}return this.a};hr.prototype.s=function(){this.state=3;this.g.forEach(Nc);this.g=null;yi(this)}; -hr.prototype.u=function(){void 0===this.resolution&&(this.resolution=Qd(this.extent)/this.a.height);this.state=2;this.g.forEach(Nc);this.g=null;yi(this)};hr.prototype.load=function(){0==this.state&&(this.state=1,yi(this),this.g=[Lc(this.a,"error",this.s,!1,this),Lc(this.a,"load",this.u,!1,this)],this.j(this,this.l))};function ir(a,c,d,e,f){og.call(this,a,c);this.j=d;this.c=new Image;null!==e&&(this.c.crossOrigin=e);this.f={};this.i=null;this.A=f}x(ir,og);k=ir.prototype;k.Z=function(){1==this.state&&jr(this);this.g&&kc(this.g);ir.fa.Z.call(this)};k.xb=function(a){if(void 0!==a){var c=na(a);if(c in this.f)return this.f[c];a=Gb(this.f)?this.c:this.c.cloneNode(!1);return this.f[c]=a}return this.c};k.Hd=function(){return this.j};k.ci=function(){this.state=3;jr(this);pg(this)}; -k.di=function(){this.state=this.c.naturalWidth&&this.c.naturalHeight?2:4;jr(this);pg(this)};k.load=function(){0==this.state&&(this.state=1,pg(this),this.i=[Lc(this.c,"error",this.ci,!1,this),Lc(this.c,"load",this.di,!1,this)],this.A(this,this.j))};function jr(a){a.i.forEach(Nc);a.i=null};function kr(a,c){lc.call(this,a);this.feature=c}x(kr,lc); -function lr(a){oj.call(this,{handleDownEvent:mr,handleEvent:nr,handleUpEvent:or});this.ea=null;this.J=!1;this.cb=a.source?a.source:null;this.Va=a.features?a.features:null;this.Hf=a.snapTolerance?a.snapTolerance:12;this.Y=a.type;this.c=pr(this.Y);this.Ga=a.minPoints?a.minPoints:this.c===qr?3:2;this.qa=a.maxPoints?a.maxPoints:Infinity;var c=a.geometryFunction;if(!c)if("Circle"===this.Y)c=function(a,c){var d=c?c:new W([NaN,NaN]);d.Rd(a[0],Math.sqrt(md(a[0],a[1])));return d};else{var d,c=this.c;c===rr? -d=A:c===sr?d=Q:c===qr&&(d=C);c=function(a,c){var g=c;g?g.da(a):g=new d(a);return g}}this.D=c;this.I=this.u=this.a=this.B=this.i=this.j=null;this.Pf=a.clickTolerance?a.clickTolerance*a.clickTolerance:36;this.ja=new J({source:new N({useSpatialIndex:!1,wrapX:a.wrapX?a.wrapX:!1}),style:a.style?a.style:tr()});this.bb=a.geometryName;this.Zc=a.condition?a.condition:kj;this.na=a.freehandCondition?a.freehandCondition:lj;y(this,$c("active"),this.Cf,!1,this)}x(lr,oj); -function tr(){var a=wk();return function(c){return a[c.O().N()]}}k=lr.prototype;k.setMap=function(a){lr.fa.setMap.call(this,a);this.Cf()};function nr(a){var c=!this.J;this.J&&a.type===qi?(ur(this,a),c=!1):a.type===pi?c=vr(this,a):a.type===ji&&(c=!1);return pj.call(this,a)&&c}function mr(a){if(this.Zc(a))return this.ea=a.pixel,!0;if(this.c!==sr&&this.c!==qr||!this.na(a))return!1;this.ea=a.pixel;this.J=!0;this.j||wr(this,a);return!0} -function or(a){this.J=!1;var c=this.ea,d=a.pixel,e=c[0]-d[0],c=c[1]-d[1],d=!0;e*e+c*c<=this.Pf&&(vr(this,a),this.j?this.c===xr?this.Qb():yr(this,a)?this.Qb():ur(this,a):(wr(this,a),this.c===rr&&this.Qb()),d=!1);return d} -function vr(a,c){if(a.j){var d=c.coordinate,e=a.i.O(),f;a.c===rr?f=a.a:a.c===qr?(f=a.a[0],f=f[f.length-1],yr(a,c)&&(d=a.j.slice())):(f=a.a,f=f[f.length-1]);f[0]=d[0];f[1]=d[1];a.D(a.a,e);a.B&&a.B.O().da(d);e instanceof C&&a.c!==qr?(a.u||(a.u=new Kl(new Q(null))),e=e.ve(0),d=a.u.O(),Yn(d,e.c,e.ba())):a.I&&(d=a.u.O(),d.da(a.I));zr(a)}else d=c.coordinate.slice(),a.B?a.B.O().da(d):(a.B=new Kl(new A(d)),zr(a));return!0} -function yr(a,c){var d=!1;if(a.i){var e=!1,f=[a.j];a.c===sr?e=a.a.length>a.Ga:a.c===qr&&(e=a.a[0].length>a.Ga,f=[a.a[0][0],a.a[0][a.a[0].length-2]]);if(e)for(var e=c.map,g=0,h=f.length;g<h;g++){var l=f[g],m=e.xa(l),n=c.pixel,d=n[0]-m[0],m=n[1]-m[1],n=a.J&&a.na(c)?1:a.Hf;if(d=Math.sqrt(d*d+m*m)<=n){a.j=l;break}}}return d} -function wr(a,c){var d=c.coordinate;a.j=d;a.c===rr?a.a=d.slice():a.c===qr?(a.a=[[d.slice(),d.slice()]],a.I=a.a[0]):(a.a=[d.slice(),d.slice()],a.c===xr&&(a.I=a.a));a.I&&(a.u=new Kl(new Q(a.I)));d=a.D(a.a);a.i=new Kl;a.bb&&a.i.Uc(a.bb);a.i.Sa(d);zr(a);a.b(new kr("drawstart",a.i))} -function ur(a,c){var d=c.coordinate,e=a.i.O(),f,g;if(a.c===sr)a.j=d.slice(),g=a.a,g.push(d.slice()),f=g.length>a.qa,a.D(g,e);else if(a.c===qr){g=a.a[0];g.push(d.slice());if(f=g.length>a.qa)a.j=g[0];a.D(a.a,e)}zr(a);f&&a.Qb()}k.Uj=function(){var a=this.i.O(),c,d;this.c===sr?(c=this.a,c.splice(-2,1),this.D(c,a)):this.c===qr&&(c=this.a[0],c.splice(-2,1),d=this.u.O(),d.da(c),this.D(this.a,a));0===c.length&&(this.j=null);zr(this)}; -k.Qb=function(){var a=Ar(this),c=this.a,d=a.O();this.c===sr?(c.pop(),this.D(c,d)):this.c===qr&&(c[0].pop(),c[0].push(c[0][0]),this.D(c,d));"MultiPoint"===this.Y?a.Sa(new S([c])):"MultiLineString"===this.Y?a.Sa(new R([c])):"MultiPolygon"===this.Y&&a.Sa(new T([c]));this.b(new kr("drawend",a));this.Va&&this.Va.push(a);this.cb&&this.cb.Lc(a)};function Ar(a){a.j=null;var c=a.i;c&&(a.i=null,a.B=null,a.u=null,a.ja.ha().clear(!0));return c} -k.si=function(a){var c=a.O();this.i=a;this.a=c.R();a=this.a[this.a.length-1];this.j=a.slice();this.a.push(a.slice());zr(this);this.b(new kr("drawstart",this.i))};k.mb=Wd;function zr(a){var c=[];a.i&&c.push(a.i);a.u&&c.push(a.u);a.B&&c.push(a.B);a=a.ja.ha();a.clear(!0);a.ad(c)}k.Cf=function(){var a=this.G,c=this.l();a&&c||Ar(this);this.ja.setMap(c?a:null)}; -function pr(a){var c;"Point"===a||"MultiPoint"===a?c=rr:"LineString"===a||"MultiLineString"===a?c=sr:"Polygon"===a||"MultiPolygon"===a?c=qr:"Circle"===a&&(c=xr);return c}var rr="Point",sr="LineString",qr="Polygon",xr="Circle";function Br(a,c,d){lc.call(this,a);this.features=c;this.mapBrowserPointerEvent=d}x(Br,lc); -function Cr(a){oj.call(this,{handleDownEvent:Dr,handleDragEvent:Er,handleEvent:Fr,handleUpEvent:Gr});this.qa=a.deleteCondition?a.deleteCondition:Zd(kj,jj);this.na=this.c=null;this.ea=[0,0];this.D=this.J=!1;this.a=new cn;this.B=void 0!==a.pixelTolerance?a.pixelTolerance:10;this.j=this.ja=!1;this.i=null;this.I=new J({source:new N({useSpatialIndex:!1,wrapX:!!a.wrapX}),style:a.style?a.style:Hr(),updateWhileAnimating:!0,updateWhileInteracting:!0});this.Y={Point:this.zi,LineString:this.Te,LinearRing:this.Te, -Polygon:this.Ai,MultiPoint:this.xi,MultiLineString:this.wi,MultiPolygon:this.yi,GeometryCollection:this.vi};this.u=a.features;this.u.forEach(this.Jd,this);y(this.u,"add",this.ti,!1,this);y(this.u,"remove",this.ui,!1,this)}x(Cr,oj);k=Cr.prototype;k.Jd=function(a){var c=a.O();c.N()in this.Y&&this.Y[c.N()].call(this,a,c);(c=this.G)&&Ir(this,this.ea,c);y(a,"change",this.Se,!1,this)};function Jr(a,c){a.D||(a.D=!0,a.b(new Br("modifystart",a.u,c)))} -function Kr(a,c){Lr(a,c);a.c&&0===a.u.gb()&&(a.I.ha().fc(a.c),a.c=null);Mc(c,"change",a.Se,!1,a)}function Lr(a,c){var d=a.a,e=[];d.forEach(function(a){c===a.feature&&e.push(a)});for(var f=e.length-1;0<=f;--f)d.remove(e[f])}k.setMap=function(a){this.I.setMap(a);Cr.fa.setMap.call(this,a)};k.ti=function(a){this.Jd(a.element)};k.Se=function(a){this.j||(a=a.target,Kr(this,a),this.Jd(a))};k.ui=function(a){Kr(this,a.element)}; -k.zi=function(a,c){var d=c.R(),d={feature:a,geometry:c,ca:[d,d]};this.a.ka(c.F(),d)};k.xi=function(a,c){var d=c.R(),e,f,g;f=0;for(g=d.length;f<g;++f)e=d[f],e={feature:a,geometry:c,depth:[f],index:f,ca:[e,e]},this.a.ka(c.F(),e)};k.Te=function(a,c){var d=c.R(),e,f,g,h;e=0;for(f=d.length-1;e<f;++e)g=d.slice(e,e+2),h={feature:a,geometry:c,index:e,ca:g},this.a.ka(ud(g),h)}; -k.wi=function(a,c){var d=c.R(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:a,geometry:c,depth:[h],index:f,ca:m},this.a.ka(ud(m),n)};k.Ai=function(a,c){var d=c.R(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:a,geometry:c,depth:[h],index:f,ca:m},this.a.ka(ud(m),n)}; -k.yi=function(a,c){var d=c.R(),e,f,g,h,l,m,n,p,q,r;m=0;for(n=d.length;m<n;++m)for(p=d[m],h=0,l=p.length;h<l;++h)for(e=p[h],f=0,g=e.length-1;f<g;++f)q=e.slice(f,f+2),r={feature:a,geometry:c,depth:[h,m],index:f,ca:q},this.a.ka(ud(q),r)};k.vi=function(a,c){var d,e=c.a;for(d=0;d<e.length;++d)this.Y[e[d].N()].call(this,a,e[d])};function Mr(a,c){var d=a.c;d?d.O().da(c):(d=new Kl(new A(c)),a.c=d,a.I.ha().Lc(d))}function Nr(a,c){return a.index-c.index} -function Dr(a){Ir(this,a.pixel,a.map);this.i=[];this.D=!1;var c=this.c;if(c){var d=[],c=c.O().R(),e=ud([c]),e=fn(this.a,e),f={};e.sort(Nr);for(var g=0,h=e.length;g<h;++g){var l=e[g],m=l.ca,n=na(l.feature),p=l.depth;p&&(n+="-"+p.join("-"));f[n]||(f[n]=Array(2));if(kd(m[0],c)&&!f[n][0])this.i.push([l,0]),f[n][0]=l;else if(kd(m[1],c)&&!f[n][1]){if("LineString"!==l.geometry.N()&&"MultiLineString"!==l.geometry.N()||!f[n][0]||0!==f[n][0].index)this.i.push([l,1]),f[n][1]=l}else na(m)in this.na&&!f[n][0]&& -!f[n][1]&&d.push([l,c])}d.length&&Jr(this,a);for(g=d.length-1;0<=g;--g)this.Dh.apply(this,d[g])}return!!this.c} -function Er(a){this.J=!1;Jr(this,a);a=a.coordinate;for(var c=0,d=this.i.length;c<d;++c){for(var e=this.i[c],f=e[0],g=f.depth,h=f.geometry,l=h.R(),m=f.ca,e=e[1];a.length<h.la();)a.push(0);switch(h.N()){case "Point":l=a;m[0]=m[1]=a;break;case "MultiPoint":l[f.index]=a;m[0]=m[1]=a;break;case "LineString":l[f.index+e]=a;m[e]=a;break;case "MultiLineString":l[g[0]][f.index+e]=a;m[e]=a;break;case "Polygon":l[g[0]][f.index+e]=a;m[e]=a;break;case "MultiPolygon":l[g[1]][g[0]][f.index+e]=a,m[e]=a}f=h;this.j= -!0;f.da(l);this.j=!1}Mr(this,a)}function Gr(a){for(var c,d=this.i.length-1;0<=d;--d)c=this.i[d][0],dn(this.a,ud(c.ca),c);this.D&&(this.b(new Br("modifyend",this.u,a)),this.D=!1);return!1} -function Fr(a){if(!(a instanceof fi))return!0;var c;a.map.ga().a.slice()[1]||a.type!=pi||this.H||(this.ea=a.pixel,Ir(this,a.pixel,a.map));if(this.c&&this.qa(a))if(a.type==ki&&this.J)c=!0;else{this.c.O();Jr(this,a);c=this.i;var d={},e,f,g,h,l,m,n,p,q;for(l=c.length-1;0<=l;--l)if(g=c[l],p=g[0],h=p.geometry,f=h.R(),q=na(p.feature),p.depth&&(q+="-"+p.depth.join("-")),n=e=m=void 0,0===g[1]?(e=p,m=p.index):1==g[1]&&(n=p,m=p.index+1),q in d||(d[q]=[n,e,m]),g=d[q],void 0!==n&&(g[0]=n),void 0!==e&&(g[1]=e), -void 0!==g[0]&&void 0!==g[1]){e=f;q=!1;n=m-1;switch(h.N()){case "MultiLineString":f[p.depth[0]].splice(m,1);q=!0;break;case "LineString":f.splice(m,1);q=!0;break;case "MultiPolygon":e=e[p.depth[1]];case "Polygon":e=e[p.depth[0]],4<e.length&&(m==e.length-1&&(m=0),e.splice(m,1),q=!0,0===m&&(e.pop(),e.push(e[0]),n=e.length-1))}q&&(this.a.remove(g[0]),this.a.remove(g[1]),e=h,this.j=!0,e.da(f),this.j=!1,f={depth:p.depth,feature:p.feature,geometry:p.geometry,index:n,ca:[g[0].ca[0],g[1].ca[1]]},this.a.ka(ud(f.ca), -f),Or(this,h,m,p.depth,-1),this.c&&(this.I.ha().fc(this.c),this.c=null))}c=!0;this.b(new Br("modifyend",this.u,a));this.D=!1}a.type==ki&&(this.J=!1);return pj.call(this,a)&&!c} -function Ir(a,c,d){function e(a,c){return nd(f,a.ca)-nd(f,c.ca)}var f=d.ra(c),g=d.ra([c[0]-a.B,c[1]+a.B]),h=d.ra([c[0]+a.B,c[1]-a.B]),g=ud([g,h]),g=fn(a.a,g);if(0<g.length){g.sort(e);var h=g[0].ca,l=hd(f,h),m=d.xa(l);if(Math.sqrt(md(c,m))<=a.B){c=d.xa(h[0]);d=d.xa(h[1]);c=md(m,c);d=md(m,d);a.ja=Math.sqrt(Math.min(c,d))<=a.B;a.ja&&(l=c>d?h[1]:h[0]);Mr(a,l);d={};d[na(h)]=!0;c=1;for(m=g.length;c<m;++c)if(l=g[c].ca,kd(h[0],l[0])&&kd(h[1],l[1])||kd(h[0],l[1])&&kd(h[1],l[0]))d[na(l)]=!0;else break;a.na= -d;return}}a.c&&(a.I.ha().fc(a.c),a.c=null)} -k.Dh=function(a,c){for(var d=a.ca,e=a.feature,f=a.geometry,g=a.depth,h=a.index,l;c.length<f.la();)c.push(0);switch(f.N()){case "MultiLineString":l=f.R();l[g[0]].splice(h+1,0,c);break;case "Polygon":l=f.R();l[g[0]].splice(h+1,0,c);break;case "MultiPolygon":l=f.R();l[g[1]][g[0]].splice(h+1,0,c);break;case "LineString":l=f.R();l.splice(h+1,0,c);break;default:return}this.j=!0;f.da(l);this.j=!1;l=this.a;l.remove(a);Or(this,f,h,g,1);var m={ca:[d[0],c],feature:e,geometry:f,depth:g,index:h};l.ka(ud(m.ca), -m);this.i.push([m,1]);d={ca:[c,d[1]],feature:e,geometry:f,depth:g,index:h+1};l.ka(ud(d.ca),d);this.i.push([d,0]);this.J=!0};function Or(a,c,d,e,f){hn(a.a,c.F(),function(a){a.geometry===c&&(void 0===e||void 0===a.depth||nb(a.depth,e))&&a.index>d&&(a.index+=f)})}function Hr(){var a=wk();return function(){return a.Point}};function Pr(a,c,d,e){lc.call(this,a);this.selected=c;this.deselected=d;this.mapBrowserEvent=e}x(Pr,lc); -function Qr(a){cj.call(this,{handleEvent:Rr});a=a?a:{};this.H=a.condition?a.condition:jj;this.j=a.addCondition?a.addCondition:Wd;this.D=a.removeCondition?a.removeCondition:Wd;this.B=a.toggleCondition?a.toggleCondition:lj;this.u=a.multi?a.multi:!1;this.f=a.filter?a.filter:Xd;var c;if(a.layers)if(la(a.layers))c=a.layers;else{var d=a.layers;c=function(a){return 0<=d.indexOf(a)}}else c=Xd;this.i=c;this.a={};this.c=new J({source:new N({useSpatialIndex:!1,features:a.features,wrapX:a.wrapX}),style:a.style? -a.style:Sr(),updateWhileAnimating:!0,updateWhileInteracting:!0});a=this.c.ha().c;y(a,"add",this.Bi,!1,this);y(a,"remove",this.Ei,!1,this)}x(Qr,cj);k=Qr.prototype;k.Ci=function(){return this.c.ha().c};k.Di=function(a){a=na(a);return this.a[a]}; -function Rr(a){if(!this.H(a))return!0;var c=this.j(a),d=this.D(a),e=this.B(a),f=!c&&!d&&!e,g=a.map,h=this.c.ha().c,l=[],m=[],n=!1;if(f)g.nd(a.pixel,function(a,c){if(c&&this.f(a,c)){m.push(a);var d=na(a);this.a[d]=c;return!this.u}},this,this.i),0<m.length&&1==h.gb()&&h.item(0)==m[0]||(n=!0,0!==h.gb()&&(l=Array.prototype.concat(h.a),h.clear()),h.Dd(m),0===m.length?Hb(this.a):0<l.length&&l.forEach(function(a){a=na(a);delete this.a[a]},this));else{g.nd(a.pixel,function(a,f){if(!(0<=h.a.indexOf(a))){if((c|| -e)&&this.f(a,f)){m.push(a);var g=na(a);this.a[g]=f}}else if(d||e)l.push(a),g=na(a),delete this.a[g]},this,this.i);for(f=l.length-1;0<=f;--f)h.remove(l[f]);h.Dd(m);if(0<m.length||0<l.length)n=!0}n&&this.b(new Pr("select",m,l,a));return"pointermove"==a.type}k.setMap=function(a){var c=this.G,d=this.c.ha().c;null===c||d.forEach(c.Af,c);Qr.fa.setMap.call(this,a);this.c.setMap(a);null===a||d.forEach(a.zf,a)}; -function Sr(){var a=wk();eb(a.Polygon,a.LineString);eb(a.GeometryCollection,a.LineString);return function(c){return a[c.O().N()]}}k.Bi=function(a){a=a.element;var c=this.G;null===c||c.zf(a)};k.Ei=function(a){a=a.element;var c=this.G;null===c||c.Af(a)};function Tr(a){oj.call(this,{handleEvent:Ur,handleDownEvent:Xd,handleUpEvent:Vr});a=a?a:{};this.j=a.source?a.source:null;this.i=a.features?a.features:null;this.ea=[];this.D={};this.B={};this.J={};this.u={};this.I=null;this.c=void 0!==a.pixelTolerance?a.pixelTolerance:10;this.ja=sa(Wr,this);this.a=new cn;this.Y={Point:this.Ki,LineString:this.We,LinearRing:this.We,Polygon:this.Li,MultiPoint:this.Ii,MultiLineString:this.Hi,MultiPolygon:this.Ji,GeometryCollection:this.Gi}}x(Tr,oj);k=Tr.prototype; -k.Zb=function(a,c){var d=void 0!==c?c:!0,e=a.O(),f=this.Y[e.N()];if(f){var g=na(a);this.J[g]=e.F(vd());f.call(this,a,e);d&&(this.B[g]=e.M("change",sa(this.gh,this,a),this),this.D[g]=a.M($c(a.a),this.Fi,this))}};k.eg=function(a){this.Zb(a)};k.gg=function(a){this.$b(a)};k.Ue=function(a){var c;a instanceof nn?c=a.feature:a instanceof rf&&(c=a.element);this.Zb(c)};k.Ve=function(a){var c;a instanceof nn?c=a.feature:a instanceof rf&&(c=a.element);this.$b(c)}; -k.Fi=function(a){a=a.g;this.$b(a,!0);this.Zb(a,!0)};k.gh=function(a){if(this.H){var c=na(a);c in this.u||(this.u[c]=a)}else this.Bf(a)};k.$b=function(a,c){var d=void 0!==c?c:!0,e=na(a),f=this.J[e];if(f){var g=this.a,h=[];hn(g,f,function(c){a===c.feature&&h.push(c)});for(f=h.length-1;0<=f;--f)g.remove(h[f]);d&&(Nc(this.B[e]),delete this.B[e],Nc(this.D[e]),delete this.D[e])}}; -k.setMap=function(a){var c=this.G,d=this.ea,e;this.i?e=this.i:this.j&&(e=this.j.af());c&&(d.forEach(Wc),d.length=0,e.forEach(this.gg,this));Tr.fa.setMap.call(this,a);a&&(this.i?(d.push(this.i.M("add",this.Ue,this)),d.push(this.i.M("remove",this.Ve,this))):this.j&&(d.push(this.j.M("addfeature",this.Ue,this)),d.push(this.j.M("removefeature",this.Ve,this))),e.forEach(this.eg,this))};k.mb=Wd;k.Bf=function(a){this.$b(a,!1);this.Zb(a,!1)}; -k.Gi=function(a,c){var d,e=c.a;for(d=0;d<e.length;++d)this.Y[e[d].N()].call(this,a,e[d])};k.We=function(a,c){var d=c.R(),e,f,g,h;e=0;for(f=d.length-1;e<f;++e)g=d.slice(e,e+2),h={feature:a,ca:g},this.a.ka(ud(g),h)};k.Hi=function(a,c){var d=c.R(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:a,ca:m},this.a.ka(ud(m),n)};k.Ii=function(a,c){var d=c.R(),e,f,g;f=0;for(g=d.length;f<g;++f)e=d[f],e={feature:a,ca:[e,e]},this.a.ka(c.F(),e)}; -k.Ji=function(a,c){var d=c.R(),e,f,g,h,l,m,n,p,q,r;m=0;for(n=d.length;m<n;++m)for(p=d[m],h=0,l=p.length;h<l;++h)for(e=p[h],f=0,g=e.length-1;f<g;++f)q=e.slice(f,f+2),r={feature:a,ca:q},this.a.ka(ud(q),r)};k.Ki=function(a,c){var d=c.R(),d={feature:a,ca:[d,d]};this.a.ka(c.F(),d)};k.Li=function(a,c){var d=c.R(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:a,ca:m},this.a.ka(ud(m),n)}; -function Ur(a){var c,d,e=a.pixel,f=a.coordinate;c=a.map;var g=c.ra([e[0]-this.c,e[1]+this.c]);d=c.ra([e[0]+this.c,e[1]-this.c]);var g=ud([g,d]),h=fn(this.a,g),l=!1,g=!1,m=null;d=null;0<h.length&&(this.I=f,h.sort(this.ja),h=h[0].ca,m=hd(f,h),d=c.xa(m),Math.sqrt(md(e,d))<=this.c&&(g=!0,e=c.xa(h[0]),f=c.xa(h[1]),e=md(d,e),f=md(d,f),l=Math.sqrt(Math.min(e,f))<=this.c))&&(m=e>f?h[1]:h[0],d=c.xa(m),d=[Math.round(d[0]),Math.round(d[1])]);c=m;g&&(a.coordinate=c.slice(0,2),a.pixel=d);return pj.call(this,a)} -function Vr(){var a=Eb(this.u);a.length&&(a.forEach(this.Bf,this),this.u={});return!1}function Wr(a,c){return nd(this.I,a.ca)-nd(this.I,c.ca)};function Xr(a,c,d,e,f,g,h,l,m,n,p){og.call(this,[f,g,h],0);this.D=void 0!==p?p:!1;this.H=l;this.j=null;this.i={};this.A=c;this.s=e;this.c=[];this.f=null;this.l=0;h=e.Ca(this.a);p=this.s.F();g=this.A.F();h=p?Td(h,p):h;if(0===Nd(h))this.state=4;else if((p=a.F())&&(g?g=Td(g,p):g=p),e=e.$(f),e=tl(a,d,Rd(h),e),!isFinite(e)||isNaN(e)||0>=e)this.state=4;else if(this.u=new wl(a,d,h,g,e*(void 0!==n?n:.5)),0===this.u.c.length)this.state=4;else if(this.l=Ag(c,e),d=yl(this.u),g&&(a.a?(d[1]=Pa(d[1],g[1],g[3]), -d[3]=Pa(d[3],g[1],g[3])):d=Td(d,g)),Nd(d))if(a=c.Wa(d,this.l),100>(a.a-a.b+1)*qf(a)){for(c=a.b;c<=a.a;c++)for(d=a.c;d<=a.g;d++)(n=m(this.l,c,d,l))&&this.c.push(n);0===this.c.length&&(this.state=4)}else this.state=3;else this.state=4}x(Xr,og);Xr.prototype.Z=function(){1==this.state&&(this.f.forEach(Nc),this.f=null);Xr.fa.Z.call(this)};Xr.prototype.xb=function(a){if(void 0!==a){var c=na(a);if(c in this.i)return this.i[c];a=Gb(this.i)?this.j:this.j.cloneNode(!1);return this.i[c]=a}return this.j}; -function Yr(a){var c=[];a.c.forEach(function(a){a&&2==a.state&&c.push({extent:this.A.Ca(a.a),image:a.xb()})},a);a.c.length=0;var d=a.a,e=d[0],f=a.s.Ia(e),g=ka(f)?f:f[0],f=ka(f)?f:f[1],e=a.s.$(e),h=a.A.$(a.l),d=a.s.Ca(d);a.j=vl(g,f,a.H,h,a.A.F(),e,d,a.u,c,a.D);a.state=2;pg(a)} -Xr.prototype.load=function(){if(0==this.state){this.state=1;pg(this);var a=0;this.f=[];this.c.forEach(function(c){var d=c.state;if(0==d||1==d){a++;var e;e=Fc(c,"change",function(){var d=c.state;if(2==d||3==d||4==d)Nc(e),a--,0===a&&(this.f.forEach(Nc),this.f=null,Yr(this))},!1,this);this.f.push(e)}},this);this.c.forEach(function(a){0==a.state&&a.load()});0===a&&Yr(this)}};function X(a){yn.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,opaque:a.opaque,projection:a.projection,state:void 0!==a.state?a.state:void 0,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction?a.tileLoadFunction:Zr,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:a.tileUrlFunction,url:a.url,urls:a.urls,wrapX:a.wrapX});this.crossOrigin=void 0!==a.crossOrigin?a.crossOrigin:null;this.tileClass=void 0!==a.tileClass?a.tileClass:ir;this.i={};this.s={};this.Ga=a.reprojectionErrorThreshold; -this.I=!1}x(X,yn);k=X.prototype;k.Ze=function(){return mg(this.a)?!0:Cb(this.i,function(a){return mg(a)})};k.$e=function(a,c){var d=this.Vb(a);ng(this.a,this.a==d?c:{});Bb(this.i,function(a){ng(a,a==d?c:{})})};k.Ra=function(a){var c=this.j;return!this.tileGrid||c&&!pe(c,a)?(c=na(a).toString(),c in this.s||(this.s[c]=Bg(a)),this.s[c]):this.tileGrid};k.Vb=function(a){var c=this.j;if(!c||pe(c,a))return this.a;a=na(a).toString();a in this.i||(this.i[a]=new lg);return this.i[a]}; -function $r(a,c,d,e,f,g,h){e=c=[c,d,e];var l=void 0!==g?g:a.j;d=a.Ra(l);if(a.D&&l.c){var m=e;e=m[0];var n=zg(d,m),l=Cg(l);Cd(l,n)?e=m:(m=Pd(l),n[0]+=m*Math.ceil((l[0]-n[0])/m),e=d.ud(n,e))}m=e[0];n=e[1];l=e[2];if(d.minZoom>m||m>d.maxZoom)d=!1;else{var p=d.F();d=(d=p?d.Wa(p,m):d.a?d.a[m]:null)?of(d,n,l):!0}f=(d=d?e:null)?a.tileUrlFunction(d,f,g):void 0;f=new a.tileClass(c,void 0!==f?0:4,void 0!==f?f:"",a.crossOrigin,a.tileLoadFunction);f.key=h;y(f,"change",a.aj,!1,a);return f} -function Ki(a,c,d,e,f,g){if(a.j&&g&&!pe(a.j,g)){f=a.Vb(g);var h=a.rb(c,d,e);if(f.g.hasOwnProperty(h))return f.get(h);var l=a.j,m=a.Ra(l),n=a.Ra(g);a=new Xr(l,m,g,n,c,d,e,a.na,sa(function(a,c,d,e){return as(this,a,c,d,e,l)},a),a.Ga,a.I);kg(f,h,a);return a}return as(a,c,d,e,f,g)} -function as(a,c,d,e,f,g){var h=null,l=a.rb(c,d,e),m=a.te();if(a.a.g.hasOwnProperty(l)){if(h=a.a.get(l),h.key!=m){var n=h;h.g&&h.g.key==m?(h=h.g,2==n.state&&(h.g=n)):(h=$r(a,c,d,e,f,g,m),2==n.state?h.g=n:n.g&&2==n.g.state&&(h.g=n.g,n.g=null));h.g&&(h.g.g=null);a.a.replace(l,h)}}else h=$r(a,c,d,e,f,g,m),kg(a.a,l,h);return h}k.Ud=function(a){this.I!=a&&(this.I=a,Bb(this.i,function(a){a.clear()}),this.v())};k.Wd=function(a,c){var d=fe(a);d&&(d=na(d).toString(),d in this.s||(this.s[d]=c))}; -function Zr(a,c){a.xb().src=c};function bs(a){a=a||{};Bl.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions});this.ja=void 0!==a.crossOrigin?a.crossOrigin:null;this.i=a.url;this.B=void 0!==a.imageLoadFunction?a.imageLoadFunction:Il;this.f=a.params;this.s=!0;cs(this);this.aa=a.serverType;this.qa=void 0!==a.hidpi?a.hidpi:!0;this.c=null;this.I=[0,0];this.J=0;this.l=void 0!==a.ratio?a.ratio:1.5}x(bs,Bl);var ds=[101,101];k=bs.prototype; -k.Ui=function(a,c,d,e){if(void 0!==this.i){var f=Sd(a,c,0,ds),g={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.f.LAYERS};Nb(g,this.f,e);e=Math.floor((f[3]-a[1])/c);g[this.s?"I":"X"]=Math.floor((a[0]-f[0])/c);g[this.s?"J":"Y"]=e;return es(this,f,ds,1,fe(d),g)}};k.Vi=function(){return this.f}; -k.pd=function(a,c,d,e){if(void 0===this.i)return null;c=Cl(this,c);1==d||this.qa&&void 0!==this.aa||(d=1);a=a.slice();var f=(a[0]+a[2])/2,g=(a[1]+a[3])/2,h=c/d,l=Pd(a)/h,h=Qd(a)/h,m=this.c;if(m&&this.J==this.g&&m.$()==c&&m.c==d&&Ed(m.F(),a))return m;if(1!=this.l){var m=this.l*Pd(a)/2,n=this.l*Qd(a)/2;a[0]=f-m;a[1]=g-n;a[2]=f+m;a[3]=g+n}f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};Nb(f,this.f);this.I[0]=Math.ceil(l*this.l);this.I[1]=Math.ceil(h*this.l);e=es(this, -a,this.I,d,e,f);this.c=new hr(a,c,d,this.u,e,this.ja,this.B);this.J=this.g;y(this.c,"change",this.na,!1,this);return this.c};k.Cg=function(){return this.B}; -function es(a,c,d,e,f,g){g[a.s?"CRS":"SRS"]=f.b;"STYLES"in a.f||(g.STYLES=new String(""));if(1!=e)switch(a.aa){case "geoserver":e=90*e+.5|0;g.FORMAT_OPTIONS="FORMAT_OPTIONS"in g?g.FORMAT_OPTIONS+(";dpi:"+e):"dpi:"+e;break;case "mapserver":g.MAP_RESOLUTION=90*e;break;case "carmentaserver":case "qgis":g.DPI=90*e}g.WIDTH=d[0];g.HEIGHT=d[1];d=f.i;var h;a.s&&"ne"==d.substr(0,2)?h=[c[1],c[0],c[3],c[2]]:h=c;g.BBOX=h.join(",");return Xl(Zl([a.i],g))}k.Zg=function(){return this.i}; -k.ek=function(a){this.c=null;this.B=a;this.v()};k.Wi=function(a){a!=this.i&&(this.i=a,this.c=null,this.v())};k.Xi=function(a){Nb(this.f,a);cs(this);this.c=null;this.v()};function cs(a){a.s=0<=Na(Ib(a.f,"VERSION","1.3.0"),"1.3")};function Y(a){a=a||{};var c=void 0!==a.params?a.params:{};X.call(this,{attributions:a.attributions,crossOrigin:a.crossOrigin,logo:a.logo,opaque:!Ib(c,"TRANSPARENT",!0),projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction,tileUrlFunction:sa(this.rk,this),url:a.url,urls:a.urls,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.G=void 0!==a.gutter?a.gutter:0;this.c=c;this.l=!0;this.B=a.serverType;this.aa=void 0!==a.hidpi?a.hidpi: -!0;this.J="";fs(this);this.ea=vd();gs(this)}x(Y,X);k=Y.prototype; -k.Yi=function(a,c,d,e){d=fe(d);var f=this.tileGrid;f||(f=this.Ra(d));c=f.td(a,c);if(!(f.b.length<=c[0])){var g=f.$(c[0]),h=f.Ca(c,this.ea),f=dd(f.Ia(c[0]),this.f),l=this.G;0!==l&&(f=bd(f,l,this.f),h=zd(h,g*l,h));l={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.c.LAYERS};Nb(l,this.c,e);e=Math.floor((h[3]-a[1])/g);l[this.l?"I":"X"]=Math.floor((a[0]-h[0])/g);l[this.l?"J":"Y"]=e;return hs(this,c,f,h,1,d,l)}};k.qe=function(){return this.G}; -k.rb=function(a,c,d){return this.J+Y.fa.rb.call(this,a,c,d)};k.Zi=function(){return this.c}; -function hs(a,c,d,e,f,g,h){var l=a.urls;if(l){h.WIDTH=d[0];h.HEIGHT=d[1];h[a.l?"CRS":"SRS"]=g.b;"STYLES"in a.c||(h.STYLES=new String(""));if(1!=f)switch(a.B){case "geoserver":d=90*f+.5|0;h.FORMAT_OPTIONS="FORMAT_OPTIONS"in h?h.FORMAT_OPTIONS+(";dpi:"+d):"dpi:"+d;break;case "mapserver":h.MAP_RESOLUTION=90*f;break;case "carmentaserver":case "qgis":h.DPI=90*f}g=g.i;a.l&&"ne"==g.substr(0,2)&&(a=e[0],e[0]=e[1],e[1]=a,a=e[2],e[2]=e[3],e[3]=a);h.BBOX=e.join(",");return Xl(Zl([1==l.length?l[0]:l[ed((c[1]<< -c[0])+c[2],l.length)]],h))}}k.wc=function(a,c,d){a=Y.fa.wc.call(this,a,c,d);return 1!=c&&this.aa&&void 0!==this.B?cd(a,c,this.f):a};function fs(a){var c=0,d=[];if(a.urls){var e,f;e=0;for(f=a.urls.length;e<f;++e)d[c++]=a.urls[e]}for(var g in a.c)d[c++]=g+"-"+a.c[g];a.J=d.join("#")} -k.rk=function(a,c,d){var e=this.tileGrid;e||(e=this.Ra(d));if(!(e.b.length<=a[0])){1==c||this.aa&&void 0!==this.B||(c=1);var f=e.$(a[0]),g=e.Ca(a,this.ea),e=dd(e.Ia(a[0]),this.f),h=this.G;0!==h&&(e=bd(e,h,this.f),g=zd(g,f*h,g));1!=c&&(e=cd(e,c,this.f));f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};Nb(f,this.c);return hs(this,a,e,g,c,d,f)}};k.$i=function(a){Nb(this.c,a);fs(this);gs(this);this.v()};function gs(a){a.l=0<=Na(Ib(a.c,"VERSION","1.3.0"),"1.3")};function is(a){this.j=a.matrixIds;sg.call(this,{extent:a.extent,origin:a.origin,origins:a.origins,resolutions:a.resolutions,tileSize:a.tileSize,tileSizes:a.tileSizes,sizes:a.sizes})}x(is,sg);is.prototype.l=function(){return this.j};function Z(a){function c(a){a="KVP"==e?Xl(Zl([a],g)):a.replace(/\{(\w+?)\}/g,function(a,c){return c.toLowerCase()in g?g[c.toLowerCase()]:a});return function(c){if(c){var d={TileMatrix:f.j[c[0]],TileCol:c[1],TileRow:-c[2]-1};Nb(d,h);c=a;return c="KVP"==e?Xl(Zl([c],d)):c.replace(/\{(\w+?)\}/g,function(a,c){return d[c]})}}}this.ea=void 0!==a.version?a.version:"1.0.0";this.B=void 0!==a.format?a.format:"image/jpeg";this.c=void 0!==a.dimensions?a.dimensions:{};this.l="";js(this);this.J=a.layer;this.G=a.matrixSet; -this.aa=a.style;var d=a.urls;void 0===d&&void 0!==a.url&&(d=xn(a.url));var e=this.ja=void 0!==a.requestEncoding?a.requestEncoding:"KVP",f=a.tileGrid,g={layer:this.J,style:this.aa,tilematrixset:this.G};"KVP"==e&&Nb(g,{Service:"WMTS",Request:"GetTile",Version:this.ea,Format:this.B});var h=this.c,l=d&&0<d.length?vn(d.map(c)):wn;X.call(this,{attributions:a.attributions,crossOrigin:a.crossOrigin,logo:a.logo,projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileClass:a.tileClass, -tileGrid:f,tileLoadFunction:a.tileLoadFunction,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:l,urls:d,wrapX:void 0!==a.wrapX?a.wrapX:!1})}x(Z,X);k=Z.prototype;k.rg=function(){return this.c};k.bj=function(){return this.B};k.te=function(){return this.l};k.cj=function(){return this.J};k.Kg=function(){return this.G};k.Ug=function(){return this.ja};k.dj=function(){return this.aa};k.$g=function(){return this.ea};function js(a){var c=0,d=[],e;for(e in a.c)d[c++]=e+"-"+a.c[e];a.l=d.join("/")} -k.xk=function(a){Nb(this.c,a);js(this);this.v()};function ks(a){this.u=this.c=this.f=null;this.l=void 0!==a.fill?a.fill:null;this.ma=[0,0];this.b=a.points;this.g=void 0!==a.radius?a.radius:a.radius1;this.i=void 0!==a.radius2?a.radius2:this.g;this.A=void 0!==a.angle?a.angle:0;this.a=void 0!==a.stroke?a.stroke:null;this.ia=this.I=this.B=null;var c=a.atlasManager,d="",e="",f=0,g=null,h,l=0;this.a&&(h=yf(this.a.b),l=this.a.a,void 0===l&&(l=1),g=this.a.g,vh||(g=null),e=this.a.f,void 0===e&&(e="round"),d=this.a.c,void 0===d&&(d="round"),f=this.a.i,void 0=== -f&&(f=10));var m=2*(this.g+l)+1,d={strokeStyle:h,lc:l,size:m,lineCap:d,lineDash:g,lineJoin:e,miterLimit:f};if(void 0===c){this.c=document.createElement("CANVAS");this.c.height=m;this.c.width=m;var c=m=this.c.width,n=this.c.getContext("2d");this.ff(d,n,0,0);this.l?this.u=this.c:(n=this.u=document.createElement("CANVAS"),n.height=d.size,n.width=d.size,n=n.getContext("2d"),this.ef(d,n,0,0))}else m=Math.round(m),(e=!this.l)&&(n=sa(this.ef,this,d)),f=this.Ma(),n=c.add(f,m,m,sa(this.ff,this,d),n),this.c= -n.image,this.ma=[n.offsetX,n.offsetY],c=n.image.width,this.u=e?n.Ch:this.c;this.B=[m/2,m/2];this.I=[m,m];this.ia=[c,c];Mi.call(this,{opacity:1,rotateWithView:!1,rotation:void 0!==a.rotation?a.rotation:0,scale:1,snapToPixel:void 0!==a.snapToPixel?a.snapToPixel:!0})}x(ks,Mi);k=ks.prototype;k.eb=function(){return this.B};k.ij=function(){return this.A};k.jj=function(){return this.l};k.Md=function(){return this.u};k.jb=function(){return this.c};k.tc=function(){return this.ia};k.gc=function(){return 2}; -k.ta=function(){return this.ma};k.kj=function(){return this.b};k.lj=function(){return this.g};k.Tg=function(){return this.i};k.Ta=function(){return this.I};k.mj=function(){return this.a};k.Cd=wa;k.load=wa;k.Yd=wa; -k.ff=function(a,c,d,e){var f;c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();this.i!==this.g&&(this.b*=2);for(d=0;d<=this.b;d++)e=2*d*Math.PI/this.b-Math.PI/2+this.A,f=0===d%2?this.g:this.i,c.lineTo(a.size/2+f*Math.cos(e),a.size/2+f*Math.sin(e));this.l&&(c.fillStyle=yf(this.l.b),c.fill());this.a&&(c.strokeStyle=a.strokeStyle,c.lineWidth=a.lc,a.lineDash&&c.setLineDash(a.lineDash),c.lineCap=a.lineCap,c.lineJoin=a.lineJoin,c.miterLimit=a.miterLimit,c.stroke());c.closePath()}; -k.ef=function(a,c,d,e){c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();this.i!==this.g&&(this.b*=2);var f;for(d=0;d<=this.b;d++)f=2*d*Math.PI/this.b-Math.PI/2+this.A,e=0===d%2?this.g:this.i,c.lineTo(a.size/2+e*Math.cos(f),a.size/2+e*Math.sin(f));c.fillStyle=hk;c.fill();this.a&&(c.strokeStyle=a.strokeStyle,c.lineWidth=a.lc,a.lineDash&&c.setLineDash(a.lineDash),c.stroke());c.closePath()}; -k.Ma=function(){var a=this.a?this.a.Ma():"-",c=this.l?this.l.Ma():"-";this.f&&a==this.f[1]&&c==this.f[2]&&this.g==this.f[3]&&this.i==this.f[4]&&this.A==this.f[5]&&this.b==this.f[6]||(this.f=["r"+a+c+(void 0!==this.g?this.g.toString():"-")+(void 0!==this.i?this.i.toString():"-")+(void 0!==this.A?this.A.toString():"-")+(void 0!==this.b?this.b.toString():"-"),a,c,this.g,this.i,this.A,this.b]);return this.f[0]};v("ol.Collection",F,OPENLAYERS);F.prototype.clear=F.prototype.clear;F.prototype.extend=F.prototype.Dd;F.prototype.forEach=F.prototype.forEach;F.prototype.getArray=F.prototype.Uh;F.prototype.item=F.prototype.item;F.prototype.getLength=F.prototype.gb;F.prototype.insertAt=F.prototype.Ac;F.prototype.pop=F.prototype.pop;F.prototype.push=F.prototype.push;F.prototype.remove=F.prototype.remove;F.prototype.removeAt=F.prototype.Qd;F.prototype.setAt=F.prototype.$j;F.prototype.get=F.prototype.get; -F.prototype.getKeys=F.prototype.L;F.prototype.getProperties=F.prototype.P;F.prototype.set=F.prototype.C;F.prototype.setProperties=F.prototype.K;F.prototype.unset=F.prototype.W;F.prototype.changed=F.prototype.v;F.prototype.dispatchEvent=F.prototype.b;F.prototype.getRevision=F.prototype.S;F.prototype.on=F.prototype.M;F.prototype.once=F.prototype.T;F.prototype.un=F.prototype.U;F.prototype.unByKey=F.prototype.V;v("ol.DeviceOrientation",Mn,OPENLAYERS);Mn.prototype.getAlpha=Mn.prototype.kg; -Mn.prototype.getBeta=Mn.prototype.ng;Mn.prototype.getGamma=Mn.prototype.yg;Mn.prototype.getHeading=Mn.prototype.Vh;Mn.prototype.getTracking=Mn.prototype.He;Mn.prototype.setTracking=Mn.prototype.Ed;Mn.prototype.get=Mn.prototype.get;Mn.prototype.getKeys=Mn.prototype.L;Mn.prototype.getProperties=Mn.prototype.P;Mn.prototype.set=Mn.prototype.C;Mn.prototype.setProperties=Mn.prototype.K;Mn.prototype.unset=Mn.prototype.W;Mn.prototype.changed=Mn.prototype.v;Mn.prototype.dispatchEvent=Mn.prototype.b; -Mn.prototype.getRevision=Mn.prototype.S;Mn.prototype.on=Mn.prototype.M;Mn.prototype.once=Mn.prototype.T;Mn.prototype.un=Mn.prototype.U;Mn.prototype.unByKey=Mn.prototype.V;v("ol.Feature",Kl,OPENLAYERS);Kl.prototype.clone=Kl.prototype.clone;Kl.prototype.getGeometry=Kl.prototype.O;Kl.prototype.getId=Kl.prototype.Ba;Kl.prototype.getGeometryName=Kl.prototype.Bg;Kl.prototype.getStyle=Kl.prototype.Xh;Kl.prototype.getStyleFunction=Kl.prototype.Yb;Kl.prototype.setGeometry=Kl.prototype.Sa; -Kl.prototype.setStyle=Kl.prototype.Fd;Kl.prototype.setId=Kl.prototype.Sd;Kl.prototype.setGeometryName=Kl.prototype.Uc;Kl.prototype.get=Kl.prototype.get;Kl.prototype.getKeys=Kl.prototype.L;Kl.prototype.getProperties=Kl.prototype.P;Kl.prototype.set=Kl.prototype.C;Kl.prototype.setProperties=Kl.prototype.K;Kl.prototype.unset=Kl.prototype.W;Kl.prototype.changed=Kl.prototype.v;Kl.prototype.dispatchEvent=Kl.prototype.b;Kl.prototype.getRevision=Kl.prototype.S;Kl.prototype.on=Kl.prototype.M; -Kl.prototype.once=Kl.prototype.T;Kl.prototype.un=Kl.prototype.U;Kl.prototype.unByKey=Kl.prototype.V;v("ol.Geolocation",fr,OPENLAYERS);fr.prototype.getAccuracy=fr.prototype.ig;fr.prototype.getAccuracyGeometry=fr.prototype.jg;fr.prototype.getAltitude=fr.prototype.lg;fr.prototype.getAltitudeAccuracy=fr.prototype.mg;fr.prototype.getHeading=fr.prototype.Zh;fr.prototype.getPosition=fr.prototype.$h;fr.prototype.getProjection=fr.prototype.Ie;fr.prototype.getSpeed=fr.prototype.Vg; -fr.prototype.getTracking=fr.prototype.Je;fr.prototype.getTrackingOptions=fr.prototype.Ce;fr.prototype.setProjection=fr.prototype.Ke;fr.prototype.setTracking=fr.prototype.Ec;fr.prototype.setTrackingOptions=fr.prototype.yf;fr.prototype.get=fr.prototype.get;fr.prototype.getKeys=fr.prototype.L;fr.prototype.getProperties=fr.prototype.P;fr.prototype.set=fr.prototype.C;fr.prototype.setProperties=fr.prototype.K;fr.prototype.unset=fr.prototype.W;fr.prototype.changed=fr.prototype.v; -fr.prototype.dispatchEvent=fr.prototype.b;fr.prototype.getRevision=fr.prototype.S;fr.prototype.on=fr.prototype.M;fr.prototype.once=fr.prototype.T;fr.prototype.un=fr.prototype.U;fr.prototype.unByKey=fr.prototype.V;ir.prototype.getImage=ir.prototype.xb;v("ol.Map",P,OPENLAYERS);P.prototype.addControl=P.prototype.Qf;P.prototype.addInteraction=P.prototype.Rf;P.prototype.addLayer=P.prototype.Sf;P.prototype.addOverlay=P.prototype.Tf;P.prototype.beforeRender=P.prototype.wa; -P.prototype.forEachFeatureAtPixel=P.prototype.nd;P.prototype.forEachLayerAtPixel=P.prototype.fi;P.prototype.hasFeatureAtPixel=P.prototype.Bh;P.prototype.getEventCoordinate=P.prototype.sg;P.prototype.getEventPixel=P.prototype.sc;P.prototype.getTarget=P.prototype.Le;P.prototype.getTargetElement=P.prototype.Ub;P.prototype.getCoordinateFromPixel=P.prototype.ra;P.prototype.getControls=P.prototype.qg;P.prototype.getOverlays=P.prototype.Pg;P.prototype.getOverlayById=P.prototype.Og; -P.prototype.getInteractions=P.prototype.Dg;P.prototype.getLayerGroup=P.prototype.sb;P.prototype.getLayers=P.prototype.gi;P.prototype.getPixelFromCoordinate=P.prototype.xa;P.prototype.getSize=P.prototype.hb;P.prototype.getView=P.prototype.ga;P.prototype.getViewport=P.prototype.ah;P.prototype.renderSync=P.prototype.Yj;P.prototype.render=P.prototype.render;P.prototype.removeControl=P.prototype.Sj;P.prototype.removeInteraction=P.prototype.Tj;P.prototype.removeLayer=P.prototype.Vj; -P.prototype.removeOverlay=P.prototype.Wj;P.prototype.setLayerGroup=P.prototype.fk;P.prototype.setSize=P.prototype.Vd;P.prototype.setTarget=P.prototype.hi;P.prototype.setView=P.prototype.mk;P.prototype.updateSize=P.prototype.Zd;P.prototype.get=P.prototype.get;P.prototype.getKeys=P.prototype.L;P.prototype.getProperties=P.prototype.P;P.prototype.set=P.prototype.C;P.prototype.setProperties=P.prototype.K;P.prototype.unset=P.prototype.W;P.prototype.changed=P.prototype.v;P.prototype.dispatchEvent=P.prototype.b; -P.prototype.getRevision=P.prototype.S;P.prototype.on=P.prototype.M;P.prototype.once=P.prototype.T;P.prototype.un=P.prototype.U;P.prototype.unByKey=P.prototype.V;ei.prototype.originalEvent=ei.prototype.originalEvent;ei.prototype.pixel=ei.prototype.pixel;ei.prototype.coordinate=ei.prototype.coordinate;ei.prototype.dragging=ei.prototype.dragging;ei.prototype.preventDefault=ei.prototype.preventDefault;ei.prototype.stopPropagation=ei.prototype.i;ei.prototype.map=ei.prototype.map; -ei.prototype.frameState=ei.prototype.frameState;v("ol.Observable.unByKey",Wc,OPENLAYERS);v("ol.Overlay",Dn,OPENLAYERS);Dn.prototype.getElement=Dn.prototype.Gd;Dn.prototype.getId=Dn.prototype.Ba;Dn.prototype.getMap=Dn.prototype.Fc;Dn.prototype.getOffset=Dn.prototype.ze;Dn.prototype.getPosition=Dn.prototype.Me;Dn.prototype.getPositioning=Dn.prototype.Be;Dn.prototype.setElement=Dn.prototype.pf;Dn.prototype.setMap=Dn.prototype.setMap;Dn.prototype.setOffset=Dn.prototype.sf;Dn.prototype.setPosition=Dn.prototype.Ne; -Dn.prototype.setPositioning=Dn.prototype.vf;Dn.prototype.get=Dn.prototype.get;Dn.prototype.getKeys=Dn.prototype.L;Dn.prototype.getProperties=Dn.prototype.P;Dn.prototype.set=Dn.prototype.C;Dn.prototype.setProperties=Dn.prototype.K;Dn.prototype.unset=Dn.prototype.W;Dn.prototype.changed=Dn.prototype.v;Dn.prototype.dispatchEvent=Dn.prototype.b;Dn.prototype.getRevision=Dn.prototype.S;Dn.prototype.on=Dn.prototype.M;Dn.prototype.once=Dn.prototype.T;Dn.prototype.un=Dn.prototype.U;Dn.prototype.unByKey=Dn.prototype.V; -v("ol.View",D,OPENLAYERS);D.prototype.constrainCenter=D.prototype.qc;D.prototype.constrainResolution=D.prototype.constrainResolution;D.prototype.constrainRotation=D.prototype.constrainRotation;D.prototype.getCenter=D.prototype.za;D.prototype.calculateExtent=D.prototype.$f;D.prototype.getProjection=D.prototype.ii;D.prototype.getResolution=D.prototype.$;D.prototype.getRotation=D.prototype.ua;D.prototype.getZoom=D.prototype.dh;D.prototype.fit=D.prototype.oe;D.prototype.centerOn=D.prototype.bg; -D.prototype.rotate=D.prototype.rotate;D.prototype.setCenter=D.prototype.Ea;D.prototype.setResolution=D.prototype.Gb;D.prototype.setRotation=D.prototype.Id;D.prototype.setZoom=D.prototype.qk;D.prototype.get=D.prototype.get;D.prototype.getKeys=D.prototype.L;D.prototype.getProperties=D.prototype.P;D.prototype.set=D.prototype.C;D.prototype.setProperties=D.prototype.K;D.prototype.unset=D.prototype.W;D.prototype.changed=D.prototype.v;D.prototype.dispatchEvent=D.prototype.b;D.prototype.getRevision=D.prototype.S; -D.prototype.on=D.prototype.M;D.prototype.once=D.prototype.T;D.prototype.un=D.prototype.U;D.prototype.unByKey=D.prototype.V;v("ol.animation.bounce",function(a){var c=a.resolution,d=a.start?a.start:Date.now(),e=void 0!==a.duration?a.duration:1E3,f=a.easing?a.easing:gf;return function(a,h){if(h.time<d)return h.animate=!0,h.viewHints[0]+=1,!0;if(h.time<d+e){var l=f((h.time-d)/e),m=c-h.viewState.resolution;h.animate=!0;h.viewState.resolution+=l*m;h.viewHints[0]+=1;return!0}return!1}},OPENLAYERS); -v("ol.animation.pan",hf,OPENLAYERS);v("ol.animation.rotate",jf,OPENLAYERS);v("ol.animation.zoom",kf,OPENLAYERS);v("ol.color.asArray",wf,OPENLAYERS);v("ol.color.asString",yf,OPENLAYERS);v("ol.control.MousePosition",Mg,OPENLAYERS);Mg.prototype.getCoordinateFormat=Mg.prototype.pe;Mg.prototype.getProjection=Mg.prototype.Oe;Mg.prototype.setCoordinateFormat=Mg.prototype.of;Mg.prototype.setProjection=Mg.prototype.Pe;Mg.prototype.getMap=Mg.prototype.I;Mg.prototype.setMap=Mg.prototype.setMap; -Mg.prototype.setTarget=Mg.prototype.H;Mg.prototype.get=Mg.prototype.get;Mg.prototype.getKeys=Mg.prototype.L;Mg.prototype.getProperties=Mg.prototype.P;Mg.prototype.set=Mg.prototype.C;Mg.prototype.setProperties=Mg.prototype.K;Mg.prototype.unset=Mg.prototype.W;Mg.prototype.changed=Mg.prototype.v;Mg.prototype.dispatchEvent=Mg.prototype.b;Mg.prototype.getRevision=Mg.prototype.S;Mg.prototype.on=Mg.prototype.M;Mg.prototype.once=Mg.prototype.T;Mg.prototype.un=Mg.prototype.U;Mg.prototype.unByKey=Mg.prototype.V; -v("ol.control.ScaleLine",Hn,OPENLAYERS);Hn.prototype.getUnits=Hn.prototype.G;Hn.prototype.setUnits=Hn.prototype.Y;Hn.prototype.getMap=Hn.prototype.I;Hn.prototype.setMap=Hn.prototype.setMap;Hn.prototype.setTarget=Hn.prototype.H;Hn.prototype.get=Hn.prototype.get;Hn.prototype.getKeys=Hn.prototype.L;Hn.prototype.getProperties=Hn.prototype.P;Hn.prototype.set=Hn.prototype.C;Hn.prototype.setProperties=Hn.prototype.K;Hn.prototype.unset=Hn.prototype.W;Hn.prototype.changed=Hn.prototype.v; -Hn.prototype.dispatchEvent=Hn.prototype.b;Hn.prototype.getRevision=Hn.prototype.S;Hn.prototype.on=Hn.prototype.M;Hn.prototype.once=Hn.prototype.T;Hn.prototype.un=Hn.prototype.U;Hn.prototype.unByKey=Hn.prototype.V;v("ol.control.ZoomToExtent",Ln,OPENLAYERS);Ln.prototype.getMap=Ln.prototype.I;Ln.prototype.setMap=Ln.prototype.setMap;Ln.prototype.setTarget=Ln.prototype.H;Ln.prototype.get=Ln.prototype.get;Ln.prototype.getKeys=Ln.prototype.L;Ln.prototype.getProperties=Ln.prototype.P;Ln.prototype.set=Ln.prototype.C; -Ln.prototype.setProperties=Ln.prototype.K;Ln.prototype.unset=Ln.prototype.W;Ln.prototype.changed=Ln.prototype.v;Ln.prototype.dispatchEvent=Ln.prototype.b;Ln.prototype.getRevision=Ln.prototype.S;Ln.prototype.on=Ln.prototype.M;Ln.prototype.once=Ln.prototype.T;Ln.prototype.un=Ln.prototype.U;Ln.prototype.unByKey=Ln.prototype.V;v("ol.control.defaults",Lg,OPENLAYERS);v("ol.coordinate.format",jd,OPENLAYERS);v("ol.coordinate.toStringHDMS",function(a){return a?id(a[1],"NS")+" "+id(a[0],"EW"):""},OPENLAYERS); -v("ol.coordinate.toStringXY",function(a,c){return jd(a,"{x}, {y}",c)},OPENLAYERS);v("ol.easing.easeOut",df,OPENLAYERS);v("ol.easing.linear",ff,OPENLAYERS);v("ol.extent.buffer",zd,OPENLAYERS);v("ol.extent.containsCoordinate",Cd,OPENLAYERS);v("ol.extent.containsXY",Dd,OPENLAYERS);v("ol.extent.getCenter",Rd,OPENLAYERS);v("ol.extent.getHeight",Qd,OPENLAYERS);v("ol.extent.getWidth",Pd,OPENLAYERS);v("ol.extent.intersects",Ud,OPENLAYERS);v("ol.format.GeoJSON",fo,OPENLAYERS);fo.prototype.readFeature=fo.prototype.Od; -fo.prototype.readFeatures=fo.prototype.Sc;fo.prototype.readGeometry=fo.prototype.kf;fo.prototype.readProjection=fo.prototype.hc;fo.prototype.writeFeature=fo.prototype.Ff;fo.prototype.writeFeatureObject=fo.prototype.b;fo.prototype.writeFeatures=fo.prototype.$d;fo.prototype.writeFeaturesObject=fo.prototype.g;fo.prototype.writeGeometry=fo.prototype.Gf;fo.prototype.writeGeometryObject=fo.prototype.c;v("ol.format.KML",Ro,OPENLAYERS);Ro.prototype.readFeature=Ro.prototype.Od;Ro.prototype.readFeatures=Ro.prototype.Sc; -Ro.prototype.readName=Ro.prototype.Nj;Ro.prototype.readNetworkLinks=Ro.prototype.Oj;Ro.prototype.readProjection=Ro.prototype.hc;Ro.prototype.writeFeatures=Ro.prototype.$d;Ro.prototype.writeFeaturesNode=Ro.prototype.a;v("ol.format.WMSCapabilities",Iq,OPENLAYERS);Iq.prototype.read=Iq.prototype.b;v("ol.geom.Circle",W,OPENLAYERS);W.prototype.clone=W.prototype.clone;W.prototype.getCenter=W.prototype.Gc;W.prototype.getRadius=W.prototype.Qe;W.prototype.getType=W.prototype.N; -W.prototype.intersectsExtent=W.prototype.pa;W.prototype.setCenter=W.prototype.ki;W.prototype.setCenterAndRadius=W.prototype.Rd;W.prototype.setRadius=W.prototype.jk;W.prototype.transform=W.prototype.Fa;W.prototype.getFirstCoordinate=W.prototype.Oa;W.prototype.getLastCoordinate=W.prototype.Pa;W.prototype.getLayout=W.prototype.Qa;W.prototype.getClosestPoint=W.prototype.Ha;W.prototype.getExtent=W.prototype.F;W.prototype.simplify=W.prototype.Ka;W.prototype.get=W.prototype.get;W.prototype.getKeys=W.prototype.L; -W.prototype.getProperties=W.prototype.P;W.prototype.set=W.prototype.C;W.prototype.setProperties=W.prototype.K;W.prototype.unset=W.prototype.W;W.prototype.changed=W.prototype.v;W.prototype.dispatchEvent=W.prototype.b;W.prototype.getRevision=W.prototype.S;W.prototype.on=W.prototype.M;W.prototype.once=W.prototype.T;W.prototype.un=W.prototype.U;W.prototype.unByKey=W.prototype.V;v("ol.geom.GeometryCollection",U,OPENLAYERS);U.prototype.clone=U.prototype.clone;U.prototype.getGeometries=U.prototype.zg; -U.prototype.getType=U.prototype.N;U.prototype.intersectsExtent=U.prototype.pa;U.prototype.setGeometries=U.prototype.qf;U.prototype.applyTransform=U.prototype.pb;U.prototype.translate=U.prototype.Hc;U.prototype.getClosestPoint=U.prototype.Ha;U.prototype.getExtent=U.prototype.F;U.prototype.simplify=U.prototype.Ka;U.prototype.transform=U.prototype.Fa;U.prototype.get=U.prototype.get;U.prototype.getKeys=U.prototype.L;U.prototype.getProperties=U.prototype.P;U.prototype.set=U.prototype.C; -U.prototype.setProperties=U.prototype.K;U.prototype.unset=U.prototype.W;U.prototype.changed=U.prototype.v;U.prototype.dispatchEvent=U.prototype.b;U.prototype.getRevision=U.prototype.S;U.prototype.on=U.prototype.M;U.prototype.once=U.prototype.T;U.prototype.un=U.prototype.U;U.prototype.unByKey=U.prototype.V;v("ol.geom.LinearRing",Ne,OPENLAYERS);Ne.prototype.clone=Ne.prototype.clone;Ne.prototype.getArea=Ne.prototype.ni;Ne.prototype.getCoordinates=Ne.prototype.R;Ne.prototype.getType=Ne.prototype.N; -Ne.prototype.setCoordinates=Ne.prototype.da;Ne.prototype.getFirstCoordinate=Ne.prototype.Oa;Ne.prototype.getLastCoordinate=Ne.prototype.Pa;Ne.prototype.getLayout=Ne.prototype.Qa;Ne.prototype.getClosestPoint=Ne.prototype.Ha;Ne.prototype.getExtent=Ne.prototype.F;Ne.prototype.simplify=Ne.prototype.Ka;Ne.prototype.transform=Ne.prototype.Fa;Ne.prototype.get=Ne.prototype.get;Ne.prototype.getKeys=Ne.prototype.L;Ne.prototype.getProperties=Ne.prototype.P;Ne.prototype.set=Ne.prototype.C; -Ne.prototype.setProperties=Ne.prototype.K;Ne.prototype.unset=Ne.prototype.W;Ne.prototype.changed=Ne.prototype.v;Ne.prototype.dispatchEvent=Ne.prototype.b;Ne.prototype.getRevision=Ne.prototype.S;Ne.prototype.on=Ne.prototype.M;Ne.prototype.once=Ne.prototype.T;Ne.prototype.un=Ne.prototype.U;Ne.prototype.unByKey=Ne.prototype.V;v("ol.geom.LineString",Q,OPENLAYERS);Q.prototype.appendCoordinate=Q.prototype.Uf;Q.prototype.clone=Q.prototype.clone;Q.prototype.forEachSegment=Q.prototype.hg; -Q.prototype.getCoordinateAtM=Q.prototype.li;Q.prototype.getCoordinates=Q.prototype.R;Q.prototype.getLength=Q.prototype.mi;Q.prototype.getType=Q.prototype.N;Q.prototype.intersectsExtent=Q.prototype.pa;Q.prototype.setCoordinates=Q.prototype.da;Q.prototype.getFirstCoordinate=Q.prototype.Oa;Q.prototype.getLastCoordinate=Q.prototype.Pa;Q.prototype.getLayout=Q.prototype.Qa;Q.prototype.getClosestPoint=Q.prototype.Ha;Q.prototype.getExtent=Q.prototype.F;Q.prototype.simplify=Q.prototype.Ka; -Q.prototype.transform=Q.prototype.Fa;Q.prototype.get=Q.prototype.get;Q.prototype.getKeys=Q.prototype.L;Q.prototype.getProperties=Q.prototype.P;Q.prototype.set=Q.prototype.C;Q.prototype.setProperties=Q.prototype.K;Q.prototype.unset=Q.prototype.W;Q.prototype.changed=Q.prototype.v;Q.prototype.dispatchEvent=Q.prototype.b;Q.prototype.getRevision=Q.prototype.S;Q.prototype.on=Q.prototype.M;Q.prototype.once=Q.prototype.T;Q.prototype.un=Q.prototype.U;Q.prototype.unByKey=Q.prototype.V; -v("ol.geom.MultiLineString",R,OPENLAYERS);R.prototype.appendLineString=R.prototype.Vf;R.prototype.clone=R.prototype.clone;R.prototype.getCoordinateAtM=R.prototype.oi;R.prototype.getCoordinates=R.prototype.R;R.prototype.getLineString=R.prototype.Ig;R.prototype.getLineStrings=R.prototype.ue;R.prototype.getType=R.prototype.N;R.prototype.intersectsExtent=R.prototype.pa;R.prototype.setCoordinates=R.prototype.da;R.prototype.getFirstCoordinate=R.prototype.Oa;R.prototype.getLastCoordinate=R.prototype.Pa; -R.prototype.getLayout=R.prototype.Qa;R.prototype.getClosestPoint=R.prototype.Ha;R.prototype.getExtent=R.prototype.F;R.prototype.simplify=R.prototype.Ka;R.prototype.transform=R.prototype.Fa;R.prototype.get=R.prototype.get;R.prototype.getKeys=R.prototype.L;R.prototype.getProperties=R.prototype.P;R.prototype.set=R.prototype.C;R.prototype.setProperties=R.prototype.K;R.prototype.unset=R.prototype.W;R.prototype.changed=R.prototype.v;R.prototype.dispatchEvent=R.prototype.b;R.prototype.getRevision=R.prototype.S; -R.prototype.on=R.prototype.M;R.prototype.once=R.prototype.T;R.prototype.un=R.prototype.U;R.prototype.unByKey=R.prototype.V;v("ol.geom.MultiPoint",S,OPENLAYERS);S.prototype.appendPoint=S.prototype.Xf;S.prototype.clone=S.prototype.clone;S.prototype.getCoordinates=S.prototype.R;S.prototype.getPoint=S.prototype.Qg;S.prototype.getPoints=S.prototype.Re;S.prototype.getType=S.prototype.N;S.prototype.intersectsExtent=S.prototype.pa;S.prototype.setCoordinates=S.prototype.da;S.prototype.getFirstCoordinate=S.prototype.Oa; -S.prototype.getLastCoordinate=S.prototype.Pa;S.prototype.getLayout=S.prototype.Qa;S.prototype.getClosestPoint=S.prototype.Ha;S.prototype.getExtent=S.prototype.F;S.prototype.simplify=S.prototype.Ka;S.prototype.transform=S.prototype.Fa;S.prototype.get=S.prototype.get;S.prototype.getKeys=S.prototype.L;S.prototype.getProperties=S.prototype.P;S.prototype.set=S.prototype.C;S.prototype.setProperties=S.prototype.K;S.prototype.unset=S.prototype.W;S.prototype.changed=S.prototype.v; -S.prototype.dispatchEvent=S.prototype.b;S.prototype.getRevision=S.prototype.S;S.prototype.on=S.prototype.M;S.prototype.once=S.prototype.T;S.prototype.un=S.prototype.U;S.prototype.unByKey=S.prototype.V;v("ol.geom.MultiPolygon",T,OPENLAYERS);T.prototype.appendPolygon=T.prototype.Yf;T.prototype.clone=T.prototype.clone;T.prototype.getArea=T.prototype.pi;T.prototype.getCoordinates=T.prototype.R;T.prototype.getInteriorPoints=T.prototype.Fg;T.prototype.getPolygon=T.prototype.Sg;T.prototype.getPolygons=T.prototype.Ae; -T.prototype.getType=T.prototype.N;T.prototype.intersectsExtent=T.prototype.pa;T.prototype.setCoordinates=T.prototype.da;T.prototype.getFirstCoordinate=T.prototype.Oa;T.prototype.getLastCoordinate=T.prototype.Pa;T.prototype.getLayout=T.prototype.Qa;T.prototype.getClosestPoint=T.prototype.Ha;T.prototype.getExtent=T.prototype.F;T.prototype.simplify=T.prototype.Ka;T.prototype.transform=T.prototype.Fa;T.prototype.get=T.prototype.get;T.prototype.getKeys=T.prototype.L;T.prototype.getProperties=T.prototype.P; -T.prototype.set=T.prototype.C;T.prototype.setProperties=T.prototype.K;T.prototype.unset=T.prototype.W;T.prototype.changed=T.prototype.v;T.prototype.dispatchEvent=T.prototype.b;T.prototype.getRevision=T.prototype.S;T.prototype.on=T.prototype.M;T.prototype.once=T.prototype.T;T.prototype.un=T.prototype.U;T.prototype.unByKey=T.prototype.V;v("ol.geom.Point",A,OPENLAYERS);A.prototype.clone=A.prototype.clone;A.prototype.getCoordinates=A.prototype.R;A.prototype.getType=A.prototype.N; -A.prototype.intersectsExtent=A.prototype.pa;A.prototype.setCoordinates=A.prototype.da;A.prototype.getFirstCoordinate=A.prototype.Oa;A.prototype.getLastCoordinate=A.prototype.Pa;A.prototype.getLayout=A.prototype.Qa;A.prototype.getClosestPoint=A.prototype.Ha;A.prototype.getExtent=A.prototype.F;A.prototype.simplify=A.prototype.Ka;A.prototype.transform=A.prototype.Fa;A.prototype.get=A.prototype.get;A.prototype.getKeys=A.prototype.L;A.prototype.getProperties=A.prototype.P;A.prototype.set=A.prototype.C; -A.prototype.setProperties=A.prototype.K;A.prototype.unset=A.prototype.W;A.prototype.changed=A.prototype.v;A.prototype.dispatchEvent=A.prototype.b;A.prototype.getRevision=A.prototype.S;A.prototype.on=A.prototype.M;A.prototype.once=A.prototype.T;A.prototype.un=A.prototype.U;A.prototype.unByKey=A.prototype.V;v("ol.geom.Polygon",C,OPENLAYERS);C.prototype.appendLinearRing=C.prototype.Wf;C.prototype.clone=C.prototype.clone;C.prototype.getArea=C.prototype.ri;C.prototype.getCoordinates=C.prototype.R; -C.prototype.getInteriorPoint=C.prototype.Eg;C.prototype.getLinearRingCount=C.prototype.Jg;C.prototype.getLinearRing=C.prototype.ve;C.prototype.getLinearRings=C.prototype.we;C.prototype.getType=C.prototype.N;C.prototype.intersectsExtent=C.prototype.pa;C.prototype.setCoordinates=C.prototype.da;C.prototype.getFirstCoordinate=C.prototype.Oa;C.prototype.getLastCoordinate=C.prototype.Pa;C.prototype.getLayout=C.prototype.Qa;C.prototype.getClosestPoint=C.prototype.Ha;C.prototype.getExtent=C.prototype.F; -C.prototype.simplify=C.prototype.Ka;C.prototype.transform=C.prototype.Fa;C.prototype.get=C.prototype.get;C.prototype.getKeys=C.prototype.L;C.prototype.getProperties=C.prototype.P;C.prototype.set=C.prototype.C;C.prototype.setProperties=C.prototype.K;C.prototype.unset=C.prototype.W;C.prototype.changed=C.prototype.v;C.prototype.dispatchEvent=C.prototype.b;C.prototype.getRevision=C.prototype.S;C.prototype.on=C.prototype.M;C.prototype.once=C.prototype.T;C.prototype.un=C.prototype.U; -C.prototype.unByKey=C.prototype.V;v("ol.geom.SimpleGeometry",z,OPENLAYERS);z.prototype.getFirstCoordinate=z.prototype.Oa;z.prototype.getLastCoordinate=z.prototype.Pa;z.prototype.getLayout=z.prototype.Qa;z.prototype.applyTransform=z.prototype.pb;z.prototype.translate=z.prototype.Hc;z.prototype.getClosestPoint=z.prototype.Ha;z.prototype.getExtent=z.prototype.F;z.prototype.simplify=z.prototype.Ka;z.prototype.transform=z.prototype.Fa;z.prototype.get=z.prototype.get;z.prototype.getKeys=z.prototype.L; -z.prototype.getProperties=z.prototype.P;z.prototype.set=z.prototype.C;z.prototype.setProperties=z.prototype.K;z.prototype.unset=z.prototype.W;z.prototype.changed=z.prototype.v;z.prototype.dispatchEvent=z.prototype.b;z.prototype.getRevision=z.prototype.S;z.prototype.on=z.prototype.M;z.prototype.once=z.prototype.T;z.prototype.un=z.prototype.U;z.prototype.unByKey=z.prototype.V;v("ol.has.DEVICE_ORIENTATION",xh,OPENLAYERS);v("ol.has.DEVICE_PIXEL_RATIO",uh,OPENLAYERS);v("ol.interaction.DragBox",Dj,OPENLAYERS); -Dj.prototype.getGeometry=Dj.prototype.O;Dj.prototype.getActive=Dj.prototype.l;Dj.prototype.setActive=Dj.prototype.s;Dj.prototype.get=Dj.prototype.get;Dj.prototype.getKeys=Dj.prototype.L;Dj.prototype.getProperties=Dj.prototype.P;Dj.prototype.set=Dj.prototype.C;Dj.prototype.setProperties=Dj.prototype.K;Dj.prototype.unset=Dj.prototype.W;Dj.prototype.changed=Dj.prototype.v;Dj.prototype.dispatchEvent=Dj.prototype.b;Dj.prototype.getRevision=Dj.prototype.S;Dj.prototype.on=Dj.prototype.M; -Dj.prototype.once=Dj.prototype.T;Dj.prototype.un=Dj.prototype.U;Dj.prototype.unByKey=Dj.prototype.V;v("ol.interaction.DragZoom",Hj,OPENLAYERS);Hj.prototype.getGeometry=Hj.prototype.O;Hj.prototype.getActive=Hj.prototype.l;Hj.prototype.setActive=Hj.prototype.s;Hj.prototype.get=Hj.prototype.get;Hj.prototype.getKeys=Hj.prototype.L;Hj.prototype.getProperties=Hj.prototype.P;Hj.prototype.set=Hj.prototype.C;Hj.prototype.setProperties=Hj.prototype.K;Hj.prototype.unset=Hj.prototype.W;Hj.prototype.changed=Hj.prototype.v; -Hj.prototype.dispatchEvent=Hj.prototype.b;Hj.prototype.getRevision=Hj.prototype.S;Hj.prototype.on=Hj.prototype.M;Hj.prototype.once=Hj.prototype.T;Hj.prototype.un=Hj.prototype.U;Hj.prototype.unByKey=Hj.prototype.V;v("ol.interaction.Draw",lr,OPENLAYERS);lr.prototype.removeLastPoint=lr.prototype.Uj;lr.prototype.finishDrawing=lr.prototype.Qb;lr.prototype.extend=lr.prototype.si;lr.prototype.getActive=lr.prototype.l;lr.prototype.setActive=lr.prototype.s;lr.prototype.get=lr.prototype.get; -lr.prototype.getKeys=lr.prototype.L;lr.prototype.getProperties=lr.prototype.P;lr.prototype.set=lr.prototype.C;lr.prototype.setProperties=lr.prototype.K;lr.prototype.unset=lr.prototype.W;lr.prototype.changed=lr.prototype.v;lr.prototype.dispatchEvent=lr.prototype.b;lr.prototype.getRevision=lr.prototype.S;lr.prototype.on=lr.prototype.M;lr.prototype.once=lr.prototype.T;lr.prototype.un=lr.prototype.U;lr.prototype.unByKey=lr.prototype.V;v("ol.interaction.KeyboardPan",Ij,OPENLAYERS); -Ij.prototype.getActive=Ij.prototype.l;Ij.prototype.setActive=Ij.prototype.s;Ij.prototype.get=Ij.prototype.get;Ij.prototype.getKeys=Ij.prototype.L;Ij.prototype.getProperties=Ij.prototype.P;Ij.prototype.set=Ij.prototype.C;Ij.prototype.setProperties=Ij.prototype.K;Ij.prototype.unset=Ij.prototype.W;Ij.prototype.changed=Ij.prototype.v;Ij.prototype.dispatchEvent=Ij.prototype.b;Ij.prototype.getRevision=Ij.prototype.S;Ij.prototype.on=Ij.prototype.M;Ij.prototype.once=Ij.prototype.T;Ij.prototype.un=Ij.prototype.U; -Ij.prototype.unByKey=Ij.prototype.V;v("ol.interaction.KeyboardZoom",Kj,OPENLAYERS);Kj.prototype.getActive=Kj.prototype.l;Kj.prototype.setActive=Kj.prototype.s;Kj.prototype.get=Kj.prototype.get;Kj.prototype.getKeys=Kj.prototype.L;Kj.prototype.getProperties=Kj.prototype.P;Kj.prototype.set=Kj.prototype.C;Kj.prototype.setProperties=Kj.prototype.K;Kj.prototype.unset=Kj.prototype.W;Kj.prototype.changed=Kj.prototype.v;Kj.prototype.dispatchEvent=Kj.prototype.b;Kj.prototype.getRevision=Kj.prototype.S; -Kj.prototype.on=Kj.prototype.M;Kj.prototype.once=Kj.prototype.T;Kj.prototype.un=Kj.prototype.U;Kj.prototype.unByKey=Kj.prototype.V;v("ol.interaction.Modify",Cr,OPENLAYERS);Cr.prototype.getActive=Cr.prototype.l;Cr.prototype.setActive=Cr.prototype.s;Cr.prototype.get=Cr.prototype.get;Cr.prototype.getKeys=Cr.prototype.L;Cr.prototype.getProperties=Cr.prototype.P;Cr.prototype.set=Cr.prototype.C;Cr.prototype.setProperties=Cr.prototype.K;Cr.prototype.unset=Cr.prototype.W;Cr.prototype.changed=Cr.prototype.v; -Cr.prototype.dispatchEvent=Cr.prototype.b;Cr.prototype.getRevision=Cr.prototype.S;Cr.prototype.on=Cr.prototype.M;Cr.prototype.once=Cr.prototype.T;Cr.prototype.un=Cr.prototype.U;Cr.prototype.unByKey=Cr.prototype.V;v("ol.interaction.Select",Qr,OPENLAYERS);Qr.prototype.getFeatures=Qr.prototype.Ci;Qr.prototype.getLayer=Qr.prototype.Di;Qr.prototype.setMap=Qr.prototype.setMap;Qr.prototype.getActive=Qr.prototype.l;Qr.prototype.setActive=Qr.prototype.s;Qr.prototype.get=Qr.prototype.get; -Qr.prototype.getKeys=Qr.prototype.L;Qr.prototype.getProperties=Qr.prototype.P;Qr.prototype.set=Qr.prototype.C;Qr.prototype.setProperties=Qr.prototype.K;Qr.prototype.unset=Qr.prototype.W;Qr.prototype.changed=Qr.prototype.v;Qr.prototype.dispatchEvent=Qr.prototype.b;Qr.prototype.getRevision=Qr.prototype.S;Qr.prototype.on=Qr.prototype.M;Qr.prototype.once=Qr.prototype.T;Qr.prototype.un=Qr.prototype.U;Qr.prototype.unByKey=Qr.prototype.V;v("ol.interaction.Snap",Tr,OPENLAYERS);Tr.prototype.addFeature=Tr.prototype.Zb; -Tr.prototype.removeFeature=Tr.prototype.$b;Tr.prototype.getActive=Tr.prototype.l;Tr.prototype.setActive=Tr.prototype.s;Tr.prototype.get=Tr.prototype.get;Tr.prototype.getKeys=Tr.prototype.L;Tr.prototype.getProperties=Tr.prototype.P;Tr.prototype.set=Tr.prototype.C;Tr.prototype.setProperties=Tr.prototype.K;Tr.prototype.unset=Tr.prototype.W;Tr.prototype.changed=Tr.prototype.v;Tr.prototype.dispatchEvent=Tr.prototype.b;Tr.prototype.getRevision=Tr.prototype.S;Tr.prototype.on=Tr.prototype.M; -Tr.prototype.once=Tr.prototype.T;Tr.prototype.un=Tr.prototype.U;Tr.prototype.unByKey=Tr.prototype.V;v("ol.interaction.defaults",Wj,OPENLAYERS);v("ol.layer.Group",K,OPENLAYERS);K.prototype.getLayers=K.prototype.Ab;K.prototype.setLayers=K.prototype.rf;K.prototype.getExtent=K.prototype.F;K.prototype.getMaxResolution=K.prototype.ub;K.prototype.getMinResolution=K.prototype.vb;K.prototype.getOpacity=K.prototype.yb;K.prototype.getVisible=K.prototype.Xa;K.prototype.getZIndex=K.prototype.zb; -K.prototype.setExtent=K.prototype.ac;K.prototype.setMaxResolution=K.prototype.ic;K.prototype.setMinResolution=K.prototype.jc;K.prototype.setOpacity=K.prototype.bc;K.prototype.setVisible=K.prototype.cc;K.prototype.setZIndex=K.prototype.dc;K.prototype.get=K.prototype.get;K.prototype.getKeys=K.prototype.L;K.prototype.getProperties=K.prototype.P;K.prototype.set=K.prototype.C;K.prototype.setProperties=K.prototype.K;K.prototype.unset=K.prototype.W;K.prototype.changed=K.prototype.v; -K.prototype.dispatchEvent=K.prototype.b;K.prototype.getRevision=K.prototype.S;K.prototype.on=K.prototype.M;K.prototype.once=K.prototype.T;K.prototype.un=K.prototype.U;K.prototype.unByKey=K.prototype.V;v("ol.layer.Image",H,OPENLAYERS);H.prototype.getSource=H.prototype.ha;H.prototype.setMap=H.prototype.setMap;H.prototype.setSource=H.prototype.kc;H.prototype.getExtent=H.prototype.F;H.prototype.getMaxResolution=H.prototype.ub;H.prototype.getMinResolution=H.prototype.vb;H.prototype.getOpacity=H.prototype.yb; -H.prototype.getVisible=H.prototype.Xa;H.prototype.getZIndex=H.prototype.zb;H.prototype.setExtent=H.prototype.ac;H.prototype.setMaxResolution=H.prototype.ic;H.prototype.setMinResolution=H.prototype.jc;H.prototype.setOpacity=H.prototype.bc;H.prototype.setVisible=H.prototype.cc;H.prototype.setZIndex=H.prototype.dc;H.prototype.get=H.prototype.get;H.prototype.getKeys=H.prototype.L;H.prototype.getProperties=H.prototype.P;H.prototype.set=H.prototype.C;H.prototype.setProperties=H.prototype.K; -H.prototype.unset=H.prototype.W;H.prototype.changed=H.prototype.v;H.prototype.dispatchEvent=H.prototype.b;H.prototype.getRevision=H.prototype.S;H.prototype.on=H.prototype.M;H.prototype.once=H.prototype.T;H.prototype.un=H.prototype.U;H.prototype.unByKey=H.prototype.V;v("ol.layer.Layer",G,OPENLAYERS);G.prototype.getSource=G.prototype.ha;G.prototype.setMap=G.prototype.setMap;G.prototype.setSource=G.prototype.kc;G.prototype.getExtent=G.prototype.F;G.prototype.getMaxResolution=G.prototype.ub; -G.prototype.getMinResolution=G.prototype.vb;G.prototype.getOpacity=G.prototype.yb;G.prototype.getVisible=G.prototype.Xa;G.prototype.getZIndex=G.prototype.zb;G.prototype.setExtent=G.prototype.ac;G.prototype.setMaxResolution=G.prototype.ic;G.prototype.setMinResolution=G.prototype.jc;G.prototype.setOpacity=G.prototype.bc;G.prototype.setVisible=G.prototype.cc;G.prototype.setZIndex=G.prototype.dc;G.prototype.get=G.prototype.get;G.prototype.getKeys=G.prototype.L;G.prototype.getProperties=G.prototype.P; -G.prototype.set=G.prototype.C;G.prototype.setProperties=G.prototype.K;G.prototype.unset=G.prototype.W;G.prototype.changed=G.prototype.v;G.prototype.dispatchEvent=G.prototype.b;G.prototype.getRevision=G.prototype.S;G.prototype.on=G.prototype.M;G.prototype.once=G.prototype.T;G.prototype.un=G.prototype.U;G.prototype.unByKey=G.prototype.V;v("ol.layer.Tile",I,OPENLAYERS);I.prototype.getPreload=I.prototype.i;I.prototype.getSource=I.prototype.ha;I.prototype.setPreload=I.prototype.l; -I.prototype.getUseInterimTilesOnError=I.prototype.j;I.prototype.setUseInterimTilesOnError=I.prototype.s;I.prototype.setMap=I.prototype.setMap;I.prototype.setSource=I.prototype.kc;I.prototype.getExtent=I.prototype.F;I.prototype.getMaxResolution=I.prototype.ub;I.prototype.getMinResolution=I.prototype.vb;I.prototype.getOpacity=I.prototype.yb;I.prototype.getVisible=I.prototype.Xa;I.prototype.getZIndex=I.prototype.zb;I.prototype.setExtent=I.prototype.ac;I.prototype.setMaxResolution=I.prototype.ic; -I.prototype.setMinResolution=I.prototype.jc;I.prototype.setOpacity=I.prototype.bc;I.prototype.setVisible=I.prototype.cc;I.prototype.setZIndex=I.prototype.dc;I.prototype.get=I.prototype.get;I.prototype.getKeys=I.prototype.L;I.prototype.getProperties=I.prototype.P;I.prototype.set=I.prototype.C;I.prototype.setProperties=I.prototype.K;I.prototype.unset=I.prototype.W;I.prototype.changed=I.prototype.v;I.prototype.dispatchEvent=I.prototype.b;I.prototype.getRevision=I.prototype.S;I.prototype.on=I.prototype.M; -I.prototype.once=I.prototype.T;I.prototype.un=I.prototype.U;I.prototype.unByKey=I.prototype.V;v("ol.layer.Vector",J,OPENLAYERS);J.prototype.getSource=J.prototype.ha;J.prototype.getStyle=J.prototype.u;J.prototype.getStyleFunction=J.prototype.H;J.prototype.setStyle=J.prototype.s;J.prototype.setMap=J.prototype.setMap;J.prototype.setSource=J.prototype.kc;J.prototype.getExtent=J.prototype.F;J.prototype.getMaxResolution=J.prototype.ub;J.prototype.getMinResolution=J.prototype.vb;J.prototype.getOpacity=J.prototype.yb; -J.prototype.getVisible=J.prototype.Xa;J.prototype.getZIndex=J.prototype.zb;J.prototype.setExtent=J.prototype.ac;J.prototype.setMaxResolution=J.prototype.ic;J.prototype.setMinResolution=J.prototype.jc;J.prototype.setOpacity=J.prototype.bc;J.prototype.setVisible=J.prototype.cc;J.prototype.setZIndex=J.prototype.dc;J.prototype.get=J.prototype.get;J.prototype.getKeys=J.prototype.L;J.prototype.getProperties=J.prototype.P;J.prototype.set=J.prototype.C;J.prototype.setProperties=J.prototype.K; -J.prototype.unset=J.prototype.W;J.prototype.changed=J.prototype.v;J.prototype.dispatchEvent=J.prototype.b;J.prototype.getRevision=J.prototype.S;J.prototype.on=J.prototype.M;J.prototype.once=J.prototype.T;J.prototype.un=J.prototype.U;J.prototype.unByKey=J.prototype.V;v("ol.proj.Projection",de,OPENLAYERS);de.prototype.getCode=de.prototype.pg;de.prototype.getExtent=de.prototype.F;de.prototype.getUnits=de.prototype.Ni;de.prototype.getMetersPerUnit=de.prototype.Sb;de.prototype.getWorldExtent=de.prototype.bh; -de.prototype.isGlobal=de.prototype.Eh;de.prototype.setGlobal=de.prototype.dk;de.prototype.setExtent=de.prototype.Oi;de.prototype.setWorldExtent=de.prototype.pk;de.prototype.setGetPointResolution=de.prototype.ck;de.prototype.getPointResolution=de.prototype.getPointResolution;v("ol.proj.get",fe,OPENLAYERS);v("ol.proj.getTransform",qe,OPENLAYERS);v("ol.proj.transform",se,OPENLAYERS);v("ol.proj.transformExtent",te,OPENLAYERS);v("ol.style.Circle",qk,OPENLAYERS);qk.prototype.getFill=qk.prototype.ej; -qk.prototype.getImage=qk.prototype.jb;qk.prototype.getRadius=qk.prototype.fj;qk.prototype.getStroke=qk.prototype.gj;qk.prototype.getOpacity=qk.prototype.Mc;qk.prototype.getRotateWithView=qk.prototype.uc;qk.prototype.getRotation=qk.prototype.Nc;qk.prototype.getScale=qk.prototype.Oc;qk.prototype.getSnapToPixel=qk.prototype.vc;qk.prototype.setOpacity=qk.prototype.Pc;qk.prototype.setRotation=qk.prototype.Qc;qk.prototype.setScale=qk.prototype.Rc;v("ol.style.Fill",kk,OPENLAYERS);kk.prototype.getColor=kk.prototype.g; -kk.prototype.setColor=kk.prototype.c;v("ol.style.Icon",Ni,OPENLAYERS);Ni.prototype.getAnchor=Ni.prototype.eb;Ni.prototype.getImage=Ni.prototype.jb;Ni.prototype.getOrigin=Ni.prototype.ta;Ni.prototype.getSrc=Ni.prototype.hj;Ni.prototype.getSize=Ni.prototype.Ta;Ni.prototype.load=Ni.prototype.load;Ni.prototype.getOpacity=Ni.prototype.Mc;Ni.prototype.getRotateWithView=Ni.prototype.uc;Ni.prototype.getRotation=Ni.prototype.Nc;Ni.prototype.getScale=Ni.prototype.Oc;Ni.prototype.getSnapToPixel=Ni.prototype.vc; -Ni.prototype.setOpacity=Ni.prototype.Pc;Ni.prototype.setRotation=Ni.prototype.Qc;Ni.prototype.setScale=Ni.prototype.Rc;v("ol.style.Image",Mi,OPENLAYERS);Mi.prototype.getOpacity=Mi.prototype.Mc;Mi.prototype.getRotateWithView=Mi.prototype.uc;Mi.prototype.getRotation=Mi.prototype.Nc;Mi.prototype.getScale=Mi.prototype.Oc;Mi.prototype.getSnapToPixel=Mi.prototype.vc;Mi.prototype.setOpacity=Mi.prototype.Pc;Mi.prototype.setRotation=Mi.prototype.Qc;Mi.prototype.setScale=Mi.prototype.Rc; -v("ol.style.RegularShape",ks,OPENLAYERS);ks.prototype.getAnchor=ks.prototype.eb;ks.prototype.getAngle=ks.prototype.ij;ks.prototype.getFill=ks.prototype.jj;ks.prototype.getImage=ks.prototype.jb;ks.prototype.getOrigin=ks.prototype.ta;ks.prototype.getPoints=ks.prototype.kj;ks.prototype.getRadius=ks.prototype.lj;ks.prototype.getRadius2=ks.prototype.Tg;ks.prototype.getSize=ks.prototype.Ta;ks.prototype.getStroke=ks.prototype.mj;ks.prototype.getOpacity=ks.prototype.Mc;ks.prototype.getRotateWithView=ks.prototype.uc; -ks.prototype.getRotation=ks.prototype.Nc;ks.prototype.getScale=ks.prototype.Oc;ks.prototype.getSnapToPixel=ks.prototype.vc;ks.prototype.setOpacity=ks.prototype.Pc;ks.prototype.setRotation=ks.prototype.Qc;ks.prototype.setScale=ks.prototype.Rc;v("ol.style.Stroke",pk,OPENLAYERS);pk.prototype.getColor=pk.prototype.nj;pk.prototype.getLineCap=pk.prototype.Gg;pk.prototype.getLineDash=pk.prototype.oj;pk.prototype.getLineJoin=pk.prototype.Hg;pk.prototype.getMiterLimit=pk.prototype.Lg; -pk.prototype.getWidth=pk.prototype.pj;pk.prototype.setColor=pk.prototype.qj;pk.prototype.setLineCap=pk.prototype.gk;pk.prototype.setLineDash=pk.prototype.rj;pk.prototype.setLineJoin=pk.prototype.hk;pk.prototype.setMiterLimit=pk.prototype.ik;pk.prototype.setWidth=pk.prototype.nk;v("ol.style.Style",rk,OPENLAYERS);rk.prototype.getGeometry=rk.prototype.O;rk.prototype.getGeometryFunction=rk.prototype.Ag;rk.prototype.getFill=rk.prototype.sj;rk.prototype.getImage=rk.prototype.tj;rk.prototype.getStroke=rk.prototype.uj; -rk.prototype.getText=rk.prototype.oa;rk.prototype.getZIndex=rk.prototype.vj;rk.prototype.setGeometry=rk.prototype.gf;rk.prototype.setZIndex=rk.prototype.wj;v("ol.style.Text",Qo,OPENLAYERS);Qo.prototype.getFont=Qo.prototype.xg;Qo.prototype.getOffsetX=Qo.prototype.Mg;Qo.prototype.getOffsetY=Qo.prototype.Ng;Qo.prototype.getFill=Qo.prototype.xj;Qo.prototype.getRotation=Qo.prototype.yj;Qo.prototype.getScale=Qo.prototype.zj;Qo.prototype.getStroke=Qo.prototype.Aj;Qo.prototype.getText=Qo.prototype.oa; -Qo.prototype.getTextAlign=Qo.prototype.Wg;Qo.prototype.getTextBaseline=Qo.prototype.Xg;Qo.prototype.setFont=Qo.prototype.bk;Qo.prototype.setOffsetX=Qo.prototype.tf;Qo.prototype.setOffsetY=Qo.prototype.uf;Qo.prototype.setFill=Qo.prototype.ak;Qo.prototype.setRotation=Qo.prototype.Bj;Qo.prototype.setScale=Qo.prototype.Cj;Qo.prototype.setStroke=Qo.prototype.kk;Qo.prototype.setText=Qo.prototype.wf;Qo.prototype.setTextAlign=Qo.prototype.xf;Qo.prototype.setTextBaseline=Qo.prototype.lk; -v("ol.source.ImageVector",rn,OPENLAYERS);rn.prototype.getSource=rn.prototype.Pi;rn.prototype.getStyle=rn.prototype.Qi;rn.prototype.getStyleFunction=rn.prototype.Ri;rn.prototype.setStyle=rn.prototype.Xe;rn.prototype.getAttributions=rn.prototype.Bb;rn.prototype.getLogo=rn.prototype.tb;rn.prototype.getProjection=rn.prototype.Cb;rn.prototype.getState=rn.prototype.Db;rn.prototype.setAttributions=rn.prototype.Fb;rn.prototype.get=rn.prototype.get;rn.prototype.getKeys=rn.prototype.L; -rn.prototype.getProperties=rn.prototype.P;rn.prototype.set=rn.prototype.C;rn.prototype.setProperties=rn.prototype.K;rn.prototype.unset=rn.prototype.W;rn.prototype.changed=rn.prototype.v;rn.prototype.dispatchEvent=rn.prototype.b;rn.prototype.getRevision=rn.prototype.S;rn.prototype.on=rn.prototype.M;rn.prototype.once=rn.prototype.T;rn.prototype.un=rn.prototype.U;rn.prototype.unByKey=rn.prototype.V;v("ol.source.ImageWMS",bs,OPENLAYERS);bs.prototype.getGetFeatureInfoUrl=bs.prototype.Ui; -bs.prototype.getParams=bs.prototype.Vi;bs.prototype.getImageLoadFunction=bs.prototype.Cg;bs.prototype.getUrl=bs.prototype.Zg;bs.prototype.setImageLoadFunction=bs.prototype.ek;bs.prototype.setUrl=bs.prototype.Wi;bs.prototype.updateParams=bs.prototype.Xi;bs.prototype.getAttributions=bs.prototype.Bb;bs.prototype.getLogo=bs.prototype.tb;bs.prototype.getProjection=bs.prototype.Cb;bs.prototype.getState=bs.prototype.Db;bs.prototype.setAttributions=bs.prototype.Fb;bs.prototype.get=bs.prototype.get; -bs.prototype.getKeys=bs.prototype.L;bs.prototype.getProperties=bs.prototype.P;bs.prototype.set=bs.prototype.C;bs.prototype.setProperties=bs.prototype.K;bs.prototype.unset=bs.prototype.W;bs.prototype.changed=bs.prototype.v;bs.prototype.dispatchEvent=bs.prototype.b;bs.prototype.getRevision=bs.prototype.S;bs.prototype.on=bs.prototype.M;bs.prototype.once=bs.prototype.T;bs.prototype.un=bs.prototype.U;bs.prototype.unByKey=bs.prototype.V;v("ol.source.TileImage",X,OPENLAYERS); -X.prototype.setRenderReprojectionEdges=X.prototype.Ud;X.prototype.setTileGridForProjection=X.prototype.Wd;X.prototype.getTileLoadFunction=X.prototype.wd;X.prototype.getTileUrlFunction=X.prototype.xd;X.prototype.getUrls=X.prototype.yd;X.prototype.setTileLoadFunction=X.prototype.Xd;X.prototype.setTileUrlFunction=X.prototype.Hb;X.prototype.setUrl=X.prototype.Kc;X.prototype.setUrls=X.prototype.Vc;X.prototype.getTileGrid=X.prototype.vd;X.prototype.getAttributions=X.prototype.Bb;X.prototype.getLogo=X.prototype.tb; -X.prototype.getProjection=X.prototype.Cb;X.prototype.getState=X.prototype.Db;X.prototype.setAttributions=X.prototype.Fb;X.prototype.get=X.prototype.get;X.prototype.getKeys=X.prototype.L;X.prototype.getProperties=X.prototype.P;X.prototype.set=X.prototype.C;X.prototype.setProperties=X.prototype.K;X.prototype.unset=X.prototype.W;X.prototype.changed=X.prototype.v;X.prototype.dispatchEvent=X.prototype.b;X.prototype.getRevision=X.prototype.S;X.prototype.on=X.prototype.M;X.prototype.once=X.prototype.T; -X.prototype.un=X.prototype.U;X.prototype.unByKey=X.prototype.V;v("ol.source.TileWMS",Y,OPENLAYERS);Y.prototype.getGetFeatureInfoUrl=Y.prototype.Yi;Y.prototype.getParams=Y.prototype.Zi;Y.prototype.updateParams=Y.prototype.$i;Y.prototype.setRenderReprojectionEdges=Y.prototype.Ud;Y.prototype.setTileGridForProjection=Y.prototype.Wd;Y.prototype.getTileLoadFunction=Y.prototype.wd;Y.prototype.getTileUrlFunction=Y.prototype.xd;Y.prototype.getUrls=Y.prototype.yd;Y.prototype.setTileLoadFunction=Y.prototype.Xd; -Y.prototype.setTileUrlFunction=Y.prototype.Hb;Y.prototype.setUrl=Y.prototype.Kc;Y.prototype.setUrls=Y.prototype.Vc;Y.prototype.getTileGrid=Y.prototype.vd;Y.prototype.getAttributions=Y.prototype.Bb;Y.prototype.getLogo=Y.prototype.tb;Y.prototype.getProjection=Y.prototype.Cb;Y.prototype.getState=Y.prototype.Db;Y.prototype.setAttributions=Y.prototype.Fb;Y.prototype.get=Y.prototype.get;Y.prototype.getKeys=Y.prototype.L;Y.prototype.getProperties=Y.prototype.P;Y.prototype.set=Y.prototype.C; -Y.prototype.setProperties=Y.prototype.K;Y.prototype.unset=Y.prototype.W;Y.prototype.changed=Y.prototype.v;Y.prototype.dispatchEvent=Y.prototype.b;Y.prototype.getRevision=Y.prototype.S;Y.prototype.on=Y.prototype.M;Y.prototype.once=Y.prototype.T;Y.prototype.un=Y.prototype.U;Y.prototype.unByKey=Y.prototype.V;v("ol.source.Vector",N,OPENLAYERS);N.prototype.addFeature=N.prototype.Lc;N.prototype.addFeatures=N.prototype.ad;N.prototype.clear=N.prototype.clear;N.prototype.forEachFeature=N.prototype.dg; -N.prototype.forEachFeatureInExtent=N.prototype.qb;N.prototype.forEachFeatureIntersectingExtent=N.prototype.fg;N.prototype.getFeaturesCollection=N.prototype.vg;N.prototype.getFeatures=N.prototype.af;N.prototype.getFeaturesAtCoordinate=N.prototype.ug;N.prototype.getFeaturesInExtent=N.prototype.wg;N.prototype.getClosestFeatureToCoordinate=N.prototype.og;N.prototype.getExtent=N.prototype.F;N.prototype.getFeatureById=N.prototype.tg;N.prototype.removeFeature=N.prototype.fc;N.prototype.getAttributions=N.prototype.Bb; -N.prototype.getLogo=N.prototype.tb;N.prototype.getProjection=N.prototype.Cb;N.prototype.getState=N.prototype.Db;N.prototype.setAttributions=N.prototype.Fb;N.prototype.get=N.prototype.get;N.prototype.getKeys=N.prototype.L;N.prototype.getProperties=N.prototype.P;N.prototype.set=N.prototype.C;N.prototype.setProperties=N.prototype.K;N.prototype.unset=N.prototype.W;N.prototype.changed=N.prototype.v;N.prototype.dispatchEvent=N.prototype.b;N.prototype.getRevision=N.prototype.S;N.prototype.on=N.prototype.M; -N.prototype.once=N.prototype.T;N.prototype.un=N.prototype.U;N.prototype.unByKey=N.prototype.V;v("ol.source.WMTS",Z,OPENLAYERS);Z.prototype.getDimensions=Z.prototype.rg;Z.prototype.getFormat=Z.prototype.bj;Z.prototype.getLayer=Z.prototype.cj;Z.prototype.getMatrixSet=Z.prototype.Kg;Z.prototype.getRequestEncoding=Z.prototype.Ug;Z.prototype.getStyle=Z.prototype.dj;Z.prototype.getVersion=Z.prototype.$g;Z.prototype.updateDimensions=Z.prototype.xk;Z.prototype.setRenderReprojectionEdges=Z.prototype.Ud; -Z.prototype.setTileGridForProjection=Z.prototype.Wd;Z.prototype.getTileLoadFunction=Z.prototype.wd;Z.prototype.getTileUrlFunction=Z.prototype.xd;Z.prototype.getUrls=Z.prototype.yd;Z.prototype.setTileLoadFunction=Z.prototype.Xd;Z.prototype.setTileUrlFunction=Z.prototype.Hb;Z.prototype.setUrl=Z.prototype.Kc;Z.prototype.setUrls=Z.prototype.Vc;Z.prototype.getTileGrid=Z.prototype.vd;Z.prototype.getAttributions=Z.prototype.Bb;Z.prototype.getLogo=Z.prototype.tb;Z.prototype.getProjection=Z.prototype.Cb; -Z.prototype.getState=Z.prototype.Db;Z.prototype.setAttributions=Z.prototype.Fb;Z.prototype.get=Z.prototype.get;Z.prototype.getKeys=Z.prototype.L;Z.prototype.getProperties=Z.prototype.P;Z.prototype.set=Z.prototype.C;Z.prototype.setProperties=Z.prototype.K;Z.prototype.unset=Z.prototype.W;Z.prototype.changed=Z.prototype.v;Z.prototype.dispatchEvent=Z.prototype.b;Z.prototype.getRevision=Z.prototype.S;Z.prototype.on=Z.prototype.M;Z.prototype.once=Z.prototype.T;Z.prototype.un=Z.prototype.U; -Z.prototype.unByKey=Z.prototype.V;v("ol.tilegrid.TileGrid",sg,OPENLAYERS);sg.prototype.getMaxZoom=sg.prototype.xe;sg.prototype.getMinZoom=sg.prototype.ye;sg.prototype.getOrigin=sg.prototype.ta;sg.prototype.getResolution=sg.prototype.$;sg.prototype.getResolutions=sg.prototype.hf;sg.prototype.getTileCoordExtent=sg.prototype.Ca;sg.prototype.getTileCoordForCoordAndResolution=sg.prototype.td;sg.prototype.getTileCoordForCoordAndZ=sg.prototype.ud;sg.prototype.getTileSize=sg.prototype.Ia; -v("ol.tilegrid.WMTS",is,OPENLAYERS);is.prototype.getMatrixIds=is.prototype.l;is.prototype.getMaxZoom=is.prototype.xe;is.prototype.getMinZoom=is.prototype.ye;is.prototype.getOrigin=is.prototype.ta;is.prototype.getResolution=is.prototype.$;is.prototype.getResolutions=is.prototype.hf;is.prototype.getTileCoordExtent=is.prototype.Ca;is.prototype.getTileCoordForCoordAndResolution=is.prototype.td;is.prototype.getTileCoordForCoordAndZ=is.prototype.ud;is.prototype.getTileSize=is.prototype.Ia; - return OPENLAYERS.ol; -})); - diff --git a/src/lib/ol3cesium-debug.js b/src/lib/ol3cesium-debug.js index 0f273619b9..f318971659 100644 --- a/src/lib/ol3cesium-debug.js +++ b/src/lib/ol3cesium-debug.js @@ -1,6 +1,6 @@ // Ol3-Cesium. See https://github.com/openlayers/ol3-cesium/ // License: https://github.com/openlayers/ol3-cesium/blob/master/LICENSE -// Version: v1.9-33-gc68901a +// Version: v1.9-43-gdbbc31d var CLOSURE_NO_DEPS = true; // Copyright 2006 The Closure Library Authors. All Rights Reserved. @@ -2185,8 +2185,8 @@ goog.exportProperty = function(object, publicName, symbol) { * child.foo(); // This works. * </pre> * - * @param {Function} childCtor Child class. - * @param {Function} parentCtor Parent class. + * @param {!Function} childCtor Child class. + * @param {!Function} parentCtor Parent class. */ goog.inherits = function(childCtor, parentCtor) { /** @constructor */ @@ -2516,2392 +2516,2892 @@ goog.tagUnsealableClass = function(ctr) { */ goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable'; -goog.provide('ol.ext.pbf'); -/** @typedef {function(*)} */ -ol.ext.pbf; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} + * @fileoverview Utilities for manipulating objects/maps/hashes. + * @author arv@google.com (Erik Arvidsson) */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pbf = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ -'use strict'; -// lightweight Buffer shim for pbf browser build -// based on code from github.com/feross/buffer (MIT-licensed) +goog.provide('goog.object'); -module.exports = Buffer; -var ieee754 = _dereq_('ieee754'); +/** + * Calls a function for each element in an object/map/hash. + * + * @param {Object<K,V>} obj The object over which to iterate. + * @param {function(this:T,V,?,Object<K,V>):?} f The function to call + * for every element. This function takes 3 arguments (the value, the + * key and the object) and the return value is ignored. + * @param {T=} opt_obj This is used as the 'this' object within f. + * @template T,K,V + */ +goog.object.forEach = function(obj, f, opt_obj) { + for (var key in obj) { + f.call(opt_obj, obj[key], key, obj); + } +}; -var BufferMethods; -function Buffer(length) { - var arr; - if (length && length.length) { - arr = length; - length = arr.length; +/** + * Calls a function for each element in an object/map/hash. If that call returns + * true, adds the element to a new object. + * + * @param {Object<K,V>} obj The object over which to iterate. + * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to call + * for every element. This + * function takes 3 arguments (the value, the key and the object) + * and should return a boolean. If the return value is true the + * element is added to the result object. If it is false the + * element is not included. + * @param {T=} opt_obj This is used as the 'this' object within f. + * @return {!Object<K,V>} a new object in which only elements that passed the + * test are present. + * @template T,K,V + */ +goog.object.filter = function(obj, f, opt_obj) { + var res = {}; + for (var key in obj) { + if (f.call(opt_obj, obj[key], key, obj)) { + res[key] = obj[key]; } - var buf = new Uint8Array(length || 0); - if (arr) buf.set(arr); - - buf.readUInt32LE = BufferMethods.readUInt32LE; - buf.writeUInt32LE = BufferMethods.writeUInt32LE; - buf.readInt32LE = BufferMethods.readInt32LE; - buf.writeInt32LE = BufferMethods.writeInt32LE; - buf.readFloatLE = BufferMethods.readFloatLE; - buf.writeFloatLE = BufferMethods.writeFloatLE; - buf.readDoubleLE = BufferMethods.readDoubleLE; - buf.writeDoubleLE = BufferMethods.writeDoubleLE; - buf.toString = BufferMethods.toString; - buf.write = BufferMethods.write; - buf.slice = BufferMethods.slice; - buf.copy = BufferMethods.copy; - - buf._isBuffer = true; - return buf; -} + } + return res; +}; -var lastStr, lastStrEncoded; -BufferMethods = { - readUInt32LE: function(pos) { - return ((this[pos]) | - (this[pos + 1] << 8) | - (this[pos + 2] << 16)) + - (this[pos + 3] * 0x1000000); - }, +/** + * For every element in an object/map/hash calls a function and inserts the + * result into a new object. + * + * @param {Object<K,V>} obj The object over which to iterate. + * @param {function(this:T,V,?,Object<K,V>):R} f The function to call + * for every element. This function + * takes 3 arguments (the value, the key and the object) + * and should return something. The result will be inserted + * into a new object. + * @param {T=} opt_obj This is used as the 'this' object within f. + * @return {!Object<K,R>} a new object with the results from f. + * @template T,K,V,R + */ +goog.object.map = function(obj, f, opt_obj) { + var res = {}; + for (var key in obj) { + res[key] = f.call(opt_obj, obj[key], key, obj); + } + return res; +}; - writeUInt32LE: function(val, pos) { - this[pos] = val; - this[pos + 1] = (val >>> 8); - this[pos + 2] = (val >>> 16); - this[pos + 3] = (val >>> 24); - }, - readInt32LE: function(pos) { - return ((this[pos]) | - (this[pos + 1] << 8) | - (this[pos + 2] << 16)) + - (this[pos + 3] << 24); - }, +/** + * Calls a function for each element in an object/map/hash. If any + * call returns true, returns true (without checking the rest). If + * all calls return false, returns false. + * + * @param {Object<K,V>} obj The object to check. + * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to + * call for every element. This function + * takes 3 arguments (the value, the key and the object) and should + * return a boolean. + * @param {T=} opt_obj This is used as the 'this' object within f. + * @return {boolean} true if any element passes the test. + * @template T,K,V + */ +goog.object.some = function(obj, f, opt_obj) { + for (var key in obj) { + if (f.call(opt_obj, obj[key], key, obj)) { + return true; + } + } + return false; +}; - readFloatLE: function(pos) { return ieee754.read(this, pos, true, 23, 4); }, - readDoubleLE: function(pos) { return ieee754.read(this, pos, true, 52, 8); }, - writeFloatLE: function(val, pos) { return ieee754.write(this, val, pos, true, 23, 4); }, - writeDoubleLE: function(val, pos) { return ieee754.write(this, val, pos, true, 52, 8); }, +/** + * Calls a function for each element in an object/map/hash. If + * all calls return true, returns true. If any call returns false, returns + * false at this point and does not continue to check the remaining elements. + * + * @param {Object<K,V>} obj The object to check. + * @param {?function(this:T,V,?,Object<K,V>):boolean} f The function to + * call for every element. This function + * takes 3 arguments (the value, the key and the object) and should + * return a boolean. + * @param {T=} opt_obj This is used as the 'this' object within f. + * @return {boolean} false if any element fails the test. + * @template T,K,V + */ +goog.object.every = function(obj, f, opt_obj) { + for (var key in obj) { + if (!f.call(opt_obj, obj[key], key, obj)) { + return false; + } + } + return true; +}; - toString: function(encoding, start, end) { - var str = '', - tmp = ''; - start = start || 0; - end = Math.min(this.length, end || this.length); +/** + * Returns the number of key-value pairs in the object map. + * + * @param {Object} obj The object for which to get the number of key-value + * pairs. + * @return {number} The number of key-value pairs in the object map. + */ +goog.object.getCount = function(obj) { + // JS1.5 has __count__ but it has been deprecated so it raises a warning... + // in other words do not use. Also __count__ only includes the fields on the + // actual object and not in the prototype chain. + var rv = 0; + for (var key in obj) { + rv++; + } + return rv; +}; - for (var i = start; i < end; i++) { - var ch = this[i]; - if (ch <= 0x7F) { - str += decodeURIComponent(tmp) + String.fromCharCode(ch); - tmp = ''; - } else { - tmp += '%' + ch.toString(16); - } - } - str += decodeURIComponent(tmp); +/** + * Returns one key from the object map, if any exists. + * For map literals the returned key will be the first one in most of the + * browsers (a know exception is Konqueror). + * + * @param {Object} obj The object to pick a key from. + * @return {string|undefined} The key or undefined if the object is empty. + */ +goog.object.getAnyKey = function(obj) { + for (var key in obj) { + return key; + } +}; - return str; - }, - write: function(str, pos) { - var bytes = str === lastStr ? lastStrEncoded : encodeString(str); - for (var i = 0; i < bytes.length; i++) { - this[pos + i] = bytes[i]; - } - }, +/** + * Returns one value from the object map, if any exists. + * For map literals the returned value will be the first one in most of the + * browsers (a know exception is Konqueror). + * + * @param {Object<K,V>} obj The object to pick a value from. + * @return {V|undefined} The value or undefined if the object is empty. + * @template K,V + */ +goog.object.getAnyValue = function(obj) { + for (var key in obj) { + return obj[key]; + } +}; - slice: function(start, end) { - return this.subarray(start, end); - }, - copy: function(buf, pos) { - pos = pos || 0; - for (var i = 0; i < this.length; i++) { - buf[pos + i] = this[i]; - } - } +/** + * Whether the object/hash/map contains the given object as a value. + * An alias for goog.object.containsValue(obj, val). + * + * @param {Object<K,V>} obj The object in which to look for val. + * @param {V} val The object for which to check. + * @return {boolean} true if val is present. + * @template K,V + */ +goog.object.contains = function(obj, val) { + return goog.object.containsValue(obj, val); }; -BufferMethods.writeInt32LE = BufferMethods.writeUInt32LE; -Buffer.byteLength = function(str) { - lastStr = str; - lastStrEncoded = encodeString(str); - return lastStrEncoded.length; +/** + * Returns the values of the object/map/hash. + * + * @param {Object<K,V>} obj The object from which to get the values. + * @return {!Array<V>} The values in the object/map/hash. + * @template K,V + */ +goog.object.getValues = function(obj) { + var res = []; + var i = 0; + for (var key in obj) { + res[i++] = obj[key]; + } + return res; }; -Buffer.isBuffer = function(buf) { - return !!(buf && buf._isBuffer); -}; -function encodeString(str) { - var length = str.length, - bytes = []; +/** + * Returns the keys of the object/map/hash. + * + * @param {Object} obj The object from which to get the keys. + * @return {!Array<string>} Array of property keys. + */ +goog.object.getKeys = function(obj) { + var res = []; + var i = 0; + for (var key in obj) { + res[i++] = key; + } + return res; +}; - for (var i = 0, c, lead; i < length; i++) { - c = str.charCodeAt(i); // code point - if (c > 0xD7FF && c < 0xE000) { +/** + * Get a value from an object multiple levels deep. This is useful for + * pulling values from deeply nested objects, such as JSON responses. + * Example usage: getValueByKeys(jsonObj, 'foo', 'entries', 3) + * + * @param {!Object} obj An object to get the value from. Can be array-like. + * @param {...(string|number|!Array<number|string>)} var_args A number of keys + * (as strings, or numbers, for array-like objects). Can also be + * specified as a single array of keys. + * @return {*} The resulting value. If, at any point, the value for a key + * is undefined, returns undefined. + */ +goog.object.getValueByKeys = function(obj, var_args) { + var isArrayLike = goog.isArrayLike(var_args); + var keys = isArrayLike ? var_args : arguments; - if (lead) { - if (c < 0xDC00) { - bytes.push(0xEF, 0xBF, 0xBD); - lead = c; - continue; + // Start with the 2nd parameter for the variable parameters syntax. + for (var i = isArrayLike ? 0 : 1; i < keys.length; i++) { + obj = obj[keys[i]]; + if (!goog.isDef(obj)) { + break; + } + } - } else { - c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; - lead = null; - } + return obj; +}; - } else { - if (c > 0xDBFF || (i + 1 === length)) bytes.push(0xEF, 0xBF, 0xBD); - else lead = c; - continue; - } +/** + * Whether the object/map/hash contains the given key. + * + * @param {Object} obj The object in which to look for key. + * @param {*} key The key for which to check. + * @return {boolean} true If the map contains the key. + */ +goog.object.containsKey = function(obj, key) { + return key in obj; +}; - } else if (lead) { - bytes.push(0xEF, 0xBF, 0xBD); - lead = null; - } - if (c < 0x80) bytes.push(c); - else if (c < 0x800) bytes.push(c >> 0x6 | 0xC0, c & 0x3F | 0x80); - else if (c < 0x10000) bytes.push(c >> 0xC | 0xE0, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); - else bytes.push(c >> 0x12 | 0xF0, c >> 0xC & 0x3F | 0x80, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); +/** + * Whether the object/map/hash contains the given value. This is O(n). + * + * @param {Object<K,V>} obj The object in which to look for val. + * @param {V} val The value for which to check. + * @return {boolean} true If the map contains the value. + * @template K,V + */ +goog.object.containsValue = function(obj, val) { + for (var key in obj) { + if (obj[key] == val) { + return true; } - return bytes; -} - -},{"ieee754":3}],2:[function(_dereq_,module,exports){ -(function (global){ -'use strict'; + } + return false; +}; -module.exports = Pbf; -var Buffer = global.Buffer || _dereq_('./buffer'); +/** + * Searches an object for an element that satisfies the given condition and + * returns its key. + * @param {Object<K,V>} obj The object to search in. + * @param {function(this:T,V,string,Object<K,V>):boolean} f The + * function to call for every element. Takes 3 arguments (the value, + * the key and the object) and should return a boolean. + * @param {T=} opt_this An optional "this" context for the function. + * @return {string|undefined} The key of an element for which the function + * returns true or undefined if no such element is found. + * @template T,K,V + */ +goog.object.findKey = function(obj, f, opt_this) { + for (var key in obj) { + if (f.call(opt_this, obj[key], key, obj)) { + return key; + } + } + return undefined; +}; -function Pbf(buf) { - this.buf = !Buffer.isBuffer(buf) ? new Buffer(buf || 0) : buf; - this.pos = 0; - this.length = this.buf.length; -} -Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum -Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 -Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields -Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 +/** + * Searches an object for an element that satisfies the given condition and + * returns its value. + * @param {Object<K,V>} obj The object to search in. + * @param {function(this:T,V,string,Object<K,V>):boolean} f The function + * to call for every element. Takes 3 arguments (the value, the key + * and the object) and should return a boolean. + * @param {T=} opt_this An optional "this" context for the function. + * @return {V} The value of an element for which the function returns true or + * undefined if no such element is found. + * @template T,K,V + */ +goog.object.findValue = function(obj, f, opt_this) { + var key = goog.object.findKey(obj, f, opt_this); + return key && obj[key]; +}; -var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), - SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32, - POW_2_63 = Math.pow(2, 63); -Pbf.prototype = { +/** + * Whether the object/map/hash is empty. + * + * @param {Object} obj The object to test. + * @return {boolean} true if obj is empty. + */ +goog.object.isEmpty = function(obj) { + for (var key in obj) { + return false; + } + return true; +}; - destroy: function() { - this.buf = null; - }, - // === READING ================================================================= +/** + * Removes all key value pairs from the object/map/hash. + * + * @param {Object} obj The object to clear. + */ +goog.object.clear = function(obj) { + for (var i in obj) { + delete obj[i]; + } +}; - readFields: function(readField, result, end) { - end = end || this.length; - while (this.pos < end) { - var val = this.readVarint(), - tag = val >> 3, - startPos = this.pos; +/** + * Removes a key-value pair based on the key. + * + * @param {Object} obj The object from which to remove the key. + * @param {*} key The key to remove. + * @return {boolean} Whether an element was removed. + */ +goog.object.remove = function(obj, key) { + var rv; + if ((rv = key in obj)) { + delete obj[key]; + } + return rv; +}; - readField(tag, result, this); - if (this.pos === startPos) this.skip(val); - } - return result; - }, +/** + * Adds a key-value pair to the object. Throws an exception if the key is + * already in use. Use set if you want to change an existing pair. + * + * @param {Object<K,V>} obj The object to which to add the key-value pair. + * @param {string} key The key to add. + * @param {V} val The value to add. + * @template K,V + */ +goog.object.add = function(obj, key, val) { + if (key in obj) { + throw Error('The object already contains the key "' + key + '"'); + } + goog.object.set(obj, key, val); +}; - readMessage: function(readField, result) { - return this.readFields(readField, result, this.readVarint() + this.pos); - }, - readFixed32: function() { - var val = this.buf.readUInt32LE(this.pos); - this.pos += 4; - return val; - }, +/** + * Returns the value for the given key. + * + * @param {Object<K,V>} obj The object from which to get the value. + * @param {string} key The key for which to get the value. + * @param {R=} opt_val The value to return if no item is found for the given + * key (default is undefined). + * @return {V|R|undefined} The value for the given key. + * @template K,V,R + */ +goog.object.get = function(obj, key, opt_val) { + if (key in obj) { + return obj[key]; + } + return opt_val; +}; - readSFixed32: function() { - var val = this.buf.readInt32LE(this.pos); - this.pos += 4; - return val; - }, - // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) +/** + * Adds a key-value pair to the object/map/hash. + * + * @param {Object<K,V>} obj The object to which to add the key-value pair. + * @param {string} key The key to add. + * @param {V} value The value to add. + * @template K,V + */ +goog.object.set = function(obj, key, value) { + obj[key] = value; +}; - readFixed64: function() { - var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, - readSFixed64: function() { - var val = this.buf.readUInt32LE(this.pos) + this.buf.readInt32LE(this.pos + 4) * SHIFT_LEFT_32; - this.pos += 8; - return val; - }, +/** + * Adds a key-value pair to the object/map/hash if it doesn't exist yet. + * + * @param {Object<K,V>} obj The object to which to add the key-value pair. + * @param {string} key The key to add. + * @param {V} value The value to add if the key wasn't present. + * @return {V} The value of the entry at the end of the function. + * @template K,V + */ +goog.object.setIfUndefined = function(obj, key, value) { + return key in obj ? obj[key] : (obj[key] = value); +}; - readFloat: function() { - var val = this.buf.readFloatLE(this.pos); - this.pos += 4; - return val; - }, - readDouble: function() { - var val = this.buf.readDoubleLE(this.pos); - this.pos += 8; - return val; - }, +/** + * Sets a key and value to an object if the key is not set. The value will be + * the return value of the given function. If the key already exists, the + * object will not be changed and the function will not be called (the function + * will be lazily evaluated -- only called if necessary). + * + * This function is particularly useful for use with a map used a as a cache. + * + * @param {!Object<K,V>} obj The object to which to add the key-value pair. + * @param {string} key The key to add. + * @param {function():V} f The value to add if the key wasn't present. + * @return {V} The value of the entry at the end of the function. + * @template K,V + */ +goog.object.setWithReturnValueIfNotSet = function(obj, key, f) { + if (key in obj) { + return obj[key]; + } - readVarint: function() { - var buf = this.buf, - val, b, b0, b1, b2, b3; + var val = f(); + obj[key] = val; + return val; +}; - b0 = buf[this.pos++]; if (b0 < 0x80) return b0; b0 = b0 & 0x7f; - b1 = buf[this.pos++]; if (b1 < 0x80) return b0 | b1 << 7; b1 = (b1 & 0x7f) << 7; - b2 = buf[this.pos++]; if (b2 < 0x80) return b0 | b1 | b2 << 14; b2 = (b2 & 0x7f) << 14; - b3 = buf[this.pos++]; if (b3 < 0x80) return b0 | b1 | b2 | b3 << 21; - val = b0 | b1 | b2 | (b3 & 0x7f) << 21; +/** + * Compares two objects for equality using === on the values. + * + * @param {!Object<K,V>} a + * @param {!Object<K,V>} b + * @return {boolean} + * @template K,V + */ +goog.object.equals = function(a, b) { + for (var k in a) { + if (!(k in b) || a[k] !== b[k]) { + return false; + } + } + for (var k in b) { + if (!(k in a)) { + return false; + } + } + return true; +}; - b = buf[this.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val; - b = buf[this.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val; - throw new Error('Expected varint not more than 10 bytes'); - }, +/** + * Does a flat clone of the object. + * + * @param {Object<K,V>} obj Object to clone. + * @return {!Object<K,V>} Clone of the input object. + * @template K,V + */ +goog.object.clone = function(obj) { + // We cannot use the prototype trick because a lot of methods depend on where + // the actual key is set. - readVarint64: function() { - var startPos = this.pos, - val = this.readVarint(); + var res = {}; + for (var key in obj) { + res[key] = obj[key]; + } + return res; + // We could also use goog.mixin but I wanted this to be independent from that. +}; - if (val < POW_2_63) return val; - var pos = this.pos - 2; - while (this.buf[pos] === 0xff) pos--; - if (pos < startPos) pos = startPos; +/** + * Clones a value. The input may be an Object, Array, or basic type. Objects and + * arrays will be cloned recursively. + * + * WARNINGS: + * <code>goog.object.unsafeClone</code> does not detect reference loops. Objects + * that refer to themselves will cause infinite recursion. + * + * <code>goog.object.unsafeClone</code> is unaware of unique identifiers, and + * copies UIDs created by <code>getUid</code> into cloned results. + * + * @param {*} obj The value to clone. + * @return {*} A clone of the input value. + */ +goog.object.unsafeClone = function(obj) { + var type = goog.typeOf(obj); + if (type == 'object' || type == 'array') { + if (goog.isFunction(obj.clone)) { + return obj.clone(); + } + var clone = type == 'array' ? [] : {}; + for (var key in obj) { + clone[key] = goog.object.unsafeClone(obj[key]); + } + return clone; + } - val = 0; - for (var i = 0; i < pos - startPos + 1; i++) { - var b = ~this.buf[startPos + i] & 0x7f; - val += i < 4 ? b << i * 7 : b * Math.pow(2, i * 7); - } + return obj; +}; - return -val - 1; - }, - readSVarint: function() { - var num = this.readVarint(); - return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding - }, +/** + * Returns a new object in which all the keys and values are interchanged + * (keys become values and values become keys). If multiple keys map to the + * same value, the chosen transposed value is implementation-dependent. + * + * @param {Object} obj The object to transpose. + * @return {!Object} The transposed object. + */ +goog.object.transpose = function(obj) { + var transposed = {}; + for (var key in obj) { + transposed[obj[key]] = key; + } + return transposed; +}; - readBoolean: function() { - return Boolean(this.readVarint()); - }, - readString: function() { - var end = this.readVarint() + this.pos, - str = this.buf.toString('utf8', this.pos, end); - this.pos = end; - return str; - }, +/** + * The names of the fields that are defined on Object.prototype. + * @type {Array<string>} + * @private + */ +goog.object.PROTOTYPE_FIELDS_ = [ + 'constructor', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + 'toString', + 'valueOf' +]; - readBytes: function() { - var end = this.readVarint() + this.pos, - buffer = this.buf.slice(this.pos, end); - this.pos = end; - return buffer; - }, - // verbose for performance reasons; doesn't affect gzipped size +/** + * Extends an object with another object. + * This operates 'in-place'; it does not create a new Object. + * + * Example: + * var o = {}; + * goog.object.extend(o, {a: 0, b: 1}); + * o; // {a: 0, b: 1} + * goog.object.extend(o, {b: 2, c: 3}); + * o; // {a: 0, b: 2, c: 3} + * + * @param {Object} target The object to modify. Existing properties will be + * overwritten if they are also present in one of the objects in + * {@code var_args}. + * @param {...Object} var_args The objects from which values will be copied. + */ +goog.object.extend = function(target, var_args) { + var key, source; + for (var i = 1; i < arguments.length; i++) { + source = arguments[i]; + for (key in source) { + target[key] = source[key]; + } - readPackedVarint: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readVarint()); - return arr; - }, - readPackedSVarint: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSVarint()); - return arr; - }, - readPackedBoolean: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readBoolean()); - return arr; - }, - readPackedFloat: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFloat()); - return arr; - }, - readPackedDouble: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readDouble()); - return arr; - }, - readPackedFixed32: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFixed32()); - return arr; - }, - readPackedSFixed32: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSFixed32()); - return arr; - }, - readPackedFixed64: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readFixed64()); - return arr; - }, - readPackedSFixed64: function() { - var end = this.readVarint() + this.pos, arr = []; - while (this.pos < end) arr.push(this.readSFixed64()); - return arr; - }, + // For IE the for-in-loop does not contain any properties that are not + // enumerable on the prototype object (for example isPrototypeOf from + // Object.prototype) and it will also not include 'replace' on objects that + // extend String and change 'replace' (not that it is common for anyone to + // extend anything except Object). - skip: function(val) { - var type = val & 0x7; - if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} - else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; - else if (type === Pbf.Fixed32) this.pos += 4; - else if (type === Pbf.Fixed64) this.pos += 8; - else throw new Error('Unimplemented type: ' + type); - }, + for (var j = 0; j < goog.object.PROTOTYPE_FIELDS_.length; j++) { + key = goog.object.PROTOTYPE_FIELDS_[j]; + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } +}; - // === WRITING ================================================================= - writeTag: function(tag, type) { - this.writeVarint((tag << 3) | type); - }, +/** + * Creates a new object built from the key-value pairs provided as arguments. + * @param {...*} var_args If only one argument is provided and it is an array + * then this is used as the arguments, otherwise even arguments are used as + * the property names and odd arguments are used as the property values. + * @return {!Object} The new object. + * @throws {Error} If there are uneven number of arguments or there is only one + * non array argument. + */ +goog.object.create = function(var_args) { + var argLength = arguments.length; + if (argLength == 1 && goog.isArray(arguments[0])) { + return goog.object.create.apply(null, arguments[0]); + } - realloc: function(min) { - var length = this.length || 16; + if (argLength % 2) { + throw Error('Uneven number of arguments'); + } - while (length < this.pos + min) length *= 2; + var rv = {}; + for (var i = 0; i < argLength; i += 2) { + rv[arguments[i]] = arguments[i + 1]; + } + return rv; +}; - if (length !== this.length) { - var buf = new Buffer(length); - this.buf.copy(buf); - this.buf = buf; - this.length = length; - } - }, - finish: function() { - this.length = this.pos; - this.pos = 0; - return this.buf.slice(0, this.length); - }, +/** + * Creates a new object where the property names come from the arguments but + * the value is always set to true + * @param {...*} var_args If only one argument is provided and it is an array + * then this is used as the arguments, otherwise the arguments are used + * as the property names. + * @return {!Object} The new object. + */ +goog.object.createSet = function(var_args) { + var argLength = arguments.length; + if (argLength == 1 && goog.isArray(arguments[0])) { + return goog.object.createSet.apply(null, arguments[0]); + } - writeFixed32: function(val) { - this.realloc(4); - this.buf.writeUInt32LE(val, this.pos); - this.pos += 4; - }, + var rv = {}; + for (var i = 0; i < argLength; i++) { + rv[arguments[i]] = true; + } + return rv; +}; - writeSFixed32: function(val) { - this.realloc(4); - this.buf.writeInt32LE(val, this.pos); - this.pos += 4; - }, - writeFixed64: function(val) { - this.realloc(8); - this.buf.writeInt32LE(val & -1, this.pos); - this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, +/** + * Creates an immutable view of the underlying object, if the browser + * supports immutable objects. + * + * In default mode, writes to this view will fail silently. In strict mode, + * they will throw an error. + * + * @param {!Object<K,V>} obj An object. + * @return {!Object<K,V>} An immutable view of that object, or the + * original object if this browser does not support immutables. + * @template K,V + */ +goog.object.createImmutableView = function(obj) { + var result = obj; + if (Object.isFrozen && !Object.isFrozen(obj)) { + result = Object.create(obj); + Object.freeze(result); + } + return result; +}; - writeSFixed64: function(val) { - this.realloc(8); - this.buf.writeInt32LE(val & -1, this.pos); - this.buf.writeInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); - this.pos += 8; - }, - writeVarint: function(val) { - val = +val; +/** + * @param {!Object} obj An object. + * @return {boolean} Whether this is an immutable view of the object. + */ +goog.object.isImmutableView = function(obj) { + return !!Object.isFrozen && Object.isFrozen(obj); +}; - if (val <= 0x7f) { - this.realloc(1); - this.buf[this.pos++] = val; +// Copyright 2009 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - } else if (val <= 0x3fff) { - this.realloc(2); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f); +/** + * @fileoverview Provides a base class for custom Error objects such that the + * stack is correctly maintained. + * + * You should never need to throw goog.debug.Error(msg) directly, Error(msg) is + * sufficient. + * + */ - } else if (val <= 0x1fffff) { - this.realloc(3); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 14) & 0x7f); +goog.provide('goog.debug.Error'); - } else if (val <= 0xfffffff) { - this.realloc(4); - this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 14) & 0x7f) | 0x80; - this.buf[this.pos++] = ((val >>> 21) & 0x7f); - } else { - var pos = this.pos; - while (val >= 0x80) { - this.realloc(1); - this.buf[this.pos++] = (val & 0xff) | 0x80; - val /= 0x80; - } - this.realloc(1); - this.buf[this.pos++] = val | 0; - if (this.pos - pos > 10) throw new Error('Given varint doesn\'t fit into 10 bytes'); - } - }, - writeSVarint: function(val) { - this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); - }, +/** + * Base class for custom error objects. + * @param {*=} opt_msg The message associated with the error. + * @constructor + * @extends {Error} + */ +goog.debug.Error = function(opt_msg) { - writeBoolean: function(val) { - this.writeVarint(Boolean(val)); - }, + // Attempt to ensure there is a stack trace. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, goog.debug.Error); + } else { + var stack = new Error().stack; + if (stack) { + this.stack = stack; + } + } - writeString: function(str) { - str = String(str); - var bytes = Buffer.byteLength(str); - this.writeVarint(bytes); - this.realloc(bytes); - this.buf.write(str, this.pos); - this.pos += bytes; - }, - - writeFloat: function(val) { - this.realloc(4); - this.buf.writeFloatLE(val, this.pos); - this.pos += 4; - }, - - writeDouble: function(val) { - this.realloc(8); - this.buf.writeDoubleLE(val, this.pos); - this.pos += 8; - }, - - writeBytes: function(buffer) { - var len = buffer.length; - this.writeVarint(len); - this.realloc(len); - for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; - }, - - writeRawMessage: function(fn, obj) { - this.pos++; // reserve 1 byte for short message length - - // write the message directly to the buffer and see how much was written - var startPos = this.pos; - fn(obj, this); - var len = this.pos - startPos; - - var varintLen = - len <= 0x7f ? 1 : - len <= 0x3fff ? 2 : - len <= 0x1fffff ? 3 : - len <= 0xfffffff ? 4 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); - - // if 1 byte isn't enough for encoding message length, shift the data to the right - if (varintLen > 1) { - this.realloc(varintLen - 1); - for (var i = this.pos - 1; i >= startPos; i--) this.buf[i + varintLen - 1] = this.buf[i]; - } - - // finally, write the message length in the reserved place and restore the position - this.pos = startPos - 1; - this.writeVarint(len); - this.pos += len; - }, - - writeMessage: function(tag, fn, obj) { - this.writeTag(tag, Pbf.Bytes); - this.writeRawMessage(fn, obj); - }, - - writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, - writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, - writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, - writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, - writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, - writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, - writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, - writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, - writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, + if (opt_msg) { + this.message = String(opt_msg); + } - writeBytesField: function(tag, buffer) { - this.writeTag(tag, Pbf.Bytes); - this.writeBytes(buffer); - }, - writeFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFixed32(val); - }, - writeSFixed32Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeSFixed32(val); - }, - writeFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeFixed64(val); - }, - writeSFixed64Field: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeSFixed64(val); - }, - writeVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeVarint(val); - }, - writeSVarintField: function(tag, val) { - this.writeTag(tag, Pbf.Varint); - this.writeSVarint(val); - }, - writeStringField: function(tag, str) { - this.writeTag(tag, Pbf.Bytes); - this.writeString(str); - }, - writeFloatField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed32); - this.writeFloat(val); - }, - writeDoubleField: function(tag, val) { - this.writeTag(tag, Pbf.Fixed64); - this.writeDouble(val); - }, - writeBooleanField: function(tag, val) { - this.writeVarintField(tag, Boolean(val)); - } + /** + * Whether to report this error to the server. Setting this to false will + * cause the error reporter to not report the error back to the server, + * which can be useful if the client knows that the error has already been + * logged on the server. + * @type {boolean} + */ + this.reportErrorToServer = true; }; +goog.inherits(goog.debug.Error, Error); -function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } -function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } -function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } -function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } -function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } -function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } -function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } -function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } -function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./buffer":1}],3:[function(_dereq_,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] +/** @override */ +goog.debug.Error.prototype.name = 'CustomError'; - i += d +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} +/** + * @fileoverview Definition of goog.dom.NodeType. + */ - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} +goog.provide('goog.dom.NodeType'); - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 +/** + * Constants for the nodeType attribute in the Node interface. + * + * These constants match those specified in the Node interface. These are + * usually present on the Node object in recent browsers, but not in older + * browsers (specifically, early IEs) and thus are given here. + * + * In some browsers (early IEs), these are not defined on the Node object, + * so they are provided here. + * + * See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247 + * @enum {number} + */ +goog.dom.NodeType = { + ELEMENT: 1, + ATTRIBUTE: 2, + TEXT: 3, + CDATA_SECTION: 4, + ENTITY_REFERENCE: 5, + ENTITY: 6, + PROCESSING_INSTRUCTION: 7, + COMMENT: 8, + DOCUMENT: 9, + DOCUMENT_TYPE: 10, + DOCUMENT_FRAGMENT: 11, + NOTATION: 12 +}; - value = Math.abs(value) +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } +/** + * @fileoverview Utilities for string manipulation. + * @author arv@google.com (Erik Arvidsson) + */ - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} +/** + * Namespace for string utilities + */ +goog.provide('goog.string'); +goog.provide('goog.string.Unicode'); - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - buffer[offset + i - d] |= s * 128 -} +/** + * @define {boolean} Enables HTML escaping of lowercase letter "e" which helps + * with detection of double-escaping as this letter is frequently used. + */ +goog.define('goog.string.DETECT_DOUBLE_ESCAPING', false); -},{}]},{},[2])(2) -}); -ol.ext.pbf = module.exports; -})(); -goog.provide('ol.ext.pixelworks'); -/** @typedef {function(*)} */ -ol.ext.pixelworks; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; /** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} + * @define {boolean} Whether to force non-dom html unescaping. */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixelworks = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ -var Processor = _dereq_('./processor'); - -exports.Processor = Processor; +goog.define('goog.string.FORCE_NON_DOM_HTML_UNESCAPING', false); -},{"./processor":2}],2:[function(_dereq_,module,exports){ -/* eslint-disable dot-notation */ /** - * Create a function for running operations. - * @param {function(Array, Object):*} operation The operation. - * @return {function(Object):ArrayBuffer} A function that takes an object with - * buffers, meta, imageOps, width, and height properties and returns an array - * buffer. + * Common Unicode string characters. + * @enum {string} */ -function createMinion(operation) { - return function(data) { - // bracket notation for minification support - var buffers = data['buffers']; - var meta = data['meta']; - var imageOps = data['imageOps']; - var width = data['width']; - var height = data['height']; - - var numBuffers = buffers.length; - var numBytes = buffers[0].byteLength; - var output, b; +goog.string.Unicode = { + NBSP: '\xa0' +}; - if (imageOps) { - var images = new Array(numBuffers); - for (b = 0; b < numBuffers; ++b) { - images[b] = new ImageData( - new Uint8ClampedArray(buffers[b]), width, height); - } - output = operation(images, meta).data; - } else { - output = new Uint8ClampedArray(numBytes); - var arrays = new Array(numBuffers); - var pixels = new Array(numBuffers); - for (b = 0; b < numBuffers; ++b) { - arrays[b] = new Uint8ClampedArray(buffers[b]); - pixels[b] = [0, 0, 0, 0]; - } - for (var i = 0; i < numBytes; i += 4) { - for (var j = 0; j < numBuffers; ++j) { - var array = arrays[j]; - pixels[j][0] = array[i]; - pixels[j][1] = array[i + 1]; - pixels[j][2] = array[i + 2]; - pixels[j][3] = array[i + 3]; - } - var pixel = operation(pixels, meta); - output[i] = pixel[0]; - output[i + 1] = pixel[1]; - output[i + 2] = pixel[2]; - output[i + 3] = pixel[3]; - } - } - return output.buffer; - }; -} /** - * Create a worker for running operations. - * @param {Object} config Configuration. - * @param {function(Object)} onMessage Called with a message event. - * @return {Worker} The worker. + * Fast prefix-checker. + * @param {string} str The string to check. + * @param {string} prefix A string to look for at the start of {@code str}. + * @return {boolean} True if {@code str} begins with {@code prefix}. */ -function createWorker(config, onMessage) { - var lib = Object.keys(config.lib || {}).map(function(name) { - return 'var ' + name + ' = ' + config.lib[name].toString() + ';'; - }); - - var lines = lib.concat([ - 'var __minion__ = (' + createMinion.toString() + ')(', - config.operation.toString(), - ');', - 'self.addEventListener("message", function(__event__) {', - 'var buffer = __minion__(__event__.data);', - 'self.postMessage({buffer: buffer, meta: __event__.data.meta}, [buffer]);', - '});' - ]); +goog.string.startsWith = function(str, prefix) { + return str.lastIndexOf(prefix, 0) == 0; +}; - var blob = new Blob(lines, {type: 'text/javascript'}); - var source = URL.createObjectURL(blob); - var worker = new Worker(source); - worker.addEventListener('message', onMessage); - return worker; -} /** - * Create a faux worker for running operations. - * @param {Object} config Configuration. - * @param {function(Object)} onMessage Called with a message event. - * @return {Object} The faux worker. + * Fast suffix-checker. + * @param {string} str The string to check. + * @param {string} suffix A string to look for at the end of {@code str}. + * @return {boolean} True if {@code str} ends with {@code suffix}. */ -function createFauxWorker(config, onMessage) { - var minion = createMinion(config.operation); - return { - postMessage: function(data) { - setTimeout(function() { - onMessage({data: {buffer: minion(data), meta: data.meta}}); - }, 0); - } - }; -} +goog.string.endsWith = function(str, suffix) { + var l = str.length - suffix.length; + return l >= 0 && str.indexOf(suffix, l) == l; +}; + /** - * A processor runs pixel or image operations in workers. - * @param {Object} config Configuration. + * Case-insensitive prefix-checker. + * @param {string} str The string to check. + * @param {string} prefix A string to look for at the end of {@code str}. + * @return {boolean} True if {@code str} begins with {@code prefix} (ignoring + * case). */ -function Processor(config) { - this._imageOps = !!config.imageOps; - var threads; - if (config.threads === 0) { - threads = 0; - } else if (this._imageOps) { - threads = 1; - } else { - threads = config.threads || 1; - } - var workers = []; - if (threads) { - for (var i = 0; i < threads; ++i) { - workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i)); - } - } else { - workers[0] = createFauxWorker(config, this._onWorkerMessage.bind(this, 0)); - } - this._workers = workers; - this._queue = []; - this._maxQueueLength = config.queue || Infinity; - this._running = 0; - this._dataLookup = {}; - this._job = null; -} +goog.string.caseInsensitiveStartsWith = function(str, prefix) { + return goog.string.caseInsensitiveCompare( + prefix, str.substr(0, prefix.length)) == 0; +}; + /** - * Run operation on input data. - * @param {Array.<Array|ImageData>} inputs Array of pixels or image data - * (depending on the operation type). - * @param {Object} meta A user data object. This is passed to all operations - * and must be serializable. - * @param {function(Error, ImageData, Object)} callback Called when work - * completes. The first argument is any error. The second is the ImageData - * generated by operations. The third is the user data object. + * Case-insensitive suffix-checker. + * @param {string} str The string to check. + * @param {string} suffix A string to look for at the end of {@code str}. + * @return {boolean} True if {@code str} ends with {@code suffix} (ignoring + * case). */ -Processor.prototype.process = function(inputs, meta, callback) { - this._enqueue({ - inputs: inputs, - meta: meta, - callback: callback - }); - this._dispatch(); +goog.string.caseInsensitiveEndsWith = function(str, suffix) { + return goog.string.caseInsensitiveCompare( + suffix, str.substr(str.length - suffix.length, suffix.length)) == 0; }; + /** - * Stop responding to any completed work and destroy the processor. + * Case-insensitive equality checker. + * @param {string} str1 First string to check. + * @param {string} str2 Second string to check. + * @return {boolean} True if {@code str1} and {@code str2} are the same string, + * ignoring case. */ -Processor.prototype.destroy = function() { - for (var key in this) { - this[key] = null; - } - this._destroyed = true; +goog.string.caseInsensitiveEquals = function(str1, str2) { + return str1.toLowerCase() == str2.toLowerCase(); }; + /** - * Add a job to the queue. - * @param {Object} job The job. + * Does simple python-style string substitution. + * subs("foo%s hot%s", "bar", "dog") becomes "foobar hotdog". + * @param {string} str The string containing the pattern. + * @param {...*} var_args The items to substitute into the pattern. + * @return {string} A copy of {@code str} in which each occurrence of + * {@code %s} has been replaced an argument from {@code var_args}. */ -Processor.prototype._enqueue = function(job) { - this._queue.push(job); - while (this._queue.length > this._maxQueueLength) { - this._queue.shift().callback(null, null); +goog.string.subs = function(str, var_args) { + var splitParts = str.split('%s'); + var returnString = ''; + + var subsArguments = Array.prototype.slice.call(arguments, 1); + while (subsArguments.length && + // Replace up to the last split part. We are inserting in the + // positions between split parts. + splitParts.length > 1) { + returnString += splitParts.shift() + subsArguments.shift(); } + + return returnString + splitParts.join('%s'); // Join unused '%s' }; + /** - * Dispatch a job. - */ -Processor.prototype._dispatch = function() { - if (this._running === 0 && this._queue.length > 0) { - var job = this._job = this._queue.shift(); - var width = job.inputs[0].width; - var height = job.inputs[0].height; - var buffers = job.inputs.map(function(input) { - return input.data.buffer; - }); - var threads = this._workers.length; - this._running = threads; - if (threads === 1) { - this._workers[0].postMessage({ - 'buffers': buffers, - 'meta': job.meta, - 'imageOps': this._imageOps, - 'width': width, - 'height': height - }, buffers); - } else { - var length = job.inputs[0].data.length; - var segmentLength = 4 * Math.ceil(length / 4 / threads); - for (var i = 0; i < threads; ++i) { - var offset = i * segmentLength; - var slices = []; - for (var j = 0, jj = buffers.length; j < jj; ++j) { - slices.push(buffers[i].slice(offset, offset + segmentLength)); - } - this._workers[i].postMessage({ - 'buffers': slices, - 'meta': job.meta, - 'imageOps': this._imageOps, - 'width': width, - 'height': height - }, slices); - } - } - } + * Converts multiple whitespace chars (spaces, non-breaking-spaces, new lines + * and tabs) to a single space, and strips leading and trailing whitespace. + * @param {string} str Input string. + * @return {string} A copy of {@code str} with collapsed whitespace. + */ +goog.string.collapseWhitespace = function(str) { + // Since IE doesn't include non-breaking-space (0xa0) in their \s character + // class (as required by section 7.2 of the ECMAScript spec), we explicitly + // include it in the regexp to enforce consistent cross-browser behavior. + return str.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, ''); }; + /** - * Handle messages from the worker. - * @param {number} index The worker index. - * @param {Object} event The message event. + * Checks if a string is empty or contains only whitespaces. + * @param {string} str The string to check. + * @return {boolean} Whether {@code str} is empty or whitespace only. */ -Processor.prototype._onWorkerMessage = function(index, event) { - if (this._destroyed) { - return; - } - this._dataLookup[index] = event.data; - --this._running; - if (this._running === 0) { - this._resolveJob(); - } +goog.string.isEmptyOrWhitespace = function(str) { + // testing length == 0 first is actually slower in all browsers (about the + // same in Opera). + // Since IE doesn't include non-breaking-space (0xa0) in their \s character + // class (as required by section 7.2 of the ECMAScript spec), we explicitly + // include it in the regexp to enforce consistent cross-browser behavior. + return /^[\s\xa0]*$/.test(str); }; + /** - * Resolve a job. If there are no more worker threads, the processor callback - * will be called. + * Checks if a string is empty. + * @param {string} str The string to check. + * @return {boolean} Whether {@code str} is empty. */ -Processor.prototype._resolveJob = function() { - var job = this._job; - var threads = this._workers.length; - var data, meta; - if (threads === 1) { - data = new Uint8ClampedArray(this._dataLookup[0]['buffer']); - meta = this._dataLookup[0]['meta']; - } else { - var length = job.inputs[0].data.length; - data = new Uint8ClampedArray(length); - meta = new Array(length); - var segmentLength = 4 * Math.ceil(length / 4 / threads); - for (var i = 0; i < threads; ++i) { - var buffer = this._dataLookup[i]['buffer']; - var offset = i * segmentLength; - data.set(new Uint8ClampedArray(buffer), offset); - meta[i] = this._dataLookup[i]['meta']; - } - } - this._job = null; - this._dataLookup = {}; - job.callback(null, - new ImageData(data, job.inputs[0].width, job.inputs[0].height), meta); - this._dispatch(); +goog.string.isEmptyString = function(str) { + return str.length == 0; }; -module.exports = Processor; - -},{}]},{},[1])(1) -}); -ol.ext.pixelworks = module.exports; -})(); -goog.provide('ol.ext.rbush'); -/** @typedef {function(*)} */ -ol.ext.rbush; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; /** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} + * Checks if a string is empty or contains only whitespaces. + * + * TODO(user): Deprecate this when clients have been switched over to + * goog.string.isEmptyOrWhitespace. + * + * @param {string} str The string to check. + * @return {boolean} Whether {@code str} is empty or whitespace only. */ -/* - (c) 2015, Vladimir Agafonkin - RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles. - https://github.com/mourner/rbush -*/ +goog.string.isEmpty = goog.string.isEmptyOrWhitespace; -(function () { 'use strict'; -function rbush(maxEntries, format) { +/** + * Checks if a string is null, undefined, empty or contains only whitespaces. + * @param {*} str The string to check. + * @return {boolean} Whether {@code str} is null, undefined, empty, or + * whitespace only. + * @deprecated Use goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str)) + * instead. + */ +goog.string.isEmptyOrWhitespaceSafe = function(str) { + return goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str)); +}; - // jshint newcap: false, validthis: true - if (!(this instanceof rbush)) return new rbush(maxEntries, format); - // max entries in a node is 9 by default; min node fill is 40% for best performance - this._maxEntries = Math.max(4, maxEntries || 9); - this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); +/** + * Checks if a string is null, undefined, empty or contains only whitespaces. + * + * TODO(user): Deprecate this when clients have been switched over to + * goog.string.isEmptyOrWhitespaceSafe. + * + * @param {*} str The string to check. + * @return {boolean} Whether {@code str} is null, undefined, empty, or + * whitespace only. + */ +goog.string.isEmptySafe = goog.string.isEmptyOrWhitespaceSafe; - if (format) { - this._initFormat(format); - } - this.clear(); -} +/** + * Checks if a string is all breaking whitespace. + * @param {string} str The string to check. + * @return {boolean} Whether the string is all breaking whitespace. + */ +goog.string.isBreakingWhitespace = function(str) { + return !/[^\t\n\r ]/.test(str); +}; -rbush.prototype = { - all: function () { - return this._all(this.data, []); - }, +/** + * Checks if a string contains all letters. + * @param {string} str string to check. + * @return {boolean} True if {@code str} consists entirely of letters. + */ +goog.string.isAlpha = function(str) { + return !/[^a-zA-Z]/.test(str); +}; - search: function (bbox) { - var node = this.data, - result = [], - toBBox = this.toBBox; +/** + * Checks if a string contains only numbers. + * @param {*} str string to check. If not a string, it will be + * casted to one. + * @return {boolean} True if {@code str} is numeric. + */ +goog.string.isNumeric = function(str) { + return !/[^0-9]/.test(str); +}; - if (!intersects(bbox, node.bbox)) return result; - var nodesToSearch = [], - i, len, child, childBBox; +/** + * Checks if a string contains only numbers or letters. + * @param {string} str string to check. + * @return {boolean} True if {@code str} is alphanumeric. + */ +goog.string.isAlphaNumeric = function(str) { + return !/[^a-zA-Z0-9]/.test(str); +}; - while (node) { - for (i = 0, len = node.children.length; i < len; i++) { - child = node.children[i]; - childBBox = node.leaf ? toBBox(child) : child.bbox; +/** + * Checks if a character is a space character. + * @param {string} ch Character to check. + * @return {boolean} True if {@code ch} is a space. + */ +goog.string.isSpace = function(ch) { + return ch == ' '; +}; - if (intersects(bbox, childBBox)) { - if (node.leaf) result.push(child); - else if (contains(bbox, childBBox)) this._all(child, result); - else nodesToSearch.push(child); - } - } - node = nodesToSearch.pop(); - } - return result; - }, +/** + * Checks if a character is a valid unicode character. + * @param {string} ch Character to check. + * @return {boolean} True if {@code ch} is a valid unicode character. + */ +goog.string.isUnicodeChar = function(ch) { + return ch.length == 1 && ch >= ' ' && ch <= '~' || + ch >= '\u0080' && ch <= '\uFFFD'; +}; - collides: function (bbox) { - var node = this.data, - toBBox = this.toBBox; +/** + * Takes a string and replaces newlines with a space. Multiple lines are + * replaced with a single space. + * @param {string} str The string from which to strip newlines. + * @return {string} A copy of {@code str} stripped of newlines. + */ +goog.string.stripNewlines = function(str) { + return str.replace(/(\r\n|\r|\n)+/g, ' '); +}; - if (!intersects(bbox, node.bbox)) return false; - var nodesToSearch = [], - i, len, child, childBBox; +/** + * Replaces Windows and Mac new lines with unix style: \r or \r\n with \n. + * @param {string} str The string to in which to canonicalize newlines. + * @return {string} {@code str} A copy of {@code} with canonicalized newlines. + */ +goog.string.canonicalizeNewlines = function(str) { + return str.replace(/(\r\n|\r|\n)/g, '\n'); +}; - while (node) { - for (i = 0, len = node.children.length; i < len; i++) { - child = node.children[i]; - childBBox = node.leaf ? toBBox(child) : child.bbox; +/** + * Normalizes whitespace in a string, replacing all whitespace chars with + * a space. + * @param {string} str The string in which to normalize whitespace. + * @return {string} A copy of {@code str} with all whitespace normalized. + */ +goog.string.normalizeWhitespace = function(str) { + return str.replace(/\xa0|\s/g, ' '); +}; - if (intersects(bbox, childBBox)) { - if (node.leaf || contains(bbox, childBBox)) return true; - nodesToSearch.push(child); - } - } - node = nodesToSearch.pop(); - } - return false; - }, +/** + * Normalizes spaces in a string, replacing all consecutive spaces and tabs + * with a single space. Replaces non-breaking space with a space. + * @param {string} str The string in which to normalize spaces. + * @return {string} A copy of {@code str} with all consecutive spaces and tabs + * replaced with a single space. + */ +goog.string.normalizeSpaces = function(str) { + return str.replace(/\xa0|[ \t]+/g, ' '); +}; - load: function (data) { - if (!(data && data.length)) return this; - if (data.length < this._minEntries) { - for (var i = 0, len = data.length; i < len; i++) { - this.insert(data[i]); - } - return this; - } +/** + * Removes the breaking spaces from the left and right of the string and + * collapses the sequences of breaking spaces in the middle into single spaces. + * The original and the result strings render the same way in HTML. + * @param {string} str A string in which to collapse spaces. + * @return {string} Copy of the string with normalized breaking spaces. + */ +goog.string.collapseBreakingSpaces = function(str) { + return str.replace(/[\t\r\n ]+/g, ' ').replace( + /^[\t\r\n ]+|[\t\r\n ]+$/g, ''); +}; - // recursively build the tree with the given data from stratch using OMT algorithm - var node = this._build(data.slice(), 0, data.length - 1, 0); - if (!this.data.children.length) { - // save as is if tree is empty - this.data = node; +/** + * Trims white spaces to the left and right of a string. + * @param {string} str The string to trim. + * @return {string} A trimmed copy of {@code str}. + */ +goog.string.trim = (goog.TRUSTED_SITE && String.prototype.trim) ? + function(str) { + return str.trim(); + } : + function(str) { + // Since IE doesn't include non-breaking-space (0xa0) in their \s + // character class (as required by section 7.2 of the ECMAScript spec), + // we explicitly include it in the regexp to enforce consistent + // cross-browser behavior. + return str.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); + }; - } else if (this.data.height === node.height) { - // split root if trees have the same height - this._splitRoot(this.data, node); - } else { - if (this.data.height < node.height) { - // swap trees if inserted one is bigger - var tmpNode = this.data; - this.data = node; - node = tmpNode; - } +/** + * Trims whitespaces at the left end of a string. + * @param {string} str The string to left trim. + * @return {string} A trimmed copy of {@code str}. + */ +goog.string.trimLeft = function(str) { + // Since IE doesn't include non-breaking-space (0xa0) in their \s character + // class (as required by section 7.2 of the ECMAScript spec), we explicitly + // include it in the regexp to enforce consistent cross-browser behavior. + return str.replace(/^[\s\xa0]+/, ''); +}; - // insert the small tree into the large tree at appropriate level - this._insert(node, this.data.height - node.height - 1, true); - } - return this; - }, +/** + * Trims whitespaces at the right end of a string. + * @param {string} str The string to right trim. + * @return {string} A trimmed copy of {@code str}. + */ +goog.string.trimRight = function(str) { + // Since IE doesn't include non-breaking-space (0xa0) in their \s character + // class (as required by section 7.2 of the ECMAScript spec), we explicitly + // include it in the regexp to enforce consistent cross-browser behavior. + return str.replace(/[\s\xa0]+$/, ''); +}; - insert: function (item) { - if (item) this._insert(item, this.data.height - 1); - return this; - }, - clear: function () { - this.data = { - children: [], - height: 1, - bbox: empty(), - leaf: true - }; - return this; - }, +/** + * A string comparator that ignores case. + * -1 = str1 less than str2 + * 0 = str1 equals str2 + * 1 = str1 greater than str2 + * + * @param {string} str1 The string to compare. + * @param {string} str2 The string to compare {@code str1} to. + * @return {number} The comparator result, as described above. + */ +goog.string.caseInsensitiveCompare = function(str1, str2) { + var test1 = String(str1).toLowerCase(); + var test2 = String(str2).toLowerCase(); - remove: function (item) { - if (!item) return this; + if (test1 < test2) { + return -1; + } else if (test1 == test2) { + return 0; + } else { + return 1; + } +}; - var node = this.data, - bbox = this.toBBox(item), - path = [], - indexes = [], - i, parent, index, goingUp; - // depth-first iterative tree traversal - while (node || path.length) { +/** + * Regular expression used for splitting a string into substrings of fractional + * numbers, integers, and non-numeric characters. + * @type {RegExp} + * @private + */ +goog.string.numerateCompareRegExp_ = /(\.\d+)|(\d+)|(\D+)/g; - if (!node) { // go up - node = path.pop(); - parent = path[path.length - 1]; - i = indexes.pop(); - goingUp = true; - } - if (node.leaf) { // check current node - index = node.children.indexOf(item); +/** + * String comparison function that handles numbers in a way humans might expect. + * Using this function, the string "File 2.jpg" sorts before "File 10.jpg". The + * comparison is mostly case-insensitive, though strings that are identical + * except for case are sorted with the upper-case strings before lower-case. + * + * This comparison function is significantly slower (about 500x) than either + * the default or the case-insensitive compare. It should not be used in + * time-critical code, but should be fast enough to sort several hundred short + * strings (like filenames) with a reasonable delay. + * + * @param {string} str1 The string to compare in a numerically sensitive way. + * @param {string} str2 The string to compare {@code str1} to. + * @return {number} less than 0 if str1 < str2, 0 if str1 == str2, greater than + * 0 if str1 > str2. + */ +goog.string.numerateCompare = function(str1, str2) { + if (str1 == str2) { + return 0; + } + if (!str1) { + return -1; + } + if (!str2) { + return 1; + } - if (index !== -1) { - // item found, remove the item and condense tree upwards - node.children.splice(index, 1); - path.push(node); - this._condense(path); - return this; - } - } + // Using match to split the entire string ahead of time turns out to be faster + // for most inputs than using RegExp.exec or iterating over each character. + var tokens1 = str1.toLowerCase().match(goog.string.numerateCompareRegExp_); + var tokens2 = str2.toLowerCase().match(goog.string.numerateCompareRegExp_); - if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down - path.push(node); - indexes.push(i); - i = 0; - parent = node; - node = node.children[0]; + var count = Math.min(tokens1.length, tokens2.length); - } else if (parent) { // go right - i++; - node = parent.children[i]; - goingUp = false; + for (var i = 0; i < count; i++) { + var a = tokens1[i]; + var b = tokens2[i]; - } else node = null; // nothing found - } + // Compare pairs of tokens, returning if one token sorts before the other. + if (a != b) { - return this; - }, + // Only if both tokens are integers is a special comparison required. + // Decimal numbers are sorted as strings (e.g., '.09' < '.1'). + var num1 = parseInt(a, 10); + if (!isNaN(num1)) { + var num2 = parseInt(b, 10); + if (!isNaN(num2) && num1 - num2) { + return num1 - num2; + } + } + return a < b ? -1 : 1; + } + } - toBBox: function (item) { return item; }, + // If one string is a substring of the other, the shorter string sorts first. + if (tokens1.length != tokens2.length) { + return tokens1.length - tokens2.length; + } - compareMinX: function (a, b) { return a[0] - b[0]; }, - compareMinY: function (a, b) { return a[1] - b[1]; }, + // The two strings must be equivalent except for case (perfect equality is + // tested at the head of the function.) Revert to default ASCII-betical string + // comparison to stablize the sort. + return str1 < str2 ? -1 : 1; +}; - toJSON: function () { return this.data; }, - fromJSON: function (data) { - this.data = data; - return this; - }, - - _all: function (node, result) { - var nodesToSearch = []; - while (node) { - if (node.leaf) result.push.apply(result, node.children); - else nodesToSearch.push.apply(nodesToSearch, node.children); - - node = nodesToSearch.pop(); - } - return result; - }, +/** + * URL-encodes a string + * @param {*} str The string to url-encode. + * @return {string} An encoded copy of {@code str} that is safe for urls. + * Note that '#', ':', and other characters used to delimit portions + * of URLs *will* be encoded. + */ +goog.string.urlEncode = function(str) { + return encodeURIComponent(String(str)); +}; - _build: function (items, left, right, height) { - var N = right - left + 1, - M = this._maxEntries, - node; +/** + * URL-decodes the string. We need to specially handle '+'s because + * the javascript library doesn't convert them to spaces. + * @param {string} str The string to url decode. + * @return {string} The decoded {@code str}. + */ +goog.string.urlDecode = function(str) { + return decodeURIComponent(str.replace(/\+/g, ' ')); +}; - if (N <= M) { - // reached leaf level; return leaf - node = { - children: items.slice(left, right + 1), - height: 1, - bbox: null, - leaf: true - }; - calcBBox(node, this.toBBox); - return node; - } - if (!height) { - // target height of the bulk-loaded tree - height = Math.ceil(Math.log(N) / Math.log(M)); +/** + * Converts \n to <br>s or <br />s. + * @param {string} str The string in which to convert newlines. + * @param {boolean=} opt_xml Whether to use XML compatible tags. + * @return {string} A copy of {@code str} with converted newlines. + */ +goog.string.newLineToBr = function(str, opt_xml) { + return str.replace(/(\r\n|\r|\n)/g, opt_xml ? '<br />' : '<br>'); +}; - // target number of root entries to maximize storage utilization - M = Math.ceil(N / Math.pow(M, height - 1)); - } - // TODO eliminate recursion? +/** + * Escapes double quote '"' and single quote '\'' characters in addition to + * '&', '<', and '>' so that a string can be included in an HTML tag attribute + * value within double or single quotes. + * + * It should be noted that > doesn't need to be escaped for the HTML or XML to + * be valid, but it has been decided to escape it for consistency with other + * implementations. + * + * With goog.string.DETECT_DOUBLE_ESCAPING, this function escapes also the + * lowercase letter "e". + * + * NOTE(user): + * HtmlEscape is often called during the generation of large blocks of HTML. + * Using statics for the regular expressions and strings is an optimization + * that can more than half the amount of time IE spends in this function for + * large apps, since strings and regexes both contribute to GC allocations. + * + * Testing for the presence of a character before escaping increases the number + * of function calls, but actually provides a speed increase for the average + * case -- since the average case often doesn't require the escaping of all 4 + * characters and indexOf() is much cheaper than replace(). + * The worst case does suffer slightly from the additional calls, therefore the + * opt_isLikelyToContainHtmlChars option has been included for situations + * where all 4 HTML entities are very likely to be present and need escaping. + * + * Some benchmarks (times tended to fluctuate +-0.05ms): + * FireFox IE6 + * (no chars / average (mix of cases) / all 4 chars) + * no checks 0.13 / 0.22 / 0.22 0.23 / 0.53 / 0.80 + * indexOf 0.08 / 0.17 / 0.26 0.22 / 0.54 / 0.84 + * indexOf + re test 0.07 / 0.17 / 0.28 0.19 / 0.50 / 0.85 + * + * An additional advantage of checking if replace actually needs to be called + * is a reduction in the number of object allocations, so as the size of the + * application grows the difference between the various methods would increase. + * + * @param {string} str string to be escaped. + * @param {boolean=} opt_isLikelyToContainHtmlChars Don't perform a check to see + * if the character needs replacing - use this option if you expect each of + * the characters to appear often. Leave false if you expect few html + * characters to occur in your strings, such as if you are escaping HTML. + * @return {string} An escaped copy of {@code str}. + */ +goog.string.htmlEscape = function(str, opt_isLikelyToContainHtmlChars) { - node = { - children: [], - height: height, - bbox: null - }; + if (opt_isLikelyToContainHtmlChars) { + str = str.replace(goog.string.AMP_RE_, '&') + .replace(goog.string.LT_RE_, '<') + .replace(goog.string.GT_RE_, '>') + .replace(goog.string.QUOT_RE_, '"') + .replace(goog.string.SINGLE_QUOTE_RE_, ''') + .replace(goog.string.NULL_RE_, '�'); + if (goog.string.DETECT_DOUBLE_ESCAPING) { + str = str.replace(goog.string.E_RE_, 'e'); + } + return str; - // split the items into M mostly square tiles + } else { + // quick test helps in the case when there are no chars to replace, in + // worst case this makes barely a difference to the time taken + if (!goog.string.ALL_RE_.test(str)) return str; - var N2 = Math.ceil(N / M), - N1 = N2 * Math.ceil(Math.sqrt(M)), - i, j, right2, right3; + // str.indexOf is faster than regex.test in this case + if (str.indexOf('&') != -1) { + str = str.replace(goog.string.AMP_RE_, '&'); + } + if (str.indexOf('<') != -1) { + str = str.replace(goog.string.LT_RE_, '<'); + } + if (str.indexOf('>') != -1) { + str = str.replace(goog.string.GT_RE_, '>'); + } + if (str.indexOf('"') != -1) { + str = str.replace(goog.string.QUOT_RE_, '"'); + } + if (str.indexOf('\'') != -1) { + str = str.replace(goog.string.SINGLE_QUOTE_RE_, '''); + } + if (str.indexOf('\x00') != -1) { + str = str.replace(goog.string.NULL_RE_, '�'); + } + if (goog.string.DETECT_DOUBLE_ESCAPING && str.indexOf('e') != -1) { + str = str.replace(goog.string.E_RE_, 'e'); + } + return str; + } +}; - multiSelect(items, left, right, N1, this.compareMinX); - for (i = left; i <= right; i += N1) { +/** + * Regular expression that matches an ampersand, for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.AMP_RE_ = /&/g; - right2 = Math.min(i + N1 - 1, right); - multiSelect(items, i, right2, N2, this.compareMinY); +/** + * Regular expression that matches a less than sign, for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.LT_RE_ = /</g; - for (j = i; j <= right2; j += N2) { - right3 = Math.min(j + N2 - 1, right2); +/** + * Regular expression that matches a greater than sign, for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.GT_RE_ = />/g; - // pack each entry recursively - node.children.push(this._build(items, j, right3, height - 1)); - } - } - calcBBox(node, this.toBBox); +/** + * Regular expression that matches a double quote, for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.QUOT_RE_ = /"/g; - return node; - }, - _chooseSubtree: function (bbox, node, level, path) { +/** + * Regular expression that matches a single quote, for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.SINGLE_QUOTE_RE_ = /'/g; - var i, len, child, targetNode, area, enlargement, minArea, minEnlargement; - while (true) { - path.push(node); +/** + * Regular expression that matches null character, for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.NULL_RE_ = /\x00/g; - if (node.leaf || path.length - 1 === level) break; - minArea = minEnlargement = Infinity; +/** + * Regular expression that matches a lowercase letter "e", for use in escaping. + * @const {!RegExp} + * @private + */ +goog.string.E_RE_ = /e/g; - for (i = 0, len = node.children.length; i < len; i++) { - child = node.children[i]; - area = bboxArea(child.bbox); - enlargement = enlargedArea(bbox, child.bbox) - area; - // choose entry with the least area enlargement - if (enlargement < minEnlargement) { - minEnlargement = enlargement; - minArea = area < minArea ? area : minArea; - targetNode = child; +/** + * Regular expression that matches any character that needs to be escaped. + * @const {!RegExp} + * @private + */ +goog.string.ALL_RE_ = (goog.string.DETECT_DOUBLE_ESCAPING ? + /[\x00&<>"'e]/ : + /[\x00&<>"']/); - } else if (enlargement === minEnlargement) { - // otherwise choose one with the smallest area - if (area < minArea) { - minArea = area; - targetNode = child; - } - } - } - node = targetNode; - } +/** + * Unescapes an HTML string. + * + * @param {string} str The string to unescape. + * @return {string} An unescaped copy of {@code str}. + */ +goog.string.unescapeEntities = function(str) { + if (goog.string.contains(str, '&')) { + // We are careful not to use a DOM if we do not have one or we explicitly + // requested non-DOM html unescaping. + if (!goog.string.FORCE_NON_DOM_HTML_UNESCAPING && + 'document' in goog.global) { + return goog.string.unescapeEntitiesUsingDom_(str); + } else { + // Fall back on pure XML entities + return goog.string.unescapePureXmlEntities_(str); + } + } + return str; +}; - return node; - }, - _insert: function (item, level, isNode) { +/** + * Unescapes a HTML string using the provided document. + * + * @param {string} str The string to unescape. + * @param {!Document} document A document to use in escaping the string. + * @return {string} An unescaped copy of {@code str}. + */ +goog.string.unescapeEntitiesWithDocument = function(str, document) { + if (goog.string.contains(str, '&')) { + return goog.string.unescapeEntitiesUsingDom_(str, document); + } + return str; +}; - var toBBox = this.toBBox, - bbox = isNode ? item.bbox : toBBox(item), - insertPath = []; - // find the best node for accommodating the item, saving all nodes along the path too - var node = this._chooseSubtree(bbox, this.data, level, insertPath); +/** + * Unescapes an HTML string using a DOM to resolve non-XML, non-numeric + * entities. This function is XSS-safe and whitespace-preserving. + * @private + * @param {string} str The string to unescape. + * @param {Document=} opt_document An optional document to use for creating + * elements. If this is not specified then the default window.document + * will be used. + * @return {string} The unescaped {@code str} string. + */ +goog.string.unescapeEntitiesUsingDom_ = function(str, opt_document) { + /** @type {!Object<string, string>} */ + var seen = {'&': '&', '<': '<', '>': '>', '"': '"'}; + var div; + if (opt_document) { + div = opt_document.createElement('div'); + } else { + div = goog.global.document.createElement('div'); + } + // Match as many valid entity characters as possible. If the actual entity + // happens to be shorter, it will still work as innerHTML will return the + // trailing characters unchanged. Since the entity characters do not include + // open angle bracket, there is no chance of XSS from the innerHTML use. + // Since no whitespace is passed to innerHTML, whitespace is preserved. + return str.replace(goog.string.HTML_ENTITY_PATTERN_, function(s, entity) { + // Check for cached entity. + var value = seen[s]; + if (value) { + return value; + } + // Check for numeric entity. + if (entity.charAt(0) == '#') { + // Prefix with 0 so that hex entities (e.g. ) parse as hex numbers. + var n = Number('0' + entity.substr(1)); + if (!isNaN(n)) { + value = String.fromCharCode(n); + } + } + // Fall back to innerHTML otherwise. + if (!value) { + // Append a non-entity character to avoid a bug in Webkit that parses + // an invalid entity at the end of innerHTML text as the empty string. + div.innerHTML = s + ' '; + // Then remove the trailing character from the result. + value = div.firstChild.nodeValue.slice(0, -1); + } + // Cache and return. + return seen[s] = value; + }); +}; - // put the item into the node - node.children.push(item); - extend(node.bbox, bbox); - // split on node overflow; propagate upwards if necessary - while (level >= 0) { - if (insertPath[level].children.length > this._maxEntries) { - this._split(insertPath, level); - level--; - } else break; +/** + * Unescapes XML entities. + * @private + * @param {string} str The string to unescape. + * @return {string} An unescaped copy of {@code str}. + */ +goog.string.unescapePureXmlEntities_ = function(str) { + return str.replace(/&([^;]+);/g, function(s, entity) { + switch (entity) { + case 'amp': + return '&'; + case 'lt': + return '<'; + case 'gt': + return '>'; + case 'quot': + return '"'; + default: + if (entity.charAt(0) == '#') { + // Prefix with 0 so that hex entities (e.g. ) parse as hex. + var n = Number('0' + entity.substr(1)); + if (!isNaN(n)) { + return String.fromCharCode(n); + } } + // For invalid entities we just return the entity + return s; + } + }); +}; - // adjust bboxes along the insertion path - this._adjustParentBBoxes(bbox, insertPath, level); - }, - - // split overflowed node into two - _split: function (insertPath, level) { - - var node = insertPath[level], - M = node.children.length, - m = this._minEntries; - this._chooseSplitAxis(node, m, M); +/** + * Regular expression that matches an HTML entity. + * See also HTML5: Tokenization / Tokenizing character references. + * @private + * @type {!RegExp} + */ +goog.string.HTML_ENTITY_PATTERN_ = /&([^;\s<&]+);?/g; - var splitIndex = this._chooseSplitIndex(node, m, M); - var newNode = { - children: node.children.splice(splitIndex, node.children.length - splitIndex), - height: node.height - }; +/** + * Do escaping of whitespace to preserve spatial formatting. We use character + * entity #160 to make it safer for xml. + * @param {string} str The string in which to escape whitespace. + * @param {boolean=} opt_xml Whether to use XML compatible tags. + * @return {string} An escaped copy of {@code str}. + */ +goog.string.whitespaceEscape = function(str, opt_xml) { + // This doesn't use goog.string.preserveSpaces for backwards compatibility. + return goog.string.newLineToBr(str.replace(/ /g, '  '), opt_xml); +}; - if (node.leaf) newNode.leaf = true; - calcBBox(node, this.toBBox); - calcBBox(newNode, this.toBBox); +/** + * Preserve spaces that would be otherwise collapsed in HTML by replacing them + * with non-breaking space Unicode characters. + * @param {string} str The string in which to preserve whitespace. + * @return {string} A copy of {@code str} with preserved whitespace. + */ +goog.string.preserveSpaces = function(str) { + return str.replace(/(^|[\n ]) /g, '$1' + goog.string.Unicode.NBSP); +}; - if (level) insertPath[level - 1].children.push(newNode); - else this._splitRoot(node, newNode); - }, - _splitRoot: function (node, newNode) { - // split root node - this.data = { - children: [node, newNode], - height: node.height + 1 - }; - calcBBox(this.data, this.toBBox); - }, +/** + * Strip quote characters around a string. The second argument is a string of + * characters to treat as quotes. This can be a single character or a string of + * multiple character and in that case each of those are treated as possible + * quote characters. For example: + * + * <pre> + * goog.string.stripQuotes('"abc"', '"`') --> 'abc' + * goog.string.stripQuotes('`abc`', '"`') --> 'abc' + * </pre> + * + * @param {string} str The string to strip. + * @param {string} quoteChars The quote characters to strip. + * @return {string} A copy of {@code str} without the quotes. + */ +goog.string.stripQuotes = function(str, quoteChars) { + var length = quoteChars.length; + for (var i = 0; i < length; i++) { + var quoteChar = length == 1 ? quoteChars : quoteChars.charAt(i); + if (str.charAt(0) == quoteChar && str.charAt(str.length - 1) == quoteChar) { + return str.substring(1, str.length - 1); + } + } + return str; +}; - _chooseSplitIndex: function (node, m, M) { - var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index; +/** + * Truncates a string to a certain length and adds '...' if necessary. The + * length also accounts for the ellipsis, so a maximum length of 10 and a string + * 'Hello World!' produces 'Hello W...'. + * @param {string} str The string to truncate. + * @param {number} chars Max number of characters. + * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped + * characters from being cut off in the middle. + * @return {string} The truncated {@code str} string. + */ +goog.string.truncate = function(str, chars, opt_protectEscapedCharacters) { + if (opt_protectEscapedCharacters) { + str = goog.string.unescapeEntities(str); + } - minOverlap = minArea = Infinity; + if (str.length > chars) { + str = str.substring(0, chars - 3) + '...'; + } - for (i = m; i <= M - m; i++) { - bbox1 = distBBox(node, 0, i, this.toBBox); - bbox2 = distBBox(node, i, M, this.toBBox); + if (opt_protectEscapedCharacters) { + str = goog.string.htmlEscape(str); + } - overlap = intersectionArea(bbox1, bbox2); - area = bboxArea(bbox1) + bboxArea(bbox2); + return str; +}; - // choose distribution with minimum overlap - if (overlap < minOverlap) { - minOverlap = overlap; - index = i; - minArea = area < minArea ? area : minArea; +/** + * Truncate a string in the middle, adding "..." if necessary, + * and favoring the beginning of the string. + * @param {string} str The string to truncate the middle of. + * @param {number} chars Max number of characters. + * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped + * characters from being cutoff in the middle. + * @param {number=} opt_trailingChars Optional number of trailing characters to + * leave at the end of the string, instead of truncating as close to the + * middle as possible. + * @return {string} A truncated copy of {@code str}. + */ +goog.string.truncateMiddle = function(str, chars, + opt_protectEscapedCharacters, opt_trailingChars) { + if (opt_protectEscapedCharacters) { + str = goog.string.unescapeEntities(str); + } - } else if (overlap === minOverlap) { - // otherwise choose distribution with minimum area - if (area < minArea) { - minArea = area; - index = i; - } - } - } - - return index; - }, - - // sorts node children by the best axis for split - _chooseSplitAxis: function (node, m, M) { - - var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX, - compareMinY = node.leaf ? this.compareMinY : compareNodeMinY, - xMargin = this._allDistMargin(node, m, M, compareMinX), - yMargin = this._allDistMargin(node, m, M, compareMinY); - - // if total distributions margin value is minimal for x, sort by minX, - // otherwise it's already sorted by minY - if (xMargin < yMargin) node.children.sort(compareMinX); - }, - - // total margin of all possible split distributions where each node is at least m full - _allDistMargin: function (node, m, M, compare) { - - node.children.sort(compare); + if (opt_trailingChars && str.length > chars) { + if (opt_trailingChars > chars) { + opt_trailingChars = chars; + } + var endPoint = str.length - opt_trailingChars; + var startPoint = chars - opt_trailingChars; + str = str.substring(0, startPoint) + '...' + str.substring(endPoint); + } else if (str.length > chars) { + // Favor the beginning of the string: + var half = Math.floor(chars / 2); + var endPos = str.length - half; + half += chars % 2; + str = str.substring(0, half) + '...' + str.substring(endPos); + } - var toBBox = this.toBBox, - leftBBox = distBBox(node, 0, m, toBBox), - rightBBox = distBBox(node, M - m, M, toBBox), - margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), - i, child; + if (opt_protectEscapedCharacters) { + str = goog.string.htmlEscape(str); + } - for (i = m; i < M - m; i++) { - child = node.children[i]; - extend(leftBBox, node.leaf ? toBBox(child) : child.bbox); - margin += bboxMargin(leftBBox); - } + return str; +}; - for (i = M - m - 1; i >= m; i--) { - child = node.children[i]; - extend(rightBBox, node.leaf ? toBBox(child) : child.bbox); - margin += bboxMargin(rightBBox); - } - return margin; - }, +/** + * Special chars that need to be escaped for goog.string.quote. + * @private {!Object<string, string>} + */ +goog.string.specialEscapeChars_ = { + '\0': '\\0', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\x0B': '\\x0B', // '\v' is not supported in JScript + '"': '\\"', + '\\': '\\\\' +}; - _adjustParentBBoxes: function (bbox, path, level) { - // adjust bboxes along the given tree path - for (var i = level; i >= 0; i--) { - extend(path[i].bbox, bbox); - } - }, - _condense: function (path) { - // go through the path, removing empty nodes and updating bboxes - for (var i = path.length - 1, siblings; i >= 0; i--) { - if (path[i].children.length === 0) { - if (i > 0) { - siblings = path[i - 1].children; - siblings.splice(siblings.indexOf(path[i]), 1); +/** + * Character mappings used internally for goog.string.escapeChar. + * @private {!Object<string, string>} + */ +goog.string.jsEscapeCache_ = { + '\'': '\\\'' +}; - } else this.clear(); - } else calcBBox(path[i], this.toBBox); - } - }, +/** + * Encloses a string in double quotes and escapes characters so that the + * string is a valid JS string. + * @param {string} s The string to quote. + * @return {string} A copy of {@code s} surrounded by double quotes. + */ +goog.string.quote = function(s) { + s = String(s); + if (s.quote) { + return s.quote(); + } else { + var sb = ['"']; + for (var i = 0; i < s.length; i++) { + var ch = s.charAt(i); + var cc = ch.charCodeAt(0); + sb[i + 1] = goog.string.specialEscapeChars_[ch] || + ((cc > 31 && cc < 127) ? ch : goog.string.escapeChar(ch)); + } + sb.push('"'); + return sb.join(''); + } +}; - _initFormat: function (format) { - // data format (minX, minY, maxX, maxY accessors) - // uses eval-type function compilation instead of just accepting a toBBox function - // because the algorithms are very sensitive to sorting functions performance, - // so they should be dead simple and without inner calls +/** + * Takes a string and returns the escaped string for that character. + * @param {string} str The string to escape. + * @return {string} An escaped string representing {@code str}. + */ +goog.string.escapeString = function(str) { + var sb = []; + for (var i = 0; i < str.length; i++) { + sb[i] = goog.string.escapeChar(str.charAt(i)); + } + return sb.join(''); +}; - // jshint evil: true - var compareArr = ['return a', ' - b', ';']; +/** + * Takes a character and returns the escaped string for that character. For + * example escapeChar(String.fromCharCode(15)) -> "\\x0E". + * @param {string} c The character to escape. + * @return {string} An escaped string representing {@code c}. + */ +goog.string.escapeChar = function(c) { + if (c in goog.string.jsEscapeCache_) { + return goog.string.jsEscapeCache_[c]; + } - this.compareMinX = new Function('a', 'b', compareArr.join(format[0])); - this.compareMinY = new Function('a', 'b', compareArr.join(format[1])); + if (c in goog.string.specialEscapeChars_) { + return goog.string.jsEscapeCache_[c] = goog.string.specialEscapeChars_[c]; + } - this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];'); + var rv = c; + var cc = c.charCodeAt(0); + if (cc > 31 && cc < 127) { + rv = c; + } else { + // tab is 9 but handled above + if (cc < 256) { + rv = '\\x'; + if (cc < 16 || cc > 256) { + rv += '0'; + } + } else { + rv = '\\u'; + if (cc < 4096) { // \u1000 + rv += '0'; + } } + rv += cc.toString(16).toUpperCase(); + } + + return goog.string.jsEscapeCache_[c] = rv; }; -// calculate node's bbox from bboxes of its children -function calcBBox(node, toBBox) { - node.bbox = distBBox(node, 0, node.children.length, toBBox); -} +/** + * Determines whether a string contains a substring. + * @param {string} str The string to search. + * @param {string} subString The substring to search for. + * @return {boolean} Whether {@code str} contains {@code subString}. + */ +goog.string.contains = function(str, subString) { + return str.indexOf(subString) != -1; +}; -// min bounding rectangle of node children from k to p-1 -function distBBox(node, k, p, toBBox) { - var bbox = empty(); - for (var i = k, child; i < p; i++) { - child = node.children[i]; - extend(bbox, node.leaf ? toBBox(child) : child.bbox); - } +/** + * Determines whether a string contains a substring, ignoring case. + * @param {string} str The string to search. + * @param {string} subString The substring to search for. + * @return {boolean} Whether {@code str} contains {@code subString}. + */ +goog.string.caseInsensitiveContains = function(str, subString) { + return goog.string.contains(str.toLowerCase(), subString.toLowerCase()); +}; - return bbox; -} -function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; } +/** + * Returns the non-overlapping occurrences of ss in s. + * If either s or ss evalutes to false, then returns zero. + * @param {string} s The string to look in. + * @param {string} ss The string to look for. + * @return {number} Number of occurrences of ss in s. + */ +goog.string.countOf = function(s, ss) { + return s && ss ? s.split(ss).length - 1 : 0; +}; -function extend(a, b) { - a[0] = Math.min(a[0], b[0]); - a[1] = Math.min(a[1], b[1]); - a[2] = Math.max(a[2], b[2]); - a[3] = Math.max(a[3], b[3]); - return a; -} -function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; } -function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; } +/** + * Removes a substring of a specified length at a specific + * index in a string. + * @param {string} s The base string from which to remove. + * @param {number} index The index at which to remove the substring. + * @param {number} stringLength The length of the substring to remove. + * @return {string} A copy of {@code s} with the substring removed or the full + * string if nothing is removed or the input is invalid. + */ +goog.string.removeAt = function(s, index, stringLength) { + var resultStr = s; + // If the index is greater or equal to 0 then remove substring + if (index >= 0 && index < s.length && stringLength > 0) { + resultStr = s.substr(0, index) + + s.substr(index + stringLength, s.length - index - stringLength); + } + return resultStr; +}; -function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); } -function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); } -function enlargedArea(a, b) { - return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) * - (Math.max(b[3], a[3]) - Math.min(b[1], a[1])); -} +/** + * Removes the first occurrence of a substring from a string. + * @param {string} s The base string from which to remove. + * @param {string} ss The string to remove. + * @return {string} A copy of {@code s} with {@code ss} removed or the full + * string if nothing is removed. + */ +goog.string.remove = function(s, ss) { + var re = new RegExp(goog.string.regExpEscape(ss), ''); + return s.replace(re, ''); +}; -function intersectionArea(a, b) { - var minX = Math.max(a[0], b[0]), - minY = Math.max(a[1], b[1]), - maxX = Math.min(a[2], b[2]), - maxY = Math.min(a[3], b[3]); - return Math.max(0, maxX - minX) * - Math.max(0, maxY - minY); -} +/** + * Removes all occurrences of a substring from a string. + * @param {string} s The base string from which to remove. + * @param {string} ss The string to remove. + * @return {string} A copy of {@code s} with {@code ss} removed or the full + * string if nothing is removed. + */ +goog.string.removeAll = function(s, ss) { + var re = new RegExp(goog.string.regExpEscape(ss), 'g'); + return s.replace(re, ''); +}; -function contains(a, b) { - return a[0] <= b[0] && - a[1] <= b[1] && - b[2] <= a[2] && - b[3] <= a[3]; -} -function intersects(a, b) { - return b[0] <= a[2] && - b[1] <= a[3] && - b[2] >= a[0] && - b[3] >= a[1]; -} +/** + * Escapes characters in the string that are not safe to use in a RegExp. + * @param {*} s The string to escape. If not a string, it will be casted + * to one. + * @return {string} A RegExp safe, escaped copy of {@code s}. + */ +goog.string.regExpEscape = function(s) { + return String(s).replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1'). + replace(/\x08/g, '\\x08'); +}; -// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; -// combines selection algorithm with binary divide & conquer approach -function multiSelect(arr, left, right, n, compare) { - var stack = [left, right], - mid; +/** + * Repeats a string n times. + * @param {string} string The string to repeat. + * @param {number} length The number of times to repeat. + * @return {string} A string containing {@code length} repetitions of + * {@code string}. + */ +goog.string.repeat = (String.prototype.repeat) ? + function(string, length) { + // The native method is over 100 times faster than the alternative. + return string.repeat(length); + } : + function(string, length) { + return new Array(length + 1).join(string); + }; - while (stack.length) { - right = stack.pop(); - left = stack.pop(); - if (right - left <= n) continue; +/** + * Pads number to given length and optionally rounds it to a given precision. + * For example: + * <pre>padNumber(1.25, 2, 3) -> '01.250' + * padNumber(1.25, 2) -> '01.25' + * padNumber(1.25, 2, 1) -> '01.3' + * padNumber(1.25, 0) -> '1.25'</pre> + * + * @param {number} num The number to pad. + * @param {number} length The desired length. + * @param {number=} opt_precision The desired precision. + * @return {string} {@code num} as a string with the given options. + */ +goog.string.padNumber = function(num, length, opt_precision) { + var s = goog.isDef(opt_precision) ? num.toFixed(opt_precision) : String(num); + var index = s.indexOf('.'); + if (index == -1) { + index = s.length; + } + return goog.string.repeat('0', Math.max(0, length - index)) + s; +}; - mid = left + Math.ceil((right - left) / n / 2) * n; - select(arr, left, right, mid, compare); - stack.push(left, mid, mid, right); - } -} +/** + * Returns a string representation of the given object, with + * null and undefined being returned as the empty string. + * + * @param {*} obj The object to convert. + * @return {string} A string representation of the {@code obj}. + */ +goog.string.makeSafe = function(obj) { + return obj == null ? '' : String(obj); +}; -// Floyd-Rivest selection algorithm: -// sort an array between left and right (inclusive) so that the smallest k elements come first (unordered) -function select(arr, left, right, k, compare) { - var n, i, z, s, sd, newLeft, newRight, t, j; - while (right > left) { - if (right - left > 600) { - n = right - left + 1; - i = k - left + 1; - z = Math.log(n); - s = 0.5 * Math.exp(2 * z / 3); - sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1); - newLeft = Math.max(left, Math.floor(k - i * s / n + sd)); - newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd)); - select(arr, newLeft, newRight, k, compare); - } +/** + * Concatenates string expressions. This is useful + * since some browsers are very inefficient when it comes to using plus to + * concat strings. Be careful when using null and undefined here since + * these will not be included in the result. If you need to represent these + * be sure to cast the argument to a String first. + * For example: + * <pre>buildString('a', 'b', 'c', 'd') -> 'abcd' + * buildString(null, undefined) -> '' + * </pre> + * @param {...*} var_args A list of strings to concatenate. If not a string, + * it will be casted to one. + * @return {string} The concatenation of {@code var_args}. + */ +goog.string.buildString = function(var_args) { + return Array.prototype.join.call(arguments, ''); +}; - t = arr[k]; - i = left; - j = right; - swap(arr, left, k); - if (compare(arr[right], t) > 0) swap(arr, left, right); +/** + * Returns a string with at least 64-bits of randomness. + * + * Doesn't trust Javascript's random function entirely. Uses a combination of + * random and current timestamp, and then encodes the string in base-36 to + * make it shorter. + * + * @return {string} A random string, e.g. sn1s7vb4gcic. + */ +goog.string.getRandomString = function() { + var x = 2147483648; + return Math.floor(Math.random() * x).toString(36) + + Math.abs(Math.floor(Math.random() * x) ^ goog.now()).toString(36); +}; - while (i < j) { - swap(arr, i, j); - i++; - j--; - while (compare(arr[i], t) < 0) i++; - while (compare(arr[j], t) > 0) j--; - } - if (compare(arr[left], t) === 0) swap(arr, left, j); - else { - j++; - swap(arr, j, right); - } +/** + * Compares two version numbers. + * + * @param {string|number} version1 Version of first item. + * @param {string|number} version2 Version of second item. + * + * @return {number} 1 if {@code version1} is higher. + * 0 if arguments are equal. + * -1 if {@code version2} is higher. + */ +goog.string.compareVersions = function(version1, version2) { + var order = 0; + // Trim leading and trailing whitespace and split the versions into + // subversions. + var v1Subs = goog.string.trim(String(version1)).split('.'); + var v2Subs = goog.string.trim(String(version2)).split('.'); + var subCount = Math.max(v1Subs.length, v2Subs.length); - if (j <= k) left = j + 1; - if (k <= j) right = j - 1; - } -} + // Iterate over the subversions, as long as they appear to be equivalent. + for (var subIdx = 0; order == 0 && subIdx < subCount; subIdx++) { + var v1Sub = v1Subs[subIdx] || ''; + var v2Sub = v2Subs[subIdx] || ''; -function swap(arr, i, j) { - var tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; -} + // Split the subversions into pairs of numbers and qualifiers (like 'b'). + // Two different RegExp objects are needed because they are both using + // the 'g' flag. + var v1CompParser = new RegExp('(\\d*)(\\D*)', 'g'); + var v2CompParser = new RegExp('(\\d*)(\\D*)', 'g'); + do { + var v1Comp = v1CompParser.exec(v1Sub) || ['', '', '']; + var v2Comp = v2CompParser.exec(v2Sub) || ['', '', '']; + // Break if there are no more matches. + if (v1Comp[0].length == 0 && v2Comp[0].length == 0) { + break; + } + // Parse the numeric part of the subversion. A missing number is + // equivalent to 0. + var v1CompNum = v1Comp[1].length == 0 ? 0 : parseInt(v1Comp[1], 10); + var v2CompNum = v2Comp[1].length == 0 ? 0 : parseInt(v2Comp[1], 10); -// export as AMD/CommonJS module or global variable -if (typeof define === 'function' && define.amd) define('rbush', function() { return rbush; }); -else if (typeof module !== 'undefined') module.exports = rbush; -else if (typeof self !== 'undefined') self.rbush = rbush; -else window.rbush = rbush; + // Compare the subversion components. The number has the highest + // precedence. Next, if the numbers are equal, a subversion without any + // qualifier is always higher than a subversion with any qualifier. Next, + // the qualifiers are compared as strings. + order = goog.string.compareElements_(v1CompNum, v2CompNum) || + goog.string.compareElements_(v1Comp[2].length == 0, + v2Comp[2].length == 0) || + goog.string.compareElements_(v1Comp[2], v2Comp[2]); + // Stop as soon as an inequality is discovered. + } while (order == 0); + } -})(); + return order; +}; -ol.ext.rbush = module.exports; -})(); -goog.provide('ol.ext.vectortile'); -/** @typedef {function(*)} */ -ol.ext.vectortile; -(function() { -var exports = {}; -var module = {exports: exports}; -var define; /** - * @fileoverview - * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} + * Compares elements of a version number. + * + * @param {string|number|boolean} left An element from a version number. + * @param {string|number|boolean} right An element from a version number. + * + * @return {number} 1 if {@code left} is higher. + * 0 if arguments are equal. + * -1 if {@code right} is higher. + * @private */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vectortile = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ -module.exports.VectorTile = _dereq_('./lib/vectortile.js'); -module.exports.VectorTileFeature = _dereq_('./lib/vectortilefeature.js'); -module.exports.VectorTileLayer = _dereq_('./lib/vectortilelayer.js'); - -},{"./lib/vectortile.js":2,"./lib/vectortilefeature.js":3,"./lib/vectortilelayer.js":4}],2:[function(_dereq_,module,exports){ -'use strict'; - -var VectorTileLayer = _dereq_('./vectortilelayer'); +goog.string.compareElements_ = function(left, right) { + if (left < right) { + return -1; + } else if (left > right) { + return 1; + } + return 0; +}; -module.exports = VectorTile; -function VectorTile(pbf, end) { - this.layers = pbf.readFields(readTile, {}, end); -} +/** + * String hash function similar to java.lang.String.hashCode(). + * The hash code for a string is computed as + * s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1], + * where s[i] is the ith character of the string and n is the length of + * the string. We mod the result to make it between 0 (inclusive) and 2^32 + * (exclusive). + * @param {string} str A string. + * @return {number} Hash value for {@code str}, between 0 (inclusive) and 2^32 + * (exclusive). The empty string returns 0. + */ +goog.string.hashCode = function(str) { + var result = 0; + for (var i = 0; i < str.length; ++i) { + // Normalize to 4 byte range, 0 ... 2^32. + result = (31 * result + str.charCodeAt(i)) >>> 0; + } + return result; +}; -function readTile(tag, layers, pbf) { - if (tag === 3) { - var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); - if (layer.length) layers[layer.name] = layer; - } -} +/** + * The most recent unique ID. |0 is equivalent to Math.floor in this case. + * @type {number} + * @private + */ +goog.string.uniqueStringCounter_ = Math.random() * 0x80000000 | 0; -},{"./vectortilelayer":4}],3:[function(_dereq_,module,exports){ -'use strict'; -var Point = _dereq_('point-geometry'); +/** + * Generates and returns a string which is unique in the current document. + * This is useful, for example, to create unique IDs for DOM elements. + * @return {string} A unique id. + */ +goog.string.createUniqueString = function() { + return 'goog_' + goog.string.uniqueStringCounter_++; +}; -module.exports = VectorTileFeature; -function VectorTileFeature(pbf, end, extent, keys, values) { - // Public - this.properties = {}; - this.extent = extent; - this.type = 0; +/** + * Converts the supplied string to a number, which may be Infinity or NaN. + * This function strips whitespace: (toNumber(' 123') === 123) + * This function accepts scientific notation: (toNumber('1e1') === 10) + * + * This is better than Javascript's built-in conversions because, sadly: + * (Number(' ') === 0) and (parseFloat('123a') === 123) + * + * @param {string} str The string to convert. + * @return {number} The number the supplied string represents, or NaN. + */ +goog.string.toNumber = function(str) { + var num = Number(str); + if (num == 0 && goog.string.isEmptyOrWhitespace(str)) { + return NaN; + } + return num; +}; - // Private - this._pbf = pbf; - this._geometry = -1; - this._keys = keys; - this._values = values; - pbf.readFields(readFeature, this, end); -} +/** + * Returns whether the given string is lower camel case (e.g. "isFooBar"). + * + * Note that this assumes the string is entirely letters. + * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms + * + * @param {string} str String to test. + * @return {boolean} Whether the string is lower camel case. + */ +goog.string.isLowerCamelCase = function(str) { + return /^[a-z]+([A-Z][a-z]*)*$/.test(str); +}; -function readFeature(tag, feature, pbf) { - if (tag == 1) feature._id = pbf.readVarint(); - else if (tag == 2) readTag(pbf, feature); - else if (tag == 3) feature.type = pbf.readVarint(); - else if (tag == 4) feature._geometry = pbf.pos; -} -function readTag(pbf, feature) { - var end = pbf.readVarint() + pbf.pos; +/** + * Returns whether the given string is upper camel case (e.g. "FooBarBaz"). + * + * Note that this assumes the string is entirely letters. + * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms + * + * @param {string} str String to test. + * @return {boolean} Whether the string is upper camel case. + */ +goog.string.isUpperCamelCase = function(str) { + return /^([A-Z][a-z]*)+$/.test(str); +}; - while (pbf.pos < end) { - var key = feature._keys[pbf.readVarint()], - value = feature._values[pbf.readVarint()]; - feature.properties[key] = value; - } -} -VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; +/** + * Converts a string from selector-case to camelCase (e.g. from + * "multi-part-string" to "multiPartString"), useful for converting + * CSS selectors and HTML dataset keys to their equivalent JS properties. + * @param {string} str The string in selector-case form. + * @return {string} The string in camelCase form. + */ +goog.string.toCamelCase = function(str) { + return String(str).replace(/\-([a-z])/g, function(all, match) { + return match.toUpperCase(); + }); +}; -VectorTileFeature.prototype.loadGeometry = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - lines = [], - line; +/** + * Converts a string from camelCase to selector-case (e.g. from + * "multiPartString" to "multi-part-string"), useful for converting JS + * style and dataset properties to equivalent CSS selectors and HTML keys. + * @param {string} str The string in camelCase form. + * @return {string} The string in selector-case form. + */ +goog.string.toSelectorCase = function(str) { + return String(str).replace(/([A-Z])/g, '-$1').toLowerCase(); +}; - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } - length--; +/** + * Converts a string into TitleCase. First character of the string is always + * capitalized in addition to the first letter of every subsequent word. + * Words are delimited by one or more whitespaces by default. Custom delimiters + * can optionally be specified to replace the default, which doesn't preserve + * whitespace delimiters and instead must be explicitly included if needed. + * + * Default delimiter => " ": + * goog.string.toTitleCase('oneTwoThree') => 'OneTwoThree' + * goog.string.toTitleCase('one two three') => 'One Two Three' + * goog.string.toTitleCase(' one two ') => ' One Two ' + * goog.string.toTitleCase('one_two_three') => 'One_two_three' + * goog.string.toTitleCase('one-two-three') => 'One-two-three' + * + * Custom delimiter => "_-.": + * goog.string.toTitleCase('oneTwoThree', '_-.') => 'OneTwoThree' + * goog.string.toTitleCase('one two three', '_-.') => 'One two three' + * goog.string.toTitleCase(' one two ', '_-.') => ' one two ' + * goog.string.toTitleCase('one_two_three', '_-.') => 'One_Two_Three' + * goog.string.toTitleCase('one-two-three', '_-.') => 'One-Two-Three' + * goog.string.toTitleCase('one...two...three', '_-.') => 'One...Two...Three' + * goog.string.toTitleCase('one. two. three', '_-.') => 'One. two. three' + * goog.string.toTitleCase('one-two.three', '_-.') => 'One-Two.Three' + * + * @param {string} str String value in camelCase form. + * @param {string=} opt_delimiters Custom delimiter character set used to + * distinguish words in the string value. Each character represents a + * single delimiter. When provided, default whitespace delimiter is + * overridden and must be explicitly included if needed. + * @return {string} String value in TitleCase form. + */ +goog.string.toTitleCase = function(str, opt_delimiters) { + var delimiters = goog.isString(opt_delimiters) ? + goog.string.regExpEscape(opt_delimiters) : '\\s'; - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); + // For IE8, we need to prevent using an empty character set. Otherwise, + // incorrect matching will occur. + delimiters = delimiters ? '|[' + delimiters + ']+' : ''; - if (cmd === 1) { // moveTo - if (line) lines.push(line); - line = []; - } + var regexp = new RegExp('(^' + delimiters + ')([a-z])', 'g'); + return str.replace(regexp, function(all, p1, p2) { + return p1 + p2.toUpperCase(); + }); +}; - line.push(new Point(x, y)); - } else if (cmd === 7) { +/** + * Capitalizes a string, i.e. converts the first letter to uppercase + * and all other letters to lowercase, e.g.: + * + * goog.string.capitalize('one') => 'One' + * goog.string.capitalize('ONE') => 'One' + * goog.string.capitalize('one two') => 'One two' + * + * Note that this function does not trim initial whitespace. + * + * @param {string} str String value to capitalize. + * @return {string} String value with first letter in uppercase. + */ +goog.string.capitalize = function(str) { + return String(str.charAt(0)).toUpperCase() + + String(str.substr(1)).toLowerCase(); +}; - // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 - if (line) { - line.push(line[0].clone()); // closePolygon - } - } else { - throw new Error('unknown command ' + cmd); - } - } +/** + * Parse a string in decimal or hexidecimal ('0xFFFF') form. + * + * To parse a particular radix, please use parseInt(string, radix) directly. See + * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt + * + * This is a wrapper for the built-in parseInt function that will only parse + * numbers as base 10 or base 16. Some JS implementations assume strings + * starting with "0" are intended to be octal. ES3 allowed but discouraged + * this behavior. ES5 forbids it. This function emulates the ES5 behavior. + * + * For more information, see Mozilla JS Reference: http://goo.gl/8RiFj + * + * @param {string|number|null|undefined} value The value to be parsed. + * @return {number} The number, parsed. If the string failed to parse, this + * will be NaN. + */ +goog.string.parseInt = function(value) { + // Force finite numbers to strings. + if (isFinite(value)) { + value = String(value); + } - if (line) lines.push(line); + if (goog.isString(value)) { + // If the string starts with '0x' or '-0x', parse as hex. + return /^\s*-?0x/i.test(value) ? + parseInt(value, 16) : parseInt(value, 10); + } - return lines; + return NaN; }; -VectorTileFeature.prototype.bbox = function() { - var pbf = this._pbf; - pbf.pos = this._geometry; - - var end = pbf.readVarint() + pbf.pos, - cmd = 1, - length = 0, - x = 0, - y = 0, - x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity; - while (pbf.pos < end) { - if (!length) { - var cmdLen = pbf.readVarint(); - cmd = cmdLen & 0x7; - length = cmdLen >> 3; - } +/** + * Splits a string on a separator a limited number of times. + * + * This implementation is more similar to Python or Java, where the limit + * parameter specifies the maximum number of splits rather than truncating + * the number of results. + * + * See http://docs.python.org/2/library/stdtypes.html#str.split + * See JavaDoc: http://goo.gl/F2AsY + * See Mozilla reference: http://goo.gl/dZdZs + * + * @param {string} str String to split. + * @param {string} separator The separator. + * @param {number} limit The limit to the number of splits. The resulting array + * will have a maximum length of limit+1. Negative numbers are the same + * as zero. + * @return {!Array<string>} The string, split. + */ - length--; +goog.string.splitLimit = function(str, separator, limit) { + var parts = str.split(separator); + var returnVal = []; - if (cmd === 1 || cmd === 2) { - x += pbf.readSVarint(); - y += pbf.readSVarint(); - if (x < x1) x1 = x; - if (x > x2) x2 = x; - if (y < y1) y1 = y; - if (y > y2) y2 = y; + // Only continue doing this while we haven't hit the limit and we have + // parts left. + while (limit > 0 && parts.length) { + returnVal.push(parts.shift()); + limit--; + } - } else if (cmd !== 7) { - throw new Error('unknown command ' + cmd); - } - } + // If there are remaining parts, append them to the end. + if (parts.length) { + returnVal.push(parts.join(separator)); + } - return [x1, y1, x2, y2]; + return returnVal; }; -VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { - var size = this.extent * Math.pow(2, z), - x0 = this.extent * x, - y0 = this.extent * y, - coords = this.loadGeometry(), - type = VectorTileFeature.types[this.type]; - for (var i = 0; i < coords.length; i++) { - var line = coords[i]; - for (var j = 0; j < line.length; j++) { - var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; - line[j] = [ - (p.x + x0) * 360 / size - 180, - 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 - ]; - } +/** + * Computes the Levenshtein edit distance between two strings. + * @param {string} a + * @param {string} b + * @return {number} The edit distance between the two strings. + */ +goog.string.editDistance = function(a, b) { + var v0 = []; + var v1 = []; + + if (a == b) { + return 0; + } + + if (!a.length || !b.length) { + return Math.max(a.length, b.length); + } + + for (var i = 0; i < b.length + 1; i++) { + v0[i] = i; + } + + for (var i = 0; i < a.length; i++) { + v1[0] = i + 1; + + for (var j = 0; j < b.length; j++) { + var cost = a[i] != b[j]; + // Cost for the substring is the minimum of adding one character, removing + // one character, or a swap. + v1[j + 1] = Math.min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost); } - if (type === 'Point' && coords.length === 1) { - coords = coords[0][0]; - } else if (type === 'Point') { - coords = coords[0]; - type = 'MultiPoint'; - } else if (type === 'LineString' && coords.length === 1) { - coords = coords[0]; - } else if (type === 'LineString') { - type = 'MultiLineString'; + for (var j = 0; j < v0.length; j++) { + v0[j] = v1[j]; } + } - return { - type: "Feature", - geometry: { - type: type, - coordinates: coords - }, - properties: this.properties - }; + return v1[b.length]; }; -},{"point-geometry":5}],4:[function(_dereq_,module,exports){ -'use strict'; +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -var VectorTileFeature = _dereq_('./vectortilefeature.js'); +/** + * @fileoverview Utilities to check the preconditions, postconditions and + * invariants runtime. + * + * Methods in this package should be given special treatment by the compiler + * for type-inference. For example, <code>goog.asserts.assert(foo)</code> + * will restrict <code>foo</code> to a truthy value. + * + * The compiler has an option to disable asserts. So code like: + * <code> + * var x = goog.asserts.assert(foo()); goog.asserts.assert(bar()); + * </code> + * will be transformed into: + * <code> + * var x = foo(); + * </code> + * The compiler will leave in foo() (because its return value is used), + * but it will remove bar() because it assumes it does not have side-effects. + * + * @author agrieve@google.com (Andrew Grieve) + */ -module.exports = VectorTileLayer; +goog.provide('goog.asserts'); +goog.provide('goog.asserts.AssertionError'); -function VectorTileLayer(pbf, end) { - // Public - this.version = 1; - this.name = null; - this.extent = 4096; - this.length = 0; +goog.require('goog.debug.Error'); +goog.require('goog.dom.NodeType'); +goog.require('goog.string'); - // Private - this._pbf = pbf; - this._keys = []; - this._values = []; - this._features = []; - pbf.readFields(readLayer, this, end); +/** + * @define {boolean} Whether to strip out asserts or to leave them in. + */ +goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG); - this.length = this._features.length; -} -function readLayer(tag, layer, pbf) { - if (tag === 15) layer.version = pbf.readVarint(); - else if (tag === 1) layer.name = pbf.readString(); - else if (tag === 5) layer.extent = pbf.readVarint(); - else if (tag === 2) layer._features.push(pbf.pos); - else if (tag === 3) layer._keys.push(pbf.readString()); - else if (tag === 4) layer._values.push(readValueMessage(pbf)); -} -function readValueMessage(pbf) { - var value = null, - end = pbf.readVarint() + pbf.pos; +/** + * Error object for failed assertions. + * @param {string} messagePattern The pattern that was used to form message. + * @param {!Array<*>} messageArgs The items to substitute into the pattern. + * @constructor + * @extends {goog.debug.Error} + * @final + */ +goog.asserts.AssertionError = function(messagePattern, messageArgs) { + messageArgs.unshift(messagePattern); + goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs)); + // Remove the messagePattern afterwards to avoid permanently modifying the + // passed in array. + messageArgs.shift(); - while (pbf.pos < end) { - var tag = pbf.readVarint() >> 3; + /** + * The message pattern used to format the error message. Error handlers can + * use this to uniquely identify the assertion. + * @type {string} + */ + this.messagePattern = messagePattern; +}; +goog.inherits(goog.asserts.AssertionError, goog.debug.Error); - value = tag === 1 ? pbf.readString() : - tag === 2 ? pbf.readFloat() : - tag === 3 ? pbf.readDouble() : - tag === 4 ? pbf.readVarint64() : - tag === 5 ? pbf.readVarint() : - tag === 6 ? pbf.readSVarint() : - tag === 7 ? pbf.readBoolean() : null; - } - return value; -} - -// return feature `i` from this layer as a `VectorTileFeature` -VectorTileLayer.prototype.feature = function(i) { - if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); - - this._pbf.pos = this._features[i]; - - var end = this._pbf.readVarint() + this._pbf.pos; - return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); -}; - -},{"./vectortilefeature.js":3}],5:[function(_dereq_,module,exports){ -'use strict'; - -module.exports = Point; - -function Point(x, y) { - this.x = x; - this.y = y; -} - -Point.prototype = { - clone: function() { return new Point(this.x, this.y); }, - - add: function(p) { return this.clone()._add(p); }, - sub: function(p) { return this.clone()._sub(p); }, - mult: function(k) { return this.clone()._mult(k); }, - div: function(k) { return this.clone()._div(k); }, - rotate: function(a) { return this.clone()._rotate(a); }, - matMult: function(m) { return this.clone()._matMult(m); }, - unit: function() { return this.clone()._unit(); }, - perp: function() { return this.clone()._perp(); }, - round: function() { return this.clone()._round(); }, - - mag: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, - - equals: function(p) { - return this.x === p.x && - this.y === p.y; - }, - - dist: function(p) { - return Math.sqrt(this.distSqr(p)); - }, - - distSqr: function(p) { - var dx = p.x - this.x, - dy = p.y - this.y; - return dx * dx + dy * dy; - }, - - angle: function() { - return Math.atan2(this.y, this.x); - }, - - angleTo: function(b) { - return Math.atan2(this.y - b.y, this.x - b.x); - }, - - angleWith: function(b) { - return this.angleWithSep(b.x, b.y); - }, - - // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ. - angleWithSep: function(x, y) { - return Math.atan2( - this.x * y - this.y * x, - this.x * x + this.y * y); - }, - - _matMult: function(m) { - var x = m[0] * this.x + m[1] * this.y, - y = m[2] * this.x + m[3] * this.y; - this.x = x; - this.y = y; - return this; - }, - - _add: function(p) { - this.x += p.x; - this.y += p.y; - return this; - }, - - _sub: function(p) { - this.x -= p.x; - this.y -= p.y; - return this; - }, - - _mult: function(k) { - this.x *= k; - this.y *= k; - return this; - }, - - _div: function(k) { - this.x /= k; - this.y /= k; - return this; - }, - - _unit: function() { - this._div(this.mag()); - return this; - }, - - _perp: function() { - var y = this.y; - this.y = this.x; - this.x = -y; - return this; - }, - - _rotate: function(angle) { - var cos = Math.cos(angle), - sin = Math.sin(angle), - x = cos * this.x - sin * this.y, - y = sin * this.x + cos * this.y; - this.x = x; - this.y = y; - return this; - }, - - _round: function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - } -}; - -// constructs Point from an array if necessary -Point.convert = function (a) { - if (a instanceof Point) { - return a; - } - if (Array.isArray(a)) { - return new Point(a[0], a[1]); - } - return a; -}; - -},{}]},{},[1])(1) -}); -ol.ext.vectortile = module.exports; -})(); - -goog.provide('ol'); +/** @override */ +goog.asserts.AssertionError.prototype.name = 'AssertionError'; /** - * Constants defined with the define tag cannot be changed in application - * code, but can be set at compile time. - * Some reduce the size of the build in advanced compile mode. + * The default error handler. + * @param {!goog.asserts.AssertionError} e The exception to be handled. */ +goog.asserts.DEFAULT_ERROR_HANDLER = function(e) { throw e; }; /** - * @define {boolean} Assume touch. Default is `false`. + * The handler responsible for throwing or logging assertion errors. + * @private {function(!goog.asserts.AssertionError)} */ -ol.ASSUME_TOUCH = false; +goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER; /** - * TODO: rename this to something having to do with tile grids - * see https://github.com/openlayers/ol3/issues/2076 - * @define {number} Default maximum zoom for default tile grids. + * Throws an exception with the given message and "Assertion failed" prefixed + * onto it. + * @param {string} defaultMessage The message to use if givenMessage is empty. + * @param {Array<*>} defaultArgs The substitution arguments for defaultMessage. + * @param {string|undefined} givenMessage Message supplied by the caller. + * @param {Array<*>} givenArgs The substitution arguments for givenMessage. + * @throws {goog.asserts.AssertionError} When the value is not a number. + * @private */ -ol.DEFAULT_MAX_ZOOM = 42; +goog.asserts.doAssertFailure_ = + function(defaultMessage, defaultArgs, givenMessage, givenArgs) { + var message = 'Assertion failed'; + if (givenMessage) { + message += ': ' + givenMessage; + var args = givenArgs; + } else if (defaultMessage) { + message += ': ' + defaultMessage; + args = defaultArgs; + } + // The '' + works around an Opera 10 bug in the unit tests. Without it, + // a stack trace is added to var message above. With this, a stack trace is + // not added until this line (it causes the extra garbage to be added after + // the assertion message instead of in the middle of it). + var e = new goog.asserts.AssertionError('' + message, args || []); + goog.asserts.errorHandler_(e); +}; /** - * @define {number} Default min zoom level for the map view. Default is `0`. + * Sets a custom error handler that can be used to customize the behavior of + * assertion failures, for example by turning all assertion failures into log + * messages. + * @param {function(!goog.asserts.AssertionError)} errorHandler */ -ol.DEFAULT_MIN_ZOOM = 0; +goog.asserts.setErrorHandler = function(errorHandler) { + if (goog.asserts.ENABLE_ASSERTS) { + goog.asserts.errorHandler_ = errorHandler; + } +}; /** - * @define {number} Default maximum allowed threshold (in pixels) for - * reprojection triangulation. Default is `0.5`. + * Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is + * true. + * @template T + * @param {T} condition The condition to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {T} The value of the condition. + * @throws {goog.asserts.AssertionError} When the condition evaluates to false. */ -ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD = 0.5; +goog.asserts.assert = function(condition, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !condition) { + goog.asserts.doAssertFailure_('', null, opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return condition; +}; /** - * @define {number} Default high water mark. + * Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case + * when we want to add a check in the unreachable area like switch-case + * statement: + * + * <pre> + * switch(type) { + * case FOO: doSomething(); break; + * case BAR: doSomethingElse(); break; + * default: goog.assert.fail('Unrecognized type: ' + type); + * // We have only 2 types - "default:" section is unreachable code. + * } + * </pre> + * + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @throws {goog.asserts.AssertionError} Failure. */ -ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK = 2048; +goog.asserts.fail = function(opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS) { + goog.asserts.errorHandler_(new goog.asserts.AssertionError( + 'Failure' + (opt_message ? ': ' + opt_message : ''), + Array.prototype.slice.call(arguments, 1))); + } +}; /** - * @define {number} Default tile size. + * Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {number} The value, guaranteed to be a number when asserts enabled. + * @throws {goog.asserts.AssertionError} When the value is not a number. */ -ol.DEFAULT_TILE_SIZE = 256; +goog.asserts.assertNumber = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !goog.isNumber(value)) { + goog.asserts.doAssertFailure_('Expected number but got %s: %s.', + [goog.typeOf(value), value], opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return /** @type {number} */ (value); +}; /** - * @define {string} Default WMS version. + * Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {string} The value, guaranteed to be a string when asserts enabled. + * @throws {goog.asserts.AssertionError} When the value is not a string. */ -ol.DEFAULT_WMS_VERSION = '1.3.0'; +goog.asserts.assertString = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !goog.isString(value)) { + goog.asserts.doAssertFailure_('Expected string but got %s: %s.', + [goog.typeOf(value), value], opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return /** @type {string} */ (value); +}; /** - * @define {number} Hysteresis pixels. + * Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {!Function} The value, guaranteed to be a function when asserts + * enabled. + * @throws {goog.asserts.AssertionError} When the value is not a function. */ -ol.DRAG_BOX_HYSTERESIS_PIXELS = 8; +goog.asserts.assertFunction = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !goog.isFunction(value)) { + goog.asserts.doAssertFailure_('Expected function but got %s: %s.', + [goog.typeOf(value), value], opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return /** @type {!Function} */ (value); +}; /** - * @define {boolean} Enable the Canvas renderer. Default is `true`. Setting - * this to false at compile time in advanced mode removes all code - * supporting the Canvas renderer from the build. + * Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {!Object} The value, guaranteed to be a non-null object. + * @throws {goog.asserts.AssertionError} When the value is not an object. */ -ol.ENABLE_CANVAS = true; +goog.asserts.assertObject = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) { + goog.asserts.doAssertFailure_('Expected object but got %s: %s.', + [goog.typeOf(value), value], + opt_message, Array.prototype.slice.call(arguments, 2)); + } + return /** @type {!Object} */ (value); +}; /** - * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is - * not available). Default is `true`. Setting this to false at compile time - * in advanced mode removes all code supporting the DOM renderer from the - * build. + * Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {!Array<?>} The value, guaranteed to be a non-null array. + * @throws {goog.asserts.AssertionError} When the value is not an array. */ -ol.ENABLE_DOM = true; +goog.asserts.assertArray = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !goog.isArray(value)) { + goog.asserts.doAssertFailure_('Expected array but got %s: %s.', + [goog.typeOf(value), value], opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return /** @type {!Array<?>} */ (value); +}; /** - * @define {boolean} Enable rendering of ol.layer.Image based layers. Default - * is `true`. Setting this to false at compile time in advanced mode removes - * all code supporting Image layers from the build. + * Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {boolean} The value, guaranteed to be a boolean when asserts are + * enabled. + * @throws {goog.asserts.AssertionError} When the value is not a boolean. */ -ol.ENABLE_IMAGE = true; +goog.asserts.assertBoolean = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !goog.isBoolean(value)) { + goog.asserts.doAssertFailure_('Expected boolean but got %s: %s.', + [goog.typeOf(value), value], opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return /** @type {boolean} */ (value); +}; /** - * @define {boolean} Enable Closure named colors (`goog.color.names`). - * Enabling these colors adds about 3KB uncompressed / 1.5KB compressed to - * the final build size. Default is `false`. This setting has no effect - * with Canvas renderer, which uses its own names, whether this is true or - * false. + * Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true. + * @param {*} value The value to check. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @return {!Element} The value, likely to be a DOM Element when asserts are + * enabled. + * @throws {goog.asserts.AssertionError} When the value is not an Element. */ -ol.ENABLE_NAMED_COLORS = false; +goog.asserts.assertElement = function(value, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && (!goog.isObject(value) || + value.nodeType != goog.dom.NodeType.ELEMENT)) { + goog.asserts.doAssertFailure_('Expected Element but got %s: %s.', + [goog.typeOf(value), value], opt_message, + Array.prototype.slice.call(arguments, 2)); + } + return /** @type {!Element} */ (value); +}; /** - * @define {boolean} Enable integration with the Proj4js library. Default is - * `true`. + * Checks if the value is an instance of the user-defined type if + * goog.asserts.ENABLE_ASSERTS is true. + * + * The compiler may tighten the type returned by this function. + * + * @param {*} value The value to check. + * @param {function(new: T, ...)} type A user-defined constructor. + * @param {string=} opt_message Error message in case of failure. + * @param {...*} var_args The items to substitute into the failure message. + * @throws {goog.asserts.AssertionError} When the value is not an instance of + * type. + * @return {T} + * @template T */ -ol.ENABLE_PROJ4JS = true; +goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) { + if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) { + goog.asserts.doAssertFailure_('Expected instanceof %s but got %s.', + [goog.asserts.getType_(type), goog.asserts.getType_(value)], + opt_message, Array.prototype.slice.call(arguments, 3)); + } + return value; +}; /** - * @define {boolean} Enable automatic reprojection of raster sources. Default is - * `true`. + * Checks that no enumerable keys are present in Object.prototype. Such keys + * would break most code that use {@code for (var ... in ...)} loops. */ -ol.ENABLE_RASTER_REPROJECTION = true; +goog.asserts.assertObjectPrototypeIsIntact = function() { + for (var key in Object.prototype) { + goog.asserts.fail(key + ' should not be enumerable in Object.prototype.'); + } +}; /** - * @define {boolean} Enable rendering of ol.layer.Tile based layers. Default is - * `true`. Setting this to false at compile time in advanced mode removes - * all code supporting Tile layers from the build. + * Returns the type of a value. If a constructor is passed, and a suitable + * string cannot be found, 'unknown type name' will be returned. + * @param {*} value A constructor, object, or primitive. + * @return {string} The best display name for the value, or 'unknown type name'. + * @private */ -ol.ENABLE_TILE = true; +goog.asserts.getType_ = function(value) { + if (value instanceof Function) { + return value.displayName || value.name || 'unknown type name'; + } else if (value instanceof Object) { + return value.constructor.displayName || value.constructor.name || + Object.prototype.toString.call(value); + } else { + return value === null ? 'null' : typeof value; + } +}; +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @define {boolean} Enable rendering of ol.layer.Vector based layers. Default - * is `true`. Setting this to false at compile time in advanced mode removes - * all code supporting Vector layers from the build. + * @fileoverview A global registry for entry points into a program, + * so that they can be instrumented. Each module should register their + * entry points with this registry. Designed to be compiled out + * if no instrumentation is requested. + * + * Entry points may be registered before or after a call to + * goog.debug.entryPointRegistry.monitorAll. If an entry point is registered + * later, the existing monitor will instrument the new entry point. + * + * @author nicksantos@google.com (Nick Santos) */ -ol.ENABLE_VECTOR = true; +goog.provide('goog.debug.EntryPointMonitor'); +goog.provide('goog.debug.entryPointRegistry'); + +goog.require('goog.asserts'); -/** - * @define {boolean} Enable rendering of ol.layer.VectorTile based layers. - * Default is `true`. Setting this to false at compile time in advanced mode - * removes all code supporting VectorTile layers from the build. - */ -ol.ENABLE_VECTOR_TILE = true; /** - * @define {boolean} Enable the WebGL renderer. Default is `true`. Setting - * this to false at compile time in advanced mode removes all code - * supporting the WebGL renderer from the build. + * @interface */ -ol.ENABLE_WEBGL = true; +goog.debug.EntryPointMonitor = function() {}; /** - * @define {number} The size in pixels of the first atlas image. Default is - * `256`. + * Instruments a function. + * + * @param {!Function} fn A function to instrument. + * @return {!Function} The instrumented function. */ -ol.INITIAL_ATLAS_SIZE = 256; +goog.debug.EntryPointMonitor.prototype.wrap; /** - * @define {number} The maximum size in pixels of atlas images. Default is - * `-1`, meaning it is not used (and `ol.WEBGL_MAX_TEXTURE_SIZE` is - * used instead). + * Try to remove an instrumentation wrapper created by this monitor. + * If the function passed to unwrap is not a wrapper created by this + * monitor, then we will do nothing. + * + * Notice that some wrappers may not be unwrappable. For example, if other + * monitors have applied their own wrappers, then it will be impossible to + * unwrap them because their wrappers will have captured our wrapper. + * + * So it is important that entry points are unwrapped in the reverse + * order that they were wrapped. + * + * @param {!Function} fn A function to unwrap. + * @return {!Function} The unwrapped function, or {@code fn} if it was not + * a wrapped function created by this monitor. */ -ol.MAX_ATLAS_SIZE = -1; +goog.debug.EntryPointMonitor.prototype.unwrap; /** - * @define {number} Maximum mouse wheel delta. + * An array of entry point callbacks. + * @type {!Array<function(!Function)>} + * @private */ -ol.MOUSEWHEELZOOM_MAXDELTA = 1; +goog.debug.entryPointRegistry.refList_ = []; /** - * @define {number} Mouse wheel timeout duration. + * Monitors that should wrap all the entry points. + * @type {!Array<!goog.debug.EntryPointMonitor>} + * @private */ -ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80; +goog.debug.entryPointRegistry.monitors_ = []; /** - * @define {number} Maximum width and/or height extent ratio that determines - * when the overview map should be zoomed out. + * Whether goog.debug.entryPointRegistry.monitorAll has ever been called. + * Checking this allows the compiler to optimize out the registrations. + * @type {boolean} + * @private */ -ol.OVERVIEWMAP_MAX_RATIO = 0.75; +goog.debug.entryPointRegistry.monitorsMayExist_ = false; /** - * @define {number} Minimum width and/or height extent ratio that determines - * when the overview map should be zoomed in. - */ -ol.OVERVIEWMAP_MIN_RATIO = 0.1; - - -/** - * @define {number} Maximum number of source tiles for raster reprojection of - * a single tile. - * If too many source tiles are determined to be loaded to create a single - * reprojected tile the browser can become unresponsive or even crash. - * This can happen if the developer defines projections improperly and/or - * with unlimited extents. - * If too many tiles are required, no tiles are loaded and - * `ol.TileState.ERROR` state is set. Default is `100`. - */ -ol.RASTER_REPROJECTION_MAX_SOURCE_TILES = 100; - - -/** - * @define {number} Maximum number of subdivision steps during raster - * reprojection triangulation. Prevents high memory usage and large - * number of proj4 calls (for certain transformations and areas). - * At most `2*(2^this)` triangles are created for each triangulated - * extent (tile/image). Default is `10`. - */ -ol.RASTER_REPROJECTION_MAX_SUBDIVISION = 10; - - -/** - * @define {number} Maximum allowed size of triangle relative to world width. - * When transforming corners of world extent between certain projections, - * the resulting triangulation seems to have zero error and no subdivision - * is performed. - * If the triangle width is more than this (relative to world width; 0-1), - * subdivison is forced (up to `ol.RASTER_REPROJECTION_MAX_SUBDIVISION`). - * Default is `0.25`. - */ -ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH = 0.25; - - -/** - * @define {number} Tolerance for geometry simplification in device pixels. - */ -ol.SIMPLIFY_TOLERANCE = 0.5; - - -/** - * @define {number} Texture cache high water mark. - */ -ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024; - - -/** - * The maximum supported WebGL texture size in pixels. If WebGL is not - * supported, the value is set to `undefined`. - * @const - * @type {number|undefined} - */ -ol.WEBGL_MAX_TEXTURE_SIZE; // value is set in `ol.has` - - -/** - * List of supported WebGL extensions. - * @const - * @type {Array.<string>} - */ -ol.WEBGL_EXTENSIONS; // value is set in `ol.has` - - -/** - * Inherit the prototype methods from one constructor into another. - * - * Usage: - * - * function ParentClass(a, b) { } - * ParentClass.prototype.foo = function(a) { } - * - * function ChildClass(a, b, c) { - * // Call parent constructor - * ParentClass.call(this, a, b); - * } - * ol.inherits(ChildClass, ParentClass); - * - * var child = new ChildClass('a', 'b', 'see'); - * child.foo(); // This works. - * - * In addition, a superclass' implementation of a method can be invoked as - * follows: - * - * ChildClass.prototype.foo = function(a) { - * ChildClass.base(this, 'foo', a); - * // Other code here. - * }; + * Register an entry point with this module. * - * @param {!Function} childCtor Child constructor. - * @param {!Function} parentCtor Parent constructor. - * @function - * @api - */ -ol.inherits = - goog.inherits; -// note that the newline above is necessary to satisfy the linter - - -/** - * A reusable function, used e.g. as a default for callbacks. + * The entry point will be instrumented when a monitor is passed to + * goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the + * entry point is instrumented immediately. * - * @return {undefined} Nothing. - */ -ol.nullFunction = function() {}; - -// FIXME factor out common code between usedTiles and wantedTiles - -goog.provide('ol.PostRenderFunction'); -goog.provide('ol.PreRenderFunction'); - - -/** - * @typedef {function(ol.Map, ?olx.FrameState): boolean} - */ -ol.PostRenderFunction; - - -/** - * Function to perform manipulations before rendering. This function is called - * with the {@link ol.Map} as first and an optional {@link olx.FrameState} as - * second argument. Return `true` to keep this function for the next frame, - * `false` to remove it. - * @typedef {function(ol.Map, ?olx.FrameState): boolean} - * @api + * @param {function(!Function)} callback A callback function which is called + * with a transforming function to instrument the entry point. The callback + * is responsible for wrapping the relevant entry point with the + * transforming function. */ -ol.PreRenderFunction; +goog.debug.entryPointRegistry.register = function(callback) { + // Don't use push(), so that this can be compiled out. + goog.debug.entryPointRegistry.refList_[ + goog.debug.entryPointRegistry.refList_.length] = callback; + // If no one calls monitorAll, this can be compiled out. + if (goog.debug.entryPointRegistry.monitorsMayExist_) { + var monitors = goog.debug.entryPointRegistry.monitors_; + for (var i = 0; i < monitors.length; i++) { + callback(goog.bind(monitors[i].wrap, monitors[i])); + } + } +}; -// Copyright 2009 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Provides a base class for custom Error objects such that the - * stack is correctly maintained. + * Configures a monitor to wrap all entry points. * - * You should never need to throw goog.debug.Error(msg) directly, Error(msg) is - * sufficient. + * Entry points that have already been registered are immediately wrapped by + * the monitor. When an entry point is registered in the future, it will also + * be wrapped by the monitor when it is registered. * + * @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor. */ - -goog.provide('goog.debug.Error'); - +goog.debug.entryPointRegistry.monitorAll = function(monitor) { + goog.debug.entryPointRegistry.monitorsMayExist_ = true; + var transformer = goog.bind(monitor.wrap, monitor); + for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) { + goog.debug.entryPointRegistry.refList_[i](transformer); + } + goog.debug.entryPointRegistry.monitors_.push(monitor); +}; /** - * Base class for custom error objects. - * @param {*=} opt_msg The message associated with the error. - * @constructor - * @extends {Error} + * Try to unmonitor all the entry points that have already been registered. If + * an entry point is registered in the future, it will not be wrapped by the + * monitor when it is registered. Note that this may fail if the entry points + * have additional wrapping. + * + * @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap + * the entry points. + * @throws {Error} If the monitor is not the most recently configured monitor. */ -goog.debug.Error = function(opt_msg) { - - // Attempt to ensure there is a stack trace. - if (Error.captureStackTrace) { - Error.captureStackTrace(this, goog.debug.Error); - } else { - var stack = new Error().stack; - if (stack) { - this.stack = stack; - } - } - - if (opt_msg) { - this.message = String(opt_msg); +goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) { + var monitors = goog.debug.entryPointRegistry.monitors_; + goog.asserts.assert(monitor == monitors[monitors.length - 1], + 'Only the most recent monitor can be unwrapped.'); + var transformer = goog.bind(monitor.unwrap, monitor); + for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) { + goog.debug.entryPointRegistry.refList_[i](transformer); } - - /** - * Whether to report this error to the server. Setting this to false will - * cause the error reporter to not report the error back to the server, - * which can be useful if the client knows that the error has already been - * logged on the server. - * @type {boolean} - */ - this.reportErrorToServer = true; + monitors.length--; }; -goog.inherits(goog.debug.Error, Error); - - -/** @override */ -goog.debug.Error.prototype.name = 'CustomError'; // Copyright 2006 The Closure Library Authors. All Rights Reserved. // @@ -4918,2198 +5418,2299 @@ goog.debug.Error.prototype.name = 'CustomError'; // limitations under the License. /** - * @fileoverview Definition of goog.dom.NodeType. + * @fileoverview Utilities for manipulating arrays. + * + * @author arv@google.com (Erik Arvidsson) */ -goog.provide('goog.dom.NodeType'); + +goog.provide('goog.array'); +goog.provide('goog.array.ArrayLike'); + +goog.require('goog.asserts'); /** - * Constants for the nodeType attribute in the Node interface. + * @define {boolean} NATIVE_ARRAY_PROTOTYPES indicates whether the code should + * rely on Array.prototype functions, if available. * - * These constants match those specified in the Node interface. These are - * usually present on the Node object in recent browsers, but not in older - * browsers (specifically, early IEs) and thus are given here. + * The Array.prototype functions can be defined by external libraries like + * Prototype and setting this flag to false forces closure to use its own + * goog.array implementation. * - * In some browsers (early IEs), these are not defined on the Node object, - * so they are provided here. + * If your javascript can be loaded by a third party site and you are wary about + * relying on the prototype functions, specify + * "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler. * - * See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247 - * @enum {number} + * Setting goog.TRUSTED_SITE to false will automatically set + * NATIVE_ARRAY_PROTOTYPES to false. */ -goog.dom.NodeType = { - ELEMENT: 1, - ATTRIBUTE: 2, - TEXT: 3, - CDATA_SECTION: 4, - ENTITY_REFERENCE: 5, - ENTITY: 6, - PROCESSING_INSTRUCTION: 7, - COMMENT: 8, - DOCUMENT: 9, - DOCUMENT_TYPE: 10, - DOCUMENT_FRAGMENT: 11, - NOTATION: 12 -}; +goog.define('goog.NATIVE_ARRAY_PROTOTYPES', goog.TRUSTED_SITE); -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utilities for string manipulation. - * @author arv@google.com (Erik Arvidsson) + * @define {boolean} If true, JSCompiler will use the native implementation of + * array functions where appropriate (e.g., {@code Array#filter}) and remove the + * unused pure JS implementation. */ +goog.define('goog.array.ASSUME_NATIVE_FUNCTIONS', false); /** - * Namespace for string utilities + * @typedef {Array|NodeList|Arguments|{length: number}} */ -goog.provide('goog.string'); -goog.provide('goog.string.Unicode'); +goog.array.ArrayLike; /** - * @define {boolean} Enables HTML escaping of lowercase letter "e" which helps - * with detection of double-escaping as this letter is frequently used. + * Returns the last element in an array without removing it. + * Same as goog.array.last. + * @param {Array<T>|goog.array.ArrayLike} array The array. + * @return {T} Last item in array. + * @template T */ -goog.define('goog.string.DETECT_DOUBLE_ESCAPING', false); +goog.array.peek = function(array) { + return array[array.length - 1]; +}; /** - * @define {boolean} Whether to force non-dom html unescaping. + * Returns the last element in an array without removing it. + * Same as goog.array.peek. + * @param {Array<T>|goog.array.ArrayLike} array The array. + * @return {T} Last item in array. + * @template T */ -goog.define('goog.string.FORCE_NON_DOM_HTML_UNESCAPING', false); +goog.array.last = goog.array.peek; /** - * Common Unicode string characters. - * @enum {string} + * Reference to the original {@code Array.prototype}. + * @private */ -goog.string.Unicode = { - NBSP: '\xa0' -}; +goog.array.ARRAY_PROTOTYPE_ = Array.prototype; -/** - * Fast prefix-checker. - * @param {string} str The string to check. - * @param {string} prefix A string to look for at the start of {@code str}. - * @return {boolean} True if {@code str} begins with {@code prefix}. - */ -goog.string.startsWith = function(str, prefix) { - return str.lastIndexOf(prefix, 0) == 0; -}; +// NOTE(arv): Since most of the array functions are generic it allows you to +// pass an array-like object. Strings have a length and are considered array- +// like. However, the 'in' operator does not work on strings so we cannot just +// use the array path even if the browser supports indexing into strings. We +// therefore end up splitting the string. /** - * Fast suffix-checker. - * @param {string} str The string to check. - * @param {string} suffix A string to look for at the end of {@code str}. - * @return {boolean} True if {@code str} ends with {@code suffix}. + * Returns the index of the first element of an array with a specified value, or + * -1 if the element is not present in the array. + * + * See {@link http://tinyurl.com/developer-mozilla-org-array-indexof} + * + * @param {Array<T>|goog.array.ArrayLike} arr The array to be searched. + * @param {T} obj The object for which we are searching. + * @param {number=} opt_fromIndex The index at which to start the search. If + * omitted the search starts at index 0. + * @return {number} The index of the first matching array element. + * @template T */ -goog.string.endsWith = function(str, suffix) { - var l = str.length - suffix.length; - return l >= 0 && str.indexOf(suffix, l) == l; -}; - +goog.array.indexOf = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.indexOf) ? + function(arr, obj, opt_fromIndex) { + goog.asserts.assert(arr.length != null); -/** - * Case-insensitive prefix-checker. - * @param {string} str The string to check. - * @param {string} prefix A string to look for at the end of {@code str}. - * @return {boolean} True if {@code str} begins with {@code prefix} (ignoring - * case). - */ -goog.string.caseInsensitiveStartsWith = function(str, prefix) { - return goog.string.caseInsensitiveCompare( - prefix, str.substr(0, prefix.length)) == 0; -}; + return goog.array.ARRAY_PROTOTYPE_.indexOf.call(arr, obj, opt_fromIndex); + } : + function(arr, obj, opt_fromIndex) { + var fromIndex = opt_fromIndex == null ? + 0 : (opt_fromIndex < 0 ? + Math.max(0, arr.length + opt_fromIndex) : opt_fromIndex); + if (goog.isString(arr)) { + // Array.prototype.indexOf uses === so only strings should be found. + if (!goog.isString(obj) || obj.length != 1) { + return -1; + } + return arr.indexOf(obj, fromIndex); + } -/** - * Case-insensitive suffix-checker. - * @param {string} str The string to check. - * @param {string} suffix A string to look for at the end of {@code str}. - * @return {boolean} True if {@code str} ends with {@code suffix} (ignoring - * case). - */ -goog.string.caseInsensitiveEndsWith = function(str, suffix) { - return goog.string.caseInsensitiveCompare( - suffix, str.substr(str.length - suffix.length, suffix.length)) == 0; -}; + for (var i = fromIndex; i < arr.length; i++) { + if (i in arr && arr[i] === obj) + return i; + } + return -1; + }; /** - * Case-insensitive equality checker. - * @param {string} str1 First string to check. - * @param {string} str2 Second string to check. - * @return {boolean} True if {@code str1} and {@code str2} are the same string, - * ignoring case. + * Returns the index of the last element of an array with a specified value, or + * -1 if the element is not present in the array. + * + * See {@link http://tinyurl.com/developer-mozilla-org-array-lastindexof} + * + * @param {!Array<T>|!goog.array.ArrayLike} arr The array to be searched. + * @param {T} obj The object for which we are searching. + * @param {?number=} opt_fromIndex The index at which to start the search. If + * omitted the search starts at the end of the array. + * @return {number} The index of the last matching array element. + * @template T */ -goog.string.caseInsensitiveEquals = function(str1, str2) { - return str1.toLowerCase() == str2.toLowerCase(); -}; +goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.lastIndexOf) ? + function(arr, obj, opt_fromIndex) { + goog.asserts.assert(arr.length != null); + // Firefox treats undefined and null as 0 in the fromIndex argument which + // leads it to always return -1 + var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex; + return goog.array.ARRAY_PROTOTYPE_.lastIndexOf.call(arr, obj, fromIndex); + } : + function(arr, obj, opt_fromIndex) { + var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex; -/** - * Does simple python-style string substitution. - * subs("foo%s hot%s", "bar", "dog") becomes "foobar hotdog". - * @param {string} str The string containing the pattern. - * @param {...*} var_args The items to substitute into the pattern. - * @return {string} A copy of {@code str} in which each occurrence of - * {@code %s} has been replaced an argument from {@code var_args}. - */ -goog.string.subs = function(str, var_args) { - var splitParts = str.split('%s'); - var returnString = ''; + if (fromIndex < 0) { + fromIndex = Math.max(0, arr.length + fromIndex); + } - var subsArguments = Array.prototype.slice.call(arguments, 1); - while (subsArguments.length && - // Replace up to the last split part. We are inserting in the - // positions between split parts. - splitParts.length > 1) { - returnString += splitParts.shift() + subsArguments.shift(); - } + if (goog.isString(arr)) { + // Array.prototype.lastIndexOf uses === so only strings should be found. + if (!goog.isString(obj) || obj.length != 1) { + return -1; + } + return arr.lastIndexOf(obj, fromIndex); + } - return returnString + splitParts.join('%s'); // Join unused '%s' -}; + for (var i = fromIndex; i >= 0; i--) { + if (i in arr && arr[i] === obj) + return i; + } + return -1; + }; /** - * Converts multiple whitespace chars (spaces, non-breaking-spaces, new lines - * and tabs) to a single space, and strips leading and trailing whitespace. - * @param {string} str Input string. - * @return {string} A copy of {@code str} with collapsed whitespace. + * Calls a function for each element in an array. Skips holes in the array. + * See {@link http://tinyurl.com/developer-mozilla-org-array-foreach} + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over + * which to iterate. + * @param {?function(this: S, T, number, ?): ?} f The function to call for every + * element. This function takes 3 arguments (the element, the index and the + * array). The return value is ignored. + * @param {S=} opt_obj The object to be used as the value of 'this' within f. + * @template T,S */ -goog.string.collapseWhitespace = function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return str.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, ''); -}; +goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.forEach) ? + function(arr, f, opt_obj) { + goog.asserts.assert(arr.length != null); + + goog.array.ARRAY_PROTOTYPE_.forEach.call(arr, f, opt_obj); + } : + function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = 0; i < l; i++) { + if (i in arr2) { + f.call(opt_obj, arr2[i], i, arr); + } + } + }; /** - * Checks if a string is empty or contains only whitespaces. - * @param {string} str The string to check. - * @return {boolean} Whether {@code str} is empty or whitespace only. + * Calls a function for each element in an array, starting from the last + * element rather than the first. + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this: S, T, number, ?): ?} f The function to call for every + * element. This function + * takes 3 arguments (the element, the index and the array). The return + * value is ignored. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within f. + * @template T,S */ -goog.string.isEmptyOrWhitespace = function(str) { - // testing length == 0 first is actually slower in all browsers (about the - // same in Opera). - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return /^[\s\xa0]*$/.test(str); +goog.array.forEachRight = function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = l - 1; i >= 0; --i) { + if (i in arr2) { + f.call(opt_obj, arr2[i], i, arr); + } + } }; /** - * Checks if a string is empty. - * @param {string} str The string to check. - * @return {boolean} Whether {@code str} is empty. + * Calls a function for each element in an array, and if the function returns + * true adds the element to a new array. + * + * See {@link http://tinyurl.com/developer-mozilla-org-array-filter} + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?):boolean} f The function to call for + * every element. This function + * takes 3 arguments (the element, the index and the array) and must + * return a Boolean. If the return value is true the element is added to the + * result array. If it is false the element is not included. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within f. + * @return {!Array<T>} a new array in which only elements that passed the test + * are present. + * @template T,S */ -goog.string.isEmptyString = function(str) { - return str.length == 0; -}; +goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.filter) ? + function(arr, f, opt_obj) { + goog.asserts.assert(arr.length != null); + + return goog.array.ARRAY_PROTOTYPE_.filter.call(arr, f, opt_obj); + } : + function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var res = []; + var resLength = 0; + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = 0; i < l; i++) { + if (i in arr2) { + var val = arr2[i]; // in case f mutates arr2 + if (f.call(opt_obj, val, i, arr)) { + res[resLength++] = val; + } + } + } + return res; + }; /** - * Checks if a string is empty or contains only whitespaces. + * Calls a function for each element in an array and inserts the result into a + * new array. * - * TODO(user): Deprecate this when clients have been switched over to - * goog.string.isEmptyOrWhitespace. + * See {@link http://tinyurl.com/developer-mozilla-org-array-map} * - * @param {string} str The string to check. - * @return {boolean} Whether {@code str} is empty or whitespace only. + * @param {Array<VALUE>|goog.array.ArrayLike} arr Array or array like object + * over which to iterate. + * @param {function(this:THIS, VALUE, number, ?): RESULT} f The function to call + * for every element. This function takes 3 arguments (the element, + * the index and the array) and should return something. The result will be + * inserted into a new array. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within f. + * @return {!Array<RESULT>} a new array with the results from f. + * @template THIS, VALUE, RESULT */ -goog.string.isEmpty = goog.string.isEmptyOrWhitespace; - +goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.map) ? + function(arr, f, opt_obj) { + goog.asserts.assert(arr.length != null); -/** - * Checks if a string is null, undefined, empty or contains only whitespaces. - * @param {*} str The string to check. - * @return {boolean} Whether {@code str} is null, undefined, empty, or - * whitespace only. - * @deprecated Use goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str)) - * instead. - */ -goog.string.isEmptyOrWhitespaceSafe = function(str) { - return goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str)); -}; + return goog.array.ARRAY_PROTOTYPE_.map.call(arr, f, opt_obj); + } : + function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var res = new Array(l); + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = 0; i < l; i++) { + if (i in arr2) { + res[i] = f.call(opt_obj, arr2[i], i, arr); + } + } + return res; + }; /** - * Checks if a string is null, undefined, empty or contains only whitespaces. + * Passes every element of an array into a function and accumulates the result. * - * TODO(user): Deprecate this when clients have been switched over to - * goog.string.isEmptyOrWhitespaceSafe. + * See {@link http://tinyurl.com/developer-mozilla-org-array-reduce} * - * @param {*} str The string to check. - * @return {boolean} Whether {@code str} is null, undefined, empty, or - * whitespace only. + * For example: + * var a = [1, 2, 3, 4]; + * goog.array.reduce(a, function(r, v, i, arr) {return r + v;}, 0); + * returns 10 + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {function(this:S, R, T, number, ?) : R} f The function to call for + * every element. This function + * takes 4 arguments (the function's previous result or the initial value, + * the value of the current array element, the current array index, and the + * array itself) + * function(previousValue, currentValue, index, array). + * @param {?} val The initial value to pass into the function on the first call. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within f. + * @return {R} Result of evaluating f repeatedly across the values of the array. + * @template T,S,R */ -goog.string.isEmptySafe = goog.string.isEmptyOrWhitespaceSafe; +goog.array.reduce = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.reduce) ? + function(arr, f, val, opt_obj) { + goog.asserts.assert(arr.length != null); + if (opt_obj) { + f = goog.bind(f, opt_obj); + } + return goog.array.ARRAY_PROTOTYPE_.reduce.call(arr, f, val); + } : + function(arr, f, val, opt_obj) { + var rval = val; + goog.array.forEach(arr, function(val, index) { + rval = f.call(opt_obj, rval, val, index, arr); + }); + return rval; + }; /** - * Checks if a string is all breaking whitespace. - * @param {string} str The string to check. - * @return {boolean} Whether the string is all breaking whitespace. + * Passes every element of an array into a function and accumulates the result, + * starting from the last element and working towards the first. + * + * See {@link http://tinyurl.com/developer-mozilla-org-array-reduceright} + * + * For example: + * var a = ['a', 'b', 'c']; + * goog.array.reduceRight(a, function(r, v, i, arr) {return r + v;}, ''); + * returns 'cba' + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, R, T, number, ?) : R} f The function to call for + * every element. This function + * takes 4 arguments (the function's previous result or the initial value, + * the value of the current array element, the current array index, and the + * array itself) + * function(previousValue, currentValue, index, array). + * @param {?} val The initial value to pass into the function on the first call. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within f. + * @return {R} Object returned as a result of evaluating f repeatedly across the + * values of the array. + * @template T,S,R */ -goog.string.isBreakingWhitespace = function(str) { - return !/[^\t\n\r ]/.test(str); -}; +goog.array.reduceRight = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.reduceRight) ? + function(arr, f, val, opt_obj) { + goog.asserts.assert(arr.length != null); + if (opt_obj) { + f = goog.bind(f, opt_obj); + } + return goog.array.ARRAY_PROTOTYPE_.reduceRight.call(arr, f, val); + } : + function(arr, f, val, opt_obj) { + var rval = val; + goog.array.forEachRight(arr, function(val, index) { + rval = f.call(opt_obj, rval, val, index, arr); + }); + return rval; + }; /** - * Checks if a string contains all letters. - * @param {string} str string to check. - * @return {boolean} True if {@code str} consists entirely of letters. + * Calls f for each element of an array. If any call returns true, some() + * returns true (without checking the remaining elements). If all calls + * return false, some() returns false. + * + * See {@link http://tinyurl.com/developer-mozilla-org-array-some} + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call for + * for every element. This function takes 3 arguments (the element, the + * index and the array) and should return a boolean. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within f. + * @return {boolean} true if any element passes the test. + * @template T,S */ -goog.string.isAlpha = function(str) { - return !/[^a-zA-Z]/.test(str); -}; +goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.some) ? + function(arr, f, opt_obj) { + goog.asserts.assert(arr.length != null); + + return goog.array.ARRAY_PROTOTYPE_.some.call(arr, f, opt_obj); + } : + function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = 0; i < l; i++) { + if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { + return true; + } + } + return false; + }; /** - * Checks if a string contains only numbers. - * @param {*} str string to check. If not a string, it will be - * casted to one. - * @return {boolean} True if {@code str} is numeric. + * Call f for each element of an array. If all calls return true, every() + * returns true. If any call returns false, every() returns false and + * does not continue to check the remaining elements. + * + * See {@link http://tinyurl.com/developer-mozilla-org-array-every} + * + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call for + * for every element. This function takes 3 arguments (the element, the + * index and the array) and should return a boolean. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within f. + * @return {boolean} false if any element fails the test. + * @template T,S */ -goog.string.isNumeric = function(str) { - return !/[^0-9]/.test(str); -}; +goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES && + (goog.array.ASSUME_NATIVE_FUNCTIONS || + goog.array.ARRAY_PROTOTYPE_.every) ? + function(arr, f, opt_obj) { + goog.asserts.assert(arr.length != null); + + return goog.array.ARRAY_PROTOTYPE_.every.call(arr, f, opt_obj); + } : + function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = 0; i < l; i++) { + if (i in arr2 && !f.call(opt_obj, arr2[i], i, arr)) { + return false; + } + } + return true; + }; /** - * Checks if a string contains only numbers or letters. - * @param {string} str string to check. - * @return {boolean} True if {@code str} is alphanumeric. + * Counts the array elements that fulfill the predicate, i.e. for which the + * callback function returns true. Skips holes in the array. + * + * @param {!(Array<T>|goog.array.ArrayLike)} arr Array or array like object + * over which to iterate. + * @param {function(this: S, T, number, ?): boolean} f The function to call for + * every element. Takes 3 arguments (the element, the index and the array). + * @param {S=} opt_obj The object to be used as the value of 'this' within f. + * @return {number} The number of the matching elements. + * @template T,S */ -goog.string.isAlphaNumeric = function(str) { - return !/[^a-zA-Z0-9]/.test(str); +goog.array.count = function(arr, f, opt_obj) { + var count = 0; + goog.array.forEach(arr, function(element, index, arr) { + if (f.call(opt_obj, element, index, arr)) { + ++count; + } + }, opt_obj); + return count; }; /** - * Checks if a character is a space character. - * @param {string} ch Character to check. - * @return {boolean} True if {@code ch} is a space. + * Search an array for the first element that satisfies a given condition and + * return that element. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call + * for every element. This function takes 3 arguments (the element, the + * index and the array) and should return a boolean. + * @param {S=} opt_obj An optional "this" context for the function. + * @return {T|null} The first array element that passes the test, or null if no + * element is found. + * @template T,S */ -goog.string.isSpace = function(ch) { - return ch == ' '; +goog.array.find = function(arr, f, opt_obj) { + var i = goog.array.findIndex(arr, f, opt_obj); + return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i]; }; /** - * Checks if a character is a valid unicode character. - * @param {string} ch Character to check. - * @return {boolean} True if {@code ch} is a valid unicode character. + * Search an array for the first element that satisfies a given condition and + * return its index. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call for + * every element. This function + * takes 3 arguments (the element, the index and the array) and should + * return a boolean. + * @param {S=} opt_obj An optional "this" context for the function. + * @return {number} The index of the first array element that passes the test, + * or -1 if no element is found. + * @template T,S */ -goog.string.isUnicodeChar = function(ch) { - return ch.length == 1 && ch >= ' ' && ch <= '~' || - ch >= '\u0080' && ch <= '\uFFFD'; +goog.array.findIndex = function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = 0; i < l; i++) { + if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { + return i; + } + } + return -1; }; /** - * Takes a string and replaces newlines with a space. Multiple lines are - * replaced with a single space. - * @param {string} str The string from which to strip newlines. - * @return {string} A copy of {@code str} stripped of newlines. + * Search an array (in reverse order) for the last element that satisfies a + * given condition and return that element. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call + * for every element. This function + * takes 3 arguments (the element, the index and the array) and should + * return a boolean. + * @param {S=} opt_obj An optional "this" context for the function. + * @return {T|null} The last array element that passes the test, or null if no + * element is found. + * @template T,S */ -goog.string.stripNewlines = function(str) { - return str.replace(/(\r\n|\r|\n)+/g, ' '); +goog.array.findRight = function(arr, f, opt_obj) { + var i = goog.array.findIndexRight(arr, f, opt_obj); + return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i]; }; /** - * Replaces Windows and Mac new lines with unix style: \r or \r\n with \n. - * @param {string} str The string to in which to canonicalize newlines. - * @return {string} {@code str} A copy of {@code} with canonicalized newlines. + * Search an array (in reverse order) for the last element that satisfies a + * given condition and return its index. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call + * for every element. This function + * takes 3 arguments (the element, the index and the array) and should + * return a boolean. + * @param {S=} opt_obj An optional "this" context for the function. + * @return {number} The index of the last array element that passes the test, + * or -1 if no element is found. + * @template T,S */ -goog.string.canonicalizeNewlines = function(str) { - return str.replace(/(\r\n|\r|\n)/g, '\n'); +goog.array.findIndexRight = function(arr, f, opt_obj) { + var l = arr.length; // must be fixed during loop... see docs + var arr2 = goog.isString(arr) ? arr.split('') : arr; + for (var i = l - 1; i >= 0; i--) { + if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { + return i; + } + } + return -1; }; /** - * Normalizes whitespace in a string, replacing all whitespace chars with - * a space. - * @param {string} str The string in which to normalize whitespace. - * @return {string} A copy of {@code str} with all whitespace normalized. + * Whether the array contains the given object. + * @param {goog.array.ArrayLike} arr The array to test for the presence of the + * element. + * @param {*} obj The object for which to test. + * @return {boolean} true if obj is present. */ -goog.string.normalizeWhitespace = function(str) { - return str.replace(/\xa0|\s/g, ' '); +goog.array.contains = function(arr, obj) { + return goog.array.indexOf(arr, obj) >= 0; }; /** - * Normalizes spaces in a string, replacing all consecutive spaces and tabs - * with a single space. Replaces non-breaking space with a space. - * @param {string} str The string in which to normalize spaces. - * @return {string} A copy of {@code str} with all consecutive spaces and tabs - * replaced with a single space. + * Whether the array is empty. + * @param {goog.array.ArrayLike} arr The array to test. + * @return {boolean} true if empty. */ -goog.string.normalizeSpaces = function(str) { - return str.replace(/\xa0|[ \t]+/g, ' '); +goog.array.isEmpty = function(arr) { + return arr.length == 0; }; /** - * Removes the breaking spaces from the left and right of the string and - * collapses the sequences of breaking spaces in the middle into single spaces. - * The original and the result strings render the same way in HTML. - * @param {string} str A string in which to collapse spaces. - * @return {string} Copy of the string with normalized breaking spaces. + * Clears the array. + * @param {goog.array.ArrayLike} arr Array or array like object to clear. */ -goog.string.collapseBreakingSpaces = function(str) { - return str.replace(/[\t\r\n ]+/g, ' ').replace( - /^[\t\r\n ]+|[\t\r\n ]+$/g, ''); +goog.array.clear = function(arr) { + // For non real arrays we don't have the magic length so we delete the + // indices. + if (!goog.isArray(arr)) { + for (var i = arr.length - 1; i >= 0; i--) { + delete arr[i]; + } + } + arr.length = 0; }; /** - * Trims white spaces to the left and right of a string. - * @param {string} str The string to trim. - * @return {string} A trimmed copy of {@code str}. + * Pushes an item into an array, if it's not already in the array. + * @param {Array<T>} arr Array into which to insert the item. + * @param {T} obj Value to add. + * @template T */ -goog.string.trim = (goog.TRUSTED_SITE && String.prototype.trim) ? - function(str) { - return str.trim(); - } : - function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s - // character class (as required by section 7.2 of the ECMAScript spec), - // we explicitly include it in the regexp to enforce consistent - // cross-browser behavior. - return str.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); - }; +goog.array.insert = function(arr, obj) { + if (!goog.array.contains(arr, obj)) { + arr.push(obj); + } +}; /** - * Trims whitespaces at the left end of a string. - * @param {string} str The string to left trim. - * @return {string} A trimmed copy of {@code str}. + * Inserts an object at the given index of the array. + * @param {goog.array.ArrayLike} arr The array to modify. + * @param {*} obj The object to insert. + * @param {number=} opt_i The index at which to insert the object. If omitted, + * treated as 0. A negative index is counted from the end of the array. */ -goog.string.trimLeft = function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return str.replace(/^[\s\xa0]+/, ''); +goog.array.insertAt = function(arr, obj, opt_i) { + goog.array.splice(arr, opt_i, 0, obj); }; /** - * Trims whitespaces at the right end of a string. - * @param {string} str The string to right trim. - * @return {string} A trimmed copy of {@code str}. + * Inserts at the given index of the array, all elements of another array. + * @param {goog.array.ArrayLike} arr The array to modify. + * @param {goog.array.ArrayLike} elementsToAdd The array of elements to add. + * @param {number=} opt_i The index at which to insert the object. If omitted, + * treated as 0. A negative index is counted from the end of the array. */ -goog.string.trimRight = function(str) { - // Since IE doesn't include non-breaking-space (0xa0) in their \s character - // class (as required by section 7.2 of the ECMAScript spec), we explicitly - // include it in the regexp to enforce consistent cross-browser behavior. - return str.replace(/[\s\xa0]+$/, ''); +goog.array.insertArrayAt = function(arr, elementsToAdd, opt_i) { + goog.partial(goog.array.splice, arr, opt_i, 0).apply(null, elementsToAdd); }; /** - * A string comparator that ignores case. - * -1 = str1 less than str2 - * 0 = str1 equals str2 - * 1 = str1 greater than str2 - * - * @param {string} str1 The string to compare. - * @param {string} str2 The string to compare {@code str1} to. - * @return {number} The comparator result, as described above. + * Inserts an object into an array before a specified object. + * @param {Array<T>} arr The array to modify. + * @param {T} obj The object to insert. + * @param {T=} opt_obj2 The object before which obj should be inserted. If obj2 + * is omitted or not found, obj is inserted at the end of the array. + * @template T */ -goog.string.caseInsensitiveCompare = function(str1, str2) { - var test1 = String(str1).toLowerCase(); - var test2 = String(str2).toLowerCase(); - - if (test1 < test2) { - return -1; - } else if (test1 == test2) { - return 0; +goog.array.insertBefore = function(arr, obj, opt_obj2) { + var i; + if (arguments.length == 2 || (i = goog.array.indexOf(arr, opt_obj2)) < 0) { + arr.push(obj); } else { - return 1; + goog.array.insertAt(arr, obj, i); } }; /** - * Regular expression used for splitting a string into substrings of fractional - * numbers, integers, and non-numeric characters. - * @type {RegExp} - * @private - */ -goog.string.numerateCompareRegExp_ = /(\.\d+)|(\d+)|(\D+)/g; - - -/** - * String comparison function that handles numbers in a way humans might expect. - * Using this function, the string "File 2.jpg" sorts before "File 10.jpg". The - * comparison is mostly case-insensitive, though strings that are identical - * except for case are sorted with the upper-case strings before lower-case. - * - * This comparison function is significantly slower (about 500x) than either - * the default or the case-insensitive compare. It should not be used in - * time-critical code, but should be fast enough to sort several hundred short - * strings (like filenames) with a reasonable delay. - * - * @param {string} str1 The string to compare in a numerically sensitive way. - * @param {string} str2 The string to compare {@code str1} to. - * @return {number} less than 0 if str1 < str2, 0 if str1 == str2, greater than - * 0 if str1 > str2. + * Removes the first occurrence of a particular value from an array. + * @param {Array<T>|goog.array.ArrayLike} arr Array from which to remove + * value. + * @param {T} obj Object to remove. + * @return {boolean} True if an element was removed. + * @template T */ -goog.string.numerateCompare = function(str1, str2) { - if (str1 == str2) { - return 0; - } - if (!str1) { - return -1; - } - if (!str2) { - return 1; - } - - // Using match to split the entire string ahead of time turns out to be faster - // for most inputs than using RegExp.exec or iterating over each character. - var tokens1 = str1.toLowerCase().match(goog.string.numerateCompareRegExp_); - var tokens2 = str2.toLowerCase().match(goog.string.numerateCompareRegExp_); - - var count = Math.min(tokens1.length, tokens2.length); - - for (var i = 0; i < count; i++) { - var a = tokens1[i]; - var b = tokens2[i]; - - // Compare pairs of tokens, returning if one token sorts before the other. - if (a != b) { - - // Only if both tokens are integers is a special comparison required. - // Decimal numbers are sorted as strings (e.g., '.09' < '.1'). - var num1 = parseInt(a, 10); - if (!isNaN(num1)) { - var num2 = parseInt(b, 10); - if (!isNaN(num2) && num1 - num2) { - return num1 - num2; - } - } - return a < b ? -1 : 1; - } - } - - // If one string is a substring of the other, the shorter string sorts first. - if (tokens1.length != tokens2.length) { - return tokens1.length - tokens2.length; +goog.array.remove = function(arr, obj) { + var i = goog.array.indexOf(arr, obj); + var rv; + if ((rv = i >= 0)) { + goog.array.removeAt(arr, i); } - - // The two strings must be equivalent except for case (perfect equality is - // tested at the head of the function.) Revert to default ASCII-betical string - // comparison to stablize the sort. - return str1 < str2 ? -1 : 1; + return rv; }; /** - * URL-encodes a string - * @param {*} str The string to url-encode. - * @return {string} An encoded copy of {@code str} that is safe for urls. - * Note that '#', ':', and other characters used to delimit portions - * of URLs *will* be encoded. + * Removes from an array the element at index i + * @param {goog.array.ArrayLike} arr Array or array like object from which to + * remove value. + * @param {number} i The index to remove. + * @return {boolean} True if an element was removed. */ -goog.string.urlEncode = function(str) { - return encodeURIComponent(String(str)); +goog.array.removeAt = function(arr, i) { + goog.asserts.assert(arr.length != null); + + // use generic form of splice + // splice returns the removed items and if successful the length of that + // will be 1 + return goog.array.ARRAY_PROTOTYPE_.splice.call(arr, i, 1).length == 1; }; /** - * URL-decodes the string. We need to specially handle '+'s because - * the javascript library doesn't convert them to spaces. - * @param {string} str The string to url decode. - * @return {string} The decoded {@code str}. + * Removes the first value that satisfies the given condition. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call + * for every element. This function + * takes 3 arguments (the element, the index and the array) and should + * return a boolean. + * @param {S=} opt_obj An optional "this" context for the function. + * @return {boolean} True if an element was removed. + * @template T,S */ -goog.string.urlDecode = function(str) { - return decodeURIComponent(str.replace(/\+/g, ' ')); +goog.array.removeIf = function(arr, f, opt_obj) { + var i = goog.array.findIndex(arr, f, opt_obj); + if (i >= 0) { + goog.array.removeAt(arr, i); + return true; + } + return false; }; /** - * Converts \n to <br>s or <br />s. - * @param {string} str The string in which to convert newlines. - * @param {boolean=} opt_xml Whether to use XML compatible tags. - * @return {string} A copy of {@code str} with converted newlines. + * Removes all values that satisfy the given condition. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array + * like object over which to iterate. + * @param {?function(this:S, T, number, ?) : boolean} f The function to call + * for every element. This function + * takes 3 arguments (the element, the index and the array) and should + * return a boolean. + * @param {S=} opt_obj An optional "this" context for the function. + * @return {number} The number of items removed + * @template T,S */ -goog.string.newLineToBr = function(str, opt_xml) { - return str.replace(/(\r\n|\r|\n)/g, opt_xml ? '<br />' : '<br>'); +goog.array.removeAllIf = function(arr, f, opt_obj) { + var removedCount = 0; + goog.array.forEachRight(arr, function(val, index) { + if (f.call(opt_obj, val, index, arr)) { + if (goog.array.removeAt(arr, index)) { + removedCount++; + } + } + }); + return removedCount; }; /** - * Escapes double quote '"' and single quote '\'' characters in addition to - * '&', '<', and '>' so that a string can be included in an HTML tag attribute - * value within double or single quotes. - * - * It should be noted that > doesn't need to be escaped for the HTML or XML to - * be valid, but it has been decided to escape it for consistency with other - * implementations. + * Returns a new array that is the result of joining the arguments. If arrays + * are passed then their items are added, however, if non-arrays are passed they + * will be added to the return array as is. * - * With goog.string.DETECT_DOUBLE_ESCAPING, this function escapes also the - * lowercase letter "e". + * Note that ArrayLike objects will be added as is, rather than having their + * items added. * - * NOTE(user): - * HtmlEscape is often called during the generation of large blocks of HTML. - * Using statics for the regular expressions and strings is an optimization - * that can more than half the amount of time IE spends in this function for - * large apps, since strings and regexes both contribute to GC allocations. + * goog.array.concat([1, 2], [3, 4]) -> [1, 2, 3, 4] + * goog.array.concat(0, [1, 2]) -> [0, 1, 2] + * goog.array.concat([1, 2], null) -> [1, 2, null] * - * Testing for the presence of a character before escaping increases the number - * of function calls, but actually provides a speed increase for the average - * case -- since the average case often doesn't require the escaping of all 4 - * characters and indexOf() is much cheaper than replace(). - * The worst case does suffer slightly from the additional calls, therefore the - * opt_isLikelyToContainHtmlChars option has been included for situations - * where all 4 HTML entities are very likely to be present and need escaping. + * There is bug in all current versions of IE (6, 7 and 8) where arrays created + * in an iframe become corrupted soon (not immediately) after the iframe is + * destroyed. This is common if loading data via goog.net.IframeIo, for example. + * This corruption only affects the concat method which will start throwing + * Catastrophic Errors (#-2147418113). * - * Some benchmarks (times tended to fluctuate +-0.05ms): - * FireFox IE6 - * (no chars / average (mix of cases) / all 4 chars) - * no checks 0.13 / 0.22 / 0.22 0.23 / 0.53 / 0.80 - * indexOf 0.08 / 0.17 / 0.26 0.22 / 0.54 / 0.84 - * indexOf + re test 0.07 / 0.17 / 0.28 0.19 / 0.50 / 0.85 + * See http://endoflow.com/scratch/corrupted-arrays.html for a test case. * - * An additional advantage of checking if replace actually needs to be called - * is a reduction in the number of object allocations, so as the size of the - * application grows the difference between the various methods would increase. + * Internally goog.array should use this, so that all methods will continue to + * work on these broken array objects. * - * @param {string} str string to be escaped. - * @param {boolean=} opt_isLikelyToContainHtmlChars Don't perform a check to see - * if the character needs replacing - use this option if you expect each of - * the characters to appear often. Leave false if you expect few html - * characters to occur in your strings, such as if you are escaping HTML. - * @return {string} An escaped copy of {@code str}. + * @param {...*} var_args Items to concatenate. Arrays will have each item + * added, while primitives and objects will be added as is. + * @return {!Array<?>} The new resultant array. */ -goog.string.htmlEscape = function(str, opt_isLikelyToContainHtmlChars) { - - if (opt_isLikelyToContainHtmlChars) { - str = str.replace(goog.string.AMP_RE_, '&') - .replace(goog.string.LT_RE_, '<') - .replace(goog.string.GT_RE_, '>') - .replace(goog.string.QUOT_RE_, '"') - .replace(goog.string.SINGLE_QUOTE_RE_, ''') - .replace(goog.string.NULL_RE_, '�'); - if (goog.string.DETECT_DOUBLE_ESCAPING) { - str = str.replace(goog.string.E_RE_, 'e'); - } - return str; - - } else { - // quick test helps in the case when there are no chars to replace, in - // worst case this makes barely a difference to the time taken - if (!goog.string.ALL_RE_.test(str)) return str; - - // str.indexOf is faster than regex.test in this case - if (str.indexOf('&') != -1) { - str = str.replace(goog.string.AMP_RE_, '&'); - } - if (str.indexOf('<') != -1) { - str = str.replace(goog.string.LT_RE_, '<'); - } - if (str.indexOf('>') != -1) { - str = str.replace(goog.string.GT_RE_, '>'); - } - if (str.indexOf('"') != -1) { - str = str.replace(goog.string.QUOT_RE_, '"'); - } - if (str.indexOf('\'') != -1) { - str = str.replace(goog.string.SINGLE_QUOTE_RE_, '''); - } - if (str.indexOf('\x00') != -1) { - str = str.replace(goog.string.NULL_RE_, '�'); - } - if (goog.string.DETECT_DOUBLE_ESCAPING && str.indexOf('e') != -1) { - str = str.replace(goog.string.E_RE_, 'e'); - } - return str; - } +goog.array.concat = function(var_args) { + return goog.array.ARRAY_PROTOTYPE_.concat.apply( + goog.array.ARRAY_PROTOTYPE_, arguments); }; /** - * Regular expression that matches an ampersand, for use in escaping. - * @const {!RegExp} - * @private + * Returns a new array that contains the contents of all the arrays passed. + * @param {...!Array<T>} var_args + * @return {!Array<T>} + * @template T */ -goog.string.AMP_RE_ = /&/g; +goog.array.join = function(var_args) { + return goog.array.ARRAY_PROTOTYPE_.concat.apply( + goog.array.ARRAY_PROTOTYPE_, arguments); +}; /** - * Regular expression that matches a less than sign, for use in escaping. - * @const {!RegExp} - * @private + * Converts an object to an array. + * @param {Array<T>|goog.array.ArrayLike} object The object to convert to an + * array. + * @return {!Array<T>} The object converted into an array. If object has a + * length property, every property indexed with a non-negative number + * less than length will be included in the result. If object does not + * have a length property, an empty array will be returned. + * @template T */ -goog.string.LT_RE_ = /</g; - +goog.array.toArray = function(object) { + var length = object.length; -/** - * Regular expression that matches a greater than sign, for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.GT_RE_ = />/g; + // If length is not a number the following it false. This case is kept for + // backwards compatibility since there are callers that pass objects that are + // not array like. + if (length > 0) { + var rv = new Array(length); + for (var i = 0; i < length; i++) { + rv[i] = object[i]; + } + return rv; + } + return []; +}; /** - * Regular expression that matches a double quote, for use in escaping. - * @const {!RegExp} - * @private + * Does a shallow copy of an array. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array-like object to + * clone. + * @return {!Array<T>} Clone of the input array. + * @template T */ -goog.string.QUOT_RE_ = /"/g; +goog.array.clone = goog.array.toArray; /** - * Regular expression that matches a single quote, for use in escaping. - * @const {!RegExp} - * @private + * Extends an array with another array, element, or "array like" object. + * This function operates 'in-place', it does not create a new Array. + * + * Example: + * var a = []; + * goog.array.extend(a, [0, 1]); + * a; // [0, 1] + * goog.array.extend(a, 2); + * a; // [0, 1, 2] + * + * @param {Array<VALUE>} arr1 The array to modify. + * @param {...(Array<VALUE>|VALUE)} var_args The elements or arrays of elements + * to add to arr1. + * @template VALUE */ -goog.string.SINGLE_QUOTE_RE_ = /'/g; +goog.array.extend = function(arr1, var_args) { + for (var i = 1; i < arguments.length; i++) { + var arr2 = arguments[i]; + if (goog.isArrayLike(arr2)) { + var len1 = arr1.length || 0; + var len2 = arr2.length || 0; + arr1.length = len1 + len2; + for (var j = 0; j < len2; j++) { + arr1[len1 + j] = arr2[j]; + } + } else { + arr1.push(arr2); + } + } +}; /** - * Regular expression that matches null character, for use in escaping. - * @const {!RegExp} - * @private + * Adds or removes elements from an array. This is a generic version of Array + * splice. This means that it might work on other objects similar to arrays, + * such as the arguments object. + * + * @param {Array<T>|goog.array.ArrayLike} arr The array to modify. + * @param {number|undefined} index The index at which to start changing the + * array. If not defined, treated as 0. + * @param {number} howMany How many elements to remove (0 means no removal. A + * value below 0 is treated as zero and so is any other non number. Numbers + * are floored). + * @param {...T} var_args Optional, additional elements to insert into the + * array. + * @return {!Array<T>} the removed elements. + * @template T */ -goog.string.NULL_RE_ = /\x00/g; - +goog.array.splice = function(arr, index, howMany, var_args) { + goog.asserts.assert(arr.length != null); -/** - * Regular expression that matches a lowercase letter "e", for use in escaping. - * @const {!RegExp} - * @private - */ -goog.string.E_RE_ = /e/g; + return goog.array.ARRAY_PROTOTYPE_.splice.apply( + arr, goog.array.slice(arguments, 1)); +}; /** - * Regular expression that matches any character that needs to be escaped. - * @const {!RegExp} - * @private + * Returns a new array from a segment of an array. This is a generic version of + * Array slice. This means that it might work on other objects similar to + * arrays, such as the arguments object. + * + * @param {Array<T>|goog.array.ArrayLike} arr The array from + * which to copy a segment. + * @param {number} start The index of the first element to copy. + * @param {number=} opt_end The index after the last element to copy. + * @return {!Array<T>} A new array containing the specified segment of the + * original array. + * @template T */ -goog.string.ALL_RE_ = (goog.string.DETECT_DOUBLE_ESCAPING ? - /[\x00&<>"'e]/ : - /[\x00&<>"']/); +goog.array.slice = function(arr, start, opt_end) { + goog.asserts.assert(arr.length != null); + + // passing 1 arg to slice is not the same as passing 2 where the second is + // null or undefined (in that case the second argument is treated as 0). + // we could use slice on the arguments object and then use apply instead of + // testing the length + if (arguments.length <= 2) { + return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start); + } else { + return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start, opt_end); + } +}; /** - * Unescapes an HTML string. + * Removes all duplicates from an array (retaining only the first + * occurrence of each array element). This function modifies the + * array in place and doesn't change the order of the non-duplicate items. * - * @param {string} str The string to unescape. - * @return {string} An unescaped copy of {@code str}. + * For objects, duplicates are identified as having the same unique ID as + * defined by {@link goog.getUid}. + * + * Alternatively you can specify a custom hash function that returns a unique + * value for each item in the array it should consider unique. + * + * Runtime: N, + * Worstcase space: 2N (no dupes) + * + * @param {Array<T>|goog.array.ArrayLike} arr The array from which to remove + * duplicates. + * @param {Array=} opt_rv An optional array in which to return the results, + * instead of performing the removal inplace. If specified, the original + * array will remain unchanged. + * @param {function(T):string=} opt_hashFn An optional function to use to + * apply to every item in the array. This function should return a unique + * value for each item in the array it should consider unique. + * @template T */ -goog.string.unescapeEntities = function(str) { - if (goog.string.contains(str, '&')) { - // We are careful not to use a DOM if we do not have one or we explicitly - // requested non-DOM html unescaping. - if (!goog.string.FORCE_NON_DOM_HTML_UNESCAPING && - 'document' in goog.global) { - return goog.string.unescapeEntitiesUsingDom_(str); - } else { - // Fall back on pure XML entities - return goog.string.unescapePureXmlEntities_(str); +goog.array.removeDuplicates = function(arr, opt_rv, opt_hashFn) { + var returnArray = opt_rv || arr; + var defaultHashFn = function(item) { + // Prefix each type with a single character representing the type to + // prevent conflicting keys (e.g. true and 'true'). + return goog.isObject(item) ? 'o' + goog.getUid(item) : + (typeof item).charAt(0) + item; + }; + var hashFn = opt_hashFn || defaultHashFn; + + var seen = {}, cursorInsert = 0, cursorRead = 0; + while (cursorRead < arr.length) { + var current = arr[cursorRead++]; + var key = hashFn(current); + if (!Object.prototype.hasOwnProperty.call(seen, key)) { + seen[key] = true; + returnArray[cursorInsert++] = current; } } - return str; + returnArray.length = cursorInsert; }; /** - * Unescapes a HTML string using the provided document. + * Searches the specified array for the specified target using the binary + * search algorithm. If no opt_compareFn is specified, elements are compared + * using <code>goog.array.defaultCompare</code>, which compares the elements + * using the built in < and > operators. This will produce the expected + * behavior for homogeneous arrays of String(s) and Number(s). The array + * specified <b>must</b> be sorted in ascending order (as defined by the + * comparison function). If the array is not sorted, results are undefined. + * If the array contains multiple instances of the specified target value, any + * of these instances may be found. * - * @param {string} str The string to unescape. - * @param {!Document} document A document to use in escaping the string. - * @return {string} An unescaped copy of {@code str}. + * Runtime: O(log n) + * + * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. + * @param {TARGET} target The sought value. + * @param {function(TARGET, VALUE): number=} opt_compareFn Optional comparison + * function by which the array is ordered. Should take 2 arguments to + * compare, and return a negative number, zero, or a positive number + * depending on whether the first argument is less than, equal to, or + * greater than the second. + * @return {number} Lowest index of the target value if found, otherwise + * (-(insertion point) - 1). The insertion point is where the value should + * be inserted into arr to preserve the sorted property. Return value >= 0 + * iff target is found. + * @template TARGET, VALUE */ -goog.string.unescapeEntitiesWithDocument = function(str, document) { - if (goog.string.contains(str, '&')) { - return goog.string.unescapeEntitiesUsingDom_(str, document); - } - return str; +goog.array.binarySearch = function(arr, target, opt_compareFn) { + return goog.array.binarySearch_(arr, + opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */, + target); }; /** - * Unescapes an HTML string using a DOM to resolve non-XML, non-numeric - * entities. This function is XSS-safe and whitespace-preserving. - * @private - * @param {string} str The string to unescape. - * @param {Document=} opt_document An optional document to use for creating - * elements. If this is not specified then the default window.document - * will be used. - * @return {string} The unescaped {@code str} string. + * Selects an index in the specified array using the binary search algorithm. + * The evaluator receives an element and determines whether the desired index + * is before, at, or after it. The evaluator must be consistent (formally, + * goog.array.map(goog.array.map(arr, evaluator, opt_obj), goog.math.sign) + * must be monotonically non-increasing). + * + * Runtime: O(log n) + * + * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. + * @param {function(this:THIS, VALUE, number, ?): number} evaluator + * Evaluator function that receives 3 arguments (the element, the index and + * the array). Should return a negative number, zero, or a positive number + * depending on whether the desired index is before, at, or after the + * element passed to it. + * @param {THIS=} opt_obj The object to be used as the value of 'this' + * within evaluator. + * @return {number} Index of the leftmost element matched by the evaluator, if + * such exists; otherwise (-(insertion point) - 1). The insertion point is + * the index of the first element for which the evaluator returns negative, + * or arr.length if no such element exists. The return value is non-negative + * iff a match is found. + * @template THIS, VALUE */ -goog.string.unescapeEntitiesUsingDom_ = function(str, opt_document) { - /** @type {!Object<string, string>} */ - var seen = {'&': '&', '<': '<', '>': '>', '"': '"'}; - var div; - if (opt_document) { - div = opt_document.createElement('div'); - } else { - div = goog.global.document.createElement('div'); - } - // Match as many valid entity characters as possible. If the actual entity - // happens to be shorter, it will still work as innerHTML will return the - // trailing characters unchanged. Since the entity characters do not include - // open angle bracket, there is no chance of XSS from the innerHTML use. - // Since no whitespace is passed to innerHTML, whitespace is preserved. - return str.replace(goog.string.HTML_ENTITY_PATTERN_, function(s, entity) { - // Check for cached entity. - var value = seen[s]; - if (value) { - return value; - } - // Check for numeric entity. - if (entity.charAt(0) == '#') { - // Prefix with 0 so that hex entities (e.g. ) parse as hex numbers. - var n = Number('0' + entity.substr(1)); - if (!isNaN(n)) { - value = String.fromCharCode(n); - } - } - // Fall back to innerHTML otherwise. - if (!value) { - // Append a non-entity character to avoid a bug in Webkit that parses - // an invalid entity at the end of innerHTML text as the empty string. - div.innerHTML = s + ' '; - // Then remove the trailing character from the result. - value = div.firstChild.nodeValue.slice(0, -1); - } - // Cache and return. - return seen[s] = value; - }); +goog.array.binarySelect = function(arr, evaluator, opt_obj) { + return goog.array.binarySearch_(arr, evaluator, true /* isEvaluator */, + undefined /* opt_target */, opt_obj); }; /** - * Unescapes XML entities. + * Implementation of a binary search algorithm which knows how to use both + * comparison functions and evaluators. If an evaluator is provided, will call + * the evaluator with the given optional data object, conforming to the + * interface defined in binarySelect. Otherwise, if a comparison function is + * provided, will call the comparison function against the given data object. + * + * This implementation purposefully does not use goog.bind or goog.partial for + * performance reasons. + * + * Runtime: O(log n) + * + * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. + * @param {function(TARGET, VALUE): number| + * function(this:THIS, VALUE, number, ?): number} compareFn Either an + * evaluator or a comparison function, as defined by binarySearch + * and binarySelect above. + * @param {boolean} isEvaluator Whether the function is an evaluator or a + * comparison function. + * @param {TARGET=} opt_target If the function is a comparison function, then + * this is the target to binary search for. + * @param {THIS=} opt_selfObj If the function is an evaluator, this is an + * optional this object for the evaluator. + * @return {number} Lowest index of the target value if found, otherwise + * (-(insertion point) - 1). The insertion point is where the value should + * be inserted into arr to preserve the sorted property. Return value >= 0 + * iff target is found. + * @template THIS, VALUE, TARGET * @private - * @param {string} str The string to unescape. - * @return {string} An unescaped copy of {@code str}. */ -goog.string.unescapePureXmlEntities_ = function(str) { - return str.replace(/&([^;]+);/g, function(s, entity) { - switch (entity) { - case 'amp': - return '&'; - case 'lt': - return '<'; - case 'gt': - return '>'; - case 'quot': - return '"'; - default: - if (entity.charAt(0) == '#') { - // Prefix with 0 so that hex entities (e.g. ) parse as hex. - var n = Number('0' + entity.substr(1)); - if (!isNaN(n)) { - return String.fromCharCode(n); - } - } - // For invalid entities we just return the entity - return s; +goog.array.binarySearch_ = function(arr, compareFn, isEvaluator, opt_target, + opt_selfObj) { + var left = 0; // inclusive + var right = arr.length; // exclusive + var found; + while (left < right) { + var middle = (left + right) >> 1; + var compareResult; + if (isEvaluator) { + compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr); + } else { + compareResult = compareFn(opt_target, arr[middle]); } - }); + if (compareResult > 0) { + left = middle + 1; + } else { + right = middle; + // We are looking for the lowest index so we can't return immediately. + found = !compareResult; + } + } + // left is the index if found, or the insertion point otherwise. + // ~left is a shorthand for -left - 1. + return found ? left : ~left; }; /** - * Regular expression that matches an HTML entity. - * See also HTML5: Tokenization / Tokenizing character references. - * @private - * @type {!RegExp} + * Sorts the specified array into ascending order. If no opt_compareFn is + * specified, elements are compared using + * <code>goog.array.defaultCompare</code>, which compares the elements using + * the built in < and > operators. This will produce the expected behavior + * for homogeneous arrays of String(s) and Number(s), unlike the native sort, + * but will give unpredictable results for heterogenous lists of strings and + * numbers with different numbers of digits. + * + * This sort is not guaranteed to be stable. + * + * Runtime: Same as <code>Array.prototype.sort</code> + * + * @param {Array<T>} arr The array to be sorted. + * @param {?function(T,T):number=} opt_compareFn Optional comparison + * function by which the + * array is to be ordered. Should take 2 arguments to compare, and return a + * negative number, zero, or a positive number depending on whether the + * first argument is less than, equal to, or greater than the second. + * @template T */ -goog.string.HTML_ENTITY_PATTERN_ = /&([^;\s<&]+);?/g; +goog.array.sort = function(arr, opt_compareFn) { + // TODO(arv): Update type annotation since null is not accepted. + arr.sort(opt_compareFn || goog.array.defaultCompare); +}; /** - * Do escaping of whitespace to preserve spatial formatting. We use character - * entity #160 to make it safer for xml. - * @param {string} str The string in which to escape whitespace. - * @param {boolean=} opt_xml Whether to use XML compatible tags. - * @return {string} An escaped copy of {@code str}. + * Sorts the specified array into ascending order in a stable way. If no + * opt_compareFn is specified, elements are compared using + * <code>goog.array.defaultCompare</code>, which compares the elements using + * the built in < and > operators. This will produce the expected behavior + * for homogeneous arrays of String(s) and Number(s). + * + * Runtime: Same as <code>Array.prototype.sort</code>, plus an additional + * O(n) overhead of copying the array twice. + * + * @param {Array<T>} arr The array to be sorted. + * @param {?function(T, T): number=} opt_compareFn Optional comparison function + * by which the array is to be ordered. Should take 2 arguments to compare, + * and return a negative number, zero, or a positive number depending on + * whether the first argument is less than, equal to, or greater than the + * second. + * @template T */ -goog.string.whitespaceEscape = function(str, opt_xml) { - // This doesn't use goog.string.preserveSpaces for backwards compatibility. - return goog.string.newLineToBr(str.replace(/ /g, '  '), opt_xml); +goog.array.stableSort = function(arr, opt_compareFn) { + for (var i = 0; i < arr.length; i++) { + arr[i] = {index: i, value: arr[i]}; + } + var valueCompareFn = opt_compareFn || goog.array.defaultCompare; + function stableCompareFn(obj1, obj2) { + return valueCompareFn(obj1.value, obj2.value) || obj1.index - obj2.index; + }; + goog.array.sort(arr, stableCompareFn); + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].value; + } }; /** - * Preserve spaces that would be otherwise collapsed in HTML by replacing them - * with non-breaking space Unicode characters. - * @param {string} str The string in which to preserve whitespace. - * @return {string} A copy of {@code str} with preserved whitespace. + * Sort the specified array into ascending order based on item keys + * returned by the specified key function. + * If no opt_compareFn is specified, the keys are compared in ascending order + * using <code>goog.array.defaultCompare</code>. + * + * Runtime: O(S(f(n)), where S is runtime of <code>goog.array.sort</code> + * and f(n) is runtime of the key function. + * + * @param {Array<T>} arr The array to be sorted. + * @param {function(T): K} keyFn Function taking array element and returning + * a key used for sorting this element. + * @param {?function(K, K): number=} opt_compareFn Optional comparison function + * by which the keys are to be ordered. Should take 2 arguments to compare, + * and return a negative number, zero, or a positive number depending on + * whether the first argument is less than, equal to, or greater than the + * second. + * @template T,K */ -goog.string.preserveSpaces = function(str) { - return str.replace(/(^|[\n ]) /g, '$1' + goog.string.Unicode.NBSP); +goog.array.sortByKey = function(arr, keyFn, opt_compareFn) { + var keyCompareFn = opt_compareFn || goog.array.defaultCompare; + goog.array.sort(arr, function(a, b) { + return keyCompareFn(keyFn(a), keyFn(b)); + }); }; /** - * Strip quote characters around a string. The second argument is a string of - * characters to treat as quotes. This can be a single character or a string of - * multiple character and in that case each of those are treated as possible - * quote characters. For example: - * - * <pre> - * goog.string.stripQuotes('"abc"', '"`') --> 'abc' - * goog.string.stripQuotes('`abc`', '"`') --> 'abc' - * </pre> - * - * @param {string} str The string to strip. - * @param {string} quoteChars The quote characters to strip. - * @return {string} A copy of {@code str} without the quotes. + * Sorts an array of objects by the specified object key and compare + * function. If no compare function is provided, the key values are + * compared in ascending order using <code>goog.array.defaultCompare</code>. + * This won't work for keys that get renamed by the compiler. So use + * {'foo': 1, 'bar': 2} rather than {foo: 1, bar: 2}. + * @param {Array<Object>} arr An array of objects to sort. + * @param {string} key The object key to sort by. + * @param {Function=} opt_compareFn The function to use to compare key + * values. */ -goog.string.stripQuotes = function(str, quoteChars) { - var length = quoteChars.length; - for (var i = 0; i < length; i++) { - var quoteChar = length == 1 ? quoteChars : quoteChars.charAt(i); - if (str.charAt(0) == quoteChar && str.charAt(str.length - 1) == quoteChar) { - return str.substring(1, str.length - 1); - } - } - return str; +goog.array.sortObjectsByKey = function(arr, key, opt_compareFn) { + goog.array.sortByKey(arr, + function(obj) { return obj[key]; }, + opt_compareFn); }; /** - * Truncates a string to a certain length and adds '...' if necessary. The - * length also accounts for the ellipsis, so a maximum length of 10 and a string - * 'Hello World!' produces 'Hello W...'. - * @param {string} str The string to truncate. - * @param {number} chars Max number of characters. - * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped - * characters from being cut off in the middle. - * @return {string} The truncated {@code str} string. + * Tells if the array is sorted. + * @param {!Array<T>} arr The array. + * @param {?function(T,T):number=} opt_compareFn Function to compare the + * array elements. + * Should take 2 arguments to compare, and return a negative number, zero, + * or a positive number depending on whether the first argument is less + * than, equal to, or greater than the second. + * @param {boolean=} opt_strict If true no equal elements are allowed. + * @return {boolean} Whether the array is sorted. + * @template T */ -goog.string.truncate = function(str, chars, opt_protectEscapedCharacters) { - if (opt_protectEscapedCharacters) { - str = goog.string.unescapeEntities(str); +goog.array.isSorted = function(arr, opt_compareFn, opt_strict) { + var compare = opt_compareFn || goog.array.defaultCompare; + for (var i = 1; i < arr.length; i++) { + var compareResult = compare(arr[i - 1], arr[i]); + if (compareResult > 0 || compareResult == 0 && opt_strict) { + return false; + } } + return true; +}; - if (str.length > chars) { - str = str.substring(0, chars - 3) + '...'; - } - if (opt_protectEscapedCharacters) { - str = goog.string.htmlEscape(str); +/** + * Compares two arrays for equality. Two arrays are considered equal if they + * have the same length and their corresponding elements are equal according to + * the comparison function. + * + * @param {goog.array.ArrayLike} arr1 The first array to compare. + * @param {goog.array.ArrayLike} arr2 The second array to compare. + * @param {Function=} opt_equalsFn Optional comparison function. + * Should take 2 arguments to compare, and return true if the arguments + * are equal. Defaults to {@link goog.array.defaultCompareEquality} which + * compares the elements using the built-in '===' operator. + * @return {boolean} Whether the two arrays are equal. + */ +goog.array.equals = function(arr1, arr2, opt_equalsFn) { + if (!goog.isArrayLike(arr1) || !goog.isArrayLike(arr2) || + arr1.length != arr2.length) { + return false; } - - return str; + var l = arr1.length; + var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality; + for (var i = 0; i < l; i++) { + if (!equalsFn(arr1[i], arr2[i])) { + return false; + } + } + return true; }; /** - * Truncate a string in the middle, adding "..." if necessary, - * and favoring the beginning of the string. - * @param {string} str The string to truncate the middle of. - * @param {number} chars Max number of characters. - * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped - * characters from being cutoff in the middle. - * @param {number=} opt_trailingChars Optional number of trailing characters to - * leave at the end of the string, instead of truncating as close to the - * middle as possible. - * @return {string} A truncated copy of {@code str}. + * 3-way array compare function. + * @param {!Array<VALUE>|!goog.array.ArrayLike} arr1 The first array to + * compare. + * @param {!Array<VALUE>|!goog.array.ArrayLike} arr2 The second array to + * compare. + * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison + * function by which the array is to be ordered. Should take 2 arguments to + * compare, and return a negative number, zero, or a positive number + * depending on whether the first argument is less than, equal to, or + * greater than the second. + * @return {number} Negative number, zero, or a positive number depending on + * whether the first argument is less than, equal to, or greater than the + * second. + * @template VALUE */ -goog.string.truncateMiddle = function(str, chars, - opt_protectEscapedCharacters, opt_trailingChars) { - if (opt_protectEscapedCharacters) { - str = goog.string.unescapeEntities(str); - } - - if (opt_trailingChars && str.length > chars) { - if (opt_trailingChars > chars) { - opt_trailingChars = chars; +goog.array.compare3 = function(arr1, arr2, opt_compareFn) { + var compare = opt_compareFn || goog.array.defaultCompare; + var l = Math.min(arr1.length, arr2.length); + for (var i = 0; i < l; i++) { + var result = compare(arr1[i], arr2[i]); + if (result != 0) { + return result; } - var endPoint = str.length - opt_trailingChars; - var startPoint = chars - opt_trailingChars; - str = str.substring(0, startPoint) + '...' + str.substring(endPoint); - } else if (str.length > chars) { - // Favor the beginning of the string: - var half = Math.floor(chars / 2); - var endPos = str.length - half; - half += chars % 2; - str = str.substring(0, half) + '...' + str.substring(endPos); } + return goog.array.defaultCompare(arr1.length, arr2.length); +}; - if (opt_protectEscapedCharacters) { - str = goog.string.htmlEscape(str); - } - return str; +/** + * Compares its two arguments for order, using the built in < and > + * operators. + * @param {VALUE} a The first object to be compared. + * @param {VALUE} b The second object to be compared. + * @return {number} A negative number, zero, or a positive number as the first + * argument is less than, equal to, or greater than the second, + * respectively. + * @template VALUE + */ +goog.array.defaultCompare = function(a, b) { + return a > b ? 1 : a < b ? -1 : 0; }; /** - * Special chars that need to be escaped for goog.string.quote. - * @private {!Object<string, string>} + * Compares its two arguments for inverse order, using the built in < and > + * operators. + * @param {VALUE} a The first object to be compared. + * @param {VALUE} b The second object to be compared. + * @return {number} A negative number, zero, or a positive number as the first + * argument is greater than, equal to, or less than the second, + * respectively. + * @template VALUE */ -goog.string.specialEscapeChars_ = { - '\0': '\\0', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', - '\x0B': '\\x0B', // '\v' is not supported in JScript - '"': '\\"', - '\\': '\\\\' +goog.array.inverseDefaultCompare = function(a, b) { + return -goog.array.defaultCompare(a, b); }; /** - * Character mappings used internally for goog.string.escapeChar. - * @private {!Object<string, string>} + * Compares its two arguments for equality, using the built in === operator. + * @param {*} a The first object to compare. + * @param {*} b The second object to compare. + * @return {boolean} True if the two arguments are equal, false otherwise. */ -goog.string.jsEscapeCache_ = { - '\'': '\\\'' +goog.array.defaultCompareEquality = function(a, b) { + return a === b; }; /** - * Encloses a string in double quotes and escapes characters so that the - * string is a valid JS string. - * @param {string} s The string to quote. - * @return {string} A copy of {@code s} surrounded by double quotes. + * Inserts a value into a sorted array. The array is not modified if the + * value is already present. + * @param {Array<VALUE>|goog.array.ArrayLike} array The array to modify. + * @param {VALUE} value The object to insert. + * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison + * function by which the array is ordered. Should take 2 arguments to + * compare, and return a negative number, zero, or a positive number + * depending on whether the first argument is less than, equal to, or + * greater than the second. + * @return {boolean} True if an element was inserted. + * @template VALUE */ -goog.string.quote = function(s) { - s = String(s); - if (s.quote) { - return s.quote(); - } else { - var sb = ['"']; - for (var i = 0; i < s.length; i++) { - var ch = s.charAt(i); - var cc = ch.charCodeAt(0); - sb[i + 1] = goog.string.specialEscapeChars_[ch] || - ((cc > 31 && cc < 127) ? ch : goog.string.escapeChar(ch)); - } - sb.push('"'); - return sb.join(''); +goog.array.binaryInsert = function(array, value, opt_compareFn) { + var index = goog.array.binarySearch(array, value, opt_compareFn); + if (index < 0) { + goog.array.insertAt(array, value, -(index + 1)); + return true; } + return false; }; /** - * Takes a string and returns the escaped string for that character. - * @param {string} str The string to escape. - * @return {string} An escaped string representing {@code str}. + * Removes a value from a sorted array. + * @param {!Array<VALUE>|!goog.array.ArrayLike} array The array to modify. + * @param {VALUE} value The object to remove. + * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison + * function by which the array is ordered. Should take 2 arguments to + * compare, and return a negative number, zero, or a positive number + * depending on whether the first argument is less than, equal to, or + * greater than the second. + * @return {boolean} True if an element was removed. + * @template VALUE */ -goog.string.escapeString = function(str) { - var sb = []; - for (var i = 0; i < str.length; i++) { - sb[i] = goog.string.escapeChar(str.charAt(i)); - } - return sb.join(''); +goog.array.binaryRemove = function(array, value, opt_compareFn) { + var index = goog.array.binarySearch(array, value, opt_compareFn); + return (index >= 0) ? goog.array.removeAt(array, index) : false; }; /** - * Takes a character and returns the escaped string for that character. For - * example escapeChar(String.fromCharCode(15)) -> "\\x0E". - * @param {string} c The character to escape. - * @return {string} An escaped string representing {@code c}. + * Splits an array into disjoint buckets according to a splitting function. + * @param {Array<T>} array The array. + * @param {function(this:S, T,number,Array<T>):?} sorter Function to call for + * every element. This takes 3 arguments (the element, the index and the + * array) and must return a valid object key (a string, number, etc), or + * undefined, if that object should not be placed in a bucket. + * @param {S=} opt_obj The object to be used as the value of 'this' within + * sorter. + * @return {!Object} An object, with keys being all of the unique return values + * of sorter, and values being arrays containing the items for + * which the splitter returned that key. + * @template T,S */ -goog.string.escapeChar = function(c) { - if (c in goog.string.jsEscapeCache_) { - return goog.string.jsEscapeCache_[c]; - } +goog.array.bucket = function(array, sorter, opt_obj) { + var buckets = {}; - if (c in goog.string.specialEscapeChars_) { - return goog.string.jsEscapeCache_[c] = goog.string.specialEscapeChars_[c]; - } - - var rv = c; - var cc = c.charCodeAt(0); - if (cc > 31 && cc < 127) { - rv = c; - } else { - // tab is 9 but handled above - if (cc < 256) { - rv = '\\x'; - if (cc < 16 || cc > 256) { - rv += '0'; - } - } else { - rv = '\\u'; - if (cc < 4096) { // \u1000 - rv += '0'; - } + for (var i = 0; i < array.length; i++) { + var value = array[i]; + var key = sorter.call(opt_obj, value, i, array); + if (goog.isDef(key)) { + // Push the value to the right bucket, creating it if necessary. + var bucket = buckets[key] || (buckets[key] = []); + bucket.push(value); } - rv += cc.toString(16).toUpperCase(); } - return goog.string.jsEscapeCache_[c] = rv; + return buckets; }; /** - * Determines whether a string contains a substring. - * @param {string} str The string to search. - * @param {string} subString The substring to search for. - * @return {boolean} Whether {@code str} contains {@code subString}. + * Creates a new object built from the provided array and the key-generation + * function. + * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over + * which to iterate whose elements will be the values in the new object. + * @param {?function(this:S, T, number, ?) : string} keyFunc The function to + * call for every element. This function takes 3 arguments (the element, the + * index and the array) and should return a string that will be used as the + * key for the element in the new object. If the function returns the same + * key for more than one element, the value for that key is + * implementation-defined. + * @param {S=} opt_obj The object to be used as the value of 'this' + * within keyFunc. + * @return {!Object<T>} The new object. + * @template T,S */ -goog.string.contains = function(str, subString) { - return str.indexOf(subString) != -1; +goog.array.toObject = function(arr, keyFunc, opt_obj) { + var ret = {}; + goog.array.forEach(arr, function(element, index) { + ret[keyFunc.call(opt_obj, element, index, arr)] = element; + }); + return ret; }; /** - * Determines whether a string contains a substring, ignoring case. - * @param {string} str The string to search. - * @param {string} subString The substring to search for. - * @return {boolean} Whether {@code str} contains {@code subString}. + * Creates a range of numbers in an arithmetic progression. + * + * Range takes 1, 2, or 3 arguments: + * <pre> + * range(5) is the same as range(0, 5, 1) and produces [0, 1, 2, 3, 4] + * range(2, 5) is the same as range(2, 5, 1) and produces [2, 3, 4] + * range(-2, -5, -1) produces [-2, -3, -4] + * range(-2, -5, 1) produces [], since stepping by 1 wouldn't ever reach -5. + * </pre> + * + * @param {number} startOrEnd The starting value of the range if an end argument + * is provided. Otherwise, the start value is 0, and this is the end value. + * @param {number=} opt_end The optional end value of the range. + * @param {number=} opt_step The step size between range values. Defaults to 1 + * if opt_step is undefined or 0. + * @return {!Array<number>} An array of numbers for the requested range. May be + * an empty array if adding the step would not converge toward the end + * value. */ -goog.string.caseInsensitiveContains = function(str, subString) { - return goog.string.contains(str.toLowerCase(), subString.toLowerCase()); -}; +goog.array.range = function(startOrEnd, opt_end, opt_step) { + var array = []; + var start = 0; + var end = startOrEnd; + var step = opt_step || 1; + if (opt_end !== undefined) { + start = startOrEnd; + end = opt_end; + } + if (step * (end - start) < 0) { + // Sign mismatch: start + step will never reach the end value. + return []; + } -/** - * Returns the non-overlapping occurrences of ss in s. - * If either s or ss evalutes to false, then returns zero. - * @param {string} s The string to look in. - * @param {string} ss The string to look for. - * @return {number} Number of occurrences of ss in s. - */ -goog.string.countOf = function(s, ss) { - return s && ss ? s.split(ss).length - 1 : 0; + if (step > 0) { + for (var i = start; i < end; i += step) { + array.push(i); + } + } else { + for (var i = start; i > end; i += step) { + array.push(i); + } + } + return array; }; /** - * Removes a substring of a specified length at a specific - * index in a string. - * @param {string} s The base string from which to remove. - * @param {number} index The index at which to remove the substring. - * @param {number} stringLength The length of the substring to remove. - * @return {string} A copy of {@code s} with the substring removed or the full - * string if nothing is removed or the input is invalid. + * Returns an array consisting of the given value repeated N times. + * + * @param {VALUE} value The value to repeat. + * @param {number} n The repeat count. + * @return {!Array<VALUE>} An array with the repeated value. + * @template VALUE */ -goog.string.removeAt = function(s, index, stringLength) { - var resultStr = s; - // If the index is greater or equal to 0 then remove substring - if (index >= 0 && index < s.length && stringLength > 0) { - resultStr = s.substr(0, index) + - s.substr(index + stringLength, s.length - index - stringLength); +goog.array.repeat = function(value, n) { + var array = []; + for (var i = 0; i < n; i++) { + array[i] = value; } - return resultStr; + return array; }; /** - * Removes the first occurrence of a substring from a string. - * @param {string} s The base string from which to remove. - * @param {string} ss The string to remove. - * @return {string} A copy of {@code s} with {@code ss} removed or the full - * string if nothing is removed. + * Returns an array consisting of every argument with all arrays + * expanded in-place recursively. + * + * @param {...*} var_args The values to flatten. + * @return {!Array<?>} An array containing the flattened values. */ -goog.string.remove = function(s, ss) { - var re = new RegExp(goog.string.regExpEscape(ss), ''); - return s.replace(re, ''); -}; - +goog.array.flatten = function(var_args) { + var CHUNK_SIZE = 8192; -/** - * Removes all occurrences of a substring from a string. - * @param {string} s The base string from which to remove. - * @param {string} ss The string to remove. - * @return {string} A copy of {@code s} with {@code ss} removed or the full - * string if nothing is removed. - */ -goog.string.removeAll = function(s, ss) { - var re = new RegExp(goog.string.regExpEscape(ss), 'g'); - return s.replace(re, ''); + var result = []; + for (var i = 0; i < arguments.length; i++) { + var element = arguments[i]; + if (goog.isArray(element)) { + for (var c = 0; c < element.length; c += CHUNK_SIZE) { + var chunk = goog.array.slice(element, c, c + CHUNK_SIZE); + var recurseResult = goog.array.flatten.apply(null, chunk); + for (var r = 0; r < recurseResult.length; r++) { + result.push(recurseResult[r]); + } + } + } else { + result.push(element); + } + } + return result; }; /** - * Escapes characters in the string that are not safe to use in a RegExp. - * @param {*} s The string to escape. If not a string, it will be casted - * to one. - * @return {string} A RegExp safe, escaped copy of {@code s}. + * Rotates an array in-place. After calling this method, the element at + * index i will be the element previously at index (i - n) % + * array.length, for all values of i between 0 and array.length - 1, + * inclusive. + * + * For example, suppose list comprises [t, a, n, k, s]. After invoking + * rotate(array, 1) (or rotate(array, -4)), array will comprise [s, t, a, n, k]. + * + * @param {!Array<T>} array The array to rotate. + * @param {number} n The amount to rotate. + * @return {!Array<T>} The array. + * @template T */ -goog.string.regExpEscape = function(s) { - return String(s).replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1'). - replace(/\x08/g, '\\x08'); +goog.array.rotate = function(array, n) { + goog.asserts.assert(array.length != null); + + if (array.length) { + n %= array.length; + if (n > 0) { + goog.array.ARRAY_PROTOTYPE_.unshift.apply(array, array.splice(-n, n)); + } else if (n < 0) { + goog.array.ARRAY_PROTOTYPE_.push.apply(array, array.splice(0, -n)); + } + } + return array; }; /** - * Repeats a string n times. - * @param {string} string The string to repeat. - * @param {number} length The number of times to repeat. - * @return {string} A string containing {@code length} repetitions of - * {@code string}. + * Moves one item of an array to a new position keeping the order of the rest + * of the items. Example use case: keeping a list of JavaScript objects + * synchronized with the corresponding list of DOM elements after one of the + * elements has been dragged to a new position. + * @param {!(Array|Arguments|{length:number})} arr The array to modify. + * @param {number} fromIndex Index of the item to move between 0 and + * {@code arr.length - 1}. + * @param {number} toIndex Target index between 0 and {@code arr.length - 1}. */ -goog.string.repeat = function(string, length) { - return new Array(length + 1).join(string); +goog.array.moveItem = function(arr, fromIndex, toIndex) { + goog.asserts.assert(fromIndex >= 0 && fromIndex < arr.length); + goog.asserts.assert(toIndex >= 0 && toIndex < arr.length); + // Remove 1 item at fromIndex. + var removedItems = goog.array.ARRAY_PROTOTYPE_.splice.call(arr, fromIndex, 1); + // Insert the removed item at toIndex. + goog.array.ARRAY_PROTOTYPE_.splice.call(arr, toIndex, 0, removedItems[0]); + // We don't use goog.array.insertAt and goog.array.removeAt, because they're + // significantly slower than splice. }; /** - * Pads number to given length and optionally rounds it to a given precision. - * For example: - * <pre>padNumber(1.25, 2, 3) -> '01.250' - * padNumber(1.25, 2) -> '01.25' - * padNumber(1.25, 2, 1) -> '01.3' - * padNumber(1.25, 0) -> '1.25'</pre> + * Creates a new array for which the element at position i is an array of the + * ith element of the provided arrays. The returned array will only be as long + * as the shortest array provided; additional values are ignored. For example, + * the result of zipping [1, 2] and [3, 4, 5] is [[1,3], [2, 4]]. * - * @param {number} num The number to pad. - * @param {number} length The desired length. - * @param {number=} opt_precision The desired precision. - * @return {string} {@code num} as a string with the given options. + * This is similar to the zip() function in Python. See {@link + * http://docs.python.org/library/functions.html#zip} + * + * @param {...!goog.array.ArrayLike} var_args Arrays to be combined. + * @return {!Array<!Array<?>>} A new array of arrays created from + * provided arrays. */ -goog.string.padNumber = function(num, length, opt_precision) { - var s = goog.isDef(opt_precision) ? num.toFixed(opt_precision) : String(num); - var index = s.indexOf('.'); - if (index == -1) { - index = s.length; +goog.array.zip = function(var_args) { + if (!arguments.length) { + return []; + } + var result = []; + for (var i = 0; true; i++) { + var value = []; + for (var j = 0; j < arguments.length; j++) { + var arr = arguments[j]; + // If i is larger than the array length, this is the shortest array. + if (i >= arr.length) { + return result; + } + value.push(arr[i]); + } + result.push(value); } - return goog.string.repeat('0', Math.max(0, length - index)) + s; }; /** - * Returns a string representation of the given object, with - * null and undefined being returned as the empty string. + * Shuffles the values in the specified array using the Fisher-Yates in-place + * shuffle (also known as the Knuth Shuffle). By default, calls Math.random() + * and so resets the state of that random number generator. Similarly, may reset + * the state of the any other specified random number generator. * - * @param {*} obj The object to convert. - * @return {string} A string representation of the {@code obj}. + * Runtime: O(n) + * + * @param {!Array<?>} arr The array to be shuffled. + * @param {function():number=} opt_randFn Optional random function to use for + * shuffling. + * Takes no arguments, and returns a random number on the interval [0, 1). + * Defaults to Math.random() using JavaScript's built-in Math library. */ -goog.string.makeSafe = function(obj) { - return obj == null ? '' : String(obj); -}; +goog.array.shuffle = function(arr, opt_randFn) { + var randFn = opt_randFn || Math.random; + for (var i = arr.length - 1; i > 0; i--) { + // Choose a random array index in [0, i] (inclusive with i). + var j = Math.floor(randFn() * (i + 1)); -/** - * Concatenates string expressions. This is useful - * since some browsers are very inefficient when it comes to using plus to - * concat strings. Be careful when using null and undefined here since - * these will not be included in the result. If you need to represent these - * be sure to cast the argument to a String first. - * For example: - * <pre>buildString('a', 'b', 'c', 'd') -> 'abcd' - * buildString(null, undefined) -> '' - * </pre> - * @param {...*} var_args A list of strings to concatenate. If not a string, - * it will be casted to one. - * @return {string} The concatenation of {@code var_args}. - */ -goog.string.buildString = function(var_args) { - return Array.prototype.join.call(arguments, ''); + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } }; /** - * Returns a string with at least 64-bits of randomness. - * - * Doesn't trust Javascript's random function entirely. Uses a combination of - * random and current timestamp, and then encodes the string in base-36 to - * make it shorter. + * Returns a new array of elements from arr, based on the indexes of elements + * provided by index_arr. For example, the result of index copying + * ['a', 'b', 'c'] with index_arr [1,0,0,2] is ['b', 'a', 'a', 'c']. * - * @return {string} A random string, e.g. sn1s7vb4gcic. + * @param {!Array<T>} arr The array to get a indexed copy from. + * @param {!Array<number>} index_arr An array of indexes to get from arr. + * @return {!Array<T>} A new array of elements from arr in index_arr order. + * @template T */ -goog.string.getRandomString = function() { - var x = 2147483648; - return Math.floor(Math.random() * x).toString(36) + - Math.abs(Math.floor(Math.random() * x) ^ goog.now()).toString(36); +goog.array.copyByIndex = function(arr, index_arr) { + var result = []; + goog.array.forEach(index_arr, function(index) { + result.push(arr[index]); + }); + return result; }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Compares two version numbers. + * @fileoverview Utilities used by goog.labs.userAgent tools. These functions + * should not be used outside of goog.labs.userAgent.*. * - * @param {string|number} version1 Version of first item. - * @param {string|number} version2 Version of second item. * - * @return {number} 1 if {@code version1} is higher. - * 0 if arguments are equal. - * -1 if {@code version2} is higher. + * @author nnaze@google.com (Nathan Naze) */ -goog.string.compareVersions = function(version1, version2) { - var order = 0; - // Trim leading and trailing whitespace and split the versions into - // subversions. - var v1Subs = goog.string.trim(String(version1)).split('.'); - var v2Subs = goog.string.trim(String(version2)).split('.'); - var subCount = Math.max(v1Subs.length, v2Subs.length); - // Iterate over the subversions, as long as they appear to be equivalent. - for (var subIdx = 0; order == 0 && subIdx < subCount; subIdx++) { - var v1Sub = v1Subs[subIdx] || ''; - var v2Sub = v2Subs[subIdx] || ''; +goog.provide('goog.labs.userAgent.util'); - // Split the subversions into pairs of numbers and qualifiers (like 'b'). - // Two different RegExp objects are needed because they are both using - // the 'g' flag. - var v1CompParser = new RegExp('(\\d*)(\\D*)', 'g'); - var v2CompParser = new RegExp('(\\d*)(\\D*)', 'g'); - do { - var v1Comp = v1CompParser.exec(v1Sub) || ['', '', '']; - var v2Comp = v2CompParser.exec(v2Sub) || ['', '', '']; - // Break if there are no more matches. - if (v1Comp[0].length == 0 && v2Comp[0].length == 0) { - break; - } +goog.require('goog.string'); - // Parse the numeric part of the subversion. A missing number is - // equivalent to 0. - var v1CompNum = v1Comp[1].length == 0 ? 0 : parseInt(v1Comp[1], 10); - var v2CompNum = v2Comp[1].length == 0 ? 0 : parseInt(v2Comp[1], 10); - // Compare the subversion components. The number has the highest - // precedence. Next, if the numbers are equal, a subversion without any - // qualifier is always higher than a subversion with any qualifier. Next, - // the qualifiers are compared as strings. - order = goog.string.compareElements_(v1CompNum, v2CompNum) || - goog.string.compareElements_(v1Comp[2].length == 0, - v2Comp[2].length == 0) || - goog.string.compareElements_(v1Comp[2], v2Comp[2]); - // Stop as soon as an inequality is discovered. - } while (order == 0); +/** + * Gets the native userAgent string from navigator if it exists. + * If navigator or navigator.userAgent string is missing, returns an empty + * string. + * @return {string} + * @private + */ +goog.labs.userAgent.util.getNativeUserAgentString_ = function() { + var navigator = goog.labs.userAgent.util.getNavigator_(); + if (navigator) { + var userAgent = navigator.userAgent; + if (userAgent) { + return userAgent; + } } - - return order; + return ''; }; /** - * Compares elements of a version number. - * - * @param {string|number|boolean} left An element from a version number. - * @param {string|number|boolean} right An element from a version number. - * - * @return {number} 1 if {@code left} is higher. - * 0 if arguments are equal. - * -1 if {@code right} is higher. + * Getter for the native navigator. + * This is a separate function so it can be stubbed out in testing. + * @return {Navigator} * @private */ -goog.string.compareElements_ = function(left, right) { - if (left < right) { - return -1; - } else if (left > right) { - return 1; - } - return 0; +goog.labs.userAgent.util.getNavigator_ = function() { + return goog.global.navigator; }; /** - * Maximum value of #goog.string.hashCode, exclusive. 2^32. - * @type {number} - * @private + * A possible override for applications which wish to not check + * navigator.userAgent but use a specified value for detection instead. + * @private {string} */ -goog.string.HASHCODE_MAX_ = 0x100000000; +goog.labs.userAgent.util.userAgent_ = + goog.labs.userAgent.util.getNativeUserAgentString_(); /** - * String hash function similar to java.lang.String.hashCode(). - * The hash code for a string is computed as - * s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1], - * where s[i] is the ith character of the string and n is the length of - * the string. We mod the result to make it between 0 (inclusive) and 2^32 - * (exclusive). - * @param {string} str A string. - * @return {number} Hash value for {@code str}, between 0 (inclusive) and 2^32 - * (exclusive). The empty string returns 0. + * Applications may override browser detection on the built in + * navigator.userAgent object by setting this string. Set to null to use the + * browser object instead. + * @param {?string=} opt_userAgent The User-Agent override. */ -goog.string.hashCode = function(str) { - var result = 0; - for (var i = 0; i < str.length; ++i) { - result = 31 * result + str.charCodeAt(i); - // Normalize to 4 byte range, 0 ... 2^32. - result %= goog.string.HASHCODE_MAX_; - } - return result; +goog.labs.userAgent.util.setUserAgent = function(opt_userAgent) { + goog.labs.userAgent.util.userAgent_ = opt_userAgent || + goog.labs.userAgent.util.getNativeUserAgentString_(); }; /** - * The most recent unique ID. |0 is equivalent to Math.floor in this case. - * @type {number} - * @private + * @return {string} The user agent string. */ -goog.string.uniqueStringCounter_ = Math.random() * 0x80000000 | 0; +goog.labs.userAgent.util.getUserAgent = function() { + return goog.labs.userAgent.util.userAgent_; +}; /** - * Generates and returns a string which is unique in the current document. - * This is useful, for example, to create unique IDs for DOM elements. - * @return {string} A unique id. + * @param {string} str + * @return {boolean} Whether the user agent contains the given string, ignoring + * case. */ -goog.string.createUniqueString = function() { - return 'goog_' + goog.string.uniqueStringCounter_++; +goog.labs.userAgent.util.matchUserAgent = function(str) { + var userAgent = goog.labs.userAgent.util.getUserAgent(); + return goog.string.contains(userAgent, str); }; /** - * Converts the supplied string to a number, which may be Infinity or NaN. - * This function strips whitespace: (toNumber(' 123') === 123) - * This function accepts scientific notation: (toNumber('1e1') === 10) - * - * This is better than Javascript's built-in conversions because, sadly: - * (Number(' ') === 0) and (parseFloat('123a') === 123) - * - * @param {string} str The string to convert. - * @return {number} The number the supplied string represents, or NaN. + * @param {string} str + * @return {boolean} Whether the user agent contains the given string. */ -goog.string.toNumber = function(str) { - var num = Number(str); - if (num == 0 && goog.string.isEmptyOrWhitespace(str)) { - return NaN; - } - return num; +goog.labs.userAgent.util.matchUserAgentIgnoreCase = function(str) { + var userAgent = goog.labs.userAgent.util.getUserAgent(); + return goog.string.caseInsensitiveContains(userAgent, str); }; /** - * Returns whether the given string is lower camel case (e.g. "isFooBar"). - * - * Note that this assumes the string is entirely letters. - * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms - * - * @param {string} str String to test. - * @return {boolean} Whether the string is lower camel case. + * Parses the user agent into tuples for each section. + * @param {string} userAgent + * @return {!Array<!Array<string>>} Tuples of key, version, and the contents + * of the parenthetical. */ -goog.string.isLowerCamelCase = function(str) { - return /^[a-z]+([A-Z][a-z]*)*$/.test(str); +goog.labs.userAgent.util.extractVersionTuples = function(userAgent) { + // Matches each section of a user agent string. + // Example UA: + // Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) + // AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405 + // This has three version tuples: Mozilla, AppleWebKit, and Mobile. + + var versionRegExp = new RegExp( + // Key. Note that a key may have a space. + // (i.e. 'Mobile Safari' in 'Mobile Safari/5.0') + '(\\w[\\w ]+)' + + + '/' + // slash + '([^\\s]+)' + // version (i.e. '5.0b') + '\\s*' + // whitespace + '(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched. + 'g'); + + var data = []; + var match; + + // Iterate and collect the version tuples. Each iteration will be the + // next regex match. + while (match = versionRegExp.exec(userAgent)) { + data.push([ + match[1], // key + match[2], // value + // || undefined as this is not undefined in IE7 and IE8 + match[3] || undefined // info + ]); + } + + return data; }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /** - * Returns whether the given string is upper camel case (e.g. "FooBarBaz"). - * - * Note that this assumes the string is entirely letters. - * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms + * @fileoverview Closure user agent detection (Browser). + * @see <a href="http://www.useragentstring.com/">User agent strings</a> + * For more information on rendering engine, platform, or device see the other + * sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform, + * goog.labs.userAgent.device respectively.) * - * @param {string} str String to test. - * @return {boolean} Whether the string is upper camel case. + * @author martone@google.com (Andy Martone) */ -goog.string.isUpperCamelCase = function(str) { - return /^([A-Z][a-z]*)+$/.test(str); -}; + +goog.provide('goog.labs.userAgent.browser'); + +goog.require('goog.array'); +goog.require('goog.labs.userAgent.util'); +goog.require('goog.object'); +goog.require('goog.string'); + + +// TODO(nnaze): Refactor to remove excessive exclusion logic in matching +// functions. /** - * Converts a string from selector-case to camelCase (e.g. from - * "multi-part-string" to "multiPartString"), useful for converting - * CSS selectors and HTML dataset keys to their equivalent JS properties. - * @param {string} str The string in selector-case form. - * @return {string} The string in camelCase form. + * @return {boolean} Whether the user's browser is Opera. + * @private */ -goog.string.toCamelCase = function(str) { - return String(str).replace(/\-([a-z])/g, function(all, match) { - return match.toUpperCase(); - }); +goog.labs.userAgent.browser.matchOpera_ = function() { + return goog.labs.userAgent.util.matchUserAgent('Opera') || + goog.labs.userAgent.util.matchUserAgent('OPR'); }; /** - * Converts a string from camelCase to selector-case (e.g. from - * "multiPartString" to "multi-part-string"), useful for converting JS - * style and dataset properties to equivalent CSS selectors and HTML keys. - * @param {string} str The string in camelCase form. - * @return {string} The string in selector-case form. + * @return {boolean} Whether the user's browser is IE. + * @private */ -goog.string.toSelectorCase = function(str) { - return String(str).replace(/([A-Z])/g, '-$1').toLowerCase(); +goog.labs.userAgent.browser.matchIE_ = function() { + return goog.labs.userAgent.util.matchUserAgent('Trident') || + goog.labs.userAgent.util.matchUserAgent('MSIE'); }; /** - * Converts a string into TitleCase. First character of the string is always - * capitalized in addition to the first letter of every subsequent word. - * Words are delimited by one or more whitespaces by default. Custom delimiters - * can optionally be specified to replace the default, which doesn't preserve - * whitespace delimiters and instead must be explicitly included if needed. - * - * Default delimiter => " ": - * goog.string.toTitleCase('oneTwoThree') => 'OneTwoThree' - * goog.string.toTitleCase('one two three') => 'One Two Three' - * goog.string.toTitleCase(' one two ') => ' One Two ' - * goog.string.toTitleCase('one_two_three') => 'One_two_three' - * goog.string.toTitleCase('one-two-three') => 'One-two-three' - * - * Custom delimiter => "_-.": - * goog.string.toTitleCase('oneTwoThree', '_-.') => 'OneTwoThree' - * goog.string.toTitleCase('one two three', '_-.') => 'One two three' - * goog.string.toTitleCase(' one two ', '_-.') => ' one two ' - * goog.string.toTitleCase('one_two_three', '_-.') => 'One_Two_Three' - * goog.string.toTitleCase('one-two-three', '_-.') => 'One-Two-Three' - * goog.string.toTitleCase('one...two...three', '_-.') => 'One...Two...Three' - * goog.string.toTitleCase('one. two. three', '_-.') => 'One. two. three' - * goog.string.toTitleCase('one-two.three', '_-.') => 'One-Two.Three' - * - * @param {string} str String value in camelCase form. - * @param {string=} opt_delimiters Custom delimiter character set used to - * distinguish words in the string value. Each character represents a - * single delimiter. When provided, default whitespace delimiter is - * overridden and must be explicitly included if needed. - * @return {string} String value in TitleCase form. + * @return {boolean} Whether the user's browser is Edge. + * @private */ -goog.string.toTitleCase = function(str, opt_delimiters) { - var delimiters = goog.isString(opt_delimiters) ? - goog.string.regExpEscape(opt_delimiters) : '\\s'; - - // For IE8, we need to prevent using an empty character set. Otherwise, - // incorrect matching will occur. - delimiters = delimiters ? '|[' + delimiters + ']+' : ''; - - var regexp = new RegExp('(^' + delimiters + ')([a-z])', 'g'); - return str.replace(regexp, function(all, p1, p2) { - return p1 + p2.toUpperCase(); - }); +goog.labs.userAgent.browser.matchEdge_ = function() { + return goog.labs.userAgent.util.matchUserAgent('Edge'); }; /** - * Capitalizes a string, i.e. converts the first letter to uppercase - * and all other letters to lowercase, e.g.: - * - * goog.string.capitalize('one') => 'One' - * goog.string.capitalize('ONE') => 'One' - * goog.string.capitalize('one two') => 'One two' - * - * Note that this function does not trim initial whitespace. - * - * @param {string} str String value to capitalize. - * @return {string} String value with first letter in uppercase. + * @return {boolean} Whether the user's browser is Firefox. + * @private */ -goog.string.capitalize = function(str) { - return String(str.charAt(0)).toUpperCase() + - String(str.substr(1)).toLowerCase(); +goog.labs.userAgent.browser.matchFirefox_ = function() { + return goog.labs.userAgent.util.matchUserAgent('Firefox'); }; /** - * Parse a string in decimal or hexidecimal ('0xFFFF') form. - * - * To parse a particular radix, please use parseInt(string, radix) directly. See - * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt - * - * This is a wrapper for the built-in parseInt function that will only parse - * numbers as base 10 or base 16. Some JS implementations assume strings - * starting with "0" are intended to be octal. ES3 allowed but discouraged - * this behavior. ES5 forbids it. This function emulates the ES5 behavior. - * - * For more information, see Mozilla JS Reference: http://goo.gl/8RiFj - * - * @param {string|number|null|undefined} value The value to be parsed. - * @return {number} The number, parsed. If the string failed to parse, this - * will be NaN. + * @return {boolean} Whether the user's browser is Safari. + * @private */ -goog.string.parseInt = function(value) { - // Force finite numbers to strings. - if (isFinite(value)) { - value = String(value); - } - - if (goog.isString(value)) { - // If the string starts with '0x' or '-0x', parse as hex. - return /^\s*-?0x/i.test(value) ? - parseInt(value, 16) : parseInt(value, 10); - } - - return NaN; +goog.labs.userAgent.browser.matchSafari_ = function() { + return goog.labs.userAgent.util.matchUserAgent('Safari') && + !(goog.labs.userAgent.browser.matchChrome_() || + goog.labs.userAgent.browser.matchCoast_() || + goog.labs.userAgent.browser.matchOpera_() || + goog.labs.userAgent.browser.matchEdge_() || + goog.labs.userAgent.browser.isSilk() || + goog.labs.userAgent.util.matchUserAgent('Android')); }; /** - * Splits a string on a separator a limited number of times. - * - * This implementation is more similar to Python or Java, where the limit - * parameter specifies the maximum number of splits rather than truncating - * the number of results. - * - * See http://docs.python.org/2/library/stdtypes.html#str.split - * See JavaDoc: http://goo.gl/F2AsY - * See Mozilla reference: http://goo.gl/dZdZs - * - * @param {string} str String to split. - * @param {string} separator The separator. - * @param {number} limit The limit to the number of splits. The resulting array - * will have a maximum length of limit+1. Negative numbers are the same - * as zero. - * @return {!Array<string>} The string, split. + * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based + * iOS browser). + * @private */ - -goog.string.splitLimit = function(str, separator, limit) { - var parts = str.split(separator); - var returnVal = []; - - // Only continue doing this while we haven't hit the limit and we have - // parts left. - while (limit > 0 && parts.length) { - returnVal.push(parts.shift()); - limit--; - } - - // If there are remaining parts, append them to the end. - if (parts.length) { - returnVal.push(parts.join(separator)); - } - - return returnVal; +goog.labs.userAgent.browser.matchCoast_ = function() { + return goog.labs.userAgent.util.matchUserAgent('Coast'); }; /** - * Computes the Levenshtein edit distance between two strings. - * @param {string} a - * @param {string} b - * @return {number} The edit distance between the two strings. + * @return {boolean} Whether the user's browser is iOS Webview. + * @private */ -goog.string.editDistance = function(a, b) { - var v0 = []; - var v1 = []; - - if (a == b) { - return 0; - } - - if (!a.length || !b.length) { - return Math.max(a.length, b.length); - } - - for (var i = 0; i < b.length + 1; i++) { - v0[i] = i; - } - - for (var i = 0; i < a.length; i++) { - v1[0] = i + 1; - - for (var j = 0; j < b.length; j++) { - var cost = a[i] != b[j]; - // Cost for the substring is the minimum of adding one character, removing - // one character, or a swap. - v1[j + 1] = Math.min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost); - } - - for (var j = 0; j < v0.length; j++) { - v0[j] = v1[j]; - } - } - - return v1[b.length]; +goog.labs.userAgent.browser.matchIosWebview_ = function() { + // iOS Webview does not show up as Chrome or Safari. Also check for Opera's + // WebKit-based iOS browser, Coast. + return (goog.labs.userAgent.util.matchUserAgent('iPad') || + goog.labs.userAgent.util.matchUserAgent('iPhone')) && + !goog.labs.userAgent.browser.matchSafari_() && + !goog.labs.userAgent.browser.matchChrome_() && + !goog.labs.userAgent.browser.matchCoast_() && + goog.labs.userAgent.util.matchUserAgent('AppleWebKit'); }; -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utilities to check the preconditions, postconditions and - * invariants runtime. - * - * Methods in this package should be given special treatment by the compiler - * for type-inference. For example, <code>goog.asserts.assert(foo)</code> - * will restrict <code>foo</code> to a truthy value. - * - * The compiler has an option to disable asserts. So code like: - * <code> - * var x = goog.asserts.assert(foo()); goog.asserts.assert(bar()); - * </code> - * will be transformed into: - * <code> - * var x = foo(); - * </code> - * The compiler will leave in foo() (because its return value is used), - * but it will remove bar() because it assumes it does not have side-effects. - * - * @author agrieve@google.com (Andrew Grieve) + * @return {boolean} Whether the user's browser is Chrome. + * @private */ +goog.labs.userAgent.browser.matchChrome_ = function() { + return (goog.labs.userAgent.util.matchUserAgent('Chrome') || + goog.labs.userAgent.util.matchUserAgent('CriOS')) && + !goog.labs.userAgent.browser.matchOpera_() && + !goog.labs.userAgent.browser.matchEdge_(); +}; -goog.provide('goog.asserts'); -goog.provide('goog.asserts.AssertionError'); -goog.require('goog.debug.Error'); -goog.require('goog.dom.NodeType'); -goog.require('goog.string'); +/** + * @return {boolean} Whether the user's browser is the Android browser. + * @private + */ +goog.labs.userAgent.browser.matchAndroidBrowser_ = function() { + // Android can appear in the user agent string for Chrome on Android. + // This is not the Android standalone browser if it does. + return goog.labs.userAgent.util.matchUserAgent('Android') && + !(goog.labs.userAgent.browser.isChrome() || + goog.labs.userAgent.browser.isFirefox() || + goog.labs.userAgent.browser.isOpera() || + goog.labs.userAgent.browser.isSilk()); +}; /** - * @define {boolean} Whether to strip out asserts or to leave them in. + * @return {boolean} Whether the user's browser is Opera. */ -goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG); - +goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_; /** - * Error object for failed assertions. - * @param {string} messagePattern The pattern that was used to form message. - * @param {!Array<*>} messageArgs The items to substitute into the pattern. - * @constructor - * @extends {goog.debug.Error} - * @final + * @return {boolean} Whether the user's browser is IE. */ -goog.asserts.AssertionError = function(messagePattern, messageArgs) { - messageArgs.unshift(messagePattern); - goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs)); - // Remove the messagePattern afterwards to avoid permanently modifying the - // passed in array. - messageArgs.shift(); - - /** - * The message pattern used to format the error message. Error handlers can - * use this to uniquely identify the assertion. - * @type {string} - */ - this.messagePattern = messagePattern; -}; -goog.inherits(goog.asserts.AssertionError, goog.debug.Error); +goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_; -/** @override */ -goog.asserts.AssertionError.prototype.name = 'AssertionError'; +/** + * @return {boolean} Whether the user's browser is Edge. + */ +goog.labs.userAgent.browser.isEdge = goog.labs.userAgent.browser.matchEdge_; /** - * The default error handler. - * @param {!goog.asserts.AssertionError} e The exception to be handled. + * @return {boolean} Whether the user's browser is Firefox. */ -goog.asserts.DEFAULT_ERROR_HANDLER = function(e) { throw e; }; +goog.labs.userAgent.browser.isFirefox = + goog.labs.userAgent.browser.matchFirefox_; /** - * The handler responsible for throwing or logging assertion errors. - * @private {function(!goog.asserts.AssertionError)} + * @return {boolean} Whether the user's browser is Safari. */ -goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER; +goog.labs.userAgent.browser.isSafari = + goog.labs.userAgent.browser.matchSafari_; /** - * Throws an exception with the given message and "Assertion failed" prefixed - * onto it. - * @param {string} defaultMessage The message to use if givenMessage is empty. - * @param {Array<*>} defaultArgs The substitution arguments for defaultMessage. - * @param {string|undefined} givenMessage Message supplied by the caller. - * @param {Array<*>} givenArgs The substitution arguments for givenMessage. - * @throws {goog.asserts.AssertionError} When the value is not a number. - * @private + * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based + * iOS browser). */ -goog.asserts.doAssertFailure_ = - function(defaultMessage, defaultArgs, givenMessage, givenArgs) { - var message = 'Assertion failed'; - if (givenMessage) { - message += ': ' + givenMessage; - var args = givenArgs; - } else if (defaultMessage) { - message += ': ' + defaultMessage; - args = defaultArgs; - } - // The '' + works around an Opera 10 bug in the unit tests. Without it, - // a stack trace is added to var message above. With this, a stack trace is - // not added until this line (it causes the extra garbage to be added after - // the assertion message instead of in the middle of it). - var e = new goog.asserts.AssertionError('' + message, args || []); - goog.asserts.errorHandler_(e); -}; +goog.labs.userAgent.browser.isCoast = + goog.labs.userAgent.browser.matchCoast_; /** - * Sets a custom error handler that can be used to customize the behavior of - * assertion failures, for example by turning all assertion failures into log - * messages. - * @param {function(!goog.asserts.AssertionError)} errorHandler + * @return {boolean} Whether the user's browser is iOS Webview. */ -goog.asserts.setErrorHandler = function(errorHandler) { - if (goog.asserts.ENABLE_ASSERTS) { - goog.asserts.errorHandler_ = errorHandler; - } -}; +goog.labs.userAgent.browser.isIosWebview = + goog.labs.userAgent.browser.matchIosWebview_; /** - * Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is - * true. - * @template T - * @param {T} condition The condition to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {T} The value of the condition. - * @throws {goog.asserts.AssertionError} When the condition evaluates to false. + * @return {boolean} Whether the user's browser is Chrome. */ -goog.asserts.assert = function(condition, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !condition) { - goog.asserts.doAssertFailure_('', null, opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return condition; -}; +goog.labs.userAgent.browser.isChrome = + goog.labs.userAgent.browser.matchChrome_; /** - * Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case - * when we want to add a check in the unreachable area like switch-case - * statement: - * - * <pre> - * switch(type) { - * case FOO: doSomething(); break; - * case BAR: doSomethingElse(); break; - * default: goog.assert.fail('Unrecognized type: ' + type); - * // We have only 2 types - "default:" section is unreachable code. - * } - * </pre> - * - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @throws {goog.asserts.AssertionError} Failure. + * @return {boolean} Whether the user's browser is the Android browser. */ -goog.asserts.fail = function(opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS) { - goog.asserts.errorHandler_(new goog.asserts.AssertionError( - 'Failure' + (opt_message ? ': ' + opt_message : ''), - Array.prototype.slice.call(arguments, 1))); - } -}; +goog.labs.userAgent.browser.isAndroidBrowser = + goog.labs.userAgent.browser.matchAndroidBrowser_; /** - * Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {number} The value, guaranteed to be a number when asserts enabled. - * @throws {goog.asserts.AssertionError} When the value is not a number. + * For more information, see: + * http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html + * @return {boolean} Whether the user's browser is Silk. */ -goog.asserts.assertNumber = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isNumber(value)) { - goog.asserts.doAssertFailure_('Expected number but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {number} */ (value); +goog.labs.userAgent.browser.isSilk = function() { + return goog.labs.userAgent.util.matchUserAgent('Silk'); }; /** - * Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {string} The value, guaranteed to be a string when asserts enabled. - * @throws {goog.asserts.AssertionError} When the value is not a string. + * @return {string} The browser version or empty string if version cannot be + * determined. Note that for Internet Explorer, this returns the version of + * the browser, not the version of the rendering engine. (IE 8 in + * compatibility mode will return 8.0 rather than 7.0. To determine the + * rendering engine version, look at document.documentMode instead. See + * http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more + * details.) */ -goog.asserts.assertString = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isString(value)) { - goog.asserts.doAssertFailure_('Expected string but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); +goog.labs.userAgent.browser.getVersion = function() { + var userAgentString = goog.labs.userAgent.util.getUserAgent(); + // Special case IE since IE's version is inside the parenthesis and + // without the '/'. + if (goog.labs.userAgent.browser.isIE()) { + return goog.labs.userAgent.browser.getIEVersion_(userAgentString); } - return /** @type {string} */ (value); -}; + var versionTuples = goog.labs.userAgent.util.extractVersionTuples( + userAgentString); -/** - * Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Function} The value, guaranteed to be a function when asserts - * enabled. - * @throws {goog.asserts.AssertionError} When the value is not a function. - */ -goog.asserts.assertFunction = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isFunction(value)) { - goog.asserts.doAssertFailure_('Expected function but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {!Function} */ (value); -}; + // Construct a map for easy lookup. + var versionMap = {}; + goog.array.forEach(versionTuples, function(tuple) { + // Note that the tuple is of length three, but we only care about the + // first two. + var key = tuple[0]; + var value = tuple[1]; + versionMap[key] = value; + }); + var versionMapHasKey = goog.partial(goog.object.containsKey, versionMap); -/** - * Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Object} The value, guaranteed to be a non-null object. - * @throws {goog.asserts.AssertionError} When the value is not an object. - */ -goog.asserts.assertObject = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) { - goog.asserts.doAssertFailure_('Expected object but got %s: %s.', - [goog.typeOf(value), value], - opt_message, Array.prototype.slice.call(arguments, 2)); + // Gives the value with the first key it finds, otherwise empty string. + function lookUpValueWithKeys(keys) { + var key = goog.array.find(keys, versionMapHasKey); + return versionMap[key] || ''; } - return /** @type {!Object} */ (value); -}; - -/** - * Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Array<?>} The value, guaranteed to be a non-null array. - * @throws {goog.asserts.AssertionError} When the value is not an array. - */ -goog.asserts.assertArray = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isArray(value)) { - goog.asserts.doAssertFailure_('Expected array but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); + // Check Opera before Chrome since Opera 15+ has "Chrome" in the string. + // See + // http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond + if (goog.labs.userAgent.browser.isOpera()) { + // Opera 10 has Version/10.0 but Opera/9.8, so look for "Version" first. + // Opera uses 'OPR' for more recent UAs. + return lookUpValueWithKeys(['Version', 'Opera', 'OPR']); } - return /** @type {!Array<?>} */ (value); -}; + // Check Edge before Chrome since it has Chrome in the string. + if (goog.labs.userAgent.browser.isEdge()) { + return lookUpValueWithKeys(['Edge']); + } -/** - * Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {boolean} The value, guaranteed to be a boolean when asserts are - * enabled. - * @throws {goog.asserts.AssertionError} When the value is not a boolean. - */ -goog.asserts.assertBoolean = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !goog.isBoolean(value)) { - goog.asserts.doAssertFailure_('Expected boolean but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); + if (goog.labs.userAgent.browser.isChrome()) { + return lookUpValueWithKeys(['Chrome', 'CriOS']); } - return /** @type {boolean} */ (value); + + // Usually products browser versions are in the third tuple after "Mozilla" + // and the engine. + var tuple = versionTuples[2]; + return tuple && tuple[1] || ''; }; /** - * Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true. - * @param {*} value The value to check. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @return {!Element} The value, likely to be a DOM Element when asserts are - * enabled. - * @throws {goog.asserts.AssertionError} When the value is not an Element. + * @param {string|number} version The version to check. + * @return {boolean} Whether the browser version is higher or the same as the + * given version. */ -goog.asserts.assertElement = function(value, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && (!goog.isObject(value) || - value.nodeType != goog.dom.NodeType.ELEMENT)) { - goog.asserts.doAssertFailure_('Expected Element but got %s: %s.', - [goog.typeOf(value), value], opt_message, - Array.prototype.slice.call(arguments, 2)); - } - return /** @type {!Element} */ (value); +goog.labs.userAgent.browser.isVersionOrHigher = function(version) { + return goog.string.compareVersions(goog.labs.userAgent.browser.getVersion(), + version) >= 0; }; /** - * Checks if the value is an instance of the user-defined type if - * goog.asserts.ENABLE_ASSERTS is true. - * - * The compiler may tighten the type returned by this function. + * Determines IE version. More information: + * http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString + * http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx + * http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx + * http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx * - * @param {*} value The value to check. - * @param {function(new: T, ...)} type A user-defined constructor. - * @param {string=} opt_message Error message in case of failure. - * @param {...*} var_args The items to substitute into the failure message. - * @throws {goog.asserts.AssertionError} When the value is not an instance of - * type. - * @return {T} - * @template T + * @param {string} userAgent the User-Agent. + * @return {string} + * @private */ -goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) { - if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) { - goog.asserts.doAssertFailure_('Expected instanceof %s but got %s.', - [goog.asserts.getType_(type), goog.asserts.getType_(value)], - opt_message, Array.prototype.slice.call(arguments, 3)); +goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) { + // IE11 may identify itself as MSIE 9.0 or MSIE 10.0 due to an IE 11 upgrade + // bug. Example UA: + // Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) + // like Gecko. + // See http://www.whatismybrowser.com/developers/unknown-user-agent-fragments. + var rv = /rv: *([\d\.]*)/.exec(userAgent); + if (rv && rv[1]) { + return rv[1]; } - return value; -}; - -/** - * Checks that no enumerable keys are present in Object.prototype. Such keys - * would break most code that use {@code for (var ... in ...)} loops. - */ -goog.asserts.assertObjectPrototypeIsIntact = function() { - for (var key in Object.prototype) { - goog.asserts.fail(key + ' should not be enumerable in Object.prototype.'); + var version = ''; + var msie = /MSIE +([\d\.]+)/.exec(userAgent); + if (msie && msie[1]) { + // IE in compatibility mode usually identifies itself as MSIE 7.0; in this + // case, use the Trident version to determine the version of IE. For more + // details, see the links above. + var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent); + if (msie[1] == '7.0') { + if (tridentVersion && tridentVersion[1]) { + switch (tridentVersion[1]) { + case '4.0': + version = '8.0'; + break; + case '5.0': + version = '9.0'; + break; + case '6.0': + version = '10.0'; + break; + case '7.0': + version = '11.0'; + break; + } + } else { + version = '7.0'; + } + } else { + version = msie[1]; + } } + return version; }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Returns the type of a value. If a constructor is passed, and a suitable - * string cannot be found, 'unknown type name' will be returned. - * @param {*} value A constructor, object, or primitive. - * @return {string} The best display name for the value, or 'unknown type name'. - * @private + * @fileoverview Closure user agent detection. + * @see http://en.wikipedia.org/wiki/User_agent + * For more information on browser brand, platform, or device see the other + * sub-namespaces in goog.labs.userAgent (browser, platform, and device). + * */ -goog.asserts.getType_ = function(value) { - if (value instanceof Function) { - return value.displayName || value.name || 'unknown type name'; - } else if (value instanceof Object) { - return value.constructor.displayName || value.constructor.name || - Object.prototype.toString.call(value); - } else { - return value === null ? 'null' : typeof value; - } -}; -goog.provide('ol.math'); +goog.provide('goog.labs.userAgent.engine'); -goog.require('goog.asserts'); +goog.require('goog.array'); +goog.require('goog.labs.userAgent.util'); +goog.require('goog.string'); /** - * Takes a number and clamps it to within the provided bounds. - * @param {number} value The input number. - * @param {number} min The minimum value to return. - * @param {number} max The maximum value to return. - * @return {number} The input number if it is within bounds, or the nearest - * number within the bounds. + * @return {boolean} Whether the rendering engine is Presto. */ -ol.math.clamp = function(value, min, max) { - return Math.min(Math.max(value, min), max); +goog.labs.userAgent.engine.isPresto = function() { + return goog.labs.userAgent.util.matchUserAgent('Presto'); }; /** - * Return the hyperbolic cosine of a given number. The method will use the - * native `Math.cosh` function if it is available, otherwise the hyperbolic - * cosine will be calculated via the reference implementation of the Mozilla - * developer network. - * - * @param {number} x X. - * @return {number} Hyperbolic cosine of x. + * @return {boolean} Whether the rendering engine is Trident. */ -ol.math.cosh = (function() { - // Wrapped in a iife, to save the overhead of checking for the native - // implementation on every invocation. - var cosh; - if ('cosh' in Math) { - // The environment supports the native Math.cosh function, use it… - cosh = Math.cosh; - } else { - // … else, use the reference implementation of MDN: - cosh = function(x) { - var y = Math.exp(x); - return (y + 1 / y) / 2; - }; - } - return cosh; -}()); +goog.labs.userAgent.engine.isTrident = function() { + // IE only started including the Trident token in IE8. + return goog.labs.userAgent.util.matchUserAgent('Trident') || + goog.labs.userAgent.util.matchUserAgent('MSIE'); +}; /** - * @param {number} x X. - * @return {number} The smallest power of two greater than or equal to x. + * @return {boolean} Whether the rendering engine is Edge. */ -ol.math.roundUpToPowerOfTwo = function(x) { - goog.asserts.assert(0 < x, 'x should be larger than 0'); - return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2)); +goog.labs.userAgent.engine.isEdge = function() { + return goog.labs.userAgent.util.matchUserAgent('Edge'); }; /** - * Returns the square of the closest distance between the point (x, y) and the - * line segment (x1, y1) to (x2, y2). - * @param {number} x X. - * @param {number} y Y. - * @param {number} x1 X1. - * @param {number} y1 Y1. - * @param {number} x2 X2. - * @param {number} y2 Y2. - * @return {number} Squared distance. + * @return {boolean} Whether the rendering engine is WebKit. */ -ol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) { - var dx = x2 - x1; - var dy = y2 - y1; - if (dx !== 0 || dy !== 0) { - var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); - if (t > 1) { - x1 = x2; - y1 = y2; - } else if (t > 0) { - x1 += dx * t; - y1 += dy * t; - } - } - return ol.math.squaredDistance(x, y, x1, y1); +goog.labs.userAgent.engine.isWebKit = function() { + return goog.labs.userAgent.util.matchUserAgentIgnoreCase('WebKit') && + !goog.labs.userAgent.engine.isEdge(); }; /** - * Returns the square of the distance between the points (x1, y1) and (x2, y2). - * @param {number} x1 X1. - * @param {number} y1 Y1. - * @param {number} x2 X2. - * @param {number} y2 Y2. - * @return {number} Squared distance. + * @return {boolean} Whether the rendering engine is Gecko. */ -ol.math.squaredDistance = function(x1, y1, x2, y2) { - var dx = x2 - x1; - var dy = y2 - y1; - return dx * dx + dy * dy; +goog.labs.userAgent.engine.isGecko = function() { + return goog.labs.userAgent.util.matchUserAgent('Gecko') && + !goog.labs.userAgent.engine.isWebKit() && + !goog.labs.userAgent.engine.isTrident() && + !goog.labs.userAgent.engine.isEdge(); }; /** - * Solves system of linear equations using Gaussian elimination method. - * - * @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column) - * in row-major order. - * @return {Array.<number>} The resulting vector. + * @return {string} The rendering engine's version or empty string if version + * can't be determined. */ -ol.math.solveLinearSystem = function(mat) { - var n = mat.length; - - if (goog.asserts.ENABLE_ASSERTS) { - for (var row = 0; row < n; row++) { - goog.asserts.assert(mat[row].length == n + 1, - 'every row should have correct number of columns'); - } - } +goog.labs.userAgent.engine.getVersion = function() { + var userAgentString = goog.labs.userAgent.util.getUserAgent(); + if (userAgentString) { + var tuples = goog.labs.userAgent.util.extractVersionTuples( + userAgentString); - for (var i = 0; i < n; i++) { - // Find max in the i-th column (ignoring i - 1 first rows) - var maxRow = i; - var maxEl = Math.abs(mat[i][i]); - for (var r = i + 1; r < n; r++) { - var absValue = Math.abs(mat[r][i]); - if (absValue > maxEl) { - maxEl = absValue; - maxRow = r; + var engineTuple = goog.labs.userAgent.engine.getEngineTuple_(tuples); + if (engineTuple) { + // In Gecko, the version string is either in the browser info or the + // Firefox version. See Gecko user agent string reference: + // http://goo.gl/mULqa + if (engineTuple[0] == 'Gecko') { + return goog.labs.userAgent.engine.getVersionForKey_( + tuples, 'Firefox'); } - } - if (maxEl === 0) { - return null; // matrix is singular + return engineTuple[1]; } - // Swap max row with i-th (current) row - var tmp = mat[maxRow]; - mat[maxRow] = mat[i]; - mat[i] = tmp; - - // Subtract the i-th row to make all the remaining rows 0 in the i-th column - for (var j = i + 1; j < n; j++) { - var coef = -mat[j][i] / mat[i][i]; - for (var k = i; k < n + 1; k++) { - if (i == k) { - mat[j][k] = 0; - } else { - mat[j][k] += coef * mat[i][k]; - } + // MSIE has only one version identifier, and the Trident version is + // specified in the parenthetical. IE Edge is covered in the engine tuple + // detection. + var browserTuple = tuples[0]; + var info; + if (browserTuple && (info = browserTuple[2])) { + var match = /Trident\/([^\s;]+)/.exec(info); + if (match) { + return match[1]; } } } - - // Solve Ax=b for upper triangular matrix A (mat) - var x = new Array(n); - for (var l = n - 1; l >= 0; l--) { - x[l] = mat[l][n] / mat[l][l]; - for (var m = l - 1; m >= 0; m--) { - mat[m][n] -= mat[m][l] * x[l]; - } - } - return x; + return ''; }; /** - * Converts radians to to degrees. - * - * @param {number} angleInRadians Angle in radians. - * @return {number} Angle in degrees. + * @param {!Array<!Array<string>>} tuples Extracted version tuples. + * @return {!Array<string>|undefined} The engine tuple or undefined if not + * found. + * @private */ -ol.math.toDegrees = function(angleInRadians) { - return angleInRadians * 180 / Math.PI; +goog.labs.userAgent.engine.getEngineTuple_ = function(tuples) { + if (!goog.labs.userAgent.engine.isEdge()) { + return tuples[1]; + } + for (var i = 0; i < tuples.length; i++) { + var tuple = tuples[i]; + if (tuple[0] == 'Edge') { + return tuple; + } + } }; /** - * Converts degrees to radians. - * - * @param {number} angleInDegrees Angle in degrees. - * @return {number} Angle in radians. + * @param {string|number} version The version to check. + * @return {boolean} Whether the rendering engine version is higher or the same + * as the given version. */ -ol.math.toRadians = function(angleInDegrees) { - return angleInDegrees * Math.PI / 180; +goog.labs.userAgent.engine.isVersionOrHigher = function(version) { + return goog.string.compareVersions(goog.labs.userAgent.engine.getVersion(), + version) >= 0; }; -goog.provide('ol.CenterConstraint'); -goog.provide('ol.CenterConstraintType'); - -goog.require('ol.math'); - /** - * @typedef {function((ol.Coordinate|undefined)): (ol.Coordinate|undefined)} - */ -ol.CenterConstraintType; - - -/** - * @param {ol.Extent} extent Extent. - * @return {ol.CenterConstraintType} + * @param {!Array<!Array<string>>} tuples Version tuples. + * @param {string} key The key to look for. + * @return {string} The version string of the given key, if present. + * Otherwise, the empty string. + * @private */ -ol.CenterConstraint.createExtent = function(extent) { - return ( - /** - * @param {ol.Coordinate|undefined} center Center. - * @return {ol.Coordinate|undefined} Center. - */ - function(center) { - if (center) { - return [ - ol.math.clamp(center[0], extent[0], extent[2]), - ol.math.clamp(center[1], extent[1], extent[3]) - ]; - } else { - return undefined; - } - }); -}; +goog.labs.userAgent.engine.getVersionForKey_ = function(tuples, key) { + // TODO(nnaze): Move to util if useful elsewhere. + var pair = goog.array.find(tuples, function(pair) { + return key == pair[0]; + }); -/** - * @param {ol.Coordinate|undefined} center Center. - * @return {ol.Coordinate|undefined} Center. - */ -ol.CenterConstraint.none = function(center) { - return center; + return pair && pair[1] || ''; }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// Copyright 2013 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -7124,1966 +7725,1214 @@ ol.CenterConstraint.none = function(center) { // limitations under the License. /** - * @fileoverview Utilities for manipulating arrays. + * @fileoverview Closure user agent platform detection. + * @see <a href="http://www.useragentstring.com/">User agent strings</a> + * For more information on browser brand, rendering engine, or device see the + * other sub-namespaces in goog.labs.userAgent (browser, engine, and device + * respectively). * - * @author arv@google.com (Erik Arvidsson) */ +goog.provide('goog.labs.userAgent.platform'); -goog.provide('goog.array'); -goog.provide('goog.array.ArrayLike'); +goog.require('goog.labs.userAgent.util'); +goog.require('goog.string'); -goog.require('goog.asserts'); + +/** + * @return {boolean} Whether the platform is Android. + */ +goog.labs.userAgent.platform.isAndroid = function() { + return goog.labs.userAgent.util.matchUserAgent('Android'); +}; /** - * @define {boolean} NATIVE_ARRAY_PROTOTYPES indicates whether the code should - * rely on Array.prototype functions, if available. - * - * The Array.prototype functions can be defined by external libraries like - * Prototype and setting this flag to false forces closure to use its own - * goog.array implementation. - * - * If your javascript can be loaded by a third party site and you are wary about - * relying on the prototype functions, specify - * "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler. - * - * Setting goog.TRUSTED_SITE to false will automatically set - * NATIVE_ARRAY_PROTOTYPES to false. + * @return {boolean} Whether the platform is iPod. */ -goog.define('goog.NATIVE_ARRAY_PROTOTYPES', goog.TRUSTED_SITE); +goog.labs.userAgent.platform.isIpod = function() { + return goog.labs.userAgent.util.matchUserAgent('iPod'); +}; /** - * @define {boolean} If true, JSCompiler will use the native implementation of - * array functions where appropriate (e.g., {@code Array#filter}) and remove the - * unused pure JS implementation. + * @return {boolean} Whether the platform is iPhone. */ -goog.define('goog.array.ASSUME_NATIVE_FUNCTIONS', false); +goog.labs.userAgent.platform.isIphone = function() { + return goog.labs.userAgent.util.matchUserAgent('iPhone') && + !goog.labs.userAgent.util.matchUserAgent('iPod') && + !goog.labs.userAgent.util.matchUserAgent('iPad'); +}; /** - * @typedef {Array|NodeList|Arguments|{length: number}} + * @return {boolean} Whether the platform is iPad. */ -goog.array.ArrayLike; +goog.labs.userAgent.platform.isIpad = function() { + return goog.labs.userAgent.util.matchUserAgent('iPad'); +}; /** - * Returns the last element in an array without removing it. - * Same as goog.array.last. - * @param {Array<T>|goog.array.ArrayLike} array The array. - * @return {T} Last item in array. - * @template T + * @return {boolean} Whether the platform is iOS. */ -goog.array.peek = function(array) { - return array[array.length - 1]; +goog.labs.userAgent.platform.isIos = function() { + return goog.labs.userAgent.platform.isIphone() || + goog.labs.userAgent.platform.isIpad() || + goog.labs.userAgent.platform.isIpod(); }; /** - * Returns the last element in an array without removing it. - * Same as goog.array.peek. - * @param {Array<T>|goog.array.ArrayLike} array The array. - * @return {T} Last item in array. - * @template T + * @return {boolean} Whether the platform is Mac. */ -goog.array.last = goog.array.peek; +goog.labs.userAgent.platform.isMacintosh = function() { + return goog.labs.userAgent.util.matchUserAgent('Macintosh'); +}; /** - * Reference to the original {@code Array.prototype}. - * @private + * Note: ChromeOS is not considered to be Linux as it does not report itself + * as Linux in the user agent string. + * @return {boolean} Whether the platform is Linux. */ -goog.array.ARRAY_PROTOTYPE_ = Array.prototype; +goog.labs.userAgent.platform.isLinux = function() { + return goog.labs.userAgent.util.matchUserAgent('Linux'); +}; -// NOTE(arv): Since most of the array functions are generic it allows you to -// pass an array-like object. Strings have a length and are considered array- -// like. However, the 'in' operator does not work on strings so we cannot just -// use the array path even if the browser supports indexing into strings. We -// therefore end up splitting the string. +/** + * @return {boolean} Whether the platform is Windows. + */ +goog.labs.userAgent.platform.isWindows = function() { + return goog.labs.userAgent.util.matchUserAgent('Windows'); +}; /** - * Returns the index of the first element of an array with a specified value, or - * -1 if the element is not present in the array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-indexof} - * - * @param {Array<T>|goog.array.ArrayLike} arr The array to be searched. - * @param {T} obj The object for which we are searching. - * @param {number=} opt_fromIndex The index at which to start the search. If - * omitted the search starts at index 0. - * @return {number} The index of the first matching array element. - * @template T + * @return {boolean} Whether the platform is ChromeOS. */ -goog.array.indexOf = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.indexOf) ? - function(arr, obj, opt_fromIndex) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.indexOf.call(arr, obj, opt_fromIndex); - } : - function(arr, obj, opt_fromIndex) { - var fromIndex = opt_fromIndex == null ? - 0 : (opt_fromIndex < 0 ? - Math.max(0, arr.length + opt_fromIndex) : opt_fromIndex); +goog.labs.userAgent.platform.isChromeOS = function() { + return goog.labs.userAgent.util.matchUserAgent('CrOS'); +}; - if (goog.isString(arr)) { - // Array.prototype.indexOf uses === so only strings should be found. - if (!goog.isString(obj) || obj.length != 1) { - return -1; - } - return arr.indexOf(obj, fromIndex); - } - for (var i = fromIndex; i < arr.length; i++) { - if (i in arr && arr[i] === obj) - return i; - } - return -1; - }; +/** + * The version of the platform. We only determine the version for Windows, + * Mac, and Chrome OS. It doesn't make much sense on Linux. For Windows, we only + * look at the NT version. Non-NT-based versions (e.g. 95, 98, etc.) are given + * version 0.0. + * + * @return {string} The platform version or empty string if version cannot be + * determined. + */ +goog.labs.userAgent.platform.getVersion = function() { + var userAgentString = goog.labs.userAgent.util.getUserAgent(); + var version = '', re; + if (goog.labs.userAgent.platform.isWindows()) { + re = /Windows (?:NT|Phone) ([0-9.]+)/; + var match = re.exec(userAgentString); + if (match) { + version = match[1]; + } else { + version = '0.0'; + } + } else if (goog.labs.userAgent.platform.isIos()) { + re = /(?:iPhone|iPod|iPad|CPU)\s+OS\s+(\S+)/; + var match = re.exec(userAgentString); + // Report the version as x.y.z and not x_y_z + version = match && match[1].replace(/_/g, '.'); + } else if (goog.labs.userAgent.platform.isMacintosh()) { + re = /Mac OS X ([0-9_.]+)/; + var match = re.exec(userAgentString); + // Note: some old versions of Camino do not report an OSX version. + // Default to 10. + version = match ? match[1].replace(/_/g, '.') : '10'; + } else if (goog.labs.userAgent.platform.isAndroid()) { + re = /Android\s+([^\);]+)(\)|;)/; + var match = re.exec(userAgentString); + version = match && match[1]; + } else if (goog.labs.userAgent.platform.isChromeOS()) { + re = /(?:CrOS\s+(?:i686|x86_64)\s+([0-9.]+))/; + var match = re.exec(userAgentString); + version = match && match[1]; + } + return version || ''; +}; /** - * Returns the index of the last element of an array with a specified value, or - * -1 if the element is not present in the array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-lastindexof} - * - * @param {!Array<T>|!goog.array.ArrayLike} arr The array to be searched. - * @param {T} obj The object for which we are searching. - * @param {?number=} opt_fromIndex The index at which to start the search. If - * omitted the search starts at the end of the array. - * @return {number} The index of the last matching array element. - * @template T + * @param {string|number} version The version to check. + * @return {boolean} Whether the browser version is higher or the same as the + * given version. */ -goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.lastIndexOf) ? - function(arr, obj, opt_fromIndex) { - goog.asserts.assert(arr.length != null); +goog.labs.userAgent.platform.isVersionOrHigher = function(version) { + return goog.string.compareVersions(goog.labs.userAgent.platform.getVersion(), + version) >= 0; +}; - // Firefox treats undefined and null as 0 in the fromIndex argument which - // leads it to always return -1 - var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex; - return goog.array.ARRAY_PROTOTYPE_.lastIndexOf.call(arr, obj, fromIndex); - } : - function(arr, obj, opt_fromIndex) { - var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - if (fromIndex < 0) { - fromIndex = Math.max(0, arr.length + fromIndex); - } +/** + * @fileoverview Rendering engine detection. + * @see <a href="http://www.useragentstring.com/">User agent strings</a> + * For information on the browser brand (such as Safari versus Chrome), see + * goog.userAgent.product. + * @author arv@google.com (Erik Arvidsson) + * @see ../demos/useragent.html + */ - if (goog.isString(arr)) { - // Array.prototype.lastIndexOf uses === so only strings should be found. - if (!goog.isString(obj) || obj.length != 1) { - return -1; - } - return arr.lastIndexOf(obj, fromIndex); - } +goog.provide('goog.userAgent'); - for (var i = fromIndex; i >= 0; i--) { - if (i in arr && arr[i] === obj) - return i; - } - return -1; - }; +goog.require('goog.labs.userAgent.browser'); +goog.require('goog.labs.userAgent.engine'); +goog.require('goog.labs.userAgent.platform'); +goog.require('goog.labs.userAgent.util'); +goog.require('goog.string'); /** - * Calls a function for each element in an array. Skips holes in the array. - * See {@link http://tinyurl.com/developer-mozilla-org-array-foreach} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over - * which to iterate. - * @param {?function(this: S, T, number, ?): ?} f The function to call for every - * element. This function takes 3 arguments (the element, the index and the - * array). The return value is ignored. - * @param {S=} opt_obj The object to be used as the value of 'this' within f. - * @template T,S + * @define {boolean} Whether we know at compile-time that the browser is IE. */ -goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.forEach) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - goog.array.ARRAY_PROTOTYPE_.forEach.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2) { - f.call(opt_obj, arr2[i], i, arr); - } - } - }; +goog.define('goog.userAgent.ASSUME_IE', false); /** - * Calls a function for each element in an array, starting from the last - * element rather than the first. - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this: S, T, number, ?): ?} f The function to call for every - * element. This function - * takes 3 arguments (the element, the index and the array). The return - * value is ignored. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @template T,S + * @define {boolean} Whether we know at compile-time that the browser is EDGE. */ -goog.array.forEachRight = function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = l - 1; i >= 0; --i) { - if (i in arr2) { - f.call(opt_obj, arr2[i], i, arr); - } - } -}; +goog.define('goog.userAgent.ASSUME_EDGE', false); /** - * Calls a function for each element in an array, and if the function returns - * true adds the element to a new array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-filter} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?):boolean} f The function to call for - * every element. This function - * takes 3 arguments (the element, the index and the array) and must - * return a Boolean. If the return value is true the element is added to the - * result array. If it is false the element is not included. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {!Array<T>} a new array in which only elements that passed the test - * are present. - * @template T,S + * @define {boolean} Whether we know at compile-time that the browser is GECKO. */ -goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.filter) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); +goog.define('goog.userAgent.ASSUME_GECKO', false); - return goog.array.ARRAY_PROTOTYPE_.filter.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var res = []; - var resLength = 0; - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2) { - var val = arr2[i]; // in case f mutates arr2 - if (f.call(opt_obj, val, i, arr)) { - res[resLength++] = val; - } - } - } - return res; - }; + +/** + * @define {boolean} Whether we know at compile-time that the browser is WEBKIT. + */ +goog.define('goog.userAgent.ASSUME_WEBKIT', false); /** - * Calls a function for each element in an array and inserts the result into a - * new array. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-map} - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr Array or array like object - * over which to iterate. - * @param {function(this:THIS, VALUE, number, ?): RESULT} f The function to call - * for every element. This function takes 3 arguments (the element, - * the index and the array) and should return something. The result will be - * inserted into a new array. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within f. - * @return {!Array<RESULT>} a new array with the results from f. - * @template THIS, VALUE, RESULT + * @define {boolean} Whether we know at compile-time that the browser is a + * mobile device running WebKit e.g. iPhone or Android. */ -goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.map) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); +goog.define('goog.userAgent.ASSUME_MOBILE_WEBKIT', false); - return goog.array.ARRAY_PROTOTYPE_.map.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var res = new Array(l); - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2) { - res[i] = f.call(opt_obj, arr2[i], i, arr); - } - } - return res; - }; + +/** + * @define {boolean} Whether we know at compile-time that the browser is OPERA. + */ +goog.define('goog.userAgent.ASSUME_OPERA', false); /** - * Passes every element of an array into a function and accumulates the result. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-reduce} - * - * For example: - * var a = [1, 2, 3, 4]; - * goog.array.reduce(a, function(r, v, i, arr) {return r + v;}, 0); - * returns 10 - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {function(this:S, R, T, number, ?) : R} f The function to call for - * every element. This function - * takes 4 arguments (the function's previous result or the initial value, - * the value of the current array element, the current array index, and the - * array itself) - * function(previousValue, currentValue, index, array). - * @param {?} val The initial value to pass into the function on the first call. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {R} Result of evaluating f repeatedly across the values of the array. - * @template T,S,R + * @define {boolean} Whether the + * {@code goog.userAgent.isVersionOrHigher} + * function will return true for any version. */ -goog.array.reduce = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.reduce) ? - function(arr, f, val, opt_obj) { - goog.asserts.assert(arr.length != null); - if (opt_obj) { - f = goog.bind(f, opt_obj); - } - return goog.array.ARRAY_PROTOTYPE_.reduce.call(arr, f, val); - } : - function(arr, f, val, opt_obj) { - var rval = val; - goog.array.forEach(arr, function(val, index) { - rval = f.call(opt_obj, rval, val, index, arr); - }); - return rval; - }; +goog.define('goog.userAgent.ASSUME_ANY_VERSION', false); /** - * Passes every element of an array into a function and accumulates the result, - * starting from the last element and working towards the first. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-reduceright} - * - * For example: - * var a = ['a', 'b', 'c']; - * goog.array.reduceRight(a, function(r, v, i, arr) {return r + v;}, ''); - * returns 'cba' - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, R, T, number, ?) : R} f The function to call for - * every element. This function - * takes 4 arguments (the function's previous result or the initial value, - * the value of the current array element, the current array index, and the - * array itself) - * function(previousValue, currentValue, index, array). - * @param {?} val The initial value to pass into the function on the first call. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {R} Object returned as a result of evaluating f repeatedly across the - * values of the array. - * @template T,S,R + * Whether we know the browser engine at compile-time. + * @type {boolean} + * @private */ -goog.array.reduceRight = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.reduceRight) ? - function(arr, f, val, opt_obj) { - goog.asserts.assert(arr.length != null); - if (opt_obj) { - f = goog.bind(f, opt_obj); - } - return goog.array.ARRAY_PROTOTYPE_.reduceRight.call(arr, f, val); - } : - function(arr, f, val, opt_obj) { - var rval = val; - goog.array.forEachRight(arr, function(val, index) { - rval = f.call(opt_obj, rval, val, index, arr); - }); - return rval; - }; +goog.userAgent.BROWSER_KNOWN_ = + goog.userAgent.ASSUME_IE || + goog.userAgent.ASSUME_EDGE || + goog.userAgent.ASSUME_GECKO || + goog.userAgent.ASSUME_MOBILE_WEBKIT || + goog.userAgent.ASSUME_WEBKIT || + goog.userAgent.ASSUME_OPERA; /** - * Calls f for each element of an array. If any call returns true, some() - * returns true (without checking the remaining elements). If all calls - * return false, some() returns false. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-some} + * Returns the userAgent string for the current browser. * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call for - * for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a boolean. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {boolean} true if any element passes the test. - * @template T,S + * @return {string} The userAgent string. */ -goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.some) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); +goog.userAgent.getUserAgentString = function() { + return goog.labs.userAgent.util.getUserAgent(); +}; - return goog.array.ARRAY_PROTOTYPE_.some.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { - return true; - } - } - return false; - }; + +/** + * TODO(nnaze): Change type to "Navigator" and update compilation targets. + * @return {Object} The native navigator object. + */ +goog.userAgent.getNavigator = function() { + // Need a local navigator reference instead of using the global one, + // to avoid the rare case where they reference different objects. + // (in a WorkerPool, for example). + return goog.global['navigator'] || null; +}; /** - * Call f for each element of an array. If all calls return true, every() - * returns true. If any call returns false, every() returns false and - * does not continue to check the remaining elements. - * - * See {@link http://tinyurl.com/developer-mozilla-org-array-every} - * - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call for - * for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a boolean. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within f. - * @return {boolean} false if any element fails the test. - * @template T,S + * Whether the user agent is Opera. + * @type {boolean} */ -goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES && - (goog.array.ASSUME_NATIVE_FUNCTIONS || - goog.array.ARRAY_PROTOTYPE_.every) ? - function(arr, f, opt_obj) { - goog.asserts.assert(arr.length != null); - - return goog.array.ARRAY_PROTOTYPE_.every.call(arr, f, opt_obj); - } : - function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2 && !f.call(opt_obj, arr2[i], i, arr)) { - return false; - } - } - return true; - }; +goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ? + goog.userAgent.ASSUME_OPERA : + goog.labs.userAgent.browser.isOpera(); /** - * Counts the array elements that fulfill the predicate, i.e. for which the - * callback function returns true. Skips holes in the array. - * - * @param {!(Array<T>|goog.array.ArrayLike)} arr Array or array like object - * over which to iterate. - * @param {function(this: S, T, number, ?): boolean} f The function to call for - * every element. Takes 3 arguments (the element, the index and the array). - * @param {S=} opt_obj The object to be used as the value of 'this' within f. - * @return {number} The number of the matching elements. - * @template T,S + * Whether the user agent is Internet Explorer. + * @type {boolean} */ -goog.array.count = function(arr, f, opt_obj) { - var count = 0; - goog.array.forEach(arr, function(element, index, arr) { - if (f.call(opt_obj, element, index, arr)) { - ++count; - } - }, opt_obj); - return count; -}; +goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ? + goog.userAgent.ASSUME_IE : + goog.labs.userAgent.browser.isIE(); /** - * Search an array for the first element that satisfies a given condition and - * return that element. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {T|null} The first array element that passes the test, or null if no - * element is found. - * @template T,S + * Whether the user agent is Microsoft Edge. + * @type {boolean} */ -goog.array.find = function(arr, f, opt_obj) { - var i = goog.array.findIndex(arr, f, opt_obj); - return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i]; -}; +goog.userAgent.EDGE = goog.userAgent.BROWSER_KNOWN_ ? + goog.userAgent.ASSUME_EDGE : + goog.labs.userAgent.engine.isEdge(); /** - * Search an array for the first element that satisfies a given condition and - * return its index. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call for - * every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {number} The index of the first array element that passes the test, - * or -1 if no element is found. - * @template T,S + * Whether the user agent is MS Internet Explorer or MS Edge. + * @type {boolean} */ -goog.array.findIndex = function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = 0; i < l; i++) { - if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { - return i; - } - } - return -1; -}; +goog.userAgent.EDGE_OR_IE = goog.userAgent.EDGE || goog.userAgent.IE; /** - * Search an array (in reverse order) for the last element that satisfies a - * given condition and return that element. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {T|null} The last array element that passes the test, or null if no - * element is found. - * @template T,S + * Whether the user agent is Gecko. Gecko is the rendering engine used by + * Mozilla, Firefox, and others. + * @type {boolean} */ -goog.array.findRight = function(arr, f, opt_obj) { - var i = goog.array.findIndexRight(arr, f, opt_obj); - return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i]; -}; +goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ? + goog.userAgent.ASSUME_GECKO : + goog.labs.userAgent.engine.isGecko(); /** - * Search an array (in reverse order) for the last element that satisfies a - * given condition and return its index. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {number} The index of the last array element that passes the test, - * or -1 if no element is found. - * @template T,S + * Whether the user agent is WebKit. WebKit is the rendering engine that + * Safari, Android and others use. + * @type {boolean} */ -goog.array.findIndexRight = function(arr, f, opt_obj) { - var l = arr.length; // must be fixed during loop... see docs - var arr2 = goog.isString(arr) ? arr.split('') : arr; - for (var i = l - 1; i >= 0; i--) { - if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) { - return i; - } - } - return -1; -}; +goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ? + goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT : + goog.labs.userAgent.engine.isWebKit(); /** - * Whether the array contains the given object. - * @param {goog.array.ArrayLike} arr The array to test for the presence of the - * element. - * @param {*} obj The object for which to test. - * @return {boolean} true if obj is present. + * Whether the user agent is running on a mobile device. + * + * This is a separate function so that the logic can be tested. + * + * TODO(nnaze): Investigate swapping in goog.labs.userAgent.device.isMobile(). + * + * @return {boolean} Whether the user agent is running on a mobile device. + * @private */ -goog.array.contains = function(arr, obj) { - return goog.array.indexOf(arr, obj) >= 0; +goog.userAgent.isMobile_ = function() { + return goog.userAgent.WEBKIT && + goog.labs.userAgent.util.matchUserAgent('Mobile'); }; /** - * Whether the array is empty. - * @param {goog.array.ArrayLike} arr The array to test. - * @return {boolean} true if empty. + * Whether the user agent is running on a mobile device. + * + * TODO(nnaze): Consider deprecating MOBILE when labs.userAgent + * is promoted as the gecko/webkit logic is likely inaccurate. + * + * @type {boolean} */ -goog.array.isEmpty = function(arr) { - return arr.length == 0; -}; +goog.userAgent.MOBILE = goog.userAgent.ASSUME_MOBILE_WEBKIT || + goog.userAgent.isMobile_(); /** - * Clears the array. - * @param {goog.array.ArrayLike} arr Array or array like object to clear. + * Used while transitioning code to use WEBKIT instead. + * @type {boolean} + * @deprecated Use {@link goog.userAgent.product.SAFARI} instead. + * TODO(nicksantos): Delete this from goog.userAgent. */ -goog.array.clear = function(arr) { - // For non real arrays we don't have the magic length so we delete the - // indices. - if (!goog.isArray(arr)) { - for (var i = arr.length - 1; i >= 0; i--) { - delete arr[i]; - } - } - arr.length = 0; -}; +goog.userAgent.SAFARI = goog.userAgent.WEBKIT; /** - * Pushes an item into an array, if it's not already in the array. - * @param {Array<T>} arr Array into which to insert the item. - * @param {T} obj Value to add. - * @template T + * @return {string} the platform (operating system) the user agent is running + * on. Default to empty string because navigator.platform may not be defined + * (on Rhino, for example). + * @private */ -goog.array.insert = function(arr, obj) { - if (!goog.array.contains(arr, obj)) { - arr.push(obj); - } +goog.userAgent.determinePlatform_ = function() { + var navigator = goog.userAgent.getNavigator(); + return navigator && navigator.platform || ''; }; /** - * Inserts an object at the given index of the array. - * @param {goog.array.ArrayLike} arr The array to modify. - * @param {*} obj The object to insert. - * @param {number=} opt_i The index at which to insert the object. If omitted, - * treated as 0. A negative index is counted from the end of the array. + * The platform (operating system) the user agent is running on. Default to + * empty string because navigator.platform may not be defined (on Rhino, for + * example). + * @type {string} */ -goog.array.insertAt = function(arr, obj, opt_i) { - goog.array.splice(arr, opt_i, 0, obj); -}; +goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_(); /** - * Inserts at the given index of the array, all elements of another array. - * @param {goog.array.ArrayLike} arr The array to modify. - * @param {goog.array.ArrayLike} elementsToAdd The array of elements to add. - * @param {number=} opt_i The index at which to insert the object. If omitted, - * treated as 0. A negative index is counted from the end of the array. + * @define {boolean} Whether the user agent is running on a Macintosh operating + * system. */ -goog.array.insertArrayAt = function(arr, elementsToAdd, opt_i) { - goog.partial(goog.array.splice, arr, opt_i, 0).apply(null, elementsToAdd); -}; +goog.define('goog.userAgent.ASSUME_MAC', false); /** - * Inserts an object into an array before a specified object. - * @param {Array<T>} arr The array to modify. - * @param {T} obj The object to insert. - * @param {T=} opt_obj2 The object before which obj should be inserted. If obj2 - * is omitted or not found, obj is inserted at the end of the array. - * @template T + * @define {boolean} Whether the user agent is running on a Windows operating + * system. */ -goog.array.insertBefore = function(arr, obj, opt_obj2) { - var i; - if (arguments.length == 2 || (i = goog.array.indexOf(arr, opt_obj2)) < 0) { - arr.push(obj); - } else { - goog.array.insertAt(arr, obj, i); - } -}; +goog.define('goog.userAgent.ASSUME_WINDOWS', false); /** - * Removes the first occurrence of a particular value from an array. - * @param {Array<T>|goog.array.ArrayLike} arr Array from which to remove - * value. - * @param {T} obj Object to remove. - * @return {boolean} True if an element was removed. - * @template T + * @define {boolean} Whether the user agent is running on a Linux operating + * system. */ -goog.array.remove = function(arr, obj) { - var i = goog.array.indexOf(arr, obj); - var rv; - if ((rv = i >= 0)) { - goog.array.removeAt(arr, i); - } - return rv; -}; +goog.define('goog.userAgent.ASSUME_LINUX', false); /** - * Removes from an array the element at index i - * @param {goog.array.ArrayLike} arr Array or array like object from which to - * remove value. - * @param {number} i The index to remove. - * @return {boolean} True if an element was removed. + * @define {boolean} Whether the user agent is running on a X11 windowing + * system. */ -goog.array.removeAt = function(arr, i) { - goog.asserts.assert(arr.length != null); - - // use generic form of splice - // splice returns the removed items and if successful the length of that - // will be 1 - return goog.array.ARRAY_PROTOTYPE_.splice.call(arr, i, 1).length == 1; -}; +goog.define('goog.userAgent.ASSUME_X11', false); /** - * Removes the first value that satisfies the given condition. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {boolean} True if an element was removed. - * @template T,S + * @define {boolean} Whether the user agent is running on Android. */ -goog.array.removeIf = function(arr, f, opt_obj) { - var i = goog.array.findIndex(arr, f, opt_obj); - if (i >= 0) { - goog.array.removeAt(arr, i); - return true; - } - return false; -}; +goog.define('goog.userAgent.ASSUME_ANDROID', false); /** - * Removes all values that satisfy the given condition. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array - * like object over which to iterate. - * @param {?function(this:S, T, number, ?) : boolean} f The function to call - * for every element. This function - * takes 3 arguments (the element, the index and the array) and should - * return a boolean. - * @param {S=} opt_obj An optional "this" context for the function. - * @return {number} The number of items removed - * @template T,S + * @define {boolean} Whether the user agent is running on an iPhone. */ -goog.array.removeAllIf = function(arr, f, opt_obj) { - var removedCount = 0; - goog.array.forEachRight(arr, function(val, index) { - if (f.call(opt_obj, val, index, arr)) { - if (goog.array.removeAt(arr, index)) { - removedCount++; - } - } - }); - return removedCount; -}; +goog.define('goog.userAgent.ASSUME_IPHONE', false); /** - * Returns a new array that is the result of joining the arguments. If arrays - * are passed then their items are added, however, if non-arrays are passed they - * will be added to the return array as is. - * - * Note that ArrayLike objects will be added as is, rather than having their - * items added. - * - * goog.array.concat([1, 2], [3, 4]) -> [1, 2, 3, 4] - * goog.array.concat(0, [1, 2]) -> [0, 1, 2] - * goog.array.concat([1, 2], null) -> [1, 2, null] - * - * There is bug in all current versions of IE (6, 7 and 8) where arrays created - * in an iframe become corrupted soon (not immediately) after the iframe is - * destroyed. This is common if loading data via goog.net.IframeIo, for example. - * This corruption only affects the concat method which will start throwing - * Catastrophic Errors (#-2147418113). - * - * See http://endoflow.com/scratch/corrupted-arrays.html for a test case. - * - * Internally goog.array should use this, so that all methods will continue to - * work on these broken array objects. - * - * @param {...*} var_args Items to concatenate. Arrays will have each item - * added, while primitives and objects will be added as is. - * @return {!Array<?>} The new resultant array. + * @define {boolean} Whether the user agent is running on an iPad. */ -goog.array.concat = function(var_args) { - return goog.array.ARRAY_PROTOTYPE_.concat.apply( - goog.array.ARRAY_PROTOTYPE_, arguments); -}; +goog.define('goog.userAgent.ASSUME_IPAD', false); /** - * Returns a new array that contains the contents of all the arrays passed. - * @param {...!Array<T>} var_args - * @return {!Array<T>} - * @template T + * @type {boolean} + * @private */ -goog.array.join = function(var_args) { - return goog.array.ARRAY_PROTOTYPE_.concat.apply( - goog.array.ARRAY_PROTOTYPE_, arguments); -}; +goog.userAgent.PLATFORM_KNOWN_ = + goog.userAgent.ASSUME_MAC || + goog.userAgent.ASSUME_WINDOWS || + goog.userAgent.ASSUME_LINUX || + goog.userAgent.ASSUME_X11 || + goog.userAgent.ASSUME_ANDROID || + goog.userAgent.ASSUME_IPHONE || + goog.userAgent.ASSUME_IPAD; /** - * Converts an object to an array. - * @param {Array<T>|goog.array.ArrayLike} object The object to convert to an - * array. - * @return {!Array<T>} The object converted into an array. If object has a - * length property, every property indexed with a non-negative number - * less than length will be included in the result. If object does not - * have a length property, an empty array will be returned. - * @template T + * Whether the user agent is running on a Macintosh operating system. + * @type {boolean} */ -goog.array.toArray = function(object) { - var length = object.length; - - // If length is not a number the following it false. This case is kept for - // backwards compatibility since there are callers that pass objects that are - // not array like. - if (length > 0) { - var rv = new Array(length); - for (var i = 0; i < length; i++) { - rv[i] = object[i]; - } - return rv; - } - return []; -}; +goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_MAC : goog.labs.userAgent.platform.isMacintosh(); /** - * Does a shallow copy of an array. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array-like object to - * clone. - * @return {!Array<T>} Clone of the input array. - * @template T + * Whether the user agent is running on a Windows operating system. + * @type {boolean} */ -goog.array.clone = goog.array.toArray; +goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_WINDOWS : + goog.labs.userAgent.platform.isWindows(); /** - * Extends an array with another array, element, or "array like" object. - * This function operates 'in-place', it does not create a new Array. - * - * Example: - * var a = []; - * goog.array.extend(a, [0, 1]); - * a; // [0, 1] - * goog.array.extend(a, 2); - * a; // [0, 1, 2] - * - * @param {Array<VALUE>} arr1 The array to modify. - * @param {...(Array<VALUE>|VALUE)} var_args The elements or arrays of elements - * to add to arr1. - * @template VALUE + * Whether the user agent is Linux per the legacy behavior of + * goog.userAgent.LINUX, which considered ChromeOS to also be + * Linux. + * @return {boolean} + * @private */ -goog.array.extend = function(arr1, var_args) { - for (var i = 1; i < arguments.length; i++) { - var arr2 = arguments[i]; - if (goog.isArrayLike(arr2)) { - var len1 = arr1.length || 0; - var len2 = arr2.length || 0; - arr1.length = len1 + len2; - for (var j = 0; j < len2; j++) { - arr1[len1 + j] = arr2[j]; - } - } else { - arr1.push(arr2); - } - } +goog.userAgent.isLegacyLinux_ = function() { + return goog.labs.userAgent.platform.isLinux() || + goog.labs.userAgent.platform.isChromeOS(); }; /** - * Adds or removes elements from an array. This is a generic version of Array - * splice. This means that it might work on other objects similar to arrays, - * such as the arguments object. + * Whether the user agent is running on a Linux operating system. * - * @param {Array<T>|goog.array.ArrayLike} arr The array to modify. - * @param {number|undefined} index The index at which to start changing the - * array. If not defined, treated as 0. - * @param {number} howMany How many elements to remove (0 means no removal. A - * value below 0 is treated as zero and so is any other non number. Numbers - * are floored). - * @param {...T} var_args Optional, additional elements to insert into the - * array. - * @return {!Array<T>} the removed elements. - * @template T + * Note that goog.userAgent.LINUX considers ChromeOS to be Linux, + * while goog.labs.userAgent.platform considers ChromeOS and + * Linux to be different OSes. + * + * @type {boolean} */ -goog.array.splice = function(arr, index, howMany, var_args) { - goog.asserts.assert(arr.length != null); +goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_LINUX : + goog.userAgent.isLegacyLinux_(); - return goog.array.ARRAY_PROTOTYPE_.splice.apply( - arr, goog.array.slice(arguments, 1)); + +/** + * @return {boolean} Whether the user agent is an X11 windowing system. + * @private + */ +goog.userAgent.isX11_ = function() { + var navigator = goog.userAgent.getNavigator(); + return !!navigator && + goog.string.contains(navigator['appVersion'] || '', 'X11'); }; /** - * Returns a new array from a segment of an array. This is a generic version of - * Array slice. This means that it might work on other objects similar to - * arrays, such as the arguments object. - * - * @param {Array<T>|goog.array.ArrayLike} arr The array from - * which to copy a segment. - * @param {number} start The index of the first element to copy. - * @param {number=} opt_end The index after the last element to copy. - * @return {!Array<T>} A new array containing the specified segment of the - * original array. - * @template T + * Whether the user agent is running on a X11 windowing system. + * @type {boolean} */ -goog.array.slice = function(arr, start, opt_end) { - goog.asserts.assert(arr.length != null); - - // passing 1 arg to slice is not the same as passing 2 where the second is - // null or undefined (in that case the second argument is treated as 0). - // we could use slice on the arguments object and then use apply instead of - // testing the length - if (arguments.length <= 2) { - return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start); - } else { - return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start, opt_end); - } -}; +goog.userAgent.X11 = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_X11 : + goog.userAgent.isX11_(); /** - * Removes all duplicates from an array (retaining only the first - * occurrence of each array element). This function modifies the - * array in place and doesn't change the order of the non-duplicate items. - * - * For objects, duplicates are identified as having the same unique ID as - * defined by {@link goog.getUid}. - * - * Alternatively you can specify a custom hash function that returns a unique - * value for each item in the array it should consider unique. - * - * Runtime: N, - * Worstcase space: 2N (no dupes) - * - * @param {Array<T>|goog.array.ArrayLike} arr The array from which to remove - * duplicates. - * @param {Array=} opt_rv An optional array in which to return the results, - * instead of performing the removal inplace. If specified, the original - * array will remain unchanged. - * @param {function(T):string=} opt_hashFn An optional function to use to - * apply to every item in the array. This function should return a unique - * value for each item in the array it should consider unique. - * @template T + * Whether the user agent is running on Android. + * @type {boolean} */ -goog.array.removeDuplicates = function(arr, opt_rv, opt_hashFn) { - var returnArray = opt_rv || arr; - var defaultHashFn = function(item) { - // Prefix each type with a single character representing the type to - // prevent conflicting keys (e.g. true and 'true'). - return goog.isObject(item) ? 'o' + goog.getUid(item) : - (typeof item).charAt(0) + item; - }; - var hashFn = opt_hashFn || defaultHashFn; - - var seen = {}, cursorInsert = 0, cursorRead = 0; - while (cursorRead < arr.length) { - var current = arr[cursorRead++]; - var key = hashFn(current); - if (!Object.prototype.hasOwnProperty.call(seen, key)) { - seen[key] = true; - returnArray[cursorInsert++] = current; - } - } - returnArray.length = cursorInsert; -}; +goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_ANDROID : + goog.labs.userAgent.platform.isAndroid(); /** - * Searches the specified array for the specified target using the binary - * search algorithm. If no opt_compareFn is specified, elements are compared - * using <code>goog.array.defaultCompare</code>, which compares the elements - * using the built in < and > operators. This will produce the expected - * behavior for homogeneous arrays of String(s) and Number(s). The array - * specified <b>must</b> be sorted in ascending order (as defined by the - * comparison function). If the array is not sorted, results are undefined. - * If the array contains multiple instances of the specified target value, any - * of these instances may be found. - * - * Runtime: O(log n) - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. - * @param {TARGET} target The sought value. - * @param {function(TARGET, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {number} Lowest index of the target value if found, otherwise - * (-(insertion point) - 1). The insertion point is where the value should - * be inserted into arr to preserve the sorted property. Return value >= 0 - * iff target is found. - * @template TARGET, VALUE + * Whether the user agent is running on an iPhone. + * @type {boolean} */ -goog.array.binarySearch = function(arr, target, opt_compareFn) { - return goog.array.binarySearch_(arr, - opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */, - target); -}; +goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_IPHONE : + goog.labs.userAgent.platform.isIphone(); /** - * Selects an index in the specified array using the binary search algorithm. - * The evaluator receives an element and determines whether the desired index - * is before, at, or after it. The evaluator must be consistent (formally, - * goog.array.map(goog.array.map(arr, evaluator, opt_obj), goog.math.sign) - * must be monotonically non-increasing). - * - * Runtime: O(log n) - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. - * @param {function(this:THIS, VALUE, number, ?): number} evaluator - * Evaluator function that receives 3 arguments (the element, the index and - * the array). Should return a negative number, zero, or a positive number - * depending on whether the desired index is before, at, or after the - * element passed to it. - * @param {THIS=} opt_obj The object to be used as the value of 'this' - * within evaluator. - * @return {number} Index of the leftmost element matched by the evaluator, if - * such exists; otherwise (-(insertion point) - 1). The insertion point is - * the index of the first element for which the evaluator returns negative, - * or arr.length if no such element exists. The return value is non-negative - * iff a match is found. - * @template THIS, VALUE + * Whether the user agent is running on an iPad. + * @type {boolean} */ -goog.array.binarySelect = function(arr, evaluator, opt_obj) { - return goog.array.binarySearch_(arr, evaluator, true /* isEvaluator */, - undefined /* opt_target */, opt_obj); -}; +goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ? + goog.userAgent.ASSUME_IPAD : + goog.labs.userAgent.platform.isIpad(); /** - * Implementation of a binary search algorithm which knows how to use both - * comparison functions and evaluators. If an evaluator is provided, will call - * the evaluator with the given optional data object, conforming to the - * interface defined in binarySelect. Otherwise, if a comparison function is - * provided, will call the comparison function against the given data object. - * - * This implementation purposefully does not use goog.bind or goog.partial for - * performance reasons. - * - * Runtime: O(log n) - * - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched. - * @param {function(TARGET, VALUE): number| - * function(this:THIS, VALUE, number, ?): number} compareFn Either an - * evaluator or a comparison function, as defined by binarySearch - * and binarySelect above. - * @param {boolean} isEvaluator Whether the function is an evaluator or a - * comparison function. - * @param {TARGET=} opt_target If the function is a comparison function, then - * this is the target to binary search for. - * @param {THIS=} opt_selfObj If the function is an evaluator, this is an - * optional this object for the evaluator. - * @return {number} Lowest index of the target value if found, otherwise - * (-(insertion point) - 1). The insertion point is where the value should - * be inserted into arr to preserve the sorted property. Return value >= 0 - * iff target is found. - * @template THIS, VALUE, TARGET + * @return {string} The string that describes the version number of the user + * agent. + * Assumes user agent is opera. * @private */ -goog.array.binarySearch_ = function(arr, compareFn, isEvaluator, opt_target, - opt_selfObj) { - var left = 0; // inclusive - var right = arr.length; // exclusive - var found; - while (left < right) { - var middle = (left + right) >> 1; - var compareResult; - if (isEvaluator) { - compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr); - } else { - compareResult = compareFn(opt_target, arr[middle]); - } - if (compareResult > 0) { - left = middle + 1; - } else { - right = middle; - // We are looking for the lowest index so we can't return immediately. - found = !compareResult; - } +goog.userAgent.operaVersion_ = function() { + var version = goog.global.opera.version; + try { + return version(); + } catch (e) { + return version; } - // left is the index if found, or the insertion point otherwise. - // ~left is a shorthand for -left - 1. - return found ? left : ~left; }; /** - * Sorts the specified array into ascending order. If no opt_compareFn is - * specified, elements are compared using - * <code>goog.array.defaultCompare</code>, which compares the elements using - * the built in < and > operators. This will produce the expected behavior - * for homogeneous arrays of String(s) and Number(s), unlike the native sort, - * but will give unpredictable results for heterogenous lists of strings and - * numbers with different numbers of digits. - * - * This sort is not guaranteed to be stable. - * - * Runtime: Same as <code>Array.prototype.sort</code> - * - * @param {Array<T>} arr The array to be sorted. - * @param {?function(T,T):number=} opt_compareFn Optional comparison - * function by which the - * array is to be ordered. Should take 2 arguments to compare, and return a - * negative number, zero, or a positive number depending on whether the - * first argument is less than, equal to, or greater than the second. - * @template T + * @return {string} The string that describes the version number of the user + * agent. + * @private */ -goog.array.sort = function(arr, opt_compareFn) { - // TODO(arv): Update type annotation since null is not accepted. - arr.sort(opt_compareFn || goog.array.defaultCompare); -}; +goog.userAgent.determineVersion_ = function() { + // All browsers have different ways to detect the version and they all have + // different naming schemes. + if (goog.userAgent.OPERA && goog.global['opera']) { + return goog.userAgent.operaVersion_(); + } -/** - * Sorts the specified array into ascending order in a stable way. If no - * opt_compareFn is specified, elements are compared using - * <code>goog.array.defaultCompare</code>, which compares the elements using - * the built in < and > operators. This will produce the expected behavior - * for homogeneous arrays of String(s) and Number(s). - * - * Runtime: Same as <code>Array.prototype.sort</code>, plus an additional - * O(n) overhead of copying the array twice. - * - * @param {Array<T>} arr The array to be sorted. - * @param {?function(T, T): number=} opt_compareFn Optional comparison function - * by which the array is to be ordered. Should take 2 arguments to compare, - * and return a negative number, zero, or a positive number depending on - * whether the first argument is less than, equal to, or greater than the - * second. - * @template T - */ -goog.array.stableSort = function(arr, opt_compareFn) { - for (var i = 0; i < arr.length; i++) { - arr[i] = {index: i, value: arr[i]}; + // version is a string rather than a number because it may contain 'b', 'a', + // and so on. + var version = ''; + var arr = goog.userAgent.getVersionRegexResult_(); + if (arr) { + version = arr ? arr[1] : ''; } - var valueCompareFn = opt_compareFn || goog.array.defaultCompare; - function stableCompareFn(obj1, obj2) { - return valueCompareFn(obj1.value, obj2.value) || obj1.index - obj2.index; - }; - goog.array.sort(arr, stableCompareFn); - for (var i = 0; i < arr.length; i++) { - arr[i] = arr[i].value; + + if (goog.userAgent.IE) { + // IE9 can be in document mode 9 but be reporting an inconsistent user agent + // version. If it is identifying as a version lower than 9 we take the + // documentMode as the version instead. IE8 has similar behavior. + // It is recommended to set the X-UA-Compatible header to ensure that IE9 + // uses documentMode 9. + var docMode = goog.userAgent.getDocumentMode_(); + if (docMode > parseFloat(version)) { + return String(docMode); + } } + + return version; }; /** - * Sort the specified array into ascending order based on item keys - * returned by the specified key function. - * If no opt_compareFn is specified, the keys are compared in ascending order - * using <code>goog.array.defaultCompare</code>. - * - * Runtime: O(S(f(n)), where S is runtime of <code>goog.array.sort</code> - * and f(n) is runtime of the key function. - * - * @param {Array<T>} arr The array to be sorted. - * @param {function(T): K} keyFn Function taking array element and returning - * a key used for sorting this element. - * @param {?function(K, K): number=} opt_compareFn Optional comparison function - * by which the keys are to be ordered. Should take 2 arguments to compare, - * and return a negative number, zero, or a positive number depending on - * whether the first argument is less than, equal to, or greater than the - * second. - * @template T,K + * @return {Array|undefined} The version regex matches from parsing the user + * agent string. These regex statements must be executed inline so they can + * be compiled out by the closure compiler with the rest of the useragent + * detection logic when ASSUME_* is specified. + * @private */ -goog.array.sortByKey = function(arr, keyFn, opt_compareFn) { - var keyCompareFn = opt_compareFn || goog.array.defaultCompare; - goog.array.sort(arr, function(a, b) { - return keyCompareFn(keyFn(a), keyFn(b)); - }); +goog.userAgent.getVersionRegexResult_ = function() { + var userAgent = goog.userAgent.getUserAgentString(); + if (goog.userAgent.GECKO) { + return /rv\:([^\);]+)(\)|;)/.exec(userAgent); + } + if (goog.userAgent.EDGE) { + return /Edge\/([\d\.]+)/.exec(userAgent); + } + if (goog.userAgent.IE) { + return /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(userAgent); + } + if (goog.userAgent.WEBKIT) { + // WebKit/125.4 + return /WebKit\/(\S+)/.exec(userAgent); + } }; /** - * Sorts an array of objects by the specified object key and compare - * function. If no compare function is provided, the key values are - * compared in ascending order using <code>goog.array.defaultCompare</code>. - * This won't work for keys that get renamed by the compiler. So use - * {'foo': 1, 'bar': 2} rather than {foo: 1, bar: 2}. - * @param {Array<Object>} arr An array of objects to sort. - * @param {string} key The object key to sort by. - * @param {Function=} opt_compareFn The function to use to compare key - * values. + * @return {number|undefined} Returns the document mode (for testing). + * @private */ -goog.array.sortObjectsByKey = function(arr, key, opt_compareFn) { - goog.array.sortByKey(arr, - function(obj) { return obj[key]; }, - opt_compareFn); +goog.userAgent.getDocumentMode_ = function() { + // NOTE(user): goog.userAgent may be used in context where there is no DOM. + var doc = goog.global['document']; + return doc ? doc['documentMode'] : undefined; }; /** - * Tells if the array is sorted. - * @param {!Array<T>} arr The array. - * @param {?function(T,T):number=} opt_compareFn Function to compare the - * array elements. - * Should take 2 arguments to compare, and return a negative number, zero, - * or a positive number depending on whether the first argument is less - * than, equal to, or greater than the second. - * @param {boolean=} opt_strict If true no equal elements are allowed. - * @return {boolean} Whether the array is sorted. - * @template T + * The version of the user agent. This is a string because it might contain + * 'b' (as in beta) as well as multiple dots. + * @type {string} */ -goog.array.isSorted = function(arr, opt_compareFn, opt_strict) { - var compare = opt_compareFn || goog.array.defaultCompare; - for (var i = 1; i < arr.length; i++) { - var compareResult = compare(arr[i - 1], arr[i]); - if (compareResult > 0 || compareResult == 0 && opt_strict) { - return false; - } - } - return true; -}; +goog.userAgent.VERSION = goog.userAgent.determineVersion_(); /** - * Compares two arrays for equality. Two arrays are considered equal if they - * have the same length and their corresponding elements are equal according to - * the comparison function. + * Compares two version numbers. * - * @param {goog.array.ArrayLike} arr1 The first array to compare. - * @param {goog.array.ArrayLike} arr2 The second array to compare. - * @param {Function=} opt_equalsFn Optional comparison function. - * Should take 2 arguments to compare, and return true if the arguments - * are equal. Defaults to {@link goog.array.defaultCompareEquality} which - * compares the elements using the built-in '===' operator. - * @return {boolean} Whether the two arrays are equal. + * @param {string} v1 Version of first item. + * @param {string} v2 Version of second item. + * + * @return {number} 1 if first argument is higher + * 0 if arguments are equal + * -1 if second argument is higher. + * @deprecated Use goog.string.compareVersions. */ -goog.array.equals = function(arr1, arr2, opt_equalsFn) { - if (!goog.isArrayLike(arr1) || !goog.isArrayLike(arr2) || - arr1.length != arr2.length) { - return false; - } - var l = arr1.length; - var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality; - for (var i = 0; i < l; i++) { - if (!equalsFn(arr1[i], arr2[i])) { - return false; - } - } - return true; +goog.userAgent.compare = function(v1, v2) { + return goog.string.compareVersions(v1, v2); }; /** - * 3-way array compare function. - * @param {!Array<VALUE>|!goog.array.ArrayLike} arr1 The first array to - * compare. - * @param {!Array<VALUE>|!goog.array.ArrayLike} arr2 The second array to - * compare. - * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is to be ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {number} Negative number, zero, or a positive number depending on - * whether the first argument is less than, equal to, or greater than the - * second. - * @template VALUE + * Cache for {@link goog.userAgent.isVersionOrHigher}. + * Calls to compareVersions are surprisingly expensive and, as a browser's + * version number is unlikely to change during a session, we cache the results. + * @const + * @private */ -goog.array.compare3 = function(arr1, arr2, opt_compareFn) { - var compare = opt_compareFn || goog.array.defaultCompare; - var l = Math.min(arr1.length, arr2.length); - for (var i = 0; i < l; i++) { - var result = compare(arr1[i], arr2[i]); - if (result != 0) { - return result; - } - } - return goog.array.defaultCompare(arr1.length, arr2.length); -}; +goog.userAgent.isVersionOrHigherCache_ = {}; /** - * Compares its two arguments for order, using the built in < and > - * operators. - * @param {VALUE} a The first object to be compared. - * @param {VALUE} b The second object to be compared. - * @return {number} A negative number, zero, or a positive number as the first - * argument is less than, equal to, or greater than the second, - * respectively. - * @template VALUE + * Whether the user agent version is higher or the same as the given version. + * NOTE: When checking the version numbers for Firefox and Safari, be sure to + * use the engine's version, not the browser's version number. For example, + * Firefox 3.0 corresponds to Gecko 1.9 and Safari 3.0 to Webkit 522.11. + * Opera and Internet Explorer versions match the product release number.<br> + * @see <a href="http://en.wikipedia.org/wiki/Safari_version_history"> + * Webkit</a> + * @see <a href="http://en.wikipedia.org/wiki/Gecko_engine">Gecko</a> + * + * @param {string|number} version The version to check. + * @return {boolean} Whether the user agent version is higher or the same as + * the given version. */ -goog.array.defaultCompare = function(a, b) { - return a > b ? 1 : a < b ? -1 : 0; +goog.userAgent.isVersionOrHigher = function(version) { + return goog.userAgent.ASSUME_ANY_VERSION || + goog.userAgent.isVersionOrHigherCache_[version] || + (goog.userAgent.isVersionOrHigherCache_[version] = + goog.string.compareVersions(goog.userAgent.VERSION, version) >= 0); }; /** - * Compares its two arguments for inverse order, using the built in < and > - * operators. - * @param {VALUE} a The first object to be compared. - * @param {VALUE} b The second object to be compared. - * @return {number} A negative number, zero, or a positive number as the first - * argument is greater than, equal to, or less than the second, - * respectively. - * @template VALUE + * Deprecated alias to {@code goog.userAgent.isVersionOrHigher}. + * @param {string|number} version The version to check. + * @return {boolean} Whether the user agent version is higher or the same as + * the given version. + * @deprecated Use goog.userAgent.isVersionOrHigher(). */ -goog.array.inverseDefaultCompare = function(a, b) { - return -goog.array.defaultCompare(a, b); -}; +goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher; /** - * Compares its two arguments for equality, using the built in === operator. - * @param {*} a The first object to compare. - * @param {*} b The second object to compare. - * @return {boolean} True if the two arguments are equal, false otherwise. + * Whether the IE effective document mode is higher or the same as the given + * document mode version. + * NOTE: Only for IE, return false for another browser. + * + * @param {number} documentMode The document mode version to check. + * @return {boolean} Whether the IE effective document mode is higher or the + * same as the given version. */ -goog.array.defaultCompareEquality = function(a, b) { - return a === b; +goog.userAgent.isDocumentModeOrHigher = function(documentMode) { + return goog.userAgent.DOCUMENT_MODE >= documentMode; }; /** - * Inserts a value into a sorted array. The array is not modified if the - * value is already present. - * @param {Array<VALUE>|goog.array.ArrayLike} array The array to modify. - * @param {VALUE} value The object to insert. - * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {boolean} True if an element was inserted. - * @template VALUE + * Deprecated alias to {@code goog.userAgent.isDocumentModeOrHigher}. + * @param {number} version The version to check. + * @return {boolean} Whether the IE effective document mode is higher or the + * same as the given version. + * @deprecated Use goog.userAgent.isDocumentModeOrHigher(). */ -goog.array.binaryInsert = function(array, value, opt_compareFn) { - var index = goog.array.binarySearch(array, value, opt_compareFn); - if (index < 0) { - goog.array.insertAt(array, value, -(index + 1)); - return true; - } - return false; -}; +goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher; /** - * Removes a value from a sorted array. - * @param {!Array<VALUE>|!goog.array.ArrayLike} array The array to modify. - * @param {VALUE} value The object to remove. - * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison - * function by which the array is ordered. Should take 2 arguments to - * compare, and return a negative number, zero, or a positive number - * depending on whether the first argument is less than, equal to, or - * greater than the second. - * @return {boolean} True if an element was removed. - * @template VALUE + * For IE version < 7, documentMode is undefined, so attempt to use the + * CSS1Compat property to see if we are in standards mode. If we are in + * standards mode, treat the browser version as the document mode. Otherwise, + * IE is emulating version 5. + * @type {number|undefined} + * @const */ -goog.array.binaryRemove = function(array, value, opt_compareFn) { - var index = goog.array.binarySearch(array, value, opt_compareFn); - return (index >= 0) ? goog.array.removeAt(array, index) : false; -}; - - -/** - * Splits an array into disjoint buckets according to a splitting function. - * @param {Array<T>} array The array. - * @param {function(this:S, T,number,Array<T>):?} sorter Function to call for - * every element. This takes 3 arguments (the element, the index and the - * array) and must return a valid object key (a string, number, etc), or - * undefined, if that object should not be placed in a bucket. - * @param {S=} opt_obj The object to be used as the value of 'this' within - * sorter. - * @return {!Object} An object, with keys being all of the unique return values - * of sorter, and values being arrays containing the items for - * which the splitter returned that key. - * @template T,S +goog.userAgent.DOCUMENT_MODE = (function() { + var doc = goog.global['document']; + var mode = goog.userAgent.getDocumentMode_(); + if (!doc || !goog.userAgent.IE) { + return undefined; + } + return mode || (doc['compatMode'] == 'CSS1Compat' ? + parseInt(goog.userAgent.VERSION, 10) : 5); +})(); + +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Browser capability checks for the events package. + * */ -goog.array.bucket = function(array, sorter, opt_obj) { - var buckets = {}; - for (var i = 0; i < array.length; i++) { - var value = array[i]; - var key = sorter.call(opt_obj, value, i, array); - if (goog.isDef(key)) { - // Push the value to the right bucket, creating it if necessary. - var bucket = buckets[key] || (buckets[key] = []); - bucket.push(value); - } - } - return buckets; -}; +goog.provide('goog.events.BrowserFeature'); + +goog.require('goog.userAgent'); /** - * Creates a new object built from the provided array and the key-generation - * function. - * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over - * which to iterate whose elements will be the values in the new object. - * @param {?function(this:S, T, number, ?) : string} keyFunc The function to - * call for every element. This function takes 3 arguments (the element, the - * index and the array) and should return a string that will be used as the - * key for the element in the new object. If the function returns the same - * key for more than one element, the value for that key is - * implementation-defined. - * @param {S=} opt_obj The object to be used as the value of 'this' - * within keyFunc. - * @return {!Object<T>} The new object. - * @template T,S + * Enum of browser capabilities. + * @enum {boolean} */ -goog.array.toObject = function(arr, keyFunc, opt_obj) { - var ret = {}; - goog.array.forEach(arr, function(element, index) { - ret[keyFunc.call(opt_obj, element, index, arr)] = element; - }); - return ret; +goog.events.BrowserFeature = { + /** + * Whether the button attribute of the event is W3C compliant. False in + * Internet Explorer prior to version 9; document-version dependent. + */ + HAS_W3C_BUTTON: !goog.userAgent.IE || + goog.userAgent.isDocumentModeOrHigher(9), + + /** + * Whether the browser supports full W3C event model. + */ + HAS_W3C_EVENT_SUPPORT: !goog.userAgent.IE || + goog.userAgent.isDocumentModeOrHigher(9), + + /** + * To prevent default in IE7-8 for certain keydown events we need set the + * keyCode to -1. + */ + SET_KEY_CODE_TO_PREVENT_DEFAULT: goog.userAgent.IE && + !goog.userAgent.isVersionOrHigher('9'), + + /** + * Whether the {@code navigator.onLine} property is supported. + */ + HAS_NAVIGATOR_ONLINE_PROPERTY: !goog.userAgent.WEBKIT || + goog.userAgent.isVersionOrHigher('528'), + + /** + * Whether HTML5 network online/offline events are supported. + */ + HAS_HTML5_NETWORK_EVENT_SUPPORT: + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9b') || + goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8') || + goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('9.5') || + goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('528'), + + /** + * Whether HTML5 network events fire on document.body, or otherwise the + * window. + */ + HTML5_NETWORK_EVENTS_FIRE_ON_BODY: + goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('8') || + goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'), + + /** + * Whether touch is enabled in the browser. + */ + TOUCH_ENABLED: + ('ontouchstart' in goog.global || + !!(goog.global['document'] && + document.documentElement && + 'ontouchstart' in document.documentElement) || + // IE10 uses non-standard touch events, so it has a different check. + !!(goog.global['navigator'] && + goog.global['navigator']['msMaxTouchPoints'])) }; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Creates a range of numbers in an arithmetic progression. - * - * Range takes 1, 2, or 3 arguments: - * <pre> - * range(5) is the same as range(0, 5, 1) and produces [0, 1, 2, 3, 4] - * range(2, 5) is the same as range(2, 5, 1) and produces [2, 3, 4] - * range(-2, -5, -1) produces [-2, -3, -4] - * range(-2, -5, 1) produces [], since stepping by 1 wouldn't ever reach -5. - * </pre> - * - * @param {number} startOrEnd The starting value of the range if an end argument - * is provided. Otherwise, the start value is 0, and this is the end value. - * @param {number=} opt_end The optional end value of the range. - * @param {number=} opt_step The step size between range values. Defaults to 1 - * if opt_step is undefined or 0. - * @return {!Array<number>} An array of numbers for the requested range. May be - * an empty array if adding the step would not converge toward the end - * value. + * @fileoverview Definition of the disposable interface. A disposable object + * has a dispose method to to clean up references and resources. + * @author nnaze@google.com (Nathan Naze) */ -goog.array.range = function(startOrEnd, opt_end, opt_step) { - var array = []; - var start = 0; - var end = startOrEnd; - var step = opt_step || 1; - if (opt_end !== undefined) { - start = startOrEnd; - end = opt_end; - } - if (step * (end - start) < 0) { - // Sign mismatch: start + step will never reach the end value. - return []; - } - if (step > 0) { - for (var i = start; i < end; i += step) { - array.push(i); - } - } else { - for (var i = start; i > end; i += step) { - array.push(i); - } - } - return array; -}; +goog.provide('goog.disposable.IDisposable'); + /** - * Returns an array consisting of the given value repeated N times. - * - * @param {VALUE} value The value to repeat. - * @param {number} n The repeat count. - * @return {!Array<VALUE>} An array with the repeated value. - * @template VALUE + * Interface for a disposable object. If a instance requires cleanup + * (references COM objects, DOM notes, or other disposable objects), it should + * implement this interface (it may subclass goog.Disposable). + * @interface */ -goog.array.repeat = function(value, n) { - var array = []; - for (var i = 0; i < n; i++) { - array[i] = value; - } - return array; -}; +goog.disposable.IDisposable = function() {}; /** - * Returns an array consisting of every argument with all arrays - * expanded in-place recursively. - * - * @param {...*} var_args The values to flatten. - * @return {!Array<?>} An array containing the flattened values. + * Disposes of the object and its resources. + * @return {void} Nothing. */ -goog.array.flatten = function(var_args) { - var CHUNK_SIZE = 8192; +goog.disposable.IDisposable.prototype.dispose = goog.abstractMethod; - var result = []; - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (goog.isArray(element)) { - for (var c = 0; c < element.length; c += CHUNK_SIZE) { - var chunk = goog.array.slice(element, c, c + CHUNK_SIZE); - var recurseResult = goog.array.flatten.apply(null, chunk); - for (var r = 0; r < recurseResult.length; r++) { - result.push(recurseResult[r]); - } - } - } else { - result.push(element); - } - } - return result; -}; +/** + * @return {boolean} Whether the object has been disposed of. + */ +goog.disposable.IDisposable.prototype.isDisposed = goog.abstractMethod; + +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Rotates an array in-place. After calling this method, the element at - * index i will be the element previously at index (i - n) % - * array.length, for all values of i between 0 and array.length - 1, - * inclusive. - * - * For example, suppose list comprises [t, a, n, k, s]. After invoking - * rotate(array, 1) (or rotate(array, -4)), array will comprise [s, t, a, n, k]. - * - * @param {!Array<T>} array The array to rotate. - * @param {number} n The amount to rotate. - * @return {!Array<T>} The array. - * @template T + * @fileoverview Implements the disposable interface. The dispose method is used + * to clean up references and resources. + * @author arv@google.com (Erik Arvidsson) */ -goog.array.rotate = function(array, n) { - goog.asserts.assert(array.length != null); - if (array.length) { - n %= array.length; - if (n > 0) { - goog.array.ARRAY_PROTOTYPE_.unshift.apply(array, array.splice(-n, n)); - } else if (n < 0) { - goog.array.ARRAY_PROTOTYPE_.push.apply(array, array.splice(0, -n)); + +goog.provide('goog.Disposable'); +/** @suppress {extraProvide} */ +goog.provide('goog.dispose'); +/** @suppress {extraProvide} */ +goog.provide('goog.disposeAll'); + +goog.require('goog.disposable.IDisposable'); + + + +/** + * Class that provides the basic implementation for disposable objects. If your + * class holds one or more references to COM objects, DOM nodes, or other + * disposable objects, it should extend this class or implement the disposable + * interface (defined in goog.disposable.IDisposable). + * @constructor + * @implements {goog.disposable.IDisposable} + */ +goog.Disposable = function() { + if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) { + if (goog.Disposable.INCLUDE_STACK_ON_CREATION) { + this.creationStack = new Error().stack; } + goog.Disposable.instances_[goog.getUid(this)] = this; } - return array; + // Support sealing + this.disposed_ = this.disposed_; + this.onDisposeCallbacks_ = this.onDisposeCallbacks_; }; /** - * Moves one item of an array to a new position keeping the order of the rest - * of the items. Example use case: keeping a list of JavaScript objects - * synchronized with the corresponding list of DOM elements after one of the - * elements has been dragged to a new position. - * @param {!(Array|Arguments|{length:number})} arr The array to modify. - * @param {number} fromIndex Index of the item to move between 0 and - * {@code arr.length - 1}. - * @param {number} toIndex Target index between 0 and {@code arr.length - 1}. + * @enum {number} Different monitoring modes for Disposable. */ -goog.array.moveItem = function(arr, fromIndex, toIndex) { - goog.asserts.assert(fromIndex >= 0 && fromIndex < arr.length); - goog.asserts.assert(toIndex >= 0 && toIndex < arr.length); - // Remove 1 item at fromIndex. - var removedItems = goog.array.ARRAY_PROTOTYPE_.splice.call(arr, fromIndex, 1); - // Insert the removed item at toIndex. - goog.array.ARRAY_PROTOTYPE_.splice.call(arr, toIndex, 0, removedItems[0]); - // We don't use goog.array.insertAt and goog.array.removeAt, because they're - // significantly slower than splice. +goog.Disposable.MonitoringMode = { + /** + * No monitoring. + */ + OFF: 0, + /** + * Creating and disposing the goog.Disposable instances is monitored. All + * disposable objects need to call the {@code goog.Disposable} base + * constructor. The PERMANENT mode must be switched on before creating any + * goog.Disposable instances. + */ + PERMANENT: 1, + /** + * INTERACTIVE mode can be switched on and off on the fly without producing + * errors. It also doesn't warn if the disposable objects don't call the + * {@code goog.Disposable} base constructor. + */ + INTERACTIVE: 2 }; /** - * Creates a new array for which the element at position i is an array of the - * ith element of the provided arrays. The returned array will only be as long - * as the shortest array provided; additional values are ignored. For example, - * the result of zipping [1, 2] and [3, 4, 5] is [[1,3], [2, 4]]. - * - * This is similar to the zip() function in Python. See {@link - * http://docs.python.org/library/functions.html#zip} - * - * @param {...!goog.array.ArrayLike} var_args Arrays to be combined. - * @return {!Array<!Array<?>>} A new array of arrays created from - * provided arrays. + * @define {number} The monitoring mode of the goog.Disposable + * instances. Default is OFF. Switching on the monitoring is only + * recommended for debugging because it has a significant impact on + * performance and memory usage. If switched off, the monitoring code + * compiles down to 0 bytes. */ -goog.array.zip = function(var_args) { - if (!arguments.length) { - return []; - } - var result = []; - for (var i = 0; true; i++) { - var value = []; - for (var j = 0; j < arguments.length; j++) { - var arr = arguments[j]; - // If i is larger than the array length, this is the shortest array. - if (i >= arr.length) { - return result; - } - value.push(arr[i]); - } - result.push(value); - } -}; +goog.define('goog.Disposable.MONITORING_MODE', 0); /** - * Shuffles the values in the specified array using the Fisher-Yates in-place - * shuffle (also known as the Knuth Shuffle). By default, calls Math.random() - * and so resets the state of that random number generator. Similarly, may reset - * the state of the any other specified random number generator. - * - * Runtime: O(n) - * - * @param {!Array<?>} arr The array to be shuffled. - * @param {function():number=} opt_randFn Optional random function to use for - * shuffling. - * Takes no arguments, and returns a random number on the interval [0, 1). - * Defaults to Math.random() using JavaScript's built-in Math library. + * @define {boolean} Whether to attach creation stack to each created disposable + * instance; This is only relevant for when MonitoringMode != OFF. */ -goog.array.shuffle = function(arr, opt_randFn) { - var randFn = opt_randFn || Math.random; +goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true); - for (var i = arr.length - 1; i > 0; i--) { - // Choose a random array index in [0, i] (inclusive with i). - var j = Math.floor(randFn() * (i + 1)); - var tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; +/** + * Maps the unique ID of every undisposed {@code goog.Disposable} object to + * the object itself. + * @type {!Object<number, !goog.Disposable>} + * @private + */ +goog.Disposable.instances_ = {}; + + +/** + * @return {!Array<!goog.Disposable>} All {@code goog.Disposable} objects that + * haven't been disposed of. + */ +goog.Disposable.getUndisposedObjects = function() { + var ret = []; + for (var id in goog.Disposable.instances_) { + if (goog.Disposable.instances_.hasOwnProperty(id)) { + ret.push(goog.Disposable.instances_[Number(id)]); + } } + return ret; }; /** - * Returns a new array of elements from arr, based on the indexes of elements - * provided by index_arr. For example, the result of index copying - * ['a', 'b', 'c'] with index_arr [1,0,0,2] is ['b', 'a', 'a', 'c']. - * - * @param {!Array<T>} arr The array to get a indexed copy from. - * @param {!Array<number>} index_arr An array of indexes to get from arr. - * @return {!Array<T>} A new array of elements from arr in index_arr order. - * @template T + * Clears the registry of undisposed objects but doesn't dispose of them. */ -goog.array.copyByIndex = function(arr, index_arr) { - var result = []; - goog.array.forEach(index_arr, function(index) { - result.push(arr[index]); - }); - return result; +goog.Disposable.clearUndisposedObjects = function() { + goog.Disposable.instances_ = {}; }; -goog.provide('ol.array'); -goog.require('goog.array'); -goog.require('goog.asserts'); +/** + * Whether the object has been disposed of. + * @type {boolean} + * @private + */ +goog.Disposable.prototype.disposed_ = false; /** - * @param {Array.<number>} arr Array. - * @param {number} target Target. - * @return {number} Index. + * Callbacks to invoke when this object is disposed. + * @type {Array<!Function>} + * @private */ -ol.array.binaryFindNearest = function(arr, target) { - var index = goog.array.binarySearch(arr, target, - /** - * @param {number} a A. - * @param {number} b B. - * @return {number} b minus a. - */ - function(a, b) { - return b - a; - }); - if (index >= 0) { - return index; - } else if (index == -1) { - return 0; - } else if (index == -arr.length - 1) { - return arr.length - 1; - } else { - var left = -index - 2; - var right = -index - 1; - if (arr[left] - target < target - arr[right]) { - return left; - } else { - return right; - } - } -}; +goog.Disposable.prototype.onDisposeCallbacks_; /** - * Whether the array contains the given object. - * @param {Array.<*>} arr The array to test for the presence of the element. - * @param {*} obj The object for which to test. - * @return {boolean} The object is in the array. + * If monitoring the goog.Disposable instances is enabled, stores the creation + * stack trace of the Disposable instance. + * @const {string} */ -ol.array.includes = function(arr, obj) { - return arr.indexOf(obj) >= 0; +goog.Disposable.prototype.creationStack; + + +/** + * @return {boolean} Whether the object has been disposed of. + * @override + */ +goog.Disposable.prototype.isDisposed = function() { + return this.disposed_; }; /** - * @param {Array.<number>} arr Array. - * @param {number} target Target. - * @param {number} direction 0 means return the nearest, > 0 - * means return the largest nearest, < 0 means return the - * smallest nearest. - * @return {number} Index. + * @return {boolean} Whether the object has been disposed of. + * @deprecated Use {@link #isDisposed} instead. */ -ol.array.linearFindNearest = function(arr, target, direction) { - var n = arr.length; - if (arr[0] <= target) { - return 0; - } else if (target <= arr[n - 1]) { - return n - 1; - } else { - var i; - if (direction > 0) { - for (i = 1; i < n; ++i) { - if (arr[i] < target) { - return i - 1; - } - } - } else if (direction < 0) { - for (i = 1; i < n; ++i) { - if (arr[i] <= target) { - return i; - } - } - } else { - for (i = 1; i < n; ++i) { - if (arr[i] == target) { - return i; - } else if (arr[i] < target) { - if (arr[i - 1] - target < target - arr[i]) { - return i - 1; - } else { - return i; - } - } - } - } - // We should never get here, but the compiler complains - // if it finds a path for which no number is returned. - goog.asserts.fail(); - return n - 1; - } -}; +goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed; /** - * @param {Array.<*>} arr Array. - * @param {number} begin Begin index. - * @param {number} end End index. + * Disposes of the object. If the object hasn't already been disposed of, calls + * {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should + * override {@link #disposeInternal} in order to delete references to COM + * objects, DOM nodes, and other disposable objects. Reentrant. + * + * @return {void} Nothing. + * @override */ -ol.array.reverseSubArray = function(arr, begin, end) { - goog.asserts.assert(begin >= 0, - 'Array begin index should be equal to or greater than 0'); - goog.asserts.assert(end < arr.length, - 'Array end index should be less than the array length'); - while (begin < end) { - var tmp = arr[begin]; - arr[begin] = arr[end]; - arr[end] = tmp; - ++begin; - --end; +goog.Disposable.prototype.dispose = function() { + if (!this.disposed_) { + // Set disposed_ to true first, in case during the chain of disposal this + // gets disposed recursively. + this.disposed_ = true; + this.disposeInternal(); + if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) { + var uid = goog.getUid(this); + if (goog.Disposable.MONITORING_MODE == + goog.Disposable.MonitoringMode.PERMANENT && + !goog.Disposable.instances_.hasOwnProperty(uid)) { + throw Error(this + ' did not call the goog.Disposable base ' + + 'constructor or was disposed of after a clearUndisposedObjects ' + + 'call'); + } + delete goog.Disposable.instances_[uid]; + } } }; -goog.provide('ol.ResolutionConstraint'); -goog.provide('ol.ResolutionConstraintType'); - -goog.require('ol.array'); -goog.require('ol.math'); - - -/** - * @typedef {function((number|undefined), number, number): (number|undefined)} - */ -ol.ResolutionConstraintType; - /** - * @param {Array.<number>} resolutions Resolutions. - * @return {ol.ResolutionConstraintType} Zoom function. + * Associates a disposable object with this object so that they will be disposed + * together. + * @param {goog.disposable.IDisposable} disposable that will be disposed when + * this object is disposed. */ -ol.ResolutionConstraint.createSnapToResolutions = - function(resolutions) { - return ( - /** - * @param {number|undefined} resolution Resolution. - * @param {number} delta Delta. - * @param {number} direction Direction. - * @return {number|undefined} Resolution. - */ - function(resolution, delta, direction) { - if (resolution !== undefined) { - var z = - ol.array.linearFindNearest(resolutions, resolution, direction); - z = ol.math.clamp(z + delta, 0, resolutions.length - 1); - return resolutions[z]; - } else { - return undefined; - } - }); +goog.Disposable.prototype.registerDisposable = function(disposable) { + this.addOnDisposeCallback(goog.partial(goog.dispose, disposable)); }; /** - * @param {number} power Power. - * @param {number} maxResolution Maximum resolution. - * @param {number=} opt_maxLevel Maximum level. - * @return {ol.ResolutionConstraintType} Zoom function. + * Invokes a callback function when this object is disposed. Callbacks are + * invoked in the order in which they were added. If a callback is added to + * an already disposed Disposable, it will be called immediately. + * @param {function(this:T):?} callback The callback function. + * @param {T=} opt_scope An optional scope to call the callback in. + * @template T */ -ol.ResolutionConstraint.createSnapToPower = - function(power, maxResolution, opt_maxLevel) { - return ( - /** - * @param {number|undefined} resolution Resolution. - * @param {number} delta Delta. - * @param {number} direction Direction. - * @return {number|undefined} Resolution. - */ - function(resolution, delta, direction) { - if (resolution !== undefined) { - var offset; - if (direction > 0) { - offset = 0; - } else if (direction < 0) { - offset = 1; - } else { - offset = 0.5; - } - var oldLevel = Math.floor( - Math.log(maxResolution / resolution) / Math.log(power) + offset); - var newLevel = Math.max(oldLevel + delta, 0); - if (opt_maxLevel !== undefined) { - newLevel = Math.min(newLevel, opt_maxLevel); - } - return maxResolution / Math.pow(power, newLevel); - } else { - return undefined; - } - }); -}; - -goog.provide('ol.RotationConstraint'); -goog.provide('ol.RotationConstraintType'); - -goog.require('ol.math'); - +goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) { + if (this.disposed_) { + callback.call(opt_scope); + return; + } + if (!this.onDisposeCallbacks_) { + this.onDisposeCallbacks_ = []; + } -/** - * @typedef {function((number|undefined), number): (number|undefined)} - */ -ol.RotationConstraintType; + this.onDisposeCallbacks_.push( + goog.isDef(opt_scope) ? goog.bind(callback, opt_scope) : callback); +}; /** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. + * Deletes or nulls out any references to COM objects, DOM nodes, or other + * disposable objects. Classes that extend {@code goog.Disposable} should + * override this method. + * Not reentrant. To avoid calling it twice, it must only be called from the + * subclass' {@code disposeInternal} method. Everywhere else the public + * {@code dispose} method must be used. + * For example: + * <pre> + * mypackage.MyClass = function() { + * mypackage.MyClass.base(this, 'constructor'); + * // Constructor logic specific to MyClass. + * ... + * }; + * goog.inherits(mypackage.MyClass, goog.Disposable); + * + * mypackage.MyClass.prototype.disposeInternal = function() { + * // Dispose logic specific to MyClass. + * ... + * // Call superclass's disposeInternal at the end of the subclass's, like + * // in C++, to avoid hard-to-catch issues. + * mypackage.MyClass.base(this, 'disposeInternal'); + * }; + * </pre> + * @protected */ -ol.RotationConstraint.disable = function(rotation, delta) { - if (rotation !== undefined) { - return 0; - } else { - return undefined; +goog.Disposable.prototype.disposeInternal = function() { + if (this.onDisposeCallbacks_) { + while (this.onDisposeCallbacks_.length) { + this.onDisposeCallbacks_.shift()(); + } } }; /** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. + * Returns True if we can verify the object is disposed. + * Calls {@code isDisposed} on the argument if it supports it. If obj + * is not an object with an isDisposed() method, return false. + * @param {*} obj The object to investigate. + * @return {boolean} True if we can verify the object is disposed. */ -ol.RotationConstraint.none = function(rotation, delta) { - if (rotation !== undefined) { - return rotation + delta; - } else { - return undefined; +goog.Disposable.isDisposed = function(obj) { + if (obj && typeof obj.isDisposed == 'function') { + return obj.isDisposed(); } + return false; }; /** - * @param {number} n N. - * @return {ol.RotationConstraintType} Rotation constraint. + * Calls {@code dispose} on the argument if it supports it. If obj is not an + * object with a dispose() method, this is a no-op. + * @param {*} obj The object to dispose of. */ -ol.RotationConstraint.createSnapToN = function(n) { - var theta = 2 * Math.PI / n; - return ( - /** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. - */ - function(rotation, delta) { - if (rotation !== undefined) { - rotation = Math.floor((rotation + delta) / theta + 0.5) * theta; - return rotation; - } else { - return undefined; - } - }); +goog.dispose = function(obj) { + if (obj && typeof obj.dispose == 'function') { + obj.dispose(); + } }; /** - * @param {number=} opt_tolerance Tolerance. - * @return {ol.RotationConstraintType} Rotation constraint. + * Calls {@code dispose} on each member of the list that supports it. (If the + * member is an ArrayLike, then {@code goog.disposeAll()} will be called + * recursively on each of its members.) If the member is not an object with a + * {@code dispose()} method, then it is ignored. + * @param {...*} var_args The list. */ -ol.RotationConstraint.createSnapToZero = function(opt_tolerance) { - var tolerance = opt_tolerance || ol.math.toRadians(5); - return ( - /** - * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. - * @return {number|undefined} Rotation. - */ - function(rotation, delta) { - if (rotation !== undefined) { - if (Math.abs(rotation + delta) <= tolerance) { - return 0; - } else { - return rotation + delta; - } - } else { - return undefined; - } - }); +goog.disposeAll = function(var_args) { + for (var i = 0, len = arguments.length; i < len; ++i) { + var disposable = arguments[i]; + if (goog.isArrayLike(disposable)) { + goog.disposeAll.apply(null, disposable); + } else { + goog.dispose(disposable); + } + } }; -goog.provide('ol.Constraints'); +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -goog.require('ol.CenterConstraintType'); -goog.require('ol.ResolutionConstraintType'); -goog.require('ol.RotationConstraintType'); +goog.provide('goog.events.EventId'); /** + * A templated class that is used when registering for events. Typical usage: + * <code> + * /** @type {goog.events.EventId<MyEventObj>} + * var myEventId = new goog.events.EventId( + * goog.events.getUniqueId(('someEvent')); + * + * // No need to cast or declare here since the compiler knows the correct + * // type of 'evt' (MyEventObj). + * something.listen(myEventId, function(evt) {}); + * </code> + * + * @param {string} eventId + * @template T * @constructor - * @param {ol.CenterConstraintType} centerConstraint Center constraint. - * @param {ol.ResolutionConstraintType} resolutionConstraint - * Resolution constraint. - * @param {ol.RotationConstraintType} rotationConstraint - * Rotation constraint. + * @struct + * @final */ -ol.Constraints = - function(centerConstraint, resolutionConstraint, rotationConstraint) { - - /** - * @type {ol.CenterConstraintType} - */ - this.center = centerConstraint; - - /** - * @type {ol.ResolutionConstraintType} - */ - this.resolution = resolutionConstraint; +goog.events.EventId = function(eventId) { + /** @const */ this.id = eventId; +}; - /** - * @type {ol.RotationConstraintType} - */ - this.rotation = rotationConstraint; +/** + * @override + */ +goog.events.EventId.prototype.toString = function() { + return this.id; }; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// Copyright 2005 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9098,151 +8947,136 @@ ol.Constraints = // limitations under the License. /** - * @fileoverview A global registry for entry points into a program, - * so that they can be instrumented. Each module should register their - * entry points with this registry. Designed to be compiled out - * if no instrumentation is requested. - * - * Entry points may be registered before or after a call to - * goog.debug.entryPointRegistry.monitorAll. If an entry point is registered - * later, the existing monitor will instrument the new entry point. + * @fileoverview A base class for event objects. * - * @author nicksantos@google.com (Nick Santos) */ -goog.provide('goog.debug.EntryPointMonitor'); -goog.provide('goog.debug.entryPointRegistry'); - -goog.require('goog.asserts'); - +goog.provide('goog.events.Event'); +goog.provide('goog.events.EventLike'); /** - * @interface + * goog.events.Event no longer depends on goog.Disposable. Keep requiring + * goog.Disposable here to not break projects which assume this dependency. + * @suppress {extraRequire} */ -goog.debug.EntryPointMonitor = function() {}; +goog.require('goog.Disposable'); +goog.require('goog.events.EventId'); /** - * Instruments a function. - * - * @param {!Function} fn A function to instrument. - * @return {!Function} The instrumented function. + * A typedef for event like objects that are dispatchable via the + * goog.events.dispatchEvent function. strings are treated as the type for a + * goog.events.Event. Objects are treated as an extension of a new + * goog.events.Event with the type property of the object being used as the type + * of the Event. + * @typedef {string|Object|goog.events.Event|goog.events.EventId} */ -goog.debug.EntryPointMonitor.prototype.wrap; +goog.events.EventLike; + /** - * Try to remove an instrumentation wrapper created by this monitor. - * If the function passed to unwrap is not a wrapper created by this - * monitor, then we will do nothing. - * - * Notice that some wrappers may not be unwrappable. For example, if other - * monitors have applied their own wrappers, then it will be impossible to - * unwrap them because their wrappers will have captured our wrapper. - * - * So it is important that entry points are unwrapped in the reverse - * order that they were wrapped. + * A base class for event objects, so that they can support preventDefault and + * stopPropagation. * - * @param {!Function} fn A function to unwrap. - * @return {!Function} The unwrapped function, or {@code fn} if it was not - * a wrapped function created by this monitor. + * @param {string|!goog.events.EventId} type Event Type. + * @param {Object=} opt_target Reference to the object that is the target of + * this event. It has to implement the {@code EventTarget} interface + * declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}. + * @constructor */ -goog.debug.EntryPointMonitor.prototype.unwrap; +goog.events.Event = function(type, opt_target) { + /** + * Event type. + * @type {string} + */ + this.type = type instanceof goog.events.EventId ? String(type) : type; + + /** + * TODO(tbreisacher): The type should probably be + * EventTarget|goog.events.EventTarget. + * + * Target of the event. + * @type {Object|undefined} + */ + this.target = opt_target; + /** + * Object that had the listener attached. + * @type {Object|undefined} + */ + this.currentTarget = this.target; -/** - * An array of entry point callbacks. - * @type {!Array<function(!Function)>} - * @private - */ -goog.debug.entryPointRegistry.refList_ = []; + /** + * Whether to cancel the event in internal capture/bubble processing for IE. + * @type {boolean} + * @public + * @suppress {underscore|visibility} Technically public, but referencing this + * outside this package is strongly discouraged. + */ + this.propagationStopped_ = false; + + /** + * Whether the default action has been prevented. + * This is a property to match the W3C specification at + * {@link http://www.w3.org/TR/DOM-Level-3-Events/ + * #events-event-type-defaultPrevented}. + * Must be treated as read-only outside the class. + * @type {boolean} + */ + this.defaultPrevented = false; + + /** + * Return value for in internal capture/bubble processing for IE. + * @type {boolean} + * @public + * @suppress {underscore|visibility} Technically public, but referencing this + * outside this package is strongly discouraged. + */ + this.returnValue_ = true; +}; /** - * Monitors that should wrap all the entry points. - * @type {!Array<!goog.debug.EntryPointMonitor>} - * @private + * Stops event propagation. */ -goog.debug.entryPointRegistry.monitors_ = []; +goog.events.Event.prototype.stopPropagation = function() { + this.propagationStopped_ = true; +}; /** - * Whether goog.debug.entryPointRegistry.monitorAll has ever been called. - * Checking this allows the compiler to optimize out the registrations. - * @type {boolean} - * @private + * Prevents the default action, for example a link redirecting to a url. */ -goog.debug.entryPointRegistry.monitorsMayExist_ = false; +goog.events.Event.prototype.preventDefault = function() { + this.defaultPrevented = true; + this.returnValue_ = false; +}; /** - * Register an entry point with this module. - * - * The entry point will be instrumented when a monitor is passed to - * goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the - * entry point is instrumented immediately. - * - * @param {function(!Function)} callback A callback function which is called - * with a transforming function to instrument the entry point. The callback - * is responsible for wrapping the relevant entry point with the - * transforming function. + * Stops the propagation of the event. It is equivalent to + * {@code e.stopPropagation()}, but can be used as the callback argument of + * {@link goog.events.listen} without declaring another function. + * @param {!goog.events.Event} e An event. */ -goog.debug.entryPointRegistry.register = function(callback) { - // Don't use push(), so that this can be compiled out. - goog.debug.entryPointRegistry.refList_[ - goog.debug.entryPointRegistry.refList_.length] = callback; - // If no one calls monitorAll, this can be compiled out. - if (goog.debug.entryPointRegistry.monitorsMayExist_) { - var monitors = goog.debug.entryPointRegistry.monitors_; - for (var i = 0; i < monitors.length; i++) { - callback(goog.bind(monitors[i].wrap, monitors[i])); - } - } +goog.events.Event.stopPropagation = function(e) { + e.stopPropagation(); }; /** - * Configures a monitor to wrap all entry points. - * - * Entry points that have already been registered are immediately wrapped by - * the monitor. When an entry point is registered in the future, it will also - * be wrapped by the monitor when it is registered. - * - * @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor. - */ -goog.debug.entryPointRegistry.monitorAll = function(monitor) { - goog.debug.entryPointRegistry.monitorsMayExist_ = true; - var transformer = goog.bind(monitor.wrap, monitor); - for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) { - goog.debug.entryPointRegistry.refList_[i](transformer); - } - goog.debug.entryPointRegistry.monitors_.push(monitor); -}; - - -/** - * Try to unmonitor all the entry points that have already been registered. If - * an entry point is registered in the future, it will not be wrapped by the - * monitor when it is registered. Note that this may fail if the entry points - * have additional wrapping. - * - * @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap - * the entry points. - * @throws {Error} If the monitor is not the most recently configured monitor. + * Prevents the default action. It is equivalent to + * {@code e.preventDefault()}, but can be used as the callback argument of + * {@link goog.events.listen} without declaring another function. + * @param {!goog.events.Event} e An event. */ -goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) { - var monitors = goog.debug.entryPointRegistry.monitors_; - goog.asserts.assert(monitor == monitors[monitors.length - 1], - 'Only the most recent monitor can be unwrapped.'); - var transformer = goog.bind(monitor.unwrap, monitor); - for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) { - goog.debug.entryPointRegistry.refList_[i](transformer); - } - monitors.length--; +goog.events.Event.preventDefault = function(e) { + e.preventDefault(); }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// Copyright 2010 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9257,141 +9091,230 @@ goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) { // limitations under the License. /** - * @fileoverview Utilities used by goog.labs.userAgent tools. These functions - * should not be used outside of goog.labs.userAgent.*. - * + * @fileoverview Event Types. * - * @author nnaze@google.com (Nathan Naze) + * @author arv@google.com (Erik Arvidsson) */ -goog.provide('goog.labs.userAgent.util'); -goog.require('goog.string'); +goog.provide('goog.events.EventType'); + +goog.require('goog.userAgent'); /** - * Gets the native userAgent string from navigator if it exists. - * If navigator or navigator.userAgent string is missing, returns an empty - * string. - * @return {string} + * Returns a prefixed event name for the current browser. + * @param {string} eventName The name of the event. + * @return {string} The prefixed event name. + * @suppress {missingRequire|missingProvide} * @private */ -goog.labs.userAgent.util.getNativeUserAgentString_ = function() { - var navigator = goog.labs.userAgent.util.getNavigator_(); - if (navigator) { - var userAgent = navigator.userAgent; - if (userAgent) { - return userAgent; - } - } - return ''; +goog.events.getVendorPrefixedName_ = function(eventName) { + return goog.userAgent.WEBKIT ? 'webkit' + eventName : + (goog.userAgent.OPERA ? 'o' + eventName.toLowerCase() : + eventName.toLowerCase()); }; /** - * Getter for the native navigator. - * This is a separate function so it can be stubbed out in testing. - * @return {Navigator} - * @private + * Constants for event names. + * @enum {string} */ -goog.labs.userAgent.util.getNavigator_ = function() { - return goog.global.navigator; -}; +goog.events.EventType = { + // Mouse events + CLICK: 'click', + RIGHTCLICK: 'rightclick', + DBLCLICK: 'dblclick', + MOUSEDOWN: 'mousedown', + MOUSEUP: 'mouseup', + MOUSEOVER: 'mouseover', + MOUSEOUT: 'mouseout', + MOUSEMOVE: 'mousemove', + MOUSEENTER: 'mouseenter', + MOUSELEAVE: 'mouseleave', + // Select start is non-standard. + // See http://msdn.microsoft.com/en-us/library/ie/ms536969(v=vs.85).aspx. + SELECTSTART: 'selectstart', // IE, Safari, Chrome + // Wheel events + // http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents + WHEEL: 'wheel', -/** - * A possible override for applications which wish to not check - * navigator.userAgent but use a specified value for detection instead. - * @private {string} - */ -goog.labs.userAgent.util.userAgent_ = - goog.labs.userAgent.util.getNativeUserAgentString_(); + // Key events + KEYPRESS: 'keypress', + KEYDOWN: 'keydown', + KEYUP: 'keyup', + // Focus + BLUR: 'blur', + FOCUS: 'focus', + DEACTIVATE: 'deactivate', // IE only + // NOTE: The following two events are not stable in cross-browser usage. + // WebKit and Opera implement DOMFocusIn/Out. + // IE implements focusin/out. + // Gecko implements neither see bug at + // https://bugzilla.mozilla.org/show_bug.cgi?id=396927. + // The DOM Events Level 3 Draft deprecates DOMFocusIn in favor of focusin: + // http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html + // You can use FOCUS in Capture phase until implementations converge. + FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn', + FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut', -/** - * Applications may override browser detection on the built in - * navigator.userAgent object by setting this string. Set to null to use the - * browser object instead. - * @param {?string=} opt_userAgent The User-Agent override. - */ -goog.labs.userAgent.util.setUserAgent = function(opt_userAgent) { - goog.labs.userAgent.util.userAgent_ = opt_userAgent || - goog.labs.userAgent.util.getNativeUserAgentString_(); -}; + // Forms + CHANGE: 'change', + RESET: 'reset', + SELECT: 'select', + SUBMIT: 'submit', + INPUT: 'input', + PROPERTYCHANGE: 'propertychange', // IE only + // Drag and drop + DRAGSTART: 'dragstart', + DRAG: 'drag', + DRAGENTER: 'dragenter', + DRAGOVER: 'dragover', + DRAGLEAVE: 'dragleave', + DROP: 'drop', + DRAGEND: 'dragend', -/** - * @return {string} The user agent string. - */ -goog.labs.userAgent.util.getUserAgent = function() { - return goog.labs.userAgent.util.userAgent_; -}; + // Touch events + // Note that other touch events exist, but we should follow the W3C list here. + // http://www.w3.org/TR/touch-events/#list-of-touchevent-types + TOUCHSTART: 'touchstart', + TOUCHMOVE: 'touchmove', + TOUCHEND: 'touchend', + TOUCHCANCEL: 'touchcancel', + // Misc + BEFOREUNLOAD: 'beforeunload', + CONSOLEMESSAGE: 'consolemessage', + CONTEXTMENU: 'contextmenu', + DOMCONTENTLOADED: 'DOMContentLoaded', + ERROR: 'error', + HELP: 'help', + LOAD: 'load', + LOSECAPTURE: 'losecapture', + ORIENTATIONCHANGE: 'orientationchange', + READYSTATECHANGE: 'readystatechange', + RESIZE: 'resize', + SCROLL: 'scroll', + UNLOAD: 'unload', -/** - * @param {string} str - * @return {boolean} Whether the user agent contains the given string, ignoring - * case. - */ -goog.labs.userAgent.util.matchUserAgent = function(str) { - var userAgent = goog.labs.userAgent.util.getUserAgent(); - return goog.string.contains(userAgent, str); -}; + // HTML 5 History events + // See http://www.w3.org/TR/html5/browsers.html#event-definitions-0 + HASHCHANGE: 'hashchange', + PAGEHIDE: 'pagehide', + PAGESHOW: 'pageshow', + POPSTATE: 'popstate', + // Copy and Paste + // Support is limited. Make sure it works on your favorite browser + // before using. + // http://www.quirksmode.org/dom/events/cutcopypaste.html + COPY: 'copy', + PASTE: 'paste', + CUT: 'cut', + BEFORECOPY: 'beforecopy', + BEFORECUT: 'beforecut', + BEFOREPASTE: 'beforepaste', -/** - * @param {string} str - * @return {boolean} Whether the user agent contains the given string. - */ -goog.labs.userAgent.util.matchUserAgentIgnoreCase = function(str) { - var userAgent = goog.labs.userAgent.util.getUserAgent(); - return goog.string.caseInsensitiveContains(userAgent, str); -}; + // HTML5 online/offline events. + // http://www.w3.org/TR/offline-webapps/#related + ONLINE: 'online', + OFFLINE: 'offline', + // HTML 5 worker events + MESSAGE: 'message', + CONNECT: 'connect', -/** - * Parses the user agent into tuples for each section. - * @param {string} userAgent - * @return {!Array<!Array<string>>} Tuples of key, version, and the contents - * of the parenthetical. - */ -goog.labs.userAgent.util.extractVersionTuples = function(userAgent) { - // Matches each section of a user agent string. - // Example UA: - // Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) - // AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405 - // This has three version tuples: Mozilla, AppleWebKit, and Mobile. + // CSS animation events. + /** @suppress {missingRequire} */ + ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'), + /** @suppress {missingRequire} */ + ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'), + /** @suppress {missingRequire} */ + ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'), - var versionRegExp = new RegExp( - // Key. Note that a key may have a space. - // (i.e. 'Mobile Safari' in 'Mobile Safari/5.0') - '(\\w[\\w ]+)' + + // CSS transition events. Based on the browser support described at: + // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility + /** @suppress {missingRequire} */ + TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'), - '/' + // slash - '([^\\s]+)' + // version (i.e. '5.0b') - '\\s*' + // whitespace - '(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched. - 'g'); + // W3C Pointer Events + // http://www.w3.org/TR/pointerevents/ + POINTERDOWN: 'pointerdown', + POINTERUP: 'pointerup', + POINTERCANCEL: 'pointercancel', + POINTERMOVE: 'pointermove', + POINTEROVER: 'pointerover', + POINTEROUT: 'pointerout', + POINTERENTER: 'pointerenter', + POINTERLEAVE: 'pointerleave', + GOTPOINTERCAPTURE: 'gotpointercapture', + LOSTPOINTERCAPTURE: 'lostpointercapture', - var data = []; - var match; + // IE specific events. + // See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx + // Note: these events will be supplanted in IE11. + MSGESTURECHANGE: 'MSGestureChange', + MSGESTUREEND: 'MSGestureEnd', + MSGESTUREHOLD: 'MSGestureHold', + MSGESTURESTART: 'MSGestureStart', + MSGESTURETAP: 'MSGestureTap', + MSGOTPOINTERCAPTURE: 'MSGotPointerCapture', + MSINERTIASTART: 'MSInertiaStart', + MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture', + MSPOINTERCANCEL: 'MSPointerCancel', + MSPOINTERDOWN: 'MSPointerDown', + MSPOINTERENTER: 'MSPointerEnter', + MSPOINTERHOVER: 'MSPointerHover', + MSPOINTERLEAVE: 'MSPointerLeave', + MSPOINTERMOVE: 'MSPointerMove', + MSPOINTEROUT: 'MSPointerOut', + MSPOINTEROVER: 'MSPointerOver', + MSPOINTERUP: 'MSPointerUp', - // Iterate and collect the version tuples. Each iteration will be the - // next regex match. - while (match = versionRegExp.exec(userAgent)) { - data.push([ - match[1], // key - match[2], // value - // || undefined as this is not undefined in IE7 and IE8 - match[3] || undefined // info - ]); - } + // Native IMEs/input tools events. + TEXT: 'text', + TEXTINPUT: 'textInput', + COMPOSITIONSTART: 'compositionstart', + COMPOSITIONUPDATE: 'compositionupdate', + COMPOSITIONEND: 'compositionend', - return data; -}; + // Webview tag events + // See http://developer.chrome.com/dev/apps/webview_tag.html + EXIT: 'exit', + LOADABORT: 'loadabort', + LOADCOMMIT: 'loadcommit', + LOADREDIRECT: 'loadredirect', + LOADSTART: 'loadstart', + LOADSTOP: 'loadstop', + RESPONSIVE: 'responsive', + SIZECHANGED: 'sizechanged', + UNRESPONSIVE: 'unresponsive', + + // HTML5 Page Visibility API. See details at + // {@code goog.labs.dom.PageVisibilityMonitor}. + VISIBILITYCHANGE: 'visibilitychange', + // LocalStorage event. + STORAGE: 'storage', -// Copyright 2006 The Closure Library Authors. All Rights Reserved. + // DOM Level 2 mutation events (deprecated). + DOMSUBTREEMODIFIED: 'DOMSubtreeModified', + DOMNODEINSERTED: 'DOMNodeInserted', + DOMNODEREMOVED: 'DOMNodeRemoved', + DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument', + DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument', + DOMATTRMODIFIED: 'DOMAttrModified', + DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified', + + // Print events. + BEFOREPRINT: 'beforeprint', + AFTERPRINT: 'afterprint' +}; + +// Copyright 2009 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9406,679 +9329,807 @@ goog.labs.userAgent.util.extractVersionTuples = function(userAgent) { // limitations under the License. /** - * @fileoverview Utilities for manipulating objects/maps/hashes. - * @author arv@google.com (Erik Arvidsson) + * @fileoverview Useful compiler idioms. + * + * @author johnlenz@google.com (John Lenz) */ -goog.provide('goog.object'); +goog.provide('goog.reflect'); /** - * Calls a function for each element in an object/map/hash. + * Syntax for object literal casts. + * @see http://go/jscompiler-renaming + * @see https://github.com/google/closure-compiler/wiki/Type-Based-Property-Renaming * - * @param {Object<K,V>} obj The object over which to iterate. - * @param {function(this:T,V,?,Object<K,V>):?} f The function to call - * for every element. This function takes 3 arguments (the value, the - * key and the object) and the return value is ignored. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @template T,K,V + * Use this if you have an object literal whose keys need to have the same names + * as the properties of some class even after they are renamed by the compiler. + * + * @param {!Function} type Type to cast to. + * @param {Object} object Object literal to cast. + * @return {Object} The object literal. */ -goog.object.forEach = function(obj, f, opt_obj) { - for (var key in obj) { - f.call(opt_obj, obj[key], key, obj); - } +goog.reflect.object = function(type, object) { + return object; }; /** - * Calls a function for each element in an object/map/hash. If that call returns - * true, adds the element to a new object. - * - * @param {Object<K,V>} obj The object over which to iterate. - * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to call - * for every element. This - * function takes 3 arguments (the value, the key and the object) - * and should return a boolean. If the return value is true the - * element is added to the result object. If it is false the - * element is not included. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {!Object<K,V>} a new object in which only elements that passed the - * test are present. - * @template T,K,V + * To assert to the compiler that an operation is needed when it would + * otherwise be stripped. For example: + * <code> + * // Force a layout + * goog.reflect.sinkValue(dialog.offsetHeight); + * </code> + * @type {!Function} */ -goog.object.filter = function(obj, f, opt_obj) { - var res = {}; - for (var key in obj) { - if (f.call(opt_obj, obj[key], key, obj)) { - res[key] = obj[key]; - } - } - return res; +goog.reflect.sinkValue = function(x) { + goog.reflect.sinkValue[' '](x); + return x; }; /** - * For every element in an object/map/hash calls a function and inserts the - * result into a new object. - * - * @param {Object<K,V>} obj The object over which to iterate. - * @param {function(this:T,V,?,Object<K,V>):R} f The function to call - * for every element. This function - * takes 3 arguments (the value, the key and the object) - * and should return something. The result will be inserted - * into a new object. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {!Object<K,R>} a new object with the results from f. - * @template T,K,V,R + * The compiler should optimize this function away iff no one ever uses + * goog.reflect.sinkValue. */ -goog.object.map = function(obj, f, opt_obj) { - var res = {}; - for (var key in obj) { - res[key] = f.call(opt_obj, obj[key], key, obj); - } - return res; -}; +goog.reflect.sinkValue[' '] = goog.nullFunction; /** - * Calls a function for each element in an object/map/hash. If any - * call returns true, returns true (without checking the rest). If - * all calls return false, returns false. - * - * @param {Object<K,V>} obj The object to check. - * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to - * call for every element. This function - * takes 3 arguments (the value, the key and the object) and should - * return a boolean. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {boolean} true if any element passes the test. - * @template T,K,V + * Check if a property can be accessed without throwing an exception. + * @param {Object} obj The owner of the property. + * @param {string} prop The property name. + * @return {boolean} Whether the property is accessible. Will also return true + * if obj is null. */ -goog.object.some = function(obj, f, opt_obj) { - for (var key in obj) { - if (f.call(opt_obj, obj[key], key, obj)) { - return true; - } - } +goog.reflect.canAccessProperty = function(obj, prop) { + /** @preserveTry */ + try { + goog.reflect.sinkValue(obj[prop]); + return true; + } catch (e) {} return false; }; +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Calls a function for each element in an object/map/hash. If - * all calls return true, returns true. If any call returns false, returns - * false at this point and does not continue to check the remaining elements. + * @fileoverview A patched, standardized event object for browser events. * - * @param {Object<K,V>} obj The object to check. - * @param {?function(this:T,V,?,Object<K,V>):boolean} f The function to - * call for every element. This function - * takes 3 arguments (the value, the key and the object) and should - * return a boolean. - * @param {T=} opt_obj This is used as the 'this' object within f. - * @return {boolean} false if any element fails the test. - * @template T,K,V + * <pre> + * The patched event object contains the following members: + * - type {string} Event type, e.g. 'click' + * - target {Object} The element that actually triggered the event + * - currentTarget {Object} The element the listener is attached to + * - relatedTarget {Object} For mouseover and mouseout, the previous object + * - offsetX {number} X-coordinate relative to target + * - offsetY {number} Y-coordinate relative to target + * - clientX {number} X-coordinate relative to viewport + * - clientY {number} Y-coordinate relative to viewport + * - screenX {number} X-coordinate relative to the edge of the screen + * - screenY {number} Y-coordinate relative to the edge of the screen + * - button {number} Mouse button. Use isButton() to test. + * - keyCode {number} Key-code + * - ctrlKey {boolean} Was ctrl key depressed + * - altKey {boolean} Was alt key depressed + * - shiftKey {boolean} Was shift key depressed + * - metaKey {boolean} Was meta key depressed + * - defaultPrevented {boolean} Whether the default action has been prevented + * - state {Object} History state object + * + * NOTE: The keyCode member contains the raw browser keyCode. For normalized + * key and character code use {@link goog.events.KeyHandler}. + * </pre> + * + * @author arv@google.com (Erik Arvidsson) */ -goog.object.every = function(obj, f, opt_obj) { - for (var key in obj) { - if (!f.call(opt_obj, obj[key], key, obj)) { - return false; - } - } - return true; -}; + +goog.provide('goog.events.BrowserEvent'); +goog.provide('goog.events.BrowserEvent.MouseButton'); + +goog.require('goog.events.BrowserFeature'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.reflect'); +goog.require('goog.userAgent'); + /** - * Returns the number of key-value pairs in the object map. - * - * @param {Object} obj The object for which to get the number of key-value - * pairs. - * @return {number} The number of key-value pairs in the object map. + * Accepts a browser event object and creates a patched, cross browser event + * object. + * The content of this object will not be initialized if no event object is + * provided. If this is the case, init() needs to be invoked separately. + * @param {Event=} opt_e Browser event object. + * @param {EventTarget=} opt_currentTarget Current target for event. + * @constructor + * @extends {goog.events.Event} */ -goog.object.getCount = function(obj) { - // JS1.5 has __count__ but it has been deprecated so it raises a warning... - // in other words do not use. Also __count__ only includes the fields on the - // actual object and not in the prototype chain. - var rv = 0; - for (var key in obj) { - rv++; - } - return rv; -}; +goog.events.BrowserEvent = function(opt_e, opt_currentTarget) { + goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : ''); + /** + * Target that fired the event. + * @override + * @type {Node} + */ + this.target = null; -/** - * Returns one key from the object map, if any exists. - * For map literals the returned key will be the first one in most of the - * browsers (a know exception is Konqueror). - * - * @param {Object} obj The object to pick a key from. - * @return {string|undefined} The key or undefined if the object is empty. - */ -goog.object.getAnyKey = function(obj) { - for (var key in obj) { - return key; + /** + * Node that had the listener attached. + * @override + * @type {Node|undefined} + */ + this.currentTarget = null; + + /** + * For mouseover and mouseout events, the related object for the event. + * @type {Node} + */ + this.relatedTarget = null; + + /** + * X-coordinate relative to target. + * @type {number} + */ + this.offsetX = 0; + + /** + * Y-coordinate relative to target. + * @type {number} + */ + this.offsetY = 0; + + /** + * X-coordinate relative to the window. + * @type {number} + */ + this.clientX = 0; + + /** + * Y-coordinate relative to the window. + * @type {number} + */ + this.clientY = 0; + + /** + * X-coordinate relative to the monitor. + * @type {number} + */ + this.screenX = 0; + + /** + * Y-coordinate relative to the monitor. + * @type {number} + */ + this.screenY = 0; + + /** + * Which mouse button was pressed. + * @type {number} + */ + this.button = 0; + + /** + * Keycode of key press. + * @type {number} + */ + this.keyCode = 0; + + /** + * Keycode of key press. + * @type {number} + */ + this.charCode = 0; + + /** + * Whether control was pressed at time of event. + * @type {boolean} + */ + this.ctrlKey = false; + + /** + * Whether alt was pressed at time of event. + * @type {boolean} + */ + this.altKey = false; + + /** + * Whether shift was pressed at time of event. + * @type {boolean} + */ + this.shiftKey = false; + + /** + * Whether the meta key was pressed at time of event. + * @type {boolean} + */ + this.metaKey = false; + + /** + * History state object, only set for PopState events where it's a copy of the + * state object provided to pushState or replaceState. + * @type {Object} + */ + this.state = null; + + /** + * Whether the default platform modifier key was pressed at time of event. + * (This is control for all platforms except Mac, where it's Meta.) + * @type {boolean} + */ + this.platformModifierKey = false; + + /** + * The browser event object. + * @private {Event} + */ + this.event_ = null; + + if (opt_e) { + this.init(opt_e, opt_currentTarget); } }; +goog.inherits(goog.events.BrowserEvent, goog.events.Event); /** - * Returns one value from the object map, if any exists. - * For map literals the returned value will be the first one in most of the - * browsers (a know exception is Konqueror). - * - * @param {Object<K,V>} obj The object to pick a value from. - * @return {V|undefined} The value or undefined if the object is empty. - * @template K,V + * Normalized button constants for the mouse. + * @enum {number} */ -goog.object.getAnyValue = function(obj) { - for (var key in obj) { - return obj[key]; - } +goog.events.BrowserEvent.MouseButton = { + LEFT: 0, + MIDDLE: 1, + RIGHT: 2 }; /** - * Whether the object/hash/map contains the given object as a value. - * An alias for goog.object.containsValue(obj, val). - * - * @param {Object<K,V>} obj The object in which to look for val. - * @param {V} val The object for which to check. - * @return {boolean} true if val is present. - * @template K,V + * Static data for mapping mouse buttons. + * @type {!Array<number>} */ -goog.object.contains = function(obj, val) { - return goog.object.containsValue(obj, val); -}; +goog.events.BrowserEvent.IEButtonMap = [ + 1, // LEFT + 4, // MIDDLE + 2 // RIGHT +]; /** - * Returns the values of the object/map/hash. - * - * @param {Object<K,V>} obj The object from which to get the values. - * @return {!Array<V>} The values in the object/map/hash. - * @template K,V + * Accepts a browser event object and creates a patched, cross browser event + * object. + * @param {Event} e Browser event object. + * @param {EventTarget=} opt_currentTarget Current target for event. */ -goog.object.getValues = function(obj) { - var res = []; - var i = 0; - for (var key in obj) { - res[i++] = obj[key]; +goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) { + var type = this.type = e.type; + + /** + * On touch devices use the first "changed touch" as the relevant touch. + * @type {Touch} + */ + var relevantTouch = e.changedTouches ? e.changedTouches[0] : null; + + // TODO(nicksantos): Change this.target to type EventTarget. + this.target = /** @type {Node} */ (e.target) || e.srcElement; + + // TODO(nicksantos): Change this.currentTarget to type EventTarget. + this.currentTarget = /** @type {Node} */ (opt_currentTarget); + + var relatedTarget = /** @type {Node} */ (e.relatedTarget); + if (relatedTarget) { + // There's a bug in FireFox where sometimes, relatedTarget will be a + // chrome element, and accessing any property of it will get a permission + // denied exception. See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=497780 + if (goog.userAgent.GECKO) { + if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) { + relatedTarget = null; + } + } + // TODO(arv): Use goog.events.EventType when it has been refactored into its + // own file. + } else if (type == goog.events.EventType.MOUSEOVER) { + relatedTarget = e.fromElement; + } else if (type == goog.events.EventType.MOUSEOUT) { + relatedTarget = e.toElement; } - return res; -}; + this.relatedTarget = relatedTarget; -/** - * Returns the keys of the object/map/hash. - * - * @param {Object} obj The object from which to get the keys. - * @return {!Array<string>} Array of property keys. - */ -goog.object.getKeys = function(obj) { - var res = []; - var i = 0; - for (var key in obj) { - res[i++] = key; + if (!goog.isNull(relevantTouch)) { + this.clientX = relevantTouch.clientX !== undefined ? + relevantTouch.clientX : relevantTouch.pageX; + this.clientY = relevantTouch.clientY !== undefined ? + relevantTouch.clientY : relevantTouch.pageY; + this.screenX = relevantTouch.screenX || 0; + this.screenY = relevantTouch.screenY || 0; + } else { + // Webkit emits a lame warning whenever layerX/layerY is accessed. + // http://code.google.com/p/chromium/issues/detail?id=101733 + this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ? + e.offsetX : e.layerX; + this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ? + e.offsetY : e.layerY; + this.clientX = e.clientX !== undefined ? e.clientX : e.pageX; + this.clientY = e.clientY !== undefined ? e.clientY : e.pageY; + this.screenX = e.screenX || 0; + this.screenY = e.screenY || 0; + } + + this.button = e.button; + + this.keyCode = e.keyCode || 0; + this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0); + this.ctrlKey = e.ctrlKey; + this.altKey = e.altKey; + this.shiftKey = e.shiftKey; + this.metaKey = e.metaKey; + this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey; + this.state = e.state; + this.event_ = e; + if (e.defaultPrevented) { + this.preventDefault(); } - return res; }; /** - * Get a value from an object multiple levels deep. This is useful for - * pulling values from deeply nested objects, such as JSON responses. - * Example usage: getValueByKeys(jsonObj, 'foo', 'entries', 3) + * Tests to see which button was pressed during the event. This is really only + * useful in IE and Gecko browsers. And in IE, it's only useful for + * mousedown/mouseup events, because click only fires for the left mouse button. * - * @param {!Object} obj An object to get the value from. Can be array-like. - * @param {...(string|number|!Array<number|string>)} var_args A number of keys - * (as strings, or numbers, for array-like objects). Can also be - * specified as a single array of keys. - * @return {*} The resulting value. If, at any point, the value for a key - * is undefined, returns undefined. + * Safari 2 only reports the left button being clicked, and uses the value '1' + * instead of 0. Opera only reports a mousedown event for the middle button, and + * no mouse events for the right button. Opera has default behavior for left and + * middle click that can only be overridden via a configuration setting. + * + * There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html. + * + * @param {goog.events.BrowserEvent.MouseButton} button The button + * to test for. + * @return {boolean} True if button was pressed. */ -goog.object.getValueByKeys = function(obj, var_args) { - var isArrayLike = goog.isArrayLike(var_args); - var keys = isArrayLike ? var_args : arguments; - - // Start with the 2nd parameter for the variable parameters syntax. - for (var i = isArrayLike ? 0 : 1; i < keys.length; i++) { - obj = obj[keys[i]]; - if (!goog.isDef(obj)) { - break; +goog.events.BrowserEvent.prototype.isButton = function(button) { + if (!goog.events.BrowserFeature.HAS_W3C_BUTTON) { + if (this.type == 'click') { + return button == goog.events.BrowserEvent.MouseButton.LEFT; + } else { + return !!(this.event_.button & + goog.events.BrowserEvent.IEButtonMap[button]); } + } else { + return this.event_.button == button; } - - return obj; }; /** - * Whether the object/map/hash contains the given key. + * Whether this has an "action"-producing mouse button. * - * @param {Object} obj The object in which to look for key. - * @param {*} key The key for which to check. - * @return {boolean} true If the map contains the key. + * By definition, this includes left-click on windows/linux, and left-click + * without the ctrl key on Macs. + * + * @return {boolean} The result. */ -goog.object.containsKey = function(obj, key) { - return key in obj; +goog.events.BrowserEvent.prototype.isMouseActionButton = function() { + // Webkit does not ctrl+click to be a right-click, so we + // normalize it to behave like Gecko and Opera. + return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) && + !(goog.userAgent.WEBKIT && goog.userAgent.MAC && this.ctrlKey); }; /** - * Whether the object/map/hash contains the given value. This is O(n). - * - * @param {Object<K,V>} obj The object in which to look for val. - * @param {V} val The value for which to check. - * @return {boolean} true If the map contains the value. - * @template K,V + * @override */ -goog.object.containsValue = function(obj, val) { - for (var key in obj) { - if (obj[key] == val) { - return true; - } +goog.events.BrowserEvent.prototype.stopPropagation = function() { + goog.events.BrowserEvent.superClass_.stopPropagation.call(this); + if (this.event_.stopPropagation) { + this.event_.stopPropagation(); + } else { + this.event_.cancelBubble = true; } - return false; }; /** - * Searches an object for an element that satisfies the given condition and - * returns its key. - * @param {Object<K,V>} obj The object to search in. - * @param {function(this:T,V,string,Object<K,V>):boolean} f The - * function to call for every element. Takes 3 arguments (the value, - * the key and the object) and should return a boolean. - * @param {T=} opt_this An optional "this" context for the function. - * @return {string|undefined} The key of an element for which the function - * returns true or undefined if no such element is found. - * @template T,K,V + * @override */ -goog.object.findKey = function(obj, f, opt_this) { - for (var key in obj) { - if (f.call(opt_this, obj[key], key, obj)) { - return key; +goog.events.BrowserEvent.prototype.preventDefault = function() { + goog.events.BrowserEvent.superClass_.preventDefault.call(this); + var be = this.event_; + if (!be.preventDefault) { + be.returnValue = false; + if (goog.events.BrowserFeature.SET_KEY_CODE_TO_PREVENT_DEFAULT) { + /** @preserveTry */ + try { + // Most keys can be prevented using returnValue. Some special keys + // require setting the keyCode to -1 as well: + // + // In IE7: + // F3, F5, F10, F11, Ctrl+P, Crtl+O, Ctrl+F (these are taken from IE6) + // + // In IE8: + // Ctrl+P, Crtl+O, Ctrl+F (F1-F12 cannot be stopped through the event) + // + // We therefore do this for all function keys as well as when Ctrl key + // is pressed. + var VK_F1 = 112; + var VK_F12 = 123; + if (be.ctrlKey || be.keyCode >= VK_F1 && be.keyCode <= VK_F12) { + be.keyCode = -1; + } + } catch (ex) { + // IE throws an 'access denied' exception when trying to change + // keyCode in some situations (e.g. srcElement is input[type=file], + // or srcElement is an anchor tag rewritten by parent's innerHTML). + // Do nothing in this case. + } } + } else { + be.preventDefault(); } - return undefined; }; /** - * Searches an object for an element that satisfies the given condition and - * returns its value. - * @param {Object<K,V>} obj The object to search in. - * @param {function(this:T,V,string,Object<K,V>):boolean} f The function - * to call for every element. Takes 3 arguments (the value, the key - * and the object) and should return a boolean. - * @param {T=} opt_this An optional "this" context for the function. - * @return {V} The value of an element for which the function returns true or - * undefined if no such element is found. - * @template T,K,V + * @return {Event} The underlying browser event object. */ -goog.object.findValue = function(obj, f, opt_this) { - var key = goog.object.findKey(obj, f, opt_this); - return key && obj[key]; +goog.events.BrowserEvent.prototype.getBrowserEvent = function() { + return this.event_; }; +// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Whether the object/map/hash is empty. - * - * @param {Object} obj The object to test. - * @return {boolean} true if obj is empty. + * @fileoverview An interface for a listenable JavaScript object. + * @author chrishenry@google.com (Chris Henry) */ -goog.object.isEmpty = function(obj) { - for (var key in obj) { - return false; - } - return true; -}; + +goog.provide('goog.events.Listenable'); +goog.provide('goog.events.ListenableKey'); + +/** @suppress {extraRequire} */ +goog.require('goog.events.EventId'); + /** - * Removes all key value pairs from the object/map/hash. + * A listenable interface. A listenable is an object with the ability + * to dispatch/broadcast events to "event listeners" registered via + * listen/listenOnce. * - * @param {Object} obj The object to clear. + * The interface allows for an event propagation mechanism similar + * to one offered by native browser event targets, such as + * capture/bubble mechanism, stopping propagation, and preventing + * default actions. Capture/bubble mechanism depends on the ancestor + * tree constructed via {@code #getParentEventTarget}; this tree + * must be directed acyclic graph. The meaning of default action(s) + * in preventDefault is specific to a particular use case. + * + * Implementations that do not support capture/bubble or can not have + * a parent listenable can simply not implement any ability to set the + * parent listenable (and have {@code #getParentEventTarget} return + * null). + * + * Implementation of this class can be used with or independently from + * goog.events. + * + * Implementation must call {@code #addImplementation(implClass)}. + * + * @interface + * @see goog.events + * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html */ -goog.object.clear = function(obj) { - for (var i in obj) { - delete obj[i]; - } -}; +goog.events.Listenable = function() {}; /** - * Removes a key-value pair based on the key. + * An expando property to indicate that an object implements + * goog.events.Listenable. * - * @param {Object} obj The object from which to remove the key. - * @param {*} key The key to remove. - * @return {boolean} Whether an element was removed. + * See addImplementation/isImplementedBy. + * + * @type {string} + * @const */ -goog.object.remove = function(obj, key) { - var rv; - if ((rv = key in obj)) { - delete obj[key]; - } - return rv; -}; +goog.events.Listenable.IMPLEMENTED_BY_PROP = + 'closure_listenable_' + ((Math.random() * 1e6) | 0); /** - * Adds a key-value pair to the object. Throws an exception if the key is - * already in use. Use set if you want to change an existing pair. - * - * @param {Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {V} val The value to add. - * @template K,V + * Marks a given class (constructor) as an implementation of + * Listenable, do that we can query that fact at runtime. The class + * must have already implemented the interface. + * @param {!Function} cls The class constructor. The corresponding + * class must have already implemented the interface. */ -goog.object.add = function(obj, key, val) { - if (key in obj) { - throw Error('The object already contains the key "' + key + '"'); - } - goog.object.set(obj, key, val); +goog.events.Listenable.addImplementation = function(cls) { + cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true; }; /** - * Returns the value for the given key. - * - * @param {Object<K,V>} obj The object from which to get the value. - * @param {string} key The key for which to get the value. - * @param {R=} opt_val The value to return if no item is found for the given - * key (default is undefined). - * @return {V|R|undefined} The value for the given key. - * @template K,V,R + * @param {Object} obj The object to check. + * @return {boolean} Whether a given instance implements Listenable. The + * class/superclass of the instance must call addImplementation. */ -goog.object.get = function(obj, key, opt_val) { - if (key in obj) { - return obj[key]; - } - return opt_val; +goog.events.Listenable.isImplementedBy = function(obj) { + return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]); }; /** - * Adds a key-value pair to the object/map/hash. + * Adds an event listener. A listener can only be added once to an + * object and if it is added again the key for the listener is + * returned. Note that if the existing listener is a one-off listener + * (registered via listenOnce), it will no longer be a one-off + * listener after a call to listen(). * - * @param {Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {V} value The value to add. - * @template K,V + * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} Unique key for the listener. + * @template SCOPE,EVENTOBJ */ -goog.object.set = function(obj, key, value) { - obj[key] = value; -}; +goog.events.Listenable.prototype.listen; /** - * Adds a key-value pair to the object/map/hash if it doesn't exist yet. + * Adds an event listener that is removed automatically after the + * listener fired once. * - * @param {Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {V} value The value to add if the key wasn't present. - * @return {V} The value of the entry at the end of the function. - * @template K,V + * If an existing listener already exists, listenOnce will do + * nothing. In particular, if the listener was previously registered + * via listen(), listenOnce() will not turn the listener into a + * one-off listener. Similarly, if there is already an existing + * one-off listener, listenOnce does not modify the listeners (it is + * still a once listener). + * + * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} Unique key for the listener. + * @template SCOPE,EVENTOBJ */ -goog.object.setIfUndefined = function(obj, key, value) { - return key in obj ? obj[key] : (obj[key] = value); -}; +goog.events.Listenable.prototype.listenOnce; /** - * Sets a key and value to an object if the key is not set. The value will be - * the return value of the given function. If the key already exists, the - * object will not be changed and the function will not be called (the function - * will be lazily evaluated -- only called if necessary). - * - * This function is particularly useful for use with a map used a as a cache. + * Removes an event listener which was added with listen() or listenOnce(). * - * @param {!Object<K,V>} obj The object to which to add the key-value pair. - * @param {string} key The key to add. - * @param {function():V} f The value to add if the key wasn't present. - * @return {V} The value of the entry at the end of the function. - * @template K,V + * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call + * the listener. + * @return {boolean} Whether any listener was removed. + * @template SCOPE,EVENTOBJ */ -goog.object.setWithReturnValueIfNotSet = function(obj, key, f) { - if (key in obj) { - return obj[key]; - } - - var val = f(); - obj[key] = val; - return val; -}; +goog.events.Listenable.prototype.unlisten; /** - * Compares two objects for equality using === on the values. + * Removes an event listener which was added with listen() by the key + * returned by listen(). * - * @param {!Object<K,V>} a - * @param {!Object<K,V>} b - * @return {boolean} - * @template K,V + * @param {goog.events.ListenableKey} key The key returned by + * listen() or listenOnce(). + * @return {boolean} Whether any listener was removed. */ -goog.object.equals = function(a, b) { - for (var k in a) { - if (!(k in b) || a[k] !== b[k]) { - return false; - } - } - for (var k in b) { - if (!(k in a)) { - return false; - } - } - return true; -}; +goog.events.Listenable.prototype.unlistenByKey; /** - * Does a flat clone of the object. + * Dispatches an event (or event like object) and calls all listeners + * listening for events of this type. The type of the event is decided by the + * type property on the event object. * - * @param {Object<K,V>} obj Object to clone. - * @return {!Object<K,V>} Clone of the input object. - * @template K,V + * If any of the listeners returns false OR calls preventDefault then this + * function will return false. If one of the capture listeners calls + * stopPropagation, then the bubble listeners won't fire. + * + * @param {goog.events.EventLike} e Event object. + * @return {boolean} If anyone called preventDefault on the event object (or + * if any of the listeners returns false) this will also return false. */ -goog.object.clone = function(obj) { - // We cannot use the prototype trick because a lot of methods depend on where - // the actual key is set. - - var res = {}; - for (var key in obj) { - res[key] = obj[key]; - } - return res; - // We could also use goog.mixin but I wanted this to be independent from that. -}; +goog.events.Listenable.prototype.dispatchEvent; /** - * Clones a value. The input may be an Object, Array, or basic type. Objects and - * arrays will be cloned recursively. + * Removes all listeners from this listenable. If type is specified, + * it will only remove listeners of the particular type. otherwise all + * registered listeners will be removed. * - * WARNINGS: - * <code>goog.object.unsafeClone</code> does not detect reference loops. Objects - * that refer to themselves will cause infinite recursion. + * @param {string=} opt_type Type of event to remove, default is to + * remove all types. + * @return {number} Number of listeners removed. + */ +goog.events.Listenable.prototype.removeAllListeners; + + +/** + * Returns the parent of this event target to use for capture/bubble + * mechanism. * - * <code>goog.object.unsafeClone</code> is unaware of unique identifiers, and - * copies UIDs created by <code>getUid</code> into cloned results. + * NOTE(chrishenry): The name reflects the original implementation of + * custom event target ({@code goog.events.EventTarget}). We decided + * that changing the name is not worth it. * - * @param {*} obj The value to clone. - * @return {*} A clone of the input value. + * @return {goog.events.Listenable} The parent EventTarget or null if + * there is no parent. */ -goog.object.unsafeClone = function(obj) { - var type = goog.typeOf(obj); - if (type == 'object' || type == 'array') { - if (goog.isFunction(obj.clone)) { - return obj.clone(); - } - var clone = type == 'array' ? [] : {}; - for (var key in obj) { - clone[key] = goog.object.unsafeClone(obj[key]); - } - return clone; - } - - return obj; -}; +goog.events.Listenable.prototype.getParentEventTarget; /** - * Returns a new object in which all the keys and values are interchanged - * (keys become values and values become keys). If multiple keys map to the - * same value, the chosen transposed value is implementation-dependent. + * Fires all registered listeners in this listenable for the given + * type and capture mode, passing them the given eventObject. This + * does not perform actual capture/bubble. Only implementors of the + * interface should be using this. * - * @param {Object} obj The object to transpose. - * @return {!Object} The transposed object. + * @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the + * listeners to fire. + * @param {boolean} capture The capture mode of the listeners to fire. + * @param {EVENTOBJ} eventObject The event object to fire. + * @return {boolean} Whether all listeners succeeded without + * attempting to prevent default behavior. If any listener returns + * false or called goog.events.Event#preventDefault, this returns + * false. + * @template EVENTOBJ */ -goog.object.transpose = function(obj) { - var transposed = {}; - for (var key in obj) { - transposed[obj[key]] = key; - } - return transposed; -}; +goog.events.Listenable.prototype.fireListeners; /** - * The names of the fields that are defined on Object.prototype. - * @type {Array<string>} - * @private + * Gets all listeners in this listenable for the given type and + * capture mode. + * + * @param {string|!goog.events.EventId} type The type of the listeners to fire. + * @param {boolean} capture The capture mode of the listeners to fire. + * @return {!Array<goog.events.ListenableKey>} An array of registered + * listeners. + * @template EVENTOBJ */ -goog.object.PROTOTYPE_FIELDS_ = [ - 'constructor', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'toLocaleString', - 'toString', - 'valueOf' -]; +goog.events.Listenable.prototype.getListeners; /** - * Extends an object with another object. - * This operates 'in-place'; it does not create a new Object. + * Gets the goog.events.ListenableKey for the event or null if no such + * listener is in use. * - * Example: - * var o = {}; - * goog.object.extend(o, {a: 0, b: 1}); - * o; // {a: 0, b: 1} - * goog.object.extend(o, {b: 2, c: 3}); - * o; // {a: 0, b: 2, c: 3} + * @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event + * without the 'on' prefix. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The + * listener function to get. + * @param {boolean} capture Whether the listener is a capturing listener. + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} the found listener or null if not found. + * @template SCOPE,EVENTOBJ + */ +goog.events.Listenable.prototype.getListener; + + +/** + * Whether there is any active listeners matching the specified + * signature. If either the type or capture parameters are + * unspecified, the function will match on the remaining criteria. * - * @param {Object} target The object to modify. Existing properties will be - * overwritten if they are also present in one of the objects in - * {@code var_args}. - * @param {...Object} var_args The objects from which values will be copied. + * @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type. + * @param {boolean=} opt_capture Whether to check for capture or bubble + * listeners. + * @return {boolean} Whether there is any active listeners matching + * the requested type and/or capture phase. + * @template EVENTOBJ */ -goog.object.extend = function(target, var_args) { - var key, source; - for (var i = 1; i < arguments.length; i++) { - source = arguments[i]; - for (key in source) { - target[key] = source[key]; - } +goog.events.Listenable.prototype.hasListener; - // For IE the for-in-loop does not contain any properties that are not - // enumerable on the prototype object (for example isPrototypeOf from - // Object.prototype) and it will also not include 'replace' on objects that - // extend String and change 'replace' (not that it is common for anyone to - // extend anything except Object). - for (var j = 0; j < goog.object.PROTOTYPE_FIELDS_.length; j++) { - key = goog.object.PROTOTYPE_FIELDS_[j]; - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } -}; + +/** + * An interface that describes a single registered listener. + * @interface + */ +goog.events.ListenableKey = function() {}; /** - * Creates a new object built from the key-value pairs provided as arguments. - * @param {...*} var_args If only one argument is provided and it is an array - * then this is used as the arguments, otherwise even arguments are used as - * the property names and odd arguments are used as the property values. - * @return {!Object} The new object. - * @throws {Error} If there are uneven number of arguments or there is only one - * non array argument. + * Counter used to create a unique key + * @type {number} + * @private */ -goog.object.create = function(var_args) { - var argLength = arguments.length; - if (argLength == 1 && goog.isArray(arguments[0])) { - return goog.object.create.apply(null, arguments[0]); - } +goog.events.ListenableKey.counter_ = 0; - if (argLength % 2) { - throw Error('Uneven number of arguments'); - } - var rv = {}; - for (var i = 0; i < argLength; i += 2) { - rv[arguments[i]] = arguments[i + 1]; - } - return rv; +/** + * Reserves a key to be used for ListenableKey#key field. + * @return {number} A number to be used to fill ListenableKey#key + * field. + */ +goog.events.ListenableKey.reserveKey = function() { + return ++goog.events.ListenableKey.counter_; }; /** - * Creates a new object where the property names come from the arguments but - * the value is always set to true - * @param {...*} var_args If only one argument is provided and it is an array - * then this is used as the arguments, otherwise the arguments are used - * as the property names. - * @return {!Object} The new object. + * The source event target. + * @type {!(Object|goog.events.Listenable|goog.events.EventTarget)} */ -goog.object.createSet = function(var_args) { - var argLength = arguments.length; - if (argLength == 1 && goog.isArray(arguments[0])) { - return goog.object.createSet.apply(null, arguments[0]); - } +goog.events.ListenableKey.prototype.src; - var rv = {}; - for (var i = 0; i < argLength; i++) { - rv[arguments[i]] = true; - } - return rv; -}; + +/** + * The event type the listener is listening to. + * @type {string} + */ +goog.events.ListenableKey.prototype.type; /** - * Creates an immutable view of the underlying object, if the browser - * supports immutable objects. - * - * In default mode, writes to this view will fail silently. In strict mode, - * they will throw an error. - * - * @param {!Object<K,V>} obj An object. - * @return {!Object<K,V>} An immutable view of that object, or the - * original object if this browser does not support immutables. - * @template K,V + * The listener function. + * @type {function(?):?|{handleEvent:function(?):?}|null} */ -goog.object.createImmutableView = function(obj) { - var result = obj; - if (Object.isFrozen && !Object.isFrozen(obj)) { - result = Object.create(obj); - Object.freeze(result); - } - return result; -}; +goog.events.ListenableKey.prototype.listener; /** - * @param {!Object} obj An object. - * @return {boolean} Whether this is an immutable view of the object. + * Whether the listener works on capture phase. + * @type {boolean} */ -goog.object.isImmutableView = function(obj) { - return !!Object.isFrozen && Object.isFrozen(obj); -}; +goog.events.ListenableKey.prototype.capture; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. + +/** + * The 'this' object for the listener function's scope. + * @type {Object} + */ +goog.events.ListenableKey.prototype.handler; + + +/** + * A globally unique number to identify the key. + * @type {number} + */ +goog.events.ListenableKey.prototype.key; + +// Copyright 2005 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -10093,334 +10144,433 @@ goog.object.isImmutableView = function(obj) { // limitations under the License. /** - * @fileoverview Closure user agent detection (Browser). - * @see <a href="http://www.useragentstring.com/">User agent strings</a> - * For more information on rendering engine, platform, or device see the other - * sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform, - * goog.labs.userAgent.device respectively.) - * - * @author martone@google.com (Andy Martone) + * @fileoverview Listener object. + * @see ../demos/events.html */ -goog.provide('goog.labs.userAgent.browser'); - -goog.require('goog.array'); -goog.require('goog.labs.userAgent.util'); -goog.require('goog.object'); -goog.require('goog.string'); - - -// TODO(nnaze): Refactor to remove excessive exclusion logic in matching -// functions. +goog.provide('goog.events.Listener'); +goog.require('goog.events.ListenableKey'); -/** - * @return {boolean} Whether the user's browser is Opera. - * @private - */ -goog.labs.userAgent.browser.matchOpera_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Opera') || - goog.labs.userAgent.util.matchUserAgent('OPR'); -}; /** - * @return {boolean} Whether the user's browser is IE. - * @private + * Simple class that stores information about a listener + * @param {!Function} listener Callback function. + * @param {Function} proxy Wrapper for the listener that patches the event. + * @param {EventTarget|goog.events.Listenable} src Source object for + * the event. + * @param {string} type Event type. + * @param {boolean} capture Whether in capture or bubble phase. + * @param {Object=} opt_handler Object in whose context to execute the callback. + * @implements {goog.events.ListenableKey} + * @constructor */ -goog.labs.userAgent.browser.matchIE_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Trident') || - goog.labs.userAgent.util.matchUserAgent('MSIE'); -}; +goog.events.Listener = function( + listener, proxy, src, type, capture, opt_handler) { + if (goog.events.Listener.ENABLE_MONITORING) { + this.creationStack = new Error().stack; + } + /** + * Callback function. + * @type {Function} + */ + this.listener = listener; -/** - * @return {boolean} Whether the user's browser is Edge. - * @private - */ -goog.labs.userAgent.browser.matchEdge_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Edge'); -}; + /** + * A wrapper over the original listener. This is used solely to + * handle native browser events (it is used to simulate the capture + * phase and to patch the event object). + * @type {Function} + */ + this.proxy = proxy; + /** + * Object or node that callback is listening to + * @type {EventTarget|goog.events.Listenable} + */ + this.src = src; -/** - * @return {boolean} Whether the user's browser is Firefox. - * @private - */ -goog.labs.userAgent.browser.matchFirefox_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Firefox'); -}; + /** + * The event type. + * @const {string} + */ + this.type = type; + /** + * Whether the listener is being called in the capture or bubble phase + * @const {boolean} + */ + this.capture = !!capture; -/** - * @return {boolean} Whether the user's browser is Safari. - * @private - */ -goog.labs.userAgent.browser.matchSafari_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Safari') && - !(goog.labs.userAgent.browser.matchChrome_() || - goog.labs.userAgent.browser.matchCoast_() || - goog.labs.userAgent.browser.matchOpera_() || - goog.labs.userAgent.browser.matchEdge_() || - goog.labs.userAgent.browser.isSilk() || - goog.labs.userAgent.util.matchUserAgent('Android')); -}; + /** + * Optional object whose context to execute the listener in + * @type {Object|undefined} + */ + this.handler = opt_handler; + /** + * The key of the listener. + * @const {number} + * @override + */ + this.key = goog.events.ListenableKey.reserveKey(); -/** - * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based - * iOS browser). - * @private - */ -goog.labs.userAgent.browser.matchCoast_ = function() { - return goog.labs.userAgent.util.matchUserAgent('Coast'); + /** + * Whether to remove the listener after it has been called. + * @type {boolean} + */ + this.callOnce = false; + + /** + * Whether the listener has been removed. + * @type {boolean} + */ + this.removed = false; }; /** - * @return {boolean} Whether the user's browser is iOS Webview. - * @private + * @define {boolean} Whether to enable the monitoring of the + * goog.events.Listener instances. Switching on the monitoring is only + * recommended for debugging because it has a significant impact on + * performance and memory usage. If switched off, the monitoring code + * compiles down to 0 bytes. */ -goog.labs.userAgent.browser.matchIosWebview_ = function() { - // iOS Webview does not show up as Chrome or Safari. Also check for Opera's - // WebKit-based iOS browser, Coast. - return (goog.labs.userAgent.util.matchUserAgent('iPad') || - goog.labs.userAgent.util.matchUserAgent('iPhone')) && - !goog.labs.userAgent.browser.matchSafari_() && - !goog.labs.userAgent.browser.matchChrome_() && - !goog.labs.userAgent.browser.matchCoast_() && - goog.labs.userAgent.util.matchUserAgent('AppleWebKit'); -}; +goog.define('goog.events.Listener.ENABLE_MONITORING', false); /** - * @return {boolean} Whether the user's browser is Chrome. - * @private + * If monitoring the goog.events.Listener instances is enabled, stores the + * creation stack trace of the Disposable instance. + * @type {string} */ -goog.labs.userAgent.browser.matchChrome_ = function() { - return (goog.labs.userAgent.util.matchUserAgent('Chrome') || - goog.labs.userAgent.util.matchUserAgent('CriOS')) && - !goog.labs.userAgent.browser.matchOpera_() && - !goog.labs.userAgent.browser.matchEdge_(); -}; +goog.events.Listener.prototype.creationStack; /** - * @return {boolean} Whether the user's browser is the Android browser. - * @private + * Marks this listener as removed. This also remove references held by + * this listener object (such as listener and event source). */ -goog.labs.userAgent.browser.matchAndroidBrowser_ = function() { - // Android can appear in the user agent string for Chrome on Android. - // This is not the Android standalone browser if it does. - return goog.labs.userAgent.util.matchUserAgent('Android') && - !(goog.labs.userAgent.browser.isChrome() || - goog.labs.userAgent.browser.isFirefox() || - goog.labs.userAgent.browser.isOpera() || - goog.labs.userAgent.browser.isSilk()); +goog.events.Listener.prototype.markAsRemoved = function() { + this.removed = true; + this.listener = null; + this.proxy = null; + this.src = null; + this.handler = null; }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @return {boolean} Whether the user's browser is Opera. + * @fileoverview A map of listeners that provides utility functions to + * deal with listeners on an event target. Used by + * {@code goog.events.EventTarget}. + * + * WARNING: Do not use this class from outside goog.events package. + * + * @visibility {//closure/goog/bin/sizetests:__pkg__} + * @visibility {//closure/goog/events:__pkg__} + * @visibility {//closure/goog/labs/events:__pkg__} */ -goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_; +goog.provide('goog.events.ListenerMap'); -/** - * @return {boolean} Whether the user's browser is IE. - */ -goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_; - +goog.require('goog.array'); +goog.require('goog.events.Listener'); +goog.require('goog.object'); -/** - * @return {boolean} Whether the user's browser is Edge. - */ -goog.labs.userAgent.browser.isEdge = goog.labs.userAgent.browser.matchEdge_; /** - * @return {boolean} Whether the user's browser is Firefox. + * Creates a new listener map. + * @param {EventTarget|goog.events.Listenable} src The src object. + * @constructor + * @final */ -goog.labs.userAgent.browser.isFirefox = - goog.labs.userAgent.browser.matchFirefox_; +goog.events.ListenerMap = function(src) { + /** @type {EventTarget|goog.events.Listenable} */ + this.src = src; + /** + * Maps of event type to an array of listeners. + * @type {Object<string, !Array<!goog.events.Listener>>} + */ + this.listeners = {}; -/** - * @return {boolean} Whether the user's browser is Safari. - */ -goog.labs.userAgent.browser.isSafari = - goog.labs.userAgent.browser.matchSafari_; + /** + * The count of types in this map that have registered listeners. + * @private {number} + */ + this.typeCount_ = 0; +}; /** - * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based - * iOS browser). + * @return {number} The count of event types in this map that actually + * have registered listeners. */ -goog.labs.userAgent.browser.isCoast = - goog.labs.userAgent.browser.matchCoast_; +goog.events.ListenerMap.prototype.getTypeCount = function() { + return this.typeCount_; +}; /** - * @return {boolean} Whether the user's browser is iOS Webview. + * @return {number} Total number of registered listeners. */ -goog.labs.userAgent.browser.isIosWebview = - goog.labs.userAgent.browser.matchIosWebview_; +goog.events.ListenerMap.prototype.getListenerCount = function() { + var count = 0; + for (var type in this.listeners) { + count += this.listeners[type].length; + } + return count; +}; /** - * @return {boolean} Whether the user's browser is Chrome. + * Adds an event listener. A listener can only be added once to an + * object and if it is added again the key for the listener is + * returned. + * + * Note that a one-off listener will not change an existing listener, + * if any. On the other hand a normal listener will change existing + * one-off listener to become a normal listener. + * + * @param {string|!goog.events.EventId} type The listener event type. + * @param {!Function} listener This listener callback method. + * @param {boolean} callOnce Whether the listener is a one-off + * listener. + * @param {boolean=} opt_useCapture The capture mode of the listener. + * @param {Object=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} Unique key for the listener. */ -goog.labs.userAgent.browser.isChrome = - goog.labs.userAgent.browser.matchChrome_; - +goog.events.ListenerMap.prototype.add = function( + type, listener, callOnce, opt_useCapture, opt_listenerScope) { + var typeStr = type.toString(); + var listenerArray = this.listeners[typeStr]; + if (!listenerArray) { + listenerArray = this.listeners[typeStr] = []; + this.typeCount_++; + } -/** - * @return {boolean} Whether the user's browser is the Android browser. - */ -goog.labs.userAgent.browser.isAndroidBrowser = - goog.labs.userAgent.browser.matchAndroidBrowser_; + var listenerObj; + var index = goog.events.ListenerMap.findListenerIndex_( + listenerArray, listener, opt_useCapture, opt_listenerScope); + if (index > -1) { + listenerObj = listenerArray[index]; + if (!callOnce) { + // Ensure that, if there is an existing callOnce listener, it is no + // longer a callOnce listener. + listenerObj.callOnce = false; + } + } else { + listenerObj = new goog.events.Listener( + listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope); + listenerObj.callOnce = callOnce; + listenerArray.push(listenerObj); + } + return listenerObj; +}; /** - * For more information, see: - * http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html - * @return {boolean} Whether the user's browser is Silk. + * Removes a matching listener. + * @param {string|!goog.events.EventId} type The listener event type. + * @param {!Function} listener This listener callback method. + * @param {boolean=} opt_useCapture The capture mode of the listener. + * @param {Object=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {boolean} Whether any listener was removed. */ -goog.labs.userAgent.browser.isSilk = function() { - return goog.labs.userAgent.util.matchUserAgent('Silk'); +goog.events.ListenerMap.prototype.remove = function( + type, listener, opt_useCapture, opt_listenerScope) { + var typeStr = type.toString(); + if (!(typeStr in this.listeners)) { + return false; + } + + var listenerArray = this.listeners[typeStr]; + var index = goog.events.ListenerMap.findListenerIndex_( + listenerArray, listener, opt_useCapture, opt_listenerScope); + if (index > -1) { + var listenerObj = listenerArray[index]; + listenerObj.markAsRemoved(); + goog.array.removeAt(listenerArray, index); + if (listenerArray.length == 0) { + delete this.listeners[typeStr]; + this.typeCount_--; + } + return true; + } + return false; }; /** - * @return {string} The browser version or empty string if version cannot be - * determined. Note that for Internet Explorer, this returns the version of - * the browser, not the version of the rendering engine. (IE 8 in - * compatibility mode will return 8.0 rather than 7.0. To determine the - * rendering engine version, look at document.documentMode instead. See - * http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more - * details.) + * Removes the given listener object. + * @param {goog.events.ListenableKey} listener The listener to remove. + * @return {boolean} Whether the listener is removed. */ -goog.labs.userAgent.browser.getVersion = function() { - var userAgentString = goog.labs.userAgent.util.getUserAgent(); - // Special case IE since IE's version is inside the parenthesis and - // without the '/'. - if (goog.labs.userAgent.browser.isIE()) { - return goog.labs.userAgent.browser.getIEVersion_(userAgentString); +goog.events.ListenerMap.prototype.removeByKey = function(listener) { + var type = listener.type; + if (!(type in this.listeners)) { + return false; } - var versionTuples = goog.labs.userAgent.util.extractVersionTuples( - userAgentString); - - // Construct a map for easy lookup. - var versionMap = {}; - goog.array.forEach(versionTuples, function(tuple) { - // Note that the tuple is of length three, but we only care about the - // first two. - var key = tuple[0]; - var value = tuple[1]; - versionMap[key] = value; - }); - - var versionMapHasKey = goog.partial(goog.object.containsKey, versionMap); - - // Gives the value with the first key it finds, otherwise empty string. - function lookUpValueWithKeys(keys) { - var key = goog.array.find(keys, versionMapHasKey); - return versionMap[key] || ''; + var removed = goog.array.remove(this.listeners[type], listener); + if (removed) { + listener.markAsRemoved(); + if (this.listeners[type].length == 0) { + delete this.listeners[type]; + this.typeCount_--; + } } + return removed; +}; - // Check Opera before Chrome since Opera 15+ has "Chrome" in the string. - // See - // http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond - if (goog.labs.userAgent.browser.isOpera()) { - // Opera 10 has Version/10.0 but Opera/9.8, so look for "Version" first. - // Opera uses 'OPR' for more recent UAs. - return lookUpValueWithKeys(['Version', 'Opera', 'OPR']); - } - // Check Edge before Chrome since it has Chrome in the string. - if (goog.labs.userAgent.browser.isEdge()) { - return lookUpValueWithKeys(['Edge']); +/** + * Removes all listeners from this map. If opt_type is provided, only + * listeners that match the given type are removed. + * @param {string|!goog.events.EventId=} opt_type Type of event to remove. + * @return {number} Number of listeners removed. + */ +goog.events.ListenerMap.prototype.removeAll = function(opt_type) { + var typeStr = opt_type && opt_type.toString(); + var count = 0; + for (var type in this.listeners) { + if (!typeStr || type == typeStr) { + var listenerArray = this.listeners[type]; + for (var i = 0; i < listenerArray.length; i++) { + ++count; + listenerArray[i].markAsRemoved(); + } + delete this.listeners[type]; + this.typeCount_--; + } } + return count; +}; - if (goog.labs.userAgent.browser.isChrome()) { - return lookUpValueWithKeys(['Chrome', 'CriOS']); - } - // Usually products browser versions are in the third tuple after "Mozilla" - // and the engine. - var tuple = versionTuples[2]; - return tuple && tuple[1] || ''; +/** + * Gets all listeners that match the given type and capture mode. The + * returned array is a copy (but the listener objects are not). + * @param {string|!goog.events.EventId} type The type of the listeners + * to retrieve. + * @param {boolean} capture The capture mode of the listeners to retrieve. + * @return {!Array<goog.events.ListenableKey>} An array of matching + * listeners. + */ +goog.events.ListenerMap.prototype.getListeners = function(type, capture) { + var listenerArray = this.listeners[type.toString()]; + var rv = []; + if (listenerArray) { + for (var i = 0; i < listenerArray.length; ++i) { + var listenerObj = listenerArray[i]; + if (listenerObj.capture == capture) { + rv.push(listenerObj); + } + } + } + return rv; }; /** - * @param {string|number} version The version to check. - * @return {boolean} Whether the browser version is higher or the same as the - * given version. + * Gets the goog.events.ListenableKey for the event or null if no such + * listener is in use. + * + * @param {string|!goog.events.EventId} type The type of the listener + * to retrieve. + * @param {!Function} listener The listener function to get. + * @param {boolean} capture Whether the listener is a capturing listener. + * @param {Object=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} the found listener or null if not found. */ -goog.labs.userAgent.browser.isVersionOrHigher = function(version) { - return goog.string.compareVersions(goog.labs.userAgent.browser.getVersion(), - version) >= 0; +goog.events.ListenerMap.prototype.getListener = function( + type, listener, capture, opt_listenerScope) { + var listenerArray = this.listeners[type.toString()]; + var i = -1; + if (listenerArray) { + i = goog.events.ListenerMap.findListenerIndex_( + listenerArray, listener, capture, opt_listenerScope); + } + return i > -1 ? listenerArray[i] : null; }; /** - * Determines IE version. More information: - * http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString - * http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx - * http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx - * http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx + * Whether there is a matching listener. If either the type or capture + * parameters are unspecified, the function will match on the + * remaining criteria. * - * @param {string} userAgent the User-Agent. - * @return {string} - * @private + * @param {string|!goog.events.EventId=} opt_type The type of the listener. + * @param {boolean=} opt_capture The capture mode of the listener. + * @return {boolean} Whether there is an active listener matching + * the requested type and/or capture phase. */ -goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) { - // IE11 may identify itself as MSIE 9.0 or MSIE 10.0 due to an IE 11 upgrade - // bug. Example UA: - // Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) - // like Gecko. - // See http://www.whatismybrowser.com/developers/unknown-user-agent-fragments. - var rv = /rv: *([\d\.]*)/.exec(userAgent); - if (rv && rv[1]) { - return rv[1]; - } +goog.events.ListenerMap.prototype.hasListener = function( + opt_type, opt_capture) { + var hasType = goog.isDef(opt_type); + var typeStr = hasType ? opt_type.toString() : ''; + var hasCapture = goog.isDef(opt_capture); - var version = ''; - var msie = /MSIE +([\d\.]+)/.exec(userAgent); - if (msie && msie[1]) { - // IE in compatibility mode usually identifies itself as MSIE 7.0; in this - // case, use the Trident version to determine the version of IE. For more - // details, see the links above. - var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent); - if (msie[1] == '7.0') { - if (tridentVersion && tridentVersion[1]) { - switch (tridentVersion[1]) { - case '4.0': - version = '8.0'; - break; - case '5.0': - version = '9.0'; - break; - case '6.0': - version = '10.0'; - break; - case '7.0': - version = '11.0'; - break; + return goog.object.some( + this.listeners, function(listenerArray, type) { + for (var i = 0; i < listenerArray.length; ++i) { + if ((!hasType || listenerArray[i].type == typeStr) && + (!hasCapture || listenerArray[i].capture == opt_capture)) { + return true; + } } - } else { - version = '7.0'; - } - } else { - version = msie[1]; + + return false; + }); +}; + + +/** + * Finds the index of a matching goog.events.Listener in the given + * listenerArray. + * @param {!Array<!goog.events.Listener>} listenerArray Array of listener. + * @param {!Function} listener The listener function. + * @param {boolean=} opt_useCapture The capture flag for the listener. + * @param {Object=} opt_listenerScope The listener scope. + * @return {number} The index of the matching listener within the + * listenerArray. + * @private + */ +goog.events.ListenerMap.findListenerIndex_ = function( + listenerArray, listener, opt_useCapture, opt_listenerScope) { + for (var i = 0; i < listenerArray.length; ++i) { + var listenerObj = listenerArray[i]; + if (!listenerObj.removed && + listenerObj.listener == listener && + listenerObj.capture == !!opt_useCapture && + listenerObj.handler == opt_listenerScope) { + return i; } } - return version; + return -1; }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// Copyright 2005 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -10435,872 +10585,977 @@ goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) { // limitations under the License. /** - * @fileoverview Closure user agent detection. - * @see http://en.wikipedia.org/wiki/User_agent - * For more information on browser brand, platform, or device see the other - * sub-namespaces in goog.labs.userAgent (browser, platform, and device). + * @fileoverview An event manager for both native browser event + * targets and custom JavaScript event targets + * ({@code goog.events.Listenable}). This provides an abstraction + * over browsers' event systems. * - */ - -goog.provide('goog.labs.userAgent.engine'); - -goog.require('goog.array'); -goog.require('goog.labs.userAgent.util'); -goog.require('goog.string'); - - -/** - * @return {boolean} Whether the rendering engine is Presto. - */ -goog.labs.userAgent.engine.isPresto = function() { - return goog.labs.userAgent.util.matchUserAgent('Presto'); -}; - - -/** - * @return {boolean} Whether the rendering engine is Trident. - */ -goog.labs.userAgent.engine.isTrident = function() { - // IE only started including the Trident token in IE8. - return goog.labs.userAgent.util.matchUserAgent('Trident') || - goog.labs.userAgent.util.matchUserAgent('MSIE'); -}; + * It also provides a simulation of W3C event model's capture phase in + * Internet Explorer (IE 8 and below). Caveat: the simulation does not + * interact well with listeners registered directly on the elements + * (bypassing goog.events) or even with listeners registered via + * goog.events in a separate JS binary. In these cases, we provide + * no ordering guarantees. + * + * The listeners will receive a "patched" event object. Such event object + * contains normalized values for certain event properties that differs in + * different browsers. + * + * Example usage: + * <pre> + * goog.events.listen(myNode, 'click', function(e) { alert('woo') }); + * goog.events.listen(myNode, 'mouseover', mouseHandler, true); + * goog.events.unlisten(myNode, 'mouseover', mouseHandler, true); + * goog.events.removeAll(myNode); + * </pre> + * + * in IE and event object patching] + * @author arv@google.com (Erik Arvidsson) + * + * @see ../demos/events.html + * @see ../demos/event-propagation.html + * @see ../demos/stopevent.html + */ +// IMPLEMENTATION NOTES: +// goog.events stores an auxiliary data structure on each EventTarget +// source being listened on. This allows us to take advantage of GC, +// having the data structure GC'd when the EventTarget is GC'd. This +// GC behavior is equivalent to using W3C DOM Events directly. -/** - * @return {boolean} Whether the rendering engine is Edge. - */ -goog.labs.userAgent.engine.isEdge = function() { - return goog.labs.userAgent.util.matchUserAgent('Edge'); -}; +goog.provide('goog.events'); +goog.provide('goog.events.CaptureSimulationMode'); +goog.provide('goog.events.Key'); +goog.provide('goog.events.ListenableType'); +goog.require('goog.asserts'); +goog.require('goog.debug.entryPointRegistry'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.BrowserFeature'); +goog.require('goog.events.Listenable'); +goog.require('goog.events.ListenerMap'); -/** - * @return {boolean} Whether the rendering engine is WebKit. - */ -goog.labs.userAgent.engine.isWebKit = function() { - return goog.labs.userAgent.util.matchUserAgentIgnoreCase('WebKit') && - !goog.labs.userAgent.engine.isEdge(); -}; +goog.forwardDeclare('goog.debug.ErrorHandler'); +goog.forwardDeclare('goog.events.EventWrapper'); /** - * @return {boolean} Whether the rendering engine is Gecko. + * @typedef {number|goog.events.ListenableKey} */ -goog.labs.userAgent.engine.isGecko = function() { - return goog.labs.userAgent.util.matchUserAgent('Gecko') && - !goog.labs.userAgent.engine.isWebKit() && - !goog.labs.userAgent.engine.isTrident() && - !goog.labs.userAgent.engine.isEdge(); -}; +goog.events.Key; /** - * @return {string} The rendering engine's version or empty string if version - * can't be determined. + * @typedef {EventTarget|goog.events.Listenable} */ -goog.labs.userAgent.engine.getVersion = function() { - var userAgentString = goog.labs.userAgent.util.getUserAgent(); - if (userAgentString) { - var tuples = goog.labs.userAgent.util.extractVersionTuples( - userAgentString); - - var engineTuple = goog.labs.userAgent.engine.getEngineTuple_(tuples); - if (engineTuple) { - // In Gecko, the version string is either in the browser info or the - // Firefox version. See Gecko user agent string reference: - // http://goo.gl/mULqa - if (engineTuple[0] == 'Gecko') { - return goog.labs.userAgent.engine.getVersionForKey_( - tuples, 'Firefox'); - } - - return engineTuple[1]; - } - - // MSIE has only one version identifier, and the Trident version is - // specified in the parenthetical. IE Edge is covered in the engine tuple - // detection. - var browserTuple = tuples[0]; - var info; - if (browserTuple && (info = browserTuple[2])) { - var match = /Trident\/([^\s;]+)/.exec(info); - if (match) { - return match[1]; - } - } - } - return ''; -}; +goog.events.ListenableType; /** - * @param {!Array<!Array<string>>} tuples Extracted version tuples. - * @return {!Array<string>|undefined} The engine tuple or undefined if not - * found. - * @private + * Property name on a native event target for the listener map + * associated with the event target. + * @private @const {string} */ -goog.labs.userAgent.engine.getEngineTuple_ = function(tuples) { - if (!goog.labs.userAgent.engine.isEdge()) { - return tuples[1]; - } - for (var i = 0; i < tuples.length; i++) { - var tuple = tuples[i]; - if (tuple[0] == 'Edge') { - return tuple; - } - } -}; +goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0); /** - * @param {string|number} version The version to check. - * @return {boolean} Whether the rendering engine version is higher or the same - * as the given version. + * String used to prepend to IE event types. + * @const + * @private */ -goog.labs.userAgent.engine.isVersionOrHigher = function(version) { - return goog.string.compareVersions(goog.labs.userAgent.engine.getVersion(), - version) >= 0; -}; +goog.events.onString_ = 'on'; /** - * @param {!Array<!Array<string>>} tuples Version tuples. - * @param {string} key The key to look for. - * @return {string} The version string of the given key, if present. - * Otherwise, the empty string. + * Map of computed "on<eventname>" strings for IE event types. Caching + * this removes an extra object allocation in goog.events.listen which + * improves IE6 performance. + * @const + * @dict * @private */ -goog.labs.userAgent.engine.getVersionForKey_ = function(tuples, key) { - // TODO(nnaze): Move to util if useful elsewhere. - - var pair = goog.array.find(tuples, function(pair) { - return key == pair[0]; - }); - - return pair && pair[1] || ''; -}; +goog.events.onStringMap_ = {}; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Closure user agent platform detection. - * @see <a href="http://www.useragentstring.com/">User agent strings</a> - * For more information on browser brand, rendering engine, or device see the - * other sub-namespaces in goog.labs.userAgent (browser, engine, and device - * respectively). - * + * @enum {number} Different capture simulation mode for IE8-. */ +goog.events.CaptureSimulationMode = { + /** + * Does not perform capture simulation. Will asserts in IE8- when you + * add capture listeners. + */ + OFF_AND_FAIL: 0, -goog.provide('goog.labs.userAgent.platform'); + /** + * Does not perform capture simulation, silently ignore capture + * listeners. + */ + OFF_AND_SILENT: 1, -goog.require('goog.labs.userAgent.util'); -goog.require('goog.string'); + /** + * Performs capture simulation. + */ + ON: 2 +}; /** - * @return {boolean} Whether the platform is Android. + * @define {number} The capture simulation mode for IE8-. By default, + * this is ON. */ -goog.labs.userAgent.platform.isAndroid = function() { - return goog.labs.userAgent.util.matchUserAgent('Android'); -}; +goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2); /** - * @return {boolean} Whether the platform is iPod. + * Estimated count of total native listeners. + * @private {number} */ -goog.labs.userAgent.platform.isIpod = function() { - return goog.labs.userAgent.util.matchUserAgent('iPod'); -}; +goog.events.listenerCountEstimate_ = 0; /** - * @return {boolean} Whether the platform is iPhone. + * Adds an event listener for a specific event on a native event + * target (such as a DOM element) or an object that has implemented + * {@link goog.events.Listenable}. A listener can only be added once + * to an object and if it is added again the key for the listener is + * returned. Note that if the existing listener is a one-off listener + * (registered via listenOnce), it will no longer be a one-off + * listener after a call to listen(). + * + * @param {EventTarget|goog.events.Listenable} src The node to listen + * to events on. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} + * listener Callback method, or an object with a handleEvent function. + * WARNING: passing an Object is now softly deprecated. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {T=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.Key} Unique key for the listener. + * @template T,EVENTOBJ */ -goog.labs.userAgent.platform.isIphone = function() { - return goog.labs.userAgent.util.matchUserAgent('iPhone') && - !goog.labs.userAgent.util.matchUserAgent('iPod') && - !goog.labs.userAgent.util.matchUserAgent('iPad'); +goog.events.listen = function(src, type, listener, opt_capt, opt_handler) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + goog.events.listen(src, type[i], listener, opt_capt, opt_handler); + } + return null; + } + + listener = goog.events.wrapListener(listener); + if (goog.events.Listenable.isImplementedBy(src)) { + return src.listen( + /** @type {string|!goog.events.EventId} */ (type), + listener, opt_capt, opt_handler); + } else { + return goog.events.listen_( + /** @type {!EventTarget} */ (src), + /** @type {string|!goog.events.EventId} */ (type), + listener, /* callOnce */ false, opt_capt, opt_handler); + } }; /** - * @return {boolean} Whether the platform is iPad. + * Adds an event listener for a specific event on a native event + * target. A listener can only be added once to an object and if it + * is added again the key for the listener is returned. + * + * Note that a one-off listener will not change an existing listener, + * if any. On the other hand a normal listener will change existing + * one-off listener to become a normal listener. + * + * @param {EventTarget} src The node to listen to events on. + * @param {string|!goog.events.EventId} type Event type. + * @param {!Function} listener Callback function. + * @param {boolean} callOnce Whether the listener is a one-off + * listener or otherwise. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {Object=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.ListenableKey} Unique key for the listener. + * @private */ -goog.labs.userAgent.platform.isIpad = function() { - return goog.labs.userAgent.util.matchUserAgent('iPad'); -}; +goog.events.listen_ = function( + src, type, listener, callOnce, opt_capt, opt_handler) { + if (!type) { + throw Error('Invalid event type'); + } + var capture = !!opt_capt; + if (capture && !goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { + if (goog.events.CAPTURE_SIMULATION_MODE == + goog.events.CaptureSimulationMode.OFF_AND_FAIL) { + goog.asserts.fail('Can not register capture listener in IE8-.'); + return null; + } else if (goog.events.CAPTURE_SIMULATION_MODE == + goog.events.CaptureSimulationMode.OFF_AND_SILENT) { + return null; + } + } -/** - * @return {boolean} Whether the platform is iOS. - */ -goog.labs.userAgent.platform.isIos = function() { - return goog.labs.userAgent.platform.isIphone() || - goog.labs.userAgent.platform.isIpad() || - goog.labs.userAgent.platform.isIpod(); -}; + var listenerMap = goog.events.getListenerMap_(src); + if (!listenerMap) { + src[goog.events.LISTENER_MAP_PROP_] = listenerMap = + new goog.events.ListenerMap(src); + } + var listenerObj = listenerMap.add( + type, listener, callOnce, opt_capt, opt_handler); -/** - * @return {boolean} Whether the platform is Mac. - */ -goog.labs.userAgent.platform.isMacintosh = function() { - return goog.labs.userAgent.util.matchUserAgent('Macintosh'); -}; + // If the listenerObj already has a proxy, it has been set up + // previously. We simply return. + if (listenerObj.proxy) { + return listenerObj; + } + var proxy = goog.events.getProxy(); + listenerObj.proxy = proxy; -/** - * Note: ChromeOS is not considered to be Linux as it does not report itself - * as Linux in the user agent string. - * @return {boolean} Whether the platform is Linux. - */ -goog.labs.userAgent.platform.isLinux = function() { - return goog.labs.userAgent.util.matchUserAgent('Linux'); -}; + proxy.src = src; + proxy.listener = listenerObj; + // Attach the proxy through the browser's API + if (src.addEventListener) { + src.addEventListener(type.toString(), proxy, capture); + } else if (src.attachEvent) { + // The else if above used to be an unconditional else. It would call + // exception on IE11, spoiling the day of some callers. The previous + // incarnation of this code, from 2007, indicates that it replaced an + // earlier still version that caused excess allocations on IE6. + src.attachEvent(goog.events.getOnString_(type.toString()), proxy); + } else { + throw Error('addEventListener and attachEvent are unavailable.'); + } -/** - * @return {boolean} Whether the platform is Windows. - */ -goog.labs.userAgent.platform.isWindows = function() { - return goog.labs.userAgent.util.matchUserAgent('Windows'); + goog.events.listenerCountEstimate_++; + return listenerObj; }; /** - * @return {boolean} Whether the platform is ChromeOS. + * Helper function for returning a proxy function. + * @return {!Function} A new or reused function object. */ -goog.labs.userAgent.platform.isChromeOS = function() { - return goog.labs.userAgent.util.matchUserAgent('CrOS'); +goog.events.getProxy = function() { + var proxyCallbackFunction = goog.events.handleBrowserEvent_; + // Use a local var f to prevent one allocation. + var f = goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT ? + function(eventObject) { + return proxyCallbackFunction.call(f.src, f.listener, eventObject); + } : + function(eventObject) { + var v = proxyCallbackFunction.call(f.src, f.listener, eventObject); + // NOTE(chrishenry): In IE, we hack in a capture phase. However, if + // there is inline event handler which tries to prevent default (for + // example <a href="..." onclick="return false">...</a>) in a + // descendant element, the prevent default will be overridden + // by this listener if this listener were to return true. Hence, we + // return undefined. + if (!v) return v; + }; + return f; }; /** - * The version of the platform. We only determine the version for Windows, - * Mac, and Chrome OS. It doesn't make much sense on Linux. For Windows, we only - * look at the NT version. Non-NT-based versions (e.g. 95, 98, etc.) are given - * version 0.0. + * Adds an event listener for a specific event on a native event + * target (such as a DOM element) or an object that has implemented + * {@link goog.events.Listenable}. After the event has fired the event + * listener is removed from the target. * - * @return {string} The platform version or empty string if version cannot be - * determined. + * If an existing listener already exists, listenOnce will do + * nothing. In particular, if the listener was previously registered + * via listen(), listenOnce() will not turn the listener into a + * one-off listener. Similarly, if there is already an existing + * one-off listener, listenOnce does not modify the listeners (it is + * still a once listener). + * + * @param {EventTarget|goog.events.Listenable} src The node to listen + * to events on. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} + * listener Callback method. + * @param {boolean=} opt_capt Fire in capture phase?. + * @param {T=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.Key} Unique key for the listener. + * @template T,EVENTOBJ */ -goog.labs.userAgent.platform.getVersion = function() { - var userAgentString = goog.labs.userAgent.util.getUserAgent(); - var version = '', re; - if (goog.labs.userAgent.platform.isWindows()) { - re = /Windows (?:NT|Phone) ([0-9.]+)/; - var match = re.exec(userAgentString); - if (match) { - version = match[1]; - } else { - version = '0.0'; +goog.events.listenOnce = function(src, type, listener, opt_capt, opt_handler) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + goog.events.listenOnce(src, type[i], listener, opt_capt, opt_handler); } - } else if (goog.labs.userAgent.platform.isIos()) { - re = /(?:iPhone|iPod|iPad|CPU)\s+OS\s+(\S+)/; - var match = re.exec(userAgentString); - // Report the version as x.y.z and not x_y_z - version = match && match[1].replace(/_/g, '.'); - } else if (goog.labs.userAgent.platform.isMacintosh()) { - re = /Mac OS X ([0-9_.]+)/; - var match = re.exec(userAgentString); - // Note: some old versions of Camino do not report an OSX version. - // Default to 10. - version = match ? match[1].replace(/_/g, '.') : '10'; - } else if (goog.labs.userAgent.platform.isAndroid()) { - re = /Android\s+([^\);]+)(\)|;)/; - var match = re.exec(userAgentString); - version = match && match[1]; - } else if (goog.labs.userAgent.platform.isChromeOS()) { - re = /(?:CrOS\s+(?:i686|x86_64)\s+([0-9.]+))/; - var match = re.exec(userAgentString); - version = match && match[1]; + return null; + } + + listener = goog.events.wrapListener(listener); + if (goog.events.Listenable.isImplementedBy(src)) { + return src.listenOnce( + /** @type {string|!goog.events.EventId} */ (type), + listener, opt_capt, opt_handler); + } else { + return goog.events.listen_( + /** @type {!EventTarget} */ (src), + /** @type {string|!goog.events.EventId} */ (type), + listener, /* callOnce */ true, opt_capt, opt_handler); } - return version || ''; }; /** - * @param {string|number} version The version to check. - * @return {boolean} Whether the browser version is higher or the same as the - * given version. + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.Listenable}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.Listenable} src The target to + * listen to events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener + * Callback method, or an object with a handleEvent function. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {T=} opt_handler Element in whose scope to call the listener. + * @template T */ -goog.labs.userAgent.platform.isVersionOrHigher = function(version) { - return goog.string.compareVersions(goog.labs.userAgent.platform.getVersion(), - version) >= 0; +goog.events.listenWithWrapper = function(src, wrapper, listener, opt_capt, + opt_handler) { + wrapper.listen(src, listener, opt_capt, opt_handler); }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Rendering engine detection. - * @see <a href="http://www.useragentstring.com/">User agent strings</a> - * For information on the browser brand (such as Safari versus Chrome), see - * goog.userAgent.product. - * @author arv@google.com (Erik Arvidsson) - * @see ../demos/useragent.html + * Removes an event listener which was added with listen(). + * + * @param {EventTarget|goog.events.Listenable} src The target to stop + * listening to events on. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types to unlisten to. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener The + * listener function to remove. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase of the + * event. + * @param {Object=} opt_handler Element in whose scope to call the listener. + * @return {?boolean} indicating whether the listener was there to remove. + * @template EVENTOBJ */ +goog.events.unlisten = function(src, type, listener, opt_capt, opt_handler) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + goog.events.unlisten(src, type[i], listener, opt_capt, opt_handler); + } + return null; + } -goog.provide('goog.userAgent'); - -goog.require('goog.labs.userAgent.browser'); -goog.require('goog.labs.userAgent.engine'); -goog.require('goog.labs.userAgent.platform'); -goog.require('goog.labs.userAgent.util'); -goog.require('goog.string'); - + listener = goog.events.wrapListener(listener); + if (goog.events.Listenable.isImplementedBy(src)) { + return src.unlisten( + /** @type {string|!goog.events.EventId} */ (type), + listener, opt_capt, opt_handler); + } -/** - * @define {boolean} Whether we know at compile-time that the browser is IE. - */ -goog.define('goog.userAgent.ASSUME_IE', false); + if (!src) { + // TODO(chrishenry): We should tighten the API to only accept + // non-null objects, or add an assertion here. + return false; + } + var capture = !!opt_capt; + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (src)); + if (listenerMap) { + var listenerObj = listenerMap.getListener( + /** @type {string|!goog.events.EventId} */ (type), + listener, capture, opt_handler); + if (listenerObj) { + return goog.events.unlistenByKey(listenerObj); + } + } -/** - * @define {boolean} Whether we know at compile-time that the browser is EDGE. - */ -goog.define('goog.userAgent.ASSUME_EDGE', false); + return false; +}; /** - * @define {boolean} Whether we know at compile-time that the browser is GECKO. + * Removes an event listener which was added with listen() by the key + * returned by listen(). + * + * @param {goog.events.Key} key The key returned by listen() for this + * event listener. + * @return {boolean} indicating whether the listener was there to remove. */ -goog.define('goog.userAgent.ASSUME_GECKO', false); - +goog.events.unlistenByKey = function(key) { + // TODO(chrishenry): Remove this check when tests that rely on this + // are fixed. + if (goog.isNumber(key)) { + return false; + } -/** - * @define {boolean} Whether we know at compile-time that the browser is WEBKIT. - */ -goog.define('goog.userAgent.ASSUME_WEBKIT', false); + var listener = key; + if (!listener || listener.removed) { + return false; + } + var src = listener.src; + if (goog.events.Listenable.isImplementedBy(src)) { + return src.unlistenByKey(listener); + } -/** - * @define {boolean} Whether we know at compile-time that the browser is a - * mobile device running WebKit e.g. iPhone or Android. - */ -goog.define('goog.userAgent.ASSUME_MOBILE_WEBKIT', false); + var type = listener.type; + var proxy = listener.proxy; + if (src.removeEventListener) { + src.removeEventListener(type, proxy, listener.capture); + } else if (src.detachEvent) { + src.detachEvent(goog.events.getOnString_(type), proxy); + } + goog.events.listenerCountEstimate_--; + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (src)); + // TODO(chrishenry): Try to remove this conditional and execute the + // first branch always. This should be safe. + if (listenerMap) { + listenerMap.removeByKey(listener); + if (listenerMap.getTypeCount() == 0) { + // Null the src, just because this is simple to do (and useful + // for IE <= 7). + listenerMap.src = null; + // We don't use delete here because IE does not allow delete + // on a window object. + src[goog.events.LISTENER_MAP_PROP_] = null; + } + } else { + listener.markAsRemoved(); + } -/** - * @define {boolean} Whether we know at compile-time that the browser is OPERA. - */ -goog.define('goog.userAgent.ASSUME_OPERA', false); + return true; +}; /** - * @define {boolean} Whether the - * {@code goog.userAgent.isVersionOrHigher} - * function will return true for any version. + * Removes an event listener which was added with listenWithWrapper(). + * + * @param {EventTarget|goog.events.Listenable} src The target to stop + * listening to events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener The + * listener function to remove. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase of the + * event. + * @param {Object=} opt_handler Element in whose scope to call the listener. */ -goog.define('goog.userAgent.ASSUME_ANY_VERSION', false); +goog.events.unlistenWithWrapper = function(src, wrapper, listener, opt_capt, + opt_handler) { + wrapper.unlisten(src, listener, opt_capt, opt_handler); +}; /** - * Whether we know the browser engine at compile-time. - * @type {boolean} - * @private + * Removes all listeners from an object. You can also optionally + * remove listeners of a particular type. + * + * @param {Object|undefined} obj Object to remove listeners from. Must be an + * EventTarget or a goog.events.Listenable. + * @param {string|!goog.events.EventId=} opt_type Type of event to remove. + * Default is all types. + * @return {number} Number of listeners removed. */ -goog.userAgent.BROWSER_KNOWN_ = - goog.userAgent.ASSUME_IE || - goog.userAgent.ASSUME_EDGE || - goog.userAgent.ASSUME_GECKO || - goog.userAgent.ASSUME_MOBILE_WEBKIT || - goog.userAgent.ASSUME_WEBKIT || - goog.userAgent.ASSUME_OPERA; +goog.events.removeAll = function(obj, opt_type) { + // TODO(chrishenry): Change the type of obj to + // (!EventTarget|!goog.events.Listenable). + if (!obj) { + return 0; + } -/** - * Returns the userAgent string for the current browser. - * - * @return {string} The userAgent string. - */ -goog.userAgent.getUserAgentString = function() { - return goog.labs.userAgent.util.getUserAgent(); -}; + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.removeAllListeners(opt_type); + } + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (obj)); + if (!listenerMap) { + return 0; + } -/** - * TODO(nnaze): Change type to "Navigator" and update compilation targets. - * @return {Object} The native navigator object. - */ -goog.userAgent.getNavigator = function() { - // Need a local navigator reference instead of using the global one, - // to avoid the rare case where they reference different objects. - // (in a WorkerPool, for example). - return goog.global['navigator'] || null; + var count = 0; + var typeStr = opt_type && opt_type.toString(); + for (var type in listenerMap.listeners) { + if (!typeStr || type == typeStr) { + // Clone so that we don't need to worry about unlistenByKey + // changing the content of the ListenerMap. + var listeners = listenerMap.listeners[type].concat(); + for (var i = 0; i < listeners.length; ++i) { + if (goog.events.unlistenByKey(listeners[i])) { + ++count; + } + } + } + } + return count; }; /** - * Whether the user agent is Opera. - * @type {boolean} + * Gets the listeners for a given object, type and capture phase. + * + * @param {Object} obj Object to get listeners for. + * @param {string|!goog.events.EventId} type Event type. + * @param {boolean} capture Capture phase?. + * @return {Array<goog.events.Listener>} Array of listener objects. */ -goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_OPERA : - goog.labs.userAgent.browser.isOpera(); - +goog.events.getListeners = function(obj, type, capture) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.getListeners(type, capture); + } else { + if (!obj) { + // TODO(chrishenry): We should tighten the API to accept + // !EventTarget|goog.events.Listenable, and add an assertion here. + return []; + } -/** - * Whether the user agent is Internet Explorer. - * @type {boolean} - */ -goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_IE : - goog.labs.userAgent.browser.isIE(); + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (obj)); + return listenerMap ? listenerMap.getListeners(type, capture) : []; + } +}; /** - * Whether the user agent is Microsoft Edge. - * @type {boolean} + * Gets the goog.events.Listener for the event or null if no such listener is + * in use. + * + * @param {EventTarget|goog.events.Listenable} src The target from + * which to get listeners. + * @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The + * listener function to get. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the + * capture or bubble phase of the event. + * @param {Object=} opt_handler Element in whose scope to call the listener. + * @return {goog.events.ListenableKey} the found listener or null if not found. + * @template EVENTOBJ */ -goog.userAgent.EDGE = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_EDGE : - goog.labs.userAgent.engine.isEdge(); +goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) { + // TODO(chrishenry): Change type from ?string to string, or add assertion. + type = /** @type {string} */ (type); + listener = goog.events.wrapListener(listener); + var capture = !!opt_capt; + if (goog.events.Listenable.isImplementedBy(src)) { + return src.getListener(type, listener, capture, opt_handler); + } + if (!src) { + // TODO(chrishenry): We should tighten the API to only accept + // non-null objects, or add an assertion here. + return null; + } -/** - * Whether the user agent is MS Internet Explorer or MS Edge. - * @type {boolean} - */ -goog.userAgent.EDGE_OR_IE = goog.userAgent.EDGE || goog.userAgent.IE; + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (src)); + if (listenerMap) { + return listenerMap.getListener(type, listener, capture, opt_handler); + } + return null; +}; /** - * Whether the user agent is Gecko. Gecko is the rendering engine used by - * Mozilla, Firefox, and others. - * @type {boolean} + * Returns whether an event target has any active listeners matching the + * specified signature. If either the type or capture parameters are + * unspecified, the function will match on the remaining criteria. + * + * @param {EventTarget|goog.events.Listenable} obj Target to get + * listeners for. + * @param {string|!goog.events.EventId=} opt_type Event type. + * @param {boolean=} opt_capture Whether to check for capture or bubble-phase + * listeners. + * @return {boolean} Whether an event target has one or more listeners matching + * the requested type and/or capture phase. */ -goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_GECKO : - goog.labs.userAgent.engine.isGecko(); +goog.events.hasListener = function(obj, opt_type, opt_capture) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.hasListener(opt_type, opt_capture); + } + + var listenerMap = goog.events.getListenerMap_( + /** @type {!EventTarget} */ (obj)); + return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture); +}; /** - * Whether the user agent is WebKit. WebKit is the rendering engine that - * Safari, Android and others use. - * @type {boolean} + * Provides a nice string showing the normalized event objects public members + * @param {Object} e Event Object. + * @return {string} String of the public members of the normalized event object. */ -goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ? - goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT : - goog.labs.userAgent.engine.isWebKit(); +goog.events.expose = function(e) { + var str = []; + for (var key in e) { + if (e[key] && e[key].id) { + str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')'); + } else { + str.push(key + ' = ' + e[key]); + } + } + return str.join('\n'); +}; /** - * Whether the user agent is running on a mobile device. - * - * This is a separate function so that the logic can be tested. - * - * TODO(nnaze): Investigate swapping in goog.labs.userAgent.device.isMobile(). - * - * @return {boolean} Whether the user agent is running on a mobile device. + * Returns a string with on prepended to the specified type. This is used for IE + * which expects "on" to be prepended. This function caches the string in order + * to avoid extra allocations in steady state. + * @param {string} type Event type. + * @return {string} The type string with 'on' prepended. * @private */ -goog.userAgent.isMobile_ = function() { - return goog.userAgent.WEBKIT && - goog.labs.userAgent.util.matchUserAgent('Mobile'); +goog.events.getOnString_ = function(type) { + if (type in goog.events.onStringMap_) { + return goog.events.onStringMap_[type]; + } + return goog.events.onStringMap_[type] = goog.events.onString_ + type; }; /** - * Whether the user agent is running on a mobile device. - * - * TODO(nnaze): Consider deprecating MOBILE when labs.userAgent - * is promoted as the gecko/webkit logic is likely inaccurate. + * Fires an object's listeners of a particular type and phase * - * @type {boolean} + * @param {Object} obj Object whose listeners to call. + * @param {string|!goog.events.EventId} type Event type. + * @param {boolean} capture Which event phase. + * @param {Object} eventObject Event object to be passed to listener. + * @return {boolean} True if all listeners returned true else false. */ -goog.userAgent.MOBILE = goog.userAgent.ASSUME_MOBILE_WEBKIT || - goog.userAgent.isMobile_(); - +goog.events.fireListeners = function(obj, type, capture, eventObject) { + if (goog.events.Listenable.isImplementedBy(obj)) { + return obj.fireListeners(type, capture, eventObject); + } -/** - * Used while transitioning code to use WEBKIT instead. - * @type {boolean} - * @deprecated Use {@link goog.userAgent.product.SAFARI} instead. - * TODO(nicksantos): Delete this from goog.userAgent. - */ -goog.userAgent.SAFARI = goog.userAgent.WEBKIT; + return goog.events.fireListeners_(obj, type, capture, eventObject); +}; /** - * @return {string} the platform (operating system) the user agent is running - * on. Default to empty string because navigator.platform may not be defined - * (on Rhino, for example). + * Fires an object's listeners of a particular type and phase. + * @param {Object} obj Object whose listeners to call. + * @param {string|!goog.events.EventId} type Event type. + * @param {boolean} capture Which event phase. + * @param {Object} eventObject Event object to be passed to listener. + * @return {boolean} True if all listeners returned true else false. * @private */ -goog.userAgent.determinePlatform_ = function() { - var navigator = goog.userAgent.getNavigator(); - return navigator && navigator.platform || ''; -}; - +goog.events.fireListeners_ = function(obj, type, capture, eventObject) { + /** @type {boolean} */ + var retval = true; -/** - * The platform (operating system) the user agent is running on. Default to - * empty string because navigator.platform may not be defined (on Rhino, for - * example). - * @type {string} - */ -goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_(); + var listenerMap = goog.events.getListenerMap_( + /** @type {EventTarget} */ (obj)); + if (listenerMap) { + // TODO(chrishenry): Original code avoids array creation when there + // is no listener, so we do the same. If this optimization turns + // out to be not required, we can replace this with + // listenerMap.getListeners(type, capture) instead, which is simpler. + var listenerArray = listenerMap.listeners[type.toString()]; + if (listenerArray) { + listenerArray = listenerArray.concat(); + for (var i = 0; i < listenerArray.length; i++) { + var listener = listenerArray[i]; + // We might not have a listener if the listener was removed. + if (listener && listener.capture == capture && !listener.removed) { + var result = goog.events.fireListener(listener, eventObject); + retval = retval && (result !== false); + } + } + } + } + return retval; +}; /** - * @define {boolean} Whether the user agent is running on a Macintosh operating - * system. + * Fires a listener with a set of arguments + * + * @param {goog.events.Listener} listener The listener object to call. + * @param {Object} eventObject The event object to pass to the listener. + * @return {boolean} Result of listener. */ -goog.define('goog.userAgent.ASSUME_MAC', false); - +goog.events.fireListener = function(listener, eventObject) { + var listenerFn = listener.listener; + var listenerHandler = listener.handler || listener.src; -/** - * @define {boolean} Whether the user agent is running on a Windows operating - * system. - */ -goog.define('goog.userAgent.ASSUME_WINDOWS', false); + if (listener.callOnce) { + goog.events.unlistenByKey(listener); + } + return listenerFn.call(listenerHandler, eventObject); +}; /** - * @define {boolean} Whether the user agent is running on a Linux operating - * system. + * Gets the total number of listeners currently in the system. + * @return {number} Number of listeners. + * @deprecated This returns estimated count, now that Closure no longer + * stores a central listener registry. We still return an estimation + * to keep existing listener-related tests passing. In the near future, + * this function will be removed. */ -goog.define('goog.userAgent.ASSUME_LINUX', false); +goog.events.getTotalListenerCount = function() { + return goog.events.listenerCountEstimate_; +}; /** - * @define {boolean} Whether the user agent is running on a X11 windowing - * system. + * Dispatches an event (or event like object) and calls all listeners + * listening for events of this type. The type of the event is decided by the + * type property on the event object. + * + * If any of the listeners returns false OR calls preventDefault then this + * function will return false. If one of the capture listeners calls + * stopPropagation, then the bubble listeners won't fire. + * + * @param {goog.events.Listenable} src The event target. + * @param {goog.events.EventLike} e Event object. + * @return {boolean} If anyone called preventDefault on the event object (or + * if any of the handlers returns false) this will also return false. + * If there are no handlers, or if all handlers return true, this returns + * true. */ -goog.define('goog.userAgent.ASSUME_X11', false); +goog.events.dispatchEvent = function(src, e) { + goog.asserts.assert( + goog.events.Listenable.isImplementedBy(src), + 'Can not use goog.events.dispatchEvent with ' + + 'non-goog.events.Listenable instance.'); + return src.dispatchEvent(e); +}; /** - * @define {boolean} Whether the user agent is running on Android. + * Installs exception protection for the browser event entry point using the + * given error handler. + * + * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to + * protect the entry point. */ -goog.define('goog.userAgent.ASSUME_ANDROID', false); +goog.events.protectBrowserEventEntryPoint = function(errorHandler) { + goog.events.handleBrowserEvent_ = errorHandler.protectEntryPoint( + goog.events.handleBrowserEvent_); +}; /** - * @define {boolean} Whether the user agent is running on an iPhone. + * Handles an event and dispatches it to the correct listeners. This + * function is a proxy for the real listener the user specified. + * + * @param {goog.events.Listener} listener The listener object. + * @param {Event=} opt_evt Optional event object that gets passed in via the + * native event handlers. + * @return {boolean} Result of the event handler. + * @this {EventTarget} The object or Element that fired the event. + * @private */ -goog.define('goog.userAgent.ASSUME_IPHONE', false); +goog.events.handleBrowserEvent_ = function(listener, opt_evt) { + if (listener.removed) { + return true; + } + // Synthesize event propagation if the browser does not support W3C + // event model. + if (!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { + var ieEvent = opt_evt || + /** @type {Event} */ (goog.getObjectByName('window.event')); + var evt = new goog.events.BrowserEvent(ieEvent, this); + /** @type {boolean} */ + var retval = true; -/** - * @define {boolean} Whether the user agent is running on an iPad. - */ -goog.define('goog.userAgent.ASSUME_IPAD', false); + if (goog.events.CAPTURE_SIMULATION_MODE == + goog.events.CaptureSimulationMode.ON) { + // If we have not marked this event yet, we should perform capture + // simulation. + if (!goog.events.isMarkedIeEvent_(ieEvent)) { + goog.events.markIeEvent_(ieEvent); + var ancestors = []; + for (var parent = evt.currentTarget; parent; + parent = parent.parentNode) { + ancestors.push(parent); + } -/** - * @type {boolean} - * @private - */ -goog.userAgent.PLATFORM_KNOWN_ = - goog.userAgent.ASSUME_MAC || - goog.userAgent.ASSUME_WINDOWS || - goog.userAgent.ASSUME_LINUX || - goog.userAgent.ASSUME_X11 || - goog.userAgent.ASSUME_ANDROID || - goog.userAgent.ASSUME_IPHONE || - goog.userAgent.ASSUME_IPAD; - - -/** - * Whether the user agent is running on a Macintosh operating system. - * @type {boolean} - */ -goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_MAC : goog.labs.userAgent.platform.isMacintosh(); - - -/** - * Whether the user agent is running on a Windows operating system. - * @type {boolean} - */ -goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_WINDOWS : - goog.labs.userAgent.platform.isWindows(); - - -/** - * Whether the user agent is Linux per the legacy behavior of - * goog.userAgent.LINUX, which considered ChromeOS to also be - * Linux. - * @return {boolean} - * @private - */ -goog.userAgent.isLegacyLinux_ = function() { - return goog.labs.userAgent.platform.isLinux() || - goog.labs.userAgent.platform.isChromeOS(); -}; - - -/** - * Whether the user agent is running on a Linux operating system. - * - * Note that goog.userAgent.LINUX considers ChromeOS to be Linux, - * while goog.labs.userAgent.platform considers ChromeOS and - * Linux to be different OSes. - * - * @type {boolean} - */ -goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_LINUX : - goog.userAgent.isLegacyLinux_(); + // Fire capture listeners. + var type = listener.type; + for (var i = ancestors.length - 1; !evt.propagationStopped_ && i >= 0; + i--) { + evt.currentTarget = ancestors[i]; + var result = goog.events.fireListeners_(ancestors[i], type, true, evt); + retval = retval && result; + } + // Fire bubble listeners. + // + // We can technically rely on IE to perform bubble event + // propagation. However, it turns out that IE fires events in + // opposite order of attachEvent registration, which broke + // some code and tests that rely on the order. (While W3C DOM + // Level 2 Events TR leaves the event ordering unspecified, + // modern browsers and W3C DOM Level 3 Events Working Draft + // actually specify the order as the registration order.) + for (var i = 0; !evt.propagationStopped_ && i < ancestors.length; i++) { + evt.currentTarget = ancestors[i]; + var result = goog.events.fireListeners_(ancestors[i], type, false, evt); + retval = retval && result; + } + } + } else { + retval = goog.events.fireListener(listener, evt); + } + return retval; + } -/** - * @return {boolean} Whether the user agent is an X11 windowing system. - * @private - */ -goog.userAgent.isX11_ = function() { - var navigator = goog.userAgent.getNavigator(); - return !!navigator && - goog.string.contains(navigator['appVersion'] || '', 'X11'); + // Otherwise, simply fire the listener. + return goog.events.fireListener( + listener, new goog.events.BrowserEvent(opt_evt, this)); }; /** - * Whether the user agent is running on a X11 windowing system. - * @type {boolean} - */ -goog.userAgent.X11 = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_X11 : - goog.userAgent.isX11_(); - - -/** - * Whether the user agent is running on Android. - * @type {boolean} - */ -goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_ANDROID : - goog.labs.userAgent.platform.isAndroid(); - - -/** - * Whether the user agent is running on an iPhone. - * @type {boolean} - */ -goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_IPHONE : - goog.labs.userAgent.platform.isIphone(); - - -/** - * Whether the user agent is running on an iPad. - * @type {boolean} - */ -goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ? - goog.userAgent.ASSUME_IPAD : - goog.labs.userAgent.platform.isIpad(); - - -/** - * @return {string} The string that describes the version number of the user - * agent. + * This is used to mark the IE event object so we do not do the Closure pass + * twice for a bubbling event. + * @param {Event} e The IE browser event. * @private */ -goog.userAgent.determineVersion_ = function() { - // All browsers have different ways to detect the version and they all have - // different naming schemes. - - if (goog.userAgent.OPERA && goog.global['opera']) { - var operaVersion = goog.global['opera'].version; - return goog.isFunction(operaVersion) ? operaVersion() : operaVersion; - } +goog.events.markIeEvent_ = function(e) { + // Only the keyCode and the returnValue can be changed. We use keyCode for + // non keyboard events. + // event.returnValue is a bit more tricky. It is undefined by default. A + // boolean false prevents the default action. In a window.onbeforeunload and + // the returnValue is non undefined it will be alerted. However, we will only + // modify the returnValue for keyboard events. We can get a problem if non + // closure events sets the keyCode or the returnValue - // version is a string rather than a number because it may contain 'b', 'a', - // and so on. - var version = ''; - var arr = goog.userAgent.getVersionRegexResult_(); - if (arr) { - version = arr ? arr[1] : ''; - } + var useReturnValue = false; - if (goog.userAgent.IE) { - // IE9 can be in document mode 9 but be reporting an inconsistent user agent - // version. If it is identifying as a version lower than 9 we take the - // documentMode as the version instead. IE8 has similar behavior. - // It is recommended to set the X-UA-Compatible header to ensure that IE9 - // uses documentMode 9. - var docMode = goog.userAgent.getDocumentMode_(); - if (docMode > parseFloat(version)) { - return String(docMode); + if (e.keyCode == 0) { + // We cannot change the keyCode in case that srcElement is input[type=file]. + // We could test that that is the case but that would allocate 3 objects. + // If we use try/catch we will only allocate extra objects in the case of a + // failure. + /** @preserveTry */ + try { + e.keyCode = -1; + return; + } catch (ex) { + useReturnValue = true; } } - return version; -}; - - -/** - * @return {Array|undefined} The version regex matches from parsing the user - * agent string. These regex statements must be executed inline so they can - * be compiled out by the closure compiler with the rest of the useragent - * detection logic when ASSUME_* is specified. - * @private - */ -goog.userAgent.getVersionRegexResult_ = function() { - var userAgent = goog.userAgent.getUserAgentString(); - if (goog.userAgent.GECKO) { - return /rv\:([^\);]+)(\)|;)/.exec(userAgent); - } - if (goog.userAgent.EDGE) { - return /Edge\/([\d\.]+)/.exec(userAgent); - } - if (goog.userAgent.IE) { - return /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(userAgent); - } - if (goog.userAgent.WEBKIT) { - // WebKit/125.4 - return /WebKit\/(\S+)/.exec(userAgent); + if (useReturnValue || + /** @type {boolean|undefined} */ (e.returnValue) == undefined) { + e.returnValue = true; } }; /** - * @return {number|undefined} Returns the document mode (for testing). + * This is used to check if an IE event has already been handled by the Closure + * system so we do not do the Closure pass twice for a bubbling event. + * @param {Event} e The IE browser event. + * @return {boolean} True if the event object has been marked. * @private */ -goog.userAgent.getDocumentMode_ = function() { - // NOTE(user): goog.userAgent may be used in context where there is no DOM. - var doc = goog.global['document']; - return doc ? doc['documentMode'] : undefined; +goog.events.isMarkedIeEvent_ = function(e) { + return e.keyCode < 0 || e.returnValue != undefined; }; /** - * The version of the user agent. This is a string because it might contain - * 'b' (as in beta) as well as multiple dots. - * @type {string} + * Counter to create unique event ids. + * @private {number} */ -goog.userAgent.VERSION = goog.userAgent.determineVersion_(); +goog.events.uniqueIdCounter_ = 0; /** - * Compares two version numbers. - * - * @param {string} v1 Version of first item. - * @param {string} v2 Version of second item. + * Creates a unique event id. * - * @return {number} 1 if first argument is higher - * 0 if arguments are equal - * -1 if second argument is higher. - * @deprecated Use goog.string.compareVersions. + * @param {string} identifier The identifier. + * @return {string} A unique identifier. + * @idGenerator */ -goog.userAgent.compare = function(v1, v2) { - return goog.string.compareVersions(v1, v2); +goog.events.getUniqueId = function(identifier) { + return identifier + '_' + goog.events.uniqueIdCounter_++; }; /** - * Cache for {@link goog.userAgent.isVersionOrHigher}. - * Calls to compareVersions are surprisingly expensive and, as a browser's - * version number is unlikely to change during a session, we cache the results. - * @const + * @param {EventTarget} src The source object. + * @return {goog.events.ListenerMap} A listener map for the given + * source object, or null if none exists. * @private */ -goog.userAgent.isVersionOrHigherCache_ = {}; - - -/** - * Whether the user agent version is higher or the same as the given version. - * NOTE: When checking the version numbers for Firefox and Safari, be sure to - * use the engine's version, not the browser's version number. For example, - * Firefox 3.0 corresponds to Gecko 1.9 and Safari 3.0 to Webkit 522.11. - * Opera and Internet Explorer versions match the product release number.<br> - * @see <a href="http://en.wikipedia.org/wiki/Safari_version_history"> - * Webkit</a> - * @see <a href="http://en.wikipedia.org/wiki/Gecko_engine">Gecko</a> - * - * @param {string|number} version The version to check. - * @return {boolean} Whether the user agent version is higher or the same as - * the given version. - */ -goog.userAgent.isVersionOrHigher = function(version) { - return goog.userAgent.ASSUME_ANY_VERSION || - goog.userAgent.isVersionOrHigherCache_[version] || - (goog.userAgent.isVersionOrHigherCache_[version] = - goog.string.compareVersions(goog.userAgent.VERSION, version) >= 0); +goog.events.getListenerMap_ = function(src) { + var listenerMap = src[goog.events.LISTENER_MAP_PROP_]; + // IE serializes the property as well (e.g. when serializing outer + // HTML). So we must check that the value is of the correct type. + return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null; }; /** - * Deprecated alias to {@code goog.userAgent.isVersionOrHigher}. - * @param {string|number} version The version to check. - * @return {boolean} Whether the user agent version is higher or the same as - * the given version. - * @deprecated Use goog.userAgent.isVersionOrHigher(). + * Expando property for listener function wrapper for Object with + * handleEvent. + * @private @const {string} */ -goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher; +goog.events.LISTENER_WRAPPER_PROP_ = '__closure_events_fn_' + + ((Math.random() * 1e9) >>> 0); /** - * Whether the IE effective document mode is higher or the same as the given - * document mode version. - * NOTE: Only for IE, return false for another browser. - * - * @param {number} documentMode The document mode version to check. - * @return {boolean} Whether the IE effective document mode is higher or the - * same as the given version. + * @param {Object|Function} listener The listener function or an + * object that contains handleEvent method. + * @return {!Function} Either the original function or a function that + * calls obj.handleEvent. If the same listener is passed to this + * function more than once, the same function is guaranteed to be + * returned. */ -goog.userAgent.isDocumentModeOrHigher = function(documentMode) { - return goog.userAgent.DOCUMENT_MODE >= documentMode; -}; +goog.events.wrapListener = function(listener) { + goog.asserts.assert(listener, 'Listener can not be null.'); + if (goog.isFunction(listener)) { + return listener; + } -/** - * Deprecated alias to {@code goog.userAgent.isDocumentModeOrHigher}. - * @param {number} version The version to check. - * @return {boolean} Whether the IE effective document mode is higher or the - * same as the given version. - * @deprecated Use goog.userAgent.isDocumentModeOrHigher(). - */ -goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher; + goog.asserts.assert( + listener.handleEvent, 'An object listener must have handleEvent method.'); + if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) { + listener[goog.events.LISTENER_WRAPPER_PROP_] = + function(e) { return listener.handleEvent(e); }; + } + return listener[goog.events.LISTENER_WRAPPER_PROP_]; +}; -/** - * For IE version < 7, documentMode is undefined, so attempt to use the - * CSS1Compat property to see if we are in standards mode. If we are in - * standards mode, treat the browser version as the document mode. Otherwise, - * IE is emulating version 5. - * @type {number|undefined} - * @const - */ -goog.userAgent.DOCUMENT_MODE = (function() { - var doc = goog.global['document']; - var mode = goog.userAgent.getDocumentMode_(); - if (!doc || !goog.userAgent.IE) { - return undefined; - } - return mode || (doc['compatMode'] == 'CSS1Compat' ? - parseInt(goog.userAgent.VERSION, 10) : 5); -})(); +// Register the browser event handler as an entry point, so that +// it can be monitored for exception handling, etc. +goog.debug.entryPointRegistry.register( + /** + * @param {function(!Function): !Function} transformer The transforming + * function. + */ + function(transformer) { + goog.events.handleBrowserEvent_ = transformer( + goog.events.handleBrowserEvent_); + }); -// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// Copyright 2005 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11315,862 +11570,1050 @@ goog.userAgent.DOCUMENT_MODE = (function() { // limitations under the License. /** - * @fileoverview Browser capability checks for the events package. + * @fileoverview A disposable implementation of a custom + * listenable/event target. See also: documentation for + * {@code goog.events.Listenable}. * + * @author arv@google.com (Erik Arvidsson) [Original implementation] + * @see ../demos/eventtarget.html + * @see goog.events.Listenable */ +goog.provide('goog.events.EventTarget'); -goog.provide('goog.events.BrowserFeature'); +goog.require('goog.Disposable'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.Listenable'); +goog.require('goog.events.ListenerMap'); +goog.require('goog.object'); -goog.require('goog.userAgent'); /** - * Enum of browser capabilities. - * @enum {boolean} + * An implementation of {@code goog.events.Listenable} with full W3C + * EventTarget-like support (capture/bubble mechanism, stopping event + * propagation, preventing default actions). + * + * You may subclass this class to turn your class into a Listenable. + * + * Unless propagation is stopped, an event dispatched by an + * EventTarget will bubble to the parent returned by + * {@code getParentEventTarget}. To set the parent, call + * {@code setParentEventTarget}. Subclasses that don't support + * changing the parent can override the setter to throw an error. + * + * Example usage: + * <pre> + * var source = new goog.events.EventTarget(); + * function handleEvent(e) { + * alert('Type: ' + e.type + '; Target: ' + e.target); + * } + * source.listen('foo', handleEvent); + * // Or: goog.events.listen(source, 'foo', handleEvent); + * ... + * source.dispatchEvent('foo'); // will call handleEvent + * ... + * source.unlisten('foo', handleEvent); + * // Or: goog.events.unlisten(source, 'foo', handleEvent); + * </pre> + * + * @constructor + * @extends {goog.Disposable} + * @implements {goog.events.Listenable} */ -goog.events.BrowserFeature = { - /** - * Whether the button attribute of the event is W3C compliant. False in - * Internet Explorer prior to version 9; document-version dependent. - */ - HAS_W3C_BUTTON: !goog.userAgent.IE || - goog.userAgent.isDocumentModeOrHigher(9), - - /** - * Whether the browser supports full W3C event model. - */ - HAS_W3C_EVENT_SUPPORT: !goog.userAgent.IE || - goog.userAgent.isDocumentModeOrHigher(9), - - /** - * To prevent default in IE7-8 for certain keydown events we need set the - * keyCode to -1. - */ - SET_KEY_CODE_TO_PREVENT_DEFAULT: goog.userAgent.IE && - !goog.userAgent.isVersionOrHigher('9'), - - /** - * Whether the {@code navigator.onLine} property is supported. - */ - HAS_NAVIGATOR_ONLINE_PROPERTY: !goog.userAgent.WEBKIT || - goog.userAgent.isVersionOrHigher('528'), +goog.events.EventTarget = function() { + goog.Disposable.call(this); /** - * Whether HTML5 network online/offline events are supported. + * Maps of event type to an array of listeners. + * @private {!goog.events.ListenerMap} */ - HAS_HTML5_NETWORK_EVENT_SUPPORT: - goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9b') || - goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8') || - goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('9.5') || - goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('528'), + this.eventTargetListeners_ = new goog.events.ListenerMap(this); /** - * Whether HTML5 network events fire on document.body, or otherwise the - * window. + * The object to use for event.target. Useful when mixing in an + * EventTarget to another object. + * @private {!Object} */ - HTML5_NETWORK_EVENTS_FIRE_ON_BODY: - goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('8') || - goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'), + this.actualEventTarget_ = this; /** - * Whether touch is enabled in the browser. + * Parent event target, used during event bubbling. + * + * TODO(chrishenry): Change this to goog.events.Listenable. This + * currently breaks people who expect getParentEventTarget to return + * goog.events.EventTarget. + * + * @private {goog.events.EventTarget} */ - TOUCH_ENABLED: - ('ontouchstart' in goog.global || - !!(goog.global['document'] && - document.documentElement && - 'ontouchstart' in document.documentElement) || - // IE10 uses non-standard touch events, so it has a different check. - !!(goog.global['navigator'] && - goog.global['navigator']['msMaxTouchPoints'])) + this.parentEventTarget_ = null; }; +goog.inherits(goog.events.EventTarget, goog.Disposable); +goog.events.Listenable.addImplementation(goog.events.EventTarget); -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Definition of the disposable interface. A disposable object - * has a dispose method to to clean up references and resources. - * @author nnaze@google.com (Nathan Naze) + * An artificial cap on the number of ancestors you can have. This is mainly + * for loop detection. + * @const {number} + * @private */ - - -goog.provide('goog.disposable.IDisposable'); - +goog.events.EventTarget.MAX_ANCESTORS_ = 1000; /** - * Interface for a disposable object. If a instance requires cleanup - * (references COM objects, DOM notes, or other disposable objects), it should - * implement this interface (it may subclass goog.Disposable). - * @interface + * Returns the parent of this event target to use for bubbling. + * + * @return {goog.events.EventTarget} The parent EventTarget or null if + * there is no parent. + * @override */ -goog.disposable.IDisposable = function() {}; +goog.events.EventTarget.prototype.getParentEventTarget = function() { + return this.parentEventTarget_; +}; /** - * Disposes of the object and its resources. - * @return {void} Nothing. + * Sets the parent of this event target to use for capture/bubble + * mechanism. + * @param {goog.events.EventTarget} parent Parent listenable (null if none). */ -goog.disposable.IDisposable.prototype.dispose = goog.abstractMethod; +goog.events.EventTarget.prototype.setParentEventTarget = function(parent) { + this.parentEventTarget_ = parent; +}; /** - * @return {boolean} Whether the object has been disposed of. - */ -goog.disposable.IDisposable.prototype.isDisposed = goog.abstractMethod; - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + * Adds an event listener to the event target. The same handler can only be + * added once per the type. Even if you add the same handler multiple times + * using the same type then it will only be called once when the event is + * dispatched. + * + * @param {string} type The type of the event to listen for. + * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function + * to handle the event. The handler can also be an object that implements + * the handleEvent method which takes the event object as argument. + * @param {boolean=} opt_capture In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase + * of the event. + * @param {Object=} opt_handlerScope Object in whose scope to call + * the listener. + * @deprecated Use {@code #listen} instead, when possible. Otherwise, use + * {@code goog.events.listen} if you are passing Object + * (instead of Function) as handler. + */ +goog.events.EventTarget.prototype.addEventListener = function( + type, handler, opt_capture, opt_handlerScope) { + goog.events.listen(this, type, handler, opt_capture, opt_handlerScope); +}; + /** - * @fileoverview Implements the disposable interface. The dispose method is used - * to clean up references and resources. - * @author arv@google.com (Erik Arvidsson) + * Removes an event listener from the event target. The handler must be the + * same object as the one added. If the handler has not been added then + * nothing is done. + * + * @param {string} type The type of the event to listen for. + * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function + * to handle the event. The handler can also be an object that implements + * the handleEvent method which takes the event object as argument. + * @param {boolean=} opt_capture In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase + * of the event. + * @param {Object=} opt_handlerScope Object in whose scope to call + * the listener. + * @deprecated Use {@code #unlisten} instead, when possible. Otherwise, use + * {@code goog.events.unlisten} if you are passing Object + * (instead of Function) as handler. */ +goog.events.EventTarget.prototype.removeEventListener = function( + type, handler, opt_capture, opt_handlerScope) { + goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope); +}; -goog.provide('goog.Disposable'); -/** @suppress {extraProvide} */ -goog.provide('goog.dispose'); -/** @suppress {extraProvide} */ -goog.provide('goog.disposeAll'); +/** @override */ +goog.events.EventTarget.prototype.dispatchEvent = function(e) { + this.assertInitialized_(); -goog.require('goog.disposable.IDisposable'); + var ancestorsTree, ancestor = this.getParentEventTarget(); + if (ancestor) { + ancestorsTree = []; + var ancestorCount = 1; + for (; ancestor; ancestor = ancestor.getParentEventTarget()) { + ancestorsTree.push(ancestor); + goog.asserts.assert( + (++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_), + 'infinite loop'); + } + } + return goog.events.EventTarget.dispatchEventInternal_( + this.actualEventTarget_, e, ancestorsTree); +}; /** - * Class that provides the basic implementation for disposable objects. If your - * class holds one or more references to COM objects, DOM nodes, or other - * disposable objects, it should extend this class or implement the disposable - * interface (defined in goog.disposable.IDisposable). - * @constructor - * @implements {goog.disposable.IDisposable} + * Removes listeners from this object. Classes that extend EventTarget may + * need to override this method in order to remove references to DOM Elements + * and additional listeners. + * @override */ -goog.Disposable = function() { - if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) { - if (goog.Disposable.INCLUDE_STACK_ON_CREATION) { - this.creationStack = new Error().stack; - } - goog.Disposable.instances_[goog.getUid(this)] = this; - } - // Support sealing - this.disposed_ = this.disposed_; - this.onDisposeCallbacks_ = this.onDisposeCallbacks_; +goog.events.EventTarget.prototype.disposeInternal = function() { + goog.events.EventTarget.superClass_.disposeInternal.call(this); + + this.removeAllListeners(); + this.parentEventTarget_ = null; }; -/** - * @enum {number} Different monitoring modes for Disposable. - */ -goog.Disposable.MonitoringMode = { - /** - * No monitoring. - */ - OFF: 0, - /** - * Creating and disposing the goog.Disposable instances is monitored. All - * disposable objects need to call the {@code goog.Disposable} base - * constructor. The PERMANENT mode must be switched on before creating any - * goog.Disposable instances. - */ - PERMANENT: 1, - /** - * INTERACTIVE mode can be switched on and off on the fly without producing - * errors. It also doesn't warn if the disposable objects don't call the - * {@code goog.Disposable} base constructor. - */ - INTERACTIVE: 2 +/** @override */ +goog.events.EventTarget.prototype.listen = function( + type, listener, opt_useCapture, opt_listenerScope) { + this.assertInitialized_(); + return this.eventTargetListeners_.add( + String(type), listener, false /* callOnce */, opt_useCapture, + opt_listenerScope); }; -/** - * @define {number} The monitoring mode of the goog.Disposable - * instances. Default is OFF. Switching on the monitoring is only - * recommended for debugging because it has a significant impact on - * performance and memory usage. If switched off, the monitoring code - * compiles down to 0 bytes. - */ -goog.define('goog.Disposable.MONITORING_MODE', 0); +/** @override */ +goog.events.EventTarget.prototype.listenOnce = function( + type, listener, opt_useCapture, opt_listenerScope) { + return this.eventTargetListeners_.add( + String(type), listener, true /* callOnce */, opt_useCapture, + opt_listenerScope); +}; -/** - * @define {boolean} Whether to attach creation stack to each created disposable - * instance; This is only relevant for when MonitoringMode != OFF. - */ -goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true); +/** @override */ +goog.events.EventTarget.prototype.unlisten = function( + type, listener, opt_useCapture, opt_listenerScope) { + return this.eventTargetListeners_.remove( + String(type), listener, opt_useCapture, opt_listenerScope); +}; -/** - * Maps the unique ID of every undisposed {@code goog.Disposable} object to - * the object itself. - * @type {!Object<number, !goog.Disposable>} - * @private - */ -goog.Disposable.instances_ = {}; +/** @override */ +goog.events.EventTarget.prototype.unlistenByKey = function(key) { + return this.eventTargetListeners_.removeByKey(key); +}; -/** - * @return {!Array<!goog.Disposable>} All {@code goog.Disposable} objects that - * haven't been disposed of. - */ -goog.Disposable.getUndisposedObjects = function() { - var ret = []; - for (var id in goog.Disposable.instances_) { - if (goog.Disposable.instances_.hasOwnProperty(id)) { - ret.push(goog.Disposable.instances_[Number(id)]); +/** @override */ +goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) { + // TODO(chrishenry): Previously, removeAllListeners can be called on + // uninitialized EventTarget, so we preserve that behavior. We + // should remove this when usages that rely on that fact are purged. + if (!this.eventTargetListeners_) { + return 0; + } + return this.eventTargetListeners_.removeAll(opt_type); +}; + + +/** @override */ +goog.events.EventTarget.prototype.fireListeners = function( + type, capture, eventObject) { + // TODO(chrishenry): Original code avoids array creation when there + // is no listener, so we do the same. If this optimization turns + // out to be not required, we can replace this with + // getListeners(type, capture) instead, which is simpler. + var listenerArray = this.eventTargetListeners_.listeners[String(type)]; + if (!listenerArray) { + return true; + } + listenerArray = listenerArray.concat(); + + var rv = true; + for (var i = 0; i < listenerArray.length; ++i) { + var listener = listenerArray[i]; + // We might not have a listener if the listener was removed. + if (listener && !listener.removed && listener.capture == capture) { + var listenerFn = listener.listener; + var listenerHandler = listener.handler || listener.src; + + if (listener.callOnce) { + this.unlistenByKey(listener); + } + rv = listenerFn.call(listenerHandler, eventObject) !== false && rv; } } - return ret; + + return rv && eventObject.returnValue_ != false; +}; + + +/** @override */ +goog.events.EventTarget.prototype.getListeners = function(type, capture) { + return this.eventTargetListeners_.getListeners(String(type), capture); +}; + + +/** @override */ +goog.events.EventTarget.prototype.getListener = function( + type, listener, capture, opt_listenerScope) { + return this.eventTargetListeners_.getListener( + String(type), listener, capture, opt_listenerScope); +}; + + +/** @override */ +goog.events.EventTarget.prototype.hasListener = function( + opt_type, opt_capture) { + var id = goog.isDef(opt_type) ? String(opt_type) : undefined; + return this.eventTargetListeners_.hasListener(id, opt_capture); }; /** - * Clears the registry of undisposed objects but doesn't dispose of them. + * Sets the target to be used for {@code event.target} when firing + * event. Mainly used for testing. For example, see + * {@code goog.testing.events.mixinListenable}. + * @param {!Object} target The target. */ -goog.Disposable.clearUndisposedObjects = function() { - goog.Disposable.instances_ = {}; +goog.events.EventTarget.prototype.setTargetForTesting = function(target) { + this.actualEventTarget_ = target; }; /** - * Whether the object has been disposed of. - * @type {boolean} + * Asserts that the event target instance is initialized properly. * @private */ -goog.Disposable.prototype.disposed_ = false; +goog.events.EventTarget.prototype.assertInitialized_ = function() { + goog.asserts.assert( + this.eventTargetListeners_, + 'Event target is not initialized. Did you call the superclass ' + + '(goog.events.EventTarget) constructor?'); +}; /** - * Callbacks to invoke when this object is disposed. - * @type {Array<!Function>} + * Dispatches the given event on the ancestorsTree. + * + * @param {!Object} target The target to dispatch on. + * @param {goog.events.Event|Object|string} e The event object. + * @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors + * tree of the target, in reverse order from the closest ancestor + * to the root event target. May be null if the target has no ancestor. + * @return {boolean} If anyone called preventDefault on the event object (or + * if any of the listeners returns false) this will also return false. * @private */ -goog.Disposable.prototype.onDisposeCallbacks_; +goog.events.EventTarget.dispatchEventInternal_ = function( + target, e, opt_ancestorsTree) { + var type = e.type || /** @type {string} */ (e); + + // If accepting a string or object, create a custom event object so that + // preventDefault and stopPropagation work with the event. + if (goog.isString(e)) { + e = new goog.events.Event(e, target); + } else if (!(e instanceof goog.events.Event)) { + var oldEvent = e; + e = new goog.events.Event(type, target); + goog.object.extend(e, oldEvent); + } else { + e.target = e.target || target; + } + var rv = true, currentTarget; + + // Executes all capture listeners on the ancestors, if any. + if (opt_ancestorsTree) { + for (var i = opt_ancestorsTree.length - 1; !e.propagationStopped_ && i >= 0; + i--) { + currentTarget = e.currentTarget = opt_ancestorsTree[i]; + rv = currentTarget.fireListeners(type, true, e) && rv; + } + } + + // Executes capture and bubble listeners on the target. + if (!e.propagationStopped_) { + currentTarget = e.currentTarget = target; + rv = currentTarget.fireListeners(type, true, e) && rv; + if (!e.propagationStopped_) { + rv = currentTarget.fireListeners(type, false, e) && rv; + } + } + + // Executes all bubble listeners on the ancestors, if any. + if (opt_ancestorsTree) { + for (i = 0; !e.propagationStopped_ && i < opt_ancestorsTree.length; i++) { + currentTarget = e.currentTarget = opt_ancestorsTree[i]; + rv = currentTarget.fireListeners(type, false, e) && rv; + } + } + + return rv; +}; + +goog.provide('ol.Observable'); + +goog.require('goog.events'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); -/** - * If monitoring the goog.Disposable instances is enabled, stores the creation - * stack trace of the Disposable instance. - * @const {string} - */ -goog.Disposable.prototype.creationStack; /** - * @return {boolean} Whether the object has been disposed of. - * @override + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * An event target providing convenient methods for listener registration + * and unregistration. A generic `change` event is always available through + * {@link ol.Observable#changed}. + * + * @constructor + * @extends {goog.events.EventTarget} + * @fires change + * @struct + * @api stable */ -goog.Disposable.prototype.isDisposed = function() { - return this.disposed_; +ol.Observable = function() { + + goog.base(this); + + /** + * @private + * @type {number} + */ + this.revision_ = 0; + }; +goog.inherits(ol.Observable, goog.events.EventTarget); /** - * @return {boolean} Whether the object has been disposed of. - * @deprecated Use {@link #isDisposed} instead. + * Removes an event listener using the key returned by `on()` or `once()`. + * @param {goog.events.Key} key The key returned by `on()` or `once()`. + * @api stable */ -goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed; +ol.Observable.unByKey = function(key) { + goog.events.unlistenByKey(key); +}; /** - * Disposes of the object. If the object hasn't already been disposed of, calls - * {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should - * override {@link #disposeInternal} in order to delete references to COM - * objects, DOM nodes, and other disposable objects. Reentrant. - * - * @return {void} Nothing. - * @override + * Increases the revision counter and dispatches a 'change' event. + * @api */ -goog.Disposable.prototype.dispose = function() { - if (!this.disposed_) { - // Set disposed_ to true first, in case during the chain of disposal this - // gets disposed recursively. - this.disposed_ = true; - this.disposeInternal(); - if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) { - var uid = goog.getUid(this); - if (goog.Disposable.MONITORING_MODE == - goog.Disposable.MonitoringMode.PERMANENT && - !goog.Disposable.instances_.hasOwnProperty(uid)) { - throw Error(this + ' did not call the goog.Disposable base ' + - 'constructor or was disposed of after a clearUndisposedObjects ' + - 'call'); - } - delete goog.Disposable.instances_[uid]; - } - } +ol.Observable.prototype.changed = function() { + ++this.revision_; + this.dispatchEvent(goog.events.EventType.CHANGE); }; /** - * Associates a disposable object with this object so that they will be disposed - * together. - * @param {goog.disposable.IDisposable} disposable that will be disposed when - * this object is disposed. + * Triggered when the revision counter is increased. + * @event change + * @api */ -goog.Disposable.prototype.registerDisposable = function(disposable) { - this.addOnDisposeCallback(goog.partial(goog.dispose, disposable)); -}; /** - * Invokes a callback function when this object is disposed. Callbacks are - * invoked in the order in which they were added. If a callback is added to - * an already disposed Disposable, it will be called immediately. - * @param {function(this:T):?} callback The callback function. - * @param {T=} opt_scope An optional scope to call the callback in. - * @template T + * Dispatches an event and calls all listeners listening for events + * of this type. The event parameter can either be a string or an + * Object with a `type` property. + * + * @param {goog.events.EventLike} event Event object. + * @function + * @api */ -goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) { - if (this.disposed_) { - callback.call(opt_scope); - return; - } - if (!this.onDisposeCallbacks_) { - this.onDisposeCallbacks_ = []; - } +ol.Observable.prototype.dispatchEvent; - this.onDisposeCallbacks_.push( - goog.isDef(opt_scope) ? goog.bind(callback, opt_scope) : callback); + +/** + * Get the version number for this object. Each time the object is modified, + * its version number will be incremented. + * @return {number} Revision. + * @api + */ +ol.Observable.prototype.getRevision = function() { + return this.revision_; }; /** - * Deletes or nulls out any references to COM objects, DOM nodes, or other - * disposable objects. Classes that extend {@code goog.Disposable} should - * override this method. - * Not reentrant. To avoid calling it twice, it must only be called from the - * subclass' {@code disposeInternal} method. Everywhere else the public - * {@code dispose} method must be used. - * For example: - * <pre> - * mypackage.MyClass = function() { - * mypackage.MyClass.base(this, 'constructor'); - * // Constructor logic specific to MyClass. - * ... - * }; - * goog.inherits(mypackage.MyClass, goog.Disposable); - * - * mypackage.MyClass.prototype.disposeInternal = function() { - * // Dispose logic specific to MyClass. - * ... - * // Call superclass's disposeInternal at the end of the subclass's, like - * // in C++, to avoid hard-to-catch issues. - * mypackage.MyClass.base(this, 'disposeInternal'); - * }; - * </pre> - * @protected + * Listen for a certain type of event. + * @param {string|Array.<string>} type The event type or array of event types. + * @param {function(?): ?} listener The listener function. + * @param {Object=} opt_this The object to use as `this` in `listener`. + * @return {goog.events.Key} Unique key for the listener. + * @api stable */ -goog.Disposable.prototype.disposeInternal = function() { - if (this.onDisposeCallbacks_) { - while (this.onDisposeCallbacks_.length) { - this.onDisposeCallbacks_.shift()(); - } - } +ol.Observable.prototype.on = function(type, listener, opt_this) { + return goog.events.listen(this, type, listener, false, opt_this); }; /** - * Returns True if we can verify the object is disposed. - * Calls {@code isDisposed} on the argument if it supports it. If obj - * is not an object with an isDisposed() method, return false. - * @param {*} obj The object to investigate. - * @return {boolean} True if we can verify the object is disposed. + * Listen once for a certain type of event. + * @param {string|Array.<string>} type The event type or array of event types. + * @param {function(?): ?} listener The listener function. + * @param {Object=} opt_this The object to use as `this` in `listener`. + * @return {goog.events.Key} Unique key for the listener. + * @api stable */ -goog.Disposable.isDisposed = function(obj) { - if (obj && typeof obj.isDisposed == 'function') { - return obj.isDisposed(); - } - return false; +ol.Observable.prototype.once = function(type, listener, opt_this) { + return goog.events.listenOnce(this, type, listener, false, opt_this); }; /** - * Calls {@code dispose} on the argument if it supports it. If obj is not an - * object with a dispose() method, this is a no-op. - * @param {*} obj The object to dispose of. + * Unlisten for a certain type of event. + * @param {string|Array.<string>} type The event type or array of event types. + * @param {function(?): ?} listener The listener function. + * @param {Object=} opt_this The object which was used as `this` by the + * `listener`. + * @api stable */ -goog.dispose = function(obj) { - if (obj && typeof obj.dispose == 'function') { - obj.dispose(); - } +ol.Observable.prototype.un = function(type, listener, opt_this) { + goog.events.unlisten(this, type, listener, false, opt_this); }; /** - * Calls {@code dispose} on each member of the list that supports it. (If the - * member is an ArrayLike, then {@code goog.disposeAll()} will be called - * recursively on each of its members.) If the member is not an object with a - * {@code dispose()} method, then it is ignored. - * @param {...*} var_args The list. + * Removes an event listener using the key returned by `on()` or `once()`. + * Note that using the {@link ol.Observable.unByKey} static function is to + * be preferred. + * @param {goog.events.Key} key The key returned by `on()` or `once()`. + * @function + * @api stable */ -goog.disposeAll = function(var_args) { - for (var i = 0, len = arguments.length; i < len; ++i) { - var disposable = arguments[i]; - if (goog.isArrayLike(disposable)) { - goog.disposeAll.apply(null, disposable); - } else { - goog.dispose(disposable); - } - } +ol.Observable.prototype.unByKey = ol.Observable.unByKey; + +goog.provide('ol.Object'); +goog.provide('ol.ObjectEvent'); +goog.provide('ol.ObjectEventType'); + +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('ol.Observable'); + + +/** + * @enum {string} + */ +ol.ObjectEventType = { + /** + * Triggered when a property is changed. + * @event ol.ObjectEvent#propertychange + * @api stable + */ + PROPERTYCHANGE: 'propertychange' }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -goog.provide('goog.events.EventId'); + +/** + * @classdesc + * Events emitted by {@link ol.Object} instances are instances of this type. + * + * @param {string} type The event type. + * @param {string} key The property name. + * @param {*} oldValue The old value for `key`. + * @extends {goog.events.Event} + * @implements {oli.ObjectEvent} + * @constructor + */ +ol.ObjectEvent = function(type, key, oldValue) { + goog.base(this, type); + + /** + * The name of the property whose value is changing. + * @type {string} + * @api stable + */ + this.key = key; + + /** + * The old value. To get the new value use `e.target.get(e.key)` where + * `e` is the event object. + * @type {*} + * @api stable + */ + this.oldValue = oldValue; + +}; +goog.inherits(ol.ObjectEvent, goog.events.Event); /** - * A templated class that is used when registering for events. Typical usage: - * <code> - * /** @type {goog.events.EventId<MyEventObj>} - * var myEventId = new goog.events.EventId( - * goog.events.getUniqueId(('someEvent')); + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Most non-trivial classes inherit from this. * - * // No need to cast or declare here since the compiler knows the correct - * // type of 'evt' (MyEventObj). - * something.listen(myEventId, function(evt) {}); - * </code> + * This extends {@link ol.Observable} with observable properties, where each + * property is observable as well as the object as a whole. + * + * Classes that inherit from this have pre-defined properties, to which you can + * add your owns. The pre-defined properties are listed in this documentation as + * 'Observable Properties', and have their own accessors; for example, + * {@link ol.Map} has a `target` property, accessed with `getTarget()` and + * changed with `setTarget()`. Not all properties are however settable. There + * are also general-purpose accessors `get()` and `set()`. For example, + * `get('target')` is equivalent to `getTarget()`. + * + * The `set` accessors trigger a change event, and you can monitor this by + * registering a listener. For example, {@link ol.View} has a `center` + * property, so `view.on('change:center', function(evt) {...});` would call the + * function whenever the value of the center property changes. Within the + * function, `evt.target` would be the view, so `evt.target.getCenter()` would + * return the new center. + * + * You can add your own observable properties with + * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`. + * You can listen for changes on that property value with + * `object.on('change:prop', listener)`. You can get a list of all + * properties with {@link ol.Object#getProperties object.getProperties()}. + * + * Note that the observable properties are separate from standard JS properties. + * You can, for example, give your map object a title with + * `map.title='New title'` and with `map.set('title', 'Another title')`. The + * first will be a `hasOwnProperty`; the second will appear in + * `getProperties()`. Only the second is observable. + * + * Properties can be deleted by using the unset method. E.g. + * object.unset('foo'). * - * @param {string} eventId - * @template T * @constructor - * @struct - * @final + * @extends {ol.Observable} + * @param {Object.<string, *>=} opt_values An object with key-value pairs. + * @fires ol.ObjectEvent + * @api */ -goog.events.EventId = function(eventId) { - /** @const */ this.id = eventId; +ol.Object = function(opt_values) { + goog.base(this); + + // Call goog.getUid to ensure that the order of objects' ids is the same as + // the order in which they were created. This also helps to ensure that + // object properties are always added in the same order, which helps many + // JavaScript engines generate faster code. + goog.getUid(this); + + /** + * @private + * @type {!Object.<string, *>} + */ + this.values_ = {}; + + if (opt_values !== undefined) { + this.setProperties(opt_values); + } }; +goog.inherits(ol.Object, ol.Observable); /** - * @override + * @private + * @type {Object.<string, string>} */ -goog.events.EventId.prototype.toString = function() { - return this.id; +ol.Object.changeEventTypeCache_ = {}; + + +/** + * @param {string} key Key name. + * @return {string} Change name. + */ +ol.Object.getChangeEventType = function(key) { + return ol.Object.changeEventTypeCache_.hasOwnProperty(key) ? + ol.Object.changeEventTypeCache_[key] : + (ol.Object.changeEventTypeCache_[key] = 'change:' + key); }; -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview A base class for event objects. - * + * Gets a value. + * @param {string} key Key name. + * @return {*} Value. + * @api stable */ +ol.Object.prototype.get = function(key) { + var value; + if (this.values_.hasOwnProperty(key)) { + value = this.values_[key]; + } + return value; +}; -goog.provide('goog.events.Event'); -goog.provide('goog.events.EventLike'); +/** + * Get a list of object property names. + * @return {Array.<string>} List of property names. + * @api stable + */ +ol.Object.prototype.getKeys = function() { + return Object.keys(this.values_); +}; + /** - * goog.events.Event no longer depends on goog.Disposable. Keep requiring - * goog.Disposable here to not break projects which assume this dependency. - * @suppress {extraRequire} + * Get an object of all property names and values. + * @return {Object.<string, *>} Object. + * @api stable */ -goog.require('goog.Disposable'); -goog.require('goog.events.EventId'); +ol.Object.prototype.getProperties = function() { + var properties = {}; + var key; + for (key in this.values_) { + properties[key] = this.values_[key]; + } + return properties; +}; /** - * A typedef for event like objects that are dispatchable via the - * goog.events.dispatchEvent function. strings are treated as the type for a - * goog.events.Event. Objects are treated as an extension of a new - * goog.events.Event with the type property of the object being used as the type - * of the Event. - * @typedef {string|Object|goog.events.Event|goog.events.EventId} + * @param {string} key Key name. + * @param {*} oldValue Old value. */ -goog.events.EventLike; +ol.Object.prototype.notify = function(key, oldValue) { + var eventType; + eventType = ol.Object.getChangeEventType(key); + this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue)); + eventType = ol.ObjectEventType.PROPERTYCHANGE; + this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue)); +}; + + +/** + * Sets a value. + * @param {string} key Key name. + * @param {*} value Value. + * @param {boolean=} opt_silent Update without triggering an event. + * @api stable + */ +ol.Object.prototype.set = function(key, value, opt_silent) { + if (opt_silent) { + this.values_[key] = value; + } else { + var oldValue = this.values_[key]; + this.values_[key] = value; + if (oldValue !== value) { + this.notify(key, oldValue); + } + } +}; + +/** + * Sets a collection of key-value pairs. Note that this changes any existing + * properties and adds new ones (it does not remove any existing properties). + * @param {Object.<string, *>} values Values. + * @param {boolean=} opt_silent Update without triggering an event. + * @api stable + */ +ol.Object.prototype.setProperties = function(values, opt_silent) { + var key; + for (key in values) { + this.set(key, values[key], opt_silent); + } +}; /** - * A base class for event objects, so that they can support preventDefault and - * stopPropagation. - * - * @param {string|!goog.events.EventId} type Event Type. - * @param {Object=} opt_target Reference to the object that is the target of - * this event. It has to implement the {@code EventTarget} interface - * declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}. - * @constructor + * Unsets a property. + * @param {string} key Key name. + * @param {boolean=} opt_silent Unset without triggering an event. + * @api stable */ -goog.events.Event = function(type, opt_target) { - /** - * Event type. - * @type {string} - */ - this.type = type instanceof goog.events.EventId ? String(type) : type; +ol.Object.prototype.unset = function(key, opt_silent) { + if (key in this.values_) { + var oldValue = this.values_[key]; + delete this.values_[key]; + if (!opt_silent) { + this.notify(key, oldValue); + } + } +}; - /** - * TODO(tbreisacher): The type should probably be - * EventTarget|goog.events.EventTarget. - * - * Target of the event. - * @type {Object|undefined} - */ - this.target = opt_target; +/** + * An implementation of Google Maps' MVCArray. + * @see https://developers.google.com/maps/documentation/javascript/reference + */ - /** - * Object that had the listener attached. - * @type {Object|undefined} - */ - this.currentTarget = this.target; +goog.provide('ol.Collection'); +goog.provide('ol.CollectionEvent'); +goog.provide('ol.CollectionEventType'); + +goog.require('goog.array'); +goog.require('goog.events.Event'); +goog.require('ol.Object'); + +/** + * @enum {string} + */ +ol.CollectionEventType = { /** - * Whether to cancel the event in internal capture/bubble processing for IE. - * @type {boolean} - * @public - * @suppress {underscore|visibility} Technically public, but referencing this - * outside this package is strongly discouraged. + * Triggered when an item is added to the collection. + * @event ol.CollectionEvent#add + * @api stable */ - this.propagationStopped_ = false; - + ADD: 'add', /** - * Whether the default action has been prevented. - * This is a property to match the W3C specification at - * {@link http://www.w3.org/TR/DOM-Level-3-Events/ - * #events-event-type-defaultPrevented}. - * Must be treated as read-only outside the class. - * @type {boolean} + * Triggered when an item is removed from the collection. + * @event ol.CollectionEvent#remove + * @api stable */ - this.defaultPrevented = false; + REMOVE: 'remove' +}; + + + +/** + * @classdesc + * Events emitted by {@link ol.Collection} instances are instances of this + * type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.CollectionEvent} + * @param {ol.CollectionEventType} type Type. + * @param {*=} opt_element Element. + * @param {Object=} opt_target Target. + */ +ol.CollectionEvent = function(type, opt_element, opt_target) { + + goog.base(this, type, opt_target); /** - * Return value for in internal capture/bubble processing for IE. - * @type {boolean} - * @public - * @suppress {underscore|visibility} Technically public, but referencing this - * outside this package is strongly discouraged. + * The element that is added to or removed from the collection. + * @type {*} + * @api stable */ - this.returnValue_ = true; + this.element = opt_element; + }; +goog.inherits(ol.CollectionEvent, goog.events.Event); /** - * Stops event propagation. + * @enum {string} */ -goog.events.Event.prototype.stopPropagation = function() { - this.propagationStopped_ = true; +ol.CollectionProperty = { + LENGTH: 'length' }; + /** - * Prevents the default action, for example a link redirecting to a url. + * @classdesc + * An expanded version of standard JS Array, adding convenience methods for + * manipulation. Add and remove changes to the Collection trigger a Collection + * event. Note that this does not cover changes to the objects _within_ the + * Collection; they trigger events on the appropriate object, not on the + * Collection as a whole. + * + * @constructor + * @extends {ol.Object} + * @fires ol.CollectionEvent + * @param {!Array.<T>=} opt_array Array. + * @template T + * @api stable */ -goog.events.Event.prototype.preventDefault = function() { - this.defaultPrevented = true; - this.returnValue_ = false; +ol.Collection = function(opt_array) { + + goog.base(this); + + /** + * @private + * @type {!Array.<T>} + */ + this.array_ = opt_array ? opt_array : []; + + this.updateLength_(); + }; +goog.inherits(ol.Collection, ol.Object); /** - * Stops the propagation of the event. It is equivalent to - * {@code e.stopPropagation()}, but can be used as the callback argument of - * {@link goog.events.listen} without declaring another function. - * @param {!goog.events.Event} e An event. + * Remove all elements from the collection. + * @api stable */ -goog.events.Event.stopPropagation = function(e) { - e.stopPropagation(); +ol.Collection.prototype.clear = function() { + while (this.getLength() > 0) { + this.pop(); + } }; /** - * Prevents the default action. It is equivalent to - * {@code e.preventDefault()}, but can be used as the callback argument of - * {@link goog.events.listen} without declaring another function. - * @param {!goog.events.Event} e An event. + * Add elements to the collection. This pushes each item in the provided array + * to the end of the collection. + * @param {!Array.<T>} arr Array. + * @return {ol.Collection.<T>} This collection. + * @api stable */ -goog.events.Event.preventDefault = function(e) { - e.preventDefault(); +ol.Collection.prototype.extend = function(arr) { + var i, ii; + for (i = 0, ii = arr.length; i < ii; ++i) { + this.push(arr[i]); + } + return this; }; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Event Types. - * - * @author arv@google.com (Erik Arvidsson) + * Iterate over each element, calling the provided callback. + * @param {function(this: S, T, number, Array.<T>): *} f The function to call + * for every element. This function takes 3 arguments (the element, the + * index and the array). The return value is ignored. + * @param {S=} opt_this The object to use as `this` in `f`. + * @template S + * @api stable */ +ol.Collection.prototype.forEach = function(f, opt_this) { + this.array_.forEach(f, opt_this); +}; -goog.provide('goog.events.EventType'); - -goog.require('goog.userAgent'); +/** + * Get a reference to the underlying Array object. Warning: if the array + * is mutated, no events will be dispatched by the collection, and the + * collection's "length" property won't be in sync with the actual length + * of the array. + * @return {!Array.<T>} Array. + * @api stable + */ +ol.Collection.prototype.getArray = function() { + return this.array_; +}; /** - * Returns a prefixed event name for the current browser. - * @param {string} eventName The name of the event. - * @return {string} The prefixed event name. - * @suppress {missingRequire|missingProvide} - * @private + * Get the element at the provided index. + * @param {number} index Index. + * @return {T} Element. + * @api stable */ -goog.events.getVendorPrefixedName_ = function(eventName) { - return goog.userAgent.WEBKIT ? 'webkit' + eventName : - (goog.userAgent.OPERA ? 'o' + eventName.toLowerCase() : - eventName.toLowerCase()); +ol.Collection.prototype.item = function(index) { + return this.array_[index]; }; /** - * Constants for event names. - * @enum {string} - */ -goog.events.EventType = { - // Mouse events - CLICK: 'click', - RIGHTCLICK: 'rightclick', - DBLCLICK: 'dblclick', - MOUSEDOWN: 'mousedown', - MOUSEUP: 'mouseup', - MOUSEOVER: 'mouseover', - MOUSEOUT: 'mouseout', - MOUSEMOVE: 'mousemove', - MOUSEENTER: 'mouseenter', - MOUSELEAVE: 'mouseleave', - // Select start is non-standard. - // See http://msdn.microsoft.com/en-us/library/ie/ms536969(v=vs.85).aspx. - SELECTSTART: 'selectstart', // IE, Safari, Chrome - - // Wheel events - // http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents - WHEEL: 'wheel', - - // Key events - KEYPRESS: 'keypress', - KEYDOWN: 'keydown', - KEYUP: 'keyup', - - // Focus - BLUR: 'blur', - FOCUS: 'focus', - DEACTIVATE: 'deactivate', // IE only - // NOTE: The following two events are not stable in cross-browser usage. - // WebKit and Opera implement DOMFocusIn/Out. - // IE implements focusin/out. - // Gecko implements neither see bug at - // https://bugzilla.mozilla.org/show_bug.cgi?id=396927. - // The DOM Events Level 3 Draft deprecates DOMFocusIn in favor of focusin: - // http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html - // You can use FOCUS in Capture phase until implementations converge. - FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn', - FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut', - - // Forms - CHANGE: 'change', - RESET: 'reset', - SELECT: 'select', - SUBMIT: 'submit', - INPUT: 'input', - PROPERTYCHANGE: 'propertychange', // IE only - - // Drag and drop - DRAGSTART: 'dragstart', - DRAG: 'drag', - DRAGENTER: 'dragenter', - DRAGOVER: 'dragover', - DRAGLEAVE: 'dragleave', - DROP: 'drop', - DRAGEND: 'dragend', - - // Touch events - // Note that other touch events exist, but we should follow the W3C list here. - // http://www.w3.org/TR/touch-events/#list-of-touchevent-types - TOUCHSTART: 'touchstart', - TOUCHMOVE: 'touchmove', - TOUCHEND: 'touchend', - TOUCHCANCEL: 'touchcancel', - - // Misc - BEFOREUNLOAD: 'beforeunload', - CONSOLEMESSAGE: 'consolemessage', - CONTEXTMENU: 'contextmenu', - DOMCONTENTLOADED: 'DOMContentLoaded', - ERROR: 'error', - HELP: 'help', - LOAD: 'load', - LOSECAPTURE: 'losecapture', - ORIENTATIONCHANGE: 'orientationchange', - READYSTATECHANGE: 'readystatechange', - RESIZE: 'resize', - SCROLL: 'scroll', - UNLOAD: 'unload', + * Get the length of this collection. + * @return {number} The length of the array. + * @observable + * @api stable + */ +ol.Collection.prototype.getLength = function() { + return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH)); +}; - // HTML 5 History events - // See http://www.w3.org/TR/html5/browsers.html#event-definitions-0 - HASHCHANGE: 'hashchange', - PAGEHIDE: 'pagehide', - PAGESHOW: 'pageshow', - POPSTATE: 'popstate', - // Copy and Paste - // Support is limited. Make sure it works on your favorite browser - // before using. - // http://www.quirksmode.org/dom/events/cutcopypaste.html - COPY: 'copy', - PASTE: 'paste', - CUT: 'cut', - BEFORECOPY: 'beforecopy', - BEFORECUT: 'beforecut', - BEFOREPASTE: 'beforepaste', +/** + * Insert an element at the provided index. + * @param {number} index Index. + * @param {T} elem Element. + * @api stable + */ +ol.Collection.prototype.insertAt = function(index, elem) { + goog.array.insertAt(this.array_, elem, index); + this.updateLength_(); + this.dispatchEvent( + new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); +}; - // HTML5 online/offline events. - // http://www.w3.org/TR/offline-webapps/#related - ONLINE: 'online', - OFFLINE: 'offline', - // HTML 5 worker events - MESSAGE: 'message', - CONNECT: 'connect', +/** + * Remove the last element of the collection and return it. + * Return `undefined` if the collection is empty. + * @return {T|undefined} Element. + * @api stable + */ +ol.Collection.prototype.pop = function() { + return this.removeAt(this.getLength() - 1); +}; - // CSS animation events. - /** @suppress {missingRequire} */ - ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'), - /** @suppress {missingRequire} */ - ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'), - /** @suppress {missingRequire} */ - ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'), - // CSS transition events. Based on the browser support described at: - // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility - /** @suppress {missingRequire} */ - TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'), +/** + * Insert the provided element at the end of the collection. + * @param {T} elem Element. + * @return {number} Length. + * @api stable + */ +ol.Collection.prototype.push = function(elem) { + var n = this.array_.length; + this.insertAt(n, elem); + return n; +}; - // W3C Pointer Events - // http://www.w3.org/TR/pointerevents/ - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTERCANCEL: 'pointercancel', - POINTERMOVE: 'pointermove', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - GOTPOINTERCAPTURE: 'gotpointercapture', - LOSTPOINTERCAPTURE: 'lostpointercapture', - // IE specific events. - // See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx - // Note: these events will be supplanted in IE11. - MSGESTURECHANGE: 'MSGestureChange', - MSGESTUREEND: 'MSGestureEnd', - MSGESTUREHOLD: 'MSGestureHold', - MSGESTURESTART: 'MSGestureStart', - MSGESTURETAP: 'MSGestureTap', - MSGOTPOINTERCAPTURE: 'MSGotPointerCapture', - MSINERTIASTART: 'MSInertiaStart', - MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture', - MSPOINTERCANCEL: 'MSPointerCancel', - MSPOINTERDOWN: 'MSPointerDown', - MSPOINTERENTER: 'MSPointerEnter', - MSPOINTERHOVER: 'MSPointerHover', - MSPOINTERLEAVE: 'MSPointerLeave', - MSPOINTERMOVE: 'MSPointerMove', - MSPOINTEROUT: 'MSPointerOut', - MSPOINTEROVER: 'MSPointerOver', - MSPOINTERUP: 'MSPointerUp', +/** + * Remove the first occurrence of an element from the collection. + * @param {T} elem Element. + * @return {T|undefined} The removed element or undefined if none found. + * @api stable + */ +ol.Collection.prototype.remove = function(elem) { + var arr = this.array_; + var i, ii; + for (i = 0, ii = arr.length; i < ii; ++i) { + if (arr[i] === elem) { + return this.removeAt(i); + } + } + return undefined; +}; - // Native IMEs/input tools events. - TEXT: 'text', - TEXTINPUT: 'textInput', - COMPOSITIONSTART: 'compositionstart', - COMPOSITIONUPDATE: 'compositionupdate', - COMPOSITIONEND: 'compositionend', - // Webview tag events - // See http://developer.chrome.com/dev/apps/webview_tag.html - EXIT: 'exit', - LOADABORT: 'loadabort', - LOADCOMMIT: 'loadcommit', - LOADREDIRECT: 'loadredirect', - LOADSTART: 'loadstart', - LOADSTOP: 'loadstop', - RESPONSIVE: 'responsive', - SIZECHANGED: 'sizechanged', - UNRESPONSIVE: 'unresponsive', +/** + * Remove the element at the provided index and return it. + * Return `undefined` if the collection does not contain this index. + * @param {number} index Index. + * @return {T|undefined} Value. + * @api stable + */ +ol.Collection.prototype.removeAt = function(index) { + var prev = this.array_[index]; + goog.array.removeAt(this.array_, index); + this.updateLength_(); + this.dispatchEvent( + new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); + return prev; +}; - // HTML5 Page Visibility API. See details at - // {@code goog.labs.dom.PageVisibilityMonitor}. - VISIBILITYCHANGE: 'visibilitychange', - // LocalStorage event. - STORAGE: 'storage', +/** + * Set the element at the provided index. + * @param {number} index Index. + * @param {T} elem Element. + * @api stable + */ +ol.Collection.prototype.setAt = function(index, elem) { + var n = this.getLength(); + if (index < n) { + var prev = this.array_[index]; + this.array_[index] = elem; + this.dispatchEvent( + new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); + this.dispatchEvent( + new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); + } else { + var j; + for (j = n; j < index; ++j) { + this.insertAt(j, undefined); + } + this.insertAt(index, elem); + } +}; - // DOM Level 2 mutation events (deprecated). - DOMSUBTREEMODIFIED: 'DOMSubtreeModified', - DOMNODEINSERTED: 'DOMNodeInserted', - DOMNODEREMOVED: 'DOMNodeRemoved', - DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument', - DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument', - DOMATTRMODIFIED: 'DOMAttrModified', - DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified', - // Print events. - BEFOREPRINT: 'beforeprint', - AFTERPRINT: 'afterprint' +/** + * @private + */ +ol.Collection.prototype.updateLength_ = function() { + this.set(ol.CollectionProperty.LENGTH, this.array_.length); }; -// Copyright 2009 The Closure Library Authors. All Rights Reserved. +// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12184,72 +12627,105 @@ goog.events.EventType = { // See the License for the specific language governing permissions and // limitations under the License. + /** - * @fileoverview Useful compiler idioms. + * @fileoverview Supplies a Float32Array implementation that implements + * most of the Float32Array spec and that can be used when a built-in + * implementation is not available. + * + * Note that if no existing Float32Array implementation is found then + * this class and all its public properties are exported as Float32Array. + * + * Adding support for the other TypedArray classes here does not make sense + * since this vector math library only needs Float32Array. * - * @author johnlenz@google.com (John Lenz) */ +goog.provide('goog.vec.Float32Array'); -goog.provide('goog.reflect'); /** - * Syntax for object literal casts. - * @see http://go/jscompiler-renaming - * @see http://code.google.com/p/closure-compiler/wiki/ - * ExperimentalTypeBasedPropertyRenaming - * - * Use this if you have an object literal whose keys need to have the same names - * as the properties of some class even after they are renamed by the compiler. + * Constructs a new Float32Array. The new array is initialized to all zeros. * - * @param {!Function} type Type to cast to. - * @param {Object} object Object literal to cast. - * @return {Object} The object literal. + * @param {goog.vec.Float32Array|Array|ArrayBuffer|number} p0 + * The length of the array, or an array to initialize the contents of the + * new Float32Array. + * @constructor + * @final */ -goog.reflect.object = function(type, object) { - return object; +goog.vec.Float32Array = function(p0) { + this.length = /** @type {number} */ (p0.length || p0); + for (var i = 0; i < this.length; i++) { + this[i] = p0[i] || 0; + } }; /** - * To assert to the compiler that an operation is needed when it would - * otherwise be stripped. For example: - * <code> - * // Force a layout - * goog.reflect.sinkValue(dialog.offsetHeight); - * </code> - * @type {!Function} + * The number of bytes in an element (as defined by the Typed Array + * specification). + * + * @type {number} */ -goog.reflect.sinkValue = function(x) { - goog.reflect.sinkValue[' '](x); - return x; -}; +goog.vec.Float32Array.BYTES_PER_ELEMENT = 4; /** - * The compiler should optimize this function away iff no one ever uses - * goog.reflect.sinkValue. + * The number of bytes in an element (as defined by the Typed Array + * specification). + * + * @type {number} */ -goog.reflect.sinkValue[' '] = goog.nullFunction; +goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT = 4; /** - * Check if a property can be accessed without throwing an exception. - * @param {Object} obj The owner of the property. - * @param {string} prop The property name. - * @return {boolean} Whether the property is accessible. Will also return true - * if obj is null. + * Sets elements of the array. + * @param {Array<number>|Float32Array} values The array of values. + * @param {number=} opt_offset The offset in this array to start. */ -goog.reflect.canAccessProperty = function(obj, prop) { - /** @preserveTry */ - try { - goog.reflect.sinkValue(obj[prop]); - return true; - } catch (e) {} - return false; +goog.vec.Float32Array.prototype.set = function(values, opt_offset) { + opt_offset = opt_offset || 0; + for (var i = 0; i < values.length && opt_offset + i < this.length; i++) { + this[opt_offset + i] = values[i]; + } }; -// Copyright 2005 The Closure Library Authors. All Rights Reserved. + +/** + * Creates a string representation of this array. + * @return {string} The string version of this array. + * @override + */ +goog.vec.Float32Array.prototype.toString = Array.prototype.join; + + +/** + * Note that we cannot implement the subarray() or (deprecated) slice() + * methods properly since doing so would require being able to overload + * the [] operator which is not possible in javascript. So we leave + * them unimplemented. Any attempt to call these methods will just result + * in a javascript error since we leave them undefined. + */ + + +/** + * If no existing Float32Array implementation is found then we export + * goog.vec.Float32Array as Float32Array. + */ +if (typeof Float32Array == 'undefined') { + goog.exportProperty(goog.vec.Float32Array, 'BYTES_PER_ELEMENT', + goog.vec.Float32Array.BYTES_PER_ELEMENT); + goog.exportProperty(goog.vec.Float32Array.prototype, 'BYTES_PER_ELEMENT', + goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT); + goog.exportProperty(goog.vec.Float32Array.prototype, 'set', + goog.vec.Float32Array.prototype.set); + goog.exportProperty(goog.vec.Float32Array.prototype, 'toString', + goog.vec.Float32Array.prototype.toString); + goog.exportSymbol('Float32Array', goog.vec.Float32Array); +} + +// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12263,394 +12739,186 @@ goog.reflect.canAccessProperty = function(obj, prop) { // See the License for the specific language governing permissions and // limitations under the License. + /** - * @fileoverview A patched, standardized event object for browser events. + * @fileoverview Supplies a Float64Array implementation that implements + * most of the Float64Array spec and that can be used when a built-in + * implementation is not available. * - * <pre> - * The patched event object contains the following members: - * - type {string} Event type, e.g. 'click' - * - target {Object} The element that actually triggered the event - * - currentTarget {Object} The element the listener is attached to - * - relatedTarget {Object} For mouseover and mouseout, the previous object - * - offsetX {number} X-coordinate relative to target - * - offsetY {number} Y-coordinate relative to target - * - clientX {number} X-coordinate relative to viewport - * - clientY {number} Y-coordinate relative to viewport - * - screenX {number} X-coordinate relative to the edge of the screen - * - screenY {number} Y-coordinate relative to the edge of the screen - * - button {number} Mouse button. Use isButton() to test. - * - keyCode {number} Key-code - * - ctrlKey {boolean} Was ctrl key depressed - * - altKey {boolean} Was alt key depressed - * - shiftKey {boolean} Was shift key depressed - * - metaKey {boolean} Was meta key depressed - * - defaultPrevented {boolean} Whether the default action has been prevented - * - state {Object} History state object + * Note that if no existing Float64Array implementation is found then this + * class and all its public properties are exported as Float64Array. * - * NOTE: The keyCode member contains the raw browser keyCode. For normalized - * key and character code use {@link goog.events.KeyHandler}. - * </pre> + * Adding support for the other TypedArray classes here does not make sense + * since this vector math library only needs Float32Array and Float64Array. * - * @author arv@google.com (Erik Arvidsson) */ +goog.provide('goog.vec.Float64Array'); -goog.provide('goog.events.BrowserEvent'); -goog.provide('goog.events.BrowserEvent.MouseButton'); -goog.require('goog.events.BrowserFeature'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.reflect'); -goog.require('goog.userAgent'); +/** + * Constructs a new Float64Array. The new array is initialized to all zeros. + * + * @param {goog.vec.Float64Array|Array|ArrayBuffer|number} p0 + * The length of the array, or an array to initialize the contents of the + * new Float64Array. + * @constructor + * @final + */ +goog.vec.Float64Array = function(p0) { + this.length = /** @type {number} */ (p0.length || p0); + for (var i = 0; i < this.length; i++) { + this[i] = p0[i] || 0; + } +}; /** - * Accepts a browser event object and creates a patched, cross browser event - * object. - * The content of this object will not be initialized if no event object is - * provided. If this is the case, init() needs to be invoked separately. - * @param {Event=} opt_e Browser event object. - * @param {EventTarget=} opt_currentTarget Current target for event. - * @constructor - * @extends {goog.events.Event} + * The number of bytes in an element (as defined by the Typed Array + * specification). + * + * @type {number} */ -goog.events.BrowserEvent = function(opt_e, opt_currentTarget) { - goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : ''); +goog.vec.Float64Array.BYTES_PER_ELEMENT = 8; - /** - * Target that fired the event. - * @override - * @type {Node} - */ - this.target = null; - /** - * Node that had the listener attached. - * @override - * @type {Node|undefined} - */ - this.currentTarget = null; +/** + * The number of bytes in an element (as defined by the Typed Array + * specification). + * + * @type {number} + */ +goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT = 8; - /** - * For mouseover and mouseout events, the related object for the event. - * @type {Node} - */ - this.relatedTarget = null; - /** - * X-coordinate relative to target. - * @type {number} - */ - this.offsetX = 0; - - /** - * Y-coordinate relative to target. - * @type {number} - */ - this.offsetY = 0; - - /** - * X-coordinate relative to the window. - * @type {number} - */ - this.clientX = 0; - - /** - * Y-coordinate relative to the window. - * @type {number} - */ - this.clientY = 0; - - /** - * X-coordinate relative to the monitor. - * @type {number} - */ - this.screenX = 0; - - /** - * Y-coordinate relative to the monitor. - * @type {number} - */ - this.screenY = 0; - - /** - * Which mouse button was pressed. - * @type {number} - */ - this.button = 0; - - /** - * Keycode of key press. - * @type {number} - */ - this.keyCode = 0; - - /** - * Keycode of key press. - * @type {number} - */ - this.charCode = 0; - - /** - * Whether control was pressed at time of event. - * @type {boolean} - */ - this.ctrlKey = false; - - /** - * Whether alt was pressed at time of event. - * @type {boolean} - */ - this.altKey = false; - - /** - * Whether shift was pressed at time of event. - * @type {boolean} - */ - this.shiftKey = false; - - /** - * Whether the meta key was pressed at time of event. - * @type {boolean} - */ - this.metaKey = false; - - /** - * History state object, only set for PopState events where it's a copy of the - * state object provided to pushState or replaceState. - * @type {Object} - */ - this.state = null; - - /** - * Whether the default platform modifier key was pressed at time of event. - * (This is control for all platforms except Mac, where it's Meta.) - * @type {boolean} - */ - this.platformModifierKey = false; - - /** - * The browser event object. - * @private {Event} - */ - this.event_ = null; - - if (opt_e) { - this.init(opt_e, opt_currentTarget); - } -}; -goog.inherits(goog.events.BrowserEvent, goog.events.Event); +/** + * Sets elements of the array. + * @param {Array<number>|Float64Array} values The array of values. + * @param {number=} opt_offset The offset in this array to start. + */ +goog.vec.Float64Array.prototype.set = function(values, opt_offset) { + opt_offset = opt_offset || 0; + for (var i = 0; i < values.length && opt_offset + i < this.length; i++) { + this[opt_offset + i] = values[i]; + } +}; /** - * Normalized button constants for the mouse. - * @enum {number} + * Creates a string representation of this array. + * @return {string} The string version of this array. + * @override */ -goog.events.BrowserEvent.MouseButton = { - LEFT: 0, - MIDDLE: 1, - RIGHT: 2 -}; +goog.vec.Float64Array.prototype.toString = Array.prototype.join; /** - * Static data for mapping mouse buttons. - * @type {!Array<number>} + * Note that we cannot implement the subarray() or (deprecated) slice() + * methods properly since doing so would require being able to overload + * the [] operator which is not possible in javascript. So we leave + * them unimplemented. Any attempt to call these methods will just result + * in a javascript error since we leave them undefined. */ -goog.events.BrowserEvent.IEButtonMap = [ - 1, // LEFT - 4, // MIDDLE - 2 // RIGHT -]; /** - * Accepts a browser event object and creates a patched, cross browser event - * object. - * @param {Event} e Browser event object. - * @param {EventTarget=} opt_currentTarget Current target for event. + * If no existing Float64Array implementation is found then we export + * goog.vec.Float64Array as Float64Array. */ -goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) { - var type = this.type = e.type; +if (typeof Float64Array == 'undefined') { + try { + goog.exportProperty(goog.vec.Float64Array, 'BYTES_PER_ELEMENT', + goog.vec.Float64Array.BYTES_PER_ELEMENT); + } catch (float64ArrayError) { + // Do nothing. This code is in place to fix b/7225850, in which an error + // is incorrectly thrown for Google TV on an old Chrome. + // TODO(user): remove after that version is retired. + } - /** - * On touch devices use the first "changed touch" as the relevant touch. - * @type {Touch} - */ - var relevantTouch = e.changedTouches ? e.changedTouches[0] : null; + goog.exportProperty(goog.vec.Float64Array.prototype, 'BYTES_PER_ELEMENT', + goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT); + goog.exportProperty(goog.vec.Float64Array.prototype, 'set', + goog.vec.Float64Array.prototype.set); + goog.exportProperty(goog.vec.Float64Array.prototype, 'toString', + goog.vec.Float64Array.prototype.toString); + goog.exportSymbol('Float64Array', goog.vec.Float64Array); +} - // TODO(nicksantos): Change this.target to type EventTarget. - this.target = /** @type {Node} */ (e.target) || e.srcElement; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - // TODO(nicksantos): Change this.currentTarget to type EventTarget. - this.currentTarget = /** @type {Node} */ (opt_currentTarget); - var relatedTarget = /** @type {Node} */ (e.relatedTarget); - if (relatedTarget) { - // There's a bug in FireFox where sometimes, relatedTarget will be a - // chrome element, and accessing any property of it will get a permission - // denied exception. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=497780 - if (goog.userAgent.GECKO) { - if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) { - relatedTarget = null; - } - } - // TODO(arv): Use goog.events.EventType when it has been refactored into its - // own file. - } else if (type == goog.events.EventType.MOUSEOVER) { - relatedTarget = e.fromElement; - } else if (type == goog.events.EventType.MOUSEOUT) { - relatedTarget = e.toElement; - } +/** + * @fileoverview Supplies global data types and constants for the vector math + * library. + */ +goog.provide('goog.vec'); +goog.provide('goog.vec.AnyType'); +goog.provide('goog.vec.ArrayType'); +goog.provide('goog.vec.Float32'); +goog.provide('goog.vec.Float64'); +goog.provide('goog.vec.Number'); - this.relatedTarget = relatedTarget; - if (!goog.isNull(relevantTouch)) { - this.clientX = relevantTouch.clientX !== undefined ? - relevantTouch.clientX : relevantTouch.pageX; - this.clientY = relevantTouch.clientY !== undefined ? - relevantTouch.clientY : relevantTouch.pageY; - this.screenX = relevantTouch.screenX || 0; - this.screenY = relevantTouch.screenY || 0; - } else { - // Webkit emits a lame warning whenever layerX/layerY is accessed. - // http://code.google.com/p/chromium/issues/detail?id=101733 - this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ? - e.offsetX : e.layerX; - this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ? - e.offsetY : e.layerY; - this.clientX = e.clientX !== undefined ? e.clientX : e.pageX; - this.clientY = e.clientY !== undefined ? e.clientY : e.pageY; - this.screenX = e.screenX || 0; - this.screenY = e.screenY || 0; - } +/** + * On platforms that don't have native Float32Array or Float64Array support we + * use a javascript implementation so that this math library can be used on all + * platforms. + * @suppress {extraRequire} + */ +goog.require('goog.vec.Float32Array'); +/** @suppress {extraRequire} */ +goog.require('goog.vec.Float64Array'); - this.button = e.button; +// All vector and matrix operations are based upon arrays of numbers using +// either Float32Array, Float64Array, or a standard Javascript Array of +// Numbers. - this.keyCode = e.keyCode || 0; - this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0); - this.ctrlKey = e.ctrlKey; - this.altKey = e.altKey; - this.shiftKey = e.shiftKey; - this.metaKey = e.metaKey; - this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey; - this.state = e.state; - this.event_ = e; - if (e.defaultPrevented) { - this.preventDefault(); - } -}; +/** @typedef {!Float32Array} */ +goog.vec.Float32; -/** - * Tests to see which button was pressed during the event. This is really only - * useful in IE and Gecko browsers. And in IE, it's only useful for - * mousedown/mouseup events, because click only fires for the left mouse button. - * - * Safari 2 only reports the left button being clicked, and uses the value '1' - * instead of 0. Opera only reports a mousedown event for the middle button, and - * no mouse events for the right button. Opera has default behavior for left and - * middle click that can only be overridden via a configuration setting. - * - * There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html. - * - * @param {goog.events.BrowserEvent.MouseButton} button The button - * to test for. - * @return {boolean} True if button was pressed. - */ -goog.events.BrowserEvent.prototype.isButton = function(button) { - if (!goog.events.BrowserFeature.HAS_W3C_BUTTON) { - if (this.type == 'click') { - return button == goog.events.BrowserEvent.MouseButton.LEFT; - } else { - return !!(this.event_.button & - goog.events.BrowserEvent.IEButtonMap[button]); - } - } else { - return this.event_.button == button; - } -}; +/** @typedef {!Float64Array} */ +goog.vec.Float64; -/** - * Whether this has an "action"-producing mouse button. - * - * By definition, this includes left-click on windows/linux, and left-click - * without the ctrl key on Macs. - * - * @return {boolean} The result. - */ -goog.events.BrowserEvent.prototype.isMouseActionButton = function() { - // Webkit does not ctrl+click to be a right-click, so we - // normalize it to behave like Gecko and Opera. - return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) && - !(goog.userAgent.WEBKIT && goog.userAgent.MAC && this.ctrlKey); -}; +/** @typedef {!Array<number>} */ +goog.vec.Number; -/** - * @override - */ -goog.events.BrowserEvent.prototype.stopPropagation = function() { - goog.events.BrowserEvent.superClass_.stopPropagation.call(this); - if (this.event_.stopPropagation) { - this.event_.stopPropagation(); - } else { - this.event_.cancelBubble = true; - } -}; + +/** @typedef {!goog.vec.Float32|!goog.vec.Float64|!goog.vec.Number} */ +goog.vec.AnyType; /** - * @override + * @deprecated Use AnyType. + * @typedef {!Float32Array|!Array<number>} */ -goog.events.BrowserEvent.prototype.preventDefault = function() { - goog.events.BrowserEvent.superClass_.preventDefault.call(this); - var be = this.event_; - if (!be.preventDefault) { - be.returnValue = false; - if (goog.events.BrowserFeature.SET_KEY_CODE_TO_PREVENT_DEFAULT) { - /** @preserveTry */ - try { - // Most keys can be prevented using returnValue. Some special keys - // require setting the keyCode to -1 as well: - // - // In IE7: - // F3, F5, F10, F11, Ctrl+P, Crtl+O, Ctrl+F (these are taken from IE6) - // - // In IE8: - // Ctrl+P, Crtl+O, Ctrl+F (F1-F12 cannot be stopped through the event) - // - // We therefore do this for all function keys as well as when Ctrl key - // is pressed. - var VK_F1 = 112; - var VK_F12 = 123; - if (be.ctrlKey || be.keyCode >= VK_F1 && be.keyCode <= VK_F12) { - be.keyCode = -1; - } - } catch (ex) { - // IE throws an 'access denied' exception when trying to change - // keyCode in some situations (e.g. srcElement is input[type=file], - // or srcElement is an anchor tag rewritten by parent's innerHTML). - // Do nothing in this case. - } - } - } else { - be.preventDefault(); - } -}; +goog.vec.ArrayType; /** - * @return {Event} The underlying browser event object. + * For graphics work, 6 decimal places of accuracy are typically all that is + * required. + * + * @type {number} + * @const */ -goog.events.BrowserEvent.prototype.getBrowserEvent = function() { - return this.event_; -}; +goog.vec.EPSILON = 1e-6; -// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12664,329 +12932,536 @@ goog.events.BrowserEvent.prototype.getBrowserEvent = function() { // See the License for the specific language governing permissions and // limitations under the License. + /** - * @fileoverview An interface for a listenable JavaScript object. - * @author chrishenry@google.com (Chris Henry) + * @fileoverview Supplies 3 element vectors that are compatible with WebGL. + * Each element is a float32 since that is typically the desired size of a + * 3-vector in the GPU. The API is structured to avoid unnecessary memory + * allocations. The last parameter will typically be the output vector and + * an object can be both an input and output parameter to all methods except + * where noted. + * */ - -goog.provide('goog.events.Listenable'); -goog.provide('goog.events.ListenableKey'); +goog.provide('goog.vec.Vec3'); /** @suppress {extraRequire} */ -goog.require('goog.events.EventId'); +goog.require('goog.vec'); + +/** @typedef {goog.vec.Float32} */ goog.vec.Vec3.Float32; +/** @typedef {goog.vec.Float64} */ goog.vec.Vec3.Float64; +/** @typedef {goog.vec.Number} */ goog.vec.Vec3.Number; +/** @typedef {goog.vec.AnyType} */ goog.vec.Vec3.AnyType; +// The following two types are deprecated - use the above types instead. +/** @typedef {Float32Array} */ goog.vec.Vec3.Type; +/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec3.Vec3Like; /** - * A listenable interface. A listenable is an object with the ability - * to dispatch/broadcast events to "event listeners" registered via - * listen/listenOnce. - * - * The interface allows for an event propagation mechanism similar - * to one offered by native browser event targets, such as - * capture/bubble mechanism, stopping propagation, and preventing - * default actions. Capture/bubble mechanism depends on the ancestor - * tree constructed via {@code #getParentEventTarget}; this tree - * must be directed acyclic graph. The meaning of default action(s) - * in preventDefault is specific to a particular use case. - * - * Implementations that do not support capture/bubble or can not have - * a parent listenable can simply not implement any ability to set the - * parent listenable (and have {@code #getParentEventTarget} return - * null). - * - * Implementation of this class can be used with or independently from - * goog.events. - * - * Implementation must call {@code #addImplementation(implClass)}. + * Creates a 3 element vector of Float32. The array is initialized to zero. * - * @interface - * @see goog.events - * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html + * @return {!goog.vec.Vec3.Float32} The new 3 element array. */ -goog.events.Listenable = function() {}; +goog.vec.Vec3.createFloat32 = function() { + return new Float32Array(3); +}; /** - * An expando property to indicate that an object implements - * goog.events.Listenable. - * - * See addImplementation/isImplementedBy. + * Creates a 3 element vector of Float64. The array is initialized to zero. * - * @type {string} - * @const + * @return {!goog.vec.Vec3.Float64} The new 3 element array. */ -goog.events.Listenable.IMPLEMENTED_BY_PROP = - 'closure_listenable_' + ((Math.random() * 1e6) | 0); +goog.vec.Vec3.createFloat64 = function() { + return new Float64Array(3); +}; /** - * Marks a given class (constructor) as an implementation of - * Listenable, do that we can query that fact at runtime. The class - * must have already implemented the interface. - * @param {!Function} cls The class constructor. The corresponding - * class must have already implemented the interface. + * Creates a 3 element vector of Number. The array is initialized to zero. + * + * @return {!goog.vec.Vec3.Number} The new 3 element array. */ -goog.events.Listenable.addImplementation = function(cls) { - cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true; +goog.vec.Vec3.createNumber = function() { + var a = new Array(3); + goog.vec.Vec3.setFromValues(a, 0, 0, 0); + return a; }; /** - * @param {Object} obj The object to check. - * @return {boolean} Whether a given instance implements Listenable. The - * class/superclass of the instance must call addImplementation. + * Creates a 3 element vector of Float32Array. The array is initialized to zero. + * + * @deprecated Use createFloat32. + * @return {!goog.vec.Vec3.Type} The new 3 element array. */ -goog.events.Listenable.isImplementedBy = function(obj) { - return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]); +goog.vec.Vec3.create = function() { + return new Float32Array(3); }; /** - * Adds an event listener. A listener can only be added once to an - * object and if it is added again the key for the listener is - * returned. Note that if the existing listener is a one-off listener - * (registered via listenOnce), it will no longer be a one-off - * listener after a call to listen(). + * Creates a new 3 element FLoat32 vector initialized with the value from the + * given array. * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @template SCOPE,EVENTOBJ + * @param {goog.vec.Vec3.AnyType} vec The source 3 element array. + * @return {!goog.vec.Vec3.Float32} The new 3 element array. */ -goog.events.Listenable.prototype.listen; +goog.vec.Vec3.createFloat32FromArray = function(vec) { + var newVec = goog.vec.Vec3.createFloat32(); + goog.vec.Vec3.setFromArray(newVec, vec); + return newVec; +}; /** - * Adds an event listener that is removed automatically after the - * listener fired once. - * - * If an existing listener already exists, listenOnce will do - * nothing. In particular, if the listener was previously registered - * via listen(), listenOnce() will not turn the listener into a - * one-off listener. Similarly, if there is already an existing - * one-off listener, listenOnce does not modify the listeners (it is - * still a once listener). + * Creates a new 3 element Float32 vector initialized with the supplied values. * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @template SCOPE,EVENTOBJ + * @param {number} v0 The value for element at index 0. + * @param {number} v1 The value for element at index 1. + * @param {number} v2 The value for element at index 2. + * @return {!goog.vec.Vec3.Float32} The new vector. */ -goog.events.Listenable.prototype.listenOnce; +goog.vec.Vec3.createFloat32FromValues = function(v0, v1, v2) { + var a = goog.vec.Vec3.createFloat32(); + goog.vec.Vec3.setFromValues(a, v0, v1, v2); + return a; +}; /** - * Removes an event listener which was added with listen() or listenOnce(). + * Creates a clone of the given 3 element Float32 vector. * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call - * the listener. - * @return {boolean} Whether any listener was removed. - * @template SCOPE,EVENTOBJ + * @param {goog.vec.Vec3.Float32} vec The source 3 element vector. + * @return {!goog.vec.Vec3.Float32} The new cloned vector. */ -goog.events.Listenable.prototype.unlisten; +goog.vec.Vec3.cloneFloat32 = goog.vec.Vec3.createFloat32FromArray; /** - * Removes an event listener which was added with listen() by the key - * returned by listen(). + * Creates a new 3 element Float64 vector initialized with the value from the + * given array. * - * @param {goog.events.ListenableKey} key The key returned by - * listen() or listenOnce(). - * @return {boolean} Whether any listener was removed. + * @param {goog.vec.Vec3.AnyType} vec The source 3 element array. + * @return {!goog.vec.Vec3.Float64} The new 3 element array. */ -goog.events.Listenable.prototype.unlistenByKey; +goog.vec.Vec3.createFloat64FromArray = function(vec) { + var newVec = goog.vec.Vec3.createFloat64(); + goog.vec.Vec3.setFromArray(newVec, vec); + return newVec; +}; /** - * Dispatches an event (or event like object) and calls all listeners - * listening for events of this type. The type of the event is decided by the - * type property on the event object. +* Creates a new 3 element Float64 vector initialized with the supplied values. +* +* @param {number} v0 The value for element at index 0. +* @param {number} v1 The value for element at index 1. +* @param {number} v2 The value for element at index 2. +* @return {!goog.vec.Vec3.Float64} The new vector. +*/ +goog.vec.Vec3.createFloat64FromValues = function(v0, v1, v2) { + var vec = goog.vec.Vec3.createFloat64(); + goog.vec.Vec3.setFromValues(vec, v0, v1, v2); + return vec; +}; + + +/** + * Creates a clone of the given 3 element vector. * - * If any of the listeners returns false OR calls preventDefault then this - * function will return false. If one of the capture listeners calls - * stopPropagation, then the bubble listeners won't fire. + * @param {goog.vec.Vec3.Float64} vec The source 3 element vector. + * @return {!goog.vec.Vec3.Float64} The new cloned vector. + */ +goog.vec.Vec3.cloneFloat64 = goog.vec.Vec3.createFloat64FromArray; + + +/** + * Creates a new 3 element vector initialized with the value from the given + * array. * - * @param {goog.events.EventLike} e Event object. - * @return {boolean} If anyone called preventDefault on the event object (or - * if any of the listeners returns false) this will also return false. + * @deprecated Use createFloat32FromArray. + * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element array. + * @return {!goog.vec.Vec3.Type} The new 3 element array. */ -goog.events.Listenable.prototype.dispatchEvent; +goog.vec.Vec3.createFromArray = function(vec) { + var newVec = goog.vec.Vec3.create(); + goog.vec.Vec3.setFromArray(newVec, vec); + return newVec; +}; /** - * Removes all listeners from this listenable. If type is specified, - * it will only remove listeners of the particular type. otherwise all - * registered listeners will be removed. + * Creates a new 3 element vector initialized with the supplied values. * - * @param {string=} opt_type Type of event to remove, default is to - * remove all types. - * @return {number} Number of listeners removed. + * @deprecated Use createFloat32FromValues. + * @param {number} v0 The value for element at index 0. + * @param {number} v1 The value for element at index 1. + * @param {number} v2 The value for element at index 2. + * @return {!goog.vec.Vec3.Type} The new vector. */ -goog.events.Listenable.prototype.removeAllListeners; +goog.vec.Vec3.createFromValues = function(v0, v1, v2) { + var vec = goog.vec.Vec3.create(); + goog.vec.Vec3.setFromValues(vec, v0, v1, v2); + return vec; +}; /** - * Returns the parent of this event target to use for capture/bubble - * mechanism. + * Creates a clone of the given 3 element vector. * - * NOTE(chrishenry): The name reflects the original implementation of - * custom event target ({@code goog.events.EventTarget}). We decided - * that changing the name is not worth it. + * @deprecated Use cloneFloat32. + * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element vector. + * @return {!goog.vec.Vec3.Type} The new cloned vector. + */ +goog.vec.Vec3.clone = function(vec) { + var newVec = goog.vec.Vec3.create(); + goog.vec.Vec3.setFromArray(newVec, vec); + return newVec; +}; + + +/** + * Initializes the vector with the given values. * - * @return {goog.events.Listenable} The parent EventTarget or null if - * there is no parent. + * @param {goog.vec.Vec3.AnyType} vec The vector to receive the values. + * @param {number} v0 The value for element at index 0. + * @param {number} v1 The value for element at index 1. + * @param {number} v2 The value for element at index 2. + * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be + * chained together. */ -goog.events.Listenable.prototype.getParentEventTarget; +goog.vec.Vec3.setFromValues = function(vec, v0, v1, v2) { + vec[0] = v0; + vec[1] = v1; + vec[2] = v2; + return vec; +}; /** - * Fires all registered listeners in this listenable for the given - * type and capture mode, passing them the given eventObject. This - * does not perform actual capture/bubble. Only implementors of the - * interface should be using this. + * Initializes the vector with the given array of values. * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the - * listeners to fire. - * @param {boolean} capture The capture mode of the listeners to fire. - * @param {EVENTOBJ} eventObject The event object to fire. - * @return {boolean} Whether all listeners succeeded without - * attempting to prevent default behavior. If any listener returns - * false or called goog.events.Event#preventDefault, this returns - * false. - * @template EVENTOBJ + * @param {goog.vec.Vec3.AnyType} vec The vector to receive the + * values. + * @param {goog.vec.Vec3.AnyType} values The array of values. + * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be + * chained together. */ -goog.events.Listenable.prototype.fireListeners; +goog.vec.Vec3.setFromArray = function(vec, values) { + vec[0] = values[0]; + vec[1] = values[1]; + vec[2] = values[2]; + return vec; +}; /** - * Gets all listeners in this listenable for the given type and - * capture mode. + * Performs a component-wise addition of vec0 and vec1 together storing the + * result into resultVec. * - * @param {string|!goog.events.EventId} type The type of the listeners to fire. - * @param {boolean} capture The capture mode of the listeners to fire. - * @return {!Array<goog.events.ListenableKey>} An array of registered - * listeners. - * @template EVENTOBJ + * @param {goog.vec.Vec3.AnyType} vec0 The first addend. + * @param {goog.vec.Vec3.AnyType} vec1 The second addend. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to + * receive the result. May be vec0 or vec1. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.Listenable.prototype.getListeners; +goog.vec.Vec3.add = function(vec0, vec1, resultVec) { + resultVec[0] = vec0[0] + vec1[0]; + resultVec[1] = vec0[1] + vec1[1]; + resultVec[2] = vec0[2] + vec1[2]; + return resultVec; +}; /** - * Gets the goog.events.ListenableKey for the event or null if no such - * listener is in use. + * Performs a component-wise subtraction of vec1 from vec0 storing the + * result into resultVec. * - * @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event - * without the 'on' prefix. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The - * listener function to get. - * @param {boolean} capture Whether the listener is a capturing listener. - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} the found listener or null if not found. - * @template SCOPE,EVENTOBJ + * @param {goog.vec.Vec3.AnyType} vec0 The minuend. + * @param {goog.vec.Vec3.AnyType} vec1 The subtrahend. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to + * receive the result. May be vec0 or vec1. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.Listenable.prototype.getListener; +goog.vec.Vec3.subtract = function(vec0, vec1, resultVec) { + resultVec[0] = vec0[0] - vec1[0]; + resultVec[1] = vec0[1] - vec1[1]; + resultVec[2] = vec0[2] - vec1[2]; + return resultVec; +}; /** - * Whether there is any active listeners matching the specified - * signature. If either the type or capture parameters are - * unspecified, the function will match on the remaining criteria. + * Negates vec0, storing the result into resultVec. * - * @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type. - * @param {boolean=} opt_capture Whether to check for capture or bubble - * listeners. - * @return {boolean} Whether there is any active listeners matching - * the requested type and/or capture phase. - * @template EVENTOBJ + * @param {goog.vec.Vec3.AnyType} vec0 The vector to negate. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to + * receive the result. May be vec0. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.Listenable.prototype.hasListener; +goog.vec.Vec3.negate = function(vec0, resultVec) { + resultVec[0] = -vec0[0]; + resultVec[1] = -vec0[1]; + resultVec[2] = -vec0[2]; + return resultVec; +}; +/** + * Takes the absolute value of each component of vec0 storing the result in + * resultVec. + * + * @param {goog.vec.Vec3.AnyType} vec0 The source vector. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the result. + * May be vec0. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec3.abs = function(vec0, resultVec) { + resultVec[0] = Math.abs(vec0[0]); + resultVec[1] = Math.abs(vec0[1]); + resultVec[2] = Math.abs(vec0[2]); + return resultVec; +}; + /** - * An interface that describes a single registered listener. - * @interface + * Multiplies each component of vec0 with scalar storing the product into + * resultVec. + * + * @param {goog.vec.Vec3.AnyType} vec0 The source vector. + * @param {number} scalar The value to multiply with each component of vec0. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to + * receive the result. May be vec0. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenableKey = function() {}; +goog.vec.Vec3.scale = function(vec0, scalar, resultVec) { + resultVec[0] = vec0[0] * scalar; + resultVec[1] = vec0[1] * scalar; + resultVec[2] = vec0[2] * scalar; + return resultVec; +}; /** - * Counter used to create a unique key - * @type {number} - * @private + * Returns the magnitudeSquared of the given vector. + * + * @param {goog.vec.Vec3.AnyType} vec0 The vector. + * @return {number} The magnitude of the vector. */ -goog.events.ListenableKey.counter_ = 0; +goog.vec.Vec3.magnitudeSquared = function(vec0) { + var x = vec0[0], y = vec0[1], z = vec0[2]; + return x * x + y * y + z * z; +}; /** - * Reserves a key to be used for ListenableKey#key field. - * @return {number} A number to be used to fill ListenableKey#key - * field. + * Returns the magnitude of the given vector. + * + * @param {goog.vec.Vec3.AnyType} vec0 The vector. + * @return {number} The magnitude of the vector. */ -goog.events.ListenableKey.reserveKey = function() { - return ++goog.events.ListenableKey.counter_; +goog.vec.Vec3.magnitude = function(vec0) { + var x = vec0[0], y = vec0[1], z = vec0[2]; + return Math.sqrt(x * x + y * y + z * z); }; /** - * The source event target. - * @type {!(Object|goog.events.Listenable|goog.events.EventTarget)} + * Normalizes the given vector storing the result into resultVec. + * + * @param {goog.vec.Vec3.AnyType} vec0 The vector to normalize. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to + * receive the result. May be vec0. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenableKey.prototype.src; +goog.vec.Vec3.normalize = function(vec0, resultVec) { + var ilen = 1 / goog.vec.Vec3.magnitude(vec0); + resultVec[0] = vec0[0] * ilen; + resultVec[1] = vec0[1] * ilen; + resultVec[2] = vec0[2] * ilen; + return resultVec; +}; /** - * The event type the listener is listening to. - * @type {string} + * Returns the scalar product of vectors v0 and v1. + * + * @param {goog.vec.Vec3.AnyType} v0 The first vector. + * @param {goog.vec.Vec3.AnyType} v1 The second vector. + * @return {number} The scalar product. */ -goog.events.ListenableKey.prototype.type; +goog.vec.Vec3.dot = function(v0, v1) { + return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]; +}; /** - * The listener function. - * @type {function(?):?|{handleEvent:function(?):?}|null} + * Computes the vector (cross) product of v0 and v1 storing the result into + * resultVec. + * + * @param {goog.vec.Vec3.AnyType} v0 The first vector. + * @param {goog.vec.Vec3.AnyType} v1 The second vector. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the + * results. May be either v0 or v1. + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenableKey.prototype.listener; +goog.vec.Vec3.cross = function(v0, v1, resultVec) { + var x0 = v0[0], y0 = v0[1], z0 = v0[2]; + var x1 = v1[0], y1 = v1[1], z1 = v1[2]; + resultVec[0] = y0 * z1 - z0 * y1; + resultVec[1] = z0 * x1 - x0 * z1; + resultVec[2] = x0 * y1 - y0 * x1; + return resultVec; +}; /** - * Whether the listener works on capture phase. - * @type {boolean} + * Returns the squared distance between two points. + * + * @param {goog.vec.Vec3.AnyType} vec0 First point. + * @param {goog.vec.Vec3.AnyType} vec1 Second point. + * @return {number} The squared distance between the points. */ -goog.events.ListenableKey.prototype.capture; +goog.vec.Vec3.distanceSquared = function(vec0, vec1) { + var x = vec0[0] - vec1[0]; + var y = vec0[1] - vec1[1]; + var z = vec0[2] - vec1[2]; + return x * x + y * y + z * z; +}; /** - * The 'this' object for the listener function's scope. - * @type {Object} + * Returns the distance between two points. + * + * @param {goog.vec.Vec3.AnyType} vec0 First point. + * @param {goog.vec.Vec3.AnyType} vec1 Second point. + * @return {number} The distance between the points. */ -goog.events.ListenableKey.prototype.handler; +goog.vec.Vec3.distance = function(vec0, vec1) { + return Math.sqrt(goog.vec.Vec3.distanceSquared(vec0, vec1)); +}; /** - * A globally unique number to identify the key. - * @type {number} + * Returns a unit vector pointing from one point to another. + * If the input points are equal then the result will be all zeros. + * + * @param {goog.vec.Vec3.AnyType} vec0 Origin point. + * @param {goog.vec.Vec3.AnyType} vec1 Target point. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the + * results (may be vec0 or vec1). + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenableKey.prototype.key; +goog.vec.Vec3.direction = function(vec0, vec1, resultVec) { + var x = vec1[0] - vec0[0]; + var y = vec1[1] - vec0[1]; + var z = vec1[2] - vec0[2]; + var d = Math.sqrt(x * x + y * y + z * z); + if (d) { + d = 1 / d; + resultVec[0] = x * d; + resultVec[1] = y * d; + resultVec[2] = z * d; + } else { + resultVec[0] = resultVec[1] = resultVec[2] = 0; + } + return resultVec; +}; -// Copyright 2005 The Closure Library Authors. All Rights Reserved. + +/** + * Linearly interpolate from vec0 to v1 according to f. The value of f should be + * in the range [0..1] otherwise the results are undefined. + * + * @param {goog.vec.Vec3.AnyType} v0 The first vector. + * @param {goog.vec.Vec3.AnyType} v1 The second vector. + * @param {number} f The interpolation factor. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the + * results (may be v0 or v1). + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec3.lerp = function(v0, v1, f, resultVec) { + var x = v0[0], y = v0[1], z = v0[2]; + resultVec[0] = (v1[0] - x) * f + x; + resultVec[1] = (v1[1] - y) * f + y; + resultVec[2] = (v1[2] - z) * f + z; + return resultVec; +}; + + +/** + * Compares the components of vec0 with the components of another vector or + * scalar, storing the larger values in resultVec. + * + * @param {goog.vec.Vec3.AnyType} vec0 The source vector. + * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the + * results (may be vec0 or limit). + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec3.max = function(vec0, limit, resultVec) { + if (goog.isNumber(limit)) { + resultVec[0] = Math.max(vec0[0], limit); + resultVec[1] = Math.max(vec0[1], limit); + resultVec[2] = Math.max(vec0[2], limit); + } else { + resultVec[0] = Math.max(vec0[0], limit[0]); + resultVec[1] = Math.max(vec0[1], limit[1]); + resultVec[2] = Math.max(vec0[2], limit[2]); + } + return resultVec; +}; + + +/** + * Compares the components of vec0 with the components of another vector or + * scalar, storing the smaller values in resultVec. + * + * @param {goog.vec.Vec3.AnyType} vec0 The source vector. + * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar. + * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the + * results (may be vec0 or limit). + * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec3.min = function(vec0, limit, resultVec) { + if (goog.isNumber(limit)) { + resultVec[0] = Math.min(vec0[0], limit); + resultVec[1] = Math.min(vec0[1], limit); + resultVec[2] = Math.min(vec0[2], limit); + } else { + resultVec[0] = Math.min(vec0[0], limit[0]); + resultVec[1] = Math.min(vec0[1], limit[1]); + resultVec[2] = Math.min(vec0[2], limit[2]); + } + return resultVec; +}; + + +/** + * Returns true if the components of v0 are equal to the components of v1. + * + * @param {goog.vec.Vec3.AnyType} v0 The first vector. + * @param {goog.vec.Vec3.AnyType} v1 The second vector. + * @return {boolean} True if the vectors are equal, false otherwise. + */ +goog.vec.Vec3.equals = function(v0, v1) { + return v0.length == v1.length && + v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2]; +}; + +// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13000,434 +13475,473 @@ goog.events.ListenableKey.prototype.key; // See the License for the specific language governing permissions and // limitations under the License. + /** - * @fileoverview Listener object. - * @see ../demos/events.html + * @fileoverview Supplies 4 element vectors that are compatible with WebGL. + * Each element is a float32 since that is typically the desired size of a + * 4-vector in the GPU. The API is structured to avoid unnecessary memory + * allocations. The last parameter will typically be the output vector and + * an object can be both an input and output parameter to all methods except + * where noted. + * */ +goog.provide('goog.vec.Vec4'); -goog.provide('goog.events.Listener'); +/** @suppress {extraRequire} */ +goog.require('goog.vec'); -goog.require('goog.events.ListenableKey'); +/** @typedef {goog.vec.Float32} */ goog.vec.Vec4.Float32; +/** @typedef {goog.vec.Float64} */ goog.vec.Vec4.Float64; +/** @typedef {goog.vec.Number} */ goog.vec.Vec4.Number; +/** @typedef {goog.vec.AnyType} */ goog.vec.Vec4.AnyType; +// The following two types are deprecated - use the above types instead. +/** @typedef {Float32Array} */ goog.vec.Vec4.Type; +/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec4.Vec4Like; /** - * Simple class that stores information about a listener - * @param {!Function} listener Callback function. - * @param {Function} proxy Wrapper for the listener that patches the event. - * @param {EventTarget|goog.events.Listenable} src Source object for - * the event. - * @param {string} type Event type. - * @param {boolean} capture Whether in capture or bubble phase. - * @param {Object=} opt_handler Object in whose context to execute the callback. - * @implements {goog.events.ListenableKey} - * @constructor + * Creates a 4 element vector of Float32. The array is initialized to zero. + * + * @return {!goog.vec.Vec4.Float32} The new 3 element array. */ -goog.events.Listener = function( - listener, proxy, src, type, capture, opt_handler) { - if (goog.events.Listener.ENABLE_MONITORING) { - this.creationStack = new Error().stack; - } +goog.vec.Vec4.createFloat32 = function() { + return new Float32Array(4); +}; - /** - * Callback function. - * @type {Function} - */ - this.listener = listener; - /** - * A wrapper over the original listener. This is used solely to - * handle native browser events (it is used to simulate the capture - * phase and to patch the event object). - * @type {Function} - */ - this.proxy = proxy; +/** + * Creates a 4 element vector of Float64. The array is initialized to zero. + * + * @return {!goog.vec.Vec4.Float64} The new 4 element array. + */ +goog.vec.Vec4.createFloat64 = function() { + return new Float64Array(4); +}; - /** - * Object or node that callback is listening to - * @type {EventTarget|goog.events.Listenable} - */ - this.src = src; - - /** - * The event type. - * @const {string} - */ - this.type = type; - - /** - * Whether the listener is being called in the capture or bubble phase - * @const {boolean} - */ - this.capture = !!capture; - - /** - * Optional object whose context to execute the listener in - * @type {Object|undefined} - */ - this.handler = opt_handler; - /** - * The key of the listener. - * @const {number} - * @override - */ - this.key = goog.events.ListenableKey.reserveKey(); +/** + * Creates a 4 element vector of Number. The array is initialized to zero. + * + * @return {!goog.vec.Vec4.Number} The new 4 element array. + */ +goog.vec.Vec4.createNumber = function() { + var v = new Array(4); + goog.vec.Vec4.setFromValues(v, 0, 0, 0, 0); + return v; +}; - /** - * Whether to remove the listener after it has been called. - * @type {boolean} - */ - this.callOnce = false; - /** - * Whether the listener has been removed. - * @type {boolean} - */ - this.removed = false; +/** + * Creates a 4 element vector of Float32Array. The array is initialized to zero. + * + * @deprecated Use createFloat32. + * @return {!goog.vec.Vec4.Type} The new 4 element array. + */ +goog.vec.Vec4.create = function() { + return new Float32Array(4); }; /** - * @define {boolean} Whether to enable the monitoring of the - * goog.events.Listener instances. Switching on the monitoring is only - * recommended for debugging because it has a significant impact on - * performance and memory usage. If switched off, the monitoring code - * compiles down to 0 bytes. + * Creates a new 4 element vector initialized with the value from the given + * array. + * + * @deprecated Use createFloat32FromArray. + * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element array. + * @return {!goog.vec.Vec4.Type} The new 4 element array. */ -goog.define('goog.events.Listener.ENABLE_MONITORING', false); +goog.vec.Vec4.createFromArray = function(vec) { + var newVec = goog.vec.Vec4.create(); + goog.vec.Vec4.setFromArray(newVec, vec); + return newVec; +}; /** - * If monitoring the goog.events.Listener instances is enabled, stores the - * creation stack trace of the Disposable instance. - * @type {string} + * Creates a new 4 element FLoat32 vector initialized with the value from the + * given array. + * + * @param {goog.vec.Vec4.AnyType} vec The source 3 element array. + * @return {!goog.vec.Vec4.Float32} The new 3 element array. */ -goog.events.Listener.prototype.creationStack; +goog.vec.Vec4.createFloat32FromArray = function(vec) { + var newVec = goog.vec.Vec4.createFloat32(); + goog.vec.Vec4.setFromArray(newVec, vec); + return newVec; +}; /** - * Marks this listener as removed. This also remove references held by - * this listener object (such as listener and event source). + * Creates a new 4 element Float32 vector initialized with the supplied values. + * + * @param {number} v0 The value for element at index 0. + * @param {number} v1 The value for element at index 1. + * @param {number} v2 The value for element at index 2. + * @param {number} v3 The value for element at index 3. + * @return {!goog.vec.Vec4.Float32} The new vector. */ -goog.events.Listener.prototype.markAsRemoved = function() { - this.removed = true; - this.listener = null; - this.proxy = null; - this.src = null; - this.handler = null; +goog.vec.Vec4.createFloat32FromValues = function(v0, v1, v2, v3) { + var vec = goog.vec.Vec4.createFloat32(); + goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); + return vec; }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview A map of listeners that provides utility functions to - * deal with listeners on an event target. Used by - * {@code goog.events.EventTarget}. - * - * WARNING: Do not use this class from outside goog.events package. + * Creates a clone of the given 4 element Float32 vector. * - * @visibility {//closure/goog/bin/sizetests:__pkg__} - * @visibility {//closure/goog/events:__pkg__} - * @visibility {//closure/goog/labs/events:__pkg__} + * @param {goog.vec.Vec4.Float32} vec The source 3 element vector. + * @return {!goog.vec.Vec4.Float32} The new cloned vector. */ +goog.vec.Vec4.cloneFloat32 = goog.vec.Vec4.createFloat32FromArray; -goog.provide('goog.events.ListenerMap'); -goog.require('goog.array'); -goog.require('goog.events.Listener'); -goog.require('goog.object'); +/** + * Creates a new 4 element Float64 vector initialized with the value from the + * given array. + * + * @param {goog.vec.Vec4.AnyType} vec The source 4 element array. + * @return {!goog.vec.Vec4.Float64} The new 4 element array. + */ +goog.vec.Vec4.createFloat64FromArray = function(vec) { + var newVec = goog.vec.Vec4.createFloat64(); + goog.vec.Vec4.setFromArray(newVec, vec); + return newVec; +}; +/** +* Creates a new 4 element Float64 vector initialized with the supplied values. +* +* @param {number} v0 The value for element at index 0. +* @param {number} v1 The value for element at index 1. +* @param {number} v2 The value for element at index 2. +* @param {number} v3 The value for element at index 3. +* @return {!goog.vec.Vec4.Float64} The new vector. +*/ +goog.vec.Vec4.createFloat64FromValues = function(v0, v1, v2, v3) { + var vec = goog.vec.Vec4.createFloat64(); + goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); + return vec; +}; + /** - * Creates a new listener map. - * @param {EventTarget|goog.events.Listenable} src The src object. - * @constructor - * @final + * Creates a clone of the given 4 element vector. + * + * @param {goog.vec.Vec4.Float64} vec The source 4 element vector. + * @return {!goog.vec.Vec4.Float64} The new cloned vector. */ -goog.events.ListenerMap = function(src) { - /** @type {EventTarget|goog.events.Listenable} */ - this.src = src; +goog.vec.Vec4.cloneFloat64 = goog.vec.Vec4.createFloat64FromArray; - /** - * Maps of event type to an array of listeners. - * @type {Object<string, !Array<!goog.events.Listener>>} - */ - this.listeners = {}; - /** - * The count of types in this map that have registered listeners. - * @private {number} - */ - this.typeCount_ = 0; +/** + * Creates a new 4 element vector initialized with the supplied values. + * + * @deprecated Use createFloat32FromValues. + * @param {number} v0 The value for element at index 0. + * @param {number} v1 The value for element at index 1. + * @param {number} v2 The value for element at index 2. + * @param {number} v3 The value for element at index 3. + * @return {!goog.vec.Vec4.Type} The new vector. + */ +goog.vec.Vec4.createFromValues = function(v0, v1, v2, v3) { + var vec = goog.vec.Vec4.create(); + goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); + return vec; }; /** - * @return {number} The count of event types in this map that actually - * have registered listeners. + * Creates a clone of the given 4 element vector. + * + * @deprecated Use cloneFloat32. + * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element vector. + * @return {!goog.vec.Vec4.Type} The new cloned vector. */ -goog.events.ListenerMap.prototype.getTypeCount = function() { - return this.typeCount_; -}; +goog.vec.Vec4.clone = goog.vec.Vec4.createFromArray; /** - * @return {number} Total number of registered listeners. + * Initializes the vector with the given values. + * + * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values. + * @param {number} v0 The value for element at index 0. + * @param {number} v1 The value for element at index 1. + * @param {number} v2 The value for element at index 2. + * @param {number} v3 The value for element at index 3. + * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.getListenerCount = function() { - var count = 0; - for (var type in this.listeners) { - count += this.listeners[type].length; - } - return count; +goog.vec.Vec4.setFromValues = function(vec, v0, v1, v2, v3) { + vec[0] = v0; + vec[1] = v1; + vec[2] = v2; + vec[3] = v3; + return vec; }; /** - * Adds an event listener. A listener can only be added once to an - * object and if it is added again the key for the listener is - * returned. - * - * Note that a one-off listener will not change an existing listener, - * if any. On the other hand a normal listener will change existing - * one-off listener to become a normal listener. + * Initializes the vector with the given array of values. * - * @param {string|!goog.events.EventId} type The listener event type. - * @param {!Function} listener This listener callback method. - * @param {boolean} callOnce Whether the listener is a one-off - * listener. - * @param {boolean=} opt_useCapture The capture mode of the listener. - * @param {Object=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. + * @param {goog.vec.Vec4.AnyType} vec The vector to receive the + * values. + * @param {goog.vec.Vec4.AnyType} values The array of values. + * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.add = function( - type, listener, callOnce, opt_useCapture, opt_listenerScope) { - var typeStr = type.toString(); - var listenerArray = this.listeners[typeStr]; - if (!listenerArray) { - listenerArray = this.listeners[typeStr] = []; - this.typeCount_++; - } - - var listenerObj; - var index = goog.events.ListenerMap.findListenerIndex_( - listenerArray, listener, opt_useCapture, opt_listenerScope); - if (index > -1) { - listenerObj = listenerArray[index]; - if (!callOnce) { - // Ensure that, if there is an existing callOnce listener, it is no - // longer a callOnce listener. - listenerObj.callOnce = false; - } - } else { - listenerObj = new goog.events.Listener( - listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope); - listenerObj.callOnce = callOnce; - listenerArray.push(listenerObj); - } - return listenerObj; +goog.vec.Vec4.setFromArray = function(vec, values) { + vec[0] = values[0]; + vec[1] = values[1]; + vec[2] = values[2]; + vec[3] = values[3]; + return vec; }; /** - * Removes a matching listener. - * @param {string|!goog.events.EventId} type The listener event type. - * @param {!Function} listener This listener callback method. - * @param {boolean=} opt_useCapture The capture mode of the listener. - * @param {Object=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {boolean} Whether any listener was removed. + * Performs a component-wise addition of vec0 and vec1 together storing the + * result into resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The first addend. + * @param {goog.vec.Vec4.AnyType} vec1 The second addend. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to + * receive the result. May be vec0 or vec1. + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.remove = function( - type, listener, opt_useCapture, opt_listenerScope) { - var typeStr = type.toString(); - if (!(typeStr in this.listeners)) { - return false; - } - - var listenerArray = this.listeners[typeStr]; - var index = goog.events.ListenerMap.findListenerIndex_( - listenerArray, listener, opt_useCapture, opt_listenerScope); - if (index > -1) { - var listenerObj = listenerArray[index]; - listenerObj.markAsRemoved(); - goog.array.removeAt(listenerArray, index); - if (listenerArray.length == 0) { - delete this.listeners[typeStr]; - this.typeCount_--; - } - return true; - } - return false; +goog.vec.Vec4.add = function(vec0, vec1, resultVec) { + resultVec[0] = vec0[0] + vec1[0]; + resultVec[1] = vec0[1] + vec1[1]; + resultVec[2] = vec0[2] + vec1[2]; + resultVec[3] = vec0[3] + vec1[3]; + return resultVec; }; /** - * Removes the given listener object. - * @param {goog.events.ListenableKey} listener The listener to remove. - * @return {boolean} Whether the listener is removed. + * Performs a component-wise subtraction of vec1 from vec0 storing the + * result into resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The minuend. + * @param {goog.vec.Vec4.AnyType} vec1 The subtrahend. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to + * receive the result. May be vec0 or vec1. + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.removeByKey = function(listener) { - var type = listener.type; - if (!(type in this.listeners)) { - return false; - } - - var removed = goog.array.remove(this.listeners[type], listener); - if (removed) { - listener.markAsRemoved(); - if (this.listeners[type].length == 0) { - delete this.listeners[type]; - this.typeCount_--; - } - } - return removed; +goog.vec.Vec4.subtract = function(vec0, vec1, resultVec) { + resultVec[0] = vec0[0] - vec1[0]; + resultVec[1] = vec0[1] - vec1[1]; + resultVec[2] = vec0[2] - vec1[2]; + resultVec[3] = vec0[3] - vec1[3]; + return resultVec; }; /** - * Removes all listeners from this map. If opt_type is provided, only - * listeners that match the given type are removed. - * @param {string|!goog.events.EventId=} opt_type Type of event to remove. - * @return {number} Number of listeners removed. + * Negates vec0, storing the result into resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The vector to negate. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to + * receive the result. May be vec0. + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.removeAll = function(opt_type) { - var typeStr = opt_type && opt_type.toString(); - var count = 0; - for (var type in this.listeners) { - if (!typeStr || type == typeStr) { - var listenerArray = this.listeners[type]; - for (var i = 0; i < listenerArray.length; i++) { - ++count; - listenerArray[i].markAsRemoved(); - } - delete this.listeners[type]; - this.typeCount_--; - } - } - return count; +goog.vec.Vec4.negate = function(vec0, resultVec) { + resultVec[0] = -vec0[0]; + resultVec[1] = -vec0[1]; + resultVec[2] = -vec0[2]; + resultVec[3] = -vec0[3]; + return resultVec; }; /** - * Gets all listeners that match the given type and capture mode. The - * returned array is a copy (but the listener objects are not). - * @param {string|!goog.events.EventId} type The type of the listeners - * to retrieve. - * @param {boolean} capture The capture mode of the listeners to retrieve. - * @return {!Array<goog.events.ListenableKey>} An array of matching - * listeners. + * Takes the absolute value of each component of vec0 storing the result in + * resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The source vector. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the result. + * May be vec0. + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.getListeners = function(type, capture) { - var listenerArray = this.listeners[type.toString()]; - var rv = []; - if (listenerArray) { - for (var i = 0; i < listenerArray.length; ++i) { - var listenerObj = listenerArray[i]; - if (listenerObj.capture == capture) { - rv.push(listenerObj); - } - } - } - return rv; +goog.vec.Vec4.abs = function(vec0, resultVec) { + resultVec[0] = Math.abs(vec0[0]); + resultVec[1] = Math.abs(vec0[1]); + resultVec[2] = Math.abs(vec0[2]); + resultVec[3] = Math.abs(vec0[3]); + return resultVec; }; /** - * Gets the goog.events.ListenableKey for the event or null if no such - * listener is in use. + * Multiplies each component of vec0 with scalar storing the product into + * resultVec. * - * @param {string|!goog.events.EventId} type The type of the listener - * to retrieve. - * @param {!Function} listener The listener function to get. - * @param {boolean} capture Whether the listener is a capturing listener. - * @param {Object=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} the found listener or null if not found. + * @param {goog.vec.Vec4.AnyType} vec0 The source vector. + * @param {number} scalar The value to multiply with each component of vec0. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to + * receive the result. May be vec0. + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenerMap.prototype.getListener = function( - type, listener, capture, opt_listenerScope) { - var listenerArray = this.listeners[type.toString()]; - var i = -1; - if (listenerArray) { - i = goog.events.ListenerMap.findListenerIndex_( - listenerArray, listener, capture, opt_listenerScope); - } - return i > -1 ? listenerArray[i] : null; +goog.vec.Vec4.scale = function(vec0, scalar, resultVec) { + resultVec[0] = vec0[0] * scalar; + resultVec[1] = vec0[1] * scalar; + resultVec[2] = vec0[2] * scalar; + resultVec[3] = vec0[3] * scalar; + return resultVec; }; /** - * Whether there is a matching listener. If either the type or capture - * parameters are unspecified, the function will match on the - * remaining criteria. + * Returns the magnitudeSquared of the given vector. * - * @param {string|!goog.events.EventId=} opt_type The type of the listener. - * @param {boolean=} opt_capture The capture mode of the listener. - * @return {boolean} Whether there is an active listener matching - * the requested type and/or capture phase. + * @param {goog.vec.Vec4.AnyType} vec0 The vector. + * @return {number} The magnitude of the vector. */ -goog.events.ListenerMap.prototype.hasListener = function( - opt_type, opt_capture) { - var hasType = goog.isDef(opt_type); - var typeStr = hasType ? opt_type.toString() : ''; - var hasCapture = goog.isDef(opt_capture); +goog.vec.Vec4.magnitudeSquared = function(vec0) { + var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3]; + return x * x + y * y + z * z + w * w; +}; - return goog.object.some( - this.listeners, function(listenerArray, type) { - for (var i = 0; i < listenerArray.length; ++i) { - if ((!hasType || listenerArray[i].type == typeStr) && - (!hasCapture || listenerArray[i].capture == opt_capture)) { - return true; - } - } - return false; - }); +/** + * Returns the magnitude of the given vector. + * + * @param {goog.vec.Vec4.AnyType} vec0 The vector. + * @return {number} The magnitude of the vector. + */ +goog.vec.Vec4.magnitude = function(vec0) { + var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3]; + return Math.sqrt(x * x + y * y + z * z + w * w); }; /** - * Finds the index of a matching goog.events.Listener in the given - * listenerArray. - * @param {!Array<!goog.events.Listener>} listenerArray Array of listener. - * @param {!Function} listener The listener function. - * @param {boolean=} opt_useCapture The capture flag for the listener. - * @param {Object=} opt_listenerScope The listener scope. - * @return {number} The index of the matching listener within the - * listenerArray. - * @private + * Normalizes the given vector storing the result into resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The vector to normalize. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to + * receive the result. May be vec0. + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. */ -goog.events.ListenerMap.findListenerIndex_ = function( - listenerArray, listener, opt_useCapture, opt_listenerScope) { - for (var i = 0; i < listenerArray.length; ++i) { - var listenerObj = listenerArray[i]; - if (!listenerObj.removed && - listenerObj.listener == listener && - listenerObj.capture == !!opt_useCapture && - listenerObj.handler == opt_listenerScope) { - return i; - } +goog.vec.Vec4.normalize = function(vec0, resultVec) { + var ilen = 1 / goog.vec.Vec4.magnitude(vec0); + resultVec[0] = vec0[0] * ilen; + resultVec[1] = vec0[1] * ilen; + resultVec[2] = vec0[2] * ilen; + resultVec[3] = vec0[3] * ilen; + return resultVec; +}; + + +/** + * Returns the scalar product of vectors v0 and v1. + * + * @param {goog.vec.Vec4.AnyType} v0 The first vector. + * @param {goog.vec.Vec4.AnyType} v1 The second vector. + * @return {number} The scalar product. + */ +goog.vec.Vec4.dot = function(v0, v1) { + return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2] + v0[3] * v1[3]; +}; + + +/** + * Linearly interpolate from v0 to v1 according to f. The value of f should be + * in the range [0..1] otherwise the results are undefined. + * + * @param {goog.vec.Vec4.AnyType} v0 The first vector. + * @param {goog.vec.Vec4.AnyType} v1 The second vector. + * @param {number} f The interpolation factor. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the + * results (may be v0 or v1). + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec4.lerp = function(v0, v1, f, resultVec) { + var x = v0[0], y = v0[1], z = v0[2], w = v0[3]; + resultVec[0] = (v1[0] - x) * f + x; + resultVec[1] = (v1[1] - y) * f + y; + resultVec[2] = (v1[2] - z) * f + z; + resultVec[3] = (v1[3] - w) * f + w; + return resultVec; +}; + + +/** + * Compares the components of vec0 with the components of another vector or + * scalar, storing the larger values in resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The source vector. + * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the + * results (may be vec0 or limit). + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec4.max = function(vec0, limit, resultVec) { + if (goog.isNumber(limit)) { + resultVec[0] = Math.max(vec0[0], limit); + resultVec[1] = Math.max(vec0[1], limit); + resultVec[2] = Math.max(vec0[2], limit); + resultVec[3] = Math.max(vec0[3], limit); + } else { + resultVec[0] = Math.max(vec0[0], limit[0]); + resultVec[1] = Math.max(vec0[1], limit[1]); + resultVec[2] = Math.max(vec0[2], limit[2]); + resultVec[3] = Math.max(vec0[3], limit[3]); } - return -1; + return resultVec; }; -// Copyright 2005 The Closure Library Authors. All Rights Reserved. + +/** + * Compares the components of vec0 with the components of another vector or + * scalar, storing the smaller values in resultVec. + * + * @param {goog.vec.Vec4.AnyType} vec0 The source vector. + * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the + * results (may be vec0 or limit). + * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be + * chained together. + */ +goog.vec.Vec4.min = function(vec0, limit, resultVec) { + if (goog.isNumber(limit)) { + resultVec[0] = Math.min(vec0[0], limit); + resultVec[1] = Math.min(vec0[1], limit); + resultVec[2] = Math.min(vec0[2], limit); + resultVec[3] = Math.min(vec0[3], limit); + } else { + resultVec[0] = Math.min(vec0[0], limit[0]); + resultVec[1] = Math.min(vec0[1], limit[1]); + resultVec[2] = Math.min(vec0[2], limit[2]); + resultVec[3] = Math.min(vec0[3], limit[3]); + } + return resultVec; +}; + + +/** + * Returns true if the components of v0 are equal to the components of v1. + * + * @param {goog.vec.Vec4.AnyType} v0 The first vector. + * @param {goog.vec.Vec4.AnyType} v1 The second vector. + * @return {boolean} True if the vectors are equal, false otherwise. + */ +goog.vec.Vec4.equals = function(v0, v1) { + return v0.length == v1.length && + v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2] && v0[3] == v1[3]; +}; + +// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13442,1845 +13956,1813 @@ goog.events.ListenerMap.findListenerIndex_ = function( // limitations under the License. /** - * @fileoverview An event manager for both native browser event - * targets and custom JavaScript event targets - * ({@code goog.events.Listenable}). This provides an abstraction - * over browsers' event systems. - * - * It also provides a simulation of W3C event model's capture phase in - * Internet Explorer (IE 8 and below). Caveat: the simulation does not - * interact well with listeners registered directly on the elements - * (bypassing goog.events) or even with listeners registered via - * goog.events in a separate JS binary. In these cases, we provide - * no ordering guarantees. - * - * The listeners will receive a "patched" event object. Such event object - * contains normalized values for certain event properties that differs in - * different browsers. - * - * Example usage: - * <pre> - * goog.events.listen(myNode, 'click', function(e) { alert('woo') }); - * goog.events.listen(myNode, 'mouseover', mouseHandler, true); - * goog.events.unlisten(myNode, 'mouseover', mouseHandler, true); - * goog.events.removeAll(myNode); - * </pre> + * @fileoverview Implements 4x4 matrices and their related functions which are + * compatible with WebGL. The API is structured to avoid unnecessary memory + * allocations. The last parameter will typically be the output vector and + * an object can be both an input and output parameter to all methods except + * where noted. Matrix operations follow the mathematical form when multiplying + * vectors as follows: resultVec = matrix * vec. * - * in IE and event object patching] - * @author arv@google.com (Erik Arvidsson) + * The matrices are stored in column-major order. * - * @see ../demos/events.html - * @see ../demos/event-propagation.html - * @see ../demos/stopevent.html */ +goog.provide('goog.vec.Mat4'); -// IMPLEMENTATION NOTES: -// goog.events stores an auxiliary data structure on each EventTarget -// source being listened on. This allows us to take advantage of GC, -// having the data structure GC'd when the EventTarget is GC'd. This -// GC behavior is equivalent to using W3C DOM Events directly. +goog.require('goog.vec'); +goog.require('goog.vec.Vec3'); +goog.require('goog.vec.Vec4'); -goog.provide('goog.events'); -goog.provide('goog.events.CaptureSimulationMode'); -goog.provide('goog.events.Key'); -goog.provide('goog.events.ListenableType'); -goog.require('goog.asserts'); -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.BrowserFeature'); -goog.require('goog.events.Listenable'); -goog.require('goog.events.ListenerMap'); +/** @typedef {goog.vec.Float32} */ goog.vec.Mat4.Float32; +/** @typedef {goog.vec.Float64} */ goog.vec.Mat4.Float64; +/** @typedef {goog.vec.Number} */ goog.vec.Mat4.Number; +/** @typedef {goog.vec.AnyType} */ goog.vec.Mat4.AnyType; -goog.forwardDeclare('goog.debug.ErrorHandler'); -goog.forwardDeclare('goog.events.EventWrapper'); +// The following two types are deprecated - use the above types instead. +/** @typedef {!Float32Array} */ goog.vec.Mat4.Type; +/** @typedef {goog.vec.ArrayType} */ goog.vec.Mat4.Mat4Like; /** - * @typedef {number|goog.events.ListenableKey} + * Creates the array representation of a 4x4 matrix of Float32. + * The use of the array directly instead of a class reduces overhead. + * The returned matrix is cleared to all zeros. + * + * @return {!goog.vec.Mat4.Float32} The new matrix. */ -goog.events.Key; +goog.vec.Mat4.createFloat32 = function() { + return new Float32Array(16); +}; /** - * @typedef {EventTarget|goog.events.Listenable} + * Creates the array representation of a 4x4 matrix of Float64. + * The returned matrix is cleared to all zeros. + * + * @return {!goog.vec.Mat4.Float64} The new matrix. */ -goog.events.ListenableType; +goog.vec.Mat4.createFloat64 = function() { + return new Float64Array(16); +}; /** - * Property name on a native event target for the listener map - * associated with the event target. - * @private @const {string} + * Creates the array representation of a 4x4 matrix of Number. + * The returned matrix is cleared to all zeros. + * + * @return {!goog.vec.Mat4.Number} The new matrix. */ -goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0); +goog.vec.Mat4.createNumber = function() { + var a = new Array(16); + goog.vec.Mat4.setFromValues(a, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0); + return a; +}; /** - * String used to prepend to IE event types. - * @const - * @private + * Creates the array representation of a 4x4 matrix of Float32. + * The returned matrix is cleared to all zeros. + * + * @deprecated Use createFloat32. + * @return {!goog.vec.Mat4.Type} The new matrix. */ -goog.events.onString_ = 'on'; +goog.vec.Mat4.create = function() { + return goog.vec.Mat4.createFloat32(); +}; /** - * Map of computed "on<eventname>" strings for IE event types. Caching - * this removes an extra object allocation in goog.events.listen which - * improves IE6 performance. - * @const - * @dict - * @private + * Creates a 4x4 identity matrix of Float32. + * + * @return {!goog.vec.Mat4.Float32} The new 16 element array. */ -goog.events.onStringMap_ = {}; +goog.vec.Mat4.createFloat32Identity = function() { + var mat = goog.vec.Mat4.createFloat32(); + mat[0] = mat[5] = mat[10] = mat[15] = 1; + return mat; +}; /** - * @enum {number} Different capture simulation mode for IE8-. + * Creates a 4x4 identity matrix of Float64. + * + * @return {!goog.vec.Mat4.Float64} The new 16 element array. */ -goog.events.CaptureSimulationMode = { - /** - * Does not perform capture simulation. Will asserts in IE8- when you - * add capture listeners. - */ - OFF_AND_FAIL: 0, - - /** - * Does not perform capture simulation, silently ignore capture - * listeners. - */ - OFF_AND_SILENT: 1, - - /** - * Performs capture simulation. - */ - ON: 2 +goog.vec.Mat4.createFloat64Identity = function() { + var mat = goog.vec.Mat4.createFloat64(); + mat[0] = mat[5] = mat[10] = mat[15] = 1; + return mat; }; /** - * @define {number} The capture simulation mode for IE8-. By default, - * this is ON. + * Creates a 4x4 identity matrix of Number. + * The returned matrix is cleared to all zeros. + * + * @return {!goog.vec.Mat4.Number} The new 16 element array. */ -goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2); +goog.vec.Mat4.createNumberIdentity = function() { + var a = new Array(16); + goog.vec.Mat4.setFromValues(a, + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + return a; +}; /** - * Estimated count of total native listeners. - * @private {number} + * Creates the array representation of a 4x4 matrix of Float32. + * The returned matrix is cleared to all zeros. + * + * @deprecated Use createFloat32Identity. + * @return {!goog.vec.Mat4.Type} The new 16 element array. */ -goog.events.listenerCountEstimate_ = 0; +goog.vec.Mat4.createIdentity = function() { + return goog.vec.Mat4.createFloat32Identity(); +}; /** - * Adds an event listener for a specific event on a native event - * target (such as a DOM element) or an object that has implemented - * {@link goog.events.Listenable}. A listener can only be added once - * to an object and if it is added again the key for the listener is - * returned. Note that if the existing listener is a one-off listener - * (registered via listenOnce), it will no longer be a one-off - * listener after a call to listen(). + * Creates a 4x4 matrix of Float32 initialized from the given array. * - * @param {EventTarget|goog.events.Listenable} src The node to listen - * to events on. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} - * listener Callback method, or an object with a handleEvent function. - * WARNING: passing an Object is now softly deprecated. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {T=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.Key} Unique key for the listener. - * @template T,EVENTOBJ + * @param {goog.vec.Mat4.AnyType} matrix The array containing the + * matrix values in column major order. + * @return {!goog.vec.Mat4.Float32} The new, 16 element array. */ -goog.events.listen = function(src, type, listener, opt_capt, opt_handler) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - goog.events.listen(src, type[i], listener, opt_capt, opt_handler); - } - return null; - } - - listener = goog.events.wrapListener(listener); - if (goog.events.Listenable.isImplementedBy(src)) { - return src.listen( - /** @type {string|!goog.events.EventId} */ (type), - listener, opt_capt, opt_handler); - } else { - return goog.events.listen_( - /** @type {!EventTarget} */ (src), - /** @type {string|!goog.events.EventId} */ (type), - listener, /* callOnce */ false, opt_capt, opt_handler); - } +goog.vec.Mat4.createFloat32FromArray = function(matrix) { + var newMatrix = goog.vec.Mat4.createFloat32(); + goog.vec.Mat4.setFromArray(newMatrix, matrix); + return newMatrix; }; /** - * Adds an event listener for a specific event on a native event - * target. A listener can only be added once to an object and if it - * is added again the key for the listener is returned. - * - * Note that a one-off listener will not change an existing listener, - * if any. On the other hand a normal listener will change existing - * one-off listener to become a normal listener. + * Creates a 4x4 matrix of Float32 initialized from the given values. * - * @param {EventTarget} src The node to listen to events on. - * @param {string|!goog.events.EventId} type Event type. - * @param {!Function} listener Callback function. - * @param {boolean} callOnce Whether the listener is a one-off - * listener or otherwise. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {Object=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @private + * @param {number} v00 The values at (0, 0). + * @param {number} v10 The values at (1, 0). + * @param {number} v20 The values at (2, 0). + * @param {number} v30 The values at (3, 0). + * @param {number} v01 The values at (0, 1). + * @param {number} v11 The values at (1, 1). + * @param {number} v21 The values at (2, 1). + * @param {number} v31 The values at (3, 1). + * @param {number} v02 The values at (0, 2). + * @param {number} v12 The values at (1, 2). + * @param {number} v22 The values at (2, 2). + * @param {number} v32 The values at (3, 2). + * @param {number} v03 The values at (0, 3). + * @param {number} v13 The values at (1, 3). + * @param {number} v23 The values at (2, 3). + * @param {number} v33 The values at (3, 3). + * @return {!goog.vec.Mat4.Float32} The new, 16 element array. */ -goog.events.listen_ = function( - src, type, listener, callOnce, opt_capt, opt_handler) { - if (!type) { - throw Error('Invalid event type'); - } - - var capture = !!opt_capt; - if (capture && !goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { - if (goog.events.CAPTURE_SIMULATION_MODE == - goog.events.CaptureSimulationMode.OFF_AND_FAIL) { - goog.asserts.fail('Can not register capture listener in IE8-.'); - return null; - } else if (goog.events.CAPTURE_SIMULATION_MODE == - goog.events.CaptureSimulationMode.OFF_AND_SILENT) { - return null; - } - } - - var listenerMap = goog.events.getListenerMap_(src); - if (!listenerMap) { - src[goog.events.LISTENER_MAP_PROP_] = listenerMap = - new goog.events.ListenerMap(src); - } - - var listenerObj = listenerMap.add( - type, listener, callOnce, opt_capt, opt_handler); - - // If the listenerObj already has a proxy, it has been set up - // previously. We simply return. - if (listenerObj.proxy) { - return listenerObj; - } +goog.vec.Mat4.createFloat32FromValues = function( + v00, v10, v20, v30, + v01, v11, v21, v31, + v02, v12, v22, v32, + v03, v13, v23, v33) { + var newMatrix = goog.vec.Mat4.createFloat32(); + goog.vec.Mat4.setFromValues( + newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, + v03, v13, v23, v33); + return newMatrix; +}; - var proxy = goog.events.getProxy(); - listenerObj.proxy = proxy; - proxy.src = src; - proxy.listener = listenerObj; +/** + * Creates a clone of a 4x4 matrix of Float32. + * + * @param {goog.vec.Mat4.Float32} matrix The source 4x4 matrix. + * @return {!goog.vec.Mat4.Float32} The new 4x4 element matrix. + */ +goog.vec.Mat4.cloneFloat32 = goog.vec.Mat4.createFloat32FromArray; - // Attach the proxy through the browser's API - if (src.addEventListener) { - src.addEventListener(type.toString(), proxy, capture); - } else if (src.attachEvent) { - // The else if above used to be an unconditional else. It would call - // exception on IE11, spoiling the day of some callers. The previous - // incarnation of this code, from 2007, indicates that it replaced an - // earlier still version that caused excess allocations on IE6. - src.attachEvent(goog.events.getOnString_(type.toString()), proxy); - } else { - throw Error('addEventListener and attachEvent are unavailable.'); - } - goog.events.listenerCountEstimate_++; - return listenerObj; +/** + * Creates a 4x4 matrix of Float64 initialized from the given array. + * + * @param {goog.vec.Mat4.AnyType} matrix The array containing the + * matrix values in column major order. + * @return {!goog.vec.Mat4.Float64} The new, nine element array. + */ +goog.vec.Mat4.createFloat64FromArray = function(matrix) { + var newMatrix = goog.vec.Mat4.createFloat64(); + goog.vec.Mat4.setFromArray(newMatrix, matrix); + return newMatrix; }; /** - * Helper function for returning a proxy function. - * @return {!Function} A new or reused function object. + * Creates a 4x4 matrix of Float64 initialized from the given values. + * + * @param {number} v00 The values at (0, 0). + * @param {number} v10 The values at (1, 0). + * @param {number} v20 The values at (2, 0). + * @param {number} v30 The values at (3, 0). + * @param {number} v01 The values at (0, 1). + * @param {number} v11 The values at (1, 1). + * @param {number} v21 The values at (2, 1). + * @param {number} v31 The values at (3, 1). + * @param {number} v02 The values at (0, 2). + * @param {number} v12 The values at (1, 2). + * @param {number} v22 The values at (2, 2). + * @param {number} v32 The values at (3, 2). + * @param {number} v03 The values at (0, 3). + * @param {number} v13 The values at (1, 3). + * @param {number} v23 The values at (2, 3). + * @param {number} v33 The values at (3, 3). + * @return {!goog.vec.Mat4.Float64} The new, 16 element array. */ -goog.events.getProxy = function() { - var proxyCallbackFunction = goog.events.handleBrowserEvent_; - // Use a local var f to prevent one allocation. - var f = goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT ? - function(eventObject) { - return proxyCallbackFunction.call(f.src, f.listener, eventObject); - } : - function(eventObject) { - var v = proxyCallbackFunction.call(f.src, f.listener, eventObject); - // NOTE(chrishenry): In IE, we hack in a capture phase. However, if - // there is inline event handler which tries to prevent default (for - // example <a href="..." onclick="return false">...</a>) in a - // descendant element, the prevent default will be overridden - // by this listener if this listener were to return true. Hence, we - // return undefined. - if (!v) return v; - }; - return f; +goog.vec.Mat4.createFloat64FromValues = function( + v00, v10, v20, v30, + v01, v11, v21, v31, + v02, v12, v22, v32, + v03, v13, v23, v33) { + var newMatrix = goog.vec.Mat4.createFloat64(); + goog.vec.Mat4.setFromValues( + newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, + v03, v13, v23, v33); + return newMatrix; }; /** - * Adds an event listener for a specific event on a native event - * target (such as a DOM element) or an object that has implemented - * {@link goog.events.Listenable}. After the event has fired the event - * listener is removed from the target. + * Creates a clone of a 4x4 matrix of Float64. * - * If an existing listener already exists, listenOnce will do - * nothing. In particular, if the listener was previously registered - * via listen(), listenOnce() will not turn the listener into a - * one-off listener. Similarly, if there is already an existing - * one-off listener, listenOnce does not modify the listeners (it is - * still a once listener). - * - * @param {EventTarget|goog.events.Listenable} src The node to listen - * to events on. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null} - * listener Callback method. - * @param {boolean=} opt_capt Fire in capture phase?. - * @param {T=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.Key} Unique key for the listener. - * @template T,EVENTOBJ + * @param {goog.vec.Mat4.Float64} matrix The source 4x4 matrix. + * @return {!goog.vec.Mat4.Float64} The new 4x4 element matrix. */ -goog.events.listenOnce = function(src, type, listener, opt_capt, opt_handler) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - goog.events.listenOnce(src, type[i], listener, opt_capt, opt_handler); - } - return null; - } - - listener = goog.events.wrapListener(listener); - if (goog.events.Listenable.isImplementedBy(src)) { - return src.listenOnce( - /** @type {string|!goog.events.EventId} */ (type), - listener, opt_capt, opt_handler); - } else { - return goog.events.listen_( - /** @type {!EventTarget} */ (src), - /** @type {string|!goog.events.EventId} */ (type), - listener, /* callOnce */ true, opt_capt, opt_handler); - } -}; +goog.vec.Mat4.cloneFloat64 = goog.vec.Mat4.createFloat64FromArray; /** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.Listenable}. A listener can - * only be added once to an object. + * Creates a 4x4 matrix of Float32 initialized from the given array. * - * @param {EventTarget|goog.events.Listenable} src The target to - * listen to events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener - * Callback method, or an object with a handleEvent function. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {T=} opt_handler Element in whose scope to call the listener. - * @template T + * @deprecated Use createFloat32FromArray. + * @param {goog.vec.Mat4.Mat4Like} matrix The array containing the + * matrix values in column major order. + * @return {!goog.vec.Mat4.Type} The new, nine element array. */ -goog.events.listenWithWrapper = function(src, wrapper, listener, opt_capt, - opt_handler) { - wrapper.listen(src, listener, opt_capt, opt_handler); +goog.vec.Mat4.createFromArray = function(matrix) { + var newMatrix = goog.vec.Mat4.createFloat32(); + goog.vec.Mat4.setFromArray(newMatrix, matrix); + return newMatrix; }; /** - * Removes an event listener which was added with listen(). + * Creates a 4x4 matrix of Float32 initialized from the given values. * - * @param {EventTarget|goog.events.Listenable} src The target to stop - * listening to events on. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types to unlisten to. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener The - * listener function to remove. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase of the - * event. - * @param {Object=} opt_handler Element in whose scope to call the listener. - * @return {?boolean} indicating whether the listener was there to remove. - * @template EVENTOBJ + * @deprecated Use createFloat32FromValues. + * @param {number} v00 The values at (0, 0). + * @param {number} v10 The values at (1, 0). + * @param {number} v20 The values at (2, 0). + * @param {number} v30 The values at (3, 0). + * @param {number} v01 The values at (0, 1). + * @param {number} v11 The values at (1, 1). + * @param {number} v21 The values at (2, 1). + * @param {number} v31 The values at (3, 1). + * @param {number} v02 The values at (0, 2). + * @param {number} v12 The values at (1, 2). + * @param {number} v22 The values at (2, 2). + * @param {number} v32 The values at (3, 2). + * @param {number} v03 The values at (0, 3). + * @param {number} v13 The values at (1, 3). + * @param {number} v23 The values at (2, 3). + * @param {number} v33 The values at (3, 3). + * @return {!goog.vec.Mat4.Type} The new, 16 element array. */ -goog.events.unlisten = function(src, type, listener, opt_capt, opt_handler) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - goog.events.unlisten(src, type[i], listener, opt_capt, opt_handler); - } - return null; - } - - listener = goog.events.wrapListener(listener); - if (goog.events.Listenable.isImplementedBy(src)) { - return src.unlisten( - /** @type {string|!goog.events.EventId} */ (type), - listener, opt_capt, opt_handler); - } - - if (!src) { - // TODO(chrishenry): We should tighten the API to only accept - // non-null objects, or add an assertion here. - return false; - } - - var capture = !!opt_capt; - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (src)); - if (listenerMap) { - var listenerObj = listenerMap.getListener( - /** @type {string|!goog.events.EventId} */ (type), - listener, capture, opt_handler); - if (listenerObj) { - return goog.events.unlistenByKey(listenerObj); - } - } - - return false; +goog.vec.Mat4.createFromValues = function( + v00, v10, v20, v30, + v01, v11, v21, v31, + v02, v12, v22, v32, + v03, v13, v23, v33) { + return goog.vec.Mat4.createFloat32FromValues( + v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, + v03, v13, v23, v33); }; /** - * Removes an event listener which was added with listen() by the key - * returned by listen(). + * Creates a clone of a 4x4 matrix of Float32. * - * @param {goog.events.Key} key The key returned by listen() for this - * event listener. - * @return {boolean} indicating whether the listener was there to remove. + * @deprecated Use cloneFloat32. + * @param {goog.vec.Mat4.Mat4Like} matrix The source 4x4 matrix. + * @return {!goog.vec.Mat4.Type} The new 4x4 element matrix. */ -goog.events.unlistenByKey = function(key) { - // TODO(chrishenry): Remove this check when tests that rely on this - // are fixed. - if (goog.isNumber(key)) { - return false; - } - - var listener = key; - if (!listener || listener.removed) { - return false; - } - - var src = listener.src; - if (goog.events.Listenable.isImplementedBy(src)) { - return src.unlistenByKey(listener); - } - - var type = listener.type; - var proxy = listener.proxy; - if (src.removeEventListener) { - src.removeEventListener(type, proxy, listener.capture); - } else if (src.detachEvent) { - src.detachEvent(goog.events.getOnString_(type), proxy); - } - goog.events.listenerCountEstimate_--; - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (src)); - // TODO(chrishenry): Try to remove this conditional and execute the - // first branch always. This should be safe. - if (listenerMap) { - listenerMap.removeByKey(listener); - if (listenerMap.getTypeCount() == 0) { - // Null the src, just because this is simple to do (and useful - // for IE <= 7). - listenerMap.src = null; - // We don't use delete here because IE does not allow delete - // on a window object. - src[goog.events.LISTENER_MAP_PROP_] = null; - } - } else { - listener.markAsRemoved(); - } - - return true; -}; +goog.vec.Mat4.clone = goog.vec.Mat4.createFromArray; /** - * Removes an event listener which was added with listenWithWrapper(). + * Retrieves the element at the requested row and column. * - * @param {EventTarget|goog.events.Listenable} src The target to stop - * listening to events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener The - * listener function to remove. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase of the - * event. - * @param {Object=} opt_handler Element in whose scope to call the listener. + * @param {goog.vec.Mat4.AnyType} mat The matrix containing the + * value to retrieve. + * @param {number} row The row index. + * @param {number} column The column index. + * @return {number} The element value at the requested row, column indices. */ -goog.events.unlistenWithWrapper = function(src, wrapper, listener, opt_capt, - opt_handler) { - wrapper.unlisten(src, listener, opt_capt, opt_handler); +goog.vec.Mat4.getElement = function(mat, row, column) { + return mat[row + column * 4]; }; /** - * Removes all listeners from an object. You can also optionally - * remove listeners of a particular type. + * Sets the element at the requested row and column. * - * @param {Object|undefined} obj Object to remove listeners from. Must be an - * EventTarget or a goog.events.Listenable. - * @param {string|!goog.events.EventId=} opt_type Type of event to remove. - * Default is all types. - * @return {number} Number of listeners removed. + * @param {goog.vec.Mat4.AnyType} mat The matrix to set the value on. + * @param {number} row The row index. + * @param {number} column The column index. + * @param {number} value The value to set at the requested row, column. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.removeAll = function(obj, opt_type) { - // TODO(chrishenry): Change the type of obj to - // (!EventTarget|!goog.events.Listenable). - - if (!obj) { - return 0; - } - - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.removeAllListeners(opt_type); - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (obj)); - if (!listenerMap) { - return 0; - } - - var count = 0; - var typeStr = opt_type && opt_type.toString(); - for (var type in listenerMap.listeners) { - if (!typeStr || type == typeStr) { - // Clone so that we don't need to worry about unlistenByKey - // changing the content of the ListenerMap. - var listeners = listenerMap.listeners[type].concat(); - for (var i = 0; i < listeners.length; ++i) { - if (goog.events.unlistenByKey(listeners[i])) { - ++count; - } - } - } - } - return count; +goog.vec.Mat4.setElement = function(mat, row, column, value) { + mat[row + column * 4] = value; + return mat; }; /** - * Gets the listeners for a given object, type and capture phase. + * Initializes the matrix from the set of values. Note the values supplied are + * in column major order. * - * @param {Object} obj Object to get listeners for. - * @param {string|!goog.events.EventId} type Event type. - * @param {boolean} capture Capture phase?. - * @return {Array<goog.events.Listener>} Array of listener objects. + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the + * values. + * @param {number} v00 The values at (0, 0). + * @param {number} v10 The values at (1, 0). + * @param {number} v20 The values at (2, 0). + * @param {number} v30 The values at (3, 0). + * @param {number} v01 The values at (0, 1). + * @param {number} v11 The values at (1, 1). + * @param {number} v21 The values at (2, 1). + * @param {number} v31 The values at (3, 1). + * @param {number} v02 The values at (0, 2). + * @param {number} v12 The values at (1, 2). + * @param {number} v22 The values at (2, 2). + * @param {number} v32 The values at (3, 2). + * @param {number} v03 The values at (0, 3). + * @param {number} v13 The values at (1, 3). + * @param {number} v23 The values at (2, 3). + * @param {number} v33 The values at (3, 3). + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.getListeners = function(obj, type, capture) { - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.getListeners(type, capture); - } else { - if (!obj) { - // TODO(chrishenry): We should tighten the API to accept - // !EventTarget|goog.events.Listenable, and add an assertion here. - return []; - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (obj)); - return listenerMap ? listenerMap.getListeners(type, capture) : []; - } +goog.vec.Mat4.setFromValues = function( + mat, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, + v03, v13, v23, v33) { + mat[0] = v00; + mat[1] = v10; + mat[2] = v20; + mat[3] = v30; + mat[4] = v01; + mat[5] = v11; + mat[6] = v21; + mat[7] = v31; + mat[8] = v02; + mat[9] = v12; + mat[10] = v22; + mat[11] = v32; + mat[12] = v03; + mat[13] = v13; + mat[14] = v23; + mat[15] = v33; + return mat; }; /** - * Gets the goog.events.Listener for the event or null if no such listener is - * in use. + * Sets the matrix from the array of values stored in column major order. * - * @param {EventTarget|goog.events.Listenable} src The target from - * which to get listeners. - * @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The - * listener function to get. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the - * capture or bubble phase of the event. - * @param {Object=} opt_handler Element in whose scope to call the listener. - * @return {goog.events.ListenableKey} the found listener or null if not found. - * @template EVENTOBJ + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {goog.vec.Mat4.AnyType} values The column major ordered + * array of values to store in the matrix. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) { - // TODO(chrishenry): Change type from ?string to string, or add assertion. - type = /** @type {string} */ (type); - listener = goog.events.wrapListener(listener); - var capture = !!opt_capt; - if (goog.events.Listenable.isImplementedBy(src)) { - return src.getListener(type, listener, capture, opt_handler); - } - - if (!src) { - // TODO(chrishenry): We should tighten the API to only accept - // non-null objects, or add an assertion here. - return null; - } - - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (src)); - if (listenerMap) { - return listenerMap.getListener(type, listener, capture, opt_handler); - } - return null; +goog.vec.Mat4.setFromArray = function(mat, values) { + mat[0] = values[0]; + mat[1] = values[1]; + mat[2] = values[2]; + mat[3] = values[3]; + mat[4] = values[4]; + mat[5] = values[5]; + mat[6] = values[6]; + mat[7] = values[7]; + mat[8] = values[8]; + mat[9] = values[9]; + mat[10] = values[10]; + mat[11] = values[11]; + mat[12] = values[12]; + mat[13] = values[13]; + mat[14] = values[14]; + mat[15] = values[15]; + return mat; }; /** - * Returns whether an event target has any active listeners matching the - * specified signature. If either the type or capture parameters are - * unspecified, the function will match on the remaining criteria. + * Sets the matrix from the array of values stored in row major order. * - * @param {EventTarget|goog.events.Listenable} obj Target to get - * listeners for. - * @param {string|!goog.events.EventId=} opt_type Event type. - * @param {boolean=} opt_capture Whether to check for capture or bubble-phase - * listeners. - * @return {boolean} Whether an event target has one or more listeners matching - * the requested type and/or capture phase. + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {goog.vec.Mat4.AnyType} values The row major ordered array of + * values to store in the matrix. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.hasListener = function(obj, opt_type, opt_capture) { - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.hasListener(opt_type, opt_capture); - } +goog.vec.Mat4.setFromRowMajorArray = function(mat, values) { + mat[0] = values[0]; + mat[1] = values[4]; + mat[2] = values[8]; + mat[3] = values[12]; - var listenerMap = goog.events.getListenerMap_( - /** @type {!EventTarget} */ (obj)); - return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture); + mat[4] = values[1]; + mat[5] = values[5]; + mat[6] = values[9]; + mat[7] = values[13]; + + mat[8] = values[2]; + mat[9] = values[6]; + mat[10] = values[10]; + mat[11] = values[14]; + + mat[12] = values[3]; + mat[13] = values[7]; + mat[14] = values[11]; + mat[15] = values[15]; + + return mat; }; /** - * Provides a nice string showing the normalized event objects public members - * @param {Object} e Event Object. - * @return {string} String of the public members of the normalized event object. + * Sets the diagonal values of the matrix from the given values. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {number} v00 The values for (0, 0). + * @param {number} v11 The values for (1, 1). + * @param {number} v22 The values for (2, 2). + * @param {number} v33 The values for (3, 3). + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.expose = function(e) { - var str = []; - for (var key in e) { - if (e[key] && e[key].id) { - str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')'); - } else { - str.push(key + ' = ' + e[key]); - } - } - return str.join('\n'); +goog.vec.Mat4.setDiagonalValues = function(mat, v00, v11, v22, v33) { + mat[0] = v00; + mat[5] = v11; + mat[10] = v22; + mat[15] = v33; + return mat; }; /** - * Returns a string with on prepended to the specified type. This is used for IE - * which expects "on" to be prepended. This function caches the string in order - * to avoid extra allocations in steady state. - * @param {string} type Event type. - * @return {string} The type string with 'on' prepended. - * @private + * Sets the diagonal values of the matrix from the given vector. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {goog.vec.Vec4.AnyType} vec The vector containing the values. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.getOnString_ = function(type) { - if (type in goog.events.onStringMap_) { - return goog.events.onStringMap_[type]; - } - return goog.events.onStringMap_[type] = goog.events.onString_ + type; +goog.vec.Mat4.setDiagonal = function(mat, vec) { + mat[0] = vec[0]; + mat[5] = vec[1]; + mat[10] = vec[2]; + mat[15] = vec[3]; + return mat; }; /** - * Fires an object's listeners of a particular type and phase + * Gets the diagonal values of the matrix into the given vector. * - * @param {Object} obj Object whose listeners to call. - * @param {string|!goog.events.EventId} type Event type. - * @param {boolean} capture Which event phase. - * @param {Object} eventObject Event object to be passed to listener. - * @return {boolean} True if all listeners returned true else false. + * @param {goog.vec.Mat4.AnyType} mat The matrix containing the values. + * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values. + * @param {number=} opt_diagonal Which diagonal to get. A value of 0 selects the + * main diagonal, a positive number selects a super diagonal and a negative + * number selects a sub diagonal. + * @return {goog.vec.Vec4.AnyType} return vec so that operations can be + * chained together. */ -goog.events.fireListeners = function(obj, type, capture, eventObject) { - if (goog.events.Listenable.isImplementedBy(obj)) { - return obj.fireListeners(type, capture, eventObject); +goog.vec.Mat4.getDiagonal = function(mat, vec, opt_diagonal) { + if (!opt_diagonal) { + // This is the most common case, so we avoid the for loop. + vec[0] = mat[0]; + vec[1] = mat[5]; + vec[2] = mat[10]; + vec[3] = mat[15]; + } else { + var offset = opt_diagonal > 0 ? 4 * opt_diagonal : -opt_diagonal; + for (var i = 0; i < 4 - Math.abs(opt_diagonal); i++) { + vec[i] = mat[offset + 5 * i]; + } } - - return goog.events.fireListeners_(obj, type, capture, eventObject); + return vec; }; /** - * Fires an object's listeners of a particular type and phase. - * @param {Object} obj Object whose listeners to call. - * @param {string|!goog.events.EventId} type Event type. - * @param {boolean} capture Which event phase. - * @param {Object} eventObject Event object to be passed to listener. - * @return {boolean} True if all listeners returned true else false. - * @private + * Sets the specified column with the supplied values. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to recieve the values. + * @param {number} column The column index to set the values on. + * @param {number} v0 The value for row 0. + * @param {number} v1 The value for row 1. + * @param {number} v2 The value for row 2. + * @param {number} v3 The value for row 3. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.fireListeners_ = function(obj, type, capture, eventObject) { - /** @type {boolean} */ - var retval = true; - - var listenerMap = goog.events.getListenerMap_( - /** @type {EventTarget} */ (obj)); - if (listenerMap) { - // TODO(chrishenry): Original code avoids array creation when there - // is no listener, so we do the same. If this optimization turns - // out to be not required, we can replace this with - // listenerMap.getListeners(type, capture) instead, which is simpler. - var listenerArray = listenerMap.listeners[type.toString()]; - if (listenerArray) { - listenerArray = listenerArray.concat(); - for (var i = 0; i < listenerArray.length; i++) { - var listener = listenerArray[i]; - // We might not have a listener if the listener was removed. - if (listener && listener.capture == capture && !listener.removed) { - var result = goog.events.fireListener(listener, eventObject); - retval = retval && (result !== false); - } - } - } - } - return retval; +goog.vec.Mat4.setColumnValues = function(mat, column, v0, v1, v2, v3) { + var i = column * 4; + mat[i] = v0; + mat[i + 1] = v1; + mat[i + 2] = v2; + mat[i + 3] = v3; + return mat; }; /** - * Fires a listener with a set of arguments + * Sets the specified column with the value from the supplied vector. * - * @param {goog.events.Listener} listener The listener object to call. - * @param {Object} eventObject The event object to pass to the listener. - * @return {boolean} Result of listener. + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {number} column The column index to set the values on. + * @param {goog.vec.Vec4.AnyType} vec The vector of elements for the column. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.fireListener = function(listener, eventObject) { - var listenerFn = listener.listener; - var listenerHandler = listener.handler || listener.src; - - if (listener.callOnce) { - goog.events.unlistenByKey(listener); - } - return listenerFn.call(listenerHandler, eventObject); +goog.vec.Mat4.setColumn = function(mat, column, vec) { + var i = column * 4; + mat[i] = vec[0]; + mat[i + 1] = vec[1]; + mat[i + 2] = vec[2]; + mat[i + 3] = vec[3]; + return mat; }; /** - * Gets the total number of listeners currently in the system. - * @return {number} Number of listeners. - * @deprecated This returns estimated count, now that Closure no longer - * stores a central listener registry. We still return an estimation - * to keep existing listener-related tests passing. In the near future, - * this function will be removed. + * Retrieves the specified column from the matrix into the given vector. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values. + * @param {number} column The column to get the values from. + * @param {goog.vec.Vec4.AnyType} vec The vector of elements to + * receive the column. + * @return {goog.vec.Vec4.AnyType} return vec so that operations can be + * chained together. */ -goog.events.getTotalListenerCount = function() { - return goog.events.listenerCountEstimate_; +goog.vec.Mat4.getColumn = function(mat, column, vec) { + var i = column * 4; + vec[0] = mat[i]; + vec[1] = mat[i + 1]; + vec[2] = mat[i + 2]; + vec[3] = mat[i + 3]; + return vec; }; /** - * Dispatches an event (or event like object) and calls all listeners - * listening for events of this type. The type of the event is decided by the - * type property on the event object. - * - * If any of the listeners returns false OR calls preventDefault then this - * function will return false. If one of the capture listeners calls - * stopPropagation, then the bubble listeners won't fire. + * Sets the columns of the matrix from the given vectors. * - * @param {goog.events.Listenable} src The event target. - * @param {goog.events.EventLike} e Event object. - * @return {boolean} If anyone called preventDefault on the event object (or - * if any of the handlers returns false) this will also return false. - * If there are no handlers, or if all handlers return true, this returns - * true. + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {goog.vec.Vec4.AnyType} vec0 The values for column 0. + * @param {goog.vec.Vec4.AnyType} vec1 The values for column 1. + * @param {goog.vec.Vec4.AnyType} vec2 The values for column 2. + * @param {goog.vec.Vec4.AnyType} vec3 The values for column 3. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.dispatchEvent = function(src, e) { - goog.asserts.assert( - goog.events.Listenable.isImplementedBy(src), - 'Can not use goog.events.dispatchEvent with ' + - 'non-goog.events.Listenable instance.'); - return src.dispatchEvent(e); +goog.vec.Mat4.setColumns = function(mat, vec0, vec1, vec2, vec3) { + goog.vec.Mat4.setColumn(mat, 0, vec0); + goog.vec.Mat4.setColumn(mat, 1, vec1); + goog.vec.Mat4.setColumn(mat, 2, vec2); + goog.vec.Mat4.setColumn(mat, 3, vec3); + return mat; }; /** - * Installs exception protection for the browser event entry point using the - * given error handler. + * Retrieves the column values from the given matrix into the given vectors. * - * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry point. + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the columns. + * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive column 0. + * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive column 1. + * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive column 2. + * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive column 3. */ -goog.events.protectBrowserEventEntryPoint = function(errorHandler) { - goog.events.handleBrowserEvent_ = errorHandler.protectEntryPoint( - goog.events.handleBrowserEvent_); +goog.vec.Mat4.getColumns = function(mat, vec0, vec1, vec2, vec3) { + goog.vec.Mat4.getColumn(mat, 0, vec0); + goog.vec.Mat4.getColumn(mat, 1, vec1); + goog.vec.Mat4.getColumn(mat, 2, vec2); + goog.vec.Mat4.getColumn(mat, 3, vec3); }; /** - * Handles an event and dispatches it to the correct listeners. This - * function is a proxy for the real listener the user specified. + * Sets the row values from the supplied values. * - * @param {goog.events.Listener} listener The listener object. - * @param {Event=} opt_evt Optional event object that gets passed in via the - * native event handlers. - * @return {boolean} Result of the event handler. - * @this {EventTarget} The object or Element that fired the event. - * @private + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {number} row The index of the row to receive the values. + * @param {number} v0 The value for column 0. + * @param {number} v1 The value for column 1. + * @param {number} v2 The value for column 2. + * @param {number} v3 The value for column 3. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.handleBrowserEvent_ = function(listener, opt_evt) { - if (listener.removed) { - return true; - } - - // Synthesize event propagation if the browser does not support W3C - // event model. - if (!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) { - var ieEvent = opt_evt || - /** @type {Event} */ (goog.getObjectByName('window.event')); - var evt = new goog.events.BrowserEvent(ieEvent, this); - /** @type {boolean} */ - var retval = true; - - if (goog.events.CAPTURE_SIMULATION_MODE == - goog.events.CaptureSimulationMode.ON) { - // If we have not marked this event yet, we should perform capture - // simulation. - if (!goog.events.isMarkedIeEvent_(ieEvent)) { - goog.events.markIeEvent_(ieEvent); - - var ancestors = []; - for (var parent = evt.currentTarget; parent; - parent = parent.parentNode) { - ancestors.push(parent); - } - - // Fire capture listeners. - var type = listener.type; - for (var i = ancestors.length - 1; !evt.propagationStopped_ && i >= 0; - i--) { - evt.currentTarget = ancestors[i]; - var result = goog.events.fireListeners_(ancestors[i], type, true, evt); - retval = retval && result; - } - - // Fire bubble listeners. - // - // We can technically rely on IE to perform bubble event - // propagation. However, it turns out that IE fires events in - // opposite order of attachEvent registration, which broke - // some code and tests that rely on the order. (While W3C DOM - // Level 2 Events TR leaves the event ordering unspecified, - // modern browsers and W3C DOM Level 3 Events Working Draft - // actually specify the order as the registration order.) - for (var i = 0; !evt.propagationStopped_ && i < ancestors.length; i++) { - evt.currentTarget = ancestors[i]; - var result = goog.events.fireListeners_(ancestors[i], type, false, evt); - retval = retval && result; - } - } - } else { - retval = goog.events.fireListener(listener, evt); - } - return retval; - } - - // Otherwise, simply fire the listener. - return goog.events.fireListener( - listener, new goog.events.BrowserEvent(opt_evt, this)); +goog.vec.Mat4.setRowValues = function(mat, row, v0, v1, v2, v3) { + mat[row] = v0; + mat[row + 4] = v1; + mat[row + 8] = v2; + mat[row + 12] = v3; + return mat; }; /** - * This is used to mark the IE event object so we do not do the Closure pass - * twice for a bubbling event. - * @param {Event} e The IE browser event. - * @private + * Sets the row values from the supplied vector. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the row values. + * @param {number} row The index of the row. + * @param {goog.vec.Vec4.AnyType} vec The vector containing the values. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.markIeEvent_ = function(e) { - // Only the keyCode and the returnValue can be changed. We use keyCode for - // non keyboard events. - // event.returnValue is a bit more tricky. It is undefined by default. A - // boolean false prevents the default action. In a window.onbeforeunload and - // the returnValue is non undefined it will be alerted. However, we will only - // modify the returnValue for keyboard events. We can get a problem if non - // closure events sets the keyCode or the returnValue - - var useReturnValue = false; - - if (e.keyCode == 0) { - // We cannot change the keyCode in case that srcElement is input[type=file]. - // We could test that that is the case but that would allocate 3 objects. - // If we use try/catch we will only allocate extra objects in the case of a - // failure. - /** @preserveTry */ - try { - e.keyCode = -1; - return; - } catch (ex) { - useReturnValue = true; - } - } - - if (useReturnValue || - /** @type {boolean|undefined} */ (e.returnValue) == undefined) { - e.returnValue = true; - } +goog.vec.Mat4.setRow = function(mat, row, vec) { + mat[row] = vec[0]; + mat[row + 4] = vec[1]; + mat[row + 8] = vec[2]; + mat[row + 12] = vec[3]; + return mat; }; /** - * This is used to check if an IE event has already been handled by the Closure - * system so we do not do the Closure pass twice for a bubbling event. - * @param {Event} e The IE browser event. - * @return {boolean} True if the event object has been marked. - * @private + * Retrieves the row values into the given vector. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values. + * @param {number} row The index of the row supplying the values. + * @param {goog.vec.Vec4.AnyType} vec The vector to receive the row. + * @return {goog.vec.Vec4.AnyType} return vec so that operations can be + * chained together. */ -goog.events.isMarkedIeEvent_ = function(e) { - return e.keyCode < 0 || e.returnValue != undefined; +goog.vec.Mat4.getRow = function(mat, row, vec) { + vec[0] = mat[row]; + vec[1] = mat[row + 4]; + vec[2] = mat[row + 8]; + vec[3] = mat[row + 12]; + return vec; }; /** - * Counter to create unique event ids. - * @private {number} + * Sets the rows of the matrix from the supplied vectors. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. + * @param {goog.vec.Vec4.AnyType} vec0 The values for row 0. + * @param {goog.vec.Vec4.AnyType} vec1 The values for row 1. + * @param {goog.vec.Vec4.AnyType} vec2 The values for row 2. + * @param {goog.vec.Vec4.AnyType} vec3 The values for row 3. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained together. */ -goog.events.uniqueIdCounter_ = 0; +goog.vec.Mat4.setRows = function(mat, vec0, vec1, vec2, vec3) { + goog.vec.Mat4.setRow(mat, 0, vec0); + goog.vec.Mat4.setRow(mat, 1, vec1); + goog.vec.Mat4.setRow(mat, 2, vec2); + goog.vec.Mat4.setRow(mat, 3, vec3); + return mat; +}; /** - * Creates a unique event id. + * Retrieves the rows of the matrix into the supplied vectors. * - * @param {string} identifier The identifier. - * @return {string} A unique identifier. - * @idGenerator + * @param {goog.vec.Mat4.AnyType} mat The matrix to supply the values. + * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive row 0. + * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive row 1. + * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive row 2. + * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive row 3. */ -goog.events.getUniqueId = function(identifier) { - return identifier + '_' + goog.events.uniqueIdCounter_++; +goog.vec.Mat4.getRows = function(mat, vec0, vec1, vec2, vec3) { + goog.vec.Mat4.getRow(mat, 0, vec0); + goog.vec.Mat4.getRow(mat, 1, vec1); + goog.vec.Mat4.getRow(mat, 2, vec2); + goog.vec.Mat4.getRow(mat, 3, vec3); }; /** - * @param {EventTarget} src The source object. - * @return {goog.events.ListenerMap} A listener map for the given - * source object, or null if none exists. - * @private + * Makes the given 4x4 matrix the zero matrix. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @return {!goog.vec.Mat4.AnyType} return mat so operations can be chained. */ -goog.events.getListenerMap_ = function(src) { - var listenerMap = src[goog.events.LISTENER_MAP_PROP_]; - // IE serializes the property as well (e.g. when serializing outer - // HTML). So we must check that the value is of the correct type. - return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null; +goog.vec.Mat4.makeZero = function(mat) { + mat[0] = 0; + mat[1] = 0; + mat[2] = 0; + mat[3] = 0; + mat[4] = 0; + mat[5] = 0; + mat[6] = 0; + mat[7] = 0; + mat[8] = 0; + mat[9] = 0; + mat[10] = 0; + mat[11] = 0; + mat[12] = 0; + mat[13] = 0; + mat[14] = 0; + mat[15] = 0; + return mat; }; /** - * Expando property for listener function wrapper for Object with - * handleEvent. - * @private @const {string} + * Makes the given 4x4 matrix the identity matrix. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @return {goog.vec.Mat4.AnyType} return mat so operations can be chained. */ -goog.events.LISTENER_WRAPPER_PROP_ = '__closure_events_fn_' + - ((Math.random() * 1e9) >>> 0); +goog.vec.Mat4.makeIdentity = function(mat) { + mat[0] = 1; + mat[1] = 0; + mat[2] = 0; + mat[3] = 0; + mat[4] = 0; + mat[5] = 1; + mat[6] = 0; + mat[7] = 0; + mat[8] = 0; + mat[9] = 0; + mat[10] = 1; + mat[11] = 0; + mat[12] = 0; + mat[13] = 0; + mat[14] = 0; + mat[15] = 1; + return mat; +}; /** - * @param {Object|Function} listener The listener function or an - * object that contains handleEvent method. - * @return {!Function} Either the original function or a function that - * calls obj.handleEvent. If the same listener is passed to this - * function more than once, the same function is guaranteed to be - * returned. + * Performs a per-component addition of the matrix mat0 and mat1, storing + * the result into resultMat. + * + * @param {goog.vec.Mat4.AnyType} mat0 The first addend. + * @param {goog.vec.Mat4.AnyType} mat1 The second addend. + * @param {goog.vec.Mat4.AnyType} resultMat The matrix to + * receive the results (may be either mat0 or mat1). + * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be + * chained together. */ -goog.events.wrapListener = function(listener) { - goog.asserts.assert(listener, 'Listener can not be null.'); - - if (goog.isFunction(listener)) { - return listener; - } - - goog.asserts.assert( - listener.handleEvent, 'An object listener must have handleEvent method.'); - if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) { - listener[goog.events.LISTENER_WRAPPER_PROP_] = - function(e) { return listener.handleEvent(e); }; - } - return listener[goog.events.LISTENER_WRAPPER_PROP_]; +goog.vec.Mat4.addMat = function(mat0, mat1, resultMat) { + resultMat[0] = mat0[0] + mat1[0]; + resultMat[1] = mat0[1] + mat1[1]; + resultMat[2] = mat0[2] + mat1[2]; + resultMat[3] = mat0[3] + mat1[3]; + resultMat[4] = mat0[4] + mat1[4]; + resultMat[5] = mat0[5] + mat1[5]; + resultMat[6] = mat0[6] + mat1[6]; + resultMat[7] = mat0[7] + mat1[7]; + resultMat[8] = mat0[8] + mat1[8]; + resultMat[9] = mat0[9] + mat1[9]; + resultMat[10] = mat0[10] + mat1[10]; + resultMat[11] = mat0[11] + mat1[11]; + resultMat[12] = mat0[12] + mat1[12]; + resultMat[13] = mat0[13] + mat1[13]; + resultMat[14] = mat0[14] + mat1[14]; + resultMat[15] = mat0[15] + mat1[15]; + return resultMat; }; -// Register the browser event handler as an entry point, so that -// it can be monitored for exception handling, etc. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.events.handleBrowserEvent_ = transformer( - goog.events.handleBrowserEvent_); - }); - -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - /** - * @fileoverview A disposable implementation of a custom - * listenable/event target. See also: documentation for - * {@code goog.events.Listenable}. + * Performs a per-component subtraction of the matrix mat0 and mat1, + * storing the result into resultMat. * - * @author arv@google.com (Erik Arvidsson) [Original implementation] - * @see ../demos/eventtarget.html - * @see goog.events.Listenable + * @param {goog.vec.Mat4.AnyType} mat0 The minuend. + * @param {goog.vec.Mat4.AnyType} mat1 The subtrahend. + * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive + * the results (may be either mat0 or mat1). + * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be + * chained together. */ - -goog.provide('goog.events.EventTarget'); - -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.Listenable'); -goog.require('goog.events.ListenerMap'); -goog.require('goog.object'); - +goog.vec.Mat4.subMat = function(mat0, mat1, resultMat) { + resultMat[0] = mat0[0] - mat1[0]; + resultMat[1] = mat0[1] - mat1[1]; + resultMat[2] = mat0[2] - mat1[2]; + resultMat[3] = mat0[3] - mat1[3]; + resultMat[4] = mat0[4] - mat1[4]; + resultMat[5] = mat0[5] - mat1[5]; + resultMat[6] = mat0[6] - mat1[6]; + resultMat[7] = mat0[7] - mat1[7]; + resultMat[8] = mat0[8] - mat1[8]; + resultMat[9] = mat0[9] - mat1[9]; + resultMat[10] = mat0[10] - mat1[10]; + resultMat[11] = mat0[11] - mat1[11]; + resultMat[12] = mat0[12] - mat1[12]; + resultMat[13] = mat0[13] - mat1[13]; + resultMat[14] = mat0[14] - mat1[14]; + resultMat[15] = mat0[15] - mat1[15]; + return resultMat; +}; /** - * An implementation of {@code goog.events.Listenable} with full W3C - * EventTarget-like support (capture/bubble mechanism, stopping event - * propagation, preventing default actions). - * - * You may subclass this class to turn your class into a Listenable. - * - * Unless propagation is stopped, an event dispatched by an - * EventTarget will bubble to the parent returned by - * {@code getParentEventTarget}. To set the parent, call - * {@code setParentEventTarget}. Subclasses that don't support - * changing the parent can override the setter to throw an error. - * - * Example usage: - * <pre> - * var source = new goog.events.EventTarget(); - * function handleEvent(e) { - * alert('Type: ' + e.type + '; Target: ' + e.target); - * } - * source.listen('foo', handleEvent); - * // Or: goog.events.listen(source, 'foo', handleEvent); - * ... - * source.dispatchEvent('foo'); // will call handleEvent - * ... - * source.unlisten('foo', handleEvent); - * // Or: goog.events.unlisten(source, 'foo', handleEvent); - * </pre> + * Multiplies matrix mat with the given scalar, storing the result + * into resultMat. * - * @constructor - * @extends {goog.Disposable} - * @implements {goog.events.Listenable} + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} scalar The scalar value to multiply to each element of mat. + * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive + * the results (may be mat). + * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be + * chained together. */ -goog.events.EventTarget = function() { - goog.Disposable.call(this); - - /** - * Maps of event type to an array of listeners. - * @private {!goog.events.ListenerMap} - */ - this.eventTargetListeners_ = new goog.events.ListenerMap(this); - - /** - * The object to use for event.target. Useful when mixing in an - * EventTarget to another object. - * @private {!Object} - */ - this.actualEventTarget_ = this; - - /** - * Parent event target, used during event bubbling. - * - * TODO(chrishenry): Change this to goog.events.Listenable. This - * currently breaks people who expect getParentEventTarget to return - * goog.events.EventTarget. - * - * @private {goog.events.EventTarget} - */ - this.parentEventTarget_ = null; +goog.vec.Mat4.multScalar = function(mat, scalar, resultMat) { + resultMat[0] = mat[0] * scalar; + resultMat[1] = mat[1] * scalar; + resultMat[2] = mat[2] * scalar; + resultMat[3] = mat[3] * scalar; + resultMat[4] = mat[4] * scalar; + resultMat[5] = mat[5] * scalar; + resultMat[6] = mat[6] * scalar; + resultMat[7] = mat[7] * scalar; + resultMat[8] = mat[8] * scalar; + resultMat[9] = mat[9] * scalar; + resultMat[10] = mat[10] * scalar; + resultMat[11] = mat[11] * scalar; + resultMat[12] = mat[12] * scalar; + resultMat[13] = mat[13] * scalar; + resultMat[14] = mat[14] * scalar; + resultMat[15] = mat[15] * scalar; + return resultMat; }; -goog.inherits(goog.events.EventTarget, goog.Disposable); -goog.events.Listenable.addImplementation(goog.events.EventTarget); /** - * An artificial cap on the number of ancestors you can have. This is mainly - * for loop detection. - * @const {number} - * @private - */ -goog.events.EventTarget.MAX_ANCESTORS_ = 1000; - - -/** - * Returns the parent of this event target to use for bubbling. + * Multiplies the two matrices mat0 and mat1 using matrix multiplication, + * storing the result into resultMat. * - * @return {goog.events.EventTarget} The parent EventTarget or null if - * there is no parent. - * @override + * @param {goog.vec.Mat4.AnyType} mat0 The first (left hand) matrix. + * @param {goog.vec.Mat4.AnyType} mat1 The second (right hand) matrix. + * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive + * the results (may be either mat0 or mat1). + * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be + * chained together. */ -goog.events.EventTarget.prototype.getParentEventTarget = function() { - return this.parentEventTarget_; -}; +goog.vec.Mat4.multMat = function(mat0, mat1, resultMat) { + var a00 = mat0[0], a10 = mat0[1], a20 = mat0[2], a30 = mat0[3]; + var a01 = mat0[4], a11 = mat0[5], a21 = mat0[6], a31 = mat0[7]; + var a02 = mat0[8], a12 = mat0[9], a22 = mat0[10], a32 = mat0[11]; + var a03 = mat0[12], a13 = mat0[13], a23 = mat0[14], a33 = mat0[15]; + + var b00 = mat1[0], b10 = mat1[1], b20 = mat1[2], b30 = mat1[3]; + var b01 = mat1[4], b11 = mat1[5], b21 = mat1[6], b31 = mat1[7]; + var b02 = mat1[8], b12 = mat1[9], b22 = mat1[10], b32 = mat1[11]; + var b03 = mat1[12], b13 = mat1[13], b23 = mat1[14], b33 = mat1[15]; + resultMat[0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30; + resultMat[1] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30; + resultMat[2] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30; + resultMat[3] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30; -/** - * Sets the parent of this event target to use for capture/bubble - * mechanism. - * @param {goog.events.EventTarget} parent Parent listenable (null if none). - */ -goog.events.EventTarget.prototype.setParentEventTarget = function(parent) { - this.parentEventTarget_ = parent; -}; + resultMat[4] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31; + resultMat[5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31; + resultMat[6] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31; + resultMat[7] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31; + resultMat[8] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32; + resultMat[9] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32; + resultMat[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32; + resultMat[11] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32; -/** - * Adds an event listener to the event target. The same handler can only be - * added once per the type. Even if you add the same handler multiple times - * using the same type then it will only be called once when the event is - * dispatched. - * - * @param {string} type The type of the event to listen for. - * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function - * to handle the event. The handler can also be an object that implements - * the handleEvent method which takes the event object as argument. - * @param {boolean=} opt_capture In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase - * of the event. - * @param {Object=} opt_handlerScope Object in whose scope to call - * the listener. - * @deprecated Use {@code #listen} instead, when possible. Otherwise, use - * {@code goog.events.listen} if you are passing Object - * (instead of Function) as handler. - */ -goog.events.EventTarget.prototype.addEventListener = function( - type, handler, opt_capture, opt_handlerScope) { - goog.events.listen(this, type, handler, opt_capture, opt_handlerScope); + resultMat[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33; + resultMat[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33; + resultMat[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33; + resultMat[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33; + return resultMat; }; /** - * Removes an event listener from the event target. The handler must be the - * same object as the one added. If the handler has not been added then - * nothing is done. + * Transposes the given matrix mat storing the result into resultMat. * - * @param {string} type The type of the event to listen for. - * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function - * to handle the event. The handler can also be an object that implements - * the handleEvent method which takes the event object as argument. - * @param {boolean=} opt_capture In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase - * of the event. - * @param {Object=} opt_handlerScope Object in whose scope to call - * the listener. - * @deprecated Use {@code #unlisten} instead, when possible. Otherwise, use - * {@code goog.events.unlisten} if you are passing Object - * (instead of Function) as handler. + * @param {goog.vec.Mat4.AnyType} mat The matrix to transpose. + * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive + * the results (may be mat). + * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be + * chained together. */ -goog.events.EventTarget.prototype.removeEventListener = function( - type, handler, opt_capture, opt_handlerScope) { - goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope); -}; +goog.vec.Mat4.transpose = function(mat, resultMat) { + if (resultMat == mat) { + var a10 = mat[1], a20 = mat[2], a30 = mat[3]; + var a21 = mat[6], a31 = mat[7]; + var a32 = mat[11]; + resultMat[1] = mat[4]; + resultMat[2] = mat[8]; + resultMat[3] = mat[12]; + resultMat[4] = a10; + resultMat[6] = mat[9]; + resultMat[7] = mat[13]; + resultMat[8] = a20; + resultMat[9] = a21; + resultMat[11] = mat[14]; + resultMat[12] = a30; + resultMat[13] = a31; + resultMat[14] = a32; + } else { + resultMat[0] = mat[0]; + resultMat[1] = mat[4]; + resultMat[2] = mat[8]; + resultMat[3] = mat[12]; + resultMat[4] = mat[1]; + resultMat[5] = mat[5]; + resultMat[6] = mat[9]; + resultMat[7] = mat[13]; -/** @override */ -goog.events.EventTarget.prototype.dispatchEvent = function(e) { - this.assertInitialized_(); + resultMat[8] = mat[2]; + resultMat[9] = mat[6]; + resultMat[10] = mat[10]; + resultMat[11] = mat[14]; - var ancestorsTree, ancestor = this.getParentEventTarget(); - if (ancestor) { - ancestorsTree = []; - var ancestorCount = 1; - for (; ancestor; ancestor = ancestor.getParentEventTarget()) { - ancestorsTree.push(ancestor); - goog.asserts.assert( - (++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_), - 'infinite loop'); - } + resultMat[12] = mat[3]; + resultMat[13] = mat[7]; + resultMat[14] = mat[11]; + resultMat[15] = mat[15]; } - - return goog.events.EventTarget.dispatchEventInternal_( - this.actualEventTarget_, e, ancestorsTree); + return resultMat; }; /** - * Removes listeners from this object. Classes that extend EventTarget may - * need to override this method in order to remove references to DOM Elements - * and additional listeners. - * @override + * Computes the determinant of the matrix. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to compute the matrix for. + * @return {number} The determinant of the matrix. */ -goog.events.EventTarget.prototype.disposeInternal = function() { - goog.events.EventTarget.superClass_.disposeInternal.call(this); - - this.removeAllListeners(); - this.parentEventTarget_ = null; -}; - - -/** @override */ -goog.events.EventTarget.prototype.listen = function( - type, listener, opt_useCapture, opt_listenerScope) { - this.assertInitialized_(); - return this.eventTargetListeners_.add( - String(type), listener, false /* callOnce */, opt_useCapture, - opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.listenOnce = function( - type, listener, opt_useCapture, opt_listenerScope) { - return this.eventTargetListeners_.add( - String(type), listener, true /* callOnce */, opt_useCapture, - opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.unlisten = function( - type, listener, opt_useCapture, opt_listenerScope) { - return this.eventTargetListeners_.remove( - String(type), listener, opt_useCapture, opt_listenerScope); -}; - - -/** @override */ -goog.events.EventTarget.prototype.unlistenByKey = function(key) { - return this.eventTargetListeners_.removeByKey(key); -}; +goog.vec.Mat4.determinant = function(mat) { + var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; + var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; + var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; + var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; + var a0 = m00 * m11 - m10 * m01; + var a1 = m00 * m21 - m20 * m01; + var a2 = m00 * m31 - m30 * m01; + var a3 = m10 * m21 - m20 * m11; + var a4 = m10 * m31 - m30 * m11; + var a5 = m20 * m31 - m30 * m21; + var b0 = m02 * m13 - m12 * m03; + var b1 = m02 * m23 - m22 * m03; + var b2 = m02 * m33 - m32 * m03; + var b3 = m12 * m23 - m22 * m13; + var b4 = m12 * m33 - m32 * m13; + var b5 = m22 * m33 - m32 * m23; -/** @override */ -goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) { - // TODO(chrishenry): Previously, removeAllListeners can be called on - // uninitialized EventTarget, so we preserve that behavior. We - // should remove this when usages that rely on that fact are purged. - if (!this.eventTargetListeners_) { - return 0; - } - return this.eventTargetListeners_.removeAll(opt_type); + return a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; }; -/** @override */ -goog.events.EventTarget.prototype.fireListeners = function( - type, capture, eventObject) { - // TODO(chrishenry): Original code avoids array creation when there - // is no listener, so we do the same. If this optimization turns - // out to be not required, we can replace this with - // getListeners(type, capture) instead, which is simpler. - var listenerArray = this.eventTargetListeners_.listeners[String(type)]; - if (!listenerArray) { - return true; - } - listenerArray = listenerArray.concat(); +/** + * Computes the inverse of mat storing the result into resultMat. If the + * inverse is defined, this function returns true, false otherwise. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix to invert. + * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive + * the result (may be mat). + * @return {boolean} True if the inverse is defined. If false is returned, + * resultMat is not modified. + */ +goog.vec.Mat4.invert = function(mat, resultMat) { + var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; + var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; + var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; + var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; - var rv = true; - for (var i = 0; i < listenerArray.length; ++i) { - var listener = listenerArray[i]; - // We might not have a listener if the listener was removed. - if (listener && !listener.removed && listener.capture == capture) { - var listenerFn = listener.listener; - var listenerHandler = listener.handler || listener.src; + var a0 = m00 * m11 - m10 * m01; + var a1 = m00 * m21 - m20 * m01; + var a2 = m00 * m31 - m30 * m01; + var a3 = m10 * m21 - m20 * m11; + var a4 = m10 * m31 - m30 * m11; + var a5 = m20 * m31 - m30 * m21; + var b0 = m02 * m13 - m12 * m03; + var b1 = m02 * m23 - m22 * m03; + var b2 = m02 * m33 - m32 * m03; + var b3 = m12 * m23 - m22 * m13; + var b4 = m12 * m33 - m32 * m13; + var b5 = m22 * m33 - m32 * m23; - if (listener.callOnce) { - this.unlistenByKey(listener); - } - rv = listenerFn.call(listenerHandler, eventObject) !== false && rv; - } + var det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; + if (det == 0) { + return false; } - return rv && eventObject.returnValue_ != false; + var idet = 1.0 / det; + resultMat[0] = (m11 * b5 - m21 * b4 + m31 * b3) * idet; + resultMat[1] = (-m10 * b5 + m20 * b4 - m30 * b3) * idet; + resultMat[2] = (m13 * a5 - m23 * a4 + m33 * a3) * idet; + resultMat[3] = (-m12 * a5 + m22 * a4 - m32 * a3) * idet; + resultMat[4] = (-m01 * b5 + m21 * b2 - m31 * b1) * idet; + resultMat[5] = (m00 * b5 - m20 * b2 + m30 * b1) * idet; + resultMat[6] = (-m03 * a5 + m23 * a2 - m33 * a1) * idet; + resultMat[7] = (m02 * a5 - m22 * a2 + m32 * a1) * idet; + resultMat[8] = (m01 * b4 - m11 * b2 + m31 * b0) * idet; + resultMat[9] = (-m00 * b4 + m10 * b2 - m30 * b0) * idet; + resultMat[10] = (m03 * a4 - m13 * a2 + m33 * a0) * idet; + resultMat[11] = (-m02 * a4 + m12 * a2 - m32 * a0) * idet; + resultMat[12] = (-m01 * b3 + m11 * b1 - m21 * b0) * idet; + resultMat[13] = (m00 * b3 - m10 * b1 + m20 * b0) * idet; + resultMat[14] = (-m03 * a3 + m13 * a1 - m23 * a0) * idet; + resultMat[15] = (m02 * a3 - m12 * a1 + m22 * a0) * idet; + return true; }; -/** @override */ -goog.events.EventTarget.prototype.getListeners = function(type, capture) { - return this.eventTargetListeners_.getListeners(String(type), capture); +/** + * Returns true if the components of mat0 are equal to the components of mat1. + * + * @param {goog.vec.Mat4.AnyType} mat0 The first matrix. + * @param {goog.vec.Mat4.AnyType} mat1 The second matrix. + * @return {boolean} True if the the two matrices are equivalent. + */ +goog.vec.Mat4.equals = function(mat0, mat1) { + return mat0.length == mat1.length && + mat0[0] == mat1[0] && + mat0[1] == mat1[1] && + mat0[2] == mat1[2] && + mat0[3] == mat1[3] && + mat0[4] == mat1[4] && + mat0[5] == mat1[5] && + mat0[6] == mat1[6] && + mat0[7] == mat1[7] && + mat0[8] == mat1[8] && + mat0[9] == mat1[9] && + mat0[10] == mat1[10] && + mat0[11] == mat1[11] && + mat0[12] == mat1[12] && + mat0[13] == mat1[13] && + mat0[14] == mat1[14] && + mat0[15] == mat1[15]; }; -/** @override */ -goog.events.EventTarget.prototype.getListener = function( - type, listener, capture, opt_listenerScope) { - return this.eventTargetListeners_.getListener( - String(type), listener, capture, opt_listenerScope); +/** + * Transforms the given vector with the given matrix storing the resulting, + * transformed vector into resultVec. The input vector is multiplied against the + * upper 3x4 matrix omitting the projective component. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. + * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. + * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to + * receive the results (may be vec). + * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be + * chained together. + */ +goog.vec.Mat4.multVec3 = function(mat, vec, resultVec) { + var x = vec[0], y = vec[1], z = vec[2]; + resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + mat[12]; + resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + mat[13]; + resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + mat[14]; + return resultVec; }; -/** @override */ -goog.events.EventTarget.prototype.hasListener = function( - opt_type, opt_capture) { - var id = goog.isDef(opt_type) ? String(opt_type) : undefined; - return this.eventTargetListeners_.hasListener(id, opt_capture); +/** + * Transforms the given vector with the given matrix storing the resulting, + * transformed vector into resultVec. The input vector is multiplied against the + * upper 3x3 matrix omitting the projective component and translation + * components. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. + * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. + * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to + * receive the results (may be vec). + * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be + * chained together. + */ +goog.vec.Mat4.multVec3NoTranslate = function(mat, vec, resultVec) { + var x = vec[0], y = vec[1], z = vec[2]; + resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8]; + resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9]; + resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10]; + return resultVec; }; /** - * Sets the target to be used for {@code event.target} when firing - * event. Mainly used for testing. For example, see - * {@code goog.testing.events.mixinListenable}. - * @param {!Object} target The target. + * Transforms the given vector with the given matrix storing the resulting, + * transformed vector into resultVec. The input vector is multiplied against the + * full 4x4 matrix with the homogeneous divide applied to reduce the 4 element + * vector to a 3 element vector. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. + * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. + * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector + * to receive the results (may be vec). + * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be + * chained together. */ -goog.events.EventTarget.prototype.setTargetForTesting = function(target) { - this.actualEventTarget_ = target; +goog.vec.Mat4.multVec3Projective = function(mat, vec, resultVec) { + var x = vec[0], y = vec[1], z = vec[2]; + var invw = 1 / (x * mat[3] + y * mat[7] + z * mat[11] + mat[15]); + resultVec[0] = (x * mat[0] + y * mat[4] + z * mat[8] + mat[12]) * invw; + resultVec[1] = (x * mat[1] + y * mat[5] + z * mat[9] + mat[13]) * invw; + resultVec[2] = (x * mat[2] + y * mat[6] + z * mat[10] + mat[14]) * invw; + return resultVec; }; /** - * Asserts that the event target instance is initialized properly. - * @private + * Transforms the given vector with the given matrix storing the resulting, + * transformed vector into resultVec. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. + * @param {goog.vec.Vec4.AnyType} vec The vector to transform. + * @param {goog.vec.Vec4.AnyType} resultVec The vector to + * receive the results (may be vec). + * @return {goog.vec.Vec4.AnyType} return resultVec so that operations can be + * chained together. */ -goog.events.EventTarget.prototype.assertInitialized_ = function() { - goog.asserts.assert( - this.eventTargetListeners_, - 'Event target is not initialized. Did you call the superclass ' + - '(goog.events.EventTarget) constructor?'); +goog.vec.Mat4.multVec4 = function(mat, vec, resultVec) { + var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; + resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + w * mat[12]; + resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + w * mat[13]; + resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + w * mat[14]; + resultVec[3] = x * mat[3] + y * mat[7] + z * mat[11] + w * mat[15]; + return resultVec; }; /** - * Dispatches the given event on the ancestorsTree. + * Makes the given 4x4 matrix a translation matrix with x, y and z + * translation factors. * - * @param {!Object} target The target to dispatch on. - * @param {goog.events.Event|Object|string} e The event object. - * @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors - * tree of the target, in reverse order from the closest ancestor - * to the root event target. May be null if the target has no ancestor. - * @return {boolean} If anyone called preventDefault on the event object (or - * if any of the listeners returns false) this will also return false. - * @private + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} x The translation along the x axis. + * @param {number} y The translation along the y axis. + * @param {number} z The translation along the z axis. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -goog.events.EventTarget.dispatchEventInternal_ = function( - target, e, opt_ancestorsTree) { - var type = e.type || /** @type {string} */ (e); - - // If accepting a string or object, create a custom event object so that - // preventDefault and stopPropagation work with the event. - if (goog.isString(e)) { - e = new goog.events.Event(e, target); - } else if (!(e instanceof goog.events.Event)) { - var oldEvent = e; - e = new goog.events.Event(type, target); - goog.object.extend(e, oldEvent); - } else { - e.target = e.target || target; - } - - var rv = true, currentTarget; - - // Executes all capture listeners on the ancestors, if any. - if (opt_ancestorsTree) { - for (var i = opt_ancestorsTree.length - 1; !e.propagationStopped_ && i >= 0; - i--) { - currentTarget = e.currentTarget = opt_ancestorsTree[i]; - rv = currentTarget.fireListeners(type, true, e) && rv; - } - } - - // Executes capture and bubble listeners on the target. - if (!e.propagationStopped_) { - currentTarget = e.currentTarget = target; - rv = currentTarget.fireListeners(type, true, e) && rv; - if (!e.propagationStopped_) { - rv = currentTarget.fireListeners(type, false, e) && rv; - } - } - - // Executes all bubble listeners on the ancestors, if any. - if (opt_ancestorsTree) { - for (i = 0; !e.propagationStopped_ && i < opt_ancestorsTree.length; i++) { - currentTarget = e.currentTarget = opt_ancestorsTree[i]; - rv = currentTarget.fireListeners(type, false, e) && rv; - } - } - - return rv; +goog.vec.Mat4.makeTranslate = function(mat, x, y, z) { + goog.vec.Mat4.makeIdentity(mat); + return goog.vec.Mat4.setColumnValues(mat, 3, x, y, z, 1); }; -goog.provide('ol.Observable'); - -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); +/** + * Makes the given 4x4 matrix as a scale matrix with x, y and z scale factors. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} x The scale along the x axis. + * @param {number} y The scale along the y axis. + * @param {number} z The scale along the z axis. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. + */ +goog.vec.Mat4.makeScale = function(mat, x, y, z) { + goog.vec.Mat4.makeIdentity(mat); + return goog.vec.Mat4.setDiagonalValues(mat, x, y, z, 1); +}; /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * An event target providing convenient methods for listener registration - * and unregistration. A generic `change` event is always available through - * {@link ol.Observable#changed}. + * Makes the given 4x4 matrix a rotation matrix with the given rotation + * angle about the axis defined by the vector (ax, ay, az). * - * @constructor - * @extends {goog.events.EventTarget} - * @fires change - * @struct - * @api stable + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The rotation angle in radians. + * @param {number} ax The x component of the rotation axis. + * @param {number} ay The y component of the rotation axis. + * @param {number} az The z component of the rotation axis. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable = function() { +goog.vec.Mat4.makeRotate = function(mat, angle, ax, ay, az) { + var c = Math.cos(angle); + var d = 1 - c; + var s = Math.sin(angle); - goog.base(this); + return goog.vec.Mat4.setFromValues(mat, + ax * ax * d + c, + ax * ay * d + az * s, + ax * az * d - ay * s, + 0, - /** - * @private - * @type {number} - */ - this.revision_ = 0; + ax * ay * d - az * s, + ay * ay * d + c, + ay * az * d + ax * s, + 0, + + ax * az * d + ay * s, + ay * az * d - ax * s, + az * az * d + c, + 0, + 0, 0, 0, 1); }; -goog.inherits(ol.Observable, goog.events.EventTarget); /** - * Removes an event listener using the key returned by `on()` or `once()`. - * @param {goog.events.Key} key The key returned by `on()` or `once()`. - * @api stable + * Makes the given 4x4 matrix a rotation matrix with the given rotation + * angle about the X axis. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The rotation angle in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.unByKey = function(key) { - goog.events.unlistenByKey(key); +goog.vec.Mat4.makeRotateX = function(mat, angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + return goog.vec.Mat4.setFromValues( + mat, 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1); }; /** - * Increases the revision counter and dispatches a 'change' event. - * @api + * Makes the given 4x4 matrix a rotation matrix with the given rotation + * angle about the Y axis. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The rotation angle in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.prototype.changed = function() { - ++this.revision_; - this.dispatchEvent(goog.events.EventType.CHANGE); +goog.vec.Mat4.makeRotateY = function(mat, angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + return goog.vec.Mat4.setFromValues( + mat, c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1); }; /** - * Triggered when the revision counter is increased. - * @event change - * @api + * Makes the given 4x4 matrix a rotation matrix with the given rotation + * angle about the Z axis. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The rotation angle in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ +goog.vec.Mat4.makeRotateZ = function(mat, angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + return goog.vec.Mat4.setFromValues( + mat, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); +}; /** - * Dispatches an event and calls all listeners listening for events - * of this type. The event parameter can either be a string or an - * Object with a `type` property. + * Makes the given 4x4 matrix a perspective projection matrix. * - * @param {goog.events.EventLike} event Event object. - * @function - * @api + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} left The coordinate of the left clipping plane. + * @param {number} right The coordinate of the right clipping plane. + * @param {number} bottom The coordinate of the bottom clipping plane. + * @param {number} top The coordinate of the top clipping plane. + * @param {number} near The distance to the near clipping plane. + * @param {number} far The distance to the far clipping plane. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.prototype.dispatchEvent; +goog.vec.Mat4.makeFrustum = function(mat, left, right, bottom, top, near, far) { + var x = (2 * near) / (right - left); + var y = (2 * near) / (top - bottom); + var a = (right + left) / (right - left); + var b = (top + bottom) / (top - bottom); + var c = -(far + near) / (far - near); + var d = -(2 * far * near) / (far - near); + + return goog.vec.Mat4.setFromValues(mat, + x, 0, 0, 0, + 0, y, 0, 0, + a, b, c, -1, + 0, 0, d, 0 + ); +}; /** - * Get the version number for this object. Each time the object is modified, - * its version number will be incremented. - * @return {number} Revision. - * @api + * Makse the given 4x4 matrix perspective projection matrix given a + * field of view and aspect ratio. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} fovy The field of view along the y (vertical) axis in + * radians. + * @param {number} aspect The x (width) to y (height) aspect ratio. + * @param {number} near The distance to the near clipping plane. + * @param {number} far The distance to the far clipping plane. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.prototype.getRevision = function() { - return this.revision_; +goog.vec.Mat4.makePerspective = function(mat, fovy, aspect, near, far) { + var angle = fovy / 2; + var dz = far - near; + var sinAngle = Math.sin(angle); + if (dz == 0 || sinAngle == 0 || aspect == 0) { + return mat; + } + + var cot = Math.cos(angle) / sinAngle; + return goog.vec.Mat4.setFromValues(mat, + cot / aspect, 0, 0, 0, + 0, cot, 0, 0, + 0, 0, -(far + near) / dz, -1, + 0, 0, -(2 * near * far) / dz, 0 + ); }; /** - * Listen for a certain type of event. - * @param {string|Array.<string>} type The event type or array of event types. - * @param {function(?): ?} listener The listener function. - * @param {Object=} opt_this The object to use as `this` in `listener`. - * @return {goog.events.Key} Unique key for the listener. - * @api stable + * Makes the given 4x4 matrix an orthographic projection matrix. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} left The coordinate of the left clipping plane. + * @param {number} right The coordinate of the right clipping plane. + * @param {number} bottom The coordinate of the bottom clipping plane. + * @param {number} top The coordinate of the top clipping plane. + * @param {number} near The distance to the near clipping plane. + * @param {number} far The distance to the far clipping plane. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.prototype.on = function(type, listener, opt_this) { - return goog.events.listen(this, type, listener, false, opt_this); +goog.vec.Mat4.makeOrtho = function(mat, left, right, bottom, top, near, far) { + var x = 2 / (right - left); + var y = 2 / (top - bottom); + var z = -2 / (far - near); + var a = -(right + left) / (right - left); + var b = -(top + bottom) / (top - bottom); + var c = -(far + near) / (far - near); + + return goog.vec.Mat4.setFromValues(mat, + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + a, b, c, 1 + ); }; /** - * Listen once for a certain type of event. - * @param {string|Array.<string>} type The event type or array of event types. - * @param {function(?): ?} listener The listener function. - * @param {Object=} opt_this The object to use as `this` in `listener`. - * @return {goog.events.Key} Unique key for the listener. - * @api stable + * Makes the given 4x4 matrix a modelview matrix of a camera so that + * the camera is 'looking at' the given center point. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point + * (camera origin). + * @param {goog.vec.Vec3.AnyType} centerPt The point to aim the camera at. + * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that identifies + * the up direction for the camera. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.prototype.once = function(type, listener, opt_this) { - return goog.events.listenOnce(this, type, listener, false, opt_this); +goog.vec.Mat4.makeLookAt = function(mat, eyePt, centerPt, worldUpVec) { + // Compute the direction vector from the eye point to the center point and + // normalize. + var fwdVec = goog.vec.Mat4.tmpVec4_[0]; + goog.vec.Vec3.subtract(centerPt, eyePt, fwdVec); + goog.vec.Vec3.normalize(fwdVec, fwdVec); + fwdVec[3] = 0; + + // Compute the side vector from the forward vector and the input up vector. + var sideVec = goog.vec.Mat4.tmpVec4_[1]; + goog.vec.Vec3.cross(fwdVec, worldUpVec, sideVec); + goog.vec.Vec3.normalize(sideVec, sideVec); + sideVec[3] = 0; + + // Now the up vector to form the orthonormal basis. + var upVec = goog.vec.Mat4.tmpVec4_[2]; + goog.vec.Vec3.cross(sideVec, fwdVec, upVec); + goog.vec.Vec3.normalize(upVec, upVec); + upVec[3] = 0; + + // Update the view matrix with the new orthonormal basis and position the + // camera at the given eye point. + goog.vec.Vec3.negate(fwdVec, fwdVec); + goog.vec.Mat4.setRow(mat, 0, sideVec); + goog.vec.Mat4.setRow(mat, 1, upVec); + goog.vec.Mat4.setRow(mat, 2, fwdVec); + goog.vec.Mat4.setRowValues(mat, 3, 0, 0, 0, 1); + goog.vec.Mat4.translate( + mat, -eyePt[0], -eyePt[1], -eyePt[2]); + + return mat; }; /** - * Unlisten for a certain type of event. - * @param {string|Array.<string>} type The event type or array of event types. - * @param {function(?): ?} listener The listener function. - * @param {Object=} opt_this The object which was used as `this` by the - * `listener`. - * @api stable + * Decomposes a matrix into the lookAt vectors eyePt, fwdVec and worldUpVec. + * The matrix represents the modelview matrix of a camera. It is the inverse + * of lookAt except for the output of the fwdVec instead of centerPt. + * The centerPt itself cannot be recovered from a modelview matrix. + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point + * (camera origin). + * @param {goog.vec.Vec3.AnyType} fwdVec The vector describing where + * the camera points to. + * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that + * identifies the up direction for the camera. + * @return {boolean} True if the method succeeds, false otherwise. + * The method can only fail if the inverse of viewMatrix is not defined. */ -ol.Observable.prototype.un = function(type, listener, opt_this) { - goog.events.unlisten(this, type, listener, false, opt_this); +goog.vec.Mat4.toLookAt = function(mat, eyePt, fwdVec, worldUpVec) { + // Get eye of the camera. + var matInverse = goog.vec.Mat4.tmpMat4_[0]; + if (!goog.vec.Mat4.invert(mat, matInverse)) { + // The input matrix does not have a valid inverse. + return false; + } + + if (eyePt) { + eyePt[0] = matInverse[12]; + eyePt[1] = matInverse[13]; + eyePt[2] = matInverse[14]; + } + + // Get forward vector from the definition of lookAt. + if (fwdVec || worldUpVec) { + if (!fwdVec) { + fwdVec = goog.vec.Mat4.tmpVec3_[0]; + } + fwdVec[0] = -mat[2]; + fwdVec[1] = -mat[6]; + fwdVec[2] = -mat[10]; + // Normalize forward vector. + goog.vec.Vec3.normalize(fwdVec, fwdVec); + } + + if (worldUpVec) { + // Get side vector from the definition of gluLookAt. + var side = goog.vec.Mat4.tmpVec3_[1]; + side[0] = mat[0]; + side[1] = mat[4]; + side[2] = mat[8]; + // Compute up vector as a up = side x forward. + goog.vec.Vec3.cross(side, fwdVec, worldUpVec); + // Normalize up vector. + goog.vec.Vec3.normalize(worldUpVec, worldUpVec); + } + return true; }; /** - * Removes an event listener using the key returned by `on()` or `once()`. - * Note that using the {@link ol.Observable.unByKey} static function is to - * be preferred. - * @param {goog.events.Key} key The key returned by `on()` or `once()`. - * @function - * @api stable + * Makes the given 4x4 matrix a rotation matrix given Euler angles using + * the ZXZ convention. + * Given the euler angles [theta1, theta2, theta3], the rotation is defined as + * rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3), + * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi]. + * rotation_x(theta) means rotation around the X axis of theta radians, + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} theta1 The angle of rotation around the Z axis in radians. + * @param {number} theta2 The angle of rotation around the X axis in radians. + * @param {number} theta3 The angle of rotation around the Z axis in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Observable.prototype.unByKey = ol.Observable.unByKey; +goog.vec.Mat4.makeEulerZXZ = function(mat, theta1, theta2, theta3) { + var c1 = Math.cos(theta1); + var s1 = Math.sin(theta1); -goog.provide('ol.Object'); -goog.provide('ol.ObjectEvent'); -goog.provide('ol.ObjectEventType'); + var c2 = Math.cos(theta2); + var s2 = Math.sin(theta2); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('ol.Observable'); + var c3 = Math.cos(theta3); + var s3 = Math.sin(theta3); + + mat[0] = c1 * c3 - c2 * s1 * s3; + mat[1] = c2 * c1 * s3 + c3 * s1; + mat[2] = s3 * s2; + mat[3] = 0; + mat[4] = -c1 * s3 - c3 * c2 * s1; + mat[5] = c1 * c2 * c3 - s1 * s3; + mat[6] = c3 * s2; + mat[7] = 0; -/** - * @enum {string} - */ -ol.ObjectEventType = { - /** - * Triggered when a property is changed. - * @event ol.ObjectEvent#propertychange - * @api stable - */ - PROPERTYCHANGE: 'propertychange' -}; + mat[8] = s2 * s1; + mat[9] = -c1 * s2; + mat[10] = c2; + mat[11] = 0; + + mat[12] = 0; + mat[13] = 0; + mat[14] = 0; + mat[15] = 1; + return mat; +}; /** - * @classdesc - * Events emitted by {@link ol.Object} instances are instances of this type. + * Decomposes a rotation matrix into Euler angles using the ZXZ convention so + * that rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3), + * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi]. + * rotation_x(theta) means rotation around the X axis of theta radians. * - * @param {string} type The event type. - * @param {string} key The property name. - * @param {*} oldValue The old value for `key`. - * @extends {goog.events.Event} - * @implements {oli.ObjectEvent} - * @constructor + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {goog.vec.Vec3.AnyType} euler The ZXZ Euler angles in + * radians as [theta1, theta2, theta3]. + * @param {boolean=} opt_theta2IsNegative Whether theta2 is in [-pi, 0] instead + * of the default [0, pi]. + * @return {goog.vec.Vec4.AnyType} return euler so that operations can be + * chained together. */ -ol.ObjectEvent = function(type, key, oldValue) { - goog.base(this, type); +goog.vec.Mat4.toEulerZXZ = function(mat, euler, opt_theta2IsNegative) { + // There is an ambiguity in the sign of sinTheta2 because of the sqrt. + var sinTheta2 = Math.sqrt(mat[2] * mat[2] + mat[6] * mat[6]); - /** - * The name of the property whose value is changing. - * @type {string} - * @api stable - */ - this.key = key; + // By default we explicitely constrain theta2 to be in [0, pi], + // so sinTheta2 is always positive. We can change the behavior and specify + // theta2 to be negative in [-pi, 0] with opt_Theta2IsNegative. + var signTheta2 = opt_theta2IsNegative ? -1 : 1; - /** - * The old value. To get the new value use `e.target.get(e.key)` where - * `e` is the event object. - * @type {*} - * @api stable - */ - this.oldValue = oldValue; + if (sinTheta2 > goog.vec.EPSILON) { + euler[2] = Math.atan2(mat[2] * signTheta2, mat[6] * signTheta2); + euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]); + euler[0] = Math.atan2(mat[8] * signTheta2, -mat[9] * signTheta2); + } else { + // There is also an arbitrary choice for theta1 = 0 or theta2 = 0 here. + // We assume theta1 = 0 as some applications do not allow the camera to roll + // (i.e. have theta1 != 0). + euler[0] = 0; + euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]); + euler[2] = Math.atan2(mat[1], mat[0]); + } -}; -goog.inherits(ol.ObjectEvent, goog.events.Event); + // Atan2 outputs angles in [-pi, pi] so we bring them back to [0, 2 * pi]. + euler[0] = (euler[0] + Math.PI * 2) % (Math.PI * 2); + euler[2] = (euler[2] + Math.PI * 2) % (Math.PI * 2); + // For theta2 we want the angle to be in [0, pi] or [-pi, 0] depending on + // signTheta2. + euler[1] = ((euler[1] * signTheta2 + Math.PI * 2) % (Math.PI * 2)) * + signTheta2; + return euler; +}; /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Most non-trivial classes inherit from this. - * - * This extends {@link ol.Observable} with observable properties, where each - * property is observable as well as the object as a whole. - * - * Classes that inherit from this have pre-defined properties, to which you can - * add your owns. The pre-defined properties are listed in this documentation as - * 'Observable Properties', and have their own accessors; for example, - * {@link ol.Map} has a `target` property, accessed with `getTarget()` and - * changed with `setTarget()`. Not all properties are however settable. There - * are also general-purpose accessors `get()` and `set()`. For example, - * `get('target')` is equivalent to `getTarget()`. - * - * The `set` accessors trigger a change event, and you can monitor this by - * registering a listener. For example, {@link ol.View} has a `center` - * property, so `view.on('change:center', function(evt) {...});` would call the - * function whenever the value of the center property changes. Within the - * function, `evt.target` would be the view, so `evt.target.getCenter()` would - * return the new center. - * - * You can add your own observable properties with - * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`. - * You can listen for changes on that property value with - * `object.on('change:prop', listener)`. You can get a list of all - * properties with {@link ol.Object#getProperties object.getProperties()}. - * - * Note that the observable properties are separate from standard JS properties. - * You can, for example, give your map object a title with - * `map.title='New title'` and with `map.set('title', 'Another title')`. The - * first will be a `hasOwnProperty`; the second will appear in - * `getProperties()`. Only the second is observable. - * - * Properties can be deleted by using the unset method. E.g. - * object.unset('foo'). + * Translates the given matrix by x,y,z. Equvialent to: + * goog.vec.Mat4.multMat( + * mat, + * goog.vec.Mat4.makeTranslate(goog.vec.Mat4.create(), x, y, z), + * mat); * - * @constructor - * @extends {ol.Observable} - * @param {Object.<string, *>=} opt_values An object with key-value pairs. - * @fires ol.ObjectEvent - * @api + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} x The translation along the x axis. + * @param {number} y The translation along the y axis. + * @param {number} z The translation along the z axis. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Object = function(opt_values) { - goog.base(this); - - // Call goog.getUid to ensure that the order of objects' ids is the same as - // the order in which they were created. This also helps to ensure that - // object properties are always added in the same order, which helps many - // JavaScript engines generate faster code. - goog.getUid(this); - - /** - * @private - * @type {!Object.<string, *>} - */ - this.values_ = {}; - - if (opt_values !== undefined) { - this.setProperties(opt_values); - } +goog.vec.Mat4.translate = function(mat, x, y, z) { + return goog.vec.Mat4.setColumnValues( + mat, 3, + mat[0] * x + mat[4] * y + mat[8] * z + mat[12], + mat[1] * x + mat[5] * y + mat[9] * z + mat[13], + mat[2] * x + mat[6] * y + mat[10] * z + mat[14], + mat[3] * x + mat[7] * y + mat[11] * z + mat[15]); }; -goog.inherits(ol.Object, ol.Observable); /** - * @private - * @type {Object.<string, string>} - */ -ol.Object.changeEventTypeCache_ = {}; - - -/** - * @param {string} key Key name. - * @return {string} Change name. + * Scales the given matrix by x,y,z. Equivalent to: + * goog.vec.Mat4.multMat( + * mat, + * goog.vec.Mat4.makeScale(goog.vec.Mat4.create(), x, y, z), + * mat); + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} x The x scale factor. + * @param {number} y The y scale factor. + * @param {number} z The z scale factor. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Object.getChangeEventType = function(key) { - return ol.Object.changeEventTypeCache_.hasOwnProperty(key) ? - ol.Object.changeEventTypeCache_[key] : - (ol.Object.changeEventTypeCache_[key] = 'change:' + key); +goog.vec.Mat4.scale = function(mat, x, y, z) { + return goog.vec.Mat4.setFromValues( + mat, + mat[0] * x, mat[1] * x, mat[2] * x, mat[3] * x, + mat[4] * y, mat[5] * y, mat[6] * y, mat[7] * y, + mat[8] * z, mat[9] * z, mat[10] * z, mat[11] * z, + mat[12], mat[13], mat[14], mat[15]); }; /** - * Gets a value. - * @param {string} key Key name. - * @return {*} Value. - * @api stable + * Rotate the given matrix by angle about the x,y,z axis. Equivalent to: + * goog.vec.Mat4.multMat( + * mat, + * goog.vec.Mat4.makeRotate(goog.vec.Mat4.create(), angle, x, y, z), + * mat); + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The angle in radians. + * @param {number} x The x component of the rotation axis. + * @param {number} y The y component of the rotation axis. + * @param {number} z The z component of the rotation axis. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Object.prototype.get = function(key) { - var value; - if (this.values_.hasOwnProperty(key)) { - value = this.values_[key]; - } - return value; -}; +goog.vec.Mat4.rotate = function(mat, angle, x, y, z) { + var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; + var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; + var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; + var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; + var cosAngle = Math.cos(angle); + var sinAngle = Math.sin(angle); + var diffCosAngle = 1 - cosAngle; + var r00 = x * x * diffCosAngle + cosAngle; + var r10 = x * y * diffCosAngle + z * sinAngle; + var r20 = x * z * diffCosAngle - y * sinAngle; -/** - * Get a list of object property names. - * @return {Array.<string>} List of property names. - * @api stable - */ -ol.Object.prototype.getKeys = function() { - return Object.keys(this.values_); -}; + var r01 = x * y * diffCosAngle - z * sinAngle; + var r11 = y * y * diffCosAngle + cosAngle; + var r21 = y * z * diffCosAngle + x * sinAngle; + var r02 = x * z * diffCosAngle + y * sinAngle; + var r12 = y * z * diffCosAngle - x * sinAngle; + var r22 = z * z * diffCosAngle + cosAngle; -/** - * Get an object of all property names and values. - * @return {Object.<string, *>} Object. - * @api stable - */ -ol.Object.prototype.getProperties = function() { - var properties = {}; - var key; - for (key in this.values_) { - properties[key] = this.values_[key]; - } - return properties; -}; + return goog.vec.Mat4.setFromValues( + mat, + m00 * r00 + m01 * r10 + m02 * r20, + m10 * r00 + m11 * r10 + m12 * r20, + m20 * r00 + m21 * r10 + m22 * r20, + m30 * r00 + m31 * r10 + m32 * r20, + m00 * r01 + m01 * r11 + m02 * r21, + m10 * r01 + m11 * r11 + m12 * r21, + m20 * r01 + m21 * r11 + m22 * r21, + m30 * r01 + m31 * r11 + m32 * r21, -/** - * @param {string} key Key name. - * @param {*} oldValue Old value. - */ -ol.Object.prototype.notify = function(key, oldValue) { - var eventType; - eventType = ol.Object.getChangeEventType(key); - this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue)); - eventType = ol.ObjectEventType.PROPERTYCHANGE; - this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue)); + m00 * r02 + m01 * r12 + m02 * r22, + m10 * r02 + m11 * r12 + m12 * r22, + m20 * r02 + m21 * r12 + m22 * r22, + m30 * r02 + m31 * r12 + m32 * r22, + + m03, m13, m23, m33); }; /** - * Sets a value. - * @param {string} key Key name. - * @param {*} value Value. - * @param {boolean=} opt_silent Update without triggering an event. - * @api stable + * Rotate the given matrix by angle about the x axis. Equivalent to: + * goog.vec.Mat4.multMat( + * mat, + * goog.vec.Mat4.makeRotateX(goog.vec.Mat4.create(), angle), + * mat); + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The angle in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Object.prototype.set = function(key, value, opt_silent) { - if (opt_silent) { - this.values_[key] = value; - } else { - var oldValue = this.values_[key]; - this.values_[key] = value; - if (oldValue !== value) { - this.notify(key, oldValue); - } - } -}; +goog.vec.Mat4.rotateX = function(mat, angle) { + var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; + var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; + var c = Math.cos(angle); + var s = Math.sin(angle); -/** - * Sets a collection of key-value pairs. Note that this changes any existing - * properties and adds new ones (it does not remove any existing properties). - * @param {Object.<string, *>} values Values. - * @param {boolean=} opt_silent Update without triggering an event. - * @api stable - */ -ol.Object.prototype.setProperties = function(values, opt_silent) { - var key; - for (key in values) { - this.set(key, values[key], opt_silent); - } + mat[4] = m01 * c + m02 * s; + mat[5] = m11 * c + m12 * s; + mat[6] = m21 * c + m22 * s; + mat[7] = m31 * c + m32 * s; + mat[8] = m01 * -s + m02 * c; + mat[9] = m11 * -s + m12 * c; + mat[10] = m21 * -s + m22 * c; + mat[11] = m31 * -s + m32 * c; + + return mat; }; /** - * Unsets a property. - * @param {string} key Key name. - * @param {boolean=} opt_silent Unset without triggering an event. - * @api stable + * Rotate the given matrix by angle about the y axis. Equivalent to: + * goog.vec.Mat4.multMat( + * mat, + * goog.vec.Mat4.makeRotateY(goog.vec.Mat4.create(), angle), + * mat); + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The angle in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Object.prototype.unset = function(key, opt_silent) { - if (key in this.values_) { - var oldValue = this.values_[key]; - delete this.values_[key]; - if (!opt_silent) { - this.notify(key, oldValue); - } - } -}; +goog.vec.Mat4.rotateY = function(mat, angle) { + var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; + var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; -goog.provide('ol.Size'); -goog.provide('ol.size'); + var c = Math.cos(angle); + var s = Math.sin(angle); + mat[0] = m00 * c + m02 * -s; + mat[1] = m10 * c + m12 * -s; + mat[2] = m20 * c + m22 * -s; + mat[3] = m30 * c + m32 * -s; + mat[8] = m00 * s + m02 * c; + mat[9] = m10 * s + m12 * c; + mat[10] = m20 * s + m22 * c; + mat[11] = m30 * s + m32 * c; -goog.require('goog.asserts'); + return mat; +}; /** - * An array of numbers representing a size: `[width, height]`. - * @typedef {Array.<number>} - * @api stable + * Rotate the given matrix by angle about the z axis. Equivalent to: + * goog.vec.Mat4.multMat( + * mat, + * goog.vec.Mat4.makeRotateZ(goog.vec.Mat4.create(), angle), + * mat); + * + * @param {goog.vec.Mat4.AnyType} mat The matrix. + * @param {number} angle The angle in radians. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.Size; +goog.vec.Mat4.rotateZ = function(mat, angle) { + var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; + var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; + var c = Math.cos(angle); + var s = Math.sin(angle); -/** - * Returns a buffered size. - * @param {ol.Size} size Size. - * @param {number} buffer Buffer. - * @param {ol.Size=} opt_size Optional reusable size array. - * @return {ol.Size} - */ -ol.size.buffer = function(size, buffer, opt_size) { - if (opt_size === undefined) { - opt_size = [0, 0]; - } - opt_size[0] = size[0] + 2 * buffer; - opt_size[1] = size[1] + 2 * buffer; - return opt_size; + mat[0] = m00 * c + m01 * s; + mat[1] = m10 * c + m11 * s; + mat[2] = m20 * c + m21 * s; + mat[3] = m30 * c + m31 * s; + mat[4] = m00 * -s + m01 * c; + mat[5] = m10 * -s + m11 * c; + mat[6] = m20 * -s + m21 * c; + mat[7] = m30 * -s + m31 * c; + + return mat; }; /** - * Compares sizes for equality. - * @param {ol.Size} a Size. - * @param {ol.Size} b Size. - * @return {boolean} Equals. + * Retrieves the translation component of the transformation matrix. + * + * @param {goog.vec.Mat4.AnyType} mat The transformation matrix. + * @param {goog.vec.Vec3.AnyType} translation The vector for storing the + * result. + * @return {goog.vec.Mat4.AnyType} return mat so that operations can be + * chained. */ -ol.size.equals = function(a, b) { - return a[0] == b[0] && a[1] == b[1]; +goog.vec.Mat4.getTranslation = function(mat, translation) { + translation[0] = mat[12]; + translation[1] = mat[13]; + translation[2] = mat[14]; + return translation; }; /** - * Determines if a size has a positive area. - * @param {ol.Size} size The size to test. - * @return {boolean} The size has a positive area. + * @type {!Array<!goog.vec.Vec3.Type>} + * @private */ -ol.size.hasArea = function(size) { - return size[0] > 0 && size[1] > 0; -}; +goog.vec.Mat4.tmpVec3_ = [ + goog.vec.Vec3.createFloat64(), + goog.vec.Vec3.createFloat64() +]; /** - * Returns a size scaled by a ratio. The result will be an array of integers. - * @param {ol.Size} size Size. - * @param {number} ratio Ratio. - * @param {ol.Size=} opt_size Optional reusable size array. - * @return {ol.Size} + * @type {!Array<!goog.vec.Vec4.Type>} + * @private */ -ol.size.scale = function(size, ratio, opt_size) { - if (opt_size === undefined) { - opt_size = [0, 0]; - } - opt_size[0] = (size[0] * ratio + 0.5) | 0; - opt_size[1] = (size[1] * ratio + 0.5) | 0; - return opt_size; -}; +goog.vec.Mat4.tmpVec4_ = [ + goog.vec.Vec4.createFloat64(), + goog.vec.Vec4.createFloat64(), + goog.vec.Vec4.createFloat64() +]; /** - * Returns an `ol.Size` array for the passed in number (meaning: square) or - * `ol.Size` array. - * (meaning: non-square), - * @param {number|ol.Size} size Width and height. - * @param {ol.Size=} opt_size Optional reusable size array. - * @return {ol.Size} Size. - * @api stable + * @type {!Array<!goog.vec.Mat4.Type>} + * @private */ -ol.size.toSize = function(size, opt_size) { - if (goog.isArray(size)) { - return size; - } else { - goog.asserts.assert(goog.isNumber(size)); - if (opt_size === undefined) { - opt_size = [size, size]; - } else { - opt_size[0] = size; - opt_size[1] = size; - } - return opt_size; - } -}; +goog.vec.Mat4.tmpMat4_ = [ + goog.vec.Mat4.createFloat64() +]; // Copyright 2006 The Closure Library Authors. All Rights Reserved. // @@ -16090,11462 +16572,10524 @@ ol.coordinate.fromProjectedArray = function(array, axis) { } }; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.provide('ol.Size'); +goog.provide('ol.size'); + + +goog.require('goog.asserts'); /** - * @fileoverview Supplies a Float32Array implementation that implements - * most of the Float32Array spec and that can be used when a built-in - * implementation is not available. - * - * Note that if no existing Float32Array implementation is found then - * this class and all its public properties are exported as Float32Array. - * - * Adding support for the other TypedArray classes here does not make sense - * since this vector math library only needs Float32Array. - * + * An array of numbers representing a size: `[width, height]`. + * @typedef {Array.<number>} + * @api stable */ -goog.provide('goog.vec.Float32Array'); - +ol.Size; /** - * Constructs a new Float32Array. The new array is initialized to all zeros. - * - * @param {goog.vec.Float32Array|Array|ArrayBuffer|number} p0 - * The length of the array, or an array to initialize the contents of the - * new Float32Array. - * @constructor - * @final + * Returns a buffered size. + * @param {ol.Size} size Size. + * @param {number} buffer Buffer. + * @param {ol.Size=} opt_size Optional reusable size array. + * @return {ol.Size} */ -goog.vec.Float32Array = function(p0) { - this.length = /** @type {number} */ (p0.length || p0); - for (var i = 0; i < this.length; i++) { - this[i] = p0[i] || 0; +ol.size.buffer = function(size, buffer, opt_size) { + if (opt_size === undefined) { + opt_size = [0, 0]; } + opt_size[0] = size[0] + 2 * buffer; + opt_size[1] = size[1] + 2 * buffer; + return opt_size; }; /** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} + * Compares sizes for equality. + * @param {ol.Size} a Size. + * @param {ol.Size} b Size. + * @return {boolean} Equals. */ -goog.vec.Float32Array.BYTES_PER_ELEMENT = 4; +ol.size.equals = function(a, b) { + return a[0] == b[0] && a[1] == b[1]; +}; /** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} + * Determines if a size has a positive area. + * @param {ol.Size} size The size to test. + * @return {boolean} The size has a positive area. */ -goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT = 4; +ol.size.hasArea = function(size) { + return size[0] > 0 && size[1] > 0; +}; /** - * Sets elements of the array. - * @param {Array<number>|Float32Array} values The array of values. - * @param {number=} opt_offset The offset in this array to start. + * Returns a size scaled by a ratio. The result will be an array of integers. + * @param {ol.Size} size Size. + * @param {number} ratio Ratio. + * @param {ol.Size=} opt_size Optional reusable size array. + * @return {ol.Size} */ -goog.vec.Float32Array.prototype.set = function(values, opt_offset) { - opt_offset = opt_offset || 0; - for (var i = 0; i < values.length && opt_offset + i < this.length; i++) { - this[opt_offset + i] = values[i]; +ol.size.scale = function(size, ratio, opt_size) { + if (opt_size === undefined) { + opt_size = [0, 0]; } + opt_size[0] = (size[0] * ratio + 0.5) | 0; + opt_size[1] = (size[1] * ratio + 0.5) | 0; + return opt_size; }; /** - * Creates a string representation of this array. - * @return {string} The string version of this array. - * @override + * Returns an `ol.Size` array for the passed in number (meaning: square) or + * `ol.Size` array. + * (meaning: non-square), + * @param {number|ol.Size} size Width and height. + * @param {ol.Size=} opt_size Optional reusable size array. + * @return {ol.Size} Size. + * @api stable */ -goog.vec.Float32Array.prototype.toString = Array.prototype.join; +ol.size.toSize = function(size, opt_size) { + if (goog.isArray(size)) { + return size; + } else { + goog.asserts.assert(goog.isNumber(size)); + if (opt_size === undefined) { + opt_size = [size, size]; + } else { + opt_size[0] = size; + opt_size[1] = size; + } + return opt_size; + } +}; + +goog.provide('ol.TransformFunction'); /** - * Note that we cannot implement the subarray() or (deprecated) slice() - * methods properly since doing so would require being able to overload - * the [] operator which is not possible in javascript. So we leave - * them unimplemented. Any attempt to call these methods will just result - * in a javascript error since we leave them undefined. + * A transform function accepts an array of input coordinate values, an optional + * output array, and an optional dimension (default should be 2). The function + * transforms the input coordinate values, populates the output array, and + * returns the output array. + * + * @typedef {function(Array.<number>, Array.<number>=, number=): Array.<number>} + * @api stable */ +ol.TransformFunction; + +goog.provide('ol.Extent'); +goog.provide('ol.extent'); +goog.provide('ol.extent.Corner'); +goog.provide('ol.extent.Relationship'); + +goog.require('goog.asserts'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Coordinate'); +goog.require('ol.Size'); +goog.require('ol.TransformFunction'); /** - * If no existing Float32Array implementation is found then we export - * goog.vec.Float32Array as Float32Array. + * An array of numbers representing an extent: `[minx, miny, maxx, maxy]`. + * @typedef {Array.<number>} + * @api stable */ -if (typeof Float32Array == 'undefined') { - goog.exportProperty(goog.vec.Float32Array, 'BYTES_PER_ELEMENT', - goog.vec.Float32Array.BYTES_PER_ELEMENT); - goog.exportProperty(goog.vec.Float32Array.prototype, 'BYTES_PER_ELEMENT', - goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT); - goog.exportProperty(goog.vec.Float32Array.prototype, 'set', - goog.vec.Float32Array.prototype.set); - goog.exportProperty(goog.vec.Float32Array.prototype, 'toString', - goog.vec.Float32Array.prototype.toString); - goog.exportSymbol('Float32Array', goog.vec.Float32Array); -} - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +ol.Extent; /** - * @fileoverview Supplies a Float64Array implementation that implements - * most of the Float64Array spec and that can be used when a built-in - * implementation is not available. - * - * Note that if no existing Float64Array implementation is found then this - * class and all its public properties are exported as Float64Array. - * - * Adding support for the other TypedArray classes here does not make sense - * since this vector math library only needs Float32Array and Float64Array. - * + * Extent corner. + * @enum {string} */ -goog.provide('goog.vec.Float64Array'); - +ol.extent.Corner = { + BOTTOM_LEFT: 'bottom-left', + BOTTOM_RIGHT: 'bottom-right', + TOP_LEFT: 'top-left', + TOP_RIGHT: 'top-right' +}; /** - * Constructs a new Float64Array. The new array is initialized to all zeros. - * - * @param {goog.vec.Float64Array|Array|ArrayBuffer|number} p0 - * The length of the array, or an array to initialize the contents of the - * new Float64Array. - * @constructor - * @final + * Relationship to an extent. + * @enum {number} */ -goog.vec.Float64Array = function(p0) { - this.length = /** @type {number} */ (p0.length || p0); - for (var i = 0; i < this.length; i++) { - this[i] = p0[i] || 0; - } +ol.extent.Relationship = { + UNKNOWN: 0, + INTERSECTING: 1, + ABOVE: 2, + RIGHT: 4, + BELOW: 8, + LEFT: 16 }; /** - * The number of bytes in an element (as defined by the Typed Array - * specification). + * Build an extent that includes all given coordinates. * - * @type {number} + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @return {ol.Extent} Bounding extent. + * @api stable */ -goog.vec.Float64Array.BYTES_PER_ELEMENT = 8; +ol.extent.boundingExtent = function(coordinates) { + var extent = ol.extent.createEmpty(); + for (var i = 0, ii = coordinates.length; i < ii; ++i) { + ol.extent.extendCoordinate(extent, coordinates[i]); + } + return extent; +}; /** - * The number of bytes in an element (as defined by the Typed Array - * specification). - * - * @type {number} + * @param {Array.<number>} xs Xs. + * @param {Array.<number>} ys Ys. + * @param {ol.Extent=} opt_extent Destination extent. + * @private + * @return {ol.Extent} Extent. */ -goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT = 8; +ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) { + goog.asserts.assert(xs.length > 0, 'xs length should be larger than 0'); + goog.asserts.assert(ys.length > 0, 'ys length should be larger than 0'); + var minX = Math.min.apply(null, xs); + var minY = Math.min.apply(null, ys); + var maxX = Math.max.apply(null, xs); + var maxY = Math.max.apply(null, ys); + return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); +}; /** - * Sets elements of the array. - * @param {Array<number>|Float64Array} values The array of values. - * @param {number=} opt_offset The offset in this array to start. + * Return extent increased by the provided value. + * @param {ol.Extent} extent Extent. + * @param {number} value The amount by which the extent should be buffered. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. + * @api stable */ -goog.vec.Float64Array.prototype.set = function(values, opt_offset) { - opt_offset = opt_offset || 0; - for (var i = 0; i < values.length && opt_offset + i < this.length; i++) { - this[opt_offset + i] = values[i]; +ol.extent.buffer = function(extent, value, opt_extent) { + if (opt_extent) { + opt_extent[0] = extent[0] - value; + opt_extent[1] = extent[1] - value; + opt_extent[2] = extent[2] + value; + opt_extent[3] = extent[3] + value; + return opt_extent; + } else { + return [ + extent[0] - value, + extent[1] - value, + extent[2] + value, + extent[3] + value + ]; } }; /** - * Creates a string representation of this array. - * @return {string} The string version of this array. - * @override + * Creates a clone of an extent. + * + * @param {ol.Extent} extent Extent to clone. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} The clone. */ -goog.vec.Float64Array.prototype.toString = Array.prototype.join; +ol.extent.clone = function(extent, opt_extent) { + if (opt_extent) { + opt_extent[0] = extent[0]; + opt_extent[1] = extent[1]; + opt_extent[2] = extent[2]; + opt_extent[3] = extent[3]; + return opt_extent; + } else { + return extent.slice(); + } +}; /** - * Note that we cannot implement the subarray() or (deprecated) slice() - * methods properly since doing so would require being able to overload - * the [] operator which is not possible in javascript. So we leave - * them unimplemented. Any attempt to call these methods will just result - * in a javascript error since we leave them undefined. + * @param {ol.Extent} extent Extent. + * @param {number} x X. + * @param {number} y Y. + * @return {number} Closest squared distance. */ +ol.extent.closestSquaredDistanceXY = function(extent, x, y) { + var dx, dy; + if (x < extent[0]) { + dx = extent[0] - x; + } else if (extent[2] < x) { + dx = x - extent[2]; + } else { + dx = 0; + } + if (y < extent[1]) { + dy = extent[1] - y; + } else if (extent[3] < y) { + dy = y - extent[3]; + } else { + dy = 0; + } + return dx * dx + dy * dy; +}; /** - * If no existing Float64Array implementation is found then we export - * goog.vec.Float64Array as Float64Array. + * Check if the passed coordinate is contained or on the edge of the extent. + * + * @param {ol.Extent} extent Extent. + * @param {ol.Coordinate} coordinate Coordinate. + * @return {boolean} The coordinate is contained in the extent. + * @api stable */ -if (typeof Float64Array == 'undefined') { - try { - goog.exportProperty(goog.vec.Float64Array, 'BYTES_PER_ELEMENT', - goog.vec.Float64Array.BYTES_PER_ELEMENT); - } catch (float64ArrayError) { - // Do nothing. This code is in place to fix b/7225850, in which an error - // is incorrectly thrown for Google TV on an old Chrome. - // TODO(user): remove after that version is retired. - } +ol.extent.containsCoordinate = function(extent, coordinate) { + return ol.extent.containsXY(extent, coordinate[0], coordinate[1]); +}; - goog.exportProperty(goog.vec.Float64Array.prototype, 'BYTES_PER_ELEMENT', - goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT); - goog.exportProperty(goog.vec.Float64Array.prototype, 'set', - goog.vec.Float64Array.prototype.set); - goog.exportProperty(goog.vec.Float64Array.prototype, 'toString', - goog.vec.Float64Array.prototype.toString); - goog.exportSymbol('Float64Array', goog.vec.Float64Array); -} -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/** + * Check if one extent contains another. + * + * An extent is deemed contained if it lies completely within the other extent, + * including if they share one or more edges. + * + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent 2. + * @return {boolean} The second extent is contained by or on the edge of the + * first. + * @api stable + */ +ol.extent.containsExtent = function(extent1, extent2) { + return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] && + extent1[1] <= extent2[1] && extent2[3] <= extent1[3]; +}; /** - * @fileoverview Supplies global data types and constants for the vector math - * library. + * Check if the passed coordinate is contained or on the edge of the extent. + * + * @param {ol.Extent} extent Extent. + * @param {number} x X coordinate. + * @param {number} y Y coordinate. + * @return {boolean} The x, y values are contained in the extent. + * @api stable */ -goog.provide('goog.vec'); -goog.provide('goog.vec.AnyType'); -goog.provide('goog.vec.ArrayType'); -goog.provide('goog.vec.Float32'); -goog.provide('goog.vec.Float64'); -goog.provide('goog.vec.Number'); +ol.extent.containsXY = function(extent, x, y) { + return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3]; +}; /** - * On platforms that don't have native Float32Array or Float64Array support we - * use a javascript implementation so that this math library can be used on all - * platforms. - * @suppress {extraRequire} + * Get the relationship between a coordinate and extent. + * @param {ol.Extent} extent The extent. + * @param {ol.Coordinate} coordinate The coordinate. + * @return {number} The relationship (bitwise compare with + * ol.extent.Relationship). */ -goog.require('goog.vec.Float32Array'); -/** @suppress {extraRequire} */ -goog.require('goog.vec.Float64Array'); - -// All vector and matrix operations are based upon arrays of numbers using -// either Float32Array, Float64Array, or a standard Javascript Array of -// Numbers. +ol.extent.coordinateRelationship = function(extent, coordinate) { + var minX = extent[0]; + var minY = extent[1]; + var maxX = extent[2]; + var maxY = extent[3]; + var x = coordinate[0]; + var y = coordinate[1]; + var relationship = ol.extent.Relationship.UNKNOWN; + if (x < minX) { + relationship = relationship | ol.extent.Relationship.LEFT; + } else if (x > maxX) { + relationship = relationship | ol.extent.Relationship.RIGHT; + } + if (y < minY) { + relationship = relationship | ol.extent.Relationship.BELOW; + } else if (y > maxY) { + relationship = relationship | ol.extent.Relationship.ABOVE; + } + if (relationship === ol.extent.Relationship.UNKNOWN) { + relationship = ol.extent.Relationship.INTERSECTING; + } + return relationship; +}; -/** @typedef {!Float32Array} */ -goog.vec.Float32; +/** + * Create an empty extent. + * @return {ol.Extent} Empty extent. + * @api stable + */ +ol.extent.createEmpty = function() { + return [Infinity, Infinity, -Infinity, -Infinity]; +}; -/** @typedef {!Float64Array} */ -goog.vec.Float64; +/** + * Create a new extent or update the provided extent. + * @param {number} minX Minimum X. + * @param {number} minY Minimum Y. + * @param {number} maxX Maximum X. + * @param {number} maxY Maximum Y. + * @param {ol.Extent=} opt_extent Destination extent. + * @return {ol.Extent} Extent. + */ +ol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) { + if (opt_extent) { + opt_extent[0] = minX; + opt_extent[1] = minY; + opt_extent[2] = maxX; + opt_extent[3] = maxY; + return opt_extent; + } else { + return [minX, minY, maxX, maxY]; + } +}; -/** @typedef {!Array<number>} */ -goog.vec.Number; +/** + * Create a new empty extent or make the provided one empty. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. + */ +ol.extent.createOrUpdateEmpty = function(opt_extent) { + return ol.extent.createOrUpdate( + Infinity, Infinity, -Infinity, -Infinity, opt_extent); +}; -/** @typedef {!goog.vec.Float32|!goog.vec.Float64|!goog.vec.Number} */ -goog.vec.AnyType; +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. + */ +ol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) { + var x = coordinate[0]; + var y = coordinate[1]; + return ol.extent.createOrUpdate(x, y, x, y, opt_extent); +}; /** - * @deprecated Use AnyType. - * @typedef {!Float32Array|!Array<number>} + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. */ -goog.vec.ArrayType; +ol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) { + var extent = ol.extent.createOrUpdateEmpty(opt_extent); + return ol.extent.extendCoordinates(extent, coordinates); +}; /** - * For graphics work, 6 decimal places of accuracy are typically all that is - * required. - * - * @type {number} - * @const + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. */ -goog.vec.EPSILON = 1e-6; - -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +ol.extent.createOrUpdateFromFlatCoordinates = + function(flatCoordinates, offset, end, stride, opt_extent) { + var extent = ol.extent.createOrUpdateEmpty(opt_extent); + return ol.extent.extendFlatCoordinates( + extent, flatCoordinates, offset, end, stride); +}; /** - * @fileoverview Supplies 3 element vectors that are compatible with WebGL. - * Each element is a float32 since that is typically the desired size of a - * 3-vector in the GPU. The API is structured to avoid unnecessary memory - * allocations. The last parameter will typically be the output vector and - * an object can be both an input and output parameter to all methods except - * where noted. - * + * @param {Array.<Array.<ol.Coordinate>>} rings Rings. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. */ -goog.provide('goog.vec.Vec3'); - -/** @suppress {extraRequire} */ -goog.require('goog.vec'); +ol.extent.createOrUpdateFromRings = function(rings, opt_extent) { + var extent = ol.extent.createOrUpdateEmpty(opt_extent); + return ol.extent.extendRings(extent, rings); +}; -/** @typedef {goog.vec.Float32} */ goog.vec.Vec3.Float32; -/** @typedef {goog.vec.Float64} */ goog.vec.Vec3.Float64; -/** @typedef {goog.vec.Number} */ goog.vec.Vec3.Number; -/** @typedef {goog.vec.AnyType} */ goog.vec.Vec3.AnyType; -// The following two types are deprecated - use the above types instead. -/** @typedef {Float32Array} */ goog.vec.Vec3.Type; -/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec3.Vec3Like; +/** + * Empty an extent in place. + * @param {ol.Extent} extent Extent. + * @return {ol.Extent} Extent. + */ +ol.extent.empty = function(extent) { + extent[0] = extent[1] = Infinity; + extent[2] = extent[3] = -Infinity; + return extent; +}; /** - * Creates a 3 element vector of Float32. The array is initialized to zero. - * - * @return {!goog.vec.Vec3.Float32} The new 3 element array. + * Determine if two extents are equivalent. + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent 2. + * @return {boolean} The two extents are equivalent. + * @api stable */ -goog.vec.Vec3.createFloat32 = function() { - return new Float32Array(3); +ol.extent.equals = function(extent1, extent2) { + return extent1[0] == extent2[0] && extent1[2] == extent2[2] && + extent1[1] == extent2[1] && extent1[3] == extent2[3]; }; /** - * Creates a 3 element vector of Float64. The array is initialized to zero. - * - * @return {!goog.vec.Vec3.Float64} The new 3 element array. + * Modify an extent to include another extent. + * @param {ol.Extent} extent1 The extent to be modified. + * @param {ol.Extent} extent2 The extent that will be included in the first. + * @return {ol.Extent} A reference to the first (extended) extent. + * @api stable */ -goog.vec.Vec3.createFloat64 = function() { - return new Float64Array(3); +ol.extent.extend = function(extent1, extent2) { + if (extent2[0] < extent1[0]) { + extent1[0] = extent2[0]; + } + if (extent2[2] > extent1[2]) { + extent1[2] = extent2[2]; + } + if (extent2[1] < extent1[1]) { + extent1[1] = extent2[1]; + } + if (extent2[3] > extent1[3]) { + extent1[3] = extent2[3]; + } + return extent1; }; /** - * Creates a 3 element vector of Number. The array is initialized to zero. - * - * @return {!goog.vec.Vec3.Number} The new 3 element array. + * @param {ol.Extent} extent Extent. + * @param {ol.Coordinate} coordinate Coordinate. */ -goog.vec.Vec3.createNumber = function() { - var a = new Array(3); - goog.vec.Vec3.setFromValues(a, 0, 0, 0); - return a; +ol.extent.extendCoordinate = function(extent, coordinate) { + if (coordinate[0] < extent[0]) { + extent[0] = coordinate[0]; + } + if (coordinate[0] > extent[2]) { + extent[2] = coordinate[0]; + } + if (coordinate[1] < extent[1]) { + extent[1] = coordinate[1]; + } + if (coordinate[1] > extent[3]) { + extent[3] = coordinate[1]; + } }; /** - * Creates a 3 element vector of Float32Array. The array is initialized to zero. - * - * @deprecated Use createFloat32. - * @return {!goog.vec.Vec3.Type} The new 3 element array. + * @param {ol.Extent} extent Extent. + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @return {ol.Extent} Extent. */ -goog.vec.Vec3.create = function() { - return new Float32Array(3); +ol.extent.extendCoordinates = function(extent, coordinates) { + var i, ii; + for (i = 0, ii = coordinates.length; i < ii; ++i) { + ol.extent.extendCoordinate(extent, coordinates[i]); + } + return extent; }; /** - * Creates a new 3 element FLoat32 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec3.AnyType} vec The source 3 element array. - * @return {!goog.vec.Vec3.Float32} The new 3 element array. + * @param {ol.Extent} extent Extent. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {ol.Extent} Extent. */ -goog.vec.Vec3.createFloat32FromArray = function(vec) { - var newVec = goog.vec.Vec3.createFloat32(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; +ol.extent.extendFlatCoordinates = + function(extent, flatCoordinates, offset, end, stride) { + for (; offset < end; offset += stride) { + ol.extent.extendXY( + extent, flatCoordinates[offset], flatCoordinates[offset + 1]); + } + return extent; }; /** - * Creates a new 3 element Float32 vector initialized with the supplied values. - * - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @return {!goog.vec.Vec3.Float32} The new vector. + * @param {ol.Extent} extent Extent. + * @param {Array.<Array.<ol.Coordinate>>} rings Rings. + * @return {ol.Extent} Extent. */ -goog.vec.Vec3.createFloat32FromValues = function(v0, v1, v2) { - var a = goog.vec.Vec3.createFloat32(); - goog.vec.Vec3.setFromValues(a, v0, v1, v2); - return a; +ol.extent.extendRings = function(extent, rings) { + var i, ii; + for (i = 0, ii = rings.length; i < ii; ++i) { + ol.extent.extendCoordinates(extent, rings[i]); + } + return extent; }; /** - * Creates a clone of the given 3 element Float32 vector. - * - * @param {goog.vec.Vec3.Float32} vec The source 3 element vector. - * @return {!goog.vec.Vec3.Float32} The new cloned vector. + * @param {ol.Extent} extent Extent. + * @param {number} x X. + * @param {number} y Y. */ -goog.vec.Vec3.cloneFloat32 = goog.vec.Vec3.createFloat32FromArray; +ol.extent.extendXY = function(extent, x, y) { + extent[0] = Math.min(extent[0], x); + extent[1] = Math.min(extent[1], y); + extent[2] = Math.max(extent[2], x); + extent[3] = Math.max(extent[3], y); +}; /** - * Creates a new 3 element Float64 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec3.AnyType} vec The source 3 element array. - * @return {!goog.vec.Vec3.Float64} The new 3 element array. + * This function calls `callback` for each corner of the extent. If the + * callback returns a truthy value the function returns that value + * immediately. Otherwise the function returns `false`. + * @param {ol.Extent} extent Extent. + * @param {function(this:T, ol.Coordinate): S} callback Callback. + * @param {T=} opt_this Value to use as `this` when executing `callback`. + * @return {S|boolean} Value. + * @template S, T */ -goog.vec.Vec3.createFloat64FromArray = function(vec) { - var newVec = goog.vec.Vec3.createFloat64(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; +ol.extent.forEachCorner = function(extent, callback, opt_this) { + var val; + val = callback.call(opt_this, ol.extent.getBottomLeft(extent)); + if (val) { + return val; + } + val = callback.call(opt_this, ol.extent.getBottomRight(extent)); + if (val) { + return val; + } + val = callback.call(opt_this, ol.extent.getTopRight(extent)); + if (val) { + return val; + } + val = callback.call(opt_this, ol.extent.getTopLeft(extent)); + if (val) { + return val; + } + return false; }; /** -* Creates a new 3 element Float64 vector initialized with the supplied values. -* -* @param {number} v0 The value for element at index 0. -* @param {number} v1 The value for element at index 1. -* @param {number} v2 The value for element at index 2. -* @return {!goog.vec.Vec3.Float64} The new vector. -*/ -goog.vec.Vec3.createFloat64FromValues = function(v0, v1, v2) { - var vec = goog.vec.Vec3.createFloat64(); - goog.vec.Vec3.setFromValues(vec, v0, v1, v2); - return vec; + * @param {ol.Extent} extent Extent. + * @return {number} Area. + */ +ol.extent.getArea = function(extent) { + var area = 0; + if (!ol.extent.isEmpty(extent)) { + area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent); + } + return area; }; /** - * Creates a clone of the given 3 element vector. - * - * @param {goog.vec.Vec3.Float64} vec The source 3 element vector. - * @return {!goog.vec.Vec3.Float64} The new cloned vector. + * Get the bottom left coordinate of an extent. + * @param {ol.Extent} extent Extent. + * @return {ol.Coordinate} Bottom left coordinate. + * @api stable */ -goog.vec.Vec3.cloneFloat64 = goog.vec.Vec3.createFloat64FromArray; +ol.extent.getBottomLeft = function(extent) { + return [extent[0], extent[1]]; +}; /** - * Creates a new 3 element vector initialized with the value from the given - * array. - * - * @deprecated Use createFloat32FromArray. - * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element array. - * @return {!goog.vec.Vec3.Type} The new 3 element array. + * Get the bottom right coordinate of an extent. + * @param {ol.Extent} extent Extent. + * @return {ol.Coordinate} Bottom right coordinate. + * @api stable */ -goog.vec.Vec3.createFromArray = function(vec) { - var newVec = goog.vec.Vec3.create(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; +ol.extent.getBottomRight = function(extent) { + return [extent[2], extent[1]]; }; /** - * Creates a new 3 element vector initialized with the supplied values. - * - * @deprecated Use createFloat32FromValues. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @return {!goog.vec.Vec3.Type} The new vector. + * Get the center coordinate of an extent. + * @param {ol.Extent} extent Extent. + * @return {ol.Coordinate} Center. + * @api stable */ -goog.vec.Vec3.createFromValues = function(v0, v1, v2) { - var vec = goog.vec.Vec3.create(); - goog.vec.Vec3.setFromValues(vec, v0, v1, v2); - return vec; +ol.extent.getCenter = function(extent) { + return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2]; }; /** - * Creates a clone of the given 3 element vector. - * - * @deprecated Use cloneFloat32. - * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element vector. - * @return {!goog.vec.Vec3.Type} The new cloned vector. + * Get a corner coordinate of an extent. + * @param {ol.Extent} extent Extent. + * @param {ol.extent.Corner} corner Corner. + * @return {ol.Coordinate} Corner coordinate. */ -goog.vec.Vec3.clone = function(vec) { - var newVec = goog.vec.Vec3.create(); - goog.vec.Vec3.setFromArray(newVec, vec); - return newVec; +ol.extent.getCorner = function(extent, corner) { + var coordinate; + if (corner === ol.extent.Corner.BOTTOM_LEFT) { + coordinate = ol.extent.getBottomLeft(extent); + } else if (corner === ol.extent.Corner.BOTTOM_RIGHT) { + coordinate = ol.extent.getBottomRight(extent); + } else if (corner === ol.extent.Corner.TOP_LEFT) { + coordinate = ol.extent.getTopLeft(extent); + } else if (corner === ol.extent.Corner.TOP_RIGHT) { + coordinate = ol.extent.getTopRight(extent); + } else { + goog.asserts.fail('Invalid corner: %s', corner); + } + goog.asserts.assert(coordinate, 'coordinate should be defined'); + return coordinate; }; /** - * Initializes the vector with the given values. - * - * @param {goog.vec.Vec3.AnyType} vec The vector to receive the values. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be - * chained together. + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent 2. + * @return {number} Enlarged area. */ -goog.vec.Vec3.setFromValues = function(vec, v0, v1, v2) { - vec[0] = v0; - vec[1] = v1; - vec[2] = v2; - return vec; +ol.extent.getEnlargedArea = function(extent1, extent2) { + var minX = Math.min(extent1[0], extent2[0]); + var minY = Math.min(extent1[1], extent2[1]); + var maxX = Math.max(extent1[2], extent2[2]); + var maxY = Math.max(extent1[3], extent2[3]); + return (maxX - minX) * (maxY - minY); }; /** - * Initializes the vector with the given array of values. - * - * @param {goog.vec.Vec3.AnyType} vec The vector to receive the - * values. - * @param {goog.vec.Vec3.AnyType} values The array of values. - * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be - * chained together. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {ol.Extent=} opt_extent Destination extent. + * @return {ol.Extent} Extent. */ -goog.vec.Vec3.setFromArray = function(vec, values) { - vec[0] = values[0]; - vec[1] = values[1]; - vec[2] = values[2]; - return vec; +ol.extent.getForViewAndSize = + function(center, resolution, rotation, size, opt_extent) { + var dx = resolution * size[0] / 2; + var dy = resolution * size[1] / 2; + var cosRotation = Math.cos(rotation); + var sinRotation = Math.sin(rotation); + /** @type {Array.<number>} */ + var xs = [-dx, -dx, dx, dx]; + /** @type {Array.<number>} */ + var ys = [-dy, dy, -dy, dy]; + var i, x, y; + for (i = 0; i < 4; ++i) { + x = xs[i]; + y = ys[i]; + xs[i] = center[0] + x * cosRotation - y * sinRotation; + ys[i] = center[1] + x * sinRotation + y * cosRotation; + } + return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); }; /** - * Performs a component-wise addition of vec0 and vec1 together storing the - * result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The first addend. - * @param {goog.vec.Vec3.AnyType} vec1 The second addend. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * Get the height of an extent. + * @param {ol.Extent} extent Extent. + * @return {number} Height. + * @api stable */ -goog.vec.Vec3.add = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] + vec1[0]; - resultVec[1] = vec0[1] + vec1[1]; - resultVec[2] = vec0[2] + vec1[2]; - return resultVec; +ol.extent.getHeight = function(extent) { + return extent[3] - extent[1]; }; /** - * Performs a component-wise subtraction of vec1 from vec0 storing the - * result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The minuend. - * @param {goog.vec.Vec3.AnyType} vec1 The subtrahend. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent 2. + * @return {number} Intersection area. */ -goog.vec.Vec3.subtract = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] - vec1[0]; - resultVec[1] = vec0[1] - vec1[1]; - resultVec[2] = vec0[2] - vec1[2]; - return resultVec; +ol.extent.getIntersectionArea = function(extent1, extent2) { + var intersection = ol.extent.getIntersection(extent1, extent2); + return ol.extent.getArea(intersection); }; /** - * Negates vec0, storing the result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector to negate. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * Get the intersection of two extents. + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent 2. + * @param {ol.Extent=} opt_extent Optional extent to populate with intersection. + * @return {ol.Extent} Intersecting extent. + * @api stable */ -goog.vec.Vec3.negate = function(vec0, resultVec) { - resultVec[0] = -vec0[0]; - resultVec[1] = -vec0[1]; - resultVec[2] = -vec0[2]; - return resultVec; +ol.extent.getIntersection = function(extent1, extent2, opt_extent) { + var intersection = opt_extent ? opt_extent : ol.extent.createEmpty(); + if (ol.extent.intersects(extent1, extent2)) { + if (extent1[0] > extent2[0]) { + intersection[0] = extent1[0]; + } else { + intersection[0] = extent2[0]; + } + if (extent1[1] > extent2[1]) { + intersection[1] = extent1[1]; + } else { + intersection[1] = extent2[1]; + } + if (extent1[2] < extent2[2]) { + intersection[2] = extent1[2]; + } else { + intersection[2] = extent2[2]; + } + if (extent1[3] < extent2[3]) { + intersection[3] = extent1[3]; + } else { + intersection[3] = extent2[3]; + } + } + return intersection; }; /** - * Takes the absolute value of each component of vec0 storing the result in - * resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the result. - * May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * @param {ol.Extent} extent Extent. + * @return {number} Margin. */ -goog.vec.Vec3.abs = function(vec0, resultVec) { - resultVec[0] = Math.abs(vec0[0]); - resultVec[1] = Math.abs(vec0[1]); - resultVec[2] = Math.abs(vec0[2]); - return resultVec; +ol.extent.getMargin = function(extent) { + return ol.extent.getWidth(extent) + ol.extent.getHeight(extent); }; /** - * Multiplies each component of vec0 with scalar storing the product into - * resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {number} scalar The value to multiply with each component of vec0. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * Get the size (width, height) of an extent. + * @param {ol.Extent} extent The extent. + * @return {ol.Size} The extent size. + * @api stable */ -goog.vec.Vec3.scale = function(vec0, scalar, resultVec) { - resultVec[0] = vec0[0] * scalar; - resultVec[1] = vec0[1] * scalar; - resultVec[2] = vec0[2] * scalar; - return resultVec; +ol.extent.getSize = function(extent) { + return [extent[2] - extent[0], extent[3] - extent[1]]; }; /** - * Returns the magnitudeSquared of the given vector. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. + * Get the top left coordinate of an extent. + * @param {ol.Extent} extent Extent. + * @return {ol.Coordinate} Top left coordinate. + * @api stable */ -goog.vec.Vec3.magnitudeSquared = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2]; - return x * x + y * y + z * z; +ol.extent.getTopLeft = function(extent) { + return [extent[0], extent[3]]; }; /** - * Returns the magnitude of the given vector. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. + * Get the top right coordinate of an extent. + * @param {ol.Extent} extent Extent. + * @return {ol.Coordinate} Top right coordinate. + * @api stable */ -goog.vec.Vec3.magnitude = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2]; - return Math.sqrt(x * x + y * y + z * z); +ol.extent.getTopRight = function(extent) { + return [extent[2], extent[3]]; }; /** - * Normalizes the given vector storing the result into resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The vector to normalize. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * Get the width of an extent. + * @param {ol.Extent} extent Extent. + * @return {number} Width. + * @api stable */ -goog.vec.Vec3.normalize = function(vec0, resultVec) { - var ilen = 1 / goog.vec.Vec3.magnitude(vec0); - resultVec[0] = vec0[0] * ilen; - resultVec[1] = vec0[1] * ilen; - resultVec[2] = vec0[2] * ilen; - return resultVec; +ol.extent.getWidth = function(extent) { + return extent[2] - extent[0]; }; /** - * Returns the scalar product of vectors v0 and v1. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @return {number} The scalar product. + * Determine if one extent intersects another. + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent. + * @return {boolean} The two extents intersect. + * @api stable */ -goog.vec.Vec3.dot = function(v0, v1) { - return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]; +ol.extent.intersects = function(extent1, extent2) { + return extent1[0] <= extent2[2] && + extent1[2] >= extent2[0] && + extent1[1] <= extent2[3] && + extent1[3] >= extent2[1]; }; /** - * Computes the vector (cross) product of v0 and v1 storing the result into - * resultVec. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results. May be either v0 or v1. - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * Determine if an extent is empty. + * @param {ol.Extent} extent Extent. + * @return {boolean} Is empty. + * @api stable */ -goog.vec.Vec3.cross = function(v0, v1, resultVec) { - var x0 = v0[0], y0 = v0[1], z0 = v0[2]; - var x1 = v1[0], y1 = v1[1], z1 = v1[2]; - resultVec[0] = y0 * z1 - z0 * y1; - resultVec[1] = z0 * x1 - x0 * z1; - resultVec[2] = x0 * y1 - y0 * x1; - return resultVec; +ol.extent.isEmpty = function(extent) { + return extent[2] < extent[0] || extent[3] < extent[1]; }; /** - * Returns the squared distance between two points. - * - * @param {goog.vec.Vec3.AnyType} vec0 First point. - * @param {goog.vec.Vec3.AnyType} vec1 Second point. - * @return {number} The squared distance between the points. + * @param {ol.Extent} extent Extent. + * @return {boolean} Is infinite. */ -goog.vec.Vec3.distanceSquared = function(vec0, vec1) { - var x = vec0[0] - vec1[0]; - var y = vec0[1] - vec1[1]; - var z = vec0[2] - vec1[2]; - return x * x + y * y + z * z; +ol.extent.isInfinite = function(extent) { + return extent[0] == -Infinity || extent[1] == -Infinity || + extent[2] == Infinity || extent[3] == Infinity; }; /** - * Returns the distance between two points. - * - * @param {goog.vec.Vec3.AnyType} vec0 First point. - * @param {goog.vec.Vec3.AnyType} vec1 Second point. - * @return {number} The distance between the points. + * @param {ol.Extent} extent Extent. + * @param {ol.Coordinate} coordinate Coordinate. + * @return {ol.Coordinate} Coordinate. */ -goog.vec.Vec3.distance = function(vec0, vec1) { - return Math.sqrt(goog.vec.Vec3.distanceSquared(vec0, vec1)); +ol.extent.normalize = function(extent, coordinate) { + return [ + (coordinate[0] - extent[0]) / (extent[2] - extent[0]), + (coordinate[1] - extent[1]) / (extent[3] - extent[1]) + ]; }; /** - * Returns a unit vector pointing from one point to another. - * If the input points are equal then the result will be all zeros. - * - * @param {goog.vec.Vec3.AnyType} vec0 Origin point. - * @param {goog.vec.Vec3.AnyType} vec1 Target point. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be vec0 or vec1). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * @param {ol.Extent} extent Extent. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} Extent. */ -goog.vec.Vec3.direction = function(vec0, vec1, resultVec) { - var x = vec1[0] - vec0[0]; - var y = vec1[1] - vec0[1]; - var z = vec1[2] - vec0[2]; - var d = Math.sqrt(x * x + y * y + z * z); - if (d) { - d = 1 / d; - resultVec[0] = x * d; - resultVec[1] = y * d; - resultVec[2] = z * d; +ol.extent.returnOrUpdate = function(extent, opt_extent) { + if (opt_extent) { + opt_extent[0] = extent[0]; + opt_extent[1] = extent[1]; + opt_extent[2] = extent[2]; + opt_extent[3] = extent[3]; + return opt_extent; } else { - resultVec[0] = resultVec[1] = resultVec[2] = 0; + return extent; } - return resultVec; }; /** - * Linearly interpolate from vec0 to v1 according to f. The value of f should be - * in the range [0..1] otherwise the results are undefined. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @param {number} f The interpolation factor. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be v0 or v1). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * @param {ol.Extent} extent Extent. + * @param {number} value Value. */ -goog.vec.Vec3.lerp = function(v0, v1, f, resultVec) { - var x = v0[0], y = v0[1], z = v0[2]; - resultVec[0] = (v1[0] - x) * f + x; - resultVec[1] = (v1[1] - y) * f + y; - resultVec[2] = (v1[2] - z) * f + z; - return resultVec; +ol.extent.scaleFromCenter = function(extent, value) { + var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1); + var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1); + extent[0] -= deltaX; + extent[2] += deltaX; + extent[1] -= deltaY; + extent[3] += deltaY; }; /** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the larger values in resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * Determine if the segment between two coordinates intersects (crosses, + * touches, or is contained by) the provided extent. + * @param {ol.Extent} extent The extent. + * @param {ol.Coordinate} start Segment start coordinate. + * @param {ol.Coordinate} end Segment end coordinate. + * @return {boolean} The segment intersects the extent. */ -goog.vec.Vec3.max = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.max(vec0[0], limit); - resultVec[1] = Math.max(vec0[1], limit); - resultVec[2] = Math.max(vec0[2], limit); +ol.extent.intersectsSegment = function(extent, start, end) { + var intersects = false; + var startRel = ol.extent.coordinateRelationship(extent, start); + var endRel = ol.extent.coordinateRelationship(extent, end); + if (startRel === ol.extent.Relationship.INTERSECTING || + endRel === ol.extent.Relationship.INTERSECTING) { + intersects = true; } else { - resultVec[0] = Math.max(vec0[0], limit[0]); - resultVec[1] = Math.max(vec0[1], limit[1]); - resultVec[2] = Math.max(vec0[2], limit[2]); + var minX = extent[0]; + var minY = extent[1]; + var maxX = extent[2]; + var maxY = extent[3]; + var startX = start[0]; + var startY = start[1]; + var endX = end[0]; + var endY = end[1]; + var slope = (endY - startY) / (endX - startX); + var x, y; + if (!!(endRel & ol.extent.Relationship.ABOVE) && + !(startRel & ol.extent.Relationship.ABOVE)) { + // potentially intersects top + x = endX - ((endY - maxY) / slope); + intersects = x >= minX && x <= maxX; + } + if (!intersects && !!(endRel & ol.extent.Relationship.RIGHT) && + !(startRel & ol.extent.Relationship.RIGHT)) { + // potentially intersects right + y = endY - ((endX - maxX) * slope); + intersects = y >= minY && y <= maxY; + } + if (!intersects && !!(endRel & ol.extent.Relationship.BELOW) && + !(startRel & ol.extent.Relationship.BELOW)) { + // potentially intersects bottom + x = endX - ((endY - minY) / slope); + intersects = x >= minX && x <= maxX; + } + if (!intersects && !!(endRel & ol.extent.Relationship.LEFT) && + !(startRel & ol.extent.Relationship.LEFT)) { + // potentially intersects left + y = endY - ((endX - minX) * slope); + intersects = y >= minY && y <= maxY; + } + } - return resultVec; + return intersects; }; /** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the smaller values in resultVec. - * - * @param {goog.vec.Vec3.AnyType} vec0 The source vector. - * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be - * chained together. + * @param {ol.Extent} extent1 Extent 1. + * @param {ol.Extent} extent2 Extent 2. + * @return {boolean} Touches. */ -goog.vec.Vec3.min = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.min(vec0[0], limit); - resultVec[1] = Math.min(vec0[1], limit); - resultVec[2] = Math.min(vec0[2], limit); - } else { - resultVec[0] = Math.min(vec0[0], limit[0]); - resultVec[1] = Math.min(vec0[1], limit[1]); - resultVec[2] = Math.min(vec0[2], limit[2]); - } - return resultVec; +ol.extent.touches = function(extent1, extent2) { + var intersects = ol.extent.intersects(extent1, extent2); + return intersects && + (extent1[0] == extent2[2] || extent1[2] == extent2[0] || + extent1[1] == extent2[3] || extent1[3] == extent2[1]); }; /** - * Returns true if the components of v0 are equal to the components of v1. - * - * @param {goog.vec.Vec3.AnyType} v0 The first vector. - * @param {goog.vec.Vec3.AnyType} v1 The second vector. - * @return {boolean} True if the vectors are equal, false otherwise. + * Apply a transform function to the extent. + * @param {ol.Extent} extent Extent. + * @param {ol.TransformFunction} transformFn Transform function. Called with + * [minX, minY, maxX, maxY] extent coordinates. + * @param {ol.Extent=} opt_extent Destination extent. + * @return {ol.Extent} Extent. + * @api stable */ -goog.vec.Vec3.equals = function(v0, v1) { - return v0.length == v1.length && - v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2]; +ol.extent.applyTransform = function(extent, transformFn, opt_extent) { + var coordinates = [ + extent[0], extent[1], + extent[0], extent[3], + extent[2], extent[1], + extent[2], extent[3] + ]; + transformFn(coordinates, coordinates, 2); + var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]]; + var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]]; + return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); }; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - /** - * @fileoverview Supplies 4 element vectors that are compatible with WebGL. - * Each element is a float32 since that is typically the desired size of a - * 4-vector in the GPU. The API is structured to avoid unnecessary memory - * allocations. The last parameter will typically be the output vector and - * an object can be both an input and output parameter to all methods except - * where noted. - * + * Apply a 2d transform to an extent. + * @param {ol.Extent} extent Input extent. + * @param {goog.vec.Mat4.Number} transform The transform matrix. + * @param {ol.Extent=} opt_extent Optional extent for return values. + * @return {ol.Extent} The transformed extent. */ -goog.provide('goog.vec.Vec4'); +ol.extent.transform2D = function(extent, transform, opt_extent) { + var dest = opt_extent ? opt_extent : []; + var m00 = goog.vec.Mat4.getElement(transform, 0, 0); + var m10 = goog.vec.Mat4.getElement(transform, 1, 0); + var m01 = goog.vec.Mat4.getElement(transform, 0, 1); + var m11 = goog.vec.Mat4.getElement(transform, 1, 1); + var m03 = goog.vec.Mat4.getElement(transform, 0, 3); + var m13 = goog.vec.Mat4.getElement(transform, 1, 3); + var xi = [0, 2, 0, 2]; + var yi = [1, 1, 3, 3]; + var xs = []; + var ys = []; + var i, x, y; + for (i = 0; i < 4; ++i) { + x = extent[xi[i]]; + y = extent[yi[i]]; + xs[i] = m00 * x + m01 * y + m03; + ys[i] = m10 * x + m11 * y + m13; + } + dest[0] = Math.min.apply(null, xs); + dest[1] = Math.min.apply(null, ys); + dest[2] = Math.max.apply(null, xs); + dest[3] = Math.max.apply(null, ys); + return dest; +}; -/** @suppress {extraRequire} */ -goog.require('goog.vec'); +goog.provide('ol'); -/** @typedef {goog.vec.Float32} */ goog.vec.Vec4.Float32; -/** @typedef {goog.vec.Float64} */ goog.vec.Vec4.Float64; -/** @typedef {goog.vec.Number} */ goog.vec.Vec4.Number; -/** @typedef {goog.vec.AnyType} */ goog.vec.Vec4.AnyType; -// The following two types are deprecated - use the above types instead. -/** @typedef {Float32Array} */ goog.vec.Vec4.Type; -/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec4.Vec4Like; +/** + * Constants defined with the define tag cannot be changed in application + * code, but can be set at compile time. + * Some reduce the size of the build in advanced compile mode. + */ /** - * Creates a 4 element vector of Float32. The array is initialized to zero. - * - * @return {!goog.vec.Vec4.Float32} The new 3 element array. + * @define {boolean} Assume touch. Default is `false`. */ -goog.vec.Vec4.createFloat32 = function() { - return new Float32Array(4); -}; +ol.ASSUME_TOUCH = false; /** - * Creates a 4 element vector of Float64. The array is initialized to zero. - * - * @return {!goog.vec.Vec4.Float64} The new 4 element array. + * TODO: rename this to something having to do with tile grids + * see https://github.com/openlayers/ol3/issues/2076 + * @define {number} Default maximum zoom for default tile grids. */ -goog.vec.Vec4.createFloat64 = function() { - return new Float64Array(4); -}; +ol.DEFAULT_MAX_ZOOM = 42; /** - * Creates a 4 element vector of Number. The array is initialized to zero. - * - * @return {!goog.vec.Vec4.Number} The new 4 element array. + * @define {number} Default min zoom level for the map view. Default is `0`. */ -goog.vec.Vec4.createNumber = function() { - var v = new Array(4); - goog.vec.Vec4.setFromValues(v, 0, 0, 0, 0); - return v; -}; +ol.DEFAULT_MIN_ZOOM = 0; /** - * Creates a 4 element vector of Float32Array. The array is initialized to zero. - * - * @deprecated Use createFloat32. - * @return {!goog.vec.Vec4.Type} The new 4 element array. + * @define {number} Default maximum allowed threshold (in pixels) for + * reprojection triangulation. Default is `0.5`. */ -goog.vec.Vec4.create = function() { - return new Float32Array(4); -}; +ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD = 0.5; /** - * Creates a new 4 element vector initialized with the value from the given - * array. - * - * @deprecated Use createFloat32FromArray. - * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element array. - * @return {!goog.vec.Vec4.Type} The new 4 element array. + * @define {number} Default high water mark. */ -goog.vec.Vec4.createFromArray = function(vec) { - var newVec = goog.vec.Vec4.create(); - goog.vec.Vec4.setFromArray(newVec, vec); - return newVec; -}; +ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK = 2048; /** - * Creates a new 4 element FLoat32 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec4.AnyType} vec The source 3 element array. - * @return {!goog.vec.Vec4.Float32} The new 3 element array. + * @define {number} Default tile size. */ -goog.vec.Vec4.createFloat32FromArray = function(vec) { - var newVec = goog.vec.Vec4.createFloat32(); - goog.vec.Vec4.setFromArray(newVec, vec); - return newVec; -}; +ol.DEFAULT_TILE_SIZE = 256; /** - * Creates a new 4 element Float32 vector initialized with the supplied values. - * - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @param {number} v3 The value for element at index 3. - * @return {!goog.vec.Vec4.Float32} The new vector. + * @define {string} Default WMS version. */ -goog.vec.Vec4.createFloat32FromValues = function(v0, v1, v2, v3) { - var vec = goog.vec.Vec4.createFloat32(); - goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); - return vec; -}; +ol.DEFAULT_WMS_VERSION = '1.3.0'; /** - * Creates a clone of the given 4 element Float32 vector. - * - * @param {goog.vec.Vec4.Float32} vec The source 3 element vector. - * @return {!goog.vec.Vec4.Float32} The new cloned vector. + * @define {number} Hysteresis pixels. */ -goog.vec.Vec4.cloneFloat32 = goog.vec.Vec4.createFloat32FromArray; +ol.DRAG_BOX_HYSTERESIS_PIXELS = 8; /** - * Creates a new 4 element Float64 vector initialized with the value from the - * given array. - * - * @param {goog.vec.Vec4.AnyType} vec The source 4 element array. - * @return {!goog.vec.Vec4.Float64} The new 4 element array. + * @define {boolean} Enable the Canvas renderer. Default is `true`. Setting + * this to false at compile time in advanced mode removes all code + * supporting the Canvas renderer from the build. */ -goog.vec.Vec4.createFloat64FromArray = function(vec) { - var newVec = goog.vec.Vec4.createFloat64(); - goog.vec.Vec4.setFromArray(newVec, vec); - return newVec; -}; +ol.ENABLE_CANVAS = true; /** -* Creates a new 4 element Float64 vector initialized with the supplied values. -* -* @param {number} v0 The value for element at index 0. -* @param {number} v1 The value for element at index 1. -* @param {number} v2 The value for element at index 2. -* @param {number} v3 The value for element at index 3. -* @return {!goog.vec.Vec4.Float64} The new vector. -*/ -goog.vec.Vec4.createFloat64FromValues = function(v0, v1, v2, v3) { - var vec = goog.vec.Vec4.createFloat64(); - goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); - return vec; -}; + * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is + * not available). Default is `true`. Setting this to false at compile time + * in advanced mode removes all code supporting the DOM renderer from the + * build. + */ +ol.ENABLE_DOM = true; /** - * Creates a clone of the given 4 element vector. - * - * @param {goog.vec.Vec4.Float64} vec The source 4 element vector. - * @return {!goog.vec.Vec4.Float64} The new cloned vector. + * @define {boolean} Enable rendering of ol.layer.Image based layers. Default + * is `true`. Setting this to false at compile time in advanced mode removes + * all code supporting Image layers from the build. */ -goog.vec.Vec4.cloneFloat64 = goog.vec.Vec4.createFloat64FromArray; +ol.ENABLE_IMAGE = true; /** - * Creates a new 4 element vector initialized with the supplied values. - * - * @deprecated Use createFloat32FromValues. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @param {number} v3 The value for element at index 3. - * @return {!goog.vec.Vec4.Type} The new vector. + * @define {boolean} Enable Closure named colors (`goog.color.names`). + * Enabling these colors adds about 3KB uncompressed / 1.5KB compressed to + * the final build size. Default is `false`. This setting has no effect + * with Canvas renderer, which uses its own names, whether this is true or + * false. */ -goog.vec.Vec4.createFromValues = function(v0, v1, v2, v3) { - var vec = goog.vec.Vec4.create(); - goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3); - return vec; -}; +ol.ENABLE_NAMED_COLORS = false; /** - * Creates a clone of the given 4 element vector. - * - * @deprecated Use cloneFloat32. - * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element vector. - * @return {!goog.vec.Vec4.Type} The new cloned vector. + * @define {boolean} Enable integration with the Proj4js library. Default is + * `true`. */ -goog.vec.Vec4.clone = goog.vec.Vec4.createFromArray; +ol.ENABLE_PROJ4JS = true; /** - * Initializes the vector with the given values. - * - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values. - * @param {number} v0 The value for element at index 0. - * @param {number} v1 The value for element at index 1. - * @param {number} v2 The value for element at index 2. - * @param {number} v3 The value for element at index 3. - * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be - * chained together. + * @define {boolean} Enable automatic reprojection of raster sources. Default is + * `true`. */ -goog.vec.Vec4.setFromValues = function(vec, v0, v1, v2, v3) { - vec[0] = v0; - vec[1] = v1; - vec[2] = v2; - vec[3] = v3; - return vec; -}; +ol.ENABLE_RASTER_REPROJECTION = true; /** - * Initializes the vector with the given array of values. - * - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the - * values. - * @param {goog.vec.Vec4.AnyType} values The array of values. - * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be - * chained together. + * @define {boolean} Enable rendering of ol.layer.Tile based layers. Default is + * `true`. Setting this to false at compile time in advanced mode removes + * all code supporting Tile layers from the build. */ -goog.vec.Vec4.setFromArray = function(vec, values) { - vec[0] = values[0]; - vec[1] = values[1]; - vec[2] = values[2]; - vec[3] = values[3]; - return vec; -}; +ol.ENABLE_TILE = true; /** - * Performs a component-wise addition of vec0 and vec1 together storing the - * result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The first addend. - * @param {goog.vec.Vec4.AnyType} vec1 The second addend. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {boolean} Enable rendering of ol.layer.Vector based layers. Default + * is `true`. Setting this to false at compile time in advanced mode removes + * all code supporting Vector layers from the build. */ -goog.vec.Vec4.add = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] + vec1[0]; - resultVec[1] = vec0[1] + vec1[1]; - resultVec[2] = vec0[2] + vec1[2]; - resultVec[3] = vec0[3] + vec1[3]; - return resultVec; -}; +ol.ENABLE_VECTOR = true; /** - * Performs a component-wise subtraction of vec1 from vec0 storing the - * result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The minuend. - * @param {goog.vec.Vec4.AnyType} vec1 The subtrahend. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0 or vec1. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {boolean} Enable rendering of ol.layer.VectorTile based layers. + * Default is `true`. Setting this to false at compile time in advanced mode + * removes all code supporting VectorTile layers from the build. */ -goog.vec.Vec4.subtract = function(vec0, vec1, resultVec) { - resultVec[0] = vec0[0] - vec1[0]; - resultVec[1] = vec0[1] - vec1[1]; - resultVec[2] = vec0[2] - vec1[2]; - resultVec[3] = vec0[3] - vec1[3]; - return resultVec; -}; +ol.ENABLE_VECTOR_TILE = true; /** - * Negates vec0, storing the result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector to negate. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {boolean} Enable the WebGL renderer. Default is `true`. Setting + * this to false at compile time in advanced mode removes all code + * supporting the WebGL renderer from the build. */ -goog.vec.Vec4.negate = function(vec0, resultVec) { - resultVec[0] = -vec0[0]; - resultVec[1] = -vec0[1]; - resultVec[2] = -vec0[2]; - resultVec[3] = -vec0[3]; - return resultVec; -}; +ol.ENABLE_WEBGL = true; /** - * Takes the absolute value of each component of vec0 storing the result in - * resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the result. - * May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {number} The size in pixels of the first atlas image. Default is + * `256`. */ -goog.vec.Vec4.abs = function(vec0, resultVec) { - resultVec[0] = Math.abs(vec0[0]); - resultVec[1] = Math.abs(vec0[1]); - resultVec[2] = Math.abs(vec0[2]); - resultVec[3] = Math.abs(vec0[3]); - return resultVec; -}; +ol.INITIAL_ATLAS_SIZE = 256; /** - * Multiplies each component of vec0 with scalar storing the product into - * resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {number} scalar The value to multiply with each component of vec0. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {number} The maximum size in pixels of atlas images. Default is + * `-1`, meaning it is not used (and `ol.WEBGL_MAX_TEXTURE_SIZE` is + * used instead). */ -goog.vec.Vec4.scale = function(vec0, scalar, resultVec) { - resultVec[0] = vec0[0] * scalar; - resultVec[1] = vec0[1] * scalar; - resultVec[2] = vec0[2] * scalar; - resultVec[3] = vec0[3] * scalar; - return resultVec; -}; +ol.MAX_ATLAS_SIZE = -1; /** - * Returns the magnitudeSquared of the given vector. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. + * @define {number} Maximum mouse wheel delta. */ -goog.vec.Vec4.magnitudeSquared = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3]; - return x * x + y * y + z * z + w * w; -}; +ol.MOUSEWHEELZOOM_MAXDELTA = 1; /** - * Returns the magnitude of the given vector. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector. - * @return {number} The magnitude of the vector. + * @define {number} Mouse wheel timeout duration. */ -goog.vec.Vec4.magnitude = function(vec0) { - var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3]; - return Math.sqrt(x * x + y * y + z * z + w * w); -}; +ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80; /** - * Normalizes the given vector storing the result into resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The vector to normalize. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the result. May be vec0. - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {number} Maximum width and/or height extent ratio that determines + * when the overview map should be zoomed out. */ -goog.vec.Vec4.normalize = function(vec0, resultVec) { - var ilen = 1 / goog.vec.Vec4.magnitude(vec0); - resultVec[0] = vec0[0] * ilen; - resultVec[1] = vec0[1] * ilen; - resultVec[2] = vec0[2] * ilen; - resultVec[3] = vec0[3] * ilen; - return resultVec; -}; +ol.OVERVIEWMAP_MAX_RATIO = 0.75; /** - * Returns the scalar product of vectors v0 and v1. - * - * @param {goog.vec.Vec4.AnyType} v0 The first vector. - * @param {goog.vec.Vec4.AnyType} v1 The second vector. - * @return {number} The scalar product. + * @define {number} Minimum width and/or height extent ratio that determines + * when the overview map should be zoomed in. */ -goog.vec.Vec4.dot = function(v0, v1) { - return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2] + v0[3] * v1[3]; -}; +ol.OVERVIEWMAP_MIN_RATIO = 0.1; /** - * Linearly interpolate from v0 to v1 according to f. The value of f should be - * in the range [0..1] otherwise the results are undefined. - * - * @param {goog.vec.Vec4.AnyType} v0 The first vector. - * @param {goog.vec.Vec4.AnyType} v1 The second vector. - * @param {number} f The interpolation factor. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the - * results (may be v0 or v1). - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {number} Maximum number of source tiles for raster reprojection of + * a single tile. + * If too many source tiles are determined to be loaded to create a single + * reprojected tile the browser can become unresponsive or even crash. + * This can happen if the developer defines projections improperly and/or + * with unlimited extents. + * If too many tiles are required, no tiles are loaded and + * `ol.TileState.ERROR` state is set. Default is `100`. */ -goog.vec.Vec4.lerp = function(v0, v1, f, resultVec) { - var x = v0[0], y = v0[1], z = v0[2], w = v0[3]; - resultVec[0] = (v1[0] - x) * f + x; - resultVec[1] = (v1[1] - y) * f + y; - resultVec[2] = (v1[2] - z) * f + z; - resultVec[3] = (v1[3] - w) * f + w; - return resultVec; -}; +ol.RASTER_REPROJECTION_MAX_SOURCE_TILES = 100; /** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the larger values in resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {number} Maximum number of subdivision steps during raster + * reprojection triangulation. Prevents high memory usage and large + * number of proj4 calls (for certain transformations and areas). + * At most `2*(2^this)` triangles are created for each triangulated + * extent (tile/image). Default is `10`. */ -goog.vec.Vec4.max = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.max(vec0[0], limit); - resultVec[1] = Math.max(vec0[1], limit); - resultVec[2] = Math.max(vec0[2], limit); - resultVec[3] = Math.max(vec0[3], limit); - } else { - resultVec[0] = Math.max(vec0[0], limit[0]); - resultVec[1] = Math.max(vec0[1], limit[1]); - resultVec[2] = Math.max(vec0[2], limit[2]); - resultVec[3] = Math.max(vec0[3], limit[3]); - } - return resultVec; -}; +ol.RASTER_REPROJECTION_MAX_SUBDIVISION = 10; /** - * Compares the components of vec0 with the components of another vector or - * scalar, storing the smaller values in resultVec. - * - * @param {goog.vec.Vec4.AnyType} vec0 The source vector. - * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the - * results (may be vec0 or limit). - * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be - * chained together. + * @define {number} Maximum allowed size of triangle relative to world width. + * When transforming corners of world extent between certain projections, + * the resulting triangulation seems to have zero error and no subdivision + * is performed. + * If the triangle width is more than this (relative to world width; 0-1), + * subdivison is forced (up to `ol.RASTER_REPROJECTION_MAX_SUBDIVISION`). + * Default is `0.25`. */ -goog.vec.Vec4.min = function(vec0, limit, resultVec) { - if (goog.isNumber(limit)) { - resultVec[0] = Math.min(vec0[0], limit); - resultVec[1] = Math.min(vec0[1], limit); - resultVec[2] = Math.min(vec0[2], limit); - resultVec[3] = Math.min(vec0[3], limit); - } else { - resultVec[0] = Math.min(vec0[0], limit[0]); - resultVec[1] = Math.min(vec0[1], limit[1]); - resultVec[2] = Math.min(vec0[2], limit[2]); - resultVec[3] = Math.min(vec0[3], limit[3]); - } - return resultVec; -}; +ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH = 0.25; /** - * Returns true if the components of v0 are equal to the components of v1. - * - * @param {goog.vec.Vec4.AnyType} v0 The first vector. - * @param {goog.vec.Vec4.AnyType} v1 The second vector. - * @return {boolean} True if the vectors are equal, false otherwise. + * @define {number} Tolerance for geometry simplification in device pixels. */ -goog.vec.Vec4.equals = function(v0, v1) { - return v0.length == v1.length && - v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2] && v0[3] == v1[3]; -}; +ol.SIMPLIFY_TOLERANCE = 0.5; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Implements 4x4 matrices and their related functions which are - * compatible with WebGL. The API is structured to avoid unnecessary memory - * allocations. The last parameter will typically be the output vector and - * an object can be both an input and output parameter to all methods except - * where noted. Matrix operations follow the mathematical form when multiplying - * vectors as follows: resultVec = matrix * vec. - * - * The matrices are stored in column-major order. - * + * @define {number} Texture cache high water mark. */ -goog.provide('goog.vec.Mat4'); - -goog.require('goog.vec'); -goog.require('goog.vec.Vec3'); -goog.require('goog.vec.Vec4'); - +ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024; -/** @typedef {goog.vec.Float32} */ goog.vec.Mat4.Float32; -/** @typedef {goog.vec.Float64} */ goog.vec.Mat4.Float64; -/** @typedef {goog.vec.Number} */ goog.vec.Mat4.Number; -/** @typedef {goog.vec.AnyType} */ goog.vec.Mat4.AnyType; -// The following two types are deprecated - use the above types instead. -/** @typedef {!Float32Array} */ goog.vec.Mat4.Type; -/** @typedef {goog.vec.ArrayType} */ goog.vec.Mat4.Mat4Like; +/** + * The maximum supported WebGL texture size in pixels. If WebGL is not + * supported, the value is set to `undefined`. + * @const + * @type {number|undefined} + */ +ol.WEBGL_MAX_TEXTURE_SIZE; // value is set in `ol.has` /** - * Creates the array representation of a 4x4 matrix of Float32. - * The use of the array directly instead of a class reduces overhead. - * The returned matrix is cleared to all zeros. - * - * @return {!goog.vec.Mat4.Float32} The new matrix. + * List of supported WebGL extensions. + * @const + * @type {Array.<string>} */ -goog.vec.Mat4.createFloat32 = function() { - return new Float32Array(16); -}; +ol.WEBGL_EXTENSIONS; // value is set in `ol.has` /** - * Creates the array representation of a 4x4 matrix of Float64. - * The returned matrix is cleared to all zeros. + * Inherit the prototype methods from one constructor into another. * - * @return {!goog.vec.Mat4.Float64} The new matrix. + * Usage: + * + * function ParentClass(a, b) { } + * ParentClass.prototype.foo = function(a) { } + * + * function ChildClass(a, b, c) { + * // Call parent constructor + * ParentClass.call(this, a, b); + * } + * ol.inherits(ChildClass, ParentClass); + * + * var child = new ChildClass('a', 'b', 'see'); + * child.foo(); // This works. + * + * In addition, a superclass' implementation of a method can be invoked as + * follows: + * + * ChildClass.prototype.foo = function(a) { + * ChildClass.base(this, 'foo', a); + * // Other code here. + * }; + * + * @param {!Function} childCtor Child constructor. + * @param {!Function} parentCtor Parent constructor. + * @function + * @api */ -goog.vec.Mat4.createFloat64 = function() { - return new Float64Array(16); -}; +ol.inherits = + goog.inherits; +// note that the newline above is necessary to satisfy the linter /** - * Creates the array representation of a 4x4 matrix of Number. - * The returned matrix is cleared to all zeros. + * A reusable function, used e.g. as a default for callbacks. * - * @return {!goog.vec.Mat4.Number} The new matrix. + * @return {undefined} Nothing. */ -goog.vec.Mat4.createNumber = function() { - var a = new Array(16); - goog.vec.Mat4.setFromValues(a, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0); - return a; -}; +ol.nullFunction = function() {}; + +goog.provide('ol.math'); + +goog.require('goog.asserts'); /** - * Creates the array representation of a 4x4 matrix of Float32. - * The returned matrix is cleared to all zeros. - * - * @deprecated Use createFloat32. - * @return {!goog.vec.Mat4.Type} The new matrix. + * Takes a number and clamps it to within the provided bounds. + * @param {number} value The input number. + * @param {number} min The minimum value to return. + * @param {number} max The maximum value to return. + * @return {number} The input number if it is within bounds, or the nearest + * number within the bounds. */ -goog.vec.Mat4.create = function() { - return goog.vec.Mat4.createFloat32(); +ol.math.clamp = function(value, min, max) { + return Math.min(Math.max(value, min), max); }; /** - * Creates a 4x4 identity matrix of Float32. + * Return the hyperbolic cosine of a given number. The method will use the + * native `Math.cosh` function if it is available, otherwise the hyperbolic + * cosine will be calculated via the reference implementation of the Mozilla + * developer network. * - * @return {!goog.vec.Mat4.Float32} The new 16 element array. + * @param {number} x X. + * @return {number} Hyperbolic cosine of x. */ -goog.vec.Mat4.createFloat32Identity = function() { - var mat = goog.vec.Mat4.createFloat32(); - mat[0] = mat[5] = mat[10] = mat[15] = 1; - return mat; -}; +ol.math.cosh = (function() { + // Wrapped in a iife, to save the overhead of checking for the native + // implementation on every invocation. + var cosh; + if ('cosh' in Math) { + // The environment supports the native Math.cosh function, use it… + cosh = Math.cosh; + } else { + // … else, use the reference implementation of MDN: + cosh = function(x) { + var y = Math.exp(x); + return (y + 1 / y) / 2; + }; + } + return cosh; +}()); /** - * Creates a 4x4 identity matrix of Float64. - * - * @return {!goog.vec.Mat4.Float64} The new 16 element array. + * @param {number} x X. + * @return {number} The smallest power of two greater than or equal to x. */ -goog.vec.Mat4.createFloat64Identity = function() { - var mat = goog.vec.Mat4.createFloat64(); - mat[0] = mat[5] = mat[10] = mat[15] = 1; - return mat; +ol.math.roundUpToPowerOfTwo = function(x) { + goog.asserts.assert(0 < x, 'x should be larger than 0'); + return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2)); }; /** - * Creates a 4x4 identity matrix of Number. - * The returned matrix is cleared to all zeros. - * - * @return {!goog.vec.Mat4.Number} The new 16 element array. + * Returns the square of the closest distance between the point (x, y) and the + * line segment (x1, y1) to (x2, y2). + * @param {number} x X. + * @param {number} y Y. + * @param {number} x1 X1. + * @param {number} y1 Y1. + * @param {number} x2 X2. + * @param {number} y2 Y2. + * @return {number} Squared distance. */ -goog.vec.Mat4.createNumberIdentity = function() { - var a = new Array(16); - goog.vec.Mat4.setFromValues(a, - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - return a; +ol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) { + var dx = x2 - x1; + var dy = y2 - y1; + if (dx !== 0 || dy !== 0) { + var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); + if (t > 1) { + x1 = x2; + y1 = y2; + } else if (t > 0) { + x1 += dx * t; + y1 += dy * t; + } + } + return ol.math.squaredDistance(x, y, x1, y1); }; /** - * Creates the array representation of a 4x4 matrix of Float32. - * The returned matrix is cleared to all zeros. - * - * @deprecated Use createFloat32Identity. - * @return {!goog.vec.Mat4.Type} The new 16 element array. + * Returns the square of the distance between the points (x1, y1) and (x2, y2). + * @param {number} x1 X1. + * @param {number} y1 Y1. + * @param {number} x2 X2. + * @param {number} y2 Y2. + * @return {number} Squared distance. */ -goog.vec.Mat4.createIdentity = function() { - return goog.vec.Mat4.createFloat32Identity(); +ol.math.squaredDistance = function(x1, y1, x2, y2) { + var dx = x2 - x1; + var dy = y2 - y1; + return dx * dx + dy * dy; }; /** - * Creates a 4x4 matrix of Float32 initialized from the given array. + * Solves system of linear equations using Gaussian elimination method. * - * @param {goog.vec.Mat4.AnyType} matrix The array containing the - * matrix values in column major order. - * @return {!goog.vec.Mat4.Float32} The new, 16 element array. + * @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column) + * in row-major order. + * @return {Array.<number>} The resulting vector. */ -goog.vec.Mat4.createFloat32FromArray = function(matrix) { - var newMatrix = goog.vec.Mat4.createFloat32(); - goog.vec.Mat4.setFromArray(newMatrix, matrix); - return newMatrix; -}; +ol.math.solveLinearSystem = function(mat) { + var n = mat.length; + if (goog.asserts.ENABLE_ASSERTS) { + for (var row = 0; row < n; row++) { + goog.asserts.assert(mat[row].length == n + 1, + 'every row should have correct number of columns'); + } + } -/** - * Creates a 4x4 matrix of Float32 initialized from the given values. - * - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {!goog.vec.Mat4.Float32} The new, 16 element array. - */ -goog.vec.Mat4.createFloat32FromValues = function( - v00, v10, v20, v30, - v01, v11, v21, v31, - v02, v12, v22, v32, - v03, v13, v23, v33) { - var newMatrix = goog.vec.Mat4.createFloat32(); - goog.vec.Mat4.setFromValues( - newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33); - return newMatrix; + for (var i = 0; i < n; i++) { + // Find max in the i-th column (ignoring i - 1 first rows) + var maxRow = i; + var maxEl = Math.abs(mat[i][i]); + for (var r = i + 1; r < n; r++) { + var absValue = Math.abs(mat[r][i]); + if (absValue > maxEl) { + maxEl = absValue; + maxRow = r; + } + } + + if (maxEl === 0) { + return null; // matrix is singular + } + + // Swap max row with i-th (current) row + var tmp = mat[maxRow]; + mat[maxRow] = mat[i]; + mat[i] = tmp; + + // Subtract the i-th row to make all the remaining rows 0 in the i-th column + for (var j = i + 1; j < n; j++) { + var coef = -mat[j][i] / mat[i][i]; + for (var k = i; k < n + 1; k++) { + if (i == k) { + mat[j][k] = 0; + } else { + mat[j][k] += coef * mat[i][k]; + } + } + } + } + + // Solve Ax=b for upper triangular matrix A (mat) + var x = new Array(n); + for (var l = n - 1; l >= 0; l--) { + x[l] = mat[l][n] / mat[l][l]; + for (var m = l - 1; m >= 0; m--) { + mat[m][n] -= mat[m][l] * x[l]; + } + } + return x; }; /** - * Creates a clone of a 4x4 matrix of Float32. + * Converts radians to to degrees. * - * @param {goog.vec.Mat4.Float32} matrix The source 4x4 matrix. - * @return {!goog.vec.Mat4.Float32} The new 4x4 element matrix. + * @param {number} angleInRadians Angle in radians. + * @return {number} Angle in degrees. */ -goog.vec.Mat4.cloneFloat32 = goog.vec.Mat4.createFloat32FromArray; +ol.math.toDegrees = function(angleInRadians) { + return angleInRadians * 180 / Math.PI; +}; /** - * Creates a 4x4 matrix of Float64 initialized from the given array. + * Converts degrees to radians. * - * @param {goog.vec.Mat4.AnyType} matrix The array containing the - * matrix values in column major order. - * @return {!goog.vec.Mat4.Float64} The new, nine element array. + * @param {number} angleInDegrees Angle in degrees. + * @return {number} Angle in radians. */ -goog.vec.Mat4.createFloat64FromArray = function(matrix) { - var newMatrix = goog.vec.Mat4.createFloat64(); - goog.vec.Mat4.setFromArray(newMatrix, matrix); - return newMatrix; +ol.math.toRadians = function(angleInDegrees) { + return angleInDegrees * Math.PI / 180; }; +goog.provide('ol.TileCoord'); +goog.provide('ol.tilecoord'); + +goog.require('goog.asserts'); +goog.require('ol.extent'); + /** - * Creates a 4x4 matrix of Float64 initialized from the given values. - * - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {!goog.vec.Mat4.Float64} The new, 16 element array. + * An array of three numbers representing the location of a tile in a tile + * grid. The order is `z`, `x`, and `y`. `z` is the zoom level. + * @typedef {Array.<number>} ol.TileCoord + * @api */ -goog.vec.Mat4.createFloat64FromValues = function( - v00, v10, v20, v30, - v01, v11, v21, v31, - v02, v12, v22, v32, - v03, v13, v23, v33) { - var newMatrix = goog.vec.Mat4.createFloat64(); - goog.vec.Mat4.setFromValues( - newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33); - return newMatrix; -}; +ol.TileCoord; /** - * Creates a clone of a 4x4 matrix of Float64. - * - * @param {goog.vec.Mat4.Float64} matrix The source 4x4 matrix. - * @return {!goog.vec.Mat4.Float64} The new 4x4 element matrix. + * @enum {number} */ -goog.vec.Mat4.cloneFloat64 = goog.vec.Mat4.createFloat64FromArray; +ol.QuadKeyCharCode = { + ZERO: '0'.charCodeAt(0), + ONE: '1'.charCodeAt(0), + TWO: '2'.charCodeAt(0), + THREE: '3'.charCodeAt(0) +}; /** - * Creates a 4x4 matrix of Float32 initialized from the given array. - * - * @deprecated Use createFloat32FromArray. - * @param {goog.vec.Mat4.Mat4Like} matrix The array containing the - * matrix values in column major order. - * @return {!goog.vec.Mat4.Type} The new, nine element array. + * @param {string} str String that follows pattern “z/x/y” where x, y and z are + * numbers. + * @return {ol.TileCoord} Tile coord. */ -goog.vec.Mat4.createFromArray = function(matrix) { - var newMatrix = goog.vec.Mat4.createFloat32(); - goog.vec.Mat4.setFromArray(newMatrix, matrix); - return newMatrix; +ol.tilecoord.createFromString = function(str) { + var v = str.split('/'); + goog.asserts.assert(v.length === 3, + 'must provide a string in "z/x/y" format, got "%s"', str); + return v.map(function(e) { + return parseInt(e, 10); + }); }; /** - * Creates a 4x4 matrix of Float32 initialized from the given values. - * - * @deprecated Use createFloat32FromValues. - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {!goog.vec.Mat4.Type} The new, 16 element array. + * @param {number} z Z. + * @param {number} x X. + * @param {number} y Y. + * @param {ol.TileCoord=} opt_tileCoord Tile coordinate. + * @return {ol.TileCoord} Tile coordinate. */ -goog.vec.Mat4.createFromValues = function( - v00, v10, v20, v30, - v01, v11, v21, v31, - v02, v12, v22, v32, - v03, v13, v23, v33) { - return goog.vec.Mat4.createFloat32FromValues( - v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33); +ol.tilecoord.createOrUpdate = function(z, x, y, opt_tileCoord) { + if (opt_tileCoord !== undefined) { + opt_tileCoord[0] = z; + opt_tileCoord[1] = x; + opt_tileCoord[2] = y; + return opt_tileCoord; + } else { + return [z, x, y]; + } }; /** - * Creates a clone of a 4x4 matrix of Float32. - * - * @deprecated Use cloneFloat32. - * @param {goog.vec.Mat4.Mat4Like} matrix The source 4x4 matrix. - * @return {!goog.vec.Mat4.Type} The new 4x4 element matrix. + * @param {number} z Z. + * @param {number} x X. + * @param {number} y Y. + * @return {string} Key. */ -goog.vec.Mat4.clone = goog.vec.Mat4.createFromArray; +ol.tilecoord.getKeyZXY = function(z, x, y) { + return z + '/' + x + '/' + y; +}; /** - * Retrieves the element at the requested row and column. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix containing the - * value to retrieve. - * @param {number} row The row index. - * @param {number} column The column index. - * @return {number} The element value at the requested row, column indices. + * @param {ol.TileCoord} tileCoord Tile coord. + * @return {number} Hash. */ -goog.vec.Mat4.getElement = function(mat, row, column) { - return mat[row + column * 4]; +ol.tilecoord.hash = function(tileCoord) { + return (tileCoord[1] << tileCoord[0]) + tileCoord[2]; }; /** - * Sets the element at the requested row and column. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to set the value on. - * @param {number} row The row index. - * @param {number} column The column index. - * @param {number} value The value to set at the requested row, column. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {ol.TileCoord} tileCoord Tile coord. + * @return {string} Quad key. */ -goog.vec.Mat4.setElement = function(mat, row, column, value) { - mat[row + column * 4] = value; - return mat; +ol.tilecoord.quadKey = function(tileCoord) { + var z = tileCoord[0]; + var digits = new Array(z); + var mask = 1 << (z - 1); + var i, charCode; + for (i = 0; i < z; ++i) { + charCode = ol.QuadKeyCharCode.ZERO; + if (tileCoord[1] & mask) { + charCode += 1; + } + if (tileCoord[2] & mask) { + charCode += 2; + } + digits[i] = String.fromCharCode(charCode); + mask >>= 1; + } + return digits.join(''); }; /** - * Initializes the matrix from the set of values. Note the values supplied are - * in column major order. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the - * values. - * @param {number} v00 The values at (0, 0). - * @param {number} v10 The values at (1, 0). - * @param {number} v20 The values at (2, 0). - * @param {number} v30 The values at (3, 0). - * @param {number} v01 The values at (0, 1). - * @param {number} v11 The values at (1, 1). - * @param {number} v21 The values at (2, 1). - * @param {number} v31 The values at (3, 1). - * @param {number} v02 The values at (0, 2). - * @param {number} v12 The values at (1, 2). - * @param {number} v22 The values at (2, 2). - * @param {number} v32 The values at (3, 2). - * @param {number} v03 The values at (0, 3). - * @param {number} v13 The values at (1, 3). - * @param {number} v23 The values at (2, 3). - * @param {number} v33 The values at (3, 3). - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {ol.TileCoord} tileCoord Tile coord. + * @return {string} String. */ -goog.vec.Mat4.setFromValues = function( - mat, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, - v03, v13, v23, v33) { - mat[0] = v00; - mat[1] = v10; - mat[2] = v20; - mat[3] = v30; - mat[4] = v01; - mat[5] = v11; - mat[6] = v21; - mat[7] = v31; - mat[8] = v02; - mat[9] = v12; - mat[10] = v22; - mat[11] = v32; - mat[12] = v03; - mat[13] = v13; - mat[14] = v23; - mat[15] = v33; - return mat; +ol.tilecoord.toString = function(tileCoord) { + return ol.tilecoord.getKeyZXY(tileCoord[0], tileCoord[1], tileCoord[2]); }; /** - * Sets the matrix from the array of values stored in column major order. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Mat4.AnyType} values The column major ordered - * array of values to store in the matrix. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.TileCoord} Tile coordinate. */ -goog.vec.Mat4.setFromArray = function(mat, values) { - mat[0] = values[0]; - mat[1] = values[1]; - mat[2] = values[2]; - mat[3] = values[3]; - mat[4] = values[4]; - mat[5] = values[5]; - mat[6] = values[6]; - mat[7] = values[7]; - mat[8] = values[8]; - mat[9] = values[9]; - mat[10] = values[10]; - mat[11] = values[11]; - mat[12] = values[12]; - mat[13] = values[13]; - mat[14] = values[14]; - mat[15] = values[15]; - return mat; +ol.tilecoord.wrapX = function(tileCoord, tileGrid, projection) { + var z = tileCoord[0]; + var center = tileGrid.getTileCoordCenter(tileCoord); + var projectionExtent = ol.tilegrid.extentFromProjection(projection); + if (!ol.extent.containsCoordinate(projectionExtent, center)) { + var worldWidth = ol.extent.getWidth(projectionExtent); + var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth); + center[0] += worldWidth * worldsAway; + return tileGrid.getTileCoordForCoordAndZ(center, z); + } else { + return tileCoord; + } }; /** - * Sets the matrix from the array of values stored in row major order. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Mat4.AnyType} values The row major ordered array of - * values to store in the matrix. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid. + * @return {boolean} Tile coordinate is within extent and zoom level range. */ -goog.vec.Mat4.setFromRowMajorArray = function(mat, values) { - mat[0] = values[0]; - mat[1] = values[4]; - mat[2] = values[8]; - mat[3] = values[12]; +ol.tilecoord.withinExtentAndZ = function(tileCoord, tileGrid) { + var z = tileCoord[0]; + var x = tileCoord[1]; + var y = tileCoord[2]; - mat[4] = values[1]; - mat[5] = values[5]; - mat[6] = values[9]; - mat[7] = values[13]; + if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) { + return false; + } + var extent = tileGrid.getExtent(); + var tileRange; + if (!extent) { + tileRange = tileGrid.getFullTileRange(z); + } else { + tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + } + if (!tileRange) { + return true; + } else { + return tileRange.containsXY(x, y); + } +}; - mat[8] = values[2]; - mat[9] = values[6]; - mat[10] = values[10]; - mat[11] = values[14]; +goog.provide('ol.TileRange'); - mat[12] = values[3]; - mat[13] = values[7]; - mat[14] = values[11]; - mat[15] = values[15]; +goog.require('goog.asserts'); +goog.require('ol.Size'); +goog.require('ol.TileCoord'); - return mat; -}; /** - * Sets the diagonal values of the matrix from the given values. + * A representation of a contiguous block of tiles. A tile range is specified + * by its min/max tile coordinates and is inclusive of coordinates. * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {number} v00 The values for (0, 0). - * @param {number} v11 The values for (1, 1). - * @param {number} v22 The values for (2, 2). - * @param {number} v33 The values for (3, 3). - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @constructor + * @param {number} minX Minimum X. + * @param {number} maxX Maximum X. + * @param {number} minY Minimum Y. + * @param {number} maxY Maximum Y. + * @struct */ -goog.vec.Mat4.setDiagonalValues = function(mat, v00, v11, v22, v33) { - mat[0] = v00; - mat[5] = v11; - mat[10] = v22; - mat[15] = v33; - return mat; -}; +ol.TileRange = function(minX, maxX, minY, maxY) { + /** + * @type {number} + */ + this.minX = minX; + + /** + * @type {number} + */ + this.maxX = maxX; + + /** + * @type {number} + */ + this.minY = minY; + + /** + * @type {number} + */ + this.maxY = maxY; -/** - * Sets the diagonal values of the matrix from the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Vec4.AnyType} vec The vector containing the values. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. - */ -goog.vec.Mat4.setDiagonal = function(mat, vec) { - mat[0] = vec[0]; - mat[5] = vec[1]; - mat[10] = vec[2]; - mat[15] = vec[3]; - return mat; }; /** - * Gets the diagonal values of the matrix into the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix containing the values. - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values. - * @param {number=} opt_diagonal Which diagonal to get. A value of 0 selects the - * main diagonal, a positive number selects a super diagonal and a negative - * number selects a sub diagonal. - * @return {goog.vec.Vec4.AnyType} return vec so that operations can be - * chained together. + * @param {...ol.TileCoord} var_args Tile coordinates. + * @return {!ol.TileRange} Bounding tile box. */ -goog.vec.Mat4.getDiagonal = function(mat, vec, opt_diagonal) { - if (!opt_diagonal) { - // This is the most common case, so we avoid the for loop. - vec[0] = mat[0]; - vec[1] = mat[5]; - vec[2] = mat[10]; - vec[3] = mat[15]; - } else { - var offset = opt_diagonal > 0 ? 4 * opt_diagonal : -opt_diagonal; - for (var i = 0; i < 4 - Math.abs(opt_diagonal); i++) { - vec[i] = mat[offset + 5 * i]; - } +ol.TileRange.boundingTileRange = function(var_args) { + var tileCoord0 = /** @type {ol.TileCoord} */ (arguments[0]); + var tileCoord0Z = tileCoord0[0]; + var tileCoord0X = tileCoord0[1]; + var tileCoord0Y = tileCoord0[2]; + var tileRange = new ol.TileRange(tileCoord0X, tileCoord0X, + tileCoord0Y, tileCoord0Y); + var i, ii, tileCoord, tileCoordX, tileCoordY, tileCoordZ; + for (i = 1, ii = arguments.length; i < ii; ++i) { + tileCoord = /** @type {ol.TileCoord} */ (arguments[i]); + tileCoordZ = tileCoord[0]; + tileCoordX = tileCoord[1]; + tileCoordY = tileCoord[2]; + goog.asserts.assert(tileCoordZ == tileCoord0Z, + 'passed tilecoords all have the same Z-value'); + tileRange.minX = Math.min(tileRange.minX, tileCoordX); + tileRange.maxX = Math.max(tileRange.maxX, tileCoordX); + tileRange.minY = Math.min(tileRange.minY, tileCoordY); + tileRange.maxY = Math.max(tileRange.maxY, tileCoordY); } - return vec; + return tileRange; }; /** - * Sets the specified column with the supplied values. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to recieve the values. - * @param {number} column The column index to set the values on. - * @param {number} v0 The value for row 0. - * @param {number} v1 The value for row 1. - * @param {number} v2 The value for row 2. - * @param {number} v3 The value for row 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {number} minX Minimum X. + * @param {number} maxX Maximum X. + * @param {number} minY Minimum Y. + * @param {number} maxY Maximum Y. + * @param {ol.TileRange|undefined} tileRange TileRange. + * @return {ol.TileRange} Tile range. */ -goog.vec.Mat4.setColumnValues = function(mat, column, v0, v1, v2, v3) { - var i = column * 4; - mat[i] = v0; - mat[i + 1] = v1; - mat[i + 2] = v2; - mat[i + 3] = v3; - return mat; +ol.TileRange.createOrUpdate = function(minX, maxX, minY, maxY, tileRange) { + if (tileRange !== undefined) { + tileRange.minX = minX; + tileRange.maxX = maxX; + tileRange.minY = minY; + tileRange.maxY = maxY; + return tileRange; + } else { + return new ol.TileRange(minX, maxX, minY, maxY); + } }; /** - * Sets the specified column with the value from the supplied vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {number} column The column index to set the values on. - * @param {goog.vec.Vec4.AnyType} vec The vector of elements for the column. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @return {boolean} Contains tile coordinate. */ -goog.vec.Mat4.setColumn = function(mat, column, vec) { - var i = column * 4; - mat[i] = vec[0]; - mat[i + 1] = vec[1]; - mat[i + 2] = vec[2]; - mat[i + 3] = vec[3]; - return mat; +ol.TileRange.prototype.contains = function(tileCoord) { + return this.containsXY(tileCoord[1], tileCoord[2]); }; /** - * Retrieves the specified column from the matrix into the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values. - * @param {number} column The column to get the values from. - * @param {goog.vec.Vec4.AnyType} vec The vector of elements to - * receive the column. - * @return {goog.vec.Vec4.AnyType} return vec so that operations can be - * chained together. + * @param {ol.TileRange} tileRange Tile range. + * @return {boolean} Contains. */ -goog.vec.Mat4.getColumn = function(mat, column, vec) { - var i = column * 4; - vec[0] = mat[i]; - vec[1] = mat[i + 1]; - vec[2] = mat[i + 2]; - vec[3] = mat[i + 3]; - return vec; +ol.TileRange.prototype.containsTileRange = function(tileRange) { + return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX && + this.minY <= tileRange.minY && tileRange.maxY <= this.maxY; }; /** - * Sets the columns of the matrix from the given vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Vec4.AnyType} vec0 The values for column 0. - * @param {goog.vec.Vec4.AnyType} vec1 The values for column 1. - * @param {goog.vec.Vec4.AnyType} vec2 The values for column 2. - * @param {goog.vec.Vec4.AnyType} vec3 The values for column 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {number} x Tile coordinate x. + * @param {number} y Tile coordinate y. + * @return {boolean} Contains coordinate. */ -goog.vec.Mat4.setColumns = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.setColumn(mat, 0, vec0); - goog.vec.Mat4.setColumn(mat, 1, vec1); - goog.vec.Mat4.setColumn(mat, 2, vec2); - goog.vec.Mat4.setColumn(mat, 3, vec3); - return mat; +ol.TileRange.prototype.containsXY = function(x, y) { + return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY; }; /** - * Retrieves the column values from the given matrix into the given vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the columns. - * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive column 0. - * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive column 1. - * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive column 2. - * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive column 3. + * @param {ol.TileRange} tileRange Tile range. + * @return {boolean} Equals. */ -goog.vec.Mat4.getColumns = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.getColumn(mat, 0, vec0); - goog.vec.Mat4.getColumn(mat, 1, vec1); - goog.vec.Mat4.getColumn(mat, 2, vec2); - goog.vec.Mat4.getColumn(mat, 3, vec3); +ol.TileRange.prototype.equals = function(tileRange) { + return this.minX == tileRange.minX && this.minY == tileRange.minY && + this.maxX == tileRange.maxX && this.maxY == tileRange.maxY; }; /** - * Sets the row values from the supplied values. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {number} row The index of the row to receive the values. - * @param {number} v0 The value for column 0. - * @param {number} v1 The value for column 1. - * @param {number} v2 The value for column 2. - * @param {number} v3 The value for column 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @param {ol.TileRange} tileRange Tile range. */ -goog.vec.Mat4.setRowValues = function(mat, row, v0, v1, v2, v3) { - mat[row] = v0; - mat[row + 4] = v1; - mat[row + 8] = v2; - mat[row + 12] = v3; - return mat; +ol.TileRange.prototype.extend = function(tileRange) { + if (tileRange.minX < this.minX) { + this.minX = tileRange.minX; + } + if (tileRange.maxX > this.maxX) { + this.maxX = tileRange.maxX; + } + if (tileRange.minY < this.minY) { + this.minY = tileRange.minY; + } + if (tileRange.maxY > this.maxY) { + this.maxY = tileRange.maxY; + } }; /** - * Sets the row values from the supplied vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the row values. - * @param {number} row The index of the row. - * @param {goog.vec.Vec4.AnyType} vec The vector containing the values. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @return {number} Height. */ -goog.vec.Mat4.setRow = function(mat, row, vec) { - mat[row] = vec[0]; - mat[row + 4] = vec[1]; - mat[row + 8] = vec[2]; - mat[row + 12] = vec[3]; - return mat; +ol.TileRange.prototype.getHeight = function() { + return this.maxY - this.minY + 1; }; /** - * Retrieves the row values into the given vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values. - * @param {number} row The index of the row supplying the values. - * @param {goog.vec.Vec4.AnyType} vec The vector to receive the row. - * @return {goog.vec.Vec4.AnyType} return vec so that operations can be - * chained together. + * @return {ol.Size} Size. */ -goog.vec.Mat4.getRow = function(mat, row, vec) { - vec[0] = mat[row]; - vec[1] = mat[row + 4]; - vec[2] = mat[row + 8]; - vec[3] = mat[row + 12]; - return vec; +ol.TileRange.prototype.getSize = function() { + return [this.getWidth(), this.getHeight()]; }; /** - * Sets the rows of the matrix from the supplied vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values. - * @param {goog.vec.Vec4.AnyType} vec0 The values for row 0. - * @param {goog.vec.Vec4.AnyType} vec1 The values for row 1. - * @param {goog.vec.Vec4.AnyType} vec2 The values for row 2. - * @param {goog.vec.Vec4.AnyType} vec3 The values for row 3. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained together. + * @return {number} Width. */ -goog.vec.Mat4.setRows = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.setRow(mat, 0, vec0); - goog.vec.Mat4.setRow(mat, 1, vec1); - goog.vec.Mat4.setRow(mat, 2, vec2); - goog.vec.Mat4.setRow(mat, 3, vec3); - return mat; +ol.TileRange.prototype.getWidth = function() { + return this.maxX - this.minX + 1; }; /** - * Retrieves the rows of the matrix into the supplied vectors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix to supply the values. - * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive row 0. - * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive row 1. - * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive row 2. - * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive row 3. + * @param {ol.TileRange} tileRange Tile range. + * @return {boolean} Intersects. */ -goog.vec.Mat4.getRows = function(mat, vec0, vec1, vec2, vec3) { - goog.vec.Mat4.getRow(mat, 0, vec0); - goog.vec.Mat4.getRow(mat, 1, vec1); - goog.vec.Mat4.getRow(mat, 2, vec2); - goog.vec.Mat4.getRow(mat, 3, vec3); +ol.TileRange.prototype.intersects = function(tileRange) { + return this.minX <= tileRange.maxX && + this.maxX >= tileRange.minX && + this.minY <= tileRange.maxY && + this.maxY >= tileRange.minY; }; +/** + * @return {number} Min X + */ +ol.TileRange.prototype.getMinX = function() { + return this.minX; +} +goog.exportProperty(ol.TileRange.prototype, 'getMinX', + ol.TileRange.prototype.getMinX); /** - * Makes the given 4x4 matrix the zero matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @return {!goog.vec.Mat4.AnyType} return mat so operations can be chained. + * @return {number} Max X */ -goog.vec.Mat4.makeZero = function(mat) { - mat[0] = 0; - mat[1] = 0; - mat[2] = 0; - mat[3] = 0; - mat[4] = 0; - mat[5] = 0; - mat[6] = 0; - mat[7] = 0; - mat[8] = 0; - mat[9] = 0; - mat[10] = 0; - mat[11] = 0; - mat[12] = 0; - mat[13] = 0; - mat[14] = 0; - mat[15] = 0; - return mat; -}; +ol.TileRange.prototype.getMaxX = function() { + return this.maxX; +} +goog.exportProperty(ol.TileRange.prototype, 'getMaxX', + ol.TileRange.prototype.getMaxX); /** - * Makes the given 4x4 matrix the identity matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @return {goog.vec.Mat4.AnyType} return mat so operations can be chained. + * @return {number} Min Y */ -goog.vec.Mat4.makeIdentity = function(mat) { - mat[0] = 1; - mat[1] = 0; - mat[2] = 0; - mat[3] = 0; - mat[4] = 0; - mat[5] = 1; - mat[6] = 0; - mat[7] = 0; - mat[8] = 0; - mat[9] = 0; - mat[10] = 1; - mat[11] = 0; - mat[12] = 0; - mat[13] = 0; - mat[14] = 0; - mat[15] = 1; - return mat; -}; +ol.TileRange.prototype.getMinY = function() { + return this.minY; +} +goog.exportProperty(ol.TileRange.prototype, 'getMinY', + ol.TileRange.prototype.getMinY); /** - * Performs a per-component addition of the matrix mat0 and mat1, storing - * the result into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat0 The first addend. - * @param {goog.vec.Mat4.AnyType} mat1 The second addend. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to - * receive the results (may be either mat0 or mat1). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. + * @return {number} Max Y */ -goog.vec.Mat4.addMat = function(mat0, mat1, resultMat) { - resultMat[0] = mat0[0] + mat1[0]; - resultMat[1] = mat0[1] + mat1[1]; - resultMat[2] = mat0[2] + mat1[2]; - resultMat[3] = mat0[3] + mat1[3]; - resultMat[4] = mat0[4] + mat1[4]; - resultMat[5] = mat0[5] + mat1[5]; - resultMat[6] = mat0[6] + mat1[6]; - resultMat[7] = mat0[7] + mat1[7]; - resultMat[8] = mat0[8] + mat1[8]; - resultMat[9] = mat0[9] + mat1[9]; - resultMat[10] = mat0[10] + mat1[10]; - resultMat[11] = mat0[11] + mat1[11]; - resultMat[12] = mat0[12] + mat1[12]; - resultMat[13] = mat0[13] + mat1[13]; - resultMat[14] = mat0[14] + mat1[14]; - resultMat[15] = mat0[15] + mat1[15]; - return resultMat; -}; +ol.TileRange.prototype.getMaxY = function() { + return this.maxY; +} +goog.exportProperty(ol.TileRange.prototype, 'getMaxY', + ol.TileRange.prototype.getMaxY); + + +goog.provide('ol.Attribution'); + +goog.require('goog.math'); +goog.require('ol.TileRange'); + /** - * Performs a per-component subtraction of the matrix mat0 and mat1, - * storing the result into resultMat. + * @classdesc + * An attribution for a layer source. * - * @param {goog.vec.Mat4.AnyType} mat0 The minuend. - * @param {goog.vec.Mat4.AnyType} mat1 The subtrahend. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be either mat0 or mat1). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. + * Example: + * + * source: new ol.source.OSM({ + * attributions: [ + * new ol.Attribution({ + * html: 'All maps © ' + + * '<a href="http://www.opencyclemap.org/">OpenCycleMap</a>' + * }), + * ol.source.OSM.ATTRIBUTION + * ], + * .. + * + * @constructor + * @param {olx.AttributionOptions} options Attribution options. + * @struct + * @api stable */ -goog.vec.Mat4.subMat = function(mat0, mat1, resultMat) { - resultMat[0] = mat0[0] - mat1[0]; - resultMat[1] = mat0[1] - mat1[1]; - resultMat[2] = mat0[2] - mat1[2]; - resultMat[3] = mat0[3] - mat1[3]; - resultMat[4] = mat0[4] - mat1[4]; - resultMat[5] = mat0[5] - mat1[5]; - resultMat[6] = mat0[6] - mat1[6]; - resultMat[7] = mat0[7] - mat1[7]; - resultMat[8] = mat0[8] - mat1[8]; - resultMat[9] = mat0[9] - mat1[9]; - resultMat[10] = mat0[10] - mat1[10]; - resultMat[11] = mat0[11] - mat1[11]; - resultMat[12] = mat0[12] - mat1[12]; - resultMat[13] = mat0[13] - mat1[13]; - resultMat[14] = mat0[14] - mat1[14]; - resultMat[15] = mat0[15] - mat1[15]; - return resultMat; +ol.Attribution = function(options) { + + /** + * @private + * @type {string} + */ + this.html_ = options.html; + + /** + * @private + * @type {Object.<string, Array.<ol.TileRange>>} + */ + this.tileRanges_ = options.tileRanges ? options.tileRanges : null; + }; /** - * Multiplies matrix mat with the given scalar, storing the result - * into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} scalar The scalar value to multiply to each element of mat. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be mat). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. + * Get the attribution markup. + * @return {string} The attribution HTML. + * @api stable */ -goog.vec.Mat4.multScalar = function(mat, scalar, resultMat) { - resultMat[0] = mat[0] * scalar; - resultMat[1] = mat[1] * scalar; - resultMat[2] = mat[2] * scalar; - resultMat[3] = mat[3] * scalar; - resultMat[4] = mat[4] * scalar; - resultMat[5] = mat[5] * scalar; - resultMat[6] = mat[6] * scalar; - resultMat[7] = mat[7] * scalar; - resultMat[8] = mat[8] * scalar; - resultMat[9] = mat[9] * scalar; - resultMat[10] = mat[10] * scalar; - resultMat[11] = mat[11] * scalar; - resultMat[12] = mat[12] * scalar; - resultMat[13] = mat[13] * scalar; - resultMat[14] = mat[14] * scalar; - resultMat[15] = mat[15] * scalar; - return resultMat; +ol.Attribution.prototype.getHTML = function() { + return this.html_; }; /** - * Multiplies the two matrices mat0 and mat1 using matrix multiplication, - * storing the result into resultMat. - * - * @param {goog.vec.Mat4.AnyType} mat0 The first (left hand) matrix. - * @param {goog.vec.Mat4.AnyType} mat1 The second (right hand) matrix. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be either mat0 or mat1). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. + * @param {Object.<string, ol.TileRange>} tileRanges Tile ranges. + * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid. + * @param {!ol.proj.Projection} projection Projection. + * @return {boolean} Intersects any tile range. */ -goog.vec.Mat4.multMat = function(mat0, mat1, resultMat) { - var a00 = mat0[0], a10 = mat0[1], a20 = mat0[2], a30 = mat0[3]; - var a01 = mat0[4], a11 = mat0[5], a21 = mat0[6], a31 = mat0[7]; - var a02 = mat0[8], a12 = mat0[9], a22 = mat0[10], a32 = mat0[11]; - var a03 = mat0[12], a13 = mat0[13], a23 = mat0[14], a33 = mat0[15]; +ol.Attribution.prototype.intersectsAnyTileRange = + function(tileRanges, tileGrid, projection) { + if (!this.tileRanges_) { + return true; + } + var i, ii, tileRange, zKey; + for (zKey in tileRanges) { + if (!(zKey in this.tileRanges_)) { + continue; + } + tileRange = tileRanges[zKey]; + var testTileRange; + for (i = 0, ii = this.tileRanges_[zKey].length; i < ii; ++i) { + testTileRange = this.tileRanges_[zKey][i]; + if (testTileRange.intersects(tileRange)) { + return true; + } + var extentTileRange = tileGrid.getTileRangeForExtentAndZ( + projection.getExtent(), parseInt(zKey, 10)); + var width = extentTileRange.getWidth(); + if (tileRange.minX < extentTileRange.minX || + tileRange.maxX > extentTileRange.maxX) { + if (testTileRange.intersects(new ol.TileRange( + goog.math.modulo(tileRange.minX, width), + goog.math.modulo(tileRange.maxX, width), + tileRange.minY, tileRange.maxY))) { + return true; + } + if (tileRange.getWidth() > width && + testTileRange.intersects(extentTileRange)) { + return true; + } + } + } + } + return false; +}; - var b00 = mat1[0], b10 = mat1[1], b20 = mat1[2], b30 = mat1[3]; - var b01 = mat1[4], b11 = mat1[5], b21 = mat1[6], b31 = mat1[7]; - var b02 = mat1[8], b12 = mat1[9], b22 = mat1[10], b32 = mat1[11]; - var b03 = mat1[12], b13 = mat1[13], b23 = mat1[14], b33 = mat1[15]; +/** + * @license + * Latitude/longitude spherical geodesy formulae taken from + * http://www.movable-type.co.uk/scripts/latlong.html + * Licensed under CC-BY-3.0. + */ - resultMat[0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30; - resultMat[1] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30; - resultMat[2] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30; - resultMat[3] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30; +goog.provide('ol.Sphere'); - resultMat[4] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31; - resultMat[5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31; - resultMat[6] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31; - resultMat[7] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31; +goog.require('ol.math'); - resultMat[8] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32; - resultMat[9] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32; - resultMat[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32; - resultMat[11] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32; - resultMat[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33; - resultMat[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33; - resultMat[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33; - resultMat[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33; - return resultMat; + +/** + * @classdesc + * Class to create objects that can be used with {@link + * ol.geom.Polygon.circular}. + * + * For example to create a sphere whose radius is equal to the semi-major + * axis of the WGS84 ellipsoid: + * + * ```js + * var wgs84Sphere= new ol.Sphere(6378137); + * ``` + * + * @constructor + * @param {number} radius Radius. + * @api + */ +ol.Sphere = function(radius) { + + /** + * @type {number} + */ + this.radius = radius; + }; /** - * Transposes the given matrix mat storing the result into resultMat. + * Returns the geodesic area for a list of coordinates. * - * @param {goog.vec.Mat4.AnyType} mat The matrix to transpose. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the results (may be mat). - * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be - * chained together. + * [Reference](http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409) + * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for + * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion + * Laboratory, Pasadena, CA, June 2007 + * + * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear + * ring. If the ring is oriented clockwise, the area will be positive, + * otherwise it will be negative. + * @return {number} Area. + * @api */ -goog.vec.Mat4.transpose = function(mat, resultMat) { - if (resultMat == mat) { - var a10 = mat[1], a20 = mat[2], a30 = mat[3]; - var a21 = mat[6], a31 = mat[7]; - var a32 = mat[11]; - resultMat[1] = mat[4]; - resultMat[2] = mat[8]; - resultMat[3] = mat[12]; - resultMat[4] = a10; - resultMat[6] = mat[9]; - resultMat[7] = mat[13]; - resultMat[8] = a20; - resultMat[9] = a21; - resultMat[11] = mat[14]; - resultMat[12] = a30; - resultMat[13] = a31; - resultMat[14] = a32; - } else { - resultMat[0] = mat[0]; - resultMat[1] = mat[4]; - resultMat[2] = mat[8]; - resultMat[3] = mat[12]; - - resultMat[4] = mat[1]; - resultMat[5] = mat[5]; - resultMat[6] = mat[9]; - resultMat[7] = mat[13]; - - resultMat[8] = mat[2]; - resultMat[9] = mat[6]; - resultMat[10] = mat[10]; - resultMat[11] = mat[14]; - - resultMat[12] = mat[3]; - resultMat[13] = mat[7]; - resultMat[14] = mat[11]; - resultMat[15] = mat[15]; +ol.Sphere.prototype.geodesicArea = function(coordinates) { + var area = 0, len = coordinates.length; + var x1 = coordinates[len - 1][0]; + var y1 = coordinates[len - 1][1]; + for (var i = 0; i < len; i++) { + var x2 = coordinates[i][0], y2 = coordinates[i][1]; + area += ol.math.toRadians(x2 - x1) * + (2 + Math.sin(ol.math.toRadians(y1)) + + Math.sin(ol.math.toRadians(y2))); + x1 = x2; + y1 = y2; } - return resultMat; + return area * this.radius * this.radius / 2.0; }; /** - * Computes the determinant of the matrix. + * Returns the distance from c1 to c2 using the haversine formula. * - * @param {goog.vec.Mat4.AnyType} mat The matrix to compute the matrix for. - * @return {number} The determinant of the matrix. + * @param {ol.Coordinate} c1 Coordinate 1. + * @param {ol.Coordinate} c2 Coordinate 2. + * @return {number} Haversine distance. + * @api */ -goog.vec.Mat4.determinant = function(mat) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; - - var a0 = m00 * m11 - m10 * m01; - var a1 = m00 * m21 - m20 * m01; - var a2 = m00 * m31 - m30 * m01; - var a3 = m10 * m21 - m20 * m11; - var a4 = m10 * m31 - m30 * m11; - var a5 = m20 * m31 - m30 * m21; - var b0 = m02 * m13 - m12 * m03; - var b1 = m02 * m23 - m22 * m03; - var b2 = m02 * m33 - m32 * m03; - var b3 = m12 * m23 - m22 * m13; - var b4 = m12 * m33 - m32 * m13; - var b5 = m22 * m33 - m32 * m23; - - return a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; +ol.Sphere.prototype.haversineDistance = function(c1, c2) { + var lat1 = ol.math.toRadians(c1[1]); + var lat2 = ol.math.toRadians(c2[1]); + var deltaLatBy2 = (lat2 - lat1) / 2; + var deltaLonBy2 = ol.math.toRadians(c2[0] - c1[0]) / 2; + var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + + Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * + Math.cos(lat1) * Math.cos(lat2); + return 2 * this.radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); }; /** - * Computes the inverse of mat storing the result into resultMat. If the - * inverse is defined, this function returns true, false otherwise. + * Returns the coordinate at the given distance and bearing from `c1`. * - * @param {goog.vec.Mat4.AnyType} mat The matrix to invert. - * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive - * the result (may be mat). - * @return {boolean} True if the inverse is defined. If false is returned, - * resultMat is not modified. + * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees). + * @param {number} distance The great-circle distance between the origin + * point and the target point. + * @param {number} bearing The bearing (in radians). + * @return {ol.Coordinate} The target point. */ -goog.vec.Mat4.invert = function(mat, resultMat) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; - - var a0 = m00 * m11 - m10 * m01; - var a1 = m00 * m21 - m20 * m01; - var a2 = m00 * m31 - m30 * m01; - var a3 = m10 * m21 - m20 * m11; - var a4 = m10 * m31 - m30 * m11; - var a5 = m20 * m31 - m30 * m21; - var b0 = m02 * m13 - m12 * m03; - var b1 = m02 * m23 - m22 * m03; - var b2 = m02 * m33 - m32 * m03; - var b3 = m12 * m23 - m22 * m13; - var b4 = m12 * m33 - m32 * m13; - var b5 = m22 * m33 - m32 * m23; +ol.Sphere.prototype.offset = function(c1, distance, bearing) { + var lat1 = ol.math.toRadians(c1[1]); + var lon1 = ol.math.toRadians(c1[0]); + var dByR = distance / this.radius; + var lat = Math.asin( + Math.sin(lat1) * Math.cos(dByR) + + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing)); + var lon = lon1 + Math.atan2( + Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), + Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat)); + return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)]; +}; - var det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; - if (det == 0) { - return false; - } +goog.provide('ol.sphere.NORMAL'); - var idet = 1.0 / det; - resultMat[0] = (m11 * b5 - m21 * b4 + m31 * b3) * idet; - resultMat[1] = (-m10 * b5 + m20 * b4 - m30 * b3) * idet; - resultMat[2] = (m13 * a5 - m23 * a4 + m33 * a3) * idet; - resultMat[3] = (-m12 * a5 + m22 * a4 - m32 * a3) * idet; - resultMat[4] = (-m01 * b5 + m21 * b2 - m31 * b1) * idet; - resultMat[5] = (m00 * b5 - m20 * b2 + m30 * b1) * idet; - resultMat[6] = (-m03 * a5 + m23 * a2 - m33 * a1) * idet; - resultMat[7] = (m02 * a5 - m22 * a2 + m32 * a1) * idet; - resultMat[8] = (m01 * b4 - m11 * b2 + m31 * b0) * idet; - resultMat[9] = (-m00 * b4 + m10 * b2 - m30 * b0) * idet; - resultMat[10] = (m03 * a4 - m13 * a2 + m33 * a0) * idet; - resultMat[11] = (-m02 * a4 + m12 * a2 - m32 * a0) * idet; - resultMat[12] = (-m01 * b3 + m11 * b1 - m21 * b0) * idet; - resultMat[13] = (m00 * b3 - m10 * b1 + m20 * b0) * idet; - resultMat[14] = (-m03 * a3 + m13 * a1 - m23 * a0) * idet; - resultMat[15] = (m02 * a3 - m12 * a1 + m22 * a0) * idet; - return true; -}; +goog.require('ol.Sphere'); /** - * Returns true if the components of mat0 are equal to the components of mat1. - * - * @param {goog.vec.Mat4.AnyType} mat0 The first matrix. - * @param {goog.vec.Mat4.AnyType} mat1 The second matrix. - * @return {boolean} True if the the two matrices are equivalent. + * The normal sphere. + * @const + * @type {ol.Sphere} */ -goog.vec.Mat4.equals = function(mat0, mat1) { - return mat0.length == mat1.length && - mat0[0] == mat1[0] && - mat0[1] == mat1[1] && - mat0[2] == mat1[2] && - mat0[3] == mat1[3] && - mat0[4] == mat1[4] && - mat0[5] == mat1[5] && - mat0[6] == mat1[6] && - mat0[7] == mat1[7] && - mat0[8] == mat1[8] && - mat0[9] == mat1[9] && - mat0[10] == mat1[10] && - mat0[11] == mat1[11] && - mat0[12] == mat1[12] && - mat0[13] == mat1[13] && - mat0[14] == mat1[14] && - mat0[15] == mat1[15]; -}; +ol.sphere.NORMAL = new ol.Sphere(6370997); +goog.provide('ol.proj'); +goog.provide('ol.proj.METERS_PER_UNIT'); +goog.provide('ol.proj.Projection'); +goog.provide('ol.proj.ProjectionLike'); +goog.provide('ol.proj.Units'); -/** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * upper 3x4 matrix omitting the projective component. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. - * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to - * receive the results (may be vec). - * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be - * chained together. - */ -goog.vec.Mat4.multVec3 = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2]; - resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + mat[12]; - resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + mat[13]; - resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + mat[14]; - return resultVec; -}; +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Extent'); +goog.require('ol.TransformFunction'); +goog.require('ol.extent'); +goog.require('ol.sphere.NORMAL'); /** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * upper 3x3 matrix omitting the projective component and translation - * components. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. - * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to - * receive the results (may be vec). - * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be - * chained together. + * A projection as {@link ol.proj.Projection}, SRS identifier string or + * undefined. + * @typedef {ol.proj.Projection|string|undefined} ol.proj.ProjectionLike + * @api stable */ -goog.vec.Mat4.multVec3NoTranslate = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2]; - resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8]; - resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9]; - resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10]; - return resultVec; -}; +ol.proj.ProjectionLike; /** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * full 4x4 matrix with the homogeneous divide applied to reduce the 4 element - * vector to a 3 element vector. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform. - * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector - * to receive the results (may be vec). - * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be - * chained together. + * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or + * `'us-ft'`. + * @enum {string} + * @api stable */ -goog.vec.Mat4.multVec3Projective = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2]; - var invw = 1 / (x * mat[3] + y * mat[7] + z * mat[11] + mat[15]); - resultVec[0] = (x * mat[0] + y * mat[4] + z * mat[8] + mat[12]) * invw; - resultVec[1] = (x * mat[1] + y * mat[5] + z * mat[9] + mat[13]) * invw; - resultVec[2] = (x * mat[2] + y * mat[6] + z * mat[10] + mat[14]) * invw; - return resultVec; +ol.proj.Units = { + DEGREES: 'degrees', + FEET: 'ft', + METERS: 'm', + PIXELS: 'pixels', + TILE_PIXELS: 'tile-pixels', + USFEET: 'us-ft' }; /** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation. - * @param {goog.vec.Vec4.AnyType} vec The vector to transform. - * @param {goog.vec.Vec4.AnyType} resultVec The vector to - * receive the results (may be vec). - * @return {goog.vec.Vec4.AnyType} return resultVec so that operations can be - * chained together. + * Meters per unit lookup table. + * @const + * @type {Object.<ol.proj.Units, number>} + * @api stable */ -goog.vec.Mat4.multVec4 = function(mat, vec, resultVec) { - var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; - resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + w * mat[12]; - resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + w * mat[13]; - resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + w * mat[14]; - resultVec[3] = x * mat[3] + y * mat[7] + z * mat[11] + w * mat[15]; - return resultVec; -}; +ol.proj.METERS_PER_UNIT = {}; +ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] = + 2 * Math.PI * ol.sphere.NORMAL.radius / 360; +ol.proj.METERS_PER_UNIT[ol.proj.Units.FEET] = 0.3048; +ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1; +ol.proj.METERS_PER_UNIT[ol.proj.Units.USFEET] = 1200 / 3937; + /** - * Makes the given 4x4 matrix a translation matrix with x, y and z - * translation factors. + * @classdesc + * Projection definition class. One of these is created for each projection + * supported in the application and stored in the {@link ol.proj} namespace. + * You can use these in applications, but this is not required, as API params + * and options use {@link ol.proj.ProjectionLike} which means the simple string + * code will suffice. * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The translation along the x axis. - * @param {number} y The translation along the y axis. - * @param {number} z The translation along the z axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * You can use {@link ol.proj.get} to retrieve the object for a particular + * projection. + * + * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together + * with the following aliases: + * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, + * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84, + * http://www.opengis.net/gml/srs/epsg.xml#4326, + * urn:x-ogc:def:crs:EPSG:4326 + * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913, + * urn:ogc:def:crs:EPSG:6.18:3:3857, + * http://www.opengis.net/gml/srs/epsg.xml#3857 + * + * If you use proj4js, aliases can be added using `proj4.defs()`; see + * [documentation](https://github.com/proj4js/proj4js). + * + * @constructor + * @param {olx.ProjectionOptions} options Projection options. + * @struct + * @api stable */ -goog.vec.Mat4.makeTranslate = function(mat, x, y, z) { - goog.vec.Mat4.makeIdentity(mat); - return goog.vec.Mat4.setColumnValues(mat, 3, x, y, z, 1); -}; +ol.proj.Projection = function(options) { + /** + * @private + * @type {string} + */ + this.code_ = options.code; -/** - * Makes the given 4x4 matrix as a scale matrix with x, y and z scale factors. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The scale along the x axis. - * @param {number} y The scale along the y axis. - * @param {number} z The scale along the z axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeScale = function(mat, x, y, z) { - goog.vec.Mat4.makeIdentity(mat); - return goog.vec.Mat4.setDiagonalValues(mat, x, y, z, 1); -}; + /** + * @private + * @type {ol.proj.Units} + */ + this.units_ = /** @type {ol.proj.Units} */ (options.units); + /** + * @private + * @type {ol.Extent} + */ + this.extent_ = options.extent !== undefined ? options.extent : null; -/** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the axis defined by the vector (ax, ay, az). - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @param {number} ax The x component of the rotation axis. - * @param {number} ay The y component of the rotation axis. - * @param {number} az The z component of the rotation axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. - */ -goog.vec.Mat4.makeRotate = function(mat, angle, ax, ay, az) { - var c = Math.cos(angle); - var d = 1 - c; - var s = Math.sin(angle); + /** + * @private + * @type {ol.Extent} + */ + this.worldExtent_ = options.worldExtent !== undefined ? + options.worldExtent : null; - return goog.vec.Mat4.setFromValues(mat, - ax * ax * d + c, - ax * ay * d + az * s, - ax * az * d - ay * s, - 0, + /** + * @private + * @type {string} + */ + this.axisOrientation_ = options.axisOrientation !== undefined ? + options.axisOrientation : 'enu'; - ax * ay * d - az * s, - ay * ay * d + c, - ay * az * d + ax * s, - 0, + /** + * @private + * @type {boolean} + */ + this.global_ = options.global !== undefined ? options.global : false; - ax * az * d + ay * s, - ay * az * d - ax * s, - az * az * d + c, - 0, - 0, 0, 0, 1); + /** + * @private + * @type {boolean} + */ + this.canWrapX_ = !!(this.global_ && this.extent_); + + /** + * @private + * @type {function(number, ol.Coordinate):number} + */ + this.getPointResolutionFunc_ = options.getPointResolution !== undefined ? + options.getPointResolution : this.getPointResolution_; + + /** + * @private + * @type {ol.tilegrid.TileGrid} + */ + this.defaultTileGrid_ = null; + + var projections = ol.proj.projections_; + var code = options.code; + goog.asserts.assert(code !== undefined, + 'Option "code" is required for constructing instance'); + if (ol.ENABLE_PROJ4JS && typeof proj4 == 'function' && + projections[code] === undefined) { + var def = proj4.defs(code); + if (def !== undefined) { + if (def.axis !== undefined && options.axisOrientation === undefined) { + this.axisOrientation_ = def.axis; + } + if (options.units === undefined) { + var units = def.units; + if (def.to_meter !== undefined) { + if (units === undefined || + ol.proj.METERS_PER_UNIT[units] === undefined) { + units = def.to_meter.toString(); + ol.proj.METERS_PER_UNIT[units] = def.to_meter; + } + } + this.units_ = units; + } + var currentCode, currentDef, currentProj, proj4Transform; + for (currentCode in projections) { + currentDef = proj4.defs(currentCode); + if (currentDef !== undefined) { + currentProj = ol.proj.get(currentCode); + if (currentDef === def) { + ol.proj.addEquivalentProjections([currentProj, this]); + } else { + proj4Transform = proj4(currentCode, code); + ol.proj.addCoordinateTransforms(currentProj, this, + proj4Transform.forward, proj4Transform.inverse); + } + } + } + } + } + }; /** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the X axis. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @return {boolean} The projection is suitable for wrapping the x-axis */ -goog.vec.Mat4.makeRotateX = function(mat, angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - return goog.vec.Mat4.setFromValues( - mat, 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1); +ol.proj.Projection.prototype.canWrapX = function() { + return this.canWrapX_; }; /** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the Y axis. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Get the code for this projection, e.g. 'EPSG:4326'. + * @return {string} Code. + * @api stable */ -goog.vec.Mat4.makeRotateY = function(mat, angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - return goog.vec.Mat4.setFromValues( - mat, c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1); +ol.proj.Projection.prototype.getCode = function() { + return this.code_; }; /** - * Makes the given 4x4 matrix a rotation matrix with the given rotation - * angle about the Z axis. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The rotation angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Get the validity extent for this projection. + * @return {ol.Extent} Extent. + * @api stable */ -goog.vec.Mat4.makeRotateZ = function(mat, angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - return goog.vec.Mat4.setFromValues( - mat, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); +ol.proj.Projection.prototype.getExtent = function() { + return this.extent_; }; /** - * Makes the given 4x4 matrix a perspective projection matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} left The coordinate of the left clipping plane. - * @param {number} right The coordinate of the right clipping plane. - * @param {number} bottom The coordinate of the bottom clipping plane. - * @param {number} top The coordinate of the top clipping plane. - * @param {number} near The distance to the near clipping plane. - * @param {number} far The distance to the far clipping plane. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Get the units of this projection. + * @return {ol.proj.Units} Units. + * @api stable */ -goog.vec.Mat4.makeFrustum = function(mat, left, right, bottom, top, near, far) { - var x = (2 * near) / (right - left); - var y = (2 * near) / (top - bottom); - var a = (right + left) / (right - left); - var b = (top + bottom) / (top - bottom); - var c = -(far + near) / (far - near); - var d = -(2 * far * near) / (far - near); - - return goog.vec.Mat4.setFromValues(mat, - x, 0, 0, 0, - 0, y, 0, 0, - a, b, c, -1, - 0, 0, d, 0 - ); +ol.proj.Projection.prototype.getUnits = function() { + return this.units_; }; /** - * Makse the given 4x4 matrix perspective projection matrix given a - * field of view and aspect ratio. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} fovy The field of view along the y (vertical) axis in - * radians. - * @param {number} aspect The x (width) to y (height) aspect ratio. - * @param {number} near The distance to the near clipping plane. - * @param {number} far The distance to the far clipping plane. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Get the amount of meters per unit of this projection. If the projection is + * not configured with a units identifier, the return is `undefined`. + * @return {number|undefined} Meters. + * @api stable */ -goog.vec.Mat4.makePerspective = function(mat, fovy, aspect, near, far) { - var angle = fovy / 2; - var dz = far - near; - var sinAngle = Math.sin(angle); - if (dz == 0 || sinAngle == 0 || aspect == 0) { - return mat; - } - - var cot = Math.cos(angle) / sinAngle; - return goog.vec.Mat4.setFromValues(mat, - cot / aspect, 0, 0, 0, - 0, cot, 0, 0, - 0, 0, -(far + near) / dz, -1, - 0, 0, -(2 * near * far) / dz, 0 - ); +ol.proj.Projection.prototype.getMetersPerUnit = function() { + return ol.proj.METERS_PER_UNIT[this.units_]; }; /** - * Makes the given 4x4 matrix an orthographic projection matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} left The coordinate of the left clipping plane. - * @param {number} right The coordinate of the right clipping plane. - * @param {number} bottom The coordinate of the bottom clipping plane. - * @param {number} top The coordinate of the top clipping plane. - * @param {number} near The distance to the near clipping plane. - * @param {number} far The distance to the far clipping plane. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Get the world extent for this projection. + * @return {ol.Extent} Extent. + * @api */ -goog.vec.Mat4.makeOrtho = function(mat, left, right, bottom, top, near, far) { - var x = 2 / (right - left); - var y = 2 / (top - bottom); - var z = -2 / (far - near); - var a = -(right + left) / (right - left); - var b = -(top + bottom) / (top - bottom); - var c = -(far + near) / (far - near); - - return goog.vec.Mat4.setFromValues(mat, - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - a, b, c, 1 - ); +ol.proj.Projection.prototype.getWorldExtent = function() { + return this.worldExtent_; }; /** - * Makes the given 4x4 matrix a modelview matrix of a camera so that - * the camera is 'looking at' the given center point. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point - * (camera origin). - * @param {goog.vec.Vec3.AnyType} centerPt The point to aim the camera at. - * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that identifies - * the up direction for the camera. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Get the axis orientation of this projection. + * Example values are: + * enu - the default easting, northing, elevation. + * neu - northing, easting, up - useful for "lat/long" geographic coordinates, + * or south orientated transverse mercator. + * wnu - westing, northing, up - some planetary coordinate systems have + * "west positive" coordinate systems + * @return {string} Axis orientation. */ -goog.vec.Mat4.makeLookAt = function(mat, eyePt, centerPt, worldUpVec) { - // Compute the direction vector from the eye point to the center point and - // normalize. - var fwdVec = goog.vec.Mat4.tmpVec4_[0]; - goog.vec.Vec3.subtract(centerPt, eyePt, fwdVec); - goog.vec.Vec3.normalize(fwdVec, fwdVec); - fwdVec[3] = 0; +ol.proj.Projection.prototype.getAxisOrientation = function() { + return this.axisOrientation_; +}; - // Compute the side vector from the forward vector and the input up vector. - var sideVec = goog.vec.Mat4.tmpVec4_[1]; - goog.vec.Vec3.cross(fwdVec, worldUpVec, sideVec); - goog.vec.Vec3.normalize(sideVec, sideVec); - sideVec[3] = 0; - // Now the up vector to form the orthonormal basis. - var upVec = goog.vec.Mat4.tmpVec4_[2]; - goog.vec.Vec3.cross(sideVec, fwdVec, upVec); - goog.vec.Vec3.normalize(upVec, upVec); - upVec[3] = 0; +/** + * Is this projection a global projection which spans the whole world? + * @return {boolean} Whether the projection is global. + * @api stable + */ +ol.proj.Projection.prototype.isGlobal = function() { + return this.global_; +}; - // Update the view matrix with the new orthonormal basis and position the - // camera at the given eye point. - goog.vec.Vec3.negate(fwdVec, fwdVec); - goog.vec.Mat4.setRow(mat, 0, sideVec); - goog.vec.Mat4.setRow(mat, 1, upVec); - goog.vec.Mat4.setRow(mat, 2, fwdVec); - goog.vec.Mat4.setRowValues(mat, 3, 0, 0, 0, 1); - goog.vec.Mat4.translate( - mat, -eyePt[0], -eyePt[1], -eyePt[2]); - return mat; +/** +* Set if the projection is a global projection which spans the whole world +* @param {boolean} global Whether the projection is global. +* @api stable +*/ +ol.proj.Projection.prototype.setGlobal = function(global) { + this.global_ = global; + this.canWrapX_ = !!(global && this.extent_); }; /** - * Decomposes a matrix into the lookAt vectors eyePt, fwdVec and worldUpVec. - * The matrix represents the modelview matrix of a camera. It is the inverse - * of lookAt except for the output of the fwdVec instead of centerPt. - * The centerPt itself cannot be recovered from a modelview matrix. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point - * (camera origin). - * @param {goog.vec.Vec3.AnyType} fwdVec The vector describing where - * the camera points to. - * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that - * identifies the up direction for the camera. - * @return {boolean} True if the method succeeds, false otherwise. - * The method can only fail if the inverse of viewMatrix is not defined. + * @return {ol.tilegrid.TileGrid} The default tile grid. */ -goog.vec.Mat4.toLookAt = function(mat, eyePt, fwdVec, worldUpVec) { - // Get eye of the camera. - var matInverse = goog.vec.Mat4.tmpMat4_[0]; - if (!goog.vec.Mat4.invert(mat, matInverse)) { - // The input matrix does not have a valid inverse. - return false; - } - - if (eyePt) { - eyePt[0] = matInverse[12]; - eyePt[1] = matInverse[13]; - eyePt[2] = matInverse[14]; - } +ol.proj.Projection.prototype.getDefaultTileGrid = function() { + return this.defaultTileGrid_; +}; - // Get forward vector from the definition of lookAt. - if (fwdVec || worldUpVec) { - if (!fwdVec) { - fwdVec = goog.vec.Mat4.tmpVec3_[0]; - } - fwdVec[0] = -mat[2]; - fwdVec[1] = -mat[6]; - fwdVec[2] = -mat[10]; - // Normalize forward vector. - goog.vec.Vec3.normalize(fwdVec, fwdVec); - } - if (worldUpVec) { - // Get side vector from the definition of gluLookAt. - var side = goog.vec.Mat4.tmpVec3_[1]; - side[0] = mat[0]; - side[1] = mat[4]; - side[2] = mat[8]; - // Compute up vector as a up = side x forward. - goog.vec.Vec3.cross(side, fwdVec, worldUpVec); - // Normalize up vector. - goog.vec.Vec3.normalize(worldUpVec, worldUpVec); - } - return true; +/** + * @param {ol.tilegrid.TileGrid} tileGrid The default tile grid. + */ +ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) { + this.defaultTileGrid_ = tileGrid; }; /** - * Makes the given 4x4 matrix a rotation matrix given Euler angles using - * the ZXZ convention. - * Given the euler angles [theta1, theta2, theta3], the rotation is defined as - * rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3), - * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi]. - * rotation_x(theta) means rotation around the X axis of theta radians, - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} theta1 The angle of rotation around the Z axis in radians. - * @param {number} theta2 The angle of rotation around the X axis in radians. - * @param {number} theta3 The angle of rotation around the Z axis in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * Set the validity extent for this projection. + * @param {ol.Extent} extent Extent. + * @api stable */ -goog.vec.Mat4.makeEulerZXZ = function(mat, theta1, theta2, theta3) { - var c1 = Math.cos(theta1); - var s1 = Math.sin(theta1); - - var c2 = Math.cos(theta2); - var s2 = Math.sin(theta2); +ol.proj.Projection.prototype.setExtent = function(extent) { + this.extent_ = extent; + this.canWrapX_ = !!(this.global_ && extent); +}; - var c3 = Math.cos(theta3); - var s3 = Math.sin(theta3); - mat[0] = c1 * c3 - c2 * s1 * s3; - mat[1] = c2 * c1 * s3 + c3 * s1; - mat[2] = s3 * s2; - mat[3] = 0; +/** + * Set the world extent for this projection. + * @param {ol.Extent} worldExtent World extent + * [minlon, minlat, maxlon, maxlat]. + * @api + */ +ol.proj.Projection.prototype.setWorldExtent = function(worldExtent) { + this.worldExtent_ = worldExtent; +}; - mat[4] = -c1 * s3 - c3 * c2 * s1; - mat[5] = c1 * c2 * c3 - s1 * s3; - mat[6] = c3 * s2; - mat[7] = 0; - mat[8] = s2 * s1; - mat[9] = -c1 * s2; - mat[10] = c2; - mat[11] = 0; +/** +* Set the getPointResolution function for this projection. +* @param {function(number, ol.Coordinate):number} func Function +* @api +*/ +ol.proj.Projection.prototype.setGetPointResolution = function(func) { + this.getPointResolutionFunc_ = func; +}; - mat[12] = 0; - mat[13] = 0; - mat[14] = 0; - mat[15] = 1; - return mat; +/** +* Default version. +* Get the resolution of the point in degrees or distance units. +* For projections with degrees as the unit this will simply return the +* provided resolution. For other projections the point resolution is +* estimated by transforming the 'point' pixel to EPSG:4326, +* measuring its width and height on the normal sphere, +* and taking the average of the width and height. +* @param {number} resolution Nominal resolution in projection units. +* @param {ol.Coordinate} point Point to find adjusted resolution at. +* @return {number} Point resolution at point in projection units. +* @private +*/ +ol.proj.Projection.prototype.getPointResolution_ = function(resolution, point) { + var units = this.getUnits(); + if (units == ol.proj.Units.DEGREES) { + return resolution; + } else { + // Estimate point resolution by transforming the center pixel to EPSG:4326, + // measuring its width and height on the normal sphere, and taking the + // average of the width and height. + var toEPSG4326 = ol.proj.getTransformFromProjections( + this, ol.proj.get('EPSG:4326')); + var vertices = [ + point[0] - resolution / 2, point[1], + point[0] + resolution / 2, point[1], + point[0], point[1] - resolution / 2, + point[0], point[1] + resolution / 2 + ]; + vertices = toEPSG4326(vertices, vertices, 2); + var width = ol.sphere.NORMAL.haversineDistance( + vertices.slice(0, 2), vertices.slice(2, 4)); + var height = ol.sphere.NORMAL.haversineDistance( + vertices.slice(4, 6), vertices.slice(6, 8)); + var pointResolution = (width + height) / 2; + var metersPerUnit = this.getMetersPerUnit(); + if (metersPerUnit !== undefined) { + pointResolution /= metersPerUnit; + } + return pointResolution; + } }; /** - * Decomposes a rotation matrix into Euler angles using the ZXZ convention so - * that rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3), - * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi]. - * rotation_x(theta) means rotation around the X axis of theta radians. - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {goog.vec.Vec3.AnyType} euler The ZXZ Euler angles in - * radians as [theta1, theta2, theta3]. - * @param {boolean=} opt_theta2IsNegative Whether theta2 is in [-pi, 0] instead - * of the default [0, pi]. - * @return {goog.vec.Vec4.AnyType} return euler so that operations can be - * chained together. + * Get the resolution of the point in degrees or distance units. + * For projections with degrees as the unit this will simply return the + * provided resolution. The default for other projections is to estimate + * the point resolution by transforming the 'point' pixel to EPSG:4326, + * measuring its width and height on the normal sphere, + * and taking the average of the width and height. + * An alternative implementation may be given when constructing a + * projection. For many local projections, + * such a custom function will return the resolution unchanged. + * @param {number} resolution Resolution in projection units. + * @param {ol.Coordinate} point Point. + * @return {number} Point resolution in projection units. + * @api */ -goog.vec.Mat4.toEulerZXZ = function(mat, euler, opt_theta2IsNegative) { - // There is an ambiguity in the sign of sinTheta2 because of the sqrt. - var sinTheta2 = Math.sqrt(mat[2] * mat[2] + mat[6] * mat[6]); +ol.proj.Projection.prototype.getPointResolution = function(resolution, point) { + return this.getPointResolutionFunc_(resolution, point); +}; - // By default we explicitely constrain theta2 to be in [0, pi], - // so sinTheta2 is always positive. We can change the behavior and specify - // theta2 to be negative in [-pi, 0] with opt_Theta2IsNegative. - var signTheta2 = opt_theta2IsNegative ? -1 : 1; - if (sinTheta2 > goog.vec.EPSILON) { - euler[2] = Math.atan2(mat[2] * signTheta2, mat[6] * signTheta2); - euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]); - euler[0] = Math.atan2(mat[8] * signTheta2, -mat[9] * signTheta2); - } else { - // There is also an arbitrary choice for theta1 = 0 or theta2 = 0 here. - // We assume theta1 = 0 as some applications do not allow the camera to roll - // (i.e. have theta1 != 0). - euler[0] = 0; - euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]); - euler[2] = Math.atan2(mat[1], mat[0]); - } +/** + * @private + * @type {Object.<string, ol.proj.Projection>} + */ +ol.proj.projections_ = {}; - // Atan2 outputs angles in [-pi, pi] so we bring them back to [0, 2 * pi]. - euler[0] = (euler[0] + Math.PI * 2) % (Math.PI * 2); - euler[2] = (euler[2] + Math.PI * 2) % (Math.PI * 2); - // For theta2 we want the angle to be in [0, pi] or [-pi, 0] depending on - // signTheta2. - euler[1] = ((euler[1] * signTheta2 + Math.PI * 2) % (Math.PI * 2)) * - signTheta2; - return euler; -}; +/** + * @private + * @type {Object.<string, Object.<string, ol.TransformFunction>>} + */ +ol.proj.transforms_ = {}; /** - * Translates the given matrix by x,y,z. Equvialent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeTranslate(goog.vec.Mat4.create(), x, y, z), - * mat); + * Registers transformation functions that don't alter coordinates. Those allow + * to transform between projections with equal meaning. * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The translation along the x axis. - * @param {number} y The translation along the y axis. - * @param {number} z The translation along the z axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @param {Array.<ol.proj.Projection>} projections Projections. + * @api */ -goog.vec.Mat4.translate = function(mat, x, y, z) { - return goog.vec.Mat4.setColumnValues( - mat, 3, - mat[0] * x + mat[4] * y + mat[8] * z + mat[12], - mat[1] * x + mat[5] * y + mat[9] * z + mat[13], - mat[2] * x + mat[6] * y + mat[10] * z + mat[14], - mat[3] * x + mat[7] * y + mat[11] * z + mat[15]); +ol.proj.addEquivalentProjections = function(projections) { + ol.proj.addProjections(projections); + projections.forEach(function(source) { + projections.forEach(function(destination) { + if (source !== destination) { + ol.proj.addTransform(source, destination, ol.proj.cloneTransform); + } + }); + }); }; /** - * Scales the given matrix by x,y,z. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeScale(goog.vec.Mat4.create(), x, y, z), - * mat); + * Registers transformation functions to convert coordinates in any projection + * in projection1 to any projection in projection2. * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} x The x scale factor. - * @param {number} y The y scale factor. - * @param {number} z The z scale factor. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @param {Array.<ol.proj.Projection>} projections1 Projections with equal + * meaning. + * @param {Array.<ol.proj.Projection>} projections2 Projections with equal + * meaning. + * @param {ol.TransformFunction} forwardTransform Transformation from any + * projection in projection1 to any projection in projection2. + * @param {ol.TransformFunction} inverseTransform Transform from any projection + * in projection2 to any projection in projection1.. */ -goog.vec.Mat4.scale = function(mat, x, y, z) { - return goog.vec.Mat4.setFromValues( - mat, - mat[0] * x, mat[1] * x, mat[2] * x, mat[3] * x, - mat[4] * y, mat[5] * y, mat[6] * y, mat[7] * y, - mat[8] * z, mat[9] * z, mat[10] * z, mat[11] * z, - mat[12], mat[13], mat[14], mat[15]); +ol.proj.addEquivalentTransforms = + function(projections1, projections2, forwardTransform, inverseTransform) { + projections1.forEach(function(projection1) { + projections2.forEach(function(projection2) { + ol.proj.addTransform(projection1, projection2, forwardTransform); + ol.proj.addTransform(projection2, projection1, inverseTransform); + }); + }); }; /** - * Rotate the given matrix by angle about the x,y,z axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotate(goog.vec.Mat4.create(), angle, x, y, z), - * mat); + * Add a Projection object to the list of supported projections that can be + * looked up by their code. * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @param {number} x The x component of the rotation axis. - * @param {number} y The y component of the rotation axis. - * @param {number} z The z component of the rotation axis. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @param {ol.proj.Projection} projection Projection instance. + * @api stable */ -goog.vec.Mat4.rotate = function(mat, angle, x, y, z) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15]; +ol.proj.addProjection = function(projection) { + ol.proj.projections_[projection.getCode()] = projection; + ol.proj.addTransform(projection, projection, ol.proj.cloneTransform); +}; - var cosAngle = Math.cos(angle); - var sinAngle = Math.sin(angle); - var diffCosAngle = 1 - cosAngle; - var r00 = x * x * diffCosAngle + cosAngle; - var r10 = x * y * diffCosAngle + z * sinAngle; - var r20 = x * z * diffCosAngle - y * sinAngle; - var r01 = x * y * diffCosAngle - z * sinAngle; - var r11 = y * y * diffCosAngle + cosAngle; - var r21 = y * z * diffCosAngle + x * sinAngle; - - var r02 = x * z * diffCosAngle + y * sinAngle; - var r12 = y * z * diffCosAngle - x * sinAngle; - var r22 = z * z * diffCosAngle + cosAngle; - - return goog.vec.Mat4.setFromValues( - mat, - m00 * r00 + m01 * r10 + m02 * r20, - m10 * r00 + m11 * r10 + m12 * r20, - m20 * r00 + m21 * r10 + m22 * r20, - m30 * r00 + m31 * r10 + m32 * r20, - - m00 * r01 + m01 * r11 + m02 * r21, - m10 * r01 + m11 * r11 + m12 * r21, - m20 * r01 + m21 * r11 + m22 * r21, - m30 * r01 + m31 * r11 + m32 * r21, - - m00 * r02 + m01 * r12 + m02 * r22, - m10 * r02 + m11 * r12 + m12 * r22, - m20 * r02 + m21 * r12 + m22 * r22, - m30 * r02 + m31 * r12 + m32 * r22, - - m03, m13, m23, m33); -}; +/** + * @param {Array.<ol.proj.Projection>} projections Projections. + */ +ol.proj.addProjections = function(projections) { + var addedProjections = []; + projections.forEach(function(projection) { + addedProjections.push(ol.proj.addProjection(projection)); + }); +}; /** - * Rotate the given matrix by angle about the x axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotateX(goog.vec.Mat4.create(), angle), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * FIXME empty description for jsdoc */ -goog.vec.Mat4.rotateX = function(mat, angle) { - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - - var c = Math.cos(angle); - var s = Math.sin(angle); - - mat[4] = m01 * c + m02 * s; - mat[5] = m11 * c + m12 * s; - mat[6] = m21 * c + m22 * s; - mat[7] = m31 * c + m32 * s; - mat[8] = m01 * -s + m02 * c; - mat[9] = m11 * -s + m12 * c; - mat[10] = m21 * -s + m22 * c; - mat[11] = m31 * -s + m32 * c; - - return mat; +ol.proj.clearAllProjections = function() { + ol.proj.projections_ = {}; + ol.proj.transforms_ = {}; }; /** - * Rotate the given matrix by angle about the y axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotateY(goog.vec.Mat4.create(), angle), - * mat); - * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @param {ol.proj.Projection|string|undefined} projection Projection. + * @param {string} defaultCode Default code. + * @return {ol.proj.Projection} Projection. */ -goog.vec.Mat4.rotateY = function(mat, angle) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11]; - - var c = Math.cos(angle); - var s = Math.sin(angle); - - mat[0] = m00 * c + m02 * -s; - mat[1] = m10 * c + m12 * -s; - mat[2] = m20 * c + m22 * -s; - mat[3] = m30 * c + m32 * -s; - mat[8] = m00 * s + m02 * c; - mat[9] = m10 * s + m12 * c; - mat[10] = m20 * s + m22 * c; - mat[11] = m30 * s + m32 * c; - - return mat; +ol.proj.createProjection = function(projection, defaultCode) { + if (!projection) { + return ol.proj.get(defaultCode); + } else if (goog.isString(projection)) { + return ol.proj.get(projection); + } else { + goog.asserts.assertInstanceof(projection, ol.proj.Projection, + 'projection should be an ol.proj.Projection'); + return projection; + } }; /** - * Rotate the given matrix by angle about the z axis. Equivalent to: - * goog.vec.Mat4.multMat( - * mat, - * goog.vec.Mat4.makeRotateZ(goog.vec.Mat4.create(), angle), - * mat); + * Registers a conversion function to convert coordinates from the source + * projection to the destination projection. * - * @param {goog.vec.Mat4.AnyType} mat The matrix. - * @param {number} angle The angle in radians. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @param {ol.proj.Projection} source Source. + * @param {ol.proj.Projection} destination Destination. + * @param {ol.TransformFunction} transformFn Transform. */ -goog.vec.Mat4.rotateZ = function(mat, angle) { - var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3]; - var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7]; - - var c = Math.cos(angle); - var s = Math.sin(angle); - - mat[0] = m00 * c + m01 * s; - mat[1] = m10 * c + m11 * s; - mat[2] = m20 * c + m21 * s; - mat[3] = m30 * c + m31 * s; - mat[4] = m00 * -s + m01 * c; - mat[5] = m10 * -s + m11 * c; - mat[6] = m20 * -s + m21 * c; - mat[7] = m30 * -s + m31 * c; - - return mat; +ol.proj.addTransform = function(source, destination, transformFn) { + var sourceCode = source.getCode(); + var destinationCode = destination.getCode(); + var transforms = ol.proj.transforms_; + if (!goog.object.containsKey(transforms, sourceCode)) { + transforms[sourceCode] = {}; + } + transforms[sourceCode][destinationCode] = transformFn; }; /** - * Retrieves the translation component of the transformation matrix. + * Registers coordinate transform functions to convert coordinates between the + * source projection and the destination projection. + * The forward and inverse functions convert coordinate pairs; this function + * converts these into the functions used internally which also handle + * extents and coordinate arrays. * - * @param {goog.vec.Mat4.AnyType} mat The transformation matrix. - * @param {goog.vec.Vec3.AnyType} translation The vector for storing the - * result. - * @return {goog.vec.Mat4.AnyType} return mat so that operations can be - * chained. + * @param {ol.proj.ProjectionLike} source Source projection. + * @param {ol.proj.ProjectionLike} destination Destination projection. + * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform + * function (that is, from the source projection to the destination + * projection) that takes a {@link ol.Coordinate} as argument and returns + * the transformed {@link ol.Coordinate}. + * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform + * function (that is, from the destination projection to the source + * projection) that takes a {@link ol.Coordinate} as argument and returns + * the transformed {@link ol.Coordinate}. + * @api stable */ -goog.vec.Mat4.getTranslation = function(mat, translation) { - translation[0] = mat[12]; - translation[1] = mat[13]; - translation[2] = mat[14]; - return translation; +ol.proj.addCoordinateTransforms = + function(source, destination, forward, inverse) { + var sourceProj = ol.proj.get(source); + var destProj = ol.proj.get(destination); + ol.proj.addTransform(sourceProj, destProj, + ol.proj.createTransformFromCoordinateTransform(forward)); + ol.proj.addTransform(destProj, sourceProj, + ol.proj.createTransformFromCoordinateTransform(inverse)); }; /** - * @type {!Array<!goog.vec.Vec3.Type>} - * @private - */ -goog.vec.Mat4.tmpVec3_ = [ - goog.vec.Vec3.createFloat64(), - goog.vec.Vec3.createFloat64() -]; - - -/** - * @type {!Array<!goog.vec.Vec4.Type>} - * @private - */ -goog.vec.Mat4.tmpVec4_ = [ - goog.vec.Vec4.createFloat64(), - goog.vec.Vec4.createFloat64(), - goog.vec.Vec4.createFloat64() -]; - - -/** - * @type {!Array<!goog.vec.Mat4.Type>} - * @private + * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform + * function. + * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate + * transform. + * @return {ol.TransformFunction} Transform function. */ -goog.vec.Mat4.tmpMat4_ = [ - goog.vec.Mat4.createFloat64() -]; - -goog.provide('ol.TransformFunction'); +ol.proj.createTransformFromCoordinateTransform = function(transform) { + return ( + /** + * @param {Array.<number>} input Input. + * @param {Array.<number>=} opt_output Output. + * @param {number=} opt_dimension Dimension. + * @return {Array.<number>} Output. + */ + function(input, opt_output, opt_dimension) { + var length = input.length; + var dimension = opt_dimension !== undefined ? opt_dimension : 2; + var output = opt_output !== undefined ? opt_output : new Array(length); + var point, i, j; + for (i = 0; i < length; i += dimension) { + point = transform([input[i], input[i + 1]]); + output[i] = point[0]; + output[i + 1] = point[1]; + for (j = dimension - 1; j >= 2; --j) { + output[i + j] = input[i + j]; + } + } + return output; + }); +}; /** - * A transform function accepts an array of input coordinate values, an optional - * output array, and an optional dimension (default should be 2). The function - * transforms the input coordinate values, populates the output array, and - * returns the output array. + * Unregisters the conversion function to convert coordinates from the source + * projection to the destination projection. This method is used to clean up + * cached transforms during testing. * - * @typedef {function(Array.<number>, Array.<number>=, number=): Array.<number>} - * @api stable + * @param {ol.proj.Projection} source Source projection. + * @param {ol.proj.Projection} destination Destination projection. + * @return {ol.TransformFunction} transformFn The unregistered transform. */ -ol.TransformFunction; - -goog.provide('ol.Extent'); -goog.provide('ol.extent'); -goog.provide('ol.extent.Corner'); -goog.provide('ol.extent.Relationship'); - -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Coordinate'); -goog.require('ol.Size'); -goog.require('ol.TransformFunction'); +ol.proj.removeTransform = function(source, destination) { + var sourceCode = source.getCode(); + var destinationCode = destination.getCode(); + var transforms = ol.proj.transforms_; + goog.asserts.assert(sourceCode in transforms, + 'sourceCode should be in transforms'); + goog.asserts.assert(destinationCode in transforms[sourceCode], + 'destinationCode should be in transforms of sourceCode'); + var transform = transforms[sourceCode][destinationCode]; + delete transforms[sourceCode][destinationCode]; + if (goog.object.isEmpty(transforms[sourceCode])) { + delete transforms[sourceCode]; + } + return transform; +}; /** - * An array of numbers representing an extent: `[minx, miny, maxx, maxy]`. - * @typedef {Array.<number>} + * Transforms a coordinate from longitude/latitude to a different projection. + * @param {ol.Coordinate} coordinate Coordinate as longitude and latitude, i.e. + * an array with longitude as 1st and latitude as 2nd element. + * @param {ol.proj.ProjectionLike=} opt_projection Target projection. The + * default is Web Mercator, i.e. 'EPSG:3857'. + * @return {ol.Coordinate} Coordinate projected to the target projection. * @api stable */ -ol.Extent; +ol.proj.fromLonLat = function(coordinate, opt_projection) { + return ol.proj.transform(coordinate, 'EPSG:4326', + opt_projection !== undefined ? opt_projection : 'EPSG:3857'); +}; /** - * Extent corner. - * @enum {string} + * Transforms a coordinate to longitude/latitude. + * @param {ol.Coordinate} coordinate Projected coordinate. + * @param {ol.proj.ProjectionLike=} opt_projection Projection of the coordinate. + * The default is Web Mercator, i.e. 'EPSG:3857'. + * @return {ol.Coordinate} Coordinate as longitude and latitude, i.e. an array + * with longitude as 1st and latitude as 2nd element. + * @api stable */ -ol.extent.Corner = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_RIGHT: 'bottom-right', - TOP_LEFT: 'top-left', - TOP_RIGHT: 'top-right' +ol.proj.toLonLat = function(coordinate, opt_projection) { + return ol.proj.transform(coordinate, + opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326'); }; /** - * Relationship to an extent. - * @enum {number} + * Fetches a Projection object for the code specified. + * + * @param {ol.proj.ProjectionLike} projectionLike Either a code string which is + * a combination of authority and identifier such as "EPSG:4326", or an + * existing projection object, or undefined. + * @return {ol.proj.Projection} Projection object, or null if not in list. + * @api stable */ -ol.extent.Relationship = { - UNKNOWN: 0, - INTERSECTING: 1, - ABOVE: 2, - RIGHT: 4, - BELOW: 8, - LEFT: 16 +ol.proj.get = function(projectionLike) { + var projection; + if (projectionLike instanceof ol.proj.Projection) { + projection = projectionLike; + } else if (goog.isString(projectionLike)) { + var code = projectionLike; + projection = ol.proj.projections_[code]; + if (ol.ENABLE_PROJ4JS && projection === undefined && + typeof proj4 == 'function' && proj4.defs(code) !== undefined) { + projection = new ol.proj.Projection({code: code}); + ol.proj.addProjection(projection); + } + } else { + projection = null; + } + return projection; }; /** - * Build an extent that includes all given coordinates. + * Checks if two projections are the same, that is every coordinate in one + * projection does represent the same geographic point as the same coordinate in + * the other projection. * - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @return {ol.Extent} Bounding extent. - * @api stable + * @param {ol.proj.Projection} projection1 Projection 1. + * @param {ol.proj.Projection} projection2 Projection 2. + * @return {boolean} Equivalent. */ -ol.extent.boundingExtent = function(coordinates) { - var extent = ol.extent.createEmpty(); - for (var i = 0, ii = coordinates.length; i < ii; ++i) { - ol.extent.extendCoordinate(extent, coordinates[i]); +ol.proj.equivalent = function(projection1, projection2) { + if (projection1 === projection2) { + return true; + } else if (projection1.getCode() === projection2.getCode()) { + return projection1.getUnits() === projection2.getUnits(); + } else { + var transformFn = ol.proj.getTransformFromProjections( + projection1, projection2); + return transformFn === ol.proj.cloneTransform; } - return extent; }; /** - * @param {Array.<number>} xs Xs. - * @param {Array.<number>} ys Ys. - * @param {ol.Extent=} opt_extent Destination extent. - * @private - * @return {ol.Extent} Extent. + * Given the projection-like objects, searches for a transformation + * function to convert a coordinates array from the source projection to the + * destination projection. + * + * @param {ol.proj.ProjectionLike} source Source. + * @param {ol.proj.ProjectionLike} destination Destination. + * @return {ol.TransformFunction} Transform function. + * @api stable */ -ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) { - goog.asserts.assert(xs.length > 0, 'xs length should be larger than 0'); - goog.asserts.assert(ys.length > 0, 'ys length should be larger than 0'); - var minX = Math.min.apply(null, xs); - var minY = Math.min.apply(null, ys); - var maxX = Math.max.apply(null, xs); - var maxY = Math.max.apply(null, ys); - return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); +ol.proj.getTransform = function(source, destination) { + var sourceProjection = ol.proj.get(source); + var destinationProjection = ol.proj.get(destination); + return ol.proj.getTransformFromProjections( + sourceProjection, destinationProjection); }; /** - * Return extent increased by the provided value. - * @param {ol.Extent} extent Extent. - * @param {number} value The amount by which the extent should be buffered. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - * @api stable + * Searches in the list of transform functions for the function for converting + * coordinates from the source projection to the destination projection. + * + * @param {ol.proj.Projection} sourceProjection Source Projection object. + * @param {ol.proj.Projection} destinationProjection Destination Projection + * object. + * @return {ol.TransformFunction} Transform function. */ -ol.extent.buffer = function(extent, value, opt_extent) { - if (opt_extent) { - opt_extent[0] = extent[0] - value; - opt_extent[1] = extent[1] - value; - opt_extent[2] = extent[2] + value; - opt_extent[3] = extent[3] + value; - return opt_extent; - } else { - return [ - extent[0] - value, - extent[1] - value, - extent[2] + value, - extent[3] + value - ]; +ol.proj.getTransformFromProjections = + function(sourceProjection, destinationProjection) { + var transforms = ol.proj.transforms_; + var sourceCode = sourceProjection.getCode(); + var destinationCode = destinationProjection.getCode(); + var transform; + if (goog.object.containsKey(transforms, sourceCode) && + goog.object.containsKey(transforms[sourceCode], destinationCode)) { + transform = transforms[sourceCode][destinationCode]; + } + if (transform === undefined) { + goog.asserts.assert(transform !== undefined, 'transform should be defined'); + transform = ol.proj.identityTransform; } + return transform; }; /** - * Creates a clone of an extent. - * - * @param {ol.Extent} extent Extent to clone. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} The clone. + * @param {Array.<number>} input Input coordinate array. + * @param {Array.<number>=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension. + * @return {Array.<number>} Input coordinate array (same array as input). */ -ol.extent.clone = function(extent, opt_extent) { - if (opt_extent) { - opt_extent[0] = extent[0]; - opt_extent[1] = extent[1]; - opt_extent[2] = extent[2]; - opt_extent[3] = extent[3]; - return opt_extent; - } else { - return extent.slice(); +ol.proj.identityTransform = function(input, opt_output, opt_dimension) { + if (opt_output !== undefined && input !== opt_output) { + // TODO: consider making this a warning instead + goog.asserts.fail('This should not be used internally.'); + for (var i = 0, ii = input.length; i < ii; ++i) { + opt_output[i] = input[i]; + } + input = opt_output; } + return input; }; /** - * @param {ol.Extent} extent Extent. - * @param {number} x X. - * @param {number} y Y. - * @return {number} Closest squared distance. + * @param {Array.<number>} input Input coordinate array. + * @param {Array.<number>=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension. + * @return {Array.<number>} Output coordinate array (new array, same coordinate + * values). */ -ol.extent.closestSquaredDistanceXY = function(extent, x, y) { - var dx, dy; - if (x < extent[0]) { - dx = extent[0] - x; - } else if (extent[2] < x) { - dx = x - extent[2]; - } else { - dx = 0; - } - if (y < extent[1]) { - dy = extent[1] - y; - } else if (extent[3] < y) { - dy = y - extent[3]; +ol.proj.cloneTransform = function(input, opt_output, opt_dimension) { + var output; + if (opt_output !== undefined) { + for (var i = 0, ii = input.length; i < ii; ++i) { + opt_output[i] = input[i]; + } + output = opt_output; } else { - dy = 0; + output = input.slice(); } - return dx * dx + dy * dy; + return output; }; /** - * Check if the passed coordinate is contained or on the edge of the extent. + * Transforms a coordinate from source projection to destination projection. + * This returns a new coordinate (and does not modify the original). + * + * See {@link ol.proj.transformExtent} for extent transformation. + * See the transform method of {@link ol.geom.Geometry} and its subclasses for + * geometry transforms. * - * @param {ol.Extent} extent Extent. * @param {ol.Coordinate} coordinate Coordinate. - * @return {boolean} The coordinate is contained in the extent. + * @param {ol.proj.ProjectionLike} source Source projection-like. + * @param {ol.proj.ProjectionLike} destination Destination projection-like. + * @return {ol.Coordinate} Coordinate. * @api stable */ -ol.extent.containsCoordinate = function(extent, coordinate) { - return ol.extent.containsXY(extent, coordinate[0], coordinate[1]); +ol.proj.transform = function(coordinate, source, destination) { + var transformFn = ol.proj.getTransform(source, destination); + return transformFn(coordinate, undefined, coordinate.length); }; /** - * Check if one extent contains another. - * - * An extent is deemed contained if it lies completely within the other extent, - * including if they share one or more edges. + * Transforms an extent from source projection to destination projection. This + * returns a new extent (and does not modify the original). * - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} The second extent is contained by or on the edge of the - * first. + * @param {ol.Extent} extent The extent to transform. + * @param {ol.proj.ProjectionLike} source Source projection-like. + * @param {ol.proj.ProjectionLike} destination Destination projection-like. + * @return {ol.Extent} The transformed extent. * @api stable */ -ol.extent.containsExtent = function(extent1, extent2) { - return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] && - extent1[1] <= extent2[1] && extent2[3] <= extent1[3]; +ol.proj.transformExtent = function(extent, source, destination) { + var transformFn = ol.proj.getTransform(source, destination); + return ol.extent.applyTransform(extent, transformFn); }; /** - * Check if the passed coordinate is contained or on the edge of the extent. + * Transforms the given point to the destination projection. * - * @param {ol.Extent} extent Extent. - * @param {number} x X coordinate. - * @param {number} y Y coordinate. - * @return {boolean} The x, y values are contained in the extent. - * @api stable + * @param {ol.Coordinate} point Point. + * @param {ol.proj.Projection} sourceProjection Source projection. + * @param {ol.proj.Projection} destinationProjection Destination projection. + * @return {ol.Coordinate} Point. */ -ol.extent.containsXY = function(extent, x, y) { - return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3]; +ol.proj.transformWithProjections = + function(point, sourceProjection, destinationProjection) { + var transformFn = ol.proj.getTransformFromProjections( + sourceProjection, destinationProjection); + return transformFn(point); }; +goog.provide('ol.source.Source'); +goog.provide('ol.source.State'); + +goog.require('ol'); +goog.require('ol.Attribution'); +goog.require('ol.Object'); +goog.require('ol.proj'); + /** - * Get the relationship between a coordinate and extent. - * @param {ol.Extent} extent The extent. - * @param {ol.Coordinate} coordinate The coordinate. - * @return {number} The relationship (bitwise compare with - * ol.extent.Relationship). + * State of the source, one of 'undefined', 'loading', 'ready' or 'error'. + * @enum {string} + * @api */ -ol.extent.coordinateRelationship = function(extent, coordinate) { - var minX = extent[0]; - var minY = extent[1]; - var maxX = extent[2]; - var maxY = extent[3]; - var x = coordinate[0]; - var y = coordinate[1]; - var relationship = ol.extent.Relationship.UNKNOWN; - if (x < minX) { - relationship = relationship | ol.extent.Relationship.LEFT; - } else if (x > maxX) { - relationship = relationship | ol.extent.Relationship.RIGHT; - } - if (y < minY) { - relationship = relationship | ol.extent.Relationship.BELOW; - } else if (y > maxY) { - relationship = relationship | ol.extent.Relationship.ABOVE; - } - if (relationship === ol.extent.Relationship.UNKNOWN) { - relationship = ol.extent.Relationship.INTERSECTING; - } - return relationship; +ol.source.State = { + UNDEFINED: 'undefined', + LOADING: 'loading', + READY: 'ready', + ERROR: 'error' }; /** - * Create an empty extent. - * @return {ol.Extent} Empty extent. + * @typedef {{attributions: (Array.<ol.Attribution>|undefined), + * logo: (string|olx.LogoOptions|undefined), + * projection: ol.proj.ProjectionLike, + * state: (ol.source.State|undefined), + * wrapX: (boolean|undefined)}} + */ +ol.source.SourceOptions; + + + +/** + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for {@link ol.layer.Layer} sources. + * + * A generic `change` event is triggered when the state of the source changes. + * + * @constructor + * @extends {ol.Object} + * @param {ol.source.SourceOptions} options Source options. * @api stable */ -ol.extent.createEmpty = function() { - return [Infinity, Infinity, -Infinity, -Infinity]; +ol.source.Source = function(options) { + + goog.base(this); + + /** + * @private + * @type {ol.proj.Projection} + */ + this.projection_ = ol.proj.get(options.projection); + + /** + * @private + * @type {Array.<ol.Attribution>} + */ + this.attributions_ = options.attributions !== undefined ? + options.attributions : null; + + /** + * @private + * @type {string|olx.LogoOptions|undefined} + */ + this.logo_ = options.logo; + + /** + * @private + * @type {ol.source.State} + */ + this.state_ = options.state !== undefined ? + options.state : ol.source.State.READY; + + /** + * @private + * @type {boolean} + */ + this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false; + }; +goog.inherits(ol.source.Source, ol.Object); /** - * Create a new extent or update the provided extent. - * @param {number} minX Minimum X. - * @param {number} minY Minimum Y. - * @param {number} maxX Maximum X. - * @param {number} maxY Maximum Y. - * @param {ol.Extent=} opt_extent Destination extent. - * @return {ol.Extent} Extent. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {Object.<string, boolean>} skippedFeatureUids Skipped feature uids. + * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature + * callback. + * @return {T|undefined} Callback result. + * @template T */ -ol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) { - if (opt_extent) { - opt_extent[0] = minX; - opt_extent[1] = minY; - opt_extent[2] = maxX; - opt_extent[3] = maxY; - return opt_extent; - } else { - return [minX, minY, maxX, maxY]; - } -}; +ol.source.Source.prototype.forEachFeatureAtCoordinate = ol.nullFunction; /** - * Create a new empty extent or make the provided one empty. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. + * Get the attributions of the source. + * @return {Array.<ol.Attribution>} Attributions. + * @api stable */ -ol.extent.createOrUpdateEmpty = function(opt_extent) { - return ol.extent.createOrUpdate( - Infinity, Infinity, -Infinity, -Infinity, opt_extent); +ol.source.Source.prototype.getAttributions = function() { + return this.attributions_; }; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. + * Get the logo of the source. + * @return {string|olx.LogoOptions|undefined} Logo. + * @api stable */ -ol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) { - var x = coordinate[0]; - var y = coordinate[1]; - return ol.extent.createOrUpdate(x, y, x, y, opt_extent); +ol.source.Source.prototype.getLogo = function() { + return this.logo_; }; /** - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. + * Get the projection of the source. + * @return {ol.proj.Projection} Projection. + * @api */ -ol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) { - var extent = ol.extent.createOrUpdateEmpty(opt_extent); - return ol.extent.extendCoordinates(extent, coordinates); +ol.source.Source.prototype.getProjection = function() { + return this.projection_; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. + * @return {Array.<number>|undefined} Resolutions. */ -ol.extent.createOrUpdateFromFlatCoordinates = - function(flatCoordinates, offset, end, stride, opt_extent) { - var extent = ol.extent.createOrUpdateEmpty(opt_extent); - return ol.extent.extendFlatCoordinates( - extent, flatCoordinates, offset, end, stride); -}; +ol.source.Source.prototype.getResolutions = goog.abstractMethod; /** - * @param {Array.<Array.<ol.Coordinate>>} rings Rings. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. + * Get the state of the source, see {@link ol.source.State} for possible states. + * @return {ol.source.State} State. + * @api */ -ol.extent.createOrUpdateFromRings = function(rings, opt_extent) { - var extent = ol.extent.createOrUpdateEmpty(opt_extent); - return ol.extent.extendRings(extent, rings); +ol.source.Source.prototype.getState = function() { + return this.state_; }; /** - * Empty an extent in place. - * @param {ol.Extent} extent Extent. - * @return {ol.Extent} Extent. + * @return {boolean|undefined} Wrap X. */ -ol.extent.empty = function(extent) { - extent[0] = extent[1] = Infinity; - extent[2] = extent[3] = -Infinity; - return extent; +ol.source.Source.prototype.getWrapX = function() { + return this.wrapX_; }; /** - * Determine if two extents are equivalent. - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} The two extents are equivalent. - * @api stable + * Set the attributions of the source. + * @param {Array.<ol.Attribution>} attributions Attributions. + * @api */ -ol.extent.equals = function(extent1, extent2) { - return extent1[0] == extent2[0] && extent1[2] == extent2[2] && - extent1[1] == extent2[1] && extent1[3] == extent2[3]; +ol.source.Source.prototype.setAttributions = function(attributions) { + this.attributions_ = attributions; + this.changed(); }; /** - * Modify an extent to include another extent. - * @param {ol.Extent} extent1 The extent to be modified. - * @param {ol.Extent} extent2 The extent that will be included in the first. - * @return {ol.Extent} A reference to the first (extended) extent. - * @api stable + * Set the logo of the source. + * @param {string|olx.LogoOptions|undefined} logo Logo. */ -ol.extent.extend = function(extent1, extent2) { - if (extent2[0] < extent1[0]) { - extent1[0] = extent2[0]; - } - if (extent2[2] > extent1[2]) { - extent1[2] = extent2[2]; - } - if (extent2[1] < extent1[1]) { - extent1[1] = extent2[1]; - } - if (extent2[3] > extent1[3]) { - extent1[3] = extent2[3]; - } - return extent1; +ol.source.Source.prototype.setLogo = function(logo) { + this.logo_ = logo; }; /** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} coordinate Coordinate. + * Set the state of the source. + * @param {ol.source.State} state State. + * @protected */ -ol.extent.extendCoordinate = function(extent, coordinate) { - if (coordinate[0] < extent[0]) { - extent[0] = coordinate[0]; - } - if (coordinate[0] > extent[2]) { - extent[2] = coordinate[0]; - } - if (coordinate[1] < extent[1]) { - extent[1] = coordinate[1]; - } - if (coordinate[1] > extent[3]) { - extent[3] = coordinate[1]; - } +ol.source.Source.prototype.setState = function(state) { + this.state_ = state; + this.changed(); }; /** - * @param {ol.Extent} extent Extent. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @return {ol.Extent} Extent. + * Set the projection of the source. + * @param {ol.proj.Projection} projection Projection. */ -ol.extent.extendCoordinates = function(extent, coordinates) { - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - ol.extent.extendCoordinate(extent, coordinates[i]); - } - return extent; +ol.source.Source.prototype.setProjection = function(projection) { + this.projection_ = projection; }; +goog.provide('ol.layer.Base'); +goog.provide('ol.layer.LayerProperty'); +goog.provide('ol.layer.LayerState'); + +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Object'); +goog.require('ol.math'); +goog.require('ol.source.State'); + /** - * @param {ol.Extent} extent Extent. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {ol.Extent} Extent. + * @enum {string} */ -ol.extent.extendFlatCoordinates = - function(extent, flatCoordinates, offset, end, stride) { - for (; offset < end; offset += stride) { - ol.extent.extendXY( - extent, flatCoordinates[offset], flatCoordinates[offset + 1]); - } - return extent; +ol.layer.LayerProperty = { + OPACITY: 'opacity', + VISIBLE: 'visible', + EXTENT: 'extent', + Z_INDEX: 'zIndex', + MAX_RESOLUTION: 'maxResolution', + MIN_RESOLUTION: 'minResolution', + SOURCE: 'source' }; /** - * @param {ol.Extent} extent Extent. - * @param {Array.<Array.<ol.Coordinate>>} rings Rings. - * @return {ol.Extent} Extent. + * @typedef {{layer: ol.layer.Layer, + * opacity: number, + * sourceState: ol.source.State, + * visible: boolean, + * managed: boolean, + * extent: (ol.Extent|undefined), + * zIndex: number, + * maxResolution: number, + * minResolution: number}} */ -ol.extent.extendRings = function(extent, rings) { - var i, ii; - for (i = 0, ii = rings.length; i < ii; ++i) { - ol.extent.extendCoordinates(extent, rings[i]); - } - return extent; -}; +ol.layer.LayerState; + /** - * @param {ol.Extent} extent Extent. - * @param {number} x X. - * @param {number} y Y. + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Note that with `ol.layer.Base` and all its subclasses, any property set in + * the options is set as a {@link ol.Object} property on the layer object, so + * is observable, and has get/set accessors. + * + * @constructor + * @extends {ol.Object} + * @param {olx.layer.BaseOptions} options Layer options. + * @api stable */ -ol.extent.extendXY = function(extent, x, y) { - extent[0] = Math.min(extent[0], x); - extent[1] = Math.min(extent[1], y); - extent[2] = Math.max(extent[2], x); - extent[3] = Math.max(extent[3], y); +ol.layer.Base = function(options) { + + goog.base(this); + + /** + * @type {Object.<string, *>} + */ + var properties = goog.object.clone(options); + properties[ol.layer.LayerProperty.OPACITY] = + options.opacity !== undefined ? options.opacity : 1; + properties[ol.layer.LayerProperty.VISIBLE] = + options.visible !== undefined ? options.visible : true; + properties[ol.layer.LayerProperty.Z_INDEX] = + options.zIndex !== undefined ? options.zIndex : 0; + properties[ol.layer.LayerProperty.MAX_RESOLUTION] = + options.maxResolution !== undefined ? options.maxResolution : Infinity; + properties[ol.layer.LayerProperty.MIN_RESOLUTION] = + options.minResolution !== undefined ? options.minResolution : 0; + + this.setProperties(properties); }; +goog.inherits(ol.layer.Base, ol.Object); /** - * This function calls `callback` for each corner of the extent. If the - * callback returns a truthy value the function returns that value - * immediately. Otherwise the function returns `false`. - * @param {ol.Extent} extent Extent. - * @param {function(this:T, ol.Coordinate): S} callback Callback. - * @param {T=} opt_this Value to use as `this` when executing `callback`. - * @return {S|boolean} Value. - * @template S, T + * @return {ol.layer.LayerState} Layer state. */ -ol.extent.forEachCorner = function(extent, callback, opt_this) { - var val; - val = callback.call(opt_this, ol.extent.getBottomLeft(extent)); - if (val) { - return val; - } - val = callback.call(opt_this, ol.extent.getBottomRight(extent)); - if (val) { - return val; - } - val = callback.call(opt_this, ol.extent.getTopRight(extent)); - if (val) { - return val; - } - val = callback.call(opt_this, ol.extent.getTopLeft(extent)); - if (val) { - return val; - } - return false; +ol.layer.Base.prototype.getLayerState = function() { + var opacity = this.getOpacity(); + var sourceState = this.getSourceState(); + var visible = this.getVisible(); + var extent = this.getExtent(); + var zIndex = this.getZIndex(); + var maxResolution = this.getMaxResolution(); + var minResolution = this.getMinResolution(); + return { + layer: /** @type {ol.layer.Layer} */ (this), + opacity: ol.math.clamp(opacity, 0, 1), + sourceState: sourceState, + visible: visible, + managed: true, + extent: extent, + zIndex: zIndex, + maxResolution: maxResolution, + minResolution: Math.max(minResolution, 0) + }; }; /** - * @param {ol.Extent} extent Extent. - * @return {number} Area. + * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be + * modified in place). + * @return {Array.<ol.layer.Layer>} Array of layers. */ -ol.extent.getArea = function(extent) { - var area = 0; - if (!ol.extent.isEmpty(extent)) { - area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent); - } - return area; -}; +ol.layer.Base.prototype.getLayersArray = goog.abstractMethod; /** - * Get the bottom left coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Bottom left coordinate. + * @param {Array.<ol.layer.LayerState>=} opt_states Optional list of layer + * states (to be modified in place). + * @return {Array.<ol.layer.LayerState>} List of layer states. + */ +ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod; + + +/** + * Return the {@link ol.Extent extent} of the layer or `undefined` if it + * will be visible regardless of extent. + * @return {ol.Extent|undefined} The layer extent. + * @observable * @api stable */ -ol.extent.getBottomLeft = function(extent) { - return [extent[0], extent[1]]; +ol.layer.Base.prototype.getExtent = function() { + return /** @type {ol.Extent|undefined} */ ( + this.get(ol.layer.LayerProperty.EXTENT)); }; /** - * Get the bottom right coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Bottom right coordinate. + * Return the maximum resolution of the layer. + * @return {number} The maximum resolution of the layer. + * @observable * @api stable */ -ol.extent.getBottomRight = function(extent) { - return [extent[2], extent[1]]; +ol.layer.Base.prototype.getMaxResolution = function() { + return /** @type {number} */ ( + this.get(ol.layer.LayerProperty.MAX_RESOLUTION)); }; /** - * Get the center coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Center. + * Return the minimum resolution of the layer. + * @return {number} The minimum resolution of the layer. + * @observable * @api stable */ -ol.extent.getCenter = function(extent) { - return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2]; +ol.layer.Base.prototype.getMinResolution = function() { + return /** @type {number} */ ( + this.get(ol.layer.LayerProperty.MIN_RESOLUTION)); }; /** - * Get a corner coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @param {ol.extent.Corner} corner Corner. - * @return {ol.Coordinate} Corner coordinate. + * Return the opacity of the layer (between 0 and 1). + * @return {number} The opacity of the layer. + * @observable + * @api stable */ -ol.extent.getCorner = function(extent, corner) { - var coordinate; - if (corner === ol.extent.Corner.BOTTOM_LEFT) { - coordinate = ol.extent.getBottomLeft(extent); - } else if (corner === ol.extent.Corner.BOTTOM_RIGHT) { - coordinate = ol.extent.getBottomRight(extent); - } else if (corner === ol.extent.Corner.TOP_LEFT) { - coordinate = ol.extent.getTopLeft(extent); - } else if (corner === ol.extent.Corner.TOP_RIGHT) { - coordinate = ol.extent.getTopRight(extent); - } else { - goog.asserts.fail('Invalid corner: %s', corner); - } - goog.asserts.assert(coordinate, 'coordinate should be defined'); - return coordinate; +ol.layer.Base.prototype.getOpacity = function() { + return /** @type {number} */ (this.get(ol.layer.LayerProperty.OPACITY)); }; /** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {number} Enlarged area. - */ -ol.extent.getEnlargedArea = function(extent1, extent2) { - var minX = Math.min(extent1[0], extent2[0]); - var minY = Math.min(extent1[1], extent2[1]); - var maxX = Math.max(extent1[2], extent2[2]); - var maxY = Math.max(extent1[3], extent2[3]); - return (maxX - minX) * (maxY - minY); -}; - - -/** - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {ol.Extent=} opt_extent Destination extent. - * @return {ol.Extent} Extent. + * @return {ol.source.State} Source state. */ -ol.extent.getForViewAndSize = - function(center, resolution, rotation, size, opt_extent) { - var dx = resolution * size[0] / 2; - var dy = resolution * size[1] / 2; - var cosRotation = Math.cos(rotation); - var sinRotation = Math.sin(rotation); - /** @type {Array.<number>} */ - var xs = [-dx, -dx, dx, dx]; - /** @type {Array.<number>} */ - var ys = [-dy, dy, -dy, dy]; - var i, x, y; - for (i = 0; i < 4; ++i) { - x = xs[i]; - y = ys[i]; - xs[i] = center[0] + x * cosRotation - y * sinRotation; - ys[i] = center[1] + x * sinRotation + y * cosRotation; - } - return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); -}; +ol.layer.Base.prototype.getSourceState = goog.abstractMethod; /** - * Get the height of an extent. - * @param {ol.Extent} extent Extent. - * @return {number} Height. + * Return the visibility of the layer (`true` or `false`). + * @return {boolean} The visibility of the layer. + * @observable * @api stable */ -ol.extent.getHeight = function(extent) { - return extent[3] - extent[1]; +ol.layer.Base.prototype.getVisible = function() { + return /** @type {boolean} */ (this.get(ol.layer.LayerProperty.VISIBLE)); }; /** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {number} Intersection area. + * Return the Z-index of the layer, which is used to order layers before + * rendering. The default Z-index is 0. + * @return {number} The Z-index of the layer. + * @observable + * @api */ -ol.extent.getIntersectionArea = function(extent1, extent2) { - var intersection = ol.extent.getIntersection(extent1, extent2); - return ol.extent.getArea(intersection); +ol.layer.Base.prototype.getZIndex = function() { + return /** @type {number} */ (this.get(ol.layer.LayerProperty.Z_INDEX)); }; /** - * Get the intersection of two extents. - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @param {ol.Extent=} opt_extent Optional extent to populate with intersection. - * @return {ol.Extent} Intersecting extent. + * Set the extent at which the layer is visible. If `undefined`, the layer + * will be visible at all extents. + * @param {ol.Extent|undefined} extent The extent of the layer. + * @observable * @api stable */ -ol.extent.getIntersection = function(extent1, extent2, opt_extent) { - var intersection = opt_extent ? opt_extent : ol.extent.createEmpty(); - if (ol.extent.intersects(extent1, extent2)) { - if (extent1[0] > extent2[0]) { - intersection[0] = extent1[0]; - } else { - intersection[0] = extent2[0]; - } - if (extent1[1] > extent2[1]) { - intersection[1] = extent1[1]; - } else { - intersection[1] = extent2[1]; - } - if (extent1[2] < extent2[2]) { - intersection[2] = extent1[2]; - } else { - intersection[2] = extent2[2]; - } - if (extent1[3] < extent2[3]) { - intersection[3] = extent1[3]; - } else { - intersection[3] = extent2[3]; - } - } - return intersection; +ol.layer.Base.prototype.setExtent = function(extent) { + this.set(ol.layer.LayerProperty.EXTENT, extent); }; /** - * @param {ol.Extent} extent Extent. - * @return {number} Margin. + * Set the maximum resolution at which the layer is visible. + * @param {number} maxResolution The maximum resolution of the layer. + * @observable + * @api stable */ -ol.extent.getMargin = function(extent) { - return ol.extent.getWidth(extent) + ol.extent.getHeight(extent); +ol.layer.Base.prototype.setMaxResolution = function(maxResolution) { + this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution); }; /** - * Get the size (width, height) of an extent. - * @param {ol.Extent} extent The extent. - * @return {ol.Size} The extent size. + * Set the minimum resolution at which the layer is visible. + * @param {number} minResolution The minimum resolution of the layer. + * @observable * @api stable */ -ol.extent.getSize = function(extent) { - return [extent[2] - extent[0], extent[3] - extent[1]]; +ol.layer.Base.prototype.setMinResolution = function(minResolution) { + this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution); }; /** - * Get the top left coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Top left coordinate. + * Set the opacity of the layer, allowed values range from 0 to 1. + * @param {number} opacity The opacity of the layer. + * @observable * @api stable */ -ol.extent.getTopLeft = function(extent) { - return [extent[0], extent[3]]; +ol.layer.Base.prototype.setOpacity = function(opacity) { + this.set(ol.layer.LayerProperty.OPACITY, opacity); }; /** - * Get the top right coordinate of an extent. - * @param {ol.Extent} extent Extent. - * @return {ol.Coordinate} Top right coordinate. + * Set the visibility of the layer (`true` or `false`). + * @param {boolean} visible The visibility of the layer. + * @observable * @api stable */ -ol.extent.getTopRight = function(extent) { - return [extent[2], extent[3]]; +ol.layer.Base.prototype.setVisible = function(visible) { + this.set(ol.layer.LayerProperty.VISIBLE, visible); }; /** - * Get the width of an extent. - * @param {ol.Extent} extent Extent. - * @return {number} Width. - * @api stable + * Set Z-index of the layer, which is used to order layers before rendering. + * The default Z-index is 0. + * @param {number} zindex The z-index of the layer. + * @observable + * @api */ -ol.extent.getWidth = function(extent) { - return extent[2] - extent[0]; +ol.layer.Base.prototype.setZIndex = function(zindex) { + this.set(ol.layer.LayerProperty.Z_INDEX, zindex); }; +goog.provide('ol.layer.Group'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol.Collection'); +goog.require('ol.CollectionEvent'); +goog.require('ol.CollectionEventType'); +goog.require('ol.Object'); +goog.require('ol.ObjectEventType'); +goog.require('ol.extent'); +goog.require('ol.layer.Base'); +goog.require('ol.source.State'); + /** - * Determine if one extent intersects another. - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent. - * @return {boolean} The two extents intersect. - * @api stable + * @enum {string} */ -ol.extent.intersects = function(extent1, extent2) { - return extent1[0] <= extent2[2] && - extent1[2] >= extent2[0] && - extent1[1] <= extent2[3] && - extent1[3] >= extent2[1]; +ol.layer.GroupProperty = { + LAYERS: 'layers' }; + /** - * Determine if an extent is empty. - * @param {ol.Extent} extent Extent. - * @return {boolean} Is empty. + * @classdesc + * A {@link ol.Collection} of layers that are handled together. + * + * A generic `change` event is triggered when the group/Collection changes. + * + * @constructor + * @extends {ol.layer.Base} + * @param {olx.layer.GroupOptions=} opt_options Layer options. * @api stable */ -ol.extent.isEmpty = function(extent) { - return extent[2] < extent[0] || extent[3] < extent[1]; -}; +ol.layer.Group = function(opt_options) { + var options = opt_options || {}; + var baseOptions = /** @type {olx.layer.GroupOptions} */ + (goog.object.clone(options)); + delete baseOptions.layers; -/** - * @param {ol.Extent} extent Extent. - * @return {boolean} Is infinite. - */ -ol.extent.isInfinite = function(extent) { - return extent[0] == -Infinity || extent[1] == -Infinity || - extent[2] == Infinity || extent[3] == Infinity; -}; + var layers = options.layers; + goog.base(this, baseOptions); -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate} Coordinate. - */ -ol.extent.normalize = function(extent, coordinate) { - return [ - (coordinate[0] - extent[0]) / (extent[2] - extent[0]), - (coordinate[1] - extent[1]) / (extent[3] - extent[1]) - ]; -}; + /** + * @private + * @type {Array.<goog.events.Key>} + */ + this.layersListenerKeys_ = []; + /** + * @private + * @type {Object.<string, Array.<goog.events.Key>>} + */ + this.listenerKeys_ = {}; -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} Extent. - */ -ol.extent.returnOrUpdate = function(extent, opt_extent) { - if (opt_extent) { - opt_extent[0] = extent[0]; - opt_extent[1] = extent[1]; - opt_extent[2] = extent[2]; - opt_extent[3] = extent[3]; - return opt_extent; + goog.events.listen(this, + ol.Object.getChangeEventType(ol.layer.GroupProperty.LAYERS), + this.handleLayersChanged_, false, this); + + if (layers) { + if (goog.isArray(layers)) { + layers = new ol.Collection(layers.slice()); + } else { + goog.asserts.assertInstanceof(layers, ol.Collection, + 'layers should be an ol.Collection'); + layers = layers; + } } else { - return extent; + layers = new ol.Collection(); } -}; + this.setLayers(layers); -/** - * @param {ol.Extent} extent Extent. - * @param {number} value Value. - */ -ol.extent.scaleFromCenter = function(extent, value) { - var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1); - var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1); - extent[0] -= deltaX; - extent[2] += deltaX; - extent[1] -= deltaY; - extent[3] += deltaY; }; +goog.inherits(ol.layer.Group, ol.layer.Base); /** - * Determine if the segment between two coordinates intersects (crosses, - * touches, or is contained by) the provided extent. - * @param {ol.Extent} extent The extent. - * @param {ol.Coordinate} start Segment start coordinate. - * @param {ol.Coordinate} end Segment end coordinate. - * @return {boolean} The segment intersects the extent. + * @private */ -ol.extent.intersectsSegment = function(extent, start, end) { - var intersects = false; - var startRel = ol.extent.coordinateRelationship(extent, start); - var endRel = ol.extent.coordinateRelationship(extent, end); - if (startRel === ol.extent.Relationship.INTERSECTING || - endRel === ol.extent.Relationship.INTERSECTING) { - intersects = true; - } else { - var minX = extent[0]; - var minY = extent[1]; - var maxX = extent[2]; - var maxY = extent[3]; - var startX = start[0]; - var startY = start[1]; - var endX = end[0]; - var endY = end[1]; - var slope = (endY - startY) / (endX - startX); - var x, y; - if (!!(endRel & ol.extent.Relationship.ABOVE) && - !(startRel & ol.extent.Relationship.ABOVE)) { - // potentially intersects top - x = endX - ((endY - maxY) / slope); - intersects = x >= minX && x <= maxX; - } - if (!intersects && !!(endRel & ol.extent.Relationship.RIGHT) && - !(startRel & ol.extent.Relationship.RIGHT)) { - // potentially intersects right - y = endY - ((endX - maxX) * slope); - intersects = y >= minY && y <= maxY; - } - if (!intersects && !!(endRel & ol.extent.Relationship.BELOW) && - !(startRel & ol.extent.Relationship.BELOW)) { - // potentially intersects bottom - x = endX - ((endY - minY) / slope); - intersects = x >= minX && x <= maxX; - } - if (!intersects && !!(endRel & ol.extent.Relationship.LEFT) && - !(startRel & ol.extent.Relationship.LEFT)) { - // potentially intersects left - y = endY - ((endX - minX) * slope); - intersects = y >= minY && y <= maxY; - } - +ol.layer.Group.prototype.handleLayerChange_ = function() { + if (this.getVisible()) { + this.changed(); } - return intersects; }; /** - * @param {ol.Extent} extent1 Extent 1. - * @param {ol.Extent} extent2 Extent 2. - * @return {boolean} Touches. + * @param {goog.events.Event} event Event. + * @private */ -ol.extent.touches = function(extent1, extent2) { - var intersects = ol.extent.intersects(extent1, extent2); - return intersects && - (extent1[0] == extent2[2] || extent1[2] == extent2[0] || - extent1[1] == extent2[3] || extent1[3] == extent2[1]); +ol.layer.Group.prototype.handleLayersChanged_ = function(event) { + this.layersListenerKeys_.forEach(goog.events.unlistenByKey); + this.layersListenerKeys_.length = 0; + + var layers = this.getLayers(); + this.layersListenerKeys_.push( + goog.events.listen(layers, ol.CollectionEventType.ADD, + this.handleLayersAdd_, false, this), + goog.events.listen(layers, ol.CollectionEventType.REMOVE, + this.handleLayersRemove_, false, this)); + + goog.object.forEach(this.listenerKeys_, function(keys) { + keys.forEach(goog.events.unlistenByKey); + }); + goog.object.clear(this.listenerKeys_); + + var layersArray = layers.getArray(); + var i, ii, layer; + for (i = 0, ii = layersArray.length; i < ii; i++) { + layer = layersArray[i]; + this.listenerKeys_[goog.getUid(layer).toString()] = [ + goog.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE, + this.handleLayerChange_, false, this), + goog.events.listen(layer, goog.events.EventType.CHANGE, + this.handleLayerChange_, false, this) + ]; + } + + this.changed(); }; /** - * Apply a transform function to the extent. - * @param {ol.Extent} extent Extent. - * @param {ol.TransformFunction} transformFn Transform function. Called with - * [minX, minY, maxX, maxY] extent coordinates. - * @param {ol.Extent=} opt_extent Destination extent. - * @return {ol.Extent} Extent. - * @api stable + * @param {ol.CollectionEvent} collectionEvent Collection event. + * @private */ -ol.extent.applyTransform = function(extent, transformFn, opt_extent) { - var coordinates = [ - extent[0], extent[1], - extent[0], extent[3], - extent[2], extent[1], - extent[2], extent[3] +ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) { + var layer = /** @type {ol.layer.Base} */ (collectionEvent.element); + var key = goog.getUid(layer).toString(); + goog.asserts.assert(!(key in this.listenerKeys_), + 'listeners already registered'); + this.listenerKeys_[key] = [ + goog.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE, + this.handleLayerChange_, false, this), + goog.events.listen(layer, goog.events.EventType.CHANGE, + this.handleLayerChange_, false, this) ]; - transformFn(coordinates, coordinates, 2); - var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]]; - var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]]; - return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); + this.changed(); }; /** - * Apply a 2d transform to an extent. - * @param {ol.Extent} extent Input extent. - * @param {goog.vec.Mat4.Number} transform The transform matrix. - * @param {ol.Extent=} opt_extent Optional extent for return values. - * @return {ol.Extent} The transformed extent. + * @param {ol.CollectionEvent} collectionEvent Collection event. + * @private */ -ol.extent.transform2D = function(extent, transform, opt_extent) { - var dest = opt_extent ? opt_extent : []; - var m00 = goog.vec.Mat4.getElement(transform, 0, 0); - var m10 = goog.vec.Mat4.getElement(transform, 1, 0); - var m01 = goog.vec.Mat4.getElement(transform, 0, 1); - var m11 = goog.vec.Mat4.getElement(transform, 1, 1); - var m03 = goog.vec.Mat4.getElement(transform, 0, 3); - var m13 = goog.vec.Mat4.getElement(transform, 1, 3); - var xi = [0, 2, 0, 2]; - var yi = [1, 1, 3, 3]; - var xs = []; - var ys = []; - var i, x, y; - for (i = 0; i < 4; ++i) { - x = extent[xi[i]]; - y = extent[yi[i]]; - xs[i] = m00 * x + m01 * y + m03; - ys[i] = m10 * x + m11 * y + m13; - } - dest[0] = Math.min.apply(null, xs); - dest[1] = Math.min.apply(null, ys); - dest[2] = Math.max.apply(null, xs); - dest[3] = Math.max.apply(null, ys); - return dest; +ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) { + var layer = /** @type {ol.layer.Base} */ (collectionEvent.element); + var key = goog.getUid(layer).toString(); + goog.asserts.assert(key in this.listenerKeys_, 'no listeners to unregister'); + this.listenerKeys_[key].forEach(goog.events.unlistenByKey); + delete this.listenerKeys_[key]; + this.changed(); }; -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utilities for creating functions. Loosely inspired by the - * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8. - * - * @author nicksantos@google.com (Nick Santos) + * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers} + * in this group. + * @return {!ol.Collection.<ol.layer.Base>} Collection of + * {@link ol.layer.Base layers} that are part of this group. + * @observable + * @api stable */ - - -goog.provide('goog.functions'); +ol.layer.Group.prototype.getLayers = function() { + return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get( + ol.layer.GroupProperty.LAYERS)); +}; /** - * Creates a function that always returns the same value. - * @param {T} retValue The value to return. - * @return {function():T} The new function. - * @template T + * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers} + * in this group. + * @param {!ol.Collection.<ol.layer.Base>} layers Collection of + * {@link ol.layer.Base layers} that are part of this group. + * @observable + * @api stable */ -goog.functions.constant = function(retValue) { - return function() { - return retValue; - }; +ol.layer.Group.prototype.setLayers = function(layers) { + this.set(ol.layer.GroupProperty.LAYERS, layers); }; /** - * Always returns false. - * @type {function(...): boolean} + * @inheritDoc */ -goog.functions.FALSE = goog.functions.constant(false); +ol.layer.Group.prototype.getLayersArray = function(opt_array) { + var array = opt_array !== undefined ? opt_array : []; + this.getLayers().forEach(function(layer) { + layer.getLayersArray(array); + }); + return array; +}; /** - * Always returns true. - * @type {function(...): boolean} + * @inheritDoc */ -goog.functions.TRUE = goog.functions.constant(true); - +ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) { + var states = opt_states !== undefined ? opt_states : []; -/** - * Always returns NULL. - * @type {function(...): null} - */ -goog.functions.NULL = goog.functions.constant(null); + var pos = states.length; + this.getLayers().forEach(function(layer) { + layer.getLayerStatesArray(states); + }); -/** - * A simple function that returns the first argument of whatever is passed - * into it. - * @param {T=} opt_returnValue The single value that will be returned. - * @param {...*} var_args Optional trailing arguments. These are ignored. - * @return {T} The first argument passed in, or undefined if nothing was passed. - * @template T - */ -goog.functions.identity = function(opt_returnValue, var_args) { - return opt_returnValue; + var ownLayerState = this.getLayerState(); + var i, ii, layerState; + for (i = pos, ii = states.length; i < ii; i++) { + layerState = states[i]; + layerState.opacity *= ownLayerState.opacity; + layerState.visible = layerState.visible && ownLayerState.visible; + layerState.maxResolution = Math.min( + layerState.maxResolution, ownLayerState.maxResolution); + layerState.minResolution = Math.max( + layerState.minResolution, ownLayerState.minResolution); + if (ownLayerState.extent !== undefined) { + if (layerState.extent !== undefined) { + layerState.extent = ol.extent.getIntersection( + layerState.extent, ownLayerState.extent); + } else { + layerState.extent = ownLayerState.extent; + } + } + } + + return states; }; /** - * Creates a function that always throws an error with the given message. - * @param {string} message The error message. - * @return {!Function} The error-throwing function. + * @inheritDoc */ -goog.functions.error = function(message) { - return function() { - throw Error(message); - }; +ol.layer.Group.prototype.getSourceState = function() { + return ol.source.State.READY; }; +goog.provide('olcs.AbstractSynchronizer'); -/** - * Creates a function that throws the given object. - * @param {*} err An object to be thrown. - * @return {!Function} The error-throwing function. - */ -goog.functions.fail = function(err) { - return function() { - throw err; - } -}; +goog.require('goog.object'); +goog.require('ol.Observable'); +goog.require('ol.layer.Group'); -/** - * Given a function, create a function that keeps opt_numArgs arguments and - * silently discards all additional arguments. - * @param {Function} f The original function. - * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0. - * @return {!Function} A version of f that only keeps the first opt_numArgs - * arguments. - */ -goog.functions.lock = function(f, opt_numArgs) { - opt_numArgs = opt_numArgs || 0; - return function() { - return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs)); - }; -}; /** - * Creates a function that returns its nth argument. - * @param {number} n The position of the return argument. - * @return {!Function} A new function. + * @param {!ol.Map} map + * @param {!Cesium.Scene} scene + * @constructor + * @template T + * @struct + * @api */ -goog.functions.nth = function(n) { - return function() { - return arguments[n]; - }; +olcs.AbstractSynchronizer = function(map, scene) { + /** + * @type {!ol.Map} + * @protected + */ + this.map = map; + + /** + * @type {ol.View} + * @protected + */ + this.view = map.getView(); + + /** + * @type {!Cesium.Scene} + * @protected + */ + this.scene = scene; + + /** + * @type {ol.Collection.<ol.layer.Base>} + * @protected + */ + this.olLayers = map.getLayerGroup().getLayers(); + + /** + * @type {ol.layer.Group} + */ + this.mapLayerGroup = map.getLayerGroup(); + + /** + * Map of ol3 layer ids (from goog.getUid) to the Cesium ImageryLayers. + * Null value means, that we are unable to create equivalent layers. + * @type {Object.<number, ?Array.<T>>} + * @protected + */ + this.layerMap = {}; + + /** + * Map of listen keys for ol3 layer layers ids (from goog.getUid). + * @type {!Object.<number, goog.events.Key>} + * @private + */ + this.olLayerListenKeys_ = {}; + + /** + * Map of listen keys for ol3 layer groups ids (from goog.getUid). + * @type {!Object.<number, !Array.<goog.events.Key>>} + * @private + */ + this.olGroupListenKeys_ = {}; }; /** - * Given a function, create a new function that swallows its return value - * and replaces it with a new one. - * @param {Function} f A function. - * @param {T} retValue A new return value. - * @return {function(...?):T} A new function. - * @template T + * Destroy all and perform complete synchronization of the layers. + * @api */ -goog.functions.withReturnValue = function(f, retValue) { - return goog.functions.sequence(f, goog.functions.constant(retValue)); +olcs.AbstractSynchronizer.prototype.synchronize = function() { + this.destroyAll(); + this.addLayers_(this.mapLayerGroup); }; /** - * Creates a function that returns whether its arguement equals the given value. - * - * Example: - * var key = goog.object.findKey(obj, goog.functions.equalTo('needle')); - * - * @param {*} value The value to compare to. - * @param {boolean=} opt_useLooseComparison Whether to use a loose (==) - * comparison rather than a strict (===) one. Defaults to false. - * @return {function(*):boolean} The new function. + * Order counterparts using the same algorithm as the Openlayers renderer: + * z-index then original sequence order. + * @protected */ -goog.functions.equalTo = function(value, opt_useLooseComparison) { - return function(other) { - return opt_useLooseComparison ? (value == other) : (value === other); - }; +olcs.AbstractSynchronizer.prototype.orderLayers = function() { + // Ordering logics is handled in subclasses. }; /** - * Creates the composition of the functions passed in. - * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)). - * @param {function(...?):T} fn The final function. - * @param {...Function} var_args A list of functions. - * @return {function(...?):T} The composition of all inputs. - * @template T + * Add a layer hierarchy. + * @param {ol.layer.Base} root + * @private */ -goog.functions.compose = function(fn, var_args) { - var functions = arguments; - var length = functions.length; - return function() { - var result; - if (length) { - result = functions[length - 1].apply(this, arguments); +olcs.AbstractSynchronizer.prototype.addLayers_ = function(root) { + /** @type {Array.<!ol.layer.Base>} */ + var fifo = [root]; + while (fifo.length > 0) { + var olLayer = fifo.splice(0, 1)[0]; + var olLayerId = goog.getUid(olLayer); + goog.asserts.assert(!goog.isDef(this.layerMap[olLayerId])); + + var cesiumObjects = null; + if (olLayer instanceof ol.layer.Group) { + this.listenForGroupChanges_(olLayer); + cesiumObjects = this.createSingleLayerCounterparts(olLayer); + if (!cesiumObjects) { + olLayer.getLayers().forEach(function(l) { + fifo.push(l); + }); + } + } else { + cesiumObjects = this.createSingleLayerCounterparts(olLayer); } - for (var i = length - 2; i >= 0; i--) { - result = functions[i].call(this, result); + // add Cesium layers + if (!goog.isNull(cesiumObjects)) { + this.layerMap[olLayerId] = cesiumObjects; + this.olLayerListenKeys_[olLayerId] = olLayer.on('change:zIndex', + this.orderLayers, this); + cesiumObjects.forEach(function(cesiumObject) { + this.addCesiumObject(cesiumObject); + }, this); } - return result; - }; + } + + this.orderLayers(); }; /** - * Creates a function that calls the functions passed in in sequence, and - * returns the value of the last function. For example, - * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x). - * @param {...Function} var_args A list of functions. - * @return {!Function} A function that calls all inputs in sequence. + * Remove and destroy a single layer. + * @param {ol.layer.Layer} layer + * @return {boolean} counterpart destroyed + * @private */ -goog.functions.sequence = function(var_args) { - var functions = arguments; - var length = functions.length; - return function() { - var result; - for (var i = 0; i < length; i++) { - result = functions[i].apply(this, arguments); - } - return result; - }; +olcs.AbstractSynchronizer.prototype.removeAndDestroySingleLayer_ = + function(layer) { + var uid = goog.getUid(layer); + var counterparts = this.layerMap[uid]; + if (!!counterparts) { + counterparts.forEach(function(counterpart) { + this.removeSingleCesiumObject(counterpart, false); + this.destroyCesiumObject(counterpart); + }, this); + ol.Observable.unByKey(this.olLayerListenKeys_[uid]); + delete this.olLayerListenKeys_[uid]; + } + delete this.layerMap[uid]; + return !!counterparts; }; /** - * Creates a function that returns true if each of its components evaluates - * to true. The components are evaluated in order, and the evaluation will be - * short-circuited as soon as a function returns false. - * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x). - * @param {...Function} var_args A list of functions. - * @return {function(...?):boolean} A function that ANDs its component - * functions. + * Unlisten a single layer group. + * @param {ol.layer.Group} group + * @private */ -goog.functions.and = function(var_args) { - var functions = arguments; - var length = functions.length; - return function() { - for (var i = 0; i < length; i++) { - if (!functions[i].apply(this, arguments)) { - return false; - } - } - return true; - }; +olcs.AbstractSynchronizer.prototype.unlistenSingleGroup_ = + function(group) { + if (group === this.mapLayerGroup) { + return; + } + var uid = goog.getUid(group); + var keys = this.olGroupListenKeys_[uid]; + keys.forEach(function(key) { + ol.Observable.unByKey(key); + }); + delete this.olGroupListenKeys_[uid]; + delete this.layerMap[uid]; }; /** - * Creates a function that returns true if any of its components evaluates - * to true. The components are evaluated in order, and the evaluation will be - * short-circuited as soon as a function returns true. - * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x). - * @param {...Function} var_args A list of functions. - * @return {function(...?):boolean} A function that ORs its component - * functions. + * Remove layer hierarchy. + * @param {ol.layer.Base} root + * @private */ -goog.functions.or = function(var_args) { - var functions = arguments; - var length = functions.length; - return function() { - for (var i = 0; i < length; i++) { - if (functions[i].apply(this, arguments)) { - return true; +olcs.AbstractSynchronizer.prototype.removeLayer_ = function(root) { + if (!!root) { + var fifo = [root]; + while (fifo.length > 0) { + var olLayer = fifo.splice(0, 1)[0]; + var done = this.removeAndDestroySingleLayer_(olLayer); + if (olLayer instanceof ol.layer.Group) { + this.unlistenSingleGroup_(olLayer); + if (done) { + olLayer.getLayers().forEach(function(l) { + fifo.push(l); + }); + } } } - return false; - }; + } }; /** - * Creates a function that returns the Boolean opposite of a provided function. - * For example, (goog.functions.not(f))(x) is equivalent to !f(x). - * @param {!Function} f The original function. - * @return {function(...?):boolean} A function that delegates to f and returns - * opposite. + * Register listeners for single layer group change. + * @param {ol.layer.Group} group + * @private */ -goog.functions.not = function(f) { - return function() { - return !f.apply(this, arguments); - }; -}; +olcs.AbstractSynchronizer.prototype.listenForGroupChanges_ = function(group) { + var uuid = goog.getUid(group); + goog.asserts.assert(!goog.isDef(this.olGroupListenKeys_[uuid])); -/** - * Generic factory function to construct an object given the constructor - * and the arguments. Intended to be bound to create object factories. - * - * Example: - * - * var factory = goog.partial(goog.functions.create, Class); - * - * @param {function(new:T, ...)} constructor The constructor for the Object. - * @param {...*} var_args The arguments to be passed to the constructor. - * @return {T} A new instance of the class given in {@code constructor}. - * @template T - */ -goog.functions.create = function(constructor, var_args) { - /** - * @constructor - * @final - */ - var temp = function() {}; - temp.prototype = constructor.prototype; + var listenKeyArray = []; + this.olGroupListenKeys_[uuid] = listenKeyArray; - // obj will have constructor's prototype in its chain and - // 'obj instanceof constructor' will be true. - var obj = new temp(); + // only the keys that need to be relistened when collection changes + var contentKeys = []; + var listenAddRemove = (function() { + var collection = group.getLayers(); + if (goog.isDef(collection)) { + contentKeys = [ + collection.on('add', function(event) { + this.addLayers_(event.element); + }, this), + collection.on('remove', function(event) { + this.removeLayer_(event.element); + }, this) + ]; + listenKeyArray.push.apply(listenKeyArray, contentKeys); + } + }).bind(this); - // obj is initialized by constructor. - // arguments is only array-like so lacks shift(), but can be used with - // the Array prototype function. - constructor.apply(obj, Array.prototype.slice.call(arguments, 1)); - return obj; + listenAddRemove(); + + listenKeyArray.push(group.on('change:layers', function(e) { + contentKeys.forEach(function(el) { + var i = listenKeyArray.indexOf(el); + if (i >= 0) { + listenKeyArray.splice(i, 1); + } + ol.Observable.unByKey(el); + }); + listenAddRemove(); + })); }; /** - * @define {boolean} Whether the return value cache should be used. - * This should only be used to disable caches when testing. + * Destroys all the created Cesium objects. + * @protected */ -goog.define('goog.functions.CACHE_RETURN_VALUE', true); +olcs.AbstractSynchronizer.prototype.destroyAll = function() { + this.removeAllCesiumObjects(true); // destroy + goog.object.forEach(this.olGroupListenKeys_, function(keys) { + keys.forEach(ol.Observable.unByKey); + }); + goog.object.forEach(this.olLayerListenKeys_, ol.Observable.unByKey); + this.olGroupListenKeys_ = {}; + this.olLayerListenKeys_ = {}; + this.layerMap = {}; +}; /** - * Gives a wrapper function that caches the return value of a parameterless - * function when first called. - * - * When called for the first time, the given function is called and its - * return value is cached (thus this is only appropriate for idempotent - * functions). Subsequent calls will return the cached return value. This - * allows the evaluation of expensive functions to be delayed until first used. - * - * To cache the return values of functions with parameters, see goog.memoize. - * - * @param {!function():T} fn A function to lazily evaluate. - * @return {!function():T} A wrapped version the function. - * @template T + * Adds a single Cesium object to the collection. + * @param {!T} object + * @protected */ -goog.functions.cacheReturnValue = function(fn) { - var called = false; - var value; - - return function() { - if (!goog.functions.CACHE_RETURN_VALUE) { - return fn(); - } +olcs.AbstractSynchronizer.prototype.addCesiumObject = goog.abstractMethod; - if (!called) { - value = fn(); - called = true; - } - return value; - } -}; +/** + * @param {!T} object + * @protected + */ +olcs.AbstractSynchronizer.prototype.destroyCesiumObject = goog.abstractMethod; /** - * Wraps a function to allow it to be called, at most, once. All - * additional calls are no-ops. - * - * This is particularly useful for initialization functions - * that should be called, at most, once. - * - * @param {function():*} f Function to call. - * @return {function():undefined} Wrapped function. + * Remove single Cesium object from the collection. + * @param {!T} object + * @param {boolean} destroy + * @protected */ -goog.functions.once = function(f) { - // Keep a reference to the function that we null out when we're done with - // it -- that way, the function can be GC'd when we're done with it. - var inner = f; - return function() { - if (inner) { - var tmp = inner; - inner = null; - tmp(); - } - }; -}; +olcs.AbstractSynchronizer.prototype.removeSingleCesiumObject = + goog.abstractMethod; /** - * Wraps a function to allow it to be called, at most, once for each sequence of - * calls fired repeatedly so long as they are fired less than a specified - * interval apart (in milliseconds). Whether it receives one signal or multiple, - * it will always wait until a full interval has elapsed since the last signal - * before performing the action. - * - * This is particularly useful for bulking up repeated user actions (e.g. only - * refreshing a view once a user finishes typing rather than updating with every - * keystroke). For more stateful debouncing with support for pausing, resuming, - * and canceling debounced actions, use {@code goog.async.Debouncer}. - * - * @param {function(this:SCOPE):*} f Function to call. - * @param {number} interval Interval over which to debounce. The function will - * only be called after the full interval has elapsed since the last call. - * @param {SCOPE=} opt_scope Object in whose scope to call the function. - * @return {function():undefined} Wrapped function. - * @template SCOPE + * Remove all Cesium objects from the collection. + * @param {boolean} destroy + * @protected */ -goog.functions.debounce = function(f, interval, opt_scope) { - if (opt_scope) { - f = goog.bind(f, opt_scope); - } - var timeout = null; - return function() { - goog.global.clearTimeout(timeout); - timeout = goog.global.setTimeout(f, interval); - }; -}; +olcs.AbstractSynchronizer.prototype.removeAllCesiumObjects = + goog.abstractMethod; /** - * Wraps a function to allow it to be called, at most, once per interval - * (specified in milliseconds). If it is called multiple times while it is - * waiting, it will only perform the action once at the end of the interval. - * - * This is particularly useful for limiting repeated user requests (e.g. - * preventing a user from spamming a server with frequent view refreshes). For - * more stateful throttling with support for pausing, resuming, and canceling - * throttled actions, use {@code goog.async.Throttle}. - * - * @param {function(this:SCOPE):*} f Function to call. - * @param {number} interval Interval over which to throttle. The function can - * only be called once per interval. - * @param {SCOPE=} opt_scope Object in whose scope to call the function. - * @return {function():undefined} Wrapped function. - * @template SCOPE - */ -goog.functions.throttle = function(f, interval, opt_scope) { - if (opt_scope) { - f = goog.bind(f, opt_scope); - } - var timeout = null; - var shouldFire = false; - var fire = function() { - timeout = goog.global.setTimeout(handleTimeout, interval); - f(); - }; - var handleTimeout = function() { - timeout = null; - if (shouldFire) { - shouldFire = false; - fire(); - } - }; - - return function() { - if (!timeout) { - fire(); - } else { - shouldFire = true; - } - }; -}; - -/** - * @license - * Latitude/longitude spherical geodesy formulae taken from - * http://www.movable-type.co.uk/scripts/latlong.html - * Licensed under CC-BY-3.0. + * @param {!ol.layer.Base} olLayer + * @return {?Array.<T>} + * @protected */ +olcs.AbstractSynchronizer.prototype.createSingleLayerCounterparts = + goog.abstractMethod; -goog.provide('ol.Sphere'); +// Apache v2 license +// https://github.com/TerriaJS/terriajs/blob/ +// ebd382a8278a817fce316730d9e459bbb9b829e9/lib/Models/Cesium.js -goog.require('ol.math'); +goog.provide('olcs.AutoRenderLoop'); /** - * @classdesc - * Class to create objects that can be used with {@link - * ol.geom.Polygon.circular}. - * - * For example to create a sphere whose radius is equal to the semi-major - * axis of the WGS84 ellipsoid: - * - * ```js - * var wgs84Sphere= new ol.Sphere(6378137); - * ``` - * * @constructor - * @param {number} radius Radius. - * @api + * @param {olcs.OLCesium} ol3d + * @param {boolean} debug + * @struct */ -ol.Sphere = function(radius) { +olcs.AutoRenderLoop = function(ol3d, debug) { + this.ol3d = ol3d; + this.scene_ = ol3d.getCesiumScene(); + this.verboseRendering = debug; + this._boundNotifyRepaintRequired = this.notifyRepaintRequired.bind(this); - /** - * @type {number} - */ - this.radius = radius; + this.lastCameraViewMatrix_ = new Cesium.Matrix4(); + this.lastCameraMoveTime_ = 0; + this.stoppedRendering = false; -}; + this._removePostRenderListener = this.scene_.postRender.addEventListener( + this.postRender.bind(this)); -/** - * Returns the geodesic area for a list of coordinates. - * - * [Reference](http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409) - * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for - * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion - * Laboratory, Pasadena, CA, June 2007 - * - * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear - * ring. If the ring is oriented clockwise, the area will be positive, - * otherwise it will be negative. - * @return {number} Area. - * @api - */ -ol.Sphere.prototype.geodesicArea = function(coordinates) { - var area = 0, len = coordinates.length; - var x1 = coordinates[len - 1][0]; - var y1 = coordinates[len - 1][1]; - for (var i = 0; i < len; i++) { - var x2 = coordinates[i][0], y2 = coordinates[i][1]; - area += ol.math.toRadians(x2 - x1) * - (2 + Math.sin(ol.math.toRadians(y1)) + - Math.sin(ol.math.toRadians(y2))); - x1 = x2; - y1 = y2; + // Detect available wheel event + this._wheelEvent = ''; + if ('onwheel' in this.scene_.canvas) { + // spec event type + this._wheelEvent = 'wheel'; + } else if (!!document['onmousewheel']) { + // legacy event type + this._wheelEvent = 'mousewheel'; + } else { + // older Firefox + this._wheelEvent = 'DOMMouseScroll'; } - return area * this.radius * this.radius / 2.0; + + this._originalLoadWithXhr = Cesium.loadWithXhr.load; + this._originalScheduleTask = Cesium.TaskProcessor.prototype.scheduleTask; + this._originalCameraSetView = Cesium.Camera.prototype.setView; + this._originalCameraMove = Cesium.Camera.prototype.move; + this._originalCameraRotate = Cesium.Camera.prototype.rotate; + this._originalCameraLookAt = Cesium.Camera.prototype.lookAt; + this._originalCameraFlyTo = Cesium.Camera.prototype.flyTo; + + this.enable(); }; /** - * Returns the distance from c1 to c2 using the haversine formula. - * - * @param {ol.Coordinate} c1 Coordinate 1. - * @param {ol.Coordinate} c2 Coordinate 2. - * @return {number} Haversine distance. - * @api + * Force a repaint when the mouse moves or the window changes size. + * @param {string} key + * @param {boolean} capture + * @private */ -ol.Sphere.prototype.haversineDistance = function(c1, c2) { - var lat1 = ol.math.toRadians(c1[1]); - var lat2 = ol.math.toRadians(c2[1]); - var deltaLatBy2 = (lat2 - lat1) / 2; - var deltaLonBy2 = ol.math.toRadians(c2[0] - c1[0]) / 2; - var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + - Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * - Math.cos(lat1) * Math.cos(lat2); - return 2 * this.radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); +olcs.AutoRenderLoop.prototype.repaintOn_ = function(key, capture) { + var canvas = this.scene_.canvas; + canvas.addEventListener(key, this._boundNotifyRepaintRequired, capture); }; /** - * Returns the coordinate at the given distance and bearing from `c1`. - * - * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees). - * @param {number} distance The great-circle distance between the origin - * point and the target point. - * @param {number} bearing The bearing (in radians). - * @return {ol.Coordinate} The target point. + * @param {string} key + * @param {boolean} capture + * @private */ -ol.Sphere.prototype.offset = function(c1, distance, bearing) { - var lat1 = ol.math.toRadians(c1[1]); - var lon1 = ol.math.toRadians(c1[0]); - var dByR = distance / this.radius; - var lat = Math.asin( - Math.sin(lat1) * Math.cos(dByR) + - Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing)); - var lon = lon1 + Math.atan2( - Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), - Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat)); - return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)]; +olcs.AutoRenderLoop.prototype.removeRepaintOn_ = function(key, capture) { + var canvas = this.scene_.canvas; + canvas.removeEventListener(key, this._boundNotifyRepaintRequired, capture); }; -goog.provide('ol.sphere.NORMAL'); - -goog.require('ol.Sphere'); - /** - * The normal sphere. - * @const - * @type {ol.Sphere} + * Enable. */ -ol.sphere.NORMAL = new ol.Sphere(6370997); +olcs.AutoRenderLoop.prototype.enable = function() { + this.repaintOn_('mousemove', false); + this.repaintOn_('mousedown', false); + this.repaintOn_('mouseup', false); + this.repaintOn_('touchstart', false); + this.repaintOn_('touchend', false); + this.repaintOn_('touchmove', false); -goog.provide('ol.proj'); -goog.provide('ol.proj.METERS_PER_UNIT'); -goog.provide('ol.proj.Projection'); -goog.provide('ol.proj.ProjectionLike'); -goog.provide('ol.proj.Units'); + if (!!window['PointerEvent']) { + this.repaintOn_('pointerdown', false); + this.repaintOn_('pointerup', false); + this.repaintOn_('pointermove', false); + } -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Extent'); -goog.require('ol.TransformFunction'); -goog.require('ol.extent'); -goog.require('ol.sphere.NORMAL'); + this.repaintOn_(this._wheelEvent, false); + window.addEventListener('resize', this._boundNotifyRepaintRequired, false); -/** - * A projection as {@link ol.proj.Projection}, SRS identifier string or - * undefined. - * @typedef {ol.proj.Projection|string|undefined} ol.proj.ProjectionLike - * @api stable - */ -ol.proj.ProjectionLike; + // Hacky way to force a repaint when an async load request completes + var that = this; + Cesium.loadWithXhr.load = function(url, responseType, method, data, + headers, deferred, overrideMimeType, preferText, timeout) { + deferred['promise']['always'](that._boundNotifyRepaintRequired); + that._originalLoadWithXhr(url, responseType, method, data, headers, + deferred, overrideMimeType, preferText, timeout); + }; + // Hacky way to force a repaint when a web worker sends something back. + Cesium.TaskProcessor.prototype.scheduleTask = + function(parameters, transferableObjects) { + var result = that._originalScheduleTask.call(this, parameters, + transferableObjects); -/** - * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or - * `'us-ft'`. - * @enum {string} - * @api stable - */ -ol.proj.Units = { - DEGREES: 'degrees', - FEET: 'ft', - METERS: 'm', - PIXELS: 'pixels', - TILE_PIXELS: 'tile-pixels', - USFEET: 'us-ft' + var taskProcessor = this; + if (!taskProcessor._originalWorkerMessageSinkRepaint) { + var worker = taskProcessor['_worker']; + taskProcessor._originalWorkerMessageSinkRepaint = worker.onmessage; + worker.onmessage = function(event) { + taskProcessor._originalWorkerMessageSinkRepaint(event); + that.notifyRepaintRequired(); + }; + } + + return result; + }; + + Cesium.Camera.prototype.setView = function() { + that._originalCameraSetView.apply(this, arguments); + that.notifyRepaintRequired(); + }; + Cesium.Camera.prototype.move = function() { + that._originalCameraMove.apply(this, arguments); + that.notifyRepaintRequired(); + }; + Cesium.Camera.prototype.rotate = function() { + that._originalCameraRotate.apply(this, arguments); + that.notifyRepaintRequired(); + }; + Cesium.Camera.prototype.lookAt = function() { + that._originalCameraLookAt.apply(this, arguments); + that.notifyRepaintRequired(); + }; + Cesium.Camera.prototype.flyTo = function() { + that._originalCameraFlyTo.apply(this, arguments); + that.notifyRepaintRequired(); + }; + + // Listen for changes on the layer group + this.ol3d.getOlMap().getLayerGroup().on('change', + this._boundNotifyRepaintRequired); }; /** - * Meters per unit lookup table. - * @const - * @type {Object.<ol.proj.Units, number>} - * @api stable + * Disable. */ -ol.proj.METERS_PER_UNIT = {}; -ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] = - 2 * Math.PI * ol.sphere.NORMAL.radius / 360; -ol.proj.METERS_PER_UNIT[ol.proj.Units.FEET] = 0.3048; -ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1; -ol.proj.METERS_PER_UNIT[ol.proj.Units.USFEET] = 1200 / 3937; +olcs.AutoRenderLoop.prototype.disable = function() { + if (!!this._removePostRenderListener) { + this._removePostRenderListener(); + this._removePostRenderListener = undefined; + } + this.removeRepaintOn_('mousemove', false); + this.removeRepaintOn_('mousedown', false); + this.removeRepaintOn_('mouseup', false); + this.removeRepaintOn_('touchstart', false); + this.removeRepaintOn_('touchend', false); + this.removeRepaintOn_('touchmove', false); + if (!!window['PointerEvent']) { + this.removeRepaintOn_('pointerdown', false); + this.removeRepaintOn_('pointerup', false); + this.removeRepaintOn_('pointermove', false); + } -/** - * @classdesc - * Projection definition class. One of these is created for each projection - * supported in the application and stored in the {@link ol.proj} namespace. - * You can use these in applications, but this is not required, as API params - * and options use {@link ol.proj.ProjectionLike} which means the simple string - * code will suffice. - * - * You can use {@link ol.proj.get} to retrieve the object for a particular - * projection. - * - * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together - * with the following aliases: - * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, - * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84, - * http://www.opengis.net/gml/srs/epsg.xml#4326, - * urn:x-ogc:def:crs:EPSG:4326 - * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913, - * urn:ogc:def:crs:EPSG:6.18:3:3857, - * http://www.opengis.net/gml/srs/epsg.xml#3857 - * - * If you use proj4js, aliases can be added using `proj4.defs()`; see - * [documentation](https://github.com/proj4js/proj4js). - * - * @constructor - * @param {olx.ProjectionOptions} options Projection options. - * @struct - * @api stable - */ -ol.proj.Projection = function(options) { + this.removeRepaintOn_(this._wheelEvent, false); - /** - * @private - * @type {string} - */ - this.code_ = options.code; + window.removeEventListener('resize', this._boundNotifyRepaintRequired, false); - /** - * @private - * @type {ol.proj.Units} - */ - this.units_ = /** @type {ol.proj.Units} */ (options.units); + Cesium.loadWithXhr.load = this._originalLoadWithXhr; + Cesium.TaskProcessor.prototype.scheduleTask = this._originalScheduleTask; + Cesium.Camera.prototype.setView = this._originalCameraSetView; + Cesium.Camera.prototype.move = this._originalCameraMove; + Cesium.Camera.prototype.rotate = this._originalCameraRotate; + Cesium.Camera.prototype.lookAt = this._originalCameraLookAt; + Cesium.Camera.prototype.flyTo = this._originalCameraFlyTo; - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = options.extent !== undefined ? options.extent : null; + this.ol3d.getOlMap().getLayerGroup().un('change', + this._boundNotifyRepaintRequired); +}; - /** - * @private - * @type {ol.Extent} - */ - this.worldExtent_ = options.worldExtent !== undefined ? - options.worldExtent : null; - /** - * @private - * @type {string} - */ - this.axisOrientation_ = options.axisOrientation !== undefined ? - options.axisOrientation : 'enu'; +/** + * @param {number} date + */ +olcs.AutoRenderLoop.prototype.postRender = function(date) { + // We can safely stop rendering when: + // - the camera position hasn't changed in over a second, + // - there are no tiles waiting to load, and + // - the clock is not animating + // - there are no tweens in progress - /** - * @private - * @type {boolean} - */ - this.global_ = options.global !== undefined ? options.global : false; + var now = Date.now(); + var scene = this.scene_; + var camera = scene.camera; - /** - * @private - * @type {boolean} - */ - this.canWrapX_ = !!(this.global_ && this.extent_); + if (!Cesium.Matrix4.equalsEpsilon(this.lastCameraViewMatrix_, + camera.viewMatrix, 1e-5)) { + this.lastCameraMoveTime_ = now; + } - /** - * @private - * @type {function(number, ol.Coordinate):number} - */ - this.getPointResolutionFunc_ = options.getPointResolution !== undefined ? - options.getPointResolution : this.getPointResolution_; + var cameraMovedInLastSecond = now - this.lastCameraMoveTime_ < 1000; - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.defaultTileGrid_ = null; + var surface = scene.globe['_surface']; + var tilesWaiting = !surface['_tileProvider'].ready || + surface['_tileLoadQueue'].length > 0 || + surface['_debug']['tilesWaitingForChildren'] > 0; - var projections = ol.proj.projections_; - var code = options.code; - goog.asserts.assert(code !== undefined, - 'Option "code" is required for constructing instance'); - if (ol.ENABLE_PROJ4JS && typeof proj4 == 'function' && - projections[code] === undefined) { - var def = proj4.defs(code); - if (def !== undefined) { - if (def.axis !== undefined && options.axisOrientation === undefined) { - this.axisOrientation_ = def.axis; - } - if (options.units === undefined) { - var units = def.units; - if (def.to_meter !== undefined) { - if (units === undefined || - ol.proj.METERS_PER_UNIT[units] === undefined) { - units = def.to_meter.toString(); - ol.proj.METERS_PER_UNIT[units] = def.to_meter; - } - } - this.units_ = units; - } - var currentCode, currentDef, currentProj, proj4Transform; - for (currentCode in projections) { - currentDef = proj4.defs(currentCode); - if (currentDef !== undefined) { - currentProj = ol.proj.get(currentCode); - if (currentDef === def) { - ol.proj.addEquivalentProjections([currentProj, this]); - } else { - proj4Transform = proj4(currentCode, code); - ol.proj.addCoordinateTransforms(currentProj, this, - proj4Transform.forward, proj4Transform.inverse); - } - } - } + var tweens = scene['tweens']; + if (!cameraMovedInLastSecond && !tilesWaiting && tweens.length == 0) { + if (this.verboseRendering) { + console.log('stopping rendering @ ' + Date.now()); } + this.ol3d.setBlockCesiumRendering(true); + this.stoppedRendering = true; } + Cesium.Matrix4.clone(camera.viewMatrix, this.lastCameraViewMatrix_); }; /** - * @return {boolean} The projection is suitable for wrapping the x-axis + * Restart render loop. + * Force a restart of the render loop. + * @api */ -ol.proj.Projection.prototype.canWrapX = function() { - return this.canWrapX_; +olcs.AutoRenderLoop.prototype.restartRenderLoop = function() { + this.notifyRepaintRequired(); }; /** - * Get the code for this projection, e.g. 'EPSG:4326'. - * @return {string} Code. - * @api stable + * Notifies the viewer that a repaint is required. */ -ol.proj.Projection.prototype.getCode = function() { - return this.code_; +olcs.AutoRenderLoop.prototype.notifyRepaintRequired = function() { + if (this.verboseRendering && this.stoppedRendering) { + console.log('starting rendering @ ' + Date.now()); + } + this.lastCameraMoveTime_ = Date.now(); + // TODO: do not unblock if not blocked by us + this.ol3d.setBlockCesiumRendering(false); + this.stoppedRendering = false; }; /** - * Get the validity extent for this projection. - * @return {ol.Extent} Extent. - * @api stable + * @param {boolean} debug + * @api */ -ol.proj.Projection.prototype.getExtent = function() { - return this.extent_; +olcs.AutoRenderLoop.prototype.setDebug = function(debug) { + this.verboseRendering = debug; }; +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Get the units of this projection. - * @return {ol.proj.Units} Units. - * @api stable + * @fileoverview Utilities for creating functions. Loosely inspired by the + * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8. + * + * @author nicksantos@google.com (Nick Santos) */ -ol.proj.Projection.prototype.getUnits = function() { - return this.units_; -}; -/** - * Get the amount of meters per unit of this projection. If the projection is - * not configured with a units identifier, the return is `undefined`. - * @return {number|undefined} Meters. - * @api stable - */ -ol.proj.Projection.prototype.getMetersPerUnit = function() { - return ol.proj.METERS_PER_UNIT[this.units_]; -}; +goog.provide('goog.functions'); /** - * Get the world extent for this projection. - * @return {ol.Extent} Extent. - * @api - */ -ol.proj.Projection.prototype.getWorldExtent = function() { - return this.worldExtent_; + * Creates a function that always returns the same value. + * @param {T} retValue The value to return. + * @return {function():T} The new function. + * @template T + */ +goog.functions.constant = function(retValue) { + return function() { + return retValue; + }; }; /** - * Get the axis orientation of this projection. - * Example values are: - * enu - the default easting, northing, elevation. - * neu - northing, easting, up - useful for "lat/long" geographic coordinates, - * or south orientated transverse mercator. - * wnu - westing, northing, up - some planetary coordinate systems have - * "west positive" coordinate systems - * @return {string} Axis orientation. + * Always returns false. + * @type {function(...): boolean} */ -ol.proj.Projection.prototype.getAxisOrientation = function() { - return this.axisOrientation_; -}; +goog.functions.FALSE = goog.functions.constant(false); /** - * Is this projection a global projection which spans the whole world? - * @return {boolean} Whether the projection is global. - * @api stable + * Always returns true. + * @type {function(...): boolean} */ -ol.proj.Projection.prototype.isGlobal = function() { - return this.global_; -}; +goog.functions.TRUE = goog.functions.constant(true); /** -* Set if the projection is a global projection which spans the whole world -* @param {boolean} global Whether the projection is global. -* @api stable -*/ -ol.proj.Projection.prototype.setGlobal = function(global) { - this.global_ = global; - this.canWrapX_ = !!(global && this.extent_); -}; + * Always returns NULL. + * @type {function(...): null} + */ +goog.functions.NULL = goog.functions.constant(null); /** - * @return {ol.tilegrid.TileGrid} The default tile grid. + * A simple function that returns the first argument of whatever is passed + * into it. + * @param {T=} opt_returnValue The single value that will be returned. + * @param {...*} var_args Optional trailing arguments. These are ignored. + * @return {T} The first argument passed in, or undefined if nothing was passed. + * @template T */ -ol.proj.Projection.prototype.getDefaultTileGrid = function() { - return this.defaultTileGrid_; +goog.functions.identity = function(opt_returnValue, var_args) { + return opt_returnValue; }; /** - * @param {ol.tilegrid.TileGrid} tileGrid The default tile grid. + * Creates a function that always throws an error with the given message. + * @param {string} message The error message. + * @return {!Function} The error-throwing function. */ -ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) { - this.defaultTileGrid_ = tileGrid; +goog.functions.error = function(message) { + return function() { + throw Error(message); + }; }; /** - * Set the validity extent for this projection. - * @param {ol.Extent} extent Extent. - * @api stable + * Creates a function that throws the given object. + * @param {*} err An object to be thrown. + * @return {!Function} The error-throwing function. */ -ol.proj.Projection.prototype.setExtent = function(extent) { - this.extent_ = extent; - this.canWrapX_ = !!(this.global_ && extent); +goog.functions.fail = function(err) { + return function() { + throw err; + } }; /** - * Set the world extent for this projection. - * @param {ol.Extent} worldExtent World extent - * [minlon, minlat, maxlon, maxlat]. - * @api + * Given a function, create a function that keeps opt_numArgs arguments and + * silently discards all additional arguments. + * @param {Function} f The original function. + * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0. + * @return {!Function} A version of f that only keeps the first opt_numArgs + * arguments. */ -ol.proj.Projection.prototype.setWorldExtent = function(worldExtent) { - this.worldExtent_ = worldExtent; +goog.functions.lock = function(f, opt_numArgs) { + opt_numArgs = opt_numArgs || 0; + return function() { + return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs)); + }; }; /** -* Set the getPointResolution function for this projection. -* @param {function(number, ol.Coordinate):number} func Function -* @api -*/ -ol.proj.Projection.prototype.setGetPointResolution = function(func) { - this.getPointResolutionFunc_ = func; + * Creates a function that returns its nth argument. + * @param {number} n The position of the return argument. + * @return {!Function} A new function. + */ +goog.functions.nth = function(n) { + return function() { + return arguments[n]; + }; }; /** -* Default version. -* Get the resolution of the point in degrees or distance units. -* For projections with degrees as the unit this will simply return the -* provided resolution. For other projections the point resolution is -* estimated by transforming the 'point' pixel to EPSG:4326, -* measuring its width and height on the normal sphere, -* and taking the average of the width and height. -* @param {number} resolution Nominal resolution in projection units. -* @param {ol.Coordinate} point Point to find adjusted resolution at. -* @return {number} Point resolution at point in projection units. -* @private -*/ -ol.proj.Projection.prototype.getPointResolution_ = function(resolution, point) { - var units = this.getUnits(); - if (units == ol.proj.Units.DEGREES) { - return resolution; - } else { - // Estimate point resolution by transforming the center pixel to EPSG:4326, - // measuring its width and height on the normal sphere, and taking the - // average of the width and height. - var toEPSG4326 = ol.proj.getTransformFromProjections( - this, ol.proj.get('EPSG:4326')); - var vertices = [ - point[0] - resolution / 2, point[1], - point[0] + resolution / 2, point[1], - point[0], point[1] - resolution / 2, - point[0], point[1] + resolution / 2 - ]; - vertices = toEPSG4326(vertices, vertices, 2); - var width = ol.sphere.NORMAL.haversineDistance( - vertices.slice(0, 2), vertices.slice(2, 4)); - var height = ol.sphere.NORMAL.haversineDistance( - vertices.slice(4, 6), vertices.slice(6, 8)); - var pointResolution = (width + height) / 2; - var metersPerUnit = this.getMetersPerUnit(); - if (metersPerUnit !== undefined) { - pointResolution /= metersPerUnit; - } - return pointResolution; - } + * Given a function, create a new function that swallows its return value + * and replaces it with a new one. + * @param {Function} f A function. + * @param {T} retValue A new return value. + * @return {function(...?):T} A new function. + * @template T + */ +goog.functions.withReturnValue = function(f, retValue) { + return goog.functions.sequence(f, goog.functions.constant(retValue)); }; /** - * Get the resolution of the point in degrees or distance units. - * For projections with degrees as the unit this will simply return the - * provided resolution. The default for other projections is to estimate - * the point resolution by transforming the 'point' pixel to EPSG:4326, - * measuring its width and height on the normal sphere, - * and taking the average of the width and height. - * An alternative implementation may be given when constructing a - * projection. For many local projections, - * such a custom function will return the resolution unchanged. - * @param {number} resolution Resolution in projection units. - * @param {ol.Coordinate} point Point. - * @return {number} Point resolution in projection units. - * @api + * Creates a function that returns whether its arguement equals the given value. + * + * Example: + * var key = goog.object.findKey(obj, goog.functions.equalTo('needle')); + * + * @param {*} value The value to compare to. + * @param {boolean=} opt_useLooseComparison Whether to use a loose (==) + * comparison rather than a strict (===) one. Defaults to false. + * @return {function(*):boolean} The new function. */ -ol.proj.Projection.prototype.getPointResolution = function(resolution, point) { - return this.getPointResolutionFunc_(resolution, point); +goog.functions.equalTo = function(value, opt_useLooseComparison) { + return function(other) { + return opt_useLooseComparison ? (value == other) : (value === other); + }; }; /** - * @private - * @type {Object.<string, ol.proj.Projection>} + * Creates the composition of the functions passed in. + * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)). + * @param {function(...?):T} fn The final function. + * @param {...Function} var_args A list of functions. + * @return {function(...?):T} The composition of all inputs. + * @template T */ -ol.proj.projections_ = {}; +goog.functions.compose = function(fn, var_args) { + var functions = arguments; + var length = functions.length; + return function() { + var result; + if (length) { + result = functions[length - 1].apply(this, arguments); + } + + for (var i = length - 2; i >= 0; i--) { + result = functions[i].call(this, result); + } + return result; + }; +}; /** - * @private - * @type {Object.<string, Object.<string, ol.TransformFunction>>} + * Creates a function that calls the functions passed in in sequence, and + * returns the value of the last function. For example, + * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x). + * @param {...Function} var_args A list of functions. + * @return {!Function} A function that calls all inputs in sequence. */ -ol.proj.transforms_ = {}; +goog.functions.sequence = function(var_args) { + var functions = arguments; + var length = functions.length; + return function() { + var result; + for (var i = 0; i < length; i++) { + result = functions[i].apply(this, arguments); + } + return result; + }; +}; /** - * Registers transformation functions that don't alter coordinates. Those allow - * to transform between projections with equal meaning. - * - * @param {Array.<ol.proj.Projection>} projections Projections. - * @api + * Creates a function that returns true if each of its components evaluates + * to true. The components are evaluated in order, and the evaluation will be + * short-circuited as soon as a function returns false. + * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x). + * @param {...Function} var_args A list of functions. + * @return {function(...?):boolean} A function that ANDs its component + * functions. */ -ol.proj.addEquivalentProjections = function(projections) { - ol.proj.addProjections(projections); - projections.forEach(function(source) { - projections.forEach(function(destination) { - if (source !== destination) { - ol.proj.addTransform(source, destination, ol.proj.cloneTransform); +goog.functions.and = function(var_args) { + var functions = arguments; + var length = functions.length; + return function() { + for (var i = 0; i < length; i++) { + if (!functions[i].apply(this, arguments)) { + return false; } - }); - }); + } + return true; + }; }; /** - * Registers transformation functions to convert coordinates in any projection - * in projection1 to any projection in projection2. - * - * @param {Array.<ol.proj.Projection>} projections1 Projections with equal - * meaning. - * @param {Array.<ol.proj.Projection>} projections2 Projections with equal - * meaning. - * @param {ol.TransformFunction} forwardTransform Transformation from any - * projection in projection1 to any projection in projection2. - * @param {ol.TransformFunction} inverseTransform Transform from any projection - * in projection2 to any projection in projection1.. + * Creates a function that returns true if any of its components evaluates + * to true. The components are evaluated in order, and the evaluation will be + * short-circuited as soon as a function returns true. + * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x). + * @param {...Function} var_args A list of functions. + * @return {function(...?):boolean} A function that ORs its component + * functions. */ -ol.proj.addEquivalentTransforms = - function(projections1, projections2, forwardTransform, inverseTransform) { - projections1.forEach(function(projection1) { - projections2.forEach(function(projection2) { - ol.proj.addTransform(projection1, projection2, forwardTransform); - ol.proj.addTransform(projection2, projection1, inverseTransform); - }); - }); +goog.functions.or = function(var_args) { + var functions = arguments; + var length = functions.length; + return function() { + for (var i = 0; i < length; i++) { + if (functions[i].apply(this, arguments)) { + return true; + } + } + return false; + }; }; /** - * Add a Projection object to the list of supported projections that can be - * looked up by their code. - * - * @param {ol.proj.Projection} projection Projection instance. - * @api stable + * Creates a function that returns the Boolean opposite of a provided function. + * For example, (goog.functions.not(f))(x) is equivalent to !f(x). + * @param {!Function} f The original function. + * @return {function(...?):boolean} A function that delegates to f and returns + * opposite. */ -ol.proj.addProjection = function(projection) { - ol.proj.projections_[projection.getCode()] = projection; - ol.proj.addTransform(projection, projection, ol.proj.cloneTransform); +goog.functions.not = function(f) { + return function() { + return !f.apply(this, arguments); + }; }; /** - * @param {Array.<ol.proj.Projection>} projections Projections. + * Generic factory function to construct an object given the constructor + * and the arguments. Intended to be bound to create object factories. + * + * Example: + * + * var factory = goog.partial(goog.functions.create, Class); + * + * @param {function(new:T, ...)} constructor The constructor for the Object. + * @param {...*} var_args The arguments to be passed to the constructor. + * @return {T} A new instance of the class given in {@code constructor}. + * @template T */ -ol.proj.addProjections = function(projections) { - var addedProjections = []; - projections.forEach(function(projection) { - addedProjections.push(ol.proj.addProjection(projection)); - }); -}; +goog.functions.create = function(constructor, var_args) { + /** + * @constructor + * @final + */ + var temp = function() {}; + temp.prototype = constructor.prototype; + // obj will have constructor's prototype in its chain and + // 'obj instanceof constructor' will be true. + var obj = new temp(); -/** - * FIXME empty description for jsdoc - */ -ol.proj.clearAllProjections = function() { - ol.proj.projections_ = {}; - ol.proj.transforms_ = {}; + // obj is initialized by constructor. + // arguments is only array-like so lacks shift(), but can be used with + // the Array prototype function. + constructor.apply(obj, Array.prototype.slice.call(arguments, 1)); + return obj; }; /** - * @param {ol.proj.Projection|string|undefined} projection Projection. - * @param {string} defaultCode Default code. - * @return {ol.proj.Projection} Projection. + * @define {boolean} Whether the return value cache should be used. + * This should only be used to disable caches when testing. */ -ol.proj.createProjection = function(projection, defaultCode) { - if (!projection) { - return ol.proj.get(defaultCode); - } else if (goog.isString(projection)) { - return ol.proj.get(projection); - } else { - goog.asserts.assertInstanceof(projection, ol.proj.Projection, - 'projection should be an ol.proj.Projection'); - return projection; - } -}; +goog.define('goog.functions.CACHE_RETURN_VALUE', true); /** - * Registers a conversion function to convert coordinates from the source - * projection to the destination projection. + * Gives a wrapper function that caches the return value of a parameterless + * function when first called. * - * @param {ol.proj.Projection} source Source. - * @param {ol.proj.Projection} destination Destination. - * @param {ol.TransformFunction} transformFn Transform. + * When called for the first time, the given function is called and its + * return value is cached (thus this is only appropriate for idempotent + * functions). Subsequent calls will return the cached return value. This + * allows the evaluation of expensive functions to be delayed until first used. + * + * To cache the return values of functions with parameters, see goog.memoize. + * + * @param {!function():T} fn A function to lazily evaluate. + * @return {!function():T} A wrapped version the function. + * @template T */ -ol.proj.addTransform = function(source, destination, transformFn) { - var sourceCode = source.getCode(); - var destinationCode = destination.getCode(); - var transforms = ol.proj.transforms_; - if (!goog.object.containsKey(transforms, sourceCode)) { - transforms[sourceCode] = {}; +goog.functions.cacheReturnValue = function(fn) { + var called = false; + var value; + + return function() { + if (!goog.functions.CACHE_RETURN_VALUE) { + return fn(); + } + + if (!called) { + value = fn(); + called = true; + } + + return value; } - transforms[sourceCode][destinationCode] = transformFn; }; /** - * Registers coordinate transform functions to convert coordinates between the - * source projection and the destination projection. - * The forward and inverse functions convert coordinate pairs; this function - * converts these into the functions used internally which also handle - * extents and coordinate arrays. + * Wraps a function to allow it to be called, at most, once. All + * additional calls are no-ops. * - * @param {ol.proj.ProjectionLike} source Source projection. - * @param {ol.proj.ProjectionLike} destination Destination projection. - * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform - * function (that is, from the source projection to the destination - * projection) that takes a {@link ol.Coordinate} as argument and returns - * the transformed {@link ol.Coordinate}. - * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform - * function (that is, from the destination projection to the source - * projection) that takes a {@link ol.Coordinate} as argument and returns - * the transformed {@link ol.Coordinate}. - * @api stable + * This is particularly useful for initialization functions + * that should be called, at most, once. + * + * @param {function():*} f Function to call. + * @return {function():undefined} Wrapped function. */ -ol.proj.addCoordinateTransforms = - function(source, destination, forward, inverse) { - var sourceProj = ol.proj.get(source); - var destProj = ol.proj.get(destination); - ol.proj.addTransform(sourceProj, destProj, - ol.proj.createTransformFromCoordinateTransform(forward)); - ol.proj.addTransform(destProj, sourceProj, - ol.proj.createTransformFromCoordinateTransform(inverse)); +goog.functions.once = function(f) { + // Keep a reference to the function that we null out when we're done with + // it -- that way, the function can be GC'd when we're done with it. + var inner = f; + return function() { + if (inner) { + var tmp = inner; + inner = null; + tmp(); + } + }; }; /** - * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform - * function. - * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate - * transform. - * @return {ol.TransformFunction} Transform function. + * Wraps a function to allow it to be called, at most, once for each sequence of + * calls fired repeatedly so long as they are fired less than a specified + * interval apart (in milliseconds). Whether it receives one signal or multiple, + * it will always wait until a full interval has elapsed since the last signal + * before performing the action. + * + * This is particularly useful for bulking up repeated user actions (e.g. only + * refreshing a view once a user finishes typing rather than updating with every + * keystroke). For more stateful debouncing with support for pausing, resuming, + * and canceling debounced actions, use {@code goog.async.Debouncer}. + * + * @param {function(this:SCOPE):*} f Function to call. + * @param {number} interval Interval over which to debounce. The function will + * only be called after the full interval has elapsed since the last call. + * @param {SCOPE=} opt_scope Object in whose scope to call the function. + * @return {function():undefined} Wrapped function. + * @template SCOPE */ -ol.proj.createTransformFromCoordinateTransform = function(transform) { - return ( - /** - * @param {Array.<number>} input Input. - * @param {Array.<number>=} opt_output Output. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Output. - */ - function(input, opt_output, opt_dimension) { - var length = input.length; - var dimension = opt_dimension !== undefined ? opt_dimension : 2; - var output = opt_output !== undefined ? opt_output : new Array(length); - var point, i, j; - for (i = 0; i < length; i += dimension) { - point = transform([input[i], input[i + 1]]); - output[i] = point[0]; - output[i + 1] = point[1]; - for (j = dimension - 1; j >= 2; --j) { - output[i + j] = input[i + j]; - } - } - return output; - }); +goog.functions.debounce = function(f, interval, opt_scope) { + if (opt_scope) { + f = goog.bind(f, opt_scope); + } + var timeout = null; + return function() { + goog.global.clearTimeout(timeout); + timeout = goog.global.setTimeout(f, interval); + }; }; /** - * Unregisters the conversion function to convert coordinates from the source - * projection to the destination projection. This method is used to clean up - * cached transforms during testing. + * Wraps a function to allow it to be called, at most, once per interval + * (specified in milliseconds). If it is called multiple times while it is + * waiting, it will only perform the action once at the end of the interval. * - * @param {ol.proj.Projection} source Source projection. - * @param {ol.proj.Projection} destination Destination projection. - * @return {ol.TransformFunction} transformFn The unregistered transform. + * This is particularly useful for limiting repeated user requests (e.g. + * preventing a user from spamming a server with frequent view refreshes). For + * more stateful throttling with support for pausing, resuming, and canceling + * throttled actions, use {@code goog.async.Throttle}. + * + * @param {function(this:SCOPE):*} f Function to call. + * @param {number} interval Interval over which to throttle. The function can + * only be called once per interval. + * @param {SCOPE=} opt_scope Object in whose scope to call the function. + * @return {function():undefined} Wrapped function. + * @template SCOPE */ -ol.proj.removeTransform = function(source, destination) { - var sourceCode = source.getCode(); - var destinationCode = destination.getCode(); - var transforms = ol.proj.transforms_; - goog.asserts.assert(sourceCode in transforms, - 'sourceCode should be in transforms'); - goog.asserts.assert(destinationCode in transforms[sourceCode], - 'destinationCode should be in transforms of sourceCode'); - var transform = transforms[sourceCode][destinationCode]; - delete transforms[sourceCode][destinationCode]; - if (goog.object.isEmpty(transforms[sourceCode])) { - delete transforms[sourceCode]; +goog.functions.throttle = function(f, interval, opt_scope) { + if (opt_scope) { + f = goog.bind(f, opt_scope); } - return transform; + var timeout = null; + var shouldFire = false; + var fire = function() { + timeout = goog.global.setTimeout(handleTimeout, interval); + f(); + }; + var handleTimeout = function() { + timeout = null; + if (shouldFire) { + shouldFire = false; + fire(); + } + }; + + return function() { + if (!timeout) { + fire(); + } else { + shouldFire = true; + } + }; }; +// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Transforms a coordinate from longitude/latitude to a different projection. - * @param {ol.Coordinate} coordinate Coordinate as longitude and latitude, i.e. - * an array with longitude as 1st and latitude as 2nd element. - * @param {ol.proj.ProjectionLike=} opt_projection Target projection. The - * default is Web Mercator, i.e. 'EPSG:3857'. - * @return {ol.Coordinate} Coordinate projected to the target projection. - * @api stable + * @fileoverview A delayed callback that pegs to the next animation frame + * instead of a user-configurable timeout. + * + * @author nicksantos@google.com (Nick Santos) */ -ol.proj.fromLonLat = function(coordinate, opt_projection) { - return ol.proj.transform(coordinate, 'EPSG:4326', - opt_projection !== undefined ? opt_projection : 'EPSG:3857'); -}; +goog.provide('goog.async.AnimationDelay'); + +goog.require('goog.Disposable'); +goog.require('goog.events'); +goog.require('goog.functions'); + + + +// TODO(nicksantos): Should we factor out the common code between this and +// goog.async.Delay? I'm not sure if there's enough code for this to really +// make sense. Subclassing seems like the wrong approach for a variety of +// reasons. Maybe there should be a common interface? -/** - * Transforms a coordinate to longitude/latitude. - * @param {ol.Coordinate} coordinate Projected coordinate. - * @param {ol.proj.ProjectionLike=} opt_projection Projection of the coordinate. - * The default is Web Mercator, i.e. 'EPSG:3857'. - * @return {ol.Coordinate} Coordinate as longitude and latitude, i.e. an array - * with longitude as 1st and latitude as 2nd element. - * @api stable - */ -ol.proj.toLonLat = function(coordinate, opt_projection) { - return ol.proj.transform(coordinate, - opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326'); -}; /** - * Fetches a Projection object for the code specified. + * A delayed callback that pegs to the next animation frame + * instead of a user configurable timeout. By design, this should have + * the same interface as goog.async.Delay. * - * @param {ol.proj.ProjectionLike} projectionLike Either a code string which is - * a combination of authority and identifier such as "EPSG:4326", or an - * existing projection object, or undefined. - * @return {ol.proj.Projection} Projection object, or null if not in list. - * @api stable + * Uses requestAnimationFrame and friends when available, but falls + * back to a timeout of goog.async.AnimationDelay.TIMEOUT. + * + * For more on requestAnimationFrame and how you can use it to create smoother + * animations, see: + * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + * + * @param {function(number)} listener Function to call when the delay completes. + * Will be passed the timestamp when it's called, in unix ms. + * @param {Window=} opt_window The window object to execute the delay in. + * Defaults to the global object. + * @param {Object=} opt_handler The object scope to invoke the function in. + * @constructor + * @struct + * @extends {goog.Disposable} + * @final */ -ol.proj.get = function(projectionLike) { - var projection; - if (projectionLike instanceof ol.proj.Projection) { - projection = projectionLike; - } else if (goog.isString(projectionLike)) { - var code = projectionLike; - projection = ol.proj.projections_[code]; - if (ol.ENABLE_PROJ4JS && projection === undefined && - typeof proj4 == 'function' && proj4.defs(code) !== undefined) { - projection = new ol.proj.Projection({code: code}); - ol.proj.addProjection(projection); - } - } else { - projection = null; - } - return projection; +goog.async.AnimationDelay = function(listener, opt_window, opt_handler) { + goog.async.AnimationDelay.base(this, 'constructor'); + + /** + * Identifier of the active delay timeout, or event listener, + * or null when inactive. + * @private {goog.events.Key|number} + */ + this.id_ = null; + + /** + * If we're using dom listeners. + * @private {?boolean} + */ + this.usingListeners_ = false; + + /** + * The function that will be invoked after a delay. + * @private {function(number)} + */ + this.listener_ = listener; + + /** + * The object context to invoke the callback in. + * @private {Object|undefined} + */ + this.handler_ = opt_handler; + + /** + * @private {Window} + */ + this.win_ = opt_window || window; + + /** + * Cached callback function invoked when the delay finishes. + * @private {function()} + */ + this.callback_ = goog.bind(this.doAction_, this); }; +goog.inherits(goog.async.AnimationDelay, goog.Disposable); /** - * Checks if two projections are the same, that is every coordinate in one - * projection does represent the same geographic point as the same coordinate in - * the other projection. + * Default wait timeout for animations (in milliseconds). Only used for timed + * animation, which uses a timer (setTimeout) to schedule animation. * - * @param {ol.proj.Projection} projection1 Projection 1. - * @param {ol.proj.Projection} projection2 Projection 2. - * @return {boolean} Equivalent. + * @type {number} + * @const */ -ol.proj.equivalent = function(projection1, projection2) { - if (projection1 === projection2) { - return true; - } else if (projection1.getCode() === projection2.getCode()) { - return projection1.getUnits() === projection2.getUnits(); - } else { - var transformFn = ol.proj.getTransformFromProjections( - projection1, projection2); - return transformFn === ol.proj.cloneTransform; - } -}; +goog.async.AnimationDelay.TIMEOUT = 20; /** - * Given the projection-like objects, searches for a transformation - * function to convert a coordinates array from the source projection to the - * destination projection. + * Name of event received from the requestAnimationFrame in Firefox. * - * @param {ol.proj.ProjectionLike} source Source. - * @param {ol.proj.ProjectionLike} destination Destination. - * @return {ol.TransformFunction} Transform function. - * @api stable + * @type {string} + * @const + * @private */ -ol.proj.getTransform = function(source, destination) { - var sourceProjection = ol.proj.get(source); - var destinationProjection = ol.proj.get(destination); - return ol.proj.getTransformFromProjections( - sourceProjection, destinationProjection); -}; +goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_ = 'MozBeforePaint'; /** - * Searches in the list of transform functions for the function for converting - * coordinates from the source projection to the destination projection. - * - * @param {ol.proj.Projection} sourceProjection Source Projection object. - * @param {ol.proj.Projection} destinationProjection Destination Projection - * object. - * @return {ol.TransformFunction} Transform function. + * Starts the delay timer. The provided listener function will be called + * before the next animation frame. */ -ol.proj.getTransformFromProjections = - function(sourceProjection, destinationProjection) { - var transforms = ol.proj.transforms_; - var sourceCode = sourceProjection.getCode(); - var destinationCode = destinationProjection.getCode(); - var transform; - if (goog.object.containsKey(transforms, sourceCode) && - goog.object.containsKey(transforms[sourceCode], destinationCode)) { - transform = transforms[sourceCode][destinationCode]; - } - if (transform === undefined) { - goog.asserts.assert(transform !== undefined, 'transform should be defined'); - transform = ol.proj.identityTransform; +goog.async.AnimationDelay.prototype.start = function() { + this.stop(); + this.usingListeners_ = false; + + var raf = this.getRaf_(); + var cancelRaf = this.getCancelRaf_(); + if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { + // Because Firefox (Gecko) runs animation in separate threads, it also saves + // time by running the requestAnimationFrame callbacks in that same thread. + // Sadly this breaks the assumption of implicit thread-safety in JS, and can + // thus create thread-based inconsistencies on counters etc. + // + // Calling cycleAnimations_ using the MozBeforePaint event instead of as + // callback fixes this. + // + // Trigger this condition only if the mozRequestAnimationFrame is available, + // but not the W3C requestAnimationFrame function (as in draft) or the + // equivalent cancel functions. + this.id_ = goog.events.listen( + this.win_, + goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_, + this.callback_); + this.win_.mozRequestAnimationFrame(null); + this.usingListeners_ = true; + } else if (raf && cancelRaf) { + this.id_ = raf.call(this.win_, this.callback_); + } else { + this.id_ = this.win_.setTimeout( + // Prior to Firefox 13, Gecko passed a non-standard parameter + // to the callback that we want to ignore. + goog.functions.lock(this.callback_), + goog.async.AnimationDelay.TIMEOUT); } - return transform; }; /** - * @param {Array.<number>} input Input coordinate array. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Input coordinate array (same array as input). + * Stops the delay timer if it is active. No action is taken if the timer is not + * in use. */ -ol.proj.identityTransform = function(input, opt_output, opt_dimension) { - if (opt_output !== undefined && input !== opt_output) { - // TODO: consider making this a warning instead - goog.asserts.fail('This should not be used internally.'); - for (var i = 0, ii = input.length; i < ii; ++i) { - opt_output[i] = input[i]; +goog.async.AnimationDelay.prototype.stop = function() { + if (this.isActive()) { + var raf = this.getRaf_(); + var cancelRaf = this.getCancelRaf_(); + if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { + goog.events.unlistenByKey(this.id_); + } else if (raf && cancelRaf) { + cancelRaf.call(this.win_, /** @type {number} */ (this.id_)); + } else { + this.win_.clearTimeout(/** @type {number} */ (this.id_)); } - input = opt_output; } - return input; + this.id_ = null; }; /** - * @param {Array.<number>} input Input coordinate array. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Output coordinate array (new array, same coordinate - * values). + * Fires delay's action even if timer has already gone off or has not been + * started yet; guarantees action firing. Stops the delay timer. */ -ol.proj.cloneTransform = function(input, opt_output, opt_dimension) { - var output; - if (opt_output !== undefined) { - for (var i = 0, ii = input.length; i < ii; ++i) { - opt_output[i] = input[i]; - } - output = opt_output; - } else { - output = input.slice(); - } - return output; +goog.async.AnimationDelay.prototype.fire = function() { + this.stop(); + this.doAction_(); }; /** - * Transforms a coordinate from source projection to destination projection. - * This returns a new coordinate (and does not modify the original). - * - * See {@link ol.proj.transformExtent} for extent transformation. - * See the transform method of {@link ol.geom.Geometry} and its subclasses for - * geometry transforms. - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.proj.ProjectionLike} source Source projection-like. - * @param {ol.proj.ProjectionLike} destination Destination projection-like. - * @return {ol.Coordinate} Coordinate. - * @api stable + * Fires delay's action only if timer is currently active. Stops the delay + * timer. */ -ol.proj.transform = function(coordinate, source, destination) { - var transformFn = ol.proj.getTransform(source, destination); - return transformFn(coordinate, undefined, coordinate.length); +goog.async.AnimationDelay.prototype.fireIfActive = function() { + if (this.isActive()) { + this.fire(); + } }; /** - * Transforms an extent from source projection to destination projection. This - * returns a new extent (and does not modify the original). - * - * @param {ol.Extent} extent The extent to transform. - * @param {ol.proj.ProjectionLike} source Source projection-like. - * @param {ol.proj.ProjectionLike} destination Destination projection-like. - * @return {ol.Extent} The transformed extent. - * @api stable + * @return {boolean} True if the delay is currently active, false otherwise. */ -ol.proj.transformExtent = function(extent, source, destination) { - var transformFn = ol.proj.getTransform(source, destination); - return ol.extent.applyTransform(extent, transformFn); +goog.async.AnimationDelay.prototype.isActive = function() { + return this.id_ != null; }; /** - * Transforms the given point to the destination projection. - * - * @param {ol.Coordinate} point Point. - * @param {ol.proj.Projection} sourceProjection Source projection. - * @param {ol.proj.Projection} destinationProjection Destination projection. - * @return {ol.Coordinate} Point. + * Invokes the callback function after the delay successfully completes. + * @private */ -ol.proj.transformWithProjections = - function(point, sourceProjection, destinationProjection) { - var transformFn = ol.proj.getTransformFromProjections( - sourceProjection, destinationProjection); - return transformFn(point); +goog.async.AnimationDelay.prototype.doAction_ = function() { + if (this.usingListeners_ && this.id_) { + goog.events.unlistenByKey(this.id_); + } + this.id_ = null; + + // We are not using the timestamp returned by requestAnimationFrame + // because it may be either a Date.now-style time or a + // high-resolution time (depending on browser implementation). Using + // goog.now() will ensure that the timestamp used is consistent and + // compatible with goog.fx.Animation. + this.listener_.call(this.handler_, goog.now()); }; -goog.provide('ol.geom.Geometry'); -goog.provide('ol.geom.GeometryLayout'); -goog.provide('ol.geom.GeometryType'); -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('ol.Object'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.proj.Units'); +/** @override */ +goog.async.AnimationDelay.prototype.disposeInternal = function() { + this.stop(); + goog.async.AnimationDelay.base(this, 'disposeInternal'); +}; /** - * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`, - * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`, - * `'GeometryCollection'`, `'Circle'`. - * @enum {string} - * @api stable + * @return {?function(function(number)): number} The requestAnimationFrame + * function, or null if not available on this browser. + * @private */ -ol.geom.GeometryType = { - POINT: 'Point', - LINE_STRING: 'LineString', - LINEAR_RING: 'LinearRing', - POLYGON: 'Polygon', - MULTI_POINT: 'MultiPoint', - MULTI_LINE_STRING: 'MultiLineString', - MULTI_POLYGON: 'MultiPolygon', - GEOMETRY_COLLECTION: 'GeometryCollection', - CIRCLE: 'Circle' +goog.async.AnimationDelay.prototype.getRaf_ = function() { + var win = this.win_; + return win.requestAnimationFrame || + win.webkitRequestAnimationFrame || + win.mozRequestAnimationFrame || + win.oRequestAnimationFrame || + win.msRequestAnimationFrame || + null; }; /** - * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z') - * or measure ('M') coordinate is available. Supported values are `'XY'`, - * `'XYZ'`, `'XYM'`, `'XYZM'`. - * @enum {string} - * @api stable + * @return {?function(number): number} The cancelAnimationFrame function, + * or null if not available on this browser. + * @private */ -ol.geom.GeometryLayout = { - XY: 'XY', - XYZ: 'XYZ', - XYM: 'XYM', - XYZM: 'XYZM' +goog.async.AnimationDelay.prototype.getCancelRaf_ = function() { + var win = this.win_; + return win.cancelAnimationFrame || + win.cancelRequestAnimationFrame || + win.webkitCancelRequestAnimationFrame || + win.mozCancelRequestAnimationFrame || + win.oCancelRequestAnimationFrame || + win.msCancelRequestAnimationFrame || + null; }; +goog.provide('ol.render.VectorContext'); + /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for vector geometries. - * - * To get notified of changes to the geometry, register a listener for the - * generic `change` event on your geometry instance. - * + * Context for drawing geometries. A vector context is available on render + * events and does not need to be constructed directly. * @constructor - * @extends {ol.Object} - * @api stable + * @struct + * @api */ -ol.geom.Geometry = function() { - - goog.base(this); - - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {number} - */ - this.extentRevision_ = -1; - - /** - * @protected - * @type {Object.<string, ol.geom.Geometry>} - */ - this.simplifiedGeometryCache = {}; - - /** - * @protected - * @type {number} - */ - this.simplifiedGeometryMaxMinSquaredTolerance = 0; +ol.render.VectorContext = function() { +}; - /** - * @protected - * @type {number} - */ - this.simplifiedGeometryRevision = 0; -}; -goog.inherits(ol.geom.Geometry, ol.Object); +/** + * @param {number} zIndex Z index. + * @param {function(ol.render.VectorContext)} callback Callback. + */ +ol.render.VectorContext.prototype.drawAsync = goog.abstractMethod; /** - * Make a complete copy of the geometry. - * @function - * @return {!ol.geom.Geometry} Clone. + * @param {ol.geom.Circle} circleGeometry Circle geometry. + * @param {ol.Feature} feature Feature, */ -ol.geom.Geometry.prototype.clone = goog.abstractMethod; +ol.render.VectorContext.prototype.drawCircleGeometry = goog.abstractMethod; /** - * @param {number} x X. - * @param {number} y Y. - * @param {ol.Coordinate} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @return {number} Minimum squared distance. + * @param {ol.Feature} feature Feature. + * @param {ol.style.Style} style Style. */ -ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod; +ol.render.VectorContext.prototype.drawFeature = goog.abstractMethod; /** - * Return the closest point of the geometry to the passed point as - * {@link ol.Coordinate coordinate}. - * @param {ol.Coordinate} point Point. - * @param {ol.Coordinate=} opt_closestPoint Closest point. - * @return {ol.Coordinate} Closest point. - * @api stable + * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry + * collection. + * @param {ol.Feature} feature Feature. */ -ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) { - var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN]; - this.closestPointXY(point[0], point[1], closestPoint, Infinity); - return closestPoint; -}; +ol.render.VectorContext.prototype.drawGeometryCollectionGeometry = + goog.abstractMethod; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @return {boolean} Contains coordinate. + * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line + * string geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) { - return this.containsXY(coordinate[0], coordinate[1]); -}; +ol.render.VectorContext.prototype.drawLineStringGeometry = + goog.abstractMethod; /** - * @param {ol.Extent} extent Extent. - * @protected - * @return {ol.Extent} extent Extent. + * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry + * MultiLineString geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.geom.Geometry.prototype.computeExtent = goog.abstractMethod; +ol.render.VectorContext.prototype.drawMultiLineStringGeometry = + goog.abstractMethod; /** - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). + * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.geom.Geometry.prototype.containsXY = goog.functions.FALSE; +ol.render.VectorContext.prototype.drawMultiPointGeometry = goog.abstractMethod; /** - * Get the extent of the geometry. - * @param {ol.Extent=} opt_extent Extent. - * @return {ol.Extent} extent Extent. - * @api stable + * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry. + * @param {ol.Feature} feature Feature. */ -ol.geom.Geometry.prototype.getExtent = function(opt_extent) { - if (this.extentRevision_ != this.getRevision()) { - this.extent_ = this.computeExtent(this.extent_); - this.extentRevision_ = this.getRevision(); - } - return ol.extent.returnOrUpdate(this.extent_, opt_extent); -}; +ol.render.VectorContext.prototype.drawMultiPolygonGeometry = + goog.abstractMethod; /** - * Create a simplified version of this geometry. For linestrings, this uses - * the the {@link - * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm - * Douglas Peucker} algorithm. For polygons, a quantization-based - * simplification is used to preserve topology. - * @function - * @param {number} tolerance The tolerance distance for simplification. - * @return {ol.geom.Geometry} A new, simplified version of the original - * geometry. - * @api + * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.geom.Geometry.prototype.simplify = function(tolerance) { - return this.getSimplifiedGeometry(tolerance * tolerance); -}; +ol.render.VectorContext.prototype.drawPointGeometry = goog.abstractMethod; /** - * Create a simplified version of this geometry using the Douglas Peucker - * algorithm. - * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm - * @function - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.Geometry} Simplified geometry. + * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod; +ol.render.VectorContext.prototype.drawPolygonGeometry = goog.abstractMethod; /** - * Get the type of this geometry. - * @function - * @return {ol.geom.GeometryType} Geometry type. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.geom.Geometry.prototype.getType = goog.abstractMethod; +ol.render.VectorContext.prototype.drawText = goog.abstractMethod; /** - * Apply a transform function to each coordinate of the geometry. - * The geometry is modified in place. - * If you do not want the geometry modified in place, first clone() it and - * then use this function on the clone. - * @function - * @param {ol.TransformFunction} transformFn Transform. + * @param {ol.style.Fill} fillStyle Fill style. + * @param {ol.style.Stroke} strokeStyle Stroke style. */ -ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod; +ol.render.VectorContext.prototype.setFillStrokeStyle = goog.abstractMethod; /** - * Test if the geometry and the passed extent intersect. - * @param {ol.Extent} extent Extent. - * @return {boolean} `true` if the geometry and the extent intersect. - * @function + * @param {ol.style.Image} imageStyle Image style. */ -ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod; +ol.render.VectorContext.prototype.setImageStyle = goog.abstractMethod; /** - * Translate the geometry. This modifies the geometry coordinates in place. If - * instead you want a new geometry, first `clone()` this geometry. - * @param {number} deltaX Delta X. - * @param {number} deltaY Delta Y. - * @function + * @param {ol.style.Text} textStyle Text style. */ -ol.geom.Geometry.prototype.translate = goog.abstractMethod; +ol.render.VectorContext.prototype.setTextStyle = goog.abstractMethod; + +goog.provide('ol.render.Event'); +goog.provide('ol.render.EventType'); + +goog.require('goog.events.Event'); +goog.require('ol.render.VectorContext'); /** - * Transform each coordinate of the geometry from one coordinate reference - * system to another. The geometry is modified in place. - * For example, a line will be transformed to a line and a circle to a circle. - * If you do not want the geometry modified in place, first clone() it and - * then use this function on the clone. - * - * @param {ol.proj.ProjectionLike} source The current projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @param {ol.proj.ProjectionLike} destination The desired projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @return {ol.geom.Geometry} This geometry. Note that original geometry is - * modified in place. - * @api stable + * @enum {string} */ -ol.geom.Geometry.prototype.transform = function(source, destination) { - goog.asserts.assert( - ol.proj.get(source).getUnits() !== ol.proj.Units.TILE_PIXELS && - ol.proj.get(destination).getUnits() !== ol.proj.Units.TILE_PIXELS, - 'cannot transform geometries with TILE_PIXELS units'); - this.applyTransform(ol.proj.getTransform(source, destination)); - return this; +ol.render.EventType = { + /** + * @event ol.render.Event#postcompose + * @api + */ + POSTCOMPOSE: 'postcompose', + /** + * @event ol.render.Event#precompose + * @api + */ + PRECOMPOSE: 'precompose', + /** + * @event ol.render.Event#render + * @api + */ + RENDER: 'render' }; -goog.provide('ol.geom.flat.transform'); - -goog.require('goog.vec.Mat4'); /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Transformed coordinates. + * @constructor + * @extends {goog.events.Event} + * @implements {oli.render.Event} + * @param {ol.render.EventType} type Type. + * @param {Object=} opt_target Target. + * @param {ol.render.VectorContext=} opt_vectorContext Vector context. + * @param {olx.FrameState=} opt_frameState Frame state. + * @param {?CanvasRenderingContext2D=} opt_context Context. + * @param {?ol.webgl.Context=} opt_glContext WebGL Context. */ -ol.geom.flat.transform.transform2D = - function(flatCoordinates, offset, end, stride, transform, opt_dest) { - var m00 = goog.vec.Mat4.getElement(transform, 0, 0); - var m10 = goog.vec.Mat4.getElement(transform, 1, 0); - var m01 = goog.vec.Mat4.getElement(transform, 0, 1); - var m11 = goog.vec.Mat4.getElement(transform, 1, 1); - var m03 = goog.vec.Mat4.getElement(transform, 0, 3); - var m13 = goog.vec.Mat4.getElement(transform, 1, 3); - var dest = opt_dest ? opt_dest : []; - var i = 0; - var j; - for (j = offset; j < end; j += stride) { - var x = flatCoordinates[j]; - var y = flatCoordinates[j + 1]; - dest[i++] = m00 * x + m01 * y + m03; - dest[i++] = m10 * x + m11 * y + m13; - } - if (opt_dest && dest.length != i) { - dest.length = i; - } - return dest; -}; +ol.render.Event = function( + type, opt_target, opt_vectorContext, opt_frameState, opt_context, + opt_glContext) { + goog.base(this, type, opt_target); + + /** + * For canvas, this is an instance of {@link ol.render.canvas.Immediate}. + * @type {ol.render.VectorContext|undefined} + * @api + */ + this.vectorContext = opt_vectorContext; + + /** + * An object representing the current render frame state. + * @type {olx.FrameState|undefined} + * @api + */ + this.frameState = opt_frameState; + + /** + * Canvas context. Only available when a Canvas renderer is used, null + * otherwise. + * @type {CanvasRenderingContext2D|null|undefined} + * @api + */ + this.context = opt_context; + + /** + * WebGL context. Only available when a WebGL renderer is used, null + * otherwise. + * @type {ol.webgl.Context|null|undefined} + * @api + */ + this.glContext = opt_glContext; -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} deltaX Delta X. - * @param {number} deltaY Delta Y. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Transformed coordinates. - */ -ol.geom.flat.transform.translate = - function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) { - var dest = opt_dest ? opt_dest : []; - var i = 0; - var j, k; - for (j = offset; j < end; j += stride) { - dest[i++] = flatCoordinates[j] + deltaX; - dest[i++] = flatCoordinates[j + 1] + deltaY; - for (k = j + 2; k < j + stride; ++k) { - dest[i++] = flatCoordinates[k]; - } - } - if (opt_dest && dest.length != i) { - dest.length = i; - } - return dest; }; +goog.inherits(ol.render.Event, goog.events.Event); -goog.provide('ol.geom.SimpleGeometry'); +goog.provide('ol.layer.Layer'); -goog.require('goog.asserts'); -goog.require('goog.functions'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); goog.require('goog.object'); -goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.flat.transform'); +goog.require('ol'); +goog.require('ol.Object'); +goog.require('ol.layer.Base'); +goog.require('ol.layer.LayerProperty'); +goog.require('ol.render.EventType'); +goog.require('ol.source.State'); /** * @classdesc - * Abstract base class; only used for creating subclasses; do not instantiate - * in apps, as cannot be rendered. + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * A visual representation of raster or vector map data. + * Layers group together those properties that pertain to how the data is to be + * displayed, irrespective of the source of that data. + * + * Layers are usually added to a map with {@link ol.Map#addLayer}. Components + * like {@link ol.interaction.Select} use unmanaged layers internally. These + * unmanaged layers are associated with the map using + * {@link ol.layer.Layer#setMap} instead. + * + * A generic `change` event is fired when the state of the source changes. * * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.layer.Base} + * @fires ol.render.Event + * @param {olx.layer.LayerOptions} options Layer options. * @api stable */ -ol.geom.SimpleGeometry = function() { +ol.layer.Layer = function(options) { - goog.base(this); + var baseOptions = goog.object.clone(options); + delete baseOptions.source; + + goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); /** - * @protected - * @type {ol.geom.GeometryLayout} + * @private + * @type {goog.events.Key} */ - this.layout = ol.geom.GeometryLayout.XY; + this.mapPrecomposeKey_ = null; /** - * @protected - * @type {number} + * @private + * @type {goog.events.Key} */ - this.stride = 2; + this.mapRenderKey_ = null; /** - * @protected - * @type {Array.<number>} + * @private + * @type {goog.events.Key} */ - this.flatCoordinates = null; + this.sourceChangeKey_ = null; + + if (options.map) { + this.setMap(options.map); + } + + goog.events.listen(this, + ol.Object.getChangeEventType(ol.layer.LayerProperty.SOURCE), + this.handleSourcePropertyChange_, false, this); + var source = options.source ? options.source : null; + this.setSource(source); }; -goog.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry); +goog.inherits(ol.layer.Layer, ol.layer.Base); /** - * @param {number} stride Stride. - * @private - * @return {ol.geom.GeometryLayout} layout Layout. + * Return `true` if the layer is visible, and if the passed resolution is + * between the layer's minResolution and maxResolution. The comparison is + * inclusive for `minResolution` and exclusive for `maxResolution`. + * @param {ol.layer.LayerState} layerState Layer state. + * @param {number} resolution Resolution. + * @return {boolean} The layer is visible at the given resolution. */ -ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) { - if (stride == 2) { - return ol.geom.GeometryLayout.XY; - } else if (stride == 3) { - return ol.geom.GeometryLayout.XYZ; - } else if (stride == 4) { - return ol.geom.GeometryLayout.XYZM; - } else { - goog.asserts.fail('unsupported stride: ' + stride); - } +ol.layer.Layer.visibleAtResolution = function(layerState, resolution) { + return layerState.visible && resolution >= layerState.minResolution && + resolution < layerState.maxResolution; }; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @return {number} Stride. + * @inheritDoc */ -ol.geom.SimpleGeometry.getStrideForLayout = function(layout) { - if (layout == ol.geom.GeometryLayout.XY) { - return 2; - } else if (layout == ol.geom.GeometryLayout.XYZ) { - return 3; - } else if (layout == ol.geom.GeometryLayout.XYM) { - return 3; - } else if (layout == ol.geom.GeometryLayout.XYZM) { - return 4; - } else { - goog.asserts.fail('unsupported layout: ' + layout); - } +ol.layer.Layer.prototype.getLayersArray = function(opt_array) { + var array = opt_array ? opt_array : []; + array.push(this); + return array; }; /** * @inheritDoc */ -ol.geom.SimpleGeometry.prototype.containsXY = goog.functions.FALSE; +ol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) { + var states = opt_states ? opt_states : []; + states.push(this.getLayerState()); + return states; +}; /** - * @inheritDoc + * Get the layer source. + * @return {ol.source.Source} The layer source (or `null` if not yet set). + * @observable + * @api stable */ -ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) { - return ol.extent.createOrUpdateFromFlatCoordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - extent); +ol.layer.Layer.prototype.getSource = function() { + var source = this.get(ol.layer.LayerProperty.SOURCE); + return /** @type {ol.source.Source} */ (source) || null; }; /** - * @return {Array} Coordinates. + * @inheritDoc + */ +ol.layer.Layer.prototype.getSourceState = function() { + var source = this.getSource(); + return !source ? ol.source.State.UNDEFINED : source.getState(); +}; + + +/** + * @private */ -ol.geom.SimpleGeometry.prototype.getCoordinates = goog.abstractMethod; +ol.layer.Layer.prototype.handleSourceChange_ = function() { + this.changed(); +}; /** - * Return the first coordinate of the geometry. - * @return {ol.Coordinate} First coordinate. - * @api stable + * @private */ -ol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() { - return this.flatCoordinates.slice(0, this.stride); +ol.layer.Layer.prototype.handleSourcePropertyChange_ = function() { + if (this.sourceChangeKey_) { + goog.events.unlistenByKey(this.sourceChangeKey_); + this.sourceChangeKey_ = null; + } + var source = this.getSource(); + if (source) { + this.sourceChangeKey_ = goog.events.listen(source, + goog.events.EventType.CHANGE, this.handleSourceChange_, false, this); + } + this.changed(); }; /** - * @return {Array.<number>} Flat coordinates. + * Sets the layer to be rendered on a map. The map will not manage this layer in + * its layers collection, layer filters in {@link ol.Map#forEachLayerAtPixel} + * will not filter the layer, and it will be rendered on top. This is useful for + * temporary layers. To remove an unmanaged layer from the map, use + * `#setMap(null)`. + * + * To add the layer to a map and have it managed by the map, use + * {@link ol.Map#addLayer} instead. + * @param {ol.Map} map Map. + * @api */ -ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() { - return this.flatCoordinates; +ol.layer.Layer.prototype.setMap = function(map) { + goog.events.unlistenByKey(this.mapPrecomposeKey_); + this.mapPrecomposeKey_ = null; + if (!map) { + this.changed(); + } + goog.events.unlistenByKey(this.mapRenderKey_); + this.mapRenderKey_ = null; + if (map) { + this.mapPrecomposeKey_ = goog.events.listen( + map, ol.render.EventType.PRECOMPOSE, function(evt) { + var layerState = this.getLayerState(); + layerState.managed = false; + layerState.zIndex = Infinity; + evt.frameState.layerStatesArray.push(layerState); + evt.frameState.layerStates[goog.getUid(this)] = layerState; + }, false, this); + this.mapRenderKey_ = goog.events.listen( + this, goog.events.EventType.CHANGE, map.render, false, map); + this.changed(); + } }; /** - * Return the last coordinate of the geometry. - * @return {ol.Coordinate} Last point. + * Set the layer source. + * @param {ol.source.Source} source The layer source. + * @observable * @api stable */ -ol.geom.SimpleGeometry.prototype.getLastCoordinate = function() { - return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride); +ol.layer.Layer.prototype.setSource = function(source) { + this.set(ol.layer.LayerProperty.SOURCE, source); }; +goog.provide('ol.layer.Tile'); + +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.layer.Layer'); + /** - * Return the {@link ol.geom.GeometryLayout layout} of the geometry. - * @return {ol.geom.GeometryLayout} Layout. - * @api stable + * @enum {string} */ -ol.geom.SimpleGeometry.prototype.getLayout = function() { - return this.layout; +ol.layer.TileProperty = { + PRELOAD: 'preload', + USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError' }; + /** - * @inheritDoc + * @classdesc + * For layer sources that provide pre-rendered, tiled images in grids that are + * organized by zoom levels for specific resolutions. + * Note that any property set in the options is set as a {@link ol.Object} + * property on the layer object; for example, setting `title: 'My Title'` in the + * options means that `title` is observable, and has get/set accessors. + * + * @constructor + * @extends {ol.layer.Layer} + * @fires ol.render.Event + * @param {olx.layer.TileOptions=} opt_options Tile layer options. + * @api stable */ -ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = - function(squaredTolerance) { - if (this.simplifiedGeometryRevision != this.getRevision()) { - goog.object.clear(this.simplifiedGeometryCache); - this.simplifiedGeometryMaxMinSquaredTolerance = 0; - this.simplifiedGeometryRevision = this.getRevision(); - } - // If squaredTolerance is negative or if we know that simplification will not - // have any effect then just return this. - if (squaredTolerance < 0 || - (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && - squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) { - return this; - } - var key = squaredTolerance.toString(); - if (this.simplifiedGeometryCache.hasOwnProperty(key)) { - return this.simplifiedGeometryCache[key]; - } else { - var simplifiedGeometry = - this.getSimplifiedGeometryInternal(squaredTolerance); - var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates(); - if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) { - this.simplifiedGeometryCache[key] = simplifiedGeometry; - return simplifiedGeometry; - } else { - // Simplification did not actually remove any coordinates. We now know - // that any calls to getSimplifiedGeometry with a squaredTolerance less - // than or equal to the current squaredTolerance will also not have any - // effect. This allows us to short circuit simplification (saving CPU - // cycles) and prevents the cache of simplified geometries from filling - // up with useless identical copies of this geometry (saving memory). - this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; - return this; - } - } +ol.layer.Tile = function(opt_options) { + var options = opt_options ? opt_options : {}; + + var baseOptions = goog.object.clone(options); + + delete baseOptions.preload; + delete baseOptions.useInterimTilesOnError; + goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); + + this.setPreload(options.preload !== undefined ? options.preload : 0); + this.setUseInterimTilesOnError(options.useInterimTilesOnError !== undefined ? + options.useInterimTilesOnError : true); }; +goog.inherits(ol.layer.Tile, ol.layer.Layer); /** - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.SimpleGeometry} Simplified geometry. - * @protected + * Return the level as number to which we will preload tiles up to. + * @return {number} The level to preload tiles up to. + * @observable + * @api */ -ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - return this; +ol.layer.Tile.prototype.getPreload = function() { + return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD)); }; /** - * @return {number} Stride. + * Return the associated {@link ol.source.Tile tilesource} of the layer. + * @function + * @return {ol.source.Tile} Source. + * @api stable */ -ol.geom.SimpleGeometry.prototype.getStride = function() { - return this.stride; -}; +ol.layer.Tile.prototype.getSource; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @protected + * Set the level as number to which we will preload tiles up to. + * @param {number} preload The level to preload tiles up to. + * @observable + * @api */ -ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = - function(layout, flatCoordinates) { - this.stride = ol.geom.SimpleGeometry.getStrideForLayout(layout); - this.layout = layout; - this.flatCoordinates = flatCoordinates; +ol.layer.Tile.prototype.setPreload = function(preload) { + this.set(ol.layer.TileProperty.PRELOAD, preload); }; /** - * @param {Array} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * Whether we use interim tiles on error. + * @return {boolean} Use interim tiles on error. + * @observable + * @api */ -ol.geom.SimpleGeometry.prototype.setCoordinates = goog.abstractMethod; +ol.layer.Tile.prototype.getUseInterimTilesOnError = function() { + return /** @type {boolean} */ ( + this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR)); +}; /** - * @param {ol.geom.GeometryLayout|undefined} layout Layout. - * @param {Array} coordinates Coordinates. - * @param {number} nesting Nesting. - * @protected + * Set whether we use interim tiles on error. + * @param {boolean} useInterimTilesOnError Use interim tiles on error. + * @observable + * @api */ -ol.geom.SimpleGeometry.prototype.setLayout = - function(layout, coordinates, nesting) { - /** @type {number} */ - var stride; - if (layout) { - stride = ol.geom.SimpleGeometry.getStrideForLayout(layout); - } else { - var i; - for (i = 0; i < nesting; ++i) { - if (coordinates.length === 0) { - this.layout = ol.geom.GeometryLayout.XY; - this.stride = 2; - return; - } else { - coordinates = /** @type {Array} */ (coordinates[0]); - } - } - stride = (/** @type {Array} */ (coordinates)).length; - layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride); - } - this.layout = layout; - this.stride = stride; +ol.layer.Tile.prototype.setUseInterimTilesOnError = + function(useInterimTilesOnError) { + this.set( + ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); }; +goog.provide('ol.Tile'); +goog.provide('ol.TileState'); + +goog.require('goog.events'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('ol.TileCoord'); + /** - * @inheritDoc - * @api stable + * @enum {number} */ -ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) { - if (this.flatCoordinates) { - transformFn(this.flatCoordinates, this.flatCoordinates, this.stride); - this.changed(); - } +ol.TileState = { + IDLE: 0, + LOADING: 1, + LOADED: 2, + ERROR: 3, + EMPTY: 4 }; + /** - * @inheritDoc - * @api stable + * @classdesc + * Base class for tiles. + * + * @constructor + * @extends {goog.events.EventTarget} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.TileState} state State. */ -ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) { - var flatCoordinates = this.getFlatCoordinates(); - if (flatCoordinates) { - var stride = this.getStride(); - ol.geom.flat.transform.translate( - flatCoordinates, 0, flatCoordinates.length, stride, - deltaX, deltaY, flatCoordinates); - this.changed(); - } +ol.Tile = function(tileCoord, state) { + + goog.base(this); + + /** + * @type {ol.TileCoord} + */ + this.tileCoord = tileCoord; + + /** + * @protected + * @type {ol.TileState} + */ + this.state = state; + + /** + * An "interim" tile for this tile. The interim tile may be used while this + * one is loading, for "smooth" transitions when changing params/dimensions + * on the source. + * @type {ol.Tile} + */ + this.interimTile = null; + + /** + * A key assigned to the tile. This is used by the tile source to determine + * if this tile can effectively be used, or if a new tile should be created + * and this one be used as an interim tile for this new tile. + * @type {string} + */ + this.key = ''; + }; +goog.inherits(ol.Tile, goog.events.EventTarget); /** - * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Transformed flat coordinates. + * @protected */ -ol.geom.transformSimpleGeometry2D = - function(simpleGeometry, transform, opt_dest) { - var flatCoordinates = simpleGeometry.getFlatCoordinates(); - if (!flatCoordinates) { - return null; - } else { - var stride = simpleGeometry.getStride(); - return ol.geom.flat.transform.transform2D( - flatCoordinates, 0, flatCoordinates.length, stride, - transform, opt_dest); - } +ol.Tile.prototype.changed = function() { + this.dispatchEvent(goog.events.EventType.CHANGE); }; -goog.provide('ol.geom.flat.area'); + +/** + * Get the HTML image element for this tile (may be a Canvas, Image, or Video). + * @function + * @param {Object=} opt_context Object. + * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image. + */ +ol.Tile.prototype.getImage = goog.abstractMethod; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Area. + * @return {string} Key. */ -ol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) { - var twiceArea = 0; - var x1 = flatCoordinates[end - stride]; - var y1 = flatCoordinates[end - stride + 1]; - for (; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - twiceArea += y1 * x2 - x1 * y2; - x1 = x2; - y1 = y2; - } - return twiceArea / 2; +ol.Tile.prototype.getKey = function() { + return goog.getUid(this).toString(); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @return {number} Area. + * Get the tile coordinate for this tile. + * @return {ol.TileCoord} + * @api */ -ol.geom.flat.area.linearRings = - function(flatCoordinates, offset, ends, stride) { - var area = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride); - offset = end; - } - return area; +ol.Tile.prototype.getTileCoord = function() { + return this.tileCoord; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @return {number} Area. + * @return {ol.TileState} State. */ -ol.geom.flat.area.linearRingss = - function(flatCoordinates, offset, endss, stride) { - var area = 0; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - area += - ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride); - offset = ends[ends.length - 1]; - } - return area; +ol.Tile.prototype.getState = function() { + return this.state; }; -goog.provide('ol.geom.flat.closest'); + +/** + * FIXME empty description for jsdoc + */ +ol.Tile.prototype.load = goog.abstractMethod; + +goog.provide('ol.TileLoadFunctionType'); +goog.provide('ol.TileVectorLoadFunctionType'); + + +/** + * A function that takes an {@link ol.Tile} for the tile and a + * `{string}` for the url as arguments. + * + * @typedef {function(ol.Tile, string)} + * @api + */ +ol.TileLoadFunctionType; + + +/** + * A function that is called with a tile url for the features to load and + * a callback that takes the loaded features as argument. + * + * @typedef {function(string, function(Array.<ol.Feature>))} + * @api + */ +ol.TileVectorLoadFunctionType; + +goog.provide('ol.ImageTile'); goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol.math'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol.Tile'); +goog.require('ol.TileCoord'); +goog.require('ol.TileLoadFunctionType'); +goog.require('ol.TileState'); + /** - * Returns the point on the 2D line segment flatCoordinates[offset1] to - * flatCoordinates[offset2] that is closest to the point (x, y). Extra - * dimensions are linearly interpolated. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset1 Offset 1. - * @param {number} offset2 Offset 2. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. + * @constructor + * @extends {ol.Tile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.TileState} state State. + * @param {string} src Image source URI. + * @param {?string} crossOrigin Cross origin. + * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. */ -ol.geom.flat.closest.point = - function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) { - var x1 = flatCoordinates[offset1]; - var y1 = flatCoordinates[offset1 + 1]; - var dx = flatCoordinates[offset2] - x1; - var dy = flatCoordinates[offset2 + 1] - y1; - var i, offset; - if (dx === 0 && dy === 0) { - offset = offset1; - } else { - var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); - if (t > 1) { - offset = offset2; - } else if (t > 0) { - for (i = 0; i < stride; ++i) { - closestPoint[i] = goog.math.lerp(flatCoordinates[offset1 + i], - flatCoordinates[offset2 + i], t); - } - closestPoint.length = stride; - return; - } else { - offset = offset1; - } - } - for (i = 0; i < stride; ++i) { - closestPoint[i] = flatCoordinates[offset + i]; +ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) { + + goog.base(this, tileCoord, state); + + /** + * Image URI + * + * @private + * @type {string} + */ + this.src_ = src; + + /** + * @private + * @type {Image} + */ + this.image_ = new Image(); + if (crossOrigin !== null) { + this.image_.crossOrigin = crossOrigin; } - closestPoint.length = stride; + + /** + * @private + * @type {Object.<number, Image>} + */ + this.imageByContext_ = {}; + + /** + * @private + * @type {Array.<goog.events.Key>} + */ + this.imageListenerKeys_ = null; + + /** + * @private + * @type {ol.TileLoadFunctionType} + */ + this.tileLoadFunction_ = tileLoadFunction; + }; +goog.inherits(ol.ImageTile, ol.Tile); /** - * Return the squared of the largest distance between any pair of consecutive - * coordinates. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} maxSquaredDelta Max squared delta. - * @return {number} Max squared delta. + * @inheritDoc */ -ol.geom.flat.closest.getMaxSquaredDelta = - function(flatCoordinates, offset, end, stride, maxSquaredDelta) { - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - for (offset += stride; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2); - if (squaredDelta > maxSquaredDelta) { - maxSquaredDelta = squaredDelta; - } - x1 = x2; - y1 = y2; +ol.ImageTile.prototype.disposeInternal = function() { + if (this.state == ol.TileState.LOADING) { + this.unlistenImage_(); } - return maxSquaredDelta; + if (this.interimTile) { + goog.dispose(this.interimTile); + } + goog.base(this, 'disposeInternal'); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} maxSquaredDelta Max squared delta. - * @return {number} Max squared delta. + * Get the image element for this tile. + * @inheritDoc + * @api */ -ol.geom.flat.closest.getsMaxSquaredDelta = - function(flatCoordinates, offset, ends, stride, maxSquaredDelta) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta( - flatCoordinates, offset, end, stride, maxSquaredDelta); - offset = end; +ol.ImageTile.prototype.getImage = function(opt_context) { + if (opt_context !== undefined) { + var image; + var key = goog.getUid(opt_context); + if (key in this.imageByContext_) { + return this.imageByContext_[key]; + } else if (goog.object.isEmpty(this.imageByContext_)) { + image = this.image_; + } else { + image = /** @type {Image} */ (this.image_.cloneNode(false)); + } + this.imageByContext_[key] = image; + return image; + } else { + return this.image_; } - return maxSquaredDelta; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} maxSquaredDelta Max squared delta. - * @return {number} Max squared delta. + * @inheritDoc */ -ol.geom.flat.closest.getssMaxSquaredDelta = - function(flatCoordinates, offset, endss, stride, maxSquaredDelta) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta( - flatCoordinates, offset, ends, stride, maxSquaredDelta); - offset = ends[ends.length - 1]; - } - return maxSquaredDelta; +ol.ImageTile.prototype.getKey = function() { + return this.src_; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} maxDelta Max delta. - * @param {boolean} isRing Is ring. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @param {Array.<number>=} opt_tmpPoint Temporary point object. - * @return {number} Minimum squared distance. + * Tracks loading or read errors. + * + * @private */ -ol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end, - stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, - opt_tmpPoint) { - if (offset == end) { - return minSquaredDistance; - } - var i, squaredDistance; - if (maxDelta === 0) { - // All points are identical, so just test the first point. - squaredDistance = ol.math.squaredDistance( - x, y, flatCoordinates[offset], flatCoordinates[offset + 1]); - if (squaredDistance < minSquaredDistance) { - for (i = 0; i < stride; ++i) { - closestPoint[i] = flatCoordinates[offset + i]; - } - closestPoint.length = stride; - return squaredDistance; - } else { - return minSquaredDistance; - } - } - goog.asserts.assert(maxDelta > 0, 'maxDelta should be larger than 0'); - var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; - var index = offset + stride; - while (index < end) { - ol.geom.flat.closest.point( - flatCoordinates, index - stride, index, stride, x, y, tmpPoint); - squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); - if (squaredDistance < minSquaredDistance) { - minSquaredDistance = squaredDistance; - for (i = 0; i < stride; ++i) { - closestPoint[i] = tmpPoint[i]; - } - closestPoint.length = stride; - index += stride; - } else { - // Skip ahead multiple points, because we know that all the skipped - // points cannot be any closer than the closest point we have found so - // far. We know this because we know how close the current point is, how - // close the closest point we have found so far is, and the maximum - // distance between consecutive points. For example, if we're currently - // at distance 10, the best we've found so far is 3, and that the maximum - // distance between consecutive points is 2, then we'll need to skip at - // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of - // finding a closer point. We use Math.max(..., 1) to ensure that we - // always advance at least one point, to avoid an infinite loop. - index += stride * Math.max( - ((Math.sqrt(squaredDistance) - - Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1); - } - } - if (isRing) { - // Check the closing segment. - ol.geom.flat.closest.point( - flatCoordinates, end - stride, offset, stride, x, y, tmpPoint); - squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); - if (squaredDistance < minSquaredDistance) { - minSquaredDistance = squaredDistance; - for (i = 0; i < stride; ++i) { - closestPoint[i] = tmpPoint[i]; - } - closestPoint.length = stride; - } - } - return minSquaredDistance; +ol.ImageTile.prototype.handleImageError_ = function() { + this.state = ol.TileState.ERROR; + this.unlistenImage_(); + this.changed(); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} maxDelta Max delta. - * @param {boolean} isRing Is ring. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @param {Array.<number>=} opt_tmpPoint Temporary point object. - * @return {number} Minimum squared distance. + * Tracks successful image load. + * + * @private */ -ol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends, - stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, - opt_tmpPoint) { - var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - minSquaredDistance = ol.geom.flat.closest.getClosestPoint( - flatCoordinates, offset, end, stride, - maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint); - offset = end; +ol.ImageTile.prototype.handleImageLoad_ = function() { + if (this.image_.naturalWidth && this.image_.naturalHeight) { + this.state = ol.TileState.LOADED; + } else { + this.state = ol.TileState.EMPTY; } - return minSquaredDistance; + this.unlistenImage_(); + this.changed(); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} maxDelta Max delta. - * @param {boolean} isRing Is ring. - * @param {number} x X. - * @param {number} y Y. - * @param {Array.<number>} closestPoint Closest point. - * @param {number} minSquaredDistance Minimum squared distance. - * @param {Array.<number>=} opt_tmpPoint Temporary point object. - * @return {number} Minimum squared distance. + * Load not yet loaded URI. */ -ol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset, - endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, - opt_tmpPoint) { - var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - minSquaredDistance = ol.geom.flat.closest.getsClosestPoint( - flatCoordinates, offset, ends, stride, - maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint); - offset = ends[ends.length - 1]; +ol.ImageTile.prototype.load = function() { + if (this.state == ol.TileState.IDLE) { + this.state = ol.TileState.LOADING; + this.changed(); + goog.asserts.assert(!this.imageListenerKeys_, + 'this.imageListenerKeys_ should be null'); + this.imageListenerKeys_ = [ + goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, + this.handleImageError_, false, this), + goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, + this.handleImageLoad_, false, this) + ]; + this.tileLoadFunction_(this, this.src_); } - return minSquaredDistance; }; -goog.provide('ol.geom.flat.deflate'); + +/** + * Discards event handlers which listen for load completion or errors. + * + * @private + */ +ol.ImageTile.prototype.unlistenImage_ = function() { + goog.asserts.assert(this.imageListenerKeys_, + 'this.imageListenerKeys_ should not be null'); + this.imageListenerKeys_.forEach(goog.events.unlistenByKey); + this.imageListenerKeys_ = null; +}; + +goog.provide('ol.structs.LRUCache'); goog.require('goog.asserts'); +goog.require('goog.object'); + /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} stride Stride. - * @return {number} offset Offset. + * Implements a Least-Recently-Used cache where the keys do not conflict with + * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring + * items from the cache is the responsibility of the user. + * @constructor + * @struct + * @template T */ -ol.geom.flat.deflate.coordinate = - function(flatCoordinates, offset, coordinate, stride) { - goog.asserts.assert(coordinate.length == stride, - 'length of the coordinate array should match stride'); - var i, ii; - for (i = 0, ii = coordinate.length; i < ii; ++i) { - flatCoordinates[offset++] = coordinate[i]; - } - return offset; +ol.structs.LRUCache = function() { + + /** + * @private + * @type {number} + */ + this.count_ = 0; + + /** + * @private + * @type {Object.<string, ol.structs.LRUCacheEntry>} + */ + this.entries_ = {}; + + /** + * @private + * @type {?ol.structs.LRUCacheEntry} + */ + this.oldest_ = null; + + /** + * @private + * @type {?ol.structs.LRUCacheEntry} + */ + this.newest_ = null; + }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {number} stride Stride. - * @return {number} offset Offset. + * FIXME empty description for jsdoc */ -ol.geom.flat.deflate.coordinates = - function(flatCoordinates, offset, coordinates, stride) { - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - var coordinate = coordinates[i]; - goog.asserts.assert(coordinate.length == stride, - 'length of coordinate array should match stride'); - var j; - for (j = 0; j < stride; ++j) { - flatCoordinates[offset++] = coordinate[j]; +ol.structs.LRUCache.prototype.assertValid = function() { + if (this.count_ === 0) { + goog.asserts.assert(goog.object.isEmpty(this.entries_), + 'entries must be an empty object (count = 0)'); + goog.asserts.assert(!this.oldest_, + 'oldest must be null (count = 0)'); + goog.asserts.assert(!this.newest_, + 'newest must be null (count = 0)'); + } else { + goog.asserts.assert(goog.object.getCount(this.entries_) == this.count_, + 'number of entries matches count'); + goog.asserts.assert(this.oldest_, + 'we have an oldest entry'); + goog.asserts.assert(!this.oldest_.older, + 'no entry is older than oldest'); + goog.asserts.assert(this.newest_, + 'we have a newest entry'); + goog.asserts.assert(!this.newest_.newer, + 'no entry is newer than newest'); + var i, entry; + var older = null; + i = 0; + for (entry = this.oldest_; entry; entry = entry.newer) { + goog.asserts.assert(entry.older === older, + 'entry.older links to correct older'); + older = entry; + ++i; + } + goog.asserts.assert(i == this.count_, 'iterated correct amount of times'); + var newer = null; + i = 0; + for (entry = this.newest_; entry; entry = entry.older) { + goog.asserts.assert(entry.newer === newer, + 'entry.newer links to correct newer'); + newer = entry; + ++i; } + goog.asserts.assert(i == this.count_, 'iterated correct amount of times'); } - return offset; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess. - * @param {number} stride Stride. - * @param {Array.<number>=} opt_ends Ends. - * @return {Array.<number>} Ends. + * FIXME empty description for jsdoc */ -ol.geom.flat.deflate.coordinatess = - function(flatCoordinates, offset, coordinatess, stride, opt_ends) { - var ends = opt_ends ? opt_ends : []; - var i = 0; - var j, jj; - for (j = 0, jj = coordinatess.length; j < jj; ++j) { - var end = ol.geom.flat.deflate.coordinates( - flatCoordinates, offset, coordinatess[j], stride); - ends[i++] = end; - offset = end; - } - ends.length = i; - return ends; +ol.structs.LRUCache.prototype.clear = function() { + this.count_ = 0; + this.entries_ = {}; + this.oldest_ = null; + this.newest_ = null; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss. - * @param {number} stride Stride. - * @param {Array.<Array.<number>>=} opt_endss Endss. - * @return {Array.<Array.<number>>} Endss. + * @param {string} key Key. + * @return {boolean} Contains key. */ -ol.geom.flat.deflate.coordinatesss = - function(flatCoordinates, offset, coordinatesss, stride, opt_endss) { - var endss = opt_endss ? opt_endss : []; - var i = 0; - var j, jj; - for (j = 0, jj = coordinatesss.length; j < jj; ++j) { - var ends = ol.geom.flat.deflate.coordinatess( - flatCoordinates, offset, coordinatesss[j], stride, endss[i]); - endss[i++] = ends; - offset = ends[ends.length - 1]; - } - endss.length = i; - return endss; +ol.structs.LRUCache.prototype.containsKey = function(key) { + return this.entries_.hasOwnProperty(key); }; -goog.provide('ol.geom.flat.inflate'); + +/** + * @param {function(this: S, T, string, ol.structs.LRUCache): ?} f The function + * to call for every entry from the oldest to the newer. This function takes + * 3 arguments (the entry value, the entry key and the LRUCache object). + * The return value is ignored. + * @param {S=} opt_this The object to use as `this` in `f`. + * @template S + */ +ol.structs.LRUCache.prototype.forEach = function(f, opt_this) { + var entry = this.oldest_; + while (entry) { + f.call(opt_this, entry.value_, entry.key_, this); + entry = entry.newer; + } +}; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates. - * @return {Array.<ol.Coordinate>} Coordinates. + * @param {string} key Key. + * @return {T} Value. */ -ol.geom.flat.inflate.coordinates = - function(flatCoordinates, offset, end, stride, opt_coordinates) { - var coordinates = opt_coordinates !== undefined ? opt_coordinates : []; - var i = 0; - var j; - for (j = offset; j < end; j += stride) { - coordinates[i++] = flatCoordinates.slice(j, j + stride); +ol.structs.LRUCache.prototype.get = function(key) { + var entry = this.entries_[key]; + goog.asserts.assert(entry !== undefined, 'an entry exists for key %s', key); + if (entry === this.newest_) { + return entry.value_; + } else if (entry === this.oldest_) { + this.oldest_ = this.oldest_.newer; + this.oldest_.older = null; + } else { + entry.newer.older = entry.older; + entry.older.newer = entry.newer; } - coordinates.length = i; - return coordinates; + entry.newer = null; + entry.older = this.newest_; + this.newest_.newer = entry; + this.newest_ = entry; + return entry.value_; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess. - * @return {Array.<Array.<ol.Coordinate>>} Coordinatess. + * @return {number} Count. */ -ol.geom.flat.inflate.coordinatess = - function(flatCoordinates, offset, ends, stride, opt_coordinatess) { - var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : []; +ol.structs.LRUCache.prototype.getCount = function() { + return this.count_; +}; + + +/** + * @return {Array.<string>} Keys. + */ +ol.structs.LRUCache.prototype.getKeys = function() { + var keys = new Array(this.count_); var i = 0; - var j, jj; - for (j = 0, jj = ends.length; j < jj; ++j) { - var end = ends[j]; - coordinatess[i++] = ol.geom.flat.inflate.coordinates( - flatCoordinates, offset, end, stride, coordinatess[i]); - offset = end; + var entry; + for (entry = this.newest_; entry; entry = entry.older) { + keys[i++] = entry.key_; } - coordinatess.length = i; - return coordinatess; + goog.asserts.assert(i == this.count_, 'iterated correct number of times'); + return keys; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss - * Coordinatesss. - * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss. + * @return {Array.<T>} Values. */ -ol.geom.flat.inflate.coordinatesss = - function(flatCoordinates, offset, endss, stride, opt_coordinatesss) { - var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : []; +ol.structs.LRUCache.prototype.getValues = function() { + var values = new Array(this.count_); var i = 0; - var j, jj; - for (j = 0, jj = endss.length; j < jj; ++j) { - var ends = endss[j]; - coordinatesss[i++] = ol.geom.flat.inflate.coordinatess( - flatCoordinates, offset, ends, stride, coordinatesss[i]); - offset = ends[ends.length - 1]; + var entry; + for (entry = this.newest_; entry; entry = entry.older) { + values[i++] = entry.value_; } - coordinatesss.length = i; - return coordinatesss; + goog.asserts.assert(i == this.count_, 'iterated correct number of times'); + return values; }; -// Based on simplify-js https://github.com/mourner/simplify-js -// Copyright (c) 2012, Vladimir Agafonkin -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -goog.provide('ol.geom.flat.simplify'); +/** + * @return {T} Last value. + */ +ol.structs.LRUCache.prototype.peekLast = function() { + goog.asserts.assert(this.oldest_, 'oldest must not be null'); + return this.oldest_.value_; +}; -goog.require('ol.math'); + +/** + * @return {string} Last key. + */ +ol.structs.LRUCache.prototype.peekLastKey = function() { + goog.asserts.assert(this.oldest_, 'oldest must not be null'); + return this.oldest_.key_; +}; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {boolean} highQuality Highest quality. - * @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat - * coordinates. - * @return {Array.<number>} Simplified line string. + * @return {T} value Value. */ -ol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end, - stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) { - var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ? - opt_simplifiedFlatCoordinates : []; - if (!highQuality) { - end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end, - stride, squaredTolerance, - simplifiedFlatCoordinates, 0); - flatCoordinates = simplifiedFlatCoordinates; - offset = 0; - stride = 2; +ol.structs.LRUCache.prototype.pop = function() { + goog.asserts.assert(this.oldest_, 'oldest must not be null'); + goog.asserts.assert(this.newest_, 'newest must not be null'); + var entry = this.oldest_; + goog.asserts.assert(entry.key_ in this.entries_, + 'oldest is indexed in entries'); + delete this.entries_[entry.key_]; + if (entry.newer) { + entry.newer.older = null; } - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( - flatCoordinates, offset, end, stride, squaredTolerance, - simplifiedFlatCoordinates, 0); - return simplifiedFlatCoordinates; + this.oldest_ = entry.newer; + if (!this.oldest_) { + this.newest_ = null; + } + --this.count_; + return entry.value_; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @return {number} Simplified offset. + * @param {string} key Key. + * @param {T} value Value. */ -ol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end, - stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) { - var n = (end - offset) / stride; - if (n < 3) { - for (; offset < end; offset += stride) { - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset]; - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + 1]; - } - return simplifiedOffset; - } - /** @type {Array.<number>} */ - var markers = new Array(n); - markers[0] = 1; - markers[n - 1] = 1; - /** @type {Array.<number>} */ - var stack = [offset, end - stride]; - var index = 0; - var i; - while (stack.length > 0) { - var last = stack.pop(); - var first = stack.pop(); - var maxSquaredDistance = 0; - var x1 = flatCoordinates[first]; - var y1 = flatCoordinates[first + 1]; - var x2 = flatCoordinates[last]; - var y2 = flatCoordinates[last + 1]; - for (i = first + stride; i < last; i += stride) { - var x = flatCoordinates[i]; - var y = flatCoordinates[i + 1]; - var squaredDistance = ol.math.squaredSegmentDistance( - x, y, x1, y1, x2, y2); - if (squaredDistance > maxSquaredDistance) { - index = i; - maxSquaredDistance = squaredDistance; - } - } - if (maxSquaredDistance > squaredTolerance) { - markers[(index - offset) / stride] = 1; - if (first + stride < index) { - stack.push(first, index); - } - if (index + stride < last) { - stack.push(index, last); - } - } - } - for (i = 0; i < n; ++i) { - if (markers[i]) { - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + i * stride]; - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + i * stride + 1]; - } - } - return simplifiedOffset; +ol.structs.LRUCache.prototype.replace = function(key, value) { + this.get(key); // update `newest_` + this.entries_[key].value_ = value; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<number>} simplifiedEnds Simplified ends. - * @return {number} Simplified offset. + * @param {string} key Key. + * @param {T} value Value. */ -ol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset, - ends, stride, squaredTolerance, simplifiedFlatCoordinates, - simplifiedOffset, simplifiedEnds) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - simplifiedOffset = ol.geom.flat.simplify.douglasPeucker( - flatCoordinates, offset, end, stride, squaredTolerance, - simplifiedFlatCoordinates, simplifiedOffset); - simplifiedEnds.push(simplifiedOffset); - offset = end; +ol.structs.LRUCache.prototype.set = function(key, value) { + goog.asserts.assert(!(key in {}), + 'key is not a standard property of objects (e.g. "__proto__")'); + goog.asserts.assert(!(key in this.entries_), + 'key is not used already'); + var entry = { + key_: key, + newer: null, + older: this.newest_, + value_: value + }; + if (!this.newest_) { + this.oldest_ = entry; + } else { + this.newest_.newer = entry; } - return simplifiedOffset; + this.newest_ = entry; + this.entries_[key] = entry; + ++this.count_; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss. - * @return {number} Simplified offset. + * @typedef {{key_: string, + * newer: ol.structs.LRUCacheEntry, + * older: ol.structs.LRUCacheEntry, + * value_: *}} */ -ol.geom.flat.simplify.douglasPeuckerss = function( - flatCoordinates, offset, endss, stride, squaredTolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - var simplifiedEnds = []; - simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers( - flatCoordinates, offset, ends, stride, squaredTolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds); - simplifiedEndss.push(simplifiedEnds); - offset = ends[ends.length - 1]; - } - return simplifiedOffset; -}; +ol.structs.LRUCacheEntry; + +goog.provide('ol.TileCache'); + +goog.require('ol'); +goog.require('ol.TileRange'); +goog.require('ol.structs.LRUCache'); +goog.require('ol.tilecoord'); + /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} squaredTolerance Squared tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @return {number} Simplified offset. + * @constructor + * @extends {ol.structs.LRUCache.<ol.Tile>} + * @param {number=} opt_highWaterMark High water mark. + * @struct */ -ol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end, - stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) { - if (end <= offset + stride) { - // zero or one point, no simplification possible, so copy and return - for (; offset < end; offset += stride) { - simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset]; - simplifiedFlatCoordinates[simplifiedOffset++] = - flatCoordinates[offset + 1]; - } - return simplifiedOffset; - } - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - // copy first point - simplifiedFlatCoordinates[simplifiedOffset++] = x1; - simplifiedFlatCoordinates[simplifiedOffset++] = y1; - var x2 = x1; - var y2 = y1; - for (offset += stride; offset < end; offset += stride) { - x2 = flatCoordinates[offset]; - y2 = flatCoordinates[offset + 1]; - if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) { - // copy point at offset - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - x1 = x2; - y1 = y2; - } - } - if (x2 != x1 || y2 != y1) { - // copy last point - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - } - return simplifiedOffset; +ol.TileCache = function(opt_highWaterMark) { + + goog.base(this); + + /** + * @private + * @type {number} + */ + this.highWaterMark_ = opt_highWaterMark !== undefined ? + opt_highWaterMark : ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK; + }; +goog.inherits(ol.TileCache, ol.structs.LRUCache); /** - * @param {number} value Value. - * @param {number} tolerance Tolerance. - * @return {number} Rounded value. + * @return {boolean} Can expire cache. */ -ol.geom.flat.simplify.snap = function(value, tolerance) { - return tolerance * Math.round(value / tolerance); +ol.TileCache.prototype.canExpireCache = function() { + return this.getCount() > this.highWaterMark_; }; /** - * Simplifies a line string using an algorithm designed by Tim Schaub. - * Coordinates are snapped to the nearest value in a virtual grid and - * consecutive duplicate coordinates are discarded. This effectively preserves - * topology as the simplification of any subsection of a line string is - * independent of the rest of the line string. This means that, for examples, - * the common edge between two polygons will be simplified to the same line - * string independently in both polygons. This implementation uses a single - * pass over the coordinates and eliminates intermediate collinear points. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} tolerance Tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @return {number} Simplified offset. + * @param {Object.<string, ol.TileRange>} usedTiles Used tiles. */ -ol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride, - tolerance, simplifiedFlatCoordinates, simplifiedOffset) { - // do nothing if the line is empty - if (offset == end) { - return simplifiedOffset; - } - // snap the first coordinate (P1) - var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); - var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); - offset += stride; - // add the first coordinate to the output - simplifiedFlatCoordinates[simplifiedOffset++] = x1; - simplifiedFlatCoordinates[simplifiedOffset++] = y1; - // find the next coordinate that does not snap to the same value as the first - // coordinate (P2) - var x2, y2; - do { - x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); - y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); - offset += stride; - if (offset == end) { - // all coordinates snap to the same value, the line collapses to a point - // push the last snapped value anyway to ensure that the output contains - // at least two points - // FIXME should we really return at least two points anyway? - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - return simplifiedOffset; - } - } while (x2 == x1 && y2 == y1); - while (offset < end) { - var x3, y3; - // snap the next coordinate (P3) - x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); - y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); - offset += stride; - // skip P3 if it is equal to P2 - if (x3 == x2 && y3 == y2) { - continue; - } - // calculate the delta between P1 and P2 - var dx1 = x2 - x1; - var dy1 = y2 - y1; - // calculate the delta between P3 and P1 - var dx2 = x3 - x1; - var dy2 = y3 - y1; - // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from - // P1 in the same direction then P2 is on the straight line between P1 and - // P3 - if ((dx1 * dy2 == dy1 * dx2) && - ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) && - ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) { - // discard P2 and set P2 = P3 - x2 = x3; - y2 = y3; - continue; +ol.TileCache.prototype.expireCache = function(usedTiles) { + var tile, zKey; + while (this.canExpireCache()) { + tile = this.peekLast(); + zKey = tile.tileCoord[0].toString(); + if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) { + break; + } else { + this.pop().dispose(); } - // either P1, P2, and P3 are not colinear, or they are colinear but P3 is - // between P3 and P1 or on the opposite half of the line to P2. add P2, - // and continue with P1 = P2 and P2 = P3 - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - x1 = x2; - y1 = y2; - x2 = x3; - y2 = y3; } - // add the last point (P2) - simplifiedFlatCoordinates[simplifiedOffset++] = x2; - simplifiedFlatCoordinates[simplifiedOffset++] = y2; - return simplifiedOffset; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} tolerance Tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<number>} simplifiedEnds Simplified ends. - * @return {number} Simplified offset. + * Remove a tile range from the cache, e.g. to invalidate tiles. + * @param {ol.TileRange} tileRange The tile range to prune. */ -ol.geom.flat.simplify.quantizes = function( - flatCoordinates, offset, ends, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - simplifiedOffset = ol.geom.flat.simplify.quantize( - flatCoordinates, offset, end, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset); - simplifiedEnds.push(simplifiedOffset); - offset = end; +ol.TileCache.prototype.pruneTileRange = function(tileRange) { + var i = this.getCount(), + key; + while (i--) { + key = this.peekLastKey(); + if (tileRange.contains(ol.tilecoord.createFromString(key))) { + this.pop().dispose(); + } else { + this.get(key); + } } - return simplifiedOffset; }; +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} tolerance Tolerance. - * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat - * coordinates. - * @param {number} simplifiedOffset Simplified offset. - * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss. - * @return {number} Simplified offset. + * @fileoverview Browser capability checks for the dom package. + * */ -ol.geom.flat.simplify.quantizess = function( - flatCoordinates, offset, endss, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - var simplifiedEnds = []; - simplifiedOffset = ol.geom.flat.simplify.quantizes( - flatCoordinates, offset, ends, stride, - tolerance, - simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds); - simplifiedEndss.push(simplifiedEnds); - offset = ends[ends.length - 1]; - } - return simplifiedOffset; -}; -goog.provide('ol.geom.LinearRing'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.area'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.simplify'); +goog.provide('goog.dom.BrowserFeature'); +goog.require('goog.userAgent'); /** - * @classdesc - * Linear ring geometry. Only used as part of polygon; cannot be rendered - * on its own. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * Enum of browser capabilities. + * @enum {boolean} */ -ol.geom.LinearRing = function(coordinates, opt_layout) { - - goog.base(this); - +goog.dom.BrowserFeature = { /** - * @private - * @type {number} + * Whether attributes 'name' and 'type' can be added to an element after it's + * created. False in Internet Explorer prior to version 9. */ - this.maxDelta_ = -1; + CAN_ADD_NAME_OR_TYPE_ATTRIBUTES: !goog.userAgent.IE || + goog.userAgent.isDocumentModeOrHigher(9), /** - * @private - * @type {number} + * Whether we can use element.children to access an element's Element + * children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment + * nodes in the collection.) */ - this.maxDeltaRevision_ = -1; - - this.setCoordinates(coordinates, opt_layout); - -}; -goog.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry); - - -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.LinearRing} Clone. - * @api stable - */ -ol.geom.LinearRing.prototype.clone = function() { - var linearRing = new ol.geom.LinearRing(null); - linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return linearRing; -}; + CAN_USE_CHILDREN_ATTRIBUTE: !goog.userAgent.GECKO && !goog.userAgent.IE || + goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9) || + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'), + /** + * Opera, Safari 3, and Internet Explorer 9 all support innerText but they + * include text nodes in script and style tags. Not document-mode-dependent. + */ + CAN_USE_INNER_TEXT: ( + goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')), -/** - * @inheritDoc - */ -ol.geom.LinearRing.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getClosestPoint( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); -}; + /** + * MSIE, Opera, and Safari>=4 support element.parentElement to access an + * element's parent if it is an Element. + */ + CAN_USE_PARENT_ELEMENT_PROPERTY: goog.userAgent.IE || goog.userAgent.OPERA || + goog.userAgent.WEBKIT, + /** + * Whether NoScope elements need a scoped element written before them in + * innerHTML. + * MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1 + */ + INNER_HTML_NEEDS_SCOPED_ELEMENT: goog.userAgent.IE, -/** - * Return the area of the linear ring on projected plane. - * @return {number} Area (on projected plane). - * @api stable - */ -ol.geom.LinearRing.prototype.getArea = function() { - return ol.geom.flat.area.linearRing( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); + /** + * Whether we use legacy IE range API. + */ + LEGACY_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) }; +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Return the coordinates of the linear ring. - * @return {Array.<ol.Coordinate>} Coordinates. - * @api stable + * @fileoverview Defines the goog.dom.TagName enum. This enumerates + * all HTML tag names specified in either the the W3C HTML 4.01 index of + * elements or the HTML5 draft specification. + * + * References: + * http://www.w3.org/TR/html401/index/elements.html + * http://dev.w3.org/html5/spec/section-index.html + * */ -ol.geom.LinearRing.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; +goog.provide('goog.dom.TagName'); /** - * @inheritDoc + * Enum of all html tag names specified by the W3C HTML4.01 and HTML5 + * specifications. + * @enum {string} */ -ol.geom.LinearRing.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - squaredTolerance, simplifiedFlatCoordinates, 0); - var simplifiedLinearRing = new ol.geom.LinearRing(null); - simplifiedLinearRing.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates); - return simplifiedLinearRing; +goog.dom.TagName = { + A: 'A', + ABBR: 'ABBR', + ACRONYM: 'ACRONYM', + ADDRESS: 'ADDRESS', + APPLET: 'APPLET', + AREA: 'AREA', + ARTICLE: 'ARTICLE', + ASIDE: 'ASIDE', + AUDIO: 'AUDIO', + B: 'B', + BASE: 'BASE', + BASEFONT: 'BASEFONT', + BDI: 'BDI', + BDO: 'BDO', + BIG: 'BIG', + BLOCKQUOTE: 'BLOCKQUOTE', + BODY: 'BODY', + BR: 'BR', + BUTTON: 'BUTTON', + CANVAS: 'CANVAS', + CAPTION: 'CAPTION', + CENTER: 'CENTER', + CITE: 'CITE', + CODE: 'CODE', + COL: 'COL', + COLGROUP: 'COLGROUP', + COMMAND: 'COMMAND', + DATA: 'DATA', + DATALIST: 'DATALIST', + DD: 'DD', + DEL: 'DEL', + DETAILS: 'DETAILS', + DFN: 'DFN', + DIALOG: 'DIALOG', + DIR: 'DIR', + DIV: 'DIV', + DL: 'DL', + DT: 'DT', + EM: 'EM', + EMBED: 'EMBED', + FIELDSET: 'FIELDSET', + FIGCAPTION: 'FIGCAPTION', + FIGURE: 'FIGURE', + FONT: 'FONT', + FOOTER: 'FOOTER', + FORM: 'FORM', + FRAME: 'FRAME', + FRAMESET: 'FRAMESET', + H1: 'H1', + H2: 'H2', + H3: 'H3', + H4: 'H4', + H5: 'H5', + H6: 'H6', + HEAD: 'HEAD', + HEADER: 'HEADER', + HGROUP: 'HGROUP', + HR: 'HR', + HTML: 'HTML', + I: 'I', + IFRAME: 'IFRAME', + IMG: 'IMG', + INPUT: 'INPUT', + INS: 'INS', + ISINDEX: 'ISINDEX', + KBD: 'KBD', + KEYGEN: 'KEYGEN', + LABEL: 'LABEL', + LEGEND: 'LEGEND', + LI: 'LI', + LINK: 'LINK', + MAP: 'MAP', + MARK: 'MARK', + MATH: 'MATH', + MENU: 'MENU', + META: 'META', + METER: 'METER', + NAV: 'NAV', + NOFRAMES: 'NOFRAMES', + NOSCRIPT: 'NOSCRIPT', + OBJECT: 'OBJECT', + OL: 'OL', + OPTGROUP: 'OPTGROUP', + OPTION: 'OPTION', + OUTPUT: 'OUTPUT', + P: 'P', + PARAM: 'PARAM', + PRE: 'PRE', + PROGRESS: 'PROGRESS', + Q: 'Q', + RP: 'RP', + RT: 'RT', + RUBY: 'RUBY', + S: 'S', + SAMP: 'SAMP', + SCRIPT: 'SCRIPT', + SECTION: 'SECTION', + SELECT: 'SELECT', + SMALL: 'SMALL', + SOURCE: 'SOURCE', + SPAN: 'SPAN', + STRIKE: 'STRIKE', + STRONG: 'STRONG', + STYLE: 'STYLE', + SUB: 'SUB', + SUMMARY: 'SUMMARY', + SUP: 'SUP', + SVG: 'SVG', + TABLE: 'TABLE', + TBODY: 'TBODY', + TD: 'TD', + TEMPLATE: 'TEMPLATE', + TEXTAREA: 'TEXTAREA', + TFOOT: 'TFOOT', + TH: 'TH', + THEAD: 'THEAD', + TIME: 'TIME', + TITLE: 'TITLE', + TR: 'TR', + TRACK: 'TRACK', + TT: 'TT', + U: 'U', + UL: 'UL', + VAR: 'VAR', + VIDEO: 'VIDEO', + WBR: 'WBR' }; +// Copyright 2014 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @inheritDoc - * @api stable + * @fileoverview Utilities for HTML element tag names. */ -ol.geom.LinearRing.prototype.getType = function() { - return ol.geom.GeometryType.LINEAR_RING; -}; +goog.provide('goog.dom.tags'); + +goog.require('goog.object'); /** - * Set the coordinates of the linear ring. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * The void elements specified by + * http://www.w3.org/TR/html-markup/syntax.html#void-elements. + * @const @private {!Object<string, boolean>} */ -ol.geom.LinearRing.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 1); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); - } -}; +goog.dom.tags.VOID_TAGS_ = goog.object.createSet( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', + 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'); /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. + * Checks whether the tag is void (with no contents allowed and no legal end + * tag), for example 'br'. + * @param {string} tagName The tag name in lower case. + * @return {boolean} */ -ol.geom.LinearRing.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); +goog.dom.tags.isVoidTag = function(tagName) { + return goog.dom.tags.VOID_TAGS_[tagName] === true; }; -goog.provide('ol.geom.Point'); +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.math'); +goog.provide('goog.string.TypedString'); /** - * @classdesc - * Point geometry. + * Wrapper for strings that conform to a data type or language. * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {ol.Coordinate} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * Implementations of this interface are wrappers for strings, and typically + * associate a type contract with the wrapped string. Concrete implementations + * of this interface may choose to implement additional run-time type checking, + * see for example {@code goog.html.SafeHtml}. If available, client code that + * needs to ensure type membership of an object should use the type's function + * to assert type membership, such as {@code goog.html.SafeHtml.unwrap}. + * @interface */ -ol.geom.Point = function(coordinates, opt_layout) { - goog.base(this); - this.setCoordinates(coordinates, opt_layout); -}; -goog.inherits(ol.geom.Point, ol.geom.SimpleGeometry); +goog.string.TypedString = function() {}; /** - * Make a complete copy of the geometry. - * @return {!ol.geom.Point} Clone. - * @api stable + * Interface marker of the TypedString interface. + * + * This property can be used to determine at runtime whether or not an object + * implements this interface. All implementations of this interface set this + * property to {@code true}. + * @type {boolean} */ -ol.geom.Point.prototype.clone = function() { - var point = new ol.geom.Point(null); - point.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return point; -}; +goog.string.TypedString.prototype.implementsGoogStringTypedString; /** - * @inheritDoc + * Retrieves this wrapped string's value. + * @return {!string} The wrapped string's value. */ -ol.geom.Point.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - var flatCoordinates = this.flatCoordinates; - var squaredDistance = ol.math.squaredDistance( - x, y, flatCoordinates[0], flatCoordinates[1]); - if (squaredDistance < minSquaredDistance) { - var stride = this.stride; - var i; - for (i = 0; i < stride; ++i) { - closestPoint[i] = flatCoordinates[i]; - } - closestPoint.length = stride; - return squaredDistance; - } else { - return minSquaredDistance; - } -}; +goog.string.TypedString.prototype.getTypedStringValue; + +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +goog.provide('goog.string.Const'); + +goog.require('goog.asserts'); +goog.require('goog.string.TypedString'); + /** - * Return the coordinate of the point. - * @return {ol.Coordinate} Coordinates. - * @api stable + * Wrapper for compile-time-constant strings. + * + * Const is a wrapper for strings that can only be created from program + * constants (i.e., string literals). This property relies on a custom Closure + * compiler check that {@code goog.string.Const.from} is only invoked on + * compile-time-constant expressions. + * + * Const is useful in APIs whose correct and secure use requires that certain + * arguments are not attacker controlled: Compile-time constants are inherently + * under the control of the application and not under control of external + * attackers, and hence are safe to use in such contexts. + * + * Instances of this type must be created via its factory method + * {@code goog.string.Const.from} and not by invoking its constructor. The + * constructor intentionally takes no parameters and the type is immutable; + * hence only a default instance corresponding to the empty string can be + * obtained via constructor invocation. + * + * @see goog.string.Const#from + * @constructor + * @final + * @struct + * @implements {goog.string.TypedString} */ -ol.geom.Point.prototype.getCoordinates = function() { - return !this.flatCoordinates ? [] : this.flatCoordinates.slice(); +goog.string.Const = function() { + /** + * The wrapped value of this Const object. The field has a purposely ugly + * name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} + */ + this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = ''; + + /** + * A type marker used to implement additional run-time type checking. + * @see goog.string.Const#unwrap + * @const + * @private + */ + this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ = + goog.string.Const.TYPE_MARKER_; }; /** - * @inheritDoc + * @override + * @const */ -ol.geom.Point.prototype.computeExtent = function(extent) { - return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent); -}; +goog.string.Const.prototype.implementsGoogStringTypedString = true; /** - * @inheritDoc - * @api stable + * Returns this Const's value a string. + * + * IMPORTANT: In code where it is security-relevant that an object's type is + * indeed {@code goog.string.Const}, use {@code goog.string.Const.unwrap} + * instead of this method. + * + * @see goog.string.Const#unwrap + * @override */ -ol.geom.Point.prototype.getType = function() { - return ol.geom.GeometryType.POINT; +goog.string.Const.prototype.getTypedStringValue = function() { + return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_; }; /** - * @inheritDoc - * @api stable + * Returns a debug-string representation of this value. + * + * To obtain the actual string value wrapped inside an object of this type, + * use {@code goog.string.Const.unwrap}. + * + * @see goog.string.Const#unwrap + * @override */ -ol.geom.Point.prototype.intersectsExtent = function(extent) { - return ol.extent.containsXY(extent, - this.flatCoordinates[0], this.flatCoordinates[1]); +goog.string.Const.prototype.toString = function() { + return 'Const{' + + this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ + + '}'; }; /** - * Set the coordinate of the point. - * @param {ol.Coordinate} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * Performs a runtime check that the provided object is indeed an instance + * of {@code goog.string.Const}, and returns its value. + * @param {!goog.string.Const} stringConst The object to extract from. + * @return {string} The Const object's contained string, unless the run-time + * type check fails. In that case, {@code unwrap} returns an innocuous + * string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); +goog.string.Const.unwrap = function(stringConst) { + // Perform additional run-time type-checking to ensure that stringConst is + // indeed an instance of the expected type. This provides some additional + // protection against security bugs due to application code that disables type + // checks. + if (stringConst instanceof goog.string.Const && + stringConst.constructor === goog.string.Const && + stringConst.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ === + goog.string.Const.TYPE_MARKER_) { + return stringConst. + stringConstValueWithSecurityContract__googStringSecurityPrivate_; } else { - this.setLayout(opt_layout, coordinates, 0); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinate( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); + goog.asserts.fail('expected object of type Const, got \'' + + stringConst + '\''); + return 'type_error:Const'; } }; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. + * Creates a Const object from a compile-time constant string. + * + * It is illegal to invoke this function on an expression whose + * compile-time-contant value cannot be determined by the Closure compiler. + * + * Correct invocations include, + * <pre> + * var s = goog.string.Const.from('hello'); + * var t = goog.string.Const.from('hello' + 'world'); + * </pre> + * + * In contrast, the following are illegal: + * <pre> + * var s = goog.string.Const.from(getHello()); + * var t = goog.string.Const.from('hello' + world); + * </pre> + * + * TODO(xtof): Compile-time checks that this function is only called + * with compile-time constant expressions. + * + * @param {string} s A constant string from which to create a Const. + * @return {!goog.string.Const} A Const object initialized to stringConst. */ -ol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); +goog.string.Const.from = function(s) { + return goog.string.Const.create__googStringSecurityPrivate_(s); }; -goog.provide('ol.geom.flat.contains'); -goog.require('goog.asserts'); -goog.require('ol.extent'); +/** + * Type marker for the Const type, used to implement additional run-time + * type checking. + * @const {!Object} + * @private + */ +goog.string.Const.TYPE_MARKER_ = {}; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} Contains extent. + * Utility method to create Const instances. + * @param {string} s The string to initialize the Const object with. + * @return {!goog.string.Const} The initialized Const object. + * @private */ -ol.geom.flat.contains.linearRingContainsExtent = - function(flatCoordinates, offset, end, stride, extent) { - var outside = ol.extent.forEachCorner(extent, - /** - * @param {ol.Coordinate} coordinate Coordinate. - */ - function(coordinate) { - return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates, - offset, end, stride, coordinate[0], coordinate[1]); - }); - return !outside; +goog.string.Const.create__googStringSecurityPrivate_ = function(s) { + var stringConst = new goog.string.Const(); + stringConst.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = + s; + return stringConst; }; +// Copyright 2014 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). + * @fileoverview The SafeStyle type and its builders. + * + * TODO(xtof): Link to document stating type contract. */ -ol.geom.flat.contains.linearRingContainsXY = - function(flatCoordinates, offset, end, stride, x, y) { - // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html - var contains = false; - var x1 = flatCoordinates[end - stride]; - var y1 = flatCoordinates[end - stride + 1]; - for (; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - var intersect = ((y1 > y) != (y2 > y)) && - (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1); - if (intersect) { - contains = !contains; - } - x1 = x2; - y1 = y2; - } - return contains; -}; + +goog.provide('goog.html.SafeStyle'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.string'); +goog.require('goog.string.Const'); +goog.require('goog.string.TypedString'); + /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). + * A string-like object which represents a sequence of CSS declarations + * ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...}) + * and that carries the security type contract that its value, as a string, + * will not cause untrusted script execution (XSS) when evaluated as CSS in a + * browser. + * + * Instances of this type must be created via the factory methods + * ({@code goog.html.SafeStyle.create} or + * {@code goog.html.SafeStyle.fromConstant}) and not by invoking its + * constructor. The constructor intentionally takes no parameters and the type + * is immutable; hence only a default instance corresponding to the empty string + * can be obtained via constructor invocation. + * + * A SafeStyle's string representation ({@link #getTypedStringValue()}) can + * safely: + * <ul> + * <li>Be interpolated as the entire content of a *quoted* HTML style + * attribute, or before already existing properties. The SafeStyle string + * *must be HTML-attribute-escaped* (where " and ' are escaped) before + * interpolation. + * <li>Be interpolated as the entire content of a {}-wrapped block within a + * stylesheet, or before already existing properties. The SafeStyle string + * should not be escaped before interpolation. SafeStyle's contract also + * guarantees that the string will not be able to introduce new properties + * or elide existing ones. + * <li>Be assigned to the style property of a DOM node. The SafeStyle string + * should not be escaped before being assigned to the property. + * </ul> + * + * A SafeStyle may never contain literal angle brackets. Otherwise, it could + * be unsafe to place a SafeStyle into a <style> tag (where it can't + * be HTML escaped). For example, if the SafeStyle containing + * "{@code font: 'foo <style/><script>evil</script>'}" were + * interpolated within a <style> tag, this would then break out of the + * style context into HTML. + * + * A SafeStyle may contain literal single or double quotes, and as such the + * entire style string must be escaped when used in a style attribute (if + * this were not the case, the string could contain a matching quote that + * would escape from the style attribute). + * + * Values of this type must be composable, i.e. for any two values + * {@code style1} and {@code style2} of this type, + * {@code goog.html.SafeStyle.unwrap(style1) + + * goog.html.SafeStyle.unwrap(style2)} must itself be a value that satisfies + * the SafeStyle type constraint. This requirement implies that for any value + * {@code style} of this type, {@code goog.html.SafeStyle.unwrap(style)} must + * not end in a "property value" or "property name" context. For example, + * a value of {@code background:url("} or {@code font-} would not satisfy the + * SafeStyle contract. This is because concatenating such strings with a + * second value that itself does not contain unsafe CSS can result in an + * overall string that does. For example, if {@code javascript:evil())"} is + * appended to {@code background:url("}, the resulting string may result in + * the execution of a malicious script. + * + * TODO(user): Consider whether we should implement UTF-8 interchange + * validity checks and blacklisting of newlines (including Unicode ones) and + * other whitespace characters (\t, \f). Document here if so and also update + * SafeStyle.fromConstant(). + * + * The following example values comply with this type's contract: + * <ul> + * <li><pre>width: 1em;</pre> + * <li><pre>height:1em;</pre> + * <li><pre>width: 1em;height: 1em;</pre> + * <li><pre>background:url('http://url');</pre> + * </ul> + * In addition, the empty string is safe for use in a CSS attribute. + * + * The following example values do NOT comply with this type's contract: + * <ul> + * <li><pre>background: red</pre> (missing a trailing semi-colon) + * <li><pre>background:</pre> (missing a value and a trailing semi-colon) + * <li><pre>1em</pre> (missing an attribute name, which provides context for + * the value) + * </ul> + * + * @see goog.html.SafeStyle#create + * @see goog.html.SafeStyle#fromConstant + * @see http://www.w3.org/TR/css3-syntax/ + * @constructor + * @final + * @struct + * @implements {goog.string.TypedString} */ -ol.geom.flat.contains.linearRingsContainsXY = - function(flatCoordinates, offset, ends, stride, x, y) { - goog.asserts.assert(ends.length > 0, 'ends should not be an empty array'); - if (ends.length === 0) { - return false; - } - if (!ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, ends[0], stride, x, y)) { - return false; - } - var i, ii; - for (i = 1, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, ends[i - 1], ends[i], stride, x, y)) { - return false; - } - } - return true; +goog.html.SafeStyle = function() { + /** + * The contained value of this SafeStyle. The field has a purposely + * ugly name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} + */ + this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = ''; + + /** + * A type marker used to implement additional run-time type checking. + * @see goog.html.SafeStyle#unwrap + * @const + * @private + */ + this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = + goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). + * @override + * @const */ -ol.geom.flat.contains.linearRingssContainsXY = - function(flatCoordinates, offset, endss, stride, x, y) { - goog.asserts.assert(endss.length > 0, 'endss should not be an empty array'); - if (endss.length === 0) { - return false; - } - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - if (ol.geom.flat.contains.linearRingsContainsXY( - flatCoordinates, offset, ends, stride, x, y)) { - return true; - } - offset = ends[ends.length - 1]; - } - return false; -}; +goog.html.SafeStyle.prototype.implementsGoogStringTypedString = true; -goog.provide('ol.geom.flat.interiorpoint'); -goog.require('goog.asserts'); -goog.require('ol.geom.flat.contains'); +/** + * Type marker for the SafeStyle type, used to implement additional + * run-time type checking. + * @const {!Object} + * @private + */ +goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; /** - * Calculates a point that is likely to lie in the interior of the linear rings. - * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {Array.<number>} flatCenters Flat centers. - * @param {number} flatCentersOffset Flat center offset. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Destination. + * Creates a SafeStyle object from a compile-time constant string. + * + * {@code style} should be in the format + * {@code name: value; [name: value; ...]} and must not have any < or > + * characters in it. This is so that SafeStyle's contract is preserved, + * allowing the SafeStyle to correctly be interpreted as a sequence of CSS + * declarations and without affecting the syntactic structure of any + * surrounding CSS and HTML. + * + * This method performs basic sanity checks on the format of {@code style} + * but does not constrain the format of {@code name} and {@code value}, except + * for disallowing tag characters. + * + * @param {!goog.string.Const} style A compile-time-constant string from which + * to create a SafeStyle. + * @return {!goog.html.SafeStyle} A SafeStyle object initialized to + * {@code style}. */ -ol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset, - ends, stride, flatCenters, flatCentersOffset, opt_dest) { - var i, ii, x, x1, x2, y1, y2; - var y = flatCenters[flatCentersOffset + 1]; - /** @type {Array.<number>} */ - var intersections = []; - // Calculate intersections with the horizontal line - var end = ends[0]; - x1 = flatCoordinates[end - stride]; - y1 = flatCoordinates[end - stride + 1]; - for (i = offset; i < end; i += stride) { - x2 = flatCoordinates[i]; - y2 = flatCoordinates[i + 1]; - if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { - x = (y - y1) / (y2 - y1) * (x2 - x1) + x1; - intersections.push(x); - } - x1 = x2; - y1 = y2; - } - // Find the longest segment of the horizontal line that has its center point - // inside the linear ring. - var pointX = NaN; - var maxSegmentLength = -Infinity; - intersections.sort(); - x1 = intersections[0]; - for (i = 1, ii = intersections.length; i < ii; ++i) { - x2 = intersections[i]; - var segmentLength = Math.abs(x2 - x1); - if (segmentLength > maxSegmentLength) { - x = (x1 + x2) / 2; - if (ol.geom.flat.contains.linearRingsContainsXY( - flatCoordinates, offset, ends, stride, x, y)) { - pointX = x; - maxSegmentLength = segmentLength; - } - } - x1 = x2; - } - if (isNaN(pointX)) { - // There is no horizontal line that has its center point inside the linear - // ring. Use the center of the the linear ring's extent. - pointX = flatCenters[flatCentersOffset]; - } - if (opt_dest) { - opt_dest.push(pointX, y); - return opt_dest; - } else { - return [pointX, y]; +goog.html.SafeStyle.fromConstant = function(style) { + var styleString = goog.string.Const.unwrap(style); + if (styleString.length === 0) { + return goog.html.SafeStyle.EMPTY; } + goog.html.SafeStyle.checkStyle_(styleString); + goog.asserts.assert(goog.string.endsWith(styleString, ';'), + 'Last character of style string is not \';\': ' + styleString); + goog.asserts.assert(goog.string.contains(styleString, ':'), + 'Style string must contain at least one \':\', to ' + + 'specify a "name: value" pair: ' + styleString); + return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( + styleString); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {Array.<number>} flatCenters Flat centers. - * @return {Array.<number>} Interior points. + * Checks if the style definition is valid. + * @param {string} style + * @private */ -ol.geom.flat.interiorpoint.linearRingss = - function(flatCoordinates, offset, endss, stride, flatCenters) { - goog.asserts.assert(2 * endss.length == flatCenters.length, - 'endss.length times 2 should be flatCenters.length'); - var interiorPoints = []; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates, - offset, ends, stride, flatCenters, 2 * i, interiorPoints); - offset = ends[ends.length - 1]; - } - return interiorPoints; +goog.html.SafeStyle.checkStyle_ = function(style) { + goog.asserts.assert(!/[<>]/.test(style), + 'Forbidden characters in style string: ' + style); }; -goog.provide('ol.geom.flat.segments'); - /** - * This function calls `callback` for each segment of the flat coordinates - * array. If the callback returns a truthy value the function returns that - * value immediately. Otherwise the function returns `false`. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function - * called for each segment. - * @param {S=} opt_this The object to be used as the value of 'this' - * within callback. - * @return {T|boolean} Value. - * @template T,S + * Returns this SafeStyle's value as a string. + * + * IMPORTANT: In code where it is security relevant that an object's type is + * indeed {@code SafeStyle}, use {@code goog.html.SafeStyle.unwrap} instead of + * this method. If in doubt, assume that it's security relevant. In particular, + * note that goog.html functions which return a goog.html type do not guarantee + * the returned instance is of the right type. For example: + * + * <pre> + * var fakeSafeHtml = new String('fake'); + * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; + * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); + * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by + * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml + * // instanceof goog.html.SafeHtml. + * </pre> + * + * @see goog.html.SafeStyle#unwrap + * @override */ -ol.geom.flat.segments.forEach = - function(flatCoordinates, offset, end, stride, callback, opt_this) { - var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]]; - var point2 = []; - var ret; - for (; (offset + stride) < end; offset += stride) { - point2[0] = flatCoordinates[offset + stride]; - point2[1] = flatCoordinates[offset + stride + 1]; - ret = callback.call(opt_this, point1, point2); - if (ret) { - return ret; - } - point1[0] = point2[0]; - point1[1] = point2[1]; - } - return false; +goog.html.SafeStyle.prototype.getTypedStringValue = function() { + return this.privateDoNotAccessOrElseSafeStyleWrappedValue_; }; -goog.provide('ol.geom.flat.intersectsextent'); -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.flat.contains'); -goog.require('ol.geom.flat.segments'); +if (goog.DEBUG) { + /** + * Returns a debug string-representation of this value. + * + * To obtain the actual string value wrapped in a SafeStyle, use + * {@code goog.html.SafeStyle.unwrap}. + * + * @see goog.html.SafeStyle#unwrap + * @override + */ + goog.html.SafeStyle.prototype.toString = function() { + return 'SafeStyle{' + + this.privateDoNotAccessOrElseSafeStyleWrappedValue_ + '}'; + }; +} /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. + * Performs a runtime check that the provided object is indeed a + * SafeStyle object, and returns its value. + * + * @param {!goog.html.SafeStyle} safeStyle The object to extract from. + * @return {string} The safeStyle object's contained string, unless + * the run-time type check fails. In that case, {@code unwrap} returns an + * innocuous string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.geom.flat.intersectsextent.lineString = - function(flatCoordinates, offset, end, stride, extent) { - var coordinatesExtent = ol.extent.extendFlatCoordinates( - ol.extent.createEmpty(), flatCoordinates, offset, end, stride); - if (!ol.extent.intersects(extent, coordinatesExtent)) { - return false; - } - if (ol.extent.containsExtent(extent, coordinatesExtent)) { - return true; - } - if (coordinatesExtent[0] >= extent[0] && - coordinatesExtent[2] <= extent[2]) { - return true; - } - if (coordinatesExtent[1] >= extent[1] && - coordinatesExtent[3] <= extent[3]) { - return true; +goog.html.SafeStyle.unwrap = function(safeStyle) { + // Perform additional Run-time type-checking to ensure that + // safeStyle is indeed an instance of the expected type. This + // provides some additional protection against security bugs due to + // application code that disables type checks. + // Specifically, the following checks are performed: + // 1. The object is an instance of the expected type. + // 2. The object is not an instance of a subclass. + // 3. The object carries a type marker for the expected type. "Faking" an + // object requires a reference to the type marker, which has names intended + // to stand out in code reviews. + if (safeStyle instanceof goog.html.SafeStyle && + safeStyle.constructor === goog.html.SafeStyle && + safeStyle.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === + goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { + return safeStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_; + } else { + goog.asserts.fail( + 'expected object of type SafeStyle, got \'' + safeStyle + '\''); + return 'type_error:SafeStyle'; } - return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride, - /** - * @param {ol.Coordinate} point1 Start point. - * @param {ol.Coordinate} point2 End point. - * @return {boolean} `true` if the segment and the extent intersect, - * `false` otherwise. - */ - function(point1, point2) { - return ol.extent.intersectsSegment(extent, point1, point2); - }); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. + * Package-internal utility method to create SafeStyle instances. + * + * @param {string} style The string to initialize the SafeStyle object with. + * @return {!goog.html.SafeStyle} The initialized SafeStyle object. + * @package */ -ol.geom.flat.intersectsextent.lineStrings = - function(flatCoordinates, offset, ends, stride, extent) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.intersectsextent.lineString( - flatCoordinates, offset, ends[i], stride, extent)) { - return true; - } - offset = ends[i]; - } - return false; +goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse = + function(style) { + return new goog.html.SafeStyle().initSecurityPrivateDoNotAccessOrElse_(style); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. + * Called from createSafeStyleSecurityPrivateDoNotAccessOrElse(). This + * method exists only so that the compiler can dead code eliminate static + * fields (like EMPTY) when they're not accessed. + * @param {string} style + * @return {!goog.html.SafeStyle} + * @private */ -ol.geom.flat.intersectsextent.linearRing = - function(flatCoordinates, offset, end, stride, extent) { - if (ol.geom.flat.intersectsextent.lineString( - flatCoordinates, offset, end, stride, extent)) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[0], extent[1])) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[0], extent[3])) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[2], extent[1])) { - return true; - } - if (ol.geom.flat.contains.linearRingContainsXY( - flatCoordinates, offset, end, stride, extent[2], extent[3])) { - return true; - } - return false; +goog.html.SafeStyle.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( + style) { + this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = style; + return this; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. + * A SafeStyle instance corresponding to the empty string. + * @const {!goog.html.SafeStyle} */ -ol.geom.flat.intersectsextent.linearRings = - function(flatCoordinates, offset, ends, stride, extent) { - goog.asserts.assert(ends.length > 0, 'ends should not be an empty array'); - if (!ol.geom.flat.intersectsextent.linearRing( - flatCoordinates, offset, ends[0], stride, extent)) { - return false; - } - if (ends.length === 1) { - return true; - } - var i, ii; - for (i = 1, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.contains.linearRingContainsExtent( - flatCoordinates, ends[i - 1], ends[i], stride, extent)) { - return false; - } - } - return true; -}; +goog.html.SafeStyle.EMPTY = + goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(''); /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @param {ol.Extent} extent Extent. - * @return {boolean} True if the geometry and the extent intersect. + * The innocuous string generated by goog.html.SafeUrl.create when passed + * an unsafe value. + * @const {string} */ -ol.geom.flat.intersectsextent.linearRingss = - function(flatCoordinates, offset, endss, stride, extent) { - goog.asserts.assert(endss.length > 0, 'endss should not be an empty array'); - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - if (ol.geom.flat.intersectsextent.linearRings( - flatCoordinates, offset, ends, stride, extent)) { - return true; - } - offset = ends[ends.length - 1]; - } - return false; -}; - -goog.provide('ol.geom.flat.reverse'); +goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez'; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. + * Mapping of property names to their values. + * @typedef {!Object<string, goog.string.Const|string>} */ -ol.geom.flat.reverse.coordinates = - function(flatCoordinates, offset, end, stride) { - while (offset < end - stride) { - var i; - for (i = 0; i < stride; ++i) { - var tmp = flatCoordinates[offset + i]; - flatCoordinates[offset + i] = flatCoordinates[end - stride + i]; - flatCoordinates[end - stride + i] = tmp; - } - offset += stride; - end -= stride; - } -}; - -goog.provide('ol.geom.flat.orient'); - -goog.require('ol'); -goog.require('ol.geom.flat.reverse'); +goog.html.SafeStyle.PropertyMap; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {boolean} Is clockwise. + * Creates a new SafeStyle object from the properties specified in the map. + * @param {goog.html.SafeStyle.PropertyMap} map Mapping of property names to + * their values, for example {'margin': '1px'}. Names must consist of + * [-_a-zA-Z0-9]. Values might be strings consisting of + * [-,.'"%_!# a-zA-Z0-9], where " and ' must be properly balanced. + * Other values must be wrapped in goog.string.Const. Null value causes + * skipping the property. + * @return {!goog.html.SafeStyle} + * @throws {Error} If invalid name is provided. + * @throws {goog.asserts.AssertionError} If invalid value is provided. With + * disabled assertions, invalid value is replaced by + * goog.html.SafeStyle.INNOCUOUS_STRING. */ -ol.geom.flat.orient.linearRingIsClockwise = - function(flatCoordinates, offset, end, stride) { - // http://tinyurl.com/clockwise-method - // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp - var edge = 0; - var x1 = flatCoordinates[end - stride]; - var y1 = flatCoordinates[end - stride + 1]; - for (; offset < end; offset += stride) { - var x2 = flatCoordinates[offset]; - var y2 = flatCoordinates[offset + 1]; - edge += (x2 - x1) * (y2 + y1); - x1 = x2; - y1 = y2; +goog.html.SafeStyle.create = function(map) { + var style = ''; + for (var name in map) { + if (!/^[-_a-zA-Z0-9]+$/.test(name)) { + throw Error('Name allows only [-_a-zA-Z0-9], got: ' + name); + } + var value = map[name]; + if (value == null) { + continue; + } + if (value instanceof goog.string.Const) { + value = goog.string.Const.unwrap(value); + // These characters can be used to change context and we don't want that + // even with const values. + goog.asserts.assert(!/[{;}]/.test(value), 'Value does not allow [{;}].'); + } else if (!goog.html.SafeStyle.VALUE_RE_.test(value)) { + goog.asserts.fail( + 'String value allows only [-,."\'%_!# a-zA-Z0-9], got: ' + value); + value = goog.html.SafeStyle.INNOCUOUS_STRING; + } else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) { + goog.asserts.fail('String value requires balanced quotes, got: ' + value); + value = goog.html.SafeStyle.INNOCUOUS_STRING; + } + style += name + ':' + value + ';'; } - return edge > 0; + if (!style) { + return goog.html.SafeStyle.EMPTY; + } + goog.html.SafeStyle.checkStyle_(style); + return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( + style); }; /** - * Determines if linear rings are oriented. By default, left-hand orientation - * is tested (first ring must be clockwise, remaining rings counter-clockwise). - * To test for right-hand orientation, use the `opt_right` argument. - * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Array of end indexes. - * @param {number} stride Stride. - * @param {boolean=} opt_right Test for right-hand orientation - * (counter-clockwise exterior ring and clockwise interior rings). - * @return {boolean} Rings are correctly oriented. + * Checks that quotes (" and ') are properly balanced inside a string. Assumes + * that neither escape (\) nor any other character that could result in + * breaking out of a string parsing context are allowed; + * see http://www.w3.org/TR/css3-syntax/#string-token-diagram. + * @param {string} value Untrusted CSS property value. + * @return {boolean} True if property value is safe with respect to quote + * balancedness. + * @private */ -ol.geom.flat.orient.linearRingsAreOriented = - function(flatCoordinates, offset, ends, stride, opt_right) { - var right = opt_right !== undefined ? opt_right : false; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( - flatCoordinates, offset, end, stride); - if (i === 0) { - if ((right && isClockwise) || (!right && !isClockwise)) { - return false; - } - } else { - if ((right && !isClockwise) || (!right && isClockwise)) { - return false; - } +goog.html.SafeStyle.hasBalancedQuotes_ = function(value) { + var outsideSingle = true; + var outsideDouble = true; + for (var i = 0; i < value.length; i++) { + var c = value.charAt(i); + if (c == "'" && outsideDouble) { + outsideSingle = !outsideSingle; + } else if (c == '"' && outsideSingle) { + outsideDouble = !outsideDouble; } - offset = end; } - return true; + return outsideSingle && outsideDouble; }; +// Keep in sync with the error string in create(). /** - * Determines if linear rings are oriented. By default, left-hand orientation - * is tested (first ring must be clockwise, remaining rings counter-clockwise). - * To test for right-hand orientation, use the `opt_right` argument. + * Regular expression for safe values. * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Array of array of end indexes. - * @param {number} stride Stride. - * @param {boolean=} opt_right Test for right-hand orientation - * (counter-clockwise exterior ring and clockwise interior rings). - * @return {boolean} Rings are correctly oriented. + * Quotes (" and ') are allowed, but a check must be done elsewhere to ensure + * they're balanced. + * + * ',' allows multiple values to be assigned to the same property + * (e.g. background-attachment or font-family) and hence could allow + * multiple values to get injected, but that should pose no risk of XSS. + * @const {!RegExp} + * @private */ -ol.geom.flat.orient.linearRingssAreOriented = - function(flatCoordinates, offset, endss, stride, opt_right) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - if (!ol.geom.flat.orient.linearRingsAreOriented( - flatCoordinates, offset, endss[i], stride, opt_right)) { - return false; - } - } - return true; -}; +goog.html.SafeStyle.VALUE_RE_ = /^[-,."'%_!# a-zA-Z0-9]+$/; /** - * Orient coordinates in a flat array of linear rings. By default, rings - * are oriented following the left-hand rule (clockwise for exterior and - * counter-clockwise for interior rings). To orient according to the - * right-hand rule, use the `opt_right` argument. - * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {boolean=} opt_right Follow the right-hand rule for orientation. - * @return {number} End. + * Creates a new SafeStyle object by concatenating the values. + * @param {...(!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>)} var_args + * SafeStyles to concatenate. + * @return {!goog.html.SafeStyle} */ -ol.geom.flat.orient.orientLinearRings = - function(flatCoordinates, offset, ends, stride, opt_right) { - var right = opt_right !== undefined ? opt_right : false; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( - flatCoordinates, offset, end, stride); - var reverse = i === 0 ? - (right && isClockwise) || (!right && !isClockwise) : - (right && !isClockwise) || (!right && isClockwise); - if (reverse) { - ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride); +goog.html.SafeStyle.concat = function(var_args) { + var style = ''; + + /** + * @param {!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>} argument + */ + var addArgument = function(argument) { + if (goog.isArray(argument)) { + goog.array.forEach(argument, addArgument); + } else { + style += goog.html.SafeStyle.unwrap(argument); } - offset = end; + }; + + goog.array.forEach(arguments, addArgument); + if (!style) { + return goog.html.SafeStyle.EMPTY; } - return offset; + return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( + style); }; +// Copyright 2014 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Orient coordinates in a flat array of linear rings. By default, rings - * are oriented following the left-hand rule (clockwise for exterior and - * counter-clockwise for interior rings). To orient according to the - * right-hand rule, use the `opt_right` argument. + * @fileoverview The SafeStyleSheet type and its builders. * - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Array of array of end indexes. - * @param {number} stride Stride. - * @param {boolean=} opt_right Follow the right-hand rule for orientation. - * @return {number} End. + * TODO(xtof): Link to document stating type contract. */ -ol.geom.flat.orient.orientLinearRingss = - function(flatCoordinates, offset, endss, stride, opt_right) { - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - offset = ol.geom.flat.orient.orientLinearRings( - flatCoordinates, offset, endss[i], stride, opt_right); - } - return offset; -}; -goog.provide('ol.geom.Polygon'); +goog.provide('goog.html.SafeStyleSheet'); goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.area'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.contains'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interiorpoint'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.orient'); -goog.require('ol.geom.flat.simplify'); +goog.require('goog.string'); +goog.require('goog.string.Const'); +goog.require('goog.string.TypedString'); /** - * @classdesc - * Polygon geometry. + * A string-like object which represents a CSS style sheet and that carries the + * security type contract that its value, as a string, will not cause untrusted + * script execution (XSS) when evaluated as CSS in a browser. + * + * Instances of this type must be created via the factory method + * {@code goog.html.SafeStyleSheet.fromConstant} and not by invoking its + * constructor. The constructor intentionally takes no parameters and the type + * is immutable; hence only a default instance corresponding to the empty string + * can be obtained via constructor invocation. + * + * A SafeStyleSheet's string representation can safely be interpolated as the + * content of a style element within HTML. The SafeStyleSheet string should + * not be escaped before interpolation. + * + * Values of this type must be composable, i.e. for any two values + * {@code styleSheet1} and {@code styleSheet2} of this type, + * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1) + + * goog.html.SafeStyleSheet.unwrap(styleSheet2)} must itself be a value that + * satisfies the SafeStyleSheet type constraint. This requirement implies that + * for any value {@code styleSheet} of this type, + * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1)} must end in + * "beginning of rule" context. + + * A SafeStyleSheet can be constructed via security-reviewed unchecked + * conversions. In this case producers of SafeStyleSheet must ensure themselves + * that the SafeStyleSheet does not contain unsafe script. Note in particular + * that {@code <} is dangerous, even when inside CSS strings, and so should + * always be forbidden or CSS-escaped in user controlled input. For example, if + * {@code </style><script>evil</script>"} were interpolated + * inside a CSS string, it would break out of the context of the original + * style element and {@code evil} would execute. Also note that within an HTML + * style (raw text) element, HTML character references, such as + * {@code &lt;}, are not allowed. See + * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements + * (similar considerations apply to the style element). * + * @see goog.html.SafeStyleSheet#fromConstant * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * @final + * @struct + * @implements {goog.string.TypedString} */ -ol.geom.Polygon = function(coordinates, opt_layout) { - - goog.base(this); - - /** - * @type {Array.<number>} - * @private - */ - this.ends_ = []; - - /** - * @private - * @type {number} - */ - this.flatInteriorPointRevision_ = -1; - - /** - * @private - * @type {ol.Coordinate} - */ - this.flatInteriorPoint_ = null; - - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; - +goog.html.SafeStyleSheet = function() { /** - * @private - * @type {number} + * The contained value of this SafeStyleSheet. The field has a purposely + * ugly name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} */ - this.orientedRevision_ = -1; + this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = ''; /** + * A type marker used to implement additional run-time type checking. + * @see goog.html.SafeStyleSheet#unwrap + * @const * @private - * @type {Array.<number>} */ - this.orientedFlatCoordinates_ = null; - - this.setCoordinates(coordinates, opt_layout); - + this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = + goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; }; -goog.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry); /** - * Append the passed linear ring to this polygon. - * @param {ol.geom.LinearRing} linearRing Linear ring. - * @api stable + * @override + * @const */ -ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) { - goog.asserts.assert(linearRing.getLayout() == this.layout, - 'layout of linearRing should match layout'); - if (!this.flatCoordinates) { - this.flatCoordinates = linearRing.getFlatCoordinates().slice(); - } else { - goog.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates()); - } - this.ends_.push(this.flatCoordinates.length); - this.changed(); -}; +goog.html.SafeStyleSheet.prototype.implementsGoogStringTypedString = true; /** - * Make a complete copy of the geometry. - * @return {!ol.geom.Polygon} Clone. - * @api stable + * Type marker for the SafeStyleSheet type, used to implement additional + * run-time type checking. + * @const {!Object} + * @private */ -ol.geom.Polygon.prototype.clone = function() { - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(), this.ends_.slice()); - return polygon; -}; +goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; /** - * @inheritDoc + * Creates a new SafeStyleSheet object by concatenating values. + * @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)} + * var_args Values to concatenate. + * @return {!goog.html.SafeStyleSheet} */ -ol.geom.Polygon.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta( - this.flatCoordinates, 0, this.ends_, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getsClosestPoint( - this.flatCoordinates, 0, this.ends_, this.stride, - this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); -}; +goog.html.SafeStyleSheet.concat = function(var_args) { + var result = ''; + /** + * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>} + * argument + */ + var addArgument = function(argument) { + if (goog.isArray(argument)) { + goog.array.forEach(argument, addArgument); + } else { + result += goog.html.SafeStyleSheet.unwrap(argument); + } + }; -/** - * @inheritDoc - */ -ol.geom.Polygon.prototype.containsXY = function(x, y) { - return ol.geom.flat.contains.linearRingsContainsXY( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y); + goog.array.forEach(arguments, addArgument); + return goog.html.SafeStyleSheet + .createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(result); }; /** - * Return the area of the polygon on projected plane. - * @return {number} Area (on projected plane). - * @api stable + * Creates a SafeStyleSheet object from a compile-time constant string. + * + * {@code styleSheet} must not have any < characters in it, so that + * the syntactic structure of the surrounding HTML is not affected. + * + * @param {!goog.string.Const} styleSheet A compile-time-constant string from + * which to create a SafeStyleSheet. + * @return {!goog.html.SafeStyleSheet} A SafeStyleSheet object initialized to + * {@code styleSheet}. */ -ol.geom.Polygon.prototype.getArea = function() { - return ol.geom.flat.area.linearRings( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride); +goog.html.SafeStyleSheet.fromConstant = function(styleSheet) { + var styleSheetString = goog.string.Const.unwrap(styleSheet); + if (styleSheetString.length === 0) { + return goog.html.SafeStyleSheet.EMPTY; + } + // > is a valid character in CSS selectors and there's no strict need to + // block it if we already block <. + goog.asserts.assert(!goog.string.contains(styleSheetString, '<'), + "Forbidden '<' character in style sheet string: " + styleSheetString); + return goog.html.SafeStyleSheet. + createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheetString); }; /** - * Get the coordinate array for this geometry. This array has the structure - * of a GeoJSON coordinate array for polygons. + * Returns this SafeStyleSheet's value as a string. * - * @param {boolean=} opt_right Orient coordinates according to the right-hand - * rule (counter-clockwise for exterior and clockwise for interior rings). - * If `false`, coordinates will be oriented according to the left-hand rule - * (clockwise for exterior and counter-clockwise for interior rings). - * By default, coordinate orientation will depend on how the geometry was - * constructed. - * @return {Array.<Array.<ol.Coordinate>>} Coordinates. - * @api stable - */ -ol.geom.Polygon.prototype.getCoordinates = function(opt_right) { - var flatCoordinates; - if (opt_right !== undefined) { - flatCoordinates = this.getOrientedFlatCoordinates().slice(); - ol.geom.flat.orient.orientLinearRings( - flatCoordinates, 0, this.ends_, this.stride, opt_right); - } else { - flatCoordinates = this.flatCoordinates; - } - - return ol.geom.flat.inflate.coordinatess( - flatCoordinates, 0, this.ends_, this.stride); -}; - - -/** - * @return {Array.<number>} Ends. + * IMPORTANT: In code where it is security relevant that an object's type is + * indeed {@code SafeStyleSheet}, use {@code goog.html.SafeStyleSheet.unwrap} + * instead of this method. If in doubt, assume that it's security relevant. In + * particular, note that goog.html functions which return a goog.html type do + * not guarantee the returned instance is of the right type. For example: + * + * <pre> + * var fakeSafeHtml = new String('fake'); + * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; + * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); + * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by + * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml + * // instanceof goog.html.SafeHtml. + * </pre> + * + * @see goog.html.SafeStyleSheet#unwrap + * @override */ -ol.geom.Polygon.prototype.getEnds = function() { - return this.ends_; +goog.html.SafeStyleSheet.prototype.getTypedStringValue = function() { + return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_; }; -/** - * @return {Array.<number>} Interior point. - */ -ol.geom.Polygon.prototype.getFlatInteriorPoint = function() { - if (this.flatInteriorPointRevision_ != this.getRevision()) { - var flatCenter = ol.extent.getCenter(this.getExtent()); - this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, - flatCenter, 0); - this.flatInteriorPointRevision_ = this.getRevision(); - } - return this.flatInteriorPoint_; -}; +if (goog.DEBUG) { + /** + * Returns a debug string-representation of this value. + * + * To obtain the actual string value wrapped in a SafeStyleSheet, use + * {@code goog.html.SafeStyleSheet.unwrap}. + * + * @see goog.html.SafeStyleSheet#unwrap + * @override + */ + goog.html.SafeStyleSheet.prototype.toString = function() { + return 'SafeStyleSheet{' + + this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ + '}'; + }; +} /** - * Return an interior point of the polygon. - * @return {ol.geom.Point} Interior point. - * @api stable + * Performs a runtime check that the provided object is indeed a + * SafeStyleSheet object, and returns its value. + * + * @param {!goog.html.SafeStyleSheet} safeStyleSheet The object to extract from. + * @return {string} The safeStyleSheet object's contained string, unless + * the run-time type check fails. In that case, {@code unwrap} returns an + * innocuous string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.geom.Polygon.prototype.getInteriorPoint = function() { - return new ol.geom.Point(this.getFlatInteriorPoint()); +goog.html.SafeStyleSheet.unwrap = function(safeStyleSheet) { + // Perform additional Run-time type-checking to ensure that + // safeStyleSheet is indeed an instance of the expected type. This + // provides some additional protection against security bugs due to + // application code that disables type checks. + // Specifically, the following checks are performed: + // 1. The object is an instance of the expected type. + // 2. The object is not an instance of a subclass. + // 3. The object carries a type marker for the expected type. "Faking" an + // object requires a reference to the type marker, which has names intended + // to stand out in code reviews. + if (safeStyleSheet instanceof goog.html.SafeStyleSheet && + safeStyleSheet.constructor === goog.html.SafeStyleSheet && + safeStyleSheet.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === + goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { + return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_; + } else { + goog.asserts.fail( + "expected object of type SafeStyleSheet, got '" + safeStyleSheet + + "'"); + return 'type_error:SafeStyleSheet'; + } }; /** - * Return the number of rings of the polygon, this includes the exterior - * ring and any interior rings. + * Package-internal utility method to create SafeStyleSheet instances. * - * @return {number} Number of rings. - * @api + * @param {string} styleSheet The string to initialize the SafeStyleSheet + * object with. + * @return {!goog.html.SafeStyleSheet} The initialized SafeStyleSheet object. + * @package */ -ol.geom.Polygon.prototype.getLinearRingCount = function() { - return this.ends_.length; +goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse = + function(styleSheet) { + return new goog.html.SafeStyleSheet().initSecurityPrivateDoNotAccessOrElse_( + styleSheet); }; /** - * Return the Nth linear ring of the polygon geometry. Return `null` if the - * given index is out of range. - * The exterior linear ring is available at index `0` and the interior rings - * at index `1` and beyond. - * - * @param {number} index Index. - * @return {ol.geom.LinearRing} Linear ring. - * @api stable + * Called from createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(). This + * method exists only so that the compiler can dead code eliminate static + * fields (like EMPTY) when they're not accessed. + * @param {string} styleSheet + * @return {!goog.html.SafeStyleSheet} + * @private */ -ol.geom.Polygon.prototype.getLinearRing = function(index) { - goog.asserts.assert(0 <= index && index < this.ends_.length, - 'index should be in between 0 and and length of this.ends_'); - if (index < 0 || this.ends_.length <= index) { - return null; - } - var linearRing = new ol.geom.LinearRing(null); - linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice( - index === 0 ? 0 : this.ends_[index - 1], this.ends_[index])); - return linearRing; +goog.html.SafeStyleSheet.prototype.initSecurityPrivateDoNotAccessOrElse_ = + function(styleSheet) { + this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = styleSheet; + return this; }; /** - * Return the linear rings of the polygon. - * @return {Array.<ol.geom.LinearRing>} Linear rings. - * @api stable + * A SafeStyleSheet instance corresponding to the empty string. + * @const {!goog.html.SafeStyleSheet} */ -ol.geom.Polygon.prototype.getLinearRings = function() { - var layout = this.layout; - var flatCoordinates = this.flatCoordinates; - var ends = this.ends_; - var linearRings = []; - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var linearRing = new ol.geom.LinearRing(null); - linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end)); - linearRings.push(linearRing); - offset = end; - } - return linearRings; -}; +goog.html.SafeStyleSheet.EMPTY = + goog.html.SafeStyleSheet. + createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(''); +// Copyright 2015 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @return {Array.<number>} Oriented flat coordinates. + * @fileoverview Wrapper for URL and its createObjectUrl and revokeObjectUrl + * methods that are part of the HTML5 File API. */ -ol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() { - if (this.orientedRevision_ != this.getRevision()) { - var flatCoordinates = this.flatCoordinates; - if (ol.geom.flat.orient.linearRingsAreOriented( - flatCoordinates, 0, this.ends_, this.stride)) { - this.orientedFlatCoordinates_ = flatCoordinates; - } else { - this.orientedFlatCoordinates_ = flatCoordinates.slice(); - this.orientedFlatCoordinates_.length = - ol.geom.flat.orient.orientLinearRings( - this.orientedFlatCoordinates_, 0, this.ends_, this.stride); - } - this.orientedRevision_ = this.getRevision(); - } - return this.orientedFlatCoordinates_; -}; + +goog.provide('goog.fs.url'); /** - * @inheritDoc + * Creates a blob URL for a blob object. + * Throws an error if the browser does not support Object Urls. + * + * @param {!Blob} blob The object for which to create the URL. + * @return {string} The URL for the object. */ -ol.geom.Polygon.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - var simplifiedEnds = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes( - this.flatCoordinates, 0, this.ends_, this.stride, - Math.sqrt(squaredTolerance), - simplifiedFlatCoordinates, 0, simplifiedEnds); - var simplifiedPolygon = new ol.geom.Polygon(null); - simplifiedPolygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds); - return simplifiedPolygon; +goog.fs.url.createObjectUrl = function(blob) { + return goog.fs.url.getUrlObject_().createObjectURL(blob); }; /** - * @inheritDoc - * @api stable + * Revokes a URL created by {@link goog.fs.url.createObjectUrl}. + * Throws an error if the browser does not support Object Urls. + * + * @param {string} url The URL to revoke. */ -ol.geom.Polygon.prototype.getType = function() { - return ol.geom.GeometryType.POLYGON; +goog.fs.url.revokeObjectUrl = function(url) { + goog.fs.url.getUrlObject_().revokeObjectURL(url); }; /** - * @inheritDoc - * @api stable + * @typedef {{createObjectURL: (function(!Blob): string), + * revokeObjectURL: function(string): void}} */ -ol.geom.Polygon.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.linearRings( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent); -}; +goog.fs.url.UrlObject_; /** - * Set the coordinates of the polygon. - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * Get the object that has the createObjectURL and revokeObjectURL functions for + * this browser. + * + * @return {goog.fs.url.UrlObject_} The object for this browser. + * @private */ -ol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_); +goog.fs.url.getUrlObject_ = function() { + var urlObject = goog.fs.url.findUrlObject_(); + if (urlObject != null) { + return urlObject; } else { - this.setLayout(opt_layout, coordinates, 2); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - var ends = ol.geom.flat.deflate.coordinatess( - this.flatCoordinates, 0, coordinates, this.stride, this.ends_); - this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; - this.changed(); + throw Error('This browser doesn\'t seem to support blob URLs'); } }; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Array.<number>} ends Ends. + * Finds the object that has the createObjectURL and revokeObjectURL functions + * for this browser. + * + * @return {?goog.fs.url.UrlObject_} The object for this browser or null if the + * browser does not support Object Urls. + * @suppress {unnecessaryCasts} Depending on how the code is compiled, casting + * goog.global to UrlObject_ may result in unnecessary cast warning. + * However, the cast cannot be removed because with different set of + * compiler flags, the cast is indeed necessary. As such, silencing it. + * @private */ -ol.geom.Polygon.prototype.setFlatCoordinates = - function(layout, flatCoordinates, ends) { - if (!flatCoordinates) { - goog.asserts.assert(ends && ends.length === 0, - 'ends must be an empty array'); - } else if (ends.length === 0) { - goog.asserts.assert(flatCoordinates.length === 0, - 'flatCoordinates should be an empty array'); +goog.fs.url.findUrlObject_ = function() { + // This is what the spec says to do + // http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL + if (goog.isDef(goog.global.URL) && + goog.isDef(goog.global.URL.createObjectURL)) { + return /** @type {goog.fs.url.UrlObject_} */ (goog.global.URL); + // This is what Chrome does (as of 10.0.648.6 dev) + } else if (goog.isDef(goog.global.webkitURL) && + goog.isDef(goog.global.webkitURL.createObjectURL)) { + return /** @type {goog.fs.url.UrlObject_} */ (goog.global.webkitURL); + // This is what the spec used to say to do + } else if (goog.isDef(goog.global.createObjectURL)) { + return /** @type {goog.fs.url.UrlObject_} */ (goog.global); } else { - goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], - 'the length of flatCoordinates should be the last entry of ends'); + return null; } - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.ends_ = ends; - this.changed(); }; /** - * Create an approximation of a circle on the surface of a sphere. - * @param {ol.Sphere} sphere The sphere. - * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees). - * @param {number} radius The great-circle distance from the center to - * the polygon vertices. - * @param {number=} opt_n Optional number of vertices for the resulting - * polygon. Default is `32`. - * @return {ol.geom.Polygon} The "circular" polygon. - * @api stable + * Checks whether this browser supports Object Urls. If not, calls to + * createObjectUrl and revokeObjectUrl will result in an error. + * + * @return {boolean} True if this browser supports Object Urls. */ -ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) { - var n = opt_n ? opt_n : 32; - /** @type {Array.<number>} */ - var flatCoordinates = []; - var i; - for (i = 0; i < n; ++i) { - goog.array.extend( - flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n)); - } - flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]); - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); - return polygon; +goog.fs.url.browserSupportsObjectUrls = function() { + return goog.fs.url.findUrlObject_() != null; }; +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Create a polygon from an extent. The layout used is `XY`. - * @param {ol.Extent} extent The extent. - * @return {ol.geom.Polygon} The polygon. - * @api + * @fileoverview Utility functions for supporting Bidi issues. */ -ol.geom.Polygon.fromExtent = function(extent) { - var minX = extent[0]; - var minY = extent[1]; - var maxX = extent[2]; - var maxY = extent[3]; - var flatCoordinates = - [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY]; - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); - return polygon; -}; /** - * Create a regular polygon from a circle. - * @param {ol.geom.Circle} circle Circle geometry. - * @param {number=} opt_sides Number of sides of the polygon. Default is 32. - * @param {number=} opt_angle Start angle for the first vertex of the polygon in - * radians. Default is 0. - * @return {ol.geom.Polygon} Polygon geometry. - * @api + * Namespace for bidi supporting functions. */ -ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) { - var sides = opt_sides ? opt_sides : 32; - var stride = circle.getStride(); - var layout = circle.getLayout(); - var polygon = new ol.geom.Polygon(null, layout); - var flatCoordinates = goog.array.repeat(0, stride * (sides + 1)); - var ends = [flatCoordinates.length]; - polygon.setFlatCoordinates(layout, flatCoordinates, ends); - ol.geom.Polygon.makeRegular( - polygon, circle.getCenter(), circle.getRadius(), opt_angle); - return polygon; -}; +goog.provide('goog.i18n.bidi'); +goog.provide('goog.i18n.bidi.Dir'); +goog.provide('goog.i18n.bidi.DirectionalString'); +goog.provide('goog.i18n.bidi.Format'); /** - * Modify the coordinates of a polygon to make it a regular polygon. - * @param {ol.geom.Polygon} polygon Polygon geometry. - * @param {ol.Coordinate} center Center of the regular polygon. - * @param {number} radius Radius of the regular polygon. - * @param {number=} opt_angle Start angle for the first vertex of the polygon in - * radians. Default is 0. + * @define {boolean} FORCE_RTL forces the {@link goog.i18n.bidi.IS_RTL} constant + * to say that the current locale is a RTL locale. This should only be used + * if you want to override the default behavior for deciding whether the + * current locale is RTL or not. + * + * {@see goog.i18n.bidi.IS_RTL} */ -ol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) { - var flatCoordinates = polygon.getFlatCoordinates(); - var layout = polygon.getLayout(); - var stride = polygon.getStride(); - var ends = polygon.getEnds(); - goog.asserts.assert(ends.length === 1, 'only 1 ring is supported'); - var sides = flatCoordinates.length / stride - 1; - var startAngle = opt_angle ? opt_angle : 0; - var angle, offset; - for (var i = 0; i <= sides; ++i) { - offset = i * stride; - angle = startAngle + (goog.math.modulo(i, sides) * 2 * Math.PI / sides); - flatCoordinates[offset] = center[0] + (radius * Math.cos(angle)); - flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle)); - } - polygon.setFlatCoordinates(layout, flatCoordinates, ends); -}; +goog.define('goog.i18n.bidi.FORCE_RTL', false); -goog.provide('ol.View'); -goog.provide('ol.ViewHint'); -goog.provide('ol.ViewProperty'); -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.CenterConstraint'); -goog.require('ol.Constraints'); -goog.require('ol.Object'); -goog.require('ol.ResolutionConstraint'); -goog.require('ol.RotationConstraint'); -goog.require('ol.RotationConstraintType'); -goog.require('ol.Size'); -goog.require('ol.coordinate'); -goog.require('ol.extent'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); +/** + * Constant that defines whether or not the current locale is a RTL locale. + * If {@link goog.i18n.bidi.FORCE_RTL} is not true, this constant will default + * to check that {@link goog.LOCALE} is one of a few major RTL locales. + * + * <p>This is designed to be a maximally efficient compile-time constant. For + * example, for the default goog.LOCALE, compiling + * "if (goog.i18n.bidi.IS_RTL) alert('rtl') else {}" should produce no code. It + * is this design consideration that limits the implementation to only + * supporting a few major RTL locales, as opposed to the broader repertoire of + * something like goog.i18n.bidi.isRtlLanguage. + * + * <p>Since this constant refers to the directionality of the locale, it is up + * to the caller to determine if this constant should also be used for the + * direction of the UI. + * + * {@see goog.LOCALE} + * + * @type {boolean} + * + * TODO(user): write a test that checks that this is a compile-time constant. + */ +goog.i18n.bidi.IS_RTL = goog.i18n.bidi.FORCE_RTL || + ( + (goog.LOCALE.substring(0, 2).toLowerCase() == 'ar' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'fa' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'he' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'iw' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'ps' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'sd' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'ug' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'ur' || + goog.LOCALE.substring(0, 2).toLowerCase() == 'yi') && + (goog.LOCALE.length == 2 || + goog.LOCALE.substring(2, 3) == '-' || + goog.LOCALE.substring(2, 3) == '_') + ) || ( + goog.LOCALE.length >= 3 && + goog.LOCALE.substring(0, 3).toLowerCase() == 'ckb' && + (goog.LOCALE.length == 3 || + goog.LOCALE.substring(3, 4) == '-' || + goog.LOCALE.substring(3, 4) == '_') + ); /** + * Unicode formatting characters and directionality string constants. * @enum {string} */ -ol.ViewProperty = { - CENTER: 'center', - RESOLUTION: 'resolution', - ROTATION: 'rotation' +goog.i18n.bidi.Format = { + /** Unicode "Left-To-Right Embedding" (LRE) character. */ + LRE: '\u202A', + /** Unicode "Right-To-Left Embedding" (RLE) character. */ + RLE: '\u202B', + /** Unicode "Pop Directional Formatting" (PDF) character. */ + PDF: '\u202C', + /** Unicode "Left-To-Right Mark" (LRM) character. */ + LRM: '\u200E', + /** Unicode "Right-To-Left Mark" (RLM) character. */ + RLM: '\u200F' }; /** + * Directionality enum. * @enum {number} */ -ol.ViewHint = { - ANIMATING: 0, - INTERACTING: 1 -}; +goog.i18n.bidi.Dir = { + /** + * Left-to-right. + */ + LTR: 1, + + /** + * Right-to-left. + */ + RTL: -1, + /** + * Neither left-to-right nor right-to-left. + */ + NEUTRAL: 0 +}; /** - * @classdesc - * An ol.View object represents a simple 2D view of the map. - * - * This is the object to act upon to change the center, resolution, - * and rotation of the map. - * - * ### The view states - * - * An `ol.View` is determined by three states: `center`, `resolution`, - * and `rotation`. Each state has a corresponding getter and setter, e.g. - * `getCenter` and `setCenter` for the `center` state. - * - * An `ol.View` has a `projection`. The projection determines the - * coordinate system of the center, and its units determine the units of the - * resolution (projection units per pixel). The default projection is - * Spherical Mercator (EPSG:3857). - * - * ### The constraints - * - * `setCenter`, `setResolution` and `setRotation` can be used to change the - * states of the view. Any value can be passed to the setters. And the value - * that is passed to a setter will effectively be the value set in the view, - * and returned by the corresponding getter. - * - * But an `ol.View` object also has a *resolution constraint*, a - * *rotation constraint* and a *center constraint*. - * - * As said above, no constraints are applied when the setters are used to set - * new states for the view. Applying constraints is done explicitly through - * the use of the `constrain*` functions (`constrainResolution` and - * `constrainRotation` and `constrainCenter`). - * - * The main users of the constraints are the interactions and the - * controls. For example, double-clicking on the map changes the view to - * the "next" resolution. And releasing the fingers after pinch-zooming - * snaps to the closest resolution (with an animation). - * - * The *resolution constraint* snaps to specific resolutions. It is - * determined by the following options: `resolutions`, `maxResolution`, - * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three - * options are ignored. See documentation for each option for more - * information. - * - * The *rotation constraint* snaps to specific angles. It is determined - * by the following options: `enableRotation` and `constrainRotation`. - * By default the rotation value is snapped to zero when approaching the - * horizontal. - * - * The *center constraint* is determined by the `extent` option. By - * default the center is not constrained at all. - * - * @constructor - * @extends {ol.Object} - * @param {olx.ViewOptions=} opt_options View options. - * @api stable + * 'right' string constant. + * @type {string} */ -ol.View = function(opt_options) { - goog.base(this); - var options = opt_options || {}; - - /** - * @private - * @type {Array.<number>} - */ - this.hints_ = [0, 0]; - - /** - * @type {Object.<string, *>} - */ - var properties = {}; - properties[ol.ViewProperty.CENTER] = options.center !== undefined ? - options.center : null; +goog.i18n.bidi.RIGHT = 'right'; - /** - * @private - * @const - * @type {ol.proj.Projection} - */ - this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857'); - var resolutionConstraintInfo = ol.View.createResolutionConstraint_( - options); +/** + * 'left' string constant. + * @type {string} + */ +goog.i18n.bidi.LEFT = 'left'; - /** - * @private - * @type {number} - */ - this.maxResolution_ = resolutionConstraintInfo.maxResolution; - /** - * @private - * @type {number} - */ - this.minResolution_ = resolutionConstraintInfo.minResolution; +/** + * 'left' if locale is RTL, 'right' if not. + * @type {string} + */ +goog.i18n.bidi.I18N_RIGHT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.LEFT : + goog.i18n.bidi.RIGHT; - /** - * @private - * @type {number} - */ - this.minZoom_ = resolutionConstraintInfo.minZoom; - var centerConstraint = ol.View.createCenterConstraint_(options); - var resolutionConstraint = resolutionConstraintInfo.constraint; - var rotationConstraint = ol.View.createRotationConstraint_(options); +/** + * 'right' if locale is RTL, 'left' if not. + * @type {string} + */ +goog.i18n.bidi.I18N_LEFT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.RIGHT : + goog.i18n.bidi.LEFT; - /** - * @private - * @type {ol.Constraints} - */ - this.constraints_ = new ol.Constraints( - centerConstraint, resolutionConstraint, rotationConstraint); - if (options.resolution !== undefined) { - properties[ol.ViewProperty.RESOLUTION] = options.resolution; - } else if (options.zoom !== undefined) { - properties[ol.ViewProperty.RESOLUTION] = this.constrainResolution( - this.maxResolution_, options.zoom - this.minZoom_); +/** + * Convert a directionality given in various formats to a goog.i18n.bidi.Dir + * constant. Useful for interaction with different standards of directionality + * representation. + * + * @param {goog.i18n.bidi.Dir|number|boolean|null} givenDir Directionality given + * in one of the following formats: + * 1. A goog.i18n.bidi.Dir constant. + * 2. A number (positive = LTR, negative = RTL, 0 = neutral). + * 3. A boolean (true = RTL, false = LTR). + * 4. A null for unknown directionality. + * @param {boolean=} opt_noNeutral Whether a givenDir of zero or + * goog.i18n.bidi.Dir.NEUTRAL should be treated as null, i.e. unknown, in + * order to preserve legacy behavior. + * @return {?goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the + * given directionality. If given null, returns null (i.e. unknown). + */ +goog.i18n.bidi.toDir = function(givenDir, opt_noNeutral) { + if (typeof givenDir == 'number') { + // This includes the non-null goog.i18n.bidi.Dir case. + return givenDir > 0 ? goog.i18n.bidi.Dir.LTR : + givenDir < 0 ? goog.i18n.bidi.Dir.RTL : + opt_noNeutral ? null : goog.i18n.bidi.Dir.NEUTRAL; + } else if (givenDir == null) { + return null; + } else { + // Must be typeof givenDir == 'boolean'. + return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR; } - properties[ol.ViewProperty.ROTATION] = - options.rotation !== undefined ? options.rotation : 0; - this.setProperties(properties); }; -goog.inherits(ol.View, ol.Object); /** - * @param {number} rotation Target rotation. - * @param {ol.Coordinate} anchor Rotation anchor. - * @return {ol.Coordinate|undefined} Center for rotation and anchor. + * A practical pattern to identify strong LTR characters. This pattern is not + * theoretically correct according to the Unicode standard. It is simplified for + * performance and small code size. + * @type {string} + * @private */ -ol.View.prototype.calculateCenterRotate = function(rotation, anchor) { - var center; - var currentCenter = this.getCenter(); - if (currentCenter !== undefined) { - center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]]; - ol.coordinate.rotate(center, rotation - this.getRotation()); - ol.coordinate.add(center, anchor); - } - return center; -}; +goog.i18n.bidi.ltrChars_ = + 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' + + '\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF'; /** - * @param {number} resolution Target resolution. - * @param {ol.Coordinate} anchor Zoom anchor. - * @return {ol.Coordinate|undefined} Center for resolution and anchor. + * A practical pattern to identify strong RTL character. This pattern is not + * theoretically correct according to the Unicode standard. It is simplified + * for performance and small code size. + * @type {string} + * @private */ -ol.View.prototype.calculateCenterZoom = function(resolution, anchor) { - var center; - var currentCenter = this.getCenter(); - var currentResolution = this.getResolution(); - if (currentCenter !== undefined && currentResolution !== undefined) { - var x = anchor[0] - - resolution * (anchor[0] - currentCenter[0]) / currentResolution; - var y = anchor[1] - - resolution * (anchor[1] - currentCenter[1]) / currentResolution; - center = [x, y]; - } - return center; -}; +goog.i18n.bidi.rtlChars_ = + '\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC'; /** - * Get the constrained center of this view. - * @param {ol.Coordinate|undefined} center Center. - * @return {ol.Coordinate|undefined} Constrained center. - * @api + * Simplified regular expression for an HTML tag (opening or closing) or an HTML + * escape. We might want to skip over such expressions when estimating the text + * directionality. + * @type {RegExp} + * @private */ -ol.View.prototype.constrainCenter = function(center) { - return this.constraints_.center(center); -}; +goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g; /** - * Get the constrained resolution of this view. - * @param {number|undefined} resolution Resolution. - * @param {number=} opt_delta Delta. Default is `0`. - * @param {number=} opt_direction Direction. Default is `0`. - * @return {number|undefined} Constrained resolution. - * @api + * Returns the input text with spaces instead of HTML tags or HTML escapes, if + * opt_isStripNeeded is true. Else returns the input as is. + * Useful for text directionality estimation. + * Note: the function should not be used in other contexts; it is not 100% + * correct, but rather a good-enough implementation for directionality + * estimation purposes. + * @param {string} str The given string. + * @param {boolean=} opt_isStripNeeded Whether to perform the stripping. + * Default: false (to retain consistency with calling functions). + * @return {string} The given string cleaned of HTML tags / escapes. + * @private */ -ol.View.prototype.constrainResolution = function( - resolution, opt_delta, opt_direction) { - var delta = opt_delta || 0; - var direction = opt_direction || 0; - return this.constraints_.resolution(resolution, delta, direction); +goog.i18n.bidi.stripHtmlIfNeeded_ = function(str, opt_isStripNeeded) { + return opt_isStripNeeded ? str.replace(goog.i18n.bidi.htmlSkipReg_, '') : + str; }; /** - * Get the constrained rotation of this view. - * @param {number|undefined} rotation Rotation. - * @param {number=} opt_delta Delta. Default is `0`. - * @return {number|undefined} Constrained rotation. - * @api + * Regular expression to check for RTL characters. + * @type {RegExp} + * @private */ -ol.View.prototype.constrainRotation = function(rotation, opt_delta) { - var delta = opt_delta || 0; - return this.constraints_.rotation(rotation, delta); -}; +goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']'); /** - * Get the view center. - * @return {ol.Coordinate|undefined} The center of the view. - * @observable - * @api stable + * Regular expression to check for LTR characters. + * @type {RegExp} + * @private */ -ol.View.prototype.getCenter = function() { - return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.ViewProperty.CENTER)); -}; +goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']'); /** - * @return {Array.<number>} Hint. + * Test whether the given string has any RTL characters in it. + * @param {string} str The given string that need to be tested. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether the string contains RTL characters. */ -ol.View.prototype.getHints = function() { - return this.hints_.slice(); +goog.i18n.bidi.hasAnyRtl = function(str, opt_isHtml) { + return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_( + str, opt_isHtml)); }; /** - * Calculate the extent for the current view state and the passed size. - * The size is the pixel dimensions of the box into which the calculated extent - * should fit. In most cases you want to get the extent of the entire map, - * that is `map.getSize()`. - * @param {ol.Size} size Box pixel size. - * @return {ol.Extent} Extent. - * @api stable + * Test whether the given string has any RTL characters in it. + * @param {string} str The given string that need to be tested. + * @return {boolean} Whether the string contains RTL characters. + * @deprecated Use hasAnyRtl. */ -ol.View.prototype.calculateExtent = function(size) { - var center = this.getCenter(); - goog.asserts.assert(center, 'The view center is not defined'); - var resolution = this.getResolution(); - goog.asserts.assert(resolution !== undefined, - 'The view resolution is not defined'); - var rotation = this.getRotation(); - goog.asserts.assert(rotation !== undefined, - 'The view rotation is not defined'); - - return ol.extent.getForViewAndSize(center, resolution, rotation, size); -}; +goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl; /** - * Get the view projection. - * @return {ol.proj.Projection} The projection of the view. - * @api stable + * Test whether the given string has any LTR characters in it. + * @param {string} str The given string that need to be tested. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether the string contains LTR characters. */ -ol.View.prototype.getProjection = function() { - return this.projection_; +goog.i18n.bidi.hasAnyLtr = function(str, opt_isHtml) { + return goog.i18n.bidi.ltrCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_( + str, opt_isHtml)); }; /** - * Get the view resolution. - * @return {number|undefined} The resolution of the view. - * @observable - * @api stable + * Regular expression pattern to check if the first character in the string + * is LTR. + * @type {RegExp} + * @private */ -ol.View.prototype.getResolution = function() { - return /** @type {number|undefined} */ ( - this.get(ol.ViewProperty.RESOLUTION)); -}; +goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']'); /** - * Get the resolution for a provided extent (in map units) and size (in pixels). - * @param {ol.Extent} extent Extent. - * @param {ol.Size} size Box pixel size. - * @return {number} The resolution at which the provided extent will render at - * the given size. + * Regular expression pattern to check if the first character in the string + * is RTL. + * @type {RegExp} + * @private */ -ol.View.prototype.getResolutionForExtent = function(extent, size) { - var xResolution = ol.extent.getWidth(extent) / size[0]; - var yResolution = ol.extent.getHeight(extent) / size[1]; - return Math.max(xResolution, yResolution); -}; +goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']'); /** - * Return a function that returns a value between 0 and 1 for a - * resolution. Exponential scaling is assumed. - * @param {number=} opt_power Power. - * @return {function(number): number} Resolution for value function. + * Check if the first character in the string is RTL or not. + * @param {string} str The given string that need to be tested. + * @return {boolean} Whether the first character in str is an RTL char. */ -ol.View.prototype.getResolutionForValueFunction = function(opt_power) { - var power = opt_power || 2; - var maxResolution = this.maxResolution_; - var minResolution = this.minResolution_; - var max = Math.log(maxResolution / minResolution) / Math.log(power); - return ( - /** - * @param {number} value Value. - * @return {number} Resolution. - */ - function(value) { - var resolution = maxResolution / Math.pow(power, value * max); - goog.asserts.assert(resolution >= minResolution && - resolution <= maxResolution, - 'calculated resolution outside allowed bounds (%s <= %s <= %s)', - minResolution, resolution, maxResolution); - return resolution; - }); +goog.i18n.bidi.isRtlChar = function(str) { + return goog.i18n.bidi.rtlRe_.test(str); }; /** - * Get the view rotation. - * @return {number} The rotation of the view in radians. - * @observable - * @api stable + * Check if the first character in the string is LTR or not. + * @param {string} str The given string that need to be tested. + * @return {boolean} Whether the first character in str is an LTR char. */ -ol.View.prototype.getRotation = function() { - return /** @type {number} */ (this.get(ol.ViewProperty.ROTATION)); +goog.i18n.bidi.isLtrChar = function(str) { + return goog.i18n.bidi.ltrRe_.test(str); }; /** - * Return a function that returns a resolution for a value between - * 0 and 1. Exponential scaling is assumed. - * @param {number=} opt_power Power. - * @return {function(number): number} Value for resolution function. + * Check if the first character in the string is neutral or not. + * @param {string} str The given string that need to be tested. + * @return {boolean} Whether the first character in str is a neutral char. */ -ol.View.prototype.getValueForResolutionFunction = function(opt_power) { - var power = opt_power || 2; - var maxResolution = this.maxResolution_; - var minResolution = this.minResolution_; - var max = Math.log(maxResolution / minResolution) / Math.log(power); - return ( - /** - * @param {number} resolution Resolution. - * @return {number} Value. - */ - function(resolution) { - var value = - (Math.log(maxResolution / resolution) / Math.log(power)) / max; - goog.asserts.assert(value >= 0 && value <= 1, - 'calculated value (%s) ouside allowed range (0-1)', value); - return value; - }); +goog.i18n.bidi.isNeutralChar = function(str) { + return !goog.i18n.bidi.isLtrChar(str) && !goog.i18n.bidi.isRtlChar(str); }; /** - * @return {olx.ViewState} View state. + * Regular expressions to check if a piece of text is of LTR directionality + * on first character with strong directionality. + * @type {RegExp} + * @private */ -ol.View.prototype.getState = function() { - goog.asserts.assert(this.isDef(), - 'the view was not defined (had no center and/or resolution)'); - var center = /** @type {ol.Coordinate} */ (this.getCenter()); - var projection = this.getProjection(); - var resolution = /** @type {number} */ (this.getResolution()); - var rotation = this.getRotation(); - return /** @type {olx.ViewState} */ ({ - // Snap center to closest pixel - center: [ - Math.round(center[0] / resolution) * resolution, - Math.round(center[1] / resolution) * resolution - ], - projection: projection !== undefined ? projection : null, - resolution: resolution, - rotation: rotation - }); -}; +goog.i18n.bidi.ltrDirCheckRe_ = new RegExp( + '^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']'); /** - * Get the current zoom level. Return undefined if the current - * resolution is undefined or not a "constrained resolution". - * @return {number|undefined} Zoom. - * @api stable + * Regular expressions to check if a piece of text is of RTL directionality + * on first character with strong directionality. + * @type {RegExp} + * @private */ -ol.View.prototype.getZoom = function() { - var offset; - var resolution = this.getResolution(); +goog.i18n.bidi.rtlDirCheckRe_ = new RegExp( + '^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']'); - if (resolution !== undefined) { - var res, z = 0; - do { - res = this.constrainResolution(this.maxResolution_, z); - if (res == resolution) { - offset = z; - break; - } - ++z; - } while (res > this.minResolution_); - } - return offset !== undefined ? this.minZoom_ + offset : offset; +/** + * Check whether the first strongly directional character (if any) is RTL. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether RTL directionality is detected using the first + * strongly-directional character method. + */ +goog.i18n.bidi.startsWithRtl = function(str, opt_isHtml) { + return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_( + str, opt_isHtml)); }; /** - * Fit the given geometry or extent based on the given map size and border. - * The size is pixel dimensions of the box to fit the extent into. - * In most cases you will want to use the map size, that is `map.getSize()`. - * Takes care of the map angle. - * @param {ol.geom.SimpleGeometry|ol.Extent} geometry Geometry. - * @param {ol.Size} size Box pixel size. - * @param {olx.view.FitOptions=} opt_options Options. - * @api + * Check whether the first strongly directional character (if any) is RTL. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether RTL directionality is detected using the first + * strongly-directional character method. + * @deprecated Use startsWithRtl. */ -ol.View.prototype.fit = function(geometry, size, opt_options) { - if (!(geometry instanceof ol.geom.SimpleGeometry)) { - goog.asserts.assert(goog.isArray(geometry), - 'invalid extent or geometry'); - goog.asserts.assert(!ol.extent.isEmpty(geometry), - 'cannot fit empty extent'); - geometry = ol.geom.Polygon.fromExtent(geometry); - } - - var options = opt_options || {}; +goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl; - var padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0]; - var constrainResolution = options.constrainResolution !== undefined ? - options.constrainResolution : true; - var nearest = options.nearest !== undefined ? options.nearest : false; - var minResolution; - if (options.minResolution !== undefined) { - minResolution = options.minResolution; - } else if (options.maxZoom !== undefined) { - minResolution = this.constrainResolution( - this.maxResolution_, options.maxZoom - this.minZoom_, 0); - } else { - minResolution = 0; - } - var coords = geometry.getFlatCoordinates(); - // calculate rotated extent - var rotation = this.getRotation(); - goog.asserts.assert(rotation !== undefined, 'rotation was not defined'); - var cosAngle = Math.cos(-rotation); - var sinAngle = Math.sin(-rotation); - var minRotX = +Infinity; - var minRotY = +Infinity; - var maxRotX = -Infinity; - var maxRotY = -Infinity; - var stride = geometry.getStride(); - for (var i = 0, ii = coords.length; i < ii; i += stride) { - var rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle; - var rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle; - minRotX = Math.min(minRotX, rotX); - minRotY = Math.min(minRotY, rotY); - maxRotX = Math.max(maxRotX, rotX); - maxRotY = Math.max(maxRotY, rotY); - } - - // calculate resolution - var resolution = this.getResolutionForExtent( - [minRotX, minRotY, maxRotX, maxRotY], - [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]); - resolution = isNaN(resolution) ? minResolution : - Math.max(resolution, minResolution); - if (constrainResolution) { - var constrainedResolution = this.constrainResolution(resolution, 0, 0); - if (!nearest && constrainedResolution < resolution) { - constrainedResolution = this.constrainResolution( - constrainedResolution, -1, 0); - } - resolution = constrainedResolution; - } - this.setResolution(resolution); - - // calculate center - sinAngle = -sinAngle; // go back to original rotation - var centerRotX = (minRotX + maxRotX) / 2; - var centerRotY = (minRotY + maxRotY) / 2; - centerRotX += (padding[1] - padding[3]) / 2 * resolution; - centerRotY += (padding[0] - padding[2]) / 2 * resolution; - var centerX = centerRotX * cosAngle - centerRotY * sinAngle; - var centerY = centerRotY * cosAngle + centerRotX * sinAngle; - - this.setCenter([centerX, centerY]); +/** + * Check whether the first strongly directional character (if any) is LTR. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether LTR directionality is detected using the first + * strongly-directional character method. + */ +goog.i18n.bidi.startsWithLtr = function(str, opt_isHtml) { + return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_( + str, opt_isHtml)); }; /** - * Center on coordinate and view position. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.Size} size Box pixel size. - * @param {ol.Pixel} position Position on the view to center on. - * @api + * Check whether the first strongly directional character (if any) is LTR. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether LTR directionality is detected using the first + * strongly-directional character method. + * @deprecated Use startsWithLtr. */ -ol.View.prototype.centerOn = function(coordinate, size, position) { - // calculate rotated position - var rotation = this.getRotation(); - var cosAngle = Math.cos(-rotation); - var sinAngle = Math.sin(-rotation); - var rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle; - var rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle; - var resolution = this.getResolution(); - rotX += (size[0] / 2 - position[0]) * resolution; - rotY += (position[1] - size[1] / 2) * resolution; +goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr; - // go back to original angle - sinAngle = -sinAngle; // go back to original rotation - var centerX = rotX * cosAngle - rotY * sinAngle; - var centerY = rotY * cosAngle + rotX * sinAngle; - this.setCenter([centerX, centerY]); -}; +/** + * Regular expression to check if a string looks like something that must + * always be LTR even in RTL text, e.g. a URL. When estimating the + * directionality of text containing these, we treat these as weakly LTR, + * like numbers. + * @type {RegExp} + * @private + */ +goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/; /** - * @return {boolean} Is defined. + * Check whether the input string either contains no strongly directional + * characters or looks like a url. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether neutral directionality is detected. */ -ol.View.prototype.isDef = function() { - return !!this.getCenter() && this.getResolution() !== undefined; +goog.i18n.bidi.isNeutralText = function(str, opt_isHtml) { + str = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml); + return goog.i18n.bidi.isRequiredLtrRe_.test(str) || + !goog.i18n.bidi.hasAnyLtr(str) && !goog.i18n.bidi.hasAnyRtl(str); }; /** - * Rotate the view around a given coordinate. - * @param {number} rotation New rotation value for the view. - * @param {ol.Coordinate=} opt_anchor The rotation center. - * @api stable + * Regular expressions to check if the last strongly-directional character in a + * piece of text is LTR. + * @type {RegExp} + * @private */ -ol.View.prototype.rotate = function(rotation, opt_anchor) { - if (opt_anchor !== undefined) { - var center = this.calculateCenterRotate(rotation, opt_anchor); - this.setCenter(center); - } - this.setRotation(rotation); -}; +goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp( + '[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$'); /** - * Set the center of the current view. - * @param {ol.Coordinate|undefined} center The center of the view. - * @observable - * @api stable + * Regular expressions to check if the last strongly-directional character in a + * piece of text is RTL. + * @type {RegExp} + * @private */ -ol.View.prototype.setCenter = function(center) { - this.set(ol.ViewProperty.CENTER, center); -}; +goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp( + '[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$'); /** - * @param {ol.ViewHint} hint Hint. - * @param {number} delta Delta. - * @return {number} New value. + * Check if the exit directionality a piece of text is LTR, i.e. if the last + * strongly-directional character in the string is LTR. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether LTR exit directionality was detected. */ -ol.View.prototype.setHint = function(hint, delta) { - goog.asserts.assert(0 <= hint && hint < this.hints_.length, - 'illegal hint (%s), must be between 0 and %s', hint, this.hints_.length); - this.hints_[hint] += delta; - goog.asserts.assert(this.hints_[hint] >= 0, - 'Hint at %s must be positive, was %s', hint, this.hints_[hint]); - return this.hints_[hint]; +goog.i18n.bidi.endsWithLtr = function(str, opt_isHtml) { + return goog.i18n.bidi.ltrExitDirCheckRe_.test( + goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)); }; /** - * Set the resolution for this view. - * @param {number|undefined} resolution The resolution of the view. - * @observable - * @api stable + * Check if the exit directionality a piece of text is LTR, i.e. if the last + * strongly-directional character in the string is LTR. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether LTR exit directionality was detected. + * @deprecated Use endsWithLtr. */ -ol.View.prototype.setResolution = function(resolution) { - this.set(ol.ViewProperty.RESOLUTION, resolution); -}; +goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr; /** - * Set the rotation for this view. - * @param {number} rotation The rotation of the view in radians. - * @observable - * @api stable + * Check if the exit directionality a piece of text is RTL, i.e. if the last + * strongly-directional character in the string is RTL. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether RTL exit directionality was detected. */ -ol.View.prototype.setRotation = function(rotation) { - this.set(ol.ViewProperty.ROTATION, rotation); +goog.i18n.bidi.endsWithRtl = function(str, opt_isHtml) { + return goog.i18n.bidi.rtlExitDirCheckRe_.test( + goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)); }; /** - * Zoom to a specific zoom level. - * @param {number} zoom Zoom level. - * @api stable + * Check if the exit directionality a piece of text is RTL, i.e. if the last + * strongly-directional character in the string is RTL. + * @param {string} str String being checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether RTL exit directionality was detected. + * @deprecated Use endsWithRtl. */ -ol.View.prototype.setZoom = function(zoom) { - var resolution = this.constrainResolution( - this.maxResolution_, zoom - this.minZoom_, 0); - this.setResolution(resolution); -}; +goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl; /** - * @param {olx.ViewOptions} options View options. + * A regular expression for matching right-to-left language codes. + * See {@link #isRtlLanguage} for the design. + * @type {RegExp} * @private - * @return {ol.CenterConstraintType} */ -ol.View.createCenterConstraint_ = function(options) { - if (options.extent !== undefined) { - return ol.CenterConstraint.createExtent(options.extent); - } else { - return ol.CenterConstraint.none; - } +goog.i18n.bidi.rtlLocalesRe_ = new RegExp( + '^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|' + + '.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))' + + '(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)', + 'i'); + + +/** + * Check if a BCP 47 / III language code indicates an RTL language, i.e. either: + * - a language code explicitly specifying one of the right-to-left scripts, + * e.g. "az-Arab", or<p> + * - a language code specifying one of the languages normally written in a + * right-to-left script, e.g. "fa" (Farsi), except ones explicitly specifying + * Latin or Cyrillic script (which are the usual LTR alternatives).<p> + * The list of right-to-left scripts appears in the 100-199 range in + * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and + * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and + * Tifinagh, which also have significant modern usage. The rest (Syriac, + * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage + * and are not recognized to save on code size. + * The languages usually written in a right-to-left script are taken as those + * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in + * http://www.iana.org/assignments/language-subtag-registry, + * as well as Central (or Sorani) Kurdish (ckb), Sindhi (sd) and Uyghur (ug). + * Other subtags of the language code, e.g. regions like EG (Egypt), are + * ignored. + * @param {string} lang BCP 47 (a.k.a III) language code. + * @return {boolean} Whether the language code is an RTL language. + */ +goog.i18n.bidi.isRtlLanguage = function(lang) { + return goog.i18n.bidi.rtlLocalesRe_.test(lang); }; /** + * Regular expression for bracket guard replacement in html. + * @type {RegExp} * @private - * @param {olx.ViewOptions} options View options. - * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number, - * minResolution: number}} */ -ol.View.createResolutionConstraint_ = function(options) { - var resolutionConstraint; - var maxResolution; - var minResolution; +goog.i18n.bidi.bracketGuardHtmlRe_ = + /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?(>)+)/g; - // TODO: move these to be ol constants - // see https://github.com/openlayers/ol3/issues/2076 - var defaultMaxZoom = 28; - var defaultZoomFactor = 2; - var minZoom = options.minZoom !== undefined ? - options.minZoom : ol.DEFAULT_MIN_ZOOM; +/** + * Regular expression for bracket guard replacement in text. + * @type {RegExp} + * @private + */ +goog.i18n.bidi.bracketGuardTextRe_ = + /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; - var maxZoom = options.maxZoom !== undefined ? - options.maxZoom : defaultMaxZoom; - var zoomFactor = options.zoomFactor !== undefined ? - options.zoomFactor : defaultZoomFactor; +/** + * Apply bracket guard using html span tag. This is to address the problem of + * messy bracket display frequently happens in RTL layout. + * @param {string} s The string that need to be processed. + * @param {boolean=} opt_isRtlContext specifies default direction (usually + * direction of the UI). + * @return {string} The processed string, with all bracket guarded. + */ +goog.i18n.bidi.guardBracketInHtml = function(s, opt_isRtlContext) { + var useRtl = opt_isRtlContext === undefined ? + goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext; + if (useRtl) { + return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_, + '<span dir=rtl>$&</span>'); + } + return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_, + '<span dir=ltr>$&</span>'); +}; - if (options.resolutions !== undefined) { - var resolutions = options.resolutions; - maxResolution = resolutions[0]; - minResolution = resolutions[resolutions.length - 1]; - resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions( - resolutions); - } else { - // calculate the default min and max resolution - var projection = ol.proj.createProjection(options.projection, 'EPSG:3857'); - var extent = projection.getExtent(); - var size = !extent ? - // use an extent that can fit the whole world if need be - 360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] / - ol.proj.METERS_PER_UNIT[projection.getUnits()] : - Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent)); - var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow( - defaultZoomFactor, ol.DEFAULT_MIN_ZOOM); +/** + * Apply bracket guard using LRM and RLM. This is to address the problem of + * messy bracket display frequently happens in RTL layout. + * This version works for both plain text and html. But it does not work as + * good as guardBracketInHtml in some cases. + * @param {string} s The string that need to be processed. + * @param {boolean=} opt_isRtlContext specifies default direction (usually + * direction of the UI). + * @return {string} The processed string, with all bracket guarded. + */ +goog.i18n.bidi.guardBracketInText = function(s, opt_isRtlContext) { + var useRtl = opt_isRtlContext === undefined ? + goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext; + var mark = useRtl ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM; + return s.replace(goog.i18n.bidi.bracketGuardTextRe_, mark + '$&' + mark); +}; - var defaultMinResolution = defaultMaxResolution / Math.pow( - defaultZoomFactor, defaultMaxZoom - ol.DEFAULT_MIN_ZOOM); - // user provided maxResolution takes precedence - maxResolution = options.maxResolution; - if (maxResolution !== undefined) { - minZoom = 0; - } else { - maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom); - } +/** + * Enforce the html snippet in RTL directionality regardless overall context. + * If the html piece was enclosed by tag, dir will be applied to existing + * tag, otherwise a span tag will be added as wrapper. For this reason, if + * html snippet start with with tag, this tag must enclose the whole piece. If + * the tag already has a dir specified, this new one will override existing + * one in behavior (tested on FF and IE). + * @param {string} html The string that need to be processed. + * @return {string} The processed string, with directionality enforced to RTL. + */ +goog.i18n.bidi.enforceRtlInHtml = function(html) { + if (html.charAt(0) == '<') { + return html.replace(/<\w+/, '$& dir=rtl'); + } + // '\n' is important for FF so that it won't incorrectly merge span groups + return '\n<span dir=rtl>' + html + '</span>'; +}; - // user provided minResolution takes precedence - minResolution = options.minResolution; - if (minResolution === undefined) { - if (options.maxZoom !== undefined) { - if (options.maxResolution !== undefined) { - minResolution = maxResolution / Math.pow(zoomFactor, maxZoom); - } else { - minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom); - } - } else { - minResolution = defaultMinResolution; - } - } - // given discrete zoom levels, minResolution may be different than provided - maxZoom = minZoom + Math.floor( - Math.log(maxResolution / minResolution) / Math.log(zoomFactor)); - minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom); +/** + * Enforce RTL on both end of the given text piece using unicode BiDi formatting + * characters RLE and PDF. + * @param {string} text The piece of text that need to be wrapped. + * @return {string} The wrapped string after process. + */ +goog.i18n.bidi.enforceRtlInText = function(text) { + return goog.i18n.bidi.Format.RLE + text + goog.i18n.bidi.Format.PDF; +}; - resolutionConstraint = ol.ResolutionConstraint.createSnapToPower( - zoomFactor, maxResolution, maxZoom - minZoom); + +/** + * Enforce the html snippet in RTL directionality regardless overall context. + * If the html piece was enclosed by tag, dir will be applied to existing + * tag, otherwise a span tag will be added as wrapper. For this reason, if + * html snippet start with with tag, this tag must enclose the whole piece. If + * the tag already has a dir specified, this new one will override existing + * one in behavior (tested on FF and IE). + * @param {string} html The string that need to be processed. + * @return {string} The processed string, with directionality enforced to RTL. + */ +goog.i18n.bidi.enforceLtrInHtml = function(html) { + if (html.charAt(0) == '<') { + return html.replace(/<\w+/, '$& dir=ltr'); } - return {constraint: resolutionConstraint, maxResolution: maxResolution, - minResolution: minResolution, minZoom: minZoom}; + // '\n' is important for FF so that it won't incorrectly merge span groups + return '\n<span dir=ltr>' + html + '</span>'; }; /** - * @private - * @param {olx.ViewOptions} options View options. - * @return {ol.RotationConstraintType} Rotation constraint. + * Enforce LTR on both end of the given text piece using unicode BiDi formatting + * characters LRE and PDF. + * @param {string} text The piece of text that need to be wrapped. + * @return {string} The wrapped string after process. */ -ol.View.createRotationConstraint_ = function(options) { - var enableRotation = options.enableRotation !== undefined ? - options.enableRotation : true; - if (enableRotation) { - var constrainRotation = options.constrainRotation; - if (constrainRotation === undefined || constrainRotation === true) { - return ol.RotationConstraint.createSnapToZero(); - } else if (constrainRotation === false) { - return ol.RotationConstraint.none; - } else if (goog.isNumber(constrainRotation)) { - return ol.RotationConstraint.createSnapToN(constrainRotation); - } else { - goog.asserts.fail( - 'illegal option for constrainRotation (%s)', constrainRotation); - return ol.RotationConstraint.none; - } - } else { - return ol.RotationConstraint.disable; - } +goog.i18n.bidi.enforceLtrInText = function(text) { + return goog.i18n.bidi.Format.LRE + text + goog.i18n.bidi.Format.PDF; }; -goog.exportProperty(ol.View.prototype, 'getResolutionForExtent', - ol.View.prototype.getResolutionForExtent); -goog.provide('ol.easing'); +/** + * Regular expression to find dimensions such as "padding: .3 0.4ex 5px 6;" + * @type {RegExp} + * @private + */ +goog.i18n.bidi.dimensionsRe_ = + /:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g; /** - * Start slow and speed up. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api + * Regular expression for left. + * @type {RegExp} + * @private */ -ol.easing.easeIn = function(t) { - return Math.pow(t, 3); -}; +goog.i18n.bidi.leftRe_ = /left/gi; /** - * Start fast and slow down. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api + * Regular expression for right. + * @type {RegExp} + * @private */ -ol.easing.easeOut = function(t) { - return 1 - ol.easing.easeIn(1 - t); -}; +goog.i18n.bidi.rightRe_ = /right/gi; /** - * Start slow, speed up, and then slow down again. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api + * Placeholder regular expression for swapping. + * @type {RegExp} + * @private */ -ol.easing.inAndOut = function(t) { - return 3 * t * t - 2 * t * t * t; -}; +goog.i18n.bidi.tempRe_ = /%%%%/g; /** - * Maintain a constant speed over time. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api + * Swap location parameters and 'left'/'right' in CSS specification. The + * processed string will be suited for RTL layout. Though this function can + * cover most cases, there are always exceptions. It is suggested to put + * those exceptions in separate group of CSS string. + * @param {string} cssStr CSS spefication string. + * @return {string} Processed CSS specification string. */ -ol.easing.linear = function(t) { - return t; +goog.i18n.bidi.mirrorCSS = function(cssStr) { + return cssStr. + // reverse dimensions + replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2'). + replace(goog.i18n.bidi.leftRe_, '%%%%'). // swap left and right + replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT). + replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT); }; /** - * Start slow, speed up, and at the very end slow down again. This has the - * same general behavior as {@link ol.easing.inAndOut}, but the final slowdown - * is delayed. - * @param {number} t Input between 0 and 1. - * @return {number} Output between 0 and 1. - * @api + * Regular expression for hebrew double quote substitution, finding quote + * directly after hebrew characters. + * @type {RegExp} + * @private */ -ol.easing.upAndDown = function(t) { - if (t < 0.5) { - return ol.easing.inAndOut(2 * t); - } else { - return 1 - ol.easing.inAndOut(2 * (t - 0.5)); - } -}; +goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g; -goog.provide('ol.animation'); -goog.require('ol'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.ViewHint'); -goog.require('ol.coordinate'); -goog.require('ol.easing'); +/** + * Regular expression for hebrew single quote substitution, finding quote + * directly after hebrew characters. + * @type {RegExp} + * @private + */ +goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g; /** - * Generate an animated transition that will "bounce" the resolution as it - * approaches the final value. - * @param {olx.animation.BounceOptions} options Bounce options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api + * Replace the double and single quote directly after a Hebrew character with + * GERESH and GERSHAYIM. In such case, most likely that's user intention. + * @param {string} str String that need to be processed. + * @return {string} Processed string with double/single quote replaced. */ -ol.animation.bounce = function(options) { - var resolution = options.resolution; - var start = options.start ? options.start : Date.now(); - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.upAndDown; - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = easing((frameState.time - start) / duration); - var deltaResolution = resolution - frameState.viewState.resolution; - frameState.animate = true; - frameState.viewState.resolution += delta * deltaResolution; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); +goog.i18n.bidi.normalizeHebrewQuote = function(str) { + return str. + replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1\u05f4'). + replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1\u05f3'); }; /** - * Generate an animated transition while updating the view center. - * @param {olx.animation.PanOptions} options Pan options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api + * Regular expression to split a string into "words" for directionality + * estimation based on relative word counts. + * @type {RegExp} + * @private */ -ol.animation.pan = function(options) { - var source = options.source; - var start = options.start ? options.start : Date.now(); - var sourceX = source[0]; - var sourceY = source[1]; - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.inAndOut; - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = 1 - easing((frameState.time - start) / duration); - var deltaX = sourceX - frameState.viewState.center[0]; - var deltaY = sourceY - frameState.viewState.center[1]; - frameState.animate = true; - frameState.viewState.center[0] += delta * deltaX; - frameState.viewState.center[1] += delta * deltaY; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; +goog.i18n.bidi.wordSeparatorRe_ = /\s+/; /** - * Generate an animated transition while updating the view rotation. - * @param {olx.animation.RotateOptions} options Rotate options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api + * Regular expression to check if a string contains any numerals. Used to + * differentiate between completely neutral strings and those containing + * numbers, which are weakly LTR. + * + * Native Arabic digits (\u0660 - \u0669) are not included because although they + * do flow left-to-right inside a number, this is the case even if the overall + * directionality is RTL, and a mathematical expression using these digits is + * supposed to flow right-to-left overall, including unary plus and minus + * appearing to the right of a number, and this does depend on the overall + * directionality being RTL. The digits used in Farsi (\u06F0 - \u06F9), on the + * other hand, are included, since Farsi math (including unary plus and minus) + * does flow left-to-right. + * + * @type {RegExp} + * @private */ -ol.animation.rotate = function(options) { - var sourceRotation = options.rotation ? options.rotation : 0; - var start = options.start ? options.start : Date.now(); - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.inAndOut; - var anchor = options.anchor ? - options.anchor : null; - - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = 1 - easing((frameState.time - start) / duration); - var deltaRotation = - (sourceRotation - frameState.viewState.rotation) * delta; - frameState.animate = true; - frameState.viewState.rotation += deltaRotation; - if (anchor) { - var center = frameState.viewState.center; - ol.coordinate.sub(center, anchor); - ol.coordinate.rotate(center, deltaRotation); - ol.coordinate.add(center, anchor); - } - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; +goog.i18n.bidi.hasNumeralsRe_ = /[\d\u06f0-\u06f9]/; /** - * Generate an animated transition while updating the view resolution. - * @param {olx.animation.ZoomOptions} options Zoom options. - * @return {ol.PreRenderFunction} Pre-render function. - * @api + * This constant controls threshold of RTL directionality. + * @type {number} + * @private */ -ol.animation.zoom = function(options) { - var sourceResolution = options.resolution; - var start = options.start ? options.start : Date.now(); - var duration = options.duration !== undefined ? options.duration : 1000; - var easing = options.easing ? - options.easing : ol.easing.inAndOut; - return ( - /** - * @param {ol.Map} map Map. - * @param {?olx.FrameState} frameState Frame state. - */ - function(map, frameState) { - if (frameState.time < start) { - frameState.animate = true; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else if (frameState.time < start + duration) { - var delta = 1 - easing((frameState.time - start) / duration); - var deltaResolution = - sourceResolution - frameState.viewState.resolution; - frameState.animate = true; - frameState.viewState.resolution += delta * deltaResolution; - frameState.viewHints[ol.ViewHint.ANIMATING] += 1; - return true; - } else { - return false; - } - }); -}; - -goog.provide('ol.TileCoord'); -goog.provide('ol.tilecoord'); - -goog.require('goog.asserts'); -goog.require('ol.extent'); +goog.i18n.bidi.rtlDetectionThreshold_ = 0.40; /** - * An array of three numbers representing the location of a tile in a tile - * grid. The order is `z`, `x`, and `y`. `z` is the zoom level. - * @typedef {Array.<number>} ol.TileCoord - * @api + * Estimates the directionality of a string based on relative word counts. + * If the number of RTL words is above a certain percentage of the total number + * of strongly directional words, returns RTL. + * Otherwise, if any words are strongly or weakly LTR, returns LTR. + * Otherwise, returns UNKNOWN, which is used to mean "neutral". + * Numbers are counted as weakly LTR. + * @param {string} str The string to be checked. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}. */ -ol.TileCoord; - +goog.i18n.bidi.estimateDirection = function(str, opt_isHtml) { + var rtlCount = 0; + var totalCount = 0; + var hasWeaklyLtr = false; + var tokens = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml). + split(goog.i18n.bidi.wordSeparatorRe_); + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (goog.i18n.bidi.startsWithRtl(token)) { + rtlCount++; + totalCount++; + } else if (goog.i18n.bidi.isRequiredLtrRe_.test(token)) { + hasWeaklyLtr = true; + } else if (goog.i18n.bidi.hasAnyLtr(token)) { + totalCount++; + } else if (goog.i18n.bidi.hasNumeralsRe_.test(token)) { + hasWeaklyLtr = true; + } + } -/** - * @enum {number} - */ -ol.QuadKeyCharCode = { - ZERO: '0'.charCodeAt(0), - ONE: '1'.charCodeAt(0), - TWO: '2'.charCodeAt(0), - THREE: '3'.charCodeAt(0) + return totalCount == 0 ? + (hasWeaklyLtr ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL) : + (rtlCount / totalCount > goog.i18n.bidi.rtlDetectionThreshold_ ? + goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR); }; /** - * @param {string} str String that follows pattern “z/x/y” where x, y and z are - * numbers. - * @return {ol.TileCoord} Tile coord. + * Check the directionality of a piece of text, return true if the piece of + * text should be laid out in RTL direction. + * @param {string} str The piece of text that need to be detected. + * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. + * Default: false. + * @return {boolean} Whether this piece of text should be laid out in RTL. */ -ol.tilecoord.createFromString = function(str) { - var v = str.split('/'); - goog.asserts.assert(v.length === 3, - 'must provide a string in "z/x/y" format, got "%s"', str); - return v.map(function(e) { - return parseInt(e, 10); - }); +goog.i18n.bidi.detectRtlDirectionality = function(str, opt_isHtml) { + return goog.i18n.bidi.estimateDirection(str, opt_isHtml) == + goog.i18n.bidi.Dir.RTL; }; /** - * @param {number} z Z. - * @param {number} x X. - * @param {number} y Y. - * @param {ol.TileCoord=} opt_tileCoord Tile coordinate. - * @return {ol.TileCoord} Tile coordinate. + * Sets text input element's directionality and text alignment based on a + * given directionality. Does nothing if the given directionality is unknown or + * neutral. + * @param {Element} element Input field element to set directionality to. + * @param {goog.i18n.bidi.Dir|number|boolean|null} dir Desired directionality, + * given in one of the following formats: + * 1. A goog.i18n.bidi.Dir constant. + * 2. A number (positive = LRT, negative = RTL, 0 = neutral). + * 3. A boolean (true = RTL, false = LTR). + * 4. A null for unknown directionality. */ -ol.tilecoord.createOrUpdate = function(z, x, y, opt_tileCoord) { - if (opt_tileCoord !== undefined) { - opt_tileCoord[0] = z; - opt_tileCoord[1] = x; - opt_tileCoord[2] = y; - return opt_tileCoord; - } else { - return [z, x, y]; +goog.i18n.bidi.setElementDirAndAlign = function(element, dir) { + if (element) { + dir = goog.i18n.bidi.toDir(dir); + if (dir) { + element.style.textAlign = + dir == goog.i18n.bidi.Dir.RTL ? + goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT; + element.dir = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr'; + } } }; /** - * @param {number} z Z. - * @param {number} x X. - * @param {number} y Y. - * @return {string} Key. + * Sets element dir based on estimated directionality of the given text. + * @param {!Element} element + * @param {string} text */ -ol.tilecoord.getKeyZXY = function(z, x, y) { - return z + '/' + x + '/' + y; +goog.i18n.bidi.setElementDirByTextDirectionality = function(element, text) { + switch (goog.i18n.bidi.estimateDirection(text)) { + case (goog.i18n.bidi.Dir.LTR): + element.dir = 'ltr'; + break; + case (goog.i18n.bidi.Dir.RTL): + element.dir = 'rtl'; + break; + default: + // Default for no direction, inherit from document. + element.removeAttribute('dir'); + } }; -/** - * @param {ol.TileCoord} tileCoord Tile coord. - * @return {number} Hash. - */ -ol.tilecoord.hash = function(tileCoord) { - return (tileCoord[1] << tileCoord[0]) + tileCoord[2]; -}; - /** - * @param {ol.TileCoord} tileCoord Tile coord. - * @return {string} Quad key. + * Strings that have an (optional) known direction. + * + * Implementations of this interface are string-like objects that carry an + * attached direction, if known. + * @interface */ -ol.tilecoord.quadKey = function(tileCoord) { - var z = tileCoord[0]; - var digits = new Array(z); - var mask = 1 << (z - 1); - var i, charCode; - for (i = 0; i < z; ++i) { - charCode = ol.QuadKeyCharCode.ZERO; - if (tileCoord[1] & mask) { - charCode += 1; - } - if (tileCoord[2] & mask) { - charCode += 2; - } - digits[i] = String.fromCharCode(charCode); - mask >>= 1; - } - return digits.join(''); -}; +goog.i18n.bidi.DirectionalString = function() {}; /** - * @param {ol.TileCoord} tileCoord Tile coord. - * @return {string} String. + * Interface marker of the DirectionalString interface. + * + * This property can be used to determine at runtime whether or not an object + * implements this interface. All implementations of this interface set this + * property to {@code true}. + * @type {boolean} */ -ol.tilecoord.toString = function(tileCoord) { - return ol.tilecoord.getKeyZXY(tileCoord[0], tileCoord[1], tileCoord[2]); -}; +goog.i18n.bidi.DirectionalString.prototype. + implementsGoogI18nBidiDirectionalString; /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.TileCoord} Tile coordinate. + * Retrieves this object's known direction (if any). + * @return {?goog.i18n.bidi.Dir} The known direction. Null if unknown. */ -ol.tilecoord.wrapX = function(tileCoord, tileGrid, projection) { - var z = tileCoord[0]; - var center = tileGrid.getTileCoordCenter(tileCoord); - var projectionExtent = ol.tilegrid.extentFromProjection(projection); - if (!ol.extent.containsCoordinate(projectionExtent, center)) { - var worldWidth = ol.extent.getWidth(projectionExtent); - var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth); - center[0] += worldWidth * worldsAway; - return tileGrid.getTileCoordForCoordAndZ(center, z); - } else { - return tileCoord; - } -}; +goog.i18n.bidi.DirectionalString.prototype.getDirection; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {boolean} Tile coordinate is within extent and zoom level range. + * @fileoverview The SafeUrl type and its builders. + * + * TODO(xtof): Link to document stating type contract. */ -ol.tilecoord.withinExtentAndZ = function(tileCoord, tileGrid) { - var z = tileCoord[0]; - var x = tileCoord[1]; - var y = tileCoord[2]; - - if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) { - return false; - } - var extent = tileGrid.getExtent(); - var tileRange; - if (!extent) { - tileRange = tileGrid.getFullTileRange(z); - } else { - tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - } - if (!tileRange) { - return true; - } else { - return tileRange.containsXY(x, y); - } -}; -goog.provide('ol.TileRange'); +goog.provide('goog.html.SafeUrl'); goog.require('goog.asserts'); -goog.require('ol.Size'); -goog.require('ol.TileCoord'); +goog.require('goog.fs.url'); +goog.require('goog.i18n.bidi.Dir'); +goog.require('goog.i18n.bidi.DirectionalString'); +goog.require('goog.string.Const'); +goog.require('goog.string.TypedString'); /** - * A representation of a contiguous block of tiles. A tile range is specified - * by its min/max tile coordinates and is inclusive of coordinates. + * A string that is safe to use in URL context in DOM APIs and HTML documents. + * + * A SafeUrl is a string-like object that carries the security type contract + * that its value as a string will not cause untrusted script execution + * when evaluated as a hyperlink URL in a browser. + * + * Values of this type are guaranteed to be safe to use in URL/hyperlink + * contexts, such as, assignment to URL-valued DOM properties, or + * interpolation into a HTML template in URL context (e.g., inside a href + * attribute), in the sense that the use will not result in a + * Cross-Site-Scripting vulnerability. + * + * Note that, as documented in {@code goog.html.SafeUrl.unwrap}, this type's + * contract does not guarantee that instances are safe to interpolate into HTML + * without appropriate escaping. + * + * Note also that this type's contract does not imply any guarantees regarding + * the resource the URL refers to. In particular, SafeUrls are <b>not</b> + * safe to use in a context where the referred-to resource is interpreted as + * trusted code, e.g., as the src of a script tag. + * + * Instances of this type must be created via the factory methods + * ({@code goog.html.SafeUrl.fromConstant}, {@code goog.html.SafeUrl.sanitize}), + * etc and not by invoking its constructor. The constructor intentionally + * takes no parameters and the type is immutable; hence only a default instance + * corresponding to the empty string can be obtained via constructor invocation. * + * @see goog.html.SafeUrl#fromConstant + * @see goog.html.SafeUrl#from + * @see goog.html.SafeUrl#sanitize * @constructor - * @param {number} minX Minimum X. - * @param {number} maxX Maximum X. - * @param {number} minY Minimum Y. - * @param {number} maxY Maximum Y. + * @final * @struct + * @implements {goog.i18n.bidi.DirectionalString} + * @implements {goog.string.TypedString} */ -ol.TileRange = function(minX, maxX, minY, maxY) { - - /** - * @type {number} - */ - this.minX = minX; - +goog.html.SafeUrl = function() { /** - * @type {number} + * The contained value of this SafeUrl. The field has a purposely ugly + * name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} */ - this.maxX = maxX; + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ''; /** - * @type {number} + * A type marker used to implement additional run-time type checking. + * @see goog.html.SafeUrl#unwrap + * @const + * @private */ - this.minY = minY; + this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = + goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; +}; - /** - * @type {number} - */ - this.maxY = maxY; -}; +/** + * The innocuous string generated by goog.html.SafeUrl.sanitize when passed + * an unsafe URL. + * + * about:invalid is registered in + * http://www.w3.org/TR/css3-values/#about-invalid. + * http://tools.ietf.org/html/rfc6694#section-2.2.1 permits about URLs to + * contain a fragment, which is not to be considered when determining if an + * about URL is well-known. + * + * Using about:invalid seems preferable to using a fixed data URL, since + * browsers might choose to not report CSP violations on it, as legitimate + * CSS function calls to attr() can result in this URL being produced. It is + * also a standard URL which matches exactly the semantics we need: + * "The about:invalid URI references a non-existent document with a generic + * error condition. It can be used when a URI is necessary, but the default + * value shouldn't be resolveable as any type of document". + * + * @const {string} + */ +goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez'; /** - * @param {...ol.TileCoord} var_args Tile coordinates. - * @return {!ol.TileRange} Bounding tile box. + * @override + * @const */ -ol.TileRange.boundingTileRange = function(var_args) { - var tileCoord0 = /** @type {ol.TileCoord} */ (arguments[0]); - var tileCoord0Z = tileCoord0[0]; - var tileCoord0X = tileCoord0[1]; - var tileCoord0Y = tileCoord0[2]; - var tileRange = new ol.TileRange(tileCoord0X, tileCoord0X, - tileCoord0Y, tileCoord0Y); - var i, ii, tileCoord, tileCoordX, tileCoordY, tileCoordZ; - for (i = 1, ii = arguments.length; i < ii; ++i) { - tileCoord = /** @type {ol.TileCoord} */ (arguments[i]); - tileCoordZ = tileCoord[0]; - tileCoordX = tileCoord[1]; - tileCoordY = tileCoord[2]; - goog.asserts.assert(tileCoordZ == tileCoord0Z, - 'passed tilecoords all have the same Z-value'); - tileRange.minX = Math.min(tileRange.minX, tileCoordX); - tileRange.maxX = Math.max(tileRange.maxX, tileCoordX); - tileRange.minY = Math.min(tileRange.minY, tileCoordY); - tileRange.maxY = Math.max(tileRange.maxY, tileCoordY); - } - return tileRange; -}; +goog.html.SafeUrl.prototype.implementsGoogStringTypedString = true; /** - * @param {number} minX Minimum X. - * @param {number} maxX Maximum X. - * @param {number} minY Minimum Y. - * @param {number} maxY Maximum Y. - * @param {ol.TileRange|undefined} tileRange TileRange. - * @return {ol.TileRange} Tile range. + * Returns this SafeUrl's value a string. + * + * IMPORTANT: In code where it is security relevant that an object's type is + * indeed {@code SafeUrl}, use {@code goog.html.SafeUrl.unwrap} instead of this + * method. If in doubt, assume that it's security relevant. In particular, note + * that goog.html functions which return a goog.html type do not guarantee that + * the returned instance is of the right type. For example: + * + * <pre> + * var fakeSafeHtml = new String('fake'); + * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; + * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); + * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by + * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof + * // goog.html.SafeHtml. + * </pre> + * + * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the + * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST + * be appropriately escaped before embedding in a HTML document. Note that the + * required escaping is context-sensitive (e.g. a different escaping is + * required for embedding a URL in a style property within a style + * attribute, as opposed to embedding in a href attribute). + * + * @see goog.html.SafeUrl#unwrap + * @override */ -ol.TileRange.createOrUpdate = function(minX, maxX, minY, maxY, tileRange) { - if (tileRange !== undefined) { - tileRange.minX = minX; - tileRange.maxX = maxX; - tileRange.minY = minY; - tileRange.maxY = maxY; - return tileRange; - } else { - return new ol.TileRange(minX, maxX, minY, maxY); - } +goog.html.SafeUrl.prototype.getTypedStringValue = function() { + return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_; }; /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @return {boolean} Contains tile coordinate. + * @override + * @const */ -ol.TileRange.prototype.contains = function(tileCoord) { - return this.containsXY(tileCoord[1], tileCoord[2]); -}; +goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = true; /** - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} Contains. + * Returns this URLs directionality, which is always {@code LTR}. + * @override */ -ol.TileRange.prototype.containsTileRange = function(tileRange) { - return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX && - this.minY <= tileRange.minY && tileRange.maxY <= this.maxY; +goog.html.SafeUrl.prototype.getDirection = function() { + return goog.i18n.bidi.Dir.LTR; }; +if (goog.DEBUG) { + /** + * Returns a debug string-representation of this value. + * + * To obtain the actual string value wrapped in a SafeUrl, use + * {@code goog.html.SafeUrl.unwrap}. + * + * @see goog.html.SafeUrl#unwrap + * @override + */ + goog.html.SafeUrl.prototype.toString = function() { + return 'SafeUrl{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ + + '}'; + }; +} + + /** - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @return {boolean} Contains coordinate. + * Performs a runtime check that the provided object is indeed a SafeUrl + * object, and returns its value. + * + * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the + * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST + * be appropriately escaped before embedding in a HTML document. Note that the + * required escaping is context-sensitive (e.g. a different escaping is + * required for embedding a URL in a style property within a style + * attribute, as opposed to embedding in a href attribute). + * + * @param {!goog.html.SafeUrl} safeUrl The object to extract from. + * @return {string} The SafeUrl object's contained string, unless the run-time + * type check fails. In that case, {@code unwrap} returns an innocuous + * string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.TileRange.prototype.containsXY = function(x, y) { - return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY; +goog.html.SafeUrl.unwrap = function(safeUrl) { + // Perform additional Run-time type-checking to ensure that safeUrl is indeed + // an instance of the expected type. This provides some additional protection + // against security bugs due to application code that disables type checks. + // Specifically, the following checks are performed: + // 1. The object is an instance of the expected type. + // 2. The object is not an instance of a subclass. + // 3. The object carries a type marker for the expected type. "Faking" an + // object requires a reference to the type marker, which has names intended + // to stand out in code reviews. + if (safeUrl instanceof goog.html.SafeUrl && + safeUrl.constructor === goog.html.SafeUrl && + safeUrl.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === + goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { + return safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_; + } else { + goog.asserts.fail('expected object of type SafeUrl, got \'' + + safeUrl + '\''); + return 'type_error:SafeUrl'; + + } }; /** - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} Equals. + * Creates a SafeUrl object from a compile-time constant string. + * + * Compile-time constant strings are inherently program-controlled and hence + * trusted. + * + * @param {!goog.string.Const} url A compile-time-constant string from which to + * create a SafeUrl. + * @return {!goog.html.SafeUrl} A SafeUrl object initialized to {@code url}. */ -ol.TileRange.prototype.equals = function(tileRange) { - return this.minX == tileRange.minX && this.minY == tileRange.minY && - this.maxX == tileRange.maxX && this.maxY == tileRange.maxY; +goog.html.SafeUrl.fromConstant = function(url) { + return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( + goog.string.Const.unwrap(url)); }; /** - * @param {ol.TileRange} tileRange Tile range. + * A pattern that matches Blob or data types that can have SafeUrls created + * from URL.createObjectURL(blob) or via a data: URI. Only matches image and + * video types, currently. + * @const + * @private */ -ol.TileRange.prototype.extend = function(tileRange) { - if (tileRange.minX < this.minX) { - this.minX = tileRange.minX; - } - if (tileRange.maxX > this.maxX) { - this.maxX = tileRange.maxX; - } - if (tileRange.minY < this.minY) { - this.minY = tileRange.minY; - } - if (tileRange.maxY > this.maxY) { - this.maxY = tileRange.maxY; - } -}; +goog.html.SAFE_MIME_TYPE_PATTERN_ = + /^(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm))$/i; /** - * @return {number} Height. + * Creates a SafeUrl wrapping a blob URL for the given {@code blob}. + * + * The blob URL is created with {@code URL.createObjectURL}. If the MIME type + * for {@code blob} is not of a known safe image or video MIME type, then the + * SafeUrl will wrap {@link #INNOCUOUS_STRING}. + * + * @see http://www.w3.org/TR/FileAPI/#url + * @param {!Blob} blob + * @return {!goog.html.SafeUrl} The blob URL, or an innocuous string wrapped + * as a SafeUrl. */ -ol.TileRange.prototype.getHeight = function() { - return this.maxY - this.minY + 1; +goog.html.SafeUrl.fromBlob = function(blob) { + var url = goog.html.SAFE_MIME_TYPE_PATTERN_.test(blob.type) ? + goog.fs.url.createObjectUrl(blob) : goog.html.SafeUrl.INNOCUOUS_STRING; + return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); }; /** - * @return {ol.Size} Size. + * Matches a base-64 data URL, with the first match group being the MIME type. + * @const + * @private */ -ol.TileRange.prototype.getSize = function() { - return [this.getWidth(), this.getHeight()]; -}; +goog.html.DATA_URL_PATTERN_ = /^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; /** - * @return {number} Width. + * Creates a SafeUrl wrapping a data: URL, after validating it matches a + * known-safe image or video MIME type. + * + * @param {string} dataUrl A valid base64 data URL with one of the whitelisted + * image or video MIME types. + * @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING} + * wrapped as a SafeUrl if it does not pass. */ -ol.TileRange.prototype.getWidth = function() { - return this.maxX - this.minX + 1; +goog.html.SafeUrl.fromDataUrl = function(dataUrl) { + // There's a slight risk here that a browser sniffs the content type if it + // doesn't know the MIME type and executes HTML within the data: URL. For this + // to cause XSS it would also have to execute the HTML in the same origin + // of the page with the link. It seems unlikely that both of these will + // happen, particularly in not really old IEs. + var match = dataUrl.match(goog.html.DATA_URL_PATTERN_); + var valid = match && goog.html.SAFE_MIME_TYPE_PATTERN_.test(match[1]); + return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( + valid ? dataUrl : goog.html.SafeUrl.INNOCUOUS_STRING); }; /** - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} Intersects. + * A pattern that recognizes a commonly useful subset of URLs that satisfy + * the SafeUrl contract. + * + * This regular expression matches a subset of URLs that will not cause script + * execution if used in URL context within a HTML document. Specifically, this + * regular expression matches if (comment from here on and regex copied from + * Soy's EscapingConventions): + * (1) Either a protocol in a whitelist (http, https, mailto or ftp). + * (2) or no protocol. A protocol must be followed by a colon. The below + * allows that by allowing colons only after one of the characters [/?#]. + * A colon after a hash (#) must be in the fragment. + * Otherwise, a colon after a (?) must be in a query. + * Otherwise, a colon after a single solidus (/) must be in a path. + * Otherwise, a colon after a double solidus (//) must be in the authority + * (before port). + * + * The pattern disallows &, used in HTML entity declarations before + * one of the characters in [/?#]. This disallows HTML entities used in the + * protocol name, which should never happen, e.g. "http" for "http". + * It also disallows HTML entities in the first path part of a relative path, + * e.g. "foo<bar/baz". Our existing escaping functions should not produce + * that. More importantly, it disallows masking of a colon, + * e.g. "javascript:...". + * + * @private + * @const {!RegExp} */ -ol.TileRange.prototype.intersects = function(tileRange) { - return this.minX <= tileRange.maxX && - this.maxX >= tileRange.minX && - this.minY <= tileRange.maxY && - this.maxY >= tileRange.minY; -}; +goog.html.SAFE_URL_PATTERN_ = + /^(?:(?:https?|mailto|ftp):|[^&:/?#]*(?:[/?#]|$))/i; + + /** - * @return {number} Min X + * Creates a SafeUrl object from {@code url}. If {@code url} is a + * goog.html.SafeUrl then it is simply returned. Otherwise the input string is + * validated to match a pattern of commonly used safe URLs. The string is + * converted to UTF-8 and non-whitelisted characters are percent-encoded. The + * string wrapped by the created SafeUrl will thus contain only ASCII printable + * characters. + * + * {@code url} may be a URL with the http, https, mailto or ftp scheme, + * or a relative URL (i.e., a URL without a scheme; specifically, a + * scheme-relative, absolute-path-relative, or path-relative URL). + * + * {@code url} is converted to UTF-8 and non-whitelisted characters are + * percent-encoded. Whitelisted characters are '%' and, from RFC 3986, + * unreserved characters and reserved characters, with the exception of '\'', + * '(' and ')'. This ensures the the SafeUrl contains only ASCII-printable + * characters and reduces the chance of security bugs were it to be + * interpolated into a specific context without the necessary escaping. + * + * If {@code url} fails validation or does not UTF-16 decode correctly + * (JavaScript strings are UTF-16 encoded), this function returns a SafeUrl + * object containing an innocuous string, goog.html.SafeUrl.INNOCUOUS_STRING. + * + * @see http://url.spec.whatwg.org/#concept-relative-url + * @param {string|!goog.string.TypedString} url The URL to validate. + * @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl. */ -ol.TileRange.prototype.getMinX = function() { - return this.minX; -} -goog.exportProperty(ol.TileRange.prototype, 'getMinX', - ol.TileRange.prototype.getMinX); +goog.html.SafeUrl.sanitize = function(url) { + if (url instanceof goog.html.SafeUrl) { + return url; + } + else if (url.implementsGoogStringTypedString) { + url = url.getTypedStringValue(); + } else { + url = String(url); + } + if (!goog.html.SAFE_URL_PATTERN_.test(url)) { + url = goog.html.SafeUrl.INNOCUOUS_STRING; + } + return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); +}; /** - * @return {number} Max X + * Type marker for the SafeUrl type, used to implement additional run-time + * type checking. + * @const {!Object} + * @private */ -ol.TileRange.prototype.getMaxX = function() { - return this.maxX; -} -goog.exportProperty(ol.TileRange.prototype, 'getMaxX', - ol.TileRange.prototype.getMaxX); +goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; /** - * @return {number} Min Y + * Package-internal utility method to create SafeUrl instances. + * + * @param {string} url The string to initialize the SafeUrl object with. + * @return {!goog.html.SafeUrl} The initialized SafeUrl object. + * @package */ -ol.TileRange.prototype.getMinY = function() { - return this.minY; -} -goog.exportProperty(ol.TileRange.prototype, 'getMinY', - ol.TileRange.prototype.getMinY); +goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function( + url) { + var safeUrl = new goog.html.SafeUrl(); + safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = url; + return safeUrl; +}; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @return {number} Max Y + * @fileoverview The TrustedResourceUrl type and its builders. + * + * TODO(xtof): Link to document stating type contract. */ -ol.TileRange.prototype.getMaxY = function() { - return this.maxY; -} -goog.exportProperty(ol.TileRange.prototype, 'getMaxY', - ol.TileRange.prototype.getMaxY); +goog.provide('goog.html.TrustedResourceUrl'); -goog.provide('ol.Attribution'); - -goog.require('goog.math'); -goog.require('ol.TileRange'); +goog.require('goog.asserts'); +goog.require('goog.i18n.bidi.Dir'); +goog.require('goog.i18n.bidi.DirectionalString'); +goog.require('goog.string.Const'); +goog.require('goog.string.TypedString'); /** - * @classdesc - * An attribution for a layer source. + * A URL which is under application control and from which script, CSS, and + * other resources that represent executable code, can be fetched. * - * Example: + * Given that the URL can only be constructed from strings under application + * control and is used to load resources, bugs resulting in a malformed URL + * should not have a security impact and are likely to be easily detectable + * during testing. Given the wide number of non-RFC compliant URLs in use, + * stricter validation could prevent some applications from being able to use + * this type. * - * source: new ol.source.OSM({ - * attributions: [ - * new ol.Attribution({ - * html: 'All maps © ' + - * '<a href="http://www.opencyclemap.org/">OpenCycleMap</a>' - * }), - * ol.source.OSM.ATTRIBUTION - * ], - * .. + * Instances of this type must be created via the factory method, + * ({@code goog.html.TrustedResourceUrl.fromConstant}), and not by invoking its + * constructor. The constructor intentionally takes no parameters and the type + * is immutable; hence only a default instance corresponding to the empty + * string can be obtained via constructor invocation. * + * @see goog.html.TrustedResourceUrl#fromConstant * @constructor - * @param {olx.AttributionOptions} options Attribution options. + * @final * @struct - * @api stable + * @implements {goog.i18n.bidi.DirectionalString} + * @implements {goog.string.TypedString} */ -ol.Attribution = function(options) { - +goog.html.TrustedResourceUrl = function() { /** - * @private - * @type {string} + * The contained value of this TrustedResourceUrl. The field has a purposely + * ugly name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} */ - this.html_ = options.html; + this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = ''; /** + * A type marker used to implement additional run-time type checking. + * @see goog.html.TrustedResourceUrl#unwrap + * @const * @private - * @type {Object.<string, Array.<ol.TileRange>>} */ - this.tileRanges_ = options.tileRanges ? options.tileRanges : null; - + this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = + goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; }; /** - * Get the attribution markup. - * @return {string} The attribution HTML. - * @api stable + * @override + * @const */ -ol.Attribution.prototype.getHTML = function() { - return this.html_; -}; +goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true; /** - * @param {Object.<string, ol.TileRange>} tileRanges Tile ranges. - * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {!ol.proj.Projection} projection Projection. - * @return {boolean} Intersects any tile range. + * Returns this TrustedResourceUrl's value as a string. + * + * IMPORTANT: In code where it is security relevant that an object's type is + * indeed {@code TrustedResourceUrl}, use + * {@code goog.html.TrustedResourceUrl.unwrap} instead of this method. If in + * doubt, assume that it's security relevant. In particular, note that + * goog.html functions which return a goog.html type do not guarantee that + * the returned instance is of the right type. For example: + * + * <pre> + * var fakeSafeHtml = new String('fake'); + * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; + * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); + * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by + * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof + * // goog.html.SafeHtml. + * </pre> + * + * @see goog.html.TrustedResourceUrl#unwrap + * @override */ -ol.Attribution.prototype.intersectsAnyTileRange = - function(tileRanges, tileGrid, projection) { - if (!this.tileRanges_) { - return true; - } - var i, ii, tileRange, zKey; - for (zKey in tileRanges) { - if (!(zKey in this.tileRanges_)) { - continue; - } - tileRange = tileRanges[zKey]; - var testTileRange; - for (i = 0, ii = this.tileRanges_[zKey].length; i < ii; ++i) { - testTileRange = this.tileRanges_[zKey][i]; - if (testTileRange.intersects(tileRange)) { - return true; - } - var extentTileRange = tileGrid.getTileRangeForExtentAndZ( - projection.getExtent(), parseInt(zKey, 10)); - var width = extentTileRange.getWidth(); - if (tileRange.minX < extentTileRange.minX || - tileRange.maxX > extentTileRange.maxX) { - if (testTileRange.intersects(new ol.TileRange( - goog.math.modulo(tileRange.minX, width), - goog.math.modulo(tileRange.maxX, width), - tileRange.minY, tileRange.maxY))) { - return true; - } - if (tileRange.getWidth() > width && - testTileRange.intersects(extentTileRange)) { - return true; - } - } - } - } - return false; +goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() { + return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_; }; -goog.provide('ol.CanvasFunctionType'); - /** - * A function returning the canvas element (`{HTMLCanvasElement}`) - * used by the source as an image. The arguments passed to the function are: - * {@link ol.Extent} the image extent, `{number}` the image resolution, - * `{number}` the device pixel ratio, {@link ol.Size} the image size, and - * {@link ol.proj.Projection} the image projection. The canvas returned by - * this function is cached by the source. The this keyword inside the function - * references the {@link ol.source.ImageCanvas}. - * - * @typedef {function(this:ol.source.ImageCanvas, ol.Extent, number, - * number, ol.Size, ol.proj.Projection): HTMLCanvasElement} - * @api + * @override + * @const */ -ol.CanvasFunctionType; +goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString = + true; + /** - * An implementation of Google Maps' MVCArray. - * @see https://developers.google.com/maps/documentation/javascript/reference + * Returns this URLs directionality, which is always {@code LTR}. + * @override */ +goog.html.TrustedResourceUrl.prototype.getDirection = function() { + return goog.i18n.bidi.Dir.LTR; +}; -goog.provide('ol.Collection'); -goog.provide('ol.CollectionEvent'); -goog.provide('ol.CollectionEventType'); -goog.require('goog.array'); -goog.require('goog.events.Event'); -goog.require('ol.Object'); +if (goog.DEBUG) { + /** + * Returns a debug string-representation of this value. + * + * To obtain the actual string value wrapped in a TrustedResourceUrl, use + * {@code goog.html.TrustedResourceUrl.unwrap}. + * + * @see goog.html.TrustedResourceUrl#unwrap + * @override + */ + goog.html.TrustedResourceUrl.prototype.toString = function() { + return 'TrustedResourceUrl{' + + this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}'; + }; +} /** - * @enum {string} + * Performs a runtime check that the provided object is indeed a + * TrustedResourceUrl object, and returns its value. + * + * @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to + * extract from. + * @return {string} The trustedResourceUrl object's contained string, unless + * the run-time type check fails. In that case, {@code unwrap} returns an + * innocuous string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.CollectionEventType = { - /** - * Triggered when an item is added to the collection. - * @event ol.CollectionEvent#add - * @api stable - */ - ADD: 'add', - /** - * Triggered when an item is removed from the collection. - * @event ol.CollectionEvent#remove - * @api stable - */ - REMOVE: 'remove' -}; +goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) { + // Perform additional Run-time type-checking to ensure that + // trustedResourceUrl is indeed an instance of the expected type. This + // provides some additional protection against security bugs due to + // application code that disables type checks. + // Specifically, the following checks are performed: + // 1. The object is an instance of the expected type. + // 2. The object is not an instance of a subclass. + // 3. The object carries a type marker for the expected type. "Faking" an + // object requires a reference to the type marker, which has names intended + // to stand out in code reviews. + if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl && + trustedResourceUrl.constructor === goog.html.TrustedResourceUrl && + trustedResourceUrl + .TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === + goog.html.TrustedResourceUrl + .TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { + return trustedResourceUrl + .privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_; + } else { + goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' + + trustedResourceUrl + '\''); + return 'type_error:TrustedResourceUrl'; + } +}; /** - * @classdesc - * Events emitted by {@link ol.Collection} instances are instances of this - * type. + * Creates a TrustedResourceUrl object from a compile-time constant string. * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.CollectionEvent} - * @param {ol.CollectionEventType} type Type. - * @param {*=} opt_element Element. - * @param {Object=} opt_target Target. + * Compile-time constant strings are inherently program-controlled and hence + * trusted. + * + * @param {!goog.string.Const} url A compile-time-constant string from which to + * create a TrustedResourceUrl. + * @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object + * initialized to {@code url}. */ -ol.CollectionEvent = function(type, opt_element, opt_target) { +goog.html.TrustedResourceUrl.fromConstant = function(url) { + return goog.html.TrustedResourceUrl + .createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( + goog.string.Const.unwrap(url)); +}; - goog.base(this, type, opt_target); - /** - * The element that is added to or removed from the collection. - * @type {*} - * @api stable - */ - this.element = opt_element; +/** + * Type marker for the TrustedResourceUrl type, used to implement additional + * run-time type checking. + * @const {!Object} + * @private + */ +goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; + +/** + * Package-internal utility method to create TrustedResourceUrl instances. + * + * @param {string} url The string to initialize the TrustedResourceUrl object + * with. + * @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl + * object. + * @package + */ +goog.html.TrustedResourceUrl. + createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) { + var trustedResourceUrl = new goog.html.TrustedResourceUrl(); + trustedResourceUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = + url; + return trustedResourceUrl; }; -goog.inherits(ol.CollectionEvent, goog.events.Event); + +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @enum {string} + * @fileoverview The SafeHtml type and its builders. + * + * TODO(xtof): Link to document stating type contract. */ -ol.CollectionProperty = { - LENGTH: 'length' -}; + +goog.provide('goog.html.SafeHtml'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.TagName'); +goog.require('goog.dom.tags'); +goog.require('goog.html.SafeStyle'); +goog.require('goog.html.SafeStyleSheet'); +goog.require('goog.html.SafeUrl'); +goog.require('goog.html.TrustedResourceUrl'); +goog.require('goog.i18n.bidi.Dir'); +goog.require('goog.i18n.bidi.DirectionalString'); +goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.string.Const'); +goog.require('goog.string.TypedString'); /** - * @classdesc - * An expanded version of standard JS Array, adding convenience methods for - * manipulation. Add and remove changes to the Collection trigger a Collection - * event. Note that this does not cover changes to the objects _within_ the - * Collection; they trigger events on the appropriate object, not on the - * Collection as a whole. + * A string that is safe to use in HTML context in DOM APIs and HTML documents. + * + * A SafeHtml is a string-like object that carries the security type contract + * that its value as a string will not cause untrusted script execution when + * evaluated as HTML in a browser. + * + * Values of this type are guaranteed to be safe to use in HTML contexts, + * such as, assignment to the innerHTML DOM property, or interpolation into + * a HTML template in HTML PC_DATA context, in the sense that the use will not + * result in a Cross-Site-Scripting vulnerability. + * + * Instances of this type must be created via the factory methods + * ({@code goog.html.SafeHtml.create}, {@code goog.html.SafeHtml.htmlEscape}), + * etc and not by invoking its constructor. The constructor intentionally + * takes no parameters and the type is immutable; hence only a default instance + * corresponding to the empty string can be obtained via constructor invocation. * + * @see goog.html.SafeHtml#create + * @see goog.html.SafeHtml#htmlEscape * @constructor - * @extends {ol.Object} - * @fires ol.CollectionEvent - * @param {!Array.<T>=} opt_array Array. - * @template T - * @api stable + * @final + * @struct + * @implements {goog.i18n.bidi.DirectionalString} + * @implements {goog.string.TypedString} */ -ol.Collection = function(opt_array) { - - goog.base(this); +goog.html.SafeHtml = function() { + /** + * The contained value of this SafeHtml. The field has a purposely ugly + * name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} + */ + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ''; /** + * A type marker used to implement additional run-time type checking. + * @see goog.html.SafeHtml#unwrap + * @const * @private - * @type {!Array.<T>} */ - this.array_ = opt_array ? opt_array : []; - - this.updateLength_(); + this.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = + goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; + /** + * This SafeHtml's directionality, or null if unknown. + * @private {?goog.i18n.bidi.Dir} + */ + this.dir_ = null; }; -goog.inherits(ol.Collection, ol.Object); /** - * Remove all elements from the collection. - * @api stable + * @override + * @const */ -ol.Collection.prototype.clear = function() { - while (this.getLength() > 0) { - this.pop(); - } +goog.html.SafeHtml.prototype.implementsGoogI18nBidiDirectionalString = true; + + +/** @override */ +goog.html.SafeHtml.prototype.getDirection = function() { + return this.dir_; }; /** - * Add elements to the collection. This pushes each item in the provided array - * to the end of the collection. - * @param {!Array.<T>} arr Array. - * @return {ol.Collection.<T>} This collection. - * @api stable + * @override + * @const */ -ol.Collection.prototype.extend = function(arr) { - var i, ii; - for (i = 0, ii = arr.length; i < ii; ++i) { - this.push(arr[i]); - } - return this; -}; +goog.html.SafeHtml.prototype.implementsGoogStringTypedString = true; /** - * Iterate over each element, calling the provided callback. - * @param {function(this: S, T, number, Array.<T>): *} f The function to call - * for every element. This function takes 3 arguments (the element, the - * index and the array). The return value is ignored. - * @param {S=} opt_this The object to use as `this` in `f`. - * @template S - * @api stable + * Returns this SafeHtml's value a string. + * + * IMPORTANT: In code where it is security relevant that an object's type is + * indeed {@code SafeHtml}, use {@code goog.html.SafeHtml.unwrap} instead of + * this method. If in doubt, assume that it's security relevant. In particular, + * note that goog.html functions which return a goog.html type do not guarantee + * that the returned instance is of the right type. For example: + * + * <pre> + * var fakeSafeHtml = new String('fake'); + * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; + * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); + * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by + * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml + * // instanceof goog.html.SafeHtml. + * </pre> + * + * @see goog.html.SafeHtml#unwrap + * @override */ -ol.Collection.prototype.forEach = function(f, opt_this) { - this.array_.forEach(f, opt_this); +goog.html.SafeHtml.prototype.getTypedStringValue = function() { + return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_; }; +if (goog.DEBUG) { + /** + * Returns a debug string-representation of this value. + * + * To obtain the actual string value wrapped in a SafeHtml, use + * {@code goog.html.SafeHtml.unwrap}. + * + * @see goog.html.SafeHtml#unwrap + * @override + */ + goog.html.SafeHtml.prototype.toString = function() { + return 'SafeHtml{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ + + '}'; + }; +} + + /** - * Get a reference to the underlying Array object. Warning: if the array - * is mutated, no events will be dispatched by the collection, and the - * collection's "length" property won't be in sync with the actual length - * of the array. - * @return {!Array.<T>} Array. - * @api stable + * Performs a runtime check that the provided object is indeed a SafeHtml + * object, and returns its value. + * @param {!goog.html.SafeHtml} safeHtml The object to extract from. + * @return {string} The SafeHtml object's contained string, unless the run-time + * type check fails. In that case, {@code unwrap} returns an innocuous + * string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.Collection.prototype.getArray = function() { - return this.array_; +goog.html.SafeHtml.unwrap = function(safeHtml) { + // Perform additional run-time type-checking to ensure that safeHtml is indeed + // an instance of the expected type. This provides some additional protection + // against security bugs due to application code that disables type checks. + // Specifically, the following checks are performed: + // 1. The object is an instance of the expected type. + // 2. The object is not an instance of a subclass. + // 3. The object carries a type marker for the expected type. "Faking" an + // object requires a reference to the type marker, which has names intended + // to stand out in code reviews. + if (safeHtml instanceof goog.html.SafeHtml && + safeHtml.constructor === goog.html.SafeHtml && + safeHtml.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === + goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { + return safeHtml.privateDoNotAccessOrElseSafeHtmlWrappedValue_; + } else { + goog.asserts.fail('expected object of type SafeHtml, got \'' + + safeHtml + '\''); + return 'type_error:SafeHtml'; + } }; /** - * Get the element at the provided index. - * @param {number} index Index. - * @return {T} Element. - * @api stable + * Shorthand for union of types that can sensibly be converted to strings + * or might already be SafeHtml (as SafeHtml is a goog.string.TypedString). + * @private + * @typedef {string|number|boolean|!goog.string.TypedString| + * !goog.i18n.bidi.DirectionalString} */ -ol.Collection.prototype.item = function(index) { - return this.array_[index]; -}; +goog.html.SafeHtml.TextOrHtml_; /** - * Get the length of this collection. - * @return {number} The length of the array. - * @observable - * @api stable + * Returns HTML-escaped text as a SafeHtml object. + * + * If text is of a type that implements + * {@code goog.i18n.bidi.DirectionalString}, the directionality of the new + * {@code SafeHtml} object is set to {@code text}'s directionality, if known. + * Otherwise, the directionality of the resulting SafeHtml is unknown (i.e., + * {@code null}). + * + * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If + * the parameter is of type SafeHtml it is returned directly (no escaping + * is done). + * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. */ -ol.Collection.prototype.getLength = function() { - return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH)); +goog.html.SafeHtml.htmlEscape = function(textOrHtml) { + if (textOrHtml instanceof goog.html.SafeHtml) { + return textOrHtml; + } + var dir = null; + if (textOrHtml.implementsGoogI18nBidiDirectionalString) { + dir = textOrHtml.getDirection(); + } + var textAsString; + if (textOrHtml.implementsGoogStringTypedString) { + textAsString = textOrHtml.getTypedStringValue(); + } else { + textAsString = String(textOrHtml); + } + return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + goog.string.htmlEscape(textAsString), dir); }; /** - * Insert an element at the provided index. - * @param {number} index Index. - * @param {T} elem Element. - * @api stable + * Returns HTML-escaped text as a SafeHtml object, with newlines changed to + * <br>. + * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If + * the parameter is of type SafeHtml it is returned directly (no escaping + * is done). + * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. */ -ol.Collection.prototype.insertAt = function(index, elem) { - goog.array.insertAt(this.array_, elem, index); - this.updateLength_(); - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); +goog.html.SafeHtml.htmlEscapePreservingNewlines = function(textOrHtml) { + if (textOrHtml instanceof goog.html.SafeHtml) { + return textOrHtml; + } + var html = goog.html.SafeHtml.htmlEscape(textOrHtml); + return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + goog.string.newLineToBr(goog.html.SafeHtml.unwrap(html)), + html.getDirection()); }; /** - * Remove the last element of the collection and return it. - * Return `undefined` if the collection is empty. - * @return {T|undefined} Element. - * @api stable + * Returns HTML-escaped text as a SafeHtml object, with newlines changed to + * <br> and escaping whitespace to preserve spatial formatting. Character + * entity #160 is used to make it safer for XML. + * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If + * the parameter is of type SafeHtml it is returned directly (no escaping + * is done). + * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. */ -ol.Collection.prototype.pop = function() { - return this.removeAt(this.getLength() - 1); +goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces = function( + textOrHtml) { + if (textOrHtml instanceof goog.html.SafeHtml) { + return textOrHtml; + } + var html = goog.html.SafeHtml.htmlEscape(textOrHtml); + return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + goog.string.whitespaceEscape(goog.html.SafeHtml.unwrap(html)), + html.getDirection()); }; /** - * Insert the provided element at the end of the collection. - * @param {T} elem Element. - * @return {number} Length. - * @api stable + * Coerces an arbitrary object into a SafeHtml object. + * + * If {@code textOrHtml} is already of type {@code goog.html.SafeHtml}, the same + * object is returned. Otherwise, {@code textOrHtml} is coerced to string, and + * HTML-escaped. If {@code textOrHtml} is of a type that implements + * {@code goog.i18n.bidi.DirectionalString}, its directionality, if known, is + * preserved. + * + * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text or SafeHtml to + * coerce. + * @return {!goog.html.SafeHtml} The resulting SafeHtml object. + * @deprecated Use goog.html.SafeHtml.htmlEscape. */ -ol.Collection.prototype.push = function(elem) { - var n = this.array_.length; - this.insertAt(n, elem); - return n; -}; +goog.html.SafeHtml.from = goog.html.SafeHtml.htmlEscape; /** - * Remove the first occurrence of an element from the collection. - * @param {T} elem Element. - * @return {T|undefined} The removed element or undefined if none found. - * @api stable + * @const + * @private */ -ol.Collection.prototype.remove = function(elem) { - var arr = this.array_; - var i, ii; - for (i = 0, ii = arr.length; i < ii; ++i) { - if (arr[i] === elem) { - return this.removeAt(i); - } - } - return undefined; -}; +goog.html.SafeHtml.VALID_NAMES_IN_TAG_ = /^[a-zA-Z0-9-]+$/; /** - * Remove the element at the provided index and return it. - * Return `undefined` if the collection does not contain this index. - * @param {number} index Index. - * @return {T|undefined} Value. - * @api stable + * Set of attributes containing URL as defined at + * http://www.w3.org/TR/html5/index.html#attributes-1. + * @private @const {!Object<string,boolean>} */ -ol.Collection.prototype.removeAt = function(index) { - var prev = this.array_[index]; - goog.array.removeAt(this.array_, index); - this.updateLength_(); - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); - return prev; -}; +goog.html.SafeHtml.URL_ATTRIBUTES_ = goog.object.createSet('action', 'cite', + 'data', 'formaction', 'href', 'manifest', 'poster', 'src'); /** - * Set the element at the provided index. - * @param {number} index Index. - * @param {T} elem Element. - * @api stable + * Tags which are unsupported via create(). They might be supported via a + * tag-specific create method. These are tags which might require a + * TrustedResourceUrl in one of their attributes or a restricted type for + * their content. + * @private @const {!Object<string,boolean>} */ -ol.Collection.prototype.setAt = function(index, elem) { - var n = this.getLength(); - if (index < n) { - var prev = this.array_[index]; - this.array_[index] = elem; - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); - this.dispatchEvent( - new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); - } else { - var j; - for (j = n; j < index; ++j) { - this.insertAt(j, undefined); - } - this.insertAt(index, elem); - } -}; +goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_ = goog.object.createSet( + goog.dom.TagName.EMBED, goog.dom.TagName.IFRAME, goog.dom.TagName.LINK, + goog.dom.TagName.OBJECT, goog.dom.TagName.SCRIPT, goog.dom.TagName.STYLE, + goog.dom.TagName.TEMPLATE); /** + * @typedef {string|number|goog.string.TypedString| + * goog.html.SafeStyle.PropertyMap} * @private */ -ol.Collection.prototype.updateLength_ = function() { - this.set(ol.CollectionProperty.LENGTH, this.array_.length); -}; +goog.html.SafeHtml.AttributeValue_; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Names of standard colors with their associated hex values. + * Creates a SafeHtml content consisting of a tag with optional attributes and + * optional content. + * + * For convenience tag names and attribute names are accepted as regular + * strings, instead of goog.string.Const. Nevertheless, you should not pass + * user-controlled values to these parameters. Note that these parameters are + * syntactically validated at runtime, and invalid values will result in + * an exception. + * + * Example usage: + * + * goog.html.SafeHtml.create('br'); + * goog.html.SafeHtml.create('div', {'class': 'a'}); + * goog.html.SafeHtml.create('p', {}, 'a'); + * goog.html.SafeHtml.create('p', {}, goog.html.SafeHtml.create('br')); + * + * goog.html.SafeHtml.create('span', { + * 'style': {'margin': '0'} + * }); + * + * To guarantee SafeHtml's type contract is upheld there are restrictions on + * attribute values and tag names. + * + * - For attributes which contain script code (on*), a goog.string.Const is + * required. + * - For attributes which contain style (style), a goog.html.SafeStyle or a + * goog.html.SafeStyle.PropertyMap is required. + * - For attributes which are interpreted as URLs (e.g. src, href) a + * goog.html.SafeUrl, goog.string.Const or string is required. If a string + * is passed, it will be sanitized with SafeUrl.sanitize(). + * - For tags which can load code, more specific goog.html.SafeHtml.create*() + * functions must be used. Tags which can load code and are not supported by + * this function are embed, iframe, link, object, script, style, and template. + * + * @param {string} tagName The name of the tag. Only tag names consisting of + * [a-zA-Z0-9-] are allowed. Tag names documented above are disallowed. + * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} + * opt_attributes Mapping from attribute names to their values. Only + * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or + * undefined causes the attribute to be omitted. + * @param {!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to + * HTML-escape and put inside the tag. This must be empty for void tags + * like <br>. Array elements are concatenated. + * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. + * @throws {Error} If invalid tag name, attribute name, or attribute value is + * provided. + * @throws {goog.asserts.AssertionError} If content for void tag is provided. */ - -goog.provide('goog.color.names'); +goog.html.SafeHtml.create = function(tagName, opt_attributes, opt_content) { + if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(tagName)) { + throw Error('Invalid tag name <' + tagName + '>.'); + } + if (tagName.toUpperCase() in goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_) { + throw Error('Tag name <' + tagName + '> is not allowed for SafeHtml.'); + } + return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( + tagName, opt_attributes, opt_content); +}; /** - * A map that contains a lot of colors that are recognised by various browsers. - * This list is way larger than the minimal one dictated by W3C. - * The keys of this map are the lowercase "readable" names of the colors, while - * the values are the "hex" values. + * Creates a SafeHtml representing an iframe tag. * - * @type {!Object<string, string>} + * By default the sandbox attribute is set to an empty value, which is the most + * secure option, as it confers the iframe the least privileges. If this + * is too restrictive then granting individual privileges is the preferable + * option. Unsetting the attribute entirely is the least secure option and + * should never be done unless it's stricly necessary. + * + * @param {goog.html.TrustedResourceUrl=} opt_src The value of the src + * attribute. If null or undefined src will not be set. + * @param {goog.html.SafeHtml=} opt_srcdoc The value of the srcdoc attribute. + * If null or undefined srcdoc will not be set. + * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} + * opt_attributes Mapping from attribute names to their values. Only + * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or + * undefined causes the attribute to be omitted. + * @param {!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to + * HTML-escape and put inside the tag. Array elements are concatenated. + * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. + * @throws {Error} If invalid tag name, attribute name, or attribute value is + * provided. If opt_attributes contains the src or srcdoc attributes. */ -goog.color.names = { - 'aliceblue': '#f0f8ff', - 'antiquewhite': '#faebd7', - 'aqua': '#00ffff', - 'aquamarine': '#7fffd4', - 'azure': '#f0ffff', - 'beige': '#f5f5dc', - 'bisque': '#ffe4c4', - 'black': '#000000', - 'blanchedalmond': '#ffebcd', - 'blue': '#0000ff', - 'blueviolet': '#8a2be2', - 'brown': '#a52a2a', - 'burlywood': '#deb887', - 'cadetblue': '#5f9ea0', - 'chartreuse': '#7fff00', - 'chocolate': '#d2691e', - 'coral': '#ff7f50', - 'cornflowerblue': '#6495ed', - 'cornsilk': '#fff8dc', - 'crimson': '#dc143c', - 'cyan': '#00ffff', - 'darkblue': '#00008b', - 'darkcyan': '#008b8b', - 'darkgoldenrod': '#b8860b', - 'darkgray': '#a9a9a9', - 'darkgreen': '#006400', - 'darkgrey': '#a9a9a9', - 'darkkhaki': '#bdb76b', - 'darkmagenta': '#8b008b', - 'darkolivegreen': '#556b2f', - 'darkorange': '#ff8c00', - 'darkorchid': '#9932cc', - 'darkred': '#8b0000', - 'darksalmon': '#e9967a', - 'darkseagreen': '#8fbc8f', - 'darkslateblue': '#483d8b', - 'darkslategray': '#2f4f4f', - 'darkslategrey': '#2f4f4f', - 'darkturquoise': '#00ced1', - 'darkviolet': '#9400d3', - 'deeppink': '#ff1493', - 'deepskyblue': '#00bfff', - 'dimgray': '#696969', - 'dimgrey': '#696969', - 'dodgerblue': '#1e90ff', - 'firebrick': '#b22222', - 'floralwhite': '#fffaf0', - 'forestgreen': '#228b22', - 'fuchsia': '#ff00ff', - 'gainsboro': '#dcdcdc', - 'ghostwhite': '#f8f8ff', - 'gold': '#ffd700', - 'goldenrod': '#daa520', - 'gray': '#808080', - 'green': '#008000', - 'greenyellow': '#adff2f', - 'grey': '#808080', - 'honeydew': '#f0fff0', - 'hotpink': '#ff69b4', - 'indianred': '#cd5c5c', - 'indigo': '#4b0082', - 'ivory': '#fffff0', - 'khaki': '#f0e68c', - 'lavender': '#e6e6fa', - 'lavenderblush': '#fff0f5', - 'lawngreen': '#7cfc00', - 'lemonchiffon': '#fffacd', - 'lightblue': '#add8e6', - 'lightcoral': '#f08080', - 'lightcyan': '#e0ffff', - 'lightgoldenrodyellow': '#fafad2', - 'lightgray': '#d3d3d3', - 'lightgreen': '#90ee90', - 'lightgrey': '#d3d3d3', - 'lightpink': '#ffb6c1', - 'lightsalmon': '#ffa07a', - 'lightseagreen': '#20b2aa', - 'lightskyblue': '#87cefa', - 'lightslategray': '#778899', - 'lightslategrey': '#778899', - 'lightsteelblue': '#b0c4de', - 'lightyellow': '#ffffe0', - 'lime': '#00ff00', - 'limegreen': '#32cd32', - 'linen': '#faf0e6', - 'magenta': '#ff00ff', - 'maroon': '#800000', - 'mediumaquamarine': '#66cdaa', - 'mediumblue': '#0000cd', - 'mediumorchid': '#ba55d3', - 'mediumpurple': '#9370db', - 'mediumseagreen': '#3cb371', - 'mediumslateblue': '#7b68ee', - 'mediumspringgreen': '#00fa9a', - 'mediumturquoise': '#48d1cc', - 'mediumvioletred': '#c71585', - 'midnightblue': '#191970', - 'mintcream': '#f5fffa', - 'mistyrose': '#ffe4e1', - 'moccasin': '#ffe4b5', - 'navajowhite': '#ffdead', - 'navy': '#000080', - 'oldlace': '#fdf5e6', - 'olive': '#808000', - 'olivedrab': '#6b8e23', - 'orange': '#ffa500', - 'orangered': '#ff4500', - 'orchid': '#da70d6', - 'palegoldenrod': '#eee8aa', - 'palegreen': '#98fb98', - 'paleturquoise': '#afeeee', - 'palevioletred': '#db7093', - 'papayawhip': '#ffefd5', - 'peachpuff': '#ffdab9', - 'peru': '#cd853f', - 'pink': '#ffc0cb', - 'plum': '#dda0dd', - 'powderblue': '#b0e0e6', - 'purple': '#800080', - 'red': '#ff0000', - 'rosybrown': '#bc8f8f', - 'royalblue': '#4169e1', - 'saddlebrown': '#8b4513', - 'salmon': '#fa8072', - 'sandybrown': '#f4a460', - 'seagreen': '#2e8b57', - 'seashell': '#fff5ee', - 'sienna': '#a0522d', - 'silver': '#c0c0c0', - 'skyblue': '#87ceeb', - 'slateblue': '#6a5acd', - 'slategray': '#708090', - 'slategrey': '#708090', - 'snow': '#fffafa', - 'springgreen': '#00ff7f', - 'steelblue': '#4682b4', - 'tan': '#d2b48c', - 'teal': '#008080', - 'thistle': '#d8bfd8', - 'tomato': '#ff6347', - 'turquoise': '#40e0d0', - 'violet': '#ee82ee', - 'wheat': '#f5deb3', - 'white': '#ffffff', - 'whitesmoke': '#f5f5f5', - 'yellow': '#ffff00', - 'yellowgreen': '#9acd32' +goog.html.SafeHtml.createIframe = function( + opt_src, opt_srcdoc, opt_attributes, opt_content) { + var fixedAttributes = {}; + fixedAttributes['src'] = opt_src || null; + fixedAttributes['srcdoc'] = opt_srcdoc || null; + var defaultAttributes = {'sandbox': ''}; + var attributes = goog.html.SafeHtml.combineAttributes( + fixedAttributes, defaultAttributes, opt_attributes); + return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( + 'iframe', attributes, opt_content); }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utilities related to color and color conversion. + * Creates a SafeHtml representing a style tag. The type attribute is set + * to "text/css". + * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>} + * styleSheet Content to put inside the tag. Array elements are + * concatenated. + * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} + * opt_attributes Mapping from attribute names to their values. Only + * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or + * undefined causes the attribute to be omitted. + * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. + * @throws {Error} If invalid attribute name or attribute value is provided. If + * opt_attributes contains the type attribute. */ +goog.html.SafeHtml.createStyle = function(styleSheet, opt_attributes) { + var fixedAttributes = {'type': 'text/css'}; + var defaultAttributes = {}; + var attributes = goog.html.SafeHtml.combineAttributes( + fixedAttributes, defaultAttributes, opt_attributes); -goog.provide('goog.color'); -goog.provide('goog.color.Hsl'); -goog.provide('goog.color.Hsv'); -goog.provide('goog.color.Rgb'); - -goog.require('goog.color.names'); -goog.require('goog.math'); + var content = ''; + styleSheet = goog.array.concat(styleSheet); + for (var i = 0; i < styleSheet.length; i++) { + content += goog.html.SafeStyleSheet.unwrap(styleSheet[i]); + } + // Convert to SafeHtml so that it's not HTML-escaped. + var htmlContent = goog.html.SafeHtml + .createSafeHtmlSecurityPrivateDoNotAccessOrElse( + content, goog.i18n.bidi.Dir.NEUTRAL); + return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( + 'style', attributes, htmlContent); +}; /** - * RGB color representation. An array containing three elements [r, g, b], - * each an integer in [0, 255], representing the red, green, and blue components - * of the color respectively. - * @typedef {Array<number>} + * @param {string} tagName The tag name. + * @param {string} name The attribute name. + * @param {!goog.html.SafeHtml.AttributeValue_} value The attribute value. + * @return {string} A "name=value" string. + * @throws {Error} If attribute value is unsafe for the given tag and attribute. + * @private */ -goog.color.Rgb; +goog.html.SafeHtml.getAttrNameAndValue_ = function(tagName, name, value) { + // If it's goog.string.Const, allow any valid attribute name. + if (value instanceof goog.string.Const) { + value = goog.string.Const.unwrap(value); + } else if (name.toLowerCase() == 'style') { + value = goog.html.SafeHtml.getStyleValue_(value); + } else if (/^on/i.test(name)) { + // TODO(jakubvrana): Disallow more attributes with a special meaning. + throw Error('Attribute "' + name + + '" requires goog.string.Const value, "' + value + '" given.'); + // URL attributes handled differently accroding to tag. + } else if (name.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) { + if (value instanceof goog.html.TrustedResourceUrl) { + value = goog.html.TrustedResourceUrl.unwrap(value); + } else if (value instanceof goog.html.SafeUrl) { + value = goog.html.SafeUrl.unwrap(value); + } else if (goog.isString(value)) { + value = goog.html.SafeUrl.sanitize(value).getTypedStringValue(); + } else { + throw Error('Attribute "' + name + '" on tag "' + tagName + + '" requires goog.html.SafeUrl, goog.string.Const, or string,' + + ' value "' + value + '" given.'); + } + } + + // Accept SafeUrl, TrustedResourceUrl, etc. for attributes which only require + // HTML-escaping. + if (value.implementsGoogStringTypedString) { + // Ok to call getTypedStringValue() since there's no reliance on the type + // contract for security here. + value = value.getTypedStringValue(); + } + + goog.asserts.assert(goog.isString(value) || goog.isNumber(value), + 'String or number value expected, got ' + + (typeof value) + ' with value: ' + value); + return name + '="' + goog.string.htmlEscape(String(value)) + '"'; +}; /** - * HSV color representation. An array containing three elements [h, s, v]: - * h (hue) must be an integer in [0, 360], cyclic. - * s (saturation) must be a number in [0, 1]. - * v (value/brightness) must be an integer in [0, 255]. - * @typedef {Array<number>} + * Gets value allowed in "style" attribute. + * @param {goog.html.SafeHtml.AttributeValue_} value It could be SafeStyle or a + * map which will be passed to goog.html.SafeStyle.create. + * @return {string} Unwrapped value. + * @throws {Error} If string value is given. + * @private */ -goog.color.Hsv; +goog.html.SafeHtml.getStyleValue_ = function(value) { + if (!goog.isObject(value)) { + throw Error('The "style" attribute requires goog.html.SafeStyle or map ' + + 'of style properties, ' + (typeof value) + ' given: ' + value); + } + if (!(value instanceof goog.html.SafeStyle)) { + // Process the property bag into a style object. + value = goog.html.SafeStyle.create(value); + } + return goog.html.SafeStyle.unwrap(value); +}; /** - * HSL color representation. An array containing three elements [h, s, l]: - * h (hue) must be an integer in [0, 360], cyclic. - * s (saturation) must be a number in [0, 1]. - * l (lightness) must be a number in [0, 1]. - * @typedef {Array<number>} + * Creates a SafeHtml content with known directionality consisting of a tag with + * optional attributes and optional content. + * @param {!goog.i18n.bidi.Dir} dir Directionality. + * @param {string} tagName + * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes + * @param {!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content + * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. */ -goog.color.Hsl; +goog.html.SafeHtml.createWithDir = function(dir, tagName, opt_attributes, + opt_content) { + var html = goog.html.SafeHtml.create(tagName, opt_attributes, opt_content); + html.dir_ = dir; + return html; +}; /** - * Parses a color out of a string. - * @param {string} str Color in some format. - * @return {{hex: string, type: string}} 'hex' is a string containing a hex - * representation of the color, 'type' is a string containing the type - * of color format passed in ('hex', 'rgb', 'named'). + * Creates a new SafeHtml object by concatenating values. + * @param {...(!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Values to concatenate. + * @return {!goog.html.SafeHtml} */ -goog.color.parse = function(str) { - var result = {}; - str = String(str); +goog.html.SafeHtml.concat = function(var_args) { + var dir = goog.i18n.bidi.Dir.NEUTRAL; + var content = ''; - var maybeHex = goog.color.prependHashIfNecessaryHelper(str); - if (goog.color.isValidHexColor_(maybeHex)) { - result.hex = goog.color.normalizeHex(maybeHex); - result.type = 'hex'; - return result; - } else { - var rgb = goog.color.isValidRgbColor_(str); - if (rgb.length) { - result.hex = goog.color.rgbArrayToHex(rgb); - result.type = 'rgb'; - return result; - } else if (goog.color.names) { - var hex = goog.color.names[str.toLowerCase()]; - if (hex) { - result.hex = hex; - result.type = 'named'; - return result; + /** + * @param {!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>} argument + */ + var addArgument = function(argument) { + if (goog.isArray(argument)) { + goog.array.forEach(argument, addArgument); + } else { + var html = goog.html.SafeHtml.htmlEscape(argument); + content += goog.html.SafeHtml.unwrap(html); + var htmlDir = html.getDirection(); + if (dir == goog.i18n.bidi.Dir.NEUTRAL) { + dir = htmlDir; + } else if (htmlDir != goog.i18n.bidi.Dir.NEUTRAL && dir != htmlDir) { + dir = null; } } - } - throw Error(str + ' is not a valid color string'); + }; + + goog.array.forEach(arguments, addArgument); + return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + content, dir); }; /** - * Determines if the given string can be parsed as a color. - * {@see goog.color.parse}. - * @param {string} str Potential color string. - * @return {boolean} True if str is in a format that can be parsed to a color. + * Creates a new SafeHtml object with known directionality by concatenating the + * values. + * @param {!goog.i18n.bidi.Dir} dir Directionality. + * @param {...(!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Elements of array + * arguments would be processed recursively. + * @return {!goog.html.SafeHtml} */ -goog.color.isValidColor = function(str) { - var maybeHex = goog.color.prependHashIfNecessaryHelper(str); - return !!(goog.color.isValidHexColor_(maybeHex) || - goog.color.isValidRgbColor_(str).length || - goog.color.names && goog.color.names[str.toLowerCase()]); +goog.html.SafeHtml.concatWithDir = function(dir, var_args) { + var html = goog.html.SafeHtml.concat(goog.array.slice(arguments, 1)); + html.dir_ = dir; + return html; }; /** - * Parses red, green, blue components out of a valid rgb color string. - * Throws Error if the color string is invalid. - * @param {string} str RGB representation of a color. - * {@see goog.color.isValidRgbColor_}. - * @return {!goog.color.Rgb} rgb representation of the color. + * Type marker for the SafeHtml type, used to implement additional run-time + * type checking. + * @const {!Object} + * @private */ -goog.color.parseRgb = function(str) { - var rgb = goog.color.isValidRgbColor_(str); - if (!rgb.length) { - throw Error(str + ' is not a valid RGB color'); - } - return rgb; -}; +goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; /** - * Converts a hex representation of a color to RGB. - * @param {string} hexColor Color to convert. - * @return {string} string of the form 'rgb(R,G,B)' which can be used in - * styles. + * Package-internal utility method to create SafeHtml instances. + * + * @param {string} html The string to initialize the SafeHtml object with. + * @param {?goog.i18n.bidi.Dir} dir The directionality of the SafeHtml to be + * constructed, or null if unknown. + * @return {!goog.html.SafeHtml} The initialized SafeHtml object. + * @package */ -goog.color.hexToRgbStyle = function(hexColor) { - return goog.color.rgbStyle_(goog.color.hexToRgb(hexColor)); +goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse = function( + html, dir) { + return new goog.html.SafeHtml().initSecurityPrivateDoNotAccessOrElse_( + html, dir); }; /** - * Regular expression for extracting the digits in a hex color triplet. - * @type {RegExp} + * Called from createSafeHtmlSecurityPrivateDoNotAccessOrElse(). This + * method exists only so that the compiler can dead code eliminate static + * fields (like EMPTY) when they're not accessed. + * @param {string} html + * @param {?goog.i18n.bidi.Dir} dir + * @return {!goog.html.SafeHtml} * @private */ -goog.color.hexTripletRe_ = /#(.)(.)(.)/; - - -/** - * Normalize an hex representation of a color - * @param {string} hexColor an hex color string. - * @return {string} hex color in the format '#rrggbb' with all lowercase - * literals. - */ -goog.color.normalizeHex = function(hexColor) { - if (!goog.color.isValidHexColor_(hexColor)) { - throw Error("'" + hexColor + "' is not a valid hex color"); - } - if (hexColor.length == 4) { // of the form #RGB - hexColor = hexColor.replace(goog.color.hexTripletRe_, '#$1$1$2$2$3$3'); - } - return hexColor.toLowerCase(); +goog.html.SafeHtml.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( + html, dir) { + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = html; + this.dir_ = dir; + return this; }; /** - * Converts a hex representation of a color to RGB. - * @param {string} hexColor Color to convert. - * @return {!goog.color.Rgb} rgb representation of the color. + * Like create() but does not restrict which tags can be constructed. + * + * @param {string} tagName Tag name. Set or validated by caller. + * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes + * @param {(!goog.html.SafeHtml.TextOrHtml_| + * !Array<!goog.html.SafeHtml.TextOrHtml_>)=} opt_content + * @return {!goog.html.SafeHtml} + * @throws {Error} If invalid or unsafe attribute name or value is provided. + * @throws {goog.asserts.AssertionError} If content for void tag is provided. + * @package */ -goog.color.hexToRgb = function(hexColor) { - hexColor = goog.color.normalizeHex(hexColor); - var r = parseInt(hexColor.substr(1, 2), 16); - var g = parseInt(hexColor.substr(3, 2), 16); - var b = parseInt(hexColor.substr(5, 2), 16); +goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse = + function(tagName, opt_attributes, opt_content) { + var dir = null; + var result = '<' + tagName; - return [r, g, b]; -}; + if (opt_attributes) { + for (var name in opt_attributes) { + if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(name)) { + throw Error('Invalid attribute name "' + name + '".'); + } + var value = opt_attributes[name]; + if (!goog.isDefAndNotNull(value)) { + continue; + } + result += ' ' + + goog.html.SafeHtml.getAttrNameAndValue_(tagName, name, value); + } + } + var content = opt_content; + if (!goog.isDefAndNotNull(content)) { + content = []; + } else if (!goog.isArray(content)) { + content = [content]; + } -/** - * Converts a color from RGB to hex representation. - * @param {number} r Amount of red, int between 0 and 255. - * @param {number} g Amount of green, int between 0 and 255. - * @param {number} b Amount of blue, int between 0 and 255. - * @return {string} hex representation of the color. - */ -goog.color.rgbToHex = function(r, g, b) { - r = Number(r); - g = Number(g); - b = Number(b); - if (isNaN(r) || r < 0 || r > 255 || - isNaN(g) || g < 0 || g > 255 || - isNaN(b) || b < 0 || b > 255) { - throw Error('"(' + r + ',' + g + ',' + b + '") is not a valid RGB color'); + if (goog.dom.tags.isVoidTag(tagName.toLowerCase())) { + goog.asserts.assert(!content.length, + 'Void tag <' + tagName + '> does not allow content.'); + result += '>'; + } else { + var html = goog.html.SafeHtml.concat(content); + result += '>' + goog.html.SafeHtml.unwrap(html) + '</' + tagName + '>'; + dir = html.getDirection(); } - var hexR = goog.color.prependZeroIfNecessaryHelper(r.toString(16)); - var hexG = goog.color.prependZeroIfNecessaryHelper(g.toString(16)); - var hexB = goog.color.prependZeroIfNecessaryHelper(b.toString(16)); - return '#' + hexR + hexG + hexB; -}; + var dirAttribute = opt_attributes && opt_attributes['dir']; + if (dirAttribute) { + if (/^(ltr|rtl|auto)$/i.test(dirAttribute)) { + // If the tag has the "dir" attribute specified then its direction is + // neutral because it can be safely used in any context. + dir = goog.i18n.bidi.Dir.NEUTRAL; + } else { + dir = null; + } + } -/** - * Converts a color from RGB to hex representation. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {string} hex representation of the color. - */ -goog.color.rgbArrayToHex = function(rgb) { - return goog.color.rgbToHex(rgb[0], rgb[1], rgb[2]); + return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + result, dir); }; /** - * Converts a color from RGB color space to HSL color space. - * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}. - * @param {number} r Value of red, in [0, 255]. - * @param {number} g Value of green, in [0, 255]. - * @param {number} b Value of blue, in [0, 255]. - * @return {!goog.color.Hsl} hsl representation of the color. + * @param {!Object<string, string>} fixedAttributes + * @param {!Object<string, string>} defaultAttributes + * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} + * opt_attributes Optional attributes passed to create*(). + * @return {!Object<string, goog.html.SafeHtml.AttributeValue_>} + * @throws {Error} If opt_attributes contains an attribute with the same name + * as an attribute in fixedAttributes. + * @package */ -goog.color.rgbToHsl = function(r, g, b) { - // First must normalize r, g, b to be between 0 and 1. - var normR = r / 255; - var normG = g / 255; - var normB = b / 255; - var max = Math.max(normR, normG, normB); - var min = Math.min(normR, normG, normB); - var h = 0; - var s = 0; +goog.html.SafeHtml.combineAttributes = function( + fixedAttributes, defaultAttributes, opt_attributes) { + var combinedAttributes = {}; + var name; - // Luminosity is the average of the max and min rgb color intensities. - var l = 0.5 * (max + min); + for (name in fixedAttributes) { + goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case'); + combinedAttributes[name] = fixedAttributes[name]; + } + for (name in defaultAttributes) { + goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case'); + combinedAttributes[name] = defaultAttributes[name]; + } - // The hue and saturation are dependent on which color intensity is the max. - // If max and min are equal, the color is gray and h and s should be 0. - if (max != min) { - if (max == normR) { - h = 60 * (normG - normB) / (max - min); - } else if (max == normG) { - h = 60 * (normB - normR) / (max - min) + 120; - } else if (max == normB) { - h = 60 * (normR - normG) / (max - min) + 240; + for (name in opt_attributes) { + var nameLower = name.toLowerCase(); + if (nameLower in fixedAttributes) { + throw Error('Cannot override "' + nameLower + '" attribute, got "' + + name + '" with value "' + opt_attributes[name] + '"'); } - - if (0 < l && l <= 0.5) { - s = (max - min) / (2 * l); - } else { - s = (max - min) / (2 - 2 * l); + if (nameLower in defaultAttributes) { + delete combinedAttributes[nameLower]; } + combinedAttributes[name] = opt_attributes[name]; } - // Make sure the hue falls between 0 and 360. - return [Math.round(h + 360) % 360, s, l]; + return combinedAttributes; }; /** - * Converts a color from RGB color space to HSL color space. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {!goog.color.Hsl} hsl representation of the color. + * A SafeHtml instance corresponding to the HTML doctype: "<!DOCTYPE html>". + * @const {!goog.html.SafeHtml} */ -goog.color.rgbArrayToHsl = function(rgb) { - return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]); -}; +goog.html.SafeHtml.DOCTYPE_HTML = + goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + '<!DOCTYPE html>', goog.i18n.bidi.Dir.NEUTRAL); /** - * Helper for hslToRgb. - * @param {number} v1 Helper variable 1. - * @param {number} v2 Helper variable 2. - * @param {number} vH Helper variable 3. - * @return {number} Appropriate RGB value, given the above. - * @private + * A SafeHtml instance corresponding to the empty string. + * @const {!goog.html.SafeHtml} */ -goog.color.hueToRgb_ = function(v1, v2, vH) { - if (vH < 0) { - vH += 1; - } else if (vH > 1) { - vH -= 1; - } - if ((6 * vH) < 1) { - return (v1 + (v2 - v1) * 6 * vH); - } else if (2 * vH < 1) { - return v2; - } else if (3 * vH < 2) { - return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6); - } - return v1; -}; +goog.html.SafeHtml.EMPTY = + goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + '', goog.i18n.bidi.Dir.NEUTRAL); +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Converts a color from HSL color space to RGB color space. - * Modified from {@link http://www.easyrgb.com/math.html} - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} l Luminosity, in [0, 1]. - * @return {!goog.color.Rgb} rgb representation of the color. + * @fileoverview Type-safe wrappers for unsafe DOM APIs. + * + * This file provides type-safe wrappers for DOM APIs that can result in + * cross-site scripting (XSS) vulnerabilities, if the API is supplied with + * untrusted (attacker-controlled) input. Instead of plain strings, the type + * safe wrappers consume values of types from the goog.html package whose + * contract promises that values are safe to use in the corresponding context. + * + * Hence, a program that exclusively uses the wrappers in this file (i.e., whose + * only reference to security-sensitive raw DOM APIs are in this file) is + * guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo + * correctness of code that produces values of the respective goog.html types, + * and absent code that violates type safety). + * + * For example, assigning to an element's .innerHTML property a string that is + * derived (even partially) from untrusted input typically results in an XSS + * vulnerability. The type-safe wrapper goog.html.setInnerHtml consumes a value + * of type goog.html.SafeHtml, whose contract states that using its values in a + * HTML context will not result in XSS. Hence a program that is free of direct + * assignments to any element's innerHTML property (with the exception of the + * assignment to .innerHTML in this file) is guaranteed to be free of XSS due to + * assignment of untrusted strings to the innerHTML property. */ -goog.color.hslToRgb = function(h, s, l) { - var r = 0; - var g = 0; - var b = 0; - var normH = h / 360; // normalize h to fall in [0, 1] - if (s == 0) { - r = g = b = l * 255; - } else { - var temp1 = 0; - var temp2 = 0; - if (l < 0.5) { - temp2 = l * (1 + s); - } else { - temp2 = l + s - (s * l); - } - temp1 = 2 * l - temp2; - r = 255 * goog.color.hueToRgb_(temp1, temp2, normH + (1 / 3)); - g = 255 * goog.color.hueToRgb_(temp1, temp2, normH); - b = 255 * goog.color.hueToRgb_(temp1, temp2, normH - (1 / 3)); - } +goog.provide('goog.dom.safe'); +goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition'); - return [Math.round(r), Math.round(g), Math.round(b)]; -}; +goog.require('goog.asserts'); +goog.require('goog.html.SafeHtml'); +goog.require('goog.html.SafeUrl'); +goog.require('goog.html.TrustedResourceUrl'); +goog.require('goog.string'); +goog.require('goog.string.Const'); -/** - * Converts a color from HSL color space to RGB color space. - * @param {goog.color.Hsl} hsl hsl representation of the color. - * @return {!goog.color.Rgb} rgb representation of the color. - */ -goog.color.hslArrayToRgb = function(hsl) { - return goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]); +/** @enum {string} */ +goog.dom.safe.InsertAdjacentHtmlPosition = { + AFTERBEGIN: 'afterbegin', + AFTEREND: 'afterend', + BEFOREBEGIN: 'beforebegin', + BEFOREEND: 'beforeend' }; /** - * Helper for isValidHexColor_. - * @type {RegExp} - * @private + * Inserts known-safe HTML into a Node, at the specified position. + * @param {!Node} node The node on which to call insertAdjacentHTML. + * @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where + * to insert the HTML. + * @param {!goog.html.SafeHtml} html The known-safe HTML to insert. */ -goog.color.validHexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; +goog.dom.safe.insertAdjacentHtml = function(node, position, html) { + node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrap(html)); +}; /** - * Checks if a string is a valid hex color. We expect strings of the format - * #RRGGBB (ex: #1b3d5f) or #RGB (ex: #3CA == #33CCAA). - * @param {string} str String to check. - * @return {boolean} Whether the string is a valid hex color. - * @private + * Assigns known-safe HTML to an element's innerHTML property. + * @param {!Element} elem The element whose innerHTML is to be assigned to. + * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. */ -goog.color.isValidHexColor_ = function(str) { - return goog.color.validHexColorRe_.test(str); +goog.dom.safe.setInnerHtml = function(elem, html) { + elem.innerHTML = goog.html.SafeHtml.unwrap(html); }; /** - * Helper for isNormalizedHexColor_. - * @type {RegExp} - * @private + * Assigns known-safe HTML to an element's outerHTML property. + * @param {!Element} elem The element whose outerHTML is to be assigned to. + * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. */ -goog.color.normalizedHexColorRe_ = /^#[0-9a-f]{6}$/; +goog.dom.safe.setOuterHtml = function(elem, html) { + elem.outerHTML = goog.html.SafeHtml.unwrap(html); +}; /** - * Checks if a string is a normalized hex color. - * We expect strings of the format #RRGGBB (ex: #1b3d5f) - * using only lowercase letters. - * @param {string} str String to check. - * @return {boolean} Whether the string is a normalized hex color. - * @private + * Writes known-safe HTML to a document. + * @param {!Document} doc The document to be written to. + * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. */ -goog.color.isNormalizedHexColor_ = function(str) { - return goog.color.normalizedHexColorRe_.test(str); +goog.dom.safe.documentWrite = function(doc, html) { + doc.write(goog.html.SafeHtml.unwrap(html)); }; /** - * Regular expression for matching and capturing RGB style strings. Helper for - * isValidRgbColor_. - * @type {RegExp} - * @private + * Safely assigns a URL to an anchor element's href property. + * + * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to + * anchor's href property. If url is of type string however, it is first + * sanitized using goog.html.SafeUrl.sanitize. + * + * Example usage: + * goog.dom.safe.setAnchorHref(anchorEl, url); + * which is a safe alternative to + * anchorEl.href = url; + * The latter can result in XSS vulnerabilities if url is a + * user-/attacker-controlled value. + * + * @param {!HTMLAnchorElement} anchor The anchor element whose href property + * is to be assigned to. + * @param {string|!goog.html.SafeUrl} url The URL to assign. + * @see goog.html.SafeUrl#sanitize */ -goog.color.rgbColorRe_ = - /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; +goog.dom.safe.setAnchorHref = function(anchor, url) { + /** @type {!goog.html.SafeUrl} */ + var safeUrl; + if (url instanceof goog.html.SafeUrl) { + safeUrl = url; + } else { + safeUrl = goog.html.SafeUrl.sanitize(url); + } + anchor.href = goog.html.SafeUrl.unwrap(safeUrl); +}; /** - * Checks if a string is a valid rgb color. We expect strings of the format - * '(r, g, b)', or 'rgb(r, g, b)', where each color component is an int in - * [0, 255]. - * @param {string} str String to check. - * @return {!goog.color.Rgb} the rgb representation of the color if it is - * a valid color, or the empty array otherwise. - * @private + * Safely assigns a URL to an embed element's src property. + * + * Example usage: + * goog.dom.safe.setEmbedSrc(embedEl, url); + * which is a safe alternative to + * embedEl.src = url; + * The latter can result in loading untrusted code unless it is ensured that + * the URL refers to a trustworthy resource. + * + * @param {!HTMLEmbedElement} embed The embed element whose src property + * is to be assigned to. + * @param {!goog.html.TrustedResourceUrl} url The URL to assign. */ -goog.color.isValidRgbColor_ = function(str) { - // Each component is separate (rather than using a repeater) so we can - // capture the match. Also, we explicitly set each component to be either 0, - // or start with a non-zero, to prevent octal numbers from slipping through. - var regExpResultArray = str.match(goog.color.rgbColorRe_); - if (regExpResultArray) { - var r = Number(regExpResultArray[1]); - var g = Number(regExpResultArray[2]); - var b = Number(regExpResultArray[3]); - if (r >= 0 && r <= 255 && - g >= 0 && g <= 255 && - b >= 0 && b <= 255) { - return [r, g, b]; - } - } - return []; +goog.dom.safe.setEmbedSrc = function(embed, url) { + embed.src = goog.html.TrustedResourceUrl.unwrap(url); }; /** - * Takes a hex value and prepends a zero if it's a single digit. - * Small helper method for use by goog.color and friends. - * @param {string} hex Hex value to prepend if single digit. - * @return {string} hex value prepended with zero if it was single digit, - * otherwise the same value that was passed in. + * Safely assigns a URL to a frame element's src property. + * + * Example usage: + * goog.dom.safe.setFrameSrc(frameEl, url); + * which is a safe alternative to + * frameEl.src = url; + * The latter can result in loading untrusted code unless it is ensured that + * the URL refers to a trustworthy resource. + * + * @param {!HTMLFrameElement} frame The frame element whose src property + * is to be assigned to. + * @param {!goog.html.TrustedResourceUrl} url The URL to assign. */ -goog.color.prependZeroIfNecessaryHelper = function(hex) { - return hex.length == 1 ? '0' + hex : hex; +goog.dom.safe.setFrameSrc = function(frame, url) { + frame.src = goog.html.TrustedResourceUrl.unwrap(url); }; /** - * Takes a string a prepends a '#' sign if one doesn't exist. - * Small helper method for use by goog.color and friends. - * @param {string} str String to check. - * @return {string} The value passed in, prepended with a '#' if it didn't - * already have one. + * Safely assigns a URL to an iframe element's src property. + * + * Example usage: + * goog.dom.safe.setIframeSrc(iframeEl, url); + * which is a safe alternative to + * iframeEl.src = url; + * The latter can result in loading untrusted code unless it is ensured that + * the URL refers to a trustworthy resource. + * + * @param {!HTMLIFrameElement} iframe The iframe element whose src property + * is to be assigned to. + * @param {!goog.html.TrustedResourceUrl} url The URL to assign. */ -goog.color.prependHashIfNecessaryHelper = function(str) { - return str.charAt(0) == '#' ? str : '#' + str; +goog.dom.safe.setIframeSrc = function(iframe, url) { + iframe.src = goog.html.TrustedResourceUrl.unwrap(url); }; /** - * Takes an array of [r, g, b] and converts it into a string appropriate for - * CSS styles. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {string} string of the form 'rgb(r,g,b)'. - * @private + * Safely sets a link element's href and rel properties. Whether or not + * the URL assigned to href has to be a goog.html.TrustedResourceUrl + * depends on the value of the rel property. If rel contains "stylesheet" + * then a TrustedResourceUrl is required. + * + * Example usage: + * goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet'); + * which is a safe alternative to + * linkEl.rel = 'stylesheet'; + * linkEl.href = url; + * The latter can result in loading untrusted code unless it is ensured that + * the URL refers to a trustworthy resource. + * + * @param {!HTMLLinkElement} link The link element whose href property + * is to be assigned to. + * @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL + * to assign to the href property. Must be a TrustedResourceUrl if the + * value assigned to rel contains "stylesheet". A string value is + * sanitized with goog.html.SafeUrl.sanitize. + * @param {string} rel The value to assign to the rel property. + * @throws {Error} if rel contains "stylesheet" and url is not a + * TrustedResourceUrl + * @see goog.html.SafeUrl#sanitize */ -goog.color.rgbStyle_ = function(rgb) { - return 'rgb(' + rgb.join(',') + ')'; +goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) { + link.rel = rel; + if (goog.string.caseInsensitiveContains(rel, 'stylesheet')) { + goog.asserts.assert( + url instanceof goog.html.TrustedResourceUrl, + 'URL must be TrustedResourceUrl because "rel" contains "stylesheet"'); + link.href = goog.html.TrustedResourceUrl.unwrap(url); + } else if (url instanceof goog.html.TrustedResourceUrl) { + link.href = goog.html.TrustedResourceUrl.unwrap(url); + } else if (url instanceof goog.html.SafeUrl) { + link.href = goog.html.SafeUrl.unwrap(url); + } else { // string + // SafeUrl.sanitize must return legitimate SafeUrl when passed a string. + link.href = goog.html.SafeUrl.sanitize(url).getTypedStringValue(); + } }; /** - * Converts an HSV triplet to an RGB array. V is brightness because b is - * reserved for blue in RGB. - * @param {number} h Hue value in [0, 360]. - * @param {number} s Saturation value in [0, 1]. - * @param {number} brightness brightness in [0, 255]. - * @return {!goog.color.Rgb} rgb representation of the color. + * Safely assigns a URL to an object element's data property. + * + * Example usage: + * goog.dom.safe.setObjectData(objectEl, url); + * which is a safe alternative to + * objectEl.data = url; + * The latter can result in loading untrusted code unless setit is ensured that + * the URL refers to a trustworthy resource. + * + * @param {!HTMLObjectElement} object The object element whose data property + * is to be assigned to. + * @param {!goog.html.TrustedResourceUrl} url The URL to assign. */ -goog.color.hsvToRgb = function(h, s, brightness) { - var red = 0; - var green = 0; - var blue = 0; - if (s == 0) { - red = brightness; - green = brightness; - blue = brightness; - } else { - var sextant = Math.floor(h / 60); - var remainder = (h / 60) - sextant; - var val1 = brightness * (1 - s); - var val2 = brightness * (1 - (s * remainder)); - var val3 = brightness * (1 - (s * (1 - remainder))); - switch (sextant) { - case 1: - red = val2; - green = brightness; - blue = val1; - break; - case 2: - red = val1; - green = brightness; - blue = val3; - break; - case 3: - red = val1; - green = val2; - blue = brightness; - break; - case 4: - red = val3; - green = val1; - blue = brightness; - break; - case 5: - red = brightness; - green = val1; - blue = val2; - break; - case 6: - case 0: - red = brightness; - green = val3; - blue = val1; - break; - } - } - - return [Math.floor(red), Math.floor(green), Math.floor(blue)]; +goog.dom.safe.setObjectData = function(object, url) { + object.data = goog.html.TrustedResourceUrl.unwrap(url); }; /** - * Converts from RGB values to an array of HSV values. - * @param {number} red Red value in [0, 255]. - * @param {number} green Green value in [0, 255]. - * @param {number} blue Blue value in [0, 255]. - * @return {!goog.color.Hsv} hsv representation of the color. + * Safely assigns a URL to an iframe element's src property. + * + * Example usage: + * goog.dom.safe.setScriptSrc(scriptEl, url); + * which is a safe alternative to + * scriptEl.src = url; + * The latter can result in loading untrusted code unless it is ensured that + * the URL refers to a trustworthy resource. + * + * @param {!HTMLScriptElement} script The script element whose src property + * is to be assigned to. + * @param {!goog.html.TrustedResourceUrl} url The URL to assign. */ -goog.color.rgbToHsv = function(red, green, blue) { - - var max = Math.max(Math.max(red, green), blue); - var min = Math.min(Math.min(red, green), blue); - var hue; - var saturation; - var value = max; - if (min == max) { - hue = 0; - saturation = 0; - } else { - var delta = (max - min); - saturation = delta / max; - - if (red == max) { - hue = (green - blue) / delta; - } else if (green == max) { - hue = 2 + ((blue - red) / delta); - } else { - hue = 4 + ((red - green) / delta); - } - hue *= 60; - if (hue < 0) { - hue += 360; - } - if (hue > 360) { - hue -= 360; - } - } - - return [hue, saturation, value]; +goog.dom.safe.setScriptSrc = function(script, url) { + script.src = goog.html.TrustedResourceUrl.unwrap(url); }; /** - * Converts from an array of RGB values to an array of HSV values. - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @return {!goog.color.Hsv} hsv representation of the color. + * Safely assigns a URL to a Location object's href property. + * + * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to + * loc's href property. If url is of type string however, it is first sanitized + * using goog.html.SafeUrl.sanitize. + * + * Example usage: + * goog.dom.safe.setLocationHref(document.location, redirectUrl); + * which is a safe alternative to + * document.location.href = redirectUrl; + * The latter can result in XSS vulnerabilities if redirectUrl is a + * user-/attacker-controlled value. + * + * @param {!Location} loc The Location object whose href property is to be + * assigned to. + * @param {string|!goog.html.SafeUrl} url The URL to assign. + * @see goog.html.SafeUrl#sanitize */ -goog.color.rgbArrayToHsv = function(rgb) { - return goog.color.rgbToHsv(rgb[0], rgb[1], rgb[2]); +goog.dom.safe.setLocationHref = function(loc, url) { + /** @type {!goog.html.SafeUrl} */ + var safeUrl; + if (url instanceof goog.html.SafeUrl) { + safeUrl = url; + } else { + safeUrl = goog.html.SafeUrl.sanitize(url); + } + loc.href = goog.html.SafeUrl.unwrap(safeUrl); }; /** - * Converts an HSV triplet to an RGB array. - * @param {goog.color.Hsv} hsv hsv representation of the color. - * @return {!goog.color.Rgb} rgb representation of the color. + * Safely opens a URL in a new window (via window.open). + * + * If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to + * window.open. If url is of type string however, it is first sanitized + * using goog.html.SafeUrl.sanitize. + * + * Note that this function does not prevent leakages via the referer that is + * sent by window.open. It is advised to only use this to open 1st party URLs. + * + * Example usage: + * goog.dom.safe.openInWindow(url); + * which is a safe alternative to + * window.open(url); + * The latter can result in XSS vulnerabilities if redirectUrl is a + * user-/attacker-controlled value. + * + * @param {string|!goog.html.SafeUrl} url The URL to open. + * @param {Window=} opt_openerWin Window of which to call the .open() method. + * Defaults to the global window. + * @param {!goog.string.Const=} opt_name Name of the window to open in. Can be + * _top, etc as allowed by window.open(). + * @param {string=} opt_specs Comma-separated list of specifications, same as + * in window.open(). + * @param {boolean=} opt_replace Whether to replace the current entry in browser + * history, same as in window.open(). + * @return {Window} Window the url was opened in. */ -goog.color.hsvArrayToRgb = function(hsv) { - return goog.color.hsvToRgb(hsv[0], hsv[1], hsv[2]); +goog.dom.safe.openInWindow = function( + url, opt_openerWin, opt_name, opt_specs, opt_replace) { + /** @type {!goog.html.SafeUrl} */ + var safeUrl; + if (url instanceof goog.html.SafeUrl) { + safeUrl = url; + } else { + safeUrl = goog.html.SafeUrl.sanitize(url); + } + var win = opt_openerWin || window; + return win.open(goog.html.SafeUrl.unwrap(safeUrl), + // If opt_name is undefined, simply passing that in to open() causes IE to + // reuse the current window instead of opening a new one. Thus we pass '' + // in instead, which according to spec opens a new window. See + // https://html.spec.whatwg.org/multipage/browsers.html#dom-open . + opt_name ? goog.string.Const.unwrap(opt_name) : '', + opt_specs, opt_replace); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Converts a hex representation of a color to HSL. - * @param {string} hex Color to convert. - * @return {!goog.color.Hsv} hsv representation of the color. + * @fileoverview A utility class for representing two-dimensional positions. */ -goog.color.hexToHsl = function(hex) { - var rgb = goog.color.hexToRgb(hex); - return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]); -}; -/** - * Converts from h,s,l values to a hex string - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} l Luminosity, in [0, 1]. - * @return {string} hex representation of the color. - */ -goog.color.hslToHex = function(h, s, l) { - return goog.color.rgbArrayToHex(goog.color.hslToRgb(h, s, l)); -}; +goog.provide('goog.math.Coordinate'); +goog.require('goog.math'); -/** - * Converts from an hsl array to a hex string - * @param {goog.color.Hsl} hsl hsl representation of the color. - * @return {string} hex representation of the color. - */ -goog.color.hslArrayToHex = function(hsl) { - return goog.color.rgbArrayToHex(goog.color.hslToRgb(hsl[0], hsl[1], hsl[2])); -}; /** - * Converts a hex representation of a color to HSV - * @param {string} hex Color to convert. - * @return {!goog.color.Hsv} hsv representation of the color. + * Class for representing coordinates and positions. + * @param {number=} opt_x Left, defaults to 0. + * @param {number=} opt_y Top, defaults to 0. + * @struct + * @constructor */ -goog.color.hexToHsv = function(hex) { - return goog.color.rgbArrayToHsv(goog.color.hexToRgb(hex)); +goog.math.Coordinate = function(opt_x, opt_y) { + /** + * X-value + * @type {number} + */ + this.x = goog.isDef(opt_x) ? opt_x : 0; + + /** + * Y-value + * @type {number} + */ + this.y = goog.isDef(opt_y) ? opt_y : 0; }; /** - * Converts from h,s,v values to a hex string - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} v Value, in [0, 255]. - * @return {string} hex representation of the color. + * Returns a new copy of the coordinate. + * @return {!goog.math.Coordinate} A clone of this coordinate. */ -goog.color.hsvToHex = function(h, s, v) { - return goog.color.rgbArrayToHex(goog.color.hsvToRgb(h, s, v)); +goog.math.Coordinate.prototype.clone = function() { + return new goog.math.Coordinate(this.x, this.y); }; -/** - * Converts from an HSV array to a hex string - * @param {goog.color.Hsv} hsv hsv representation of the color. - * @return {string} hex representation of the color. - */ -goog.color.hsvArrayToHex = function(hsv) { - return goog.color.hsvToHex(hsv[0], hsv[1], hsv[2]); -}; +if (goog.DEBUG) { + /** + * Returns a nice string representing the coordinate. + * @return {string} In the form (50, 73). + * @override + */ + goog.math.Coordinate.prototype.toString = function() { + return '(' + this.x + ', ' + this.y + ')'; + }; +} /** - * Calculates the Euclidean distance between two color vectors on an HSL sphere. - * A demo of the sphere can be found at: - * http://en.wikipedia.org/wiki/HSL_color_space - * In short, a vector for color (H, S, L) in this system can be expressed as - * (S*L'*cos(2*PI*H), S*L'*sin(2*PI*H), L), where L' = abs(L - 0.5), and we - * simply calculate the 1-2 distance using these coordinates - * @param {goog.color.Hsl} hsl1 First color in hsl representation. - * @param {goog.color.Hsl} hsl2 Second color in hsl representation. - * @return {number} Distance between the two colors, in the range [0, 1]. + * Compares coordinates for equality. + * @param {goog.math.Coordinate} a A Coordinate. + * @param {goog.math.Coordinate} b A Coordinate. + * @return {boolean} True iff the coordinates are equal, or if both are null. */ -goog.color.hslDistance = function(hsl1, hsl2) { - var sl1, sl2; - if (hsl1[2] <= 0.5) { - sl1 = hsl1[1] * hsl1[2]; - } else { - sl1 = hsl1[1] * (1.0 - hsl1[2]); +goog.math.Coordinate.equals = function(a, b) { + if (a == b) { + return true; } - - if (hsl2[2] <= 0.5) { - sl2 = hsl2[1] * hsl2[2]; - } else { - sl2 = hsl2[1] * (1.0 - hsl2[2]); + if (!a || !b) { + return false; } - - var h1 = hsl1[0] / 360.0; - var h2 = hsl2[0] / 360.0; - var dh = (h1 - h2) * 2.0 * Math.PI; - return (hsl1[2] - hsl2[2]) * (hsl1[2] - hsl2[2]) + - sl1 * sl1 + sl2 * sl2 - 2 * sl1 * sl2 * Math.cos(dh); + return a.x == b.x && a.y == b.y; }; /** - * Blend two colors together, using the specified factor to indicate the weight - * given to the first color - * @param {goog.color.Rgb} rgb1 First color represented in rgb. - * @param {goog.color.Rgb} rgb2 Second color represented in rgb. - * @param {number} factor The weight to be given to rgb1 over rgb2. Values - * should be in the range [0, 1]. If less than 0, factor will be set to 0. - * If greater than 1, factor will be set to 1. - * @return {!goog.color.Rgb} Combined color represented in rgb. + * Returns the distance between two coordinates. + * @param {!goog.math.Coordinate} a A Coordinate. + * @param {!goog.math.Coordinate} b A Coordinate. + * @return {number} The distance between {@code a} and {@code b}. */ -goog.color.blend = function(rgb1, rgb2, factor) { - factor = goog.math.clamp(factor, 0, 1); - - return [ - Math.round(factor * rgb1[0] + (1.0 - factor) * rgb2[0]), - Math.round(factor * rgb1[1] + (1.0 - factor) * rgb2[1]), - Math.round(factor * rgb1[2] + (1.0 - factor) * rgb2[2]) - ]; +goog.math.Coordinate.distance = function(a, b) { + var dx = a.x - b.x; + var dy = a.y - b.y; + return Math.sqrt(dx * dx + dy * dy); }; /** - * Adds black to the specified color, darkening it - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while - * 1 will return black. If less than 0, factor will be set to 0. If greater - * than 1, factor will be set to 1. - * @return {!goog.color.Rgb} Combined rgb color. + * Returns the magnitude of a coordinate. + * @param {!goog.math.Coordinate} a A Coordinate. + * @return {number} The distance between the origin and {@code a}. */ -goog.color.darken = function(rgb, factor) { - var black = [0, 0, 0]; - return goog.color.blend(black, rgb, factor); +goog.math.Coordinate.magnitude = function(a) { + return Math.sqrt(a.x * a.x + a.y * a.y); }; /** - * Adds white to the specified color, lightening it - * @param {goog.color.Rgb} rgb rgb representation of the color. - * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while - * 1 will return white. If less than 0, factor will be set to 0. If greater - * than 1, factor will be set to 1. - * @return {!goog.color.Rgb} Combined rgb color. + * Returns the angle from the origin to a coordinate. + * @param {!goog.math.Coordinate} a A Coordinate. + * @return {number} The angle, in degrees, clockwise from the positive X + * axis to {@code a}. */ -goog.color.lighten = function(rgb, factor) { - var white = [255, 255, 255]; - return goog.color.blend(white, rgb, factor); +goog.math.Coordinate.azimuth = function(a) { + return goog.math.angle(0, 0, a.x, a.y); }; /** - * Find the "best" (highest-contrast) of the suggested colors for the prime - * color. Uses W3C formula for judging readability and visual accessibility: - * http://www.w3.org/TR/AERT#color-contrast - * @param {goog.color.Rgb} prime Color represented as a rgb array. - * @param {Array<goog.color.Rgb>} suggestions Array of colors, - * each representing a rgb array. - * @return {!goog.color.Rgb} Highest-contrast color represented by an array.. + * Returns the squared distance between two coordinates. Squared distances can + * be used for comparisons when the actual value is not required. + * + * Performance note: eliminating the square root is an optimization often used + * in lower-level languages, but the speed difference is not nearly as + * pronounced in JavaScript (only a few percent.) + * + * @param {!goog.math.Coordinate} a A Coordinate. + * @param {!goog.math.Coordinate} b A Coordinate. + * @return {number} The squared distance between {@code a} and {@code b}. */ -goog.color.highContrast = function(prime, suggestions) { - var suggestionsWithDiff = []; - for (var i = 0; i < suggestions.length; i++) { - suggestionsWithDiff.push({ - color: suggestions[i], - diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) + - goog.color.colorDiff_(suggestions[i], prime) - }); - } - suggestionsWithDiff.sort(function(a, b) { - return b.diff - a.diff; - }); - return suggestionsWithDiff[0].color; +goog.math.Coordinate.squaredDistance = function(a, b) { + var dx = a.x - b.x; + var dy = a.y - b.y; + return dx * dx + dy * dy; }; /** - * Calculate brightness of a color according to YIQ formula (brightness is Y). - * More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for - * goog.color.highContrast() - * @param {goog.color.Rgb} rgb Color represented by a rgb array. - * @return {number} brightness (Y). - * @private + * Returns the difference between two coordinates as a new + * goog.math.Coordinate. + * @param {!goog.math.Coordinate} a A Coordinate. + * @param {!goog.math.Coordinate} b A Coordinate. + * @return {!goog.math.Coordinate} A Coordinate representing the difference + * between {@code a} and {@code b}. */ -goog.color.yiqBrightness_ = function(rgb) { - return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000); +goog.math.Coordinate.difference = function(a, b) { + return new goog.math.Coordinate(a.x - b.x, a.y - b.y); }; /** - * Calculate difference in brightness of two colors. Helper method for - * goog.color.highContrast() - * @param {goog.color.Rgb} rgb1 Color represented by a rgb array. - * @param {goog.color.Rgb} rgb2 Color represented by a rgb array. - * @return {number} Brightness difference. - * @private + * Returns the sum of two coordinates as a new goog.math.Coordinate. + * @param {!goog.math.Coordinate} a A Coordinate. + * @param {!goog.math.Coordinate} b A Coordinate. + * @return {!goog.math.Coordinate} A Coordinate representing the sum of the two + * coordinates. */ -goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) { - return Math.abs(goog.color.yiqBrightness_(rgb1) - - goog.color.yiqBrightness_(rgb2)); +goog.math.Coordinate.sum = function(a, b) { + return new goog.math.Coordinate(a.x + b.x, a.y + b.y); }; /** - * Calculate color difference between two colors. Helper method for - * goog.color.highContrast() - * @param {goog.color.Rgb} rgb1 Color represented by a rgb array. - * @param {goog.color.Rgb} rgb2 Color represented by a rgb array. - * @return {number} Color difference. - * @private + * Rounds the x and y fields to the next larger integer values. + * @return {!goog.math.Coordinate} This coordinate with ceil'd fields. */ -goog.color.colorDiff_ = function(rgb1, rgb2) { - return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) + - Math.abs(rgb1[2] - rgb2[2]); +goog.math.Coordinate.prototype.ceil = function() { + this.x = Math.ceil(this.x); + this.y = Math.ceil(this.y); + return this; }; -// We can't use goog.color or goog.color.alpha because they interally use a hex -// string representation that encodes each channel in a single byte. This -// causes occasional loss of precision and rounding errors, especially in the -// alpha channel. - -goog.provide('ol.Color'); -goog.provide('ol.color'); - -goog.require('goog.asserts'); -goog.require('goog.color'); -goog.require('goog.color.names'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.math'); - /** - * A color represented as a short array [red, green, blue, alpha]. - * red, green, and blue should be integers in the range 0..255 inclusive. - * alpha should be a float in the range 0..1 inclusive. - * @typedef {Array.<number>} - * @api + * Rounds the x and y fields to the next smaller integer values. + * @return {!goog.math.Coordinate} This coordinate with floored fields. */ -ol.Color; +goog.math.Coordinate.prototype.floor = function() { + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + return this; +}; /** - * This RegExp matches # followed by 3 or 6 hex digits. - * @const - * @type {RegExp} - * @private + * Rounds the x and y fields to the nearest integer values. + * @return {!goog.math.Coordinate} This coordinate with rounded fields. */ -ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; +goog.math.Coordinate.prototype.round = function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; +}; /** - * @see goog.color.rgbColorRe_ - * @const - * @type {RegExp} - * @private + * Translates this box by the given offsets. If a {@code goog.math.Coordinate} + * is given, then the x and y values are translated by the coordinate's x and y. + * Otherwise, x and y are translated by {@code tx} and {@code opt_ty} + * respectively. + * @param {number|goog.math.Coordinate} tx The value to translate x by or the + * the coordinate to translate this coordinate by. + * @param {number=} opt_ty The value to translate y by. + * @return {!goog.math.Coordinate} This coordinate after translating. */ -ol.color.rgbColorRe_ = - /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; - - -/** - * @see goog.color.alpha.rgbaColorRe_ - * @const - * @type {RegExp} - * @private - */ -ol.color.rgbaColorRe_ = - /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i; - - -/** - * @param {ol.Color} dst Destination. - * @param {ol.Color} src Source. - * @param {ol.Color=} opt_color Color. - * @return {ol.Color} Color. - */ -ol.color.blend = function(dst, src, opt_color) { - // http://en.wikipedia.org/wiki/Alpha_compositing - // FIXME do we need to scale by 255? - var out = opt_color ? opt_color : []; - var dstA = dst[3]; - var srcA = src[3]; - if (dstA == 1) { - out[0] = (src[0] * srcA + dst[0] * (1 - srcA) + 0.5) | 0; - out[1] = (src[1] * srcA + dst[1] * (1 - srcA) + 0.5) | 0; - out[2] = (src[2] * srcA + dst[2] * (1 - srcA) + 0.5) | 0; - out[3] = 1; - } else if (srcA === 0) { - out[0] = dst[0]; - out[1] = dst[1]; - out[2] = dst[2]; - out[3] = dstA; +goog.math.Coordinate.prototype.translate = function(tx, opt_ty) { + if (tx instanceof goog.math.Coordinate) { + this.x += tx.x; + this.y += tx.y; } else { - var outA = srcA + dstA * (1 - srcA); - if (outA === 0) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; - } else { - out[0] = ((src[0] * srcA + dst[0] * dstA * (1 - srcA)) / outA + 0.5) | 0; - out[1] = ((src[1] * srcA + dst[1] * dstA * (1 - srcA)) / outA + 0.5) | 0; - out[2] = ((src[2] * srcA + dst[2] * dstA * (1 - srcA)) / outA + 0.5) | 0; - out[3] = outA; + this.x += tx; + if (goog.isNumber(opt_ty)) { + this.y += opt_ty; } } - goog.asserts.assert(ol.color.isValid(out), - 'Output color of blend should be a valid color'); - return out; + return this; }; /** - * Return the color as an array. This function maintains a cache of calculated - * arrays which means the result should not be modified. - * @param {ol.Color|string} color Color. - * @return {ol.Color} Color. - * @api + * Scales this coordinate by the given scale factors. The x and y values are + * scaled by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} + * is not given, then {@code sx} is used for both x and y. + * @param {number} sx The scale factor to use for the x dimension. + * @param {number=} opt_sy The scale factor to use for the y dimension. + * @return {!goog.math.Coordinate} This coordinate after scaling. */ -ol.color.asArray = function(color) { - if (goog.isArray(color)) { - return color; - } else { - goog.asserts.assert(goog.isString(color), 'Color should be a string'); - return ol.color.fromString(color); - } +goog.math.Coordinate.prototype.scale = function(sx, opt_sy) { + var sy = goog.isNumber(opt_sy) ? opt_sy : sx; + this.x *= sx; + this.y *= sy; + return this; }; /** - * Return the color as an rgba string. - * @param {ol.Color|string} color Color. - * @return {string} Rgba string. - * @api + * Rotates this coordinate clockwise about the origin (or, optionally, the given + * center) by the given angle, in radians. + * @param {number} radians The angle by which to rotate this coordinate + * clockwise about the given center, in radians. + * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults + * to (0, 0) if not given. */ -ol.color.asString = function(color) { - if (goog.isString(color)) { - return color; - } else { - goog.asserts.assert(goog.isArray(color), 'Color should be an array'); - return ol.color.toString(color); - } +goog.math.Coordinate.prototype.rotateRadians = function(radians, opt_center) { + var center = opt_center || new goog.math.Coordinate(0, 0); + + var x = this.x; + var y = this.y; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + + this.x = (x - center.x) * cos - (y - center.y) * sin + center.x; + this.y = (x - center.x) * sin + (y - center.y) * cos + center.y; }; /** - * @param {ol.Color} color1 Color1. - * @param {ol.Color} color2 Color2. - * @return {boolean} Equals. + * Rotates this coordinate clockwise about the origin (or, optionally, the given + * center) by the given angle, in degrees. + * @param {number} degrees The angle by which to rotate this coordinate + * clockwise about the given center, in degrees. + * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults + * to (0, 0) if not given. */ -ol.color.equals = function(color1, color2) { - return color1 === color2 || ( - color1[0] == color2[0] && color1[1] == color2[1] && - color1[2] == color2[2] && color1[3] == color2[3]); +goog.math.Coordinate.prototype.rotateDegrees = function(degrees, opt_center) { + this.rotateRadians(goog.math.toRadians(degrees), opt_center); }; +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {string} s String. - * @return {ol.Color} Color. + * @fileoverview A utility class for representing two-dimensional sizes. + * @author brenneman@google.com (Shawn Brenneman) */ -ol.color.fromString = ( - /** - * @return {function(string): ol.Color} - */ - function() { - // We maintain a small cache of parsed strings. To provide cheap LRU-like - // semantics, whenever the cache grows too large we simply delete an - // arbitrary 25% of the entries. - /** - * @const - * @type {number} - */ - var MAX_CACHE_SIZE = 1024; +goog.provide('goog.math.Size'); - /** - * @type {Object.<string, ol.Color>} - */ - var cache = {}; - /** - * @type {number} - */ - var cacheSize = 0; - return ( - /** - * @param {string} s String. - * @return {ol.Color} Color. - */ - function(s) { - var color; - if (cache.hasOwnProperty(s)) { - color = cache[s]; - } else { - if (cacheSize >= MAX_CACHE_SIZE) { - var i = 0; - var key; - for (key in cache) { - if ((i++ & 3) === 0) { - delete cache[key]; - --cacheSize; - } - } - } - color = ol.color.fromStringInternal_(s); - cache[s] = color; - ++cacheSize; - } - return color; - }); +/** + * Class for representing sizes consisting of a width and height. Undefined + * width and height support is deprecated and results in compiler warning. + * @param {number} width Width. + * @param {number} height Height. + * @struct + * @constructor + */ +goog.math.Size = function(width, height) { + /** + * Width + * @type {number} + */ + this.width = width; - })(); + /** + * Height + * @type {number} + */ + this.height = height; +}; /** - * @param {string} s String. - * @private - * @return {ol.Color} Color. + * Compares sizes for equality. + * @param {goog.math.Size} a A Size. + * @param {goog.math.Size} b A Size. + * @return {boolean} True iff the sizes have equal widths and equal + * heights, or if both are null. */ -ol.color.fromStringInternal_ = function(s) { - - var isHex = false; - if (ol.ENABLE_NAMED_COLORS && goog.color.names.hasOwnProperty(s)) { - s = goog.color.names[s]; - isHex = true; +goog.math.Size.equals = function(a, b) { + if (a == b) { + return true; } - - var r, g, b, a, color, match; - if (isHex || (match = ol.color.hexColorRe_.exec(s))) { // hex - var n = s.length - 1; // number of hex digits - goog.asserts.assert(n == 3 || n == 6, - 'Color string length should be 3 or 6'); - var d = n == 3 ? 1 : 2; // number of digits per channel - r = parseInt(s.substr(1 + 0 * d, d), 16); - g = parseInt(s.substr(1 + 1 * d, d), 16); - b = parseInt(s.substr(1 + 2 * d, d), 16); - if (d == 1) { - r = (r << 4) + r; - g = (g << 4) + g; - b = (b << 4) + b; - } - a = 1; - color = [r, g, b, a]; - goog.asserts.assert(ol.color.isValid(color), - 'Color should be a valid color'); - return color; - } else if ((match = ol.color.rgbaColorRe_.exec(s))) { // rgba() - r = Number(match[1]); - g = Number(match[2]); - b = Number(match[3]); - a = Number(match[4]); - color = [r, g, b, a]; - return ol.color.normalize(color, color); - } else if ((match = ol.color.rgbColorRe_.exec(s))) { // rgb() - r = Number(match[1]); - g = Number(match[2]); - b = Number(match[3]); - color = [r, g, b, 1]; - return ol.color.normalize(color, color); - } else { - goog.asserts.fail(s + ' is not a valid color'); + if (!a || !b) { + return false; } + return a.width == b.width && a.height == b.height; +}; + +/** + * @return {!goog.math.Size} A new copy of the Size. + */ +goog.math.Size.prototype.clone = function() { + return new goog.math.Size(this.width, this.height); }; +if (goog.DEBUG) { + /** + * Returns a nice string representing size. + * @return {string} In the form (50 x 73). + * @override + */ + goog.math.Size.prototype.toString = function() { + return '(' + this.width + ' x ' + this.height + ')'; + }; +} + + /** - * @param {ol.Color} color Color. - * @return {boolean} Is valid. + * @return {number} The longer of the two dimensions in the size. */ -ol.color.isValid = function(color) { - return 0 <= color[0] && color[0] < 256 && - 0 <= color[1] && color[1] < 256 && - 0 <= color[2] && color[2] < 256 && - 0 <= color[3] && color[3] <= 1; +goog.math.Size.prototype.getLongest = function() { + return Math.max(this.width, this.height); }; /** - * @param {ol.Color} color Color. - * @param {ol.Color=} opt_color Color. - * @return {ol.Color} Clamped color. + * @return {number} The shorter of the two dimensions in the size. */ -ol.color.normalize = function(color, opt_color) { - var result = opt_color || []; - result[0] = ol.math.clamp((color[0] + 0.5) | 0, 0, 255); - result[1] = ol.math.clamp((color[1] + 0.5) | 0, 0, 255); - result[2] = ol.math.clamp((color[2] + 0.5) | 0, 0, 255); - result[3] = ol.math.clamp(color[3], 0, 1); - return result; +goog.math.Size.prototype.getShortest = function() { + return Math.min(this.width, this.height); }; /** - * @param {ol.Color} color Color. - * @return {string} String. + * @return {number} The area of the size (width * height). */ -ol.color.toString = function(color) { - var r = color[0]; - if (r != (r | 0)) { - r = (r + 0.5) | 0; - } - var g = color[1]; - if (g != (g | 0)) { - g = (g + 0.5) | 0; - } - var b = color[2]; - if (b != (b | 0)) { - b = (b + 0.5) | 0; - } - var a = color[3]; - return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; +goog.math.Size.prototype.area = function() { + return this.width * this.height; }; /** - * @param {!ol.Color} color Color. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {!ol.Color=} opt_color Color. - * @return {ol.Color} Transformed color. + * @return {number} The perimeter of the size (width + height) * 2. */ -ol.color.transform = function(color, transform, opt_color) { - var result = opt_color ? opt_color : []; - result = goog.vec.Mat4.multVec3(transform, color, result); - goog.asserts.assert(goog.isArray(result), 'result should be an array'); - result[3] = color[3]; - return ol.color.normalize(result, result); +goog.math.Size.prototype.perimeter = function() { + return (this.width + this.height) * 2; }; /** - * @param {ol.Color|string} color1 Color2. - * @param {ol.Color|string} color2 Color2. - * @return {boolean} Equals. + * @return {number} The ratio of the size's width to its height. */ -ol.color.stringOrColorEquals = function(color1, color2) { - if (color1 === color2 || color1 == color2) { - return true; - } - if (goog.isString(color1)) { - color1 = ol.color.fromString(color1); - } - if (goog.isString(color2)) { - color2 = ol.color.fromString(color2); - } - return ol.color.equals(color1, color2); +goog.math.Size.prototype.aspectRatio = function() { + return this.width / this.height; }; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Browser capability checks for the dom package. - * + * @return {boolean} True if the size has zero area, false if both dimensions + * are non-zero numbers. */ +goog.math.Size.prototype.isEmpty = function() { + return !this.area(); +}; -goog.provide('goog.dom.BrowserFeature'); +/** + * Clamps the width and height parameters upward to integer values. + * @return {!goog.math.Size} This size with ceil'd components. + */ +goog.math.Size.prototype.ceil = function() { + this.width = Math.ceil(this.width); + this.height = Math.ceil(this.height); + return this; +}; -goog.require('goog.userAgent'); + +/** + * @param {!goog.math.Size} target The target size. + * @return {boolean} True if this Size is the same size or smaller than the + * target size in both dimensions. + */ +goog.math.Size.prototype.fitsInside = function(target) { + return this.width <= target.width && this.height <= target.height; +}; /** - * Enum of browser capabilities. - * @enum {boolean} + * Clamps the width and height parameters downward to integer values. + * @return {!goog.math.Size} This size with floored components. */ -goog.dom.BrowserFeature = { - /** - * Whether attributes 'name' and 'type' can be added to an element after it's - * created. False in Internet Explorer prior to version 9. - */ - CAN_ADD_NAME_OR_TYPE_ATTRIBUTES: !goog.userAgent.IE || - goog.userAgent.isDocumentModeOrHigher(9), +goog.math.Size.prototype.floor = function() { + this.width = Math.floor(this.width); + this.height = Math.floor(this.height); + return this; +}; - /** - * Whether we can use element.children to access an element's Element - * children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment - * nodes in the collection.) - */ - CAN_USE_CHILDREN_ATTRIBUTE: !goog.userAgent.GECKO && !goog.userAgent.IE || - goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9) || - goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'), - /** - * Opera, Safari 3, and Internet Explorer 9 all support innerText but they - * include text nodes in script and style tags. Not document-mode-dependent. - */ - CAN_USE_INNER_TEXT: ( - goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')), +/** + * Rounds the width and height parameters to integer values. + * @return {!goog.math.Size} This size with rounded components. + */ +goog.math.Size.prototype.round = function() { + this.width = Math.round(this.width); + this.height = Math.round(this.height); + return this; +}; - /** - * MSIE, Opera, and Safari>=4 support element.parentElement to access an - * element's parent if it is an Element. - */ - CAN_USE_PARENT_ELEMENT_PROPERTY: goog.userAgent.IE || goog.userAgent.OPERA || - goog.userAgent.WEBKIT, - /** - * Whether NoScope elements need a scoped element written before them in - * innerHTML. - * MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1 - */ - INNER_HTML_NEEDS_SCOPED_ELEMENT: goog.userAgent.IE, +/** + * Scales this size by the given scale factors. The width and height are scaled + * by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} is not + * given, then {@code sx} is used for both the width and height. + * @param {number} sx The scale factor to use for the width. + * @param {number=} opt_sy The scale factor to use for the height. + * @return {!goog.math.Size} This Size object after scaling. + */ +goog.math.Size.prototype.scale = function(sx, opt_sy) { + var sy = goog.isNumber(opt_sy) ? opt_sy : sx; + this.width *= sx; + this.height *= sy; + return this; +}; - /** - * Whether we use legacy IE range API. - */ - LEGACY_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) + +/** + * Uniformly scales the size to perfectly cover the dimensions of a given size. + * If the size is already larger than the target, it will be scaled down to the + * minimum size at which it still covers the entire target. The original aspect + * ratio will be preserved. + * + * This function assumes that both Sizes contain strictly positive dimensions. + * @param {!goog.math.Size} target The target size. + * @return {!goog.math.Size} This Size object, after optional scaling. + */ +goog.math.Size.prototype.scaleToCover = function(target) { + var s = this.aspectRatio() <= target.aspectRatio() ? + target.width / this.width : + target.height / this.height; + + return this.scale(s); }; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. + +/** + * Uniformly scales the size to fit inside the dimensions of a given size. The + * original aspect ratio will be preserved. + * + * This function assumes that both Sizes contain strictly positive dimensions. + * @param {!goog.math.Size} target The target size. + * @return {!goog.math.Size} This Size object, after optional scaling. + */ +goog.math.Size.prototype.scaleToFit = function(target) { + var s = this.aspectRatio() > target.aspectRatio() ? + target.width / this.width : + target.height / this.height; + + return this.scale(s); +}; + +// Copyright 2006 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -27560,13299 +27104,12942 @@ goog.dom.BrowserFeature = { // limitations under the License. /** - * @fileoverview Defines the goog.dom.TagName enum. This enumerates - * all HTML tag names specified in either the the W3C HTML 4.01 index of - * elements or the HTML5 draft specification. + * @fileoverview Utilities for manipulating the browser's Document Object Model + * Inspiration taken *heavily* from mochikit (http://mochikit.com/). * - * References: - * http://www.w3.org/TR/html401/index/elements.html - * http://dev.w3.org/html5/spec/section-index.html + * You can use {@link goog.dom.DomHelper} to create new dom helpers that refer + * to a different document object. This is useful if you are working with + * frames or multiple windows. * + * @author arv@google.com (Erik Arvidsson) */ -goog.provide('goog.dom.TagName'); -/** - * Enum of all html tag names specified by the W3C HTML4.01 and HTML5 - * specifications. - * @enum {string} - */ -goog.dom.TagName = { - A: 'A', - ABBR: 'ABBR', - ACRONYM: 'ACRONYM', - ADDRESS: 'ADDRESS', - APPLET: 'APPLET', - AREA: 'AREA', - ARTICLE: 'ARTICLE', - ASIDE: 'ASIDE', - AUDIO: 'AUDIO', - B: 'B', - BASE: 'BASE', - BASEFONT: 'BASEFONT', - BDI: 'BDI', - BDO: 'BDO', - BIG: 'BIG', - BLOCKQUOTE: 'BLOCKQUOTE', - BODY: 'BODY', - BR: 'BR', - BUTTON: 'BUTTON', - CANVAS: 'CANVAS', - CAPTION: 'CAPTION', - CENTER: 'CENTER', - CITE: 'CITE', - CODE: 'CODE', - COL: 'COL', - COLGROUP: 'COLGROUP', - COMMAND: 'COMMAND', - DATA: 'DATA', - DATALIST: 'DATALIST', - DD: 'DD', - DEL: 'DEL', - DETAILS: 'DETAILS', - DFN: 'DFN', - DIALOG: 'DIALOG', - DIR: 'DIR', - DIV: 'DIV', - DL: 'DL', - DT: 'DT', - EM: 'EM', - EMBED: 'EMBED', - FIELDSET: 'FIELDSET', - FIGCAPTION: 'FIGCAPTION', - FIGURE: 'FIGURE', - FONT: 'FONT', - FOOTER: 'FOOTER', - FORM: 'FORM', - FRAME: 'FRAME', - FRAMESET: 'FRAMESET', - H1: 'H1', - H2: 'H2', - H3: 'H3', - H4: 'H4', - H5: 'H5', - H6: 'H6', - HEAD: 'HEAD', - HEADER: 'HEADER', - HGROUP: 'HGROUP', - HR: 'HR', - HTML: 'HTML', - I: 'I', - IFRAME: 'IFRAME', - IMG: 'IMG', - INPUT: 'INPUT', - INS: 'INS', - ISINDEX: 'ISINDEX', - KBD: 'KBD', - KEYGEN: 'KEYGEN', - LABEL: 'LABEL', - LEGEND: 'LEGEND', - LI: 'LI', - LINK: 'LINK', - MAP: 'MAP', - MARK: 'MARK', - MATH: 'MATH', - MENU: 'MENU', - META: 'META', - METER: 'METER', - NAV: 'NAV', - NOFRAMES: 'NOFRAMES', - NOSCRIPT: 'NOSCRIPT', - OBJECT: 'OBJECT', - OL: 'OL', - OPTGROUP: 'OPTGROUP', - OPTION: 'OPTION', - OUTPUT: 'OUTPUT', - P: 'P', - PARAM: 'PARAM', - PRE: 'PRE', - PROGRESS: 'PROGRESS', - Q: 'Q', - RP: 'RP', - RT: 'RT', - RUBY: 'RUBY', - S: 'S', - SAMP: 'SAMP', - SCRIPT: 'SCRIPT', - SECTION: 'SECTION', - SELECT: 'SELECT', - SMALL: 'SMALL', - SOURCE: 'SOURCE', - SPAN: 'SPAN', - STRIKE: 'STRIKE', - STRONG: 'STRONG', - STYLE: 'STYLE', - SUB: 'SUB', - SUMMARY: 'SUMMARY', - SUP: 'SUP', - SVG: 'SVG', - TABLE: 'TABLE', - TBODY: 'TBODY', - TD: 'TD', - TEMPLATE: 'TEMPLATE', - TEXTAREA: 'TEXTAREA', - TFOOT: 'TFOOT', - TH: 'TH', - THEAD: 'THEAD', - TIME: 'TIME', - TITLE: 'TITLE', - TR: 'TR', - TRACK: 'TRACK', - TT: 'TT', - U: 'U', - UL: 'UL', - VAR: 'VAR', - VIDEO: 'VIDEO', - WBR: 'WBR' -}; +// TODO(arv): Rename/refactor getTextContent and getRawTextContent. The problem +// is that getTextContent should mimic the DOM3 textContent. We should add a +// getInnerText (or getText) which tries to return the visible text, innerText. -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** - * @fileoverview Utilities for HTML element tag names. - */ -goog.provide('goog.dom.tags'); +goog.provide('goog.dom'); +goog.provide('goog.dom.Appendable'); +goog.provide('goog.dom.DomHelper'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.BrowserFeature'); +goog.require('goog.dom.NodeType'); +goog.require('goog.dom.TagName'); +goog.require('goog.dom.safe'); +goog.require('goog.html.SafeHtml'); +goog.require('goog.math.Coordinate'); +goog.require('goog.math.Size'); goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.string.Unicode'); +goog.require('goog.userAgent'); /** - * The void elements specified by - * http://www.w3.org/TR/html-markup/syntax.html#void-elements. - * @const @private {!Object<string, boolean>} + * @define {boolean} Whether we know at compile time that the browser is in + * quirks mode. */ -goog.dom.tags.VOID_TAGS_ = goog.object.createSet( - 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', - 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'); +goog.define('goog.dom.ASSUME_QUIRKS_MODE', false); /** - * Checks whether the tag is void (with no contents allowed and no legal end - * tag), for example 'br'. - * @param {string} tagName The tag name in lower case. - * @return {boolean} + * @define {boolean} Whether we know at compile time that the browser is in + * standards compliance mode. */ -goog.dom.tags.isVoidTag = function(tagName) { - return goog.dom.tags.VOID_TAGS_[tagName] === true; -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.string.TypedString'); - +goog.define('goog.dom.ASSUME_STANDARDS_MODE', false); /** - * Wrapper for strings that conform to a data type or language. - * - * Implementations of this interface are wrappers for strings, and typically - * associate a type contract with the wrapped string. Concrete implementations - * of this interface may choose to implement additional run-time type checking, - * see for example {@code goog.html.SafeHtml}. If available, client code that - * needs to ensure type membership of an object should use the type's function - * to assert type membership, such as {@code goog.html.SafeHtml.unwrap}. - * @interface + * Whether we know the compatibility mode at compile time. + * @type {boolean} + * @private */ -goog.string.TypedString = function() {}; +goog.dom.COMPAT_MODE_KNOWN_ = + goog.dom.ASSUME_QUIRKS_MODE || goog.dom.ASSUME_STANDARDS_MODE; /** - * Interface marker of the TypedString interface. - * - * This property can be used to determine at runtime whether or not an object - * implements this interface. All implementations of this interface set this - * property to {@code true}. - * @type {boolean} + * Gets the DomHelper object for the document where the element resides. + * @param {(Node|Window)=} opt_element If present, gets the DomHelper for this + * element. + * @return {!goog.dom.DomHelper} The DomHelper. */ -goog.string.TypedString.prototype.implementsGoogStringTypedString; +goog.dom.getDomHelper = function(opt_element) { + return opt_element ? + new goog.dom.DomHelper(goog.dom.getOwnerDocument(opt_element)) : + (goog.dom.defaultDomHelper_ || + (goog.dom.defaultDomHelper_ = new goog.dom.DomHelper())); +}; /** - * Retrieves this wrapped string's value. - * @return {!string} The wrapped string's value. + * Cached default DOM helper. + * @type {goog.dom.DomHelper} + * @private */ -goog.string.TypedString.prototype.getTypedStringValue; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.string.Const'); +goog.dom.defaultDomHelper_; -goog.require('goog.asserts'); -goog.require('goog.string.TypedString'); +/** + * Gets the document object being used by the dom library. + * @return {!Document} Document object. + */ +goog.dom.getDocument = function() { + return document; +}; /** - * Wrapper for compile-time-constant strings. - * - * Const is a wrapper for strings that can only be created from program - * constants (i.e., string literals). This property relies on a custom Closure - * compiler check that {@code goog.string.Const.from} is only invoked on - * compile-time-constant expressions. - * - * Const is useful in APIs whose correct and secure use requires that certain - * arguments are not attacker controlled: Compile-time constants are inherently - * under the control of the application and not under control of external - * attackers, and hence are safe to use in such contexts. + * Gets an element from the current document by element id. * - * Instances of this type must be created via its factory method - * {@code goog.string.Const.from} and not by invoking its constructor. The - * constructor intentionally takes no parameters and the type is immutable; - * hence only a default instance corresponding to the empty string can be - * obtained via constructor invocation. + * If an Element is passed in, it is returned. * - * @see goog.string.Const#from - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} + * @param {string|Element} element Element ID or a DOM node. + * @return {Element} The element with the given ID, or the node passed in. */ -goog.string.Const = function() { - /** - * The wrapped value of this Const object. The field has a purposely ugly - * name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.string.Const#unwrap - * @const - * @private - */ - this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ = - goog.string.Const.TYPE_MARKER_; +goog.dom.getElement = function(element) { + return goog.dom.getElementHelper_(document, element); }; /** - * @override - * @const + * Gets an element by id from the given document (if present). + * If an element is given, it is returned. + * @param {!Document} doc + * @param {string|Element} element Element ID or a DOM node. + * @return {Element} The resulting element. + * @private */ -goog.string.Const.prototype.implementsGoogStringTypedString = true; +goog.dom.getElementHelper_ = function(doc, element) { + return goog.isString(element) ? + doc.getElementById(element) : + element; +}; /** - * Returns this Const's value a string. + * Gets an element by id, asserting that the element is found. * - * IMPORTANT: In code where it is security-relevant that an object's type is - * indeed {@code goog.string.Const}, use {@code goog.string.Const.unwrap} - * instead of this method. + * This is used when an element is expected to exist, and should fail with + * an assertion error if it does not (if assertions are enabled). * - * @see goog.string.Const#unwrap - * @override + * @param {string} id Element ID. + * @return {!Element} The element with the given ID, if it exists. */ -goog.string.Const.prototype.getTypedStringValue = function() { - return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_; +goog.dom.getRequiredElement = function(id) { + return goog.dom.getRequiredElementHelper_(document, id); }; /** - * Returns a debug-string representation of this value. - * - * To obtain the actual string value wrapped inside an object of this type, - * use {@code goog.string.Const.unwrap}. - * - * @see goog.string.Const#unwrap - * @override + * Helper function for getRequiredElementHelper functions, both static and + * on DomHelper. Asserts the element with the given id exists. + * @param {!Document} doc + * @param {string} id + * @return {!Element} The element with the given ID, if it exists. + * @private */ -goog.string.Const.prototype.toString = function() { - return 'Const{' + - this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ + - '}'; +goog.dom.getRequiredElementHelper_ = function(doc, id) { + // To prevent users passing in Elements as is permitted in getElement(). + goog.asserts.assertString(id); + var element = goog.dom.getElementHelper_(doc, id); + element = goog.asserts.assertElement(element, + 'No element found with id: ' + id); + return element; }; /** - * Performs a runtime check that the provided object is indeed an instance - * of {@code goog.string.Const}, and returns its value. - * @param {!goog.string.Const} stringConst The object to extract from. - * @return {string} The Const object's contained string, unless the run-time - * type check fails. In that case, {@code unwrap} returns an innocuous - * string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * Alias for getElement. + * @param {string|Element} element Element ID or a DOM node. + * @return {Element} The element with the given ID, or the node passed in. + * @deprecated Use {@link goog.dom.getElement} instead. */ -goog.string.Const.unwrap = function(stringConst) { - // Perform additional run-time type-checking to ensure that stringConst is - // indeed an instance of the expected type. This provides some additional - // protection against security bugs due to application code that disables type - // checks. - if (stringConst instanceof goog.string.Const && - stringConst.constructor === goog.string.Const && - stringConst.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ === - goog.string.Const.TYPE_MARKER_) { - return stringConst. - stringConstValueWithSecurityContract__googStringSecurityPrivate_; - } else { - goog.asserts.fail('expected object of type Const, got \'' + - stringConst + '\''); - return 'type_error:Const'; - } -}; +goog.dom.$ = goog.dom.getElement; /** - * Creates a Const object from a compile-time constant string. - * - * It is illegal to invoke this function on an expression whose - * compile-time-contant value cannot be determined by the Closure compiler. - * - * Correct invocations include, - * <pre> - * var s = goog.string.Const.from('hello'); - * var t = goog.string.Const.from('hello' + 'world'); - * </pre> + * Looks up elements by both tag and class name, using browser native functions + * ({@code querySelectorAll}, {@code getElementsByTagName} or + * {@code getElementsByClassName}) where possible. This function + * is a useful, if limited, way of collecting a list of DOM elements + * with certain characteristics. {@code goog.dom.query} offers a + * more powerful and general solution which allows matching on CSS3 + * selector expressions, but at increased cost in code size. If all you + * need is particular tags belonging to a single class, this function + * is fast and sleek. * - * In contrast, the following are illegal: - * <pre> - * var s = goog.string.Const.from(getHello()); - * var t = goog.string.Const.from('hello' + world); - * </pre> + * Note that tag names are case sensitive in the SVG namespace, and this + * function converts opt_tag to uppercase for comparisons. For queries in the + * SVG namespace you should use querySelector or querySelectorAll instead. + * https://bugzilla.mozilla.org/show_bug.cgi?id=963870 + * https://bugs.webkit.org/show_bug.cgi?id=83438 * - * TODO(xtof): Compile-time checks that this function is only called - * with compile-time constant expressions. + * @see {goog.dom.query} * - * @param {string} s A constant string from which to create a Const. - * @return {!goog.string.Const} A Const object initialized to stringConst. + * @param {?string=} opt_tag Element tag name. + * @param {?string=} opt_class Optional class name. + * @param {(Document|Element)=} opt_el Optional element to look in. + * @return { {length: number} } Array-like list of elements (only a length + * property and numerical indices are guaranteed to exist). */ -goog.string.Const.from = function(s) { - return goog.string.Const.create__googStringSecurityPrivate_(s); +goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) { + return goog.dom.getElementsByTagNameAndClass_(document, opt_tag, opt_class, + opt_el); }; /** - * Type marker for the Const type, used to implement additional run-time - * type checking. - * @const {!Object} - * @private + * Returns a static, array-like list of the elements with the provided + * className. + * @see {goog.dom.query} + * @param {string} className the name of the class to look for. + * @param {(Document|Element)=} opt_el Optional element to look in. + * @return { {length: number} } The items found with the class name provided. */ -goog.string.Const.TYPE_MARKER_ = {}; +goog.dom.getElementsByClass = function(className, opt_el) { + var parent = opt_el || document; + if (goog.dom.canUseQuerySelector_(parent)) { + return parent.querySelectorAll('.' + className); + } + return goog.dom.getElementsByTagNameAndClass_( + document, '*', className, opt_el); +}; /** - * Utility method to create Const instances. - * @param {string} s The string to initialize the Const object with. - * @return {!goog.string.Const} The initialized Const object. - * @private + * Returns the first element with the provided className. + * @see {goog.dom.query} + * @param {string} className the name of the class to look for. + * @param {Element|Document=} opt_el Optional element to look in. + * @return {Element} The first item with the class name provided. */ -goog.string.Const.create__googStringSecurityPrivate_ = function(s) { - var stringConst = new goog.string.Const(); - stringConst.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = - s; - return stringConst; +goog.dom.getElementByClass = function(className, opt_el) { + var parent = opt_el || document; + var retVal = null; + if (parent.getElementsByClassName) { + retVal = parent.getElementsByClassName(className)[0]; + } else if (goog.dom.canUseQuerySelector_(parent)) { + retVal = parent.querySelector('.' + className); + } else { + retVal = goog.dom.getElementsByTagNameAndClass_( + document, '*', className, opt_el)[0]; + } + return retVal || null; }; -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview The SafeStyle type and its builders. - * - * TODO(xtof): Link to document stating type contract. + * Ensures an element with the given className exists, and then returns the + * first element with the provided className. + * @see {goog.dom.query} + * @param {string} className the name of the class to look for. + * @param {!Element|!Document=} opt_root Optional element or document to look + * in. + * @return {!Element} The first item with the class name provided. + * @throws {goog.asserts.AssertionError} Thrown if no element is found. */ +goog.dom.getRequiredElementByClass = function(className, opt_root) { + var retValue = goog.dom.getElementByClass(className, opt_root); + return goog.asserts.assert(retValue, + 'No element found with className: ' + className); +}; -goog.provide('goog.html.SafeStyle'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); +/** + * Prefer the standardized (http://www.w3.org/TR/selectors-api/), native and + * fast W3C Selectors API. + * @param {!(Element|Document)} parent The parent document object. + * @return {boolean} whether or not we can use parent.querySelector* APIs. + * @private + */ +goog.dom.canUseQuerySelector_ = function(parent) { + return !!(parent.querySelectorAll && parent.querySelector); +}; /** - * A string-like object which represents a sequence of CSS declarations - * ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...}) - * and that carries the security type contract that its value, as a string, - * will not cause untrusted script execution (XSS) when evaluated as CSS in a - * browser. - * - * Instances of this type must be created via the factory methods - * ({@code goog.html.SafeStyle.create} or - * {@code goog.html.SafeStyle.fromConstant}) and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty string - * can be obtained via constructor invocation. - * - * A SafeStyle's string representation ({@link #getTypedStringValue()}) can - * safely: - * <ul> - * <li>Be interpolated as the entire content of a *quoted* HTML style - * attribute, or before already existing properties. The SafeStyle string - * *must be HTML-attribute-escaped* (where " and ' are escaped) before - * interpolation. - * <li>Be interpolated as the entire content of a {}-wrapped block within a - * stylesheet, or before already existing properties. The SafeStyle string - * should not be escaped before interpolation. SafeStyle's contract also - * guarantees that the string will not be able to introduce new properties - * or elide existing ones. - * <li>Be assigned to the style property of a DOM node. The SafeStyle string - * should not be escaped before being assigned to the property. - * </ul> - * - * A SafeStyle may never contain literal angle brackets. Otherwise, it could - * be unsafe to place a SafeStyle into a <style> tag (where it can't - * be HTML escaped). For example, if the SafeStyle containing - * "{@code font: 'foo <style/><script>evil</script>'}" were - * interpolated within a <style> tag, this would then break out of the - * style context into HTML. - * - * A SafeStyle may contain literal single or double quotes, and as such the - * entire style string must be escaped when used in a style attribute (if - * this were not the case, the string could contain a matching quote that - * would escape from the style attribute). - * - * Values of this type must be composable, i.e. for any two values - * {@code style1} and {@code style2} of this type, - * {@code goog.html.SafeStyle.unwrap(style1) + - * goog.html.SafeStyle.unwrap(style2)} must itself be a value that satisfies - * the SafeStyle type constraint. This requirement implies that for any value - * {@code style} of this type, {@code goog.html.SafeStyle.unwrap(style)} must - * not end in a "property value" or "property name" context. For example, - * a value of {@code background:url("} or {@code font-} would not satisfy the - * SafeStyle contract. This is because concatenating such strings with a - * second value that itself does not contain unsafe CSS can result in an - * overall string that does. For example, if {@code javascript:evil())"} is - * appended to {@code background:url("}, the resulting string may result in - * the execution of a malicious script. - * - * TODO(user): Consider whether we should implement UTF-8 interchange - * validity checks and blacklisting of newlines (including Unicode ones) and - * other whitespace characters (\t, \f). Document here if so and also update - * SafeStyle.fromConstant(). - * - * The following example values comply with this type's contract: - * <ul> - * <li><pre>width: 1em;</pre> - * <li><pre>height:1em;</pre> - * <li><pre>width: 1em;height: 1em;</pre> - * <li><pre>background:url('http://url');</pre> - * </ul> - * In addition, the empty string is safe for use in a CSS attribute. - * - * The following example values do NOT comply with this type's contract: - * <ul> - * <li><pre>background: red</pre> (missing a trailing semi-colon) - * <li><pre>background:</pre> (missing a value and a trailing semi-colon) - * <li><pre>1em</pre> (missing an attribute name, which provides context for - * the value) - * </ul> - * - * @see goog.html.SafeStyle#create - * @see goog.html.SafeStyle#fromConstant - * @see http://www.w3.org/TR/css3-syntax/ - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} + * Helper for {@code getElementsByTagNameAndClass}. + * @param {!Document} doc The document to get the elements in. + * @param {?string=} opt_tag Element tag name. + * @param {?string=} opt_class Optional class name. + * @param {(Document|Element)=} opt_el Optional element to look in. + * @return { {length: number} } Array-like list of elements (only a length + * property and numerical indices are guaranteed to exist). + * @private */ -goog.html.SafeStyle = function() { - /** - * The contained value of this SafeStyle. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = ''; +goog.dom.getElementsByTagNameAndClass_ = function(doc, opt_tag, opt_class, + opt_el) { + var parent = opt_el || doc; + var tagName = (opt_tag && opt_tag != '*') ? opt_tag.toUpperCase() : ''; - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeStyle#unwrap - * @const - * @private - */ - this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; + if (goog.dom.canUseQuerySelector_(parent) && + (tagName || opt_class)) { + var query = tagName + (opt_class ? '.' + opt_class : ''); + return parent.querySelectorAll(query); + } + + // Use the native getElementsByClassName if available, under the assumption + // that even when the tag name is specified, there will be fewer elements to + // filter through when going by class than by tag name + if (opt_class && parent.getElementsByClassName) { + var els = parent.getElementsByClassName(opt_class); + + if (tagName) { + var arrayLike = {}; + var len = 0; + + // Filter for specific tags if requested. + for (var i = 0, el; el = els[i]; i++) { + if (tagName == el.nodeName) { + arrayLike[len++] = el; + } + } + arrayLike.length = len; + + return arrayLike; + } else { + return els; + } + } + + var els = parent.getElementsByTagName(tagName || '*'); + + if (opt_class) { + var arrayLike = {}; + var len = 0; + for (var i = 0, el; el = els[i]; i++) { + var className = el.className; + // Check if className has a split function since SVG className does not. + if (typeof className.split == 'function' && + goog.array.contains(className.split(/\s+/), opt_class)) { + arrayLike[len++] = el; + } + } + arrayLike.length = len; + return arrayLike; + } else { + return els; + } }; /** - * @override - * @const + * Alias for {@code getElementsByTagNameAndClass}. + * @param {?string=} opt_tag Element tag name. + * @param {?string=} opt_class Optional class name. + * @param {Element=} opt_el Optional element to look in. + * @return { {length: number} } Array-like list of elements (only a length + * property and numerical indices are guaranteed to exist). + * @deprecated Use {@link goog.dom.getElementsByTagNameAndClass} instead. */ -goog.html.SafeStyle.prototype.implementsGoogStringTypedString = true; +goog.dom.$$ = goog.dom.getElementsByTagNameAndClass; /** - * Type marker for the SafeStyle type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private + * Sets multiple properties on a node. + * @param {Element} element DOM node to set properties on. + * @param {Object} properties Hash of property:value pairs. */ -goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; +goog.dom.setProperties = function(element, properties) { + goog.object.forEach(properties, function(val, key) { + if (key == 'style') { + element.style.cssText = val; + } else if (key == 'class') { + element.className = val; + } else if (key == 'for') { + element.htmlFor = val; + } else if (goog.dom.DIRECT_ATTRIBUTE_MAP_.hasOwnProperty(key)) { + element.setAttribute(goog.dom.DIRECT_ATTRIBUTE_MAP_[key], val); + } else if (goog.string.startsWith(key, 'aria-') || + goog.string.startsWith(key, 'data-')) { + element.setAttribute(key, val); + } else { + element[key] = val; + } + }); +}; /** - * Creates a SafeStyle object from a compile-time constant string. + * Map of attributes that should be set using + * element.setAttribute(key, val) instead of element[key] = val. Used + * by goog.dom.setProperties. * - * {@code style} should be in the format - * {@code name: value; [name: value; ...]} and must not have any < or > - * characters in it. This is so that SafeStyle's contract is preserved, - * allowing the SafeStyle to correctly be interpreted as a sequence of CSS - * declarations and without affecting the syntactic structure of any - * surrounding CSS and HTML. + * @private {!Object<string, string>} + * @const + */ +goog.dom.DIRECT_ATTRIBUTE_MAP_ = { + 'cellpadding': 'cellPadding', + 'cellspacing': 'cellSpacing', + 'colspan': 'colSpan', + 'frameborder': 'frameBorder', + 'height': 'height', + 'maxlength': 'maxLength', + 'role': 'role', + 'rowspan': 'rowSpan', + 'type': 'type', + 'usemap': 'useMap', + 'valign': 'vAlign', + 'width': 'width' +}; + + +/** + * Gets the dimensions of the viewport. * - * This method performs basic sanity checks on the format of {@code style} - * but does not constrain the format of {@code name} and {@code value}, except - * for disallowing tag characters. + * Gecko Standards mode: + * docEl.clientWidth Width of viewport excluding scrollbar. + * win.innerWidth Width of viewport including scrollbar. + * body.clientWidth Width of body element. * - * @param {!goog.string.Const} style A compile-time-constant string from which - * to create a SafeStyle. - * @return {!goog.html.SafeStyle} A SafeStyle object initialized to - * {@code style}. + * docEl.clientHeight Height of viewport excluding scrollbar. + * win.innerHeight Height of viewport including scrollbar. + * body.clientHeight Height of document. + * + * Gecko Backwards compatible mode: + * docEl.clientWidth Width of viewport excluding scrollbar. + * win.innerWidth Width of viewport including scrollbar. + * body.clientWidth Width of viewport excluding scrollbar. + * + * docEl.clientHeight Height of document. + * win.innerHeight Height of viewport including scrollbar. + * body.clientHeight Height of viewport excluding scrollbar. + * + * IE6/7 Standards mode: + * docEl.clientWidth Width of viewport excluding scrollbar. + * win.innerWidth Undefined. + * body.clientWidth Width of body element. + * + * docEl.clientHeight Height of viewport excluding scrollbar. + * win.innerHeight Undefined. + * body.clientHeight Height of document element. + * + * IE5 + IE6/7 Backwards compatible mode: + * docEl.clientWidth 0. + * win.innerWidth Undefined. + * body.clientWidth Width of viewport excluding scrollbar. + * + * docEl.clientHeight 0. + * win.innerHeight Undefined. + * body.clientHeight Height of viewport excluding scrollbar. + * + * Opera 9 Standards and backwards compatible mode: + * docEl.clientWidth Width of viewport excluding scrollbar. + * win.innerWidth Width of viewport including scrollbar. + * body.clientWidth Width of viewport excluding scrollbar. + * + * docEl.clientHeight Height of document. + * win.innerHeight Height of viewport including scrollbar. + * body.clientHeight Height of viewport excluding scrollbar. + * + * WebKit: + * Safari 2 + * docEl.clientHeight Same as scrollHeight. + * docEl.clientWidth Same as innerWidth. + * win.innerWidth Width of viewport excluding scrollbar. + * win.innerHeight Height of the viewport including scrollbar. + * frame.innerHeight Height of the viewport exluding scrollbar. + * + * Safari 3 (tested in 522) + * + * docEl.clientWidth Width of viewport excluding scrollbar. + * docEl.clientHeight Height of viewport excluding scrollbar in strict mode. + * body.clientHeight Height of viewport excluding scrollbar in quirks mode. + * + * @param {Window=} opt_window Optional window element to test. + * @return {!goog.math.Size} Object with values 'width' and 'height'. */ -goog.html.SafeStyle.fromConstant = function(style) { - var styleString = goog.string.Const.unwrap(style); - if (styleString.length === 0) { - return goog.html.SafeStyle.EMPTY; - } - goog.html.SafeStyle.checkStyle_(styleString); - goog.asserts.assert(goog.string.endsWith(styleString, ';'), - 'Last character of style string is not \';\': ' + styleString); - goog.asserts.assert(goog.string.contains(styleString, ':'), - 'Style string must contain at least one \':\', to ' + - 'specify a "name: value" pair: ' + styleString); - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - styleString); +goog.dom.getViewportSize = function(opt_window) { + // TODO(arv): This should not take an argument + return goog.dom.getViewportSize_(opt_window || window); }; /** - * Checks if the style definition is valid. - * @param {string} style + * Helper for {@code getViewportSize}. + * @param {Window} win The window to get the view port size for. + * @return {!goog.math.Size} Object with values 'width' and 'height'. * @private */ -goog.html.SafeStyle.checkStyle_ = function(style) { - goog.asserts.assert(!/[<>]/.test(style), - 'Forbidden characters in style string: ' + style); +goog.dom.getViewportSize_ = function(win) { + var doc = win.document; + var el = goog.dom.isCss1CompatMode_(doc) ? doc.documentElement : doc.body; + return new goog.math.Size(el.clientWidth, el.clientHeight); }; /** - * Returns this SafeStyle's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeStyle}, use {@code goog.html.SafeStyle.unwrap} instead of - * this method. If in doubt, assume that it's security relevant. In particular, - * note that goog.html functions which return a goog.html type do not guarantee - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> + * Calculates the height of the document. * - * @see goog.html.SafeStyle#unwrap - * @override + * @return {number} The height of the current document. */ -goog.html.SafeStyle.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeStyleWrappedValue_; +goog.dom.getDocumentHeight = function() { + return goog.dom.getDocumentHeight_(window); }; -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeStyle, use - * {@code goog.html.SafeStyle.unwrap}. - * - * @see goog.html.SafeStyle#unwrap - * @override - */ - goog.html.SafeStyle.prototype.toString = function() { - return 'SafeStyle{' + - this.privateDoNotAccessOrElseSafeStyleWrappedValue_ + '}'; - }; -} - - /** - * Performs a runtime check that the provided object is indeed a - * SafeStyle object, and returns its value. + * Calculates the height of the document of the given window. * - * @param {!goog.html.SafeStyle} safeStyle The object to extract from. - * @return {string} The safeStyle object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * Function code copied from the opensocial gadget api: + * gadgets.window.adjustHeight(opt_height) + * + * @private + * @param {!Window} win The window whose document height to retrieve. + * @return {number} The height of the document of the given window. */ -goog.html.SafeStyle.unwrap = function(safeStyle) { - // Perform additional Run-time type-checking to ensure that - // safeStyle is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeStyle instanceof goog.html.SafeStyle && - safeStyle.constructor === goog.html.SafeStyle && - safeStyle.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_; - } else { - goog.asserts.fail( - 'expected object of type SafeStyle, got \'' + safeStyle + '\''); - return 'type_error:SafeStyle'; +goog.dom.getDocumentHeight_ = function(win) { + // NOTE(eae): This method will return the window size rather than the document + // size in webkit quirks mode. + var doc = win.document; + var height = 0; + + if (doc) { + // Calculating inner content height is hard and different between + // browsers rendering in Strict vs. Quirks mode. We use a combination of + // three properties within document.body and document.documentElement: + // - scrollHeight + // - offsetHeight + // - clientHeight + // These values differ significantly between browsers and rendering modes. + // But there are patterns. It just takes a lot of time and persistence + // to figure out. + + var body = doc.body; + var docEl = /** @type {!HTMLElement} */ (doc.documentElement); + if (!(docEl && body)) { + return 0; + } + + // Get the height of the viewport + var vh = goog.dom.getViewportSize_(win).height; + if (goog.dom.isCss1CompatMode_(doc) && docEl.scrollHeight) { + // In Strict mode: + // The inner content height is contained in either: + // document.documentElement.scrollHeight + // document.documentElement.offsetHeight + // Based on studying the values output by different browsers, + // use the value that's NOT equal to the viewport height found above. + height = docEl.scrollHeight != vh ? + docEl.scrollHeight : docEl.offsetHeight; + } else { + // In Quirks mode: + // documentElement.clientHeight is equal to documentElement.offsetHeight + // except in IE. In most browsers, document.documentElement can be used + // to calculate the inner content height. + // However, in other browsers (e.g. IE), document.body must be used + // instead. How do we know which one to use? + // If document.documentElement.clientHeight does NOT equal + // document.documentElement.offsetHeight, then use document.body. + var sh = docEl.scrollHeight; + var oh = docEl.offsetHeight; + if (docEl.clientHeight != oh) { + sh = body.scrollHeight; + oh = body.offsetHeight; + } + + // Detect whether the inner content height is bigger or smaller + // than the bounding box (viewport). If bigger, take the larger + // value. If smaller, take the smaller value. + if (sh > vh) { + // Content is larger + height = sh > oh ? sh : oh; + } else { + // Content is smaller + height = sh < oh ? sh : oh; + } + } } + + return height; }; /** - * Package-internal utility method to create SafeStyle instances. + * Gets the page scroll distance as a coordinate object. * - * @param {string} style The string to initialize the SafeStyle object with. - * @return {!goog.html.SafeStyle} The initialized SafeStyle object. - * @package + * @param {Window=} opt_window Optional window element to test. + * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. + * @deprecated Use {@link goog.dom.getDocumentScroll} instead. */ -goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse = - function(style) { - return new goog.html.SafeStyle().initSecurityPrivateDoNotAccessOrElse_(style); +goog.dom.getPageScroll = function(opt_window) { + var win = opt_window || goog.global || window; + return goog.dom.getDomHelper(win.document).getDocumentScroll(); }; /** - * Called from createSafeStyleSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} style - * @return {!goog.html.SafeStyle} - * @private + * Gets the document scroll distance as a coordinate object. + * + * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. */ -goog.html.SafeStyle.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( - style) { - this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = style; - return this; +goog.dom.getDocumentScroll = function() { + return goog.dom.getDocumentScroll_(document); }; /** - * A SafeStyle instance corresponding to the empty string. - * @const {!goog.html.SafeStyle} + * Helper for {@code getDocumentScroll}. + * + * @param {!Document} doc The document to get the scroll for. + * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. + * @private */ -goog.html.SafeStyle.EMPTY = - goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(''); +goog.dom.getDocumentScroll_ = function(doc) { + var el = goog.dom.getDocumentScrollElement_(doc); + var win = goog.dom.getWindow_(doc); + if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('10') && + win.pageYOffset != el.scrollTop) { + // The keyboard on IE10 touch devices shifts the page using the pageYOffset + // without modifying scrollTop. For this case, we want the body scroll + // offsets. + return new goog.math.Coordinate(el.scrollLeft, el.scrollTop); + } + return new goog.math.Coordinate(win.pageXOffset || el.scrollLeft, + win.pageYOffset || el.scrollTop); +}; /** - * The innocuous string generated by goog.html.SafeUrl.create when passed - * an unsafe value. - * @const {string} + * Gets the document scroll element. + * @return {!Element} Scrolling element. */ -goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez'; +goog.dom.getDocumentScrollElement = function() { + return goog.dom.getDocumentScrollElement_(document); +}; /** - * Mapping of property names to their values. - * @typedef {!Object<string, goog.string.Const|string>} + * Helper for {@code getDocumentScrollElement}. + * @param {!Document} doc The document to get the scroll element for. + * @return {!Element} Scrolling element. + * @private */ -goog.html.SafeStyle.PropertyMap; +goog.dom.getDocumentScrollElement_ = function(doc) { + // Old WebKit needs body.scrollLeft in both quirks mode and strict mode. We + // also default to the documentElement if the document does not have a body + // (e.g. a SVG document). + // Uses http://dev.w3.org/csswg/cssom-view/#dom-document-scrollingelement to + // avoid trying to guess about browser behavior from the UA string. + if (doc.scrollingElement) { + return doc.scrollingElement; + } + if (!goog.userAgent.WEBKIT && goog.dom.isCss1CompatMode_(doc)) { + return doc.documentElement; + } + return doc.body || doc.documentElement; +}; /** - * Creates a new SafeStyle object from the properties specified in the map. - * @param {goog.html.SafeStyle.PropertyMap} map Mapping of property names to - * their values, for example {'margin': '1px'}. Names must consist of - * [-_a-zA-Z0-9]. Values might be strings consisting of - * [-,.'"%_!# a-zA-Z0-9], where " and ' must be properly balanced. - * Other values must be wrapped in goog.string.Const. Null value causes - * skipping the property. - * @return {!goog.html.SafeStyle} - * @throws {Error} If invalid name is provided. - * @throws {goog.asserts.AssertionError} If invalid value is provided. With - * disabled assertions, invalid value is replaced by - * goog.html.SafeStyle.INNOCUOUS_STRING. + * Gets the window object associated with the given document. + * + * @param {Document=} opt_doc Document object to get window for. + * @return {!Window} The window associated with the given document. */ -goog.html.SafeStyle.create = function(map) { - var style = ''; - for (var name in map) { - if (!/^[-_a-zA-Z0-9]+$/.test(name)) { - throw Error('Name allows only [-_a-zA-Z0-9], got: ' + name); - } - var value = map[name]; - if (value == null) { - continue; - } - if (value instanceof goog.string.Const) { - value = goog.string.Const.unwrap(value); - // These characters can be used to change context and we don't want that - // even with const values. - goog.asserts.assert(!/[{;}]/.test(value), 'Value does not allow [{;}].'); - } else if (!goog.html.SafeStyle.VALUE_RE_.test(value)) { - goog.asserts.fail( - 'String value allows only [-,."\'%_!# a-zA-Z0-9], got: ' + value); - value = goog.html.SafeStyle.INNOCUOUS_STRING; - } else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) { - goog.asserts.fail('String value requires balanced quotes, got: ' + value); - value = goog.html.SafeStyle.INNOCUOUS_STRING; - } - style += name + ':' + value + ';'; - } - if (!style) { - return goog.html.SafeStyle.EMPTY; - } - goog.html.SafeStyle.checkStyle_(style); - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - style); +goog.dom.getWindow = function(opt_doc) { + // TODO(arv): This should not take an argument. + return opt_doc ? goog.dom.getWindow_(opt_doc) : window; }; /** - * Checks that quotes (" and ') are properly balanced inside a string. Assumes - * that neither escape (\) nor any other character that could result in - * breaking out of a string parsing context are allowed; - * see http://www.w3.org/TR/css3-syntax/#string-token-diagram. - * @param {string} value Untrusted CSS property value. - * @return {boolean} True if property value is safe with respect to quote - * balancedness. + * Helper for {@code getWindow}. + * + * @param {!Document} doc Document object to get window for. + * @return {!Window} The window associated with the given document. * @private */ -goog.html.SafeStyle.hasBalancedQuotes_ = function(value) { - var outsideSingle = true; - var outsideDouble = true; - for (var i = 0; i < value.length; i++) { - var c = value.charAt(i); - if (c == "'" && outsideDouble) { - outsideSingle = !outsideSingle; - } else if (c == '"' && outsideSingle) { - outsideDouble = !outsideDouble; - } - } - return outsideSingle && outsideDouble; +goog.dom.getWindow_ = function(doc) { + return doc.parentWindow || doc.defaultView; }; -// Keep in sync with the error string in create(). /** - * Regular expression for safe values. + * Returns a dom node with a set of attributes. This function accepts varargs + * for subsequent nodes to be added. Subsequent nodes will be added to the + * first node as childNodes. * - * Quotes (" and ') are allowed, but a check must be done elsewhere to ensure - * they're balanced. + * So: + * <code>createDom('div', null, createDom('p'), createDom('p'));</code> + * would return a div with two child paragraphs * - * ',' allows multiple values to be assigned to the same property - * (e.g. background-attachment or font-family) and hence could allow - * multiple values to get injected, but that should pose no risk of XSS. - * @const {!RegExp} - * @private + * @param {string} tagName Tag to create. + * @param {(Object|Array<string>|string)=} opt_attributes If object, then a map + * of name-value pairs for attributes. If a string, then this is the + * className of the new element. If an array, the elements will be joined + * together as the className of the new element. + * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or + * strings for text nodes. If one of the var_args is an array or NodeList, + * its elements will be added as childNodes instead. + * @return {!Element} Reference to a DOM node. */ -goog.html.SafeStyle.VALUE_RE_ = /^[-,."'%_!# a-zA-Z0-9]+$/; +goog.dom.createDom = function(tagName, opt_attributes, var_args) { + return goog.dom.createDom_(document, arguments); +}; /** - * Creates a new SafeStyle object by concatenating the values. - * @param {...(!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>)} var_args - * SafeStyles to concatenate. - * @return {!goog.html.SafeStyle} + * Helper for {@code createDom}. + * @param {!Document} doc The document to create the DOM in. + * @param {!Arguments} args Argument object passed from the callers. See + * {@code goog.dom.createDom} for details. + * @return {!Element} Reference to a DOM node. + * @private */ -goog.html.SafeStyle.concat = function(var_args) { - var style = ''; +goog.dom.createDom_ = function(doc, args) { + var tagName = args[0]; + var attributes = args[1]; - /** - * @param {!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>} argument - */ - var addArgument = function(argument) { - if (goog.isArray(argument)) { - goog.array.forEach(argument, addArgument); + // Internet Explorer is dumb: + // name: https://msdn.microsoft.com/en-us/library/ms534184(v=vs.85).aspx + // type: https://msdn.microsoft.com/en-us/library/ms534700(v=vs.85).aspx + // Also does not allow setting of 'type' attribute on 'input' or 'button'. + if (!goog.dom.BrowserFeature.CAN_ADD_NAME_OR_TYPE_ATTRIBUTES && attributes && + (attributes.name || attributes.type)) { + var tagNameArr = ['<', tagName]; + if (attributes.name) { + tagNameArr.push(' name="', goog.string.htmlEscape(attributes.name), '"'); + } + if (attributes.type) { + tagNameArr.push(' type="', goog.string.htmlEscape(attributes.type), '"'); + + // Clone attributes map to remove 'type' without mutating the input. + var clone = {}; + goog.object.extend(clone, attributes); + + // JSCompiler can't see how goog.object.extend added this property, + // because it was essentially added by reflection. + // So it needs to be quoted. + delete clone['type']; + + attributes = clone; + } + tagNameArr.push('>'); + tagName = tagNameArr.join(''); + } + + var element = doc.createElement(tagName); + + if (attributes) { + if (goog.isString(attributes)) { + element.className = attributes; + } else if (goog.isArray(attributes)) { + element.className = attributes.join(' '); } else { - style += goog.html.SafeStyle.unwrap(argument); + goog.dom.setProperties(element, attributes); } - }; + } - goog.array.forEach(arguments, addArgument); - if (!style) { - return goog.html.SafeStyle.EMPTY; + if (args.length > 2) { + goog.dom.append_(doc, element, args, 2); } - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - style); + + return element; }; -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview The SafeStyleSheet type and its builders. - * - * TODO(xtof): Link to document stating type contract. + * Appends a node with text or other nodes. + * @param {!Document} doc The document to create new nodes in. + * @param {!Node} parent The node to append nodes to. + * @param {!Arguments} args The values to add. See {@code goog.dom.append}. + * @param {number} startIndex The index of the array to start from. + * @private */ +goog.dom.append_ = function(doc, parent, args, startIndex) { + function childHandler(child) { + // TODO(user): More coercion, ala MochiKit? + if (child) { + parent.appendChild(goog.isString(child) ? + doc.createTextNode(child) : child); + } + } -goog.provide('goog.html.SafeStyleSheet'); + for (var i = startIndex; i < args.length; i++) { + var arg = args[i]; + // TODO(attila): Fix isArrayLike to return false for a text node. + if (goog.isArrayLike(arg) && !goog.dom.isNodeLike(arg)) { + // If the argument is a node list, not a real array, use a clone, + // because forEach can't be used to mutate a NodeList. + goog.array.forEach(goog.dom.isNodeList(arg) ? + goog.array.toArray(arg) : arg, + childHandler); + } else { + childHandler(arg); + } + } +}; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); +/** + * Alias for {@code createDom}. + * @param {string} tagName Tag to create. + * @param {(string|Object)=} opt_attributes If object, then a map of name-value + * pairs for attributes. If a string, then this is the className of the new + * element. + * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or + * strings for text nodes. If one of the var_args is an array, its + * children will be added as childNodes instead. + * @return {!Element} Reference to a DOM node. + * @deprecated Use {@link goog.dom.createDom} instead. + */ +goog.dom.$dom = goog.dom.createDom; /** - * A string-like object which represents a CSS style sheet and that carries the - * security type contract that its value, as a string, will not cause untrusted - * script execution (XSS) when evaluated as CSS in a browser. - * - * Instances of this type must be created via the factory method - * {@code goog.html.SafeStyleSheet.fromConstant} and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty string - * can be obtained via constructor invocation. - * - * A SafeStyleSheet's string representation can safely be interpolated as the - * content of a style element within HTML. The SafeStyleSheet string should - * not be escaped before interpolation. - * - * Values of this type must be composable, i.e. for any two values - * {@code styleSheet1} and {@code styleSheet2} of this type, - * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1) + - * goog.html.SafeStyleSheet.unwrap(styleSheet2)} must itself be a value that - * satisfies the SafeStyleSheet type constraint. This requirement implies that - * for any value {@code styleSheet} of this type, - * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1)} must end in - * "beginning of rule" context. - - * A SafeStyleSheet can be constructed via security-reviewed unchecked - * conversions. In this case producers of SafeStyleSheet must ensure themselves - * that the SafeStyleSheet does not contain unsafe script. Note in particular - * that {@code <} is dangerous, even when inside CSS strings, and so should - * always be forbidden or CSS-escaped in user controlled input. For example, if - * {@code </style><script>evil</script>"} were interpolated - * inside a CSS string, it would break out of the context of the original - * style element and {@code evil} would execute. Also note that within an HTML - * style (raw text) element, HTML character references, such as - * {@code &lt;}, are not allowed. See - * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements - * (similar considerations apply to the style element). - * - * @see goog.html.SafeStyleSheet#fromConstant - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} + * Creates a new element. + * @param {string} name Tag name. + * @return {!Element} The new element. */ -goog.html.SafeStyleSheet = function() { - /** - * The contained value of this SafeStyleSheet. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeStyleSheet#unwrap - * @const - * @private - */ - this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; +goog.dom.createElement = function(name) { + return document.createElement(name); }; /** - * @override - * @const + * Creates a new text node. + * @param {number|string} content Content. + * @return {!Text} The new text node. */ -goog.html.SafeStyleSheet.prototype.implementsGoogStringTypedString = true; +goog.dom.createTextNode = function(content) { + return document.createTextNode(String(content)); +}; /** - * Type marker for the SafeStyleSheet type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private + * Create a table. + * @param {number} rows The number of rows in the table. Must be >= 1. + * @param {number} columns The number of columns in the table. Must be >= 1. + * @param {boolean=} opt_fillWithNbsp If true, fills table entries with + * {@code goog.string.Unicode.NBSP} characters. + * @return {!Element} The created table. */ -goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; +goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) { + // TODO(user): Return HTMLTableElement, also in prototype function. + // Callers need to be updated to e.g. not assign numbers to table.cellSpacing. + return goog.dom.createTable_(document, rows, columns, !!opt_fillWithNbsp); +}; /** - * Creates a new SafeStyleSheet object by concatenating values. - * @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)} - * var_args Values to concatenate. - * @return {!goog.html.SafeStyleSheet} + * Create a table. + * @param {!Document} doc Document object to use to create the table. + * @param {number} rows The number of rows in the table. Must be >= 1. + * @param {number} columns The number of columns in the table. Must be >= 1. + * @param {boolean} fillWithNbsp If true, fills table entries with + * {@code goog.string.Unicode.NBSP} characters. + * @return {!HTMLTableElement} The created table. + * @private */ -goog.html.SafeStyleSheet.concat = function(var_args) { - var result = ''; - - /** - * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>} - * argument - */ - var addArgument = function(argument) { - if (goog.isArray(argument)) { - goog.array.forEach(argument, addArgument); - } else { - result += goog.html.SafeStyleSheet.unwrap(argument); +goog.dom.createTable_ = function(doc, rows, columns, fillWithNbsp) { + var table = /** @type {!HTMLTableElement} */ + (doc.createElement(goog.dom.TagName.TABLE)); + var tbody = table.appendChild(doc.createElement(goog.dom.TagName.TBODY)); + for (var i = 0; i < rows; i++) { + var tr = doc.createElement(goog.dom.TagName.TR); + for (var j = 0; j < columns; j++) { + var td = doc.createElement(goog.dom.TagName.TD); + // IE <= 9 will create a text node if we set text content to the empty + // string, so we avoid doing it unless necessary. This ensures that the + // same DOM tree is returned on all browsers. + if (fillWithNbsp) { + goog.dom.setTextContent(td, goog.string.Unicode.NBSP); + } + tr.appendChild(td); } - }; + tbody.appendChild(tr); + } + return table; +}; - goog.array.forEach(arguments, addArgument); - return goog.html.SafeStyleSheet - .createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(result); + +/** + * Converts HTML markup into a node. + * @param {!goog.html.SafeHtml} html The HTML markup to convert. + * @return {!Node} The resulting node. + */ +goog.dom.safeHtmlToNode = function(html) { + return goog.dom.safeHtmlToNode_(document, html); }; /** - * Creates a SafeStyleSheet object from a compile-time constant string. - * - * {@code styleSheet} must not have any < characters in it, so that - * the syntactic structure of the surrounding HTML is not affected. - * - * @param {!goog.string.Const} styleSheet A compile-time-constant string from - * which to create a SafeStyleSheet. - * @return {!goog.html.SafeStyleSheet} A SafeStyleSheet object initialized to - * {@code styleSheet}. + * Helper for {@code safeHtmlToNode}. + * @param {!Document} doc The document. + * @param {!goog.html.SafeHtml} html The HTML markup to convert. + * @return {!Node} The resulting node. + * @private */ -goog.html.SafeStyleSheet.fromConstant = function(styleSheet) { - var styleSheetString = goog.string.Const.unwrap(styleSheet); - if (styleSheetString.length === 0) { - return goog.html.SafeStyleSheet.EMPTY; +goog.dom.safeHtmlToNode_ = function(doc, html) { + var tempDiv = doc.createElement(goog.dom.TagName.DIV); + if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { + goog.dom.safe.setInnerHtml(tempDiv, + goog.html.SafeHtml.concat(goog.html.SafeHtml.create('br'), html)); + tempDiv.removeChild(tempDiv.firstChild); + } else { + goog.dom.safe.setInnerHtml(tempDiv, html); } - // > is a valid character in CSS selectors and there's no strict need to - // block it if we already block <. - goog.asserts.assert(!goog.string.contains(styleSheetString, '<'), - "Forbidden '<' character in style sheet string: " + styleSheetString); - return goog.html.SafeStyleSheet. - createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheetString); + return goog.dom.childrenToNode_(doc, tempDiv); }; /** - * Returns this SafeStyleSheet's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeStyleSheet}, use {@code goog.html.SafeStyleSheet.unwrap} - * instead of this method. If in doubt, assume that it's security relevant. In - * particular, note that goog.html functions which return a goog.html type do - * not guarantee the returned instance is of the right type. For example: + * Converts an HTML string into a document fragment. The string must be + * sanitized in order to avoid cross-site scripting. For example + * {@code goog.dom.htmlToDocumentFragment('<img src=x onerror=alert(0)>')} + * triggers an alert in all browsers, even if the returned document fragment + * is thrown away immediately. * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> + * NOTE: This method doesn't work if your htmlString contains elements that + * can't be contained in a <div>. For example, <tr>. * - * @see goog.html.SafeStyleSheet#unwrap - * @override + * @param {string} htmlString The HTML string to convert. + * @return {!Node} The resulting document fragment. */ -goog.html.SafeStyleSheet.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_; +goog.dom.htmlToDocumentFragment = function(htmlString) { + return goog.dom.htmlToDocumentFragment_(document, htmlString); }; -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeStyleSheet, use - * {@code goog.html.SafeStyleSheet.unwrap}. - * - * @see goog.html.SafeStyleSheet#unwrap - * @override - */ - goog.html.SafeStyleSheet.prototype.toString = function() { - return 'SafeStyleSheet{' + - this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ + '}'; - }; -} - - +// TODO(jakubvrana): Merge with {@code safeHtmlToNode_}. /** - * Performs a runtime check that the provided object is indeed a - * SafeStyleSheet object, and returns its value. + * Helper for {@code htmlToDocumentFragment}. * - * @param {!goog.html.SafeStyleSheet} safeStyleSheet The object to extract from. - * @return {string} The safeStyleSheet object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * @param {!Document} doc The document. + * @param {string} htmlString The HTML string to convert. + * @return {!Node} The resulting document fragment. + * @private */ -goog.html.SafeStyleSheet.unwrap = function(safeStyleSheet) { - // Perform additional Run-time type-checking to ensure that - // safeStyleSheet is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeStyleSheet instanceof goog.html.SafeStyleSheet && - safeStyleSheet.constructor === goog.html.SafeStyleSheet && - safeStyleSheet.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_; +goog.dom.htmlToDocumentFragment_ = function(doc, htmlString) { + var tempDiv = doc.createElement(goog.dom.TagName.DIV); + if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { + tempDiv.innerHTML = '<br>' + htmlString; + tempDiv.removeChild(tempDiv.firstChild); } else { - goog.asserts.fail( - "expected object of type SafeStyleSheet, got '" + safeStyleSheet + - "'"); - return 'type_error:SafeStyleSheet'; + tempDiv.innerHTML = htmlString; } + return goog.dom.childrenToNode_(doc, tempDiv); }; /** - * Package-internal utility method to create SafeStyleSheet instances. - * - * @param {string} styleSheet The string to initialize the SafeStyleSheet - * object with. - * @return {!goog.html.SafeStyleSheet} The initialized SafeStyleSheet object. - * @package - */ -goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse = - function(styleSheet) { - return new goog.html.SafeStyleSheet().initSecurityPrivateDoNotAccessOrElse_( - styleSheet); -}; - - -/** - * Called from createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} styleSheet - * @return {!goog.html.SafeStyleSheet} + * Helper for {@code htmlToDocumentFragment_}. + * @param {!Document} doc The document. + * @param {!Node} tempDiv The input node. + * @return {!Node} The resulting node. * @private */ -goog.html.SafeStyleSheet.prototype.initSecurityPrivateDoNotAccessOrElse_ = - function(styleSheet) { - this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = styleSheet; - return this; +goog.dom.childrenToNode_ = function(doc, tempDiv) { + if (tempDiv.childNodes.length == 1) { + return tempDiv.removeChild(tempDiv.firstChild); + } else { + var fragment = doc.createDocumentFragment(); + while (tempDiv.firstChild) { + fragment.appendChild(tempDiv.firstChild); + } + return fragment; + } }; /** - * A SafeStyleSheet instance corresponding to the empty string. - * @const {!goog.html.SafeStyleSheet} + * Returns true if the browser is in "CSS1-compatible" (standards-compliant) + * mode, false otherwise. + * @return {boolean} True if in CSS1-compatible mode. */ -goog.html.SafeStyleSheet.EMPTY = - goog.html.SafeStyleSheet. - createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(''); +goog.dom.isCss1CompatMode = function() { + return goog.dom.isCss1CompatMode_(document); +}; -// Copyright 2015 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Wrapper for URL and its createObjectUrl and revokeObjectUrl - * methods that are part of the HTML5 File API. + * Returns true if the browser is in "CSS1-compatible" (standards-compliant) + * mode, false otherwise. + * @param {!Document} doc The document to check. + * @return {boolean} True if in CSS1-compatible mode. + * @private */ +goog.dom.isCss1CompatMode_ = function(doc) { + if (goog.dom.COMPAT_MODE_KNOWN_) { + return goog.dom.ASSUME_STANDARDS_MODE; + } -goog.provide('goog.fs.url'); + return doc.compatMode == 'CSS1Compat'; +}; /** - * Creates a blob URL for a blob object. - * Throws an error if the browser does not support Object Urls. + * Determines if the given node can contain children, intended to be used for + * HTML generation. * - * @param {!Blob} blob The object for which to create the URL. - * @return {string} The URL for the object. + * IE natively supports node.canHaveChildren but has inconsistent behavior. + * Prior to IE8 the base tag allows children and in IE9 all nodes return true + * for canHaveChildren. + * + * In practice all non-IE browsers allow you to add children to any node, but + * the behavior is inconsistent: + * + * <pre> + * var a = document.createElement(goog.dom.TagName.BR); + * a.appendChild(document.createTextNode('foo')); + * a.appendChild(document.createTextNode('bar')); + * console.log(a.childNodes.length); // 2 + * console.log(a.innerHTML); // Chrome: "", IE9: "foobar", FF3.5: "foobar" + * </pre> + * + * For more information, see: + * http://dev.w3.org/html5/markup/syntax.html#syntax-elements + * + * TODO(user): Rename shouldAllowChildren() ? + * + * @param {Node} node The node to check. + * @return {boolean} Whether the node can contain children. */ -goog.fs.url.createObjectUrl = function(blob) { - return goog.fs.url.getUrlObject_().createObjectURL(blob); +goog.dom.canHaveChildren = function(node) { + if (node.nodeType != goog.dom.NodeType.ELEMENT) { + return false; + } + switch (/** @type {!Element} */ (node).tagName) { + case goog.dom.TagName.APPLET: + case goog.dom.TagName.AREA: + case goog.dom.TagName.BASE: + case goog.dom.TagName.BR: + case goog.dom.TagName.COL: + case goog.dom.TagName.COMMAND: + case goog.dom.TagName.EMBED: + case goog.dom.TagName.FRAME: + case goog.dom.TagName.HR: + case goog.dom.TagName.IMG: + case goog.dom.TagName.INPUT: + case goog.dom.TagName.IFRAME: + case goog.dom.TagName.ISINDEX: + case goog.dom.TagName.KEYGEN: + case goog.dom.TagName.LINK: + case goog.dom.TagName.NOFRAMES: + case goog.dom.TagName.NOSCRIPT: + case goog.dom.TagName.META: + case goog.dom.TagName.OBJECT: + case goog.dom.TagName.PARAM: + case goog.dom.TagName.SCRIPT: + case goog.dom.TagName.SOURCE: + case goog.dom.TagName.STYLE: + case goog.dom.TagName.TRACK: + case goog.dom.TagName.WBR: + return false; + } + return true; }; /** - * Revokes a URL created by {@link goog.fs.url.createObjectUrl}. - * Throws an error if the browser does not support Object Urls. - * - * @param {string} url The URL to revoke. + * Appends a child to a node. + * @param {Node} parent Parent. + * @param {Node} child Child. */ -goog.fs.url.revokeObjectUrl = function(url) { - goog.fs.url.getUrlObject_().revokeObjectURL(url); +goog.dom.appendChild = function(parent, child) { + parent.appendChild(child); }; /** - * @typedef {{createObjectURL: (function(!Blob): string), - * revokeObjectURL: function(string): void}} + * Appends a node with text or other nodes. + * @param {!Node} parent The node to append nodes to. + * @param {...goog.dom.Appendable} var_args The things to append to the node. + * If this is a Node it is appended as is. + * If this is a string then a text node is appended. + * If this is an array like object then fields 0 to length - 1 are appended. */ -goog.fs.url.UrlObject_; +goog.dom.append = function(parent, var_args) { + goog.dom.append_(goog.dom.getOwnerDocument(parent), parent, arguments, 1); +}; /** - * Get the object that has the createObjectURL and revokeObjectURL functions for - * this browser. - * - * @return {goog.fs.url.UrlObject_} The object for this browser. - * @private + * Removes all the child nodes on a DOM node. + * @param {Node} node Node to remove children from. */ -goog.fs.url.getUrlObject_ = function() { - var urlObject = goog.fs.url.findUrlObject_(); - if (urlObject != null) { - return urlObject; - } else { - throw Error('This browser doesn\'t seem to support blob URLs'); +goog.dom.removeChildren = function(node) { + // Note: Iterations over live collections can be slow, this is the fastest + // we could find. The double parenthesis are used to prevent JsCompiler and + // strict warnings. + var child; + while ((child = node.firstChild)) { + node.removeChild(child); } }; /** - * Finds the object that has the createObjectURL and revokeObjectURL functions - * for this browser. - * - * @return {?goog.fs.url.UrlObject_} The object for this browser or null if the - * browser does not support Object Urls. - * @private + * Inserts a new node before an existing reference node (i.e. as the previous + * sibling). If the reference node has no parent, then does nothing. + * @param {Node} newNode Node to insert. + * @param {Node} refNode Reference node to insert before. */ -goog.fs.url.findUrlObject_ = function() { - // This is what the spec says to do - // http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL - if (goog.isDef(goog.global.URL) && - goog.isDef(goog.global.URL.createObjectURL)) { - return /** @type {goog.fs.url.UrlObject_} */ (goog.global.URL); - // This is what Chrome does (as of 10.0.648.6 dev) - } else if (goog.isDef(goog.global.webkitURL) && - goog.isDef(goog.global.webkitURL.createObjectURL)) { - return /** @type {goog.fs.url.UrlObject_} */ (goog.global.webkitURL); - // This is what the spec used to say to do - } else if (goog.isDef(goog.global.createObjectURL)) { - return /** @type {goog.fs.url.UrlObject_} */ (goog.global); - } else { - return null; +goog.dom.insertSiblingBefore = function(newNode, refNode) { + if (refNode.parentNode) { + refNode.parentNode.insertBefore(newNode, refNode); } }; /** - * Checks whether this browser supports Object Urls. If not, calls to - * createObjectUrl and revokeObjectUrl will result in an error. - * - * @return {boolean} True if this browser supports Object Urls. + * Inserts a new node after an existing reference node (i.e. as the next + * sibling). If the reference node has no parent, then does nothing. + * @param {Node} newNode Node to insert. + * @param {Node} refNode Reference node to insert after. */ -goog.fs.url.browserSupportsObjectUrls = function() { - return goog.fs.url.findUrlObject_() != null; +goog.dom.insertSiblingAfter = function(newNode, refNode) { + if (refNode.parentNode) { + refNode.parentNode.insertBefore(newNode, refNode.nextSibling); + } }; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utility functions for supporting Bidi issues. + * Insert a child at a given index. If index is larger than the number of child + * nodes that the parent currently has, the node is inserted as the last child + * node. + * @param {Element} parent The element into which to insert the child. + * @param {Node} child The element to insert. + * @param {number} index The index at which to insert the new child node. Must + * not be negative. */ +goog.dom.insertChildAt = function(parent, child, index) { + // Note that if the second argument is null, insertBefore + // will append the child at the end of the list of children. + parent.insertBefore(child, parent.childNodes[index] || null); +}; /** - * Namespace for bidi supporting functions. + * Removes a node from its parent. + * @param {Node} node The node to remove. + * @return {Node} The node removed if removed; else, null. */ -goog.provide('goog.i18n.bidi'); -goog.provide('goog.i18n.bidi.Dir'); -goog.provide('goog.i18n.bidi.DirectionalString'); -goog.provide('goog.i18n.bidi.Format'); +goog.dom.removeNode = function(node) { + return node && node.parentNode ? node.parentNode.removeChild(node) : null; +}; /** - * @define {boolean} FORCE_RTL forces the {@link goog.i18n.bidi.IS_RTL} constant - * to say that the current locale is a RTL locale. This should only be used - * if you want to override the default behavior for deciding whether the - * current locale is RTL or not. - * - * {@see goog.i18n.bidi.IS_RTL} + * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no + * parent. + * @param {Node} newNode Node to insert. + * @param {Node} oldNode Node to replace. */ -goog.define('goog.i18n.bidi.FORCE_RTL', false); +goog.dom.replaceNode = function(newNode, oldNode) { + var parent = oldNode.parentNode; + if (parent) { + parent.replaceChild(newNode, oldNode); + } +}; /** - * Constant that defines whether or not the current locale is a RTL locale. - * If {@link goog.i18n.bidi.FORCE_RTL} is not true, this constant will default - * to check that {@link goog.LOCALE} is one of a few major RTL locales. - * - * <p>This is designed to be a maximally efficient compile-time constant. For - * example, for the default goog.LOCALE, compiling - * "if (goog.i18n.bidi.IS_RTL) alert('rtl') else {}" should produce no code. It - * is this design consideration that limits the implementation to only - * supporting a few major RTL locales, as opposed to the broader repertoire of - * something like goog.i18n.bidi.isRtlLanguage. - * - * <p>Since this constant refers to the directionality of the locale, it is up - * to the caller to determine if this constant should also be used for the - * direction of the UI. - * - * {@see goog.LOCALE} - * - * @type {boolean} - * - * TODO(user): write a test that checks that this is a compile-time constant. + * Flattens an element. That is, removes it and replace it with its children. + * Does nothing if the element is not in the document. + * @param {Element} element The element to flatten. + * @return {Element|undefined} The original element, detached from the document + * tree, sans children; or undefined, if the element was not in the document + * to begin with. */ -goog.i18n.bidi.IS_RTL = goog.i18n.bidi.FORCE_RTL || - ( - (goog.LOCALE.substring(0, 2).toLowerCase() == 'ar' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'fa' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'he' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'iw' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'ps' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'sd' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'ug' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'ur' || - goog.LOCALE.substring(0, 2).toLowerCase() == 'yi') && - (goog.LOCALE.length == 2 || - goog.LOCALE.substring(2, 3) == '-' || - goog.LOCALE.substring(2, 3) == '_') - ) || ( - goog.LOCALE.length >= 3 && - goog.LOCALE.substring(0, 3).toLowerCase() == 'ckb' && - (goog.LOCALE.length == 3 || - goog.LOCALE.substring(3, 4) == '-' || - goog.LOCALE.substring(3, 4) == '_') - ); +goog.dom.flattenElement = function(element) { + var child, parent = element.parentNode; + if (parent && parent.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT) { + // Use IE DOM method (supported by Opera too) if available + if (element.removeNode) { + return /** @type {Element} */ (element.removeNode(false)); + } else { + // Move all children of the original node up one level. + while ((child = element.firstChild)) { + parent.insertBefore(child, element); + } + + // Detach the original element. + return /** @type {Element} */ (goog.dom.removeNode(element)); + } + } +}; /** - * Unicode formatting characters and directionality string constants. - * @enum {string} + * Returns an array containing just the element children of the given element. + * @param {Element} element The element whose element children we want. + * @return {!(Array|NodeList)} An array or array-like list of just the element + * children of the given element. */ -goog.i18n.bidi.Format = { - /** Unicode "Left-To-Right Embedding" (LRE) character. */ - LRE: '\u202A', - /** Unicode "Right-To-Left Embedding" (RLE) character. */ - RLE: '\u202B', - /** Unicode "Pop Directional Formatting" (PDF) character. */ - PDF: '\u202C', - /** Unicode "Left-To-Right Mark" (LRM) character. */ - LRM: '\u200E', - /** Unicode "Right-To-Left Mark" (RLM) character. */ - RLM: '\u200F' +goog.dom.getChildren = function(element) { + // We check if the children attribute is supported for child elements + // since IE8 misuses the attribute by also including comments. + if (goog.dom.BrowserFeature.CAN_USE_CHILDREN_ATTRIBUTE && + element.children != undefined) { + return element.children; + } + // Fall back to manually filtering the element's child nodes. + return goog.array.filter(element.childNodes, function(node) { + return node.nodeType == goog.dom.NodeType.ELEMENT; + }); }; /** - * Directionality enum. - * @enum {number} + * Returns the first child node that is an element. + * @param {Node} node The node to get the first child element of. + * @return {Element} The first child node of {@code node} that is an element. */ -goog.i18n.bidi.Dir = { - /** - * Left-to-right. - */ - LTR: 1, - - /** - * Right-to-left. - */ - RTL: -1, - - /** - * Neither left-to-right nor right-to-left. - */ - NEUTRAL: 0 +goog.dom.getFirstElementChild = function(node) { + if (goog.isDef(node.firstElementChild)) { + return /** @type {!Element} */(node).firstElementChild; + } + return goog.dom.getNextElementNode_(node.firstChild, true); }; /** - * 'right' string constant. - * @type {string} + * Returns the last child node that is an element. + * @param {Node} node The node to get the last child element of. + * @return {Element} The last child node of {@code node} that is an element. */ -goog.i18n.bidi.RIGHT = 'right'; +goog.dom.getLastElementChild = function(node) { + if (goog.isDef(node.lastElementChild)) { + return /** @type {!Element} */(node).lastElementChild; + } + return goog.dom.getNextElementNode_(node.lastChild, false); +}; /** - * 'left' string constant. - * @type {string} + * Returns the first next sibling that is an element. + * @param {Node} node The node to get the next sibling element of. + * @return {Element} The next sibling of {@code node} that is an element. */ -goog.i18n.bidi.LEFT = 'left'; +goog.dom.getNextElementSibling = function(node) { + if (goog.isDef(node.nextElementSibling)) { + return /** @type {!Element} */(node).nextElementSibling; + } + return goog.dom.getNextElementNode_(node.nextSibling, true); +}; /** - * 'left' if locale is RTL, 'right' if not. - * @type {string} + * Returns the first previous sibling that is an element. + * @param {Node} node The node to get the previous sibling element of. + * @return {Element} The first previous sibling of {@code node} that is + * an element. */ -goog.i18n.bidi.I18N_RIGHT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.LEFT : - goog.i18n.bidi.RIGHT; +goog.dom.getPreviousElementSibling = function(node) { + if (goog.isDef(node.previousElementSibling)) { + return /** @type {!Element} */(node).previousElementSibling; + } + return goog.dom.getNextElementNode_(node.previousSibling, false); +}; /** - * 'right' if locale is RTL, 'left' if not. - * @type {string} + * Returns the first node that is an element in the specified direction, + * starting with {@code node}. + * @param {Node} node The node to get the next element from. + * @param {boolean} forward Whether to look forwards or backwards. + * @return {Element} The first element. + * @private */ -goog.i18n.bidi.I18N_LEFT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.RIGHT : - goog.i18n.bidi.LEFT; +goog.dom.getNextElementNode_ = function(node, forward) { + while (node && node.nodeType != goog.dom.NodeType.ELEMENT) { + node = forward ? node.nextSibling : node.previousSibling; + } + + return /** @type {Element} */ (node); +}; /** - * Convert a directionality given in various formats to a goog.i18n.bidi.Dir - * constant. Useful for interaction with different standards of directionality - * representation. - * - * @param {goog.i18n.bidi.Dir|number|boolean|null} givenDir Directionality given - * in one of the following formats: - * 1. A goog.i18n.bidi.Dir constant. - * 2. A number (positive = LTR, negative = RTL, 0 = neutral). - * 3. A boolean (true = RTL, false = LTR). - * 4. A null for unknown directionality. - * @param {boolean=} opt_noNeutral Whether a givenDir of zero or - * goog.i18n.bidi.Dir.NEUTRAL should be treated as null, i.e. unknown, in - * order to preserve legacy behavior. - * @return {?goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the - * given directionality. If given null, returns null (i.e. unknown). + * Returns the next node in source order from the given node. + * @param {Node} node The node. + * @return {Node} The next node in the DOM tree, or null if this was the last + * node. */ -goog.i18n.bidi.toDir = function(givenDir, opt_noNeutral) { - if (typeof givenDir == 'number') { - // This includes the non-null goog.i18n.bidi.Dir case. - return givenDir > 0 ? goog.i18n.bidi.Dir.LTR : - givenDir < 0 ? goog.i18n.bidi.Dir.RTL : - opt_noNeutral ? null : goog.i18n.bidi.Dir.NEUTRAL; - } else if (givenDir == null) { +goog.dom.getNextNode = function(node) { + if (!node) { return null; - } else { - // Must be typeof givenDir == 'boolean'. - return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR; } -}; + if (node.firstChild) { + return node.firstChild; + } -/** - * A practical pattern to identify strong LTR characters. This pattern is not - * theoretically correct according to the Unicode standard. It is simplified for - * performance and small code size. - * @type {string} - * @private - */ -goog.i18n.bidi.ltrChars_ = - 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' + - '\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF'; + while (node && !node.nextSibling) { + node = node.parentNode; + } + + return node ? node.nextSibling : null; +}; /** - * A practical pattern to identify strong RTL character. This pattern is not - * theoretically correct according to the Unicode standard. It is simplified - * for performance and small code size. - * @type {string} - * @private + * Returns the previous node in source order from the given node. + * @param {Node} node The node. + * @return {Node} The previous node in the DOM tree, or null if this was the + * first node. */ -goog.i18n.bidi.rtlChars_ = - '\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC'; +goog.dom.getPreviousNode = function(node) { + if (!node) { + return null; + } + + if (!node.previousSibling) { + return node.parentNode; + } + node = node.previousSibling; + while (node && node.lastChild) { + node = node.lastChild; + } -/** - * Simplified regular expression for an HTML tag (opening or closing) or an HTML - * escape. We might want to skip over such expressions when estimating the text - * directionality. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g; + return node; +}; /** - * Returns the input text with spaces instead of HTML tags or HTML escapes, if - * opt_isStripNeeded is true. Else returns the input as is. - * Useful for text directionality estimation. - * Note: the function should not be used in other contexts; it is not 100% - * correct, but rather a good-enough implementation for directionality - * estimation purposes. - * @param {string} str The given string. - * @param {boolean=} opt_isStripNeeded Whether to perform the stripping. - * Default: false (to retain consistency with calling functions). - * @return {string} The given string cleaned of HTML tags / escapes. - * @private + * Whether the object looks like a DOM node. + * @param {?} obj The object being tested for node likeness. + * @return {boolean} Whether the object looks like a DOM node. */ -goog.i18n.bidi.stripHtmlIfNeeded_ = function(str, opt_isStripNeeded) { - return opt_isStripNeeded ? str.replace(goog.i18n.bidi.htmlSkipReg_, '') : - str; +goog.dom.isNodeLike = function(obj) { + return goog.isObject(obj) && obj.nodeType > 0; }; /** - * Regular expression to check for RTL characters. - * @type {RegExp} - * @private + * Whether the object looks like an Element. + * @param {?} obj The object being tested for Element likeness. + * @return {boolean} Whether the object looks like an Element. */ -goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']'); +goog.dom.isElement = function(obj) { + return goog.isObject(obj) && obj.nodeType == goog.dom.NodeType.ELEMENT; +}; /** - * Regular expression to check for LTR characters. - * @type {RegExp} - * @private + * Returns true if the specified value is a Window object. This includes the + * global window for HTML pages, and iframe windows. + * @param {?} obj Variable to test. + * @return {boolean} Whether the variable is a window. */ -goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']'); +goog.dom.isWindow = function(obj) { + return goog.isObject(obj) && obj['window'] == obj; +}; /** - * Test whether the given string has any RTL characters in it. - * @param {string} str The given string that need to be tested. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether the string contains RTL characters. + * Returns an element's parent, if it's an Element. + * @param {Element} element The DOM element. + * @return {Element} The parent, or null if not an Element. */ -goog.i18n.bidi.hasAnyRtl = function(str, opt_isHtml) { - return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); +goog.dom.getParentElement = function(element) { + var parent; + if (goog.dom.BrowserFeature.CAN_USE_PARENT_ELEMENT_PROPERTY) { + var isIe9 = goog.userAgent.IE && + goog.userAgent.isVersionOrHigher('9') && + !goog.userAgent.isVersionOrHigher('10'); + // SVG elements in IE9 can't use the parentElement property. + // goog.global['SVGElement'] is not defined in IE9 quirks mode. + if (!(isIe9 && goog.global['SVGElement'] && + element instanceof goog.global['SVGElement'])) { + parent = element.parentElement; + if (parent) { + return parent; + } + } + } + parent = element.parentNode; + return goog.dom.isElement(parent) ? /** @type {!Element} */ (parent) : null; }; /** - * Test whether the given string has any RTL characters in it. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the string contains RTL characters. - * @deprecated Use hasAnyRtl. + * Whether a node contains another node. + * @param {Node} parent The node that should contain the other node. + * @param {Node} descendant The node to test presence of. + * @return {boolean} Whether the parent node contains the descendent node. */ -goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl; +goog.dom.contains = function(parent, descendant) { + // We use browser specific methods for this if available since it is faster + // that way. + // IE DOM + if (parent.contains && descendant.nodeType == goog.dom.NodeType.ELEMENT) { + return parent == descendant || parent.contains(descendant); + } -/** - * Test whether the given string has any LTR characters in it. - * @param {string} str The given string that need to be tested. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether the string contains LTR characters. - */ -goog.i18n.bidi.hasAnyLtr = function(str, opt_isHtml) { - return goog.i18n.bidi.ltrCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); + // W3C DOM Level 3 + if (typeof parent.compareDocumentPosition != 'undefined') { + return parent == descendant || + Boolean(parent.compareDocumentPosition(descendant) & 16); + } + + // W3C DOM Level 1 + while (descendant && parent != descendant) { + descendant = descendant.parentNode; + } + return descendant == parent; }; /** - * Regular expression pattern to check if the first character in the string - * is LTR. - * @type {RegExp} - * @private + * Compares the document order of two nodes, returning 0 if they are the same + * node, a negative number if node1 is before node2, and a positive number if + * node2 is before node1. Note that we compare the order the tags appear in the + * document so in the tree <b><i>text</i></b> the B node is considered to be + * before the I node. + * + * @param {Node} node1 The first node to compare. + * @param {Node} node2 The second node to compare. + * @return {number} 0 if the nodes are the same node, a negative number if node1 + * is before node2, and a positive number if node2 is before node1. */ -goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']'); +goog.dom.compareNodeOrder = function(node1, node2) { + // Fall out quickly for equality. + if (node1 == node2) { + return 0; + } + // Use compareDocumentPosition where available + if (node1.compareDocumentPosition) { + // 4 is the bitmask for FOLLOWS. + return node1.compareDocumentPosition(node2) & 2 ? 1 : -1; + } -/** - * Regular expression pattern to check if the first character in the string - * is RTL. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']'); + // Special case for document nodes on IE 7 and 8. + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { + if (node1.nodeType == goog.dom.NodeType.DOCUMENT) { + return -1; + } + if (node2.nodeType == goog.dom.NodeType.DOCUMENT) { + return 1; + } + } + // Process in IE using sourceIndex - we check to see if the first node has + // a source index or if its parent has one. + if ('sourceIndex' in node1 || + (node1.parentNode && 'sourceIndex' in node1.parentNode)) { + var isElement1 = node1.nodeType == goog.dom.NodeType.ELEMENT; + var isElement2 = node2.nodeType == goog.dom.NodeType.ELEMENT; -/** - * Check if the first character in the string is RTL or not. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the first character in str is an RTL char. - */ -goog.i18n.bidi.isRtlChar = function(str) { - return goog.i18n.bidi.rtlRe_.test(str); -}; + if (isElement1 && isElement2) { + return node1.sourceIndex - node2.sourceIndex; + } else { + var parent1 = node1.parentNode; + var parent2 = node2.parentNode; + if (parent1 == parent2) { + return goog.dom.compareSiblingOrder_(node1, node2); + } -/** - * Check if the first character in the string is LTR or not. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the first character in str is an LTR char. - */ -goog.i18n.bidi.isLtrChar = function(str) { - return goog.i18n.bidi.ltrRe_.test(str); -}; + if (!isElement1 && goog.dom.contains(parent1, node2)) { + return -1 * goog.dom.compareParentsDescendantNodeIe_(node1, node2); + } -/** - * Check if the first character in the string is neutral or not. - * @param {string} str The given string that need to be tested. - * @return {boolean} Whether the first character in str is a neutral char. - */ -goog.i18n.bidi.isNeutralChar = function(str) { - return !goog.i18n.bidi.isLtrChar(str) && !goog.i18n.bidi.isRtlChar(str); + if (!isElement2 && goog.dom.contains(parent2, node1)) { + return goog.dom.compareParentsDescendantNodeIe_(node2, node1); + } + + return (isElement1 ? node1.sourceIndex : parent1.sourceIndex) - + (isElement2 ? node2.sourceIndex : parent2.sourceIndex); + } + } + + // For Safari, we compare ranges. + var doc = goog.dom.getOwnerDocument(node1); + + var range1, range2; + range1 = doc.createRange(); + range1.selectNode(node1); + range1.collapse(true); + + range2 = doc.createRange(); + range2.selectNode(node2); + range2.collapse(true); + + return range1.compareBoundaryPoints(goog.global['Range'].START_TO_END, + range2); }; /** - * Regular expressions to check if a piece of text is of LTR directionality - * on first character with strong directionality. - * @type {RegExp} + * Utility function to compare the position of two nodes, when + * {@code textNode}'s parent is an ancestor of {@code node}. If this entry + * condition is not met, this function will attempt to reference a null object. + * @param {!Node} textNode The textNode to compare. + * @param {Node} node The node to compare. + * @return {number} -1 if node is before textNode, +1 otherwise. * @private */ -goog.i18n.bidi.ltrDirCheckRe_ = new RegExp( - '^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']'); +goog.dom.compareParentsDescendantNodeIe_ = function(textNode, node) { + var parent = textNode.parentNode; + if (parent == node) { + // If textNode is a child of node, then node comes first. + return -1; + } + var sibling = node; + while (sibling.parentNode != parent) { + sibling = sibling.parentNode; + } + return goog.dom.compareSiblingOrder_(sibling, textNode); +}; /** - * Regular expressions to check if a piece of text is of RTL directionality - * on first character with strong directionality. - * @type {RegExp} + * Utility function to compare the position of two nodes known to be non-equal + * siblings. + * @param {Node} node1 The first node to compare. + * @param {!Node} node2 The second node to compare. + * @return {number} -1 if node1 is before node2, +1 otherwise. * @private */ -goog.i18n.bidi.rtlDirCheckRe_ = new RegExp( - '^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']'); - +goog.dom.compareSiblingOrder_ = function(node1, node2) { + var s = node2; + while ((s = s.previousSibling)) { + if (s == node1) { + // We just found node1 before node2. + return -1; + } + } -/** - * Check whether the first strongly directional character (if any) is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL directionality is detected using the first - * strongly-directional character method. - */ -goog.i18n.bidi.startsWithRtl = function(str, opt_isHtml) { - return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); + // Since we didn't find it, node1 must be after node2. + return 1; }; /** - * Check whether the first strongly directional character (if any) is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL directionality is detected using the first - * strongly-directional character method. - * @deprecated Use startsWithRtl. + * Find the deepest common ancestor of the given nodes. + * @param {...Node} var_args The nodes to find a common ancestor of. + * @return {Node} The common ancestor of the nodes, or null if there is none. + * null will only be returned if two or more of the nodes are from different + * documents. */ -goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl; +goog.dom.findCommonAncestor = function(var_args) { + var i, count = arguments.length; + if (!count) { + return null; + } else if (count == 1) { + return arguments[0]; + } + + var paths = []; + var minLength = Infinity; + for (i = 0; i < count; i++) { + // Compute the list of ancestors. + var ancestors = []; + var node = arguments[i]; + while (node) { + ancestors.unshift(node); + node = node.parentNode; + } + + // Save the list for comparison. + paths.push(ancestors); + minLength = Math.min(minLength, ancestors.length); + } + var output = null; + for (i = 0; i < minLength; i++) { + var first = paths[0][i]; + for (var j = 1; j < count; j++) { + if (first != paths[j][i]) { + return output; + } + } + output = first; + } + return output; +}; /** - * Check whether the first strongly directional character (if any) is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR directionality is detected using the first - * strongly-directional character method. + * Returns the owner document for a node. + * @param {Node|Window} node The node to get the document for. + * @return {!Document} The document owning the node. */ -goog.i18n.bidi.startsWithLtr = function(str, opt_isHtml) { - return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_( - str, opt_isHtml)); +goog.dom.getOwnerDocument = function(node) { + // TODO(nnaze): Update param signature to be non-nullable. + goog.asserts.assert(node, 'Node cannot be null or undefined.'); + return /** @type {!Document} */ ( + node.nodeType == goog.dom.NodeType.DOCUMENT ? node : + node.ownerDocument || node.document); }; /** - * Check whether the first strongly directional character (if any) is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR directionality is detected using the first - * strongly-directional character method. - * @deprecated Use startsWithLtr. + * Cross-browser function for getting the document element of a frame or iframe. + * @param {Element} frame Frame element. + * @return {!Document} The frame content document. */ -goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr; +goog.dom.getFrameContentDocument = function(frame) { + var doc = frame.contentDocument || frame.contentWindow.document; + return doc; +}; /** - * Regular expression to check if a string looks like something that must - * always be LTR even in RTL text, e.g. a URL. When estimating the - * directionality of text containing these, we treat these as weakly LTR, - * like numbers. - * @type {RegExp} - * @private + * Cross-browser function for getting the window of a frame or iframe. + * @param {Element} frame Frame element. + * @return {Window} The window associated with the given frame. */ -goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/; +goog.dom.getFrameContentWindow = function(frame) { + return frame.contentWindow || + goog.dom.getWindow(goog.dom.getFrameContentDocument(frame)); +}; /** - * Check whether the input string either contains no strongly directional - * characters or looks like a url. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether neutral directionality is detected. + * Sets the text content of a node, with cross-browser support. + * @param {Node} node The node to change the text content of. + * @param {string|number} text The value that should replace the node's content. */ -goog.i18n.bidi.isNeutralText = function(str, opt_isHtml) { - str = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml); - return goog.i18n.bidi.isRequiredLtrRe_.test(str) || - !goog.i18n.bidi.hasAnyLtr(str) && !goog.i18n.bidi.hasAnyRtl(str); +goog.dom.setTextContent = function(node, text) { + goog.asserts.assert(node != null, + 'goog.dom.setTextContent expects a non-null value for node'); + + if ('textContent' in node) { + node.textContent = text; + } else if (node.nodeType == goog.dom.NodeType.TEXT) { + node.data = text; + } else if (node.firstChild && + node.firstChild.nodeType == goog.dom.NodeType.TEXT) { + // If the first child is a text node we just change its data and remove the + // rest of the children. + while (node.lastChild != node.firstChild) { + node.removeChild(node.lastChild); + } + node.firstChild.data = text; + } else { + goog.dom.removeChildren(node); + var doc = goog.dom.getOwnerDocument(node); + node.appendChild(doc.createTextNode(String(text))); + } }; /** - * Regular expressions to check if the last strongly-directional character in a - * piece of text is LTR. - * @type {RegExp} - * @private + * Gets the outerHTML of a node, which islike innerHTML, except that it + * actually contains the HTML of the node itself. + * @param {Element} element The element to get the HTML of. + * @return {string} The outerHTML of the given element. */ -goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp( - '[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$'); +goog.dom.getOuterHtml = function(element) { + // IE, Opera and WebKit all have outerHTML. + if ('outerHTML' in element) { + return element.outerHTML; + } else { + var doc = goog.dom.getOwnerDocument(element); + var div = doc.createElement(goog.dom.TagName.DIV); + div.appendChild(element.cloneNode(true)); + return div.innerHTML; + } +}; /** - * Regular expressions to check if the last strongly-directional character in a - * piece of text is RTL. - * @type {RegExp} - * @private + * Finds the first descendant node that matches the filter function, using + * a depth first search. This function offers the most general purpose way + * of finding a matching element. You may also wish to consider + * {@code goog.dom.query} which can express many matching criteria using + * CSS selector expressions. These expressions often result in a more + * compact representation of the desired result. + * @see goog.dom.query + * + * @param {Node} root The root of the tree to search. + * @param {function(Node) : boolean} p The filter function. + * @return {Node|undefined} The found node or undefined if none is found. */ -goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp( - '[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$'); +goog.dom.findNode = function(root, p) { + var rv = []; + var found = goog.dom.findNodes_(root, p, rv, true); + return found ? rv[0] : undefined; +}; /** - * Check if the exit directionality a piece of text is LTR, i.e. if the last - * strongly-directional character in the string is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR exit directionality was detected. + * Finds all the descendant nodes that match the filter function, using a + * a depth first search. This function offers the most general-purpose way + * of finding a set of matching elements. You may also wish to consider + * {@code goog.dom.query} which can express many matching criteria using + * CSS selector expressions. These expressions often result in a more + * compact representation of the desired result. + + * @param {Node} root The root of the tree to search. + * @param {function(Node) : boolean} p The filter function. + * @return {!Array<!Node>} The found nodes or an empty array if none are found. */ -goog.i18n.bidi.endsWithLtr = function(str, opt_isHtml) { - return goog.i18n.bidi.ltrExitDirCheckRe_.test( - goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)); +goog.dom.findNodes = function(root, p) { + var rv = []; + goog.dom.findNodes_(root, p, rv, false); + return rv; }; /** - * Check if the exit directionality a piece of text is LTR, i.e. if the last - * strongly-directional character in the string is LTR. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether LTR exit directionality was detected. - * @deprecated Use endsWithLtr. + * Finds the first or all the descendant nodes that match the filter function, + * using a depth first search. + * @param {Node} root The root of the tree to search. + * @param {function(Node) : boolean} p The filter function. + * @param {!Array<!Node>} rv The found nodes are added to this array. + * @param {boolean} findOne If true we exit after the first found node. + * @return {boolean} Whether the search is complete or not. True in case findOne + * is true and the node is found. False otherwise. + * @private */ -goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr; +goog.dom.findNodes_ = function(root, p, rv, findOne) { + if (root != null) { + var child = root.firstChild; + while (child) { + if (p(child)) { + rv.push(child); + if (findOne) { + return true; + } + } + if (goog.dom.findNodes_(child, p, rv, findOne)) { + return true; + } + child = child.nextSibling; + } + } + return false; +}; /** - * Check if the exit directionality a piece of text is RTL, i.e. if the last - * strongly-directional character in the string is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL exit directionality was detected. + * Map of tags whose content to ignore when calculating text length. + * @private {!Object<string, number>} + * @const */ -goog.i18n.bidi.endsWithRtl = function(str, opt_isHtml) { - return goog.i18n.bidi.rtlExitDirCheckRe_.test( - goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)); +goog.dom.TAGS_TO_IGNORE_ = { + 'SCRIPT': 1, + 'STYLE': 1, + 'HEAD': 1, + 'IFRAME': 1, + 'OBJECT': 1 }; /** - * Check if the exit directionality a piece of text is RTL, i.e. if the last - * strongly-directional character in the string is RTL. - * @param {string} str String being checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether RTL exit directionality was detected. - * @deprecated Use endsWithRtl. + * Map of tags which have predefined values with regard to whitespace. + * @private {!Object<string, string>} + * @const */ -goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl; +goog.dom.PREDEFINED_TAG_VALUES_ = {'IMG': ' ', 'BR': '\n'}; /** - * A regular expression for matching right-to-left language codes. - * See {@link #isRtlLanguage} for the design. - * @type {RegExp} - * @private + * Returns true if the element has a tab index that allows it to receive + * keyboard focus (tabIndex >= 0), false otherwise. Note that some elements + * natively support keyboard focus, even if they have no tab index. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element has a tab index that allows keyboard + * focus. + * @see http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ */ -goog.i18n.bidi.rtlLocalesRe_ = new RegExp( - '^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|' + - '.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))' + - '(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)', - 'i'); +goog.dom.isFocusableTabIndex = function(element) { + return goog.dom.hasSpecifiedTabIndex_(element) && + goog.dom.isTabIndexFocusable_(element); +}; /** - * Check if a BCP 47 / III language code indicates an RTL language, i.e. either: - * - a language code explicitly specifying one of the right-to-left scripts, - * e.g. "az-Arab", or<p> - * - a language code specifying one of the languages normally written in a - * right-to-left script, e.g. "fa" (Farsi), except ones explicitly specifying - * Latin or Cyrillic script (which are the usual LTR alternatives).<p> - * The list of right-to-left scripts appears in the 100-199 range in - * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and - * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and - * Tifinagh, which also have significant modern usage. The rest (Syriac, - * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage - * and are not recognized to save on code size. - * The languages usually written in a right-to-left script are taken as those - * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in - * http://www.iana.org/assignments/language-subtag-registry, - * as well as Central (or Sorani) Kurdish (ckb), Sindhi (sd) and Uyghur (ug). - * Other subtags of the language code, e.g. regions like EG (Egypt), are - * ignored. - * @param {string} lang BCP 47 (a.k.a III) language code. - * @return {boolean} Whether the language code is an RTL language. + * Enables or disables keyboard focus support on the element via its tab index. + * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true + * (or elements that natively support keyboard focus, like form elements) can + * receive keyboard focus. See http://go/tabindex for more info. + * @param {Element} element Element whose tab index is to be changed. + * @param {boolean} enable Whether to set or remove a tab index on the element + * that supports keyboard focus. */ -goog.i18n.bidi.isRtlLanguage = function(lang) { - return goog.i18n.bidi.rtlLocalesRe_.test(lang); +goog.dom.setFocusableTabIndex = function(element, enable) { + if (enable) { + element.tabIndex = 0; + } else { + // Set tabIndex to -1 first, then remove it. This is a workaround for + // Safari (confirmed in version 4 on Windows). When removing the attribute + // without setting it to -1 first, the element remains keyboard focusable + // despite not having a tabIndex attribute anymore. + element.tabIndex = -1; + element.removeAttribute('tabIndex'); // Must be camelCase! + } }; /** - * Regular expression for bracket guard replacement in html. - * @type {RegExp} - * @private + * Returns true if the element can be focused, i.e. it has a tab index that + * allows it to receive keyboard focus (tabIndex >= 0), or it is an element + * that natively supports keyboard focus. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element allows keyboard focus. */ -goog.i18n.bidi.bracketGuardHtmlRe_ = - /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?(>)+)/g; +goog.dom.isFocusable = function(element) { + var focusable; + // Some elements can have unspecified tab index and still receive focus. + if (goog.dom.nativelySupportsFocus_(element)) { + // Make sure the element is not disabled ... + focusable = !element.disabled && + // ... and if a tab index is specified, it allows focus. + (!goog.dom.hasSpecifiedTabIndex_(element) || + goog.dom.isTabIndexFocusable_(element)); + } else { + focusable = goog.dom.isFocusableTabIndex(element); + } + + // IE requires elements to be visible in order to focus them. + return focusable && goog.userAgent.IE ? + goog.dom.hasNonZeroBoundingRect_(element) : focusable; +}; /** - * Regular expression for bracket guard replacement in text. - * @type {RegExp} + * Returns true if the element has a specified tab index. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element has a specified tab index. * @private */ -goog.i18n.bidi.bracketGuardTextRe_ = - /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; +goog.dom.hasSpecifiedTabIndex_ = function(element) { + // IE returns 0 for an unset tabIndex, so we must use getAttributeNode(), + // which returns an object with a 'specified' property if tabIndex is + // specified. This works on other browsers, too. + var attrNode = element.getAttributeNode('tabindex'); // Must be lowercase! + return goog.isDefAndNotNull(attrNode) && attrNode.specified; +}; /** - * Apply bracket guard using html span tag. This is to address the problem of - * messy bracket display frequently happens in RTL layout. - * @param {string} s The string that need to be processed. - * @param {boolean=} opt_isRtlContext specifies default direction (usually - * direction of the UI). - * @return {string} The processed string, with all bracket guarded. + * Returns true if the element's tab index allows the element to be focused. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element's tab index allows focus. + * @private */ -goog.i18n.bidi.guardBracketInHtml = function(s, opt_isRtlContext) { - var useRtl = opt_isRtlContext === undefined ? - goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext; - if (useRtl) { - return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_, - '<span dir=rtl>$&</span>'); - } - return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_, - '<span dir=ltr>$&</span>'); +goog.dom.isTabIndexFocusable_ = function(element) { + var index = element.tabIndex; + // NOTE: IE9 puts tabIndex in 16-bit int, e.g. -2 is 65534. + return goog.isNumber(index) && index >= 0 && index < 32768; }; /** - * Apply bracket guard using LRM and RLM. This is to address the problem of - * messy bracket display frequently happens in RTL layout. - * This version works for both plain text and html. But it does not work as - * good as guardBracketInHtml in some cases. - * @param {string} s The string that need to be processed. - * @param {boolean=} opt_isRtlContext specifies default direction (usually - * direction of the UI). - * @return {string} The processed string, with all bracket guarded. + * Returns true if the element is focusable even when tabIndex is not set. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element natively supports focus. + * @private */ -goog.i18n.bidi.guardBracketInText = function(s, opt_isRtlContext) { - var useRtl = opt_isRtlContext === undefined ? - goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext; - var mark = useRtl ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM; - return s.replace(goog.i18n.bidi.bracketGuardTextRe_, mark + '$&' + mark); +goog.dom.nativelySupportsFocus_ = function(element) { + return element.tagName == goog.dom.TagName.A || + element.tagName == goog.dom.TagName.INPUT || + element.tagName == goog.dom.TagName.TEXTAREA || + element.tagName == goog.dom.TagName.SELECT || + element.tagName == goog.dom.TagName.BUTTON; }; /** - * Enforce the html snippet in RTL directionality regardless overall context. - * If the html piece was enclosed by tag, dir will be applied to existing - * tag, otherwise a span tag will be added as wrapper. For this reason, if - * html snippet start with with tag, this tag must enclose the whole piece. If - * the tag already has a dir specified, this new one will override existing - * one in behavior (tested on FF and IE). - * @param {string} html The string that need to be processed. - * @return {string} The processed string, with directionality enforced to RTL. + * Returns true if the element has a bounding rectangle that would be visible + * (i.e. its width and height are greater than zero). + * @param {!Element} element Element to check. + * @return {boolean} Whether the element has a non-zero bounding rectangle. + * @private */ -goog.i18n.bidi.enforceRtlInHtml = function(html) { - if (html.charAt(0) == '<') { - return html.replace(/<\w+/, '$& dir=rtl'); - } - // '\n' is important for FF so that it won't incorrectly merge span groups - return '\n<span dir=rtl>' + html + '</span>'; +goog.dom.hasNonZeroBoundingRect_ = function(element) { + var rect = goog.isFunction(element['getBoundingClientRect']) ? + element.getBoundingClientRect() : + {'height': element.offsetHeight, 'width': element.offsetWidth}; + return goog.isDefAndNotNull(rect) && rect.height > 0 && rect.width > 0; }; /** - * Enforce RTL on both end of the given text piece using unicode BiDi formatting - * characters RLE and PDF. - * @param {string} text The piece of text that need to be wrapped. - * @return {string} The wrapped string after process. + * Returns the text content of the current node, without markup and invisible + * symbols. New lines are stripped and whitespace is collapsed, + * such that each character would be visible. + * + * In browsers that support it, innerText is used. Other browsers attempt to + * simulate it via node traversal. Line breaks are canonicalized in IE. + * + * @param {Node} node The node from which we are getting content. + * @return {string} The text content. */ -goog.i18n.bidi.enforceRtlInText = function(text) { - return goog.i18n.bidi.Format.RLE + text + goog.i18n.bidi.Format.PDF; -}; +goog.dom.getTextContent = function(node) { + var textContent; + // Note(arv): IE9, Opera, and Safari 3 support innerText but they include + // text nodes in script tags. So we revert to use a user agent test here. + if (goog.dom.BrowserFeature.CAN_USE_INNER_TEXT && ('innerText' in node)) { + textContent = goog.string.canonicalizeNewlines(node.innerText); + // Unfortunately .innerText() returns text with ­ symbols + // We need to filter it out and then remove duplicate whitespaces + } else { + var buf = []; + goog.dom.getTextContent_(node, buf, true); + textContent = buf.join(''); + } + // Strip ­ entities. goog.format.insertWordBreaks inserts them in Opera. + textContent = textContent.replace(/ \xAD /g, ' ').replace(/\xAD/g, ''); + // Strip ​ entities. goog.format.insertWordBreaks inserts them in IE8. + textContent = textContent.replace(/\u200B/g, ''); -/** - * Enforce the html snippet in RTL directionality regardless overall context. - * If the html piece was enclosed by tag, dir will be applied to existing - * tag, otherwise a span tag will be added as wrapper. For this reason, if - * html snippet start with with tag, this tag must enclose the whole piece. If - * the tag already has a dir specified, this new one will override existing - * one in behavior (tested on FF and IE). - * @param {string} html The string that need to be processed. - * @return {string} The processed string, with directionality enforced to RTL. - */ -goog.i18n.bidi.enforceLtrInHtml = function(html) { - if (html.charAt(0) == '<') { - return html.replace(/<\w+/, '$& dir=ltr'); + // Skip this replacement on old browsers with working innerText, which + // automatically turns   into ' ' and / +/ into ' ' when reading + // innerText. + if (!goog.dom.BrowserFeature.CAN_USE_INNER_TEXT) { + textContent = textContent.replace(/ +/g, ' '); } - // '\n' is important for FF so that it won't incorrectly merge span groups - return '\n<span dir=ltr>' + html + '</span>'; + if (textContent != ' ') { + textContent = textContent.replace(/^\s*/, ''); + } + + return textContent; }; /** - * Enforce LTR on both end of the given text piece using unicode BiDi formatting - * characters LRE and PDF. - * @param {string} text The piece of text that need to be wrapped. - * @return {string} The wrapped string after process. + * Returns the text content of the current node, without markup. + * + * Unlike {@code getTextContent} this method does not collapse whitespaces + * or normalize lines breaks. + * + * @param {Node} node The node from which we are getting content. + * @return {string} The raw text content. */ -goog.i18n.bidi.enforceLtrInText = function(text) { - return goog.i18n.bidi.Format.LRE + text + goog.i18n.bidi.Format.PDF; +goog.dom.getRawTextContent = function(node) { + var buf = []; + goog.dom.getTextContent_(node, buf, false); + + return buf.join(''); }; /** - * Regular expression to find dimensions such as "padding: .3 0.4ex 5px 6;" - * @type {RegExp} + * Recursive support function for text content retrieval. + * + * @param {Node} node The node from which we are getting content. + * @param {Array<string>} buf string buffer. + * @param {boolean} normalizeWhitespace Whether to normalize whitespace. * @private */ -goog.i18n.bidi.dimensionsRe_ = - /:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g; +goog.dom.getTextContent_ = function(node, buf, normalizeWhitespace) { + if (node.nodeName in goog.dom.TAGS_TO_IGNORE_) { + // ignore certain tags + } else if (node.nodeType == goog.dom.NodeType.TEXT) { + if (normalizeWhitespace) { + buf.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, '')); + } else { + buf.push(node.nodeValue); + } + } else if (node.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) { + buf.push(goog.dom.PREDEFINED_TAG_VALUES_[node.nodeName]); + } else { + var child = node.firstChild; + while (child) { + goog.dom.getTextContent_(child, buf, normalizeWhitespace); + child = child.nextSibling; + } + } +}; /** - * Regular expression for left. - * @type {RegExp} - * @private + * Returns the text length of the text contained in a node, without markup. This + * is equivalent to the selection length if the node was selected, or the number + * of cursor movements to traverse the node. Images & BRs take one space. New + * lines are ignored. + * + * @param {Node} node The node whose text content length is being calculated. + * @return {number} The length of {@code node}'s text content. */ -goog.i18n.bidi.leftRe_ = /left/gi; +goog.dom.getNodeTextLength = function(node) { + return goog.dom.getTextContent(node).length; +}; /** - * Regular expression for right. - * @type {RegExp} - * @private + * Returns the text offset of a node relative to one of its ancestors. The text + * length is the same as the length calculated by goog.dom.getNodeTextLength. + * + * @param {Node} node The node whose offset is being calculated. + * @param {Node=} opt_offsetParent The node relative to which the offset will + * be calculated. Defaults to the node's owner document's body. + * @return {number} The text offset. */ -goog.i18n.bidi.rightRe_ = /right/gi; +goog.dom.getNodeTextOffset = function(node, opt_offsetParent) { + var root = opt_offsetParent || goog.dom.getOwnerDocument(node).body; + var buf = []; + while (node && node != root) { + var cur = node; + while ((cur = cur.previousSibling)) { + buf.unshift(goog.dom.getTextContent(cur)); + } + node = node.parentNode; + } + // Trim left to deal with FF cases when there might be line breaks and empty + // nodes at the front of the text + return goog.string.trimLeft(buf.join('')).replace(/ +/g, ' ').length; +}; /** - * Placeholder regular expression for swapping. - * @type {RegExp} - * @private + * Returns the node at a given offset in a parent node. If an object is + * provided for the optional third parameter, the node and the remainder of the + * offset will stored as properties of this object. + * @param {Node} parent The parent node. + * @param {number} offset The offset into the parent node. + * @param {Object=} opt_result Object to be used to store the return value. The + * return value will be stored in the form {node: Node, remainder: number} + * if this object is provided. + * @return {Node} The node at the given offset. */ -goog.i18n.bidi.tempRe_ = /%%%%/g; - +goog.dom.getNodeAtOffset = function(parent, offset, opt_result) { + var stack = [parent], pos = 0, cur = null; + while (stack.length > 0 && pos < offset) { + cur = stack.pop(); + if (cur.nodeName in goog.dom.TAGS_TO_IGNORE_) { + // ignore certain tags + } else if (cur.nodeType == goog.dom.NodeType.TEXT) { + var text = cur.nodeValue.replace(/(\r\n|\r|\n)/g, '').replace(/ +/g, ' '); + pos += text.length; + } else if (cur.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) { + pos += goog.dom.PREDEFINED_TAG_VALUES_[cur.nodeName].length; + } else { + for (var i = cur.childNodes.length - 1; i >= 0; i--) { + stack.push(cur.childNodes[i]); + } + } + } + if (goog.isObject(opt_result)) { + opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0; + opt_result.node = cur; + } -/** - * Swap location parameters and 'left'/'right' in CSS specification. The - * processed string will be suited for RTL layout. Though this function can - * cover most cases, there are always exceptions. It is suggested to put - * those exceptions in separate group of CSS string. - * @param {string} cssStr CSS spefication string. - * @return {string} Processed CSS specification string. - */ -goog.i18n.bidi.mirrorCSS = function(cssStr) { - return cssStr. - // reverse dimensions - replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2'). - replace(goog.i18n.bidi.leftRe_, '%%%%'). // swap left and right - replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT). - replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT); + return cur; }; /** - * Regular expression for hebrew double quote substitution, finding quote - * directly after hebrew characters. - * @type {RegExp} - * @private + * Returns true if the object is a {@code NodeList}. To qualify as a NodeList, + * the object must have a numeric length property and an item function (which + * has type 'string' on IE for some reason). + * @param {Object} val Object to test. + * @return {boolean} Whether the object is a NodeList. */ -goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g; +goog.dom.isNodeList = function(val) { + // TODO(attila): Now the isNodeList is part of goog.dom we can use + // goog.userAgent to make this simpler. + // A NodeList must have a length property of type 'number' on all platforms. + if (val && typeof val.length == 'number') { + // A NodeList is an object everywhere except Safari, where it's a function. + if (goog.isObject(val)) { + // A NodeList must have an item function (on non-IE platforms) or an item + // property of type 'string' (on IE). + return typeof val.item == 'function' || typeof val.item == 'string'; + } else if (goog.isFunction(val)) { + // On Safari, a NodeList is a function with an item property that is also + // a function. + return typeof val.item == 'function'; + } + } + + // Not a NodeList. + return false; +}; /** - * Regular expression for hebrew single quote substitution, finding quote - * directly after hebrew characters. - * @type {RegExp} - * @private + * Walks up the DOM hierarchy returning the first ancestor that has the passed + * tag name and/or class name. If the passed element matches the specified + * criteria, the element itself is returned. + * @param {Node} element The DOM node to start with. + * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or + * null/undefined to match only based on class name). + * @param {?string=} opt_class The class name to match (or null/undefined to + * match only based on tag name). + * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the + * dom. + * @return {Element} The first ancestor that matches the passed criteria, or + * null if no match is found. */ -goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g; +goog.dom.getAncestorByTagNameAndClass = function(element, opt_tag, opt_class, + opt_maxSearchSteps) { + if (!opt_tag && !opt_class) { + return null; + } + var tagName = opt_tag ? opt_tag.toUpperCase() : null; + return /** @type {Element} */ (goog.dom.getAncestor(element, + function(node) { + return (!tagName || node.nodeName == tagName) && + (!opt_class || goog.isString(node.className) && + goog.array.contains(node.className.split(/\s+/), opt_class)); + }, true, opt_maxSearchSteps)); +}; /** - * Replace the double and single quote directly after a Hebrew character with - * GERESH and GERSHAYIM. In such case, most likely that's user intention. - * @param {string} str String that need to be processed. - * @return {string} Processed string with double/single quote replaced. + * Walks up the DOM hierarchy returning the first ancestor that has the passed + * class name. If the passed element matches the specified criteria, the + * element itself is returned. + * @param {Node} element The DOM node to start with. + * @param {string} className The class name to match. + * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the + * dom. + * @return {Element} The first ancestor that matches the passed criteria, or + * null if none match. */ -goog.i18n.bidi.normalizeHebrewQuote = function(str) { - return str. - replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1\u05f4'). - replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1\u05f3'); +goog.dom.getAncestorByClass = function(element, className, opt_maxSearchSteps) { + return goog.dom.getAncestorByTagNameAndClass(element, null, className, + opt_maxSearchSteps); }; /** - * Regular expression to split a string into "words" for directionality - * estimation based on relative word counts. - * @type {RegExp} - * @private - */ -goog.i18n.bidi.wordSeparatorRe_ = /\s+/; + * Walks up the DOM hierarchy returning the first ancestor that passes the + * matcher function. + * @param {Node} element The DOM node to start with. + * @param {function(Node) : boolean} matcher A function that returns true if the + * passed node matches the desired criteria. + * @param {boolean=} opt_includeNode If true, the node itself is included in + * the search (the first call to the matcher will pass startElement as + * the node to test). + * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the + * dom. + * @return {Node} DOM node that matched the matcher, or null if there was + * no match. + */ +goog.dom.getAncestor = function( + element, matcher, opt_includeNode, opt_maxSearchSteps) { + if (!opt_includeNode) { + element = element.parentNode; + } + var ignoreSearchSteps = opt_maxSearchSteps == null; + var steps = 0; + while (element && (ignoreSearchSteps || steps <= opt_maxSearchSteps)) { + goog.asserts.assert(element.name != 'parentNode'); + if (matcher(element)) { + return element; + } + element = element.parentNode; + steps++; + } + // Reached the root of the DOM without a match + return null; +}; /** - * Regular expression to check if a string contains any numerals. Used to - * differentiate between completely neutral strings and those containing - * numbers, which are weakly LTR. + * Determines the active element in the given document. + * @param {Document} doc The document to look in. + * @return {Element} The active element. + */ +goog.dom.getActiveElement = function(doc) { + try { + return doc && doc.activeElement; + } catch (e) { + // NOTE(nicksantos): Sometimes, evaluating document.activeElement in IE + // throws an exception. I'm not 100% sure why, but I suspect it chokes + // on document.activeElement if the activeElement has been recently + // removed from the DOM by a JS operation. + // + // We assume that an exception here simply means + // "there is no active element." + } + + return null; +}; + + +/** + * Gives the current devicePixelRatio. * - * Native Arabic digits (\u0660 - \u0669) are not included because although they - * do flow left-to-right inside a number, this is the case even if the overall - * directionality is RTL, and a mathematical expression using these digits is - * supposed to flow right-to-left overall, including unary plus and minus - * appearing to the right of a number, and this does depend on the overall - * directionality being RTL. The digits used in Farsi (\u06F0 - \u06F9), on the - * other hand, are included, since Farsi math (including unary plus and minus) - * does flow left-to-right. + * By default, this is the value of window.devicePixelRatio (which should be + * preferred if present). * - * @type {RegExp} - * @private + * If window.devicePixelRatio is not present, the ratio is calculated with + * window.matchMedia, if present. Otherwise, gives 1.0. + * + * Some browsers (including Chrome) consider the browser zoom level in the pixel + * ratio, so the value may change across multiple calls. + * + * @return {number} The number of actual pixels per virtual pixel. */ -goog.i18n.bidi.hasNumeralsRe_ = /[\d\u06f0-\u06f9]/; +goog.dom.getPixelRatio = function() { + var win = goog.dom.getWindow(); + if (goog.isDef(win.devicePixelRatio)) { + return win.devicePixelRatio; + } else if (win.matchMedia) { + return goog.dom.matchesPixelRatio_(.75) || + goog.dom.matchesPixelRatio_(1.5) || + goog.dom.matchesPixelRatio_(2) || + goog.dom.matchesPixelRatio_(3) || 1; + } + return 1; +}; /** - * This constant controls threshold of RTL directionality. - * @type {number} + * Calculates a mediaQuery to check if the current device supports the + * given actual to virtual pixel ratio. + * @param {number} pixelRatio The ratio of actual pixels to virtual pixels. + * @return {number} pixelRatio if applicable, otherwise 0. * @private */ -goog.i18n.bidi.rtlDetectionThreshold_ = 0.40; +goog.dom.matchesPixelRatio_ = function(pixelRatio) { + var win = goog.dom.getWindow(); + var query = ('(-webkit-min-device-pixel-ratio: ' + pixelRatio + '),' + + '(min--moz-device-pixel-ratio: ' + pixelRatio + '),' + + '(min-resolution: ' + pixelRatio + 'dppx)'); + return win.matchMedia(query).matches ? pixelRatio : 0; +}; + /** - * Estimates the directionality of a string based on relative word counts. - * If the number of RTL words is above a certain percentage of the total number - * of strongly directional words, returns RTL. - * Otherwise, if any words are strongly or weakly LTR, returns LTR. - * Otherwise, returns UNKNOWN, which is used to mean "neutral". - * Numbers are counted as weakly LTR. - * @param {string} str The string to be checked. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}. + * Create an instance of a DOM helper with a new document object. + * @param {Document=} opt_document Document object to associate with this + * DOM helper. + * @constructor */ -goog.i18n.bidi.estimateDirection = function(str, opt_isHtml) { - var rtlCount = 0; - var totalCount = 0; - var hasWeaklyLtr = false; - var tokens = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml). - split(goog.i18n.bidi.wordSeparatorRe_); - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i]; - if (goog.i18n.bidi.startsWithRtl(token)) { - rtlCount++; - totalCount++; - } else if (goog.i18n.bidi.isRequiredLtrRe_.test(token)) { - hasWeaklyLtr = true; - } else if (goog.i18n.bidi.hasAnyLtr(token)) { - totalCount++; - } else if (goog.i18n.bidi.hasNumeralsRe_.test(token)) { - hasWeaklyLtr = true; - } - } - - return totalCount == 0 ? - (hasWeaklyLtr ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL) : - (rtlCount / totalCount > goog.i18n.bidi.rtlDetectionThreshold_ ? - goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR); +goog.dom.DomHelper = function(opt_document) { + /** + * Reference to the document object to use + * @type {!Document} + * @private + */ + this.document_ = opt_document || goog.global.document || document; }; /** - * Check the directionality of a piece of text, return true if the piece of - * text should be laid out in RTL direction. - * @param {string} str The piece of text that need to be detected. - * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped. - * Default: false. - * @return {boolean} Whether this piece of text should be laid out in RTL. + * Gets the dom helper object for the document where the element resides. + * @param {Node=} opt_node If present, gets the DomHelper for this node. + * @return {!goog.dom.DomHelper} The DomHelper. */ -goog.i18n.bidi.detectRtlDirectionality = function(str, opt_isHtml) { - return goog.i18n.bidi.estimateDirection(str, opt_isHtml) == - goog.i18n.bidi.Dir.RTL; -}; +goog.dom.DomHelper.prototype.getDomHelper = goog.dom.getDomHelper; /** - * Sets text input element's directionality and text alignment based on a - * given directionality. Does nothing if the given directionality is unknown or - * neutral. - * @param {Element} element Input field element to set directionality to. - * @param {goog.i18n.bidi.Dir|number|boolean|null} dir Desired directionality, - * given in one of the following formats: - * 1. A goog.i18n.bidi.Dir constant. - * 2. A number (positive = LRT, negative = RTL, 0 = neutral). - * 3. A boolean (true = RTL, false = LTR). - * 4. A null for unknown directionality. + * Sets the document object. + * @param {!Document} document Document object. */ -goog.i18n.bidi.setElementDirAndAlign = function(element, dir) { - if (element) { - dir = goog.i18n.bidi.toDir(dir); - if (dir) { - element.style.textAlign = - dir == goog.i18n.bidi.Dir.RTL ? - goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT; - element.dir = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr'; - } - } +goog.dom.DomHelper.prototype.setDocument = function(document) { + this.document_ = document; }; /** - * Sets element dir based on estimated directionality of the given text. - * @param {!Element} element - * @param {string} text + * Gets the document object being used by the dom library. + * @return {!Document} Document object. */ -goog.i18n.bidi.setElementDirByTextDirectionality = function(element, text) { - switch (goog.i18n.bidi.estimateDirection(text)) { - case (goog.i18n.bidi.Dir.LTR): - element.dir = 'ltr'; - break; - case (goog.i18n.bidi.Dir.RTL): - element.dir = 'rtl'; - break; - default: - // Default for no direction, inherit from document. - element.removeAttribute('dir'); - } +goog.dom.DomHelper.prototype.getDocument = function() { + return this.document_; }; - /** - * Strings that have an (optional) known direction. - * - * Implementations of this interface are string-like objects that carry an - * attached direction, if known. - * @interface + * Alias for {@code getElementById}. If a DOM node is passed in then we just + * return that. + * @param {string|Element} element Element ID or a DOM node. + * @return {Element} The element with the given ID, or the node passed in. */ -goog.i18n.bidi.DirectionalString = function() {}; +goog.dom.DomHelper.prototype.getElement = function(element) { + return goog.dom.getElementHelper_(this.document_, element); +}; /** - * Interface marker of the DirectionalString interface. + * Gets an element by id, asserting that the element is found. * - * This property can be used to determine at runtime whether or not an object - * implements this interface. All implementations of this interface set this - * property to {@code true}. - * @type {boolean} + * This is used when an element is expected to exist, and should fail with + * an assertion error if it does not (if assertions are enabled). + * + * @param {string} id Element ID. + * @return {!Element} The element with the given ID, if it exists. */ -goog.i18n.bidi.DirectionalString.prototype. - implementsGoogI18nBidiDirectionalString; +goog.dom.DomHelper.prototype.getRequiredElement = function(id) { + return goog.dom.getRequiredElementHelper_(this.document_, id); +}; /** - * Retrieves this object's known direction (if any). - * @return {?goog.i18n.bidi.Dir} The known direction. Null if unknown. + * Alias for {@code getElement}. + * @param {string|Element} element Element ID or a DOM node. + * @return {Element} The element with the given ID, or the node passed in. + * @deprecated Use {@link goog.dom.DomHelper.prototype.getElement} instead. */ -goog.i18n.bidi.DirectionalString.prototype.getDirection; +goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview The SafeUrl type and its builders. + * Looks up elements by both tag and class name, using browser native functions + * ({@code querySelectorAll}, {@code getElementsByTagName} or + * {@code getElementsByClassName}) where possible. The returned array is a live + * NodeList or a static list depending on the code path taken. * - * TODO(xtof): Link to document stating type contract. + * @see goog.dom.query + * + * @param {?string=} opt_tag Element tag name or * for all tags. + * @param {?string=} opt_class Optional class name. + * @param {(Document|Element)=} opt_el Optional element to look in. + * @return { {length: number} } Array-like list of elements (only a length + * property and numerical indices are guaranteed to exist). */ +goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(opt_tag, + opt_class, + opt_el) { + return goog.dom.getElementsByTagNameAndClass_(this.document_, opt_tag, + opt_class, opt_el); +}; -goog.provide('goog.html.SafeUrl'); -goog.require('goog.asserts'); -goog.require('goog.fs.url'); -goog.require('goog.i18n.bidi.Dir'); -goog.require('goog.i18n.bidi.DirectionalString'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); +/** + * Returns an array of all the elements with the provided className. + * @see {goog.dom.query} + * @param {string} className the name of the class to look for. + * @param {Element|Document=} opt_el Optional element to look in. + * @return { {length: number} } The items found with the class name provided. + */ +goog.dom.DomHelper.prototype.getElementsByClass = function(className, opt_el) { + var doc = opt_el || this.document_; + return goog.dom.getElementsByClass(className, doc); +}; +/** + * Returns the first element we find matching the provided class name. + * @see {goog.dom.query} + * @param {string} className the name of the class to look for. + * @param {(Element|Document)=} opt_el Optional element to look in. + * @return {Element} The first item found with the class name provided. + */ +goog.dom.DomHelper.prototype.getElementByClass = function(className, opt_el) { + var doc = opt_el || this.document_; + return goog.dom.getElementByClass(className, doc); +}; + /** - * A string that is safe to use in URL context in DOM APIs and HTML documents. - * - * A SafeUrl is a string-like object that carries the security type contract - * that its value as a string will not cause untrusted script execution - * when evaluated as a hyperlink URL in a browser. - * - * Values of this type are guaranteed to be safe to use in URL/hyperlink - * contexts, such as, assignment to URL-valued DOM properties, or - * interpolation into a HTML template in URL context (e.g., inside a href - * attribute), in the sense that the use will not result in a - * Cross-Site-Scripting vulnerability. - * - * Note that, as documented in {@code goog.html.SafeUrl.unwrap}, this type's - * contract does not guarantee that instances are safe to interpolate into HTML - * without appropriate escaping. - * - * Note also that this type's contract does not imply any guarantees regarding - * the resource the URL refers to. In particular, SafeUrls are <b>not</b> - * safe to use in a context where the referred-to resource is interpreted as - * trusted code, e.g., as the src of a script tag. - * - * Instances of this type must be created via the factory methods - * ({@code goog.html.SafeUrl.fromConstant}, {@code goog.html.SafeUrl.sanitize}), - * etc and not by invoking its constructor. The constructor intentionally - * takes no parameters and the type is immutable; hence only a default instance - * corresponding to the empty string can be obtained via constructor invocation. + * Ensures an element with the given className exists, and then returns the + * first element with the provided className. + * @see {goog.dom.query} + * @param {string} className the name of the class to look for. + * @param {(!Element|!Document)=} opt_root Optional element or document to look + * in. + * @return {!Element} The first item found with the class name provided. + * @throws {goog.asserts.AssertionError} Thrown if no element is found. + */ +goog.dom.DomHelper.prototype.getRequiredElementByClass = function(className, + opt_root) { + var root = opt_root || this.document_; + return goog.dom.getRequiredElementByClass(className, root); +}; + + +/** + * Alias for {@code getElementsByTagNameAndClass}. + * @deprecated Use DomHelper getElementsByTagNameAndClass. + * @see goog.dom.query * - * @see goog.html.SafeUrl#fromConstant - * @see goog.html.SafeUrl#from - * @see goog.html.SafeUrl#sanitize - * @constructor - * @final - * @struct - * @implements {goog.i18n.bidi.DirectionalString} - * @implements {goog.string.TypedString} + * @param {?string=} opt_tag Element tag name. + * @param {?string=} opt_class Optional class name. + * @param {Element=} opt_el Optional element to look in. + * @return { {length: number} } Array-like list of elements (only a length + * property and numerical indices are guaranteed to exist). */ -goog.html.SafeUrl = function() { - /** - * The contained value of this SafeUrl. The field has a purposely ugly - * name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ''; +goog.dom.DomHelper.prototype.$$ = + goog.dom.DomHelper.prototype.getElementsByTagNameAndClass; - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeUrl#unwrap - * @const - * @private - */ - this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; + +/** + * Sets a number of properties on a node. + * @param {Element} element DOM node to set properties on. + * @param {Object} properties Hash of property:value pairs. + */ +goog.dom.DomHelper.prototype.setProperties = goog.dom.setProperties; + + +/** + * Gets the dimensions of the viewport. + * @param {Window=} opt_window Optional window element to test. Defaults to + * the window of the Dom Helper. + * @return {!goog.math.Size} Object with values 'width' and 'height'. + */ +goog.dom.DomHelper.prototype.getViewportSize = function(opt_window) { + // TODO(arv): This should not take an argument. That breaks the rule of a + // a DomHelper representing a single frame/window/document. + return goog.dom.getViewportSize(opt_window || this.getWindow()); }; /** - * The innocuous string generated by goog.html.SafeUrl.sanitize when passed - * an unsafe URL. - * - * about:invalid is registered in - * http://www.w3.org/TR/css3-values/#about-invalid. - * http://tools.ietf.org/html/rfc6694#section-2.2.1 permits about URLs to - * contain a fragment, which is not to be considered when determining if an - * about URL is well-known. - * - * Using about:invalid seems preferable to using a fixed data URL, since - * browsers might choose to not report CSP violations on it, as legitimate - * CSS function calls to attr() can result in this URL being produced. It is - * also a standard URL which matches exactly the semantics we need: - * "The about:invalid URI references a non-existent document with a generic - * error condition. It can be used when a URI is necessary, but the default - * value shouldn't be resolveable as any type of document". + * Calculates the height of the document. * - * @const {string} + * @return {number} The height of the document. */ -goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez'; +goog.dom.DomHelper.prototype.getDocumentHeight = function() { + return goog.dom.getDocumentHeight_(this.getWindow()); +}; /** - * @override - * @const + * Typedef for use with goog.dom.createDom and goog.dom.append. + * @typedef {Object|string|Array|NodeList} */ -goog.html.SafeUrl.prototype.implementsGoogStringTypedString = true; +goog.dom.Appendable; /** - * Returns this SafeUrl's value a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeUrl}, use {@code goog.html.SafeUrl.unwrap} instead of this - * method. If in doubt, assume that it's security relevant. In particular, note - * that goog.html functions which return a goog.html type do not guarantee that - * the returned instance is of the right type. For example: + * Returns a dom node with a set of attributes. This function accepts varargs + * for subsequent nodes to be added. Subsequent nodes will be added to the + * first node as childNodes. * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof - * // goog.html.SafeHtml. - * </pre> + * So: + * <code>createDom('div', null, createDom('p'), createDom('p'));</code> + * would return a div with two child paragraphs * - * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the - * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST - * be appropriately escaped before embedding in a HTML document. Note that the - * required escaping is context-sensitive (e.g. a different escaping is - * required for embedding a URL in a style property within a style - * attribute, as opposed to embedding in a href attribute). + * An easy way to move all child nodes of an existing element to a new parent + * element is: + * <code>createDom('div', null, oldElement.childNodes);</code> + * which will remove all child nodes from the old element and add them as + * child nodes of the new DIV. * - * @see goog.html.SafeUrl#unwrap - * @override + * @param {string} tagName Tag to create. + * @param {Object|string=} opt_attributes If object, then a map of name-value + * pairs for attributes. If a string, then this is the className of the new + * element. + * @param {...goog.dom.Appendable} var_args Further DOM nodes or + * strings for text nodes. If one of the var_args is an array or + * NodeList, its elements will be added as childNodes instead. + * @return {!Element} Reference to a DOM node. */ -goog.html.SafeUrl.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_; +goog.dom.DomHelper.prototype.createDom = function(tagName, + opt_attributes, + var_args) { + return goog.dom.createDom_(this.document_, arguments); }; /** - * @override - * @const + * Alias for {@code createDom}. + * @param {string} tagName Tag to create. + * @param {(Object|string)=} opt_attributes If object, then a map of name-value + * pairs for attributes. If a string, then this is the className of the new + * element. + * @param {...goog.dom.Appendable} var_args Further DOM nodes or strings for + * text nodes. If one of the var_args is an array, its children will be + * added as childNodes instead. + * @return {!Element} Reference to a DOM node. + * @deprecated Use {@link goog.dom.DomHelper.prototype.createDom} instead. */ -goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = true; +goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom; /** - * Returns this URLs directionality, which is always {@code LTR}. - * @override + * Creates a new element. + * @param {string} name Tag name. + * @return {!Element} The new element. */ -goog.html.SafeUrl.prototype.getDirection = function() { - return goog.i18n.bidi.Dir.LTR; +goog.dom.DomHelper.prototype.createElement = function(name) { + return this.document_.createElement(name); }; -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeUrl, use - * {@code goog.html.SafeUrl.unwrap}. - * - * @see goog.html.SafeUrl#unwrap - * @override - */ - goog.html.SafeUrl.prototype.toString = function() { - return 'SafeUrl{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ + - '}'; - }; -} - - /** - * Performs a runtime check that the provided object is indeed a SafeUrl - * object, and returns its value. - * - * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the - * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST - * be appropriately escaped before embedding in a HTML document. Note that the - * required escaping is context-sensitive (e.g. a different escaping is - * required for embedding a URL in a style property within a style - * attribute, as opposed to embedding in a href attribute). - * - * @param {!goog.html.SafeUrl} safeUrl The object to extract from. - * @return {string} The SafeUrl object's contained string, unless the run-time - * type check fails. In that case, {@code unwrap} returns an innocuous - * string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * Creates a new text node. + * @param {number|string} content Content. + * @return {!Text} The new text node. */ -goog.html.SafeUrl.unwrap = function(safeUrl) { - // Perform additional Run-time type-checking to ensure that safeUrl is indeed - // an instance of the expected type. This provides some additional protection - // against security bugs due to application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeUrl instanceof goog.html.SafeUrl && - safeUrl.constructor === goog.html.SafeUrl && - safeUrl.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_; - } else { - goog.asserts.fail('expected object of type SafeUrl, got \'' + - safeUrl + '\''); - return 'type_error:SafeUrl'; - - } +goog.dom.DomHelper.prototype.createTextNode = function(content) { + return this.document_.createTextNode(String(content)); }; /** - * Creates a SafeUrl object from a compile-time constant string. - * - * Compile-time constant strings are inherently program-controlled and hence - * trusted. - * - * @param {!goog.string.Const} url A compile-time-constant string from which to - * create a SafeUrl. - * @return {!goog.html.SafeUrl} A SafeUrl object initialized to {@code url}. + * Create a table. + * @param {number} rows The number of rows in the table. Must be >= 1. + * @param {number} columns The number of columns in the table. Must be >= 1. + * @param {boolean=} opt_fillWithNbsp If true, fills table entries with + * {@code goog.string.Unicode.NBSP} characters. + * @return {!HTMLElement} The created table. */ -goog.html.SafeUrl.fromConstant = function(url) { - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( - goog.string.Const.unwrap(url)); +goog.dom.DomHelper.prototype.createTable = function(rows, columns, + opt_fillWithNbsp) { + return goog.dom.createTable_(this.document_, rows, columns, + !!opt_fillWithNbsp); }; /** - * A pattern that matches Blob or data types that can have SafeUrls created - * from URL.createObjectURL(blob) or via a data: URI. Only matches image and - * video types, currently. - * @const - * @private + * Converts an HTML into a node or a document fragment. A single Node is used if + * {@code html} only generates a single node. If {@code html} generates multiple + * nodes then these are put inside a {@code DocumentFragment}. + * @param {!goog.html.SafeHtml} html The HTML markup to convert. + * @return {!Node} The resulting node. */ -goog.html.SAFE_MIME_TYPE_PATTERN_ = - /^(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm))$/i; +goog.dom.DomHelper.prototype.safeHtmlToNode = function(html) { + return goog.dom.safeHtmlToNode_(this.document_, html); +}; /** - * Creates a SafeUrl wrapping a blob URL for the given {@code blob}. - * - * The blob URL is created with {@code URL.createObjectURL}. If the MIME type - * for {@code blob} is not of a known safe image or video MIME type, then the - * SafeUrl will wrap {@link #INNOCUOUS_STRING}. + * Converts an HTML string into a node or a document fragment. A single Node + * is used if the {@code htmlString} only generates a single node. If the + * {@code htmlString} generates multiple nodes then these are put inside a + * {@code DocumentFragment}. * - * @see http://www.w3.org/TR/FileAPI/#url - * @param {!Blob} blob - * @return {!goog.html.SafeUrl} The blob URL, or an innocuous string wrapped - * as a SafeUrl. + * @param {string} htmlString The HTML string to convert. + * @return {!Node} The resulting node. */ -goog.html.SafeUrl.fromBlob = function(blob) { - var url = goog.html.SAFE_MIME_TYPE_PATTERN_.test(blob.type) ? - goog.fs.url.createObjectUrl(blob) : goog.html.SafeUrl.INNOCUOUS_STRING; - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); +goog.dom.DomHelper.prototype.htmlToDocumentFragment = function(htmlString) { + return goog.dom.htmlToDocumentFragment_(this.document_, htmlString); }; /** - * Matches a base-64 data URL, with the first match group being the MIME type. - * @const - * @private + * Returns true if the browser is in "CSS1-compatible" (standards-compliant) + * mode, false otherwise. + * @return {boolean} True if in CSS1-compatible mode. */ -goog.html.DATA_URL_PATTERN_ = /^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; +goog.dom.DomHelper.prototype.isCss1CompatMode = function() { + return goog.dom.isCss1CompatMode_(this.document_); +}; /** - * Creates a SafeUrl wrapping a data: URL, after validating it matches a - * known-safe image or video MIME type. - * - * @param {string} dataUrl A valid base64 data URL with one of the whitelisted - * image or video MIME types. - * @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING} - * wrapped as a SafeUrl if it does not pass. + * Gets the window object associated with the document. + * @return {!Window} The window associated with the given document. */ -goog.html.SafeUrl.fromDataUrl = function(dataUrl) { - // There's a slight risk here that a browser sniffs the content type if it - // doesn't know the MIME type and executes HTML within the data: URL. For this - // to cause XSS it would also have to execute the HTML in the same origin - // of the page with the link. It seems unlikely that both of these will - // happen, particularly in not really old IEs. - var match = dataUrl.match(goog.html.DATA_URL_PATTERN_); - var valid = match && goog.html.SAFE_MIME_TYPE_PATTERN_.test(match[1]); - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( - valid ? dataUrl : goog.html.SafeUrl.INNOCUOUS_STRING); +goog.dom.DomHelper.prototype.getWindow = function() { + return goog.dom.getWindow_(this.document_); }; /** - * A pattern that recognizes a commonly useful subset of URLs that satisfy - * the SafeUrl contract. - * - * This regular expression matches a subset of URLs that will not cause script - * execution if used in URL context within a HTML document. Specifically, this - * regular expression matches if (comment from here on and regex copied from - * Soy's EscapingConventions): - * (1) Either a protocol in a whitelist (http, https, mailto or ftp). - * (2) or no protocol. A protocol must be followed by a colon. The below - * allows that by allowing colons only after one of the characters [/?#]. - * A colon after a hash (#) must be in the fragment. - * Otherwise, a colon after a (?) must be in a query. - * Otherwise, a colon after a single solidus (/) must be in a path. - * Otherwise, a colon after a double solidus (//) must be in the authority - * (before port). - * - * The pattern disallows &, used in HTML entity declarations before - * one of the characters in [/?#]. This disallows HTML entities used in the - * protocol name, which should never happen, e.g. "http" for "http". - * It also disallows HTML entities in the first path part of a relative path, - * e.g. "foo<bar/baz". Our existing escaping functions should not produce - * that. More importantly, it disallows masking of a colon, - * e.g. "javascript:...". - * - * @private - * @const {!RegExp} + * Gets the document scroll element. + * @return {!Element} Scrolling element. */ -goog.html.SAFE_URL_PATTERN_ = - /^(?:(?:https?|mailto|ftp):|[^&:/?#]*(?:[/?#]|$))/i; +goog.dom.DomHelper.prototype.getDocumentScrollElement = function() { + return goog.dom.getDocumentScrollElement_(this.document_); +}; /** - * Creates a SafeUrl object from {@code url}. If {@code url} is a - * goog.html.SafeUrl then it is simply returned. Otherwise the input string is - * validated to match a pattern of commonly used safe URLs. The string is - * converted to UTF-8 and non-whitelisted characters are percent-encoded. The - * string wrapped by the created SafeUrl will thus contain only ASCII printable - * characters. - * - * {@code url} may be a URL with the http, https, mailto or ftp scheme, - * or a relative URL (i.e., a URL without a scheme; specifically, a - * scheme-relative, absolute-path-relative, or path-relative URL). - * - * {@code url} is converted to UTF-8 and non-whitelisted characters are - * percent-encoded. Whitelisted characters are '%' and, from RFC 3986, - * unreserved characters and reserved characters, with the exception of '\'', - * '(' and ')'. This ensures the the SafeUrl contains only ASCII-printable - * characters and reduces the chance of security bugs were it to be - * interpolated into a specific context without the necessary escaping. - * - * If {@code url} fails validation or does not UTF-16 decode correctly - * (JavaScript strings are UTF-16 encoded), this function returns a SafeUrl - * object containing an innocuous string, goog.html.SafeUrl.INNOCUOUS_STRING. - * - * @see http://url.spec.whatwg.org/#concept-relative-url - * @param {string|!goog.string.TypedString} url The URL to validate. - * @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl. + * Gets the document scroll distance as a coordinate object. + * @return {!goog.math.Coordinate} Object with properties 'x' and 'y'. */ -goog.html.SafeUrl.sanitize = function(url) { - if (url instanceof goog.html.SafeUrl) { - return url; - } - else if (url.implementsGoogStringTypedString) { - url = url.getTypedStringValue(); - } else { - url = String(url); - } - if (!goog.html.SAFE_URL_PATTERN_.test(url)) { - url = goog.html.SafeUrl.INNOCUOUS_STRING; - } - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); +goog.dom.DomHelper.prototype.getDocumentScroll = function() { + return goog.dom.getDocumentScroll_(this.document_); }; /** - * Type marker for the SafeUrl type, used to implement additional run-time - * type checking. - * @const {!Object} - * @private + * Determines the active element in the given document. + * @param {Document=} opt_doc The document to look in. + * @return {Element} The active element. */ -goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; +goog.dom.DomHelper.prototype.getActiveElement = function(opt_doc) { + return goog.dom.getActiveElement(opt_doc || this.document_); +}; /** - * Package-internal utility method to create SafeUrl instances. - * - * @param {string} url The string to initialize the SafeUrl object with. - * @return {!goog.html.SafeUrl} The initialized SafeUrl object. - * @package + * Appends a child to a node. + * @param {Node} parent Parent. + * @param {Node} child Child. */ -goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function( - url) { - var safeUrl = new goog.html.SafeUrl(); - safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = url; - return safeUrl; -}; +goog.dom.DomHelper.prototype.appendChild = goog.dom.appendChild; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview The TrustedResourceUrl type and its builders. - * - * TODO(xtof): Link to document stating type contract. + * Appends a node with text or other nodes. + * @param {!Node} parent The node to append nodes to. + * @param {...goog.dom.Appendable} var_args The things to append to the node. + * If this is a Node it is appended as is. + * If this is a string then a text node is appended. + * If this is an array like object then fields 0 to length - 1 are appended. */ - -goog.provide('goog.html.TrustedResourceUrl'); - -goog.require('goog.asserts'); -goog.require('goog.i18n.bidi.Dir'); -goog.require('goog.i18n.bidi.DirectionalString'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); - +goog.dom.DomHelper.prototype.append = goog.dom.append; /** - * A URL which is under application control and from which script, CSS, and - * other resources that represent executable code, can be fetched. - * - * Given that the URL can only be constructed from strings under application - * control and is used to load resources, bugs resulting in a malformed URL - * should not have a security impact and are likely to be easily detectable - * during testing. Given the wide number of non-RFC compliant URLs in use, - * stricter validation could prevent some applications from being able to use - * this type. - * - * Instances of this type must be created via the factory method, - * ({@code goog.html.TrustedResourceUrl.fromConstant}), and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty - * string can be obtained via constructor invocation. + * Determines if the given node can contain children, intended to be used for + * HTML generation. * - * @see goog.html.TrustedResourceUrl#fromConstant - * @constructor - * @final - * @struct - * @implements {goog.i18n.bidi.DirectionalString} - * @implements {goog.string.TypedString} + * @param {Node} node The node to check. + * @return {boolean} Whether the node can contain children. */ -goog.html.TrustedResourceUrl = function() { - /** - * The contained value of this TrustedResourceUrl. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = ''; - - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.TrustedResourceUrl#unwrap - * @const - * @private - */ - this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; -}; +goog.dom.DomHelper.prototype.canHaveChildren = goog.dom.canHaveChildren; /** - * @override - * @const + * Removes all the child nodes on a DOM node. + * @param {Node} node Node to remove children from. */ -goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true; +goog.dom.DomHelper.prototype.removeChildren = goog.dom.removeChildren; /** - * Returns this TrustedResourceUrl's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code TrustedResourceUrl}, use - * {@code goog.html.TrustedResourceUrl.unwrap} instead of this method. If in - * doubt, assume that it's security relevant. In particular, note that - * goog.html functions which return a goog.html type do not guarantee that - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof - * // goog.html.SafeHtml. - * </pre> - * - * @see goog.html.TrustedResourceUrl#unwrap - * @override + * Inserts a new node before an existing reference node (i.e., as the previous + * sibling). If the reference node has no parent, then does nothing. + * @param {Node} newNode Node to insert. + * @param {Node} refNode Reference node to insert before. */ -goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_; -}; +goog.dom.DomHelper.prototype.insertSiblingBefore = goog.dom.insertSiblingBefore; /** - * @override - * @const + * Inserts a new node after an existing reference node (i.e., as the next + * sibling). If the reference node has no parent, then does nothing. + * @param {Node} newNode Node to insert. + * @param {Node} refNode Reference node to insert after. */ -goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString = - true; +goog.dom.DomHelper.prototype.insertSiblingAfter = goog.dom.insertSiblingAfter; /** - * Returns this URLs directionality, which is always {@code LTR}. - * @override + * Insert a child at a given index. If index is larger than the number of child + * nodes that the parent currently has, the node is inserted as the last child + * node. + * @param {Element} parent The element into which to insert the child. + * @param {Node} child The element to insert. + * @param {number} index The index at which to insert the new child node. Must + * not be negative. */ -goog.html.TrustedResourceUrl.prototype.getDirection = function() { - return goog.i18n.bidi.Dir.LTR; -}; +goog.dom.DomHelper.prototype.insertChildAt = goog.dom.insertChildAt; -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a TrustedResourceUrl, use - * {@code goog.html.TrustedResourceUrl.unwrap}. - * - * @see goog.html.TrustedResourceUrl#unwrap - * @override - */ - goog.html.TrustedResourceUrl.prototype.toString = function() { - return 'TrustedResourceUrl{' + - this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}'; - }; -} +/** + * Removes a node from its parent. + * @param {Node} node The node to remove. + * @return {Node} The node removed if removed; else, null. + */ +goog.dom.DomHelper.prototype.removeNode = goog.dom.removeNode; /** - * Performs a runtime check that the provided object is indeed a - * TrustedResourceUrl object, and returns its value. - * - * @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to - * extract from. - * @return {string} The trustedResourceUrl object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no + * parent. + * @param {Node} newNode Node to insert. + * @param {Node} oldNode Node to replace. */ -goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) { - // Perform additional Run-time type-checking to ensure that - // trustedResourceUrl is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl && - trustedResourceUrl.constructor === goog.html.TrustedResourceUrl && - trustedResourceUrl - .TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.TrustedResourceUrl - .TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return trustedResourceUrl - .privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_; - } else { - goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' + - trustedResourceUrl + '\''); - return 'type_error:TrustedResourceUrl'; - - } -}; +goog.dom.DomHelper.prototype.replaceNode = goog.dom.replaceNode; /** - * Creates a TrustedResourceUrl object from a compile-time constant string. - * - * Compile-time constant strings are inherently program-controlled and hence - * trusted. - * - * @param {!goog.string.Const} url A compile-time-constant string from which to - * create a TrustedResourceUrl. - * @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object - * initialized to {@code url}. + * Flattens an element. That is, removes it and replace it with its children. + * @param {Element} element The element to flatten. + * @return {Element|undefined} The original element, detached from the document + * tree, sans children, or undefined if the element was already not in the + * document. */ -goog.html.TrustedResourceUrl.fromConstant = function(url) { - return goog.html.TrustedResourceUrl - .createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( - goog.string.Const.unwrap(url)); -}; +goog.dom.DomHelper.prototype.flattenElement = goog.dom.flattenElement; /** - * Type marker for the TrustedResourceUrl type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private + * Returns an array containing just the element children of the given element. + * @param {Element} element The element whose element children we want. + * @return {!(Array|NodeList)} An array or array-like list of just the element + * children of the given element. */ -goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; +goog.dom.DomHelper.prototype.getChildren = goog.dom.getChildren; /** - * Package-internal utility method to create TrustedResourceUrl instances. - * - * @param {string} url The string to initialize the TrustedResourceUrl object - * with. - * @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl - * object. - * @package + * Returns the first child node that is an element. + * @param {Node} node The node to get the first child element of. + * @return {Element} The first child node of {@code node} that is an element. */ -goog.html.TrustedResourceUrl. - createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) { - var trustedResourceUrl = new goog.html.TrustedResourceUrl(); - trustedResourceUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = - url; - return trustedResourceUrl; -}; +goog.dom.DomHelper.prototype.getFirstElementChild = + goog.dom.getFirstElementChild; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + +/** + * Returns the last child node that is an element. + * @param {Node} node The node to get the last child element of. + * @return {Element} The last child node of {@code node} that is an element. + */ +goog.dom.DomHelper.prototype.getLastElementChild = goog.dom.getLastElementChild; /** - * @fileoverview The SafeHtml type and its builders. - * - * TODO(xtof): Link to document stating type contract. + * Returns the first next sibling that is an element. + * @param {Node} node The node to get the next sibling element of. + * @return {Element} The next sibling of {@code node} that is an element. */ +goog.dom.DomHelper.prototype.getNextElementSibling = + goog.dom.getNextElementSibling; -goog.provide('goog.html.SafeHtml'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.tags'); -goog.require('goog.html.SafeStyle'); -goog.require('goog.html.SafeStyleSheet'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.TrustedResourceUrl'); -goog.require('goog.i18n.bidi.Dir'); -goog.require('goog.i18n.bidi.DirectionalString'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); +/** + * Returns the first previous sibling that is an element. + * @param {Node} node The node to get the previous sibling element of. + * @return {Element} The first previous sibling of {@code node} that is + * an element. + */ +goog.dom.DomHelper.prototype.getPreviousElementSibling = + goog.dom.getPreviousElementSibling; +/** + * Returns the next node in source order from the given node. + * @param {Node} node The node. + * @return {Node} The next node in the DOM tree, or null if this was the last + * node. + */ +goog.dom.DomHelper.prototype.getNextNode = goog.dom.getNextNode; + /** - * A string that is safe to use in HTML context in DOM APIs and HTML documents. - * - * A SafeHtml is a string-like object that carries the security type contract - * that its value as a string will not cause untrusted script execution when - * evaluated as HTML in a browser. - * - * Values of this type are guaranteed to be safe to use in HTML contexts, - * such as, assignment to the innerHTML DOM property, or interpolation into - * a HTML template in HTML PC_DATA context, in the sense that the use will not - * result in a Cross-Site-Scripting vulnerability. - * - * Instances of this type must be created via the factory methods - * ({@code goog.html.SafeHtml.create}, {@code goog.html.SafeHtml.htmlEscape}), - * etc and not by invoking its constructor. The constructor intentionally - * takes no parameters and the type is immutable; hence only a default instance - * corresponding to the empty string can be obtained via constructor invocation. - * - * @see goog.html.SafeHtml#create - * @see goog.html.SafeHtml#htmlEscape - * @constructor - * @final - * @struct - * @implements {goog.i18n.bidi.DirectionalString} - * @implements {goog.string.TypedString} + * Returns the previous node in source order from the given node. + * @param {Node} node The node. + * @return {Node} The previous node in the DOM tree, or null if this was the + * first node. */ -goog.html.SafeHtml = function() { - /** - * The contained value of this SafeHtml. The field has a purposely ugly - * name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} - */ - this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ''; +goog.dom.DomHelper.prototype.getPreviousNode = goog.dom.getPreviousNode; - /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeHtml#unwrap - * @const - * @private - */ - this.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; - /** - * This SafeHtml's directionality, or null if unknown. - * @private {?goog.i18n.bidi.Dir} - */ - this.dir_ = null; -}; +/** + * Whether the object looks like a DOM node. + * @param {?} obj The object being tested for node likeness. + * @return {boolean} Whether the object looks like a DOM node. + */ +goog.dom.DomHelper.prototype.isNodeLike = goog.dom.isNodeLike; /** - * @override - * @const + * Whether the object looks like an Element. + * @param {?} obj The object being tested for Element likeness. + * @return {boolean} Whether the object looks like an Element. */ -goog.html.SafeHtml.prototype.implementsGoogI18nBidiDirectionalString = true; +goog.dom.DomHelper.prototype.isElement = goog.dom.isElement; -/** @override */ -goog.html.SafeHtml.prototype.getDirection = function() { - return this.dir_; -}; +/** + * Returns true if the specified value is a Window object. This includes the + * global window for HTML pages, and iframe windows. + * @param {?} obj Variable to test. + * @return {boolean} Whether the variable is a window. + */ +goog.dom.DomHelper.prototype.isWindow = goog.dom.isWindow; /** - * @override - * @const + * Returns an element's parent, if it's an Element. + * @param {Element} element The DOM element. + * @return {Element} The parent, or null if not an Element. */ -goog.html.SafeHtml.prototype.implementsGoogStringTypedString = true; +goog.dom.DomHelper.prototype.getParentElement = goog.dom.getParentElement; /** - * Returns this SafeHtml's value a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeHtml}, use {@code goog.html.SafeHtml.unwrap} instead of - * this method. If in doubt, assume that it's security relevant. In particular, - * note that goog.html functions which return a goog.html type do not guarantee - * that the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> + * Whether a node contains another node. + * @param {Node} parent The node that should contain the other node. + * @param {Node} descendant The node to test presence of. + * @return {boolean} Whether the parent node contains the descendent node. + */ +goog.dom.DomHelper.prototype.contains = goog.dom.contains; + + +/** + * Compares the document order of two nodes, returning 0 if they are the same + * node, a negative number if node1 is before node2, and a positive number if + * node2 is before node1. Note that we compare the order the tags appear in the + * document so in the tree <b><i>text</i></b> the B node is considered to be + * before the I node. * - * @see goog.html.SafeHtml#unwrap - * @override + * @param {Node} node1 The first node to compare. + * @param {Node} node2 The second node to compare. + * @return {number} 0 if the nodes are the same node, a negative number if node1 + * is before node2, and a positive number if node2 is before node1. */ -goog.html.SafeHtml.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_; -}; +goog.dom.DomHelper.prototype.compareNodeOrder = goog.dom.compareNodeOrder; -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeHtml, use - * {@code goog.html.SafeHtml.unwrap}. - * - * @see goog.html.SafeHtml#unwrap - * @override - */ - goog.html.SafeHtml.prototype.toString = function() { - return 'SafeHtml{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ + - '}'; - }; -} +/** + * Find the deepest common ancestor of the given nodes. + * @param {...Node} var_args The nodes to find a common ancestor of. + * @return {Node} The common ancestor of the nodes, or null if there is none. + * null will only be returned if two or more of the nodes are from different + * documents. + */ +goog.dom.DomHelper.prototype.findCommonAncestor = goog.dom.findCommonAncestor; /** - * Performs a runtime check that the provided object is indeed a SafeHtml - * object, and returns its value. - * @param {!goog.html.SafeHtml} safeHtml The object to extract from. - * @return {string} The SafeHtml object's contained string, unless the run-time - * type check fails. In that case, {@code unwrap} returns an innocuous - * string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * Returns the owner document for a node. + * @param {Node} node The node to get the document for. + * @return {!Document} The document owning the node. */ -goog.html.SafeHtml.unwrap = function(safeHtml) { - // Perform additional run-time type-checking to ensure that safeHtml is indeed - // an instance of the expected type. This provides some additional protection - // against security bugs due to application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeHtml instanceof goog.html.SafeHtml && - safeHtml.constructor === goog.html.SafeHtml && - safeHtml.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeHtml.privateDoNotAccessOrElseSafeHtmlWrappedValue_; - } else { - goog.asserts.fail('expected object of type SafeHtml, got \'' + - safeHtml + '\''); - return 'type_error:SafeHtml'; - } -}; +goog.dom.DomHelper.prototype.getOwnerDocument = goog.dom.getOwnerDocument; /** - * Shorthand for union of types that can sensibly be converted to strings - * or might already be SafeHtml (as SafeHtml is a goog.string.TypedString). - * @private - * @typedef {string|number|boolean|!goog.string.TypedString| - * !goog.i18n.bidi.DirectionalString} + * Cross browser function for getting the document element of an iframe. + * @param {Element} iframe Iframe element. + * @return {!Document} The frame content document. */ -goog.html.SafeHtml.TextOrHtml_; +goog.dom.DomHelper.prototype.getFrameContentDocument = + goog.dom.getFrameContentDocument; /** - * Returns HTML-escaped text as a SafeHtml object. - * - * If text is of a type that implements - * {@code goog.i18n.bidi.DirectionalString}, the directionality of the new - * {@code SafeHtml} object is set to {@code text}'s directionality, if known. - * Otherwise, the directionality of the resulting SafeHtml is unknown (i.e., - * {@code null}). - * - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If - * the parameter is of type SafeHtml it is returned directly (no escaping - * is done). - * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. + * Cross browser function for getting the window of a frame or iframe. + * @param {Element} frame Frame element. + * @return {Window} The window associated with the given frame. */ -goog.html.SafeHtml.htmlEscape = function(textOrHtml) { - if (textOrHtml instanceof goog.html.SafeHtml) { - return textOrHtml; - } - var dir = null; - if (textOrHtml.implementsGoogI18nBidiDirectionalString) { - dir = textOrHtml.getDirection(); - } - var textAsString; - if (textOrHtml.implementsGoogStringTypedString) { - textAsString = textOrHtml.getTypedStringValue(); - } else { - textAsString = String(textOrHtml); - } - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - goog.string.htmlEscape(textAsString), dir); -}; +goog.dom.DomHelper.prototype.getFrameContentWindow = + goog.dom.getFrameContentWindow; /** - * Returns HTML-escaped text as a SafeHtml object, with newlines changed to - * <br>. - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If - * the parameter is of type SafeHtml it is returned directly (no escaping - * is done). - * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. + * Sets the text content of a node, with cross-browser support. + * @param {Node} node The node to change the text content of. + * @param {string|number} text The value that should replace the node's content. */ -goog.html.SafeHtml.htmlEscapePreservingNewlines = function(textOrHtml) { - if (textOrHtml instanceof goog.html.SafeHtml) { - return textOrHtml; - } - var html = goog.html.SafeHtml.htmlEscape(textOrHtml); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - goog.string.newLineToBr(goog.html.SafeHtml.unwrap(html)), - html.getDirection()); -}; +goog.dom.DomHelper.prototype.setTextContent = goog.dom.setTextContent; /** - * Returns HTML-escaped text as a SafeHtml object, with newlines changed to - * <br> and escaping whitespace to preserve spatial formatting. Character - * entity #160 is used to make it safer for XML. - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If - * the parameter is of type SafeHtml it is returned directly (no escaping - * is done). - * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml. + * Gets the outerHTML of a node, which islike innerHTML, except that it + * actually contains the HTML of the node itself. + * @param {Element} element The element to get the HTML of. + * @return {string} The outerHTML of the given element. */ -goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces = function( - textOrHtml) { - if (textOrHtml instanceof goog.html.SafeHtml) { - return textOrHtml; - } - var html = goog.html.SafeHtml.htmlEscape(textOrHtml); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - goog.string.whitespaceEscape(goog.html.SafeHtml.unwrap(html)), - html.getDirection()); -}; +goog.dom.DomHelper.prototype.getOuterHtml = goog.dom.getOuterHtml; /** - * Coerces an arbitrary object into a SafeHtml object. - * - * If {@code textOrHtml} is already of type {@code goog.html.SafeHtml}, the same - * object is returned. Otherwise, {@code textOrHtml} is coerced to string, and - * HTML-escaped. If {@code textOrHtml} is of a type that implements - * {@code goog.i18n.bidi.DirectionalString}, its directionality, if known, is - * preserved. - * - * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text or SafeHtml to - * coerce. - * @return {!goog.html.SafeHtml} The resulting SafeHtml object. - * @deprecated Use goog.html.SafeHtml.htmlEscape. + * Finds the first descendant node that matches the filter function. This does + * a depth first search. + * @param {Node} root The root of the tree to search. + * @param {function(Node) : boolean} p The filter function. + * @return {Node|undefined} The found node or undefined if none is found. */ -goog.html.SafeHtml.from = goog.html.SafeHtml.htmlEscape; +goog.dom.DomHelper.prototype.findNode = goog.dom.findNode; /** - * @const - * @private + * Finds all the descendant nodes that matches the filter function. This does a + * depth first search. + * @param {Node} root The root of the tree to search. + * @param {function(Node) : boolean} p The filter function. + * @return {Array<Node>} The found nodes or an empty array if none are found. */ -goog.html.SafeHtml.VALID_NAMES_IN_TAG_ = /^[a-zA-Z0-9-]+$/; +goog.dom.DomHelper.prototype.findNodes = goog.dom.findNodes; /** - * Set of attributes containing URL as defined at - * http://www.w3.org/TR/html5/index.html#attributes-1. - * @private @const {!Object<string,boolean>} + * Returns true if the element has a tab index that allows it to receive + * keyboard focus (tabIndex >= 0), false otherwise. Note that some elements + * natively support keyboard focus, even if they have no tab index. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element has a tab index that allows keyboard + * focus. */ -goog.html.SafeHtml.URL_ATTRIBUTES_ = goog.object.createSet('action', 'cite', - 'data', 'formaction', 'href', 'manifest', 'poster', 'src'); +goog.dom.DomHelper.prototype.isFocusableTabIndex = goog.dom.isFocusableTabIndex; /** - * Tags which are unsupported via create(). They might be supported via a - * tag-specific create method. These are tags which might require a - * TrustedResourceUrl in one of their attributes or a restricted type for - * their content. - * @private @const {!Object<string,boolean>} + * Enables or disables keyboard focus support on the element via its tab index. + * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true + * (or elements that natively support keyboard focus, like form elements) can + * receive keyboard focus. See http://go/tabindex for more info. + * @param {Element} element Element whose tab index is to be changed. + * @param {boolean} enable Whether to set or remove a tab index on the element + * that supports keyboard focus. */ -goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_ = goog.object.createSet( - goog.dom.TagName.EMBED, goog.dom.TagName.IFRAME, goog.dom.TagName.LINK, - goog.dom.TagName.OBJECT, goog.dom.TagName.SCRIPT, goog.dom.TagName.STYLE, - goog.dom.TagName.TEMPLATE); +goog.dom.DomHelper.prototype.setFocusableTabIndex = + goog.dom.setFocusableTabIndex; /** - * @typedef {string|number|goog.string.TypedString| - * goog.html.SafeStyle.PropertyMap} - * @private + * Returns true if the element can be focused, i.e. it has a tab index that + * allows it to receive keyboard focus (tabIndex >= 0), or it is an element + * that natively supports keyboard focus. + * @param {!Element} element Element to check. + * @return {boolean} Whether the element allows keyboard focus. */ -goog.html.SafeHtml.AttributeValue_; +goog.dom.DomHelper.prototype.isFocusable = goog.dom.isFocusable; /** - * Creates a SafeHtml content consisting of a tag with optional attributes and - * optional content. - * - * For convenience tag names and attribute names are accepted as regular - * strings, instead of goog.string.Const. Nevertheless, you should not pass - * user-controlled values to these parameters. Note that these parameters are - * syntactically validated at runtime, and invalid values will result in - * an exception. - * - * Example usage: - * - * goog.html.SafeHtml.create('br'); - * goog.html.SafeHtml.create('div', {'class': 'a'}); - * goog.html.SafeHtml.create('p', {}, 'a'); - * goog.html.SafeHtml.create('p', {}, goog.html.SafeHtml.create('br')); - * - * goog.html.SafeHtml.create('span', { - * 'style': {'margin': '0'} - * }); - * - * To guarantee SafeHtml's type contract is upheld there are restrictions on - * attribute values and tag names. + * Returns the text contents of the current node, without markup. New lines are + * stripped and whitespace is collapsed, such that each character would be + * visible. * - * - For attributes which contain script code (on*), a goog.string.Const is - * required. - * - For attributes which contain style (style), a goog.html.SafeStyle or a - * goog.html.SafeStyle.PropertyMap is required. - * - For attributes which are interpreted as URLs (e.g. src, href) a - * goog.html.SafeUrl, goog.string.Const or string is required. If a string - * is passed, it will be sanitized with SafeUrl.sanitize(). - * - For tags which can load code, more specific goog.html.SafeHtml.create*() - * functions must be used. Tags which can load code and are not supported by - * this function are embed, iframe, link, object, script, style, and template. + * In browsers that support it, innerText is used. Other browsers attempt to + * simulate it via node traversal. Line breaks are canonicalized in IE. * - * @param {string} tagName The name of the tag. Only tag names consisting of - * [a-zA-Z0-9-] are allowed. Tag names documented above are disallowed. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Mapping from attribute names to their values. Only - * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or - * undefined causes the attribute to be omitted. - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to - * HTML-escape and put inside the tag. This must be empty for void tags - * like <br>. Array elements are concatenated. - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - * @throws {Error} If invalid tag name, attribute name, or attribute value is - * provided. - * @throws {goog.asserts.AssertionError} If content for void tag is provided. + * @param {Node} node The node from which we are getting content. + * @return {string} The text content. */ -goog.html.SafeHtml.create = function(tagName, opt_attributes, opt_content) { - if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(tagName)) { - throw Error('Invalid tag name <' + tagName + '>.'); - } - if (tagName.toUpperCase() in goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_) { - throw Error('Tag name <' + tagName + '> is not allowed for SafeHtml.'); - } - return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( - tagName, opt_attributes, opt_content); -}; +goog.dom.DomHelper.prototype.getTextContent = goog.dom.getTextContent; /** - * Creates a SafeHtml representing an iframe tag. - * - * By default the sandbox attribute is set to an empty value, which is the most - * secure option, as it confers the iframe the least privileges. If this - * is too restrictive then granting individual privileges is the preferable - * option. Unsetting the attribute entirely is the least secure option and - * should never be done unless it's stricly necessary. + * Returns the text length of the text contained in a node, without markup. This + * is equivalent to the selection length if the node was selected, or the number + * of cursor movements to traverse the node. Images & BRs take one space. New + * lines are ignored. * - * @param {goog.html.TrustedResourceUrl=} opt_src The value of the src - * attribute. If null or undefined src will not be set. - * @param {goog.html.SafeHtml=} opt_srcdoc The value of the srcdoc attribute. - * If null or undefined srcdoc will not be set. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Mapping from attribute names to their values. Only - * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or - * undefined causes the attribute to be omitted. - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to - * HTML-escape and put inside the tag. Array elements are concatenated. - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - * @throws {Error} If invalid tag name, attribute name, or attribute value is - * provided. If opt_attributes contains the src or srcdoc attributes. + * @param {Node} node The node whose text content length is being calculated. + * @return {number} The length of {@code node}'s text content. */ -goog.html.SafeHtml.createIframe = function( - opt_src, opt_srcdoc, opt_attributes, opt_content) { - var fixedAttributes = {}; - fixedAttributes['src'] = opt_src || null; - fixedAttributes['srcdoc'] = opt_srcdoc || null; - var defaultAttributes = {'sandbox': ''}; - var attributes = goog.html.SafeHtml.combineAttributes( - fixedAttributes, defaultAttributes, opt_attributes); - return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( - 'iframe', attributes, opt_content); -}; +goog.dom.DomHelper.prototype.getNodeTextLength = goog.dom.getNodeTextLength; /** - * Creates a SafeHtml representing a style tag. The type attribute is set - * to "text/css". - * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>} - * styleSheet Content to put inside the tag. Array elements are - * concatenated. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Mapping from attribute names to their values. Only - * attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or - * undefined causes the attribute to be omitted. - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. - * @throws {Error} If invalid attribute name or attribute value is provided. If - * opt_attributes contains the type attribute. + * Returns the text offset of a node relative to one of its ancestors. The text + * length is the same as the length calculated by + * {@code goog.dom.getNodeTextLength}. + * + * @param {Node} node The node whose offset is being calculated. + * @param {Node=} opt_offsetParent Defaults to the node's owner document's body. + * @return {number} The text offset. */ -goog.html.SafeHtml.createStyle = function(styleSheet, opt_attributes) { - var fixedAttributes = {'type': 'text/css'}; - var defaultAttributes = {}; - var attributes = goog.html.SafeHtml.combineAttributes( - fixedAttributes, defaultAttributes, opt_attributes); +goog.dom.DomHelper.prototype.getNodeTextOffset = goog.dom.getNodeTextOffset; - var content = ''; - styleSheet = goog.array.concat(styleSheet); - for (var i = 0; i < styleSheet.length; i++) { - content += goog.html.SafeStyleSheet.unwrap(styleSheet[i]); - } - // Convert to SafeHtml so that it's not HTML-escaped. - var htmlContent = goog.html.SafeHtml - .createSafeHtmlSecurityPrivateDoNotAccessOrElse( - content, goog.i18n.bidi.Dir.NEUTRAL); - return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse( - 'style', attributes, htmlContent); -}; + +/** + * Returns the node at a given offset in a parent node. If an object is + * provided for the optional third parameter, the node and the remainder of the + * offset will stored as properties of this object. + * @param {Node} parent The parent node. + * @param {number} offset The offset into the parent node. + * @param {Object=} opt_result Object to be used to store the return value. The + * return value will be stored in the form {node: Node, remainder: number} + * if this object is provided. + * @return {Node} The node at the given offset. + */ +goog.dom.DomHelper.prototype.getNodeAtOffset = goog.dom.getNodeAtOffset; /** - * @param {string} tagName The tag name. - * @param {string} name The attribute name. - * @param {!goog.html.SafeHtml.AttributeValue_} value The attribute value. - * @return {string} A "name=value" string. - * @throws {Error} If attribute value is unsafe for the given tag and attribute. - * @private + * Returns true if the object is a {@code NodeList}. To qualify as a NodeList, + * the object must have a numeric length property and an item function (which + * has type 'string' on IE for some reason). + * @param {Object} val Object to test. + * @return {boolean} Whether the object is a NodeList. */ -goog.html.SafeHtml.getAttrNameAndValue_ = function(tagName, name, value) { - // If it's goog.string.Const, allow any valid attribute name. - if (value instanceof goog.string.Const) { - value = goog.string.Const.unwrap(value); - } else if (name.toLowerCase() == 'style') { - value = goog.html.SafeHtml.getStyleValue_(value); - } else if (/^on/i.test(name)) { - // TODO(jakubvrana): Disallow more attributes with a special meaning. - throw Error('Attribute "' + name + - '" requires goog.string.Const value, "' + value + '" given.'); - // URL attributes handled differently accroding to tag. - } else if (name.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) { - if (value instanceof goog.html.TrustedResourceUrl) { - value = goog.html.TrustedResourceUrl.unwrap(value); - } else if (value instanceof goog.html.SafeUrl) { - value = goog.html.SafeUrl.unwrap(value); - } else if (goog.isString(value)) { - value = goog.html.SafeUrl.sanitize(value).getTypedStringValue(); - } else { - throw Error('Attribute "' + name + '" on tag "' + tagName + - '" requires goog.html.SafeUrl, goog.string.Const, or string,' + - ' value "' + value + '" given.'); - } - } - - // Accept SafeUrl, TrustedResourceUrl, etc. for attributes which only require - // HTML-escaping. - if (value.implementsGoogStringTypedString) { - // Ok to call getTypedStringValue() since there's no reliance on the type - // contract for security here. - value = value.getTypedStringValue(); - } - - goog.asserts.assert(goog.isString(value) || goog.isNumber(value), - 'String or number value expected, got ' + - (typeof value) + ' with value: ' + value); - return name + '="' + goog.string.htmlEscape(String(value)) + '"'; -}; +goog.dom.DomHelper.prototype.isNodeList = goog.dom.isNodeList; /** - * Gets value allowed in "style" attribute. - * @param {goog.html.SafeHtml.AttributeValue_} value It could be SafeStyle or a - * map which will be passed to goog.html.SafeStyle.create. - * @return {string} Unwrapped value. - * @throws {Error} If string value is given. - * @private + * Walks up the DOM hierarchy returning the first ancestor that has the passed + * tag name and/or class name. If the passed element matches the specified + * criteria, the element itself is returned. + * @param {Node} element The DOM node to start with. + * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or + * null/undefined to match only based on class name). + * @param {?string=} opt_class The class name to match (or null/undefined to + * match only based on tag name). + * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the + * dom. + * @return {Element} The first ancestor that matches the passed criteria, or + * null if no match is found. */ -goog.html.SafeHtml.getStyleValue_ = function(value) { - if (!goog.isObject(value)) { - throw Error('The "style" attribute requires goog.html.SafeStyle or map ' + - 'of style properties, ' + (typeof value) + ' given: ' + value); - } - if (!(value instanceof goog.html.SafeStyle)) { - // Process the property bag into a style object. - value = goog.html.SafeStyle.create(value); - } - return goog.html.SafeStyle.unwrap(value); -}; +goog.dom.DomHelper.prototype.getAncestorByTagNameAndClass = + goog.dom.getAncestorByTagNameAndClass; /** - * Creates a SafeHtml content with known directionality consisting of a tag with - * optional attributes and optional content. - * @param {!goog.i18n.bidi.Dir} dir Directionality. - * @param {string} tagName - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content - * @return {!goog.html.SafeHtml} The SafeHtml content with the tag. + * Walks up the DOM hierarchy returning the first ancestor that has the passed + * class name. If the passed element matches the specified criteria, the + * element itself is returned. + * @param {Node} element The DOM node to start with. + * @param {string} class The class name to match. + * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the + * dom. + * @return {Element} The first ancestor that matches the passed criteria, or + * null if none match. */ -goog.html.SafeHtml.createWithDir = function(dir, tagName, opt_attributes, - opt_content) { - var html = goog.html.SafeHtml.create(tagName, opt_attributes, opt_content); - html.dir_ = dir; - return html; -}; +goog.dom.DomHelper.prototype.getAncestorByClass = + goog.dom.getAncestorByClass; /** - * Creates a new SafeHtml object by concatenating values. - * @param {...(!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Values to concatenate. - * @return {!goog.html.SafeHtml} + * Walks up the DOM hierarchy returning the first ancestor that passes the + * matcher function. + * @param {Node} element The DOM node to start with. + * @param {function(Node) : boolean} matcher A function that returns true if the + * passed node matches the desired criteria. + * @param {boolean=} opt_includeNode If true, the node itself is included in + * the search (the first call to the matcher will pass startElement as + * the node to test). + * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the + * dom. + * @return {Node} DOM node that matched the matcher, or null if there was + * no match. */ -goog.html.SafeHtml.concat = function(var_args) { - var dir = goog.i18n.bidi.Dir.NEUTRAL; - var content = ''; +goog.dom.DomHelper.prototype.getAncestor = goog.dom.getAncestor; - /** - * @param {!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>} argument - */ - var addArgument = function(argument) { - if (goog.isArray(argument)) { - goog.array.forEach(argument, addArgument); - } else { - var html = goog.html.SafeHtml.htmlEscape(argument); - content += goog.html.SafeHtml.unwrap(html); - var htmlDir = html.getDirection(); - if (dir == goog.i18n.bidi.Dir.NEUTRAL) { - dir = htmlDir; - } else if (htmlDir != goog.i18n.bidi.Dir.NEUTRAL && dir != htmlDir) { - dir = null; - } - } - }; +// FIXME add tests for browser features (Modernizr?) - goog.array.forEach(arguments, addArgument); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - content, dir); -}; +goog.provide('ol.dom'); +goog.provide('ol.dom.BrowserFeature'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.userAgent'); +goog.require('goog.vec.Mat4'); +goog.require('ol'); /** - * Creates a new SafeHtml object with known directionality by concatenating the - * values. - * @param {!goog.i18n.bidi.Dir} dir Directionality. - * @param {...(!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Elements of array - * arguments would be processed recursively. - * @return {!goog.html.SafeHtml} + * Create an html canvas element and returns its 2d context. + * @param {number=} opt_width Canvas width. + * @param {number=} opt_height Canvas height. + * @return {CanvasRenderingContext2D} */ -goog.html.SafeHtml.concatWithDir = function(dir, var_args) { - var html = goog.html.SafeHtml.concat(goog.array.slice(arguments, 1)); - html.dir_ = dir; - return html; +ol.dom.createCanvasContext2D = function(opt_width, opt_height) { + var canvas = goog.dom.createElement('CANVAS'); + if (opt_width) { + canvas.width = opt_width; + } + if (opt_height) { + canvas.height = opt_height; + } + return canvas.getContext('2d'); }; /** - * Type marker for the SafeHtml type, used to implement additional run-time - * type checking. - * @const {!Object} - * @private + * Detect 2d transform. + * Adapted from http://stackoverflow.com/q/5661671/130442 + * http://caniuse.com/#feat=transforms2d + * @return {boolean} */ -goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; +ol.dom.canUseCssTransform = (function() { + var canUseCssTransform; + return function() { + if (canUseCssTransform === undefined) { + goog.asserts.assert(document.body, + 'document.body should not be null'); + if (!goog.global.getComputedStyle) { + // this browser is ancient + canUseCssTransform = false; + } else { + var el = goog.dom.createElement('P'), + has2d, + transforms = { + 'webkitTransform': '-webkit-transform', + 'OTransform': '-o-transform', + 'msTransform': '-ms-transform', + 'MozTransform': '-moz-transform', + 'transform': 'transform' + }; + document.body.appendChild(el); + for (var t in transforms) { + if (t in el.style) { + el.style[t] = 'translate(1px,1px)'; + has2d = goog.global.getComputedStyle(el).getPropertyValue( + transforms[t]); + } + } + goog.dom.removeNode(el); + + canUseCssTransform = (has2d && has2d !== 'none'); + } + } + return canUseCssTransform; + }; +}()); /** - * Package-internal utility method to create SafeHtml instances. - * - * @param {string} html The string to initialize the SafeHtml object with. - * @param {?goog.i18n.bidi.Dir} dir The directionality of the SafeHtml to be - * constructed, or null if unknown. - * @return {!goog.html.SafeHtml} The initialized SafeHtml object. - * @package + * Detect 3d transform. + * Adapted from http://stackoverflow.com/q/5661671/130442 + * http://caniuse.com/#feat=transforms3d + * @return {boolean} */ -goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse = function( - html, dir) { - return new goog.html.SafeHtml().initSecurityPrivateDoNotAccessOrElse_( - html, dir); -}; +ol.dom.canUseCssTransform3D = (function() { + var canUseCssTransform3D; + return function() { + if (canUseCssTransform3D === undefined) { + goog.asserts.assert(document.body, + 'document.body should not be null'); + if (!goog.global.getComputedStyle) { + // this browser is ancient + canUseCssTransform3D = false; + } else { + var el = goog.dom.createElement('P'), + has3d, + transforms = { + 'webkitTransform': '-webkit-transform', + 'OTransform': '-o-transform', + 'msTransform': '-ms-transform', + 'MozTransform': '-moz-transform', + 'transform': 'transform' + }; + document.body.appendChild(el); + for (var t in transforms) { + if (t in el.style) { + el.style[t] = 'translate3d(1px,1px,1px)'; + has3d = goog.global.getComputedStyle(el).getPropertyValue( + transforms[t]); + } + } + goog.dom.removeNode(el); + + canUseCssTransform3D = (has3d && has3d !== 'none'); + } + } + return canUseCssTransform3D; + }; +}()); /** - * Called from createSafeHtmlSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} html - * @param {?goog.i18n.bidi.Dir} dir - * @return {!goog.html.SafeHtml} - * @private + * @param {Element} element Element. + * @param {string} value Value. */ -goog.html.SafeHtml.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( - html, dir) { - this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = html; - this.dir_ = dir; - return this; +ol.dom.setTransform = function(element, value) { + var style = element.style; + style.WebkitTransform = value; + style.MozTransform = value; + style.OTransform = value; + style.msTransform = value; + style.transform = value; + + // IE 9+ seems to assume transform-origin: 100% 100%; for some unknown reason + if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9.0')) { + element.style.transformOrigin = '0 0'; + } }; /** - * Like create() but does not restrict which tags can be constructed. - * - * @param {string} tagName Tag name. Set or validated by caller. - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes - * @param {(!goog.html.SafeHtml.TextOrHtml_| - * !Array<!goog.html.SafeHtml.TextOrHtml_>)=} opt_content - * @return {!goog.html.SafeHtml} - * @throws {Error} If invalid or unsafe attribute name or value is provided. - * @throws {goog.asserts.AssertionError} If content for void tag is provided. - * @package + * @param {!Element} element Element. + * @param {goog.vec.Mat4.Number} transform Matrix. + * @param {number=} opt_precision Precision. */ -goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse = - function(tagName, opt_attributes, opt_content) { - var dir = null; - var result = '<' + tagName; +ol.dom.transformElement2D = function(element, transform, opt_precision) { + // using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer + // matrix3d() + var i; + if (ol.dom.canUseCssTransform3D()) { + var value3D; - if (opt_attributes) { - for (var name in opt_attributes) { - if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(name)) { - throw Error('Invalid attribute name "' + name + '".'); + if (opt_precision !== undefined) { + /** @type {Array.<string>} */ + var strings3D = new Array(16); + for (i = 0; i < 16; ++i) { + strings3D[i] = transform[i].toFixed(opt_precision); } - var value = opt_attributes[name]; - if (!goog.isDefAndNotNull(value)) { - continue; + value3D = strings3D.join(','); + } else { + value3D = transform.join(','); + } + ol.dom.setTransform(element, 'matrix3d(' + value3D + ')'); + } else if (ol.dom.canUseCssTransform()) { + /** @type {Array.<number>} */ + var transform2D = [ + goog.vec.Mat4.getElement(transform, 0, 0), + goog.vec.Mat4.getElement(transform, 1, 0), + goog.vec.Mat4.getElement(transform, 0, 1), + goog.vec.Mat4.getElement(transform, 1, 1), + goog.vec.Mat4.getElement(transform, 0, 3), + goog.vec.Mat4.getElement(transform, 1, 3) + ]; + var value2D; + if (opt_precision !== undefined) { + /** @type {Array.<string>} */ + var strings2D = new Array(6); + for (i = 0; i < 6; ++i) { + strings2D[i] = transform2D[i].toFixed(opt_precision); } - result += ' ' + - goog.html.SafeHtml.getAttrNameAndValue_(tagName, name, value); + value2D = strings2D.join(','); + } else { + value2D = transform2D.join(','); } - } + ol.dom.setTransform(element, 'matrix(' + value2D + ')'); + } else { + element.style.left = + Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px'; + element.style.top = + Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px'; - var content = opt_content; - if (!goog.isDefAndNotNull(content)) { - content = []; - } else if (!goog.isArray(content)) { - content = [content]; + // TODO: Add scaling here. This isn't quite as simple as multiplying + // width/height, because that only changes the container size, not the + // content size. } +}; - if (goog.dom.tags.isVoidTag(tagName.toLowerCase())) { - goog.asserts.assert(!content.length, - 'Void tag <' + tagName + '> does not allow content.'); - result += '>'; - } else { - var html = goog.html.SafeHtml.concat(content); - result += '>' + goog.html.SafeHtml.unwrap(html) + '</' + tagName + '>'; - dir = html.getDirection(); - } - var dirAttribute = opt_attributes && opt_attributes['dir']; - if (dirAttribute) { - if (/^(ltr|rtl|auto)$/i.test(dirAttribute)) { - // If the tag has the "dir" attribute specified then its direction is - // neutral because it can be safely used in any context. - dir = goog.i18n.bidi.Dir.NEUTRAL; - } else { - dir = null; - } - } +/** + * Get the current computed width for the given element including margin, + * padding and border. + * Equivalent to jQuery's `$(el).outerWidth(true)`. + * @param {!Element} element Element. + * @return {number} + */ +ol.dom.outerWidth = function(element) { + var width = element.offsetWidth; + var style = element.currentStyle || window.getComputedStyle(element); + width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - result, dir); + return width; }; /** - * @param {!Object<string, string>} fixedAttributes - * @param {!Object<string, string>} defaultAttributes - * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} - * opt_attributes Optional attributes passed to create*(). - * @return {!Object<string, goog.html.SafeHtml.AttributeValue_>} - * @throws {Error} If opt_attributes contains an attribute with the same name - * as an attribute in fixedAttributes. - * @package + * Get the current computed height for the given element including margin, + * padding and border. + * Equivalent to jQuery's `$(el).outerHeight(true)`. + * @param {!Element} element Element. + * @return {number} */ -goog.html.SafeHtml.combineAttributes = function( - fixedAttributes, defaultAttributes, opt_attributes) { - var combinedAttributes = {}; - var name; +ol.dom.outerHeight = function(element) { + var height = element.offsetHeight; + var style = element.currentStyle || window.getComputedStyle(element); + height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10); - for (name in fixedAttributes) { - goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case'); - combinedAttributes[name] = fixedAttributes[name]; - } - for (name in defaultAttributes) { - goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case'); - combinedAttributes[name] = defaultAttributes[name]; - } + return height; +}; - for (name in opt_attributes) { - var nameLower = name.toLowerCase(); - if (nameLower in fixedAttributes) { - throw Error('Cannot override "' + nameLower + '" attribute, got "' + - name + '" with value "' + opt_attributes[name] + '"'); - } - if (nameLower in defaultAttributes) { - delete combinedAttributes[nameLower]; - } - combinedAttributes[name] = opt_attributes[name]; - } +goog.provide('ol.reproj'); - return combinedAttributes; -}; +goog.require('goog.labs.userAgent.browser'); +goog.require('goog.labs.userAgent.platform'); +goog.require('goog.math'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.math'); +goog.require('ol.proj'); /** - * A SafeHtml instance corresponding to the HTML doctype: "<!DOCTYPE html>". - * @const {!goog.html.SafeHtml} + * We need to employ more sophisticated solution + * if the web browser antialiases clipping edges on canvas. + * + * Currently only Chrome does not antialias the edges, but this is probably + * going to be "fixed" in the future: http://crbug.com/424291 + * + * @type {boolean} + * @private */ -goog.html.SafeHtml.DOCTYPE_HTML = - goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - '<!DOCTYPE html>', goog.i18n.bidi.Dir.NEUTRAL); +ol.reproj.browserAntialiasesClip_ = !goog.labs.userAgent.browser.isChrome() || + goog.labs.userAgent.platform.isIos(); /** - * A SafeHtml instance corresponding to the empty string. - * @const {!goog.html.SafeHtml} + * Calculates ideal resolution to use from the source in order to achieve + * pixel mapping as close as possible to 1:1 during reprojection. + * The resolution is calculated regardless of what resolutions + * are actually available in the dataset (TileGrid, Image, ...). + * + * @param {ol.proj.Projection} sourceProj Source projection. + * @param {ol.proj.Projection} targetProj Target projection. + * @param {ol.Coordinate} targetCenter Target center. + * @param {number} targetResolution Target resolution. + * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0. */ -goog.html.SafeHtml.EMPTY = - goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - '', goog.i18n.bidi.Dir.NEUTRAL); +ol.reproj.calculateSourceResolution = function(sourceProj, targetProj, + targetCenter, targetResolution) { -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + var sourceCenter = ol.proj.transform(targetCenter, targetProj, sourceProj); -/** - * @fileoverview Type-safe wrappers for unsafe DOM APIs. - * - * This file provides type-safe wrappers for DOM APIs that can result in - * cross-site scripting (XSS) vulnerabilities, if the API is supplied with - * untrusted (attacker-controlled) input. Instead of plain strings, the type - * safe wrappers consume values of types from the goog.html package whose - * contract promises that values are safe to use in the corresponding context. - * - * Hence, a program that exclusively uses the wrappers in this file (i.e., whose - * only reference to security-sensitive raw DOM APIs are in this file) is - * guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo - * correctness of code that produces values of the respective goog.html types, - * and absent code that violates type safety). - * - * For example, assigning to an element's .innerHTML property a string that is - * derived (even partially) from untrusted input typically results in an XSS - * vulnerability. The type-safe wrapper goog.html.setInnerHtml consumes a value - * of type goog.html.SafeHtml, whose contract states that using its values in a - * HTML context will not result in XSS. Hence a program that is free of direct - * assignments to any element's innerHTML property (with the exception of the - * assignment to .innerHTML in this file) is guaranteed to be free of XSS due to - * assignment of untrusted strings to the innerHTML property. - */ + // calculate the ideal resolution of the source data + var sourceResolution = + targetProj.getPointResolution(targetResolution, targetCenter); -goog.provide('goog.dom.safe'); -goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition'); + var targetMetersPerUnit = targetProj.getMetersPerUnit(); + if (targetMetersPerUnit !== undefined) { + sourceResolution *= targetMetersPerUnit; + } + var sourceMetersPerUnit = sourceProj.getMetersPerUnit(); + if (sourceMetersPerUnit !== undefined) { + sourceResolution /= sourceMetersPerUnit; + } -goog.require('goog.asserts'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.TrustedResourceUrl'); -goog.require('goog.string'); -goog.require('goog.string.Const'); + // Based on the projection properties, the point resolution at the specified + // coordinates may be slightly different. We need to reverse-compensate this + // in order to achieve optimal results. + var compensationFactor = + sourceProj.getPointResolution(sourceResolution, sourceCenter) / + sourceResolution; -/** @enum {string} */ -goog.dom.safe.InsertAdjacentHtmlPosition = { - AFTERBEGIN: 'afterbegin', - AFTEREND: 'afterend', - BEFOREBEGIN: 'beforebegin', - BEFOREEND: 'beforeend' + if (goog.math.isFiniteNumber(compensationFactor) && compensationFactor > 0) { + sourceResolution /= compensationFactor; + } + + return sourceResolution; }; /** - * Inserts known-safe HTML into a Node, at the specified position. - * @param {!Node} node The node on which to call insertAdjacentHTML. - * @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where - * to insert the HTML. - * @param {!goog.html.SafeHtml} html The known-safe HTML to insert. + * Enlarge the clipping triangle point by 1 pixel to ensure the edges overlap + * in order to mask gaps caused by antialiasing. + * + * @param {number} centroidX Centroid of the triangle (x coordinate in pixels). + * @param {number} centroidY Centroid of the triangle (y coordinate in pixels). + * @param {number} x X coordinate of the point (in pixels). + * @param {number} y Y coordinate of the point (in pixels). + * @return {ol.Coordinate} New point 1 px farther from the centroid. + * @private */ -goog.dom.safe.insertAdjacentHtml = function(node, position, html) { - node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrap(html)); +ol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) { + var dX = x - centroidX, dY = y - centroidY; + var distance = Math.sqrt(dX * dX + dY * dY); + return [Math.round(x + dX / distance), Math.round(y + dY / distance)]; }; /** - * Assigns known-safe HTML to an element's innerHTML property. - * @param {!Element} elem The element whose innerHTML is to be assigned to. - * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. + * Renders the source data into new canvas based on the triangulation. + * + * @param {number} width Width of the canvas. + * @param {number} height Height of the canvas. + * @param {number} pixelRatio Pixel ratio. + * @param {number} sourceResolution Source resolution. + * @param {ol.Extent} sourceExtent Extent of the data source. + * @param {number} targetResolution Target resolution. + * @param {ol.Extent} targetExtent Target extent. + * @param {ol.reproj.Triangulation} triangulation Calculated triangulation. + * @param {Array.<{extent: ol.Extent, + * image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources + * Array of sources. + * @param {boolean=} opt_renderEdges Render reprojection edges. + * @return {HTMLCanvasElement} Canvas with reprojected data. */ -goog.dom.safe.setInnerHtml = function(elem, html) { - elem.innerHTML = goog.html.SafeHtml.unwrap(html); -}; +ol.reproj.render = function(width, height, pixelRatio, + sourceResolution, sourceExtent, targetResolution, targetExtent, + triangulation, sources, opt_renderEdges) { + var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width), + Math.round(pixelRatio * height)); -/** - * Assigns known-safe HTML to an element's outerHTML property. - * @param {!Element} elem The element whose outerHTML is to be assigned to. - * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. - */ -goog.dom.safe.setOuterHtml = function(elem, html) { - elem.outerHTML = goog.html.SafeHtml.unwrap(html); -}; + if (sources.length === 0) { + return context.canvas; + } + context.scale(pixelRatio, pixelRatio); -/** - * Writes known-safe HTML to a document. - * @param {!Document} doc The document to be written to. - * @param {!goog.html.SafeHtml} html The known-safe HTML to assign. - */ -goog.dom.safe.documentWrite = function(doc, html) { - doc.write(goog.html.SafeHtml.unwrap(html)); -}; + var sourceDataExtent = ol.extent.createEmpty(); + sources.forEach(function(src, i, arr) { + ol.extent.extend(sourceDataExtent, src.extent); + }); + var canvasWidthInUnits = ol.extent.getWidth(sourceDataExtent); + var canvasHeightInUnits = ol.extent.getHeight(sourceDataExtent); + var stitchContext = ol.dom.createCanvasContext2D( + Math.round(pixelRatio * canvasWidthInUnits / sourceResolution), + Math.round(pixelRatio * canvasHeightInUnits / sourceResolution)); -/** - * Safely assigns a URL to an anchor element's href property. - * - * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to - * anchor's href property. If url is of type string however, it is first - * sanitized using goog.html.SafeUrl.sanitize. - * - * Example usage: - * goog.dom.safe.setAnchorHref(anchorEl, url); - * which is a safe alternative to - * anchorEl.href = url; - * The latter can result in XSS vulnerabilities if url is a - * user-/attacker-controlled value. - * - * @param {!HTMLAnchorElement} anchor The anchor element whose href property - * is to be assigned to. - * @param {string|!goog.html.SafeUrl} url The URL to assign. - * @see goog.html.SafeUrl#sanitize - */ -goog.dom.safe.setAnchorHref = function(anchor, url) { - /** @type {!goog.html.SafeUrl} */ - var safeUrl; - if (url instanceof goog.html.SafeUrl) { - safeUrl = url; - } else { - safeUrl = goog.html.SafeUrl.sanitize(url); - } - anchor.href = goog.html.SafeUrl.unwrap(safeUrl); -}; + stitchContext.scale(pixelRatio / sourceResolution, + pixelRatio / sourceResolution); + stitchContext.translate(-sourceDataExtent[0], sourceDataExtent[3]); + sources.forEach(function(src, i, arr) { + var xPos = src.extent[0]; + var yPos = -src.extent[3]; + var srcWidth = ol.extent.getWidth(src.extent); + var srcHeight = ol.extent.getHeight(src.extent); -/** - * Safely assigns a URL to an embed element's src property. - * - * Example usage: - * goog.dom.safe.setEmbedSrc(embedEl, url); - * which is a safe alternative to - * embedEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLEmbedElement} embed The embed element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setEmbedSrc = function(embed, url) { - embed.src = goog.html.TrustedResourceUrl.unwrap(url); -}; + stitchContext.drawImage(src.image, xPos, yPos, srcWidth, srcHeight); + }); + var targetTopLeft = ol.extent.getTopLeft(targetExtent); -/** - * Safely assigns a URL to a frame element's src property. - * - * Example usage: - * goog.dom.safe.setFrameSrc(frameEl, url); - * which is a safe alternative to - * frameEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLFrameElement} frame The frame element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setFrameSrc = function(frame, url) { - frame.src = goog.html.TrustedResourceUrl.unwrap(url); -}; + triangulation.getTriangles().forEach(function(triangle, i, arr) { + /* Calculate affine transform (src -> dst) + * Resulting matrix can be used to transform coordinate + * from `sourceProjection` to destination pixels. + * + * To optimize number of context calls and increase numerical stability, + * we also do the following operations: + * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1) + * here before solving the linear system so [ui, vi] are pixel coordinates. + * + * Src points: xi, yi + * Dst points: ui, vi + * Affine coefficients: aij + * + * | x0 y0 1 0 0 0 | |a00| |u0| + * | x1 y1 1 0 0 0 | |a01| |u1| + * | x2 y2 1 0 0 0 | x |a02| = |u2| + * | 0 0 0 x0 y0 1 | |a10| |v0| + * | 0 0 0 x1 y1 1 | |a11| |v1| + * | 0 0 0 x2 y2 1 | |a12| |v2| + */ + var source = triangle.source, target = triangle.target; + var x0 = source[0][0], y0 = source[0][1], + x1 = source[1][0], y1 = source[1][1], + x2 = source[2][0], y2 = source[2][1]; + var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution, + v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; + var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution, + v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; + var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution, + v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; + // Shift all the source points to improve numerical stability + // of all the subsequent calculations. The [x0, y0] is used here. + // This is also used to simplify the linear system. + var sourceNumericalShiftX = x0, sourceNumericalShiftY = y0; + x0 = 0; + y0 = 0; + x1 -= sourceNumericalShiftX; + y1 -= sourceNumericalShiftY; + x2 -= sourceNumericalShiftX; + y2 -= sourceNumericalShiftY; -/** - * Safely assigns a URL to an iframe element's src property. - * - * Example usage: - * goog.dom.safe.setIframeSrc(iframeEl, url); - * which is a safe alternative to - * iframeEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLIFrameElement} iframe The iframe element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setIframeSrc = function(iframe, url) { - iframe.src = goog.html.TrustedResourceUrl.unwrap(url); -}; + var augmentedMatrix = [ + [x1, y1, 0, 0, u1 - u0], + [x2, y2, 0, 0, u2 - u0], + [0, 0, x1, y1, v1 - v0], + [0, 0, x2, y2, v2 - v0] + ]; + var affineCoefs = ol.math.solveLinearSystem(augmentedMatrix); + if (!affineCoefs) { + return; + } + context.save(); + context.beginPath(); + if (ol.reproj.browserAntialiasesClip_) { + var centroidX = (u0 + u1 + u2) / 3, centroidY = (v0 + v1 + v2) / 3; + var p0 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u0, v0); + var p1 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u1, v1); + var p2 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u2, v2); -/** - * Safely sets a link element's href and rel properties. Whether or not - * the URL assigned to href has to be a goog.html.TrustedResourceUrl - * depends on the value of the rel property. If rel contains "stylesheet" - * then a TrustedResourceUrl is required. - * - * Example usage: - * goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet'); - * which is a safe alternative to - * linkEl.rel = 'stylesheet'; - * linkEl.href = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLLinkElement} link The link element whose href property - * is to be assigned to. - * @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL - * to assign to the href property. Must be a TrustedResourceUrl if the - * value assigned to rel contains "stylesheet". A string value is - * sanitized with goog.html.SafeUrl.sanitize. - * @param {string} rel The value to assign to the rel property. - * @throws {Error} if rel contains "stylesheet" and url is not a - * TrustedResourceUrl - * @see goog.html.SafeUrl#sanitize - */ -goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) { - link.rel = rel; - if (goog.string.caseInsensitiveContains(rel, 'stylesheet')) { - goog.asserts.assert( - url instanceof goog.html.TrustedResourceUrl, - 'URL must be TrustedResourceUrl because "rel" contains "stylesheet"'); - link.href = goog.html.TrustedResourceUrl.unwrap(url); - } else if (url instanceof goog.html.TrustedResourceUrl) { - link.href = goog.html.TrustedResourceUrl.unwrap(url); - } else if (url instanceof goog.html.SafeUrl) { - link.href = goog.html.SafeUrl.unwrap(url); - } else { // string - // SafeUrl.sanitize must return legitimate SafeUrl when passed a string. - link.href = goog.html.SafeUrl.sanitize(url).getTypedStringValue(); - } -}; + context.moveTo(p0[0], p0[1]); + context.lineTo(p1[0], p1[1]); + context.lineTo(p2[0], p2[1]); + } else { + context.moveTo(u0, v0); + context.lineTo(u1, v1); + context.lineTo(u2, v2); + } + context.closePath(); + context.clip(); + context.transform( + affineCoefs[0], affineCoefs[2], affineCoefs[1], affineCoefs[3], u0, v0); -/** - * Safely assigns a URL to an object element's data property. - * - * Example usage: - * goog.dom.safe.setObjectData(objectEl, url); - * which is a safe alternative to - * objectEl.data = url; - * The latter can result in loading untrusted code unless setit is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLObjectElement} object The object element whose data property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setObjectData = function(object, url) { - object.data = goog.html.TrustedResourceUrl.unwrap(url); -}; + context.translate(sourceDataExtent[0] - sourceNumericalShiftX, + sourceDataExtent[3] - sourceNumericalShiftY); + context.scale(sourceResolution / pixelRatio, + -sourceResolution / pixelRatio); -/** - * Safely assigns a URL to an iframe element's src property. - * - * Example usage: - * goog.dom.safe.setScriptSrc(scriptEl, url); - * which is a safe alternative to - * scriptEl.src = url; - * The latter can result in loading untrusted code unless it is ensured that - * the URL refers to a trustworthy resource. - * - * @param {!HTMLScriptElement} script The script element whose src property - * is to be assigned to. - * @param {!goog.html.TrustedResourceUrl} url The URL to assign. - */ -goog.dom.safe.setScriptSrc = function(script, url) { - script.src = goog.html.TrustedResourceUrl.unwrap(url); -}; + context.drawImage(stitchContext.canvas, 0, 0); + context.restore(); + }); + if (opt_renderEdges) { + context.save(); -/** - * Safely assigns a URL to a Location object's href property. - * - * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to - * loc's href property. If url is of type string however, it is first sanitized - * using goog.html.SafeUrl.sanitize. - * - * Example usage: - * goog.dom.safe.setLocationHref(document.location, redirectUrl); - * which is a safe alternative to - * document.location.href = redirectUrl; - * The latter can result in XSS vulnerabilities if redirectUrl is a - * user-/attacker-controlled value. - * - * @param {!Location} loc The Location object whose href property is to be - * assigned to. - * @param {string|!goog.html.SafeUrl} url The URL to assign. - * @see goog.html.SafeUrl#sanitize - */ -goog.dom.safe.setLocationHref = function(loc, url) { - /** @type {!goog.html.SafeUrl} */ - var safeUrl; - if (url instanceof goog.html.SafeUrl) { - safeUrl = url; - } else { - safeUrl = goog.html.SafeUrl.sanitize(url); + context.strokeStyle = 'black'; + context.lineWidth = 1; + + triangulation.getTriangles().forEach(function(triangle, i, arr) { + var target = triangle.target; + var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution, + v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; + var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution, + v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; + var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution, + v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; + + context.beginPath(); + context.moveTo(u0, v0); + context.lineTo(u1, v1); + context.lineTo(u2, v2); + context.closePath(); + context.stroke(); + }); + + context.restore(); } - loc.href = goog.html.SafeUrl.unwrap(safeUrl); + return context.canvas; }; +goog.provide('ol.reproj.Triangulation'); + +goog.require('goog.asserts'); +goog.require('goog.math'); +goog.require('ol.extent'); +goog.require('ol.proj'); + /** - * Safely opens a URL in a new window (via window.open). - * - * If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to - * window.open. If url is of type string however, it is first sanitized - * using goog.html.SafeUrl.sanitize. - * - * Note that this function does not prevent leakages via the referer that is - * sent by window.open. It is advised to only use this to open 1st party URLs. - * - * Example usage: - * goog.dom.safe.openInWindow(url); - * which is a safe alternative to - * window.open(url); - * The latter can result in XSS vulnerabilities if redirectUrl is a - * user-/attacker-controlled value. + * Single triangle; consists of 3 source points and 3 target points. * - * @param {string|!goog.html.SafeUrl} url The URL to open. - * @param {Window=} opt_openerWin Window of which to call the .open() method. - * Defaults to the global window. - * @param {!goog.string.Const=} opt_name Name of the window to open in. Can be - * _top, etc as allowed by window.open(). - * @param {string=} opt_specs Comma-separated list of specifications, same as - * in window.open(). - * @param {boolean=} opt_replace Whether to replace the current entry in browser - * history, same as in window.open(). - * @return {Window} Window the url was opened in. + * @typedef {{source: Array.<ol.Coordinate>, + * target: Array.<ol.Coordinate>}} */ -goog.dom.safe.openInWindow = function( - url, opt_openerWin, opt_name, opt_specs, opt_replace) { - /** @type {!goog.html.SafeUrl} */ - var safeUrl; - if (url instanceof goog.html.SafeUrl) { - safeUrl = url; - } else { - safeUrl = goog.html.SafeUrl.sanitize(url); - } - var win = opt_openerWin || window; - return win.open(goog.html.SafeUrl.unwrap(safeUrl), - // If opt_name is undefined, simply passing that in to open() causes IE to - // reuse the current window instead of opening a new one. Thus we pass '' - // in instead, which according to spec opens a new window. See - // https://html.spec.whatwg.org/multipage/browsers.html#dom-open . - opt_name ? goog.string.Const.unwrap(opt_name) : '', - opt_specs, opt_replace); -}; +ol.reproj.Triangle; + -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview A utility class for representing two-dimensional positions. + * @classdesc + * Class containing triangulation of the given target extent. + * Used for determining source data and the reprojection itself. + * + * @param {ol.proj.Projection} sourceProj Source projection. + * @param {ol.proj.Projection} targetProj Target projection. + * @param {ol.Extent} targetExtent Target extent to triangulate. + * @param {ol.Extent} maxSourceExtent Maximal source extent that can be used. + * @param {number} errorThreshold Acceptable error (in source units). + * @constructor */ +ol.reproj.Triangulation = function(sourceProj, targetProj, targetExtent, + maxSourceExtent, errorThreshold) { + /** + * @type {ol.proj.Projection} + * @private + */ + this.sourceProj_ = sourceProj; -goog.provide('goog.math.Coordinate'); - -goog.require('goog.math'); + /** + * @type {ol.proj.Projection} + * @private + */ + this.targetProj_ = targetProj; + /** @type {!Object.<string, ol.Coordinate>} */ + var transformInvCache = {}; + var transformInv = ol.proj.getTransform(this.targetProj_, this.sourceProj_); + /** + * @param {ol.Coordinate} c + * @return {ol.Coordinate} + * @private + */ + this.transformInv_ = function(c) { + var key = c[0] + '/' + c[1]; + if (!transformInvCache[key]) { + transformInvCache[key] = transformInv(c); + } + return transformInvCache[key]; + }; -/** - * Class for representing coordinates and positions. - * @param {number=} opt_x Left, defaults to 0. - * @param {number=} opt_y Top, defaults to 0. - * @struct - * @constructor - */ -goog.math.Coordinate = function(opt_x, opt_y) { /** - * X-value - * @type {number} + * @type {ol.Extent} + * @private */ - this.x = goog.isDef(opt_x) ? opt_x : 0; + this.maxSourceExtent_ = maxSourceExtent; /** - * Y-value * @type {number} + * @private */ - this.y = goog.isDef(opt_y) ? opt_y : 0; -}; + this.errorThresholdSquared_ = errorThreshold * errorThreshold; + /** + * @type {Array.<ol.reproj.Triangle>} + * @private + */ + this.triangles_ = []; -/** - * Returns a new copy of the coordinate. - * @return {!goog.math.Coordinate} A clone of this coordinate. - */ -goog.math.Coordinate.prototype.clone = function() { - return new goog.math.Coordinate(this.x, this.y); -}; + /** + * Indicates that the triangulation crosses edge of the source projection. + * @type {boolean} + * @private + */ + this.wrapsXInSource_ = false; + /** + * @type {boolean} + * @private + */ + this.canWrapXInSource_ = this.sourceProj_.canWrapX() && + !!maxSourceExtent && + !!this.sourceProj_.getExtent() && + (ol.extent.getWidth(maxSourceExtent) == + ol.extent.getWidth(this.sourceProj_.getExtent())); -if (goog.DEBUG) { /** - * Returns a nice string representing the coordinate. - * @return {string} In the form (50, 73). - * @override + * @type {?number} + * @private */ - goog.math.Coordinate.prototype.toString = function() { - return '(' + this.x + ', ' + this.y + ')'; - }; -} + this.sourceWorldWidth_ = this.sourceProj_.getExtent() ? + ol.extent.getWidth(this.sourceProj_.getExtent()) : null; + /** + * @type {?number} + * @private + */ + this.targetWorldWidth_ = this.targetProj_.getExtent() ? + ol.extent.getWidth(this.targetProj_.getExtent()) : null; -/** - * Compares coordinates for equality. - * @param {goog.math.Coordinate} a A Coordinate. - * @param {goog.math.Coordinate} b A Coordinate. - * @return {boolean} True iff the coordinates are equal, or if both are null. - */ -goog.math.Coordinate.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.x == b.x && a.y == b.y; -}; + var destinationTopLeft = ol.extent.getTopLeft(targetExtent); + var destinationTopRight = ol.extent.getTopRight(targetExtent); + var destinationBottomRight = ol.extent.getBottomRight(targetExtent); + var destinationBottomLeft = ol.extent.getBottomLeft(targetExtent); + var sourceTopLeft = this.transformInv_(destinationTopLeft); + var sourceTopRight = this.transformInv_(destinationTopRight); + var sourceBottomRight = this.transformInv_(destinationBottomRight); + var sourceBottomLeft = this.transformInv_(destinationBottomLeft); + this.addQuad_( + destinationTopLeft, destinationTopRight, + destinationBottomRight, destinationBottomLeft, + sourceTopLeft, sourceTopRight, sourceBottomRight, sourceBottomLeft, + ol.RASTER_REPROJECTION_MAX_SUBDIVISION); -/** - * Returns the distance between two coordinates. - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {number} The distance between {@code a} and {@code b}. - */ -goog.math.Coordinate.distance = function(a, b) { - var dx = a.x - b.x; - var dy = a.y - b.y; - return Math.sqrt(dx * dx + dy * dy); -}; + if (this.wrapsXInSource_) { + // Fix coordinates (ol.proj returns wrapped coordinates, "unwrap" here). + // This significantly simplifies the rest of the reprojection process. + goog.asserts.assert(this.sourceWorldWidth_ !== null); + var leftBound = Infinity; + this.triangles_.forEach(function(triangle, i, arr) { + leftBound = Math.min(leftBound, + triangle.source[0][0], triangle.source[1][0], triangle.source[2][0]); + }); -/** - * Returns the magnitude of a coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @return {number} The distance between the origin and {@code a}. - */ -goog.math.Coordinate.magnitude = function(a) { - return Math.sqrt(a.x * a.x + a.y * a.y); -}; + // Shift triangles to be as close to `leftBound` as possible + // (if the distance is more than `worldWidth / 2` it can be closer. + this.triangles_.forEach(function(triangle) { + if (Math.max(triangle.source[0][0], triangle.source[1][0], + triangle.source[2][0]) - leftBound > this.sourceWorldWidth_ / 2) { + var newTriangle = [[triangle.source[0][0], triangle.source[0][1]], + [triangle.source[1][0], triangle.source[1][1]], + [triangle.source[2][0], triangle.source[2][1]]]; + if ((newTriangle[0][0] - leftBound) > this.sourceWorldWidth_ / 2) { + newTriangle[0][0] -= this.sourceWorldWidth_; + } + if ((newTriangle[1][0] - leftBound) > this.sourceWorldWidth_ / 2) { + newTriangle[1][0] -= this.sourceWorldWidth_; + } + if ((newTriangle[2][0] - leftBound) > this.sourceWorldWidth_ / 2) { + newTriangle[2][0] -= this.sourceWorldWidth_; + } + // Rarely (if the extent contains both the dateline and prime meridian) + // the shift can in turn break some triangles. + // Detect this here and don't shift in such cases. + var minX = Math.min( + newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]); + var maxX = Math.max( + newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]); + if ((maxX - minX) < this.sourceWorldWidth_ / 2) { + triangle.source = newTriangle; + } + } + }, this); + } -/** - * Returns the angle from the origin to a coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @return {number} The angle, in degrees, clockwise from the positive X - * axis to {@code a}. - */ -goog.math.Coordinate.azimuth = function(a) { - return goog.math.angle(0, 0, a.x, a.y); + transformInvCache = {}; }; /** - * Returns the squared distance between two coordinates. Squared distances can - * be used for comparisons when the actual value is not required. - * - * Performance note: eliminating the square root is an optimization often used - * in lower-level languages, but the speed difference is not nearly as - * pronounced in JavaScript (only a few percent.) - * - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {number} The squared distance between {@code a} and {@code b}. + * Adds triangle to the triangulation. + * @param {ol.Coordinate} a + * @param {ol.Coordinate} b + * @param {ol.Coordinate} c + * @param {ol.Coordinate} aSrc + * @param {ol.Coordinate} bSrc + * @param {ol.Coordinate} cSrc + * @private */ -goog.math.Coordinate.squaredDistance = function(a, b) { - var dx = a.x - b.x; - var dy = a.y - b.y; - return dx * dx + dy * dy; +ol.reproj.Triangulation.prototype.addTriangle_ = function(a, b, c, + aSrc, bSrc, cSrc) { + this.triangles_.push({ + source: [aSrc, bSrc, cSrc], + target: [a, b, c] + }); }; /** - * Returns the difference between two coordinates as a new - * goog.math.Coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {!goog.math.Coordinate} A Coordinate representing the difference - * between {@code a} and {@code b}. + * Adds quad (points in clock-wise order) to the triangulation + * (and reprojects the vertices) if valid. + * Performs quad subdivision if needed to increase precision. + * + * @param {ol.Coordinate} a + * @param {ol.Coordinate} b + * @param {ol.Coordinate} c + * @param {ol.Coordinate} d + * @param {ol.Coordinate} aSrc + * @param {ol.Coordinate} bSrc + * @param {ol.Coordinate} cSrc + * @param {ol.Coordinate} dSrc + * @param {number} maxSubdivision Maximal allowed subdivision of the quad. + * @private */ -goog.math.Coordinate.difference = function(a, b) { - return new goog.math.Coordinate(a.x - b.x, a.y - b.y); -}; +ol.reproj.Triangulation.prototype.addQuad_ = function(a, b, c, d, + aSrc, bSrc, cSrc, dSrc, maxSubdivision) { + var sourceQuadExtent = ol.extent.boundingExtent([aSrc, bSrc, cSrc, dSrc]); + var sourceCoverageX = this.sourceWorldWidth_ ? + ol.extent.getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null; -/** - * Returns the sum of two coordinates as a new goog.math.Coordinate. - * @param {!goog.math.Coordinate} a A Coordinate. - * @param {!goog.math.Coordinate} b A Coordinate. - * @return {!goog.math.Coordinate} A Coordinate representing the sum of the two - * coordinates. - */ -goog.math.Coordinate.sum = function(a, b) { - return new goog.math.Coordinate(a.x + b.x, a.y + b.y); -}; + // when the quad is wrapped in the source projection + // it covers most of the projection extent, but not fully + var wrapsX = this.sourceProj_.canWrapX() && + sourceCoverageX > 0.5 && sourceCoverageX < 1; + var needsSubdivision = false; -/** - * Rounds the x and y fields to the next larger integer values. - * @return {!goog.math.Coordinate} This coordinate with ceil'd fields. - */ -goog.math.Coordinate.prototype.ceil = function() { - this.x = Math.ceil(this.x); - this.y = Math.ceil(this.y); - return this; -}; + if (maxSubdivision > 0) { + if (this.targetProj_.isGlobal() && this.targetWorldWidth_) { + var targetQuadExtent = ol.extent.boundingExtent([a, b, c, d]); + var targetCoverageX = + ol.extent.getWidth(targetQuadExtent) / this.targetWorldWidth_; + needsSubdivision |= + targetCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH; + } + if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) { + needsSubdivision |= + sourceCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH; + } + } + if (!needsSubdivision && this.maxSourceExtent_) { + if (!ol.extent.intersects(sourceQuadExtent, this.maxSourceExtent_)) { + // whole quad outside source projection extent -> ignore + return; + } + } -/** - * Rounds the x and y fields to the next smaller integer values. - * @return {!goog.math.Coordinate} This coordinate with floored fields. - */ -goog.math.Coordinate.prototype.floor = function() { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - return this; -}; + if (!needsSubdivision) { + if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) || + !isFinite(bSrc[0]) || !isFinite(bSrc[1]) || + !isFinite(cSrc[0]) || !isFinite(cSrc[1]) || + !isFinite(dSrc[0]) || !isFinite(dSrc[1])) { + if (maxSubdivision > 0) { + needsSubdivision = true; + } else { + return; + } + } + } + if (maxSubdivision > 0) { + if (!needsSubdivision) { + var center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2]; + var centerSrc = this.transformInv_(center); -/** - * Rounds the x and y fields to the nearest integer values. - * @return {!goog.math.Coordinate} This coordinate with rounded fields. - */ -goog.math.Coordinate.prototype.round = function() { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; -}; + var dx; + if (wrapsX) { + goog.asserts.assert(this.sourceWorldWidth_); + var centerSrcEstimX = + (goog.math.modulo(aSrc[0], this.sourceWorldWidth_) + + goog.math.modulo(cSrc[0], this.sourceWorldWidth_)) / 2; + dx = centerSrcEstimX - + goog.math.modulo(centerSrc[0], this.sourceWorldWidth_); + } else { + dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0]; + } + var dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1]; + var centerSrcErrorSquared = dx * dx + dy * dy; + needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_; + } + if (needsSubdivision) { + if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) { + // split horizontally (top & bottom) + var bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2]; + var bcSrc = this.transformInv_(bc); + var da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2]; + var daSrc = this.transformInv_(da); + this.addQuad_( + a, b, bc, da, aSrc, bSrc, bcSrc, daSrc, maxSubdivision - 1); + this.addQuad_( + da, bc, c, d, daSrc, bcSrc, cSrc, dSrc, maxSubdivision - 1); + } else { + // split vertically (left & right) + var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]; + var abSrc = this.transformInv_(ab); + var cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2]; + var cdSrc = this.transformInv_(cd); -/** - * Translates this box by the given offsets. If a {@code goog.math.Coordinate} - * is given, then the x and y values are translated by the coordinate's x and y. - * Otherwise, x and y are translated by {@code tx} and {@code opt_ty} - * respectively. - * @param {number|goog.math.Coordinate} tx The value to translate x by or the - * the coordinate to translate this coordinate by. - * @param {number=} opt_ty The value to translate y by. - * @return {!goog.math.Coordinate} This coordinate after translating. - */ -goog.math.Coordinate.prototype.translate = function(tx, opt_ty) { - if (tx instanceof goog.math.Coordinate) { - this.x += tx.x; - this.y += tx.y; - } else { - this.x += tx; - if (goog.isNumber(opt_ty)) { - this.y += opt_ty; + this.addQuad_( + a, ab, cd, d, aSrc, abSrc, cdSrc, dSrc, maxSubdivision - 1); + this.addQuad_( + ab, b, c, cd, abSrc, bSrc, cSrc, cdSrc, maxSubdivision - 1); + } + return; } } - return this; -}; + if (wrapsX) { + if (!this.canWrapXInSource_) { + return; + } + this.wrapsXInSource_ = true; + } -/** - * Scales this coordinate by the given scale factors. The x and y values are - * scaled by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} - * is not given, then {@code sx} is used for both x and y. - * @param {number} sx The scale factor to use for the x dimension. - * @param {number=} opt_sy The scale factor to use for the y dimension. - * @return {!goog.math.Coordinate} This coordinate after scaling. - */ -goog.math.Coordinate.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.x *= sx; - this.y *= sy; - return this; + this.addTriangle_(a, c, d, aSrc, cSrc, dSrc); + this.addTriangle_(a, b, c, aSrc, bSrc, cSrc); }; /** - * Rotates this coordinate clockwise about the origin (or, optionally, the given - * center) by the given angle, in radians. - * @param {number} radians The angle by which to rotate this coordinate - * clockwise about the given center, in radians. - * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults - * to (0, 0) if not given. + * Calculates extent of the 'source' coordinates from all the triangles. + * + * @return {ol.Extent} Calculated extent. */ -goog.math.Coordinate.prototype.rotateRadians = function(radians, opt_center) { - var center = opt_center || new goog.math.Coordinate(0, 0); +ol.reproj.Triangulation.prototype.calculateSourceExtent = function() { + var extent = ol.extent.createEmpty(); - var x = this.x; - var y = this.y; - var cos = Math.cos(radians); - var sin = Math.sin(radians); + this.triangles_.forEach(function(triangle, i, arr) { + var src = triangle.source; + ol.extent.extendCoordinate(extent, src[0]); + ol.extent.extendCoordinate(extent, src[1]); + ol.extent.extendCoordinate(extent, src[2]); + }); - this.x = (x - center.x) * cos - (y - center.y) * sin + center.x; - this.y = (x - center.x) * sin + (y - center.y) * cos + center.y; + return extent; }; /** - * Rotates this coordinate clockwise about the origin (or, optionally, the given - * center) by the given angle, in degrees. - * @param {number} degrees The angle by which to rotate this coordinate - * clockwise about the given center, in degrees. - * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults - * to (0, 0) if not given. + * @return {Array.<ol.reproj.Triangle>} Array of the calculated triangles. */ -goog.math.Coordinate.prototype.rotateDegrees = function(degrees, opt_center) { - this.rotateRadians(goog.math.toRadians(degrees), opt_center); +ol.reproj.Triangulation.prototype.getTriangles = function() { + return this.triangles_; }; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.provide('ol.reproj.Tile'); +goog.provide('ol.reproj.TileFunctionType'); -/** - * @fileoverview A utility class for representing two-dimensional sizes. - * @author brenneman@google.com (Shawn Brenneman) - */ +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.math'); +goog.require('goog.object'); +goog.require('ol.Tile'); +goog.require('ol.TileState'); +goog.require('ol.extent'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.reproj'); +goog.require('ol.reproj.Triangulation'); -goog.provide('goog.math.Size'); +/** + * @typedef {function(number, number, number, number) : ol.Tile} + */ +ol.reproj.TileFunctionType; /** - * Class for representing sizes consisting of a width and height. Undefined - * width and height support is deprecated and results in compiler warning. - * @param {number} width Width. - * @param {number} height Height. - * @struct + * @classdesc + * Class encapsulating single reprojected tile. + * See {@link ol.source.TileImage}. + * * @constructor + * @extends {ol.Tile} + * @param {ol.proj.Projection} sourceProj Source projection. + * @param {ol.tilegrid.TileGrid} sourceTileGrid Source tile grid. + * @param {ol.proj.Projection} targetProj Target projection. + * @param {ol.tilegrid.TileGrid} targetTileGrid Target tile grid. + * @param {number} z Zoom level. + * @param {number} x X. + * @param {number} y Y. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.reproj.TileFunctionType} getTileFunction + * Function returning source tiles (z, x, y, pixelRatio). + * @param {number=} opt_errorThreshold Acceptable reprojection error (in px). + * @param {boolean=} opt_renderEdges Render reprojection edges. */ -goog.math.Size = function(width, height) { +ol.reproj.Tile = function(sourceProj, sourceTileGrid, + targetProj, targetTileGrid, z, x, y, pixelRatio, getTileFunction, + opt_errorThreshold, + opt_renderEdges) { + goog.base(this, [z, x, y], ol.TileState.IDLE); + /** - * Width - * @type {number} + * @private + * @type {boolean} */ - this.width = width; + this.renderEdges_ = opt_renderEdges !== undefined ? opt_renderEdges : false; /** - * Height + * @private * @type {number} */ - this.height = height; -}; + this.pixelRatio_ = pixelRatio; + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = null; -/** - * Compares sizes for equality. - * @param {goog.math.Size} a A Size. - * @param {goog.math.Size} b A Size. - * @return {boolean} True iff the sizes have equal widths and equal - * heights, or if both are null. - */ -goog.math.Size.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.width == b.width && a.height == b.height; -}; + /** + * @private + * @type {Object.<number, HTMLCanvasElement>} + */ + this.canvasByContext_ = {}; + /** + * @private + * @type {ol.tilegrid.TileGrid} + */ + this.sourceTileGrid_ = sourceTileGrid; -/** - * @return {!goog.math.Size} A new copy of the Size. - */ -goog.math.Size.prototype.clone = function() { - return new goog.math.Size(this.width, this.height); -}; + /** + * @private + * @type {ol.tilegrid.TileGrid} + */ + this.targetTileGrid_ = targetTileGrid; + /** + * @private + * @type {!Array.<ol.Tile>} + */ + this.sourceTiles_ = []; -if (goog.DEBUG) { /** - * Returns a nice string representing size. - * @return {string} In the form (50 x 73). - * @override + * @private + * @type {Array.<goog.events.Key>} */ - goog.math.Size.prototype.toString = function() { - return '(' + this.width + ' x ' + this.height + ')'; - }; -} + this.sourcesListenerKeys_ = null; + /** + * @private + * @type {number} + */ + this.sourceZ_ = 0; -/** - * @return {number} The longer of the two dimensions in the size. - */ -goog.math.Size.prototype.getLongest = function() { - return Math.max(this.width, this.height); -}; + var targetExtent = targetTileGrid.getTileCoordExtent(this.getTileCoord()); + var maxTargetExtent = this.targetTileGrid_.getExtent(); + var maxSourceExtent = this.sourceTileGrid_.getExtent(); + var limitedTargetExtent = maxTargetExtent ? + ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent; -/** - * @return {number} The shorter of the two dimensions in the size. - */ -goog.math.Size.prototype.getShortest = function() { - return Math.min(this.width, this.height); -}; + if (ol.extent.getArea(limitedTargetExtent) === 0) { + // Tile is completely outside range -> EMPTY + // TODO: is it actually correct that the source even creates the tile ? + this.state = ol.TileState.EMPTY; + return; + } + var sourceProjExtent = sourceProj.getExtent(); + if (sourceProjExtent) { + if (!maxSourceExtent) { + maxSourceExtent = sourceProjExtent; + } else { + maxSourceExtent = ol.extent.getIntersection( + maxSourceExtent, sourceProjExtent); + } + } -/** - * @return {number} The area of the size (width * height). - */ -goog.math.Size.prototype.area = function() { - return this.width * this.height; -}; + var targetResolution = targetTileGrid.getResolution(z); + var targetCenter = ol.extent.getCenter(limitedTargetExtent); + var sourceResolution = ol.reproj.calculateSourceResolution( + sourceProj, targetProj, targetCenter, targetResolution); -/** - * @return {number} The perimeter of the size (width + height) * 2. - */ -goog.math.Size.prototype.perimeter = function() { - return (this.width + this.height) * 2; -}; + if (!goog.math.isFiniteNumber(sourceResolution) || sourceResolution <= 0) { + // invalid sourceResolution -> EMPTY + // probably edges of the projections when no extent is defined + this.state = ol.TileState.EMPTY; + return; + } + var errorThresholdInPixels = opt_errorThreshold !== undefined ? + opt_errorThreshold : ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD; -/** - * @return {number} The ratio of the size's width to its height. - */ -goog.math.Size.prototype.aspectRatio = function() { - return this.width / this.height; -}; + /** + * @private + * @type {!ol.reproj.Triangulation} + */ + this.triangulation_ = new ol.reproj.Triangulation( + sourceProj, targetProj, limitedTargetExtent, maxSourceExtent, + sourceResolution * errorThresholdInPixels); + if (this.triangulation_.getTriangles().length === 0) { + // no valid triangles -> EMPTY + this.state = ol.TileState.EMPTY; + return; + } -/** - * @return {boolean} True if the size has zero area, false if both dimensions - * are non-zero numbers. - */ -goog.math.Size.prototype.isEmpty = function() { - return !this.area(); -}; + this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution); + var sourceExtent = this.triangulation_.calculateSourceExtent(); + if (maxSourceExtent) { + if (sourceProj.canWrapX()) { + sourceExtent[1] = ol.math.clamp( + sourceExtent[1], maxSourceExtent[1], maxSourceExtent[3]); + sourceExtent[3] = ol.math.clamp( + sourceExtent[3], maxSourceExtent[1], maxSourceExtent[3]); + } else { + sourceExtent = ol.extent.getIntersection(sourceExtent, maxSourceExtent); + } + } -/** - * Clamps the width and height parameters upward to integer values. - * @return {!goog.math.Size} This size with ceil'd components. - */ -goog.math.Size.prototype.ceil = function() { - this.width = Math.ceil(this.width); - this.height = Math.ceil(this.height); - return this; -}; + if (!ol.extent.getArea(sourceExtent)) { + this.state = ol.TileState.EMPTY; + } else { + var sourceRange = sourceTileGrid.getTileRangeForExtentAndZ( + sourceExtent, this.sourceZ_); + var tilesRequired = sourceRange.getWidth() * sourceRange.getHeight(); + if (!goog.asserts.assert( + tilesRequired < ol.RASTER_REPROJECTION_MAX_SOURCE_TILES, + 'reasonable number of tiles is required')) { + this.state = ol.TileState.ERROR; + return; + } + for (var srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) { + for (var srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) { + var tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio); + if (tile) { + this.sourceTiles_.push(tile); + } + } + } -/** - * @param {!goog.math.Size} target The target size. - * @return {boolean} True if this Size is the same size or smaller than the - * target size in both dimensions. - */ -goog.math.Size.prototype.fitsInside = function(target) { - return this.width <= target.width && this.height <= target.height; + if (this.sourceTiles_.length === 0) { + this.state = ol.TileState.EMPTY; + } + } }; +goog.inherits(ol.reproj.Tile, ol.Tile); /** - * Clamps the width and height parameters downward to integer values. - * @return {!goog.math.Size} This size with floored components. + * @inheritDoc */ -goog.math.Size.prototype.floor = function() { - this.width = Math.floor(this.width); - this.height = Math.floor(this.height); - return this; +ol.reproj.Tile.prototype.disposeInternal = function() { + if (this.state == ol.TileState.LOADING) { + this.unlistenSources_(); + } + goog.base(this, 'disposeInternal'); }; /** - * Rounds the width and height parameters to integer values. - * @return {!goog.math.Size} This size with rounded components. + * @inheritDoc */ -goog.math.Size.prototype.round = function() { - this.width = Math.round(this.width); - this.height = Math.round(this.height); - return this; +ol.reproj.Tile.prototype.getImage = function(opt_context) { + if (opt_context !== undefined) { + var image; + var key = goog.getUid(opt_context); + if (key in this.canvasByContext_) { + return this.canvasByContext_[key]; + } else if (goog.object.isEmpty(this.canvasByContext_)) { + image = this.canvas_; + } else { + image = /** @type {HTMLCanvasElement} */ (this.canvas_.cloneNode(false)); + } + this.canvasByContext_[key] = image; + return image; + } else { + return this.canvas_; + } }; /** - * Scales this size by the given scale factors. The width and height are scaled - * by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} is not - * given, then {@code sx} is used for both the width and height. - * @param {number} sx The scale factor to use for the width. - * @param {number=} opt_sy The scale factor to use for the height. - * @return {!goog.math.Size} This Size object after scaling. + * @private */ -goog.math.Size.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.width *= sx; - this.height *= sy; - return this; -}; +ol.reproj.Tile.prototype.reproject_ = function() { + var sources = []; + this.sourceTiles_.forEach(function(tile, i, arr) { + if (tile && tile.getState() == ol.TileState.LOADED) { + sources.push({ + extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord), + image: tile.getImage() + }); + } + }, this); + this.sourceTiles_.length = 0; + var tileCoord = this.getTileCoord(); + var z = tileCoord[0]; + var size = this.targetTileGrid_.getTileSize(z); + var width = goog.isNumber(size) ? size : size[0]; + var height = goog.isNumber(size) ? size : size[1]; + var targetResolution = this.targetTileGrid_.getResolution(z); + var sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_); -/** - * Uniformly scales the size to perfectly cover the dimensions of a given size. - * If the size is already larger than the target, it will be scaled down to the - * minimum size at which it still covers the entire target. The original aspect - * ratio will be preserved. - * - * This function assumes that both Sizes contain strictly positive dimensions. - * @param {!goog.math.Size} target The target size. - * @return {!goog.math.Size} This Size object, after optional scaling. - */ -goog.math.Size.prototype.scaleToCover = function(target) { - var s = this.aspectRatio() <= target.aspectRatio() ? - target.width / this.width : - target.height / this.height; + var targetExtent = this.targetTileGrid_.getTileCoordExtent(tileCoord); + this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_, + sourceResolution, this.sourceTileGrid_.getExtent(), + targetResolution, targetExtent, this.triangulation_, sources, + this.renderEdges_); - return this.scale(s); + this.state = ol.TileState.LOADED; + this.changed(); }; /** - * Uniformly scales the size to fit inside the dimensions of a given size. The - * original aspect ratio will be preserved. - * - * This function assumes that both Sizes contain strictly positive dimensions. - * @param {!goog.math.Size} target The target size. - * @return {!goog.math.Size} This Size object, after optional scaling. + * @inheritDoc */ -goog.math.Size.prototype.scaleToFit = function(target) { - var s = this.aspectRatio() > target.aspectRatio() ? - target.width / this.width : - target.height / this.height; - - return this.scale(s); -}; - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +ol.reproj.Tile.prototype.load = function() { + if (this.state == ol.TileState.IDLE) { + this.state = ol.TileState.LOADING; + this.changed(); -/** - * @fileoverview Utilities for manipulating the browser's Document Object Model - * Inspiration taken *heavily* from mochikit (http://mochikit.com/). - * - * You can use {@link goog.dom.DomHelper} to create new dom helpers that refer - * to a different document object. This is useful if you are working with - * frames or multiple windows. - * - * @author arv@google.com (Erik Arvidsson) - */ + var leftToLoad = 0; + goog.asserts.assert(!this.sourcesListenerKeys_, + 'this.sourcesListenerKeys_ should be null'); -// TODO(arv): Rename/refactor getTextContent and getRawTextContent. The problem -// is that getTextContent should mimic the DOM3 textContent. We should add a -// getInnerText (or getText) which tries to return the visible text, innerText. + this.sourcesListenerKeys_ = []; + this.sourceTiles_.forEach(function(tile, i, arr) { + var state = tile.getState(); + if (state == ol.TileState.IDLE || state == ol.TileState.LOADING) { + leftToLoad++; + var sourceListenKey; + sourceListenKey = tile.listen(goog.events.EventType.CHANGE, + function(e) { + var state = tile.getState(); + if (state == ol.TileState.LOADED || + state == ol.TileState.ERROR || + state == ol.TileState.EMPTY) { + goog.events.unlistenByKey(sourceListenKey); + leftToLoad--; + goog.asserts.assert(leftToLoad >= 0, + 'leftToLoad should not be negative'); + if (leftToLoad === 0) { + this.unlistenSources_(); + this.reproject_(); + } + } + }, false, this); + this.sourcesListenerKeys_.push(sourceListenKey); + } + }, this); -goog.provide('goog.dom'); -goog.provide('goog.dom.Appendable'); -goog.provide('goog.dom.DomHelper'); + this.sourceTiles_.forEach(function(tile, i, arr) { + var state = tile.getState(); + if (state == ol.TileState.IDLE) { + tile.load(); + } + }); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.BrowserFeature'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.safe'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Size'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.string.Unicode'); -goog.require('goog.userAgent'); + if (leftToLoad === 0) { + this.reproject_(); + } + } +}; /** - * @define {boolean} Whether we know at compile time that the browser is in - * quirks mode. + * @private */ -goog.define('goog.dom.ASSUME_QUIRKS_MODE', false); +ol.reproj.Tile.prototype.unlistenSources_ = function() { + goog.asserts.assert(this.sourcesListenerKeys_, + 'this.sourcesListenerKeys_ should not be null'); + this.sourcesListenerKeys_.forEach(goog.events.unlistenByKey); + this.sourcesListenerKeys_ = null; +}; + +goog.provide('ol.TileUrlFunction'); +goog.provide('ol.TileUrlFunctionType'); + +goog.require('goog.asserts'); +goog.require('goog.math'); +goog.require('ol.TileCoord'); +goog.require('ol.tilecoord'); /** - * @define {boolean} Whether we know at compile time that the browser is in - * standards compliance mode. + * {@link ol.source.Tile} sources use a function of this type to get the url + * that provides a tile for a given tile coordinate. + * + * This function takes an {@link ol.TileCoord} for the tile coordinate, a + * `{number}` representing the pixel ratio and an {@link ol.proj.Projection} for + * the projection as arguments and returns a `{string}` representing the tile + * URL, or undefined if no tile should be requested for the passed tile + * coordinate. + * + * @typedef {function(ol.TileCoord, number, + * ol.proj.Projection): (string|undefined)} + * @api */ -goog.define('goog.dom.ASSUME_STANDARDS_MODE', false); +ol.TileUrlFunctionType; /** - * Whether we know the compatibility mode at compile time. - * @type {boolean} - * @private + * @typedef {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=): + * ol.TileCoord} */ -goog.dom.COMPAT_MODE_KNOWN_ = - goog.dom.ASSUME_QUIRKS_MODE || goog.dom.ASSUME_STANDARDS_MODE; +ol.TileCoordTransformType; /** - * Gets the DomHelper object for the document where the element resides. - * @param {(Node|Window)=} opt_element If present, gets the DomHelper for this - * element. - * @return {!goog.dom.DomHelper} The DomHelper. + * @param {string} template Template. + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @return {ol.TileUrlFunctionType} Tile URL function. */ -goog.dom.getDomHelper = function(opt_element) { - return opt_element ? - new goog.dom.DomHelper(goog.dom.getOwnerDocument(opt_element)) : - (goog.dom.defaultDomHelper_ || - (goog.dom.defaultDomHelper_ = new goog.dom.DomHelper())); +ol.TileUrlFunction.createFromTemplate = function(template, tileGrid) { + var zRegEx = /\{z\}/g; + var xRegEx = /\{x\}/g; + var yRegEx = /\{y\}/g; + var dashYRegEx = /\{-y\}/g; + return ( + /** + * @param {ol.TileCoord} tileCoord Tile Coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. + */ + function(tileCoord, pixelRatio, projection) { + if (!tileCoord) { + return undefined; + } else { + return template.replace(zRegEx, tileCoord[0].toString()) + .replace(xRegEx, tileCoord[1].toString()) + .replace(yRegEx, function() { + var y = -tileCoord[2] - 1; + return y.toString(); + }) + .replace(dashYRegEx, function() { + var z = tileCoord[0]; + var range = tileGrid.getFullTileRange(z); + goog.asserts.assert(range, + 'The {-y} template requires a tile grid with extent'); + var y = range.getHeight() + tileCoord[2]; + return y.toString(); + }); + } + }); }; /** - * Cached default DOM helper. - * @type {goog.dom.DomHelper} - * @private + * @param {Array.<string>} templates Templates. + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @return {ol.TileUrlFunctionType} Tile URL function. */ -goog.dom.defaultDomHelper_; +ol.TileUrlFunction.createFromTemplates = function(templates, tileGrid) { + var len = templates.length; + var tileUrlFunctions = new Array(len); + for (var i = 0; i < len; ++i) { + tileUrlFunctions[i] = ol.TileUrlFunction.createFromTemplate( + templates[i], tileGrid); + } + return ol.TileUrlFunction.createFromTileUrlFunctions(tileUrlFunctions); +}; /** - * Gets the document object being used by the dom library. - * @return {!Document} Document object. + * @param {Array.<ol.TileUrlFunctionType>} tileUrlFunctions Tile URL Functions. + * @return {ol.TileUrlFunctionType} Tile URL function. */ -goog.dom.getDocument = function() { - return document; +ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) { + goog.asserts.assert(tileUrlFunctions.length > 0, + 'Length of tile url functions should be greater than 0'); + if (tileUrlFunctions.length === 1) { + return tileUrlFunctions[0]; + } + return ( + /** + * @param {ol.TileCoord} tileCoord Tile Coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. + */ + function(tileCoord, pixelRatio, projection) { + if (!tileCoord) { + return undefined; + } else { + var h = ol.tilecoord.hash(tileCoord); + var index = goog.math.modulo(h, tileUrlFunctions.length); + return tileUrlFunctions[index](tileCoord, pixelRatio, projection); + } + }); }; /** - * Gets an element from the current document by element id. - * - * If an Element is passed in, it is returned. - * - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. */ -goog.dom.getElement = function(element) { - return goog.dom.getElementHelper_(document, element); +ol.TileUrlFunction.nullTileUrlFunction = + function(tileCoord, pixelRatio, projection) { + return undefined; }; /** - * Gets an element by id from the given document (if present). - * If an element is given, it is returned. - * @param {!Document} doc - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The resulting element. - * @private + * @param {string} url URL. + * @return {Array.<string>} Array of urls. */ -goog.dom.getElementHelper_ = function(doc, element) { - return goog.isString(element) ? - doc.getElementById(element) : - element; +ol.TileUrlFunction.expandUrl = function(url) { + var urls = []; + var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url); + if (match) { + var startCharCode = match[1].charCodeAt(0); + var stopCharCode = match[2].charCodeAt(0); + var charCode; + for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) { + urls.push(url.replace(match[0], String.fromCharCode(charCode))); + } + } else { + urls.push(url); + } + return urls; }; +goog.provide('ol.array'); -/** - * Gets an element by id, asserting that the element is found. - * - * This is used when an element is expected to exist, and should fail with - * an assertion error if it does not (if assertions are enabled). - * - * @param {string} id Element ID. - * @return {!Element} The element with the given ID, if it exists. - */ -goog.dom.getRequiredElement = function(id) { - return goog.dom.getRequiredElementHelper_(document, id); -}; +goog.require('goog.array'); +goog.require('goog.asserts'); /** - * Helper function for getRequiredElementHelper functions, both static and - * on DomHelper. Asserts the element with the given id exists. - * @param {!Document} doc - * @param {string} id - * @return {!Element} The element with the given ID, if it exists. - * @private + * @param {Array.<number>} arr Array. + * @param {number} target Target. + * @return {number} Index. */ -goog.dom.getRequiredElementHelper_ = function(doc, id) { - // To prevent users passing in Elements as is permitted in getElement(). - goog.asserts.assertString(id); - var element = goog.dom.getElementHelper_(doc, id); - element = goog.asserts.assertElement(element, - 'No element found with id: ' + id); - return element; +ol.array.binaryFindNearest = function(arr, target) { + var index = goog.array.binarySearch(arr, target, + /** + * @param {number} a A. + * @param {number} b B. + * @return {number} b minus a. + */ + function(a, b) { + return b - a; + }); + if (index >= 0) { + return index; + } else if (index == -1) { + return 0; + } else if (index == -arr.length - 1) { + return arr.length - 1; + } else { + var left = -index - 2; + var right = -index - 1; + if (arr[left] - target < target - arr[right]) { + return left; + } else { + return right; + } + } }; /** - * Alias for getElement. - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. - * @deprecated Use {@link goog.dom.getElement} instead. - */ -goog.dom.$ = goog.dom.getElement; - - -/** - * Looks up elements by both tag and class name, using browser native functions - * ({@code querySelectorAll}, {@code getElementsByTagName} or - * {@code getElementsByClassName}) where possible. This function - * is a useful, if limited, way of collecting a list of DOM elements - * with certain characteristics. {@code goog.dom.query} offers a - * more powerful and general solution which allows matching on CSS3 - * selector expressions, but at increased cost in code size. If all you - * need is particular tags belonging to a single class, this function - * is fast and sleek. - * - * Note that tag names are case sensitive in the SVG namespace, and this - * function converts opt_tag to uppercase for comparisons. For queries in the - * SVG namespace you should use querySelector or querySelectorAll instead. - * https://bugzilla.mozilla.org/show_bug.cgi?id=963870 - * https://bugs.webkit.org/show_bug.cgi?id=83438 - * - * @see {goog.dom.query} - * - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). + * Whether the array contains the given object. + * @param {Array.<*>} arr The array to test for the presence of the element. + * @param {*} obj The object for which to test. + * @return {boolean} The object is in the array. */ -goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) { - return goog.dom.getElementsByTagNameAndClass_(document, opt_tag, opt_class, - opt_el); +ol.array.includes = function(arr, obj) { + return arr.indexOf(obj) >= 0; }; /** - * Returns a static, array-like list of the elements with the provided - * className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } The items found with the class name provided. + * @param {Array.<number>} arr Array. + * @param {number} target Target. + * @param {number} direction 0 means return the nearest, > 0 + * means return the largest nearest, < 0 means return the + * smallest nearest. + * @return {number} Index. */ -goog.dom.getElementsByClass = function(className, opt_el) { - var parent = opt_el || document; - if (goog.dom.canUseQuerySelector_(parent)) { - return parent.querySelectorAll('.' + className); +ol.array.linearFindNearest = function(arr, target, direction) { + var n = arr.length; + if (arr[0] <= target) { + return 0; + } else if (target <= arr[n - 1]) { + return n - 1; + } else { + var i; + if (direction > 0) { + for (i = 1; i < n; ++i) { + if (arr[i] < target) { + return i - 1; + } + } + } else if (direction < 0) { + for (i = 1; i < n; ++i) { + if (arr[i] <= target) { + return i; + } + } + } else { + for (i = 1; i < n; ++i) { + if (arr[i] == target) { + return i; + } else if (arr[i] < target) { + if (arr[i - 1] - target < target - arr[i]) { + return i - 1; + } else { + return i; + } + } + } + } + // We should never get here, but the compiler complains + // if it finds a path for which no number is returned. + goog.asserts.fail(); + return n - 1; } - return goog.dom.getElementsByTagNameAndClass_( - document, '*', className, opt_el); }; /** - * Returns the first element with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {Element|Document=} opt_el Optional element to look in. - * @return {Element} The first item with the class name provided. + * @param {Array.<*>} arr Array. + * @param {number} begin Begin index. + * @param {number} end End index. */ -goog.dom.getElementByClass = function(className, opt_el) { - var parent = opt_el || document; - var retVal = null; - if (parent.getElementsByClassName) { - retVal = parent.getElementsByClassName(className)[0]; - } else if (goog.dom.canUseQuerySelector_(parent)) { - retVal = parent.querySelector('.' + className); - } else { - retVal = goog.dom.getElementsByTagNameAndClass_( - document, '*', className, opt_el)[0]; +ol.array.reverseSubArray = function(arr, begin, end) { + goog.asserts.assert(begin >= 0, + 'Array begin index should be equal to or greater than 0'); + goog.asserts.assert(end < arr.length, + 'Array end index should be less than the array length'); + while (begin < end) { + var tmp = arr[begin]; + arr[begin] = arr[end]; + arr[end] = tmp; + ++begin; + --end; } - return retVal || null; }; +goog.provide('ol.tilegrid.TileGrid'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Coordinate'); +goog.require('ol.TileCoord'); +goog.require('ol.TileRange'); +goog.require('ol.array'); +goog.require('ol.extent'); +goog.require('ol.extent.Corner'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.proj.METERS_PER_UNIT'); +goog.require('ol.proj.Projection'); +goog.require('ol.proj.Units'); +goog.require('ol.size'); +goog.require('ol.tilecoord'); -/** - * Ensures an element with the given className exists, and then returns the - * first element with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {!Element|!Document=} opt_root Optional element or document to look - * in. - * @return {!Element} The first item with the class name provided. - * @throws {goog.asserts.AssertionError} Thrown if no element is found. - */ -goog.dom.getRequiredElementByClass = function(className, opt_root) { - var retValue = goog.dom.getElementByClass(className, opt_root); - return goog.asserts.assert(retValue, - 'No element found with className: ' + className); -}; /** - * Prefer the standardized (http://www.w3.org/TR/selectors-api/), native and - * fast W3C Selectors API. - * @param {!(Element|Document)} parent The parent document object. - * @return {boolean} whether or not we can use parent.querySelector* APIs. - * @private + * @classdesc + * Base class for setting the grid pattern for sources accessing tiled-image + * servers. + * + * @constructor + * @param {olx.tilegrid.TileGridOptions} options Tile grid options. + * @struct + * @api stable */ -goog.dom.canUseQuerySelector_ = function(parent) { - return !!(parent.querySelectorAll && parent.querySelector); -}; +ol.tilegrid.TileGrid = function(options) { + /** + * @protected + * @type {number} + */ + this.minZoom = options.minZoom !== undefined ? options.minZoom : 0; -/** - * Helper for {@code getElementsByTagNameAndClass}. - * @param {!Document} doc The document to get the elements in. - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - * @private - */ -goog.dom.getElementsByTagNameAndClass_ = function(doc, opt_tag, opt_class, - opt_el) { - var parent = opt_el || doc; - var tagName = (opt_tag && opt_tag != '*') ? opt_tag.toUpperCase() : ''; + /** + * @private + * @type {!Array.<number>} + */ + this.resolutions_ = options.resolutions; + goog.asserts.assert(goog.array.isSorted(this.resolutions_, function(a, b) { + return b - a; + }, true), 'resolutions must be sorted in descending order'); - if (goog.dom.canUseQuerySelector_(parent) && - (tagName || opt_class)) { - var query = tagName + (opt_class ? '.' + opt_class : ''); - return parent.querySelectorAll(query); + /** + * @protected + * @type {number} + */ + this.maxZoom = this.resolutions_.length - 1; + + /** + * @private + * @type {ol.Coordinate} + */ + this.origin_ = options.origin !== undefined ? options.origin : null; + + /** + * @private + * @type {Array.<ol.Coordinate>} + */ + this.origins_ = null; + if (options.origins !== undefined) { + this.origins_ = options.origins; + goog.asserts.assert(this.origins_.length == this.resolutions_.length, + 'number of origins and resolutions must be equal'); } - // Use the native getElementsByClassName if available, under the assumption - // that even when the tag name is specified, there will be fewer elements to - // filter through when going by class than by tag name - if (opt_class && parent.getElementsByClassName) { - var els = parent.getElementsByClassName(opt_class); + var extent = options.extent; - if (tagName) { - var arrayLike = {}; - var len = 0; + if (extent !== undefined && + !this.origin_ && !this.origins_) { + this.origin_ = ol.extent.getTopLeft(extent); + } - // Filter for specific tags if requested. - for (var i = 0, el; el = els[i]; i++) { - if (tagName == el.nodeName) { - arrayLike[len++] = el; - } - } - arrayLike.length = len; + goog.asserts.assert( + (!this.origin_ && this.origins_) || + (this.origin_ && !this.origins_), + 'either origin or origins must be configured, never both'); - return arrayLike; - } else { - return els; - } + /** + * @private + * @type {Array.<number|ol.Size>} + */ + this.tileSizes_ = null; + if (options.tileSizes !== undefined) { + this.tileSizes_ = options.tileSizes; + goog.asserts.assert(this.tileSizes_.length == this.resolutions_.length, + 'number of tileSizes and resolutions must be equal'); } - var els = parent.getElementsByTagName(tagName || '*'); + /** + * @private + * @type {number|ol.Size} + */ + this.tileSize_ = options.tileSize !== undefined ? + options.tileSize : + !this.tileSizes_ ? ol.DEFAULT_TILE_SIZE : null; + goog.asserts.assert( + (!this.tileSize_ && this.tileSizes_) || + (this.tileSize_ && !this.tileSizes_), + 'either tileSize or tileSizes must be configured, never both'); - if (opt_class) { - var arrayLike = {}; - var len = 0; - for (var i = 0, el; el = els[i]; i++) { - var className = el.className; - // Check if className has a split function since SVG className does not. - if (typeof className.split == 'function' && - goog.array.contains(className.split(/\s+/), opt_class)) { - arrayLike[len++] = el; + /** + * @private + * @type {ol.Extent} + */ + this.extent_ = extent !== undefined ? extent : null; + + + /** + * @private + * @type {Array.<ol.TileRange>} + */ + this.fullTileRanges_ = null; + + if (options.sizes !== undefined) { + goog.asserts.assert(options.sizes.length == this.resolutions_.length, + 'number of sizes and resolutions must be equal'); + this.fullTileRanges_ = options.sizes.map(function(size, z) { + goog.asserts.assert(size[0] !== 0, 'width must not be 0'); + goog.asserts.assert(size[1] !== 0, 'height must not be 0'); + var tileRange = new ol.TileRange( + Math.min(0, size[0]), Math.max(size[0] - 1, -1), + Math.min(0, size[1]), Math.max(size[1] - 1, -1)); + if (this.minZoom <= z && z <= this.maxZoom && extent !== undefined) { + goog.asserts.assert(tileRange.containsTileRange( + this.getTileRangeForExtentAndZ(extent, z)), + 'extent tile range must not exceed tilegrid width and height'); } - } - arrayLike.length = len; - return arrayLike; - } else { - return els; + return tileRange; + }, this); + } else if (extent) { + this.calculateTileRanges_(extent); } + + /** + * @private + * @type {ol.Size} + */ + this.tmpSize_ = [0, 0]; + }; /** - * Alias for {@code getElementsByTagNameAndClass}. - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {Element=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). - * @deprecated Use {@link goog.dom.getElementsByTagNameAndClass} instead. + * @private + * @type {ol.TileCoord} */ -goog.dom.$$ = goog.dom.getElementsByTagNameAndClass; +ol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0]; /** - * Sets multiple properties on a node. - * @param {Element} element DOM node to set properties on. - * @param {Object} properties Hash of property:value pairs. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {function(this: T, number, ol.TileRange): boolean} callback Callback. + * @param {T=} opt_this The object to use as `this` in `callback`. + * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. + * @param {ol.Extent=} opt_extent Temporary ol.Extent object. + * @return {boolean} Callback succeeded. + * @template T */ -goog.dom.setProperties = function(element, properties) { - goog.object.forEach(properties, function(val, key) { - if (key == 'style') { - element.style.cssText = val; - } else if (key == 'class') { - element.className = val; - } else if (key == 'for') { - element.htmlFor = val; - } else if (goog.dom.DIRECT_ATTRIBUTE_MAP_.hasOwnProperty(key)) { - element.setAttribute(goog.dom.DIRECT_ATTRIBUTE_MAP_[key], val); - } else if (goog.string.startsWith(key, 'aria-') || - goog.string.startsWith(key, 'data-')) { - element.setAttribute(key, val); - } else { - element[key] = val; +ol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange = + function(tileCoord, callback, opt_this, opt_tileRange, opt_extent) { + var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); + var z = tileCoord[0] - 1; + while (z >= this.minZoom) { + if (callback.call(opt_this, z, + this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange))) { + return true; } - }); + --z; + } + return false; }; /** - * Map of attributes that should be set using - * element.setAttribute(key, val) instead of element[key] = val. Used - * by goog.dom.setProperties. - * - * @private {!Object<string, string>} - * @const + * Get the extent for this tile grid, if it was configured. + * @return {ol.Extent} Extent. */ -goog.dom.DIRECT_ATTRIBUTE_MAP_ = { - 'cellpadding': 'cellPadding', - 'cellspacing': 'cellSpacing', - 'colspan': 'colSpan', - 'frameborder': 'frameBorder', - 'height': 'height', - 'maxlength': 'maxLength', - 'role': 'role', - 'rowspan': 'rowSpan', - 'type': 'type', - 'usemap': 'useMap', - 'valign': 'vAlign', - 'width': 'width' +ol.tilegrid.TileGrid.prototype.getExtent = function() { + return this.extent_; }; /** - * Gets the dimensions of the viewport. - * - * Gecko Standards mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Width of viewport including scrollbar. - * body.clientWidth Width of body element. - * - * docEl.clientHeight Height of viewport excluding scrollbar. - * win.innerHeight Height of viewport including scrollbar. - * body.clientHeight Height of document. - * - * Gecko Backwards compatible mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Width of viewport including scrollbar. - * body.clientWidth Width of viewport excluding scrollbar. - * - * docEl.clientHeight Height of document. - * win.innerHeight Height of viewport including scrollbar. - * body.clientHeight Height of viewport excluding scrollbar. - * - * IE6/7 Standards mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Undefined. - * body.clientWidth Width of body element. - * - * docEl.clientHeight Height of viewport excluding scrollbar. - * win.innerHeight Undefined. - * body.clientHeight Height of document element. - * - * IE5 + IE6/7 Backwards compatible mode: - * docEl.clientWidth 0. - * win.innerWidth Undefined. - * body.clientWidth Width of viewport excluding scrollbar. - * - * docEl.clientHeight 0. - * win.innerHeight Undefined. - * body.clientHeight Height of viewport excluding scrollbar. - * - * Opera 9 Standards and backwards compatible mode: - * docEl.clientWidth Width of viewport excluding scrollbar. - * win.innerWidth Width of viewport including scrollbar. - * body.clientWidth Width of viewport excluding scrollbar. - * - * docEl.clientHeight Height of document. - * win.innerHeight Height of viewport including scrollbar. - * body.clientHeight Height of viewport excluding scrollbar. - * - * WebKit: - * Safari 2 - * docEl.clientHeight Same as scrollHeight. - * docEl.clientWidth Same as innerWidth. - * win.innerWidth Width of viewport excluding scrollbar. - * win.innerHeight Height of the viewport including scrollbar. - * frame.innerHeight Height of the viewport exluding scrollbar. - * - * Safari 3 (tested in 522) - * - * docEl.clientWidth Width of viewport excluding scrollbar. - * docEl.clientHeight Height of viewport excluding scrollbar in strict mode. - * body.clientHeight Height of viewport excluding scrollbar in quirks mode. - * - * @param {Window=} opt_window Optional window element to test. - * @return {!goog.math.Size} Object with values 'width' and 'height'. + * Get the maximum zoom level for the grid. + * @return {number} Max zoom. + * @api */ -goog.dom.getViewportSize = function(opt_window) { - // TODO(arv): This should not take an argument - return goog.dom.getViewportSize_(opt_window || window); +ol.tilegrid.TileGrid.prototype.getMaxZoom = function() { + return this.maxZoom; }; /** - * Helper for {@code getViewportSize}. - * @param {Window} win The window to get the view port size for. - * @return {!goog.math.Size} Object with values 'width' and 'height'. - * @private + * Get the minimum zoom level for the grid. + * @return {number} Min zoom. + * @api */ -goog.dom.getViewportSize_ = function(win) { - var doc = win.document; - var el = goog.dom.isCss1CompatMode_(doc) ? doc.documentElement : doc.body; - return new goog.math.Size(el.clientWidth, el.clientHeight); +ol.tilegrid.TileGrid.prototype.getMinZoom = function() { + return this.minZoom; }; /** - * Calculates the height of the document. - * - * @return {number} The height of the current document. + * Get the origin for the grid at the given zoom level. + * @param {number} z Z. + * @return {ol.Coordinate} Origin. + * @api stable */ -goog.dom.getDocumentHeight = function() { - return goog.dom.getDocumentHeight_(window); +ol.tilegrid.TileGrid.prototype.getOrigin = function(z) { + if (this.origin_) { + return this.origin_; + } else { + goog.asserts.assert(this.origins_, + 'origins cannot be null if origin is null'); + goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, + 'given z is not in allowed range (%s <= %s <= %s)', + this.minZoom, z, this.maxZoom); + return this.origins_[z]; + } }; /** - * Calculates the height of the document of the given window. - * - * Function code copied from the opensocial gadget api: - * gadgets.window.adjustHeight(opt_height) - * - * @private - * @param {!Window} win The window whose document height to retrieve. - * @return {number} The height of the document of the given window. + * Get the resolution for the given zoom level. + * @param {number} z Z. + * @return {number} Resolution. + * @api stable */ -goog.dom.getDocumentHeight_ = function(win) { - // NOTE(eae): This method will return the window size rather than the document - // size in webkit quirks mode. - var doc = win.document; - var height = 0; - - if (doc) { - // Calculating inner content height is hard and different between - // browsers rendering in Strict vs. Quirks mode. We use a combination of - // three properties within document.body and document.documentElement: - // - scrollHeight - // - offsetHeight - // - clientHeight - // These values differ significantly between browsers and rendering modes. - // But there are patterns. It just takes a lot of time and persistence - // to figure out. - - var body = doc.body; - var docEl = /** @type {!HTMLElement} */ (doc.documentElement); - if (!(docEl && body)) { - return 0; - } - - // Get the height of the viewport - var vh = goog.dom.getViewportSize_(win).height; - if (goog.dom.isCss1CompatMode_(doc) && docEl.scrollHeight) { - // In Strict mode: - // The inner content height is contained in either: - // document.documentElement.scrollHeight - // document.documentElement.offsetHeight - // Based on studying the values output by different browsers, - // use the value that's NOT equal to the viewport height found above. - height = docEl.scrollHeight != vh ? - docEl.scrollHeight : docEl.offsetHeight; - } else { - // In Quirks mode: - // documentElement.clientHeight is equal to documentElement.offsetHeight - // except in IE. In most browsers, document.documentElement can be used - // to calculate the inner content height. - // However, in other browsers (e.g. IE), document.body must be used - // instead. How do we know which one to use? - // If document.documentElement.clientHeight does NOT equal - // document.documentElement.offsetHeight, then use document.body. - var sh = docEl.scrollHeight; - var oh = docEl.offsetHeight; - if (docEl.clientHeight != oh) { - sh = body.scrollHeight; - oh = body.offsetHeight; - } - - // Detect whether the inner content height is bigger or smaller - // than the bounding box (viewport). If bigger, take the larger - // value. If smaller, take the smaller value. - if (sh > vh) { - // Content is larger - height = sh > oh ? sh : oh; - } else { - // Content is smaller - height = sh < oh ? sh : oh; - } - } - } - - return height; +ol.tilegrid.TileGrid.prototype.getResolution = function(z) { + goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, + 'given z is not in allowed range (%s <= %s <= %s)', + this.minZoom, z, this.maxZoom); + return this.resolutions_[z]; }; /** - * Gets the page scroll distance as a coordinate object. - * - * @param {Window=} opt_window Optional window element to test. - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. - * @deprecated Use {@link goog.dom.getDocumentScroll} instead. + * Get the list of resolutions for the tile grid. + * @return {Array.<number>} Resolutions. + * @api stable */ -goog.dom.getPageScroll = function(opt_window) { - var win = opt_window || goog.global || window; - return goog.dom.getDomHelper(win.document).getDocumentScroll(); +ol.tilegrid.TileGrid.prototype.getResolutions = function() { + return this.resolutions_; }; /** - * Gets the document scroll distance as a coordinate object. - * - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. + * @param {ol.Extent=} opt_extent Temporary ol.Extent object. + * @return {ol.TileRange} Tile range. */ -goog.dom.getDocumentScroll = function() { - return goog.dom.getDocumentScroll_(document); +ol.tilegrid.TileGrid.prototype.getTileCoordChildTileRange = + function(tileCoord, opt_tileRange, opt_extent) { + if (tileCoord[0] < this.maxZoom) { + var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); + return this.getTileRangeForExtentAndZ( + tileCoordExtent, tileCoord[0] + 1, opt_tileRange); + } else { + return null; + } }; /** - * Helper for {@code getDocumentScroll}. - * - * @param {!Document} doc The document to get the scroll for. - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. - * @private + * @param {number} z Z. + * @param {ol.TileRange} tileRange Tile range. + * @param {ol.Extent=} opt_extent Temporary ol.Extent object. + * @return {ol.Extent} Extent. */ -goog.dom.getDocumentScroll_ = function(doc) { - var el = goog.dom.getDocumentScrollElement_(doc); - var win = goog.dom.getWindow_(doc); - if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('10') && - win.pageYOffset != el.scrollTop) { - // The keyboard on IE10 touch devices shifts the page using the pageYOffset - // without modifying scrollTop. For this case, we want the body scroll - // offsets. - return new goog.math.Coordinate(el.scrollLeft, el.scrollTop); - } - return new goog.math.Coordinate(win.pageXOffset || el.scrollLeft, - win.pageYOffset || el.scrollTop); +ol.tilegrid.TileGrid.prototype.getTileRangeExtent = + function(z, tileRange, opt_extent) { + var origin = this.getOrigin(z); + var resolution = this.getResolution(z); + var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_); + var minX = origin[0] + tileRange.minX * tileSize[0] * resolution; + var maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution; + var minY = origin[1] + tileRange.minY * tileSize[1] * resolution; + var maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution; + return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); }; /** - * Gets the document scroll element. - * @return {!Element} Scrolling element. + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {ol.TileRange=} opt_tileRange Temporary tile range object. + * @return {ol.TileRange} Tile range. */ -goog.dom.getDocumentScrollElement = function() { - return goog.dom.getDocumentScrollElement_(document); +ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = + function(extent, resolution, opt_tileRange) { + var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_; + this.getTileCoordForXYAndResolution_( + extent[0], extent[1], resolution, false, tileCoord); + var minX = tileCoord[1]; + var minY = tileCoord[2]; + this.getTileCoordForXYAndResolution_( + extent[2], extent[3], resolution, true, tileCoord); + return ol.TileRange.createOrUpdate( + minX, tileCoord[1], minY, tileCoord[2], opt_tileRange); }; /** - * Helper for {@code getDocumentScrollElement}. - * @param {!Document} doc The document to get the scroll element for. - * @return {!Element} Scrolling element. - * @private + * @param {ol.Extent} extent Extent. + * @param {number} z Z. + * @param {ol.TileRange=} opt_tileRange Temporary tile range object. + * @return {ol.TileRange} Tile range. */ -goog.dom.getDocumentScrollElement_ = function(doc) { - // Old WebKit needs body.scrollLeft in both quirks mode and strict mode. We - // also default to the documentElement if the document does not have a body - // (e.g. a SVG document). - // Uses http://dev.w3.org/csswg/cssom-view/#dom-document-scrollingelement to - // avoid trying to guess about browser behavior from the UA string. - if (doc.scrollingElement) { - return doc.scrollingElement; - } - if (!goog.userAgent.WEBKIT && goog.dom.isCss1CompatMode_(doc)) { - return doc.documentElement; - } - return doc.body || doc.documentElement; +ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = + function(extent, z, opt_tileRange) { + var resolution = this.getResolution(z); + return this.getTileRangeForExtentAndResolution( + extent, resolution, opt_tileRange); }; /** - * Gets the window object associated with the given document. - * - * @param {Document=} opt_doc Document object to get window for. - * @return {!Window} The window associated with the given document. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @return {ol.Coordinate} Tile center. */ -goog.dom.getWindow = function(opt_doc) { - // TODO(arv): This should not take an argument. - return opt_doc ? goog.dom.getWindow_(opt_doc) : window; +ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) { + var origin = this.getOrigin(tileCoord[0]); + var resolution = this.getResolution(tileCoord[0]); + var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); + return [ + origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution, + origin[1] + (tileCoord[2] + 0.5) * tileSize[1] * resolution + ]; }; /** - * Helper for {@code getWindow}. + * Get the extent of a tile coordinate. * - * @param {!Document} doc Document object to get window for. - * @return {!Window} The window associated with the given document. - * @private + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.Extent=} opt_extent Temporary extent object. + * @return {ol.Extent} Extent. + * @api */ -goog.dom.getWindow_ = function(doc) { - return doc.parentWindow || doc.defaultView; +ol.tilegrid.TileGrid.prototype.getTileCoordExtent = + function(tileCoord, opt_extent) { + var origin = this.getOrigin(tileCoord[0]); + var resolution = this.getResolution(tileCoord[0]); + var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); + var minX = origin[0] + tileCoord[1] * tileSize[0] * resolution; + var minY = origin[1] + tileCoord[2] * tileSize[1] * resolution; + var maxX = minX + tileSize[0] * resolution; + var maxY = minY + tileSize[1] * resolution; + return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); }; /** - * Returns a dom node with a set of attributes. This function accepts varargs - * for subsequent nodes to be added. Subsequent nodes will be added to the - * first node as childNodes. - * - * So: - * <code>createDom('div', null, createDom('p'), createDom('p'));</code> - * would return a div with two child paragraphs + * Get the tile coordinate for the given map coordinate and resolution. This + * method considers that coordinates that intersect tile boundaries should be + * assigned the higher tile coordinate. * - * @param {string} tagName Tag to create. - * @param {(Object|Array<string>|string)=} opt_attributes If object, then a map - * of name-value pairs for attributes. If a string, then this is the - * className of the new element. If an array, the elements will be joined - * together as the className of the new element. - * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or - * strings for text nodes. If one of the var_args is an array or NodeList, - * its elements will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object. + * @return {ol.TileCoord} Tile coordinate. + * @api */ -goog.dom.createDom = function(tagName, opt_attributes, var_args) { - return goog.dom.createDom_(document, arguments); +ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = + function(coordinate, resolution, opt_tileCoord) { + return this.getTileCoordForXYAndResolution_( + coordinate[0], coordinate[1], resolution, false, opt_tileCoord); }; /** - * Helper for {@code createDom}. - * @param {!Document} doc The document to create the DOM in. - * @param {!Arguments} args Argument object passed from the callers. See - * {@code goog.dom.createDom} for details. - * @return {!Element} Reference to a DOM node. + * @param {number} x X. + * @param {number} y Y. + * @param {number} resolution Resolution. + * @param {boolean} reverseIntersectionPolicy Instead of letting edge + * intersections go to the higher tile coordinate, let edge intersections + * go to the lower tile coordinate. + * @param {ol.TileCoord=} opt_tileCoord Temporary ol.TileCoord object. + * @return {ol.TileCoord} Tile coordinate. * @private */ -goog.dom.createDom_ = function(doc, args) { - var tagName = args[0]; - var attributes = args[1]; - - // Internet Explorer is dumb: http://msdn.microsoft.com/workshop/author/ - // dhtml/reference/properties/name_2.asp - // Also does not allow setting of 'type' attribute on 'input' or 'button'. - if (!goog.dom.BrowserFeature.CAN_ADD_NAME_OR_TYPE_ATTRIBUTES && attributes && - (attributes.name || attributes.type)) { - var tagNameArr = ['<', tagName]; - if (attributes.name) { - tagNameArr.push(' name="', goog.string.htmlEscape(attributes.name), - '"'); - } - if (attributes.type) { - tagNameArr.push(' type="', goog.string.htmlEscape(attributes.type), - '"'); - - // Clone attributes map to remove 'type' without mutating the input. - var clone = {}; - goog.object.extend(clone, attributes); - - // JSCompiler can't see how goog.object.extend added this property, - // because it was essentially added by reflection. - // So it needs to be quoted. - delete clone['type']; - - attributes = clone; - } - tagNameArr.push('>'); - tagName = tagNameArr.join(''); - } - - var element = doc.createElement(tagName); +ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function( + x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) { + var z = this.getZForResolution(resolution); + var scale = resolution / this.getResolution(z); + var origin = this.getOrigin(z); + var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_); - if (attributes) { - if (goog.isString(attributes)) { - element.className = attributes; - } else if (goog.isArray(attributes)) { - element.className = attributes.join(' '); - } else { - goog.dom.setProperties(element, attributes); - } - } + var adjustX = reverseIntersectionPolicy ? 0.5 : 0; + var adjustY = reverseIntersectionPolicy ? 0 : 0.5; + var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX); + var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY); + var tileCoordX = scale * xFromOrigin / tileSize[0]; + var tileCoordY = scale * yFromOrigin / tileSize[1]; - if (args.length > 2) { - goog.dom.append_(doc, element, args, 2); + if (reverseIntersectionPolicy) { + tileCoordX = Math.ceil(tileCoordX) - 1; + tileCoordY = Math.ceil(tileCoordY) - 1; + } else { + tileCoordX = Math.floor(tileCoordX); + tileCoordY = Math.floor(tileCoordY); } - return element; + return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord); }; /** - * Appends a node with text or other nodes. - * @param {!Document} doc The document to create new nodes in. - * @param {!Node} parent The node to append nodes to. - * @param {!Arguments} args The values to add. See {@code goog.dom.append}. - * @param {number} startIndex The index of the array to start from. - * @private + * Get a tile coordinate given a map coordinate and zoom level. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} z Zoom level. + * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object. + * @return {ol.TileCoord} Tile coordinate. + * @api */ -goog.dom.append_ = function(doc, parent, args, startIndex) { - function childHandler(child) { - // TODO(user): More coercion, ala MochiKit? - if (child) { - parent.appendChild(goog.isString(child) ? - doc.createTextNode(child) : child); - } - } - - for (var i = startIndex; i < args.length; i++) { - var arg = args[i]; - // TODO(attila): Fix isArrayLike to return false for a text node. - if (goog.isArrayLike(arg) && !goog.dom.isNodeLike(arg)) { - // If the argument is a node list, not a real array, use a clone, - // because forEach can't be used to mutate a NodeList. - goog.array.forEach(goog.dom.isNodeList(arg) ? - goog.array.toArray(arg) : arg, - childHandler); - } else { - childHandler(arg); - } - } +ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ = + function(coordinate, z, opt_tileCoord) { + var resolution = this.getResolution(z); + return this.getTileCoordForXYAndResolution_( + coordinate[0], coordinate[1], resolution, false, opt_tileCoord); }; /** - * Alias for {@code createDom}. - * @param {string} tagName Tag to create. - * @param {(string|Object)=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. - * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or - * strings for text nodes. If one of the var_args is an array, its - * children will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. - * @deprecated Use {@link goog.dom.createDom} instead. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @return {number} Tile resolution. */ -goog.dom.$dom = goog.dom.createDom; +ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) { + goog.asserts.assert( + this.minZoom <= tileCoord[0] && tileCoord[0] <= this.maxZoom, + 'z of given tilecoord is not in allowed range (%s <= %s <= %s', + this.minZoom, tileCoord[0], this.maxZoom); + return this.resolutions_[tileCoord[0]]; +}; /** - * Creates a new element. - * @param {string} name Tag name. - * @return {!Element} The new element. + * Get the tile size for a zoom level. The type of the return value matches the + * `tileSize` or `tileSizes` that the tile grid was configured with. To always + * get an `ol.Size`, run the result through `ol.size.toSize()`. + * @param {number} z Z. + * @return {number|ol.Size} Tile size. + * @api stable */ -goog.dom.createElement = function(name) { - return document.createElement(name); +ol.tilegrid.TileGrid.prototype.getTileSize = function(z) { + if (this.tileSize_) { + return this.tileSize_; + } else { + goog.asserts.assert(this.tileSizes_, + 'tileSizes cannot be null if tileSize is null'); + goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, + 'z is not in allowed range (%s <= %s <= %s', + this.minZoom, z, this.maxZoom); + return this.tileSizes_[z]; + } }; /** - * Creates a new text node. - * @param {number|string} content Content. - * @return {!Text} The new text node. + * @param {number} z Zoom level. + * @return {ol.TileRange} Extent tile range for the specified zoom level. */ -goog.dom.createTextNode = function(content) { - return document.createTextNode(String(content)); +ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) { + if (!this.fullTileRanges_) { + return null; + } else { + goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, + 'z is not in allowed range (%s <= %s <= %s', + this.minZoom, z, this.maxZoom); + return this.fullTileRanges_[z]; + } }; /** - * Create a table. - * @param {number} rows The number of rows in the table. Must be >= 1. - * @param {number} columns The number of columns in the table. Must be >= 1. - * @param {boolean=} opt_fillWithNbsp If true, fills table entries with - * {@code goog.string.Unicode.NBSP} characters. - * @return {!Element} The created table. + * @param {number} resolution Resolution. + * @return {number} Z. */ -goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) { - // TODO(user): Return HTMLTableElement, also in prototype function. - // Callers need to be updated to e.g. not assign numbers to table.cellSpacing. - return goog.dom.createTable_(document, rows, columns, !!opt_fillWithNbsp); +ol.tilegrid.TileGrid.prototype.getZForResolution = function(resolution) { + var z = ol.array.linearFindNearest(this.resolutions_, resolution, 0); + return ol.math.clamp(z, this.minZoom, this.maxZoom); }; /** - * Create a table. - * @param {!Document} doc Document object to use to create the table. - * @param {number} rows The number of rows in the table. Must be >= 1. - * @param {number} columns The number of columns in the table. Must be >= 1. - * @param {boolean} fillWithNbsp If true, fills table entries with - * {@code goog.string.Unicode.NBSP} characters. - * @return {!HTMLTableElement} The created table. + * @param {!ol.Extent} extent Extent for this tile grid. * @private */ -goog.dom.createTable_ = function(doc, rows, columns, fillWithNbsp) { - var table = /** @type {!HTMLTableElement} */ - (doc.createElement(goog.dom.TagName.TABLE)); - var tbody = table.appendChild(doc.createElement(goog.dom.TagName.TBODY)); - for (var i = 0; i < rows; i++) { - var tr = doc.createElement(goog.dom.TagName.TR); - for (var j = 0; j < columns; j++) { - var td = doc.createElement(goog.dom.TagName.TD); - // IE <= 9 will create a text node if we set text content to the empty - // string, so we avoid doing it unless necessary. This ensures that the - // same DOM tree is returned on all browsers. - if (fillWithNbsp) { - goog.dom.setTextContent(td, goog.string.Unicode.NBSP); - } - tr.appendChild(td); - } - tbody.appendChild(tr); +ol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) { + var length = this.resolutions_.length; + var fullTileRanges = new Array(length); + for (var z = this.minZoom; z < length; ++z) { + fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z); } - return table; + this.fullTileRanges_ = fullTileRanges; }; /** - * Converts HTML markup into a node. - * @param {!goog.html.SafeHtml} html The HTML markup to convert. - * @return {!Node} The resulting node. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.tilegrid.TileGrid} Default tile grid for the passed projection. */ -goog.dom.safeHtmlToNode = function(html) { - return goog.dom.safeHtmlToNode_(document, html); +ol.tilegrid.getForProjection = function(projection) { + var tileGrid = projection.getDefaultTileGrid(); + if (!tileGrid) { + tileGrid = ol.tilegrid.createForProjection(projection); + projection.setDefaultTileGrid(tileGrid); + } + return tileGrid; }; /** - * Helper for {@code safeHtmlToNode}. - * @param {!Document} doc The document. - * @param {!goog.html.SafeHtml} html The HTML markup to convert. - * @return {!Node} The resulting node. - * @private + * @param {ol.Extent} extent Extent. + * @param {number=} opt_maxZoom Maximum zoom level (default is + * ol.DEFAULT_MAX_ZOOM). + * @param {number|ol.Size=} opt_tileSize Tile size (default uses + * ol.DEFAULT_TILE_SIZE). + * @param {ol.extent.Corner=} opt_corner Extent corner (default is + * ol.extent.Corner.TOP_LEFT). + * @return {ol.tilegrid.TileGrid} TileGrid instance. */ -goog.dom.safeHtmlToNode_ = function(doc, html) { - var tempDiv = doc.createElement(goog.dom.TagName.DIV); - if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { - goog.dom.safe.setInnerHtml(tempDiv, - goog.html.SafeHtml.concat(goog.html.SafeHtml.create('br'), html)); - tempDiv.removeChild(tempDiv.firstChild); - } else { - goog.dom.safe.setInnerHtml(tempDiv, html); - } - return goog.dom.childrenToNode_(doc, tempDiv); -}; +ol.tilegrid.createForExtent = + function(extent, opt_maxZoom, opt_tileSize, opt_corner) { + var corner = opt_corner !== undefined ? + opt_corner : ol.extent.Corner.TOP_LEFT; + var resolutions = ol.tilegrid.resolutionsFromExtent( + extent, opt_maxZoom, opt_tileSize); -/** - * Converts an HTML string into a document fragment. The string must be - * sanitized in order to avoid cross-site scripting. For example - * {@code goog.dom.htmlToDocumentFragment('<img src=x onerror=alert(0)>')} - * triggers an alert in all browsers, even if the returned document fragment - * is thrown away immediately. - * - * NOTE: This method doesn't work if your htmlString contains elements that - * can't be contained in a <div>. For example, <tr>. - * - * @param {string} htmlString The HTML string to convert. - * @return {!Node} The resulting document fragment. - */ -goog.dom.htmlToDocumentFragment = function(htmlString) { - return goog.dom.htmlToDocumentFragment_(document, htmlString); + return new ol.tilegrid.TileGrid({ + extent: extent, + origin: ol.extent.getCorner(extent, corner), + resolutions: resolutions, + tileSize: opt_tileSize + }); }; -// TODO(jakubvrana): Merge with {@code safeHtmlToNode_}. /** - * Helper for {@code htmlToDocumentFragment}. - * - * @param {!Document} doc The document. - * @param {string} htmlString The HTML string to convert. - * @return {!Node} The resulting document fragment. - * @private + * Creates a tile grid with a standard XYZ tiling scheme. + * @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options. + * @return {ol.tilegrid.TileGrid} Tile grid instance. + * @api */ -goog.dom.htmlToDocumentFragment_ = function(doc, htmlString) { - var tempDiv = doc.createElement(goog.dom.TagName.DIV); - if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) { - tempDiv.innerHTML = '<br>' + htmlString; - tempDiv.removeChild(tempDiv.firstChild); - } else { - tempDiv.innerHTML = htmlString; +ol.tilegrid.createXYZ = function(opt_options) { + var options = /** @type {olx.tilegrid.TileGridOptions} */ ({}); + goog.object.extend(options, opt_options !== undefined ? + opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({})); + if (options.extent === undefined) { + options.extent = ol.proj.get('EPSG:3857').getExtent(); } - return goog.dom.childrenToNode_(doc, tempDiv); + options.resolutions = ol.tilegrid.resolutionsFromExtent( + options.extent, options.maxZoom, options.tileSize); + delete options.maxZoom; + + return new ol.tilegrid.TileGrid(options); }; /** - * Helper for {@code htmlToDocumentFragment_}. - * @param {!Document} doc The document. - * @param {!Node} tempDiv The input node. - * @return {!Node} The resulting node. - * @private + * Create a resolutions array from an extent. A zoom factor of 2 is assumed. + * @param {ol.Extent} extent Extent. + * @param {number=} opt_maxZoom Maximum zoom level (default is + * ol.DEFAULT_MAX_ZOOM). + * @param {number|ol.Size=} opt_tileSize Tile size (default uses + * ol.DEFAULT_TILE_SIZE). + * @return {!Array.<number>} Resolutions array. */ -goog.dom.childrenToNode_ = function(doc, tempDiv) { - if (tempDiv.childNodes.length == 1) { - return tempDiv.removeChild(tempDiv.firstChild); - } else { - var fragment = doc.createDocumentFragment(); - while (tempDiv.firstChild) { - fragment.appendChild(tempDiv.firstChild); - } - return fragment; +ol.tilegrid.resolutionsFromExtent = + function(extent, opt_maxZoom, opt_tileSize) { + var maxZoom = opt_maxZoom !== undefined ? + opt_maxZoom : ol.DEFAULT_MAX_ZOOM; + + var height = ol.extent.getHeight(extent); + var width = ol.extent.getWidth(extent); + + var tileSize = ol.size.toSize(opt_tileSize !== undefined ? + opt_tileSize : ol.DEFAULT_TILE_SIZE); + var maxResolution = Math.max( + width / tileSize[0], height / tileSize[1]); + + var length = maxZoom + 1; + var resolutions = new Array(length); + for (var z = 0; z < length; ++z) { + resolutions[z] = maxResolution / Math.pow(2, z); } + return resolutions; }; /** - * Returns true if the browser is in "CSS1-compatible" (standards-compliant) - * mode, false otherwise. - * @return {boolean} True if in CSS1-compatible mode. + * @param {ol.proj.ProjectionLike} projection Projection. + * @param {number=} opt_maxZoom Maximum zoom level (default is + * ol.DEFAULT_MAX_ZOOM). + * @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE). + * @param {ol.extent.Corner=} opt_corner Extent corner (default is + * ol.extent.Corner.BOTTOM_LEFT). + * @return {ol.tilegrid.TileGrid} TileGrid instance. */ -goog.dom.isCss1CompatMode = function() { - return goog.dom.isCss1CompatMode_(document); +ol.tilegrid.createForProjection = + function(projection, opt_maxZoom, opt_tileSize, opt_corner) { + var extent = ol.tilegrid.extentFromProjection(projection); + return ol.tilegrid.createForExtent( + extent, opt_maxZoom, opt_tileSize, opt_corner); }; /** - * Returns true if the browser is in "CSS1-compatible" (standards-compliant) - * mode, false otherwise. - * @param {!Document} doc The document to check. - * @return {boolean} True if in CSS1-compatible mode. - * @private + * Generate a tile grid extent from a projection. If the projection has an + * extent, it is used. If not, a global extent is assumed. + * @param {ol.proj.ProjectionLike} projection Projection. + * @return {ol.Extent} Extent. */ -goog.dom.isCss1CompatMode_ = function(doc) { - if (goog.dom.COMPAT_MODE_KNOWN_) { - return goog.dom.ASSUME_STANDARDS_MODE; +ol.tilegrid.extentFromProjection = function(projection) { + projection = ol.proj.get(projection); + var extent = projection.getExtent(); + if (!extent) { + var half = 180 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] / + projection.getMetersPerUnit(); + extent = ol.extent.createOrUpdate(-half, -half, half, half); } - - return doc.compatMode == 'CSS1Compat'; + return extent; }; +goog.exportProperty(ol.tilegrid.TileGrid.prototype, 'getTileRangeForExtentAndZ', + ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ); + + +goog.provide('ol.source.Tile'); +goog.provide('ol.source.TileEvent'); +goog.provide('ol.source.TileOptions'); + +goog.require('goog.asserts'); +goog.require('goog.events.Event'); +goog.require('ol'); +goog.require('ol.Attribution'); +goog.require('ol.Extent'); +goog.require('ol.TileCache'); +goog.require('ol.TileRange'); +goog.require('ol.TileState'); +goog.require('ol.proj'); +goog.require('ol.size'); +goog.require('ol.source.Source'); +goog.require('ol.tilecoord'); +goog.require('ol.tilegrid.TileGrid'); /** - * Determines if the given node can contain children, intended to be used for - * HTML generation. - * - * IE natively supports node.canHaveChildren but has inconsistent behavior. - * Prior to IE8 the base tag allows children and in IE9 all nodes return true - * for canHaveChildren. - * - * In practice all non-IE browsers allow you to add children to any node, but - * the behavior is inconsistent: - * - * <pre> - * var a = document.createElement(goog.dom.TagName.BR); - * a.appendChild(document.createTextNode('foo')); - * a.appendChild(document.createTextNode('bar')); - * console.log(a.childNodes.length); // 2 - * console.log(a.innerHTML); // Chrome: "", IE9: "foobar", FF3.5: "foobar" - * </pre> - * - * For more information, see: - * http://dev.w3.org/html5/markup/syntax.html#syntax-elements - * - * TODO(user): Rename shouldAllowChildren() ? - * - * @param {Node} node The node to check. - * @return {boolean} Whether the node can contain children. + * @typedef {{attributions: (Array.<ol.Attribution>|undefined), + * cacheSize: (number|undefined), + * extent: (ol.Extent|undefined), + * logo: (string|olx.LogoOptions|undefined), + * opaque: (boolean|undefined), + * tilePixelRatio: (number|undefined), + * projection: ol.proj.ProjectionLike, + * state: (ol.source.State|undefined), + * tileGrid: (ol.tilegrid.TileGrid|undefined), + * wrapX: (boolean|undefined)}} */ -goog.dom.canHaveChildren = function(node) { - if (node.nodeType != goog.dom.NodeType.ELEMENT) { - return false; - } - switch (/** @type {!Element} */ (node).tagName) { - case goog.dom.TagName.APPLET: - case goog.dom.TagName.AREA: - case goog.dom.TagName.BASE: - case goog.dom.TagName.BR: - case goog.dom.TagName.COL: - case goog.dom.TagName.COMMAND: - case goog.dom.TagName.EMBED: - case goog.dom.TagName.FRAME: - case goog.dom.TagName.HR: - case goog.dom.TagName.IMG: - case goog.dom.TagName.INPUT: - case goog.dom.TagName.IFRAME: - case goog.dom.TagName.ISINDEX: - case goog.dom.TagName.KEYGEN: - case goog.dom.TagName.LINK: - case goog.dom.TagName.NOFRAMES: - case goog.dom.TagName.NOSCRIPT: - case goog.dom.TagName.META: - case goog.dom.TagName.OBJECT: - case goog.dom.TagName.PARAM: - case goog.dom.TagName.SCRIPT: - case goog.dom.TagName.SOURCE: - case goog.dom.TagName.STYLE: - case goog.dom.TagName.TRACK: - case goog.dom.TagName.WBR: - return false; - } - return true; -}; +ol.source.TileOptions; + /** - * Appends a child to a node. - * @param {Node} parent Parent. - * @param {Node} child Child. + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for sources providing images divided into a tile grid. + * + * @constructor + * @extends {ol.source.Source} + * @param {ol.source.TileOptions} options Tile source options. + * @api */ -goog.dom.appendChild = function(parent, child) { - parent.appendChild(child); +ol.source.Tile = function(options) { + + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + logo: options.logo, + projection: options.projection, + state: options.state, + wrapX: options.wrapX + }); + + /** + * @private + * @type {boolean} + */ + this.opaque_ = options.opaque !== undefined ? options.opaque : false; + + /** + * @private + * @type {number} + */ + this.tilePixelRatio_ = options.tilePixelRatio !== undefined ? + options.tilePixelRatio : 1; + + /** + * @protected + * @type {ol.tilegrid.TileGrid} + */ + this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null; + + /** + * @protected + * @type {ol.TileCache} + */ + this.tileCache = new ol.TileCache(options.cacheSize); + + /** + * @protected + * @type {ol.Size} + */ + this.tmpSize = [0, 0]; + }; +goog.inherits(ol.source.Tile, ol.source.Source); /** - * Appends a node with text or other nodes. - * @param {!Node} parent The node to append nodes to. - * @param {...goog.dom.Appendable} var_args The things to append to the node. - * If this is a Node it is appended as is. - * If this is a string then a text node is appended. - * If this is an array like object then fields 0 to length - 1 are appended. + * @return {boolean} Can expire cache. */ -goog.dom.append = function(parent, var_args) { - goog.dom.append_(goog.dom.getOwnerDocument(parent), parent, arguments, 1); +ol.source.Tile.prototype.canExpireCache = function() { + return this.tileCache.canExpireCache(); }; /** - * Removes all the child nodes on a DOM node. - * @param {Node} node Node to remove children from. + * @param {ol.proj.Projection} projection Projection. + * @param {Object.<string, ol.TileRange>} usedTiles Used tiles. */ -goog.dom.removeChildren = function(node) { - // Note: Iterations over live collections can be slow, this is the fastest - // we could find. The double parenthesis are used to prevent JsCompiler and - // strict warnings. - var child; - while ((child = node.firstChild)) { - node.removeChild(child); +ol.source.Tile.prototype.expireCache = function(projection, usedTiles) { + var tileCache = this.getTileCacheForProjection(projection); + if (tileCache) { + tileCache.expireCache(usedTiles); } }; /** - * Inserts a new node before an existing reference node (i.e. as the previous - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert before. + * @param {ol.proj.Projection} projection Projection. + * @param {number} z Zoom level. + * @param {ol.TileRange} tileRange Tile range. + * @param {function(ol.Tile):(boolean|undefined)} callback Called with each + * loaded tile. If the callback returns `false`, the tile will not be + * considered loaded. + * @return {boolean} The tile range is fully covered with loaded tiles. */ -goog.dom.insertSiblingBefore = function(newNode, refNode) { - if (refNode.parentNode) { - refNode.parentNode.insertBefore(newNode, refNode); +ol.source.Tile.prototype.forEachLoadedTile = + function(projection, z, tileRange, callback) { + var tileCache = this.getTileCacheForProjection(projection); + if (!tileCache) { + return false; + } + + var covered = true; + var tile, tileCoordKey, loaded; + for (var x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (var y = tileRange.minY; y <= tileRange.maxY; ++y) { + tileCoordKey = this.getKeyZXY(z, x, y); + loaded = false; + if (tileCache.containsKey(tileCoordKey)) { + tile = /** @type {!ol.Tile} */ (tileCache.get(tileCoordKey)); + loaded = tile.getState() === ol.TileState.LOADED; + if (loaded) { + loaded = (callback(tile) !== false); + } + } + if (!loaded) { + covered = false; + } + } } + return covered; }; /** - * Inserts a new node after an existing reference node (i.e. as the next - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert after. + * @return {number} Gutter. */ -goog.dom.insertSiblingAfter = function(newNode, refNode) { - if (refNode.parentNode) { - refNode.parentNode.insertBefore(newNode, refNode.nextSibling); - } +ol.source.Tile.prototype.getGutter = function() { + return 0; }; /** - * Insert a child at a given index. If index is larger than the number of child - * nodes that the parent currently has, the node is inserted as the last child - * node. - * @param {Element} parent The element into which to insert the child. - * @param {Node} child The element to insert. - * @param {number} index The index at which to insert the new child node. Must - * not be negative. + * Return the "parameters" key, a string composed of the source's + * parameters/dimensions. + * @return {string} The parameters key. + * @protected */ -goog.dom.insertChildAt = function(parent, child, index) { - // Note that if the second argument is null, insertBefore - // will append the child at the end of the list of children. - parent.insertBefore(child, parent.childNodes[index] || null); +ol.source.Tile.prototype.getKeyParams = function() { + return ''; }; /** - * Removes a node from its parent. - * @param {Node} node The node to remove. - * @return {Node} The node removed if removed; else, null. + * @param {number} z Z. + * @param {number} x X. + * @param {number} y Y. + * @return {string} Key. + * @protected */ -goog.dom.removeNode = function(node) { - return node && node.parentNode ? node.parentNode.removeChild(node) : null; -}; +ol.source.Tile.prototype.getKeyZXY = ol.tilecoord.getKeyZXY; /** - * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no - * parent. - * @param {Node} newNode Node to insert. - * @param {Node} oldNode Node to replace. + * @return {boolean} Opaque. */ -goog.dom.replaceNode = function(newNode, oldNode) { - var parent = oldNode.parentNode; - if (parent) { - parent.replaceChild(newNode, oldNode); - } +ol.source.Tile.prototype.getOpaque = function() { + return this.opaque_; }; /** - * Flattens an element. That is, removes it and replace it with its children. - * Does nothing if the element is not in the document. - * @param {Element} element The element to flatten. - * @return {Element|undefined} The original element, detached from the document - * tree, sans children; or undefined, if the element was not in the document - * to begin with. + * @inheritDoc */ -goog.dom.flattenElement = function(element) { - var child, parent = element.parentNode; - if (parent && parent.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT) { - // Use IE DOM method (supported by Opera too) if available - if (element.removeNode) { - return /** @type {Element} */ (element.removeNode(false)); - } else { - // Move all children of the original node up one level. - while ((child = element.firstChild)) { - parent.insertBefore(child, element); - } - - // Detach the original element. - return /** @type {Element} */ (goog.dom.removeNode(element)); - } - } +ol.source.Tile.prototype.getResolutions = function() { + return this.tileGrid.getResolutions(); }; /** - * Returns an array containing just the element children of the given element. - * @param {Element} element The element whose element children we want. - * @return {!(Array|NodeList)} An array or array-like list of just the element - * children of the given element. + * @param {number} z Tile coordinate z. + * @param {number} x Tile coordinate x. + * @param {number} y Tile coordinate y. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {!ol.Tile} Tile. */ -goog.dom.getChildren = function(element) { - // We check if the children attribute is supported for child elements - // since IE8 misuses the attribute by also including comments. - if (goog.dom.BrowserFeature.CAN_USE_CHILDREN_ATTRIBUTE && - element.children != undefined) { - return element.children; - } - // Fall back to manually filtering the element's child nodes. - return goog.array.filter(element.childNodes, function(node) { - return node.nodeType == goog.dom.NodeType.ELEMENT; - }); -}; +ol.source.Tile.prototype.getTile = goog.abstractMethod; /** - * Returns the first child node that is an element. - * @param {Node} node The node to get the first child element of. - * @return {Element} The first child node of {@code node} that is an element. + * Return the tile grid of the tile source. + * @return {ol.tilegrid.TileGrid} Tile grid. + * @api stable */ -goog.dom.getFirstElementChild = function(node) { - if (goog.isDef(node.firstElementChild)) { - return /** @type {!Element} */(node).firstElementChild; - } - return goog.dom.getNextElementNode_(node.firstChild, true); +ol.source.Tile.prototype.getTileGrid = function() { + return this.tileGrid; }; /** - * Returns the last child node that is an element. - * @param {Node} node The node to get the last child element of. - * @return {Element} The last child node of {@code node} that is an element. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.tilegrid.TileGrid} Tile grid. */ -goog.dom.getLastElementChild = function(node) { - if (goog.isDef(node.lastElementChild)) { - return /** @type {!Element} */(node).lastElementChild; +ol.source.Tile.prototype.getTileGridForProjection = function(projection) { + if (!this.tileGrid) { + return ol.tilegrid.getForProjection(projection); + } else { + return this.tileGrid; } - return goog.dom.getNextElementNode_(node.lastChild, false); }; /** - * Returns the first next sibling that is an element. - * @param {Node} node The node to get the next sibling element of. - * @return {Element} The next sibling of {@code node} that is an element. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.TileCache} Tile cache. + * @protected */ -goog.dom.getNextElementSibling = function(node) { - if (goog.isDef(node.nextElementSibling)) { - return /** @type {!Element} */(node).nextElementSibling; +ol.source.Tile.prototype.getTileCacheForProjection = function(projection) { + var thisProj = this.getProjection(); + if (thisProj && !ol.proj.equivalent(thisProj, projection)) { + return null; + } else { + return this.tileCache; } - return goog.dom.getNextElementNode_(node.nextSibling, true); }; /** - * Returns the first previous sibling that is an element. - * @param {Node} node The node to get the previous sibling element of. - * @return {Element} The first previous sibling of {@code node} that is - * an element. + * @return {number} Tile pixel ratio. */ -goog.dom.getPreviousElementSibling = function(node) { - if (goog.isDef(node.previousElementSibling)) { - return /** @type {!Element} */(node).previousElementSibling; - } - return goog.dom.getNextElementNode_(node.previousSibling, false); +ol.source.Tile.prototype.getTilePixelRatio = function() { + return this.tilePixelRatio_; }; /** - * Returns the first node that is an element in the specified direction, - * starting with {@code node}. - * @param {Node} node The node to get the next element from. - * @param {boolean} forward Whether to look forwards or backwards. - * @return {Element} The first element. - * @private + * @param {number} z Z. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.Size} Tile size. */ -goog.dom.getNextElementNode_ = function(node, forward) { - while (node && node.nodeType != goog.dom.NodeType.ELEMENT) { - node = forward ? node.nextSibling : node.previousSibling; - } - - return /** @type {Element} */ (node); +ol.source.Tile.prototype.getTilePixelSize = + function(z, pixelRatio, projection) { + var tileGrid = this.getTileGridForProjection(projection); + return ol.size.scale(ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize), + this.tilePixelRatio_, this.tmpSize); }; /** - * Returns the next node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The next node in the DOM tree, or null if this was the last - * node. + * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate + * is outside the resolution and extent range of the tile grid, `null` will be + * returned. + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.proj.Projection=} opt_projection Projection. + * @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or + * null if no tile URL should be created for the passed `tileCoord`. */ -goog.dom.getNextNode = function(node) { - if (!node) { - return null; +ol.source.Tile.prototype.getTileCoordForTileUrlFunction = + function(tileCoord, opt_projection) { + var projection = opt_projection !== undefined ? + opt_projection : this.getProjection(); + var tileGrid = this.getTileGridForProjection(projection); + goog.asserts.assert(tileGrid, 'tile grid needed'); + if (this.getWrapX() && projection.isGlobal()) { + tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection); } + return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null; +}; - if (node.firstChild) { - return node.firstChild; - } - while (node && !node.nextSibling) { - node = node.parentNode; - } +/** + * Marks a tile coord as being used, without triggering a load. + * @param {number} z Tile coordinate z. + * @param {number} x Tile coordinate x. + * @param {number} y Tile coordinate y. + * @param {ol.proj.Projection} projection Projection. + */ +ol.source.Tile.prototype.useTile = ol.nullFunction; - return node ? node.nextSibling : null; -}; /** - * Returns the previous node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The previous node in the DOM tree, or null if this was the - * first node. + * @classdesc + * Events emitted by {@link ol.source.Tile} instances are instances of this + * type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.source.TileEvent} + * @param {string} type Type. + * @param {ol.Tile} tile The tile. */ -goog.dom.getPreviousNode = function(node) { - if (!node) { - return null; - } +ol.source.TileEvent = function(type, tile) { - if (!node.previousSibling) { - return node.parentNode; - } + goog.base(this, type); - node = node.previousSibling; - while (node && node.lastChild) { - node = node.lastChild; - } + /** + * The tile related to the event. + * @type {ol.Tile} + * @api + */ + this.tile = tile; - return node; }; +goog.inherits(ol.source.TileEvent, goog.events.Event); /** - * Whether the object looks like a DOM node. - * @param {?} obj The object being tested for node likeness. - * @return {boolean} Whether the object looks like a DOM node. + * @enum {string} */ -goog.dom.isNodeLike = function(obj) { - return goog.isObject(obj) && obj.nodeType > 0; -}; +ol.source.TileEventType = { + /** + * Triggered when a tile starts loading. + * @event ol.source.TileEvent#tileloadstart + * @api stable + */ + TILELOADSTART: 'tileloadstart', -/** - * Whether the object looks like an Element. - * @param {?} obj The object being tested for Element likeness. - * @return {boolean} Whether the object looks like an Element. - */ -goog.dom.isElement = function(obj) { - return goog.isObject(obj) && obj.nodeType == goog.dom.NodeType.ELEMENT; -}; + /** + * Triggered when a tile finishes loading. + * @event ol.source.TileEvent#tileloadend + * @api stable + */ + TILELOADEND: 'tileloadend', + /** + * Triggered if tile loading results in an error. + * @event ol.source.TileEvent#tileloaderror + * @api stable + */ + TILELOADERROR: 'tileloaderror' -/** - * Returns true if the specified value is a Window object. This includes the - * global window for HTML pages, and iframe windows. - * @param {?} obj Variable to test. - * @return {boolean} Whether the variable is a window. - */ -goog.dom.isWindow = function(obj) { - return goog.isObject(obj) && obj['window'] == obj; }; +goog.provide('ol.source.UrlTile'); -/** - * Returns an element's parent, if it's an Element. - * @param {Element} element The DOM element. - * @return {Element} The parent, or null if not an Element. - */ -goog.dom.getParentElement = function(element) { - var parent; - if (goog.dom.BrowserFeature.CAN_USE_PARENT_ELEMENT_PROPERTY) { - var isIe9 = goog.userAgent.IE && - goog.userAgent.isVersionOrHigher('9') && - !goog.userAgent.isVersionOrHigher('10'); - // SVG elements in IE9 can't use the parentElement property. - // goog.global['SVGElement'] is not defined in IE9 quirks mode. - if (!(isIe9 && goog.global['SVGElement'] && - element instanceof goog.global['SVGElement'])) { - parent = element.parentElement; - if (parent) { - return parent; - } - } - } - parent = element.parentNode; - return goog.dom.isElement(parent) ? /** @type {!Element} */ (parent) : null; -}; +goog.require('goog.events'); +goog.require('ol.TileLoadFunctionType'); +goog.require('ol.TileState'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.TileUrlFunctionType'); +goog.require('ol.proj'); +goog.require('ol.source.Tile'); +goog.require('ol.source.TileEvent'); /** - * Whether a node contains another node. - * @param {Node} parent The node that should contain the other node. - * @param {Node} descendant The node to test presence of. - * @return {boolean} Whether the parent node contains the descendent node. + * @typedef {{attributions: (Array.<ol.Attribution>|undefined), + * extent: (ol.Extent|undefined), + * logo: (string|olx.LogoOptions|undefined), + * opaque: (boolean|undefined), + * projection: ol.proj.ProjectionLike, + * state: (ol.source.State|string|undefined), + * tileGrid: (ol.tilegrid.TileGrid|undefined), + * tileLoadFunction: ol.TileLoadFunctionType, + * tilePixelRatio: (number|undefined), + * tileUrlFunction: (ol.TileUrlFunctionType|undefined), + * url: (string|undefined), + * urls: (Array.<string>|undefined), + * wrapX: (boolean|undefined)}} */ -goog.dom.contains = function(parent, descendant) { - // We use browser specific methods for this if available since it is faster - // that way. - - // IE DOM - if (parent.contains && descendant.nodeType == goog.dom.NodeType.ELEMENT) { - return parent == descendant || parent.contains(descendant); - } - - // W3C DOM Level 3 - if (typeof parent.compareDocumentPosition != 'undefined') { - return parent == descendant || - Boolean(parent.compareDocumentPosition(descendant) & 16); - } +ol.source.UrlTileOptions; - // W3C DOM Level 1 - while (descendant && parent != descendant) { - descendant = descendant.parentNode; - } - return descendant == parent; -}; /** - * Compares the document order of two nodes, returning 0 if they are the same - * node, a negative number if node1 is before node2, and a positive number if - * node2 is before node1. Note that we compare the order the tags appear in the - * document so in the tree <b><i>text</i></b> the B node is considered to be - * before the I node. + * @classdesc + * Base class for sources providing tiles divided into a tile grid over http. * - * @param {Node} node1 The first node to compare. - * @param {Node} node2 The second node to compare. - * @return {number} 0 if the nodes are the same node, a negative number if node1 - * is before node2, and a positive number if node2 is before node1. + * @constructor + * @fires ol.source.TileEvent + * @extends {ol.source.Tile} + * @param {ol.source.UrlTileOptions} options Image tile options. */ -goog.dom.compareNodeOrder = function(node1, node2) { - // Fall out quickly for equality. - if (node1 == node2) { - return 0; - } - - // Use compareDocumentPosition where available - if (node1.compareDocumentPosition) { - // 4 is the bitmask for FOLLOWS. - return node1.compareDocumentPosition(node2) & 2 ? 1 : -1; - } - - // Special case for document nodes on IE 7 and 8. - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { - if (node1.nodeType == goog.dom.NodeType.DOCUMENT) { - return -1; - } - if (node2.nodeType == goog.dom.NodeType.DOCUMENT) { - return 1; - } - } - - // Process in IE using sourceIndex - we check to see if the first node has - // a source index or if its parent has one. - if ('sourceIndex' in node1 || - (node1.parentNode && 'sourceIndex' in node1.parentNode)) { - var isElement1 = node1.nodeType == goog.dom.NodeType.ELEMENT; - var isElement2 = node2.nodeType == goog.dom.NodeType.ELEMENT; - - if (isElement1 && isElement2) { - return node1.sourceIndex - node2.sourceIndex; - } else { - var parent1 = node1.parentNode; - var parent2 = node2.parentNode; +ol.source.UrlTile = function(options) { - if (parent1 == parent2) { - return goog.dom.compareSiblingOrder_(node1, node2); - } + goog.base(this, { + attributions: options.attributions, + cacheSize: options.cacheSize, + extent: options.extent, + logo: options.logo, + opaque: options.opaque, + projection: options.projection, + state: options.state ? + /** @type {ol.source.State} */ (options.state) : undefined, + tileGrid: options.tileGrid, + tilePixelRatio: options.tilePixelRatio, + wrapX: options.wrapX + }); - if (!isElement1 && goog.dom.contains(parent1, node2)) { - return -1 * goog.dom.compareParentsDescendantNodeIe_(node1, node2); - } + /** + * @protected + * @type {ol.TileLoadFunctionType} + */ + this.tileLoadFunction = options.tileLoadFunction; + /** + * @protected + * @type {ol.TileUrlFunctionType} + */ + this.tileUrlFunction = options.tileUrlFunction ? + options.tileUrlFunction : + ol.TileUrlFunction.nullTileUrlFunction; - if (!isElement2 && goog.dom.contains(parent2, node1)) { - return goog.dom.compareParentsDescendantNodeIe_(node2, node1); - } + /** + * @protected + * @type {!Array.<string>|null} + */ + this.urls = null; - return (isElement1 ? node1.sourceIndex : parent1.sourceIndex) - - (isElement2 ? node2.sourceIndex : parent2.sourceIndex); + if (options.urls) { + if (options.tileUrlFunction) { + this.urls = options.urls; + } else { + this.setUrls(options.urls); } + } else if (options.url) { + this.setUrl(options.url); + } + if (options.tileUrlFunction) { + this.setTileUrlFunction(options.tileUrlFunction); } - // For Safari, we compare ranges. - var doc = goog.dom.getOwnerDocument(node1); - - var range1, range2; - range1 = doc.createRange(); - range1.selectNode(node1); - range1.collapse(true); - - range2 = doc.createRange(); - range2.selectNode(node2); - range2.collapse(true); - - return range1.compareBoundaryPoints(goog.global['Range'].START_TO_END, - range2); }; +goog.inherits(ol.source.UrlTile, ol.source.Tile); /** - * Utility function to compare the position of two nodes, when - * {@code textNode}'s parent is an ancestor of {@code node}. If this entry - * condition is not met, this function will attempt to reference a null object. - * @param {!Node} textNode The textNode to compare. - * @param {Node} node The node to compare. - * @return {number} -1 if node is before textNode, +1 otherwise. - * @private + * Return the tile load function of the source. + * @return {ol.TileLoadFunctionType} TileLoadFunction + * @api */ -goog.dom.compareParentsDescendantNodeIe_ = function(textNode, node) { - var parent = textNode.parentNode; - if (parent == node) { - // If textNode is a child of node, then node comes first. - return -1; - } - var sibling = node; - while (sibling.parentNode != parent) { - sibling = sibling.parentNode; - } - return goog.dom.compareSiblingOrder_(sibling, textNode); +ol.source.UrlTile.prototype.getTileLoadFunction = function() { + return this.tileLoadFunction; }; /** - * Utility function to compare the position of two nodes known to be non-equal - * siblings. - * @param {Node} node1 The first node to compare. - * @param {!Node} node2 The second node to compare. - * @return {number} -1 if node1 is before node2, +1 otherwise. - * @private + * Return the tile URL function of the source. + * @return {ol.TileUrlFunctionType} TileUrlFunction + * @api */ -goog.dom.compareSiblingOrder_ = function(node1, node2) { - var s = node2; - while ((s = s.previousSibling)) { - if (s == node1) { - // We just found node1 before node2. - return -1; - } - } - - // Since we didn't find it, node1 must be after node2. - return 1; +ol.source.UrlTile.prototype.getTileUrlFunction = function() { + return this.tileUrlFunction; }; /** - * Find the deepest common ancestor of the given nodes. - * @param {...Node} var_args The nodes to find a common ancestor of. - * @return {Node} The common ancestor of the nodes, or null if there is none. - * null will only be returned if two or more of the nodes are from different - * documents. + * Return the URLs used for this source. + * When a tileUrlFunction is used instead of url or urls, + * null will be returned. + * @return {!Array.<string>|null} URLs. + * @api */ -goog.dom.findCommonAncestor = function(var_args) { - var i, count = arguments.length; - if (!count) { - return null; - } else if (count == 1) { - return arguments[0]; - } +ol.source.UrlTile.prototype.getUrls = function() { + return this.urls; +}; - var paths = []; - var minLength = Infinity; - for (i = 0; i < count; i++) { - // Compute the list of ancestors. - var ancestors = []; - var node = arguments[i]; - while (node) { - ancestors.unshift(node); - node = node.parentNode; - } - // Save the list for comparison. - paths.push(ancestors); - minLength = Math.min(minLength, ancestors.length); - } - var output = null; - for (i = 0; i < minLength; i++) { - var first = paths[0][i]; - for (var j = 1; j < count; j++) { - if (first != paths[j][i]) { - return output; - } - } - output = first; +/** + * Handle tile change events. + * @param {goog.events.Event} event Event. + * @protected + */ +ol.source.UrlTile.prototype.handleTileChange = function(event) { + var tile = /** @type {ol.Tile} */ (event.target); + switch (tile.getState()) { + case ol.TileState.LOADING: + this.dispatchEvent( + new ol.source.TileEvent(ol.source.TileEventType.TILELOADSTART, tile)); + break; + case ol.TileState.LOADED: + this.dispatchEvent( + new ol.source.TileEvent(ol.source.TileEventType.TILELOADEND, tile)); + break; + case ol.TileState.ERROR: + this.dispatchEvent( + new ol.source.TileEvent(ol.source.TileEventType.TILELOADERROR, tile)); + break; } - return output; }; /** - * Returns the owner document for a node. - * @param {Node|Window} node The node to get the document for. - * @return {!Document} The document owning the node. + * Set the tile load function of the source. + * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. + * @api */ -goog.dom.getOwnerDocument = function(node) { - // TODO(nnaze): Update param signature to be non-nullable. - goog.asserts.assert(node, 'Node cannot be null or undefined.'); - return /** @type {!Document} */ ( - node.nodeType == goog.dom.NodeType.DOCUMENT ? node : - node.ownerDocument || node.document); +ol.source.UrlTile.prototype.setTileLoadFunction = function(tileLoadFunction) { + this.tileCache.clear(); + this.tileLoadFunction = tileLoadFunction; + this.changed(); }; /** - * Cross-browser function for getting the document element of a frame or iframe. - * @param {Element} frame Frame element. - * @return {!Document} The frame content document. + * Set the tile URL function of the source. + * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function. + * @api */ -goog.dom.getFrameContentDocument = function(frame) { - var doc = frame.contentDocument || frame.contentWindow.document; - return doc; +ol.source.UrlTile.prototype.setTileUrlFunction = function(tileUrlFunction) { + // FIXME It should be possible to be more intelligent and avoid clearing the + // FIXME cache. The tile URL function would need to be incorporated into the + // FIXME cache key somehow. + this.tileCache.clear(); + this.tileUrlFunction = tileUrlFunction; + this.changed(); }; /** - * Cross-browser function for getting the window of a frame or iframe. - * @param {Element} frame Frame element. - * @return {Window} The window associated with the given frame. + * Set the URL to use for requests. + * @param {string} url URL. + * @api stable */ -goog.dom.getFrameContentWindow = function(frame) { - return frame.contentWindow || - goog.dom.getWindow(goog.dom.getFrameContentDocument(frame)); +ol.source.UrlTile.prototype.setUrl = function(url) { + this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( + ol.TileUrlFunction.expandUrl(url), this.tileGrid)); + this.urls = [url]; }; /** - * Sets the text content of a node, with cross-browser support. - * @param {Node} node The node to change the text content of. - * @param {string|number} text The value that should replace the node's content. + * Set the URLs to use for requests. + * @param {Array.<string>} urls URLs. + * @api stable */ -goog.dom.setTextContent = function(node, text) { - goog.asserts.assert(node != null, - 'goog.dom.setTextContent expects a non-null value for node'); - - if ('textContent' in node) { - node.textContent = text; - } else if (node.nodeType == goog.dom.NodeType.TEXT) { - node.data = text; - } else if (node.firstChild && - node.firstChild.nodeType == goog.dom.NodeType.TEXT) { - // If the first child is a text node we just change its data and remove the - // rest of the children. - while (node.lastChild != node.firstChild) { - node.removeChild(node.lastChild); - } - node.firstChild.data = text; - } else { - goog.dom.removeChildren(node); - var doc = goog.dom.getOwnerDocument(node); - node.appendChild(doc.createTextNode(String(text))); - } +ol.source.UrlTile.prototype.setUrls = function(urls) { + this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( + urls, this.tileGrid)); + this.urls = urls; }; /** - * Gets the outerHTML of a node, which islike innerHTML, except that it - * actually contains the HTML of the node itself. - * @param {Element} element The element to get the HTML of. - * @return {string} The outerHTML of the given element. + * @inheritDoc */ -goog.dom.getOuterHtml = function(element) { - // IE, Opera and WebKit all have outerHTML. - if ('outerHTML' in element) { - return element.outerHTML; - } else { - var doc = goog.dom.getOwnerDocument(element); - var div = doc.createElement(goog.dom.TagName.DIV); - div.appendChild(element.cloneNode(true)); - return div.innerHTML; +ol.source.UrlTile.prototype.useTile = function(z, x, y) { + var tileCoordKey = this.getKeyZXY(z, x, y); + if (this.tileCache.containsKey(tileCoordKey)) { + this.tileCache.get(tileCoordKey); } }; +goog.provide('ol.source.TileImage'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol.ImageTile'); +goog.require('ol.TileCache'); +goog.require('ol.TileState'); +goog.require('ol.proj'); +goog.require('ol.reproj.Tile'); +goog.require('ol.source.UrlTile'); + + /** - * Finds the first descendant node that matches the filter function, using - * a depth first search. This function offers the most general purpose way - * of finding a matching element. You may also wish to consider - * {@code goog.dom.query} which can express many matching criteria using - * CSS selector expressions. These expressions often result in a more - * compact representation of the desired result. - * @see goog.dom.query + * @classdesc + * Base class for sources providing images divided into a tile grid. * - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {Node|undefined} The found node or undefined if none is found. + * @constructor + * @fires ol.source.TileEvent + * @extends {ol.source.UrlTile} + * @param {olx.source.TileImageOptions} options Image tile options. + * @api */ -goog.dom.findNode = function(root, p) { - var rv = []; - var found = goog.dom.findNodes_(root, p, rv, true); - return found ? rv[0] : undefined; -}; +ol.source.TileImage = function(options) { + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + logo: options.logo, + opaque: options.opaque, + projection: options.projection, + state: options.state !== undefined ? + /** @type {ol.source.State} */ (options.state) : undefined, + tileGrid: options.tileGrid, + tileLoadFunction: options.tileLoadFunction ? + options.tileLoadFunction : ol.source.TileImage.defaultTileLoadFunction, + tilePixelRatio: options.tilePixelRatio, + tileUrlFunction: options.tileUrlFunction, + url: options.url, + urls: options.urls, + wrapX: options.wrapX + }); -/** - * Finds all the descendant nodes that match the filter function, using a - * a depth first search. This function offers the most general-purpose way - * of finding a set of matching elements. You may also wish to consider - * {@code goog.dom.query} which can express many matching criteria using - * CSS selector expressions. These expressions often result in a more - * compact representation of the desired result. + /** + * @protected + * @type {?string} + */ + this.crossOrigin = + options.crossOrigin !== undefined ? options.crossOrigin : null; - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {!Array<!Node>} The found nodes or an empty array if none are found. - */ -goog.dom.findNodes = function(root, p) { - var rv = []; - goog.dom.findNodes_(root, p, rv, false); - return rv; -}; + /** + * @protected + * @type {function(new: ol.ImageTile, ol.TileCoord, ol.TileState, string, + * ?string, ol.TileLoadFunctionType)} + */ + this.tileClass = options.tileClass !== undefined ? + options.tileClass : ol.ImageTile; + /** + * @protected + * @type {Object.<string, ol.TileCache>} + */ + this.tileCacheForProjection = {}; -/** - * Finds the first or all the descendant nodes that match the filter function, - * using a depth first search. - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @param {!Array<!Node>} rv The found nodes are added to this array. - * @param {boolean} findOne If true we exit after the first found node. - * @return {boolean} Whether the search is complete or not. True in case findOne - * is true and the node is found. False otherwise. - * @private - */ -goog.dom.findNodes_ = function(root, p, rv, findOne) { - if (root != null) { - var child = root.firstChild; - while (child) { - if (p(child)) { - rv.push(child); - if (findOne) { - return true; - } - } - if (goog.dom.findNodes_(child, p, rv, findOne)) { - return true; - } - child = child.nextSibling; - } - } - return false; -}; + /** + * @protected + * @type {Object.<string, ol.tilegrid.TileGrid>} + */ + this.tileGridForProjection = {}; + /** + * @private + * @type {number|undefined} + */ + this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold; -/** - * Map of tags whose content to ignore when calculating text length. - * @private {!Object<string, number>} - * @const - */ -goog.dom.TAGS_TO_IGNORE_ = { - 'SCRIPT': 1, - 'STYLE': 1, - 'HEAD': 1, - 'IFRAME': 1, - 'OBJECT': 1 + /** + * @private + * @type {boolean} + */ + this.renderReprojectionEdges_ = false; }; +goog.inherits(ol.source.TileImage, ol.source.UrlTile); /** - * Map of tags which have predefined values with regard to whitespace. - * @private {!Object<string, string>} - * @const + * @inheritDoc */ -goog.dom.PREDEFINED_TAG_VALUES_ = {'IMG': ' ', 'BR': '\n'}; +ol.source.TileImage.prototype.canExpireCache = function() { + if (!ol.ENABLE_RASTER_REPROJECTION) { + return goog.base(this, 'canExpireCache'); + } + var canExpire = this.tileCache.canExpireCache(); + if (canExpire) { + return true; + } else { + return goog.object.some(this.tileCacheForProjection, function(tileCache) { + return tileCache.canExpireCache(); + }); + } +}; /** - * Returns true if the element has a tab index that allows it to receive - * keyboard focus (tabIndex >= 0), false otherwise. Note that some elements - * natively support keyboard focus, even if they have no tab index. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a tab index that allows keyboard - * focus. - * @see http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + * @inheritDoc */ -goog.dom.isFocusableTabIndex = function(element) { - return goog.dom.hasSpecifiedTabIndex_(element) && - goog.dom.isTabIndexFocusable_(element); +ol.source.TileImage.prototype.expireCache = function(projection, usedTiles) { + if (!ol.ENABLE_RASTER_REPROJECTION) { + goog.base(this, 'expireCache', projection, usedTiles); + return; + } + var usedTileCache = this.getTileCacheForProjection(projection); + + this.tileCache.expireCache(this.tileCache == usedTileCache ? usedTiles : {}); + goog.object.forEach(this.tileCacheForProjection, function(tileCache) { + tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {}); + }); }; /** - * Enables or disables keyboard focus support on the element via its tab index. - * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true - * (or elements that natively support keyboard focus, like form elements) can - * receive keyboard focus. See http://go/tabindex for more info. - * @param {Element} element Element whose tab index is to be changed. - * @param {boolean} enable Whether to set or remove a tab index on the element - * that supports keyboard focus. + * @inheritDoc */ -goog.dom.setFocusableTabIndex = function(element, enable) { - if (enable) { - element.tabIndex = 0; +ol.source.TileImage.prototype.getTileGridForProjection = function(projection) { + if (!ol.ENABLE_RASTER_REPROJECTION) { + return goog.base(this, 'getTileGridForProjection', projection); + } + var thisProj = this.getProjection(); + if (this.tileGrid && + (!thisProj || ol.proj.equivalent(thisProj, projection))) { + return this.tileGrid; } else { - // Set tabIndex to -1 first, then remove it. This is a workaround for - // Safari (confirmed in version 4 on Windows). When removing the attribute - // without setting it to -1 first, the element remains keyboard focusable - // despite not having a tabIndex attribute anymore. - element.tabIndex = -1; - element.removeAttribute('tabIndex'); // Must be camelCase! + var projKey = goog.getUid(projection).toString(); + if (!(projKey in this.tileGridForProjection)) { + this.tileGridForProjection[projKey] = + ol.tilegrid.getForProjection(projection); + } + return this.tileGridForProjection[projKey]; } }; /** - * Returns true if the element can be focused, i.e. it has a tab index that - * allows it to receive keyboard focus (tabIndex >= 0), or it is an element - * that natively supports keyboard focus. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element allows keyboard focus. + * @inheritDoc */ -goog.dom.isFocusable = function(element) { - var focusable; - // Some elements can have unspecified tab index and still receive focus. - if (goog.dom.nativelySupportsFocus_(element)) { - // Make sure the element is not disabled ... - focusable = !element.disabled && - // ... and if a tab index is specified, it allows focus. - (!goog.dom.hasSpecifiedTabIndex_(element) || - goog.dom.isTabIndexFocusable_(element)); +ol.source.TileImage.prototype.getTileCacheForProjection = function(projection) { + if (!ol.ENABLE_RASTER_REPROJECTION) { + return goog.base(this, 'getTileCacheForProjection', projection); + } + var thisProj = this.getProjection(); + if (!thisProj || ol.proj.equivalent(thisProj, projection)) { + return this.tileCache; } else { - focusable = goog.dom.isFocusableTabIndex(element); + var projKey = goog.getUid(projection).toString(); + if (!(projKey in this.tileCacheForProjection)) { + this.tileCacheForProjection[projKey] = new ol.TileCache(); + } + return this.tileCacheForProjection[projKey]; } - - // IE requires elements to be visible in order to focus them. - return focusable && goog.userAgent.IE ? - goog.dom.hasNonZeroBoundingRect_(element) : focusable; }; /** - * Returns true if the element has a specified tab index. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a specified tab index. + * @param {number} z Tile coordinate z. + * @param {number} x Tile coordinate x. + * @param {number} y Tile coordinate y. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @param {string} key The key set on the tile. + * @return {ol.Tile} Tile. * @private */ -goog.dom.hasSpecifiedTabIndex_ = function(element) { - // IE returns 0 for an unset tabIndex, so we must use getAttributeNode(), - // which returns an object with a 'specified' property if tabIndex is - // specified. This works on other browsers, too. - var attrNode = element.getAttributeNode('tabindex'); // Must be lowercase! - return goog.isDefAndNotNull(attrNode) && attrNode.specified; +ol.source.TileImage.prototype.createTile_ = + function(z, x, y, pixelRatio, projection, key) { + var tileCoord = [z, x, y]; + var urlTileCoord = this.getTileCoordForTileUrlFunction( + tileCoord, projection); + var tileUrl = urlTileCoord ? + this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined; + var tile = new this.tileClass( + tileCoord, + tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, + tileUrl !== undefined ? tileUrl : '', + this.crossOrigin, + this.tileLoadFunction); + tile.key = key; + goog.events.listen(tile, goog.events.EventType.CHANGE, + this.handleTileChange, false, this); + return tile; }; /** - * Returns true if the element's tab index allows the element to be focused. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element's tab index allows focus. - * @private + * @inheritDoc */ -goog.dom.isTabIndexFocusable_ = function(element) { - var index = element.tabIndex; - // NOTE: IE9 puts tabIndex in 16-bit int, e.g. -2 is 65534. - return goog.isNumber(index) && index >= 0 && index < 32768; +ol.source.TileImage.prototype.getTile = + function(z, x, y, pixelRatio, projection) { + if (!ol.ENABLE_RASTER_REPROJECTION || + !this.getProjection() || + !projection || + ol.proj.equivalent(this.getProjection(), projection)) { + return this.getTileInternal(z, x, y, pixelRatio, projection); + } else { + var cache = this.getTileCacheForProjection(projection); + var tileCoordKey = this.getKeyZXY(z, x, y); + if (cache.containsKey(tileCoordKey)) { + return /** @type {!ol.Tile} */ (cache.get(tileCoordKey)); + } else { + var sourceProjection = this.getProjection(); + var sourceTileGrid = this.getTileGridForProjection(sourceProjection); + var targetTileGrid = this.getTileGridForProjection(projection); + var tile = new ol.reproj.Tile( + sourceProjection, sourceTileGrid, + projection, targetTileGrid, + z, x, y, this.getTilePixelRatio(), + goog.bind(function(z, x, y, pixelRatio) { + return this.getTileInternal(z, x, y, pixelRatio, sourceProjection); + }, this), this.reprojectionErrorThreshold_, + this.renderReprojectionEdges_); + + cache.set(tileCoordKey, tile); + return tile; + } + } }; /** - * Returns true if the element is focusable even when tabIndex is not set. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element natively supports focus. - * @private + * @param {number} z Tile coordinate z. + * @param {number} x Tile coordinate x. + * @param {number} y Tile coordinate y. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {!ol.Tile} Tile. + * @protected */ -goog.dom.nativelySupportsFocus_ = function(element) { - return element.tagName == goog.dom.TagName.A || - element.tagName == goog.dom.TagName.INPUT || - element.tagName == goog.dom.TagName.TEXTAREA || - element.tagName == goog.dom.TagName.SELECT || - element.tagName == goog.dom.TagName.BUTTON; +ol.source.TileImage.prototype.getTileInternal = + function(z, x, y, pixelRatio, projection) { + var /** @type {ol.Tile} */ tile = null; + var tileCoordKey = this.getKeyZXY(z, x, y); + var paramsKey = this.getKeyParams(); + if (!this.tileCache.containsKey(tileCoordKey)) { + goog.asserts.assert(projection, 'argument projection is truthy'); + tile = this.createTile_(z, x, y, pixelRatio, projection, paramsKey); + this.tileCache.set(tileCoordKey, tile); + } else { + tile = /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); + if (tile.key != paramsKey) { + // The source's params changed. If the tile has an interim tile and if we + // can use it then we use it. Otherwise we create a new tile. In both + // cases we attempt to assign an interim tile to the new tile. + var /** @type {ol.Tile} */ interimTile = tile; + if (tile.interimTile && tile.interimTile.key == paramsKey) { + goog.asserts.assert(tile.interimTile.getState() == ol.TileState.LOADED); + goog.asserts.assert(tile.interimTile.interimTile === null); + tile = tile.interimTile; + if (interimTile.getState() == ol.TileState.LOADED) { + tile.interimTile = interimTile; + } + } else { + tile = this.createTile_(z, x, y, pixelRatio, projection, paramsKey); + if (interimTile.getState() == ol.TileState.LOADED) { + tile.interimTile = interimTile; + } else if (interimTile.interimTile && + interimTile.interimTile.getState() == ol.TileState.LOADED) { + tile.interimTile = interimTile.interimTile; + interimTile.interimTile = null; + } + } + if (tile.interimTile) { + tile.interimTile.interimTile = null; + } + this.tileCache.replace(tileCoordKey, tile); + } + } + goog.asserts.assert(tile); + return tile; }; /** - * Returns true if the element has a bounding rectangle that would be visible - * (i.e. its width and height are greater than zero). - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a non-zero bounding rectangle. - * @private + * Sets whether to render reprojection edges or not (usually for debugging). + * @param {boolean} render Render the edges. + * @api */ -goog.dom.hasNonZeroBoundingRect_ = function(element) { - var rect = goog.isFunction(element['getBoundingClientRect']) ? - element.getBoundingClientRect() : - {'height': element.offsetHeight, 'width': element.offsetWidth}; - return goog.isDefAndNotNull(rect) && rect.height > 0 && rect.width > 0; +ol.source.TileImage.prototype.setRenderReprojectionEdges = function(render) { + if (!ol.ENABLE_RASTER_REPROJECTION || + this.renderReprojectionEdges_ == render) { + return; + } + this.renderReprojectionEdges_ = render; + goog.object.forEach(this.tileCacheForProjection, function(tileCache) { + tileCache.clear(); + }); + this.changed(); }; /** - * Returns the text content of the current node, without markup and invisible - * symbols. New lines are stripped and whitespace is collapsed, - * such that each character would be visible. + * Sets the tile grid to use when reprojecting the tiles to the given + * projection instead of the default tile grid for the projection. * - * In browsers that support it, innerText is used. Other browsers attempt to - * simulate it via node traversal. Line breaks are canonicalized in IE. + * This can be useful when the default tile grid cannot be created + * (e.g. projection has no extent defined) or + * for optimization reasons (custom tile size, resolutions, ...). * - * @param {Node} node The node from which we are getting content. - * @return {string} The text content. + * @param {ol.proj.ProjectionLike} projection Projection. + * @param {ol.tilegrid.TileGrid} tilegrid Tile grid to use for the projection. + * @api */ -goog.dom.getTextContent = function(node) { - var textContent; - // Note(arv): IE9, Opera, and Safari 3 support innerText but they include - // text nodes in script tags. So we revert to use a user agent test here. - if (goog.dom.BrowserFeature.CAN_USE_INNER_TEXT && ('innerText' in node)) { - textContent = goog.string.canonicalizeNewlines(node.innerText); - // Unfortunately .innerText() returns text with ­ symbols - // We need to filter it out and then remove duplicate whitespaces - } else { - var buf = []; - goog.dom.getTextContent_(node, buf, true); - textContent = buf.join(''); +ol.source.TileImage.prototype.setTileGridForProjection = + function(projection, tilegrid) { + if (ol.ENABLE_RASTER_REPROJECTION) { + var proj = ol.proj.get(projection); + if (proj) { + var projKey = goog.getUid(proj).toString(); + if (!(projKey in this.tileGridForProjection)) { + this.tileGridForProjection[projKey] = tilegrid; + } + } } +}; - // Strip ­ entities. goog.format.insertWordBreaks inserts them in Opera. - textContent = textContent.replace(/ \xAD /g, ' ').replace(/\xAD/g, ''); - // Strip ​ entities. goog.format.insertWordBreaks inserts them in IE8. - textContent = textContent.replace(/\u200B/g, ''); - - // Skip this replacement on old browsers with working innerText, which - // automatically turns   into ' ' and / +/ into ' ' when reading - // innerText. - if (!goog.dom.BrowserFeature.CAN_USE_INNER_TEXT) { - textContent = textContent.replace(/ +/g, ' '); - } - if (textContent != ' ') { - textContent = textContent.replace(/^\s*/, ''); - } - return textContent; +/** + * @param {ol.ImageTile} imageTile Image tile. + * @param {string} src Source. + */ +ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) { + imageTile.getImage().src = src; }; +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Returns the text content of the current node, without markup. + * @fileoverview Simple utilities for dealing with URI strings. * - * Unlike {@code getTextContent} this method does not collapse whitespaces - * or normalize lines breaks. + * This is intended to be a lightweight alternative to constructing goog.Uri + * objects. Whereas goog.Uri adds several kilobytes to the binary regardless + * of how much of its functionality you use, this is designed to be a set of + * mostly-independent utilities so that the compiler includes only what is + * necessary for the task. Estimated savings of porting is 5k pre-gzip and + * 1.5k post-gzip. To ensure the savings remain, future developers should + * avoid adding new functionality to existing functions, but instead create + * new ones and factor out shared code. * - * @param {Node} node The node from which we are getting content. - * @return {string} The raw text content. + * Many of these utilities have limited functionality, tailored to common + * cases. The query parameter utilities assume that the parameter keys are + * already encoded, since most keys are compile-time alphanumeric strings. The + * query parameter mutation utilities also do not tolerate fragment identifiers. + * + * By design, these functions can be slower than goog.Uri equivalents. + * Repeated calls to some of functions may be quadratic in behavior for IE, + * although the effect is somewhat limited given the 2kb limit. + * + * One advantage of the limited functionality here is that this approach is + * less sensitive to differences in URI encodings than goog.Uri, since these + * functions operate on strings directly, rather than decoding them and + * then re-encoding. + * + * Uses features of RFC 3986 for parsing/formatting URIs: + * http://www.ietf.org/rfc/rfc3986.txt + * + * @author gboyer@google.com (Garrett Boyer) - The "lightened" design. */ -goog.dom.getRawTextContent = function(node) { - var buf = []; - goog.dom.getTextContent_(node, buf, false); - return buf.join(''); -}; +goog.provide('goog.uri.utils'); +goog.provide('goog.uri.utils.ComponentIndex'); +goog.provide('goog.uri.utils.QueryArray'); +goog.provide('goog.uri.utils.QueryValue'); +goog.provide('goog.uri.utils.StandardQueryParam'); + +goog.require('goog.asserts'); +goog.require('goog.string'); /** - * Recursive support function for text content retrieval. - * - * @param {Node} node The node from which we are getting content. - * @param {Array<string>} buf string buffer. - * @param {boolean} normalizeWhitespace Whether to normalize whitespace. + * Character codes inlined to avoid object allocations due to charCode. + * @enum {number} * @private */ -goog.dom.getTextContent_ = function(node, buf, normalizeWhitespace) { - if (node.nodeName in goog.dom.TAGS_TO_IGNORE_) { - // ignore certain tags - } else if (node.nodeType == goog.dom.NodeType.TEXT) { - if (normalizeWhitespace) { - buf.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, '')); - } else { - buf.push(node.nodeValue); - } - } else if (node.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) { - buf.push(goog.dom.PREDEFINED_TAG_VALUES_[node.nodeName]); - } else { - var child = node.firstChild; - while (child) { - goog.dom.getTextContent_(child, buf, normalizeWhitespace); - child = child.nextSibling; - } - } +goog.uri.utils.CharCode_ = { + AMPERSAND: 38, + EQUAL: 61, + HASH: 35, + QUESTION: 63 }; /** - * Returns the text length of the text contained in a node, without markup. This - * is equivalent to the selection length if the node was selected, or the number - * of cursor movements to traverse the node. Images & BRs take one space. New - * lines are ignored. + * Builds a URI string from already-encoded parts. * - * @param {Node} node The node whose text content length is being calculated. - * @return {number} The length of {@code node}'s text content. + * No encoding is performed. Any component may be omitted as either null or + * undefined. + * + * @param {?string=} opt_scheme The scheme such as 'http'. + * @param {?string=} opt_userInfo The user name before the '@'. + * @param {?string=} opt_domain The domain such as 'www.google.com', already + * URI-encoded. + * @param {(string|number|null)=} opt_port The port number. + * @param {?string=} opt_path The path, already URI-encoded. If it is not + * empty, it must begin with a slash. + * @param {?string=} opt_queryData The URI-encoded query data. + * @param {?string=} opt_fragment The URI-encoded fragment identifier. + * @return {string} The fully combined URI. */ -goog.dom.getNodeTextLength = function(node) { - return goog.dom.getTextContent(node).length; -}; +goog.uri.utils.buildFromEncodedParts = function(opt_scheme, opt_userInfo, + opt_domain, opt_port, opt_path, opt_queryData, opt_fragment) { + var out = ''; + if (opt_scheme) { + out += opt_scheme + ':'; + } -/** - * Returns the text offset of a node relative to one of its ancestors. The text - * length is the same as the length calculated by goog.dom.getNodeTextLength. - * - * @param {Node} node The node whose offset is being calculated. - * @param {Node=} opt_offsetParent The node relative to which the offset will - * be calculated. Defaults to the node's owner document's body. - * @return {number} The text offset. - */ -goog.dom.getNodeTextOffset = function(node, opt_offsetParent) { - var root = opt_offsetParent || goog.dom.getOwnerDocument(node).body; - var buf = []; - while (node && node != root) { - var cur = node; - while ((cur = cur.previousSibling)) { - buf.unshift(goog.dom.getTextContent(cur)); + if (opt_domain) { + out += '//'; + + if (opt_userInfo) { + out += opt_userInfo + '@'; } - node = node.parentNode; - } - // Trim left to deal with FF cases when there might be line breaks and empty - // nodes at the front of the text - return goog.string.trimLeft(buf.join('')).replace(/ +/g, ' ').length; -}; + out += opt_domain; -/** - * Returns the node at a given offset in a parent node. If an object is - * provided for the optional third parameter, the node and the remainder of the - * offset will stored as properties of this object. - * @param {Node} parent The parent node. - * @param {number} offset The offset into the parent node. - * @param {Object=} opt_result Object to be used to store the return value. The - * return value will be stored in the form {node: Node, remainder: number} - * if this object is provided. - * @return {Node} The node at the given offset. - */ -goog.dom.getNodeAtOffset = function(parent, offset, opt_result) { - var stack = [parent], pos = 0, cur = null; - while (stack.length > 0 && pos < offset) { - cur = stack.pop(); - if (cur.nodeName in goog.dom.TAGS_TO_IGNORE_) { - // ignore certain tags - } else if (cur.nodeType == goog.dom.NodeType.TEXT) { - var text = cur.nodeValue.replace(/(\r\n|\r|\n)/g, '').replace(/ +/g, ' '); - pos += text.length; - } else if (cur.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) { - pos += goog.dom.PREDEFINED_TAG_VALUES_[cur.nodeName].length; - } else { - for (var i = cur.childNodes.length - 1; i >= 0; i--) { - stack.push(cur.childNodes[i]); - } + if (opt_port) { + out += ':' + opt_port; } } - if (goog.isObject(opt_result)) { - opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0; - opt_result.node = cur; - } - return cur; -}; + if (opt_path) { + out += opt_path; + } + if (opt_queryData) { + out += '?' + opt_queryData; + } -/** - * Returns true if the object is a {@code NodeList}. To qualify as a NodeList, - * the object must have a numeric length property and an item function (which - * has type 'string' on IE for some reason). - * @param {Object} val Object to test. - * @return {boolean} Whether the object is a NodeList. - */ -goog.dom.isNodeList = function(val) { - // TODO(attila): Now the isNodeList is part of goog.dom we can use - // goog.userAgent to make this simpler. - // A NodeList must have a length property of type 'number' on all platforms. - if (val && typeof val.length == 'number') { - // A NodeList is an object everywhere except Safari, where it's a function. - if (goog.isObject(val)) { - // A NodeList must have an item function (on non-IE platforms) or an item - // property of type 'string' (on IE). - return typeof val.item == 'function' || typeof val.item == 'string'; - } else if (goog.isFunction(val)) { - // On Safari, a NodeList is a function with an item property that is also - // a function. - return typeof val.item == 'function'; - } + if (opt_fragment) { + out += '#' + opt_fragment; } - // Not a NodeList. - return false; + return out; }; /** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * tag name and/or class name. If the passed element matches the specified - * criteria, the element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or - * null/undefined to match only based on class name). - * @param {?string=} opt_class The class name to match (or null/undefined to - * match only based on tag name). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if no match is found. + * A regular expression for breaking a URI into its component parts. + * + * {@link http://www.ietf.org/rfc/rfc3986.txt} says in Appendix B + * As the "first-match-wins" algorithm is identical to the "greedy" + * disambiguation method used by POSIX regular expressions, it is natural and + * commonplace to use a regular expression for parsing the potential five + * components of a URI reference. + * + * The following line is the regular expression for breaking-down a + * well-formed URI reference into its components. + * + * <pre> + * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? + * 12 3 4 5 6 7 8 9 + * </pre> + * + * The numbers in the second line above are only to assist readability; they + * indicate the reference points for each subexpression (i.e., each paired + * parenthesis). We refer to the value matched for subexpression <n> as $<n>. + * For example, matching the above expression to + * <pre> + * http://www.ics.uci.edu/pub/ietf/uri/#Related + * </pre> + * results in the following subexpression matches: + * <pre> + * $1 = http: + * $2 = http + * $3 = //www.ics.uci.edu + * $4 = www.ics.uci.edu + * $5 = /pub/ietf/uri/ + * $6 = <undefined> + * $7 = <undefined> + * $8 = #Related + * $9 = Related + * </pre> + * where <undefined> indicates that the component is not present, as is the + * case for the query component in the above example. Therefore, we can + * determine the value of the five components as + * <pre> + * scheme = $2 + * authority = $4 + * path = $5 + * query = $7 + * fragment = $9 + * </pre> + * + * The regular expression has been modified slightly to expose the + * userInfo, domain, and port separately from the authority. + * The modified version yields + * <pre> + * $1 = http scheme + * $2 = <undefined> userInfo -\ + * $3 = www.ics.uci.edu domain | authority + * $4 = <undefined> port -/ + * $5 = /pub/ietf/uri/ path + * $6 = <undefined> query without ? + * $7 = Related fragment without # + * </pre> + * @type {!RegExp} + * @private */ -goog.dom.getAncestorByTagNameAndClass = function(element, opt_tag, opt_class, - opt_maxSearchSteps) { - if (!opt_tag && !opt_class) { - return null; - } - var tagName = opt_tag ? opt_tag.toUpperCase() : null; - return /** @type {Element} */ (goog.dom.getAncestor(element, - function(node) { - return (!tagName || node.nodeName == tagName) && - (!opt_class || goog.isString(node.className) && - goog.array.contains(node.className.split(/\s+/), opt_class)); - }, true, opt_maxSearchSteps)); -}; +goog.uri.utils.splitRe_ = new RegExp( + '^' + + '(?:' + + '([^:/?#.]+)' + // scheme - ignore special characters + // used by other URL parts such as :, + // ?, /, #, and . + ':)?' + + '(?://' + + '(?:([^/?#]*)@)?' + // userInfo + '([^/#?]*?)' + // domain + '(?::([0-9]+))?' + // port + '(?=[/#?]|$)' + // authority-terminating character + ')?' + + '([^?#]+)?' + // path + '(?:\\?([^#]*))?' + // query + '(?:#(.*))?' + // fragment + '$'); /** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * class name. If the passed element matches the specified criteria, the - * element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {string} className The class name to match. - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if none match. + * The index of each URI component in the return value of goog.uri.utils.split. + * @enum {number} */ -goog.dom.getAncestorByClass = function(element, className, opt_maxSearchSteps) { - return goog.dom.getAncestorByTagNameAndClass(element, null, className, - opt_maxSearchSteps); +goog.uri.utils.ComponentIndex = { + SCHEME: 1, + USER_INFO: 2, + DOMAIN: 3, + PORT: 4, + PATH: 5, + QUERY_DATA: 6, + FRAGMENT: 7 }; /** - * Walks up the DOM hierarchy returning the first ancestor that passes the - * matcher function. - * @param {Node} element The DOM node to start with. - * @param {function(Node) : boolean} matcher A function that returns true if the - * passed node matches the desired criteria. - * @param {boolean=} opt_includeNode If true, the node itself is included in - * the search (the first call to the matcher will pass startElement as - * the node to test). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Node} DOM node that matched the matcher, or null if there was - * no match. + * Splits a URI into its component parts. + * + * Each component can be accessed via the component indices; for example: + * <pre> + * goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA]; + * </pre> + * + * @param {string} uri The URI string to examine. + * @return {!Array<string|undefined>} Each component still URI-encoded. + * Each component that is present will contain the encoded value, whereas + * components that are not present will be undefined or empty, depending + * on the browser's regular expression implementation. Never null, since + * arbitrary strings may still look like path names. */ -goog.dom.getAncestor = function( - element, matcher, opt_includeNode, opt_maxSearchSteps) { - if (!opt_includeNode) { - element = element.parentNode; - } - var ignoreSearchSteps = opt_maxSearchSteps == null; - var steps = 0; - while (element && (ignoreSearchSteps || steps <= opt_maxSearchSteps)) { - goog.asserts.assert(element.name != 'parentNode'); - if (matcher(element)) { - return element; - } - element = element.parentNode; - steps++; - } - // Reached the root of the DOM without a match - return null; +goog.uri.utils.split = function(uri) { + // See @return comment -- never null. + return /** @type {!Array<string|undefined>} */ ( + uri.match(goog.uri.utils.splitRe_)); }; /** - * Determines the active element in the given document. - * @param {Document} doc The document to look in. - * @return {Element} The active element. + * @param {?string} uri A possibly null string. + * @param {boolean=} opt_preserveReserved If true, percent-encoding of RFC-3986 + * reserved characters will not be removed. + * @return {?string} The string URI-decoded, or null if uri is null. + * @private */ -goog.dom.getActiveElement = function(doc) { - try { - return doc && doc.activeElement; - } catch (e) { - // NOTE(nicksantos): Sometimes, evaluating document.activeElement in IE - // throws an exception. I'm not 100% sure why, but I suspect it chokes - // on document.activeElement if the activeElement has been recently - // removed from the DOM by a JS operation. - // - // We assume that an exception here simply means - // "there is no active element." +goog.uri.utils.decodeIfPossible_ = function(uri, opt_preserveReserved) { + if (!uri) { + return uri; } - return null; + return opt_preserveReserved ? decodeURI(uri) : decodeURIComponent(uri); }; /** - * Gives the current devicePixelRatio. - * - * By default, this is the value of window.devicePixelRatio (which should be - * preferred if present). - * - * If window.devicePixelRatio is not present, the ratio is calculated with - * window.matchMedia, if present. Otherwise, gives 1.0. + * Gets a URI component by index. * - * Some browsers (including Chrome) consider the browser zoom level in the pixel - * ratio, so the value may change across multiple calls. + * It is preferred to use the getPathEncoded() variety of functions ahead, + * since they are more readable. * - * @return {number} The number of actual pixels per virtual pixel. - */ -goog.dom.getPixelRatio = function() { - var win = goog.dom.getWindow(); - if (goog.isDef(win.devicePixelRatio)) { - return win.devicePixelRatio; - } else if (win.matchMedia) { - return goog.dom.matchesPixelRatio_(.75) || - goog.dom.matchesPixelRatio_(1.5) || - goog.dom.matchesPixelRatio_(2) || - goog.dom.matchesPixelRatio_(3) || 1; - } - return 1; -}; - - -/** - * Calculates a mediaQuery to check if the current device supports the - * given actual to virtual pixel ratio. - * @param {number} pixelRatio The ratio of actual pixels to virtual pixels. - * @return {number} pixelRatio if applicable, otherwise 0. + * @param {goog.uri.utils.ComponentIndex} componentIndex The component index. + * @param {string} uri The URI to examine. + * @return {?string} The still-encoded component, or null if the component + * is not present. * @private */ -goog.dom.matchesPixelRatio_ = function(pixelRatio) { - var win = goog.dom.getWindow(); - var query = ('(-webkit-min-device-pixel-ratio: ' + pixelRatio + '),' + - '(min--moz-device-pixel-ratio: ' + pixelRatio + '),' + - '(min-resolution: ' + pixelRatio + 'dppx)'); - return win.matchMedia(query).matches ? pixelRatio : 0; +goog.uri.utils.getComponentByIndex_ = function(componentIndex, uri) { + // Convert undefined, null, and empty string into null. + return goog.uri.utils.split(uri)[componentIndex] || null; }; - /** - * Create an instance of a DOM helper with a new document object. - * @param {Document=} opt_document Document object to associate with this - * DOM helper. - * @constructor + * @param {string} uri The URI to examine. + * @return {?string} The protocol or scheme, or null if none. Does not + * include trailing colons or slashes. */ -goog.dom.DomHelper = function(opt_document) { - /** - * Reference to the document object to use - * @type {!Document} - * @private - */ - this.document_ = opt_document || goog.global.document || document; +goog.uri.utils.getScheme = function(uri) { + return goog.uri.utils.getComponentByIndex_( + goog.uri.utils.ComponentIndex.SCHEME, uri); }; /** - * Gets the dom helper object for the document where the element resides. - * @param {Node=} opt_node If present, gets the DomHelper for this node. - * @return {!goog.dom.DomHelper} The DomHelper. - */ -goog.dom.DomHelper.prototype.getDomHelper = goog.dom.getDomHelper; + * Gets the effective scheme for the URL. If the URL is relative then the + * scheme is derived from the page's location. + * @param {string} uri The URI to examine. + * @return {string} The protocol or scheme, always lower case. + */ +goog.uri.utils.getEffectiveScheme = function(uri) { + var scheme = goog.uri.utils.getScheme(uri); + if (!scheme && goog.global.self && goog.global.self.location) { + var protocol = goog.global.self.location.protocol; + scheme = protocol.substr(0, protocol.length - 1); + } + // NOTE: When called from a web worker in Firefox 3.5, location maybe null. + // All other browsers with web workers support self.location from the worker. + return scheme ? scheme.toLowerCase() : ''; +}; /** - * Sets the document object. - * @param {!Document} document Document object. + * @param {string} uri The URI to examine. + * @return {?string} The user name still encoded, or null if none. */ -goog.dom.DomHelper.prototype.setDocument = function(document) { - this.document_ = document; +goog.uri.utils.getUserInfoEncoded = function(uri) { + return goog.uri.utils.getComponentByIndex_( + goog.uri.utils.ComponentIndex.USER_INFO, uri); }; /** - * Gets the document object being used by the dom library. - * @return {!Document} Document object. + * @param {string} uri The URI to examine. + * @return {?string} The decoded user info, or null if none. */ -goog.dom.DomHelper.prototype.getDocument = function() { - return this.document_; +goog.uri.utils.getUserInfo = function(uri) { + return goog.uri.utils.decodeIfPossible_( + goog.uri.utils.getUserInfoEncoded(uri)); }; /** - * Alias for {@code getElementById}. If a DOM node is passed in then we just - * return that. - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. + * @param {string} uri The URI to examine. + * @return {?string} The domain name still encoded, or null if none. */ -goog.dom.DomHelper.prototype.getElement = function(element) { - return goog.dom.getElementHelper_(this.document_, element); +goog.uri.utils.getDomainEncoded = function(uri) { + return goog.uri.utils.getComponentByIndex_( + goog.uri.utils.ComponentIndex.DOMAIN, uri); }; /** - * Gets an element by id, asserting that the element is found. - * - * This is used when an element is expected to exist, and should fail with - * an assertion error if it does not (if assertions are enabled). - * - * @param {string} id Element ID. - * @return {!Element} The element with the given ID, if it exists. + * @param {string} uri The URI to examine. + * @return {?string} The decoded domain, or null if none. */ -goog.dom.DomHelper.prototype.getRequiredElement = function(id) { - return goog.dom.getRequiredElementHelper_(this.document_, id); +goog.uri.utils.getDomain = function(uri) { + return goog.uri.utils.decodeIfPossible_( + goog.uri.utils.getDomainEncoded(uri), true /* opt_preserveReserved */); }; /** - * Alias for {@code getElement}. - * @param {string|Element} element Element ID or a DOM node. - * @return {Element} The element with the given ID, or the node passed in. - * @deprecated Use {@link goog.dom.DomHelper.prototype.getElement} instead. + * @param {string} uri The URI to examine. + * @return {?number} The port number, or null if none. */ -goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement; +goog.uri.utils.getPort = function(uri) { + // Coerce to a number. If the result of getComponentByIndex_ is null or + // non-numeric, the number coersion yields NaN. This will then return + // null for all non-numeric cases (though also zero, which isn't a relevant + // port number). + return Number(goog.uri.utils.getComponentByIndex_( + goog.uri.utils.ComponentIndex.PORT, uri)) || null; +}; /** - * Looks up elements by both tag and class name, using browser native functions - * ({@code querySelectorAll}, {@code getElementsByTagName} or - * {@code getElementsByClassName}) where possible. The returned array is a live - * NodeList or a static list depending on the code path taken. - * - * @see goog.dom.query - * - * @param {?string=} opt_tag Element tag name or * for all tags. - * @param {?string=} opt_class Optional class name. - * @param {(Document|Element)=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). + * @param {string} uri The URI to examine. + * @return {?string} The path still encoded, or null if none. Includes the + * leading slash, if any. */ -goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(opt_tag, - opt_class, - opt_el) { - return goog.dom.getElementsByTagNameAndClass_(this.document_, opt_tag, - opt_class, opt_el); +goog.uri.utils.getPathEncoded = function(uri) { + return goog.uri.utils.getComponentByIndex_( + goog.uri.utils.ComponentIndex.PATH, uri); }; /** - * Returns an array of all the elements with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {Element|Document=} opt_el Optional element to look in. - * @return { {length: number} } The items found with the class name provided. + * @param {string} uri The URI to examine. + * @return {?string} The decoded path, or null if none. Includes the leading + * slash, if any. */ -goog.dom.DomHelper.prototype.getElementsByClass = function(className, opt_el) { - var doc = opt_el || this.document_; - return goog.dom.getElementsByClass(className, doc); +goog.uri.utils.getPath = function(uri) { + return goog.uri.utils.decodeIfPossible_( + goog.uri.utils.getPathEncoded(uri), true /* opt_preserveReserved */); }; /** - * Returns the first element we find matching the provided class name. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {(Element|Document)=} opt_el Optional element to look in. - * @return {Element} The first item found with the class name provided. + * @param {string} uri The URI to examine. + * @return {?string} The query data still encoded, or null if none. Does not + * include the question mark itself. */ -goog.dom.DomHelper.prototype.getElementByClass = function(className, opt_el) { - var doc = opt_el || this.document_; - return goog.dom.getElementByClass(className, doc); +goog.uri.utils.getQueryData = function(uri) { + return goog.uri.utils.getComponentByIndex_( + goog.uri.utils.ComponentIndex.QUERY_DATA, uri); }; /** - * Ensures an element with the given className exists, and then returns the - * first element with the provided className. - * @see {goog.dom.query} - * @param {string} className the name of the class to look for. - * @param {(!Element|!Document)=} opt_root Optional element or document to look - * in. - * @return {!Element} The first item found with the class name provided. - * @throws {goog.asserts.AssertionError} Thrown if no element is found. + * @param {string} uri The URI to examine. + * @return {?string} The fragment identifier, or null if none. Does not + * include the hash mark itself. */ -goog.dom.DomHelper.prototype.getRequiredElementByClass = function(className, - opt_root) { - var root = opt_root || this.document_; - return goog.dom.getRequiredElementByClass(className, root); +goog.uri.utils.getFragmentEncoded = function(uri) { + // The hash mark may not appear in any other part of the URL. + var hashIndex = uri.indexOf('#'); + return hashIndex < 0 ? null : uri.substr(hashIndex + 1); }; /** - * Alias for {@code getElementsByTagNameAndClass}. - * @deprecated Use DomHelper getElementsByTagNameAndClass. - * @see goog.dom.query - * - * @param {?string=} opt_tag Element tag name. - * @param {?string=} opt_class Optional class name. - * @param {Element=} opt_el Optional element to look in. - * @return { {length: number} } Array-like list of elements (only a length - * property and numerical indices are guaranteed to exist). + * @param {string} uri The URI to examine. + * @param {?string} fragment The encoded fragment identifier, or null if none. + * Does not include the hash mark itself. + * @return {string} The URI with the fragment set. */ -goog.dom.DomHelper.prototype.$$ = - goog.dom.DomHelper.prototype.getElementsByTagNameAndClass; +goog.uri.utils.setFragmentEncoded = function(uri, fragment) { + return goog.uri.utils.removeFragment(uri) + (fragment ? '#' + fragment : ''); +}; /** - * Sets a number of properties on a node. - * @param {Element} element DOM node to set properties on. - * @param {Object} properties Hash of property:value pairs. + * @param {string} uri The URI to examine. + * @return {?string} The decoded fragment identifier, or null if none. Does + * not include the hash mark. */ -goog.dom.DomHelper.prototype.setProperties = goog.dom.setProperties; +goog.uri.utils.getFragment = function(uri) { + return goog.uri.utils.decodeIfPossible_( + goog.uri.utils.getFragmentEncoded(uri)); +}; /** - * Gets the dimensions of the viewport. - * @param {Window=} opt_window Optional window element to test. Defaults to - * the window of the Dom Helper. - * @return {!goog.math.Size} Object with values 'width' and 'height'. + * Extracts everything up to the port of the URI. + * @param {string} uri The URI string. + * @return {string} Everything up to and including the port. */ -goog.dom.DomHelper.prototype.getViewportSize = function(opt_window) { - // TODO(arv): This should not take an argument. That breaks the rule of a - // a DomHelper representing a single frame/window/document. - return goog.dom.getViewportSize(opt_window || this.getWindow()); +goog.uri.utils.getHost = function(uri) { + var pieces = goog.uri.utils.split(uri); + return goog.uri.utils.buildFromEncodedParts( + pieces[goog.uri.utils.ComponentIndex.SCHEME], + pieces[goog.uri.utils.ComponentIndex.USER_INFO], + pieces[goog.uri.utils.ComponentIndex.DOMAIN], + pieces[goog.uri.utils.ComponentIndex.PORT]); }; /** - * Calculates the height of the document. - * - * @return {number} The height of the document. + * Extracts the path of the URL and everything after. + * @param {string} uri The URI string. + * @return {string} The URI, starting at the path and including the query + * parameters and fragment identifier. */ -goog.dom.DomHelper.prototype.getDocumentHeight = function() { - return goog.dom.getDocumentHeight_(this.getWindow()); +goog.uri.utils.getPathAndAfter = function(uri) { + var pieces = goog.uri.utils.split(uri); + return goog.uri.utils.buildFromEncodedParts(null, null, null, null, + pieces[goog.uri.utils.ComponentIndex.PATH], + pieces[goog.uri.utils.ComponentIndex.QUERY_DATA], + pieces[goog.uri.utils.ComponentIndex.FRAGMENT]); }; /** - * Typedef for use with goog.dom.createDom and goog.dom.append. - * @typedef {Object|string|Array|NodeList} + * Gets the URI with the fragment identifier removed. + * @param {string} uri The URI to examine. + * @return {string} Everything preceding the hash mark. */ -goog.dom.Appendable; +goog.uri.utils.removeFragment = function(uri) { + // The hash mark may not appear in any other part of the URL. + var hashIndex = uri.indexOf('#'); + return hashIndex < 0 ? uri : uri.substr(0, hashIndex); +}; /** - * Returns a dom node with a set of attributes. This function accepts varargs - * for subsequent nodes to be added. Subsequent nodes will be added to the - * first node as childNodes. - * - * So: - * <code>createDom('div', null, createDom('p'), createDom('p'));</code> - * would return a div with two child paragraphs + * Ensures that two URI's have the exact same domain, scheme, and port. * - * An easy way to move all child nodes of an existing element to a new parent - * element is: - * <code>createDom('div', null, oldElement.childNodes);</code> - * which will remove all child nodes from the old element and add them as - * child nodes of the new DIV. + * Unlike the version in goog.Uri, this checks protocol, and therefore is + * suitable for checking against the browser's same-origin policy. * - * @param {string} tagName Tag to create. - * @param {Object|string=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. - * @param {...goog.dom.Appendable} var_args Further DOM nodes or - * strings for text nodes. If one of the var_args is an array or - * NodeList, its elements will be added as childNodes instead. - * @return {!Element} Reference to a DOM node. + * @param {string} uri1 The first URI. + * @param {string} uri2 The second URI. + * @return {boolean} Whether they have the same scheme, domain and port. */ -goog.dom.DomHelper.prototype.createDom = function(tagName, - opt_attributes, - var_args) { - return goog.dom.createDom_(this.document_, arguments); +goog.uri.utils.haveSameDomain = function(uri1, uri2) { + var pieces1 = goog.uri.utils.split(uri1); + var pieces2 = goog.uri.utils.split(uri2); + return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] == + pieces2[goog.uri.utils.ComponentIndex.DOMAIN] && + pieces1[goog.uri.utils.ComponentIndex.SCHEME] == + pieces2[goog.uri.utils.ComponentIndex.SCHEME] && + pieces1[goog.uri.utils.ComponentIndex.PORT] == + pieces2[goog.uri.utils.ComponentIndex.PORT]; }; /** - * Alias for {@code createDom}. - * @param {string} tagName Tag to create. - * @param {(Object|string)=} opt_attributes If object, then a map of name-value - * pairs for attributes. If a string, then this is the className of the new - * element. - * @param {...goog.dom.Appendable} var_args Further DOM nodes or strings for - * text nodes. If one of the var_args is an array, its children will be - * added as childNodes instead. - * @return {!Element} Reference to a DOM node. - * @deprecated Use {@link goog.dom.DomHelper.prototype.createDom} instead. + * Asserts that there are no fragment or query identifiers, only in uncompiled + * mode. + * @param {string} uri The URI to examine. + * @private */ -goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom; +goog.uri.utils.assertNoFragmentsOrQueries_ = function(uri) { + // NOTE: would use goog.asserts here, but jscompiler doesn't know that + // indexOf has no side effects. + if (goog.DEBUG && (uri.indexOf('#') >= 0 || uri.indexOf('?') >= 0)) { + throw Error('goog.uri.utils: Fragment or query identifiers are not ' + + 'supported: [' + uri + ']'); + } +}; /** - * Creates a new element. - * @param {string} name Tag name. - * @return {!Element} The new element. + * Supported query parameter values by the parameter serializing utilities. + * + * If a value is null or undefined, the key-value pair is skipped, as an easy + * way to omit parameters conditionally. Non-array parameters are converted + * to a string and URI encoded. Array values are expanded into multiple + * &key=value pairs, with each element stringized and URI-encoded. + * + * @typedef {*} */ -goog.dom.DomHelper.prototype.createElement = function(name) { - return this.document_.createElement(name); -}; +goog.uri.utils.QueryValue; /** - * Creates a new text node. - * @param {number|string} content Content. - * @return {!Text} The new text node. + * An array representing a set of query parameters with alternating keys + * and values. + * + * Keys are assumed to be URI encoded already and live at even indices. See + * goog.uri.utils.QueryValue for details on how parameter values are encoded. + * + * Example: + * <pre> + * var data = [ + * // Simple param: ?name=BobBarker + * 'name', 'BobBarker', + * // Conditional param -- may be omitted entirely. + * 'specialDietaryNeeds', hasDietaryNeeds() ? getDietaryNeeds() : null, + * // Multi-valued param: &house=LosAngeles&house=NewYork&house=null + * 'house', ['LosAngeles', 'NewYork', null] + * ]; + * </pre> + * + * @typedef {!Array<string|goog.uri.utils.QueryValue>} */ -goog.dom.DomHelper.prototype.createTextNode = function(content) { - return this.document_.createTextNode(String(content)); -}; +goog.uri.utils.QueryArray; /** - * Create a table. - * @param {number} rows The number of rows in the table. Must be >= 1. - * @param {number} columns The number of columns in the table. Must be >= 1. - * @param {boolean=} opt_fillWithNbsp If true, fills table entries with - * {@code goog.string.Unicode.NBSP} characters. - * @return {!HTMLElement} The created table. + * Parses encoded query parameters and calls callback function for every + * parameter found in the string. + * + * Missing value of parameter (e.g. “…&key&…”) is treated as if the value was an + * empty string. Keys may be empty strings (e.g. “…&=value&…”) which also means + * that “…&=&…” and “…&&…” will result in an empty key and value. + * + * @param {string} encodedQuery Encoded query string excluding question mark at + * the beginning. + * @param {function(string, string)} callback Function called for every + * parameter found in query string. The first argument (name) will not be + * urldecoded (so the function is consistent with buildQueryData), but the + * second will. If the parameter has no value (i.e. “=” was not present) + * the second argument (value) will be an empty string. */ -goog.dom.DomHelper.prototype.createTable = function(rows, columns, - opt_fillWithNbsp) { - return goog.dom.createTable_(this.document_, rows, columns, - !!opt_fillWithNbsp); +goog.uri.utils.parseQueryData = function(encodedQuery, callback) { + if (!encodedQuery) { + return; + } + var pairs = encodedQuery.split('&'); + for (var i = 0; i < pairs.length; i++) { + var indexOfEquals = pairs[i].indexOf('='); + var name = null; + var value = null; + if (indexOfEquals >= 0) { + name = pairs[i].substring(0, indexOfEquals); + value = pairs[i].substring(indexOfEquals + 1); + } else { + name = pairs[i]; + } + callback(name, value ? goog.string.urlDecode(value) : ''); + } }; /** - * Converts an HTML into a node or a document fragment. A single Node is used if - * {@code html} only generates a single node. If {@code html} generates multiple - * nodes then these are put inside a {@code DocumentFragment}. - * @param {!goog.html.SafeHtml} html The HTML markup to convert. - * @return {!Node} The resulting node. + * Appends a URI and query data in a string buffer with special preconditions. + * + * Internal implementation utility, performing very few object allocations. + * + * @param {!Array<string|undefined>} buffer A string buffer. The first element + * must be the base URI, and may have a fragment identifier. If the array + * contains more than one element, the second element must be an ampersand, + * and may be overwritten, depending on the base URI. Undefined elements + * are treated as empty-string. + * @return {string} The concatenated URI and query data. + * @private */ -goog.dom.DomHelper.prototype.safeHtmlToNode = function(html) { - return goog.dom.safeHtmlToNode_(this.document_, html); +goog.uri.utils.appendQueryData_ = function(buffer) { + if (buffer[1]) { + // At least one query parameter was added. We need to check the + // punctuation mark, which is currently an ampersand, and also make sure + // there aren't any interfering fragment identifiers. + var baseUri = /** @type {string} */ (buffer[0]); + var hashIndex = baseUri.indexOf('#'); + if (hashIndex >= 0) { + // Move the fragment off the base part of the URI into the end. + buffer.push(baseUri.substr(hashIndex)); + buffer[0] = baseUri = baseUri.substr(0, hashIndex); + } + var questionIndex = baseUri.indexOf('?'); + if (questionIndex < 0) { + // No question mark, so we need a question mark instead of an ampersand. + buffer[1] = '?'; + } else if (questionIndex == baseUri.length - 1) { + // Question mark is the very last character of the existing URI, so don't + // append an additional delimiter. + buffer[1] = undefined; + } + } + + return buffer.join(''); }; /** - * Converts an HTML string into a node or a document fragment. A single Node - * is used if the {@code htmlString} only generates a single node. If the - * {@code htmlString} generates multiple nodes then these are put inside a - * {@code DocumentFragment}. - * - * @param {string} htmlString The HTML string to convert. - * @return {!Node} The resulting node. + * Appends key=value pairs to an array, supporting multi-valued objects. + * @param {string} key The key prefix. + * @param {goog.uri.utils.QueryValue} value The value to serialize. + * @param {!Array<string>} pairs The array to which the 'key=value' strings + * should be appended. + * @private */ -goog.dom.DomHelper.prototype.htmlToDocumentFragment = function(htmlString) { - return goog.dom.htmlToDocumentFragment_(this.document_, htmlString); +goog.uri.utils.appendKeyValuePairs_ = function(key, value, pairs) { + if (goog.isArray(value)) { + // Convince the compiler it's an array. + goog.asserts.assertArray(value); + for (var j = 0; j < value.length; j++) { + // Convert to string explicitly, to short circuit the null and array + // logic in this function -- this ensures that null and undefined get + // written as literal 'null' and 'undefined', and arrays don't get + // expanded out but instead encoded in the default way. + goog.uri.utils.appendKeyValuePairs_(key, String(value[j]), pairs); + } + } else if (value != null) { + // Skip a top-level null or undefined entirely. + pairs.push('&', key, + // Check for empty string. Zero gets encoded into the url as literal + // strings. For empty string, skip the equal sign, to be consistent + // with UriBuilder.java. + value === '' ? '' : '=', + goog.string.urlEncode(value)); + } }; /** - * Returns true if the browser is in "CSS1-compatible" (standards-compliant) - * mode, false otherwise. - * @return {boolean} True if in CSS1-compatible mode. + * Builds a buffer of query data from a sequence of alternating keys and values. + * + * @param {!Array<string|undefined>} buffer A string buffer to append to. The + * first element appended will be an '&', and may be replaced by the caller. + * @param {!goog.uri.utils.QueryArray|!Arguments} keysAndValues An array with + * alternating keys and values -- see the typedef. + * @param {number=} opt_startIndex A start offset into the arary, defaults to 0. + * @return {!Array<string|undefined>} The buffer argument. + * @private */ -goog.dom.DomHelper.prototype.isCss1CompatMode = function() { - return goog.dom.isCss1CompatMode_(this.document_); +goog.uri.utils.buildQueryDataBuffer_ = function( + buffer, keysAndValues, opt_startIndex) { + goog.asserts.assert(Math.max(keysAndValues.length - (opt_startIndex || 0), + 0) % 2 == 0, 'goog.uri.utils: Key/value lists must be even in length.'); + + for (var i = opt_startIndex || 0; i < keysAndValues.length; i += 2) { + goog.uri.utils.appendKeyValuePairs_( + keysAndValues[i], keysAndValues[i + 1], buffer); + } + + return buffer; }; /** - * Gets the window object associated with the document. - * @return {!Window} The window associated with the given document. + * Builds a query data string from a sequence of alternating keys and values. + * Currently generates "&key&" for empty args. + * + * @param {goog.uri.utils.QueryArray} keysAndValues Alternating keys and + * values. See the typedef. + * @param {number=} opt_startIndex A start offset into the arary, defaults to 0. + * @return {string} The encoded query string, in the form 'a=1&b=2'. */ -goog.dom.DomHelper.prototype.getWindow = function() { - return goog.dom.getWindow_(this.document_); +goog.uri.utils.buildQueryData = function(keysAndValues, opt_startIndex) { + var buffer = goog.uri.utils.buildQueryDataBuffer_( + [], keysAndValues, opt_startIndex); + buffer[0] = ''; // Remove the leading ampersand. + return buffer.join(''); }; /** - * Gets the document scroll element. - * @return {!Element} Scrolling element. + * Builds a buffer of query data from a map. + * + * @param {!Array<string|undefined>} buffer A string buffer to append to. The + * first element appended will be an '&', and may be replaced by the caller. + * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys + * are URI-encoded parameter keys, and the values conform to the contract + * specified in the goog.uri.utils.QueryValue typedef. + * @return {!Array<string|undefined>} The buffer argument. + * @private */ -goog.dom.DomHelper.prototype.getDocumentScrollElement = function() { - return goog.dom.getDocumentScrollElement_(this.document_); +goog.uri.utils.buildQueryDataBufferFromMap_ = function(buffer, map) { + for (var key in map) { + goog.uri.utils.appendKeyValuePairs_(key, map[key], buffer); + } + + return buffer; }; /** - * Gets the document scroll distance as a coordinate object. - * @return {!goog.math.Coordinate} Object with properties 'x' and 'y'. + * Builds a query data string from a map. + * Currently generates "&key&" for empty args. + * + * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys + * are URI-encoded parameter keys, and the values are arbitrary types + * or arrays. Keys with a null value are dropped. + * @return {string} The encoded query string, in the form 'a=1&b=2'. */ -goog.dom.DomHelper.prototype.getDocumentScroll = function() { - return goog.dom.getDocumentScroll_(this.document_); +goog.uri.utils.buildQueryDataFromMap = function(map) { + var buffer = goog.uri.utils.buildQueryDataBufferFromMap_([], map); + buffer[0] = ''; + return buffer.join(''); }; /** - * Determines the active element in the given document. - * @param {Document=} opt_doc The document to look in. - * @return {Element} The active element. + * Appends URI parameters to an existing URI. + * + * The variable arguments may contain alternating keys and values. Keys are + * assumed to be already URI encoded. The values should not be URI-encoded, + * and will instead be encoded by this function. + * <pre> + * appendParams('http://www.foo.com?existing=true', + * 'key1', 'value1', + * 'key2', 'value?willBeEncoded', + * 'key3', ['valueA', 'valueB', 'valueC'], + * 'key4', null); + * result: 'http://www.foo.com?existing=true&' + + * 'key1=value1&' + + * 'key2=value%3FwillBeEncoded&' + + * 'key3=valueA&key3=valueB&key3=valueC' + * </pre> + * + * A single call to this function will not exhibit quadratic behavior in IE, + * whereas multiple repeated calls may, although the effect is limited by + * fact that URL's generally can't exceed 2kb. + * + * @param {string} uri The original URI, which may already have query data. + * @param {...(goog.uri.utils.QueryArray|string|goog.uri.utils.QueryValue)} var_args + * An array or argument list conforming to goog.uri.utils.QueryArray. + * @return {string} The URI with all query parameters added. */ -goog.dom.DomHelper.prototype.getActiveElement = function(opt_doc) { - return goog.dom.getActiveElement(opt_doc || this.document_); +goog.uri.utils.appendParams = function(uri, var_args) { + return goog.uri.utils.appendQueryData_( + arguments.length == 2 ? + goog.uri.utils.buildQueryDataBuffer_([uri], arguments[1], 0) : + goog.uri.utils.buildQueryDataBuffer_([uri], arguments, 1)); }; /** - * Appends a child to a node. - * @param {Node} parent Parent. - * @param {Node} child Child. + * Appends query parameters from a map. + * + * @param {string} uri The original URI, which may already have query data. + * @param {!Object<goog.uri.utils.QueryValue>} map An object where keys are + * URI-encoded parameter keys, and the values are arbitrary types or arrays. + * Keys with a null value are dropped. + * @return {string} The new parameters. */ -goog.dom.DomHelper.prototype.appendChild = goog.dom.appendChild; +goog.uri.utils.appendParamsFromMap = function(uri, map) { + return goog.uri.utils.appendQueryData_( + goog.uri.utils.buildQueryDataBufferFromMap_([uri], map)); +}; /** - * Appends a node with text or other nodes. - * @param {!Node} parent The node to append nodes to. - * @param {...goog.dom.Appendable} var_args The things to append to the node. - * If this is a Node it is appended as is. - * If this is a string then a text node is appended. - * If this is an array like object then fields 0 to length - 1 are appended. + * Appends a single URI parameter. + * + * Repeated calls to this can exhibit quadratic behavior in IE6 due to the + * way string append works, though it should be limited given the 2kb limit. + * + * @param {string} uri The original URI, which may already have query data. + * @param {string} key The key, which must already be URI encoded. + * @param {*=} opt_value The value, which will be stringized and encoded + * (assumed not already to be encoded). If omitted, undefined, or null, the + * key will be added as a valueless parameter. + * @return {string} The URI with the query parameter added. */ -goog.dom.DomHelper.prototype.append = goog.dom.append; +goog.uri.utils.appendParam = function(uri, key, opt_value) { + var paramArr = [uri, '&', key]; + if (goog.isDefAndNotNull(opt_value)) { + paramArr.push('=', goog.string.urlEncode(opt_value)); + } + return goog.uri.utils.appendQueryData_(paramArr); +}; /** - * Determines if the given node can contain children, intended to be used for - * HTML generation. + * Finds the next instance of a query parameter with the specified name. * - * @param {Node} node The node to check. - * @return {boolean} Whether the node can contain children. + * Does not instantiate any objects. + * + * @param {string} uri The URI to search. May contain a fragment identifier + * if opt_hashIndex is specified. + * @param {number} startIndex The index to begin searching for the key at. A + * match may be found even if this is one character after the ampersand. + * @param {string} keyEncoded The URI-encoded key. + * @param {number} hashOrEndIndex Index to stop looking at. If a hash + * mark is present, it should be its index, otherwise it should be the + * length of the string. + * @return {number} The position of the first character in the key's name, + * immediately after either a question mark or a dot. + * @private */ -goog.dom.DomHelper.prototype.canHaveChildren = goog.dom.canHaveChildren; +goog.uri.utils.findParam_ = function( + uri, startIndex, keyEncoded, hashOrEndIndex) { + var index = startIndex; + var keyLength = keyEncoded.length; + // Search for the key itself and post-filter for surronuding punctuation, + // rather than expensively building a regexp. + while ((index = uri.indexOf(keyEncoded, index)) >= 0 && + index < hashOrEndIndex) { + var precedingChar = uri.charCodeAt(index - 1); + // Ensure that the preceding character is '&' or '?'. + if (precedingChar == goog.uri.utils.CharCode_.AMPERSAND || + precedingChar == goog.uri.utils.CharCode_.QUESTION) { + // Ensure the following character is '&', '=', '#', or NaN + // (end of string). + var followingChar = uri.charCodeAt(index + keyLength); + if (!followingChar || + followingChar == goog.uri.utils.CharCode_.EQUAL || + followingChar == goog.uri.utils.CharCode_.AMPERSAND || + followingChar == goog.uri.utils.CharCode_.HASH) { + return index; + } + } + index += keyLength + 1; + } -/** - * Removes all the child nodes on a DOM node. - * @param {Node} node Node to remove children from. - */ -goog.dom.DomHelper.prototype.removeChildren = goog.dom.removeChildren; + return -1; +}; /** - * Inserts a new node before an existing reference node (i.e., as the previous - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert before. + * Regular expression for finding a hash mark or end of string. + * @type {RegExp} + * @private */ -goog.dom.DomHelper.prototype.insertSiblingBefore = goog.dom.insertSiblingBefore; +goog.uri.utils.hashOrEndRe_ = /#|$/; /** - * Inserts a new node after an existing reference node (i.e., as the next - * sibling). If the reference node has no parent, then does nothing. - * @param {Node} newNode Node to insert. - * @param {Node} refNode Reference node to insert after. + * Determines if the URI contains a specific key. + * + * Performs no object instantiations. + * + * @param {string} uri The URI to process. May contain a fragment + * identifier. + * @param {string} keyEncoded The URI-encoded key. Case-sensitive. + * @return {boolean} Whether the key is present. */ -goog.dom.DomHelper.prototype.insertSiblingAfter = goog.dom.insertSiblingAfter; +goog.uri.utils.hasParam = function(uri, keyEncoded) { + return goog.uri.utils.findParam_(uri, 0, keyEncoded, + uri.search(goog.uri.utils.hashOrEndRe_)) >= 0; +}; /** - * Insert a child at a given index. If index is larger than the number of child - * nodes that the parent currently has, the node is inserted as the last child - * node. - * @param {Element} parent The element into which to insert the child. - * @param {Node} child The element to insert. - * @param {number} index The index at which to insert the new child node. Must - * not be negative. + * Gets the first value of a query parameter. + * @param {string} uri The URI to process. May contain a fragment. + * @param {string} keyEncoded The URI-encoded key. Case-sensitive. + * @return {?string} The first value of the parameter (URI-decoded), or null + * if the parameter is not found. */ -goog.dom.DomHelper.prototype.insertChildAt = goog.dom.insertChildAt; - +goog.uri.utils.getParamValue = function(uri, keyEncoded) { + var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); + var foundIndex = goog.uri.utils.findParam_( + uri, 0, keyEncoded, hashOrEndIndex); -/** - * Removes a node from its parent. - * @param {Node} node The node to remove. - * @return {Node} The node removed if removed; else, null. - */ -goog.dom.DomHelper.prototype.removeNode = goog.dom.removeNode; + if (foundIndex < 0) { + return null; + } else { + var endPosition = uri.indexOf('&', foundIndex); + if (endPosition < 0 || endPosition > hashOrEndIndex) { + endPosition = hashOrEndIndex; + } + // Progress forth to the end of the "key=" or "key&" substring. + foundIndex += keyEncoded.length + 1; + // Use substr, because it (unlike substring) will return empty string + // if foundIndex > endPosition. + return goog.string.urlDecode( + uri.substr(foundIndex, endPosition - foundIndex)); + } +}; /** - * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no - * parent. - * @param {Node} newNode Node to insert. - * @param {Node} oldNode Node to replace. + * Gets all values of a query parameter. + * @param {string} uri The URI to process. May contain a fragment. + * @param {string} keyEncoded The URI-encoded key. Case-sensitive. + * @return {!Array<string>} All URI-decoded values with the given key. + * If the key is not found, this will have length 0, but never be null. */ -goog.dom.DomHelper.prototype.replaceNode = goog.dom.replaceNode; - +goog.uri.utils.getParamValues = function(uri, keyEncoded) { + var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); + var position = 0; + var foundIndex; + var result = []; -/** - * Flattens an element. That is, removes it and replace it with its children. - * @param {Element} element The element to flatten. - * @return {Element|undefined} The original element, detached from the document - * tree, sans children, or undefined if the element was already not in the - * document. - */ -goog.dom.DomHelper.prototype.flattenElement = goog.dom.flattenElement; + while ((foundIndex = goog.uri.utils.findParam_( + uri, position, keyEncoded, hashOrEndIndex)) >= 0) { + // Find where this parameter ends, either the '&' or the end of the + // query parameters. + position = uri.indexOf('&', foundIndex); + if (position < 0 || position > hashOrEndIndex) { + position = hashOrEndIndex; + } + // Progress forth to the end of the "key=" or "key&" substring. + foundIndex += keyEncoded.length + 1; + // Use substr, because it (unlike substring) will return empty string + // if foundIndex > position. + result.push(goog.string.urlDecode(uri.substr( + foundIndex, position - foundIndex))); + } -/** - * Returns an array containing just the element children of the given element. - * @param {Element} element The element whose element children we want. - * @return {!(Array|NodeList)} An array or array-like list of just the element - * children of the given element. - */ -goog.dom.DomHelper.prototype.getChildren = goog.dom.getChildren; + return result; +}; /** - * Returns the first child node that is an element. - * @param {Node} node The node to get the first child element of. - * @return {Element} The first child node of {@code node} that is an element. + * Regexp to find trailing question marks and ampersands. + * @type {RegExp} + * @private */ -goog.dom.DomHelper.prototype.getFirstElementChild = - goog.dom.getFirstElementChild; +goog.uri.utils.trailingQueryPunctuationRe_ = /[?&]($|#)/; /** - * Returns the last child node that is an element. - * @param {Node} node The node to get the last child element of. - * @return {Element} The last child node of {@code node} that is an element. + * Removes all instances of a query parameter. + * @param {string} uri The URI to process. Must not contain a fragment. + * @param {string} keyEncoded The URI-encoded key. + * @return {string} The URI with all instances of the parameter removed. */ -goog.dom.DomHelper.prototype.getLastElementChild = goog.dom.getLastElementChild; - +goog.uri.utils.removeParam = function(uri, keyEncoded) { + var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); + var position = 0; + var foundIndex; + var buffer = []; -/** - * Returns the first next sibling that is an element. - * @param {Node} node The node to get the next sibling element of. - * @return {Element} The next sibling of {@code node} that is an element. - */ -goog.dom.DomHelper.prototype.getNextElementSibling = - goog.dom.getNextElementSibling; + // Look for a query parameter. + while ((foundIndex = goog.uri.utils.findParam_( + uri, position, keyEncoded, hashOrEndIndex)) >= 0) { + // Get the portion of the query string up to, but not including, the ? + // or & starting the parameter. + buffer.push(uri.substring(position, foundIndex)); + // Progress to immediately after the '&'. If not found, go to the end. + // Avoid including the hash mark. + position = Math.min((uri.indexOf('&', foundIndex) + 1) || hashOrEndIndex, + hashOrEndIndex); + } + // Append everything that is remaining. + buffer.push(uri.substr(position)); -/** - * Returns the first previous sibling that is an element. - * @param {Node} node The node to get the previous sibling element of. - * @return {Element} The first previous sibling of {@code node} that is - * an element. - */ -goog.dom.DomHelper.prototype.getPreviousElementSibling = - goog.dom.getPreviousElementSibling; + // Join the buffer, and remove trailing punctuation that remains. + return buffer.join('').replace( + goog.uri.utils.trailingQueryPunctuationRe_, '$1'); +}; /** - * Returns the next node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The next node in the DOM tree, or null if this was the last - * node. + * Replaces all existing definitions of a parameter with a single definition. + * + * Repeated calls to this can exhibit quadratic behavior due to the need to + * find existing instances and reconstruct the string, though it should be + * limited given the 2kb limit. Consider using appendParams to append multiple + * parameters in bulk. + * + * @param {string} uri The original URI, which may already have query data. + * @param {string} keyEncoded The key, which must already be URI encoded. + * @param {*} value The value, which will be stringized and encoded (assumed + * not already to be encoded). + * @return {string} The URI with the query parameter added. */ -goog.dom.DomHelper.prototype.getNextNode = goog.dom.getNextNode; +goog.uri.utils.setParam = function(uri, keyEncoded, value) { + return goog.uri.utils.appendParam( + goog.uri.utils.removeParam(uri, keyEncoded), keyEncoded, value); +}; /** - * Returns the previous node in source order from the given node. - * @param {Node} node The node. - * @return {Node} The previous node in the DOM tree, or null if this was the - * first node. + * Generates a URI path using a given URI and a path with checks to + * prevent consecutive "//". The baseUri passed in must not contain + * query or fragment identifiers. The path to append may not contain query or + * fragment identifiers. + * + * @param {string} baseUri URI to use as the base. + * @param {string} path Path to append. + * @return {string} Updated URI. */ -goog.dom.DomHelper.prototype.getPreviousNode = goog.dom.getPreviousNode; - +goog.uri.utils.appendPath = function(baseUri, path) { + goog.uri.utils.assertNoFragmentsOrQueries_(baseUri); -/** - * Whether the object looks like a DOM node. - * @param {?} obj The object being tested for node likeness. - * @return {boolean} Whether the object looks like a DOM node. - */ -goog.dom.DomHelper.prototype.isNodeLike = goog.dom.isNodeLike; + // Remove any trailing '/' + if (goog.string.endsWith(baseUri, '/')) { + baseUri = baseUri.substr(0, baseUri.length - 1); + } + // Remove any leading '/' + if (goog.string.startsWith(path, '/')) { + path = path.substr(1); + } + return goog.string.buildString(baseUri, '/', path); +}; /** - * Whether the object looks like an Element. - * @param {?} obj The object being tested for Element likeness. - * @return {boolean} Whether the object looks like an Element. + * Replaces the path. + * @param {string} uri URI to use as the base. + * @param {string} path New path. + * @return {string} Updated URI. */ -goog.dom.DomHelper.prototype.isElement = goog.dom.isElement; +goog.uri.utils.setPath = function(uri, path) { + // Add any missing '/'. + if (!goog.string.startsWith(path, '/')) { + path = '/' + path; + } + var parts = goog.uri.utils.split(uri); + return goog.uri.utils.buildFromEncodedParts( + parts[goog.uri.utils.ComponentIndex.SCHEME], + parts[goog.uri.utils.ComponentIndex.USER_INFO], + parts[goog.uri.utils.ComponentIndex.DOMAIN], + parts[goog.uri.utils.ComponentIndex.PORT], + path, + parts[goog.uri.utils.ComponentIndex.QUERY_DATA], + parts[goog.uri.utils.ComponentIndex.FRAGMENT]); +}; /** - * Returns true if the specified value is a Window object. This includes the - * global window for HTML pages, and iframe windows. - * @param {?} obj Variable to test. - * @return {boolean} Whether the variable is a window. + * Standard supported query parameters. + * @enum {string} */ -goog.dom.DomHelper.prototype.isWindow = goog.dom.isWindow; - +goog.uri.utils.StandardQueryParam = { -/** - * Returns an element's parent, if it's an Element. - * @param {Element} element The DOM element. - * @return {Element} The parent, or null if not an Element. - */ -goog.dom.DomHelper.prototype.getParentElement = goog.dom.getParentElement; + /** Unused parameter for unique-ifying. */ + RANDOM: 'zx' +}; /** - * Whether a node contains another node. - * @param {Node} parent The node that should contain the other node. - * @param {Node} descendant The node to test presence of. - * @return {boolean} Whether the parent node contains the descendent node. + * Sets the zx parameter of a URI to a random value. + * @param {string} uri Any URI. + * @return {string} That URI with the "zx" parameter added or replaced to + * contain a random string. */ -goog.dom.DomHelper.prototype.contains = goog.dom.contains; - +goog.uri.utils.makeUnique = function(uri) { + return goog.uri.utils.setParam(uri, + goog.uri.utils.StandardQueryParam.RANDOM, goog.string.getRandomString()); +}; -/** - * Compares the document order of two nodes, returning 0 if they are the same - * node, a negative number if node1 is before node2, and a positive number if - * node2 is before node1. Note that we compare the order the tags appear in the - * document so in the tree <b><i>text</i></b> the B node is considered to be - * before the I node. - * - * @param {Node} node1 The first node to compare. - * @param {Node} node2 The second node to compare. - * @return {number} 0 if the nodes are the same node, a negative number if node1 - * is before node2, and a positive number if node2 is before node1. - */ -goog.dom.DomHelper.prototype.compareNodeOrder = goog.dom.compareNodeOrder; +goog.provide('ol.tilegrid.WMTS'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('ol.proj'); +goog.require('ol.tilegrid.TileGrid'); -/** - * Find the deepest common ancestor of the given nodes. - * @param {...Node} var_args The nodes to find a common ancestor of. - * @return {Node} The common ancestor of the nodes, or null if there is none. - * null will only be returned if two or more of the nodes are from different - * documents. - */ -goog.dom.DomHelper.prototype.findCommonAncestor = goog.dom.findCommonAncestor; /** - * Returns the owner document for a node. - * @param {Node} node The node to get the document for. - * @return {!Document} The document owning the node. + * @classdesc + * Set the grid pattern for sources accessing WMTS tiled-image servers. + * + * @constructor + * @extends {ol.tilegrid.TileGrid} + * @param {olx.tilegrid.WMTSOptions} options WMTS options. + * @struct + * @api */ -goog.dom.DomHelper.prototype.getOwnerDocument = goog.dom.getOwnerDocument; +ol.tilegrid.WMTS = function(options) { + goog.asserts.assert( + options.resolutions.length == options.matrixIds.length, + 'options resolutions and matrixIds must have equal length (%s == %s)', + options.resolutions.length, options.matrixIds.length); -/** - * Cross browser function for getting the document element of an iframe. - * @param {Element} iframe Iframe element. - * @return {!Document} The frame content document. - */ -goog.dom.DomHelper.prototype.getFrameContentDocument = - goog.dom.getFrameContentDocument; + /** + * @private + * @type {!Array.<string>} + */ + this.matrixIds_ = options.matrixIds; + // FIXME: should the matrixIds become optionnal? + goog.base(this, { + extent: options.extent, + origin: options.origin, + origins: options.origins, + resolutions: options.resolutions, + tileSize: options.tileSize, + tileSizes: options.tileSizes, + sizes: options.sizes + }); -/** - * Cross browser function for getting the window of a frame or iframe. - * @param {Element} frame Frame element. - * @return {Window} The window associated with the given frame. - */ -goog.dom.DomHelper.prototype.getFrameContentWindow = - goog.dom.getFrameContentWindow; +}; +goog.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid); /** - * Sets the text content of a node, with cross-browser support. - * @param {Node} node The node to change the text content of. - * @param {string|number} text The value that should replace the node's content. + * @param {number} z Z. + * @return {string} MatrixId.. */ -goog.dom.DomHelper.prototype.setTextContent = goog.dom.setTextContent; +ol.tilegrid.WMTS.prototype.getMatrixId = function(z) { + goog.asserts.assert(0 <= z && z < this.matrixIds_.length, + 'attempted to retrive matrixId for illegal z (%s)', z); + return this.matrixIds_[z]; +}; /** - * Gets the outerHTML of a node, which islike innerHTML, except that it - * actually contains the HTML of the node itself. - * @param {Element} element The element to get the HTML of. - * @return {string} The outerHTML of the given element. + * Get the list of matrix identifiers. + * @return {Array.<string>} MatrixIds. + * @api */ -goog.dom.DomHelper.prototype.getOuterHtml = goog.dom.getOuterHtml; +ol.tilegrid.WMTS.prototype.getMatrixIds = function() { + return this.matrixIds_; +}; /** - * Finds the first descendant node that matches the filter function. This does - * a depth first search. - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {Node|undefined} The found node or undefined if none is found. + * Create a tile grid from a WMTS capabilities matrix set. + * @param {Object} matrixSet An object representing a matrixSet in the + * capabilities document. + * @param {ol.Extent=} opt_extent An optional extent to restrict the tile + * ranges the server provides. + * @return {ol.tilegrid.WMTS} WMTS tileGrid instance. + * @api */ -goog.dom.DomHelper.prototype.findNode = goog.dom.findNode; +ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = + function(matrixSet, opt_extent) { + /** @type {!Array.<number>} */ + var resolutions = []; + /** @type {!Array.<string>} */ + var matrixIds = []; + /** @type {!Array.<ol.Coordinate>} */ + var origins = []; + /** @type {!Array.<ol.Size>} */ + var tileSizes = []; + /** @type {!Array.<ol.Size>} */ + var sizes = []; -/** - * Finds all the descendant nodes that matches the filter function. This does a - * depth first search. - * @param {Node} root The root of the tree to search. - * @param {function(Node) : boolean} p The filter function. - * @return {Array<Node>} The found nodes or an empty array if none are found. - */ -goog.dom.DomHelper.prototype.findNodes = goog.dom.findNodes; + var supportedCRSPropName = 'SupportedCRS'; + var matrixIdsPropName = 'TileMatrix'; + var identifierPropName = 'Identifier'; + var scaleDenominatorPropName = 'ScaleDenominator'; + var topLeftCornerPropName = 'TopLeftCorner'; + var tileWidthPropName = 'TileWidth'; + var tileHeightPropName = 'TileHeight'; + var projection; + projection = ol.proj.get(matrixSet[supportedCRSPropName].replace( + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3')); + var metersPerUnit = projection.getMetersPerUnit(); + // swap origin x and y coordinates if axis orientation is lat/long + var switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne'; -/** - * Returns true if the element has a tab index that allows it to receive - * keyboard focus (tabIndex >= 0), false otherwise. Note that some elements - * natively support keyboard focus, even if they have no tab index. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element has a tab index that allows keyboard - * focus. - */ -goog.dom.DomHelper.prototype.isFocusableTabIndex = goog.dom.isFocusableTabIndex; + goog.array.sort(matrixSet[matrixIdsPropName], function(a, b) { + return b[scaleDenominatorPropName] - a[scaleDenominatorPropName]; + }); + matrixSet[matrixIdsPropName].forEach(function(elt, index, array) { + matrixIds.push(elt[identifierPropName]); + var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit; + var tileWidth = elt[tileWidthPropName]; + var tileHeight = elt[tileHeightPropName]; + if (switchOriginXY) { + origins.push([elt[topLeftCornerPropName][1], + elt[topLeftCornerPropName][0]]); + } else { + origins.push(elt[topLeftCornerPropName]); + } + resolutions.push(resolution); + tileSizes.push(tileWidth == tileHeight ? + tileWidth : [tileWidth, tileHeight]); + // top-left origin, so height is negative + sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]); + }); -/** - * Enables or disables keyboard focus support on the element via its tab index. - * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true - * (or elements that natively support keyboard focus, like form elements) can - * receive keyboard focus. See http://go/tabindex for more info. - * @param {Element} element Element whose tab index is to be changed. - * @param {boolean} enable Whether to set or remove a tab index on the element - * that supports keyboard focus. - */ -goog.dom.DomHelper.prototype.setFocusableTabIndex = - goog.dom.setFocusableTabIndex; + return new ol.tilegrid.WMTS({ + extent: opt_extent, + origins: origins, + resolutions: resolutions, + matrixIds: matrixIds, + tileSizes: tileSizes, + sizes: sizes + }); +}; +goog.provide('ol.source.WMTS'); +goog.provide('ol.source.WMTSRequestEncoding'); -/** - * Returns true if the element can be focused, i.e. it has a tab index that - * allows it to receive keyboard focus (tabIndex >= 0), or it is an element - * that natively supports keyboard focus. - * @param {!Element} element Element to check. - * @return {boolean} Whether the element allows keyboard focus. - */ -goog.dom.DomHelper.prototype.isFocusable = goog.dom.isFocusable; +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('goog.uri.utils'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.TileUrlFunctionType'); +goog.require('ol.array'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.source.TileImage'); +goog.require('ol.tilegrid.WMTS'); /** - * Returns the text contents of the current node, without markup. New lines are - * stripped and whitespace is collapsed, such that each character would be - * visible. - * - * In browsers that support it, innerText is used. Other browsers attempt to - * simulate it via node traversal. Line breaks are canonicalized in IE. - * - * @param {Node} node The node from which we are getting content. - * @return {string} The text content. + * Request encoding. One of 'KVP', 'REST'. + * @enum {string} + * @api */ -goog.dom.DomHelper.prototype.getTextContent = goog.dom.getTextContent; - +ol.source.WMTSRequestEncoding = { + KVP: 'KVP', // see spec §8 + REST: 'REST' // see spec §10 +}; -/** - * Returns the text length of the text contained in a node, without markup. This - * is equivalent to the selection length if the node was selected, or the number - * of cursor movements to traverse the node. Images & BRs take one space. New - * lines are ignored. - * - * @param {Node} node The node whose text content length is being calculated. - * @return {number} The length of {@code node}'s text content. - */ -goog.dom.DomHelper.prototype.getNodeTextLength = goog.dom.getNodeTextLength; /** - * Returns the text offset of a node relative to one of its ancestors. The text - * length is the same as the length calculated by - * {@code goog.dom.getNodeTextLength}. + * @classdesc + * Layer source for tile data from WMTS servers. * - * @param {Node} node The node whose offset is being calculated. - * @param {Node=} opt_offsetParent Defaults to the node's owner document's body. - * @return {number} The text offset. + * @constructor + * @extends {ol.source.TileImage} + * @param {olx.source.WMTSOptions} options WMTS options. + * @api stable */ -goog.dom.DomHelper.prototype.getNodeTextOffset = goog.dom.getNodeTextOffset; +ol.source.WMTS = function(options) { + // TODO: add support for TileMatrixLimits -/** - * Returns the node at a given offset in a parent node. If an object is - * provided for the optional third parameter, the node and the remainder of the - * offset will stored as properties of this object. - * @param {Node} parent The parent node. - * @param {number} offset The offset into the parent node. - * @param {Object=} opt_result Object to be used to store the return value. The - * return value will be stored in the form {node: Node, remainder: number} - * if this object is provided. - * @return {Node} The node at the given offset. - */ -goog.dom.DomHelper.prototype.getNodeAtOffset = goog.dom.getNodeAtOffset; + /** + * @private + * @type {string} + */ + this.version_ = options.version !== undefined ? options.version : '1.0.0'; + /** + * @private + * @type {string} + */ + this.format_ = options.format !== undefined ? options.format : 'image/jpeg'; -/** - * Returns true if the object is a {@code NodeList}. To qualify as a NodeList, - * the object must have a numeric length property and an item function (which - * has type 'string' on IE for some reason). - * @param {Object} val Object to test. - * @return {boolean} Whether the object is a NodeList. - */ -goog.dom.DomHelper.prototype.isNodeList = goog.dom.isNodeList; + /** + * @private + * @type {Object} + */ + this.dimensions_ = options.dimensions !== undefined ? options.dimensions : {}; + /** + * @private + * @type {string} + */ + this.dimensionsKey_ = ''; + this.resetDimensionsKey_(); -/** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * tag name and/or class name. If the passed element matches the specified - * criteria, the element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or - * null/undefined to match only based on class name). - * @param {?string=} opt_class The class name to match (or null/undefined to - * match only based on tag name). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if no match is found. - */ -goog.dom.DomHelper.prototype.getAncestorByTagNameAndClass = - goog.dom.getAncestorByTagNameAndClass; + /** + * @private + * @type {string} + */ + this.layer_ = options.layer; + /** + * @private + * @type {string} + */ + this.matrixSet_ = options.matrixSet; -/** - * Walks up the DOM hierarchy returning the first ancestor that has the passed - * class name. If the passed element matches the specified criteria, the - * element itself is returned. - * @param {Node} element The DOM node to start with. - * @param {string} class The class name to match. - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Element} The first ancestor that matches the passed criteria, or - * null if none match. - */ -goog.dom.DomHelper.prototype.getAncestorByClass = - goog.dom.getAncestorByClass; + /** + * @private + * @type {string} + */ + this.style_ = options.style; + var urls = options.urls; + if (urls === undefined && options.url !== undefined) { + urls = ol.TileUrlFunction.expandUrl(options.url); + } -/** - * Walks up the DOM hierarchy returning the first ancestor that passes the - * matcher function. - * @param {Node} element The DOM node to start with. - * @param {function(Node) : boolean} matcher A function that returns true if the - * passed node matches the desired criteria. - * @param {boolean=} opt_includeNode If true, the node itself is included in - * the search (the first call to the matcher will pass startElement as - * the node to test). - * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the - * dom. - * @return {Node} DOM node that matched the matcher, or null if there was - * no match. - */ -goog.dom.DomHelper.prototype.getAncestor = goog.dom.getAncestor; + // FIXME: should we guess this requestEncoding from options.url(s) + // structure? that would mean KVP only if a template is not provided. -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + /** + * @private + * @type {ol.source.WMTSRequestEncoding} + */ + this.requestEncoding_ = options.requestEncoding !== undefined ? + /** @type {ol.source.WMTSRequestEncoding} */ (options.requestEncoding) : + ol.source.WMTSRequestEncoding.KVP; -/** - * @fileoverview Utilities for detecting, adding and removing classes. Prefer - * this over goog.dom.classes for new code since it attempts to use classList - * (DOMTokenList: http://dom.spec.whatwg.org/#domtokenlist) which is faster - * and requires less code. - * - * Note: these utilities are meant to operate on HTMLElements - * and may have unexpected behavior on elements with differing interfaces - * (such as SVGElements). - */ + var requestEncoding = this.requestEncoding_; + // FIXME: should we create a default tileGrid? + // we could issue a getCapabilities xhr to retrieve missing configuration + var tileGrid = options.tileGrid; -goog.provide('goog.dom.classlist'); + // context property names are lower case to allow for a case insensitive + // replacement as some services use different naming conventions + var context = { + 'layer': this.layer_, + 'style': this.style_, + 'tilematrixset': this.matrixSet_ + }; -goog.require('goog.array'); + if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { + goog.object.extend(context, { + 'Service': 'WMTS', + 'Request': 'GetTile', + 'Version': this.version_, + 'Format': this.format_ + }); + } + var dimensions = this.dimensions_; -/** - * Override this define at build-time if you know your target supports it. - * @define {boolean} Whether to use the classList property (DOMTokenList). - */ -goog.define('goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST', false); + /** + * @param {string} template Template. + * @return {ol.TileUrlFunctionType} Tile URL function. + */ + function createFromWMTSTemplate(template) { + // TODO: we may want to create our own appendParams function so that params + // order conforms to wmts spec guidance, and so that we can avoid to escape + // special template params -/** - * Gets an array-like object of class names on an element. - * @param {Element} element DOM node to get the classes of. - * @return {!goog.array.ArrayLike} Class names on {@code element}. - */ -goog.dom.classlist.get = function(element) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - return element.classList; + template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ? + goog.uri.utils.appendParamsFromMap(template, context) : + template.replace(/\{(\w+?)\}/g, function(m, p) { + return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m; + }); + + return ( + /** + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. + */ + function(tileCoord, pixelRatio, projection) { + if (!tileCoord) { + return undefined; + } else { + var localContext = { + 'TileMatrix': tileGrid.getMatrixId(tileCoord[0]), + 'TileCol': tileCoord[1], + 'TileRow': -tileCoord[2] - 1 + }; + goog.object.extend(localContext, dimensions); + var url = template; + if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { + url = goog.uri.utils.appendParamsFromMap(url, localContext); + } else { + url = url.replace(/\{(\w+?)\}/g, function(m, p) { + return localContext[p]; + }); + } + return url; + } + }); } - var className = element.className; - // Some types of elements don't have a className in IE (e.g. iframes). - // Furthermore, in Firefox, className is not a string when the element is - // an SVG element. - return goog.isString(className) && className.match(/\S+/g) || []; + var tileUrlFunction = (urls && urls.length > 0) ? + ol.TileUrlFunction.createFromTileUrlFunctions( + urls.map(createFromWMTSTemplate)) : + ol.TileUrlFunction.nullTileUrlFunction; + + goog.base(this, { + attributions: options.attributions, + crossOrigin: options.crossOrigin, + logo: options.logo, + projection: options.projection, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileClass: options.tileClass, + tileGrid: tileGrid, + tileLoadFunction: options.tileLoadFunction, + tilePixelRatio: options.tilePixelRatio, + tileUrlFunction: tileUrlFunction, + urls: urls, + wrapX: options.wrapX !== undefined ? options.wrapX : false + }); + }; +goog.inherits(ol.source.WMTS, ol.source.TileImage); /** - * Sets the entire class name of an element. - * @param {Element} element DOM node to set class of. - * @param {string} className Class name(s) to apply to element. + * Get the dimensions, i.e. those passed to the constructor through the + * "dimensions" option, and possibly updated using the updateDimensions + * method. + * @return {Object} Dimensions. + * @api */ -goog.dom.classlist.set = function(element, className) { - element.className = className; +ol.source.WMTS.prototype.getDimensions = function() { + return this.dimensions_; }; /** - * Returns true if an element has a class. This method may throw a DOM - * exception for an invalid or empty class name if DOMTokenList is used. - * @param {Element} element DOM node to test. - * @param {string} className Class name to test for. - * @return {boolean} Whether element has the class. + * Return the image format of the WMTS source. + * @return {string} Format. + * @api */ -goog.dom.classlist.contains = function(element, className) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - return element.classList.contains(className); - } - return goog.array.contains(goog.dom.classlist.get(element), className); +ol.source.WMTS.prototype.getFormat = function() { + return this.format_; }; /** - * Adds a class to an element. Does not add multiples of class names. This - * method may throw a DOM exception for an invalid or empty class name if - * DOMTokenList is used. - * @param {Element} element DOM node to add class to. - * @param {string} className Class name to add. + * @inheritDoc */ -goog.dom.classlist.add = function(element, className) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - element.classList.add(className); - return; - } - - if (!goog.dom.classlist.contains(element, className)) { - // Ensure we add a space if this is not the first class name added. - element.className += element.className.length > 0 ? - (' ' + className) : className; - } +ol.source.WMTS.prototype.getKeyParams = function() { + return this.dimensionsKey_; }; /** - * Convenience method to add a number of class names at once. - * @param {Element} element The element to which to add classes. - * @param {goog.array.ArrayLike<string>} classesToAdd An array-like object - * containing a collection of class names to add to the element. - * This method may throw a DOM exception if classesToAdd contains invalid - * or empty class names. + * Return the layer of the WMTS source. + * @return {string} Layer. + * @api */ -goog.dom.classlist.addAll = function(element, classesToAdd) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - goog.array.forEach(classesToAdd, function(className) { - goog.dom.classlist.add(element, className); - }); - return; - } +ol.source.WMTS.prototype.getLayer = function() { + return this.layer_; +}; - var classMap = {}; - // Get all current class names into a map. - goog.array.forEach(goog.dom.classlist.get(element), - function(className) { - classMap[className] = true; - }); +/** + * Return the matrix set of the WMTS source. + * @return {string} MatrixSet. + * @api + */ +ol.source.WMTS.prototype.getMatrixSet = function() { + return this.matrixSet_; +}; - // Add new class names to the map. - goog.array.forEach(classesToAdd, - function(className) { - classMap[className] = true; - }); - // Flatten the keys of the map into the className. - element.className = ''; - for (var className in classMap) { - element.className += element.className.length > 0 ? - (' ' + className) : className; - } +/** + * Return the request encoding, either "KVP" or "REST". + * @return {ol.source.WMTSRequestEncoding} Request encoding. + * @api + */ +ol.source.WMTS.prototype.getRequestEncoding = function() { + return this.requestEncoding_; }; /** - * Removes a class from an element. This method may throw a DOM exception - * for an invalid or empty class name if DOMTokenList is used. - * @param {Element} element DOM node to remove class from. - * @param {string} className Class name to remove. + * Return the style of the WMTS source. + * @return {string} Style. + * @api */ -goog.dom.classlist.remove = function(element, className) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - element.classList.remove(className); - return; - } +ol.source.WMTS.prototype.getStyle = function() { + return this.style_; +}; - if (goog.dom.classlist.contains(element, className)) { - // Filter out the class name. - element.className = goog.array.filter( - goog.dom.classlist.get(element), - function(c) { - return c != className; - }).join(' '); - } + +/** + * Return the version of the WMTS source. + * @return {string} Version. + * @api + */ +ol.source.WMTS.prototype.getVersion = function() { + return this.version_; }; /** - * Removes a set of classes from an element. Prefer this call to - * repeatedly calling {@code goog.dom.classlist.remove} if you want to remove - * a large set of class names at once. - * @param {Element} element The element from which to remove classes. - * @param {goog.array.ArrayLike<string>} classesToRemove An array-like object - * containing a collection of class names to remove from the element. - * This method may throw a DOM exception if classesToRemove contains invalid - * or empty class names. - */ -goog.dom.classlist.removeAll = function(element, classesToRemove) { - if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { - goog.array.forEach(classesToRemove, function(className) { - goog.dom.classlist.remove(element, className); - }); - return; - } - // Filter out those classes in classesToRemove. - element.className = goog.array.filter( - goog.dom.classlist.get(element), - function(className) { - // If this class is not one we are trying to remove, - // add it to the array of new class names. - return !goog.array.contains(classesToRemove, className); - }).join(' '); -}; - - -/** - * Adds or removes a class depending on the enabled argument. This method - * may throw a DOM exception for an invalid or empty class name if DOMTokenList - * is used. - * @param {Element} element DOM node to add or remove the class on. - * @param {string} className Class name to add or remove. - * @param {boolean} enabled Whether to add or remove the class (true adds, - * false removes). - */ -goog.dom.classlist.enable = function(element, className, enabled) { - if (enabled) { - goog.dom.classlist.add(element, className); - } else { - goog.dom.classlist.remove(element, className); - } -}; - - -/** - * Adds or removes a set of classes depending on the enabled argument. This - * method may throw a DOM exception for an invalid or empty class name if - * DOMTokenList is used. - * @param {!Element} element DOM node to add or remove the class on. - * @param {goog.array.ArrayLike<string>} classesToEnable An array-like object - * containing a collection of class names to add or remove from the element. - * @param {boolean} enabled Whether to add or remove the classes (true adds, - * false removes). - */ -goog.dom.classlist.enableAll = function(element, classesToEnable, enabled) { - var f = enabled ? goog.dom.classlist.addAll : - goog.dom.classlist.removeAll; - f(element, classesToEnable); -}; - - -/** - * Switches a class on an element from one to another without disturbing other - * classes. If the fromClass isn't removed, the toClass won't be added. This - * method may throw a DOM exception if the class names are empty or invalid. - * @param {Element} element DOM node to swap classes on. - * @param {string} fromClass Class to remove. - * @param {string} toClass Class to add. - * @return {boolean} Whether classes were switched. + * @private */ -goog.dom.classlist.swap = function(element, fromClass, toClass) { - if (goog.dom.classlist.contains(element, fromClass)) { - goog.dom.classlist.remove(element, fromClass); - goog.dom.classlist.add(element, toClass); - return true; +ol.source.WMTS.prototype.resetDimensionsKey_ = function() { + var i = 0; + var res = []; + for (var key in this.dimensions_) { + res[i++] = key + '-' + this.dimensions_[key]; } - return false; + this.dimensionsKey_ = res.join('/'); }; /** - * Removes a class if an element has it, and adds it the element doesn't have - * it. Won't affect other classes on the node. This method may throw a DOM - * exception if the class name is empty or invalid. - * @param {Element} element DOM node to toggle class on. - * @param {string} className Class to toggle. - * @return {boolean} True if class was added, false if it was removed - * (in other words, whether element has the class after this function has - * been called). + * Update the dimensions. + * @param {Object} dimensions Dimensions. + * @api */ -goog.dom.classlist.toggle = function(element, className) { - var add = !goog.dom.classlist.contains(element, className); - goog.dom.classlist.enable(element, className, add); - return add; +ol.source.WMTS.prototype.updateDimensions = function(dimensions) { + goog.object.extend(this.dimensions_, dimensions); + this.resetDimensionsKey_(); + this.changed(); }; /** - * Adds and removes a class of an element. Unlike - * {@link goog.dom.classlist.swap}, this method adds the classToAdd regardless - * of whether the classToRemove was present and had been removed. This method - * may throw a DOM exception if the class names are empty or invalid. + * Generate source options from a capabilities object. + * @param {Object} wmtsCap An object representing the capabilities document. + * @param {Object} config Configuration properties for the layer. Defaults for + * the layer will apply if not provided. * - * @param {Element} element DOM node to swap classes on. - * @param {string} classToRemove Class to remove. - * @param {string} classToAdd Class to add. + * Required config properties: + * layer - {String} The layer identifier. + * + * Optional config properties: + * matrixSet - {String} The matrix set identifier, required if there is + * more than one matrix set in the layer capabilities. + * projection - {String} The desired CRS when no matrixSet is specified. + * eg: "EPSG:3857". If the desired projection is not available, + * an error is thrown. + * requestEncoding - {String} url encoding format for the layer. Default is the + * first tile url format found in the GetCapabilities response. + * style - {String} The name of the style + * format - {String} Image format for the layer. Default is the first + * format returned in the GetCapabilities response. + * @return {olx.source.WMTSOptions} WMTS source options object. + * @api */ -goog.dom.classlist.addRemove = function(element, classToRemove, classToAdd) { - goog.dom.classlist.remove(element, classToRemove); - goog.dom.classlist.add(element, classToAdd); -}; - -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { -/** - * @fileoverview Vendor prefix getters. - */ + // TODO: add support for TileMatrixLimits + goog.asserts.assert(config['layer'], + 'config "layer" must not be null'); -goog.provide('goog.dom.vendor'); + var layers = wmtsCap['Contents']['Layer']; + var l = goog.array.find(layers, function(elt, index, array) { + return elt['Identifier'] == config['layer']; + }); + goog.asserts.assert(l, 'found a matching layer in Contents/Layer'); -goog.require('goog.string'); -goog.require('goog.userAgent'); + goog.asserts.assert(l['TileMatrixSetLink'].length > 0, + 'layer has TileMatrixSetLink'); + var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet']; + var idx, matrixSet; + if (l['TileMatrixSetLink'].length > 1) { + if ('projection' in config) { + idx = goog.array.findIndex(l['TileMatrixSetLink'], + function(elt, index, array) { + var tileMatrixSet = goog.array.find(tileMatrixSets, function(el) { + return el['Identifier'] == elt['TileMatrixSet']; + }); + return tileMatrixSet['SupportedCRS'].replace( + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3' + ) == config['projection']; + }); + } else { + idx = goog.array.findIndex(l['TileMatrixSetLink'], + function(elt, index, array) { + return elt['TileMatrixSet'] == config['matrixSet']; + }); + } + } else { + idx = 0; + } + if (idx < 0) { + idx = 0; + } + matrixSet = /** @type {string} */ + (l['TileMatrixSetLink'][idx]['TileMatrixSet']); + goog.asserts.assert(matrixSet, 'TileMatrixSet must not be null'); -/** - * Returns the JS vendor prefix used in CSS properties. Different vendors - * use different methods of changing the case of the property names. - * - * @return {?string} The JS vendor prefix or null if there is none. - */ -goog.dom.vendor.getVendorJsPrefix = function() { - if (goog.userAgent.WEBKIT) { - return 'Webkit'; - } else if (goog.userAgent.GECKO) { - return 'Moz'; - } else if (goog.userAgent.IE) { - return 'ms'; - } else if (goog.userAgent.OPERA) { - return 'O'; + var format = /** @type {string} */ (l['Format'][0]); + if ('format' in config) { + format = config['format']; + } + idx = goog.array.findIndex(l['Style'], function(elt, index, array) { + if ('style' in config) { + return elt['Title'] == config['style']; + } else { + return elt['isDefault']; + } + }); + if (idx < 0) { + idx = 0; } + var style = /** @type {string} */ (l['Style'][idx]['Identifier']); - return null; -}; + var dimensions = {}; + if ('Dimension' in l) { + l['Dimension'].forEach(function(elt, index, array) { + var key = elt['Identifier']; + var value = elt['Default']; + if (value !== undefined) { + goog.asserts.assert(ol.array.includes(elt['Value'], value), + 'default value contained in values'); + } else { + value = elt['Value'][0]; + } + goog.asserts.assert(value !== undefined, 'value could be found'); + dimensions[key] = value; + }); + } + var matrixSets = wmtsCap['Contents']['TileMatrixSet']; + var matrixSetObj = goog.array.find(matrixSets, function(elt, index, array) { + return elt['Identifier'] == matrixSet; + }); + goog.asserts.assert(matrixSetObj, + 'found matrixSet in Contents/TileMatrixSet'); -/** - * Returns the vendor prefix used in CSS properties. - * - * @return {?string} The vendor prefix or null if there is none. - */ -goog.dom.vendor.getVendorPrefix = function() { - if (goog.userAgent.WEBKIT) { - return '-webkit'; - } else if (goog.userAgent.GECKO) { - return '-moz'; - } else if (goog.userAgent.IE) { - return '-ms'; - } else if (goog.userAgent.OPERA) { - return '-o'; + var projection; + if ('projection' in config) { + projection = ol.proj.get(config['projection']); + } else { + projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace( + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3')); } - return null; -}; + var wgs84BoundingBox = l['WGS84BoundingBox']; + var extent, wrapX; + if (wgs84BoundingBox !== undefined) { + var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent(); + wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] && + wgs84BoundingBox[2] == wgs84ProjectionExtent[2]); + extent = ol.proj.transformExtent( + wgs84BoundingBox, 'EPSG:4326', projection); + var projectionExtent = projection.getExtent(); + if (projectionExtent) { + // If possible, do a sanity check on the extent - it should never be + // bigger than the validity extent of the projection of a matrix set. + if (!ol.extent.containsExtent(projectionExtent, extent)) { + extent = undefined; + } + } + } + var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( + matrixSetObj, extent); -/** - * @param {string} propertyName A property name. - * @param {!Object=} opt_object If provided, we verify if the property exists in - * the object. - * @return {?string} A vendor prefixed property name, or null if it does not - * exist. - */ -goog.dom.vendor.getPrefixedPropertyName = function(propertyName, opt_object) { - // We first check for a non-prefixed property, if available. - if (opt_object && propertyName in opt_object) { - return propertyName; - } - var prefix = goog.dom.vendor.getVendorJsPrefix(); - if (prefix) { - prefix = prefix.toLowerCase(); - var prefixedPropertyName = prefix + goog.string.toTitleCase(propertyName); - return (!goog.isDef(opt_object) || prefixedPropertyName in opt_object) ? - prefixedPropertyName : null; - } - return null; -}; + /** @type {!Array.<string>} */ + var urls = []; + var requestEncoding = config['requestEncoding']; + requestEncoding = requestEncoding !== undefined ? requestEncoding : ''; + goog.asserts.assert( + ol.array.includes(['REST', 'RESTful', 'KVP', ''], requestEncoding), + 'requestEncoding (%s) is one of "REST", "RESTful", "KVP" or ""', + requestEncoding); -/** - * @param {string} eventType An event type. - * @return {string} A lower-cased vendor prefixed event type. - */ -goog.dom.vendor.getPrefixedEventType = function(eventType) { - var prefix = goog.dom.vendor.getVendorJsPrefix() || ''; - return (prefix + eventType).toLowerCase(); -}; + if (!wmtsCap.hasOwnProperty('OperationsMetadata') || + !wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') || + requestEncoding.indexOf('REST') === 0) { + // Add REST tile resource url + requestEncoding = ol.source.WMTSRequestEncoding.REST; + l['ResourceURL'].forEach(function(elt, index, array) { + if (elt['resourceType'] == 'tile') { + format = elt['format']; + urls.push(/** @type {string} */ (elt['template'])); + } + }); + } else { + var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get']; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + for (var i = 0, ii = gets.length; i < ii; ++i) { + var constraint = goog.array.find(gets[i]['Constraint'], + function(elt, index, array) { + return elt['name'] == 'GetEncoding'; + }); + var encodings = constraint['AllowedValues']['Value']; + if (encodings.length > 0 && ol.array.includes(encodings, 'KVP')) { + requestEncoding = ol.source.WMTSRequestEncoding.KVP; + urls.push(/** @type {string} */ (gets[i]['href'])); + } + } + } + goog.asserts.assert(urls.length > 0, 'At least one URL found'); -/** - * @fileoverview A utility class for representing a numeric box. - */ + return { + urls: urls, + layer: config['layer'], + matrixSet: matrixSet, + format: format, + projection: projection, + requestEncoding: requestEncoding, + tileGrid: tileGrid, + style: style, + dimensions: dimensions, + wrapX: wrapX + }; +}; -goog.provide('goog.math.Box'); +goog.provide('olcs.core.OLImageryProvider'); -goog.require('goog.math.Coordinate'); +goog.require('goog.events'); +goog.require('ol.proj'); /** - * Class for representing a box. A box is specified as a top, right, bottom, - * and left. A box is useful for representing margins and padding. - * - * This class assumes 'screen coordinates': larger Y coordinates are further - * from the top of the screen. - * - * @param {number} top Top. - * @param {number} right Right. - * @param {number} bottom Bottom. - * @param {number} left Left. - * @struct + * Special class derived from Cesium.ImageryProvider + * that is connected to the given ol.source.TileImage. + * @param {!ol.source.TileImage} source + * @param {ol.proj.Projection=} opt_fallbackProj Projection to assume if the + * projection of the source + * is not defined. * @constructor + * @extends {Cesium.ImageryProvider} */ -goog.math.Box = function(top, right, bottom, left) { - /** - * Top - * @type {number} - */ - this.top = top; +olcs.core.OLImageryProvider = function(source, opt_fallbackProj) { + // Do not goog.inherit() or call super constructor from + // Cesium.ImageryProvider since this particular function is a + // 'non instanciable interface' which throws on instanciation. /** - * Right - * @type {number} + * @type {!ol.source.TileImage} + * @private */ - this.right = right; + this.source_ = source; /** - * Bottom - * @type {number} + * @type {?ol.proj.Projection} + * @private */ - this.bottom = bottom; + this.projection_ = null; /** - * Left - * @type {number} + * @type {?ol.proj.Projection} + * @private */ - this.left = left; -}; + this.fallbackProj_ = goog.isDef(opt_fallbackProj) ? opt_fallbackProj : null; + this.ready_ = false; -/** - * Creates a Box by bounding a collection of goog.math.Coordinate objects - * @param {...goog.math.Coordinate} var_args Coordinates to be included inside - * the box. - * @return {!goog.math.Box} A Box containing all the specified Coordinates. - */ -goog.math.Box.boundingBox = function(var_args) { - var box = new goog.math.Box(arguments[0].y, arguments[0].x, - arguments[0].y, arguments[0].x); - for (var i = 1; i < arguments.length; i++) { - box.expandToIncludeCoordinate(arguments[i]); - } - return box; -}; + this.errorEvent_ = new Cesium.Event(); + this.emptyCanvas_ = goog.dom.createElement(goog.dom.TagName.CANVAS); + this.emptyCanvas_.width = 1; + this.emptyCanvas_.height = 1; -/** - * @return {number} width The width of this Box. - */ -goog.math.Box.prototype.getWidth = function() { - return this.right - this.left; + this.source_.on(goog.events.EventType.CHANGE, function(e) { + this.handleSourceChanged_(); + }, this); + this.handleSourceChanged_(); }; -/** - * @return {number} height The height of this Box. - */ -goog.math.Box.prototype.getHeight = function() { - return this.bottom - this.top; -}; - +// definitions of getters that are required to be present +// in the Cesium.ImageryProvider instance: +Object.defineProperties(olcs.core.OLImageryProvider.prototype, { + ready: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() {return this.ready_;} + }, -/** - * Creates a copy of the box with the same dimensions. - * @return {!goog.math.Box} A clone of this Box. - */ -goog.math.Box.prototype.clone = function() { - return new goog.math.Box(this.top, this.right, this.bottom, this.left); -}; + rectangle: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() {return this.rectangle_;} + }, + tileWidth: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() { + var tg = this.source_.getTileGrid(); + return !goog.isNull(tg) ? tg.getTileSize(0) : 256; + } + }, -if (goog.DEBUG) { - /** - * Returns a nice string representing the box. - * @return {string} In the form (50t, 73r, 24b, 13l). - * @override - */ - goog.math.Box.prototype.toString = function() { - return '(' + this.top + 't, ' + this.right + 'r, ' + this.bottom + 'b, ' + - this.left + 'l)'; - }; -} + tileHeight: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() {return this.tileWidth;} + }, + maximumLevel: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() { + var tg = this.source_.getTileGrid(); + return !goog.isNull(tg) ? tg.getMaxZoom() : 18; + } + }, -/** - * Returns whether the box contains a coordinate or another box. - * - * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box. - * @return {boolean} Whether the box contains the coordinate or other box. - */ -goog.math.Box.prototype.contains = function(other) { - return goog.math.Box.contains(this, other); -}; + minimumLevel: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() { + // WARNING: Do not use the minimum level (at least until the extent is + // properly set). Cesium assumes the minimumLevel to contain only + // a few tiles and tries to load them all at once -- this can + // freeze and/or crash the browser ! + return 0; + //var tg = this.source_.getTileGrid(); + //return !goog.isNull(tg) ? tg.getMinZoom() : 0; + } + }, + tilingScheme: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() {return this.tilingScheme_;} + }, -/** - * Expands box with the given margins. - * - * @param {number|goog.math.Box} top Top margin or box with all margins. - * @param {number=} opt_right Right margin. - * @param {number=} opt_bottom Bottom margin. - * @param {number=} opt_left Left margin. - * @return {!goog.math.Box} A reference to this Box. - */ -goog.math.Box.prototype.expand = function(top, opt_right, opt_bottom, - opt_left) { - if (goog.isObject(top)) { - this.top -= top.top; - this.right += top.right; - this.bottom += top.bottom; - this.left -= top.left; - } else { - this.top -= top; - this.right += opt_right; - this.bottom += opt_bottom; - this.left -= opt_left; - } + tileDiscardPolicy: { + get: function() {return undefined;} + }, - return this; -}; + errorEvent: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() {return this.errorEvent_;} + }, + credit: { + get: /** @this {olcs.core.OLImageryProvider} */ + function() {return this.credit_;} + }, -/** - * Expand this box to include another box. - * NOTE(user): This is used in code that needs to be very fast, please don't - * add functionality to this function at the expense of speed (variable - * arguments, accepting multiple argument types, etc). - * @param {goog.math.Box} box The box to include in this one. - */ -goog.math.Box.prototype.expandToInclude = function(box) { - this.left = Math.min(this.left, box.left); - this.top = Math.min(this.top, box.top); - this.right = Math.max(this.right, box.right); - this.bottom = Math.max(this.bottom, box.bottom); -}; + proxy: { + get: function() {return undefined;} + }, + hasAlphaChannel: { + get: function() {return true;} + }, -/** - * Expand this box to include the coordinate. - * @param {!goog.math.Coordinate} coord The coordinate to be included - * inside the box. - */ -goog.math.Box.prototype.expandToIncludeCoordinate = function(coord) { - this.top = Math.min(this.top, coord.y); - this.right = Math.max(this.right, coord.x); - this.bottom = Math.max(this.bottom, coord.y); - this.left = Math.min(this.left, coord.x); -}; + pickFeatures: { + get: function() {return undefined;} + } +}); /** - * Compares boxes for equality. - * @param {goog.math.Box} a A Box. - * @param {goog.math.Box} b A Box. - * @return {boolean} True iff the boxes are equal, or if both are null. + * Checks if the underlying source is ready and cached required data. + * @private */ -goog.math.Box.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; +olcs.core.OLImageryProvider.prototype.handleSourceChanged_ = function() { + if (!this.ready_ && this.source_.getState() == 'ready') { + var proj = this.source_.getProjection(); + this.projection_ = goog.isDefAndNotNull(proj) ? proj : this.fallbackProj_; + if (this.projection_ == ol.proj.get('EPSG:4326')) { + this.tilingScheme_ = new Cesium.GeographicTilingScheme(); + } else if (this.projection_ == ol.proj.get('EPSG:3857')) { + this.tilingScheme_ = new Cesium.WebMercatorTilingScheme(); + } else { + return; + } + this.rectangle_ = this.tilingScheme_.rectangle; + + var credit = + olcs.core.OLImageryProvider.createCreditForSource(this.source_); + this.credit_ = !goog.isNull(credit) ? credit : undefined; + + this.ready_ = true; } - return a.top == b.top && a.right == b.right && - a.bottom == b.bottom && a.left == b.left; }; /** - * Returns whether a box contains a coordinate or another box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box. - * @return {boolean} Whether the box contains the coordinate or other box. + * Tries to create proper Cesium.Credit for + * the given ol.source.Source as closely as possible. + * @param {!ol.source.Source} source + * @return {?Cesium.Credit} */ -goog.math.Box.contains = function(box, other) { - if (!box || !other) { - return false; +olcs.core.OLImageryProvider.createCreditForSource = function(source) { + var text = ''; + var attributions = source.getAttributions(); + if (!goog.isNull(attributions)) { + attributions.forEach(function(el) { + // strip html tags (not supported in Cesium) + text += el.getHTML().replace(/<\/?[^>]+(>|$)/g, '') + ' '; + }); } - if (other instanceof goog.math.Box) { - return other.left >= box.left && other.right <= box.right && - other.top >= box.top && other.bottom <= box.bottom; + var imageUrl, link; + if (text.length == 0) { + // only use logo if no text is specified + // otherwise the Cesium will automatically skip the text: + // "The text to be displayed on the screen if no imageUrl is specified." + var logo = source.getLogo(); + if (goog.isDef(logo)) { + if (typeof logo == 'string') { + imageUrl = logo; + } else { + imageUrl = logo.src; + link = logo.href; + } + } } - // other is a Coordinate. - return other.x >= box.left && other.x <= box.right && - other.y >= box.top && other.y <= box.bottom; + return (goog.isDef(imageUrl) || text.length > 0) ? + new Cesium.Credit(text, imageUrl, link) : null; }; /** - * Returns the relative x position of a coordinate compared to a box. Returns - * zero if the coordinate is inside the box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate} coord A Coordinate. - * @return {number} The x position of {@code coord} relative to the nearest - * side of {@code box}, or zero if {@code coord} is inside {@code box}. + * TODO: attributions for individual tile ranges + * @override */ -goog.math.Box.relativePositionX = function(box, coord) { - if (coord.x < box.left) { - return coord.x - box.left; - } else if (coord.x > box.right) { - return coord.x - box.right; - } - return 0; +olcs.core.OLImageryProvider.prototype.getTileCredits = function(x, y, level) { + return undefined; }; +goog.exportProperty(olcs.core.OLImageryProvider.prototype, 'getTileCredits', + olcs.core.OLImageryProvider.prototype.getTileCredits); /** - * Returns the relative y position of a coordinate compared to a box. Returns - * zero if the coordinate is inside the box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate} coord A Coordinate. - * @return {number} The y position of {@code coord} relative to the nearest - * side of {@code box}, or zero if {@code coord} is inside {@code box}. + * @override */ -goog.math.Box.relativePositionY = function(box, coord) { - if (coord.y < box.top) { - return coord.y - box.top; - } else if (coord.y > box.bottom) { - return coord.y - box.bottom; - } - return 0; -}; +olcs.core.OLImageryProvider.prototype.requestImage = function(x, y, level) { + var tileUrlFunction = this.source_.getTileUrlFunction(); + if (!goog.isNull(tileUrlFunction) && !goog.isNull(this.projection_)) { + // Perform mapping of Cesium tile coordinates to ol3 tile coordinates: + // 1) Cesium zoom level 0 is OpenLayers zoom level 1 for EPSG:4326 + var z_ = this.tilingScheme_ instanceof Cesium.GeographicTilingScheme ? + level + 1 : level; + // 2) OpenLayers tile coordinates increase from bottom to top + var y_ = -y - 1; -/** - * Returns the distance between a coordinate and the nearest corner/side of a - * box. Returns zero if the coordinate is inside the box. - * - * @param {goog.math.Box} box A Box. - * @param {goog.math.Coordinate} coord A Coordinate. - * @return {number} The distance between {@code coord} and the nearest - * corner/side of {@code box}, or zero if {@code coord} is inside - * {@code box}. - */ -goog.math.Box.distance = function(box, coord) { - var x = goog.math.Box.relativePositionX(box, coord); - var y = goog.math.Box.relativePositionY(box, coord); - return Math.sqrt(x * x + y * y); + var url = tileUrlFunction([z_, x, y_], 1, this.projection_); + return goog.isDef(url) ? + Cesium.ImageryProvider.loadImage(this, url) : this.emptyCanvas_; + } else { + // return empty canvas to stop Cesium from retrying later + return this.emptyCanvas_; + } }; +goog.exportProperty(olcs.core.OLImageryProvider.prototype, 'requestImage', + olcs.core.OLImageryProvider.prototype.requestImage); +goog.provide('olcs.core'); -/** - * Returns whether two boxes intersect. - * - * @param {goog.math.Box} a A Box. - * @param {goog.math.Box} b A second Box. - * @return {boolean} Whether the boxes intersect. - */ -goog.math.Box.intersects = function(a, b) { - return (a.left <= b.right && b.left <= a.right && - a.top <= b.bottom && b.top <= a.bottom); -}; +goog.require('goog.asserts'); +goog.require('goog.async.AnimationDelay'); +goog.require('ol.layer.Tile'); +goog.require('ol.proj'); +goog.require('ol.source.TileImage'); +goog.require('ol.source.WMTS'); +goog.require('olcs.core.OLImageryProvider'); /** - * Returns whether two boxes would intersect with additional padding. - * - * @param {goog.math.Box} a A Box. - * @param {goog.math.Box} b A second Box. - * @param {number} padding The additional padding. - * @return {boolean} Whether the boxes intersect. + * Compute the pixel width and height of a point in meters using the + * camera frustum. + * @param {!Cesium.Scene} scene + * @param {!Cesium.Cartesian3} target + * @return {!Cesium.Cartesian2} the pixel size + * @api */ -goog.math.Box.intersectsWithPadding = function(a, b, padding) { - return (a.left <= b.right + padding && b.left <= a.right + padding && - a.top <= b.bottom + padding && b.top <= a.bottom + padding); +olcs.core.computePixelSizeAtCoordinate = function(scene, target) { + var camera = scene.camera; + var canvas = scene.canvas; + var frustum = camera.frustum; + var canvasDimensions = new Cesium.Cartesian2( + canvas.clientWidth, canvas.clientHeight); + var distance = Cesium.Cartesian3.magnitude(Cesium.Cartesian3.subtract( + camera.position, target, new Cesium.Cartesian3())); + var pixelSize = frustum.getPixelSize(canvasDimensions, distance); + return pixelSize; }; /** - * Rounds the fields to the next larger integer values. - * - * @return {!goog.math.Box} This box with ceil'd fields. + * Compute bounding box around a target point. + * @param {!Cesium.Scene} scene + * @param {!Cesium.Cartesian3} target + * @param {number} amount Half the side of the box, in pixels. + * @return {Array<Cesium.Cartographic>} bottom left and top right + * coordinates of the box */ -goog.math.Box.prototype.ceil = function() { - this.top = Math.ceil(this.top); - this.right = Math.ceil(this.right); - this.bottom = Math.ceil(this.bottom); - this.left = Math.ceil(this.left); - return this; -}; - +olcs.core.computeBoundingBoxAtTarget = function(scene, target, amount) { + var pixelSize = olcs.core.computePixelSizeAtCoordinate(scene, target); + var transform = Cesium.Transforms.eastNorthUpToFixedFrame(target); -/** - * Rounds the fields to the next smaller integer values. - * - * @return {!goog.math.Box} This box with floored fields. - */ -goog.math.Box.prototype.floor = function() { - this.top = Math.floor(this.top); - this.right = Math.floor(this.right); - this.bottom = Math.floor(this.bottom); - this.left = Math.floor(this.left); - return this; -}; + var bottomLeft = Cesium.Matrix4.multiplyByPoint( + transform, + new Cesium.Cartesian3(-pixelSize.x * amount, -pixelSize.y * amount, 0), + new Cesium.Cartesian3()); + var topRight = Cesium.Matrix4.multiplyByPoint( + transform, + new Cesium.Cartesian3(pixelSize.x * amount, pixelSize.y * amount, 0), + new Cesium.Cartesian3()); -/** - * Rounds the fields to nearest integer values. - * - * @return {!goog.math.Box} This box with rounded fields. - */ -goog.math.Box.prototype.round = function() { - this.top = Math.round(this.top); - this.right = Math.round(this.right); - this.bottom = Math.round(this.bottom); - this.left = Math.round(this.left); - return this; + return Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray( + [bottomLeft, topRight]); }; /** - * Translates this box by the given offsets. If a {@code goog.math.Coordinate} - * is given, then the left and right values are translated by the coordinate's - * x value and the top and bottom values are translated by the coordinate's y - * value. Otherwise, {@code tx} and {@code opt_ty} are used to translate the x - * and y dimension values. * - * @param {number|goog.math.Coordinate} tx The value to translate the x - * dimension values by or the the coordinate to translate this box by. - * @param {number=} opt_ty The value to translate y dimension values by. - * @return {!goog.math.Box} This box after translating. + * @param {!ol.geom.Geometry} geometry + * @param {number} height + * @api */ -goog.math.Box.prototype.translate = function(tx, opt_ty) { - if (tx instanceof goog.math.Coordinate) { - this.left += tx.x; - this.right += tx.x; - this.top += tx.y; - this.bottom += tx.y; - } else { - this.left += tx; - this.right += tx; - if (goog.isNumber(opt_ty)) { - this.top += opt_ty; - this.bottom += opt_ty; +olcs.core.applyHeightOffsetToGeometry = function(geometry, height) { + geometry.applyTransform(function(input, output, stride) { + goog.asserts.assert(input === output); + if (goog.isDef(stride) && stride >= 3) { + for (var i = 0; i < output.length; i += stride) { + output[i + 2] = output[i + 2] + height; + } } - } - return this; + return output; + }); }; /** - * Scales this coordinate by the given scale factors. The x and y dimension - * values are scaled by {@code sx} and {@code opt_sy} respectively. - * If {@code opt_sy} is not given, then {@code sx} is used for both x and y. - * - * @param {number} sx The scale factor to use for the x dimension. - * @param {number=} opt_sy The scale factor to use for the y dimension. - * @return {!goog.math.Box} This box after scaling. + * @param {!Cesium.Camera} camera + * @param {number} angle + * @param {!Cesium.Cartesian3} axis + * @param {!Cesium.Matrix4} transform + * @param {olcsx.core.RotateAroundAxisOption=} opt_options + * @api */ -goog.math.Box.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.left *= sx; - this.right *= sx; - this.top *= sy; - this.bottom *= sy; - return this; -}; +olcs.core.rotateAroundAxis = function(camera, angle, axis, transform, + opt_options) { + var clamp = Cesium.Math.clamp; + var defaultValue = Cesium.defaultValue; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + var options = opt_options || {}; + var duration = defaultValue(options.duration, 500); // ms + var easing = defaultValue(options.easing, ol.easing.linear); + var callback = options.callback; -/** - * @fileoverview A utility class for representing rectangles. - */ + var start = goog.now(); + var lastProgress = 0; + var oldTransform = new Cesium.Matrix4(); -goog.provide('goog.math.Rect'); + var animation = new goog.async.AnimationDelay(function(millis) { + var progress = easing(clamp((millis - start) / duration, 0, 1)); + goog.asserts.assert(progress > lastProgress); -goog.require('goog.math.Box'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Size'); + camera.transform.clone(oldTransform); + var stepAngle = (progress - lastProgress) * angle; + lastProgress = progress; + camera.lookAtTransform(transform); + camera.rotate(axis, stepAngle); + camera.lookAtTransform(oldTransform); + if (progress < 1) { + animation.start(); + } else if (callback) { + callback(); + } + }); + animation.start(); +}; /** - * Class for representing rectangular regions. - * @param {number} x Left. - * @param {number} y Top. - * @param {number} w Width. - * @param {number} h Height. - * @struct - * @constructor + * @param {!Cesium.Scene} scene + * @param {number} heading + * @param {!Cesium.Cartesian3} bottomCenter + * @param {olcsx.core.RotateAroundAxisOption=} opt_options + * @api */ -goog.math.Rect = function(x, y, w, h) { - /** @type {number} */ - this.left = x; - - /** @type {number} */ - this.top = y; +olcs.core.setHeadingUsingBottomCenter = function(scene, heading, + bottomCenter, opt_options) { + var camera = scene.camera; + // Compute the camera position to zenith quaternion + var angleToZenith = olcs.core.computeAngleToZenith(scene, bottomCenter); + var axis = camera.right; + var quaternion = Cesium.Quaternion.fromAxisAngle(axis, angleToZenith); + var rotation = Cesium.Matrix3.fromQuaternion(quaternion); - /** @type {number} */ - this.width = w; + // Get the zenith point from the rotation of the position vector + var vector = new Cesium.Cartesian3(); + Cesium.Cartesian3.subtract(camera.position, bottomCenter, vector); + var zenith = new Cesium.Cartesian3(); + Cesium.Matrix3.multiplyByVector(rotation, vector, zenith); + Cesium.Cartesian3.add(zenith, bottomCenter, zenith); - /** @type {number} */ - this.height = h; + // Actually rotate around the zenith normal + var transform = Cesium.Matrix4.fromTranslation(zenith); + var rotateAroundAxis = olcs.core.rotateAroundAxis; + rotateAroundAxis(camera, heading, zenith, transform, opt_options); }; /** - * @return {!goog.math.Rect} A new copy of this Rectangle. + * Get the 3D position of the given pixel of the canvas. + * @param {!Cesium.Scene} scene + * @param {!Cesium.Cartesian2} pixel + * @return {!Cesium.Cartesian3|undefined} + * @api */ -goog.math.Rect.prototype.clone = function() { - return new goog.math.Rect(this.left, this.top, this.width, this.height); +olcs.core.pickOnTerrainOrEllipsoid = function(scene, pixel) { + var ray = scene.camera.getPickRay(pixel); + var target = scene.globe.pick(ray, scene); + return target || scene.camera.pickEllipsoid(pixel); }; /** - * Returns a new Box object with the same position and dimensions as this - * rectangle. - * @return {!goog.math.Box} A new Box representation of this Rectangle. + * Get the 3D position of the point at the bottom-center of the screen. + * @param {!Cesium.Scene} scene + * @return {!Cesium.Cartesian3|undefined} + * @api */ -goog.math.Rect.prototype.toBox = function() { - var right = this.left + this.width; - var bottom = this.top + this.height; - return new goog.math.Box(this.top, - right, - bottom, - this.left); +olcs.core.pickBottomPoint = function(scene) { + var canvas = scene.canvas; + var bottom = new Cesium.Cartesian2( + canvas.clientWidth / 2, canvas.clientHeight); + return olcs.core.pickOnTerrainOrEllipsoid(scene, bottom); }; /** - * Creates a new Rect object with the position and size given. - * @param {!goog.math.Coordinate} position The top-left coordinate of the Rect - * @param {!goog.math.Size} size The size of the Rect - * @return {!goog.math.Rect} A new Rect initialized with the given position and - * size. - */ -goog.math.Rect.createFromPositionAndSize = function(position, size) { - return new goog.math.Rect(position.x, position.y, size.width, size.height); + * Get the 3D position of the point at the center of the screen. + * @param {!Cesium.Scene} scene + * @return {!Cesium.Cartesian3|undefined} + * @api + */ +olcs.core.pickCenterPoint = function(scene) { + var canvas = scene.canvas; + var center = new Cesium.Cartesian2( + canvas.clientWidth / 2, + canvas.clientHeight / 2); + return olcs.core.pickOnTerrainOrEllipsoid(scene, center); }; /** - * Creates a new Rect object with the same position and dimensions as a given - * Box. Note that this is only the inverse of toBox if left/top are defined. - * @param {goog.math.Box} box A box. - * @return {!goog.math.Rect} A new Rect initialized with the box's position - * and size. + * Compute the signed tilt angle on globe, between the opposite of the + * camera direction and the target normal. Return undefined if there is no + * intersection of the camera direction with the globe. + * @param {!Cesium.Scene} scene + * @return {number|undefined} + * @api */ -goog.math.Rect.createFromBox = function(box) { - return new goog.math.Rect(box.left, box.top, - box.right - box.left, box.bottom - box.top); -}; +olcs.core.computeSignedTiltAngleOnGlobe = function(scene) { + var camera = scene.camera; + var ray = new Cesium.Ray(camera.position, camera.direction); + var target = scene.globe.pick(ray, scene); + if (!target) { + // no tiles in the area were loaded? + var ellipsoid = Cesium.Ellipsoid.WGS84; + var obj = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid); + if (obj) { + target = Cesium.Ray.getPoint(ray, obj.start); + } + } -if (goog.DEBUG) { - /** - * Returns a nice string representing size and dimensions of rectangle. - * @return {string} In the form (50, 73 - 75w x 25h). - * @override - */ - goog.math.Rect.prototype.toString = function() { - return '(' + this.left + ', ' + this.top + ' - ' + this.width + 'w x ' + - this.height + 'h)'; - }; -} + if (!target) { + return undefined; + } + var normal = new Cesium.Cartesian3(); + Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(target, normal); -/** - * Compares rectangles for equality. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {boolean} True iff the rectangles have the same left, top, width, - * and height, or if both are null. - */ -goog.math.Rect.equals = function(a, b) { - if (a == b) { - return true; - } - if (!a || !b) { - return false; - } - return a.left == b.left && a.width == b.width && - a.top == b.top && a.height == b.height; + var angleBetween = olcs.core.signedAngleBetween; + var angle = angleBetween(camera.direction, normal, camera.right) - Math.PI; + return Cesium.Math.convertLongitudeRange(angle); }; /** - * Computes the intersection of this rectangle and the rectangle parameter. If - * there is no intersection, returns false and leaves this rectangle as is. - * @param {goog.math.Rect} rect A Rectangle. - * @return {boolean} True iff this rectangle intersects with the parameter. + * Compute the ray from the camera to the bottom-center of the screen. + * @param {!Cesium.Scene} scene + * @return {!Cesium.Ray} */ -goog.math.Rect.prototype.intersection = function(rect) { - var x0 = Math.max(this.left, rect.left); - var x1 = Math.min(this.left + this.width, rect.left + rect.width); - - if (x0 <= x1) { - var y0 = Math.max(this.top, rect.top); - var y1 = Math.min(this.top + this.height, rect.top + rect.height); - - if (y0 <= y1) { - this.left = x0; - this.top = y0; - this.width = x1 - x0; - this.height = y1 - y0; - - return true; - } - } - return false; +olcs.core.bottomFovRay = function(scene) { + var camera = scene.camera; + var fovy2 = camera.frustum.fovy / 2; + var direction = camera.direction; + var rotation = Cesium.Quaternion.fromAxisAngle(camera.right, fovy2); + var matrix = Cesium.Matrix3.fromQuaternion(rotation); + var vector = new Cesium.Cartesian3(); + Cesium.Matrix3.multiplyByVector(matrix, direction, vector); + return new Cesium.Ray(camera.position, vector); }; /** - * Returns the intersection of two rectangles. Two rectangles intersect if they - * touch at all, for example, two zero width and height rectangles would - * intersect if they had the same top and left. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {goog.math.Rect} A new intersection rect (even if width and height - * are 0), or null if there is no intersection. + * Compute the angle between two Cartesian3. + * @param {!Cesium.Cartesian3} first + * @param {!Cesium.Cartesian3} second + * @param {!Cesium.Cartesian3} normal Normal to test orientation against. + * @return {number} */ -goog.math.Rect.intersection = function(a, b) { - // There is no nice way to do intersection via a clone, because any such - // clone might be unnecessary if this function returns null. So, we duplicate - // code from above. - - var x0 = Math.max(a.left, b.left); - var x1 = Math.min(a.left + a.width, b.left + b.width); +olcs.core.signedAngleBetween = function(first, second, normal) { + // We are using the dot for the angle. + // Then the cross and the dot for the sign. + var a = new Cesium.Cartesian3(); + var b = new Cesium.Cartesian3(); + var c = new Cesium.Cartesian3(); + Cesium.Cartesian3.normalize(first, a); + Cesium.Cartesian3.normalize(second, b); + Cesium.Cartesian3.cross(a, b, c); - if (x0 <= x1) { - var y0 = Math.max(a.top, b.top); - var y1 = Math.min(a.top + a.height, b.top + b.height); + var cosine = Cesium.Cartesian3.dot(a, b); + var sine = Cesium.Cartesian3.magnitude(c); - if (y0 <= y1) { - return new goog.math.Rect(x0, y0, x1 - x0, y1 - y0); - } - } - return null; + // Sign of the vector product and the orientation normal + var sign = Cesium.Cartesian3.dot(normal, c); + var angle = Math.atan2(sine, cosine); + return sign >= 0 ? angle : -angle; }; /** - * Returns whether two rectangles intersect. Two rectangles intersect if they - * touch at all, for example, two zero width and height rectangles would - * intersect if they had the same top and left. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {boolean} Whether a and b intersect. + * Compute the rotation angle around a given point, needed to reach the + * zenith position. + * At a zenith position, the camera direction is going througth the earth + * center and the frustrum bottom ray is going through the chosen pivot + * point. + * The bottom-center of the screen is a good candidate for the pivot point. + * @param {!Cesium.Scene} scene + * @param {!Cesium.Cartesian3} pivot Point around which the camera rotates. + * @return {number} + * @api */ -goog.math.Rect.intersects = function(a, b) { - return (a.left <= b.left + b.width && b.left <= a.left + a.width && - a.top <= b.top + b.height && b.top <= a.top + a.height); -}; +olcs.core.computeAngleToZenith = function(scene, pivot) { + // This angle is the sum of the angles 'fy' and 'a', which are defined + // using the pivot point and its surface normal. + // Zenith | camera + // \ | / + // \fy| / + // \ |a/ + // \|/pivot + var camera = scene.camera; + var fy = camera.frustum.fovy / 2; + var ray = olcs.core.bottomFovRay(scene); + var direction = Cesium.Cartesian3.clone(ray.direction); + Cesium.Cartesian3.negate(direction, direction); + var normal = new Cesium.Cartesian3(); + Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(pivot, normal); -/** - * Returns whether a rectangle intersects this rectangle. - * @param {goog.math.Rect} rect A rectangle. - * @return {boolean} Whether rect intersects this rectangle. - */ -goog.math.Rect.prototype.intersects = function(rect) { - return goog.math.Rect.intersects(this, rect); + var left = new Cesium.Cartesian3(); + Cesium.Cartesian3.negate(camera.right, left); + + var a = olcs.core.signedAngleBetween(normal, direction, left); + return a + fy; }; /** - * Computes the difference regions between two rectangles. The return value is - * an array of 0 to 4 rectangles defining the remaining regions of the first - * rectangle after the second has been subtracted. - * @param {goog.math.Rect} a A Rectangle. - * @param {goog.math.Rect} b A Rectangle. - * @return {!Array<!goog.math.Rect>} An array with 0 to 4 rectangles which - * together define the difference area of rectangle a minus rectangle b. + * Rotate the camera so that its direction goes through the target point. + * If a globe is given, the target height is first interpolated from terrain. + * @param {!Cesium.Camera} camera + * @param {!Cesium.Cartographic} target + * @param {Cesium.Globe=} opt_globe + * @api */ -goog.math.Rect.difference = function(a, b) { - var intersection = goog.math.Rect.intersection(a, b); - if (!intersection || !intersection.height || !intersection.width) { - return [a.clone()]; +olcs.core.lookAt = function(camera, target, opt_globe) { + if (goog.isDef(opt_globe)) { + var height = opt_globe.getHeight(target); + target.height = goog.isDef(height) ? height : 0; } - var result = []; - - var top = a.top; - var height = a.height; - - var ar = a.left + a.width; - var ab = a.top + a.height; - - var br = b.left + b.width; - var bb = b.top + b.height; + var ellipsoid = Cesium.Ellipsoid.WGS84; + var targetb = ellipsoid.cartographicToCartesian(target); - // Subtract off any area on top where A extends past B - if (b.top > a.top) { - result.push(new goog.math.Rect(a.left, a.top, a.width, b.top - a.top)); - top = b.top; - // If we're moving the top down, we also need to subtract the height diff. - height -= b.top - a.top; - } - // Subtract off any area on bottom where A extends past B - if (bb < ab) { - result.push(new goog.math.Rect(a.left, bb, a.width, ab - bb)); - height = bb - top; - } - // Subtract any area on left where A extends past B - if (b.left > a.left) { - result.push(new goog.math.Rect(a.left, top, b.left - a.left, height)); - } - // Subtract any area on right where A extends past B - if (br < ar) { - result.push(new goog.math.Rect(br, top, ar - br, height)); - } + var position = camera.position; + var up = new Cesium.Cartesian3(); + ellipsoid.geocentricSurfaceNormal(position, up); - return result; + camera.lookAt(position, targetb, up); }; /** - * Computes the difference regions between this rectangle and {@code rect}. The - * return value is an array of 0 to 4 rectangles defining the remaining regions - * of this rectangle after the other has been subtracted. - * @param {goog.math.Rect} rect A Rectangle. - * @return {!Array<!goog.math.Rect>} An array with 0 to 4 rectangles which - * together define the difference area of rectangle a minus rectangle b. + * Convert an OpenLayers extent to a Cesium rectangle. + * @param {ol.Extent} extent Extent. + * @param {ol.proj.ProjectionLike} projection Extent projection. + * @return {Cesium.Rectangle} The corresponding Cesium rectangle. + * @api */ -goog.math.Rect.prototype.difference = function(rect) { - return goog.math.Rect.difference(this, rect); +olcs.core.extentToRectangle = function(extent, projection) { + if (!goog.isNull(extent) && !goog.isNull(projection)) { + var ext = ol.proj.transformExtent(extent, projection, 'EPSG:4326'); + return Cesium.Rectangle.fromDegrees(ext[0], ext[1], ext[2], ext[3]); + } else { + return null; + } }; /** - * Expand this rectangle to also include the area of the given rectangle. - * @param {goog.math.Rect} rect The other rectangle. + * Creates Cesium.ImageryLayer best corresponding to the given ol.layer.Layer. + * Only supports raster layers + * @param {!ol.layer.Base} olLayer + * @param {?ol.proj.Projection} viewProj Projection of the view. + * @return {?Cesium.ImageryLayer} null if not possible (or supported) + * @api */ -goog.math.Rect.prototype.boundingRect = function(rect) { - // We compute right and bottom before we change left and top below. - var right = Math.max(this.left + this.width, rect.left + rect.width); - var bottom = Math.max(this.top + this.height, rect.top + rect.height); +olcs.core.tileLayerToImageryLayer = function(olLayer, viewProj) { + if (!(olLayer instanceof ol.layer.Tile)) { + return null; + } - this.left = Math.min(this.left, rect.left); - this.top = Math.min(this.top, rect.top); + var provider = null; - this.width = right - this.left; - this.height = bottom - this.top; -}; + var source = olLayer.getSource(); + // handle special cases before the general synchronization + if (source instanceof ol.source.WMTS) { + // WMTS uses different TileGrid which is not currently supported + return null; + } + if (source instanceof ol.source.TileImage) { + var projection = source.getProjection(); + if (goog.isNull(projection)) { + // if not explicit, assume the same projection as view + projection = viewProj; + } else if (projection !== viewProj) { + return null; // do not sync layers with projections different than view + } -/** - * Returns a new rectangle which completely contains both input rectangles. - * @param {goog.math.Rect} a A rectangle. - * @param {goog.math.Rect} b A rectangle. - * @return {goog.math.Rect} A new bounding rect, or null if either rect is - * null. - */ -goog.math.Rect.boundingRect = function(a, b) { - if (!a || !b) { + var is3857 = projection === ol.proj.get('EPSG:3857'); + var is4326 = projection === ol.proj.get('EPSG:4326'); + if (is3857 || is4326) { + provider = new olcs.core.OLImageryProvider(source, viewProj); + } else { + return null; + } + } else { + // sources other than TileImage are currently not supported return null; } - var clone = a.clone(); - clone.boundingRect(b); - - return clone; -}; + // the provider is always non-null if we got this far + var layerOptions = {}; -/** - * Tests whether this rectangle entirely contains another rectangle or - * coordinate. - * - * @param {goog.math.Rect|goog.math.Coordinate} another The rectangle or - * coordinate to test for containment. - * @return {boolean} Whether this rectangle contains given rectangle or - * coordinate. - */ -goog.math.Rect.prototype.contains = function(another) { - if (another instanceof goog.math.Rect) { - return this.left <= another.left && - this.left + this.width >= another.left + another.width && - this.top <= another.top && - this.top + this.height >= another.top + another.height; - } else { // (another instanceof goog.math.Coordinate) - return another.x >= this.left && - another.x <= this.left + this.width && - another.y >= this.top && - another.y <= this.top + this.height; + var ext = olLayer.getExtent(); + if (goog.isDefAndNotNull(ext) && !goog.isNull(viewProj)) { + layerOptions.rectangle = olcs.core.extentToRectangle(ext, viewProj); } -}; - -/** - * @param {!goog.math.Coordinate} point A coordinate. - * @return {number} The squared distance between the point and the closest - * point inside the rectangle. Returns 0 if the point is inside the - * rectangle. - */ -goog.math.Rect.prototype.squaredDistance = function(point) { - var dx = point.x < this.left ? - this.left - point.x : Math.max(point.x - (this.left + this.width), 0); - var dy = point.y < this.top ? - this.top - point.y : Math.max(point.y - (this.top + this.height), 0); - return dx * dx + dy * dy; + var cesiumLayer = new Cesium.ImageryLayer(provider, layerOptions); + return cesiumLayer; }; /** - * @param {!goog.math.Coordinate} point A coordinate. - * @return {number} The distance between the point and the closest point - * inside the rectangle. Returns 0 if the point is inside the rectangle. + * Synchronizes the layer rendering properties (opacity, visible) + * to the given Cesium ImageryLayer. + * @param {!ol.layer.Base} olLayer + * @param {!Cesium.ImageryLayer} csLayer + * @api */ -goog.math.Rect.prototype.distance = function(point) { - return Math.sqrt(this.squaredDistance(point)); +olcs.core.updateCesiumLayerProperties = function(olLayer, csLayer) { + var opacity = olLayer.getOpacity(); + if (goog.isDef(opacity)) { + csLayer.alpha = opacity; + } + var visible = olLayer.getVisible(); + if (goog.isDef(visible)) { + csLayer.show = visible; + } }; /** - * @return {!goog.math.Size} The size of this rectangle. + * Convert a 2D or 3D OpenLayers coordinate to Cesium. + * @param {ol.Coordinate} coordinate Ol3 coordinate. + * @return {!Cesium.Cartesian3} Cesium cartesian coordinate + * @api */ -goog.math.Rect.prototype.getSize = function() { - return new goog.math.Size(this.width, this.height); +olcs.core.ol4326CoordinateToCesiumCartesian = function(coordinate) { + var coo = coordinate; + goog.isDefAndNotNull(coo); + return coo.length > 2 ? + Cesium.Cartesian3.fromDegrees(coo[0], coo[1], coo[2]) : + Cesium.Cartesian3.fromDegrees(coo[0], coo[1]); }; /** - * @return {!goog.math.Coordinate} A new coordinate for the top-left corner of - * the rectangle. + * Convert an array of 2D or 3D OpenLayers coordinates to Cesium. + * @param {Array.<!ol.Coordinate>} coordinates Ol3 coordinates. + * @return {!Array.<Cesium.Cartesian3>} Cesium cartesian coordinates + * @api */ -goog.math.Rect.prototype.getTopLeft = function() { - return new goog.math.Coordinate(this.left, this.top); +olcs.core.ol4326CoordinateArrayToCsCartesians = function(coordinates) { + goog.asserts.assert(coordinates !== null); + var toCartesian = olcs.core.ol4326CoordinateToCesiumCartesian; + var cartesians = []; + for (var i = 0; i < coordinates.length; ++i) { + cartesians.push(toCartesian(coordinates[i])); + } + return cartesians; }; /** - * @return {!goog.math.Coordinate} A new coordinate for the center of the - * rectangle. + * Reproject an OpenLayers geometry to EPSG:4326 if needed. + * The geometry will be cloned only when original projection is not EPSG:4326 + * and the properties will be shallow copied. + * @param {!T} geometry + * @param {!ol.proj.ProjectionLike} projection + * @return {!T} + * @template T + * @api */ -goog.math.Rect.prototype.getCenter = function() { - return new goog.math.Coordinate( - this.left + this.width / 2, this.top + this.height / 2); -}; - +olcs.core.olGeometryCloneTo4326 = function(geometry, projection) { + goog.asserts.assert(goog.isDef(projection)); -/** - * @return {!goog.math.Coordinate} A new coordinate for the bottom-right corner - * of the rectangle. - */ -goog.math.Rect.prototype.getBottomRight = function() { - return new goog.math.Coordinate( - this.left + this.width, this.top + this.height); + var proj4326 = ol.proj.get('EPSG:4326'); + var proj = ol.proj.get(projection); + if (proj !== proj4326) { + var properties = geometry.getProperties(); + geometry = geometry.clone(); + geometry.transform(proj, proj4326); + geometry.setProperties(properties); + } + return geometry; }; /** - * Rounds the fields to the next larger integer values. - * @return {!goog.math.Rect} This rectangle with ceil'd fields. + * Convert an OpenLayers color to Cesium. + * @param {ol.Color|string} olColor + * @return {!Cesium.Color} + * @api */ -goog.math.Rect.prototype.ceil = function() { - this.left = Math.ceil(this.left); - this.top = Math.ceil(this.top); - this.width = Math.ceil(this.width); - this.height = Math.ceil(this.height); - return this; +olcs.core.convertColorToCesium = function(olColor) { + olColor = olColor || 'black'; + if (Array.isArray(olColor)) { + return new Cesium.Color( + Cesium.Color.byteToFloat(olColor[0]), + Cesium.Color.byteToFloat(olColor[1]), + Cesium.Color.byteToFloat(olColor[2]), + olColor[3] + ); + } else if (typeof olColor == 'string') { + return Cesium.Color.fromCssColorString(olColor); + } + goog.asserts.fail('impossible'); }; +goog.provide('olcs.Camera'); -/** - * Rounds the fields to the next smaller integer values. - * @return {!goog.math.Rect} This rectangle with floored fields. - */ -goog.math.Rect.prototype.floor = function() { - this.left = Math.floor(this.left); - this.top = Math.floor(this.top); - this.width = Math.floor(this.width); - this.height = Math.floor(this.height); - return this; -}; - +goog.require('goog.events'); +goog.require('ol.Observable'); +goog.require('ol.proj'); +goog.require('olcs.core'); -/** - * Rounds the fields to nearest integer values. - * @return {!goog.math.Rect} This rectangle with rounded fields. - */ -goog.math.Rect.prototype.round = function() { - this.left = Math.round(this.left); - this.top = Math.round(this.top); - this.width = Math.round(this.width); - this.height = Math.round(this.height); - return this; -}; /** - * Translates this rectangle by the given offsets. If a - * {@code goog.math.Coordinate} is given, then the left and top values are - * translated by the coordinate's x and y values. Otherwise, top and left are - * translated by {@code tx} and {@code opt_ty} respectively. - * @param {number|goog.math.Coordinate} tx The value to translate left by or the - * the coordinate to translate this rect by. - * @param {number=} opt_ty The value to translate top by. - * @return {!goog.math.Rect} This rectangle after translating. + * This object takes care of additional 3d-specific properties of the view and + * ensures proper synchronization with the underlying raw Cesium.Camera object. + * @param {!Cesium.Scene} scene + * @param {!ol.Map} map + * @constructor + * @api + * @struct */ -goog.math.Rect.prototype.translate = function(tx, opt_ty) { - if (tx instanceof goog.math.Coordinate) { - this.left += tx.x; - this.top += tx.y; - } else { - this.left += tx; - if (goog.isNumber(opt_ty)) { - this.top += opt_ty; - } - } - return this; -}; +olcs.Camera = function(scene, map) { + /** + * @type {!Cesium.Scene} + * @private + */ + this.scene_ = scene; + /** + * @type {!Cesium.Camera} + * @private + */ + this.cam_ = scene.camera; -/** - * Scales this rectangle by the given scale factors. The left and width values - * are scaled by {@code sx} and the top and height values are scaled by - * {@code opt_sy}. If {@code opt_sy} is not given, then all fields are scaled - * by {@code sx}. - * @param {number} sx The scale factor to use for the x dimension. - * @param {number=} opt_sy The scale factor to use for the y dimension. - * @return {!goog.math.Rect} This rectangle after scaling. - */ -goog.math.Rect.prototype.scale = function(sx, opt_sy) { - var sy = goog.isNumber(opt_sy) ? opt_sy : sx; - this.left *= sx; - this.width *= sx; - this.top *= sy; - this.height *= sy; - return this; -}; + /** + * @type {!ol.Map} + * @private + */ + this.map_ = map; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + /** + * @type {?ol.View} + * @private + */ + this.view_ = null; -/** - * @fileoverview Utilities for element styles. - * - * @author arv@google.com (Erik Arvidsson) - * @author eae@google.com (Emil A Eklund) - * @see ../demos/inline_block_quirks.html - * @see ../demos/inline_block_standards.html - * @see ../demos/style_viewport.html - */ + /** + * @type {?goog.events.Key} + * @private + */ + this.viewListenKey_ = null; -goog.provide('goog.style'); + /** + * @type {!ol.TransformFunction} + * @private + */ + this.toLonLat_ = olcs.Camera.identityProjection; + /** + * @type {!ol.TransformFunction} + * @private + */ + this.fromLonLat_ = olcs.Camera.identityProjection; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.vendor'); -goog.require('goog.math.Box'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Rect'); -goog.require('goog.math.Size'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.userAgent'); + /** + * 0 -- topdown, PI/2 -- the horizon + * @type {number} + * @private + */ + this.tilt_ = 0; -goog.forwardDeclare('goog.events.BrowserEvent'); -goog.forwardDeclare('goog.events.Event'); + /** + * @type {number} + * @private + */ + this.distance_ = 0; + + /** + * @type {?Cesium.Matrix4} + * @private + */ + this.lastCameraViewMatrix_ = null; + /** + * This is used to discard change events on view caused by updateView method. + * @type {boolean} + * @private + */ + this.viewUpdateInProgress_ = false; -/** - * Sets a style value on an element. - * - * This function is not indended to patch issues in the browser's style - * handling, but to allow easy programmatic access to setting dash-separated - * style properties. An example is setting a batch of properties from a data - * object without overwriting old styles. When possible, use native APIs: - * elem.style.propertyKey = 'value' or (if obliterating old styles is fine) - * elem.style.cssText = 'property1: value1; property2: value2'. - * - * @param {Element} element The element to change. - * @param {string|Object} style If a string, a style name. If an object, a hash - * of style names to style values. - * @param {string|number|boolean=} opt_value If style was a string, then this - * should be the value. - */ -goog.style.setStyle = function(element, style, opt_value) { - if (goog.isString(style)) { - goog.style.setStyle_(element, opt_value, style); - } else { - for (var key in style) { - goog.style.setStyle_(element, style[key], key); - } - } + this.map_.on('change:view', function(e) { + this.setView_(this.map_.getView()); + }, this); + this.setView_(this.map_.getView()); }; /** - * Sets a style value on an element, with parameters swapped to work with - * {@code goog.object.forEach()}. Prepends a vendor-specific prefix when - * necessary. - * @param {Element} element The element to change. - * @param {string|number|boolean|undefined} value Style value. - * @param {string} style Style name. - * @private + * @param {Array.<number>} input Input coordinate array. + * @param {Array.<number>=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension. + * @return {Array.<number>} Input coordinate array (same array as input). */ -goog.style.setStyle_ = function(element, value, style) { - var propertyName = goog.style.getVendorJsStyleName_(element, style); - - if (propertyName) { - element.style[propertyName] = value; +olcs.Camera.identityProjection = function(input, opt_output, opt_dimension) { + var dim = opt_dimension || input.length; + if (opt_output) { + for (var i = 0; i < dim; ++i) { + opt_output[i] = input[i]; + } } + return input; }; /** - * Style name cache that stores previous property name lookups. - * - * This is used by setStyle to speed up property lookups, entries look like: - * { StyleName: ActualPropertyName } - * - * @private {!Object<string, string>} - */ -goog.style.styleNameCache_ = {}; - - -/** - * Returns the style property name in camel-case. If it does not exist and a - * vendor-specific version of the property does exist, then return the vendor- - * specific property name instead. - * @param {Element} element The element to change. - * @param {string} style Style name. - * @return {string} Vendor-specific style. + * @param {?ol.View} view New view to use. * @private */ -goog.style.getVendorJsStyleName_ = function(element, style) { - var propertyName = goog.style.styleNameCache_[style]; - if (!propertyName) { - var camelStyle = goog.string.toCamelCase(style); - propertyName = camelStyle; +olcs.Camera.prototype.setView_ = function(view) { + if (!goog.isNull(this.view_)) { + ol.Observable.unByKey(this.viewListenKey_); + this.viewListenKey_ = null; + } - if (element.style[camelStyle] === undefined) { - var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() + - goog.string.toTitleCase(camelStyle); + this.view_ = view; + if (!goog.isNull(view)) { + var toLonLat = ol.proj.getTransform(view.getProjection(), 'EPSG:4326'); + var fromLonLat = ol.proj.getTransform('EPSG:4326', view.getProjection()); + goog.asserts.assert(toLonLat && fromLonLat); - if (element.style[prefixedStyle] !== undefined) { - propertyName = prefixedStyle; - } - } - goog.style.styleNameCache_[style] = propertyName; - } + this.toLonLat_ = toLonLat; + this.fromLonLat_ = fromLonLat; - return propertyName; + this.viewListenKey_ = view.on('propertychange', + this.handleViewEvent_, this); + this.readFromView(); + } else { + this.toLonLat_ = olcs.Camera.identityProjection; + this.fromLonLat_ = olcs.Camera.identityProjection; + } }; /** - * Returns the style property name in CSS notation. If it does not exist and a - * vendor-specific version of the property does exist, then return the vendor- - * specific property name instead. - * @param {Element} element The element to change. - * @param {string} style Style name. - * @return {string} Vendor-specific style. + * @param {?} e * @private */ -goog.style.getVendorStyleName_ = function(element, style) { - var camelStyle = goog.string.toCamelCase(style); - - if (element.style[camelStyle] === undefined) { - var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() + - goog.string.toTitleCase(camelStyle); - - if (element.style[prefixedStyle] !== undefined) { - return goog.dom.vendor.getVendorPrefix() + '-' + style; - } +olcs.Camera.prototype.handleViewEvent_ = function(e) { + if (!this.viewUpdateInProgress_) { + this.readFromView(); } - - return style; }; /** - * Retrieves an explicitly-set style value of a node. This returns '' if there - * isn't a style attribute on the element or if this style property has not been - * explicitly set in script. - * - * @param {Element} element Element to get style of. - * @param {string} property Property to get, css-style (if you have a camel-case - * property, use element.style[style]). - * @return {string} Style value. + * @param {number} heading In radians. + * @api */ -goog.style.getStyle = function(element, property) { - // element.style is '' for well-known properties which are unset. - // For for browser specific styles as 'filter' is undefined - // so we need to return '' explicitly to make it consistent across - // browsers. - var styleValue = element.style[goog.string.toCamelCase(property)]; - - // Using typeof here because of a bug in Safari 5.1, where this value - // was undefined, but === undefined returned false. - if (typeof(styleValue) !== 'undefined') { - return styleValue; +olcs.Camera.prototype.setHeading = function(heading) { + if (goog.isNull(this.view_)) { + return; } - return element.style[goog.style.getVendorJsStyleName_(element, property)] || - ''; + this.view_.setRotation(heading); }; /** - * Retrieves a computed style value of a node. It returns empty string if the - * value cannot be computed (which will be the case in Internet Explorer) or - * "none" if the property requested is an SVG one and it has not been - * explicitly set (firefox and webkit). - * - * @param {Element} element Element to get style of. - * @param {string} property Property to get (camel-case). - * @return {string} Style value. + * @return {number|undefined} Heading in radians. + * @api */ -goog.style.getComputedStyle = function(element, property) { - var doc = goog.dom.getOwnerDocument(element); - if (doc.defaultView && doc.defaultView.getComputedStyle) { - var styles = doc.defaultView.getComputedStyle(element, null); - if (styles) { - // element.style[..] is undefined for browser specific styles - // as 'filter'. - return styles[property] || styles.getPropertyValue(property) || ''; - } +olcs.Camera.prototype.getHeading = function() { + if (goog.isNull(this.view_)) { + return undefined; } - - return ''; + var rotation = this.view_.getRotation(); + return goog.isDef(rotation) ? rotation : 0; }; /** - * Gets the cascaded style value of a node, or null if the value cannot be - * computed (only Internet Explorer can do this). - * - * @param {Element} element Element to get style of. - * @param {string} style Property to get (camel-case). - * @return {string} Style value. + * @param {number} tilt In radians. + * @api */ -goog.style.getCascadedStyle = function(element, style) { - // TODO(nicksantos): This should be documented to return null. #fixTypes - return element.currentStyle ? element.currentStyle[style] : null; +olcs.Camera.prototype.setTilt = function(tilt) { + this.tilt_ = tilt; + this.updateCamera_(); }; /** - * Cross-browser pseudo get computed style. It returns the computed style where - * available. If not available it tries the cascaded style value (IE - * currentStyle) and in worst case the inline style value. It shouldn't be - * called directly, see http://wiki/Main/ComputedStyleVsCascadedStyle for - * discussion. - * - * @param {Element} element Element to get style of. - * @param {string} style Property to get (must be camelCase, not css-style.). - * @return {string} Style value. - * @private + * @return {number} Tilt in radians. + * @api */ -goog.style.getStyle_ = function(element, style) { - return goog.style.getComputedStyle(element, style) || - goog.style.getCascadedStyle(element, style) || - (element.style && element.style[style]); +olcs.Camera.prototype.getTilt = function() { + return this.tilt_; }; /** - * Retrieves the computed value of the box-sizing CSS attribute. - * Browser support: http://caniuse.com/css3-boxsizing. - * @param {!Element} element The element whose box-sizing to get. - * @return {?string} 'content-box', 'border-box' or 'padding-box'. null if - * box-sizing is not supported (IE7 and below). + * @param {number} distance In meters. + * @api */ -goog.style.getComputedBoxSizing = function(element) { - return goog.style.getStyle_(element, 'boxSizing') || - goog.style.getStyle_(element, 'MozBoxSizing') || - goog.style.getStyle_(element, 'WebkitBoxSizing') || null; +olcs.Camera.prototype.setDistance = function(distance) { + this.distance_ = distance; + this.updateCamera_(); + this.updateView(); }; /** - * Retrieves the computed value of the position CSS attribute. - * @param {Element} element The element to get the position of. - * @return {string} Position value. + * @return {number} Distance in meters. + * @api */ -goog.style.getComputedPosition = function(element) { - return goog.style.getStyle_(element, 'position'); +olcs.Camera.prototype.getDistance = function() { + return this.distance_; }; /** - * Retrieves the computed background color string for a given element. The - * string returned is suitable for assigning to another element's - * background-color, but is not guaranteed to be in any particular string - * format. Accessing the color in a numeric form may not be possible in all - * browsers or with all input. - * - * If the background color for the element is defined as a hexadecimal value, - * the resulting string can be parsed by goog.color.parse in all supported - * browsers. - * - * Whether named colors like "red" or "lightblue" get translated into a - * format which can be parsed is browser dependent. Calling this function on - * transparent elements will return "transparent" in most browsers or - * "rgba(0, 0, 0, 0)" in WebKit. - * @param {Element} element The element to get the background color of. - * @return {string} The computed string value of the background color. + * Shortcut for ol.View.setCenter(). + * @param {!ol.Coordinate} center Same projection as the ol.View. + * @api */ -goog.style.getBackgroundColor = function(element) { - return goog.style.getStyle_(element, 'backgroundColor'); +olcs.Camera.prototype.setCenter = function(center) { + if (goog.isNull(this.view_)) { + return; + } + this.view_.setCenter(center); }; /** - * Retrieves the computed value of the overflow-x CSS attribute. - * @param {Element} element The element to get the overflow-x of. - * @return {string} The computed string value of the overflow-x attribute. + * Shortcut for ol.View.getCenter(). + * @return {ol.Coordinate|undefined} Same projection as the ol.View. + * @api */ -goog.style.getComputedOverflowX = function(element) { - return goog.style.getStyle_(element, 'overflowX'); +olcs.Camera.prototype.getCenter = function() { + if (goog.isNull(this.view_)) { + return undefined; + } + return this.view_.getCenter(); }; /** - * Retrieves the computed value of the overflow-y CSS attribute. - * @param {Element} element The element to get the overflow-y of. - * @return {string} The computed string value of the overflow-y attribute. + * Sets the position of the camera. + * @param {!ol.Coordinate} position Same projection as the ol.View. + * @api */ -goog.style.getComputedOverflowY = function(element) { - return goog.style.getStyle_(element, 'overflowY'); +olcs.Camera.prototype.setPosition = function(position) { + if (goog.isNull(this.toLonLat_)) { + return; + } + var ll = this.toLonLat_(position); + goog.asserts.assert(!goog.isNull(ll)); + + var carto = new Cesium.Cartographic(goog.math.toRadians(ll[0]), + goog.math.toRadians(ll[1]), + this.getAltitude()); + + this.cam_.position = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); + this.updateView(); }; /** - * Retrieves the computed value of the z-index CSS attribute. - * @param {Element} element The element to get the z-index of. - * @return {string|number} The computed value of the z-index attribute. + * Calculates position under the camera. + * @return {!ol.Coordinate|undefined} Same projection as the ol.View. + * @api */ -goog.style.getComputedZIndex = function(element) { - return goog.style.getStyle_(element, 'zIndex'); +olcs.Camera.prototype.getPosition = function() { + if (goog.isNull(this.fromLonLat_)) { + return undefined; + } + var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic( + this.cam_.position); + + var pos = this.fromLonLat_([goog.math.toDegrees(carto.longitude), + goog.math.toDegrees(carto.latitude)]); + goog.asserts.assert(!goog.isNull(pos)); + return pos; }; /** - * Retrieves the computed value of the text-align CSS attribute. - * @param {Element} element The element to get the text-align of. - * @return {string} The computed string value of the text-align attribute. + * @param {number} altitude In meters. + * @api */ -goog.style.getComputedTextAlign = function(element) { - return goog.style.getStyle_(element, 'textAlign'); +olcs.Camera.prototype.setAltitude = function(altitude) { + var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic( + this.cam_.position); + carto.height = altitude; + this.cam_.position = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); + + this.updateView(); }; /** - * Retrieves the computed value of the cursor CSS attribute. - * @param {Element} element The element to get the cursor of. - * @return {string} The computed string value of the cursor attribute. + * @return {number} Altitude in meters. + * @api */ -goog.style.getComputedCursor = function(element) { - return goog.style.getStyle_(element, 'cursor'); +olcs.Camera.prototype.getAltitude = function() { + var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic( + this.cam_.position); + + return carto.height; }; /** - * Retrieves the computed value of the CSS transform attribute. - * @param {Element} element The element to get the transform of. - * @return {string} The computed string representation of the transform matrix. + * Rotates the camera to point at the specified target. + * @param {!ol.Coordinate} position Same projection as the ol.View. + * @api */ -goog.style.getComputedTransform = function(element) { - var property = goog.style.getVendorStyleName_(element, 'transform'); - return goog.style.getStyle_(element, property) || - goog.style.getStyle_(element, 'transform'); +olcs.Camera.prototype.lookAt = function(position) { + if (goog.isNull(this.toLonLat_)) { + return; + } + var ll = this.toLonLat_(position); + goog.asserts.assert(!goog.isNull(ll)); + + var carto = Cesium.Cartographic.fromDegrees(ll[0], ll[1]); + olcs.core.lookAt(this.cam_, carto, this.scene_.globe); + + this.updateView(); }; /** - * Sets the top/left values of an element. If no unit is specified in the - * argument then it will add px. The second argument is required if the first - * argument is a string or number and is ignored if the first argument - * is a coordinate. - * @param {Element} el Element to move. - * @param {string|number|goog.math.Coordinate} arg1 Left position or coordinate. - * @param {string|number=} opt_arg2 Top position. + * Updates the state of the underlying Cesium.Camera + * according to the current values of the properties. + * @private */ -goog.style.setPosition = function(el, arg1, opt_arg2) { - var x, y; - - if (arg1 instanceof goog.math.Coordinate) { - x = arg1.x; - y = arg1.y; - } else { - x = arg1; - y = opt_arg2; +olcs.Camera.prototype.updateCamera_ = function() { + if (goog.isNull(this.view_) || goog.isNull(this.toLonLat_)) { + return; + } + var center = this.view_.getCenter(); + if (!center) { + return; } + var ll = this.toLonLat_(center); + goog.asserts.assert(!goog.isNull(ll)); - el.style.left = goog.style.getPixelStyleValue_( - /** @type {number|string} */ (x), false); - el.style.top = goog.style.getPixelStyleValue_( - /** @type {number|string} */ (y), false); -}; + var carto = new Cesium.Cartographic(goog.math.toRadians(ll[0]), + goog.math.toRadians(ll[1])); + if (this.scene_.globe) { + var height = this.scene_.globe.getHeight(carto); + carto.height = goog.isDef(height) ? height : 0; + } + var destination = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); -/** - * Gets the offsetLeft and offsetTop properties of an element and returns them - * in a Coordinate object - * @param {Element} element Element. - * @return {!goog.math.Coordinate} The position. - */ -goog.style.getPosition = function(element) { - return new goog.math.Coordinate( - /** @type {!HTMLElement} */ (element).offsetLeft, - /** @type {!HTMLElement} */ (element).offsetTop); + /** @type {Cesium.optionsOrientation} */ + var orientation = { + pitch: this.tilt_ - Cesium.Math.PI_OVER_TWO, + heading: -this.view_.getRotation(), + roll: undefined + }; + this.cam_.setView({ + destination: destination, + orientation: orientation + }); + + this.cam_.moveBackward(this.distance_); + + this.checkCameraChange(true); }; /** - * Returns the viewport element for a particular document - * @param {Node=} opt_node DOM node (Document is OK) to get the viewport element - * of. - * @return {Element} document.documentElement or document.body. + * Calculates the values of the properties from the current ol.View state. + * @api */ -goog.style.getClientViewportElement = function(opt_node) { - var doc; - if (opt_node) { - doc = goog.dom.getOwnerDocument(opt_node); - } else { - doc = goog.dom.getDocument(); +olcs.Camera.prototype.readFromView = function() { + if (goog.isNull(this.view_) || goog.isNull(this.toLonLat_)) { + return; } - - // In old IE versions the document.body represented the viewport - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) && - !goog.dom.getDomHelper(doc).isCss1CompatMode()) { - return doc.body; + var center = this.view_.getCenter(); + if (!goog.isDefAndNotNull(center)) { + return; } - return doc.documentElement; -}; + var ll = this.toLonLat_(center); + goog.asserts.assert(!goog.isNull(ll)); + var resolution = this.view_.getResolution(); + this.distance_ = this.calcDistanceForResolution_( + goog.isDef(resolution) ? resolution : 0, goog.math.toRadians(ll[1])); -/** - * Calculates the viewport coordinates relative to the page/document - * containing the node. The viewport may be the browser viewport for - * non-iframe document, or the iframe container for iframe'd document. - * @param {!Document} doc The document to use as the reference point. - * @return {!goog.math.Coordinate} The page offset of the viewport. - */ -goog.style.getViewportPageOffset = function(doc) { - var body = doc.body; - var documentElement = doc.documentElement; - var scrollLeft = body.scrollLeft || documentElement.scrollLeft; - var scrollTop = body.scrollTop || documentElement.scrollTop; - return new goog.math.Coordinate(scrollLeft, scrollTop); + this.updateCamera_(); }; /** - * Gets the client rectangle of the DOM element. - * - * getBoundingClientRect is part of a new CSS object model draft (with a - * long-time presence in IE), replacing the error-prone parent offset - * computation and the now-deprecated Gecko getBoxObjectFor. - * - * This utility patches common browser bugs in getBoundingClientRect. It - * will fail if getBoundingClientRect is unsupported. - * - * If the element is not in the DOM, the result is undefined, and an error may - * be thrown depending on user agent. - * - * @param {!Element} el The element whose bounding rectangle is being queried. - * @return {Object} A native bounding rectangle with numerical left, top, - * right, and bottom. Reported by Firefox to be of object type ClientRect. - * @private + * Calculates the values of the properties from the current Cesium.Camera state. + * Modifies the center, resolution and rotation properties of the view. + * @api */ -goog.style.getBoundingClientRect_ = function(el) { - var rect; - try { - rect = el.getBoundingClientRect(); - } catch (e) { - // In IE < 9, calling getBoundingClientRect on an orphan element raises an - // "Unspecified Error". All other browsers return zeros. - return {'left': 0, 'top': 0, 'right': 0, 'bottom': 0}; +olcs.Camera.prototype.updateView = function() { + if (goog.isNull(this.view_) || goog.isNull(this.fromLonLat_)) { + return; } + this.viewUpdateInProgress_ = true; - // Patch the result in IE only, so that this function can be inlined if - // compiled for non-IE. - if (goog.userAgent.IE && el.ownerDocument.body) { + // target & distance + var ellipsoid = Cesium.Ellipsoid.WGS84; + var scene = this.scene_; + var target = olcs.core.pickCenterPoint(scene); - // In IE, most of the time, 2 extra pixels are added to the top and left - // due to the implicit 2-pixel inset border. In IE6/7 quirks mode and - // IE6 standards mode, this border can be overridden by setting the - // document element's border to zero -- thus, we cannot rely on the - // offset always being 2 pixels. + var bestTarget = target; + if (!bestTarget) { + //TODO: how to handle this properly ? + var globe = scene.globe; + var carto = this.cam_.positionCartographic.clone(); + var height = globe.getHeight(carto); + carto.height = goog.isDef(height) ? height : 0; + bestTarget = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); + } + this.distance_ = Cesium.Cartesian3.distance(bestTarget, this.cam_.position); + var bestTargetCartographic = ellipsoid.cartesianToCartographic(bestTarget); + this.view_.setCenter(this.fromLonLat_([ + goog.math.toDegrees(bestTargetCartographic.longitude), + goog.math.toDegrees(bestTargetCartographic.latitude)])); - // In quirks mode, the offset can be determined by querying the body's - // clientLeft/clientTop, but in standards mode, it is found by querying - // the document element's clientLeft/clientTop. Since we already called - // getBoundingClientRect we have already forced a reflow, so it is not - // too expensive just to query them all. + // resolution + this.view_.setResolution( + this.calcResolutionForDistance_(this.distance_, + bestTargetCartographic ? bestTargetCartographic.latitude : 0)); - // See: http://msdn.microsoft.com/en-us/library/ms536433(VS.85).aspx - var doc = el.ownerDocument; - rect.left -= doc.documentElement.clientLeft + doc.body.clientLeft; - rect.top -= doc.documentElement.clientTop + doc.body.clientTop; + + /* + * Since we are positioning the target, the values of heading and tilt + * need to be calculated _at the target_. + */ + if (target) { + var pos = this.cam_.position; + + // normal to the ellipsoid at the target + var targetNormal = new Cesium.Cartesian3(); + ellipsoid.geocentricSurfaceNormal(target, targetNormal); + + // vector from the target to the camera + var targetToCamera = new Cesium.Cartesian3(); + Cesium.Cartesian3.subtract(pos, target, targetToCamera); + Cesium.Cartesian3.normalize(targetToCamera, targetToCamera); + + + // HEADING + var up = this.cam_.up; + var right = this.cam_.right; + var normal = new Cesium.Cartesian3(-target.y, target.x, 0); // what is it? + var heading = Cesium.Cartesian3.angleBetween(right, normal); + var cross = Cesium.Cartesian3.cross(target, up, new Cesium.Cartesian3()); + var orientation = cross.z; + + this.view_.setRotation((orientation < 0 ? heading : -heading)); + + // TILT + var tiltAngle = Math.acos( + Cesium.Cartesian3.dot(targetNormal, targetToCamera)); + this.tilt_ = isNaN(tiltAngle) ? 0 : tiltAngle; + } else { + // fallback when there is no target + this.view_.setRotation(this.cam_.heading); + this.tilt_ = -this.cam_.pitch + Math.PI / 2; } - return rect; + + this.viewUpdateInProgress_ = false; }; /** - * Returns the first parent that could affect the position of a given element. - * @param {Element} element The element to get the offset parent for. - * @return {Element} The first offset parent or null if one cannot be found. + * Check if the underlying camera state has changed and ensure synchronization. + * @param {boolean=} opt_dontSync Do not synchronize the view. */ -goog.style.getOffsetParent = function(element) { - // element.offsetParent does the right thing in IE7 and below. In other - // browsers it only includes elements with position absolute, relative or - // fixed, not elements with overflow set to auto or scroll. - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(8)) { - return element.offsetParent; - } +olcs.Camera.prototype.checkCameraChange = function(opt_dontSync) { + var old = this.lastCameraViewMatrix_; + var current = this.cam_.viewMatrix; - var doc = goog.dom.getOwnerDocument(element); - var positionStyle = goog.style.getStyle_(element, 'position'); - var skipStatic = positionStyle == 'fixed' || positionStyle == 'absolute'; - for (var parent = element.parentNode; parent && parent != doc; - parent = parent.parentNode) { - // Skip shadowDOM roots. - if (parent.nodeType == goog.dom.NodeType.DOCUMENT_FRAGMENT && - parent.host) { - parent = parent.host; - } - positionStyle = - goog.style.getStyle_(/** @type {!Element} */ (parent), 'position'); - skipStatic = skipStatic && positionStyle == 'static' && - parent != doc.documentElement && parent != doc.body; - if (!skipStatic && (parent.scrollWidth > parent.clientWidth || - parent.scrollHeight > parent.clientHeight || - positionStyle == 'fixed' || - positionStyle == 'absolute' || - positionStyle == 'relative')) { - return /** @type {!Element} */ (parent); + if (!old || !Cesium.Matrix4.equalsEpsilon(old, current, 1e-5)) { + this.lastCameraViewMatrix_ = current.clone(); + if (opt_dontSync !== true) { + this.updateView(); } } - return null; }; /** - * Calculates and returns the visible rectangle for a given element. Returns a - * box describing the visible portion of the nearest scrollable offset ancestor. - * Coordinates are given relative to the document. - * - * @param {Element} element Element to get the visible rect for. - * @return {goog.math.Box} Bounding elementBox describing the visible rect or - * null if scrollable ancestor isn't inside the visible viewport. + * @param {number} resolution Number of map units per pixel. + * @param {number} latitude Latitude in radians. + * @return {number} The calculated distance. + * @private */ -goog.style.getVisibleRectForElement = function(element) { - var visibleRect = new goog.math.Box(0, Infinity, Infinity, 0); - var dom = goog.dom.getDomHelper(element); - var body = dom.getDocument().body; - var documentElement = dom.getDocument().documentElement; - var scrollEl = dom.getDocumentScrollElement(); +olcs.Camera.prototype.calcDistanceForResolution_ = function(resolution, + latitude) { + var canvas = this.scene_.canvas; + var fovy = this.cam_.frustum.fovy; // vertical field of view + var metersPerUnit = this.view_.getProjection().getMetersPerUnit(); - // Determine the size of the visible rect by climbing the dom accounting for - // all scrollable containers. - for (var el = element; el = goog.style.getOffsetParent(el); ) { - // clientWidth is zero for inline block elements in IE. - // on WEBKIT, body element can have clientHeight = 0 and scrollHeight > 0 - if ((!goog.userAgent.IE || el.clientWidth != 0) && - (!goog.userAgent.WEBKIT || el.clientHeight != 0 || el != body) && - // body may have overflow set on it, yet we still get the entire - // viewport. In some browsers, el.offsetParent may be - // document.documentElement, so check for that too. - (el != body && el != documentElement && - goog.style.getStyle_(el, 'overflow') != 'visible')) { - var pos = goog.style.getPageOffset(el); - var client = goog.style.getClientLeftTop(el); - pos.x += client.x; - pos.y += client.y; + // number of "map units" visible in 2D (vertically) + var visibleMapUnits = resolution * canvas.clientHeight; - visibleRect.top = Math.max(visibleRect.top, pos.y); - visibleRect.right = Math.min(visibleRect.right, - pos.x + el.clientWidth); - visibleRect.bottom = Math.min(visibleRect.bottom, - pos.y + el.clientHeight); - visibleRect.left = Math.max(visibleRect.left, pos.x); - } - } + // The metersPerUnit does not take latitude into account, but it should + // be lower with increasing latitude -- we have to compensate. + // In 3D it is not possible to maintain the resolution at more than one point, + // so it only makes sense to use the latitude of the "target" point. + var relativeCircumference = Math.cos(Math.abs(latitude)); - // Clip by window's viewport. - var scrollX = scrollEl.scrollLeft, scrollY = scrollEl.scrollTop; - visibleRect.left = Math.max(visibleRect.left, scrollX); - visibleRect.top = Math.max(visibleRect.top, scrollY); - var winSize = dom.getViewportSize(); - visibleRect.right = Math.min(visibleRect.right, scrollX + winSize.width); - visibleRect.bottom = Math.min(visibleRect.bottom, scrollY + winSize.height); - return visibleRect.top >= 0 && visibleRect.left >= 0 && - visibleRect.bottom > visibleRect.top && - visibleRect.right > visibleRect.left ? - visibleRect : null; -}; + // how many meters should be visible in 3D + var visibleMeters = visibleMapUnits * metersPerUnit * relativeCircumference; + // distance required to view the calculated length in meters + // + // fovy/2 + // |\ + // x | \ + // |--\ + // visibleMeters/2 + var requiredDistance = (visibleMeters / 2) / Math.tan(fovy / 2); -/** - * Calculate the scroll position of {@code container} with the minimum amount so - * that the content and the borders of the given {@code element} become visible. - * If the element is bigger than the container, its top left corner will be - * aligned as close to the container's top left corner as possible. - * - * @param {Element} element The element to make visible. - * @param {Element=} opt_container The container to scroll. If not set, then the - * document scroll element will be used. - * @param {boolean=} opt_center Whether to center the element in the container. - * Defaults to false. - * @return {!goog.math.Coordinate} The new scroll position of the container, - * in form of goog.math.Coordinate(scrollLeft, scrollTop). - */ -goog.style.getContainerOffsetToScrollInto = - function(element, opt_container, opt_center) { - var container = opt_container || goog.dom.getDocumentScrollElement(); - // Absolute position of the element's border's top left corner. - var elementPos = goog.style.getPageOffset(element); - // Absolute position of the container's border's top left corner. - var containerPos = goog.style.getPageOffset(container); - var containerBorder = goog.style.getBorderBox(container); - if (container == goog.dom.getDocumentScrollElement()) { - // The element position is calculated based on the page offset, and the - // document scroll element holds the scroll position within the page. We can - // use the scroll position to calculate the relative position from the - // element. - var relX = elementPos.x - container.scrollLeft; - var relY = elementPos.y - container.scrollTop; - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) { - // In older versions of IE getPageOffset(element) does not include the - // container border so it has to be added to accomodate. - relX += containerBorder.left; - relY += containerBorder.top; - } - } else { - // Relative pos. of the element's border box to the container's content box. - var relX = elementPos.x - containerPos.x - containerBorder.left; - var relY = elementPos.y - containerPos.y - containerBorder.top; - } - // How much the element can move in the container, i.e. the difference between - // the element's bottom-right-most and top-left-most position where it's - // fully visible. - var spaceX = container.clientWidth - - /** @type {HTMLElement} */ (element).offsetWidth; - var spaceY = container.clientHeight - - /** @type {HTMLElement} */ (element).offsetHeight; + // NOTE: This calculation is not absolutely precise, because metersPerUnit + // is a great simplification. It does not take ellipsoid/terrain into account. - var scrollLeft = container.scrollLeft; - var scrollTop = container.scrollTop; - if (opt_center) { - // All browsers round non-integer scroll positions down. - scrollLeft += relX - spaceX / 2; - scrollTop += relY - spaceY / 2; - } else { - // This formula was designed to give the correct scroll values in the - // following cases: - // - element is higher than container (spaceY < 0) => scroll down by relY - // - element is not higher that container (spaceY >= 0): - // - it is above container (relY < 0) => scroll up by abs(relY) - // - it is below container (relY > spaceY) => scroll down by relY - spaceY - // - it is in the container => don't scroll - scrollLeft += Math.min(relX, Math.max(relX - spaceX, 0)); - scrollTop += Math.min(relY, Math.max(relY - spaceY, 0)); - } - return new goog.math.Coordinate(scrollLeft, scrollTop); + return requiredDistance; }; /** - * Changes the scroll position of {@code container} with the minimum amount so - * that the content and the borders of the given {@code element} become visible. - * If the element is bigger than the container, its top left corner will be - * aligned as close to the container's top left corner as possible. - * - * @param {Element} element The element to make visible. - * @param {Element=} opt_container The container to scroll. If not set, then the - * document scroll element will be used. - * @param {boolean=} opt_center Whether to center the element in the container. - * Defaults to false. + * @param {number} distance + * @param {number} latitude + * @return {number} The calculated resolution. + * @private */ -goog.style.scrollIntoContainerView = - function(element, opt_container, opt_center) { - var container = opt_container || goog.dom.getDocumentScrollElement(); - var offset = - goog.style.getContainerOffsetToScrollInto(element, container, opt_center); - container.scrollLeft = offset.x; - container.scrollTop = offset.y; -}; +olcs.Camera.prototype.calcResolutionForDistance_ = function(distance, + latitude) { + // See the reverse calculation (calcDistanceForResolution_) for details + var canvas = this.scene_.canvas; + var fovy = this.cam_.frustum.fovy; + var metersPerUnit = this.view_.getProjection().getMetersPerUnit(); + var visibleMeters = 2 * distance * Math.tan(fovy / 2); + var relativeCircumference = Math.cos(Math.abs(latitude)); + var visibleMapUnits = visibleMeters / metersPerUnit / relativeCircumference; + var resolution = visibleMapUnits / canvas.clientHeight; -/** - * Returns clientLeft (width of the left border and, if the directionality is - * right to left, the vertical scrollbar) and clientTop as a coordinate object. - * - * @param {Element} el Element to get clientLeft for. - * @return {!goog.math.Coordinate} Client left and top. - */ -goog.style.getClientLeftTop = function(el) { - return new goog.math.Coordinate(el.clientLeft, el.clientTop); + return resolution; }; +goog.provide('olcs.core.VectorLayerCounterpart'); -/** - * Returns a Coordinate object relative to the top-left of the HTML document. - * Implemented as a single function to save having to do two recursive loops in - * opera and safari just to get both coordinates. If you just want one value do - * use goog.style.getPageOffsetLeft() and goog.style.getPageOffsetTop(), but - * note if you call both those methods the tree will be analysed twice. - * - * @param {Element} el Element to get the page offset for. - * @return {!goog.math.Coordinate} The page offset. - */ -goog.style.getPageOffset = function(el) { - var doc = goog.dom.getOwnerDocument(el); - // TODO(gboyer): Update the jsdoc in a way that doesn't break the universe. - goog.asserts.assertObject(el, 'Parameter is required'); +goog.require('ol.Observable'); - // NOTE(arv): If element is hidden (display none or disconnected or any the - // ancestors are hidden) we get (0,0) by default but we still do the - // accumulation of scroll position. - // TODO(arv): Should we check if the node is disconnected and in that case - // return (0,0)? - var pos = new goog.math.Coordinate(0, 0); - var viewportElement = goog.style.getClientViewportElement(doc); - if (el == viewportElement) { - // viewport is always at 0,0 as that defined the coordinate system for this - // function - this avoids special case checks in the code below - return pos; - } +/** + * Result of the conversion of an OpenLayers layer to Cesium. + * @constructor + * @param {!(ol.proj.Projection|string)} layerProjection + * @param {!Cesium.Scene} scene + */ +olcs.core.VectorLayerCounterpart = function(layerProjection, scene) { + var billboards = new Cesium.BillboardCollection({scene: scene}); + var primitives = new Cesium.PrimitiveCollection(); - var box = goog.style.getBoundingClientRect_(el); - // Must add the scroll coordinates in to get the absolute page offset - // of element since getBoundingClientRect returns relative coordinates to - // the viewport. - var scrollCoord = goog.dom.getDomHelper(doc).getDocumentScroll(); - pos.x = box.left + scrollCoord.x; - pos.y = box.top + scrollCoord.y; + /** + * @type {!Array.<goog.events.Key>} + */ + this.olListenKeys = []; - return pos; + this.rootCollection_ = new Cesium.PrimitiveCollection(); + /** + * @type {!olcsx.core.OlFeatureToCesiumContext} + */ + this.context = { + projection: layerProjection, + billboards: billboards, + featureToCesiumMap: {}, + primitives: primitives + }; + + this.rootCollection_.add(billboards); + this.rootCollection_.add(primitives); }; /** - * Returns the left coordinate of an element relative to the HTML document - * @param {Element} el Elements. - * @return {number} The left coordinate. + * Unlisten. */ -goog.style.getPageOffsetLeft = function(el) { - return goog.style.getPageOffset(el).x; +olcs.core.VectorLayerCounterpart.prototype.destroy = function() { + this.olListenKeys.forEach(ol.Observable.unByKey); + this.olListenKeys.length = 0; }; /** - * Returns the top coordinate of an element relative to the HTML document - * @param {Element} el Elements. - * @return {number} The top coordinate. + * @return {!Cesium.Primitive} */ -goog.style.getPageOffsetTop = function(el) { - return goog.style.getPageOffset(el).y; +olcs.core.VectorLayerCounterpart.prototype.getRootPrimitive = function() { + return this.rootCollection_; }; +// FIXME: box style +goog.provide('olcs.DragBox'); +goog.provide('olcs.DragBoxEventType'); -/** - * Returns a Coordinate object relative to the top-left of an HTML document - * in an ancestor frame of this element. Used for measuring the position of - * an element inside a frame relative to a containing frame. - * - * @param {Element} el Element to get the page offset for. - * @param {Window} relativeWin The window to measure relative to. If relativeWin - * is not in the ancestor frame chain of the element, we measure relative to - * the top-most window. - * @return {!goog.math.Coordinate} The page offset. - */ -goog.style.getFramedPageOffset = function(el, relativeWin) { - var position = new goog.math.Coordinate(0, 0); - - // Iterate up the ancestor frame chain, keeping track of the current window - // and the current element in that window. - var currentWin = goog.dom.getWindow(goog.dom.getOwnerDocument(el)); - var currentEl = el; - do { - // if we're at the top window, we want to get the page offset. - // if we're at an inner frame, we only want to get the window position - // so that we can determine the actual page offset in the context of - // the outer window. - var offset = currentWin == relativeWin ? - goog.style.getPageOffset(currentEl) : - goog.style.getClientPositionForElement_( - goog.asserts.assert(currentEl)); +goog.require('goog.asserts'); +goog.require('goog.events.EventTarget'); - position.x += offset.x; - position.y += offset.y; - } while (currentWin && currentWin != relativeWin && - currentWin != currentWin.parent && - (currentEl = currentWin.frameElement) && - (currentWin = currentWin.parent)); - return position; +/** + * @enum {string} + */ +olcs.DragBoxEventType = { + /** + * Triggered upon drag box start. + */ + BOXSTART: 'boxstart', + /** + * Triggered upon drag box end. + */ + BOXEND: 'boxend' }; + /** - * Translates the specified rect relative to origBase page, for newBase page. - * If origBase and newBase are the same, this function does nothing. - * - * @param {goog.math.Rect} rect The source rectangle relative to origBase page, - * and it will have the translated result. - * @param {goog.dom.DomHelper} origBase The DomHelper for the input rectangle. - * @param {goog.dom.DomHelper} newBase The DomHelper for the resultant - * coordinate. This must be a DOM for an ancestor frame of origBase - * or the same as origBase. + * @constructor + * @extends {goog.events.EventTarget} + * @param {Object=} opt_options Options. + * @api + * @struct */ -goog.style.translateRectForAnotherFrame = function(rect, origBase, newBase) { - if (origBase.getDocument() != newBase.getDocument()) { - var body = origBase.getDocument().body; - var pos = goog.style.getFramedPageOffset(body, newBase.getWindow()); +olcs.DragBox = function(opt_options) { - // Adjust Body's margin. - pos = goog.math.Coordinate.difference(pos, goog.style.getPageOffset(body)); + var options = goog.isDef(opt_options) ? opt_options : {}; - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) && - !origBase.isCss1CompatMode()) { - pos = goog.math.Coordinate.difference(pos, origBase.getDocumentScroll()); - } + goog.base(this); - rect.left += pos.x; - rect.top += pos.y; - } -}; + /** + * @private + * @type {Cesium.Scene} + */ + this.scene_ = null; + /** + * @private + * @type {Cesium.ScreenSpaceEventHandler} + */ + this.handler_ = null; + + /** + * @private + * @type {Cesium.RectanglePrimitive} + */ + this.box_ = new Cesium.RectanglePrimitive({ + asynchronous: false, + rectangle: new Cesium.Rectangle(), + material: Cesium.Material.fromType(Cesium.Material.ColorType) + }); + + // FIXME: configurable + this.box_.material.uniforms.color = new Cesium.Color(0.0, 0.0, 1.0, 0.5); + + /** + * @private + * @type {Cesium.KeyboardEventModifier|undefined} + */ + this.modifier_ = goog.isDef(options.modifier) ? + options.modifier : Cesium.KeyboardEventModifier.SHIFT; + + /** + * @private + * @type {Cesium.Cartographic} + */ + this.startPosition_ = null; -/** - * Returns the position of an element relative to another element in the - * document. A relative to B - * @param {Element|Event|goog.events.Event} a Element or mouse event whose - * position we're calculating. - * @param {Element|Event|goog.events.Event} b Element or mouse event position - * is relative to. - * @return {!goog.math.Coordinate} The relative position. - */ -goog.style.getRelativePosition = function(a, b) { - var ap = goog.style.getClientPosition(a); - var bp = goog.style.getClientPosition(b); - return new goog.math.Coordinate(ap.x - bp.x, ap.y - bp.y); }; +goog.inherits(olcs.DragBox, goog.events.EventTarget); /** - * Returns the position of the event or the element's border box relative to - * the client viewport. - * @param {!Element} el Element whose position to get. - * @return {!goog.math.Coordinate} The position. - * @private + * @param {Object} event Mouse down event. */ -goog.style.getClientPositionForElement_ = function(el) { - var box = goog.style.getBoundingClientRect_(el); - return new goog.math.Coordinate(box.left, box.top); +olcs.DragBox.prototype.handleMouseDown = function(event) { + var ellipsoid = this.scene_.globe.ellipsoid; + var ray = this.scene_.camera.getPickRay(event.position); + var intersection = this.scene_.globe.pick(ray, this.scene_); + if (goog.isDef(intersection)) { + this.handler_.setInputAction(this.handleMouseMove.bind(this), + Cesium.ScreenSpaceEventType.MOUSE_MOVE); + this.handler_.setInputAction(this.handleMouseUp.bind(this), + Cesium.ScreenSpaceEventType.LEFT_UP); + + if (goog.isDef(this.modifier_)) { + // listen to the event with and without the modifier to be able to start + // a box with the key pressed and finish it without. + this.handler_.setInputAction(this.handleMouseMove.bind(this), + Cesium.ScreenSpaceEventType.MOUSE_MOVE, this.modifier_); + this.handler_.setInputAction(this.handleMouseUp.bind(this), + Cesium.ScreenSpaceEventType.LEFT_UP, this.modifier_); + } + var cartographic = ellipsoid.cartesianToCartographic(intersection); + var rectangle = this.box_.rectangle; + rectangle.north = rectangle.south = cartographic.latitude; + rectangle.east = rectangle.west = cartographic.longitude; + this.box_.height = cartographic.height; + + this.box_.show = true; + + this.dispatchEvent({ + type: olcs.DragBoxEventType.BOXSTART, + position: cartographic + }); + + goog.asserts.assert(!goog.isNull(this.box_)); + if (!this.scene_.primitives.contains(this.box_)) { + this.scene_.primitives.add(this.box_); + } + this.scene_.screenSpaceCameraController.enableInputs = false; + + this.startPosition_ = cartographic; + } }; /** - * Returns the position of the event or the element's border box relative to - * the client viewport. If an event is passed, and if this event is a "touch" - * event, then the position of the first changedTouches will be returned. - * @param {Element|Event|goog.events.Event} el Element or a mouse / touch event. - * @return {!goog.math.Coordinate} The position. + * @param {Object} event Mouse move event. */ -goog.style.getClientPosition = function(el) { - goog.asserts.assert(el); - if (el.nodeType == goog.dom.NodeType.ELEMENT) { - return goog.style.getClientPositionForElement_( - /** @type {!Element} */ (el)); - } else { - var targetEvent = el.changedTouches ? el.changedTouches[0] : el; - return new goog.math.Coordinate( - targetEvent.clientX, - targetEvent.clientY); +olcs.DragBox.prototype.handleMouseMove = function(event) { + var ellipsoid = this.scene_.globe.ellipsoid; + var ray = this.scene_.camera.getPickRay(event.endPosition); + var intersection = this.scene_.globe.pick(ray, this.scene_); + if (goog.isDef(intersection)) { + var cartographic = ellipsoid.cartesianToCartographic(intersection); + this.box_.height = Math.max(this.box_.height, cartographic.height); + + if (cartographic.latitude < this.startPosition_.latitude) { + this.box_.rectangle.south = cartographic.latitude; + } else { + this.box_.rectangle.north = cartographic.latitude; + } + if (cartographic.longitude < this.startPosition_.longitude) { + this.box_.rectangle.west = cartographic.longitude; + } else { + this.box_.rectangle.east = cartographic.longitude; + } } }; /** - * Moves an element to the given coordinates relative to the client viewport. - * @param {Element} el Absolutely positioned element to set page offset for. - * It must be in the document. - * @param {number|goog.math.Coordinate} x Left position of the element's margin - * box or a coordinate object. - * @param {number=} opt_y Top position of the element's margin box. + * @param {Object} event Mouse up event. */ -goog.style.setPageOffset = function(el, x, opt_y) { - // Get current pageoffset - var cur = goog.style.getPageOffset(el); - - if (x instanceof goog.math.Coordinate) { - opt_y = x.y; - x = x.x; - } +olcs.DragBox.prototype.handleMouseUp = function(event) { + var ellipsoid = this.scene_.globe.ellipsoid; + var ray = this.scene_.camera.getPickRay(event.position); + var intersection = this.scene_.globe.pick(ray, this.scene_); + if (goog.isDef(intersection)) { + var cartographic = ellipsoid.cartesianToCartographic(intersection); - // NOTE(arv): We cannot allow strings for x and y. We could but that would - // require us to manually transform between different units + this.box_.show = false; - // Work out deltas - var dx = x - cur.x; - var dy = opt_y - cur.y; + this.dispatchEvent({ + type: olcs.DragBoxEventType.BOXEND, + position: cartographic + }); - // Set position to current left/top + delta - goog.style.setPosition(el, /** @type {!HTMLElement} */ (el).offsetLeft + dx, - /** @type {!HTMLElement} */ (el).offsetTop + dy); + this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP); + this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE); + if (goog.isDef(this.modifier_)) { + this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP, + this.modifier_); + this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE, + this.modifier_); + } + } + this.scene_.screenSpaceCameraController.enableInputs = true; }; /** - * Sets the width/height values of an element. If an argument is numeric, - * or a goog.math.Size is passed, it is assumed to be pixels and will add - * 'px' after converting it to an integer in string form. (This just sets the - * CSS width and height properties so it might set content-box or border-box - * size depending on the box model the browser is using.) - * - * @param {Element} element Element to set the size of. - * @param {string|number|goog.math.Size} w Width of the element, or a - * size object. - * @param {string|number=} opt_h Height of the element. Required if w is not a - * size object. + * @param {Cesium.Scene} scene Scene. + * @api */ -goog.style.setSize = function(element, w, opt_h) { - var h; - if (w instanceof goog.math.Size) { - h = w.height; - w = w.width; - } else { - if (opt_h == undefined) { - throw Error('missing height argument'); +olcs.DragBox.prototype.setScene = function(scene) { + if (goog.isNull(scene)) { + goog.asserts.assert(!goog.isNull(this.box_)); + if (this.scene_.primitives.contains(this.box_)) { + this.scene_.primitives.remove(this.box_); } - h = opt_h; + if (!goog.isNull(this.handler_)) { + this.handler_.destroy(); + this.handler_ = null; + } + } else { + goog.asserts.assert(scene.canvas); + this.handler_ = new Cesium.ScreenSpaceEventHandler(scene.canvas); + this.handler_.setInputAction(this.handleMouseDown.bind(this), + Cesium.ScreenSpaceEventType.LEFT_DOWN, this.modifier_); } - - goog.style.setWidth(element, /** @type {string|number} */ (w)); - goog.style.setHeight(element, h); + this.scene_ = scene; }; /** - * Helper function to create a string to be set into a pixel-value style - * property of an element. Can round to the nearest integer value. + * Adds an event listener. A listener can only be added once to an + * object and if it is added again the key for the listener is + * returned. Note that if the existing listener is a one-off listener + * (registered via listenOnce), it will no longer be a one-off + * listener after a call to listen(). * - * @param {string|number} value The style value to be used. If a number, - * 'px' will be appended, otherwise the value will be applied directly. - * @param {boolean} round Whether to round the nearest integer (if property - * is a number). - * @return {string} The string value for the property. - * @private + * @param {string|!goog.events.EventId.<EVENTOBJ>} type The event type id. + * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback + * method. + * @param {boolean=} opt_useCapture Whether to fire in capture phase + * (defaults to false). + * @param {SCOPE=} opt_listenerScope Object in whose scope to call the + * listener. + * @return {goog.events.ListenableKey} Unique key for the listener. + * @template SCOPE,EVENTOBJ + * @api */ -goog.style.getPixelStyleValue_ = function(value, round) { - if (typeof value == 'number') { - value = (round ? Math.round(value) : value) + 'px'; - } +olcs.DragBox.prototype.listen; - return value; -}; +goog.provide('ol.geom.Geometry'); +goog.provide('ol.geom.GeometryLayout'); +goog.provide('ol.geom.GeometryType'); + +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('ol.Object'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.proj.Units'); /** - * Set the height of an element. Sets the element's style property. - * @param {Element} element Element to set the height of. - * @param {string|number} height The height value to set. If a number, 'px' - * will be appended, otherwise the value will be applied directly. + * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`, + * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`, + * `'GeometryCollection'`, `'Circle'`. + * @enum {string} + * @api stable */ -goog.style.setHeight = function(element, height) { - element.style.height = goog.style.getPixelStyleValue_(height, true); +ol.geom.GeometryType = { + POINT: 'Point', + LINE_STRING: 'LineString', + LINEAR_RING: 'LinearRing', + POLYGON: 'Polygon', + MULTI_POINT: 'MultiPoint', + MULTI_LINE_STRING: 'MultiLineString', + MULTI_POLYGON: 'MultiPolygon', + GEOMETRY_COLLECTION: 'GeometryCollection', + CIRCLE: 'Circle' }; /** - * Set the width of an element. Sets the element's style property. - * @param {Element} element Element to set the width of. - * @param {string|number} width The width value to set. If a number, 'px' - * will be appended, otherwise the value will be applied directly. + * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z') + * or measure ('M') coordinate is available. Supported values are `'XY'`, + * `'XYZ'`, `'XYM'`, `'XYZM'`. + * @enum {string} + * @api stable */ -goog.style.setWidth = function(element, width) { - element.style.width = goog.style.getPixelStyleValue_(width, true); +ol.geom.GeometryLayout = { + XY: 'XY', + XYZ: 'XYZ', + XYM: 'XYM', + XYZM: 'XYZM' }; + /** - * Gets the height and width of an element, even if its display is none. + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for vector geometries. * - * Specifically, this returns the height and width of the border box, - * irrespective of the box model in effect. + * To get notified of changes to the geometry, register a listener for the + * generic `change` event on your geometry instance. * - * Note that this function does not take CSS transforms into account. Please see - * {@code goog.style.getTransformedSize}. - * @param {Element} element Element to get size of. - * @return {!goog.math.Size} Object with width/height properties. + * @constructor + * @extends {ol.Object} + * @api stable */ -goog.style.getSize = function(element) { - return goog.style.evaluateWithTemporaryDisplay_( - goog.style.getSizeWithDisplay_, /** @type {!Element} */ (element)); -}; +ol.geom.Geometry = function() { + goog.base(this); -/** - * Call {@code fn} on {@code element} such that {@code element}'s dimensions are - * accurate when it's passed to {@code fn}. - * @param {function(!Element): T} fn Function to call with {@code element} as - * an argument after temporarily changing {@code element}'s display such - * that its dimensions are accurate. - * @param {!Element} element Element (which may have display none) to use as - * argument to {@code fn}. - * @return {T} Value returned by calling {@code fn} with {@code element}. - * @template T - * @private - */ -goog.style.evaluateWithTemporaryDisplay_ = function(fn, element) { - if (goog.style.getStyle_(element, 'display') != 'none') { - return fn(element); - } + /** + * @private + * @type {ol.Extent} + */ + this.extent_ = ol.extent.createEmpty(); - var style = element.style; - var originalDisplay = style.display; - var originalVisibility = style.visibility; - var originalPosition = style.position; + /** + * @private + * @type {number} + */ + this.extentRevision_ = -1; - style.visibility = 'hidden'; - style.position = 'absolute'; - style.display = 'inline'; + /** + * @protected + * @type {Object.<string, ol.geom.Geometry>} + */ + this.simplifiedGeometryCache = {}; - var retVal = fn(element); + /** + * @protected + * @type {number} + */ + this.simplifiedGeometryMaxMinSquaredTolerance = 0; - style.display = originalDisplay; - style.position = originalPosition; - style.visibility = originalVisibility; + /** + * @protected + * @type {number} + */ + this.simplifiedGeometryRevision = 0; - return retVal; }; +goog.inherits(ol.geom.Geometry, ol.Object); /** - * Gets the height and width of an element when the display is not none. - * @param {Element} element Element to get size of. - * @return {!goog.math.Size} Object with width/height properties. - * @private + * Make a complete copy of the geometry. + * @function + * @return {!ol.geom.Geometry} Clone. */ -goog.style.getSizeWithDisplay_ = function(element) { - var offsetWidth = /** @type {!HTMLElement} */ (element).offsetWidth; - var offsetHeight = /** @type {!HTMLElement} */ (element).offsetHeight; - var webkitOffsetsZero = - goog.userAgent.WEBKIT && !offsetWidth && !offsetHeight; - if ((!goog.isDef(offsetWidth) || webkitOffsetsZero) && - element.getBoundingClientRect) { - // Fall back to calling getBoundingClientRect when offsetWidth or - // offsetHeight are not defined, or when they are zero in WebKit browsers. - // This makes sure that we return for the correct size for SVG elements, but - // will still return 0 on Webkit prior to 534.8, see - // http://trac.webkit.org/changeset/67252. - var clientRect = goog.style.getBoundingClientRect_(element); - return new goog.math.Size(clientRect.right - clientRect.left, - clientRect.bottom - clientRect.top); - } - return new goog.math.Size(offsetWidth, offsetHeight); -}; +ol.geom.Geometry.prototype.clone = goog.abstractMethod; /** - * Gets the height and width of an element, post transform, even if its display - * is none. - * - * This is like {@code goog.style.getSize}, except: - * <ol> - * <li>Takes webkitTransforms such as rotate and scale into account. - * <li>Will return null if {@code element} doesn't respond to - * {@code getBoundingClientRect}. - * <li>Currently doesn't make sense on non-WebKit browsers which don't support - * webkitTransforms. - * </ol> - * @param {!Element} element Element to get size of. - * @return {goog.math.Size} Object with width/height properties. + * @param {number} x X. + * @param {number} y Y. + * @param {ol.Coordinate} closestPoint Closest point. + * @param {number} minSquaredDistance Minimum squared distance. + * @return {number} Minimum squared distance. */ -goog.style.getTransformedSize = function(element) { - if (!element.getBoundingClientRect) { - return null; - } - - var clientRect = goog.style.evaluateWithTemporaryDisplay_( - goog.style.getBoundingClientRect_, element); - return new goog.math.Size(clientRect.right - clientRect.left, - clientRect.bottom - clientRect.top); -}; +ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod; /** - * Returns a bounding rectangle for a given element in page space. - * @param {Element} element Element to get bounds of. Must not be display none. - * @return {!goog.math.Rect} Bounding rectangle for the element. - */ -goog.style.getBounds = function(element) { - var o = goog.style.getPageOffset(element); - var s = goog.style.getSize(element); - return new goog.math.Rect(o.x, o.y, s.width, s.height); + * Return the closest point of the geometry to the passed point as + * {@link ol.Coordinate coordinate}. + * @param {ol.Coordinate} point Point. + * @param {ol.Coordinate=} opt_closestPoint Closest point. + * @return {ol.Coordinate} Closest point. + * @api stable + */ +ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) { + var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN]; + this.closestPointXY(point[0], point[1], closestPoint, Infinity); + return closestPoint; }; /** - * Converts a CSS selector in the form style-property to styleProperty. - * @param {*} selector CSS Selector. - * @return {string} Camel case selector. - * @deprecated Use goog.string.toCamelCase instead. + * @param {ol.Coordinate} coordinate Coordinate. + * @return {boolean} Contains coordinate. */ -goog.style.toCamelCase = function(selector) { - return goog.string.toCamelCase(String(selector)); +ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) { + return this.containsXY(coordinate[0], coordinate[1]); }; /** - * Converts a CSS selector in the form styleProperty to style-property. - * @param {string} selector Camel case selector. - * @return {string} Selector cased. - * @deprecated Use goog.string.toSelectorCase instead. + * @param {ol.Extent} extent Extent. + * @protected + * @return {ol.Extent} extent Extent. */ -goog.style.toSelectorCase = function(selector) { - return goog.string.toSelectorCase(selector); -}; +ol.geom.Geometry.prototype.computeExtent = goog.abstractMethod; /** - * Gets the opacity of a node (x-browser). This gets the inline style opacity - * of the node, and does not take into account the cascaded or the computed - * style for this node. - * @param {Element} el Element whose opacity has to be found. - * @return {number|string} Opacity between 0 and 1 or an empty string {@code ''} - * if the opacity is not set. + * @param {number} x X. + * @param {number} y Y. + * @return {boolean} Contains (x, y). */ -goog.style.getOpacity = function(el) { - var style = el.style; - var result = ''; - if ('opacity' in style) { - result = style.opacity; - } else if ('MozOpacity' in style) { - result = style.MozOpacity; - } else if ('filter' in style) { - var match = style.filter.match(/alpha\(opacity=([\d.]+)\)/); - if (match) { - result = String(match[1] / 100); - } - } - return result == '' ? result : Number(result); -}; +ol.geom.Geometry.prototype.containsXY = goog.functions.FALSE; /** - * Sets the opacity of a node (x-browser). - * @param {Element} el Elements whose opacity has to be set. - * @param {number|string} alpha Opacity between 0 and 1 or an empty string - * {@code ''} to clear the opacity. + * Get the extent of the geometry. + * @param {ol.Extent=} opt_extent Extent. + * @return {ol.Extent} extent Extent. + * @api stable */ -goog.style.setOpacity = function(el, alpha) { - var style = el.style; - if ('opacity' in style) { - style.opacity = alpha; - } else if ('MozOpacity' in style) { - style.MozOpacity = alpha; - } else if ('filter' in style) { - // TODO(arv): Overwriting the filter might have undesired side effects. - if (alpha === '') { - style.filter = ''; - } else { - style.filter = 'alpha(opacity=' + alpha * 100 + ')'; - } +ol.geom.Geometry.prototype.getExtent = function(opt_extent) { + if (this.extentRevision_ != this.getRevision()) { + this.extent_ = this.computeExtent(this.extent_); + this.extentRevision_ = this.getRevision(); } + return ol.extent.returnOrUpdate(this.extent_, opt_extent); }; /** - * Sets the background of an element to a transparent image in a browser- - * independent manner. - * - * This function does not support repeating backgrounds or alternate background - * positions to match the behavior of Internet Explorer. It also does not - * support sizingMethods other than crop since they cannot be replicated in - * browsers other than Internet Explorer. - * - * @param {Element} el The element to set background on. - * @param {string} src The image source URL. + * Create a simplified version of this geometry. For linestrings, this uses + * the the {@link + * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm + * Douglas Peucker} algorithm. For polygons, a quantization-based + * simplification is used to preserve topology. + * @function + * @param {number} tolerance The tolerance distance for simplification. + * @return {ol.geom.Geometry} A new, simplified version of the original + * geometry. + * @api */ -goog.style.setTransparentBackgroundImage = function(el, src) { - var style = el.style; - // It is safe to use the style.filter in IE only. In Safari 'filter' is in - // style object but access to style.filter causes it to throw an exception. - // Note: IE8 supports images with an alpha channel. - if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { - // See TODO in setOpacity. - style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(' + - 'src="' + src + '", sizingMethod="crop")'; - } else { - // Set style properties individually instead of using background shorthand - // to prevent overwriting a pre-existing background color. - style.backgroundImage = 'url(' + src + ')'; - style.backgroundPosition = 'top left'; - style.backgroundRepeat = 'no-repeat'; - } +ol.geom.Geometry.prototype.simplify = function(tolerance) { + return this.getSimplifiedGeometry(tolerance * tolerance); }; /** - * Clears the background image of an element in a browser independent manner. - * @param {Element} el The element to clear background image for. + * Create a simplified version of this geometry using the Douglas Peucker + * algorithm. + * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm + * @function + * @param {number} squaredTolerance Squared tolerance. + * @return {ol.geom.Geometry} Simplified geometry. */ -goog.style.clearTransparentBackgroundImage = function(el) { - var style = el.style; - if ('filter' in style) { - // See TODO in setOpacity. - style.filter = ''; - } else { - // Set style properties individually instead of using background shorthand - // to prevent overwriting a pre-existing background color. - style.backgroundImage = 'none'; - } -}; +ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod; /** - * Shows or hides an element from the page. Hiding the element is done by - * setting the display property to "none", removing the element from the - * rendering hierarchy so it takes up no space. To show the element, the default - * inherited display property is restored (defined either in stylesheets or by - * the browser's default style rules.) - * - * Caveat 1: if the inherited display property for the element is set to "none" - * by the stylesheets, that is the property that will be restored by a call to - * showElement(), effectively toggling the display between "none" and "none". - * - * Caveat 2: if the element display style is set inline (by setting either - * element.style.display or a style attribute in the HTML), a call to - * showElement will clear that setting and defer to the inherited style in the - * stylesheet. - * @param {Element} el Element to show or hide. - * @param {*} display True to render the element in its default style, - * false to disable rendering the element. - * @deprecated Use goog.style.setElementShown instead. + * Get the type of this geometry. + * @function + * @return {ol.geom.GeometryType} Geometry type. */ -goog.style.showElement = function(el, display) { - goog.style.setElementShown(el, display); -}; +ol.geom.Geometry.prototype.getType = goog.abstractMethod; /** - * Shows or hides an element from the page. Hiding the element is done by - * setting the display property to "none", removing the element from the - * rendering hierarchy so it takes up no space. To show the element, the default - * inherited display property is restored (defined either in stylesheets or by - * the browser's default style rules). - * - * Caveat 1: if the inherited display property for the element is set to "none" - * by the stylesheets, that is the property that will be restored by a call to - * setElementShown(), effectively toggling the display between "none" and - * "none". - * - * Caveat 2: if the element display style is set inline (by setting either - * element.style.display or a style attribute in the HTML), a call to - * setElementShown will clear that setting and defer to the inherited style in - * the stylesheet. - * @param {Element} el Element to show or hide. - * @param {*} isShown True to render the element in its default style, - * false to disable rendering the element. + * Apply a transform function to each coordinate of the geometry. + * The geometry is modified in place. + * If you do not want the geometry modified in place, first clone() it and + * then use this function on the clone. + * @function + * @param {ol.TransformFunction} transformFn Transform. */ -goog.style.setElementShown = function(el, isShown) { - el.style.display = isShown ? '' : 'none'; -}; +ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod; /** - * Test whether the given element has been shown or hidden via a call to - * {@link #setElementShown}. - * - * Note this is strictly a companion method for a call - * to {@link #setElementShown} and the same caveats apply; in particular, this - * method does not guarantee that the return value will be consistent with - * whether or not the element is actually visible. + * Test if the geometry and the passed extent intersect. + * @param {ol.Extent} extent Extent. + * @return {boolean} `true` if the geometry and the extent intersect. + * @function + */ +ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod; + + +/** + * Translate the geometry. This modifies the geometry coordinates in place. If + * instead you want a new geometry, first `clone()` this geometry. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @function + */ +ol.geom.Geometry.prototype.translate = goog.abstractMethod; + + +/** + * Transform each coordinate of the geometry from one coordinate reference + * system to another. The geometry is modified in place. + * For example, a line will be transformed to a line and a circle to a circle. + * If you do not want the geometry modified in place, first clone() it and + * then use this function on the clone. * - * @param {Element} el The element to test. - * @return {boolean} Whether the element has been shown. - * @see #setElementShown + * @param {ol.proj.ProjectionLike} source The current projection. Can be a + * string identifier or a {@link ol.proj.Projection} object. + * @param {ol.proj.ProjectionLike} destination The desired projection. Can be a + * string identifier or a {@link ol.proj.Projection} object. + * @return {ol.geom.Geometry} This geometry. Note that original geometry is + * modified in place. + * @api stable */ -goog.style.isElementShown = function(el) { - return el.style.display != 'none'; +ol.geom.Geometry.prototype.transform = function(source, destination) { + goog.asserts.assert( + ol.proj.get(source).getUnits() !== ol.proj.Units.TILE_PIXELS && + ol.proj.get(destination).getUnits() !== ol.proj.Units.TILE_PIXELS, + 'cannot transform geometries with TILE_PIXELS units'); + this.applyTransform(ol.proj.getTransform(source, destination)); + return this; }; +goog.provide('ol.geom.flat.transform'); + +goog.require('goog.vec.Mat4'); + /** - * Installs the styles string into the window that contains opt_element. If - * opt_element is null, the main window is used. - * @param {string} stylesString The style string to install. - * @param {Node=} opt_node Node whose parent document should have the - * styles installed. - * @return {Element|StyleSheet} The style element created. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {Array.<number>=} opt_dest Destination. + * @return {Array.<number>} Transformed coordinates. */ -goog.style.installStyles = function(stylesString, opt_node) { - var dh = goog.dom.getDomHelper(opt_node); - var styleSheet = null; +ol.geom.flat.transform.transform2D = + function(flatCoordinates, offset, end, stride, transform, opt_dest) { + var m00 = goog.vec.Mat4.getElement(transform, 0, 0); + var m10 = goog.vec.Mat4.getElement(transform, 1, 0); + var m01 = goog.vec.Mat4.getElement(transform, 0, 1); + var m11 = goog.vec.Mat4.getElement(transform, 1, 1); + var m03 = goog.vec.Mat4.getElement(transform, 0, 3); + var m13 = goog.vec.Mat4.getElement(transform, 1, 3); + var dest = opt_dest ? opt_dest : []; + var i = 0; + var j; + for (j = offset; j < end; j += stride) { + var x = flatCoordinates[j]; + var y = flatCoordinates[j + 1]; + dest[i++] = m00 * x + m01 * y + m03; + dest[i++] = m10 * x + m11 * y + m13; + } + if (opt_dest && dest.length != i) { + dest.length = i; + } + return dest; +}; - // IE < 11 requires createStyleSheet. Note that doc.createStyleSheet will be - // undefined as of IE 11. - var doc = dh.getDocument(); - if (goog.userAgent.IE && doc.createStyleSheet) { - styleSheet = doc.createStyleSheet(); - goog.style.setStyles(styleSheet, stylesString); - } else { - var head = dh.getElementsByTagNameAndClass(goog.dom.TagName.HEAD)[0]; - // In opera documents are not guaranteed to have a head element, thus we - // have to make sure one exists before using it. - if (!head) { - var body = dh.getElementsByTagNameAndClass(goog.dom.TagName.BODY)[0]; - head = dh.createDom(goog.dom.TagName.HEAD); - body.parentNode.insertBefore(head, body); +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @param {Array.<number>=} opt_dest Destination. + * @return {Array.<number>} Transformed coordinates. + */ +ol.geom.flat.transform.translate = + function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) { + var dest = opt_dest ? opt_dest : []; + var i = 0; + var j, k; + for (j = offset; j < end; j += stride) { + dest[i++] = flatCoordinates[j] + deltaX; + dest[i++] = flatCoordinates[j + 1] + deltaY; + for (k = j + 2; k < j + stride; ++k) { + dest[i++] = flatCoordinates[k]; } - styleSheet = dh.createDom(goog.dom.TagName.STYLE); - // NOTE(user): Setting styles after the style element has been appended - // to the head results in a nasty Webkit bug in certain scenarios. Please - // refer to https://bugs.webkit.org/show_bug.cgi?id=26307 for additional - // details. - goog.style.setStyles(styleSheet, stylesString); - dh.appendChild(head, styleSheet); } - return styleSheet; + if (opt_dest && dest.length != i) { + dest.length = i; + } + return dest; }; +goog.provide('ol.geom.SimpleGeometry'); + +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('ol.extent'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.flat.transform'); + + /** - * Removes the styles added by {@link #installStyles}. - * @param {Element|StyleSheet} styleSheet The value returned by - * {@link #installStyles}. + * @classdesc + * Abstract base class; only used for creating subclasses; do not instantiate + * in apps, as cannot be rendered. + * + * @constructor + * @extends {ol.geom.Geometry} + * @api stable */ -goog.style.uninstallStyles = function(styleSheet) { - var node = styleSheet.ownerNode || styleSheet.owningElement || - /** @type {Element} */ (styleSheet); - goog.dom.removeNode(node); +ol.geom.SimpleGeometry = function() { + + goog.base(this); + + /** + * @protected + * @type {ol.geom.GeometryLayout} + */ + this.layout = ol.geom.GeometryLayout.XY; + + /** + * @protected + * @type {number} + */ + this.stride = 2; + + /** + * @protected + * @type {Array.<number>} + */ + this.flatCoordinates = null; + }; +goog.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry); /** - * Sets the content of a style element. The style element can be any valid - * style element. This element will have its content completely replaced by - * the new stylesString. - * @param {Element|StyleSheet} element A stylesheet element as returned by - * installStyles. - * @param {string} stylesString The new content of the stylesheet. + * @param {number} stride Stride. + * @private + * @return {ol.geom.GeometryLayout} layout Layout. */ -goog.style.setStyles = function(element, stylesString) { - if (goog.userAgent.IE && goog.isDef(element.cssText)) { - // Adding the selectors individually caused the browser to hang if the - // selector was invalid or there were CSS comments. Setting the cssText of - // the style node works fine and ignores CSS that IE doesn't understand. - // However IE >= 11 doesn't support cssText any more, so we make sure that - // cssText is a defined property and otherwise fall back to innerHTML. - element.cssText = stylesString; +ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) { + if (stride == 2) { + return ol.geom.GeometryLayout.XY; + } else if (stride == 3) { + return ol.geom.GeometryLayout.XYZ; + } else if (stride == 4) { + return ol.geom.GeometryLayout.XYZM; } else { - element.innerHTML = stylesString; + goog.asserts.fail('unsupported stride: ' + stride); } }; /** - * Sets 'white-space: pre-wrap' for a node (x-browser). - * - * There are as many ways of specifying pre-wrap as there are browsers. - * - * CSS3/IE8: white-space: pre-wrap; - * Mozilla: white-space: -moz-pre-wrap; - * Opera: white-space: -o-pre-wrap; - * IE6/7: white-space: pre; word-wrap: break-word; - * - * @param {Element} el Element to enable pre-wrap for. + * @param {ol.geom.GeometryLayout} layout Layout. + * @return {number} Stride. */ -goog.style.setPreWrap = function(el) { - var style = el.style; - if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { - style.whiteSpace = 'pre'; - style.wordWrap = 'break-word'; - } else if (goog.userAgent.GECKO) { - style.whiteSpace = '-moz-pre-wrap'; +ol.geom.SimpleGeometry.getStrideForLayout = function(layout) { + if (layout == ol.geom.GeometryLayout.XY) { + return 2; + } else if (layout == ol.geom.GeometryLayout.XYZ) { + return 3; + } else if (layout == ol.geom.GeometryLayout.XYM) { + return 3; + } else if (layout == ol.geom.GeometryLayout.XYZM) { + return 4; } else { - style.whiteSpace = 'pre-wrap'; + goog.asserts.fail('unsupported layout: ' + layout); } }; /** - * Sets 'display: inline-block' for an element (cross-browser). - * @param {Element} el Element to which the inline-block display style is to be - * applied. - * @see ../demos/inline_block_quirks.html - * @see ../demos/inline_block_standards.html + * @inheritDoc */ -goog.style.setInlineBlock = function(el) { - var style = el.style; - // Without position:relative, weirdness ensues. Just accept it and move on. - style.position = 'relative'; +ol.geom.SimpleGeometry.prototype.containsXY = goog.functions.FALSE; - if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { - // IE8 supports inline-block so fall through to the else - // Zoom:1 forces hasLayout, display:inline gives inline behavior. - style.zoom = '1'; - style.display = 'inline'; - } else { - // Opera, Webkit, and Safari seem to do OK with the standard inline-block - // style. - style.display = 'inline-block'; - } + +/** + * @inheritDoc + */ +ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) { + return ol.extent.createOrUpdateFromFlatCoordinates( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + extent); }; /** - * Returns true if the element is using right to left (rtl) direction. - * @param {Element} el The element to test. - * @return {boolean} True for right to left, false for left to right. + * @return {Array} Coordinates. */ -goog.style.isRightToLeft = function(el) { - return 'rtl' == goog.style.getStyle_(el, 'direction'); +ol.geom.SimpleGeometry.prototype.getCoordinates = goog.abstractMethod; + + +/** + * Return the first coordinate of the geometry. + * @return {ol.Coordinate} First coordinate. + * @api stable + */ +ol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() { + return this.flatCoordinates.slice(0, this.stride); }; /** - * The CSS style property corresponding to an element being - * unselectable on the current browser platform (null if none). - * Opera and IE instead use a DOM attribute 'unselectable'. - * @type {?string} - * @private + * @return {Array.<number>} Flat coordinates. */ -goog.style.unselectableStyle_ = - goog.userAgent.GECKO ? 'MozUserSelect' : - goog.userAgent.WEBKIT ? 'WebkitUserSelect' : - null; +ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() { + return this.flatCoordinates; +}; /** - * Returns true if the element is set to be unselectable, false otherwise. - * Note that on some platforms (e.g. Mozilla), even if an element isn't set - * to be unselectable, it will behave as such if any of its ancestors is - * unselectable. - * @param {Element} el Element to check. - * @return {boolean} Whether the element is set to be unselectable. + * Return the last coordinate of the geometry. + * @return {ol.Coordinate} Last point. + * @api stable */ -goog.style.isUnselectable = function(el) { - if (goog.style.unselectableStyle_) { - return el.style[goog.style.unselectableStyle_].toLowerCase() == 'none'; - } else if (goog.userAgent.IE || goog.userAgent.OPERA) { - return el.getAttribute('unselectable') == 'on'; - } - return false; +ol.geom.SimpleGeometry.prototype.getLastCoordinate = function() { + return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride); }; /** - * Makes the element and its descendants selectable or unselectable. Note - * that on some platforms (e.g. Mozilla), even if an element isn't set to - * be unselectable, it will behave as such if any of its ancestors is - * unselectable. - * @param {Element} el The element to alter. - * @param {boolean} unselectable Whether the element and its descendants - * should be made unselectable. - * @param {boolean=} opt_noRecurse Whether to only alter the element's own - * selectable state, and leave its descendants alone; defaults to false. - */ -goog.style.setUnselectable = function(el, unselectable, opt_noRecurse) { - // TODO(attila): Do we need all of TR_DomUtil.makeUnselectable() in Closure? - var descendants = !opt_noRecurse ? el.getElementsByTagName('*') : null; - var name = goog.style.unselectableStyle_; - if (name) { - // Add/remove the appropriate CSS style to/from the element and its - // descendants. - var value = unselectable ? 'none' : ''; - // MathML elements do not have a style property. Verify before setting. - if (el.style) { - el.style[name] = value; - } - if (descendants) { - for (var i = 0, descendant; descendant = descendants[i]; i++) { - if (descendant.style) { - descendant.style[name] = value; - } - } - } - } else if (goog.userAgent.IE || goog.userAgent.OPERA) { - // Toggle the 'unselectable' attribute on the element and its descendants. - var value = unselectable ? 'on' : ''; - el.setAttribute('unselectable', value); - if (descendants) { - for (var i = 0, descendant; descendant = descendants[i]; i++) { - descendant.setAttribute('unselectable', value); - } - } - } -}; - - -/** - * Gets the border box size for an element. - * @param {Element} element The element to get the size for. - * @return {!goog.math.Size} The border box size. + * Return the {@link ol.geom.GeometryLayout layout} of the geometry. + * @return {ol.geom.GeometryLayout} Layout. + * @api stable */ -goog.style.getBorderBoxSize = function(element) { - return new goog.math.Size( - /** @type {!HTMLElement} */ (element).offsetWidth, - /** @type {!HTMLElement} */ (element).offsetHeight); +ol.geom.SimpleGeometry.prototype.getLayout = function() { + return this.layout; }; /** - * Sets the border box size of an element. This is potentially expensive in IE - * if the document is CSS1Compat mode - * @param {Element} element The element to set the size on. - * @param {goog.math.Size} size The new size. + * @inheritDoc */ -goog.style.setBorderBoxSize = function(element, size) { - var doc = goog.dom.getOwnerDocument(element); - var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode(); - - if (goog.userAgent.IE && - !goog.userAgent.isVersionOrHigher('10') && - (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) { - var style = element.style; - if (isCss1CompatMode) { - var paddingBox = goog.style.getPaddingBox(element); - var borderBox = goog.style.getBorderBox(element); - style.pixelWidth = size.width - borderBox.left - paddingBox.left - - paddingBox.right - borderBox.right; - style.pixelHeight = size.height - borderBox.top - paddingBox.top - - paddingBox.bottom - borderBox.bottom; - } else { - style.pixelWidth = size.width; - style.pixelHeight = size.height; - } - } else { - goog.style.setBoxSizingSize_(element, size, 'border-box'); +ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = + function(squaredTolerance) { + if (this.simplifiedGeometryRevision != this.getRevision()) { + goog.object.clear(this.simplifiedGeometryCache); + this.simplifiedGeometryMaxMinSquaredTolerance = 0; + this.simplifiedGeometryRevision = this.getRevision(); } -}; - - -/** - * Gets the content box size for an element. This is potentially expensive in - * all browsers. - * @param {Element} element The element to get the size for. - * @return {!goog.math.Size} The content box size. - */ -goog.style.getContentBoxSize = function(element) { - var doc = goog.dom.getOwnerDocument(element); - var ieCurrentStyle = goog.userAgent.IE && element.currentStyle; - if (ieCurrentStyle && - goog.dom.getDomHelper(doc).isCss1CompatMode() && - ieCurrentStyle.width != 'auto' && ieCurrentStyle.height != 'auto' && - !ieCurrentStyle.boxSizing) { - // If IE in CSS1Compat mode than just use the width and height. - // If we have a boxSizing then fall back on measuring the borders etc. - var width = goog.style.getIePixelValue_(element, ieCurrentStyle.width, - 'width', 'pixelWidth'); - var height = goog.style.getIePixelValue_(element, ieCurrentStyle.height, - 'height', 'pixelHeight'); - return new goog.math.Size(width, height); + // If squaredTolerance is negative or if we know that simplification will not + // have any effect then just return this. + if (squaredTolerance < 0 || + (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && + squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) { + return this; + } + var key = squaredTolerance.toString(); + if (this.simplifiedGeometryCache.hasOwnProperty(key)) { + return this.simplifiedGeometryCache[key]; } else { - var borderBoxSize = goog.style.getBorderBoxSize(element); - var paddingBox = goog.style.getPaddingBox(element); - var borderBox = goog.style.getBorderBox(element); - return new goog.math.Size(borderBoxSize.width - - borderBox.left - paddingBox.left - - paddingBox.right - borderBox.right, - borderBoxSize.height - - borderBox.top - paddingBox.top - - paddingBox.bottom - borderBox.bottom); + var simplifiedGeometry = + this.getSimplifiedGeometryInternal(squaredTolerance); + var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates(); + if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) { + this.simplifiedGeometryCache[key] = simplifiedGeometry; + return simplifiedGeometry; + } else { + // Simplification did not actually remove any coordinates. We now know + // that any calls to getSimplifiedGeometry with a squaredTolerance less + // than or equal to the current squaredTolerance will also not have any + // effect. This allows us to short circuit simplification (saving CPU + // cycles) and prevents the cache of simplified geometries from filling + // up with useless identical copies of this geometry (saving memory). + this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; + return this; + } } }; /** - * Sets the content box size of an element. This is potentially expensive in IE - * if the document is BackCompat mode. - * @param {Element} element The element to set the size on. - * @param {goog.math.Size} size The new size. + * @param {number} squaredTolerance Squared tolerance. + * @return {ol.geom.SimpleGeometry} Simplified geometry. + * @protected */ -goog.style.setContentBoxSize = function(element, size) { - var doc = goog.dom.getOwnerDocument(element); - var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode(); - if (goog.userAgent.IE && - !goog.userAgent.isVersionOrHigher('10') && - (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) { - var style = element.style; - if (isCss1CompatMode) { - style.pixelWidth = size.width; - style.pixelHeight = size.height; - } else { - var paddingBox = goog.style.getPaddingBox(element); - var borderBox = goog.style.getBorderBox(element); - style.pixelWidth = size.width + borderBox.left + paddingBox.left + - paddingBox.right + borderBox.right; - style.pixelHeight = size.height + borderBox.top + paddingBox.top + - paddingBox.bottom + borderBox.bottom; - } - } else { - goog.style.setBoxSizingSize_(element, size, 'content-box'); - } +ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + return this; }; /** - * Helper function that sets the box sizing as well as the width and height - * @param {Element} element The element to set the size on. - * @param {goog.math.Size} size The new size to set. - * @param {string} boxSizing The box-sizing value. - * @private + * @return {number} Stride. */ -goog.style.setBoxSizingSize_ = function(element, size, boxSizing) { - var style = element.style; - if (goog.userAgent.GECKO) { - style.MozBoxSizing = boxSizing; - } else if (goog.userAgent.WEBKIT) { - style.WebkitBoxSizing = boxSizing; - } else { - // Includes IE8 and Opera 9.50+ - style.boxSizing = boxSizing; - } - - // Setting this to a negative value will throw an exception on IE - // (and doesn't do anything different than setting it to 0). - style.width = Math.max(size.width, 0) + 'px'; - style.height = Math.max(size.height, 0) + 'px'; +ol.geom.SimpleGeometry.prototype.getStride = function() { + return this.stride; }; /** - * IE specific function that converts a non pixel unit to pixels. - * @param {Element} element The element to convert the value for. - * @param {string} value The current value as a string. The value must not be - * ''. - * @param {string} name The CSS property name to use for the converstion. This - * should be 'left', 'top', 'width' or 'height'. - * @param {string} pixelName The CSS pixel property name to use to get the - * value in pixels. - * @return {number} The value in pixels. - * @private + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @protected */ -goog.style.getIePixelValue_ = function(element, value, name, pixelName) { - // Try if we already have a pixel value. IE does not do half pixels so we - // only check if it matches a number followed by 'px'. - if (/^\d+px?$/.test(value)) { - return parseInt(value, 10); - } else { - var oldStyleValue = element.style[name]; - var oldRuntimeValue = element.runtimeStyle[name]; - // set runtime style to prevent changes - element.runtimeStyle[name] = element.currentStyle[name]; - element.style[name] = value; - var pixelValue = element.style[pixelName]; - // restore - element.style[name] = oldStyleValue; - element.runtimeStyle[name] = oldRuntimeValue; - return pixelValue; - } +ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = + function(layout, flatCoordinates) { + this.stride = ol.geom.SimpleGeometry.getStrideForLayout(layout); + this.layout = layout; + this.flatCoordinates = flatCoordinates; }; /** - * Helper function for getting the pixel padding or margin for IE. - * @param {Element} element The element to get the padding for. - * @param {string} propName The property name. - * @return {number} The pixel padding. - * @private + * @param {Array} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ -goog.style.getIePixelDistance_ = function(element, propName) { - var value = goog.style.getCascadedStyle(element, propName); - return value ? - goog.style.getIePixelValue_(element, value, 'left', 'pixelLeft') : 0; -}; +ol.geom.SimpleGeometry.prototype.setCoordinates = goog.abstractMethod; /** - * Gets the computed paddings or margins (on all sides) in pixels. - * @param {Element} element The element to get the padding for. - * @param {string} stylePrefix Pass 'padding' to retrieve the padding box, - * or 'margin' to retrieve the margin box. - * @return {!goog.math.Box} The computed paddings or margins. - * @private + * @param {ol.geom.GeometryLayout|undefined} layout Layout. + * @param {Array} coordinates Coordinates. + * @param {number} nesting Nesting. + * @protected */ -goog.style.getBox_ = function(element, stylePrefix) { - if (goog.userAgent.IE) { - var left = goog.style.getIePixelDistance_(element, stylePrefix + 'Left'); - var right = goog.style.getIePixelDistance_(element, stylePrefix + 'Right'); - var top = goog.style.getIePixelDistance_(element, stylePrefix + 'Top'); - var bottom = goog.style.getIePixelDistance_( - element, stylePrefix + 'Bottom'); - return new goog.math.Box(top, right, bottom, left); +ol.geom.SimpleGeometry.prototype.setLayout = + function(layout, coordinates, nesting) { + /** @type {number} */ + var stride; + if (layout) { + stride = ol.geom.SimpleGeometry.getStrideForLayout(layout); } else { - // On non-IE browsers, getComputedStyle is always non-null. - var left = goog.style.getComputedStyle(element, stylePrefix + 'Left'); - var right = goog.style.getComputedStyle(element, stylePrefix + 'Right'); - var top = goog.style.getComputedStyle(element, stylePrefix + 'Top'); - var bottom = goog.style.getComputedStyle(element, stylePrefix + 'Bottom'); - - // NOTE(arv): Gecko can return floating point numbers for the computed - // style values. - return new goog.math.Box(parseFloat(top), - parseFloat(right), - parseFloat(bottom), - parseFloat(left)); + var i; + for (i = 0; i < nesting; ++i) { + if (coordinates.length === 0) { + this.layout = ol.geom.GeometryLayout.XY; + this.stride = 2; + return; + } else { + coordinates = /** @type {Array} */ (coordinates[0]); + } + } + stride = (/** @type {Array} */ (coordinates)).length; + layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride); } + this.layout = layout; + this.stride = stride; }; /** - * Gets the computed paddings (on all sides) in pixels. - * @param {Element} element The element to get the padding for. - * @return {!goog.math.Box} The computed paddings. + * @inheritDoc + * @api stable */ -goog.style.getPaddingBox = function(element) { - return goog.style.getBox_(element, 'padding'); +ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) { + if (this.flatCoordinates) { + transformFn(this.flatCoordinates, this.flatCoordinates, this.stride); + this.changed(); + } }; /** - * Gets the computed margins (on all sides) in pixels. - * @param {Element} element The element to get the margins for. - * @return {!goog.math.Box} The computed margins. + * @inheritDoc + * @api stable */ -goog.style.getMarginBox = function(element) { - return goog.style.getBox_(element, 'margin'); +ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) { + var flatCoordinates = this.getFlatCoordinates(); + if (flatCoordinates) { + var stride = this.getStride(); + ol.geom.flat.transform.translate( + flatCoordinates, 0, flatCoordinates.length, stride, + deltaX, deltaY, flatCoordinates); + this.changed(); + } }; /** - * A map used to map the border width keywords to a pixel width. - * @type {Object} - * @private + * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {Array.<number>=} opt_dest Destination. + * @return {Array.<number>} Transformed flat coordinates. */ -goog.style.ieBorderWidthKeywords_ = { - 'thin': 2, - 'medium': 4, - 'thick': 6 +ol.geom.transformSimpleGeometry2D = + function(simpleGeometry, transform, opt_dest) { + var flatCoordinates = simpleGeometry.getFlatCoordinates(); + if (!flatCoordinates) { + return null; + } else { + var stride = simpleGeometry.getStride(); + return ol.geom.flat.transform.transform2D( + flatCoordinates, 0, flatCoordinates.length, stride, + transform, opt_dest); + } }; +goog.provide('olcs.obj'); + /** - * Helper function for IE to get the pixel border. - * @param {Element} element The element to get the pixel border for. - * @param {string} prop The part of the property name. - * @return {number} The value in pixels. - * @private + * Cast to object. + * @param {Object} param + * @return {Object} */ -goog.style.getIePixelBorder_ = function(element, prop) { - if (goog.style.getCascadedStyle(element, prop + 'Style') == 'none') { - return 0; - } - var width = goog.style.getCascadedStyle(element, prop + 'Width'); - if (width in goog.style.ieBorderWidthKeywords_) { - return goog.style.ieBorderWidthKeywords_[width]; - } - return goog.style.getIePixelValue_(element, width, 'left', 'pixelLeft'); +olcs.obj = function(param) { + return param; }; +goog.provide('olcs.FeatureConverter'); -/** - * Gets the computed border widths (on all sides) in pixels - * @param {Element} element The element to get the border widths for. - * @return {!goog.math.Box} The computed border widths. - */ -goog.style.getBorderBox = function(element) { - if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { - var left = goog.style.getIePixelBorder_(element, 'borderLeft'); - var right = goog.style.getIePixelBorder_(element, 'borderRight'); - var top = goog.style.getIePixelBorder_(element, 'borderTop'); - var bottom = goog.style.getIePixelBorder_(element, 'borderBottom'); - return new goog.math.Box(top, right, bottom, left); - } else { - // On non-IE browsers, getComputedStyle is always non-null. - var left = goog.style.getComputedStyle(element, 'borderLeftWidth'); - var right = goog.style.getComputedStyle(element, 'borderRightWidth'); - var top = goog.style.getComputedStyle(element, 'borderTopWidth'); - var bottom = goog.style.getComputedStyle(element, 'borderBottomWidth'); +goog.require('goog.asserts'); +goog.require('ol.extent'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('olcs.core.VectorLayerCounterpart'); +goog.require('olcs.obj'); - return new goog.math.Box(parseFloat(top), - parseFloat(right), - parseFloat(bottom), - parseFloat(left)); - } -}; /** - * Returns the font face applied to a given node. Opera and IE should return - * the font actually displayed. Firefox returns the author's most-preferred - * font (whether the browser is capable of displaying it or not.) - * @param {Element} el The element whose font family is returned. - * @return {string} The font family applied to el. + * Concrete base class for converting from OpenLayers3 vectors to Cesium + * primitives. + * Extending this class is possible provided that the extending class and + * the library are compiled together by the closure compiler. + * @param {!Cesium.Scene} scene Cesium scene. + * @constructor + * @api + * @struct */ -goog.style.getFontFamily = function(el) { - var doc = goog.dom.getOwnerDocument(el); - var font = ''; - // The moveToElementText method from the TextRange only works if the element - // is attached to the owner document. - if (doc.body.createTextRange && goog.dom.contains(doc, el)) { - var range = doc.body.createTextRange(); - range.moveToElementText(el); - /** @preserveTry */ - try { - font = range.queryCommandValue('FontName'); - } catch (e) { - // This is a workaround for a awkward exception. - // On some IE, there is an exception coming from it. - // The error description from this exception is: - // This window has already been registered as a drop target - // This is bogus description, likely due to a bug in ie. - font = ''; - } - } - if (!font) { - // Note if for some reason IE can't derive FontName with a TextRange, we - // fallback to using currentStyle - font = goog.style.getStyle_(el, 'fontFamily'); - } +olcs.FeatureConverter = function(scene) { - // Firefox returns the applied font-family string (author's list of - // preferred fonts.) We want to return the most-preferred font, in lieu of - // the *actually* applied font. - var fontsArray = font.split(','); - if (fontsArray.length > 1) font = fontsArray[0]; + /** + * @protected + */ + this.scene = scene; - // Sanitize for x-browser consistency: - // Strip quotes because browsers aren't consistent with how they're - // applied; Opera always encloses, Firefox sometimes, and IE never. - return goog.string.stripQuotes(font, '"\''); + /** + * Bind once to have a unique function for using as a listener + * @type {function(ol.source.VectorEvent)} + * @private + */ + this.boundOnRemoveOrClearFeatureListener_ = + this.onRemoveOrClearFeature_.bind(this); }; /** - * Regular expression used for getLengthUnits. - * @type {RegExp} + * @param {ol.source.VectorEvent} evt * @private */ -goog.style.lengthUnitRegex_ = /[^\d]+$/; - +olcs.FeatureConverter.prototype.onRemoveOrClearFeature_ = function(evt) { + var source = evt.target; + goog.asserts.assertInstanceof(source, ol.source.Vector); -/** - * Returns the units used for a CSS length measurement. - * @param {string} value A CSS length quantity. - * @return {?string} The units of measurement. - */ -goog.style.getLengthUnits = function(value) { - var units = value.match(goog.style.lengthUnitRegex_); - return units && units[0] || null; + var cancellers = olcs.obj(source)['olcs_cancellers']; + if (cancellers) { + var feature = evt.feature; + if (goog.isDef(feature)) { + // remove + var id = goog.getUid(feature); + var canceller = cancellers[id]; + if (canceller) { + canceller(); + delete cancellers[id]; + } + } else { + // clear + for (var key in cancellers) { + if (cancellers.hasOwnProperty(key)) { + cancellers[key](); + } + } + olcs.obj(source)['olcs_cancellers'] = {}; + } + } }; /** - * Map of absolute CSS length units - * @type {Object} - * @private + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature. + * @param {!Cesium.Primitive|Cesium.Label|Cesium.Billboard} primitive + * @protected */ -goog.style.ABSOLUTE_CSS_LENGTH_UNITS_ = { - 'cm' : 1, - 'in' : 1, - 'mm' : 1, - 'pc' : 1, - 'pt' : 1 +olcs.FeatureConverter.prototype.setReferenceForPicking = + function(layer, feature, primitive) { + primitive.olLayer = layer; + primitive.olFeature = feature; }; /** - * Map of relative CSS length units that can be accurately converted to px - * font-size values using getIePixelValue_. Only units that are defined in - * relation to a font size are convertible (%, small, etc. are not). - * @type {Object} - * @private - */ -goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_ = { - 'em' : 1, - 'ex' : 1 -}; - - -/** - * Returns the font size, in pixels, of text in an element. - * @param {Element} el The element whose font size is returned. - * @return {number} The font size (in pixels). + * Basics primitive creation using a color attribute. + * Note that Cesium has 'interior' and outline geometries. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature. + * @param {!ol.geom.Geometry} olGeometry Ol3 geometry. + * @param {!Cesium.Geometry} geometry + * @param {!Cesium.Color} color + * @param {number=} opt_lineWidth + * @return {!Cesium.Primitive} + * @protected */ -goog.style.getFontSize = function(el) { - var fontSize = goog.style.getStyle_(el, 'fontSize'); - var sizeUnits = goog.style.getLengthUnits(fontSize); - if (fontSize && 'px' == sizeUnits) { - // NOTE(user): This could be parseFloat instead, but IE doesn't return - // decimal fractions in getStyle_ and Firefox reports the fractions, but - // ignores them when rendering. Interestingly enough, when we force the - // issue and size something to e.g., 50% of 25px, the browsers round in - // opposite directions with Firefox reporting 12px and IE 13px. I punt. - return parseInt(fontSize, 10); - } +olcs.FeatureConverter.prototype.createColoredPrimitive = + function(layer, feature, olGeometry, geometry, color, opt_lineWidth) { + var createInstance = function(geometry, color) { + return new Cesium.GeometryInstance({ + // always update Cesium externs before adding a property + geometry: geometry, + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(color) + } + }); + }; - // In IE, we can convert absolute length units to a px value using - // goog.style.getIePixelValue_. Units defined in relation to a font size - // (em, ex) are applied relative to the element's parentNode and can also - // be converted. - if (goog.userAgent.IE) { - if (sizeUnits in goog.style.ABSOLUTE_CSS_LENGTH_UNITS_) { - return goog.style.getIePixelValue_(el, - fontSize, - 'left', - 'pixelLeft'); - } else if (el.parentNode && - el.parentNode.nodeType == goog.dom.NodeType.ELEMENT && - sizeUnits in goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_) { - // Check the parent size - if it is the same it means the relative size - // value is inherited and we therefore don't want to count it twice. If - // it is different, this element either has explicit style or has a CSS - // rule applying to it. - var parentElement = /** @type {!Element} */ (el.parentNode); - var parentSize = goog.style.getStyle_(parentElement, 'fontSize'); - return goog.style.getIePixelValue_(parentElement, - fontSize == parentSize ? - '1em' : fontSize, - 'left', - 'pixelLeft'); + var options = { + // always update Cesium externs before adding a property + flat: true, // work with all geometries + renderState: { + depthTest: { + enabled: true + } + } + }; + + if (goog.isDef(opt_lineWidth)) { + if (!options.renderState) { + options.renderState = {}; } + options.renderState.lineWidth = opt_lineWidth; } - // Sometimes we can't cleanly find the font size (some units relative to a - // node's parent's font size are difficult: %, smaller et al), so we create - // an invisible, absolutely-positioned span sized to be the height of an 'M' - // rendered in its parent's (i.e., our target element's) font size. This is - // the definition of CSS's font size attribute. - var sizeElement = goog.dom.createDom( - goog.dom.TagName.SPAN, - {'style': 'visibility:hidden;position:absolute;' + - 'line-height:0;padding:0;margin:0;border:0;height:1em;'}); - goog.dom.appendChild(el, sizeElement); - fontSize = sizeElement.offsetHeight; - goog.dom.removeNode(sizeElement); + var instances = createInstance(geometry, color); - return fontSize; -}; + var heightReference = this.getHeightReference(layer, feature, olGeometry); + var primitive; -/** - * Parses a style attribute value. Converts CSS property names to camel case. - * @param {string} value The style attribute value. - * @return {!Object} Map of CSS properties to string values. - */ -goog.style.parseStyleAttribute = function(value) { - var result = {}; - goog.array.forEach(value.split(/\s*;\s*/), function(pair) { - var keyValue = pair.match(/\s*([\w-]+)\s*\:(.+)/); - if (keyValue) { - var styleName = keyValue[1]; - var styleValue = goog.string.trim(keyValue[2]); - result[goog.string.toCamelCase(styleName.toLowerCase())] = styleValue; - } - }); - return result; + if (heightReference == Cesium.HeightReference.CLAMP_TO_GROUND) { + primitive = new Cesium.GroundPrimitive({ + // always update Cesium externs before adding a property + geometryInstance: instances + }); + } else { + var appearance = new Cesium.PerInstanceColorAppearance(options); + primitive = new Cesium.Primitive({ + // always update Cesium externs before adding a property + geometryInstances: instances, + appearance: appearance + }); + } + + this.setReferenceForPicking(layer, feature, primitive); + return primitive; }; /** - * Reverse of parseStyleAttribute; that is, takes a style object and returns the - * corresponding attribute value. Converts camel case property names to proper - * CSS selector names. - * @param {Object} obj Map of CSS properties to values. - * @return {string} The style attribute value. + * Return the fill or stroke color from a plain ol style. + * @param {!ol.style.Style|ol.style.Text} style + * @param {boolean} outline + * @return {!Cesium.Color} + * @protected */ -goog.style.toStyleAttribute = function(obj) { - var buffer = []; - goog.object.forEach(obj, function(value, key) { - buffer.push(goog.string.toSelectorCase(key), ':', value, ';'); - }); - return buffer.join(''); -}; +olcs.FeatureConverter.prototype.extractColorFromOlStyle = + function(style, outline) { + var fillColor = style.getFill() ? style.getFill().getColor() : null; + var strokeColor = style.getStroke() ? style.getStroke().getColor() : null; + var olColor = 'black'; + if (strokeColor && outline) { + olColor = strokeColor; + } else if (fillColor) { + olColor = fillColor; + } -/** - * Sets CSS float property on an element. - * @param {Element} el The element to set float property on. - * @param {string} value The value of float CSS property to set on this element. - */ -goog.style.setFloat = function(el, value) { - el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] = value; + return olcs.core.convertColorToCesium(olColor); }; /** - * Gets value of explicitly-set float CSS property on an element. - * @param {Element} el The element to get float property of. - * @return {string} The value of explicitly-set float CSS property on this - * element. + * Return the width of stroke from a plain ol style. + * Use GL aliased line width range constraint. + * @param {!ol.style.Style|ol.style.Text} style + * @return {number} + * @protected */ -goog.style.getFloat = function(el) { - return el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] || ''; +olcs.FeatureConverter.prototype.extractLineWidthFromOlStyle = + function(style) { + var width = style.getStroke() ? style.getStroke().getWidth() : 1; + return Math.min(width, this.scene.maximumAliasedLineWidth); }; /** - * Returns the scroll bar width (represents the width of both horizontal - * and vertical scroll). - * - * @param {string=} opt_className An optional class name (or names) to apply - * to the invisible div created to measure the scrollbar. This is necessary - * if some scrollbars are styled differently than others. - * @return {number} The scroll bar width in px. + * Create a primitive collection out of two Cesium geometries. + * Only the OpenLayers style colors will be used. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature. + * @param {!ol.geom.Geometry} olGeometry Ol3 geometry. + * @param {!Cesium.Geometry} fillGeometry + * @param {!Cesium.Geometry} outlineGeometry + * @param {!ol.style.Style} olStyle + * @return {!Cesium.PrimitiveCollection} + * @protected */ -goog.style.getScrollbarWidth = function(opt_className) { - // Add two hidden divs. The child div is larger than the parent and - // forces scrollbars to appear on it. - // Using overflow:scroll does not work consistently with scrollbars that - // are styled with ::-webkit-scrollbar. - var outerDiv = goog.dom.createElement(goog.dom.TagName.DIV); - if (opt_className) { - outerDiv.className = opt_className; +olcs.FeatureConverter.prototype.wrapFillAndOutlineGeometries = + function(layer, feature, olGeometry, fillGeometry, outlineGeometry, + olStyle) { + var fillColor = this.extractColorFromOlStyle(olStyle, false); + var outlineColor = this.extractColorFromOlStyle(olStyle, true); + + var primitives = new Cesium.PrimitiveCollection(); + if (olStyle.getFill()) { + var p = this.createColoredPrimitive(layer, feature, olGeometry, + fillGeometry, fillColor); + primitives.add(p); } - outerDiv.style.cssText = 'overflow:auto;' + - 'position:absolute;top:0;width:100px;height:100px'; - var innerDiv = goog.dom.createElement(goog.dom.TagName.DIV); - goog.style.setSize(innerDiv, '200px', '200px'); - outerDiv.appendChild(innerDiv); - goog.dom.appendChild(goog.dom.getDocument().body, outerDiv); - var width = outerDiv.offsetWidth - outerDiv.clientWidth; - goog.dom.removeNode(outerDiv); - return width; -}; + if (olStyle.getStroke()) { + var width = this.extractLineWidthFromOlStyle(olStyle); + var p = this.createColoredPrimitive(layer, feature, olGeometry, + outlineGeometry, outlineColor, width); + primitives.add(p); + } -/** - * Regular expression to extract x and y translation components from a CSS - * transform Matrix representation. - * - * @type {!RegExp} - * @const - * @private - */ -goog.style.MATRIX_TRANSLATION_REGEX_ = - new RegExp('matrix\\([0-9\\.\\-]+, [0-9\\.\\-]+, ' + - '[0-9\\.\\-]+, [0-9\\.\\-]+, ' + - '([0-9\\.\\-]+)p?x?, ([0-9\\.\\-]+)p?x?\\)'); + return primitives; +}; +// Geometry converters /** - * Returns the x,y translation component of any CSS transforms applied to the - * element, in pixels. - * - * @param {!Element} element The element to get the translation of. - * @return {!goog.math.Coordinate} The CSS translation of the element in px. + * Create a Cesium primitive if style has a text component. + * Eventually return a PrimitiveCollection including current primitive. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Geometry} geometry + * @param {!ol.style.Style} style + * @param {!Cesium.Primitive} primitive current primitive + * @return {!Cesium.PrimitiveCollection} + * @protected */ -goog.style.getCssTranslation = function(element) { - var transform = goog.style.getComputedTransform(element); - if (!transform) { - return new goog.math.Coordinate(0, 0); - } - var matches = transform.match(goog.style.MATRIX_TRANSLATION_REGEX_); - if (!matches) { - return new goog.math.Coordinate(0, 0); +olcs.FeatureConverter.prototype.addTextStyle = + function(layer, feature, geometry, style, primitive) { + var primitives; + if (!(primitive instanceof Cesium.PrimitiveCollection)) { + primitives = new Cesium.PrimitiveCollection(); + primitives.add(primitive); + } else { + primitives = primitive; } - return new goog.math.Coordinate(parseFloat(matches[1]), - parseFloat(matches[2])); -}; -goog.provide('ol.MapEvent'); -goog.provide('ol.MapEventType'); + if (!style.getText()) { + return primitives; + } -goog.require('goog.events.Event'); + var text = /** @type {!ol.style.Text} */ (style.getText()); + var label = this.olGeometry4326TextPartToCesium(layer, feature, geometry, + text); + if (label) { + primitives.add(label); + } + return primitives; +}; /** - * @enum {string} + * Add a billboard to a Cesium.BillboardCollection. + * Overriding this wrapper allows manipulating the billboard options. + * @param {!Cesium.BillboardCollection} billboards + * @param {!Cesium.optionsBillboardCollectionAdd} bbOptions + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature. + * @param {!ol.geom.Geometry} geometry + * @param {!ol.style.Style} style + * @return {!Cesium.Billboard} newly created billboard + * @api */ -ol.MapEventType = { - - /** - * Triggered after a map frame is rendered. - * @event ol.MapEvent#postrender - * @api - */ - POSTRENDER: 'postrender', - - /** - * Triggered after the map is moved. - * @event ol.MapEvent#moveend - * @api stable - */ - MOVEEND: 'moveend' - +olcs.FeatureConverter.prototype.csAddBillboard = + function(billboards, bbOptions, layer, feature, geometry, style) { + var bb = billboards.add(bbOptions); + this.setReferenceForPicking(layer, feature, bb); + return bb; }; - /** - * @classdesc - * Events emitted as map events are instances of this type. - * See {@link ol.Map} for which events trigger a map event. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.MapEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {?olx.FrameState=} opt_frameState Frame state. + * Convert an OpenLayers circle geometry to Cesium. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Circle} olGeometry Ol3 circle geometry. + * @param {!ol.proj.ProjectionLike} projection + * @param {!ol.style.Style} olStyle + * @return {!Cesium.PrimitiveCollection} primitives + * @api */ -ol.MapEvent = function(type, map, opt_frameState) { +olcs.FeatureConverter.prototype.olCircleGeometryToCesium = + function(layer, feature, olGeometry, projection, olStyle) { - goog.base(this, type); + olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); + goog.asserts.assert(olGeometry.getType() == 'Circle'); - /** - * The map where the event occurred. - * @type {ol.Map} - * @api stable - */ - this.map = map; + // ol.Coordinate + var center = olGeometry.getCenter(); + var height = center.length == 3 ? center[2] : 0.0; + var point = center.slice(); + point[0] += olGeometry.getRadius(); - /** - * The frame state at the time of the event. - * @type {?olx.FrameState} - * @api - */ - this.frameState = opt_frameState !== undefined ? opt_frameState : null; + // Cesium + center = olcs.core.ol4326CoordinateToCesiumCartesian(center); + point = olcs.core.ol4326CoordinateToCesiumCartesian(point); -}; -goog.inherits(ol.MapEvent, goog.events.Event); + // Accurate computation of straight distance + var radius = Cesium.Cartesian3.distance(center, point); -goog.provide('ol.control.Control'); + var fillGeometry = new Cesium.CircleGeometry({ + // always update Cesium externs before adding a property + center: center, + radius: radius, + height: height + }); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('ol'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); + var outlineGeometry = new Cesium.CircleOutlineGeometry({ + // always update Cesium externs before adding a property + center: center, + radius: radius, + extrudedHeight: height, + height: height + }); + + var primitives = this.wrapFillAndOutlineGeometries( + layer, feature, olGeometry, fillGeometry, outlineGeometry, olStyle); + return this.addTextStyle(layer, feature, olGeometry, olStyle, primitives); +}; /** - * @classdesc - * A control is a visible widget with a DOM element in a fixed position on the - * screen. They can involve user input (buttons), or be informational only; - * the position is determined using CSS. By default these are placed in the - * container with CSS class name `ol-overlaycontainer-stopevent`, but can use - * any outside DOM element. - * - * This is the base class for controls. You can use it for simple custom - * controls by creating the element with listeners, creating an instance: - * ```js - * var myControl = new ol.control.Control({element: myElement}); - * ``` - * and then adding this to the map. - * - * The main advantage of having this as a control rather than a simple separate - * DOM element is that preventing propagation is handled for you. Controls - * will also be `ol.Object`s in a `ol.Collection`, so you can use their - * methods. - * - * You can also extend this base for your own control class. See - * examples/custom-controls for an example of how to do this. - * - * @constructor - * @extends {ol.Object} - * @implements {oli.control.Control} - * @param {olx.control.ControlOptions} options Control options. - * @api stable + * Convert an OpenLayers line string geometry to Cesium. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.LineString} olGeometry Ol3 line string geometry. + * @param {!ol.proj.ProjectionLike} projection + * @param {!ol.style.Style} olStyle + * @return {!Cesium.PrimitiveCollection} primitives + * @api */ -ol.control.Control = function(options) { - - goog.base(this); - - /** - * @protected - * @type {Element} - */ - this.element = options.element ? options.element : null; +olcs.FeatureConverter.prototype.olLineStringGeometryToCesium = + function(layer, feature, olGeometry, projection, olStyle) { - /** - * @private - * @type {Element} - */ - this.target_ = null; + olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); + goog.asserts.assert(olGeometry.getType() == 'LineString'); - /** - * @private - * @type {ol.Map} - */ - this.map_ = null; + var positions = olcs.core.ol4326CoordinateArrayToCsCartesians( + olGeometry.getCoordinates()); - /** - * @protected - * @type {!Array.<?number>} - */ - this.listenerKeys = []; + var appearance = new Cesium.PolylineMaterialAppearance({ + // always update Cesium externs before adding a property + material: this.olStyleToCesium(feature, olStyle, true) + }); - /** - * @type {function(ol.MapEvent)} - */ - this.render = options.render ? options.render : ol.nullFunction; + // Handle both color and width + var outlineGeometry = new Cesium.PolylineGeometry({ + // always update Cesium externs before adding a property + positions: positions, + width: this.extractLineWidthFromOlStyle(olStyle), + vertexFormat: appearance.vertexFormat + }); - if (options.target) { - this.setTarget(options.target); - } + var outlinePrimitive = new Cesium.Primitive({ + // always update Cesium externs before adding a property + geometryInstances: new Cesium.GeometryInstance({ + geometry: outlineGeometry + }), + appearance: appearance + }); + this.setReferenceForPicking(layer, feature, outlinePrimitive); + return this.addTextStyle(layer, feature, olGeometry, olStyle, + outlinePrimitive); }; -goog.inherits(ol.control.Control, ol.Object); /** - * @inheritDoc + * Convert an OpenLayers polygon geometry to Cesium. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Polygon} olGeometry Ol3 polygon geometry. + * @param {!ol.proj.ProjectionLike} projection + * @param {!ol.style.Style} olStyle + * @return {!Cesium.PrimitiveCollection} primitives + * @api */ -ol.control.Control.prototype.disposeInternal = function() { - goog.dom.removeNode(this.element); - goog.base(this, 'disposeInternal'); -}; +olcs.FeatureConverter.prototype.olPolygonGeometryToCesium = + function(layer, feature, olGeometry, projection, olStyle) { + olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); + goog.asserts.assert(olGeometry.getType() == 'Polygon'); -/** - * Get the map associated with this control. - * @return {ol.Map} Map. - * @api stable - */ -ol.control.Control.prototype.getMap = function() { - return this.map_; + var rings = olGeometry.getLinearRings(); + // always update Cesium externs before adding a property + var hierarchy = {}; + var polygonHierarchy = hierarchy; + goog.asserts.assert(rings.length > 0); + + for (var i = 0; i < rings.length; ++i) { + var olPos = rings[i].getCoordinates(); + var positions = olcs.core.ol4326CoordinateArrayToCsCartesians(olPos); + goog.asserts.assert(positions && positions.length > 0); + if (i == 0) { + hierarchy.positions = positions; + } else { + hierarchy.holes = { + // always update Cesium externs before adding a property + positions: positions + }; + hierarchy = hierarchy.holes; + } + } + + var fillGeometry = new Cesium.PolygonGeometry({ + // always update Cesium externs before adding a property + polygonHierarchy: polygonHierarchy, + perPositionHeight: true + }); + + var outlineGeometry = new Cesium.PolygonOutlineGeometry({ + // always update Cesium externs before adding a property + polygonHierarchy: hierarchy, + perPositionHeight: true + }); + + var primitives = this.wrapFillAndOutlineGeometries( + layer, feature, olGeometry, fillGeometry, outlineGeometry, olStyle); + + return this.addTextStyle(layer, feature, olGeometry, olStyle, primitives); }; /** - * Remove the control from its current map and attach it to the new map. - * Subclasses may set up event handlers to get notified about changes to - * the map here. - * @param {ol.Map} map Map. - * @api stable + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Geometry} geometry + * @return {!Cesium.HeightReference} + * @api */ -ol.control.Control.prototype.setMap = function(map) { - if (this.map_) { - goog.dom.removeNode(this.element); +olcs.FeatureConverter.prototype.getHeightReference = + function(layer, feature, geometry) { + + // Read from the geometry + var altitudeMode = geometry.get('altitudeMode'); + + // Or from the feature + if (!goog.isDef(altitudeMode)) { + altitudeMode = feature.get('altitudeMode'); } - if (this.listenerKeys.length > 0) { - this.listenerKeys.forEach(goog.events.unlistenByKey); - this.listenerKeys.length = 0; + + // Or from the layer + if (!goog.isDef(altitudeMode)) { + altitudeMode = layer.get('altitudeMode'); } - this.map_ = map; - if (this.map_) { - var target = this.target_ ? - this.target_ : map.getOverlayContainerStopEvent(); - target.appendChild(this.element); - if (this.render !== ol.nullFunction) { - this.listenerKeys.push(goog.events.listen(map, - ol.MapEventType.POSTRENDER, this.render, false, this)); - } - map.render(); + + var heightReference = Cesium.HeightReference.NONE; + if (altitudeMode === 'clampToGround') { + heightReference = Cesium.HeightReference.CLAMP_TO_GROUND; + } else if (altitudeMode === 'relativeToGround') { + heightReference = Cesium.HeightReference.RELATIVE_TO_GROUND; } + + return heightReference; }; /** - * This function is used to set a target element for the control. It has no - * effect if it is called after the control has been added to the map (i.e. - * after `setMap` is called on the control). If no `target` is set in the - * options passed to the control constructor and if `setTarget` is not called - * then the control is added to the map's overlay container. - * @param {Element|string} target Target. + * Convert a point geometry to a Cesium BillboardCollection. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Point} olGeometry Ol3 point geometry. + * @param {!ol.proj.ProjectionLike} projection + * @param {!ol.style.Style} style + * @param {!Cesium.BillboardCollection} billboards + * @param {function(!Cesium.Billboard)=} opt_newBillboardCallback Called when + * the new billboard is added. + * @return {Cesium.Primitive} primitives * @api */ -ol.control.Control.prototype.setTarget = function(target) { - this.target_ = goog.dom.getElement(target); -}; +olcs.FeatureConverter.prototype.olPointGeometryToCesium = + function(layer, feature, olGeometry, projection, style, billboards, + opt_newBillboardCallback) { + goog.asserts.assert(olGeometry.getType() == 'Point'); + olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); -goog.provide('ol.css'); + var imageStyle = style.getImage(); + if (imageStyle) { + if (imageStyle instanceof ol.style.Icon) { + // make sure the image is scheduled for load + imageStyle.load(); + } + + var image = imageStyle.getImage(1); // get normal density + var isImageLoaded = function(image) { + return image.src != '' && + image.naturalHeight != 0 && + image.naturalWidth != 0 && + image.complete; + }; + var reallyCreateBillboard = (function() { + if (goog.isNull(image)) { + return; + } + if (!(image instanceof HTMLCanvasElement || + image instanceof Image || + image instanceof HTMLImageElement)) { + return; + } + var center = olGeometry.getCoordinates(); + var position = olcs.core.ol4326CoordinateToCesiumCartesian(center); + var color; + var opacity = imageStyle.getOpacity(); + if (goog.isDef(opacity)) { + color = new Cesium.Color(1.0, 1.0, 1.0, opacity); + } + var heightReference = this.getHeightReference(layer, feature, olGeometry); -/** - * The CSS class for hidden feature. - * - * @const - * @type {string} - */ -ol.css.CLASS_HIDDEN = 'ol-hidden'; + var bbOptions = /** @type {Cesium.optionsBillboardCollectionAdd} */ ({ + // always update Cesium externs before adding a property + image: image, + color: color, + heightReference: heightReference, + verticalOrigin: Cesium.VerticalOrigin.BOTTOM, + position: position + }); + var bb = this.csAddBillboard(billboards, bbOptions, layer, feature, + olGeometry, style); + if (opt_newBillboardCallback) { + opt_newBillboardCallback(bb); + } + }).bind(this); + if (image instanceof Image && !isImageLoaded(image)) { + // Cesium requires the image to be loaded + var cancelled = false; + var source = layer.getSource(); + if (source instanceof ol.source.ImageVector) { + source = source.getSource(); + } + var canceller = function() { + cancelled = true; + }; + source.on(['removefeature', 'clear'], + this.boundOnRemoveOrClearFeatureListener_); + var cancellers = olcs.obj(source)['olcs_cancellers']; + if (!cancellers) { + cancellers = olcs.obj(source)['olcs_cancellers'] = {}; + } -/** - * The CSS class that we'll give the DOM elements to have them unselectable. - * - * @const - * @type {string} - */ -ol.css.CLASS_UNSELECTABLE = 'ol-unselectable'; + goog.asserts.assert(!cancellers[goog.getUid(feature)]); + cancellers[goog.getUid(feature)] = canceller; + var listener = function() { + if (!billboards.isDestroyed() && !cancelled) { + // Create billboard if the feature is still displayed on the map. + reallyCreateBillboard(); + } + }; -/** - * The CSS class for unsupported feature. - * - * @const - * @type {string} - */ -ol.css.CLASS_UNSUPPORTED = 'ol-unsupported'; + goog.events.listenOnce(image, 'load', listener); + } else { + reallyCreateBillboard(); + } + } + + if (style.getText()) { + return this.addTextStyle(layer, feature, olGeometry, style, + new Cesium.Primitive()); + } else { + return null; + } +}; /** - * The CSS class for controls. - * - * @const - * @type {string} + * Convert an OpenLayers multi-something geometry to Cesium. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Geometry} geometry Ol3 geometry. + * @param {!ol.proj.ProjectionLike} projection + * @param {!ol.style.Style} olStyle + * @param {!Cesium.BillboardCollection} billboards + * @param {function(!Cesium.Billboard)=} opt_newBillboardCallback Called when + * the new billboard is added. + * @return {Cesium.Primitive} primitives + * @api */ -ol.css.CLASS_CONTROL = 'ol-control'; - -goog.provide('ol.structs.LRUCache'); +olcs.FeatureConverter.prototype.olMultiGeometryToCesium = + function(layer, feature, geometry, projection, olStyle, billboards, + opt_newBillboardCallback) { + // Do not reproject to 4326 now because it will be done later. -goog.require('goog.asserts'); -goog.require('goog.object'); + // FIXME: would be better to combine all child geometries in one primitive + // instead we create n primitives for simplicity. + var accumulate = function(geometries, functor) { + var primitives = new Cesium.PrimitiveCollection(); + geometries.forEach(function(geometry) { + primitives.add(functor(layer, feature, geometry, projection, olStyle)); + }); + return primitives; + }; + var subgeos; + switch (geometry.getType()) { + case 'MultiPoint': + geometry = /** @type {!ol.geom.MultiPoint} */ (geometry); + subgeos = geometry.getPoints(); + if (olStyle.getText()) { + var primitives = new Cesium.PrimitiveCollection(); + subgeos.forEach(function(geometry) { + goog.asserts.assert(geometry); + var result = this.olPointGeometryToCesium(layer, feature, geometry, + projection, olStyle, billboards, opt_newBillboardCallback); + if (result) { + primitives.add(result); + } + }.bind(this)); + return primitives; + } else { + subgeos.forEach(function(geometry) { + goog.asserts.assert(!goog.isNull(geometry)); + this.olPointGeometryToCesium(layer, feature, geometry, projection, + olStyle, billboards, opt_newBillboardCallback); + }); + return null; + } + case 'MultiLineString': + geometry = /** @type {!ol.geom.MultiLineString} */ (geometry); + subgeos = geometry.getLineStrings(); + return accumulate(subgeos, this.olLineStringGeometryToCesium.bind(this)); + case 'MultiPolygon': + geometry = /** @type {!ol.geom.MultiPolygon} */ (geometry); + subgeos = geometry.getPolygons(); + return accumulate(subgeos, this.olPolygonGeometryToCesium.bind(this)); + default: + goog.asserts.fail('Unhandled multi geometry type' + geometry.getType()); + } +}; /** - * Implements a Least-Recently-Used cache where the keys do not conflict with - * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring - * items from the cache is the responsibility of the user. - * @constructor - * @struct - * @template T + * Convert an OpenLayers text style to Cesium. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature.. + * @param {!ol.geom.Geometry} geometry + * @param {!ol.style.Text} style + * @return {Cesium.LabelCollection} Cesium primitive + * @api */ -ol.structs.LRUCache = function() { +olcs.FeatureConverter.prototype.olGeometry4326TextPartToCesium = + function(layer, feature, geometry, style) { + var text = style.getText(); + goog.asserts.assert(goog.isDef(text)); - /** - * @private - * @type {number} - */ - this.count_ = 0; - /** - * @private - * @type {Object.<string, ol.structs.LRUCacheEntry>} - */ - this.entries_ = {}; + var labels = new Cesium.LabelCollection({scene: this.scene}); + // TODO: export and use the text draw position from ol3 . + // See src/ol/render/vector.js + var extentCenter = ol.extent.getCenter(geometry.getExtent()); + if (geometry instanceof ol.geom.SimpleGeometry) { + var first = geometry.getFirstCoordinate(); + extentCenter[2] = first.length == 3 ? first[2] : 0.0; + } + var options = /** @type {Cesium.optionsLabelCollection} */ ({}); - /** - * @private - * @type {?ol.structs.LRUCacheEntry} - */ - this.oldest_ = null; + options.position = olcs.core.ol4326CoordinateToCesiumCartesian(extentCenter); - /** - * @private - * @type {?ol.structs.LRUCacheEntry} - */ - this.newest_ = null; + options.text = text; -}; + options.heightReference = this.getHeightReference(layer, feature, geometry); + var offsetX = style.getOffsetX(); + var offsetY = style.getOffsetY(); + if (offsetX != 0 && offsetY != 0) { + var offset = new Cesium.Cartesian2(offsetX, offsetY); + options.pixelOffset = offset; + } -/** - * FIXME empty description for jsdoc - */ -ol.structs.LRUCache.prototype.assertValid = function() { - if (this.count_ === 0) { - goog.asserts.assert(goog.object.isEmpty(this.entries_), - 'entries must be an empty object (count = 0)'); - goog.asserts.assert(!this.oldest_, - 'oldest must be null (count = 0)'); - goog.asserts.assert(!this.newest_, - 'newest must be null (count = 0)'); - } else { - goog.asserts.assert(goog.object.getCount(this.entries_) == this.count_, - 'number of entries matches count'); - goog.asserts.assert(this.oldest_, - 'we have an oldest entry'); - goog.asserts.assert(!this.oldest_.older, - 'no entry is older than oldest'); - goog.asserts.assert(this.newest_, - 'we have a newest entry'); - goog.asserts.assert(!this.newest_.newer, - 'no entry is newer than newest'); - var i, entry; - var older = null; - i = 0; - for (entry = this.oldest_; entry; entry = entry.newer) { - goog.asserts.assert(entry.older === older, - 'entry.older links to correct older'); - older = entry; - ++i; - } - goog.asserts.assert(i == this.count_, 'iterated correct amount of times'); - var newer = null; - i = 0; - for (entry = this.newest_; entry; entry = entry.older) { - goog.asserts.assert(entry.newer === newer, - 'entry.newer links to correct newer'); - newer = entry; - ++i; - } - goog.asserts.assert(i == this.count_, 'iterated correct amount of times'); + var font = style.getFont(); + if (goog.isDefAndNotNull(font)) { + options.font = font; } -}; + var labelStyle = undefined; + if (style.getFill()) { + options.fillColor = this.extractColorFromOlStyle(style, false); + labelStyle = Cesium.LabelStyle.FILL; + } + if (style.getStroke()) { + options.outlineWidth = this.extractLineWidthFromOlStyle(style); + options.outlineColor = this.extractColorFromOlStyle(style, true); + labelStyle = Cesium.LabelStyle.OUTLINE; + } + if (style.getFill() && style.getStroke()) { + labelStyle = Cesium.LabelStyle.FILL_AND_OUTLINE; + } + options.style = labelStyle; + + var horizontalOrigin; + switch (style.getTextAlign()) { + case 'left': + horizontalOrigin = Cesium.HorizontalOrigin.LEFT; + break; + case 'right': + horizontalOrigin = Cesium.HorizontalOrigin.RIGHT; + break; + case 'center': + default: + horizontalOrigin = Cesium.HorizontalOrigin.CENTER; + } + options.horizontalOrigin = horizontalOrigin; -/** - * FIXME empty description for jsdoc - */ -ol.structs.LRUCache.prototype.clear = function() { - this.count_ = 0; - this.entries_ = {}; - this.oldest_ = null; - this.newest_ = null; -}; + if (style.getTextBaseline()) { + var verticalOrigin; + switch (style.getTextBaseline()) { + case 'top': + verticalOrigin = Cesium.VerticalOrigin.TOP; + break; + case 'middle': + verticalOrigin = Cesium.VerticalOrigin.CENTER; + break; + case 'bottom': + verticalOrigin = Cesium.VerticalOrigin.BOTTOM; + break; + case 'alphabetic': + verticalOrigin = Cesium.VerticalOrigin.TOP; + break; + case 'hanging': + verticalOrigin = Cesium.VerticalOrigin.BOTTOM; + break; + default: + goog.asserts.fail('unhandled baseline ' + style.getTextBaseline()); + } + options.verticalOrigin = verticalOrigin; + } -/** - * @param {string} key Key. - * @return {boolean} Contains key. - */ -ol.structs.LRUCache.prototype.containsKey = function(key) { - return this.entries_.hasOwnProperty(key); + var l = labels.add(options); + this.setReferenceForPicking(layer, feature, l); + return labels; }; /** - * @param {function(this: S, T, string, ol.structs.LRUCache): ?} f The function - * to call for every entry from the oldest to the newer. This function takes - * 3 arguments (the entry value, the entry key and the LRUCache object). - * The return value is ignored. - * @param {S=} opt_this The object to use as `this` in `f`. - * @template S + * Convert an OpenLayers style to a Cesium Material. + * @param {ol.Feature} feature Ol3 feature.. + * @param {!ol.style.Style} style + * @param {boolean} outline + * @return {Cesium.Material} + * @api */ -ol.structs.LRUCache.prototype.forEach = function(f, opt_this) { - var entry = this.oldest_; - while (entry) { - f.call(opt_this, entry.value_, entry.key_, this); - entry = entry.newer; +olcs.FeatureConverter.prototype.olStyleToCesium = + function(feature, style, outline) { + var fill = style.getFill(); + var stroke = style.getStroke(); + if ((outline && !stroke) || (!outline && !fill)) { + return null; // FIXME use a default style? Developer error? } -}; + var color = outline ? stroke.getColor() : fill.getColor(); + color = olcs.core.convertColorToCesium(color); -/** - * @param {string} key Key. - * @return {T} Value. - */ -ol.structs.LRUCache.prototype.get = function(key) { - var entry = this.entries_[key]; - goog.asserts.assert(entry !== undefined, 'an entry exists for key %s', key); - if (entry === this.newest_) { - return entry.value_; - } else if (entry === this.oldest_) { - this.oldest_ = this.oldest_.newer; - this.oldest_.older = null; + if (outline && stroke.getLineDash()) { + return Cesium.Material.fromType('Stripe', { + // always update Cesium externs before adding a property + horizontal: false, + repeat: 500, // TODO how to calculate this? + evenColor: color, + oddColor: new Cesium.Color(0, 0, 0, 0) // transparent + }); } else { - entry.newer.older = entry.older; - entry.older.newer = entry.newer; + return Cesium.Material.fromType('Color', { + // always update Cesium externs before adding a property + color: color + }); } - entry.newer = null; - entry.older = this.newest_; - this.newest_.newer = entry; - this.newest_ = entry; - return entry.value_; -}; - -/** - * @return {number} Count. - */ -ol.structs.LRUCache.prototype.getCount = function() { - return this.count_; }; /** - * @return {Array.<string>} Keys. + * Compute OpenLayers plain style. + * Evaluates style function, blend arrays, get default style. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature + * @param {ol.style.StyleFunction|undefined} fallbackStyle + * @param {number} resolution + * @return {ol.style.Style} null if no style is available + * @api */ -ol.structs.LRUCache.prototype.getKeys = function() { - var keys = new Array(this.count_); - var i = 0; - var entry; - for (entry = this.newest_; entry; entry = entry.older) { - keys[i++] = entry.key_; +olcs.FeatureConverter.prototype.computePlainStyle = + function(layer, feature, fallbackStyle, resolution) { + var featureStyle = feature.getStyleFunction(); + var style; + if (goog.isDef(featureStyle)) { + style = featureStyle.call(feature, resolution); } - goog.asserts.assert(i == this.count_, 'iterated correct number of times'); - return keys; + if (!goog.isDefAndNotNull(style) && goog.isDefAndNotNull(fallbackStyle)) { + style = fallbackStyle(feature, resolution); + } + + if (!goog.isDef(style)) { + // The feature must not be displayed + return null; + } + + goog.asserts.assert(Array.isArray(style)); + // FIXME combine materials as in cesium-materials-pack? + // then this function must return a custom material + // More simply, could blend the colors like described in + // http://en.wikipedia.org/wiki/Alpha_compositing + return style[0]; }; /** - * @return {Array.<T>} Values. + * Convert one OpenLayers feature up to a collection of Cesium primitives. + * @param {ol.layer.Vector|ol.layer.Image} layer + * @param {!ol.Feature} feature Ol3 feature. + * @param {!ol.style.Style} style + * @param {!olcsx.core.OlFeatureToCesiumContext} context + * @param {!ol.geom.Geometry=} opt_geom Geometry to be converted. + * @return {Cesium.Primitive} primitives + * @api */ -ol.structs.LRUCache.prototype.getValues = function() { - var values = new Array(this.count_); - var i = 0; - var entry; - for (entry = this.newest_; entry; entry = entry.older) { - values[i++] = entry.value_; +olcs.FeatureConverter.prototype.olFeatureToCesium = + function(layer, feature, style, context, opt_geom) { + var geom = opt_geom || feature.getGeometry(); + var proj = context.projection; + if (!geom) { + // Ol3 features may not have a geometry + // See http://geojson.org/geojson-spec.html#feature-objects + return null; } - goog.asserts.assert(i == this.count_, 'iterated correct number of times'); - return values; -}; + var newBillboardAddedCallback = function(bb) { + context.featureToCesiumMap[goog.getUid(feature)] = bb; + }; -/** - * @return {T} Last value. - */ -ol.structs.LRUCache.prototype.peekLast = function() { - goog.asserts.assert(this.oldest_, 'oldest must not be null'); - return this.oldest_.value_; + switch (geom.getType()) { + case 'GeometryCollection': + var primitives = new Cesium.PrimitiveCollection(); + var collection = /** @type {!ol.geom.GeometryCollection} */ (geom); + // TODO: use getGeometriesArray() instead + collection.getGeometries().forEach(function(geom) { + if (geom) { + var prims = this.olFeatureToCesium(layer, feature, style, context, + geom); + if (prims) { + primitives.add(prims); + } + } + }.bind(this)); + return primitives; + case 'Point': + geom = /** @type {!ol.geom.Point} */ (geom); + var bbs = context.billboards; + var result = this.olPointGeometryToCesium(layer, feature, geom, proj, + style, bbs, newBillboardAddedCallback); + if (!result) { + // no wrapping primitive + return null; + } else { + return result; + } + case 'Circle': + geom = /** @type {!ol.geom.Circle} */ (geom); + return this.olCircleGeometryToCesium(layer, feature, geom, proj, + style); + case 'LineString': + geom = /** @type {!ol.geom.LineString} */ (geom); + return this.olLineStringGeometryToCesium(layer, feature, geom, proj, + style); + case 'Polygon': + geom = /** @type {!ol.geom.Polygon} */ (geom); + return this.olPolygonGeometryToCesium(layer, feature, geom, proj, + style); + case 'MultiPoint': + case 'MultiLineString': + case 'MultiPolygon': + var result = this.olMultiGeometryToCesium(layer, feature, geom, proj, + style, context.billboards, newBillboardAddedCallback); + if (!result) { + // no wrapping primitive + return null; + } else { + return result; + } + case 'LinearRing': + throw new Error('LinearRing should only be part of polygon.'); + default: + throw new Error('Ol geom type not handled : ' + geom.getType()); + } }; /** - * @return {string} Last key. + * Convert an OpenLayers vector layer to Cesium primitive collection. + * For each feature, the associated primitive will be stored in + * `featurePrimitiveMap`. + * @param {!(ol.layer.Vector|ol.layer.Image)} olLayer + * @param {!ol.View} olView + * @param {!Object.<number, !Cesium.Primitive>} featurePrimitiveMap + * @return {!olcs.core.VectorLayerCounterpart} + * @api */ -ol.structs.LRUCache.prototype.peekLastKey = function() { - goog.asserts.assert(this.oldest_, 'oldest must not be null'); - return this.oldest_.key_; -}; +olcs.FeatureConverter.prototype.olVectorLayerToCesium = + function(olLayer, olView, featurePrimitiveMap) { + var proj = olView.getProjection(); + var resolution = olView.getResolution(); + if (!goog.isDef(resolution) || !proj) { + goog.asserts.fail('View not ready'); + // an assertion is not enough for closure to assume resolution and proj + // are defined + throw new Error('View not ready'); + } -/** - * @return {T} value Value. - */ -ol.structs.LRUCache.prototype.pop = function() { - goog.asserts.assert(this.oldest_, 'oldest must not be null'); - goog.asserts.assert(this.newest_, 'newest must not be null'); - var entry = this.oldest_; - goog.asserts.assert(entry.key_ in this.entries_, - 'oldest is indexed in entries'); - delete this.entries_[entry.key_]; - if (entry.newer) { - entry.newer.older = null; + var source = olLayer.getSource(); + if (olLayer instanceof ol.layer.Image) { + if (source instanceof ol.source.ImageVector) { + source = source.getSource(); + } else { + // Not supported + return new olcs.core.VectorLayerCounterpart(proj, this.scene); + } } - this.oldest_ = entry.newer; - if (!this.oldest_) { - this.newest_ = null; + + goog.asserts.assertInstanceof(source, ol.source.Vector); + var features = source.getFeatures(); + var counterpart = new olcs.core.VectorLayerCounterpart(proj, this.scene); + var context = counterpart.context; + for (var i = 0; i < features.length; ++i) { + var feature = features[i]; + if (!goog.isDefAndNotNull(feature)) { + continue; + } + var layerStyle; + if (olLayer instanceof ol.layer.Image) { + var imageSource = olLayer.getSource(); + goog.asserts.assertInstanceof(imageSource, ol.source.ImageVector); + layerStyle = imageSource.getStyleFunction(); + } else { + layerStyle = olLayer.getStyleFunction(); + } + var style = this.computePlainStyle(olLayer, feature, layerStyle, + resolution); + if (!style) { + // only 'render' features with a style + continue; + } + var primitives = this.olFeatureToCesium(olLayer, feature, style, context); + if (!primitives) continue; + featurePrimitiveMap[goog.getUid(feature)] = primitives; + counterpart.getRootPrimitive().add(primitives); } - --this.count_; - return entry.value_; + + return counterpart; }; /** - * @param {string} key Key. - * @param {T} value Value. + * Convert an OpenLayers feature to Cesium primitive collection. + * @param {!(ol.layer.Vector|ol.layer.Image)} layer + * @param {!ol.View} view + * @param {!ol.Feature} feature + * @param {!olcsx.core.OlFeatureToCesiumContext} context + * @return {Cesium.Primitive} + * @api */ -ol.structs.LRUCache.prototype.replace = function(key, value) { - this.get(key); // update `newest_` - this.entries_[key].value_ = value; -}; +olcs.FeatureConverter.prototype.convert = + function(layer, view, feature, context) { + var proj = view.getProjection(); + var resolution = view.getResolution(); + if (!goog.isDef(resolution) || !proj) { + return null; + } -/** - * @param {string} key Key. - * @param {T} value Value. - */ -ol.structs.LRUCache.prototype.set = function(key, value) { - goog.asserts.assert(!(key in {}), - 'key is not a standard property of objects (e.g. "__proto__")'); - goog.asserts.assert(!(key in this.entries_), - 'key is not used already'); - var entry = { - key_: key, - newer: null, - older: this.newest_, - value_: value - }; - if (!this.newest_) { - this.oldest_ = entry; + var layerStyle; + if (layer instanceof ol.layer.Image) { + var imageSource = layer.getSource(); + if (imageSource instanceof ol.source.ImageVector) { + layerStyle = imageSource.getStyleFunction(); + } else { + return null; + } } else { - this.newest_.newer = entry; + layerStyle = layer.getStyleFunction(); } - this.newest_ = entry; - this.entries_[key] = entry; - ++this.count_; -}; + var style = this.computePlainStyle(layer, feature, layerStyle, resolution); + if (!style) { + // only 'render' features with a style + return null; + } -/** - * @typedef {{key_: string, - * newer: ol.structs.LRUCacheEntry, - * older: ol.structs.LRUCacheEntry, - * value_: *}} - */ -ol.structs.LRUCacheEntry; + context.projection = proj; + return this.olFeatureToCesium(layer, feature, style, context); +}; -goog.provide('ol.TileCache'); +goog.provide('olcs.RasterSynchronizer'); -goog.require('ol'); -goog.require('ol.TileRange'); -goog.require('ol.structs.LRUCache'); -goog.require('ol.tilecoord'); +goog.require('olcs.AbstractSynchronizer'); +goog.require('olcs.core'); /** + * This object takes care of one-directional synchronization of + * ol3 raster layers to the given Cesium globe. + * @param {!ol.Map} map + * @param {!Cesium.Scene} scene * @constructor - * @extends {ol.structs.LRUCache.<ol.Tile>} - * @param {number=} opt_highWaterMark High water mark. + * @extends {olcs.AbstractSynchronizer.<Cesium.ImageryLayer>} + * @api * @struct */ -ol.TileCache = function(opt_highWaterMark) { - - goog.base(this); +olcs.RasterSynchronizer = function(map, scene) { + /** + * @type {!Cesium.ImageryLayerCollection} + * @private + */ + this.cesiumLayers_ = scene.imageryLayers; /** + * @type {!Cesium.ImageryLayerCollection} * @private - * @type {number} */ - this.highWaterMark_ = opt_highWaterMark !== undefined ? - opt_highWaterMark : ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK; + this.ourLayers_ = new Cesium.ImageryLayerCollection(); + goog.base(this, map, scene); }; -goog.inherits(ol.TileCache, ol.structs.LRUCache); +goog.inherits(olcs.RasterSynchronizer, olcs.AbstractSynchronizer); /** - * @return {boolean} Can expire cache. + * @inheritDoc */ -ol.TileCache.prototype.canExpireCache = function() { - return this.getCount() > this.highWaterMark_; +olcs.RasterSynchronizer.prototype.addCesiumObject = function(object) { + this.cesiumLayers_.add(object); + this.ourLayers_.add(object); }; /** - * @param {Object.<string, ol.TileRange>} usedTiles Used tiles. + * @inheritDoc */ -ol.TileCache.prototype.expireCache = function(usedTiles) { - var tile, zKey; - while (this.canExpireCache()) { - tile = this.peekLast(); - zKey = tile.tileCoord[0].toString(); - if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) { - break; - } else { - this.pop().dispose(); - } - } +olcs.RasterSynchronizer.prototype.destroyCesiumObject = function(object) { + object.destroy(); }; /** - * Remove a tile range from the cache, e.g. to invalidate tiles. - * @param {ol.TileRange} tileRange The tile range to prune. + * @inheritDoc */ -ol.TileCache.prototype.pruneTileRange = function(tileRange) { - var i = this.getCount(), - key; - while (i--) { - key = this.peekLastKey(); - if (tileRange.contains(ol.tilecoord.createFromString(key))) { - this.pop().dispose(); - } else { - this.get(key); - } - } +olcs.RasterSynchronizer.prototype.removeSingleCesiumObject = + function(object, destroy) { + this.cesiumLayers_.remove(object, destroy); + this.ourLayers_.remove(object, false); }; -goog.provide('ol.Tile'); -goog.provide('ol.TileState'); - -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('ol.TileCoord'); - /** - * @enum {number} + * @inheritDoc */ -ol.TileState = { - IDLE: 0, - LOADING: 1, - LOADED: 2, - ERROR: 3, - EMPTY: 4 +olcs.RasterSynchronizer.prototype.removeAllCesiumObjects = function(destroy) { + for (var i = 0; i < this.ourLayers_.length; ++i) { + this.cesiumLayers_.remove(this.ourLayers_.get(i), destroy); + } + this.ourLayers_.removeAll(false); }; - /** - * @classdesc - * Base class for tiles. - * - * @constructor - * @extends {goog.events.EventTarget} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. + * Creates an array of Cesium.ImageryLayer. + * May be overriden by child classes to implement custom behavior. + * The default implementation handles tiled imageries in EPSG:4326 or + * EPSG:3859. + * @param {!ol.layer.Base} olLayer + * @param {?ol.proj.Projection} viewProj Projection of the view. + * @return {?Array.<!Cesium.ImageryLayer>} array or null if not possible + * (or supported) + * @protected */ -ol.Tile = function(tileCoord, state) { +olcs.RasterSynchronizer.prototype.convertLayerToCesiumImageries = + function(olLayer, viewProj) { + var result = olcs.core.tileLayerToImageryLayer(olLayer, viewProj); + return result ? [result] : null; +}; - goog.base(this); - /** - * @type {ol.TileCoord} - */ - this.tileCoord = tileCoord; +/** + * @inheritDoc + */ +olcs.RasterSynchronizer.prototype.createSingleLayerCounterparts = + function(olLayer) { + var viewProj = this.view.getProjection(); + var cesiumObjects = this.convertLayerToCesiumImageries(olLayer, viewProj); + if (!goog.isNull(cesiumObjects)) { + olLayer.on(['change:opacity', 'change:visible'], + function(e) { + // the compiler does not seem to be able to infer this + goog.asserts.assert(!goog.isNull(cesiumObjects)); + for (var i = 0; i < cesiumObjects.length; ++i) { + olcs.core.updateCesiumLayerProperties(olLayer, cesiumObjects[i]); + } + }); - /** - * @protected - * @type {ol.TileState} - */ - this.state = state; + for (var i = 0; i < cesiumObjects.length; ++i) { + olcs.core.updateCesiumLayerProperties(olLayer, cesiumObjects[i]); + } - /** - * An "interim" tile for this tile. The interim tile may be used while this - * one is loading, for "smooth" transitions when changing params/dimensions - * on the source. - * @type {ol.Tile} - */ - this.interimTile = null; + // there is no way to modify Cesium layer extent, + // we have to recreate when ol3 layer extent changes: + olLayer.on('change:extent', function(e) { + for (var i = 0; i < cesiumObjects.length; ++i) { + this.cesiumLayers_.remove(cesiumObjects[i], true); // destroy + this.ourLayers_.remove(cesiumObjects[i], false); + } + delete this.layerMap[goog.getUid(olLayer)]; // invalidate the map entry + this.synchronize(); + }, this); - /** - * A key assigned to the tile. This is used by the tile source to determine - * if this tile can effectively be used, or if a new tile should be created - * and this one be used as an interim tile for this new tile. - * @type {string} - */ - this.key = ''; + olLayer.on('change', function(e) { + // when the source changes, re-add the layer to force update + for (var i = 0; i < cesiumObjects.length; ++i) { + var position = this.cesiumLayers_.indexOf(cesiumObjects[i]); + if (position >= 0) { + this.cesiumLayers_.remove(cesiumObjects[i], false); + this.cesiumLayers_.add(cesiumObjects[i], position); + } + } + }, this); + } + return Array.isArray(cesiumObjects) ? cesiumObjects : null; }; -goog.inherits(ol.Tile, goog.events.EventTarget); /** + * Order counterparts using the same algorithm as the Openlayers renderer: + * z-index then original sequence order. * @protected */ -ol.Tile.prototype.changed = function() { - this.dispatchEvent(goog.events.EventType.CHANGE); -}; +olcs.RasterSynchronizer.prototype.orderLayers = function() { + var layers = []; + var zIndices = {}; + var fifo = [this.mapLayerGroup]; + while (fifo.length > 0) { + var olLayer = fifo.splice(0, 1)[0]; + layers.push(olLayer); + zIndices[goog.getUid(olLayer)] = olLayer.getZIndex(); -/** - * Get the HTML image element for this tile (may be a Canvas, Image, or Video). - * @function - * @param {Object=} opt_context Object. - * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image. - */ -ol.Tile.prototype.getImage = goog.abstractMethod; + if (olLayer instanceof ol.layer.Group) { + var sublayers = olLayer.getLayers(); + if (goog.isDef(sublayers)) { + sublayers.forEach(function(el) { + fifo.push(el); + }); + } + } + } + goog.array.stableSort(layers, function(layer1, layer2) { + return zIndices[goog.getUid(layer1)] - zIndices[goog.getUid(layer2)]; + }); -/** - * @return {string} Key. - */ -ol.Tile.prototype.getKey = function() { - return goog.getUid(this).toString(); + layers.forEach(function(olLayer) { + var olLayerId = goog.getUid(olLayer); + var cesiumObjects = this.layerMap[olLayerId]; + if (cesiumObjects) { + cesiumObjects.forEach(this.raiseToTop, this); + } + }, this); }; /** - * Get the tile coordinate for this tile. - * @return {ol.TileCoord} - * @api + * @param {Cesium.ImageryLayer} counterpart */ -ol.Tile.prototype.getTileCoord = function() { - return this.tileCoord; +olcs.RasterSynchronizer.prototype.raiseToTop = function(counterpart) { + this.cesiumLayers_.raiseToTop(counterpart); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @return {ol.TileState} State. + * @fileoverview Names of standard colors with their associated hex values. */ -ol.Tile.prototype.getState = function() { - return this.state; -}; - - -/** - * FIXME empty description for jsdoc - */ -ol.Tile.prototype.load = goog.abstractMethod; - -goog.provide('ol.source.Source'); -goog.provide('ol.source.State'); -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.Object'); -goog.require('ol.proj'); +goog.provide('goog.color.names'); /** - * State of the source, one of 'undefined', 'loading', 'ready' or 'error'. - * @enum {string} - * @api + * A map that contains a lot of colors that are recognised by various browsers. + * This list is way larger than the minimal one dictated by W3C. + * The keys of this map are the lowercase "readable" names of the colors, while + * the values are the "hex" values. + * + * @type {!Object<string, string>} */ -ol.source.State = { - UNDEFINED: 'undefined', - LOADING: 'loading', - READY: 'ready', - ERROR: 'error' +goog.color.names = { + 'aliceblue': '#f0f8ff', + 'antiquewhite': '#faebd7', + 'aqua': '#00ffff', + 'aquamarine': '#7fffd4', + 'azure': '#f0ffff', + 'beige': '#f5f5dc', + 'bisque': '#ffe4c4', + 'black': '#000000', + 'blanchedalmond': '#ffebcd', + 'blue': '#0000ff', + 'blueviolet': '#8a2be2', + 'brown': '#a52a2a', + 'burlywood': '#deb887', + 'cadetblue': '#5f9ea0', + 'chartreuse': '#7fff00', + 'chocolate': '#d2691e', + 'coral': '#ff7f50', + 'cornflowerblue': '#6495ed', + 'cornsilk': '#fff8dc', + 'crimson': '#dc143c', + 'cyan': '#00ffff', + 'darkblue': '#00008b', + 'darkcyan': '#008b8b', + 'darkgoldenrod': '#b8860b', + 'darkgray': '#a9a9a9', + 'darkgreen': '#006400', + 'darkgrey': '#a9a9a9', + 'darkkhaki': '#bdb76b', + 'darkmagenta': '#8b008b', + 'darkolivegreen': '#556b2f', + 'darkorange': '#ff8c00', + 'darkorchid': '#9932cc', + 'darkred': '#8b0000', + 'darksalmon': '#e9967a', + 'darkseagreen': '#8fbc8f', + 'darkslateblue': '#483d8b', + 'darkslategray': '#2f4f4f', + 'darkslategrey': '#2f4f4f', + 'darkturquoise': '#00ced1', + 'darkviolet': '#9400d3', + 'deeppink': '#ff1493', + 'deepskyblue': '#00bfff', + 'dimgray': '#696969', + 'dimgrey': '#696969', + 'dodgerblue': '#1e90ff', + 'firebrick': '#b22222', + 'floralwhite': '#fffaf0', + 'forestgreen': '#228b22', + 'fuchsia': '#ff00ff', + 'gainsboro': '#dcdcdc', + 'ghostwhite': '#f8f8ff', + 'gold': '#ffd700', + 'goldenrod': '#daa520', + 'gray': '#808080', + 'green': '#008000', + 'greenyellow': '#adff2f', + 'grey': '#808080', + 'honeydew': '#f0fff0', + 'hotpink': '#ff69b4', + 'indianred': '#cd5c5c', + 'indigo': '#4b0082', + 'ivory': '#fffff0', + 'khaki': '#f0e68c', + 'lavender': '#e6e6fa', + 'lavenderblush': '#fff0f5', + 'lawngreen': '#7cfc00', + 'lemonchiffon': '#fffacd', + 'lightblue': '#add8e6', + 'lightcoral': '#f08080', + 'lightcyan': '#e0ffff', + 'lightgoldenrodyellow': '#fafad2', + 'lightgray': '#d3d3d3', + 'lightgreen': '#90ee90', + 'lightgrey': '#d3d3d3', + 'lightpink': '#ffb6c1', + 'lightsalmon': '#ffa07a', + 'lightseagreen': '#20b2aa', + 'lightskyblue': '#87cefa', + 'lightslategray': '#778899', + 'lightslategrey': '#778899', + 'lightsteelblue': '#b0c4de', + 'lightyellow': '#ffffe0', + 'lime': '#00ff00', + 'limegreen': '#32cd32', + 'linen': '#faf0e6', + 'magenta': '#ff00ff', + 'maroon': '#800000', + 'mediumaquamarine': '#66cdaa', + 'mediumblue': '#0000cd', + 'mediumorchid': '#ba55d3', + 'mediumpurple': '#9370db', + 'mediumseagreen': '#3cb371', + 'mediumslateblue': '#7b68ee', + 'mediumspringgreen': '#00fa9a', + 'mediumturquoise': '#48d1cc', + 'mediumvioletred': '#c71585', + 'midnightblue': '#191970', + 'mintcream': '#f5fffa', + 'mistyrose': '#ffe4e1', + 'moccasin': '#ffe4b5', + 'navajowhite': '#ffdead', + 'navy': '#000080', + 'oldlace': '#fdf5e6', + 'olive': '#808000', + 'olivedrab': '#6b8e23', + 'orange': '#ffa500', + 'orangered': '#ff4500', + 'orchid': '#da70d6', + 'palegoldenrod': '#eee8aa', + 'palegreen': '#98fb98', + 'paleturquoise': '#afeeee', + 'palevioletred': '#db7093', + 'papayawhip': '#ffefd5', + 'peachpuff': '#ffdab9', + 'peru': '#cd853f', + 'pink': '#ffc0cb', + 'plum': '#dda0dd', + 'powderblue': '#b0e0e6', + 'purple': '#800080', + 'red': '#ff0000', + 'rosybrown': '#bc8f8f', + 'royalblue': '#4169e1', + 'saddlebrown': '#8b4513', + 'salmon': '#fa8072', + 'sandybrown': '#f4a460', + 'seagreen': '#2e8b57', + 'seashell': '#fff5ee', + 'sienna': '#a0522d', + 'silver': '#c0c0c0', + 'skyblue': '#87ceeb', + 'slateblue': '#6a5acd', + 'slategray': '#708090', + 'slategrey': '#708090', + 'snow': '#fffafa', + 'springgreen': '#00ff7f', + 'steelblue': '#4682b4', + 'tan': '#d2b48c', + 'teal': '#008080', + 'thistle': '#d8bfd8', + 'tomato': '#ff6347', + 'turquoise': '#40e0d0', + 'violet': '#ee82ee', + 'wheat': '#f5deb3', + 'white': '#ffffff', + 'whitesmoke': '#f5f5f5', + 'yellow': '#ffff00', + 'yellowgreen': '#9acd32' }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * logo: (string|olx.LogoOptions|undefined), - * projection: ol.proj.ProjectionLike, - * state: (ol.source.State|undefined), - * wrapX: (boolean|undefined)}} + * @fileoverview Utilities related to color and color conversion. */ -ol.source.SourceOptions; +goog.provide('goog.color'); +goog.provide('goog.color.Hsl'); +goog.provide('goog.color.Hsv'); +goog.provide('goog.color.Rgb'); + +goog.require('goog.color.names'); +goog.require('goog.math'); /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for {@link ol.layer.Layer} sources. - * - * A generic `change` event is triggered when the state of the source changes. - * - * @constructor - * @extends {ol.Object} - * @param {ol.source.SourceOptions} options Source options. - * @api stable + * RGB color representation. An array containing three elements [r, g, b], + * each an integer in [0, 255], representing the red, green, and blue components + * of the color respectively. + * @typedef {Array<number>} */ -ol.source.Source = function(options) { - - goog.base(this); - - /** - * @private - * @type {ol.proj.Projection} - */ - this.projection_ = ol.proj.get(options.projection); - - /** - * @private - * @type {Array.<ol.Attribution>} - */ - this.attributions_ = options.attributions !== undefined ? - options.attributions : null; - - /** - * @private - * @type {string|olx.LogoOptions|undefined} - */ - this.logo_ = options.logo; - - /** - * @private - * @type {ol.source.State} - */ - this.state_ = options.state !== undefined ? - options.state : ol.source.State.READY; +goog.color.Rgb; - /** - * @private - * @type {boolean} - */ - this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false; -}; -goog.inherits(ol.source.Source, ol.Object); +/** + * HSV color representation. An array containing three elements [h, s, v]: + * h (hue) must be an integer in [0, 360], cyclic. + * s (saturation) must be a number in [0, 1]. + * v (value/brightness) must be an integer in [0, 255]. + * @typedef {Array<number>} + */ +goog.color.Hsv; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {Object.<string, boolean>} skippedFeatureUids Skipped feature uids. - * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature - * callback. - * @return {T|undefined} Callback result. - * @template T + * HSL color representation. An array containing three elements [h, s, l]: + * h (hue) must be an integer in [0, 360], cyclic. + * s (saturation) must be a number in [0, 1]. + * l (lightness) must be a number in [0, 1]. + * @typedef {Array<number>} */ -ol.source.Source.prototype.forEachFeatureAtCoordinate = ol.nullFunction; +goog.color.Hsl; /** - * Get the attributions of the source. - * @return {Array.<ol.Attribution>} Attributions. - * @api stable + * Parses a color out of a string. + * @param {string} str Color in some format. + * @return {{hex: string, type: string}} 'hex' is a string containing a hex + * representation of the color, 'type' is a string containing the type + * of color format passed in ('hex', 'rgb', 'named'). */ -ol.source.Source.prototype.getAttributions = function() { - return this.attributions_; +goog.color.parse = function(str) { + var result = {}; + str = String(str); + + var maybeHex = goog.color.prependHashIfNecessaryHelper(str); + if (goog.color.isValidHexColor_(maybeHex)) { + result.hex = goog.color.normalizeHex(maybeHex); + result.type = 'hex'; + return result; + } else { + var rgb = goog.color.isValidRgbColor_(str); + if (rgb.length) { + result.hex = goog.color.rgbArrayToHex(rgb); + result.type = 'rgb'; + return result; + } else if (goog.color.names) { + var hex = goog.color.names[str.toLowerCase()]; + if (hex) { + result.hex = hex; + result.type = 'named'; + return result; + } + } + } + throw Error(str + ' is not a valid color string'); }; /** - * Get the logo of the source. - * @return {string|olx.LogoOptions|undefined} Logo. - * @api stable + * Determines if the given string can be parsed as a color. + * {@see goog.color.parse}. + * @param {string} str Potential color string. + * @return {boolean} True if str is in a format that can be parsed to a color. */ -ol.source.Source.prototype.getLogo = function() { - return this.logo_; +goog.color.isValidColor = function(str) { + var maybeHex = goog.color.prependHashIfNecessaryHelper(str); + return !!(goog.color.isValidHexColor_(maybeHex) || + goog.color.isValidRgbColor_(str).length || + goog.color.names && goog.color.names[str.toLowerCase()]); }; /** - * Get the projection of the source. - * @return {ol.proj.Projection} Projection. - * @api + * Parses red, green, blue components out of a valid rgb color string. + * Throws Error if the color string is invalid. + * @param {string} str RGB representation of a color. + * {@see goog.color.isValidRgbColor_}. + * @return {!goog.color.Rgb} rgb representation of the color. */ -ol.source.Source.prototype.getProjection = function() { - return this.projection_; +goog.color.parseRgb = function(str) { + var rgb = goog.color.isValidRgbColor_(str); + if (!rgb.length) { + throw Error(str + ' is not a valid RGB color'); + } + return rgb; }; /** - * @return {Array.<number>|undefined} Resolutions. + * Converts a hex representation of a color to RGB. + * @param {string} hexColor Color to convert. + * @return {string} string of the form 'rgb(R,G,B)' which can be used in + * styles. */ -ol.source.Source.prototype.getResolutions = goog.abstractMethod; +goog.color.hexToRgbStyle = function(hexColor) { + return goog.color.rgbStyle_(goog.color.hexToRgb(hexColor)); +}; /** - * Get the state of the source, see {@link ol.source.State} for possible states. - * @return {ol.source.State} State. - * @api + * Regular expression for extracting the digits in a hex color triplet. + * @type {RegExp} + * @private */ -ol.source.Source.prototype.getState = function() { - return this.state_; -}; +goog.color.hexTripletRe_ = /#(.)(.)(.)/; /** - * @return {boolean|undefined} Wrap X. + * Normalize an hex representation of a color + * @param {string} hexColor an hex color string. + * @return {string} hex color in the format '#rrggbb' with all lowercase + * literals. */ -ol.source.Source.prototype.getWrapX = function() { - return this.wrapX_; +goog.color.normalizeHex = function(hexColor) { + if (!goog.color.isValidHexColor_(hexColor)) { + throw Error("'" + hexColor + "' is not a valid hex color"); + } + if (hexColor.length == 4) { // of the form #RGB + hexColor = hexColor.replace(goog.color.hexTripletRe_, '#$1$1$2$2$3$3'); + } + return hexColor.toLowerCase(); }; /** - * Set the attributions of the source. - * @param {Array.<ol.Attribution>} attributions Attributions. - * @api + * Converts a hex representation of a color to RGB. + * @param {string} hexColor Color to convert. + * @return {!goog.color.Rgb} rgb representation of the color. */ -ol.source.Source.prototype.setAttributions = function(attributions) { - this.attributions_ = attributions; - this.changed(); +goog.color.hexToRgb = function(hexColor) { + hexColor = goog.color.normalizeHex(hexColor); + var r = parseInt(hexColor.substr(1, 2), 16); + var g = parseInt(hexColor.substr(3, 2), 16); + var b = parseInt(hexColor.substr(5, 2), 16); + + return [r, g, b]; }; /** - * Set the logo of the source. - * @param {string|olx.LogoOptions|undefined} logo Logo. + * Converts a color from RGB to hex representation. + * @param {number} r Amount of red, int between 0 and 255. + * @param {number} g Amount of green, int between 0 and 255. + * @param {number} b Amount of blue, int between 0 and 255. + * @return {string} hex representation of the color. */ -ol.source.Source.prototype.setLogo = function(logo) { - this.logo_ = logo; +goog.color.rgbToHex = function(r, g, b) { + r = Number(r); + g = Number(g); + b = Number(b); + if (isNaN(r) || r < 0 || r > 255 || + isNaN(g) || g < 0 || g > 255 || + isNaN(b) || b < 0 || b > 255) { + throw Error('"(' + r + ',' + g + ',' + b + '") is not a valid RGB color'); + } + var hexR = goog.color.prependZeroIfNecessaryHelper(r.toString(16)); + var hexG = goog.color.prependZeroIfNecessaryHelper(g.toString(16)); + var hexB = goog.color.prependZeroIfNecessaryHelper(b.toString(16)); + return '#' + hexR + hexG + hexB; }; /** - * Set the state of the source. - * @param {ol.source.State} state State. - * @protected + * Converts a color from RGB to hex representation. + * @param {goog.color.Rgb} rgb rgb representation of the color. + * @return {string} hex representation of the color. */ -ol.source.Source.prototype.setState = function(state) { - this.state_ = state; - this.changed(); +goog.color.rgbArrayToHex = function(rgb) { + return goog.color.rgbToHex(rgb[0], rgb[1], rgb[2]); }; /** - * Set the projection of the source. - * @param {ol.proj.Projection} projection Projection. + * Converts a color from RGB color space to HSL color space. + * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}. + * @param {number} r Value of red, in [0, 255]. + * @param {number} g Value of green, in [0, 255]. + * @param {number} b Value of blue, in [0, 255]. + * @return {!goog.color.Hsl} hsl representation of the color. */ -ol.source.Source.prototype.setProjection = function(projection) { - this.projection_ = projection; -}; +goog.color.rgbToHsl = function(r, g, b) { + // First must normalize r, g, b to be between 0 and 1. + var normR = r / 255; + var normG = g / 255; + var normB = b / 255; + var max = Math.max(normR, normG, normB); + var min = Math.min(normR, normG, normB); + var h = 0; + var s = 0; -goog.provide('ol.tilegrid.TileGrid'); + // Luminosity is the average of the max and min rgb color intensities. + var l = 0.5 * (max + min); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.TileCoord'); -goog.require('ol.TileRange'); -goog.require('ol.array'); -goog.require('ol.extent'); -goog.require('ol.extent.Corner'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); + // The hue and saturation are dependent on which color intensity is the max. + // If max and min are equal, the color is gray and h and s should be 0. + if (max != min) { + if (max == normR) { + h = 60 * (normG - normB) / (max - min); + } else if (max == normG) { + h = 60 * (normB - normR) / (max - min) + 120; + } else if (max == normB) { + h = 60 * (normR - normG) / (max - min) + 240; + } + + if (0 < l && l <= 0.5) { + s = (max - min) / (2 * l); + } else { + s = (max - min) / (2 - 2 * l); + } + } + // Make sure the hue falls between 0 and 360. + return [Math.round(h + 360) % 360, s, l]; +}; /** - * @classdesc - * Base class for setting the grid pattern for sources accessing tiled-image - * servers. - * - * @constructor - * @param {olx.tilegrid.TileGridOptions} options Tile grid options. - * @struct - * @api stable + * Converts a color from RGB color space to HSL color space. + * @param {goog.color.Rgb} rgb rgb representation of the color. + * @return {!goog.color.Hsl} hsl representation of the color. */ -ol.tilegrid.TileGrid = function(options) { +goog.color.rgbArrayToHsl = function(rgb) { + return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]); +}; - /** - * @protected - * @type {number} - */ - this.minZoom = options.minZoom !== undefined ? options.minZoom : 0; - /** - * @private - * @type {!Array.<number>} - */ - this.resolutions_ = options.resolutions; - goog.asserts.assert(goog.array.isSorted(this.resolutions_, function(a, b) { - return b - a; - }, true), 'resolutions must be sorted in descending order'); +/** + * Helper for hslToRgb. + * @param {number} v1 Helper variable 1. + * @param {number} v2 Helper variable 2. + * @param {number} vH Helper variable 3. + * @return {number} Appropriate RGB value, given the above. + * @private + */ +goog.color.hueToRgb_ = function(v1, v2, vH) { + if (vH < 0) { + vH += 1; + } else if (vH > 1) { + vH -= 1; + } + if ((6 * vH) < 1) { + return (v1 + (v2 - v1) * 6 * vH); + } else if (2 * vH < 1) { + return v2; + } else if (3 * vH < 2) { + return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6); + } + return v1; +}; - /** - * @protected - * @type {number} - */ - this.maxZoom = this.resolutions_.length - 1; - /** - * @private - * @type {ol.Coordinate} - */ - this.origin_ = options.origin !== undefined ? options.origin : null; +/** + * Converts a color from HSL color space to RGB color space. + * Modified from {@link http://www.easyrgb.com/math.html} + * @param {number} h Hue, in [0, 360]. + * @param {number} s Saturation, in [0, 1]. + * @param {number} l Luminosity, in [0, 1]. + * @return {!goog.color.Rgb} rgb representation of the color. + */ +goog.color.hslToRgb = function(h, s, l) { + var r = 0; + var g = 0; + var b = 0; + var normH = h / 360; // normalize h to fall in [0, 1] - /** - * @private - * @type {Array.<ol.Coordinate>} - */ - this.origins_ = null; - if (options.origins !== undefined) { - this.origins_ = options.origins; - goog.asserts.assert(this.origins_.length == this.resolutions_.length, - 'number of origins and resolutions must be equal'); + if (s == 0) { + r = g = b = l * 255; + } else { + var temp1 = 0; + var temp2 = 0; + if (l < 0.5) { + temp2 = l * (1 + s); + } else { + temp2 = l + s - (s * l); + } + temp1 = 2 * l - temp2; + r = 255 * goog.color.hueToRgb_(temp1, temp2, normH + (1 / 3)); + g = 255 * goog.color.hueToRgb_(temp1, temp2, normH); + b = 255 * goog.color.hueToRgb_(temp1, temp2, normH - (1 / 3)); } - var extent = options.extent; + return [Math.round(r), Math.round(g), Math.round(b)]; +}; - if (extent !== undefined && - !this.origin_ && !this.origins_) { - this.origin_ = ol.extent.getTopLeft(extent); - } - goog.asserts.assert( - (!this.origin_ && this.origins_) || - (this.origin_ && !this.origins_), - 'either origin or origins must be configured, never both'); +/** + * Converts a color from HSL color space to RGB color space. + * @param {goog.color.Hsl} hsl hsl representation of the color. + * @return {!goog.color.Rgb} rgb representation of the color. + */ +goog.color.hslArrayToRgb = function(hsl) { + return goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]); +}; - /** - * @private - * @type {Array.<number|ol.Size>} - */ - this.tileSizes_ = null; - if (options.tileSizes !== undefined) { - this.tileSizes_ = options.tileSizes; - goog.asserts.assert(this.tileSizes_.length == this.resolutions_.length, - 'number of tileSizes and resolutions must be equal'); - } - /** - * @private - * @type {number|ol.Size} - */ - this.tileSize_ = options.tileSize !== undefined ? - options.tileSize : - !this.tileSizes_ ? ol.DEFAULT_TILE_SIZE : null; - goog.asserts.assert( - (!this.tileSize_ && this.tileSizes_) || - (this.tileSize_ && !this.tileSizes_), - 'either tileSize or tileSizes must be configured, never both'); +/** + * Helper for isValidHexColor_. + * @type {RegExp} + * @private + */ +goog.color.validHexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = extent !== undefined ? extent : null; +/** + * Checks if a string is a valid hex color. We expect strings of the format + * #RRGGBB (ex: #1b3d5f) or #RGB (ex: #3CA == #33CCAA). + * @param {string} str String to check. + * @return {boolean} Whether the string is a valid hex color. + * @private + */ +goog.color.isValidHexColor_ = function(str) { + return goog.color.validHexColorRe_.test(str); +}; - /** - * @private - * @type {Array.<ol.TileRange>} - */ - this.fullTileRanges_ = null; - if (options.sizes !== undefined) { - goog.asserts.assert(options.sizes.length == this.resolutions_.length, - 'number of sizes and resolutions must be equal'); - this.fullTileRanges_ = options.sizes.map(function(size, z) { - goog.asserts.assert(size[0] !== 0, 'width must not be 0'); - goog.asserts.assert(size[1] !== 0, 'height must not be 0'); - var tileRange = new ol.TileRange( - Math.min(0, size[0]), Math.max(size[0] - 1, -1), - Math.min(0, size[1]), Math.max(size[1] - 1, -1)); - if (this.minZoom <= z && z <= this.maxZoom && extent !== undefined) { - goog.asserts.assert(tileRange.containsTileRange( - this.getTileRangeForExtentAndZ(extent, z)), - 'extent tile range must not exceed tilegrid width and height'); - } - return tileRange; - }, this); - } else if (extent) { - this.calculateTileRanges_(extent); - } +/** + * Helper for isNormalizedHexColor_. + * @type {RegExp} + * @private + */ +goog.color.normalizedHexColorRe_ = /^#[0-9a-f]{6}$/; - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; +/** + * Checks if a string is a normalized hex color. + * We expect strings of the format #RRGGBB (ex: #1b3d5f) + * using only lowercase letters. + * @param {string} str String to check. + * @return {boolean} Whether the string is a normalized hex color. + * @private + */ +goog.color.isNormalizedHexColor_ = function(str) { + return goog.color.normalizedHexColorRe_.test(str); }; /** + * Regular expression for matching and capturing RGB style strings. Helper for + * isValidRgbColor_. + * @type {RegExp} * @private - * @type {ol.TileCoord} */ -ol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0]; +goog.color.rgbColorRe_ = + /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {function(this: T, number, ol.TileRange): boolean} callback Callback. - * @param {T=} opt_this The object to use as `this` in `callback`. - * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. - * @param {ol.Extent=} opt_extent Temporary ol.Extent object. - * @return {boolean} Callback succeeded. - * @template T + * Checks if a string is a valid rgb color. We expect strings of the format + * '(r, g, b)', or 'rgb(r, g, b)', where each color component is an int in + * [0, 255]. + * @param {string} str String to check. + * @return {!goog.color.Rgb} the rgb representation of the color if it is + * a valid color, or the empty array otherwise. + * @private */ -ol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange = - function(tileCoord, callback, opt_this, opt_tileRange, opt_extent) { - var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); - var z = tileCoord[0] - 1; - while (z >= this.minZoom) { - if (callback.call(opt_this, z, - this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange))) { - return true; +goog.color.isValidRgbColor_ = function(str) { + // Each component is separate (rather than using a repeater) so we can + // capture the match. Also, we explicitly set each component to be either 0, + // or start with a non-zero, to prevent octal numbers from slipping through. + var regExpResultArray = str.match(goog.color.rgbColorRe_); + if (regExpResultArray) { + var r = Number(regExpResultArray[1]); + var g = Number(regExpResultArray[2]); + var b = Number(regExpResultArray[3]); + if (r >= 0 && r <= 255 && + g >= 0 && g <= 255 && + b >= 0 && b <= 255) { + return [r, g, b]; } - --z; } - return false; + return []; }; /** - * Get the extent for this tile grid, if it was configured. - * @return {ol.Extent} Extent. + * Takes a hex value and prepends a zero if it's a single digit. + * Small helper method for use by goog.color and friends. + * @param {string} hex Hex value to prepend if single digit. + * @return {string} hex value prepended with zero if it was single digit, + * otherwise the same value that was passed in. */ -ol.tilegrid.TileGrid.prototype.getExtent = function() { - return this.extent_; +goog.color.prependZeroIfNecessaryHelper = function(hex) { + return hex.length == 1 ? '0' + hex : hex; }; /** - * Get the maximum zoom level for the grid. - * @return {number} Max zoom. - * @api + * Takes a string a prepends a '#' sign if one doesn't exist. + * Small helper method for use by goog.color and friends. + * @param {string} str String to check. + * @return {string} The value passed in, prepended with a '#' if it didn't + * already have one. */ -ol.tilegrid.TileGrid.prototype.getMaxZoom = function() { - return this.maxZoom; +goog.color.prependHashIfNecessaryHelper = function(str) { + return str.charAt(0) == '#' ? str : '#' + str; }; /** - * Get the minimum zoom level for the grid. - * @return {number} Min zoom. - * @api + * Takes an array of [r, g, b] and converts it into a string appropriate for + * CSS styles. + * @param {goog.color.Rgb} rgb rgb representation of the color. + * @return {string} string of the form 'rgb(r,g,b)'. + * @private */ -ol.tilegrid.TileGrid.prototype.getMinZoom = function() { - return this.minZoom; +goog.color.rgbStyle_ = function(rgb) { + return 'rgb(' + rgb.join(',') + ')'; }; /** - * Get the origin for the grid at the given zoom level. - * @param {number} z Z. - * @return {ol.Coordinate} Origin. - * @api stable + * Converts an HSV triplet to an RGB array. V is brightness because b is + * reserved for blue in RGB. + * @param {number} h Hue value in [0, 360]. + * @param {number} s Saturation value in [0, 1]. + * @param {number} brightness brightness in [0, 255]. + * @return {!goog.color.Rgb} rgb representation of the color. */ -ol.tilegrid.TileGrid.prototype.getOrigin = function(z) { - if (this.origin_) { - return this.origin_; +goog.color.hsvToRgb = function(h, s, brightness) { + var red = 0; + var green = 0; + var blue = 0; + if (s == 0) { + red = brightness; + green = brightness; + blue = brightness; } else { - goog.asserts.assert(this.origins_, - 'origins cannot be null if origin is null'); - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'given z is not in allowed range (%s <= %s <= %s)', - this.minZoom, z, this.maxZoom); - return this.origins_[z]; + var sextant = Math.floor(h / 60); + var remainder = (h / 60) - sextant; + var val1 = brightness * (1 - s); + var val2 = brightness * (1 - (s * remainder)); + var val3 = brightness * (1 - (s * (1 - remainder))); + switch (sextant) { + case 1: + red = val2; + green = brightness; + blue = val1; + break; + case 2: + red = val1; + green = brightness; + blue = val3; + break; + case 3: + red = val1; + green = val2; + blue = brightness; + break; + case 4: + red = val3; + green = val1; + blue = brightness; + break; + case 5: + red = brightness; + green = val1; + blue = val2; + break; + case 6: + case 0: + red = brightness; + green = val3; + blue = val1; + break; + } } + + return [Math.floor(red), Math.floor(green), Math.floor(blue)]; }; /** - * Get the resolution for the given zoom level. - * @param {number} z Z. - * @return {number} Resolution. - * @api stable + * Converts from RGB values to an array of HSV values. + * @param {number} red Red value in [0, 255]. + * @param {number} green Green value in [0, 255]. + * @param {number} blue Blue value in [0, 255]. + * @return {!goog.color.Hsv} hsv representation of the color. */ -ol.tilegrid.TileGrid.prototype.getResolution = function(z) { - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'given z is not in allowed range (%s <= %s <= %s)', - this.minZoom, z, this.maxZoom); - return this.resolutions_[z]; +goog.color.rgbToHsv = function(red, green, blue) { + + var max = Math.max(Math.max(red, green), blue); + var min = Math.min(Math.min(red, green), blue); + var hue; + var saturation; + var value = max; + if (min == max) { + hue = 0; + saturation = 0; + } else { + var delta = (max - min); + saturation = delta / max; + + if (red == max) { + hue = (green - blue) / delta; + } else if (green == max) { + hue = 2 + ((blue - red) / delta); + } else { + hue = 4 + ((red - green) / delta); + } + hue *= 60; + if (hue < 0) { + hue += 360; + } + if (hue > 360) { + hue -= 360; + } + } + + return [hue, saturation, value]; }; /** - * Get the list of resolutions for the tile grid. - * @return {Array.<number>} Resolutions. - * @api stable + * Converts from an array of RGB values to an array of HSV values. + * @param {goog.color.Rgb} rgb rgb representation of the color. + * @return {!goog.color.Hsv} hsv representation of the color. */ -ol.tilegrid.TileGrid.prototype.getResolutions = function() { - return this.resolutions_; +goog.color.rgbArrayToHsv = function(rgb) { + return goog.color.rgbToHsv(rgb[0], rgb[1], rgb[2]); }; /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. - * @param {ol.Extent=} opt_extent Temporary ol.Extent object. - * @return {ol.TileRange} Tile range. + * Converts an HSV triplet to an RGB array. + * @param {goog.color.Hsv} hsv hsv representation of the color. + * @return {!goog.color.Rgb} rgb representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileCoordChildTileRange = - function(tileCoord, opt_tileRange, opt_extent) { - if (tileCoord[0] < this.maxZoom) { - var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); - return this.getTileRangeForExtentAndZ( - tileCoordExtent, tileCoord[0] + 1, opt_tileRange); - } else { - return null; - } +goog.color.hsvArrayToRgb = function(hsv) { + return goog.color.hsvToRgb(hsv[0], hsv[1], hsv[2]); }; /** - * @param {number} z Z. - * @param {ol.TileRange} tileRange Tile range. - * @param {ol.Extent=} opt_extent Temporary ol.Extent object. - * @return {ol.Extent} Extent. + * Converts a hex representation of a color to HSL. + * @param {string} hex Color to convert. + * @return {!goog.color.Hsv} hsv representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileRangeExtent = - function(z, tileRange, opt_extent) { - var origin = this.getOrigin(z); - var resolution = this.getResolution(z); - var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_); - var minX = origin[0] + tileRange.minX * tileSize[0] * resolution; - var maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution; - var minY = origin[1] + tileRange.minY * tileSize[1] * resolution; - var maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution; - return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); +goog.color.hexToHsl = function(hex) { + var rgb = goog.color.hexToRgb(hex); + return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]); }; /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {ol.TileRange=} opt_tileRange Temporary tile range object. - * @return {ol.TileRange} Tile range. + * Converts from h,s,l values to a hex string + * @param {number} h Hue, in [0, 360]. + * @param {number} s Saturation, in [0, 1]. + * @param {number} l Luminosity, in [0, 1]. + * @return {string} hex representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = - function(extent, resolution, opt_tileRange) { - var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_; - this.getTileCoordForXYAndResolution_( - extent[0], extent[1], resolution, false, tileCoord); - var minX = tileCoord[1]; - var minY = tileCoord[2]; - this.getTileCoordForXYAndResolution_( - extent[2], extent[3], resolution, true, tileCoord); - return ol.TileRange.createOrUpdate( - minX, tileCoord[1], minY, tileCoord[2], opt_tileRange); +goog.color.hslToHex = function(h, s, l) { + return goog.color.rgbArrayToHex(goog.color.hslToRgb(h, s, l)); }; /** - * @param {ol.Extent} extent Extent. - * @param {number} z Z. - * @param {ol.TileRange=} opt_tileRange Temporary tile range object. - * @return {ol.TileRange} Tile range. + * Converts from an hsl array to a hex string + * @param {goog.color.Hsl} hsl hsl representation of the color. + * @return {string} hex representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = - function(extent, z, opt_tileRange) { - var resolution = this.getResolution(z); - return this.getTileRangeForExtentAndResolution( - extent, resolution, opt_tileRange); +goog.color.hslArrayToHex = function(hsl) { + return goog.color.rgbArrayToHex(goog.color.hslToRgb(hsl[0], hsl[1], hsl[2])); }; /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @return {ol.Coordinate} Tile center. + * Converts a hex representation of a color to HSV + * @param {string} hex Color to convert. + * @return {!goog.color.Hsv} hsv representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) { - var origin = this.getOrigin(tileCoord[0]); - var resolution = this.getResolution(tileCoord[0]); - var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); - return [ - origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution, - origin[1] + (tileCoord[2] + 0.5) * tileSize[1] * resolution - ]; +goog.color.hexToHsv = function(hex) { + return goog.color.rgbArrayToHsv(goog.color.hexToRgb(hex)); }; /** - * Get the extent of a tile coordinate. - * - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Extent=} opt_extent Temporary extent object. - * @return {ol.Extent} Extent. - * @api + * Converts from h,s,v values to a hex string + * @param {number} h Hue, in [0, 360]. + * @param {number} s Saturation, in [0, 1]. + * @param {number} v Value, in [0, 255]. + * @return {string} hex representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileCoordExtent = - function(tileCoord, opt_extent) { - var origin = this.getOrigin(tileCoord[0]); - var resolution = this.getResolution(tileCoord[0]); - var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); - var minX = origin[0] + tileCoord[1] * tileSize[0] * resolution; - var minY = origin[1] + tileCoord[2] * tileSize[1] * resolution; - var maxX = minX + tileSize[0] * resolution; - var maxY = minY + tileSize[1] * resolution; - return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent); +goog.color.hsvToHex = function(h, s, v) { + return goog.color.rgbArrayToHex(goog.color.hsvToRgb(h, s, v)); }; /** - * Get the tile coordinate for the given map coordinate and resolution. This - * method considers that coordinates that intersect tile boundaries should be - * assigned the higher tile coordinate. - * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object. - * @return {ol.TileCoord} Tile coordinate. - * @api + * Converts from an HSV array to a hex string + * @param {goog.color.Hsv} hsv hsv representation of the color. + * @return {string} hex representation of the color. */ -ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = - function(coordinate, resolution, opt_tileCoord) { - return this.getTileCoordForXYAndResolution_( - coordinate[0], coordinate[1], resolution, false, opt_tileCoord); +goog.color.hsvArrayToHex = function(hsv) { + return goog.color.hsvToHex(hsv[0], hsv[1], hsv[2]); }; /** - * @param {number} x X. - * @param {number} y Y. - * @param {number} resolution Resolution. - * @param {boolean} reverseIntersectionPolicy Instead of letting edge - * intersections go to the higher tile coordinate, let edge intersections - * go to the lower tile coordinate. - * @param {ol.TileCoord=} opt_tileCoord Temporary ol.TileCoord object. - * @return {ol.TileCoord} Tile coordinate. - * @private + * Calculates the Euclidean distance between two color vectors on an HSL sphere. + * A demo of the sphere can be found at: + * http://en.wikipedia.org/wiki/HSL_color_space + * In short, a vector for color (H, S, L) in this system can be expressed as + * (S*L'*cos(2*PI*H), S*L'*sin(2*PI*H), L), where L' = abs(L - 0.5), and we + * simply calculate the 1-2 distance using these coordinates + * @param {goog.color.Hsl} hsl1 First color in hsl representation. + * @param {goog.color.Hsl} hsl2 Second color in hsl representation. + * @return {number} Distance between the two colors, in the range [0, 1]. */ -ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function( - x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) { - var z = this.getZForResolution(resolution); - var scale = resolution / this.getResolution(z); - var origin = this.getOrigin(z); - var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_); - - var adjustX = reverseIntersectionPolicy ? 0.5 : 0; - var adjustY = reverseIntersectionPolicy ? 0 : 0.5; - var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX); - var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY); - var tileCoordX = scale * xFromOrigin / tileSize[0]; - var tileCoordY = scale * yFromOrigin / tileSize[1]; +goog.color.hslDistance = function(hsl1, hsl2) { + var sl1, sl2; + if (hsl1[2] <= 0.5) { + sl1 = hsl1[1] * hsl1[2]; + } else { + sl1 = hsl1[1] * (1.0 - hsl1[2]); + } - if (reverseIntersectionPolicy) { - tileCoordX = Math.ceil(tileCoordX) - 1; - tileCoordY = Math.ceil(tileCoordY) - 1; + if (hsl2[2] <= 0.5) { + sl2 = hsl2[1] * hsl2[2]; } else { - tileCoordX = Math.floor(tileCoordX); - tileCoordY = Math.floor(tileCoordY); + sl2 = hsl2[1] * (1.0 - hsl2[2]); } - return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord); + var h1 = hsl1[0] / 360.0; + var h2 = hsl2[0] / 360.0; + var dh = (h1 - h2) * 2.0 * Math.PI; + return (hsl1[2] - hsl2[2]) * (hsl1[2] - hsl2[2]) + + sl1 * sl1 + sl2 * sl2 - 2 * sl1 * sl2 * Math.cos(dh); }; /** - * Get a tile coordinate given a map coordinate and zoom level. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} z Zoom level. - * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object. - * @return {ol.TileCoord} Tile coordinate. - * @api + * Blend two colors together, using the specified factor to indicate the weight + * given to the first color + * @param {goog.color.Rgb} rgb1 First color represented in rgb. + * @param {goog.color.Rgb} rgb2 Second color represented in rgb. + * @param {number} factor The weight to be given to rgb1 over rgb2. Values + * should be in the range [0, 1]. If less than 0, factor will be set to 0. + * If greater than 1, factor will be set to 1. + * @return {!goog.color.Rgb} Combined color represented in rgb. */ -ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ = - function(coordinate, z, opt_tileCoord) { - var resolution = this.getResolution(z); - return this.getTileCoordForXYAndResolution_( - coordinate[0], coordinate[1], resolution, false, opt_tileCoord); +goog.color.blend = function(rgb1, rgb2, factor) { + factor = goog.math.clamp(factor, 0, 1); + + return [ + Math.round(factor * rgb1[0] + (1.0 - factor) * rgb2[0]), + Math.round(factor * rgb1[1] + (1.0 - factor) * rgb2[1]), + Math.round(factor * rgb1[2] + (1.0 - factor) * rgb2[2]) + ]; }; /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @return {number} Tile resolution. + * Adds black to the specified color, darkening it + * @param {goog.color.Rgb} rgb rgb representation of the color. + * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while + * 1 will return black. If less than 0, factor will be set to 0. If greater + * than 1, factor will be set to 1. + * @return {!goog.color.Rgb} Combined rgb color. */ -ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) { - goog.asserts.assert( - this.minZoom <= tileCoord[0] && tileCoord[0] <= this.maxZoom, - 'z of given tilecoord is not in allowed range (%s <= %s <= %s', - this.minZoom, tileCoord[0], this.maxZoom); - return this.resolutions_[tileCoord[0]]; +goog.color.darken = function(rgb, factor) { + var black = [0, 0, 0]; + return goog.color.blend(black, rgb, factor); }; /** - * Get the tile size for a zoom level. The type of the return value matches the - * `tileSize` or `tileSizes` that the tile grid was configured with. To always - * get an `ol.Size`, run the result through `ol.size.toSize()`. - * @param {number} z Z. - * @return {number|ol.Size} Tile size. - * @api stable + * Adds white to the specified color, lightening it + * @param {goog.color.Rgb} rgb rgb representation of the color. + * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while + * 1 will return white. If less than 0, factor will be set to 0. If greater + * than 1, factor will be set to 1. + * @return {!goog.color.Rgb} Combined rgb color. */ -ol.tilegrid.TileGrid.prototype.getTileSize = function(z) { - if (this.tileSize_) { - return this.tileSize_; - } else { - goog.asserts.assert(this.tileSizes_, - 'tileSizes cannot be null if tileSize is null'); - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'z is not in allowed range (%s <= %s <= %s', - this.minZoom, z, this.maxZoom); - return this.tileSizes_[z]; - } +goog.color.lighten = function(rgb, factor) { + var white = [255, 255, 255]; + return goog.color.blend(white, rgb, factor); }; /** - * @param {number} z Zoom level. - * @return {ol.TileRange} Extent tile range for the specified zoom level. + * Find the "best" (highest-contrast) of the suggested colors for the prime + * color. Uses W3C formula for judging readability and visual accessibility: + * http://www.w3.org/TR/AERT#color-contrast + * @param {goog.color.Rgb} prime Color represented as a rgb array. + * @param {Array<goog.color.Rgb>} suggestions Array of colors, + * each representing a rgb array. + * @return {!goog.color.Rgb} Highest-contrast color represented by an array.. */ -ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) { - if (!this.fullTileRanges_) { - return null; - } else { - goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom, - 'z is not in allowed range (%s <= %s <= %s', - this.minZoom, z, this.maxZoom); - return this.fullTileRanges_[z]; +goog.color.highContrast = function(prime, suggestions) { + var suggestionsWithDiff = []; + for (var i = 0; i < suggestions.length; i++) { + suggestionsWithDiff.push({ + color: suggestions[i], + diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) + + goog.color.colorDiff_(suggestions[i], prime) + }); } + suggestionsWithDiff.sort(function(a, b) { + return b.diff - a.diff; + }); + return suggestionsWithDiff[0].color; }; /** - * @param {number} resolution Resolution. - * @return {number} Z. + * Calculate brightness of a color according to YIQ formula (brightness is Y). + * More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for + * goog.color.highContrast() + * @param {goog.color.Rgb} rgb Color represented by a rgb array. + * @return {number} brightness (Y). + * @private */ -ol.tilegrid.TileGrid.prototype.getZForResolution = function(resolution) { - var z = ol.array.linearFindNearest(this.resolutions_, resolution, 0); - return ol.math.clamp(z, this.minZoom, this.maxZoom); +goog.color.yiqBrightness_ = function(rgb) { + return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000); }; /** - * @param {!ol.Extent} extent Extent for this tile grid. + * Calculate difference in brightness of two colors. Helper method for + * goog.color.highContrast() + * @param {goog.color.Rgb} rgb1 Color represented by a rgb array. + * @param {goog.color.Rgb} rgb2 Color represented by a rgb array. + * @return {number} Brightness difference. * @private */ -ol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) { - var length = this.resolutions_.length; - var fullTileRanges = new Array(length); - for (var z = this.minZoom; z < length; ++z) { - fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z); - } - this.fullTileRanges_ = fullTileRanges; +goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) { + return Math.abs(goog.color.yiqBrightness_(rgb1) - + goog.color.yiqBrightness_(rgb2)); }; /** - * @param {ol.proj.Projection} projection Projection. - * @return {ol.tilegrid.TileGrid} Default tile grid for the passed projection. + * Calculate color difference between two colors. Helper method for + * goog.color.highContrast() + * @param {goog.color.Rgb} rgb1 Color represented by a rgb array. + * @param {goog.color.Rgb} rgb2 Color represented by a rgb array. + * @return {number} Color difference. + * @private */ -ol.tilegrid.getForProjection = function(projection) { - var tileGrid = projection.getDefaultTileGrid(); - if (!tileGrid) { - tileGrid = ol.tilegrid.createForProjection(projection); - projection.setDefaultTileGrid(tileGrid); - } - return tileGrid; +goog.color.colorDiff_ = function(rgb1, rgb2) { + return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) + + Math.abs(rgb1[2] - rgb2[2]); }; +// We can't use goog.color or goog.color.alpha because they interally use a hex +// string representation that encodes each channel in a single byte. This +// causes occasional loss of precision and rounding errors, especially in the +// alpha channel. -/** - * @param {ol.Extent} extent Extent. - * @param {number=} opt_maxZoom Maximum zoom level (default is - * ol.DEFAULT_MAX_ZOOM). - * @param {number|ol.Size=} opt_tileSize Tile size (default uses - * ol.DEFAULT_TILE_SIZE). - * @param {ol.extent.Corner=} opt_corner Extent corner (default is - * ol.extent.Corner.TOP_LEFT). - * @return {ol.tilegrid.TileGrid} TileGrid instance. - */ -ol.tilegrid.createForExtent = - function(extent, opt_maxZoom, opt_tileSize, opt_corner) { - var corner = opt_corner !== undefined ? - opt_corner : ol.extent.Corner.TOP_LEFT; - - var resolutions = ol.tilegrid.resolutionsFromExtent( - extent, opt_maxZoom, opt_tileSize); +goog.provide('ol.Color'); +goog.provide('ol.color'); - return new ol.tilegrid.TileGrid({ - extent: extent, - origin: ol.extent.getCorner(extent, corner), - resolutions: resolutions, - tileSize: opt_tileSize - }); -}; +goog.require('goog.asserts'); +goog.require('goog.color'); +goog.require('goog.color.names'); +goog.require('goog.vec.Mat4'); +goog.require('ol'); +goog.require('ol.math'); /** - * Creates a tile grid with a standard XYZ tiling scheme. - * @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options. - * @return {ol.tilegrid.TileGrid} Tile grid instance. + * A color represented as a short array [red, green, blue, alpha]. + * red, green, and blue should be integers in the range 0..255 inclusive. + * alpha should be a float in the range 0..1 inclusive. + * @typedef {Array.<number>} * @api */ -ol.tilegrid.createXYZ = function(opt_options) { - var options = /** @type {olx.tilegrid.TileGridOptions} */ ({}); - goog.object.extend(options, opt_options !== undefined ? - opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({})); - if (options.extent === undefined) { - options.extent = ol.proj.get('EPSG:3857').getExtent(); - } - options.resolutions = ol.tilegrid.resolutionsFromExtent( - options.extent, options.maxZoom, options.tileSize); - delete options.maxZoom; - - return new ol.tilegrid.TileGrid(options); -}; +ol.Color; /** - * Create a resolutions array from an extent. A zoom factor of 2 is assumed. - * @param {ol.Extent} extent Extent. - * @param {number=} opt_maxZoom Maximum zoom level (default is - * ol.DEFAULT_MAX_ZOOM). - * @param {number|ol.Size=} opt_tileSize Tile size (default uses - * ol.DEFAULT_TILE_SIZE). - * @return {!Array.<number>} Resolutions array. + * This RegExp matches # followed by 3 or 6 hex digits. + * @const + * @type {RegExp} + * @private */ -ol.tilegrid.resolutionsFromExtent = - function(extent, opt_maxZoom, opt_tileSize) { - var maxZoom = opt_maxZoom !== undefined ? - opt_maxZoom : ol.DEFAULT_MAX_ZOOM; - - var height = ol.extent.getHeight(extent); - var width = ol.extent.getWidth(extent); - - var tileSize = ol.size.toSize(opt_tileSize !== undefined ? - opt_tileSize : ol.DEFAULT_TILE_SIZE); - var maxResolution = Math.max( - width / tileSize[0], height / tileSize[1]); - - var length = maxZoom + 1; - var resolutions = new Array(length); - for (var z = 0; z < length; ++z) { - resolutions[z] = maxResolution / Math.pow(2, z); - } - return resolutions; -}; +ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i; /** - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {number=} opt_maxZoom Maximum zoom level (default is - * ol.DEFAULT_MAX_ZOOM). - * @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE). - * @param {ol.extent.Corner=} opt_corner Extent corner (default is - * ol.extent.Corner.BOTTOM_LEFT). - * @return {ol.tilegrid.TileGrid} TileGrid instance. + * @see goog.color.rgbColorRe_ + * @const + * @type {RegExp} + * @private */ -ol.tilegrid.createForProjection = - function(projection, opt_maxZoom, opt_tileSize, opt_corner) { - var extent = ol.tilegrid.extentFromProjection(projection); - return ol.tilegrid.createForExtent( - extent, opt_maxZoom, opt_tileSize, opt_corner); -}; +ol.color.rgbColorRe_ = + /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i; /** - * Generate a tile grid extent from a projection. If the projection has an - * extent, it is used. If not, a global extent is assumed. - * @param {ol.proj.ProjectionLike} projection Projection. - * @return {ol.Extent} Extent. + * @see goog.color.alpha.rgbaColorRe_ + * @const + * @type {RegExp} + * @private */ -ol.tilegrid.extentFromProjection = function(projection) { - projection = ol.proj.get(projection); - var extent = projection.getExtent(); - if (!extent) { - var half = 180 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] / - projection.getMetersPerUnit(); - extent = ol.extent.createOrUpdate(-half, -half, half, half); - } - return extent; -}; -goog.exportProperty(ol.tilegrid.TileGrid.prototype, 'getTileRangeForExtentAndZ', - ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ); - - -goog.provide('ol.source.Tile'); -goog.provide('ol.source.TileEvent'); -goog.provide('ol.source.TileOptions'); - -goog.require('goog.asserts'); -goog.require('goog.events.Event'); -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.Extent'); -goog.require('ol.TileCache'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.proj'); -goog.require('ol.size'); -goog.require('ol.source.Source'); -goog.require('ol.tilecoord'); -goog.require('ol.tilegrid.TileGrid'); +ol.color.rgbaColorRe_ = + /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i; /** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * cacheSize: (number|undefined), - * extent: (ol.Extent|undefined), - * logo: (string|olx.LogoOptions|undefined), - * opaque: (boolean|undefined), - * tilePixelRatio: (number|undefined), - * projection: ol.proj.ProjectionLike, - * state: (ol.source.State|undefined), - * tileGrid: (ol.tilegrid.TileGrid|undefined), - * wrapX: (boolean|undefined)}} + * @param {ol.Color} dst Destination. + * @param {ol.Color} src Source. + * @param {ol.Color=} opt_color Color. + * @return {ol.Color} Color. */ -ol.source.TileOptions; - +ol.color.blend = function(dst, src, opt_color) { + // http://en.wikipedia.org/wiki/Alpha_compositing + // FIXME do we need to scale by 255? + var out = opt_color ? opt_color : []; + var dstA = dst[3]; + var srcA = src[3]; + if (dstA == 1) { + out[0] = (src[0] * srcA + dst[0] * (1 - srcA) + 0.5) | 0; + out[1] = (src[1] * srcA + dst[1] * (1 - srcA) + 0.5) | 0; + out[2] = (src[2] * srcA + dst[2] * (1 - srcA) + 0.5) | 0; + out[3] = 1; + } else if (srcA === 0) { + out[0] = dst[0]; + out[1] = dst[1]; + out[2] = dst[2]; + out[3] = dstA; + } else { + var outA = srcA + dstA * (1 - srcA); + if (outA === 0) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } else { + out[0] = ((src[0] * srcA + dst[0] * dstA * (1 - srcA)) / outA + 0.5) | 0; + out[1] = ((src[1] * srcA + dst[1] * dstA * (1 - srcA)) / outA + 0.5) | 0; + out[2] = ((src[2] * srcA + dst[2] * dstA * (1 - srcA)) / outA + 0.5) | 0; + out[3] = outA; + } + } + goog.asserts.assert(ol.color.isValid(out), + 'Output color of blend should be a valid color'); + return out; +}; /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for sources providing images divided into a tile grid. - * - * @constructor - * @extends {ol.source.Source} - * @param {ol.source.TileOptions} options Tile source options. + * Return the color as an array. This function maintains a cache of calculated + * arrays which means the result should not be modified. + * @param {ol.Color|string} color Color. + * @return {ol.Color} Color. * @api */ -ol.source.Tile = function(options) { - - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection, - state: options.state, - wrapX: options.wrapX - }); - - /** - * @private - * @type {boolean} - */ - this.opaque_ = options.opaque !== undefined ? options.opaque : false; - - /** - * @private - * @type {number} - */ - this.tilePixelRatio_ = options.tilePixelRatio !== undefined ? - options.tilePixelRatio : 1; - - /** - * @protected - * @type {ol.tilegrid.TileGrid} - */ - this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null; - - /** - * @protected - * @type {ol.TileCache} - */ - this.tileCache = new ol.TileCache(options.cacheSize); - - /** - * @protected - * @type {ol.Size} - */ - this.tmpSize = [0, 0]; - +ol.color.asArray = function(color) { + if (goog.isArray(color)) { + return color; + } else { + goog.asserts.assert(goog.isString(color), 'Color should be a string'); + return ol.color.fromString(color); + } }; -goog.inherits(ol.source.Tile, ol.source.Source); /** - * @return {boolean} Can expire cache. + * Return the color as an rgba string. + * @param {ol.Color|string} color Color. + * @return {string} Rgba string. + * @api */ -ol.source.Tile.prototype.canExpireCache = function() { - return this.tileCache.canExpireCache(); +ol.color.asString = function(color) { + if (goog.isString(color)) { + return color; + } else { + goog.asserts.assert(goog.isArray(color), 'Color should be an array'); + return ol.color.toString(color); + } }; /** - * @param {ol.proj.Projection} projection Projection. - * @param {Object.<string, ol.TileRange>} usedTiles Used tiles. + * @param {ol.Color} color1 Color1. + * @param {ol.Color} color2 Color2. + * @return {boolean} Equals. */ -ol.source.Tile.prototype.expireCache = function(projection, usedTiles) { - var tileCache = this.getTileCacheForProjection(projection); - if (tileCache) { - tileCache.expireCache(usedTiles); - } +ol.color.equals = function(color1, color2) { + return color1 === color2 || ( + color1[0] == color2[0] && color1[1] == color2[1] && + color1[2] == color2[2] && color1[3] == color2[3]); }; /** - * @param {ol.proj.Projection} projection Projection. - * @param {number} z Zoom level. - * @param {ol.TileRange} tileRange Tile range. - * @param {function(ol.Tile):(boolean|undefined)} callback Called with each - * loaded tile. If the callback returns `false`, the tile will not be - * considered loaded. - * @return {boolean} The tile range is fully covered with loaded tiles. + * @param {string} s String. + * @return {ol.Color} Color. */ -ol.source.Tile.prototype.forEachLoadedTile = - function(projection, z, tileRange, callback) { - var tileCache = this.getTileCacheForProjection(projection); - if (!tileCache) { - return false; - } +ol.color.fromString = ( + /** + * @return {function(string): ol.Color} + */ + function() { - var covered = true; - var tile, tileCoordKey, loaded; - for (var x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (var y = tileRange.minY; y <= tileRange.maxY; ++y) { - tileCoordKey = this.getKeyZXY(z, x, y); - loaded = false; - if (tileCache.containsKey(tileCoordKey)) { - tile = /** @type {!ol.Tile} */ (tileCache.get(tileCoordKey)); - loaded = tile.getState() === ol.TileState.LOADED; - if (loaded) { - loaded = (callback(tile) !== false); - } - } - if (!loaded) { - covered = false; - } + // We maintain a small cache of parsed strings. To provide cheap LRU-like + // semantics, whenever the cache grows too large we simply delete an + // arbitrary 25% of the entries. + + /** + * @const + * @type {number} + */ + var MAX_CACHE_SIZE = 1024; + + /** + * @type {Object.<string, ol.Color>} + */ + var cache = {}; + + /** + * @type {number} + */ + var cacheSize = 0; + + return ( + /** + * @param {string} s String. + * @return {ol.Color} Color. + */ + function(s) { + var color; + if (cache.hasOwnProperty(s)) { + color = cache[s]; + } else { + if (cacheSize >= MAX_CACHE_SIZE) { + var i = 0; + var key; + for (key in cache) { + if ((i++ & 3) === 0) { + delete cache[key]; + --cacheSize; + } + } + } + color = ol.color.fromStringInternal_(s); + cache[s] = color; + ++cacheSize; + } + return color; + }); + + })(); + + +/** + * @param {string} s String. + * @private + * @return {ol.Color} Color. + */ +ol.color.fromStringInternal_ = function(s) { + + var isHex = false; + if (ol.ENABLE_NAMED_COLORS && goog.color.names.hasOwnProperty(s)) { + s = goog.color.names[s]; + isHex = true; + } + + var r, g, b, a, color, match; + if (isHex || (match = ol.color.hexColorRe_.exec(s))) { // hex + var n = s.length - 1; // number of hex digits + goog.asserts.assert(n == 3 || n == 6, + 'Color string length should be 3 or 6'); + var d = n == 3 ? 1 : 2; // number of digits per channel + r = parseInt(s.substr(1 + 0 * d, d), 16); + g = parseInt(s.substr(1 + 1 * d, d), 16); + b = parseInt(s.substr(1 + 2 * d, d), 16); + if (d == 1) { + r = (r << 4) + r; + g = (g << 4) + g; + b = (b << 4) + b; } + a = 1; + color = [r, g, b, a]; + goog.asserts.assert(ol.color.isValid(color), + 'Color should be a valid color'); + return color; + } else if ((match = ol.color.rgbaColorRe_.exec(s))) { // rgba() + r = Number(match[1]); + g = Number(match[2]); + b = Number(match[3]); + a = Number(match[4]); + color = [r, g, b, a]; + return ol.color.normalize(color, color); + } else if ((match = ol.color.rgbColorRe_.exec(s))) { // rgb() + r = Number(match[1]); + g = Number(match[2]); + b = Number(match[3]); + color = [r, g, b, 1]; + return ol.color.normalize(color, color); + } else { + goog.asserts.fail(s + ' is not a valid color'); } - return covered; + }; /** - * @return {number} Gutter. + * @param {ol.Color} color Color. + * @return {boolean} Is valid. */ -ol.source.Tile.prototype.getGutter = function() { - return 0; +ol.color.isValid = function(color) { + return 0 <= color[0] && color[0] < 256 && + 0 <= color[1] && color[1] < 256 && + 0 <= color[2] && color[2] < 256 && + 0 <= color[3] && color[3] <= 1; }; /** - * Return the "parameters" key, a string composed of the source's - * parameters/dimensions. - * @return {string} The parameters key. - * @protected + * @param {ol.Color} color Color. + * @param {ol.Color=} opt_color Color. + * @return {ol.Color} Clamped color. */ -ol.source.Tile.prototype.getKeyParams = function() { - return ''; +ol.color.normalize = function(color, opt_color) { + var result = opt_color || []; + result[0] = ol.math.clamp((color[0] + 0.5) | 0, 0, 255); + result[1] = ol.math.clamp((color[1] + 0.5) | 0, 0, 255); + result[2] = ol.math.clamp((color[2] + 0.5) | 0, 0, 255); + result[3] = ol.math.clamp(color[3], 0, 1); + return result; }; /** - * @param {number} z Z. - * @param {number} x X. - * @param {number} y Y. - * @return {string} Key. - * @protected + * @param {ol.Color} color Color. + * @return {string} String. */ -ol.source.Tile.prototype.getKeyZXY = ol.tilecoord.getKeyZXY; +ol.color.toString = function(color) { + var r = color[0]; + if (r != (r | 0)) { + r = (r + 0.5) | 0; + } + var g = color[1]; + if (g != (g | 0)) { + g = (g + 0.5) | 0; + } + var b = color[2]; + if (b != (b | 0)) { + b = (b + 0.5) | 0; + } + var a = color[3]; + return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; +}; /** - * @return {boolean} Opaque. + * @param {!ol.Color} color Color. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {!ol.Color=} opt_color Color. + * @return {ol.Color} Transformed color. */ -ol.source.Tile.prototype.getOpaque = function() { - return this.opaque_; +ol.color.transform = function(color, transform, opt_color) { + var result = opt_color ? opt_color : []; + result = goog.vec.Mat4.multVec3(transform, color, result); + goog.asserts.assert(goog.isArray(result), 'result should be an array'); + result[3] = color[3]; + return ol.color.normalize(result, result); }; /** - * @inheritDoc + * @param {ol.Color|string} color1 Color2. + * @param {ol.Color|string} color2 Color2. + * @return {boolean} Equals. */ -ol.source.Tile.prototype.getResolutions = function() { - return this.tileGrid.getResolutions(); +ol.color.stringOrColorEquals = function(color1, color2) { + if (color1 === color2 || color1 == color2) { + return true; + } + if (goog.isString(color1)) { + color1 = ol.color.fromString(color1); + } + if (goog.isString(color2)) { + color2 = ol.color.fromString(color2); + } + return ol.color.equals(color1, color2); }; +goog.provide('ol.webgl'); +goog.provide('ol.webgl.WebGLContextEventType'); + /** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {!ol.Tile} Tile. + * @const + * @private + * @type {Array.<string>} */ -ol.source.Tile.prototype.getTile = goog.abstractMethod; +ol.webgl.CONTEXT_IDS_ = [ + 'experimental-webgl', + 'webgl', + 'webkit-3d', + 'moz-webgl' +]; /** - * Return the tile grid of the tile source. - * @return {ol.tilegrid.TileGrid} Tile grid. - * @api stable + * @enum {string} */ -ol.source.Tile.prototype.getTileGrid = function() { - return this.tileGrid; +ol.webgl.WebGLContextEventType = { + LOST: 'webglcontextlost', + RESTORED: 'webglcontextrestored' }; /** - * @param {ol.proj.Projection} projection Projection. - * @return {ol.tilegrid.TileGrid} Tile grid. + * @param {HTMLCanvasElement} canvas Canvas. + * @param {Object=} opt_attributes Attributes. + * @return {WebGLRenderingContext} WebGL rendering context. */ -ol.source.Tile.prototype.getTileGridForProjection = function(projection) { - if (!this.tileGrid) { - return ol.tilegrid.getForProjection(projection); - } else { - return this.tileGrid; +ol.webgl.getContext = function(canvas, opt_attributes) { + var context, i, ii = ol.webgl.CONTEXT_IDS_.length; + for (i = 0; i < ii; ++i) { + try { + context = canvas.getContext(ol.webgl.CONTEXT_IDS_[i], opt_attributes); + if (context) { + return /** @type {!WebGLRenderingContext} */ (context); + } + } catch (e) { + } } + return null; }; +goog.provide('ol.has'); + +goog.require('goog.dom'); +goog.require('ol'); +goog.require('ol.dom'); +goog.require('ol.webgl'); + /** - * @param {ol.proj.Projection} projection Projection. - * @return {ol.TileCache} Tile cache. - * @protected + * The ratio between physical pixels and device-independent pixels + * (dips) on the device (`window.devicePixelRatio`). + * @const + * @type {number} + * @api stable */ -ol.source.Tile.prototype.getTileCacheForProjection = function(projection) { - var thisProj = this.getProjection(); - if (thisProj && !ol.proj.equivalent(thisProj, projection)) { - return null; - } else { - return this.tileCache; - } -}; +ol.has.DEVICE_PIXEL_RATIO = goog.global.devicePixelRatio || 1; /** - * @return {number} Tile pixel ratio. + * True if the browser's Canvas implementation implements {get,set}LineDash. + * @type {boolean} */ -ol.source.Tile.prototype.getTilePixelRatio = function() { - return this.tilePixelRatio_; -}; +ol.has.CANVAS_LINE_DASH = false; /** - * @param {number} z Z. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.Size} Tile size. + * True if both the library and browser support Canvas. Always `false` + * if `ol.ENABLE_CANVAS` is set to `false` at compile time. + * @const + * @type {boolean} + * @api stable */ -ol.source.Tile.prototype.getTilePixelSize = - function(z, pixelRatio, projection) { - var tileGrid = this.getTileGridForProjection(projection); - return ol.size.scale(ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize), - this.tilePixelRatio_, this.tmpSize); -}; +ol.has.CANVAS = ol.ENABLE_CANVAS && ( + /** + * @return {boolean} Canvas supported. + */ + function() { + if (!('HTMLCanvasElement' in goog.global)) { + return false; + } + try { + var context = ol.dom.createCanvasContext2D(); + if (!context) { + return false; + } else { + if (context.setLineDash !== undefined) { + ol.has.CANVAS_LINE_DASH = true; + } + return true; + } + } catch (e) { + return false; + } + })(); /** - * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate - * is outside the resolution and extent range of the tile grid, `null` will be - * returned. - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.proj.Projection=} opt_projection Projection. - * @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or - * null if no tile URL should be created for the passed `tileCoord`. + * Indicates if DeviceOrientation is supported in the user's browser. + * @const + * @type {boolean} + * @api stable */ -ol.source.Tile.prototype.getTileCoordForTileUrlFunction = - function(tileCoord, opt_projection) { - var projection = opt_projection !== undefined ? - opt_projection : this.getProjection(); - var tileGrid = this.getTileGridForProjection(projection); - goog.asserts.assert(tileGrid, 'tile grid needed'); - if (this.getWrapX() && projection.isGlobal()) { - tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection); - } - return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null; -}; +ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in goog.global; /** - * Marks a tile coord as being used, without triggering a load. - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {ol.proj.Projection} projection Projection. + * True if `ol.ENABLE_DOM` is set to `true` at compile time. + * @const + * @type {boolean} */ -ol.source.Tile.prototype.useTile = ol.nullFunction; - +ol.has.DOM = ol.ENABLE_DOM; /** - * @classdesc - * Events emitted by {@link ol.source.Tile} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.TileEvent} - * @param {string} type Type. - * @param {ol.Tile} tile The tile. + * Is HTML5 geolocation supported in the current browser? + * @const + * @type {boolean} + * @api stable */ -ol.source.TileEvent = function(type, tile) { - - goog.base(this, type); +ol.has.GEOLOCATION = 'geolocation' in goog.global.navigator; - /** - * The tile related to the event. - * @type {ol.Tile} - * @api - */ - this.tile = tile; -}; -goog.inherits(ol.source.TileEvent, goog.events.Event); +/** + * True if browser supports touch events. + * @const + * @type {boolean} + * @api stable + */ +ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in goog.global; /** - * @enum {string} + * True if browser supports pointer events. + * @const + * @type {boolean} */ -ol.source.TileEventType = { +ol.has.POINTER = 'PointerEvent' in goog.global; - /** - * Triggered when a tile starts loading. - * @event ol.source.TileEvent#tileloadstart - * @api stable - */ - TILELOADSTART: 'tileloadstart', - /** - * Triggered when a tile finishes loading. - * @event ol.source.TileEvent#tileloadend - * @api stable - */ - TILELOADEND: 'tileloadend', +/** + * True if browser supports ms pointer events (IE 10). + * @const + * @type {boolean} + */ +ol.has.MSPOINTER = !!(goog.global.navigator.msPointerEnabled); - /** - * Triggered if tile loading results in an error. - * @event ol.source.TileEvent#tileloaderror - * @api stable - */ - TILELOADERROR: 'tileloaderror' -}; +/** + * True if both OpenLayers and browser support WebGL. Always `false` + * if `ol.ENABLE_WEBGL` is set to `false` at compile time. + * @const + * @type {boolean} + * @api stable + */ +ol.has.WEBGL; -// FIXME handle date line wrap -goog.provide('ol.control.Attribution'); +(function() { + if (ol.ENABLE_WEBGL) { + var hasWebGL = false; + var textureSize; + var /** @type {Array.<string>} */ extensions = []; -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Attribution'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.source.Tile'); + if ('WebGLRenderingContext' in goog.global) { + try { + var canvas = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + var gl = ol.webgl.getContext(canvas, { + failIfMajorPerformanceCaveat: true + }); + if (gl) { + hasWebGL = true; + textureSize = /** @type {number} */ + (gl.getParameter(gl.MAX_TEXTURE_SIZE)); + extensions = gl.getSupportedExtensions(); + } + } catch (e) {} + } + ol.has.WEBGL = hasWebGL; + ol.WEBGL_EXTENSIONS = extensions; + ol.WEBGL_MAX_TEXTURE_SIZE = textureSize; + } +})(); +goog.provide('ol.render.canvas'); /** - * @classdesc - * Control to show all the attributions associated with the layer sources - * in the map. This control is one of the default controls included in maps. - * By default it will show in the bottom right portion of the map, but this can - * be changed by using a css selector for `.ol-attribution`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.AttributionOptions=} opt_options Attribution options. - * @api stable + * @typedef {{fillStyle: string}} */ -ol.control.Attribution = function(opt_options) { - - var options = opt_options ? opt_options : {}; +ol.render.canvas.FillState; - /** - * @private - * @type {Element} - */ - this.ulElement_ = goog.dom.createElement('UL'); - /** - * @private - * @type {Element} - */ - this.logoLi_ = goog.dom.createElement('LI'); +/** + * @typedef {{lineCap: string, + * lineDash: Array.<number>, + * lineJoin: string, + * lineWidth: number, + * miterLimit: number, + * strokeStyle: string}} + */ +ol.render.canvas.StrokeState; - this.ulElement_.appendChild(this.logoLi_); - goog.style.setElementShown(this.logoLi_, false); - /** - * @private - * @type {boolean} - */ - this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true; +/** + * @typedef {{font: string, + * textAlign: string, + * textBaseline: string}} + */ +ol.render.canvas.TextState; - /** - * @private - * @type {boolean} - */ - this.collapsible_ = options.collapsible !== undefined ? - options.collapsible : true; - if (!this.collapsible_) { - this.collapsed_ = false; - } +/** + * @const + * @type {string} + */ +ol.render.canvas.defaultFont = '10px sans-serif'; - var className = options.className ? options.className : 'ol-attribution'; - var tipLabel = options.tipLabel ? options.tipLabel : 'Attributions'; - - var collapseLabel = options.collapseLabel ? options.collapseLabel : '\u00BB'; - - /** - * @private - * @type {Node} - */ - this.collapseLabel_ = goog.isString(collapseLabel) ? - goog.dom.createDom('SPAN', {}, collapseLabel) : - collapseLabel; - - var label = options.label ? options.label : 'i'; - - /** - * @private - * @type {Node} - */ - this.label_ = goog.isString(label) ? - goog.dom.createDom('SPAN', {}, label) : - label; - - var activeLabel = (this.collapsible_ && !this.collapsed_) ? - this.collapseLabel_ : this.label_; - var button = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'title': tipLabel - }, activeLabel); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - - goog.events.listen(button, [ - goog.events.EventType.MOUSEOUT, - goog.events.EventType.FOCUSOUT - ], function() { - this.blur(); - }, false); +/** + * @const + * @type {ol.Color} + */ +ol.render.canvas.defaultFillStyle = [0, 0, 0, 1]; - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL + - (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') + - (this.collapsible_ ? '' : ' ol-uncollapsible'); - var element = goog.dom.createDom('DIV', - cssClasses, this.ulElement_, button); - var render = options.render ? options.render : ol.control.Attribution.render; +/** + * @const + * @type {string} + */ +ol.render.canvas.defaultLineCap = 'round'; - goog.base(this, { - element: element, - render: render, - target: options.target - }); - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; +/** + * @const + * @type {Array.<number>} + */ +ol.render.canvas.defaultLineDash = []; - /** - * @private - * @type {Object.<string, Element>} - */ - this.attributionElements_ = {}; - /** - * @private - * @type {Object.<string, boolean>} - */ - this.attributionElementRenderedVisible_ = {}; +/** + * @const + * @type {string} + */ +ol.render.canvas.defaultLineJoin = 'round'; - /** - * @private - * @type {Object.<string, Element>} - */ - this.logoElements_ = {}; -}; -goog.inherits(ol.control.Attribution, ol.control.Control); +/** + * @const + * @type {number} + */ +ol.render.canvas.defaultMiterLimit = 10; /** - * @param {?olx.FrameState} frameState Frame state. - * @return {Array.<Object.<string, ol.Attribution>>} Attributions. + * @const + * @type {ol.Color} */ -ol.control.Attribution.prototype.getSourceAttributions = function(frameState) { - var i, ii, j, jj, tileRanges, source, sourceAttribution, - sourceAttributionKey, sourceAttributions, sourceKey; - var intersectsTileRange; - var layerStatesArray = frameState.layerStatesArray; - /** @type {Object.<string, ol.Attribution>} */ - var attributions = goog.object.clone(frameState.attributions); - /** @type {Object.<string, ol.Attribution>} */ - var hiddenAttributions = {}; - var projection = frameState.viewState.projection; - goog.asserts.assert(projection, 'projection of viewState required'); - for (i = 0, ii = layerStatesArray.length; i < ii; i++) { - source = layerStatesArray[i].layer.getSource(); - if (!source) { - continue; - } - sourceKey = goog.getUid(source).toString(); - sourceAttributions = source.getAttributions(); - if (!sourceAttributions) { - continue; - } - for (j = 0, jj = sourceAttributions.length; j < jj; j++) { - sourceAttribution = sourceAttributions[j]; - sourceAttributionKey = goog.getUid(sourceAttribution).toString(); - if (sourceAttributionKey in attributions) { - continue; - } - tileRanges = frameState.usedTiles[sourceKey]; - if (tileRanges) { - goog.asserts.assertInstanceof(source, ol.source.Tile, - 'source should be an ol.source.Tile'); - var tileGrid = source.getTileGridForProjection(projection); - goog.asserts.assert(tileGrid, 'tileGrid required for projection'); - intersectsTileRange = sourceAttribution.intersectsAnyTileRange( - tileRanges, tileGrid, projection); - } else { - intersectsTileRange = false; - } - if (intersectsTileRange) { - if (sourceAttributionKey in hiddenAttributions) { - delete hiddenAttributions[sourceAttributionKey]; - } - attributions[sourceAttributionKey] = sourceAttribution; - } else { - hiddenAttributions[sourceAttributionKey] = sourceAttribution; - } - } - } - return [attributions, hiddenAttributions]; -}; +ol.render.canvas.defaultStrokeStyle = [0, 0, 0, 1]; /** - * Update the attribution element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.Attribution} - * @api + * @const + * @type {string} */ -ol.control.Attribution.render = function(mapEvent) { - this.updateElement_(mapEvent.frameState); -}; +ol.render.canvas.defaultTextAlign = 'center'; /** - * @private - * @param {?olx.FrameState} frameState Frame state. + * @const + * @type {string} */ -ol.control.Attribution.prototype.updateElement_ = function(frameState) { +ol.render.canvas.defaultTextBaseline = 'middle'; - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.element, false); - this.renderedVisible_ = false; - } - return; - } - var attributions = this.getSourceAttributions(frameState); - /** @type {Object.<string, ol.Attribution>} */ - var visibleAttributions = attributions[0]; - /** @type {Object.<string, ol.Attribution>} */ - var hiddenAttributions = attributions[1]; +/** + * @const + * @type {number} + */ +ol.render.canvas.defaultLineWidth = 1; - var attributionElement, attributionKey; - for (attributionKey in this.attributionElements_) { - if (attributionKey in visibleAttributions) { - if (!this.attributionElementRenderedVisible_[attributionKey]) { - goog.style.setElementShown( - this.attributionElements_[attributionKey], true); - this.attributionElementRenderedVisible_[attributionKey] = true; - } - delete visibleAttributions[attributionKey]; - } - else if (attributionKey in hiddenAttributions) { - if (this.attributionElementRenderedVisible_[attributionKey]) { - goog.style.setElementShown( - this.attributionElements_[attributionKey], false); - delete this.attributionElementRenderedVisible_[attributionKey]; - } - delete hiddenAttributions[attributionKey]; - } - else { - goog.dom.removeNode(this.attributionElements_[attributionKey]); - delete this.attributionElements_[attributionKey]; - delete this.attributionElementRenderedVisible_[attributionKey]; - } - } - for (attributionKey in visibleAttributions) { - attributionElement = goog.dom.createElement('LI'); - attributionElement.innerHTML = - visibleAttributions[attributionKey].getHTML(); - this.ulElement_.appendChild(attributionElement); - this.attributionElements_[attributionKey] = attributionElement; - this.attributionElementRenderedVisible_[attributionKey] = true; - } - for (attributionKey in hiddenAttributions) { - attributionElement = goog.dom.createElement('LI'); - attributionElement.innerHTML = - hiddenAttributions[attributionKey].getHTML(); - goog.style.setElementShown(attributionElement, false); - this.ulElement_.appendChild(attributionElement); - this.attributionElements_[attributionKey] = attributionElement; - } +goog.provide('ol.structs.IHasChecksum'); - var renderVisible = - !goog.object.isEmpty(this.attributionElementRenderedVisible_) || - !goog.object.isEmpty(frameState.logos); - if (this.renderedVisible_ != renderVisible) { - goog.style.setElementShown(this.element, renderVisible); - this.renderedVisible_ = renderVisible; - } - if (renderVisible && - goog.object.isEmpty(this.attributionElementRenderedVisible_)) { - goog.dom.classlist.add(this.element, 'ol-logo-only'); - } else { - goog.dom.classlist.remove(this.element, 'ol-logo-only'); - } - this.insertLogos_(frameState); +/** + * @interface + */ +ol.structs.IHasChecksum = function() { }; /** - * @param {?olx.FrameState} frameState Frame state. - * @private + * @return {string} The checksum. */ -ol.control.Attribution.prototype.insertLogos_ = function(frameState) { - - var logo; - var logos = frameState.logos; - var logoElements = this.logoElements_; - - for (logo in logoElements) { - if (!(logo in logos)) { - goog.dom.removeNode(logoElements[logo]); - delete logoElements[logo]; - } - } +ol.structs.IHasChecksum.prototype.getChecksum = function() { +}; - var image, logoElement, logoKey; - for (logoKey in logos) { - if (!(logoKey in logoElements)) { - image = new Image(); - image.src = logoKey; - var logoValue = logos[logoKey]; - if (logoValue === '') { - logoElement = image; - } else { - logoElement = goog.dom.createDom('A', { - 'href': logoValue - }); - logoElement.appendChild(image); - } - this.logoLi_.appendChild(logoElement); - logoElements[logoKey] = logoElement; - } - } +goog.provide('ol.style.Fill'); - goog.style.setElementShown(this.logoLi_, !goog.object.isEmpty(logos)); +goog.require('ol.color'); +goog.require('ol.structs.IHasChecksum'); -}; /** - * @param {goog.events.BrowserEvent} event The event to handle - * @private + * @classdesc + * Set fill style for vector features. + * + * @constructor + * @param {olx.style.FillOptions=} opt_options Options. + * @implements {ol.structs.IHasChecksum} + * @api */ -ol.control.Attribution.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleToggle_(); -}; +ol.style.Fill = function(opt_options) { + var options = opt_options || {}; -/** - * @private - */ -ol.control.Attribution.prototype.handleToggle_ = function() { - goog.dom.classlist.toggle(this.element, 'ol-collapsed'); - if (this.collapsed_) { - goog.dom.replaceNode(this.collapseLabel_, this.label_); - } else { - goog.dom.replaceNode(this.label_, this.collapseLabel_); - } - this.collapsed_ = !this.collapsed_; + /** + * @private + * @type {ol.Color|string} + */ + this.color_ = options.color !== undefined ? options.color : null; + + /** + * @private + * @type {string|undefined} + */ + this.checksum_ = undefined; }; /** - * Return `true` if the attribution is collapsible, `false` otherwise. - * @return {boolean} True if the widget is collapsible. - * @api stable + * Get the fill color. + * @return {ol.Color|string} Color. + * @api */ -ol.control.Attribution.prototype.getCollapsible = function() { - return this.collapsible_; +ol.style.Fill.prototype.getColor = function() { + return this.color_; }; /** - * Set whether the attribution should be collapsible. - * @param {boolean} collapsible True if the widget is collapsible. - * @api stable + * Set the color. + * + * @param {ol.Color|string} color Color. + * @api */ -ol.control.Attribution.prototype.setCollapsible = function(collapsible) { - if (this.collapsible_ === collapsible) { - return; - } - this.collapsible_ = collapsible; - goog.dom.classlist.toggle(this.element, 'ol-uncollapsible'); - if (!collapsible && this.collapsed_) { - this.handleToggle_(); - } +ol.style.Fill.prototype.setColor = function(color) { + this.color_ = color; + this.checksum_ = undefined; }; /** - * Collapse or expand the attribution according to the passed parameter. Will - * not do anything if the attribution isn't collapsible or if the current - * collapsed state is already the one requested. - * @param {boolean} collapsed True if the widget is collapsed. - * @api stable + * @inheritDoc */ -ol.control.Attribution.prototype.setCollapsed = function(collapsed) { - if (!this.collapsible_ || this.collapsed_ === collapsed) { - return; +ol.style.Fill.prototype.getChecksum = function() { + if (this.checksum_ === undefined) { + this.checksum_ = 'f' + (this.color_ ? + ol.color.asString(this.color_) : '-'); } - this.handleToggle_(); + + return this.checksum_; }; +goog.provide('ol.style.Image'); +goog.provide('ol.style.ImageState'); + /** - * Return `true` when the attribution is currently collapsed or `false` - * otherwise. - * @return {boolean} True if the widget is collapsed. - * @api stable + * @enum {number} */ -ol.control.Attribution.prototype.getCollapsed = function() { - return this.collapsed_; +ol.style.ImageState = { + IDLE: 0, + LOADING: 1, + LOADED: 2, + ERROR: 3 }; -goog.provide('ol.control.Rotate'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol'); -goog.require('ol.animation'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.easing'); +/** + * @typedef {{opacity: number, + * rotateWithView: boolean, + * rotation: number, + * scale: number, + * snapToPixel: boolean}} + */ +ol.style.ImageOptions; /** * @classdesc - * A button control to reset rotation to 0. - * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css - * selector is added to the button when the rotation is 0. + * A base class used for creating subclasses and not instantiated in + * apps. Base class for {@link ol.style.Icon} and {@link ol.style.Circle}. * * @constructor - * @extends {ol.control.Control} - * @param {olx.control.RotateOptions=} opt_options Rotate options. - * @api stable + * @param {ol.style.ImageOptions} options Options. + * @api */ -ol.control.Rotate = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var className = options.className ? - options.className : 'ol-rotate'; - - var label = options.label ? options.label : '\u21E7'; +ol.style.Image = function(options) { /** - * @type {Element} * @private + * @type {number} */ - this.label_ = null; - - if (goog.isString(label)) { - this.label_ = goog.dom.createDom('SPAN', - 'ol-compass', label); - } else { - this.label_ = label; - goog.dom.classlist.add(this.label_, 'ol-compass'); - } - - var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation'; - - var button = goog.dom.createDom('BUTTON', { - 'class': className + '-reset', - 'type' : 'button', - 'title': tipLabel - }, this.label_); - - goog.events.listen(button, goog.events.EventType.CLICK, - ol.control.Rotate.prototype.handleClick_, false, this); - - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL; - var element = goog.dom.createDom('DIV', cssClasses, button); - - var render = options.render ? options.render : ol.control.Rotate.render; - - this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined; + this.opacity_ = options.opacity; - goog.base(this, { - element: element, - render: render, - target: options.target - }); + /** + * @private + * @type {boolean} + */ + this.rotateWithView_ = options.rotateWithView; /** - * @type {number} * @private + * @type {number} */ - this.duration_ = options.duration !== undefined ? options.duration : 250; + this.rotation_ = options.rotation; /** - * @type {boolean} * @private + * @type {number} */ - this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true; + this.scale_ = options.scale; /** * @private - * @type {number|undefined} + * @type {boolean} */ - this.rotation_ = undefined; + this.snapToPixel_ = options.snapToPixel; - if (this.autoHide_) { - goog.dom.classlist.add(this.element, ol.css.CLASS_HIDDEN); - } +}; + +/** + * Get the symbolizer opacity. + * @return {number} Opacity. + * @api + */ +ol.style.Image.prototype.getOpacity = function() { + return this.opacity_; }; -goog.inherits(ol.control.Rotate, ol.control.Control); /** - * @param {goog.events.BrowserEvent} event The event to handle - * @private + * Determine whether the symbolizer rotates with the map. + * @return {boolean} Rotate with map. + * @api */ -ol.control.Rotate.prototype.handleClick_ = function(event) { - event.preventDefault(); - if (this.callResetNorth_ !== undefined) { - this.callResetNorth_(); - } else { - this.resetNorth_(); - } +ol.style.Image.prototype.getRotateWithView = function() { + return this.rotateWithView_; }; /** - * @private + * Get the symoblizer rotation. + * @return {number} Rotation. + * @api */ -ol.control.Rotate.prototype.resetNorth_ = function() { - var map = this.getMap(); - var view = map.getView(); - if (!view) { - // the map does not have a view, so we can't act - // upon it - return; - } - var currentRotation = view.getRotation(); - if (currentRotation !== undefined) { - if (this.duration_ > 0) { - currentRotation = currentRotation % (2 * Math.PI); - if (currentRotation < -Math.PI) { - currentRotation += 2 * Math.PI; - } - if (currentRotation > Math.PI) { - currentRotation -= 2 * Math.PI; - } - map.beforeRender(ol.animation.rotate({ - rotation: currentRotation, - duration: this.duration_, - easing: ol.easing.easeOut - })); - } - view.setRotation(0); - } +ol.style.Image.prototype.getRotation = function() { + return this.rotation_; }; /** - * Update the rotate control element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.Rotate} + * Get the symbolizer scale. + * @return {number} Scale. * @api */ -ol.control.Rotate.render = function(mapEvent) { - var frameState = mapEvent.frameState; - if (!frameState) { - return; - } - var rotation = frameState.viewState.rotation; - if (rotation != this.rotation_) { - var transform = 'rotate(' + rotation + 'rad)'; - if (this.autoHide_) { - goog.dom.classlist.enable( - this.element, ol.css.CLASS_HIDDEN, rotation === 0); - } - this.label_.style.msTransform = transform; - this.label_.style.webkitTransform = transform; - this.label_.style.transform = transform; - } - this.rotation_ = rotation; +ol.style.Image.prototype.getScale = function() { + return this.scale_; }; -goog.provide('ol.control.Zoom'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.animation'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.easing'); +/** + * Determine whether the symbolizer should be snapped to a pixel. + * @return {boolean} The symbolizer should snap to a pixel. + * @api + */ +ol.style.Image.prototype.getSnapToPixel = function() { + return this.snapToPixel_; +}; + +/** + * Get the anchor point. The anchor determines the center point for the + * symbolizer. Its units are determined by `anchorXUnits` and `anchorYUnits`. + * @function + * @return {Array.<number>} Anchor. + */ +ol.style.Image.prototype.getAnchor = goog.abstractMethod; /** - * @classdesc - * A control with 2 buttons, one for zoom in and one for zoom out. - * This control is one of the default controls of a map. To style this control - * use css selectors `.ol-zoom-in` and `.ol-zoom-out`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ZoomOptions=} opt_options Zoom options. - * @api stable + * Get the image element for the symbolizer. + * @function + * @param {number} pixelRatio Pixel ratio. + * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element. */ -ol.control.Zoom = function(opt_options) { +ol.style.Image.prototype.getImage = goog.abstractMethod; - var options = opt_options ? opt_options : {}; - var className = options.className ? options.className : 'ol-zoom'; +/** + * @param {number} pixelRatio Pixel ratio. + * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element. + */ +ol.style.Image.prototype.getHitDetectionImage = goog.abstractMethod; - var delta = options.delta ? options.delta : 1; - var zoomInLabel = options.zoomInLabel ? options.zoomInLabel : '+'; - var zoomOutLabel = options.zoomOutLabel ? options.zoomOutLabel : '\u2212'; +/** + * @return {ol.style.ImageState} Image state. + */ +ol.style.Image.prototype.getImageState = goog.abstractMethod; - var zoomInTipLabel = options.zoomInTipLabel ? - options.zoomInTipLabel : 'Zoom in'; - var zoomOutTipLabel = options.zoomOutTipLabel ? - options.zoomOutTipLabel : 'Zoom out'; - var inElement = goog.dom.createDom('BUTTON', { - 'class': className + '-in', - 'type' : 'button', - 'title': zoomInTipLabel - }, zoomInLabel); +/** + * @return {ol.Size} Image size. + */ +ol.style.Image.prototype.getImageSize = goog.abstractMethod; - goog.events.listen(inElement, - goog.events.EventType.CLICK, goog.partial( - ol.control.Zoom.prototype.handleClick_, delta), false, this); - var outElement = goog.dom.createDom('BUTTON', { - 'class': className + '-out', - 'type' : 'button', - 'title': zoomOutTipLabel - }, zoomOutLabel); +/** + * @return {ol.Size} Size of the hit-detection image. + */ +ol.style.Image.prototype.getHitDetectionImageSize = goog.abstractMethod; - goog.events.listen(outElement, - goog.events.EventType.CLICK, goog.partial( - ol.control.Zoom.prototype.handleClick_, -delta), false, this); - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL; - var element = goog.dom.createDom('DIV', cssClasses, inElement, - outElement); +/** + * Get the origin of the symbolizer. + * @function + * @return {Array.<number>} Origin. + */ +ol.style.Image.prototype.getOrigin = goog.abstractMethod; - goog.base(this, { - element: element, - target: options.target - }); - /** - * @type {number} - * @private - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; +/** + * Get the size of the symbolizer (in pixels). + * @function + * @return {ol.Size} Size. + */ +ol.style.Image.prototype.getSize = goog.abstractMethod; + +/** + * Set the opacity. + * + * @param {number} opacity Opacity. + * @api + */ +ol.style.Image.prototype.setOpacity = function(opacity) { + this.opacity_ = opacity; }; -goog.inherits(ol.control.Zoom, ol.control.Control); /** - * @param {number} delta Zoom delta. - * @param {goog.events.BrowserEvent} event The event to handle - * @private + * Set whether to rotate the style with the view. + * + * @param {boolean} rotateWithView Rotate with map. */ -ol.control.Zoom.prototype.handleClick_ = function(delta, event) { - event.preventDefault(); - this.zoomByDelta_(delta); +ol.style.Image.prototype.setRotateWithView = function(rotateWithView) { + this.rotateWithView_ = rotateWithView; }; /** - * @param {number} delta Zoom delta. - * @private + * Set the rotation. + * + * @param {number} rotation Rotation. + * @api */ -ol.control.Zoom.prototype.zoomByDelta_ = function(delta) { - var map = this.getMap(); - var view = map.getView(); - if (!view) { - // the map does not have a view, so we can't act - // upon it - return; - } - var currentResolution = view.getResolution(); - if (currentResolution) { - if (this.duration_ > 0) { - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: this.duration_, - easing: ol.easing.easeOut - })); - } - var newResolution = view.constrainResolution(currentResolution, delta); - view.setResolution(newResolution); - } +ol.style.Image.prototype.setRotation = function(rotation) { + this.rotation_ = rotation; }; -goog.provide('ol.control'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.control.Attribution'); -goog.require('ol.control.Rotate'); -goog.require('ol.control.Zoom'); +/** + * Set the scale. + * + * @param {number} scale Scale. + * @api + */ +ol.style.Image.prototype.setScale = function(scale) { + this.scale_ = scale; +}; /** - * Set of controls included in maps by default. Unless configured otherwise, - * this returns a collection containing an instance of each of the following - * controls: - * * {@link ol.control.Zoom} - * * {@link ol.control.Rotate} - * * {@link ol.control.Attribution} + * Set whether to snap the image to the closest pixel. * - * @param {olx.control.DefaultsOptions=} opt_options Defaults options. - * @return {ol.Collection.<ol.control.Control>} Controls. - * @api stable + * @param {boolean} snapToPixel Snap to pixel? */ -ol.control.defaults = function(opt_options) { - - var options = opt_options ? opt_options : {}; +ol.style.Image.prototype.setSnapToPixel = function(snapToPixel) { + this.snapToPixel_ = snapToPixel; +}; - var controls = new ol.Collection(); - var zoomControl = options.zoom !== undefined ? options.zoom : true; - if (zoomControl) { - controls.push(new ol.control.Zoom(options.zoomOptions)); - } +/** + * @param {function(this: T, goog.events.Event)} listener Listener function. + * @param {T} thisArg Value to use as `this` when executing `listener`. + * @return {goog.events.Key|undefined} Listener key. + * @template T + */ +ol.style.Image.prototype.listenImageChange = goog.abstractMethod; - var rotateControl = options.rotate !== undefined ? options.rotate : true; - if (rotateControl) { - controls.push(new ol.control.Rotate(options.rotateOptions)); - } - var attributionControl = options.attribution !== undefined ? - options.attribution : true; - if (attributionControl) { - controls.push(new ol.control.Attribution(options.attributionOptions)); - } +/** + * Load not yet loaded URI. + */ +ol.style.Image.prototype.load = goog.abstractMethod; - return controls; -}; +/** + * @param {function(this: T, goog.events.Event)} listener Listener function. + * @param {T} thisArg Value to use as `this` when executing `listener`. + * @template T + */ +ol.style.Image.prototype.unlistenImageChange = goog.abstractMethod; -// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// Copyright 2008 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -40867,5919 +40054,6043 @@ ol.control.defaults = function(opt_options) { // limitations under the License. /** - * @fileoverview Functions for managing full screen status of the DOM. - * + * @fileoverview Namespace with crypto related helper functions. */ -goog.provide('goog.dom.fullscreen'); -goog.provide('goog.dom.fullscreen.EventType'); +goog.provide('goog.crypt'); -goog.require('goog.dom'); -goog.require('goog.userAgent'); +goog.require('goog.array'); +goog.require('goog.asserts'); /** - * Event types for full screen. - * @enum {string} + * Turns a string into an array of bytes; a "byte" being a JS number in the + * range 0-255. + * @param {string} str String value to arrify. + * @return {!Array<number>} Array of numbers corresponding to the + * UCS character codes of each character in str. */ -goog.dom.fullscreen.EventType = { - /** Dispatched by the Document when the fullscreen status changes. */ - CHANGE: (function() { - if (goog.userAgent.WEBKIT) { - return 'webkitfullscreenchange'; - } - if (goog.userAgent.GECKO) { - return 'mozfullscreenchange'; - } - if (goog.userAgent.IE) { - return 'MSFullscreenChange'; +goog.crypt.stringToByteArray = function(str) { + var output = [], p = 0; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + while (c > 0xff) { + output[p++] = c & 0xff; + c >>= 8; } - // Opera 12-14, and W3C standard (Draft): - // https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html - return 'fullscreenchange'; - })() + output[p++] = c; + } + return output; }; /** - * Determines if full screen is supported. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {boolean} True iff full screen is supported. + * Turns an array of numbers into the string given by the concatenation of the + * characters to which the numbers correspond. + * @param {Array<number>} bytes Array of numbers representing characters. + * @return {string} Stringification of the array. */ -goog.dom.fullscreen.isSupported = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - var body = doc.body; - return !!(body.webkitRequestFullscreen || - (body.mozRequestFullScreen && doc.mozFullScreenEnabled) || - (body.msRequestFullscreen && doc.msFullscreenEnabled) || - (body.requestFullscreen && doc.fullscreenEnabled)); -}; +goog.crypt.byteArrayToString = function(bytes) { + var CHUNK_SIZE = 8192; + // Special-case the simple case for speed's sake. + if (bytes.length <= CHUNK_SIZE) { + return String.fromCharCode.apply(null, bytes); + } -/** - * Requests putting the element in full screen. - * @param {!Element} element The element to put full screen. - */ -goog.dom.fullscreen.requestFullScreen = function(element) { - if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else if (element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if (element.msRequestFullscreen) { - element.msRequestFullscreen(); - } else if (element.requestFullscreen) { - element.requestFullscreen(); + // The remaining logic splits conversion by chunks since + // Function#apply() has a maximum parameter count. + // See discussion: http://goo.gl/LrWmZ9 + + var str = ''; + for (var i = 0; i < bytes.length; i += CHUNK_SIZE) { + var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE); + str += String.fromCharCode.apply(null, chunk); } + return str; }; /** - * Requests putting the element in full screen with full keyboard access. - * @param {!Element} element The element to put full screen. + * Turns an array of numbers into the hex string given by the concatenation of + * the hex values to which the numbers correspond. + * @param {Uint8Array|Array<number>} array Array of numbers representing + * characters. + * @return {string} Hex string. */ -goog.dom.fullscreen.requestFullScreenWithKeys = function( - element) { - if (element.mozRequestFullScreenWithKeys) { - element.mozRequestFullScreenWithKeys(); - } else if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else { - goog.dom.fullscreen.requestFullScreen(element); - } +goog.crypt.byteArrayToHex = function(array) { + return goog.array.map(array, function(numByte) { + var hexByte = numByte.toString(16); + return hexByte.length > 1 ? hexByte : '0' + hexByte; + }).join(''); }; /** - * Exits full screen. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. + * Converts a hex string into an integer array. + * @param {string} hexString Hex string of 16-bit integers (two characters + * per integer). + * @return {!Array<number>} Array of {0,255} integers for the given string. */ -goog.dom.fullscreen.exitFullScreen = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - if (doc.webkitCancelFullScreen) { - doc.webkitCancelFullScreen(); - } else if (doc.mozCancelFullScreen) { - doc.mozCancelFullScreen(); - } else if (doc.msExitFullscreen) { - doc.msExitFullscreen(); - } else if (doc.exitFullscreen) { - doc.exitFullscreen(); +goog.crypt.hexToByteArray = function(hexString) { + goog.asserts.assert(hexString.length % 2 == 0, + 'Key string length must be multiple of 2'); + var arr = []; + for (var i = 0; i < hexString.length; i += 2) { + arr.push(parseInt(hexString.substring(i, i + 2), 16)); } + return arr; }; /** - * Determines if the document is full screen. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {boolean} Whether the document is full screen. + * Converts a JS string to a UTF-8 "byte" array. + * @param {string} str 16-bit unicode string. + * @return {!Array<number>} UTF-8 byte array. */ -goog.dom.fullscreen.isFullScreen = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - // IE 11 doesn't have similar boolean property, so check whether - // document.msFullscreenElement is null instead. - return !!(doc.webkitIsFullScreen || doc.mozFullScreen || - doc.msFullscreenElement || doc.fullscreenElement); +goog.crypt.stringToUtf8ByteArray = function(str) { + // TODO(user): Use native implementations if/when available + var out = [], p = 0; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + if (c < 128) { + out[p++] = c; + } else if (c < 2048) { + out[p++] = (c >> 6) | 192; + out[p++] = (c & 63) | 128; + } else { + out[p++] = (c >> 12) | 224; + out[p++] = ((c >> 6) & 63) | 128; + out[p++] = (c & 63) | 128; + } + } + return out; }; /** - * Get the root element in full screen mode. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {?Element} The root element in full screen mode. + * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode. + * @param {Uint8Array|Array<number>} bytes UTF-8 byte array. + * @return {string} 16-bit Unicode string. */ -goog.dom.fullscreen.getFullScreenElement = function(opt_domHelper) { - var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); - var element_list = [ - doc.webkitFullscreenElement, - doc.mozFullScreenElement, - doc.msFullscreenElement, - doc.fullscreenElement - ]; - for (var i = 0; i < element_list.length; i++) { - if (element_list[i] != null) { - return element_list[i]; +goog.crypt.utf8ByteArrayToString = function(bytes) { + // TODO(user): Use native implementations if/when available + var out = [], pos = 0, c = 0; + while (pos < bytes.length) { + var c1 = bytes[pos++]; + if (c1 < 128) { + out[c++] = String.fromCharCode(c1); + } else if (c1 > 191 && c1 < 224) { + var c2 = bytes[pos++]; + out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63); + } else { + var c2 = bytes[pos++]; + var c3 = bytes[pos++]; + out[c++] = String.fromCharCode( + (c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63); } } - return null; + return out.join(''); }; /** - * Gets the document object of the dom. - * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being - * queried. If not provided, use the current DOM. - * @return {!Document} The dom document. - * @private + * XOR two byte arrays. + * @param {!ArrayBufferView|!Array<number>} bytes1 Byte array 1. + * @param {!ArrayBufferView|!Array<number>} bytes2 Byte array 2. + * @return {!Array<number>} Resulting XOR of the two byte arrays. */ -goog.dom.fullscreen.getDocument_ = function(opt_domHelper) { - return opt_domHelper ? - opt_domHelper.getDocument() : - goog.dom.getDomHelper().getDocument(); -}; - -goog.provide('ol.control.FullScreen'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.dom.fullscreen'); -goog.require('goog.dom.fullscreen.EventType'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol'); -goog.require('ol.control.Control'); -goog.require('ol.css'); +goog.crypt.xorByteArray = function(bytes1, bytes2) { + goog.asserts.assert( + bytes1.length == bytes2.length, + 'XOR array lengths must match'); + var result = []; + for (var i = 0; i < bytes1.length; i++) { + result.push(bytes1[i] ^ bytes2[i]); + } + return result; +}; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @classdesc - * Provides a button that when clicked fills up the full screen with the map. - * When in full screen mode, a close button is shown to exit full screen mode. - * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to - * toggle the map in full screen mode. + * @fileoverview Abstract cryptographic hash interface. * + * See goog.crypt.Sha1 and goog.crypt.Md5 for sample implementations. * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.FullScreenOptions=} opt_options Options. - * @api stable */ -ol.control.FullScreen = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {string} - */ - this.cssClassName_ = options.className ? options.className : 'ol-full-screen'; - - var label = options.label ? options.label : '\u2922'; - - /** - * @private - * @type {Node} - */ - this.labelNode_ = goog.isString(label) ? - goog.dom.createTextNode(label) : label; - - var labelActive = options.labelActive ? options.labelActive : '\u00d7'; - - /** - * @private - * @type {Node} - */ - this.labelActiveNode_ = goog.isString(labelActive) ? - goog.dom.createTextNode(labelActive) : labelActive; - - var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen'; - var button = goog.dom.createDom('BUTTON', { - 'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen(), - 'type': 'button', - 'title': tipLabel - }, this.labelNode_); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - goog.events.listen(goog.global.document, - goog.dom.fullscreen.EventType.CHANGE, - this.handleFullScreenChange_, false, this); +goog.provide('goog.crypt.Hash'); - var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE + - ' ' + ol.css.CLASS_CONTROL + ' ' + - (!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : ''); - var element = goog.dom.createDom('DIV', cssClasses, button); - goog.base(this, { - element: element, - target: options.target - }); +/** + * Create a cryptographic hash instance. + * + * @constructor + * @struct + */ +goog.crypt.Hash = function() { /** - * @private - * @type {boolean} + * The block size for the hasher. + * @type {number} */ - this.keys_ = options.keys !== undefined ? options.keys : false; - + this.blockSize = -1; }; -goog.inherits(ol.control.FullScreen, ol.control.Control); /** - * @param {goog.events.BrowserEvent} event The event to handle - * @private + * Resets the internal accumulator. */ -ol.control.FullScreen.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleFullScreen_(); -}; +goog.crypt.Hash.prototype.reset = goog.abstractMethod; /** - * @private + * Adds a byte array (array with values in [0-255] range) or a string (might + * only contain 8-bit, i.e., Latin1 characters) to the internal accumulator. + * + * Many hash functions operate on blocks of data and implement optimizations + * when a full chunk of data is readily available. Hence it is often preferable + * to provide large chunks of data (a kilobyte or more) than to repeatedly + * call the update method with few tens of bytes. If this is not possible, or + * not feasible, it might be good to provide data in multiplies of hash block + * size (often 64 bytes). Please see the implementation and performance tests + * of your favourite hash. + * + * @param {Array<number>|Uint8Array|string} bytes Data used for the update. + * @param {number=} opt_length Number of bytes to use. */ -ol.control.FullScreen.prototype.handleFullScreen_ = function() { - if (!goog.dom.fullscreen.isSupported()) { - return; - } - var map = this.getMap(); - if (!map) { - return; - } - if (goog.dom.fullscreen.isFullScreen()) { - goog.dom.fullscreen.exitFullScreen(); - } else { - var target = map.getTarget(); - goog.asserts.assert(target, 'target should be defined'); - var element = goog.dom.getElement(target); - goog.asserts.assert(element, 'element should be defined'); - if (this.keys_) { - goog.dom.fullscreen.requestFullScreenWithKeys(element); - } else { - goog.dom.fullscreen.requestFullScreen(element); - } - } -}; +goog.crypt.Hash.prototype.update = goog.abstractMethod; /** - * @private + * @return {!Array<number>} The finalized hash computed + * from the internal accumulator. */ -ol.control.FullScreen.prototype.handleFullScreenChange_ = function() { - var opened = this.cssClassName_ + '-true'; - var closed = this.cssClassName_ + '-false'; - var button = goog.dom.getFirstElementChild(this.element); - var map = this.getMap(); - if (goog.dom.fullscreen.isFullScreen()) { - goog.dom.classlist.swap(button, closed, opened); - goog.dom.replaceNode(this.labelActiveNode_, this.labelNode_); - } else { - goog.dom.classlist.swap(button, opened, closed); - goog.dom.replaceNode(this.labelNode_, this.labelActiveNode_); - } - if (map) { - map.updateSize(); - } -}; - -goog.provide('ol.Pixel'); +goog.crypt.Hash.prototype.digest = goog.abstractMethod; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * An array with two elements, representing a pixel. The first element is the - * x-coordinate, the second the y-coordinate of the pixel. - * @typedef {Array.<number>} - * @api stable + * @fileoverview MD5 cryptographic hash. + * Implementation of http://tools.ietf.org/html/rfc1321 with common + * optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5). + * + * Usage: + * var md5 = new goog.crypt.Md5(); + * md5.update(bytes); + * var hash = md5.digest(); + * + * Performance: + * Chrome 23 ~680 Mbit/s + * Chrome 13 (in a VM) ~250 Mbit/s + * Firefox 6.0 (in a VM) ~100 Mbit/s + * IE9 (in a VM) ~27 Mbit/s + * Firefox 3.6 ~15 Mbit/s + * IE8 (in a VM) ~13 Mbit/s + * */ -ol.Pixel; - -// FIXME should listen on appropriate pane, once it is defined - -goog.provide('ol.control.MousePosition'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.CoordinateFormatType'); -goog.require('ol.Object'); -goog.require('ol.Pixel'); -goog.require('ol.TransformFunction'); -goog.require('ol.control.Control'); -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); +goog.provide('goog.crypt.Md5'); -/** - * @enum {string} - */ -ol.control.MousePositionProperty = { - PROJECTION: 'projection', - COORDINATE_FORMAT: 'coordinateFormat' -}; +goog.require('goog.crypt.Hash'); /** - * @classdesc - * A control to show the 2D coordinates of the mouse cursor. By default, these - * are in the view projection, but can be in any supported projection. - * By default the control is shown in the top right corner of the map, but this - * can be changed by using the css selector `.ol-mouse-position`. - * + * MD5 cryptographic hash constructor. * @constructor - * @extends {ol.control.Control} - * @param {olx.control.MousePositionOptions=} opt_options Mouse position - * options. - * @api stable + * @extends {goog.crypt.Hash} + * @final + * @struct */ -ol.control.MousePosition = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var className = options.className ? options.className : 'ol-mouse-position'; - - var element = goog.dom.createDom('DIV', className); - - var render = options.render ? - options.render : ol.control.MousePosition.render; - - goog.base(this, { - element: element, - render: render, - target: options.target - }); - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION), - this.handleProjectionChanged_, false, this); - - if (options.coordinateFormat) { - this.setCoordinateFormat(options.coordinateFormat); - } - if (options.projection) { - this.setProjection(ol.proj.get(options.projection)); - } +goog.crypt.Md5 = function() { + goog.crypt.Md5.base(this, 'constructor'); - /** - * @private - * @type {string} - */ - this.undefinedHTML_ = options.undefinedHTML ? options.undefinedHTML : ''; + this.blockSize = 512 / 8; /** + * Holds the current values of accumulated A-D variables (MD buffer). + * @type {!Array<number>} * @private - * @type {string} */ - this.renderedHTML_ = element.innerHTML; + this.chain_ = new Array(4); /** + * A buffer holding the data until the whole block can be processed. + * @type {!Array<number>} * @private - * @type {ol.proj.Projection} */ - this.mapProjection_ = null; + this.block_ = new Array(this.blockSize); /** + * The length of yet-unprocessed data as collected in the block. + * @type {number} * @private - * @type {?ol.TransformFunction} */ - this.transform_ = null; + this.blockLength_ = 0; /** + * The total length of the message so far. + * @type {number} * @private - * @type {ol.Pixel} */ - this.lastMouseMovePixel_ = null; - -}; -goog.inherits(ol.control.MousePosition, ol.control.Control); - + this.totalLength_ = 0; -/** - * Update the mouseposition element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.MousePosition} - * @api - */ -ol.control.MousePosition.render = function(mapEvent) { - var frameState = mapEvent.frameState; - if (!frameState) { - this.mapProjection_ = null; - } else { - if (this.mapProjection_ != frameState.viewState.projection) { - this.mapProjection_ = frameState.viewState.projection; - this.transform_ = null; - } - } - this.updateHTML_(this.lastMouseMovePixel_); + this.reset(); }; +goog.inherits(goog.crypt.Md5, goog.crypt.Hash); /** + * Integer rotation constants used by the abbreviated implementation. + * They are hardcoded in the unrolled implementation, so it is left + * here commented out. + * @type {Array<number>} * @private + * +goog.crypt.Md5.S_ = [ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 +]; */ -ol.control.MousePosition.prototype.handleProjectionChanged_ = function() { - this.transform_ = null; -}; - - -/** - * Return the coordinate format type used to render the current position or - * undefined. - * @return {ol.CoordinateFormatType|undefined} The format to render the current - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.getCoordinateFormat = function() { - return /** @type {ol.CoordinateFormatType|undefined} */ ( - this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT)); -}; - /** - * Return the projection that is used to report the mouse position. - * @return {ol.proj.Projection|undefined} The projection to report mouse - * position in. - * @observable - * @api stable + * Sine function constants used by the abbreviated implementation. + * They are hardcoded in the unrolled implementation, so it is left + * here commented out. + * @type {Array<number>} + * @private + * +goog.crypt.Md5.T_ = [ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 +]; */ -ol.control.MousePosition.prototype.getProjection = function() { - return /** @type {ol.proj.Projection|undefined} */ ( - this.get(ol.control.MousePositionProperty.PROJECTION)); -}; -/** - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @protected - */ -ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) { - var map = this.getMap(); - this.lastMouseMovePixel_ = map.getEventPixel(browserEvent.getBrowserEvent()); - this.updateHTML_(this.lastMouseMovePixel_); -}; - +/** @override */ +goog.crypt.Md5.prototype.reset = function() { + this.chain_[0] = 0x67452301; + this.chain_[1] = 0xefcdab89; + this.chain_[2] = 0x98badcfe; + this.chain_[3] = 0x10325476; -/** - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @protected - */ -ol.control.MousePosition.prototype.handleMouseOut = function(browserEvent) { - this.updateHTML_(null); - this.lastMouseMovePixel_ = null; + this.blockLength_ = 0; + this.totalLength_ = 0; }; /** - * @inheritDoc - * @api stable + * Internal compress helper function. It takes a block of data (64 bytes) + * and updates the accumulator. + * @param {Array<number>|Uint8Array|string} buf The block to compress. + * @param {number=} opt_offset Offset of the block in the buffer. + * @private */ -ol.control.MousePosition.prototype.setMap = function(map) { - goog.base(this, 'setMap', map); - if (map) { - var viewport = map.getViewport(); - this.listenerKeys.push( - goog.events.listen(viewport, goog.events.EventType.MOUSEMOVE, - this.handleMouseMove, false, this), - goog.events.listen(viewport, goog.events.EventType.MOUSEOUT, - this.handleMouseOut, false, this) - ); +goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) { + if (!opt_offset) { + opt_offset = 0; } -}; - - -/** - * Set the coordinate format type used to render the current position. - * @param {ol.CoordinateFormatType} format The format to render the current - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.setCoordinateFormat = function(format) { - this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format); -}; - - -/** - * Set the projection that is used to report the mouse position. - * @param {ol.proj.Projection} projection The projection to report mouse - * position in. - * @observable - * @api stable - */ -ol.control.MousePosition.prototype.setProjection = function(projection) { - this.set(ol.control.MousePositionProperty.PROJECTION, projection); -}; + // We allocate the array every time, but it's cheap in practice. + var X = new Array(16); -/** - * @param {?ol.Pixel} pixel Pixel. - * @private - */ -ol.control.MousePosition.prototype.updateHTML_ = function(pixel) { - var html = this.undefinedHTML_; - if (pixel && this.mapProjection_) { - if (!this.transform_) { - var projection = this.getProjection(); - if (projection) { - this.transform_ = ol.proj.getTransformFromProjections( - this.mapProjection_, projection); - } else { - this.transform_ = ol.proj.identityTransform; - } + // Get 16 little endian words. It is not worth unrolling this for Chrome 11. + if (goog.isString(buf)) { + for (var i = 0; i < 16; ++i) { + X[i] = (buf.charCodeAt(opt_offset++)) | + (buf.charCodeAt(opt_offset++) << 8) | + (buf.charCodeAt(opt_offset++) << 16) | + (buf.charCodeAt(opt_offset++) << 24); } - var map = this.getMap(); - var coordinate = map.getCoordinateFromPixel(pixel); - if (coordinate) { - this.transform_(coordinate, coordinate); - var coordinateFormat = this.getCoordinateFormat(); - if (coordinateFormat) { - html = coordinateFormat(coordinate); - } else { - html = coordinate.toString(); - } + } else { + for (var i = 0; i < 16; ++i) { + X[i] = (buf[opt_offset++]) | + (buf[opt_offset++] << 8) | + (buf[opt_offset++] << 16) | + (buf[opt_offset++] << 24); } } - if (!this.renderedHTML_ || html != this.renderedHTML_) { - this.element.innerHTML = html; - this.renderedHTML_ = html; - } -}; -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + var A = this.chain_[0]; + var B = this.chain_[1]; + var C = this.chain_[2]; + var D = this.chain_[3]; + var sum = 0; -/** - * @fileoverview A delayed callback that pegs to the next animation frame - * instead of a user-configurable timeout. - * - * @author nicksantos@google.com (Nick Santos) - */ + /* + * This is an abbreviated implementation, it is left here commented out for + * reference purposes. See below for an unrolled version in use. + * + var f, n, tmp; + for (var i = 0; i < 64; ++i) { -goog.provide('goog.async.AnimationDelay'); + if (i < 16) { + f = (D ^ (B & (C ^ D))); + n = i; + } else if (i < 32) { + f = (C ^ (D & (B ^ C))); + n = (5 * i + 1) % 16; + } else if (i < 48) { + f = (B ^ C ^ D); + n = (3 * i + 5) % 16; + } else { + f = (C ^ (B | (~D))); + n = (7 * i) % 16; + } -goog.require('goog.Disposable'); -goog.require('goog.events'); -goog.require('goog.functions'); + tmp = D; + D = C; + C = B; + sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff; + B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) | + (sum >>> (32 - goog.crypt.Md5.S_[i])); + A = tmp; + } + */ + + /* + * This is an unrolled MD5 implementation, which gives ~30% speedup compared + * to the abbreviated implementation above, as measured on Chrome 11. It is + * important to keep 32-bit croppings to minimum and inline the integer + * rotation. + */ + sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff; + A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); + sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff; + D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); + sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff; + C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); + sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff; + B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); + sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff; + A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); + sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff; + D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); + sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff; + C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); + sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff; + B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); + sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff; + A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); + sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff; + D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); + sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff; + C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); + sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff; + B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); + sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff; + A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); + sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff; + D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); + sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff; + C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); + sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff; + B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); + sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff; + A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); + sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff; + D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); + sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff; + C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); + sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff; + B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); + sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff; + A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); + sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff; + D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); + sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff; + C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); + sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff; + B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); + sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff; + A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); + sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff; + D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); + sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff; + C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); + sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff; + B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); + sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff; + A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); + sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff; + D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); + sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff; + C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); + sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff; + B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); + sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff; + A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); + sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff; + D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); + sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff; + C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); + sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff; + B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); + sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff; + A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); + sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff; + D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); + sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff; + C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); + sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff; + B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); + sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff; + A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); + sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff; + D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); + sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff; + C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); + sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff; + B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); + sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff; + A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); + sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff; + D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); + sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff; + C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); + sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff; + B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); + sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff; + A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); + sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff; + D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); + sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff; + C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); + sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff; + B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); + sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff; + A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); + sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff; + D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); + sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff; + C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); + sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff; + B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); + sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff; + A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); + sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff; + D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); + sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff; + C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); + sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff; + B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); + sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff; + A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); + sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff; + D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); + sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff; + C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); + sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff; + B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); + this.chain_[0] = (this.chain_[0] + A) & 0xffffffff; + this.chain_[1] = (this.chain_[1] + B) & 0xffffffff; + this.chain_[2] = (this.chain_[2] + C) & 0xffffffff; + this.chain_[3] = (this.chain_[3] + D) & 0xffffffff; +}; -// TODO(nicksantos): Should we factor out the common code between this and -// goog.async.Delay? I'm not sure if there's enough code for this to really -// make sense. Subclassing seems like the wrong approach for a variety of -// reasons. Maybe there should be a common interface? +/** @override */ +goog.crypt.Md5.prototype.update = function(bytes, opt_length) { + if (!goog.isDef(opt_length)) { + opt_length = bytes.length; + } + var lengthMinusBlock = opt_length - this.blockSize; + + // Copy some object properties to local variables in order to save on access + // time from inside the loop (~10% speedup was observed on Chrome 11). + var block = this.block_; + var blockLength = this.blockLength_; + var i = 0; + + // The outer while loop should execute at most twice. + while (i < opt_length) { + // When we have no data in the block to top up, we can directly process the + // input buffer (assuming it contains sufficient data). This gives ~30% + // speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that + // the data is provided in large chunks (or in multiples of 64 bytes). + if (blockLength == 0) { + while (i <= lengthMinusBlock) { + this.compress_(bytes, i); + i += this.blockSize; + } + } + + if (goog.isString(bytes)) { + while (i < opt_length) { + block[blockLength++] = bytes.charCodeAt(i++); + if (blockLength == this.blockSize) { + this.compress_(block); + blockLength = 0; + // Jump to the outer loop so we use the full-block optimization. + break; + } + } + } else { + while (i < opt_length) { + block[blockLength++] = bytes[i++]; + if (blockLength == this.blockSize) { + this.compress_(block); + blockLength = 0; + // Jump to the outer loop so we use the full-block optimization. + break; + } + } + } + } + + this.blockLength_ = blockLength; + this.totalLength_ += opt_length; +}; + + +/** @override */ +goog.crypt.Md5.prototype.digest = function() { + // This must accommodate at least 1 padding byte (0x80), 8 bytes of + // total bitlength, and must end at a 64-byte boundary. + var pad = new Array((this.blockLength_ < 56 ? + this.blockSize : + this.blockSize * 2) - this.blockLength_); + + // Add padding: 0x80 0x00* + pad[0] = 0x80; + for (var i = 1; i < pad.length - 8; ++i) { + pad[i] = 0; + } + // Add the total number of bits, little endian 64-bit integer. + var totalBits = this.totalLength_ * 8; + for (var i = pad.length - 8; i < pad.length; ++i) { + pad[i] = totalBits & 0xff; + totalBits /= 0x100; // Don't use bit-shifting here! + } + this.update(pad); + + var digest = new Array(16); + var n = 0; + for (var i = 0; i < 4; ++i) { + for (var j = 0; j < 32; j += 8) { + digest[n++] = (this.chain_[i] >>> j) & 0xff; + } + } + return digest; +}; + +goog.provide('ol.style.Stroke'); + +goog.require('goog.crypt'); +goog.require('goog.crypt.Md5'); +goog.require('ol.color'); +goog.require('ol.structs.IHasChecksum'); /** - * A delayed callback that pegs to the next animation frame - * instead of a user configurable timeout. By design, this should have - * the same interface as goog.async.Delay. - * - * Uses requestAnimationFrame and friends when available, but falls - * back to a timeout of goog.async.AnimationDelay.TIMEOUT. - * - * For more on requestAnimationFrame and how you can use it to create smoother - * animations, see: - * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + * @classdesc + * Set stroke style for vector features. + * Note that the defaults given are the Canvas defaults, which will be used if + * option is not defined. The `get` functions return whatever was entered in + * the options; they will not return the default. * - * @param {function(number)} listener Function to call when the delay completes. - * Will be passed the timestamp when it's called, in unix ms. - * @param {Window=} opt_window The window object to execute the delay in. - * Defaults to the global object. - * @param {Object=} opt_handler The object scope to invoke the function in. * @constructor - * @struct - * @extends {goog.Disposable} - * @final + * @param {olx.style.StrokeOptions=} opt_options Options. + * @implements {ol.structs.IHasChecksum} + * @api */ -goog.async.AnimationDelay = function(listener, opt_window, opt_handler) { - goog.async.AnimationDelay.base(this, 'constructor'); +ol.style.Stroke = function(opt_options) { + + var options = opt_options || {}; /** - * Identifier of the active delay timeout, or event listener, - * or null when inactive. - * @private {goog.events.Key|number} + * @private + * @type {ol.Color|string} */ - this.id_ = null; + this.color_ = options.color !== undefined ? options.color : null; /** - * If we're using dom listeners. - * @private {?boolean} + * @private + * @type {string|undefined} */ - this.usingListeners_ = false; + this.lineCap_ = options.lineCap; /** - * The function that will be invoked after a delay. - * @private {function(number)} + * @private + * @type {Array.<number>} */ - this.listener_ = listener; + this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null; /** - * The object context to invoke the callback in. - * @private {Object|undefined} + * @private + * @type {string|undefined} */ - this.handler_ = opt_handler; + this.lineJoin_ = options.lineJoin; /** - * @private {Window} + * @private + * @type {number|undefined} */ - this.win_ = opt_window || window; + this.miterLimit_ = options.miterLimit; /** - * Cached callback function invoked when the delay finishes. - * @private {function()} + * @private + * @type {number|undefined} */ - this.callback_ = goog.bind(this.doAction_, this); + this.width_ = options.width; + + /** + * @private + * @type {string|undefined} + */ + this.checksum_ = undefined; }; -goog.inherits(goog.async.AnimationDelay, goog.Disposable); /** - * Default wait timeout for animations (in milliseconds). Only used for timed - * animation, which uses a timer (setTimeout) to schedule animation. - * - * @type {number} - * @const + * Get the stroke color. + * @return {ol.Color|string} Color. + * @api */ -goog.async.AnimationDelay.TIMEOUT = 20; +ol.style.Stroke.prototype.getColor = function() { + return this.color_; +}; /** - * Name of event received from the requestAnimationFrame in Firefox. - * - * @type {string} - * @const - * @private + * Get the line cap type for the stroke. + * @return {string|undefined} Line cap. + * @api */ -goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_ = 'MozBeforePaint'; +ol.style.Stroke.prototype.getLineCap = function() { + return this.lineCap_; +}; /** - * Starts the delay timer. The provided listener function will be called - * before the next animation frame. + * Get the line dash style for the stroke. + * @return {Array.<number>} Line dash. + * @api */ -goog.async.AnimationDelay.prototype.start = function() { - this.stop(); - this.usingListeners_ = false; - - var raf = this.getRaf_(); - var cancelRaf = this.getCancelRaf_(); - if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { - // Because Firefox (Gecko) runs animation in separate threads, it also saves - // time by running the requestAnimationFrame callbacks in that same thread. - // Sadly this breaks the assumption of implicit thread-safety in JS, and can - // thus create thread-based inconsistencies on counters etc. - // - // Calling cycleAnimations_ using the MozBeforePaint event instead of as - // callback fixes this. - // - // Trigger this condition only if the mozRequestAnimationFrame is available, - // but not the W3C requestAnimationFrame function (as in draft) or the - // equivalent cancel functions. - this.id_ = goog.events.listen( - this.win_, - goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_, - this.callback_); - this.win_.mozRequestAnimationFrame(null); - this.usingListeners_ = true; - } else if (raf && cancelRaf) { - this.id_ = raf.call(this.win_, this.callback_); - } else { - this.id_ = this.win_.setTimeout( - // Prior to Firefox 13, Gecko passed a non-standard parameter - // to the callback that we want to ignore. - goog.functions.lock(this.callback_), - goog.async.AnimationDelay.TIMEOUT); - } +ol.style.Stroke.prototype.getLineDash = function() { + return this.lineDash_; }; /** - * Stops the delay timer if it is active. No action is taken if the timer is not - * in use. + * Get the line join type for the stroke. + * @return {string|undefined} Line join. + * @api */ -goog.async.AnimationDelay.prototype.stop = function() { - if (this.isActive()) { - var raf = this.getRaf_(); - var cancelRaf = this.getCancelRaf_(); - if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { - goog.events.unlistenByKey(this.id_); - } else if (raf && cancelRaf) { - cancelRaf.call(this.win_, /** @type {number} */ (this.id_)); - } else { - this.win_.clearTimeout(/** @type {number} */ (this.id_)); - } - } - this.id_ = null; +ol.style.Stroke.prototype.getLineJoin = function() { + return this.lineJoin_; }; /** - * Fires delay's action even if timer has already gone off or has not been - * started yet; guarantees action firing. Stops the delay timer. + * Get the miter limit for the stroke. + * @return {number|undefined} Miter limit. + * @api */ -goog.async.AnimationDelay.prototype.fire = function() { - this.stop(); - this.doAction_(); +ol.style.Stroke.prototype.getMiterLimit = function() { + return this.miterLimit_; }; /** - * Fires delay's action only if timer is currently active. Stops the delay - * timer. + * Get the stroke width. + * @return {number|undefined} Width. + * @api */ -goog.async.AnimationDelay.prototype.fireIfActive = function() { - if (this.isActive()) { - this.fire(); - } +ol.style.Stroke.prototype.getWidth = function() { + return this.width_; }; /** - * @return {boolean} True if the delay is currently active, false otherwise. + * Set the color. + * + * @param {ol.Color|string} color Color. + * @api */ -goog.async.AnimationDelay.prototype.isActive = function() { - return this.id_ != null; +ol.style.Stroke.prototype.setColor = function(color) { + this.color_ = color; + this.checksum_ = undefined; }; /** - * Invokes the callback function after the delay successfully completes. - * @private + * Set the line cap. + * + * @param {string|undefined} lineCap Line cap. + * @api */ -goog.async.AnimationDelay.prototype.doAction_ = function() { - if (this.usingListeners_ && this.id_) { - goog.events.unlistenByKey(this.id_); - } - this.id_ = null; - - // We are not using the timestamp returned by requestAnimationFrame - // because it may be either a Date.now-style time or a - // high-resolution time (depending on browser implementation). Using - // goog.now() will ensure that the timestamp used is consistent and - // compatible with goog.fx.Animation. - this.listener_.call(this.handler_, goog.now()); +ol.style.Stroke.prototype.setLineCap = function(lineCap) { + this.lineCap_ = lineCap; + this.checksum_ = undefined; }; -/** @override */ -goog.async.AnimationDelay.prototype.disposeInternal = function() { - this.stop(); - goog.async.AnimationDelay.base(this, 'disposeInternal'); +/** + * Set the line dash. + * + * @param {Array.<number>} lineDash Line dash. + * @api + */ +ol.style.Stroke.prototype.setLineDash = function(lineDash) { + this.lineDash_ = lineDash; + this.checksum_ = undefined; }; /** - * @return {?function(function(number)): number} The requestAnimationFrame - * function, or null if not available on this browser. - * @private + * Set the line join. + * + * @param {string|undefined} lineJoin Line join. + * @api */ -goog.async.AnimationDelay.prototype.getRaf_ = function() { - var win = this.win_; - return win.requestAnimationFrame || - win.webkitRequestAnimationFrame || - win.mozRequestAnimationFrame || - win.oRequestAnimationFrame || - win.msRequestAnimationFrame || - null; +ol.style.Stroke.prototype.setLineJoin = function(lineJoin) { + this.lineJoin_ = lineJoin; + this.checksum_ = undefined; }; /** - * @return {?function(number): number} The cancelAnimationFrame function, - * or null if not available on this browser. - * @private + * Set the miter limit. + * + * @param {number|undefined} miterLimit Miter limit. + * @api */ -goog.async.AnimationDelay.prototype.getCancelRaf_ = function() { - var win = this.win_; - return win.cancelAnimationFrame || - win.cancelRequestAnimationFrame || - win.webkitCancelRequestAnimationFrame || - win.mozCancelRequestAnimationFrame || - win.oCancelRequestAnimationFrame || - win.msCancelRequestAnimationFrame || - null; +ol.style.Stroke.prototype.setMiterLimit = function(miterLimit) { + this.miterLimit_ = miterLimit; + this.checksum_ = undefined; }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Provides a function to schedule running a function as soon - * as possible after the current JS execution stops and yields to the event - * loop. + * Set the width. * + * @param {number|undefined} width Width. + * @api */ - -goog.provide('goog.async.nextTick'); -goog.provide('goog.async.throwException'); - -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.dom.TagName'); -goog.require('goog.functions'); -goog.require('goog.labs.userAgent.browser'); -goog.require('goog.labs.userAgent.engine'); - - -/** - * Throw an item without interrupting the current execution context. For - * example, if processing a group of items in a loop, sometimes it is useful - * to report an error while still allowing the rest of the batch to be - * processed. - * @param {*} exception - */ -goog.async.throwException = function(exception) { - // Each throw needs to be in its own context. - goog.global.setTimeout(function() { throw exception; }, 0); +ol.style.Stroke.prototype.setWidth = function(width) { + this.width_ = width; + this.checksum_ = undefined; }; /** - * Fires the provided callbacks as soon as possible after the current JS - * execution context. setTimeout(…, 0) takes at least 4ms when called from - * within another setTimeout(…, 0) for legacy reasons. - * - * This will not schedule the callback as a microtask (i.e. a task that can - * preempt user input or networking callbacks). It is meant to emulate what - * setTimeout(_, 0) would do if it were not throttled. If you desire microtask - * behavior, use {@see goog.Promise} instead. - * - * @param {function(this:SCOPE)} callback Callback function to fire as soon as - * possible. - * @param {SCOPE=} opt_context Object in whose scope to call the listener. - * @param {boolean=} opt_useSetImmediate Avoid the IE workaround that - * ensures correctness at the cost of speed. See comments for details. - * @template SCOPE + * @inheritDoc */ -goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) { - var cb = callback; - if (opt_context) { - cb = goog.bind(callback, opt_context); - } - cb = goog.async.nextTick.wrapCallback_(cb); - // window.setImmediate was introduced and currently only supported by IE10+, - // but due to a bug in the implementation it is not guaranteed that - // setImmediate is faster than setTimeout nor that setImmediate N is before - // setImmediate N+1. That is why we do not use the native version if - // available. We do, however, call setImmediate if it is a normal function - // because that indicates that it has been replaced by goog.testing.MockClock - // which we do want to support. - // See - // http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10 - // - // Note we do allow callers to also request setImmediate if they are willing - // to accept the possible tradeoffs of incorrectness in exchange for speed. - // The IE fallback of readystate change is much slower. - if (goog.isFunction(goog.global.setImmediate) && - // Opt in. - (opt_useSetImmediate || - // or it isn't a browser or the environment is weird - !goog.global.Window || !goog.global.Window.prototype || - // or something redefined setImmediate in which case we (YOLO) decide - // to use it (This is so that we use the mockClock setImmediate. sigh). - goog.global.Window.prototype.setImmediate != goog.global.setImmediate)) { - goog.global.setImmediate(cb); - return; - } +ol.style.Stroke.prototype.getChecksum = function() { + if (this.checksum_ === undefined) { + var raw = 's' + + (this.color_ ? + ol.color.asString(this.color_) : '-') + ',' + + (this.lineCap_ !== undefined ? + this.lineCap_.toString() : '-') + ',' + + (this.lineDash_ ? + this.lineDash_.toString() : '-') + ',' + + (this.lineJoin_ !== undefined ? + this.lineJoin_ : '-') + ',' + + (this.miterLimit_ !== undefined ? + this.miterLimit_.toString() : '-') + ',' + + (this.width_ !== undefined ? + this.width_.toString() : '-'); - // Look for and cache the custom fallback version of setImmediate. - if (!goog.async.nextTick.setImmediate_) { - goog.async.nextTick.setImmediate_ = - goog.async.nextTick.getSetImmediateEmulator_(); + var md5 = new goog.crypt.Md5(); + md5.update(raw); + this.checksum_ = goog.crypt.byteArrayToString(md5.digest()); } - goog.async.nextTick.setImmediate_(cb); + + return this.checksum_; }; +goog.provide('ol.style.Circle'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('ol'); +goog.require('ol.color'); +goog.require('ol.has'); +goog.require('ol.render.canvas'); +goog.require('ol.structs.IHasChecksum'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Image'); +goog.require('ol.style.ImageState'); +goog.require('ol.style.Stroke'); -/** - * Cache for the setImmediate implementation. - * @type {function(function())} - * @private - */ -goog.async.nextTick.setImmediate_; /** - * Determines the best possible implementation to run a function as soon as - * the JS event loop is idle. - * @return {function(function())} The "setImmediate" implementation. - * @private + * @classdesc + * Set circle style for vector features. + * + * @constructor + * @param {olx.style.CircleOptions=} opt_options Options. + * @extends {ol.style.Image} + * @implements {ol.structs.IHasChecksum} + * @api */ -goog.async.nextTick.getSetImmediateEmulator_ = function() { - // Create a private message channel and use it to postMessage empty messages - // to ourselves. - var Channel = goog.global['MessageChannel']; - // If MessageChannel is not available and we are in a browser, implement - // an iframe based polyfill in browsers that have postMessage and - // document.addEventListener. The latter excludes IE8 because it has a - // synchronous postMessage implementation. - if (typeof Channel === 'undefined' && typeof window !== 'undefined' && - window.postMessage && window.addEventListener && - // Presto (The old pre-blink Opera engine) has problems with iframes - // and contentWindow. - !goog.labs.userAgent.engine.isPresto()) { - /** @constructor */ - Channel = function() { - // Make an empty, invisible iframe. - var iframe = document.createElement(goog.dom.TagName.IFRAME); - iframe.style.display = 'none'; - iframe.src = ''; - document.documentElement.appendChild(iframe); - var win = iframe.contentWindow; - var doc = win.document; - doc.open(); - doc.write(''); - doc.close(); - // Do not post anything sensitive over this channel, as the workaround for - // pages with file: origin could allow that information to be modified or - // intercepted. - var message = 'callImmediate' + Math.random(); - // The same origin policy rejects attempts to postMessage from file: urls - // unless the origin is '*'. - // TODO(b/16335441): Use '*' origin for data: and other similar protocols. - var origin = win.location.protocol == 'file:' ? - '*' : win.location.protocol + '//' + win.location.host; - var onmessage = goog.bind(function(e) { - // Validate origin and message to make sure that this message was - // intended for us. If the origin is set to '*' (see above) only the - // message needs to match since, for example, '*' != 'file://'. Allowing - // the wildcard is ok, as we are not concerned with security here. - if ((origin != '*' && e.origin != origin) || e.data != message) { - return; - } - this['port1'].onmessage(); - }, this); - win.addEventListener('message', onmessage, false); - this['port1'] = {}; - this['port2'] = { - postMessage: function() { - win.postMessage(message, origin); - } - }; - }; - } - if (typeof Channel !== 'undefined' && - (!goog.labs.userAgent.browser.isIE())) { - // Exclude all of IE due to - // http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/ - // which allows starving postMessage with a busy setTimeout loop. - // This currently affects IE10 and IE11 which would otherwise be able - // to use the postMessage based fallbacks. - var channel = new Channel(); - // Use a fifo linked list to call callbacks in the right order. - var head = {}; - var tail = head; - channel['port1'].onmessage = function() { - if (goog.isDef(head.next)) { - head = head.next; - var cb = head.cb; - head.cb = null; - cb(); - } - }; - return function(cb) { - tail.next = { - cb: cb - }; - tail = tail.next; - channel['port2'].postMessage(0); - }; - } - // Implementation for IE6+: Script elements fire an asynchronous - // onreadystatechange event when inserted into the DOM. - if (typeof document !== 'undefined' && 'onreadystatechange' in - document.createElement(goog.dom.TagName.SCRIPT)) { - return function(cb) { - var script = document.createElement(goog.dom.TagName.SCRIPT); - script.onreadystatechange = function() { - // Clean up and call the callback. - script.onreadystatechange = null; - script.parentNode.removeChild(script); - script = null; - cb(); - cb = null; - }; - document.documentElement.appendChild(script); - }; - } - // Fall back to setTimeout with 0. In browsers this creates a delay of 5ms - // or more. - return function(cb) { - goog.global.setTimeout(cb, 0); - }; -}; +ol.style.Circle = function(opt_options) { + var options = opt_options || {}; -/** - * Helper function that is overrided to protect callbacks with entry point - * monitor if the application monitors entry points. - * @param {function()} callback Callback function to fire as soon as possible. - * @return {function()} The wrapped callback. - * @private - */ -goog.async.nextTick.wrapCallback_ = goog.functions.identity; + /** + * @private + * @type {Array.<string>} + */ + this.checksums_ = null; + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = null; -// Register the callback function as an entry point, so that it can be -// monitored for exception handling, etc. This has to be done in this file -// since it requires special code to handle all browsers. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.async.nextTick.wrapCallback_ = transformer; - }); + /** + * @private + * @type {HTMLCanvasElement} + */ + this.hitDetectionCanvas_ = null; -// Copyright 2014 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + /** + * @private + * @type {ol.style.Fill} + */ + this.fill_ = options.fill !== undefined ? options.fill : null; -/** - * @fileoverview The SafeScript type and its builders. - * - * TODO(xtof): Link to document stating type contract. - */ + /** + * @private + * @type {ol.style.Stroke} + */ + this.stroke_ = options.stroke !== undefined ? options.stroke : null; -goog.provide('goog.html.SafeScript'); + /** + * @private + * @type {number} + */ + this.radius_ = options.radius; -goog.require('goog.asserts'); -goog.require('goog.string.Const'); -goog.require('goog.string.TypedString'); + /** + * @private + * @type {Array.<number>} + */ + this.origin_ = [0, 0]; + /** + * @private + * @type {Array.<number>} + */ + this.anchor_ = null; + /** + * @private + * @type {ol.Size} + */ + this.size_ = null; -/** - * A string-like object which represents JavaScript code and that carries the - * security type contract that its value, as a string, will not cause execution - * of unconstrained attacker controlled code (XSS) when evaluated as JavaScript - * in a browser. - * - * Instances of this type must be created via the factory method - * {@code goog.html.SafeScript.fromConstant} and not by invoking its - * constructor. The constructor intentionally takes no parameters and the type - * is immutable; hence only a default instance corresponding to the empty string - * can be obtained via constructor invocation. - * - * A SafeScript's string representation can safely be interpolated as the - * content of a script element within HTML. The SafeScript string should not be - * escaped before interpolation. - * - * Note that the SafeScript might contain text that is attacker-controlled but - * that text should have been interpolated with appropriate escaping, - * sanitization and/or validation into the right location in the script, such - * that it is highly constrained in its effect (for example, it had to match a - * set of whitelisted words). - * - * A SafeScript can be constructed via security-reviewed unchecked - * conversions. In this case producers of SafeScript must ensure themselves that - * the SafeScript does not contain unsafe script. Note in particular that - * {@code <} is dangerous, even when inside JavaScript strings, and so should - * always be forbidden or JavaScript escaped in user controlled input. For - * example, if {@code </script><script>evil</script>"} were - * interpolated inside a JavaScript string, it would break out of the context - * of the original script element and {@code evil} would execute. Also note - * that within an HTML script (raw text) element, HTML character references, - * such as "<" are not allowed. See - * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements. - * - * @see goog.html.SafeScript#fromConstant - * @constructor - * @final - * @struct - * @implements {goog.string.TypedString} - */ -goog.html.SafeScript = function() { /** - * The contained value of this SafeScript. The field has a purposely - * ugly name to make (non-compiled) code that attempts to directly access this - * field stand out. - * @private {string} + * @private + * @type {ol.Size} */ - this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = ''; + this.imageSize_ = null; /** - * A type marker used to implement additional run-time type checking. - * @see goog.html.SafeScript#unwrap - * @const * @private + * @type {ol.Size} */ - this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = - goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; + this.hitDetectionImageSize_ = null; + + this.render_(options.atlasManager); + + /** + * @type {boolean} + */ + var snapToPixel = options.snapToPixel !== undefined ? + options.snapToPixel : true; + + goog.base(this, { + opacity: 1, + rotateWithView: false, + rotation: 0, + scale: 1, + snapToPixel: snapToPixel + }); + }; +goog.inherits(ol.style.Circle, ol.style.Image); /** - * @override - * @const + * @inheritDoc */ -goog.html.SafeScript.prototype.implementsGoogStringTypedString = true; +ol.style.Circle.prototype.getAnchor = function() { + return this.anchor_; +}; /** - * Type marker for the SafeScript type, used to implement additional - * run-time type checking. - * @const {!Object} - * @private + * Get the fill style for the circle. + * @return {ol.style.Fill} Fill style. + * @api */ -goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; +ol.style.Circle.prototype.getFill = function() { + return this.fill_; +}; /** - * Creates a SafeScript object from a compile-time constant string. - * - * @param {!goog.string.Const} script A compile-time-constant string from which - * to create a SafeScript. - * @return {!goog.html.SafeScript} A SafeScript object initialized to - * {@code script}. + * @inheritDoc */ -goog.html.SafeScript.fromConstant = function(script) { - var scriptString = goog.string.Const.unwrap(script); - if (scriptString.length === 0) { - return goog.html.SafeScript.EMPTY; - } - return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( - scriptString); +ol.style.Circle.prototype.getHitDetectionImage = function(pixelRatio) { + return this.hitDetectionCanvas_; }; /** - * Returns this SafeScript's value as a string. - * - * IMPORTANT: In code where it is security relevant that an object's type is - * indeed {@code SafeScript}, use {@code goog.html.SafeScript.unwrap} instead of - * this method. If in doubt, assume that it's security relevant. In particular, - * note that goog.html functions which return a goog.html type do not guarantee - * the returned instance is of the right type. For example: - * - * <pre> - * var fakeSafeHtml = new String('fake'); - * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; - * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); - * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by - * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml - * // instanceof goog.html.SafeHtml. - * </pre> - * - * @see goog.html.SafeScript#unwrap - * @override + * Get the image used to render the circle. + * @param {number} pixelRatio Pixel ratio. + * @return {HTMLCanvasElement} Canvas element. + * @api */ -goog.html.SafeScript.prototype.getTypedStringValue = function() { - return this.privateDoNotAccessOrElseSafeScriptWrappedValue_; +ol.style.Circle.prototype.getImage = function(pixelRatio) { + return this.canvas_; }; -if (goog.DEBUG) { - /** - * Returns a debug string-representation of this value. - * - * To obtain the actual string value wrapped in a SafeScript, use - * {@code goog.html.SafeScript.unwrap}. - * - * @see goog.html.SafeScript#unwrap - * @override - */ - goog.html.SafeScript.prototype.toString = function() { - return 'SafeScript{' + - this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}'; - }; -} +/** + * @inheritDoc + */ +ol.style.Circle.prototype.getImageState = function() { + return ol.style.ImageState.LOADED; +}; /** - * Performs a runtime check that the provided object is indeed a - * SafeScript object, and returns its value. - * - * @param {!goog.html.SafeScript} safeScript The object to extract from. - * @return {string} The safeScript object's contained string, unless - * the run-time type check fails. In that case, {@code unwrap} returns an - * innocuous string, or, if assertions are enabled, throws - * {@code goog.asserts.AssertionError}. + * @inheritDoc */ -goog.html.SafeScript.unwrap = function(safeScript) { - // Perform additional Run-time type-checking to ensure that - // safeScript is indeed an instance of the expected type. This - // provides some additional protection against security bugs due to - // application code that disables type checks. - // Specifically, the following checks are performed: - // 1. The object is an instance of the expected type. - // 2. The object is not an instance of a subclass. - // 3. The object carries a type marker for the expected type. "Faking" an - // object requires a reference to the type marker, which has names intended - // to stand out in code reviews. - if (safeScript instanceof goog.html.SafeScript && - safeScript.constructor === goog.html.SafeScript && - safeScript.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === - goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { - return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_; - } else { - goog.asserts.fail( - 'expected object of type SafeScript, got \'' + safeScript + '\''); - return 'type_error:SafeScript'; - } +ol.style.Circle.prototype.getImageSize = function() { + return this.imageSize_; }; /** - * Package-internal utility method to create SafeScript instances. - * - * @param {string} script The string to initialize the SafeScript object with. - * @return {!goog.html.SafeScript} The initialized SafeScript object. - * @package + * @inheritDoc */ -goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse = - function(script) { - return new goog.html.SafeScript().initSecurityPrivateDoNotAccessOrElse_( - script); +ol.style.Circle.prototype.getHitDetectionImageSize = function() { + return this.hitDetectionImageSize_; }; /** - * Called from createSafeScriptSecurityPrivateDoNotAccessOrElse(). This - * method exists only so that the compiler can dead code eliminate static - * fields (like EMPTY) when they're not accessed. - * @param {string} script - * @return {!goog.html.SafeScript} - * @private + * @inheritDoc */ -goog.html.SafeScript.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( - script) { - this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = script; - return this; +ol.style.Circle.prototype.getOrigin = function() { + return this.origin_; }; /** - * A SafeScript instance corresponding to the empty string. - * @const {!goog.html.SafeScript} + * Get the circle radius. + * @return {number} Radius. + * @api */ -goog.html.SafeScript.EMPTY = - goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(''); +ol.style.Circle.prototype.getRadius = function() { + return this.radius_; +}; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Unchecked conversions to create values of goog.html types from - * plain strings. Use of these functions could potentially result in instances - * of goog.html types that violate their type contracts, and hence result in - * security vulnerabilties. - * - * Therefore, all uses of the methods herein must be carefully security - * reviewed. Avoid use of the methods in this file whenever possible; instead - * prefer to create instances of goog.html types using inherently safe builders - * or template systems. - * - * - * - * @visibility {//closure/goog/html:approved_for_unchecked_conversion} - * @visibility {//closure/goog/bin/sizetests:__pkg__} + * @inheritDoc */ - - -goog.provide('goog.html.uncheckedconversions'); - -goog.require('goog.asserts'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeScript'); -goog.require('goog.html.SafeStyle'); -goog.require('goog.html.SafeStyleSheet'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.TrustedResourceUrl'); -goog.require('goog.string'); -goog.require('goog.string.Const'); +ol.style.Circle.prototype.getSize = function() { + return this.size_; +}; /** - * Performs an "unchecked conversion" to SafeHtml from a plain string that is - * known to satisfy the SafeHtml type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code html} satisfies the SafeHtml type contract in all - * possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} html A string that is claimed to adhere to the SafeHtml - * contract. - * @param {?goog.i18n.bidi.Dir=} opt_dir The optional directionality of the - * SafeHtml to be constructed. A null or undefined value signifies an - * unknown directionality. - * @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml - * object. - * @suppress {visibility} For access to SafeHtml.create... Note that this - * use is appropriate since this method is intended to be "package private" - * withing goog.html. DO NOT call SafeHtml.create... from outside this - * package; use appropriate wrappers instead. + * Get the stroke style for the circle. + * @return {ol.style.Stroke} Stroke style. + * @api */ -goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract = - function(justification, html, opt_dir) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( - html, opt_dir || null); +ol.style.Circle.prototype.getStroke = function() { + return this.stroke_; }; /** - * Performs an "unchecked conversion" to SafeScript from a plain string that is - * known to satisfy the SafeScript type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code script} satisfies the SafeScript type contract in - * all possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} script The string to wrap as a SafeScript. - * @return {!goog.html.SafeScript} The value of {@code script}, wrapped in a - * SafeScript object. + * @inheritDoc */ -goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract = - function(justification, script) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmpty(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( - script); -}; +ol.style.Circle.prototype.listenImageChange = ol.nullFunction; /** - * Performs an "unchecked conversion" to SafeStyle from a plain string that is - * known to satisfy the SafeStyle type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code style} satisfies the SafeUrl type contract in all - * possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} style The string to wrap as a SafeStyle. - * @return {!goog.html.SafeStyle} The value of {@code style}, wrapped in a - * SafeStyle object. + * @inheritDoc */ -goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract = - function(justification, style) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( - style); -}; +ol.style.Circle.prototype.load = ol.nullFunction; /** - * Performs an "unchecked conversion" to SafeStyleSheet from a plain string - * that is known to satisfy the SafeStyleSheet type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code styleSheet} satisfies the SafeUrl type contract in - * all possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} styleSheet The string to wrap as a SafeStyleSheet. - * @return {!goog.html.SafeStyleSheet} The value of {@code styleSheet}, wrapped - * in a SafeStyleSheet object. + * @inheritDoc */ -goog.html.uncheckedconversions. - safeStyleSheetFromStringKnownToSatisfyTypeContract = - function(justification, styleSheet) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeStyleSheet. - createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet); -}; +ol.style.Circle.prototype.unlistenImageChange = ol.nullFunction; /** - * Performs an "unchecked conversion" to SafeUrl from a plain string that is - * known to satisfy the SafeUrl type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code url} satisfies the SafeUrl type contract in all - * possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} url The string to wrap as a SafeUrl. - * @return {!goog.html.SafeUrl} The value of {@code url}, wrapped in a SafeUrl - * object. + * @typedef {{strokeStyle: (string|undefined), strokeWidth: number, + * size: number, lineDash: Array.<number>}} */ -goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract = - function(justification, url) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); -}; +ol.style.Circle.RenderOptions; /** - * Performs an "unchecked conversion" to TrustedResourceUrl from a plain string - * that is known to satisfy the TrustedResourceUrl type contract. - * - * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure - * that the value of {@code url} satisfies the TrustedResourceUrl type contract - * in all possible program states. - * - * - * @param {!goog.string.Const} justification A constant string explaining why - * this use of this method is safe. May include a security review ticket - * number. - * @param {string} url The string to wrap as a TrustedResourceUrl. - * @return {!goog.html.TrustedResourceUrl} The value of {@code url}, wrapped in - * a TrustedResourceUrl object. + * @private + * @param {ol.style.AtlasManager|undefined} atlasManager */ -goog.html.uncheckedconversions. - trustedResourceUrlFromStringKnownToSatisfyTypeContract = - function(justification, url) { - // unwrap() called inside an assert so that justification can be optimized - // away in production code. - goog.asserts.assertString(goog.string.Const.unwrap(justification), - 'must provide justification'); - goog.asserts.assert( - !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), - 'must provide non-empty justification'); - return goog.html.TrustedResourceUrl. - createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url); -}; +ol.style.Circle.prototype.render_ = function(atlasManager) { + var imageSize; + var lineDash = null; + var strokeStyle; + var strokeWidth = 0; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + if (this.stroke_) { + strokeStyle = ol.color.asString(this.stroke_.getColor()); + strokeWidth = this.stroke_.getWidth(); + if (strokeWidth === undefined) { + strokeWidth = ol.render.canvas.defaultLineWidth; + } + lineDash = this.stroke_.getLineDash(); + if (!ol.has.CANVAS_LINE_DASH) { + lineDash = null; + } + } -/** - * @fileoverview Generics method for collection-like classes and objects. - * - * @author arv@google.com (Erik Arvidsson) - * - * This file contains functions to work with collections. It supports using - * Map, Set, Array and Object and other classes that implement collection-like - * methods. - */ + var size = 2 * (this.radius_ + strokeWidth) + 1; -goog.provide('goog.structs'); + /** @type {ol.style.Circle.RenderOptions} */ + var renderOptions = { + strokeStyle: strokeStyle, + strokeWidth: strokeWidth, + size: size, + lineDash: lineDash + }; -goog.require('goog.array'); -goog.require('goog.object'); + if (atlasManager === undefined) { + // no atlas manager is used, create a new canvas + this.canvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + this.canvas_.height = size; + this.canvas_.width = size; + // canvas.width and height are rounded to the closest integer + size = this.canvas_.width; + imageSize = size; -// We treat an object as a dictionary if it has getKeys or it is an object that -// isn't arrayLike. + // draw the circle on the canvas + var context = /** @type {CanvasRenderingContext2D} */ + (this.canvas_.getContext('2d')); + this.draw_(renderOptions, context, 0, 0); + this.createHitDetectionCanvas_(renderOptions); + } else { + // an atlas manager is used, add the symbol to an atlas + size = Math.round(size); -/** - * Returns the number of values in the collection-like object. - * @param {Object} col The collection-like object. - * @return {number} The number of values in the collection-like object. - */ -goog.structs.getCount = function(col) { - if (typeof col.getCount == 'function') { - return col.getCount(); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return col.length; - } - return goog.object.getCount(col); -}; + var hasCustomHitDetectionImage = !this.fill_; + var renderHitDetectionCallback; + if (hasCustomHitDetectionImage) { + // render the hit-detection image into a separate atlas image + renderHitDetectionCallback = + goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); + } + var id = this.getChecksum(); + var info = atlasManager.add( + id, size, size, goog.bind(this.draw_, this, renderOptions), + renderHitDetectionCallback); + goog.asserts.assert(info, 'circle radius is too large'); -/** - * Returns the values of the collection-like object. - * @param {Object} col The collection-like object. - * @return {!Array<?>} The values in the collection-like object. - */ -goog.structs.getValues = function(col) { - if (typeof col.getValues == 'function') { - return col.getValues(); - } - if (goog.isString(col)) { - return col.split(''); - } - if (goog.isArrayLike(col)) { - var rv = []; - var l = col.length; - for (var i = 0; i < l; i++) { - rv.push(col[i]); + this.canvas_ = info.image; + this.origin_ = [info.offsetX, info.offsetY]; + imageSize = info.image.width; + + if (hasCustomHitDetectionImage) { + this.hitDetectionCanvas_ = info.hitImage; + this.hitDetectionImageSize_ = + [info.hitImage.width, info.hitImage.height]; + } else { + this.hitDetectionCanvas_ = this.canvas_; + this.hitDetectionImageSize_ = [imageSize, imageSize]; } - return rv; } - return goog.object.getValues(col); + + this.anchor_ = [size / 2, size / 2]; + this.size_ = [size, size]; + this.imageSize_ = [imageSize, imageSize]; }; /** - * Returns the keys of the collection. Some collections have no notion of - * keys/indexes and this function will return undefined in those cases. - * @param {Object} col The collection-like object. - * @return {!Array|undefined} The keys in the collection. + * @private + * @param {ol.style.Circle.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). */ -goog.structs.getKeys = function(col) { - if (typeof col.getKeys == 'function') { - return col.getKeys(); - } - // if we have getValues but no getKeys we know this is a key-less collection - if (typeof col.getValues == 'function') { - return undefined; +ol.style.Circle.prototype.draw_ = function(renderOptions, context, x, y) { + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); + + // then move to (x, y) + context.translate(x, y); + + context.beginPath(); + context.arc( + renderOptions.size / 2, renderOptions.size / 2, + this.radius_, 0, 2 * Math.PI, true); + + if (this.fill_) { + context.fillStyle = ol.color.asString(this.fill_.getColor()); + context.fill(); } - if (goog.isArrayLike(col) || goog.isString(col)) { - var rv = []; - var l = col.length; - for (var i = 0; i < l; i++) { - rv.push(i); + if (this.stroke_) { + context.strokeStyle = renderOptions.strokeStyle; + context.lineWidth = renderOptions.strokeWidth; + if (renderOptions.lineDash) { + context.setLineDash(renderOptions.lineDash); } - return rv; + context.stroke(); } - - return goog.object.getKeys(col); + context.closePath(); }; /** - * Whether the collection contains the given value. This is O(n) and uses - * equals (==) to test the existence. - * @param {Object} col The collection-like object. - * @param {*} val The value to check for. - * @return {boolean} True if the map contains the value. + * @private + * @param {ol.style.Circle.RenderOptions} renderOptions */ -goog.structs.contains = function(col, val) { - if (typeof col.contains == 'function') { - return col.contains(val); - } - if (typeof col.containsValue == 'function') { - return col.containsValue(val); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.contains(/** @type {!Array<?>} */ (col), val); +ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) { + this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; + if (this.fill_) { + this.hitDetectionCanvas_ = this.canvas_; + return; } - return goog.object.containsValue(col, val); + + // if no fill style is set, create an extra hit-detection image with a + // default fill style + this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + var canvas = this.hitDetectionCanvas_; + + canvas.height = renderOptions.size; + canvas.width = renderOptions.size; + + var context = /** @type {CanvasRenderingContext2D} */ + (canvas.getContext('2d')); + this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); }; /** - * Whether the collection is empty. - * @param {Object} col The collection-like object. - * @return {boolean} True if empty. + * @private + * @param {ol.style.Circle.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). */ -goog.structs.isEmpty = function(col) { - if (typeof col.isEmpty == 'function') { - return col.isEmpty(); - } +ol.style.Circle.prototype.drawHitDetectionCanvas_ = + function(renderOptions, context, x, y) { + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); - // We do not use goog.string.isEmptyOrWhitespace because here we treat the string as - // collection and as such even whitespace matters + // then move to (x, y) + context.translate(x, y); - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.isEmpty(/** @type {!Array<?>} */ (col)); + context.beginPath(); + context.arc( + renderOptions.size / 2, renderOptions.size / 2, + this.radius_, 0, 2 * Math.PI, true); + + context.fillStyle = ol.color.asString(ol.render.canvas.defaultFillStyle); + context.fill(); + if (this.stroke_) { + context.strokeStyle = renderOptions.strokeStyle; + context.lineWidth = renderOptions.strokeWidth; + if (renderOptions.lineDash) { + context.setLineDash(renderOptions.lineDash); + } + context.stroke(); } - return goog.object.isEmpty(col); + context.closePath(); }; /** - * Removes all the elements from the collection. - * @param {Object} col The collection-like object. + * @inheritDoc */ -goog.structs.clear = function(col) { - // NOTE(arv): This should not contain strings because strings are immutable - if (typeof col.clear == 'function') { - col.clear(); - } else if (goog.isArrayLike(col)) { - goog.array.clear(/** @type {goog.array.ArrayLike} */ (col)); - } else { - goog.object.clear(col); - } -}; +ol.style.Circle.prototype.getChecksum = function() { + var strokeChecksum = this.stroke_ ? + this.stroke_.getChecksum() : '-'; + var fillChecksum = this.fill_ ? + this.fill_.getChecksum() : '-'; + var recalculate = !this.checksums_ || + (strokeChecksum != this.checksums_[1] || + fillChecksum != this.checksums_[2] || + this.radius_ != this.checksums_[3]); -/** - * Calls a function for each value in a collection. The function takes - * three arguments; the value, the key and the collection. - * - * NOTE: This will be deprecated soon! Please use a more specific method if - * possible, e.g. goog.array.forEach, goog.object.forEach, etc. - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):?} f The function to call for every value. - * This function takes - * 3 arguments (the value, the key or undefined if the collection has no - * notion of keys, and the collection) and the return value is irrelevant. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @template T,S - */ -goog.structs.forEach = function(col, f, opt_obj) { - if (typeof col.forEach == 'function') { - col.forEach(f, opt_obj); - } else if (goog.isArrayLike(col) || goog.isString(col)) { - goog.array.forEach(/** @type {!Array<?>} */ (col), f, opt_obj); - } else { - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - f.call(opt_obj, values[i], keys && keys[i], col); - } + if (recalculate) { + var checksum = 'c' + strokeChecksum + fillChecksum + + (this.radius_ !== undefined ? this.radius_.toString() : '-'); + this.checksums_ = [checksum, strokeChecksum, fillChecksum, this.radius_]; } + + return this.checksums_[0]; }; +goog.provide('ol.style.GeometryFunction'); +goog.provide('ol.style.Style'); +goog.provide('ol.style.StyleFunction'); +goog.provide('ol.style.defaultGeometryFunction'); -/** - * Calls a function for every value in the collection. When a call returns true, - * adds the value to a new collection (Array is returned by default). - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):boolean} f The function to call for every - * value. This function takes - * 3 arguments (the value, the key or undefined if the collection has no - * notion of keys, and the collection) and should return a Boolean. If the - * return value is true the value is added to the result collection. If it - * is false the value is not included. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {!Object|!Array<?>} A new collection where the passed values are - * present. If col is a key-less collection an array is returned. If col - * has keys and values a plain old JS object is returned. - * @template T,S - */ -goog.structs.filter = function(col, f, opt_obj) { - if (typeof col.filter == 'function') { - return col.filter(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.filter(/** @type {!Array<?>} */ (col), f, opt_obj); - } +goog.require('goog.asserts'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Image'); +goog.require('ol.style.Stroke'); - var rv; - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - if (keys) { - rv = {}; - for (var i = 0; i < l; i++) { - if (f.call(opt_obj, values[i], keys[i], col)) { - rv[keys[i]] = values[i]; - } - } - } else { - // We should not use goog.array.filter here since we want to make sure that - // the index is undefined as well as make sure that col is passed to the - // function. - rv = []; - for (var i = 0; i < l; i++) { - if (f.call(opt_obj, values[i], undefined, col)) { - rv.push(values[i]); - } - } - } - return rv; -}; /** - * Calls a function for every value in the collection and adds the result into a - * new collection (defaults to creating a new Array). + * @classdesc + * Container for vector feature rendering styles. Any changes made to the style + * or its children through `set*()` methods will not take effect until the + * feature or layer that uses the style is re-rendered. * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):V} f The function to call for every value. - * This function takes 3 arguments (the value, the key or undefined if the - * collection has no notion of keys, and the collection) and should return - * something. The result will be used as the value in the new collection. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {!Object<V>|!Array<V>} A new collection with the new values. If - * col is a key-less collection an array is returned. If col has keys and - * values a plain old JS object is returned. - * @template T,S,V + * @constructor + * @param {olx.style.StyleOptions=} opt_options Style options. + * @api */ -goog.structs.map = function(col, f, opt_obj) { - if (typeof col.map == 'function') { - return col.map(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.map(/** @type {!Array<?>} */ (col), f, opt_obj); - } +ol.style.Style = function(opt_options) { - var rv; - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - if (keys) { - rv = {}; - for (var i = 0; i < l; i++) { - rv[keys[i]] = f.call(opt_obj, values[i], keys[i], col); - } - } else { - // We should not use goog.array.map here since we want to make sure that - // the index is undefined as well as make sure that col is passed to the - // function. - rv = []; - for (var i = 0; i < l; i++) { - rv[i] = f.call(opt_obj, values[i], undefined, col); - } + var options = opt_options || {}; + + /** + * @private + * @type {string|ol.geom.Geometry|ol.style.GeometryFunction} + */ + this.geometry_ = null; + + /** + * @private + * @type {!ol.style.GeometryFunction} + */ + this.geometryFunction_ = ol.style.defaultGeometryFunction; + + if (options.geometry !== undefined) { + this.setGeometry(options.geometry); } - return rv; + + /** + * @private + * @type {ol.style.Fill} + */ + this.fill_ = options.fill !== undefined ? options.fill : null; + + /** + * @private + * @type {ol.style.Image} + */ + this.image_ = options.image !== undefined ? options.image : null; + + /** + * @private + * @type {ol.style.Stroke} + */ + this.stroke_ = options.stroke !== undefined ? options.stroke : null; + + /** + * @private + * @type {ol.style.Text} + */ + this.text_ = options.text !== undefined ? options.text : null; + + /** + * @private + * @type {number|undefined} + */ + this.zIndex_ = options.zIndex; + }; /** - * Calls f for each value in a collection. If any call returns true this returns - * true (without checking the rest). If all returns false this returns false. - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):boolean} f The function to call for every - * value. This function takes 3 arguments (the value, the key or undefined - * if the collection has no notion of keys, and the collection) and should - * return a boolean. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {boolean} True if any value passes the test. - * @template T,S + * Get the geometry to be rendered. + * @return {string|ol.geom.Geometry|ol.style.GeometryFunction} + * Feature property or geometry or function that returns the geometry that will + * be rendered with this style. + * @api */ -goog.structs.some = function(col, f, opt_obj) { - if (typeof col.some == 'function') { - return col.some(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.some(/** @type {!Array<?>} */ (col), f, opt_obj); - } - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - if (f.call(opt_obj, values[i], keys && keys[i], col)) { - return true; - } - } - return false; +ol.style.Style.prototype.getGeometry = function() { + return this.geometry_; }; /** - * Calls f for each value in a collection. If all calls return true this return - * true this returns true. If any returns false this returns false at this point - * and does not continue to check the remaining values. - * - * @param {S} col The collection-like object. - * @param {function(this:T,?,?,S):boolean} f The function to call for every - * value. This function takes 3 arguments (the value, the key or - * undefined if the collection has no notion of keys, and the collection) - * and should return a boolean. - * @param {T=} opt_obj The object to be used as the value of 'this' - * within {@code f}. - * @return {boolean} True if all key-value pairs pass the test. - * @template T,S + * Get the function used to generate a geometry for rendering. + * @return {!ol.style.GeometryFunction} Function that is called with a feature + * and returns the geometry to render instead of the feature's geometry. + * @api */ -goog.structs.every = function(col, f, opt_obj) { - if (typeof col.every == 'function') { - return col.every(f, opt_obj); - } - if (goog.isArrayLike(col) || goog.isString(col)) { - return goog.array.every(/** @type {!Array<?>} */ (col), f, opt_obj); - } - var keys = goog.structs.getKeys(col); - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - if (!f.call(opt_obj, values[i], keys && keys[i], col)) { - return false; - } - } - return true; +ol.style.Style.prototype.getGeometryFunction = function() { + return this.geometryFunction_; }; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Defines the collection interface. - * - * @author nnaze@google.com (Nathan Naze) + * Get the fill style. + * @return {ol.style.Fill} Fill style. + * @api */ - -goog.provide('goog.structs.Collection'); - +ol.style.Style.prototype.getFill = function() { + return this.fill_; +}; /** - * An interface for a collection of values. - * @interface - * @template T + * Get the image style. + * @return {ol.style.Image} Image style. + * @api */ -goog.structs.Collection = function() {}; +ol.style.Style.prototype.getImage = function() { + return this.image_; +}; /** - * @param {T} value Value to add to the collection. + * Get the stroke style. + * @return {ol.style.Stroke} Stroke style. + * @api */ -goog.structs.Collection.prototype.add; +ol.style.Style.prototype.getStroke = function() { + return this.stroke_; +}; /** - * @param {T} value Value to remove from the collection. + * Get the text style. + * @return {ol.style.Text} Text style. + * @api */ -goog.structs.Collection.prototype.remove; +ol.style.Style.prototype.getText = function() { + return this.text_; +}; /** - * @param {T} value Value to find in the collection. - * @return {boolean} Whether the collection contains the specified value. + * Get the z-index for the style. + * @return {number|undefined} ZIndex. + * @api */ -goog.structs.Collection.prototype.contains; +ol.style.Style.prototype.getZIndex = function() { + return this.zIndex_; +}; /** - * @return {number} The number of values stored in the collection. + * Set a geometry that is rendered instead of the feature's geometry. + * + * @param {string|ol.geom.Geometry|ol.style.GeometryFunction} geometry + * Feature property or geometry or function returning a geometry to render + * for this style. + * @api */ -goog.structs.Collection.prototype.getCount; - +ol.style.Style.prototype.setGeometry = function(geometry) { + if (goog.isFunction(geometry)) { + this.geometryFunction_ = geometry; + } else if (goog.isString(geometry)) { + this.geometryFunction_ = function(feature) { + var result = feature.get(geometry); + if (result) { + goog.asserts.assertInstanceof(result, ol.geom.Geometry, + 'feature geometry must be an ol.geom.Geometry instance'); + } + return result; + }; + } else if (!geometry) { + this.geometryFunction_ = ol.style.defaultGeometryFunction; + } else if (geometry !== undefined) { + goog.asserts.assertInstanceof(geometry, ol.geom.Geometry, + 'geometry must be an ol.geom.Geometry instance'); + this.geometryFunction_ = function() { + return geometry; + }; + } + this.geometry_ = geometry; +}; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Python style iteration utilities. - * @author arv@google.com (Erik Arvidsson) + * Set the z-index. + * + * @param {number|undefined} zIndex ZIndex. + * @api */ - - -goog.provide('goog.iter'); -goog.provide('goog.iter.Iterable'); -goog.provide('goog.iter.Iterator'); -goog.provide('goog.iter.StopIteration'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.math'); +ol.style.Style.prototype.setZIndex = function(zIndex) { + this.zIndex_ = zIndex; +}; /** - * @typedef {goog.iter.Iterator|{length:number}|{__iterator__}} + * A function that takes an {@link ol.Feature} and a `{number}` representing + * the view's resolution. The function should return an array of + * {@link ol.style.Style}. This way e.g. a vector layer can be styled. + * + * @typedef {function((ol.Feature|ol.render.Feature), number): + * (ol.style.Style|Array.<ol.style.Style>)} + * @api */ -goog.iter.Iterable; +ol.style.StyleFunction; /** - * Singleton Error object that is used to terminate iterations. - * @const {!Error} + * Convert the provided object into a style function. Functions passed through + * unchanged. Arrays of ol.style.Style or single style objects wrapped in a + * new style function. + * @param {ol.style.StyleFunction|Array.<ol.style.Style>|ol.style.Style} obj + * A style function, a single style, or an array of styles. + * @return {ol.style.StyleFunction} A style function. */ -goog.iter.StopIteration = ('StopIteration' in goog.global) ? - // For script engines that support legacy iterators. - goog.global['StopIteration'] : - { message: 'StopIteration', stack: ''}; +ol.style.createStyleFunction = function(obj) { + var styleFunction; + if (goog.isFunction(obj)) { + styleFunction = obj; + } else { + /** + * @type {Array.<ol.style.Style>} + */ + var styles; + if (goog.isArray(obj)) { + styles = obj; + } else { + goog.asserts.assertInstanceof(obj, ol.style.Style, + 'obj geometry must be an ol.style.Style instance'); + styles = [obj]; + } + styleFunction = function() { + return styles; + }; + } + return styleFunction; +}; /** - * Class/interface for iterators. An iterator needs to implement a {@code next} - * method and it needs to throw a {@code goog.iter.StopIteration} when the - * iteration passes beyond the end. Iterators have no {@code hasNext} method. - * It is recommended to always use the helper functions to iterate over the - * iterator or in case you are only targeting JavaScript 1.7 for in loops. - * @constructor - * @template VALUE + * @type {Array.<ol.style.Style>} + * @private */ -goog.iter.Iterator = function() {}; +ol.style.defaultStyle_ = null; /** - * Returns the next value of the iteration. This will throw the object - * {@see goog.iter#StopIteration} when the iteration passes the end. - * @return {VALUE} Any object or value. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {number} resolution Resolution. + * @return {Array.<ol.style.Style>} Style. */ -goog.iter.Iterator.prototype.next = function() { - throw goog.iter.StopIteration; +ol.style.defaultStyleFunction = function(feature, resolution) { + // We don't use an immediately-invoked function + // and a closure so we don't get an error at script evaluation time in + // browsers that do not support Canvas. (ol.style.Circle does + // canvas.getContext('2d') at construction time, which will cause an.error + // in such browsers.) + if (!ol.style.defaultStyle_) { + var fill = new ol.style.Fill({ + color: 'rgba(255,255,255,0.4)' + }); + var stroke = new ol.style.Stroke({ + color: '#3399CC', + width: 1.25 + }); + ol.style.defaultStyle_ = [ + new ol.style.Style({ + image: new ol.style.Circle({ + fill: fill, + stroke: stroke, + radius: 5 + }), + fill: fill, + stroke: stroke + }) + ]; + } + return ol.style.defaultStyle_; }; /** - * Returns the {@code Iterator} object itself. This is used to implement - * the iterator protocol in JavaScript 1.7 - * @param {boolean=} opt_keys Whether to return the keys or values. Default is - * to only return the values. This is being used by the for-in loop (true) - * and the for-each-in loop (false). Even though the param gives a hint - * about what the iterator will return there is no guarantee that it will - * return the keys when true is passed. - * @return {!goog.iter.Iterator<VALUE>} The object itself. + * Default styles for editing features. + * @return {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} Styles */ -goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) { - return this; -}; - - -/** - * Returns an iterator that knows how to iterate over the values in the object. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable If the - * object is an iterator it will be returned as is. If the object has an - * {@code __iterator__} method that will be called to get the value - * iterator. If the object is an array-like object we create an iterator - * for that. - * @return {!goog.iter.Iterator<VALUE>} An iterator that knows how to iterate - * over the values in {@code iterable}. - * @template VALUE - */ -goog.iter.toIterator = function(iterable) { - if (iterable instanceof goog.iter.Iterator) { - return iterable; - } - if (typeof iterable.__iterator__ == 'function') { - return iterable.__iterator__(false); - } - if (goog.isArrayLike(iterable)) { - var i = 0; - var newIter = new goog.iter.Iterator; - newIter.next = function() { - while (true) { - if (i >= iterable.length) { - throw goog.iter.StopIteration; - } - // Don't include deleted elements. - if (!(i in iterable)) { - i++; - continue; - } - return iterable[i++]; - } - }; - return newIter; - } +ol.style.createDefaultEditingStyles = function() { + /** @type {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} */ + var styles = {}; + var white = [255, 255, 255, 1]; + var blue = [0, 153, 255, 1]; + var width = 3; + styles[ol.geom.GeometryType.POLYGON] = [ + new ol.style.Style({ + fill: new ol.style.Fill({ + color: [255, 255, 255, 0.5] + }) + }) + ]; + styles[ol.geom.GeometryType.MULTI_POLYGON] = + styles[ol.geom.GeometryType.POLYGON]; + + styles[ol.geom.GeometryType.LINE_STRING] = [ + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: white, + width: width + 2 + }) + }), + new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: blue, + width: width + }) + }) + ]; + styles[ol.geom.GeometryType.MULTI_LINE_STRING] = + styles[ol.geom.GeometryType.LINE_STRING]; + + styles[ol.geom.GeometryType.CIRCLE] = + styles[ol.geom.GeometryType.POLYGON].concat( + styles[ol.geom.GeometryType.LINE_STRING] + ); - // TODO(arv): Should we fall back on goog.structs.getValues()? - throw Error('Not implemented'); + styles[ol.geom.GeometryType.POINT] = [ + new ol.style.Style({ + image: new ol.style.Circle({ + radius: width * 2, + fill: new ol.style.Fill({ + color: blue + }), + stroke: new ol.style.Stroke({ + color: white, + width: width / 2 + }) + }), + zIndex: Infinity + }) + ]; + styles[ol.geom.GeometryType.MULTI_POINT] = + styles[ol.geom.GeometryType.POINT]; + + styles[ol.geom.GeometryType.GEOMETRY_COLLECTION] = + styles[ol.geom.GeometryType.POLYGON].concat( + styles[ol.geom.GeometryType.LINE_STRING], + styles[ol.geom.GeometryType.POINT] + ); + + return styles; }; /** - * Calls a function for each element in the iterator with the element of the - * iterator passed as argument. + * A function that takes an {@link ol.Feature} as argument and returns an + * {@link ol.geom.Geometry} that will be rendered and styled for the feature. * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. If the iterable is an object {@code toIterator} will be - * called on it. - * @param {function(this:THIS,VALUE,?,!goog.iter.Iterator<VALUE>)} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and the return value is - * irrelevant. The reason for passing undefined as the second argument is - * so that the same function can be used in {@see goog.array#forEach} as - * well as others. The third parameter is of type "number" for - * arraylike objects, undefined, otherwise. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @template THIS, VALUE + * @typedef {function((ol.Feature|ol.render.Feature)): + * (ol.geom.Geometry|ol.render.Feature|undefined)} + * @api */ -goog.iter.forEach = function(iterable, f, opt_obj) { - if (goog.isArrayLike(iterable)) { - /** @preserveTry */ - try { - // NOTES: this passes the index number to the second parameter - // of the callback contrary to the documentation above. - goog.array.forEach(/** @type {goog.array.ArrayLike} */(iterable), f, - opt_obj); - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - } else { - iterable = goog.iter.toIterator(iterable); - /** @preserveTry */ - try { - while (true) { - f.call(opt_obj, iterable.next(), undefined, iterable); - } - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - } -}; +ol.style.GeometryFunction; /** - * Calls a function for every element in the iterator, and if the function - * returns true adds the element to a new iterator. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and should return a boolean. - * If the return value is true the element will be included in the returned - * iterator. If it is false the element is not included. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements - * that passed the test are present. - * @template THIS, VALUE + * Function that is called with a feature and returns its default geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry + * for. + * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render. */ -goog.iter.filter = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var newIter = new goog.iter.Iterator; - newIter.next = function() { - while (true) { - var val = iterator.next(); - if (f.call(opt_obj, val, undefined, iterator)) { - return val; - } - } - }; - return newIter; +ol.style.defaultGeometryFunction = function(feature) { + goog.asserts.assert(feature, 'feature must not be null'); + return feature.getGeometry(); }; +goog.exportSymbol('ol.style.defaultStyleFunction', ol.style.defaultStyleFunction); + +goog.provide('ol.layer.Vector'); + +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.layer.Layer'); +goog.require('ol.style.Style'); /** - * Calls a function for every element in the iterator, and if the function - * returns false adds the element to a new iterator. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and should return a boolean. - * If the return value is false the element will be included in the returned - * iterator. If it is true the element is not included. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements - * that did not pass the test are present. - * @template THIS, VALUE + * @enum {string} */ -goog.iter.filterFalse = function(iterable, f, opt_obj) { - return goog.iter.filter(iterable, goog.functions.not(f), opt_obj); +ol.layer.VectorProperty = { + RENDER_ORDER: 'renderOrder' }; + /** - * Creates a new iterator that returns the values in a range. This function - * can take 1, 2 or 3 arguments: - * <pre> - * range(5) same as range(0, 5, 1) - * range(2, 5) same as range(2, 5, 1) - * </pre> + * @classdesc + * Vector data that is rendered client-side. + * Note that any property set in the options is set as a {@link ol.Object} + * property on the layer object; for example, setting `title: 'My Title'` in the + * options means that `title` is observable, and has get/set accessors. * - * @param {number} startOrStop The stop value if only one argument is provided. - * The start value if 2 or more arguments are provided. If only one - * argument is used the start value is 0. - * @param {number=} opt_stop The stop value. If left out then the first - * argument is used as the stop value. - * @param {number=} opt_step The number to increment with between each call to - * next. This can be negative. - * @return {!goog.iter.Iterator<number>} A new iterator that returns the values - * in the range. + * @constructor + * @extends {ol.layer.Layer} + * @fires ol.render.Event + * @param {olx.layer.VectorOptions=} opt_options Options. + * @api stable */ -goog.iter.range = function(startOrStop, opt_stop, opt_step) { - var start = 0; - var stop = startOrStop; - var step = opt_step || 1; - if (arguments.length > 1) { - start = startOrStop; - stop = opt_stop; - } - if (step == 0) { - throw Error('Range step argument must not be zero'); - } +ol.layer.Vector = function(opt_options) { + + var options = opt_options ? + opt_options : /** @type {olx.layer.VectorOptions} */ ({}); + + goog.asserts.assert( + options.renderOrder === undefined || !options.renderOrder || + goog.isFunction(options.renderOrder), + 'renderOrder must be a comparator function'); + + var baseOptions = goog.object.clone(options); + + delete baseOptions.style; + delete baseOptions.renderBuffer; + delete baseOptions.updateWhileAnimating; + delete baseOptions.updateWhileInteracting; + goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); + + /** + * @type {number} + * @private + */ + this.renderBuffer_ = options.renderBuffer !== undefined ? + options.renderBuffer : 100; + + /** + * User provided style. + * @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} + * @private + */ + this.style_ = null; + + /** + * Style function for use within the library. + * @type {ol.style.StyleFunction|undefined} + * @private + */ + this.styleFunction_ = undefined; + + this.setStyle(options.style); + + /** + * @type {boolean} + * @private + */ + this.updateWhileAnimating_ = options.updateWhileAnimating !== undefined ? + options.updateWhileAnimating : false; + + /** + * @type {boolean} + * @private + */ + this.updateWhileInteracting_ = options.updateWhileInteracting !== undefined ? + options.updateWhileInteracting : false; - var newIter = new goog.iter.Iterator; - newIter.next = function() { - if (step > 0 && start >= stop || step < 0 && start <= stop) { - throw goog.iter.StopIteration; - } - var rv = start; - start += step; - return rv; - }; - return newIter; }; +goog.inherits(ol.layer.Vector, ol.layer.Layer); /** - * Joins the values in a iterator with a delimiter. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to get the values from. - * @param {string} deliminator The text to put between the values. - * @return {string} The joined value string. - * @template VALUE + * @return {number|undefined} Render buffer. */ -goog.iter.join = function(iterable, deliminator) { - return goog.iter.toArray(iterable).join(deliminator); +ol.layer.Vector.prototype.getRenderBuffer = function() { + return this.renderBuffer_; }; /** - * For every element in the iterator call a function and return a new iterator - * with that value. - * - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterator to iterate over. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):RESULT} f - * The function to call for every element. This function takes 3 arguments - * (the element, undefined, and the iterator) and should return a new value. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the - * results of applying the function to each element in the original - * iterator. - * @template THIS, VALUE, RESULT + * @return {function(ol.Feature, ol.Feature): number|null|undefined} Render + * order. */ -goog.iter.map = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var newIter = new goog.iter.Iterator; - newIter.next = function() { - var val = iterator.next(); - return f.call(opt_obj, val, undefined, iterator); - }; - return newIter; +ol.layer.Vector.prototype.getRenderOrder = function() { + return /** @type {function(ol.Feature, ol.Feature):number|null|undefined} */ ( + this.get(ol.layer.VectorProperty.RENDER_ORDER)); }; /** - * Passes every element of an iterator into a function and accumulates the - * result. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to iterate over. - * @param {function(this:THIS,VALUE,VALUE):VALUE} f The function to call for - * every element. This function takes 2 arguments (the function's previous - * result or the initial value, and the value of the current element). - * function(previousValue, currentElement) : newValue. - * @param {VALUE} val The initial value to pass into the function on the first - * call. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * f. - * @return {VALUE} Result of evaluating f repeatedly across the values of - * the iterator. - * @template THIS, VALUE + * Return the associated {@link ol.source.Vector vectorsource} of the layer. + * @function + * @return {ol.source.Vector} Source. + * @api stable */ -goog.iter.reduce = function(iterable, f, val, opt_obj) { - var rval = val; - goog.iter.forEach(iterable, function(val) { - rval = f.call(opt_obj, rval, val); - }); - return rval; -}; +ol.layer.Vector.prototype.getSource; /** - * Goes through the values in the iterator. Calls f for each of these, and if - * any of them returns true, this returns true (without checking the rest). If - * all return false this will return false. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {boolean} true if any value passes the test. - * @template THIS, VALUE + * Get the style for features. This returns whatever was passed to the `style` + * option at construction or to the `setStyle` method. + * @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} + * Layer style. + * @api stable */ -goog.iter.some = function(iterable, f, opt_obj) { - iterable = goog.iter.toIterator(iterable); - /** @preserveTry */ - try { - while (true) { - if (f.call(opt_obj, iterable.next(), undefined, iterable)) { - return true; - } - } - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - return false; +ol.layer.Vector.prototype.getStyle = function() { + return this.style_; }; /** - * Goes through the values in the iterator. Calls f for each of these and if any - * of them returns false this returns false (without checking the rest). If all - * return true this will return true. - * - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {boolean} true if every value passes the test. - * @template THIS, VALUE + * Get the style function. + * @return {ol.style.StyleFunction|undefined} Layer style function. + * @api stable */ -goog.iter.every = function(iterable, f, opt_obj) { - iterable = goog.iter.toIterator(iterable); - /** @preserveTry */ - try { - while (true) { - if (!f.call(opt_obj, iterable.next(), undefined, iterable)) { - return false; - } - } - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - } - return true; +ol.layer.Vector.prototype.getStyleFunction = function() { + return this.styleFunction_; }; /** - * Takes zero or more iterables and returns one iterator that will iterate over - * them in the order chained. - * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any - * number of iterable objects. - * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will - * iterate over all the given iterables' contents. - * @template VALUE + * @return {boolean} Whether the rendered layer should be updated while + * animating. */ -goog.iter.chain = function(var_args) { - return goog.iter.chainFromIterable(arguments); +ol.layer.Vector.prototype.getUpdateWhileAnimating = function() { + return this.updateWhileAnimating_; }; /** - * Takes a single iterable containing zero or more iterables and returns one - * iterator that will iterate over each one in the order given. - * @see http://docs.python.org/2/library/itertools.html#itertools.chain.from_iterable - * @param {goog.iter.Iterable} iterable The iterable of iterables to chain. - * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will - * iterate over all the contents of the iterables contained within - * {@code iterable}. - * @template VALUE + * @return {boolean} Whether the rendered layer should be updated while + * interacting. */ -goog.iter.chainFromIterable = function(iterable) { - var iterator = goog.iter.toIterator(iterable); - var iter = new goog.iter.Iterator(); - var current = null; +ol.layer.Vector.prototype.getUpdateWhileInteracting = function() { + return this.updateWhileInteracting_; +}; - iter.next = function() { - while (true) { - if (current == null) { - var it = iterator.next(); - current = goog.iter.toIterator(it); - } - try { - return current.next(); - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - current = null; - } - } - }; - return iter; +/** + * @param {function(ol.Feature, ol.Feature):number|null|undefined} renderOrder + * Render order. + */ +ol.layer.Vector.prototype.setRenderOrder = function(renderOrder) { + goog.asserts.assert( + renderOrder === undefined || !renderOrder || + goog.isFunction(renderOrder), + 'renderOrder must be a comparator function'); + this.set(ol.layer.VectorProperty.RENDER_ORDER, renderOrder); }; /** - * Builds a new iterator that iterates over the original, but skips elements as - * long as a supplied function returns true. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that drops elements from - * the original iterator as long as {@code f} is true. - * @template THIS, VALUE + * Set the style for features. This can be a single style object, an array + * of styles, or a function that takes a feature and resolution and returns + * an array of styles. If it is `undefined` the default style is used. If + * it is `null` the layer has no style (a `null` style), so only features + * that have their own styles will be rendered in the layer. See + * {@link ol.style} for information on the default style. + * @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|null|undefined} + * style Layer style. + * @api stable */ -goog.iter.dropWhile = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var newIter = new goog.iter.Iterator; - var dropping = true; - newIter.next = function() { - while (true) { - var val = iterator.next(); - if (dropping && f.call(opt_obj, val, undefined, iterator)) { - continue; - } else { - dropping = false; - } - return val; - } - }; - return newIter; +ol.layer.Vector.prototype.setStyle = function(style) { + this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction; + this.styleFunction_ = style === null ? + undefined : ol.style.createStyleFunction(this.style_); + this.changed(); }; +goog.provide('olcs.VectorSynchronizer'); + +goog.require('ol.layer.Vector'); +goog.require('olcs.AbstractSynchronizer'); +goog.require('olcs.FeatureConverter'); +goog.require('olcs.core'); +goog.require('olcs.core.VectorLayerCounterpart'); + + /** - * Builds a new iterator that iterates over the original, but only as long as a - * supplied function returns true. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * object. - * @param { - * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f - * The function to call for every value. This function takes 3 arguments - * (the value, undefined, and the iterator) and should return a boolean. - * @param {THIS=} opt_obj This is used as the 'this' object in f when called. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that keeps elements in - * the original iterator as long as the function is true. - * @template THIS, VALUE + * Unidirectionally synchronize OpenLayers vector layers to Cesium. + * @param {!ol.Map} map + * @param {!Cesium.Scene} scene + * @param {olcs.FeatureConverter=} opt_converter + * @constructor + * @extends {olcs.AbstractSynchronizer.<olcs.core.VectorLayerCounterpart>} + * @api + * @struct */ -goog.iter.takeWhile = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var iter = new goog.iter.Iterator(); - iter.next = function() { - var val = iterator.next(); - if (f.call(opt_obj, val, undefined, iterator)) { - return val; - } - throw goog.iter.StopIteration; - }; - return iter; +olcs.VectorSynchronizer = function(map, scene, opt_converter) { + + /** + * @protected + */ + this.converter = opt_converter || new olcs.FeatureConverter(scene); + + /** + * @private + */ + this.csAllPrimitives_ = new Cesium.PrimitiveCollection(); + scene.primitives.add(this.csAllPrimitives_); + this.csAllPrimitives_.destroyPrimitives = false; + + goog.base(this, map, scene); }; +goog.inherits(olcs.VectorSynchronizer, olcs.AbstractSynchronizer); /** - * Converts the iterator to an array - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator - * to convert to an array. - * @return {!Array<VALUE>} An array of the elements the iterator iterates over. - * @template VALUE + * @inheritDoc */ -goog.iter.toArray = function(iterable) { - // Fast path for array-like. - if (goog.isArrayLike(iterable)) { - return goog.array.toArray(/** @type {!goog.array.ArrayLike} */(iterable)); - } - iterable = goog.iter.toIterator(iterable); - var array = []; - goog.iter.forEach(iterable, function(val) { - array.push(val); - }); - return array; +olcs.VectorSynchronizer.prototype.addCesiumObject = function(counterpart) { + goog.asserts.assert(!goog.isNull(counterpart)); + counterpart.getRootPrimitive()['counterpart'] = counterpart; + this.csAllPrimitives_.add(counterpart.getRootPrimitive()); }; /** - * Iterates over two iterables and returns true if they contain the same - * sequence of elements and have the same length. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable1 The first - * iterable object. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable2 The second - * iterable object. - * @param {function(VALUE,VALUE):boolean=} opt_equalsFn Optional comparison - * function. - * Should take two arguments to compare, and return true if the arguments - * are equal. Defaults to {@link goog.array.defaultCompareEquality} which - * compares the elements using the built-in '===' operator. - * @return {boolean} true if the iterables contain the same sequence of elements - * and have the same length. - * @template VALUE + * @inheritDoc */ -goog.iter.equals = function(iterable1, iterable2, opt_equalsFn) { - var fillValue = {}; - var pairs = goog.iter.zipLongest(fillValue, iterable1, iterable2); - var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality; - return goog.iter.every(pairs, function(pair) { - return equalsFn(pair[0], pair[1]); - }); +olcs.VectorSynchronizer.prototype.destroyCesiumObject = function(object) { + object.getRootPrimitive().destroy(); }; /** - * Advances the iterator to the next position, returning the given default value - * instead of throwing an exception if the iterator has no more entries. - * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterable - * object. - * @param {VALUE} defaultValue The value to return if the iterator is empty. - * @return {VALUE} The next item in the iteration, or defaultValue if the - * iterator was empty. - * @template VALUE + * @inheritDoc */ -goog.iter.nextOrValue = function(iterable, defaultValue) { - try { - return goog.iter.toIterator(iterable).next(); - } catch (e) { - if (e != goog.iter.StopIteration) { - throw e; +olcs.VectorSynchronizer.prototype.removeSingleCesiumObject = + function(object, destroy) { + object.destroy(); + this.csAllPrimitives_.destroyPrimitives = destroy; + this.csAllPrimitives_.remove(object.getRootPrimitive()); + this.csAllPrimitives_.destroyPrimitives = false; +}; + + +/** + * @inheritDoc + */ +olcs.VectorSynchronizer.prototype.removeAllCesiumObjects = function(destroy) { + this.csAllPrimitives_.destroyPrimitives = destroy; + if (destroy) { + for (var i = 0; i < this.csAllPrimitives_.length; ++i) { + this.csAllPrimitives_.get(i)['counterpart'].destroy(); } - return defaultValue; } + this.csAllPrimitives_.removeAll(); + this.csAllPrimitives_.destroyPrimitives = false; }; /** - * Cartesian product of zero or more sets. Gives an iterator that gives every - * combination of one element chosen from each set. For example, - * ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]). - * @see http://docs.python.org/library/itertools.html#itertools.product - * @param {...!goog.array.ArrayLike<VALUE>} var_args Zero or more sets, as - * arrays. - * @return {!goog.iter.Iterator<!Array<VALUE>>} An iterator that gives each - * n-tuple (as an array). - * @template VALUE + * @inheritDoc */ -goog.iter.product = function(var_args) { - var someArrayEmpty = goog.array.some(arguments, function(arr) { - return !arr.length; - }); +olcs.VectorSynchronizer.prototype.createSingleLayerCounterparts = + function(olLayer) { + if (!(olLayer instanceof ol.layer.Vector) && + !(olLayer instanceof ol.layer.Image && + olLayer.getSource() instanceof ol.source.ImageVector)) { + return null; + } + goog.asserts.assertInstanceof(olLayer, ol.layer.Layer); - // An empty set in a cartesian product gives an empty set. - if (someArrayEmpty || !arguments.length) { - return new goog.iter.Iterator(); + var source = olLayer.getSource(); + if (source instanceof ol.source.ImageVector) { + source = source.getSource(); } - var iter = new goog.iter.Iterator(); - var arrays = arguments; + goog.asserts.assertInstanceof(source, ol.source.Vector); + goog.asserts.assert(!goog.isNull(this.view)); - // The first indices are [0, 0, ...] - var indicies = goog.array.repeat(0, arrays.length); + var view = this.view; + var featurePrimitiveMap = {}; + var counterpart = this.converter.olVectorLayerToCesium(olLayer, view, + featurePrimitiveMap); + var csPrimitives = counterpart.getRootPrimitive(); + var olListenKeys = counterpart.olListenKeys; - iter.next = function() { + csPrimitives.show = olLayer.getVisible(); - if (indicies) { - var retVal = goog.array.map(indicies, function(valueIndex, arrayIndex) { - return arrays[arrayIndex][valueIndex]; - }); + olListenKeys.push(olLayer.on('change:visible', function(e) { + csPrimitives.show = olLayer.getVisible(); + })); - // Generate the next-largest indices for the next call. - // Increase the rightmost index. If it goes over, increase the next - // rightmost (like carry-over addition). - for (var i = indicies.length - 1; i >= 0; i--) { - // Assertion prevents compiler warning below. - goog.asserts.assert(indicies); - if (indicies[i] < arrays[i].length - 1) { - indicies[i]++; - break; - } + var onAddFeature = (function(feature) { + goog.asserts.assert( + (olLayer instanceof ol.layer.Vector) || + (olLayer instanceof ol.layer.Image) + ); + var context = counterpart.context; + var prim = this.converter.convert(olLayer, view, feature, context); + if (prim) { + featurePrimitiveMap[goog.getUid(feature)] = prim; + csPrimitives.add(prim); + } + }).bind(this); - // We're at the last indices (the last element of every array), so - // the iteration is over on the next call. - if (i == 0) { - indicies = null; - break; - } - // Reset the index in this column and loop back to increment the - // next one. - indicies[i] = 0; + var onRemoveFeature = (function(feature) { + var geometry = feature.getGeometry(); + var id = goog.getUid(feature); + if (!geometry || geometry.getType() == 'Point') { + var context = counterpart.context; + var bb = context.featureToCesiumMap[id]; + delete context.featureToCesiumMap[id]; + if (bb instanceof Cesium.Billboard) { + context.billboards.remove(bb); } - return retVal; } + var csPrimitive = featurePrimitiveMap[id]; + delete featurePrimitiveMap[id]; + if (goog.isDefAndNotNull(csPrimitive)) { + csPrimitives.remove(csPrimitive); + } + }).bind(this); - throw goog.iter.StopIteration; - }; + olListenKeys.push(source.on('addfeature', function(e) { + goog.asserts.assert(goog.isDefAndNotNull(e.feature)); + onAddFeature(e.feature); + }, this)); - return iter; + olListenKeys.push(source.on('removefeature', function(e) { + goog.asserts.assert(goog.isDefAndNotNull(e.feature)); + onRemoveFeature(e.feature); + }, this)); + + olListenKeys.push(source.on('changefeature', function(e) { + var feature = e.feature; + goog.asserts.assert(goog.isDefAndNotNull(feature)); + onRemoveFeature(feature); + onAddFeature(feature); + }, this)); + + return counterpart ? [counterpart] : null; }; +goog.provide('olcs.OLCesium'); + +goog.require('goog.async.AnimationDelay'); +goog.require('goog.dom'); +goog.require('olcs.AutoRenderLoop'); +goog.require('olcs.Camera'); +goog.require('olcs.RasterSynchronizer'); +goog.require('olcs.VectorSynchronizer'); + + /** - * Create an iterator to cycle over the iterable's elements indefinitely. - * For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ... - * @see: http://docs.python.org/library/itertools.html#itertools.cycle. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable object. - * @return {!goog.iter.Iterator<VALUE>} An iterator that iterates indefinitely - * over the values in {@code iterable}. - * @template VALUE + * @param {!olcsx.OLCesiumOptions} options Options. + * @constructor + * @api + * @struct */ -goog.iter.cycle = function(iterable) { - var baseIterator = goog.iter.toIterator(iterable); +olcs.OLCesium = function(options) { - // We maintain a cache to store the iterable elements as we iterate - // over them. The cache is used to return elements once we have - // iterated over the iterable once. - var cache = []; - var cacheIndex = 0; + /** + * @type {olcs.AutoRenderLoop} + * @private + */ + this.autoRenderLoop_ = null; - var iter = new goog.iter.Iterator(); + /** + * @type {!ol.Map} + * @private + */ + this.map_ = options.map; - // This flag is set after the iterable is iterated over once - var useCache = false; + /** + * @type {number} + * @private + */ + this.resolutionScale_ = 1.0; - iter.next = function() { - var returnElement = null; + /** + * @type {number} + * @private + */ + this.canvasClientWidth_ = 0.0; - // Pull elements off the original iterator if not using cache - if (!useCache) { - try { - // Return the element from the iterable - returnElement = baseIterator.next(); - cache.push(returnElement); - return returnElement; - } catch (e) { - // If an exception other than StopIteration is thrown - // or if there are no elements to iterate over (the iterable was empty) - // throw an exception - if (e != goog.iter.StopIteration || goog.array.isEmpty(cache)) { - throw e; - } - // set useCache to true after we know that a 'StopIteration' exception - // was thrown and the cache is not empty (to handle the 'empty iterable' - // use case) - useCache = true; - } - } + /** + * @type {number} + * @private + */ + this.canvasClientHeight_ = 0.0; - returnElement = cache[cacheIndex]; - cacheIndex = (cacheIndex + 1) % cache.length; + /** + * @type {boolean} + * @private + */ + this.resolutionScaleChanged_ = true; // force resize - return returnElement; - }; + var fillArea = 'position:absolute;top:0;left:0;width:100%;height:100%;'; - return iter; -}; + /** + * @type {!Element} + * @private + */ + this.container_ = goog.dom.createDom(goog.dom.TagName.DIV, + {style: fillArea + 'visibility:hidden;'}); + var targetElement = goog.dom.getElement(options.target || null); + if (targetElement) { + goog.dom.appendChild(targetElement, this.container_); + } else { + var vp = this.map_.getViewport(); + var oc = goog.dom.getElementByClass('ol-overlaycontainer', vp); + if (oc) { + goog.dom.insertSiblingBefore(this.container_, oc); + } + } -/** - * Creates an iterator that counts indefinitely from a starting value. - * @see http://docs.python.org/2/library/itertools.html#itertools.count - * @param {number=} opt_start The starting value. Default is 0. - * @param {number=} opt_step The number to increment with between each call to - * next. Negative and floating point numbers are allowed. Default is 1. - * @return {!goog.iter.Iterator<number>} A new iterator that returns the values - * in the series. - */ -goog.iter.count = function(opt_start, opt_step) { - var counter = opt_start || 0; - var step = goog.isDef(opt_step) ? opt_step : 1; - var iter = new goog.iter.Iterator(); + /** + * Whether the Cesium container is placed over the ol map. + * @type {boolean} + * @private + */ + this.isOverMap_ = !goog.isDefAndNotNull(targetElement); - iter.next = function() { - var returnValue = counter; - counter += step; - return returnValue; - }; + /** + * @type {!HTMLCanvasElement} + * @private + */ + this.canvas_ = /** @type {!HTMLCanvasElement} */ + (goog.dom.createDom(goog.dom.TagName.CANVAS, {style: fillArea})); + this.canvas_.oncontextmenu = function() { return false; }; + this.canvas_.onselectstart = function() { return false; }; - return iter; -}; + goog.dom.appendChild(this.container_, this.canvas_); + /** + * @type {boolean} + * @private + */ + this.enabled_ = false; -/** - * Creates an iterator that returns the same object or value repeatedly. - * @param {VALUE} value Any object or value to repeat. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the - * repeated value. - * @template VALUE - */ -goog.iter.repeat = function(value) { - var iter = new goog.iter.Iterator(); + /** + * @type {!Array.<ol.interaction.Interaction>} + * @private + */ + this.pausedInteractions_ = []; - iter.next = goog.functions.constant(value); + /** + * @type {?ol.layer.Group} + * @private + */ + this.hiddenRootGroup_ = null; - return iter; -}; + /** + * @type {!Cesium.Scene} + * @private + */ + this.scene_ = new Cesium.Scene({ + canvas: this.canvas_, + scene3DOnly: true + }); + var sscc = this.scene_.screenSpaceCameraController; + sscc.inertiaSpin = 0; + sscc.inertiaTranslate = 0; + sscc.inertiaZoom = 0; -/** - * Creates an iterator that returns running totals from the numbers in - * {@code iterable}. For example, the array {@code [1, 2, 3, 4, 5]} yields - * {@code 1 -> 3 -> 6 -> 10 -> 15}. - * @see http://docs.python.org/3.2/library/itertools.html#itertools.accumulate - * @param {!goog.iter.Iterable<number>} iterable The iterable of numbers to - * accumulate. - * @return {!goog.iter.Iterator<number>} A new iterator that returns the - * numbers in the series. - */ -goog.iter.accumulate = function(iterable) { - var iterator = goog.iter.toIterator(iterable); - var total = 0; - var iter = new goog.iter.Iterator(); + sscc.tiltEventTypes.push({ + 'eventType': Cesium.CameraEventType.LEFT_DRAG, + 'modifier': Cesium.KeyboardEventModifier.SHIFT + }); - iter.next = function() { - total += iterator.next(); - return total; - }; + sscc.tiltEventTypes.push({ + 'eventType': Cesium.CameraEventType.LEFT_DRAG, + 'modifier': Cesium.KeyboardEventModifier.ALT + }); - return iter; -}; + sscc.enableLook = false; + this.scene_.camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z; -/** - * Creates an iterator that returns arrays containing the ith elements from the - * provided iterables. The returned arrays will be the same size as the number - * of iterables given in {@code var_args}. Once the shortest iterable is - * exhausted, subsequent calls to {@code next()} will throw - * {@code goog.iter.StopIteration}. - * @see http://docs.python.org/2/library/itertools.html#itertools.izip - * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any - * number of iterable objects. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns - * arrays of elements from the provided iterables. - * @template VALUE - */ -goog.iter.zip = function(var_args) { - var args = arguments; - var iter = new goog.iter.Iterator(); - - if (args.length > 0) { - var iterators = goog.array.map(args, goog.iter.toIterator); - iter.next = function() { - var arr = goog.array.map(iterators, function(it) { - return it.next(); - }); - return arr; - }; - } - - return iter; -}; + /** + * @type {!olcs.Camera} + * @private + */ + this.camera_ = new olcs.Camera(this.scene_, this.map_); + /** + * @type {!Cesium.Globe} + * @private + */ + this.globe_ = new Cesium.Globe(Cesium.Ellipsoid.WGS84); + this.scene_.globe = this.globe_; + this.scene_.skyAtmosphere = new Cesium.SkyAtmosphere(); -/** - * Creates an iterator that returns arrays containing the ith elements from the - * provided iterables. The returned arrays will be the same size as the number - * of iterables given in {@code var_args}. Shorter iterables will be extended - * with {@code fillValue}. Once the longest iterable is exhausted, subsequent - * calls to {@code next()} will throw {@code goog.iter.StopIteration}. - * @see http://docs.python.org/2/library/itertools.html#itertools.izip_longest - * @param {VALUE} fillValue The object or value used to fill shorter iterables. - * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any - * number of iterable objects. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns - * arrays of elements from the provided iterables. - * @template VALUE - */ -goog.iter.zipLongest = function(fillValue, var_args) { - var args = goog.array.slice(arguments, 1); - var iter = new goog.iter.Iterator(); + this.dataSourceCollection_ = new Cesium.DataSourceCollection(); + this.dataSourceDisplay_ = new Cesium.DataSourceDisplay({ + scene: this.scene_, + dataSourceCollection: this.dataSourceCollection_ + }); - if (args.length > 0) { - var iterators = goog.array.map(args, goog.iter.toIterator); + var synchronizers = goog.isDef(options.createSynchronizers) ? + options.createSynchronizers(this.map_, this.scene_) : + [ + new olcs.RasterSynchronizer(this.map_, this.scene_), + new olcs.VectorSynchronizer(this.map_, this.scene_) + ]; - iter.next = function() { - var iteratorsHaveValues = false; // false when all iterators are empty. - var arr = goog.array.map(iterators, function(it) { - var returnValue; - try { - returnValue = it.next(); - // Iterator had a value, so we've not exhausted the iterators. - // Set flag accordingly. - iteratorsHaveValues = true; - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - returnValue = fillValue; - } - return returnValue; - }); + // Assures correct canvas size after initialisation + this.handleResize_(); - if (!iteratorsHaveValues) { - throw goog.iter.StopIteration; - } - return arr; - }; + for (var i = synchronizers.length - 1; i >= 0; --i) { + synchronizers[i].synchronize(); } - return iter; -}; - + if (this.isOverMap_) { + // if in "stacked mode", hide everything except canvas (including credits) + var credits = goog.dom.getNextElementSibling(this.canvas_); + if (goog.isDefAndNotNull(credits)) { + credits.style.display = 'none'; + } + } -/** - * Creates an iterator that filters {@code iterable} based on a series of - * {@code selectors}. On each call to {@code next()}, one item is taken from - * both the {@code iterable} and {@code selectors} iterators. If the item from - * {@code selectors} evaluates to true, the item from {@code iterable} is given. - * Otherwise, it is skipped. Once either {@code iterable} or {@code selectors} - * is exhausted, subsequent calls to {@code next()} will throw - * {@code goog.iter.StopIteration}. - * @see http://docs.python.org/2/library/itertools.html#itertools.compress - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to filter. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} selectors An - * iterable of items to be evaluated in a boolean context to determine if - * the corresponding element in {@code iterable} should be included in the - * result. - * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the - * filtered values. - * @template VALUE - */ -goog.iter.compress = function(iterable, selectors) { - var selectorIterator = goog.iter.toIterator(selectors); + this.cesiumRenderingDelay_ = new goog.async.AnimationDelay(function(time) { + if (!this.blockCesiumRendering_) { + var julianDate = Cesium.JulianDate.now(); + this.scene_.initializeFrame(); + this.handleResize_(); + this.dataSourceDisplay_.update(julianDate); + this.scene_.render(julianDate); + this.enabled_ && this.camera_.checkCameraChange(); + } + this.cesiumRenderingDelay_.start(); + }, undefined, this); - return goog.iter.filter(iterable, function() { - return !!selectorIterator.next(); - }); + /** + * @private + */ + this.blockCesiumRendering_ = false; }; - /** - * Implements the {@code goog.iter.groupBy} iterator. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to group. - * @param {function(...VALUE): KEY=} opt_keyFunc Optional function for - * determining the key value for each group in the {@code iterable}. Default - * is the identity function. - * @constructor - * @extends {goog.iter.Iterator<!Array<?>>} - * @template KEY, VALUE * @private */ -goog.iter.GroupByIterator_ = function(iterable, opt_keyFunc) { - - /** - * The iterable to group, coerced to an iterator. - * @type {!goog.iter.Iterator} - */ - this.iterator = goog.iter.toIterator(iterable); - - /** - * A function for determining the key value for each element in the iterable. - * If no function is provided, the identity function is used and returns the - * element unchanged. - * @type {function(...VALUE): KEY} - */ - this.keyFunc = opt_keyFunc || goog.functions.identity; +olcs.OLCesium.prototype.handleResize_ = function() { + var width = this.canvas_.clientWidth; + var height = this.canvas_.clientHeight; - /** - * The target key for determining the start of a group. - * @type {KEY} - */ - this.targetKey; + if (width === this.canvasClientWidth_ && + height === this.canvasClientHeight_ && + !this.resolutionScaleChanged_) { + return; + } - /** - * The current key visited during iteration. - * @type {KEY} - */ - this.currentKey; + var zoomFactor = (window.devicePixelRatio || 1.0) * this.resolutionScale_; + this.resolutionScaleChanged_ = false; - /** - * The current value being added to the group. - * @type {VALUE} - */ - this.currentValue; -}; -goog.inherits(goog.iter.GroupByIterator_, goog.iter.Iterator); + this.canvasClientWidth_ = width; + this.canvasClientHeight_ = height; + width *= zoomFactor; + height *= zoomFactor; -/** @override */ -goog.iter.GroupByIterator_.prototype.next = function() { - while (this.currentKey == this.targetKey) { - this.currentValue = this.iterator.next(); // Exits on StopIteration - this.currentKey = this.keyFunc(this.currentValue); - } - this.targetKey = this.currentKey; - return [this.currentKey, this.groupItems_(this.targetKey)]; + this.canvas_.width = width; + this.canvas_.height = height; + this.scene_.camera.frustum.aspectRatio = width / height; }; /** - * Performs the grouping of objects using the given key. - * @param {KEY} targetKey The target key object for the group. - * @return {!Array<VALUE>} An array of grouped objects. - * @private + * @return {!olcs.Camera} + * @api */ -goog.iter.GroupByIterator_.prototype.groupItems_ = function(targetKey) { - var arr = []; - while (this.currentKey == targetKey) { - arr.push(this.currentValue); - try { - this.currentValue = this.iterator.next(); - } catch (ex) { - if (ex !== goog.iter.StopIteration) { - throw ex; - } - break; - } - this.currentKey = this.keyFunc(this.currentValue); - } - return arr; +olcs.OLCesium.prototype.getCamera = function() { + return this.camera_; }; /** - * Creates an iterator that returns arrays containing elements from the - * {@code iterable} grouped by a key value. For iterables with repeated - * elements (i.e. sorted according to a particular key function), this function - * has a {@code uniq}-like effect. For example, grouping the array: - * {@code [A, B, B, C, C, A]} produces - * {@code [A, [A]], [B, [B, B]], [C, [C, C]], [A, [A]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.groupby - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to group. - * @param {function(...VALUE): KEY=} opt_keyFunc Optional function for - * determining the key value for each group in the {@code iterable}. Default - * is the identity function. - * @return {!goog.iter.Iterator<!Array<?>>} A new iterator that returns - * arrays of consecutive key and groups. - * @template KEY, VALUE + * @return {!ol.Map} + * @api */ -goog.iter.groupBy = function(iterable, opt_keyFunc) { - return new goog.iter.GroupByIterator_(iterable, opt_keyFunc); +olcs.OLCesium.prototype.getOlMap = function() { + return this.map_; }; /** - * Gives an iterator that gives the result of calling the given function - * <code>f</code> with the arguments taken from the next element from - * <code>iterable</code> (the elements are expected to also be iterables). - * - * Similar to {@see goog.iter#map} but allows the function to accept multiple - * arguments from the iterable. - * - * @param {!goog.iter.Iterable<!goog.iter.Iterable>} iterable The iterable of - * iterables to iterate over. - * @param {function(this:THIS,...*):RESULT} f The function to call for every - * element. This function takes N+2 arguments, where N represents the - * number of items from the next element of the iterable. The two - * additional arguments passed to the function are undefined and the - * iterator itself. The function should return a new value. - * @param {THIS=} opt_obj The object to be used as the value of 'this' within - * {@code f}. - * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the - * results of applying the function to each element in the original - * iterator. - * @template THIS, RESULT + * @return {!Cesium.Scene} + * @api */ -goog.iter.starMap = function(iterable, f, opt_obj) { - var iterator = goog.iter.toIterator(iterable); - var iter = new goog.iter.Iterator(); - - iter.next = function() { - var args = goog.iter.toArray(iterator.next()); - return f.apply(opt_obj, goog.array.concat(args, undefined, iterator)); - }; - - return iter; +olcs.OLCesium.prototype.getCesiumScene = function() { + return this.scene_; }; /** - * Returns an array of iterators each of which can iterate over the values in - * {@code iterable} without advancing the others. - * @see http://docs.python.org/2/library/itertools.html#itertools.tee - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to tee. - * @param {number=} opt_num The number of iterators to create. Default is 2. - * @return {!Array<goog.iter.Iterator<VALUE>>} An array of iterators. - * @template VALUE + * @return {!Cesium.DataSourceCollection} + * @api */ -goog.iter.tee = function(iterable, opt_num) { - var iterator = goog.iter.toIterator(iterable); - var num = goog.isNumber(opt_num) ? opt_num : 2; - var buffers = goog.array.map(goog.array.range(num), function() { - return []; - }); - - var addNextIteratorValueToBuffers = function() { - var val = iterator.next(); - goog.array.forEach(buffers, function(buffer) { - buffer.push(val); - }); - }; - - var createIterator = function(buffer) { - // Each tee'd iterator has an associated buffer (initially empty). When a - // tee'd iterator's buffer is empty, it calls - // addNextIteratorValueToBuffers(), adding the next value to all tee'd - // iterators' buffers, and then returns that value. This allows each - // iterator to be advanced independently. - var iter = new goog.iter.Iterator(); - - iter.next = function() { - if (goog.array.isEmpty(buffer)) { - addNextIteratorValueToBuffers(); - } - goog.asserts.assert(!goog.array.isEmpty(buffer)); - return buffer.shift(); - }; - - return iter; - }; - - return goog.array.map(buffers, createIterator); +olcs.OLCesium.prototype.getDataSources = function() { + return this.dataSourceCollection_; }; /** - * Creates an iterator that returns arrays containing a count and an element - * obtained from the given {@code iterable}. - * @see http://docs.python.org/2/library/functions.html#enumerate - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to enumerate. - * @param {number=} opt_start Optional starting value. Default is 0. - * @return {!goog.iter.Iterator<!Array<?>>} A new iterator containing - * count/item pairs. - * @template VALUE + * @return {boolean} + * @api */ -goog.iter.enumerate = function(iterable, opt_start) { - return goog.iter.zip(goog.iter.count(opt_start), iterable); +olcs.OLCesium.prototype.getEnabled = function() { + return this.enabled_; }; /** - * Creates an iterator that returns the first {@code limitSize} elements from an - * iterable. If this number is greater than the number of elements in the - * iterable, all the elements are returned. - * @see http://goo.gl/V0sihp Inspired by the limit iterator in Guava. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to limit. - * @param {number} limitSize The maximum number of elements to return. - * @return {!goog.iter.Iterator<VALUE>} A new iterator containing - * {@code limitSize} elements. - * @template VALUE + * Enables/disables the Cesium. + * This modifies the visibility style of the container element. + * @param {boolean} enable + * @api */ -goog.iter.limit = function(iterable, limitSize) { - goog.asserts.assert(goog.math.isInt(limitSize) && limitSize >= 0); +olcs.OLCesium.prototype.setEnabled = function(enable) { + if (this.enabled_ == enable) { + return; + } + this.enabled_ = enable; - var iterator = goog.iter.toIterator(iterable); + // some Cesium operations are operating with canvas.clientWidth, + // so we can't remove it from DOM or even make display:none; + this.container_.style.visibility = this.enabled_ ? 'visible' : 'hidden'; + if (this.enabled_) { + if (this.isOverMap_) { + var interactions = this.map_.getInteractions(); + interactions.forEach(function(el, i, arr) { + this.pausedInteractions_.push(el); + }, this); + interactions.clear(); - var iter = new goog.iter.Iterator(); - var remaining = limitSize; + var rootGroup = this.map_.getLayerGroup(); + if (rootGroup.getVisible()) { + this.hiddenRootGroup_ = rootGroup; + this.hiddenRootGroup_.setVisible(false); + } + } + this.camera_.readFromView(); + this.cesiumRenderingDelay_.start(); + } else { + if (this.isOverMap_) { + var interactions = this.map_.getInteractions(); + this.pausedInteractions_.forEach(function(interaction) { + interactions.push(interaction); + }); + this.pausedInteractions_.length = 0; - iter.next = function() { - if (remaining-- > 0) { - return iterator.next(); + if (!goog.isNull(this.hiddenRootGroup_)) { + this.hiddenRootGroup_.setVisible(true); + this.hiddenRootGroup_ = null; + } } - throw goog.iter.StopIteration; - }; - return iter; + this.camera_.updateView(); + this.cesiumRenderingDelay_.stop(); + } }; /** - * Creates an iterator that is advanced {@code count} steps ahead. Consumed - * values are silently discarded. If {@code count} is greater than the number - * of elements in {@code iterable}, an empty iterator is returned. Subsequent - * calls to {@code next()} will throw {@code goog.iter.StopIteration}. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to consume. - * @param {number} count The number of elements to consume from the iterator. - * @return {!goog.iter.Iterator<VALUE>} An iterator advanced zero or more steps - * ahead. - * @template VALUE - */ -goog.iter.consume = function(iterable, count) { - goog.asserts.assert(goog.math.isInt(count) && count >= 0); - - var iterator = goog.iter.toIterator(iterable); - - while (count-- > 0) { - goog.iter.nextOrValue(iterator, null); + * Preload Cesium so that it is ready when transitioning from 2D to 3D. + * @param {number} height Target height of the camera + * @param {number} timeout Milliseconds after which the warming will stop + * @api +*/ +olcs.OLCesium.prototype.warmUp = function(height, timeout) { + if (this.enabled_) { + // already enabled + return; } - - return iterator; + this.camera_.readFromView(); + var ellipsoid = this.globe_.ellipsoid; + var csCamera = this.scene_.camera; + var position = ellipsoid.cartesianToCartographic(csCamera.position); + if (position.height < height) { + position.height = height; + csCamera.position = ellipsoid.cartographicToCartesian(position); + } + this.cesiumRenderingDelay_.start(); + var that = this; + setTimeout( + function() { !that.enabled_ && that.cesiumRenderingDelay_.stop(); }, + timeout); }; /** - * Creates an iterator that returns a range of elements from an iterable. - * Similar to {@see goog.array#slice} but does not support negative indexes. - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to slice. - * @param {number} start The index of the first element to return. - * @param {number=} opt_end The index after the last element to return. If - * defined, must be greater than or equal to {@code start}. - * @return {!goog.iter.Iterator<VALUE>} A new iterator containing a slice of - * the original. - * @template VALUE - */ -goog.iter.slice = function(iterable, start, opt_end) { - goog.asserts.assert(goog.math.isInt(start) && start >= 0); + * Block Cesium rendering to save resources. + * @param {boolean} block True to block. + * @api +*/ +olcs.OLCesium.prototype.setBlockCesiumRendering = function(block) { + this.blockCesiumRendering_ = block; +}; - var iterator = goog.iter.consume(iterable, start); - if (goog.isNumber(opt_end)) { - goog.asserts.assert(goog.math.isInt(opt_end) && opt_end >= start); - iterator = goog.iter.limit(iterator, opt_end - start /* limitSize */); +/** + * Render the globe only when necessary in order to save resources. + * Experimental. + * @api + */ +olcs.OLCesium.prototype.enableAutoRenderLoop = function() { + if (!this.autoRenderLoop_) { + this.autoRenderLoop_ = new olcs.AutoRenderLoop(this, false); } - - return iterator; }; /** - * Checks an array for duplicate elements. - * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to check for - * duplicates. - * @return {boolean} True, if the array contains duplicates, false otherwise. - * @private - * @template VALUE - */ -// TODO(user): Consider moving this into goog.array as a public function. -goog.iter.hasDuplicates_ = function(arr) { - var deduped = []; - goog.array.removeDuplicates(arr, deduped); - return arr.length != deduped.length; + * Get the autorender loop. + * @return {?olcs.AutoRenderLoop} + * @api +*/ +olcs.OLCesium.prototype.getAutoRenderLoop = function() { + return this.autoRenderLoop_; }; /** - * Creates an iterator that returns permutations of elements in - * {@code iterable}. + * The 3D Cesium globe is rendered in a canvas with two different dimensions: + * clientWidth and clientHeight which are the dimension on the screen and + * width and height which are the dimensions of the drawing buffer. * - * Permutations are obtained by taking the Cartesian product of - * {@code opt_length} iterables and filtering out those with repeated - * elements. For example, the permutations of {@code [1,2,3]} are - * {@code [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.permutations - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable from which to generate permutations. - * @param {number=} opt_length Length of each permutation. If omitted, defaults - * to the length of {@code iterable}. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing the - * permutations of {@code iterable}. - * @template VALUE + * By using a resolution scale lower than 1.0, it is possible to render the + * globe in a buffer smaller than the canvas client dimensions and improve + * performance, at the cost of quality. + * + * Pixel ratio should also be taken into account; by default, a device with + * pixel ratio of 2.0 will have a buffer surface 4 times bigger than the client + * surface. + * + * @param {number} value + * @this {olcs.OLCesium} + * @api */ -goog.iter.permutations = function(iterable, opt_length) { - var elements = goog.iter.toArray(iterable); - var length = goog.isNumber(opt_length) ? opt_length : elements.length; +olcs.OLCesium.prototype.setResolutionScale = function(value) { + value = Math.max(0, value); + if (value !== this.resolutionScale_) { + this.resolutionScale_ = Math.max(0, value); + this.resolutionScaleChanged_ = true; + if (this.autoRenderLoop_) { + this.autoRenderLoop_.restartRenderLoop(); + } + } +}; - var sets = goog.array.repeat(elements, length); - var product = goog.iter.product.apply(undefined, sets); +goog.provide('olcs.GaRasterSynchronizer'); +goog.require('olcs.RasterSynchronizer'); - return goog.iter.filter(product, function(arr) { - return !goog.iter.hasDuplicates_(arr); - }); -}; /** - * Creates an iterator that returns combinations of elements from - * {@code iterable}. - * - * Combinations are obtained by taking the {@see goog.iter#permutations} of - * {@code iterable} and filtering those whose elements appear in the order they - * are encountered in {@code iterable}. For example, the 3-length combinations - * of {@code [0,1,2,3]} are {@code [[0,1,2], [0,1,3], [0,2,3], [1,2,3]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.combinations - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable from which to generate combinations. - * @param {number} length The length of each combination. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing - * combinations from the {@code iterable}. - * @template VALUE + * Handle mapping OL3 2D layers to Cesium 3D Imageries in EPSG:4326. + * @param {!ol.Map} map + * @param {!Cesium.Scene} scene + * @constructor + * @extends {olcs.RasterSynchronizer} + * @api */ -goog.iter.combinations = function(iterable, length) { - var elements = goog.iter.toArray(iterable); - var indexes = goog.iter.range(elements.length); - var indexIterator = goog.iter.permutations(indexes, length); - // sortedIndexIterator will now give arrays of with the given length that - // indicate what indexes into "elements" should be returned on each iteration. - var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { - return goog.array.isSorted(arr); - }); - - var iter = new goog.iter.Iterator(); - - function getIndexFromElements(index) { - return elements[index]; - } - - iter.next = function() { - return goog.array.map(sortedIndexIterator.next(), getIndexFromElements); - }; - - return iter; +olcs.GaRasterSynchronizer = function(map, scene) { + goog.base(this, map, scene); }; +goog.inherits(olcs.GaRasterSynchronizer, olcs.RasterSynchronizer); /** - * Creates an iterator that returns combinations of elements from - * {@code iterable}, with repeated elements possible. - * - * Combinations are obtained by taking the Cartesian product of {@code length} - * iterables and filtering those whose elements appear in the order they are - * encountered in {@code iterable}. For example, the 2-length combinations of - * {@code [1,2,3]} are {@code [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]}. - * @see http://docs.python.org/2/library/itertools.html#itertools.combinations_with_replacement - * @see http://en.wikipedia.org/wiki/Combination#Number_of_combinations_with_repetition - * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The - * iterable to combine. - * @param {number} length The length of each combination. - * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing - * combinations from the {@code iterable}. - * @template VALUE + * @override */ -goog.iter.combinationsWithReplacement = function(iterable, length) { - var elements = goog.iter.toArray(iterable); - var indexes = goog.array.range(elements.length); - var sets = goog.array.repeat(indexes, length); - var indexIterator = goog.iter.product.apply(undefined, sets); - // sortedIndexIterator will now give arrays of with the given length that - // indicate what indexes into "elements" should be returned on each iteration. - var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { - return goog.array.isSorted(arr); - }); +olcs.GaRasterSynchronizer.prototype.convertLayerToCesiumImageries = + function(olLayer, viewProj) { - var iter = new goog.iter.Iterator(); + /** + * @type {Cesium.ImageryProvider} + */ + var provider = null; - function getIndexFromElements(index) { - return elements[index]; + var isLayer = olLayer instanceof ol.layer.Layer; + if (olLayer instanceof ol.layer.Layer) { + var source = olLayer.getSource(); + if (source instanceof ol.source.Vector) { + return null; + } } - iter.next = function() { - return goog.array.map( - /** @type {!Array<number>} */ - (sortedIndexIterator.next()), getIndexFromElements); - }; + // Read custom, non standard properties + var factory = olcs.obj(olLayer)['getCesiumImageryProvider']; + if (!factory) { + // root layer group + return null; + } + provider = factory(); + if (!provider) { + return null; + } - return iter; + // the provider is always non-null if we got this far + + var providers = Array.isArray(provider) ? provider : [provider]; + return providers.map(function(p) { + return new Cesium.ImageryLayer(p); + }); }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// FIXME factor out common code between usedTiles and wantedTiles + +goog.provide('ol.PostRenderFunction'); +goog.provide('ol.PreRenderFunction'); + /** - * @fileoverview Datastructure: Hash Map. - * - * @author arv@google.com (Erik Arvidsson) - * - * This file contains an implementation of a Map structure. It implements a lot - * of the methods used in goog.structs so those functions work on hashes. This - * is best suited for complex key types. For simple keys such as numbers and - * strings consider using the lighter-weight utilities in goog.object. + * @typedef {function(ol.Map, ?olx.FrameState): boolean} */ +ol.PostRenderFunction; -goog.provide('goog.structs.Map'); +/** + * Function to perform manipulations before rendering. This function is called + * with the {@link ol.Map} as first and an optional {@link olx.FrameState} as + * second argument. Return `true` to keep this function for the next frame, + * `false` to remove it. + * @typedef {function(ol.Map, ?olx.FrameState): boolean} + * @api + */ +ol.PreRenderFunction; -goog.require('goog.iter.Iterator'); -goog.require('goog.iter.StopIteration'); -goog.require('goog.object'); +goog.provide('ol.CenterConstraint'); +goog.provide('ol.CenterConstraintType'); +goog.require('ol.math'); /** - * Class for Hash Map datastructure. - * @param {*=} opt_map Map or Object to initialize the map with. - * @param {...*} var_args If 2 or more arguments are present then they - * will be used as key-value pairs. - * @constructor - * @template K, V + * @typedef {function((ol.Coordinate|undefined)): (ol.Coordinate|undefined)} */ -goog.structs.Map = function(opt_map, var_args) { +ol.CenterConstraintType; - /** - * Underlying JS object used to implement the map. - * @private {!Object} - */ - this.map_ = {}; - /** - * An array of keys. This is necessary for two reasons: - * 1. Iterating the keys using for (var key in this.map_) allocates an - * object for every key in IE which is really bad for IE6 GC perf. - * 2. Without a side data structure, we would need to escape all the keys - * as that would be the only way we could tell during iteration if the - * key was an internal key or a property of the object. - * - * This array can contain deleted keys so it's necessary to check the map - * as well to see if the key is still in the map (this doesn't require a - * memory allocation in IE). - * @private {!Array<string>} - */ - this.keys_ = []; +/** + * @param {ol.Extent} extent Extent. + * @return {ol.CenterConstraintType} + */ +ol.CenterConstraint.createExtent = function(extent) { + return ( + /** + * @param {ol.Coordinate|undefined} center Center. + * @return {ol.Coordinate|undefined} Center. + */ + function(center) { + if (center) { + return [ + ol.math.clamp(center[0], extent[0], extent[2]), + ol.math.clamp(center[1], extent[1], extent[3]) + ]; + } else { + return undefined; + } + }); +}; - /** - * The number of key value pairs in the map. - * @private {number} - */ - this.count_ = 0; - /** - * Version used to detect changes while iterating. - * @private {number} - */ - this.version_ = 0; +/** + * @param {ol.Coordinate|undefined} center Center. + * @return {ol.Coordinate|undefined} Center. + */ +ol.CenterConstraint.none = function(center) { + return center; +}; - var argLength = arguments.length; +goog.provide('ol.ResolutionConstraint'); +goog.provide('ol.ResolutionConstraintType'); - if (argLength > 1) { - if (argLength % 2) { - throw Error('Uneven number of arguments'); - } - for (var i = 0; i < argLength; i += 2) { - this.set(arguments[i], arguments[i + 1]); - } - } else if (opt_map) { - this.addAll(/** @type {Object} */ (opt_map)); - } -}; +goog.require('ol.array'); +goog.require('ol.math'); /** - * @return {number} The number of key-value pairs in the map. + * @typedef {function((number|undefined), number, number): (number|undefined)} */ -goog.structs.Map.prototype.getCount = function() { - return this.count_; -}; +ol.ResolutionConstraintType; /** - * Returns the values of the map. - * @return {!Array<V>} The values in the map. + * @param {Array.<number>} resolutions Resolutions. + * @return {ol.ResolutionConstraintType} Zoom function. */ -goog.structs.Map.prototype.getValues = function() { - this.cleanupKeysArray_(); - - var rv = []; - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - rv.push(this.map_[key]); - } - return rv; +ol.ResolutionConstraint.createSnapToResolutions = + function(resolutions) { + return ( + /** + * @param {number|undefined} resolution Resolution. + * @param {number} delta Delta. + * @param {number} direction Direction. + * @return {number|undefined} Resolution. + */ + function(resolution, delta, direction) { + if (resolution !== undefined) { + var z = + ol.array.linearFindNearest(resolutions, resolution, direction); + z = ol.math.clamp(z + delta, 0, resolutions.length - 1); + return resolutions[z]; + } else { + return undefined; + } + }); }; /** - * Returns the keys of the map. - * @return {!Array<string>} Array of string values. + * @param {number} power Power. + * @param {number} maxResolution Maximum resolution. + * @param {number=} opt_maxLevel Maximum level. + * @return {ol.ResolutionConstraintType} Zoom function. */ -goog.structs.Map.prototype.getKeys = function() { - this.cleanupKeysArray_(); - return /** @type {!Array<string>} */ (this.keys_.concat()); +ol.ResolutionConstraint.createSnapToPower = + function(power, maxResolution, opt_maxLevel) { + return ( + /** + * @param {number|undefined} resolution Resolution. + * @param {number} delta Delta. + * @param {number} direction Direction. + * @return {number|undefined} Resolution. + */ + function(resolution, delta, direction) { + if (resolution !== undefined) { + var offset; + if (direction > 0) { + offset = 0; + } else if (direction < 0) { + offset = 1; + } else { + offset = 0.5; + } + var oldLevel = Math.floor( + Math.log(maxResolution / resolution) / Math.log(power) + offset); + var newLevel = Math.max(oldLevel + delta, 0); + if (opt_maxLevel !== undefined) { + newLevel = Math.min(newLevel, opt_maxLevel); + } + return maxResolution / Math.pow(power, newLevel); + } else { + return undefined; + } + }); }; +goog.provide('ol.RotationConstraint'); +goog.provide('ol.RotationConstraintType'); + +goog.require('ol.math'); + /** - * Whether the map contains the given key. - * @param {*} key The key to check for. - * @return {boolean} Whether the map contains the key. + * @typedef {function((number|undefined), number): (number|undefined)} */ -goog.structs.Map.prototype.containsKey = function(key) { - return goog.structs.Map.hasKey_(this.map_, key); -}; +ol.RotationConstraintType; /** - * Whether the map contains the given value. This is O(n). - * @param {V} val The value to check for. - * @return {boolean} Whether the map contains the value. + * @param {number|undefined} rotation Rotation. + * @param {number} delta Delta. + * @return {number|undefined} Rotation. */ -goog.structs.Map.prototype.containsValue = function(val) { - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) { - return true; - } +ol.RotationConstraint.disable = function(rotation, delta) { + if (rotation !== undefined) { + return 0; + } else { + return undefined; } - return false; }; /** - * Whether this map is equal to the argument map. - * @param {goog.structs.Map} otherMap The map against which to test equality. - * @param {function(V, V): boolean=} opt_equalityFn Optional equality function - * to test equality of values. If not specified, this will test whether - * the values contained in each map are identical objects. - * @return {boolean} Whether the maps are equal. + * @param {number|undefined} rotation Rotation. + * @param {number} delta Delta. + * @return {number|undefined} Rotation. */ -goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) { - if (this === otherMap) { - return true; - } - - if (this.count_ != otherMap.getCount()) { - return false; - } - - var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals; - - this.cleanupKeysArray_(); - for (var key, i = 0; key = this.keys_[i]; i++) { - if (!equalityFn(this.get(key), otherMap.get(key))) { - return false; - } +ol.RotationConstraint.none = function(rotation, delta) { + if (rotation !== undefined) { + return rotation + delta; + } else { + return undefined; } - - return true; }; /** - * Default equality test for values. - * @param {*} a The first value. - * @param {*} b The second value. - * @return {boolean} Whether a and b reference the same object. + * @param {number} n N. + * @return {ol.RotationConstraintType} Rotation constraint. */ -goog.structs.Map.defaultEquals = function(a, b) { - return a === b; +ol.RotationConstraint.createSnapToN = function(n) { + var theta = 2 * Math.PI / n; + return ( + /** + * @param {number|undefined} rotation Rotation. + * @param {number} delta Delta. + * @return {number|undefined} Rotation. + */ + function(rotation, delta) { + if (rotation !== undefined) { + rotation = Math.floor((rotation + delta) / theta + 0.5) * theta; + return rotation; + } else { + return undefined; + } + }); }; /** - * @return {boolean} Whether the map is empty. + * @param {number=} opt_tolerance Tolerance. + * @return {ol.RotationConstraintType} Rotation constraint. */ -goog.structs.Map.prototype.isEmpty = function() { - return this.count_ == 0; +ol.RotationConstraint.createSnapToZero = function(opt_tolerance) { + var tolerance = opt_tolerance || ol.math.toRadians(5); + return ( + /** + * @param {number|undefined} rotation Rotation. + * @param {number} delta Delta. + * @return {number|undefined} Rotation. + */ + function(rotation, delta) { + if (rotation !== undefined) { + if (Math.abs(rotation + delta) <= tolerance) { + return 0; + } else { + return rotation + delta; + } + } else { + return undefined; + } + }); }; +goog.provide('ol.Constraints'); + +goog.require('ol.CenterConstraintType'); +goog.require('ol.ResolutionConstraintType'); +goog.require('ol.RotationConstraintType'); -/** - * Removes all key-value pairs from the map. - */ -goog.structs.Map.prototype.clear = function() { - this.map_ = {}; - this.keys_.length = 0; - this.count_ = 0; - this.version_ = 0; -}; /** - * Removes a key-value pair based on the key. This is O(logN) amortized due to - * updating the keys array whenever the count becomes half the size of the keys - * in the keys array. - * @param {*} key The key to remove. - * @return {boolean} Whether object was removed. + * @constructor + * @param {ol.CenterConstraintType} centerConstraint Center constraint. + * @param {ol.ResolutionConstraintType} resolutionConstraint + * Resolution constraint. + * @param {ol.RotationConstraintType} rotationConstraint + * Rotation constraint. */ -goog.structs.Map.prototype.remove = function(key) { - if (goog.structs.Map.hasKey_(this.map_, key)) { - delete this.map_[key]; - this.count_--; - this.version_++; +ol.Constraints = + function(centerConstraint, resolutionConstraint, rotationConstraint) { - // clean up the keys array if the threshhold is hit - if (this.keys_.length > 2 * this.count_) { - this.cleanupKeysArray_(); - } + /** + * @type {ol.CenterConstraintType} + */ + this.center = centerConstraint; + + /** + * @type {ol.ResolutionConstraintType} + */ + this.resolution = resolutionConstraint; + + /** + * @type {ol.RotationConstraintType} + */ + this.rotation = rotationConstraint; - return true; - } - return false; }; +goog.provide('ol.geom.flat.area'); + /** - * Cleans up the temp keys array by removing entries that are no longer in the - * map. - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {number} Area. */ -goog.structs.Map.prototype.cleanupKeysArray_ = function() { - if (this.count_ != this.keys_.length) { - // First remove keys that are no longer in the map. - var srcIndex = 0; - var destIndex = 0; - while (srcIndex < this.keys_.length) { - var key = this.keys_[srcIndex]; - if (goog.structs.Map.hasKey_(this.map_, key)) { - this.keys_[destIndex++] = key; - } - srcIndex++; - } - this.keys_.length = destIndex; - } - - if (this.count_ != this.keys_.length) { - // If the count still isn't correct, that means we have duplicates. This can - // happen when the same key is added and removed multiple times. Now we have - // to allocate one extra Object to remove the duplicates. This could have - // been done in the first pass, but in the common case, we can avoid - // allocating an extra object by only doing this when necessary. - var seen = {}; - var srcIndex = 0; - var destIndex = 0; - while (srcIndex < this.keys_.length) { - var key = this.keys_[srcIndex]; - if (!(goog.structs.Map.hasKey_(seen, key))) { - this.keys_[destIndex++] = key; - seen[key] = 1; - } - srcIndex++; - } - this.keys_.length = destIndex; +ol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) { + var twiceArea = 0; + var x1 = flatCoordinates[end - stride]; + var y1 = flatCoordinates[end - stride + 1]; + for (; offset < end; offset += stride) { + var x2 = flatCoordinates[offset]; + var y2 = flatCoordinates[offset + 1]; + twiceArea += y1 * x2 - x1 * y2; + x1 = x2; + y1 = y2; } + return twiceArea / 2; }; /** - * Returns the value for the given key. If the key is not found and the default - * value is not given this will return {@code undefined}. - * @param {*} key The key to get the value for. - * @param {DEFAULT=} opt_val The value to return if no item is found for the - * given key, defaults to undefined. - * @return {V|DEFAULT} The value for the given key. - * @template DEFAULT + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @return {number} Area. */ -goog.structs.Map.prototype.get = function(key, opt_val) { - if (goog.structs.Map.hasKey_(this.map_, key)) { - return this.map_[key]; +ol.geom.flat.area.linearRings = + function(flatCoordinates, offset, ends, stride) { + var area = 0; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride); + offset = end; } - return opt_val; + return area; }; /** - * Adds a key-value pair to the map. - * @param {*} key The key. - * @param {V} value The value to add. - * @return {*} Some subclasses return a value. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @return {number} Area. */ -goog.structs.Map.prototype.set = function(key, value) { - if (!(goog.structs.Map.hasKey_(this.map_, key))) { - this.count_++; - this.keys_.push(key); - // Only change the version if we add a new key. - this.version_++; +ol.geom.flat.area.linearRingss = + function(flatCoordinates, offset, endss, stride) { + var area = 0; + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + area += + ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride); + offset = ends[ends.length - 1]; } - this.map_[key] = value; + return area; }; +goog.provide('ol.geom.flat.closest'); + +goog.require('goog.asserts'); +goog.require('goog.math'); +goog.require('ol.math'); + /** - * Adds multiple key-value pairs from another goog.structs.Map or Object. - * @param {Object} map Object containing the data to add. + * Returns the point on the 2D line segment flatCoordinates[offset1] to + * flatCoordinates[offset2] that is closest to the point (x, y). Extra + * dimensions are linearly interpolated. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset1 Offset 1. + * @param {number} offset2 Offset 2. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @param {Array.<number>} closestPoint Closest point. */ -goog.structs.Map.prototype.addAll = function(map) { - var keys, values; - if (map instanceof goog.structs.Map) { - keys = map.getKeys(); - values = map.getValues(); +ol.geom.flat.closest.point = + function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) { + var x1 = flatCoordinates[offset1]; + var y1 = flatCoordinates[offset1 + 1]; + var dx = flatCoordinates[offset2] - x1; + var dy = flatCoordinates[offset2 + 1] - y1; + var i, offset; + if (dx === 0 && dy === 0) { + offset = offset1; } else { - keys = goog.object.getKeys(map); - values = goog.object.getValues(map); + var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); + if (t > 1) { + offset = offset2; + } else if (t > 0) { + for (i = 0; i < stride; ++i) { + closestPoint[i] = goog.math.lerp(flatCoordinates[offset1 + i], + flatCoordinates[offset2 + i], t); + } + closestPoint.length = stride; + return; + } else { + offset = offset1; + } } - // we could use goog.array.forEach here but I don't want to introduce that - // dependency just for this. - for (var i = 0; i < keys.length; i++) { - this.set(keys[i], values[i]); + for (i = 0; i < stride; ++i) { + closestPoint[i] = flatCoordinates[offset + i]; } + closestPoint.length = stride; }; /** - * Calls the given function on each entry in the map. - * @param {function(this:T, V, K, goog.structs.Map<K,V>)} f - * @param {T=} opt_obj The value of "this" inside f. - * @template T + * Return the squared of the largest distance between any pair of consecutive + * coordinates. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} maxSquaredDelta Max squared delta. + * @return {number} Max squared delta. */ -goog.structs.Map.prototype.forEach = function(f, opt_obj) { - var keys = this.getKeys(); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = this.get(key); - f.call(opt_obj, value, key, this); +ol.geom.flat.closest.getMaxSquaredDelta = + function(flatCoordinates, offset, end, stride, maxSquaredDelta) { + var x1 = flatCoordinates[offset]; + var y1 = flatCoordinates[offset + 1]; + for (offset += stride; offset < end; offset += stride) { + var x2 = flatCoordinates[offset]; + var y2 = flatCoordinates[offset + 1]; + var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2); + if (squaredDelta > maxSquaredDelta) { + maxSquaredDelta = squaredDelta; + } + x1 = x2; + y1 = y2; } + return maxSquaredDelta; }; /** - * Clones a map and returns a new map. - * @return {!goog.structs.Map} A new map with the same key-value pairs. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {number} maxSquaredDelta Max squared delta. + * @return {number} Max squared delta. */ -goog.structs.Map.prototype.clone = function() { - return new goog.structs.Map(this); +ol.geom.flat.closest.getsMaxSquaredDelta = + function(flatCoordinates, offset, ends, stride, maxSquaredDelta) { + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta( + flatCoordinates, offset, end, stride, maxSquaredDelta); + offset = end; + } + return maxSquaredDelta; }; /** - * Returns a new map in which all the keys and values are interchanged - * (keys become values and values become keys). If multiple keys map to the - * same value, the chosen transposed value is implementation-dependent. - * - * It acts very similarly to {goog.object.transpose(Object)}. - * - * @return {!goog.structs.Map} The transposed map. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {number} maxSquaredDelta Max squared delta. + * @return {number} Max squared delta. */ -goog.structs.Map.prototype.transpose = function() { - var transposed = new goog.structs.Map(); - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - var value = this.map_[key]; - transposed.set(value, key); +ol.geom.flat.closest.getssMaxSquaredDelta = + function(flatCoordinates, offset, endss, stride, maxSquaredDelta) { + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta( + flatCoordinates, offset, ends, stride, maxSquaredDelta); + offset = ends[ends.length - 1]; } - - return transposed; + return maxSquaredDelta; }; /** - * @return {!Object} Object representation of the map. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} maxDelta Max delta. + * @param {boolean} isRing Is ring. + * @param {number} x X. + * @param {number} y Y. + * @param {Array.<number>} closestPoint Closest point. + * @param {number} minSquaredDistance Minimum squared distance. + * @param {Array.<number>=} opt_tmpPoint Temporary point object. + * @return {number} Minimum squared distance. */ -goog.structs.Map.prototype.toObject = function() { - this.cleanupKeysArray_(); - var obj = {}; - for (var i = 0; i < this.keys_.length; i++) { - var key = this.keys_[i]; - obj[key] = this.map_[key]; +ol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end, + stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, + opt_tmpPoint) { + if (offset == end) { + return minSquaredDistance; } - return obj; + var i, squaredDistance; + if (maxDelta === 0) { + // All points are identical, so just test the first point. + squaredDistance = ol.math.squaredDistance( + x, y, flatCoordinates[offset], flatCoordinates[offset + 1]); + if (squaredDistance < minSquaredDistance) { + for (i = 0; i < stride; ++i) { + closestPoint[i] = flatCoordinates[offset + i]; + } + closestPoint.length = stride; + return squaredDistance; + } else { + return minSquaredDistance; + } + } + goog.asserts.assert(maxDelta > 0, 'maxDelta should be larger than 0'); + var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; + var index = offset + stride; + while (index < end) { + ol.geom.flat.closest.point( + flatCoordinates, index - stride, index, stride, x, y, tmpPoint); + squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); + if (squaredDistance < minSquaredDistance) { + minSquaredDistance = squaredDistance; + for (i = 0; i < stride; ++i) { + closestPoint[i] = tmpPoint[i]; + } + closestPoint.length = stride; + index += stride; + } else { + // Skip ahead multiple points, because we know that all the skipped + // points cannot be any closer than the closest point we have found so + // far. We know this because we know how close the current point is, how + // close the closest point we have found so far is, and the maximum + // distance between consecutive points. For example, if we're currently + // at distance 10, the best we've found so far is 3, and that the maximum + // distance between consecutive points is 2, then we'll need to skip at + // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of + // finding a closer point. We use Math.max(..., 1) to ensure that we + // always advance at least one point, to avoid an infinite loop. + index += stride * Math.max( + ((Math.sqrt(squaredDistance) - + Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1); + } + } + if (isRing) { + // Check the closing segment. + ol.geom.flat.closest.point( + flatCoordinates, end - stride, offset, stride, x, y, tmpPoint); + squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); + if (squaredDistance < minSquaredDistance) { + minSquaredDistance = squaredDistance; + for (i = 0; i < stride; ++i) { + closestPoint[i] = tmpPoint[i]; + } + closestPoint.length = stride; + } + } + return minSquaredDistance; }; /** - * Returns an iterator that iterates over the keys in the map. Removal of keys - * while iterating might have undesired side effects. - * @return {!goog.iter.Iterator} An iterator over the keys in the map. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {number} maxDelta Max delta. + * @param {boolean} isRing Is ring. + * @param {number} x X. + * @param {number} y Y. + * @param {Array.<number>} closestPoint Closest point. + * @param {number} minSquaredDistance Minimum squared distance. + * @param {Array.<number>=} opt_tmpPoint Temporary point object. + * @return {number} Minimum squared distance. */ -goog.structs.Map.prototype.getKeyIterator = function() { - return this.__iterator__(true); +ol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends, + stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, + opt_tmpPoint) { + var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + minSquaredDistance = ol.geom.flat.closest.getClosestPoint( + flatCoordinates, offset, end, stride, + maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint); + offset = end; + } + return minSquaredDistance; }; /** - * Returns an iterator that iterates over the values in the map. Removal of - * keys while iterating might have undesired side effects. - * @return {!goog.iter.Iterator} An iterator over the values in the map. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {number} maxDelta Max delta. + * @param {boolean} isRing Is ring. + * @param {number} x X. + * @param {number} y Y. + * @param {Array.<number>} closestPoint Closest point. + * @param {number} minSquaredDistance Minimum squared distance. + * @param {Array.<number>=} opt_tmpPoint Temporary point object. + * @return {number} Minimum squared distance. */ -goog.structs.Map.prototype.getValueIterator = function() { - return this.__iterator__(false); +ol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset, + endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, + opt_tmpPoint) { + var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN]; + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + minSquaredDistance = ol.geom.flat.closest.getsClosestPoint( + flatCoordinates, offset, ends, stride, + maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint); + offset = ends[ends.length - 1]; + } + return minSquaredDistance; }; +goog.provide('ol.geom.flat.deflate'); + +goog.require('goog.asserts'); + /** - * Returns an iterator that iterates over the values or the keys in the map. - * This throws an exception if the map was mutated since the iterator was - * created. - * @param {boolean=} opt_keys True to iterate over the keys. False to iterate - * over the values. The default value is false. - * @return {!goog.iter.Iterator} An iterator over the values or keys in the map. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} stride Stride. + * @return {number} offset Offset. */ -goog.structs.Map.prototype.__iterator__ = function(opt_keys) { - // Clean up keys to minimize the risk of iterating over dead keys. - this.cleanupKeysArray_(); +ol.geom.flat.deflate.coordinate = + function(flatCoordinates, offset, coordinate, stride) { + goog.asserts.assert(coordinate.length == stride, + 'length of the coordinate array should match stride'); + var i, ii; + for (i = 0, ii = coordinate.length; i < ii; ++i) { + flatCoordinates[offset++] = coordinate[i]; + } + return offset; +}; - var i = 0; - var version = this.version_; - var selfObj = this; - var newIter = new goog.iter.Iterator; - newIter.next = function() { - if (version != selfObj.version_) { - throw Error('The map has changed since the iterator was created'); - } - if (i >= selfObj.keys_.length) { - throw goog.iter.StopIteration; +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {number} stride Stride. + * @return {number} offset Offset. + */ +ol.geom.flat.deflate.coordinates = + function(flatCoordinates, offset, coordinates, stride) { + var i, ii; + for (i = 0, ii = coordinates.length; i < ii; ++i) { + var coordinate = coordinates[i]; + goog.asserts.assert(coordinate.length == stride, + 'length of coordinate array should match stride'); + var j; + for (j = 0; j < stride; ++j) { + flatCoordinates[offset++] = coordinate[j]; } - var key = selfObj.keys_[i++]; - return opt_keys ? key : selfObj.map_[key]; - }; - return newIter; + } + return offset; }; /** - * Safe way to test for hasOwnProperty. It even allows testing for - * 'hasOwnProperty'. - * @param {Object} obj The object to test for presence of the given key. - * @param {*} key The key to check for. - * @return {boolean} Whether the object has the key. - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess. + * @param {number} stride Stride. + * @param {Array.<number>=} opt_ends Ends. + * @return {Array.<number>} Ends. */ -goog.structs.Map.hasKey_ = function(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); +ol.geom.flat.deflate.coordinatess = + function(flatCoordinates, offset, coordinatess, stride, opt_ends) { + var ends = opt_ends ? opt_ends : []; + var i = 0; + var j, jj; + for (j = 0, jj = coordinatess.length; j < jj; ++j) { + var end = ol.geom.flat.deflate.coordinates( + flatCoordinates, offset, coordinatess[j], stride); + ends[i++] = end; + offset = end; + } + ends.length = i; + return ends; }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Datastructure: Set. - * - * @author arv@google.com (Erik Arvidsson) - * - * This class implements a set data structure. Adding and removing is O(1). It - * supports both object and primitive values. Be careful because you can add - * both 1 and new Number(1), because these are not the same. You can even add - * multiple new Number(1) because these are not equal. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss. + * @param {number} stride Stride. + * @param {Array.<Array.<number>>=} opt_endss Endss. + * @return {Array.<Array.<number>>} Endss. */ +ol.geom.flat.deflate.coordinatesss = + function(flatCoordinates, offset, coordinatesss, stride, opt_endss) { + var endss = opt_endss ? opt_endss : []; + var i = 0; + var j, jj; + for (j = 0, jj = coordinatesss.length; j < jj; ++j) { + var ends = ol.geom.flat.deflate.coordinatess( + flatCoordinates, offset, coordinatesss[j], stride, endss[i]); + endss[i++] = ends; + offset = ends[ends.length - 1]; + } + endss.length = i; + return endss; +}; - -goog.provide('goog.structs.Set'); - -goog.require('goog.structs'); -goog.require('goog.structs.Collection'); -goog.require('goog.structs.Map'); - +goog.provide('ol.geom.flat.inflate'); /** - * A set that can contain both primitives and objects. Adding and removing - * elements is O(1). Primitives are treated as identical if they have the same - * type and convert to the same string. Objects are treated as identical only - * if they are references to the same object. WARNING: A goog.structs.Set can - * contain both 1 and (new Number(1)), because they are not the same. WARNING: - * Adding (new Number(1)) twice will yield two distinct elements, because they - * are two different objects. WARNING: Any object that is added to a - * goog.structs.Set will be modified! Because goog.getUid() is used to - * identify objects, every object in the set will be mutated. - * @param {Array<T>|Object<?,T>=} opt_values Initial values to start with. - * @constructor - * @implements {goog.structs.Collection<T>} - * @final - * @template T + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates. + * @return {Array.<ol.Coordinate>} Coordinates. */ -goog.structs.Set = function(opt_values) { - this.map_ = new goog.structs.Map; - if (opt_values) { - this.addAll(opt_values); +ol.geom.flat.inflate.coordinates = + function(flatCoordinates, offset, end, stride, opt_coordinates) { + var coordinates = opt_coordinates !== undefined ? opt_coordinates : []; + var i = 0; + var j; + for (j = offset; j < end; j += stride) { + coordinates[i++] = flatCoordinates.slice(j, j + stride); } + coordinates.length = i; + return coordinates; }; /** - * Obtains a unique key for an element of the set. Primitives will yield the - * same key if they have the same type and convert to the same string. Object - * references will yield the same key only if they refer to the same object. - * @param {*} val Object or primitive value to get a key for. - * @return {string} A unique key for this value/object. - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess. + * @return {Array.<Array.<ol.Coordinate>>} Coordinatess. */ -goog.structs.Set.getKey_ = function(val) { - var type = typeof val; - if (type == 'object' && val || type == 'function') { - return 'o' + goog.getUid(/** @type {Object} */ (val)); - } else { - return type.substr(0, 1) + val; +ol.geom.flat.inflate.coordinatess = + function(flatCoordinates, offset, ends, stride, opt_coordinatess) { + var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : []; + var i = 0; + var j, jj; + for (j = 0, jj = ends.length; j < jj; ++j) { + var end = ends[j]; + coordinatess[i++] = ol.geom.flat.inflate.coordinates( + flatCoordinates, offset, end, stride, coordinatess[i]); + offset = end; } + coordinatess.length = i; + return coordinatess; }; /** - * @return {number} The number of elements in the set. - * @override + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss + * Coordinatesss. + * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss. */ -goog.structs.Set.prototype.getCount = function() { - return this.map_.getCount(); +ol.geom.flat.inflate.coordinatesss = + function(flatCoordinates, offset, endss, stride, opt_coordinatesss) { + var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : []; + var i = 0; + var j, jj; + for (j = 0, jj = endss.length; j < jj; ++j) { + var ends = endss[j]; + coordinatesss[i++] = ol.geom.flat.inflate.coordinatess( + flatCoordinates, offset, ends, stride, coordinatesss[i]); + offset = ends[ends.length - 1]; + } + coordinatesss.length = i; + return coordinatesss; }; +// Based on simplify-js https://github.com/mourner/simplify-js +// Copyright (c) 2012, Vladimir Agafonkin +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +goog.provide('ol.geom.flat.simplify'); -/** - * Add a primitive or an object to the set. - * @param {T} element The primitive or object to add. - * @override - */ -goog.structs.Set.prototype.add = function(element) { - this.map_.set(goog.structs.Set.getKey_(element), element); -}; +goog.require('ol.math'); /** - * Adds all the values in the given collection to this set. - * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection - * containing the elements to add. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} squaredTolerance Squared tolerance. + * @param {boolean} highQuality Highest quality. + * @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat + * coordinates. + * @return {Array.<number>} Simplified line string. */ -goog.structs.Set.prototype.addAll = function(col) { - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - this.add(values[i]); +ol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end, + stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) { + var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ? + opt_simplifiedFlatCoordinates : []; + if (!highQuality) { + end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end, + stride, squaredTolerance, + simplifiedFlatCoordinates, 0); + flatCoordinates = simplifiedFlatCoordinates; + offset = 0; + stride = 2; } + simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( + flatCoordinates, offset, end, stride, squaredTolerance, + simplifiedFlatCoordinates, 0); + return simplifiedFlatCoordinates; }; /** - * Removes all values in the given collection from this set. - * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection - * containing the elements to remove. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} squaredTolerance Squared tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.removeAll = function(col) { - var values = goog.structs.getValues(col); - var l = values.length; - for (var i = 0; i < l; i++) { - this.remove(values[i]); +ol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end, + stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) { + var n = (end - offset) / stride; + if (n < 3) { + for (; offset < end; offset += stride) { + simplifiedFlatCoordinates[simplifiedOffset++] = + flatCoordinates[offset]; + simplifiedFlatCoordinates[simplifiedOffset++] = + flatCoordinates[offset + 1]; + } + return simplifiedOffset; + } + /** @type {Array.<number>} */ + var markers = new Array(n); + markers[0] = 1; + markers[n - 1] = 1; + /** @type {Array.<number>} */ + var stack = [offset, end - stride]; + var index = 0; + var i; + while (stack.length > 0) { + var last = stack.pop(); + var first = stack.pop(); + var maxSquaredDistance = 0; + var x1 = flatCoordinates[first]; + var y1 = flatCoordinates[first + 1]; + var x2 = flatCoordinates[last]; + var y2 = flatCoordinates[last + 1]; + for (i = first + stride; i < last; i += stride) { + var x = flatCoordinates[i]; + var y = flatCoordinates[i + 1]; + var squaredDistance = ol.math.squaredSegmentDistance( + x, y, x1, y1, x2, y2); + if (squaredDistance > maxSquaredDistance) { + index = i; + maxSquaredDistance = squaredDistance; + } + } + if (maxSquaredDistance > squaredTolerance) { + markers[(index - offset) / stride] = 1; + if (first + stride < index) { + stack.push(first, index); + } + if (index + stride < last) { + stack.push(index, last); + } + } + } + for (i = 0; i < n; ++i) { + if (markers[i]) { + simplifiedFlatCoordinates[simplifiedOffset++] = + flatCoordinates[offset + i * stride]; + simplifiedFlatCoordinates[simplifiedOffset++] = + flatCoordinates[offset + i * stride + 1]; + } } + return simplifiedOffset; }; /** - * Removes the given element from this set. - * @param {T} element The primitive or object to remove. - * @return {boolean} Whether the element was found and removed. - * @override + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {number} squaredTolerance Squared tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @param {Array.<number>} simplifiedEnds Simplified ends. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.remove = function(element) { - return this.map_.remove(goog.structs.Set.getKey_(element)); +ol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset, + ends, stride, squaredTolerance, simplifiedFlatCoordinates, + simplifiedOffset, simplifiedEnds) { + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + simplifiedOffset = ol.geom.flat.simplify.douglasPeucker( + flatCoordinates, offset, end, stride, squaredTolerance, + simplifiedFlatCoordinates, simplifiedOffset); + simplifiedEnds.push(simplifiedOffset); + offset = end; + } + return simplifiedOffset; }; /** - * Removes all elements from this set. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {number} squaredTolerance Squared tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.clear = function() { - this.map_.clear(); +ol.geom.flat.simplify.douglasPeuckerss = function( + flatCoordinates, offset, endss, stride, squaredTolerance, + simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) { + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + var simplifiedEnds = []; + simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers( + flatCoordinates, offset, ends, stride, squaredTolerance, + simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds); + simplifiedEndss.push(simplifiedEnds); + offset = ends[ends.length - 1]; + } + return simplifiedOffset; }; /** - * Tests whether this set is empty. - * @return {boolean} True if there are no elements in this set. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} squaredTolerance Squared tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.isEmpty = function() { - return this.map_.isEmpty(); +ol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end, + stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) { + if (end <= offset + stride) { + // zero or one point, no simplification possible, so copy and return + for (; offset < end; offset += stride) { + simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset]; + simplifiedFlatCoordinates[simplifiedOffset++] = + flatCoordinates[offset + 1]; + } + return simplifiedOffset; + } + var x1 = flatCoordinates[offset]; + var y1 = flatCoordinates[offset + 1]; + // copy first point + simplifiedFlatCoordinates[simplifiedOffset++] = x1; + simplifiedFlatCoordinates[simplifiedOffset++] = y1; + var x2 = x1; + var y2 = y1; + for (offset += stride; offset < end; offset += stride) { + x2 = flatCoordinates[offset]; + y2 = flatCoordinates[offset + 1]; + if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) { + // copy point at offset + simplifiedFlatCoordinates[simplifiedOffset++] = x2; + simplifiedFlatCoordinates[simplifiedOffset++] = y2; + x1 = x2; + y1 = y2; + } + } + if (x2 != x1 || y2 != y1) { + // copy last point + simplifiedFlatCoordinates[simplifiedOffset++] = x2; + simplifiedFlatCoordinates[simplifiedOffset++] = y2; + } + return simplifiedOffset; }; /** - * Tests whether this set contains the given element. - * @param {T} element The primitive or object to test for. - * @return {boolean} True if this set contains the given element. - * @override + * @param {number} value Value. + * @param {number} tolerance Tolerance. + * @return {number} Rounded value. */ -goog.structs.Set.prototype.contains = function(element) { - return this.map_.containsKey(goog.structs.Set.getKey_(element)); +ol.geom.flat.simplify.snap = function(value, tolerance) { + return tolerance * Math.round(value / tolerance); }; /** - * Tests whether this set contains all the values in a given collection. - * Repeated elements in the collection are ignored, e.g. (new - * goog.structs.Set([1, 2])).containsAll([1, 1]) is True. - * @param {goog.structs.Collection<T>|Object} col A collection-like object. - * @return {boolean} True if the set contains all elements. + * Simplifies a line string using an algorithm designed by Tim Schaub. + * Coordinates are snapped to the nearest value in a virtual grid and + * consecutive duplicate coordinates are discarded. This effectively preserves + * topology as the simplification of any subsection of a line string is + * independent of the rest of the line string. This means that, for examples, + * the common edge between two polygons will be simplified to the same line + * string independently in both polygons. This implementation uses a single + * pass over the coordinates and eliminates intermediate collinear points. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} tolerance Tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.containsAll = function(col) { - return goog.structs.every(col, this.contains, this); +ol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride, + tolerance, simplifiedFlatCoordinates, simplifiedOffset) { + // do nothing if the line is empty + if (offset == end) { + return simplifiedOffset; + } + // snap the first coordinate (P1) + var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); + var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); + offset += stride; + // add the first coordinate to the output + simplifiedFlatCoordinates[simplifiedOffset++] = x1; + simplifiedFlatCoordinates[simplifiedOffset++] = y1; + // find the next coordinate that does not snap to the same value as the first + // coordinate (P2) + var x2, y2; + do { + x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); + y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); + offset += stride; + if (offset == end) { + // all coordinates snap to the same value, the line collapses to a point + // push the last snapped value anyway to ensure that the output contains + // at least two points + // FIXME should we really return at least two points anyway? + simplifiedFlatCoordinates[simplifiedOffset++] = x2; + simplifiedFlatCoordinates[simplifiedOffset++] = y2; + return simplifiedOffset; + } + } while (x2 == x1 && y2 == y1); + while (offset < end) { + var x3, y3; + // snap the next coordinate (P3) + x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance); + y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance); + offset += stride; + // skip P3 if it is equal to P2 + if (x3 == x2 && y3 == y2) { + continue; + } + // calculate the delta between P1 and P2 + var dx1 = x2 - x1; + var dy1 = y2 - y1; + // calculate the delta between P3 and P1 + var dx2 = x3 - x1; + var dy2 = y3 - y1; + // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from + // P1 in the same direction then P2 is on the straight line between P1 and + // P3 + if ((dx1 * dy2 == dy1 * dx2) && + ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) && + ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) { + // discard P2 and set P2 = P3 + x2 = x3; + y2 = y3; + continue; + } + // either P1, P2, and P3 are not colinear, or they are colinear but P3 is + // between P3 and P1 or on the opposite half of the line to P2. add P2, + // and continue with P1 = P2 and P2 = P3 + simplifiedFlatCoordinates[simplifiedOffset++] = x2; + simplifiedFlatCoordinates[simplifiedOffset++] = y2; + x1 = x2; + y1 = y2; + x2 = x3; + y2 = y3; + } + // add the last point (P2) + simplifiedFlatCoordinates[simplifiedOffset++] = x2; + simplifiedFlatCoordinates[simplifiedOffset++] = y2; + return simplifiedOffset; }; /** - * Finds all values that are present in both this set and the given collection. - * @param {Array<S>|Object<?,S>} col A collection. - * @return {!goog.structs.Set<T|S>} A new set containing all the values - * (primitives or objects) present in both this set and the given - * collection. - * @template S + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {number} tolerance Tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @param {Array.<number>} simplifiedEnds Simplified ends. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.intersection = function(col) { - var result = new goog.structs.Set(); - - var values = goog.structs.getValues(col); - for (var i = 0; i < values.length; i++) { - var value = values[i]; - if (this.contains(value)) { - result.add(value); - } +ol.geom.flat.simplify.quantizes = function( + flatCoordinates, offset, ends, stride, + tolerance, + simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) { + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + simplifiedOffset = ol.geom.flat.simplify.quantize( + flatCoordinates, offset, end, stride, + tolerance, + simplifiedFlatCoordinates, simplifiedOffset); + simplifiedEnds.push(simplifiedOffset); + offset = end; } - - return result; + return simplifiedOffset; }; /** - * Finds all values that are present in this set and not in the given - * collection. - * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection. - * @return {!goog.structs.Set} A new set containing all the values - * (primitives or objects) present in this set but not in the given - * collection. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {number} tolerance Tolerance. + * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat + * coordinates. + * @param {number} simplifiedOffset Simplified offset. + * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss. + * @return {number} Simplified offset. */ -goog.structs.Set.prototype.difference = function(col) { - var result = this.clone(); - result.removeAll(col); - return result; +ol.geom.flat.simplify.quantizess = function( + flatCoordinates, offset, endss, stride, + tolerance, + simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) { + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + var simplifiedEnds = []; + simplifiedOffset = ol.geom.flat.simplify.quantizes( + flatCoordinates, offset, ends, stride, + tolerance, + simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds); + simplifiedEndss.push(simplifiedEnds); + offset = ends[ends.length - 1]; + } + return simplifiedOffset; }; +goog.provide('ol.geom.LinearRing'); + +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.area'); +goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.geom.flat.simplify'); -/** - * Returns an array containing all the elements in this set. - * @return {!Array<T>} An array containing all the elements in this set. - */ -goog.structs.Set.prototype.getValues = function() { - return this.map_.getValues(); -}; /** - * Creates a shallow clone of this set. - * @return {!goog.structs.Set<T>} A new set containing all the same elements as - * this set. + * @classdesc + * Linear ring geometry. Only used as part of polygon; cannot be rendered + * on its own. + * + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable */ -goog.structs.Set.prototype.clone = function() { - return new goog.structs.Set(this); +ol.geom.LinearRing = function(coordinates, opt_layout) { + + goog.base(this); + + /** + * @private + * @type {number} + */ + this.maxDelta_ = -1; + + /** + * @private + * @type {number} + */ + this.maxDeltaRevision_ = -1; + + this.setCoordinates(coordinates, opt_layout); + }; +goog.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry); /** - * Tests whether the given collection consists of the same elements as this set, - * regardless of order, without repetition. Primitives are treated as equal if - * they have the same type and convert to the same string; objects are treated - * as equal if they are references to the same object. This operation is O(n). - * @param {goog.structs.Collection<T>|Object} col A collection. - * @return {boolean} True if the given collection consists of the same elements - * as this set, regardless of order, without repetition. + * Make a complete copy of the geometry. + * @return {!ol.geom.LinearRing} Clone. + * @api stable */ -goog.structs.Set.prototype.equals = function(col) { - return this.getCount() == goog.structs.getCount(col) && this.isSubsetOf(col); +ol.geom.LinearRing.prototype.clone = function() { + var linearRing = new ol.geom.LinearRing(null); + linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return linearRing; }; /** - * Tests whether the given collection contains all the elements in this set. - * Primitives are treated as equal if they have the same type and convert to the - * same string; objects are treated as equal if they are references to the same - * object. This operation is O(n). - * @param {goog.structs.Collection<T>|Object} col A collection. - * @return {boolean} True if this set is a subset of the given collection. + * @inheritDoc */ -goog.structs.Set.prototype.isSubsetOf = function(col) { - var colCount = goog.structs.getCount(col); - if (this.getCount() > colCount) { - return false; +ol.geom.LinearRing.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; } - // TODO(user) Find the minimal collection size where the conversion makes - // the contains() method faster. - if (!(col instanceof goog.structs.Set) && colCount > 5) { - // Convert to a goog.structs.Set so that goog.structs.contains runs in - // O(1) time instead of O(n) time. - col = new goog.structs.Set(col); + if (this.maxDeltaRevision_ != this.getRevision()) { + this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0)); + this.maxDeltaRevision_ = this.getRevision(); } - return goog.structs.every(this, function(value) { - return goog.structs.contains(col, value); - }); + return ol.geom.flat.closest.getClosestPoint( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); }; /** - * Returns an iterator that iterates over the elements in this set. - * @param {boolean=} opt_keys This argument is ignored. - * @return {!goog.iter.Iterator} An iterator over the elements in this set. + * Return the area of the linear ring on projected plane. + * @return {number} Area (on projected plane). + * @api stable */ -goog.structs.Set.prototype.__iterator__ = function(opt_keys) { - return this.map_.__iterator__(false); +ol.geom.LinearRing.prototype.getArea = function() { + return ol.geom.flat.area.linearRing( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Logging and debugging utilities. - * - * @see ../demos/debug.html + * Return the coordinates of the linear ring. + * @return {Array.<ol.Coordinate>} Coordinates. + * @api stable */ - -goog.provide('goog.debug'); - -goog.require('goog.array'); -goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeUrl'); -goog.require('goog.html.uncheckedconversions'); -goog.require('goog.string.Const'); -goog.require('goog.structs.Set'); -goog.require('goog.userAgent'); - - -/** @define {boolean} Whether logging should be enabled. */ -goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG); +ol.geom.LinearRing.prototype.getCoordinates = function() { + return ol.geom.flat.inflate.coordinates( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); +}; /** - * Catches onerror events fired by windows and similar objects. - * @param {function(Object)} logFunc The function to call with the error - * information. - * @param {boolean=} opt_cancel Whether to stop the error from reaching the - * browser. - * @param {Object=} opt_target Object that fires onerror events. + * @inheritDoc */ -goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) { - var target = opt_target || goog.global; - var oldErrorHandler = target.onerror; - var retVal = !!opt_cancel; +ol.geom.LinearRing.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + var simplifiedFlatCoordinates = []; + simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + squaredTolerance, simplifiedFlatCoordinates, 0); + var simplifiedLinearRing = new ol.geom.LinearRing(null); + simplifiedLinearRing.setFlatCoordinates( + ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates); + return simplifiedLinearRing; +}; - // Chrome interprets onerror return value backwards (http://crbug.com/92062) - // until it was fixed in webkit revision r94061 (Webkit 535.3). This - // workaround still needs to be skipped in Safari after the webkit change - // gets pushed out in Safari. - // See https://bugs.webkit.org/show_bug.cgi?id=67119 - if (goog.userAgent.WEBKIT && - !goog.userAgent.isVersionOrHigher('535.3')) { - retVal = !retVal; - } - /** - * New onerror handler for this target. This onerror handler follows the spec - * according to - * http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors - * The spec was changed in August 2013 to support receiving column information - * and an error object for all scripts on the same origin or cross origin - * scripts with the proper headers. See - * https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror - * - * @param {string} message The error message. For cross-origin errors, this - * will be scrubbed to just "Script error.". For new browsers that have - * updated to follow the latest spec, errors that come from origins that - * have proper cross origin headers will not be scrubbed. - * @param {string} url The URL of the script that caused the error. The URL - * will be scrubbed to "" for cross origin scripts unless the script has - * proper cross origin headers and the browser has updated to the latest - * spec. - * @param {number} line The line number in the script that the error - * occurred on. - * @param {number=} opt_col The optional column number that the error - * occurred on. Only browsers that have updated to the latest spec will - * include this. - * @param {Error=} opt_error The optional actual error object for this - * error that should include the stack. Only browsers that have updated - * to the latest spec will inlude this parameter. - * @return {boolean} Whether to prevent the error from reaching the browser. - */ - target.onerror = function(message, url, line, opt_col, opt_error) { - if (oldErrorHandler) { - oldErrorHandler(message, url, line, opt_col, opt_error); - } - logFunc({ - message: message, - fileName: url, - line: line, - col: opt_col, - error: opt_error - }); - return retVal; - }; +/** + * @inheritDoc + * @api stable + */ +ol.geom.LinearRing.prototype.getType = function() { + return ol.geom.GeometryType.LINEAR_RING; }; /** - * Creates a string representing an object and all its properties. - * @param {Object|null|undefined} obj Object to expose. - * @param {boolean=} opt_showFn Show the functions as well as the properties, - * default is false. - * @return {string} The string representation of {@code obj}. + * Set the coordinates of the linear ring. + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable */ -goog.debug.expose = function(obj, opt_showFn) { - if (typeof obj == 'undefined') { - return 'undefined'; - } - if (obj == null) { - return 'NULL'; - } - var str = []; - - for (var x in obj) { - if (!opt_showFn && goog.isFunction(obj[x])) { - continue; - } - var s = x + ' = '; - /** @preserveTry */ - try { - s += obj[x]; - } catch (e) { - s += '*** ' + e + ' ***'; +ol.geom.LinearRing.prototype.setCoordinates = + function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); + } else { + this.setLayout(opt_layout, coordinates, 1); + if (!this.flatCoordinates) { + this.flatCoordinates = []; } - str.push(s); + this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( + this.flatCoordinates, 0, coordinates, this.stride); + this.changed(); } - return str.join('\n'); }; /** - * Creates a string representing a given primitive or object, and for an - * object, all its properties and nested objects. WARNING: If an object is - * given, it and all its nested objects will be modified. To detect reference - * cycles, this method identifies objects using goog.getUid() which mutates the - * object. - * @param {*} obj Object to expose. - * @param {boolean=} opt_showFn Also show properties that are functions (by - * default, functions are omitted). - * @return {string} A string representation of {@code obj}. + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. */ -goog.debug.deepExpose = function(obj, opt_showFn) { - var str = []; - - var helper = function(obj, space, parentSeen) { - var nestspace = space + ' '; - var seen = new goog.structs.Set(parentSeen); +ol.geom.LinearRing.prototype.setFlatCoordinates = + function(layout, flatCoordinates) { + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.changed(); +}; - var indentMultiline = function(str) { - return str.replace(/\n/g, '\n' + space); - }; +goog.provide('ol.geom.Point'); - /** @preserveTry */ - try { - if (!goog.isDef(obj)) { - str.push('undefined'); - } else if (goog.isNull(obj)) { - str.push('NULL'); - } else if (goog.isString(obj)) { - str.push('"' + indentMultiline(obj) + '"'); - } else if (goog.isFunction(obj)) { - str.push(indentMultiline(String(obj))); - } else if (goog.isObject(obj)) { - if (seen.contains(obj)) { - str.push('*** reference loop detected ***'); - } else { - seen.add(obj); - str.push('{'); - for (var x in obj) { - if (!opt_showFn && goog.isFunction(obj[x])) { - continue; - } - str.push('\n'); - str.push(nestspace); - str.push(x + ' = '); - helper(obj[x], nestspace, seen); - } - str.push('\n' + space + '}'); - } - } else { - str.push(obj); - } - } catch (e) { - str.push('*** ' + e + ' ***'); - } - }; +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.math'); - helper(obj, '', new goog.structs.Set()); - return str.join(''); -}; /** - * Recursively outputs a nested array as a string. - * @param {Array<?>} arr The array. - * @return {string} String representing nested array. + * @classdesc + * Point geometry. + * + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {ol.Coordinate} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable */ -goog.debug.exposeArray = function(arr) { - var str = []; - for (var i = 0; i < arr.length; i++) { - if (goog.isArray(arr[i])) { - str.push(goog.debug.exposeArray(arr[i])); - } else { - str.push(arr[i]); - } - } - return '[ ' + str.join(', ') + ' ]'; +ol.geom.Point = function(coordinates, opt_layout) { + goog.base(this); + this.setCoordinates(coordinates, opt_layout); }; +goog.inherits(ol.geom.Point, ol.geom.SimpleGeometry); /** - * Exposes an exception that has been caught by a try...catch and outputs the - * error as HTML with a stack trace. - * @param {Object} err Error object or string. - * @param {Function=} opt_fn Optional function to start stack trace from. - * @return {string} Details of exception, as HTML. + * Make a complete copy of the geometry. + * @return {!ol.geom.Point} Clone. + * @api stable */ -goog.debug.exposeException = function(err, opt_fn) { - var html = goog.debug.exposeExceptionAsHtml(err, opt_fn); - return goog.html.SafeHtml.unwrap(html); +ol.geom.Point.prototype.clone = function() { + var point = new ol.geom.Point(null); + point.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return point; }; /** - * Exposes an exception that has been caught by a try...catch and outputs the - * error with a stack trace. - * @param {Object} err Error object or string. - * @param {Function=} opt_fn Optional function to start stack trace from. - * @return {!goog.html.SafeHtml} Details of exception. + * @inheritDoc */ -goog.debug.exposeExceptionAsHtml = function(err, opt_fn) { - /** @preserveTry */ - try { - var e = goog.debug.normalizeErrorObject(err); - // Create the error message - var viewSourceUrl = goog.debug.createViewSourceUrl_(e.fileName); - var error = goog.html.SafeHtml.concat( - goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - 'Message: ' + e.message + '\nUrl: '), - goog.html.SafeHtml.create('a', - {href: viewSourceUrl, target: '_new'}, e.fileName), - goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - '\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' + - e.stack + '-> ' + '[end]\n\nJS stack traversal:\n' + - goog.debug.getStacktrace(opt_fn) + '-> ')); - return error; - } catch (e2) { - return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - 'Exception trying to expose exception! You win, we lose. ' + e2); +ol.geom.Point.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + var flatCoordinates = this.flatCoordinates; + var squaredDistance = ol.math.squaredDistance( + x, y, flatCoordinates[0], flatCoordinates[1]); + if (squaredDistance < minSquaredDistance) { + var stride = this.stride; + var i; + for (i = 0; i < stride; ++i) { + closestPoint[i] = flatCoordinates[i]; + } + closestPoint.length = stride; + return squaredDistance; + } else { + return minSquaredDistance; } }; /** - * @param {?string=} opt_fileName - * @return {!goog.html.SafeUrl} SafeUrl with view-source scheme, pointing at - * fileName. - * @private + * Return the coordinate of the point. + * @return {ol.Coordinate} Coordinates. + * @api stable */ -goog.debug.createViewSourceUrl_ = function(opt_fileName) { - if (!goog.isDefAndNotNull(opt_fileName)) { - opt_fileName = ''; - } - if (!/^https?:\/\//i.test(opt_fileName)) { - return goog.html.SafeUrl.fromConstant( - goog.string.Const.from('sanitizedviewsrc')); - } - var sanitizedFileName = goog.html.SafeUrl.sanitize(opt_fileName); - return goog.html.uncheckedconversions. - safeUrlFromStringKnownToSatisfyTypeContract( - goog.string.Const.from('view-source scheme plus HTTP/HTTPS URL'), - 'view-source:' + goog.html.SafeUrl.unwrap(sanitizedFileName)); +ol.geom.Point.prototype.getCoordinates = function() { + return !this.flatCoordinates ? [] : this.flatCoordinates.slice(); }; /** - * Normalizes the error/exception object between browsers. - * @param {Object} err Raw error object. - * @return {!Object} Normalized error object. + * @inheritDoc */ -goog.debug.normalizeErrorObject = function(err) { - var href = goog.getObjectByName('window.location.href'); - if (goog.isString(err)) { - return { - 'message': err, - 'name': 'Unknown error', - 'lineNumber': 'Not available', - 'fileName': href, - 'stack': 'Not available' - }; - } - - var lineNumber, fileName; - var threwError = false; +ol.geom.Point.prototype.computeExtent = function(extent) { + return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent); +}; - try { - lineNumber = err.lineNumber || err.line || 'Not available'; - } catch (e) { - // Firefox 2 sometimes throws an error when accessing 'lineNumber': - // Message: Permission denied to get property UnnamedClass.lineNumber - lineNumber = 'Not available'; - threwError = true; - } - try { - fileName = err.fileName || err.filename || err.sourceURL || - // $googDebugFname may be set before a call to eval to set the filename - // that the eval is supposed to present. - goog.global['$googDebugFname'] || href; - } catch (e) { - // Firefox 2 may also throw an error when accessing 'filename'. - fileName = 'Not available'; - threwError = true; - } +/** + * @inheritDoc + * @api stable + */ +ol.geom.Point.prototype.getType = function() { + return ol.geom.GeometryType.POINT; +}; - // The IE Error object contains only the name and the message. - // The Safari Error object uses the line and sourceURL fields. - if (threwError || !err.lineNumber || !err.fileName || !err.stack || - !err.message || !err.name) { - return { - 'message': err.message || 'Not available', - 'name': err.name || 'UnknownError', - 'lineNumber': lineNumber, - 'fileName': fileName, - 'stack': err.stack || 'Not available' - }; - } - // Standards error object - return err; +/** + * @inheritDoc + * @api stable + */ +ol.geom.Point.prototype.intersectsExtent = function(extent) { + return ol.extent.containsXY(extent, + this.flatCoordinates[0], this.flatCoordinates[1]); }; /** - * Converts an object to an Error if it's a String, - * adds a stacktrace if there isn't one, - * and optionally adds an extra message. - * @param {Error|string} err the original thrown object or string. - * @param {string=} opt_message optional additional message to add to the - * error. - * @return {!Error} If err is a string, it is used to create a new Error, - * which is enhanced and returned. Otherwise err itself is enhanced - * and returned. + * Set the coordinate of the point. + * @param {ol.Coordinate} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable */ -goog.debug.enhanceError = function(err, opt_message) { - var error; - if (typeof err == 'string') { - error = Error(err); - if (Error.captureStackTrace) { - // Trim this function off the call stack, if we can. - Error.captureStackTrace(error, goog.debug.enhanceError); - } +ol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); } else { - error = err; - } - - if (!error.stack) { - error.stack = goog.debug.getStacktrace(goog.debug.enhanceError); - } - if (opt_message) { - // find the first unoccupied 'messageX' property - var x = 0; - while (error['message' + x]) { - ++x; + this.setLayout(opt_layout, coordinates, 0); + if (!this.flatCoordinates) { + this.flatCoordinates = []; } - error['message' + x] = String(opt_message); + this.flatCoordinates.length = ol.geom.flat.deflate.coordinate( + this.flatCoordinates, 0, coordinates, this.stride); + this.changed(); } - return error; }; /** - * Gets the current stack trace. Simple and iterative - doesn't worry about - * catching circular references or getting the args. - * @param {number=} opt_depth Optional maximum depth to trace back to. - * @return {string} A string with the function names of all functions in the - * stack, separated by \n. - * @suppress {es5Strict} + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. */ -goog.debug.getStacktraceSimple = function(opt_depth) { - if (goog.STRICT_MODE_COMPATIBLE) { - var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple); - if (stack) { - return stack; - } - // NOTE: browsers that have strict mode support also have native "stack" - // properties. Fall-through for legacy browser support. - } - - var sb = []; - var fn = arguments.callee.caller; - var depth = 0; +ol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) { + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.changed(); +}; - while (fn && (!opt_depth || depth < opt_depth)) { - sb.push(goog.debug.getFunctionName(fn)); - sb.push('()\n'); - /** @preserveTry */ - try { - fn = fn.caller; - } catch (e) { - sb.push('[exception trying to get caller]\n'); - break; - } - depth++; - if (depth >= goog.debug.MAX_STACK_DEPTH) { - sb.push('[...long stack...]'); - break; - } - } - if (opt_depth && depth >= opt_depth) { - sb.push('[...reached max depth limit...]'); - } else { - sb.push('[end]'); - } +goog.provide('ol.geom.flat.contains'); - return sb.join(''); -}; +goog.require('goog.asserts'); +goog.require('ol.extent'); /** - * Max length of stack to try and output - * @type {number} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {ol.Extent} extent Extent. + * @return {boolean} Contains extent. */ -goog.debug.MAX_STACK_DEPTH = 50; +ol.geom.flat.contains.linearRingContainsExtent = + function(flatCoordinates, offset, end, stride, extent) { + var outside = ol.extent.forEachCorner(extent, + /** + * @param {ol.Coordinate} coordinate Coordinate. + */ + function(coordinate) { + return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates, + offset, end, stride, coordinate[0], coordinate[1]); + }); + return !outside; +}; /** - * @param {Function} fn The function to start getting the trace from. - * @return {?string} - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @return {boolean} Contains (x, y). */ -goog.debug.getNativeStackTrace_ = function(fn) { - var tempErr = new Error(); - if (Error.captureStackTrace) { - Error.captureStackTrace(tempErr, fn); - return String(tempErr.stack); - } else { - // IE10, only adds stack traces when an exception is thrown. - try { - throw tempErr; - } catch (e) { - tempErr = e; - } - var stack = tempErr.stack; - if (stack) { - return String(stack); +ol.geom.flat.contains.linearRingContainsXY = + function(flatCoordinates, offset, end, stride, x, y) { + // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html + var contains = false; + var x1 = flatCoordinates[end - stride]; + var y1 = flatCoordinates[end - stride + 1]; + for (; offset < end; offset += stride) { + var x2 = flatCoordinates[offset]; + var y2 = flatCoordinates[offset + 1]; + var intersect = ((y1 > y) != (y2 > y)) && + (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1); + if (intersect) { + contains = !contains; } + x1 = x2; + y1 = y2; } - return null; + return contains; }; /** - * Gets the current stack trace, either starting from the caller or starting - * from a specified function that's currently on the call stack. - * @param {Function=} opt_fn Optional function to start getting the trace from. - * If not provided, defaults to the function that called this. - * @return {string} Stack trace. - * @suppress {es5Strict} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @return {boolean} Contains (x, y). */ -goog.debug.getStacktrace = function(opt_fn) { - var stack; - if (goog.STRICT_MODE_COMPATIBLE) { - // Try to get the stack trace from the environment if it is available. - var contextFn = opt_fn || goog.debug.getStacktrace; - stack = goog.debug.getNativeStackTrace_(contextFn); +ol.geom.flat.contains.linearRingsContainsXY = + function(flatCoordinates, offset, ends, stride, x, y) { + goog.asserts.assert(ends.length > 0, 'ends should not be an empty array'); + if (ends.length === 0) { + return false; } - if (!stack) { - // NOTE: browsers that have strict mode support also have native "stack" - // properties. This function will throw in strict mode. - stack = goog.debug.getStacktraceHelper_( - opt_fn || arguments.callee.caller, []); + if (!ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, offset, ends[0], stride, x, y)) { + return false; } - return stack; + var i, ii; + for (i = 1, ii = ends.length; i < ii; ++i) { + if (ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, ends[i - 1], ends[i], stride, x, y)) { + return false; + } + } + return true; }; /** - * Private helper for getStacktrace(). - * @param {Function} fn Function to start getting the trace from. - * @param {Array<!Function>} visited List of functions visited so far. - * @return {string} Stack trace starting from function fn. - * @suppress {es5Strict} - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @return {boolean} Contains (x, y). */ -goog.debug.getStacktraceHelper_ = function(fn, visited) { - var sb = []; - - // Circular reference, certain functions like bind seem to cause a recursive - // loop so we need to catch circular references - if (goog.array.contains(visited, fn)) { - sb.push('[...circular reference...]'); - - // Traverse the call stack until function not found or max depth is reached - } else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) { - sb.push(goog.debug.getFunctionName(fn) + '('); - var args = fn.arguments; - // Args may be null for some special functions such as host objects or eval. - for (var i = 0; args && i < args.length; i++) { - if (i > 0) { - sb.push(', '); - } - var argDesc; - var arg = args[i]; - switch (typeof arg) { - case 'object': - argDesc = arg ? 'object' : 'null'; - break; - - case 'string': - argDesc = arg; - break; - - case 'number': - argDesc = String(arg); - break; +ol.geom.flat.contains.linearRingssContainsXY = + function(flatCoordinates, offset, endss, stride, x, y) { + goog.asserts.assert(endss.length > 0, 'endss should not be an empty array'); + if (endss.length === 0) { + return false; + } + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + if (ol.geom.flat.contains.linearRingsContainsXY( + flatCoordinates, offset, ends, stride, x, y)) { + return true; + } + offset = ends[ends.length - 1]; + } + return false; +}; - case 'boolean': - argDesc = arg ? 'true' : 'false'; - break; +goog.provide('ol.geom.flat.interiorpoint'); - case 'function': - argDesc = goog.debug.getFunctionName(arg); - argDesc = argDesc ? argDesc : '[fn]'; - break; +goog.require('goog.asserts'); +goog.require('ol.geom.flat.contains'); - case 'undefined': - default: - argDesc = typeof arg; - break; - } - if (argDesc.length > 40) { - argDesc = argDesc.substr(0, 40) + '...'; - } - sb.push(argDesc); +/** + * Calculates a point that is likely to lie in the interior of the linear rings. + * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {Array.<number>} flatCenters Flat centers. + * @param {number} flatCentersOffset Flat center offset. + * @param {Array.<number>=} opt_dest Destination. + * @return {Array.<number>} Destination. + */ +ol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset, + ends, stride, flatCenters, flatCentersOffset, opt_dest) { + var i, ii, x, x1, x2, y1, y2; + var y = flatCenters[flatCentersOffset + 1]; + /** @type {Array.<number>} */ + var intersections = []; + // Calculate intersections with the horizontal line + var end = ends[0]; + x1 = flatCoordinates[end - stride]; + y1 = flatCoordinates[end - stride + 1]; + for (i = offset; i < end; i += stride) { + x2 = flatCoordinates[i]; + y2 = flatCoordinates[i + 1]; + if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { + x = (y - y1) / (y2 - y1) * (x2 - x1) + x1; + intersections.push(x); } - visited.push(fn); - sb.push(')\n'); - /** @preserveTry */ - try { - sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited)); - } catch (e) { - sb.push('[exception trying to get caller]\n'); + x1 = x2; + y1 = y2; + } + // Find the longest segment of the horizontal line that has its center point + // inside the linear ring. + var pointX = NaN; + var maxSegmentLength = -Infinity; + intersections.sort(); + x1 = intersections[0]; + for (i = 1, ii = intersections.length; i < ii; ++i) { + x2 = intersections[i]; + var segmentLength = Math.abs(x2 - x1); + if (segmentLength > maxSegmentLength) { + x = (x1 + x2) / 2; + if (ol.geom.flat.contains.linearRingsContainsXY( + flatCoordinates, offset, ends, stride, x, y)) { + pointX = x; + maxSegmentLength = segmentLength; + } } - - } else if (fn) { - sb.push('[...long stack...]'); + x1 = x2; + } + if (isNaN(pointX)) { + // There is no horizontal line that has its center point inside the linear + // ring. Use the center of the the linear ring's extent. + pointX = flatCenters[flatCentersOffset]; + } + if (opt_dest) { + opt_dest.push(pointX, y); + return opt_dest; } else { - sb.push('[end]'); + return [pointX, y]; } - return sb.join(''); }; /** - * Set a custom function name resolver. - * @param {function(Function): string} resolver Resolves functions to their - * names. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {Array.<number>} flatCenters Flat centers. + * @return {Array.<number>} Interior points. */ -goog.debug.setFunctionResolver = function(resolver) { - goog.debug.fnNameResolver_ = resolver; +ol.geom.flat.interiorpoint.linearRingss = + function(flatCoordinates, offset, endss, stride, flatCenters) { + goog.asserts.assert(2 * endss.length == flatCenters.length, + 'endss.length times 2 should be flatCenters.length'); + var interiorPoints = []; + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates, + offset, ends, stride, flatCenters, 2 * i, interiorPoints); + offset = ends[ends.length - 1]; + } + return interiorPoints; }; +goog.provide('ol.geom.flat.segments'); + /** - * Gets a function name - * @param {Function} fn Function to get name of. - * @return {string} Function's name. + * This function calls `callback` for each segment of the flat coordinates + * array. If the callback returns a truthy value the function returns that + * value immediately. Otherwise the function returns `false`. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function + * called for each segment. + * @param {S=} opt_this The object to be used as the value of 'this' + * within callback. + * @return {T|boolean} Value. + * @template T,S */ -goog.debug.getFunctionName = function(fn) { - if (goog.debug.fnNameCache_[fn]) { - return goog.debug.fnNameCache_[fn]; - } - if (goog.debug.fnNameResolver_) { - var name = goog.debug.fnNameResolver_(fn); - if (name) { - goog.debug.fnNameCache_[fn] = name; - return name; +ol.geom.flat.segments.forEach = + function(flatCoordinates, offset, end, stride, callback, opt_this) { + var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]]; + var point2 = []; + var ret; + for (; (offset + stride) < end; offset += stride) { + point2[0] = flatCoordinates[offset + stride]; + point2[1] = flatCoordinates[offset + stride + 1]; + ret = callback.call(opt_this, point1, point2); + if (ret) { + return ret; } + point1[0] = point2[0]; + point1[1] = point2[1]; } + return false; +}; - // Heuristically determine function name based on code. - var functionSource = String(fn); - if (!goog.debug.fnNameCache_[functionSource]) { - var matches = /function ([^\(]+)/.exec(functionSource); - if (matches) { - var method = matches[1]; - goog.debug.fnNameCache_[functionSource] = method; - } else { - goog.debug.fnNameCache_[functionSource] = '[Anonymous]'; - } - } +goog.provide('ol.geom.flat.intersectsextent'); - return goog.debug.fnNameCache_[functionSource]; -}; +goog.require('goog.asserts'); +goog.require('ol.extent'); +goog.require('ol.geom.flat.contains'); +goog.require('ol.geom.flat.segments'); /** - * Makes whitespace visible by replacing it with printable characters. - * This is useful in finding diffrences between the expected and the actual - * output strings of a testcase. - * @param {string} string whose whitespace needs to be made visible. - * @return {string} string whose whitespace is made visible. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {ol.Extent} extent Extent. + * @return {boolean} True if the geometry and the extent intersect. */ -goog.debug.makeWhitespaceVisible = function(string) { - return string.replace(/ /g, '[_]') - .replace(/\f/g, '[f]') - .replace(/\n/g, '[n]\n') - .replace(/\r/g, '[r]') - .replace(/\t/g, '[t]'); +ol.geom.flat.intersectsextent.lineString = + function(flatCoordinates, offset, end, stride, extent) { + var coordinatesExtent = ol.extent.extendFlatCoordinates( + ol.extent.createEmpty(), flatCoordinates, offset, end, stride); + if (!ol.extent.intersects(extent, coordinatesExtent)) { + return false; + } + if (ol.extent.containsExtent(extent, coordinatesExtent)) { + return true; + } + if (coordinatesExtent[0] >= extent[0] && + coordinatesExtent[2] <= extent[2]) { + return true; + } + if (coordinatesExtent[1] >= extent[1] && + coordinatesExtent[3] <= extent[3]) { + return true; + } + return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride, + /** + * @param {ol.Coordinate} point1 Start point. + * @param {ol.Coordinate} point2 End point. + * @return {boolean} `true` if the segment and the extent intersect, + * `false` otherwise. + */ + function(point1, point2) { + return ol.extent.intersectsSegment(extent, point1, point2); + }); }; /** - * Returns the type of a value. If a constructor is passed, and a suitable - * string cannot be found, 'unknown type name' will be returned. - * - * <p>Forked rather than moved from {@link goog.asserts.getType_} - * to avoid adding a dependency to goog.asserts. - * @param {*} value A constructor, object, or primitive. - * @return {string} The best display name for the value, or 'unknown type name'. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {ol.Extent} extent Extent. + * @return {boolean} True if the geometry and the extent intersect. */ -goog.debug.runtimeType = function(value) { - if (value instanceof Function) { - return value.displayName || value.name || 'unknown type name'; - } else if (value instanceof Object) { - return value.constructor.displayName || value.constructor.name || - Object.prototype.toString.call(value); - } else { - return value === null ? 'null' : typeof value; +ol.geom.flat.intersectsextent.lineStrings = + function(flatCoordinates, offset, ends, stride, extent) { + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + if (ol.geom.flat.intersectsextent.lineString( + flatCoordinates, offset, ends[i], stride, extent)) { + return true; + } + offset = ends[i]; } + return false; }; /** - * Hash map for storing function names that have already been looked up. - * @type {Object} - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {ol.Extent} extent Extent. + * @return {boolean} True if the geometry and the extent intersect. */ -goog.debug.fnNameCache_ = {}; - - -/** - * Resolves functions to their names. Resolved function names will be cached. - * @type {function(Function):string} - * @private - */ -goog.debug.fnNameResolver_; +ol.geom.flat.intersectsextent.linearRing = + function(flatCoordinates, offset, end, stride, extent) { + if (ol.geom.flat.intersectsextent.lineString( + flatCoordinates, offset, end, stride, extent)) { + return true; + } + if (ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, offset, end, stride, extent[0], extent[1])) { + return true; + } + if (ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, offset, end, stride, extent[0], extent[3])) { + return true; + } + if (ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, offset, end, stride, extent[2], extent[1])) { + return true; + } + if (ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, offset, end, stride, extent[2], extent[3])) { + return true; + } + return false; +}; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Definition of the LogRecord class. Please minimize - * dependencies this file has on other closure classes as any dependency it - * takes won't be able to use the logging infrastructure. - * + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {ol.Extent} extent Extent. + * @return {boolean} True if the geometry and the extent intersect. */ - -goog.provide('goog.debug.LogRecord'); - +ol.geom.flat.intersectsextent.linearRings = + function(flatCoordinates, offset, ends, stride, extent) { + goog.asserts.assert(ends.length > 0, 'ends should not be an empty array'); + if (!ol.geom.flat.intersectsextent.linearRing( + flatCoordinates, offset, ends[0], stride, extent)) { + return false; + } + if (ends.length === 1) { + return true; + } + var i, ii; + for (i = 1, ii = ends.length; i < ii; ++i) { + if (ol.geom.flat.contains.linearRingContainsExtent( + flatCoordinates, ends[i - 1], ends[i], stride, extent)) { + return false; + } + } + return true; +}; /** - * LogRecord objects are used to pass logging requests between - * the logging framework and individual log Handlers. - * @constructor - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {string} loggerName The name of the source logger. - * @param {number=} opt_time Time this log record was created if other than now. - * If 0, we use #goog.now. - * @param {number=} opt_sequenceNumber Sequence number of this log record. This - * should only be passed in when restoring a log record from persistence. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @param {ol.Extent} extent Extent. + * @return {boolean} True if the geometry and the extent intersect. */ -goog.debug.LogRecord = function(level, msg, loggerName, - opt_time, opt_sequenceNumber) { - this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber); +ol.geom.flat.intersectsextent.linearRingss = + function(flatCoordinates, offset, endss, stride, extent) { + goog.asserts.assert(endss.length > 0, 'endss should not be an empty array'); + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + if (ol.geom.flat.intersectsextent.linearRings( + flatCoordinates, offset, ends, stride, extent)) { + return true; + } + offset = ends[ends.length - 1]; + } + return false; }; - -/** - * Time the LogRecord was created. - * @type {number} - * @private - */ -goog.debug.LogRecord.prototype.time_; +goog.provide('ol.geom.flat.reverse'); /** - * Level of the LogRecord - * @type {goog.debug.Logger.Level} - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. */ -goog.debug.LogRecord.prototype.level_; +ol.geom.flat.reverse.coordinates = + function(flatCoordinates, offset, end, stride) { + while (offset < end - stride) { + var i; + for (i = 0; i < stride; ++i) { + var tmp = flatCoordinates[offset + i]; + flatCoordinates[offset + i] = flatCoordinates[end - stride + i]; + flatCoordinates[end - stride + i] = tmp; + } + offset += stride; + end -= stride; + } +}; +goog.provide('ol.geom.flat.orient'); -/** - * Message associated with the record - * @type {string} - * @private - */ -goog.debug.LogRecord.prototype.msg_; +goog.require('ol'); +goog.require('ol.geom.flat.reverse'); /** - * Name of the logger that created the record. - * @type {string} - * @private + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {boolean} Is clockwise. */ -goog.debug.LogRecord.prototype.loggerName_; +ol.geom.flat.orient.linearRingIsClockwise = + function(flatCoordinates, offset, end, stride) { + // http://tinyurl.com/clockwise-method + // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp + var edge = 0; + var x1 = flatCoordinates[end - stride]; + var y1 = flatCoordinates[end - stride + 1]; + for (; offset < end; offset += stride) { + var x2 = flatCoordinates[offset]; + var y2 = flatCoordinates[offset + 1]; + edge += (x2 - x1) * (y2 + y1); + x1 = x2; + y1 = y2; + } + return edge > 0; +}; /** - * Sequence number for the LogRecord. Each record has a unique sequence number - * that is greater than all log records created before it. - * @type {number} - * @private + * Determines if linear rings are oriented. By default, left-hand orientation + * is tested (first ring must be clockwise, remaining rings counter-clockwise). + * To test for right-hand orientation, use the `opt_right` argument. + * + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Array of end indexes. + * @param {number} stride Stride. + * @param {boolean=} opt_right Test for right-hand orientation + * (counter-clockwise exterior ring and clockwise interior rings). + * @return {boolean} Rings are correctly oriented. */ -goog.debug.LogRecord.prototype.sequenceNumber_ = 0; +ol.geom.flat.orient.linearRingsAreOriented = + function(flatCoordinates, offset, ends, stride, opt_right) { + var right = opt_right !== undefined ? opt_right : false; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( + flatCoordinates, offset, end, stride); + if (i === 0) { + if ((right && isClockwise) || (!right && !isClockwise)) { + return false; + } + } else { + if ((right && !isClockwise) || (!right && isClockwise)) { + return false; + } + } + offset = end; + } + return true; +}; /** - * Exception associated with the record - * @type {Object} - * @private + * Determines if linear rings are oriented. By default, left-hand orientation + * is tested (first ring must be clockwise, remaining rings counter-clockwise). + * To test for right-hand orientation, use the `opt_right` argument. + * + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Array of array of end indexes. + * @param {number} stride Stride. + * @param {boolean=} opt_right Test for right-hand orientation + * (counter-clockwise exterior ring and clockwise interior rings). + * @return {boolean} Rings are correctly oriented. */ -goog.debug.LogRecord.prototype.exception_ = null; +ol.geom.flat.orient.linearRingssAreOriented = + function(flatCoordinates, offset, endss, stride, opt_right) { + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + if (!ol.geom.flat.orient.linearRingsAreOriented( + flatCoordinates, offset, endss[i], stride, opt_right)) { + return false; + } + } + return true; +}; /** - * @define {boolean} Whether to enable log sequence numbers. + * Orient coordinates in a flat array of linear rings. By default, rings + * are oriented following the left-hand rule (clockwise for exterior and + * counter-clockwise for interior rings). To orient according to the + * right-hand rule, use the `opt_right` argument. + * + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {boolean=} opt_right Follow the right-hand rule for orientation. + * @return {number} End. */ -goog.define('goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS', true); +ol.geom.flat.orient.orientLinearRings = + function(flatCoordinates, offset, ends, stride, opt_right) { + var right = opt_right !== undefined ? opt_right : false; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + var isClockwise = ol.geom.flat.orient.linearRingIsClockwise( + flatCoordinates, offset, end, stride); + var reverse = i === 0 ? + (right && isClockwise) || (!right && !isClockwise) : + (right && !isClockwise) || (!right && isClockwise); + if (reverse) { + ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride); + } + offset = end; + } + return offset; +}; /** - * A sequence counter for assigning increasing sequence numbers to LogRecord - * objects. - * @type {number} - * @private + * Orient coordinates in a flat array of linear rings. By default, rings + * are oriented following the left-hand rule (clockwise for exterior and + * counter-clockwise for interior rings). To orient according to the + * right-hand rule, use the `opt_right` argument. + * + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Array of array of end indexes. + * @param {number} stride Stride. + * @param {boolean=} opt_right Follow the right-hand rule for orientation. + * @return {number} End. */ -goog.debug.LogRecord.nextSequenceNumber_ = 0; +ol.geom.flat.orient.orientLinearRingss = + function(flatCoordinates, offset, endss, stride, opt_right) { + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + offset = ol.geom.flat.orient.orientLinearRings( + flatCoordinates, offset, endss[i], stride, opt_right); + } + return offset; +}; +goog.provide('ol.geom.Polygon'); -/** - * Sets all fields of the log record. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {string} loggerName The name of the source logger. - * @param {number=} opt_time Time this log record was created if other than now. - * If 0, we use #goog.now. - * @param {number=} opt_sequenceNumber Sequence number of this log record. This - * should only be passed in when restoring a log record from persistence. - */ -goog.debug.LogRecord.prototype.reset = function(level, msg, loggerName, - opt_time, opt_sequenceNumber) { - if (goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) { - this.sequenceNumber_ = typeof opt_sequenceNumber == 'number' ? - opt_sequenceNumber : goog.debug.LogRecord.nextSequenceNumber_++; - } +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.math'); +goog.require('ol'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.area'); +goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.contains'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.geom.flat.interiorpoint'); +goog.require('ol.geom.flat.intersectsextent'); +goog.require('ol.geom.flat.orient'); +goog.require('ol.geom.flat.simplify'); - this.time_ = opt_time || goog.now(); - this.level_ = level; - this.msg_ = msg; - this.loggerName_ = loggerName; - delete this.exception_; -}; /** - * Get the source Logger's name. + * @classdesc + * Polygon geometry. * - * @return {string} source logger name (may be null). + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable */ -goog.debug.LogRecord.prototype.getLoggerName = function() { - return this.loggerName_; -}; +ol.geom.Polygon = function(coordinates, opt_layout) { + goog.base(this); -/** - * Get the exception that is part of the log record. - * - * @return {Object} the exception. - */ -goog.debug.LogRecord.prototype.getException = function() { - return this.exception_; -}; + /** + * @type {Array.<number>} + * @private + */ + this.ends_ = []; + /** + * @private + * @type {number} + */ + this.flatInteriorPointRevision_ = -1; + + /** + * @private + * @type {ol.Coordinate} + */ + this.flatInteriorPoint_ = null; + + /** + * @private + * @type {number} + */ + this.maxDelta_ = -1; + + /** + * @private + * @type {number} + */ + this.maxDeltaRevision_ = -1; + + /** + * @private + * @type {number} + */ + this.orientedRevision_ = -1; + + /** + * @private + * @type {Array.<number>} + */ + this.orientedFlatCoordinates_ = null; + + this.setCoordinates(coordinates, opt_layout); -/** - * Set the exception that is part of the log record. - * - * @param {Object} exception the exception. - */ -goog.debug.LogRecord.prototype.setException = function(exception) { - this.exception_ = exception; }; +goog.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry); /** - * Get the source Logger's name. - * - * @param {string} loggerName source logger name (may be null). + * Append the passed linear ring to this polygon. + * @param {ol.geom.LinearRing} linearRing Linear ring. + * @api stable */ -goog.debug.LogRecord.prototype.setLoggerName = function(loggerName) { - this.loggerName_ = loggerName; +ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) { + goog.asserts.assert(linearRing.getLayout() == this.layout, + 'layout of linearRing should match layout'); + if (!this.flatCoordinates) { + this.flatCoordinates = linearRing.getFlatCoordinates().slice(); + } else { + goog.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates()); + } + this.ends_.push(this.flatCoordinates.length); + this.changed(); }; /** - * Get the logging message level, for example Level.SEVERE. - * @return {goog.debug.Logger.Level} the logging message level. + * Make a complete copy of the geometry. + * @return {!ol.geom.Polygon} Clone. + * @api stable */ -goog.debug.LogRecord.prototype.getLevel = function() { - return this.level_; +ol.geom.Polygon.prototype.clone = function() { + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(), this.ends_.slice()); + return polygon; }; /** - * Set the logging message level, for example Level.SEVERE. - * @param {goog.debug.Logger.Level} level the logging message level. + * @inheritDoc */ -goog.debug.LogRecord.prototype.setLevel = function(level) { - this.level_ = level; +ol.geom.Polygon.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + if (this.maxDeltaRevision_ != this.getRevision()) { + this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta( + this.flatCoordinates, 0, this.ends_, this.stride, 0)); + this.maxDeltaRevision_ = this.getRevision(); + } + return ol.geom.flat.closest.getsClosestPoint( + this.flatCoordinates, 0, this.ends_, this.stride, + this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); }; /** - * Get the "raw" log message, before localization or formatting. - * - * @return {string} the raw message string. + * @inheritDoc */ -goog.debug.LogRecord.prototype.getMessage = function() { - return this.msg_; +ol.geom.Polygon.prototype.containsXY = function(x, y) { + return ol.geom.flat.contains.linearRingsContainsXY( + this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y); }; /** - * Set the "raw" log message, before localization or formatting. - * - * @param {string} msg the raw message string. + * Return the area of the polygon on projected plane. + * @return {number} Area (on projected plane). + * @api stable */ -goog.debug.LogRecord.prototype.setMessage = function(msg) { - this.msg_ = msg; +ol.geom.Polygon.prototype.getArea = function() { + return ol.geom.flat.area.linearRings( + this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride); }; /** - * Get event time in milliseconds since 1970. + * Get the coordinate array for this geometry. This array has the structure + * of a GeoJSON coordinate array for polygons. * - * @return {number} event time in millis since 1970. + * @param {boolean=} opt_right Orient coordinates according to the right-hand + * rule (counter-clockwise for exterior and clockwise for interior rings). + * If `false`, coordinates will be oriented according to the left-hand rule + * (clockwise for exterior and counter-clockwise for interior rings). + * By default, coordinate orientation will depend on how the geometry was + * constructed. + * @return {Array.<Array.<ol.Coordinate>>} Coordinates. + * @api stable */ -goog.debug.LogRecord.prototype.getMillis = function() { - return this.time_; +ol.geom.Polygon.prototype.getCoordinates = function(opt_right) { + var flatCoordinates; + if (opt_right !== undefined) { + flatCoordinates = this.getOrientedFlatCoordinates().slice(); + ol.geom.flat.orient.orientLinearRings( + flatCoordinates, 0, this.ends_, this.stride, opt_right); + } else { + flatCoordinates = this.flatCoordinates; + } + + return ol.geom.flat.inflate.coordinatess( + flatCoordinates, 0, this.ends_, this.stride); }; /** - * Set event time in milliseconds since 1970. - * - * @param {number} time event time in millis since 1970. + * @return {Array.<number>} Ends. */ -goog.debug.LogRecord.prototype.setMillis = function(time) { - this.time_ = time; +ol.geom.Polygon.prototype.getEnds = function() { + return this.ends_; }; /** - * Get the sequence number. - * <p> - * Sequence numbers are normally assigned in the LogRecord - * constructor, which assigns unique sequence numbers to - * each new LogRecord in increasing order. - * @return {number} the sequence number. + * @return {Array.<number>} Interior point. */ -goog.debug.LogRecord.prototype.getSequenceNumber = function() { - return this.sequenceNumber_; +ol.geom.Polygon.prototype.getFlatInteriorPoint = function() { + if (this.flatInteriorPointRevision_ != this.getRevision()) { + var flatCenter = ol.extent.getCenter(this.getExtent()); + this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings( + this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, + flatCenter, 0); + this.flatInteriorPointRevision_ = this.getRevision(); + } + return this.flatInteriorPoint_; }; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/** + * Return an interior point of the polygon. + * @return {ol.geom.Point} Interior point. + * @api stable + */ +ol.geom.Polygon.prototype.getInteriorPoint = function() { + return new ol.geom.Point(this.getFlatInteriorPoint()); +}; + /** - * @fileoverview A buffer for log records. The purpose of this is to improve - * logging performance by re-using old objects when the buffer becomes full and - * to eliminate the need for each app to implement their own log buffer. The - * disadvantage to doing this is that log handlers cannot maintain references to - * log records and expect that they are not overwriten at a later point. + * Return the number of rings of the polygon, this includes the exterior + * ring and any interior rings. * - * @author agrieve@google.com (Andrew Grieve) + * @return {number} Number of rings. + * @api */ +ol.geom.Polygon.prototype.getLinearRingCount = function() { + return this.ends_.length; +}; -goog.provide('goog.debug.LogBuffer'); - -goog.require('goog.asserts'); -goog.require('goog.debug.LogRecord'); +/** + * Return the Nth linear ring of the polygon geometry. Return `null` if the + * given index is out of range. + * The exterior linear ring is available at index `0` and the interior rings + * at index `1` and beyond. + * + * @param {number} index Index. + * @return {ol.geom.LinearRing} Linear ring. + * @api stable + */ +ol.geom.Polygon.prototype.getLinearRing = function(index) { + goog.asserts.assert(0 <= index && index < this.ends_.length, + 'index should be in between 0 and and length of this.ends_'); + if (index < 0 || this.ends_.length <= index) { + return null; + } + var linearRing = new ol.geom.LinearRing(null); + linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice( + index === 0 ? 0 : this.ends_[index - 1], this.ends_[index])); + return linearRing; +}; /** - * Creates the log buffer. - * @constructor - * @final + * Return the linear rings of the polygon. + * @return {Array.<ol.geom.LinearRing>} Linear rings. + * @api stable */ -goog.debug.LogBuffer = function() { - goog.asserts.assert(goog.debug.LogBuffer.isBufferingEnabled(), - 'Cannot use goog.debug.LogBuffer without defining ' + - 'goog.debug.LogBuffer.CAPACITY.'); - this.clear(); +ol.geom.Polygon.prototype.getLinearRings = function() { + var layout = this.layout; + var flatCoordinates = this.flatCoordinates; + var ends = this.ends_; + var linearRings = []; + var offset = 0; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + var linearRing = new ol.geom.LinearRing(null); + linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end)); + linearRings.push(linearRing); + offset = end; + } + return linearRings; }; /** - * A static method that always returns the same instance of LogBuffer. - * @return {!goog.debug.LogBuffer} The LogBuffer singleton instance. + * @return {Array.<number>} Oriented flat coordinates. */ -goog.debug.LogBuffer.getInstance = function() { - if (!goog.debug.LogBuffer.instance_) { - // This function is written with the return statement after the assignment - // to avoid the jscompiler StripCode bug described in http://b/2608064. - // After that bug is fixed this can be refactored. - goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer(); +ol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() { + if (this.orientedRevision_ != this.getRevision()) { + var flatCoordinates = this.flatCoordinates; + if (ol.geom.flat.orient.linearRingsAreOriented( + flatCoordinates, 0, this.ends_, this.stride)) { + this.orientedFlatCoordinates_ = flatCoordinates; + } else { + this.orientedFlatCoordinates_ = flatCoordinates.slice(); + this.orientedFlatCoordinates_.length = + ol.geom.flat.orient.orientLinearRings( + this.orientedFlatCoordinates_, 0, this.ends_, this.stride); + } + this.orientedRevision_ = this.getRevision(); } - return goog.debug.LogBuffer.instance_; + return this.orientedFlatCoordinates_; }; /** - * @define {number} The number of log records to buffer. 0 means disable - * buffering. + * @inheritDoc */ -goog.define('goog.debug.LogBuffer.CAPACITY', 0); +ol.geom.Polygon.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + var simplifiedFlatCoordinates = []; + var simplifiedEnds = []; + simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes( + this.flatCoordinates, 0, this.ends_, this.stride, + Math.sqrt(squaredTolerance), + simplifiedFlatCoordinates, 0, simplifiedEnds); + var simplifiedPolygon = new ol.geom.Polygon(null); + simplifiedPolygon.setFlatCoordinates( + ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds); + return simplifiedPolygon; +}; /** - * The array to store the records. - * @type {!Array<!goog.debug.LogRecord|undefined>} - * @private + * @inheritDoc + * @api stable */ -goog.debug.LogBuffer.prototype.buffer_; +ol.geom.Polygon.prototype.getType = function() { + return ol.geom.GeometryType.POLYGON; +}; /** - * The index of the most recently added record or -1 if there are no records. - * @type {number} - * @private + * @inheritDoc + * @api stable */ -goog.debug.LogBuffer.prototype.curIndex_; +ol.geom.Polygon.prototype.intersectsExtent = function(extent) { + return ol.geom.flat.intersectsextent.linearRings( + this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent); +}; /** - * Whether the buffer is at capacity. - * @type {boolean} - * @private + * Set the coordinates of the polygon. + * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable */ -goog.debug.LogBuffer.prototype.isFull_; +ol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_); + } else { + this.setLayout(opt_layout, coordinates, 2); + if (!this.flatCoordinates) { + this.flatCoordinates = []; + } + var ends = ol.geom.flat.deflate.coordinatess( + this.flatCoordinates, 0, coordinates, this.stride, this.ends_); + this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; + this.changed(); + } +}; /** - * Adds a log record to the buffer, possibly overwriting the oldest record. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {string} loggerName The name of the source logger. - * @return {!goog.debug.LogRecord} The log record. + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {Array.<number>} ends Ends. */ -goog.debug.LogBuffer.prototype.addRecord = function(level, msg, loggerName) { - var curIndex = (this.curIndex_ + 1) % goog.debug.LogBuffer.CAPACITY; - this.curIndex_ = curIndex; - if (this.isFull_) { - var ret = this.buffer_[curIndex]; - ret.reset(level, msg, loggerName); - return ret; +ol.geom.Polygon.prototype.setFlatCoordinates = + function(layout, flatCoordinates, ends) { + if (!flatCoordinates) { + goog.asserts.assert(ends && ends.length === 0, + 'ends must be an empty array'); + } else if (ends.length === 0) { + goog.asserts.assert(flatCoordinates.length === 0, + 'flatCoordinates should be an empty array'); + } else { + goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], + 'the length of flatCoordinates should be the last entry of ends'); } - this.isFull_ = curIndex == goog.debug.LogBuffer.CAPACITY - 1; - return this.buffer_[curIndex] = - new goog.debug.LogRecord(level, msg, loggerName); + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.ends_ = ends; + this.changed(); }; /** - * @return {boolean} Whether the log buffer is enabled. + * Create an approximation of a circle on the surface of a sphere. + * @param {ol.Sphere} sphere The sphere. + * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees). + * @param {number} radius The great-circle distance from the center to + * the polygon vertices. + * @param {number=} opt_n Optional number of vertices for the resulting + * polygon. Default is `32`. + * @return {ol.geom.Polygon} The "circular" polygon. + * @api stable */ -goog.debug.LogBuffer.isBufferingEnabled = function() { - return goog.debug.LogBuffer.CAPACITY > 0; +ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) { + var n = opt_n ? opt_n : 32; + /** @type {Array.<number>} */ + var flatCoordinates = []; + var i; + for (i = 0; i < n; ++i) { + goog.array.extend( + flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n)); + } + flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]); + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates( + ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); + return polygon; }; /** - * Removes all buffered log records. + * Create a polygon from an extent. The layout used is `XY`. + * @param {ol.Extent} extent The extent. + * @return {ol.geom.Polygon} The polygon. + * @api */ -goog.debug.LogBuffer.prototype.clear = function() { - this.buffer_ = new Array(goog.debug.LogBuffer.CAPACITY); - this.curIndex_ = -1; - this.isFull_ = false; +ol.geom.Polygon.fromExtent = function(extent) { + var minX = extent[0]; + var minY = extent[1]; + var maxX = extent[2]; + var maxY = extent[3]; + var flatCoordinates = + [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY]; + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates( + ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); + return polygon; }; /** - * Calls the given function for each buffered log record, starting with the - * oldest one. - * @param {function(!goog.debug.LogRecord)} func The function to call. + * Create a regular polygon from a circle. + * @param {ol.geom.Circle} circle Circle geometry. + * @param {number=} opt_sides Number of sides of the polygon. Default is 32. + * @param {number=} opt_angle Start angle for the first vertex of the polygon in + * radians. Default is 0. + * @return {ol.geom.Polygon} Polygon geometry. + * @api */ -goog.debug.LogBuffer.prototype.forEachRecord = function(func) { - var buffer = this.buffer_; - // Corner case: no records. - if (!buffer[0]) { - return; - } - var curIndex = this.curIndex_; - var i = this.isFull_ ? curIndex : -1; - do { - i = (i + 1) % goog.debug.LogBuffer.CAPACITY; - func(/** @type {!goog.debug.LogRecord} */ (buffer[i])); - } while (i != curIndex); +ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) { + var sides = opt_sides ? opt_sides : 32; + var stride = circle.getStride(); + var layout = circle.getLayout(); + var polygon = new ol.geom.Polygon(null, layout); + var flatCoordinates = goog.array.repeat(0, stride * (sides + 1)); + var ends = [flatCoordinates.length]; + polygon.setFlatCoordinates(layout, flatCoordinates, ends); + ol.geom.Polygon.makeRegular( + polygon, circle.getCenter(), circle.getRadius(), opt_angle); + return polygon; }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - /** - * @fileoverview Definition of the Logger class. Please minimize dependencies - * this file has on other closure classes as any dependency it takes won't be - * able to use the logging infrastructure. - * - * @see ../demos/debug.html + * Modify the coordinates of a polygon to make it a regular polygon. + * @param {ol.geom.Polygon} polygon Polygon geometry. + * @param {ol.Coordinate} center Center of the regular polygon. + * @param {number} radius Radius of the regular polygon. + * @param {number=} opt_angle Start angle for the first vertex of the polygon in + * radians. Default is 0. */ +ol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) { + var flatCoordinates = polygon.getFlatCoordinates(); + var layout = polygon.getLayout(); + var stride = polygon.getStride(); + var ends = polygon.getEnds(); + goog.asserts.assert(ends.length === 1, 'only 1 ring is supported'); + var sides = flatCoordinates.length / stride - 1; + var startAngle = opt_angle ? opt_angle : 0; + var angle, offset; + for (var i = 0; i <= sides; ++i) { + offset = i * stride; + angle = startAngle + (goog.math.modulo(i, sides) * 2 * Math.PI / sides); + flatCoordinates[offset] = center[0] + (radius * Math.cos(angle)); + flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle)); + } + polygon.setFlatCoordinates(layout, flatCoordinates, ends); +}; -goog.provide('goog.debug.LogManager'); -goog.provide('goog.debug.Loggable'); -goog.provide('goog.debug.Logger'); -goog.provide('goog.debug.Logger.Level'); +goog.provide('ol.View'); +goog.provide('ol.ViewHint'); +goog.provide('ol.ViewProperty'); -goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.debug'); -goog.require('goog.debug.LogBuffer'); -goog.require('goog.debug.LogRecord'); +goog.require('ol'); +goog.require('ol.CenterConstraint'); +goog.require('ol.Constraints'); +goog.require('ol.Object'); +goog.require('ol.ResolutionConstraint'); +goog.require('ol.RotationConstraint'); +goog.require('ol.RotationConstraintType'); +goog.require('ol.Size'); +goog.require('ol.coordinate'); +goog.require('ol.extent'); +goog.require('ol.geom.Polygon'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.proj'); +goog.require('ol.proj.METERS_PER_UNIT'); +goog.require('ol.proj.Projection'); +goog.require('ol.proj.Units'); /** - * A message value that can be handled by a Logger. - * - * Functions are treated like callbacks, but are only called when the event's - * log level is enabled. This is useful for logging messages that are expensive - * to construct. - * - * @typedef {string|function(): string} + * @enum {string} */ -goog.debug.Loggable; +ol.ViewProperty = { + CENTER: 'center', + RESOLUTION: 'resolution', + ROTATION: 'rotation' +}; + + +/** + * @enum {number} + */ +ol.ViewHint = { + ANIMATING: 0, + INTERACTING: 1 +}; /** - * The Logger is an object used for logging debug messages. Loggers are - * normally named, using a hierarchical dot-separated namespace. Logger names - * can be arbitrary strings, but they should normally be based on the package - * name or class name of the logged component, such as goog.net.BrowserChannel. + * @classdesc + * An ol.View object represents a simple 2D view of the map. * - * The Logger object is loosely based on the java class - * java.util.logging.Logger. It supports different levels of filtering for - * different loggers. + * This is the object to act upon to change the center, resolution, + * and rotation of the map. * - * The logger object should never be instantiated by application code. It - * should always use the goog.debug.Logger.getLogger function. + * ### The view states + * + * An `ol.View` is determined by three states: `center`, `resolution`, + * and `rotation`. Each state has a corresponding getter and setter, e.g. + * `getCenter` and `setCenter` for the `center` state. + * + * An `ol.View` has a `projection`. The projection determines the + * coordinate system of the center, and its units determine the units of the + * resolution (projection units per pixel). The default projection is + * Spherical Mercator (EPSG:3857). + * + * ### The constraints + * + * `setCenter`, `setResolution` and `setRotation` can be used to change the + * states of the view. Any value can be passed to the setters. And the value + * that is passed to a setter will effectively be the value set in the view, + * and returned by the corresponding getter. + * + * But an `ol.View` object also has a *resolution constraint*, a + * *rotation constraint* and a *center constraint*. + * + * As said above, no constraints are applied when the setters are used to set + * new states for the view. Applying constraints is done explicitly through + * the use of the `constrain*` functions (`constrainResolution` and + * `constrainRotation` and `constrainCenter`). + * + * The main users of the constraints are the interactions and the + * controls. For example, double-clicking on the map changes the view to + * the "next" resolution. And releasing the fingers after pinch-zooming + * snaps to the closest resolution (with an animation). + * + * The *resolution constraint* snaps to specific resolutions. It is + * determined by the following options: `resolutions`, `maxResolution`, + * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three + * options are ignored. See documentation for each option for more + * information. + * + * The *rotation constraint* snaps to specific angles. It is determined + * by the following options: `enableRotation` and `constrainRotation`. + * By default the rotation value is snapped to zero when approaching the + * horizontal. + * + * The *center constraint* is determined by the `extent` option. By + * default the center is not constrained at all. * * @constructor - * @param {string} name The name of the Logger. - * @final + * @extends {ol.Object} + * @param {olx.ViewOptions=} opt_options View options. + * @api stable */ -goog.debug.Logger = function(name) { +ol.View = function(opt_options) { + goog.base(this); + var options = opt_options || {}; + /** - * Name of the Logger. Generally a dot-separated namespace - * @private {string} + * @private + * @type {Array.<number>} */ - this.name_ = name; + this.hints_ = [0, 0]; /** - * Parent Logger. - * @private {goog.debug.Logger} + * @type {Object.<string, *>} */ - this.parent_ = null; + var properties = {}; + properties[ol.ViewProperty.CENTER] = options.center !== undefined ? + options.center : null; /** - * Level that this logger only filters above. Null indicates it should - * inherit from the parent. - * @private {goog.debug.Logger.Level} + * @private + * @const + * @type {ol.proj.Projection} */ - this.level_ = null; + this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857'); + + var resolutionConstraintInfo = ol.View.createResolutionConstraint_( + options); /** - * Map of children loggers. The keys are the leaf names of the children and - * the values are the child loggers. - * @private {Object} + * @private + * @type {number} */ - this.children_ = null; + this.maxResolution_ = resolutionConstraintInfo.maxResolution; /** - * Handlers that are listening to this logger. - * @private {Array<Function>} + * @private + * @type {number} */ - this.handlers_ = null; -}; - - -/** @const */ -goog.debug.Logger.ROOT_LOGGER_NAME = ''; - - -/** - * @define {boolean} Toggles whether loggers other than the root logger can have - * log handlers attached to them and whether they can have their log level - * set. Logging is a bit faster when this is set to false. - */ -goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true); - + this.minResolution_ = resolutionConstraintInfo.minResolution; -if (!goog.debug.Logger.ENABLE_HIERARCHY) { /** - * @type {!Array<Function>} * @private + * @type {number} */ - goog.debug.Logger.rootHandlers_ = []; + this.minZoom_ = resolutionConstraintInfo.minZoom; + var centerConstraint = ol.View.createCenterConstraint_(options); + var resolutionConstraint = resolutionConstraintInfo.constraint; + var rotationConstraint = ol.View.createRotationConstraint_(options); /** - * @type {goog.debug.Logger.Level} * @private + * @type {ol.Constraints} */ - goog.debug.Logger.rootLevel_; -} + this.constraints_ = new ol.Constraints( + centerConstraint, resolutionConstraint, rotationConstraint); + if (options.resolution !== undefined) { + properties[ol.ViewProperty.RESOLUTION] = options.resolution; + } else if (options.zoom !== undefined) { + properties[ol.ViewProperty.RESOLUTION] = this.constrainResolution( + this.maxResolution_, options.zoom - this.minZoom_); + } + properties[ol.ViewProperty.ROTATION] = + options.rotation !== undefined ? options.rotation : 0; + this.setProperties(properties); +}; +goog.inherits(ol.View, ol.Object); /** - * The Level class defines a set of standard logging levels that - * can be used to control logging output. The logging Level objects - * are ordered and are specified by ordered integers. Enabling logging - * at a given level also enables logging at all higher levels. - * <p> - * Clients should normally use the predefined Level constants such - * as Level.SEVERE. - * <p> - * The levels in descending order are: - * <ul> - * <li>SEVERE (highest value) - * <li>WARNING - * <li>INFO - * <li>CONFIG - * <li>FINE - * <li>FINER - * <li>FINEST (lowest value) - * </ul> - * In addition there is a level OFF that can be used to turn - * off logging, and a level ALL that can be used to enable - * logging of all messages. - * - * @param {string} name The name of the level. - * @param {number} value The numeric value of the level. - * @constructor - * @final + * @param {number} rotation Target rotation. + * @param {ol.Coordinate} anchor Rotation anchor. + * @return {ol.Coordinate|undefined} Center for rotation and anchor. */ -goog.debug.Logger.Level = function(name, value) { - /** - * The name of the level - * @type {string} - */ - this.name = name; - - /** - * The numeric value of the level - * @type {number} - */ - this.value = value; +ol.View.prototype.calculateCenterRotate = function(rotation, anchor) { + var center; + var currentCenter = this.getCenter(); + if (currentCenter !== undefined) { + center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]]; + ol.coordinate.rotate(center, rotation - this.getRotation()); + ol.coordinate.add(center, anchor); + } + return center; }; /** - * @return {string} String representation of the logger level. - * @override + * @param {number} resolution Target resolution. + * @param {ol.Coordinate} anchor Zoom anchor. + * @return {ol.Coordinate|undefined} Center for resolution and anchor. */ -goog.debug.Logger.Level.prototype.toString = function() { - return this.name; +ol.View.prototype.calculateCenterZoom = function(resolution, anchor) { + var center; + var currentCenter = this.getCenter(); + var currentResolution = this.getResolution(); + if (currentCenter !== undefined && currentResolution !== undefined) { + var x = anchor[0] - + resolution * (anchor[0] - currentCenter[0]) / currentResolution; + var y = anchor[1] - + resolution * (anchor[1] - currentCenter[1]) / currentResolution; + center = [x, y]; + } + return center; }; /** - * OFF is a special level that can be used to turn off logging. - * This level is initialized to <CODE>Infinity</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the constrained center of this view. + * @param {ol.Coordinate|undefined} center Center. + * @return {ol.Coordinate|undefined} Constrained center. + * @api */ -goog.debug.Logger.Level.OFF = - new goog.debug.Logger.Level('OFF', Infinity); +ol.View.prototype.constrainCenter = function(center) { + return this.constraints_.center(center); +}; /** - * SHOUT is a message level for extra debugging loudness. - * This level is initialized to <CODE>1200</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the constrained resolution of this view. + * @param {number|undefined} resolution Resolution. + * @param {number=} opt_delta Delta. Default is `0`. + * @param {number=} opt_direction Direction. Default is `0`. + * @return {number|undefined} Constrained resolution. + * @api */ -goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200); +ol.View.prototype.constrainResolution = function( + resolution, opt_delta, opt_direction) { + var delta = opt_delta || 0; + var direction = opt_direction || 0; + return this.constraints_.resolution(resolution, delta, direction); +}; /** - * SEVERE is a message level indicating a serious failure. - * This level is initialized to <CODE>1000</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the constrained rotation of this view. + * @param {number|undefined} rotation Rotation. + * @param {number=} opt_delta Delta. Default is `0`. + * @return {number|undefined} Constrained rotation. + * @api */ -goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000); +ol.View.prototype.constrainRotation = function(rotation, opt_delta) { + var delta = opt_delta || 0; + return this.constraints_.rotation(rotation, delta); +}; /** - * WARNING is a message level indicating a potential problem. - * This level is initialized to <CODE>900</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the view center. + * @return {ol.Coordinate|undefined} The center of the view. + * @observable + * @api stable */ -goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900); +ol.View.prototype.getCenter = function() { + return /** @type {ol.Coordinate|undefined} */ ( + this.get(ol.ViewProperty.CENTER)); +}; /** - * INFO is a message level for informational messages. - * This level is initialized to <CODE>800</CODE>. - * @type {!goog.debug.Logger.Level} + * @return {Array.<number>} Hint. */ -goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800); +ol.View.prototype.getHints = function() { + return this.hints_.slice(); +}; /** - * CONFIG is a message level for static configuration messages. - * This level is initialized to <CODE>700</CODE>. - * @type {!goog.debug.Logger.Level} + * Calculate the extent for the current view state and the passed size. + * The size is the pixel dimensions of the box into which the calculated extent + * should fit. In most cases you want to get the extent of the entire map, + * that is `map.getSize()`. + * @param {ol.Size} size Box pixel size. + * @return {ol.Extent} Extent. + * @api stable */ -goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700); +ol.View.prototype.calculateExtent = function(size) { + var center = this.getCenter(); + goog.asserts.assert(center, 'The view center is not defined'); + var resolution = this.getResolution(); + goog.asserts.assert(resolution !== undefined, + 'The view resolution is not defined'); + var rotation = this.getRotation(); + goog.asserts.assert(rotation !== undefined, + 'The view rotation is not defined'); + + return ol.extent.getForViewAndSize(center, resolution, rotation, size); +}; /** - * FINE is a message level providing tracing information. - * This level is initialized to <CODE>500</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the view projection. + * @return {ol.proj.Projection} The projection of the view. + * @api stable */ -goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500); +ol.View.prototype.getProjection = function() { + return this.projection_; +}; /** - * FINER indicates a fairly detailed tracing message. - * This level is initialized to <CODE>400</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the view resolution. + * @return {number|undefined} The resolution of the view. + * @observable + * @api stable */ -goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400); +ol.View.prototype.getResolution = function() { + return /** @type {number|undefined} */ ( + this.get(ol.ViewProperty.RESOLUTION)); +}; + /** - * FINEST indicates a highly detailed tracing message. - * This level is initialized to <CODE>300</CODE>. - * @type {!goog.debug.Logger.Level} + * Get the resolution for a provided extent (in map units) and size (in pixels). + * @param {ol.Extent} extent Extent. + * @param {ol.Size} size Box pixel size. + * @return {number} The resolution at which the provided extent will render at + * the given size. */ - -goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300); +ol.View.prototype.getResolutionForExtent = function(extent, size) { + var xResolution = ol.extent.getWidth(extent) / size[0]; + var yResolution = ol.extent.getHeight(extent) / size[1]; + return Math.max(xResolution, yResolution); +}; /** - * ALL indicates that all messages should be logged. - * This level is initialized to <CODE>0</CODE>. - * @type {!goog.debug.Logger.Level} + * Return a function that returns a value between 0 and 1 for a + * resolution. Exponential scaling is assumed. + * @param {number=} opt_power Power. + * @return {function(number): number} Resolution for value function. */ -goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0); +ol.View.prototype.getResolutionForValueFunction = function(opt_power) { + var power = opt_power || 2; + var maxResolution = this.maxResolution_; + var minResolution = this.minResolution_; + var max = Math.log(maxResolution / minResolution) / Math.log(power); + return ( + /** + * @param {number} value Value. + * @return {number} Resolution. + */ + function(value) { + var resolution = maxResolution / Math.pow(power, value * max); + goog.asserts.assert(resolution >= minResolution && + resolution <= maxResolution, + 'calculated resolution outside allowed bounds (%s <= %s <= %s)', + minResolution, resolution, maxResolution); + return resolution; + }); +}; /** - * The predefined levels. - * @type {!Array<!goog.debug.Logger.Level>} - * @final + * Get the view rotation. + * @return {number} The rotation of the view in radians. + * @observable + * @api stable */ -goog.debug.Logger.Level.PREDEFINED_LEVELS = [ - goog.debug.Logger.Level.OFF, - goog.debug.Logger.Level.SHOUT, - goog.debug.Logger.Level.SEVERE, - goog.debug.Logger.Level.WARNING, - goog.debug.Logger.Level.INFO, - goog.debug.Logger.Level.CONFIG, - goog.debug.Logger.Level.FINE, - goog.debug.Logger.Level.FINER, - goog.debug.Logger.Level.FINEST, - goog.debug.Logger.Level.ALL]; +ol.View.prototype.getRotation = function() { + return /** @type {number} */ (this.get(ol.ViewProperty.ROTATION)); +}; /** - * A lookup map used to find the level object based on the name or value of - * the level object. - * @type {Object} - * @private + * Return a function that returns a resolution for a value between + * 0 and 1. Exponential scaling is assumed. + * @param {number=} opt_power Power. + * @return {function(number): number} Value for resolution function. */ -goog.debug.Logger.Level.predefinedLevelsCache_ = null; +ol.View.prototype.getValueForResolutionFunction = function(opt_power) { + var power = opt_power || 2; + var maxResolution = this.maxResolution_; + var minResolution = this.minResolution_; + var max = Math.log(maxResolution / minResolution) / Math.log(power); + return ( + /** + * @param {number} resolution Resolution. + * @return {number} Value. + */ + function(resolution) { + var value = + (Math.log(maxResolution / resolution) / Math.log(power)) / max; + goog.asserts.assert(value >= 0 && value <= 1, + 'calculated value (%s) ouside allowed range (0-1)', value); + return value; + }); +}; /** - * Creates the predefined levels cache and populates it. - * @private + * @return {olx.ViewState} View state. */ -goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() { - goog.debug.Logger.Level.predefinedLevelsCache_ = {}; - for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i]; - i++) { - goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level; - goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level; - } +ol.View.prototype.getState = function() { + goog.asserts.assert(this.isDef(), + 'the view was not defined (had no center and/or resolution)'); + var center = /** @type {ol.Coordinate} */ (this.getCenter()); + var projection = this.getProjection(); + var resolution = /** @type {number} */ (this.getResolution()); + var rotation = this.getRotation(); + return /** @type {olx.ViewState} */ ({ + // Snap center to closest pixel + center: [ + Math.round(center[0] / resolution) * resolution, + Math.round(center[1] / resolution) * resolution + ], + projection: projection !== undefined ? projection : null, + resolution: resolution, + rotation: rotation + }); }; /** - * Gets the predefined level with the given name. - * @param {string} name The name of the level. - * @return {goog.debug.Logger.Level} The level, or null if none found. + * Get the current zoom level. Return undefined if the current + * resolution is undefined or not a "constrained resolution". + * @return {number|undefined} Zoom. + * @api stable */ -goog.debug.Logger.Level.getPredefinedLevel = function(name) { - if (!goog.debug.Logger.Level.predefinedLevelsCache_) { - goog.debug.Logger.Level.createPredefinedLevelsCache_(); +ol.View.prototype.getZoom = function() { + var offset; + var resolution = this.getResolution(); + + if (resolution !== undefined) { + var res, z = 0; + do { + res = this.constrainResolution(this.maxResolution_, z); + if (res == resolution) { + offset = z; + break; + } + ++z; + } while (res > this.minResolution_); } - return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null; + return offset !== undefined ? this.minZoom_ + offset : offset; }; /** - * Gets the highest predefined level <= #value. - * @param {number} value Level value. - * @return {goog.debug.Logger.Level} The level, or null if none found. + * Fit the given geometry or extent based on the given map size and border. + * The size is pixel dimensions of the box to fit the extent into. + * In most cases you will want to use the map size, that is `map.getSize()`. + * Takes care of the map angle. + * @param {ol.geom.SimpleGeometry|ol.Extent} geometry Geometry. + * @param {ol.Size} size Box pixel size. + * @param {olx.view.FitOptions=} opt_options Options. + * @api */ -goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) { - if (!goog.debug.Logger.Level.predefinedLevelsCache_) { - goog.debug.Logger.Level.createPredefinedLevelsCache_(); +ol.View.prototype.fit = function(geometry, size, opt_options) { + if (!(geometry instanceof ol.geom.SimpleGeometry)) { + goog.asserts.assert(goog.isArray(geometry), + 'invalid extent or geometry'); + goog.asserts.assert(!ol.extent.isEmpty(geometry), + 'cannot fit empty extent'); + geometry = ol.geom.Polygon.fromExtent(geometry); } - if (value in goog.debug.Logger.Level.predefinedLevelsCache_) { - return goog.debug.Logger.Level.predefinedLevelsCache_[value]; + var options = opt_options || {}; + + var padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0]; + var constrainResolution = options.constrainResolution !== undefined ? + options.constrainResolution : true; + var nearest = options.nearest !== undefined ? options.nearest : false; + var minResolution; + if (options.minResolution !== undefined) { + minResolution = options.minResolution; + } else if (options.maxZoom !== undefined) { + minResolution = this.constrainResolution( + this.maxResolution_, options.maxZoom - this.minZoom_, 0); + } else { + minResolution = 0; } + var coords = geometry.getFlatCoordinates(); - for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) { - var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i]; - if (level.value <= value) { - return level; + // calculate rotated extent + var rotation = this.getRotation(); + goog.asserts.assert(rotation !== undefined, 'rotation was not defined'); + var cosAngle = Math.cos(-rotation); + var sinAngle = Math.sin(-rotation); + var minRotX = +Infinity; + var minRotY = +Infinity; + var maxRotX = -Infinity; + var maxRotY = -Infinity; + var stride = geometry.getStride(); + for (var i = 0, ii = coords.length; i < ii; i += stride) { + var rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle; + var rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle; + minRotX = Math.min(minRotX, rotX); + minRotY = Math.min(minRotY, rotY); + maxRotX = Math.max(maxRotX, rotX); + maxRotY = Math.max(maxRotY, rotY); + } + + // calculate resolution + var resolution = this.getResolutionForExtent( + [minRotX, minRotY, maxRotX, maxRotY], + [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]); + resolution = isNaN(resolution) ? minResolution : + Math.max(resolution, minResolution); + if (constrainResolution) { + var constrainedResolution = this.constrainResolution(resolution, 0, 0); + if (!nearest && constrainedResolution < resolution) { + constrainedResolution = this.constrainResolution( + constrainedResolution, -1, 0); } + resolution = constrainedResolution; } - return null; -}; + this.setResolution(resolution); + // calculate center + sinAngle = -sinAngle; // go back to original rotation + var centerRotX = (minRotX + maxRotX) / 2; + var centerRotY = (minRotY + maxRotY) / 2; + centerRotX += (padding[1] - padding[3]) / 2 * resolution; + centerRotY += (padding[0] - padding[2]) / 2 * resolution; + var centerX = centerRotX * cosAngle - centerRotY * sinAngle; + var centerY = centerRotY * cosAngle + centerRotX * sinAngle; -/** - * Finds or creates a logger for a named subsystem. If a logger has already been - * created with the given name it is returned. Otherwise a new logger is - * created. If a new logger is created its log level will be configured based - * on the LogManager configuration and it will configured to also send logging - * output to its parent's handlers. It will be registered in the LogManager - * global namespace. - * - * @param {string} name A name for the logger. This should be a dot-separated - * name and should normally be based on the package name or class name of the - * subsystem, such as goog.net.BrowserChannel. - * @return {!goog.debug.Logger} The named logger. - * @deprecated use goog.log instead. http://go/goog-debug-logger-deprecated - */ -goog.debug.Logger.getLogger = function(name) { - return goog.debug.LogManager.getLogger(name); + this.setCenter([centerX, centerY]); }; /** - * Logs a message to profiling tools, if available. - * {@see https://developers.google.com/web-toolkit/speedtracer/logging-api} - * {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx} - * @param {string} msg The message to log. + * Center on coordinate and view position. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {ol.Size} size Box pixel size. + * @param {ol.Pixel} position Position on the view to center on. + * @api */ -goog.debug.Logger.logToProfilers = function(msg) { - // Using goog.global, as loggers might be used in window-less contexts. - if (goog.global['console']) { - if (goog.global['console']['timeStamp']) { - // Logs a message to Firebug, Web Inspector, SpeedTracer, etc. - goog.global['console']['timeStamp'](msg); - } else if (goog.global['console']['markTimeline']) { - // TODO(user): markTimeline is deprecated. Drop this else clause entirely - // after Chrome M14 hits stable. - goog.global['console']['markTimeline'](msg); - } - } +ol.View.prototype.centerOn = function(coordinate, size, position) { + // calculate rotated position + var rotation = this.getRotation(); + var cosAngle = Math.cos(-rotation); + var sinAngle = Math.sin(-rotation); + var rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle; + var rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle; + var resolution = this.getResolution(); + rotX += (size[0] / 2 - position[0]) * resolution; + rotY += (position[1] - size[1] / 2) * resolution; - if (goog.global['msWriteProfilerMark']) { - // Logs a message to the Microsoft profiler - goog.global['msWriteProfilerMark'](msg); - } + // go back to original angle + sinAngle = -sinAngle; // go back to original rotation + var centerX = rotX * cosAngle - rotY * sinAngle; + var centerY = rotY * cosAngle + rotX * sinAngle; + + this.setCenter([centerX, centerY]); }; /** - * Gets the name of this logger. - * @return {string} The name of this logger. + * @return {boolean} Is defined. */ -goog.debug.Logger.prototype.getName = function() { - return this.name_; +ol.View.prototype.isDef = function() { + return !!this.getCenter() && this.getResolution() !== undefined; }; /** - * Adds a handler to the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {Function} handler Handler function to add. + * Rotate the view around a given coordinate. + * @param {number} rotation New rotation value for the view. + * @param {ol.Coordinate=} opt_anchor The rotation center. + * @api stable */ -goog.debug.Logger.prototype.addHandler = function(handler) { - if (goog.debug.LOGGING_ENABLED) { - if (goog.debug.Logger.ENABLE_HIERARCHY) { - if (!this.handlers_) { - this.handlers_ = []; - } - this.handlers_.push(handler); - } else { - goog.asserts.assert(!this.name_, - 'Cannot call addHandler on a non-root logger when ' + - 'goog.debug.Logger.ENABLE_HIERARCHY is false.'); - goog.debug.Logger.rootHandlers_.push(handler); - } +ol.View.prototype.rotate = function(rotation, opt_anchor) { + if (opt_anchor !== undefined) { + var center = this.calculateCenterRotate(rotation, opt_anchor); + this.setCenter(center); } + this.setRotation(rotation); }; /** - * Removes a handler from the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {Function} handler Handler function to remove. - * @return {boolean} Whether the handler was removed. - */ -goog.debug.Logger.prototype.removeHandler = function(handler) { - if (goog.debug.LOGGING_ENABLED) { - var handlers = goog.debug.Logger.ENABLE_HIERARCHY ? this.handlers_ : - goog.debug.Logger.rootHandlers_; - return !!handlers && goog.array.remove(handlers, handler); - } else { - return false; - } + * Set the center of the current view. + * @param {ol.Coordinate|undefined} center The center of the view. + * @observable + * @api stable + */ +ol.View.prototype.setCenter = function(center) { + this.set(ol.ViewProperty.CENTER, center); }; /** - * Returns the parent of this logger. - * @return {goog.debug.Logger} The parent logger or null if this is the root. + * @param {ol.ViewHint} hint Hint. + * @param {number} delta Delta. + * @return {number} New value. */ -goog.debug.Logger.prototype.getParent = function() { - return this.parent_; +ol.View.prototype.setHint = function(hint, delta) { + goog.asserts.assert(0 <= hint && hint < this.hints_.length, + 'illegal hint (%s), must be between 0 and %s', hint, this.hints_.length); + this.hints_[hint] += delta; + goog.asserts.assert(this.hints_[hint] >= 0, + 'Hint at %s must be positive, was %s', hint, this.hints_[hint]); + return this.hints_[hint]; }; /** - * Returns the children of this logger as a map of the child name to the logger. - * @return {!Object} The map where the keys are the child leaf names and the - * values are the Logger objects. + * Set the resolution for this view. + * @param {number|undefined} resolution The resolution of the view. + * @observable + * @api stable */ -goog.debug.Logger.prototype.getChildren = function() { - if (!this.children_) { - this.children_ = {}; - } - return this.children_; +ol.View.prototype.setResolution = function(resolution) { + this.set(ol.ViewProperty.RESOLUTION, resolution); }; /** - * Set the log level specifying which message levels will be logged by this - * logger. Message levels lower than this value will be discarded. - * The level value Level.OFF can be used to turn off logging. If the new level - * is null, it means that this node should inherit its level from its nearest - * ancestor with a specific (non-null) level value. - * - * @param {goog.debug.Logger.Level} level The new level. + * Set the rotation for this view. + * @param {number} rotation The rotation of the view in radians. + * @observable + * @api stable */ -goog.debug.Logger.prototype.setLevel = function(level) { - if (goog.debug.LOGGING_ENABLED) { - if (goog.debug.Logger.ENABLE_HIERARCHY) { - this.level_ = level; - } else { - goog.asserts.assert(!this.name_, - 'Cannot call setLevel() on a non-root logger when ' + - 'goog.debug.Logger.ENABLE_HIERARCHY is false.'); - goog.debug.Logger.rootLevel_ = level; - } - } +ol.View.prototype.setRotation = function(rotation) { + this.set(ol.ViewProperty.ROTATION, rotation); }; /** - * Gets the log level specifying which message levels will be logged by this - * logger. Message levels lower than this value will be discarded. - * The level value Level.OFF can be used to turn off logging. If the level - * is null, it means that this node should inherit its level from its nearest - * ancestor with a specific (non-null) level value. - * - * @return {goog.debug.Logger.Level} The level. + * Zoom to a specific zoom level. + * @param {number} zoom Zoom level. + * @api stable */ -goog.debug.Logger.prototype.getLevel = function() { - return goog.debug.LOGGING_ENABLED ? - this.level_ : goog.debug.Logger.Level.OFF; +ol.View.prototype.setZoom = function(zoom) { + var resolution = this.constrainResolution( + this.maxResolution_, zoom - this.minZoom_, 0); + this.setResolution(resolution); }; /** - * Returns the effective level of the logger based on its ancestors' levels. - * @return {goog.debug.Logger.Level} The level. + * @param {olx.ViewOptions} options View options. + * @private + * @return {ol.CenterConstraintType} */ -goog.debug.Logger.prototype.getEffectiveLevel = function() { - if (!goog.debug.LOGGING_ENABLED) { - return goog.debug.Logger.Level.OFF; - } - - if (!goog.debug.Logger.ENABLE_HIERARCHY) { - return goog.debug.Logger.rootLevel_; - } - if (this.level_) { - return this.level_; - } - if (this.parent_) { - return this.parent_.getEffectiveLevel(); +ol.View.createCenterConstraint_ = function(options) { + if (options.extent !== undefined) { + return ol.CenterConstraint.createExtent(options.extent); + } else { + return ol.CenterConstraint.none; } - goog.asserts.fail('Root logger has no level set.'); - return null; }; /** - * Checks if a message of the given level would actually be logged by this - * logger. This check is based on the Loggers effective level, which may be - * inherited from its parent. - * @param {goog.debug.Logger.Level} level The level to check. - * @return {boolean} Whether the message would be logged. + * @private + * @param {olx.ViewOptions} options View options. + * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number, + * minResolution: number}} */ -goog.debug.Logger.prototype.isLoggable = function(level) { - return goog.debug.LOGGING_ENABLED && - level.value >= this.getEffectiveLevel().value; -}; +ol.View.createResolutionConstraint_ = function(options) { + var resolutionConstraint; + var maxResolution; + var minResolution; + // TODO: move these to be ol constants + // see https://github.com/openlayers/ol3/issues/2076 + var defaultMaxZoom = 28; + var defaultZoomFactor = 2; -/** - * Logs a message. If the logger is currently enabled for the - * given message level then the given message is forwarded to all the - * registered output Handler objects. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error|Object=} opt_exception An exception associated with the - * message. - */ -goog.debug.Logger.prototype.log = function(level, msg, opt_exception) { - // java caches the effective level, not sure it's necessary here - if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) { - // Message callbacks can be useful when a log message is expensive to build. - if (goog.isFunction(msg)) { - msg = msg(); - } + var minZoom = options.minZoom !== undefined ? + options.minZoom : ol.DEFAULT_MIN_ZOOM; - this.doLogRecord_(this.getLogRecord(level, msg, opt_exception)); - } -}; + var maxZoom = options.maxZoom !== undefined ? + options.maxZoom : defaultMaxZoom; + var zoomFactor = options.zoomFactor !== undefined ? + options.zoomFactor : defaultZoomFactor; -/** - * Creates a new log record and adds the exception (if present) to it. - * @param {goog.debug.Logger.Level} level One of the level identifiers. - * @param {string} msg The string message. - * @param {Error|Object=} opt_exception An exception associated with the - * message. - * @return {!goog.debug.LogRecord} A log record. - * @suppress {es5Strict} - */ -goog.debug.Logger.prototype.getLogRecord = function( - level, msg, opt_exception) { - if (goog.debug.LogBuffer.isBufferingEnabled()) { - var logRecord = - goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_); + if (options.resolutions !== undefined) { + var resolutions = options.resolutions; + maxResolution = resolutions[0]; + minResolution = resolutions[resolutions.length - 1]; + resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions( + resolutions); } else { - logRecord = new goog.debug.LogRecord(level, String(msg), this.name_); - } - if (opt_exception) { - logRecord.setException(opt_exception); - } - return logRecord; -}; + // calculate the default min and max resolution + var projection = ol.proj.createProjection(options.projection, 'EPSG:3857'); + var extent = projection.getExtent(); + var size = !extent ? + // use an extent that can fit the whole world if need be + 360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] / + ol.proj.METERS_PER_UNIT[projection.getUnits()] : + Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent)); + var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow( + defaultZoomFactor, ol.DEFAULT_MIN_ZOOM); -/** - * Logs a message at the Logger.Level.SHOUT level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.shout = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception); - } -}; + var defaultMinResolution = defaultMaxResolution / Math.pow( + defaultZoomFactor, defaultMaxZoom - ol.DEFAULT_MIN_ZOOM); + // user provided maxResolution takes precedence + maxResolution = options.maxResolution; + if (maxResolution !== undefined) { + minZoom = 0; + } else { + maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom); + } -/** - * Logs a message at the Logger.Level.SEVERE level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.severe = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception); - } -}; + // user provided minResolution takes precedence + minResolution = options.minResolution; + if (minResolution === undefined) { + if (options.maxZoom !== undefined) { + if (options.maxResolution !== undefined) { + minResolution = maxResolution / Math.pow(zoomFactor, maxZoom); + } else { + minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom); + } + } else { + minResolution = defaultMinResolution; + } + } + // given discrete zoom levels, minResolution may be different than provided + maxZoom = minZoom + Math.floor( + Math.log(maxResolution / minResolution) / Math.log(zoomFactor)); + minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom); -/** - * Logs a message at the Logger.Level.WARNING level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.warning = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception); + resolutionConstraint = ol.ResolutionConstraint.createSnapToPower( + zoomFactor, maxResolution, maxZoom - minZoom); } + return {constraint: resolutionConstraint, maxResolution: maxResolution, + minResolution: minResolution, minZoom: minZoom}; }; /** - * Logs a message at the Logger.Level.INFO level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * @private + * @param {olx.ViewOptions} options View options. + * @return {ol.RotationConstraintType} Rotation constraint. */ -goog.debug.Logger.prototype.info = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.INFO, msg, opt_exception); +ol.View.createRotationConstraint_ = function(options) { + var enableRotation = options.enableRotation !== undefined ? + options.enableRotation : true; + if (enableRotation) { + var constrainRotation = options.constrainRotation; + if (constrainRotation === undefined || constrainRotation === true) { + return ol.RotationConstraint.createSnapToZero(); + } else if (constrainRotation === false) { + return ol.RotationConstraint.none; + } else if (goog.isNumber(constrainRotation)) { + return ol.RotationConstraint.createSnapToN(constrainRotation); + } else { + goog.asserts.fail( + 'illegal option for constrainRotation (%s)', constrainRotation); + return ol.RotationConstraint.none; + } + } else { + return ol.RotationConstraint.disable; } }; +goog.exportProperty(ol.View.prototype, 'getResolutionForExtent', + ol.View.prototype.getResolutionForExtent); -/** - * Logs a message at the Logger.Level.CONFIG level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. - */ -goog.debug.Logger.prototype.config = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception); - } -}; +goog.provide('ol.easing'); /** - * Logs a message at the Logger.Level.FINE level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Start slow and speed up. + * @param {number} t Input between 0 and 1. + * @return {number} Output between 0 and 1. + * @api */ -goog.debug.Logger.prototype.fine = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.FINE, msg, opt_exception); - } +ol.easing.easeIn = function(t) { + return Math.pow(t, 3); }; /** - * Logs a message at the Logger.Level.FINER level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Start fast and slow down. + * @param {number} t Input between 0 and 1. + * @return {number} Output between 0 and 1. + * @api */ -goog.debug.Logger.prototype.finer = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.FINER, msg, opt_exception); - } +ol.easing.easeOut = function(t) { + return 1 - ol.easing.easeIn(1 - t); }; /** - * Logs a message at the Logger.Level.FINEST level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Start slow, speed up, and then slow down again. + * @param {number} t Input between 0 and 1. + * @return {number} Output between 0 and 1. + * @api */ -goog.debug.Logger.prototype.finest = function(msg, opt_exception) { - if (goog.debug.LOGGING_ENABLED) { - this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception); - } +ol.easing.inAndOut = function(t) { + return 3 * t * t - 2 * t * t * t; }; /** - * Logs a LogRecord. If the logger is currently enabled for the - * given message level then the given message is forwarded to all the - * registered output Handler objects. - * @param {goog.debug.LogRecord} logRecord A log record to log. + * Maintain a constant speed over time. + * @param {number} t Input between 0 and 1. + * @return {number} Output between 0 and 1. + * @api */ -goog.debug.Logger.prototype.logRecord = function(logRecord) { - if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) { - this.doLogRecord_(logRecord); - } +ol.easing.linear = function(t) { + return t; }; /** - * Logs a LogRecord. - * @param {goog.debug.LogRecord} logRecord A log record to log. - * @private + * Start slow, speed up, and at the very end slow down again. This has the + * same general behavior as {@link ol.easing.inAndOut}, but the final slowdown + * is delayed. + * @param {number} t Input between 0 and 1. + * @return {number} Output between 0 and 1. + * @api */ -goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) { - goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage()); - if (goog.debug.Logger.ENABLE_HIERARCHY) { - var target = this; - while (target) { - target.callPublish_(logRecord); - target = target.getParent(); - } +ol.easing.upAndDown = function(t) { + if (t < 0.5) { + return ol.easing.inAndOut(2 * t); } else { - for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++]; ) { - handler(logRecord); - } + return 1 - ol.easing.inAndOut(2 * (t - 0.5)); } }; +goog.provide('ol.animation'); -/** - * Calls the handlers for publish. - * @param {goog.debug.LogRecord} logRecord The log record to publish. - * @private - */ -goog.debug.Logger.prototype.callPublish_ = function(logRecord) { - if (this.handlers_) { - for (var i = 0, handler; handler = this.handlers_[i]; i++) { - handler(logRecord); - } - } -}; +goog.require('ol'); +goog.require('ol.PreRenderFunction'); +goog.require('ol.ViewHint'); +goog.require('ol.coordinate'); +goog.require('ol.easing'); /** - * Sets the parent of this logger. This is used for setting up the logger tree. - * @param {goog.debug.Logger} parent The parent logger. - * @private + * Generate an animated transition that will "bounce" the resolution as it + * approaches the final value. + * @param {olx.animation.BounceOptions} options Bounce options. + * @return {ol.PreRenderFunction} Pre-render function. + * @api */ -goog.debug.Logger.prototype.setParent_ = function(parent) { - this.parent_ = parent; +ol.animation.bounce = function(options) { + var resolution = options.resolution; + var start = options.start ? options.start : Date.now(); + var duration = options.duration !== undefined ? options.duration : 1000; + var easing = options.easing ? + options.easing : ol.easing.upAndDown; + return ( + /** + * @param {ol.Map} map Map. + * @param {?olx.FrameState} frameState Frame state. + */ + function(map, frameState) { + if (frameState.time < start) { + frameState.animate = true; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else if (frameState.time < start + duration) { + var delta = easing((frameState.time - start) / duration); + var deltaResolution = resolution - frameState.viewState.resolution; + frameState.animate = true; + frameState.viewState.resolution += delta * deltaResolution; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else { + return false; + } + }); }; /** - * Adds a child to this logger. This is used for setting up the logger tree. - * @param {string} name The leaf name of the child. - * @param {goog.debug.Logger} logger The child logger. - * @private + * Generate an animated transition while updating the view center. + * @param {olx.animation.PanOptions} options Pan options. + * @return {ol.PreRenderFunction} Pre-render function. + * @api */ -goog.debug.Logger.prototype.addChild_ = function(name, logger) { - this.getChildren()[name] = logger; +ol.animation.pan = function(options) { + var source = options.source; + var start = options.start ? options.start : Date.now(); + var sourceX = source[0]; + var sourceY = source[1]; + var duration = options.duration !== undefined ? options.duration : 1000; + var easing = options.easing ? + options.easing : ol.easing.inAndOut; + return ( + /** + * @param {ol.Map} map Map. + * @param {?olx.FrameState} frameState Frame state. + */ + function(map, frameState) { + if (frameState.time < start) { + frameState.animate = true; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else if (frameState.time < start + duration) { + var delta = 1 - easing((frameState.time - start) / duration); + var deltaX = sourceX - frameState.viewState.center[0]; + var deltaY = sourceY - frameState.viewState.center[1]; + frameState.animate = true; + frameState.viewState.center[0] += delta * deltaX; + frameState.viewState.center[1] += delta * deltaY; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else { + return false; + } + }); }; /** - * There is a single global LogManager object that is used to maintain a set of - * shared state about Loggers and log services. This is loosely based on the - * java class java.util.logging.LogManager. - * @const - */ -goog.debug.LogManager = {}; - - -/** - * Map of logger names to logger objects. - * - * @type {!Object<string, !goog.debug.Logger>} - * @private - */ -goog.debug.LogManager.loggers_ = {}; - - -/** - * The root logger which is the root of the logger tree. - * @type {goog.debug.Logger} - * @private + * Generate an animated transition while updating the view rotation. + * @param {olx.animation.RotateOptions} options Rotate options. + * @return {ol.PreRenderFunction} Pre-render function. + * @api */ -goog.debug.LogManager.rootLogger_ = null; +ol.animation.rotate = function(options) { + var sourceRotation = options.rotation ? options.rotation : 0; + var start = options.start ? options.start : Date.now(); + var duration = options.duration !== undefined ? options.duration : 1000; + var easing = options.easing ? + options.easing : ol.easing.inAndOut; + var anchor = options.anchor ? + options.anchor : null; - -/** - * Initializes the LogManager if not already initialized. - */ -goog.debug.LogManager.initialize = function() { - if (!goog.debug.LogManager.rootLogger_) { - goog.debug.LogManager.rootLogger_ = new goog.debug.Logger( - goog.debug.Logger.ROOT_LOGGER_NAME); - goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] = - goog.debug.LogManager.rootLogger_; - goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG); - } + return ( + /** + * @param {ol.Map} map Map. + * @param {?olx.FrameState} frameState Frame state. + */ + function(map, frameState) { + if (frameState.time < start) { + frameState.animate = true; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else if (frameState.time < start + duration) { + var delta = 1 - easing((frameState.time - start) / duration); + var deltaRotation = + (sourceRotation - frameState.viewState.rotation) * delta; + frameState.animate = true; + frameState.viewState.rotation += deltaRotation; + if (anchor) { + var center = frameState.viewState.center; + ol.coordinate.sub(center, anchor); + ol.coordinate.rotate(center, deltaRotation); + ol.coordinate.add(center, anchor); + } + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else { + return false; + } + }); }; /** - * Returns all the loggers. - * @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger - * objects. + * Generate an animated transition while updating the view resolution. + * @param {olx.animation.ZoomOptions} options Zoom options. + * @return {ol.PreRenderFunction} Pre-render function. + * @api */ -goog.debug.LogManager.getLoggers = function() { - return goog.debug.LogManager.loggers_; +ol.animation.zoom = function(options) { + var sourceResolution = options.resolution; + var start = options.start ? options.start : Date.now(); + var duration = options.duration !== undefined ? options.duration : 1000; + var easing = options.easing ? + options.easing : ol.easing.inAndOut; + return ( + /** + * @param {ol.Map} map Map. + * @param {?olx.FrameState} frameState Frame state. + */ + function(map, frameState) { + if (frameState.time < start) { + frameState.animate = true; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else if (frameState.time < start + duration) { + var delta = 1 - easing((frameState.time - start) / duration); + var deltaResolution = + sourceResolution - frameState.viewState.resolution; + frameState.animate = true; + frameState.viewState.resolution += delta * deltaResolution; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else { + return false; + } + }); }; - -/** - * Returns the root of the logger tree namespace, the logger with the empty - * string as its name. - * - * @return {!goog.debug.Logger} The root logger. - */ -goog.debug.LogManager.getRoot = function() { - goog.debug.LogManager.initialize(); - return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_); -}; +goog.provide('ol.CanvasFunctionType'); /** - * Finds a named logger. + * A function returning the canvas element (`{HTMLCanvasElement}`) + * used by the source as an image. The arguments passed to the function are: + * {@link ol.Extent} the image extent, `{number}` the image resolution, + * `{number}` the device pixel ratio, {@link ol.Size} the image size, and + * {@link ol.proj.Projection} the image projection. The canvas returned by + * this function is cached by the source. The this keyword inside the function + * references the {@link ol.source.ImageCanvas}. * - * @param {string} name A name for the logger. This should be a dot-separated - * name and should normally be based on the package name or class name of the - * subsystem, such as goog.net.BrowserChannel. - * @return {!goog.debug.Logger} The named logger. - */ -goog.debug.LogManager.getLogger = function(name) { - goog.debug.LogManager.initialize(); - var ret = goog.debug.LogManager.loggers_[name]; - return ret || goog.debug.LogManager.createLogger_(name); -}; - - -/** - * Creates a function that can be passed to goog.debug.catchErrors. The function - * will log all reported errors using the given logger. - * @param {goog.debug.Logger=} opt_logger The logger to log the errors to. - * Defaults to the root logger. - * @return {function(Object)} The created function. - */ -goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) { - return function(info) { - var logger = opt_logger || goog.debug.LogManager.getRoot(); - logger.severe('Error: ' + info.message + ' (' + info.fileName + - ' @ Line: ' + info.line + ')'); - }; -}; - - -/** - * Creates the named logger. Will also create the parents of the named logger - * if they don't yet exist. - * @param {string} name The name of the logger. - * @return {!goog.debug.Logger} The named logger. - * @private + * @typedef {function(this:ol.source.ImageCanvas, ol.Extent, number, + * number, ol.Size, ol.proj.Projection): HTMLCanvasElement} + * @api */ -goog.debug.LogManager.createLogger_ = function(name) { - // find parent logger - var logger = new goog.debug.Logger(name); - if (goog.debug.Logger.ENABLE_HIERARCHY) { - var lastDotIndex = name.lastIndexOf('.'); - var parentName = name.substr(0, lastDotIndex); - var leafName = name.substr(lastDotIndex + 1); - var parentLogger = goog.debug.LogManager.getLogger(parentName); - - // tell the parent about the child and the child about the parent - parentLogger.addChild_(leafName, logger); - logger.setParent_(parentLogger); - } - - goog.debug.LogManager.loggers_[name] = logger; - return logger; -}; +ol.CanvasFunctionType; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// Copyright 2012 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -46794,462 +46105,364 @@ goog.debug.LogManager.createLogger_ = function(name) { // limitations under the License. /** - * @fileoverview Definition the goog.debug.RelativeTimeProvider class. + * @fileoverview Utilities for detecting, adding and removing classes. Prefer + * this over goog.dom.classes for new code since it attempts to use classList + * (DOMTokenList: http://dom.spec.whatwg.org/#domtokenlist) which is faster + * and requires less code. * + * Note: these utilities are meant to operate on HTMLElements + * and may have unexpected behavior on elements with differing interfaces + * (such as SVGElements). */ -goog.provide('goog.debug.RelativeTimeProvider'); - +goog.provide('goog.dom.classlist'); -/** - * A simple object to keep track of a timestamp considered the start of - * something. The main use is for the logger system to maintain a start time - * that is occasionally reset. For example, in Gmail, we reset this relative - * time at the start of a user action so that timings are offset from the - * beginning of the action. This class also provides a singleton as the default - * behavior for most use cases is to share the same start time. - * - * @constructor - * @final - */ -goog.debug.RelativeTimeProvider = function() { - /** - * The start time. - * @type {number} - * @private - */ - this.relativeTimeStart_ = goog.now(); -}; +goog.require('goog.array'); /** - * Default instance. - * @type {goog.debug.RelativeTimeProvider} - * @private + * Override this define at build-time if you know your target supports it. + * @define {boolean} Whether to use the classList property (DOMTokenList). */ -goog.debug.RelativeTimeProvider.defaultInstance_ = - new goog.debug.RelativeTimeProvider(); +goog.define('goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST', false); /** - * Sets the start time to the specified time. - * @param {number} timeStamp The start time. + * Gets an array-like object of class names on an element. + * @param {Element} element DOM node to get the classes of. + * @return {!goog.array.ArrayLike} Class names on {@code element}. */ -goog.debug.RelativeTimeProvider.prototype.set = function(timeStamp) { - this.relativeTimeStart_ = timeStamp; +goog.dom.classlist.get = function(element) { + if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { + return element.classList; + } + + var className = element.className; + // Some types of elements don't have a className in IE (e.g. iframes). + // Furthermore, in Firefox, className is not a string when the element is + // an SVG element. + return goog.isString(className) && className.match(/\S+/g) || []; }; /** - * Resets the start time to now. + * Sets the entire class name of an element. + * @param {Element} element DOM node to set class of. + * @param {string} className Class name(s) to apply to element. */ -goog.debug.RelativeTimeProvider.prototype.reset = function() { - this.set(goog.now()); +goog.dom.classlist.set = function(element, className) { + element.className = className; }; /** - * @return {number} The start time. + * Returns true if an element has a class. This method may throw a DOM + * exception for an invalid or empty class name if DOMTokenList is used. + * @param {Element} element DOM node to test. + * @param {string} className Class name to test for. + * @return {boolean} Whether element has the class. */ -goog.debug.RelativeTimeProvider.prototype.get = function() { - return this.relativeTimeStart_; +goog.dom.classlist.contains = function(element, className) { + if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { + return element.classList.contains(className); + } + return goog.array.contains(goog.dom.classlist.get(element), className); }; /** - * @return {goog.debug.RelativeTimeProvider} The default instance. + * Adds a class to an element. Does not add multiples of class names. This + * method may throw a DOM exception for an invalid or empty class name if + * DOMTokenList is used. + * @param {Element} element DOM node to add class to. + * @param {string} className Class name to add. */ -goog.debug.RelativeTimeProvider.getDefaultInstance = function() { - return goog.debug.RelativeTimeProvider.defaultInstance_; +goog.dom.classlist.add = function(element, className) { + if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { + element.classList.add(className); + return; + } + + if (!goog.dom.classlist.contains(element, className)) { + // Ensure we add a space if this is not the first class name added. + element.className += element.className.length > 0 ? + (' ' + className) : className; + } }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Definition of various formatters for logging. Please minimize - * dependencies this file has on other closure classes as any dependency it - * takes won't be able to use the logging infrastructure. - * + * Convenience method to add a number of class names at once. + * @param {Element} element The element to which to add classes. + * @param {goog.array.ArrayLike<string>} classesToAdd An array-like object + * containing a collection of class names to add to the element. + * This method may throw a DOM exception if classesToAdd contains invalid + * or empty class names. */ +goog.dom.classlist.addAll = function(element, classesToAdd) { + if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { + goog.array.forEach(classesToAdd, function(className) { + goog.dom.classlist.add(element, className); + }); + return; + } -goog.provide('goog.debug.Formatter'); -goog.provide('goog.debug.HtmlFormatter'); -goog.provide('goog.debug.TextFormatter'); + var classMap = {}; -goog.require('goog.debug'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.RelativeTimeProvider'); -goog.require('goog.html.SafeHtml'); + // Get all current class names into a map. + goog.array.forEach(goog.dom.classlist.get(element), + function(className) { + classMap[className] = true; + }); + + // Add new class names to the map. + goog.array.forEach(classesToAdd, + function(className) { + classMap[className] = true; + }); + // Flatten the keys of the map into the className. + element.className = ''; + for (var className in classMap) { + element.className += element.className.length > 0 ? + (' ' + className) : className; + } +}; /** - * Base class for Formatters. A Formatter is used to format a LogRecord into - * something that can be displayed to the user. - * - * @param {string=} opt_prefix The prefix to place before text records. - * @constructor + * Removes a class from an element. This method may throw a DOM exception + * for an invalid or empty class name if DOMTokenList is used. + * @param {Element} element DOM node to remove class from. + * @param {string} className Class name to remove. */ -goog.debug.Formatter = function(opt_prefix) { - this.prefix_ = opt_prefix || ''; +goog.dom.classlist.remove = function(element, className) { + if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { + element.classList.remove(className); + return; + } - /** - * A provider that returns the relative start time. - * @type {goog.debug.RelativeTimeProvider} - * @private - */ - this.startTimeProvider_ = - goog.debug.RelativeTimeProvider.getDefaultInstance(); + if (goog.dom.classlist.contains(element, className)) { + // Filter out the class name. + element.className = goog.array.filter( + goog.dom.classlist.get(element), + function(c) { + return c != className; + }).join(' '); + } }; /** - * Whether to append newlines to the end of formatted log records. - * @type {boolean} + * Removes a set of classes from an element. Prefer this call to + * repeatedly calling {@code goog.dom.classlist.remove} if you want to remove + * a large set of class names at once. + * @param {Element} element The element from which to remove classes. + * @param {goog.array.ArrayLike<string>} classesToRemove An array-like object + * containing a collection of class names to remove from the element. + * This method may throw a DOM exception if classesToRemove contains invalid + * or empty class names. */ -goog.debug.Formatter.prototype.appendNewline = true; +goog.dom.classlist.removeAll = function(element, classesToRemove) { + if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) { + goog.array.forEach(classesToRemove, function(className) { + goog.dom.classlist.remove(element, className); + }); + return; + } + // Filter out those classes in classesToRemove. + element.className = goog.array.filter( + goog.dom.classlist.get(element), + function(className) { + // If this class is not one we are trying to remove, + // add it to the array of new class names. + return !goog.array.contains(classesToRemove, className); + }).join(' '); +}; /** - * Whether to show absolute time in the DebugWindow. - * @type {boolean} + * Adds or removes a class depending on the enabled argument. This method + * may throw a DOM exception for an invalid or empty class name if DOMTokenList + * is used. + * @param {Element} element DOM node to add or remove the class on. + * @param {string} className Class name to add or remove. + * @param {boolean} enabled Whether to add or remove the class (true adds, + * false removes). */ -goog.debug.Formatter.prototype.showAbsoluteTime = true; +goog.dom.classlist.enable = function(element, className, enabled) { + if (enabled) { + goog.dom.classlist.add(element, className); + } else { + goog.dom.classlist.remove(element, className); + } +}; /** - * Whether to show relative time in the DebugWindow. - * @type {boolean} + * Adds or removes a set of classes depending on the enabled argument. This + * method may throw a DOM exception for an invalid or empty class name if + * DOMTokenList is used. + * @param {!Element} element DOM node to add or remove the class on. + * @param {goog.array.ArrayLike<string>} classesToEnable An array-like object + * containing a collection of class names to add or remove from the element. + * @param {boolean} enabled Whether to add or remove the classes (true adds, + * false removes). */ -goog.debug.Formatter.prototype.showRelativeTime = true; +goog.dom.classlist.enableAll = function(element, classesToEnable, enabled) { + var f = enabled ? goog.dom.classlist.addAll : + goog.dom.classlist.removeAll; + f(element, classesToEnable); +}; /** - * Whether to show the logger name in the DebugWindow. - * @type {boolean} + * Switches a class on an element from one to another without disturbing other + * classes. If the fromClass isn't removed, the toClass won't be added. This + * method may throw a DOM exception if the class names are empty or invalid. + * @param {Element} element DOM node to swap classes on. + * @param {string} fromClass Class to remove. + * @param {string} toClass Class to add. + * @return {boolean} Whether classes were switched. */ -goog.debug.Formatter.prototype.showLoggerName = true; +goog.dom.classlist.swap = function(element, fromClass, toClass) { + if (goog.dom.classlist.contains(element, fromClass)) { + goog.dom.classlist.remove(element, fromClass); + goog.dom.classlist.add(element, toClass); + return true; + } + return false; +}; /** - * Whether to show the logger exception text. - * @type {boolean} + * Removes a class if an element has it, and adds it the element doesn't have + * it. Won't affect other classes on the node. This method may throw a DOM + * exception if the class name is empty or invalid. + * @param {Element} element DOM node to toggle class on. + * @param {string} className Class to toggle. + * @return {boolean} True if class was added, false if it was removed + * (in other words, whether element has the class after this function has + * been called). */ -goog.debug.Formatter.prototype.showExceptionText = false; +goog.dom.classlist.toggle = function(element, className) { + var add = !goog.dom.classlist.contains(element, className); + goog.dom.classlist.enable(element, className, add); + return add; +}; /** - * Whether to show the severity level. - * @type {boolean} + * Adds and removes a class of an element. Unlike + * {@link goog.dom.classlist.swap}, this method adds the classToAdd regardless + * of whether the classToRemove was present and had been removed. This method + * may throw a DOM exception if the class names are empty or invalid. + * + * @param {Element} element DOM node to swap classes on. + * @param {string} classToRemove Class to remove. + * @param {string} classToAdd Class to add. */ -goog.debug.Formatter.prototype.showSeverityLevel = false; +goog.dom.classlist.addRemove = function(element, classToRemove, classToAdd) { + goog.dom.classlist.remove(element, classToRemove); + goog.dom.classlist.add(element, classToAdd); +}; +// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Formats a record. - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {string} The formatted string. + * @fileoverview Vendor prefix getters. */ -goog.debug.Formatter.prototype.formatRecord = goog.abstractMethod; +goog.provide('goog.dom.vendor'); -/** - * Formats a record as SafeHtml. - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. - */ -goog.debug.Formatter.prototype.formatRecordAsHtml = goog.abstractMethod; +goog.require('goog.string'); +goog.require('goog.userAgent'); /** - * Sets the start time provider. By default, this is the default instance - * but can be changed. - * @param {goog.debug.RelativeTimeProvider} provider The provider to use. + * Returns the JS vendor prefix used in CSS properties. Different vendors + * use different methods of changing the case of the property names. + * + * @return {?string} The JS vendor prefix or null if there is none. */ -goog.debug.Formatter.prototype.setStartTimeProvider = function(provider) { - this.startTimeProvider_ = provider; -}; - +goog.dom.vendor.getVendorJsPrefix = function() { + if (goog.userAgent.WEBKIT) { + return 'Webkit'; + } else if (goog.userAgent.GECKO) { + return 'Moz'; + } else if (goog.userAgent.IE) { + return 'ms'; + } else if (goog.userAgent.OPERA) { + return 'O'; + } -/** - * Returns the start time provider. By default, this is the default instance - * but can be changed. - * @return {goog.debug.RelativeTimeProvider} The start time provider. - */ -goog.debug.Formatter.prototype.getStartTimeProvider = function() { - return this.startTimeProvider_; + return null; }; /** - * Resets the start relative time. + * Returns the vendor prefix used in CSS properties. + * + * @return {?string} The vendor prefix or null if there is none. */ -goog.debug.Formatter.prototype.resetRelativeTimeStart = function() { - this.startTimeProvider_.reset(); -}; - - -/** - * Returns a string for the time/date of the LogRecord. - * @param {goog.debug.LogRecord} logRecord The record to get a time stamp for. - * @return {string} A string representation of the time/date of the LogRecord. - * @private - */ -goog.debug.Formatter.getDateTimeStamp_ = function(logRecord) { - var time = new Date(logRecord.getMillis()); - return goog.debug.Formatter.getTwoDigitString_((time.getFullYear() - 2000)) + - goog.debug.Formatter.getTwoDigitString_((time.getMonth() + 1)) + - goog.debug.Formatter.getTwoDigitString_(time.getDate()) + ' ' + - goog.debug.Formatter.getTwoDigitString_(time.getHours()) + ':' + - goog.debug.Formatter.getTwoDigitString_(time.getMinutes()) + ':' + - goog.debug.Formatter.getTwoDigitString_(time.getSeconds()) + '.' + - goog.debug.Formatter.getTwoDigitString_( - Math.floor(time.getMilliseconds() / 10)); -}; - - -/** - * Returns the number as a two-digit string, meaning it prepends a 0 if the - * number if less than 10. - * @param {number} n The number to format. - * @return {string} A two-digit string representation of {@code n}. - * @private - */ -goog.debug.Formatter.getTwoDigitString_ = function(n) { - if (n < 10) { - return '0' + n; - } - return String(n); -}; - - -/** - * Returns a string for the number of seconds relative to the start time. - * Prepads with spaces so that anything less than 1000 seconds takes up the - * same number of characters for better formatting. - * @param {goog.debug.LogRecord} logRecord The log to compare time to. - * @param {number} relativeTimeStart The start time to compare to. - * @return {string} The number of seconds of the LogRecord relative to the - * start time. - * @private - */ -goog.debug.Formatter.getRelativeTime_ = function(logRecord, - relativeTimeStart) { - var ms = logRecord.getMillis() - relativeTimeStart; - var sec = ms / 1000; - var str = sec.toFixed(3); - - var spacesToPrepend = 0; - if (sec < 1) { - spacesToPrepend = 2; - } else { - while (sec < 100) { - spacesToPrepend++; - sec *= 10; - } - } - while (spacesToPrepend-- > 0) { - str = ' ' + str; - } - return str; -}; - - - -/** - * Formatter that returns formatted html. See formatRecord for the classes - * it uses for various types of formatted output. - * - * @param {string=} opt_prefix The prefix to place before text records. - * @constructor - * @extends {goog.debug.Formatter} - */ -goog.debug.HtmlFormatter = function(opt_prefix) { - goog.debug.Formatter.call(this, opt_prefix); -}; -goog.inherits(goog.debug.HtmlFormatter, goog.debug.Formatter); - - -/** - * Whether to show the logger exception text - * @type {boolean} - * @override - */ -goog.debug.HtmlFormatter.prototype.showExceptionText = true; - - -/** - * Formats a record - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {string} The formatted string as html. - * @override - */ -goog.debug.HtmlFormatter.prototype.formatRecord = function(logRecord) { - if (!logRecord) { - return ''; - } - // OK not to use goog.html.SafeHtml.unwrap() here. - return this.formatRecordAsHtml(logRecord).getTypedStringValue(); -}; - - -/** - * Formats a record. - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. - * @override - */ -goog.debug.HtmlFormatter.prototype.formatRecordAsHtml = function(logRecord) { - if (!logRecord) { - return goog.html.SafeHtml.EMPTY; - } - - var className; - switch (logRecord.getLevel().value) { - case goog.debug.Logger.Level.SHOUT.value: - className = 'dbg-sh'; - break; - case goog.debug.Logger.Level.SEVERE.value: - className = 'dbg-sev'; - break; - case goog.debug.Logger.Level.WARNING.value: - className = 'dbg-w'; - break; - case goog.debug.Logger.Level.INFO.value: - className = 'dbg-i'; - break; - case goog.debug.Logger.Level.FINE.value: - default: - className = 'dbg-f'; - break; - } - - // HTML for user defined prefix, time, logger name, and severity. - var sb = []; - sb.push(this.prefix_, ' '); - if (this.showAbsoluteTime) { - sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] '); - } - if (this.showRelativeTime) { - sb.push('[', - goog.debug.Formatter.getRelativeTime_( - logRecord, this.startTimeProvider_.get()), - 's] '); - } - if (this.showLoggerName) { - sb.push('[', logRecord.getLoggerName(), '] '); - } - if (this.showSeverityLevel) { - sb.push('[', logRecord.getLevel().name, '] '); - } - var fullPrefixHtml = - goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(sb.join('')); - - // HTML for exception text and log record. - var exceptionHtml = goog.html.SafeHtml.EMPTY; - if (this.showExceptionText && logRecord.getException()) { - exceptionHtml = goog.html.SafeHtml.concat( - goog.html.SafeHtml.create('br'), - goog.debug.exposeExceptionAsHtml(logRecord.getException())); - } - var logRecordHtml = goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - logRecord.getMessage()); - var recordAndExceptionHtml = goog.html.SafeHtml.create( - 'span', - {'class': className}, - goog.html.SafeHtml.concat(logRecordHtml, exceptionHtml)); - - - // Combine both pieces of HTML and, if needed, append a final newline. - var html; - if (this.appendNewline) { - html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml, - goog.html.SafeHtml.create('br')); - } else { - html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml); +goog.dom.vendor.getVendorPrefix = function() { + if (goog.userAgent.WEBKIT) { + return '-webkit'; + } else if (goog.userAgent.GECKO) { + return '-moz'; + } else if (goog.userAgent.IE) { + return '-ms'; + } else if (goog.userAgent.OPERA) { + return '-o'; } - return html; -}; - - -/** - * Formatter that returns formatted plain text - * - * @param {string=} opt_prefix The prefix to place before text records. - * @constructor - * @extends {goog.debug.Formatter} - * @final - */ -goog.debug.TextFormatter = function(opt_prefix) { - goog.debug.Formatter.call(this, opt_prefix); + return null; }; -goog.inherits(goog.debug.TextFormatter, goog.debug.Formatter); /** - * Formats a record as text - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {string} The formatted string. - * @override + * @param {string} propertyName A property name. + * @param {!Object=} opt_object If provided, we verify if the property exists in + * the object. + * @return {?string} A vendor prefixed property name, or null if it does not + * exist. */ -goog.debug.TextFormatter.prototype.formatRecord = function(logRecord) { - var sb = []; - sb.push(this.prefix_, ' '); - if (this.showAbsoluteTime) { - sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] '); - } - if (this.showRelativeTime) { - sb.push('[', goog.debug.Formatter.getRelativeTime_(logRecord, - this.startTimeProvider_.get()), 's] '); - } - - if (this.showLoggerName) { - sb.push('[', logRecord.getLoggerName(), '] '); - } - if (this.showSeverityLevel) { - sb.push('[', logRecord.getLevel().name, '] '); - } - sb.push(logRecord.getMessage()); - if (this.showExceptionText) { - var exception = logRecord.getException(); - if (exception) { - var exceptionText = exception instanceof Error ? - exception.message : - exception.toString(); - sb.push('\n', exceptionText); - } +goog.dom.vendor.getPrefixedPropertyName = function(propertyName, opt_object) { + // We first check for a non-prefixed property, if available. + if (opt_object && propertyName in opt_object) { + return propertyName; } - if (this.appendNewline) { - sb.push('\n'); + var prefix = goog.dom.vendor.getVendorJsPrefix(); + if (prefix) { + prefix = prefix.toLowerCase(); + var prefixedPropertyName = prefix + goog.string.toTitleCase(propertyName); + return (!goog.isDef(opt_object) || prefixedPropertyName in opt_object) ? + prefixedPropertyName : null; } - return sb.join(''); + return null; }; /** - * Formats a record as text - * @param {goog.debug.LogRecord} logRecord the logRecord to format. - * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. This is - * just an HTML-escaped version of the text obtained from formatRecord(). - * @override + * @param {string} eventType An event type. + * @return {string} A lower-cased vendor prefixed event type. */ -goog.debug.TextFormatter.prototype.formatRecordAsHtml = function(logRecord) { - return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( - goog.debug.TextFormatter.prototype.formatRecord(logRecord)); +goog.dom.vendor.getPrefixedEventType = function(eventType) { + var prefix = goog.dom.vendor.getVendorJsPrefix() || ''; + return (prefix + eventType).toLowerCase(); }; // Copyright 2006 The Closure Library Authors. All Rights Reserved. @@ -47267,363 +46480,388 @@ goog.debug.TextFormatter.prototype.formatRecordAsHtml = function(logRecord) { // limitations under the License. /** - * @fileoverview Simple logger that logs to the window console if available. - * - * Has an autoInstall option which can be put into initialization code, which - * will start logging if "Debug=true" is in document.location.href - * + * @fileoverview A utility class for representing a numeric box. */ -goog.provide('goog.debug.Console'); -goog.require('goog.debug.LogManager'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.TextFormatter'); +goog.provide('goog.math.Box'); + +goog.require('goog.math.Coordinate'); /** - * Create and install a log handler that logs to window.console if available + * Class for representing a box. A box is specified as a top, right, bottom, + * and left. A box is useful for representing margins and padding. + * + * This class assumes 'screen coordinates': larger Y coordinates are further + * from the top of the screen. + * + * @param {number} top Top. + * @param {number} right Right. + * @param {number} bottom Bottom. + * @param {number} left Left. + * @struct * @constructor */ -goog.debug.Console = function() { - this.publishHandler_ = goog.bind(this.addLogRecord, this); +goog.math.Box = function(top, right, bottom, left) { + /** + * Top + * @type {number} + */ + this.top = top; /** - * Formatter for formatted output. - * @type {!goog.debug.TextFormatter} - * @private + * Right + * @type {number} */ - this.formatter_ = new goog.debug.TextFormatter(); - this.formatter_.showAbsoluteTime = false; - this.formatter_.showExceptionText = false; - // The console logging methods automatically append a newline. - this.formatter_.appendNewline = false; + this.right = right; - this.isCapturing_ = false; - this.logBuffer_ = ''; + /** + * Bottom + * @type {number} + */ + this.bottom = bottom; /** - * Loggers that we shouldn't output. - * @type {!Object<boolean>} - * @private + * Left + * @type {number} */ - this.filteredLoggers_ = {}; + this.left = left; }; /** - * Returns the text formatter used by this console - * @return {!goog.debug.TextFormatter} The text formatter. + * Creates a Box by bounding a collection of goog.math.Coordinate objects + * @param {...goog.math.Coordinate} var_args Coordinates to be included inside + * the box. + * @return {!goog.math.Box} A Box containing all the specified Coordinates. */ -goog.debug.Console.prototype.getFormatter = function() { - return this.formatter_; +goog.math.Box.boundingBox = function(var_args) { + var box = new goog.math.Box(arguments[0].y, arguments[0].x, + arguments[0].y, arguments[0].x); + for (var i = 1; i < arguments.length; i++) { + box.expandToIncludeCoordinate(arguments[i]); + } + return box; }; /** - * Sets whether we are currently capturing logger output. - * @param {boolean} capturing Whether to capture logger output. + * @return {number} width The width of this Box. */ -goog.debug.Console.prototype.setCapturing = function(capturing) { - if (capturing == this.isCapturing_) { - return; - } - - // attach or detach handler from the root logger - var rootLogger = goog.debug.LogManager.getRoot(); - if (capturing) { - rootLogger.addHandler(this.publishHandler_); - } else { - rootLogger.removeHandler(this.publishHandler_); - this.logBuffer = ''; - } - this.isCapturing_ = capturing; +goog.math.Box.prototype.getWidth = function() { + return this.right - this.left; }; /** - * Adds a log record. - * @param {goog.debug.LogRecord} logRecord The log entry. + * @return {number} height The height of this Box. */ -goog.debug.Console.prototype.addLogRecord = function(logRecord) { - - // Check to see if the log record is filtered or not. - if (this.filteredLoggers_[logRecord.getLoggerName()]) { - return; - } - - var record = this.formatter_.formatRecord(logRecord); - var console = goog.debug.Console.console_; - if (console) { - switch (logRecord.getLevel()) { - case goog.debug.Logger.Level.SHOUT: - goog.debug.Console.logToConsole_(console, 'info', record); - break; - case goog.debug.Logger.Level.SEVERE: - goog.debug.Console.logToConsole_(console, 'error', record); - break; - case goog.debug.Logger.Level.WARNING: - goog.debug.Console.logToConsole_(console, 'warn', record); - break; - default: - goog.debug.Console.logToConsole_(console, 'debug', record); - break; - } - } else { - this.logBuffer_ += record; - } +goog.math.Box.prototype.getHeight = function() { + return this.bottom - this.top; }; /** - * Adds a logger name to be filtered. - * @param {string} loggerName the logger name to add. + * Creates a copy of the box with the same dimensions. + * @return {!goog.math.Box} A clone of this Box. */ -goog.debug.Console.prototype.addFilter = function(loggerName) { - this.filteredLoggers_[loggerName] = true; +goog.math.Box.prototype.clone = function() { + return new goog.math.Box(this.top, this.right, this.bottom, this.left); }; +if (goog.DEBUG) { + /** + * Returns a nice string representing the box. + * @return {string} In the form (50t, 73r, 24b, 13l). + * @override + */ + goog.math.Box.prototype.toString = function() { + return '(' + this.top + 't, ' + this.right + 'r, ' + this.bottom + 'b, ' + + this.left + 'l)'; + }; +} + + /** - * Removes a logger name to be filtered. - * @param {string} loggerName the logger name to remove. + * Returns whether the box contains a coordinate or another box. + * + * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box. + * @return {boolean} Whether the box contains the coordinate or other box. */ -goog.debug.Console.prototype.removeFilter = function(loggerName) { - delete this.filteredLoggers_[loggerName]; +goog.math.Box.prototype.contains = function(other) { + return goog.math.Box.contains(this, other); }; /** - * Global console logger instance - * @type {goog.debug.Console} + * Expands box with the given margins. + * + * @param {number|goog.math.Box} top Top margin or box with all margins. + * @param {number=} opt_right Right margin. + * @param {number=} opt_bottom Bottom margin. + * @param {number=} opt_left Left margin. + * @return {!goog.math.Box} A reference to this Box. */ -goog.debug.Console.instance = null; +goog.math.Box.prototype.expand = function(top, opt_right, opt_bottom, + opt_left) { + if (goog.isObject(top)) { + this.top -= top.top; + this.right += top.right; + this.bottom += top.bottom; + this.left -= top.left; + } else { + this.top -= top; + this.right += opt_right; + this.bottom += opt_bottom; + this.left -= opt_left; + } + + return this; +}; /** - * The console to which to log. This is a property so it can be mocked out in - * this unit test for goog.debug.Console. Using goog.global, as console might be - * used in window-less contexts. - * @type {Object} - * @private + * Expand this box to include another box. + * NOTE(user): This is used in code that needs to be very fast, please don't + * add functionality to this function at the expense of speed (variable + * arguments, accepting multiple argument types, etc). + * @param {goog.math.Box} box The box to include in this one. */ -goog.debug.Console.console_ = goog.global['console']; +goog.math.Box.prototype.expandToInclude = function(box) { + this.left = Math.min(this.left, box.left); + this.top = Math.min(this.top, box.top); + this.right = Math.max(this.right, box.right); + this.bottom = Math.max(this.bottom, box.bottom); +}; /** - * Sets the console to which to log. - * @param {!Object} console The console to which to log. + * Expand this box to include the coordinate. + * @param {!goog.math.Coordinate} coord The coordinate to be included + * inside the box. */ -goog.debug.Console.setConsole = function(console) { - goog.debug.Console.console_ = console; +goog.math.Box.prototype.expandToIncludeCoordinate = function(coord) { + this.top = Math.min(this.top, coord.y); + this.right = Math.max(this.right, coord.x); + this.bottom = Math.max(this.bottom, coord.y); + this.left = Math.min(this.left, coord.x); }; /** - * Install the console and start capturing if "Debug=true" is in the page URL + * Compares boxes for equality. + * @param {goog.math.Box} a A Box. + * @param {goog.math.Box} b A Box. + * @return {boolean} True iff the boxes are equal, or if both are null. */ -goog.debug.Console.autoInstall = function() { - if (!goog.debug.Console.instance) { - goog.debug.Console.instance = new goog.debug.Console(); +goog.math.Box.equals = function(a, b) { + if (a == b) { + return true; } - - if (goog.global.location && - goog.global.location.href.indexOf('Debug=true') != -1) { - goog.debug.Console.instance.setCapturing(true); + if (!a || !b) { + return false; } + return a.top == b.top && a.right == b.right && + a.bottom == b.bottom && a.left == b.left; }; /** - * Show an alert with all of the captured debug information. - * Information is only captured if console is not available + * Returns whether a box contains a coordinate or another box. + * + * @param {goog.math.Box} box A Box. + * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box. + * @return {boolean} Whether the box contains the coordinate or other box. */ -goog.debug.Console.show = function() { - alert(goog.debug.Console.instance.logBuffer_); -}; +goog.math.Box.contains = function(box, other) { + if (!box || !other) { + return false; + } + if (other instanceof goog.math.Box) { + return other.left >= box.left && other.right <= box.right && + other.top >= box.top && other.bottom <= box.bottom; + } -/** - * Logs the record to the console using the given function. If the function is - * not available on the console object, the log function is used instead. - * @param {!Object} console The console object. - * @param {string} fnName The name of the function to use. - * @param {string} record The record to log. - * @private - */ -goog.debug.Console.logToConsole_ = function(console, fnName, record) { - if (console[fnName]) { - console[fnName](record); - } else { - console.log(record); - } + // other is a Coordinate. + return other.x >= box.left && other.x <= box.right && + other.y >= box.top && other.y <= box.bottom; }; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utility class that monitors viewport size changes. + * Returns the relative x position of a coordinate compared to a box. Returns + * zero if the coordinate is inside the box. * - * @author attila@google.com (Attila Bodis) - * @see ../demos/viewportsizemonitor.html + * @param {goog.math.Box} box A Box. + * @param {goog.math.Coordinate} coord A Coordinate. + * @return {number} The x position of {@code coord} relative to the nearest + * side of {@code box}, or zero if {@code coord} is inside {@code box}. */ +goog.math.Box.relativePositionX = function(box, coord) { + if (coord.x < box.left) { + return coord.x - box.left; + } else if (coord.x > box.right) { + return coord.x - box.right; + } + return 0; +}; -goog.provide('goog.dom.ViewportSizeMonitor'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.math.Size'); +/** + * Returns the relative y position of a coordinate compared to a box. Returns + * zero if the coordinate is inside the box. + * + * @param {goog.math.Box} box A Box. + * @param {goog.math.Coordinate} coord A Coordinate. + * @return {number} The y position of {@code coord} relative to the nearest + * side of {@code box}, or zero if {@code coord} is inside {@code box}. + */ +goog.math.Box.relativePositionY = function(box, coord) { + if (coord.y < box.top) { + return coord.y - box.top; + } else if (coord.y > box.bottom) { + return coord.y - box.bottom; + } + return 0; +}; /** - * This class can be used to monitor changes in the viewport size. Instances - * dispatch a {@link goog.events.EventType.RESIZE} event when the viewport size - * changes. Handlers can call {@link goog.dom.ViewportSizeMonitor#getSize} to - * get the new viewport size. - * - * Use this class if you want to execute resize/reflow logic each time the - * user resizes the browser window. This class is guaranteed to only dispatch - * {@code RESIZE} events when the pixel dimensions of the viewport change. - * (Internet Explorer fires resize events if any element on the page is resized, - * even if the viewport dimensions are unchanged, which can lead to infinite - * resize loops.) - * - * Example usage: - * <pre> - * var vsm = new goog.dom.ViewportSizeMonitor(); - * goog.events.listen(vsm, goog.events.EventType.RESIZE, function(e) { - * alert('Viewport size changed to ' + vsm.getSize()); - * }); - * </pre> - * - * Manually verified on IE6, IE7, FF2, Opera 11, Safari 4 and Chrome. + * Returns the distance between a coordinate and the nearest corner/side of a + * box. Returns zero if the coordinate is inside the box. * - * @param {Window=} opt_window The window to monitor; defaults to the window in - * which this code is executing. - * @constructor - * @extends {goog.events.EventTarget} + * @param {goog.math.Box} box A Box. + * @param {goog.math.Coordinate} coord A Coordinate. + * @return {number} The distance between {@code coord} and the nearest + * corner/side of {@code box}, or zero if {@code coord} is inside + * {@code box}. */ -goog.dom.ViewportSizeMonitor = function(opt_window) { - goog.dom.ViewportSizeMonitor.base(this, 'constructor'); - - /** - * The window to monitor. Defaults to the window in which the code is running. - * @private {Window} - */ - this.window_ = opt_window || window; +goog.math.Box.distance = function(box, coord) { + var x = goog.math.Box.relativePositionX(box, coord); + var y = goog.math.Box.relativePositionY(box, coord); + return Math.sqrt(x * x + y * y); +}; - /** - * Event listener key for window the window resize handler, as returned by - * {@link goog.events.listen}. - * @private {goog.events.Key} - */ - this.listenerKey_ = goog.events.listen(this.window_, - goog.events.EventType.RESIZE, this.handleResize_, false, this); - /** - * The most recently recorded size of the viewport, in pixels. - * @private {goog.math.Size} - */ - this.size_ = goog.dom.getViewportSize(this.window_); +/** + * Returns whether two boxes intersect. + * + * @param {goog.math.Box} a A Box. + * @param {goog.math.Box} b A second Box. + * @return {boolean} Whether the boxes intersect. + */ +goog.math.Box.intersects = function(a, b) { + return (a.left <= b.right && b.left <= a.right && + a.top <= b.bottom && b.top <= a.bottom); }; -goog.inherits(goog.dom.ViewportSizeMonitor, goog.events.EventTarget); /** - * Returns a viewport size monitor for the given window. A new one is created - * if it doesn't exist already. This prevents the unnecessary creation of - * multiple spooling monitors for a window. - * @param {Window=} opt_window The window to monitor; defaults to the window in - * which this code is executing. - * @return {!goog.dom.ViewportSizeMonitor} Monitor for the given window. + * Returns whether two boxes would intersect with additional padding. + * + * @param {goog.math.Box} a A Box. + * @param {goog.math.Box} b A second Box. + * @param {number} padding The additional padding. + * @return {boolean} Whether the boxes intersect. */ -goog.dom.ViewportSizeMonitor.getInstanceForWindow = function(opt_window) { - var currentWindow = opt_window || window; - var uid = goog.getUid(currentWindow); - - return goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] = - goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] || - new goog.dom.ViewportSizeMonitor(currentWindow); +goog.math.Box.intersectsWithPadding = function(a, b, padding) { + return (a.left <= b.right + padding && b.left <= a.right + padding && + a.top <= b.bottom + padding && b.top <= a.bottom + padding); }; /** - * Removes and disposes a viewport size monitor for the given window if one - * exists. - * @param {Window=} opt_window The window whose monitor should be removed; - * defaults to the window in which this code is executing. + * Rounds the fields to the next larger integer values. + * + * @return {!goog.math.Box} This box with ceil'd fields. */ -goog.dom.ViewportSizeMonitor.removeInstanceForWindow = function(opt_window) { - var uid = goog.getUid(opt_window || window); - - goog.dispose(goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]); - delete goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]; +goog.math.Box.prototype.ceil = function() { + this.top = Math.ceil(this.top); + this.right = Math.ceil(this.right); + this.bottom = Math.ceil(this.bottom); + this.left = Math.ceil(this.left); + return this; }; /** - * Map of window hash code to viewport size monitor for that window, if - * created. - * @type {Object<number,goog.dom.ViewportSizeMonitor>} - * @private + * Rounds the fields to the next smaller integer values. + * + * @return {!goog.math.Box} This box with floored fields. */ -goog.dom.ViewportSizeMonitor.windowInstanceMap_ = {}; +goog.math.Box.prototype.floor = function() { + this.top = Math.floor(this.top); + this.right = Math.floor(this.right); + this.bottom = Math.floor(this.bottom); + this.left = Math.floor(this.left); + return this; +}; /** - * Returns the most recently recorded size of the viewport, in pixels. May - * return null if no window resize event has been handled yet. - * @return {goog.math.Size} The viewport dimensions, in pixels. + * Rounds the fields to nearest integer values. + * + * @return {!goog.math.Box} This box with rounded fields. */ -goog.dom.ViewportSizeMonitor.prototype.getSize = function() { - // Return a clone instead of the original to preserve encapsulation. - return this.size_ ? this.size_.clone() : null; +goog.math.Box.prototype.round = function() { + this.top = Math.round(this.top); + this.right = Math.round(this.right); + this.bottom = Math.round(this.bottom); + this.left = Math.round(this.left); + return this; }; -/** @override */ -goog.dom.ViewportSizeMonitor.prototype.disposeInternal = function() { - goog.dom.ViewportSizeMonitor.superClass_.disposeInternal.call(this); - - if (this.listenerKey_) { - goog.events.unlistenByKey(this.listenerKey_); - this.listenerKey_ = null; +/** + * Translates this box by the given offsets. If a {@code goog.math.Coordinate} + * is given, then the left and right values are translated by the coordinate's + * x value and the top and bottom values are translated by the coordinate's y + * value. Otherwise, {@code tx} and {@code opt_ty} are used to translate the x + * and y dimension values. + * + * @param {number|goog.math.Coordinate} tx The value to translate the x + * dimension values by or the the coordinate to translate this box by. + * @param {number=} opt_ty The value to translate y dimension values by. + * @return {!goog.math.Box} This box after translating. + */ +goog.math.Box.prototype.translate = function(tx, opt_ty) { + if (tx instanceof goog.math.Coordinate) { + this.left += tx.x; + this.right += tx.x; + this.top += tx.y; + this.bottom += tx.y; + } else { + this.left += tx; + this.right += tx; + if (goog.isNumber(opt_ty)) { + this.top += opt_ty; + this.bottom += opt_ty; + } } - - this.window_ = null; - this.size_ = null; + return this; }; /** - * Handles window resize events by measuring the dimensions of the - * viewport and dispatching a {@link goog.events.EventType.RESIZE} event if the - * current dimensions are different from the previous ones. - * @param {goog.events.Event} event The window resize event to handle. - * @private + * Scales this coordinate by the given scale factors. The x and y dimension + * values are scaled by {@code sx} and {@code opt_sy} respectively. + * If {@code opt_sy} is not given, then {@code sx} is used for both x and y. + * + * @param {number} sx The scale factor to use for the x dimension. + * @param {number=} opt_sy The scale factor to use for the y dimension. + * @return {!goog.math.Box} This box after scaling. */ -goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) { - var size = goog.dom.getViewportSize(this.window_); - if (!goog.math.Size.equals(size, this.size_)) { - this.size_ = size; - this.dispatchEvent(goog.events.EventType.RESIZE); - } +goog.math.Box.prototype.scale = function(sx, opt_sy) { + var sy = goog.isNumber(opt_sy) ? opt_sy : sx; + this.left *= sx; + this.right *= sx; + this.top *= sy; + this.bottom *= sy; + return this; }; // Copyright 2006 The Closure Library Authors. All Rights Reserved. @@ -47641,975 +46879,467 @@ goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) { // limitations under the License. /** - * @fileoverview Constant declarations for common key codes. - * - * @author eae@google.com (Emil A Eklund) - * @see ../demos/keyhandler.html + * @fileoverview A utility class for representing rectangles. */ -goog.provide('goog.events.KeyCodes'); +goog.provide('goog.math.Rect'); -goog.require('goog.userAgent'); +goog.require('goog.math.Box'); +goog.require('goog.math.Coordinate'); +goog.require('goog.math.Size'); -goog.forwardDeclare('goog.events.BrowserEvent'); /** - * Key codes for common characters. - * - * This list is not localized and therefore some of the key codes are not - * correct for non US keyboard layouts. See comments below. - * - * @enum {number} + * Class for representing rectangular regions. + * @param {number} x Left. + * @param {number} y Top. + * @param {number} w Width. + * @param {number} h Height. + * @struct + * @constructor */ -goog.events.KeyCodes = { - WIN_KEY_FF_LINUX: 0, - MAC_ENTER: 3, - BACKSPACE: 8, - TAB: 9, - NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac - ENTER: 13, - SHIFT: 16, - CTRL: 17, - ALT: 18, - PAUSE: 19, - CAPS_LOCK: 20, - ESC: 27, - SPACE: 32, - PAGE_UP: 33, // also NUM_NORTH_EAST - PAGE_DOWN: 34, // also NUM_SOUTH_EAST - END: 35, // also NUM_SOUTH_WEST - HOME: 36, // also NUM_NORTH_WEST - LEFT: 37, // also NUM_WEST - UP: 38, // also NUM_NORTH - RIGHT: 39, // also NUM_EAST - DOWN: 40, // also NUM_SOUTH - PLUS_SIGN: 43, // NOT numpad plus - PRINT_SCREEN: 44, - INSERT: 45, // also NUM_INSERT - DELETE: 46, // also NUM_DELETE - ZERO: 48, - ONE: 49, - TWO: 50, - THREE: 51, - FOUR: 52, - FIVE: 53, - SIX: 54, - SEVEN: 55, - EIGHT: 56, - NINE: 57, - FF_SEMICOLON: 59, // Firefox (Gecko) fires this for semicolon instead of 186 - FF_EQUALS: 61, // Firefox (Gecko) fires this for equals instead of 187 - FF_DASH: 173, // Firefox (Gecko) fires this for dash instead of 189 - QUESTION_MARK: 63, // needs localization - AT_SIGN: 64, - A: 65, - B: 66, - C: 67, - D: 68, - E: 69, - F: 70, - G: 71, - H: 72, - I: 73, - J: 74, - K: 75, - L: 76, - M: 77, - N: 78, - O: 79, - P: 80, - Q: 81, - R: 82, - S: 83, - T: 84, - U: 85, - V: 86, - W: 87, - X: 88, - Y: 89, - Z: 90, - META: 91, // WIN_KEY_LEFT - WIN_KEY_RIGHT: 92, - CONTEXT_MENU: 93, - NUM_ZERO: 96, - NUM_ONE: 97, - NUM_TWO: 98, - NUM_THREE: 99, - NUM_FOUR: 100, - NUM_FIVE: 101, - NUM_SIX: 102, - NUM_SEVEN: 103, - NUM_EIGHT: 104, - NUM_NINE: 105, - NUM_MULTIPLY: 106, - NUM_PLUS: 107, - NUM_MINUS: 109, - NUM_PERIOD: 110, - NUM_DIVISION: 111, - F1: 112, - F2: 113, - F3: 114, - F4: 115, - F5: 116, - F6: 117, - F7: 118, - F8: 119, - F9: 120, - F10: 121, - F11: 122, - F12: 123, - NUMLOCK: 144, - SCROLL_LOCK: 145, +goog.math.Rect = function(x, y, w, h) { + /** @type {number} */ + this.left = x; - // OS-specific media keys like volume controls and browser controls. - FIRST_MEDIA_KEY: 166, - LAST_MEDIA_KEY: 183, + /** @type {number} */ + this.top = y; - SEMICOLON: 186, // needs localization - DASH: 189, // needs localization - EQUALS: 187, // needs localization - COMMA: 188, // needs localization - PERIOD: 190, // needs localization - SLASH: 191, // needs localization - APOSTROPHE: 192, // needs localization - TILDE: 192, // needs localization - SINGLE_QUOTE: 222, // needs localization - OPEN_SQUARE_BRACKET: 219, // needs localization - BACKSLASH: 220, // needs localization - CLOSE_SQUARE_BRACKET: 221, // needs localization - WIN_KEY: 224, - MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91 - MAC_WK_CMD_LEFT: 91, // WebKit Left Command key fired, same as META - MAC_WK_CMD_RIGHT: 93, // WebKit Right Command key fired, different from META - WIN_IME: 229, + /** @type {number} */ + this.width = w; - // "Reserved for future use". Some programs (e.g. the SlingPlayer 2.4 ActiveX - // control) fire this as a hacky way to disable screensavers. - VK_NONAME: 252, + /** @type {number} */ + this.height = h; +}; - // We've seen users whose machines fire this keycode at regular one - // second intervals. The common thread among these users is that - // they're all using Dell Inspiron laptops, so we suspect that this - // indicates a hardware/bios problem. - // http://en.community.dell.com/support-forums/laptop/f/3518/p/19285957/19523128.aspx - PHANTOM: 255 + +/** + * @return {!goog.math.Rect} A new copy of this Rectangle. + */ +goog.math.Rect.prototype.clone = function() { + return new goog.math.Rect(this.left, this.top, this.width, this.height); }; /** - * Returns true if the event contains a text modifying key. - * @param {goog.events.BrowserEvent} e A key event. - * @return {boolean} Whether it's a text modifying key. + * Returns a new Box object with the same position and dimensions as this + * rectangle. + * @return {!goog.math.Box} A new Box representation of this Rectangle. */ -goog.events.KeyCodes.isTextModifyingKeyEvent = function(e) { - if (e.altKey && !e.ctrlKey || - e.metaKey || - // Function keys don't generate text - e.keyCode >= goog.events.KeyCodes.F1 && - e.keyCode <= goog.events.KeyCodes.F12) { - return false; - } +goog.math.Rect.prototype.toBox = function() { + var right = this.left + this.width; + var bottom = this.top + this.height; + return new goog.math.Box(this.top, + right, + bottom, + this.left); +}; - // The following keys are quite harmless, even in combination with - // CTRL, ALT or SHIFT. - switch (e.keyCode) { - case goog.events.KeyCodes.ALT: - case goog.events.KeyCodes.CAPS_LOCK: - case goog.events.KeyCodes.CONTEXT_MENU: - case goog.events.KeyCodes.CTRL: - case goog.events.KeyCodes.DOWN: - case goog.events.KeyCodes.END: - case goog.events.KeyCodes.ESC: - case goog.events.KeyCodes.HOME: - case goog.events.KeyCodes.INSERT: - case goog.events.KeyCodes.LEFT: - case goog.events.KeyCodes.MAC_FF_META: - case goog.events.KeyCodes.META: - case goog.events.KeyCodes.NUMLOCK: - case goog.events.KeyCodes.NUM_CENTER: - case goog.events.KeyCodes.PAGE_DOWN: - case goog.events.KeyCodes.PAGE_UP: - case goog.events.KeyCodes.PAUSE: - case goog.events.KeyCodes.PHANTOM: - case goog.events.KeyCodes.PRINT_SCREEN: - case goog.events.KeyCodes.RIGHT: - case goog.events.KeyCodes.SCROLL_LOCK: - case goog.events.KeyCodes.SHIFT: - case goog.events.KeyCodes.UP: - case goog.events.KeyCodes.VK_NONAME: - case goog.events.KeyCodes.WIN_KEY: - case goog.events.KeyCodes.WIN_KEY_RIGHT: - return false; - case goog.events.KeyCodes.WIN_KEY_FF_LINUX: - return !goog.userAgent.GECKO; - default: - return e.keyCode < goog.events.KeyCodes.FIRST_MEDIA_KEY || - e.keyCode > goog.events.KeyCodes.LAST_MEDIA_KEY; - } + +/** + * Creates a new Rect object with the position and size given. + * @param {!goog.math.Coordinate} position The top-left coordinate of the Rect + * @param {!goog.math.Size} size The size of the Rect + * @return {!goog.math.Rect} A new Rect initialized with the given position and + * size. + */ +goog.math.Rect.createFromPositionAndSize = function(position, size) { + return new goog.math.Rect(position.x, position.y, size.width, size.height); }; /** - * Returns true if the key fires a keypress event in the current browser. - * - * Accoridng to MSDN [1] IE only fires keypress events for the following keys: - * - Letters: A - Z (uppercase and lowercase) - * - Numerals: 0 - 9 - * - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ - * - System: ESC, SPACEBAR, ENTER - * - * That's not entirely correct though, for instance there's no distinction - * between upper and lower case letters. - * - * [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx) - * - * Safari is similar to IE, but does not fire keypress for ESC. - * - * Additionally, IE6 does not fire keydown or keypress events for letters when - * the control or alt keys are held down and the shift key is not. IE7 does - * fire keydown in these cases, though, but not keypress. - * - * @param {number} keyCode A key code. - * @param {number=} opt_heldKeyCode Key code of a currently-held key. - * @param {boolean=} opt_shiftKey Whether the shift key is held down. - * @param {boolean=} opt_ctrlKey Whether the control key is held down. - * @param {boolean=} opt_altKey Whether the alt key is held down. - * @return {boolean} Whether it's a key that fires a keypress event. + * Creates a new Rect object with the same position and dimensions as a given + * Box. Note that this is only the inverse of toBox if left/top are defined. + * @param {goog.math.Box} box A box. + * @return {!goog.math.Rect} A new Rect initialized with the box's position + * and size. */ -goog.events.KeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode, - opt_shiftKey, opt_ctrlKey, opt_altKey) { - if (!goog.userAgent.IE && !goog.userAgent.EDGE && - !(goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'))) { - return true; - } +goog.math.Rect.createFromBox = function(box) { + return new goog.math.Rect(box.left, box.top, + box.right - box.left, box.bottom - box.top); +}; - if (goog.userAgent.MAC && opt_altKey) { - return goog.events.KeyCodes.isCharacterKey(keyCode); - } - // Alt but not AltGr which is represented as Alt+Ctrl. - if (opt_altKey && !opt_ctrlKey) { - return false; - } +if (goog.DEBUG) { + /** + * Returns a nice string representing size and dimensions of rectangle. + * @return {string} In the form (50, 73 - 75w x 25h). + * @override + */ + goog.math.Rect.prototype.toString = function() { + return '(' + this.left + ', ' + this.top + ' - ' + this.width + 'w x ' + + this.height + 'h)'; + }; +} - // Saves Ctrl or Alt + key for IE and WebKit 525+, which won't fire keypress. - // Non-IE browsers and WebKit prior to 525 won't get this far so no need to - // check the user agent. - if (goog.isNumber(opt_heldKeyCode)) { - opt_heldKeyCode = goog.events.KeyCodes.normalizeKeyCode(opt_heldKeyCode); - } - if (!opt_shiftKey && - (opt_heldKeyCode == goog.events.KeyCodes.CTRL || - opt_heldKeyCode == goog.events.KeyCodes.ALT || - goog.userAgent.MAC && - opt_heldKeyCode == goog.events.KeyCodes.META)) { - return false; - } - // Some keys with Ctrl/Shift do not issue keypress in WEBKIT. - if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && - opt_ctrlKey && opt_shiftKey) { - switch (keyCode) { - case goog.events.KeyCodes.BACKSLASH: - case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: - case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: - case goog.events.KeyCodes.TILDE: - case goog.events.KeyCodes.SEMICOLON: - case goog.events.KeyCodes.DASH: - case goog.events.KeyCodes.EQUALS: - case goog.events.KeyCodes.COMMA: - case goog.events.KeyCodes.PERIOD: - case goog.events.KeyCodes.SLASH: - case goog.events.KeyCodes.APOSTROPHE: - case goog.events.KeyCodes.SINGLE_QUOTE: - return false; - } +/** + * Compares rectangles for equality. + * @param {goog.math.Rect} a A Rectangle. + * @param {goog.math.Rect} b A Rectangle. + * @return {boolean} True iff the rectangles have the same left, top, width, + * and height, or if both are null. + */ +goog.math.Rect.equals = function(a, b) { + if (a == b) { + return true; } - - // When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it - // continues to fire keydown events as the event repeats. - if (goog.userAgent.IE && opt_ctrlKey && opt_heldKeyCode == keyCode) { + if (!a || !b) { return false; } - - switch (keyCode) { - case goog.events.KeyCodes.ENTER: - return true; - case goog.events.KeyCodes.ESC: - return !(goog.userAgent.WEBKIT || goog.userAgent.EDGE); - } - - return goog.events.KeyCodes.isCharacterKey(keyCode); + return a.left == b.left && a.width == b.width && + a.top == b.top && a.height == b.height; }; /** - * Returns true if the key produces a character. - * This does not cover characters on non-US keyboards (Russian, Hebrew, etc.). - * - * @param {number} keyCode A key code. - * @return {boolean} Whether it's a character key. + * Computes the intersection of this rectangle and the rectangle parameter. If + * there is no intersection, returns false and leaves this rectangle as is. + * @param {goog.math.Rect} rect A Rectangle. + * @return {boolean} True iff this rectangle intersects with the parameter. */ -goog.events.KeyCodes.isCharacterKey = function(keyCode) { - if (keyCode >= goog.events.KeyCodes.ZERO && - keyCode <= goog.events.KeyCodes.NINE) { - return true; - } - - if (keyCode >= goog.events.KeyCodes.NUM_ZERO && - keyCode <= goog.events.KeyCodes.NUM_MULTIPLY) { - return true; - } +goog.math.Rect.prototype.intersection = function(rect) { + var x0 = Math.max(this.left, rect.left); + var x1 = Math.min(this.left + this.width, rect.left + rect.width); - if (keyCode >= goog.events.KeyCodes.A && - keyCode <= goog.events.KeyCodes.Z) { - return true; - } + if (x0 <= x1) { + var y0 = Math.max(this.top, rect.top); + var y1 = Math.min(this.top + this.height, rect.top + rect.height); - // Safari sends zero key code for non-latin characters. - if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && keyCode == 0) { - return true; - } + if (y0 <= y1) { + this.left = x0; + this.top = y0; + this.width = x1 - x0; + this.height = y1 - y0; - switch (keyCode) { - case goog.events.KeyCodes.SPACE: - case goog.events.KeyCodes.PLUS_SIGN: - case goog.events.KeyCodes.QUESTION_MARK: - case goog.events.KeyCodes.AT_SIGN: - case goog.events.KeyCodes.NUM_PLUS: - case goog.events.KeyCodes.NUM_MINUS: - case goog.events.KeyCodes.NUM_PERIOD: - case goog.events.KeyCodes.NUM_DIVISION: - case goog.events.KeyCodes.SEMICOLON: - case goog.events.KeyCodes.FF_SEMICOLON: - case goog.events.KeyCodes.DASH: - case goog.events.KeyCodes.EQUALS: - case goog.events.KeyCodes.FF_EQUALS: - case goog.events.KeyCodes.COMMA: - case goog.events.KeyCodes.PERIOD: - case goog.events.KeyCodes.SLASH: - case goog.events.KeyCodes.APOSTROPHE: - case goog.events.KeyCodes.SINGLE_QUOTE: - case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: - case goog.events.KeyCodes.BACKSLASH: - case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: return true; - default: - return false; + } } + return false; }; /** - * Normalizes key codes from OS/Browser-specific value to the general one. - * @param {number} keyCode The native key code. - * @return {number} The normalized key code. + * Returns the intersection of two rectangles. Two rectangles intersect if they + * touch at all, for example, two zero width and height rectangles would + * intersect if they had the same top and left. + * @param {goog.math.Rect} a A Rectangle. + * @param {goog.math.Rect} b A Rectangle. + * @return {goog.math.Rect} A new intersection rect (even if width and height + * are 0), or null if there is no intersection. */ -goog.events.KeyCodes.normalizeKeyCode = function(keyCode) { - if (goog.userAgent.GECKO) { - return goog.events.KeyCodes.normalizeGeckoKeyCode(keyCode); - } else if (goog.userAgent.MAC && goog.userAgent.WEBKIT) { - return goog.events.KeyCodes.normalizeMacWebKitKeyCode(keyCode); - } else { - return keyCode; +goog.math.Rect.intersection = function(a, b) { + // There is no nice way to do intersection via a clone, because any such + // clone might be unnecessary if this function returns null. So, we duplicate + // code from above. + + var x0 = Math.max(a.left, b.left); + var x1 = Math.min(a.left + a.width, b.left + b.width); + + if (x0 <= x1) { + var y0 = Math.max(a.top, b.top); + var y1 = Math.min(a.top + a.height, b.top + b.height); + + if (y0 <= y1) { + return new goog.math.Rect(x0, y0, x1 - x0, y1 - y0); + } } + return null; }; /** - * Normalizes key codes from their Gecko-specific value to the general one. - * @param {number} keyCode The native key code. - * @return {number} The normalized key code. + * Returns whether two rectangles intersect. Two rectangles intersect if they + * touch at all, for example, two zero width and height rectangles would + * intersect if they had the same top and left. + * @param {goog.math.Rect} a A Rectangle. + * @param {goog.math.Rect} b A Rectangle. + * @return {boolean} Whether a and b intersect. */ -goog.events.KeyCodes.normalizeGeckoKeyCode = function(keyCode) { - switch (keyCode) { - case goog.events.KeyCodes.FF_EQUALS: - return goog.events.KeyCodes.EQUALS; - case goog.events.KeyCodes.FF_SEMICOLON: - return goog.events.KeyCodes.SEMICOLON; - case goog.events.KeyCodes.FF_DASH: - return goog.events.KeyCodes.DASH; - case goog.events.KeyCodes.MAC_FF_META: - return goog.events.KeyCodes.META; - case goog.events.KeyCodes.WIN_KEY_FF_LINUX: - return goog.events.KeyCodes.WIN_KEY; - default: - return keyCode; - } +goog.math.Rect.intersects = function(a, b) { + return (a.left <= b.left + b.width && b.left <= a.left + a.width && + a.top <= b.top + b.height && b.top <= a.top + a.height); }; /** - * Normalizes key codes from their Mac WebKit-specific value to the general one. - * @param {number} keyCode The native key code. - * @return {number} The normalized key code. + * Returns whether a rectangle intersects this rectangle. + * @param {goog.math.Rect} rect A rectangle. + * @return {boolean} Whether rect intersects this rectangle. */ -goog.events.KeyCodes.normalizeMacWebKitKeyCode = function(keyCode) { - switch (keyCode) { - case goog.events.KeyCodes.MAC_WK_CMD_RIGHT: // 93 - return goog.events.KeyCodes.META; // 91 - default: - return keyCode; - } +goog.math.Rect.prototype.intersects = function(rect) { + return goog.math.Rect.intersects(this, rect); }; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview This file contains a class for working with keyboard events - * that repeat consistently across browsers and platforms. It also unifies the - * key code so that it is the same in all browsers and platforms. - * - * Different web browsers have very different keyboard event handling. Most - * importantly is that only certain browsers repeat keydown events: - * IE, Opera, FF/Win32, and Safari 3 repeat keydown events. - * FF/Mac and Safari 2 do not. - * - * For the purposes of this code, "Safari 3" means WebKit 525+, when WebKit - * decided that they should try to match IE's key handling behavior. - * Safari 3.0.4, which shipped with Leopard (WebKit 523), has the - * Safari 2 behavior. - * - * Firefox, Safari, Opera prevent on keypress - * - * IE prevents on keydown - * - * Firefox does not fire keypress for shift, ctrl, alt - * Firefox does fire keydown for shift, ctrl, alt, meta - * Firefox does not repeat keydown for shift, ctrl, alt, meta - * - * Firefox does not fire keypress for up and down in an input - * - * Opera fires keypress for shift, ctrl, alt, meta - * Opera does not repeat keypress for shift, ctrl, alt, meta - * - * Safari 2 and 3 do not fire keypress for shift, ctrl, alt - * Safari 2 does not fire keydown for shift, ctrl, alt - * Safari 3 *does* fire keydown for shift, ctrl, alt - * - * IE provides the keycode for keyup/down events and the charcode (in the - * keycode field) for keypress. - * - * Mozilla provides the keycode for keyup/down and the charcode for keypress - * unless it's a non text modifying key in which case the keycode is provided. - * - * Safari 3 provides the keycode and charcode for all events. - * - * Opera provides the keycode for keyup/down event and either the charcode or - * the keycode (in the keycode field) for keypress events. - * - * Firefox x11 doesn't fire keydown events if a another key is already held down - * until the first key is released. This can cause a key event to be fired with - * a keyCode for the first key and a charCode for the second key. - * - * Safari in keypress - * - * charCode keyCode which - * ENTER: 13 13 13 - * F1: 63236 63236 63236 - * F8: 63243 63243 63243 - * ... - * p: 112 112 112 - * P: 80 80 80 - * - * Firefox, keypress: - * - * charCode keyCode which - * ENTER: 0 13 13 - * F1: 0 112 0 - * F8: 0 119 0 - * ... - * p: 112 0 112 - * P: 80 0 80 - * - * Opera, Mac+Win32, keypress: - * - * charCode keyCode which - * ENTER: undefined 13 13 - * F1: undefined 112 0 - * F8: undefined 119 0 - * ... - * p: undefined 112 112 - * P: undefined 80 80 - * - * IE7, keydown - * - * charCode keyCode which - * ENTER: undefined 13 undefined - * F1: undefined 112 undefined - * F8: undefined 119 undefined - * ... - * p: undefined 80 undefined - * P: undefined 80 undefined - * - * @author arv@google.com (Erik Arvidsson) - * @author eae@google.com (Emil A Eklund) - * @see ../demos/keyhandler.html + * Computes the difference regions between two rectangles. The return value is + * an array of 0 to 4 rectangles defining the remaining regions of the first + * rectangle after the second has been subtracted. + * @param {goog.math.Rect} a A Rectangle. + * @param {goog.math.Rect} b A Rectangle. + * @return {!Array<!goog.math.Rect>} An array with 0 to 4 rectangles which + * together define the difference area of rectangle a minus rectangle b. */ +goog.math.Rect.difference = function(a, b) { + var intersection = goog.math.Rect.intersection(a, b); + if (!intersection || !intersection.height || !intersection.width) { + return [a.clone()]; + } -goog.provide('goog.events.KeyEvent'); -goog.provide('goog.events.KeyHandler'); -goog.provide('goog.events.KeyHandler.EventType'); - -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.events.KeyCodes'); -goog.require('goog.userAgent'); + var result = []; + var top = a.top; + var height = a.height; + var ar = a.left + a.width; + var ab = a.top + a.height; -/** - * A wrapper around an element that you want to listen to keyboard events on. - * @param {Element|Document=} opt_element The element or document to listen on. - * @param {boolean=} opt_capture Whether to listen for browser events in - * capture phase (defaults to false). - * @constructor - * @extends {goog.events.EventTarget} - * @final - */ -goog.events.KeyHandler = function(opt_element, opt_capture) { - goog.events.EventTarget.call(this); + var br = b.left + b.width; + var bb = b.top + b.height; - if (opt_element) { - this.attach(opt_element, opt_capture); + // Subtract off any area on top where A extends past B + if (b.top > a.top) { + result.push(new goog.math.Rect(a.left, a.top, a.width, b.top - a.top)); + top = b.top; + // If we're moving the top down, we also need to subtract the height diff. + height -= b.top - a.top; + } + // Subtract off any area on bottom where A extends past B + if (bb < ab) { + result.push(new goog.math.Rect(a.left, bb, a.width, ab - bb)); + height = bb - top; + } + // Subtract any area on left where A extends past B + if (b.left > a.left) { + result.push(new goog.math.Rect(a.left, top, b.left - a.left, height)); + } + // Subtract any area on right where A extends past B + if (br < ar) { + result.push(new goog.math.Rect(br, top, ar - br, height)); } + + return result; }; -goog.inherits(goog.events.KeyHandler, goog.events.EventTarget); /** - * This is the element that we will listen to the real keyboard events on. - * @type {Element|Document|null} - * @private + * Computes the difference regions between this rectangle and {@code rect}. The + * return value is an array of 0 to 4 rectangles defining the remaining regions + * of this rectangle after the other has been subtracted. + * @param {goog.math.Rect} rect A Rectangle. + * @return {!Array<!goog.math.Rect>} An array with 0 to 4 rectangles which + * together define the difference area of rectangle a minus rectangle b. */ -goog.events.KeyHandler.prototype.element_ = null; +goog.math.Rect.prototype.difference = function(rect) { + return goog.math.Rect.difference(this, rect); +}; /** - * The key for the key press listener. - * @type {goog.events.Key} - * @private + * Expand this rectangle to also include the area of the given rectangle. + * @param {goog.math.Rect} rect The other rectangle. */ -goog.events.KeyHandler.prototype.keyPressKey_ = null; +goog.math.Rect.prototype.boundingRect = function(rect) { + // We compute right and bottom before we change left and top below. + var right = Math.max(this.left + this.width, rect.left + rect.width); + var bottom = Math.max(this.top + this.height, rect.top + rect.height); + this.left = Math.min(this.left, rect.left); + this.top = Math.min(this.top, rect.top); -/** - * The key for the key down listener. - * @type {goog.events.Key} - * @private - */ -goog.events.KeyHandler.prototype.keyDownKey_ = null; + this.width = right - this.left; + this.height = bottom - this.top; +}; /** - * The key for the key up listener. - * @type {goog.events.Key} - * @private + * Returns a new rectangle which completely contains both input rectangles. + * @param {goog.math.Rect} a A rectangle. + * @param {goog.math.Rect} b A rectangle. + * @return {goog.math.Rect} A new bounding rect, or null if either rect is + * null. */ -goog.events.KeyHandler.prototype.keyUpKey_ = null; +goog.math.Rect.boundingRect = function(a, b) { + if (!a || !b) { + return null; + } + var clone = a.clone(); + clone.boundingRect(b); -/** - * Used to detect keyboard repeat events. - * @private - * @type {number} - */ -goog.events.KeyHandler.prototype.lastKey_ = -1; + return clone; +}; /** - * Keycode recorded for key down events. As most browsers don't report the - * keycode in the key press event we need to record it in the key down phase. - * @private - * @type {number} + * Tests whether this rectangle entirely contains another rectangle or + * coordinate. + * + * @param {goog.math.Rect|goog.math.Coordinate} another The rectangle or + * coordinate to test for containment. + * @return {boolean} Whether this rectangle contains given rectangle or + * coordinate. */ -goog.events.KeyHandler.prototype.keyCode_ = -1; +goog.math.Rect.prototype.contains = function(another) { + if (another instanceof goog.math.Rect) { + return this.left <= another.left && + this.left + this.width >= another.left + another.width && + this.top <= another.top && + this.top + this.height >= another.top + another.height; + } else { // (another instanceof goog.math.Coordinate) + return another.x >= this.left && + another.x <= this.left + this.width && + another.y >= this.top && + another.y <= this.top + this.height; + } +}; /** - * Alt key recorded for key down events. FF on Mac does not report the alt key - * flag in the key press event, we need to record it in the key down phase. - * @type {boolean} - * @private + * @param {!goog.math.Coordinate} point A coordinate. + * @return {number} The squared distance between the point and the closest + * point inside the rectangle. Returns 0 if the point is inside the + * rectangle. */ -goog.events.KeyHandler.prototype.altKey_ = false; +goog.math.Rect.prototype.squaredDistance = function(point) { + var dx = point.x < this.left ? + this.left - point.x : Math.max(point.x - (this.left + this.width), 0); + var dy = point.y < this.top ? + this.top - point.y : Math.max(point.y - (this.top + this.height), 0); + return dx * dx + dy * dy; +}; /** - * Enum type for the events fired by the key handler - * @enum {string} - */ -goog.events.KeyHandler.EventType = { - KEY: 'key' -}; - - -/** - * An enumeration of key codes that Safari 2 does incorrectly - * @type {Object} - * @private + * @param {!goog.math.Coordinate} point A coordinate. + * @return {number} The distance between the point and the closest point + * inside the rectangle. Returns 0 if the point is inside the rectangle. */ -goog.events.KeyHandler.safariKey_ = { - '3': goog.events.KeyCodes.ENTER, // 13 - '12': goog.events.KeyCodes.NUMLOCK, // 144 - '63232': goog.events.KeyCodes.UP, // 38 - '63233': goog.events.KeyCodes.DOWN, // 40 - '63234': goog.events.KeyCodes.LEFT, // 37 - '63235': goog.events.KeyCodes.RIGHT, // 39 - '63236': goog.events.KeyCodes.F1, // 112 - '63237': goog.events.KeyCodes.F2, // 113 - '63238': goog.events.KeyCodes.F3, // 114 - '63239': goog.events.KeyCodes.F4, // 115 - '63240': goog.events.KeyCodes.F5, // 116 - '63241': goog.events.KeyCodes.F6, // 117 - '63242': goog.events.KeyCodes.F7, // 118 - '63243': goog.events.KeyCodes.F8, // 119 - '63244': goog.events.KeyCodes.F9, // 120 - '63245': goog.events.KeyCodes.F10, // 121 - '63246': goog.events.KeyCodes.F11, // 122 - '63247': goog.events.KeyCodes.F12, // 123 - '63248': goog.events.KeyCodes.PRINT_SCREEN, // 44 - '63272': goog.events.KeyCodes.DELETE, // 46 - '63273': goog.events.KeyCodes.HOME, // 36 - '63275': goog.events.KeyCodes.END, // 35 - '63276': goog.events.KeyCodes.PAGE_UP, // 33 - '63277': goog.events.KeyCodes.PAGE_DOWN, // 34 - '63289': goog.events.KeyCodes.NUMLOCK, // 144 - '63302': goog.events.KeyCodes.INSERT // 45 +goog.math.Rect.prototype.distance = function(point) { + return Math.sqrt(this.squaredDistance(point)); }; /** - * An enumeration of key identifiers currently part of the W3C draft for DOM3 - * and their mappings to keyCodes. - * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set - * This is currently supported in Safari and should be platform independent. - * @type {Object} - * @private + * @return {!goog.math.Size} The size of this rectangle. */ -goog.events.KeyHandler.keyIdentifier_ = { - 'Up': goog.events.KeyCodes.UP, // 38 - 'Down': goog.events.KeyCodes.DOWN, // 40 - 'Left': goog.events.KeyCodes.LEFT, // 37 - 'Right': goog.events.KeyCodes.RIGHT, // 39 - 'Enter': goog.events.KeyCodes.ENTER, // 13 - 'F1': goog.events.KeyCodes.F1, // 112 - 'F2': goog.events.KeyCodes.F2, // 113 - 'F3': goog.events.KeyCodes.F3, // 114 - 'F4': goog.events.KeyCodes.F4, // 115 - 'F5': goog.events.KeyCodes.F5, // 116 - 'F6': goog.events.KeyCodes.F6, // 117 - 'F7': goog.events.KeyCodes.F7, // 118 - 'F8': goog.events.KeyCodes.F8, // 119 - 'F9': goog.events.KeyCodes.F9, // 120 - 'F10': goog.events.KeyCodes.F10, // 121 - 'F11': goog.events.KeyCodes.F11, // 122 - 'F12': goog.events.KeyCodes.F12, // 123 - 'U+007F': goog.events.KeyCodes.DELETE, // 46 - 'Home': goog.events.KeyCodes.HOME, // 36 - 'End': goog.events.KeyCodes.END, // 35 - 'PageUp': goog.events.KeyCodes.PAGE_UP, // 33 - 'PageDown': goog.events.KeyCodes.PAGE_DOWN, // 34 - 'Insert': goog.events.KeyCodes.INSERT // 45 +goog.math.Rect.prototype.getSize = function() { + return new goog.math.Size(this.width, this.height); }; /** - * If true, the KeyEvent fires on keydown. Otherwise, it fires on keypress. - * - * @type {boolean} - * @private - */ -goog.events.KeyHandler.USES_KEYDOWN_ = goog.userAgent.IE || - goog.userAgent.EDGE || - goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'); - - -/** - * If true, the alt key flag is saved during the key down and reused when - * handling the key press. FF on Mac does not set the alt flag in the key press - * event. - * @type {boolean} - * @private - */ -goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_ = goog.userAgent.MAC && - goog.userAgent.GECKO; - - -/** - * Records the keycode for browsers that only returns the keycode for key up/ - * down events. For browser/key combinations that doesn't trigger a key pressed - * event it also fires the patched key event. - * @param {goog.events.BrowserEvent} e The key down event. - * @private + * @return {!goog.math.Coordinate} A new coordinate for the top-left corner of + * the rectangle. */ -goog.events.KeyHandler.prototype.handleKeyDown_ = function(e) { - // Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window - // before we've caught a key-up event. If the last-key was one of these we - // reset the state. - if (goog.userAgent.WEBKIT || goog.userAgent.EDGE) { - if (this.lastKey_ == goog.events.KeyCodes.CTRL && !e.ctrlKey || - this.lastKey_ == goog.events.KeyCodes.ALT && !e.altKey || - goog.userAgent.MAC && - this.lastKey_ == goog.events.KeyCodes.META && !e.metaKey) { - this.resetState(); - } - } - - if (this.lastKey_ == -1) { - if (e.ctrlKey && e.keyCode != goog.events.KeyCodes.CTRL) { - this.lastKey_ = goog.events.KeyCodes.CTRL; - } else if (e.altKey && e.keyCode != goog.events.KeyCodes.ALT) { - this.lastKey_ = goog.events.KeyCodes.ALT; - } else if (e.metaKey && e.keyCode != goog.events.KeyCodes.META) { - this.lastKey_ = goog.events.KeyCodes.META; - } - } - - if (goog.events.KeyHandler.USES_KEYDOWN_ && - !goog.events.KeyCodes.firesKeyPressEvent(e.keyCode, - this.lastKey_, e.shiftKey, e.ctrlKey, e.altKey)) { - this.handleEvent(e); - } else { - this.keyCode_ = goog.events.KeyCodes.normalizeKeyCode(e.keyCode); - if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) { - this.altKey_ = e.altKey; - } - } +goog.math.Rect.prototype.getTopLeft = function() { + return new goog.math.Coordinate(this.left, this.top); }; /** - * Resets the stored previous values. Needed to be called for webkit which will - * not generate a key up for meta key operations. This should only be called - * when having finished with repeat key possiblities. + * @return {!goog.math.Coordinate} A new coordinate for the center of the + * rectangle. */ -goog.events.KeyHandler.prototype.resetState = function() { - this.lastKey_ = -1; - this.keyCode_ = -1; +goog.math.Rect.prototype.getCenter = function() { + return new goog.math.Coordinate( + this.left + this.width / 2, this.top + this.height / 2); }; /** - * Clears the stored previous key value, resetting the key repeat status. Uses - * -1 because the Safari 3 Windows beta reports 0 for certain keys (like Home - * and End.) - * @param {goog.events.BrowserEvent} e The keyup event. - * @private + * @return {!goog.math.Coordinate} A new coordinate for the bottom-right corner + * of the rectangle. */ -goog.events.KeyHandler.prototype.handleKeyup_ = function(e) { - this.resetState(); - this.altKey_ = e.altKey; +goog.math.Rect.prototype.getBottomRight = function() { + return new goog.math.Coordinate( + this.left + this.width, this.top + this.height); }; /** - * Handles the events on the element. - * @param {goog.events.BrowserEvent} e The keyboard event sent from the - * browser. + * Rounds the fields to the next larger integer values. + * @return {!goog.math.Rect} This rectangle with ceil'd fields. */ -goog.events.KeyHandler.prototype.handleEvent = function(e) { - var be = e.getBrowserEvent(); - var keyCode, charCode; - var altKey = be.altKey; - - // IE reports the character code in the keyCode field for keypress events. - // There are two exceptions however, Enter and Escape. - if (goog.userAgent.IE && e.type == goog.events.EventType.KEYPRESS) { - keyCode = this.keyCode_; - charCode = keyCode != goog.events.KeyCodes.ENTER && - keyCode != goog.events.KeyCodes.ESC ? - be.keyCode : 0; - - // Safari reports the character code in the keyCode field for keypress - // events but also has a charCode field. - } else if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && - e.type == goog.events.EventType.KEYPRESS) { - keyCode = this.keyCode_; - charCode = be.charCode >= 0 && be.charCode < 63232 && - goog.events.KeyCodes.isCharacterKey(keyCode) ? - be.charCode : 0; - - // Opera reports the keycode or the character code in the keyCode field. - } else if (goog.userAgent.OPERA && !goog.userAgent.WEBKIT) { - keyCode = this.keyCode_; - charCode = goog.events.KeyCodes.isCharacterKey(keyCode) ? - be.keyCode : 0; - - // Mozilla reports the character code in the charCode field. - } else { - keyCode = be.keyCode || this.keyCode_; - charCode = be.charCode || 0; - if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) { - altKey = this.altKey_; - } - // On the Mac, shift-/ triggers a question mark char code and no key code - // (normalized to WIN_KEY), so we synthesize the latter. - if (goog.userAgent.MAC && - charCode == goog.events.KeyCodes.QUESTION_MARK && - keyCode == goog.events.KeyCodes.WIN_KEY) { - keyCode = goog.events.KeyCodes.SLASH; - } - } - - keyCode = goog.events.KeyCodes.normalizeKeyCode(keyCode); - var key = keyCode; - var keyIdentifier = be.keyIdentifier; - - // Correct the key value for certain browser-specific quirks. - if (keyCode) { - if (keyCode >= 63232 && keyCode in goog.events.KeyHandler.safariKey_) { - // NOTE(nicksantos): Safari 3 has fixed this problem, - // this is only needed for Safari 2. - key = goog.events.KeyHandler.safariKey_[keyCode]; - } else { - - // Safari returns 25 for Shift+Tab instead of 9. - if (keyCode == 25 && e.shiftKey) { - key = 9; - } - } - } else if (keyIdentifier && - keyIdentifier in goog.events.KeyHandler.keyIdentifier_) { - // This is needed for Safari Windows because it currently doesn't give a - // keyCode/which for non printable keys. - key = goog.events.KeyHandler.keyIdentifier_[keyIdentifier]; - } - - // If we get the same keycode as a keydown/keypress without having seen a - // keyup event, then this event was caused by key repeat. - var repeat = key == this.lastKey_; - this.lastKey_ = key; - - var event = new goog.events.KeyEvent(key, charCode, repeat, be); - event.altKey = altKey; - this.dispatchEvent(event); +goog.math.Rect.prototype.ceil = function() { + this.left = Math.ceil(this.left); + this.top = Math.ceil(this.top); + this.width = Math.ceil(this.width); + this.height = Math.ceil(this.height); + return this; }; /** - * Returns the element listened on for the real keyboard events. - * @return {Element|Document|null} The element listened on for the real - * keyboard events. + * Rounds the fields to the next smaller integer values. + * @return {!goog.math.Rect} This rectangle with floored fields. */ -goog.events.KeyHandler.prototype.getElement = function() { - return this.element_; +goog.math.Rect.prototype.floor = function() { + this.left = Math.floor(this.left); + this.top = Math.floor(this.top); + this.width = Math.floor(this.width); + this.height = Math.floor(this.height); + return this; }; /** - * Adds the proper key event listeners to the element. - * @param {Element|Document} element The element to listen on. - * @param {boolean=} opt_capture Whether to listen for browser events in - * capture phase (defaults to false). + * Rounds the fields to nearest integer values. + * @return {!goog.math.Rect} This rectangle with rounded fields. */ -goog.events.KeyHandler.prototype.attach = function(element, opt_capture) { - if (this.keyUpKey_) { - this.detach(); - } - - this.element_ = element; - - this.keyPressKey_ = goog.events.listen(this.element_, - goog.events.EventType.KEYPRESS, - this, - opt_capture); - - // Most browsers (Safari 2 being the notable exception) doesn't include the - // keyCode in keypress events (IE has the char code in the keyCode field and - // Mozilla only included the keyCode if there's no charCode). Thus we have to - // listen for keydown to capture the keycode. - this.keyDownKey_ = goog.events.listen(this.element_, - goog.events.EventType.KEYDOWN, - this.handleKeyDown_, - opt_capture, - this); - - - this.keyUpKey_ = goog.events.listen(this.element_, - goog.events.EventType.KEYUP, - this.handleKeyup_, - opt_capture, - this); +goog.math.Rect.prototype.round = function() { + this.left = Math.round(this.left); + this.top = Math.round(this.top); + this.width = Math.round(this.width); + this.height = Math.round(this.height); + return this; }; /** - * Removes the listeners that may exist. + * Translates this rectangle by the given offsets. If a + * {@code goog.math.Coordinate} is given, then the left and top values are + * translated by the coordinate's x and y values. Otherwise, top and left are + * translated by {@code tx} and {@code opt_ty} respectively. + * @param {number|goog.math.Coordinate} tx The value to translate left by or the + * the coordinate to translate this rect by. + * @param {number=} opt_ty The value to translate top by. + * @return {!goog.math.Rect} This rectangle after translating. */ -goog.events.KeyHandler.prototype.detach = function() { - if (this.keyPressKey_) { - goog.events.unlistenByKey(this.keyPressKey_); - goog.events.unlistenByKey(this.keyDownKey_); - goog.events.unlistenByKey(this.keyUpKey_); - this.keyPressKey_ = null; - this.keyDownKey_ = null; - this.keyUpKey_ = null; +goog.math.Rect.prototype.translate = function(tx, opt_ty) { + if (tx instanceof goog.math.Coordinate) { + this.left += tx.x; + this.top += tx.y; + } else { + this.left += tx; + if (goog.isNumber(opt_ty)) { + this.top += opt_ty; + } } - this.element_ = null; - this.lastKey_ = -1; - this.keyCode_ = -1; -}; - - -/** @override */ -goog.events.KeyHandler.prototype.disposeInternal = function() { - goog.events.KeyHandler.superClass_.disposeInternal.call(this); - this.detach(); + return this; }; - /** - * This class is used for the goog.events.KeyHandler.EventType.KEY event and - * it overrides the key code with the fixed key code. - * @param {number} keyCode The adjusted key code. - * @param {number} charCode The unicode character code. - * @param {boolean} repeat Whether this event was generated by keyboard repeat. - * @param {Event} browserEvent Browser event object. - * @constructor - * @extends {goog.events.BrowserEvent} - * @final + * Scales this rectangle by the given scale factors. The left and width values + * are scaled by {@code sx} and the top and height values are scaled by + * {@code opt_sy}. If {@code opt_sy} is not given, then all fields are scaled + * by {@code sx}. + * @param {number} sx The scale factor to use for the x dimension. + * @param {number=} opt_sy The scale factor to use for the y dimension. + * @return {!goog.math.Rect} This rectangle after scaling. */ -goog.events.KeyEvent = function(keyCode, charCode, repeat, browserEvent) { - goog.events.BrowserEvent.call(this, browserEvent); - this.type = goog.events.KeyHandler.EventType.KEY; - - /** - * Keycode of key press. - * @type {number} - */ - this.keyCode = keyCode; - - /** - * Unicode character code. - * @type {number} - */ - this.charCode = charCode; - - /** - * True if this event was generated by keyboard auto-repeat (i.e., the user is - * holding the key down.) - * @type {boolean} - */ - this.repeat = repeat; +goog.math.Rect.prototype.scale = function(sx, opt_sy) { + var sy = goog.isNumber(opt_sy) ? opt_sy : sx; + this.left *= sx; + this.width *= sx; + this.top *= sy; + this.height *= sy; + return this; }; -goog.inherits(goog.events.KeyEvent, goog.events.BrowserEvent); // Copyright 2006 The Closure Library Authors. All Rights Reserved. // @@ -48626,9700 +47356,10511 @@ goog.inherits(goog.events.KeyEvent, goog.events.BrowserEvent); // limitations under the License. /** - * @fileoverview This event wrapper will dispatch an event when the user uses - * the mouse wheel to scroll an element. You can get the direction by checking - * the deltaX and deltaY properties of the event. - * - * This class aims to smooth out inconsistencies between browser platforms with - * regards to mousewheel events, but we do not cover every possible - * software/hardware combination out there, some of which occasionally produce - * very large deltas in mousewheel events. If your application wants to guard - * against extremely large deltas, use the setMaxDeltaX and setMaxDeltaY APIs - * to set maximum values that make sense for your application. + * @fileoverview Utilities for element styles. * * @author arv@google.com (Erik Arvidsson) - * @see ../demos/mousewheelhandler.html + * @author eae@google.com (Emil A Eklund) + * @see ../demos/inline_block_quirks.html + * @see ../demos/inline_block_standards.html + * @see ../demos/style_viewport.html */ -goog.provide('goog.events.MouseWheelEvent'); -goog.provide('goog.events.MouseWheelHandler'); -goog.provide('goog.events.MouseWheelHandler.EventType'); +goog.provide('goog.style'); + +goog.require('goog.array'); +goog.require('goog.asserts'); goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); -goog.require('goog.math'); -goog.require('goog.style'); +goog.require('goog.dom.NodeType'); +goog.require('goog.dom.TagName'); +goog.require('goog.dom.vendor'); +goog.require('goog.math.Box'); +goog.require('goog.math.Coordinate'); +goog.require('goog.math.Rect'); +goog.require('goog.math.Size'); +goog.require('goog.object'); +goog.require('goog.string'); goog.require('goog.userAgent'); +goog.forwardDeclare('goog.events.BrowserEvent'); +goog.forwardDeclare('goog.events.Event'); /** - * This event handler allows you to catch mouse wheel events in a consistent - * manner. - * @param {Element|Document} element The element to listen to the mouse wheel - * event on. - * @param {boolean=} opt_capture Whether to handle the mouse wheel event in - * capture phase. - * @constructor - * @extends {goog.events.EventTarget} + * Sets a style value on an element. + * + * This function is not indended to patch issues in the browser's style + * handling, but to allow easy programmatic access to setting dash-separated + * style properties. An example is setting a batch of properties from a data + * object without overwriting old styles. When possible, use native APIs: + * elem.style.propertyKey = 'value' or (if obliterating old styles is fine) + * elem.style.cssText = 'property1: value1; property2: value2'. + * + * @param {Element} element The element to change. + * @param {string|Object} style If a string, a style name. If an object, a hash + * of style names to style values. + * @param {string|number|boolean=} opt_value If style was a string, then this + * should be the value. */ -goog.events.MouseWheelHandler = function(element, opt_capture) { - goog.events.EventTarget.call(this); - - /** - * This is the element that we will listen to the real mouse wheel events on. - * @type {Element|Document} - * @private - */ - this.element_ = element; - - var rtlElement = goog.dom.isElement(this.element_) ? - /** @type {Element} */ (this.element_) : - (this.element_ ? /** @type {Document} */ (this.element_).body : null); +goog.style.setStyle = function(element, style, opt_value) { + if (goog.isString(style)) { + goog.style.setStyle_(element, opt_value, style); + } else { + for (var key in style) { + goog.style.setStyle_(element, style[key], key); + } + } +}; - /** - * True if the element exists and is RTL, false otherwise. - * @type {boolean} - * @private - */ - this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement); - var type = goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel'; +/** + * Sets a style value on an element, with parameters swapped to work with + * {@code goog.object.forEach()}. Prepends a vendor-specific prefix when + * necessary. + * @param {Element} element The element to change. + * @param {string|number|boolean|undefined} value Style value. + * @param {string} style Style name. + * @private + */ +goog.style.setStyle_ = function(element, value, style) { + var propertyName = goog.style.getVendorJsStyleName_(element, style); - /** - * The key returned from the goog.events.listen. - * @type {goog.events.Key} - * @private - */ - this.listenKey_ = goog.events.listen(this.element_, type, this, opt_capture); + if (propertyName) { + element.style[propertyName] = value; + } }; -goog.inherits(goog.events.MouseWheelHandler, goog.events.EventTarget); /** - * Enum type for the events fired by the mouse wheel handler. - * @enum {string} + * Style name cache that stores previous property name lookups. + * + * This is used by setStyle to speed up property lookups, entries look like: + * { StyleName: ActualPropertyName } + * + * @private {!Object<string, string>} */ -goog.events.MouseWheelHandler.EventType = { - MOUSEWHEEL: 'mousewheel' -}; +goog.style.styleNameCache_ = {}; /** - * Optional maximum magnitude for x delta on each mousewheel event. - * @type {number|undefined} + * Returns the style property name in camel-case. If it does not exist and a + * vendor-specific version of the property does exist, then return the vendor- + * specific property name instead. + * @param {Element} element The element to change. + * @param {string} style Style name. + * @return {string} Vendor-specific style. * @private */ -goog.events.MouseWheelHandler.prototype.maxDeltaX_; - +goog.style.getVendorJsStyleName_ = function(element, style) { + var propertyName = goog.style.styleNameCache_[style]; + if (!propertyName) { + var camelStyle = goog.string.toCamelCase(style); + propertyName = camelStyle; -/** - * Optional maximum magnitude for y delta on each mousewheel event. - * @type {number|undefined} - * @private - */ -goog.events.MouseWheelHandler.prototype.maxDeltaY_; + if (element.style[camelStyle] === undefined) { + var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() + + goog.string.toTitleCase(camelStyle); + if (element.style[prefixedStyle] !== undefined) { + propertyName = prefixedStyle; + } + } + goog.style.styleNameCache_[style] = propertyName; + } -/** - * @param {number} maxDeltaX Maximum magnitude for x delta on each mousewheel - * event. Should be non-negative. - */ -goog.events.MouseWheelHandler.prototype.setMaxDeltaX = function(maxDeltaX) { - this.maxDeltaX_ = maxDeltaX; + return propertyName; }; /** - * @param {number} maxDeltaY Maximum magnitude for y delta on each mousewheel - * event. Should be non-negative. + * Returns the style property name in CSS notation. If it does not exist and a + * vendor-specific version of the property does exist, then return the vendor- + * specific property name instead. + * @param {Element} element The element to change. + * @param {string} style Style name. + * @return {string} Vendor-specific style. + * @private */ -goog.events.MouseWheelHandler.prototype.setMaxDeltaY = function(maxDeltaY) { - this.maxDeltaY_ = maxDeltaY; -}; - +goog.style.getVendorStyleName_ = function(element, style) { + var camelStyle = goog.string.toCamelCase(style); -/** - * Handles the events on the element. - * @param {goog.events.BrowserEvent} e The underlying browser event. - */ -goog.events.MouseWheelHandler.prototype.handleEvent = function(e) { - var deltaX = 0; - var deltaY = 0; - var detail = 0; - var be = e.getBrowserEvent(); - if (be.type == 'mousewheel') { - var wheelDeltaScaleFactor = 1; - if (goog.userAgent.IE || - goog.userAgent.WEBKIT && - (goog.userAgent.WINDOWS || goog.userAgent.isVersionOrHigher('532.0'))) { - // In IE we get a multiple of 120; we adjust to a multiple of 3 to - // represent number of lines scrolled (like Gecko). - // Newer versions of Webkit match IE behavior, and WebKit on - // Windows also matches IE behavior. - // See bug https://bugs.webkit.org/show_bug.cgi?id=24368 - wheelDeltaScaleFactor = 40; - } + if (element.style[camelStyle] === undefined) { + var prefixedStyle = goog.dom.vendor.getVendorJsPrefix() + + goog.string.toTitleCase(camelStyle); - detail = goog.events.MouseWheelHandler.smartScale_( - -be.wheelDelta, wheelDeltaScaleFactor); - if (goog.isDef(be.wheelDeltaX)) { - // Webkit has two properties to indicate directional scroll, and - // can scroll both directions at once. - deltaX = goog.events.MouseWheelHandler.smartScale_( - -be.wheelDeltaX, wheelDeltaScaleFactor); - deltaY = goog.events.MouseWheelHandler.smartScale_( - -be.wheelDeltaY, wheelDeltaScaleFactor); - } else { - deltaY = detail; + if (element.style[prefixedStyle] !== undefined) { + return goog.dom.vendor.getVendorPrefix() + '-' + style; } + } - // Historical note: Opera (pre 9.5) used to negate the detail value. - } else { // Gecko - // Gecko returns multiple of 3 (representing the number of lines scrolled) - detail = be.detail; + return style; +}; - // Gecko sometimes returns really big values if the user changes settings to - // scroll a whole page per scroll - if (detail > 100) { - detail = 3; - } else if (detail < -100) { - detail = -3; - } - // Firefox 3.1 adds an axis field to the event to indicate direction of - // scroll. See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events - if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) { - deltaX = detail; - } else { - deltaY = detail; - } - } +/** + * Retrieves an explicitly-set style value of a node. This returns '' if there + * isn't a style attribute on the element or if this style property has not been + * explicitly set in script. + * + * @param {Element} element Element to get style of. + * @param {string} property Property to get, css-style (if you have a camel-case + * property, use element.style[style]). + * @return {string} Style value. + */ +goog.style.getStyle = function(element, property) { + // element.style is '' for well-known properties which are unset. + // For for browser specific styles as 'filter' is undefined + // so we need to return '' explicitly to make it consistent across + // browsers. + var styleValue = element.style[goog.string.toCamelCase(property)]; - if (goog.isNumber(this.maxDeltaX_)) { - deltaX = goog.math.clamp(deltaX, -this.maxDeltaX_, this.maxDeltaX_); - } - if (goog.isNumber(this.maxDeltaY_)) { - deltaY = goog.math.clamp(deltaY, -this.maxDeltaY_, this.maxDeltaY_); + // Using typeof here because of a bug in Safari 5.1, where this value + // was undefined, but === undefined returned false. + if (typeof(styleValue) !== 'undefined') { + return styleValue; } - // Don't clamp 'detail', since it could be ambiguous which axis it refers to - // and because it's informally deprecated anyways. - // For horizontal scrolling we need to flip the value for RTL grids. - if (this.isRtl_) { - deltaX = -deltaX; - } - var newEvent = new goog.events.MouseWheelEvent(detail, be, deltaX, deltaY); - this.dispatchEvent(newEvent); + return element.style[goog.style.getVendorJsStyleName_(element, property)] || + ''; }; /** - * Helper for scaling down a mousewheel delta by a scale factor, if appropriate. - * @param {number} mouseWheelDelta Delta from a mouse wheel event. Expected to - * be an integer. - * @param {number} scaleFactor Factor to scale the delta down by. Expected to - * be an integer. - * @return {number} Scaled-down delta value, or the original delta if the - * scaleFactor does not appear to be applicable. - * @private + * Retrieves a computed style value of a node. It returns empty string if the + * value cannot be computed (which will be the case in Internet Explorer) or + * "none" if the property requested is an SVG one and it has not been + * explicitly set (firefox and webkit). + * + * @param {Element} element Element to get style of. + * @param {string} property Property to get (camel-case). + * @return {string} Style value. */ -goog.events.MouseWheelHandler.smartScale_ = function(mouseWheelDelta, - scaleFactor) { - // The basic problem here is that in Webkit on Mac and Linux, we can get two - // very different types of mousewheel events: from continuous devices - // (touchpads, Mighty Mouse) or non-continuous devices (normal wheel mice). - // - // Non-continuous devices in Webkit get their wheel deltas scaled up to - // behave like IE. Continuous devices return much smaller unscaled values - // (which most of the time will not be cleanly divisible by the IE scale - // factor), so we should not try to normalize them down. - // - // Detailed discussion: - // https://bugs.webkit.org/show_bug.cgi?id=29601 - // http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063 - if (goog.userAgent.WEBKIT && - (goog.userAgent.MAC || goog.userAgent.LINUX) && - (mouseWheelDelta % scaleFactor) != 0) { - return mouseWheelDelta; - } else { - return mouseWheelDelta / scaleFactor; +goog.style.getComputedStyle = function(element, property) { + var doc = goog.dom.getOwnerDocument(element); + if (doc.defaultView && doc.defaultView.getComputedStyle) { + var styles = doc.defaultView.getComputedStyle(element, null); + if (styles) { + // element.style[..] is undefined for browser specific styles + // as 'filter'. + return styles[property] || styles.getPropertyValue(property) || ''; + } } -}; - -/** @override */ -goog.events.MouseWheelHandler.prototype.disposeInternal = function() { - goog.events.MouseWheelHandler.superClass_.disposeInternal.call(this); - goog.events.unlistenByKey(this.listenKey_); - this.listenKey_ = null; + return ''; }; - /** - * A base class for mouse wheel events. This is used with the - * MouseWheelHandler. + * Gets the cascaded style value of a node, or null if the value cannot be + * computed (only Internet Explorer can do this). * - * @param {number} detail The number of rows the user scrolled. - * @param {Event} browserEvent Browser event object. - * @param {number} deltaX The number of rows the user scrolled in the X - * direction. - * @param {number} deltaY The number of rows the user scrolled in the Y - * direction. - * @constructor - * @extends {goog.events.BrowserEvent} - * @final + * @param {Element} element Element to get style of. + * @param {string} style Property to get (camel-case). + * @return {string} Style value. */ -goog.events.MouseWheelEvent = function(detail, browserEvent, deltaX, deltaY) { - goog.events.BrowserEvent.call(this, browserEvent); - - this.type = goog.events.MouseWheelHandler.EventType.MOUSEWHEEL; - - /** - * The number of lines the user scrolled - * @type {number} - * NOTE: Informally deprecated. Use deltaX and deltaY instead, they provide - * more information. - */ - this.detail = detail; - - /** - * The number of "lines" scrolled in the X direction. - * - * Note that not all browsers provide enough information to distinguish - * horizontal and vertical scroll events, so for these unsupported browsers, - * we will always have a deltaX of 0, even if the user scrolled their mouse - * wheel or trackpad sideways. - * - * Currently supported browsers are Webkit and Firefox 3.1 or later. - * - * @type {number} - */ - this.deltaX = deltaX; - - /** - * The number of lines scrolled in the Y direction. - * @type {number} - */ - this.deltaY = deltaY; +goog.style.getCascadedStyle = function(element, style) { + // TODO(nicksantos): This should be documented to return null. #fixTypes + return element.currentStyle ? element.currentStyle[style] : null; }; -goog.inherits(goog.events.MouseWheelEvent, goog.events.BrowserEvent); -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Basic strippable logging definitions. - * @see http://go/closurelogging + * Cross-browser pseudo get computed style. It returns the computed style where + * available. If not available it tries the cascaded style value (IE + * currentStyle) and in worst case the inline style value. It shouldn't be + * called directly, see http://wiki/Main/ComputedStyleVsCascadedStyle for + * discussion. * - * @author johnlenz@google.com (John Lenz) + * @param {Element} element Element to get style of. + * @param {string} style Property to get (must be camelCase, not css-style.). + * @return {string} Style value. + * @private */ +goog.style.getStyle_ = function(element, style) { + return goog.style.getComputedStyle(element, style) || + goog.style.getCascadedStyle(element, style) || + (element.style && element.style[style]); +}; -goog.provide('goog.log'); -goog.provide('goog.log.Level'); -goog.provide('goog.log.LogRecord'); -goog.provide('goog.log.Logger'); - -goog.require('goog.debug'); -goog.require('goog.debug.LogManager'); -goog.require('goog.debug.LogRecord'); -goog.require('goog.debug.Logger'); - - -/** @define {boolean} Whether logging is enabled. */ -goog.define('goog.log.ENABLED', goog.debug.LOGGING_ENABLED); +/** + * Retrieves the computed value of the box-sizing CSS attribute. + * Browser support: http://caniuse.com/css3-boxsizing. + * @param {!Element} element The element whose box-sizing to get. + * @return {?string} 'content-box', 'border-box' or 'padding-box'. null if + * box-sizing is not supported (IE7 and below). + */ +goog.style.getComputedBoxSizing = function(element) { + return goog.style.getStyle_(element, 'boxSizing') || + goog.style.getStyle_(element, 'MozBoxSizing') || + goog.style.getStyle_(element, 'WebkitBoxSizing') || null; +}; -/** @const */ -goog.log.ROOT_LOGGER_NAME = goog.debug.Logger.ROOT_LOGGER_NAME; +/** + * Retrieves the computed value of the position CSS attribute. + * @param {Element} element The element to get the position of. + * @return {string} Position value. + */ +goog.style.getComputedPosition = function(element) { + return goog.style.getStyle_(element, 'position'); +}; /** - * @constructor - * @final + * Retrieves the computed background color string for a given element. The + * string returned is suitable for assigning to another element's + * background-color, but is not guaranteed to be in any particular string + * format. Accessing the color in a numeric form may not be possible in all + * browsers or with all input. + * + * If the background color for the element is defined as a hexadecimal value, + * the resulting string can be parsed by goog.color.parse in all supported + * browsers. + * + * Whether named colors like "red" or "lightblue" get translated into a + * format which can be parsed is browser dependent. Calling this function on + * transparent elements will return "transparent" in most browsers or + * "rgba(0, 0, 0, 0)" in WebKit. + * @param {Element} element The element to get the background color of. + * @return {string} The computed string value of the background color. */ -goog.log.Logger = goog.debug.Logger; - +goog.style.getBackgroundColor = function(element) { + return goog.style.getStyle_(element, 'backgroundColor'); +}; /** - * @constructor - * @final + * Retrieves the computed value of the overflow-x CSS attribute. + * @param {Element} element The element to get the overflow-x of. + * @return {string} The computed string value of the overflow-x attribute. */ -goog.log.Level = goog.debug.Logger.Level; - +goog.style.getComputedOverflowX = function(element) { + return goog.style.getStyle_(element, 'overflowX'); +}; /** - * @constructor - * @final + * Retrieves the computed value of the overflow-y CSS attribute. + * @param {Element} element The element to get the overflow-y of. + * @return {string} The computed string value of the overflow-y attribute. */ -goog.log.LogRecord = goog.debug.LogRecord; +goog.style.getComputedOverflowY = function(element) { + return goog.style.getStyle_(element, 'overflowY'); +}; /** - * Finds or creates a logger for a named subsystem. If a logger has already been - * created with the given name it is returned. Otherwise a new logger is - * created. If a new logger is created its log level will be configured based - * on the goog.debug.LogManager configuration and it will configured to also - * send logging output to its parent's handlers. - * @see goog.debug.LogManager - * - * @param {string} name A name for the logger. This should be a dot-separated - * name and should normally be based on the package name or class name of - * the subsystem, such as goog.net.BrowserChannel. - * @param {goog.log.Level=} opt_level If provided, override the - * default logging level with the provided level. - * @return {goog.log.Logger} The named logger or null if logging is disabled. + * Retrieves the computed value of the z-index CSS attribute. + * @param {Element} element The element to get the z-index of. + * @return {string|number} The computed value of the z-index attribute. */ -goog.log.getLogger = function(name, opt_level) { - if (goog.log.ENABLED) { - var logger = goog.debug.LogManager.getLogger(name); - if (opt_level && logger) { - logger.setLevel(opt_level); - } - return logger; - } else { - return null; - } +goog.style.getComputedZIndex = function(element) { + return goog.style.getStyle_(element, 'zIndex'); }; -// TODO(johnlenz): try to tighten the types to these functions. /** - * Adds a handler to the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {goog.log.Logger} logger - * @param {Function} handler Handler function to add. + * Retrieves the computed value of the text-align CSS attribute. + * @param {Element} element The element to get the text-align of. + * @return {string} The computed string value of the text-align attribute. */ -goog.log.addHandler = function(logger, handler) { - if (goog.log.ENABLED && logger) { - logger.addHandler(handler); - } +goog.style.getComputedTextAlign = function(element) { + return goog.style.getStyle_(element, 'textAlign'); }; /** - * Removes a handler from the logger. This doesn't use the event system because - * we want to be able to add logging to the event system. - * @param {goog.log.Logger} logger - * @param {Function} handler Handler function to remove. - * @return {boolean} Whether the handler was removed. + * Retrieves the computed value of the cursor CSS attribute. + * @param {Element} element The element to get the cursor of. + * @return {string} The computed string value of the cursor attribute. */ -goog.log.removeHandler = function(logger, handler) { - if (goog.log.ENABLED && logger) { - return logger.removeHandler(handler); - } else { - return false; - } +goog.style.getComputedCursor = function(element) { + return goog.style.getStyle_(element, 'cursor'); }; /** - * Logs a message. If the logger is currently enabled for the - * given message level then the given message is forwarded to all the - * registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.log.Level} level One of the level identifiers. - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error|Object=} opt_exception An exception associated with the - * message. + * Retrieves the computed value of the CSS transform attribute. + * @param {Element} element The element to get the transform of. + * @return {string} The computed string representation of the transform matrix. */ -goog.log.log = function(logger, level, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.log(level, msg, opt_exception); - } +goog.style.getComputedTransform = function(element) { + var property = goog.style.getVendorStyleName_(element, 'transform'); + return goog.style.getStyle_(element, property) || + goog.style.getStyle_(element, 'transform'); }; /** - * Logs a message at the Level.SEVERE level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Sets the top/left values of an element. If no unit is specified in the + * argument then it will add px. The second argument is required if the first + * argument is a string or number and is ignored if the first argument + * is a coordinate. + * @param {Element} el Element to move. + * @param {string|number|goog.math.Coordinate} arg1 Left position or coordinate. + * @param {string|number=} opt_arg2 Top position. */ -goog.log.error = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.severe(msg, opt_exception); +goog.style.setPosition = function(el, arg1, opt_arg2) { + var x, y; + + if (arg1 instanceof goog.math.Coordinate) { + x = arg1.x; + y = arg1.y; + } else { + x = arg1; + y = opt_arg2; } + + el.style.left = goog.style.getPixelStyleValue_( + /** @type {number|string} */ (x), false); + el.style.top = goog.style.getPixelStyleValue_( + /** @type {number|string} */ (y), false); }; /** - * Logs a message at the Level.WARNING level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Gets the offsetLeft and offsetTop properties of an element and returns them + * in a Coordinate object + * @param {Element} element Element. + * @return {!goog.math.Coordinate} The position. */ -goog.log.warning = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.warning(msg, opt_exception); - } +goog.style.getPosition = function(element) { + return new goog.math.Coordinate( + /** @type {!HTMLElement} */ (element).offsetLeft, + /** @type {!HTMLElement} */ (element).offsetTop); }; /** - * Logs a message at the Level.INFO level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Returns the viewport element for a particular document + * @param {Node=} opt_node DOM node (Document is OK) to get the viewport element + * of. + * @return {Element} document.documentElement or document.body. */ -goog.log.info = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.info(msg, opt_exception); +goog.style.getClientViewportElement = function(opt_node) { + var doc; + if (opt_node) { + doc = goog.dom.getOwnerDocument(opt_node); + } else { + doc = goog.dom.getDocument(); + } + + // In old IE versions the document.body represented the viewport + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) && + !goog.dom.getDomHelper(doc).isCss1CompatMode()) { + return doc.body; } + return doc.documentElement; }; /** - * Logs a message at the Level.Fine level. - * If the logger is currently enabled for the given message level then the - * given message is forwarded to all the registered output Handler objects. - * @param {goog.log.Logger} logger - * @param {goog.debug.Loggable} msg The message to log. - * @param {Error=} opt_exception An exception associated with the message. + * Calculates the viewport coordinates relative to the page/document + * containing the node. The viewport may be the browser viewport for + * non-iframe document, or the iframe container for iframe'd document. + * @param {!Document} doc The document to use as the reference point. + * @return {!goog.math.Coordinate} The page offset of the viewport. */ -goog.log.fine = function(logger, msg, opt_exception) { - if (goog.log.ENABLED && logger) { - logger.fine(msg, opt_exception); - } +goog.style.getViewportPageOffset = function(doc) { + var body = doc.body; + var documentElement = doc.documentElement; + var scrollLeft = body.scrollLeft || documentElement.scrollLeft; + var scrollTop = body.scrollTop || documentElement.scrollTop; + return new goog.math.Coordinate(scrollLeft, scrollTop); }; -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.PointerEvent'); - - -goog.require('goog.events'); -goog.require('goog.events.Event'); - - /** - * A class for pointer events. + * Gets the client rectangle of the DOM element. * - * This class is used as an abstraction for mouse events, - * touch events and even native pointer events. + * getBoundingClientRect is part of a new CSS object model draft (with a + * long-time presence in IE), replacing the error-prone parent offset + * computation and the now-deprecated Gecko getBoxObjectFor. * - * @constructor - * @extends {goog.events.Event} - * @param {string} type The type of the event to create. - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object.<string, ?>=} opt_eventDict An optional dictionary of - * initial event properties. + * This utility patches common browser bugs in getBoundingClientRect. It + * will fail if getBoundingClientRect is unsupported. + * + * If the element is not in the DOM, the result is undefined, and an error may + * be thrown depending on user agent. + * + * @param {!Element} el The element whose bounding rectangle is being queried. + * @return {Object} A native bounding rectangle with numerical left, top, + * right, and bottom. Reported by Firefox to be of object type ClientRect. + * @private */ -ol.pointer.PointerEvent = function(type, browserEvent, opt_eventDict) { - goog.base(this, type); - - /** - * @const - * @type {goog.events.BrowserEvent} - */ - this.browserEvent = browserEvent; - - var eventDict = opt_eventDict ? opt_eventDict : {}; - - /** - * @type {number} - */ - this.buttons = this.getButtons_(eventDict); - - /** - * @type {number} - */ - this.pressure = this.getPressure_(eventDict, this.buttons); - - // MouseEvent related properties +goog.style.getBoundingClientRect_ = function(el) { + var rect; + try { + rect = el.getBoundingClientRect(); + } catch (e) { + // In IE < 9, calling getBoundingClientRect on an orphan element raises an + // "Unspecified Error". All other browsers return zeros. + return {'left': 0, 'top': 0, 'right': 0, 'bottom': 0}; + } - /** - * @type {boolean} - */ - this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false; + // Patch the result in IE only, so that this function can be inlined if + // compiled for non-IE. + if (goog.userAgent.IE && el.ownerDocument.body) { - /** - * @type {boolean} - */ - this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false; + // In IE, most of the time, 2 extra pixels are added to the top and left + // due to the implicit 2-pixel inset border. In IE6/7 quirks mode and + // IE6 standards mode, this border can be overridden by setting the + // document element's border to zero -- thus, we cannot rely on the + // offset always being 2 pixels. - /** - * @type {Object} - */ - this.view = 'view' in eventDict ? eventDict['view'] : null; + // In quirks mode, the offset can be determined by querying the body's + // clientLeft/clientTop, but in standards mode, it is found by querying + // the document element's clientLeft/clientTop. Since we already called + // getBoundingClientRect we have already forced a reflow, so it is not + // too expensive just to query them all. - /** - * @type {number} - */ - this.detail = 'detail' in eventDict ? eventDict['detail'] : null; + // See: http://msdn.microsoft.com/en-us/library/ms536433(VS.85).aspx + var doc = el.ownerDocument; + rect.left -= doc.documentElement.clientLeft + doc.body.clientLeft; + rect.top -= doc.documentElement.clientTop + doc.body.clientTop; + } + return rect; +}; - /** - * @type {number} - */ - this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0; - /** - * @type {number} - */ - this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0; +/** + * Returns the first parent that could affect the position of a given element. + * @param {Element} element The element to get the offset parent for. + * @return {Element} The first offset parent or null if one cannot be found. + */ +goog.style.getOffsetParent = function(element) { + // element.offsetParent does the right thing in IE7 and below. In other + // browsers it only includes elements with position absolute, relative or + // fixed, not elements with overflow set to auto or scroll. + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(8)) { + return element.offsetParent; + } - /** - * @type {number} - */ - this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0; + var doc = goog.dom.getOwnerDocument(element); + var positionStyle = goog.style.getStyle_(element, 'position'); + var skipStatic = positionStyle == 'fixed' || positionStyle == 'absolute'; + for (var parent = element.parentNode; parent && parent != doc; + parent = parent.parentNode) { + // Skip shadowDOM roots. + if (parent.nodeType == goog.dom.NodeType.DOCUMENT_FRAGMENT && + parent.host) { + parent = parent.host; + } + positionStyle = + goog.style.getStyle_(/** @type {!Element} */ (parent), 'position'); + skipStatic = skipStatic && positionStyle == 'static' && + parent != doc.documentElement && parent != doc.body; + if (!skipStatic && (parent.scrollWidth > parent.clientWidth || + parent.scrollHeight > parent.clientHeight || + positionStyle == 'fixed' || + positionStyle == 'absolute' || + positionStyle == 'relative')) { + return /** @type {!Element} */ (parent); + } + } + return null; +}; - /** - * @type {number} - */ - this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0; - /** - * @type {boolean} - */ - this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false; +/** + * Calculates and returns the visible rectangle for a given element. Returns a + * box describing the visible portion of the nearest scrollable offset ancestor. + * Coordinates are given relative to the document. + * + * @param {Element} element Element to get the visible rect for. + * @return {goog.math.Box} Bounding elementBox describing the visible rect or + * null if scrollable ancestor isn't inside the visible viewport. + */ +goog.style.getVisibleRectForElement = function(element) { + var visibleRect = new goog.math.Box(0, Infinity, Infinity, 0); + var dom = goog.dom.getDomHelper(element); + var body = dom.getDocument().body; + var documentElement = dom.getDocument().documentElement; + var scrollEl = dom.getDocumentScrollElement(); - /** - * @type {boolean} - */ - this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false; + // Determine the size of the visible rect by climbing the dom accounting for + // all scrollable containers. + for (var el = element; el = goog.style.getOffsetParent(el); ) { + // clientWidth is zero for inline block elements in IE. + // on WEBKIT, body element can have clientHeight = 0 and scrollHeight > 0 + if ((!goog.userAgent.IE || el.clientWidth != 0) && + (!goog.userAgent.WEBKIT || el.clientHeight != 0 || el != body) && + // body may have overflow set on it, yet we still get the entire + // viewport. In some browsers, el.offsetParent may be + // document.documentElement, so check for that too. + (el != body && el != documentElement && + goog.style.getStyle_(el, 'overflow') != 'visible')) { + var pos = goog.style.getPageOffset(el); + var client = goog.style.getClientLeftTop(el); + pos.x += client.x; + pos.y += client.y; - /** - * @type {boolean} - */ - this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false; + visibleRect.top = Math.max(visibleRect.top, pos.y); + visibleRect.right = Math.min(visibleRect.right, + pos.x + el.clientWidth); + visibleRect.bottom = Math.min(visibleRect.bottom, + pos.y + el.clientHeight); + visibleRect.left = Math.max(visibleRect.left, pos.x); + } + } - /** - * @type {boolean} - */ - this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false; + // Clip by window's viewport. + var scrollX = scrollEl.scrollLeft, scrollY = scrollEl.scrollTop; + visibleRect.left = Math.max(visibleRect.left, scrollX); + visibleRect.top = Math.max(visibleRect.top, scrollY); + var winSize = dom.getViewportSize(); + visibleRect.right = Math.min(visibleRect.right, scrollX + winSize.width); + visibleRect.bottom = Math.min(visibleRect.bottom, scrollY + winSize.height); + return visibleRect.top >= 0 && visibleRect.left >= 0 && + visibleRect.bottom > visibleRect.top && + visibleRect.right > visibleRect.left ? + visibleRect : null; +}; - /** - * @type {number} - */ - this.button = 'button' in eventDict ? eventDict['button'] : 0; - /** - * @type {Node} - */ - this.relatedTarget = 'relatedTarget' in eventDict ? - eventDict['relatedTarget'] : null; +/** + * Calculate the scroll position of {@code container} with the minimum amount so + * that the content and the borders of the given {@code element} become visible. + * If the element is bigger than the container, its top left corner will be + * aligned as close to the container's top left corner as possible. + * + * @param {Element} element The element to make visible. + * @param {Element=} opt_container The container to scroll. If not set, then the + * document scroll element will be used. + * @param {boolean=} opt_center Whether to center the element in the container. + * Defaults to false. + * @return {!goog.math.Coordinate} The new scroll position of the container, + * in form of goog.math.Coordinate(scrollLeft, scrollTop). + */ +goog.style.getContainerOffsetToScrollInto = + function(element, opt_container, opt_center) { + var container = opt_container || goog.dom.getDocumentScrollElement(); + // Absolute position of the element's border's top left corner. + var elementPos = goog.style.getPageOffset(element); + // Absolute position of the container's border's top left corner. + var containerPos = goog.style.getPageOffset(container); + var containerBorder = goog.style.getBorderBox(container); + if (container == goog.dom.getDocumentScrollElement()) { + // The element position is calculated based on the page offset, and the + // document scroll element holds the scroll position within the page. We can + // use the scroll position to calculate the relative position from the + // element. + var relX = elementPos.x - container.scrollLeft; + var relY = elementPos.y - container.scrollTop; + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) { + // In older versions of IE getPageOffset(element) does not include the + // container border so it has to be added to accomodate. + relX += containerBorder.left; + relY += containerBorder.top; + } + } else { + // Relative pos. of the element's border box to the container's content box. + var relX = elementPos.x - containerPos.x - containerBorder.left; + var relY = elementPos.y - containerPos.y - containerBorder.top; + } + // How much the element can move in the container, i.e. the difference between + // the element's bottom-right-most and top-left-most position where it's + // fully visible. + var spaceX = container.clientWidth - + /** @type {HTMLElement} */ (element).offsetWidth; + var spaceY = container.clientHeight - + /** @type {HTMLElement} */ (element).offsetHeight; - // PointerEvent related properties + var scrollLeft = container.scrollLeft; + var scrollTop = container.scrollTop; + if (opt_center) { + // All browsers round non-integer scroll positions down. + scrollLeft += relX - spaceX / 2; + scrollTop += relY - spaceY / 2; + } else { + // This formula was designed to give the correct scroll values in the + // following cases: + // - element is higher than container (spaceY < 0) => scroll down by relY + // - element is not higher that container (spaceY >= 0): + // - it is above container (relY < 0) => scroll up by abs(relY) + // - it is below container (relY > spaceY) => scroll down by relY - spaceY + // - it is in the container => don't scroll + scrollLeft += Math.min(relX, Math.max(relX - spaceX, 0)); + scrollTop += Math.min(relY, Math.max(relY - spaceY, 0)); + } + return new goog.math.Coordinate(scrollLeft, scrollTop); +}; - /** - * @const - * @type {number} - */ - this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0; - /** - * @type {number} - */ - this.width = 'width' in eventDict ? eventDict['width'] : 0; +/** + * Changes the scroll position of {@code container} with the minimum amount so + * that the content and the borders of the given {@code element} become visible. + * If the element is bigger than the container, its top left corner will be + * aligned as close to the container's top left corner as possible. + * + * @param {Element} element The element to make visible. + * @param {Element=} opt_container The container to scroll. If not set, then the + * document scroll element will be used. + * @param {boolean=} opt_center Whether to center the element in the container. + * Defaults to false. + */ +goog.style.scrollIntoContainerView = + function(element, opt_container, opt_center) { + var container = opt_container || goog.dom.getDocumentScrollElement(); + var offset = + goog.style.getContainerOffsetToScrollInto(element, container, opt_center); + container.scrollLeft = offset.x; + container.scrollTop = offset.y; +}; - /** - * @type {number} - */ - this.height = 'height' in eventDict ? eventDict['height'] : 0; - /** - * @type {number} - */ - this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0; +/** + * Returns clientLeft (width of the left border and, if the directionality is + * right to left, the vertical scrollbar) and clientTop as a coordinate object. + * + * @param {Element} el Element to get clientLeft for. + * @return {!goog.math.Coordinate} Client left and top. + */ +goog.style.getClientLeftTop = function(el) { + return new goog.math.Coordinate(el.clientLeft, el.clientTop); +}; - /** - * @type {number} - */ - this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0; - /** - * @type {string} - */ - this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : ''; +/** + * Returns a Coordinate object relative to the top-left of the HTML document. + * Implemented as a single function to save having to do two recursive loops in + * opera and safari just to get both coordinates. If you just want one value do + * use goog.style.getPageOffsetLeft() and goog.style.getPageOffsetTop(), but + * note if you call both those methods the tree will be analysed twice. + * + * @param {Element} el Element to get the page offset for. + * @return {!goog.math.Coordinate} The page offset. + */ +goog.style.getPageOffset = function(el) { + var doc = goog.dom.getOwnerDocument(el); + // TODO(gboyer): Update the jsdoc in a way that doesn't break the universe. + goog.asserts.assertObject(el, 'Parameter is required'); - /** - * @type {number} - */ - this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0; + // NOTE(arv): If element is hidden (display none or disconnected or any the + // ancestors are hidden) we get (0,0) by default but we still do the + // accumulation of scroll position. - /** - * @type {boolean} - */ - this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false; + // TODO(arv): Should we check if the node is disconnected and in that case + // return (0,0)? - // keep the semantics of preventDefault - if (browserEvent.preventDefault) { - this.preventDefault = function() { - browserEvent.preventDefault(); - }; + var pos = new goog.math.Coordinate(0, 0); + var viewportElement = goog.style.getClientViewportElement(doc); + if (el == viewportElement) { + // viewport is always at 0,0 as that defined the coordinate system for this + // function - this avoids special case checks in the code below + return pos; } -}; -goog.inherits(ol.pointer.PointerEvent, goog.events.Event); + var box = goog.style.getBoundingClientRect_(el); + // Must add the scroll coordinates in to get the absolute page offset + // of element since getBoundingClientRect returns relative coordinates to + // the viewport. + var scrollCoord = goog.dom.getDomHelper(doc).getDocumentScroll(); + pos.x = box.left + scrollCoord.x; + pos.y = box.top + scrollCoord.y; -/** - * @private - * @param {Object.<string, ?>} eventDict - * @return {number} - */ -ol.pointer.PointerEvent.prototype.getButtons_ = function(eventDict) { - // According to the w3c spec, - // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button - // MouseEvent.button == 0 can mean either no mouse button depressed, or the - // left mouse button depressed. - // - // As of now, the only way to distinguish between the two states of - // MouseEvent.button is by using the deprecated MouseEvent.which property, as - // this maps mouse buttons to positive integers > 0, and uses 0 to mean that - // no mouse button is held. - // - // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation, - // but initMouseEvent does not expose an argument with which to set - // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set - // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations - // of app developers. - // - // The only way to propagate the correct state of MouseEvent.which and - // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0 - // is to call initMouseEvent with a buttonArg value of -1. - // - // This is fixed with DOM Level 4's use of buttons - var buttons; - if (eventDict.buttons || ol.pointer.PointerEvent.HAS_BUTTONS) { - buttons = eventDict.buttons; - } else { - switch (eventDict.which) { - case 1: buttons = 1; break; - case 2: buttons = 4; break; - case 3: buttons = 2; break; - default: buttons = 0; - } - } - return buttons; + return pos; }; /** - * @private - * @param {Object.<string, ?>} eventDict - * @param {number} buttons - * @return {number} + * Returns the left coordinate of an element relative to the HTML document + * @param {Element} el Elements. + * @return {number} The left coordinate. */ -ol.pointer.PointerEvent.prototype.getPressure_ = function(eventDict, buttons) { - // Spec requires that pointers without pressure specified use 0.5 for down - // state and 0 for up state. - var pressure = 0; - if (eventDict.pressure) { - pressure = eventDict.pressure; - } else { - pressure = buttons ? 0.5 : 0; - } - return pressure; +goog.style.getPageOffsetLeft = function(el) { + return goog.style.getPageOffset(el).x; }; /** - * Is the `buttons` property supported? - * @type {boolean} + * Returns the top coordinate of an element relative to the HTML document + * @param {Element} el Elements. + * @return {number} The top coordinate. */ -ol.pointer.PointerEvent.HAS_BUTTONS = false; +goog.style.getPageOffsetTop = function(el) { + return goog.style.getPageOffset(el).y; +}; /** - * Checks if the `buttons` property is supported. + * Returns a Coordinate object relative to the top-left of an HTML document + * in an ancestor frame of this element. Used for measuring the position of + * an element inside a frame relative to a containing frame. + * + * @param {Element} el Element to get the page offset for. + * @param {Window} relativeWin The window to measure relative to. If relativeWin + * is not in the ancestor frame chain of the element, we measure relative to + * the top-most window. + * @return {!goog.math.Coordinate} The page offset. */ -(function() { - try { - var ev = new MouseEvent('click', {buttons: 1}); - ol.pointer.PointerEvent.HAS_BUTTONS = ev.buttons === 1; - } catch (e) { - } -})(); +goog.style.getFramedPageOffset = function(el, relativeWin) { + var position = new goog.math.Coordinate(0, 0); -// FIXME add tests for browser features (Modernizr?) + // Iterate up the ancestor frame chain, keeping track of the current window + // and the current element in that window. + var currentWin = goog.dom.getWindow(goog.dom.getOwnerDocument(el)); + var currentEl = el; + do { + // if we're at the top window, we want to get the page offset. + // if we're at an inner frame, we only want to get the window position + // so that we can determine the actual page offset in the context of + // the outer window. + var offset = currentWin == relativeWin ? + goog.style.getPageOffset(currentEl) : + goog.style.getClientPositionForElement_( + goog.asserts.assert(currentEl)); -goog.provide('ol.dom'); -goog.provide('ol.dom.BrowserFeature'); + position.x += offset.x; + position.y += offset.y; + } while (currentWin && currentWin != relativeWin && + currentWin != currentWin.parent && + (currentEl = currentWin.frameElement) && + (currentWin = currentWin.parent)); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.userAgent'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); + return position; +}; /** - * Create an html canvas element and returns its 2d context. - * @param {number=} opt_width Canvas width. - * @param {number=} opt_height Canvas height. - * @return {CanvasRenderingContext2D} + * Translates the specified rect relative to origBase page, for newBase page. + * If origBase and newBase are the same, this function does nothing. + * + * @param {goog.math.Rect} rect The source rectangle relative to origBase page, + * and it will have the translated result. + * @param {goog.dom.DomHelper} origBase The DomHelper for the input rectangle. + * @param {goog.dom.DomHelper} newBase The DomHelper for the resultant + * coordinate. This must be a DOM for an ancestor frame of origBase + * or the same as origBase. */ -ol.dom.createCanvasContext2D = function(opt_width, opt_height) { - var canvas = goog.dom.createElement('CANVAS'); - if (opt_width) { - canvas.width = opt_width; - } - if (opt_height) { - canvas.height = opt_height; +goog.style.translateRectForAnotherFrame = function(rect, origBase, newBase) { + if (origBase.getDocument() != newBase.getDocument()) { + var body = origBase.getDocument().body; + var pos = goog.style.getFramedPageOffset(body, newBase.getWindow()); + + // Adjust Body's margin. + pos = goog.math.Coordinate.difference(pos, goog.style.getPageOffset(body)); + + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9) && + !origBase.isCss1CompatMode()) { + pos = goog.math.Coordinate.difference(pos, origBase.getDocumentScroll()); + } + + rect.left += pos.x; + rect.top += pos.y; } - return canvas.getContext('2d'); }; /** - * Detect 2d transform. - * Adapted from http://stackoverflow.com/q/5661671/130442 - * http://caniuse.com/#feat=transforms2d - * @return {boolean} + * Returns the position of an element relative to another element in the + * document. A relative to B + * @param {Element|Event|goog.events.Event} a Element or mouse event whose + * position we're calculating. + * @param {Element|Event|goog.events.Event} b Element or mouse event position + * is relative to. + * @return {!goog.math.Coordinate} The relative position. */ -ol.dom.canUseCssTransform = (function() { - var canUseCssTransform; - return function() { - if (canUseCssTransform === undefined) { - goog.asserts.assert(document.body, - 'document.body should not be null'); - if (!goog.global.getComputedStyle) { - // this browser is ancient - canUseCssTransform = false; - } else { - var el = goog.dom.createElement('P'), - has2d, - transforms = { - 'webkitTransform': '-webkit-transform', - 'OTransform': '-o-transform', - 'msTransform': '-ms-transform', - 'MozTransform': '-moz-transform', - 'transform': 'transform' - }; - document.body.appendChild(el); - for (var t in transforms) { - if (t in el.style) { - el.style[t] = 'translate(1px,1px)'; - has2d = goog.global.getComputedStyle(el).getPropertyValue( - transforms[t]); - } - } - goog.dom.removeNode(el); - - canUseCssTransform = (has2d && has2d !== 'none'); - } - } - return canUseCssTransform; - }; -}()); +goog.style.getRelativePosition = function(a, b) { + var ap = goog.style.getClientPosition(a); + var bp = goog.style.getClientPosition(b); + return new goog.math.Coordinate(ap.x - bp.x, ap.y - bp.y); +}; /** - * Detect 3d transform. - * Adapted from http://stackoverflow.com/q/5661671/130442 - * http://caniuse.com/#feat=transforms3d - * @return {boolean} + * Returns the position of the event or the element's border box relative to + * the client viewport. + * @param {!Element} el Element whose position to get. + * @return {!goog.math.Coordinate} The position. + * @private */ -ol.dom.canUseCssTransform3D = (function() { - var canUseCssTransform3D; - return function() { - if (canUseCssTransform3D === undefined) { - goog.asserts.assert(document.body, - 'document.body should not be null'); - if (!goog.global.getComputedStyle) { - // this browser is ancient - canUseCssTransform3D = false; - } else { - var el = goog.dom.createElement('P'), - has3d, - transforms = { - 'webkitTransform': '-webkit-transform', - 'OTransform': '-o-transform', - 'msTransform': '-ms-transform', - 'MozTransform': '-moz-transform', - 'transform': 'transform' - }; - document.body.appendChild(el); - for (var t in transforms) { - if (t in el.style) { - el.style[t] = 'translate3d(1px,1px,1px)'; - has3d = goog.global.getComputedStyle(el).getPropertyValue( - transforms[t]); - } - } - goog.dom.removeNode(el); - - canUseCssTransform3D = (has3d && has3d !== 'none'); - } - } - return canUseCssTransform3D; - }; -}()); +goog.style.getClientPositionForElement_ = function(el) { + var box = goog.style.getBoundingClientRect_(el); + return new goog.math.Coordinate(box.left, box.top); +}; /** - * @param {Element} element Element. - * @param {string} value Value. + * Returns the position of the event or the element's border box relative to + * the client viewport. If an event is passed, and if this event is a "touch" + * event, then the position of the first changedTouches will be returned. + * @param {Element|Event|goog.events.Event} el Element or a mouse / touch event. + * @return {!goog.math.Coordinate} The position. */ -ol.dom.setTransform = function(element, value) { - var style = element.style; - style.WebkitTransform = value; - style.MozTransform = value; - style.OTransform = value; - style.msTransform = value; - style.transform = value; - - // IE 9+ seems to assume transform-origin: 100% 100%; for some unknown reason - if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9.0')) { - element.style.transformOrigin = '0 0'; +goog.style.getClientPosition = function(el) { + goog.asserts.assert(el); + if (el.nodeType == goog.dom.NodeType.ELEMENT) { + return goog.style.getClientPositionForElement_( + /** @type {!Element} */ (el)); + } else { + var targetEvent = el.changedTouches ? el.changedTouches[0] : el; + return new goog.math.Coordinate( + targetEvent.clientX, + targetEvent.clientY); } }; /** - * @param {!Element} element Element. - * @param {goog.vec.Mat4.Number} transform Matrix. - * @param {number=} opt_precision Precision. + * Moves an element to the given coordinates relative to the client viewport. + * @param {Element} el Absolutely positioned element to set page offset for. + * It must be in the document. + * @param {number|goog.math.Coordinate} x Left position of the element's margin + * box or a coordinate object. + * @param {number=} opt_y Top position of the element's margin box. */ -ol.dom.transformElement2D = function(element, transform, opt_precision) { - // using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer - // matrix3d() - var i; - if (ol.dom.canUseCssTransform3D()) { - var value3D; - - if (opt_precision !== undefined) { - /** @type {Array.<string>} */ - var strings3D = new Array(16); - for (i = 0; i < 16; ++i) { - strings3D[i] = transform[i].toFixed(opt_precision); - } - value3D = strings3D.join(','); - } else { - value3D = transform.join(','); - } - ol.dom.setTransform(element, 'matrix3d(' + value3D + ')'); - } else if (ol.dom.canUseCssTransform()) { - /** @type {Array.<number>} */ - var transform2D = [ - goog.vec.Mat4.getElement(transform, 0, 0), - goog.vec.Mat4.getElement(transform, 1, 0), - goog.vec.Mat4.getElement(transform, 0, 1), - goog.vec.Mat4.getElement(transform, 1, 1), - goog.vec.Mat4.getElement(transform, 0, 3), - goog.vec.Mat4.getElement(transform, 1, 3) - ]; - var value2D; - if (opt_precision !== undefined) { - /** @type {Array.<string>} */ - var strings2D = new Array(6); - for (i = 0; i < 6; ++i) { - strings2D[i] = transform2D[i].toFixed(opt_precision); - } - value2D = strings2D.join(','); - } else { - value2D = transform2D.join(','); - } - ol.dom.setTransform(element, 'matrix(' + value2D + ')'); - } else { - element.style.left = - Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px'; - element.style.top = - Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px'; +goog.style.setPageOffset = function(el, x, opt_y) { + // Get current pageoffset + var cur = goog.style.getPageOffset(el); - // TODO: Add scaling here. This isn't quite as simple as multiplying - // width/height, because that only changes the container size, not the - // content size. + if (x instanceof goog.math.Coordinate) { + opt_y = x.y; + x = x.x; } -}; + // NOTE(arv): We cannot allow strings for x and y. We could but that would + // require us to manually transform between different units -/** - * Get the current computed width for the given element including margin, - * padding and border. - * Equivalent to jQuery's `$(el).outerWidth(true)`. - * @param {!Element} element Element. - * @return {number} - */ -ol.dom.outerWidth = function(element) { - var width = element.offsetWidth; - var style = element.currentStyle || window.getComputedStyle(element); - width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); + // Work out deltas + var dx = x - cur.x; + var dy = opt_y - cur.y; - return width; + // Set position to current left/top + delta + goog.style.setPosition(el, /** @type {!HTMLElement} */ (el).offsetLeft + dx, + /** @type {!HTMLElement} */ (el).offsetTop + dy); }; /** - * Get the current computed height for the given element including margin, - * padding and border. - * Equivalent to jQuery's `$(el).outerHeight(true)`. - * @param {!Element} element Element. - * @return {number} + * Sets the width/height values of an element. If an argument is numeric, + * or a goog.math.Size is passed, it is assumed to be pixels and will add + * 'px' after converting it to an integer in string form. (This just sets the + * CSS width and height properties so it might set content-box or border-box + * size depending on the box model the browser is using.) + * + * @param {Element} element Element to set the size of. + * @param {string|number|goog.math.Size} w Width of the element, or a + * size object. + * @param {string|number=} opt_h Height of the element. Required if w is not a + * size object. */ -ol.dom.outerHeight = function(element) { - var height = element.offsetHeight; - var style = element.currentStyle || window.getComputedStyle(element); - height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10); +goog.style.setSize = function(element, w, opt_h) { + var h; + if (w instanceof goog.math.Size) { + h = w.height; + w = w.width; + } else { + if (opt_h == undefined) { + throw Error('missing height argument'); + } + h = opt_h; + } - return height; + goog.style.setWidth(element, /** @type {string|number} */ (w)); + goog.style.setHeight(element, h); }; -goog.provide('ol.webgl'); -goog.provide('ol.webgl.WebGLContextEventType'); - /** - * @const + * Helper function to create a string to be set into a pixel-value style + * property of an element. Can round to the nearest integer value. + * + * @param {string|number} value The style value to be used. If a number, + * 'px' will be appended, otherwise the value will be applied directly. + * @param {boolean} round Whether to round the nearest integer (if property + * is a number). + * @return {string} The string value for the property. * @private - * @type {Array.<string>} */ -ol.webgl.CONTEXT_IDS_ = [ - 'experimental-webgl', - 'webgl', - 'webkit-3d', - 'moz-webgl' -]; - +goog.style.getPixelStyleValue_ = function(value, round) { + if (typeof value == 'number') { + value = (round ? Math.round(value) : value) + 'px'; + } -/** - * @enum {string} - */ -ol.webgl.WebGLContextEventType = { - LOST: 'webglcontextlost', - RESTORED: 'webglcontextrestored' + return value; }; /** - * @param {HTMLCanvasElement} canvas Canvas. - * @param {Object=} opt_attributes Attributes. - * @return {WebGLRenderingContext} WebGL rendering context. + * Set the height of an element. Sets the element's style property. + * @param {Element} element Element to set the height of. + * @param {string|number} height The height value to set. If a number, 'px' + * will be appended, otherwise the value will be applied directly. */ -ol.webgl.getContext = function(canvas, opt_attributes) { - var context, i, ii = ol.webgl.CONTEXT_IDS_.length; - for (i = 0; i < ii; ++i) { - try { - context = canvas.getContext(ol.webgl.CONTEXT_IDS_[i], opt_attributes); - if (context) { - return /** @type {!WebGLRenderingContext} */ (context); - } - } catch (e) { - } - } - return null; +goog.style.setHeight = function(element, height) { + element.style.height = goog.style.getPixelStyleValue_(height, true); }; -goog.provide('ol.has'); - -goog.require('goog.dom'); -goog.require('ol'); -goog.require('ol.dom'); -goog.require('ol.webgl'); - /** - * The ratio between physical pixels and device-independent pixels - * (dips) on the device (`window.devicePixelRatio`). - * @const - * @type {number} - * @api stable + * Set the width of an element. Sets the element's style property. + * @param {Element} element Element to set the width of. + * @param {string|number} width The width value to set. If a number, 'px' + * will be appended, otherwise the value will be applied directly. */ -ol.has.DEVICE_PIXEL_RATIO = goog.global.devicePixelRatio || 1; +goog.style.setWidth = function(element, width) { + element.style.width = goog.style.getPixelStyleValue_(width, true); +}; /** - * True if the browser's Canvas implementation implements {get,set}LineDash. - * @type {boolean} + * Gets the height and width of an element, even if its display is none. + * + * Specifically, this returns the height and width of the border box, + * irrespective of the box model in effect. + * + * Note that this function does not take CSS transforms into account. Please see + * {@code goog.style.getTransformedSize}. + * @param {Element} element Element to get size of. + * @return {!goog.math.Size} Object with width/height properties. */ -ol.has.CANVAS_LINE_DASH = false; +goog.style.getSize = function(element) { + return goog.style.evaluateWithTemporaryDisplay_( + goog.style.getSizeWithDisplay_, /** @type {!Element} */ (element)); +}; /** - * True if both the library and browser support Canvas. Always `false` - * if `ol.ENABLE_CANVAS` is set to `false` at compile time. - * @const - * @type {boolean} - * @api stable + * Call {@code fn} on {@code element} such that {@code element}'s dimensions are + * accurate when it's passed to {@code fn}. + * @param {function(!Element): T} fn Function to call with {@code element} as + * an argument after temporarily changing {@code element}'s display such + * that its dimensions are accurate. + * @param {!Element} element Element (which may have display none) to use as + * argument to {@code fn}. + * @return {T} Value returned by calling {@code fn} with {@code element}. + * @template T + * @private */ -ol.has.CANVAS = ol.ENABLE_CANVAS && ( - /** - * @return {boolean} Canvas supported. - */ - function() { - if (!('HTMLCanvasElement' in goog.global)) { - return false; - } - try { - var context = ol.dom.createCanvasContext2D(); - if (!context) { - return false; - } else { - if (context.setLineDash !== undefined) { - ol.has.CANVAS_LINE_DASH = true; - } - return true; - } - } catch (e) { - return false; - } - })(); +goog.style.evaluateWithTemporaryDisplay_ = function(fn, element) { + if (goog.style.getStyle_(element, 'display') != 'none') { + return fn(element); + } + var style = element.style; + var originalDisplay = style.display; + var originalVisibility = style.visibility; + var originalPosition = style.position; -/** - * Indicates if DeviceOrientation is supported in the user's browser. - * @const - * @type {boolean} - * @api stable - */ -ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in goog.global; + style.visibility = 'hidden'; + style.position = 'absolute'; + style.display = 'inline'; + var retVal = fn(element); -/** - * True if `ol.ENABLE_DOM` is set to `true` at compile time. - * @const - * @type {boolean} - */ -ol.has.DOM = ol.ENABLE_DOM; + style.display = originalDisplay; + style.position = originalPosition; + style.visibility = originalVisibility; + + return retVal; +}; /** - * Is HTML5 geolocation supported in the current browser? - * @const - * @type {boolean} - * @api stable + * Gets the height and width of an element when the display is not none. + * @param {Element} element Element to get size of. + * @return {!goog.math.Size} Object with width/height properties. + * @private */ -ol.has.GEOLOCATION = 'geolocation' in goog.global.navigator; +goog.style.getSizeWithDisplay_ = function(element) { + var offsetWidth = /** @type {!HTMLElement} */ (element).offsetWidth; + var offsetHeight = /** @type {!HTMLElement} */ (element).offsetHeight; + var webkitOffsetsZero = + goog.userAgent.WEBKIT && !offsetWidth && !offsetHeight; + if ((!goog.isDef(offsetWidth) || webkitOffsetsZero) && + element.getBoundingClientRect) { + // Fall back to calling getBoundingClientRect when offsetWidth or + // offsetHeight are not defined, or when they are zero in WebKit browsers. + // This makes sure that we return for the correct size for SVG elements, but + // will still return 0 on Webkit prior to 534.8, see + // http://trac.webkit.org/changeset/67252. + var clientRect = goog.style.getBoundingClientRect_(element); + return new goog.math.Size(clientRect.right - clientRect.left, + clientRect.bottom - clientRect.top); + } + return new goog.math.Size(offsetWidth, offsetHeight); +}; /** - * True if browser supports touch events. - * @const - * @type {boolean} - * @api stable - */ -ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in goog.global; - - -/** - * True if browser supports pointer events. - * @const - * @type {boolean} - */ -ol.has.POINTER = 'PointerEvent' in goog.global; - - -/** - * True if browser supports ms pointer events (IE 10). - * @const - * @type {boolean} - */ -ol.has.MSPOINTER = !!(goog.global.navigator.msPointerEnabled); - - -/** - * True if both OpenLayers and browser support WebGL. Always `false` - * if `ol.ENABLE_WEBGL` is set to `false` at compile time. - * @const - * @type {boolean} - * @api stable + * Gets the height and width of an element, post transform, even if its display + * is none. + * + * This is like {@code goog.style.getSize}, except: + * <ol> + * <li>Takes webkitTransforms such as rotate and scale into account. + * <li>Will return null if {@code element} doesn't respond to + * {@code getBoundingClientRect}. + * <li>Currently doesn't make sense on non-WebKit browsers which don't support + * webkitTransforms. + * </ol> + * @param {!Element} element Element to get size of. + * @return {goog.math.Size} Object with width/height properties. */ -ol.has.WEBGL; - - -(function() { - if (ol.ENABLE_WEBGL) { - var hasWebGL = false; - var textureSize; - var /** @type {Array.<string>} */ extensions = []; - - if ('WebGLRenderingContext' in goog.global) { - try { - var canvas = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - var gl = ol.webgl.getContext(canvas, { - failIfMajorPerformanceCaveat: true - }); - if (gl) { - hasWebGL = true; - textureSize = /** @type {number} */ - (gl.getParameter(gl.MAX_TEXTURE_SIZE)); - extensions = gl.getSupportedExtensions(); - } - } catch (e) {} - } - ol.has.WEBGL = hasWebGL; - ol.WEBGL_EXTENSIONS = extensions; - ol.WEBGL_MAX_TEXTURE_SIZE = textureSize; +goog.style.getTransformedSize = function(element) { + if (!element.getBoundingClientRect) { + return null; } -})(); - -goog.provide('ol.pointer.EventSource'); - -goog.require('goog.events.BrowserEvent'); + var clientRect = goog.style.evaluateWithTemporaryDisplay_( + goog.style.getBoundingClientRect_, element); + return new goog.math.Size(clientRect.right - clientRect.left, + clientRect.bottom - clientRect.top); +}; /** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @param {!Object.<string, function(goog.events.BrowserEvent)>} mapping - * @constructor + * Returns a bounding rectangle for a given element in page space. + * @param {Element} element Element to get bounds of. Must not be display none. + * @return {!goog.math.Rect} Bounding rectangle for the element. */ -ol.pointer.EventSource = function(dispatcher, mapping) { - /** - * @type {ol.pointer.PointerEventHandler} - */ - this.dispatcher = dispatcher; - - /** - * @private - * @const - * @type {!Object.<string, function(goog.events.BrowserEvent)>} - */ - this.mapping_ = mapping; +goog.style.getBounds = function(element) { + var o = goog.style.getPageOffset(element); + var s = goog.style.getSize(element); + return new goog.math.Rect(o.x, o.y, s.width, s.height); }; /** - * List of events supported by this source. - * @return {Array.<string>} Event names + * Converts a CSS selector in the form style-property to styleProperty. + * @param {*} selector CSS Selector. + * @return {string} Camel case selector. + * @deprecated Use goog.string.toCamelCase instead. */ -ol.pointer.EventSource.prototype.getEvents = function() { - return Object.keys(this.mapping_); +goog.style.toCamelCase = function(selector) { + return goog.string.toCamelCase(String(selector)); }; /** - * Returns a mapping between the supported event types and - * the handlers that should handle an event. - * @return {Object.<string, function(goog.events.BrowserEvent)>} - * Event/Handler mapping + * Converts a CSS selector in the form styleProperty to style-property. + * @param {string} selector Camel case selector. + * @return {string} Selector cased. + * @deprecated Use goog.string.toSelectorCase instead. */ -ol.pointer.EventSource.prototype.getMapping = function() { - return this.mapping_; +goog.style.toSelectorCase = function(selector) { + return goog.string.toSelectorCase(selector); }; /** - * Returns the handler that should handle a given event type. - * @param {string} eventType - * @return {function(goog.events.BrowserEvent)} Handler + * Gets the opacity of a node (x-browser). This gets the inline style opacity + * of the node, and does not take into account the cascaded or the computed + * style for this node. + * @param {Element} el Element whose opacity has to be found. + * @return {number|string} Opacity between 0 and 1 or an empty string {@code ''} + * if the opacity is not set. */ -ol.pointer.EventSource.prototype.getHandlerForEvent = function(eventType) { - return this.mapping_[eventType]; +goog.style.getOpacity = function(el) { + var style = el.style; + var result = ''; + if ('opacity' in style) { + result = style.opacity; + } else if ('MozOpacity' in style) { + result = style.MozOpacity; + } else if ('filter' in style) { + var match = style.filter.match(/alpha\(opacity=([\d.]+)\)/); + if (match) { + result = String(match[1] / 100); + } + } + return result == '' ? result : Number(result); }; -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.MouseSource'); - -goog.require('ol.pointer.EventSource'); - - /** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @constructor - * @extends {ol.pointer.EventSource} + * Sets the opacity of a node (x-browser). + * @param {Element} el Elements whose opacity has to be set. + * @param {number|string} alpha Opacity between 0 and 1 or an empty string + * {@code ''} to clear the opacity. */ -ol.pointer.MouseSource = function(dispatcher) { - var mapping = { - 'mousedown': this.mousedown, - 'mousemove': this.mousemove, - 'mouseup': this.mouseup, - 'mouseover': this.mouseover, - 'mouseout': this.mouseout - }; - goog.base(this, dispatcher, mapping); - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = dispatcher.pointerMap; - - /** - * @const - * @type {Array.<ol.Pixel>} - */ - this.lastTouches = []; +goog.style.setOpacity = function(el, alpha) { + var style = el.style; + if ('opacity' in style) { + style.opacity = alpha; + } else if ('MozOpacity' in style) { + style.MozOpacity = alpha; + } else if ('filter' in style) { + // TODO(arv): Overwriting the filter might have undesired side effects. + if (alpha === '') { + style.filter = ''; + } else { + style.filter = 'alpha(opacity=' + alpha * 100 + ')'; + } + } }; -goog.inherits(ol.pointer.MouseSource, ol.pointer.EventSource); /** - * @const - * @type {number} + * Sets the background of an element to a transparent image in a browser- + * independent manner. + * + * This function does not support repeating backgrounds or alternate background + * positions to match the behavior of Internet Explorer. It also does not + * support sizingMethods other than crop since they cannot be replicated in + * browsers other than Internet Explorer. + * + * @param {Element} el The element to set background on. + * @param {string} src The image source URL. */ -ol.pointer.MouseSource.POINTER_ID = 1; +goog.style.setTransparentBackgroundImage = function(el, src) { + var style = el.style; + // It is safe to use the style.filter in IE only. In Safari 'filter' is in + // style object but access to style.filter causes it to throw an exception. + // Note: IE8 supports images with an alpha channel. + if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { + // See TODO in setOpacity. + style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(' + + 'src="' + src + '", sizingMethod="crop")'; + } else { + // Set style properties individually instead of using background shorthand + // to prevent overwriting a pre-existing background color. + style.backgroundImage = 'url(' + src + ')'; + style.backgroundPosition = 'top left'; + style.backgroundRepeat = 'no-repeat'; + } +}; /** - * @const - * @type {string} + * Clears the background image of an element in a browser independent manner. + * @param {Element} el The element to clear background image for. */ -ol.pointer.MouseSource.POINTER_TYPE = 'mouse'; +goog.style.clearTransparentBackgroundImage = function(el) { + var style = el.style; + if ('filter' in style) { + // See TODO in setOpacity. + style.filter = ''; + } else { + // Set style properties individually instead of using background shorthand + // to prevent overwriting a pre-existing background color. + style.backgroundImage = 'none'; + } +}; /** - * Radius around touchend that swallows mouse events. + * Shows or hides an element from the page. Hiding the element is done by + * setting the display property to "none", removing the element from the + * rendering hierarchy so it takes up no space. To show the element, the default + * inherited display property is restored (defined either in stylesheets or by + * the browser's default style rules.) * - * @const - * @type {number} + * Caveat 1: if the inherited display property for the element is set to "none" + * by the stylesheets, that is the property that will be restored by a call to + * showElement(), effectively toggling the display between "none" and "none". + * + * Caveat 2: if the element display style is set inline (by setting either + * element.style.display or a style attribute in the HTML), a call to + * showElement will clear that setting and defer to the inherited style in the + * stylesheet. + * @param {Element} el Element to show or hide. + * @param {*} display True to render the element in its default style, + * false to disable rendering the element. + * @deprecated Use goog.style.setElementShown instead. */ -ol.pointer.MouseSource.DEDUP_DIST = 25; +goog.style.showElement = function(el, display) { + goog.style.setElementShown(el, display); +}; /** - * Detect if a mouse event was simulated from a touch by - * checking if previously there was a touch event at the - * same position. + * Shows or hides an element from the page. Hiding the element is done by + * setting the display property to "none", removing the element from the + * rendering hierarchy so it takes up no space. To show the element, the default + * inherited display property is restored (defined either in stylesheets or by + * the browser's default style rules). * - * FIXME - Known problem with the native Android browser on - * Samsung GT-I9100 (Android 4.1.2): - * In case the page is scrolled, this function does not work - * correctly when a canvas is used (WebGL or canvas renderer). - * Mouse listeners on canvas elements (for this browser), create - * two mouse events: One 'good' and one 'bad' one (on other browsers or - * when a div is used, there is only one event). For the 'bad' one, - * clientX/clientY and also pageX/pageY are wrong when the page - * is scrolled. Because of that, this function can not detect if - * the events were simulated from a touch event. As result, a - * pointer event at a wrong position is dispatched, which confuses - * the map interactions. - * It is unclear, how one can get the correct position for the event - * or detect that the positions are invalid. + * Caveat 1: if the inherited display property for the element is set to "none" + * by the stylesheets, that is the property that will be restored by a call to + * setElementShown(), effectively toggling the display between "none" and + * "none". * - * @private - * @param {goog.events.BrowserEvent} inEvent - * @return {boolean} True, if the event was generated by a touch. + * Caveat 2: if the element display style is set inline (by setting either + * element.style.display or a style attribute in the HTML), a call to + * setElementShown will clear that setting and defer to the inherited style in + * the stylesheet. + * @param {Element} el Element to show or hide. + * @param {*} isShown True to render the element in its default style, + * false to disable rendering the element. */ -ol.pointer.MouseSource.prototype.isEventSimulatedFromTouch_ = - function(inEvent) { - var lts = this.lastTouches; - var x = inEvent.clientX, y = inEvent.clientY; - for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) { - // simulated mouse events will be swallowed near a primary touchend - var dx = Math.abs(x - t[0]), dy = Math.abs(y - t[1]); - if (dx <= ol.pointer.MouseSource.DEDUP_DIST && - dy <= ol.pointer.MouseSource.DEDUP_DIST) { - return true; - } - } - return false; +goog.style.setElementShown = function(el, isShown) { + el.style.display = isShown ? '' : 'none'; }; /** - * Creates a copy of the original event that will be used - * for the fake pointer event. + * Test whether the given element has been shown or hidden via a call to + * {@link #setElementShown}. * - * @param {goog.events.BrowserEvent} inEvent - * @param {ol.pointer.PointerEventHandler} dispatcher - * @return {Object} + * Note this is strictly a companion method for a call + * to {@link #setElementShown} and the same caveats apply; in particular, this + * method does not guarantee that the return value will be consistent with + * whether or not the element is actually visible. + * + * @param {Element} el The element to test. + * @return {boolean} Whether the element has been shown. + * @see #setElementShown */ -ol.pointer.MouseSource.prepareEvent = function(inEvent, dispatcher) { - var e = dispatcher.cloneEvent(inEvent, inEvent.getBrowserEvent()); - - // forward mouse preventDefault - var pd = e.preventDefault; - e.preventDefault = function() { - inEvent.preventDefault(); - pd(); - }; - - e.pointerId = ol.pointer.MouseSource.POINTER_ID; - e.isPrimary = true; - e.pointerType = ol.pointer.MouseSource.POINTER_TYPE; - - return e; +goog.style.isElementShown = function(el) { + return el.style.display != 'none'; }; /** - * Handler for `mousedown`. - * - * @param {goog.events.BrowserEvent} inEvent + * Installs the styles string into the window that contains opt_element. If + * opt_element is null, the main window is used. + * @param {string} stylesString The style string to install. + * @param {Node=} opt_node Node whose parent document should have the + * styles installed. + * @return {Element|StyleSheet} The style element created. */ -ol.pointer.MouseSource.prototype.mousedown = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - // TODO(dfreedman) workaround for some elements not sending mouseup - // http://crbug/149091 - if (ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap) { - this.cancel(inEvent); +goog.style.installStyles = function(stylesString, opt_node) { + var dh = goog.dom.getDomHelper(opt_node); + var styleSheet = null; + + // IE < 11 requires createStyleSheet. Note that doc.createStyleSheet will be + // undefined as of IE 11. + var doc = dh.getDocument(); + if (goog.userAgent.IE && doc.createStyleSheet) { + styleSheet = doc.createStyleSheet(); + goog.style.setStyles(styleSheet, stylesString); + } else { + var head = dh.getElementsByTagNameAndClass(goog.dom.TagName.HEAD)[0]; + + // In opera documents are not guaranteed to have a head element, thus we + // have to make sure one exists before using it. + if (!head) { + var body = dh.getElementsByTagNameAndClass(goog.dom.TagName.BODY)[0]; + head = dh.createDom(goog.dom.TagName.HEAD); + body.parentNode.insertBefore(head, body); } - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()] = inEvent; - this.dispatcher.down(e, inEvent); + styleSheet = dh.createDom(goog.dom.TagName.STYLE); + // NOTE(user): Setting styles after the style element has been appended + // to the head results in a nasty Webkit bug in certain scenarios. Please + // refer to https://bugs.webkit.org/show_bug.cgi?id=26307 for additional + // details. + goog.style.setStyles(styleSheet, stylesString); + dh.appendChild(head, styleSheet); } + return styleSheet; }; /** - * Handler for `mousemove`. - * - * @param {goog.events.BrowserEvent} inEvent + * Removes the styles added by {@link #installStyles}. + * @param {Element|StyleSheet} styleSheet The value returned by + * {@link #installStyles}. */ -ol.pointer.MouseSource.prototype.mousemove = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.move(e, inEvent); - } +goog.style.uninstallStyles = function(styleSheet) { + var node = styleSheet.ownerNode || styleSheet.owningElement || + /** @type {Element} */ (styleSheet); + goog.dom.removeNode(node); }; /** - * Handler for `mouseup`. - * - * @param {goog.events.BrowserEvent} inEvent + * Sets the content of a style element. The style element can be any valid + * style element. This element will have its content completely replaced by + * the new stylesString. + * @param {Element|StyleSheet} element A stylesheet element as returned by + * installStyles. + * @param {string} stylesString The new content of the stylesheet. */ -ol.pointer.MouseSource.prototype.mouseup = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var p = this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()]; - - if (p && p.button === inEvent.button) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.up(e, inEvent); - this.cleanupMouse(); - } +goog.style.setStyles = function(element, stylesString) { + if (goog.userAgent.IE && goog.isDef(element.cssText)) { + // Adding the selectors individually caused the browser to hang if the + // selector was invalid or there were CSS comments. Setting the cssText of + // the style node works fine and ignores CSS that IE doesn't understand. + // However IE >= 11 doesn't support cssText any more, so we make sure that + // cssText is a defined property and otherwise fall back to innerHTML. + element.cssText = stylesString; + } else { + element.innerHTML = stylesString; } }; /** - * Handler for `mouseover`. + * Sets 'white-space: pre-wrap' for a node (x-browser). * - * @param {goog.events.BrowserEvent} inEvent + * There are as many ways of specifying pre-wrap as there are browsers. + * + * CSS3/IE8: white-space: pre-wrap; + * Mozilla: white-space: -moz-pre-wrap; + * Opera: white-space: -o-pre-wrap; + * IE6/7: white-space: pre; word-wrap: break-word; + * + * @param {Element} el Element to enable pre-wrap for. */ -ol.pointer.MouseSource.prototype.mouseover = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.enterOver(e, inEvent); +goog.style.setPreWrap = function(el) { + var style = el.style; + if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { + style.whiteSpace = 'pre'; + style.wordWrap = 'break-word'; + } else if (goog.userAgent.GECKO) { + style.whiteSpace = '-moz-pre-wrap'; + } else { + style.whiteSpace = 'pre-wrap'; } }; /** - * Handler for `mouseout`. - * - * @param {goog.events.BrowserEvent} inEvent + * Sets 'display: inline-block' for an element (cross-browser). + * @param {Element} el Element to which the inline-block display style is to be + * applied. + * @see ../demos/inline_block_quirks.html + * @see ../demos/inline_block_standards.html */ -ol.pointer.MouseSource.prototype.mouseout = function(inEvent) { - if (!this.isEventSimulatedFromTouch_(inEvent)) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.leaveOut(e, inEvent); - } -}; +goog.style.setInlineBlock = function(el) { + var style = el.style; + // Without position:relative, weirdness ensues. Just accept it and move on. + style.position = 'relative'; - -/** - * Dispatches a `pointercancel` event. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MouseSource.prototype.cancel = function(inEvent) { - var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); - this.dispatcher.cancel(e, inEvent); - this.cleanupMouse(); + if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) { + // IE8 supports inline-block so fall through to the else + // Zoom:1 forces hasLayout, display:inline gives inline behavior. + style.zoom = '1'; + style.display = 'inline'; + } else { + // Opera, Webkit, and Safari seem to do OK with the standard inline-block + // style. + style.display = 'inline-block'; + } }; /** - * Remove the mouse from the list of active pointers. + * Returns true if the element is using right to left (rtl) direction. + * @param {Element} el The element to test. + * @return {boolean} True for right to left, false for left to right. */ -ol.pointer.MouseSource.prototype.cleanupMouse = function() { - delete this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()]; +goog.style.isRightToLeft = function(el) { + return 'rtl' == goog.style.getStyle_(el, 'direction'); }; -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.MsSource'); - -goog.require('ol.pointer.EventSource'); - - /** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @constructor - * @extends {ol.pointer.EventSource} + * The CSS style property corresponding to an element being + * unselectable on the current browser platform (null if none). + * Opera and IE instead use a DOM attribute 'unselectable'. + * @type {?string} + * @private */ -ol.pointer.MsSource = function(dispatcher) { - var mapping = { - 'MSPointerDown': this.msPointerDown, - 'MSPointerMove': this.msPointerMove, - 'MSPointerUp': this.msPointerUp, - 'MSPointerOut': this.msPointerOut, - 'MSPointerOver': this.msPointerOver, - 'MSPointerCancel': this.msPointerCancel, - 'MSGotPointerCapture': this.msGotPointerCapture, - 'MSLostPointerCapture': this.msLostPointerCapture - }; - goog.base(this, dispatcher, mapping); - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = dispatcher.pointerMap; - - /** - * @const - * @type {Array.<string>} - */ - this.POINTER_TYPES = [ - '', - 'unavailable', - 'touch', - 'pen', - 'mouse' - ]; -}; -goog.inherits(ol.pointer.MsSource, ol.pointer.EventSource); +goog.style.unselectableStyle_ = + goog.userAgent.GECKO ? 'MozUserSelect' : + goog.userAgent.WEBKIT ? 'WebkitUserSelect' : + null; /** - * Creates a copy of the original event that will be used - * for the fake pointer event. - * - * @private - * @param {goog.events.BrowserEvent} inEvent - * @return {Object} + * Returns true if the element is set to be unselectable, false otherwise. + * Note that on some platforms (e.g. Mozilla), even if an element isn't set + * to be unselectable, it will behave as such if any of its ancestors is + * unselectable. + * @param {Element} el Element to check. + * @return {boolean} Whether the element is set to be unselectable. */ -ol.pointer.MsSource.prototype.prepareEvent_ = function(inEvent) { - var e = inEvent; - if (goog.isNumber(inEvent.getBrowserEvent().pointerType)) { - e = this.dispatcher.cloneEvent(inEvent, inEvent.getBrowserEvent()); - e.pointerType = this.POINTER_TYPES[inEvent.getBrowserEvent().pointerType]; +goog.style.isUnselectable = function(el) { + if (goog.style.unselectableStyle_) { + return el.style[goog.style.unselectableStyle_].toLowerCase() == 'none'; + } else if (goog.userAgent.IE || goog.userAgent.OPERA) { + return el.getAttribute('unselectable') == 'on'; } - - return e; + return false; }; /** - * Remove this pointer from the list of active pointers. - * @param {number} pointerId + * Makes the element and its descendants selectable or unselectable. Note + * that on some platforms (e.g. Mozilla), even if an element isn't set to + * be unselectable, it will behave as such if any of its ancestors is + * unselectable. + * @param {Element} el The element to alter. + * @param {boolean} unselectable Whether the element and its descendants + * should be made unselectable. + * @param {boolean=} opt_noRecurse Whether to only alter the element's own + * selectable state, and leave its descendants alone; defaults to false. */ -ol.pointer.MsSource.prototype.cleanup = function(pointerId) { - delete this.pointerMap[pointerId.toString()]; +goog.style.setUnselectable = function(el, unselectable, opt_noRecurse) { + // TODO(attila): Do we need all of TR_DomUtil.makeUnselectable() in Closure? + var descendants = !opt_noRecurse ? el.getElementsByTagName('*') : null; + var name = goog.style.unselectableStyle_; + if (name) { + // Add/remove the appropriate CSS style to/from the element and its + // descendants. + var value = unselectable ? 'none' : ''; + // MathML elements do not have a style property. Verify before setting. + if (el.style) { + el.style[name] = value; + } + if (descendants) { + for (var i = 0, descendant; descendant = descendants[i]; i++) { + if (descendant.style) { + descendant.style[name] = value; + } + } + } + } else if (goog.userAgent.IE || goog.userAgent.OPERA) { + // Toggle the 'unselectable' attribute on the element and its descendants. + var value = unselectable ? 'on' : ''; + el.setAttribute('unselectable', value); + if (descendants) { + for (var i = 0, descendant; descendant = descendants[i]; i++) { + descendant.setAttribute('unselectable', value); + } + } + } }; /** - * Handler for `msPointerDown`. - * - * @param {goog.events.BrowserEvent} inEvent + * Gets the border box size for an element. + * @param {Element} element The element to get the size for. + * @return {!goog.math.Size} The border box size. */ -ol.pointer.MsSource.prototype.msPointerDown = function(inEvent) { - this.pointerMap[inEvent.getBrowserEvent().pointerId.toString()] = inEvent; - var e = this.prepareEvent_(inEvent); - this.dispatcher.down(e, inEvent); +goog.style.getBorderBoxSize = function(element) { + return new goog.math.Size( + /** @type {!HTMLElement} */ (element).offsetWidth, + /** @type {!HTMLElement} */ (element).offsetHeight); }; /** - * Handler for `msPointerMove`. - * - * @param {goog.events.BrowserEvent} inEvent + * Sets the border box size of an element. This is potentially expensive in IE + * if the document is CSS1Compat mode + * @param {Element} element The element to set the size on. + * @param {goog.math.Size} size The new size. */ -ol.pointer.MsSource.prototype.msPointerMove = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.move(e, inEvent); -}; - +goog.style.setBorderBoxSize = function(element, size) { + var doc = goog.dom.getOwnerDocument(element); + var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode(); -/** - * Handler for `msPointerUp`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msPointerUp = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.up(e, inEvent); - this.cleanup(inEvent.getBrowserEvent().pointerId); + if (goog.userAgent.IE && + !goog.userAgent.isVersionOrHigher('10') && + (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) { + var style = element.style; + if (isCss1CompatMode) { + var paddingBox = goog.style.getPaddingBox(element); + var borderBox = goog.style.getBorderBox(element); + style.pixelWidth = size.width - borderBox.left - paddingBox.left - + paddingBox.right - borderBox.right; + style.pixelHeight = size.height - borderBox.top - paddingBox.top - + paddingBox.bottom - borderBox.bottom; + } else { + style.pixelWidth = size.width; + style.pixelHeight = size.height; + } + } else { + goog.style.setBoxSizingSize_(element, size, 'border-box'); + } }; /** - * Handler for `msPointerOut`. - * - * @param {goog.events.BrowserEvent} inEvent + * Gets the content box size for an element. This is potentially expensive in + * all browsers. + * @param {Element} element The element to get the size for. + * @return {!goog.math.Size} The content box size. */ -ol.pointer.MsSource.prototype.msPointerOut = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.leaveOut(e, inEvent); +goog.style.getContentBoxSize = function(element) { + var doc = goog.dom.getOwnerDocument(element); + var ieCurrentStyle = goog.userAgent.IE && element.currentStyle; + if (ieCurrentStyle && + goog.dom.getDomHelper(doc).isCss1CompatMode() && + ieCurrentStyle.width != 'auto' && ieCurrentStyle.height != 'auto' && + !ieCurrentStyle.boxSizing) { + // If IE in CSS1Compat mode than just use the width and height. + // If we have a boxSizing then fall back on measuring the borders etc. + var width = goog.style.getIePixelValue_(element, ieCurrentStyle.width, + 'width', 'pixelWidth'); + var height = goog.style.getIePixelValue_(element, ieCurrentStyle.height, + 'height', 'pixelHeight'); + return new goog.math.Size(width, height); + } else { + var borderBoxSize = goog.style.getBorderBoxSize(element); + var paddingBox = goog.style.getPaddingBox(element); + var borderBox = goog.style.getBorderBox(element); + return new goog.math.Size(borderBoxSize.width - + borderBox.left - paddingBox.left - + paddingBox.right - borderBox.right, + borderBoxSize.height - + borderBox.top - paddingBox.top - + paddingBox.bottom - borderBox.bottom); + } }; /** - * Handler for `msPointerOver`. - * - * @param {goog.events.BrowserEvent} inEvent + * Sets the content box size of an element. This is potentially expensive in IE + * if the document is BackCompat mode. + * @param {Element} element The element to set the size on. + * @param {goog.math.Size} size The new size. */ -ol.pointer.MsSource.prototype.msPointerOver = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.enterOver(e, inEvent); +goog.style.setContentBoxSize = function(element, size) { + var doc = goog.dom.getOwnerDocument(element); + var isCss1CompatMode = goog.dom.getDomHelper(doc).isCss1CompatMode(); + if (goog.userAgent.IE && + !goog.userAgent.isVersionOrHigher('10') && + (!isCss1CompatMode || !goog.userAgent.isVersionOrHigher('8'))) { + var style = element.style; + if (isCss1CompatMode) { + style.pixelWidth = size.width; + style.pixelHeight = size.height; + } else { + var paddingBox = goog.style.getPaddingBox(element); + var borderBox = goog.style.getBorderBox(element); + style.pixelWidth = size.width + borderBox.left + paddingBox.left + + paddingBox.right + borderBox.right; + style.pixelHeight = size.height + borderBox.top + paddingBox.top + + paddingBox.bottom + borderBox.bottom; + } + } else { + goog.style.setBoxSizingSize_(element, size, 'content-box'); + } }; /** - * Handler for `msPointerCancel`. - * - * @param {goog.events.BrowserEvent} inEvent + * Helper function that sets the box sizing as well as the width and height + * @param {Element} element The element to set the size on. + * @param {goog.math.Size} size The new size to set. + * @param {string} boxSizing The box-sizing value. + * @private */ -ol.pointer.MsSource.prototype.msPointerCancel = function(inEvent) { - var e = this.prepareEvent_(inEvent); - this.dispatcher.cancel(e, inEvent); - this.cleanup(inEvent.getBrowserEvent().pointerId); -}; - +goog.style.setBoxSizingSize_ = function(element, size, boxSizing) { + var style = element.style; + if (goog.userAgent.GECKO) { + style.MozBoxSizing = boxSizing; + } else if (goog.userAgent.WEBKIT) { + style.WebkitBoxSizing = boxSizing; + } else { + // Includes IE8 and Opera 9.50+ + style.boxSizing = boxSizing; + } -/** - * Handler for `msLostPointerCapture`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.MsSource.prototype.msLostPointerCapture = function(inEvent) { - var e = this.dispatcher.makeEvent('lostpointercapture', - inEvent.getBrowserEvent(), inEvent); - this.dispatcher.dispatchEvent(e); + // Setting this to a negative value will throw an exception on IE + // (and doesn't do anything different than setting it to 0). + style.width = Math.max(size.width, 0) + 'px'; + style.height = Math.max(size.height, 0) + 'px'; }; /** - * Handler for `msGotPointerCapture`. - * - * @param {goog.events.BrowserEvent} inEvent + * IE specific function that converts a non pixel unit to pixels. + * @param {Element} element The element to convert the value for. + * @param {string} value The current value as a string. The value must not be + * ''. + * @param {string} name The CSS property name to use for the converstion. This + * should be 'left', 'top', 'width' or 'height'. + * @param {string} pixelName The CSS pixel property name to use to get the + * value in pixels. + * @return {number} The value in pixels. + * @private */ -ol.pointer.MsSource.prototype.msGotPointerCapture = function(inEvent) { - var e = this.dispatcher.makeEvent('gotpointercapture', - inEvent.getBrowserEvent(), inEvent); - this.dispatcher.dispatchEvent(e); +goog.style.getIePixelValue_ = function(element, value, name, pixelName) { + // Try if we already have a pixel value. IE does not do half pixels so we + // only check if it matches a number followed by 'px'. + if (/^\d+px?$/.test(value)) { + return parseInt(value, 10); + } else { + var oldStyleValue = element.style[name]; + var oldRuntimeValue = element.runtimeStyle[name]; + // set runtime style to prevent changes + element.runtimeStyle[name] = element.currentStyle[name]; + element.style[name] = value; + var pixelValue = element.style[pixelName]; + // restore + element.style[name] = oldStyleValue; + element.runtimeStyle[name] = oldRuntimeValue; + return pixelValue; + } }; -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.NativeSource'); - -goog.require('ol.pointer.EventSource'); - - /** - * @param {ol.pointer.PointerEventHandler} dispatcher - * @constructor - * @extends {ol.pointer.EventSource} + * Helper function for getting the pixel padding or margin for IE. + * @param {Element} element The element to get the padding for. + * @param {string} propName The property name. + * @return {number} The pixel padding. + * @private */ -ol.pointer.NativeSource = function(dispatcher) { - var mapping = { - 'pointerdown': this.pointerDown, - 'pointermove': this.pointerMove, - 'pointerup': this.pointerUp, - 'pointerout': this.pointerOut, - 'pointerover': this.pointerOver, - 'pointercancel': this.pointerCancel, - 'gotpointercapture': this.gotPointerCapture, - 'lostpointercapture': this.lostPointerCapture - }; - goog.base(this, dispatcher, mapping); +goog.style.getIePixelDistance_ = function(element, propName) { + var value = goog.style.getCascadedStyle(element, propName); + return value ? + goog.style.getIePixelValue_(element, value, 'left', 'pixelLeft') : 0; }; -goog.inherits(ol.pointer.NativeSource, ol.pointer.EventSource); /** - * Handler for `pointerdown`. - * - * @param {goog.events.BrowserEvent} inEvent + * Gets the computed paddings or margins (on all sides) in pixels. + * @param {Element} element The element to get the padding for. + * @param {string} stylePrefix Pass 'padding' to retrieve the padding box, + * or 'margin' to retrieve the margin box. + * @return {!goog.math.Box} The computed paddings or margins. + * @private */ -ol.pointer.NativeSource.prototype.pointerDown = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); +goog.style.getBox_ = function(element, stylePrefix) { + if (goog.userAgent.IE) { + var left = goog.style.getIePixelDistance_(element, stylePrefix + 'Left'); + var right = goog.style.getIePixelDistance_(element, stylePrefix + 'Right'); + var top = goog.style.getIePixelDistance_(element, stylePrefix + 'Top'); + var bottom = goog.style.getIePixelDistance_( + element, stylePrefix + 'Bottom'); + return new goog.math.Box(top, right, bottom, left); + } else { + // On non-IE browsers, getComputedStyle is always non-null. + var left = goog.style.getComputedStyle(element, stylePrefix + 'Left'); + var right = goog.style.getComputedStyle(element, stylePrefix + 'Right'); + var top = goog.style.getComputedStyle(element, stylePrefix + 'Top'); + var bottom = goog.style.getComputedStyle(element, stylePrefix + 'Bottom'); + + // NOTE(arv): Gecko can return floating point numbers for the computed + // style values. + return new goog.math.Box(parseFloat(top), + parseFloat(right), + parseFloat(bottom), + parseFloat(left)); + } }; /** - * Handler for `pointermove`. - * - * @param {goog.events.BrowserEvent} inEvent + * Gets the computed paddings (on all sides) in pixels. + * @param {Element} element The element to get the padding for. + * @return {!goog.math.Box} The computed paddings. */ -ol.pointer.NativeSource.prototype.pointerMove = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); +goog.style.getPaddingBox = function(element) { + return goog.style.getBox_(element, 'padding'); }; /** - * Handler for `pointerup`. - * - * @param {goog.events.BrowserEvent} inEvent + * Gets the computed margins (on all sides) in pixels. + * @param {Element} element The element to get the margins for. + * @return {!goog.math.Box} The computed margins. */ -ol.pointer.NativeSource.prototype.pointerUp = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); +goog.style.getMarginBox = function(element) { + return goog.style.getBox_(element, 'margin'); }; /** - * Handler for `pointerout`. - * - * @param {goog.events.BrowserEvent} inEvent + * A map used to map the border width keywords to a pixel width. + * @type {Object} + * @private */ -ol.pointer.NativeSource.prototype.pointerOut = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); +goog.style.ieBorderWidthKeywords_ = { + 'thin': 2, + 'medium': 4, + 'thick': 6 }; /** - * Handler for `pointerover`. - * - * @param {goog.events.BrowserEvent} inEvent + * Helper function for IE to get the pixel border. + * @param {Element} element The element to get the pixel border for. + * @param {string} prop The part of the property name. + * @return {number} The value in pixels. + * @private */ -ol.pointer.NativeSource.prototype.pointerOver = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); +goog.style.getIePixelBorder_ = function(element, prop) { + if (goog.style.getCascadedStyle(element, prop + 'Style') == 'none') { + return 0; + } + var width = goog.style.getCascadedStyle(element, prop + 'Width'); + if (width in goog.style.ieBorderWidthKeywords_) { + return goog.style.ieBorderWidthKeywords_[width]; + } + return goog.style.getIePixelValue_(element, width, 'left', 'pixelLeft'); }; /** - * Handler for `pointercancel`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.pointerCancel = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - - -/** - * Handler for `lostpointercapture`. - * - * @param {goog.events.BrowserEvent} inEvent + * Gets the computed border widths (on all sides) in pixels + * @param {Element} element The element to get the border widths for. + * @return {!goog.math.Box} The computed border widths. */ -ol.pointer.NativeSource.prototype.lostPointerCapture = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); -}; - +goog.style.getBorderBox = function(element) { + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { + var left = goog.style.getIePixelBorder_(element, 'borderLeft'); + var right = goog.style.getIePixelBorder_(element, 'borderRight'); + var top = goog.style.getIePixelBorder_(element, 'borderTop'); + var bottom = goog.style.getIePixelBorder_(element, 'borderBottom'); + return new goog.math.Box(top, right, bottom, left); + } else { + // On non-IE browsers, getComputedStyle is always non-null. + var left = goog.style.getComputedStyle(element, 'borderLeftWidth'); + var right = goog.style.getComputedStyle(element, 'borderRightWidth'); + var top = goog.style.getComputedStyle(element, 'borderTopWidth'); + var bottom = goog.style.getComputedStyle(element, 'borderBottomWidth'); -/** - * Handler for `gotpointercapture`. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.NativeSource.prototype.gotPointerCapture = function(inEvent) { - this.dispatcher.fireNativeEvent(inEvent); + return new goog.math.Box(parseFloat(top), + parseFloat(right), + parseFloat(bottom), + parseFloat(left)); + } }; -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.TouchSource'); - -goog.require('goog.array'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.pointer.EventSource'); -goog.require('ol.pointer.MouseSource'); - - /** - * @constructor - * @param {ol.pointer.PointerEventHandler} dispatcher - * @param {ol.pointer.MouseSource} mouseSource - * @extends {ol.pointer.EventSource} + * Returns the font face applied to a given node. Opera and IE should return + * the font actually displayed. Firefox returns the author's most-preferred + * font (whether the browser is capable of displaying it or not.) + * @param {Element} el The element whose font family is returned. + * @return {string} The font family applied to el. */ -ol.pointer.TouchSource = function(dispatcher, mouseSource) { - var mapping = { - 'touchstart': this.touchstart, - 'touchmove': this.touchmove, - 'touchend': this.touchend, - 'touchcancel': this.touchcancel - }; - goog.base(this, dispatcher, mapping); - - /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} - */ - this.pointerMap = dispatcher.pointerMap; - - /** - * @const - * @type {ol.pointer.MouseSource} - */ - this.mouseSource = mouseSource; - - /** - * @private - * @type {number|undefined} - */ - this.firstTouchId_ = undefined; +goog.style.getFontFamily = function(el) { + var doc = goog.dom.getOwnerDocument(el); + var font = ''; + // The moveToElementText method from the TextRange only works if the element + // is attached to the owner document. + if (doc.body.createTextRange && goog.dom.contains(doc, el)) { + var range = doc.body.createTextRange(); + range.moveToElementText(el); + /** @preserveTry */ + try { + font = range.queryCommandValue('FontName'); + } catch (e) { + // This is a workaround for a awkward exception. + // On some IE, there is an exception coming from it. + // The error description from this exception is: + // This window has already been registered as a drop target + // This is bogus description, likely due to a bug in ie. + font = ''; + } + } + if (!font) { + // Note if for some reason IE can't derive FontName with a TextRange, we + // fallback to using currentStyle + font = goog.style.getStyle_(el, 'fontFamily'); + } - /** - * @private - * @type {number} - */ - this.clickCount_ = 0; + // Firefox returns the applied font-family string (author's list of + // preferred fonts.) We want to return the most-preferred font, in lieu of + // the *actually* applied font. + var fontsArray = font.split(','); + if (fontsArray.length > 1) font = fontsArray[0]; - /** - * @private - * @type {number|undefined} - */ - this.resetId_ = undefined; + // Sanitize for x-browser consistency: + // Strip quotes because browsers aren't consistent with how they're + // applied; Opera always encloses, Firefox sometimes, and IE never. + return goog.string.stripQuotes(font, '"\''); }; -goog.inherits(ol.pointer.TouchSource, ol.pointer.EventSource); - - -/** - * Mouse event timeout: This should be long enough to - * ignore compat mouse events made by touch. - * @const - * @type {number} - */ -ol.pointer.TouchSource.DEDUP_TIMEOUT = 2500; /** - * @const - * @type {number} + * Regular expression used for getLengthUnits. + * @type {RegExp} + * @private */ -ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT = 200; +goog.style.lengthUnitRegex_ = /[^\d]+$/; /** - * @const - * @type {string} + * Returns the units used for a CSS length measurement. + * @param {string} value A CSS length quantity. + * @return {?string} The units of measurement. */ -ol.pointer.TouchSource.POINTER_TYPE = 'touch'; +goog.style.getLengthUnits = function(value) { + var units = value.match(goog.style.lengthUnitRegex_); + return units && units[0] || null; +}; /** + * Map of absolute CSS length units + * @type {Object} * @private - * @param {Touch} inTouch - * @return {boolean} True, if this is the primary touch. */ -ol.pointer.TouchSource.prototype.isPrimaryTouch_ = function(inTouch) { - return this.firstTouchId_ === inTouch.identifier; +goog.style.ABSOLUTE_CSS_LENGTH_UNITS_ = { + 'cm' : 1, + 'in' : 1, + 'mm' : 1, + 'pc' : 1, + 'pt' : 1 }; /** - * Set primary touch if there are no pointers, or the only pointer is the mouse. - * @param {Touch} inTouch + * Map of relative CSS length units that can be accurately converted to px + * font-size values using getIePixelValue_. Only units that are defined in + * relation to a font size are convertible (%, small, etc. are not). + * @type {Object} * @private */ -ol.pointer.TouchSource.prototype.setPrimaryTouch_ = function(inTouch) { - var count = goog.object.getCount(this.pointerMap); - if (count === 0 || (count === 1 && goog.object.containsKey(this.pointerMap, - ol.pointer.MouseSource.POINTER_ID.toString()))) { - this.firstTouchId_ = inTouch.identifier; - this.cancelResetClickCount_(); - } +goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_ = { + 'em' : 1, + 'ex' : 1 }; /** - * @private - * @param {Object} inPointer + * Returns the font size, in pixels, of text in an element. + * @param {Element} el The element whose font size is returned. + * @return {number} The font size (in pixels). */ -ol.pointer.TouchSource.prototype.removePrimaryPointer_ = function(inPointer) { - if (inPointer.isPrimary) { - this.firstTouchId_ = undefined; - this.resetClickCount_(); +goog.style.getFontSize = function(el) { + var fontSize = goog.style.getStyle_(el, 'fontSize'); + var sizeUnits = goog.style.getLengthUnits(fontSize); + if (fontSize && 'px' == sizeUnits) { + // NOTE(user): This could be parseFloat instead, but IE doesn't return + // decimal fractions in getStyle_ and Firefox reports the fractions, but + // ignores them when rendering. Interestingly enough, when we force the + // issue and size something to e.g., 50% of 25px, the browsers round in + // opposite directions with Firefox reporting 12px and IE 13px. I punt. + return parseInt(fontSize, 10); + } + + // In IE, we can convert absolute length units to a px value using + // goog.style.getIePixelValue_. Units defined in relation to a font size + // (em, ex) are applied relative to the element's parentNode and can also + // be converted. + if (goog.userAgent.IE) { + if (sizeUnits in goog.style.ABSOLUTE_CSS_LENGTH_UNITS_) { + return goog.style.getIePixelValue_(el, + fontSize, + 'left', + 'pixelLeft'); + } else if (el.parentNode && + el.parentNode.nodeType == goog.dom.NodeType.ELEMENT && + sizeUnits in goog.style.CONVERTIBLE_RELATIVE_CSS_UNITS_) { + // Check the parent size - if it is the same it means the relative size + // value is inherited and we therefore don't want to count it twice. If + // it is different, this element either has explicit style or has a CSS + // rule applying to it. + var parentElement = /** @type {!Element} */ (el.parentNode); + var parentSize = goog.style.getStyle_(parentElement, 'fontSize'); + return goog.style.getIePixelValue_(parentElement, + fontSize == parentSize ? + '1em' : fontSize, + 'left', + 'pixelLeft'); + } } -}; + // Sometimes we can't cleanly find the font size (some units relative to a + // node's parent's font size are difficult: %, smaller et al), so we create + // an invisible, absolutely-positioned span sized to be the height of an 'M' + // rendered in its parent's (i.e., our target element's) font size. This is + // the definition of CSS's font size attribute. + var sizeElement = goog.dom.createDom( + goog.dom.TagName.SPAN, + {'style': 'visibility:hidden;position:absolute;' + + 'line-height:0;padding:0;margin:0;border:0;height:1em;'}); + goog.dom.appendChild(el, sizeElement); + fontSize = sizeElement.offsetHeight; + goog.dom.removeNode(sizeElement); -/** - * @private - */ -ol.pointer.TouchSource.prototype.resetClickCount_ = function() { - this.resetId_ = goog.global.setTimeout( - goog.bind(this.resetClickCountHandler_, this), - ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT); + return fontSize; }; /** - * @private + * Parses a style attribute value. Converts CSS property names to camel case. + * @param {string} value The style attribute value. + * @return {!Object} Map of CSS properties to string values. */ -ol.pointer.TouchSource.prototype.resetClickCountHandler_ = function() { - this.clickCount_ = 0; - this.resetId_ = undefined; +goog.style.parseStyleAttribute = function(value) { + var result = {}; + goog.array.forEach(value.split(/\s*;\s*/), function(pair) { + var keyValue = pair.match(/\s*([\w-]+)\s*\:(.+)/); + if (keyValue) { + var styleName = keyValue[1]; + var styleValue = goog.string.trim(keyValue[2]); + result[goog.string.toCamelCase(styleName.toLowerCase())] = styleValue; + } + }); + return result; }; /** - * @private + * Reverse of parseStyleAttribute; that is, takes a style object and returns the + * corresponding attribute value. Converts camel case property names to proper + * CSS selector names. + * @param {Object} obj Map of CSS properties to values. + * @return {string} The style attribute value. */ -ol.pointer.TouchSource.prototype.cancelResetClickCount_ = function() { - if (this.resetId_ !== undefined) { - goog.global.clearTimeout(this.resetId_); - } +goog.style.toStyleAttribute = function(obj) { + var buffer = []; + goog.object.forEach(obj, function(value, key) { + buffer.push(goog.string.toSelectorCase(key), ':', value, ';'); + }); + return buffer.join(''); }; /** - * @private - * @param {goog.events.BrowserEvent} browserEvent Browser event - * @param {Touch} inTouch Touch event - * @return {Object} + * Sets CSS float property on an element. + * @param {Element} el The element to set float property on. + * @param {string} value The value of float CSS property to set on this element. */ -ol.pointer.TouchSource.prototype.touchToPointer_ = - function(browserEvent, inTouch) { - var e = this.dispatcher.cloneEvent(browserEvent, inTouch); - // Spec specifies that pointerId 1 is reserved for Mouse. - // Touch identifiers can start at 0. - // Add 2 to the touch identifier for compatibility. - e.pointerId = inTouch.identifier + 2; - // TODO: check if this is necessary? - //e.target = findTarget(e); - e.bubbles = true; - e.cancelable = true; - e.detail = this.clickCount_; - e.button = 0; - e.buttons = 1; - e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; - e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; - e.pressure = inTouch.webkitForce || inTouch.force || 0.5; - e.isPrimary = this.isPrimaryTouch_(inTouch); - e.pointerType = ol.pointer.TouchSource.POINTER_TYPE; - - // make sure that the properties that are different for - // each `Touch` object are not copied from the BrowserEvent object - e.clientX = inTouch.clientX; - e.clientY = inTouch.clientY; - e.screenX = inTouch.screenX; - e.screenY = inTouch.screenY; - - return e; +goog.style.setFloat = function(el, value) { + el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] = value; }; /** - * @private - * @param {goog.events.BrowserEvent} inEvent Touch event - * @param {function(goog.events.BrowserEvent, Object)} inFunction + * Gets value of explicitly-set float CSS property on an element. + * @param {Element} el The element to get float property of. + * @return {string} The value of explicitly-set float CSS property on this + * element. */ -ol.pointer.TouchSource.prototype.processTouches_ = - function(inEvent, inFunction) { - var touches = Array.prototype.slice.call( - inEvent.getBrowserEvent().changedTouches); - var count = touches.length; - function preventDefault() { - inEvent.preventDefault(); - } - var i, pointer; - for (i = 0; i < count; ++i) { - pointer = this.touchToPointer_(inEvent, touches[i]); - // forward touch preventDefaults - pointer.preventDefault = preventDefault; - inFunction.call(this, inEvent, pointer); - } +goog.style.getFloat = function(el) { + return el.style[goog.userAgent.IE ? 'styleFloat' : 'cssFloat'] || ''; }; /** - * @private - * @param {TouchList} touchList - * @param {number} searchId - * @return {boolean} True, if the `Touch` with the given id is in the list. + * Returns the scroll bar width (represents the width of both horizontal + * and vertical scroll). + * + * @param {string=} opt_className An optional class name (or names) to apply + * to the invisible div created to measure the scrollbar. This is necessary + * if some scrollbars are styled differently than others. + * @return {number} The scroll bar width in px. */ -ol.pointer.TouchSource.prototype.findTouch_ = function(touchList, searchId) { - var l = touchList.length; - var touch; - for (var i = 0; i < l; i++) { - touch = touchList[i]; - if (touch.identifier === searchId) { - return true; - } +goog.style.getScrollbarWidth = function(opt_className) { + // Add two hidden divs. The child div is larger than the parent and + // forces scrollbars to appear on it. + // Using overflow:scroll does not work consistently with scrollbars that + // are styled with ::-webkit-scrollbar. + var outerDiv = goog.dom.createElement(goog.dom.TagName.DIV); + if (opt_className) { + outerDiv.className = opt_className; } - return false; + outerDiv.style.cssText = 'overflow:auto;' + + 'position:absolute;top:0;width:100px;height:100px'; + var innerDiv = goog.dom.createElement(goog.dom.TagName.DIV); + goog.style.setSize(innerDiv, '200px', '200px'); + outerDiv.appendChild(innerDiv); + goog.dom.appendChild(goog.dom.getDocument().body, outerDiv); + var width = outerDiv.offsetWidth - outerDiv.clientWidth; + goog.dom.removeNode(outerDiv); + return width; }; /** - * In some instances, a touchstart can happen without a touchend. This - * leaves the pointermap in a broken state. - * Therefore, on every touchstart, we remove the touches that did not fire a - * touchend event. - * To keep state globally consistent, we fire a pointercancel for - * this "abandoned" touch + * Regular expression to extract x and y translation components from a CSS + * transform Matrix representation. * + * @type {!RegExp} + * @const * @private - * @param {goog.events.BrowserEvent} inEvent */ -ol.pointer.TouchSource.prototype.vacuumTouches_ = function(inEvent) { - var touchList = inEvent.getBrowserEvent().touches; - // pointerMap.getCount() should be < touchList.length here, - // as the touchstart has not been processed yet. - var keys = goog.object.getKeys(this.pointerMap); - var count = keys.length; - if (count >= touchList.length) { - var d = []; - var i, key, value; - for (i = 0; i < count; ++i) { - key = keys[i]; - value = this.pointerMap[key]; - // Never remove pointerId == 1, which is mouse. - // Touch identifiers are 2 smaller than their pointerId, which is the - // index in pointermap. - if (key != ol.pointer.MouseSource.POINTER_ID && - !this.findTouch_(touchList, key - 2)) { - d.push(value.out); - } - } - for (i = 0; i < d.length; ++i) { - this.cancelOut_(inEvent, d[i]); - } - } -}; +goog.style.MATRIX_TRANSLATION_REGEX_ = + new RegExp('matrix\\([0-9\\.\\-]+, [0-9\\.\\-]+, ' + + '[0-9\\.\\-]+, [0-9\\.\\-]+, ' + + '([0-9\\.\\-]+)p?x?, ([0-9\\.\\-]+)p?x?\\)'); /** - * Handler for `touchstart`, triggers `pointerover`, - * `pointerenter` and `pointerdown` events. + * Returns the x,y translation component of any CSS transforms applied to the + * element, in pixels. * - * @param {goog.events.BrowserEvent} inEvent + * @param {!Element} element The element to get the translation of. + * @return {!goog.math.Coordinate} The CSS translation of the element in px. */ -ol.pointer.TouchSource.prototype.touchstart = function(inEvent) { - this.vacuumTouches_(inEvent); - this.setPrimaryTouch_(inEvent.getBrowserEvent().changedTouches[0]); - this.dedupSynthMouse_(inEvent); - this.clickCount_++; - this.processTouches_(inEvent, this.overDown_); +goog.style.getCssTranslation = function(element) { + var transform = goog.style.getComputedTransform(element); + if (!transform) { + return new goog.math.Coordinate(0, 0); + } + var matches = transform.match(goog.style.MATRIX_TRANSLATION_REGEX_); + if (!matches) { + return new goog.math.Coordinate(0, 0); + } + return new goog.math.Coordinate(parseFloat(matches[1]), + parseFloat(matches[2])); }; +goog.provide('ol.MapEvent'); +goog.provide('ol.MapEventType'); -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.overDown_ = function(browserEvent, inPointer) { - this.pointerMap[inPointer.pointerId] = { - target: inPointer.target, - out: inPointer, - outTarget: inPointer.target - }; - this.dispatcher.over(inPointer, browserEvent); - this.dispatcher.enter(inPointer, browserEvent); - this.dispatcher.down(inPointer, browserEvent); -}; +goog.require('goog.events.Event'); /** - * Handler for `touchmove`. - * - * @param {goog.events.BrowserEvent} inEvent + * @enum {string} */ -ol.pointer.TouchSource.prototype.touchmove = function(inEvent) { - inEvent.preventDefault(); - this.processTouches_(inEvent, this.moveOverOut_); -}; - +ol.MapEventType = { -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.moveOverOut_ = - function(browserEvent, inPointer) { - var event = inPointer; - var pointer = this.pointerMap[event.pointerId]; - // a finger drifted off the screen, ignore it - if (!pointer) { - return; - } - var outEvent = pointer.out; - var outTarget = pointer.outTarget; - this.dispatcher.move(event, browserEvent); - if (outEvent && outTarget !== event.target) { - outEvent.relatedTarget = event.target; - event.relatedTarget = outTarget; - // recover from retargeting by shadow - outEvent.target = outTarget; - if (event.target) { - this.dispatcher.leaveOut(outEvent, browserEvent); - this.dispatcher.enterOver(event, browserEvent); - } else { - // clean up case when finger leaves the screen - event.target = outTarget; - event.relatedTarget = null; - this.cancelOut_(browserEvent, event); - } - } - pointer.out = event; - pointer.outTarget = event.target; -}; + /** + * Triggered after a map frame is rendered. + * @event ol.MapEvent#postrender + * @api + */ + POSTRENDER: 'postrender', + /** + * Triggered after the map is moved. + * @event ol.MapEvent#moveend + * @api stable + */ + MOVEEND: 'moveend' -/** - * Handler for `touchend`, triggers `pointerup`, - * `pointerout` and `pointerleave` events. - * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.touchend = function(inEvent) { - this.dedupSynthMouse_(inEvent); - this.processTouches_(inEvent, this.upOut_); }; -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.upOut_ = function(browserEvent, inPointer) { - this.dispatcher.up(inPointer, browserEvent); - this.dispatcher.out(inPointer, browserEvent); - this.dispatcher.leave(inPointer, browserEvent); - this.cleanUpPointer_(inPointer); -}; - /** - * Handler for `touchcancel`, triggers `pointercancel`, - * `pointerout` and `pointerleave` events. + * @classdesc + * Events emitted as map events are instances of this type. + * See {@link ol.Map} for which events trigger a map event. * - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.touchcancel = function(inEvent) { - this.processTouches_(inEvent, this.cancelOut_); -}; - - -/** - * @private - * @param {goog.events.BrowserEvent} browserEvent - * @param {Object} inPointer + * @constructor + * @extends {goog.events.Event} + * @implements {oli.MapEvent} + * @param {string} type Event type. + * @param {ol.Map} map Map. + * @param {?olx.FrameState=} opt_frameState Frame state. */ -ol.pointer.TouchSource.prototype.cancelOut_ = - function(browserEvent, inPointer) { - this.dispatcher.cancel(inPointer, browserEvent); - this.dispatcher.out(inPointer, browserEvent); - this.dispatcher.leave(inPointer, browserEvent); - this.cleanUpPointer_(inPointer); -}; - +ol.MapEvent = function(type, map, opt_frameState) { -/** - * @private - * @param {Object} inPointer - */ -ol.pointer.TouchSource.prototype.cleanUpPointer_ = function(inPointer) { - delete this.pointerMap[inPointer.pointerId]; - this.removePrimaryPointer_(inPointer); -}; + goog.base(this, type); + /** + * The map where the event occurred. + * @type {ol.Map} + * @api stable + */ + this.map = map; -/** - * Prevent synth mouse events from creating pointer events. - * - * @private - * @param {goog.events.BrowserEvent} inEvent - */ -ol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) { - var lts = this.mouseSource.lastTouches; - var t = inEvent.getBrowserEvent().changedTouches[0]; - // only the primary finger will synth mouse events - if (this.isPrimaryTouch_(t)) { - // remember x/y of last touch - var lt = /** @type {ol.Pixel} */ ([t.clientX, t.clientY]); - lts.push(lt); + /** + * The frame state at the time of the event. + * @type {?olx.FrameState} + * @api + */ + this.frameState = opt_frameState !== undefined ? opt_frameState : null; - goog.global.setTimeout(function() { - // remove touch after timeout - goog.array.remove(lts, lt); - }, ol.pointer.TouchSource.DEDUP_TIMEOUT); - } }; +goog.inherits(ol.MapEvent, goog.events.Event); -// Based on https://github.com/Polymer/PointerEvents - -// Copyright (c) 2013 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -goog.provide('ol.pointer.PointerEventHandler'); +goog.provide('ol.control.Control'); goog.require('goog.dom'); goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); - -goog.require('ol.has'); -goog.require('ol.pointer.MouseSource'); -goog.require('ol.pointer.MsSource'); -goog.require('ol.pointer.NativeSource'); -goog.require('ol.pointer.PointerEvent'); -goog.require('ol.pointer.TouchSource'); +goog.require('ol'); +goog.require('ol.MapEventType'); +goog.require('ol.Object'); /** + * @classdesc + * A control is a visible widget with a DOM element in a fixed position on the + * screen. They can involve user input (buttons), or be informational only; + * the position is determined using CSS. By default these are placed in the + * container with CSS class name `ol-overlaycontainer-stopevent`, but can use + * any outside DOM element. + * + * This is the base class for controls. You can use it for simple custom + * controls by creating the element with listeners, creating an instance: + * ```js + * var myControl = new ol.control.Control({element: myElement}); + * ``` + * and then adding this to the map. + * + * The main advantage of having this as a control rather than a simple separate + * DOM element is that preventing propagation is handled for you. Controls + * will also be `ol.Object`s in a `ol.Collection`, so you can use their + * methods. + * + * You can also extend this base for your own control class. See + * examples/custom-controls for an example of how to do this. + * * @constructor - * @extends {goog.events.EventTarget} - * @param {Element|HTMLDocument} element Viewport element. + * @extends {ol.Object} + * @implements {oli.control.Control} + * @param {olx.control.ControlOptions} options Control options. + * @api stable */ -ol.pointer.PointerEventHandler = function(element) { +ol.control.Control = function(options) { + goog.base(this); /** - * @const - * @private - * @type {Element|HTMLDocument} + * @protected + * @type {Element} */ - this.element_ = element; + this.element = options.element ? options.element : null; /** - * @const - * @type {Object.<string, goog.events.BrowserEvent|Object>} + * @private + * @type {Element} */ - this.pointerMap = {}; + this.target_ = null; /** - * @type {Object.<string, function(goog.events.BrowserEvent)>} * @private + * @type {ol.Map} */ - this.eventMap_ = {}; + this.map_ = null; /** - * @type {Array.<ol.pointer.EventSource>} - * @private + * @protected + * @type {!Array.<?number>} */ - this.eventSourceList_ = []; - - this.registerSources(); -}; -goog.inherits(ol.pointer.PointerEventHandler, goog.events.EventTarget); - + this.listenerKeys = []; -/** - * Set up the event sources (mouse, touch and native pointers) - * that generate pointer events. - */ -ol.pointer.PointerEventHandler.prototype.registerSources = function() { - if (ol.has.POINTER) { - this.registerSource('native', new ol.pointer.NativeSource(this)); - } else if (ol.has.MSPOINTER) { - this.registerSource('ms', new ol.pointer.MsSource(this)); - } else { - var mouseSource = new ol.pointer.MouseSource(this); - this.registerSource('mouse', mouseSource); + /** + * @type {function(ol.MapEvent)} + */ + this.render = options.render ? options.render : ol.nullFunction; - if (ol.has.TOUCH) { - this.registerSource('touch', - new ol.pointer.TouchSource(this, mouseSource)); - } + if (options.target) { + this.setTarget(options.target); } - // register events on the viewport element - this.register_(); }; +goog.inherits(ol.control.Control, ol.Object); /** - * Add a new event source that will generate pointer events. - * - * @param {string} name A name for the event source - * @param {ol.pointer.EventSource} source + * @inheritDoc */ -ol.pointer.PointerEventHandler.prototype.registerSource = - function(name, source) { - var s = source; - var newEvents = s.getEvents(); - - if (newEvents) { - newEvents.forEach(function(e) { - var handler = s.getHandlerForEvent(e); - - if (handler) { - this.eventMap_[e] = goog.bind(handler, s); - } - }, this); - this.eventSourceList_.push(s); - } +ol.control.Control.prototype.disposeInternal = function() { + goog.dom.removeNode(this.element); + goog.base(this, 'disposeInternal'); }; /** - * Set up the events for all registered event sources. - * @private + * Get the map associated with this control. + * @return {ol.Map} Map. + * @api stable */ -ol.pointer.PointerEventHandler.prototype.register_ = function() { - var l = this.eventSourceList_.length; - var eventSource; - for (var i = 0; i < l; i++) { - eventSource = this.eventSourceList_[i]; - this.addEvents_(eventSource.getEvents()); - } +ol.control.Control.prototype.getMap = function() { + return this.map_; }; /** - * Remove all registered events. - * @private + * Remove the control from its current map and attach it to the new map. + * Subclasses may set up event handlers to get notified about changes to + * the map here. + * @param {ol.Map} map Map. + * @api stable */ -ol.pointer.PointerEventHandler.prototype.unregister_ = function() { - var l = this.eventSourceList_.length; - var eventSource; - for (var i = 0; i < l; i++) { - eventSource = this.eventSourceList_[i]; - this.removeEvents_(eventSource.getEvents()); +ol.control.Control.prototype.setMap = function(map) { + if (this.map_) { + goog.dom.removeNode(this.element); + } + if (this.listenerKeys.length > 0) { + this.listenerKeys.forEach(goog.events.unlistenByKey); + this.listenerKeys.length = 0; + } + this.map_ = map; + if (this.map_) { + var target = this.target_ ? + this.target_ : map.getOverlayContainerStopEvent(); + target.appendChild(this.element); + if (this.render !== ol.nullFunction) { + this.listenerKeys.push(goog.events.listen(map, + ol.MapEventType.POSTRENDER, this.render, false, this)); + } + map.render(); } }; /** - * Calls the right handler for a new event. - * @private - * @param {goog.events.BrowserEvent} inEvent Browser event. + * This function is used to set a target element for the control. It has no + * effect if it is called after the control has been added to the map (i.e. + * after `setMap` is called on the control). If no `target` is set in the + * options passed to the control constructor and if `setTarget` is not called + * then the control is added to the map's overlay container. + * @param {Element|string} target Target. + * @api */ -ol.pointer.PointerEventHandler.prototype.eventHandler_ = function(inEvent) { - var type = inEvent.type; - var handler = this.eventMap_[type]; - if (handler) { - handler(inEvent); - } +ol.control.Control.prototype.setTarget = function(target) { + this.target_ = goog.dom.getElement(target); }; +goog.provide('ol.css'); + /** - * Setup listeners for the given events. - * @private - * @param {Array.<string>} events List of events. + * The CSS class for hidden feature. + * + * @const + * @type {string} */ -ol.pointer.PointerEventHandler.prototype.addEvents_ = function(events) { - events.forEach(function(eventName) { - goog.events.listen(this.element_, eventName, - this.eventHandler_, false, this); - }, this); -}; +ol.css.CLASS_HIDDEN = 'ol-hidden'; /** - * Unregister listeners for the given events. - * @private - * @param {Array.<string>} events List of events. + * The CSS class that we'll give the DOM elements to have them unselectable. + * + * @const + * @type {string} */ -ol.pointer.PointerEventHandler.prototype.removeEvents_ = function(events) { - events.forEach(function(e) { - goog.events.unlisten(this.element_, e, - this.eventHandler_, false, this); - }, this); -}; +ol.css.CLASS_UNSELECTABLE = 'ol-unselectable'; /** - * Returns a snapshot of inEvent, with writable properties. + * The CSS class for unsupported feature. * - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @param {Event|Touch} inEvent An event that contains - * properties to copy. - * @return {Object} An object containing shallow copies of - * `inEvent`'s properties. + * @const + * @type {string} */ -ol.pointer.PointerEventHandler.prototype.cloneEvent = - function(browserEvent, inEvent) { - var eventCopy = {}, p; - for (var i = 0, ii = ol.pointer.CLONE_PROPS.length; i < ii; i++) { - p = ol.pointer.CLONE_PROPS[i][0]; - eventCopy[p] = - browserEvent[p] || - inEvent[p] || - ol.pointer.CLONE_PROPS[i][1]; - } - - return eventCopy; -}; - - -// EVENTS +ol.css.CLASS_UNSUPPORTED = 'ol-unsupported'; /** - * Triggers a 'pointerdown' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent + * The CSS class for controls. + * + * @const + * @type {string} */ -ol.pointer.PointerEventHandler.prototype.down = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERDOWN, - pointerEventData, browserEvent); -}; +ol.css.CLASS_CONTROL = 'ol-control'; +// FIXME handle date line wrap -/** - * Triggers a 'pointermove' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.move = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERMOVE, - pointerEventData, browserEvent); -}; +goog.provide('ol.control.Attribution'); +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.dom.classlist'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('goog.style'); +goog.require('ol'); +goog.require('ol.Attribution'); +goog.require('ol.control.Control'); +goog.require('ol.css'); +goog.require('ol.source.Tile'); -/** - * Triggers a 'pointerup' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.up = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERUP, - pointerEventData, browserEvent); -}; /** - * Triggers a 'pointerenter' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent + * @classdesc + * Control to show all the attributions associated with the layer sources + * in the map. This control is one of the default controls included in maps. + * By default it will show in the bottom right portion of the map, but this can + * be changed by using a css selector for `.ol-attribution`. + * + * @constructor + * @extends {ol.control.Control} + * @param {olx.control.AttributionOptions=} opt_options Attribution options. + * @api stable */ -ol.pointer.PointerEventHandler.prototype.enter = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = false; - this.fireEvent(ol.pointer.EventType.POINTERENTER, - pointerEventData, browserEvent); -}; +ol.control.Attribution = function(opt_options) { + var options = opt_options ? opt_options : {}; -/** - * Triggers a 'pointerleave' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.leave = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = false; - this.fireEvent(ol.pointer.EventType.POINTERLEAVE, - pointerEventData, browserEvent); -}; + /** + * @private + * @type {Element} + */ + this.ulElement_ = goog.dom.createElement('UL'); + /** + * @private + * @type {Element} + */ + this.logoLi_ = goog.dom.createElement('LI'); -/** - * Triggers a 'pointerover' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.over = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = true; - this.fireEvent(ol.pointer.EventType.POINTEROVER, - pointerEventData, browserEvent); -}; + this.ulElement_.appendChild(this.logoLi_); + goog.style.setElementShown(this.logoLi_, false); + /** + * @private + * @type {boolean} + */ + this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true; -/** - * Triggers a 'pointerout' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.out = - function(pointerEventData, browserEvent) { - pointerEventData.bubbles = true; - this.fireEvent(ol.pointer.EventType.POINTEROUT, - pointerEventData, browserEvent); -}; + /** + * @private + * @type {boolean} + */ + this.collapsible_ = options.collapsible !== undefined ? + options.collapsible : true; + if (!this.collapsible_) { + this.collapsed_ = false; + } + + var className = options.className ? options.className : 'ol-attribution'; + + var tipLabel = options.tipLabel ? options.tipLabel : 'Attributions'; + + var collapseLabel = options.collapseLabel ? options.collapseLabel : '\u00BB'; + + /** + * @private + * @type {Node} + */ + this.collapseLabel_ = goog.isString(collapseLabel) ? + goog.dom.createDom('SPAN', {}, collapseLabel) : + collapseLabel; + + var label = options.label ? options.label : 'i'; + + /** + * @private + * @type {Node} + */ + this.label_ = goog.isString(label) ? + goog.dom.createDom('SPAN', {}, label) : + label; + + var activeLabel = (this.collapsible_ && !this.collapsed_) ? + this.collapseLabel_ : this.label_; + var button = goog.dom.createDom('BUTTON', { + 'type': 'button', + 'title': tipLabel + }, activeLabel); + + goog.events.listen(button, goog.events.EventType.CLICK, + this.handleClick_, false, this); + + goog.events.listen(button, [ + goog.events.EventType.MOUSEOUT, + goog.events.EventType.FOCUSOUT + ], function() { + this.blur(); + }, false); + + var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + + ol.css.CLASS_CONTROL + + (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') + + (this.collapsible_ ? '' : ' ol-uncollapsible'); + var element = goog.dom.createDom('DIV', + cssClasses, this.ulElement_, button); + + var render = options.render ? options.render : ol.control.Attribution.render; + + goog.base(this, { + element: element, + render: render, + target: options.target + }); + + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = true; + + /** + * @private + * @type {Object.<string, Element>} + */ + this.attributionElements_ = {}; + + /** + * @private + * @type {Object.<string, boolean>} + */ + this.attributionElementRenderedVisible_ = {}; + + /** + * @private + * @type {Object.<string, Element>} + */ + this.logoElements_ = {}; -/** - * Triggers a 'pointercancel' event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - */ -ol.pointer.PointerEventHandler.prototype.cancel = - function(pointerEventData, browserEvent) { - this.fireEvent(ol.pointer.EventType.POINTERCANCEL, - pointerEventData, browserEvent); }; +goog.inherits(ol.control.Attribution, ol.control.Control); /** - * Triggers a combination of 'pointerout' and 'pointerleave' events. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent + * @param {?olx.FrameState} frameState Frame state. + * @return {Array.<Object.<string, ol.Attribution>>} Attributions. */ -ol.pointer.PointerEventHandler.prototype.leaveOut = - function(pointerEventData, browserEvent) { - this.out(pointerEventData, browserEvent); - if (!this.contains_( - pointerEventData.target, - pointerEventData.relatedTarget)) { - this.leave(pointerEventData, browserEvent); +ol.control.Attribution.prototype.getSourceAttributions = function(frameState) { + var i, ii, j, jj, tileRanges, source, sourceAttribution, + sourceAttributionKey, sourceAttributions, sourceKey; + var intersectsTileRange; + var layerStatesArray = frameState.layerStatesArray; + /** @type {Object.<string, ol.Attribution>} */ + var attributions = goog.object.clone(frameState.attributions); + /** @type {Object.<string, ol.Attribution>} */ + var hiddenAttributions = {}; + var projection = frameState.viewState.projection; + goog.asserts.assert(projection, 'projection of viewState required'); + for (i = 0, ii = layerStatesArray.length; i < ii; i++) { + source = layerStatesArray[i].layer.getSource(); + if (!source) { + continue; + } + sourceKey = goog.getUid(source).toString(); + sourceAttributions = source.getAttributions(); + if (!sourceAttributions) { + continue; + } + for (j = 0, jj = sourceAttributions.length; j < jj; j++) { + sourceAttribution = sourceAttributions[j]; + sourceAttributionKey = goog.getUid(sourceAttribution).toString(); + if (sourceAttributionKey in attributions) { + continue; + } + tileRanges = frameState.usedTiles[sourceKey]; + if (tileRanges) { + goog.asserts.assertInstanceof(source, ol.source.Tile, + 'source should be an ol.source.Tile'); + var tileGrid = source.getTileGridForProjection(projection); + goog.asserts.assert(tileGrid, 'tileGrid required for projection'); + intersectsTileRange = sourceAttribution.intersectsAnyTileRange( + tileRanges, tileGrid, projection); + } else { + intersectsTileRange = false; + } + if (intersectsTileRange) { + if (sourceAttributionKey in hiddenAttributions) { + delete hiddenAttributions[sourceAttributionKey]; + } + attributions[sourceAttributionKey] = sourceAttribution; + } else { + hiddenAttributions[sourceAttributionKey] = sourceAttribution; + } + } } + return [attributions, hiddenAttributions]; }; /** - * Triggers a combination of 'pointerover' and 'pointerevents' events. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent + * Update the attribution element. + * @param {ol.MapEvent} mapEvent Map event. + * @this {ol.control.Attribution} + * @api */ -ol.pointer.PointerEventHandler.prototype.enterOver = - function(pointerEventData, browserEvent) { - this.over(pointerEventData, browserEvent); - if (!this.contains_( - pointerEventData.target, - pointerEventData.relatedTarget)) { - this.enter(pointerEventData, browserEvent); - } +ol.control.Attribution.render = function(mapEvent) { + this.updateElement_(mapEvent.frameState); }; /** * @private - * @param {Element} container - * @param {Element} contained - * @return {boolean} Returns true if the container element - * contains the other element. + * @param {?olx.FrameState} frameState Frame state. */ -ol.pointer.PointerEventHandler.prototype.contains_ = - function(container, contained) { - if (!contained) { - return false; +ol.control.Attribution.prototype.updateElement_ = function(frameState) { + + if (!frameState) { + if (this.renderedVisible_) { + goog.style.setElementShown(this.element, false); + this.renderedVisible_ = false; + } + return; } - return goog.dom.contains(container, contained); + + var attributions = this.getSourceAttributions(frameState); + /** @type {Object.<string, ol.Attribution>} */ + var visibleAttributions = attributions[0]; + /** @type {Object.<string, ol.Attribution>} */ + var hiddenAttributions = attributions[1]; + + var attributionElement, attributionKey; + for (attributionKey in this.attributionElements_) { + if (attributionKey in visibleAttributions) { + if (!this.attributionElementRenderedVisible_[attributionKey]) { + goog.style.setElementShown( + this.attributionElements_[attributionKey], true); + this.attributionElementRenderedVisible_[attributionKey] = true; + } + delete visibleAttributions[attributionKey]; + } + else if (attributionKey in hiddenAttributions) { + if (this.attributionElementRenderedVisible_[attributionKey]) { + goog.style.setElementShown( + this.attributionElements_[attributionKey], false); + delete this.attributionElementRenderedVisible_[attributionKey]; + } + delete hiddenAttributions[attributionKey]; + } + else { + goog.dom.removeNode(this.attributionElements_[attributionKey]); + delete this.attributionElements_[attributionKey]; + delete this.attributionElementRenderedVisible_[attributionKey]; + } + } + for (attributionKey in visibleAttributions) { + attributionElement = goog.dom.createElement('LI'); + attributionElement.innerHTML = + visibleAttributions[attributionKey].getHTML(); + this.ulElement_.appendChild(attributionElement); + this.attributionElements_[attributionKey] = attributionElement; + this.attributionElementRenderedVisible_[attributionKey] = true; + } + for (attributionKey in hiddenAttributions) { + attributionElement = goog.dom.createElement('LI'); + attributionElement.innerHTML = + hiddenAttributions[attributionKey].getHTML(); + goog.style.setElementShown(attributionElement, false); + this.ulElement_.appendChild(attributionElement); + this.attributionElements_[attributionKey] = attributionElement; + } + + var renderVisible = + !goog.object.isEmpty(this.attributionElementRenderedVisible_) || + !goog.object.isEmpty(frameState.logos); + if (this.renderedVisible_ != renderVisible) { + goog.style.setElementShown(this.element, renderVisible); + this.renderedVisible_ = renderVisible; + } + if (renderVisible && + goog.object.isEmpty(this.attributionElementRenderedVisible_)) { + goog.dom.classlist.add(this.element, 'ol-logo-only'); + } else { + goog.dom.classlist.remove(this.element, 'ol-logo-only'); + } + + this.insertLogos_(frameState); + }; -// EVENT CREATION AND TRACKING /** - * Creates a new Event of type `inType`, based on the information in - * `pointerEventData`. - * - * @param {string} inType A string representing the type of event to create. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent - * @return {ol.pointer.PointerEvent} A PointerEvent of type `inType`. + * @param {?olx.FrameState} frameState Frame state. + * @private */ -ol.pointer.PointerEventHandler.prototype.makeEvent = - function(inType, pointerEventData, browserEvent) { - return new ol.pointer.PointerEvent(inType, browserEvent, pointerEventData); +ol.control.Attribution.prototype.insertLogos_ = function(frameState) { + + var logo; + var logos = frameState.logos; + var logoElements = this.logoElements_; + + for (logo in logoElements) { + if (!(logo in logos)) { + goog.dom.removeNode(logoElements[logo]); + delete logoElements[logo]; + } + } + + var image, logoElement, logoKey; + for (logoKey in logos) { + if (!(logoKey in logoElements)) { + image = new Image(); + image.src = logoKey; + var logoValue = logos[logoKey]; + if (logoValue === '') { + logoElement = image; + } else { + logoElement = goog.dom.createDom('A', { + 'href': logoValue + }); + logoElement.appendChild(image); + } + this.logoLi_.appendChild(logoElement); + logoElements[logoKey] = logoElement; + } + } + + goog.style.setElementShown(this.logoLi_, !goog.object.isEmpty(logos)); + }; /** - * Make and dispatch an event in one call. - * @param {string} inType A string representing the type of event. - * @param {Object} pointerEventData - * @param {goog.events.BrowserEvent} browserEvent + * @param {goog.events.BrowserEvent} event The event to handle + * @private */ -ol.pointer.PointerEventHandler.prototype.fireEvent = - function(inType, pointerEventData, browserEvent) { - var e = this.makeEvent(inType, pointerEventData, browserEvent); - this.dispatchEvent(e); +ol.control.Attribution.prototype.handleClick_ = function(event) { + event.preventDefault(); + this.handleToggle_(); }; /** - * Creates a pointer event from a native pointer event - * and dispatches this event. - * @param {goog.events.BrowserEvent} nativeEvent A platform event with a target. + * @private */ -ol.pointer.PointerEventHandler.prototype.fireNativeEvent = - function(nativeEvent) { - var e = this.makeEvent(nativeEvent.type, nativeEvent.getBrowserEvent(), - nativeEvent); - this.dispatchEvent(e); +ol.control.Attribution.prototype.handleToggle_ = function() { + goog.dom.classlist.toggle(this.element, 'ol-collapsed'); + if (this.collapsed_) { + goog.dom.replaceNode(this.collapseLabel_, this.label_); + } else { + goog.dom.replaceNode(this.label_, this.collapseLabel_); + } + this.collapsed_ = !this.collapsed_; }; /** - * Wrap a native mouse event into a pointer event. - * This proxy method is required for the legacy IE support. - * @param {string} eventType The pointer event type. - * @param {goog.events.BrowserEvent} browserEvent - * @return {ol.pointer.PointerEvent} + * Return `true` if the attribution is collapsible, `false` otherwise. + * @return {boolean} True if the widget is collapsible. + * @api stable */ -ol.pointer.PointerEventHandler.prototype.wrapMouseEvent = - function(eventType, browserEvent) { - var pointerEvent = this.makeEvent( - eventType, - ol.pointer.MouseSource.prepareEvent(browserEvent, this), - browserEvent - ); - return pointerEvent; +ol.control.Attribution.prototype.getCollapsible = function() { + return this.collapsible_; }; /** - * @inheritDoc + * Set whether the attribution should be collapsible. + * @param {boolean} collapsible True if the widget is collapsible. + * @api stable */ -ol.pointer.PointerEventHandler.prototype.disposeInternal = function() { - this.unregister_(); - goog.base(this, 'disposeInternal'); +ol.control.Attribution.prototype.setCollapsible = function(collapsible) { + if (this.collapsible_ === collapsible) { + return; + } + this.collapsible_ = collapsible; + goog.dom.classlist.toggle(this.element, 'ol-uncollapsible'); + if (!collapsible && this.collapsed_) { + this.handleToggle_(); + } }; /** - * Constants for event names. - * @enum {string} + * Collapse or expand the attribution according to the passed parameter. Will + * not do anything if the attribution isn't collapsible or if the current + * collapsed state is already the one requested. + * @param {boolean} collapsed True if the widget is collapsed. + * @api stable */ -ol.pointer.EventType = { - POINTERMOVE: 'pointermove', - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - POINTERCANCEL: 'pointercancel' +ol.control.Attribution.prototype.setCollapsed = function(collapsed) { + if (!this.collapsible_ || this.collapsed_ === collapsed) { + return; + } + this.handleToggle_(); }; /** - * Properties to copy when cloning an event, with default values. - * @type {Array.<Array>} + * Return `true` when the attribution is currently collapsed or `false` + * otherwise. + * @return {boolean} True if the widget is collapsed. + * @api stable */ -ol.pointer.CLONE_PROPS = [ - // MouseEvent - ['bubbles', false], - ['cancelable', false], - ['view', null], - ['detail', null], - ['screenX', 0], - ['screenY', 0], - ['clientX', 0], - ['clientY', 0], - ['ctrlKey', false], - ['altKey', false], - ['shiftKey', false], - ['metaKey', false], - ['button', 0], - ['relatedTarget', null], - // DOM Level 3 - ['buttons', 0], - // PointerEvent - ['pointerId', 0], - ['width', 0], - ['height', 0], - ['pressure', 0], - ['tiltX', 0], - ['tiltY', 0], - ['pointerType', ''], - ['hwTimestamp', 0], - ['isPrimary', false], - // event instance - ['type', ''], - ['target', null], - ['currentTarget', null], - ['which', 0] -]; +ol.control.Attribution.prototype.getCollapsed = function() { + return this.collapsed_; +}; -goog.provide('ol.MapBrowserEvent'); -goog.provide('ol.MapBrowserEvent.EventType'); -goog.provide('ol.MapBrowserEventHandler'); -goog.provide('ol.MapBrowserPointerEvent'); +goog.provide('ol.control.Rotate'); -goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.dom.classlist'); goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventTarget'); goog.require('goog.events.EventType'); -goog.require('goog.object'); goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.MapEvent'); -goog.require('ol.Pixel'); -goog.require('ol.pointer.PointerEvent'); -goog.require('ol.pointer.PointerEventHandler'); +goog.require('ol.animation'); +goog.require('ol.control.Control'); +goog.require('ol.css'); +goog.require('ol.easing'); /** * @classdesc - * Events emitted as map browser events are instances of this type. - * See {@link ol.Map} for which events trigger a map browser event. + * A button control to reset rotation to 0. + * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css + * selector is added to the button when the rotation is 0. * * @constructor - * @extends {ol.MapEvent} - * @implements {oli.MapBrowserEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @param {boolean=} opt_dragging Is the map currently being dragged? - * @param {?olx.FrameState=} opt_frameState Frame state. + * @extends {ol.control.Control} + * @param {olx.control.RotateOptions=} opt_options Rotate options. + * @api stable */ -ol.MapBrowserEvent = function(type, map, browserEvent, opt_dragging, - opt_frameState) { +ol.control.Rotate = function(opt_options) { - goog.base(this, type, map, opt_frameState); + var options = opt_options ? opt_options : {}; - /** - * @const - * @type {goog.events.BrowserEvent} - */ - this.browserEvent = browserEvent; + var className = options.className ? + options.className : 'ol-rotate'; - /** - * The original browser event. - * @const - * @type {Event} - * @api stable - */ - this.originalEvent = browserEvent.getBrowserEvent(); + var label = options.label ? options.label : '\u21E7'; /** - * The pixel of the original browser event. - * @type {ol.Pixel} - * @api stable + * @type {Element} + * @private */ - this.pixel = map.getEventPixel(this.originalEvent); + this.label_ = null; - /** - * The coordinate of the original browser event. - * @type {ol.Coordinate} - * @api stable - */ - this.coordinate = map.getCoordinateFromPixel(this.pixel); + if (goog.isString(label)) { + this.label_ = goog.dom.createDom('SPAN', + 'ol-compass', label); + } else { + this.label_ = label; + goog.dom.classlist.add(this.label_, 'ol-compass'); + } + + var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation'; + + var button = goog.dom.createDom('BUTTON', { + 'class': className + '-reset', + 'type' : 'button', + 'title': tipLabel + }, this.label_); + + goog.events.listen(button, goog.events.EventType.CLICK, + ol.control.Rotate.prototype.handleClick_, false, this); + + var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + + ol.css.CLASS_CONTROL; + var element = goog.dom.createDom('DIV', cssClasses, button); + + var render = options.render ? options.render : ol.control.Rotate.render; + + this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined; + + goog.base(this, { + element: element, + render: render, + target: options.target + }); + + /** + * @type {number} + * @private + */ + this.duration_ = options.duration !== undefined ? options.duration : 250; /** - * Indicates if the map is currently being dragged. Only set for - * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`. - * * @type {boolean} - * @api stable + * @private */ - this.dragging = opt_dragging !== undefined ? opt_dragging : false; + this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true; + + /** + * @private + * @type {number|undefined} + */ + this.rotation_ = undefined; + + if (this.autoHide_) { + goog.dom.classlist.add(this.element, ol.css.CLASS_HIDDEN); + } }; -goog.inherits(ol.MapBrowserEvent, ol.MapEvent); +goog.inherits(ol.control.Rotate, ol.control.Control); /** - * Prevents the default browser action. - * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault - * @override - * @api stable + * @param {goog.events.BrowserEvent} event The event to handle + * @private */ -ol.MapBrowserEvent.prototype.preventDefault = function() { - goog.base(this, 'preventDefault'); - this.browserEvent.preventDefault(); +ol.control.Rotate.prototype.handleClick_ = function(event) { + event.preventDefault(); + if (this.callResetNorth_ !== undefined) { + this.callResetNorth_(); + } else { + this.resetNorth_(); + } }; /** - * Prevents further propagation of the current event. - * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation - * @override - * @api stable + * @private */ -ol.MapBrowserEvent.prototype.stopPropagation = function() { - goog.base(this, 'stopPropagation'); - this.browserEvent.stopPropagation(); +ol.control.Rotate.prototype.resetNorth_ = function() { + var map = this.getMap(); + var view = map.getView(); + if (!view) { + // the map does not have a view, so we can't act + // upon it + return; + } + var currentRotation = view.getRotation(); + if (currentRotation !== undefined) { + if (this.duration_ > 0) { + currentRotation = currentRotation % (2 * Math.PI); + if (currentRotation < -Math.PI) { + currentRotation += 2 * Math.PI; + } + if (currentRotation > Math.PI) { + currentRotation -= 2 * Math.PI; + } + map.beforeRender(ol.animation.rotate({ + rotation: currentRotation, + duration: this.duration_, + easing: ol.easing.easeOut + })); + } + view.setRotation(0); + } }; - /** - * @constructor - * @extends {ol.MapBrowserEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @param {boolean=} opt_dragging Is the map currently being dragged? - * @param {?olx.FrameState=} opt_frameState Frame state. + * Update the rotate control element. + * @param {ol.MapEvent} mapEvent Map event. + * @this {ol.control.Rotate} + * @api */ -ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging, - opt_frameState) { - - goog.base(this, type, map, pointerEvent.browserEvent, opt_dragging, - opt_frameState); +ol.control.Rotate.render = function(mapEvent) { + var frameState = mapEvent.frameState; + if (!frameState) { + return; + } + var rotation = frameState.viewState.rotation; + if (rotation != this.rotation_) { + var transform = 'rotate(' + rotation + 'rad)'; + if (this.autoHide_) { + goog.dom.classlist.enable( + this.element, ol.css.CLASS_HIDDEN, rotation === 0); + } + this.label_.style.msTransform = transform; + this.label_.style.webkitTransform = transform; + this.label_.style.transform = transform; + } + this.rotation_ = rotation; +}; - /** - * @const - * @type {ol.pointer.PointerEvent} - */ - this.pointerEvent = pointerEvent; +goog.provide('ol.control.Zoom'); -}; -goog.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.animation'); +goog.require('ol.control.Control'); +goog.require('ol.css'); +goog.require('ol.easing'); /** - * @param {ol.Map} map The map with the viewport to listen to events on. + * @classdesc + * A control with 2 buttons, one for zoom in and one for zoom out. + * This control is one of the default controls of a map. To style this control + * use css selectors `.ol-zoom-in` and `.ol-zoom-out`. + * * @constructor - * @extends {goog.events.EventTarget} + * @extends {ol.control.Control} + * @param {olx.control.ZoomOptions=} opt_options Zoom options. + * @api stable */ -ol.MapBrowserEventHandler = function(map) { +ol.control.Zoom = function(opt_options) { - goog.base(this); + var options = opt_options ? opt_options : {}; - /** - * This is the element that we will listen to the real events on. - * @type {ol.Map} - * @private - */ - this.map_ = map; + var className = options.className ? options.className : 'ol-zoom'; - /** - * @type {number} - * @private - */ - this.clickTimeoutId_ = 0; + var delta = options.delta ? options.delta : 1; - /** - * @type {boolean} - * @private - */ - this.dragging_ = false; + var zoomInLabel = options.zoomInLabel ? options.zoomInLabel : '+'; + var zoomOutLabel = options.zoomOutLabel ? options.zoomOutLabel : '\u2212'; - /** - * @type {Array.<goog.events.Key>} - * @private - */ - this.dragListenerKeys_ = null; + var zoomInTipLabel = options.zoomInTipLabel ? + options.zoomInTipLabel : 'Zoom in'; + var zoomOutTipLabel = options.zoomOutTipLabel ? + options.zoomOutTipLabel : 'Zoom out'; - /** - * @type {goog.events.Key} - * @private - */ - this.pointerdownListenerKey_ = null; + var inElement = goog.dom.createDom('BUTTON', { + 'class': className + '-in', + 'type' : 'button', + 'title': zoomInTipLabel + }, zoomInLabel); - /** - * The most recent "down" type event (or null if none have occurred). - * Set on pointerdown. - * @type {ol.pointer.PointerEvent} - * @private - */ - this.down_ = null; + goog.events.listen(inElement, + goog.events.EventType.CLICK, goog.partial( + ol.control.Zoom.prototype.handleClick_, delta), false, this); - var element = this.map_.getViewport(); + var outElement = goog.dom.createDom('BUTTON', { + 'class': className + '-out', + 'type' : 'button', + 'title': zoomOutTipLabel + }, zoomOutLabel); - /** - * @type {number} - * @private - */ - this.activePointers_ = 0; + goog.events.listen(outElement, + goog.events.EventType.CLICK, goog.partial( + ol.control.Zoom.prototype.handleClick_, -delta), false, this); - /** - * @type {Object.<number, boolean>} - * @private - */ - this.trackedTouches_ = {}; + var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + + ol.css.CLASS_CONTROL; + var element = goog.dom.createDom('DIV', cssClasses, inElement, + outElement); - /** - * Event handler which generates pointer events for - * the viewport element. - * - * @type {ol.pointer.PointerEventHandler} - * @private - */ - this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element); + goog.base(this, { + element: element, + target: options.target + }); /** - * Event handler which generates pointer events for - * the document (used when dragging). - * - * @type {ol.pointer.PointerEventHandler} + * @type {number} * @private */ - this.documentPointerEventHandler_ = null; + this.duration_ = options.duration !== undefined ? options.duration : 250; - this.pointerdownListenerKey_ = goog.events.listen(this.pointerEventHandler_, - ol.pointer.EventType.POINTERDOWN, - this.handlePointerDown_, false, this); +}; +goog.inherits(ol.control.Zoom, ol.control.Control); - this.relayedListenerKey_ = goog.events.listen(this.pointerEventHandler_, - ol.pointer.EventType.POINTERMOVE, - this.relayEvent_, false, this); +/** + * @param {number} delta Zoom delta. + * @param {goog.events.BrowserEvent} event The event to handle + * @private + */ +ol.control.Zoom.prototype.handleClick_ = function(delta, event) { + event.preventDefault(); + this.zoomByDelta_(delta); }; -goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget); /** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @param {number} delta Zoom delta. * @private */ -ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) { - var newEvent; - newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - if (this.clickTimeoutId_ !== 0) { - // double-click - goog.global.clearTimeout(this.clickTimeoutId_); - this.clickTimeoutId_ = 0; - newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - } else { - // click - this.clickTimeoutId_ = goog.global.setTimeout(goog.bind(function() { - this.clickTimeoutId_ = 0; - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - }, this), 250); +ol.control.Zoom.prototype.zoomByDelta_ = function(delta) { + var map = this.getMap(); + var view = map.getView(); + if (!view) { + // the map does not have a view, so we can't act + // upon it + return; + } + var currentResolution = view.getResolution(); + if (currentResolution) { + if (this.duration_ > 0) { + map.beforeRender(ol.animation.zoom({ + resolution: currentResolution, + duration: this.duration_, + easing: ol.easing.easeOut + })); + } + var newResolution = view.constrainResolution(currentResolution, delta); + view.setResolution(newResolution); } }; +goog.provide('ol.control'); + +goog.require('ol'); +goog.require('ol.Collection'); +goog.require('ol.control.Attribution'); +goog.require('ol.control.Rotate'); +goog.require('ol.control.Zoom'); + /** - * Keeps track on how many pointers are currently active. + * Set of controls included in maps by default. Unless configured otherwise, + * this returns a collection containing an instance of each of the following + * controls: + * * {@link ol.control.Zoom} + * * {@link ol.control.Rotate} + * * {@link ol.control.Attribution} * - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private + * @param {olx.control.DefaultsOptions=} opt_options Defaults options. + * @return {ol.Collection.<ol.control.Control>} Controls. + * @api stable */ -ol.MapBrowserEventHandler.prototype.updateActivePointers_ = - function(pointerEvent) { - var event = pointerEvent; +ol.control.defaults = function(opt_options) { - if (event.type == ol.MapBrowserEvent.EventType.POINTERUP || - event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) { - delete this.trackedTouches_[event.pointerId]; - } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { - this.trackedTouches_[event.pointerId] = true; + var options = opt_options ? opt_options : {}; + + var controls = new ol.Collection(); + + var zoomControl = options.zoom !== undefined ? options.zoom : true; + if (zoomControl) { + controls.push(new ol.control.Zoom(options.zoomOptions)); } - this.activePointers_ = goog.object.getCount(this.trackedTouches_); + + var rotateControl = options.rotate !== undefined ? options.rotate : true; + if (rotateControl) { + controls.push(new ol.control.Rotate(options.rotateOptions)); + } + + var attributionControl = options.attribution !== undefined ? + options.attribution : true; + if (attributionControl) { + controls.push(new ol.control.Attribution(options.attributionOptions)); + } + + return controls; + }; +// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private + * @fileoverview Functions for managing full screen status of the DOM. + * */ -ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) { - this.updateActivePointers_(pointerEvent); - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - // We emulate click events on left mouse button click, touch contact, and pen - // contact. isMouseActionButton returns true in these cases (evt.button is set - // to 0). - // See http://www.w3.org/TR/pointerevents/#button-states - if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) { - goog.asserts.assert(this.down_, 'this.down_ must be truthy'); - this.emulateClick_(this.down_); - } +goog.provide('goog.dom.fullscreen'); +goog.provide('goog.dom.fullscreen.EventType'); - goog.asserts.assert(this.activePointers_ >= 0, - 'this.activePointers_ should be equal to or larger than 0'); - if (this.activePointers_ === 0) { - this.dragListenerKeys_.forEach(goog.events.unlistenByKey); - this.dragListenerKeys_ = null; - this.dragging_ = false; - this.down_ = null; - goog.dispose(this.documentPointerEventHandler_); - this.documentPointerEventHandler_ = null; - } -}; +goog.require('goog.dom'); +goog.require('goog.userAgent'); /** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @return {boolean} If the left mouse button was pressed. - * @private + * Event types for full screen. + * @enum {string} */ -ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = - function(pointerEvent) { - return pointerEvent.button === 0; +goog.dom.fullscreen.EventType = { + /** Dispatched by the Document when the fullscreen status changes. */ + CHANGE: (function() { + if (goog.userAgent.WEBKIT) { + return 'webkitfullscreenchange'; + } + if (goog.userAgent.GECKO) { + return 'mozfullscreenchange'; + } + if (goog.userAgent.IE) { + return 'MSFullscreenChange'; + } + // Opera 12-14, and W3C standard (Draft): + // https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html + return 'fullscreenchange'; + })() }; /** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private + * Determines if full screen is supported. + * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being + * queried. If not provided, use the current DOM. + * @return {boolean} True iff full screen is supported. */ -ol.MapBrowserEventHandler.prototype.handlePointerDown_ = - function(pointerEvent) { - this.updateActivePointers_(pointerEvent); - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - - this.down_ = pointerEvent; +goog.dom.fullscreen.isSupported = function(opt_domHelper) { + var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); + var body = doc.body; + return !!(body.webkitRequestFullscreen || + (body.mozRequestFullScreen && doc.mozFullScreenEnabled) || + (body.msRequestFullscreen && doc.msFullscreenEnabled) || + (body.requestFullscreen && doc.fullscreenEnabled)); +}; - if (!this.dragListenerKeys_) { - /* Set up a pointer event handler on the `document`, - * which is required when the pointer is moved outside - * the viewport when dragging. - */ - this.documentPointerEventHandler_ = - new ol.pointer.PointerEventHandler(document); - this.dragListenerKeys_ = [ - goog.events.listen(this.documentPointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERMOVE, - this.handlePointerMove_, false, this), - goog.events.listen(this.documentPointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERUP, - this.handlePointerUp_, false, this), - /* Note that the listener for `pointercancel is set up on - * `pointerEventHandler_` and not `documentPointerEventHandler_` like - * the `pointerup` and `pointermove` listeners. - * - * The reason for this is the following: `TouchSource.vacuumTouches_()` - * issues `pointercancel` events, when there was no `touchend` for a - * `touchstart`. Now, let's say a first `touchstart` is registered on - * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. - * But `documentPointerEventHandler_` doesn't know about the first - * `touchstart`. If there is no `touchend` for the `touchstart`, we can - * only receive a `touchcancel` from `pointerEventHandler_`, because it is - * only registered there. - */ - goog.events.listen(this.pointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERCANCEL, - this.handlePointerUp_, false, this) - ]; +/** + * Requests putting the element in full screen. + * @param {!Element} element The element to put full screen. + */ +goog.dom.fullscreen.requestFullScreen = function(element) { + if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } else if (element.requestFullscreen) { + element.requestFullscreen(); } }; /** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private + * Requests putting the element in full screen with full keyboard access. + * @param {!Element} element The element to put full screen. */ -ol.MapBrowserEventHandler.prototype.handlePointerMove_ = - function(pointerEvent) { - // Fix IE10 on windows Surface : When you tap the tablet, it triggers - // multiple pointermove events between pointerdown and pointerup with - // the exact same coordinates of the pointerdown event. To avoid a - // 'false' touchmove event to be dispatched , we test if the pointer - // effectively moved. - if (this.isMoving_(pointerEvent)) { - this.dragging_ = true; - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent, - this.dragging_); - this.dispatchEvent(newEvent); +goog.dom.fullscreen.requestFullScreenWithKeys = function( + element) { + if (element.mozRequestFullScreenWithKeys) { + element.mozRequestFullScreenWithKeys(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else { + goog.dom.fullscreen.requestFullScreen(element); } - - // Some native android browser triggers mousemove events during small period - // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or - // https://code.google.com/p/android/issues/detail?id=19827 - // ex: Galaxy Tab P3110 + Android 4.1.1 - pointerEvent.preventDefault(); }; /** - * Wrap and relay a pointer event. Note that this requires that the type - * string for the MapBrowserPointerEvent matches the PointerEvent type. - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private + * Exits full screen. + * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being + * queried. If not provided, use the current DOM. */ -ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) { - var dragging = !!(this.down_ && this.isMoving_(pointerEvent)); - this.dispatchEvent(new ol.MapBrowserPointerEvent( - pointerEvent.type, this.map_, pointerEvent, dragging)); +goog.dom.fullscreen.exitFullScreen = function(opt_domHelper) { + var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); + if (doc.webkitCancelFullScreen) { + doc.webkitCancelFullScreen(); + } else if (doc.mozCancelFullScreen) { + doc.mozCancelFullScreen(); + } else if (doc.msExitFullscreen) { + doc.msExitFullscreen(); + } else if (doc.exitFullscreen) { + doc.exitFullscreen(); + } }; /** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @return {boolean} - * @private + * Determines if the document is full screen. + * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being + * queried. If not provided, use the current DOM. + * @return {boolean} Whether the document is full screen. */ -ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) { - return pointerEvent.clientX != this.down_.clientX || - pointerEvent.clientY != this.down_.clientY; +goog.dom.fullscreen.isFullScreen = function(opt_domHelper) { + var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); + // IE 11 doesn't have similar boolean property, so check whether + // document.msFullscreenElement is null instead. + return !!(doc.webkitIsFullScreen || doc.mozFullScreen || + doc.msFullscreenElement || doc.fullscreenElement); }; /** - * @inheritDoc + * Get the root element in full screen mode. + * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being + * queried. If not provided, use the current DOM. + * @return {?Element} The root element in full screen mode. */ -ol.MapBrowserEventHandler.prototype.disposeInternal = function() { - if (this.relayedListenerKey_) { - goog.events.unlistenByKey(this.relayedListenerKey_); - this.relayedListenerKey_ = null; - } - if (this.pointerdownListenerKey_) { - goog.events.unlistenByKey(this.pointerdownListenerKey_); - this.pointerdownListenerKey_ = null; - } - if (this.dragListenerKeys_) { - this.dragListenerKeys_.forEach(goog.events.unlistenByKey); - this.dragListenerKeys_ = null; - } - if (this.documentPointerEventHandler_) { - goog.dispose(this.documentPointerEventHandler_); - this.documentPointerEventHandler_ = null; - } - if (this.pointerEventHandler_) { - goog.dispose(this.pointerEventHandler_); - this.pointerEventHandler_ = null; +goog.dom.fullscreen.getFullScreenElement = function(opt_domHelper) { + var doc = goog.dom.fullscreen.getDocument_(opt_domHelper); + var element_list = [ + doc.webkitFullscreenElement, + doc.mozFullScreenElement, + doc.msFullscreenElement, + doc.fullscreenElement + ]; + for (var i = 0; i < element_list.length; i++) { + if (element_list[i] != null) { + return element_list[i]; + } } - goog.base(this, 'disposeInternal'); + return null; }; /** - * Constants for event names. - * @enum {string} + * Gets the document object of the dom. + * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being + * queried. If not provided, use the current DOM. + * @return {!Document} The dom document. + * @private */ -ol.MapBrowserEvent.EventType = { +goog.dom.fullscreen.getDocument_ = function(opt_domHelper) { + return opt_domHelper ? + opt_domHelper.getDocument() : + goog.dom.getDomHelper().getDocument(); +}; - /** - * A true single click with no dragging and no double click. Note that this - * event is delayed by 250 ms to ensure that it is not a double click. - * @event ol.MapBrowserEvent#singleclick - * @api stable - */ - SINGLECLICK: 'singleclick', +goog.provide('ol.control.FullScreen'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.dom.classlist'); +goog.require('goog.dom.fullscreen'); +goog.require('goog.dom.fullscreen.EventType'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol'); +goog.require('ol.control.Control'); +goog.require('ol.css'); + + + +/** + * @classdesc + * Provides a button that when clicked fills up the full screen with the map. + * When in full screen mode, a close button is shown to exit full screen mode. + * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to + * toggle the map in full screen mode. + * + * + * @constructor + * @extends {ol.control.Control} + * @param {olx.control.FullScreenOptions=} opt_options Options. + * @api stable + */ +ol.control.FullScreen = function(opt_options) { + + var options = opt_options ? opt_options : {}; /** - * A click with no dragging. A double click will fire two of this. - * @event ol.MapBrowserEvent#click - * @api stable + * @private + * @type {string} */ - CLICK: goog.events.EventType.CLICK, + this.cssClassName_ = options.className ? options.className : 'ol-full-screen'; + + var label = options.label ? options.label : '\u2922'; /** - * A true double click, with no dragging. - * @event ol.MapBrowserEvent#dblclick - * @api stable + * @private + * @type {Node} */ - DBLCLICK: goog.events.EventType.DBLCLICK, + this.labelNode_ = goog.isString(label) ? + goog.dom.createTextNode(label) : label; + + var labelActive = options.labelActive ? options.labelActive : '\u00d7'; /** - * Triggered when a pointer is dragged. - * @event ol.MapBrowserEvent#pointerdrag - * @api + * @private + * @type {Node} */ - POINTERDRAG: 'pointerdrag', + this.labelActiveNode_ = goog.isString(labelActive) ? + goog.dom.createTextNode(labelActive) : labelActive; + + var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen'; + var button = goog.dom.createDom('BUTTON', { + 'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen(), + 'type': 'button', + 'title': tipLabel + }, this.labelNode_); + + goog.events.listen(button, goog.events.EventType.CLICK, + this.handleClick_, false, this); + + goog.events.listen(goog.global.document, + goog.dom.fullscreen.EventType.CHANGE, + this.handleFullScreenChange_, false, this); + + var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE + + ' ' + ol.css.CLASS_CONTROL + ' ' + + (!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : ''); + var element = goog.dom.createDom('DIV', cssClasses, button); + + goog.base(this, { + element: element, + target: options.target + }); /** - * Triggered when a pointer is moved. Note that on touch devices this is - * triggered when the map is panned, so is not the same as mousemove. - * @event ol.MapBrowserEvent#pointermove - * @api stable + * @private + * @type {boolean} */ - POINTERMOVE: 'pointermove', + this.keys_ = options.keys !== undefined ? options.keys : false; - POINTERDOWN: 'pointerdown', - POINTERUP: 'pointerup', - POINTEROVER: 'pointerover', - POINTEROUT: 'pointerout', - POINTERENTER: 'pointerenter', - POINTERLEAVE: 'pointerleave', - POINTERCANCEL: 'pointercancel' }; +goog.inherits(ol.control.FullScreen, ol.control.Control); -goog.provide('ol.layer.Base'); -goog.provide('ol.layer.LayerProperty'); -goog.provide('ol.layer.LayerState'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.math'); -goog.require('ol.source.State'); +/** + * @param {goog.events.BrowserEvent} event The event to handle + * @private + */ +ol.control.FullScreen.prototype.handleClick_ = function(event) { + event.preventDefault(); + this.handleFullScreen_(); +}; /** - * @enum {string} + * @private */ -ol.layer.LayerProperty = { - OPACITY: 'opacity', - VISIBLE: 'visible', - EXTENT: 'extent', - Z_INDEX: 'zIndex', - MAX_RESOLUTION: 'maxResolution', - MIN_RESOLUTION: 'minResolution', - SOURCE: 'source' +ol.control.FullScreen.prototype.handleFullScreen_ = function() { + if (!goog.dom.fullscreen.isSupported()) { + return; + } + var map = this.getMap(); + if (!map) { + return; + } + if (goog.dom.fullscreen.isFullScreen()) { + goog.dom.fullscreen.exitFullScreen(); + } else { + var target = map.getTarget(); + goog.asserts.assert(target, 'target should be defined'); + var element = goog.dom.getElement(target); + goog.asserts.assert(element, 'element should be defined'); + if (this.keys_) { + goog.dom.fullscreen.requestFullScreenWithKeys(element); + } else { + goog.dom.fullscreen.requestFullScreen(element); + } + } }; /** - * @typedef {{layer: ol.layer.Layer, - * opacity: number, - * sourceState: ol.source.State, - * visible: boolean, - * managed: boolean, - * extent: (ol.Extent|undefined), - * zIndex: number, - * maxResolution: number, - * minResolution: number}} + * @private */ -ol.layer.LayerState; +ol.control.FullScreen.prototype.handleFullScreenChange_ = function() { + var opened = this.cssClassName_ + '-true'; + var closed = this.cssClassName_ + '-false'; + var button = goog.dom.getFirstElementChild(this.element); + var map = this.getMap(); + if (goog.dom.fullscreen.isFullScreen()) { + goog.dom.classlist.swap(button, closed, opened); + goog.dom.replaceNode(this.labelActiveNode_, this.labelNode_); + } else { + goog.dom.classlist.swap(button, opened, closed); + goog.dom.replaceNode(this.labelNode_, this.labelActiveNode_); + } + if (map) { + map.updateSize(); + } +}; + +goog.provide('ol.Pixel'); + + +/** + * An array with two elements, representing a pixel. The first element is the + * x-coordinate, the second the y-coordinate of the pixel. + * @typedef {Array.<number>} + * @api stable + */ +ol.Pixel; + +// FIXME should listen on appropriate pane, once it is defined + +goog.provide('ol.control.MousePosition'); + +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.CoordinateFormatType'); +goog.require('ol.Object'); +goog.require('ol.Pixel'); +goog.require('ol.TransformFunction'); +goog.require('ol.control.Control'); +goog.require('ol.proj'); +goog.require('ol.proj.Projection'); + + +/** + * @enum {string} + */ +ol.control.MousePositionProperty = { + PROJECTION: 'projection', + COORDINATE_FORMAT: 'coordinateFormat' +}; /** * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Note that with `ol.layer.Base` and all its subclasses, any property set in - * the options is set as a {@link ol.Object} property on the layer object, so - * is observable, and has get/set accessors. + * A control to show the 2D coordinates of the mouse cursor. By default, these + * are in the view projection, but can be in any supported projection. + * By default the control is shown in the top right corner of the map, but this + * can be changed by using the css selector `.ol-mouse-position`. * * @constructor - * @extends {ol.Object} - * @param {olx.layer.BaseOptions} options Layer options. + * @extends {ol.control.Control} + * @param {olx.control.MousePositionOptions=} opt_options Mouse position + * options. * @api stable */ -ol.layer.Base = function(options) { +ol.control.MousePosition = function(opt_options) { - goog.base(this); + var options = opt_options ? opt_options : {}; + + var className = options.className ? options.className : 'ol-mouse-position'; + + var element = goog.dom.createDom('DIV', className); + + var render = options.render ? + options.render : ol.control.MousePosition.render; + + goog.base(this, { + element: element, + render: render, + target: options.target + }); + + goog.events.listen(this, + ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION), + this.handleProjectionChanged_, false, this); + + if (options.coordinateFormat) { + this.setCoordinateFormat(options.coordinateFormat); + } + if (options.projection) { + this.setProjection(ol.proj.get(options.projection)); + } /** - * @type {Object.<string, *>} + * @private + * @type {string} */ - var properties = goog.object.clone(options); - properties[ol.layer.LayerProperty.OPACITY] = - options.opacity !== undefined ? options.opacity : 1; - properties[ol.layer.LayerProperty.VISIBLE] = - options.visible !== undefined ? options.visible : true; - properties[ol.layer.LayerProperty.Z_INDEX] = - options.zIndex !== undefined ? options.zIndex : 0; - properties[ol.layer.LayerProperty.MAX_RESOLUTION] = - options.maxResolution !== undefined ? options.maxResolution : Infinity; - properties[ol.layer.LayerProperty.MIN_RESOLUTION] = - options.minResolution !== undefined ? options.minResolution : 0; + this.undefinedHTML_ = options.undefinedHTML ? options.undefinedHTML : ''; - this.setProperties(properties); -}; -goog.inherits(ol.layer.Base, ol.Object); + /** + * @private + * @type {string} + */ + this.renderedHTML_ = element.innerHTML; + /** + * @private + * @type {ol.proj.Projection} + */ + this.mapProjection_ = null; + + /** + * @private + * @type {?ol.TransformFunction} + */ + this.transform_ = null; + + /** + * @private + * @type {ol.Pixel} + */ + this.lastMouseMovePixel_ = null; -/** - * @return {ol.layer.LayerState} Layer state. - */ -ol.layer.Base.prototype.getLayerState = function() { - var opacity = this.getOpacity(); - var sourceState = this.getSourceState(); - var visible = this.getVisible(); - var extent = this.getExtent(); - var zIndex = this.getZIndex(); - var maxResolution = this.getMaxResolution(); - var minResolution = this.getMinResolution(); - return { - layer: /** @type {ol.layer.Layer} */ (this), - opacity: ol.math.clamp(opacity, 0, 1), - sourceState: sourceState, - visible: visible, - managed: true, - extent: extent, - zIndex: zIndex, - maxResolution: maxResolution, - minResolution: Math.max(minResolution, 0) - }; }; +goog.inherits(ol.control.MousePosition, ol.control.Control); /** - * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be - * modified in place). - * @return {Array.<ol.layer.Layer>} Array of layers. + * Update the mouseposition element. + * @param {ol.MapEvent} mapEvent Map event. + * @this {ol.control.MousePosition} + * @api */ -ol.layer.Base.prototype.getLayersArray = goog.abstractMethod; +ol.control.MousePosition.render = function(mapEvent) { + var frameState = mapEvent.frameState; + if (!frameState) { + this.mapProjection_ = null; + } else { + if (this.mapProjection_ != frameState.viewState.projection) { + this.mapProjection_ = frameState.viewState.projection; + this.transform_ = null; + } + } + this.updateHTML_(this.lastMouseMovePixel_); +}; /** - * @param {Array.<ol.layer.LayerState>=} opt_states Optional list of layer - * states (to be modified in place). - * @return {Array.<ol.layer.LayerState>} List of layer states. + * @private */ -ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod; +ol.control.MousePosition.prototype.handleProjectionChanged_ = function() { + this.transform_ = null; +}; /** - * Return the {@link ol.Extent extent} of the layer or `undefined` if it - * will be visible regardless of extent. - * @return {ol.Extent|undefined} The layer extent. + * Return the coordinate format type used to render the current position or + * undefined. + * @return {ol.CoordinateFormatType|undefined} The format to render the current + * position in. * @observable * @api stable */ -ol.layer.Base.prototype.getExtent = function() { - return /** @type {ol.Extent|undefined} */ ( - this.get(ol.layer.LayerProperty.EXTENT)); +ol.control.MousePosition.prototype.getCoordinateFormat = function() { + return /** @type {ol.CoordinateFormatType|undefined} */ ( + this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT)); }; /** - * Return the maximum resolution of the layer. - * @return {number} The maximum resolution of the layer. + * Return the projection that is used to report the mouse position. + * @return {ol.proj.Projection|undefined} The projection to report mouse + * position in. * @observable * @api stable */ -ol.layer.Base.prototype.getMaxResolution = function() { - return /** @type {number} */ ( - this.get(ol.layer.LayerProperty.MAX_RESOLUTION)); +ol.control.MousePosition.prototype.getProjection = function() { + return /** @type {ol.proj.Projection|undefined} */ ( + this.get(ol.control.MousePositionProperty.PROJECTION)); }; /** - * Return the minimum resolution of the layer. - * @return {number} The minimum resolution of the layer. - * @observable - * @api stable + * @param {goog.events.BrowserEvent} browserEvent Browser event. + * @protected */ -ol.layer.Base.prototype.getMinResolution = function() { - return /** @type {number} */ ( - this.get(ol.layer.LayerProperty.MIN_RESOLUTION)); +ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) { + var map = this.getMap(); + this.lastMouseMovePixel_ = map.getEventPixel(browserEvent.getBrowserEvent()); + this.updateHTML_(this.lastMouseMovePixel_); }; /** - * Return the opacity of the layer (between 0 and 1). - * @return {number} The opacity of the layer. - * @observable - * @api stable + * @param {goog.events.BrowserEvent} browserEvent Browser event. + * @protected */ -ol.layer.Base.prototype.getOpacity = function() { - return /** @type {number} */ (this.get(ol.layer.LayerProperty.OPACITY)); +ol.control.MousePosition.prototype.handleMouseOut = function(browserEvent) { + this.updateHTML_(null); + this.lastMouseMovePixel_ = null; }; /** - * @return {ol.source.State} Source state. - */ -ol.layer.Base.prototype.getSourceState = goog.abstractMethod; - - -/** - * Return the visibility of the layer (`true` or `false`). - * @return {boolean} The visibility of the layer. - * @observable + * @inheritDoc * @api stable */ -ol.layer.Base.prototype.getVisible = function() { - return /** @type {boolean} */ (this.get(ol.layer.LayerProperty.VISIBLE)); -}; - - -/** - * Return the Z-index of the layer, which is used to order layers before - * rendering. The default Z-index is 0. - * @return {number} The Z-index of the layer. - * @observable - * @api - */ -ol.layer.Base.prototype.getZIndex = function() { - return /** @type {number} */ (this.get(ol.layer.LayerProperty.Z_INDEX)); +ol.control.MousePosition.prototype.setMap = function(map) { + goog.base(this, 'setMap', map); + if (map) { + var viewport = map.getViewport(); + this.listenerKeys.push( + goog.events.listen(viewport, goog.events.EventType.MOUSEMOVE, + this.handleMouseMove, false, this), + goog.events.listen(viewport, goog.events.EventType.MOUSEOUT, + this.handleMouseOut, false, this) + ); + } }; /** - * Set the extent at which the layer is visible. If `undefined`, the layer - * will be visible at all extents. - * @param {ol.Extent|undefined} extent The extent of the layer. + * Set the coordinate format type used to render the current position. + * @param {ol.CoordinateFormatType} format The format to render the current + * position in. * @observable * @api stable */ -ol.layer.Base.prototype.setExtent = function(extent) { - this.set(ol.layer.LayerProperty.EXTENT, extent); +ol.control.MousePosition.prototype.setCoordinateFormat = function(format) { + this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format); }; /** - * Set the maximum resolution at which the layer is visible. - * @param {number} maxResolution The maximum resolution of the layer. + * Set the projection that is used to report the mouse position. + * @param {ol.proj.Projection} projection The projection to report mouse + * position in. * @observable * @api stable */ -ol.layer.Base.prototype.setMaxResolution = function(maxResolution) { - this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution); +ol.control.MousePosition.prototype.setProjection = function(projection) { + this.set(ol.control.MousePositionProperty.PROJECTION, projection); }; /** - * Set the minimum resolution at which the layer is visible. - * @param {number} minResolution The minimum resolution of the layer. - * @observable - * @api stable + * @param {?ol.Pixel} pixel Pixel. + * @private */ -ol.layer.Base.prototype.setMinResolution = function(minResolution) { - this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution); +ol.control.MousePosition.prototype.updateHTML_ = function(pixel) { + var html = this.undefinedHTML_; + if (pixel && this.mapProjection_) { + if (!this.transform_) { + var projection = this.getProjection(); + if (projection) { + this.transform_ = ol.proj.getTransformFromProjections( + this.mapProjection_, projection); + } else { + this.transform_ = ol.proj.identityTransform; + } + } + var map = this.getMap(); + var coordinate = map.getCoordinateFromPixel(pixel); + if (coordinate) { + this.transform_(coordinate, coordinate); + var coordinateFormat = this.getCoordinateFormat(); + if (coordinateFormat) { + html = coordinateFormat(coordinate); + } else { + html = coordinate.toString(); + } + } + } + if (!this.renderedHTML_ || html != this.renderedHTML_) { + this.element.innerHTML = html; + this.renderedHTML_ = html; + } }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Set the opacity of the layer, allowed values range from 0 to 1. - * @param {number} opacity The opacity of the layer. - * @observable - * @api stable + * @fileoverview Provides a function to schedule running a function as soon + * as possible after the current JS execution stops and yields to the event + * loop. + * */ -ol.layer.Base.prototype.setOpacity = function(opacity) { - this.set(ol.layer.LayerProperty.OPACITY, opacity); -}; +goog.provide('goog.async.nextTick'); +goog.provide('goog.async.throwException'); -/** - * Set the visibility of the layer (`true` or `false`). - * @param {boolean} visible The visibility of the layer. - * @observable - * @api stable - */ -ol.layer.Base.prototype.setVisible = function(visible) { - this.set(ol.layer.LayerProperty.VISIBLE, visible); -}; +goog.require('goog.debug.entryPointRegistry'); +goog.require('goog.dom.TagName'); +goog.require('goog.functions'); +goog.require('goog.labs.userAgent.browser'); +goog.require('goog.labs.userAgent.engine'); /** - * Set Z-index of the layer, which is used to order layers before rendering. - * The default Z-index is 0. - * @param {number} zindex The z-index of the layer. - * @observable - * @api + * Throw an item without interrupting the current execution context. For + * example, if processing a group of items in a loop, sometimes it is useful + * to report an error while still allowing the rest of the batch to be + * processed. + * @param {*} exception */ -ol.layer.Base.prototype.setZIndex = function(zindex) { - this.set(ol.layer.LayerProperty.Z_INDEX, zindex); +goog.async.throwException = function(exception) { + // Each throw needs to be in its own context. + goog.global.setTimeout(function() { throw exception; }, 0); }; -goog.provide('ol.render.VectorContext'); - - /** - * Context for drawing geometries. A vector context is available on render - * events and does not need to be constructed directly. - * @constructor - * @struct - * @api + * Fires the provided callbacks as soon as possible after the current JS + * execution context. setTimeout(…, 0) takes at least 4ms when called from + * within another setTimeout(…, 0) for legacy reasons. + * + * This will not schedule the callback as a microtask (i.e. a task that can + * preempt user input or networking callbacks). It is meant to emulate what + * setTimeout(_, 0) would do if it were not throttled. If you desire microtask + * behavior, use {@see goog.Promise} instead. + * + * @param {function(this:SCOPE)} callback Callback function to fire as soon as + * possible. + * @param {SCOPE=} opt_context Object in whose scope to call the listener. + * @param {boolean=} opt_useSetImmediate Avoid the IE workaround that + * ensures correctness at the cost of speed. See comments for details. + * @template SCOPE */ -ol.render.VectorContext = function() { +goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) { + var cb = callback; + if (opt_context) { + cb = goog.bind(callback, opt_context); + } + cb = goog.async.nextTick.wrapCallback_(cb); + // window.setImmediate was introduced and currently only supported by IE10+, + // but due to a bug in the implementation it is not guaranteed that + // setImmediate is faster than setTimeout nor that setImmediate N is before + // setImmediate N+1. That is why we do not use the native version if + // available. We do, however, call setImmediate if it is a normal function + // because that indicates that it has been replaced by goog.testing.MockClock + // which we do want to support. + // See + // http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10 + // + // Note we do allow callers to also request setImmediate if they are willing + // to accept the possible tradeoffs of incorrectness in exchange for speed. + // The IE fallback of readystate change is much slower. + if (goog.isFunction(goog.global.setImmediate) && + // Opt in. + (opt_useSetImmediate || + // or it isn't a browser or the environment is weird + !goog.global.Window || !goog.global.Window.prototype || + // or something redefined setImmediate in which case we (YOLO) decide + // to use it (This is so that we use the mockClock setImmediate. sigh). + goog.global.Window.prototype.setImmediate != goog.global.setImmediate)) { + goog.global.setImmediate(cb); + return; + } + + // Look for and cache the custom fallback version of setImmediate. + if (!goog.async.nextTick.setImmediate_) { + goog.async.nextTick.setImmediate_ = + goog.async.nextTick.getSetImmediateEmulator_(); + } + goog.async.nextTick.setImmediate_(cb); }; /** - * @param {number} zIndex Z index. - * @param {function(ol.render.VectorContext)} callback Callback. + * Cache for the setImmediate implementation. + * @type {function(function())} + * @private */ -ol.render.VectorContext.prototype.drawAsync = goog.abstractMethod; +goog.async.nextTick.setImmediate_; /** - * @param {ol.geom.Circle} circleGeometry Circle geometry. - * @param {ol.Feature} feature Feature, + * Determines the best possible implementation to run a function as soon as + * the JS event loop is idle. + * @return {function(function())} The "setImmediate" implementation. + * @private */ -ol.render.VectorContext.prototype.drawCircleGeometry = goog.abstractMethod; +goog.async.nextTick.getSetImmediateEmulator_ = function() { + // Create a private message channel and use it to postMessage empty messages + // to ourselves. + var Channel = goog.global['MessageChannel']; + // If MessageChannel is not available and we are in a browser, implement + // an iframe based polyfill in browsers that have postMessage and + // document.addEventListener. The latter excludes IE8 because it has a + // synchronous postMessage implementation. + if (typeof Channel === 'undefined' && typeof window !== 'undefined' && + window.postMessage && window.addEventListener && + // Presto (The old pre-blink Opera engine) has problems with iframes + // and contentWindow. + !goog.labs.userAgent.engine.isPresto()) { + /** @constructor */ + Channel = function() { + // Make an empty, invisible iframe. + var iframe = document.createElement(goog.dom.TagName.IFRAME); + iframe.style.display = 'none'; + iframe.src = ''; + document.documentElement.appendChild(iframe); + var win = iframe.contentWindow; + var doc = win.document; + doc.open(); + doc.write(''); + doc.close(); + // Do not post anything sensitive over this channel, as the workaround for + // pages with file: origin could allow that information to be modified or + // intercepted. + var message = 'callImmediate' + Math.random(); + // The same origin policy rejects attempts to postMessage from file: urls + // unless the origin is '*'. + // TODO(b/16335441): Use '*' origin for data: and other similar protocols. + var origin = win.location.protocol == 'file:' ? + '*' : win.location.protocol + '//' + win.location.host; + var onmessage = goog.bind(function(e) { + // Validate origin and message to make sure that this message was + // intended for us. If the origin is set to '*' (see above) only the + // message needs to match since, for example, '*' != 'file://'. Allowing + // the wildcard is ok, as we are not concerned with security here. + if ((origin != '*' && e.origin != origin) || e.data != message) { + return; + } + this['port1'].onmessage(); + }, this); + win.addEventListener('message', onmessage, false); + this['port1'] = {}; + this['port2'] = { + postMessage: function() { + win.postMessage(message, origin); + } + }; + }; + } + if (typeof Channel !== 'undefined' && + (!goog.labs.userAgent.browser.isIE())) { + // Exclude all of IE due to + // http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/ + // which allows starving postMessage with a busy setTimeout loop. + // This currently affects IE10 and IE11 which would otherwise be able + // to use the postMessage based fallbacks. + var channel = new Channel(); + // Use a fifo linked list to call callbacks in the right order. + var head = {}; + var tail = head; + channel['port1'].onmessage = function() { + if (goog.isDef(head.next)) { + head = head.next; + var cb = head.cb; + head.cb = null; + cb(); + } + }; + return function(cb) { + tail.next = { + cb: cb + }; + tail = tail.next; + channel['port2'].postMessage(0); + }; + } + // Implementation for IE6+: Script elements fire an asynchronous + // onreadystatechange event when inserted into the DOM. + if (typeof document !== 'undefined' && 'onreadystatechange' in + document.createElement(goog.dom.TagName.SCRIPT)) { + return function(cb) { + var script = document.createElement(goog.dom.TagName.SCRIPT); + script.onreadystatechange = function() { + // Clean up and call the callback. + script.onreadystatechange = null; + script.parentNode.removeChild(script); + script = null; + cb(); + cb = null; + }; + document.documentElement.appendChild(script); + }; + } + // Fall back to setTimeout with 0. In browsers this creates a delay of 5ms + // or more. + return function(cb) { + goog.global.setTimeout(cb, 0); + }; +}; /** - * @param {ol.Feature} feature Feature. - * @param {ol.style.Style} style Style. + * Helper function that is overrided to protect callbacks with entry point + * monitor if the application monitors entry points. + * @param {function()} callback Callback function to fire as soon as possible. + * @return {function()} The wrapped callback. + * @private */ -ol.render.VectorContext.prototype.drawFeature = goog.abstractMethod; +goog.async.nextTick.wrapCallback_ = goog.functions.identity; -/** - * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry - * collection. - * @param {ol.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawGeometryCollectionGeometry = - goog.abstractMethod; +// Register the callback function as an entry point, so that it can be +// monitored for exception handling, etc. This has to be done in this file +// since it requires special code to handle all browsers. +goog.debug.entryPointRegistry.register( + /** + * @param {function(!Function): !Function} transformer The transforming + * function. + */ + function(transformer) { + goog.async.nextTick.wrapCallback_ = transformer; + }); +// Copyright 2014 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line - * string geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. + * @fileoverview The SafeScript type and its builders. + * + * TODO(xtof): Link to document stating type contract. */ -ol.render.VectorContext.prototype.drawLineStringGeometry = - goog.abstractMethod; - -/** - * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry - * MultiLineString geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawMultiLineStringGeometry = - goog.abstractMethod; +goog.provide('goog.html.SafeScript'); +goog.require('goog.asserts'); +goog.require('goog.string.Const'); +goog.require('goog.string.TypedString'); -/** - * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawMultiPointGeometry = goog.abstractMethod; /** - * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry. - * @param {ol.Feature} feature Feature. + * A string-like object which represents JavaScript code and that carries the + * security type contract that its value, as a string, will not cause execution + * of unconstrained attacker controlled code (XSS) when evaluated as JavaScript + * in a browser. + * + * Instances of this type must be created via the factory method + * {@code goog.html.SafeScript.fromConstant} and not by invoking its + * constructor. The constructor intentionally takes no parameters and the type + * is immutable; hence only a default instance corresponding to the empty string + * can be obtained via constructor invocation. + * + * A SafeScript's string representation can safely be interpolated as the + * content of a script element within HTML. The SafeScript string should not be + * escaped before interpolation. + * + * Note that the SafeScript might contain text that is attacker-controlled but + * that text should have been interpolated with appropriate escaping, + * sanitization and/or validation into the right location in the script, such + * that it is highly constrained in its effect (for example, it had to match a + * set of whitelisted words). + * + * A SafeScript can be constructed via security-reviewed unchecked + * conversions. In this case producers of SafeScript must ensure themselves that + * the SafeScript does not contain unsafe script. Note in particular that + * {@code <} is dangerous, even when inside JavaScript strings, and so should + * always be forbidden or JavaScript escaped in user controlled input. For + * example, if {@code </script><script>evil</script>"} were + * interpolated inside a JavaScript string, it would break out of the context + * of the original script element and {@code evil} would execute. Also note + * that within an HTML script (raw text) element, HTML character references, + * such as "<" are not allowed. See + * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements. + * + * @see goog.html.SafeScript#fromConstant + * @constructor + * @final + * @struct + * @implements {goog.string.TypedString} */ -ol.render.VectorContext.prototype.drawMultiPolygonGeometry = - goog.abstractMethod; - +goog.html.SafeScript = function() { + /** + * The contained value of this SafeScript. The field has a purposely + * ugly name to make (non-compiled) code that attempts to directly access this + * field stand out. + * @private {string} + */ + this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = ''; -/** - * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - */ -ol.render.VectorContext.prototype.drawPointGeometry = goog.abstractMethod; + /** + * A type marker used to implement additional run-time type checking. + * @see goog.html.SafeScript#unwrap + * @const + * @private + */ + this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = + goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_; +}; /** - * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. + * @override + * @const */ -ol.render.VectorContext.prototype.drawPolygonGeometry = goog.abstractMethod; +goog.html.SafeScript.prototype.implementsGoogStringTypedString = true; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. + * Type marker for the SafeScript type, used to implement additional + * run-time type checking. + * @const {!Object} + * @private */ -ol.render.VectorContext.prototype.drawText = goog.abstractMethod; +goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}; /** - * @param {ol.style.Fill} fillStyle Fill style. - * @param {ol.style.Stroke} strokeStyle Stroke style. + * Creates a SafeScript object from a compile-time constant string. + * + * @param {!goog.string.Const} script A compile-time-constant string from which + * to create a SafeScript. + * @return {!goog.html.SafeScript} A SafeScript object initialized to + * {@code script}. */ -ol.render.VectorContext.prototype.setFillStrokeStyle = goog.abstractMethod; +goog.html.SafeScript.fromConstant = function(script) { + var scriptString = goog.string.Const.unwrap(script); + if (scriptString.length === 0) { + return goog.html.SafeScript.EMPTY; + } + return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( + scriptString); +}; /** - * @param {ol.style.Image} imageStyle Image style. + * Returns this SafeScript's value as a string. + * + * IMPORTANT: In code where it is security relevant that an object's type is + * indeed {@code SafeScript}, use {@code goog.html.SafeScript.unwrap} instead of + * this method. If in doubt, assume that it's security relevant. In particular, + * note that goog.html functions which return a goog.html type do not guarantee + * the returned instance is of the right type. For example: + * + * <pre> + * var fakeSafeHtml = new String('fake'); + * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype; + * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml); + * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by + * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml + * // instanceof goog.html.SafeHtml. + * </pre> + * + * @see goog.html.SafeScript#unwrap + * @override */ -ol.render.VectorContext.prototype.setImageStyle = goog.abstractMethod; +goog.html.SafeScript.prototype.getTypedStringValue = function() { + return this.privateDoNotAccessOrElseSafeScriptWrappedValue_; +}; -/** - * @param {ol.style.Text} textStyle Text style. - */ -ol.render.VectorContext.prototype.setTextStyle = goog.abstractMethod; - -goog.provide('ol.render.Event'); -goog.provide('ol.render.EventType'); - -goog.require('goog.events.Event'); -goog.require('ol.render.VectorContext'); +if (goog.DEBUG) { + /** + * Returns a debug string-representation of this value. + * + * To obtain the actual string value wrapped in a SafeScript, use + * {@code goog.html.SafeScript.unwrap}. + * + * @see goog.html.SafeScript#unwrap + * @override + */ + goog.html.SafeScript.prototype.toString = function() { + return 'SafeScript{' + + this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}'; + }; +} /** - * @enum {string} + * Performs a runtime check that the provided object is indeed a + * SafeScript object, and returns its value. + * + * @param {!goog.html.SafeScript} safeScript The object to extract from. + * @return {string} The safeScript object's contained string, unless + * the run-time type check fails. In that case, {@code unwrap} returns an + * innocuous string, or, if assertions are enabled, throws + * {@code goog.asserts.AssertionError}. */ -ol.render.EventType = { - /** - * @event ol.render.Event#postcompose - * @api - */ - POSTCOMPOSE: 'postcompose', - /** - * @event ol.render.Event#precompose - * @api - */ - PRECOMPOSE: 'precompose', - /** - * @event ol.render.Event#render - * @api - */ - RENDER: 'render' +goog.html.SafeScript.unwrap = function(safeScript) { + // Perform additional Run-time type-checking to ensure that + // safeScript is indeed an instance of the expected type. This + // provides some additional protection against security bugs due to + // application code that disables type checks. + // Specifically, the following checks are performed: + // 1. The object is an instance of the expected type. + // 2. The object is not an instance of a subclass. + // 3. The object carries a type marker for the expected type. "Faking" an + // object requires a reference to the type marker, which has names intended + // to stand out in code reviews. + if (safeScript instanceof goog.html.SafeScript && + safeScript.constructor === goog.html.SafeScript && + safeScript.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === + goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) { + return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_; + } else { + goog.asserts.fail( + 'expected object of type SafeScript, got \'' + safeScript + '\''); + return 'type_error:SafeScript'; + } }; - /** - * @constructor - * @extends {goog.events.Event} - * @implements {oli.render.Event} - * @param {ol.render.EventType} type Type. - * @param {Object=} opt_target Target. - * @param {ol.render.VectorContext=} opt_vectorContext Vector context. - * @param {olx.FrameState=} opt_frameState Frame state. - * @param {?CanvasRenderingContext2D=} opt_context Context. - * @param {?ol.webgl.Context=} opt_glContext WebGL Context. + * Package-internal utility method to create SafeScript instances. + * + * @param {string} script The string to initialize the SafeScript object with. + * @return {!goog.html.SafeScript} The initialized SafeScript object. + * @package */ -ol.render.Event = function( - type, opt_target, opt_vectorContext, opt_frameState, opt_context, - opt_glContext) { - - goog.base(this, type, opt_target); - - /** - * For canvas, this is an instance of {@link ol.render.canvas.Immediate}. - * @type {ol.render.VectorContext|undefined} - * @api - */ - this.vectorContext = opt_vectorContext; - - /** - * An object representing the current render frame state. - * @type {olx.FrameState|undefined} - * @api - */ - this.frameState = opt_frameState; - - /** - * Canvas context. Only available when a Canvas renderer is used, null - * otherwise. - * @type {CanvasRenderingContext2D|null|undefined} - * @api - */ - this.context = opt_context; +goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse = + function(script) { + return new goog.html.SafeScript().initSecurityPrivateDoNotAccessOrElse_( + script); +}; - /** - * WebGL context. Only available when a WebGL renderer is used, null - * otherwise. - * @type {ol.webgl.Context|null|undefined} - * @api - */ - this.glContext = opt_glContext; +/** + * Called from createSafeScriptSecurityPrivateDoNotAccessOrElse(). This + * method exists only so that the compiler can dead code eliminate static + * fields (like EMPTY) when they're not accessed. + * @param {string} script + * @return {!goog.html.SafeScript} + * @private + */ +goog.html.SafeScript.prototype.initSecurityPrivateDoNotAccessOrElse_ = function( + script) { + this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = script; + return this; }; -goog.inherits(ol.render.Event, goog.events.Event); - -goog.provide('ol.layer.Layer'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.layer.Base'); -goog.require('ol.layer.LayerProperty'); -goog.require('ol.render.EventType'); -goog.require('ol.source.State'); +/** + * A SafeScript instance corresponding to the empty string. + * @const {!goog.html.SafeScript} + */ +goog.html.SafeScript.EMPTY = + goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(''); +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * A visual representation of raster or vector map data. - * Layers group together those properties that pertain to how the data is to be - * displayed, irrespective of the source of that data. + * @fileoverview Unchecked conversions to create values of goog.html types from + * plain strings. Use of these functions could potentially result in instances + * of goog.html types that violate their type contracts, and hence result in + * security vulnerabilties. * - * Layers are usually added to a map with {@link ol.Map#addLayer}. Components - * like {@link ol.interaction.Select} use unmanaged layers internally. These - * unmanaged layers are associated with the map using - * {@link ol.layer.Layer#setMap} instead. + * Therefore, all uses of the methods herein must be carefully security + * reviewed. Avoid use of the methods in this file whenever possible; instead + * prefer to create instances of goog.html types using inherently safe builders + * or template systems. * - * A generic `change` event is fired when the state of the source changes. * - * @constructor - * @extends {ol.layer.Base} - * @fires ol.render.Event - * @param {olx.layer.LayerOptions} options Layer options. - * @api stable + * + * @visibility {//closure/goog/html:approved_for_unchecked_conversion} + * @visibility {//closure/goog/bin/sizetests:__pkg__} */ -ol.layer.Layer = function(options) { - - var baseOptions = goog.object.clone(options); - delete baseOptions.source; - - goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); - - /** - * @private - * @type {goog.events.Key} - */ - this.mapPrecomposeKey_ = null; - /** - * @private - * @type {goog.events.Key} - */ - this.mapRenderKey_ = null; - /** - * @private - * @type {goog.events.Key} - */ - this.sourceChangeKey_ = null; +goog.provide('goog.html.uncheckedconversions'); - if (options.map) { - this.setMap(options.map); - } +goog.require('goog.asserts'); +goog.require('goog.html.SafeHtml'); +goog.require('goog.html.SafeScript'); +goog.require('goog.html.SafeStyle'); +goog.require('goog.html.SafeStyleSheet'); +goog.require('goog.html.SafeUrl'); +goog.require('goog.html.TrustedResourceUrl'); +goog.require('goog.string'); +goog.require('goog.string.Const'); - goog.events.listen(this, - ol.Object.getChangeEventType(ol.layer.LayerProperty.SOURCE), - this.handleSourcePropertyChange_, false, this); - var source = options.source ? options.source : null; - this.setSource(source); +/** + * Performs an "unchecked conversion" to SafeHtml from a plain string that is + * known to satisfy the SafeHtml type contract. + * + * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure + * that the value of {@code html} satisfies the SafeHtml type contract in all + * possible program states. + * + * + * @param {!goog.string.Const} justification A constant string explaining why + * this use of this method is safe. May include a security review ticket + * number. + * @param {string} html A string that is claimed to adhere to the SafeHtml + * contract. + * @param {?goog.i18n.bidi.Dir=} opt_dir The optional directionality of the + * SafeHtml to be constructed. A null or undefined value signifies an + * unknown directionality. + * @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml + * object. + * @suppress {visibility} For access to SafeHtml.create... Note that this + * use is appropriate since this method is intended to be "package private" + * withing goog.html. DO NOT call SafeHtml.create... from outside this + * package; use appropriate wrappers instead. + */ +goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract = + function(justification, html, opt_dir) { + // unwrap() called inside an assert so that justification can be optimized + // away in production code. + goog.asserts.assertString(goog.string.Const.unwrap(justification), + 'must provide justification'); + goog.asserts.assert( + !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), + 'must provide non-empty justification'); + return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( + html, opt_dir || null); }; -goog.inherits(ol.layer.Layer, ol.layer.Base); /** - * Return `true` if the layer is visible, and if the passed resolution is - * between the layer's minResolution and maxResolution. The comparison is - * inclusive for `minResolution` and exclusive for `maxResolution`. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {number} resolution Resolution. - * @return {boolean} The layer is visible at the given resolution. + * Performs an "unchecked conversion" to SafeScript from a plain string that is + * known to satisfy the SafeScript type contract. + * + * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure + * that the value of {@code script} satisfies the SafeScript type contract in + * all possible program states. + * + * + * @param {!goog.string.Const} justification A constant string explaining why + * this use of this method is safe. May include a security review ticket + * number. + * @param {string} script The string to wrap as a SafeScript. + * @return {!goog.html.SafeScript} The value of {@code script}, wrapped in a + * SafeScript object. */ -ol.layer.Layer.visibleAtResolution = function(layerState, resolution) { - return layerState.visible && resolution >= layerState.minResolution && - resolution < layerState.maxResolution; +goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract = + function(justification, script) { + // unwrap() called inside an assert so that justification can be optimized + // away in production code. + goog.asserts.assertString(goog.string.Const.unwrap(justification), + 'must provide justification'); + goog.asserts.assert( + !goog.string.isEmpty(goog.string.Const.unwrap(justification)), + 'must provide non-empty justification'); + return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( + script); }; /** - * @inheritDoc + * Performs an "unchecked conversion" to SafeStyle from a plain string that is + * known to satisfy the SafeStyle type contract. + * + * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure + * that the value of {@code style} satisfies the SafeUrl type contract in all + * possible program states. + * + * + * @param {!goog.string.Const} justification A constant string explaining why + * this use of this method is safe. May include a security review ticket + * number. + * @param {string} style The string to wrap as a SafeStyle. + * @return {!goog.html.SafeStyle} The value of {@code style}, wrapped in a + * SafeStyle object. */ -ol.layer.Layer.prototype.getLayersArray = function(opt_array) { - var array = opt_array ? opt_array : []; - array.push(this); - return array; +goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract = + function(justification, style) { + // unwrap() called inside an assert so that justification can be optimized + // away in production code. + goog.asserts.assertString(goog.string.Const.unwrap(justification), + 'must provide justification'); + goog.asserts.assert( + !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), + 'must provide non-empty justification'); + return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( + style); }; /** - * @inheritDoc + * Performs an "unchecked conversion" to SafeStyleSheet from a plain string + * that is known to satisfy the SafeStyleSheet type contract. + * + * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure + * that the value of {@code styleSheet} satisfies the SafeUrl type contract in + * all possible program states. + * + * + * @param {!goog.string.Const} justification A constant string explaining why + * this use of this method is safe. May include a security review ticket + * number. + * @param {string} styleSheet The string to wrap as a SafeStyleSheet. + * @return {!goog.html.SafeStyleSheet} The value of {@code styleSheet}, wrapped + * in a SafeStyleSheet object. */ -ol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) { - var states = opt_states ? opt_states : []; - states.push(this.getLayerState()); - return states; +goog.html.uncheckedconversions. + safeStyleSheetFromStringKnownToSatisfyTypeContract = + function(justification, styleSheet) { + // unwrap() called inside an assert so that justification can be optimized + // away in production code. + goog.asserts.assertString(goog.string.Const.unwrap(justification), + 'must provide justification'); + goog.asserts.assert( + !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), + 'must provide non-empty justification'); + return goog.html.SafeStyleSheet. + createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet); }; /** - * Get the layer source. - * @return {ol.source.Source} The layer source (or `null` if not yet set). - * @observable - * @api stable + * Performs an "unchecked conversion" to SafeUrl from a plain string that is + * known to satisfy the SafeUrl type contract. + * + * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure + * that the value of {@code url} satisfies the SafeUrl type contract in all + * possible program states. + * + * + * @param {!goog.string.Const} justification A constant string explaining why + * this use of this method is safe. May include a security review ticket + * number. + * @param {string} url The string to wrap as a SafeUrl. + * @return {!goog.html.SafeUrl} The value of {@code url}, wrapped in a SafeUrl + * object. */ -ol.layer.Layer.prototype.getSource = function() { - var source = this.get(ol.layer.LayerProperty.SOURCE); - return /** @type {ol.source.Source} */ (source) || null; +goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract = + function(justification, url) { + // unwrap() called inside an assert so that justification can be optimized + // away in production code. + goog.asserts.assertString(goog.string.Const.unwrap(justification), + 'must provide justification'); + goog.asserts.assert( + !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), + 'must provide non-empty justification'); + return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url); }; /** - * @inheritDoc - */ -ol.layer.Layer.prototype.getSourceState = function() { - var source = this.getSource(); - return !source ? ol.source.State.UNDEFINED : source.getState(); + * Performs an "unchecked conversion" to TrustedResourceUrl from a plain string + * that is known to satisfy the TrustedResourceUrl type contract. + * + * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure + * that the value of {@code url} satisfies the TrustedResourceUrl type contract + * in all possible program states. + * + * + * @param {!goog.string.Const} justification A constant string explaining why + * this use of this method is safe. May include a security review ticket + * number. + * @param {string} url The string to wrap as a TrustedResourceUrl. + * @return {!goog.html.TrustedResourceUrl} The value of {@code url}, wrapped in + * a TrustedResourceUrl object. + */ +goog.html.uncheckedconversions. + trustedResourceUrlFromStringKnownToSatisfyTypeContract = + function(justification, url) { + // unwrap() called inside an assert so that justification can be optimized + // away in production code. + goog.asserts.assertString(goog.string.Const.unwrap(justification), + 'must provide justification'); + goog.asserts.assert( + !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)), + 'must provide non-empty justification'); + return goog.html.TrustedResourceUrl. + createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @private + * @fileoverview Generics method for collection-like classes and objects. + * + * @author arv@google.com (Erik Arvidsson) + * + * This file contains functions to work with collections. It supports using + * Map, Set, Array and Object and other classes that implement collection-like + * methods. */ -ol.layer.Layer.prototype.handleSourceChange_ = function() { - this.changed(); -}; + + +goog.provide('goog.structs'); + +goog.require('goog.array'); +goog.require('goog.object'); + + +// We treat an object as a dictionary if it has getKeys or it is an object that +// isn't arrayLike. /** - * @private + * Returns the number of values in the collection-like object. + * @param {Object} col The collection-like object. + * @return {number} The number of values in the collection-like object. */ -ol.layer.Layer.prototype.handleSourcePropertyChange_ = function() { - if (this.sourceChangeKey_) { - goog.events.unlistenByKey(this.sourceChangeKey_); - this.sourceChangeKey_ = null; +goog.structs.getCount = function(col) { + if (typeof col.getCount == 'function') { + return col.getCount(); } - var source = this.getSource(); - if (source) { - this.sourceChangeKey_ = goog.events.listen(source, - goog.events.EventType.CHANGE, this.handleSourceChange_, false, this); + if (goog.isArrayLike(col) || goog.isString(col)) { + return col.length; } - this.changed(); + return goog.object.getCount(col); }; /** - * Sets the layer to be rendered on a map. The map will not manage this layer in - * its layers collection, layer filters in {@link ol.Map#forEachLayerAtPixel} - * will not filter the layer, and it will be rendered on top. This is useful for - * temporary layers. To remove an unmanaged layer from the map, use - * `#setMap(null)`. - * - * To add the layer to a map and have it managed by the map, use - * {@link ol.Map#addLayer} instead. - * @param {ol.Map} map Map. - * @api + * Returns the values of the collection-like object. + * @param {Object} col The collection-like object. + * @return {!Array<?>} The values in the collection-like object. */ -ol.layer.Layer.prototype.setMap = function(map) { - goog.events.unlistenByKey(this.mapPrecomposeKey_); - this.mapPrecomposeKey_ = null; - if (!map) { - this.changed(); +goog.structs.getValues = function(col) { + if (typeof col.getValues == 'function') { + return col.getValues(); } - goog.events.unlistenByKey(this.mapRenderKey_); - this.mapRenderKey_ = null; - if (map) { - this.mapPrecomposeKey_ = goog.events.listen( - map, ol.render.EventType.PRECOMPOSE, function(evt) { - var layerState = this.getLayerState(); - layerState.managed = false; - layerState.zIndex = Infinity; - evt.frameState.layerStatesArray.push(layerState); - evt.frameState.layerStates[goog.getUid(this)] = layerState; - }, false, this); - this.mapRenderKey_ = goog.events.listen( - this, goog.events.EventType.CHANGE, map.render, false, map); - this.changed(); + if (goog.isString(col)) { + return col.split(''); + } + if (goog.isArrayLike(col)) { + var rv = []; + var l = col.length; + for (var i = 0; i < l; i++) { + rv.push(col[i]); + } + return rv; } + return goog.object.getValues(col); }; /** - * Set the layer source. - * @param {ol.source.Source} source The layer source. - * @observable - * @api stable + * Returns the keys of the collection. Some collections have no notion of + * keys/indexes and this function will return undefined in those cases. + * @param {Object} col The collection-like object. + * @return {!Array|undefined} The keys in the collection. */ -ol.layer.Layer.prototype.setSource = function(source) { - this.set(ol.layer.LayerProperty.SOURCE, source); -}; - -goog.provide('ol.ImageBase'); -goog.provide('ol.ImageState'); +goog.structs.getKeys = function(col) { + if (typeof col.getKeys == 'function') { + return col.getKeys(); + } + // if we have getValues but no getKeys we know this is a key-less collection + if (typeof col.getValues == 'function') { + return undefined; + } + if (goog.isArrayLike(col) || goog.isString(col)) { + var rv = []; + var l = col.length; + for (var i = 0; i < l; i++) { + rv.push(i); + } + return rv; + } -goog.require('goog.asserts'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('ol.Attribution'); -goog.require('ol.Extent'); + return goog.object.getKeys(col); +}; /** - * @enum {number} + * Whether the collection contains the given value. This is O(n) and uses + * equals (==) to test the existence. + * @param {Object} col The collection-like object. + * @param {*} val The value to check for. + * @return {boolean} True if the map contains the value. */ -ol.ImageState = { - IDLE: 0, - LOADING: 1, - LOADED: 2, - ERROR: 3 +goog.structs.contains = function(col, val) { + if (typeof col.contains == 'function') { + return col.contains(val); + } + if (typeof col.containsValue == 'function') { + return col.containsValue(val); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.contains(/** @type {!Array<?>} */ (col), val); + } + return goog.object.containsValue(col, val); }; - /** - * @constructor - * @extends {goog.events.EventTarget} - * @param {ol.Extent} extent Extent. - * @param {number|undefined} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.ImageState} state State. - * @param {Array.<ol.Attribution>} attributions Attributions. + * Whether the collection is empty. + * @param {Object} col The collection-like object. + * @return {boolean} True if empty. */ -ol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) { - - goog.base(this); - - /** - * @private - * @type {Array.<ol.Attribution>} - */ - this.attributions_ = attributions; - - /** - * @protected - * @type {ol.Extent} - */ - this.extent = extent; - - /** - * @private - * @type {number} - */ - this.pixelRatio_ = pixelRatio; - - /** - * @protected - * @type {number|undefined} - */ - this.resolution = resolution; +goog.structs.isEmpty = function(col) { + if (typeof col.isEmpty == 'function') { + return col.isEmpty(); + } - /** - * @protected - * @type {ol.ImageState} - */ - this.state = state; + // We do not use goog.string.isEmptyOrWhitespace because here we treat the string as + // collection and as such even whitespace matters + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.isEmpty(/** @type {!Array<?>} */ (col)); + } + return goog.object.isEmpty(col); }; -goog.inherits(ol.ImageBase, goog.events.EventTarget); /** - * @protected + * Removes all the elements from the collection. + * @param {Object} col The collection-like object. */ -ol.ImageBase.prototype.changed = function() { - this.dispatchEvent(goog.events.EventType.CHANGE); +goog.structs.clear = function(col) { + // NOTE(arv): This should not contain strings because strings are immutable + if (typeof col.clear == 'function') { + col.clear(); + } else if (goog.isArrayLike(col)) { + goog.array.clear(/** @type {goog.array.ArrayLike} */ (col)); + } else { + goog.object.clear(col); + } }; /** - * @return {Array.<ol.Attribution>} Attributions. + * Calls a function for each value in a collection. The function takes + * three arguments; the value, the key and the collection. + * + * NOTE: This will be deprecated soon! Please use a more specific method if + * possible, e.g. goog.array.forEach, goog.object.forEach, etc. + * + * @param {S} col The collection-like object. + * @param {function(this:T,?,?,S):?} f The function to call for every value. + * This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and the return value is irrelevant. + * @param {T=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @template T,S */ -ol.ImageBase.prototype.getAttributions = function() { - return this.attributions_; +goog.structs.forEach = function(col, f, opt_obj) { + if (typeof col.forEach == 'function') { + col.forEach(f, opt_obj); + } else if (goog.isArrayLike(col) || goog.isString(col)) { + goog.array.forEach(/** @type {!Array<?>} */ (col), f, opt_obj); + } else { + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + f.call(opt_obj, values[i], keys && keys[i], col); + } + } }; /** - * @return {ol.Extent} Extent. + * Calls a function for every value in the collection. When a call returns true, + * adds the value to a new collection (Array is returned by default). + * + * @param {S} col The collection-like object. + * @param {function(this:T,?,?,S):boolean} f The function to call for every + * value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. If the + * return value is true the value is added to the result collection. If it + * is false the value is not included. + * @param {T=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {!Object|!Array<?>} A new collection where the passed values are + * present. If col is a key-less collection an array is returned. If col + * has keys and values a plain old JS object is returned. + * @template T,S */ -ol.ImageBase.prototype.getExtent = function() { - return this.extent; +goog.structs.filter = function(col, f, opt_obj) { + if (typeof col.filter == 'function') { + return col.filter(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.filter(/** @type {!Array<?>} */ (col), f, opt_obj); + } + + var rv; + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + if (keys) { + rv = {}; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], keys[i], col)) { + rv[keys[i]] = values[i]; + } + } + } else { + // We should not use goog.array.filter here since we want to make sure that + // the index is undefined as well as make sure that col is passed to the + // function. + rv = []; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], undefined, col)) { + rv.push(values[i]); + } + } + } + return rv; }; /** - * @param {Object=} opt_context Object. - * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image. + * Calls a function for every value in the collection and adds the result into a + * new collection (defaults to creating a new Array). + * + * @param {S} col The collection-like object. + * @param {function(this:T,?,?,S):V} f The function to call for every value. + * This function takes 3 arguments (the value, the key or undefined if the + * collection has no notion of keys, and the collection) and should return + * something. The result will be used as the value in the new collection. + * @param {T=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {!Object<V>|!Array<V>} A new collection with the new values. If + * col is a key-less collection an array is returned. If col has keys and + * values a plain old JS object is returned. + * @template T,S,V */ -ol.ImageBase.prototype.getImage = goog.abstractMethod; - +goog.structs.map = function(col, f, opt_obj) { + if (typeof col.map == 'function') { + return col.map(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.map(/** @type {!Array<?>} */ (col), f, opt_obj); + } -/** - * @return {number} PixelRatio. - */ -ol.ImageBase.prototype.getPixelRatio = function() { - return this.pixelRatio_; + var rv; + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + if (keys) { + rv = {}; + for (var i = 0; i < l; i++) { + rv[keys[i]] = f.call(opt_obj, values[i], keys[i], col); + } + } else { + // We should not use goog.array.map here since we want to make sure that + // the index is undefined as well as make sure that col is passed to the + // function. + rv = []; + for (var i = 0; i < l; i++) { + rv[i] = f.call(opt_obj, values[i], undefined, col); + } + } + return rv; }; /** - * @return {number} Resolution. + * Calls f for each value in a collection. If any call returns true this returns + * true (without checking the rest). If all returns false this returns false. + * + * @param {S} col The collection-like object. + * @param {function(this:T,?,?,S):boolean} f The function to call for every + * value. This function takes 3 arguments (the value, the key or undefined + * if the collection has no notion of keys, and the collection) and should + * return a boolean. + * @param {T=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {boolean} True if any value passes the test. + * @template T,S */ -ol.ImageBase.prototype.getResolution = function() { - goog.asserts.assert(this.resolution !== undefined, 'resolution not yet set'); - return this.resolution; +goog.structs.some = function(col, f, opt_obj) { + if (typeof col.some == 'function') { + return col.some(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.some(/** @type {!Array<?>} */ (col), f, opt_obj); + } + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], keys && keys[i], col)) { + return true; + } + } + return false; }; /** - * @return {ol.ImageState} State. + * Calls f for each value in a collection. If all calls return true this return + * true this returns true. If any returns false this returns false at this point + * and does not continue to check the remaining values. + * + * @param {S} col The collection-like object. + * @param {function(this:T,?,?,S):boolean} f The function to call for every + * value. This function takes 3 arguments (the value, the key or + * undefined if the collection has no notion of keys, and the collection) + * and should return a boolean. + * @param {T=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {boolean} True if all key-value pairs pass the test. + * @template T,S */ -ol.ImageBase.prototype.getState = function() { - return this.state; +goog.structs.every = function(col, f, opt_obj) { + if (typeof col.every == 'function') { + return col.every(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.every(/** @type {!Array<?>} */ (col), f, opt_obj); + } + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + if (!f.call(opt_obj, values[i], keys && keys[i], col)) { + return false; + } + } + return true; }; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Load not yet loaded URI. + * @fileoverview Defines the collection interface. + * + * @author nnaze@google.com (Nathan Naze) */ -ol.ImageBase.prototype.load = goog.abstractMethod; -goog.provide('ol.vec.Mat4'); -goog.provide('ol.vec.Mat4.Number'); +goog.provide('goog.structs.Collection'); -goog.require('goog.vec.Mat4'); /** - * A alias for the goog.vec.Number type. - * @typedef {goog.vec.Number} + * An interface for a collection of values. + * @interface + * @template T */ -ol.vec.Mat4.Number; +goog.structs.Collection = function() {}; /** - * @param {!goog.vec.Mat4.Number} mat Matrix. - * @param {number} translateX1 Translate X1. - * @param {number} translateY1 Translate Y1. - * @param {number} scaleX Scale X. - * @param {number} scaleY Scale Y. - * @param {number} rotation Rotation. - * @param {number} translateX2 Translate X2. - * @param {number} translateY2 Translate Y2. - * @return {!goog.vec.Mat4.Number} Matrix. + * @param {T} value Value to add to the collection. */ -ol.vec.Mat4.makeTransform2D = function(mat, translateX1, translateY1, - scaleX, scaleY, rotation, translateX2, translateY2) { - goog.vec.Mat4.makeIdentity(mat); - if (translateX1 !== 0 || translateY1 !== 0) { - goog.vec.Mat4.translate(mat, translateX1, translateY1, 0); - } - if (scaleX != 1 || scaleY != 1) { - goog.vec.Mat4.scale(mat, scaleX, scaleY, 1); - } - if (rotation !== 0) { - goog.vec.Mat4.rotateZ(mat, rotation); - } - if (translateX2 !== 0 || translateY2 !== 0) { - goog.vec.Mat4.translate(mat, translateX2, translateY2, 0); - } - return mat; -}; +goog.structs.Collection.prototype.add; /** - * Returns true if mat1 and mat2 represent the same 2D transformation. - * @param {goog.vec.Mat4.Number} mat1 Matrix 1. - * @param {goog.vec.Mat4.Number} mat2 Matrix 2. - * @return {boolean} Equal 2D. + * @param {T} value Value to remove from the collection. */ -ol.vec.Mat4.equals2D = function(mat1, mat2) { - return ( - goog.vec.Mat4.getElement(mat1, 0, 0) == - goog.vec.Mat4.getElement(mat2, 0, 0) && - goog.vec.Mat4.getElement(mat1, 1, 0) == - goog.vec.Mat4.getElement(mat2, 1, 0) && - goog.vec.Mat4.getElement(mat1, 0, 1) == - goog.vec.Mat4.getElement(mat2, 0, 1) && - goog.vec.Mat4.getElement(mat1, 1, 1) == - goog.vec.Mat4.getElement(mat2, 1, 1) && - goog.vec.Mat4.getElement(mat1, 0, 3) == - goog.vec.Mat4.getElement(mat2, 0, 3) && - goog.vec.Mat4.getElement(mat1, 1, 3) == - goog.vec.Mat4.getElement(mat2, 1, 3)); -}; +goog.structs.Collection.prototype.remove; /** - * Transforms the given vector with the given matrix storing the resulting, - * transformed vector into resultVec. The input vector is multiplied against the - * upper 2x4 matrix omitting the projective component. - * - * @param {goog.vec.Mat4.Number} mat The matrix supplying the transformation. - * @param {Array.<number>} vec The 3 element vector to transform. - * @param {Array.<number>} resultVec The 3 element vector to receive the results - * (may be vec). - * @return {Array.<number>} return resultVec so that operations can be - * chained together. + * @param {T} value Value to find in the collection. + * @return {boolean} Whether the collection contains the specified value. */ -ol.vec.Mat4.multVec2 = function(mat, vec, resultVec) { - var m00 = goog.vec.Mat4.getElement(mat, 0, 0); - var m10 = goog.vec.Mat4.getElement(mat, 1, 0); - var m01 = goog.vec.Mat4.getElement(mat, 0, 1); - var m11 = goog.vec.Mat4.getElement(mat, 1, 1); - var m03 = goog.vec.Mat4.getElement(mat, 0, 3); - var m13 = goog.vec.Mat4.getElement(mat, 1, 3); - var x = vec[0], y = vec[1]; - resultVec[0] = m00 * x + m01 * y + m03; - resultVec[1] = m10 * x + m11 * y + m13; - return resultVec; -}; +goog.structs.Collection.prototype.contains; -goog.provide('ol.renderer.Layer'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.functions'); -goog.require('ol'); -goog.require('ol.ImageState'); -goog.require('ol.Observable'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.layer.Layer'); -goog.require('ol.source.Source'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); +/** + * @return {number} The number of values stored in the collection. + */ +goog.structs.Collection.prototype.getCount; +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @constructor - * @extends {ol.Observable} - * @param {ol.layer.Layer} layer Layer. - * @struct + * @fileoverview Python style iteration utilities. + * @author arv@google.com (Erik Arvidsson) */ -ol.renderer.Layer = function(layer) { - - goog.base(this); - /** - * @private - * @type {ol.layer.Layer} - */ - this.layer_ = layer; +goog.provide('goog.iter'); +goog.provide('goog.iter.Iterable'); +goog.provide('goog.iter.Iterator'); +goog.provide('goog.iter.StopIteration'); -}; -goog.inherits(ol.renderer.Layer, ol.Observable); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('goog.math'); /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState Frame state. - * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T} - * callback Feature callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @return {T|undefined} Callback result. - * @template S,T + * @typedef {goog.iter.Iterator|{length:number}|{__iterator__}} */ -ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction; +goog.iter.Iterable; /** - * @param {ol.Pixel} pixel Pixel. - * @param {olx.FrameState} frameState Frame state. - * @param {function(this: S, ol.layer.Layer): T} callback Layer callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @return {T|undefined} Callback result. - * @template S,T + * Singleton Error object that is used to terminate iterations. + * @const {!Error} */ -ol.renderer.Layer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); +goog.iter.StopIteration = ('StopIteration' in goog.global) ? + // For script engines that support legacy iterators. + goog.global['StopIteration'] : + { message: 'StopIteration', stack: ''}; - if (hasFeature) { - return callback.call(thisArg, this.layer_); - } else { - return undefined; - } -}; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState Frame state. - * @return {boolean} Is there a feature at the given coordinate? + * Class/interface for iterators. An iterator needs to implement a {@code next} + * method and it needs to throw a {@code goog.iter.StopIteration} when the + * iteration passes beyond the end. Iterators have no {@code hasNext} method. + * It is recommended to always use the helper functions to iterate over the + * iterator or in case you are only targeting JavaScript 1.7 for in loops. + * @constructor + * @template VALUE */ -ol.renderer.Layer.prototype.hasFeatureAtCoordinate = goog.functions.FALSE; +goog.iter.Iterator = function() {}; /** - * Create a function that adds loaded tiles to the tile lookup. - * @param {ol.source.Tile} source Tile source. - * @param {ol.proj.Projection} projection Projection of the tiles. - * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded - * tiles by zoom level. - * @return {function(number, ol.TileRange):boolean} A function that can be - * called with a zoom level and a tile range to add loaded tiles to the - * lookup. - * @protected + * Returns the next value of the iteration. This will throw the object + * {@see goog.iter#StopIteration} when the iteration passes the end. + * @return {VALUE} Any object or value. */ -ol.renderer.Layer.prototype.createLoadedTileFinder = - function(source, projection, tiles) { - return ( - /** - * @param {number} zoom Zoom level. - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} The tile range is fully loaded. - */ - function(zoom, tileRange) { - return source.forEachLoadedTile(projection, zoom, - tileRange, function(tile) { - if (!tiles[zoom]) { - tiles[zoom] = {}; - } - tiles[zoom][tile.tileCoord.toString()] = tile; - }); - }); +goog.iter.Iterator.prototype.next = function() { + throw goog.iter.StopIteration; }; /** - * @return {ol.layer.Layer} Layer. + * Returns the {@code Iterator} object itself. This is used to implement + * the iterator protocol in JavaScript 1.7 + * @param {boolean=} opt_keys Whether to return the keys or values. Default is + * to only return the values. This is being used by the for-in loop (true) + * and the for-each-in loop (false). Even though the param gives a hint + * about what the iterator will return there is no guarantee that it will + * return the keys when true is passed. + * @return {!goog.iter.Iterator<VALUE>} The object itself. */ -ol.renderer.Layer.prototype.getLayer = function() { - return this.layer_; +goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) { + return this; }; /** - * Handle changes in image state. - * @param {goog.events.Event} event Image change event. - * @private + * Returns an iterator that knows how to iterate over the values in the object. + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable If the + * object is an iterator it will be returned as is. If the object has an + * {@code __iterator__} method that will be called to get the value + * iterator. If the object is an array-like object we create an iterator + * for that. + * @return {!goog.iter.Iterator<VALUE>} An iterator that knows how to iterate + * over the values in {@code iterable}. + * @template VALUE */ -ol.renderer.Layer.prototype.handleImageChange_ = function(event) { - var image = /** @type {ol.Image} */ (event.target); - if (image.getState() === ol.ImageState.LOADED) { - this.renderIfReadyAndVisible(); +goog.iter.toIterator = function(iterable) { + if (iterable instanceof goog.iter.Iterator) { + return iterable; } -}; - - -/** - * Load the image if not already loaded, and register the image change - * listener if needed. - * @param {ol.ImageBase} image Image. - * @return {boolean} `true` if the image is already loaded, `false` - * otherwise. - * @protected - */ -ol.renderer.Layer.prototype.loadImage = function(image) { - var imageState = image.getState(); - if (imageState != ol.ImageState.LOADED && - imageState != ol.ImageState.ERROR) { - // the image is either "idle" or "loading", register the change - // listener (a noop if the listener was already registered) - goog.asserts.assert(imageState == ol.ImageState.IDLE || - imageState == ol.ImageState.LOADING, - 'imageState is "idle" or "loading"'); - goog.events.listen(image, goog.events.EventType.CHANGE, - this.handleImageChange_, false, this); + if (typeof iterable.__iterator__ == 'function') { + return iterable.__iterator__(false); } - if (imageState == ol.ImageState.IDLE) { - image.load(); - imageState = image.getState(); - goog.asserts.assert(imageState == ol.ImageState.LOADING || - imageState == ol.ImageState.LOADED, - 'imageState is "loading" or "loaded"'); + if (goog.isArrayLike(iterable)) { + var i = 0; + var newIter = new goog.iter.Iterator; + newIter.next = function() { + while (true) { + if (i >= iterable.length) { + throw goog.iter.StopIteration; + } + // Don't include deleted elements. + if (!(i in iterable)) { + i++; + continue; + } + return iterable[i++]; + } + }; + return newIter; } - return imageState == ol.ImageState.LOADED; -}; -/** - * @protected - */ -ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() { - var layer = this.getLayer(); - if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) { - this.changed(); - } + // TODO(arv): Should we fall back on goog.structs.getValues()? + throw Error('Not implemented'); }; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.source.Tile} tileSource Tile source. - * @protected + * Calls a function for each element in the iterator with the element of the + * iterator passed as argument. + * + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * to iterate over. If the iterable is an object {@code toIterator} will be + * called on it. + * @param {function(this:THIS,VALUE,?,!goog.iter.Iterator<VALUE>)} f + * The function to call for every element. This function takes 3 arguments + * (the element, undefined, and the iterator) and the return value is + * irrelevant. The reason for passing undefined as the second argument is + * so that the same function can be used in {@see goog.array#forEach} as + * well as others. The third parameter is of type "number" for + * arraylike objects, undefined, otherwise. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @template THIS, VALUE */ -ol.renderer.Layer.prototype.scheduleExpireCache = - function(frameState, tileSource) { - if (tileSource.canExpireCache()) { - frameState.postRenderFunctions.push( - goog.partial( - /** - * @param {ol.source.Tile} tileSource Tile source. - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. - */ - function(tileSource, map, frameState) { - var tileSourceKey = goog.getUid(tileSource).toString(); - tileSource.expireCache(frameState.viewState.projection, - frameState.usedTiles[tileSourceKey]); - }, tileSource)); +goog.iter.forEach = function(iterable, f, opt_obj) { + if (goog.isArrayLike(iterable)) { + /** @preserveTry */ + try { + // NOTES: this passes the index number to the second parameter + // of the callback contrary to the documentation above. + goog.array.forEach(/** @type {goog.array.ArrayLike} */(iterable), f, + opt_obj); + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + } + } else { + iterable = goog.iter.toIterator(iterable); + /** @preserveTry */ + try { + while (true) { + f.call(opt_obj, iterable.next(), undefined, iterable); + } + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + } } }; /** - * @param {Object.<string, ol.Attribution>} attributionsSet Attributions - * set (target). - * @param {Array.<ol.Attribution>} attributions Attributions (source). - * @protected + * Calls a function for every element in the iterator, and if the function + * returns true adds the element to a new iterator. + * + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * to iterate over. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f + * The function to call for every element. This function takes 3 arguments + * (the element, undefined, and the iterator) and should return a boolean. + * If the return value is true the element will be included in the returned + * iterator. If it is false the element is not included. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements + * that passed the test are present. + * @template THIS, VALUE */ -ol.renderer.Layer.prototype.updateAttributions = - function(attributionsSet, attributions) { - if (attributions) { - var attribution, i, ii; - for (i = 0, ii = attributions.length; i < ii; ++i) { - attribution = attributions[i]; - attributionsSet[goog.getUid(attribution).toString()] = attribution; +goog.iter.filter = function(iterable, f, opt_obj) { + var iterator = goog.iter.toIterator(iterable); + var newIter = new goog.iter.Iterator; + newIter.next = function() { + while (true) { + var val = iterator.next(); + if (f.call(opt_obj, val, undefined, iterator)) { + return val; + } } - } + }; + return newIter; }; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.source.Source} source Source. - * @protected + * Calls a function for every element in the iterator, and if the function + * returns false adds the element to a new iterator. + * + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * to iterate over. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f + * The function to call for every element. This function takes 3 arguments + * (the element, undefined, and the iterator) and should return a boolean. + * If the return value is false the element will be included in the returned + * iterator. If it is true the element is not included. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements + * that did not pass the test are present. + * @template THIS, VALUE */ -ol.renderer.Layer.prototype.updateLogos = function(frameState, source) { - var logo = source.getLogo(); - if (logo !== undefined) { - if (goog.isString(logo)) { - frameState.logos[logo] = ''; - } else if (goog.isObject(logo)) { - goog.asserts.assertString(logo.href, 'logo.href is a string'); - goog.asserts.assertString(logo.src, 'logo.src is a string'); - frameState.logos[logo.src] = logo.href; - } - } +goog.iter.filterFalse = function(iterable, f, opt_obj) { + return goog.iter.filter(iterable, goog.functions.not(f), opt_obj); }; /** - * @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles. - * @param {ol.source.Tile} tileSource Tile source. - * @param {number} z Z. - * @param {ol.TileRange} tileRange Tile range. - * @protected + * Creates a new iterator that returns the values in a range. This function + * can take 1, 2 or 3 arguments: + * <pre> + * range(5) same as range(0, 5, 1) + * range(2, 5) same as range(2, 5, 1) + * </pre> + * + * @param {number} startOrStop The stop value if only one argument is provided. + * The start value if 2 or more arguments are provided. If only one + * argument is used the start value is 0. + * @param {number=} opt_stop The stop value. If left out then the first + * argument is used as the stop value. + * @param {number=} opt_step The number to increment with between each call to + * next. This can be negative. + * @return {!goog.iter.Iterator<number>} A new iterator that returns the values + * in the range. */ -ol.renderer.Layer.prototype.updateUsedTiles = - function(usedTiles, tileSource, z, tileRange) { - // FIXME should we use tilesToDrawByZ instead? - var tileSourceKey = goog.getUid(tileSource).toString(); - var zKey = z.toString(); - if (tileSourceKey in usedTiles) { - if (zKey in usedTiles[tileSourceKey]) { - usedTiles[tileSourceKey][zKey].extend(tileRange); - } else { - usedTiles[tileSourceKey][zKey] = tileRange; - } - } else { - usedTiles[tileSourceKey] = {}; - usedTiles[tileSourceKey][zKey] = tileRange; +goog.iter.range = function(startOrStop, opt_stop, opt_step) { + var start = 0; + var stop = startOrStop; + var step = opt_step || 1; + if (arguments.length > 1) { + start = startOrStop; + stop = opt_stop; + } + if (step == 0) { + throw Error('Range step argument must not be zero'); } + + var newIter = new goog.iter.Iterator; + newIter.next = function() { + if (step > 0 && start >= stop || step < 0 && start <= stop) { + throw goog.iter.StopIteration; + } + var rv = start; + start += step; + return rv; + }; + return newIter; }; /** - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {ol.Size} size Size. - * @protected - * @return {ol.Coordinate} Snapped center. + * Joins the values in a iterator with a delimiter. + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * to get the values from. + * @param {string} deliminator The text to put between the values. + * @return {string} The joined value string. + * @template VALUE */ -ol.renderer.Layer.prototype.snapCenterToPixel = - function(center, resolution, size) { - return [ - resolution * (Math.round(center[0] / resolution) + (size[0] % 2) / 2), - resolution * (Math.round(center[1] / resolution) + (size[1] % 2) / 2) - ]; +goog.iter.join = function(iterable, deliminator) { + return goog.iter.toArray(iterable).join(deliminator); }; /** - * Manage tile pyramid. - * This function performs a number of functions related to the tiles at the - * current zoom and lower zoom levels: - * - registers idle tiles in frameState.wantedTiles so that they are not - * discarded by the tile queue - * - enqueues missing tiles - * @param {olx.FrameState} frameState Frame state. - * @param {ol.source.Tile} tileSource Tile source. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {ol.Extent} extent Extent. - * @param {number} currentZ Current Z. - * @param {number} preload Load low resolution tiles up to 'preload' levels. - * @param {function(this: T, ol.Tile)=} opt_tileCallback Tile callback. - * @param {T=} opt_this Object to use as `this` in `opt_tileCallback`. - * @protected - * @template T + * For every element in the iterator call a function and return a new iterator + * with that value. + * + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterator to iterate over. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):RESULT} f + * The function to call for every element. This function takes 3 arguments + * (the element, undefined, and the iterator) and should return a new value. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the + * results of applying the function to each element in the original + * iterator. + * @template THIS, VALUE, RESULT */ -ol.renderer.Layer.prototype.manageTilePyramid = function( - frameState, tileSource, tileGrid, pixelRatio, projection, extent, - currentZ, preload, opt_tileCallback, opt_this) { - var tileSourceKey = goog.getUid(tileSource).toString(); - if (!(tileSourceKey in frameState.wantedTiles)) { - frameState.wantedTiles[tileSourceKey] = {}; - } - var wantedTiles = frameState.wantedTiles[tileSourceKey]; - var tileQueue = frameState.tileQueue; - var minZoom = tileGrid.getMinZoom(); - var tile, tileRange, tileResolution, x, y, z; - for (z = currentZ; z >= minZoom; --z) { - tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange); - tileResolution = tileGrid.getResolution(z); - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - if (currentZ - z <= preload) { - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - if (tile.getState() == ol.TileState.IDLE) { - wantedTiles[ol.tilecoord.toString(tile.tileCoord)] = true; - if (!tileQueue.isKeyQueued(tile.getKey())) { - tileQueue.enqueue([tile, tileSourceKey, - tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]); - } - } - if (opt_tileCallback !== undefined) { - opt_tileCallback.call(opt_this, tile); - } - } else { - tileSource.useTile(z, x, y, projection); - } - } - } - } +goog.iter.map = function(iterable, f, opt_obj) { + var iterator = goog.iter.toIterator(iterable); + var newIter = new goog.iter.Iterator; + newIter.next = function() { + var val = iterator.next(); + return f.call(opt_obj, val, undefined, iterator); + }; + return newIter; }; -goog.provide('ol.style.Image'); -goog.provide('ol.style.ImageState'); - /** - * @enum {number} + * Passes every element of an iterator into a function and accumulates the + * result. + * + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * to iterate over. + * @param {function(this:THIS,VALUE,VALUE):VALUE} f The function to call for + * every element. This function takes 2 arguments (the function's previous + * result or the initial value, and the value of the current element). + * function(previousValue, currentElement) : newValue. + * @param {VALUE} val The initial value to pass into the function on the first + * call. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * f. + * @return {VALUE} Result of evaluating f repeatedly across the values of + * the iterator. + * @template THIS, VALUE */ -ol.style.ImageState = { - IDLE: 0, - LOADING: 1, - LOADED: 2, - ERROR: 3 +goog.iter.reduce = function(iterable, f, val, opt_obj) { + var rval = val; + goog.iter.forEach(iterable, function(val) { + rval = f.call(opt_obj, rval, val); + }); + return rval; }; /** - * @typedef {{opacity: number, - * rotateWithView: boolean, - * rotation: number, - * scale: number, - * snapToPixel: boolean}} + * Goes through the values in the iterator. Calls f for each of these, and if + * any of them returns true, this returns true (without checking the rest). If + * all return false this will return false. + * + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * object. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f + * The function to call for every value. This function takes 3 arguments + * (the value, undefined, and the iterator) and should return a boolean. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {boolean} true if any value passes the test. + * @template THIS, VALUE */ -ol.style.ImageOptions; - +goog.iter.some = function(iterable, f, opt_obj) { + iterable = goog.iter.toIterator(iterable); + /** @preserveTry */ + try { + while (true) { + if (f.call(opt_obj, iterable.next(), undefined, iterable)) { + return true; + } + } + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + } + return false; +}; /** - * @classdesc - * A base class used for creating subclasses and not instantiated in - * apps. Base class for {@link ol.style.Icon} and {@link ol.style.Circle}. + * Goes through the values in the iterator. Calls f for each of these and if any + * of them returns false this returns false (without checking the rest). If all + * return true this will return true. * - * @constructor - * @param {ol.style.ImageOptions} options Options. - * @api - */ -ol.style.Image = function(options) { + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * object. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f + * The function to call for every value. This function takes 3 arguments + * (the value, undefined, and the iterator) and should return a boolean. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {boolean} true if every value passes the test. + * @template THIS, VALUE + */ +goog.iter.every = function(iterable, f, opt_obj) { + iterable = goog.iter.toIterator(iterable); + /** @preserveTry */ + try { + while (true) { + if (!f.call(opt_obj, iterable.next(), undefined, iterable)) { + return false; + } + } + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + } + return true; +}; - /** - * @private - * @type {number} - */ - this.opacity_ = options.opacity; - /** - * @private - * @type {boolean} - */ - this.rotateWithView_ = options.rotateWithView; +/** + * Takes zero or more iterables and returns one iterator that will iterate over + * them in the order chained. + * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any + * number of iterable objects. + * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will + * iterate over all the given iterables' contents. + * @template VALUE + */ +goog.iter.chain = function(var_args) { + return goog.iter.chainFromIterable(arguments); +}; - /** - * @private - * @type {number} - */ - this.rotation_ = options.rotation; - /** - * @private - * @type {number} - */ - this.scale_ = options.scale; +/** + * Takes a single iterable containing zero or more iterables and returns one + * iterator that will iterate over each one in the order given. + * @see http://docs.python.org/2/library/itertools.html#itertools.chain.from_iterable + * @param {goog.iter.Iterable} iterable The iterable of iterables to chain. + * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will + * iterate over all the contents of the iterables contained within + * {@code iterable}. + * @template VALUE + */ +goog.iter.chainFromIterable = function(iterable) { + var iterator = goog.iter.toIterator(iterable); + var iter = new goog.iter.Iterator(); + var current = null; - /** - * @private - * @type {boolean} - */ - this.snapToPixel_ = options.snapToPixel; + iter.next = function() { + while (true) { + if (current == null) { + var it = iterator.next(); + current = goog.iter.toIterator(it); + } + try { + return current.next(); + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + current = null; + } + } + }; + return iter; }; /** - * Get the symbolizer opacity. - * @return {number} Opacity. - * @api + * Builds a new iterator that iterates over the original, but skips elements as + * long as a supplied function returns true. + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * object. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f + * The function to call for every value. This function takes 3 arguments + * (the value, undefined, and the iterator) and should return a boolean. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {!goog.iter.Iterator<VALUE>} A new iterator that drops elements from + * the original iterator as long as {@code f} is true. + * @template THIS, VALUE */ -ol.style.Image.prototype.getOpacity = function() { - return this.opacity_; +goog.iter.dropWhile = function(iterable, f, opt_obj) { + var iterator = goog.iter.toIterator(iterable); + var newIter = new goog.iter.Iterator; + var dropping = true; + newIter.next = function() { + while (true) { + var val = iterator.next(); + if (dropping && f.call(opt_obj, val, undefined, iterator)) { + continue; + } else { + dropping = false; + } + return val; + } + }; + return newIter; }; /** - * Determine whether the symbolizer rotates with the map. - * @return {boolean} Rotate with map. - * @api + * Builds a new iterator that iterates over the original, but only as long as a + * supplied function returns true. + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * object. + * @param { + * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f + * The function to call for every value. This function takes 3 arguments + * (the value, undefined, and the iterator) and should return a boolean. + * @param {THIS=} opt_obj This is used as the 'this' object in f when called. + * @return {!goog.iter.Iterator<VALUE>} A new iterator that keeps elements in + * the original iterator as long as the function is true. + * @template THIS, VALUE */ -ol.style.Image.prototype.getRotateWithView = function() { - return this.rotateWithView_; +goog.iter.takeWhile = function(iterable, f, opt_obj) { + var iterator = goog.iter.toIterator(iterable); + var iter = new goog.iter.Iterator(); + iter.next = function() { + var val = iterator.next(); + if (f.call(opt_obj, val, undefined, iterator)) { + return val; + } + throw goog.iter.StopIteration; + }; + return iter; }; /** - * Get the symoblizer rotation. - * @return {number} Rotation. - * @api + * Converts the iterator to an array + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator + * to convert to an array. + * @return {!Array<VALUE>} An array of the elements the iterator iterates over. + * @template VALUE */ -ol.style.Image.prototype.getRotation = function() { - return this.rotation_; +goog.iter.toArray = function(iterable) { + // Fast path for array-like. + if (goog.isArrayLike(iterable)) { + return goog.array.toArray(/** @type {!goog.array.ArrayLike} */(iterable)); + } + iterable = goog.iter.toIterator(iterable); + var array = []; + goog.iter.forEach(iterable, function(val) { + array.push(val); + }); + return array; }; /** - * Get the symbolizer scale. - * @return {number} Scale. - * @api + * Iterates over two iterables and returns true if they contain the same + * sequence of elements and have the same length. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable1 The first + * iterable object. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable2 The second + * iterable object. + * @param {function(VALUE,VALUE):boolean=} opt_equalsFn Optional comparison + * function. + * Should take two arguments to compare, and return true if the arguments + * are equal. Defaults to {@link goog.array.defaultCompareEquality} which + * compares the elements using the built-in '===' operator. + * @return {boolean} true if the iterables contain the same sequence of elements + * and have the same length. + * @template VALUE */ -ol.style.Image.prototype.getScale = function() { - return this.scale_; +goog.iter.equals = function(iterable1, iterable2, opt_equalsFn) { + var fillValue = {}; + var pairs = goog.iter.zipLongest(fillValue, iterable1, iterable2); + var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality; + return goog.iter.every(pairs, function(pair) { + return equalsFn(pair[0], pair[1]); + }); }; /** - * Determine whether the symbolizer should be snapped to a pixel. - * @return {boolean} The symbolizer should snap to a pixel. - * @api + * Advances the iterator to the next position, returning the given default value + * instead of throwing an exception if the iterator has no more entries. + * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterable + * object. + * @param {VALUE} defaultValue The value to return if the iterator is empty. + * @return {VALUE} The next item in the iteration, or defaultValue if the + * iterator was empty. + * @template VALUE */ -ol.style.Image.prototype.getSnapToPixel = function() { - return this.snapToPixel_; +goog.iter.nextOrValue = function(iterable, defaultValue) { + try { + return goog.iter.toIterator(iterable).next(); + } catch (e) { + if (e != goog.iter.StopIteration) { + throw e; + } + return defaultValue; + } }; /** - * Get the anchor point. The anchor determines the center point for the - * symbolizer. Its units are determined by `anchorXUnits` and `anchorYUnits`. - * @function - * @return {Array.<number>} Anchor. + * Cartesian product of zero or more sets. Gives an iterator that gives every + * combination of one element chosen from each set. For example, + * ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]). + * @see http://docs.python.org/library/itertools.html#itertools.product + * @param {...!goog.array.ArrayLike<VALUE>} var_args Zero or more sets, as + * arrays. + * @return {!goog.iter.Iterator<!Array<VALUE>>} An iterator that gives each + * n-tuple (as an array). + * @template VALUE */ -ol.style.Image.prototype.getAnchor = goog.abstractMethod; - +goog.iter.product = function(var_args) { + var someArrayEmpty = goog.array.some(arguments, function(arr) { + return !arr.length; + }); -/** - * Get the image element for the symbolizer. - * @function - * @param {number} pixelRatio Pixel ratio. - * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element. - */ -ol.style.Image.prototype.getImage = goog.abstractMethod; + // An empty set in a cartesian product gives an empty set. + if (someArrayEmpty || !arguments.length) { + return new goog.iter.Iterator(); + } + var iter = new goog.iter.Iterator(); + var arrays = arguments; -/** - * @param {number} pixelRatio Pixel ratio. - * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element. - */ -ol.style.Image.prototype.getHitDetectionImage = goog.abstractMethod; + // The first indices are [0, 0, ...] + var indicies = goog.array.repeat(0, arrays.length); + iter.next = function() { -/** - * @return {ol.style.ImageState} Image state. - */ -ol.style.Image.prototype.getImageState = goog.abstractMethod; + if (indicies) { + var retVal = goog.array.map(indicies, function(valueIndex, arrayIndex) { + return arrays[arrayIndex][valueIndex]; + }); + // Generate the next-largest indices for the next call. + // Increase the rightmost index. If it goes over, increase the next + // rightmost (like carry-over addition). + for (var i = indicies.length - 1; i >= 0; i--) { + // Assertion prevents compiler warning below. + goog.asserts.assert(indicies); + if (indicies[i] < arrays[i].length - 1) { + indicies[i]++; + break; + } -/** - * @return {ol.Size} Image size. - */ -ol.style.Image.prototype.getImageSize = goog.abstractMethod; + // We're at the last indices (the last element of every array), so + // the iteration is over on the next call. + if (i == 0) { + indicies = null; + break; + } + // Reset the index in this column and loop back to increment the + // next one. + indicies[i] = 0; + } + return retVal; + } + throw goog.iter.StopIteration; + }; -/** - * @return {ol.Size} Size of the hit-detection image. - */ -ol.style.Image.prototype.getHitDetectionImageSize = goog.abstractMethod; + return iter; +}; /** - * Get the origin of the symbolizer. - * @function - * @return {Array.<number>} Origin. + * Create an iterator to cycle over the iterable's elements indefinitely. + * For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ... + * @see: http://docs.python.org/library/itertools.html#itertools.cycle. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable object. + * @return {!goog.iter.Iterator<VALUE>} An iterator that iterates indefinitely + * over the values in {@code iterable}. + * @template VALUE */ -ol.style.Image.prototype.getOrigin = goog.abstractMethod; +goog.iter.cycle = function(iterable) { + var baseIterator = goog.iter.toIterator(iterable); + // We maintain a cache to store the iterable elements as we iterate + // over them. The cache is used to return elements once we have + // iterated over the iterable once. + var cache = []; + var cacheIndex = 0; -/** - * Get the size of the symbolizer (in pixels). - * @function - * @return {ol.Size} Size. - */ -ol.style.Image.prototype.getSize = goog.abstractMethod; + var iter = new goog.iter.Iterator(); + // This flag is set after the iterable is iterated over once + var useCache = false; -/** - * Set the opacity. - * - * @param {number} opacity Opacity. - * @api - */ -ol.style.Image.prototype.setOpacity = function(opacity) { - this.opacity_ = opacity; -}; + iter.next = function() { + var returnElement = null; + // Pull elements off the original iterator if not using cache + if (!useCache) { + try { + // Return the element from the iterable + returnElement = baseIterator.next(); + cache.push(returnElement); + return returnElement; + } catch (e) { + // If an exception other than StopIteration is thrown + // or if there are no elements to iterate over (the iterable was empty) + // throw an exception + if (e != goog.iter.StopIteration || goog.array.isEmpty(cache)) { + throw e; + } + // set useCache to true after we know that a 'StopIteration' exception + // was thrown and the cache is not empty (to handle the 'empty iterable' + // use case) + useCache = true; + } + } -/** - * Set whether to rotate the style with the view. - * - * @param {boolean} rotateWithView Rotate with map. - */ -ol.style.Image.prototype.setRotateWithView = function(rotateWithView) { - this.rotateWithView_ = rotateWithView; -}; + returnElement = cache[cacheIndex]; + cacheIndex = (cacheIndex + 1) % cache.length; + return returnElement; + }; -/** - * Set the rotation. - * - * @param {number} rotation Rotation. - * @api - */ -ol.style.Image.prototype.setRotation = function(rotation) { - this.rotation_ = rotation; + return iter; }; /** - * Set the scale. - * - * @param {number} scale Scale. - * @api + * Creates an iterator that counts indefinitely from a starting value. + * @see http://docs.python.org/2/library/itertools.html#itertools.count + * @param {number=} opt_start The starting value. Default is 0. + * @param {number=} opt_step The number to increment with between each call to + * next. Negative and floating point numbers are allowed. Default is 1. + * @return {!goog.iter.Iterator<number>} A new iterator that returns the values + * in the series. */ -ol.style.Image.prototype.setScale = function(scale) { - this.scale_ = scale; -}; +goog.iter.count = function(opt_start, opt_step) { + var counter = opt_start || 0; + var step = goog.isDef(opt_step) ? opt_step : 1; + var iter = new goog.iter.Iterator(); + iter.next = function() { + var returnValue = counter; + counter += step; + return returnValue; + }; -/** - * Set whether to snap the image to the closest pixel. - * - * @param {boolean} snapToPixel Snap to pixel? - */ -ol.style.Image.prototype.setSnapToPixel = function(snapToPixel) { - this.snapToPixel_ = snapToPixel; + return iter; }; /** - * @param {function(this: T, goog.events.Event)} listener Listener function. - * @param {T} thisArg Value to use as `this` when executing `listener`. - * @return {goog.events.Key|undefined} Listener key. - * @template T + * Creates an iterator that returns the same object or value repeatedly. + * @param {VALUE} value Any object or value to repeat. + * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the + * repeated value. + * @template VALUE */ -ol.style.Image.prototype.listenImageChange = goog.abstractMethod; +goog.iter.repeat = function(value) { + var iter = new goog.iter.Iterator(); + iter.next = goog.functions.constant(value); -/** - * Load not yet loaded URI. - */ -ol.style.Image.prototype.load = goog.abstractMethod; + return iter; +}; /** - * @param {function(this: T, goog.events.Event)} listener Listener function. - * @param {T} thisArg Value to use as `this` when executing `listener`. - * @template T + * Creates an iterator that returns running totals from the numbers in + * {@code iterable}. For example, the array {@code [1, 2, 3, 4, 5]} yields + * {@code 1 -> 3 -> 6 -> 10 -> 15}. + * @see http://docs.python.org/3.2/library/itertools.html#itertools.accumulate + * @param {!goog.iter.Iterable<number>} iterable The iterable of numbers to + * accumulate. + * @return {!goog.iter.Iterator<number>} A new iterator that returns the + * numbers in the series. */ -ol.style.Image.prototype.unlistenImageChange = goog.abstractMethod; +goog.iter.accumulate = function(iterable) { + var iterator = goog.iter.toIterator(iterable); + var total = 0; + var iter = new goog.iter.Iterator(); -goog.provide('ol.style.Icon'); -goog.provide('ol.style.IconAnchorUnits'); -goog.provide('ol.style.IconImageCache'); -goog.provide('ol.style.IconOrigin'); + iter.next = function() { + total += iterator.next(); + return total; + }; -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('ol.dom'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); + return iter; +}; /** - * Icon anchor units. One of 'fraction', 'pixels'. - * @enum {string} - * @api + * Creates an iterator that returns arrays containing the ith elements from the + * provided iterables. The returned arrays will be the same size as the number + * of iterables given in {@code var_args}. Once the shortest iterable is + * exhausted, subsequent calls to {@code next()} will throw + * {@code goog.iter.StopIteration}. + * @see http://docs.python.org/2/library/itertools.html#itertools.izip + * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any + * number of iterable objects. + * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns + * arrays of elements from the provided iterables. + * @template VALUE */ -ol.style.IconAnchorUnits = { - FRACTION: 'fraction', - PIXELS: 'pixels' +goog.iter.zip = function(var_args) { + var args = arguments; + var iter = new goog.iter.Iterator(); + + if (args.length > 0) { + var iterators = goog.array.map(args, goog.iter.toIterator); + iter.next = function() { + var arr = goog.array.map(iterators, function(it) { + return it.next(); + }); + return arr; + }; + } + + return iter; }; /** - * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'. - * @enum {string} - * @api - */ -ol.style.IconOrigin = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_RIGHT: 'bottom-right', - TOP_LEFT: 'top-left', - TOP_RIGHT: 'top-right' -}; - - - -/** - * @classdesc - * Set icon style for vector features. - * - * @constructor - * @param {olx.style.IconOptions=} opt_options Options. - * @extends {ol.style.Image} - * @api + * Creates an iterator that returns arrays containing the ith elements from the + * provided iterables. The returned arrays will be the same size as the number + * of iterables given in {@code var_args}. Shorter iterables will be extended + * with {@code fillValue}. Once the longest iterable is exhausted, subsequent + * calls to {@code next()} will throw {@code goog.iter.StopIteration}. + * @see http://docs.python.org/2/library/itertools.html#itertools.izip_longest + * @param {VALUE} fillValue The object or value used to fill shorter iterables. + * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any + * number of iterable objects. + * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns + * arrays of elements from the provided iterables. + * @template VALUE */ -ol.style.Icon = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {Array.<number>} - */ - this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5]; - - /** - * @private - * @type {Array.<number>} - */ - this.normalizedAnchor_ = null; - - /** - * @private - * @type {ol.style.IconOrigin} - */ - this.anchorOrigin_ = options.anchorOrigin !== undefined ? - options.anchorOrigin : ol.style.IconOrigin.TOP_LEFT; - - /** - * @private - * @type {ol.style.IconAnchorUnits} - */ - this.anchorXUnits_ = options.anchorXUnits !== undefined ? - options.anchorXUnits : ol.style.IconAnchorUnits.FRACTION; - - /** - * @private - * @type {ol.style.IconAnchorUnits} - */ - this.anchorYUnits_ = options.anchorYUnits !== undefined ? - options.anchorYUnits : ol.style.IconAnchorUnits.FRACTION; - - /** - * @type {?string} - */ - var crossOrigin = - options.crossOrigin !== undefined ? options.crossOrigin : null; - - /** - * @type {Image} - */ - var image = options.img !== undefined ? options.img : null; - - /** - * @type {ol.Size} - */ - var imgSize = options.imgSize !== undefined ? options.imgSize : null; +goog.iter.zipLongest = function(fillValue, var_args) { + var args = goog.array.slice(arguments, 1); + var iter = new goog.iter.Iterator(); - /** - * @type {string|undefined} - */ - var src = options.src; + if (args.length > 0) { + var iterators = goog.array.map(args, goog.iter.toIterator); - goog.asserts.assert(!(src !== undefined && image), - 'image and src can not provided at the same time'); - goog.asserts.assert( - src === undefined || (src !== undefined && !imgSize), - 'imgSize should not be set when src is provided'); - goog.asserts.assert( - !image || (image && imgSize), - 'imgSize must be set when image is provided'); + iter.next = function() { + var iteratorsHaveValues = false; // false when all iterators are empty. + var arr = goog.array.map(iterators, function(it) { + var returnValue; + try { + returnValue = it.next(); + // Iterator had a value, so we've not exhausted the iterators. + // Set flag accordingly. + iteratorsHaveValues = true; + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + returnValue = fillValue; + } + return returnValue; + }); - if ((src === undefined || src.length === 0) && image) { - src = image.src; + if (!iteratorsHaveValues) { + throw goog.iter.StopIteration; + } + return arr; + }; } - goog.asserts.assert(src !== undefined && src.length > 0, - 'must provide a defined and non-empty src or image'); - /** - * @type {ol.style.ImageState} - */ - var imageState = options.src !== undefined ? - ol.style.ImageState.IDLE : ol.style.ImageState.LOADED; + return iter; +}; - /** - * @private - * @type {ol.style.IconImage_} - */ - this.iconImage_ = ol.style.IconImage_.get( - image, src, imgSize, crossOrigin, imageState); - /** - * @private - * @type {Array.<number>} - */ - this.offset_ = options.offset !== undefined ? options.offset : [0, 0]; +/** + * Creates an iterator that filters {@code iterable} based on a series of + * {@code selectors}. On each call to {@code next()}, one item is taken from + * both the {@code iterable} and {@code selectors} iterators. If the item from + * {@code selectors} evaluates to true, the item from {@code iterable} is given. + * Otherwise, it is skipped. Once either {@code iterable} or {@code selectors} + * is exhausted, subsequent calls to {@code next()} will throw + * {@code goog.iter.StopIteration}. + * @see http://docs.python.org/2/library/itertools.html#itertools.compress + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to filter. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} selectors An + * iterable of items to be evaluated in a boolean context to determine if + * the corresponding element in {@code iterable} should be included in the + * result. + * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the + * filtered values. + * @template VALUE + */ +goog.iter.compress = function(iterable, selectors) { + var selectorIterator = goog.iter.toIterator(selectors); - /** - * @private - * @type {ol.style.IconOrigin} - */ - this.offsetOrigin_ = options.offsetOrigin !== undefined ? - options.offsetOrigin : ol.style.IconOrigin.TOP_LEFT; + return goog.iter.filter(iterable, function() { + return !!selectorIterator.next(); + }); +}; - /** - * @private - * @type {Array.<number>} - */ - this.origin_ = null; - /** - * @private - * @type {ol.Size} - */ - this.size_ = options.size !== undefined ? options.size : null; + +/** + * Implements the {@code goog.iter.groupBy} iterator. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to group. + * @param {function(...VALUE): KEY=} opt_keyFunc Optional function for + * determining the key value for each group in the {@code iterable}. Default + * is the identity function. + * @constructor + * @extends {goog.iter.Iterator<!Array<?>>} + * @template KEY, VALUE + * @private + */ +goog.iter.GroupByIterator_ = function(iterable, opt_keyFunc) { /** - * @type {number} + * The iterable to group, coerced to an iterator. + * @type {!goog.iter.Iterator} */ - var opacity = options.opacity !== undefined ? options.opacity : 1; + this.iterator = goog.iter.toIterator(iterable); /** - * @type {boolean} + * A function for determining the key value for each element in the iterable. + * If no function is provided, the identity function is used and returns the + * element unchanged. + * @type {function(...VALUE): KEY} */ - var rotateWithView = options.rotateWithView !== undefined ? - options.rotateWithView : false; + this.keyFunc = opt_keyFunc || goog.functions.identity; /** - * @type {number} + * The target key for determining the start of a group. + * @type {KEY} */ - var rotation = options.rotation !== undefined ? options.rotation : 0; + this.targetKey; /** - * @type {number} + * The current key visited during iteration. + * @type {KEY} */ - var scale = options.scale !== undefined ? options.scale : 1; + this.currentKey; /** - * @type {boolean} + * The current value being added to the group. + * @type {VALUE} */ - var snapToPixel = options.snapToPixel !== undefined ? - options.snapToPixel : true; + this.currentValue; +}; +goog.inherits(goog.iter.GroupByIterator_, goog.iter.Iterator); - goog.base(this, { - opacity: opacity, - rotation: rotation, - scale: scale, - snapToPixel: snapToPixel, - rotateWithView: rotateWithView - }); +/** @override */ +goog.iter.GroupByIterator_.prototype.next = function() { + while (this.currentKey == this.targetKey) { + this.currentValue = this.iterator.next(); // Exits on StopIteration + this.currentKey = this.keyFunc(this.currentValue); + } + this.targetKey = this.currentKey; + return [this.currentKey, this.groupItems_(this.targetKey)]; }; -goog.inherits(ol.style.Icon, ol.style.Image); /** - * @inheritDoc - * @api + * Performs the grouping of objects using the given key. + * @param {KEY} targetKey The target key object for the group. + * @return {!Array<VALUE>} An array of grouped objects. + * @private */ -ol.style.Icon.prototype.getAnchor = function() { - if (this.normalizedAnchor_) { - return this.normalizedAnchor_; - } - var anchor = this.anchor_; - var size = this.getSize(); - if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION || - this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { - if (!size) { - return null; - } - anchor = this.anchor_.slice(); - if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION) { - anchor[0] *= size[0]; - } - if (this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { - anchor[1] *= size[1]; - } - } - - if (this.anchorOrigin_ != ol.style.IconOrigin.TOP_LEFT) { - if (!size) { - return null; - } - if (anchor === this.anchor_) { - anchor = this.anchor_.slice(); - } - if (this.anchorOrigin_ == ol.style.IconOrigin.TOP_RIGHT || - this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - anchor[0] = -anchor[0] + size[0]; - } - if (this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || - this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - anchor[1] = -anchor[1] + size[1]; +goog.iter.GroupByIterator_.prototype.groupItems_ = function(targetKey) { + var arr = []; + while (this.currentKey == targetKey) { + arr.push(this.currentValue); + try { + this.currentValue = this.iterator.next(); + } catch (ex) { + if (ex !== goog.iter.StopIteration) { + throw ex; + } + break; } + this.currentKey = this.keyFunc(this.currentValue); } - this.normalizedAnchor_ = anchor; - return this.normalizedAnchor_; + return arr; }; /** - * Get the image icon. - * @param {number} pixelRatio Pixel ratio. - * @return {Image} Image element. - * @api + * Creates an iterator that returns arrays containing elements from the + * {@code iterable} grouped by a key value. For iterables with repeated + * elements (i.e. sorted according to a particular key function), this function + * has a {@code uniq}-like effect. For example, grouping the array: + * {@code [A, B, B, C, C, A]} produces + * {@code [A, [A]], [B, [B, B]], [C, [C, C]], [A, [A]]}. + * @see http://docs.python.org/2/library/itertools.html#itertools.groupby + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to group. + * @param {function(...VALUE): KEY=} opt_keyFunc Optional function for + * determining the key value for each group in the {@code iterable}. Default + * is the identity function. + * @return {!goog.iter.Iterator<!Array<?>>} A new iterator that returns + * arrays of consecutive key and groups. + * @template KEY, VALUE */ -ol.style.Icon.prototype.getImage = function(pixelRatio) { - return this.iconImage_.getImage(pixelRatio); +goog.iter.groupBy = function(iterable, opt_keyFunc) { + return new goog.iter.GroupByIterator_(iterable, opt_keyFunc); }; /** - * Real Image size used. - * @return {ol.Size} Size. + * Gives an iterator that gives the result of calling the given function + * <code>f</code> with the arguments taken from the next element from + * <code>iterable</code> (the elements are expected to also be iterables). + * + * Similar to {@see goog.iter#map} but allows the function to accept multiple + * arguments from the iterable. + * + * @param {!goog.iter.Iterable<!goog.iter.Iterable>} iterable The iterable of + * iterables to iterate over. + * @param {function(this:THIS,...*):RESULT} f The function to call for every + * element. This function takes N+2 arguments, where N represents the + * number of items from the next element of the iterable. The two + * additional arguments passed to the function are undefined and the + * iterator itself. The function should return a new value. + * @param {THIS=} opt_obj The object to be used as the value of 'this' within + * {@code f}. + * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the + * results of applying the function to each element in the original + * iterator. + * @template THIS, RESULT */ -ol.style.Icon.prototype.getImageSize = function() { - return this.iconImage_.getSize(); -}; +goog.iter.starMap = function(iterable, f, opt_obj) { + var iterator = goog.iter.toIterator(iterable); + var iter = new goog.iter.Iterator(); + iter.next = function() { + var args = goog.iter.toArray(iterator.next()); + return f.apply(opt_obj, goog.array.concat(args, undefined, iterator)); + }; -/** - * @inheritDoc - */ -ol.style.Icon.prototype.getHitDetectionImageSize = function() { - return this.getImageSize(); + return iter; }; /** - * @inheritDoc + * Returns an array of iterators each of which can iterate over the values in + * {@code iterable} without advancing the others. + * @see http://docs.python.org/2/library/itertools.html#itertools.tee + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to tee. + * @param {number=} opt_num The number of iterators to create. Default is 2. + * @return {!Array<goog.iter.Iterator<VALUE>>} An array of iterators. + * @template VALUE */ -ol.style.Icon.prototype.getImageState = function() { - return this.iconImage_.getImageState(); -}; +goog.iter.tee = function(iterable, opt_num) { + var iterator = goog.iter.toIterator(iterable); + var num = goog.isNumber(opt_num) ? opt_num : 2; + var buffers = goog.array.map(goog.array.range(num), function() { + return []; + }); + var addNextIteratorValueToBuffers = function() { + var val = iterator.next(); + goog.array.forEach(buffers, function(buffer) { + buffer.push(val); + }); + }; -/** - * @inheritDoc - */ -ol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) { - return this.iconImage_.getHitDetectionImage(pixelRatio); -}; + var createIterator = function(buffer) { + // Each tee'd iterator has an associated buffer (initially empty). When a + // tee'd iterator's buffer is empty, it calls + // addNextIteratorValueToBuffers(), adding the next value to all tee'd + // iterators' buffers, and then returns that value. This allows each + // iterator to be advanced independently. + var iter = new goog.iter.Iterator(); + iter.next = function() { + if (goog.array.isEmpty(buffer)) { + addNextIteratorValueToBuffers(); + } + goog.asserts.assert(!goog.array.isEmpty(buffer)); + return buffer.shift(); + }; -/** - * @inheritDoc - * @api - */ -ol.style.Icon.prototype.getOrigin = function() { - if (this.origin_) { - return this.origin_; - } - var offset = this.offset_; + return iter; + }; - if (this.offsetOrigin_ != ol.style.IconOrigin.TOP_LEFT) { - var size = this.getSize(); - var iconImageSize = this.iconImage_.getSize(); - if (!size || !iconImageSize) { - return null; - } - offset = offset.slice(); - if (this.offsetOrigin_ == ol.style.IconOrigin.TOP_RIGHT || - this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - offset[0] = iconImageSize[0] - size[0] - offset[0]; - } - if (this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || - this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { - offset[1] = iconImageSize[1] - size[1] - offset[1]; - } - } - this.origin_ = offset; - return this.origin_; + return goog.array.map(buffers, createIterator); }; /** - * Get the image URL. - * @return {string|undefined} Image src. - * @api + * Creates an iterator that returns arrays containing a count and an element + * obtained from the given {@code iterable}. + * @see http://docs.python.org/2/library/functions.html#enumerate + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to enumerate. + * @param {number=} opt_start Optional starting value. Default is 0. + * @return {!goog.iter.Iterator<!Array<?>>} A new iterator containing + * count/item pairs. + * @template VALUE */ -ol.style.Icon.prototype.getSrc = function() { - return this.iconImage_.getSrc(); +goog.iter.enumerate = function(iterable, opt_start) { + return goog.iter.zip(goog.iter.count(opt_start), iterable); }; /** - * @inheritDoc - * @api + * Creates an iterator that returns the first {@code limitSize} elements from an + * iterable. If this number is greater than the number of elements in the + * iterable, all the elements are returned. + * @see http://goo.gl/V0sihp Inspired by the limit iterator in Guava. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to limit. + * @param {number} limitSize The maximum number of elements to return. + * @return {!goog.iter.Iterator<VALUE>} A new iterator containing + * {@code limitSize} elements. + * @template VALUE */ -ol.style.Icon.prototype.getSize = function() { - return !this.size_ ? this.iconImage_.getSize() : this.size_; -}; +goog.iter.limit = function(iterable, limitSize) { + goog.asserts.assert(goog.math.isInt(limitSize) && limitSize >= 0); + var iterator = goog.iter.toIterator(iterable); -/** - * @inheritDoc - */ -ol.style.Icon.prototype.listenImageChange = function(listener, thisArg) { - return goog.events.listen(this.iconImage_, goog.events.EventType.CHANGE, - listener, false, thisArg); -}; + var iter = new goog.iter.Iterator(); + var remaining = limitSize; + iter.next = function() { + if (remaining-- > 0) { + return iterator.next(); + } + throw goog.iter.StopIteration; + }; -/** - * Load not yet loaded URI. - * When rendering a feature with an icon style, the vector renderer will - * automatically call this method. However, you might want to call this - * method yourself for preloading or other purposes. - * @api - */ -ol.style.Icon.prototype.load = function() { - this.iconImage_.load(); + return iter; }; /** - * @inheritDoc + * Creates an iterator that is advanced {@code count} steps ahead. Consumed + * values are silently discarded. If {@code count} is greater than the number + * of elements in {@code iterable}, an empty iterator is returned. Subsequent + * calls to {@code next()} will throw {@code goog.iter.StopIteration}. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to consume. + * @param {number} count The number of elements to consume from the iterator. + * @return {!goog.iter.Iterator<VALUE>} An iterator advanced zero or more steps + * ahead. + * @template VALUE */ -ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) { - goog.events.unlisten(this.iconImage_, goog.events.EventType.CHANGE, - listener, false, thisArg); -}; +goog.iter.consume = function(iterable, count) { + goog.asserts.assert(goog.math.isInt(count) && count >= 0); + var iterator = goog.iter.toIterator(iterable); + while (count-- > 0) { + goog.iter.nextOrValue(iterator, null); + } -/** - * @constructor - * @param {Image} image Image. - * @param {string|undefined} src Src. - * @param {ol.Size} size Size. - * @param {?string} crossOrigin Cross origin. - * @param {ol.style.ImageState} imageState Image state. - * @extends {goog.events.EventTarget} - * @private - */ -ol.style.IconImage_ = function(image, src, size, crossOrigin, imageState) { - - goog.base(this); - - /** - * @private - * @type {Image|HTMLCanvasElement} - */ - this.hitDetectionImage_ = null; - - /** - * @private - * @type {Image} - */ - this.image_ = !image ? new Image() : image; - - if (crossOrigin !== null) { - this.image_.crossOrigin = crossOrigin; - } - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.imageListenerKeys_ = null; - - /** - * @private - * @type {ol.style.ImageState} - */ - this.imageState_ = imageState; - - /** - * @private - * @type {ol.Size} - */ - this.size_ = size; - - /** - * @private - * @type {string|undefined} - */ - this.src_ = src; - - /** - * @private - * @type {boolean} - */ - this.tainting_ = false; - if (this.imageState_ == ol.style.ImageState.LOADED) { - this.determineTainting_(); - } - + return iterator; }; -goog.inherits(ol.style.IconImage_, goog.events.EventTarget); /** - * @param {Image} image Image. - * @param {string} src Src. - * @param {ol.Size} size Size. - * @param {?string} crossOrigin Cross origin. - * @param {ol.style.ImageState} imageState Image state. - * @return {ol.style.IconImage_} Icon image. + * Creates an iterator that returns a range of elements from an iterable. + * Similar to {@see goog.array#slice} but does not support negative indexes. + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to slice. + * @param {number} start The index of the first element to return. + * @param {number=} opt_end The index after the last element to return. If + * defined, must be greater than or equal to {@code start}. + * @return {!goog.iter.Iterator<VALUE>} A new iterator containing a slice of + * the original. + * @template VALUE */ -ol.style.IconImage_.get = function(image, src, size, crossOrigin, imageState) { - var iconImageCache = ol.style.IconImageCache.getInstance(); - var iconImage = iconImageCache.get(src, crossOrigin); - if (!iconImage) { - iconImage = new ol.style.IconImage_( - image, src, size, crossOrigin, imageState); - iconImageCache.set(src, crossOrigin, iconImage); - } - return iconImage; -}; +goog.iter.slice = function(iterable, start, opt_end) { + goog.asserts.assert(goog.math.isInt(start) && start >= 0); + var iterator = goog.iter.consume(iterable, start); -/** - * @private - */ -ol.style.IconImage_.prototype.determineTainting_ = function() { - var context = ol.dom.createCanvasContext2D(1, 1); - try { - context.drawImage(this.image_, 0, 0); - context.getImageData(0, 0, 1, 1); - } catch (e) { - this.tainting_ = true; + if (goog.isNumber(opt_end)) { + goog.asserts.assert(goog.math.isInt(opt_end) && opt_end >= start); + iterator = goog.iter.limit(iterator, opt_end - start /* limitSize */); } -}; - -/** - * @private - */ -ol.style.IconImage_.prototype.dispatchChangeEvent_ = function() { - this.dispatchEvent(goog.events.EventType.CHANGE); + return iterator; }; /** + * Checks an array for duplicate elements. + * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to check for + * duplicates. + * @return {boolean} True, if the array contains duplicates, false otherwise. * @private + * @template VALUE */ -ol.style.IconImage_.prototype.handleImageError_ = function() { - this.imageState_ = ol.style.ImageState.ERROR; - this.unlistenImage_(); - this.dispatchChangeEvent_(); +// TODO(user): Consider moving this into goog.array as a public function. +goog.iter.hasDuplicates_ = function(arr) { + var deduped = []; + goog.array.removeDuplicates(arr, deduped); + return arr.length != deduped.length; }; /** - * @private + * Creates an iterator that returns permutations of elements in + * {@code iterable}. + * + * Permutations are obtained by taking the Cartesian product of + * {@code opt_length} iterables and filtering out those with repeated + * elements. For example, the permutations of {@code [1,2,3]} are + * {@code [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]}. + * @see http://docs.python.org/2/library/itertools.html#itertools.permutations + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable from which to generate permutations. + * @param {number=} opt_length Length of each permutation. If omitted, defaults + * to the length of {@code iterable}. + * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing the + * permutations of {@code iterable}. + * @template VALUE */ -ol.style.IconImage_.prototype.handleImageLoad_ = function() { - this.imageState_ = ol.style.ImageState.LOADED; - this.size_ = [this.image_.width, this.image_.height]; - this.unlistenImage_(); - this.determineTainting_(); - this.dispatchChangeEvent_(); -}; +goog.iter.permutations = function(iterable, opt_length) { + var elements = goog.iter.toArray(iterable); + var length = goog.isNumber(opt_length) ? opt_length : elements.length; + var sets = goog.array.repeat(elements, length); + var product = goog.iter.product.apply(undefined, sets); -/** - * @param {number} pixelRatio Pixel ratio. - * @return {Image} Image element. - */ -ol.style.IconImage_.prototype.getImage = function(pixelRatio) { - return this.image_; + return goog.iter.filter(product, function(arr) { + return !goog.iter.hasDuplicates_(arr); + }); }; /** - * @return {ol.style.ImageState} Image state. + * Creates an iterator that returns combinations of elements from + * {@code iterable}. + * + * Combinations are obtained by taking the {@see goog.iter#permutations} of + * {@code iterable} and filtering those whose elements appear in the order they + * are encountered in {@code iterable}. For example, the 3-length combinations + * of {@code [0,1,2,3]} are {@code [[0,1,2], [0,1,3], [0,2,3], [1,2,3]]}. + * @see http://docs.python.org/2/library/itertools.html#itertools.combinations + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable from which to generate combinations. + * @param {number} length The length of each combination. + * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing + * combinations from the {@code iterable}. + * @template VALUE */ -ol.style.IconImage_.prototype.getImageState = function() { - return this.imageState_; -}; +goog.iter.combinations = function(iterable, length) { + var elements = goog.iter.toArray(iterable); + var indexes = goog.iter.range(elements.length); + var indexIterator = goog.iter.permutations(indexes, length); + // sortedIndexIterator will now give arrays of with the given length that + // indicate what indexes into "elements" should be returned on each iteration. + var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { + return goog.array.isSorted(arr); + }); + var iter = new goog.iter.Iterator(); -/** - * @param {number} pixelRatio Pixel ratio. - * @return {Image|HTMLCanvasElement} Image element. - */ -ol.style.IconImage_.prototype.getHitDetectionImage = function(pixelRatio) { - if (!this.hitDetectionImage_) { - if (this.tainting_) { - var width = this.size_[0]; - var height = this.size_[1]; - var context = ol.dom.createCanvasContext2D(width, height); - context.fillRect(0, 0, width, height); - this.hitDetectionImage_ = context.canvas; - } else { - this.hitDetectionImage_ = this.image_; - } + function getIndexFromElements(index) { + return elements[index]; } - return this.hitDetectionImage_; -}; + iter.next = function() { + return goog.array.map(sortedIndexIterator.next(), getIndexFromElements); + }; -/** - * @return {ol.Size} Image size. - */ -ol.style.IconImage_.prototype.getSize = function() { - return this.size_; + return iter; }; /** - * @return {string|undefined} Image src. + * Creates an iterator that returns combinations of elements from + * {@code iterable}, with repeated elements possible. + * + * Combinations are obtained by taking the Cartesian product of {@code length} + * iterables and filtering those whose elements appear in the order they are + * encountered in {@code iterable}. For example, the 2-length combinations of + * {@code [1,2,3]} are {@code [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]}. + * @see http://docs.python.org/2/library/itertools.html#itertools.combinations_with_replacement + * @see http://en.wikipedia.org/wiki/Combination#Number_of_combinations_with_repetition + * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The + * iterable to combine. + * @param {number} length The length of each combination. + * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing + * combinations from the {@code iterable}. + * @template VALUE */ -ol.style.IconImage_.prototype.getSrc = function() { - return this.src_; -}; +goog.iter.combinationsWithReplacement = function(iterable, length) { + var elements = goog.iter.toArray(iterable); + var indexes = goog.array.range(elements.length); + var sets = goog.array.repeat(indexes, length); + var indexIterator = goog.iter.product.apply(undefined, sets); + // sortedIndexIterator will now give arrays of with the given length that + // indicate what indexes into "elements" should be returned on each iteration. + var sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) { + return goog.array.isSorted(arr); + }); + var iter = new goog.iter.Iterator(); -/** - * Load not yet loaded URI. - */ -ol.style.IconImage_.prototype.load = function() { - if (this.imageState_ == ol.style.ImageState.IDLE) { - goog.asserts.assert(this.src_ !== undefined, - 'this.src_ must not be undefined'); - goog.asserts.assert(!this.imageListenerKeys_, - 'no listener keys existing'); - this.imageState_ = ol.style.ImageState.LOADING; - this.imageListenerKeys_ = [ - goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, - this.handleImageError_, false, this), - goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, - this.handleImageLoad_, false, this) - ]; - try { - this.image_.src = this.src_; - } catch (e) { - this.handleImageError_(); - } + function getIndexFromElements(index) { + return elements[index]; } + + iter.next = function() { + return goog.array.map( + /** @type {!Array<number>} */ + (sortedIndexIterator.next()), getIndexFromElements); + }; + + return iter; }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Discards event handlers which listen for load completion or errors. + * @fileoverview Datastructure: Hash Map. * - * @private + * @author arv@google.com (Erik Arvidsson) + * + * This file contains an implementation of a Map structure. It implements a lot + * of the methods used in goog.structs so those functions work on hashes. This + * is best suited for complex key types. For simple keys such as numbers and + * strings consider using the lighter-weight utilities in goog.object. */ -ol.style.IconImage_.prototype.unlistenImage_ = function() { - goog.asserts.assert(this.imageListenerKeys_, - 'we must have listeners registered'); - this.imageListenerKeys_.forEach(goog.events.unlistenByKey); - this.imageListenerKeys_ = null; -}; + + +goog.provide('goog.structs.Map'); + +goog.require('goog.iter.Iterator'); +goog.require('goog.iter.StopIteration'); +goog.require('goog.object'); /** + * Class for Hash Map datastructure. + * @param {*=} opt_map Map or Object to initialize the map with. + * @param {...*} var_args If 2 or more arguments are present then they + * will be used as key-value pairs. * @constructor + * @template K, V */ -ol.style.IconImageCache = function() { +goog.structs.Map = function(opt_map, var_args) { /** - * @type {Object.<string, ol.style.IconImage_>} - * @private + * Underlying JS object used to implement the map. + * @private {!Object} */ - this.cache_ = {}; + this.map_ = {}; /** - * @type {number} - * @private + * An array of keys. This is necessary for two reasons: + * 1. Iterating the keys using for (var key in this.map_) allocates an + * object for every key in IE which is really bad for IE6 GC perf. + * 2. Without a side data structure, we would need to escape all the keys + * as that would be the only way we could tell during iteration if the + * key was an internal key or a property of the object. + * + * This array can contain deleted keys so it's necessary to check the map + * as well to see if the key is still in the map (this doesn't require a + * memory allocation in IE). + * @private {!Array<string>} */ - this.cacheSize_ = 0; + this.keys_ = []; /** - * @const - * @type {number} - * @private + * The number of key value pairs in the map. + * @private {number} */ - this.maxCacheSize_ = 32; -}; -goog.addSingletonGetter(ol.style.IconImageCache); + this.count_ = 0; + /** + * Version used to detect changes while iterating. + * @private {number} + */ + this.version_ = 0; -/** - * @param {string} src Src. - * @param {?string} crossOrigin Cross origin. - * @return {string} Cache key. - */ -ol.style.IconImageCache.getKey = function(src, crossOrigin) { - goog.asserts.assert(crossOrigin !== undefined, - 'argument crossOrigin must be defined'); - return crossOrigin + ':' + src; + var argLength = arguments.length; + + if (argLength > 1) { + if (argLength % 2) { + throw Error('Uneven number of arguments'); + } + for (var i = 0; i < argLength; i += 2) { + this.set(arguments[i], arguments[i + 1]); + } + } else if (opt_map) { + this.addAll(/** @type {Object} */ (opt_map)); + } }; /** - * FIXME empty description for jsdoc + * @return {number} The number of key-value pairs in the map. */ -ol.style.IconImageCache.prototype.clear = function() { - this.cache_ = {}; - this.cacheSize_ = 0; +goog.structs.Map.prototype.getCount = function() { + return this.count_; }; /** - * FIXME empty description for jsdoc + * Returns the values of the map. + * @return {!Array<V>} The values in the map. */ -ol.style.IconImageCache.prototype.expire = function() { - if (this.cacheSize_ > this.maxCacheSize_) { - var i = 0; - var key, iconImage; - for (key in this.cache_) { - iconImage = this.cache_[key]; - if ((i++ & 3) === 0 && !goog.events.hasListener(iconImage)) { - delete this.cache_[key]; - --this.cacheSize_; - } - } +goog.structs.Map.prototype.getValues = function() { + this.cleanupKeysArray_(); + + var rv = []; + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + rv.push(this.map_[key]); } + return rv; }; /** - * @param {string} src Src. - * @param {?string} crossOrigin Cross origin. - * @return {ol.style.IconImage_} Icon image. + * Returns the keys of the map. + * @return {!Array<string>} Array of string values. */ -ol.style.IconImageCache.prototype.get = function(src, crossOrigin) { - var key = ol.style.IconImageCache.getKey(src, crossOrigin); - return key in this.cache_ ? this.cache_[key] : null; +goog.structs.Map.prototype.getKeys = function() { + this.cleanupKeysArray_(); + return /** @type {!Array<string>} */ (this.keys_.concat()); }; /** - * @param {string} src Src. - * @param {?string} crossOrigin Cross origin. - * @param {ol.style.IconImage_} iconImage Icon image. + * Whether the map contains the given key. + * @param {*} key The key to check for. + * @return {boolean} Whether the map contains the key. */ -ol.style.IconImageCache.prototype.set = function(src, crossOrigin, iconImage) { - var key = ol.style.IconImageCache.getKey(src, crossOrigin); - this.cache_[key] = iconImage; - ++this.cacheSize_; +goog.structs.Map.prototype.containsKey = function(key) { + return goog.structs.Map.hasKey_(this.map_, key); }; -goog.provide('ol.RendererType'); -goog.provide('ol.renderer.Map'); - -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('goog.dispose'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.layer.Layer'); -goog.require('ol.renderer.Layer'); -goog.require('ol.style.IconImageCache'); -goog.require('ol.vec.Mat4'); - /** - * Available renderers: `'canvas'`, `'dom'` or `'webgl'`. - * @enum {string} - * @api stable + * Whether the map contains the given value. This is O(n). + * @param {V} val The value to check for. + * @return {boolean} Whether the map contains the value. */ -ol.RendererType = { - CANVAS: 'canvas', - DOM: 'dom', - WEBGL: 'webgl' +goog.structs.Map.prototype.containsValue = function(val) { + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) { + return true; + } + } + return false; }; - /** - * @constructor - * @extends {goog.Disposable} - * @param {Element} container Container. - * @param {ol.Map} map Map. - * @struct + * Whether this map is equal to the argument map. + * @param {goog.structs.Map} otherMap The map against which to test equality. + * @param {function(V, V): boolean=} opt_equalityFn Optional equality function + * to test equality of values. If not specified, this will test whether + * the values contained in each map are identical objects. + * @return {boolean} Whether the maps are equal. */ -ol.renderer.Map = function(container, map) { +goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) { + if (this === otherMap) { + return true; + } - goog.base(this); + if (this.count_ != otherMap.getCount()) { + return false; + } + var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals; - /** - * @private - * @type {ol.Map} - */ - this.map_ = map; + this.cleanupKeysArray_(); + for (var key, i = 0; key = this.keys_[i]; i++) { + if (!equalityFn(this.get(key), otherMap.get(key))) { + return false; + } + } - /** - * @private - * @type {Object.<string, ol.renderer.Layer>} - */ - this.layerRenderers_ = {}; + return true; +}; - /** - * @private - * @type {Object.<string, goog.events.Key>} - */ - this.layerRendererListeners_ = {}; +/** + * Default equality test for values. + * @param {*} a The first value. + * @param {*} b The second value. + * @return {boolean} Whether a and b reference the same object. + */ +goog.structs.Map.defaultEquals = function(a, b) { + return a === b; }; -goog.inherits(ol.renderer.Map, goog.Disposable); /** - * @param {olx.FrameState} frameState FrameState. - * @protected + * @return {boolean} Whether the map is empty. */ -ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) { - var viewState = frameState.viewState; - var coordinateToPixelMatrix = frameState.coordinateToPixelMatrix; - goog.asserts.assert(coordinateToPixelMatrix, - 'frameState has a coordinateToPixelMatrix'); - ol.vec.Mat4.makeTransform2D(coordinateToPixelMatrix, - frameState.size[0] / 2, frameState.size[1] / 2, - 1 / viewState.resolution, -1 / viewState.resolution, - -viewState.rotation, - -viewState.center[0], -viewState.center[1]); - var inverted = goog.vec.Mat4.invert( - coordinateToPixelMatrix, frameState.pixelToCoordinateMatrix); - goog.asserts.assert(inverted, 'matrix could be inverted'); +goog.structs.Map.prototype.isEmpty = function() { + return this.count_ == 0; }; /** - * @param {ol.layer.Layer} layer Layer. - * @protected - * @return {ol.renderer.Layer} layerRenderer Layer renderer. + * Removes all key-value pairs from the map. */ -ol.renderer.Map.prototype.createLayerRenderer = goog.abstractMethod; +goog.structs.Map.prototype.clear = function() { + this.map_ = {}; + this.keys_.length = 0; + this.count_ = 0; + this.version_ = 0; +}; /** - * @inheritDoc + * Removes a key-value pair based on the key. This is O(logN) amortized due to + * updating the keys array whenever the count becomes half the size of the keys + * in the keys array. + * @param {*} key The key to remove. + * @return {boolean} Whether object was removed. */ -ol.renderer.Map.prototype.disposeInternal = function() { - goog.object.forEach(this.layerRenderers_, goog.dispose); - goog.base(this, 'disposeInternal'); +goog.structs.Map.prototype.remove = function(key) { + if (goog.structs.Map.hasKey_(this.map_, key)) { + delete this.map_[key]; + this.count_--; + this.version_++; + + // clean up the keys array if the threshhold is hit + if (this.keys_.length > 2 * this.count_) { + this.cleanupKeysArray_(); + } + + return true; + } + return false; }; /** - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. + * Cleans up the temp keys array by removing entries that are no longer in the + * map. * @private */ -ol.renderer.Map.expireIconCache_ = function(map, frameState) { - ol.style.IconImageCache.getInstance().expire(); +goog.structs.Map.prototype.cleanupKeysArray_ = function() { + if (this.count_ != this.keys_.length) { + // First remove keys that are no longer in the map. + var srcIndex = 0; + var destIndex = 0; + while (srcIndex < this.keys_.length) { + var key = this.keys_[srcIndex]; + if (goog.structs.Map.hasKey_(this.map_, key)) { + this.keys_[destIndex++] = key; + } + srcIndex++; + } + this.keys_.length = destIndex; + } + + if (this.count_ != this.keys_.length) { + // If the count still isn't correct, that means we have duplicates. This can + // happen when the same key is added and removed multiple times. Now we have + // to allocate one extra Object to remove the duplicates. This could have + // been done in the first pass, but in the common case, we can avoid + // allocating an extra object by only doing this when necessary. + var seen = {}; + var srcIndex = 0; + var destIndex = 0; + while (srcIndex < this.keys_.length) { + var key = this.keys_[srcIndex]; + if (!(goog.structs.Map.hasKey_(seen, key))) { + this.keys_[destIndex++] = key; + seen[key] = 1; + } + srcIndex++; + } + this.keys_.length = destIndex; + } }; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState FrameState. - * @param {function(this: S, (ol.Feature|ol.render.Feature), - * ol.layer.Layer): T} callback Feature callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result. - * @template S,T,U + * Returns the value for the given key. If the key is not found and the default + * value is not given this will return {@code undefined}. + * @param {*} key The key to get the value for. + * @param {DEFAULT=} opt_val The value to return if no item is found for the + * given key, defaults to undefined. + * @return {V|DEFAULT} The value for the given key. + * @template DEFAULT */ -ol.renderer.Map.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg, - layerFilter, thisArg2) { - var result; - var viewState = frameState.viewState; - var viewResolution = viewState.resolution; +goog.structs.Map.prototype.get = function(key, opt_val) { + if (goog.structs.Map.hasKey_(this.map_, key)) { + return this.map_[key]; + } + return opt_val; +}; - /** @type {Object.<string, boolean>} */ - var features = {}; - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function forEachFeatureAtCoordinate(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, null); - } +/** + * Adds a key-value pair to the map. + * @param {*} key The key. + * @param {V} value The value to add. + * @return {*} Some subclasses return a value. + */ +goog.structs.Map.prototype.set = function(key, value) { + if (!(goog.structs.Map.hasKey_(this.map_, key))) { + this.count_++; + this.keys_.push(key); + // Only change the version if we add a new key. + this.version_++; } + this.map_[key] = value; +}; - var projection = viewState.projection; - var translatedCoordinate = coordinate; - if (projection.canWrapX()) { - var projectionExtent = projection.getExtent(); - var worldWidth = ol.extent.getWidth(projectionExtent); - var x = coordinate[0]; - if (x < projectionExtent[0] || x > projectionExtent[2]) { - var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth); - translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]]; - } +/** + * Adds multiple key-value pairs from another goog.structs.Map or Object. + * @param {Object} map Object containing the data to add. + */ +goog.structs.Map.prototype.addAll = function(map) { + var keys, values; + if (map instanceof goog.structs.Map) { + keys = map.getKeys(); + values = map.getValues(); + } else { + keys = goog.object.getKeys(map); + values = goog.object.getValues(map); } - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (!layerState.managed || - (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerFilter.call(thisArg2, layer))) { - var layerRenderer = this.getLayerRenderer(layer); - if (layer.getSource()) { - result = layerRenderer.forEachFeatureAtCoordinate( - layer.getSource().getWrapX() ? translatedCoordinate : coordinate, - frameState, - layerState.managed ? callback : forEachFeatureAtCoordinate, - thisArg); - } - if (result) { - return result; - } - } + // we could use goog.array.forEach here but I don't want to introduce that + // dependency just for this. + for (var i = 0; i < keys.length; i++) { + this.set(keys[i], values[i]); } - return undefined; }; /** - * @param {ol.Pixel} pixel Pixel. - * @param {olx.FrameState} frameState FrameState. - * @param {function(this: S, ol.layer.Layer): T} callback Layer - * callback. - * @param {S} thisArg Value to use as `this` when executing `callback`. - * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result. - * @template S,T,U + * Calls the given function on each entry in the map. + * @param {function(this:T, V, K, goog.structs.Map<K,V>)} f + * @param {T=} opt_obj The value of "this" inside f. + * @template T */ -ol.renderer.Map.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg, - layerFilter, thisArg2) { - var result; - var viewState = frameState.viewState; - var viewResolution = viewState.resolution; - - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerFilter.call(thisArg2, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - result = layerRenderer.forEachLayerAtPixel( - pixel, frameState, callback, thisArg); - if (result) { - return result; - } - } +goog.structs.Map.prototype.forEach = function(f, opt_obj) { + var keys = this.getKeys(); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var value = this.get(key); + f.call(opt_obj, value, key, this); } - return undefined; }; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {olx.FrameState} frameState FrameState. - * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter - * function, only layers which are visible and for which this function - * returns `true` will be tested for features. By default, all visible - * layers will be tested. - * @param {U} thisArg Value to use as `this` when executing `layerFilter`. - * @return {boolean} Is there a feature at the given coordinate? - * @template U + * Clones a map and returns a new map. + * @return {!goog.structs.Map} A new map with the same key-value pairs. */ -ol.renderer.Map.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState, layerFilter, thisArg) { - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this, layerFilter, thisArg); - - return hasFeature !== undefined; +goog.structs.Map.prototype.clone = function() { + return new goog.structs.Map(this); }; /** - * @param {ol.layer.Layer} layer Layer. - * @protected - * @return {ol.renderer.Layer} Layer renderer. + * Returns a new map in which all the keys and values are interchanged + * (keys become values and values become keys). If multiple keys map to the + * same value, the chosen transposed value is implementation-dependent. + * + * It acts very similarly to {goog.object.transpose(Object)}. + * + * @return {!goog.structs.Map} The transposed map. */ -ol.renderer.Map.prototype.getLayerRenderer = function(layer) { - var layerKey = goog.getUid(layer).toString(); - if (layerKey in this.layerRenderers_) { - return this.layerRenderers_[layerKey]; - } else { - var layerRenderer = this.createLayerRenderer(layer); - this.layerRenderers_[layerKey] = layerRenderer; - this.layerRendererListeners_[layerKey] = goog.events.listen(layerRenderer, - goog.events.EventType.CHANGE, this.handleLayerRendererChange_, - false, this); - - return layerRenderer; +goog.structs.Map.prototype.transpose = function() { + var transposed = new goog.structs.Map(); + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + var value = this.map_[key]; + transposed.set(value, key); } + + return transposed; }; /** - * @param {string} layerKey Layer key. - * @protected - * @return {ol.renderer.Layer} Layer renderer. + * @return {!Object} Object representation of the map. */ -ol.renderer.Map.prototype.getLayerRendererByKey = function(layerKey) { - goog.asserts.assert(layerKey in this.layerRenderers_, - 'given layerKey (%s) exists in layerRenderers', layerKey); - return this.layerRenderers_[layerKey]; +goog.structs.Map.prototype.toObject = function() { + this.cleanupKeysArray_(); + var obj = {}; + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + obj[key] = this.map_[key]; + } + return obj; }; /** - * @protected - * @return {Object.<number, ol.renderer.Layer>} Layer renderers. + * Returns an iterator that iterates over the keys in the map. Removal of keys + * while iterating might have undesired side effects. + * @return {!goog.iter.Iterator} An iterator over the keys in the map. */ -ol.renderer.Map.prototype.getLayerRenderers = function() { - return this.layerRenderers_; +goog.structs.Map.prototype.getKeyIterator = function() { + return this.__iterator__(true); }; /** - * @return {ol.Map} Map. + * Returns an iterator that iterates over the values in the map. Removal of + * keys while iterating might have undesired side effects. + * @return {!goog.iter.Iterator} An iterator over the values in the map. */ -ol.renderer.Map.prototype.getMap = function() { - return this.map_; +goog.structs.Map.prototype.getValueIterator = function() { + return this.__iterator__(false); }; /** - * @return {string} Type + * Returns an iterator that iterates over the values or the keys in the map. + * This throws an exception if the map was mutated since the iterator was + * created. + * @param {boolean=} opt_keys True to iterate over the keys. False to iterate + * over the values. The default value is false. + * @return {!goog.iter.Iterator} An iterator over the values or keys in the map. */ -ol.renderer.Map.prototype.getType = goog.abstractMethod; +goog.structs.Map.prototype.__iterator__ = function(opt_keys) { + // Clean up keys to minimize the risk of iterating over dead keys. + this.cleanupKeysArray_(); + + var i = 0; + var version = this.version_; + var selfObj = this; + + var newIter = new goog.iter.Iterator; + newIter.next = function() { + if (version != selfObj.version_) { + throw Error('The map has changed since the iterator was created'); + } + if (i >= selfObj.keys_.length) { + throw goog.iter.StopIteration; + } + var key = selfObj.keys_[i++]; + return opt_keys ? key : selfObj.map_[key]; + }; + return newIter; +}; /** - * Handle changes in a layer renderer. + * Safe way to test for hasOwnProperty. It even allows testing for + * 'hasOwnProperty'. + * @param {Object} obj The object to test for presence of the given key. + * @param {*} key The key to check for. + * @return {boolean} Whether the object has the key. * @private */ -ol.renderer.Map.prototype.handleLayerRendererChange_ = function() { - this.map_.render(); +goog.structs.Map.hasKey_ = function(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {string} layerKey Layer key. - * @return {ol.renderer.Layer} Layer renderer. - * @private + * @fileoverview Datastructure: Set. + * + * @author arv@google.com (Erik Arvidsson) + * + * This class implements a set data structure. Adding and removing is O(1). It + * supports both object and primitive values. Be careful because you can add + * both 1 and new Number(1), because these are not the same. You can even add + * multiple new Number(1) because these are not equal. */ -ol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) { - goog.asserts.assert(layerKey in this.layerRenderers_, - 'given layerKey (%s) exists in layerRenderers', layerKey); - var layerRenderer = this.layerRenderers_[layerKey]; - delete this.layerRenderers_[layerKey]; - goog.asserts.assert(layerKey in this.layerRendererListeners_, - 'given layerKey (%s) exists in layerRendererListeners', layerKey); - goog.events.unlistenByKey(this.layerRendererListeners_[layerKey]); - delete this.layerRendererListeners_[layerKey]; - return layerRenderer; -}; +goog.provide('goog.structs.Set'); + +goog.require('goog.structs'); +goog.require('goog.structs.Collection'); +goog.require('goog.structs.Map'); + /** - * Render. - * @param {?olx.FrameState} frameState Frame state. + * A set that can contain both primitives and objects. Adding and removing + * elements is O(1). Primitives are treated as identical if they have the same + * type and convert to the same string. Objects are treated as identical only + * if they are references to the same object. WARNING: A goog.structs.Set can + * contain both 1 and (new Number(1)), because they are not the same. WARNING: + * Adding (new Number(1)) twice will yield two distinct elements, because they + * are two different objects. WARNING: Any object that is added to a + * goog.structs.Set will be modified! Because goog.getUid() is used to + * identify objects, every object in the set will be mutated. + * @param {Array<T>|Object<?,T>=} opt_values Initial values to start with. + * @constructor + * @implements {goog.structs.Collection<T>} + * @final + * @template T */ -ol.renderer.Map.prototype.renderFrame = ol.nullFunction; +goog.structs.Set = function(opt_values) { + this.map_ = new goog.structs.Map; + if (opt_values) { + this.addAll(opt_values); + } +}; /** - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. + * Obtains a unique key for an element of the set. Primitives will yield the + * same key if they have the same type and convert to the same string. Object + * references will yield the same key only if they refer to the same object. + * @param {*} val Object or primitive value to get a key for. + * @return {string} A unique key for this value/object. * @private */ -ol.renderer.Map.prototype.removeUnusedLayerRenderers_ = - function(map, frameState) { - var layerKey; - for (layerKey in this.layerRenderers_) { - if (!frameState || !(layerKey in frameState.layerStates)) { - goog.dispose(this.removeLayerRendererByKey_(layerKey)); - } +goog.structs.Set.getKey_ = function(val) { + var type = typeof val; + if (type == 'object' && val || type == 'function') { + return 'o' + goog.getUid(/** @type {Object} */ (val)); + } else { + return type.substr(0, 1) + val; } }; /** - * @param {olx.FrameState} frameState Frame state. - * @protected + * @return {number} The number of elements in the set. + * @override */ -ol.renderer.Map.prototype.scheduleExpireIconCache = function(frameState) { - frameState.postRenderFunctions.push(ol.renderer.Map.expireIconCache_); +goog.structs.Set.prototype.getCount = function() { + return this.map_.getCount(); }; /** - * @param {!olx.FrameState} frameState Frame state. - * @protected + * Add a primitive or an object to the set. + * @param {T} element The primitive or object to add. + * @override */ -ol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers = - function(frameState) { - var layerKey; - for (layerKey in this.layerRenderers_) { - if (!(layerKey in frameState.layerStates)) { - frameState.postRenderFunctions.push( - goog.bind(this.removeUnusedLayerRenderers_, this)); - return; - } - } +goog.structs.Set.prototype.add = function(element) { + this.map_.set(goog.structs.Set.getKey_(element), element); }; /** - * @param {ol.layer.LayerState} state1 - * @param {ol.layer.LayerState} state2 - * @return {number} + * Adds all the values in the given collection to this set. + * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection + * containing the elements to add. */ -ol.renderer.Map.sortByZIndex = function(state1, state2) { - return state1.zIndex - state2.zIndex; +goog.structs.Set.prototype.addAll = function(col) { + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + this.add(values[i]); + } }; -goog.provide('ol.structs.PriorityQueue'); - -goog.require('goog.asserts'); -goog.require('goog.object'); +/** + * Removes all values in the given collection from this set. + * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection + * containing the elements to remove. + */ +goog.structs.Set.prototype.removeAll = function(col) { + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + this.remove(values[i]); + } +}; /** - * Priority queue. - * - * The implementation is inspired from the Closure Library's Heap class and - * Python's heapq module. - * - * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html - * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py - * - * @constructor - * @param {function(T): number} priorityFunction Priority function. - * @param {function(T): string} keyFunction Key function. - * @struct - * @template T + * Removes the given element from this set. + * @param {T} element The primitive or object to remove. + * @return {boolean} Whether the element was found and removed. + * @override */ -ol.structs.PriorityQueue = function(priorityFunction, keyFunction) { - - /** - * @type {function(T): number} - * @private - */ - this.priorityFunction_ = priorityFunction; - - /** - * @type {function(T): string} - * @private - */ - this.keyFunction_ = keyFunction; - - /** - * @type {Array.<T>} - * @private - */ - this.elements_ = []; - - /** - * @type {Array.<number>} - * @private - */ - this.priorities_ = []; - - /** - * @type {Object.<string, boolean>} - * @private - */ - this.queuedElements_ = {}; - +goog.structs.Set.prototype.remove = function(element) { + return this.map_.remove(goog.structs.Set.getKey_(element)); }; /** - * @const - * @type {number} + * Removes all elements from this set. */ -ol.structs.PriorityQueue.DROP = Infinity; +goog.structs.Set.prototype.clear = function() { + this.map_.clear(); +}; /** - * FIXME empty description for jsdoc + * Tests whether this set is empty. + * @return {boolean} True if there are no elements in this set. */ -ol.structs.PriorityQueue.prototype.assertValid = function() { - var elements = this.elements_; - var priorities = this.priorities_; - var n = elements.length; - goog.asserts.assert(priorities.length == n); - var i, priority; - for (i = 0; i < (n >> 1) - 1; ++i) { - priority = priorities[i]; - goog.asserts.assert(priority <= priorities[this.getLeftChildIndex_(i)], - 'priority smaller than or equal to priority of left child (%s <= %s)', - priority, priorities[this.getLeftChildIndex_(i)]); - goog.asserts.assert(priority <= priorities[this.getRightChildIndex_(i)], - 'priority smaller than or equal to priority of right child (%s <= %s)', - priority, priorities[this.getRightChildIndex_(i)]); - } +goog.structs.Set.prototype.isEmpty = function() { + return this.map_.isEmpty(); }; /** - * FIXME empty description for jsdoc + * Tests whether this set contains the given element. + * @param {T} element The primitive or object to test for. + * @return {boolean} True if this set contains the given element. + * @override */ -ol.structs.PriorityQueue.prototype.clear = function() { - this.elements_.length = 0; - this.priorities_.length = 0; - goog.object.clear(this.queuedElements_); +goog.structs.Set.prototype.contains = function(element) { + return this.map_.containsKey(goog.structs.Set.getKey_(element)); }; /** - * Remove and return the highest-priority element. O(log N). - * @return {T} Element. + * Tests whether this set contains all the values in a given collection. + * Repeated elements in the collection are ignored, e.g. (new + * goog.structs.Set([1, 2])).containsAll([1, 1]) is True. + * @param {goog.structs.Collection<T>|Object} col A collection-like object. + * @return {boolean} True if the set contains all elements. */ -ol.structs.PriorityQueue.prototype.dequeue = function() { - var elements = this.elements_; - goog.asserts.assert(elements.length > 0, - 'must have elements in order to be able to dequeue'); - var priorities = this.priorities_; - var element = elements[0]; - if (elements.length == 1) { - elements.length = 0; - priorities.length = 0; - } else { - elements[0] = elements.pop(); - priorities[0] = priorities.pop(); - this.siftUp_(0); - } - var elementKey = this.keyFunction_(element); - goog.asserts.assert(elementKey in this.queuedElements_, - 'key %s is not listed as queued', elementKey); - delete this.queuedElements_[elementKey]; - return element; +goog.structs.Set.prototype.containsAll = function(col) { + return goog.structs.every(col, this.contains, this); }; /** - * Enqueue an element. O(log N). - * @param {T} element Element. + * Finds all values that are present in both this set and the given collection. + * @param {Array<S>|Object<?,S>} col A collection. + * @return {!goog.structs.Set<T|S>} A new set containing all the values + * (primitives or objects) present in both this set and the given + * collection. + * @template S */ -ol.structs.PriorityQueue.prototype.enqueue = function(element) { - goog.asserts.assert(!(this.keyFunction_(element) in this.queuedElements_), - 'key %s is already listed as queued', this.keyFunction_(element)); - var priority = this.priorityFunction_(element); - if (priority != ol.structs.PriorityQueue.DROP) { - this.elements_.push(element); - this.priorities_.push(priority); - this.queuedElements_[this.keyFunction_(element)] = true; - this.siftDown_(0, this.elements_.length - 1); +goog.structs.Set.prototype.intersection = function(col) { + var result = new goog.structs.Set(); + + var values = goog.structs.getValues(col); + for (var i = 0; i < values.length; i++) { + var value = values[i]; + if (this.contains(value)) { + result.add(value); + } } + + return result; }; /** - * @return {number} Count. + * Finds all values that are present in this set and not in the given + * collection. + * @param {Array<T>|goog.structs.Collection<T>|Object<?,T>} col A collection. + * @return {!goog.structs.Set} A new set containing all the values + * (primitives or objects) present in this set but not in the given + * collection. */ -ol.structs.PriorityQueue.prototype.getCount = function() { - return this.elements_.length; +goog.structs.Set.prototype.difference = function(col) { + var result = this.clone(); + result.removeAll(col); + return result; }; /** - * Gets the index of the left child of the node at the given index. - * @param {number} index The index of the node to get the left child for. - * @return {number} The index of the left child. - * @private + * Returns an array containing all the elements in this set. + * @return {!Array<T>} An array containing all the elements in this set. */ -ol.structs.PriorityQueue.prototype.getLeftChildIndex_ = function(index) { - return index * 2 + 1; +goog.structs.Set.prototype.getValues = function() { + return this.map_.getValues(); }; /** - * Gets the index of the right child of the node at the given index. - * @param {number} index The index of the node to get the right child for. - * @return {number} The index of the right child. - * @private + * Creates a shallow clone of this set. + * @return {!goog.structs.Set<T>} A new set containing all the same elements as + * this set. */ -ol.structs.PriorityQueue.prototype.getRightChildIndex_ = function(index) { - return index * 2 + 2; +goog.structs.Set.prototype.clone = function() { + return new goog.structs.Set(this); }; /** - * Gets the index of the parent of the node at the given index. - * @param {number} index The index of the node to get the parent for. - * @return {number} The index of the parent. - * @private + * Tests whether the given collection consists of the same elements as this set, + * regardless of order, without repetition. Primitives are treated as equal if + * they have the same type and convert to the same string; objects are treated + * as equal if they are references to the same object. This operation is O(n). + * @param {goog.structs.Collection<T>|Object} col A collection. + * @return {boolean} True if the given collection consists of the same elements + * as this set, regardless of order, without repetition. */ -ol.structs.PriorityQueue.prototype.getParentIndex_ = function(index) { - return (index - 1) >> 1; +goog.structs.Set.prototype.equals = function(col) { + return this.getCount() == goog.structs.getCount(col) && this.isSubsetOf(col); }; /** - * Make this a heap. O(N). - * @private + * Tests whether the given collection contains all the elements in this set. + * Primitives are treated as equal if they have the same type and convert to the + * same string; objects are treated as equal if they are references to the same + * object. This operation is O(n). + * @param {goog.structs.Collection<T>|Object} col A collection. + * @return {boolean} True if this set is a subset of the given collection. */ -ol.structs.PriorityQueue.prototype.heapify_ = function() { - var i; - for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) { - this.siftUp_(i); +goog.structs.Set.prototype.isSubsetOf = function(col) { + var colCount = goog.structs.getCount(col); + if (this.getCount() > colCount) { + return false; + } + // TODO(user) Find the minimal collection size where the conversion makes + // the contains() method faster. + if (!(col instanceof goog.structs.Set) && colCount > 5) { + // Convert to a goog.structs.Set so that goog.structs.contains runs in + // O(1) time instead of O(n) time. + col = new goog.structs.Set(col); } + return goog.structs.every(this, function(value) { + return goog.structs.contains(col, value); + }); }; /** - * @return {boolean} Is empty. + * Returns an iterator that iterates over the elements in this set. + * @param {boolean=} opt_keys This argument is ignored. + * @return {!goog.iter.Iterator} An iterator over the elements in this set. */ -ol.structs.PriorityQueue.prototype.isEmpty = function() { - return this.elements_.length === 0; +goog.structs.Set.prototype.__iterator__ = function(opt_keys) { + return this.map_.__iterator__(false); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {string} key Key. - * @return {boolean} Is key queued. + * @fileoverview Logging and debugging utilities. + * + * @see ../demos/debug.html */ -ol.structs.PriorityQueue.prototype.isKeyQueued = function(key) { - return key in this.queuedElements_; -}; +goog.provide('goog.debug'); -/** - * @param {T} element Element. - * @return {boolean} Is queued. - */ -ol.structs.PriorityQueue.prototype.isQueued = function(element) { - return this.isKeyQueued(this.keyFunction_(element)); -}; +goog.require('goog.array'); +goog.require('goog.html.SafeHtml'); +goog.require('goog.html.SafeUrl'); +goog.require('goog.html.uncheckedconversions'); +goog.require('goog.string.Const'); +goog.require('goog.structs.Set'); +goog.require('goog.userAgent'); + + +/** @define {boolean} Whether logging should be enabled. */ +goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG); /** - * @param {number} index The index of the node to move down. - * @private + * Catches onerror events fired by windows and similar objects. + * @param {function(Object)} logFunc The function to call with the error + * information. + * @param {boolean=} opt_cancel Whether to stop the error from reaching the + * browser. + * @param {Object=} opt_target Object that fires onerror events. */ -ol.structs.PriorityQueue.prototype.siftUp_ = function(index) { - var elements = this.elements_; - var priorities = this.priorities_; - var count = elements.length; - var element = elements[index]; - var priority = priorities[index]; - var startIndex = index; +goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) { + var target = opt_target || goog.global; + var oldErrorHandler = target.onerror; + var retVal = !!opt_cancel; - while (index < (count >> 1)) { - var lIndex = this.getLeftChildIndex_(index); - var rIndex = this.getRightChildIndex_(index); + // Chrome interprets onerror return value backwards (http://crbug.com/92062) + // until it was fixed in webkit revision r94061 (Webkit 535.3). This + // workaround still needs to be skipped in Safari after the webkit change + // gets pushed out in Safari. + // See https://bugs.webkit.org/show_bug.cgi?id=67119 + if (goog.userAgent.WEBKIT && + !goog.userAgent.isVersionOrHigher('535.3')) { + retVal = !retVal; + } - var smallerChildIndex = rIndex < count && - priorities[rIndex] < priorities[lIndex] ? - rIndex : lIndex; + /** + * New onerror handler for this target. This onerror handler follows the spec + * according to + * http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors + * The spec was changed in August 2013 to support receiving column information + * and an error object for all scripts on the same origin or cross origin + * scripts with the proper headers. See + * https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror + * + * @param {string} message The error message. For cross-origin errors, this + * will be scrubbed to just "Script error.". For new browsers that have + * updated to follow the latest spec, errors that come from origins that + * have proper cross origin headers will not be scrubbed. + * @param {string} url The URL of the script that caused the error. The URL + * will be scrubbed to "" for cross origin scripts unless the script has + * proper cross origin headers and the browser has updated to the latest + * spec. + * @param {number} line The line number in the script that the error + * occurred on. + * @param {number=} opt_col The optional column number that the error + * occurred on. Only browsers that have updated to the latest spec will + * include this. + * @param {Error=} opt_error The optional actual error object for this + * error that should include the stack. Only browsers that have updated + * to the latest spec will inlude this parameter. + * @return {boolean} Whether to prevent the error from reaching the browser. + */ + target.onerror = function(message, url, line, opt_col, opt_error) { + if (oldErrorHandler) { + oldErrorHandler(message, url, line, opt_col, opt_error); + } + logFunc({ + message: message, + fileName: url, + line: line, + col: opt_col, + error: opt_error + }); + return retVal; + }; +}; - elements[index] = elements[smallerChildIndex]; - priorities[index] = priorities[smallerChildIndex]; - index = smallerChildIndex; + +/** + * Creates a string representing an object and all its properties. + * @param {Object|null|undefined} obj Object to expose. + * @param {boolean=} opt_showFn Show the functions as well as the properties, + * default is false. + * @return {string} The string representation of {@code obj}. + */ +goog.debug.expose = function(obj, opt_showFn) { + if (typeof obj == 'undefined') { + return 'undefined'; + } + if (obj == null) { + return 'NULL'; } + var str = []; - elements[index] = element; - priorities[index] = priority; - this.siftDown_(startIndex, index); + for (var x in obj) { + if (!opt_showFn && goog.isFunction(obj[x])) { + continue; + } + var s = x + ' = '; + /** @preserveTry */ + try { + s += obj[x]; + } catch (e) { + s += '*** ' + e + ' ***'; + } + str.push(s); + } + return str.join('\n'); }; /** - * @param {number} startIndex The index of the root. - * @param {number} index The index of the node to move up. - * @private + * Creates a string representing a given primitive or object, and for an + * object, all its properties and nested objects. WARNING: If an object is + * given, it and all its nested objects will be modified. To detect reference + * cycles, this method identifies objects using goog.getUid() which mutates the + * object. + * @param {*} obj Object to expose. + * @param {boolean=} opt_showFn Also show properties that are functions (by + * default, functions are omitted). + * @return {string} A string representation of {@code obj}. */ -ol.structs.PriorityQueue.prototype.siftDown_ = function(startIndex, index) { - var elements = this.elements_; - var priorities = this.priorities_; - var element = elements[index]; - var priority = priorities[index]; +goog.debug.deepExpose = function(obj, opt_showFn) { + var str = []; - while (index > startIndex) { - var parentIndex = this.getParentIndex_(index); - if (priorities[parentIndex] > priority) { - elements[index] = elements[parentIndex]; - priorities[index] = priorities[parentIndex]; - index = parentIndex; - } else { - break; + var helper = function(obj, space, parentSeen) { + var nestspace = space + ' '; + var seen = new goog.structs.Set(parentSeen); + + var indentMultiline = function(str) { + return str.replace(/\n/g, '\n' + space); + }; + + /** @preserveTry */ + try { + if (!goog.isDef(obj)) { + str.push('undefined'); + } else if (goog.isNull(obj)) { + str.push('NULL'); + } else if (goog.isString(obj)) { + str.push('"' + indentMultiline(obj) + '"'); + } else if (goog.isFunction(obj)) { + str.push(indentMultiline(String(obj))); + } else if (goog.isObject(obj)) { + if (seen.contains(obj)) { + str.push('*** reference loop detected ***'); + } else { + seen.add(obj); + str.push('{'); + for (var x in obj) { + if (!opt_showFn && goog.isFunction(obj[x])) { + continue; + } + str.push('\n'); + str.push(nestspace); + str.push(x + ' = '); + helper(obj[x], nestspace, seen); + } + str.push('\n' + space + '}'); + } + } else { + str.push(obj); + } + } catch (e) { + str.push('*** ' + e + ' ***'); } - } - elements[index] = element; - priorities[index] = priority; + }; + + helper(obj, '', new goog.structs.Set()); + return str.join(''); }; /** - * FIXME empty description for jsdoc + * Recursively outputs a nested array as a string. + * @param {Array<?>} arr The array. + * @return {string} String representing nested array. */ -ol.structs.PriorityQueue.prototype.reprioritize = function() { - var priorityFunction = this.priorityFunction_; - var elements = this.elements_; - var priorities = this.priorities_; - var index = 0; - var n = elements.length; - var element, i, priority; - for (i = 0; i < n; ++i) { - element = elements[i]; - priority = priorityFunction(element); - if (priority == ol.structs.PriorityQueue.DROP) { - delete this.queuedElements_[this.keyFunction_(element)]; +goog.debug.exposeArray = function(arr) { + var str = []; + for (var i = 0; i < arr.length; i++) { + if (goog.isArray(arr[i])) { + str.push(goog.debug.exposeArray(arr[i])); } else { - priorities[index] = priority; - elements[index++] = element; + str.push(arr[i]); } } - elements.length = index; - priorities.length = index; - this.heapify_(); + return '[ ' + str.join(', ') + ' ]'; }; -goog.provide('ol.TilePriorityFunction'); -goog.provide('ol.TileQueue'); - -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.Coordinate'); -goog.require('ol.TileState'); -goog.require('ol.structs.PriorityQueue'); - /** - * @typedef {function(ol.Tile, string, ol.Coordinate, number): number} + * Exposes an exception that has been caught by a try...catch and outputs the + * error as HTML with a stack trace. + * @param {Object} err Error object or string. + * @param {Function=} opt_fn Optional function to start stack trace from. + * @return {string} Details of exception, as HTML. */ -ol.TilePriorityFunction; - +goog.debug.exposeException = function(err, opt_fn) { + var html = goog.debug.exposeExceptionAsHtml(err, opt_fn); + return goog.html.SafeHtml.unwrap(html); +}; /** - * @constructor - * @extends {ol.structs.PriorityQueue.<Array>} - * @param {ol.TilePriorityFunction} tilePriorityFunction - * Tile priority function. - * @param {function(): ?} tileChangeCallback - * Function called on each tile change event. - * @struct - */ -ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) { - - goog.base( - this, - /** - * @param {Array} element Element. - * @return {number} Priority. - */ - function(element) { - return tilePriorityFunction.apply(null, element); - }, - /** - * @param {Array} element Element. - * @return {string} Key. - */ - function(element) { - return /** @type {ol.Tile} */ (element[0]).getKey(); - }); - - /** - * @private - * @type {function(): ?} - */ - this.tileChangeCallback_ = tileChangeCallback; - - /** - * @private - * @type {number} - */ - this.tilesLoading_ = 0; - -}; -goog.inherits(ol.TileQueue, ol.structs.PriorityQueue); - - -/** - * @return {number} Number of tiles loading. - */ -ol.TileQueue.prototype.getTilesLoading = function() { - return this.tilesLoading_; -}; - - -/** - * @param {goog.events.Event} event Event. - * @protected + * Exposes an exception that has been caught by a try...catch and outputs the + * error with a stack trace. + * @param {Object} err Error object or string. + * @param {Function=} opt_fn Optional function to start stack trace from. + * @return {!goog.html.SafeHtml} Details of exception. */ -ol.TileQueue.prototype.handleTileChange = function(event) { - var tile = /** @type {ol.Tile} */ (event.target); - var state = tile.getState(); - if (state === ol.TileState.LOADED || state === ol.TileState.ERROR || - state === ol.TileState.EMPTY) { - goog.events.unlisten(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - --this.tilesLoading_; - this.tileChangeCallback_(); +goog.debug.exposeExceptionAsHtml = function(err, opt_fn) { + /** @preserveTry */ + try { + var e = goog.debug.normalizeErrorObject(err); + // Create the error message + var viewSourceUrl = goog.debug.createViewSourceUrl_(e.fileName); + var error = goog.html.SafeHtml.concat( + goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( + 'Message: ' + e.message + '\nUrl: '), + goog.html.SafeHtml.create('a', + {href: viewSourceUrl, target: '_new'}, e.fileName), + goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( + '\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' + + e.stack + '-> ' + '[end]\n\nJS stack traversal:\n' + + goog.debug.getStacktrace(opt_fn) + '-> ')); + return error; + } catch (e2) { + return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( + 'Exception trying to expose exception! You win, we lose. ' + e2); } }; /** - * @param {number} maxTotalLoading Maximum number tiles to load simultaneously. - * @param {number} maxNewLoads Maximum number of new tiles to load. + * @param {?string=} opt_fileName + * @return {!goog.html.SafeUrl} SafeUrl with view-source scheme, pointing at + * fileName. + * @private */ -ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { - var newLoads = 0; - var tile; - while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads && - this.getCount() > 0) { - tile = /** @type {ol.Tile} */ (this.dequeue()[0]); - if (tile.getState() === ol.TileState.IDLE) { - goog.events.listen(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - tile.load(); - ++this.tilesLoading_; - ++newLoads; - } +goog.debug.createViewSourceUrl_ = function(opt_fileName) { + if (!goog.isDefAndNotNull(opt_fileName)) { + opt_fileName = ''; + } + if (!/^https?:\/\//i.test(opt_fileName)) { + return goog.html.SafeUrl.fromConstant( + goog.string.Const.from('sanitizedviewsrc')); } + var sanitizedFileName = goog.html.SafeUrl.sanitize(opt_fileName); + return goog.html.uncheckedconversions. + safeUrlFromStringKnownToSatisfyTypeContract( + goog.string.Const.from('view-source scheme plus HTTP/HTTPS URL'), + 'view-source:' + goog.html.SafeUrl.unwrap(sanitizedFileName)); }; -goog.provide('ol.Kinetic'); - -goog.require('ol.Coordinate'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.animation'); - - /** - * @classdesc - * Implementation of inertial deceleration for map movement. - * - * @constructor - * @param {number} decay Rate of decay (must be negative). - * @param {number} minVelocity Minimum velocity (pixels/millisecond). - * @param {number} delay Delay to consider to calculate the kinetic - * initial values (milliseconds). - * @struct - * @api + * Normalizes the error/exception object between browsers. + * @param {Object} err Raw error object. + * @return {!Object} Normalized error object. */ -ol.Kinetic = function(decay, minVelocity, delay) { - - /** - * @private - * @type {number} - */ - this.decay_ = decay; +goog.debug.normalizeErrorObject = function(err) { + var href = goog.getObjectByName('window.location.href'); + if (goog.isString(err)) { + return { + 'message': err, + 'name': 'Unknown error', + 'lineNumber': 'Not available', + 'fileName': href, + 'stack': 'Not available' + }; + } - /** - * @private - * @type {number} - */ - this.minVelocity_ = minVelocity; + var lineNumber, fileName; + var threwError = false; - /** - * @private - * @type {number} - */ - this.delay_ = delay; + try { + lineNumber = err.lineNumber || err.line || 'Not available'; + } catch (e) { + // Firefox 2 sometimes throws an error when accessing 'lineNumber': + // Message: Permission denied to get property UnnamedClass.lineNumber + lineNumber = 'Not available'; + threwError = true; + } - /** - * @private - * @type {Array.<number>} - */ - this.points_ = []; + try { + fileName = err.fileName || err.filename || err.sourceURL || + // $googDebugFname may be set before a call to eval to set the filename + // that the eval is supposed to present. + goog.global['$googDebugFname'] || href; + } catch (e) { + // Firefox 2 may also throw an error when accessing 'filename'. + fileName = 'Not available'; + threwError = true; + } - /** - * @private - * @type {number} - */ - this.angle_ = 0; + // The IE Error object contains only the name and the message. + // The Safari Error object uses the line and sourceURL fields. + if (threwError || !err.lineNumber || !err.fileName || !err.stack || + !err.message || !err.name) { + return { + 'message': err.message || 'Not available', + 'name': err.name || 'UnknownError', + 'lineNumber': lineNumber, + 'fileName': fileName, + 'stack': err.stack || 'Not available' + }; + } - /** - * @private - * @type {number} - */ - this.initialVelocity_ = 0; + // Standards error object + return err; }; /** - * FIXME empty description for jsdoc + * Converts an object to an Error if it's a String, + * adds a stacktrace if there isn't one, + * and optionally adds an extra message. + * @param {Error|string} err the original thrown object or string. + * @param {string=} opt_message optional additional message to add to the + * error. + * @return {!Error} If err is a string, it is used to create a new Error, + * which is enhanced and returned. Otherwise err itself is enhanced + * and returned. */ -ol.Kinetic.prototype.begin = function() { - this.points_.length = 0; - this.angle_ = 0; - this.initialVelocity_ = 0; +goog.debug.enhanceError = function(err, opt_message) { + var error; + if (typeof err == 'string') { + error = Error(err); + if (Error.captureStackTrace) { + // Trim this function off the call stack, if we can. + Error.captureStackTrace(error, goog.debug.enhanceError); + } + } else { + error = err; + } + + if (!error.stack) { + error.stack = goog.debug.getStacktrace(goog.debug.enhanceError); + } + if (opt_message) { + // find the first unoccupied 'messageX' property + var x = 0; + while (error['message' + x]) { + ++x; + } + error['message' + x] = String(opt_message); + } + return error; }; /** - * @param {number} x X. - * @param {number} y Y. + * Gets the current stack trace. Simple and iterative - doesn't worry about + * catching circular references or getting the args. + * @param {number=} opt_depth Optional maximum depth to trace back to. + * @return {string} A string with the function names of all functions in the + * stack, separated by \n. + * @suppress {es5Strict} */ -ol.Kinetic.prototype.update = function(x, y) { - this.points_.push(x, y, Date.now()); -}; +goog.debug.getStacktraceSimple = function(opt_depth) { + if (goog.STRICT_MODE_COMPATIBLE) { + var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple); + if (stack) { + return stack; + } + // NOTE: browsers that have strict mode support also have native "stack" + // properties. Fall-through for legacy browser support. + } + var sb = []; + var fn = arguments.callee.caller; + var depth = 0; -/** - * @return {boolean} Whether we should do kinetic animation. - */ -ol.Kinetic.prototype.end = function() { - if (this.points_.length < 6) { - // at least 2 points are required (i.e. there must be at least 6 elements - // in the array) - return false; + while (fn && (!opt_depth || depth < opt_depth)) { + sb.push(goog.debug.getFunctionName(fn)); + sb.push('()\n'); + /** @preserveTry */ + try { + fn = fn.caller; + } catch (e) { + sb.push('[exception trying to get caller]\n'); + break; + } + depth++; + if (depth >= goog.debug.MAX_STACK_DEPTH) { + sb.push('[...long stack...]'); + break; + } } - var delay = Date.now() - this.delay_; - var lastIndex = this.points_.length - 3; - if (this.points_[lastIndex + 2] < delay) { - // the last tracked point is too old, which means that the user stopped - // panning before releasing the map - return false; + if (opt_depth && depth >= opt_depth) { + sb.push('[...reached max depth limit...]'); + } else { + sb.push('[end]'); } - // get the first point which still falls into the delay time - var firstIndex = lastIndex - 3; - while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) { - firstIndex -= 3; - } - var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2]; - var dx = this.points_[lastIndex] - this.points_[firstIndex]; - var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1]; - this.angle_ = Math.atan2(dy, dx); - this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration; - return this.initialVelocity_ > this.minVelocity_; + return sb.join(''); }; /** - * @param {ol.Coordinate} source Source coordinate for the animation. - * @return {ol.PreRenderFunction} Pre-render function for kinetic animation. + * Max length of stack to try and output + * @type {number} */ -ol.Kinetic.prototype.pan = function(source) { - var decay = this.decay_; - var initialVelocity = this.initialVelocity_; - var velocity = this.minVelocity_ - initialVelocity; - var duration = this.getDuration_(); - var easingFunction = ( - /** - * @param {number} t T. - * @return {number} Easing. - */ - function(t) { - return initialVelocity * (Math.exp((decay * t) * duration) - 1) / - velocity; - }); - return ol.animation.pan({ - source: source, - duration: duration, - easing: easingFunction - }); -}; +goog.debug.MAX_STACK_DEPTH = 50; /** + * @param {Function} fn The function to start getting the trace from. + * @return {?string} * @private - * @return {number} Duration of animation (milliseconds). */ -ol.Kinetic.prototype.getDuration_ = function() { - return Math.log(this.minVelocity_ / this.initialVelocity_) / this.decay_; +goog.debug.getNativeStackTrace_ = function(fn) { + var tempErr = new Error(); + if (Error.captureStackTrace) { + Error.captureStackTrace(tempErr, fn); + return String(tempErr.stack); + } else { + // IE10, only adds stack traces when an exception is thrown. + try { + throw tempErr; + } catch (e) { + tempErr = e; + } + var stack = tempErr.stack; + if (stack) { + return String(stack); + } + } + return null; }; /** - * @return {number} Total distance travelled (pixels). + * Gets the current stack trace, either starting from the caller or starting + * from a specified function that's currently on the call stack. + * @param {Function=} opt_fn Optional function to start getting the trace from. + * If not provided, defaults to the function that called this. + * @return {string} Stack trace. + * @suppress {es5Strict} */ -ol.Kinetic.prototype.getDistance = function() { - return (this.minVelocity_ - this.initialVelocity_) / this.decay_; +goog.debug.getStacktrace = function(opt_fn) { + var stack; + if (goog.STRICT_MODE_COMPATIBLE) { + // Try to get the stack trace from the environment if it is available. + var contextFn = opt_fn || goog.debug.getStacktrace; + stack = goog.debug.getNativeStackTrace_(contextFn); + } + if (!stack) { + // NOTE: browsers that have strict mode support also have native "stack" + // properties. This function will throw in strict mode. + stack = goog.debug.getStacktraceHelper_( + opt_fn || arguments.callee.caller, []); + } + return stack; }; /** - * @return {number} Angle of the kinetic panning animation (radians). + * Private helper for getStacktrace(). + * @param {Function} fn Function to start getting the trace from. + * @param {Array<!Function>} visited List of functions visited so far. + * @return {string} Stack trace starting from function fn. + * @suppress {es5Strict} + * @private */ -ol.Kinetic.prototype.getAngle = function() { - return this.angle_; -}; - -// FIXME factor out key precondition (shift et. al) - -goog.provide('ol.interaction.Interaction'); -goog.provide('ol.interaction.InteractionProperty'); - -goog.require('ol'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.Object'); -goog.require('ol.animation'); -goog.require('ol.easing'); - +goog.debug.getStacktraceHelper_ = function(fn, visited) { + var sb = []; -/** - * @enum {string} - */ -ol.interaction.InteractionProperty = { - ACTIVE: 'active' -}; + // Circular reference, certain functions like bind seem to cause a recursive + // loop so we need to catch circular references + if (goog.array.contains(visited, fn)) { + sb.push('[...circular reference...]'); + // Traverse the call stack until function not found or max depth is reached + } else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) { + sb.push(goog.debug.getFunctionName(fn) + '('); + var args = fn.arguments; + // Args may be null for some special functions such as host objects or eval. + for (var i = 0; args && i < args.length; i++) { + if (i > 0) { + sb.push(', '); + } + var argDesc; + var arg = args[i]; + switch (typeof arg) { + case 'object': + argDesc = arg ? 'object' : 'null'; + break; + case 'string': + argDesc = arg; + break; -/** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * User actions that change the state of the map. Some are similar to controls, - * but are not associated with a DOM element. - * For example, {@link ol.interaction.KeyboardZoom} is functionally the same as - * {@link ol.control.Zoom}, but triggered by a keyboard event not a button - * element event. - * Although interactions do not have a DOM element, some of them do render - * vectors and so are visible on the screen. - * - * @constructor - * @param {olx.interaction.InteractionOptions} options Options. - * @extends {ol.Object} - * @api - */ -ol.interaction.Interaction = function(options) { + case 'number': + argDesc = String(arg); + break; - goog.base(this); + case 'boolean': + argDesc = arg ? 'true' : 'false'; + break; - /** - * @private - * @type {ol.Map} - */ - this.map_ = null; + case 'function': + argDesc = goog.debug.getFunctionName(arg); + argDesc = argDesc ? argDesc : '[fn]'; + break; - this.setActive(true); + case 'undefined': + default: + argDesc = typeof arg; + break; + } - /** - * @type {function(ol.MapBrowserEvent):boolean} - */ - this.handleEvent = options.handleEvent; + if (argDesc.length > 40) { + argDesc = argDesc.substr(0, 40) + '...'; + } + sb.push(argDesc); + } + visited.push(fn); + sb.push(')\n'); + /** @preserveTry */ + try { + sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited)); + } catch (e) { + sb.push('[exception trying to get caller]\n'); + } + } else if (fn) { + sb.push('[...long stack...]'); + } else { + sb.push('[end]'); + } + return sb.join(''); }; -goog.inherits(ol.interaction.Interaction, ol.Object); /** - * Return whether the interaction is currently active. - * @return {boolean} `true` if the interaction is active, `false` otherwise. - * @observable - * @api + * Set a custom function name resolver. + * @param {function(Function): string} resolver Resolves functions to their + * names. */ -ol.interaction.Interaction.prototype.getActive = function() { - return /** @type {boolean} */ ( - this.get(ol.interaction.InteractionProperty.ACTIVE)); +goog.debug.setFunctionResolver = function(resolver) { + goog.debug.fnNameResolver_ = resolver; }; /** - * Get the map associated with this interaction. - * @return {ol.Map} Map. + * Gets a function name + * @param {Function} fn Function to get name of. + * @return {string} Function's name. */ -ol.interaction.Interaction.prototype.getMap = function() { - return this.map_; -}; +goog.debug.getFunctionName = function(fn) { + if (goog.debug.fnNameCache_[fn]) { + return goog.debug.fnNameCache_[fn]; + } + if (goog.debug.fnNameResolver_) { + var name = goog.debug.fnNameResolver_(fn); + if (name) { + goog.debug.fnNameCache_[fn] = name; + return name; + } + } + // Heuristically determine function name based on code. + var functionSource = String(fn); + if (!goog.debug.fnNameCache_[functionSource]) { + var matches = /function ([^\(]+)/.exec(functionSource); + if (matches) { + var method = matches[1]; + goog.debug.fnNameCache_[functionSource] = method; + } else { + goog.debug.fnNameCache_[functionSource] = '[Anonymous]'; + } + } -/** - * Activate or deactivate the interaction. - * @param {boolean} active Active. - * @observable - * @api - */ -ol.interaction.Interaction.prototype.setActive = function(active) { - this.set(ol.interaction.InteractionProperty.ACTIVE, active); + return goog.debug.fnNameCache_[functionSource]; }; /** - * Remove the interaction from its current map and attach it to the new map. - * Subclasses may set up event handlers to get notified about changes to - * the map here. - * @param {ol.Map} map Map. + * Makes whitespace visible by replacing it with printable characters. + * This is useful in finding diffrences between the expected and the actual + * output strings of a testcase. + * @param {string} string whose whitespace needs to be made visible. + * @return {string} string whose whitespace is made visible. */ -ol.interaction.Interaction.prototype.setMap = function(map) { - this.map_ = map; +goog.debug.makeWhitespaceVisible = function(string) { + return string.replace(/ /g, '[_]') + .replace(/\f/g, '[f]') + .replace(/\n/g, '[n]\n') + .replace(/\r/g, '[r]') + .replace(/\t/g, '[t]'); }; /** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {ol.Coordinate} delta Delta. - * @param {number=} opt_duration Duration. + * Returns the type of a value. If a constructor is passed, and a suitable + * string cannot be found, 'unknown type name' will be returned. + * + * <p>Forked rather than moved from {@link goog.asserts.getType_} + * to avoid adding a dependency to goog.asserts. + * @param {*} value A constructor, object, or primitive. + * @return {string} The best display name for the value, or 'unknown type name'. */ -ol.interaction.Interaction.pan = function(map, view, delta, opt_duration) { - var currentCenter = view.getCenter(); - if (currentCenter) { - if (opt_duration && opt_duration > 0) { - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: opt_duration, - easing: ol.easing.linear - })); - } - var center = view.constrainCenter( - [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]); - view.setCenter(center); +goog.debug.runtimeType = function(value) { + if (value instanceof Function) { + return value.displayName || value.name || 'unknown type name'; + } else if (value instanceof Object) { + return value.constructor.displayName || value.constructor.name || + Object.prototype.toString.call(value); + } else { + return value === null ? 'null' : typeof value; } }; /** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} rotation Rotation. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. + * Hash map for storing function names that have already been looked up. + * @type {Object} + * @private */ -ol.interaction.Interaction.rotate = - function(map, view, rotation, opt_anchor, opt_duration) { - rotation = view.constrainRotation(rotation, 0); - ol.interaction.Interaction.rotateWithoutConstraints( - map, view, rotation, opt_anchor, opt_duration); -}; +goog.debug.fnNameCache_ = {}; /** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} rotation Rotation. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. + * Resolves functions to their names. Resolved function names will be cached. + * @type {function(Function):string} + * @private */ -ol.interaction.Interaction.rotateWithoutConstraints = - function(map, view, rotation, opt_anchor, opt_duration) { - if (rotation !== undefined) { - var currentRotation = view.getRotation(); - var currentCenter = view.getCenter(); - if (currentRotation !== undefined && currentCenter && - opt_duration && opt_duration > 0) { - map.beforeRender(ol.animation.rotate({ - rotation: currentRotation, - duration: opt_duration, - easing: ol.easing.easeOut - })); - if (opt_anchor) { - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: opt_duration, - easing: ol.easing.easeOut - })); - } - } - view.rotate(rotation, opt_anchor); - } -}; +goog.debug.fnNameResolver_; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} resolution Resolution to go to. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - * @param {number=} opt_direction Zooming direction; > 0 indicates - * zooming out, in which case the constraints system will select - * the largest nearest resolution; < 0 indicates zooming in, in - * which case the constraints system will select the smallest - * nearest resolution; == 0 indicates that the zooming direction - * is unknown/not relevant, in which case the constraints system - * will select the nearest resolution. If not defined 0 is - * assumed. + * @fileoverview Definition of the LogRecord class. Please minimize + * dependencies this file has on other closure classes as any dependency it + * takes won't be able to use the logging infrastructure. + * */ -ol.interaction.Interaction.zoom = - function(map, view, resolution, opt_anchor, opt_duration, opt_direction) { - resolution = view.constrainResolution(resolution, 0, opt_direction); - ol.interaction.Interaction.zoomWithoutConstraints( - map, view, resolution, opt_anchor, opt_duration); -}; +goog.provide('goog.debug.LogRecord'); -/** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number} delta Delta from previous zoom level. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. - */ -ol.interaction.Interaction.zoomByDelta = - function(map, view, delta, opt_anchor, opt_duration) { - var currentResolution = view.getResolution(); - var resolution = view.constrainResolution(currentResolution, delta, 0); - ol.interaction.Interaction.zoomWithoutConstraints( - map, view, resolution, opt_anchor, opt_duration); -}; /** - * @param {ol.Map} map Map. - * @param {ol.View} view View. - * @param {number|undefined} resolution Resolution to go to. - * @param {ol.Coordinate=} opt_anchor Anchor coordinate. - * @param {number=} opt_duration Duration. + * LogRecord objects are used to pass logging requests between + * the logging framework and individual log Handlers. + * @constructor + * @param {goog.debug.Logger.Level} level One of the level identifiers. + * @param {string} msg The string message. + * @param {string} loggerName The name of the source logger. + * @param {number=} opt_time Time this log record was created if other than now. + * If 0, we use #goog.now. + * @param {number=} opt_sequenceNumber Sequence number of this log record. This + * should only be passed in when restoring a log record from persistence. */ -ol.interaction.Interaction.zoomWithoutConstraints = - function(map, view, resolution, opt_anchor, opt_duration) { - if (resolution) { - var currentResolution = view.getResolution(); - var currentCenter = view.getCenter(); - if (currentResolution !== undefined && currentCenter && - resolution !== currentResolution && - opt_duration && opt_duration > 0) { - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: opt_duration, - easing: ol.easing.easeOut - })); - if (opt_anchor) { - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: opt_duration, - easing: ol.easing.easeOut - })); - } - } - if (opt_anchor) { - var center = view.calculateCenterZoom(resolution, opt_anchor); - view.setCenter(center); - } - view.setResolution(resolution); - } +goog.debug.LogRecord = function(level, msg, loggerName, + opt_time, opt_sequenceNumber) { + this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber); }; -goog.provide('ol.interaction.DoubleClickZoom'); - -goog.require('goog.asserts'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.interaction.Interaction'); +/** + * Time the LogRecord was created. + * @type {number} + * @private + */ +goog.debug.LogRecord.prototype.time_; /** - * @classdesc - * Allows the user to zoom by double-clicking on the map. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.DoubleClickZoomOptions=} opt_options Options. - * @api stable + * Level of the LogRecord + * @type {goog.debug.Logger.Level} + * @private */ -ol.interaction.DoubleClickZoom = function(opt_options) { - - var options = opt_options ? opt_options : {}; +goog.debug.LogRecord.prototype.level_; - /** - * @private - * @type {number} - */ - this.delta_ = options.delta ? options.delta : 1; - goog.base(this, { - handleEvent: ol.interaction.DoubleClickZoom.handleEvent - }); +/** + * Message associated with the record + * @type {string} + * @private + */ +goog.debug.LogRecord.prototype.msg_; - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; -}; -goog.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction); +/** + * Name of the logger that created the record. + * @type {string} + * @private + */ +goog.debug.LogRecord.prototype.loggerName_; /** - * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a - * doubleclick) and eventually zooms the map. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.DoubleClickZoom} - * @api + * Sequence number for the LogRecord. Each record has a unique sequence number + * that is greater than all log records created before it. + * @type {number} + * @private */ -ol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - var browserEvent = mapBrowserEvent.browserEvent; - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK) { - var map = mapBrowserEvent.map; - var anchor = mapBrowserEvent.coordinate; - var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_; - var view = map.getView(); - goog.asserts.assert(view, 'map must have a view'); - ol.interaction.Interaction.zoomByDelta( - map, view, delta, anchor, this.duration_); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - return !stopEvent; -}; +goog.debug.LogRecord.prototype.sequenceNumber_ = 0; -goog.provide('ol.events.ConditionType'); -goog.provide('ol.events.condition'); -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserPointerEvent'); +/** + * Exception associated with the record + * @type {Object} + * @private + */ +goog.debug.LogRecord.prototype.exception_ = null; /** - * A function that takes an {@link ol.MapBrowserEvent} and returns a - * `{boolean}`. If the condition is met, true should be returned. - * - * @typedef {function(ol.MapBrowserEvent): boolean} - * @api stable + * @define {boolean} Whether to enable log sequence numbers. */ -ol.events.ConditionType; +goog.define('goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS', true); /** - * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when - * additionally the shift-key is pressed). - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the alt key is pressed. - * @api stable + * A sequence counter for assigning increasing sequence numbers to LogRecord + * objects. + * @type {number} + * @private */ -ol.events.condition.altKeyOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - browserEvent.altKey && - !browserEvent.platformModifierKey && - !browserEvent.shiftKey); -}; +goog.debug.LogRecord.nextSequenceNumber_ = 0; /** - * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise - * (e.g. when additionally the platform-modifier-key is pressed). - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the alt and shift keys are pressed. - * @api stable + * Sets all fields of the log record. + * @param {goog.debug.Logger.Level} level One of the level identifiers. + * @param {string} msg The string message. + * @param {string} loggerName The name of the source logger. + * @param {number=} opt_time Time this log record was created if other than now. + * If 0, we use #goog.now. + * @param {number=} opt_sequenceNumber Sequence number of this log record. This + * should only be passed in when restoring a log record from persistence. */ -ol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - browserEvent.altKey && - !browserEvent.platformModifierKey && - browserEvent.shiftKey); +goog.debug.LogRecord.prototype.reset = function(level, msg, loggerName, + opt_time, opt_sequenceNumber) { + if (goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) { + this.sequenceNumber_ = typeof opt_sequenceNumber == 'number' ? + opt_sequenceNumber : goog.debug.LogRecord.nextSequenceNumber_++; + } + + this.time_ = opt_time || goog.now(); + this.level_ = level; + this.msg_ = msg; + this.loggerName_ = loggerName; + delete this.exception_; }; /** - * Return always true. + * Get the source Logger's name. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True. - * @function - * @api stable + * @return {string} source logger name (may be null). */ -ol.events.condition.always = goog.functions.TRUE; +goog.debug.LogRecord.prototype.getLoggerName = function() { + return this.loggerName_; +}; /** - * Return `true` if the event is a `click` event, `false` otherwise. + * Get the exception that is part of the log record. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event is a map `click` event. - * @api stable + * @return {Object} the exception. */ -ol.events.condition.click = function(mapBrowserEvent) { - return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.CLICK; +goog.debug.LogRecord.prototype.getException = function() { + return this.exception_; }; /** - * Return always false. + * Set the exception that is part of the log record. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} False. - * @function - * @api stable + * @param {Object} exception the exception. */ -ol.events.condition.never = goog.functions.FALSE; +goog.debug.LogRecord.prototype.setException = function(exception) { + this.exception_ = exception; +}; /** - * Return `true` if the browser event is a `pointermove` event, `false` - * otherwise. + * Get the source Logger's name. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the browser event is a `pointermove` event. - * @api + * @param {string} loggerName source logger name (may be null). */ -ol.events.condition.pointerMove = function(mapBrowserEvent) { - return mapBrowserEvent.type == 'pointermove'; +goog.debug.LogRecord.prototype.setLoggerName = function(loggerName) { + this.loggerName_ = loggerName; }; /** - * Return `true` if the event is a map `singleclick` event, `false` otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event is a map `singleclick` event. - * @api stable + * Get the logging message level, for example Level.SEVERE. + * @return {goog.debug.Logger.Level} the logging message level. */ -ol.events.condition.singleClick = function(mapBrowserEvent) { - return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK; +goog.debug.LogRecord.prototype.getLevel = function() { + return this.level_; }; /** - * Return `true` if the event is a map `dblclick` event, `false` otherwise. - * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event is a map `dblclick` event. - * @api stable + * Set the logging message level, for example Level.SEVERE. + * @param {goog.debug.Logger.Level} level the logging message level. */ -ol.events.condition.doubleClick = function(mapBrowserEvent) { - return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK; +goog.debug.LogRecord.prototype.setLevel = function(level) { + this.level_ = level; }; /** - * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is - * pressed. + * Get the "raw" log message, before localization or formatting. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True only if there no modifier keys are pressed. - * @api stable + * @return {string} the raw message string. */ -ol.events.condition.noModifierKeys = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - !browserEvent.altKey && - !browserEvent.platformModifierKey && - !browserEvent.shiftKey); +goog.debug.LogRecord.prototype.getMessage = function() { + return this.msg_; }; /** - * Return `true` if only the platform-modifier-key (the meta-key on Mac, - * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally - * the shift-key is pressed). + * Set the "raw" log message, before localization or formatting. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the platform modifier key is pressed. - * @api stable + * @param {string} msg the raw message string. */ -ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - !browserEvent.altKey && - browserEvent.platformModifierKey && - !browserEvent.shiftKey); +goog.debug.LogRecord.prototype.setMessage = function(msg) { + this.msg_ = msg; }; /** - * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when - * additionally the alt-key is pressed). + * Get event time in milliseconds since 1970. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if only the shift key is pressed. - * @api stable + * @return {number} event time in millis since 1970. */ -ol.events.condition.shiftKeyOnly = function(mapBrowserEvent) { - var browserEvent = mapBrowserEvent.browserEvent; - return ( - !browserEvent.altKey && - !browserEvent.platformModifierKey && - browserEvent.shiftKey); +goog.debug.LogRecord.prototype.getMillis = function() { + return this.time_; }; /** - * Return `true` if the target element is not editable, i.e. not a `<input>`-, - * `<select>`- or `<textarea>`-element, `false` otherwise. + * Set event time in milliseconds since 1970. * - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} True only if the target element is not editable. - * @api + * @param {number} time event time in millis since 1970. */ -ol.events.condition.targetNotEditable = function(mapBrowserEvent) { - var target = mapBrowserEvent.browserEvent.target; - goog.asserts.assertInstanceof(target, Element, - 'target should be an Element'); - var tagName = target.tagName; - return ( - tagName !== 'INPUT' && - tagName !== 'SELECT' && - tagName !== 'TEXTAREA'); +goog.debug.LogRecord.prototype.setMillis = function(time) { + this.time_ = time; }; /** - * Return `true` if the event originates from a mouse device. - * - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Map browser event. - * @return {boolean} True if the event originates from a mouse device. - * @api stable + * Get the sequence number. + * <p> + * Sequence numbers are normally assigned in the LogRecord + * constructor, which assigns unique sequence numbers to + * each new LogRecord in increasing order. + * @return {number} the sequence number. */ -ol.events.condition.mouseOnly = function(mapBrowserEvent) { - // see http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType - return mapBrowserEvent.pointerEvent.pointerType == 'mouse'; +goog.debug.LogRecord.prototype.getSequenceNumber = function() { + return this.sequenceNumber_; }; -goog.provide('ol.interaction.Pointer'); - -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserPointerEvent'); -goog.require('ol.Pixel'); -goog.require('ol.interaction.Interaction'); - +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @classdesc - * Base class that calls user-defined functions on `down`, `move` and `up` - * events. This class also manages "drag sequences". - * - * When the `handleDownEvent` user function returns `true` a drag sequence is - * started. During a drag sequence the `handleDragEvent` user function is - * called on `move` events. The drag sequence ends when the `handleUpEvent` - * user function is called and returns `false`. + * @fileoverview A buffer for log records. The purpose of this is to improve + * logging performance by re-using old objects when the buffer becomes full and + * to eliminate the need for each app to implement their own log buffer. The + * disadvantage to doing this is that log handlers cannot maintain references to + * log records and expect that they are not overwriten at a later point. * - * @constructor - * @param {olx.interaction.PointerOptions=} opt_options Options. - * @extends {ol.interaction.Interaction} - * @api + * @author agrieve@google.com (Andrew Grieve) */ -ol.interaction.Pointer = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var handleEvent = options.handleEvent ? - options.handleEvent : ol.interaction.Pointer.handleEvent; - - goog.base(this, { - handleEvent: handleEvent - }); - - /** - * @type {function(ol.MapBrowserPointerEvent):boolean} - * @private - */ - this.handleDownEvent_ = options.handleDownEvent ? - options.handleDownEvent : ol.interaction.Pointer.handleDownEvent; - - /** - * @type {function(ol.MapBrowserPointerEvent)} - * @private - */ - this.handleDragEvent_ = options.handleDragEvent ? - options.handleDragEvent : ol.interaction.Pointer.handleDragEvent; - - /** - * @type {function(ol.MapBrowserPointerEvent)} - * @private - */ - this.handleMoveEvent_ = options.handleMoveEvent ? - options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent; - /** - * @type {function(ol.MapBrowserPointerEvent):boolean} - * @private - */ - this.handleUpEvent_ = options.handleUpEvent ? - options.handleUpEvent : ol.interaction.Pointer.handleUpEvent; +goog.provide('goog.debug.LogBuffer'); - /** - * @type {boolean} - * @protected - */ - this.handlingDownUpSequence = false; +goog.require('goog.asserts'); +goog.require('goog.debug.LogRecord'); - /** - * @type {Object.<number, ol.pointer.PointerEvent>} - * @private - */ - this.trackedPointers_ = {}; - /** - * @type {Array.<ol.pointer.PointerEvent>} - * @protected - */ - this.targetPointers = []; +/** + * Creates the log buffer. + * @constructor + * @final + */ +goog.debug.LogBuffer = function() { + goog.asserts.assert(goog.debug.LogBuffer.isBufferingEnabled(), + 'Cannot use goog.debug.LogBuffer without defining ' + + 'goog.debug.LogBuffer.CAPACITY.'); + this.clear(); }; -goog.inherits(ol.interaction.Pointer, ol.interaction.Interaction); /** - * @param {Array.<ol.pointer.PointerEvent>} pointerEvents - * @return {ol.Pixel} Centroid pixel. + * A static method that always returns the same instance of LogBuffer. + * @return {!goog.debug.LogBuffer} The LogBuffer singleton instance. */ -ol.interaction.Pointer.centroid = function(pointerEvents) { - var length = pointerEvents.length; - var clientX = 0; - var clientY = 0; - for (var i = 0; i < length; i++) { - clientX += pointerEvents[i].clientX; - clientY += pointerEvents[i].clientY; +goog.debug.LogBuffer.getInstance = function() { + if (!goog.debug.LogBuffer.instance_) { + // This function is written with the return statement after the assignment + // to avoid the jscompiler StripCode bug described in http://b/2608064. + // After that bug is fixed this can be refactored. + goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer(); } - return [clientX / length, clientY / length]; + return goog.debug.LogBuffer.instance_; }; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Whether the event is a pointerdown, pointerdrag - * or pointerup event. - * @private + * @define {number} The number of log records to buffer. 0 means disable + * buffering. */ -ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = - function(mapBrowserEvent) { - var type = mapBrowserEvent.type; - return ( - type === ol.MapBrowserEvent.EventType.POINTERDOWN || - type === ol.MapBrowserEvent.EventType.POINTERDRAG || - type === ol.MapBrowserEvent.EventType.POINTERUP); -}; +goog.define('goog.debug.LogBuffer.CAPACITY', 0); /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * The array to store the records. + * @type {!Array<!goog.debug.LogRecord|undefined>} * @private */ -ol.interaction.Pointer.prototype.updateTrackedPointers_ = - function(mapBrowserEvent) { - if (this.isPointerDraggingEvent_(mapBrowserEvent)) { - var event = mapBrowserEvent.pointerEvent; - - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { - delete this.trackedPointers_[event.pointerId]; - } else if (mapBrowserEvent.type == - ol.MapBrowserEvent.EventType.POINTERDOWN) { - this.trackedPointers_[event.pointerId] = event; - } else if (event.pointerId in this.trackedPointers_) { - // update only when there was a pointerdown event for this pointer - this.trackedPointers_[event.pointerId] = event; - } - this.targetPointers = goog.object.getValues(this.trackedPointers_); - } -}; +goog.debug.LogBuffer.prototype.buffer_; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.Pointer} + * The index of the most recently added record or -1 if there are no records. + * @type {number} + * @private */ -ol.interaction.Pointer.handleDragEvent = ol.nullFunction; +goog.debug.LogBuffer.prototype.curIndex_; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Capture dragging. - * @this {ol.interaction.Pointer} + * Whether the buffer is at capacity. + * @type {boolean} + * @private */ -ol.interaction.Pointer.handleUpEvent = goog.functions.FALSE; +goog.debug.LogBuffer.prototype.isFull_; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Capture dragging. - * @this {ol.interaction.Pointer} + * Adds a log record to the buffer, possibly overwriting the oldest record. + * @param {goog.debug.Logger.Level} level One of the level identifiers. + * @param {string} msg The string message. + * @param {string} loggerName The name of the source logger. + * @return {!goog.debug.LogRecord} The log record. */ -ol.interaction.Pointer.handleDownEvent = goog.functions.FALSE; +goog.debug.LogBuffer.prototype.addRecord = function(level, msg, loggerName) { + var curIndex = (this.curIndex_ + 1) % goog.debug.LogBuffer.CAPACITY; + this.curIndex_ = curIndex; + if (this.isFull_) { + var ret = this.buffer_[curIndex]; + ret.reset(level, msg, loggerName); + return ret; + } + this.isFull_ = curIndex == goog.debug.LogBuffer.CAPACITY - 1; + return this.buffer_[curIndex] = + new goog.debug.LogRecord(level, msg, loggerName); +}; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.Pointer} + * @return {boolean} Whether the log buffer is enabled. */ -ol.interaction.Pointer.handleMoveEvent = ol.nullFunction; +goog.debug.LogBuffer.isBufferingEnabled = function() { + return goog.debug.LogBuffer.CAPACITY > 0; +}; /** - * Handles the {@link ol.MapBrowserEvent map browser event} and may call into - * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are - * detected. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Pointer} - * @api + * Removes all buffered log records. */ -ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) { - if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) { - return true; - } +goog.debug.LogBuffer.prototype.clear = function() { + this.buffer_ = new Array(goog.debug.LogBuffer.CAPACITY); + this.curIndex_ = -1; + this.isFull_ = false; +}; - var stopEvent = false; - this.updateTrackedPointers_(mapBrowserEvent); - if (this.handlingDownUpSequence) { - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDRAG) { - this.handleDragEvent_(mapBrowserEvent); - } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { - this.handlingDownUpSequence = this.handleUpEvent_(mapBrowserEvent); - } - } - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { - var handled = this.handleDownEvent_(mapBrowserEvent); - this.handlingDownUpSequence = handled; - stopEvent = this.shouldStopEvent(handled); - } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE) { - this.handleMoveEvent_(mapBrowserEvent); + +/** + * Calls the given function for each buffered log record, starting with the + * oldest one. + * @param {function(!goog.debug.LogRecord)} func The function to call. + */ +goog.debug.LogBuffer.prototype.forEachRecord = function(func) { + var buffer = this.buffer_; + // Corner case: no records. + if (!buffer[0]) { + return; } - return !stopEvent; + var curIndex = this.curIndex_; + var i = this.isFull_ ? curIndex : -1; + do { + i = (i + 1) % goog.debug.LogBuffer.CAPACITY; + func(/** @type {!goog.debug.LogRecord} */ (buffer[i])); + } while (i != curIndex); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /** - * This method is used to determine if "down" events should be propagated to - * other interactions or should be stopped. - * - * The method receives the return code of the "handleDownEvent" function. - * - * By default this function is the "identity" function. It's overidden in - * child classes. + * @fileoverview Definition of the Logger class. Please minimize dependencies + * this file has on other closure classes as any dependency it takes won't be + * able to use the logging infrastructure. * - * @param {boolean} handled Was the event handled by the interaction? - * @return {boolean} Should the event be stopped? - * @protected + * @see ../demos/debug.html */ -ol.interaction.Pointer.prototype.shouldStopEvent = goog.functions.identity; -goog.provide('ol.interaction.DragPan'); +goog.provide('goog.debug.LogManager'); +goog.provide('goog.debug.Loggable'); +goog.provide('goog.debug.Logger'); +goog.provide('goog.debug.Logger.Level'); +goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('ol.Kinetic'); -goog.require('ol.Pixel'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.ViewHint'); -goog.require('ol.coordinate'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Pointer'); +goog.require('goog.debug'); +goog.require('goog.debug.LogBuffer'); +goog.require('goog.debug.LogRecord'); + + +/** + * A message value that can be handled by a Logger. + * + * Functions are treated like callbacks, but are only called when the event's + * log level is enabled. This is useful for logging messages that are expensive + * to construct. + * + * @typedef {string|function(): string} + */ +goog.debug.Loggable; /** - * @classdesc - * Allows the user to pan the map by dragging the map. + * The Logger is an object used for logging debug messages. Loggers are + * normally named, using a hierarchical dot-separated namespace. Logger names + * can be arbitrary strings, but they should normally be based on the package + * name or class name of the logged component, such as goog.net.BrowserChannel. + * + * The Logger object is loosely based on the java class + * java.util.logging.Logger. It supports different levels of filtering for + * different loggers. + * + * The logger object should never be instantiated by application code. It + * should always use the goog.debug.Logger.getLogger function. * * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.DragPanOptions=} opt_options Options. - * @api stable + * @param {string} name The name of the Logger. + * @final */ -ol.interaction.DragPan = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.DragPan.handleDownEvent_, - handleDragEvent: ol.interaction.DragPan.handleDragEvent_, - handleUpEvent: ol.interaction.DragPan.handleUpEvent_ - }); +goog.debug.Logger = function(name) { + /** + * Name of the Logger. Generally a dot-separated namespace + * @private {string} + */ + this.name_ = name; - var options = opt_options ? opt_options : {}; + /** + * Parent Logger. + * @private {goog.debug.Logger} + */ + this.parent_ = null; /** - * @private - * @type {ol.Kinetic|undefined} + * Level that this logger only filters above. Null indicates it should + * inherit from the parent. + * @private {goog.debug.Logger.Level} */ - this.kinetic_ = options.kinetic; + this.level_ = null; /** - * @private - * @type {?ol.PreRenderFunction} + * Map of children loggers. The keys are the leaf names of the children and + * the values are the child loggers. + * @private {Object} */ - this.kineticPreRenderFn_ = null; + this.children_ = null; /** - * @type {ol.Pixel} + * Handlers that are listening to this logger. + * @private {Array<Function>} */ - this.lastCentroid = null; + this.handlers_ = null; +}; + + +/** @const */ +goog.debug.Logger.ROOT_LOGGER_NAME = ''; + + +/** + * @define {boolean} Toggles whether loggers other than the root logger can have + * log handlers attached to them and whether they can have their log level + * set. Logging is a bit faster when this is set to false. + */ +goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true); + +if (!goog.debug.Logger.ENABLE_HIERARCHY) { /** + * @type {!Array<Function>} * @private - * @type {ol.events.ConditionType} */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.noModifierKeys; + goog.debug.Logger.rootHandlers_ = []; + /** + * @type {goog.debug.Logger.Level} * @private - * @type {boolean} */ - this.noKinetic_ = false; + goog.debug.Logger.rootLevel_; +} -}; -goog.inherits(ol.interaction.DragPan, ol.interaction.Pointer); /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragPan} - * @private + * The Level class defines a set of standard logging levels that + * can be used to control logging output. The logging Level objects + * are ordered and are specified by ordered integers. Enabling logging + * at a given level also enables logging at all higher levels. + * <p> + * Clients should normally use the predefined Level constants such + * as Level.SEVERE. + * <p> + * The levels in descending order are: + * <ul> + * <li>SEVERE (highest value) + * <li>WARNING + * <li>INFO + * <li>CONFIG + * <li>FINE + * <li>FINER + * <li>FINEST (lowest value) + * </ul> + * In addition there is a level OFF that can be used to turn + * off logging, and a level ALL that can be used to enable + * logging of all messages. + * + * @param {string} name The name of the level. + * @param {number} value The numeric value of the level. + * @constructor + * @final */ -ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) { - goog.asserts.assert(this.targetPointers.length >= 1, - 'the length of this.targetPointers should be more than 1'); - var centroid = - ol.interaction.Pointer.centroid(this.targetPointers); - if (this.kinetic_) { - this.kinetic_.update(centroid[0], centroid[1]); - } - if (this.lastCentroid) { - var deltaX = this.lastCentroid[0] - centroid[0]; - var deltaY = centroid[1] - this.lastCentroid[1]; - var map = mapBrowserEvent.map; - var view = map.getView(); - var viewState = view.getState(); - var center = [deltaX, deltaY]; - ol.coordinate.scale(center, viewState.resolution); - ol.coordinate.rotate(center, viewState.rotation); - ol.coordinate.add(center, viewState.center); - center = view.constrainCenter(center); - map.render(); - view.setCenter(center); - } - this.lastCentroid = centroid; +goog.debug.Logger.Level = function(name, value) { + /** + * The name of the level + * @type {string} + */ + this.name = name; + + /** + * The numeric value of the level + * @type {number} + */ + this.value = value; }; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragPan} - * @private + * @return {string} String representation of the logger level. + * @override */ -ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) { - var map = mapBrowserEvent.map; - var view = map.getView(); - if (this.targetPointers.length === 0) { - if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) { - var distance = this.kinetic_.getDistance(); - var angle = this.kinetic_.getAngle(); - var center = view.getCenter(); - goog.asserts.assert(center !== undefined, 'center should be defined'); - this.kineticPreRenderFn_ = this.kinetic_.pan(center); - map.beforeRender(this.kineticPreRenderFn_); - var centerpx = map.getPixelFromCoordinate(center); - var dest = map.getCoordinateFromPixel([ - centerpx[0] - distance * Math.cos(angle), - centerpx[1] - distance * Math.sin(angle) - ]); - dest = view.constrainCenter(dest); - view.setCenter(dest); - } - view.setHint(ol.ViewHint.INTERACTING, -1); - map.render(); - return false; - } else { - this.lastCentroid = null; - return true; - } +goog.debug.Logger.Level.prototype.toString = function() { + return this.name; }; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragPan} - * @private - */ -ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) { - var map = mapBrowserEvent.map; - var view = map.getView(); - this.lastCentroid = null; - if (!this.handlingDownUpSequence) { - view.setHint(ol.ViewHint.INTERACTING, 1); - } - map.render(); - if (this.kineticPreRenderFn_ && - map.removePreRenderFunction(this.kineticPreRenderFn_)) { - view.setCenter(mapBrowserEvent.frameState.viewState.center); - this.kineticPreRenderFn_ = null; - } - if (this.kinetic_) { - this.kinetic_.begin(); - } - // No kinetic as soon as more than one pointer on the screen is - // detected. This is to prevent nasty pans after pinch. - this.noKinetic_ = this.targetPointers.length > 1; - return true; - } else { - return false; - } -}; + * OFF is a special level that can be used to turn off logging. + * This level is initialized to <CODE>Infinity</CODE>. + * @type {!goog.debug.Logger.Level} + */ +goog.debug.Logger.Level.OFF = + new goog.debug.Logger.Level('OFF', Infinity); /** - * @inheritDoc + * SHOUT is a message level for extra debugging loudness. + * This level is initialized to <CODE>1200</CODE>. + * @type {!goog.debug.Logger.Level} */ -ol.interaction.DragPan.prototype.shouldStopEvent = goog.functions.FALSE; - -goog.provide('ol.interaction.DragRotate'); - -goog.require('ol'); -goog.require('ol.ViewHint'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); - +goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200); /** - * @classdesc - * Allows the user to rotate the map by clicking and dragging on the map, - * normally combined with an {@link ol.events.condition} that limits - * it to when the alt and shift keys are held down. - * - * This interaction is only supported for mouse devices. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.DragRotateOptions=} opt_options Options. - * @api stable + * SEVERE is a message level indicating a serious failure. + * This level is initialized to <CODE>1000</CODE>. + * @type {!goog.debug.Logger.Level} */ -ol.interaction.DragRotate = function(opt_options) { - - var options = opt_options ? opt_options : {}; +goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000); - goog.base(this, { - handleDownEvent: ol.interaction.DragRotate.handleDownEvent_, - handleDragEvent: ol.interaction.DragRotate.handleDragEvent_, - handleUpEvent: ol.interaction.DragRotate.handleUpEvent_ - }); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.altShiftKeysOnly; +/** + * WARNING is a message level indicating a potential problem. + * This level is initialized to <CODE>900</CODE>. + * @type {!goog.debug.Logger.Level} + */ +goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900); - /** - * @private - * @type {number|undefined} - */ - this.lastAngle_ = undefined; - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; -}; -goog.inherits(ol.interaction.DragRotate, ol.interaction.Pointer); +/** + * INFO is a message level for informational messages. + * This level is initialized to <CODE>800</CODE>. + * @type {!goog.debug.Logger.Level} + */ +goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800); /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragRotate} - * @private + * CONFIG is a message level for static configuration messages. + * This level is initialized to <CODE>700</CODE>. + * @type {!goog.debug.Logger.Level} */ -ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return; - } - - var map = mapBrowserEvent.map; - var size = map.getSize(); - var offset = mapBrowserEvent.pixel; - var theta = - Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2); - if (this.lastAngle_ !== undefined) { - var delta = theta - this.lastAngle_; - var view = map.getView(); - var rotation = view.getRotation(); - map.render(); - ol.interaction.Interaction.rotateWithoutConstraints( - map, view, rotation - delta); - } - this.lastAngle_ = theta; -}; +goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700); /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragRotate} - * @private + * FINE is a message level providing tracing information. + * This level is initialized to <CODE>500</CODE>. + * @type {!goog.debug.Logger.Level} */ -ol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return true; - } +goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500); - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - var rotation = view.getRotation(); - ol.interaction.Interaction.rotate(map, view, rotation, - undefined, this.duration_); - return false; -}; +/** + * FINER indicates a fairly detailed tracing message. + * This level is initialized to <CODE>400</CODE>. + * @type {!goog.debug.Logger.Level} + */ +goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400); /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragRotate} - * @private + * FINEST indicates a highly detailed tracing message. + * This level is initialized to <CODE>300</CODE>. + * @type {!goog.debug.Logger.Level} */ -ol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return false; - } - var browserEvent = mapBrowserEvent.browserEvent; - if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) { - var map = mapBrowserEvent.map; - map.getView().setHint(ol.ViewHint.INTERACTING, 1); - map.render(); - this.lastAngle_ = undefined; - return true; - } else { - return false; - } -}; +goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300); /** - * @inheritDoc + * ALL indicates that all messages should be logged. + * This level is initialized to <CODE>0</CODE>. + * @type {!goog.debug.Logger.Level} */ -ol.interaction.DragRotate.prototype.shouldStopEvent = goog.functions.FALSE; - -// FIXME add rotation - -goog.provide('ol.render.Box'); +goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0); -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('ol.geom.Polygon'); +/** + * The predefined levels. + * @type {!Array<!goog.debug.Logger.Level>} + * @final + */ +goog.debug.Logger.Level.PREDEFINED_LEVELS = [ + goog.debug.Logger.Level.OFF, + goog.debug.Logger.Level.SHOUT, + goog.debug.Logger.Level.SEVERE, + goog.debug.Logger.Level.WARNING, + goog.debug.Logger.Level.INFO, + goog.debug.Logger.Level.CONFIG, + goog.debug.Logger.Level.FINE, + goog.debug.Logger.Level.FINER, + goog.debug.Logger.Level.FINEST, + goog.debug.Logger.Level.ALL]; /** - * @constructor - * @extends {goog.Disposable} - * @param {string} className CSS class name. + * A lookup map used to find the level object based on the name or value of + * the level object. + * @type {Object} + * @private */ -ol.render.Box = function(className) { - - /** - * @type {ol.geom.Polygon} - * @private - */ - this.geometry_ = null; +goog.debug.Logger.Level.predefinedLevelsCache_ = null; - /** - * @type {HTMLDivElement} - * @private - */ - this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div')); - this.element_.style.position = 'absolute'; - this.element_.className = 'ol-box ' + className; - /** - * @private - * @type {ol.Map} - */ - this.map_ = null; +/** + * Creates the predefined levels cache and populates it. + * @private + */ +goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() { + goog.debug.Logger.Level.predefinedLevelsCache_ = {}; + for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i]; + i++) { + goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level; + goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level; + } +}; - /** - * @private - * @type {ol.Pixel} - */ - this.startPixel_ = null; - /** - * @private - * @type {ol.Pixel} - */ - this.endPixel_ = null; +/** + * Gets the predefined level with the given name. + * @param {string} name The name of the level. + * @return {goog.debug.Logger.Level} The level, or null if none found. + */ +goog.debug.Logger.Level.getPredefinedLevel = function(name) { + if (!goog.debug.Logger.Level.predefinedLevelsCache_) { + goog.debug.Logger.Level.createPredefinedLevelsCache_(); + } + return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null; }; -goog.inherits(ol.render.Box, goog.Disposable); /** - * @inheritDoc + * Gets the highest predefined level <= #value. + * @param {number} value Level value. + * @return {goog.debug.Logger.Level} The level, or null if none found. */ -ol.render.Box.prototype.disposeInternal = function() { - this.setMap(null); - goog.base(this, 'disposeInternal'); +goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) { + if (!goog.debug.Logger.Level.predefinedLevelsCache_) { + goog.debug.Logger.Level.createPredefinedLevelsCache_(); + } + + if (value in goog.debug.Logger.Level.predefinedLevelsCache_) { + return goog.debug.Logger.Level.predefinedLevelsCache_[value]; + } + + for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) { + var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i]; + if (level.value <= value) { + return level; + } + } + return null; }; /** - * @private + * Finds or creates a logger for a named subsystem. If a logger has already been + * created with the given name it is returned. Otherwise a new logger is + * created. If a new logger is created its log level will be configured based + * on the LogManager configuration and it will configured to also send logging + * output to its parent's handlers. It will be registered in the LogManager + * global namespace. + * + * @param {string} name A name for the logger. This should be a dot-separated + * name and should normally be based on the package name or class name of the + * subsystem, such as goog.net.BrowserChannel. + * @return {!goog.debug.Logger} The named logger. + * @deprecated use goog.log instead. http://go/goog-debug-logger-deprecated */ -ol.render.Box.prototype.render_ = function() { - var startPixel = this.startPixel_; - var endPixel = this.endPixel_; - goog.asserts.assert(startPixel, 'this.startPixel_ must be truthy'); - goog.asserts.assert(endPixel, 'this.endPixel_ must be truthy'); - var px = 'px'; - var style = this.element_.style; - style.left = Math.min(startPixel[0], endPixel[0]) + px; - style.top = Math.min(startPixel[1], endPixel[1]) + px; - style.width = Math.abs(endPixel[0] - startPixel[0]) + px; - style.height = Math.abs(endPixel[1] - startPixel[1]) + px; +goog.debug.Logger.getLogger = function(name) { + return goog.debug.LogManager.getLogger(name); }; /** - * @param {ol.Map} map Map. + * Logs a message to profiling tools, if available. + * {@see https://developers.google.com/web-toolkit/speedtracer/logging-api} + * {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx} + * @param {string} msg The message to log. */ -ol.render.Box.prototype.setMap = function(map) { - if (this.map_) { - this.map_.getOverlayContainer().removeChild(this.element_); - var style = this.element_.style; - style.left = style.top = style.width = style.height = 'inherit'; +goog.debug.Logger.logToProfilers = function(msg) { + // Using goog.global, as loggers might be used in window-less contexts. + if (goog.global['console']) { + if (goog.global['console']['timeStamp']) { + // Logs a message to Firebug, Web Inspector, SpeedTracer, etc. + goog.global['console']['timeStamp'](msg); + } else if (goog.global['console']['markTimeline']) { + // TODO(user): markTimeline is deprecated. Drop this else clause entirely + // after Chrome M14 hits stable. + goog.global['console']['markTimeline'](msg); + } } - this.map_ = map; - if (this.map_) { - this.map_.getOverlayContainer().appendChild(this.element_); + + if (goog.global['msWriteProfilerMark']) { + // Logs a message to the Microsoft profiler + goog.global['msWriteProfilerMark'](msg); } }; /** - * @param {ol.Pixel} startPixel Start pixel. - * @param {ol.Pixel} endPixel End pixel. + * Gets the name of this logger. + * @return {string} The name of this logger. */ -ol.render.Box.prototype.setPixels = function(startPixel, endPixel) { - this.startPixel_ = startPixel; - this.endPixel_ = endPixel; - this.createOrUpdateGeometry(); - this.render_(); +goog.debug.Logger.prototype.getName = function() { + return this.name_; }; /** - * Creates or updates the cached geometry. + * Adds a handler to the logger. This doesn't use the event system because + * we want to be able to add logging to the event system. + * @param {Function} handler Handler function to add. */ -ol.render.Box.prototype.createOrUpdateGeometry = function() { - goog.asserts.assert(this.startPixel_, - 'this.startPixel_ must be truthy'); - goog.asserts.assert(this.endPixel_, - 'this.endPixel_ must be truthy'); - goog.asserts.assert(this.map_, 'this.map_ must be truthy'); - var startPixel = this.startPixel_; - var endPixel = this.endPixel_; - var pixels = [ - startPixel, - [startPixel[0], endPixel[1]], - endPixel, - [endPixel[0], startPixel[1]] - ]; - var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_); - // close the polygon - coordinates[4] = coordinates[0].slice(); - if (!this.geometry_) { - this.geometry_ = new ol.geom.Polygon([coordinates]); - } else { - this.geometry_.setCoordinates([coordinates]); +goog.debug.Logger.prototype.addHandler = function(handler) { + if (goog.debug.LOGGING_ENABLED) { + if (goog.debug.Logger.ENABLE_HIERARCHY) { + if (!this.handlers_) { + this.handlers_ = []; + } + this.handlers_.push(handler); + } else { + goog.asserts.assert(!this.name_, + 'Cannot call addHandler on a non-root logger when ' + + 'goog.debug.Logger.ENABLE_HIERARCHY is false.'); + goog.debug.Logger.rootHandlers_.push(handler); + } } }; /** - * @return {ol.geom.Polygon} Geometry. + * Removes a handler from the logger. This doesn't use the event system because + * we want to be able to add logging to the event system. + * @param {Function} handler Handler function to remove. + * @return {boolean} Whether the handler was removed. */ -ol.render.Box.prototype.getGeometry = function() { - return this.geometry_; +goog.debug.Logger.prototype.removeHandler = function(handler) { + if (goog.debug.LOGGING_ENABLED) { + var handlers = goog.debug.Logger.ENABLE_HIERARCHY ? this.handlers_ : + goog.debug.Logger.rootHandlers_; + return !!handlers && goog.array.remove(handlers, handler); + } else { + return false; + } }; -// FIXME draw drag box -goog.provide('ol.DragBoxEvent'); -goog.provide('ol.interaction.DragBox'); - -goog.require('goog.events.Event'); -goog.require('ol'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.render.Box'); - /** - * @const - * @type {number} + * Returns the parent of this logger. + * @return {goog.debug.Logger} The parent logger or null if this is the root. */ -ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED = - ol.DRAG_BOX_HYSTERESIS_PIXELS * - ol.DRAG_BOX_HYSTERESIS_PIXELS; +goog.debug.Logger.prototype.getParent = function() { + return this.parent_; +}; /** - * @enum {string} + * Returns the children of this logger as a map of the child name to the logger. + * @return {!Object} The map where the keys are the child leaf names and the + * values are the Logger objects. */ -ol.DragBoxEventType = { - /** - * Triggered upon drag box start. - * @event ol.DragBoxEvent#boxstart - * @api stable - */ - BOXSTART: 'boxstart', - /** - * Triggered upon drag box end. - * @event ol.DragBoxEvent#boxend - * @api stable - */ - BOXEND: 'boxend' +goog.debug.Logger.prototype.getChildren = function() { + if (!this.children_) { + this.children_ = {}; + } + return this.children_; }; - /** - * @classdesc - * Events emitted by {@link ol.interaction.DragBox} instances are instances of - * this type. + * Set the log level specifying which message levels will be logged by this + * logger. Message levels lower than this value will be discarded. + * The level value Level.OFF can be used to turn off logging. If the new level + * is null, it means that this node should inherit its level from its nearest + * ancestor with a specific (non-null) level value. * - * @param {string} type The event type. - * @param {ol.Coordinate} coordinate The event coordinate. - * @extends {goog.events.Event} - * @constructor - * @implements {oli.DragBoxEvent} + * @param {goog.debug.Logger.Level} level The new level. */ -ol.DragBoxEvent = function(type, coordinate) { - goog.base(this, type); - - /** - * The coordinate of the drag event. - * @const - * @type {ol.Coordinate} - * @api stable - */ - this.coordinate = coordinate; - +goog.debug.Logger.prototype.setLevel = function(level) { + if (goog.debug.LOGGING_ENABLED) { + if (goog.debug.Logger.ENABLE_HIERARCHY) { + this.level_ = level; + } else { + goog.asserts.assert(!this.name_, + 'Cannot call setLevel() on a non-root logger when ' + + 'goog.debug.Logger.ENABLE_HIERARCHY is false.'); + goog.debug.Logger.rootLevel_ = level; + } + } }; -goog.inherits(ol.DragBoxEvent, goog.events.Event); - /** - * @classdesc - * Allows the user to draw a vector box by clicking and dragging on the map, - * normally combined with an {@link ol.events.condition} that limits - * it to when the shift or other key is held down. This is used, for example, - * for zooming to a specific area of the map - * (see {@link ol.interaction.DragZoom} and - * {@link ol.interaction.DragRotateAndZoom}). - * - * This interaction is only supported for mouse devices. + * Gets the log level specifying which message levels will be logged by this + * logger. Message levels lower than this value will be discarded. + * The level value Level.OFF can be used to turn off logging. If the level + * is null, it means that this node should inherit its level from its nearest + * ancestor with a specific (non-null) level value. * - * @constructor - * @extends {ol.interaction.Pointer} - * @fires ol.DragBoxEvent - * @param {olx.interaction.DragBoxOptions=} opt_options Options. - * @api stable + * @return {goog.debug.Logger.Level} The level. */ -ol.interaction.DragBox = function(opt_options) { +goog.debug.Logger.prototype.getLevel = function() { + return goog.debug.LOGGING_ENABLED ? + this.level_ : goog.debug.Logger.Level.OFF; +}; - goog.base(this, { - handleDownEvent: ol.interaction.DragBox.handleDownEvent_, - handleDragEvent: ol.interaction.DragBox.handleDragEvent_, - handleUpEvent: ol.interaction.DragBox.handleUpEvent_ - }); - - var options = opt_options ? opt_options : {}; - /** - * @type {ol.render.Box} - * @private - */ - this.box_ = new ol.render.Box(options.className || 'ol-dragbox'); +/** + * Returns the effective level of the logger based on its ancestors' levels. + * @return {goog.debug.Logger.Level} The level. + */ +goog.debug.Logger.prototype.getEffectiveLevel = function() { + if (!goog.debug.LOGGING_ENABLED) { + return goog.debug.Logger.Level.OFF; + } - /** - * @type {ol.Pixel} - * @private - */ - this.startPixel_ = null; + if (!goog.debug.Logger.ENABLE_HIERARCHY) { + return goog.debug.Logger.rootLevel_; + } + if (this.level_) { + return this.level_; + } + if (this.parent_) { + return this.parent_.getEffectiveLevel(); + } + goog.asserts.fail('Root logger has no level set.'); + return null; +}; - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.always; +/** + * Checks if a message of the given level would actually be logged by this + * logger. This check is based on the Loggers effective level, which may be + * inherited from its parent. + * @param {goog.debug.Logger.Level} level The level to check. + * @return {boolean} Whether the message would be logged. + */ +goog.debug.Logger.prototype.isLoggable = function(level) { + return goog.debug.LOGGING_ENABLED && + level.value >= this.getEffectiveLevel().value; }; -goog.inherits(ol.interaction.DragBox, ol.interaction.Pointer); /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragBox} - * @private + * Logs a message. If the logger is currently enabled for the + * given message level then the given message is forwarded to all the + * registered output Handler objects. + * @param {goog.debug.Logger.Level} level One of the level identifiers. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error|Object=} opt_exception An exception associated with the + * message. */ -ol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return; - } +goog.debug.Logger.prototype.log = function(level, msg, opt_exception) { + // java caches the effective level, not sure it's necessary here + if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) { + // Message callbacks can be useful when a log message is expensive to build. + if (goog.isFunction(msg)) { + msg = msg(); + } - this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel); + this.doLogRecord_(this.getLogRecord(level, msg, opt_exception)); + } }; /** - * Returns geometry of last drawn box. - * @return {ol.geom.Polygon} Geometry. - * @api stable + * Creates a new log record and adds the exception (if present) to it. + * @param {goog.debug.Logger.Level} level One of the level identifiers. + * @param {string} msg The string message. + * @param {Error|Object=} opt_exception An exception associated with the + * message. + * @return {!goog.debug.LogRecord} A log record. + * @suppress {es5Strict} */ -ol.interaction.DragBox.prototype.getGeometry = function() { - return this.box_.getGeometry(); +goog.debug.Logger.prototype.getLogRecord = function( + level, msg, opt_exception) { + if (goog.debug.LogBuffer.isBufferingEnabled()) { + var logRecord = + goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_); + } else { + logRecord = new goog.debug.LogRecord(level, String(msg), this.name_); + } + if (opt_exception) { + logRecord.setException(opt_exception); + } + return logRecord; }; /** - * To be overriden by child classes. - * FIXME: use constructor option instead of relying on overridding. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @protected + * Logs a message at the Logger.Level.SHOUT level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.interaction.DragBox.prototype.onBoxEnd = ol.nullFunction; +goog.debug.Logger.prototype.shout = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception); + } +}; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragBox} - * @private + * Logs a message at the Logger.Level.SEVERE level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return true; +goog.debug.Logger.prototype.severe = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception); } +}; - this.box_.setMap(null); - - var deltaX = mapBrowserEvent.pixel[0] - this.startPixel_[0]; - var deltaY = mapBrowserEvent.pixel[1] - this.startPixel_[1]; - if (deltaX * deltaX + deltaY * deltaY >= - ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED) { - this.onBoxEnd(mapBrowserEvent); - this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXEND, - mapBrowserEvent.coordinate)); +/** + * Logs a message at the Logger.Level.WARNING level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. + */ +goog.debug.Logger.prototype.warning = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception); } - return false; }; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragBox} - * @private + * Logs a message at the Logger.Level.INFO level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return false; - } - - var browserEvent = mapBrowserEvent.browserEvent; - if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) { - this.startPixel_ = mapBrowserEvent.pixel; - this.box_.setMap(mapBrowserEvent.map); - this.box_.setPixels(this.startPixel_, this.startPixel_); - this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXSTART, - mapBrowserEvent.coordinate)); - return true; - } else { - return false; +goog.debug.Logger.prototype.info = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.INFO, msg, opt_exception); } }; -goog.provide('ol.interaction.DragZoom'); - -goog.require('goog.asserts'); -goog.require('ol.animation'); -goog.require('ol.easing'); -goog.require('ol.events.condition'); -goog.require('ol.extent'); -goog.require('ol.interaction.DragBox'); +/** + * Logs a message at the Logger.Level.CONFIG level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. + */ +goog.debug.Logger.prototype.config = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception); + } +}; /** - * @classdesc - * Allows the user to zoom the map by clicking and dragging on the map, - * normally combined with an {@link ol.events.condition} that limits - * it to when a key, shift by default, is held down. - * - * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or - * your custom one configured with `className`. - * - * @constructor - * @extends {ol.interaction.DragBox} - * @param {olx.interaction.DragZoomOptions=} opt_options Options. - * @api stable + * Logs a message at the Logger.Level.FINE level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.interaction.DragZoom = function(opt_options) { - var options = opt_options ? opt_options : {}; +goog.debug.Logger.prototype.fine = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.FINE, msg, opt_exception); + } +}; - var condition = options.condition ? - options.condition : ol.events.condition.shiftKeyOnly; - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 200; +/** + * Logs a message at the Logger.Level.FINER level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. + */ +goog.debug.Logger.prototype.finer = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.FINER, msg, opt_exception); + } +}; - goog.base(this, { - condition: condition, - className: options.className || 'ol-dragzoom' - }); +/** + * Logs a message at the Logger.Level.FINEST level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. + */ +goog.debug.Logger.prototype.finest = function(msg, opt_exception) { + if (goog.debug.LOGGING_ENABLED) { + this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception); + } }; -goog.inherits(ol.interaction.DragZoom, ol.interaction.DragBox); /** - * @inheritDoc + * Logs a LogRecord. If the logger is currently enabled for the + * given message level then the given message is forwarded to all the + * registered output Handler objects. + * @param {goog.debug.LogRecord} logRecord A log record to log. */ -ol.interaction.DragZoom.prototype.onBoxEnd = function() { - var map = this.getMap(); +goog.debug.Logger.prototype.logRecord = function(logRecord) { + if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) { + this.doLogRecord_(logRecord); + } +}; - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - var size = map.getSize(); - goog.asserts.assert(size !== undefined, 'size should be defined'); +/** + * Logs a LogRecord. + * @param {goog.debug.LogRecord} logRecord A log record to log. + * @private + */ +goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) { + goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage()); + if (goog.debug.Logger.ENABLE_HIERARCHY) { + var target = this; + while (target) { + target.callPublish_(logRecord); + target = target.getParent(); + } + } else { + for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++]; ) { + handler(logRecord); + } + } +}; - var extent = this.getGeometry().getExtent(); - var resolution = view.constrainResolution( - view.getResolutionForExtent(extent, size)); +/** + * Calls the handlers for publish. + * @param {goog.debug.LogRecord} logRecord The log record to publish. + * @private + */ +goog.debug.Logger.prototype.callPublish_ = function(logRecord) { + if (this.handlers_) { + for (var i = 0, handler; handler = this.handlers_[i]; i++) { + handler(logRecord); + } + } +}; - var currentResolution = view.getResolution(); - goog.asserts.assert(currentResolution !== undefined, 'res should be defined'); - var currentCenter = view.getCenter(); - goog.asserts.assert(currentCenter !== undefined, 'center should be defined'); +/** + * Sets the parent of this logger. This is used for setting up the logger tree. + * @param {goog.debug.Logger} parent The parent logger. + * @private + */ +goog.debug.Logger.prototype.setParent_ = function(parent) { + this.parent_ = parent; +}; - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: this.duration_, - easing: ol.easing.easeOut - })); - map.beforeRender(ol.animation.pan({ - source: currentCenter, - duration: this.duration_, - easing: ol.easing.easeOut - })); - view.setCenter(ol.extent.getCenter(extent)); - view.setResolution(resolution); +/** + * Adds a child to this logger. This is used for setting up the logger tree. + * @param {string} name The leaf name of the child. + * @param {goog.debug.Logger} logger The child logger. + * @private + */ +goog.debug.Logger.prototype.addChild_ = function(name, logger) { + this.getChildren()[name] = logger; }; -goog.provide('ol.interaction.KeyboardPan'); - -goog.require('goog.asserts'); -goog.require('goog.events.KeyCodes'); -goog.require('goog.events.KeyHandler.EventType'); -goog.require('goog.functions'); -goog.require('ol'); -goog.require('ol.coordinate'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); +/** + * There is a single global LogManager object that is used to maintain a set of + * shared state about Loggers and log services. This is loosely based on the + * java class java.util.logging.LogManager. + * @const + */ +goog.debug.LogManager = {}; /** - * @classdesc - * Allows the user to pan the map using keyboard arrows. - * Note that, although this interaction is by default included in maps, - * the keys can only be used when browser focus is on the element to which - * the keyboard events are attached. By default, this is the map div, - * though you can change this with the `keyboardEventTarget` in - * {@link ol.Map}. `document` never loses focus but, for any other element, - * focus will have to be on, and returned to, this element if the keys are to - * function. - * See also {@link ol.interaction.KeyboardZoom}. + * Map of logger names to logger objects. * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.KeyboardPanOptions=} opt_options Options. - * @api stable + * @type {!Object<string, !goog.debug.Logger>} + * @private */ -ol.interaction.KeyboardPan = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.KeyboardPan.handleEvent - }); - - var options = opt_options || {}; +goog.debug.LogManager.loggers_ = {}; - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition !== undefined ? - options.condition : - goog.functions.and(ol.events.condition.noModifierKeys, - ol.events.condition.targetNotEditable); - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 100; +/** + * The root logger which is the root of the logger tree. + * @type {goog.debug.Logger} + * @private + */ +goog.debug.LogManager.rootLogger_ = null; - /** - * @private - * @type {number} - */ - this.pixelDelta_ = options.pixelDelta !== undefined ? - options.pixelDelta : 128; +/** + * Initializes the LogManager if not already initialized. + */ +goog.debug.LogManager.initialize = function() { + if (!goog.debug.LogManager.rootLogger_) { + goog.debug.LogManager.rootLogger_ = new goog.debug.Logger( + goog.debug.Logger.ROOT_LOGGER_NAME); + goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] = + goog.debug.LogManager.rootLogger_; + goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG); + } }; -goog.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction); /** - * Handles the {@link ol.MapBrowserEvent map browser event} if it was a - * `KeyEvent`, and decides the direction to pan to (if an arrow key was - * pressed). - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.KeyboardPan} - * @api + * Returns all the loggers. + * @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger + * objects. */ -ol.interaction.KeyboardPan.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) { - var keyEvent = /** @type {goog.events.KeyEvent} */ - (mapBrowserEvent.browserEvent); - var keyCode = keyEvent.keyCode; - if (this.condition_(mapBrowserEvent) && - (keyCode == goog.events.KeyCodes.DOWN || - keyCode == goog.events.KeyCodes.LEFT || - keyCode == goog.events.KeyCodes.RIGHT || - keyCode == goog.events.KeyCodes.UP)) { - var map = mapBrowserEvent.map; - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - var mapUnitsDelta = view.getResolution() * this.pixelDelta_; - var deltaX = 0, deltaY = 0; - if (keyCode == goog.events.KeyCodes.DOWN) { - deltaY = -mapUnitsDelta; - } else if (keyCode == goog.events.KeyCodes.LEFT) { - deltaX = -mapUnitsDelta; - } else if (keyCode == goog.events.KeyCodes.RIGHT) { - deltaX = mapUnitsDelta; - } else { - deltaY = mapUnitsDelta; - } - var delta = [deltaX, deltaY]; - ol.coordinate.rotate(delta, view.getRotation()); - ol.interaction.Interaction.pan(map, view, delta, this.duration_); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - } - return !stopEvent; +goog.debug.LogManager.getLoggers = function() { + return goog.debug.LogManager.loggers_; }; -goog.provide('ol.interaction.KeyboardZoom'); - -goog.require('goog.asserts'); -goog.require('goog.events.KeyHandler.EventType'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); +/** + * Returns the root of the logger tree namespace, the logger with the empty + * string as its name. + * + * @return {!goog.debug.Logger} The root logger. + */ +goog.debug.LogManager.getRoot = function() { + goog.debug.LogManager.initialize(); + return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_); +}; /** - * @classdesc - * Allows the user to zoom the map using keyboard + and -. - * Note that, although this interaction is by default included in maps, - * the keys can only be used when browser focus is on the element to which - * the keyboard events are attached. By default, this is the map div, - * though you can change this with the `keyboardEventTarget` in - * {@link ol.Map}. `document` never loses focus but, for any other element, - * focus will have to be on, and returned to, this element if the keys are to - * function. - * See also {@link ol.interaction.KeyboardPan}. + * Finds a named logger. * - * @constructor - * @param {olx.interaction.KeyboardZoomOptions=} opt_options Options. - * @extends {ol.interaction.Interaction} - * @api stable + * @param {string} name A name for the logger. This should be a dot-separated + * name and should normally be based on the package name or class name of the + * subsystem, such as goog.net.BrowserChannel. + * @return {!goog.debug.Logger} The named logger. */ -ol.interaction.KeyboardZoom = function(opt_options) { +goog.debug.LogManager.getLogger = function(name) { + goog.debug.LogManager.initialize(); + var ret = goog.debug.LogManager.loggers_[name]; + return ret || goog.debug.LogManager.createLogger_(name); +}; - goog.base(this, { - handleEvent: ol.interaction.KeyboardZoom.handleEvent - }); - var options = opt_options ? opt_options : {}; +/** + * Creates a function that can be passed to goog.debug.catchErrors. The function + * will log all reported errors using the given logger. + * @param {goog.debug.Logger=} opt_logger The logger to log the errors to. + * Defaults to the root logger. + * @return {function(Object)} The created function. + */ +goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) { + return function(info) { + var logger = opt_logger || goog.debug.LogManager.getRoot(); + logger.severe('Error: ' + info.message + ' (' + info.fileName + + ' @ Line: ' + info.line + ')'); + }; +}; - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? options.condition : - ol.events.condition.targetNotEditable; - /** - * @private - * @type {number} - */ - this.delta_ = options.delta ? options.delta : 1; +/** + * Creates the named logger. Will also create the parents of the named logger + * if they don't yet exist. + * @param {string} name The name of the logger. + * @return {!goog.debug.Logger} The named logger. + * @private + */ +goog.debug.LogManager.createLogger_ = function(name) { + // find parent logger + var logger = new goog.debug.Logger(name); + if (goog.debug.Logger.ENABLE_HIERARCHY) { + var lastDotIndex = name.lastIndexOf('.'); + var parentName = name.substr(0, lastDotIndex); + var leafName = name.substr(lastDotIndex + 1); + var parentLogger = goog.debug.LogManager.getLogger(parentName); - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 100; + // tell the parent about the child and the child about the parent + parentLogger.addChild_(leafName, logger); + logger.setParent_(parentLogger); + } + goog.debug.LogManager.loggers_[name] = logger; + return logger; }; -goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction); +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Handles the {@link ol.MapBrowserEvent map browser event} if it was a - * `KeyEvent`, and decides whether to zoom in or out (depending on whether the - * key pressed was '+' or '-'). - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.KeyboardZoom} - * @api + * @fileoverview Definition the goog.debug.RelativeTimeProvider class. + * */ -ol.interaction.KeyboardZoom.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) { - var keyEvent = /** @type {goog.events.KeyEvent} */ - (mapBrowserEvent.browserEvent); - var charCode = keyEvent.charCode; - if (this.condition_(mapBrowserEvent) && - (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) { - var map = mapBrowserEvent.map; - var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_; - map.render(); - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - ol.interaction.Interaction.zoomByDelta( - map, view, delta, undefined, this.duration_); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - } - return !stopEvent; -}; - -goog.provide('ol.interaction.MouseWheelZoom'); -goog.require('goog.asserts'); -goog.require('goog.events.MouseWheelEvent'); -goog.require('goog.events.MouseWheelHandler.EventType'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.math'); +goog.provide('goog.debug.RelativeTimeProvider'); /** - * @classdesc - * Allows the user to zoom the map by scrolling the mouse wheel. + * A simple object to keep track of a timestamp considered the start of + * something. The main use is for the logger system to maintain a start time + * that is occasionally reset. For example, in Gmail, we reset this relative + * time at the start of a user action so that timings are offset from the + * beginning of the action. This class also provides a singleton as the default + * behavior for most use cases is to share the same start time. * * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.MouseWheelZoomOptions=} opt_options Options. - * @api stable + * @final */ -ol.interaction.MouseWheelZoom = function(opt_options) { - - goog.base(this, { - handleEvent: ol.interaction.MouseWheelZoom.handleEvent - }); - - var options = opt_options || {}; - - /** - * @private - * @type {number} - */ - this.delta_ = 0; - +goog.debug.RelativeTimeProvider = function() { /** - * @private + * The start time. * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; - - /** - * @private - * @type {boolean} - */ - this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true; - - /** * @private - * @type {?ol.Coordinate} - */ - this.lastAnchor_ = null; - - /** - * @private - * @type {number|undefined} - */ - this.startTime_ = undefined; - - /** - * @private - * @type {number|undefined} */ - this.timeoutId_ = undefined; - + this.relativeTimeStart_ = goog.now(); }; -goog.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction); /** - * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a - * mousewheel-event) and eventually zooms the map. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.MouseWheelZoom} - * @api + * Default instance. + * @type {goog.debug.RelativeTimeProvider} + * @private */ -ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) { - var stopEvent = false; - if (mapBrowserEvent.type == - goog.events.MouseWheelHandler.EventType.MOUSEWHEEL) { - var map = mapBrowserEvent.map; - var mouseWheelEvent = mapBrowserEvent.browserEvent; - goog.asserts.assertInstanceof(mouseWheelEvent, goog.events.MouseWheelEvent, - 'mouseWheelEvent should be of type MouseWheelEvent'); - - if (this.useAnchor_) { - this.lastAnchor_ = mapBrowserEvent.coordinate; - } - - this.delta_ += mouseWheelEvent.deltaY; +goog.debug.RelativeTimeProvider.defaultInstance_ = + new goog.debug.RelativeTimeProvider(); - if (this.startTime_ === undefined) { - this.startTime_ = Date.now(); - } - var duration = ol.MOUSEWHEELZOOM_TIMEOUT_DURATION; - var timeLeft = Math.max(duration - (Date.now() - this.startTime_), 0); +/** + * Sets the start time to the specified time. + * @param {number} timeStamp The start time. + */ +goog.debug.RelativeTimeProvider.prototype.set = function(timeStamp) { + this.relativeTimeStart_ = timeStamp; +}; - goog.global.clearTimeout(this.timeoutId_); - this.timeoutId_ = goog.global.setTimeout( - goog.bind(this.doZoom_, this, map), timeLeft); - mapBrowserEvent.preventDefault(); - stopEvent = true; - } - return !stopEvent; +/** + * Resets the start time to now. + */ +goog.debug.RelativeTimeProvider.prototype.reset = function() { + this.set(goog.now()); }; /** - * @private - * @param {ol.Map} map Map. + * @return {number} The start time. */ -ol.interaction.MouseWheelZoom.prototype.doZoom_ = function(map) { - var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA; - var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta); - - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); +goog.debug.RelativeTimeProvider.prototype.get = function() { + return this.relativeTimeStart_; +}; - map.render(); - ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_, - this.duration_); - this.delta_ = 0; - this.lastAnchor_ = null; - this.startTime_ = undefined; - this.timeoutId_ = undefined; +/** + * @return {goog.debug.RelativeTimeProvider} The default instance. + */ +goog.debug.RelativeTimeProvider.getDefaultInstance = function() { + return goog.debug.RelativeTimeProvider.defaultInstance_; }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Enable or disable using the mouse's location as an anchor when zooming - * @param {boolean} useAnchor true to zoom to the mouse's location, false - * to zoom to the center of the map - * @api + * @fileoverview Definition of various formatters for logging. Please minimize + * dependencies this file has on other closure classes as any dependency it + * takes won't be able to use the logging infrastructure. + * */ -ol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) { - this.useAnchor_ = useAnchor; - if (!useAnchor) { - this.lastAnchor_ = null; - } -}; -goog.provide('ol.interaction.PinchRotate'); +goog.provide('goog.debug.Formatter'); +goog.provide('goog.debug.HtmlFormatter'); +goog.provide('goog.debug.TextFormatter'); -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.ViewHint'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); +goog.require('goog.debug'); +goog.require('goog.debug.Logger'); +goog.require('goog.debug.RelativeTimeProvider'); +goog.require('goog.html.SafeHtml'); /** - * @classdesc - * Allows the user to rotate the map by twisting with two fingers - * on a touch screen. + * Base class for Formatters. A Formatter is used to format a LogRecord into + * something that can be displayed to the user. * + * @param {string=} opt_prefix The prefix to place before text records. * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.PinchRotateOptions=} opt_options Options. - * @api stable */ -ol.interaction.PinchRotate = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_, - handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_, - handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_ - }); - - var options = opt_options || {}; +goog.debug.Formatter = function(opt_prefix) { + this.prefix_ = opt_prefix || ''; /** + * A provider that returns the relative start time. + * @type {goog.debug.RelativeTimeProvider} * @private - * @type {ol.Coordinate} */ - this.anchor_ = null; + this.startTimeProvider_ = + goog.debug.RelativeTimeProvider.getDefaultInstance(); +}; - /** - * @private - * @type {number|undefined} - */ - this.lastAngle_ = undefined; - /** - * @private - * @type {boolean} - */ - this.rotating_ = false; +/** + * Whether to append newlines to the end of formatted log records. + * @type {boolean} + */ +goog.debug.Formatter.prototype.appendNewline = true; - /** - * @private - * @type {number} - */ - this.rotationDelta_ = 0.0; - /** - * @private - * @type {number} - */ - this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3; +/** + * Whether to show absolute time in the DebugWindow. + * @type {boolean} + */ +goog.debug.Formatter.prototype.showAbsoluteTime = true; - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 250; -}; -goog.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer); +/** + * Whether to show relative time in the DebugWindow. + * @type {boolean} + */ +goog.debug.Formatter.prototype.showRelativeTime = true; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.PinchRotate} - * @private + * Whether to show the logger name in the DebugWindow. + * @type {boolean} */ -ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) { - goog.asserts.assert(this.targetPointers.length >= 2, - 'length of this.targetPointers should be greater than or equal to 2'); - var rotationDelta = 0.0; +goog.debug.Formatter.prototype.showLoggerName = true; - var touch0 = this.targetPointers[0]; - var touch1 = this.targetPointers[1]; - // angle between touches - var angle = Math.atan2( - touch1.clientY - touch0.clientY, - touch1.clientX - touch0.clientX); +/** + * Whether to show the logger exception text. + * @type {boolean} + */ +goog.debug.Formatter.prototype.showExceptionText = false; - if (this.lastAngle_ !== undefined) { - var delta = angle - this.lastAngle_; - this.rotationDelta_ += delta; - if (!this.rotating_ && - Math.abs(this.rotationDelta_) > this.threshold_) { - this.rotating_ = true; - } - rotationDelta = delta; - } - this.lastAngle_ = angle; - var map = mapBrowserEvent.map; +/** + * Whether to show the severity level. + * @type {boolean} + */ +goog.debug.Formatter.prototype.showSeverityLevel = false; - // rotate anchor point. - // FIXME: should be the intersection point between the lines: - // touch0,touch1 and previousTouch0,previousTouch1 - var viewportPosition = goog.style.getClientPosition(map.getViewport()); - var centroid = - ol.interaction.Pointer.centroid(this.targetPointers); - centroid[0] -= viewportPosition.x; - centroid[1] -= viewportPosition.y; - this.anchor_ = map.getCoordinateFromPixel(centroid); - // rotate - if (this.rotating_) { - var view = map.getView(); - var rotation = view.getRotation(); - map.render(); - ol.interaction.Interaction.rotateWithoutConstraints(map, view, - rotation + rotationDelta, this.anchor_); - } -}; +/** + * Formats a record. + * @param {goog.debug.LogRecord} logRecord the logRecord to format. + * @return {string} The formatted string. + */ +goog.debug.Formatter.prototype.formatRecord = goog.abstractMethod; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.PinchRotate} - * @private + * Formats a record as SafeHtml. + * @param {goog.debug.LogRecord} logRecord the logRecord to format. + * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. */ -ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length < 2) { - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - if (this.rotating_) { - var rotation = view.getRotation(); - ol.interaction.Interaction.rotate( - map, view, rotation, this.anchor_, this.duration_); - } - return false; - } else { - return true; - } -}; +goog.debug.Formatter.prototype.formatRecordAsHtml = goog.abstractMethod; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.PinchRotate} - * @private + * Sets the start time provider. By default, this is the default instance + * but can be changed. + * @param {goog.debug.RelativeTimeProvider} provider The provider to use. */ -ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length >= 2) { - var map = mapBrowserEvent.map; - this.anchor_ = null; - this.lastAngle_ = undefined; - this.rotating_ = false; - this.rotationDelta_ = 0.0; - if (!this.handlingDownUpSequence) { - map.getView().setHint(ol.ViewHint.INTERACTING, 1); - } - map.render(); - return true; - } else { - return false; - } +goog.debug.Formatter.prototype.setStartTimeProvider = function(provider) { + this.startTimeProvider_ = provider; }; /** - * @inheritDoc + * Returns the start time provider. By default, this is the default instance + * but can be changed. + * @return {goog.debug.RelativeTimeProvider} The start time provider. */ -ol.interaction.PinchRotate.prototype.shouldStopEvent = goog.functions.FALSE; - -goog.provide('ol.interaction.PinchZoom'); +goog.debug.Formatter.prototype.getStartTimeProvider = function() { + return this.startTimeProvider_; +}; -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.ViewHint'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); +/** + * Resets the start relative time. + */ +goog.debug.Formatter.prototype.resetRelativeTimeStart = function() { + this.startTimeProvider_.reset(); +}; /** - * @classdesc - * Allows the user to zoom the map by pinching with two fingers - * on a touch screen. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.PinchZoomOptions=} opt_options Options. - * @api stable + * Returns a string for the time/date of the LogRecord. + * @param {goog.debug.LogRecord} logRecord The record to get a time stamp for. + * @return {string} A string representation of the time/date of the LogRecord. + * @private */ -ol.interaction.PinchZoom = function(opt_options) { - - goog.base(this, { - handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_, - handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_, - handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_ - }); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {ol.Coordinate} - */ - this.anchor_ = null; - - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 400; - - /** - * @private - * @type {number|undefined} - */ - this.lastDistance_ = undefined; - - /** - * @private - * @type {number} - */ - this.lastScaleDelta_ = 1; - -}; -goog.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer); +goog.debug.Formatter.getDateTimeStamp_ = function(logRecord) { + var time = new Date(logRecord.getMillis()); + return goog.debug.Formatter.getTwoDigitString_((time.getFullYear() - 2000)) + + goog.debug.Formatter.getTwoDigitString_((time.getMonth() + 1)) + + goog.debug.Formatter.getTwoDigitString_(time.getDate()) + ' ' + + goog.debug.Formatter.getTwoDigitString_(time.getHours()) + ':' + + goog.debug.Formatter.getTwoDigitString_(time.getMinutes()) + ':' + + goog.debug.Formatter.getTwoDigitString_(time.getSeconds()) + '.' + + goog.debug.Formatter.getTwoDigitString_( + Math.floor(time.getMilliseconds() / 10)); +}; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.PinchZoom} + * Returns the number as a two-digit string, meaning it prepends a 0 if the + * number if less than 10. + * @param {number} n The number to format. + * @return {string} A two-digit string representation of {@code n}. * @private */ -ol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) { - goog.asserts.assert(this.targetPointers.length >= 2, - 'length of this.targetPointers should be 2 or more'); - var scaleDelta = 1.0; - - var touch0 = this.targetPointers[0]; - var touch1 = this.targetPointers[1]; - var dx = touch0.clientX - touch1.clientX; - var dy = touch0.clientY - touch1.clientY; - - // distance between touches - var distance = Math.sqrt(dx * dx + dy * dy); - - if (this.lastDistance_ !== undefined) { - scaleDelta = this.lastDistance_ / distance; - } - this.lastDistance_ = distance; - if (scaleDelta != 1.0) { - this.lastScaleDelta_ = scaleDelta; +goog.debug.Formatter.getTwoDigitString_ = function(n) { + if (n < 10) { + return '0' + n; } - - var map = mapBrowserEvent.map; - var view = map.getView(); - var resolution = view.getResolution(); - - // scale anchor point. - var viewportPosition = goog.style.getClientPosition(map.getViewport()); - var centroid = - ol.interaction.Pointer.centroid(this.targetPointers); - centroid[0] -= viewportPosition.x; - centroid[1] -= viewportPosition.y; - this.anchor_ = map.getCoordinateFromPixel(centroid); - - // scale, bypass the resolution constraint - map.render(); - ol.interaction.Interaction.zoomWithoutConstraints( - map, view, resolution * scaleDelta, this.anchor_); - + return String(n); }; /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.PinchZoom} + * Returns a string for the number of seconds relative to the start time. + * Prepads with spaces so that anything less than 1000 seconds takes up the + * same number of characters for better formatting. + * @param {goog.debug.LogRecord} logRecord The log to compare time to. + * @param {number} relativeTimeStart The start time to compare to. + * @return {string} The number of seconds of the LogRecord relative to the + * start time. * @private */ -ol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length < 2) { - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - var resolution = view.getResolution(); - // Zoom to final resolution, with an animation, and provide a - // direction not to zoom out/in if user was pinching in/out. - // Direction is > 0 if pinching out, and < 0 if pinching in. - var direction = this.lastScaleDelta_ - 1; - ol.interaction.Interaction.zoom(map, view, resolution, - this.anchor_, this.duration_, direction); - return false; +goog.debug.Formatter.getRelativeTime_ = function(logRecord, + relativeTimeStart) { + var ms = logRecord.getMillis() - relativeTimeStart; + var sec = ms / 1000; + var str = sec.toFixed(3); + + var spacesToPrepend = 0; + if (sec < 1) { + spacesToPrepend = 2; } else { - return true; + while (sec < 100) { + spacesToPrepend++; + sec *= 10; + } + } + while (spacesToPrepend-- > 0) { + str = ' ' + str; } + return str; }; + /** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.PinchZoom} - * @private + * Formatter that returns formatted html. See formatRecord for the classes + * it uses for various types of formatted output. + * + * @param {string=} opt_prefix The prefix to place before text records. + * @constructor + * @extends {goog.debug.Formatter} */ -ol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) { - if (this.targetPointers.length >= 2) { - var map = mapBrowserEvent.map; - this.anchor_ = null; - this.lastDistance_ = undefined; - this.lastScaleDelta_ = 1; - if (!this.handlingDownUpSequence) { - map.getView().setHint(ol.ViewHint.INTERACTING, 1); - } - map.render(); - return true; - } else { - return false; - } +goog.debug.HtmlFormatter = function(opt_prefix) { + goog.debug.Formatter.call(this, opt_prefix); }; +goog.inherits(goog.debug.HtmlFormatter, goog.debug.Formatter); /** - * @inheritDoc + * Whether to show the logger exception text + * @type {boolean} + * @override */ -ol.interaction.PinchZoom.prototype.shouldStopEvent = goog.functions.FALSE; - -goog.provide('ol.interaction'); - -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.Kinetic'); -goog.require('ol.interaction.DoubleClickZoom'); -goog.require('ol.interaction.DragPan'); -goog.require('ol.interaction.DragRotate'); -goog.require('ol.interaction.DragZoom'); -goog.require('ol.interaction.KeyboardPan'); -goog.require('ol.interaction.KeyboardZoom'); -goog.require('ol.interaction.MouseWheelZoom'); -goog.require('ol.interaction.PinchRotate'); -goog.require('ol.interaction.PinchZoom'); +goog.debug.HtmlFormatter.prototype.showExceptionText = true; /** - * Set of interactions included in maps by default. Specific interactions can be - * excluded by setting the appropriate option to false in the constructor - * options, but the order of the interactions is fixed. If you want to specify - * a different order for interactions, you will need to create your own - * {@link ol.interaction.Interaction} instances and insert them into a - * {@link ol.Collection} in the order you want before creating your - * {@link ol.Map} instance. The default set of interactions, in sequence, is: - * * {@link ol.interaction.DragRotate} - * * {@link ol.interaction.DoubleClickZoom} - * * {@link ol.interaction.DragPan} - * * {@link ol.interaction.PinchRotate} - * * {@link ol.interaction.PinchZoom} - * * {@link ol.interaction.KeyboardPan} - * * {@link ol.interaction.KeyboardZoom} - * * {@link ol.interaction.MouseWheelZoom} - * * {@link ol.interaction.DragZoom} - * - * Note that DragZoom renders a box as a vector polygon, so this interaction - * should be excluded if you want a build with no vector support. - * - * @param {olx.interaction.DefaultsOptions=} opt_options Defaults options. - * @return {ol.Collection.<ol.interaction.Interaction>} A collection of - * interactions to be used with the ol.Map constructor's interactions option. - * @api stable + * Formats a record + * @param {goog.debug.LogRecord} logRecord the logRecord to format. + * @return {string} The formatted string as html. + * @override */ -ol.interaction.defaults = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - var interactions = new ol.Collection(); +goog.debug.HtmlFormatter.prototype.formatRecord = function(logRecord) { + if (!logRecord) { + return ''; + } + // OK not to use goog.html.SafeHtml.unwrap() here. + return this.formatRecordAsHtml(logRecord).getTypedStringValue(); +}; - var kinetic = new ol.Kinetic(-0.005, 0.05, 100); - var altShiftDragRotate = options.altShiftDragRotate !== undefined ? - options.altShiftDragRotate : true; - if (altShiftDragRotate) { - interactions.push(new ol.interaction.DragRotate()); +/** + * Formats a record. + * @param {goog.debug.LogRecord} logRecord the logRecord to format. + * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. + * @override + */ +goog.debug.HtmlFormatter.prototype.formatRecordAsHtml = function(logRecord) { + if (!logRecord) { + return goog.html.SafeHtml.EMPTY; } - var doubleClickZoom = options.doubleClickZoom !== undefined ? - options.doubleClickZoom : true; - if (doubleClickZoom) { - interactions.push(new ol.interaction.DoubleClickZoom({ - delta: options.zoomDelta, - duration: options.zoomDuration - })); + var className; + switch (logRecord.getLevel().value) { + case goog.debug.Logger.Level.SHOUT.value: + className = 'dbg-sh'; + break; + case goog.debug.Logger.Level.SEVERE.value: + className = 'dbg-sev'; + break; + case goog.debug.Logger.Level.WARNING.value: + className = 'dbg-w'; + break; + case goog.debug.Logger.Level.INFO.value: + className = 'dbg-i'; + break; + case goog.debug.Logger.Level.FINE.value: + default: + className = 'dbg-f'; + break; } - var dragPan = options.dragPan !== undefined ? options.dragPan : true; - if (dragPan) { - interactions.push(new ol.interaction.DragPan({ - kinetic: kinetic - })); + // HTML for user defined prefix, time, logger name, and severity. + var sb = []; + sb.push(this.prefix_, ' '); + if (this.showAbsoluteTime) { + sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] '); } - - var pinchRotate = options.pinchRotate !== undefined ? options.pinchRotate : - true; - if (pinchRotate) { - interactions.push(new ol.interaction.PinchRotate()); + if (this.showRelativeTime) { + sb.push('[', + goog.debug.Formatter.getRelativeTime_( + logRecord, this.startTimeProvider_.get()), + 's] '); } - - var pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true; - if (pinchZoom) { - interactions.push(new ol.interaction.PinchZoom({ - duration: options.zoomDuration - })); + if (this.showLoggerName) { + sb.push('[', logRecord.getLoggerName(), '] '); } - - var keyboard = options.keyboard !== undefined ? options.keyboard : true; - if (keyboard) { - interactions.push(new ol.interaction.KeyboardPan()); - interactions.push(new ol.interaction.KeyboardZoom({ - delta: options.zoomDelta, - duration: options.zoomDuration - })); + if (this.showSeverityLevel) { + sb.push('[', logRecord.getLevel().name, '] '); } + var fullPrefixHtml = + goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(sb.join('')); - var mouseWheelZoom = options.mouseWheelZoom !== undefined ? - options.mouseWheelZoom : true; - if (mouseWheelZoom) { - interactions.push(new ol.interaction.MouseWheelZoom({ - duration: options.zoomDuration - })); + // HTML for exception text and log record. + var exceptionHtml = goog.html.SafeHtml.EMPTY; + if (this.showExceptionText && logRecord.getException()) { + exceptionHtml = goog.html.SafeHtml.concat( + goog.html.SafeHtml.create('br'), + goog.debug.exposeExceptionAsHtml(logRecord.getException())); } + var logRecordHtml = goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( + logRecord.getMessage()); + var recordAndExceptionHtml = goog.html.SafeHtml.create( + 'span', + {'class': className}, + goog.html.SafeHtml.concat(logRecordHtml, exceptionHtml)); - var shiftDragZoom = options.shiftDragZoom !== undefined ? - options.shiftDragZoom : true; - if (shiftDragZoom) { - interactions.push(new ol.interaction.DragZoom({ - duration: options.zoomDuration - })); + + // Combine both pieces of HTML and, if needed, append a final newline. + var html; + if (this.appendNewline) { + html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml, + goog.html.SafeHtml.create('br')); + } else { + html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml); } + return html; +}; - return interactions; + +/** + * Formatter that returns formatted plain text + * + * @param {string=} opt_prefix The prefix to place before text records. + * @constructor + * @extends {goog.debug.Formatter} + * @final + */ +goog.debug.TextFormatter = function(opt_prefix) { + goog.debug.Formatter.call(this, opt_prefix); }; +goog.inherits(goog.debug.TextFormatter, goog.debug.Formatter); -goog.provide('ol.layer.Group'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEvent'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Object'); -goog.require('ol.ObjectEventType'); -goog.require('ol.extent'); -goog.require('ol.layer.Base'); -goog.require('ol.source.State'); +/** + * Formats a record as text + * @param {goog.debug.LogRecord} logRecord the logRecord to format. + * @return {string} The formatted string. + * @override + */ +goog.debug.TextFormatter.prototype.formatRecord = function(logRecord) { + var sb = []; + sb.push(this.prefix_, ' '); + if (this.showAbsoluteTime) { + sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] '); + } + if (this.showRelativeTime) { + sb.push('[', goog.debug.Formatter.getRelativeTime_(logRecord, + this.startTimeProvider_.get()), 's] '); + } + + if (this.showLoggerName) { + sb.push('[', logRecord.getLoggerName(), '] '); + } + if (this.showSeverityLevel) { + sb.push('[', logRecord.getLevel().name, '] '); + } + sb.push(logRecord.getMessage()); + if (this.showExceptionText) { + var exception = logRecord.getException(); + if (exception) { + var exceptionText = exception instanceof Error ? + exception.message : + exception.toString(); + sb.push('\n', exceptionText); + } + } + if (this.appendNewline) { + sb.push('\n'); + } + return sb.join(''); +}; /** - * @enum {string} + * Formats a record as text + * @param {goog.debug.LogRecord} logRecord the logRecord to format. + * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. This is + * just an HTML-escaped version of the text obtained from formatRecord(). + * @override */ -ol.layer.GroupProperty = { - LAYERS: 'layers' +goog.debug.TextFormatter.prototype.formatRecordAsHtml = function(logRecord) { + return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces( + goog.debug.TextFormatter.prototype.formatRecord(logRecord)); }; - +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @classdesc - * A {@link ol.Collection} of layers that are handled together. + * @fileoverview Simple logger that logs to the window console if available. * - * A generic `change` event is triggered when the group/Collection changes. + * Has an autoInstall option which can be put into initialization code, which + * will start logging if "Debug=true" is in document.location.href * - * @constructor - * @extends {ol.layer.Base} - * @param {olx.layer.GroupOptions=} opt_options Layer options. - * @api stable */ -ol.layer.Group = function(opt_options) { - var options = opt_options || {}; - var baseOptions = /** @type {olx.layer.GroupOptions} */ - (goog.object.clone(options)); - delete baseOptions.layers; +goog.provide('goog.debug.Console'); - var layers = options.layers; +goog.require('goog.debug.LogManager'); +goog.require('goog.debug.Logger'); +goog.require('goog.debug.TextFormatter'); - goog.base(this, baseOptions); + + +/** + * Create and install a log handler that logs to window.console if available + * @constructor + */ +goog.debug.Console = function() { + this.publishHandler_ = goog.bind(this.addLogRecord, this); /** + * Formatter for formatted output. + * @type {!goog.debug.TextFormatter} * @private - * @type {Array.<goog.events.Key>} */ - this.layersListenerKeys_ = []; + this.formatter_ = new goog.debug.TextFormatter(); + this.formatter_.showAbsoluteTime = false; + this.formatter_.showExceptionText = false; + // The console logging methods automatically append a newline. + this.formatter_.appendNewline = false; + + this.isCapturing_ = false; + this.logBuffer_ = ''; /** + * Loggers that we shouldn't output. + * @type {!Object<boolean>} * @private - * @type {Object.<string, Array.<goog.events.Key>>} */ - this.listenerKeys_ = {}; - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.layer.GroupProperty.LAYERS), - this.handleLayersChanged_, false, this); - - if (layers) { - if (goog.isArray(layers)) { - layers = new ol.Collection(layers.slice()); - } else { - goog.asserts.assertInstanceof(layers, ol.Collection, - 'layers should be an ol.Collection'); - layers = layers; - } - } else { - layers = new ol.Collection(); - } + this.filteredLoggers_ = {}; +}; - this.setLayers(layers); +/** + * Returns the text formatter used by this console + * @return {!goog.debug.TextFormatter} The text formatter. + */ +goog.debug.Console.prototype.getFormatter = function() { + return this.formatter_; }; -goog.inherits(ol.layer.Group, ol.layer.Base); /** - * @private + * Sets whether we are currently capturing logger output. + * @param {boolean} capturing Whether to capture logger output. */ -ol.layer.Group.prototype.handleLayerChange_ = function() { - if (this.getVisible()) { - this.changed(); +goog.debug.Console.prototype.setCapturing = function(capturing) { + if (capturing == this.isCapturing_) { + return; + } + + // attach or detach handler from the root logger + var rootLogger = goog.debug.LogManager.getRoot(); + if (capturing) { + rootLogger.addHandler(this.publishHandler_); + } else { + rootLogger.removeHandler(this.publishHandler_); + this.logBuffer = ''; } + this.isCapturing_ = capturing; }; /** - * @param {goog.events.Event} event Event. - * @private + * Adds a log record. + * @param {goog.debug.LogRecord} logRecord The log entry. */ -ol.layer.Group.prototype.handleLayersChanged_ = function(event) { - this.layersListenerKeys_.forEach(goog.events.unlistenByKey); - this.layersListenerKeys_.length = 0; +goog.debug.Console.prototype.addLogRecord = function(logRecord) { - var layers = this.getLayers(); - this.layersListenerKeys_.push( - goog.events.listen(layers, ol.CollectionEventType.ADD, - this.handleLayersAdd_, false, this), - goog.events.listen(layers, ol.CollectionEventType.REMOVE, - this.handleLayersRemove_, false, this)); + // Check to see if the log record is filtered or not. + if (this.filteredLoggers_[logRecord.getLoggerName()]) { + return; + } - goog.object.forEach(this.listenerKeys_, function(keys) { - keys.forEach(goog.events.unlistenByKey); - }); - goog.object.clear(this.listenerKeys_); - - var layersArray = layers.getArray(); - var i, ii, layer; - for (i = 0, ii = layersArray.length; i < ii; i++) { - layer = layersArray[i]; - this.listenerKeys_[goog.getUid(layer).toString()] = [ - goog.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE, - this.handleLayerChange_, false, this), - goog.events.listen(layer, goog.events.EventType.CHANGE, - this.handleLayerChange_, false, this) - ]; + var record = this.formatter_.formatRecord(logRecord); + var console = goog.debug.Console.console_; + if (console) { + switch (logRecord.getLevel()) { + case goog.debug.Logger.Level.SHOUT: + goog.debug.Console.logToConsole_(console, 'info', record); + break; + case goog.debug.Logger.Level.SEVERE: + goog.debug.Console.logToConsole_(console, 'error', record); + break; + case goog.debug.Logger.Level.WARNING: + goog.debug.Console.logToConsole_(console, 'warn', record); + break; + default: + goog.debug.Console.logToConsole_(console, 'debug', record); + break; + } + } else { + this.logBuffer_ += record; } - - this.changed(); }; /** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @private + * Adds a logger name to be filtered. + * @param {string} loggerName the logger name to add. */ -ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) { - var layer = /** @type {ol.layer.Base} */ (collectionEvent.element); - var key = goog.getUid(layer).toString(); - goog.asserts.assert(!(key in this.listenerKeys_), - 'listeners already registered'); - this.listenerKeys_[key] = [ - goog.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE, - this.handleLayerChange_, false, this), - goog.events.listen(layer, goog.events.EventType.CHANGE, - this.handleLayerChange_, false, this) - ]; - this.changed(); +goog.debug.Console.prototype.addFilter = function(loggerName) { + this.filteredLoggers_[loggerName] = true; }; /** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @private + * Removes a logger name to be filtered. + * @param {string} loggerName the logger name to remove. */ -ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) { - var layer = /** @type {ol.layer.Base} */ (collectionEvent.element); - var key = goog.getUid(layer).toString(); - goog.asserts.assert(key in this.listenerKeys_, 'no listeners to unregister'); - this.listenerKeys_[key].forEach(goog.events.unlistenByKey); - delete this.listenerKeys_[key]; - this.changed(); +goog.debug.Console.prototype.removeFilter = function(loggerName) { + delete this.filteredLoggers_[loggerName]; }; /** - * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers} - * in this group. - * @return {!ol.Collection.<ol.layer.Base>} Collection of - * {@link ol.layer.Base layers} that are part of this group. - * @observable - * @api stable + * Global console logger instance + * @type {goog.debug.Console} */ -ol.layer.Group.prototype.getLayers = function() { - return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get( - ol.layer.GroupProperty.LAYERS)); -}; +goog.debug.Console.instance = null; /** - * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers} - * in this group. - * @param {!ol.Collection.<ol.layer.Base>} layers Collection of - * {@link ol.layer.Base layers} that are part of this group. - * @observable - * @api stable + * The console to which to log. This is a property so it can be mocked out in + * this unit test for goog.debug.Console. Using goog.global, as console might be + * used in window-less contexts. + * @type {Object} + * @private */ -ol.layer.Group.prototype.setLayers = function(layers) { - this.set(ol.layer.GroupProperty.LAYERS, layers); -}; +goog.debug.Console.console_ = goog.global['console']; /** - * @inheritDoc + * Sets the console to which to log. + * @param {!Object} console The console to which to log. */ -ol.layer.Group.prototype.getLayersArray = function(opt_array) { - var array = opt_array !== undefined ? opt_array : []; - this.getLayers().forEach(function(layer) { - layer.getLayersArray(array); - }); - return array; +goog.debug.Console.setConsole = function(console) { + goog.debug.Console.console_ = console; }; /** - * @inheritDoc + * Install the console and start capturing if "Debug=true" is in the page URL */ -ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) { - var states = opt_states !== undefined ? opt_states : []; - - var pos = states.length; - - this.getLayers().forEach(function(layer) { - layer.getLayerStatesArray(states); - }); - - var ownLayerState = this.getLayerState(); - var i, ii, layerState; - for (i = pos, ii = states.length; i < ii; i++) { - layerState = states[i]; - layerState.opacity *= ownLayerState.opacity; - layerState.visible = layerState.visible && ownLayerState.visible; - layerState.maxResolution = Math.min( - layerState.maxResolution, ownLayerState.maxResolution); - layerState.minResolution = Math.max( - layerState.minResolution, ownLayerState.minResolution); - if (ownLayerState.extent !== undefined) { - if (layerState.extent !== undefined) { - layerState.extent = ol.extent.getIntersection( - layerState.extent, ownLayerState.extent); - } else { - layerState.extent = ownLayerState.extent; - } - } +goog.debug.Console.autoInstall = function() { + if (!goog.debug.Console.instance) { + goog.debug.Console.instance = new goog.debug.Console(); } - return states; + if (goog.global.location && + goog.global.location.href.indexOf('Debug=true') != -1) { + goog.debug.Console.instance.setCapturing(true); + } }; /** - * @inheritDoc + * Show an alert with all of the captured debug information. + * Information is only captured if console is not available */ -ol.layer.Group.prototype.getSourceState = function() { - return ol.source.State.READY; +goog.debug.Console.show = function() { + alert(goog.debug.Console.instance.logBuffer_); }; -goog.provide('ol.proj.EPSG3857'); - -goog.require('goog.asserts'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); - - /** - * @classdesc - * Projection object for web/spherical Mercator (EPSG:3857). - * - * @constructor - * @extends {ol.proj.Projection} - * @param {string} code Code. + * Logs the record to the console using the given function. If the function is + * not available on the console object, the log function is used instead. + * @param {!Object} console The console object. + * @param {string} fnName The name of the function to use. + * @param {string} record The record to log. * @private */ -ol.proj.EPSG3857_ = function(code) { - goog.base(this, { - code: code, - units: ol.proj.Units.METERS, - extent: ol.proj.EPSG3857.EXTENT, - global: true, - worldExtent: ol.proj.EPSG3857.WORLD_EXTENT - }); +goog.debug.Console.logToConsole_ = function(console, fnName, record) { + if (console[fnName]) { + console[fnName](record); + } else { + console.log(record); + } }; -goog.inherits(ol.proj.EPSG3857_, ol.proj.Projection); +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @inheritDoc + * @fileoverview Utility class that monitors viewport size changes. + * + * @author attila@google.com (Attila Bodis) + * @see ../demos/viewportsizemonitor.html */ -ol.proj.EPSG3857_.prototype.getPointResolution = function(resolution, point) { - return resolution / ol.math.cosh(point[1] / ol.proj.EPSG3857.RADIUS); -}; +goog.provide('goog.dom.ViewportSizeMonitor'); -/** - * @const - * @type {number} - */ -ol.proj.EPSG3857.RADIUS = 6378137; - +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('goog.math.Size'); -/** - * @const - * @type {number} - */ -ol.proj.EPSG3857.HALF_SIZE = Math.PI * ol.proj.EPSG3857.RADIUS; /** - * @const - * @type {ol.Extent} + * This class can be used to monitor changes in the viewport size. Instances + * dispatch a {@link goog.events.EventType.RESIZE} event when the viewport size + * changes. Handlers can call {@link goog.dom.ViewportSizeMonitor#getSize} to + * get the new viewport size. + * + * Use this class if you want to execute resize/reflow logic each time the + * user resizes the browser window. This class is guaranteed to only dispatch + * {@code RESIZE} events when the pixel dimensions of the viewport change. + * (Internet Explorer fires resize events if any element on the page is resized, + * even if the viewport dimensions are unchanged, which can lead to infinite + * resize loops.) + * + * Example usage: + * <pre> + * var vsm = new goog.dom.ViewportSizeMonitor(); + * goog.events.listen(vsm, goog.events.EventType.RESIZE, function(e) { + * alert('Viewport size changed to ' + vsm.getSize()); + * }); + * </pre> + * + * Manually verified on IE6, IE7, FF2, Opera 11, Safari 4 and Chrome. + * + * @param {Window=} opt_window The window to monitor; defaults to the window in + * which this code is executing. + * @constructor + * @extends {goog.events.EventTarget} */ -ol.proj.EPSG3857.EXTENT = [ - -ol.proj.EPSG3857.HALF_SIZE, -ol.proj.EPSG3857.HALF_SIZE, - ol.proj.EPSG3857.HALF_SIZE, ol.proj.EPSG3857.HALF_SIZE -]; +goog.dom.ViewportSizeMonitor = function(opt_window) { + goog.dom.ViewportSizeMonitor.base(this, 'constructor'); + /** + * The window to monitor. Defaults to the window in which the code is running. + * @private {Window} + */ + this.window_ = opt_window || window; -/** - * @const - * @type {ol.Extent} - */ -ol.proj.EPSG3857.WORLD_EXTENT = [-180, -85, 180, 85]; + /** + * Event listener key for window the window resize handler, as returned by + * {@link goog.events.listen}. + * @private {goog.events.Key} + */ + this.listenerKey_ = goog.events.listen(this.window_, + goog.events.EventType.RESIZE, this.handleResize_, false, this); + + /** + * The most recently recorded size of the viewport, in pixels. + * @private {goog.math.Size} + */ + this.size_ = goog.dom.getViewportSize(this.window_); +}; +goog.inherits(goog.dom.ViewportSizeMonitor, goog.events.EventTarget); /** - * Lists several projection codes with the same meaning as EPSG:3857. - * - * @type {Array.<string>} + * Returns a viewport size monitor for the given window. A new one is created + * if it doesn't exist already. This prevents the unnecessary creation of + * multiple spooling monitors for a window. + * @param {Window=} opt_window The window to monitor; defaults to the window in + * which this code is executing. + * @return {!goog.dom.ViewportSizeMonitor} Monitor for the given window. */ -ol.proj.EPSG3857.CODES = [ - 'EPSG:3857', - 'EPSG:102100', - 'EPSG:102113', - 'EPSG:900913', - 'urn:ogc:def:crs:EPSG:6.18:3:3857', - 'urn:ogc:def:crs:EPSG::3857', - 'http://www.opengis.net/gml/srs/epsg.xml#3857' -]; +goog.dom.ViewportSizeMonitor.getInstanceForWindow = function(opt_window) { + var currentWindow = opt_window || window; + var uid = goog.getUid(currentWindow); + + return goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] = + goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] || + new goog.dom.ViewportSizeMonitor(currentWindow); +}; /** - * Projections equal to EPSG:3857. - * - * @const - * @type {Array.<ol.proj.Projection>} + * Removes and disposes a viewport size monitor for the given window if one + * exists. + * @param {Window=} opt_window The window whose monitor should be removed; + * defaults to the window in which this code is executing. */ -ol.proj.EPSG3857.PROJECTIONS = ol.proj.EPSG3857.CODES.map(function(code) { - return new ol.proj.EPSG3857_(code); -}); +goog.dom.ViewportSizeMonitor.removeInstanceForWindow = function(opt_window) { + var uid = goog.getUid(opt_window || window); + + goog.dispose(goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]); + delete goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]; +}; /** - * Transformation from EPSG:4326 to EPSG:3857. - * - * @param {Array.<number>} input Input array of coordinate values. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension (default is `2`). - * @return {Array.<number>} Output array of coordinate values. + * Map of window hash code to viewport size monitor for that window, if + * created. + * @type {Object<number,goog.dom.ViewportSizeMonitor>} + * @private */ -ol.proj.EPSG3857.fromEPSG4326 = function(input, opt_output, opt_dimension) { - var length = input.length, - dimension = opt_dimension > 1 ? opt_dimension : 2, - output = opt_output; - if (output === undefined) { - if (dimension > 2) { - // preserve values beyond second dimension - output = input.slice(); - } else { - output = new Array(length); - } - } - goog.asserts.assert(output.length % dimension === 0, - 'modulus of output.length with dimension should be 0'); - for (var i = 0; i < length; i += dimension) { - output[i] = ol.proj.EPSG3857.RADIUS * Math.PI * input[i] / 180; - output[i + 1] = ol.proj.EPSG3857.RADIUS * - Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360)); - } - return output; -}; +goog.dom.ViewportSizeMonitor.windowInstanceMap_ = {}; /** - * Transformation from EPSG:3857 to EPSG:4326. - * - * @param {Array.<number>} input Input array of coordinate values. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension (default is `2`). - * @return {Array.<number>} Output array of coordinate values. + * Returns the most recently recorded size of the viewport, in pixels. May + * return null if no window resize event has been handled yet. + * @return {goog.math.Size} The viewport dimensions, in pixels. */ -ol.proj.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) { - var length = input.length, - dimension = opt_dimension > 1 ? opt_dimension : 2, - output = opt_output; - if (output === undefined) { - if (dimension > 2) { - // preserve values beyond second dimension - output = input.slice(); - } else { - output = new Array(length); - } - } - goog.asserts.assert(output.length % dimension === 0, - 'modulus of output.length with dimension should be 0'); - for (var i = 0; i < length; i += dimension) { - output[i] = 180 * input[i] / (ol.proj.EPSG3857.RADIUS * Math.PI); - output[i + 1] = 360 * Math.atan( - Math.exp(input[i + 1] / ol.proj.EPSG3857.RADIUS)) / Math.PI - 90; - } - return output; +goog.dom.ViewportSizeMonitor.prototype.getSize = function() { + // Return a clone instead of the original to preserve encapsulation. + return this.size_ ? this.size_.clone() : null; }; -goog.provide('ol.proj.EPSG4326'); - -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); +/** @override */ +goog.dom.ViewportSizeMonitor.prototype.disposeInternal = function() { + goog.dom.ViewportSizeMonitor.superClass_.disposeInternal.call(this); + if (this.listenerKey_) { + goog.events.unlistenByKey(this.listenerKey_); + this.listenerKey_ = null; + } -/** - * @classdesc - * Projection object for WGS84 geographic coordinates (EPSG:4326). - * - * Note that OpenLayers does not strictly comply with the EPSG definition. - * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x). - * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates. - * - * @constructor - * @extends {ol.proj.Projection} - * @param {string} code Code. - * @param {string=} opt_axisOrientation Axis orientation. - * @private - */ -ol.proj.EPSG4326_ = function(code, opt_axisOrientation) { - goog.base(this, { - code: code, - units: ol.proj.Units.DEGREES, - extent: ol.proj.EPSG4326.EXTENT, - axisOrientation: opt_axisOrientation, - global: true, - worldExtent: ol.proj.EPSG4326.EXTENT - }); + this.window_ = null; + this.size_ = null; }; -goog.inherits(ol.proj.EPSG4326_, ol.proj.Projection); /** - * @inheritDoc + * Handles window resize events by measuring the dimensions of the + * viewport and dispatching a {@link goog.events.EventType.RESIZE} event if the + * current dimensions are different from the previous ones. + * @param {goog.events.Event} event The window resize event to handle. + * @private */ -ol.proj.EPSG4326_.prototype.getPointResolution = function(resolution, point) { - return resolution; +goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) { + var size = goog.dom.getViewportSize(this.window_); + if (!goog.math.Size.equals(size, this.size_)) { + this.size_ = size; + this.dispatchEvent(goog.events.EventType.RESIZE); + } }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Extent of the EPSG:4326 projection which is the whole world. + * @fileoverview Constant declarations for common key codes. * - * @const - * @type {ol.Extent} + * @author eae@google.com (Emil A Eklund) + * @see ../demos/keyhandler.html */ -ol.proj.EPSG4326.EXTENT = [-180, -90, 180, 90]; - -/** - * Projections equal to EPSG:4326. - * - * @const - * @type {Array.<ol.proj.Projection>} - */ -ol.proj.EPSG4326.PROJECTIONS = [ - new ol.proj.EPSG4326_('CRS:84'), - new ol.proj.EPSG4326_('EPSG:4326', 'neu'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG::4326', 'neu'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:1.3:CRS84'), - new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:2:84'), - new ol.proj.EPSG4326_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'), - new ol.proj.EPSG4326_('urn:x-ogc:def:crs:EPSG:4326', 'neu') -]; +goog.provide('goog.events.KeyCodes'); -goog.provide('ol.proj.common'); +goog.require('goog.userAgent'); -goog.require('ol.proj'); -goog.require('ol.proj.EPSG3857'); -goog.require('ol.proj.EPSG4326'); +goog.forwardDeclare('goog.events.BrowserEvent'); /** - * FIXME empty description for jsdoc - * @api + * Key codes for common characters. + * + * This list is not localized and therefore some of the key codes are not + * correct for non US keyboard layouts. See comments below. + * + * @enum {number} */ -ol.proj.common.add = function() { - // Add transformations that don't alter coordinates to convert within set of - // projections with equal meaning. - ol.proj.addEquivalentProjections(ol.proj.EPSG3857.PROJECTIONS); - ol.proj.addEquivalentProjections(ol.proj.EPSG4326.PROJECTIONS); - // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like - // coordinates and back. - ol.proj.addEquivalentTransforms( - ol.proj.EPSG4326.PROJECTIONS, - ol.proj.EPSG3857.PROJECTIONS, - ol.proj.EPSG3857.fromEPSG4326, - ol.proj.EPSG3857.toEPSG4326); -}; - -goog.provide('ol.layer.Image'); - -goog.require('ol.layer.Layer'); - - - -/** - * @classdesc - * Server-rendered images that are available for arbitrary extents and - * resolutions. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Layer} - * @fires ol.render.Event - * @param {olx.layer.ImageOptions=} opt_options Layer options. - * @api stable - */ -ol.layer.Image = function(opt_options) { - var options = opt_options ? opt_options : {}; - goog.base(this, /** @type {olx.layer.LayerOptions} */ (options)); -}; -goog.inherits(ol.layer.Image, ol.layer.Layer); - - -/** - * Return the associated {@link ol.source.Image source} of the image layer. - * @function - * @return {ol.source.Image} Source. - * @api stable - */ -ol.layer.Image.prototype.getSource; +goog.events.KeyCodes = { + WIN_KEY_FF_LINUX: 0, + MAC_ENTER: 3, + BACKSPACE: 8, + TAB: 9, + NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac + ENTER: 13, + SHIFT: 16, + CTRL: 17, + ALT: 18, + PAUSE: 19, + CAPS_LOCK: 20, + ESC: 27, + SPACE: 32, + PAGE_UP: 33, // also NUM_NORTH_EAST + PAGE_DOWN: 34, // also NUM_SOUTH_EAST + END: 35, // also NUM_SOUTH_WEST + HOME: 36, // also NUM_NORTH_WEST + LEFT: 37, // also NUM_WEST + UP: 38, // also NUM_NORTH + RIGHT: 39, // also NUM_EAST + DOWN: 40, // also NUM_SOUTH + PLUS_SIGN: 43, // NOT numpad plus + PRINT_SCREEN: 44, + INSERT: 45, // also NUM_INSERT + DELETE: 46, // also NUM_DELETE + ZERO: 48, + ONE: 49, + TWO: 50, + THREE: 51, + FOUR: 52, + FIVE: 53, + SIX: 54, + SEVEN: 55, + EIGHT: 56, + NINE: 57, + FF_SEMICOLON: 59, // Firefox (Gecko) fires this for semicolon instead of 186 + FF_EQUALS: 61, // Firefox (Gecko) fires this for equals instead of 187 + FF_DASH: 173, // Firefox (Gecko) fires this for dash instead of 189 + QUESTION_MARK: 63, // needs localization + AT_SIGN: 64, + A: 65, + B: 66, + C: 67, + D: 68, + E: 69, + F: 70, + G: 71, + H: 72, + I: 73, + J: 74, + K: 75, + L: 76, + M: 77, + N: 78, + O: 79, + P: 80, + Q: 81, + R: 82, + S: 83, + T: 84, + U: 85, + V: 86, + W: 87, + X: 88, + Y: 89, + Z: 90, + META: 91, // WIN_KEY_LEFT + WIN_KEY_RIGHT: 92, + CONTEXT_MENU: 93, + NUM_ZERO: 96, + NUM_ONE: 97, + NUM_TWO: 98, + NUM_THREE: 99, + NUM_FOUR: 100, + NUM_FIVE: 101, + NUM_SIX: 102, + NUM_SEVEN: 103, + NUM_EIGHT: 104, + NUM_NINE: 105, + NUM_MULTIPLY: 106, + NUM_PLUS: 107, + NUM_MINUS: 109, + NUM_PERIOD: 110, + NUM_DIVISION: 111, + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, + NUMLOCK: 144, + SCROLL_LOCK: 145, -goog.provide('ol.layer.Tile'); + // OS-specific media keys like volume controls and browser controls. + FIRST_MEDIA_KEY: 166, + LAST_MEDIA_KEY: 183, -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.layer.Layer'); + SEMICOLON: 186, // needs localization + DASH: 189, // needs localization + EQUALS: 187, // needs localization + COMMA: 188, // needs localization + PERIOD: 190, // needs localization + SLASH: 191, // needs localization + APOSTROPHE: 192, // needs localization + TILDE: 192, // needs localization + SINGLE_QUOTE: 222, // needs localization + OPEN_SQUARE_BRACKET: 219, // needs localization + BACKSLASH: 220, // needs localization + CLOSE_SQUARE_BRACKET: 221, // needs localization + WIN_KEY: 224, + MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91 + MAC_WK_CMD_LEFT: 91, // WebKit Left Command key fired, same as META + MAC_WK_CMD_RIGHT: 93, // WebKit Right Command key fired, different from META + WIN_IME: 229, + // "Reserved for future use". Some programs (e.g. the SlingPlayer 2.4 ActiveX + // control) fire this as a hacky way to disable screensavers. + VK_NONAME: 252, -/** - * @enum {string} - */ -ol.layer.TileProperty = { - PRELOAD: 'preload', - USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError' + // We've seen users whose machines fire this keycode at regular one + // second intervals. The common thread among these users is that + // they're all using Dell Inspiron laptops, so we suspect that this + // indicates a hardware/bios problem. + // http://en.community.dell.com/support-forums/laptop/f/3518/p/19285957/19523128.aspx + PHANTOM: 255 }; - /** - * @classdesc - * For layer sources that provide pre-rendered, tiled images in grids that are - * organized by zoom levels for specific resolutions. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Layer} - * @fires ol.render.Event - * @param {olx.layer.TileOptions=} opt_options Tile layer options. - * @api stable + * Returns true if the event contains a text modifying key. + * @param {goog.events.BrowserEvent} e A key event. + * @return {boolean} Whether it's a text modifying key. */ -ol.layer.Tile = function(opt_options) { - var options = opt_options ? opt_options : {}; - - var baseOptions = goog.object.clone(options); - - delete baseOptions.preload; - delete baseOptions.useInterimTilesOnError; - goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); +goog.events.KeyCodes.isTextModifyingKeyEvent = function(e) { + if (e.altKey && !e.ctrlKey || + e.metaKey || + // Function keys don't generate text + e.keyCode >= goog.events.KeyCodes.F1 && + e.keyCode <= goog.events.KeyCodes.F12) { + return false; + } - this.setPreload(options.preload !== undefined ? options.preload : 0); - this.setUseInterimTilesOnError(options.useInterimTilesOnError !== undefined ? - options.useInterimTilesOnError : true); + // The following keys are quite harmless, even in combination with + // CTRL, ALT or SHIFT. + switch (e.keyCode) { + case goog.events.KeyCodes.ALT: + case goog.events.KeyCodes.CAPS_LOCK: + case goog.events.KeyCodes.CONTEXT_MENU: + case goog.events.KeyCodes.CTRL: + case goog.events.KeyCodes.DOWN: + case goog.events.KeyCodes.END: + case goog.events.KeyCodes.ESC: + case goog.events.KeyCodes.HOME: + case goog.events.KeyCodes.INSERT: + case goog.events.KeyCodes.LEFT: + case goog.events.KeyCodes.MAC_FF_META: + case goog.events.KeyCodes.META: + case goog.events.KeyCodes.NUMLOCK: + case goog.events.KeyCodes.NUM_CENTER: + case goog.events.KeyCodes.PAGE_DOWN: + case goog.events.KeyCodes.PAGE_UP: + case goog.events.KeyCodes.PAUSE: + case goog.events.KeyCodes.PHANTOM: + case goog.events.KeyCodes.PRINT_SCREEN: + case goog.events.KeyCodes.RIGHT: + case goog.events.KeyCodes.SCROLL_LOCK: + case goog.events.KeyCodes.SHIFT: + case goog.events.KeyCodes.UP: + case goog.events.KeyCodes.VK_NONAME: + case goog.events.KeyCodes.WIN_KEY: + case goog.events.KeyCodes.WIN_KEY_RIGHT: + return false; + case goog.events.KeyCodes.WIN_KEY_FF_LINUX: + return !goog.userAgent.GECKO; + default: + return e.keyCode < goog.events.KeyCodes.FIRST_MEDIA_KEY || + e.keyCode > goog.events.KeyCodes.LAST_MEDIA_KEY; + } }; -goog.inherits(ol.layer.Tile, ol.layer.Layer); /** - * Return the level as number to which we will preload tiles up to. - * @return {number} The level to preload tiles up to. - * @observable - * @api + * Returns true if the key fires a keypress event in the current browser. + * + * Accoridng to MSDN [1] IE only fires keypress events for the following keys: + * - Letters: A - Z (uppercase and lowercase) + * - Numerals: 0 - 9 + * - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ + * - System: ESC, SPACEBAR, ENTER + * + * That's not entirely correct though, for instance there's no distinction + * between upper and lower case letters. + * + * [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx) + * + * Safari is similar to IE, but does not fire keypress for ESC. + * + * Additionally, IE6 does not fire keydown or keypress events for letters when + * the control or alt keys are held down and the shift key is not. IE7 does + * fire keydown in these cases, though, but not keypress. + * + * @param {number} keyCode A key code. + * @param {number=} opt_heldKeyCode Key code of a currently-held key. + * @param {boolean=} opt_shiftKey Whether the shift key is held down. + * @param {boolean=} opt_ctrlKey Whether the control key is held down. + * @param {boolean=} opt_altKey Whether the alt key is held down. + * @return {boolean} Whether it's a key that fires a keypress event. */ -ol.layer.Tile.prototype.getPreload = function() { - return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD)); -}; - +goog.events.KeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode, + opt_shiftKey, opt_ctrlKey, opt_altKey) { + if (!goog.userAgent.IE && !goog.userAgent.EDGE && + !(goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'))) { + return true; + } -/** - * Return the associated {@link ol.source.Tile tilesource} of the layer. - * @function - * @return {ol.source.Tile} Source. - * @api stable - */ -ol.layer.Tile.prototype.getSource; + if (goog.userAgent.MAC && opt_altKey) { + return goog.events.KeyCodes.isCharacterKey(keyCode); + } + // Alt but not AltGr which is represented as Alt+Ctrl. + if (opt_altKey && !opt_ctrlKey) { + return false; + } -/** - * Set the level as number to which we will preload tiles up to. - * @param {number} preload The level to preload tiles up to. - * @observable - * @api - */ -ol.layer.Tile.prototype.setPreload = function(preload) { - this.set(ol.layer.TileProperty.PRELOAD, preload); -}; + // Saves Ctrl or Alt + key for IE and WebKit 525+, which won't fire keypress. + // Non-IE browsers and WebKit prior to 525 won't get this far so no need to + // check the user agent. + if (goog.isNumber(opt_heldKeyCode)) { + opt_heldKeyCode = goog.events.KeyCodes.normalizeKeyCode(opt_heldKeyCode); + } + if (!opt_shiftKey && + (opt_heldKeyCode == goog.events.KeyCodes.CTRL || + opt_heldKeyCode == goog.events.KeyCodes.ALT || + goog.userAgent.MAC && + opt_heldKeyCode == goog.events.KeyCodes.META)) { + return false; + } + // Some keys with Ctrl/Shift do not issue keypress in WEBKIT. + if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && + opt_ctrlKey && opt_shiftKey) { + switch (keyCode) { + case goog.events.KeyCodes.BACKSLASH: + case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: + case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: + case goog.events.KeyCodes.TILDE: + case goog.events.KeyCodes.SEMICOLON: + case goog.events.KeyCodes.DASH: + case goog.events.KeyCodes.EQUALS: + case goog.events.KeyCodes.COMMA: + case goog.events.KeyCodes.PERIOD: + case goog.events.KeyCodes.SLASH: + case goog.events.KeyCodes.APOSTROPHE: + case goog.events.KeyCodes.SINGLE_QUOTE: + return false; + } + } -/** - * Whether we use interim tiles on error. - * @return {boolean} Use interim tiles on error. - * @observable - * @api - */ -ol.layer.Tile.prototype.getUseInterimTilesOnError = function() { - return /** @type {boolean} */ ( - this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR)); -}; + // When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it + // continues to fire keydown events as the event repeats. + if (goog.userAgent.IE && opt_ctrlKey && opt_heldKeyCode == keyCode) { + return false; + } + switch (keyCode) { + case goog.events.KeyCodes.ENTER: + return true; + case goog.events.KeyCodes.ESC: + return !(goog.userAgent.WEBKIT || goog.userAgent.EDGE); + } -/** - * Set whether we use interim tiles on error. - * @param {boolean} useInterimTilesOnError Use interim tiles on error. - * @observable - * @api - */ -ol.layer.Tile.prototype.setUseInterimTilesOnError = - function(useInterimTilesOnError) { - this.set( - ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); + return goog.events.KeyCodes.isCharacterKey(keyCode); }; -goog.provide('ol.render.canvas'); - - -/** - * @typedef {{fillStyle: string}} - */ -ol.render.canvas.FillState; - - -/** - * @typedef {{lineCap: string, - * lineDash: Array.<number>, - * lineJoin: string, - * lineWidth: number, - * miterLimit: number, - * strokeStyle: string}} - */ -ol.render.canvas.StrokeState; - /** - * @typedef {{font: string, - * textAlign: string, - * textBaseline: string}} + * Returns true if the key produces a character. + * This does not cover characters on non-US keyboards (Russian, Hebrew, etc.). + * + * @param {number} keyCode A key code. + * @return {boolean} Whether it's a character key. */ -ol.render.canvas.TextState; +goog.events.KeyCodes.isCharacterKey = function(keyCode) { + if (keyCode >= goog.events.KeyCodes.ZERO && + keyCode <= goog.events.KeyCodes.NINE) { + return true; + } + if (keyCode >= goog.events.KeyCodes.NUM_ZERO && + keyCode <= goog.events.KeyCodes.NUM_MULTIPLY) { + return true; + } -/** - * @const - * @type {string} - */ -ol.render.canvas.defaultFont = '10px sans-serif'; + if (keyCode >= goog.events.KeyCodes.A && + keyCode <= goog.events.KeyCodes.Z) { + return true; + } + // Safari sends zero key code for non-latin characters. + if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && keyCode == 0) { + return true; + } -/** - * @const - * @type {ol.Color} - */ -ol.render.canvas.defaultFillStyle = [0, 0, 0, 1]; + switch (keyCode) { + case goog.events.KeyCodes.SPACE: + case goog.events.KeyCodes.PLUS_SIGN: + case goog.events.KeyCodes.QUESTION_MARK: + case goog.events.KeyCodes.AT_SIGN: + case goog.events.KeyCodes.NUM_PLUS: + case goog.events.KeyCodes.NUM_MINUS: + case goog.events.KeyCodes.NUM_PERIOD: + case goog.events.KeyCodes.NUM_DIVISION: + case goog.events.KeyCodes.SEMICOLON: + case goog.events.KeyCodes.FF_SEMICOLON: + case goog.events.KeyCodes.DASH: + case goog.events.KeyCodes.EQUALS: + case goog.events.KeyCodes.FF_EQUALS: + case goog.events.KeyCodes.COMMA: + case goog.events.KeyCodes.PERIOD: + case goog.events.KeyCodes.SLASH: + case goog.events.KeyCodes.APOSTROPHE: + case goog.events.KeyCodes.SINGLE_QUOTE: + case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: + case goog.events.KeyCodes.BACKSLASH: + case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: + return true; + default: + return false; + } +}; /** - * @const - * @type {string} + * Normalizes key codes from OS/Browser-specific value to the general one. + * @param {number} keyCode The native key code. + * @return {number} The normalized key code. */ -ol.render.canvas.defaultLineCap = 'round'; +goog.events.KeyCodes.normalizeKeyCode = function(keyCode) { + if (goog.userAgent.GECKO) { + return goog.events.KeyCodes.normalizeGeckoKeyCode(keyCode); + } else if (goog.userAgent.MAC && goog.userAgent.WEBKIT) { + return goog.events.KeyCodes.normalizeMacWebKitKeyCode(keyCode); + } else { + return keyCode; + } +}; /** - * @const - * @type {Array.<number>} + * Normalizes key codes from their Gecko-specific value to the general one. + * @param {number} keyCode The native key code. + * @return {number} The normalized key code. */ -ol.render.canvas.defaultLineDash = []; +goog.events.KeyCodes.normalizeGeckoKeyCode = function(keyCode) { + switch (keyCode) { + case goog.events.KeyCodes.FF_EQUALS: + return goog.events.KeyCodes.EQUALS; + case goog.events.KeyCodes.FF_SEMICOLON: + return goog.events.KeyCodes.SEMICOLON; + case goog.events.KeyCodes.FF_DASH: + return goog.events.KeyCodes.DASH; + case goog.events.KeyCodes.MAC_FF_META: + return goog.events.KeyCodes.META; + case goog.events.KeyCodes.WIN_KEY_FF_LINUX: + return goog.events.KeyCodes.WIN_KEY; + default: + return keyCode; + } +}; /** - * @const - * @type {string} + * Normalizes key codes from their Mac WebKit-specific value to the general one. + * @param {number} keyCode The native key code. + * @return {number} The normalized key code. */ -ol.render.canvas.defaultLineJoin = 'round'; +goog.events.KeyCodes.normalizeMacWebKitKeyCode = function(keyCode) { + switch (keyCode) { + case goog.events.KeyCodes.MAC_WK_CMD_RIGHT: // 93 + return goog.events.KeyCodes.META; // 91 + default: + return keyCode; + } +}; +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @const - * @type {number} + * @fileoverview This file contains a class for working with keyboard events + * that repeat consistently across browsers and platforms. It also unifies the + * key code so that it is the same in all browsers and platforms. + * + * Different web browsers have very different keyboard event handling. Most + * importantly is that only certain browsers repeat keydown events: + * IE, Opera, FF/Win32, and Safari 3 repeat keydown events. + * FF/Mac and Safari 2 do not. + * + * For the purposes of this code, "Safari 3" means WebKit 525+, when WebKit + * decided that they should try to match IE's key handling behavior. + * Safari 3.0.4, which shipped with Leopard (WebKit 523), has the + * Safari 2 behavior. + * + * Firefox, Safari, Opera prevent on keypress + * + * IE prevents on keydown + * + * Firefox does not fire keypress for shift, ctrl, alt + * Firefox does fire keydown for shift, ctrl, alt, meta + * Firefox does not repeat keydown for shift, ctrl, alt, meta + * + * Firefox does not fire keypress for up and down in an input + * + * Opera fires keypress for shift, ctrl, alt, meta + * Opera does not repeat keypress for shift, ctrl, alt, meta + * + * Safari 2 and 3 do not fire keypress for shift, ctrl, alt + * Safari 2 does not fire keydown for shift, ctrl, alt + * Safari 3 *does* fire keydown for shift, ctrl, alt + * + * IE provides the keycode for keyup/down events and the charcode (in the + * keycode field) for keypress. + * + * Mozilla provides the keycode for keyup/down and the charcode for keypress + * unless it's a non text modifying key in which case the keycode is provided. + * + * Safari 3 provides the keycode and charcode for all events. + * + * Opera provides the keycode for keyup/down event and either the charcode or + * the keycode (in the keycode field) for keypress events. + * + * Firefox x11 doesn't fire keydown events if a another key is already held down + * until the first key is released. This can cause a key event to be fired with + * a keyCode for the first key and a charCode for the second key. + * + * Safari in keypress + * + * charCode keyCode which + * ENTER: 13 13 13 + * F1: 63236 63236 63236 + * F8: 63243 63243 63243 + * ... + * p: 112 112 112 + * P: 80 80 80 + * + * Firefox, keypress: + * + * charCode keyCode which + * ENTER: 0 13 13 + * F1: 0 112 0 + * F8: 0 119 0 + * ... + * p: 112 0 112 + * P: 80 0 80 + * + * Opera, Mac+Win32, keypress: + * + * charCode keyCode which + * ENTER: undefined 13 13 + * F1: undefined 112 0 + * F8: undefined 119 0 + * ... + * p: undefined 112 112 + * P: undefined 80 80 + * + * IE7, keydown + * + * charCode keyCode which + * ENTER: undefined 13 undefined + * F1: undefined 112 undefined + * F8: undefined 119 undefined + * ... + * p: undefined 80 undefined + * P: undefined 80 undefined + * + * @author arv@google.com (Erik Arvidsson) + * @author eae@google.com (Emil A Eklund) + * @see ../demos/keyhandler.html */ -ol.render.canvas.defaultMiterLimit = 10; + +goog.provide('goog.events.KeyEvent'); +goog.provide('goog.events.KeyHandler'); +goog.provide('goog.events.KeyHandler.EventType'); + +goog.require('goog.events'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('goog.events.KeyCodes'); +goog.require('goog.userAgent'); + /** - * @const - * @type {ol.Color} + * A wrapper around an element that you want to listen to keyboard events on. + * @param {Element|Document=} opt_element The element or document to listen on. + * @param {boolean=} opt_capture Whether to listen for browser events in + * capture phase (defaults to false). + * @constructor + * @extends {goog.events.EventTarget} + * @final */ -ol.render.canvas.defaultStrokeStyle = [0, 0, 0, 1]; +goog.events.KeyHandler = function(opt_element, opt_capture) { + goog.events.EventTarget.call(this); + + if (opt_element) { + this.attach(opt_element, opt_capture); + } +}; +goog.inherits(goog.events.KeyHandler, goog.events.EventTarget); /** - * @const - * @type {string} + * This is the element that we will listen to the real keyboard events on. + * @type {Element|Document|null} + * @private */ -ol.render.canvas.defaultTextAlign = 'center'; +goog.events.KeyHandler.prototype.element_ = null; /** - * @const - * @type {string} + * The key for the key press listener. + * @type {goog.events.Key} + * @private */ -ol.render.canvas.defaultTextBaseline = 'middle'; +goog.events.KeyHandler.prototype.keyPressKey_ = null; /** - * @const - * @type {number} + * The key for the key down listener. + * @type {goog.events.Key} + * @private */ -ol.render.canvas.defaultLineWidth = 1; +goog.events.KeyHandler.prototype.keyDownKey_ = null; -goog.provide('ol.structs.IHasChecksum'); +/** + * The key for the key up listener. + * @type {goog.events.Key} + * @private + */ +goog.events.KeyHandler.prototype.keyUpKey_ = null; /** - * @interface + * Used to detect keyboard repeat events. + * @private + * @type {number} */ -ol.structs.IHasChecksum = function() { -}; +goog.events.KeyHandler.prototype.lastKey_ = -1; /** - * @return {string} The checksum. + * Keycode recorded for key down events. As most browsers don't report the + * keycode in the key press event we need to record it in the key down phase. + * @private + * @type {number} */ -ol.structs.IHasChecksum.prototype.getChecksum = function() { -}; - -goog.provide('ol.style.Fill'); +goog.events.KeyHandler.prototype.keyCode_ = -1; -goog.require('ol.color'); -goog.require('ol.structs.IHasChecksum'); +/** + * Alt key recorded for key down events. FF on Mac does not report the alt key + * flag in the key press event, we need to record it in the key down phase. + * @type {boolean} + * @private + */ +goog.events.KeyHandler.prototype.altKey_ = false; /** - * @classdesc - * Set fill style for vector features. - * - * @constructor - * @param {olx.style.FillOptions=} opt_options Options. - * @implements {ol.structs.IHasChecksum} - * @api + * Enum type for the events fired by the key handler + * @enum {string} */ -ol.style.Fill = function(opt_options) { - - var options = opt_options || {}; +goog.events.KeyHandler.EventType = { + KEY: 'key' +}; - /** - * @private - * @type {ol.Color|string} - */ - this.color_ = options.color !== undefined ? options.color : null; - /** - * @private - * @type {string|undefined} - */ - this.checksum_ = undefined; +/** + * An enumeration of key codes that Safari 2 does incorrectly + * @type {Object} + * @private + */ +goog.events.KeyHandler.safariKey_ = { + '3': goog.events.KeyCodes.ENTER, // 13 + '12': goog.events.KeyCodes.NUMLOCK, // 144 + '63232': goog.events.KeyCodes.UP, // 38 + '63233': goog.events.KeyCodes.DOWN, // 40 + '63234': goog.events.KeyCodes.LEFT, // 37 + '63235': goog.events.KeyCodes.RIGHT, // 39 + '63236': goog.events.KeyCodes.F1, // 112 + '63237': goog.events.KeyCodes.F2, // 113 + '63238': goog.events.KeyCodes.F3, // 114 + '63239': goog.events.KeyCodes.F4, // 115 + '63240': goog.events.KeyCodes.F5, // 116 + '63241': goog.events.KeyCodes.F6, // 117 + '63242': goog.events.KeyCodes.F7, // 118 + '63243': goog.events.KeyCodes.F8, // 119 + '63244': goog.events.KeyCodes.F9, // 120 + '63245': goog.events.KeyCodes.F10, // 121 + '63246': goog.events.KeyCodes.F11, // 122 + '63247': goog.events.KeyCodes.F12, // 123 + '63248': goog.events.KeyCodes.PRINT_SCREEN, // 44 + '63272': goog.events.KeyCodes.DELETE, // 46 + '63273': goog.events.KeyCodes.HOME, // 36 + '63275': goog.events.KeyCodes.END, // 35 + '63276': goog.events.KeyCodes.PAGE_UP, // 33 + '63277': goog.events.KeyCodes.PAGE_DOWN, // 34 + '63289': goog.events.KeyCodes.NUMLOCK, // 144 + '63302': goog.events.KeyCodes.INSERT // 45 }; /** - * Get the fill color. - * @return {ol.Color|string} Color. - * @api + * An enumeration of key identifiers currently part of the W3C draft for DOM3 + * and their mappings to keyCodes. + * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set + * This is currently supported in Safari and should be platform independent. + * @type {Object} + * @private */ -ol.style.Fill.prototype.getColor = function() { - return this.color_; +goog.events.KeyHandler.keyIdentifier_ = { + 'Up': goog.events.KeyCodes.UP, // 38 + 'Down': goog.events.KeyCodes.DOWN, // 40 + 'Left': goog.events.KeyCodes.LEFT, // 37 + 'Right': goog.events.KeyCodes.RIGHT, // 39 + 'Enter': goog.events.KeyCodes.ENTER, // 13 + 'F1': goog.events.KeyCodes.F1, // 112 + 'F2': goog.events.KeyCodes.F2, // 113 + 'F3': goog.events.KeyCodes.F3, // 114 + 'F4': goog.events.KeyCodes.F4, // 115 + 'F5': goog.events.KeyCodes.F5, // 116 + 'F6': goog.events.KeyCodes.F6, // 117 + 'F7': goog.events.KeyCodes.F7, // 118 + 'F8': goog.events.KeyCodes.F8, // 119 + 'F9': goog.events.KeyCodes.F9, // 120 + 'F10': goog.events.KeyCodes.F10, // 121 + 'F11': goog.events.KeyCodes.F11, // 122 + 'F12': goog.events.KeyCodes.F12, // 123 + 'U+007F': goog.events.KeyCodes.DELETE, // 46 + 'Home': goog.events.KeyCodes.HOME, // 36 + 'End': goog.events.KeyCodes.END, // 35 + 'PageUp': goog.events.KeyCodes.PAGE_UP, // 33 + 'PageDown': goog.events.KeyCodes.PAGE_DOWN, // 34 + 'Insert': goog.events.KeyCodes.INSERT // 45 }; /** - * Set the color. + * If true, the KeyEvent fires on keydown. Otherwise, it fires on keypress. * - * @param {ol.Color|string} color Color. - * @api + * @type {boolean} + * @private */ -ol.style.Fill.prototype.setColor = function(color) { - this.color_ = color; - this.checksum_ = undefined; -}; +goog.events.KeyHandler.USES_KEYDOWN_ = goog.userAgent.IE || + goog.userAgent.EDGE || + goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'); /** - * @inheritDoc + * If true, the alt key flag is saved during the key down and reused when + * handling the key press. FF on Mac does not set the alt flag in the key press + * event. + * @type {boolean} + * @private */ -ol.style.Fill.prototype.getChecksum = function() { - if (this.checksum_ === undefined) { - this.checksum_ = 'f' + (this.color_ ? - ol.color.asString(this.color_) : '-'); +goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_ = goog.userAgent.MAC && + goog.userAgent.GECKO; + + +/** + * Records the keycode for browsers that only returns the keycode for key up/ + * down events. For browser/key combinations that doesn't trigger a key pressed + * event it also fires the patched key event. + * @param {goog.events.BrowserEvent} e The key down event. + * @private + */ +goog.events.KeyHandler.prototype.handleKeyDown_ = function(e) { + // Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window + // before we've caught a key-up event. If the last-key was one of these we + // reset the state. + if (goog.userAgent.WEBKIT || goog.userAgent.EDGE) { + if (this.lastKey_ == goog.events.KeyCodes.CTRL && !e.ctrlKey || + this.lastKey_ == goog.events.KeyCodes.ALT && !e.altKey || + goog.userAgent.MAC && + this.lastKey_ == goog.events.KeyCodes.META && !e.metaKey) { + this.resetState(); + } } - return this.checksum_; + if (this.lastKey_ == -1) { + if (e.ctrlKey && e.keyCode != goog.events.KeyCodes.CTRL) { + this.lastKey_ = goog.events.KeyCodes.CTRL; + } else if (e.altKey && e.keyCode != goog.events.KeyCodes.ALT) { + this.lastKey_ = goog.events.KeyCodes.ALT; + } else if (e.metaKey && e.keyCode != goog.events.KeyCodes.META) { + this.lastKey_ = goog.events.KeyCodes.META; + } + } + + if (goog.events.KeyHandler.USES_KEYDOWN_ && + !goog.events.KeyCodes.firesKeyPressEvent(e.keyCode, + this.lastKey_, e.shiftKey, e.ctrlKey, e.altKey)) { + this.handleEvent(e); + } else { + this.keyCode_ = goog.events.KeyCodes.normalizeKeyCode(e.keyCode); + if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) { + this.altKey_ = e.altKey; + } + } }; -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Namespace with crypto related helper functions. + * Resets the stored previous values. Needed to be called for webkit which will + * not generate a key up for meta key operations. This should only be called + * when having finished with repeat key possiblities. */ - -goog.provide('goog.crypt'); - -goog.require('goog.array'); -goog.require('goog.asserts'); +goog.events.KeyHandler.prototype.resetState = function() { + this.lastKey_ = -1; + this.keyCode_ = -1; +}; /** - * Turns a string into an array of bytes; a "byte" being a JS number in the - * range 0-255. - * @param {string} str String value to arrify. - * @return {!Array<number>} Array of numbers corresponding to the - * UCS character codes of each character in str. + * Clears the stored previous key value, resetting the key repeat status. Uses + * -1 because the Safari 3 Windows beta reports 0 for certain keys (like Home + * and End.) + * @param {goog.events.BrowserEvent} e The keyup event. + * @private */ -goog.crypt.stringToByteArray = function(str) { - var output = [], p = 0; - for (var i = 0; i < str.length; i++) { - var c = str.charCodeAt(i); - while (c > 0xff) { - output[p++] = c & 0xff; - c >>= 8; - } - output[p++] = c; - } - return output; +goog.events.KeyHandler.prototype.handleKeyup_ = function(e) { + this.resetState(); + this.altKey_ = e.altKey; }; /** - * Turns an array of numbers into the string given by the concatenation of the - * characters to which the numbers correspond. - * @param {Array<number>} bytes Array of numbers representing characters. - * @return {string} Stringification of the array. + * Handles the events on the element. + * @param {goog.events.BrowserEvent} e The keyboard event sent from the + * browser. */ -goog.crypt.byteArrayToString = function(bytes) { - var CHUNK_SIZE = 8192; +goog.events.KeyHandler.prototype.handleEvent = function(e) { + var be = e.getBrowserEvent(); + var keyCode, charCode; + var altKey = be.altKey; - // Special-case the simple case for speed's sake. - if (bytes.length <= CHUNK_SIZE) { - return String.fromCharCode.apply(null, bytes); + // IE reports the character code in the keyCode field for keypress events. + // There are two exceptions however, Enter and Escape. + if (goog.userAgent.IE && e.type == goog.events.EventType.KEYPRESS) { + keyCode = this.keyCode_; + charCode = keyCode != goog.events.KeyCodes.ENTER && + keyCode != goog.events.KeyCodes.ESC ? + be.keyCode : 0; + + // Safari reports the character code in the keyCode field for keypress + // events but also has a charCode field. + } else if ((goog.userAgent.WEBKIT || goog.userAgent.EDGE) && + e.type == goog.events.EventType.KEYPRESS) { + keyCode = this.keyCode_; + charCode = be.charCode >= 0 && be.charCode < 63232 && + goog.events.KeyCodes.isCharacterKey(keyCode) ? + be.charCode : 0; + + // Opera reports the keycode or the character code in the keyCode field. + } else if (goog.userAgent.OPERA && !goog.userAgent.WEBKIT) { + keyCode = this.keyCode_; + charCode = goog.events.KeyCodes.isCharacterKey(keyCode) ? + be.keyCode : 0; + + // Mozilla reports the character code in the charCode field. + } else { + keyCode = be.keyCode || this.keyCode_; + charCode = be.charCode || 0; + if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) { + altKey = this.altKey_; + } + // On the Mac, shift-/ triggers a question mark char code and no key code + // (normalized to WIN_KEY), so we synthesize the latter. + if (goog.userAgent.MAC && + charCode == goog.events.KeyCodes.QUESTION_MARK && + keyCode == goog.events.KeyCodes.WIN_KEY) { + keyCode = goog.events.KeyCodes.SLASH; + } } - // The remaining logic splits conversion by chunks since - // Function#apply() has a maximum parameter count. - // See discussion: http://goo.gl/LrWmZ9 + keyCode = goog.events.KeyCodes.normalizeKeyCode(keyCode); + var key = keyCode; + var keyIdentifier = be.keyIdentifier; - var str = ''; - for (var i = 0; i < bytes.length; i += CHUNK_SIZE) { - var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE); - str += String.fromCharCode.apply(null, chunk); + // Correct the key value for certain browser-specific quirks. + if (keyCode) { + if (keyCode >= 63232 && keyCode in goog.events.KeyHandler.safariKey_) { + // NOTE(nicksantos): Safari 3 has fixed this problem, + // this is only needed for Safari 2. + key = goog.events.KeyHandler.safariKey_[keyCode]; + } else { + + // Safari returns 25 for Shift+Tab instead of 9. + if (keyCode == 25 && e.shiftKey) { + key = 9; + } + } + } else if (keyIdentifier && + keyIdentifier in goog.events.KeyHandler.keyIdentifier_) { + // This is needed for Safari Windows because it currently doesn't give a + // keyCode/which for non printable keys. + key = goog.events.KeyHandler.keyIdentifier_[keyIdentifier]; } - return str; + + // If we get the same keycode as a keydown/keypress without having seen a + // keyup event, then this event was caused by key repeat. + var repeat = key == this.lastKey_; + this.lastKey_ = key; + + var event = new goog.events.KeyEvent(key, charCode, repeat, be); + event.altKey = altKey; + this.dispatchEvent(event); }; /** - * Turns an array of numbers into the hex string given by the concatenation of - * the hex values to which the numbers correspond. - * @param {Uint8Array|Array<number>} array Array of numbers representing - * characters. - * @return {string} Hex string. + * Returns the element listened on for the real keyboard events. + * @return {Element|Document|null} The element listened on for the real + * keyboard events. */ -goog.crypt.byteArrayToHex = function(array) { - return goog.array.map(array, function(numByte) { - var hexByte = numByte.toString(16); - return hexByte.length > 1 ? hexByte : '0' + hexByte; - }).join(''); +goog.events.KeyHandler.prototype.getElement = function() { + return this.element_; }; /** - * Converts a hex string into an integer array. - * @param {string} hexString Hex string of 16-bit integers (two characters - * per integer). - * @return {!Array<number>} Array of {0,255} integers for the given string. + * Adds the proper key event listeners to the element. + * @param {Element|Document} element The element to listen on. + * @param {boolean=} opt_capture Whether to listen for browser events in + * capture phase (defaults to false). */ -goog.crypt.hexToByteArray = function(hexString) { - goog.asserts.assert(hexString.length % 2 == 0, - 'Key string length must be multiple of 2'); - var arr = []; - for (var i = 0; i < hexString.length; i += 2) { - arr.push(parseInt(hexString.substring(i, i + 2), 16)); +goog.events.KeyHandler.prototype.attach = function(element, opt_capture) { + if (this.keyUpKey_) { + this.detach(); } - return arr; -}; + this.element_ = element; -/** - * Converts a JS string to a UTF-8 "byte" array. - * @param {string} str 16-bit unicode string. - * @return {!Array<number>} UTF-8 byte array. - */ -goog.crypt.stringToUtf8ByteArray = function(str) { - // TODO(user): Use native implementations if/when available - var out = [], p = 0; - for (var i = 0; i < str.length; i++) { - var c = str.charCodeAt(i); - if (c < 128) { - out[p++] = c; - } else if (c < 2048) { - out[p++] = (c >> 6) | 192; - out[p++] = (c & 63) | 128; - } else { - out[p++] = (c >> 12) | 224; - out[p++] = ((c >> 6) & 63) | 128; - out[p++] = (c & 63) | 128; - } - } - return out; -}; + this.keyPressKey_ = goog.events.listen(this.element_, + goog.events.EventType.KEYPRESS, + this, + opt_capture); + + // Most browsers (Safari 2 being the notable exception) doesn't include the + // keyCode in keypress events (IE has the char code in the keyCode field and + // Mozilla only included the keyCode if there's no charCode). Thus we have to + // listen for keydown to capture the keycode. + this.keyDownKey_ = goog.events.listen(this.element_, + goog.events.EventType.KEYDOWN, + this.handleKeyDown_, + opt_capture, + this); -/** - * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode. - * @param {Uint8Array|Array<number>} bytes UTF-8 byte array. - * @return {string} 16-bit Unicode string. - */ -goog.crypt.utf8ByteArrayToString = function(bytes) { - // TODO(user): Use native implementations if/when available - var out = [], pos = 0, c = 0; - while (pos < bytes.length) { - var c1 = bytes[pos++]; - if (c1 < 128) { - out[c++] = String.fromCharCode(c1); - } else if (c1 > 191 && c1 < 224) { - var c2 = bytes[pos++]; - out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63); - } else { - var c2 = bytes[pos++]; - var c3 = bytes[pos++]; - out[c++] = String.fromCharCode( - (c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63); - } - } - return out.join(''); + this.keyUpKey_ = goog.events.listen(this.element_, + goog.events.EventType.KEYUP, + this.handleKeyup_, + opt_capture, + this); }; /** - * XOR two byte arrays. - * @param {!ArrayBufferView|!Array<number>} bytes1 Byte array 1. - * @param {!ArrayBufferView|!Array<number>} bytes2 Byte array 2. - * @return {!Array<number>} Resulting XOR of the two byte arrays. + * Removes the listeners that may exist. */ -goog.crypt.xorByteArray = function(bytes1, bytes2) { - goog.asserts.assert( - bytes1.length == bytes2.length, - 'XOR array lengths must match'); - - var result = []; - for (var i = 0; i < bytes1.length; i++) { - result.push(bytes1[i] ^ bytes2[i]); +goog.events.KeyHandler.prototype.detach = function() { + if (this.keyPressKey_) { + goog.events.unlistenByKey(this.keyPressKey_); + goog.events.unlistenByKey(this.keyDownKey_); + goog.events.unlistenByKey(this.keyUpKey_); + this.keyPressKey_ = null; + this.keyDownKey_ = null; + this.keyUpKey_ = null; } - return result; + this.element_ = null; + this.lastKey_ = -1; + this.keyCode_ = -1; }; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Abstract cryptographic hash interface. - * - * See goog.crypt.Sha1 and goog.crypt.Md5 for sample implementations. - * - */ -goog.provide('goog.crypt.Hash'); +/** @override */ +goog.events.KeyHandler.prototype.disposeInternal = function() { + goog.events.KeyHandler.superClass_.disposeInternal.call(this); + this.detach(); +}; /** - * Create a cryptographic hash instance. - * + * This class is used for the goog.events.KeyHandler.EventType.KEY event and + * it overrides the key code with the fixed key code. + * @param {number} keyCode The adjusted key code. + * @param {number} charCode The unicode character code. + * @param {boolean} repeat Whether this event was generated by keyboard repeat. + * @param {Event} browserEvent Browser event object. * @constructor - * @struct + * @extends {goog.events.BrowserEvent} + * @final */ -goog.crypt.Hash = function() { +goog.events.KeyEvent = function(keyCode, charCode, repeat, browserEvent) { + goog.events.BrowserEvent.call(this, browserEvent); + this.type = goog.events.KeyHandler.EventType.KEY; + /** - * The block size for the hasher. + * Keycode of key press. * @type {number} */ - this.blockSize = -1; -}; - - -/** - * Resets the internal accumulator. - */ -goog.crypt.Hash.prototype.reset = goog.abstractMethod; - - -/** - * Adds a byte array (array with values in [0-255] range) or a string (might - * only contain 8-bit, i.e., Latin1 characters) to the internal accumulator. - * - * Many hash functions operate on blocks of data and implement optimizations - * when a full chunk of data is readily available. Hence it is often preferable - * to provide large chunks of data (a kilobyte or more) than to repeatedly - * call the update method with few tens of bytes. If this is not possible, or - * not feasible, it might be good to provide data in multiplies of hash block - * size (often 64 bytes). Please see the implementation and performance tests - * of your favourite hash. - * - * @param {Array<number>|Uint8Array|string} bytes Data used for the update. - * @param {number=} opt_length Number of bytes to use. - */ -goog.crypt.Hash.prototype.update = goog.abstractMethod; + this.keyCode = keyCode; + /** + * Unicode character code. + * @type {number} + */ + this.charCode = charCode; -/** - * @return {!Array<number>} The finalized hash computed - * from the internal accumulator. - */ -goog.crypt.Hash.prototype.digest = goog.abstractMethod; + /** + * True if this event was generated by keyboard auto-repeat (i.e., the user is + * holding the key down.) + * @type {boolean} + */ + this.repeat = repeat; +}; +goog.inherits(goog.events.KeyEvent, goog.events.BrowserEvent); -// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// Copyright 2006 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -58334,5165 +57875,4308 @@ goog.crypt.Hash.prototype.digest = goog.abstractMethod; // limitations under the License. /** - * @fileoverview MD5 cryptographic hash. - * Implementation of http://tools.ietf.org/html/rfc1321 with common - * optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5). - * - * Usage: - * var md5 = new goog.crypt.Md5(); - * md5.update(bytes); - * var hash = md5.digest(); + * @fileoverview This event wrapper will dispatch an event when the user uses + * the mouse wheel to scroll an element. You can get the direction by checking + * the deltaX and deltaY properties of the event. * - * Performance: - * Chrome 23 ~680 Mbit/s - * Chrome 13 (in a VM) ~250 Mbit/s - * Firefox 6.0 (in a VM) ~100 Mbit/s - * IE9 (in a VM) ~27 Mbit/s - * Firefox 3.6 ~15 Mbit/s - * IE8 (in a VM) ~13 Mbit/s + * This class aims to smooth out inconsistencies between browser platforms with + * regards to mousewheel events, but we do not cover every possible + * software/hardware combination out there, some of which occasionally produce + * very large deltas in mousewheel events. If your application wants to guard + * against extremely large deltas, use the setMaxDeltaX and setMaxDeltaY APIs + * to set maximum values that make sense for your application. * + * @author arv@google.com (Erik Arvidsson) + * @see ../demos/mousewheelhandler.html */ -goog.provide('goog.crypt.Md5'); +goog.provide('goog.events.MouseWheelEvent'); +goog.provide('goog.events.MouseWheelHandler'); +goog.provide('goog.events.MouseWheelHandler.EventType'); -goog.require('goog.crypt.Hash'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.EventTarget'); +goog.require('goog.math'); +goog.require('goog.style'); +goog.require('goog.userAgent'); /** - * MD5 cryptographic hash constructor. + * This event handler allows you to catch mouse wheel events in a consistent + * manner. + * @param {Element|Document} element The element to listen to the mouse wheel + * event on. + * @param {boolean=} opt_capture Whether to handle the mouse wheel event in + * capture phase. * @constructor - * @extends {goog.crypt.Hash} - * @final - * @struct + * @extends {goog.events.EventTarget} */ -goog.crypt.Md5 = function() { - goog.crypt.Md5.base(this, 'constructor'); - - this.blockSize = 512 / 8; +goog.events.MouseWheelHandler = function(element, opt_capture) { + goog.events.EventTarget.call(this); /** - * Holds the current values of accumulated A-D variables (MD buffer). - * @type {!Array<number>} + * This is the element that we will listen to the real mouse wheel events on. + * @type {Element|Document} * @private */ - this.chain_ = new Array(4); + this.element_ = element; - /** - * A buffer holding the data until the whole block can be processed. - * @type {!Array<number>} - * @private - */ - this.block_ = new Array(this.blockSize); + var rtlElement = goog.dom.isElement(this.element_) ? + /** @type {Element} */ (this.element_) : + (this.element_ ? /** @type {Document} */ (this.element_).body : null); /** - * The length of yet-unprocessed data as collected in the block. - * @type {number} + * True if the element exists and is RTL, false otherwise. + * @type {boolean} * @private */ - this.blockLength_ = 0; + this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement); + + var type = goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel'; /** - * The total length of the message so far. - * @type {number} + * The key returned from the goog.events.listen. + * @type {goog.events.Key} * @private */ - this.totalLength_ = 0; + this.listenKey_ = goog.events.listen(this.element_, type, this, opt_capture); +}; +goog.inherits(goog.events.MouseWheelHandler, goog.events.EventTarget); - this.reset(); + +/** + * Enum type for the events fired by the mouse wheel handler. + * @enum {string} + */ +goog.events.MouseWheelHandler.EventType = { + MOUSEWHEEL: 'mousewheel' }; -goog.inherits(goog.crypt.Md5, goog.crypt.Hash); /** - * Integer rotation constants used by the abbreviated implementation. - * They are hardcoded in the unrolled implementation, so it is left - * here commented out. - * @type {Array<number>} + * Optional maximum magnitude for x delta on each mousewheel event. + * @type {number|undefined} * @private - * -goog.crypt.Md5.S_ = [ - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 -]; */ +goog.events.MouseWheelHandler.prototype.maxDeltaX_; + /** - * Sine function constants used by the abbreviated implementation. - * They are hardcoded in the unrolled implementation, so it is left - * here commented out. - * @type {Array<number>} + * Optional maximum magnitude for y delta on each mousewheel event. + * @type {number|undefined} * @private - * -goog.crypt.Md5.T_ = [ - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 -]; */ +goog.events.MouseWheelHandler.prototype.maxDeltaY_; -/** @override */ -goog.crypt.Md5.prototype.reset = function() { - this.chain_[0] = 0x67452301; - this.chain_[1] = 0xefcdab89; - this.chain_[2] = 0x98badcfe; - this.chain_[3] = 0x10325476; - - this.blockLength_ = 0; - this.totalLength_ = 0; +/** + * @param {number} maxDeltaX Maximum magnitude for x delta on each mousewheel + * event. Should be non-negative. + */ +goog.events.MouseWheelHandler.prototype.setMaxDeltaX = function(maxDeltaX) { + this.maxDeltaX_ = maxDeltaX; }; /** - * Internal compress helper function. It takes a block of data (64 bytes) - * and updates the accumulator. - * @param {Array<number>|Uint8Array|string} buf The block to compress. - * @param {number=} opt_offset Offset of the block in the buffer. - * @private + * @param {number} maxDeltaY Maximum magnitude for y delta on each mousewheel + * event. Should be non-negative. */ -goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) { - if (!opt_offset) { - opt_offset = 0; - } +goog.events.MouseWheelHandler.prototype.setMaxDeltaY = function(maxDeltaY) { + this.maxDeltaY_ = maxDeltaY; +}; - // We allocate the array every time, but it's cheap in practice. - var X = new Array(16); - // Get 16 little endian words. It is not worth unrolling this for Chrome 11. - if (goog.isString(buf)) { - for (var i = 0; i < 16; ++i) { - X[i] = (buf.charCodeAt(opt_offset++)) | - (buf.charCodeAt(opt_offset++) << 8) | - (buf.charCodeAt(opt_offset++) << 16) | - (buf.charCodeAt(opt_offset++) << 24); +/** + * Handles the events on the element. + * @param {goog.events.BrowserEvent} e The underlying browser event. + */ +goog.events.MouseWheelHandler.prototype.handleEvent = function(e) { + var deltaX = 0; + var deltaY = 0; + var detail = 0; + var be = e.getBrowserEvent(); + if (be.type == 'mousewheel') { + var wheelDeltaScaleFactor = 1; + if (goog.userAgent.IE || + goog.userAgent.WEBKIT && + (goog.userAgent.WINDOWS || goog.userAgent.isVersionOrHigher('532.0'))) { + // In IE we get a multiple of 120; we adjust to a multiple of 3 to + // represent number of lines scrolled (like Gecko). + // Newer versions of Webkit match IE behavior, and WebKit on + // Windows also matches IE behavior. + // See bug https://bugs.webkit.org/show_bug.cgi?id=24368 + wheelDeltaScaleFactor = 40; } - } else { - for (var i = 0; i < 16; ++i) { - X[i] = (buf[opt_offset++]) | - (buf[opt_offset++] << 8) | - (buf[opt_offset++] << 16) | - (buf[opt_offset++] << 24); + + detail = goog.events.MouseWheelHandler.smartScale_( + -be.wheelDelta, wheelDeltaScaleFactor); + if (goog.isDef(be.wheelDeltaX)) { + // Webkit has two properties to indicate directional scroll, and + // can scroll both directions at once. + deltaX = goog.events.MouseWheelHandler.smartScale_( + -be.wheelDeltaX, wheelDeltaScaleFactor); + deltaY = goog.events.MouseWheelHandler.smartScale_( + -be.wheelDeltaY, wheelDeltaScaleFactor); + } else { + deltaY = detail; } - } - var A = this.chain_[0]; - var B = this.chain_[1]; - var C = this.chain_[2]; - var D = this.chain_[3]; - var sum = 0; + // Historical note: Opera (pre 9.5) used to negate the detail value. + } else { // Gecko + // Gecko returns multiple of 3 (representing the number of lines scrolled) + detail = be.detail; - /* - * This is an abbreviated implementation, it is left here commented out for - * reference purposes. See below for an unrolled version in use. - * - var f, n, tmp; - for (var i = 0; i < 64; ++i) { + // Gecko sometimes returns really big values if the user changes settings to + // scroll a whole page per scroll + if (detail > 100) { + detail = 3; + } else if (detail < -100) { + detail = -3; + } - if (i < 16) { - f = (D ^ (B & (C ^ D))); - n = i; - } else if (i < 32) { - f = (C ^ (D & (B ^ C))); - n = (5 * i + 1) % 16; - } else if (i < 48) { - f = (B ^ C ^ D); - n = (3 * i + 5) % 16; + // Firefox 3.1 adds an axis field to the event to indicate direction of + // scroll. See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events + if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) { + deltaX = detail; } else { - f = (C ^ (B | (~D))); - n = (7 * i) % 16; + deltaY = detail; } + } - tmp = D; - D = C; - C = B; - sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff; - B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) | - (sum >>> (32 - goog.crypt.Md5.S_[i])); - A = tmp; + if (goog.isNumber(this.maxDeltaX_)) { + deltaX = goog.math.clamp(deltaX, -this.maxDeltaX_, this.maxDeltaX_); } - */ + if (goog.isNumber(this.maxDeltaY_)) { + deltaY = goog.math.clamp(deltaY, -this.maxDeltaY_, this.maxDeltaY_); + } + // Don't clamp 'detail', since it could be ambiguous which axis it refers to + // and because it's informally deprecated anyways. - /* - * This is an unrolled MD5 implementation, which gives ~30% speedup compared - * to the abbreviated implementation above, as measured on Chrome 11. It is - * important to keep 32-bit croppings to minimum and inline the integer - * rotation. - */ - sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff; - A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25)); - sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff; - D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20)); - sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff; - C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15)); - sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff; - B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10)); - sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff; - A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27)); - sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff; - D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23)); - sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff; - C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18)); - sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff; - B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12)); - sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff; - A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28)); - sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff; - D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21)); - sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff; - C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16)); - sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff; - B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9)); - sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff; - A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26)); - sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff; - D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22)); - sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff; - C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17)); - sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff; - B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11)); - - this.chain_[0] = (this.chain_[0] + A) & 0xffffffff; - this.chain_[1] = (this.chain_[1] + B) & 0xffffffff; - this.chain_[2] = (this.chain_[2] + C) & 0xffffffff; - this.chain_[3] = (this.chain_[3] + D) & 0xffffffff; -}; - - -/** @override */ -goog.crypt.Md5.prototype.update = function(bytes, opt_length) { - if (!goog.isDef(opt_length)) { - opt_length = bytes.length; + // For horizontal scrolling we need to flip the value for RTL grids. + if (this.isRtl_) { + deltaX = -deltaX; } - var lengthMinusBlock = opt_length - this.blockSize; - - // Copy some object properties to local variables in order to save on access - // time from inside the loop (~10% speedup was observed on Chrome 11). - var block = this.block_; - var blockLength = this.blockLength_; - var i = 0; + var newEvent = new goog.events.MouseWheelEvent(detail, be, deltaX, deltaY); + this.dispatchEvent(newEvent); +}; - // The outer while loop should execute at most twice. - while (i < opt_length) { - // When we have no data in the block to top up, we can directly process the - // input buffer (assuming it contains sufficient data). This gives ~30% - // speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that - // the data is provided in large chunks (or in multiples of 64 bytes). - if (blockLength == 0) { - while (i <= lengthMinusBlock) { - this.compress_(bytes, i); - i += this.blockSize; - } - } - if (goog.isString(bytes)) { - while (i < opt_length) { - block[blockLength++] = bytes.charCodeAt(i++); - if (blockLength == this.blockSize) { - this.compress_(block); - blockLength = 0; - // Jump to the outer loop so we use the full-block optimization. - break; - } - } - } else { - while (i < opt_length) { - block[blockLength++] = bytes[i++]; - if (blockLength == this.blockSize) { - this.compress_(block); - blockLength = 0; - // Jump to the outer loop so we use the full-block optimization. - break; - } - } - } +/** + * Helper for scaling down a mousewheel delta by a scale factor, if appropriate. + * @param {number} mouseWheelDelta Delta from a mouse wheel event. Expected to + * be an integer. + * @param {number} scaleFactor Factor to scale the delta down by. Expected to + * be an integer. + * @return {number} Scaled-down delta value, or the original delta if the + * scaleFactor does not appear to be applicable. + * @private + */ +goog.events.MouseWheelHandler.smartScale_ = function(mouseWheelDelta, + scaleFactor) { + // The basic problem here is that in Webkit on Mac and Linux, we can get two + // very different types of mousewheel events: from continuous devices + // (touchpads, Mighty Mouse) or non-continuous devices (normal wheel mice). + // + // Non-continuous devices in Webkit get their wheel deltas scaled up to + // behave like IE. Continuous devices return much smaller unscaled values + // (which most of the time will not be cleanly divisible by the IE scale + // factor), so we should not try to normalize them down. + // + // Detailed discussion: + // https://bugs.webkit.org/show_bug.cgi?id=29601 + // http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063 + if (goog.userAgent.WEBKIT && + (goog.userAgent.MAC || goog.userAgent.LINUX) && + (mouseWheelDelta % scaleFactor) != 0) { + return mouseWheelDelta; + } else { + return mouseWheelDelta / scaleFactor; } - - this.blockLength_ = blockLength; - this.totalLength_ += opt_length; }; /** @override */ -goog.crypt.Md5.prototype.digest = function() { - // This must accommodate at least 1 padding byte (0x80), 8 bytes of - // total bitlength, and must end at a 64-byte boundary. - var pad = new Array((this.blockLength_ < 56 ? - this.blockSize : - this.blockSize * 2) - this.blockLength_); - - // Add padding: 0x80 0x00* - pad[0] = 0x80; - for (var i = 1; i < pad.length - 8; ++i) { - pad[i] = 0; - } - // Add the total number of bits, little endian 64-bit integer. - var totalBits = this.totalLength_ * 8; - for (var i = pad.length - 8; i < pad.length; ++i) { - pad[i] = totalBits & 0xff; - totalBits /= 0x100; // Don't use bit-shifting here! - } - this.update(pad); - - var digest = new Array(16); - var n = 0; - for (var i = 0; i < 4; ++i) { - for (var j = 0; j < 32; j += 8) { - digest[n++] = (this.chain_[i] >>> j) & 0xff; - } - } - return digest; +goog.events.MouseWheelHandler.prototype.disposeInternal = function() { + goog.events.MouseWheelHandler.superClass_.disposeInternal.call(this); + goog.events.unlistenByKey(this.listenKey_); + this.listenKey_ = null; }; -goog.provide('ol.style.Stroke'); - -goog.require('goog.crypt'); -goog.require('goog.crypt.Md5'); -goog.require('ol.color'); -goog.require('ol.structs.IHasChecksum'); - /** - * @classdesc - * Set stroke style for vector features. - * Note that the defaults given are the Canvas defaults, which will be used if - * option is not defined. The `get` functions return whatever was entered in - * the options; they will not return the default. + * A base class for mouse wheel events. This is used with the + * MouseWheelHandler. * + * @param {number} detail The number of rows the user scrolled. + * @param {Event} browserEvent Browser event object. + * @param {number} deltaX The number of rows the user scrolled in the X + * direction. + * @param {number} deltaY The number of rows the user scrolled in the Y + * direction. * @constructor - * @param {olx.style.StrokeOptions=} opt_options Options. - * @implements {ol.structs.IHasChecksum} - * @api + * @extends {goog.events.BrowserEvent} + * @final */ -ol.style.Stroke = function(opt_options) { +goog.events.MouseWheelEvent = function(detail, browserEvent, deltaX, deltaY) { + goog.events.BrowserEvent.call(this, browserEvent); - var options = opt_options || {}; + this.type = goog.events.MouseWheelHandler.EventType.MOUSEWHEEL; /** - * @private - * @type {ol.Color|string} + * The number of lines the user scrolled + * @type {number} + * NOTE: Informally deprecated. Use deltaX and deltaY instead, they provide + * more information. */ - this.color_ = options.color !== undefined ? options.color : null; + this.detail = detail; /** - * @private - * @type {string|undefined} + * The number of "lines" scrolled in the X direction. + * + * Note that not all browsers provide enough information to distinguish + * horizontal and vertical scroll events, so for these unsupported browsers, + * we will always have a deltaX of 0, even if the user scrolled their mouse + * wheel or trackpad sideways. + * + * Currently supported browsers are Webkit and Firefox 3.1 or later. + * + * @type {number} */ - this.lineCap_ = options.lineCap; + this.deltaX = deltaX; /** - * @private - * @type {Array.<number>} + * The number of lines scrolled in the Y direction. + * @type {number} */ - this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null; + this.deltaY = deltaY; +}; +goog.inherits(goog.events.MouseWheelEvent, goog.events.BrowserEvent); - /** - * @private - * @type {string|undefined} - */ - this.lineJoin_ = options.lineJoin; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - /** - * @private - * @type {number|undefined} - */ - this.miterLimit_ = options.miterLimit; +/** + * @fileoverview Basic strippable logging definitions. + * @see http://go/closurelogging + * + * @author johnlenz@google.com (John Lenz) + */ - /** - * @private - * @type {number|undefined} - */ - this.width_ = options.width; +goog.provide('goog.log'); +goog.provide('goog.log.Level'); +goog.provide('goog.log.LogRecord'); +goog.provide('goog.log.Logger'); - /** - * @private - * @type {string|undefined} - */ - this.checksum_ = undefined; -}; +goog.require('goog.debug'); +goog.require('goog.debug.LogManager'); +goog.require('goog.debug.LogRecord'); +goog.require('goog.debug.Logger'); -/** - * Get the stroke color. - * @return {ol.Color|string} Color. - * @api - */ -ol.style.Stroke.prototype.getColor = function() { - return this.color_; -}; +/** @define {boolean} Whether logging is enabled. */ +goog.define('goog.log.ENABLED', goog.debug.LOGGING_ENABLED); -/** - * Get the line cap type for the stroke. - * @return {string|undefined} Line cap. - * @api - */ -ol.style.Stroke.prototype.getLineCap = function() { - return this.lineCap_; -}; +/** @const */ +goog.log.ROOT_LOGGER_NAME = goog.debug.Logger.ROOT_LOGGER_NAME; + /** - * Get the line dash style for the stroke. - * @return {Array.<number>} Line dash. - * @api + * @constructor + * @final */ -ol.style.Stroke.prototype.getLineDash = function() { - return this.lineDash_; -}; +goog.log.Logger = goog.debug.Logger; + /** - * Get the line join type for the stroke. - * @return {string|undefined} Line join. - * @api + * @constructor + * @final */ -ol.style.Stroke.prototype.getLineJoin = function() { - return this.lineJoin_; -}; +goog.log.Level = goog.debug.Logger.Level; + /** - * Get the miter limit for the stroke. - * @return {number|undefined} Miter limit. - * @api + * @constructor + * @final */ -ol.style.Stroke.prototype.getMiterLimit = function() { - return this.miterLimit_; -}; +goog.log.LogRecord = goog.debug.LogRecord; /** - * Get the stroke width. - * @return {number|undefined} Width. - * @api + * Finds or creates a logger for a named subsystem. If a logger has already been + * created with the given name it is returned. Otherwise a new logger is + * created. If a new logger is created its log level will be configured based + * on the goog.debug.LogManager configuration and it will configured to also + * send logging output to its parent's handlers. + * @see goog.debug.LogManager + * + * @param {string} name A name for the logger. This should be a dot-separated + * name and should normally be based on the package name or class name of + * the subsystem, such as goog.net.BrowserChannel. + * @param {goog.log.Level=} opt_level If provided, override the + * default logging level with the provided level. + * @return {goog.log.Logger} The named logger or null if logging is disabled. */ -ol.style.Stroke.prototype.getWidth = function() { - return this.width_; +goog.log.getLogger = function(name, opt_level) { + if (goog.log.ENABLED) { + var logger = goog.debug.LogManager.getLogger(name); + if (opt_level && logger) { + logger.setLevel(opt_level); + } + return logger; + } else { + return null; + } }; +// TODO(johnlenz): try to tighten the types to these functions. /** - * Set the color. - * - * @param {ol.Color|string} color Color. - * @api + * Adds a handler to the logger. This doesn't use the event system because + * we want to be able to add logging to the event system. + * @param {goog.log.Logger} logger + * @param {Function} handler Handler function to add. */ -ol.style.Stroke.prototype.setColor = function(color) { - this.color_ = color; - this.checksum_ = undefined; +goog.log.addHandler = function(logger, handler) { + if (goog.log.ENABLED && logger) { + logger.addHandler(handler); + } }; /** - * Set the line cap. - * - * @param {string|undefined} lineCap Line cap. - * @api + * Removes a handler from the logger. This doesn't use the event system because + * we want to be able to add logging to the event system. + * @param {goog.log.Logger} logger + * @param {Function} handler Handler function to remove. + * @return {boolean} Whether the handler was removed. */ -ol.style.Stroke.prototype.setLineCap = function(lineCap) { - this.lineCap_ = lineCap; - this.checksum_ = undefined; +goog.log.removeHandler = function(logger, handler) { + if (goog.log.ENABLED && logger) { + return logger.removeHandler(handler); + } else { + return false; + } }; /** - * Set the line dash. - * - * @param {Array.<number>} lineDash Line dash. - * @api + * Logs a message. If the logger is currently enabled for the + * given message level then the given message is forwarded to all the + * registered output Handler objects. + * @param {goog.log.Logger} logger + * @param {goog.log.Level} level One of the level identifiers. + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error|Object=} opt_exception An exception associated with the + * message. */ -ol.style.Stroke.prototype.setLineDash = function(lineDash) { - this.lineDash_ = lineDash; - this.checksum_ = undefined; +goog.log.log = function(logger, level, msg, opt_exception) { + if (goog.log.ENABLED && logger) { + logger.log(level, msg, opt_exception); + } }; /** - * Set the line join. - * - * @param {string|undefined} lineJoin Line join. - * @api + * Logs a message at the Level.SEVERE level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.log.Logger} logger + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.style.Stroke.prototype.setLineJoin = function(lineJoin) { - this.lineJoin_ = lineJoin; - this.checksum_ = undefined; +goog.log.error = function(logger, msg, opt_exception) { + if (goog.log.ENABLED && logger) { + logger.severe(msg, opt_exception); + } }; /** - * Set the miter limit. - * - * @param {number|undefined} miterLimit Miter limit. - * @api + * Logs a message at the Level.WARNING level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.log.Logger} logger + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.style.Stroke.prototype.setMiterLimit = function(miterLimit) { - this.miterLimit_ = miterLimit; - this.checksum_ = undefined; +goog.log.warning = function(logger, msg, opt_exception) { + if (goog.log.ENABLED && logger) { + logger.warning(msg, opt_exception); + } }; /** - * Set the width. - * - * @param {number|undefined} width Width. - * @api + * Logs a message at the Level.INFO level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.log.Logger} logger + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.style.Stroke.prototype.setWidth = function(width) { - this.width_ = width; - this.checksum_ = undefined; +goog.log.info = function(logger, msg, opt_exception) { + if (goog.log.ENABLED && logger) { + logger.info(msg, opt_exception); + } }; /** - * @inheritDoc + * Logs a message at the Level.Fine level. + * If the logger is currently enabled for the given message level then the + * given message is forwarded to all the registered output Handler objects. + * @param {goog.log.Logger} logger + * @param {goog.debug.Loggable} msg The message to log. + * @param {Error=} opt_exception An exception associated with the message. */ -ol.style.Stroke.prototype.getChecksum = function() { - if (this.checksum_ === undefined) { - var raw = 's' + - (this.color_ ? - ol.color.asString(this.color_) : '-') + ',' + - (this.lineCap_ !== undefined ? - this.lineCap_.toString() : '-') + ',' + - (this.lineDash_ ? - this.lineDash_.toString() : '-') + ',' + - (this.lineJoin_ !== undefined ? - this.lineJoin_ : '-') + ',' + - (this.miterLimit_ !== undefined ? - this.miterLimit_.toString() : '-') + ',' + - (this.width_ !== undefined ? - this.width_.toString() : '-'); - - var md5 = new goog.crypt.Md5(); - md5.update(raw); - this.checksum_ = goog.crypt.byteArrayToString(md5.digest()); +goog.log.fine = function(logger, msg, opt_exception) { + if (goog.log.ENABLED && logger) { + logger.fine(msg, opt_exception); } - - return this.checksum_; }; -goog.provide('ol.style.Circle'); +// Based on https://github.com/Polymer/PointerEvents -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('ol'); -goog.require('ol.color'); -goog.require('ol.has'); -goog.require('ol.render.canvas'); -goog.require('ol.structs.IHasChecksum'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.Stroke'); +// Copyright (c) 2013 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +goog.provide('ol.pointer.PointerEvent'); + + +goog.require('goog.events'); +goog.require('goog.events.Event'); /** - * @classdesc - * Set circle style for vector features. + * A class for pointer events. + * + * This class is used as an abstraction for mouse events, + * touch events and even native pointer events. * * @constructor - * @param {olx.style.CircleOptions=} opt_options Options. - * @extends {ol.style.Image} - * @implements {ol.structs.IHasChecksum} - * @api + * @extends {goog.events.Event} + * @param {string} type The type of the event to create. + * @param {goog.events.BrowserEvent} browserEvent + * @param {Object.<string, ?>=} opt_eventDict An optional dictionary of + * initial event properties. */ -ol.style.Circle = function(opt_options) { +ol.pointer.PointerEvent = function(type, browserEvent, opt_eventDict) { + goog.base(this, type); - var options = opt_options || {}; + /** + * @const + * @type {goog.events.BrowserEvent} + */ + this.browserEvent = browserEvent; + + var eventDict = opt_eventDict ? opt_eventDict : {}; /** - * @private - * @type {Array.<string>} + * @type {number} */ - this.checksums_ = null; + this.buttons = this.getButtons_(eventDict); /** - * @private - * @type {HTMLCanvasElement} + * @type {number} */ - this.canvas_ = null; + this.pressure = this.getPressure_(eventDict, this.buttons); + + // MouseEvent related properties /** - * @private - * @type {HTMLCanvasElement} + * @type {boolean} */ - this.hitDetectionCanvas_ = null; + this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false; /** - * @private - * @type {ol.style.Fill} + * @type {boolean} */ - this.fill_ = options.fill !== undefined ? options.fill : null; + this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false; /** - * @private - * @type {ol.style.Stroke} + * @type {Object} */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; + this.view = 'view' in eventDict ? eventDict['view'] : null; /** - * @private * @type {number} */ - this.radius_ = options.radius; + this.detail = 'detail' in eventDict ? eventDict['detail'] : null; /** - * @private - * @type {Array.<number>} + * @type {number} */ - this.origin_ = [0, 0]; + this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0; /** - * @private - * @type {Array.<number>} + * @type {number} */ - this.anchor_ = null; + this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0; /** - * @private - * @type {ol.Size} + * @type {number} */ - this.size_ = null; + this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0; /** - * @private - * @type {ol.Size} + * @type {number} */ - this.imageSize_ = null; + this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0; /** - * @private - * @type {ol.Size} + * @type {boolean} */ - this.hitDetectionImageSize_ = null; + this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false; - this.render_(options.atlasManager); + /** + * @type {boolean} + */ + this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false; /** * @type {boolean} */ - var snapToPixel = options.snapToPixel !== undefined ? - options.snapToPixel : true; + this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false; - goog.base(this, { - opacity: 1, - rotateWithView: false, - rotation: 0, - scale: 1, - snapToPixel: snapToPixel - }); + /** + * @type {boolean} + */ + this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false; -}; -goog.inherits(ol.style.Circle, ol.style.Image); + /** + * @type {number} + */ + this.button = 'button' in eventDict ? eventDict['button'] : 0; + /** + * @type {Node} + */ + this.relatedTarget = 'relatedTarget' in eventDict ? + eventDict['relatedTarget'] : null; -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getAnchor = function() { - return this.anchor_; -}; + // PointerEvent related properties + /** + * @const + * @type {number} + */ + this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0; -/** - * Get the fill style for the circle. - * @return {ol.style.Fill} Fill style. - * @api - */ -ol.style.Circle.prototype.getFill = function() { - return this.fill_; -}; + /** + * @type {number} + */ + this.width = 'width' in eventDict ? eventDict['width'] : 0; + /** + * @type {number} + */ + this.height = 'height' in eventDict ? eventDict['height'] : 0; -/** - * @inheritDoc - */ -ol.style.Circle.prototype.getHitDetectionImage = function(pixelRatio) { - return this.hitDetectionCanvas_; + /** + * @type {number} + */ + this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0; + + /** + * @type {number} + */ + this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0; + + /** + * @type {string} + */ + this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : ''; + + /** + * @type {number} + */ + this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0; + + /** + * @type {boolean} + */ + this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false; + + // keep the semantics of preventDefault + if (browserEvent.preventDefault) { + this.preventDefault = function() { + browserEvent.preventDefault(); + }; + } }; +goog.inherits(ol.pointer.PointerEvent, goog.events.Event); /** - * Get the image used to render the circle. - * @param {number} pixelRatio Pixel ratio. - * @return {HTMLCanvasElement} Canvas element. - * @api + * @private + * @param {Object.<string, ?>} eventDict + * @return {number} */ -ol.style.Circle.prototype.getImage = function(pixelRatio) { - return this.canvas_; +ol.pointer.PointerEvent.prototype.getButtons_ = function(eventDict) { + // According to the w3c spec, + // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button + // MouseEvent.button == 0 can mean either no mouse button depressed, or the + // left mouse button depressed. + // + // As of now, the only way to distinguish between the two states of + // MouseEvent.button is by using the deprecated MouseEvent.which property, as + // this maps mouse buttons to positive integers > 0, and uses 0 to mean that + // no mouse button is held. + // + // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation, + // but initMouseEvent does not expose an argument with which to set + // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set + // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations + // of app developers. + // + // The only way to propagate the correct state of MouseEvent.which and + // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0 + // is to call initMouseEvent with a buttonArg value of -1. + // + // This is fixed with DOM Level 4's use of buttons + var buttons; + if (eventDict.buttons || ol.pointer.PointerEvent.HAS_BUTTONS) { + buttons = eventDict.buttons; + } else { + switch (eventDict.which) { + case 1: buttons = 1; break; + case 2: buttons = 4; break; + case 3: buttons = 2; break; + default: buttons = 0; + } + } + return buttons; }; /** - * @inheritDoc + * @private + * @param {Object.<string, ?>} eventDict + * @param {number} buttons + * @return {number} */ -ol.style.Circle.prototype.getImageState = function() { - return ol.style.ImageState.LOADED; +ol.pointer.PointerEvent.prototype.getPressure_ = function(eventDict, buttons) { + // Spec requires that pointers without pressure specified use 0.5 for down + // state and 0 for up state. + var pressure = 0; + if (eventDict.pressure) { + pressure = eventDict.pressure; + } else { + pressure = buttons ? 0.5 : 0; + } + return pressure; }; /** - * @inheritDoc + * Is the `buttons` property supported? + * @type {boolean} */ -ol.style.Circle.prototype.getImageSize = function() { - return this.imageSize_; -}; +ol.pointer.PointerEvent.HAS_BUTTONS = false; /** - * @inheritDoc + * Checks if the `buttons` property is supported. */ -ol.style.Circle.prototype.getHitDetectionImageSize = function() { - return this.hitDetectionImageSize_; -}; +(function() { + try { + var ev = new MouseEvent('click', {buttons: 1}); + ol.pointer.PointerEvent.HAS_BUTTONS = ev.buttons === 1; + } catch (e) { + } +})(); + +goog.provide('ol.pointer.EventSource'); + +goog.require('goog.events.BrowserEvent'); + /** - * @inheritDoc + * @param {ol.pointer.PointerEventHandler} dispatcher + * @param {!Object.<string, function(goog.events.BrowserEvent)>} mapping + * @constructor */ -ol.style.Circle.prototype.getOrigin = function() { - return this.origin_; +ol.pointer.EventSource = function(dispatcher, mapping) { + /** + * @type {ol.pointer.PointerEventHandler} + */ + this.dispatcher = dispatcher; + + /** + * @private + * @const + * @type {!Object.<string, function(goog.events.BrowserEvent)>} + */ + this.mapping_ = mapping; }; /** - * Get the circle radius. - * @return {number} Radius. - * @api + * List of events supported by this source. + * @return {Array.<string>} Event names */ -ol.style.Circle.prototype.getRadius = function() { - return this.radius_; +ol.pointer.EventSource.prototype.getEvents = function() { + return Object.keys(this.mapping_); }; /** - * @inheritDoc + * Returns a mapping between the supported event types and + * the handlers that should handle an event. + * @return {Object.<string, function(goog.events.BrowserEvent)>} + * Event/Handler mapping */ -ol.style.Circle.prototype.getSize = function() { - return this.size_; +ol.pointer.EventSource.prototype.getMapping = function() { + return this.mapping_; }; /** - * Get the stroke style for the circle. - * @return {ol.style.Stroke} Stroke style. - * @api + * Returns the handler that should handle a given event type. + * @param {string} eventType + * @return {function(goog.events.BrowserEvent)} Handler */ -ol.style.Circle.prototype.getStroke = function() { - return this.stroke_; +ol.pointer.EventSource.prototype.getHandlerForEvent = function(eventType) { + return this.mapping_[eventType]; }; +// Based on https://github.com/Polymer/PointerEvents + +// Copyright (c) 2013 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +goog.provide('ol.pointer.MouseSource'); + +goog.require('ol.pointer.EventSource'); + + /** - * @inheritDoc + * @param {ol.pointer.PointerEventHandler} dispatcher + * @constructor + * @extends {ol.pointer.EventSource} */ -ol.style.Circle.prototype.listenImageChange = ol.nullFunction; +ol.pointer.MouseSource = function(dispatcher) { + var mapping = { + 'mousedown': this.mousedown, + 'mousemove': this.mousemove, + 'mouseup': this.mouseup, + 'mouseover': this.mouseover, + 'mouseout': this.mouseout + }; + goog.base(this, dispatcher, mapping); + + /** + * @const + * @type {Object.<string, goog.events.BrowserEvent|Object>} + */ + this.pointerMap = dispatcher.pointerMap; + + /** + * @const + * @type {Array.<ol.Pixel>} + */ + this.lastTouches = []; +}; +goog.inherits(ol.pointer.MouseSource, ol.pointer.EventSource); /** - * @inheritDoc + * @const + * @type {number} */ -ol.style.Circle.prototype.load = ol.nullFunction; +ol.pointer.MouseSource.POINTER_ID = 1; /** - * @inheritDoc + * @const + * @type {string} */ -ol.style.Circle.prototype.unlistenImageChange = ol.nullFunction; +ol.pointer.MouseSource.POINTER_TYPE = 'mouse'; /** - * @typedef {{strokeStyle: (string|undefined), strokeWidth: number, - * size: number, lineDash: Array.<number>}} + * Radius around touchend that swallows mouse events. + * + * @const + * @type {number} */ -ol.style.Circle.RenderOptions; +ol.pointer.MouseSource.DEDUP_DIST = 25; /** + * Detect if a mouse event was simulated from a touch by + * checking if previously there was a touch event at the + * same position. + * + * FIXME - Known problem with the native Android browser on + * Samsung GT-I9100 (Android 4.1.2): + * In case the page is scrolled, this function does not work + * correctly when a canvas is used (WebGL or canvas renderer). + * Mouse listeners on canvas elements (for this browser), create + * two mouse events: One 'good' and one 'bad' one (on other browsers or + * when a div is used, there is only one event). For the 'bad' one, + * clientX/clientY and also pageX/pageY are wrong when the page + * is scrolled. Because of that, this function can not detect if + * the events were simulated from a touch event. As result, a + * pointer event at a wrong position is dispatched, which confuses + * the map interactions. + * It is unclear, how one can get the correct position for the event + * or detect that the positions are invalid. + * * @private - * @param {ol.style.AtlasManager|undefined} atlasManager + * @param {goog.events.BrowserEvent} inEvent + * @return {boolean} True, if the event was generated by a touch. */ -ol.style.Circle.prototype.render_ = function(atlasManager) { - var imageSize; - var lineDash = null; - var strokeStyle; - var strokeWidth = 0; - - if (this.stroke_) { - strokeStyle = ol.color.asString(this.stroke_.getColor()); - strokeWidth = this.stroke_.getWidth(); - if (strokeWidth === undefined) { - strokeWidth = ol.render.canvas.defaultLineWidth; - } - lineDash = this.stroke_.getLineDash(); - if (!ol.has.CANVAS_LINE_DASH) { - lineDash = null; +ol.pointer.MouseSource.prototype.isEventSimulatedFromTouch_ = + function(inEvent) { + var lts = this.lastTouches; + var x = inEvent.clientX, y = inEvent.clientY; + for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) { + // simulated mouse events will be swallowed near a primary touchend + var dx = Math.abs(x - t[0]), dy = Math.abs(y - t[1]); + if (dx <= ol.pointer.MouseSource.DEDUP_DIST && + dy <= ol.pointer.MouseSource.DEDUP_DIST) { + return true; } } + return false; +}; - var size = 2 * (this.radius_ + strokeWidth) + 1; +/** + * Creates a copy of the original event that will be used + * for the fake pointer event. + * + * @param {goog.events.BrowserEvent} inEvent + * @param {ol.pointer.PointerEventHandler} dispatcher + * @return {Object} + */ +ol.pointer.MouseSource.prepareEvent = function(inEvent, dispatcher) { + var e = dispatcher.cloneEvent(inEvent, inEvent.getBrowserEvent()); - /** @type {ol.style.Circle.RenderOptions} */ - var renderOptions = { - strokeStyle: strokeStyle, - strokeWidth: strokeWidth, - size: size, - lineDash: lineDash + // forward mouse preventDefault + var pd = e.preventDefault; + e.preventDefault = function() { + inEvent.preventDefault(); + pd(); }; - if (atlasManager === undefined) { - // no atlas manager is used, create a new canvas - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - this.canvas_.height = size; - this.canvas_.width = size; + e.pointerId = ol.pointer.MouseSource.POINTER_ID; + e.isPrimary = true; + e.pointerType = ol.pointer.MouseSource.POINTER_TYPE; - // canvas.width and height are rounded to the closest integer - size = this.canvas_.width; - imageSize = size; - - // draw the circle on the canvas - var context = /** @type {CanvasRenderingContext2D} */ - (this.canvas_.getContext('2d')); - this.draw_(renderOptions, context, 0, 0); - - this.createHitDetectionCanvas_(renderOptions); - } else { - // an atlas manager is used, add the symbol to an atlas - size = Math.round(size); - - var hasCustomHitDetectionImage = !this.fill_; - var renderHitDetectionCallback; - if (hasCustomHitDetectionImage) { - // render the hit-detection image into a separate atlas image - renderHitDetectionCallback = - goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); - } - - var id = this.getChecksum(); - var info = atlasManager.add( - id, size, size, goog.bind(this.draw_, this, renderOptions), - renderHitDetectionCallback); - goog.asserts.assert(info, 'circle radius is too large'); - - this.canvas_ = info.image; - this.origin_ = [info.offsetX, info.offsetY]; - imageSize = info.image.width; - - if (hasCustomHitDetectionImage) { - this.hitDetectionCanvas_ = info.hitImage; - this.hitDetectionImageSize_ = - [info.hitImage.width, info.hitImage.height]; - } else { - this.hitDetectionCanvas_ = this.canvas_; - this.hitDetectionImageSize_ = [imageSize, imageSize]; - } - } - - this.anchor_ = [size / 2, size / 2]; - this.size_ = [size, size]; - this.imageSize_ = [imageSize, imageSize]; + return e; }; /** - * @private - * @param {ol.style.Circle.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). + * Handler for `mousedown`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Circle.prototype.draw_ = function(renderOptions, context, x, y) { - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); - - // then move to (x, y) - context.translate(x, y); - - context.beginPath(); - context.arc( - renderOptions.size / 2, renderOptions.size / 2, - this.radius_, 0, 2 * Math.PI, true); - - if (this.fill_) { - context.fillStyle = ol.color.asString(this.fill_.getColor()); - context.fill(); - } - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); +ol.pointer.MouseSource.prototype.mousedown = function(inEvent) { + if (!this.isEventSimulatedFromTouch_(inEvent)) { + // TODO(dfreedman) workaround for some elements not sending mouseup + // http://crbug/149091 + if (ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap) { + this.cancel(inEvent); } - context.stroke(); + var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); + this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()] = inEvent; + this.dispatcher.down(e, inEvent); } - context.closePath(); }; /** - * @private - * @param {ol.style.Circle.RenderOptions} renderOptions + * Handler for `mousemove`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) { - this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; - if (this.fill_) { - this.hitDetectionCanvas_ = this.canvas_; - return; +ol.pointer.MouseSource.prototype.mousemove = function(inEvent) { + if (!this.isEventSimulatedFromTouch_(inEvent)) { + var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); + this.dispatcher.move(e, inEvent); } - - // if no fill style is set, create an extra hit-detection image with a - // default fill style - this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - var canvas = this.hitDetectionCanvas_; - - canvas.height = renderOptions.size; - canvas.width = renderOptions.size; - - var context = /** @type {CanvasRenderingContext2D} */ - (canvas.getContext('2d')); - this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); }; /** - * @private - * @param {ol.style.Circle.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). + * Handler for `mouseup`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Circle.prototype.drawHitDetectionCanvas_ = - function(renderOptions, context, x, y) { - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); - - // then move to (x, y) - context.translate(x, y); - - context.beginPath(); - context.arc( - renderOptions.size / 2, renderOptions.size / 2, - this.radius_, 0, 2 * Math.PI, true); +ol.pointer.MouseSource.prototype.mouseup = function(inEvent) { + if (!this.isEventSimulatedFromTouch_(inEvent)) { + var p = this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()]; - context.fillStyle = ol.color.asString(ol.render.canvas.defaultFillStyle); - context.fill(); - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); + if (p && p.button === inEvent.button) { + var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); + this.dispatcher.up(e, inEvent); + this.cleanupMouse(); } - context.stroke(); } - context.closePath(); }; /** - * @inheritDoc + * Handler for `mouseover`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Circle.prototype.getChecksum = function() { - var strokeChecksum = this.stroke_ ? - this.stroke_.getChecksum() : '-'; - var fillChecksum = this.fill_ ? - this.fill_.getChecksum() : '-'; +ol.pointer.MouseSource.prototype.mouseover = function(inEvent) { + if (!this.isEventSimulatedFromTouch_(inEvent)) { + var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); + this.dispatcher.enterOver(e, inEvent); + } +}; - var recalculate = !this.checksums_ || - (strokeChecksum != this.checksums_[1] || - fillChecksum != this.checksums_[2] || - this.radius_ != this.checksums_[3]); - if (recalculate) { - var checksum = 'c' + strokeChecksum + fillChecksum + - (this.radius_ !== undefined ? this.radius_.toString() : '-'); - this.checksums_ = [checksum, strokeChecksum, fillChecksum, this.radius_]; +/** + * Handler for `mouseout`. + * + * @param {goog.events.BrowserEvent} inEvent + */ +ol.pointer.MouseSource.prototype.mouseout = function(inEvent) { + if (!this.isEventSimulatedFromTouch_(inEvent)) { + var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); + this.dispatcher.leaveOut(e, inEvent); } - - return this.checksums_[0]; }; -goog.provide('ol.style.GeometryFunction'); -goog.provide('ol.style.Style'); -goog.provide('ol.style.StyleFunction'); -goog.provide('ol.style.defaultGeometryFunction'); - -goog.require('goog.asserts'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.style.Circle'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Image'); -goog.require('ol.style.Stroke'); +/** + * Dispatches a `pointercancel` event. + * + * @param {goog.events.BrowserEvent} inEvent + */ +ol.pointer.MouseSource.prototype.cancel = function(inEvent) { + var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher); + this.dispatcher.cancel(e, inEvent); + this.cleanupMouse(); +}; /** - * @classdesc - * Container for vector feature rendering styles. Any changes made to the style - * or its children through `set*()` methods will not take effect until the - * feature or layer that uses the style is re-rendered. - * - * @constructor - * @param {olx.style.StyleOptions=} opt_options Style options. - * @api + * Remove the mouse from the list of active pointers. */ -ol.style.Style = function(opt_options) { +ol.pointer.MouseSource.prototype.cleanupMouse = function() { + delete this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()]; +}; - var options = opt_options || {}; +// Based on https://github.com/Polymer/PointerEvents - /** - * @private - * @type {string|ol.geom.Geometry|ol.style.GeometryFunction} - */ - this.geometry_ = null; +// Copyright (c) 2013 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - /** - * @private - * @type {!ol.style.GeometryFunction} - */ - this.geometryFunction_ = ol.style.defaultGeometryFunction; +goog.provide('ol.pointer.MsSource'); - if (options.geometry !== undefined) { - this.setGeometry(options.geometry); - } +goog.require('ol.pointer.EventSource'); - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : null; - /** - * @private - * @type {ol.style.Image} - */ - this.image_ = options.image !== undefined ? options.image : null; - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; +/** + * @param {ol.pointer.PointerEventHandler} dispatcher + * @constructor + * @extends {ol.pointer.EventSource} + */ +ol.pointer.MsSource = function(dispatcher) { + var mapping = { + 'MSPointerDown': this.msPointerDown, + 'MSPointerMove': this.msPointerMove, + 'MSPointerUp': this.msPointerUp, + 'MSPointerOut': this.msPointerOut, + 'MSPointerOver': this.msPointerOver, + 'MSPointerCancel': this.msPointerCancel, + 'MSGotPointerCapture': this.msGotPointerCapture, + 'MSLostPointerCapture': this.msLostPointerCapture + }; + goog.base(this, dispatcher, mapping); /** - * @private - * @type {ol.style.Text} + * @const + * @type {Object.<string, goog.events.BrowserEvent|Object>} */ - this.text_ = options.text !== undefined ? options.text : null; + this.pointerMap = dispatcher.pointerMap; /** - * @private - * @type {number|undefined} + * @const + * @type {Array.<string>} */ - this.zIndex_ = options.zIndex; - + this.POINTER_TYPES = [ + '', + 'unavailable', + 'touch', + 'pen', + 'mouse' + ]; }; +goog.inherits(ol.pointer.MsSource, ol.pointer.EventSource); /** - * Get the geometry to be rendered. - * @return {string|ol.geom.Geometry|ol.style.GeometryFunction} - * Feature property or geometry or function that returns the geometry that will - * be rendered with this style. - * @api + * Creates a copy of the original event that will be used + * for the fake pointer event. + * + * @private + * @param {goog.events.BrowserEvent} inEvent + * @return {Object} */ -ol.style.Style.prototype.getGeometry = function() { - return this.geometry_; +ol.pointer.MsSource.prototype.prepareEvent_ = function(inEvent) { + var e = inEvent; + if (goog.isNumber(inEvent.getBrowserEvent().pointerType)) { + e = this.dispatcher.cloneEvent(inEvent, inEvent.getBrowserEvent()); + e.pointerType = this.POINTER_TYPES[inEvent.getBrowserEvent().pointerType]; + } + + return e; }; /** - * Get the function used to generate a geometry for rendering. - * @return {!ol.style.GeometryFunction} Function that is called with a feature - * and returns the geometry to render instead of the feature's geometry. - * @api + * Remove this pointer from the list of active pointers. + * @param {number} pointerId */ -ol.style.Style.prototype.getGeometryFunction = function() { - return this.geometryFunction_; +ol.pointer.MsSource.prototype.cleanup = function(pointerId) { + delete this.pointerMap[pointerId.toString()]; }; /** - * Get the fill style. - * @return {ol.style.Fill} Fill style. - * @api + * Handler for `msPointerDown`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.getFill = function() { - return this.fill_; +ol.pointer.MsSource.prototype.msPointerDown = function(inEvent) { + this.pointerMap[inEvent.getBrowserEvent().pointerId.toString()] = inEvent; + var e = this.prepareEvent_(inEvent); + this.dispatcher.down(e, inEvent); }; /** - * Get the image style. - * @return {ol.style.Image} Image style. - * @api + * Handler for `msPointerMove`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.getImage = function() { - return this.image_; +ol.pointer.MsSource.prototype.msPointerMove = function(inEvent) { + var e = this.prepareEvent_(inEvent); + this.dispatcher.move(e, inEvent); }; /** - * Get the stroke style. - * @return {ol.style.Stroke} Stroke style. - * @api + * Handler for `msPointerUp`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.getStroke = function() { - return this.stroke_; +ol.pointer.MsSource.prototype.msPointerUp = function(inEvent) { + var e = this.prepareEvent_(inEvent); + this.dispatcher.up(e, inEvent); + this.cleanup(inEvent.getBrowserEvent().pointerId); }; /** - * Get the text style. - * @return {ol.style.Text} Text style. - * @api + * Handler for `msPointerOut`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.getText = function() { - return this.text_; +ol.pointer.MsSource.prototype.msPointerOut = function(inEvent) { + var e = this.prepareEvent_(inEvent); + this.dispatcher.leaveOut(e, inEvent); }; /** - * Get the z-index for the style. - * @return {number|undefined} ZIndex. - * @api + * Handler for `msPointerOver`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.getZIndex = function() { - return this.zIndex_; +ol.pointer.MsSource.prototype.msPointerOver = function(inEvent) { + var e = this.prepareEvent_(inEvent); + this.dispatcher.enterOver(e, inEvent); }; /** - * Set a geometry that is rendered instead of the feature's geometry. + * Handler for `msPointerCancel`. * - * @param {string|ol.geom.Geometry|ol.style.GeometryFunction} geometry - * Feature property or geometry or function returning a geometry to render - * for this style. - * @api + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.setGeometry = function(geometry) { - if (goog.isFunction(geometry)) { - this.geometryFunction_ = geometry; - } else if (goog.isString(geometry)) { - this.geometryFunction_ = function(feature) { - var result = feature.get(geometry); - if (result) { - goog.asserts.assertInstanceof(result, ol.geom.Geometry, - 'feature geometry must be an ol.geom.Geometry instance'); - } - return result; - }; - } else if (!geometry) { - this.geometryFunction_ = ol.style.defaultGeometryFunction; - } else if (geometry !== undefined) { - goog.asserts.assertInstanceof(geometry, ol.geom.Geometry, - 'geometry must be an ol.geom.Geometry instance'); - this.geometryFunction_ = function() { - return geometry; - }; - } - this.geometry_ = geometry; +ol.pointer.MsSource.prototype.msPointerCancel = function(inEvent) { + var e = this.prepareEvent_(inEvent); + this.dispatcher.cancel(e, inEvent); + this.cleanup(inEvent.getBrowserEvent().pointerId); }; /** - * Set the z-index. + * Handler for `msLostPointerCapture`. * - * @param {number|undefined} zIndex ZIndex. - * @api + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.Style.prototype.setZIndex = function(zIndex) { - this.zIndex_ = zIndex; +ol.pointer.MsSource.prototype.msLostPointerCapture = function(inEvent) { + var e = this.dispatcher.makeEvent('lostpointercapture', + inEvent.getBrowserEvent(), inEvent); + this.dispatcher.dispatchEvent(e); }; /** - * A function that takes an {@link ol.Feature} and a `{number}` representing - * the view's resolution. The function should return an array of - * {@link ol.style.Style}. This way e.g. a vector layer can be styled. + * Handler for `msGotPointerCapture`. * - * @typedef {function((ol.Feature|ol.render.Feature), number): - * (ol.style.Style|Array.<ol.style.Style>)} - * @api + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.StyleFunction; +ol.pointer.MsSource.prototype.msGotPointerCapture = function(inEvent) { + var e = this.dispatcher.makeEvent('gotpointercapture', + inEvent.getBrowserEvent(), inEvent); + this.dispatcher.dispatchEvent(e); +}; + +// Based on https://github.com/Polymer/PointerEvents + +// Copyright (c) 2013 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +goog.provide('ol.pointer.NativeSource'); + +goog.require('ol.pointer.EventSource'); + /** - * Convert the provided object into a style function. Functions passed through - * unchanged. Arrays of ol.style.Style or single style objects wrapped in a - * new style function. - * @param {ol.style.StyleFunction|Array.<ol.style.Style>|ol.style.Style} obj - * A style function, a single style, or an array of styles. - * @return {ol.style.StyleFunction} A style function. + * @param {ol.pointer.PointerEventHandler} dispatcher + * @constructor + * @extends {ol.pointer.EventSource} */ -ol.style.createStyleFunction = function(obj) { - var styleFunction; - - if (goog.isFunction(obj)) { - styleFunction = obj; - } else { - /** - * @type {Array.<ol.style.Style>} - */ - var styles; - if (goog.isArray(obj)) { - styles = obj; - } else { - goog.asserts.assertInstanceof(obj, ol.style.Style, - 'obj geometry must be an ol.style.Style instance'); - styles = [obj]; - } - styleFunction = function() { - return styles; - }; - } - return styleFunction; +ol.pointer.NativeSource = function(dispatcher) { + var mapping = { + 'pointerdown': this.pointerDown, + 'pointermove': this.pointerMove, + 'pointerup': this.pointerUp, + 'pointerout': this.pointerOut, + 'pointerover': this.pointerOver, + 'pointercancel': this.pointerCancel, + 'gotpointercapture': this.gotPointerCapture, + 'lostpointercapture': this.lostPointerCapture + }; + goog.base(this, dispatcher, mapping); }; +goog.inherits(ol.pointer.NativeSource, ol.pointer.EventSource); /** - * @type {Array.<ol.style.Style>} - * @private + * Handler for `pointerdown`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.defaultStyle_ = null; +ol.pointer.NativeSource.prototype.pointerDown = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); +}; /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {number} resolution Resolution. - * @return {Array.<ol.style.Style>} Style. + * Handler for `pointermove`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.defaultStyleFunction = function(feature, resolution) { - // We don't use an immediately-invoked function - // and a closure so we don't get an error at script evaluation time in - // browsers that do not support Canvas. (ol.style.Circle does - // canvas.getContext('2d') at construction time, which will cause an.error - // in such browsers.) - if (!ol.style.defaultStyle_) { - var fill = new ol.style.Fill({ - color: 'rgba(255,255,255,0.4)' - }); - var stroke = new ol.style.Stroke({ - color: '#3399CC', - width: 1.25 - }); - ol.style.defaultStyle_ = [ - new ol.style.Style({ - image: new ol.style.Circle({ - fill: fill, - stroke: stroke, - radius: 5 - }), - fill: fill, - stroke: stroke - }) - ]; - } - return ol.style.defaultStyle_; +ol.pointer.NativeSource.prototype.pointerMove = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); }; /** - * Default styles for editing features. - * @return {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} Styles + * Handler for `pointerup`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.createDefaultEditingStyles = function() { - /** @type {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} */ - var styles = {}; - var white = [255, 255, 255, 1]; - var blue = [0, 153, 255, 1]; - var width = 3; - styles[ol.geom.GeometryType.POLYGON] = [ - new ol.style.Style({ - fill: new ol.style.Fill({ - color: [255, 255, 255, 0.5] - }) - }) - ]; - styles[ol.geom.GeometryType.MULTI_POLYGON] = - styles[ol.geom.GeometryType.POLYGON]; - - styles[ol.geom.GeometryType.LINE_STRING] = [ - new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: white, - width: width + 2 - }) - }), - new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: blue, - width: width - }) - }) - ]; - styles[ol.geom.GeometryType.MULTI_LINE_STRING] = - styles[ol.geom.GeometryType.LINE_STRING]; - - styles[ol.geom.GeometryType.CIRCLE] = - styles[ol.geom.GeometryType.POLYGON].concat( - styles[ol.geom.GeometryType.LINE_STRING] - ); - - - styles[ol.geom.GeometryType.POINT] = [ - new ol.style.Style({ - image: new ol.style.Circle({ - radius: width * 2, - fill: new ol.style.Fill({ - color: blue - }), - stroke: new ol.style.Stroke({ - color: white, - width: width / 2 - }) - }), - zIndex: Infinity - }) - ]; - styles[ol.geom.GeometryType.MULTI_POINT] = - styles[ol.geom.GeometryType.POINT]; - - styles[ol.geom.GeometryType.GEOMETRY_COLLECTION] = - styles[ol.geom.GeometryType.POLYGON].concat( - styles[ol.geom.GeometryType.LINE_STRING], - styles[ol.geom.GeometryType.POINT] - ); - - return styles; +ol.pointer.NativeSource.prototype.pointerUp = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); }; /** - * A function that takes an {@link ol.Feature} as argument and returns an - * {@link ol.geom.Geometry} that will be rendered and styled for the feature. + * Handler for `pointerout`. * - * @typedef {function((ol.Feature|ol.render.Feature)): - * (ol.geom.Geometry|ol.render.Feature|undefined)} - * @api + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.GeometryFunction; +ol.pointer.NativeSource.prototype.pointerOut = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); +}; /** - * Function that is called with a feature and returns its default geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry - * for. - * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render. + * Handler for `pointerover`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.style.defaultGeometryFunction = function(feature) { - goog.asserts.assert(feature, 'feature must not be null'); - return feature.getGeometry(); +ol.pointer.NativeSource.prototype.pointerOver = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); }; -goog.exportSymbol('ol.style.defaultStyleFunction', ol.style.defaultStyleFunction); -goog.provide('ol.layer.Vector'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.layer.Layer'); -goog.require('ol.style.Style'); +/** + * Handler for `pointercancel`. + * + * @param {goog.events.BrowserEvent} inEvent + */ +ol.pointer.NativeSource.prototype.pointerCancel = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); +}; /** - * @enum {string} + * Handler for `lostpointercapture`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.layer.VectorProperty = { - RENDER_ORDER: 'renderOrder' +ol.pointer.NativeSource.prototype.lostPointerCapture = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); }; - /** - * @classdesc - * Vector data that is rendered client-side. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. + * Handler for `gotpointercapture`. * - * @constructor - * @extends {ol.layer.Layer} - * @fires ol.render.Event - * @param {olx.layer.VectorOptions=} opt_options Options. - * @api stable + * @param {goog.events.BrowserEvent} inEvent */ -ol.layer.Vector = function(opt_options) { +ol.pointer.NativeSource.prototype.gotPointerCapture = function(inEvent) { + this.dispatcher.fireNativeEvent(inEvent); +}; - var options = opt_options ? - opt_options : /** @type {olx.layer.VectorOptions} */ ({}); +// Based on https://github.com/Polymer/PointerEvents - goog.asserts.assert( - options.renderOrder === undefined || !options.renderOrder || - goog.isFunction(options.renderOrder), - 'renderOrder must be a comparator function'); +// Copyright (c) 2013 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - var baseOptions = goog.object.clone(options); +goog.provide('ol.pointer.TouchSource'); - delete baseOptions.style; - delete baseOptions.renderBuffer; - delete baseOptions.updateWhileAnimating; - delete baseOptions.updateWhileInteracting; - goog.base(this, /** @type {olx.layer.LayerOptions} */ (baseOptions)); +goog.require('goog.array'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.pointer.EventSource'); +goog.require('ol.pointer.MouseSource'); + + + +/** + * @constructor + * @param {ol.pointer.PointerEventHandler} dispatcher + * @param {ol.pointer.MouseSource} mouseSource + * @extends {ol.pointer.EventSource} + */ +ol.pointer.TouchSource = function(dispatcher, mouseSource) { + var mapping = { + 'touchstart': this.touchstart, + 'touchmove': this.touchmove, + 'touchend': this.touchend, + 'touchcancel': this.touchcancel + }; + goog.base(this, dispatcher, mapping); /** - * @type {number} - * @private + * @const + * @type {Object.<string, goog.events.BrowserEvent|Object>} */ - this.renderBuffer_ = options.renderBuffer !== undefined ? - options.renderBuffer : 100; + this.pointerMap = dispatcher.pointerMap; /** - * User provided style. - * @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * @private + * @const + * @type {ol.pointer.MouseSource} */ - this.style_ = null; + this.mouseSource = mouseSource; /** - * Style function for use within the library. - * @type {ol.style.StyleFunction|undefined} * @private + * @type {number|undefined} */ - this.styleFunction_ = undefined; - - this.setStyle(options.style); + this.firstTouchId_ = undefined; /** - * @type {boolean} * @private + * @type {number} */ - this.updateWhileAnimating_ = options.updateWhileAnimating !== undefined ? - options.updateWhileAnimating : false; + this.clickCount_ = 0; /** - * @type {boolean} * @private + * @type {number|undefined} */ - this.updateWhileInteracting_ = options.updateWhileInteracting !== undefined ? - options.updateWhileInteracting : false; - + this.resetId_ = undefined; }; -goog.inherits(ol.layer.Vector, ol.layer.Layer); +goog.inherits(ol.pointer.TouchSource, ol.pointer.EventSource); /** - * @return {number|undefined} Render buffer. + * Mouse event timeout: This should be long enough to + * ignore compat mouse events made by touch. + * @const + * @type {number} */ -ol.layer.Vector.prototype.getRenderBuffer = function() { - return this.renderBuffer_; -}; +ol.pointer.TouchSource.DEDUP_TIMEOUT = 2500; /** - * @return {function(ol.Feature, ol.Feature): number|null|undefined} Render - * order. + * @const + * @type {number} */ -ol.layer.Vector.prototype.getRenderOrder = function() { - return /** @type {function(ol.Feature, ol.Feature):number|null|undefined} */ ( - this.get(ol.layer.VectorProperty.RENDER_ORDER)); -}; +ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT = 200; /** - * Return the associated {@link ol.source.Vector vectorsource} of the layer. - * @function - * @return {ol.source.Vector} Source. - * @api stable + * @const + * @type {string} */ -ol.layer.Vector.prototype.getSource; +ol.pointer.TouchSource.POINTER_TYPE = 'touch'; /** - * Get the style for features. This returns whatever was passed to the `style` - * option at construction or to the `setStyle` method. - * @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * Layer style. - * @api stable + * @private + * @param {Touch} inTouch + * @return {boolean} True, if this is the primary touch. */ -ol.layer.Vector.prototype.getStyle = function() { - return this.style_; +ol.pointer.TouchSource.prototype.isPrimaryTouch_ = function(inTouch) { + return this.firstTouchId_ === inTouch.identifier; }; /** - * Get the style function. - * @return {ol.style.StyleFunction|undefined} Layer style function. - * @api stable + * Set primary touch if there are no pointers, or the only pointer is the mouse. + * @param {Touch} inTouch + * @private */ -ol.layer.Vector.prototype.getStyleFunction = function() { - return this.styleFunction_; +ol.pointer.TouchSource.prototype.setPrimaryTouch_ = function(inTouch) { + var count = goog.object.getCount(this.pointerMap); + if (count === 0 || (count === 1 && goog.object.containsKey(this.pointerMap, + ol.pointer.MouseSource.POINTER_ID.toString()))) { + this.firstTouchId_ = inTouch.identifier; + this.cancelResetClickCount_(); + } }; /** - * @return {boolean} Whether the rendered layer should be updated while - * animating. + * @private + * @param {Object} inPointer */ -ol.layer.Vector.prototype.getUpdateWhileAnimating = function() { - return this.updateWhileAnimating_; +ol.pointer.TouchSource.prototype.removePrimaryPointer_ = function(inPointer) { + if (inPointer.isPrimary) { + this.firstTouchId_ = undefined; + this.resetClickCount_(); + } }; /** - * @return {boolean} Whether the rendered layer should be updated while - * interacting. + * @private */ -ol.layer.Vector.prototype.getUpdateWhileInteracting = function() { - return this.updateWhileInteracting_; +ol.pointer.TouchSource.prototype.resetClickCount_ = function() { + this.resetId_ = goog.global.setTimeout( + goog.bind(this.resetClickCountHandler_, this), + ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT); }; /** - * @param {function(ol.Feature, ol.Feature):number|null|undefined} renderOrder - * Render order. + * @private */ -ol.layer.Vector.prototype.setRenderOrder = function(renderOrder) { - goog.asserts.assert( - renderOrder === undefined || !renderOrder || - goog.isFunction(renderOrder), - 'renderOrder must be a comparator function'); - this.set(ol.layer.VectorProperty.RENDER_ORDER, renderOrder); +ol.pointer.TouchSource.prototype.resetClickCountHandler_ = function() { + this.clickCount_ = 0; + this.resetId_ = undefined; }; /** - * Set the style for features. This can be a single style object, an array - * of styles, or a function that takes a feature and resolution and returns - * an array of styles. If it is `undefined` the default style is used. If - * it is `null` the layer has no style (a `null` style), so only features - * that have their own styles will be rendered in the layer. See - * {@link ol.style} for information on the default style. - * @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|null|undefined} - * style Layer style. - * @api stable + * @private */ -ol.layer.Vector.prototype.setStyle = function(style) { - this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction; - this.styleFunction_ = style === null ? - undefined : ol.style.createStyleFunction(this.style_); - this.changed(); +ol.pointer.TouchSource.prototype.cancelResetClickCount_ = function() { + if (this.resetId_ !== undefined) { + goog.global.clearTimeout(this.resetId_); + } }; -goog.provide('ol.layer.VectorTile'); - -goog.require('goog.object'); -goog.require('ol.layer.Vector'); - /** - * @enum {string} + * @private + * @param {goog.events.BrowserEvent} browserEvent Browser event + * @param {Touch} inTouch Touch event + * @return {Object} */ -ol.layer.VectorTileProperty = { - PRELOAD: 'preload', - USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError' -}; +ol.pointer.TouchSource.prototype.touchToPointer_ = + function(browserEvent, inTouch) { + var e = this.dispatcher.cloneEvent(browserEvent, inTouch); + // Spec specifies that pointerId 1 is reserved for Mouse. + // Touch identifiers can start at 0. + // Add 2 to the touch identifier for compatibility. + e.pointerId = inTouch.identifier + 2; + // TODO: check if this is necessary? + //e.target = findTarget(e); + e.bubbles = true; + e.cancelable = true; + e.detail = this.clickCount_; + e.button = 0; + e.buttons = 1; + e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; + e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; + e.pressure = inTouch.webkitForce || inTouch.force || 0.5; + e.isPrimary = this.isPrimaryTouch_(inTouch); + e.pointerType = ol.pointer.TouchSource.POINTER_TYPE; + + // make sure that the properties that are different for + // each `Touch` object are not copied from the BrowserEvent object + e.clientX = inTouch.clientX; + e.clientY = inTouch.clientY; + e.screenX = inTouch.screenX; + e.screenY = inTouch.screenY; + return e; +}; /** - * @classdesc - * Layer for vector tile data that is rendered client-side. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Vector} - * @param {olx.layer.VectorTileOptions=} opt_options Options. - * @api + * @private + * @param {goog.events.BrowserEvent} inEvent Touch event + * @param {function(goog.events.BrowserEvent, Object)} inFunction */ -ol.layer.VectorTile = function(opt_options) { - var options = opt_options ? opt_options : {}; - - var baseOptions = goog.object.clone(options); - - delete baseOptions.preload; - delete baseOptions.useInterimTilesOnError; - goog.base(this, /** @type {olx.layer.VectorOptions} */ (baseOptions)); - - this.setPreload(options.preload ? options.preload : 0); - this.setUseInterimTilesOnError(options.useInterimTilesOnError ? - options.useInterimTilesOnError : true); - +ol.pointer.TouchSource.prototype.processTouches_ = + function(inEvent, inFunction) { + var touches = Array.prototype.slice.call( + inEvent.getBrowserEvent().changedTouches); + var count = touches.length; + function preventDefault() { + inEvent.preventDefault(); + } + var i, pointer; + for (i = 0; i < count; ++i) { + pointer = this.touchToPointer_(inEvent, touches[i]); + // forward touch preventDefaults + pointer.preventDefault = preventDefault; + inFunction.call(this, inEvent, pointer); + } }; -goog.inherits(ol.layer.VectorTile, ol.layer.Vector); /** - * Return the level as number to which we will preload tiles up to. - * @return {number} The level to preload tiles up to. - * @observable - * @api + * @private + * @param {TouchList} touchList + * @param {number} searchId + * @return {boolean} True, if the `Touch` with the given id is in the list. */ -ol.layer.VectorTile.prototype.getPreload = function() { - return /** @type {number} */ (this.get(ol.layer.VectorTileProperty.PRELOAD)); +ol.pointer.TouchSource.prototype.findTouch_ = function(touchList, searchId) { + var l = touchList.length; + var touch; + for (var i = 0; i < l; i++) { + touch = touchList[i]; + if (touch.identifier === searchId) { + return true; + } + } + return false; }; /** - * Return the associated {@link ol.source.VectorTile source} of the layer. - * @function - * @return {ol.source.VectorTile} Source. - * @api + * In some instances, a touchstart can happen without a touchend. This + * leaves the pointermap in a broken state. + * Therefore, on every touchstart, we remove the touches that did not fire a + * touchend event. + * To keep state globally consistent, we fire a pointercancel for + * this "abandoned" touch + * + * @private + * @param {goog.events.BrowserEvent} inEvent */ -ol.layer.VectorTile.prototype.getSource; +ol.pointer.TouchSource.prototype.vacuumTouches_ = function(inEvent) { + var touchList = inEvent.getBrowserEvent().touches; + // pointerMap.getCount() should be < touchList.length here, + // as the touchstart has not been processed yet. + var keys = goog.object.getKeys(this.pointerMap); + var count = keys.length; + if (count >= touchList.length) { + var d = []; + var i, key, value; + for (i = 0; i < count; ++i) { + key = keys[i]; + value = this.pointerMap[key]; + // Never remove pointerId == 1, which is mouse. + // Touch identifiers are 2 smaller than their pointerId, which is the + // index in pointermap. + if (key != ol.pointer.MouseSource.POINTER_ID && + !this.findTouch_(touchList, key - 2)) { + d.push(value.out); + } + } + for (i = 0; i < d.length; ++i) { + this.cancelOut_(inEvent, d[i]); + } + } +}; /** - * Whether we use interim tiles on error. - * @return {boolean} Use interim tiles on error. - * @observable - * @api + * Handler for `touchstart`, triggers `pointerover`, + * `pointerenter` and `pointerdown` events. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.layer.VectorTile.prototype.getUseInterimTilesOnError = function() { - return /** @type {boolean} */ ( - this.get(ol.layer.VectorTileProperty.USE_INTERIM_TILES_ON_ERROR)); +ol.pointer.TouchSource.prototype.touchstart = function(inEvent) { + this.vacuumTouches_(inEvent); + this.setPrimaryTouch_(inEvent.getBrowserEvent().changedTouches[0]); + this.dedupSynthMouse_(inEvent); + this.clickCount_++; + this.processTouches_(inEvent, this.overDown_); }; /** - * Set the level as number to which we will preload tiles up to. - * @param {number} preload The level to preload tiles up to. - * @observable - * @api + * @private + * @param {goog.events.BrowserEvent} browserEvent + * @param {Object} inPointer */ -ol.layer.VectorTile.prototype.setPreload = function(preload) { - this.set(ol.layer.TileProperty.PRELOAD, preload); +ol.pointer.TouchSource.prototype.overDown_ = function(browserEvent, inPointer) { + this.pointerMap[inPointer.pointerId] = { + target: inPointer.target, + out: inPointer, + outTarget: inPointer.target + }; + this.dispatcher.over(inPointer, browserEvent); + this.dispatcher.enter(inPointer, browserEvent); + this.dispatcher.down(inPointer, browserEvent); }; /** - * Set whether we use interim tiles on error. - * @param {boolean} useInterimTilesOnError Use interim tiles on error. - * @observable - * @api + * Handler for `touchmove`. + * + * @param {goog.events.BrowserEvent} inEvent */ -ol.layer.VectorTile.prototype.setUseInterimTilesOnError = - function(useInterimTilesOnError) { - this.set( - ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); +ol.pointer.TouchSource.prototype.touchmove = function(inEvent) { + inEvent.preventDefault(); + this.processTouches_(inEvent, this.moveOverOut_); }; -// FIXME test, especially polygons with holes and multipolygons -// FIXME need to handle large thick features (where pixel size matters) -// FIXME add offset and end to ol.geom.flat.transform.transform2D? -goog.provide('ol.render.canvas.Immediate'); +/** + * @private + * @param {goog.events.BrowserEvent} browserEvent + * @param {Object} inPointer + */ +ol.pointer.TouchSource.prototype.moveOverOut_ = + function(browserEvent, inPointer) { + var event = inPointer; + var pointer = this.pointerMap[event.pointerId]; + // a finger drifted off the screen, ignore it + if (!pointer) { + return; + } + var outEvent = pointer.out; + var outTarget = pointer.outTarget; + this.dispatcher.move(event, browserEvent); + if (outEvent && outTarget !== event.target) { + outEvent.relatedTarget = event.target; + event.relatedTarget = outTarget; + // recover from retargeting by shadow + outEvent.target = outTarget; + if (event.target) { + this.dispatcher.leaveOut(outEvent, browserEvent); + this.dispatcher.enterOver(event, browserEvent); + } else { + // clean up case when finger leaves the screen + event.target = outTarget; + event.relatedTarget = null; + this.cancelOut_(browserEvent, event); + } + } + pointer.out = event; + pointer.outTarget = event.target; +}; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.color'); -goog.require('ol.extent'); -goog.require('ol.geom.flat.transform'); -goog.require('ol.has'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.canvas'); -goog.require('ol.vec.Mat4'); +/** + * Handler for `touchend`, triggers `pointerup`, + * `pointerout` and `pointerleave` events. + * + * @param {goog.events.BrowserEvent} inEvent + */ +ol.pointer.TouchSource.prototype.touchend = function(inEvent) { + this.dedupSynthMouse_(inEvent); + this.processTouches_(inEvent, this.upOut_); +}; /** - * @classdesc - * A concrete subclass of {@link ol.render.VectorContext} that implements - * direct rendering of features and geometries to an HTML5 Canvas context. - * Instances of this class are created internally by the library and - * provided to application code as vectorContext member of the - * {@link ol.render.Event} object associated with postcompose, precompose and - * render events emitted by layers and maps. - * - * @constructor - * @extends {ol.render.VectorContext} - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Extent} extent Extent. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @struct + * @private + * @param {goog.events.BrowserEvent} browserEvent + * @param {Object} inPointer */ -ol.render.canvas.Immediate = - function(context, pixelRatio, extent, transform, viewRotation) { +ol.pointer.TouchSource.prototype.upOut_ = function(browserEvent, inPointer) { + this.dispatcher.up(inPointer, browserEvent); + this.dispatcher.out(inPointer, browserEvent); + this.dispatcher.leave(inPointer, browserEvent); + this.cleanUpPointer_(inPointer); +}; - /** - * @private - * @type {!Object.<string, - * Array.<function(ol.render.canvas.Immediate)>>} - */ - this.callbacksByZIndex_ = {}; - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = context; +/** + * Handler for `touchcancel`, triggers `pointercancel`, + * `pointerout` and `pointerleave` events. + * + * @param {goog.events.BrowserEvent} inEvent + */ +ol.pointer.TouchSource.prototype.touchcancel = function(inEvent) { + this.processTouches_(inEvent, this.cancelOut_); +}; - /** - * @private - * @type {number} - */ - this.pixelRatio_ = pixelRatio; - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = extent; +/** + * @private + * @param {goog.events.BrowserEvent} browserEvent + * @param {Object} inPointer + */ +ol.pointer.TouchSource.prototype.cancelOut_ = + function(browserEvent, inPointer) { + this.dispatcher.cancel(inPointer, browserEvent); + this.dispatcher.out(inPointer, browserEvent); + this.dispatcher.leave(inPointer, browserEvent); + this.cleanUpPointer_(inPointer); +}; - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = transform; - /** - * @private - * @type {number} - */ - this.viewRotation_ = viewRotation; +/** + * @private + * @param {Object} inPointer + */ +ol.pointer.TouchSource.prototype.cleanUpPointer_ = function(inPointer) { + delete this.pointerMap[inPointer.pointerId]; + this.removePrimaryPointer_(inPointer); +}; - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.contextFillState_ = null; - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.contextStrokeState_ = null; +/** + * Prevent synth mouse events from creating pointer events. + * + * @private + * @param {goog.events.BrowserEvent} inEvent + */ +ol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) { + var lts = this.mouseSource.lastTouches; + var t = inEvent.getBrowserEvent().changedTouches[0]; + // only the primary finger will synth mouse events + if (this.isPrimaryTouch_(t)) { + // remember x/y of last touch + var lt = /** @type {ol.Pixel} */ ([t.clientX, t.clientY]); + lts.push(lt); - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.contextTextState_ = null; + goog.global.setTimeout(function() { + // remove touch after timeout + goog.array.remove(lts, lt); + }, ol.pointer.TouchSource.DEDUP_TIMEOUT); + } +}; - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.fillState_ = null; +// Based on https://github.com/Polymer/PointerEvents - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.strokeState_ = null; +// Copyright (c) 2013 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - /** - * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} - */ - this.image_ = null; +goog.provide('ol.pointer.PointerEventHandler'); - /** - * @private - * @type {number} - */ - this.imageAnchorX_ = 0; +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.EventTarget'); - /** - * @private - * @type {number} - */ - this.imageAnchorY_ = 0; +goog.require('ol.has'); +goog.require('ol.pointer.MouseSource'); +goog.require('ol.pointer.MsSource'); +goog.require('ol.pointer.NativeSource'); +goog.require('ol.pointer.PointerEvent'); +goog.require('ol.pointer.TouchSource'); - /** - * @private - * @type {number} - */ - this.imageHeight_ = 0; - /** - * @private - * @type {number} - */ - this.imageOpacity_ = 0; - /** - * @private - * @type {number} - */ - this.imageOriginX_ = 0; +/** + * @constructor + * @extends {goog.events.EventTarget} + * @param {Element|HTMLDocument} element Viewport element. + */ +ol.pointer.PointerEventHandler = function(element) { + goog.base(this); /** + * @const * @private - * @type {number} + * @type {Element|HTMLDocument} */ - this.imageOriginY_ = 0; + this.element_ = element; /** - * @private - * @type {boolean} + * @const + * @type {Object.<string, goog.events.BrowserEvent|Object>} */ - this.imageRotateWithView_ = false; + this.pointerMap = {}; /** + * @type {Object.<string, function(goog.events.BrowserEvent)>} * @private - * @type {number} */ - this.imageRotation_ = 0; + this.eventMap_ = {}; /** + * @type {Array.<ol.pointer.EventSource>} * @private - * @type {number} */ - this.imageScale_ = 0; + this.eventSourceList_ = []; - /** - * @private - * @type {boolean} - */ - this.imageSnapToPixel_ = false; + this.registerSources(); +}; +goog.inherits(ol.pointer.PointerEventHandler, goog.events.EventTarget); - /** - * @private - * @type {number} - */ - this.imageWidth_ = 0; - /** - * @private - * @type {string} - */ - this.text_ = ''; +/** + * Set up the event sources (mouse, touch and native pointers) + * that generate pointer events. + */ +ol.pointer.PointerEventHandler.prototype.registerSources = function() { + if (ol.has.POINTER) { + this.registerSource('native', new ol.pointer.NativeSource(this)); + } else if (ol.has.MSPOINTER) { + this.registerSource('ms', new ol.pointer.MsSource(this)); + } else { + var mouseSource = new ol.pointer.MouseSource(this); + this.registerSource('mouse', mouseSource); - /** - * @private - * @type {number} - */ - this.textOffsetX_ = 0; + if (ol.has.TOUCH) { + this.registerSource('touch', + new ol.pointer.TouchSource(this, mouseSource)); + } + } - /** - * @private - * @type {number} - */ - this.textOffsetY_ = 0; + // register events on the viewport element + this.register_(); +}; - /** - * @private - * @type {number} - */ - this.textRotation_ = 0; - /** - * @private - * @type {number} - */ - this.textScale_ = 0; +/** + * Add a new event source that will generate pointer events. + * + * @param {string} name A name for the event source + * @param {ol.pointer.EventSource} source + */ +ol.pointer.PointerEventHandler.prototype.registerSource = + function(name, source) { + var s = source; + var newEvents = s.getEvents(); - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.textFillState_ = null; + if (newEvents) { + newEvents.forEach(function(e) { + var handler = s.getHandlerForEvent(e); - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.textStrokeState_ = null; + if (handler) { + this.eventMap_[e] = goog.bind(handler, s); + } + }, this); + this.eventSourceList_.push(s); + } +}; - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.textState_ = null; - /** - * @private - * @type {Array.<number>} - */ - this.pixelCoordinates_ = []; +/** + * Set up the events for all registered event sources. + * @private + */ +ol.pointer.PointerEventHandler.prototype.register_ = function() { + var l = this.eventSourceList_.length; + var eventSource; + for (var i = 0; i < l; i++) { + eventSource = this.eventSourceList_[i]; + this.addEvents_(eventSource.getEvents()); + } +}; - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); +/** + * Remove all registered events. + * @private + */ +ol.pointer.PointerEventHandler.prototype.unregister_ = function() { + var l = this.eventSourceList_.length; + var eventSource; + for (var i = 0; i < l; i++) { + eventSource = this.eventSourceList_[i]; + this.removeEvents_(eventSource.getEvents()); + } }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. + * Calls the right handler for a new event. * @private + * @param {goog.events.BrowserEvent} inEvent Browser event. */ -ol.render.canvas.Immediate.prototype.drawImages_ = - function(flatCoordinates, offset, end, stride) { - if (!this.image_) { - return; - } - goog.asserts.assert(offset === 0, 'offset should be 0'); - goog.asserts.assert(end == flatCoordinates.length, - 'end should be equal to the length of flatCoordinates'); - var pixelCoordinates = ol.geom.flat.transform.transform2D( - flatCoordinates, offset, end, 2, this.transform_, - this.pixelCoordinates_); - var context = this.context_; - var localTransform = this.tmpLocalTransform_; - var alpha = context.globalAlpha; - if (this.imageOpacity_ != 1) { - context.globalAlpha = alpha * this.imageOpacity_; - } - var rotation = this.imageRotation_; - if (this.imageRotateWithView_) { - rotation += this.viewRotation_; - } - var i, ii; - for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { - var x = pixelCoordinates[i] - this.imageAnchorX_; - var y = pixelCoordinates[i + 1] - this.imageAnchorY_; - if (this.imageSnapToPixel_) { - x = (x + 0.5) | 0; - y = (y + 0.5) | 0; - } - if (rotation !== 0 || this.imageScale_ != 1) { - var centerX = x + this.imageAnchorX_; - var centerY = y + this.imageAnchorY_; - ol.vec.Mat4.makeTransform2D(localTransform, - centerX, centerY, this.imageScale_, this.imageScale_, - rotation, -centerX, -centerY); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - context.drawImage(this.image_, this.imageOriginX_, this.imageOriginY_, - this.imageWidth_, this.imageHeight_, x, y, - this.imageWidth_, this.imageHeight_); - } - if (rotation !== 0 || this.imageScale_ != 1) { - context.setTransform(1, 0, 0, 1, 0, 0); - } - if (this.imageOpacity_ != 1) { - context.globalAlpha = alpha; +ol.pointer.PointerEventHandler.prototype.eventHandler_ = function(inEvent) { + var type = inEvent.type; + var handler = this.eventMap_[type]; + if (handler) { + handler(inEvent); } }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. + * Setup listeners for the given events. * @private + * @param {Array.<string>} events List of events. */ -ol.render.canvas.Immediate.prototype.drawText_ = - function(flatCoordinates, offset, end, stride) { - if (!this.textState_ || this.text_ === '') { - return; - } - if (this.textFillState_) { - this.setContextFillState_(this.textFillState_); - } - if (this.textStrokeState_) { - this.setContextStrokeState_(this.textStrokeState_); - } - this.setContextTextState_(this.textState_); - goog.asserts.assert(offset === 0, 'offset should be 0'); - goog.asserts.assert(end == flatCoordinates.length, - 'end should be equal to the length of flatCoordinates'); - var pixelCoordinates = ol.geom.flat.transform.transform2D( - flatCoordinates, offset, end, stride, this.transform_, - this.pixelCoordinates_); - var context = this.context_; - for (; offset < end; offset += stride) { - var x = pixelCoordinates[offset] + this.textOffsetX_; - var y = pixelCoordinates[offset + 1] + this.textOffsetY_; - if (this.textRotation_ !== 0 || this.textScale_ != 1) { - var localTransform = ol.vec.Mat4.makeTransform2D(this.tmpLocalTransform_, - x, y, this.textScale_, this.textScale_, this.textRotation_, -x, -y); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - if (this.textStrokeState_) { - context.strokeText(this.text_, x, y); - } - if (this.textFillState_) { - context.fillText(this.text_, x, y); - } - } - if (this.textRotation_ !== 0 || this.textScale_ != 1) { - context.setTransform(1, 0, 0, 1, 0, 0); - } +ol.pointer.PointerEventHandler.prototype.addEvents_ = function(events) { + events.forEach(function(eventName) { + goog.events.listen(this.element_, eventName, + this.eventHandler_, false, this); + }, this); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {boolean} close Close. + * Unregister listeners for the given events. * @private - * @return {number} end End. + * @param {Array.<string>} events List of events. */ -ol.render.canvas.Immediate.prototype.moveToLineTo_ = - function(flatCoordinates, offset, end, stride, close) { - var context = this.context_; - var pixelCoordinates = ol.geom.flat.transform.transform2D( - flatCoordinates, offset, end, stride, this.transform_, - this.pixelCoordinates_); - context.moveTo(pixelCoordinates[0], pixelCoordinates[1]); - var i; - for (i = 2; i < pixelCoordinates.length; i += 2) { - context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]); - } - if (close) { - context.lineTo(pixelCoordinates[0], pixelCoordinates[1]); - } - return end; +ol.pointer.PointerEventHandler.prototype.removeEvents_ = function(events) { + events.forEach(function(e) { + goog.events.unlisten(this.element_, e, + this.eventHandler_, false, this); + }, this); }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @private - * @return {number} End. + * Returns a snapshot of inEvent, with writable properties. + * + * @param {goog.events.BrowserEvent} browserEvent Browser event. + * @param {Event|Touch} inEvent An event that contains + * properties to copy. + * @return {Object} An object containing shallow copies of + * `inEvent`'s properties. */ -ol.render.canvas.Immediate.prototype.drawRings_ = - function(flatCoordinates, offset, ends, stride) { - var context = this.context_; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.moveToLineTo_( - flatCoordinates, offset, ends[i], stride, true); - context.closePath(); // FIXME is this needed here? +ol.pointer.PointerEventHandler.prototype.cloneEvent = + function(browserEvent, inEvent) { + var eventCopy = {}, p; + for (var i = 0, ii = ol.pointer.CLONE_PROPS.length; i < ii; i++) { + p = ol.pointer.CLONE_PROPS[i][0]; + eventCopy[p] = + browserEvent[p] || + inEvent[p] || + ol.pointer.CLONE_PROPS[i][1]; } - return offset; + + return eventCopy; }; +// EVENTS + + /** - * Register a function to be called for rendering at a given zIndex. The - * function will be called asynchronously. The callback will receive a - * reference to {@link ol.render.canvas.Immediate} context for drawing. - * - * @param {number} zIndex Z index. - * @param {function(ol.render.canvas.Immediate)} callback Callback. - * @api + * Triggers a 'pointerdown' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawAsync = function(zIndex, callback) { - var zIndexKey = zIndex.toString(); - var callbacks = this.callbacksByZIndex_[zIndexKey]; - if (callbacks !== undefined) { - callbacks.push(callback); - } else { - this.callbacksByZIndex_[zIndexKey] = [callback]; - } +ol.pointer.PointerEventHandler.prototype.down = + function(pointerEventData, browserEvent) { + this.fireEvent(ol.pointer.EventType.POINTERDOWN, + pointerEventData, browserEvent); }; /** - * Render a circle geometry into the canvas. Rendering is immediate and uses - * the current fill and stroke styles. - * - * @param {ol.geom.Circle} circleGeometry Circle geometry. - * @param {ol.Feature} feature Feature, - * @api + * Triggers a 'pointermove' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawCircleGeometry = - function(circleGeometry, feature) { - if (!ol.extent.intersects(this.extent_, circleGeometry.getExtent())) { - return; - } - if (this.fillState_ || this.strokeState_) { - if (this.fillState_) { - this.setContextFillState_(this.fillState_); - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - } - var pixelCoordinates = ol.geom.transformSimpleGeometry2D( - circleGeometry, this.transform_, this.pixelCoordinates_); - var dx = pixelCoordinates[2] - pixelCoordinates[0]; - var dy = pixelCoordinates[3] - pixelCoordinates[1]; - var radius = Math.sqrt(dx * dx + dy * dy); - var context = this.context_; - context.beginPath(); - context.arc( - pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI); - if (this.fillState_) { - context.fill(); - } - if (this.strokeState_) { - context.stroke(); - } - } - if (this.text_ !== '') { - this.drawText_(circleGeometry.getCenter(), 0, 2, 2); - } +ol.pointer.PointerEventHandler.prototype.move = + function(pointerEventData, browserEvent) { + this.fireEvent(ol.pointer.EventType.POINTERMOVE, + pointerEventData, browserEvent); }; /** - * Render a feature into the canvas. In order to respect the zIndex of the - * style this method draws asynchronously and thus *after* calls to - * drawXxxxGeometry have been finished, effectively drawing the feature - * *on top* of everything else. You probably should be using an - * {@link ol.layer.Vector} instead of calling this method directly. - * - * @param {ol.Feature} feature Feature. - * @param {ol.style.Style} style Style. - * @api + * Triggers a 'pointerup' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) { - var geometry = style.getGeometryFunction()(feature); - if (!geometry || - !ol.extent.intersects(this.extent_, geometry.getExtent())) { - return; - } - var zIndex = style.getZIndex(); - if (zIndex === undefined) { - zIndex = 0; - } - this.drawAsync(zIndex, function(render) { - render.setFillStrokeStyle(style.getFill(), style.getStroke()); - render.setImageStyle(style.getImage()); - render.setTextStyle(style.getText()); - var renderGeometry = - ol.render.canvas.Immediate.GEOMETRY_RENDERERS_[geometry.getType()]; - goog.asserts.assert(renderGeometry !== undefined, - 'renderGeometry should be defined'); - renderGeometry.call(render, geometry, null); - }); +ol.pointer.PointerEventHandler.prototype.up = + function(pointerEventData, browserEvent) { + this.fireEvent(ol.pointer.EventType.POINTERUP, + pointerEventData, browserEvent); }; /** - * Render a GeometryCollection to the canvas. Rendering is immediate and - * uses the current styles appropriate for each geometry in the collection. - * - * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry - * collection. - * @param {ol.Feature} feature Feature. + * Triggers a 'pointerenter' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry = - function(geometryCollectionGeometry, feature) { - var geometries = geometryCollectionGeometry.getGeometriesArray(); - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometry = geometries[i]; - var geometryRenderer = - ol.render.canvas.Immediate.GEOMETRY_RENDERERS_[geometry.getType()]; - goog.asserts.assert(geometryRenderer !== undefined, - 'geometryRenderer should be defined'); - geometryRenderer.call(this, geometry, feature); - } +ol.pointer.PointerEventHandler.prototype.enter = + function(pointerEventData, browserEvent) { + pointerEventData.bubbles = false; + this.fireEvent(ol.pointer.EventType.POINTERENTER, + pointerEventData, browserEvent); }; /** - * Render a Point geometry into the canvas. Rendering is immediate and uses - * the current style. - * - * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api + * Triggers a 'pointerleave' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawPointGeometry = - function(pointGeometry, feature) { - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - if (this.image_) { - this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); - } - if (this.text_ !== '') { - this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); - } +ol.pointer.PointerEventHandler.prototype.leave = + function(pointerEventData, browserEvent) { + pointerEventData.bubbles = false; + this.fireEvent(ol.pointer.EventType.POINTERLEAVE, + pointerEventData, browserEvent); }; /** - * Render a MultiPoint geometry into the canvas. Rendering is immediate and - * uses the current style. - * - * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api + * Triggers a 'pointerover' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawMultiPointGeometry = - function(multiPointGeometry, feature) { - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - if (this.image_) { - this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); - } - if (this.text_ !== '') { - this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); - } +ol.pointer.PointerEventHandler.prototype.over = + function(pointerEventData, browserEvent) { + pointerEventData.bubbles = true; + this.fireEvent(ol.pointer.EventType.POINTEROVER, + pointerEventData, browserEvent); }; /** - * Render a LineString into the canvas. Rendering is immediate and uses - * the current style. - * - * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line - * string geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api + * Triggers a 'pointerout' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawLineStringGeometry = - function(lineStringGeometry, feature) { - if (!ol.extent.intersects(this.extent_, lineStringGeometry.getExtent())) { - return; - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - var context = this.context_; - var flatCoordinates = lineStringGeometry.getFlatCoordinates(); - context.beginPath(); - this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length, - lineStringGeometry.getStride(), false); - context.stroke(); - } - if (this.text_ !== '') { - var flatMidpoint = lineStringGeometry.getFlatMidpoint(); - this.drawText_(flatMidpoint, 0, 2, 2); - } +ol.pointer.PointerEventHandler.prototype.out = + function(pointerEventData, browserEvent) { + pointerEventData.bubbles = true; + this.fireEvent(ol.pointer.EventType.POINTEROUT, + pointerEventData, browserEvent); }; /** - * Render a MultiLineString geometry into the canvas. Rendering is immediate - * and uses the current style. - * - * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry - * MultiLineString geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api + * Triggers a 'pointercancel' event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry = - function(multiLineStringGeometry, feature) { - var geometryExtent = multiLineStringGeometry.getExtent(); - if (!ol.extent.intersects(this.extent_, geometryExtent)) { - return; - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - var context = this.context_; - var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); - var offset = 0; - var ends = multiLineStringGeometry.getEnds(); - var stride = multiLineStringGeometry.getStride(); - context.beginPath(); - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.moveToLineTo_( - flatCoordinates, offset, ends[i], stride, false); - } - context.stroke(); - } - if (this.text_ !== '') { - var flatMidpoints = multiLineStringGeometry.getFlatMidpoints(); - this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2); - } +ol.pointer.PointerEventHandler.prototype.cancel = + function(pointerEventData, browserEvent) { + this.fireEvent(ol.pointer.EventType.POINTERCANCEL, + pointerEventData, browserEvent); }; /** - * Render a Polygon geometry into the canvas. Rendering is immediate and uses - * the current style. - * - * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon - * geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @api + * Triggers a combination of 'pointerout' and 'pointerleave' events. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawPolygonGeometry = - function(polygonGeometry, feature) { - if (!ol.extent.intersects(this.extent_, polygonGeometry.getExtent())) { - return; - } - if (this.strokeState_ || this.fillState_) { - if (this.fillState_) { - this.setContextFillState_(this.fillState_); - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - } - var context = this.context_; - context.beginPath(); - this.drawRings_(polygonGeometry.getOrientedFlatCoordinates(), - 0, polygonGeometry.getEnds(), polygonGeometry.getStride()); - if (this.fillState_) { - context.fill(); - } - if (this.strokeState_) { - context.stroke(); - } - } - if (this.text_ !== '') { - var flatInteriorPoint = polygonGeometry.getFlatInteriorPoint(); - this.drawText_(flatInteriorPoint, 0, 2, 2); +ol.pointer.PointerEventHandler.prototype.leaveOut = + function(pointerEventData, browserEvent) { + this.out(pointerEventData, browserEvent); + if (!this.contains_( + pointerEventData.target, + pointerEventData.relatedTarget)) { + this.leave(pointerEventData, browserEvent); } }; /** - * Render MultiPolygon geometry into the canvas. Rendering is immediate and - * uses the current style. - * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry. - * @param {ol.Feature} feature Feature. - * @api + * Triggers a combination of 'pointerover' and 'pointerevents' events. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry = - function(multiPolygonGeometry, feature) { - if (!ol.extent.intersects(this.extent_, multiPolygonGeometry.getExtent())) { - return; - } - if (this.strokeState_ || this.fillState_) { - if (this.fillState_) { - this.setContextFillState_(this.fillState_); - } - if (this.strokeState_) { - this.setContextStrokeState_(this.strokeState_); - } - var context = this.context_; - var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); - var offset = 0; - var endss = multiPolygonGeometry.getEndss(); - var stride = multiPolygonGeometry.getStride(); - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - context.beginPath(); - offset = this.drawRings_(flatCoordinates, offset, ends, stride); - if (this.fillState_) { - context.fill(); - } - if (this.strokeState_) { - context.stroke(); - } - } - } - if (this.text_ !== '') { - var flatInteriorPoints = multiPolygonGeometry.getFlatInteriorPoints(); - this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2); +ol.pointer.PointerEventHandler.prototype.enterOver = + function(pointerEventData, browserEvent) { + this.over(pointerEventData, browserEvent); + if (!this.contains_( + pointerEventData.target, + pointerEventData.relatedTarget)) { + this.enter(pointerEventData, browserEvent); } }; /** - * @inheritDoc + * @private + * @param {Element} container + * @param {Element} contained + * @return {boolean} Returns true if the container element + * contains the other element. */ -ol.render.canvas.Immediate.prototype.drawText = goog.abstractMethod; +ol.pointer.PointerEventHandler.prototype.contains_ = + function(container, contained) { + if (!contained) { + return false; + } + return goog.dom.contains(container, contained); +}; +// EVENT CREATION AND TRACKING /** - * FIXME: empty description for jsdoc + * Creates a new Event of type `inType`, based on the information in + * `pointerEventData`. + * + * @param {string} inType A string representing the type of event to create. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent + * @return {ol.pointer.PointerEvent} A PointerEvent of type `inType`. */ -ol.render.canvas.Immediate.prototype.flush = function() { - /** @type {Array.<number>} */ - var zs = Object.keys(this.callbacksByZIndex_).map(Number); - goog.array.sort(zs); - var i, ii, callbacks, j, jj; - for (i = 0, ii = zs.length; i < ii; ++i) { - callbacks = this.callbacksByZIndex_[zs[i].toString()]; - for (j = 0, jj = callbacks.length; j < jj; ++j) { - callbacks[j](this); - } - } +ol.pointer.PointerEventHandler.prototype.makeEvent = + function(inType, pointerEventData, browserEvent) { + return new ol.pointer.PointerEvent(inType, browserEvent, pointerEventData); }; /** - * @param {ol.render.canvas.FillState} fillState Fill state. - * @private + * Make and dispatch an event in one call. + * @param {string} inType A string representing the type of event. + * @param {Object} pointerEventData + * @param {goog.events.BrowserEvent} browserEvent */ -ol.render.canvas.Immediate.prototype.setContextFillState_ = - function(fillState) { - var context = this.context_; - var contextFillState = this.contextFillState_; - if (!contextFillState) { - context.fillStyle = fillState.fillStyle; - this.contextFillState_ = { - fillStyle: fillState.fillStyle - }; - } else { - if (contextFillState.fillStyle != fillState.fillStyle) { - contextFillState.fillStyle = context.fillStyle = fillState.fillStyle; - } - } +ol.pointer.PointerEventHandler.prototype.fireEvent = + function(inType, pointerEventData, browserEvent) { + var e = this.makeEvent(inType, pointerEventData, browserEvent); + this.dispatchEvent(e); }; /** - * @param {ol.render.canvas.StrokeState} strokeState Stroke state. - * @private + * Creates a pointer event from a native pointer event + * and dispatches this event. + * @param {goog.events.BrowserEvent} nativeEvent A platform event with a target. */ -ol.render.canvas.Immediate.prototype.setContextStrokeState_ = - function(strokeState) { - var context = this.context_; - var contextStrokeState = this.contextStrokeState_; - if (!contextStrokeState) { - context.lineCap = strokeState.lineCap; - if (ol.has.CANVAS_LINE_DASH) { - context.setLineDash(strokeState.lineDash); - } - context.lineJoin = strokeState.lineJoin; - context.lineWidth = strokeState.lineWidth; - context.miterLimit = strokeState.miterLimit; - context.strokeStyle = strokeState.strokeStyle; - this.contextStrokeState_ = { - lineCap: strokeState.lineCap, - lineDash: strokeState.lineDash, - lineJoin: strokeState.lineJoin, - lineWidth: strokeState.lineWidth, - miterLimit: strokeState.miterLimit, - strokeStyle: strokeState.strokeStyle - }; - } else { - if (contextStrokeState.lineCap != strokeState.lineCap) { - contextStrokeState.lineCap = context.lineCap = strokeState.lineCap; - } - if (ol.has.CANVAS_LINE_DASH) { - if (!goog.array.equals( - contextStrokeState.lineDash, strokeState.lineDash)) { - context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash); - } - } - if (contextStrokeState.lineJoin != strokeState.lineJoin) { - contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin; - } - if (contextStrokeState.lineWidth != strokeState.lineWidth) { - contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth; - } - if (contextStrokeState.miterLimit != strokeState.miterLimit) { - contextStrokeState.miterLimit = context.miterLimit = - strokeState.miterLimit; - } - if (contextStrokeState.strokeStyle != strokeState.strokeStyle) { - contextStrokeState.strokeStyle = context.strokeStyle = - strokeState.strokeStyle; - } - } +ol.pointer.PointerEventHandler.prototype.fireNativeEvent = + function(nativeEvent) { + var e = this.makeEvent(nativeEvent.type, nativeEvent.getBrowserEvent(), + nativeEvent); + this.dispatchEvent(e); }; /** - * @param {ol.render.canvas.TextState} textState Text state. - * @private + * Wrap a native mouse event into a pointer event. + * This proxy method is required for the legacy IE support. + * @param {string} eventType The pointer event type. + * @param {goog.events.BrowserEvent} browserEvent + * @return {ol.pointer.PointerEvent} */ -ol.render.canvas.Immediate.prototype.setContextTextState_ = - function(textState) { - var context = this.context_; - var contextTextState = this.contextTextState_; - if (!contextTextState) { - context.font = textState.font; - context.textAlign = textState.textAlign; - context.textBaseline = textState.textBaseline; - this.contextTextState_ = { - font: textState.font, - textAlign: textState.textAlign, - textBaseline: textState.textBaseline - }; - } else { - if (contextTextState.font != textState.font) { - contextTextState.font = context.font = textState.font; - } - if (contextTextState.textAlign != textState.textAlign) { - contextTextState.textAlign = context.textAlign = textState.textAlign; - } - if (contextTextState.textBaseline != textState.textBaseline) { - contextTextState.textBaseline = context.textBaseline = - textState.textBaseline; - } - } +ol.pointer.PointerEventHandler.prototype.wrapMouseEvent = + function(eventType, browserEvent) { + var pointerEvent = this.makeEvent( + eventType, + ol.pointer.MouseSource.prepareEvent(browserEvent, this), + browserEvent + ); + return pointerEvent; }; /** - * Set the fill and stroke style for subsequent draw operations. To clear - * either fill or stroke styles, pass null for the appropriate parameter. - * - * @param {ol.style.Fill} fillStyle Fill style. - * @param {ol.style.Stroke} strokeStyle Stroke style. - * @api + * @inheritDoc */ -ol.render.canvas.Immediate.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { - if (!fillStyle) { - this.fillState_ = null; - } else { - var fillStyleColor = fillStyle.getColor(); - this.fillState_ = { - fillStyle: ol.color.asString(fillStyleColor ? - fillStyleColor : ol.render.canvas.defaultFillStyle) - }; - } - if (!strokeStyle) { - this.strokeState_ = null; - } else { - var strokeStyleColor = strokeStyle.getColor(); - var strokeStyleLineCap = strokeStyle.getLineCap(); - var strokeStyleLineDash = strokeStyle.getLineDash(); - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - var strokeStyleWidth = strokeStyle.getWidth(); - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - this.strokeState_ = { - lineCap: strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap, - lineDash: strokeStyleLineDash ? - strokeStyleLineDash : ol.render.canvas.defaultLineDash, - lineJoin: strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin, - lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth), - miterLimit: strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit, - strokeStyle: ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle) - }; - } +ol.pointer.PointerEventHandler.prototype.disposeInternal = function() { + this.unregister_(); + goog.base(this, 'disposeInternal'); }; /** - * Set the image style for subsequent draw operations. Pass null to remove - * the image style. - * - * @param {ol.style.Image} imageStyle Image style. - * @api + * Constants for event names. + * @enum {string} */ -ol.render.canvas.Immediate.prototype.setImageStyle = function(imageStyle) { - if (!imageStyle) { - this.image_ = null; - } else { - var imageAnchor = imageStyle.getAnchor(); - // FIXME pixel ratio - var imageImage = imageStyle.getImage(1); - var imageOrigin = imageStyle.getOrigin(); - var imageSize = imageStyle.getSize(); - goog.asserts.assert(imageAnchor, 'imageAnchor must be truthy'); - goog.asserts.assert(imageImage, 'imageImage must be truthy'); - goog.asserts.assert(imageOrigin, 'imageOrigin must be truthy'); - goog.asserts.assert(imageSize, 'imageSize must be truthy'); - this.imageAnchorX_ = imageAnchor[0]; - this.imageAnchorY_ = imageAnchor[1]; - this.imageHeight_ = imageSize[1]; - this.image_ = imageImage; - this.imageOpacity_ = imageStyle.getOpacity(); - this.imageOriginX_ = imageOrigin[0]; - this.imageOriginY_ = imageOrigin[1]; - this.imageRotateWithView_ = imageStyle.getRotateWithView(); - this.imageRotation_ = imageStyle.getRotation(); - this.imageScale_ = imageStyle.getScale(); - this.imageSnapToPixel_ = imageStyle.getSnapToPixel(); - this.imageWidth_ = imageSize[0]; - } +ol.pointer.EventType = { + POINTERMOVE: 'pointermove', + POINTERDOWN: 'pointerdown', + POINTERUP: 'pointerup', + POINTEROVER: 'pointerover', + POINTEROUT: 'pointerout', + POINTERENTER: 'pointerenter', + POINTERLEAVE: 'pointerleave', + POINTERCANCEL: 'pointercancel' }; /** - * Set the text style for subsequent draw operations. Pass null to - * remove the text style. + * Properties to copy when cloning an event, with default values. + * @type {Array.<Array>} + */ +ol.pointer.CLONE_PROPS = [ + // MouseEvent + ['bubbles', false], + ['cancelable', false], + ['view', null], + ['detail', null], + ['screenX', 0], + ['screenY', 0], + ['clientX', 0], + ['clientY', 0], + ['ctrlKey', false], + ['altKey', false], + ['shiftKey', false], + ['metaKey', false], + ['button', 0], + ['relatedTarget', null], + // DOM Level 3 + ['buttons', 0], + // PointerEvent + ['pointerId', 0], + ['width', 0], + ['height', 0], + ['pressure', 0], + ['tiltX', 0], + ['tiltY', 0], + ['pointerType', ''], + ['hwTimestamp', 0], + ['isPrimary', false], + // event instance + ['type', ''], + ['target', null], + ['currentTarget', null], + ['which', 0] +]; + +goog.provide('ol.MapBrowserEvent'); +goog.provide('ol.MapBrowserEvent.EventType'); +goog.provide('ol.MapBrowserEventHandler'); +goog.provide('ol.MapBrowserPointerEvent'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Coordinate'); +goog.require('ol.MapEvent'); +goog.require('ol.Pixel'); +goog.require('ol.pointer.PointerEvent'); +goog.require('ol.pointer.PointerEventHandler'); + + + +/** + * @classdesc + * Events emitted as map browser events are instances of this type. + * See {@link ol.Map} for which events trigger a map browser event. * - * @param {ol.style.Text} textStyle Text style. - * @api + * @constructor + * @extends {ol.MapEvent} + * @implements {oli.MapBrowserEvent} + * @param {string} type Event type. + * @param {ol.Map} map Map. + * @param {goog.events.BrowserEvent} browserEvent Browser event. + * @param {boolean=} opt_dragging Is the map currently being dragged? + * @param {?olx.FrameState=} opt_frameState Frame state. */ -ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) { - if (!textStyle) { - this.text_ = ''; - } else { - var textFillStyle = textStyle.getFill(); - if (!textFillStyle) { - this.textFillState_ = null; - } else { - var textFillStyleColor = textFillStyle.getColor(); - this.textFillState_ = { - fillStyle: ol.color.asString(textFillStyleColor ? - textFillStyleColor : ol.render.canvas.defaultFillStyle) - }; - } - var textStrokeStyle = textStyle.getStroke(); - if (!textStrokeStyle) { - this.textStrokeState_ = null; - } else { - var textStrokeStyleColor = textStrokeStyle.getColor(); - var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); - var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); - var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); - var textStrokeStyleWidth = textStrokeStyle.getWidth(); - var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); - this.textStrokeState_ = { - lineCap: textStrokeStyleLineCap !== undefined ? - textStrokeStyleLineCap : ol.render.canvas.defaultLineCap, - lineDash: textStrokeStyleLineDash ? - textStrokeStyleLineDash : ol.render.canvas.defaultLineDash, - lineJoin: textStrokeStyleLineJoin !== undefined ? - textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin, - lineWidth: textStrokeStyleWidth !== undefined ? - textStrokeStyleWidth : ol.render.canvas.defaultLineWidth, - miterLimit: textStrokeStyleMiterLimit !== undefined ? - textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit, - strokeStyle: ol.color.asString(textStrokeStyleColor ? - textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle) - }; - } - var textFont = textStyle.getFont(); - var textOffsetX = textStyle.getOffsetX(); - var textOffsetY = textStyle.getOffsetY(); - var textRotation = textStyle.getRotation(); - var textScale = textStyle.getScale(); - var textText = textStyle.getText(); - var textTextAlign = textStyle.getTextAlign(); - var textTextBaseline = textStyle.getTextBaseline(); - this.textState_ = { - font: textFont !== undefined ? - textFont : ol.render.canvas.defaultFont, - textAlign: textTextAlign !== undefined ? - textTextAlign : ol.render.canvas.defaultTextAlign, - textBaseline: textTextBaseline !== undefined ? - textTextBaseline : ol.render.canvas.defaultTextBaseline - }; - this.text_ = textText !== undefined ? textText : ''; - this.textOffsetX_ = - textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0; - this.textOffsetY_ = - textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0; - this.textRotation_ = textRotation !== undefined ? textRotation : 0; - this.textScale_ = this.pixelRatio_ * (textScale !== undefined ? - textScale : 1); - } +ol.MapBrowserEvent = function(type, map, browserEvent, opt_dragging, + opt_frameState) { + + goog.base(this, type, map, opt_frameState); + + /** + * @const + * @type {goog.events.BrowserEvent} + */ + this.browserEvent = browserEvent; + + /** + * The original browser event. + * @const + * @type {Event} + * @api stable + */ + this.originalEvent = browserEvent.getBrowserEvent(); + + /** + * The pixel of the original browser event. + * @type {ol.Pixel} + * @api stable + */ + this.pixel = map.getEventPixel(this.originalEvent); + + /** + * The coordinate of the original browser event. + * @type {ol.Coordinate} + * @api stable + */ + this.coordinate = map.getCoordinateFromPixel(this.pixel); + + /** + * Indicates if the map is currently being dragged. Only set for + * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`. + * + * @type {boolean} + * @api stable + */ + this.dragging = opt_dragging !== undefined ? opt_dragging : false; + }; +goog.inherits(ol.MapBrowserEvent, ol.MapEvent); /** - * @const - * @private - * @type {Object.<ol.geom.GeometryType, - * function(this: ol.render.canvas.Immediate, - * (ol.geom.Geometry|ol.render.Feature), Object)>} + * Prevents the default browser action. + * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault + * @override + * @api stable */ -ol.render.canvas.Immediate.GEOMETRY_RENDERERS_ = { - 'Point': ol.render.canvas.Immediate.prototype.drawPointGeometry, - 'LineString': ol.render.canvas.Immediate.prototype.drawLineStringGeometry, - 'Polygon': ol.render.canvas.Immediate.prototype.drawPolygonGeometry, - 'MultiPoint': ol.render.canvas.Immediate.prototype.drawMultiPointGeometry, - 'MultiLineString': - ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry, - 'MultiPolygon': ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry, - 'GeometryCollection': - ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry, - 'Circle': ol.render.canvas.Immediate.prototype.drawCircleGeometry +ol.MapBrowserEvent.prototype.preventDefault = function() { + goog.base(this, 'preventDefault'); + this.browserEvent.preventDefault(); }; -goog.provide('ol.renderer.canvas.Layer'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Layer'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.renderer.Layer'); -goog.require('ol.vec.Mat4'); +/** + * Prevents further propagation of the current event. + * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation + * @override + * @api stable + */ +ol.MapBrowserEvent.prototype.stopPropagation = function() { + goog.base(this, 'stopPropagation'); + this.browserEvent.stopPropagation(); +}; /** * @constructor - * @extends {ol.renderer.Layer} - * @param {ol.layer.Layer} layer Layer. + * @extends {ol.MapBrowserEvent} + * @param {string} type Event type. + * @param {ol.Map} map Map. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @param {boolean=} opt_dragging Is the map currently being dragged? + * @param {?olx.FrameState=} opt_frameState Frame state. */ -ol.renderer.canvas.Layer = function(layer) { +ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging, + opt_frameState) { - goog.base(this, layer); + goog.base(this, type, map, pointerEvent.browserEvent, opt_dragging, + opt_frameState); /** - * @private - * @type {!goog.vec.Mat4.Number} + * @const + * @type {ol.pointer.PointerEvent} */ - this.transform_ = goog.vec.Mat4.createNumber(); + this.pointerEvent = pointerEvent; }; -goog.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer); +goog.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent); + /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {CanvasRenderingContext2D} context Context. + * @param {ol.Map} map The map with the viewport to listen to events on. + * @constructor + * @extends {goog.events.EventTarget} */ -ol.renderer.canvas.Layer.prototype.composeFrame = - function(frameState, layerState, context) { +ol.MapBrowserEventHandler = function(map) { - this.dispatchPreComposeEvent(context, frameState); + goog.base(this); - var image = this.getImage(); - if (image) { + /** + * This is the element that we will listen to the real events on. + * @type {ol.Map} + * @private + */ + this.map_ = map; - // clipped rendering if layer extent is set - var extent = layerState.extent; - var clipped = extent !== undefined; - if (clipped) { - goog.asserts.assert(extent !== undefined, - 'layerState extent is defined'); - var pixelRatio = frameState.pixelRatio; - var topLeft = ol.extent.getTopLeft(extent); - var topRight = ol.extent.getTopRight(extent); - var bottomRight = ol.extent.getBottomRight(extent); - var bottomLeft = ol.extent.getBottomLeft(extent); + /** + * @type {number} + * @private + */ + this.clickTimeoutId_ = 0; - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - topLeft, topLeft); - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - topRight, topRight); - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - bottomRight, bottomRight); - ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, - bottomLeft, bottomLeft); + /** + * @type {boolean} + * @private + */ + this.dragging_ = false; - context.save(); - context.beginPath(); - context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio); - context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio); - context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio); - context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio); - context.clip(); - } + /** + * @type {Array.<goog.events.Key>} + * @private + */ + this.dragListenerKeys_ = null; - var imageTransform = this.getImageTransform(); - // for performance reasons, context.save / context.restore is not used - // to save and restore the transformation matrix and the opacity. - // see http://jsperf.com/context-save-restore-versus-variable - var alpha = context.globalAlpha; - context.globalAlpha = layerState.opacity; + /** + * @type {goog.events.Key} + * @private + */ + this.pointerdownListenerKey_ = null; - // for performance reasons, context.setTransform is only used - // when the view is rotated. see http://jsperf.com/canvas-transform - if (frameState.viewState.rotation === 0) { - var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3); - var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3); - var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0); - var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1); - context.drawImage(image, 0, 0, +image.width, +image.height, - Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh)); - } else { - context.setTransform( - goog.vec.Mat4.getElement(imageTransform, 0, 0), - goog.vec.Mat4.getElement(imageTransform, 1, 0), - goog.vec.Mat4.getElement(imageTransform, 0, 1), - goog.vec.Mat4.getElement(imageTransform, 1, 1), - goog.vec.Mat4.getElement(imageTransform, 0, 3), - goog.vec.Mat4.getElement(imageTransform, 1, 3)); - context.drawImage(image, 0, 0); - context.setTransform(1, 0, 0, 1, 0, 0); - } - context.globalAlpha = alpha; + /** + * The most recent "down" type event (or null if none have occurred). + * Set on pointerdown. + * @type {ol.pointer.PointerEvent} + * @private + */ + this.down_ = null; - if (clipped) { - context.restore(); - } - } + var element = this.map_.getViewport(); - this.dispatchPostComposeEvent(context, frameState); + /** + * @type {number} + * @private + */ + this.activePointers_ = 0; + + /** + * @type {Object.<number, boolean>} + * @private + */ + this.trackedTouches_ = {}; + + /** + * Event handler which generates pointer events for + * the viewport element. + * + * @type {ol.pointer.PointerEventHandler} + * @private + */ + this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element); + + /** + * Event handler which generates pointer events for + * the document (used when dragging). + * + * @type {ol.pointer.PointerEventHandler} + * @private + */ + this.documentPointerEventHandler_ = null; + + this.pointerdownListenerKey_ = goog.events.listen(this.pointerEventHandler_, + ol.pointer.EventType.POINTERDOWN, + this.handlePointerDown_, false, this); + + this.relayedListenerKey_ = goog.events.listen(this.pointerEventHandler_, + ol.pointer.EventType.POINTERMOVE, + this.relayEvent_, false, this); }; +goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget); /** - * @param {ol.render.EventType} type Event type. - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. * @private */ -ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = - function(type, context, frameState, opt_transform) { - var layer = this.getLayer(); - if (layer.hasListener(type)) { - var transform = opt_transform !== undefined ? - opt_transform : this.getTransform(frameState, 0); - var render = new ol.render.canvas.Immediate( - context, frameState.pixelRatio, frameState.extent, transform, - frameState.viewState.rotation); - var composeEvent = new ol.render.Event(type, layer, render, frameState, - context, null); - layer.dispatchEvent(composeEvent); - render.flush(); +ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) { + var newEvent; + newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + if (this.clickTimeoutId_ !== 0) { + // double-click + goog.global.clearTimeout(this.clickTimeoutId_); + this.clickTimeoutId_ = 0; + newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + } else { + // click + this.clickTimeoutId_ = goog.global.setTimeout(goog.bind(function() { + this.clickTimeoutId_ = 0; + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + }, this), 250); } }; /** - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @protected + * Keeps track on how many pointers are currently active. + * + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private */ -ol.renderer.canvas.Layer.prototype.dispatchPostComposeEvent = - function(context, frameState, opt_transform) { - this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, context, - frameState, opt_transform); +ol.MapBrowserEventHandler.prototype.updateActivePointers_ = + function(pointerEvent) { + var event = pointerEvent; + + if (event.type == ol.MapBrowserEvent.EventType.POINTERUP || + event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) { + delete this.trackedTouches_[event.pointerId]; + } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { + this.trackedTouches_[event.pointerId] = true; + } + this.activePointers_ = goog.object.getCount(this.trackedTouches_); }; /** - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @protected + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private */ -ol.renderer.canvas.Layer.prototype.dispatchPreComposeEvent = - function(context, frameState, opt_transform) { - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, context, - frameState, opt_transform); +ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) { + this.updateActivePointers_(pointerEvent); + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + + // We emulate click events on left mouse button click, touch contact, and pen + // contact. isMouseActionButton returns true in these cases (evt.button is set + // to 0). + // See http://www.w3.org/TR/pointerevents/#button-states + if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) { + goog.asserts.assert(this.down_, 'this.down_ must be truthy'); + this.emulateClick_(this.down_); + } + + goog.asserts.assert(this.activePointers_ >= 0, + 'this.activePointers_ should be equal to or larger than 0'); + if (this.activePointers_ === 0) { + this.dragListenerKeys_.forEach(goog.events.unlistenByKey); + this.dragListenerKeys_ = null; + this.dragging_ = false; + this.down_ = null; + goog.dispose(this.documentPointerEventHandler_); + this.documentPointerEventHandler_ = null; + } }; /** - * @param {CanvasRenderingContext2D} context Context. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number=} opt_transform Transform. - * @protected + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @return {boolean} If the left mouse button was pressed. + * @private */ -ol.renderer.canvas.Layer.prototype.dispatchRenderEvent = - function(context, frameState, opt_transform) { - this.dispatchComposeEvent_(ol.render.EventType.RENDER, context, - frameState, opt_transform); +ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = + function(pointerEvent) { + return pointerEvent.button === 0; }; /** - * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private */ -ol.renderer.canvas.Layer.prototype.getImage = goog.abstractMethod; +ol.MapBrowserEventHandler.prototype.handlePointerDown_ = + function(pointerEvent) { + this.updateActivePointers_(pointerEvent); + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + + this.down_ = pointerEvent; + + if (!this.dragListenerKeys_) { + /* Set up a pointer event handler on the `document`, + * which is required when the pointer is moved outside + * the viewport when dragging. + */ + this.documentPointerEventHandler_ = + new ol.pointer.PointerEventHandler(document); + + this.dragListenerKeys_ = [ + goog.events.listen(this.documentPointerEventHandler_, + ol.MapBrowserEvent.EventType.POINTERMOVE, + this.handlePointerMove_, false, this), + goog.events.listen(this.documentPointerEventHandler_, + ol.MapBrowserEvent.EventType.POINTERUP, + this.handlePointerUp_, false, this), + /* Note that the listener for `pointercancel is set up on + * `pointerEventHandler_` and not `documentPointerEventHandler_` like + * the `pointerup` and `pointermove` listeners. + * + * The reason for this is the following: `TouchSource.vacuumTouches_()` + * issues `pointercancel` events, when there was no `touchend` for a + * `touchstart`. Now, let's say a first `touchstart` is registered on + * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. + * But `documentPointerEventHandler_` doesn't know about the first + * `touchstart`. If there is no `touchend` for the `touchstart`, we can + * only receive a `touchcancel` from `pointerEventHandler_`, because it is + * only registered there. + */ + goog.events.listen(this.pointerEventHandler_, + ol.MapBrowserEvent.EventType.POINTERCANCEL, + this.handlePointerUp_, false, this) + ]; + } +}; /** - * @return {!goog.vec.Mat4.Number} Image transform. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private */ -ol.renderer.canvas.Layer.prototype.getImageTransform = goog.abstractMethod; +ol.MapBrowserEventHandler.prototype.handlePointerMove_ = + function(pointerEvent) { + // Fix IE10 on windows Surface : When you tap the tablet, it triggers + // multiple pointermove events between pointerdown and pointerup with + // the exact same coordinates of the pointerdown event. To avoid a + // 'false' touchmove event to be dispatched , we test if the pointer + // effectively moved. + if (this.isMoving_(pointerEvent)) { + this.dragging_ = true; + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent, + this.dragging_); + this.dispatchEvent(newEvent); + } + + // Some native android browser triggers mousemove events during small period + // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or + // https://code.google.com/p/android/issues/detail?id=19827 + // ex: Galaxy Tab P3110 + Android 4.1.1 + pointerEvent.preventDefault(); +}; /** - * @param {olx.FrameState} frameState Frame state. - * @param {number} offsetX Offset on the x-axis in view coordinates. - * @protected - * @return {!goog.vec.Mat4.Number} Transform. + * Wrap and relay a pointer event. Note that this requires that the type + * string for the MapBrowserPointerEvent matches the PointerEvent type. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private */ -ol.renderer.canvas.Layer.prototype.getTransform = - function(frameState, offsetX) { - var viewState = frameState.viewState; - var pixelRatio = frameState.pixelRatio; - return ol.vec.Mat4.makeTransform2D(this.transform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio / viewState.resolution, - -pixelRatio / viewState.resolution, - -viewState.rotation, - -viewState.center[0] + offsetX, - -viewState.center[1]); +ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) { + var dragging = !!(this.down_ && this.isMoving_(pointerEvent)); + this.dispatchEvent(new ol.MapBrowserPointerEvent( + pointerEvent.type, this.map_, pointerEvent, dragging)); }; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @return {boolean} whether composeFrame should be called. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @return {boolean} + * @private */ -ol.renderer.canvas.Layer.prototype.prepareFrame = goog.abstractMethod; +ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) { + return pointerEvent.clientX != this.down_.clientX || + pointerEvent.clientY != this.down_.clientY; +}; /** - * @param {ol.Pixel} pixelOnMap Pixel. - * @param {goog.vec.Mat4.Number} imageTransformInv The transformation matrix - * to convert from a map pixel to a canvas pixel. - * @return {ol.Pixel} - * @protected + * @inheritDoc */ -ol.renderer.canvas.Layer.prototype.getPixelOnCanvas = - function(pixelOnMap, imageTransformInv) { - var pixelOnCanvas = [0, 0]; - ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas); - return pixelOnCanvas; +ol.MapBrowserEventHandler.prototype.disposeInternal = function() { + if (this.relayedListenerKey_) { + goog.events.unlistenByKey(this.relayedListenerKey_); + this.relayedListenerKey_ = null; + } + if (this.pointerdownListenerKey_) { + goog.events.unlistenByKey(this.pointerdownListenerKey_); + this.pointerdownListenerKey_ = null; + } + if (this.dragListenerKeys_) { + this.dragListenerKeys_.forEach(goog.events.unlistenByKey); + this.dragListenerKeys_ = null; + } + if (this.documentPointerEventHandler_) { + goog.dispose(this.documentPointerEventHandler_); + this.documentPointerEventHandler_ = null; + } + if (this.pointerEventHandler_) { + goog.dispose(this.pointerEventHandler_); + this.pointerEventHandler_ = null; + } + goog.base(this, 'disposeInternal'); }; /** - * @param {ol.Size} size Size. - * @return {boolean} True when the canvas with the current size does not exceed - * the maximum dimensions. + * Constants for event names. + * @enum {string} */ -ol.renderer.canvas.Layer.testCanvasSize = (function() { +ol.MapBrowserEvent.EventType = { /** - * @type {CanvasRenderingContext2D} + * A true single click with no dragging and no double click. Note that this + * event is delayed by 250 ms to ensure that it is not a double click. + * @event ol.MapBrowserEvent#singleclick + * @api stable */ - var context = null; + SINGLECLICK: 'singleclick', /** - * @type {ImageData} + * A click with no dragging. A double click will fire two of this. + * @event ol.MapBrowserEvent#click + * @api stable */ - var imageData = null; - - return function(size) { - if (!context) { - context = ol.dom.createCanvasContext2D(1, 1); - imageData = context.createImageData(1, 1); - var data = imageData.data; - data[0] = 42; - data[1] = 84; - data[2] = 126; - data[3] = 255; - } - var canvas = context.canvas; - var good = size[0] <= canvas.width && size[1] <= canvas.height; - if (!good) { - canvas.width = size[0]; - canvas.height = size[1]; - var x = size[0] - 1; - var y = size[1] - 1; - context.putImageData(imageData, x, y); - var result = context.getImageData(x, y, 1, 1); - good = goog.array.equals(imageData.data, result.data); - } - return good; - }; -})(); + CLICK: goog.events.EventType.CLICK, -goog.provide('ol.render.IReplayGroup'); + /** + * A true double click, with no dragging. + * @event ol.MapBrowserEvent#dblclick + * @api stable + */ + DBLCLICK: goog.events.EventType.DBLCLICK, -goog.require('ol.render.VectorContext'); + /** + * Triggered when a pointer is dragged. + * @event ol.MapBrowserEvent#pointerdrag + * @api + */ + POINTERDRAG: 'pointerdrag', + /** + * Triggered when a pointer is moved. Note that on touch devices this is + * triggered when the map is panned, so is not the same as mousemove. + * @event ol.MapBrowserEvent#pointermove + * @api stable + */ + POINTERMOVE: 'pointermove', -/** - * @enum {string} - */ -ol.render.ReplayType = { - IMAGE: 'Image', - LINE_STRING: 'LineString', - POLYGON: 'Polygon', - TEXT: 'Text' + POINTERDOWN: 'pointerdown', + POINTERUP: 'pointerup', + POINTEROVER: 'pointerover', + POINTEROUT: 'pointerout', + POINTERENTER: 'pointerenter', + POINTERLEAVE: 'pointerleave', + POINTERCANCEL: 'pointercancel' }; +goog.provide('ol.ImageBase'); +goog.provide('ol.ImageState'); -/** - * @const - * @type {Array.<ol.render.ReplayType>} - */ -ol.render.REPLAY_ORDER = [ - ol.render.ReplayType.POLYGON, - ol.render.ReplayType.LINE_STRING, - ol.render.ReplayType.IMAGE, - ol.render.ReplayType.TEXT -]; - +goog.require('goog.asserts'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('ol.Attribution'); +goog.require('ol.Extent'); /** - * @interface + * @enum {number} */ -ol.render.IReplayGroup = function() { +ol.ImageState = { + IDLE: 0, + LOADING: 1, + LOADED: 2, + ERROR: 3 }; -/** - * @param {number|undefined} zIndex Z index. - * @param {ol.render.ReplayType} replayType Replay type. - * @return {ol.render.VectorContext} Replay. - */ -ol.render.IReplayGroup.prototype.getReplay = function(zIndex, replayType) { -}; - /** - * @return {boolean} Is empty. + * @constructor + * @extends {goog.events.EventTarget} + * @param {ol.Extent} extent Extent. + * @param {number|undefined} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.ImageState} state State. + * @param {Array.<ol.Attribution>} attributions Attributions. */ -ol.render.IReplayGroup.prototype.isEmpty = function() { -}; +ol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) { -// FIXME add option to apply snapToPixel to all coordinates? -// FIXME can eliminate empty set styles and strokes (when all geoms skipped) + goog.base(this); -goog.provide('ol.render.canvas.ImageReplay'); -goog.provide('ol.render.canvas.LineStringReplay'); -goog.provide('ol.render.canvas.PolygonReplay'); -goog.provide('ol.render.canvas.Replay'); -goog.provide('ol.render.canvas.ReplayGroup'); -goog.provide('ol.render.canvas.TextReplay'); + /** + * @private + * @type {Array.<ol.Attribution>} + */ + this.attributions_ = attributions; + + /** + * @protected + * @type {ol.Extent} + */ + this.extent = extent; + + /** + * @private + * @type {number} + */ + this.pixelRatio_ = pixelRatio; + + /** + * @protected + * @type {number|undefined} + */ + this.resolution = resolution; + + /** + * @protected + * @type {ol.ImageState} + */ + this.state = state; + +}; +goog.inherits(ol.ImageBase, goog.events.EventTarget); + + +/** + * @protected + */ +ol.ImageBase.prototype.changed = function() { + this.dispatchEvent(goog.events.EventType.CHANGE); +}; + + +/** + * @return {Array.<ol.Attribution>} Attributions. + */ +ol.ImageBase.prototype.getAttributions = function() { + return this.attributions_; +}; + + +/** + * @return {ol.Extent} Extent. + */ +ol.ImageBase.prototype.getExtent = function() { + return this.extent; +}; + + +/** + * @param {Object=} opt_context Object. + * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image. + */ +ol.ImageBase.prototype.getImage = goog.abstractMethod; + + +/** + * @return {number} PixelRatio. + */ +ol.ImageBase.prototype.getPixelRatio = function() { + return this.pixelRatio_; +}; + + +/** + * @return {number} Resolution. + */ +ol.ImageBase.prototype.getResolution = function() { + goog.asserts.assert(this.resolution !== undefined, 'resolution not yet set'); + return this.resolution; +}; + + +/** + * @return {ol.ImageState} State. + */ +ol.ImageBase.prototype.getState = function() { + return this.state; +}; + + +/** + * Load not yet loaded URI. + */ +ol.ImageBase.prototype.load = goog.abstractMethod; + +goog.provide('ol.vec.Mat4'); +goog.provide('ol.vec.Mat4.Number'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.array'); -goog.require('ol.color'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.extent.Relationship'); -goog.require('ol.geom.flat.simplify'); -goog.require('ol.geom.flat.transform'); -goog.require('ol.has'); -goog.require('ol.render.IReplayGroup'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.canvas'); -goog.require('ol.vec.Mat4'); /** - * @enum {number} + * A alias for the goog.vec.Number type. + * @typedef {goog.vec.Number} */ -ol.render.canvas.Instruction = { - BEGIN_GEOMETRY: 0, - BEGIN_PATH: 1, - CIRCLE: 2, - CLOSE_PATH: 3, - DRAW_IMAGE: 4, - DRAW_TEXT: 5, - END_GEOMETRY: 6, - FILL: 7, - MOVE_TO_LINE_TO: 8, - SET_FILL_STYLE: 9, - SET_STROKE_STYLE: 10, - SET_TEXT_STYLE: 11, - STROKE: 12 +ol.vec.Mat4.Number; + + +/** + * @param {!goog.vec.Mat4.Number} mat Matrix. + * @param {number} translateX1 Translate X1. + * @param {number} translateY1 Translate Y1. + * @param {number} scaleX Scale X. + * @param {number} scaleY Scale Y. + * @param {number} rotation Rotation. + * @param {number} translateX2 Translate X2. + * @param {number} translateY2 Translate Y2. + * @return {!goog.vec.Mat4.Number} Matrix. + */ +ol.vec.Mat4.makeTransform2D = function(mat, translateX1, translateY1, + scaleX, scaleY, rotation, translateX2, translateY2) { + goog.vec.Mat4.makeIdentity(mat); + if (translateX1 !== 0 || translateY1 !== 0) { + goog.vec.Mat4.translate(mat, translateX1, translateY1, 0); + } + if (scaleX != 1 || scaleY != 1) { + goog.vec.Mat4.scale(mat, scaleX, scaleY, 1); + } + if (rotation !== 0) { + goog.vec.Mat4.rotateZ(mat, rotation); + } + if (translateX2 !== 0 || translateY2 !== 0) { + goog.vec.Mat4.translate(mat, translateX2, translateY2, 0); + } + return mat; +}; + + +/** + * Returns true if mat1 and mat2 represent the same 2D transformation. + * @param {goog.vec.Mat4.Number} mat1 Matrix 1. + * @param {goog.vec.Mat4.Number} mat2 Matrix 2. + * @return {boolean} Equal 2D. + */ +ol.vec.Mat4.equals2D = function(mat1, mat2) { + return ( + goog.vec.Mat4.getElement(mat1, 0, 0) == + goog.vec.Mat4.getElement(mat2, 0, 0) && + goog.vec.Mat4.getElement(mat1, 1, 0) == + goog.vec.Mat4.getElement(mat2, 1, 0) && + goog.vec.Mat4.getElement(mat1, 0, 1) == + goog.vec.Mat4.getElement(mat2, 0, 1) && + goog.vec.Mat4.getElement(mat1, 1, 1) == + goog.vec.Mat4.getElement(mat2, 1, 1) && + goog.vec.Mat4.getElement(mat1, 0, 3) == + goog.vec.Mat4.getElement(mat2, 0, 3) && + goog.vec.Mat4.getElement(mat1, 1, 3) == + goog.vec.Mat4.getElement(mat2, 1, 3)); +}; + + +/** + * Transforms the given vector with the given matrix storing the resulting, + * transformed vector into resultVec. The input vector is multiplied against the + * upper 2x4 matrix omitting the projective component. + * + * @param {goog.vec.Mat4.Number} mat The matrix supplying the transformation. + * @param {Array.<number>} vec The 3 element vector to transform. + * @param {Array.<number>} resultVec The 3 element vector to receive the results + * (may be vec). + * @return {Array.<number>} return resultVec so that operations can be + * chained together. + */ +ol.vec.Mat4.multVec2 = function(mat, vec, resultVec) { + var m00 = goog.vec.Mat4.getElement(mat, 0, 0); + var m10 = goog.vec.Mat4.getElement(mat, 1, 0); + var m01 = goog.vec.Mat4.getElement(mat, 0, 1); + var m11 = goog.vec.Mat4.getElement(mat, 1, 1); + var m03 = goog.vec.Mat4.getElement(mat, 0, 3); + var m13 = goog.vec.Mat4.getElement(mat, 1, 3); + var x = vec[0], y = vec[1]; + resultVec[0] = m00 * x + m01 * y + m03; + resultVec[1] = m10 * x + m11 * y + m13; + return resultVec; }; +goog.provide('ol.renderer.Layer'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.functions'); +goog.require('ol'); +goog.require('ol.ImageState'); +goog.require('ol.Observable'); +goog.require('ol.TileRange'); +goog.require('ol.TileState'); +goog.require('ol.layer.Layer'); +goog.require('ol.source.Source'); +goog.require('ol.source.State'); +goog.require('ol.source.Tile'); +goog.require('ol.tilecoord'); +goog.require('ol.vec.Mat4'); + /** * @constructor - * @extends {ol.render.VectorContext} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected + * @extends {ol.Observable} + * @param {ol.layer.Layer} layer Layer. * @struct */ -ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) { +ol.renderer.Layer = function(layer) { + goog.base(this); /** - * @protected - * @type {number} + * @private + * @type {ol.layer.Layer} */ - this.tolerance = tolerance; + this.layer_ = layer; - /** - * @protected - * @const - * @type {ol.Extent} - */ - this.maxExtent = maxExtent; - /** - * @private - * @type {ol.Extent} - */ - this.bufferedMaxExtent_ = null; +}; +goog.inherits(ol.renderer.Layer, ol.Observable); - /** - * @protected - * @type {number} - */ - this.maxLineWidth = 0; - /** - * @protected - * @const - * @type {number} - */ - this.resolution = resolution; +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {olx.FrameState} frameState Frame state. + * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T} + * callback Feature callback. + * @param {S} thisArg Value to use as `this` when executing `callback`. + * @return {T|undefined} Callback result. + * @template S,T + */ +ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction; - /** - * @private - * @type {Array.<*>} - */ - this.beginGeometryInstruction1_ = null; - /** - * @private - * @type {Array.<*>} - */ - this.beginGeometryInstruction2_ = null; +/** + * @param {ol.Pixel} pixel Pixel. + * @param {olx.FrameState} frameState Frame state. + * @param {function(this: S, ol.layer.Layer): T} callback Layer callback. + * @param {S} thisArg Value to use as `this` when executing `callback`. + * @return {T|undefined} Callback result. + * @template S,T + */ +ol.renderer.Layer.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg) { + var coordinate = pixel.slice(); + ol.vec.Mat4.multVec2( + frameState.pixelToCoordinateMatrix, coordinate, coordinate); - /** - * @protected - * @type {Array.<*>} - */ - this.instructions = []; + var hasFeature = this.forEachFeatureAtCoordinate( + coordinate, frameState, goog.functions.TRUE, this); - /** - * @protected - * @type {Array.<number>} - */ - this.coordinates = []; + if (hasFeature) { + return callback.call(thisArg, this.layer_); + } else { + return undefined; + } +}; - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.renderedTransform_ = goog.vec.Mat4.createNumber(); - /** - * @protected - * @type {Array.<*>} - */ - this.hitDetectionInstructions = []; +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {olx.FrameState} frameState Frame state. + * @return {boolean} Is there a feature at the given coordinate? + */ +ol.renderer.Layer.prototype.hasFeatureAtCoordinate = goog.functions.FALSE; - /** - * @private - * @type {Array.<number>} - */ - this.pixelCoordinates_ = []; - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); +/** + * Create a function that adds loaded tiles to the tile lookup. + * @param {ol.source.Tile} source Tile source. + * @param {ol.proj.Projection} projection Projection of the tiles. + * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded + * tiles by zoom level. + * @return {function(number, ol.TileRange):boolean} A function that can be + * called with a zoom level and a tile range to add loaded tiles to the + * lookup. + * @protected + */ +ol.renderer.Layer.prototype.createLoadedTileFinder = + function(source, projection, tiles) { + return ( + /** + * @param {number} zoom Zoom level. + * @param {ol.TileRange} tileRange Tile range. + * @return {boolean} The tile range is fully loaded. + */ + function(zoom, tileRange) { + return source.forEachLoadedTile(projection, zoom, + tileRange, function(tile) { + if (!tiles[zoom]) { + tiles[zoom] = {}; + } + tiles[zoom][tile.tileCoord.toString()] = tile; + }); + }); }; -goog.inherits(ol.render.canvas.Replay, ol.render.VectorContext); /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {boolean} close Close. - * @protected - * @return {number} My end. + * @return {ol.layer.Layer} Layer. */ -ol.render.canvas.Replay.prototype.appendFlatCoordinates = - function(flatCoordinates, offset, end, stride, close) { +ol.renderer.Layer.prototype.getLayer = function() { + return this.layer_; +}; - var myEnd = this.coordinates.length; - var extent = this.getBufferedMaxExtent(); - var lastCoord = [flatCoordinates[offset], flatCoordinates[offset + 1]]; - var nextCoord = [NaN, NaN]; - var skipped = true; - var i, lastRel, nextRel; - for (i = offset + stride; i < end; i += stride) { - nextCoord[0] = flatCoordinates[i]; - nextCoord[1] = flatCoordinates[i + 1]; - nextRel = ol.extent.coordinateRelationship(extent, nextCoord); - if (nextRel !== lastRel) { - if (skipped) { - this.coordinates[myEnd++] = lastCoord[0]; - this.coordinates[myEnd++] = lastCoord[1]; - } - this.coordinates[myEnd++] = nextCoord[0]; - this.coordinates[myEnd++] = nextCoord[1]; - skipped = false; - } else if (nextRel === ol.extent.Relationship.INTERSECTING) { - this.coordinates[myEnd++] = nextCoord[0]; - this.coordinates[myEnd++] = nextCoord[1]; - skipped = false; - } else { - skipped = true; - } - lastCoord[0] = nextCoord[0]; - lastCoord[1] = nextCoord[1]; - lastRel = nextRel; +/** + * Handle changes in image state. + * @param {goog.events.Event} event Image change event. + * @private + */ +ol.renderer.Layer.prototype.handleImageChange_ = function(event) { + var image = /** @type {ol.Image} */ (event.target); + if (image.getState() === ol.ImageState.LOADED) { + this.renderIfReadyAndVisible(); } +}; - // handle case where there is only one point to append - if (i === offset + stride) { - this.coordinates[myEnd++] = lastCoord[0]; - this.coordinates[myEnd++] = lastCoord[1]; - } - if (close) { - this.coordinates[myEnd++] = flatCoordinates[offset]; - this.coordinates[myEnd++] = flatCoordinates[offset + 1]; +/** + * Load the image if not already loaded, and register the image change + * listener if needed. + * @param {ol.ImageBase} image Image. + * @return {boolean} `true` if the image is already loaded, `false` + * otherwise. + * @protected + */ +ol.renderer.Layer.prototype.loadImage = function(image) { + var imageState = image.getState(); + if (imageState != ol.ImageState.LOADED && + imageState != ol.ImageState.ERROR) { + // the image is either "idle" or "loading", register the change + // listener (a noop if the listener was already registered) + goog.asserts.assert(imageState == ol.ImageState.IDLE || + imageState == ol.ImageState.LOADING, + 'imageState is "idle" or "loading"'); + goog.events.listen(image, goog.events.EventType.CHANGE, + this.handleImageChange_, false, this); } - return myEnd; + if (imageState == ol.ImageState.IDLE) { + image.load(); + imageState = image.getState(); + goog.asserts.assert(imageState == ol.ImageState.LOADING || + imageState == ol.ImageState.LOADED, + 'imageState is "loading" or "loaded"'); + } + return imageState == ol.ImageState.LOADED; }; /** * @protected - * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. */ -ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) { - this.beginGeometryInstruction1_ = - [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0]; - this.instructions.push(this.beginGeometryInstruction1_); - this.beginGeometryInstruction2_ = - [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0]; - this.hitDetectionInstructions.push(this.beginGeometryInstruction2_); +ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() { + var layer = this.getLayer(); + if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) { + this.changed(); + } }; /** - * @private - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.<*>} instructions Instructions array. - * @param {function((ol.Feature|ol.render.Feature)): T|undefined} - * featureCallback Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. - * @return {T|undefined} Callback result. - * @template T + * @param {olx.FrameState} frameState Frame state. + * @param {ol.source.Tile} tileSource Tile source. + * @protected */ -ol.render.canvas.Replay.prototype.replay_ = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash, - instructions, featureCallback, opt_hitExtent) { - /** @type {Array.<number>} */ - var pixelCoordinates; - if (ol.vec.Mat4.equals2D(transform, this.renderedTransform_)) { - pixelCoordinates = this.pixelCoordinates_; - } else { - pixelCoordinates = ol.geom.flat.transform.transform2D( - this.coordinates, 0, this.coordinates.length, 2, - transform, this.pixelCoordinates_); - goog.vec.Mat4.setFromArray(this.renderedTransform_, transform); - goog.asserts.assert(pixelCoordinates === this.pixelCoordinates_, - 'pixelCoordinates should be the same as this.pixelCoordinates_'); +ol.renderer.Layer.prototype.scheduleExpireCache = + function(frameState, tileSource) { + if (tileSource.canExpireCache()) { + frameState.postRenderFunctions.push( + goog.partial( + /** + * @param {ol.source.Tile} tileSource Tile source. + * @param {ol.Map} map Map. + * @param {olx.FrameState} frameState Frame state. + */ + function(tileSource, map, frameState) { + var tileSourceKey = goog.getUid(tileSource).toString(); + tileSource.expireCache(frameState.viewState.projection, + frameState.usedTiles[tileSourceKey]); + }, tileSource)); } - var skipFeatures = !goog.object.isEmpty(skippedFeaturesHash); - var i = 0; // instruction index - var ii = instructions.length; // end of instructions - var d = 0; // data index - var dd; // end of per-instruction data - var localTransform = this.tmpLocalTransform_; - var prevX, prevY, roundX, roundY; - while (i < ii) { - var instruction = instructions[i]; - var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]); - var feature, fill, stroke, text, x, y; - switch (type) { - case ol.render.canvas.Instruction.BEGIN_GEOMETRY: - feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); - if ((skipFeatures && - skippedFeaturesHash[goog.getUid(feature).toString()]) || - !feature.getGeometry()) { - i = /** @type {number} */ (instruction[2]); - } else if (opt_hitExtent !== undefined && !ol.extent.intersects( - /** @type {Array<number>} */ (opt_hitExtent), - feature.getGeometry().getExtent())) { - i = /** @type {number} */ (instruction[2]); - } else { - ++i; - } - break; - case ol.render.canvas.Instruction.BEGIN_PATH: - context.beginPath(); - ++i; - break; - case ol.render.canvas.Instruction.CIRCLE: - goog.asserts.assert(goog.isNumber(instruction[1]), - 'second instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - var x1 = pixelCoordinates[d]; - var y1 = pixelCoordinates[d + 1]; - var x2 = pixelCoordinates[d + 2]; - var y2 = pixelCoordinates[d + 3]; - var dx = x2 - x1; - var dy = y2 - y1; - var r = Math.sqrt(dx * dx + dy * dy); - context.arc(x1, y1, r, 0, 2 * Math.PI, true); - ++i; - break; - case ol.render.canvas.Instruction.CLOSE_PATH: - context.closePath(); - ++i; - break; - case ol.render.canvas.Instruction.DRAW_IMAGE: - goog.asserts.assert(goog.isNumber(instruction[1]), - 'second instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - goog.asserts.assert(goog.isNumber(instruction[2]), - 'third instruction should be a number'); - dd = /** @type {number} */ (instruction[2]); - var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */ - (instruction[3]); - // Remaining arguments in DRAW_IMAGE are in alphabetical order - var anchorX = /** @type {number} */ (instruction[4]) * pixelRatio; - var anchorY = /** @type {number} */ (instruction[5]) * pixelRatio; - var height = /** @type {number} */ (instruction[6]); - var opacity = /** @type {number} */ (instruction[7]); - var originX = /** @type {number} */ (instruction[8]); - var originY = /** @type {number} */ (instruction[9]); - var rotateWithView = /** @type {boolean} */ (instruction[10]); - var rotation = /** @type {number} */ (instruction[11]); - var scale = /** @type {number} */ (instruction[12]); - var snapToPixel = /** @type {boolean} */ (instruction[13]); - var width = /** @type {number} */ (instruction[14]); - if (rotateWithView) { - rotation += viewRotation; - } - for (; d < dd; d += 2) { - x = pixelCoordinates[d] - anchorX; - y = pixelCoordinates[d + 1] - anchorY; - if (snapToPixel) { - x = (x + 0.5) | 0; - y = (y + 0.5) | 0; - } - if (scale != 1 || rotation !== 0) { - var centerX = x + anchorX; - var centerY = y + anchorY; - ol.vec.Mat4.makeTransform2D( - localTransform, centerX, centerY, scale, scale, - rotation, -centerX, -centerY); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - var alpha = context.globalAlpha; - if (opacity != 1) { - context.globalAlpha = alpha * opacity; - } +}; - context.drawImage(image, originX, originY, width, height, - x, y, width * pixelRatio, height * pixelRatio); - if (opacity != 1) { - context.globalAlpha = alpha; - } - if (scale != 1 || rotation !== 0) { - context.setTransform(1, 0, 0, 1, 0, 0); - } - } - ++i; - break; - case ol.render.canvas.Instruction.DRAW_TEXT: - goog.asserts.assert(goog.isNumber(instruction[1]), - '2nd instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - goog.asserts.assert(goog.isNumber(instruction[2]), - '3rd instruction should be a number'); - dd = /** @type {number} */ (instruction[2]); - goog.asserts.assert(goog.isString(instruction[3]), - '4th instruction should be a string'); - text = /** @type {string} */ (instruction[3]); - goog.asserts.assert(goog.isNumber(instruction[4]), - '5th instruction should be a number'); - var offsetX = /** @type {number} */ (instruction[4]) * pixelRatio; - goog.asserts.assert(goog.isNumber(instruction[5]), - '6th instruction should be a number'); - var offsetY = /** @type {number} */ (instruction[5]) * pixelRatio; - goog.asserts.assert(goog.isNumber(instruction[6]), - '7th instruction should be a number'); - rotation = /** @type {number} */ (instruction[6]); - goog.asserts.assert(goog.isNumber(instruction[7]), - '8th instruction should be a number'); - scale = /** @type {number} */ (instruction[7]) * pixelRatio; - goog.asserts.assert(goog.isBoolean(instruction[8]), - '9th instruction should be a boolean'); - fill = /** @type {boolean} */ (instruction[8]); - goog.asserts.assert(goog.isBoolean(instruction[9]), - '10th instruction should be a boolean'); - stroke = /** @type {boolean} */ (instruction[9]); - for (; d < dd; d += 2) { - x = pixelCoordinates[d] + offsetX; - y = pixelCoordinates[d + 1] + offsetY; - if (scale != 1 || rotation !== 0) { - ol.vec.Mat4.makeTransform2D( - localTransform, x, y, scale, scale, rotation, -x, -y); - context.setTransform( - goog.vec.Mat4.getElement(localTransform, 0, 0), - goog.vec.Mat4.getElement(localTransform, 1, 0), - goog.vec.Mat4.getElement(localTransform, 0, 1), - goog.vec.Mat4.getElement(localTransform, 1, 1), - goog.vec.Mat4.getElement(localTransform, 0, 3), - goog.vec.Mat4.getElement(localTransform, 1, 3)); - } - if (stroke) { - context.strokeText(text, x, y); - } - if (fill) { - context.fillText(text, x, y); - } - if (scale != 1 || rotation !== 0) { - context.setTransform(1, 0, 0, 1, 0, 0); - } - } - ++i; - break; - case ol.render.canvas.Instruction.END_GEOMETRY: - if (featureCallback !== undefined) { - feature = - /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); - var result = featureCallback(feature); - if (result) { - return result; - } - } - ++i; - break; - case ol.render.canvas.Instruction.FILL: - context.fill(); - ++i; - break; - case ol.render.canvas.Instruction.MOVE_TO_LINE_TO: - goog.asserts.assert(goog.isNumber(instruction[1]), - '2nd instruction should be a number'); - d = /** @type {number} */ (instruction[1]); - goog.asserts.assert(goog.isNumber(instruction[2]), - '3rd instruction should be a number'); - dd = /** @type {number} */ (instruction[2]); - x = pixelCoordinates[d]; - y = pixelCoordinates[d + 1]; - roundX = (x + 0.5) | 0; - roundY = (y + 0.5) | 0; - if (roundX !== prevX || roundY !== prevY) { - context.moveTo(x, y); - prevX = roundX; - prevY = roundY; - } - for (d += 2; d < dd; d += 2) { - x = pixelCoordinates[d]; - y = pixelCoordinates[d + 1]; - roundX = (x + 0.5) | 0; - roundY = (y + 0.5) | 0; - if (roundX !== prevX || roundY !== prevY) { - context.lineTo(x, y); - prevX = roundX; - prevY = roundY; - } - } - ++i; - break; - case ol.render.canvas.Instruction.SET_FILL_STYLE: - goog.asserts.assert(goog.isString(instruction[1]), - '2nd instruction should be a string'); - context.fillStyle = /** @type {string} */ (instruction[1]); - ++i; - break; - case ol.render.canvas.Instruction.SET_STROKE_STYLE: - goog.asserts.assert(goog.isString(instruction[1]), - '2nd instruction should be a string'); - goog.asserts.assert(goog.isNumber(instruction[2]), - '3rd instruction should be a number'); - goog.asserts.assert(goog.isString(instruction[3]), - '4rd instruction should be a string'); - goog.asserts.assert(goog.isString(instruction[4]), - '5th instruction should be a string'); - goog.asserts.assert(goog.isNumber(instruction[5]), - '6th instruction should be a number'); - goog.asserts.assert(instruction[6], - '7th instruction should not be null'); - var usePixelRatio = instruction[7] !== undefined ? - instruction[7] : true; - var lineWidth = /** @type {number} */ (instruction[2]); - context.strokeStyle = /** @type {string} */ (instruction[1]); - context.lineWidth = usePixelRatio ? lineWidth * pixelRatio : lineWidth; - context.lineCap = /** @type {string} */ (instruction[3]); - context.lineJoin = /** @type {string} */ (instruction[4]); - context.miterLimit = /** @type {number} */ (instruction[5]); - if (ol.has.CANVAS_LINE_DASH) { - context.setLineDash(/** @type {Array.<number>} */ (instruction[6])); - } - prevX = NaN; - prevY = NaN; - ++i; - break; - case ol.render.canvas.Instruction.SET_TEXT_STYLE: - goog.asserts.assert(goog.isString(instruction[1]), - '2nd instruction should be a string'); - goog.asserts.assert(goog.isString(instruction[2]), - '3rd instruction should be a string'); - goog.asserts.assert(goog.isString(instruction[3]), - '4th instruction should be a string'); - context.font = /** @type {string} */ (instruction[1]); - context.textAlign = /** @type {string} */ (instruction[2]); - context.textBaseline = /** @type {string} */ (instruction[3]); - ++i; - break; - case ol.render.canvas.Instruction.STROKE: - context.stroke(); - ++i; - break; - default: - goog.asserts.fail('Unknown canvas render instruction'); - ++i; // consume the instruction anyway, to avoid an infinite loop - break; +/** + * @param {Object.<string, ol.Attribution>} attributionsSet Attributions + * set (target). + * @param {Array.<ol.Attribution>} attributions Attributions (source). + * @protected + */ +ol.renderer.Layer.prototype.updateAttributions = + function(attributionsSet, attributions) { + if (attributions) { + var attribution, i, ii; + for (i = 0, ii = attributions.length; i < ii; ++i) { + attribution = attributions[i]; + attributionsSet[goog.getUid(attribution).toString()] = attribution; } } - // assert that all instructions were consumed - goog.asserts.assert(i == instructions.length, - 'all instructions should be consumed'); - return undefined; }; /** - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. + * @param {olx.FrameState} frameState Frame state. + * @param {ol.source.Source} source Source. + * @protected */ -ol.render.canvas.Replay.prototype.replay = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { - var instructions = this.instructions; - this.replay_(context, pixelRatio, transform, viewRotation, - skippedFeaturesHash, instructions, undefined); +ol.renderer.Layer.prototype.updateLogos = function(frameState, source) { + var logo = source.getLogo(); + if (logo !== undefined) { + if (goog.isString(logo)) { + frameState.logos[logo] = ''; + } else if (goog.isObject(logo)) { + goog.asserts.assertString(logo.href, 'logo.href is a string'); + goog.asserts.assertString(logo.src, 'logo.src is a string'); + frameState.logos[logo.src] = logo.href; + } + } }; /** - * @param {CanvasRenderingContext2D} context Context. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback - * Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. - * @return {T|undefined} Callback result. - * @template T + * @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles. + * @param {ol.source.Tile} tileSource Tile source. + * @param {number} z Z. + * @param {ol.TileRange} tileRange Tile range. + * @protected */ -ol.render.canvas.Replay.prototype.replayHitDetection = function( - context, transform, viewRotation, skippedFeaturesHash, - opt_featureCallback, opt_hitExtent) { - var instructions = this.hitDetectionInstructions; - return this.replay_(context, 1, transform, viewRotation, - skippedFeaturesHash, instructions, opt_featureCallback, opt_hitExtent); +ol.renderer.Layer.prototype.updateUsedTiles = + function(usedTiles, tileSource, z, tileRange) { + // FIXME should we use tilesToDrawByZ instead? + var tileSourceKey = goog.getUid(tileSource).toString(); + var zKey = z.toString(); + if (tileSourceKey in usedTiles) { + if (zKey in usedTiles[tileSourceKey]) { + usedTiles[tileSourceKey][zKey].extend(tileRange); + } else { + usedTiles[tileSourceKey][zKey] = tileRange; + } + } else { + usedTiles[tileSourceKey] = {}; + usedTiles[tileSourceKey][zKey] = tileRange; + } }; /** - * @private + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {ol.Size} size Size. + * @protected + * @return {ol.Coordinate} Snapped center. */ -ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions_ = - function() { - var hitDetectionInstructions = this.hitDetectionInstructions; - // step 1 - reverse array - hitDetectionInstructions.reverse(); - // step 2 - reverse instructions within geometry blocks - var i; - var n = hitDetectionInstructions.length; - var instruction; - var type; - var begin = -1; - for (i = 0; i < n; ++i) { - instruction = hitDetectionInstructions[i]; - type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]); - if (type == ol.render.canvas.Instruction.END_GEOMETRY) { - goog.asserts.assert(begin == -1, 'begin should be -1'); - begin = i; - } else if (type == ol.render.canvas.Instruction.BEGIN_GEOMETRY) { - instruction[2] = i; - goog.asserts.assert(begin >= 0, - 'begin should be larger than or equal to 0'); - ol.array.reverseSubArray(this.hitDetectionInstructions, begin, i); - begin = -1; - } - } +ol.renderer.Layer.prototype.snapCenterToPixel = + function(center, resolution, size) { + return [ + resolution * (Math.round(center[0] / resolution) + (size[0] % 2) / 2), + resolution * (Math.round(center[1] / resolution) + (size[1] % 2) / 2) + ]; }; /** - * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. - * @param {ol.Feature|ol.render.Feature} feature Feature. + * Manage tile pyramid. + * This function performs a number of functions related to the tiles at the + * current zoom and lower zoom levels: + * - registers idle tiles in frameState.wantedTiles so that they are not + * discarded by the tile queue + * - enqueues missing tiles + * @param {olx.FrameState} frameState Frame state. + * @param {ol.source.Tile} tileSource Tile source. + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @param {ol.Extent} extent Extent. + * @param {number} currentZ Current Z. + * @param {number} preload Load low resolution tiles up to 'preload' levels. + * @param {function(this: T, ol.Tile)=} opt_tileCallback Tile callback. + * @param {T=} opt_this Object to use as `this` in `opt_tileCallback`. + * @protected + * @template T */ -ol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) { - goog.asserts.assert(this.beginGeometryInstruction1_, - 'this.beginGeometryInstruction1_ should not be null'); - this.beginGeometryInstruction1_[2] = this.instructions.length; - this.beginGeometryInstruction1_ = null; - goog.asserts.assert(this.beginGeometryInstruction2_, - 'this.beginGeometryInstruction2_ should not be null'); - this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length; - this.beginGeometryInstruction2_ = null; - var endGeometryInstruction = - [ol.render.canvas.Instruction.END_GEOMETRY, feature]; - this.instructions.push(endGeometryInstruction); - this.hitDetectionInstructions.push(endGeometryInstruction); +ol.renderer.Layer.prototype.manageTilePyramid = function( + frameState, tileSource, tileGrid, pixelRatio, projection, extent, + currentZ, preload, opt_tileCallback, opt_this) { + var tileSourceKey = goog.getUid(tileSource).toString(); + if (!(tileSourceKey in frameState.wantedTiles)) { + frameState.wantedTiles[tileSourceKey] = {}; + } + var wantedTiles = frameState.wantedTiles[tileSourceKey]; + var tileQueue = frameState.tileQueue; + var minZoom = tileGrid.getMinZoom(); + var tile, tileRange, tileResolution, x, y, z; + for (z = currentZ; z >= minZoom; --z) { + tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange); + tileResolution = tileGrid.getResolution(z); + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + if (currentZ - z <= preload) { + tile = tileSource.getTile(z, x, y, pixelRatio, projection); + if (tile.getState() == ol.TileState.IDLE) { + wantedTiles[ol.tilecoord.toString(tile.tileCoord)] = true; + if (!tileQueue.isKeyQueued(tile.getKey())) { + tileQueue.enqueue([tile, tileSourceKey, + tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]); + } + } + if (opt_tileCallback !== undefined) { + opt_tileCallback.call(opt_this, tile); + } + } else { + tileSource.useTile(z, x, y, projection); + } + } + } + } }; +goog.provide('ol.style.Icon'); +goog.provide('ol.style.IconAnchorUnits'); +goog.provide('ol.style.IconImageCache'); +goog.provide('ol.style.IconOrigin'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('ol.dom'); +goog.require('ol.style.Image'); +goog.require('ol.style.ImageState'); + /** - * FIXME empty description for jsdoc + * Icon anchor units. One of 'fraction', 'pixels'. + * @enum {string} + * @api */ -ol.render.canvas.Replay.prototype.finish = ol.nullFunction; +ol.style.IconAnchorUnits = { + FRACTION: 'fraction', + PIXELS: 'pixels' +}; /** - * Get the buffered rendering extent. Rendering will be clipped to the extent - * provided to the constructor. To account for symbolizers that may intersect - * this extent, we calculate a buffered extent (e.g. based on stroke width). - * @return {ol.Extent} The buffered rendering extent. - * @protected + * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'. + * @enum {string} + * @api */ -ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() { - return this.maxExtent; +ol.style.IconOrigin = { + BOTTOM_LEFT: 'bottom-left', + BOTTOM_RIGHT: 'bottom-right', + TOP_LEFT: 'top-left', + TOP_RIGHT: 'top-right' }; /** + * @classdesc + * Set icon style for vector features. + * * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct + * @param {olx.style.IconOptions=} opt_options Options. + * @extends {ol.style.Image} + * @api */ -ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution) { - goog.base(this, tolerance, maxExtent, resolution); +ol.style.Icon = function(opt_options) { + + var options = opt_options || {}; /** * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} + * @type {Array.<number>} */ - this.hitDetectionImage_ = null; + this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5]; /** * @private - * @type {HTMLCanvasElement|HTMLVideoElement|Image} + * @type {Array.<number>} */ - this.image_ = null; + this.normalizedAnchor_ = null; /** * @private - * @type {number|undefined} + * @type {ol.style.IconOrigin} */ - this.anchorX_ = undefined; + this.anchorOrigin_ = options.anchorOrigin !== undefined ? + options.anchorOrigin : ol.style.IconOrigin.TOP_LEFT; /** * @private - * @type {number|undefined} + * @type {ol.style.IconAnchorUnits} */ - this.anchorY_ = undefined; + this.anchorXUnits_ = options.anchorXUnits !== undefined ? + options.anchorXUnits : ol.style.IconAnchorUnits.FRACTION; /** * @private - * @type {number|undefined} + * @type {ol.style.IconAnchorUnits} */ - this.height_ = undefined; + this.anchorYUnits_ = options.anchorYUnits !== undefined ? + options.anchorYUnits : ol.style.IconAnchorUnits.FRACTION; /** - * @private - * @type {number|undefined} + * @type {?string} */ - this.opacity_ = undefined; + var crossOrigin = + options.crossOrigin !== undefined ? options.crossOrigin : null; /** - * @private - * @type {number|undefined} + * @type {Image} */ - this.originX_ = undefined; + var image = options.img !== undefined ? options.img : null; /** - * @private - * @type {number|undefined} + * @type {ol.Size} */ - this.originY_ = undefined; + var imgSize = options.imgSize !== undefined ? options.imgSize : null; + + /** + * @type {string|undefined} + */ + var src = options.src; + + goog.asserts.assert(!(src !== undefined && image), + 'image and src can not provided at the same time'); + goog.asserts.assert( + src === undefined || (src !== undefined && !imgSize), + 'imgSize should not be set when src is provided'); + goog.asserts.assert( + !image || (image && imgSize), + 'imgSize must be set when image is provided'); + + if ((src === undefined || src.length === 0) && image) { + src = image.src; + } + goog.asserts.assert(src !== undefined && src.length > 0, + 'must provide a defined and non-empty src or image'); + + /** + * @type {ol.style.ImageState} + */ + var imageState = options.src !== undefined ? + ol.style.ImageState.IDLE : ol.style.ImageState.LOADED; /** * @private - * @type {boolean|undefined} + * @type {ol.style.IconImage_} */ - this.rotateWithView_ = undefined; + this.iconImage_ = ol.style.IconImage_.get( + image, src, imgSize, crossOrigin, imageState); /** * @private - * @type {number|undefined} + * @type {Array.<number>} */ - this.rotation_ = undefined; + this.offset_ = options.offset !== undefined ? options.offset : [0, 0]; /** * @private - * @type {number|undefined} + * @type {ol.style.IconOrigin} */ - this.scale_ = undefined; + this.offsetOrigin_ = options.offsetOrigin !== undefined ? + options.offsetOrigin : ol.style.IconOrigin.TOP_LEFT; /** * @private - * @type {boolean|undefined} + * @type {Array.<number>} */ - this.snapToPixel_ = undefined; + this.origin_ = null; /** * @private - * @type {number|undefined} + * @type {ol.Size} */ - this.width_ = undefined; + this.size_ = options.size !== undefined ? options.size : null; -}; -goog.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay); + /** + * @type {number} + */ + var opacity = options.opacity !== undefined ? options.opacity : 1; + /** + * @type {boolean} + */ + var rotateWithView = options.rotateWithView !== undefined ? + options.rotateWithView : false; + + /** + * @type {number} + */ + var rotation = options.rotation !== undefined ? options.rotation : 0; + + /** + * @type {number} + */ + var scale = options.scale !== undefined ? options.scale : 1; + + /** + * @type {boolean} + */ + var snapToPixel = options.snapToPixel !== undefined ? + options.snapToPixel : true; + + goog.base(this, { + opacity: opacity, + rotation: rotation, + scale: scale, + snapToPixel: snapToPixel, + rotateWithView: rotateWithView + }); -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - * @return {number} My end. - */ -ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = - function(flatCoordinates, offset, end, stride) { - return this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); }; +goog.inherits(ol.style.Icon, ol.style.Image); /** * @inheritDoc + * @api */ -ol.render.canvas.ImageReplay.prototype.drawPointGeometry = - function(pointGeometry, feature) { - if (!this.image_) { - return; +ol.style.Icon.prototype.getAnchor = function() { + if (this.normalizedAnchor_) { + return this.normalizedAnchor_; } - goog.asserts.assert(this.anchorX_ !== undefined, - 'this.anchorX_ should be defined'); - goog.asserts.assert(this.anchorY_ !== undefined, - 'this.anchorY_ should be defined'); - goog.asserts.assert(this.height_ !== undefined, - 'this.height_ should be defined'); - goog.asserts.assert(this.opacity_ !== undefined, - 'this.opacity_ should be defined'); - goog.asserts.assert(this.originX_ !== undefined, - 'this.originX_ should be defined'); - goog.asserts.assert(this.originY_ !== undefined, - 'this.originY_ should be defined'); - goog.asserts.assert(this.rotateWithView_ !== undefined, - 'this.rotateWithView_ should be defined'); - goog.asserts.assert(this.rotation_ !== undefined, - 'this.rotation_ should be defined'); - goog.asserts.assert(this.scale_ !== undefined, - 'this.scale_ should be defined'); - goog.asserts.assert(this.width_ !== undefined, - 'this.width_ should be defined'); - this.beginGeometry(pointGeometry, feature); - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - var myBegin = this.coordinates.length; - var myEnd = this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.instructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.hitDetectionInstructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, - this.hitDetectionImage_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.endGeometry(pointGeometry, feature); + var anchor = this.anchor_; + var size = this.getSize(); + if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION || + this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { + if (!size) { + return null; + } + anchor = this.anchor_.slice(); + if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION) { + anchor[0] *= size[0]; + } + if (this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) { + anchor[1] *= size[1]; + } + } + + if (this.anchorOrigin_ != ol.style.IconOrigin.TOP_LEFT) { + if (!size) { + return null; + } + if (anchor === this.anchor_) { + anchor = this.anchor_.slice(); + } + if (this.anchorOrigin_ == ol.style.IconOrigin.TOP_RIGHT || + this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + anchor[0] = -anchor[0] + size[0]; + } + if (this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || + this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + anchor[1] = -anchor[1] + size[1]; + } + } + this.normalizedAnchor_ = anchor; + return this.normalizedAnchor_; }; /** - * @inheritDoc + * Get the image icon. + * @param {number} pixelRatio Pixel ratio. + * @return {Image} Image element. + * @api */ -ol.render.canvas.ImageReplay.prototype.drawMultiPointGeometry = - function(multiPointGeometry, feature) { - if (!this.image_) { - return; - } - goog.asserts.assert(this.anchorX_ !== undefined, - 'this.anchorX_ should be defined'); - goog.asserts.assert(this.anchorY_ !== undefined, - 'this.anchorY_ should be defined'); - goog.asserts.assert(this.height_ !== undefined, - 'this.height_ should be defined'); - goog.asserts.assert(this.opacity_ !== undefined, - 'this.opacity_ should be defined'); - goog.asserts.assert(this.originX_ !== undefined, - 'this.originX_ should be defined'); - goog.asserts.assert(this.originY_ !== undefined, - 'this.originY_ should be defined'); - goog.asserts.assert(this.rotateWithView_ !== undefined, - 'this.rotateWithView_ should be defined'); - goog.asserts.assert(this.rotation_ !== undefined, - 'this.rotation_ should be defined'); - goog.asserts.assert(this.scale_ !== undefined, - 'this.scale_ should be defined'); - goog.asserts.assert(this.width_ !== undefined, - 'this.width_ should be defined'); - this.beginGeometry(multiPointGeometry, feature); - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - var myBegin = this.coordinates.length; - var myEnd = this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.instructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.hitDetectionInstructions.push([ - ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, - this.hitDetectionImage_, - // Remaining arguments to DRAW_IMAGE are in alphabetical order - this.anchorX_, this.anchorY_, this.height_, this.opacity_, - this.originX_, this.originY_, this.rotateWithView_, this.rotation_, - this.scale_, this.snapToPixel_, this.width_ - ]); - this.endGeometry(multiPointGeometry, feature); +ol.style.Icon.prototype.getImage = function(pixelRatio) { + return this.iconImage_.getImage(pixelRatio); }; /** - * @inheritDoc + * Real Image size used. + * @return {ol.Size} Size. */ -ol.render.canvas.ImageReplay.prototype.finish = function() { - this.reverseHitDetectionInstructions_(); - // FIXME this doesn't really protect us against further calls to draw*Geometry - this.anchorX_ = undefined; - this.anchorY_ = undefined; - this.hitDetectionImage_ = null; - this.image_ = null; - this.height_ = undefined; - this.scale_ = undefined; - this.opacity_ = undefined; - this.originX_ = undefined; - this.originY_ = undefined; - this.rotateWithView_ = undefined; - this.rotation_ = undefined; - this.snapToPixel_ = undefined; - this.width_ = undefined; +ol.style.Icon.prototype.getImageSize = function() { + return this.iconImage_.getSize(); }; /** * @inheritDoc */ -ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) { - goog.asserts.assert(imageStyle, 'imageStyle should not be null'); - var anchor = imageStyle.getAnchor(); - goog.asserts.assert(anchor, 'anchor should not be null'); - var size = imageStyle.getSize(); - goog.asserts.assert(size, 'size should not be null'); - var hitDetectionImage = imageStyle.getHitDetectionImage(1); - goog.asserts.assert(hitDetectionImage, - 'hitDetectionImage should not be null'); - var image = imageStyle.getImage(1); - goog.asserts.assert(image, 'image should not be null'); - var origin = imageStyle.getOrigin(); - goog.asserts.assert(origin, 'origin should not be null'); - this.anchorX_ = anchor[0]; - this.anchorY_ = anchor[1]; - this.hitDetectionImage_ = hitDetectionImage; - this.image_ = image; - this.height_ = size[1]; - this.opacity_ = imageStyle.getOpacity(); - this.originX_ = origin[0]; - this.originY_ = origin[1]; - this.rotateWithView_ = imageStyle.getRotateWithView(); - this.rotation_ = imageStyle.getRotation(); - this.scale_ = imageStyle.getScale(); - this.snapToPixel_ = imageStyle.getSnapToPixel(); - this.width_ = size[0]; +ol.style.Icon.prototype.getHitDetectionImageSize = function() { + return this.getImageSize(); }; - /** - * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct + * @inheritDoc */ -ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution) { - - goog.base(this, tolerance, maxExtent, resolution); - - /** - * @private - * @type {{currentStrokeStyle: (string|undefined), - * currentLineCap: (string|undefined), - * currentLineDash: Array.<number>, - * currentLineJoin: (string|undefined), - * currentLineWidth: (number|undefined), - * currentMiterLimit: (number|undefined), - * lastStroke: number, - * strokeStyle: (string|undefined), - * lineCap: (string|undefined), - * lineDash: Array.<number>, - * lineJoin: (string|undefined), - * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} - */ - this.state_ = { - currentStrokeStyle: undefined, - currentLineCap: undefined, - currentLineDash: null, - currentLineJoin: undefined, - currentLineWidth: undefined, - currentMiterLimit: undefined, - lastStroke: 0, - strokeStyle: undefined, - lineCap: undefined, - lineDash: null, - lineJoin: undefined, - lineWidth: undefined, - miterLimit: undefined - }; - +ol.style.Icon.prototype.getImageState = function() { + return this.iconImage_.getImageState(); }; -goog.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay); /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @private - * @return {number} end. + * @inheritDoc */ -ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = - function(flatCoordinates, offset, end, stride) { - var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); - var moveToLineToInstruction = - [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; - this.instructions.push(moveToLineToInstruction); - this.hitDetectionInstructions.push(moveToLineToInstruction); - return end; +ol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) { + return this.iconImage_.getHitDetectionImage(pixelRatio); }; /** * @inheritDoc + * @api */ -ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() { - if (!this.bufferedMaxExtent_) { - this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); - if (this.maxLineWidth > 0) { - var width = this.resolution * (this.maxLineWidth + 1) / 2; - ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); +ol.style.Icon.prototype.getOrigin = function() { + if (this.origin_) { + return this.origin_; + } + var offset = this.offset_; + + if (this.offsetOrigin_ != ol.style.IconOrigin.TOP_LEFT) { + var size = this.getSize(); + var iconImageSize = this.iconImage_.getSize(); + if (!size || !iconImageSize) { + return null; + } + offset = offset.slice(); + if (this.offsetOrigin_ == ol.style.IconOrigin.TOP_RIGHT || + this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + offset[0] = iconImageSize[0] - size[0] - offset[0]; + } + if (this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT || + this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) { + offset[1] = iconImageSize[1] - size[1] - offset[1]; } } - return this.bufferedMaxExtent_; + this.origin_ = offset; + return this.origin_; }; /** - * @private + * Get the image URL. + * @return {string|undefined} Image src. + * @api */ -ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() { - var state = this.state_; - var strokeStyle = state.strokeStyle; - var lineCap = state.lineCap; - var lineDash = state.lineDash; - var lineJoin = state.lineJoin; - var lineWidth = state.lineWidth; - var miterLimit = state.miterLimit; - goog.asserts.assert(strokeStyle !== undefined, - 'strokeStyle should be defined'); - goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined'); - goog.asserts.assert(lineDash, 'lineDash should not be null'); - goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined'); - goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined'); - goog.asserts.assert(miterLimit !== undefined, 'miterLimit should be defined'); - if (state.currentStrokeStyle != strokeStyle || - state.currentLineCap != lineCap || - !goog.array.equals(state.currentLineDash, lineDash) || - state.currentLineJoin != lineJoin || - state.currentLineWidth != lineWidth || - state.currentMiterLimit != miterLimit) { - if (state.lastStroke != this.coordinates.length) { - this.instructions.push( - [ol.render.canvas.Instruction.STROKE]); - state.lastStroke = this.coordinates.length; - } - this.instructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - state.currentStrokeStyle = strokeStyle; - state.currentLineCap = lineCap; - state.currentLineDash = lineDash; - state.currentLineJoin = lineJoin; - state.currentLineWidth = lineWidth; - state.currentMiterLimit = miterLimit; - } +ol.style.Icon.prototype.getSrc = function() { + return this.iconImage_.getSrc(); }; /** * @inheritDoc + * @api */ -ol.render.canvas.LineStringReplay.prototype.drawLineStringGeometry = - function(lineStringGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var strokeStyle = state.strokeStyle; - var lineWidth = state.lineWidth; - if (strokeStyle === undefined || lineWidth === undefined) { - return; - } - this.setStrokeStyle_(); - this.beginGeometry(lineStringGeometry, feature); - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - var flatCoordinates = lineStringGeometry.getFlatCoordinates(); - var stride = lineStringGeometry.getStride(); - this.drawFlatCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); - this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); - this.endGeometry(lineStringGeometry, feature); +ol.style.Icon.prototype.getSize = function() { + return !this.size_ ? this.iconImage_.getSize() : this.size_; }; /** * @inheritDoc */ -ol.render.canvas.LineStringReplay.prototype.drawMultiLineStringGeometry = - function(multiLineStringGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var strokeStyle = state.strokeStyle; - var lineWidth = state.lineWidth; - if (strokeStyle === undefined || lineWidth === undefined) { - return; - } - this.setStrokeStyle_(); - this.beginGeometry(multiLineStringGeometry, feature); - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash], - [ol.render.canvas.Instruction.BEGIN_PATH]); - var ends = multiLineStringGeometry.getEnds(); - var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); - var stride = multiLineStringGeometry.getStride(); - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - offset = this.drawFlatCoordinates_( - flatCoordinates, offset, ends[i], stride); - } - this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); - this.endGeometry(multiLineStringGeometry, feature); +ol.style.Icon.prototype.listenImageChange = function(listener, thisArg) { + return goog.events.listen(this.iconImage_, goog.events.EventType.CHANGE, + listener, false, thisArg); }; /** - * @inheritDoc + * Load not yet loaded URI. + * When rendering a feature with an icon style, the vector renderer will + * automatically call this method. However, you might want to call this + * method yourself for preloading or other purposes. + * @api */ -ol.render.canvas.LineStringReplay.prototype.finish = function() { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - if (state.lastStroke != this.coordinates.length) { - this.instructions.push([ol.render.canvas.Instruction.STROKE]); - } - this.reverseHitDetectionInstructions_(); - this.state_ = null; +ol.style.Icon.prototype.load = function() { + this.iconImage_.load(); }; /** * @inheritDoc */ -ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { - goog.asserts.assert(this.state_, 'this.state_ should not be null'); - goog.asserts.assert(!fillStyle, 'fillStyle should be null'); - goog.asserts.assert(strokeStyle, 'strokeStyle should not be null'); - var strokeStyleColor = strokeStyle.getColor(); - this.state_.strokeStyle = ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle); - var strokeStyleLineCap = strokeStyle.getLineCap(); - this.state_.lineCap = strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap; - var strokeStyleLineDash = strokeStyle.getLineDash(); - this.state_.lineDash = strokeStyleLineDash ? - strokeStyleLineDash : ol.render.canvas.defaultLineDash; - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - this.state_.lineJoin = strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var strokeStyleWidth = strokeStyle.getWidth(); - this.state_.lineWidth = strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth; - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - this.state_.miterLimit = strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - - if (this.state_.lineWidth > this.maxLineWidth) { - this.maxLineWidth = this.state_.lineWidth; - // invalidate the buffered max extent cache - this.bufferedMaxExtent_ = null; - } +ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) { + goog.events.unlisten(this.iconImage_, goog.events.EventType.CHANGE, + listener, false, thisArg); }; /** * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct + * @param {Image} image Image. + * @param {string|undefined} src Src. + * @param {ol.Size} size Size. + * @param {?string} crossOrigin Cross origin. + * @param {ol.style.ImageState} imageState Image state. + * @extends {goog.events.EventTarget} + * @private */ -ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) { +ol.style.IconImage_ = function(image, src, size, crossOrigin, imageState) { - goog.base(this, tolerance, maxExtent, resolution); + goog.base(this); /** * @private - * @type {{currentFillStyle: (string|undefined), - * currentStrokeStyle: (string|undefined), - * currentLineCap: (string|undefined), - * currentLineDash: Array.<number>, - * currentLineJoin: (string|undefined), - * currentLineWidth: (number|undefined), - * currentMiterLimit: (number|undefined), - * fillStyle: (string|undefined), - * strokeStyle: (string|undefined), - * lineCap: (string|undefined), - * lineDash: Array.<number>, - * lineJoin: (string|undefined), - * lineWidth: (number|undefined), - * miterLimit: (number|undefined)}|null} + * @type {Image|HTMLCanvasElement} */ - this.state_ = { - currentFillStyle: undefined, - currentStrokeStyle: undefined, - currentLineCap: undefined, - currentLineDash: null, - currentLineJoin: undefined, - currentLineWidth: undefined, - currentMiterLimit: undefined, - fillStyle: undefined, - strokeStyle: undefined, - lineCap: undefined, - lineDash: null, - lineJoin: undefined, - lineWidth: undefined, - miterLimit: undefined - }; + this.hitDetectionImage_ = null; + + /** + * @private + * @type {Image} + */ + this.image_ = !image ? new Image() : image; + + if (crossOrigin !== null) { + this.image_.crossOrigin = crossOrigin; + } + + /** + * @private + * @type {Array.<goog.events.Key>} + */ + this.imageListenerKeys_ = null; + + /** + * @private + * @type {ol.style.ImageState} + */ + this.imageState_ = imageState; + + /** + * @private + * @type {ol.Size} + */ + this.size_ = size; + + /** + * @private + * @type {string|undefined} + */ + this.src_ = src; + + /** + * @private + * @type {boolean} + */ + this.tainting_ = false; + if (this.imageState_ == ol.style.ImageState.LOADED) { + this.determineTainting_(); + } }; -goog.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay); +goog.inherits(ol.style.IconImage_, goog.events.EventTarget); /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @private - * @return {number} End. + * @param {Image} image Image. + * @param {string} src Src. + * @param {ol.Size} size Size. + * @param {?string} crossOrigin Cross origin. + * @param {ol.style.ImageState} imageState Image state. + * @return {ol.style.IconImage_} Icon image. */ -ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = - function(flatCoordinates, offset, ends, stride) { - var state = this.state_; - var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - this.instructions.push(beginPathInstruction); - this.hitDetectionInstructions.push(beginPathInstruction); - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var myBegin = this.coordinates.length; - var myEnd = this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, true); - var moveToLineToInstruction = - [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; - var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH]; - this.instructions.push(moveToLineToInstruction, closePathInstruction); - this.hitDetectionInstructions.push(moveToLineToInstruction, - closePathInstruction); - offset = end; - } - // FIXME is it quicker to fill and stroke each polygon individually, - // FIXME or all polygons together? - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); - if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); - } - if (state.strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); +ol.style.IconImage_.get = function(image, src, size, crossOrigin, imageState) { + var iconImageCache = ol.style.IconImageCache.getInstance(); + var iconImage = iconImageCache.get(src, crossOrigin); + if (!iconImage) { + iconImage = new ol.style.IconImage_( + image, src, size, crossOrigin, imageState); + iconImageCache.set(src, crossOrigin, iconImage); } - return offset; + return iconImage; }; /** - * @inheritDoc + * @private */ -ol.render.canvas.PolygonReplay.prototype.drawCircleGeometry = - function(circleGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(circleGeometry, feature); - // always fill the circle for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var flatCoordinates = circleGeometry.getFlatCoordinates(); - var stride = circleGeometry.getStride(); - var myBegin = this.coordinates.length; - this.appendFlatCoordinates( - flatCoordinates, 0, flatCoordinates.length, stride, false); - var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; - var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin]; - this.instructions.push(beginPathInstruction, circleInstruction); - this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction); - var fillInstruction = [ol.render.canvas.Instruction.FILL]; - this.hitDetectionInstructions.push(fillInstruction); - if (state.fillStyle !== undefined) { - this.instructions.push(fillInstruction); - } - if (state.strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; - this.instructions.push(strokeInstruction); - this.hitDetectionInstructions.push(strokeInstruction); +ol.style.IconImage_.prototype.determineTainting_ = function() { + var context = ol.dom.createCanvasContext2D(1, 1); + try { + context.drawImage(this.image_, 0, 0); + context.getImageData(0, 0, 1, 1); + } catch (e) { + this.tainting_ = true; } - this.endGeometry(circleGeometry, feature); }; /** - * @inheritDoc + * @private */ -ol.render.canvas.PolygonReplay.prototype.drawPolygonGeometry = - function(polygonGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(polygonGeometry, feature); - // always fill the polygon for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var ends = polygonGeometry.getEnds(); - var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates(); - var stride = polygonGeometry.getStride(); - this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride); - this.endGeometry(polygonGeometry, feature); +ol.style.IconImage_.prototype.dispatchChangeEvent_ = function() { + this.dispatchEvent(goog.events.EventType.CHANGE); }; /** - * @inheritDoc + * @private */ -ol.render.canvas.PolygonReplay.prototype.drawMultiPolygonGeometry = - function(multiPolygonGeometry, feature) { - var state = this.state_; - goog.asserts.assert(state, 'state should not be null'); - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - if (fillStyle === undefined && strokeStyle === undefined) { - return; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(state.lineWidth !== undefined, - 'state.lineWidth should be defined'); - } - this.setFillStrokeStyles_(); - this.beginGeometry(multiPolygonGeometry, feature); - // always fill the multi-polygon for hit detection - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, - ol.color.asString(ol.render.canvas.defaultFillStyle)]); - if (state.strokeStyle !== undefined) { - this.hitDetectionInstructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, - state.miterLimit, state.lineDash]); - } - var endss = multiPolygonGeometry.getEndss(); - var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); - var stride = multiPolygonGeometry.getStride(); - var offset = 0; - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - offset = this.drawFlatCoordinatess_( - flatCoordinates, offset, endss[i], stride); - } - this.endGeometry(multiPolygonGeometry, feature); +ol.style.IconImage_.prototype.handleImageError_ = function() { + this.imageState_ = ol.style.ImageState.ERROR; + this.unlistenImage_(); + this.dispatchChangeEvent_(); }; /** - * @inheritDoc + * @private */ -ol.render.canvas.PolygonReplay.prototype.finish = function() { - goog.asserts.assert(this.state_, 'this.state_ should not be null'); - this.reverseHitDetectionInstructions_(); - this.state_ = null; - // We want to preserve topology when drawing polygons. Polygons are - // simplified using quantization and point elimination. However, we might - // have received a mix of quantized and non-quantized geometries, so ensure - // that all are quantized by quantizing all coordinates in the batch. - var tolerance = this.tolerance; - if (tolerance !== 0) { - var coordinates = this.coordinates; - var i, ii; - for (i = 0, ii = coordinates.length; i < ii; ++i) { - coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance); - } - } +ol.style.IconImage_.prototype.handleImageLoad_ = function() { + this.imageState_ = ol.style.ImageState.LOADED; + this.size_ = [this.image_.width, this.image_.height]; + this.unlistenImage_(); + this.determineTainting_(); + this.dispatchChangeEvent_(); }; /** - * @inheritDoc + * @param {number} pixelRatio Pixel ratio. + * @return {Image} Image element. */ -ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() { - if (!this.bufferedMaxExtent_) { - this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); - if (this.maxLineWidth > 0) { - var width = this.resolution * (this.maxLineWidth + 1) / 2; - ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); +ol.style.IconImage_.prototype.getImage = function(pixelRatio) { + return this.image_; +}; + + +/** + * @return {ol.style.ImageState} Image state. + */ +ol.style.IconImage_.prototype.getImageState = function() { + return this.imageState_; +}; + + +/** + * @param {number} pixelRatio Pixel ratio. + * @return {Image|HTMLCanvasElement} Image element. + */ +ol.style.IconImage_.prototype.getHitDetectionImage = function(pixelRatio) { + if (!this.hitDetectionImage_) { + if (this.tainting_) { + var width = this.size_[0]; + var height = this.size_[1]; + var context = ol.dom.createCanvasContext2D(width, height); + context.fillRect(0, 0, width, height); + this.hitDetectionImage_ = context.canvas; + } else { + this.hitDetectionImage_ = this.image_; } } - return this.bufferedMaxExtent_; + return this.hitDetectionImage_; }; /** - * @inheritDoc + * @return {ol.Size} Image size. */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { - goog.asserts.assert(this.state_, 'this.state_ should not be null'); - goog.asserts.assert(fillStyle || strokeStyle, - 'fillStyle or strokeStyle should not be null'); - var state = this.state_; - if (fillStyle) { - var fillStyleColor = fillStyle.getColor(); - state.fillStyle = ol.color.asString(fillStyleColor ? - fillStyleColor : ol.render.canvas.defaultFillStyle); - } else { - state.fillStyle = undefined; - } - if (strokeStyle) { - var strokeStyleColor = strokeStyle.getColor(); - state.strokeStyle = ol.color.asString(strokeStyleColor ? - strokeStyleColor : ol.render.canvas.defaultStrokeStyle); - var strokeStyleLineCap = strokeStyle.getLineCap(); - state.lineCap = strokeStyleLineCap !== undefined ? - strokeStyleLineCap : ol.render.canvas.defaultLineCap; - var strokeStyleLineDash = strokeStyle.getLineDash(); - state.lineDash = strokeStyleLineDash ? - strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; - var strokeStyleLineJoin = strokeStyle.getLineJoin(); - state.lineJoin = strokeStyleLineJoin !== undefined ? - strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var strokeStyleWidth = strokeStyle.getWidth(); - state.lineWidth = strokeStyleWidth !== undefined ? - strokeStyleWidth : ol.render.canvas.defaultLineWidth; - var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); - state.miterLimit = strokeStyleMiterLimit !== undefined ? - strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; +ol.style.IconImage_.prototype.getSize = function() { + return this.size_; +}; - if (state.lineWidth > this.maxLineWidth) { - this.maxLineWidth = state.lineWidth; - // invalidate the buffered max extent cache - this.bufferedMaxExtent_ = null; + +/** + * @return {string|undefined} Image src. + */ +ol.style.IconImage_.prototype.getSrc = function() { + return this.src_; +}; + + +/** + * Load not yet loaded URI. + */ +ol.style.IconImage_.prototype.load = function() { + if (this.imageState_ == ol.style.ImageState.IDLE) { + goog.asserts.assert(this.src_ !== undefined, + 'this.src_ must not be undefined'); + goog.asserts.assert(!this.imageListenerKeys_, + 'no listener keys existing'); + this.imageState_ = ol.style.ImageState.LOADING; + this.imageListenerKeys_ = [ + goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, + this.handleImageError_, false, this), + goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, + this.handleImageLoad_, false, this) + ]; + try { + this.image_.src = this.src_; + } catch (e) { + this.handleImageError_(); } - } else { - state.strokeStyle = undefined; - state.lineCap = undefined; - state.lineDash = null; - state.lineJoin = undefined; - state.lineWidth = undefined; - state.miterLimit = undefined; } }; /** + * Discards event handlers which listen for load completion or errors. + * * @private */ -ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { - var state = this.state_; - var fillStyle = state.fillStyle; - var strokeStyle = state.strokeStyle; - var lineCap = state.lineCap; - var lineDash = state.lineDash; - var lineJoin = state.lineJoin; - var lineWidth = state.lineWidth; - var miterLimit = state.miterLimit; - if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]); - state.currentFillStyle = state.fillStyle; - } - if (strokeStyle !== undefined) { - goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined'); - goog.asserts.assert(lineDash, 'lineDash should not be null'); - goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined'); - goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined'); - goog.asserts.assert(miterLimit !== undefined, - 'miterLimit should be defined'); - if (state.currentStrokeStyle != strokeStyle || - state.currentLineCap != lineCap || - state.currentLineDash != lineDash || - state.currentLineJoin != lineJoin || - state.currentLineWidth != lineWidth || - state.currentMiterLimit != miterLimit) { - this.instructions.push( - [ol.render.canvas.Instruction.SET_STROKE_STYLE, - strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]); - state.currentStrokeStyle = strokeStyle; - state.currentLineCap = lineCap; - state.currentLineDash = lineDash; - state.currentLineJoin = lineJoin; - state.currentLineWidth = lineWidth; - state.currentMiterLimit = miterLimit; - } - } +ol.style.IconImage_.prototype.unlistenImage_ = function() { + goog.asserts.assert(this.imageListenerKeys_, + 'we must have listeners registered'); + this.imageListenerKeys_.forEach(goog.events.unlistenByKey); + this.imageListenerKeys_ = null; }; /** * @constructor - * @extends {ol.render.canvas.Replay} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Maximum extent. - * @param {number} resolution Resolution. - * @protected - * @struct */ -ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution) { - - goog.base(this, tolerance, maxExtent, resolution); +ol.style.IconImageCache = function() { /** + * @type {Object.<string, ol.style.IconImage_>} * @private - * @type {?ol.render.canvas.FillState} - */ - this.replayFillState_ = null; - - /** - * @private - * @type {?ol.render.canvas.StrokeState} - */ - this.replayStrokeState_ = null; - - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.replayTextState_ = null; - - /** - * @private - * @type {string} - */ - this.text_ = ''; - - /** - * @private - * @type {number} */ - this.textOffsetX_ = 0; + this.cache_ = {}; /** - * @private * @type {number} - */ - this.textOffsetY_ = 0; - - /** * @private - * @type {number} */ - this.textRotation_ = 0; + this.cacheSize_ = 0; /** - * @private + * @const * @type {number} - */ - this.textScale_ = 0; - - /** - * @private - * @type {?ol.render.canvas.FillState} - */ - this.textFillState_ = null; - - /** * @private - * @type {?ol.render.canvas.StrokeState} */ - this.textStrokeState_ = null; + this.maxCacheSize_ = 32; +}; +goog.addSingletonGetter(ol.style.IconImageCache); - /** - * @private - * @type {?ol.render.canvas.TextState} - */ - this.textState_ = null; +/** + * @param {string} src Src. + * @param {?string} crossOrigin Cross origin. + * @return {string} Cache key. + */ +ol.style.IconImageCache.getKey = function(src, crossOrigin) { + goog.asserts.assert(crossOrigin !== undefined, + 'argument crossOrigin must be defined'); + return crossOrigin + ':' + src; }; -goog.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay); /** - * @inheritDoc + * FIXME empty description for jsdoc */ -ol.render.canvas.TextReplay.prototype.drawText = - function(flatCoordinates, offset, end, stride, geometry, feature) { - if (this.text_ === '' || !this.textState_ || - (!this.textFillState_ && !this.textStrokeState_)) { - return; - } - if (this.textFillState_) { - this.setReplayFillState_(this.textFillState_); - } - if (this.textStrokeState_) { - this.setReplayStrokeState_(this.textStrokeState_); - } - this.setReplayTextState_(this.textState_); - this.beginGeometry(geometry, feature); - var myBegin = this.coordinates.length; - var myEnd = - this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false); - var fill = !!this.textFillState_; - var stroke = !!this.textStrokeState_; - var drawTextInstruction = [ - ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_, - this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_, - fill, stroke]; - this.instructions.push(drawTextInstruction); - this.hitDetectionInstructions.push(drawTextInstruction); - this.endGeometry(geometry, feature); +ol.style.IconImageCache.prototype.clear = function() { + this.cache_ = {}; + this.cacheSize_ = 0; }; /** - * @param {ol.render.canvas.FillState} fillState Fill state. - * @private + * FIXME empty description for jsdoc */ -ol.render.canvas.TextReplay.prototype.setReplayFillState_ = - function(fillState) { - var replayFillState = this.replayFillState_; - if (replayFillState && - replayFillState.fillStyle == fillState.fillStyle) { - return; - } - var setFillStyleInstruction = - [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle]; - this.instructions.push(setFillStyleInstruction); - this.hitDetectionInstructions.push(setFillStyleInstruction); - if (!replayFillState) { - this.replayFillState_ = { - fillStyle: fillState.fillStyle - }; - } else { - replayFillState.fillStyle = fillState.fillStyle; +ol.style.IconImageCache.prototype.expire = function() { + if (this.cacheSize_ > this.maxCacheSize_) { + var i = 0; + var key, iconImage; + for (key in this.cache_) { + iconImage = this.cache_[key]; + if ((i++ & 3) === 0 && !goog.events.hasListener(iconImage)) { + delete this.cache_[key]; + --this.cacheSize_; + } + } } }; /** - * @param {ol.render.canvas.StrokeState} strokeState Stroke state. - * @private + * @param {string} src Src. + * @param {?string} crossOrigin Cross origin. + * @return {ol.style.IconImage_} Icon image. */ -ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = - function(strokeState) { - var replayStrokeState = this.replayStrokeState_; - if (replayStrokeState && - replayStrokeState.lineCap == strokeState.lineCap && - replayStrokeState.lineDash == strokeState.lineDash && - replayStrokeState.lineJoin == strokeState.lineJoin && - replayStrokeState.lineWidth == strokeState.lineWidth && - replayStrokeState.miterLimit == strokeState.miterLimit && - replayStrokeState.strokeStyle == strokeState.strokeStyle) { - return; - } - var setStrokeStyleInstruction = [ - ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle, - strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin, - strokeState.miterLimit, strokeState.lineDash, false - ]; - this.instructions.push(setStrokeStyleInstruction); - this.hitDetectionInstructions.push(setStrokeStyleInstruction); - if (!replayStrokeState) { - this.replayStrokeState_ = { - lineCap: strokeState.lineCap, - lineDash: strokeState.lineDash, - lineJoin: strokeState.lineJoin, - lineWidth: strokeState.lineWidth, - miterLimit: strokeState.miterLimit, - strokeStyle: strokeState.strokeStyle - }; - } else { - replayStrokeState.lineCap = strokeState.lineCap; - replayStrokeState.lineDash = strokeState.lineDash; - replayStrokeState.lineJoin = strokeState.lineJoin; - replayStrokeState.lineWidth = strokeState.lineWidth; - replayStrokeState.miterLimit = strokeState.miterLimit; - replayStrokeState.strokeStyle = strokeState.strokeStyle; - } +ol.style.IconImageCache.prototype.get = function(src, crossOrigin) { + var key = ol.style.IconImageCache.getKey(src, crossOrigin); + return key in this.cache_ ? this.cache_[key] : null; }; /** - * @param {ol.render.canvas.TextState} textState Text state. - * @private + * @param {string} src Src. + * @param {?string} crossOrigin Cross origin. + * @param {ol.style.IconImage_} iconImage Icon image. */ -ol.render.canvas.TextReplay.prototype.setReplayTextState_ = - function(textState) { - var replayTextState = this.replayTextState_; - if (replayTextState && - replayTextState.font == textState.font && - replayTextState.textAlign == textState.textAlign && - replayTextState.textBaseline == textState.textBaseline) { - return; - } - var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE, - textState.font, textState.textAlign, textState.textBaseline]; - this.instructions.push(setTextStyleInstruction); - this.hitDetectionInstructions.push(setTextStyleInstruction); - if (!replayTextState) { - this.replayTextState_ = { - font: textState.font, - textAlign: textState.textAlign, - textBaseline: textState.textBaseline - }; - } else { - replayTextState.font = textState.font; - replayTextState.textAlign = textState.textAlign; - replayTextState.textBaseline = textState.textBaseline; - } +ol.style.IconImageCache.prototype.set = function(src, crossOrigin, iconImage) { + var key = ol.style.IconImageCache.getKey(src, crossOrigin); + this.cache_[key] = iconImage; + ++this.cacheSize_; }; +goog.provide('ol.RendererType'); +goog.provide('ol.renderer.Map'); + +goog.require('goog.Disposable'); +goog.require('goog.asserts'); +goog.require('goog.dispose'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('goog.vec.Mat4'); +goog.require('ol'); +goog.require('ol.extent'); +goog.require('ol.layer.Layer'); +goog.require('ol.renderer.Layer'); +goog.require('ol.style.IconImageCache'); +goog.require('ol.vec.Mat4'); + /** - * @inheritDoc + * Available renderers: `'canvas'`, `'dom'` or `'webgl'`. + * @enum {string} + * @api stable */ -ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { - if (!textStyle) { - this.text_ = ''; - } else { - var textFillStyle = textStyle.getFill(); - if (!textFillStyle) { - this.textFillState_ = null; - } else { - var textFillStyleColor = textFillStyle.getColor(); - var fillStyle = ol.color.asString(textFillStyleColor ? - textFillStyleColor : ol.render.canvas.defaultFillStyle); - if (!this.textFillState_) { - this.textFillState_ = { - fillStyle: fillStyle - }; - } else { - var textFillState = this.textFillState_; - textFillState.fillStyle = fillStyle; - } - } - var textStrokeStyle = textStyle.getStroke(); - if (!textStrokeStyle) { - this.textStrokeState_ = null; - } else { - var textStrokeStyleColor = textStrokeStyle.getColor(); - var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); - var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); - var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); - var textStrokeStyleWidth = textStrokeStyle.getWidth(); - var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); - var lineCap = textStrokeStyleLineCap !== undefined ? - textStrokeStyleLineCap : ol.render.canvas.defaultLineCap; - var lineDash = textStrokeStyleLineDash ? - textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; - var lineJoin = textStrokeStyleLineJoin !== undefined ? - textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin; - var lineWidth = textStrokeStyleWidth !== undefined ? - textStrokeStyleWidth : ol.render.canvas.defaultLineWidth; - var miterLimit = textStrokeStyleMiterLimit !== undefined ? - textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - var strokeStyle = ol.color.asString(textStrokeStyleColor ? - textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle); - if (!this.textStrokeState_) { - this.textStrokeState_ = { - lineCap: lineCap, - lineDash: lineDash, - lineJoin: lineJoin, - lineWidth: lineWidth, - miterLimit: miterLimit, - strokeStyle: strokeStyle - }; - } else { - var textStrokeState = this.textStrokeState_; - textStrokeState.lineCap = lineCap; - textStrokeState.lineDash = lineDash; - textStrokeState.lineJoin = lineJoin; - textStrokeState.lineWidth = lineWidth; - textStrokeState.miterLimit = miterLimit; - textStrokeState.strokeStyle = strokeStyle; - } - } - var textFont = textStyle.getFont(); - var textOffsetX = textStyle.getOffsetX(); - var textOffsetY = textStyle.getOffsetY(); - var textRotation = textStyle.getRotation(); - var textScale = textStyle.getScale(); - var textText = textStyle.getText(); - var textTextAlign = textStyle.getTextAlign(); - var textTextBaseline = textStyle.getTextBaseline(); - var font = textFont !== undefined ? - textFont : ol.render.canvas.defaultFont; - var textAlign = textTextAlign !== undefined ? - textTextAlign : ol.render.canvas.defaultTextAlign; - var textBaseline = textTextBaseline !== undefined ? - textTextBaseline : ol.render.canvas.defaultTextBaseline; - if (!this.textState_) { - this.textState_ = { - font: font, - textAlign: textAlign, - textBaseline: textBaseline - }; - } else { - var textState = this.textState_; - textState.font = font; - textState.textAlign = textAlign; - textState.textBaseline = textBaseline; - } - this.text_ = textText !== undefined ? textText : ''; - this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0; - this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0; - this.textRotation_ = textRotation !== undefined ? textRotation : 0; - this.textScale_ = textScale !== undefined ? textScale : 1; - } +ol.RendererType = { + CANVAS: 'canvas', + DOM: 'dom', + WEBGL: 'webgl' }; /** * @constructor - * @implements {ol.render.IReplayGroup} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @param {number} resolution Resolution. - * @param {number=} opt_renderBuffer Optional rendering buffer. + * @extends {goog.Disposable} + * @param {Element} container Container. + * @param {ol.Map} map Map. * @struct */ -ol.render.canvas.ReplayGroup = function( - tolerance, maxExtent, resolution, opt_renderBuffer) { - - /** - * @private - * @type {number} - */ - this.tolerance_ = tolerance; - - /** - * @private - * @type {ol.Extent} - */ - this.maxExtent_ = maxExtent; +ol.renderer.Map = function(container, map) { - /** - * @private - * @type {number} - */ - this.resolution_ = resolution; + goog.base(this); - /** - * @private - * @type {number|undefined} - */ - this.renderBuffer_ = opt_renderBuffer; /** * @private - * @type {!Object.<string, - * Object.<ol.render.ReplayType, ol.render.canvas.Replay>>} + * @type {ol.Map} */ - this.replaysByZIndex_ = {}; + this.map_ = map; /** * @private - * @type {CanvasRenderingContext2D} + * @type {Object.<string, ol.renderer.Layer>} */ - this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1); + this.layerRenderers_ = {}; /** * @private - * @type {!goog.vec.Mat4.Number} + * @type {Object.<string, goog.events.Key>} */ - this.hitDetectionTransform_ = goog.vec.Mat4.createNumber(); + this.layerRendererListeners_ = {}; }; +goog.inherits(ol.renderer.Map, goog.Disposable); /** - * FIXME empty description for jsdoc + * @param {olx.FrameState} frameState FrameState. + * @protected */ -ol.render.canvas.ReplayGroup.prototype.finish = function() { - var zKey; - for (zKey in this.replaysByZIndex_) { - var replays = this.replaysByZIndex_[zKey]; - var replayKey; - for (replayKey in replays) { - replays[replayKey].finish(); - } - } +ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) { + var viewState = frameState.viewState; + var coordinateToPixelMatrix = frameState.coordinateToPixelMatrix; + goog.asserts.assert(coordinateToPixelMatrix, + 'frameState has a coordinateToPixelMatrix'); + ol.vec.Mat4.makeTransform2D(coordinateToPixelMatrix, + frameState.size[0] / 2, frameState.size[1] / 2, + 1 / viewState.resolution, -1 / viewState.resolution, + -viewState.rotation, + -viewState.center[0], -viewState.center[1]); + var inverted = goog.vec.Mat4.invert( + coordinateToPixelMatrix, frameState.pixelToCoordinateMatrix); + goog.asserts.assert(inverted, 'matrix could be inverted'); }; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature - * callback. - * @return {T|undefined} Callback result. - * @template T + * @param {ol.layer.Layer} layer Layer. + * @protected + * @return {ol.renderer.Layer} layerRenderer Layer renderer. */ -ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( - coordinate, resolution, rotation, skippedFeaturesHash, callback) { - - var transform = this.hitDetectionTransform_; - ol.vec.Mat4.makeTransform2D(transform, 0.5, 0.5, - 1 / resolution, -1 / resolution, -rotation, - -coordinate[0], -coordinate[1]); - - var context = this.hitDetectionContext_; - context.clearRect(0, 0, 1, 1); - - /** - * @type {ol.Extent} - */ - var hitExtent; - if (this.renderBuffer_ !== undefined) { - hitExtent = ol.extent.createEmpty(); - ol.extent.extendCoordinate(hitExtent, coordinate); - ol.extent.buffer(hitExtent, resolution * this.renderBuffer_, hitExtent); - } - - return this.replayHitDetection_(context, transform, rotation, - skippedFeaturesHash, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - var imageData = context.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - var result = callback(feature); - if (result) { - return result; - } - context.clearRect(0, 0, 1, 1); - } - }, hitExtent); -}; +ol.renderer.Map.prototype.createLayerRenderer = goog.abstractMethod; /** * @inheritDoc */ -ol.render.canvas.ReplayGroup.prototype.getReplay = - function(zIndex, replayType) { - var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0'; - var replays = this.replaysByZIndex_[zIndexKey]; - if (replays === undefined) { - replays = {}; - this.replaysByZIndex_[zIndexKey] = replays; - } - var replay = replays[replayType]; - if (replay === undefined) { - var Constructor = ol.render.canvas.BATCH_CONSTRUCTORS_[replayType]; - goog.asserts.assert(Constructor !== undefined, - replayType + - ' constructor missing from ol.render.canvas.BATCH_CONSTRUCTORS_'); - replay = new Constructor(this.tolerance_, this.maxExtent_, - this.resolution_); - replays[replayType] = replay; - } - return replay; +ol.renderer.Map.prototype.disposeInternal = function() { + goog.object.forEach(this.layerRenderers_, goog.dispose); + goog.base(this, 'disposeInternal'); }; /** - * @inheritDoc + * @param {ol.Map} map Map. + * @param {olx.FrameState} frameState Frame state. + * @private */ -ol.render.canvas.ReplayGroup.prototype.isEmpty = function() { - return goog.object.isEmpty(this.replaysByZIndex_); +ol.renderer.Map.expireIconCache_ = function(map, frameState) { + ol.style.IconImageCache.getInstance().expire(); }; /** - * @param {CanvasRenderingContext2D} context Context. - * @param {number} pixelRatio Pixel ratio. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {olx.FrameState} frameState FrameState. + * @param {function(this: S, (ol.Feature|ol.render.Feature), + * ol.layer.Layer): T} callback Feature callback. + * @param {S} thisArg Value to use as `this` when executing `callback`. + * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter + * function, only layers which are visible and for which this function + * returns `true` will be tested for features. By default, all visible + * layers will be tested. + * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. + * @return {T|undefined} Callback result. + * @template S,T,U */ -ol.render.canvas.ReplayGroup.prototype.replay = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { +ol.renderer.Map.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg, + layerFilter, thisArg2) { + var result; + var viewState = frameState.viewState; + var viewResolution = viewState.resolution; - /** @type {Array.<number>} */ - var zs = Object.keys(this.replaysByZIndex_).map(Number); - goog.array.sort(zs); + /** @type {Object.<string, boolean>} */ + var features = {}; - // setup clipping so that the parts of over-simplified geometries are not - // visible outside the current extent when panning - var maxExtent = this.maxExtent_; - var minX = maxExtent[0]; - var minY = maxExtent[1]; - var maxX = maxExtent[2]; - var maxY = maxExtent[3]; - var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; - ol.geom.flat.transform.transform2D( - flatClipCoords, 0, 8, 2, transform, flatClipCoords); - context.save(); - context.beginPath(); - context.moveTo(flatClipCoords[0], flatClipCoords[1]); - context.lineTo(flatClipCoords[2], flatClipCoords[3]); - context.lineTo(flatClipCoords[4], flatClipCoords[5]); - context.lineTo(flatClipCoords[6], flatClipCoords[7]); - context.closePath(); - context.clip(); + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function forEachFeatureAtCoordinate(feature) { + goog.asserts.assert(feature !== undefined, 'received a feature'); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback.call(thisArg, feature, null); + } + } - var i, ii, j, jj, replays, replay; - for (i = 0, ii = zs.length; i < ii; ++i) { - replays = this.replaysByZIndex_[zs[i].toString()]; - for (j = 0, jj = ol.render.REPLAY_ORDER.length; j < jj; ++j) { - replay = replays[ol.render.REPLAY_ORDER[j]]; - if (replay !== undefined) { - replay.replay(context, pixelRatio, transform, viewRotation, - skippedFeaturesHash); - } + var projection = viewState.projection; + + var translatedCoordinate = coordinate; + if (projection.canWrapX()) { + var projectionExtent = projection.getExtent(); + var worldWidth = ol.extent.getWidth(projectionExtent); + var x = coordinate[0]; + if (x < projectionExtent[0] || x > projectionExtent[2]) { + var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth); + translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]]; } } - context.restore(); + var layerStates = frameState.layerStatesArray; + var numLayers = layerStates.length; + var i; + for (i = numLayers - 1; i >= 0; --i) { + var layerState = layerStates[i]; + var layer = layerState.layer; + if (!layerState.managed || + (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && + layerFilter.call(thisArg2, layer))) { + var layerRenderer = this.getLayerRenderer(layer); + if (layer.getSource()) { + result = layerRenderer.forEachFeatureAtCoordinate( + layer.getSource().getWrapX() ? translatedCoordinate : coordinate, + frameState, + layerState.managed ? callback : forEachFeatureAtCoordinate, + thisArg); + } + if (result) { + return result; + } + } + } + return undefined; }; /** - * @private - * @param {CanvasRenderingContext2D} context Context. - * @param {goog.vec.Mat4.Number} transform Transform. - * @param {number} viewRotation View rotation. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback - * Feature callback. - * @param {ol.Extent=} opt_hitExtent Only check features that intersect this - * extent. + * @param {ol.Pixel} pixel Pixel. + * @param {olx.FrameState} frameState FrameState. + * @param {function(this: S, ol.layer.Layer): T} callback Layer + * callback. + * @param {S} thisArg Value to use as `this` when executing `callback`. + * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter + * function, only layers which are visible and for which this function + * returns `true` will be tested for features. By default, all visible + * layers will be tested. + * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. * @return {T|undefined} Callback result. - * @template T + * @template S,T,U */ -ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( - context, transform, viewRotation, skippedFeaturesHash, - featureCallback, opt_hitExtent) { - /** @type {Array.<number>} */ - var zs = Object.keys(this.replaysByZIndex_).map(Number); - goog.array.sort(zs, function(a, b) { return b - a; }); +ol.renderer.Map.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg, + layerFilter, thisArg2) { + var result; + var viewState = frameState.viewState; + var viewResolution = viewState.resolution; - var i, ii, j, replays, replay, result; - for (i = 0, ii = zs.length; i < ii; ++i) { - replays = this.replaysByZIndex_[zs[i].toString()]; - for (j = ol.render.REPLAY_ORDER.length - 1; j >= 0; --j) { - replay = replays[ol.render.REPLAY_ORDER[j]]; - if (replay !== undefined) { - result = replay.replayHitDetection(context, transform, viewRotation, - skippedFeaturesHash, featureCallback, opt_hitExtent); - if (result) { - return result; - } + var layerStates = frameState.layerStatesArray; + var numLayers = layerStates.length; + var i; + for (i = numLayers - 1; i >= 0; --i) { + var layerState = layerStates[i]; + var layer = layerState.layer; + if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && + layerFilter.call(thisArg2, layer)) { + var layerRenderer = this.getLayerRenderer(layer); + result = layerRenderer.forEachLayerAtPixel( + pixel, frameState, callback, thisArg); + if (result) { + return result; } } } @@ -63501,7971 +62185,8462 @@ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( /** - * @const + * @param {ol.Coordinate} coordinate Coordinate. + * @param {olx.FrameState} frameState FrameState. + * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter + * function, only layers which are visible and for which this function + * returns `true` will be tested for features. By default, all visible + * layers will be tested. + * @param {U} thisArg Value to use as `this` when executing `layerFilter`. + * @return {boolean} Is there a feature at the given coordinate? + * @template U + */ +ol.renderer.Map.prototype.hasFeatureAtCoordinate = + function(coordinate, frameState, layerFilter, thisArg) { + var hasFeature = this.forEachFeatureAtCoordinate( + coordinate, frameState, goog.functions.TRUE, this, layerFilter, thisArg); + + return hasFeature !== undefined; +}; + + +/** + * @param {ol.layer.Layer} layer Layer. + * @protected + * @return {ol.renderer.Layer} Layer renderer. + */ +ol.renderer.Map.prototype.getLayerRenderer = function(layer) { + var layerKey = goog.getUid(layer).toString(); + if (layerKey in this.layerRenderers_) { + return this.layerRenderers_[layerKey]; + } else { + var layerRenderer = this.createLayerRenderer(layer); + this.layerRenderers_[layerKey] = layerRenderer; + this.layerRendererListeners_[layerKey] = goog.events.listen(layerRenderer, + goog.events.EventType.CHANGE, this.handleLayerRendererChange_, + false, this); + + return layerRenderer; + } +}; + + +/** + * @param {string} layerKey Layer key. + * @protected + * @return {ol.renderer.Layer} Layer renderer. + */ +ol.renderer.Map.prototype.getLayerRendererByKey = function(layerKey) { + goog.asserts.assert(layerKey in this.layerRenderers_, + 'given layerKey (%s) exists in layerRenderers', layerKey); + return this.layerRenderers_[layerKey]; +}; + + +/** + * @protected + * @return {Object.<number, ol.renderer.Layer>} Layer renderers. + */ +ol.renderer.Map.prototype.getLayerRenderers = function() { + return this.layerRenderers_; +}; + + +/** + * @return {ol.Map} Map. + */ +ol.renderer.Map.prototype.getMap = function() { + return this.map_; +}; + + +/** + * @return {string} Type + */ +ol.renderer.Map.prototype.getType = goog.abstractMethod; + + +/** + * Handle changes in a layer renderer. * @private - * @type {Object.<ol.render.ReplayType, - * function(new: ol.render.canvas.Replay, number, ol.Extent, - * number)>} */ -ol.render.canvas.BATCH_CONSTRUCTORS_ = { - 'Image': ol.render.canvas.ImageReplay, - 'LineString': ol.render.canvas.LineStringReplay, - 'Polygon': ol.render.canvas.PolygonReplay, - 'Text': ol.render.canvas.TextReplay +ol.renderer.Map.prototype.handleLayerRendererChange_ = function() { + this.map_.render(); }; -goog.provide('ol.render.Feature'); +/** + * @param {string} layerKey Layer key. + * @return {ol.renderer.Layer} Layer renderer. + * @private + */ +ol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) { + goog.asserts.assert(layerKey in this.layerRenderers_, + 'given layerKey (%s) exists in layerRenderers', layerKey); + var layerRenderer = this.layerRenderers_[layerKey]; + delete this.layerRenderers_[layerKey]; + + goog.asserts.assert(layerKey in this.layerRendererListeners_, + 'given layerKey (%s) exists in layerRendererListeners', layerKey); + goog.events.unlistenByKey(this.layerRendererListeners_[layerKey]); + delete this.layerRendererListeners_[layerKey]; + + return layerRenderer; +}; + + +/** + * Render. + * @param {?olx.FrameState} frameState Frame state. + */ +ol.renderer.Map.prototype.renderFrame = ol.nullFunction; + + +/** + * @param {ol.Map} map Map. + * @param {olx.FrameState} frameState Frame state. + * @private + */ +ol.renderer.Map.prototype.removeUnusedLayerRenderers_ = + function(map, frameState) { + var layerKey; + for (layerKey in this.layerRenderers_) { + if (!frameState || !(layerKey in frameState.layerStates)) { + goog.dispose(this.removeLayerRendererByKey_(layerKey)); + } + } +}; + + +/** + * @param {olx.FrameState} frameState Frame state. + * @protected + */ +ol.renderer.Map.prototype.scheduleExpireIconCache = function(frameState) { + frameState.postRenderFunctions.push(ol.renderer.Map.expireIconCache_); +}; + + +/** + * @param {!olx.FrameState} frameState Frame state. + * @protected + */ +ol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers = + function(frameState) { + var layerKey; + for (layerKey in this.layerRenderers_) { + if (!(layerKey in frameState.layerStates)) { + frameState.postRenderFunctions.push( + goog.bind(this.removeUnusedLayerRenderers_, this)); + return; + } + } +}; + + +/** + * @param {ol.layer.LayerState} state1 + * @param {ol.layer.LayerState} state2 + * @return {number} + */ +ol.renderer.Map.sortByZIndex = function(state1, state2) { + return state1.zIndex - state2.zIndex; +}; + +goog.provide('ol.structs.PriorityQueue'); goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryType'); +goog.require('goog.object'); /** - * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like - * structure, optimized for rendering and styling. Geometry access through the - * API is limited to getting the type and extent of the geometry. + * Priority queue. + * + * The implementation is inspired from the Closure Library's Heap class and + * Python's heapq module. + * + * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html + * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py * * @constructor - * @param {ol.geom.GeometryType} type Geometry type. - * @param {Array.<number>} flatCoordinates Flat coordinates. These always need - * to be right-handed for polygons. - * @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss. - * @param {Object.<string, *>} properties Properties. + * @param {function(T): number} priorityFunction Priority function. + * @param {function(T): string} keyFunction Key function. + * @struct + * @template T */ -ol.render.Feature = function(type, flatCoordinates, ends, properties) { +ol.structs.PriorityQueue = function(priorityFunction, keyFunction) { /** + * @type {function(T): number} * @private - * @type {ol.Extent|undefined} */ - this.extent_; - - goog.asserts.assert(type === ol.geom.GeometryType.POINT || - type === ol.geom.GeometryType.MULTI_POINT || - type === ol.geom.GeometryType.LINE_STRING || - type === ol.geom.GeometryType.MULTI_LINE_STRING || - type === ol.geom.GeometryType.POLYGON, - 'Need a Point, MultiPoint, LineString, MultiLineString or Polygon type'); + this.priorityFunction_ = priorityFunction; /** + * @type {function(T): string} * @private - * @type {ol.geom.GeometryType} */ - this.type_ = type; + this.keyFunction_ = keyFunction; /** + * @type {Array.<T>} * @private - * @type {Array.<number>} */ - this.flatCoordinates_ = flatCoordinates; + this.elements_ = []; /** + * @type {Array.<number>} * @private - * @type {Array.<number>|Array.<Array.<number>>} */ - this.ends_ = ends; + this.priorities_ = []; /** + * @type {Object.<string, boolean>} * @private - * @type {Object.<string, *>} */ - this.properties_ = properties; + this.queuedElements_ = {}; }; /** - * Get a feature property by its key. - * @param {string} key Key - * @return {*} Value for the requested key. - * @api + * @const + * @type {number} */ -ol.render.Feature.prototype.get = function(key) { - return this.properties_[key]; -}; +ol.structs.PriorityQueue.DROP = Infinity; /** - * @return {Array.<number>|Array.<Array.<number>>} Ends or endss. + * FIXME empty description for jsdoc */ -ol.render.Feature.prototype.getEnds = function() { - return this.ends_; +ol.structs.PriorityQueue.prototype.assertValid = function() { + var elements = this.elements_; + var priorities = this.priorities_; + var n = elements.length; + goog.asserts.assert(priorities.length == n); + var i, priority; + for (i = 0; i < (n >> 1) - 1; ++i) { + priority = priorities[i]; + goog.asserts.assert(priority <= priorities[this.getLeftChildIndex_(i)], + 'priority smaller than or equal to priority of left child (%s <= %s)', + priority, priorities[this.getLeftChildIndex_(i)]); + goog.asserts.assert(priority <= priorities[this.getRightChildIndex_(i)], + 'priority smaller than or equal to priority of right child (%s <= %s)', + priority, priorities[this.getRightChildIndex_(i)]); + } }; /** - * Get the extent of this feature's geometry. - * @return {ol.Extent} Extent. - * @api + * FIXME empty description for jsdoc */ -ol.render.Feature.prototype.getExtent = function() { - if (!this.extent_) { - this.extent_ = this.type_ === ol.geom.GeometryType.POINT ? - ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) : - ol.extent.createOrUpdateFromFlatCoordinates( - this.flatCoordinates_, 0, this.flatCoordinates_.length, 2); - - } - return this.extent_; +ol.structs.PriorityQueue.prototype.clear = function() { + this.elements_.length = 0; + this.priorities_.length = 0; + goog.object.clear(this.queuedElements_); }; /** - * @return {Array.<number>} Flat coordinates. + * Remove and return the highest-priority element. O(log N). + * @return {T} Element. */ -ol.render.Feature.prototype.getFlatCoordinates = - ol.render.Feature.prototype.getOrientedFlatCoordinates = function() { - return this.flatCoordinates_; +ol.structs.PriorityQueue.prototype.dequeue = function() { + var elements = this.elements_; + goog.asserts.assert(elements.length > 0, + 'must have elements in order to be able to dequeue'); + var priorities = this.priorities_; + var element = elements[0]; + if (elements.length == 1) { + elements.length = 0; + priorities.length = 0; + } else { + elements[0] = elements.pop(); + priorities[0] = priorities.pop(); + this.siftUp_(0); + } + var elementKey = this.keyFunction_(element); + goog.asserts.assert(elementKey in this.queuedElements_, + 'key %s is not listed as queued', elementKey); + delete this.queuedElements_[elementKey]; + return element; }; /** - * Get the feature for working with its geometry. - * @return {ol.render.Feature} Feature. - * @api + * Enqueue an element. O(log N). + * @param {T} element Element. */ -ol.render.Feature.prototype.getGeometry = function() { - return this; +ol.structs.PriorityQueue.prototype.enqueue = function(element) { + goog.asserts.assert(!(this.keyFunction_(element) in this.queuedElements_), + 'key %s is already listed as queued', this.keyFunction_(element)); + var priority = this.priorityFunction_(element); + if (priority != ol.structs.PriorityQueue.DROP) { + this.elements_.push(element); + this.priorities_.push(priority); + this.queuedElements_[this.keyFunction_(element)] = true; + this.siftDown_(0, this.elements_.length - 1); + } }; /** - * Get the feature properties. - * @return {Object.<string, *>} Feature properties. - * @api + * @return {number} Count. */ -ol.render.Feature.prototype.getProperties = function() { - return this.properties_; +ol.structs.PriorityQueue.prototype.getCount = function() { + return this.elements_.length; }; /** - * Get the feature for working with its geometry. - * @return {ol.render.Feature} Feature. + * Gets the index of the left child of the node at the given index. + * @param {number} index The index of the node to get the left child for. + * @return {number} The index of the left child. + * @private */ -ol.render.Feature.prototype.getSimplifiedGeometry = - ol.render.Feature.prototype.getGeometry; +ol.structs.PriorityQueue.prototype.getLeftChildIndex_ = function(index) { + return index * 2 + 1; +}; /** - * @return {number} Stride. + * Gets the index of the right child of the node at the given index. + * @param {number} index The index of the node to get the right child for. + * @return {number} The index of the right child. + * @private */ -ol.render.Feature.prototype.getStride = goog.functions.constant(2); +ol.structs.PriorityQueue.prototype.getRightChildIndex_ = function(index) { + return index * 2 + 2; +}; /** - * @return {undefined} + * Gets the index of the parent of the node at the given index. + * @param {number} index The index of the node to get the parent for. + * @return {number} The index of the parent. + * @private */ -ol.render.Feature.prototype.getStyleFunction = ol.nullFunction; +ol.structs.PriorityQueue.prototype.getParentIndex_ = function(index) { + return (index - 1) >> 1; +}; /** - * Get the type of this feature's geometry. - * @return {ol.geom.GeometryType} Geometry type. - * @api + * Make this a heap. O(N). + * @private */ -ol.render.Feature.prototype.getType = function() { - return this.type_; +ol.structs.PriorityQueue.prototype.heapify_ = function() { + var i; + for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) { + this.siftUp_(i); + } }; -goog.provide('ol.renderer.vector'); - -goog.require('goog.asserts'); -goog.require('ol.render.Feature'); -goog.require('ol.render.IReplayGroup'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.Style'); - /** - * @param {ol.Feature|ol.render.Feature} feature1 Feature 1. - * @param {ol.Feature|ol.render.Feature} feature2 Feature 2. - * @return {number} Order. + * @return {boolean} Is empty. */ -ol.renderer.vector.defaultOrder = function(feature1, feature2) { - return goog.getUid(feature1) - goog.getUid(feature2); +ol.structs.PriorityQueue.prototype.isEmpty = function() { + return this.elements_.length === 0; }; /** - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @return {number} Squared pixel tolerance. + * @param {string} key Key. + * @return {boolean} Is key queued. */ -ol.renderer.vector.getSquaredTolerance = function(resolution, pixelRatio) { - var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio); - return tolerance * tolerance; +ol.structs.PriorityQueue.prototype.isKeyQueued = function(key) { + return key in this.queuedElements_; }; /** - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @return {number} Pixel tolerance. + * @param {T} element Element. + * @return {boolean} Is queued. */ -ol.renderer.vector.getTolerance = function(resolution, pixelRatio) { - return ol.SIMPLIFY_TOLERANCE * resolution / pixelRatio; +ol.structs.PriorityQueue.prototype.isQueued = function(element) { + return this.isKeyQueued(this.keyFunction_(element)); }; /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Circle} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. + * @param {number} index The index of the node to move down. * @private */ -ol.renderer.vector.renderCircleGeometry_ = - function(replayGroup, geometry, style, feature) { - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - if (fillStyle || strokeStyle) { - var polygonReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.POLYGON); - polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); - polygonReplay.drawCircleGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature); +ol.structs.PriorityQueue.prototype.siftUp_ = function(index) { + var elements = this.elements_; + var priorities = this.priorities_; + var count = elements.length; + var element = elements[index]; + var priority = priorities[index]; + var startIndex = index; + + while (index < (count >> 1)) { + var lIndex = this.getLeftChildIndex_(index); + var rIndex = this.getRightChildIndex_(index); + + var smallerChildIndex = rIndex < count && + priorities[rIndex] < priorities[lIndex] ? + rIndex : lIndex; + + elements[index] = elements[smallerChildIndex]; + priorities[index] = priorities[smallerChildIndex]; + index = smallerChildIndex; } + + elements[index] = element; + priorities[index] = priority; + this.siftDown_(startIndex, index); }; /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.style.Style} style Style. - * @param {number} squaredTolerance Squared tolerance. - * @param {function(this: T, goog.events.Event)} listener Listener function. - * @param {T} thisArg Value to use as `this` when executing `listener`. - * @return {boolean} `true` if style is loading. - * @template T + * @param {number} startIndex The index of the root. + * @param {number} index The index of the node to move up. + * @private */ -ol.renderer.vector.renderFeature = function( - replayGroup, feature, style, squaredTolerance, listener, thisArg) { - var loading = false; - var imageStyle, imageState; - imageStyle = style.getImage(); - if (imageStyle) { - imageState = imageStyle.getImageState(); - if (imageState == ol.style.ImageState.LOADED || - imageState == ol.style.ImageState.ERROR) { - imageStyle.unlistenImageChange(listener, thisArg); +ol.structs.PriorityQueue.prototype.siftDown_ = function(startIndex, index) { + var elements = this.elements_; + var priorities = this.priorities_; + var element = elements[index]; + var priority = priorities[index]; + + while (index > startIndex) { + var parentIndex = this.getParentIndex_(index); + if (priorities[parentIndex] > priority) { + elements[index] = elements[parentIndex]; + priorities[index] = priorities[parentIndex]; + index = parentIndex; } else { - if (imageState == ol.style.ImageState.IDLE) { - imageStyle.load(); - } - imageState = imageStyle.getImageState(); - goog.asserts.assert(imageState == ol.style.ImageState.LOADING, - 'imageState should be LOADING'); - imageStyle.listenImageChange(listener, thisArg); - loading = true; + break; } } - ol.renderer.vector.renderFeature_(replayGroup, feature, style, - squaredTolerance); - return loading; + elements[index] = element; + priorities[index] = priority; }; /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.style.Style} style Style. - * @param {number} squaredTolerance Squared tolerance. - * @private + * FIXME empty description for jsdoc */ -ol.renderer.vector.renderFeature_ = function( - replayGroup, feature, style, squaredTolerance) { - var geometry = style.getGeometryFunction()(feature); - if (!geometry) { - return; +ol.structs.PriorityQueue.prototype.reprioritize = function() { + var priorityFunction = this.priorityFunction_; + var elements = this.elements_; + var priorities = this.priorities_; + var index = 0; + var n = elements.length; + var element, i, priority; + for (i = 0; i < n; ++i) { + element = elements[i]; + priority = priorityFunction(element); + if (priority == ol.structs.PriorityQueue.DROP) { + delete this.queuedElements_[this.keyFunction_(element)]; + } else { + priorities[index] = priority; + elements[index++] = element; + } } - var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); - var geometryRenderer = - ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()]; - goog.asserts.assert(geometryRenderer !== undefined, - 'geometryRenderer should be defined'); - geometryRenderer(replayGroup, simplifiedGeometry, style, feature); + elements.length = index; + priorities.length = index; + this.heapify_(); }; +goog.provide('ol.TilePriorityFunction'); +goog.provide('ol.TileQueue'); -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.GeometryCollection} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderGeometryCollectionGeometry_ = - function(replayGroup, geometry, style, feature) { - var geometries = geometry.getGeometriesArray(); - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometryRenderer = - ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()]; - goog.asserts.assert(geometryRenderer !== undefined, - 'geometryRenderer should be defined'); - geometryRenderer(replayGroup, geometries[i], style, feature); - } -}; +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.Coordinate'); +goog.require('ol.TileState'); +goog.require('ol.structs.PriorityQueue'); /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.LineString|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private + * @typedef {function(ol.Tile, string, ol.Coordinate, number): number} */ -ol.renderer.vector.renderLineStringGeometry_ = - function(replayGroup, geometry, style, feature) { - var strokeStyle = style.getStroke(); - if (strokeStyle) { - var lineStringReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.LINE_STRING); - lineStringReplay.setFillStrokeStyle(null, strokeStyle); - lineStringReplay.drawLineStringGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature); - } -}; +ol.TilePriorityFunction; + /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.MultiLineString|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private + * @constructor + * @extends {ol.structs.PriorityQueue.<Array>} + * @param {ol.TilePriorityFunction} tilePriorityFunction + * Tile priority function. + * @param {function(): ?} tileChangeCallback + * Function called on each tile change event. + * @struct */ -ol.renderer.vector.renderMultiLineStringGeometry_ = - function(replayGroup, geometry, style, feature) { - var strokeStyle = style.getStroke(); - if (strokeStyle) { - var lineStringReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.LINE_STRING); - lineStringReplay.setFillStrokeStyle(null, strokeStyle); - lineStringReplay.drawMultiLineStringGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - var flatMidpointCoordinates = geometry.getFlatMidpoints(); - textReplay.drawText(flatMidpointCoordinates, 0, - flatMidpointCoordinates.length, 2, geometry, feature); - } -}; +ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) { + goog.base( + this, + /** + * @param {Array} element Element. + * @return {number} Priority. + */ + function(element) { + return tilePriorityFunction.apply(null, element); + }, + /** + * @param {Array} element Element. + * @return {string} Key. + */ + function(element) { + return /** @type {ol.Tile} */ (element[0]).getKey(); + }); -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.MultiPolygon} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderMultiPolygonGeometry_ = - function(replayGroup, geometry, style, feature) { - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - if (strokeStyle || fillStyle) { - var polygonReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.POLYGON); - polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); - polygonReplay.drawMultiPolygonGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints(); - textReplay.drawText(flatInteriorPointCoordinates, 0, - flatInteriorPointCoordinates.length, 2, geometry, feature); - } -}; + /** + * @private + * @type {function(): ?} + */ + this.tileChangeCallback_ = tileChangeCallback; + /** + * @private + * @type {number} + */ + this.tilesLoading_ = 0; -/** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Point|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.renderer.vector.renderPointGeometry_ = - function(replayGroup, geometry, style, feature) { - var imageStyle = style.getImage(); - if (imageStyle) { - if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { - return; - } - var imageReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.IMAGE); - imageReplay.setImageStyle(imageStyle); - imageReplay.drawPointGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry, - feature); - } }; +goog.inherits(ol.TileQueue, ol.structs.PriorityQueue); /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.MultiPoint|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private + * @return {number} Number of tiles loading. */ -ol.renderer.vector.renderMultiPointGeometry_ = - function(replayGroup, geometry, style, feature) { - var imageStyle = style.getImage(); - if (imageStyle) { - if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { - return; - } - var imageReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.IMAGE); - imageReplay.setImageStyle(imageStyle); - imageReplay.drawMultiPointGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - var flatCoordinates = geometry.getFlatCoordinates(); - textReplay.drawText(flatCoordinates, 0, flatCoordinates.length, - geometry.getStride(), geometry, feature); - } +ol.TileQueue.prototype.getTilesLoading = function() { + return this.tilesLoading_; }; /** - * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Polygon|ol.render.Feature} geometry Geometry. - * @param {ol.style.Style} style Style. - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private + * @param {goog.events.Event} event Event. + * @protected */ -ol.renderer.vector.renderPolygonGeometry_ = - function(replayGroup, geometry, style, feature) { - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - if (fillStyle || strokeStyle) { - var polygonReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.POLYGON); - polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); - polygonReplay.drawPolygonGeometry(geometry, feature); - } - var textStyle = style.getText(); - if (textStyle) { - var textReplay = replayGroup.getReplay( - style.getZIndex(), ol.render.ReplayType.TEXT); - textReplay.setTextStyle(textStyle); - textReplay.drawText( - geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature); +ol.TileQueue.prototype.handleTileChange = function(event) { + var tile = /** @type {ol.Tile} */ (event.target); + var state = tile.getState(); + if (state === ol.TileState.LOADED || state === ol.TileState.ERROR || + state === ol.TileState.EMPTY) { + goog.events.unlisten(tile, goog.events.EventType.CHANGE, + this.handleTileChange, false, this); + --this.tilesLoading_; + this.tileChangeCallback_(); } }; /** - * @const - * @private - * @type {Object.<ol.geom.GeometryType, - * function(ol.render.IReplayGroup, ol.geom.Geometry, - * ol.style.Style, Object)>} + * @param {number} maxTotalLoading Maximum number tiles to load simultaneously. + * @param {number} maxNewLoads Maximum number of new tiles to load. */ -ol.renderer.vector.GEOMETRY_RENDERERS_ = { - 'Point': ol.renderer.vector.renderPointGeometry_, - 'LineString': ol.renderer.vector.renderLineStringGeometry_, - 'Polygon': ol.renderer.vector.renderPolygonGeometry_, - 'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_, - 'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_, - 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_, - 'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_, - 'Circle': ol.renderer.vector.renderCircleGeometry_ +ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { + var newLoads = 0; + var tile; + while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads && + this.getCount() > 0) { + tile = /** @type {ol.Tile} */ (this.dequeue()[0]); + if (tile.getState() === ol.TileState.IDLE) { + goog.events.listen(tile, goog.events.EventType.CHANGE, + this.handleTileChange, false, this); + tile.load(); + ++this.tilesLoading_; + ++newLoads; + } + } }; -goog.provide('ol.ImageCanvas'); +goog.provide('ol.Kinetic'); -goog.require('goog.asserts'); -goog.require('ol.ImageBase'); -goog.require('ol.ImageState'); +goog.require('ol.Coordinate'); +goog.require('ol.PreRenderFunction'); +goog.require('ol.animation'); /** + * @classdesc + * Implementation of inertial deceleration for map movement. + * * @constructor - * @extends {ol.ImageBase} - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {Array.<ol.Attribution>} attributions Attributions. - * @param {HTMLCanvasElement} canvas Canvas. - * @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to - * support asynchronous canvas drawing. + * @param {number} decay Rate of decay (must be negative). + * @param {number} minVelocity Minimum velocity (pixels/millisecond). + * @param {number} delay Delay to consider to calculate the kinetic + * initial values (milliseconds). + * @struct + * @api */ -ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions, - canvas, opt_loader) { +ol.Kinetic = function(decay, minVelocity, delay) { /** - * Optional canvas loader function. - * @type {?ol.ImageCanvasLoader} * @private + * @type {number} */ - this.loader_ = opt_loader !== undefined ? opt_loader : null; + this.decay_ = decay; - var state = opt_loader !== undefined ? - ol.ImageState.IDLE : ol.ImageState.LOADED; + /** + * @private + * @type {number} + */ + this.minVelocity_ = minVelocity; - goog.base(this, extent, resolution, pixelRatio, state, attributions); + /** + * @private + * @type {number} + */ + this.delay_ = delay; /** * @private - * @type {HTMLCanvasElement} + * @type {Array.<number>} */ - this.canvas_ = canvas; + this.points_ = []; /** * @private - * @type {Error} + * @type {number} */ - this.error_ = null; + this.angle_ = 0; + /** + * @private + * @type {number} + */ + this.initialVelocity_ = 0; }; -goog.inherits(ol.ImageCanvas, ol.ImageBase); /** - * Get any error associated with asynchronous rendering. - * @return {Error} Any error that occurred during rendering. + * FIXME empty description for jsdoc */ -ol.ImageCanvas.prototype.getError = function() { - return this.error_; +ol.Kinetic.prototype.begin = function() { + this.points_.length = 0; + this.angle_ = 0; + this.initialVelocity_ = 0; }; /** - * Handle async drawing complete. - * @param {Error} err Any error during drawing. - * @private + * @param {number} x X. + * @param {number} y Y. */ -ol.ImageCanvas.prototype.handleLoad_ = function(err) { - if (err) { - this.error_ = err; - this.state = ol.ImageState.ERROR; - } else { - this.state = ol.ImageState.LOADED; - } - this.changed(); +ol.Kinetic.prototype.update = function(x, y) { + this.points_.push(x, y, Date.now()); }; /** - * Trigger drawing on canvas. + * @return {boolean} Whether we should do kinetic animation. */ -ol.ImageCanvas.prototype.load = function() { - if (this.state == ol.ImageState.IDLE) { - goog.asserts.assert(this.loader_, 'this.loader_ must be set'); - this.state = ol.ImageState.LOADING; - this.changed(); - this.loader_(goog.bind(this.handleLoad_, this)); +ol.Kinetic.prototype.end = function() { + if (this.points_.length < 6) { + // at least 2 points are required (i.e. there must be at least 6 elements + // in the array) + return false; + } + var delay = Date.now() - this.delay_; + var lastIndex = this.points_.length - 3; + if (this.points_[lastIndex + 2] < delay) { + // the last tracked point is too old, which means that the user stopped + // panning before releasing the map + return false; } + + // get the first point which still falls into the delay time + var firstIndex = lastIndex - 3; + while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) { + firstIndex -= 3; + } + var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2]; + var dx = this.points_[lastIndex] - this.points_[firstIndex]; + var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1]; + this.angle_ = Math.atan2(dy, dx); + this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration; + return this.initialVelocity_ > this.minVelocity_; }; /** - * @inheritDoc + * @param {ol.Coordinate} source Source coordinate for the animation. + * @return {ol.PreRenderFunction} Pre-render function for kinetic animation. */ -ol.ImageCanvas.prototype.getImage = function(opt_context) { - return this.canvas_; +ol.Kinetic.prototype.pan = function(source) { + var decay = this.decay_; + var initialVelocity = this.initialVelocity_; + var velocity = this.minVelocity_ - initialVelocity; + var duration = this.getDuration_(); + var easingFunction = ( + /** + * @param {number} t T. + * @return {number} Easing. + */ + function(t) { + return initialVelocity * (Math.exp((decay * t) * duration) - 1) / + velocity; + }); + return ol.animation.pan({ + source: source, + duration: duration, + easing: easingFunction + }); }; /** - * A function that is called to trigger asynchronous canvas drawing. It is - * called with a "done" callback that should be called when drawing is done. - * If any error occurs during drawing, the "done" callback should be called with - * that error. - * - * @typedef {function(function(Error))} + * @private + * @return {number} Duration of animation (milliseconds). */ -ol.ImageCanvasLoader; - -goog.provide('ol.reproj'); - -goog.require('goog.labs.userAgent.browser'); -goog.require('goog.labs.userAgent.platform'); -goog.require('goog.math'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.math'); -goog.require('ol.proj'); +ol.Kinetic.prototype.getDuration_ = function() { + return Math.log(this.minVelocity_ / this.initialVelocity_) / this.decay_; +}; /** - * We need to employ more sophisticated solution - * if the web browser antialiases clipping edges on canvas. - * - * Currently only Chrome does not antialias the edges, but this is probably - * going to be "fixed" in the future: http://crbug.com/424291 - * - * @type {boolean} - * @private + * @return {number} Total distance travelled (pixels). */ -ol.reproj.browserAntialiasesClip_ = !goog.labs.userAgent.browser.isChrome() || - goog.labs.userAgent.platform.isIos(); +ol.Kinetic.prototype.getDistance = function() { + return (this.minVelocity_ - this.initialVelocity_) / this.decay_; +}; /** - * Calculates ideal resolution to use from the source in order to achieve - * pixel mapping as close as possible to 1:1 during reprojection. - * The resolution is calculated regardless of what resolutions - * are actually available in the dataset (TileGrid, Image, ...). - * - * @param {ol.proj.Projection} sourceProj Source projection. - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.Coordinate} targetCenter Target center. - * @param {number} targetResolution Target resolution. - * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0. + * @return {number} Angle of the kinetic panning animation (radians). */ -ol.reproj.calculateSourceResolution = function(sourceProj, targetProj, - targetCenter, targetResolution) { - - var sourceCenter = ol.proj.transform(targetCenter, targetProj, sourceProj); - - // calculate the ideal resolution of the source data - var sourceResolution = - targetProj.getPointResolution(targetResolution, targetCenter); - - var targetMetersPerUnit = targetProj.getMetersPerUnit(); - if (targetMetersPerUnit !== undefined) { - sourceResolution *= targetMetersPerUnit; - } - var sourceMetersPerUnit = sourceProj.getMetersPerUnit(); - if (sourceMetersPerUnit !== undefined) { - sourceResolution /= sourceMetersPerUnit; - } - - // Based on the projection properties, the point resolution at the specified - // coordinates may be slightly different. We need to reverse-compensate this - // in order to achieve optimal results. +ol.Kinetic.prototype.getAngle = function() { + return this.angle_; +}; - var compensationFactor = - sourceProj.getPointResolution(sourceResolution, sourceCenter) / - sourceResolution; +// FIXME factor out key precondition (shift et. al) - if (goog.math.isFiniteNumber(compensationFactor) && compensationFactor > 0) { - sourceResolution /= compensationFactor; - } +goog.provide('ol.interaction.Interaction'); +goog.provide('ol.interaction.InteractionProperty'); - return sourceResolution; -}; +goog.require('ol'); +goog.require('ol.MapBrowserEvent'); +goog.require('ol.Object'); +goog.require('ol.animation'); +goog.require('ol.easing'); /** - * Enlarge the clipping triangle point by 1 pixel to ensure the edges overlap - * in order to mask gaps caused by antialiasing. - * - * @param {number} centroidX Centroid of the triangle (x coordinate in pixels). - * @param {number} centroidY Centroid of the triangle (y coordinate in pixels). - * @param {number} x X coordinate of the point (in pixels). - * @param {number} y Y coordinate of the point (in pixels). - * @return {ol.Coordinate} New point 1 px farther from the centroid. - * @private + * @enum {string} */ -ol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) { - var dX = x - centroidX, dY = y - centroidY; - var distance = Math.sqrt(dX * dX + dY * dY); - return [Math.round(x + dX / distance), Math.round(y + dY / distance)]; +ol.interaction.InteractionProperty = { + ACTIVE: 'active' }; + /** - * Renders the source data into new canvas based on the triangulation. + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * User actions that change the state of the map. Some are similar to controls, + * but are not associated with a DOM element. + * For example, {@link ol.interaction.KeyboardZoom} is functionally the same as + * {@link ol.control.Zoom}, but triggered by a keyboard event not a button + * element event. + * Although interactions do not have a DOM element, some of them do render + * vectors and so are visible on the screen. * - * @param {number} width Width of the canvas. - * @param {number} height Height of the canvas. - * @param {number} pixelRatio Pixel ratio. - * @param {number} sourceResolution Source resolution. - * @param {ol.Extent} sourceExtent Extent of the data source. - * @param {number} targetResolution Target resolution. - * @param {ol.Extent} targetExtent Target extent. - * @param {ol.reproj.Triangulation} triangulation Calculated triangulation. - * @param {Array.<{extent: ol.Extent, - * image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources - * Array of sources. - * @param {boolean=} opt_renderEdges Render reprojection edges. - * @return {HTMLCanvasElement} Canvas with reprojected data. + * @constructor + * @param {olx.interaction.InteractionOptions} options Options. + * @extends {ol.Object} + * @api */ -ol.reproj.render = function(width, height, pixelRatio, - sourceResolution, sourceExtent, targetResolution, targetExtent, - triangulation, sources, opt_renderEdges) { +ol.interaction.Interaction = function(options) { - var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width), - Math.round(pixelRatio * height)); + goog.base(this); - if (sources.length === 0) { - return context.canvas; - } + /** + * @private + * @type {ol.Map} + */ + this.map_ = null; - context.scale(pixelRatio, pixelRatio); + this.setActive(true); - var sourceDataExtent = ol.extent.createEmpty(); - sources.forEach(function(src, i, arr) { - ol.extent.extend(sourceDataExtent, src.extent); - }); + /** + * @type {function(ol.MapBrowserEvent):boolean} + */ + this.handleEvent = options.handleEvent; - var canvasWidthInUnits = ol.extent.getWidth(sourceDataExtent); - var canvasHeightInUnits = ol.extent.getHeight(sourceDataExtent); - var stitchContext = ol.dom.createCanvasContext2D( - Math.round(pixelRatio * canvasWidthInUnits / sourceResolution), - Math.round(pixelRatio * canvasHeightInUnits / sourceResolution)); +}; +goog.inherits(ol.interaction.Interaction, ol.Object); - stitchContext.scale(pixelRatio / sourceResolution, - pixelRatio / sourceResolution); - stitchContext.translate(-sourceDataExtent[0], sourceDataExtent[3]); - sources.forEach(function(src, i, arr) { - var xPos = src.extent[0]; - var yPos = -src.extent[3]; - var srcWidth = ol.extent.getWidth(src.extent); - var srcHeight = ol.extent.getHeight(src.extent); +/** + * Return whether the interaction is currently active. + * @return {boolean} `true` if the interaction is active, `false` otherwise. + * @observable + * @api + */ +ol.interaction.Interaction.prototype.getActive = function() { + return /** @type {boolean} */ ( + this.get(ol.interaction.InteractionProperty.ACTIVE)); +}; - stitchContext.drawImage(src.image, xPos, yPos, srcWidth, srcHeight); - }); - var targetTopLeft = ol.extent.getTopLeft(targetExtent); +/** + * Get the map associated with this interaction. + * @return {ol.Map} Map. + */ +ol.interaction.Interaction.prototype.getMap = function() { + return this.map_; +}; - triangulation.getTriangles().forEach(function(triangle, i, arr) { - /* Calculate affine transform (src -> dst) - * Resulting matrix can be used to transform coordinate - * from `sourceProjection` to destination pixels. - * - * To optimize number of context calls and increase numerical stability, - * we also do the following operations: - * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1) - * here before solving the linear system so [ui, vi] are pixel coordinates. - * - * Src points: xi, yi - * Dst points: ui, vi - * Affine coefficients: aij - * - * | x0 y0 1 0 0 0 | |a00| |u0| - * | x1 y1 1 0 0 0 | |a01| |u1| - * | x2 y2 1 0 0 0 | x |a02| = |u2| - * | 0 0 0 x0 y0 1 | |a10| |v0| - * | 0 0 0 x1 y1 1 | |a11| |v1| - * | 0 0 0 x2 y2 1 | |a12| |v2| - */ - var source = triangle.source, target = triangle.target; - var x0 = source[0][0], y0 = source[0][1], - x1 = source[1][0], y1 = source[1][1], - x2 = source[2][0], y2 = source[2][1]; - var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution, - v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; - var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution, - v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; - var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution, - v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; - // Shift all the source points to improve numerical stability - // of all the subsequent calculations. The [x0, y0] is used here. - // This is also used to simplify the linear system. - var sourceNumericalShiftX = x0, sourceNumericalShiftY = y0; - x0 = 0; - y0 = 0; - x1 -= sourceNumericalShiftX; - y1 -= sourceNumericalShiftY; - x2 -= sourceNumericalShiftX; - y2 -= sourceNumericalShiftY; +/** + * Activate or deactivate the interaction. + * @param {boolean} active Active. + * @observable + * @api + */ +ol.interaction.Interaction.prototype.setActive = function(active) { + this.set(ol.interaction.InteractionProperty.ACTIVE, active); +}; - var augmentedMatrix = [ - [x1, y1, 0, 0, u1 - u0], - [x2, y2, 0, 0, u2 - u0], - [0, 0, x1, y1, v1 - v0], - [0, 0, x2, y2, v2 - v0] - ]; - var affineCoefs = ol.math.solveLinearSystem(augmentedMatrix); - if (!affineCoefs) { - return; - } - context.save(); - context.beginPath(); - if (ol.reproj.browserAntialiasesClip_) { - var centroidX = (u0 + u1 + u2) / 3, centroidY = (v0 + v1 + v2) / 3; - var p0 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u0, v0); - var p1 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u1, v1); - var p2 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u2, v2); +/** + * Remove the interaction from its current map and attach it to the new map. + * Subclasses may set up event handlers to get notified about changes to + * the map here. + * @param {ol.Map} map Map. + */ +ol.interaction.Interaction.prototype.setMap = function(map) { + this.map_ = map; +}; - context.moveTo(p0[0], p0[1]); - context.lineTo(p1[0], p1[1]); - context.lineTo(p2[0], p2[1]); - } else { - context.moveTo(u0, v0); - context.lineTo(u1, v1); - context.lineTo(u2, v2); + +/** + * @param {ol.Map} map Map. + * @param {ol.View} view View. + * @param {ol.Coordinate} delta Delta. + * @param {number=} opt_duration Duration. + */ +ol.interaction.Interaction.pan = function(map, view, delta, opt_duration) { + var currentCenter = view.getCenter(); + if (currentCenter) { + if (opt_duration && opt_duration > 0) { + map.beforeRender(ol.animation.pan({ + source: currentCenter, + duration: opt_duration, + easing: ol.easing.linear + })); } - context.closePath(); - context.clip(); + var center = view.constrainCenter( + [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]); + view.setCenter(center); + } +}; - context.transform( - affineCoefs[0], affineCoefs[2], affineCoefs[1], affineCoefs[3], u0, v0); - context.translate(sourceDataExtent[0] - sourceNumericalShiftX, - sourceDataExtent[3] - sourceNumericalShiftY); +/** + * @param {ol.Map} map Map. + * @param {ol.View} view View. + * @param {number|undefined} rotation Rotation. + * @param {ol.Coordinate=} opt_anchor Anchor coordinate. + * @param {number=} opt_duration Duration. + */ +ol.interaction.Interaction.rotate = + function(map, view, rotation, opt_anchor, opt_duration) { + rotation = view.constrainRotation(rotation, 0); + ol.interaction.Interaction.rotateWithoutConstraints( + map, view, rotation, opt_anchor, opt_duration); +}; - context.scale(sourceResolution / pixelRatio, - -sourceResolution / pixelRatio); - context.drawImage(stitchContext.canvas, 0, 0); - context.restore(); - }); +/** + * @param {ol.Map} map Map. + * @param {ol.View} view View. + * @param {number|undefined} rotation Rotation. + * @param {ol.Coordinate=} opt_anchor Anchor coordinate. + * @param {number=} opt_duration Duration. + */ +ol.interaction.Interaction.rotateWithoutConstraints = + function(map, view, rotation, opt_anchor, opt_duration) { + if (rotation !== undefined) { + var currentRotation = view.getRotation(); + var currentCenter = view.getCenter(); + if (currentRotation !== undefined && currentCenter && + opt_duration && opt_duration > 0) { + map.beforeRender(ol.animation.rotate({ + rotation: currentRotation, + duration: opt_duration, + easing: ol.easing.easeOut + })); + if (opt_anchor) { + map.beforeRender(ol.animation.pan({ + source: currentCenter, + duration: opt_duration, + easing: ol.easing.easeOut + })); + } + } + view.rotate(rotation, opt_anchor); + } +}; - if (opt_renderEdges) { - context.save(); - context.strokeStyle = 'black'; - context.lineWidth = 1; +/** + * @param {ol.Map} map Map. + * @param {ol.View} view View. + * @param {number|undefined} resolution Resolution to go to. + * @param {ol.Coordinate=} opt_anchor Anchor coordinate. + * @param {number=} opt_duration Duration. + * @param {number=} opt_direction Zooming direction; > 0 indicates + * zooming out, in which case the constraints system will select + * the largest nearest resolution; < 0 indicates zooming in, in + * which case the constraints system will select the smallest + * nearest resolution; == 0 indicates that the zooming direction + * is unknown/not relevant, in which case the constraints system + * will select the nearest resolution. If not defined 0 is + * assumed. + */ +ol.interaction.Interaction.zoom = + function(map, view, resolution, opt_anchor, opt_duration, opt_direction) { + resolution = view.constrainResolution(resolution, 0, opt_direction); + ol.interaction.Interaction.zoomWithoutConstraints( + map, view, resolution, opt_anchor, opt_duration); +}; - triangulation.getTriangles().forEach(function(triangle, i, arr) { - var target = triangle.target; - var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution, - v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; - var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution, - v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; - var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution, - v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; - context.beginPath(); - context.moveTo(u0, v0); - context.lineTo(u1, v1); - context.lineTo(u2, v2); - context.closePath(); - context.stroke(); - }); +/** + * @param {ol.Map} map Map. + * @param {ol.View} view View. + * @param {number} delta Delta from previous zoom level. + * @param {ol.Coordinate=} opt_anchor Anchor coordinate. + * @param {number=} opt_duration Duration. + */ +ol.interaction.Interaction.zoomByDelta = + function(map, view, delta, opt_anchor, opt_duration) { + var currentResolution = view.getResolution(); + var resolution = view.constrainResolution(currentResolution, delta, 0); + ol.interaction.Interaction.zoomWithoutConstraints( + map, view, resolution, opt_anchor, opt_duration); +}; - context.restore(); + +/** + * @param {ol.Map} map Map. + * @param {ol.View} view View. + * @param {number|undefined} resolution Resolution to go to. + * @param {ol.Coordinate=} opt_anchor Anchor coordinate. + * @param {number=} opt_duration Duration. + */ +ol.interaction.Interaction.zoomWithoutConstraints = + function(map, view, resolution, opt_anchor, opt_duration) { + if (resolution) { + var currentResolution = view.getResolution(); + var currentCenter = view.getCenter(); + if (currentResolution !== undefined && currentCenter && + resolution !== currentResolution && + opt_duration && opt_duration > 0) { + map.beforeRender(ol.animation.zoom({ + resolution: currentResolution, + duration: opt_duration, + easing: ol.easing.easeOut + })); + if (opt_anchor) { + map.beforeRender(ol.animation.pan({ + source: currentCenter, + duration: opt_duration, + easing: ol.easing.easeOut + })); + } + } + if (opt_anchor) { + var center = view.calculateCenterZoom(resolution, opt_anchor); + view.setCenter(center); + } + view.setResolution(resolution); } - return context.canvas; }; -goog.provide('ol.reproj.Triangulation'); +goog.provide('ol.interaction.DoubleClickZoom'); goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol.extent'); -goog.require('ol.proj'); - - -/** - * Single triangle; consists of 3 source points and 3 target points. - * - * @typedef {{source: Array.<ol.Coordinate>, - * target: Array.<ol.Coordinate>}} - */ -ol.reproj.Triangle; +goog.require('ol.MapBrowserEvent'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.interaction.Interaction'); /** * @classdesc - * Class containing triangulation of the given target extent. - * Used for determining source data and the reprojection itself. + * Allows the user to zoom by double-clicking on the map. * - * @param {ol.proj.Projection} sourceProj Source projection. - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.Extent} targetExtent Target extent to triangulate. - * @param {ol.Extent} maxSourceExtent Maximal source extent that can be used. - * @param {number} errorThreshold Acceptable error (in source units). * @constructor + * @extends {ol.interaction.Interaction} + * @param {olx.interaction.DoubleClickZoomOptions=} opt_options Options. + * @api stable */ -ol.reproj.Triangulation = function(sourceProj, targetProj, targetExtent, - maxSourceExtent, errorThreshold) { +ol.interaction.DoubleClickZoom = function(opt_options) { - /** - * @type {ol.proj.Projection} - * @private - */ - this.sourceProj_ = sourceProj; + var options = opt_options ? opt_options : {}; /** - * @type {ol.proj.Projection} * @private + * @type {number} */ - this.targetProj_ = targetProj; + this.delta_ = options.delta ? options.delta : 1; - /** @type {!Object.<string, ol.Coordinate>} */ - var transformInvCache = {}; - var transformInv = ol.proj.getTransform(this.targetProj_, this.sourceProj_); + goog.base(this, { + handleEvent: ol.interaction.DoubleClickZoom.handleEvent + }); /** - * @param {ol.Coordinate} c - * @return {ol.Coordinate} * @private + * @type {number} */ - this.transformInv_ = function(c) { - var key = c[0] + '/' + c[1]; - if (!transformInvCache[key]) { - transformInvCache[key] = transformInv(c); - } - return transformInvCache[key]; - }; - - /** - * @type {ol.Extent} - * @private - */ - this.maxSourceExtent_ = maxSourceExtent; - - /** - * @type {number} - * @private - */ - this.errorThresholdSquared_ = errorThreshold * errorThreshold; - - /** - * @type {Array.<ol.reproj.Triangle>} - * @private - */ - this.triangles_ = []; - - /** - * Indicates that the triangulation crosses edge of the source projection. - * @type {boolean} - * @private - */ - this.wrapsXInSource_ = false; - - /** - * @type {boolean} - * @private - */ - this.canWrapXInSource_ = this.sourceProj_.canWrapX() && - !!maxSourceExtent && - !!this.sourceProj_.getExtent() && - (ol.extent.getWidth(maxSourceExtent) == - ol.extent.getWidth(this.sourceProj_.getExtent())); + this.duration_ = options.duration !== undefined ? options.duration : 250; - /** - * @type {?number} - * @private - */ - this.sourceWorldWidth_ = this.sourceProj_.getExtent() ? - ol.extent.getWidth(this.sourceProj_.getExtent()) : null; +}; +goog.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction); - /** - * @type {?number} - * @private - */ - this.targetWorldWidth_ = this.targetProj_.getExtent() ? - ol.extent.getWidth(this.targetProj_.getExtent()) : null; - var destinationTopLeft = ol.extent.getTopLeft(targetExtent); - var destinationTopRight = ol.extent.getTopRight(targetExtent); - var destinationBottomRight = ol.extent.getBottomRight(targetExtent); - var destinationBottomLeft = ol.extent.getBottomLeft(targetExtent); - var sourceTopLeft = this.transformInv_(destinationTopLeft); - var sourceTopRight = this.transformInv_(destinationTopRight); - var sourceBottomRight = this.transformInv_(destinationBottomRight); - var sourceBottomLeft = this.transformInv_(destinationBottomLeft); +/** + * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a + * doubleclick) and eventually zooms the map. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.DoubleClickZoom} + * @api + */ +ol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) { + var stopEvent = false; + var browserEvent = mapBrowserEvent.browserEvent; + if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK) { + var map = mapBrowserEvent.map; + var anchor = mapBrowserEvent.coordinate; + var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_; + var view = map.getView(); + goog.asserts.assert(view, 'map must have a view'); + ol.interaction.Interaction.zoomByDelta( + map, view, delta, anchor, this.duration_); + mapBrowserEvent.preventDefault(); + stopEvent = true; + } + return !stopEvent; +}; - this.addQuad_( - destinationTopLeft, destinationTopRight, - destinationBottomRight, destinationBottomLeft, - sourceTopLeft, sourceTopRight, sourceBottomRight, sourceBottomLeft, - ol.RASTER_REPROJECTION_MAX_SUBDIVISION); +goog.provide('ol.events.ConditionType'); +goog.provide('ol.events.condition'); - if (this.wrapsXInSource_) { - // Fix coordinates (ol.proj returns wrapped coordinates, "unwrap" here). - // This significantly simplifies the rest of the reprojection process. +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.MapBrowserPointerEvent'); - goog.asserts.assert(this.sourceWorldWidth_ !== null); - var leftBound = Infinity; - this.triangles_.forEach(function(triangle, i, arr) { - leftBound = Math.min(leftBound, - triangle.source[0][0], triangle.source[1][0], triangle.source[2][0]); - }); - // Shift triangles to be as close to `leftBound` as possible - // (if the distance is more than `worldWidth / 2` it can be closer. - this.triangles_.forEach(function(triangle) { - if (Math.max(triangle.source[0][0], triangle.source[1][0], - triangle.source[2][0]) - leftBound > this.sourceWorldWidth_ / 2) { - var newTriangle = [[triangle.source[0][0], triangle.source[0][1]], - [triangle.source[1][0], triangle.source[1][1]], - [triangle.source[2][0], triangle.source[2][1]]]; - if ((newTriangle[0][0] - leftBound) > this.sourceWorldWidth_ / 2) { - newTriangle[0][0] -= this.sourceWorldWidth_; - } - if ((newTriangle[1][0] - leftBound) > this.sourceWorldWidth_ / 2) { - newTriangle[1][0] -= this.sourceWorldWidth_; - } - if ((newTriangle[2][0] - leftBound) > this.sourceWorldWidth_ / 2) { - newTriangle[2][0] -= this.sourceWorldWidth_; - } +/** + * A function that takes an {@link ol.MapBrowserEvent} and returns a + * `{boolean}`. If the condition is met, true should be returned. + * + * @typedef {function(ol.MapBrowserEvent): boolean} + * @api stable + */ +ol.events.ConditionType; - // Rarely (if the extent contains both the dateline and prime meridian) - // the shift can in turn break some triangles. - // Detect this here and don't shift in such cases. - var minX = Math.min( - newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]); - var maxX = Math.max( - newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]); - if ((maxX - minX) < this.sourceWorldWidth_ / 2) { - triangle.source = newTriangle; - } - } - }, this); - } - transformInvCache = {}; +/** + * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when + * additionally the shift-key is pressed). + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if only the alt key is pressed. + * @api stable + */ +ol.events.condition.altKeyOnly = function(mapBrowserEvent) { + var browserEvent = mapBrowserEvent.browserEvent; + return ( + browserEvent.altKey && + !browserEvent.platformModifierKey && + !browserEvent.shiftKey); }; /** - * Adds triangle to the triangulation. - * @param {ol.Coordinate} a - * @param {ol.Coordinate} b - * @param {ol.Coordinate} c - * @param {ol.Coordinate} aSrc - * @param {ol.Coordinate} bSrc - * @param {ol.Coordinate} cSrc - * @private + * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise + * (e.g. when additionally the platform-modifier-key is pressed). + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if only the alt and shift keys are pressed. + * @api stable */ -ol.reproj.Triangulation.prototype.addTriangle_ = function(a, b, c, - aSrc, bSrc, cSrc) { - this.triangles_.push({ - source: [aSrc, bSrc, cSrc], - target: [a, b, c] - }); +ol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) { + var browserEvent = mapBrowserEvent.browserEvent; + return ( + browserEvent.altKey && + !browserEvent.platformModifierKey && + browserEvent.shiftKey); }; /** - * Adds quad (points in clock-wise order) to the triangulation - * (and reprojects the vertices) if valid. - * Performs quad subdivision if needed to increase precision. + * Return always true. * - * @param {ol.Coordinate} a - * @param {ol.Coordinate} b - * @param {ol.Coordinate} c - * @param {ol.Coordinate} d - * @param {ol.Coordinate} aSrc - * @param {ol.Coordinate} bSrc - * @param {ol.Coordinate} cSrc - * @param {ol.Coordinate} dSrc - * @param {number} maxSubdivision Maximal allowed subdivision of the quad. - * @private + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True. + * @function + * @api stable */ -ol.reproj.Triangulation.prototype.addQuad_ = function(a, b, c, d, - aSrc, bSrc, cSrc, dSrc, maxSubdivision) { - - var sourceQuadExtent = ol.extent.boundingExtent([aSrc, bSrc, cSrc, dSrc]); - var sourceCoverageX = this.sourceWorldWidth_ ? - ol.extent.getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null; - - // when the quad is wrapped in the source projection - // it covers most of the projection extent, but not fully - var wrapsX = this.sourceProj_.canWrapX() && - sourceCoverageX > 0.5 && sourceCoverageX < 1; +ol.events.condition.always = goog.functions.TRUE; - var needsSubdivision = false; - if (maxSubdivision > 0) { - if (this.targetProj_.isGlobal() && this.targetWorldWidth_) { - var targetQuadExtent = ol.extent.boundingExtent([a, b, c, d]); - var targetCoverageX = - ol.extent.getWidth(targetQuadExtent) / this.targetWorldWidth_; - needsSubdivision |= - targetCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH; - } - if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) { - needsSubdivision |= - sourceCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH; - } - } +/** + * Return `true` if the event is a `click` event, `false` otherwise. + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if the event is a map `click` event. + * @api stable + */ +ol.events.condition.click = function(mapBrowserEvent) { + return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.CLICK; +}; - if (!needsSubdivision && this.maxSourceExtent_) { - if (!ol.extent.intersects(sourceQuadExtent, this.maxSourceExtent_)) { - // whole quad outside source projection extent -> ignore - return; - } - } - if (!needsSubdivision) { - if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) || - !isFinite(bSrc[0]) || !isFinite(bSrc[1]) || - !isFinite(cSrc[0]) || !isFinite(cSrc[1]) || - !isFinite(dSrc[0]) || !isFinite(dSrc[1])) { - if (maxSubdivision > 0) { - needsSubdivision = true; - } else { - return; - } - } - } +/** + * Return always false. + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} False. + * @function + * @api stable + */ +ol.events.condition.never = goog.functions.FALSE; - if (maxSubdivision > 0) { - if (!needsSubdivision) { - var center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2]; - var centerSrc = this.transformInv_(center); - var dx; - if (wrapsX) { - goog.asserts.assert(this.sourceWorldWidth_); - var centerSrcEstimX = - (goog.math.modulo(aSrc[0], this.sourceWorldWidth_) + - goog.math.modulo(cSrc[0], this.sourceWorldWidth_)) / 2; - dx = centerSrcEstimX - - goog.math.modulo(centerSrc[0], this.sourceWorldWidth_); - } else { - dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0]; - } - var dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1]; - var centerSrcErrorSquared = dx * dx + dy * dy; - needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_; - } - if (needsSubdivision) { - if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) { - // split horizontally (top & bottom) - var bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2]; - var bcSrc = this.transformInv_(bc); - var da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2]; - var daSrc = this.transformInv_(da); +/** + * Return `true` if the browser event is a `pointermove` event, `false` + * otherwise. + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if the browser event is a `pointermove` event. + * @api + */ +ol.events.condition.pointerMove = function(mapBrowserEvent) { + return mapBrowserEvent.type == 'pointermove'; +}; - this.addQuad_( - a, b, bc, da, aSrc, bSrc, bcSrc, daSrc, maxSubdivision - 1); - this.addQuad_( - da, bc, c, d, daSrc, bcSrc, cSrc, dSrc, maxSubdivision - 1); - } else { - // split vertically (left & right) - var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]; - var abSrc = this.transformInv_(ab); - var cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2]; - var cdSrc = this.transformInv_(cd); - this.addQuad_( - a, ab, cd, d, aSrc, abSrc, cdSrc, dSrc, maxSubdivision - 1); - this.addQuad_( - ab, b, c, cd, abSrc, bSrc, cSrc, cdSrc, maxSubdivision - 1); - } - return; - } - } +/** + * Return `true` if the event is a map `singleclick` event, `false` otherwise. + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if the event is a map `singleclick` event. + * @api stable + */ +ol.events.condition.singleClick = function(mapBrowserEvent) { + return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK; +}; - if (wrapsX) { - if (!this.canWrapXInSource_) { - return; - } - this.wrapsXInSource_ = true; - } - this.addTriangle_(a, c, d, aSrc, cSrc, dSrc); - this.addTriangle_(a, b, c, aSrc, bSrc, cSrc); +/** + * Return `true` if the event is a map `dblclick` event, `false` otherwise. + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if the event is a map `dblclick` event. + * @api stable + */ +ol.events.condition.doubleClick = function(mapBrowserEvent) { + return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK; }; /** - * Calculates extent of the 'source' coordinates from all the triangles. + * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is + * pressed. * - * @return {ol.Extent} Calculated extent. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True only if there no modifier keys are pressed. + * @api stable */ -ol.reproj.Triangulation.prototype.calculateSourceExtent = function() { - var extent = ol.extent.createEmpty(); +ol.events.condition.noModifierKeys = function(mapBrowserEvent) { + var browserEvent = mapBrowserEvent.browserEvent; + return ( + !browserEvent.altKey && + !browserEvent.platformModifierKey && + !browserEvent.shiftKey); +}; - this.triangles_.forEach(function(triangle, i, arr) { - var src = triangle.source; - ol.extent.extendCoordinate(extent, src[0]); - ol.extent.extendCoordinate(extent, src[1]); - ol.extent.extendCoordinate(extent, src[2]); - }); - return extent; +/** + * Return `true` if only the platform-modifier-key (the meta-key on Mac, + * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally + * the shift-key is pressed). + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if only the platform modifier key is pressed. + * @api stable + */ +ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) { + var browserEvent = mapBrowserEvent.browserEvent; + return ( + !browserEvent.altKey && + browserEvent.platformModifierKey && + !browserEvent.shiftKey); }; /** - * @return {Array.<ol.reproj.Triangle>} Array of the calculated triangles. + * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when + * additionally the alt-key is pressed). + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if only the shift key is pressed. + * @api stable */ -ol.reproj.Triangulation.prototype.getTriangles = function() { - return this.triangles_; +ol.events.condition.shiftKeyOnly = function(mapBrowserEvent) { + var browserEvent = mapBrowserEvent.browserEvent; + return ( + !browserEvent.altKey && + !browserEvent.platformModifierKey && + browserEvent.shiftKey); }; -goog.provide('ol.reproj.Image'); -goog.provide('ol.reproj.ImageFunctionType'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.ImageBase'); -goog.require('ol.ImageState'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.reproj'); -goog.require('ol.reproj.Triangulation'); +/** + * Return `true` if the target element is not editable, i.e. not a `<input>`-, + * `<select>`- or `<textarea>`-element, `false` otherwise. + * + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} True only if the target element is not editable. + * @api + */ +ol.events.condition.targetNotEditable = function(mapBrowserEvent) { + var target = mapBrowserEvent.browserEvent.target; + goog.asserts.assertInstanceof(target, Element, + 'target should be an Element'); + var tagName = target.tagName; + return ( + tagName !== 'INPUT' && + tagName !== 'SELECT' && + tagName !== 'TEXTAREA'); +}; /** - * @typedef {function(ol.Extent, number, number) : ol.ImageBase} + * Return `true` if the event originates from a mouse device. + * + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Map browser event. + * @return {boolean} True if the event originates from a mouse device. + * @api stable */ -ol.reproj.ImageFunctionType; +ol.events.condition.mouseOnly = function(mapBrowserEvent) { + // see http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType + return mapBrowserEvent.pointerEvent.pointerType == 'mouse'; +}; + +goog.provide('ol.interaction.Pointer'); + +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.MapBrowserPointerEvent'); +goog.require('ol.Pixel'); +goog.require('ol.interaction.Interaction'); /** * @classdesc - * Class encapsulating single reprojected image. - * See {@link ol.source.Image}. + * Base class that calls user-defined functions on `down`, `move` and `up` + * events. This class also manages "drag sequences". + * + * When the `handleDownEvent` user function returns `true` a drag sequence is + * started. During a drag sequence the `handleDragEvent` user function is + * called on `move` events. The drag sequence ends when the `handleUpEvent` + * user function is called and returns `false`. * * @constructor - * @extends {ol.ImageBase} - * @param {ol.proj.Projection} sourceProj Source projection (of the data). - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.Extent} targetExtent Target extent. - * @param {number} targetResolution Target resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.reproj.ImageFunctionType} getImageFunction - * Function returning source images (extent, resolution, pixelRatio). + * @param {olx.interaction.PointerOptions=} opt_options Options. + * @extends {ol.interaction.Interaction} + * @api */ -ol.reproj.Image = function(sourceProj, targetProj, - targetExtent, targetResolution, pixelRatio, getImageFunction) { +ol.interaction.Pointer = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + var handleEvent = options.handleEvent ? + options.handleEvent : ol.interaction.Pointer.handleEvent; + + goog.base(this, { + handleEvent: handleEvent + }); /** + * @type {function(ol.MapBrowserPointerEvent):boolean} * @private - * @type {ol.proj.Projection} */ - this.targetProj_ = targetProj; + this.handleDownEvent_ = options.handleDownEvent ? + options.handleDownEvent : ol.interaction.Pointer.handleDownEvent; /** + * @type {function(ol.MapBrowserPointerEvent)} * @private - * @type {ol.Extent} */ - this.maxSourceExtent_ = sourceProj.getExtent(); - var maxTargetExtent = targetProj.getExtent(); - - var limitedTargetExtent = maxTargetExtent ? - ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent; - - var targetCenter = ol.extent.getCenter(limitedTargetExtent); - var sourceResolution = ol.reproj.calculateSourceResolution( - sourceProj, targetProj, targetCenter, targetResolution); - - var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD; + this.handleDragEvent_ = options.handleDragEvent ? + options.handleDragEvent : ol.interaction.Pointer.handleDragEvent; /** + * @type {function(ol.MapBrowserPointerEvent)} * @private - * @type {!ol.reproj.Triangulation} */ - this.triangulation_ = new ol.reproj.Triangulation( - sourceProj, targetProj, limitedTargetExtent, this.maxSourceExtent_, - sourceResolution * errorThresholdInPixels); + this.handleMoveEvent_ = options.handleMoveEvent ? + options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent; /** + * @type {function(ol.MapBrowserPointerEvent):boolean} * @private - * @type {number} - */ - this.targetResolution_ = targetResolution; - - /** - * @private - * @type {ol.Extent} - */ - this.targetExtent_ = targetExtent; - - var sourceExtent = this.triangulation_.calculateSourceExtent(); - - /** - * @private - * @type {ol.ImageBase} */ - this.sourceImage_ = - getImageFunction(sourceExtent, sourceResolution, pixelRatio); + this.handleUpEvent_ = options.handleUpEvent ? + options.handleUpEvent : ol.interaction.Pointer.handleUpEvent; /** - * @private - * @type {number} + * @type {boolean} + * @protected */ - this.sourcePixelRatio_ = - this.sourceImage_ ? this.sourceImage_.getPixelRatio() : 1; + this.handlingDownUpSequence = false; /** + * @type {Object.<number, ol.pointer.PointerEvent>} * @private - * @type {HTMLCanvasElement} */ - this.canvas_ = null; + this.trackedPointers_ = {}; /** - * @private - * @type {goog.events.Key} + * @type {Array.<ol.pointer.PointerEvent>} + * @protected */ - this.sourceListenerKey_ = null; + this.targetPointers = []; +}; +goog.inherits(ol.interaction.Pointer, ol.interaction.Interaction); - var state = ol.ImageState.LOADED; - var attributions = []; - if (this.sourceImage_) { - state = ol.ImageState.IDLE; - attributions = this.sourceImage_.getAttributions(); +/** + * @param {Array.<ol.pointer.PointerEvent>} pointerEvents + * @return {ol.Pixel} Centroid pixel. + */ +ol.interaction.Pointer.centroid = function(pointerEvents) { + var length = pointerEvents.length; + var clientX = 0; + var clientY = 0; + for (var i = 0; i < length; i++) { + clientX += pointerEvents[i].clientX; + clientY += pointerEvents[i].clientY; } + return [clientX / length, clientY / length]; +}; - goog.base(this, targetExtent, targetResolution, this.sourcePixelRatio_, - state, attributions); + +/** + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Whether the event is a pointerdown, pointerdrag + * or pointerup event. + * @private + */ +ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = + function(mapBrowserEvent) { + var type = mapBrowserEvent.type; + return ( + type === ol.MapBrowserEvent.EventType.POINTERDOWN || + type === ol.MapBrowserEvent.EventType.POINTERDRAG || + type === ol.MapBrowserEvent.EventType.POINTERUP); }; -goog.inherits(ol.reproj.Image, ol.ImageBase); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @private */ -ol.reproj.Image.prototype.disposeInternal = function() { - if (this.state == ol.ImageState.LOADING) { - this.unlistenSource_(); +ol.interaction.Pointer.prototype.updateTrackedPointers_ = + function(mapBrowserEvent) { + if (this.isPointerDraggingEvent_(mapBrowserEvent)) { + var event = mapBrowserEvent.pointerEvent; + + if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { + delete this.trackedPointers_[event.pointerId]; + } else if (mapBrowserEvent.type == + ol.MapBrowserEvent.EventType.POINTERDOWN) { + this.trackedPointers_[event.pointerId] = event; + } else if (event.pointerId in this.trackedPointers_) { + // update only when there was a pointerdown event for this pointer + this.trackedPointers_[event.pointerId] = event; + } + this.targetPointers = goog.object.getValues(this.trackedPointers_); } - goog.base(this, 'disposeInternal'); }; /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.Pointer} */ -ol.reproj.Image.prototype.getImage = function(opt_context) { - return this.canvas_; -}; +ol.interaction.Pointer.handleDragEvent = ol.nullFunction; /** - * @return {ol.proj.Projection} Projection. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Capture dragging. + * @this {ol.interaction.Pointer} */ -ol.reproj.Image.prototype.getProjection = function() { - return this.targetProj_; -}; +ol.interaction.Pointer.handleUpEvent = goog.functions.FALSE; /** - * @private + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Capture dragging. + * @this {ol.interaction.Pointer} */ -ol.reproj.Image.prototype.reproject_ = function() { - var sourceState = this.sourceImage_.getState(); - if (sourceState == ol.ImageState.LOADED) { - var width = ol.extent.getWidth(this.targetExtent_) / this.targetResolution_; - var height = - ol.extent.getHeight(this.targetExtent_) / this.targetResolution_; +ol.interaction.Pointer.handleDownEvent = goog.functions.FALSE; - this.canvas_ = ol.reproj.render(width, height, this.sourcePixelRatio_, - this.sourceImage_.getResolution(), this.maxSourceExtent_, - this.targetResolution_, this.targetExtent_, this.triangulation_, [{ - extent: this.sourceImage_.getExtent(), - image: this.sourceImage_.getImage() - }]); - } - this.state = sourceState; - this.changed(); -}; + +/** + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.Pointer} + */ +ol.interaction.Pointer.handleMoveEvent = ol.nullFunction; /** - * @inheritDoc + * Handles the {@link ol.MapBrowserEvent map browser event} and may call into + * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are + * detected. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.Pointer} + * @api */ -ol.reproj.Image.prototype.load = function() { - if (this.state == ol.ImageState.IDLE) { - this.state = ol.ImageState.LOADING; - this.changed(); +ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) { + if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) { + return true; + } - var sourceState = this.sourceImage_.getState(); - if (sourceState == ol.ImageState.LOADED || - sourceState == ol.ImageState.ERROR) { - this.reproject_(); - } else { - this.sourceListenerKey_ = this.sourceImage_.listen( - goog.events.EventType.CHANGE, function(e) { - var sourceState = this.sourceImage_.getState(); - if (sourceState == ol.ImageState.LOADED || - sourceState == ol.ImageState.ERROR) { - this.unlistenSource_(); - this.reproject_(); - } - }, false, this); - this.sourceImage_.load(); + var stopEvent = false; + this.updateTrackedPointers_(mapBrowserEvent); + if (this.handlingDownUpSequence) { + if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDRAG) { + this.handleDragEvent_(mapBrowserEvent); + } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { + this.handlingDownUpSequence = this.handleUpEvent_(mapBrowserEvent); } } + if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { + var handled = this.handleDownEvent_(mapBrowserEvent); + this.handlingDownUpSequence = handled; + stopEvent = this.shouldStopEvent(handled); + } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE) { + this.handleMoveEvent_(mapBrowserEvent); + } + return !stopEvent; }; /** - * @private + * This method is used to determine if "down" events should be propagated to + * other interactions or should be stopped. + * + * The method receives the return code of the "handleDownEvent" function. + * + * By default this function is the "identity" function. It's overidden in + * child classes. + * + * @param {boolean} handled Was the event handled by the interaction? + * @return {boolean} Should the event be stopped? + * @protected */ -ol.reproj.Image.prototype.unlistenSource_ = function() { - goog.asserts.assert(this.sourceListenerKey_, - 'this.sourceListenerKey_ should not be null'); - goog.events.unlistenByKey(this.sourceListenerKey_); - this.sourceListenerKey_ = null; -}; +ol.interaction.Pointer.prototype.shouldStopEvent = goog.functions.identity; -goog.provide('ol.source.Image'); -goog.provide('ol.source.ImageEvent'); +goog.provide('ol.interaction.DragPan'); -goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.events.Event'); -goog.require('ol.Attribution'); -goog.require('ol.ImageState'); -goog.require('ol.array'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.reproj.Image'); -goog.require('ol.source.Source'); - - -/** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * extent: (null|ol.Extent|undefined), - * logo: (string|olx.LogoOptions|undefined), - * projection: ol.proj.ProjectionLike, - * resolutions: (Array.<number>|undefined), - * state: (ol.source.State|undefined)}} - */ -ol.source.ImageOptions; +goog.require('ol.Kinetic'); +goog.require('ol.Pixel'); +goog.require('ol.PreRenderFunction'); +goog.require('ol.ViewHint'); +goog.require('ol.coordinate'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Pointer'); /** * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for sources providing a single image. + * Allows the user to pan the map by dragging the map. * * @constructor - * @extends {ol.source.Source} - * @param {ol.source.ImageOptions} options Single image source options. - * @api + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.DragPanOptions=} opt_options Options. + * @api stable */ -ol.source.Image = function(options) { +ol.interaction.DragPan = function(opt_options) { goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection, - state: options.state + handleDownEvent: ol.interaction.DragPan.handleDownEvent_, + handleDragEvent: ol.interaction.DragPan.handleDragEvent_, + handleUpEvent: ol.interaction.DragPan.handleUpEvent_ }); + var options = opt_options ? opt_options : {}; + /** * @private - * @type {Array.<number>} + * @type {ol.Kinetic|undefined} */ - this.resolutions_ = options.resolutions !== undefined ? - options.resolutions : null; - goog.asserts.assert(!this.resolutions_ || - goog.array.isSorted(this.resolutions_, - function(a, b) { - return b - a; - }, true), 'resolutions must be null or sorted in descending order'); - + this.kinetic_ = options.kinetic; /** * @private - * @type {ol.reproj.Image} + * @type {?ol.PreRenderFunction} */ - this.reprojectedImage_ = null; + this.kineticPreRenderFn_ = null; + /** + * @type {ol.Pixel} + */ + this.lastCentroid = null; /** * @private - * @type {number} + * @type {ol.events.ConditionType} */ - this.reprojectedRevision_ = 0; - -}; -goog.inherits(ol.source.Image, ol.source.Source); + this.condition_ = options.condition ? + options.condition : ol.events.condition.noModifierKeys; + /** + * @private + * @type {boolean} + */ + this.noKinetic_ = false; -/** - * @return {Array.<number>} Resolutions. - */ -ol.source.Image.prototype.getResolutions = function() { - return this.resolutions_; }; +goog.inherits(ol.interaction.DragPan, ol.interaction.Pointer); /** - * @protected - * @param {number} resolution Resolution. - * @return {number} Resolution. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragPan} + * @private */ -ol.source.Image.prototype.findNearestResolution = - function(resolution) { - if (this.resolutions_) { - var idx = ol.array.linearFindNearest(this.resolutions_, resolution, 0); - resolution = this.resolutions_[idx]; +ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) { + goog.asserts.assert(this.targetPointers.length >= 1, + 'the length of this.targetPointers should be more than 1'); + var centroid = + ol.interaction.Pointer.centroid(this.targetPointers); + if (this.kinetic_) { + this.kinetic_.update(centroid[0], centroid[1]); } - return resolution; + if (this.lastCentroid) { + var deltaX = this.lastCentroid[0] - centroid[0]; + var deltaY = centroid[1] - this.lastCentroid[1]; + var map = mapBrowserEvent.map; + var view = map.getView(); + var viewState = view.getState(); + var center = [deltaX, deltaY]; + ol.coordinate.scale(center, viewState.resolution); + ol.coordinate.rotate(center, viewState.rotation); + ol.coordinate.add(center, viewState.center); + center = view.constrainCenter(center); + map.render(); + view.setCenter(center); + } + this.lastCentroid = centroid; }; /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.ImageBase} Single image. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragPan} + * @private */ -ol.source.Image.prototype.getImage = - function(extent, resolution, pixelRatio, projection) { - var sourceProjection = this.getProjection(); - if (!ol.ENABLE_RASTER_REPROJECTION || - !sourceProjection || - !projection || - ol.proj.equivalent(sourceProjection, projection)) { - if (sourceProjection) { - projection = sourceProjection; +ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) { + var map = mapBrowserEvent.map; + var view = map.getView(); + if (this.targetPointers.length === 0) { + if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) { + var distance = this.kinetic_.getDistance(); + var angle = this.kinetic_.getAngle(); + var center = view.getCenter(); + goog.asserts.assert(center !== undefined, 'center should be defined'); + this.kineticPreRenderFn_ = this.kinetic_.pan(center); + map.beforeRender(this.kineticPreRenderFn_); + var centerpx = map.getPixelFromCoordinate(center); + var dest = map.getCoordinateFromPixel([ + centerpx[0] - distance * Math.cos(angle), + centerpx[1] - distance * Math.sin(angle) + ]); + dest = view.constrainCenter(dest); + view.setCenter(dest); } - return this.getImageInternal(extent, resolution, pixelRatio, projection); + view.setHint(ol.ViewHint.INTERACTING, -1); + map.render(); + return false; } else { - if (this.reprojectedImage_) { - if (this.reprojectedRevision_ == this.getRevision() && - ol.proj.equivalent( - this.reprojectedImage_.getProjection(), projection) && - this.reprojectedImage_.getResolution() == resolution && - this.reprojectedImage_.getPixelRatio() == pixelRatio && - ol.extent.equals(this.reprojectedImage_.getExtent(), extent)) { - return this.reprojectedImage_; - } - this.reprojectedImage_.dispose(); - this.reprojectedImage_ = null; - } - - this.reprojectedImage_ = new ol.reproj.Image( - sourceProjection, projection, extent, resolution, pixelRatio, - goog.bind(function(extent, resolution, pixelRatio) { - return this.getImageInternal(extent, resolution, - pixelRatio, sourceProjection); - }, this)); - this.reprojectedRevision_ = this.getRevision(); - - return this.reprojectedImage_; + this.lastCentroid = null; + return true; } }; /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.ImageBase} Single image. - * @protected - */ -ol.source.Image.prototype.getImageInternal = goog.abstractMethod; - - -/** - * Handle image change events. - * @param {goog.events.Event} event Event. - * @protected + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragPan} + * @private */ -ol.source.Image.prototype.handleImageChange = function(event) { - var image = /** @type {ol.Image} */ (event.target); - switch (image.getState()) { - case ol.ImageState.LOADING: - this.dispatchEvent( - new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADSTART, - image)); - break; - case ol.ImageState.LOADED: - this.dispatchEvent( - new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADEND, - image)); - break; - case ol.ImageState.ERROR: - this.dispatchEvent( - new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADERROR, - image)); - break; +ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) { + if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) { + var map = mapBrowserEvent.map; + var view = map.getView(); + this.lastCentroid = null; + if (!this.handlingDownUpSequence) { + view.setHint(ol.ViewHint.INTERACTING, 1); + } + map.render(); + if (this.kineticPreRenderFn_ && + map.removePreRenderFunction(this.kineticPreRenderFn_)) { + view.setCenter(mapBrowserEvent.frameState.viewState.center); + this.kineticPreRenderFn_ = null; + } + if (this.kinetic_) { + this.kinetic_.begin(); + } + // No kinetic as soon as more than one pointer on the screen is + // detected. This is to prevent nasty pans after pinch. + this.noKinetic_ = this.targetPointers.length > 1; + return true; + } else { + return false; } }; /** - * Default image load function for image sources that use ol.Image image - * instances. - * @param {ol.Image} image Image. - * @param {string} src Source. + * @inheritDoc */ -ol.source.Image.defaultImageLoadFunction = function(image, src) { - image.getImage().src = src; -}; +ol.interaction.DragPan.prototype.shouldStopEvent = goog.functions.FALSE; + +goog.provide('ol.interaction.DragRotate'); + +goog.require('ol'); +goog.require('ol.ViewHint'); +goog.require('ol.events.ConditionType'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.interaction.Pointer'); /** * @classdesc - * Events emitted by {@link ol.source.Image} instances are instances of this - * type. + * Allows the user to rotate the map by clicking and dragging on the map, + * normally combined with an {@link ol.events.condition} that limits + * it to when the alt and shift keys are held down. + * + * This interaction is only supported for mouse devices. * * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.ImageEvent} - * @param {string} type Type. - * @param {ol.Image} image The image. + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.DragRotateOptions=} opt_options Options. + * @api stable */ -ol.source.ImageEvent = function(type, image) { +ol.interaction.DragRotate = function(opt_options) { - goog.base(this, type); + var options = opt_options ? opt_options : {}; + + goog.base(this, { + handleDownEvent: ol.interaction.DragRotate.handleDownEvent_, + handleDragEvent: ol.interaction.DragRotate.handleDragEvent_, + handleUpEvent: ol.interaction.DragRotate.handleUpEvent_ + }); /** - * The image related to the event. - * @type {ol.Image} - * @api + * @private + * @type {ol.events.ConditionType} */ - this.image = image; + this.condition_ = options.condition ? + options.condition : ol.events.condition.altShiftKeysOnly; + + /** + * @private + * @type {number|undefined} + */ + this.lastAngle_ = undefined; + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 250; }; -goog.inherits(ol.source.ImageEvent, goog.events.Event); +goog.inherits(ol.interaction.DragRotate, ol.interaction.Pointer); /** - * @enum {string} + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragRotate} + * @private */ -ol.source.ImageEventType = { - - /** - * Triggered when an image starts loading. - * @event ol.source.ImageEvent#imageloadstart - * @api - */ - IMAGELOADSTART: 'imageloadstart', - - /** - * Triggered when an image finishes loading. - * @event ol.source.ImageEvent#imageloadend - * @api - */ - IMAGELOADEND: 'imageloadend', - - /** - * Triggered if image loading results in an error. - * @event ol.source.ImageEvent#imageloaderror - * @api - */ - IMAGELOADERROR: 'imageloaderror' +ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return; + } + var map = mapBrowserEvent.map; + var size = map.getSize(); + var offset = mapBrowserEvent.pixel; + var theta = + Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2); + if (this.lastAngle_ !== undefined) { + var delta = theta - this.lastAngle_; + var view = map.getView(); + var rotation = view.getRotation(); + map.render(); + ol.interaction.Interaction.rotateWithoutConstraints( + map, view, rotation - delta); + } + this.lastAngle_ = theta; }; -goog.provide('ol.source.ImageCanvas'); - -goog.require('ol.CanvasFunctionType'); -goog.require('ol.ImageCanvas'); -goog.require('ol.extent'); -goog.require('ol.source.Image'); - - /** - * @classdesc - * Base class for image sources where a canvas element is the image. - * - * @constructor - * @extends {ol.source.Image} - * @param {olx.source.ImageCanvasOptions} options - * @api + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragRotate} + * @private */ -ol.source.ImageCanvas = function(options) { - - goog.base(this, { - attributions: options.attributions, - logo: options.logo, - projection: options.projection, - resolutions: options.resolutions, - state: options.state !== undefined ? - /** @type {ol.source.State} */ (options.state) : undefined - }); - - /** - * @private - * @type {ol.CanvasFunctionType} - */ - this.canvasFunction_ = options.canvasFunction; - - /** - * @private - * @type {ol.ImageCanvas} - */ - this.canvas_ = null; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; - - /** - * @private - * @type {number} - */ - this.ratio_ = options.ratio !== undefined ? - options.ratio : 1.5; +ol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return true; + } + var map = mapBrowserEvent.map; + var view = map.getView(); + view.setHint(ol.ViewHint.INTERACTING, -1); + var rotation = view.getRotation(); + ol.interaction.Interaction.rotate(map, view, rotation, + undefined, this.duration_); + return false; }; -goog.inherits(ol.source.ImageCanvas, ol.source.Image); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragRotate} + * @private */ -ol.source.ImageCanvas.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - resolution = this.findNearestResolution(resolution); +ol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return false; + } - var canvas = this.canvas_; - if (canvas && - this.renderedRevision_ == this.getRevision() && - canvas.getResolution() == resolution && - canvas.getPixelRatio() == pixelRatio && - ol.extent.containsExtent(canvas.getExtent(), extent)) { - return canvas; + var browserEvent = mapBrowserEvent.browserEvent; + if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) { + var map = mapBrowserEvent.map; + map.getView().setHint(ol.ViewHint.INTERACTING, 1); + map.render(); + this.lastAngle_ = undefined; + return true; + } else { + return false; } +}; - extent = extent.slice(); - ol.extent.scaleFromCenter(extent, this.ratio_); - var width = ol.extent.getWidth(extent) / resolution; - var height = ol.extent.getHeight(extent) / resolution; - var size = [width * pixelRatio, height * pixelRatio]; - var canvasElement = this.canvasFunction_( - extent, resolution, pixelRatio, size, projection); - if (canvasElement) { - canvas = new ol.ImageCanvas(extent, resolution, pixelRatio, - this.getAttributions(), canvasElement); - } - this.canvas_ = canvas; - this.renderedRevision_ = this.getRevision(); +/** + * @inheritDoc + */ +ol.interaction.DragRotate.prototype.shouldStopEvent = goog.functions.FALSE; - return canvas; -}; +// FIXME add rotation -goog.provide('ol.Feature'); -goog.provide('ol.FeatureStyleFunction'); +goog.provide('ol.render.Box'); +goog.require('goog.Disposable'); goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.geom.Geometry'); -goog.require('ol.style.Style'); +goog.require('ol.geom.Polygon'); /** - * @classdesc - * A vector object for geographic features with a geometry and other - * attribute properties, similar to the features in vector file formats like - * GeoJSON. - * - * Features can be styled individually with `setStyle`; otherwise they use the - * style of their vector layer. - * - * Note that attribute properties are set as {@link ol.Object} properties on - * the feature object, so they are observable, and have get/set accessors. - * - * Typically, a feature has a single geometry property. You can set the - * geometry using the `setGeometry` method and get it with `getGeometry`. - * It is possible to store more than one geometry on a feature using attribute - * properties. By default, the geometry used for rendering is identified by - * the property name `geometry`. If you want to use another geometry property - * for rendering, use the `setGeometryName` method to change the attribute - * property associated with the geometry for the feature. For example: - * - * ```js - * var feature = new ol.Feature({ - * geometry: new ol.geom.Polygon(polyCoords), - * labelPoint: new ol.geom.Point(labelCoords), - * name: 'My Polygon' - * }); - * - * // get the polygon geometry - * var poly = feature.getGeometry(); - * - * // Render the feature as a point using the coordinates from labelPoint - * feature.setGeometryName('labelPoint'); - * - * // get the point geometry - * var point = feature.getGeometry(); - * ``` - * * @constructor - * @extends {ol.Object} - * @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties - * You may pass a Geometry object directly, or an object literal - * containing properties. If you pass an object literal, you may - * include a Geometry associated with a `geometry` key. - * @api stable + * @extends {goog.Disposable} + * @param {string} className CSS class name. */ -ol.Feature = function(opt_geometryOrProperties) { - - goog.base(this); +ol.render.Box = function(className) { /** + * @type {ol.geom.Polygon} * @private - * @type {number|string|undefined} */ - this.id_ = undefined; + this.geometry_ = null; /** - * @type {string} + * @type {HTMLDivElement} * @private */ - this.geometryName_ = 'geometry'; + this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div')); + this.element_.style.position = 'absolute'; + this.element_.className = 'ol-box ' + className; /** - * User provided style. * @private - * @type {ol.style.Style|Array.<ol.style.Style>| - * ol.FeatureStyleFunction} + * @type {ol.Map} */ - this.style_ = null; + this.map_ = null; /** * @private - * @type {ol.FeatureStyleFunction|undefined} + * @type {ol.Pixel} */ - this.styleFunction_ = undefined; + this.startPixel_ = null; /** * @private - * @type {goog.events.Key} + * @type {ol.Pixel} */ - this.geometryChangeKey_ = null; - - goog.events.listen( - this, ol.Object.getChangeEventType(this.geometryName_), - this.handleGeometryChanged_, false, this); + this.endPixel_ = null; - if (opt_geometryOrProperties !== undefined) { - if (opt_geometryOrProperties instanceof ol.geom.Geometry || - !opt_geometryOrProperties) { - var geometry = /** @type {ol.geom.Geometry} */ (opt_geometryOrProperties); - this.setGeometry(geometry); - } else { - goog.asserts.assert(goog.isObject(opt_geometryOrProperties), - 'opt_geometryOrProperties should be an Object'); - var properties = /** @type {Object.<string, *>} */ - (opt_geometryOrProperties); - this.setProperties(properties); - } - } }; -goog.inherits(ol.Feature, ol.Object); +goog.inherits(ol.render.Box, goog.Disposable); /** - * Clone this feature. If the original feature has a geometry it - * is also cloned. The feature id is not set in the clone. - * @return {ol.Feature} The clone. - * @api stable + * @inheritDoc */ -ol.Feature.prototype.clone = function() { - var clone = new ol.Feature(this.getProperties()); - clone.setGeometryName(this.getGeometryName()); - var geometry = this.getGeometry(); - if (geometry) { - clone.setGeometry(geometry.clone()); - } - var style = this.getStyle(); - if (style) { - clone.setStyle(style); - } - return clone; +ol.render.Box.prototype.disposeInternal = function() { + this.setMap(null); + goog.base(this, 'disposeInternal'); }; /** - * Get the feature's default geometry. A feature may have any number of named - * geometries. The "default" geometry (the one that is rendered by default) is - * set when calling {@link ol.Feature#setGeometry}. - * @return {ol.geom.Geometry|undefined} The default geometry for the feature. - * @api stable - * @observable + * @private */ -ol.Feature.prototype.getGeometry = function() { - return /** @type {ol.geom.Geometry|undefined} */ ( - this.get(this.geometryName_)); +ol.render.Box.prototype.render_ = function() { + var startPixel = this.startPixel_; + var endPixel = this.endPixel_; + goog.asserts.assert(startPixel, 'this.startPixel_ must be truthy'); + goog.asserts.assert(endPixel, 'this.endPixel_ must be truthy'); + var px = 'px'; + var style = this.element_.style; + style.left = Math.min(startPixel[0], endPixel[0]) + px; + style.top = Math.min(startPixel[1], endPixel[1]) + px; + style.width = Math.abs(endPixel[0] - startPixel[0]) + px; + style.height = Math.abs(endPixel[1] - startPixel[1]) + px; }; /** - * Get the feature identifier. This is a stable identifier for the feature and - * is either set when reading data from a remote source or set explicitly by - * calling {@link ol.Feature#setId}. - * @return {number|string|undefined} Id. - * @api stable - * @observable + * @param {ol.Map} map Map. */ -ol.Feature.prototype.getId = function() { - return this.id_; +ol.render.Box.prototype.setMap = function(map) { + if (this.map_) { + this.map_.getOverlayContainer().removeChild(this.element_); + var style = this.element_.style; + style.left = style.top = style.width = style.height = 'inherit'; + } + this.map_ = map; + if (this.map_) { + this.map_.getOverlayContainer().appendChild(this.element_); + } }; /** - * Get the name of the feature's default geometry. By default, the default - * geometry is named `geometry`. - * @return {string} Get the property name associated with the default geometry - * for this feature. - * @api stable + * @param {ol.Pixel} startPixel Start pixel. + * @param {ol.Pixel} endPixel End pixel. */ -ol.Feature.prototype.getGeometryName = function() { - return this.geometryName_; +ol.render.Box.prototype.setPixels = function(startPixel, endPixel) { + this.startPixel_ = startPixel; + this.endPixel_ = endPixel; + this.createOrUpdateGeometry(); + this.render_(); }; /** - * Get the feature's style. This return for this method depends on what was - * provided to the {@link ol.Feature#setStyle} method. - * @return {ol.style.Style|Array.<ol.style.Style>| - * ol.FeatureStyleFunction} The feature style. - * @api stable - * @observable + * Creates or updates the cached geometry. */ -ol.Feature.prototype.getStyle = function() { - return this.style_; +ol.render.Box.prototype.createOrUpdateGeometry = function() { + goog.asserts.assert(this.startPixel_, + 'this.startPixel_ must be truthy'); + goog.asserts.assert(this.endPixel_, + 'this.endPixel_ must be truthy'); + goog.asserts.assert(this.map_, 'this.map_ must be truthy'); + var startPixel = this.startPixel_; + var endPixel = this.endPixel_; + var pixels = [ + startPixel, + [startPixel[0], endPixel[1]], + endPixel, + [endPixel[0], startPixel[1]] + ]; + var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_); + // close the polygon + coordinates[4] = coordinates[0].slice(); + if (!this.geometry_) { + this.geometry_ = new ol.geom.Polygon([coordinates]); + } else { + this.geometry_.setCoordinates([coordinates]); + } }; /** - * Get the feature's style function. - * @return {ol.FeatureStyleFunction|undefined} Return a function - * representing the current style of this feature. - * @api stable + * @return {ol.geom.Polygon} Geometry. */ -ol.Feature.prototype.getStyleFunction = function() { - return this.styleFunction_; +ol.render.Box.prototype.getGeometry = function() { + return this.geometry_; }; +// FIXME draw drag box +goog.provide('ol.DragBoxEvent'); +goog.provide('ol.interaction.DragBox'); -/** - * @private - */ -ol.Feature.prototype.handleGeometryChange_ = function() { - this.changed(); -}; +goog.require('goog.events.Event'); +goog.require('ol'); +goog.require('ol.events.ConditionType'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Pointer'); +goog.require('ol.render.Box'); /** - * @private + * @const + * @type {number} */ -ol.Feature.prototype.handleGeometryChanged_ = function() { - if (this.geometryChangeKey_) { - goog.events.unlistenByKey(this.geometryChangeKey_); - this.geometryChangeKey_ = null; - } - var geometry = this.getGeometry(); - if (geometry) { - this.geometryChangeKey_ = goog.events.listen(geometry, - goog.events.EventType.CHANGE, this.handleGeometryChange_, false, this); - } - this.changed(); -}; +ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED = + ol.DRAG_BOX_HYSTERESIS_PIXELS * + ol.DRAG_BOX_HYSTERESIS_PIXELS; /** - * Set the default geometry for the feature. This will update the property - * with the name returned by {@link ol.Feature#getGeometryName}. - * @param {ol.geom.Geometry|undefined} geometry The new geometry. - * @api stable - * @observable + * @enum {string} */ -ol.Feature.prototype.setGeometry = function(geometry) { - this.set(this.geometryName_, geometry); +ol.DragBoxEventType = { + /** + * Triggered upon drag box start. + * @event ol.DragBoxEvent#boxstart + * @api stable + */ + BOXSTART: 'boxstart', + /** + * Triggered upon drag box end. + * @event ol.DragBoxEvent#boxend + * @api stable + */ + BOXEND: 'boxend' }; -/** - * Set the style for the feature. This can be a single style object, an array - * of styles, or a function that takes a resolution and returns an array of - * styles. If it is `null` the feature has no style (a `null` style). - * @param {ol.style.Style|Array.<ol.style.Style>| - * ol.FeatureStyleFunction} style Style for this feature. - * @api stable - * @observable - */ -ol.Feature.prototype.setStyle = function(style) { - this.style_ = style; - this.styleFunction_ = !style ? - undefined : ol.Feature.createStyleFunction(style); - this.changed(); -}; - /** - * Set the feature id. The feature id is considered stable and may be used when - * requesting features or comparing identifiers returned from a remote source. - * The feature id can be used with the {@link ol.source.Vector#getFeatureById} - * method. - * @param {number|string|undefined} id The feature id. - * @api stable - * @observable + * @classdesc + * Events emitted by {@link ol.interaction.DragBox} instances are instances of + * this type. + * + * @param {string} type The event type. + * @param {ol.Coordinate} coordinate The event coordinate. + * @extends {goog.events.Event} + * @constructor + * @implements {oli.DragBoxEvent} */ -ol.Feature.prototype.setId = function(id) { - this.id_ = id; - this.changed(); -}; +ol.DragBoxEvent = function(type, coordinate) { + goog.base(this, type); + /** + * The coordinate of the drag event. + * @const + * @type {ol.Coordinate} + * @api stable + */ + this.coordinate = coordinate; -/** - * Set the property name to be used when getting the feature's default geometry. - * When calling {@link ol.Feature#getGeometry}, the value of the property with - * this name will be returned. - * @param {string} name The property name of the default geometry. - * @api stable - */ -ol.Feature.prototype.setGeometryName = function(name) { - goog.events.unlisten( - this, ol.Object.getChangeEventType(this.geometryName_), - this.handleGeometryChanged_, false, this); - this.geometryName_ = name; - goog.events.listen( - this, ol.Object.getChangeEventType(this.geometryName_), - this.handleGeometryChanged_, false, this); - this.handleGeometryChanged_(); }; +goog.inherits(ol.DragBoxEvent, goog.events.Event); + /** - * A function that returns an array of {@link ol.style.Style styles} given a - * resolution. The `this` keyword inside the function references the - * {@link ol.Feature} to be styled. + * @classdesc + * Allows the user to draw a vector box by clicking and dragging on the map, + * normally combined with an {@link ol.events.condition} that limits + * it to when the shift or other key is held down. This is used, for example, + * for zooming to a specific area of the map + * (see {@link ol.interaction.DragZoom} and + * {@link ol.interaction.DragRotateAndZoom}). * - * @typedef {function(this: ol.Feature, number): - * (ol.style.Style|Array.<ol.style.Style>)} + * This interaction is only supported for mouse devices. + * + * @constructor + * @extends {ol.interaction.Pointer} + * @fires ol.DragBoxEvent + * @param {olx.interaction.DragBoxOptions=} opt_options Options. * @api stable */ -ol.FeatureStyleFunction; +ol.interaction.DragBox = function(opt_options) { + goog.base(this, { + handleDownEvent: ol.interaction.DragBox.handleDownEvent_, + handleDragEvent: ol.interaction.DragBox.handleDragEvent_, + handleUpEvent: ol.interaction.DragBox.handleUpEvent_ + }); -/** - * Convert the provided object into a feature style function. Functions passed - * through unchanged. Arrays of ol.style.Style or single style objects wrapped - * in a new feature style function. - * @param {ol.FeatureStyleFunction|!Array.<ol.style.Style>|!ol.style.Style} obj - * A feature style function, a single style, or an array of styles. - * @return {ol.FeatureStyleFunction} A style function. - */ -ol.Feature.createStyleFunction = function(obj) { - var styleFunction; - - if (goog.isFunction(obj)) { - styleFunction = obj; - } else { - /** - * @type {Array.<ol.style.Style>} - */ - var styles; - if (goog.isArray(obj)) { - styles = obj; - } else { - goog.asserts.assertInstanceof(obj, ol.style.Style, - 'obj should be an ol.style.Style'); - styles = [obj]; - } - styleFunction = function() { - return styles; - }; - } - return styleFunction; -}; + var options = opt_options ? opt_options : {}; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + /** + * @type {ol.render.Box} + * @private + */ + this.box_ = new ol.render.Box(options.className || 'ol-dragbox'); -/** - * @fileoverview Common events for the network classes. - */ + /** + * @type {ol.Pixel} + * @private + */ + this.startPixel_ = null; + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = options.condition ? + options.condition : ol.events.condition.always; -goog.provide('goog.net.EventType'); +}; +goog.inherits(ol.interaction.DragBox, ol.interaction.Pointer); /** - * Event names for network events - * @enum {string} + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragBox} + * @private */ -goog.net.EventType = { - COMPLETE: 'complete', - SUCCESS: 'success', - ERROR: 'error', - ABORT: 'abort', - READY: 'ready', - READY_STATE_CHANGE: 'readystatechange', - TIMEOUT: 'timeout', - INCREMENTAL_DATA: 'incrementaldata', - PROGRESS: 'progress' -}; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.Thenable'); +ol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return; + } + this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel); +}; /** - * Provides a more strict interface for Thenables in terms of - * http://promisesaplus.com for interop with {@see goog.Promise}. - * - * @interface - * @extends {IThenable<TYPE>} - * @template TYPE + * Returns geometry of last drawn box. + * @return {ol.geom.Polygon} Geometry. + * @api stable */ -goog.Thenable = function() {}; +ol.interaction.DragBox.prototype.getGeometry = function() { + return this.box_.getGeometry(); +}; /** - * Adds callbacks that will operate on the result of the Thenable, returning a - * new child Promise. - * - * If the Thenable is fulfilled, the {@code onFulfilled} callback will be - * invoked with the fulfillment value as argument, and the child Promise will - * be fulfilled with the return value of the callback. If the callback throws - * an exception, the child Promise will be rejected with the thrown value - * instead. - * - * If the Thenable is rejected, the {@code onRejected} callback will be invoked - * with the rejection reason as argument, and the child Promise will be rejected - * with the return value of the callback or thrown value. - * - * @param {?(function(this:THIS, TYPE): VALUE)=} opt_onFulfilled A - * function that will be invoked with the fulfillment value if the Promise - * is fullfilled. - * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will - * be invoked with the rejection reason if the Promise is rejected. - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * with the default this. - * - * @return {RESULT} A new Promise that will receive the result - * of the fulfillment or rejection callback. - * @template VALUE - * @template THIS - * - * When a Promise (or thenable) is returned from the fulfilled callback, - * the result is the payload of that promise, not the promise itself. - * - * @template RESULT := type('goog.Promise', - * cond(isUnknown(VALUE), unknown(), - * mapunion(VALUE, (V) => - * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), - * templateTypeOf(V, 0), - * cond(sub(V, 'Thenable'), - * unknown(), - * V))))) - * =: - * + * To be overriden by child classes. + * FIXME: use constructor option instead of relying on overridding. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @protected */ -goog.Thenable.prototype.then = function(opt_onFulfilled, opt_onRejected, - opt_context) {}; +ol.interaction.DragBox.prototype.onBoxEnd = ol.nullFunction; /** - * An expando property to indicate that an object implements - * {@code goog.Thenable}. - * - * {@see addImplementation}. - * - * @const + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragBox} + * @private */ -goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable'; +ol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return true; + } + this.box_.setMap(null); -/** - * Marks a given class (constructor) as an implementation of Thenable, so - * that we can query that fact at runtime. The class must have already - * implemented the interface. - * Exports a 'then' method on the constructor prototype, so that the objects - * also implement the extern {@see goog.Thenable} interface for interop with - * other Promise implementations. - * @param {function(new:goog.Thenable,...?)} ctor The class constructor. The - * corresponding class must have already implemented the interface. - */ -goog.Thenable.addImplementation = function(ctor) { - goog.exportProperty(ctor.prototype, 'then', ctor.prototype.then); - if (COMPILED) { - ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true; - } else { - // Avoids dictionary access in uncompiled mode. - ctor.prototype.$goog_Thenable = true; + var deltaX = mapBrowserEvent.pixel[0] - this.startPixel_[0]; + var deltaY = mapBrowserEvent.pixel[1] - this.startPixel_[1]; + + if (deltaX * deltaX + deltaY * deltaY >= + ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED) { + this.onBoxEnd(mapBrowserEvent); + this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXEND, + mapBrowserEvent.coordinate)); } + return false; }; /** - * @param {*} object - * @return {boolean} Whether a given instance implements {@code goog.Thenable}. - * The class/superclass of the instance must call {@code addImplementation}. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragBox} + * @private */ -goog.Thenable.isImplementedBy = function(object) { - if (!object) { +ol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return false; } - try { - if (COMPILED) { - return !!object[goog.Thenable.IMPLEMENTED_BY_PROP]; - } - return !!object.$goog_Thenable; - } catch (e) { - // Property access seems to be forbidden. + + var browserEvent = mapBrowserEvent.browserEvent; + if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) { + this.startPixel_ = mapBrowserEvent.pixel; + this.box_.setMap(mapBrowserEvent.map); + this.box_.setPixels(this.startPixel_, this.startPixel_); + this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXSTART, + mapBrowserEvent.coordinate)); + return true; + } else { return false; } }; -// Copyright 2015 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.provide('ol.interaction.DragZoom'); -/** - * @fileoverview Simple freelist. - * - * An anterative to goog.structs.SimplePool, it imposes the requirement that the - * objects in the list contain a "next" property that can be used to maintain - * the pool. - */ +goog.require('goog.asserts'); +goog.require('ol.animation'); +goog.require('ol.easing'); +goog.require('ol.events.condition'); +goog.require('ol.extent'); +goog.require('ol.interaction.DragBox'); -goog.provide('goog.async.FreeList'); /** - * @template ITEM + * @classdesc + * Allows the user to zoom the map by clicking and dragging on the map, + * normally combined with an {@link ol.events.condition} that limits + * it to when a key, shift by default, is held down. + * + * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or + * your custom one configured with `className`. + * + * @constructor + * @extends {ol.interaction.DragBox} + * @param {olx.interaction.DragZoomOptions=} opt_options Options. + * @api stable */ -goog.async.FreeList = goog.defineClass(null, { - /** - * @param {function():ITEM} create - * @param {function(ITEM):void} reset - * @param {number} limit - */ - constructor: function(create, reset, limit) { - /** @const {number} */ - this.limit_ = limit; - /** @const {function()} */ - this.create_ = create; - /** @const {function(ITEM):void} */ - this.reset_ = reset; - - /** @type {number} */ - this.occupants_ = 0; - /** @type {ITEM} */ - this.head_ = null; - }, +ol.interaction.DragZoom = function(opt_options) { + var options = opt_options ? opt_options : {}; - /** - * @return {ITEM} - */ - get: function() { - var item; - if (this.occupants_ > 0) { - this.occupants_--; - item = this.head_; - this.head_ = item.next; - item.next = null; - } else { - item = this.create_(); - } - return item; - }, + var condition = options.condition ? + options.condition : ol.events.condition.shiftKeyOnly; /** - * @param {ITEM} item An item available for possible future reuse. + * @private + * @type {number} */ - put: function(item) { - this.reset_(item); - if (this.occupants_ < this.limit_) { - this.occupants_++; - item.next = this.head_; - this.head_ = item; - } - }, + this.duration_ = options.duration !== undefined ? options.duration : 200; - /** - * Visible for testing. - * @package - * @return {number} - */ - occupants: function() { - return this.occupants_; - } -}); + goog.base(this, { + condition: condition, + className: options.className || 'ol-dragzoom' + }); +}; +goog.inherits(ol.interaction.DragZoom, ol.interaction.DragBox); +/** + * @inheritDoc + */ +ol.interaction.DragZoom.prototype.onBoxEnd = function() { + var map = this.getMap(); -// Copyright 2015 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + var view = map.getView(); + goog.asserts.assert(view, 'map must have view'); -goog.provide('goog.async.WorkItem'); -goog.provide('goog.async.WorkQueue'); + var size = map.getSize(); + goog.asserts.assert(size !== undefined, 'size should be defined'); -goog.require('goog.asserts'); -goog.require('goog.async.FreeList'); + var extent = this.getGeometry().getExtent(); + var resolution = view.constrainResolution( + view.getResolutionForExtent(extent, size)); -// TODO(johnlenz): generalize the WorkQueue if this is used by more -// than goog.async.run. + var currentResolution = view.getResolution(); + goog.asserts.assert(currentResolution !== undefined, 'res should be defined'); + var currentCenter = view.getCenter(); + goog.asserts.assert(currentCenter !== undefined, 'center should be defined'); + map.beforeRender(ol.animation.zoom({ + resolution: currentResolution, + duration: this.duration_, + easing: ol.easing.easeOut + })); + map.beforeRender(ol.animation.pan({ + source: currentCenter, + duration: this.duration_, + easing: ol.easing.easeOut + })); -/** - * A low GC workqueue. The key elements of this design: - * - avoids the need for goog.bind or equivalent by carrying scope - * - avoids the need for array reallocation by using a linked list - * - minimizes work entry objects allocation by recycling objects - * @constructor - * @final - * @struct - */ -goog.async.WorkQueue = function() { - this.workHead_ = null; - this.workTail_ = null; + view.setCenter(ol.extent.getCenter(extent)); + view.setResolution(resolution); }; +goog.provide('ol.interaction.KeyboardPan'); -/** @define {number} The maximum number of entries to keep for recycling. */ -goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100); - +goog.require('goog.asserts'); +goog.require('goog.events.KeyCodes'); +goog.require('goog.events.KeyHandler.EventType'); +goog.require('goog.functions'); +goog.require('ol'); +goog.require('ol.coordinate'); +goog.require('ol.events.ConditionType'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Interaction'); -/** @const @private {goog.async.FreeList<goog.async.WorkItem>} */ -goog.async.WorkQueue.freelist_ = new goog.async.FreeList( - function() {return new goog.async.WorkItem(); }, - function(item) {item.reset()}, - goog.async.WorkQueue.DEFAULT_MAX_UNUSED); /** - * @param {function()} fn - * @param {Object|null|undefined} scope + * @classdesc + * Allows the user to pan the map using keyboard arrows. + * Note that, although this interaction is by default included in maps, + * the keys can only be used when browser focus is on the element to which + * the keyboard events are attached. By default, this is the map div, + * though you can change this with the `keyboardEventTarget` in + * {@link ol.Map}. `document` never loses focus but, for any other element, + * focus will have to be on, and returned to, this element if the keys are to + * function. + * See also {@link ol.interaction.KeyboardZoom}. + * + * @constructor + * @extends {ol.interaction.Interaction} + * @param {olx.interaction.KeyboardPanOptions=} opt_options Options. + * @api stable */ -goog.async.WorkQueue.prototype.add = function(fn, scope) { - var item = this.getUnusedItem_(); - item.set(fn, scope); +ol.interaction.KeyboardPan = function(opt_options) { - if (this.workTail_) { - this.workTail_.next = item; - this.workTail_ = item; - } else { - goog.asserts.assert(!this.workHead_); - this.workHead_ = item; - this.workTail_ = item; - } -}; + goog.base(this, { + handleEvent: ol.interaction.KeyboardPan.handleEvent + }); + var options = opt_options || {}; -/** - * @return {goog.async.WorkItem} - */ -goog.async.WorkQueue.prototype.remove = function() { - var item = null; + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = options.condition !== undefined ? + options.condition : + goog.functions.and(ol.events.condition.noModifierKeys, + ol.events.condition.targetNotEditable); - if (this.workHead_) { - item = this.workHead_; - this.workHead_ = this.workHead_.next; - if (!this.workHead_) { - this.workTail_ = null; - } - item.next = null; - } - return item; -}; + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 100; + /** + * @private + * @type {number} + */ + this.pixelDelta_ = options.pixelDelta !== undefined ? + options.pixelDelta : 128; -/** - * @param {goog.async.WorkItem} item - */ -goog.async.WorkQueue.prototype.returnUnused = function(item) { - goog.async.WorkQueue.freelist_.put(item); }; +goog.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction); /** - * @return {goog.async.WorkItem} - * @private + * Handles the {@link ol.MapBrowserEvent map browser event} if it was a + * `KeyEvent`, and decides the direction to pan to (if an arrow key was + * pressed). + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.KeyboardPan} + * @api */ -goog.async.WorkQueue.prototype.getUnusedItem_ = function() { - return goog.async.WorkQueue.freelist_.get(); -}; - - - -/** - * @constructor - * @final - * @struct - */ -goog.async.WorkItem = function() { - /** @type {?function()} */ - this.fn = null; - /** @type {Object|null|undefined} */ - this.scope = null; - /** @type {?goog.async.WorkItem} */ - this.next = null; +ol.interaction.KeyboardPan.handleEvent = function(mapBrowserEvent) { + var stopEvent = false; + if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) { + var keyEvent = /** @type {goog.events.KeyEvent} */ + (mapBrowserEvent.browserEvent); + var keyCode = keyEvent.keyCode; + if (this.condition_(mapBrowserEvent) && + (keyCode == goog.events.KeyCodes.DOWN || + keyCode == goog.events.KeyCodes.LEFT || + keyCode == goog.events.KeyCodes.RIGHT || + keyCode == goog.events.KeyCodes.UP)) { + var map = mapBrowserEvent.map; + var view = map.getView(); + goog.asserts.assert(view, 'map must have view'); + var mapUnitsDelta = view.getResolution() * this.pixelDelta_; + var deltaX = 0, deltaY = 0; + if (keyCode == goog.events.KeyCodes.DOWN) { + deltaY = -mapUnitsDelta; + } else if (keyCode == goog.events.KeyCodes.LEFT) { + deltaX = -mapUnitsDelta; + } else if (keyCode == goog.events.KeyCodes.RIGHT) { + deltaX = mapUnitsDelta; + } else { + deltaY = mapUnitsDelta; + } + var delta = [deltaX, deltaY]; + ol.coordinate.rotate(delta, view.getRotation()); + ol.interaction.Interaction.pan(map, view, delta, this.duration_); + mapBrowserEvent.preventDefault(); + stopEvent = true; + } + } + return !stopEvent; }; +goog.provide('ol.interaction.KeyboardZoom'); -/** - * @param {function()} fn - * @param {Object|null|undefined} scope - */ -goog.async.WorkItem.prototype.set = function(fn, scope) { - this.fn = fn; - this.scope = scope; - this.next = null; -}; - +goog.require('goog.asserts'); +goog.require('goog.events.KeyHandler.EventType'); +goog.require('ol.events.ConditionType'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Interaction'); -/** Reset the work item so they don't prevent GC before reuse */ -goog.async.WorkItem.prototype.reset = function() { - this.fn = null; - this.scope = null; - this.next = null; -}; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Simple notifiers for the Closure testing framework. + * @classdesc + * Allows the user to zoom the map using keyboard + and -. + * Note that, although this interaction is by default included in maps, + * the keys can only be used when browser focus is on the element to which + * the keyboard events are attached. By default, this is the map div, + * though you can change this with the `keyboardEventTarget` in + * {@link ol.Map}. `document` never loses focus but, for any other element, + * focus will have to be on, and returned to, this element if the keys are to + * function. + * See also {@link ol.interaction.KeyboardPan}. * - * @author johnlenz@google.com (John Lenz) + * @constructor + * @param {olx.interaction.KeyboardZoomOptions=} opt_options Options. + * @extends {ol.interaction.Interaction} + * @api stable */ +ol.interaction.KeyboardZoom = function(opt_options) { -goog.provide('goog.testing.watchers'); - + goog.base(this, { + handleEvent: ol.interaction.KeyboardZoom.handleEvent + }); -/** @private {!Array<function()>} */ -goog.testing.watchers.resetWatchers_ = []; + var options = opt_options ? opt_options : {}; + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = options.condition ? options.condition : + ol.events.condition.targetNotEditable; -/** - * Fires clock reset watching functions. - */ -goog.testing.watchers.signalClockReset = function() { - var watchers = goog.testing.watchers.resetWatchers_; - for (var i = 0; i < watchers.length; i++) { - goog.testing.watchers.resetWatchers_[i](); - } -}; + /** + * @private + * @type {number} + */ + this.delta_ = options.delta ? options.delta : 1; + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 100; -/** - * Enqueues a function to be called when the clock used for setTimeout is reset. - * @param {function()} fn - */ -goog.testing.watchers.watchClockReset = function(fn) { - goog.testing.watchers.resetWatchers_.push(fn); }; - - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -goog.provide('goog.async.run'); - -goog.require('goog.async.WorkQueue'); -goog.require('goog.async.nextTick'); -goog.require('goog.async.throwException'); -goog.require('goog.testing.watchers'); +goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction); /** - * Fires the provided callback just before the current callstack unwinds, or as - * soon as possible after the current JS execution context. - * @param {function(this:THIS)} callback - * @param {THIS=} opt_context Object to use as the "this value" when calling - * the provided function. - * @template THIS + * Handles the {@link ol.MapBrowserEvent map browser event} if it was a + * `KeyEvent`, and decides whether to zoom in or out (depending on whether the + * key pressed was '+' or '-'). + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.KeyboardZoom} + * @api */ -goog.async.run = function(callback, opt_context) { - if (!goog.async.run.schedule_) { - goog.async.run.initializeRunner_(); - } - if (!goog.async.run.workQueueScheduled_) { - // Nothing is currently scheduled, schedule it now. - goog.async.run.schedule_(); - goog.async.run.workQueueScheduled_ = true; +ol.interaction.KeyboardZoom.handleEvent = function(mapBrowserEvent) { + var stopEvent = false; + if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) { + var keyEvent = /** @type {goog.events.KeyEvent} */ + (mapBrowserEvent.browserEvent); + var charCode = keyEvent.charCode; + if (this.condition_(mapBrowserEvent) && + (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) { + var map = mapBrowserEvent.map; + var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_; + map.render(); + var view = map.getView(); + goog.asserts.assert(view, 'map must have view'); + ol.interaction.Interaction.zoomByDelta( + map, view, delta, undefined, this.duration_); + mapBrowserEvent.preventDefault(); + stopEvent = true; + } } - - goog.async.run.workQueue_.add(callback, opt_context); + return !stopEvent; }; +goog.provide('ol.interaction.MouseWheelZoom'); + +goog.require('goog.asserts'); +goog.require('goog.events.MouseWheelEvent'); +goog.require('goog.events.MouseWheelHandler.EventType'); +goog.require('ol'); +goog.require('ol.Coordinate'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.math'); -/** - * Initializes the function to use to process the work queue. - * @private - */ -goog.async.run.initializeRunner_ = function() { - // If native Promises are available in the browser, just schedule the callback - // on a fulfilled promise, which is specified to be async, but as fast as - // possible. - if (goog.global.Promise && goog.global.Promise.resolve) { - var promise = goog.global.Promise.resolve(undefined); - goog.async.run.schedule_ = function() { - promise.then(goog.async.run.processWorkQueue); - }; - } else { - goog.async.run.schedule_ = function() { - goog.async.nextTick(goog.async.run.processWorkQueue); - }; - } -}; /** - * Forces goog.async.run to use nextTick instead of Promise. - * - * This should only be done in unit tests. It's useful because MockClock - * replaces nextTick, but not the browser Promise implementation, so it allows - * Promise-based code to be tested with MockClock. - * - * However, we also want to run promises if the MockClock is no longer in - * control so we schedule a backup "setTimeout" to the unmocked timeout if - * provided. + * @classdesc + * Allows the user to zoom the map by scrolling the mouse wheel. * - * @param {function(function())=} opt_realSetTimeout + * @constructor + * @extends {ol.interaction.Interaction} + * @param {olx.interaction.MouseWheelZoomOptions=} opt_options Options. + * @api stable */ -goog.async.run.forceNextTick = function(opt_realSetTimeout) { - goog.async.run.schedule_ = function() { - goog.async.nextTick(goog.async.run.processWorkQueue); - if (opt_realSetTimeout) { - opt_realSetTimeout(goog.async.run.processWorkQueue); - } - }; -}; +ol.interaction.MouseWheelZoom = function(opt_options) { + goog.base(this, { + handleEvent: ol.interaction.MouseWheelZoom.handleEvent + }); -/** - * The function used to schedule work asynchronousely. - * @private {function()} - */ -goog.async.run.schedule_; + var options = opt_options || {}; + /** + * @private + * @type {number} + */ + this.delta_ = 0; -/** @private {boolean} */ -goog.async.run.workQueueScheduled_ = false; + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 250; + /** + * @private + * @type {boolean} + */ + this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true; -/** @private {!goog.async.WorkQueue} */ -goog.async.run.workQueue_ = new goog.async.WorkQueue(); + /** + * @private + * @type {?ol.Coordinate} + */ + this.lastAnchor_ = null; + /** + * @private + * @type {number|undefined} + */ + this.startTime_ = undefined; -if (goog.DEBUG) { /** - * Reset the work queue. * @private + * @type {number|undefined} */ - goog.async.run.resetQueue_ = function() { - goog.async.run.workQueueScheduled_ = false; - goog.async.run.workQueue_ = new goog.async.WorkQueue(); - }; + this.timeoutId_ = undefined; - // If there is a clock implemenation in use for testing - // and it is reset, reset the queue. - goog.testing.watchers.watchClockReset(goog.async.run.resetQueue_); -} +}; +goog.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction); /** - * Run any pending goog.async.run work items. This function is not intended - * for general use, but for use by entry point handlers to run items ahead of - * goog.async.nextTick. + * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a + * mousewheel-event) and eventually zooms the map. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.MouseWheelZoom} + * @api */ -goog.async.run.processWorkQueue = function() { - // NOTE: additional work queue items may be added while processing. - var item = null; - while (item = goog.async.run.workQueue_.remove()) { - try { - item.fn.call(item.scope); - } catch (e) { - goog.async.throwException(e); - } - goog.async.run.workQueue_.returnUnused(item); - } +ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) { + var stopEvent = false; + if (mapBrowserEvent.type == + goog.events.MouseWheelHandler.EventType.MOUSEWHEEL) { + var map = mapBrowserEvent.map; + var mouseWheelEvent = mapBrowserEvent.browserEvent; + goog.asserts.assertInstanceof(mouseWheelEvent, goog.events.MouseWheelEvent, + 'mouseWheelEvent should be of type MouseWheelEvent'); - // There are no more work items, allow processing to be scheduled again. - goog.async.run.workQueueScheduled_ = false; -}; + if (this.useAnchor_) { + this.lastAnchor_ = mapBrowserEvent.coordinate; + } -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + this.delta_ += mouseWheelEvent.deltaY; -goog.provide('goog.promise.Resolver'); + if (this.startTime_ === undefined) { + this.startTime_ = Date.now(); + } + var duration = ol.MOUSEWHEELZOOM_TIMEOUT_DURATION; + var timeLeft = Math.max(duration - (Date.now() - this.startTime_), 0); + goog.global.clearTimeout(this.timeoutId_); + this.timeoutId_ = goog.global.setTimeout( + goog.bind(this.doZoom_, this, map), timeLeft); -/** - * Resolver interface for promises. The resolver is a convenience interface that - * bundles the promise and its associated resolve and reject functions together, - * for cases where the resolver needs to be persisted internally. - * - * @interface - * @template TYPE - */ -goog.promise.Resolver = function() {}; + mapBrowserEvent.preventDefault(); + stopEvent = true; + } + return !stopEvent; +}; /** - * The promise that created this resolver. - * @type {!goog.Promise<TYPE>} + * @private + * @param {ol.Map} map Map. */ -goog.promise.Resolver.prototype.promise; +ol.interaction.MouseWheelZoom.prototype.doZoom_ = function(map) { + var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA; + var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta); + var view = map.getView(); + goog.asserts.assert(view, 'map must have view'); -/** - * Resolves this resolver with the specified value. - * @type {function((TYPE|goog.Promise<TYPE>|Thenable)=)} - */ -goog.promise.Resolver.prototype.resolve; + map.render(); + ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_, + this.duration_); + + this.delta_ = 0; + this.lastAnchor_ = null; + this.startTime_ = undefined; + this.timeoutId_ = undefined; +}; /** - * Rejects this resolver with the specified reason. - * @type {function(*=): void} + * Enable or disable using the mouse's location as an anchor when zooming + * @param {boolean} useAnchor true to zoom to the mouse's location, false + * to zoom to the center of the map + * @api */ -goog.promise.Resolver.prototype.reject; - -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +ol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) { + this.useAnchor_ = useAnchor; + if (!useAnchor) { + this.lastAnchor_ = null; + } +}; -goog.provide('goog.Promise'); +goog.provide('ol.interaction.PinchRotate'); -goog.require('goog.Thenable'); goog.require('goog.asserts'); -goog.require('goog.async.FreeList'); -goog.require('goog.async.run'); -goog.require('goog.async.throwException'); -goog.require('goog.debug.Error'); -goog.require('goog.promise.Resolver'); +goog.require('goog.functions'); +goog.require('goog.style'); +goog.require('ol'); +goog.require('ol.Coordinate'); +goog.require('ol.ViewHint'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.interaction.Pointer'); /** - * Promises provide a result that may be resolved asynchronously. A Promise may - * be resolved by being fulfilled with a fulfillment value, rejected with a - * rejection reason, or blocked by another Promise. A Promise is said to be - * settled if it is either fulfilled or rejected. Once settled, the Promise - * result is immutable. - * - * Promises may represent results of any type, including undefined. Rejection - * reasons are typically Errors, but may also be of any type. Closure Promises - * allow for optional type annotations that enforce that fulfillment values are - * of the appropriate types at compile time. - * - * The result of a Promise is accessible by calling {@code then} and registering - * {@code onFulfilled} and {@code onRejected} callbacks. Once the Promise - * is settled, the relevant callbacks are invoked with the fulfillment value or - * rejection reason as argument. Callbacks are always invoked in the order they - * were registered, even when additional {@code then} calls are made from inside - * another callback. A callback is always run asynchronously sometime after the - * scope containing the registering {@code then} invocation has returned. - * - * If a Promise is resolved with another Promise, the first Promise will block - * until the second is settled, and then assumes the same result as the second - * Promise. This allows Promises to depend on the results of other Promises, - * linking together multiple asynchronous operations. - * - * This implementation is compatible with the Promises/A+ specification and - * passes that specification's conformance test suite. A Closure Promise may be - * resolved with a Promise instance (or sufficiently compatible Promise-like - * object) created by other Promise implementations. From the specification, - * Promise-like objects are known as "Thenables". - * - * @see http://promisesaplus.com/ + * @classdesc + * Allows the user to rotate the map by twisting with two fingers + * on a touch screen. * - * @param {function( - * this:RESOLVER_CONTEXT, - * function((TYPE|IThenable<TYPE>|Thenable)=), - * function(*=)): void} resolver - * Initialization function that is invoked immediately with {@code resolve} - * and {@code reject} functions as arguments. The Promise is resolved or - * rejected with the first argument passed to either function. - * @param {RESOLVER_CONTEXT=} opt_context An optional context for executing the - * resolver function. If unspecified, the resolver function will be executed - * in the default scope. * @constructor - * @struct - * @final - * @implements {goog.Thenable<TYPE>} - * @template TYPE,RESOLVER_CONTEXT + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.PinchRotateOptions=} opt_options Options. + * @api stable */ -goog.Promise = function(resolver, opt_context) { +ol.interaction.PinchRotate = function(opt_options) { + + goog.base(this, { + handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_, + handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_, + handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_ + }); + + var options = opt_options || {}; + /** - * The internal state of this Promise. Either PENDING, FULFILLED, REJECTED, or - * BLOCKED. - * @private {goog.Promise.State_} + * @private + * @type {ol.Coordinate} */ - this.state_ = goog.Promise.State_.PENDING; + this.anchor_ = null; /** - * The settled result of the Promise. Immutable once set with either a - * fulfillment value or rejection reason. - * @private {*} + * @private + * @type {number|undefined} */ - this.result_ = undefined; + this.lastAngle_ = undefined; /** - * For Promises created by calling {@code then()}, the originating parent. - * @private {goog.Promise} + * @private + * @type {boolean} */ - this.parent_ = null; + this.rotating_ = false; /** - * The linked list of {@code onFulfilled} and {@code onRejected} callbacks - * added to this Promise by calls to {@code then()}. - * @private {?goog.Promise.CallbackEntry_} + * @private + * @type {number} */ - this.callbackEntries_ = null; + this.rotationDelta_ = 0.0; /** - * The tail of the linked list of {@code onFulfilled} and {@code onRejected} - * callbacks added to this Promise by calls to {@code then()}. - * @private {?goog.Promise.CallbackEntry_} + * @private + * @type {number} */ - this.callbackEntriesTail_ = null; + this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3; /** - * Whether the Promise is in the queue of Promises to execute. - * @private {boolean} + * @private + * @type {number} */ - this.executing_ = false; + this.duration_ = options.duration !== undefined ? options.duration : 250; - if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { - /** - * A timeout ID used when the {@code UNHANDLED_REJECTION_DELAY} is greater - * than 0 milliseconds. The ID is set when the Promise is rejected, and - * cleared only if an {@code onRejected} callback is invoked for the - * Promise (or one of its descendants) before the delay is exceeded. - * - * If the rejection is not handled before the timeout completes, the - * rejection reason is passed to the unhandled rejection handler. - * @private {number} - */ - this.unhandledRejectionId_ = 0; - } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { - /** - * When the {@code UNHANDLED_REJECTION_DELAY} is set to 0 milliseconds, a - * boolean that is set if the Promise is rejected, and reset to false if an - * {@code onRejected} callback is invoked for the Promise (or one of its - * descendants). If the rejection is not handled before the next timestep, - * the rejection reason is passed to the unhandled rejection handler. - * @private {boolean} - */ - this.hadUnhandledRejection_ = false; - } +}; +goog.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer); - if (goog.Promise.LONG_STACK_TRACES) { - /** - * A list of stack trace frames pointing to the locations where this Promise - * was created or had callbacks added to it. Saved to add additional context - * to stack traces when an exception is thrown. - * @private {!Array<string>} - */ - this.stack_ = []; - this.addStackTrace_(new Error('created')); - /** - * Index of the most recently executed stack frame entry. - * @private {number} - */ - this.currentStep_ = 0; - } +/** + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.PinchRotate} + * @private + */ +ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) { + goog.asserts.assert(this.targetPointers.length >= 2, + 'length of this.targetPointers should be greater than or equal to 2'); + var rotationDelta = 0.0; - // As an optimization, we can skip this if resolver is goog.nullFunction. - // This value is passed internally when creating a promise which will be - // resolved through a more optimized path. - if (resolver != goog.nullFunction) { - try { - var self = this; - resolver.call( - opt_context, - function(value) { - self.resolve_(goog.Promise.State_.FULFILLED, value); - }, - function(reason) { - if (goog.DEBUG && - !(reason instanceof goog.Promise.CancellationError)) { - try { - // Promise was rejected. Step up one call frame to see why. - if (reason instanceof Error) { - throw reason; - } else { - throw new Error('Promise rejected.'); - } - } catch (e) { - // Only thrown so browser dev tools can catch rejections of - // promises when the option to break on caught exceptions is - // activated. - } - } - self.resolve_(goog.Promise.State_.REJECTED, reason); - }); - } catch (e) { - this.resolve_(goog.Promise.State_.REJECTED, e); + var touch0 = this.targetPointers[0]; + var touch1 = this.targetPointers[1]; + + // angle between touches + var angle = Math.atan2( + touch1.clientY - touch0.clientY, + touch1.clientX - touch0.clientX); + + if (this.lastAngle_ !== undefined) { + var delta = angle - this.lastAngle_; + this.rotationDelta_ += delta; + if (!this.rotating_ && + Math.abs(this.rotationDelta_) > this.threshold_) { + this.rotating_ = true; } + rotationDelta = delta; + } + this.lastAngle_ = angle; + + var map = mapBrowserEvent.map; + + // rotate anchor point. + // FIXME: should be the intersection point between the lines: + // touch0,touch1 and previousTouch0,previousTouch1 + var viewportPosition = goog.style.getClientPosition(map.getViewport()); + var centroid = + ol.interaction.Pointer.centroid(this.targetPointers); + centroid[0] -= viewportPosition.x; + centroid[1] -= viewportPosition.y; + this.anchor_ = map.getCoordinateFromPixel(centroid); + + // rotate + if (this.rotating_) { + var view = map.getView(); + var rotation = view.getRotation(); + map.render(); + ol.interaction.Interaction.rotateWithoutConstraints(map, view, + rotation + rotationDelta, this.anchor_); } }; /** - * @define {boolean} Whether traces of {@code then} calls should be included in - * exceptions thrown + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.PinchRotate} + * @private */ -goog.define('goog.Promise.LONG_STACK_TRACES', false); +ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) { + if (this.targetPointers.length < 2) { + var map = mapBrowserEvent.map; + var view = map.getView(); + view.setHint(ol.ViewHint.INTERACTING, -1); + if (this.rotating_) { + var rotation = view.getRotation(); + ol.interaction.Interaction.rotate( + map, view, rotation, this.anchor_, this.duration_); + } + return false; + } else { + return true; + } +}; /** - * @define {number} The delay in milliseconds before a rejected Promise's reason - * is passed to the rejection handler. By default, the rejection handler - * rethrows the rejection reason so that it appears in the developer console or - * {@code window.onerror} handler. - * - * Rejections are rethrown as quickly as possible by default. A negative value - * disables rejection handling entirely. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.PinchRotate} + * @private */ -goog.define('goog.Promise.UNHANDLED_REJECTION_DELAY', 0); +ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) { + if (this.targetPointers.length >= 2) { + var map = mapBrowserEvent.map; + this.anchor_ = null; + this.lastAngle_ = undefined; + this.rotating_ = false; + this.rotationDelta_ = 0.0; + if (!this.handlingDownUpSequence) { + map.getView().setHint(ol.ViewHint.INTERACTING, 1); + } + map.render(); + return true; + } else { + return false; + } +}; /** - * The possible internal states for a Promise. These states are not directly - * observable to external callers. - * @enum {number} - * @private + * @inheritDoc */ -goog.Promise.State_ = { - /** The Promise is waiting for resolution. */ - PENDING: 0, - - /** The Promise is blocked waiting for the result of another Thenable. */ - BLOCKED: 1, +ol.interaction.PinchRotate.prototype.shouldStopEvent = goog.functions.FALSE; - /** The Promise has been resolved with a fulfillment value. */ - FULFILLED: 2, +goog.provide('ol.interaction.PinchZoom'); - /** The Promise has been resolved with a rejection reason. */ - REJECTED: 3 -}; +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('goog.style'); +goog.require('ol'); +goog.require('ol.Coordinate'); +goog.require('ol.ViewHint'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.interaction.Pointer'); /** - * Entries in the callback chain. Each call to {@code then}, - * {@code thenCatch}, or {@code thenAlways} creates an entry containing the - * functions that may be invoked once the Promise is settled. + * @classdesc + * Allows the user to zoom the map by pinching with two fingers + * on a touch screen. * - * @private @final @struct @constructor + * @constructor + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.PinchZoomOptions=} opt_options Options. + * @api stable */ -goog.Promise.CallbackEntry_ = function() { - /** @type {?goog.Promise} */ - this.child = null; - /** @type {Function} */ - this.onFulfilled = null; - /** @type {Function} */ - this.onRejected = null; - /** @type {?} */ - this.context = null; - /** @type {?goog.Promise.CallbackEntry_} */ - this.next = null; - - /** - * A boolean value to indicate this is a "thenAlways" callback entry. - * Unlike a normal "then/thenVoid" a "thenAlways doesn't participate - * in "cancel" considerations but is simply an observer and requires - * special handling. - * @type {boolean} - */ - this.always = false; -}; - +ol.interaction.PinchZoom = function(opt_options) { -/** clear the object prior to reuse */ -goog.Promise.CallbackEntry_.prototype.reset = function() { - this.child = null; - this.onFulfilled = null; - this.onRejected = null; - this.context = null; - this.always = false; -}; + goog.base(this, { + handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_, + handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_, + handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_ + }); + var options = opt_options ? opt_options : {}; -/** - * @define {number} The number of currently unused objects to keep around for - * reuse. - */ -goog.define('goog.Promise.DEFAULT_MAX_UNUSED', 100); + /** + * @private + * @type {ol.Coordinate} + */ + this.anchor_ = null; + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 400; -/** @const @private {goog.async.FreeList<!goog.Promise.CallbackEntry_>} */ -goog.Promise.freelist_ = new goog.async.FreeList( - function() { - return new goog.Promise.CallbackEntry_(); - }, - function(item) { - item.reset(); - }, - goog.Promise.DEFAULT_MAX_UNUSED); + /** + * @private + * @type {number|undefined} + */ + this.lastDistance_ = undefined; + /** + * @private + * @type {number} + */ + this.lastScaleDelta_ = 1; -/** - * @param {Function} onFulfilled - * @param {Function} onRejected - * @param {?} context - * @return {!goog.Promise.CallbackEntry_} - * @private - */ -goog.Promise.getCallbackEntry_ = function(onFulfilled, onRejected, context) { - var entry = goog.Promise.freelist_.get(); - entry.onFulfilled = onFulfilled; - entry.onRejected = onRejected; - entry.context = context; - return entry; }; +goog.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer); /** - * @param {!goog.Promise.CallbackEntry_} entry + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.PinchZoom} * @private */ -goog.Promise.returnEntry_ = function(entry) { - goog.Promise.freelist_.put(entry); -}; - +ol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) { + goog.asserts.assert(this.targetPointers.length >= 2, + 'length of this.targetPointers should be 2 or more'); + var scaleDelta = 1.0; -// NOTE: this is the same template expression as is used for -// goog.IThenable.prototype.then + var touch0 = this.targetPointers[0]; + var touch1 = this.targetPointers[1]; + var dx = touch0.clientX - touch1.clientX; + var dy = touch0.clientY - touch1.clientY; + // distance between touches + var distance = Math.sqrt(dx * dx + dy * dy); -/** - * @param {VALUE=} opt_value - * @return {RESULT} A new Promise that is immediately resolved - * with the given value. If the input value is already a goog.Promise, it - * will be returned immediately without creating a new instance. - * @template VALUE - * @template RESULT := type('goog.Promise', - * cond(isUnknown(VALUE), unknown(), - * mapunion(VALUE, (V) => - * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), - * templateTypeOf(V, 0), - * cond(sub(V, 'Thenable'), - * unknown(), - * V))))) - * =: - */ -goog.Promise.resolve = function(opt_value) { - if (opt_value instanceof goog.Promise) { - // Avoid creating a new object if we already have a promise object - // of the correct type. - return opt_value; + if (this.lastDistance_ !== undefined) { + scaleDelta = this.lastDistance_ / distance; + } + this.lastDistance_ = distance; + if (scaleDelta != 1.0) { + this.lastScaleDelta_ = scaleDelta; } - // Passing goog.nullFunction will cause the constructor to take an optimized - // path that skips calling the resolver function. - var promise = new goog.Promise(goog.nullFunction); - promise.resolve_(goog.Promise.State_.FULFILLED, opt_value); - return promise; -}; + var map = mapBrowserEvent.map; + var view = map.getView(); + var resolution = view.getResolution(); + + // scale anchor point. + var viewportPosition = goog.style.getClientPosition(map.getViewport()); + var centroid = + ol.interaction.Pointer.centroid(this.targetPointers); + centroid[0] -= viewportPosition.x; + centroid[1] -= viewportPosition.y; + this.anchor_ = map.getCoordinateFromPixel(centroid); + // scale, bypass the resolution constraint + map.render(); + ol.interaction.Interaction.zoomWithoutConstraints( + map, view, resolution * scaleDelta, this.anchor_); -/** - * @param {*=} opt_reason - * @return {!goog.Promise} A new Promise that is immediately rejected with the - * given reason. - */ -goog.Promise.reject = function(opt_reason) { - return new goog.Promise(function(resolve, reject) { - reject(opt_reason); - }); }; /** - * This is identical to - * {@code goog.Promise.resolve(value).then(onFulfilled, onRejected)}, but it - * avoids creating an unnecessary wrapper Promise when {@code value} is already - * thenable. - * - * @param {?(goog.Thenable<TYPE>|Thenable|TYPE)} value - * @param {function(TYPE): ?} onFulfilled - * @param {function(*): *} onRejected - * @template TYPE + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.PinchZoom} * @private */ -goog.Promise.resolveThen_ = function(value, onFulfilled, onRejected) { - var isThenable = goog.Promise.maybeThen_( - value, onFulfilled, onRejected, null); - if (!isThenable) { - goog.async.run(goog.partial(onFulfilled, value)); +ol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) { + if (this.targetPointers.length < 2) { + var map = mapBrowserEvent.map; + var view = map.getView(); + view.setHint(ol.ViewHint.INTERACTING, -1); + var resolution = view.getResolution(); + // Zoom to final resolution, with an animation, and provide a + // direction not to zoom out/in if user was pinching in/out. + // Direction is > 0 if pinching out, and < 0 if pinching in. + var direction = this.lastScaleDelta_ - 1; + ol.interaction.Interaction.zoom(map, view, resolution, + this.anchor_, this.duration_, direction); + return false; + } else { + return true; } }; /** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<TYPE>} A Promise that receives the result of the - * first Promise (or Promise-like) input to settle immediately after it - * settles. - * @template TYPE + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.PinchZoom} + * @private */ -goog.Promise.race = function(promises) { - return new goog.Promise(function(resolve, reject) { - if (!promises.length) { - resolve(undefined); - } - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_(promise, resolve, reject); +ol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) { + if (this.targetPointers.length >= 2) { + var map = mapBrowserEvent.map; + this.anchor_ = null; + this.lastDistance_ = undefined; + this.lastScaleDelta_ = 1; + if (!this.handlingDownUpSequence) { + map.getView().setHint(ol.ViewHint.INTERACTING, 1); } - }); + map.render(); + return true; + } else { + return false; + } }; /** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<!Array<TYPE>>} A Promise that receives a list of - * every fulfilled value once every input Promise (or Promise-like) is - * successfully fulfilled, or is rejected with the first rejection reason - * immediately after it is rejected. - * @template TYPE + * @inheritDoc */ -goog.Promise.all = function(promises) { - return new goog.Promise(function(resolve, reject) { - var toFulfill = promises.length; - var values = []; - - if (!toFulfill) { - resolve(values); - return; - } - - var onFulfill = function(index, value) { - toFulfill--; - values[index] = value; - if (toFulfill == 0) { - resolve(values); - } - }; +ol.interaction.PinchZoom.prototype.shouldStopEvent = goog.functions.FALSE; - var onReject = function(reason) { - reject(reason); - }; +goog.provide('ol.interaction'); - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_( - promise, goog.partial(onFulfill, i), onReject); - } - }); -}; +goog.require('ol'); +goog.require('ol.Collection'); +goog.require('ol.Kinetic'); +goog.require('ol.interaction.DoubleClickZoom'); +goog.require('ol.interaction.DragPan'); +goog.require('ol.interaction.DragRotate'); +goog.require('ol.interaction.DragZoom'); +goog.require('ol.interaction.KeyboardPan'); +goog.require('ol.interaction.KeyboardZoom'); +goog.require('ol.interaction.MouseWheelZoom'); +goog.require('ol.interaction.PinchRotate'); +goog.require('ol.interaction.PinchZoom'); /** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<!Array<{ - * fulfilled: boolean, - * value: (TYPE|undefined), - * reason: (*|undefined)}>>} A Promise that resolves with a list of - * result objects once all input Promises (or Promise-like) have - * settled. Each result object contains a 'fulfilled' boolean indicating - * whether an input Promise was fulfilled or rejected. For fulfilled - * Promises, the resulting value is stored in the 'value' field. For - * rejected Promises, the rejection reason is stored in the 'reason' - * field. - * @template TYPE + * Set of interactions included in maps by default. Specific interactions can be + * excluded by setting the appropriate option to false in the constructor + * options, but the order of the interactions is fixed. If you want to specify + * a different order for interactions, you will need to create your own + * {@link ol.interaction.Interaction} instances and insert them into a + * {@link ol.Collection} in the order you want before creating your + * {@link ol.Map} instance. The default set of interactions, in sequence, is: + * * {@link ol.interaction.DragRotate} + * * {@link ol.interaction.DoubleClickZoom} + * * {@link ol.interaction.DragPan} + * * {@link ol.interaction.PinchRotate} + * * {@link ol.interaction.PinchZoom} + * * {@link ol.interaction.KeyboardPan} + * * {@link ol.interaction.KeyboardZoom} + * * {@link ol.interaction.MouseWheelZoom} + * * {@link ol.interaction.DragZoom} + * + * Note that DragZoom renders a box as a vector polygon, so this interaction + * should be excluded if you want a build with no vector support. + * + * @param {olx.interaction.DefaultsOptions=} opt_options Defaults options. + * @return {ol.Collection.<ol.interaction.Interaction>} A collection of + * interactions to be used with the ol.Map constructor's interactions option. + * @api stable */ -goog.Promise.allSettled = function(promises) { - return new goog.Promise(function(resolve, reject) { - var toSettle = promises.length; - var results = []; +ol.interaction.defaults = function(opt_options) { - if (!toSettle) { - resolve(results); - return; - } + var options = opt_options ? opt_options : {}; - var onSettled = function(index, fulfilled, result) { - toSettle--; - results[index] = fulfilled ? - {fulfilled: true, value: result} : - {fulfilled: false, reason: result}; - if (toSettle == 0) { - resolve(results); - } - }; + var interactions = new ol.Collection(); - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_(promise, - goog.partial(onSettled, i, true /* fulfilled */), - goog.partial(onSettled, i, false /* fulfilled */)); - } - }); -}; + var kinetic = new ol.Kinetic(-0.005, 0.05, 100); + var altShiftDragRotate = options.altShiftDragRotate !== undefined ? + options.altShiftDragRotate : true; + if (altShiftDragRotate) { + interactions.push(new ol.interaction.DragRotate()); + } -/** - * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} - * promises - * @return {!goog.Promise<TYPE>} A Promise that receives the value of the first - * input to be fulfilled, or is rejected with a list of every rejection - * reason if all inputs are rejected. - * @template TYPE - */ -goog.Promise.firstFulfilled = function(promises) { - return new goog.Promise(function(resolve, reject) { - var toReject = promises.length; - var reasons = []; + var doubleClickZoom = options.doubleClickZoom !== undefined ? + options.doubleClickZoom : true; + if (doubleClickZoom) { + interactions.push(new ol.interaction.DoubleClickZoom({ + delta: options.zoomDelta, + duration: options.zoomDuration + })); + } - if (!toReject) { - resolve(undefined); - return; - } + var dragPan = options.dragPan !== undefined ? options.dragPan : true; + if (dragPan) { + interactions.push(new ol.interaction.DragPan({ + kinetic: kinetic + })); + } - var onFulfill = function(value) { - resolve(value); - }; + var pinchRotate = options.pinchRotate !== undefined ? options.pinchRotate : + true; + if (pinchRotate) { + interactions.push(new ol.interaction.PinchRotate()); + } - var onReject = function(index, reason) { - toReject--; - reasons[index] = reason; - if (toReject == 0) { - reject(reasons); - } - }; + var pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true; + if (pinchZoom) { + interactions.push(new ol.interaction.PinchZoom({ + duration: options.zoomDuration + })); + } + + var keyboard = options.keyboard !== undefined ? options.keyboard : true; + if (keyboard) { + interactions.push(new ol.interaction.KeyboardPan()); + interactions.push(new ol.interaction.KeyboardZoom({ + delta: options.zoomDelta, + duration: options.zoomDuration + })); + } + + var mouseWheelZoom = options.mouseWheelZoom !== undefined ? + options.mouseWheelZoom : true; + if (mouseWheelZoom) { + interactions.push(new ol.interaction.MouseWheelZoom({ + duration: options.zoomDuration + })); + } + + var shiftDragZoom = options.shiftDragZoom !== undefined ? + options.shiftDragZoom : true; + if (shiftDragZoom) { + interactions.push(new ol.interaction.DragZoom({ + duration: options.zoomDuration + })); + } + + return interactions; - for (var i = 0, promise; i < promises.length; i++) { - promise = promises[i]; - goog.Promise.resolveThen_( - promise, onFulfill, goog.partial(onReject, i)); - } - }); }; +goog.provide('ol.proj.EPSG3857'); + +goog.require('goog.asserts'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.proj.Projection'); +goog.require('ol.proj.Units'); + + /** - * @return {!goog.promise.Resolver<TYPE>} Resolver wrapping the promise and its - * resolve / reject functions. Resolving or rejecting the resolver - * resolves or rejects the promise. - * @template TYPE + * @classdesc + * Projection object for web/spherical Mercator (EPSG:3857). + * + * @constructor + * @extends {ol.proj.Projection} + * @param {string} code Code. + * @private */ -goog.Promise.withResolver = function() { - var resolve, reject; - var promise = new goog.Promise(function(rs, rj) { - resolve = rs; - reject = rj; +ol.proj.EPSG3857_ = function(code) { + goog.base(this, { + code: code, + units: ol.proj.Units.METERS, + extent: ol.proj.EPSG3857.EXTENT, + global: true, + worldExtent: ol.proj.EPSG3857.WORLD_EXTENT }); - return new goog.Promise.Resolver_(promise, resolve, reject); }; +goog.inherits(ol.proj.EPSG3857_, ol.proj.Projection); /** - * Adds callbacks that will operate on the result of the Promise, returning a - * new child Promise. - * - * If the Promise is fulfilled, the {@code onFulfilled} callback will be invoked - * with the fulfillment value as argument, and the child Promise will be - * fulfilled with the return value of the callback. If the callback throws an - * exception, the child Promise will be rejected with the thrown value instead. - * - * If the Promise is rejected, the {@code onRejected} callback will be invoked - * with the rejection reason as argument, and the child Promise will be resolved - * with the return value or rejected with the thrown value of the callback. - * - * @override + * @inheritDoc */ -goog.Promise.prototype.then = function( - opt_onFulfilled, opt_onRejected, opt_context) { - - if (opt_onFulfilled != null) { - goog.asserts.assertFunction(opt_onFulfilled, - 'opt_onFulfilled should be a function.'); - } - if (opt_onRejected != null) { - goog.asserts.assertFunction(opt_onRejected, - 'opt_onRejected should be a function. Did you pass opt_context ' + - 'as the second argument instead of the third?'); - } - - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('then')); - } - - return this.addChildPromise_( - goog.isFunction(opt_onFulfilled) ? opt_onFulfilled : null, - goog.isFunction(opt_onRejected) ? opt_onRejected : null, - opt_context); +ol.proj.EPSG3857_.prototype.getPointResolution = function(resolution, point) { + return resolution / ol.math.cosh(point[1] / ol.proj.EPSG3857.RADIUS); }; -goog.Thenable.addImplementation(goog.Promise); /** - * Adds callbacks that will operate on the result of the Promise without - * returning a child Promise (unlike "then"). - * - * If the Promise is fulfilled, the {@code onFulfilled} callback will be invoked - * with the fulfillment value as argument. - * - * If the Promise is rejected, the {@code onRejected} callback will be invoked - * with the rejection reason as argument. - * - * @param {?(function(this:THIS, TYPE):?)=} opt_onFulfilled A - * function that will be invoked with the fulfillment value if the Promise - * is fulfilled. - * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will - * be invoked with the rejection reason if the Promise is rejected. - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * with the default this. - * @package - * @template THIS + * @const + * @type {number} */ -goog.Promise.prototype.thenVoid = function( - opt_onFulfilled, opt_onRejected, opt_context) { - - if (opt_onFulfilled != null) { - goog.asserts.assertFunction(opt_onFulfilled, - 'opt_onFulfilled should be a function.'); - } - if (opt_onRejected != null) { - goog.asserts.assertFunction(opt_onRejected, - 'opt_onRejected should be a function. Did you pass opt_context ' + - 'as the second argument instead of the third?'); - } +ol.proj.EPSG3857.RADIUS = 6378137; - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('then')); - } - // Note: no default rejection handler is provided here as we need to - // distinguish unhandled rejections. - this.addCallbackEntry_(goog.Promise.getCallbackEntry_( - opt_onFulfilled || goog.nullFunction, - opt_onRejected || null, - opt_context)); -}; +/** + * @const + * @type {number} + */ +ol.proj.EPSG3857.HALF_SIZE = Math.PI * ol.proj.EPSG3857.RADIUS; /** - * Adds a callback that will be invoked when the Promise is settled (fulfilled - * or rejected). The callback receives no argument, and no new child Promise is - * created. This is useful for ensuring that cleanup takes place after certain - * asynchronous operations. Callbacks added with {@code thenAlways} will be - * executed in the same order with other calls to {@code then}, - * {@code thenAlways}, or {@code thenCatch}. - * - * Since it does not produce a new child Promise, cancellation propagation is - * not prevented by adding callbacks with {@code thenAlways}. A Promise that has - * a cleanup handler added with {@code thenAlways} will be canceled if all of - * its children created by {@code then} (or {@code thenCatch}) are canceled. - * Additionally, since any rejections are not passed to the callback, it does - * not stop the unhandled rejection handler from running. - * - * @param {function(this:THIS): void} onSettled A function that will be invoked - * when the Promise is settled (fulfilled or rejected). - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * in the global scope. - * @return {!goog.Promise<TYPE>} This Promise, for chaining additional calls. - * @template THIS + * @const + * @type {ol.Extent} */ -goog.Promise.prototype.thenAlways = function(onSettled, opt_context) { - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('thenAlways')); - } +ol.proj.EPSG3857.EXTENT = [ + -ol.proj.EPSG3857.HALF_SIZE, -ol.proj.EPSG3857.HALF_SIZE, + ol.proj.EPSG3857.HALF_SIZE, ol.proj.EPSG3857.HALF_SIZE +]; - var entry = goog.Promise.getCallbackEntry_(onSettled, onSettled, opt_context); - entry.always = true; - this.addCallbackEntry_(entry); - return this; -}; + +/** + * @const + * @type {ol.Extent} + */ +ol.proj.EPSG3857.WORLD_EXTENT = [-180, -85, 180, 85]; /** - * Adds a callback that will be invoked only if the Promise is rejected. This - * is equivalent to {@code then(null, onRejected)}. + * Lists several projection codes with the same meaning as EPSG:3857. * - * @param {!function(this:THIS, *): *} onRejected A function that will be - * invoked with the rejection reason if the Promise is rejected. - * @param {THIS=} opt_context An optional context object that will be the - * execution context for the callbacks. By default, functions are executed - * in the global scope. - * @return {!goog.Promise} A new Promise that will receive the result of the - * callback. - * @template THIS + * @type {Array.<string>} */ -goog.Promise.prototype.thenCatch = function(onRejected, opt_context) { - if (goog.Promise.LONG_STACK_TRACES) { - this.addStackTrace_(new Error('thenCatch')); - } - return this.addChildPromise_(null, onRejected, opt_context); -}; +ol.proj.EPSG3857.CODES = [ + 'EPSG:3857', + 'EPSG:102100', + 'EPSG:102113', + 'EPSG:900913', + 'urn:ogc:def:crs:EPSG:6.18:3:3857', + 'urn:ogc:def:crs:EPSG::3857', + 'http://www.opengis.net/gml/srs/epsg.xml#3857' +]; /** - * Cancels the Promise if it is still pending by rejecting it with a cancel - * Error. No action is performed if the Promise is already resolved. - * - * All child Promises of the canceled Promise will be rejected with the same - * cancel error, as with normal Promise rejection. If the Promise to be canceled - * is the only child of a pending Promise, the parent Promise will also be - * canceled. Cancellation may propagate upward through multiple generations. + * Projections equal to EPSG:3857. * - * @param {string=} opt_message An optional debugging message for describing the - * cancellation reason. + * @const + * @type {Array.<ol.proj.Projection>} */ -goog.Promise.prototype.cancel = function(opt_message) { - if (this.state_ == goog.Promise.State_.PENDING) { - goog.async.run(function() { - var err = new goog.Promise.CancellationError(opt_message); - this.cancelInternal_(err); - }, this); - } -}; +ol.proj.EPSG3857.PROJECTIONS = ol.proj.EPSG3857.CODES.map(function(code) { + return new ol.proj.EPSG3857_(code); +}); /** - * Cancels this Promise with the given error. + * Transformation from EPSG:4326 to EPSG:3857. * - * @param {!Error} err The cancellation error. - * @private + * @param {Array.<number>} input Input array of coordinate values. + * @param {Array.<number>=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension (default is `2`). + * @return {Array.<number>} Output array of coordinate values. */ -goog.Promise.prototype.cancelInternal_ = function(err) { - if (this.state_ == goog.Promise.State_.PENDING) { - if (this.parent_) { - // Cancel the Promise and remove it from the parent's child list. - this.parent_.cancelChild_(this, err); - this.parent_ = null; +ol.proj.EPSG3857.fromEPSG4326 = function(input, opt_output, opt_dimension) { + var length = input.length, + dimension = opt_dimension > 1 ? opt_dimension : 2, + output = opt_output; + if (output === undefined) { + if (dimension > 2) { + // preserve values beyond second dimension + output = input.slice(); } else { - this.resolve_(goog.Promise.State_.REJECTED, err); + output = new Array(length); } } + goog.asserts.assert(output.length % dimension === 0, + 'modulus of output.length with dimension should be 0'); + for (var i = 0; i < length; i += dimension) { + output[i] = ol.proj.EPSG3857.RADIUS * Math.PI * input[i] / 180; + output[i + 1] = ol.proj.EPSG3857.RADIUS * + Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360)); + } + return output; }; /** - * Cancels a child Promise from the list of callback entries. If the Promise has - * not already been resolved, reject it with a cancel error. If there are no - * other children in the list of callback entries, propagate the cancellation - * by canceling this Promise as well. + * Transformation from EPSG:3857 to EPSG:4326. * - * @param {!goog.Promise} childPromise The Promise to cancel. - * @param {!Error} err The cancel error to use for rejecting the Promise. - * @private + * @param {Array.<number>} input Input array of coordinate values. + * @param {Array.<number>=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension (default is `2`). + * @return {Array.<number>} Output array of coordinate values. */ -goog.Promise.prototype.cancelChild_ = function(childPromise, err) { - if (!this.callbackEntries_) { - return; - } - var childCount = 0; - var childEntry = null; - var beforeChildEntry = null; - - // Find the callback entry for the childPromise, and count whether there are - // additional child Promises. - for (var entry = this.callbackEntries_; entry; entry = entry.next) { - if (!entry.always) { - childCount++; - if (entry.child == childPromise) { - childEntry = entry; - } - if (childEntry && childCount > 1) { - break; - } - } - if (!childEntry) { - beforeChildEntry = entry; +ol.proj.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) { + var length = input.length, + dimension = opt_dimension > 1 ? opt_dimension : 2, + output = opt_output; + if (output === undefined) { + if (dimension > 2) { + // preserve values beyond second dimension + output = input.slice(); + } else { + output = new Array(length); } } + goog.asserts.assert(output.length % dimension === 0, + 'modulus of output.length with dimension should be 0'); + for (var i = 0; i < length; i += dimension) { + output[i] = 180 * input[i] / (ol.proj.EPSG3857.RADIUS * Math.PI); + output[i + 1] = 360 * Math.atan( + Math.exp(input[i + 1] / ol.proj.EPSG3857.RADIUS)) / Math.PI - 90; + } + return output; +}; - // Can a child entry be missing? +goog.provide('ol.proj.EPSG4326'); - // If the child Promise was the only child, cancel this Promise as well. - // Otherwise, reject only the child Promise with the cancel error. - if (childEntry) { - if (this.state_ == goog.Promise.State_.PENDING && childCount == 1) { - this.cancelInternal_(err); - } else { - if (beforeChildEntry) { - this.removeEntryAfter_(beforeChildEntry); - } else { - this.popEntry_(); - } +goog.require('ol.proj'); +goog.require('ol.proj.Projection'); +goog.require('ol.proj.Units'); - this.executeCallback_( - childEntry, goog.Promise.State_.REJECTED, err); - } - } -}; /** - * Adds a callback entry to the current Promise, and schedules callback - * execution if the Promise has already been settled. + * @classdesc + * Projection object for WGS84 geographic coordinates (EPSG:4326). * - * @param {goog.Promise.CallbackEntry_} callbackEntry Record containing - * {@code onFulfilled} and {@code onRejected} callbacks to execute after - * the Promise is settled. + * Note that OpenLayers does not strictly comply with the EPSG definition. + * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x). + * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates. + * + * @constructor + * @extends {ol.proj.Projection} + * @param {string} code Code. + * @param {string=} opt_axisOrientation Axis orientation. * @private */ -goog.Promise.prototype.addCallbackEntry_ = function(callbackEntry) { - if (!this.hasEntry_() && - (this.state_ == goog.Promise.State_.FULFILLED || - this.state_ == goog.Promise.State_.REJECTED)) { - this.scheduleCallbacks_(); - } - this.queueEntry_(callbackEntry); +ol.proj.EPSG4326_ = function(code, opt_axisOrientation) { + goog.base(this, { + code: code, + units: ol.proj.Units.DEGREES, + extent: ol.proj.EPSG4326.EXTENT, + axisOrientation: opt_axisOrientation, + global: true, + worldExtent: ol.proj.EPSG4326.EXTENT + }); }; +goog.inherits(ol.proj.EPSG4326_, ol.proj.Projection); /** - * Creates a child Promise and adds it to the callback entry list. The result of - * the child Promise is determined by the state of the parent Promise and the - * result of the {@code onFulfilled} or {@code onRejected} callbacks as - * specified in the Promise resolution procedure. - * - * @see http://promisesaplus.com/#the__method - * - * @param {?function(this:THIS, TYPE): - * (RESULT|goog.Promise<RESULT>|Thenable)} onFulfilled A callback that - * will be invoked if the Promise is fullfilled, or null. - * @param {?function(this:THIS, *): *} onRejected A callback that will be - * invoked if the Promise is rejected, or null. - * @param {THIS=} opt_context An optional execution context for the callbacks. - * in the default calling context. - * @return {!goog.Promise} The child Promise. - * @template RESULT,THIS - * @private + * @inheritDoc */ -goog.Promise.prototype.addChildPromise_ = function( - onFulfilled, onRejected, opt_context) { - - /** @type {goog.Promise.CallbackEntry_} */ - var callbackEntry = goog.Promise.getCallbackEntry_(null, null, null); - - callbackEntry.child = new goog.Promise(function(resolve, reject) { - // Invoke onFulfilled, or resolve with the parent's value if absent. - callbackEntry.onFulfilled = onFulfilled ? function(value) { - try { - var result = onFulfilled.call(opt_context, value); - resolve(result); - } catch (err) { - reject(err); - } - } : resolve; - - // Invoke onRejected, or reject with the parent's reason if absent. - callbackEntry.onRejected = onRejected ? function(reason) { - try { - var result = onRejected.call(opt_context, reason); - if (!goog.isDef(result) && - reason instanceof goog.Promise.CancellationError) { - // Propagate cancellation to children if no other result is returned. - reject(reason); - } else { - resolve(result); - } - } catch (err) { - reject(err); - } - } : reject; - }); - - callbackEntry.child.parent_ = this; - this.addCallbackEntry_(callbackEntry); - return callbackEntry.child; +ol.proj.EPSG4326_.prototype.getPointResolution = function(resolution, point) { + return resolution; }; /** - * Unblocks the Promise and fulfills it with the given value. + * Extent of the EPSG:4326 projection which is the whole world. * - * @param {TYPE} value - * @private + * @const + * @type {ol.Extent} */ -goog.Promise.prototype.unblockAndFulfill_ = function(value) { - goog.asserts.assert(this.state_ == goog.Promise.State_.BLOCKED); - this.state_ = goog.Promise.State_.PENDING; - this.resolve_(goog.Promise.State_.FULFILLED, value); -}; +ol.proj.EPSG4326.EXTENT = [-180, -90, 180, 90]; /** - * Unblocks the Promise and rejects it with the given rejection reason. + * Projections equal to EPSG:4326. * - * @param {*} reason - * @private + * @const + * @type {Array.<ol.proj.Projection>} */ -goog.Promise.prototype.unblockAndReject_ = function(reason) { - goog.asserts.assert(this.state_ == goog.Promise.State_.BLOCKED); - this.state_ = goog.Promise.State_.PENDING; - this.resolve_(goog.Promise.State_.REJECTED, reason); -}; +ol.proj.EPSG4326.PROJECTIONS = [ + new ol.proj.EPSG4326_('CRS:84'), + new ol.proj.EPSG4326_('EPSG:4326', 'neu'), + new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG::4326', 'neu'), + new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'), + new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:1.3:CRS84'), + new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:2:84'), + new ol.proj.EPSG4326_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'), + new ol.proj.EPSG4326_('urn:x-ogc:def:crs:EPSG:4326', 'neu') +]; + +goog.provide('ol.proj.common'); + +goog.require('ol.proj'); +goog.require('ol.proj.EPSG3857'); +goog.require('ol.proj.EPSG4326'); /** - * Attempts to resolve a Promise with a given resolution state and value. This - * is a no-op if the given Promise has already been resolved. - * - * If the given result is a Thenable (such as another Promise), the Promise will - * be settled with the same state and result as the Thenable once it is itself - * settled. - * - * If the given result is not a Thenable, the Promise will be settled (fulfilled - * or rejected) with that result based on the given state. - * - * @see http://promisesaplus.com/#the_promise_resolution_procedure - * - * @param {goog.Promise.State_} state - * @param {*} x The result to apply to the Promise. - * @private + * FIXME empty description for jsdoc + * @api */ -goog.Promise.prototype.resolve_ = function(state, x) { - if (this.state_ != goog.Promise.State_.PENDING) { - return; - } - - if (this == x) { - state = goog.Promise.State_.REJECTED; - x = new TypeError('Promise cannot resolve to itself'); - } +ol.proj.common.add = function() { + // Add transformations that don't alter coordinates to convert within set of + // projections with equal meaning. + ol.proj.addEquivalentProjections(ol.proj.EPSG3857.PROJECTIONS); + ol.proj.addEquivalentProjections(ol.proj.EPSG4326.PROJECTIONS); + // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like + // coordinates and back. + ol.proj.addEquivalentTransforms( + ol.proj.EPSG4326.PROJECTIONS, + ol.proj.EPSG3857.PROJECTIONS, + ol.proj.EPSG3857.fromEPSG4326, + ol.proj.EPSG3857.toEPSG4326); +}; - this.state_ = goog.Promise.State_.BLOCKED; - var isThenable = goog.Promise.maybeThen_( - x, this.unblockAndFulfill_, this.unblockAndReject_, this); - if (isThenable) { - return; - } +goog.provide('ol.layer.Image'); - this.result_ = x; - this.state_ = state; - // Since we can no longer be canceled, remove link to parent, so that the - // child promise does not keep the parent promise alive. - this.parent_ = null; - this.scheduleCallbacks_(); +goog.require('ol.layer.Layer'); - if (state == goog.Promise.State_.REJECTED && - !(x instanceof goog.Promise.CancellationError)) { - goog.Promise.addUnhandledRejection_(this, x); - } -}; /** - * Invokes the "then" method of an input value if that value is a Thenable. This - * is a no-op if the value is not thenable. + * @classdesc + * Server-rendered images that are available for arbitrary extents and + * resolutions. + * Note that any property set in the options is set as a {@link ol.Object} + * property on the layer object; for example, setting `title: 'My Title'` in the + * options means that `title` is observable, and has get/set accessors. * - * @param {*} value A potentially thenable value. - * @param {!Function} onFulfilled - * @param {!Function} onRejected - * @param {*} context - * @return {boolean} Whether the input value was thenable. - * @private + * @constructor + * @extends {ol.layer.Layer} + * @fires ol.render.Event + * @param {olx.layer.ImageOptions=} opt_options Layer options. + * @api stable */ -goog.Promise.maybeThen_ = function(value, onFulfilled, onRejected, context) { - if (value instanceof goog.Promise) { - value.thenVoid(onFulfilled, onRejected, context); - return true; - } else if (goog.Thenable.isImplementedBy(value)) { - value = /** @type {!goog.Thenable} */ (value); - value.then(onFulfilled, onRejected, context); - return true; - } else if (goog.isObject(value)) { - try { - var then = value['then']; - if (goog.isFunction(then)) { - goog.Promise.tryThen_( - value, then, onFulfilled, onRejected, context); - return true; - } - } catch (e) { - onRejected.call(context, e); - return true; - } - } - - return false; +ol.layer.Image = function(opt_options) { + var options = opt_options ? opt_options : {}; + goog.base(this, /** @type {olx.layer.LayerOptions} */ (options)); }; +goog.inherits(ol.layer.Image, ol.layer.Layer); /** - * Attempts to call the {@code then} method on an object in the hopes that it is - * a Promise-compatible instance. This allows interoperation between different - * Promise implementations, however a non-compliant object may cause a Promise - * to hang indefinitely. If the {@code then} method throws an exception, the - * dependent Promise will be rejected with the thrown value. - * - * @see http://promisesaplus.com/#point-70 - * - * @param {Thenable} thenable An object with a {@code then} method that may be - * compatible with the Promise/A+ specification. - * @param {!Function} then The {@code then} method of the Thenable object. - * @param {!Function} onFulfilled - * @param {!Function} onRejected - * @param {*} context - * @private + * Return the associated {@link ol.source.Image source} of the image layer. + * @function + * @return {ol.source.Image} Source. + * @api stable */ -goog.Promise.tryThen_ = function( - thenable, then, onFulfilled, onRejected, context) { - - var called = false; - var resolve = function(value) { - if (!called) { - called = true; - onFulfilled.call(context, value); - } - }; +ol.layer.Image.prototype.getSource; - var reject = function(reason) { - if (!called) { - called = true; - onRejected.call(context, reason); - } - }; +goog.provide('ol.layer.VectorTile'); - try { - then.call(thenable, resolve, reject); - } catch (e) { - reject(e); - } -}; +goog.require('goog.object'); +goog.require('ol.layer.Vector'); /** - * Executes the pending callbacks of a settled Promise after a timeout. - * - * Section 2.2.4 of the Promises/A+ specification requires that Promise - * callbacks must only be invoked from a call stack that only contains Promise - * implementation code, which we accomplish by invoking callback execution after - * a timeout. If {@code startExecution_} is called multiple times for the same - * Promise, the callback chain will be evaluated only once. Additional callbacks - * may be added during the evaluation phase, and will be executed in the same - * event loop. - * - * All Promises added to the waiting list during the same browser event loop - * will be executed in one batch to avoid using a separate timeout per Promise. - * - * @private + * @enum {string} */ -goog.Promise.prototype.scheduleCallbacks_ = function() { - if (!this.executing_) { - this.executing_ = true; - goog.async.run(this.executeCallbacks_, this); - } +ol.layer.VectorTileProperty = { + PRELOAD: 'preload', + USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError' }; + /** - * @return {boolean} Whether there are any pending callbacks queued. - * @private + * @classdesc + * Layer for vector tile data that is rendered client-side. + * Note that any property set in the options is set as a {@link ol.Object} + * property on the layer object; for example, setting `title: 'My Title'` in the + * options means that `title` is observable, and has get/set accessors. + * + * @constructor + * @extends {ol.layer.Vector} + * @param {olx.layer.VectorTileOptions=} opt_options Options. + * @api */ -goog.Promise.prototype.hasEntry_ = function() { - return !!this.callbackEntries_; -}; +ol.layer.VectorTile = function(opt_options) { + var options = opt_options ? opt_options : {}; + var baseOptions = goog.object.clone(options); -/** - * @param {goog.Promise.CallbackEntry_} entry - * @private - */ -goog.Promise.prototype.queueEntry_ = function(entry) { - goog.asserts.assert(entry.onFulfilled != null); + delete baseOptions.preload; + delete baseOptions.useInterimTilesOnError; + goog.base(this, /** @type {olx.layer.VectorOptions} */ (baseOptions)); + + this.setPreload(options.preload ? options.preload : 0); + this.setUseInterimTilesOnError(options.useInterimTilesOnError ? + options.useInterimTilesOnError : true); - if (this.callbackEntriesTail_) { - this.callbackEntriesTail_.next = entry; - this.callbackEntriesTail_ = entry; - } else { - // It the work queue was empty set the head too. - this.callbackEntries_ = entry; - this.callbackEntriesTail_ = entry; - } }; +goog.inherits(ol.layer.VectorTile, ol.layer.Vector); /** - * @return {goog.Promise.CallbackEntry_} entry - * @private + * Return the level as number to which we will preload tiles up to. + * @return {number} The level to preload tiles up to. + * @observable + * @api */ -goog.Promise.prototype.popEntry_ = function() { - var entry = null; - if (this.callbackEntries_) { - entry = this.callbackEntries_; - this.callbackEntries_ = entry.next; - entry.next = null; - } - // It the work queue is empty clear the tail too. - if (!this.callbackEntries_) { - this.callbackEntriesTail_ = null; - } - - if (entry != null) { - goog.asserts.assert(entry.onFulfilled != null); - } - return entry; +ol.layer.VectorTile.prototype.getPreload = function() { + return /** @type {number} */ (this.get(ol.layer.VectorTileProperty.PRELOAD)); }; /** - * @param {goog.Promise.CallbackEntry_} previous - * @private + * Return the associated {@link ol.source.VectorTile source} of the layer. + * @function + * @return {ol.source.VectorTile} Source. + * @api */ -goog.Promise.prototype.removeEntryAfter_ = function(previous) { - goog.asserts.assert(this.callbackEntries_); - goog.asserts.assert(previous != null); - // If the last entry is being removed, update the tail - if (previous.next == this.callbackEntriesTail_) { - this.callbackEntriesTail_ = previous; - } - - previous.next = previous.next.next; -}; +ol.layer.VectorTile.prototype.getSource; /** - * Executes all pending callbacks for this Promise. - * - * @private + * Whether we use interim tiles on error. + * @return {boolean} Use interim tiles on error. + * @observable + * @api */ -goog.Promise.prototype.executeCallbacks_ = function() { - var entry = null; - while (entry = this.popEntry_()) { - if (goog.Promise.LONG_STACK_TRACES) { - this.currentStep_++; - } - this.executeCallback_(entry, this.state_, this.result_); - } - this.executing_ = false; +ol.layer.VectorTile.prototype.getUseInterimTilesOnError = function() { + return /** @type {boolean} */ ( + this.get(ol.layer.VectorTileProperty.USE_INTERIM_TILES_ON_ERROR)); }; /** - * Executes a pending callback for this Promise. Invokes an {@code onFulfilled} - * or {@code onRejected} callback based on the settled state of the Promise. - * - * @param {!goog.Promise.CallbackEntry_} callbackEntry An entry containing the - * onFulfilled and/or onRejected callbacks for this step. - * @param {goog.Promise.State_} state The resolution status of the Promise, - * either FULFILLED or REJECTED. - * @param {*} result The settled result of the Promise. - * @private + * Set the level as number to which we will preload tiles up to. + * @param {number} preload The level to preload tiles up to. + * @observable + * @api */ -goog.Promise.prototype.executeCallback_ = function( - callbackEntry, state, result) { - // Cancel an unhandled rejection if the then/thenVoid call had an onRejected. - if (state == goog.Promise.State_.REJECTED && - callbackEntry.onRejected && !callbackEntry.always) { - this.removeUnhandledRejection_(); - } - - if (callbackEntry.child) { - // When the parent is settled, the child no longer needs to hold on to it, - // as the parent can no longer be canceled. - callbackEntry.child.parent_ = null; - goog.Promise.invokeCallback_(callbackEntry, state, result); - } else { - // Callbacks created with thenAlways or thenVoid do not have the rejection - // handling code normally set up in the child Promise. - try { - callbackEntry.always ? - callbackEntry.onFulfilled.call(callbackEntry.context) : - goog.Promise.invokeCallback_(callbackEntry, state, result); - } catch (err) { - goog.Promise.handleRejection_.call(null, err); - } - } - goog.Promise.returnEntry_(callbackEntry); +ol.layer.VectorTile.prototype.setPreload = function(preload) { + this.set(ol.layer.TileProperty.PRELOAD, preload); }; /** - * Executes the onFulfilled or onRejected callback for a callbackEntry. - * - * @param {!goog.Promise.CallbackEntry_} callbackEntry - * @param {goog.Promise.State_} state - * @param {*} result - * @private + * Set whether we use interim tiles on error. + * @param {boolean} useInterimTilesOnError Use interim tiles on error. + * @observable + * @api */ -goog.Promise.invokeCallback_ = function(callbackEntry, state, result) { - if (state == goog.Promise.State_.FULFILLED) { - callbackEntry.onFulfilled.call(callbackEntry.context, result); - } else if (callbackEntry.onRejected) { - callbackEntry.onRejected.call(callbackEntry.context, result); - } +ol.layer.VectorTile.prototype.setUseInterimTilesOnError = + function(useInterimTilesOnError) { + this.set( + ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); }; +// FIXME test, especially polygons with holes and multipolygons +// FIXME need to handle large thick features (where pixel size matters) +// FIXME add offset and end to ol.geom.flat.transform.transform2D? -/** - * Records a stack trace entry for functions that call {@code then} or the - * Promise constructor. May be disabled by unsetting {@code LONG_STACK_TRACES}. - * - * @param {!Error} err An Error object created by the calling function for - * providing a stack trace. - * @private - */ -goog.Promise.prototype.addStackTrace_ = function(err) { - if (goog.Promise.LONG_STACK_TRACES && goog.isString(err.stack)) { - // Extract the third line of the stack trace, which is the entry for the - // user function that called into Promise code. - var trace = err.stack.split('\n', 4)[3]; - var message = err.message; +goog.provide('ol.render.canvas.Immediate'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.vec.Mat4'); +goog.require('ol.color'); +goog.require('ol.extent'); +goog.require('ol.geom.flat.transform'); +goog.require('ol.has'); +goog.require('ol.render.VectorContext'); +goog.require('ol.render.canvas'); +goog.require('ol.vec.Mat4'); - // Pad the message to align the traces. - message += Array(11 - message.length).join(' '); - this.stack_.push(message + trace); - } -}; /** - * Adds extra stack trace information to an exception for the list of - * asynchronous {@code then} calls that have been run for this Promise. Stack - * trace information is recorded in {@see #addStackTrace_}, and appended to - * rethrown errors when {@code LONG_STACK_TRACES} is enabled. + * @classdesc + * A concrete subclass of {@link ol.render.VectorContext} that implements + * direct rendering of features and geometries to an HTML5 Canvas context. + * Instances of this class are created internally by the library and + * provided to application code as vectorContext member of the + * {@link ol.render.Event} object associated with postcompose, precompose and + * render events emitted by layers and maps. * - * @param {*} err An unhandled exception captured during callback execution. - * @private + * @constructor + * @extends {ol.render.VectorContext} + * @param {CanvasRenderingContext2D} context Context. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.Extent} extent Extent. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {number} viewRotation View rotation. + * @struct */ -goog.Promise.prototype.appendLongStack_ = function(err) { - if (goog.Promise.LONG_STACK_TRACES && - err && goog.isString(err.stack) && this.stack_.length) { - var longTrace = ['Promise trace:']; +ol.render.canvas.Immediate = + function(context, pixelRatio, extent, transform, viewRotation) { - for (var promise = this; promise; promise = promise.parent_) { - for (var i = this.currentStep_; i >= 0; i--) { - longTrace.push(promise.stack_[i]); - } - longTrace.push('Value: ' + - '[' + (promise.state_ == goog.Promise.State_.REJECTED ? - 'REJECTED' : 'FULFILLED') + '] ' + - '<' + String(promise.result_) + '>'); - } - err.stack += '\n\n' + longTrace.join('\n'); - } -}; + /** + * @private + * @type {!Object.<string, + * Array.<function(ol.render.canvas.Immediate)>>} + */ + this.callbacksByZIndex_ = {}; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = context; -/** - * Marks this rejected Promise as having being handled. Also marks any parent - * Promises in the rejected state as handled. The rejection handler will no - * longer be invoked for this Promise (if it has not been called already). - * - * @private - */ -goog.Promise.prototype.removeUnhandledRejection_ = function() { - if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { - for (var p = this; p && p.unhandledRejectionId_; p = p.parent_) { - goog.global.clearTimeout(p.unhandledRejectionId_); - p.unhandledRejectionId_ = 0; - } - } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { - for (var p = this; p && p.hadUnhandledRejection_; p = p.parent_) { - p.hadUnhandledRejection_ = false; - } - } -}; + /** + * @private + * @type {number} + */ + this.pixelRatio_ = pixelRatio; + /** + * @private + * @type {ol.Extent} + */ + this.extent_ = extent; -/** - * Marks this rejected Promise as unhandled. If no {@code onRejected} callback - * is called for this Promise before the {@code UNHANDLED_REJECTION_DELAY} - * expires, the reason will be passed to the unhandled rejection handler. The - * handler typically rethrows the rejection reason so that it becomes visible in - * the developer console. - * - * @param {!goog.Promise} promise The rejected Promise. - * @param {*} reason The Promise rejection reason. - * @private - */ -goog.Promise.addUnhandledRejection_ = function(promise, reason) { - if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { - promise.unhandledRejectionId_ = goog.global.setTimeout(function() { - promise.appendLongStack_(reason); - goog.Promise.handleRejection_.call(null, reason); - }, goog.Promise.UNHANDLED_REJECTION_DELAY); + /** + * @private + * @type {goog.vec.Mat4.Number} + */ + this.transform_ = transform; - } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { - promise.hadUnhandledRejection_ = true; - goog.async.run(function() { - if (promise.hadUnhandledRejection_) { - promise.appendLongStack_(reason); - goog.Promise.handleRejection_.call(null, reason); - } - }); - } -}; + /** + * @private + * @type {number} + */ + this.viewRotation_ = viewRotation; + /** + * @private + * @type {?ol.render.canvas.FillState} + */ + this.contextFillState_ = null; -/** - * A method that is invoked with the rejection reasons for Promises that are - * rejected but have no {@code onRejected} callbacks registered yet. - * @type {function(*)} - * @private - */ -goog.Promise.handleRejection_ = goog.async.throwException; + /** + * @private + * @type {?ol.render.canvas.StrokeState} + */ + this.contextStrokeState_ = null; + /** + * @private + * @type {?ol.render.canvas.TextState} + */ + this.contextTextState_ = null; -/** - * Sets a handler that will be called with reasons from unhandled rejected - * Promises. If the rejected Promise (or one of its descendants) has an - * {@code onRejected} callback registered, the rejection will be considered - * handled, and the rejection handler will not be called. - * - * By default, unhandled rejections are rethrown so that the error may be - * captured by the developer console or a {@code window.onerror} handler. - * - * @param {function(*)} handler A function that will be called with reasons from - * rejected Promises. Defaults to {@code goog.async.throwException}. - */ -goog.Promise.setUnhandledRejectionHandler = function(handler) { - goog.Promise.handleRejection_ = handler; -}; + /** + * @private + * @type {?ol.render.canvas.FillState} + */ + this.fillState_ = null; + /** + * @private + * @type {?ol.render.canvas.StrokeState} + */ + this.strokeState_ = null; + /** + * @private + * @type {HTMLCanvasElement|HTMLVideoElement|Image} + */ + this.image_ = null; -/** - * Error used as a rejection reason for canceled Promises. - * - * @param {string=} opt_message - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.Promise.CancellationError = function(opt_message) { - goog.Promise.CancellationError.base(this, 'constructor', opt_message); -}; -goog.inherits(goog.Promise.CancellationError, goog.debug.Error); + /** + * @private + * @type {number} + */ + this.imageAnchorX_ = 0; + /** + * @private + * @type {number} + */ + this.imageAnchorY_ = 0; -/** @override */ -goog.Promise.CancellationError.prototype.name = 'cancel'; + /** + * @private + * @type {number} + */ + this.imageHeight_ = 0; + /** + * @private + * @type {number} + */ + this.imageOpacity_ = 0; + /** + * @private + * @type {number} + */ + this.imageOriginX_ = 0; -/** - * Internal implementation of the resolver interface. - * - * @param {!goog.Promise<TYPE>} promise - * @param {function((TYPE|goog.Promise<TYPE>|Thenable)=)} resolve - * @param {function(*=): void} reject - * @implements {goog.promise.Resolver<TYPE>} - * @final @struct - * @constructor - * @private - * @template TYPE - */ -goog.Promise.Resolver_ = function(promise, resolve, reject) { - /** @const */ - this.promise = promise; + /** + * @private + * @type {number} + */ + this.imageOriginY_ = 0; - /** @const */ - this.resolve = resolve; + /** + * @private + * @type {boolean} + */ + this.imageRotateWithView_ = false; - /** @const */ - this.reject = reject; -}; + /** + * @private + * @type {number} + */ + this.imageRotation_ = 0; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + /** + * @private + * @type {number} + */ + this.imageScale_ = 0; -/** - * @fileoverview A timer class to which other classes and objects can - * listen on. This is only an abstraction above setInterval. - * - * @see ../demos/timers.html - */ + /** + * @private + * @type {boolean} + */ + this.imageSnapToPixel_ = false; -goog.provide('goog.Timer'); + /** + * @private + * @type {number} + */ + this.imageWidth_ = 0; -goog.require('goog.Promise'); -goog.require('goog.events.EventTarget'); + /** + * @private + * @type {string} + */ + this.text_ = ''; + /** + * @private + * @type {number} + */ + this.textOffsetX_ = 0; + /** + * @private + * @type {number} + */ + this.textOffsetY_ = 0; -/** - * Class for handling timing events. - * - * @param {number=} opt_interval Number of ms between ticks (Default: 1ms). - * @param {Object=} opt_timerObject An object that has setTimeout, setInterval, - * clearTimeout and clearInterval (eg Window). - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.Timer = function(opt_interval, opt_timerObject) { - goog.events.EventTarget.call(this); + /** + * @private + * @type {number} + */ + this.textRotation_ = 0; /** - * Number of ms between ticks + * @private * @type {number} + */ + this.textScale_ = 0; + + /** * @private + * @type {?ol.render.canvas.FillState} */ - this.interval_ = opt_interval || 1; + this.textFillState_ = null; /** - * An object that implements setTimeout, setInterval, clearTimeout and - * clearInterval. We default to the window object. Changing this on - * goog.Timer.prototype changes the object for all timer instances which can - * be useful if your environment has some other implementation of timers than - * the window object. - * @type {Object} * @private + * @type {?ol.render.canvas.StrokeState} */ - this.timerObject_ = opt_timerObject || goog.Timer.defaultTimerObject; + this.textStrokeState_ = null; /** - * Cached tick_ bound to the object for later use in the timer. - * @type {Function} * @private + * @type {?ol.render.canvas.TextState} */ - this.boundTick_ = goog.bind(this.tick_, this); + this.textState_ = null; /** - * Firefox browser often fires the timer event sooner - * (sometimes MUCH sooner) than the requested timeout. So we - * compare the time to when the event was last fired, and - * reschedule if appropriate. See also goog.Timer.intervalScale - * @type {number} * @private + * @type {Array.<number>} */ - this.last_ = goog.now(); -}; -goog.inherits(goog.Timer, goog.events.EventTarget); + this.pixelCoordinates_ = []; + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); -/** - * Maximum timeout value. - * - * Timeout values too big to fit into a signed 32-bit integer may cause - * overflow in FF, Safari, and Chrome, resulting in the timeout being - * scheduled immediately. It makes more sense simply not to schedule these - * timeouts, since 24.8 days is beyond a reasonable expectation for the - * browser to stay open. - * - * @type {number} - * @private - */ -goog.Timer.MAX_TIMEOUT_ = 2147483647; +}; /** - * A timer ID that cannot be returned by any known implmentation of - * Window.setTimeout. Passing this value to window.clearTimeout should - * therefore be a no-op. - * - * @const {number} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. * @private */ -goog.Timer.INVALID_TIMEOUT_ID_ = -1; - - -/** - * Whether this timer is enabled - * @type {boolean} - */ -goog.Timer.prototype.enabled = false; - - -/** - * An object that implements setTimout, setInterval, clearTimeout and - * clearInterval. We default to the global object. Changing - * goog.Timer.defaultTimerObject changes the object for all timer instances - * which can be useful if your environment has some other implementation of - * timers you'd like to use. - * @type {Object} - */ -goog.Timer.defaultTimerObject = goog.global; +ol.render.canvas.Immediate.prototype.drawImages_ = + function(flatCoordinates, offset, end, stride) { + if (!this.image_) { + return; + } + goog.asserts.assert(offset === 0, 'offset should be 0'); + goog.asserts.assert(end == flatCoordinates.length, + 'end should be equal to the length of flatCoordinates'); + var pixelCoordinates = ol.geom.flat.transform.transform2D( + flatCoordinates, offset, end, 2, this.transform_, + this.pixelCoordinates_); + var context = this.context_; + var localTransform = this.tmpLocalTransform_; + var alpha = context.globalAlpha; + if (this.imageOpacity_ != 1) { + context.globalAlpha = alpha * this.imageOpacity_; + } + var rotation = this.imageRotation_; + if (this.imageRotateWithView_) { + rotation += this.viewRotation_; + } + var i, ii; + for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { + var x = pixelCoordinates[i] - this.imageAnchorX_; + var y = pixelCoordinates[i + 1] - this.imageAnchorY_; + if (this.imageSnapToPixel_) { + x = (x + 0.5) | 0; + y = (y + 0.5) | 0; + } + if (rotation !== 0 || this.imageScale_ != 1) { + var centerX = x + this.imageAnchorX_; + var centerY = y + this.imageAnchorY_; + ol.vec.Mat4.makeTransform2D(localTransform, + centerX, centerY, this.imageScale_, this.imageScale_, + rotation, -centerX, -centerY); + context.setTransform( + goog.vec.Mat4.getElement(localTransform, 0, 0), + goog.vec.Mat4.getElement(localTransform, 1, 0), + goog.vec.Mat4.getElement(localTransform, 0, 1), + goog.vec.Mat4.getElement(localTransform, 1, 1), + goog.vec.Mat4.getElement(localTransform, 0, 3), + goog.vec.Mat4.getElement(localTransform, 1, 3)); + } + context.drawImage(this.image_, this.imageOriginX_, this.imageOriginY_, + this.imageWidth_, this.imageHeight_, x, y, + this.imageWidth_, this.imageHeight_); + } + if (rotation !== 0 || this.imageScale_ != 1) { + context.setTransform(1, 0, 0, 1, 0, 0); + } + if (this.imageOpacity_ != 1) { + context.globalAlpha = alpha; + } +}; /** - * A variable that controls the timer error correction. If the - * timer is called before the requested interval times - * intervalScale, which often happens on mozilla, the timer is - * rescheduled. See also this.last_ - * @type {number} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @private */ -goog.Timer.intervalScale = 0.8; +ol.render.canvas.Immediate.prototype.drawText_ = + function(flatCoordinates, offset, end, stride) { + if (!this.textState_ || this.text_ === '') { + return; + } + if (this.textFillState_) { + this.setContextFillState_(this.textFillState_); + } + if (this.textStrokeState_) { + this.setContextStrokeState_(this.textStrokeState_); + } + this.setContextTextState_(this.textState_); + goog.asserts.assert(offset === 0, 'offset should be 0'); + goog.asserts.assert(end == flatCoordinates.length, + 'end should be equal to the length of flatCoordinates'); + var pixelCoordinates = ol.geom.flat.transform.transform2D( + flatCoordinates, offset, end, stride, this.transform_, + this.pixelCoordinates_); + var context = this.context_; + for (; offset < end; offset += stride) { + var x = pixelCoordinates[offset] + this.textOffsetX_; + var y = pixelCoordinates[offset + 1] + this.textOffsetY_; + if (this.textRotation_ !== 0 || this.textScale_ != 1) { + var localTransform = ol.vec.Mat4.makeTransform2D(this.tmpLocalTransform_, + x, y, this.textScale_, this.textScale_, this.textRotation_, -x, -y); + context.setTransform( + goog.vec.Mat4.getElement(localTransform, 0, 0), + goog.vec.Mat4.getElement(localTransform, 1, 0), + goog.vec.Mat4.getElement(localTransform, 0, 1), + goog.vec.Mat4.getElement(localTransform, 1, 1), + goog.vec.Mat4.getElement(localTransform, 0, 3), + goog.vec.Mat4.getElement(localTransform, 1, 3)); + } + if (this.textStrokeState_) { + context.strokeText(this.text_, x, y); + } + if (this.textFillState_) { + context.fillText(this.text_, x, y); + } + } + if (this.textRotation_ !== 0 || this.textScale_ != 1) { + context.setTransform(1, 0, 0, 1, 0, 0); + } +}; /** - * Variable for storing the result of setInterval - * @type {?number} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {boolean} close Close. * @private + * @return {number} end End. */ -goog.Timer.prototype.timer_ = null; +ol.render.canvas.Immediate.prototype.moveToLineTo_ = + function(flatCoordinates, offset, end, stride, close) { + var context = this.context_; + var pixelCoordinates = ol.geom.flat.transform.transform2D( + flatCoordinates, offset, end, stride, this.transform_, + this.pixelCoordinates_); + context.moveTo(pixelCoordinates[0], pixelCoordinates[1]); + var i; + for (i = 2; i < pixelCoordinates.length; i += 2) { + context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]); + } + if (close) { + context.lineTo(pixelCoordinates[0], pixelCoordinates[1]); + } + return end; +}; /** - * Gets the interval of the timer. - * @return {number} interval Number of ms between ticks. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @private + * @return {number} End. */ -goog.Timer.prototype.getInterval = function() { - return this.interval_; +ol.render.canvas.Immediate.prototype.drawRings_ = + function(flatCoordinates, offset, ends, stride) { + var context = this.context_; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + offset = this.moveToLineTo_( + flatCoordinates, offset, ends[i], stride, true); + context.closePath(); // FIXME is this needed here? + } + return offset; }; /** - * Sets the interval of the timer. - * @param {number} interval Number of ms between ticks. + * Register a function to be called for rendering at a given zIndex. The + * function will be called asynchronously. The callback will receive a + * reference to {@link ol.render.canvas.Immediate} context for drawing. + * + * @param {number} zIndex Z index. + * @param {function(ol.render.canvas.Immediate)} callback Callback. + * @api */ -goog.Timer.prototype.setInterval = function(interval) { - this.interval_ = interval; - if (this.timer_ && this.enabled) { - // Stop and then start the timer to reset the interval. - this.stop(); - this.start(); - } else if (this.timer_) { - this.stop(); +ol.render.canvas.Immediate.prototype.drawAsync = function(zIndex, callback) { + var zIndexKey = zIndex.toString(); + var callbacks = this.callbacksByZIndex_[zIndexKey]; + if (callbacks !== undefined) { + callbacks.push(callback); + } else { + this.callbacksByZIndex_[zIndexKey] = [callback]; } }; /** - * Callback for the setTimeout used by the timer - * @private + * Render a circle geometry into the canvas. Rendering is immediate and uses + * the current fill and stroke styles. + * + * @param {ol.geom.Circle} circleGeometry Circle geometry. + * @param {ol.Feature} feature Feature, + * @api */ -goog.Timer.prototype.tick_ = function() { - if (this.enabled) { - var elapsed = goog.now() - this.last_; - if (elapsed > 0 && - elapsed < this.interval_ * goog.Timer.intervalScale) { - this.timer_ = this.timerObject_.setTimeout(this.boundTick_, - this.interval_ - elapsed); - return; +ol.render.canvas.Immediate.prototype.drawCircleGeometry = + function(circleGeometry, feature) { + if (!ol.extent.intersects(this.extent_, circleGeometry.getExtent())) { + return; + } + if (this.fillState_ || this.strokeState_) { + if (this.fillState_) { + this.setContextFillState_(this.fillState_); } - - // Prevents setInterval from registering a duplicate timeout when called - // in the timer event handler. - if (this.timer_) { - this.timerObject_.clearTimeout(this.timer_); - this.timer_ = null; + if (this.strokeState_) { + this.setContextStrokeState_(this.strokeState_); } - - this.dispatchTick(); - // The timer could be stopped in the timer event handler. - if (this.enabled) { - this.timer_ = this.timerObject_.setTimeout(this.boundTick_, - this.interval_); - this.last_ = goog.now(); + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( + circleGeometry, this.transform_, this.pixelCoordinates_); + var dx = pixelCoordinates[2] - pixelCoordinates[0]; + var dy = pixelCoordinates[3] - pixelCoordinates[1]; + var radius = Math.sqrt(dx * dx + dy * dy); + var context = this.context_; + context.beginPath(); + context.arc( + pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI); + if (this.fillState_) { + context.fill(); + } + if (this.strokeState_) { + context.stroke(); } } + if (this.text_ !== '') { + this.drawText_(circleGeometry.getCenter(), 0, 2, 2); + } }; /** - * Dispatches the TICK event. This is its own method so subclasses can override. + * Render a feature into the canvas. In order to respect the zIndex of the + * style this method draws asynchronously and thus *after* calls to + * drawXxxxGeometry have been finished, effectively drawing the feature + * *on top* of everything else. You probably should be using an + * {@link ol.layer.Vector} instead of calling this method directly. + * + * @param {ol.Feature} feature Feature. + * @param {ol.style.Style} style Style. + * @api */ -goog.Timer.prototype.dispatchTick = function() { - this.dispatchEvent(goog.Timer.TICK); +ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) { + var geometry = style.getGeometryFunction()(feature); + if (!geometry || + !ol.extent.intersects(this.extent_, geometry.getExtent())) { + return; + } + var zIndex = style.getZIndex(); + if (zIndex === undefined) { + zIndex = 0; + } + this.drawAsync(zIndex, function(render) { + render.setFillStrokeStyle(style.getFill(), style.getStroke()); + render.setImageStyle(style.getImage()); + render.setTextStyle(style.getText()); + var renderGeometry = + ol.render.canvas.Immediate.GEOMETRY_RENDERERS_[geometry.getType()]; + goog.asserts.assert(renderGeometry !== undefined, + 'renderGeometry should be defined'); + renderGeometry.call(render, geometry, null); + }); }; /** - * Starts the timer. + * Render a GeometryCollection to the canvas. Rendering is immediate and + * uses the current styles appropriate for each geometry in the collection. + * + * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry + * collection. + * @param {ol.Feature} feature Feature. */ -goog.Timer.prototype.start = function() { - this.enabled = true; - - // If there is no interval already registered, start it now - if (!this.timer_) { - // IMPORTANT! - // window.setInterval in FireFox has a bug - it fires based on - // absolute time, rather than on relative time. What this means - // is that if a computer is sleeping/hibernating for 24 hours - // and the timer interval was configured to fire every 1000ms, - // then after the PC wakes up the timer will fire, in rapid - // succession, 3600*24 times. - // This bug is described here and is already fixed, but it will - // take time to propagate, so for now I am switching this over - // to setTimeout logic. - // https://bugzilla.mozilla.org/show_bug.cgi?id=376643 - // - this.timer_ = this.timerObject_.setTimeout(this.boundTick_, - this.interval_); - this.last_ = goog.now(); +ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry = + function(geometryCollectionGeometry, feature) { + var geometries = geometryCollectionGeometry.getGeometriesArray(); + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometry = geometries[i]; + var geometryRenderer = + ol.render.canvas.Immediate.GEOMETRY_RENDERERS_[geometry.getType()]; + goog.asserts.assert(geometryRenderer !== undefined, + 'geometryRenderer should be defined'); + geometryRenderer.call(this, geometry, feature); } }; /** - * Stops the timer. + * Render a Point geometry into the canvas. Rendering is immediate and uses + * the current style. + * + * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @api */ -goog.Timer.prototype.stop = function() { - this.enabled = false; - if (this.timer_) { - this.timerObject_.clearTimeout(this.timer_); - this.timer_ = null; +ol.render.canvas.Immediate.prototype.drawPointGeometry = + function(pointGeometry, feature) { + var flatCoordinates = pointGeometry.getFlatCoordinates(); + var stride = pointGeometry.getStride(); + if (this.image_) { + this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); + } + if (this.text_ !== '') { + this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); } -}; - - -/** @override */ -goog.Timer.prototype.disposeInternal = function() { - goog.Timer.superClass_.disposeInternal.call(this); - this.stop(); - delete this.timerObject_; }; /** - * Constant for the timer's event type - * @type {string} + * Render a MultiPoint geometry into the canvas. Rendering is immediate and + * uses the current style. + * + * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @api */ -goog.Timer.TICK = 'tick'; +ol.render.canvas.Immediate.prototype.drawMultiPointGeometry = + function(multiPointGeometry, feature) { + var flatCoordinates = multiPointGeometry.getFlatCoordinates(); + var stride = multiPointGeometry.getStride(); + if (this.image_) { + this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); + } + if (this.text_ !== '') { + this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); + } +}; /** - * Calls the given function once, after the optional pause. - * - * The function is always called asynchronously, even if the delay is 0. This - * is a common trick to schedule a function to run after a batch of browser - * event processing. + * Render a LineString into the canvas. Rendering is immediate and uses + * the current style. * - * @param {function(this:SCOPE)|{handleEvent:function()}|null} listener Function - * or object that has a handleEvent method. - * @param {number=} opt_delay Milliseconds to wait; default is 0. - * @param {SCOPE=} opt_handler Object in whose scope to call the listener. - * @return {number} A handle to the timer ID. - * @template SCOPE + * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line + * string geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @api */ -goog.Timer.callOnce = function(listener, opt_delay, opt_handler) { - if (goog.isFunction(listener)) { - if (opt_handler) { - listener = goog.bind(listener, opt_handler); - } - } else if (listener && typeof listener.handleEvent == 'function') { - // using typeof to prevent strict js warning - listener = goog.bind(listener.handleEvent, listener); - } else { - throw Error('Invalid listener argument'); +ol.render.canvas.Immediate.prototype.drawLineStringGeometry = + function(lineStringGeometry, feature) { + if (!ol.extent.intersects(this.extent_, lineStringGeometry.getExtent())) { + return; } - - if (opt_delay > goog.Timer.MAX_TIMEOUT_) { - // Timeouts greater than MAX_INT return immediately due to integer - // overflow in many browsers. Since MAX_INT is 24.8 days, just don't - // schedule anything at all. - return goog.Timer.INVALID_TIMEOUT_ID_; - } else { - return goog.Timer.defaultTimerObject.setTimeout( - listener, opt_delay || 0); + if (this.strokeState_) { + this.setContextStrokeState_(this.strokeState_); + var context = this.context_; + var flatCoordinates = lineStringGeometry.getFlatCoordinates(); + context.beginPath(); + this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length, + lineStringGeometry.getStride(), false); + context.stroke(); + } + if (this.text_ !== '') { + var flatMidpoint = lineStringGeometry.getFlatMidpoint(); + this.drawText_(flatMidpoint, 0, 2, 2); } }; /** - * Clears a timeout initiated by callOnce - * @param {?number} timerId a timer ID. + * Render a MultiLineString geometry into the canvas. Rendering is immediate + * and uses the current style. + * + * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry + * MultiLineString geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @api */ -goog.Timer.clear = function(timerId) { - goog.Timer.defaultTimerObject.clearTimeout(timerId); +ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry = + function(multiLineStringGeometry, feature) { + var geometryExtent = multiLineStringGeometry.getExtent(); + if (!ol.extent.intersects(this.extent_, geometryExtent)) { + return; + } + if (this.strokeState_) { + this.setContextStrokeState_(this.strokeState_); + var context = this.context_; + var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); + var offset = 0; + var ends = multiLineStringGeometry.getEnds(); + var stride = multiLineStringGeometry.getStride(); + context.beginPath(); + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + offset = this.moveToLineTo_( + flatCoordinates, offset, ends[i], stride, false); + } + context.stroke(); + } + if (this.text_ !== '') { + var flatMidpoints = multiLineStringGeometry.getFlatMidpoints(); + this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2); + } }; /** - * @param {number} delay Milliseconds to wait. - * @param {(RESULT|goog.Thenable<RESULT>|Thenable)=} opt_result The value - * with which the promise will be resolved. - * @return {!goog.Promise<RESULT>} A promise that will be resolved after - * the specified delay, unless it is canceled first. - * @template RESULT + * Render a Polygon geometry into the canvas. Rendering is immediate and uses + * the current style. + * + * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @api */ -goog.Timer.promise = function(delay, opt_result) { - var timerKey = null; - return new goog.Promise(function(resolve, reject) { - timerKey = goog.Timer.callOnce(function() { - resolve(opt_result); - }, delay); - if (timerKey == goog.Timer.INVALID_TIMEOUT_ID_) { - reject(new Error('Failed to schedule timer.')); +ol.render.canvas.Immediate.prototype.drawPolygonGeometry = + function(polygonGeometry, feature) { + if (!ol.extent.intersects(this.extent_, polygonGeometry.getExtent())) { + return; + } + if (this.strokeState_ || this.fillState_) { + if (this.fillState_) { + this.setContextFillState_(this.fillState_); } - }).thenCatch(function(error) { - // Clear the timer. The most likely reason is "cancel" signal. - goog.Timer.clear(timerKey); - throw error; - }); + if (this.strokeState_) { + this.setContextStrokeState_(this.strokeState_); + } + var context = this.context_; + context.beginPath(); + this.drawRings_(polygonGeometry.getOrientedFlatCoordinates(), + 0, polygonGeometry.getEnds(), polygonGeometry.getStride()); + if (this.fillState_) { + context.fill(); + } + if (this.strokeState_) { + context.stroke(); + } + } + if (this.text_ !== '') { + var flatInteriorPoint = polygonGeometry.getFlatInteriorPoint(); + this.drawText_(flatInteriorPoint, 0, 2, 2); + } }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview JSON utility functions. - * @author arv@google.com (Erik Arvidsson) + * Render MultiPolygon geometry into the canvas. Rendering is immediate and + * uses the current style. + * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry. + * @param {ol.Feature} feature Feature. + * @api */ - - -goog.provide('goog.json'); -goog.provide('goog.json.Replacer'); -goog.provide('goog.json.Reviver'); -goog.provide('goog.json.Serializer'); +ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry = + function(multiPolygonGeometry, feature) { + if (!ol.extent.intersects(this.extent_, multiPolygonGeometry.getExtent())) { + return; + } + if (this.strokeState_ || this.fillState_) { + if (this.fillState_) { + this.setContextFillState_(this.fillState_); + } + if (this.strokeState_) { + this.setContextStrokeState_(this.strokeState_); + } + var context = this.context_; + var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); + var offset = 0; + var endss = multiPolygonGeometry.getEndss(); + var stride = multiPolygonGeometry.getStride(); + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + context.beginPath(); + offset = this.drawRings_(flatCoordinates, offset, ends, stride); + if (this.fillState_) { + context.fill(); + } + if (this.strokeState_) { + context.stroke(); + } + } + } + if (this.text_ !== '') { + var flatInteriorPoints = multiPolygonGeometry.getFlatInteriorPoints(); + this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2); + } +}; /** - * @define {boolean} If true, use the native JSON parsing API. - * NOTE(ruilopes): EXPERIMENTAL, handle with care. Setting this to true might - * break your code. The default {@code goog.json.parse} implementation is able - * to handle invalid JSON, such as JSPB. + * @inheritDoc */ -goog.define('goog.json.USE_NATIVE_JSON', false); +ol.render.canvas.Immediate.prototype.drawText = goog.abstractMethod; /** - * Tests if a string is an invalid JSON string. This only ensures that we are - * not using any invalid characters - * @param {string} s The string to test. - * @return {boolean} True if the input is a valid JSON string. + * FIXME: empty description for jsdoc */ -goog.json.isValid = function(s) { - // All empty whitespace is not valid. - if (/^\s*$/.test(s)) { - return false; +ol.render.canvas.Immediate.prototype.flush = function() { + /** @type {Array.<number>} */ + var zs = Object.keys(this.callbacksByZIndex_).map(Number); + goog.array.sort(zs); + var i, ii, callbacks, j, jj; + for (i = 0, ii = zs.length; i < ii; ++i) { + callbacks = this.callbacksByZIndex_[zs[i].toString()]; + for (j = 0, jj = callbacks.length; j < jj; ++j) { + callbacks[j](this); + } } - - // This is taken from http://www.json.org/json2.js which is released to the - // public domain. - // Changes: We dissallow \u2028 Line separator and \u2029 Paragraph separator - // inside strings. We also treat \u2028 and \u2029 as whitespace which they - // are in the RFC but IE and Safari does not match \s to these so we need to - // include them in the reg exps in all places where whitespace is allowed. - // We allowed \x7f inside strings because some tools don't escape it, - // e.g. http://www.json.org/java/org/json/JSONObject.java - - // Parsing happens in three stages. In the first stage, we run the text - // against regular expressions that look for non-JSON patterns. We are - // especially concerned with '()' and 'new' because they can cause invocation, - // and '=' because it can cause mutation. But just to be safe, we want to - // reject all unexpected forms. - - // We split the first stage into 4 regexp operations in order to work around - // crippling inefficiencies in IE's and Safari's regexp engines. First we - // replace all backslash pairs with '@' (a non-JSON character). Second, we - // replace all simple value tokens with ']' characters. Third, we delete all - // open brackets that follow a colon or comma or that begin the text. Finally, - // we look to see that the remaining characters are only whitespace or ']' or - // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - // Don't make these static since they have the global flag. - var backslashesRe = /\\["\\\/bfnrtu]/g; - var simpleValuesRe = - /"[^"\\\n\r\u2028\u2029\x00-\x08\x0a-\x1f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; - var openBracketsRe = /(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g; - var remainderRe = /^[\],:{}\s\u2028\u2029]*$/; - - return remainderRe.test(s.replace(backslashesRe, '@'). - replace(simpleValuesRe, ']'). - replace(openBracketsRe, '')); }; /** - * Parses a JSON string and returns the result. This throws an exception if - * the string is an invalid JSON string. - * - * Note that this is very slow on large strings. If you trust the source of - * the string then you should use unsafeParse instead. - * - * @param {*} s The JSON string to parse. - * @throws Error if s is invalid JSON. - * @return {Object} The object generated from the JSON string, or null. + * @param {ol.render.canvas.FillState} fillState Fill state. + * @private */ -goog.json.parse = goog.json.USE_NATIVE_JSON ? - /** @type {function(*):Object} */ (goog.global['JSON']['parse']) : - function(s) { - var o = String(s); - if (goog.json.isValid(o)) { - /** @preserveTry */ - try { - return /** @type {Object} */ (eval('(' + o + ')')); - } catch (ex) { - } - } - throw Error('Invalid JSON string: ' + o); +ol.render.canvas.Immediate.prototype.setContextFillState_ = + function(fillState) { + var context = this.context_; + var contextFillState = this.contextFillState_; + if (!contextFillState) { + context.fillStyle = fillState.fillStyle; + this.contextFillState_ = { + fillStyle: fillState.fillStyle }; + } else { + if (contextFillState.fillStyle != fillState.fillStyle) { + contextFillState.fillStyle = context.fillStyle = fillState.fillStyle; + } + } +}; /** - * Parses a JSON string and returns the result. This uses eval so it is open - * to security issues and it should only be used if you trust the source. - * - * @param {string} s The JSON string to parse. - * @return {Object} The object generated from the JSON string. + * @param {ol.render.canvas.StrokeState} strokeState Stroke state. + * @private */ -goog.json.unsafeParse = goog.json.USE_NATIVE_JSON ? - /** @type {function(string):Object} */ (goog.global['JSON']['parse']) : - function(s) { - return /** @type {Object} */ (eval('(' + s + ')')); +ol.render.canvas.Immediate.prototype.setContextStrokeState_ = + function(strokeState) { + var context = this.context_; + var contextStrokeState = this.contextStrokeState_; + if (!contextStrokeState) { + context.lineCap = strokeState.lineCap; + if (ol.has.CANVAS_LINE_DASH) { + context.setLineDash(strokeState.lineDash); + } + context.lineJoin = strokeState.lineJoin; + context.lineWidth = strokeState.lineWidth; + context.miterLimit = strokeState.miterLimit; + context.strokeStyle = strokeState.strokeStyle; + this.contextStrokeState_ = { + lineCap: strokeState.lineCap, + lineDash: strokeState.lineDash, + lineJoin: strokeState.lineJoin, + lineWidth: strokeState.lineWidth, + miterLimit: strokeState.miterLimit, + strokeStyle: strokeState.strokeStyle }; - - -/** - * JSON replacer, as defined in Section 15.12.3 of the ES5 spec. - * @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3 - * - * TODO(nicksantos): Array should also be a valid replacer. + } else { + if (contextStrokeState.lineCap != strokeState.lineCap) { + contextStrokeState.lineCap = context.lineCap = strokeState.lineCap; + } + if (ol.has.CANVAS_LINE_DASH) { + if (!goog.array.equals( + contextStrokeState.lineDash, strokeState.lineDash)) { + context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash); + } + } + if (contextStrokeState.lineJoin != strokeState.lineJoin) { + contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin; + } + if (contextStrokeState.lineWidth != strokeState.lineWidth) { + contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth; + } + if (contextStrokeState.miterLimit != strokeState.miterLimit) { + contextStrokeState.miterLimit = context.miterLimit = + strokeState.miterLimit; + } + if (contextStrokeState.strokeStyle != strokeState.strokeStyle) { + contextStrokeState.strokeStyle = context.strokeStyle = + strokeState.strokeStyle; + } + } +}; + + +/** + * @param {ol.render.canvas.TextState} textState Text state. + * @private + */ +ol.render.canvas.Immediate.prototype.setContextTextState_ = + function(textState) { + var context = this.context_; + var contextTextState = this.contextTextState_; + if (!contextTextState) { + context.font = textState.font; + context.textAlign = textState.textAlign; + context.textBaseline = textState.textBaseline; + this.contextTextState_ = { + font: textState.font, + textAlign: textState.textAlign, + textBaseline: textState.textBaseline + }; + } else { + if (contextTextState.font != textState.font) { + contextTextState.font = context.font = textState.font; + } + if (contextTextState.textAlign != textState.textAlign) { + contextTextState.textAlign = context.textAlign = textState.textAlign; + } + if (contextTextState.textBaseline != textState.textBaseline) { + contextTextState.textBaseline = context.textBaseline = + textState.textBaseline; + } + } +}; + + +/** + * Set the fill and stroke style for subsequent draw operations. To clear + * either fill or stroke styles, pass null for the appropriate parameter. * - * @typedef {function(this:Object, string, *): *} + * @param {ol.style.Fill} fillStyle Fill style. + * @param {ol.style.Stroke} strokeStyle Stroke style. + * @api */ -goog.json.Replacer; +ol.render.canvas.Immediate.prototype.setFillStrokeStyle = + function(fillStyle, strokeStyle) { + if (!fillStyle) { + this.fillState_ = null; + } else { + var fillStyleColor = fillStyle.getColor(); + this.fillState_ = { + fillStyle: ol.color.asString(fillStyleColor ? + fillStyleColor : ol.render.canvas.defaultFillStyle) + }; + } + if (!strokeStyle) { + this.strokeState_ = null; + } else { + var strokeStyleColor = strokeStyle.getColor(); + var strokeStyleLineCap = strokeStyle.getLineCap(); + var strokeStyleLineDash = strokeStyle.getLineDash(); + var strokeStyleLineJoin = strokeStyle.getLineJoin(); + var strokeStyleWidth = strokeStyle.getWidth(); + var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); + this.strokeState_ = { + lineCap: strokeStyleLineCap !== undefined ? + strokeStyleLineCap : ol.render.canvas.defaultLineCap, + lineDash: strokeStyleLineDash ? + strokeStyleLineDash : ol.render.canvas.defaultLineDash, + lineJoin: strokeStyleLineJoin !== undefined ? + strokeStyleLineJoin : ol.render.canvas.defaultLineJoin, + lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ? + strokeStyleWidth : ol.render.canvas.defaultLineWidth), + miterLimit: strokeStyleMiterLimit !== undefined ? + strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit, + strokeStyle: ol.color.asString(strokeStyleColor ? + strokeStyleColor : ol.render.canvas.defaultStrokeStyle) + }; + } +}; /** - * JSON reviver, as defined in Section 15.12.2 of the ES5 spec. - * @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3 + * Set the image style for subsequent draw operations. Pass null to remove + * the image style. * - * @typedef {function(this:Object, string, *): *} + * @param {ol.style.Image} imageStyle Image style. + * @api */ -goog.json.Reviver; +ol.render.canvas.Immediate.prototype.setImageStyle = function(imageStyle) { + if (!imageStyle) { + this.image_ = null; + } else { + var imageAnchor = imageStyle.getAnchor(); + // FIXME pixel ratio + var imageImage = imageStyle.getImage(1); + var imageOrigin = imageStyle.getOrigin(); + var imageSize = imageStyle.getSize(); + goog.asserts.assert(imageAnchor, 'imageAnchor must be truthy'); + goog.asserts.assert(imageImage, 'imageImage must be truthy'); + goog.asserts.assert(imageOrigin, 'imageOrigin must be truthy'); + goog.asserts.assert(imageSize, 'imageSize must be truthy'); + this.imageAnchorX_ = imageAnchor[0]; + this.imageAnchorY_ = imageAnchor[1]; + this.imageHeight_ = imageSize[1]; + this.image_ = imageImage; + this.imageOpacity_ = imageStyle.getOpacity(); + this.imageOriginX_ = imageOrigin[0]; + this.imageOriginY_ = imageOrigin[1]; + this.imageRotateWithView_ = imageStyle.getRotateWithView(); + this.imageRotation_ = imageStyle.getRotation(); + this.imageScale_ = imageStyle.getScale(); + this.imageSnapToPixel_ = imageStyle.getSnapToPixel(); + this.imageWidth_ = imageSize[0]; + } +}; /** - * Serializes an object or a value to a JSON string. + * Set the text style for subsequent draw operations. Pass null to + * remove the text style. * - * @param {*} object The object to serialize. - * @param {?goog.json.Replacer=} opt_replacer A replacer function - * called for each (key, value) pair that determines how the value - * should be serialized. By defult, this just returns the value - * and allows default serialization to kick in. - * @throws Error if there are loops in the object graph. - * @return {string} A JSON string representation of the input. + * @param {ol.style.Text} textStyle Text style. + * @api */ -goog.json.serialize = goog.json.USE_NATIVE_JSON ? - /** @type {function(*, ?goog.json.Replacer=):string} */ - (goog.global['JSON']['stringify']) : - function(object, opt_replacer) { - // NOTE(nicksantos): Currently, we never use JSON.stringify. - // - // The last time I evaluated this, JSON.stringify had subtle bugs and - // behavior differences on all browsers, and the performance win was not - // large enough to justify all the issues. This may change in the future - // as browser implementations get better. - // - // assertSerialize in json_test contains if branches for the cases - // that fail. - return new goog.json.Serializer(opt_replacer).serialize(object); +ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) { + if (!textStyle) { + this.text_ = ''; + } else { + var textFillStyle = textStyle.getFill(); + if (!textFillStyle) { + this.textFillState_ = null; + } else { + var textFillStyleColor = textFillStyle.getColor(); + this.textFillState_ = { + fillStyle: ol.color.asString(textFillStyleColor ? + textFillStyleColor : ol.render.canvas.defaultFillStyle) + }; + } + var textStrokeStyle = textStyle.getStroke(); + if (!textStrokeStyle) { + this.textStrokeState_ = null; + } else { + var textStrokeStyleColor = textStrokeStyle.getColor(); + var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); + var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); + var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); + var textStrokeStyleWidth = textStrokeStyle.getWidth(); + var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); + this.textStrokeState_ = { + lineCap: textStrokeStyleLineCap !== undefined ? + textStrokeStyleLineCap : ol.render.canvas.defaultLineCap, + lineDash: textStrokeStyleLineDash ? + textStrokeStyleLineDash : ol.render.canvas.defaultLineDash, + lineJoin: textStrokeStyleLineJoin !== undefined ? + textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin, + lineWidth: textStrokeStyleWidth !== undefined ? + textStrokeStyleWidth : ol.render.canvas.defaultLineWidth, + miterLimit: textStrokeStyleMiterLimit !== undefined ? + textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit, + strokeStyle: ol.color.asString(textStrokeStyleColor ? + textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle) + }; + } + var textFont = textStyle.getFont(); + var textOffsetX = textStyle.getOffsetX(); + var textOffsetY = textStyle.getOffsetY(); + var textRotation = textStyle.getRotation(); + var textScale = textStyle.getScale(); + var textText = textStyle.getText(); + var textTextAlign = textStyle.getTextAlign(); + var textTextBaseline = textStyle.getTextBaseline(); + this.textState_ = { + font: textFont !== undefined ? + textFont : ol.render.canvas.defaultFont, + textAlign: textTextAlign !== undefined ? + textTextAlign : ol.render.canvas.defaultTextAlign, + textBaseline: textTextBaseline !== undefined ? + textTextBaseline : ol.render.canvas.defaultTextBaseline }; + this.text_ = textText !== undefined ? textText : ''; + this.textOffsetX_ = + textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0; + this.textOffsetY_ = + textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0; + this.textRotation_ = textRotation !== undefined ? textRotation : 0; + this.textScale_ = this.pixelRatio_ * (textScale !== undefined ? + textScale : 1); + } +}; + + +/** + * @const + * @private + * @type {Object.<ol.geom.GeometryType, + * function(this: ol.render.canvas.Immediate, + * (ol.geom.Geometry|ol.render.Feature), Object)>} + */ +ol.render.canvas.Immediate.GEOMETRY_RENDERERS_ = { + 'Point': ol.render.canvas.Immediate.prototype.drawPointGeometry, + 'LineString': ol.render.canvas.Immediate.prototype.drawLineStringGeometry, + 'Polygon': ol.render.canvas.Immediate.prototype.drawPolygonGeometry, + 'MultiPoint': ol.render.canvas.Immediate.prototype.drawMultiPointGeometry, + 'MultiLineString': + ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry, + 'MultiPolygon': ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry, + 'GeometryCollection': + ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry, + 'Circle': ol.render.canvas.Immediate.prototype.drawCircleGeometry +}; + +goog.provide('ol.renderer.canvas.Layer'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.vec.Mat4'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Layer'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.canvas.Immediate'); +goog.require('ol.renderer.Layer'); +goog.require('ol.vec.Mat4'); /** - * Class that is used to serialize JSON objects to a string. - * @param {?goog.json.Replacer=} opt_replacer Replacer. * @constructor + * @extends {ol.renderer.Layer} + * @param {ol.layer.Layer} layer Layer. */ -goog.json.Serializer = function(opt_replacer) { +ol.renderer.canvas.Layer = function(layer) { + + goog.base(this, layer); + /** - * @type {goog.json.Replacer|null|undefined} * @private + * @type {!goog.vec.Mat4.Number} */ - this.replacer_ = opt_replacer; + this.transform_ = goog.vec.Mat4.createNumber(); + }; +goog.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer); /** - * Serializes an object or a value to a JSON string. - * - * @param {*} object The object to serialize. - * @throws Error if there are loops in the object graph. - * @return {string} A JSON string representation of the input. + * @param {olx.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. + * @param {CanvasRenderingContext2D} context Context. */ -goog.json.Serializer.prototype.serialize = function(object) { - var sb = []; - this.serializeInternal(object, sb); - return sb.join(''); -}; +ol.renderer.canvas.Layer.prototype.composeFrame = + function(frameState, layerState, context) { + this.dispatchPreComposeEvent(context, frameState); -/** - * Serializes a generic value to a JSON string - * @protected - * @param {*} object The object to serialize. - * @param {Array<string>} sb Array used as a string builder. - * @throws Error if there are loops in the object graph. - */ -goog.json.Serializer.prototype.serializeInternal = function(object, sb) { - if (object == null) { - // undefined == null so this branch covers undefined as well as null - sb.push('null'); - return; - } + var image = this.getImage(); + if (image) { - if (typeof object == 'object') { - if (goog.isArray(object)) { - this.serializeArray(object, sb); - return; - } else if (object instanceof String || - object instanceof Number || - object instanceof Boolean) { - object = object.valueOf(); - // Fall through to switch below. + // clipped rendering if layer extent is set + var extent = layerState.extent; + var clipped = extent !== undefined; + if (clipped) { + goog.asserts.assert(extent !== undefined, + 'layerState extent is defined'); + var pixelRatio = frameState.pixelRatio; + var topLeft = ol.extent.getTopLeft(extent); + var topRight = ol.extent.getTopRight(extent); + var bottomRight = ol.extent.getBottomRight(extent); + var bottomLeft = ol.extent.getBottomLeft(extent); + + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + topLeft, topLeft); + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + topRight, topRight); + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + bottomRight, bottomRight); + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + bottomLeft, bottomLeft); + + context.save(); + context.beginPath(); + context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio); + context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio); + context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio); + context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio); + context.clip(); + } + + var imageTransform = this.getImageTransform(); + // for performance reasons, context.save / context.restore is not used + // to save and restore the transformation matrix and the opacity. + // see http://jsperf.com/context-save-restore-versus-variable + var alpha = context.globalAlpha; + context.globalAlpha = layerState.opacity; + + // for performance reasons, context.setTransform is only used + // when the view is rotated. see http://jsperf.com/canvas-transform + if (frameState.viewState.rotation === 0) { + var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3); + var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3); + var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0); + var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1); + context.drawImage(image, 0, 0, +image.width, +image.height, + Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh)); } else { - this.serializeObject_(/** @type {Object} */ (object), sb); - return; + context.setTransform( + goog.vec.Mat4.getElement(imageTransform, 0, 0), + goog.vec.Mat4.getElement(imageTransform, 1, 0), + goog.vec.Mat4.getElement(imageTransform, 0, 1), + goog.vec.Mat4.getElement(imageTransform, 1, 1), + goog.vec.Mat4.getElement(imageTransform, 0, 3), + goog.vec.Mat4.getElement(imageTransform, 1, 3)); + context.drawImage(image, 0, 0); + context.setTransform(1, 0, 0, 1, 0, 0); } - } + context.globalAlpha = alpha; - switch (typeof object) { - case 'string': - this.serializeString_(object, sb); - break; - case 'number': - this.serializeNumber_(object, sb); - break; - case 'boolean': - sb.push(object); - break; - case 'function': - sb.push('null'); - break; - default: - throw Error('Unknown type: ' + typeof object); + if (clipped) { + context.restore(); + } } + + this.dispatchPostComposeEvent(context, frameState); + }; /** - * Character mappings used internally for goog.string.quote + * @param {ol.render.EventType} type Event type. + * @param {CanvasRenderingContext2D} context Context. + * @param {olx.FrameState} frameState Frame state. + * @param {goog.vec.Mat4.Number=} opt_transform Transform. * @private - * @type {!Object} */ -goog.json.Serializer.charToJsonCharCache_ = { - '\"': '\\"', - '\\': '\\\\', - '/': '\\/', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', - - '\x0B': '\\u000b' // '\v' is not supported in JScript +ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = + function(type, context, frameState, opt_transform) { + var layer = this.getLayer(); + if (layer.hasListener(type)) { + var transform = opt_transform !== undefined ? + opt_transform : this.getTransform(frameState, 0); + var render = new ol.render.canvas.Immediate( + context, frameState.pixelRatio, frameState.extent, transform, + frameState.viewState.rotation); + var composeEvent = new ol.render.Event(type, layer, render, frameState, + context, null); + layer.dispatchEvent(composeEvent); + render.flush(); + } }; /** - * Regular expression used to match characters that need to be replaced. - * The S60 browser has a bug where unicode characters are not matched by - * regular expressions. The condition below detects such behaviour and - * adjusts the regular expression accordingly. - * @private - * @type {!RegExp} + * @param {CanvasRenderingContext2D} context Context. + * @param {olx.FrameState} frameState Frame state. + * @param {goog.vec.Mat4.Number=} opt_transform Transform. + * @protected */ -goog.json.Serializer.charsToReplace_ = /\uffff/.test('\uffff') ? - /[\\\"\x00-\x1f\x7f-\uffff]/g : /[\\\"\x00-\x1f\x7f-\xff]/g; +ol.renderer.canvas.Layer.prototype.dispatchPostComposeEvent = + function(context, frameState, opt_transform) { + this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, context, + frameState, opt_transform); +}; /** - * Serializes a string to a JSON string - * @private - * @param {string} s The string to serialize. - * @param {Array<string>} sb Array used as a string builder. + * @param {CanvasRenderingContext2D} context Context. + * @param {olx.FrameState} frameState Frame state. + * @param {goog.vec.Mat4.Number=} opt_transform Transform. + * @protected */ -goog.json.Serializer.prototype.serializeString_ = function(s, sb) { - // The official JSON implementation does not work with international - // characters. - sb.push('"', s.replace(goog.json.Serializer.charsToReplace_, function(c) { - // caching the result improves performance by a factor 2-3 - var rv = goog.json.Serializer.charToJsonCharCache_[c]; - if (!rv) { - rv = '\\u' + (c.charCodeAt(0) | 0x10000).toString(16).substr(1); - goog.json.Serializer.charToJsonCharCache_[c] = rv; - } - return rv; - }), '"'); +ol.renderer.canvas.Layer.prototype.dispatchPreComposeEvent = + function(context, frameState, opt_transform) { + this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, context, + frameState, opt_transform); }; /** - * Serializes a number to a JSON string - * @private - * @param {number} n The number to serialize. - * @param {Array<string>} sb Array used as a string builder. + * @param {CanvasRenderingContext2D} context Context. + * @param {olx.FrameState} frameState Frame state. + * @param {goog.vec.Mat4.Number=} opt_transform Transform. + * @protected */ -goog.json.Serializer.prototype.serializeNumber_ = function(n, sb) { - sb.push(isFinite(n) && !isNaN(n) ? n : 'null'); +ol.renderer.canvas.Layer.prototype.dispatchRenderEvent = + function(context, frameState, opt_transform) { + this.dispatchComposeEvent_(ol.render.EventType.RENDER, context, + frameState, opt_transform); }; /** - * Serializes an array to a JSON string - * @param {Array<string>} arr The array to serialize. - * @param {Array<string>} sb Array used as a string builder. - * @protected + * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas. */ -goog.json.Serializer.prototype.serializeArray = function(arr, sb) { - var l = arr.length; - sb.push('['); - var sep = ''; - for (var i = 0; i < l; i++) { - sb.push(sep); +ol.renderer.canvas.Layer.prototype.getImage = goog.abstractMethod; - var value = arr[i]; - this.serializeInternal( - this.replacer_ ? this.replacer_.call(arr, String(i), value) : value, - sb); - sep = ','; - } - sb.push(']'); -}; +/** + * @return {!goog.vec.Mat4.Number} Image transform. + */ +ol.renderer.canvas.Layer.prototype.getImageTransform = goog.abstractMethod; /** - * Serializes an object to a JSON string - * @private - * @param {Object} obj The object to serialize. - * @param {Array<string>} sb Array used as a string builder. + * @param {olx.FrameState} frameState Frame state. + * @param {number} offsetX Offset on the x-axis in view coordinates. + * @protected + * @return {!goog.vec.Mat4.Number} Transform. */ -goog.json.Serializer.prototype.serializeObject_ = function(obj, sb) { - sb.push('{'); - var sep = ''; - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - var value = obj[key]; - // Skip functions. - if (typeof value != 'function') { - sb.push(sep); - this.serializeString_(key, sb); - sb.push(':'); - - this.serializeInternal( - this.replacer_ ? this.replacer_.call(obj, key, value) : value, - sb); - - sep = ','; - } - } - } - sb.push('}'); +ol.renderer.canvas.Layer.prototype.getTransform = + function(frameState, offsetX) { + var viewState = frameState.viewState; + var pixelRatio = frameState.pixelRatio; + return ol.vec.Mat4.makeTransform2D(this.transform_, + pixelRatio * frameState.size[0] / 2, + pixelRatio * frameState.size[1] / 2, + pixelRatio / viewState.resolution, + -pixelRatio / viewState.resolution, + -viewState.rotation, + -viewState.center[0] + offsetX, + -viewState.center[1]); }; -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Error codes shared between goog.net.IframeIo and - * goog.net.XhrIo. + * @param {olx.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. + * @return {boolean} whether composeFrame should be called. */ - -goog.provide('goog.net.ErrorCode'); +ol.renderer.canvas.Layer.prototype.prepareFrame = goog.abstractMethod; /** - * Error codes - * @enum {number} + * @param {ol.Pixel} pixelOnMap Pixel. + * @param {goog.vec.Mat4.Number} imageTransformInv The transformation matrix + * to convert from a map pixel to a canvas pixel. + * @return {ol.Pixel} + * @protected */ -goog.net.ErrorCode = { - - /** - * There is no error condition. - */ - NO_ERROR: 0, - - /** - * The most common error from iframeio, unfortunately, is that the browser - * responded with an error page that is classed as a different domain. The - * situations, are when a browser error page is shown -- 404, access denied, - * DNS failure, connection reset etc.) - * - */ - ACCESS_DENIED: 1, - - /** - * Currently the only case where file not found will be caused is when the - * code is running on the local file system and a non-IE browser makes a - * request to a file that doesn't exist. - */ - FILE_NOT_FOUND: 2, +ol.renderer.canvas.Layer.prototype.getPixelOnCanvas = + function(pixelOnMap, imageTransformInv) { + var pixelOnCanvas = [0, 0]; + ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas); + return pixelOnCanvas; +}; - /** - * If Firefox shows a browser error page, such as a connection reset by - * server or access denied, then it will fail silently without the error or - * load handlers firing. - */ - FF_SILENT_ERROR: 3, - /** - * Custom error provided by the client through the error check hook. - */ - CUSTOM_ERROR: 4, +/** + * @param {ol.Size} size Size. + * @return {boolean} True when the canvas with the current size does not exceed + * the maximum dimensions. + */ +ol.renderer.canvas.Layer.testCanvasSize = (function() { /** - * Exception was thrown while processing the request. + * @type {CanvasRenderingContext2D} */ - EXCEPTION: 5, + var context = null; /** - * The Http response returned a non-successful http status code. + * @type {ImageData} */ - HTTP_ERROR: 6, + var imageData = null; - /** - * The request was aborted. - */ - ABORT: 7, + return function(size) { + if (!context) { + context = ol.dom.createCanvasContext2D(1, 1); + imageData = context.createImageData(1, 1); + var data = imageData.data; + data[0] = 42; + data[1] = 84; + data[2] = 126; + data[3] = 255; + } + var canvas = context.canvas; + var good = size[0] <= canvas.width && size[1] <= canvas.height; + if (!good) { + canvas.width = size[0]; + canvas.height = size[1]; + var x = size[0] - 1; + var y = size[1] - 1; + context.putImageData(imageData, x, y); + var result = context.getImageData(x, y, 1, 1); + good = goog.array.equals(imageData.data, result.data); + } + return good; + }; +})(); - /** - * The request timed out. - */ - TIMEOUT: 8, +goog.provide('ol.render.IReplayGroup'); - /** - * The resource is not available offline. - */ - OFFLINE: 9 -}; +goog.require('ol.render.VectorContext'); /** - * Returns a friendly error message for an error code. These messages are for - * debugging and are not localized. - * @param {goog.net.ErrorCode} errorCode An error code. - * @return {string} A message for debugging. + * @enum {string} */ -goog.net.ErrorCode.getDebugMessage = function(errorCode) { - switch (errorCode) { - case goog.net.ErrorCode.NO_ERROR: - return 'No Error'; - - case goog.net.ErrorCode.ACCESS_DENIED: - return 'Access denied to content document'; - - case goog.net.ErrorCode.FILE_NOT_FOUND: - return 'File not found'; - - case goog.net.ErrorCode.FF_SILENT_ERROR: - return 'Firefox silently errored'; - - case goog.net.ErrorCode.CUSTOM_ERROR: - return 'Application custom error'; - - case goog.net.ErrorCode.EXCEPTION: - return 'An exception occurred'; - - case goog.net.ErrorCode.HTTP_ERROR: - return 'Http response at 400 or 500 level'; - - case goog.net.ErrorCode.ABORT: - return 'Request was aborted'; - - case goog.net.ErrorCode.TIMEOUT: - return 'Request timed out'; - - case goog.net.ErrorCode.OFFLINE: - return 'The resource is not available offline'; - - default: - return 'Unrecognized error code'; - } +ol.render.ReplayType = { + IMAGE: 'Image', + LINE_STRING: 'LineString', + POLYGON: 'Polygon', + TEXT: 'Text' }; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Constants for HTTP status codes. + * @const + * @type {Array.<ol.render.ReplayType>} */ +ol.render.REPLAY_ORDER = [ + ol.render.ReplayType.POLYGON, + ol.render.ReplayType.LINE_STRING, + ol.render.ReplayType.IMAGE, + ol.render.ReplayType.TEXT +]; -goog.provide('goog.net.HttpStatus'); /** - * HTTP Status Codes defined in RFC 2616 and RFC 6585. - * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html - * @see http://tools.ietf.org/html/rfc6585 - * @enum {number} + * @interface */ -goog.net.HttpStatus = { - // Informational 1xx - CONTINUE: 100, - SWITCHING_PROTOCOLS: 101, - - // Successful 2xx - OK: 200, - CREATED: 201, - ACCEPTED: 202, - NON_AUTHORITATIVE_INFORMATION: 203, - NO_CONTENT: 204, - RESET_CONTENT: 205, - PARTIAL_CONTENT: 206, - - // Redirection 3xx - MULTIPLE_CHOICES: 300, - MOVED_PERMANENTLY: 301, - FOUND: 302, - SEE_OTHER: 303, - NOT_MODIFIED: 304, - USE_PROXY: 305, - TEMPORARY_REDIRECT: 307, - - // Client Error 4xx - BAD_REQUEST: 400, - UNAUTHORIZED: 401, - PAYMENT_REQUIRED: 402, - FORBIDDEN: 403, - NOT_FOUND: 404, - METHOD_NOT_ALLOWED: 405, - NOT_ACCEPTABLE: 406, - PROXY_AUTHENTICATION_REQUIRED: 407, - REQUEST_TIMEOUT: 408, - CONFLICT: 409, - GONE: 410, - LENGTH_REQUIRED: 411, - PRECONDITION_FAILED: 412, - REQUEST_ENTITY_TOO_LARGE: 413, - REQUEST_URI_TOO_LONG: 414, - UNSUPPORTED_MEDIA_TYPE: 415, - REQUEST_RANGE_NOT_SATISFIABLE: 416, - EXPECTATION_FAILED: 417, - PRECONDITION_REQUIRED: 428, - TOO_MANY_REQUESTS: 429, - REQUEST_HEADER_FIELDS_TOO_LARGE: 431, +ol.render.IReplayGroup = function() { +}; - // Server Error 5xx - INTERNAL_SERVER_ERROR: 500, - NOT_IMPLEMENTED: 501, - BAD_GATEWAY: 502, - SERVICE_UNAVAILABLE: 503, - GATEWAY_TIMEOUT: 504, - HTTP_VERSION_NOT_SUPPORTED: 505, - NETWORK_AUTHENTICATION_REQUIRED: 511, - /* - * IE returns this code for 204 due to its use of URLMon, which returns this - * code for 'Operation Aborted'. The status text is 'Unknown', the response - * headers are ''. Known to occur on IE 6 on XP through IE9 on Win7. - */ - QUIRK_IE_NO_CONTENT: 1223 +/** + * @param {number|undefined} zIndex Z index. + * @param {ol.render.ReplayType} replayType Replay type. + * @return {ol.render.VectorContext} Replay. + */ +ol.render.IReplayGroup.prototype.getReplay = function(zIndex, replayType) { }; /** - * Returns whether the given status should be considered successful. - * - * Successful codes are OK (200), CREATED (201), ACCEPTED (202), - * NO CONTENT (204), PARTIAL CONTENT (206), NOT MODIFIED (304), - * and IE's no content code (1223). - * - * @param {number} status The status code to test. - * @return {boolean} Whether the status code should be considered successful. + * @return {boolean} Is empty. */ -goog.net.HttpStatus.isSuccess = function(status) { - switch (status) { - case goog.net.HttpStatus.OK: - case goog.net.HttpStatus.CREATED: - case goog.net.HttpStatus.ACCEPTED: - case goog.net.HttpStatus.NO_CONTENT: - case goog.net.HttpStatus.PARTIAL_CONTENT: - case goog.net.HttpStatus.NOT_MODIFIED: - case goog.net.HttpStatus.QUIRK_IE_NO_CONTENT: - return true; - - default: - return false; - } +ol.render.IReplayGroup.prototype.isEmpty = function() { }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// FIXME add option to apply snapToPixel to all coordinates? +// FIXME can eliminate empty set styles and strokes (when all geoms skipped) -goog.provide('goog.net.XhrLike'); +goog.provide('ol.render.canvas.ImageReplay'); +goog.provide('ol.render.canvas.LineStringReplay'); +goog.provide('ol.render.canvas.PolygonReplay'); +goog.provide('ol.render.canvas.Replay'); +goog.provide('ol.render.canvas.ReplayGroup'); +goog.provide('ol.render.canvas.TextReplay'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('goog.vec.Mat4'); +goog.require('ol'); +goog.require('ol.array'); +goog.require('ol.color'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.extent.Relationship'); +goog.require('ol.geom.flat.simplify'); +goog.require('ol.geom.flat.transform'); +goog.require('ol.has'); +goog.require('ol.render.IReplayGroup'); +goog.require('ol.render.VectorContext'); +goog.require('ol.render.canvas'); +goog.require('ol.vec.Mat4'); /** - * Interface for the common parts of XMLHttpRequest. - * - * Mostly copied from externs/w3c_xml.js. - * - * @interface - * @see http://www.w3.org/TR/XMLHttpRequest/ + * @enum {number} */ -goog.net.XhrLike = function() {}; - +ol.render.canvas.Instruction = { + BEGIN_GEOMETRY: 0, + BEGIN_PATH: 1, + CIRCLE: 2, + CLOSE_PATH: 3, + DRAW_IMAGE: 4, + DRAW_TEXT: 5, + END_GEOMETRY: 6, + FILL: 7, + MOVE_TO_LINE_TO: 8, + SET_FILL_STYLE: 9, + SET_STROKE_STYLE: 10, + SET_TEXT_STYLE: 11, + STROKE: 12 +}; -/** - * Typedef that refers to either native or custom-implemented XHR objects. - * @typedef {!goog.net.XhrLike|!XMLHttpRequest} - */ -goog.net.XhrLike.OrNative; /** - * @type {function()|null|undefined} - * @see http://www.w3.org/TR/XMLHttpRequest/#handler-xhr-onreadystatechange + * @constructor + * @extends {ol.render.VectorContext} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @protected + * @struct */ -goog.net.XhrLike.prototype.onreadystatechange; - +ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) { + goog.base(this); -/** - * @type {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute - */ -goog.net.XhrLike.prototype.responseText; + /** + * @protected + * @type {number} + */ + this.tolerance = tolerance; + /** + * @protected + * @const + * @type {ol.Extent} + */ + this.maxExtent = maxExtent; -/** - * @type {Document} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsexml-attribute - */ -goog.net.XhrLike.prototype.responseXML; + /** + * @private + * @type {ol.Extent} + */ + this.bufferedMaxExtent_ = null; + /** + * @protected + * @type {number} + */ + this.maxLineWidth = 0; -/** - * @type {number} - * @see http://www.w3.org/TR/XMLHttpRequest/#readystate - */ -goog.net.XhrLike.prototype.readyState; + /** + * @protected + * @const + * @type {number} + */ + this.resolution = resolution; + /** + * @private + * @type {Array.<*>} + */ + this.beginGeometryInstruction1_ = null; -/** - * @type {number} - * @see http://www.w3.org/TR/XMLHttpRequest/#status - */ -goog.net.XhrLike.prototype.status; + /** + * @private + * @type {Array.<*>} + */ + this.beginGeometryInstruction2_ = null; + /** + * @protected + * @type {Array.<*>} + */ + this.instructions = []; -/** - * @type {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#statustext - */ -goog.net.XhrLike.prototype.statusText; + /** + * @protected + * @type {Array.<number>} + */ + this.coordinates = []; + /** + * @private + * @type {goog.vec.Mat4.Number} + */ + this.renderedTransform_ = goog.vec.Mat4.createNumber(); -/** - * @param {string} method - * @param {string} url - * @param {?boolean=} opt_async - * @param {?string=} opt_user - * @param {?string=} opt_password - * @see http://www.w3.org/TR/XMLHttpRequest/#the-open()-method - */ -goog.net.XhrLike.prototype.open = function(method, url, opt_async, opt_user, - opt_password) {}; + /** + * @protected + * @type {Array.<*>} + */ + this.hitDetectionInstructions = []; + /** + * @private + * @type {Array.<number>} + */ + this.pixelCoordinates_ = []; -/** - * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} opt_data - * @see http://www.w3.org/TR/XMLHttpRequest/#the-send()-method - */ -goog.net.XhrLike.prototype.send = function(opt_data) {}; + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.tmpLocalTransform_ = goog.vec.Mat4.createNumber(); +}; +goog.inherits(ol.render.canvas.Replay, ol.render.VectorContext); /** - * @see http://www.w3.org/TR/XMLHttpRequest/#the-abort()-method + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {boolean} close Close. + * @protected + * @return {number} My end. */ -goog.net.XhrLike.prototype.abort = function() {}; +ol.render.canvas.Replay.prototype.appendFlatCoordinates = + function(flatCoordinates, offset, end, stride, close) { + var myEnd = this.coordinates.length; + var extent = this.getBufferedMaxExtent(); + var lastCoord = [flatCoordinates[offset], flatCoordinates[offset + 1]]; + var nextCoord = [NaN, NaN]; + var skipped = true; -/** - * @param {string} header - * @param {string} value - * @see http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method - */ -goog.net.XhrLike.prototype.setRequestHeader = function(header, value) {}; + var i, lastRel, nextRel; + for (i = offset + stride; i < end; i += stride) { + nextCoord[0] = flatCoordinates[i]; + nextCoord[1] = flatCoordinates[i + 1]; + nextRel = ol.extent.coordinateRelationship(extent, nextCoord); + if (nextRel !== lastRel) { + if (skipped) { + this.coordinates[myEnd++] = lastCoord[0]; + this.coordinates[myEnd++] = lastCoord[1]; + } + this.coordinates[myEnd++] = nextCoord[0]; + this.coordinates[myEnd++] = nextCoord[1]; + skipped = false; + } else if (nextRel === ol.extent.Relationship.INTERSECTING) { + this.coordinates[myEnd++] = nextCoord[0]; + this.coordinates[myEnd++] = nextCoord[1]; + skipped = false; + } else { + skipped = true; + } + lastCoord[0] = nextCoord[0]; + lastCoord[1] = nextCoord[1]; + lastRel = nextRel; + } + // handle case where there is only one point to append + if (i === offset + stride) { + this.coordinates[myEnd++] = lastCoord[0]; + this.coordinates[myEnd++] = lastCoord[1]; + } -/** - * @param {string} header - * @return {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method - */ -goog.net.XhrLike.prototype.getResponseHeader = function(header) {}; + if (close) { + this.coordinates[myEnd++] = flatCoordinates[offset]; + this.coordinates[myEnd++] = flatCoordinates[offset + 1]; + } + return myEnd; +}; /** - * @return {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method + * @protected + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -goog.net.XhrLike.prototype.getAllResponseHeaders = function() {}; +ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) { + this.beginGeometryInstruction1_ = + [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0]; + this.instructions.push(this.beginGeometryInstruction1_); + this.beginGeometryInstruction2_ = + [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0]; + this.hitDetectionInstructions.push(this.beginGeometryInstruction2_); +}; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Interface for a factory for creating XMLHttpRequest objects - * and metadata about them. - * @author dbk@google.com (David Barrett-Kahn) + * @private + * @param {CanvasRenderingContext2D} context Context. + * @param {number} pixelRatio Pixel ratio. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {Array.<*>} instructions Instructions array. + * @param {function((ol.Feature|ol.render.Feature)): T|undefined} + * featureCallback Feature callback. + * @param {ol.Extent=} opt_hitExtent Only check features that intersect this + * extent. + * @return {T|undefined} Callback result. + * @template T */ +ol.render.canvas.Replay.prototype.replay_ = function( + context, pixelRatio, transform, viewRotation, skippedFeaturesHash, + instructions, featureCallback, opt_hitExtent) { + /** @type {Array.<number>} */ + var pixelCoordinates; + if (ol.vec.Mat4.equals2D(transform, this.renderedTransform_)) { + pixelCoordinates = this.pixelCoordinates_; + } else { + pixelCoordinates = ol.geom.flat.transform.transform2D( + this.coordinates, 0, this.coordinates.length, 2, + transform, this.pixelCoordinates_); + goog.vec.Mat4.setFromArray(this.renderedTransform_, transform); + goog.asserts.assert(pixelCoordinates === this.pixelCoordinates_, + 'pixelCoordinates should be the same as this.pixelCoordinates_'); + } + var skipFeatures = !goog.object.isEmpty(skippedFeaturesHash); + var i = 0; // instruction index + var ii = instructions.length; // end of instructions + var d = 0; // data index + var dd; // end of per-instruction data + var localTransform = this.tmpLocalTransform_; + var prevX, prevY, roundX, roundY; + while (i < ii) { + var instruction = instructions[i]; + var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]); + var feature, fill, stroke, text, x, y; + switch (type) { + case ol.render.canvas.Instruction.BEGIN_GEOMETRY: + feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); + if ((skipFeatures && + skippedFeaturesHash[goog.getUid(feature).toString()]) || + !feature.getGeometry()) { + i = /** @type {number} */ (instruction[2]); + } else if (opt_hitExtent !== undefined && !ol.extent.intersects( + /** @type {Array<number>} */ (opt_hitExtent), + feature.getGeometry().getExtent())) { + i = /** @type {number} */ (instruction[2]); + } else { + ++i; + } + break; + case ol.render.canvas.Instruction.BEGIN_PATH: + context.beginPath(); + ++i; + break; + case ol.render.canvas.Instruction.CIRCLE: + goog.asserts.assert(goog.isNumber(instruction[1]), + 'second instruction should be a number'); + d = /** @type {number} */ (instruction[1]); + var x1 = pixelCoordinates[d]; + var y1 = pixelCoordinates[d + 1]; + var x2 = pixelCoordinates[d + 2]; + var y2 = pixelCoordinates[d + 3]; + var dx = x2 - x1; + var dy = y2 - y1; + var r = Math.sqrt(dx * dx + dy * dy); + context.arc(x1, y1, r, 0, 2 * Math.PI, true); + ++i; + break; + case ol.render.canvas.Instruction.CLOSE_PATH: + context.closePath(); + ++i; + break; + case ol.render.canvas.Instruction.DRAW_IMAGE: + goog.asserts.assert(goog.isNumber(instruction[1]), + 'second instruction should be a number'); + d = /** @type {number} */ (instruction[1]); + goog.asserts.assert(goog.isNumber(instruction[2]), + 'third instruction should be a number'); + dd = /** @type {number} */ (instruction[2]); + var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */ + (instruction[3]); + // Remaining arguments in DRAW_IMAGE are in alphabetical order + var anchorX = /** @type {number} */ (instruction[4]) * pixelRatio; + var anchorY = /** @type {number} */ (instruction[5]) * pixelRatio; + var height = /** @type {number} */ (instruction[6]); + var opacity = /** @type {number} */ (instruction[7]); + var originX = /** @type {number} */ (instruction[8]); + var originY = /** @type {number} */ (instruction[9]); + var rotateWithView = /** @type {boolean} */ (instruction[10]); + var rotation = /** @type {number} */ (instruction[11]); + var scale = /** @type {number} */ (instruction[12]); + var snapToPixel = /** @type {boolean} */ (instruction[13]); + var width = /** @type {number} */ (instruction[14]); + if (rotateWithView) { + rotation += viewRotation; + } + for (; d < dd; d += 2) { + x = pixelCoordinates[d] - anchorX; + y = pixelCoordinates[d + 1] - anchorY; + if (snapToPixel) { + x = (x + 0.5) | 0; + y = (y + 0.5) | 0; + } + if (scale != 1 || rotation !== 0) { + var centerX = x + anchorX; + var centerY = y + anchorY; + ol.vec.Mat4.makeTransform2D( + localTransform, centerX, centerY, scale, scale, + rotation, -centerX, -centerY); + context.setTransform( + goog.vec.Mat4.getElement(localTransform, 0, 0), + goog.vec.Mat4.getElement(localTransform, 1, 0), + goog.vec.Mat4.getElement(localTransform, 0, 1), + goog.vec.Mat4.getElement(localTransform, 1, 1), + goog.vec.Mat4.getElement(localTransform, 0, 3), + goog.vec.Mat4.getElement(localTransform, 1, 3)); + } + var alpha = context.globalAlpha; + if (opacity != 1) { + context.globalAlpha = alpha * opacity; + } -goog.provide('goog.net.XmlHttpFactory'); - -/** @suppress {extraRequire} Typedef. */ -goog.require('goog.net.XhrLike'); + context.drawImage(image, originX, originY, width, height, + x, y, width * pixelRatio, height * pixelRatio); + if (opacity != 1) { + context.globalAlpha = alpha; + } + if (scale != 1 || rotation !== 0) { + context.setTransform(1, 0, 0, 1, 0, 0); + } + } + ++i; + break; + case ol.render.canvas.Instruction.DRAW_TEXT: + goog.asserts.assert(goog.isNumber(instruction[1]), + '2nd instruction should be a number'); + d = /** @type {number} */ (instruction[1]); + goog.asserts.assert(goog.isNumber(instruction[2]), + '3rd instruction should be a number'); + dd = /** @type {number} */ (instruction[2]); + goog.asserts.assert(goog.isString(instruction[3]), + '4th instruction should be a string'); + text = /** @type {string} */ (instruction[3]); + goog.asserts.assert(goog.isNumber(instruction[4]), + '5th instruction should be a number'); + var offsetX = /** @type {number} */ (instruction[4]) * pixelRatio; + goog.asserts.assert(goog.isNumber(instruction[5]), + '6th instruction should be a number'); + var offsetY = /** @type {number} */ (instruction[5]) * pixelRatio; + goog.asserts.assert(goog.isNumber(instruction[6]), + '7th instruction should be a number'); + rotation = /** @type {number} */ (instruction[6]); + goog.asserts.assert(goog.isNumber(instruction[7]), + '8th instruction should be a number'); + scale = /** @type {number} */ (instruction[7]) * pixelRatio; + goog.asserts.assert(goog.isBoolean(instruction[8]), + '9th instruction should be a boolean'); + fill = /** @type {boolean} */ (instruction[8]); + goog.asserts.assert(goog.isBoolean(instruction[9]), + '10th instruction should be a boolean'); + stroke = /** @type {boolean} */ (instruction[9]); + for (; d < dd; d += 2) { + x = pixelCoordinates[d] + offsetX; + y = pixelCoordinates[d + 1] + offsetY; + if (scale != 1 || rotation !== 0) { + ol.vec.Mat4.makeTransform2D( + localTransform, x, y, scale, scale, rotation, -x, -y); + context.setTransform( + goog.vec.Mat4.getElement(localTransform, 0, 0), + goog.vec.Mat4.getElement(localTransform, 1, 0), + goog.vec.Mat4.getElement(localTransform, 0, 1), + goog.vec.Mat4.getElement(localTransform, 1, 1), + goog.vec.Mat4.getElement(localTransform, 0, 3), + goog.vec.Mat4.getElement(localTransform, 1, 3)); + } + if (stroke) { + context.strokeText(text, x, y); + } + if (fill) { + context.fillText(text, x, y); + } + if (scale != 1 || rotation !== 0) { + context.setTransform(1, 0, 0, 1, 0, 0); + } + } + ++i; + break; + case ol.render.canvas.Instruction.END_GEOMETRY: + if (featureCallback !== undefined) { + feature = + /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); + var result = featureCallback(feature); + if (result) { + return result; + } + } + ++i; + break; + case ol.render.canvas.Instruction.FILL: + context.fill(); + ++i; + break; + case ol.render.canvas.Instruction.MOVE_TO_LINE_TO: + goog.asserts.assert(goog.isNumber(instruction[1]), + '2nd instruction should be a number'); + d = /** @type {number} */ (instruction[1]); + goog.asserts.assert(goog.isNumber(instruction[2]), + '3rd instruction should be a number'); + dd = /** @type {number} */ (instruction[2]); + x = pixelCoordinates[d]; + y = pixelCoordinates[d + 1]; + roundX = (x + 0.5) | 0; + roundY = (y + 0.5) | 0; + if (roundX !== prevX || roundY !== prevY) { + context.moveTo(x, y); + prevX = roundX; + prevY = roundY; + } + for (d += 2; d < dd; d += 2) { + x = pixelCoordinates[d]; + y = pixelCoordinates[d + 1]; + roundX = (x + 0.5) | 0; + roundY = (y + 0.5) | 0; + if (roundX !== prevX || roundY !== prevY) { + context.lineTo(x, y); + prevX = roundX; + prevY = roundY; + } + } + ++i; + break; + case ol.render.canvas.Instruction.SET_FILL_STYLE: + goog.asserts.assert(goog.isString(instruction[1]), + '2nd instruction should be a string'); + context.fillStyle = /** @type {string} */ (instruction[1]); + ++i; + break; + case ol.render.canvas.Instruction.SET_STROKE_STYLE: + goog.asserts.assert(goog.isString(instruction[1]), + '2nd instruction should be a string'); + goog.asserts.assert(goog.isNumber(instruction[2]), + '3rd instruction should be a number'); + goog.asserts.assert(goog.isString(instruction[3]), + '4rd instruction should be a string'); + goog.asserts.assert(goog.isString(instruction[4]), + '5th instruction should be a string'); + goog.asserts.assert(goog.isNumber(instruction[5]), + '6th instruction should be a number'); + goog.asserts.assert(instruction[6], + '7th instruction should not be null'); + var usePixelRatio = instruction[7] !== undefined ? + instruction[7] : true; + var lineWidth = /** @type {number} */ (instruction[2]); + context.strokeStyle = /** @type {string} */ (instruction[1]); + context.lineWidth = usePixelRatio ? lineWidth * pixelRatio : lineWidth; + context.lineCap = /** @type {string} */ (instruction[3]); + context.lineJoin = /** @type {string} */ (instruction[4]); + context.miterLimit = /** @type {number} */ (instruction[5]); + if (ol.has.CANVAS_LINE_DASH) { + context.setLineDash(/** @type {Array.<number>} */ (instruction[6])); + } + prevX = NaN; + prevY = NaN; + ++i; + break; + case ol.render.canvas.Instruction.SET_TEXT_STYLE: + goog.asserts.assert(goog.isString(instruction[1]), + '2nd instruction should be a string'); + goog.asserts.assert(goog.isString(instruction[2]), + '3rd instruction should be a string'); + goog.asserts.assert(goog.isString(instruction[3]), + '4th instruction should be a string'); + context.font = /** @type {string} */ (instruction[1]); + context.textAlign = /** @type {string} */ (instruction[2]); + context.textBaseline = /** @type {string} */ (instruction[3]); + ++i; + break; + case ol.render.canvas.Instruction.STROKE: + context.stroke(); + ++i; + break; + default: + goog.asserts.fail('Unknown canvas render instruction'); + ++i; // consume the instruction anyway, to avoid an infinite loop + break; + } + } + // assert that all instructions were consumed + goog.asserts.assert(i == instructions.length, + 'all instructions should be consumed'); + return undefined; +}; /** - * Abstract base class for an XmlHttpRequest factory. - * @constructor + * @param {CanvasRenderingContext2D} context Context. + * @param {number} pixelRatio Pixel ratio. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. */ -goog.net.XmlHttpFactory = function() { +ol.render.canvas.Replay.prototype.replay = function( + context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { + var instructions = this.instructions; + this.replay_(context, pixelRatio, transform, viewRotation, + skippedFeaturesHash, instructions, undefined); }; /** - * Cache of options - we only actually call internalGetOptions once. - * @type {Object} - * @private + * @param {CanvasRenderingContext2D} context Context. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback + * Feature callback. + * @param {ol.Extent=} opt_hitExtent Only check features that intersect this + * extent. + * @return {T|undefined} Callback result. + * @template T */ -goog.net.XmlHttpFactory.prototype.cachedOptions_ = null; +ol.render.canvas.Replay.prototype.replayHitDetection = function( + context, transform, viewRotation, skippedFeaturesHash, + opt_featureCallback, opt_hitExtent) { + var instructions = this.hitDetectionInstructions; + return this.replay_(context, 1, transform, viewRotation, + skippedFeaturesHash, instructions, opt_featureCallback, opt_hitExtent); +}; /** - * @return {!goog.net.XhrLike.OrNative} A new XhrLike instance. + * @private */ -goog.net.XmlHttpFactory.prototype.createInstance = goog.abstractMethod; +ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions_ = + function() { + var hitDetectionInstructions = this.hitDetectionInstructions; + // step 1 - reverse array + hitDetectionInstructions.reverse(); + // step 2 - reverse instructions within geometry blocks + var i; + var n = hitDetectionInstructions.length; + var instruction; + var type; + var begin = -1; + for (i = 0; i < n; ++i) { + instruction = hitDetectionInstructions[i]; + type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]); + if (type == ol.render.canvas.Instruction.END_GEOMETRY) { + goog.asserts.assert(begin == -1, 'begin should be -1'); + begin = i; + } else if (type == ol.render.canvas.Instruction.BEGIN_GEOMETRY) { + instruction[2] = i; + goog.asserts.assert(begin >= 0, + 'begin should be larger than or equal to 0'); + ol.array.reverseSubArray(this.hitDetectionInstructions, begin, i); + begin = -1; + } + } +}; /** - * @return {Object} Options describing how xhr objects obtained from this - * factory should be used. + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ -goog.net.XmlHttpFactory.prototype.getOptions = function() { - return this.cachedOptions_ || - (this.cachedOptions_ = this.internalGetOptions()); +ol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) { + goog.asserts.assert(this.beginGeometryInstruction1_, + 'this.beginGeometryInstruction1_ should not be null'); + this.beginGeometryInstruction1_[2] = this.instructions.length; + this.beginGeometryInstruction1_ = null; + goog.asserts.assert(this.beginGeometryInstruction2_, + 'this.beginGeometryInstruction2_ should not be null'); + this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length; + this.beginGeometryInstruction2_ = null; + var endGeometryInstruction = + [ol.render.canvas.Instruction.END_GEOMETRY, feature]; + this.instructions.push(endGeometryInstruction); + this.hitDetectionInstructions.push(endGeometryInstruction); }; /** - * Override this method in subclasses to preserve the caching offered by - * getOptions(). - * @return {Object} Options describing how xhr objects obtained from this - * factory should be used. - * @protected + * FIXME empty description for jsdoc */ -goog.net.XmlHttpFactory.prototype.internalGetOptions = goog.abstractMethod; +ol.render.canvas.Replay.prototype.finish = ol.nullFunction; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Implementation of XmlHttpFactory which allows construction from - * simple factory methods. - * @author dbk@google.com (David Barrett-Kahn) + * Get the buffered rendering extent. Rendering will be clipped to the extent + * provided to the constructor. To account for symbolizers that may intersect + * this extent, we calculate a buffered extent (e.g. based on stroke width). + * @return {ol.Extent} The buffered rendering extent. + * @protected */ - -goog.provide('goog.net.WrapperXmlHttpFactory'); - -/** @suppress {extraRequire} Typedef. */ -goog.require('goog.net.XhrLike'); -goog.require('goog.net.XmlHttpFactory'); +ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() { + return this.maxExtent; +}; /** - * An xhr factory subclass which can be constructed using two factory methods. - * This exists partly to allow the preservation of goog.net.XmlHttp.setFactory() - * with an unchanged signature. - * @param {function():!goog.net.XhrLike.OrNative} xhrFactory - * A function which returns a new XHR object. - * @param {function():!Object} optionsFactory A function which returns the - * options associated with xhr objects from this factory. - * @extends {goog.net.XmlHttpFactory} * @constructor - * @final + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @protected + * @struct */ -goog.net.WrapperXmlHttpFactory = function(xhrFactory, optionsFactory) { - goog.net.XmlHttpFactory.call(this); +ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution) { + goog.base(this, tolerance, maxExtent, resolution); /** - * XHR factory method. - * @type {function() : !goog.net.XhrLike.OrNative} * @private + * @type {HTMLCanvasElement|HTMLVideoElement|Image} */ - this.xhrFactory_ = xhrFactory; + this.hitDetectionImage_ = null; /** - * Options factory method. - * @type {function() : !Object} * @private + * @type {HTMLCanvasElement|HTMLVideoElement|Image} */ - this.optionsFactory_ = optionsFactory; -}; -goog.inherits(goog.net.WrapperXmlHttpFactory, goog.net.XmlHttpFactory); - - -/** @override */ -goog.net.WrapperXmlHttpFactory.prototype.createInstance = function() { - return this.xhrFactory_(); -}; - - -/** @override */ -goog.net.WrapperXmlHttpFactory.prototype.getOptions = function() { - return this.optionsFactory_(); -}; - - -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Low level handling of XMLHttpRequest. - * @author arv@google.com (Erik Arvidsson) - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.DefaultXmlHttpFactory'); -goog.provide('goog.net.XmlHttp'); -goog.provide('goog.net.XmlHttp.OptionType'); -goog.provide('goog.net.XmlHttp.ReadyState'); -goog.provide('goog.net.XmlHttpDefines'); - -goog.require('goog.asserts'); -goog.require('goog.net.WrapperXmlHttpFactory'); -goog.require('goog.net.XmlHttpFactory'); - - -/** - * Static class for creating XMLHttpRequest objects. - * @return {!goog.net.XhrLike.OrNative} A new XMLHttpRequest object. - */ -goog.net.XmlHttp = function() { - return goog.net.XmlHttp.factory_.createInstance(); -}; - - -/** - * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to - * true bypasses the ActiveX probing code. - * NOTE(ruilopes): Due to the way JSCompiler works, this define *will not* strip - * out the ActiveX probing code from binaries. To achieve this, use - * {@code goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR} instead. - * TODO(ruilopes): Collapse both defines. - */ -goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false); - - -/** @const */ -goog.net.XmlHttpDefines = {}; - - -/** - * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to - * true eliminates the ActiveX probing code. - */ -goog.define('goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR', false); + this.image_ = null; + /** + * @private + * @type {number|undefined} + */ + this.anchorX_ = undefined; -/** - * Gets the options to use with the XMLHttpRequest objects obtained using - * the static methods. - * @return {Object} The options. - */ -goog.net.XmlHttp.getOptions = function() { - return goog.net.XmlHttp.factory_.getOptions(); -}; + /** + * @private + * @type {number|undefined} + */ + this.anchorY_ = undefined; + /** + * @private + * @type {number|undefined} + */ + this.height_ = undefined; -/** - * Type of options that an XmlHttp object can have. - * @enum {number} - */ -goog.net.XmlHttp.OptionType = { /** - * Whether a goog.nullFunction should be used to clear the onreadystatechange - * handler instead of null. + * @private + * @type {number|undefined} */ - USE_NULL_FUNCTION: 0, + this.opacity_ = undefined; /** - * NOTE(user): In IE if send() errors on a *local* request the readystate - * is still changed to COMPLETE. We need to ignore it and allow the - * try/catch around send() to pick up the error. + * @private + * @type {number|undefined} */ - LOCAL_REQUEST_ERROR: 1 -}; + this.originX_ = undefined; + /** + * @private + * @type {number|undefined} + */ + this.originY_ = undefined; -/** - * Status constants for XMLHTTP, matches: - * http://msdn.microsoft.com/library/default.asp?url=/library/ - * en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp - * @enum {number} - */ -goog.net.XmlHttp.ReadyState = { /** - * Constant for when xmlhttprequest.readyState is uninitialized + * @private + * @type {boolean|undefined} */ - UNINITIALIZED: 0, + this.rotateWithView_ = undefined; /** - * Constant for when xmlhttprequest.readyState is loading. + * @private + * @type {number|undefined} */ - LOADING: 1, + this.rotation_ = undefined; /** - * Constant for when xmlhttprequest.readyState is loaded. + * @private + * @type {number|undefined} */ - LOADED: 2, + this.scale_ = undefined; /** - * Constant for when xmlhttprequest.readyState is in an interactive state. + * @private + * @type {boolean|undefined} */ - INTERACTIVE: 3, + this.snapToPixel_ = undefined; /** - * Constant for when xmlhttprequest.readyState is completed + * @private + * @type {number|undefined} */ - COMPLETE: 4 + this.width_ = undefined; + }; +goog.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay); /** - * The global factory instance for creating XMLHttpRequest objects. - * @type {goog.net.XmlHttpFactory} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. * @private + * @return {number} My end. */ -goog.net.XmlHttp.factory_; +ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = + function(flatCoordinates, offset, end, stride) { + return this.appendFlatCoordinates( + flatCoordinates, offset, end, stride, false); +}; /** - * Sets the factories for creating XMLHttpRequest objects and their options. - * @param {Function} factory The factory for XMLHttpRequest objects. - * @param {Function} optionsFactory The factory for options. - * @deprecated Use setGlobalFactory instead. + * @inheritDoc */ -goog.net.XmlHttp.setFactory = function(factory, optionsFactory) { - goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( - goog.asserts.assert(factory), - goog.asserts.assert(optionsFactory))); +ol.render.canvas.ImageReplay.prototype.drawPointGeometry = + function(pointGeometry, feature) { + if (!this.image_) { + return; + } + goog.asserts.assert(this.anchorX_ !== undefined, + 'this.anchorX_ should be defined'); + goog.asserts.assert(this.anchorY_ !== undefined, + 'this.anchorY_ should be defined'); + goog.asserts.assert(this.height_ !== undefined, + 'this.height_ should be defined'); + goog.asserts.assert(this.opacity_ !== undefined, + 'this.opacity_ should be defined'); + goog.asserts.assert(this.originX_ !== undefined, + 'this.originX_ should be defined'); + goog.asserts.assert(this.originY_ !== undefined, + 'this.originY_ should be defined'); + goog.asserts.assert(this.rotateWithView_ !== undefined, + 'this.rotateWithView_ should be defined'); + goog.asserts.assert(this.rotation_ !== undefined, + 'this.rotation_ should be defined'); + goog.asserts.assert(this.scale_ !== undefined, + 'this.scale_ should be defined'); + goog.asserts.assert(this.width_ !== undefined, + 'this.width_ should be defined'); + this.beginGeometry(pointGeometry, feature); + var flatCoordinates = pointGeometry.getFlatCoordinates(); + var stride = pointGeometry.getStride(); + var myBegin = this.coordinates.length; + var myEnd = this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + this.instructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.hitDetectionInstructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, + this.hitDetectionImage_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.endGeometry(pointGeometry, feature); }; /** - * Sets the global factory object. - * @param {!goog.net.XmlHttpFactory} factory New global factory object. + * @inheritDoc */ -goog.net.XmlHttp.setGlobalFactory = function(factory) { - goog.net.XmlHttp.factory_ = factory; +ol.render.canvas.ImageReplay.prototype.drawMultiPointGeometry = + function(multiPointGeometry, feature) { + if (!this.image_) { + return; + } + goog.asserts.assert(this.anchorX_ !== undefined, + 'this.anchorX_ should be defined'); + goog.asserts.assert(this.anchorY_ !== undefined, + 'this.anchorY_ should be defined'); + goog.asserts.assert(this.height_ !== undefined, + 'this.height_ should be defined'); + goog.asserts.assert(this.opacity_ !== undefined, + 'this.opacity_ should be defined'); + goog.asserts.assert(this.originX_ !== undefined, + 'this.originX_ should be defined'); + goog.asserts.assert(this.originY_ !== undefined, + 'this.originY_ should be defined'); + goog.asserts.assert(this.rotateWithView_ !== undefined, + 'this.rotateWithView_ should be defined'); + goog.asserts.assert(this.rotation_ !== undefined, + 'this.rotation_ should be defined'); + goog.asserts.assert(this.scale_ !== undefined, + 'this.scale_ should be defined'); + goog.asserts.assert(this.width_ !== undefined, + 'this.width_ should be defined'); + this.beginGeometry(multiPointGeometry, feature); + var flatCoordinates = multiPointGeometry.getFlatCoordinates(); + var stride = multiPointGeometry.getStride(); + var myBegin = this.coordinates.length; + var myEnd = this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + this.instructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.hitDetectionInstructions.push([ + ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, + this.hitDetectionImage_, + // Remaining arguments to DRAW_IMAGE are in alphabetical order + this.anchorX_, this.anchorY_, this.height_, this.opacity_, + this.originX_, this.originY_, this.rotateWithView_, this.rotation_, + this.scale_, this.snapToPixel_, this.width_ + ]); + this.endGeometry(multiPointGeometry, feature); }; - /** - * Default factory to use when creating xhr objects. You probably shouldn't be - * instantiating this directly, but rather using it via goog.net.XmlHttp. - * @extends {goog.net.XmlHttpFactory} - * @constructor + * @inheritDoc */ -goog.net.DefaultXmlHttpFactory = function() { - goog.net.XmlHttpFactory.call(this); +ol.render.canvas.ImageReplay.prototype.finish = function() { + this.reverseHitDetectionInstructions_(); + // FIXME this doesn't really protect us against further calls to draw*Geometry + this.anchorX_ = undefined; + this.anchorY_ = undefined; + this.hitDetectionImage_ = null; + this.image_ = null; + this.height_ = undefined; + this.scale_ = undefined; + this.opacity_ = undefined; + this.originX_ = undefined; + this.originY_ = undefined; + this.rotateWithView_ = undefined; + this.rotation_ = undefined; + this.snapToPixel_ = undefined; + this.width_ = undefined; }; -goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory); -/** @override */ -goog.net.DefaultXmlHttpFactory.prototype.createInstance = function() { - var progId = this.getProgId_(); - if (progId) { - return new ActiveXObject(progId); - } else { - return new XMLHttpRequest(); - } +/** + * @inheritDoc + */ +ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) { + goog.asserts.assert(imageStyle, 'imageStyle should not be null'); + var anchor = imageStyle.getAnchor(); + goog.asserts.assert(anchor, 'anchor should not be null'); + var size = imageStyle.getSize(); + goog.asserts.assert(size, 'size should not be null'); + var hitDetectionImage = imageStyle.getHitDetectionImage(1); + goog.asserts.assert(hitDetectionImage, + 'hitDetectionImage should not be null'); + var image = imageStyle.getImage(1); + goog.asserts.assert(image, 'image should not be null'); + var origin = imageStyle.getOrigin(); + goog.asserts.assert(origin, 'origin should not be null'); + this.anchorX_ = anchor[0]; + this.anchorY_ = anchor[1]; + this.hitDetectionImage_ = hitDetectionImage; + this.image_ = image; + this.height_ = size[1]; + this.opacity_ = imageStyle.getOpacity(); + this.originX_ = origin[0]; + this.originY_ = origin[1]; + this.rotateWithView_ = imageStyle.getRotateWithView(); + this.rotation_ = imageStyle.getRotation(); + this.scale_ = imageStyle.getScale(); + this.snapToPixel_ = imageStyle.getSnapToPixel(); + this.width_ = size[0]; }; -/** @override */ -goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() { - var progId = this.getProgId_(); - var options = {}; - if (progId) { - options[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] = true; - options[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] = true; - } - return options; + +/** + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @protected + * @struct + */ +ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution) { + + goog.base(this, tolerance, maxExtent, resolution); + + /** + * @private + * @type {{currentStrokeStyle: (string|undefined), + * currentLineCap: (string|undefined), + * currentLineDash: Array.<number>, + * currentLineJoin: (string|undefined), + * currentLineWidth: (number|undefined), + * currentMiterLimit: (number|undefined), + * lastStroke: number, + * strokeStyle: (string|undefined), + * lineCap: (string|undefined), + * lineDash: Array.<number>, + * lineJoin: (string|undefined), + * lineWidth: (number|undefined), + * miterLimit: (number|undefined)}|null} + */ + this.state_ = { + currentStrokeStyle: undefined, + currentLineCap: undefined, + currentLineDash: null, + currentLineJoin: undefined, + currentLineWidth: undefined, + currentMiterLimit: undefined, + lastStroke: 0, + strokeStyle: undefined, + lineCap: undefined, + lineDash: null, + lineJoin: undefined, + lineWidth: undefined, + miterLimit: undefined + }; + }; +goog.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay); /** - * The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized. - * @type {string|undefined} + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. * @private + * @return {number} end. */ -goog.net.DefaultXmlHttpFactory.prototype.ieProgId_; +ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = + function(flatCoordinates, offset, end, stride) { + var myBegin = this.coordinates.length; + var myEnd = this.appendFlatCoordinates( + flatCoordinates, offset, end, stride, false); + var moveToLineToInstruction = + [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; + this.instructions.push(moveToLineToInstruction); + this.hitDetectionInstructions.push(moveToLineToInstruction); + return end; +}; /** - * Initialize the private state used by other functions. - * @return {string} The ActiveX PROG ID string to use to create xhr's in IE. - * @private + * @inheritDoc */ -goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() { - if (goog.net.XmlHttp.ASSUME_NATIVE_XHR || - goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR) { - return ''; - } - - // The following blog post describes what PROG IDs to use to create the - // XMLHTTP object in Internet Explorer: - // http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx - // However we do not (yet) fully trust that this will be OK for old versions - // of IE on Win9x so we therefore keep the last 2. - if (!this.ieProgId_ && typeof XMLHttpRequest == 'undefined' && - typeof ActiveXObject != 'undefined') { - // Candidate Active X types. - var ACTIVE_X_IDENTS = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', - 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP']; - for (var i = 0; i < ACTIVE_X_IDENTS.length; i++) { - var candidate = ACTIVE_X_IDENTS[i]; - /** @preserveTry */ - try { - new ActiveXObject(candidate); - // NOTE(user): cannot assign progid and return candidate in one line - // because JSCompiler complaings: BUG 658126 - this.ieProgId_ = candidate; - return candidate; - } catch (e) { - // do nothing; try next choice - } +ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() { + if (!this.bufferedMaxExtent_) { + this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); + if (this.maxLineWidth > 0) { + var width = this.resolution * (this.maxLineWidth + 1) / 2; + ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); } - - // couldn't find any matches - throw Error('Could not create ActiveXObject. ActiveX might be disabled,' + - ' or MSXML might not be installed'); } - - return /** @type {string} */ (this.ieProgId_); + return this.bufferedMaxExtent_; }; -//Set the global factory to an instance of the default factory. -goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory()); - -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - /** - * @fileoverview Simple utilities for dealing with URI strings. - * - * This is intended to be a lightweight alternative to constructing goog.Uri - * objects. Whereas goog.Uri adds several kilobytes to the binary regardless - * of how much of its functionality you use, this is designed to be a set of - * mostly-independent utilities so that the compiler includes only what is - * necessary for the task. Estimated savings of porting is 5k pre-gzip and - * 1.5k post-gzip. To ensure the savings remain, future developers should - * avoid adding new functionality to existing functions, but instead create - * new ones and factor out shared code. - * - * Many of these utilities have limited functionality, tailored to common - * cases. The query parameter utilities assume that the parameter keys are - * already encoded, since most keys are compile-time alphanumeric strings. The - * query parameter mutation utilities also do not tolerate fragment identifiers. - * - * By design, these functions can be slower than goog.Uri equivalents. - * Repeated calls to some of functions may be quadratic in behavior for IE, - * although the effect is somewhat limited given the 2kb limit. - * - * One advantage of the limited functionality here is that this approach is - * less sensitive to differences in URI encodings than goog.Uri, since these - * functions operate on strings directly, rather than decoding them and - * then re-encoding. - * - * Uses features of RFC 3986 for parsing/formatting URIs: - * http://www.ietf.org/rfc/rfc3986.txt - * - * @author gboyer@google.com (Garrett Boyer) - The "lightened" design. - */ - -goog.provide('goog.uri.utils'); -goog.provide('goog.uri.utils.ComponentIndex'); -goog.provide('goog.uri.utils.QueryArray'); -goog.provide('goog.uri.utils.QueryValue'); -goog.provide('goog.uri.utils.StandardQueryParam'); - -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.userAgent'); - - -/** - * Character codes inlined to avoid object allocations due to charCode. - * @enum {number} * @private */ -goog.uri.utils.CharCode_ = { - AMPERSAND: 38, - EQUAL: 61, - HASH: 35, - QUESTION: 63 +ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() { + var state = this.state_; + var strokeStyle = state.strokeStyle; + var lineCap = state.lineCap; + var lineDash = state.lineDash; + var lineJoin = state.lineJoin; + var lineWidth = state.lineWidth; + var miterLimit = state.miterLimit; + goog.asserts.assert(strokeStyle !== undefined, + 'strokeStyle should be defined'); + goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined'); + goog.asserts.assert(lineDash, 'lineDash should not be null'); + goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined'); + goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined'); + goog.asserts.assert(miterLimit !== undefined, 'miterLimit should be defined'); + if (state.currentStrokeStyle != strokeStyle || + state.currentLineCap != lineCap || + !goog.array.equals(state.currentLineDash, lineDash) || + state.currentLineJoin != lineJoin || + state.currentLineWidth != lineWidth || + state.currentMiterLimit != miterLimit) { + if (state.lastStroke != this.coordinates.length) { + this.instructions.push( + [ol.render.canvas.Instruction.STROKE]); + state.lastStroke = this.coordinates.length; + } + this.instructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash], + [ol.render.canvas.Instruction.BEGIN_PATH]); + state.currentStrokeStyle = strokeStyle; + state.currentLineCap = lineCap; + state.currentLineDash = lineDash; + state.currentLineJoin = lineJoin; + state.currentLineWidth = lineWidth; + state.currentMiterLimit = miterLimit; + } }; /** - * Builds a URI string from already-encoded parts. - * - * No encoding is performed. Any component may be omitted as either null or - * undefined. - * - * @param {?string=} opt_scheme The scheme such as 'http'. - * @param {?string=} opt_userInfo The user name before the '@'. - * @param {?string=} opt_domain The domain such as 'www.google.com', already - * URI-encoded. - * @param {(string|number|null)=} opt_port The port number. - * @param {?string=} opt_path The path, already URI-encoded. If it is not - * empty, it must begin with a slash. - * @param {?string=} opt_queryData The URI-encoded query data. - * @param {?string=} opt_fragment The URI-encoded fragment identifier. - * @return {string} The fully combined URI. + * @inheritDoc */ -goog.uri.utils.buildFromEncodedParts = function(opt_scheme, opt_userInfo, - opt_domain, opt_port, opt_path, opt_queryData, opt_fragment) { - var out = ''; - - if (opt_scheme) { - out += opt_scheme + ':'; - } - - if (opt_domain) { - out += '//'; - - if (opt_userInfo) { - out += opt_userInfo + '@'; - } - - out += opt_domain; - - if (opt_port) { - out += ':' + opt_port; - } - } - - if (opt_path) { - out += opt_path; - } - - if (opt_queryData) { - out += '?' + opt_queryData; - } - - if (opt_fragment) { - out += '#' + opt_fragment; +ol.render.canvas.LineStringReplay.prototype.drawLineStringGeometry = + function(lineStringGeometry, feature) { + var state = this.state_; + goog.asserts.assert(state, 'state should not be null'); + var strokeStyle = state.strokeStyle; + var lineWidth = state.lineWidth; + if (strokeStyle === undefined || lineWidth === undefined) { + return; } - - return out; + this.setStrokeStyle_(); + this.beginGeometry(lineStringGeometry, feature); + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash], + [ol.render.canvas.Instruction.BEGIN_PATH]); + var flatCoordinates = lineStringGeometry.getFlatCoordinates(); + var stride = lineStringGeometry.getStride(); + this.drawFlatCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); + this.endGeometry(lineStringGeometry, feature); }; /** - * A regular expression for breaking a URI into its component parts. - * - * {@link http://www.ietf.org/rfc/rfc3986.txt} says in Appendix B - * As the "first-match-wins" algorithm is identical to the "greedy" - * disambiguation method used by POSIX regular expressions, it is natural and - * commonplace to use a regular expression for parsing the potential five - * components of a URI reference. - * - * The following line is the regular expression for breaking-down a - * well-formed URI reference into its components. - * - * <pre> - * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? - * 12 3 4 5 6 7 8 9 - * </pre> - * - * The numbers in the second line above are only to assist readability; they - * indicate the reference points for each subexpression (i.e., each paired - * parenthesis). We refer to the value matched for subexpression <n> as $<n>. - * For example, matching the above expression to - * <pre> - * http://www.ics.uci.edu/pub/ietf/uri/#Related - * </pre> - * results in the following subexpression matches: - * <pre> - * $1 = http: - * $2 = http - * $3 = //www.ics.uci.edu - * $4 = www.ics.uci.edu - * $5 = /pub/ietf/uri/ - * $6 = <undefined> - * $7 = <undefined> - * $8 = #Related - * $9 = Related - * </pre> - * where <undefined> indicates that the component is not present, as is the - * case for the query component in the above example. Therefore, we can - * determine the value of the five components as - * <pre> - * scheme = $2 - * authority = $4 - * path = $5 - * query = $7 - * fragment = $9 - * </pre> - * - * The regular expression has been modified slightly to expose the - * userInfo, domain, and port separately from the authority. - * The modified version yields - * <pre> - * $1 = http scheme - * $2 = <undefined> userInfo -\ - * $3 = www.ics.uci.edu domain | authority - * $4 = <undefined> port -/ - * $5 = /pub/ietf/uri/ path - * $6 = <undefined> query without ? - * $7 = Related fragment without # - * </pre> - * @type {!RegExp} - * @private + * @inheritDoc */ -goog.uri.utils.splitRe_ = new RegExp( - '^' + - '(?:' + - '([^:/?#.]+)' + // scheme - ignore special characters - // used by other URL parts such as :, - // ?, /, #, and . - ':)?' + - '(?://' + - '(?:([^/?#]*)@)?' + // userInfo - '([^/#?]*?)' + // domain - '(?::([0-9]+))?' + // port - '(?=[/#?]|$)' + // authority-terminating character - ')?' + - '([^?#]+)?' + // path - '(?:\\?([^#]*))?' + // query - '(?:#(.*))?' + // fragment - '$'); +ol.render.canvas.LineStringReplay.prototype.drawMultiLineStringGeometry = + function(multiLineStringGeometry, feature) { + var state = this.state_; + goog.asserts.assert(state, 'state should not be null'); + var strokeStyle = state.strokeStyle; + var lineWidth = state.lineWidth; + if (strokeStyle === undefined || lineWidth === undefined) { + return; + } + this.setStrokeStyle_(); + this.beginGeometry(multiLineStringGeometry, feature); + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash], + [ol.render.canvas.Instruction.BEGIN_PATH]); + var ends = multiLineStringGeometry.getEnds(); + var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); + var stride = multiLineStringGeometry.getStride(); + var offset = 0; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + offset = this.drawFlatCoordinates_( + flatCoordinates, offset, ends[i], stride); + } + this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]); + this.endGeometry(multiLineStringGeometry, feature); +}; /** - * The index of each URI component in the return value of goog.uri.utils.split. - * @enum {number} + * @inheritDoc */ -goog.uri.utils.ComponentIndex = { - SCHEME: 1, - USER_INFO: 2, - DOMAIN: 3, - PORT: 4, - PATH: 5, - QUERY_DATA: 6, - FRAGMENT: 7 +ol.render.canvas.LineStringReplay.prototype.finish = function() { + var state = this.state_; + goog.asserts.assert(state, 'state should not be null'); + if (state.lastStroke != this.coordinates.length) { + this.instructions.push([ol.render.canvas.Instruction.STROKE]); + } + this.reverseHitDetectionInstructions_(); + this.state_ = null; }; /** - * Splits a URI into its component parts. - * - * Each component can be accessed via the component indices; for example: - * <pre> - * goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA]; - * </pre> - * - * @param {string} uri The URI string to examine. - * @return {!Array<string|undefined>} Each component still URI-encoded. - * Each component that is present will contain the encoded value, whereas - * components that are not present will be undefined or empty, depending - * on the browser's regular expression implementation. Never null, since - * arbitrary strings may still look like path names. + * @inheritDoc */ -goog.uri.utils.split = function(uri) { - goog.uri.utils.phishingProtection_(); +ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = + function(fillStyle, strokeStyle) { + goog.asserts.assert(this.state_, 'this.state_ should not be null'); + goog.asserts.assert(!fillStyle, 'fillStyle should be null'); + goog.asserts.assert(strokeStyle, 'strokeStyle should not be null'); + var strokeStyleColor = strokeStyle.getColor(); + this.state_.strokeStyle = ol.color.asString(strokeStyleColor ? + strokeStyleColor : ol.render.canvas.defaultStrokeStyle); + var strokeStyleLineCap = strokeStyle.getLineCap(); + this.state_.lineCap = strokeStyleLineCap !== undefined ? + strokeStyleLineCap : ol.render.canvas.defaultLineCap; + var strokeStyleLineDash = strokeStyle.getLineDash(); + this.state_.lineDash = strokeStyleLineDash ? + strokeStyleLineDash : ol.render.canvas.defaultLineDash; + var strokeStyleLineJoin = strokeStyle.getLineJoin(); + this.state_.lineJoin = strokeStyleLineJoin !== undefined ? + strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; + var strokeStyleWidth = strokeStyle.getWidth(); + this.state_.lineWidth = strokeStyleWidth !== undefined ? + strokeStyleWidth : ol.render.canvas.defaultLineWidth; + var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); + this.state_.miterLimit = strokeStyleMiterLimit !== undefined ? + strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; - // See @return comment -- never null. - return /** @type {!Array<string|undefined>} */ ( - uri.match(goog.uri.utils.splitRe_)); + if (this.state_.lineWidth > this.maxLineWidth) { + this.maxLineWidth = this.state_.lineWidth; + // invalidate the buffered max extent cache + this.bufferedMaxExtent_ = null; + } }; -/** - * Safari has a nasty bug where if you have an http URL with a username, e.g., - * http://evil.com%2F@google.com/ - * Safari will report that window.location.href is - * http://evil.com/google.com/ - * so that anyone who tries to parse the domain of that URL will get - * the wrong domain. We've seen exploits where people use this to trick - * Safari into loading resources from evil domains. - * - * To work around this, we run a little "Safari phishing check", and throw - * an exception if we see this happening. - * - * There is no convenient place to put this check. We apply it to - * anyone doing URI parsing on Webkit. We're not happy about this, but - * it fixes the problem. - * - * This should be removed once Safari fixes their bug. - * - * Exploit reported by Masato Kinugawa. - * - * @type {boolean} - * @private - */ -goog.uri.utils.needsPhishingProtection_ = goog.userAgent.WEBKIT; - /** - * Check to see if the user is being phished. - * @private + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @protected + * @struct */ -goog.uri.utils.phishingProtection_ = function() { - if (goog.uri.utils.needsPhishingProtection_) { - // Turn protection off, so that we don't recurse. - goog.uri.utils.needsPhishingProtection_ = false; - - // Use quoted access, just in case the user isn't using location externs. - var location = goog.global['location']; - if (location) { - var href = location['href']; - if (href) { - var domain = goog.uri.utils.getDomain(href); - if (domain && domain != location['hostname']) { - // Phishing attack - goog.uri.utils.needsPhishingProtection_ = true; - throw Error(); - } - } - } - } -}; +ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) { + goog.base(this, tolerance, maxExtent, resolution); -/** - * @param {?string} uri A possibly null string. - * @param {boolean=} opt_preserveReserved If true, percent-encoding of RFC-3986 - * reserved characters will not be removed. - * @return {?string} The string URI-decoded, or null if uri is null. - * @private - */ -goog.uri.utils.decodeIfPossible_ = function(uri, opt_preserveReserved) { - if (!uri) { - return uri; - } + /** + * @private + * @type {{currentFillStyle: (string|undefined), + * currentStrokeStyle: (string|undefined), + * currentLineCap: (string|undefined), + * currentLineDash: Array.<number>, + * currentLineJoin: (string|undefined), + * currentLineWidth: (number|undefined), + * currentMiterLimit: (number|undefined), + * fillStyle: (string|undefined), + * strokeStyle: (string|undefined), + * lineCap: (string|undefined), + * lineDash: Array.<number>, + * lineJoin: (string|undefined), + * lineWidth: (number|undefined), + * miterLimit: (number|undefined)}|null} + */ + this.state_ = { + currentFillStyle: undefined, + currentStrokeStyle: undefined, + currentLineCap: undefined, + currentLineDash: null, + currentLineJoin: undefined, + currentLineWidth: undefined, + currentMiterLimit: undefined, + fillStyle: undefined, + strokeStyle: undefined, + lineCap: undefined, + lineDash: null, + lineJoin: undefined, + lineWidth: undefined, + miterLimit: undefined + }; - return opt_preserveReserved ? decodeURI(uri) : decodeURIComponent(uri); }; +goog.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay); /** - * Gets a URI component by index. - * - * It is preferred to use the getPathEncoded() variety of functions ahead, - * since they are more readable. - * - * @param {goog.uri.utils.ComponentIndex} componentIndex The component index. - * @param {string} uri The URI to examine. - * @return {?string} The still-encoded component, or null if the component - * is not present. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. * @private + * @return {number} End. */ -goog.uri.utils.getComponentByIndex_ = function(componentIndex, uri) { - // Convert undefined, null, and empty string into null. - return goog.uri.utils.split(uri)[componentIndex] || null; +ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = + function(flatCoordinates, offset, ends, stride) { + var state = this.state_; + var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; + this.instructions.push(beginPathInstruction); + this.hitDetectionInstructions.push(beginPathInstruction); + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + var myBegin = this.coordinates.length; + var myEnd = this.appendFlatCoordinates( + flatCoordinates, offset, end, stride, true); + var moveToLineToInstruction = + [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd]; + var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH]; + this.instructions.push(moveToLineToInstruction, closePathInstruction); + this.hitDetectionInstructions.push(moveToLineToInstruction, + closePathInstruction); + offset = end; + } + // FIXME is it quicker to fill and stroke each polygon individually, + // FIXME or all polygons together? + var fillInstruction = [ol.render.canvas.Instruction.FILL]; + this.hitDetectionInstructions.push(fillInstruction); + if (state.fillStyle !== undefined) { + this.instructions.push(fillInstruction); + } + if (state.strokeStyle !== undefined) { + goog.asserts.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; + this.instructions.push(strokeInstruction); + this.hitDetectionInstructions.push(strokeInstruction); + } + return offset; }; /** - * @param {string} uri The URI to examine. - * @return {?string} The protocol or scheme, or null if none. Does not - * include trailing colons or slashes. + * @inheritDoc */ -goog.uri.utils.getScheme = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.SCHEME, uri); +ol.render.canvas.PolygonReplay.prototype.drawCircleGeometry = + function(circleGeometry, feature) { + var state = this.state_; + goog.asserts.assert(state, 'state should not be null'); + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + if (fillStyle === undefined && strokeStyle === undefined) { + return; + } + if (strokeStyle !== undefined) { + goog.asserts.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + } + this.setFillStrokeStyles_(); + this.beginGeometry(circleGeometry, feature); + // always fill the circle for hit detection + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, + ol.color.asString(ol.render.canvas.defaultFillStyle)]); + if (state.strokeStyle !== undefined) { + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash]); + } + var flatCoordinates = circleGeometry.getFlatCoordinates(); + var stride = circleGeometry.getStride(); + var myBegin = this.coordinates.length; + this.appendFlatCoordinates( + flatCoordinates, 0, flatCoordinates.length, stride, false); + var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH]; + var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin]; + this.instructions.push(beginPathInstruction, circleInstruction); + this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction); + var fillInstruction = [ol.render.canvas.Instruction.FILL]; + this.hitDetectionInstructions.push(fillInstruction); + if (state.fillStyle !== undefined) { + this.instructions.push(fillInstruction); + } + if (state.strokeStyle !== undefined) { + goog.asserts.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + var strokeInstruction = [ol.render.canvas.Instruction.STROKE]; + this.instructions.push(strokeInstruction); + this.hitDetectionInstructions.push(strokeInstruction); + } + this.endGeometry(circleGeometry, feature); }; /** - * Gets the effective scheme for the URL. If the URL is relative then the - * scheme is derived from the page's location. - * @param {string} uri The URI to examine. - * @return {string} The protocol or scheme, always lower case. + * @inheritDoc */ -goog.uri.utils.getEffectiveScheme = function(uri) { - var scheme = goog.uri.utils.getScheme(uri); - if (!scheme && goog.global.self && goog.global.self.location) { - var protocol = goog.global.self.location.protocol; - scheme = protocol.substr(0, protocol.length - 1); +ol.render.canvas.PolygonReplay.prototype.drawPolygonGeometry = + function(polygonGeometry, feature) { + var state = this.state_; + goog.asserts.assert(state, 'state should not be null'); + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + if (fillStyle === undefined && strokeStyle === undefined) { + return; } - // NOTE: When called from a web worker in Firefox 3.5, location maybe null. - // All other browsers with web workers support self.location from the worker. - return scheme ? scheme.toLowerCase() : ''; + if (strokeStyle !== undefined) { + goog.asserts.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + } + this.setFillStrokeStyles_(); + this.beginGeometry(polygonGeometry, feature); + // always fill the polygon for hit detection + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, + ol.color.asString(ol.render.canvas.defaultFillStyle)]); + if (state.strokeStyle !== undefined) { + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash]); + } + var ends = polygonGeometry.getEnds(); + var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates(); + var stride = polygonGeometry.getStride(); + this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride); + this.endGeometry(polygonGeometry, feature); }; /** - * @param {string} uri The URI to examine. - * @return {?string} The user name still encoded, or null if none. + * @inheritDoc */ -goog.uri.utils.getUserInfoEncoded = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.USER_INFO, uri); +ol.render.canvas.PolygonReplay.prototype.drawMultiPolygonGeometry = + function(multiPolygonGeometry, feature) { + var state = this.state_; + goog.asserts.assert(state, 'state should not be null'); + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + if (fillStyle === undefined && strokeStyle === undefined) { + return; + } + if (strokeStyle !== undefined) { + goog.asserts.assert(state.lineWidth !== undefined, + 'state.lineWidth should be defined'); + } + this.setFillStrokeStyles_(); + this.beginGeometry(multiPolygonGeometry, feature); + // always fill the multi-polygon for hit detection + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, + ol.color.asString(ol.render.canvas.defaultFillStyle)]); + if (state.strokeStyle !== undefined) { + this.hitDetectionInstructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin, + state.miterLimit, state.lineDash]); + } + var endss = multiPolygonGeometry.getEndss(); + var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); + var stride = multiPolygonGeometry.getStride(); + var offset = 0; + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + offset = this.drawFlatCoordinatess_( + flatCoordinates, offset, endss[i], stride); + } + this.endGeometry(multiPolygonGeometry, feature); }; /** - * @param {string} uri The URI to examine. - * @return {?string} The decoded user info, or null if none. + * @inheritDoc */ -goog.uri.utils.getUserInfo = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getUserInfoEncoded(uri)); +ol.render.canvas.PolygonReplay.prototype.finish = function() { + goog.asserts.assert(this.state_, 'this.state_ should not be null'); + this.reverseHitDetectionInstructions_(); + this.state_ = null; + // We want to preserve topology when drawing polygons. Polygons are + // simplified using quantization and point elimination. However, we might + // have received a mix of quantized and non-quantized geometries, so ensure + // that all are quantized by quantizing all coordinates in the batch. + var tolerance = this.tolerance; + if (tolerance !== 0) { + var coordinates = this.coordinates; + var i, ii; + for (i = 0, ii = coordinates.length; i < ii; ++i) { + coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance); + } + } }; /** - * @param {string} uri The URI to examine. - * @return {?string} The domain name still encoded, or null if none. + * @inheritDoc */ -goog.uri.utils.getDomainEncoded = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.DOMAIN, uri); +ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() { + if (!this.bufferedMaxExtent_) { + this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent); + if (this.maxLineWidth > 0) { + var width = this.resolution * (this.maxLineWidth + 1) / 2; + ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); + } + } + return this.bufferedMaxExtent_; }; /** - * @param {string} uri The URI to examine. - * @return {?string} The decoded domain, or null if none. + * @inheritDoc */ -goog.uri.utils.getDomain = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getDomainEncoded(uri), true /* opt_preserveReserved */); +ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = + function(fillStyle, strokeStyle) { + goog.asserts.assert(this.state_, 'this.state_ should not be null'); + goog.asserts.assert(fillStyle || strokeStyle, + 'fillStyle or strokeStyle should not be null'); + var state = this.state_; + if (fillStyle) { + var fillStyleColor = fillStyle.getColor(); + state.fillStyle = ol.color.asString(fillStyleColor ? + fillStyleColor : ol.render.canvas.defaultFillStyle); + } else { + state.fillStyle = undefined; + } + if (strokeStyle) { + var strokeStyleColor = strokeStyle.getColor(); + state.strokeStyle = ol.color.asString(strokeStyleColor ? + strokeStyleColor : ol.render.canvas.defaultStrokeStyle); + var strokeStyleLineCap = strokeStyle.getLineCap(); + state.lineCap = strokeStyleLineCap !== undefined ? + strokeStyleLineCap : ol.render.canvas.defaultLineCap; + var strokeStyleLineDash = strokeStyle.getLineDash(); + state.lineDash = strokeStyleLineDash ? + strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; + var strokeStyleLineJoin = strokeStyle.getLineJoin(); + state.lineJoin = strokeStyleLineJoin !== undefined ? + strokeStyleLineJoin : ol.render.canvas.defaultLineJoin; + var strokeStyleWidth = strokeStyle.getWidth(); + state.lineWidth = strokeStyleWidth !== undefined ? + strokeStyleWidth : ol.render.canvas.defaultLineWidth; + var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); + state.miterLimit = strokeStyleMiterLimit !== undefined ? + strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; + + if (state.lineWidth > this.maxLineWidth) { + this.maxLineWidth = state.lineWidth; + // invalidate the buffered max extent cache + this.bufferedMaxExtent_ = null; + } + } else { + state.strokeStyle = undefined; + state.lineCap = undefined; + state.lineDash = null; + state.lineJoin = undefined; + state.lineWidth = undefined; + state.miterLimit = undefined; + } }; /** - * @param {string} uri The URI to examine. - * @return {?number} The port number, or null if none. + * @private */ -goog.uri.utils.getPort = function(uri) { - // Coerce to a number. If the result of getComponentByIndex_ is null or - // non-numeric, the number coersion yields NaN. This will then return - // null for all non-numeric cases (though also zero, which isn't a relevant - // port number). - return Number(goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.PORT, uri)) || null; +ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() { + var state = this.state_; + var fillStyle = state.fillStyle; + var strokeStyle = state.strokeStyle; + var lineCap = state.lineCap; + var lineDash = state.lineDash; + var lineJoin = state.lineJoin; + var lineWidth = state.lineWidth; + var miterLimit = state.miterLimit; + if (fillStyle !== undefined && state.currentFillStyle != fillStyle) { + this.instructions.push( + [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]); + state.currentFillStyle = state.fillStyle; + } + if (strokeStyle !== undefined) { + goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined'); + goog.asserts.assert(lineDash, 'lineDash should not be null'); + goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined'); + goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined'); + goog.asserts.assert(miterLimit !== undefined, + 'miterLimit should be defined'); + if (state.currentStrokeStyle != strokeStyle || + state.currentLineCap != lineCap || + state.currentLineDash != lineDash || + state.currentLineJoin != lineJoin || + state.currentLineWidth != lineWidth || + state.currentMiterLimit != miterLimit) { + this.instructions.push( + [ol.render.canvas.Instruction.SET_STROKE_STYLE, + strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]); + state.currentStrokeStyle = strokeStyle; + state.currentLineCap = lineCap; + state.currentLineDash = lineDash; + state.currentLineJoin = lineJoin; + state.currentLineWidth = lineWidth; + state.currentMiterLimit = miterLimit; + } + } }; + /** - * @param {string} uri The URI to examine. - * @return {?string} The path still encoded, or null if none. Includes the - * leading slash, if any. + * @constructor + * @extends {ol.render.canvas.Replay} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Maximum extent. + * @param {number} resolution Resolution. + * @protected + * @struct */ -goog.uri.utils.getPathEncoded = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.PATH, uri); -}; +ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution) { + goog.base(this, tolerance, maxExtent, resolution); -/** - * @param {string} uri The URI to examine. - * @return {?string} The decoded path, or null if none. Includes the leading - * slash, if any. - */ -goog.uri.utils.getPath = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getPathEncoded(uri), true /* opt_preserveReserved */); -}; + /** + * @private + * @type {?ol.render.canvas.FillState} + */ + this.replayFillState_ = null; + /** + * @private + * @type {?ol.render.canvas.StrokeState} + */ + this.replayStrokeState_ = null; -/** - * @param {string} uri The URI to examine. - * @return {?string} The query data still encoded, or null if none. Does not - * include the question mark itself. - */ -goog.uri.utils.getQueryData = function(uri) { - return goog.uri.utils.getComponentByIndex_( - goog.uri.utils.ComponentIndex.QUERY_DATA, uri); -}; + /** + * @private + * @type {?ol.render.canvas.TextState} + */ + this.replayTextState_ = null; + /** + * @private + * @type {string} + */ + this.text_ = ''; -/** - * @param {string} uri The URI to examine. - * @return {?string} The fragment identifier, or null if none. Does not - * include the hash mark itself. - */ -goog.uri.utils.getFragmentEncoded = function(uri) { - // The hash mark may not appear in any other part of the URL. - var hashIndex = uri.indexOf('#'); - return hashIndex < 0 ? null : uri.substr(hashIndex + 1); -}; + /** + * @private + * @type {number} + */ + this.textOffsetX_ = 0; + /** + * @private + * @type {number} + */ + this.textOffsetY_ = 0; -/** - * @param {string} uri The URI to examine. - * @param {?string} fragment The encoded fragment identifier, or null if none. - * Does not include the hash mark itself. - * @return {string} The URI with the fragment set. - */ -goog.uri.utils.setFragmentEncoded = function(uri, fragment) { - return goog.uri.utils.removeFragment(uri) + (fragment ? '#' + fragment : ''); -}; + /** + * @private + * @type {number} + */ + this.textRotation_ = 0; + /** + * @private + * @type {number} + */ + this.textScale_ = 0; -/** - * @param {string} uri The URI to examine. - * @return {?string} The decoded fragment identifier, or null if none. Does - * not include the hash mark. - */ -goog.uri.utils.getFragment = function(uri) { - return goog.uri.utils.decodeIfPossible_( - goog.uri.utils.getFragmentEncoded(uri)); -}; + /** + * @private + * @type {?ol.render.canvas.FillState} + */ + this.textFillState_ = null; + /** + * @private + * @type {?ol.render.canvas.StrokeState} + */ + this.textStrokeState_ = null; + + /** + * @private + * @type {?ol.render.canvas.TextState} + */ + this.textState_ = null; -/** - * Extracts everything up to the port of the URI. - * @param {string} uri The URI string. - * @return {string} Everything up to and including the port. - */ -goog.uri.utils.getHost = function(uri) { - var pieces = goog.uri.utils.split(uri); - return goog.uri.utils.buildFromEncodedParts( - pieces[goog.uri.utils.ComponentIndex.SCHEME], - pieces[goog.uri.utils.ComponentIndex.USER_INFO], - pieces[goog.uri.utils.ComponentIndex.DOMAIN], - pieces[goog.uri.utils.ComponentIndex.PORT]); }; +goog.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay); /** - * Extracts the path of the URL and everything after. - * @param {string} uri The URI string. - * @return {string} The URI, starting at the path and including the query - * parameters and fragment identifier. + * @inheritDoc */ -goog.uri.utils.getPathAndAfter = function(uri) { - var pieces = goog.uri.utils.split(uri); - return goog.uri.utils.buildFromEncodedParts(null, null, null, null, - pieces[goog.uri.utils.ComponentIndex.PATH], - pieces[goog.uri.utils.ComponentIndex.QUERY_DATA], - pieces[goog.uri.utils.ComponentIndex.FRAGMENT]); +ol.render.canvas.TextReplay.prototype.drawText = + function(flatCoordinates, offset, end, stride, geometry, feature) { + if (this.text_ === '' || !this.textState_ || + (!this.textFillState_ && !this.textStrokeState_)) { + return; + } + if (this.textFillState_) { + this.setReplayFillState_(this.textFillState_); + } + if (this.textStrokeState_) { + this.setReplayStrokeState_(this.textStrokeState_); + } + this.setReplayTextState_(this.textState_); + this.beginGeometry(geometry, feature); + var myBegin = this.coordinates.length; + var myEnd = + this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false); + var fill = !!this.textFillState_; + var stroke = !!this.textStrokeState_; + var drawTextInstruction = [ + ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_, + this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_, + fill, stroke]; + this.instructions.push(drawTextInstruction); + this.hitDetectionInstructions.push(drawTextInstruction); + this.endGeometry(geometry, feature); }; /** - * Gets the URI with the fragment identifier removed. - * @param {string} uri The URI to examine. - * @return {string} Everything preceding the hash mark. + * @param {ol.render.canvas.FillState} fillState Fill state. + * @private */ -goog.uri.utils.removeFragment = function(uri) { - // The hash mark may not appear in any other part of the URL. - var hashIndex = uri.indexOf('#'); - return hashIndex < 0 ? uri : uri.substr(0, hashIndex); +ol.render.canvas.TextReplay.prototype.setReplayFillState_ = + function(fillState) { + var replayFillState = this.replayFillState_; + if (replayFillState && + replayFillState.fillStyle == fillState.fillStyle) { + return; + } + var setFillStyleInstruction = + [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle]; + this.instructions.push(setFillStyleInstruction); + this.hitDetectionInstructions.push(setFillStyleInstruction); + if (!replayFillState) { + this.replayFillState_ = { + fillStyle: fillState.fillStyle + }; + } else { + replayFillState.fillStyle = fillState.fillStyle; + } }; /** - * Ensures that two URI's have the exact same domain, scheme, and port. - * - * Unlike the version in goog.Uri, this checks protocol, and therefore is - * suitable for checking against the browser's same-origin policy. - * - * @param {string} uri1 The first URI. - * @param {string} uri2 The second URI. - * @return {boolean} Whether they have the same scheme, domain and port. + * @param {ol.render.canvas.StrokeState} strokeState Stroke state. + * @private */ -goog.uri.utils.haveSameDomain = function(uri1, uri2) { - var pieces1 = goog.uri.utils.split(uri1); - var pieces2 = goog.uri.utils.split(uri2); - return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] == - pieces2[goog.uri.utils.ComponentIndex.DOMAIN] && - pieces1[goog.uri.utils.ComponentIndex.SCHEME] == - pieces2[goog.uri.utils.ComponentIndex.SCHEME] && - pieces1[goog.uri.utils.ComponentIndex.PORT] == - pieces2[goog.uri.utils.ComponentIndex.PORT]; +ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = + function(strokeState) { + var replayStrokeState = this.replayStrokeState_; + if (replayStrokeState && + replayStrokeState.lineCap == strokeState.lineCap && + replayStrokeState.lineDash == strokeState.lineDash && + replayStrokeState.lineJoin == strokeState.lineJoin && + replayStrokeState.lineWidth == strokeState.lineWidth && + replayStrokeState.miterLimit == strokeState.miterLimit && + replayStrokeState.strokeStyle == strokeState.strokeStyle) { + return; + } + var setStrokeStyleInstruction = [ + ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle, + strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin, + strokeState.miterLimit, strokeState.lineDash, false + ]; + this.instructions.push(setStrokeStyleInstruction); + this.hitDetectionInstructions.push(setStrokeStyleInstruction); + if (!replayStrokeState) { + this.replayStrokeState_ = { + lineCap: strokeState.lineCap, + lineDash: strokeState.lineDash, + lineJoin: strokeState.lineJoin, + lineWidth: strokeState.lineWidth, + miterLimit: strokeState.miterLimit, + strokeStyle: strokeState.strokeStyle + }; + } else { + replayStrokeState.lineCap = strokeState.lineCap; + replayStrokeState.lineDash = strokeState.lineDash; + replayStrokeState.lineJoin = strokeState.lineJoin; + replayStrokeState.lineWidth = strokeState.lineWidth; + replayStrokeState.miterLimit = strokeState.miterLimit; + replayStrokeState.strokeStyle = strokeState.strokeStyle; + } }; /** - * Asserts that there are no fragment or query identifiers, only in uncompiled - * mode. - * @param {string} uri The URI to examine. + * @param {ol.render.canvas.TextState} textState Text state. * @private */ -goog.uri.utils.assertNoFragmentsOrQueries_ = function(uri) { - // NOTE: would use goog.asserts here, but jscompiler doesn't know that - // indexOf has no side effects. - if (goog.DEBUG && (uri.indexOf('#') >= 0 || uri.indexOf('?') >= 0)) { - throw Error('goog.uri.utils: Fragment or query identifiers are not ' + - 'supported: [' + uri + ']'); +ol.render.canvas.TextReplay.prototype.setReplayTextState_ = + function(textState) { + var replayTextState = this.replayTextState_; + if (replayTextState && + replayTextState.font == textState.font && + replayTextState.textAlign == textState.textAlign && + replayTextState.textBaseline == textState.textBaseline) { + return; + } + var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE, + textState.font, textState.textAlign, textState.textBaseline]; + this.instructions.push(setTextStyleInstruction); + this.hitDetectionInstructions.push(setTextStyleInstruction); + if (!replayTextState) { + this.replayTextState_ = { + font: textState.font, + textAlign: textState.textAlign, + textBaseline: textState.textBaseline + }; + } else { + replayTextState.font = textState.font; + replayTextState.textAlign = textState.textAlign; + replayTextState.textBaseline = textState.textBaseline; } }; /** - * Supported query parameter values by the parameter serializing utilities. - * - * If a value is null or undefined, the key-value pair is skipped, as an easy - * way to omit parameters conditionally. Non-array parameters are converted - * to a string and URI encoded. Array values are expanded into multiple - * &key=value pairs, with each element stringized and URI-encoded. - * - * @typedef {*} + * @inheritDoc */ -goog.uri.utils.QueryValue; - - -/** - * An array representing a set of query parameters with alternating keys - * and values. - * - * Keys are assumed to be URI encoded already and live at even indices. See - * goog.uri.utils.QueryValue for details on how parameter values are encoded. - * - * Example: - * <pre> - * var data = [ - * // Simple param: ?name=BobBarker - * 'name', 'BobBarker', - * // Conditional param -- may be omitted entirely. - * 'specialDietaryNeeds', hasDietaryNeeds() ? getDietaryNeeds() : null, - * // Multi-valued param: &house=LosAngeles&house=NewYork&house=null - * 'house', ['LosAngeles', 'NewYork', null] - * ]; - * </pre> - * - * @typedef {!Array<string|goog.uri.utils.QueryValue>} - */ -goog.uri.utils.QueryArray; - - -/** - * Parses encoded query parameters and calls callback function for every - * parameter found in the string. - * - * Missing value of parameter (e.g. “…&key&…”) is treated as if the value was an - * empty string. Keys may be empty strings (e.g. “…&=value&…”) which also means - * that “…&=&…” and “…&&…” will result in an empty key and value. - * - * @param {string} encodedQuery Encoded query string excluding question mark at - * the beginning. - * @param {function(string, string)} callback Function called for every - * parameter found in query string. The first argument (name) will not be - * urldecoded (so the function is consistent with buildQueryData), but the - * second will. If the parameter has no value (i.e. “=” was not present) - * the second argument (value) will be an empty string. - */ -goog.uri.utils.parseQueryData = function(encodedQuery, callback) { - if (!encodedQuery) { - return; - } - var pairs = encodedQuery.split('&'); - for (var i = 0; i < pairs.length; i++) { - var indexOfEquals = pairs[i].indexOf('='); - var name = null; - var value = null; - if (indexOfEquals >= 0) { - name = pairs[i].substring(0, indexOfEquals); - value = pairs[i].substring(indexOfEquals + 1); +ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { + if (!textStyle) { + this.text_ = ''; + } else { + var textFillStyle = textStyle.getFill(); + if (!textFillStyle) { + this.textFillState_ = null; } else { - name = pairs[i]; + var textFillStyleColor = textFillStyle.getColor(); + var fillStyle = ol.color.asString(textFillStyleColor ? + textFillStyleColor : ol.render.canvas.defaultFillStyle); + if (!this.textFillState_) { + this.textFillState_ = { + fillStyle: fillStyle + }; + } else { + var textFillState = this.textFillState_; + textFillState.fillStyle = fillStyle; + } } - callback(name, value ? goog.string.urlDecode(value) : ''); + var textStrokeStyle = textStyle.getStroke(); + if (!textStrokeStyle) { + this.textStrokeState_ = null; + } else { + var textStrokeStyleColor = textStrokeStyle.getColor(); + var textStrokeStyleLineCap = textStrokeStyle.getLineCap(); + var textStrokeStyleLineDash = textStrokeStyle.getLineDash(); + var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); + var textStrokeStyleWidth = textStrokeStyle.getWidth(); + var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); + var lineCap = textStrokeStyleLineCap !== undefined ? + textStrokeStyleLineCap : ol.render.canvas.defaultLineCap; + var lineDash = textStrokeStyleLineDash ? + textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash; + var lineJoin = textStrokeStyleLineJoin !== undefined ? + textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin; + var lineWidth = textStrokeStyleWidth !== undefined ? + textStrokeStyleWidth : ol.render.canvas.defaultLineWidth; + var miterLimit = textStrokeStyleMiterLimit !== undefined ? + textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit; + var strokeStyle = ol.color.asString(textStrokeStyleColor ? + textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle); + if (!this.textStrokeState_) { + this.textStrokeState_ = { + lineCap: lineCap, + lineDash: lineDash, + lineJoin: lineJoin, + lineWidth: lineWidth, + miterLimit: miterLimit, + strokeStyle: strokeStyle + }; + } else { + var textStrokeState = this.textStrokeState_; + textStrokeState.lineCap = lineCap; + textStrokeState.lineDash = lineDash; + textStrokeState.lineJoin = lineJoin; + textStrokeState.lineWidth = lineWidth; + textStrokeState.miterLimit = miterLimit; + textStrokeState.strokeStyle = strokeStyle; + } + } + var textFont = textStyle.getFont(); + var textOffsetX = textStyle.getOffsetX(); + var textOffsetY = textStyle.getOffsetY(); + var textRotation = textStyle.getRotation(); + var textScale = textStyle.getScale(); + var textText = textStyle.getText(); + var textTextAlign = textStyle.getTextAlign(); + var textTextBaseline = textStyle.getTextBaseline(); + var font = textFont !== undefined ? + textFont : ol.render.canvas.defaultFont; + var textAlign = textTextAlign !== undefined ? + textTextAlign : ol.render.canvas.defaultTextAlign; + var textBaseline = textTextBaseline !== undefined ? + textTextBaseline : ol.render.canvas.defaultTextBaseline; + if (!this.textState_) { + this.textState_ = { + font: font, + textAlign: textAlign, + textBaseline: textBaseline + }; + } else { + var textState = this.textState_; + textState.font = font; + textState.textAlign = textAlign; + textState.textBaseline = textBaseline; + } + this.text_ = textText !== undefined ? textText : ''; + this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0; + this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0; + this.textRotation_ = textRotation !== undefined ? textRotation : 0; + this.textScale_ = textScale !== undefined ? textScale : 1; } }; + /** - * Appends a URI and query data in a string buffer with special preconditions. - * - * Internal implementation utility, performing very few object allocations. - * - * @param {!Array<string|undefined>} buffer A string buffer. The first element - * must be the base URI, and may have a fragment identifier. If the array - * contains more than one element, the second element must be an ampersand, - * and may be overwritten, depending on the base URI. Undefined elements - * are treated as empty-string. - * @return {string} The concatenated URI and query data. - * @private + * @constructor + * @implements {ol.render.IReplayGroup} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Max extent. + * @param {number} resolution Resolution. + * @param {number=} opt_renderBuffer Optional rendering buffer. + * @struct */ -goog.uri.utils.appendQueryData_ = function(buffer) { - if (buffer[1]) { - // At least one query parameter was added. We need to check the - // punctuation mark, which is currently an ampersand, and also make sure - // there aren't any interfering fragment identifiers. - var baseUri = /** @type {string} */ (buffer[0]); - var hashIndex = baseUri.indexOf('#'); - if (hashIndex >= 0) { - // Move the fragment off the base part of the URI into the end. - buffer.push(baseUri.substr(hashIndex)); - buffer[0] = baseUri = baseUri.substr(0, hashIndex); - } - var questionIndex = baseUri.indexOf('?'); - if (questionIndex < 0) { - // No question mark, so we need a question mark instead of an ampersand. - buffer[1] = '?'; - } else if (questionIndex == baseUri.length - 1) { - // Question mark is the very last character of the existing URI, so don't - // append an additional delimiter. - buffer[1] = undefined; - } - } +ol.render.canvas.ReplayGroup = function( + tolerance, maxExtent, resolution, opt_renderBuffer) { + + /** + * @private + * @type {number} + */ + this.tolerance_ = tolerance; + + /** + * @private + * @type {ol.Extent} + */ + this.maxExtent_ = maxExtent; + + /** + * @private + * @type {number} + */ + this.resolution_ = resolution; + + /** + * @private + * @type {number|undefined} + */ + this.renderBuffer_ = opt_renderBuffer; + + /** + * @private + * @type {!Object.<string, + * Object.<ol.render.ReplayType, ol.render.canvas.Replay>>} + */ + this.replaysByZIndex_ = {}; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1); + + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.hitDetectionTransform_ = goog.vec.Mat4.createNumber(); - return buffer.join(''); }; /** - * Appends key=value pairs to an array, supporting multi-valued objects. - * @param {string} key The key prefix. - * @param {goog.uri.utils.QueryValue} value The value to serialize. - * @param {!Array<string>} pairs The array to which the 'key=value' strings - * should be appended. - * @private + * FIXME empty description for jsdoc */ -goog.uri.utils.appendKeyValuePairs_ = function(key, value, pairs) { - if (goog.isArray(value)) { - // Convince the compiler it's an array. - goog.asserts.assertArray(value); - for (var j = 0; j < value.length; j++) { - // Convert to string explicitly, to short circuit the null and array - // logic in this function -- this ensures that null and undefined get - // written as literal 'null' and 'undefined', and arrays don't get - // expanded out but instead encoded in the default way. - goog.uri.utils.appendKeyValuePairs_(key, String(value[j]), pairs); +ol.render.canvas.ReplayGroup.prototype.finish = function() { + var zKey; + for (zKey in this.replaysByZIndex_) { + var replays = this.replaysByZIndex_[zKey]; + var replayKey; + for (replayKey in replays) { + replays[replayKey].finish(); } - } else if (value != null) { - // Skip a top-level null or undefined entirely. - pairs.push('&', key, - // Check for empty string. Zero gets encoded into the url as literal - // strings. For empty string, skip the equal sign, to be consistent - // with UriBuilder.java. - value === '' ? '' : '=', - goog.string.urlEncode(value)); } }; /** - * Builds a buffer of query data from a sequence of alternating keys and values. - * - * @param {!Array<string|undefined>} buffer A string buffer to append to. The - * first element appended will be an '&', and may be replaced by the caller. - * @param {!goog.uri.utils.QueryArray|!Arguments} keysAndValues An array with - * alternating keys and values -- see the typedef. - * @param {number=} opt_startIndex A start offset into the arary, defaults to 0. - * @return {!Array<string|undefined>} The buffer argument. - * @private + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature + * callback. + * @return {T|undefined} Callback result. + * @template T */ -goog.uri.utils.buildQueryDataBuffer_ = function( - buffer, keysAndValues, opt_startIndex) { - goog.asserts.assert(Math.max(keysAndValues.length - (opt_startIndex || 0), - 0) % 2 == 0, 'goog.uri.utils: Key/value lists must be even in length.'); +ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( + coordinate, resolution, rotation, skippedFeaturesHash, callback) { - for (var i = opt_startIndex || 0; i < keysAndValues.length; i += 2) { - goog.uri.utils.appendKeyValuePairs_( - keysAndValues[i], keysAndValues[i + 1], buffer); + var transform = this.hitDetectionTransform_; + ol.vec.Mat4.makeTransform2D(transform, 0.5, 0.5, + 1 / resolution, -1 / resolution, -rotation, + -coordinate[0], -coordinate[1]); + + var context = this.hitDetectionContext_; + context.clearRect(0, 0, 1, 1); + + /** + * @type {ol.Extent} + */ + var hitExtent; + if (this.renderBuffer_ !== undefined) { + hitExtent = ol.extent.createEmpty(); + ol.extent.extendCoordinate(hitExtent, coordinate); + ol.extent.buffer(hitExtent, resolution * this.renderBuffer_, hitExtent); } - return buffer; + return this.replayHitDetection_(context, transform, rotation, + skippedFeaturesHash, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + var imageData = context.getImageData(0, 0, 1, 1).data; + if (imageData[3] > 0) { + var result = callback(feature); + if (result) { + return result; + } + context.clearRect(0, 0, 1, 1); + } + }, hitExtent); }; /** - * Builds a query data string from a sequence of alternating keys and values. - * Currently generates "&key&" for empty args. - * - * @param {goog.uri.utils.QueryArray} keysAndValues Alternating keys and - * values. See the typedef. - * @param {number=} opt_startIndex A start offset into the arary, defaults to 0. - * @return {string} The encoded query string, in the form 'a=1&b=2'. + * @inheritDoc */ -goog.uri.utils.buildQueryData = function(keysAndValues, opt_startIndex) { - var buffer = goog.uri.utils.buildQueryDataBuffer_( - [], keysAndValues, opt_startIndex); - buffer[0] = ''; // Remove the leading ampersand. - return buffer.join(''); +ol.render.canvas.ReplayGroup.prototype.getReplay = + function(zIndex, replayType) { + var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0'; + var replays = this.replaysByZIndex_[zIndexKey]; + if (replays === undefined) { + replays = {}; + this.replaysByZIndex_[zIndexKey] = replays; + } + var replay = replays[replayType]; + if (replay === undefined) { + var Constructor = ol.render.canvas.BATCH_CONSTRUCTORS_[replayType]; + goog.asserts.assert(Constructor !== undefined, + replayType + + ' constructor missing from ol.render.canvas.BATCH_CONSTRUCTORS_'); + replay = new Constructor(this.tolerance_, this.maxExtent_, + this.resolution_); + replays[replayType] = replay; + } + return replay; }; /** - * Builds a buffer of query data from a map. - * - * @param {!Array<string|undefined>} buffer A string buffer to append to. The - * first element appended will be an '&', and may be replaced by the caller. - * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys - * are URI-encoded parameter keys, and the values conform to the contract - * specified in the goog.uri.utils.QueryValue typedef. - * @return {!Array<string|undefined>} The buffer argument. - * @private + * @inheritDoc */ -goog.uri.utils.buildQueryDataBufferFromMap_ = function(buffer, map) { - for (var key in map) { - goog.uri.utils.appendKeyValuePairs_(key, map[key], buffer); - } - - return buffer; +ol.render.canvas.ReplayGroup.prototype.isEmpty = function() { + return goog.object.isEmpty(this.replaysByZIndex_); }; /** - * Builds a query data string from a map. - * Currently generates "&key&" for empty args. - * - * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys - * are URI-encoded parameter keys, and the values are arbitrary types - * or arrays. Keys with a null value are dropped. - * @return {string} The encoded query string, in the form 'a=1&b=2'. + * @param {CanvasRenderingContext2D} context Context. + * @param {number} pixelRatio Pixel ratio. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. */ -goog.uri.utils.buildQueryDataFromMap = function(map) { - var buffer = goog.uri.utils.buildQueryDataBufferFromMap_([], map); - buffer[0] = ''; - return buffer.join(''); +ol.render.canvas.ReplayGroup.prototype.replay = function( + context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { + + /** @type {Array.<number>} */ + var zs = Object.keys(this.replaysByZIndex_).map(Number); + goog.array.sort(zs); + + // setup clipping so that the parts of over-simplified geometries are not + // visible outside the current extent when panning + var maxExtent = this.maxExtent_; + var minX = maxExtent[0]; + var minY = maxExtent[1]; + var maxX = maxExtent[2]; + var maxY = maxExtent[3]; + var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; + ol.geom.flat.transform.transform2D( + flatClipCoords, 0, 8, 2, transform, flatClipCoords); + context.save(); + context.beginPath(); + context.moveTo(flatClipCoords[0], flatClipCoords[1]); + context.lineTo(flatClipCoords[2], flatClipCoords[3]); + context.lineTo(flatClipCoords[4], flatClipCoords[5]); + context.lineTo(flatClipCoords[6], flatClipCoords[7]); + context.closePath(); + context.clip(); + + var i, ii, j, jj, replays, replay; + for (i = 0, ii = zs.length; i < ii; ++i) { + replays = this.replaysByZIndex_[zs[i].toString()]; + for (j = 0, jj = ol.render.REPLAY_ORDER.length; j < jj; ++j) { + replay = replays[ol.render.REPLAY_ORDER[j]]; + if (replay !== undefined) { + replay.replay(context, pixelRatio, transform, viewRotation, + skippedFeaturesHash); + } + } + } + + context.restore(); }; /** - * Appends URI parameters to an existing URI. - * - * The variable arguments may contain alternating keys and values. Keys are - * assumed to be already URI encoded. The values should not be URI-encoded, - * and will instead be encoded by this function. - * <pre> - * appendParams('http://www.foo.com?existing=true', - * 'key1', 'value1', - * 'key2', 'value?willBeEncoded', - * 'key3', ['valueA', 'valueB', 'valueC'], - * 'key4', null); - * result: 'http://www.foo.com?existing=true&' + - * 'key1=value1&' + - * 'key2=value%3FwillBeEncoded&' + - * 'key3=valueA&key3=valueB&key3=valueC' - * </pre> - * - * A single call to this function will not exhibit quadratic behavior in IE, - * whereas multiple repeated calls may, although the effect is limited by - * fact that URL's generally can't exceed 2kb. - * - * @param {string} uri The original URI, which may already have query data. - * @param {...(goog.uri.utils.QueryArray|string|goog.uri.utils.QueryValue)} var_args - * An array or argument list conforming to goog.uri.utils.QueryArray. - * @return {string} The URI with all query parameters added. + * @private + * @param {CanvasRenderingContext2D} context Context. + * @param {goog.vec.Mat4.Number} transform Transform. + * @param {number} viewRotation View rotation. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback + * Feature callback. + * @param {ol.Extent=} opt_hitExtent Only check features that intersect this + * extent. + * @return {T|undefined} Callback result. + * @template T */ -goog.uri.utils.appendParams = function(uri, var_args) { - return goog.uri.utils.appendQueryData_( - arguments.length == 2 ? - goog.uri.utils.buildQueryDataBuffer_([uri], arguments[1], 0) : - goog.uri.utils.buildQueryDataBuffer_([uri], arguments, 1)); +ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( + context, transform, viewRotation, skippedFeaturesHash, + featureCallback, opt_hitExtent) { + /** @type {Array.<number>} */ + var zs = Object.keys(this.replaysByZIndex_).map(Number); + goog.array.sort(zs, function(a, b) { return b - a; }); + + var i, ii, j, replays, replay, result; + for (i = 0, ii = zs.length; i < ii; ++i) { + replays = this.replaysByZIndex_[zs[i].toString()]; + for (j = ol.render.REPLAY_ORDER.length - 1; j >= 0; --j) { + replay = replays[ol.render.REPLAY_ORDER[j]]; + if (replay !== undefined) { + result = replay.replayHitDetection(context, transform, viewRotation, + skippedFeaturesHash, featureCallback, opt_hitExtent); + if (result) { + return result; + } + } + } + } + return undefined; }; /** - * Appends query parameters from a map. - * - * @param {string} uri The original URI, which may already have query data. - * @param {!Object<goog.uri.utils.QueryValue>} map An object where keys are - * URI-encoded parameter keys, and the values are arbitrary types or arrays. - * Keys with a null value are dropped. - * @return {string} The new parameters. + * @const + * @private + * @type {Object.<ol.render.ReplayType, + * function(new: ol.render.canvas.Replay, number, ol.Extent, + * number)>} */ -goog.uri.utils.appendParamsFromMap = function(uri, map) { - return goog.uri.utils.appendQueryData_( - goog.uri.utils.buildQueryDataBufferFromMap_([uri], map)); +ol.render.canvas.BATCH_CONSTRUCTORS_ = { + 'Image': ol.render.canvas.ImageReplay, + 'LineString': ol.render.canvas.LineStringReplay, + 'Polygon': ol.render.canvas.PolygonReplay, + 'Text': ol.render.canvas.TextReplay }; +goog.provide('ol.render.Feature'); + + +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryType'); -/** - * Appends a single URI parameter. - * - * Repeated calls to this can exhibit quadratic behavior in IE6 due to the - * way string append works, though it should be limited given the 2kb limit. - * - * @param {string} uri The original URI, which may already have query data. - * @param {string} key The key, which must already be URI encoded. - * @param {*=} opt_value The value, which will be stringized and encoded - * (assumed not already to be encoded). If omitted, undefined, or null, the - * key will be added as a valueless parameter. - * @return {string} The URI with the query parameter added. - */ -goog.uri.utils.appendParam = function(uri, key, opt_value) { - var paramArr = [uri, '&', key]; - if (goog.isDefAndNotNull(opt_value)) { - paramArr.push('=', goog.string.urlEncode(opt_value)); - } - return goog.uri.utils.appendQueryData_(paramArr); -}; /** - * Finds the next instance of a query parameter with the specified name. - * - * Does not instantiate any objects. + * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like + * structure, optimized for rendering and styling. Geometry access through the + * API is limited to getting the type and extent of the geometry. * - * @param {string} uri The URI to search. May contain a fragment identifier - * if opt_hashIndex is specified. - * @param {number} startIndex The index to begin searching for the key at. A - * match may be found even if this is one character after the ampersand. - * @param {string} keyEncoded The URI-encoded key. - * @param {number} hashOrEndIndex Index to stop looking at. If a hash - * mark is present, it should be its index, otherwise it should be the - * length of the string. - * @return {number} The position of the first character in the key's name, - * immediately after either a question mark or a dot. - * @private + * @constructor + * @param {ol.geom.GeometryType} type Geometry type. + * @param {Array.<number>} flatCoordinates Flat coordinates. These always need + * to be right-handed for polygons. + * @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss. + * @param {Object.<string, *>} properties Properties. */ -goog.uri.utils.findParam_ = function( - uri, startIndex, keyEncoded, hashOrEndIndex) { - var index = startIndex; - var keyLength = keyEncoded.length; +ol.render.Feature = function(type, flatCoordinates, ends, properties) { - // Search for the key itself and post-filter for surronuding punctuation, - // rather than expensively building a regexp. - while ((index = uri.indexOf(keyEncoded, index)) >= 0 && - index < hashOrEndIndex) { - var precedingChar = uri.charCodeAt(index - 1); - // Ensure that the preceding character is '&' or '?'. - if (precedingChar == goog.uri.utils.CharCode_.AMPERSAND || - precedingChar == goog.uri.utils.CharCode_.QUESTION) { - // Ensure the following character is '&', '=', '#', or NaN - // (end of string). - var followingChar = uri.charCodeAt(index + keyLength); - if (!followingChar || - followingChar == goog.uri.utils.CharCode_.EQUAL || - followingChar == goog.uri.utils.CharCode_.AMPERSAND || - followingChar == goog.uri.utils.CharCode_.HASH) { - return index; - } - } - index += keyLength + 1; - } + /** + * @private + * @type {ol.Extent|undefined} + */ + this.extent_; + + goog.asserts.assert(type === ol.geom.GeometryType.POINT || + type === ol.geom.GeometryType.MULTI_POINT || + type === ol.geom.GeometryType.LINE_STRING || + type === ol.geom.GeometryType.MULTI_LINE_STRING || + type === ol.geom.GeometryType.POLYGON, + 'Need a Point, MultiPoint, LineString, MultiLineString or Polygon type'); + + /** + * @private + * @type {ol.geom.GeometryType} + */ + this.type_ = type; + + /** + * @private + * @type {Array.<number>} + */ + this.flatCoordinates_ = flatCoordinates; + + /** + * @private + * @type {Array.<number>|Array.<Array.<number>>} + */ + this.ends_ = ends; + + /** + * @private + * @type {Object.<string, *>} + */ + this.properties_ = properties; - return -1; }; /** - * Regular expression for finding a hash mark or end of string. - * @type {RegExp} - * @private + * Get a feature property by its key. + * @param {string} key Key + * @return {*} Value for the requested key. + * @api */ -goog.uri.utils.hashOrEndRe_ = /#|$/; +ol.render.Feature.prototype.get = function(key) { + return this.properties_[key]; +}; /** - * Determines if the URI contains a specific key. - * - * Performs no object instantiations. - * - * @param {string} uri The URI to process. May contain a fragment - * identifier. - * @param {string} keyEncoded The URI-encoded key. Case-sensitive. - * @return {boolean} Whether the key is present. + * @return {Array.<number>|Array.<Array.<number>>} Ends or endss. */ -goog.uri.utils.hasParam = function(uri, keyEncoded) { - return goog.uri.utils.findParam_(uri, 0, keyEncoded, - uri.search(goog.uri.utils.hashOrEndRe_)) >= 0; +ol.render.Feature.prototype.getEnds = function() { + return this.ends_; }; /** - * Gets the first value of a query parameter. - * @param {string} uri The URI to process. May contain a fragment. - * @param {string} keyEncoded The URI-encoded key. Case-sensitive. - * @return {?string} The first value of the parameter (URI-decoded), or null - * if the parameter is not found. + * Get the extent of this feature's geometry. + * @return {ol.Extent} Extent. + * @api */ -goog.uri.utils.getParamValue = function(uri, keyEncoded) { - var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); - var foundIndex = goog.uri.utils.findParam_( - uri, 0, keyEncoded, hashOrEndIndex); +ol.render.Feature.prototype.getExtent = function() { + if (!this.extent_) { + this.extent_ = this.type_ === ol.geom.GeometryType.POINT ? + ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) : + ol.extent.createOrUpdateFromFlatCoordinates( + this.flatCoordinates_, 0, this.flatCoordinates_.length, 2); - if (foundIndex < 0) { - return null; - } else { - var endPosition = uri.indexOf('&', foundIndex); - if (endPosition < 0 || endPosition > hashOrEndIndex) { - endPosition = hashOrEndIndex; - } - // Progress forth to the end of the "key=" or "key&" substring. - foundIndex += keyEncoded.length + 1; - // Use substr, because it (unlike substring) will return empty string - // if foundIndex > endPosition. - return goog.string.urlDecode( - uri.substr(foundIndex, endPosition - foundIndex)); } + return this.extent_; }; /** - * Gets all values of a query parameter. - * @param {string} uri The URI to process. May contain a fragment. - * @param {string} keyEncoded The URI-encoded key. Case-sensitive. - * @return {!Array<string>} All URI-decoded values with the given key. - * If the key is not found, this will have length 0, but never be null. + * @return {Array.<number>} Flat coordinates. */ -goog.uri.utils.getParamValues = function(uri, keyEncoded) { - var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); - var position = 0; - var foundIndex; - var result = []; +ol.render.Feature.prototype.getFlatCoordinates = + ol.render.Feature.prototype.getOrientedFlatCoordinates = function() { + return this.flatCoordinates_; +}; - while ((foundIndex = goog.uri.utils.findParam_( - uri, position, keyEncoded, hashOrEndIndex)) >= 0) { - // Find where this parameter ends, either the '&' or the end of the - // query parameters. - position = uri.indexOf('&', foundIndex); - if (position < 0 || position > hashOrEndIndex) { - position = hashOrEndIndex; - } - // Progress forth to the end of the "key=" or "key&" substring. - foundIndex += keyEncoded.length + 1; - // Use substr, because it (unlike substring) will return empty string - // if foundIndex > position. - result.push(goog.string.urlDecode(uri.substr( - foundIndex, position - foundIndex))); - } +/** + * Get the feature for working with its geometry. + * @return {ol.render.Feature} Feature. + * @api + */ +ol.render.Feature.prototype.getGeometry = function() { + return this; +}; - return result; + +/** + * Get the feature properties. + * @return {Object.<string, *>} Feature properties. + * @api + */ +ol.render.Feature.prototype.getProperties = function() { + return this.properties_; }; /** - * Regexp to find trailing question marks and ampersands. - * @type {RegExp} - * @private + * Get the feature for working with its geometry. + * @return {ol.render.Feature} Feature. */ -goog.uri.utils.trailingQueryPunctuationRe_ = /[?&]($|#)/; +ol.render.Feature.prototype.getSimplifiedGeometry = + ol.render.Feature.prototype.getGeometry; /** - * Removes all instances of a query parameter. - * @param {string} uri The URI to process. Must not contain a fragment. - * @param {string} keyEncoded The URI-encoded key. - * @return {string} The URI with all instances of the parameter removed. + * @return {number} Stride. */ -goog.uri.utils.removeParam = function(uri, keyEncoded) { - var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_); - var position = 0; - var foundIndex; - var buffer = []; +ol.render.Feature.prototype.getStride = goog.functions.constant(2); - // Look for a query parameter. - while ((foundIndex = goog.uri.utils.findParam_( - uri, position, keyEncoded, hashOrEndIndex)) >= 0) { - // Get the portion of the query string up to, but not including, the ? - // or & starting the parameter. - buffer.push(uri.substring(position, foundIndex)); - // Progress to immediately after the '&'. If not found, go to the end. - // Avoid including the hash mark. - position = Math.min((uri.indexOf('&', foundIndex) + 1) || hashOrEndIndex, - hashOrEndIndex); - } - // Append everything that is remaining. - buffer.push(uri.substr(position)); +/** + * @return {undefined} + */ +ol.render.Feature.prototype.getStyleFunction = ol.nullFunction; - // Join the buffer, and remove trailing punctuation that remains. - return buffer.join('').replace( - goog.uri.utils.trailingQueryPunctuationRe_, '$1'); + +/** + * Get the type of this feature's geometry. + * @return {ol.geom.GeometryType} Geometry type. + * @api + */ +ol.render.Feature.prototype.getType = function() { + return this.type_; }; +goog.provide('ol.renderer.vector'); + +goog.require('goog.asserts'); +goog.require('ol.render.Feature'); +goog.require('ol.render.IReplayGroup'); +goog.require('ol.style.ImageState'); +goog.require('ol.style.Style'); + /** - * Replaces all existing definitions of a parameter with a single definition. - * - * Repeated calls to this can exhibit quadratic behavior due to the need to - * find existing instances and reconstruct the string, though it should be - * limited given the 2kb limit. Consider using appendParams to append multiple - * parameters in bulk. - * - * @param {string} uri The original URI, which may already have query data. - * @param {string} keyEncoded The key, which must already be URI encoded. - * @param {*} value The value, which will be stringized and encoded (assumed - * not already to be encoded). - * @return {string} The URI with the query parameter added. + * @param {ol.Feature|ol.render.Feature} feature1 Feature 1. + * @param {ol.Feature|ol.render.Feature} feature2 Feature 2. + * @return {number} Order. */ -goog.uri.utils.setParam = function(uri, keyEncoded, value) { - return goog.uri.utils.appendParam( - goog.uri.utils.removeParam(uri, keyEncoded), keyEncoded, value); +ol.renderer.vector.defaultOrder = function(feature1, feature2) { + return goog.getUid(feature1) - goog.getUid(feature2); }; /** - * Generates a URI path using a given URI and a path with checks to - * prevent consecutive "//". The baseUri passed in must not contain - * query or fragment identifiers. The path to append may not contain query or - * fragment identifiers. - * - * @param {string} baseUri URI to use as the base. - * @param {string} path Path to append. - * @return {string} Updated URI. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @return {number} Squared pixel tolerance. */ -goog.uri.utils.appendPath = function(baseUri, path) { - goog.uri.utils.assertNoFragmentsOrQueries_(baseUri); +ol.renderer.vector.getSquaredTolerance = function(resolution, pixelRatio) { + var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio); + return tolerance * tolerance; +}; - // Remove any trailing '/' - if (goog.string.endsWith(baseUri, '/')) { - baseUri = baseUri.substr(0, baseUri.length - 1); + +/** + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @return {number} Pixel tolerance. + */ +ol.renderer.vector.getTolerance = function(resolution, pixelRatio) { + return ol.SIMPLIFY_TOLERANCE * resolution / pixelRatio; +}; + + +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.Circle} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature} feature Feature. + * @private + */ +ol.renderer.vector.renderCircleGeometry_ = + function(replayGroup, geometry, style, feature) { + var fillStyle = style.getFill(); + var strokeStyle = style.getStroke(); + if (fillStyle || strokeStyle) { + var polygonReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.POLYGON); + polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); + polygonReplay.drawCircleGeometry(geometry, feature); } - // Remove any leading '/' - if (goog.string.startsWith(path, '/')) { - path = path.substr(1); + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature); } - return goog.string.buildString(baseUri, '/', path); }; /** - * Replaces the path. - * @param {string} uri URI to use as the base. - * @param {string} path New path. - * @return {string} Updated URI. + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {ol.style.Style} style Style. + * @param {number} squaredTolerance Squared tolerance. + * @param {function(this: T, goog.events.Event)} listener Listener function. + * @param {T} thisArg Value to use as `this` when executing `listener`. + * @return {boolean} `true` if style is loading. + * @template T */ -goog.uri.utils.setPath = function(uri, path) { - // Add any missing '/'. - if (!goog.string.startsWith(path, '/')) { - path = '/' + path; +ol.renderer.vector.renderFeature = function( + replayGroup, feature, style, squaredTolerance, listener, thisArg) { + var loading = false; + var imageStyle, imageState; + imageStyle = style.getImage(); + if (imageStyle) { + imageState = imageStyle.getImageState(); + if (imageState == ol.style.ImageState.LOADED || + imageState == ol.style.ImageState.ERROR) { + imageStyle.unlistenImageChange(listener, thisArg); + } else { + if (imageState == ol.style.ImageState.IDLE) { + imageStyle.load(); + } + imageState = imageStyle.getImageState(); + goog.asserts.assert(imageState == ol.style.ImageState.LOADING, + 'imageState should be LOADING'); + imageStyle.listenImageChange(listener, thisArg); + loading = true; + } } - var parts = goog.uri.utils.split(uri); - return goog.uri.utils.buildFromEncodedParts( - parts[goog.uri.utils.ComponentIndex.SCHEME], - parts[goog.uri.utils.ComponentIndex.USER_INFO], - parts[goog.uri.utils.ComponentIndex.DOMAIN], - parts[goog.uri.utils.ComponentIndex.PORT], - path, - parts[goog.uri.utils.ComponentIndex.QUERY_DATA], - parts[goog.uri.utils.ComponentIndex.FRAGMENT]); + ol.renderer.vector.renderFeature_(replayGroup, feature, style, + squaredTolerance); + return loading; }; /** - * Standard supported query parameters. - * @enum {string} + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {ol.style.Style} style Style. + * @param {number} squaredTolerance Squared tolerance. + * @private */ -goog.uri.utils.StandardQueryParam = { - - /** Unused parameter for unique-ifying. */ - RANDOM: 'zx' +ol.renderer.vector.renderFeature_ = function( + replayGroup, feature, style, squaredTolerance) { + var geometry = style.getGeometryFunction()(feature); + if (!geometry) { + return; + } + var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); + var geometryRenderer = + ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()]; + goog.asserts.assert(geometryRenderer !== undefined, + 'geometryRenderer should be defined'); + geometryRenderer(replayGroup, simplifiedGeometry, style, feature); }; /** - * Sets the zx parameter of a URI to a random value. - * @param {string} uri Any URI. - * @return {string} That URI with the "zx" parameter added or replaced to - * contain a random string. + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.GeometryCollection} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature} feature Feature. + * @private */ -goog.uri.utils.makeUnique = function(uri) { - return goog.uri.utils.setParam(uri, - goog.uri.utils.StandardQueryParam.RANDOM, goog.string.getRandomString()); +ol.renderer.vector.renderGeometryCollectionGeometry_ = + function(replayGroup, geometry, style, feature) { + var geometries = geometry.getGeometriesArray(); + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometryRenderer = + ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()]; + goog.asserts.assert(geometryRenderer !== undefined, + 'geometryRenderer should be defined'); + geometryRenderer(replayGroup, geometries[i], style, feature); + } }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Wrapper class for handling XmlHttpRequests. - * - * One off requests can be sent through goog.net.XhrIo.send() or an - * instance can be created to send multiple requests. Each request uses its - * own XmlHttpRequest object and handles clearing of the event callback to - * ensure no leaks. - * - * XhrIo is event based, it dispatches events on success, failure, finishing, - * ready-state change, or progress. - * - * The ready-state or timeout event fires first, followed by - * a generic completed event. Then the abort, error, or success event - * is fired as appropriate. Progress events are fired as they are - * received. Lastly, the ready event will fire to indicate that the - * object may be used to make another request. - * - * The error event may also be called before completed and - * ready-state-change if the XmlHttpRequest.open() or .send() methods throw. - * - * This class does not support multiple requests, queuing, or prioritization. - * - * When progress events are supported by the browser, and progress is - * enabled via .setProgressEventsEnabled(true), the - * goog.net.EventType.PROGRESS event will be the re-dispatched browser - * progress event. - * - * Tested = IE6, FF1.5, Safari, Opera 8.5 - * - * TODO(user): Error cases aren't playing nicely in Safari. - * + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.LineString|ol.render.Feature} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @private */ +ol.renderer.vector.renderLineStringGeometry_ = + function(replayGroup, geometry, style, feature) { + var strokeStyle = style.getStroke(); + if (strokeStyle) { + var lineStringReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.LINE_STRING); + lineStringReplay.setFillStrokeStyle(null, strokeStyle); + lineStringReplay.drawLineStringGeometry(geometry, feature); + } + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature); + } +}; -goog.provide('goog.net.XhrIo'); -goog.provide('goog.net.XhrIo.ResponseType'); - -goog.require('goog.Timer'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.events.EventTarget'); -goog.require('goog.json'); -goog.require('goog.log'); -goog.require('goog.net.ErrorCode'); -goog.require('goog.net.EventType'); -goog.require('goog.net.HttpStatus'); -goog.require('goog.net.XmlHttp'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.structs'); -goog.require('goog.structs.Map'); -goog.require('goog.uri.utils'); -goog.require('goog.userAgent'); +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.MultiLineString|ol.render.Feature} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @private + */ +ol.renderer.vector.renderMultiLineStringGeometry_ = + function(replayGroup, geometry, style, feature) { + var strokeStyle = style.getStroke(); + if (strokeStyle) { + var lineStringReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.LINE_STRING); + lineStringReplay.setFillStrokeStyle(null, strokeStyle); + lineStringReplay.drawMultiLineStringGeometry(geometry, feature); + } + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + var flatMidpointCoordinates = geometry.getFlatMidpoints(); + textReplay.drawText(flatMidpointCoordinates, 0, + flatMidpointCoordinates.length, 2, geometry, feature); + } +}; + + +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.MultiPolygon} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature} feature Feature. + * @private + */ +ol.renderer.vector.renderMultiPolygonGeometry_ = + function(replayGroup, geometry, style, feature) { + var fillStyle = style.getFill(); + var strokeStyle = style.getStroke(); + if (strokeStyle || fillStyle) { + var polygonReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.POLYGON); + polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); + polygonReplay.drawMultiPolygonGeometry(geometry, feature); + } + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints(); + textReplay.drawText(flatInteriorPointCoordinates, 0, + flatInteriorPointCoordinates.length, 2, geometry, feature); + } +}; -goog.forwardDeclare('goog.Uri'); + +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.Point|ol.render.Feature} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @private + */ +ol.renderer.vector.renderPointGeometry_ = + function(replayGroup, geometry, style, feature) { + var imageStyle = style.getImage(); + if (imageStyle) { + if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { + return; + } + var imageReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.IMAGE); + imageReplay.setImageStyle(imageStyle); + imageReplay.drawPointGeometry(geometry, feature); + } + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry, + feature); + } +}; + + +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.MultiPoint|ol.render.Feature} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @private + */ +ol.renderer.vector.renderMultiPointGeometry_ = + function(replayGroup, geometry, style, feature) { + var imageStyle = style.getImage(); + if (imageStyle) { + if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { + return; + } + var imageReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.IMAGE); + imageReplay.setImageStyle(imageStyle); + imageReplay.drawMultiPointGeometry(geometry, feature); + } + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + var flatCoordinates = geometry.getFlatCoordinates(); + textReplay.drawText(flatCoordinates, 0, flatCoordinates.length, + geometry.getStride(), geometry, feature); + } +}; + + +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.Polygon|ol.render.Feature} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @private + */ +ol.renderer.vector.renderPolygonGeometry_ = + function(replayGroup, geometry, style, feature) { + var fillStyle = style.getFill(); + var strokeStyle = style.getStroke(); + if (fillStyle || strokeStyle) { + var polygonReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.POLYGON); + polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); + polygonReplay.drawPolygonGeometry(geometry, feature); + } + var textStyle = style.getText(); + if (textStyle) { + var textReplay = replayGroup.getReplay( + style.getZIndex(), ol.render.ReplayType.TEXT); + textReplay.setTextStyle(textStyle); + textReplay.drawText( + geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature); + } +}; + + +/** + * @const + * @private + * @type {Object.<ol.geom.GeometryType, + * function(ol.render.IReplayGroup, ol.geom.Geometry, + * ol.style.Style, Object)>} + */ +ol.renderer.vector.GEOMETRY_RENDERERS_ = { + 'Point': ol.renderer.vector.renderPointGeometry_, + 'LineString': ol.renderer.vector.renderLineStringGeometry_, + 'Polygon': ol.renderer.vector.renderPolygonGeometry_, + 'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_, + 'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_, + 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_, + 'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_, + 'Circle': ol.renderer.vector.renderCircleGeometry_ +}; + +goog.provide('ol.ImageCanvas'); + +goog.require('goog.asserts'); +goog.require('ol.ImageBase'); +goog.require('ol.ImageState'); /** - * Basic class for handling XMLHttpRequests. - * @param {goog.net.XmlHttpFactory=} opt_xmlHttpFactory Factory to use when - * creating XMLHttpRequest objects. * @constructor - * @extends {goog.events.EventTarget} + * @extends {ol.ImageBase} + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {Array.<ol.Attribution>} attributions Attributions. + * @param {HTMLCanvasElement} canvas Canvas. + * @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to + * support asynchronous canvas drawing. */ -goog.net.XhrIo = function(opt_xmlHttpFactory) { - goog.net.XhrIo.base(this, 'constructor'); +ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions, + canvas, opt_loader) { /** - * Map of default headers to add to every request, use: - * XhrIo.headers.set(name, value) - * @type {!goog.structs.Map} + * Optional canvas loader function. + * @type {?ol.ImageCanvasLoader} + * @private */ - this.headers = new goog.structs.Map(); + this.loader_ = opt_loader !== undefined ? opt_loader : null; - /** - * Optional XmlHttpFactory - * @private {goog.net.XmlHttpFactory} - */ - this.xmlHttpFactory_ = opt_xmlHttpFactory || null; + var state = opt_loader !== undefined ? + ol.ImageState.IDLE : ol.ImageState.LOADED; - /** - * Whether XMLHttpRequest is active. A request is active from the time send() - * is called until onReadyStateChange() is complete, or error() or abort() - * is called. - * @private {boolean} - */ - this.active_ = false; + goog.base(this, extent, resolution, pixelRatio, state, attributions); /** - * The XMLHttpRequest object that is being used for the transfer. - * @private {?goog.net.XhrLike.OrNative} + * @private + * @type {HTMLCanvasElement} */ - this.xhr_ = null; + this.canvas_ = canvas; /** - * The options to use with the current XMLHttpRequest object. - * @private {Object} + * @private + * @type {Error} */ - this.xhrOptions_ = null; + this.error_ = null; - /** - * Last URL that was requested. - * @private {string|goog.Uri} - */ - this.lastUri_ = ''; +}; +goog.inherits(ol.ImageCanvas, ol.ImageBase); - /** - * Method for the last request. - * @private {string} - */ - this.lastMethod_ = ''; - /** - * Last error code. - * @private {!goog.net.ErrorCode} - */ - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; +/** + * Get any error associated with asynchronous rendering. + * @return {Error} Any error that occurred during rendering. + */ +ol.ImageCanvas.prototype.getError = function() { + return this.error_; +}; - /** - * Last error message. - * @private {Error|string} - */ - this.lastError_ = ''; - /** - * Used to ensure that we don't dispatch an multiple ERROR events. This can - * happen in IE when it does a synchronous load and one error is handled in - * the ready statte change and one is handled due to send() throwing an - * exception. - * @private {boolean} - */ - this.errorDispatched_ = false; +/** + * Handle async drawing complete. + * @param {Error} err Any error during drawing. + * @private + */ +ol.ImageCanvas.prototype.handleLoad_ = function(err) { + if (err) { + this.error_ = err; + this.state = ol.ImageState.ERROR; + } else { + this.state = ol.ImageState.LOADED; + } + this.changed(); +}; + + +/** + * Trigger drawing on canvas. + */ +ol.ImageCanvas.prototype.load = function() { + if (this.state == ol.ImageState.IDLE) { + goog.asserts.assert(this.loader_, 'this.loader_ must be set'); + this.state = ol.ImageState.LOADING; + this.changed(); + this.loader_(goog.bind(this.handleLoad_, this)); + } +}; + + +/** + * @inheritDoc + */ +ol.ImageCanvas.prototype.getImage = function(opt_context) { + return this.canvas_; +}; + + +/** + * A function that is called to trigger asynchronous canvas drawing. It is + * called with a "done" callback that should be called when drawing is done. + * If any error occurs during drawing, the "done" callback should be called with + * that error. + * + * @typedef {function(function(Error))} + */ +ol.ImageCanvasLoader; + +goog.provide('ol.reproj.Image'); +goog.provide('ol.reproj.ImageFunctionType'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.ImageBase'); +goog.require('ol.ImageState'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.reproj'); +goog.require('ol.reproj.Triangulation'); + + +/** + * @typedef {function(ol.Extent, number, number) : ol.ImageBase} + */ +ol.reproj.ImageFunctionType; + + + +/** + * @classdesc + * Class encapsulating single reprojected image. + * See {@link ol.source.Image}. + * + * @constructor + * @extends {ol.ImageBase} + * @param {ol.proj.Projection} sourceProj Source projection (of the data). + * @param {ol.proj.Projection} targetProj Target projection. + * @param {ol.Extent} targetExtent Target extent. + * @param {number} targetResolution Target resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.reproj.ImageFunctionType} getImageFunction + * Function returning source images (extent, resolution, pixelRatio). + */ +ol.reproj.Image = function(sourceProj, targetProj, + targetExtent, targetResolution, pixelRatio, getImageFunction) { /** - * Used to make sure we don't fire the complete event from inside a send call. - * @private {boolean} + * @private + * @type {ol.proj.Projection} */ - this.inSend_ = false; + this.targetProj_ = targetProj; /** - * Used in determining if a call to {@link #onReadyStateChange_} is from - * within a call to this.xhr_.open. - * @private {boolean} + * @private + * @type {ol.Extent} */ - this.inOpen_ = false; + this.maxSourceExtent_ = sourceProj.getExtent(); + var maxTargetExtent = targetProj.getExtent(); + + var limitedTargetExtent = maxTargetExtent ? + ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent; + + var targetCenter = ol.extent.getCenter(limitedTargetExtent); + var sourceResolution = ol.reproj.calculateSourceResolution( + sourceProj, targetProj, targetCenter, targetResolution); + + var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD; /** - * Used in determining if a call to {@link #onReadyStateChange_} is from - * within a call to this.xhr_.abort. - * @private {boolean} + * @private + * @type {!ol.reproj.Triangulation} */ - this.inAbort_ = false; + this.triangulation_ = new ol.reproj.Triangulation( + sourceProj, targetProj, limitedTargetExtent, this.maxSourceExtent_, + sourceResolution * errorThresholdInPixels); /** - * Number of milliseconds after which an incomplete request will be aborted - * and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no timeout - * is set. - * @private {number} + * @private + * @type {number} */ - this.timeoutInterval_ = 0; + this.targetResolution_ = targetResolution; /** - * Timer to track request timeout. - * @private {?number} + * @private + * @type {ol.Extent} */ - this.timeoutId_ = null; + this.targetExtent_ = targetExtent; + + var sourceExtent = this.triangulation_.calculateSourceExtent(); /** - * The requested type for the response. The empty string means use the default - * XHR behavior. - * @private {goog.net.XhrIo.ResponseType} + * @private + * @type {ol.ImageBase} */ - this.responseType_ = goog.net.XhrIo.ResponseType.DEFAULT; + this.sourceImage_ = + getImageFunction(sourceExtent, sourceResolution, pixelRatio); /** - * Whether a "credentialed" request is to be sent (one that is aware of - * cookies and authentication). This is applicable only for cross-domain - * requests and more recent browsers that support this part of the HTTP Access - * Control standard. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-withcredentials-attribute - * - * @private {boolean} + * @private + * @type {number} */ - this.withCredentials_ = false; + this.sourcePixelRatio_ = + this.sourceImage_ ? this.sourceImage_.getPixelRatio() : 1; /** - * Whether progress events are enabled for this request. This is - * disabled by default because setting a progress event handler - * causes pre-flight OPTIONS requests to be sent for CORS requests, - * even in cases where a pre-flight request would not otherwise be - * sent. - * - * @see http://xhr.spec.whatwg.org/#security-considerations - * - * Note that this can cause problems for Firefox 22 and below, as an - * older "LSProgressEvent" will be dispatched by the browser. That - * progress event is no longer supported, and can lead to failures, - * including throwing exceptions. - * - * @see http://bugzilla.mozilla.org/show_bug.cgi?id=845631 - * @see b/23469793 - * - * @private {boolean} + * @private + * @type {HTMLCanvasElement} */ - this.progressEventsEnabled_ = false; + this.canvas_ = null; /** - * True if we can use XMLHttpRequest's timeout directly. - * @private {boolean} + * @private + * @type {goog.events.Key} */ - this.useXhr2Timeout_ = false; -}; -goog.inherits(goog.net.XhrIo, goog.events.EventTarget); + this.sourceListenerKey_ = null; -/** - * Response types that may be requested for XMLHttpRequests. - * @enum {string} - * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute - */ -goog.net.XhrIo.ResponseType = { - DEFAULT: '', - TEXT: 'text', - DOCUMENT: 'document', - // Not supported as of Chrome 10.0.612.1 dev - BLOB: 'blob', - ARRAY_BUFFER: 'arraybuffer' -}; + var state = ol.ImageState.LOADED; + var attributions = []; + if (this.sourceImage_) { + state = ol.ImageState.IDLE; + attributions = this.sourceImage_.getAttributions(); + } -/** - * A reference to the XhrIo logger - * @private {goog.debug.Logger} - * @const - */ -goog.net.XhrIo.prototype.logger_ = - goog.log.getLogger('goog.net.XhrIo'); + goog.base(this, targetExtent, targetResolution, this.sourcePixelRatio_, + state, attributions); +}; +goog.inherits(ol.reproj.Image, ol.ImageBase); /** - * The Content-Type HTTP header name - * @type {string} + * @inheritDoc */ -goog.net.XhrIo.CONTENT_TYPE_HEADER = 'Content-Type'; +ol.reproj.Image.prototype.disposeInternal = function() { + if (this.state == ol.ImageState.LOADING) { + this.unlistenSource_(); + } + goog.base(this, 'disposeInternal'); +}; /** - * The pattern matching the 'http' and 'https' URI schemes - * @type {!RegExp} + * @inheritDoc */ -goog.net.XhrIo.HTTP_SCHEME_PATTERN = /^https?$/i; +ol.reproj.Image.prototype.getImage = function(opt_context) { + return this.canvas_; +}; /** - * The methods that typically come along with form data. We set different - * headers depending on whether the HTTP action is one of these. + * @return {ol.proj.Projection} Projection. */ -goog.net.XhrIo.METHODS_WITH_FORM_DATA = ['POST', 'PUT']; +ol.reproj.Image.prototype.getProjection = function() { + return this.targetProj_; +}; /** - * The Content-Type HTTP header value for a url-encoded form - * @type {string} + * @private */ -goog.net.XhrIo.FORM_CONTENT_TYPE = - 'application/x-www-form-urlencoded;charset=utf-8'; - +ol.reproj.Image.prototype.reproject_ = function() { + var sourceState = this.sourceImage_.getState(); + if (sourceState == ol.ImageState.LOADED) { + var width = ol.extent.getWidth(this.targetExtent_) / this.targetResolution_; + var height = + ol.extent.getHeight(this.targetExtent_) / this.targetResolution_; -/** - * The XMLHttpRequest Level two timeout delay ms property name. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - * - * @private {string} - * @const - */ -goog.net.XhrIo.XHR2_TIMEOUT_ = 'timeout'; + this.canvas_ = ol.reproj.render(width, height, this.sourcePixelRatio_, + this.sourceImage_.getResolution(), this.maxSourceExtent_, + this.targetResolution_, this.targetExtent_, this.triangulation_, [{ + extent: this.sourceImage_.getExtent(), + image: this.sourceImage_.getImage() + }]); + } + this.state = sourceState; + this.changed(); +}; /** - * The XMLHttpRequest Level two ontimeout handler property name. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - * - * @private {string} - * @const + * @inheritDoc */ -goog.net.XhrIo.XHR2_ON_TIMEOUT_ = 'ontimeout'; - +ol.reproj.Image.prototype.load = function() { + if (this.state == ol.ImageState.IDLE) { + this.state = ol.ImageState.LOADING; + this.changed(); -/** - * All non-disposed instances of goog.net.XhrIo created - * by {@link goog.net.XhrIo.send} are in this Array. - * @see goog.net.XhrIo.cleanup - * @private {!Array<!goog.net.XhrIo>} - */ -goog.net.XhrIo.sendInstances_ = []; + var sourceState = this.sourceImage_.getState(); + if (sourceState == ol.ImageState.LOADED || + sourceState == ol.ImageState.ERROR) { + this.reproject_(); + } else { + this.sourceListenerKey_ = this.sourceImage_.listen( + goog.events.EventType.CHANGE, function(e) { + var sourceState = this.sourceImage_.getState(); + if (sourceState == ol.ImageState.LOADED || + sourceState == ol.ImageState.ERROR) { + this.unlistenSource_(); + this.reproject_(); + } + }, false, this); + this.sourceImage_.load(); + } + } +}; /** - * Static send that creates a short lived instance of XhrIo to send the - * request. - * @see goog.net.XhrIo.cleanup - * @param {string|goog.Uri} url Uri to make request to. - * @param {?function(this:goog.net.XhrIo, ?)=} opt_callback Callback function - * for when request is complete. - * @param {string=} opt_method Send method, default: GET. - * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} - * opt_content Body data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - * @param {number=} opt_timeoutInterval Number of milliseconds after which an - * incomplete request will be aborted; 0 means no timeout is set. - * @param {boolean=} opt_withCredentials Whether to send credentials with the - * request. Default to false. See {@link goog.net.XhrIo#setWithCredentials}. - * @return {!goog.net.XhrIo} The sent XhrIo. + * @private */ -goog.net.XhrIo.send = function(url, opt_callback, opt_method, opt_content, - opt_headers, opt_timeoutInterval, - opt_withCredentials) { - var x = new goog.net.XhrIo(); - goog.net.XhrIo.sendInstances_.push(x); - if (opt_callback) { - x.listen(goog.net.EventType.COMPLETE, opt_callback); - } - x.listenOnce(goog.net.EventType.READY, x.cleanupSend_); - if (opt_timeoutInterval) { - x.setTimeoutInterval(opt_timeoutInterval); - } - if (opt_withCredentials) { - x.setWithCredentials(opt_withCredentials); - } - x.send(url, opt_method, opt_content, opt_headers); - return x; +ol.reproj.Image.prototype.unlistenSource_ = function() { + goog.asserts.assert(this.sourceListenerKey_, + 'this.sourceListenerKey_ should not be null'); + goog.events.unlistenByKey(this.sourceListenerKey_); + this.sourceListenerKey_ = null; }; +goog.provide('ol.source.Image'); +goog.provide('ol.source.ImageEvent'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events.Event'); +goog.require('ol.Attribution'); +goog.require('ol.ImageState'); +goog.require('ol.array'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.reproj.Image'); +goog.require('ol.source.Source'); + /** - * Disposes all non-disposed instances of goog.net.XhrIo created by - * {@link goog.net.XhrIo.send}. - * {@link goog.net.XhrIo.send} cleans up the goog.net.XhrIo instance - * it creates when the request completes or fails. However, if - * the request never completes, then the goog.net.XhrIo is not disposed. - * This can occur if the window is unloaded before the request completes. - * We could have {@link goog.net.XhrIo.send} return the goog.net.XhrIo - * it creates and make the client of {@link goog.net.XhrIo.send} be - * responsible for disposing it in this case. However, this makes things - * significantly more complicated for the client, and the whole point - * of {@link goog.net.XhrIo.send} is that it's simple and easy to use. - * Clients of {@link goog.net.XhrIo.send} should call - * {@link goog.net.XhrIo.cleanup} when doing final - * cleanup on window unload. + * @typedef {{attributions: (Array.<ol.Attribution>|undefined), + * extent: (null|ol.Extent|undefined), + * logo: (string|olx.LogoOptions|undefined), + * projection: ol.proj.ProjectionLike, + * resolutions: (Array.<number>|undefined), + * state: (ol.source.State|undefined)}} */ -goog.net.XhrIo.cleanup = function() { - var instances = goog.net.XhrIo.sendInstances_; - while (instances.length) { - instances.pop().dispose(); - } -}; +ol.source.ImageOptions; + /** - * Installs exception protection for all entry point introduced by - * goog.net.XhrIo instances which are not protected by - * {@link goog.debug.ErrorHandler#protectWindowSetTimeout}, - * {@link goog.debug.ErrorHandler#protectWindowSetInterval}, or - * {@link goog.events.protectBrowserEventEntryPoint}. + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for sources providing a single image. * - * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry point(s). + * @constructor + * @extends {ol.source.Source} + * @param {ol.source.ImageOptions} options Single image source options. + * @api */ -goog.net.XhrIo.protectEntryPoints = function(errorHandler) { - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = - errorHandler.protectEntryPoint( - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); -}; +ol.source.Image = function(options) { + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + logo: options.logo, + projection: options.projection, + state: options.state + }); -/** - * Disposes of the specified goog.net.XhrIo created by - * {@link goog.net.XhrIo.send} and removes it from - * {@link goog.net.XhrIo.pendingStaticSendInstances_}. - * @private - */ -goog.net.XhrIo.prototype.cleanupSend_ = function() { - this.dispose(); - goog.array.remove(goog.net.XhrIo.sendInstances_, this); -}; + /** + * @private + * @type {Array.<number>} + */ + this.resolutions_ = options.resolutions !== undefined ? + options.resolutions : null; + goog.asserts.assert(!this.resolutions_ || + goog.array.isSorted(this.resolutions_, + function(a, b) { + return b - a; + }, true), 'resolutions must be null or sorted in descending order'); -/** - * Returns the number of milliseconds after which an incomplete request will be - * aborted, or 0 if no timeout is set. - * @return {number} Timeout interval in milliseconds. - */ -goog.net.XhrIo.prototype.getTimeoutInterval = function() { - return this.timeoutInterval_; -}; + /** + * @private + * @type {ol.reproj.Image} + */ + this.reprojectedImage_ = null; -/** - * Sets the number of milliseconds after which an incomplete request will be - * aborted and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no - * timeout is set. - * @param {number} ms Timeout interval in milliseconds; 0 means none. - */ -goog.net.XhrIo.prototype.setTimeoutInterval = function(ms) { - this.timeoutInterval_ = Math.max(0, ms); + /** + * @private + * @type {number} + */ + this.reprojectedRevision_ = 0; + }; +goog.inherits(ol.source.Image, ol.source.Source); /** - * Sets the desired type for the response. At time of writing, this is only - * supported in very recent versions of WebKit (10.0.612.1 dev and later). - * - * If this is used, the response may only be accessed via {@link #getResponse}. - * - * @param {goog.net.XhrIo.ResponseType} type The desired type for the response. + * @return {Array.<number>} Resolutions. */ -goog.net.XhrIo.prototype.setResponseType = function(type) { - this.responseType_ = type; +ol.source.Image.prototype.getResolutions = function() { + return this.resolutions_; }; /** - * Gets the desired type for the response. - * @return {goog.net.XhrIo.ResponseType} The desired type for the response. + * @protected + * @param {number} resolution Resolution. + * @return {number} Resolution. */ -goog.net.XhrIo.prototype.getResponseType = function() { - return this.responseType_; +ol.source.Image.prototype.findNearestResolution = + function(resolution) { + if (this.resolutions_) { + var idx = ol.array.linearFindNearest(this.resolutions_, resolution, 0); + resolution = this.resolutions_[idx]; + } + return resolution; }; /** - * Sets whether a "credentialed" request that is aware of cookie and - * authentication information should be made. This option is only supported by - * browsers that support HTTP Access Control. As of this writing, this option - * is not supported in IE. - * - * @param {boolean} withCredentials Whether this should be a "credentialed" - * request. + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.ImageBase} Single image. */ -goog.net.XhrIo.prototype.setWithCredentials = function(withCredentials) { - this.withCredentials_ = withCredentials; +ol.source.Image.prototype.getImage = + function(extent, resolution, pixelRatio, projection) { + var sourceProjection = this.getProjection(); + if (!ol.ENABLE_RASTER_REPROJECTION || + !sourceProjection || + !projection || + ol.proj.equivalent(sourceProjection, projection)) { + if (sourceProjection) { + projection = sourceProjection; + } + return this.getImageInternal(extent, resolution, pixelRatio, projection); + } else { + if (this.reprojectedImage_) { + if (this.reprojectedRevision_ == this.getRevision() && + ol.proj.equivalent( + this.reprojectedImage_.getProjection(), projection) && + this.reprojectedImage_.getResolution() == resolution && + this.reprojectedImage_.getPixelRatio() == pixelRatio && + ol.extent.equals(this.reprojectedImage_.getExtent(), extent)) { + return this.reprojectedImage_; + } + this.reprojectedImage_.dispose(); + this.reprojectedImage_ = null; + } + + this.reprojectedImage_ = new ol.reproj.Image( + sourceProjection, projection, extent, resolution, pixelRatio, + goog.bind(function(extent, resolution, pixelRatio) { + return this.getImageInternal(extent, resolution, + pixelRatio, sourceProjection); + }, this)); + this.reprojectedRevision_ = this.getRevision(); + + return this.reprojectedImage_; + } }; /** - * Gets whether a "credentialed" request is to be sent. - * @return {boolean} The desired type for the response. + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.ImageBase} Single image. + * @protected */ -goog.net.XhrIo.prototype.getWithCredentials = function() { - return this.withCredentials_; -}; +ol.source.Image.prototype.getImageInternal = goog.abstractMethod; /** - * Sets whether progress events are enabled for this request. Note - * that progress events require pre-flight OPTIONS request handling - * for CORS requests, and may cause trouble with older browsers. See - * progressEventsEnabled_ for details. - * @param {boolean} enabled Whether progress events should be enabled. + * Handle image change events. + * @param {goog.events.Event} event Event. + * @protected */ -goog.net.XhrIo.prototype.setProgressEventsEnabled = function(enabled) { - this.progressEventsEnabled_ = enabled; +ol.source.Image.prototype.handleImageChange = function(event) { + var image = /** @type {ol.Image} */ (event.target); + switch (image.getState()) { + case ol.ImageState.LOADING: + this.dispatchEvent( + new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADSTART, + image)); + break; + case ol.ImageState.LOADED: + this.dispatchEvent( + new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADEND, + image)); + break; + case ol.ImageState.ERROR: + this.dispatchEvent( + new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADERROR, + image)); + break; + } }; /** - * Gets whether progress events are enabled. - * @return {boolean} Whether progress events are enabled for this request. + * Default image load function for image sources that use ol.Image image + * instances. + * @param {ol.Image} image Image. + * @param {string} src Source. */ -goog.net.XhrIo.prototype.getProgressEventsEnabled = function() { - return this.progressEventsEnabled_; +ol.source.Image.defaultImageLoadFunction = function(image, src) { + image.getImage().src = src; }; + /** - * Instance send that actually uses XMLHttpRequest to make a server call. - * @param {string|goog.Uri} url Uri to make request to. - * @param {string=} opt_method Send method, default: GET. - * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} - * opt_content Body data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. + * @classdesc + * Events emitted by {@link ol.source.Image} instances are instances of this + * type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.source.ImageEvent} + * @param {string} type Type. + * @param {ol.Image} image The image. */ -goog.net.XhrIo.prototype.send = function(url, opt_method, opt_content, - opt_headers) { - if (this.xhr_) { - throw Error('[goog.net.XhrIo] Object is active with another request=' + - this.lastUri_ + '; newUri=' + url); - } +ol.source.ImageEvent = function(type, image) { - var method = opt_method ? opt_method.toUpperCase() : 'GET'; + goog.base(this, type); - this.lastUri_ = url; - this.lastError_ = ''; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - this.lastMethod_ = method; - this.errorDispatched_ = false; - this.active_ = true; + /** + * The image related to the event. + * @type {ol.Image} + * @api + */ + this.image = image; - // Use the factory to create the XHR object and options - this.xhr_ = this.createXhr(); - this.xhrOptions_ = this.xmlHttpFactory_ ? - this.xmlHttpFactory_.getOptions() : goog.net.XmlHttp.getOptions(); +}; +goog.inherits(ol.source.ImageEvent, goog.events.Event); - // Set up the onreadystatechange callback - this.xhr_.onreadystatechange = goog.bind(this.onReadyStateChange_, this); - // Set up upload/download progress events, if progress events are supported. - if (this.getProgressEventsEnabled() && 'onprogress' in this.xhr_) { - this.xhr_.onprogress = goog.bind(this.onProgressHandler_, this); - if (this.xhr_.upload) { - this.xhr_.upload.onprogress = goog.bind(this.onProgressHandler_, this); - } - } +/** + * @enum {string} + */ +ol.source.ImageEventType = { /** - * Try to open the XMLHttpRequest (always async), if an error occurs here it - * is generally permission denied - * @preserveTry + * Triggered when an image starts loading. + * @event ol.source.ImageEvent#imageloadstart + * @api */ - try { - goog.log.fine(this.logger_, this.formatMsg_('Opening Xhr')); - this.inOpen_ = true; - this.xhr_.open(method, String(url), true); // Always async! - this.inOpen_ = false; - } catch (err) { - goog.log.fine(this.logger_, - this.formatMsg_('Error opening Xhr: ' + err.message)); - this.error_(goog.net.ErrorCode.EXCEPTION, err); - return; - } + IMAGELOADSTART: 'imageloadstart', - // We can't use null since this won't allow requests with form data to have a - // content length specified which will cause some proxies to return a 411 - // error. - var content = opt_content || ''; + /** + * Triggered when an image finishes loading. + * @event ol.source.ImageEvent#imageloadend + * @api + */ + IMAGELOADEND: 'imageloadend', - var headers = this.headers.clone(); + /** + * Triggered if image loading results in an error. + * @event ol.source.ImageEvent#imageloaderror + * @api + */ + IMAGELOADERROR: 'imageloaderror' - // Add headers specific to this request - if (opt_headers) { - goog.structs.forEach(opt_headers, function(value, key) { - headers.set(key, value); - }); - } +}; - // Find whether a content type header is set, ignoring case. - // HTTP header names are case-insensitive. See: - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 - var contentTypeKey = goog.array.find(headers.getKeys(), - goog.net.XhrIo.isContentTypeHeader_); +goog.provide('ol.source.ImageCanvas'); - var contentIsFormData = (goog.global['FormData'] && - (content instanceof goog.global['FormData'])); - if (goog.array.contains(goog.net.XhrIo.METHODS_WITH_FORM_DATA, method) && - !contentTypeKey && !contentIsFormData) { - // For requests typically with form data, default to the url-encoded form - // content type unless this is a FormData request. For FormData, - // the browser will automatically add a multipart/form-data content type - // with an appropriate multipart boundary. - headers.set(goog.net.XhrIo.CONTENT_TYPE_HEADER, - goog.net.XhrIo.FORM_CONTENT_TYPE); - } +goog.require('ol.CanvasFunctionType'); +goog.require('ol.ImageCanvas'); +goog.require('ol.extent'); +goog.require('ol.source.Image'); - // Add the headers to the Xhr object - headers.forEach(function(value, key) { - this.xhr_.setRequestHeader(key, value); - }, this); - if (this.responseType_) { - this.xhr_.responseType = this.responseType_; - } - if (goog.object.containsKey(this.xhr_, 'withCredentials')) { - this.xhr_.withCredentials = this.withCredentials_; - } +/** + * @classdesc + * Base class for image sources where a canvas element is the image. + * + * @constructor + * @extends {ol.source.Image} + * @param {olx.source.ImageCanvasOptions} options + * @api + */ +ol.source.ImageCanvas = function(options) { + + goog.base(this, { + attributions: options.attributions, + logo: options.logo, + projection: options.projection, + resolutions: options.resolutions, + state: options.state !== undefined ? + /** @type {ol.source.State} */ (options.state) : undefined + }); /** - * Try to send the request, or other wise report an error (404 not found). - * @preserveTry + * @private + * @type {ol.CanvasFunctionType} */ - try { - this.cleanUpTimeoutTimer_(); // Paranoid, should never be running. - if (this.timeoutInterval_ > 0) { - this.useXhr2Timeout_ = goog.net.XhrIo.shouldUseXhr2Timeout_(this.xhr_); - goog.log.fine(this.logger_, this.formatMsg_('Will abort after ' + - this.timeoutInterval_ + 'ms if incomplete, xhr2 ' + - this.useXhr2Timeout_)); - if (this.useXhr2Timeout_) { - this.xhr_[goog.net.XhrIo.XHR2_TIMEOUT_] = this.timeoutInterval_; - this.xhr_[goog.net.XhrIo.XHR2_ON_TIMEOUT_] = - goog.bind(this.timeout_, this); - } else { - this.timeoutId_ = goog.Timer.callOnce(this.timeout_, - this.timeoutInterval_, this); - } - } - goog.log.fine(this.logger_, this.formatMsg_('Sending request')); - this.inSend_ = true; - this.xhr_.send(content); - this.inSend_ = false; - - } catch (err) { - goog.log.fine(this.logger_, this.formatMsg_('Send error: ' + err.message)); - this.error_(goog.net.ErrorCode.EXCEPTION, err); - } -}; + this.canvasFunction_ = options.canvasFunction; + /** + * @private + * @type {ol.ImageCanvas} + */ + this.canvas_ = null; -/** - * Determines if the argument is an XMLHttpRequest that supports the level 2 - * timeout value and event. - * - * Currently, FF 21.0 OS X has the fields but won't actually call the timeout - * handler. Perhaps the confusion in the bug referenced below hasn't - * entirely been resolved. - * - * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute - * @see https://bugzilla.mozilla.org/show_bug.cgi?id=525816 - * - * @param {!goog.net.XhrLike.OrNative} xhr The request. - * @return {boolean} True if the request supports level 2 timeout. - * @private - */ -goog.net.XhrIo.shouldUseXhr2Timeout_ = function(xhr) { - return goog.userAgent.IE && - goog.userAgent.isVersionOrHigher(9) && - goog.isNumber(xhr[goog.net.XhrIo.XHR2_TIMEOUT_]) && - goog.isDef(xhr[goog.net.XhrIo.XHR2_ON_TIMEOUT_]); -}; + /** + * @private + * @type {number} + */ + this.renderedRevision_ = 0; + /** + * @private + * @type {number} + */ + this.ratio_ = options.ratio !== undefined ? + options.ratio : 1.5; -/** - * @param {string} header An HTTP header key. - * @return {boolean} Whether the key is a content type header (ignoring - * case. - * @private - */ -goog.net.XhrIo.isContentTypeHeader_ = function(header) { - return goog.string.caseInsensitiveEquals( - goog.net.XhrIo.CONTENT_TYPE_HEADER, header); }; +goog.inherits(ol.source.ImageCanvas, ol.source.Image); /** - * Creates a new XHR object. - * @return {!goog.net.XhrLike.OrNative} The newly created XHR object. - * @protected + * @inheritDoc */ -goog.net.XhrIo.prototype.createXhr = function() { - return this.xmlHttpFactory_ ? - this.xmlHttpFactory_.createInstance() : goog.net.XmlHttp(); -}; - +ol.source.ImageCanvas.prototype.getImageInternal = + function(extent, resolution, pixelRatio, projection) { + resolution = this.findNearestResolution(resolution); -/** - * The request didn't complete after {@link goog.net.XhrIo#timeoutInterval_} - * milliseconds; raises a {@link goog.net.EventType.TIMEOUT} event and aborts - * the request. - * @private - */ -goog.net.XhrIo.prototype.timeout_ = function() { - if (typeof goog == 'undefined') { - // If goog is undefined then the callback has occurred as the application - // is unloading and will error. Thus we let it silently fail. - } else if (this.xhr_) { - this.lastError_ = 'Timed out after ' + this.timeoutInterval_ + - 'ms, aborting'; - this.lastErrorCode_ = goog.net.ErrorCode.TIMEOUT; - goog.log.fine(this.logger_, this.formatMsg_(this.lastError_)); - this.dispatchEvent(goog.net.EventType.TIMEOUT); - this.abort(goog.net.ErrorCode.TIMEOUT); + var canvas = this.canvas_; + if (canvas && + this.renderedRevision_ == this.getRevision() && + canvas.getResolution() == resolution && + canvas.getPixelRatio() == pixelRatio && + ol.extent.containsExtent(canvas.getExtent(), extent)) { + return canvas; } -}; + extent = extent.slice(); + ol.extent.scaleFromCenter(extent, this.ratio_); + var width = ol.extent.getWidth(extent) / resolution; + var height = ol.extent.getHeight(extent) / resolution; + var size = [width * pixelRatio, height * pixelRatio]; -/** - * Something errorred, so inactivate, fire error callback and clean up - * @param {goog.net.ErrorCode} errorCode The error code. - * @param {Error} err The error object. - * @private - */ -goog.net.XhrIo.prototype.error_ = function(errorCode, err) { - this.active_ = false; - if (this.xhr_) { - this.inAbort_ = true; - this.xhr_.abort(); // Ensures XHR isn't hung (FF) - this.inAbort_ = false; + var canvasElement = this.canvasFunction_( + extent, resolution, pixelRatio, size, projection); + if (canvasElement) { + canvas = new ol.ImageCanvas(extent, resolution, pixelRatio, + this.getAttributions(), canvasElement); } - this.lastError_ = err; - this.lastErrorCode_ = errorCode; - this.dispatchErrors_(); - this.cleanUpXhr_(); + this.canvas_ = canvas; + this.renderedRevision_ = this.getRevision(); + + return canvas; }; +goog.provide('ol.Feature'); +goog.provide('ol.FeatureStyleFunction'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol'); +goog.require('ol.Object'); +goog.require('ol.geom.Geometry'); +goog.require('ol.style.Style'); -/** - * Dispatches COMPLETE and ERROR in case of an error. This ensures that we do - * not dispatch multiple error events. - * @private - */ -goog.net.XhrIo.prototype.dispatchErrors_ = function() { - if (!this.errorDispatched_) { - this.errorDispatched_ = true; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ERROR); - } -}; /** - * Abort the current XMLHttpRequest - * @param {goog.net.ErrorCode=} opt_failureCode Optional error code to use - - * defaults to ABORT. + * @classdesc + * A vector object for geographic features with a geometry and other + * attribute properties, similar to the features in vector file formats like + * GeoJSON. + * + * Features can be styled individually with `setStyle`; otherwise they use the + * style of their vector layer. + * + * Note that attribute properties are set as {@link ol.Object} properties on + * the feature object, so they are observable, and have get/set accessors. + * + * Typically, a feature has a single geometry property. You can set the + * geometry using the `setGeometry` method and get it with `getGeometry`. + * It is possible to store more than one geometry on a feature using attribute + * properties. By default, the geometry used for rendering is identified by + * the property name `geometry`. If you want to use another geometry property + * for rendering, use the `setGeometryName` method to change the attribute + * property associated with the geometry for the feature. For example: + * + * ```js + * var feature = new ol.Feature({ + * geometry: new ol.geom.Polygon(polyCoords), + * labelPoint: new ol.geom.Point(labelCoords), + * name: 'My Polygon' + * }); + * + * // get the polygon geometry + * var poly = feature.getGeometry(); + * + * // Render the feature as a point using the coordinates from labelPoint + * feature.setGeometryName('labelPoint'); + * + * // get the point geometry + * var point = feature.getGeometry(); + * ``` + * + * @constructor + * @extends {ol.Object} + * @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties + * You may pass a Geometry object directly, or an object literal + * containing properties. If you pass an object literal, you may + * include a Geometry associated with a `geometry` key. + * @api stable */ -goog.net.XhrIo.prototype.abort = function(opt_failureCode) { - if (this.xhr_ && this.active_) { - goog.log.fine(this.logger_, this.formatMsg_('Aborting')); - this.active_ = false; - this.inAbort_ = true; - this.xhr_.abort(); - this.inAbort_ = false; - this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ABORT); - this.cleanUpXhr_(); - } -}; +ol.Feature = function(opt_geometryOrProperties) { + goog.base(this); -/** - * Nullifies all callbacks to reduce risks of leaks. - * @override - * @protected - */ -goog.net.XhrIo.prototype.disposeInternal = function() { - if (this.xhr_) { - // We explicitly do not call xhr_.abort() unless active_ is still true. - // This is to avoid unnecessarily aborting a successful request when - // dispose() is called in a callback triggered by a complete response, but - // in which browser cleanup has not yet finished. - // (See http://b/issue?id=1684217.) - if (this.active_) { - this.active_ = false; - this.inAbort_ = true; - this.xhr_.abort(); - this.inAbort_ = false; + /** + * @private + * @type {number|string|undefined} + */ + this.id_ = undefined; + + /** + * @type {string} + * @private + */ + this.geometryName_ = 'geometry'; + + /** + * User provided style. + * @private + * @type {ol.style.Style|Array.<ol.style.Style>| + * ol.FeatureStyleFunction} + */ + this.style_ = null; + + /** + * @private + * @type {ol.FeatureStyleFunction|undefined} + */ + this.styleFunction_ = undefined; + + /** + * @private + * @type {goog.events.Key} + */ + this.geometryChangeKey_ = null; + + goog.events.listen( + this, ol.Object.getChangeEventType(this.geometryName_), + this.handleGeometryChanged_, false, this); + + if (opt_geometryOrProperties !== undefined) { + if (opt_geometryOrProperties instanceof ol.geom.Geometry || + !opt_geometryOrProperties) { + var geometry = /** @type {ol.geom.Geometry} */ (opt_geometryOrProperties); + this.setGeometry(geometry); + } else { + goog.asserts.assert(goog.isObject(opt_geometryOrProperties), + 'opt_geometryOrProperties should be an Object'); + var properties = /** @type {Object.<string, *>} */ + (opt_geometryOrProperties); + this.setProperties(properties); } - this.cleanUpXhr_(true); } - - goog.net.XhrIo.base(this, 'disposeInternal'); }; +goog.inherits(ol.Feature, ol.Object); /** - * Internal handler for the XHR object's readystatechange event. This method - * checks the status and the readystate and fires the correct callbacks. - * If the request has ended, the handlers are cleaned up and the XHR object is - * nullified. - * @private + * Clone this feature. If the original feature has a geometry it + * is also cloned. The feature id is not set in the clone. + * @return {ol.Feature} The clone. + * @api stable */ -goog.net.XhrIo.prototype.onReadyStateChange_ = function() { - if (this.isDisposed()) { - // This method is the target of an untracked goog.Timer.callOnce(). - return; +ol.Feature.prototype.clone = function() { + var clone = new ol.Feature(this.getProperties()); + clone.setGeometryName(this.getGeometryName()); + var geometry = this.getGeometry(); + if (geometry) { + clone.setGeometry(geometry.clone()); } - if (!this.inOpen_ && !this.inSend_ && !this.inAbort_) { - // Were not being called from within a call to this.xhr_.send - // this.xhr_.abort, or this.xhr_.open, so this is an entry point - this.onReadyStateChangeEntryPoint_(); - } else { - this.onReadyStateChangeHelper_(); + var style = this.getStyle(); + if (style) { + clone.setStyle(style); } + return clone; }; /** - * Used to protect the onreadystatechange handler entry point. Necessary - * as {#onReadyStateChange_} maybe called from within send or abort, this - * method is only called when {#onReadyStateChange_} is called as an - * entry point. - * {@see #protectEntryPoints} - * @private + * Get the feature's default geometry. A feature may have any number of named + * geometries. The "default" geometry (the one that is rendered by default) is + * set when calling {@link ol.Feature#setGeometry}. + * @return {ol.geom.Geometry|undefined} The default geometry for the feature. + * @api stable + * @observable */ -goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = function() { - this.onReadyStateChangeHelper_(); +ol.Feature.prototype.getGeometry = function() { + return /** @type {ol.geom.Geometry|undefined} */ ( + this.get(this.geometryName_)); }; /** - * Helper for {@link #onReadyStateChange_}. This is used so that - * entry point calls to {@link #onReadyStateChange_} can be routed through - * {@link #onReadyStateChangeEntryPoint_}. - * @private + * Get the feature identifier. This is a stable identifier for the feature and + * is either set when reading data from a remote source or set explicitly by + * calling {@link ol.Feature#setId}. + * @return {number|string|undefined} Id. + * @api stable + * @observable */ -goog.net.XhrIo.prototype.onReadyStateChangeHelper_ = function() { - if (!this.active_) { - // can get called inside abort call - return; - } - - if (typeof goog == 'undefined') { - // NOTE(user): If goog is undefined then the callback has occurred as the - // application is unloading and will error. Thus we let it silently fail. - - } else if ( - this.xhrOptions_[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] && - this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE && - this.getStatus() == 2) { - // NOTE(user): In IE if send() errors on a *local* request the readystate - // is still changed to COMPLETE. We need to ignore it and allow the - // try/catch around send() to pick up the error. - goog.log.fine(this.logger_, this.formatMsg_( - 'Local request error detected and ignored')); - - } else { - - // In IE when the response has been cached we sometimes get the callback - // from inside the send call and this usually breaks code that assumes that - // XhrIo is asynchronous. If that is the case we delay the callback - // using a timer. - if (this.inSend_ && - this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE) { - goog.Timer.callOnce(this.onReadyStateChange_, 0, this); - return; - } +ol.Feature.prototype.getId = function() { + return this.id_; +}; - this.dispatchEvent(goog.net.EventType.READY_STATE_CHANGE); - // readyState indicates the transfer has finished - if (this.isComplete()) { - goog.log.fine(this.logger_, this.formatMsg_('Request complete')); +/** + * Get the name of the feature's default geometry. By default, the default + * geometry is named `geometry`. + * @return {string} Get the property name associated with the default geometry + * for this feature. + * @api stable + */ +ol.Feature.prototype.getGeometryName = function() { + return this.geometryName_; +}; - this.active_ = false; - try { - // Call the specific callbacks for success or failure. Only call the - // success if the status is 200 (HTTP_OK) or 304 (HTTP_CACHED) - if (this.isSuccess()) { - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.SUCCESS); - } else { - this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; - this.lastError_ = - this.getStatusText() + ' [' + this.getStatus() + ']'; - this.dispatchErrors_(); - } - } finally { - this.cleanUpXhr_(); - } - } - } +/** + * Get the feature's style. This return for this method depends on what was + * provided to the {@link ol.Feature#setStyle} method. + * @return {ol.style.Style|Array.<ol.style.Style>| + * ol.FeatureStyleFunction} The feature style. + * @api stable + * @observable + */ +ol.Feature.prototype.getStyle = function() { + return this.style_; }; /** - * Internal handler for the XHR object's onprogress event. - * @param {!ProgressEvent} e XHR progress event. - * @private + * Get the feature's style function. + * @return {ol.FeatureStyleFunction|undefined} Return a function + * representing the current style of this feature. + * @api stable */ -goog.net.XhrIo.prototype.onProgressHandler_ = function(e) { - goog.asserts.assert(e.type === goog.net.EventType.PROGRESS, - 'goog.net.EventType.PROGRESS is of the same type as raw XHR progress.'); - // Redispatch the progress event. - this.dispatchEvent(e); +ol.Feature.prototype.getStyleFunction = function() { + return this.styleFunction_; }; /** - * Remove the listener to protect against leaks, and nullify the XMLHttpRequest - * object. - * @param {boolean=} opt_fromDispose If this is from the dispose (don't want to - * fire any events). * @private */ -goog.net.XhrIo.prototype.cleanUpXhr_ = function(opt_fromDispose) { - if (this.xhr_) { - // Cancel any pending timeout event handler. - this.cleanUpTimeoutTimer_(); - - // Save reference so we can mark it as closed after the READY event. The - // READY event may trigger another request, thus we must nullify this.xhr_ - var xhr = this.xhr_; - var clearedOnReadyStateChange = - this.xhrOptions_[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] ? - goog.nullFunction : null; - this.xhr_ = null; - this.xhrOptions_ = null; - - if (!opt_fromDispose) { - this.dispatchEvent(goog.net.EventType.READY); - } - - try { - // NOTE(user): Not nullifying in FireFox can still leak if the callbacks - // are defined in the same scope as the instance of XhrIo. But, IE doesn't - // allow you to set the onreadystatechange to NULL so nullFunction is - // used. - xhr.onreadystatechange = clearedOnReadyStateChange; - } catch (e) { - // This seems to occur with a Gears HTTP request. Delayed the setting of - // this onreadystatechange until after READY is sent out and catching the - // error to see if we can track down the problem. - goog.log.error(this.logger_, - 'Problem encountered resetting onreadystatechange: ' + e.message); - } - } +ol.Feature.prototype.handleGeometryChange_ = function() { + this.changed(); }; /** - * Make sure the timeout timer isn't running. * @private */ -goog.net.XhrIo.prototype.cleanUpTimeoutTimer_ = function() { - if (this.xhr_ && this.useXhr2Timeout_) { - this.xhr_[goog.net.XhrIo.XHR2_ON_TIMEOUT_] = null; +ol.Feature.prototype.handleGeometryChanged_ = function() { + if (this.geometryChangeKey_) { + goog.events.unlistenByKey(this.geometryChangeKey_); + this.geometryChangeKey_ = null; } - if (goog.isNumber(this.timeoutId_)) { - goog.Timer.clear(this.timeoutId_); - this.timeoutId_ = null; + var geometry = this.getGeometry(); + if (geometry) { + this.geometryChangeKey_ = goog.events.listen(geometry, + goog.events.EventType.CHANGE, this.handleGeometryChange_, false, this); } + this.changed(); }; /** - * @return {boolean} Whether there is an active request. + * Set the default geometry for the feature. This will update the property + * with the name returned by {@link ol.Feature#getGeometryName}. + * @param {ol.geom.Geometry|undefined} geometry The new geometry. + * @api stable + * @observable */ -goog.net.XhrIo.prototype.isActive = function() { - return !!this.xhr_; +ol.Feature.prototype.setGeometry = function(geometry) { + this.set(this.geometryName_, geometry); }; /** - * @return {boolean} Whether the request has completed. + * Set the style for the feature. This can be a single style object, an array + * of styles, or a function that takes a resolution and returns an array of + * styles. If it is `null` the feature has no style (a `null` style). + * @param {ol.style.Style|Array.<ol.style.Style>| + * ol.FeatureStyleFunction} style Style for this feature. + * @api stable + * @observable */ -goog.net.XhrIo.prototype.isComplete = function() { - return this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE; +ol.Feature.prototype.setStyle = function(style) { + this.style_ = style; + this.styleFunction_ = !style ? + undefined : ol.Feature.createStyleFunction(style); + this.changed(); }; /** - * @return {boolean} Whether the request completed with a success. + * Set the feature id. The feature id is considered stable and may be used when + * requesting features or comparing identifiers returned from a remote source. + * The feature id can be used with the {@link ol.source.Vector#getFeatureById} + * method. + * @param {number|string|undefined} id The feature id. + * @api stable + * @observable */ -goog.net.XhrIo.prototype.isSuccess = function() { - var status = this.getStatus(); - // A zero status code is considered successful for local files. - return goog.net.HttpStatus.isSuccess(status) || - status === 0 && !this.isLastUriEffectiveSchemeHttp_(); +ol.Feature.prototype.setId = function(id) { + this.id_ = id; + this.changed(); }; /** - * @return {boolean} whether the effective scheme of the last URI that was - * fetched was 'http' or 'https'. - * @private + * Set the property name to be used when getting the feature's default geometry. + * When calling {@link ol.Feature#getGeometry}, the value of the property with + * this name will be returned. + * @param {string} name The property name of the default geometry. + * @api stable */ -goog.net.XhrIo.prototype.isLastUriEffectiveSchemeHttp_ = function() { - var scheme = goog.uri.utils.getEffectiveScheme(String(this.lastUri_)); - return goog.net.XhrIo.HTTP_SCHEME_PATTERN.test(scheme); +ol.Feature.prototype.setGeometryName = function(name) { + goog.events.unlisten( + this, ol.Object.getChangeEventType(this.geometryName_), + this.handleGeometryChanged_, false, this); + this.geometryName_ = name; + goog.events.listen( + this, ol.Object.getChangeEventType(this.geometryName_), + this.handleGeometryChanged_, false, this); + this.handleGeometryChanged_(); }; /** - * Get the readystate from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {goog.net.XmlHttp.ReadyState} goog.net.XmlHttp.ReadyState.*. + * A function that returns an array of {@link ol.style.Style styles} given a + * resolution. The `this` keyword inside the function references the + * {@link ol.Feature} to be styled. + * + * @typedef {function(this: ol.Feature, number): + * (ol.style.Style|Array.<ol.style.Style>)} + * @api stable */ -goog.net.XhrIo.prototype.getReadyState = function() { - return this.xhr_ ? - /** @type {goog.net.XmlHttp.ReadyState} */ (this.xhr_.readyState) : - goog.net.XmlHttp.ReadyState.UNINITIALIZED; -}; +ol.FeatureStyleFunction; /** - * Get the status from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {number} Http status. + * Convert the provided object into a feature style function. Functions passed + * through unchanged. Arrays of ol.style.Style or single style objects wrapped + * in a new feature style function. + * @param {ol.FeatureStyleFunction|!Array.<ol.style.Style>|!ol.style.Style} obj + * A feature style function, a single style, or an array of styles. + * @return {ol.FeatureStyleFunction} A style function. */ -goog.net.XhrIo.prototype.getStatus = function() { - /** - * IE doesn't like you checking status until the readystate is greater than 2 - * (i.e. it is receiving or complete). The try/catch is used for when the - * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. - * @preserveTry - */ - try { - return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? - this.xhr_.status : -1; - } catch (e) { - return -1; - } -}; - +ol.Feature.createStyleFunction = function(obj) { + var styleFunction; -/** - * Get the status text from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {string} Status text. - */ -goog.net.XhrIo.prototype.getStatusText = function() { - /** - * IE doesn't like you checking status until the readystate is greater than 2 - * (i.e. it is recieving or complete). The try/catch is used for when the - * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. - * @preserveTry - */ - try { - return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? - this.xhr_.statusText : ''; - } catch (e) { - goog.log.fine(this.logger_, 'Can not get status: ' + e.message); - return ''; + if (goog.isFunction(obj)) { + styleFunction = obj; + } else { + /** + * @type {Array.<ol.style.Style>} + */ + var styles; + if (goog.isArray(obj)) { + styles = obj; + } else { + goog.asserts.assertInstanceof(obj, ol.style.Style, + 'obj should be an ol.style.Style'); + styles = [obj]; + } + styleFunction = function() { + return styles; + }; } + return styleFunction; }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Get the last Uri that was requested - * @return {string} Last Uri. + * @fileoverview Common events for the network classes. */ -goog.net.XhrIo.prototype.getLastUri = function() { - return String(this.lastUri_); -}; -/** - * Get the response text from the Xhr object - * Will only return correct result when called from the context of a callback. - * @return {string} Result from the server, or '' if no result available. - */ -goog.net.XhrIo.prototype.getResponseText = function() { - /** @preserveTry */ - try { - return this.xhr_ ? this.xhr_.responseText : ''; - } catch (e) { - // http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute - // states that responseText should return '' (and responseXML null) - // when the state is not LOADING or DONE. Instead, IE can - // throw unexpected exceptions, for example when a request is aborted - // or no data is available yet. - goog.log.fine(this.logger_, 'Can not get responseText: ' + e.message); - return ''; - } -}; +goog.provide('goog.net.EventType'); /** - * Get the response body from the Xhr object. This property is only available - * in IE since version 7 according to MSDN: - * http://msdn.microsoft.com/en-us/library/ie/ms534368(v=vs.85).aspx - * Will only return correct result when called from the context of a callback. - * - * One option is to construct a VBArray from the returned object and convert - * it to a JavaScript array using the toArray method: - * {@code (new window['VBArray'](xhrIo.getResponseBody())).toArray()} - * This will result in an array of numbers in the range of [0..255] - * - * Another option is to use the VBScript CStr method to convert it into a - * string as outlined in http://stackoverflow.com/questions/1919972 - * - * @return {Object} Binary result from the server or null if not available. + * Event names for network events + * @enum {string} */ -goog.net.XhrIo.prototype.getResponseBody = function() { - /** @preserveTry */ - try { - if (this.xhr_ && 'responseBody' in this.xhr_) { - return this.xhr_['responseBody']; - } - } catch (e) { - // IE can throw unexpected exceptions, for example when a request is aborted - // or no data is yet available. - goog.log.fine(this.logger_, 'Can not get responseBody: ' + e.message); - } - return null; +goog.net.EventType = { + COMPLETE: 'complete', + SUCCESS: 'success', + ERROR: 'error', + ABORT: 'abort', + READY: 'ready', + READY_STATE_CHANGE: 'readystatechange', + TIMEOUT: 'timeout', + INCREMENTAL_DATA: 'incrementaldata', + PROGRESS: 'progress' }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +goog.provide('goog.Thenable'); -/** - * Get the response XML from the Xhr object - * Will only return correct result when called from the context of a callback. - * @return {Document} The DOM Document representing the XML file, or null - * if no result available. - */ -goog.net.XhrIo.prototype.getResponseXml = function() { - /** @preserveTry */ - try { - return this.xhr_ ? this.xhr_.responseXML : null; - } catch (e) { - goog.log.fine(this.logger_, 'Can not get responseXML: ' + e.message); - return null; - } -}; /** - * Get the response and evaluates it as JSON from the Xhr object - * Will only return correct result when called from the context of a callback - * @param {string=} opt_xssiPrefix Optional XSSI prefix string to use for - * stripping of the response before parsing. This needs to be set only if - * your backend server prepends the same prefix string to the JSON response. - * @return {Object|undefined} JavaScript object. + * Provides a more strict interface for Thenables in terms of + * http://promisesaplus.com for interop with {@see goog.Promise}. + * + * @interface + * @extends {IThenable<TYPE>} + * @template TYPE */ -goog.net.XhrIo.prototype.getResponseJson = function(opt_xssiPrefix) { - if (!this.xhr_) { - return undefined; - } - - var responseText = this.xhr_.responseText; - if (opt_xssiPrefix && responseText.indexOf(opt_xssiPrefix) == 0) { - responseText = responseText.substring(opt_xssiPrefix.length); - } - - return goog.json.parse(responseText); -}; +goog.Thenable = function() {}; /** - * Get the response as the type specificed by {@link #setResponseType}. At time - * of writing, this is only directly supported in very recent versions of WebKit - * (10.0.612.1 dev and later). If the field is not supported directly, we will - * try to emulate it. + * Adds callbacks that will operate on the result of the Thenable, returning a + * new child Promise. * - * Emulating the response means following the rules laid out at - * http://www.w3.org/TR/XMLHttpRequest/#the-response-attribute + * If the Thenable is fulfilled, the {@code onFulfilled} callback will be + * invoked with the fulfillment value as argument, and the child Promise will + * be fulfilled with the return value of the callback. If the callback throws + * an exception, the child Promise will be rejected with the thrown value + * instead. * - * On browsers with no support for this (Chrome < 10, Firefox < 4, etc), only - * response types of DEFAULT or TEXT may be used, and the response returned will - * be the text response. + * If the Thenable is rejected, the {@code onRejected} callback will be invoked + * with the rejection reason as argument, and the child Promise will be rejected + * with the return value of the callback or thrown value. * - * On browsers with Mozilla's draft support for array buffers (Firefox 4, 5), - * only response types of DEFAULT, TEXT, and ARRAY_BUFFER may be used, and the - * response returned will be either the text response or the Mozilla - * implementation of the array buffer response. + * @param {?(function(this:THIS, TYPE): VALUE)=} opt_onFulfilled A + * function that will be invoked with the fulfillment value if the Promise + * is fullfilled. + * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will + * be invoked with the rejection reason if the Promise is rejected. + * @param {THIS=} opt_context An optional context object that will be the + * execution context for the callbacks. By default, functions are executed + * with the default this. * - * On browsers will full support, any valid response type supported by the - * browser may be used, and the response provided by the browser will be - * returned. + * @return {RESULT} A new Promise that will receive the result + * of the fulfillment or rejection callback. + * @template VALUE + * @template THIS + * + * When a Promise (or thenable) is returned from the fulfilled callback, + * the result is the payload of that promise, not the promise itself. + * + * @template RESULT := type('goog.Promise', + * cond(isUnknown(VALUE), unknown(), + * mapunion(VALUE, (V) => + * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), + * templateTypeOf(V, 0), + * cond(sub(V, 'Thenable'), + * unknown(), + * V))))) + * =: * - * @return {*} The response. */ -goog.net.XhrIo.prototype.getResponse = function() { - /** @preserveTry */ - try { - if (!this.xhr_) { - return null; - } - if ('response' in this.xhr_) { - return this.xhr_.response; - } - switch (this.responseType_) { - case goog.net.XhrIo.ResponseType.DEFAULT: - case goog.net.XhrIo.ResponseType.TEXT: - return this.xhr_.responseText; - // DOCUMENT and BLOB don't need to be handled here because they are - // introduced in the same spec that adds the .response field, and would - // have been caught above. - // ARRAY_BUFFER needs an implementation for Firefox 4, where it was - // implemented using a draft spec rather than the final spec. - case goog.net.XhrIo.ResponseType.ARRAY_BUFFER: - if ('mozResponseArrayBuffer' in this.xhr_) { - return this.xhr_.mozResponseArrayBuffer; - } - } - // Fell through to a response type that is not supported on this browser. - goog.log.error(this.logger_, - 'Response type ' + this.responseType_ + ' is not ' + - 'supported on this browser'); - return null; - } catch (e) { - goog.log.fine(this.logger_, 'Can not get response: ' + e.message); - return null; - } -}; +goog.Thenable.prototype.then = function(opt_onFulfilled, opt_onRejected, + opt_context) {}; /** - * Get the value of the response-header with the given name from the Xhr object - * Will only return correct result when called from the context of a callback - * and the request has completed - * @param {string} key The name of the response-header to retrieve. - * @return {string|undefined} The value of the response-header named key. + * An expando property to indicate that an object implements + * {@code goog.Thenable}. + * + * {@see addImplementation}. + * + * @const */ -goog.net.XhrIo.prototype.getResponseHeader = function(key) { - return this.xhr_ && this.isComplete() ? - this.xhr_.getResponseHeader(key) : undefined; -}; +goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable'; /** - * Gets the text of all the headers in the response. - * Will only return correct result when called from the context of a callback - * and the request has completed. - * @return {string} The value of the response headers or empty string. + * Marks a given class (constructor) as an implementation of Thenable, so + * that we can query that fact at runtime. The class must have already + * implemented the interface. + * Exports a 'then' method on the constructor prototype, so that the objects + * also implement the extern {@see goog.Thenable} interface for interop with + * other Promise implementations. + * @param {function(new:goog.Thenable,...?)} ctor The class constructor. The + * corresponding class must have already implemented the interface. */ -goog.net.XhrIo.prototype.getAllResponseHeaders = function() { - return this.xhr_ && this.isComplete() ? - this.xhr_.getAllResponseHeaders() : ''; +goog.Thenable.addImplementation = function(ctor) { + goog.exportProperty(ctor.prototype, 'then', ctor.prototype.then); + if (COMPILED) { + ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true; + } else { + // Avoids dictionary access in uncompiled mode. + ctor.prototype.$goog_Thenable = true; + } }; /** - * Returns all response headers as a key-value map. - * Multiple values for the same header key can be combined into one, - * separated by a comma and a space. - * Note that the native getResponseHeader method for retrieving a single header - * does a case insensitive match on the header name. This method does not - * include any case normalization logic, it will just return a key-value - * representation of the headers. - * See: http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method - * @return {!Object<string, string>} An object with the header keys as keys - * and header values as values. + * @param {*} object + * @return {boolean} Whether a given instance implements {@code goog.Thenable}. + * The class/superclass of the instance must call {@code addImplementation}. */ -goog.net.XhrIo.prototype.getResponseHeaders = function() { - var headersObject = {}; - var headersArray = this.getAllResponseHeaders().split('\r\n'); - for (var i = 0; i < headersArray.length; i++) { - if (goog.string.isEmptyOrWhitespace(headersArray[i])) { - continue; - } - var keyValue = goog.string.splitLimit(headersArray[i], ': ', 2); - if (headersObject[keyValue[0]]) { - headersObject[keyValue[0]] += ', ' + keyValue[1]; - } else { - headersObject[keyValue[0]] = keyValue[1]; +goog.Thenable.isImplementedBy = function(object) { + if (!object) { + return false; + } + try { + if (COMPILED) { + return !!object[goog.Thenable.IMPLEMENTED_BY_PROP]; } + return !!object.$goog_Thenable; + } catch (e) { + // Property access seems to be forbidden. + return false; } - return headersObject; -}; - - -/** - * Get the last error message - * @return {goog.net.ErrorCode} Last error code. - */ -goog.net.XhrIo.prototype.getLastErrorCode = function() { - return this.lastErrorCode_; -}; - - -/** - * Get the last error message - * @return {string} Last error message. - */ -goog.net.XhrIo.prototype.getLastError = function() { - return goog.isString(this.lastError_) ? this.lastError_ : - String(this.lastError_); -}; - - -/** - * Adds the last method, status and URI to the message. This is used to add - * this information to the logging calls. - * @param {string} msg The message text that we want to add the extra text to. - * @return {string} The message with the extra text appended. - * @private - */ -goog.net.XhrIo.prototype.formatMsg_ = function(msg) { - return msg + ' [' + this.lastMethod_ + ' ' + this.lastUri_ + ' ' + - this.getStatus() + ']'; -}; - - -// Register the xhr handler as an entry point, so that -// it can be monitored for exception handling, etc. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = - transformer(goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); - }); - -goog.provide('ol.format.FormatType'); - - -/** - * @enum {string} - */ -ol.format.FormatType = { - ARRAY_BUFFER: 'arraybuffer', - JSON: 'json', - TEXT: 'text', - XML: 'xml' }; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// Copyright 2015 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -71480,18272 +70655,17423 @@ ol.format.FormatType = { // limitations under the License. /** - * @fileoverview - * XML utilities. + * @fileoverview Simple freelist. * + * An anterative to goog.structs.SimplePool, it imposes the requirement that the + * objects in the list contain a "next" property that can be used to maintain + * the pool. */ -goog.provide('goog.dom.xml'); - -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); - - -/** - * Max XML size for MSXML2. Used to prevent potential DoS attacks. - * @type {number} - */ -goog.dom.xml.MAX_XML_SIZE_KB = 2 * 1024; // In kB +goog.provide('goog.async.FreeList'); /** - * Max XML size for MSXML2. Used to prevent potential DoS attacks. - * @type {number} + * @template ITEM */ -goog.dom.xml.MAX_ELEMENT_DEPTH = 256; // Same default as MSXML6. +goog.async.FreeList = goog.defineClass(null, { + /** + * @param {function():ITEM} create + * @param {function(ITEM):void} reset + * @param {number} limit + */ + constructor: function(create, reset, limit) { + /** @const {number} */ + this.limit_ = limit; + /** @const {function()} */ + this.create_ = create; + /** @const {function(ITEM):void} */ + this.reset_ = reset; + /** @type {number} */ + this.occupants_ = 0; + /** @type {ITEM} */ + this.head_ = null; + }, -/** - * Creates an XML document appropriate for the current JS runtime - * @param {string=} opt_rootTagName The root tag name. - * @param {string=} opt_namespaceUri Namespace URI of the document element. - * @return {Document} The new document. - */ -goog.dom.xml.createDocument = function(opt_rootTagName, opt_namespaceUri) { - if (opt_namespaceUri && !opt_rootTagName) { - throw Error("Can't create document with namespace and no root tag"); - } - if (document.implementation && document.implementation.createDocument) { - return document.implementation.createDocument(opt_namespaceUri || '', - opt_rootTagName || '', - null); - } else if (typeof ActiveXObject != 'undefined') { - var doc = goog.dom.xml.createMsXmlDocument_(); - if (doc) { - if (opt_rootTagName) { - doc.appendChild(doc.createNode(goog.dom.NodeType.ELEMENT, - opt_rootTagName, - opt_namespaceUri || '')); - } - return doc; + /** + * @return {ITEM} + */ + get: function() { + var item; + if (this.occupants_ > 0) { + this.occupants_--; + item = this.head_; + this.head_ = item.next; + item.next = null; + } else { + item = this.create_(); } - } - throw Error('Your browser does not support creating new documents'); -}; + return item; + }, + /** + * @param {ITEM} item An item available for possible future reuse. + */ + put: function(item) { + this.reset_(item); + if (this.occupants_ < this.limit_) { + this.occupants_++; + item.next = this.head_; + this.head_ = item; + } + }, -/** - * Creates an XML document from a string - * @param {string} xml The text. - * @return {Document} XML document from the text. - */ -goog.dom.xml.loadXml = function(xml) { - if (typeof DOMParser != 'undefined') { - return new DOMParser().parseFromString(xml, 'application/xml'); - } else if (typeof ActiveXObject != 'undefined') { - var doc = goog.dom.xml.createMsXmlDocument_(); - doc.loadXML(xml); - return doc; + /** + * Visible for testing. + * @package + * @return {number} + */ + occupants: function() { + return this.occupants_; } - throw Error('Your browser does not support loading xml documents'); -}; +}); + + + + +// Copyright 2015 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +goog.provide('goog.async.WorkItem'); +goog.provide('goog.async.WorkQueue'); + +goog.require('goog.asserts'); +goog.require('goog.async.FreeList'); + + +// TODO(johnlenz): generalize the WorkQueue if this is used by more +// than goog.async.run. + /** - * Serializes an XML document or subtree to string. - * @param {Document|Element} xml The document or the root node of the subtree. - * @return {string} The serialized XML. + * A low GC workqueue. The key elements of this design: + * - avoids the need for goog.bind or equivalent by carrying scope + * - avoids the need for array reallocation by using a linked list + * - minimizes work entry objects allocation by recycling objects + * @constructor + * @final + * @struct */ -goog.dom.xml.serialize = function(xml) { - // Compatible with Firefox, Opera and WebKit. - if (typeof XMLSerializer != 'undefined') { - return new XMLSerializer().serializeToString(xml); - } - // Compatible with Internet Explorer. - var text = xml.xml; - if (text) { - return text; - } - throw Error('Your browser does not support serializing XML documents'); +goog.async.WorkQueue = function() { + this.workHead_ = null; + this.workTail_ = null; }; +/** @define {number} The maximum number of entries to keep for recycling. */ +goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100); + + +/** @const @private {goog.async.FreeList<goog.async.WorkItem>} */ +goog.async.WorkQueue.freelist_ = new goog.async.FreeList( + function() {return new goog.async.WorkItem(); }, + function(item) {item.reset()}, + goog.async.WorkQueue.DEFAULT_MAX_UNUSED); + + /** - * Selects a single node using an Xpath expression and a root node - * @param {Node} node The root node. - * @param {string} path Xpath selector. - * @return {Node} The selected node, or null if no matching node. + * @param {function()} fn + * @param {Object|null|undefined} scope */ -goog.dom.xml.selectSingleNode = function(node, path) { - if (typeof node.selectSingleNode != 'undefined') { - var doc = goog.dom.getOwnerDocument(node); - if (typeof doc.setProperty != 'undefined') { - doc.setProperty('SelectionLanguage', 'XPath'); - } - return node.selectSingleNode(path); - } else if (document.implementation.hasFeature('XPath', '3.0')) { - var doc = goog.dom.getOwnerDocument(node); - var resolver = doc.createNSResolver(doc.documentElement); - var result = doc.evaluate(path, node, resolver, - XPathResult.FIRST_ORDERED_NODE_TYPE, null); - return result.singleNodeValue; +goog.async.WorkQueue.prototype.add = function(fn, scope) { + var item = this.getUnusedItem_(); + item.set(fn, scope); + + if (this.workTail_) { + this.workTail_.next = item; + this.workTail_ = item; + } else { + goog.asserts.assert(!this.workHead_); + this.workHead_ = item; + this.workTail_ = item; } - return null; }; /** - * Selects multiple nodes using an Xpath expression and a root node - * @param {Node} node The root node. - * @param {string} path Xpath selector. - * @return {(NodeList|Array<Node>)} The selected nodes, or empty array if no - * matching nodes. + * @return {goog.async.WorkItem} */ -goog.dom.xml.selectNodes = function(node, path) { - if (typeof node.selectNodes != 'undefined') { - var doc = goog.dom.getOwnerDocument(node); - if (typeof doc.setProperty != 'undefined') { - doc.setProperty('SelectionLanguage', 'XPath'); - } - return node.selectNodes(path); - } else if (document.implementation.hasFeature('XPath', '3.0')) { - var doc = goog.dom.getOwnerDocument(node); - var resolver = doc.createNSResolver(doc.documentElement); - var nodes = doc.evaluate(path, node, resolver, - XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - var results = []; - var count = nodes.snapshotLength; - for (var i = 0; i < count; i++) { - results.push(nodes.snapshotItem(i)); +goog.async.WorkQueue.prototype.remove = function() { + var item = null; + + if (this.workHead_) { + item = this.workHead_; + this.workHead_ = this.workHead_.next; + if (!this.workHead_) { + this.workTail_ = null; } - return results; - } else { - return []; + item.next = null; } + return item; }; /** - * Sets multiple attributes on an element. Differs from goog.dom.setProperties - * in that it exclusively uses the element's setAttributes method. Use this - * when you need to ensure that the exact property is available as an attribute - * and can be read later by the native getAttribute method. - * @param {!Element} element XML or DOM element to set attributes on. - * @param {!Object<string, string>} attributes Map of property:value pairs. + * @param {goog.async.WorkItem} item */ -goog.dom.xml.setAttributes = function(element, attributes) { - for (var key in attributes) { - if (attributes.hasOwnProperty(key)) { - element.setAttribute(key, attributes[key]); - } - } +goog.async.WorkQueue.prototype.returnUnused = function(item) { + goog.async.WorkQueue.freelist_.put(item); }; /** - * Creates an instance of the MSXML2.DOMDocument. - * @return {Document} The new document. + * @return {goog.async.WorkItem} * @private */ -goog.dom.xml.createMsXmlDocument_ = function() { - var doc = new ActiveXObject('MSXML2.DOMDocument'); - if (doc) { - // Prevent potential vulnerabilities exposed by MSXML2, see - // http://b/1707300 and http://wiki/Main/ISETeamXMLAttacks for details. - doc.resolveExternals = false; - doc.validateOnParse = false; - // Add a try catch block because accessing these properties will throw an - // error on unsupported MSXML versions. This affects Windows machines - // running IE6 or IE7 that are on XP SP2 or earlier without MSXML updates. - // See http://msdn.microsoft.com/en-us/library/ms766391(VS.85).aspx for - // specific details on which MSXML versions support these properties. - try { - doc.setProperty('ProhibitDTD', true); - doc.setProperty('MaxXMLSize', goog.dom.xml.MAX_XML_SIZE_KB); - doc.setProperty('MaxElementDepth', goog.dom.xml.MAX_ELEMENT_DEPTH); - } catch (e) { - // No-op. - } - } - return doc; +goog.async.WorkQueue.prototype.getUnusedItem_ = function() { + return goog.async.WorkQueue.freelist_.get(); }; -goog.provide('ol.xml'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.xml'); -goog.require('goog.object'); -goog.require('goog.userAgent'); /** - * When using {@link ol.xml.makeChildAppender} or - * {@link ol.xml.makeSimpleNodeFactory}, the top `objectStack` item needs to - * have this structure. - * @typedef {{node:Node}} + * @constructor + * @final + * @struct */ -ol.xml.NodeStackItem; +goog.async.WorkItem = function() { + /** @type {?function()} */ + this.fn = null; + /** @type {Object|null|undefined} */ + this.scope = null; + /** @type {?goog.async.WorkItem} */ + this.next = null; +}; /** - * @typedef {function(Node, Array.<*>)} + * @param {function()} fn + * @param {Object|null|undefined} scope */ -ol.xml.Parser; +goog.async.WorkItem.prototype.set = function(fn, scope) { + this.fn = fn; + this.scope = scope; + this.next = null; +}; -/** - * @typedef {function(Node, *, Array.<*>)} - */ -ol.xml.Serializer; +/** Reset the work item so they don't prevent GC before reuse */ +goog.async.WorkItem.prototype.reset = function() { + this.fn = null; + this.scope = null; + this.next = null; +}; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * This document should be used when creating nodes for XML serializations. This - * document is also used by {@link ol.xml.createElementNS} and - * {@link ol.xml.setAttributeNS} - * @const - * @type {Document} + * @fileoverview Simple notifiers for the Closure testing framework. + * + * @author johnlenz@google.com (John Lenz) */ -ol.xml.DOCUMENT = goog.dom.xml.createDocument(); +goog.provide('goog.testing.watchers'); -/** - * @param {string} namespaceURI Namespace URI. - * @param {string} qualifiedName Qualified name. - * @return {Node} Node. - * @private - */ -ol.xml.createElementNS_ = function(namespaceURI, qualifiedName) { - return ol.xml.DOCUMENT.createElementNS(namespaceURI, qualifiedName); -}; + +/** @private {!Array<function()>} */ +goog.testing.watchers.resetWatchers_ = []; /** - * @param {string} namespaceURI Namespace URI. - * @param {string} qualifiedName Qualified name. - * @return {Node} Node. - * @private + * Fires clock reset watching functions. */ -ol.xml.createElementNSActiveX_ = function(namespaceURI, qualifiedName) { - if (!namespaceURI) { - namespaceURI = ''; +goog.testing.watchers.signalClockReset = function() { + var watchers = goog.testing.watchers.resetWatchers_; + for (var i = 0; i < watchers.length; i++) { + goog.testing.watchers.resetWatchers_[i](); } - return ol.xml.DOCUMENT.createNode(1, qualifiedName, namespaceURI); }; /** - * @param {string} namespaceURI Namespace URI. - * @param {string} qualifiedName Qualified name. - * @return {Node} Node. - */ -ol.xml.createElementNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.createElementNS_ : ol.xml.createElementNSActiveX_; - - -/** - * Recursively grab all text content of child nodes into a single string. - * @param {Node} node Node. - * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line - * breaks. - * @return {string} All text content. - * @api + * Enqueues a function to be called when the clock used for setTimeout is reset. + * @param {function()} fn */ -ol.xml.getAllTextContent = function(node, normalizeWhitespace) { - return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join(''); +goog.testing.watchers.watchClockReset = function(fn) { + goog.testing.watchers.resetWatchers_.push(fn); }; -/** - * Recursively grab all text content of child nodes into a single string. - * @param {Node} node Node. - * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line - * breaks. - * @param {Array.<String|string>} accumulator Accumulator. - * @private - * @return {Array.<String|string>} Accumulator. - */ -ol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) { - if (node.nodeType == goog.dom.NodeType.CDATA_SECTION || - node.nodeType == goog.dom.NodeType.TEXT) { - if (normalizeWhitespace) { - // FIXME understand why goog.dom.getTextContent_ uses String here - accumulator.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, '')); - } else { - accumulator.push(node.nodeValue); - } - } else { - var n; - for (n = node.firstChild; n; n = n.nextSibling) { - ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator); - } - } - return accumulator; -}; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +goog.provide('goog.async.run'); -/** - * @param {Node} node Node. - * @private - * @return {string} Local name. - */ -ol.xml.getLocalName_ = function(node) { - return node.localName; -}; +goog.require('goog.async.WorkQueue'); +goog.require('goog.async.nextTick'); +goog.require('goog.async.throwException'); +goog.require('goog.testing.watchers'); /** - * @param {Node} node Node. - * @private - * @return {string} Local name. + * Fires the provided callback just before the current callstack unwinds, or as + * soon as possible after the current JS execution context. + * @param {function(this:THIS)} callback + * @param {THIS=} opt_context Object to use as the "this value" when calling + * the provided function. + * @template THIS */ -ol.xml.getLocalNameIE_ = function(node) { - var localName = node.localName; - if (localName !== undefined) { - return localName; +goog.async.run = function(callback, opt_context) { + if (!goog.async.run.schedule_) { + goog.async.run.initializeRunner_(); + } + if (!goog.async.run.workQueueScheduled_) { + // Nothing is currently scheduled, schedule it now. + goog.async.run.schedule_(); + goog.async.run.workQueueScheduled_ = true; } - var baseName = node.baseName; - goog.asserts.assert(baseName, - 'Failed to get localName/baseName of node %s', node); - return baseName; -}; - -/** - * @param {Node} node Node. - * @return {string} Local name. - */ -ol.xml.getLocalName = goog.userAgent.IE ? - ol.xml.getLocalNameIE_ : ol.xml.getLocalName_; + goog.async.run.workQueue_.add(callback, opt_context); +}; /** - * @param {?} value Value. + * Initializes the function to use to process the work queue. * @private - * @return {boolean} Is document. */ -ol.xml.isDocument_ = function(value) { - return value instanceof Document; +goog.async.run.initializeRunner_ = function() { + // If native Promises are available in the browser, just schedule the callback + // on a fulfilled promise, which is specified to be async, but as fast as + // possible. + if (goog.global.Promise && goog.global.Promise.resolve) { + var promise = goog.global.Promise.resolve(undefined); + goog.async.run.schedule_ = function() { + promise.then(goog.async.run.processWorkQueue); + }; + } else { + goog.async.run.schedule_ = function() { + goog.async.nextTick(goog.async.run.processWorkQueue); + }; + } }; /** - * @param {?} value Value. - * @private - * @return {boolean} Is document. + * Forces goog.async.run to use nextTick instead of Promise. + * + * This should only be done in unit tests. It's useful because MockClock + * replaces nextTick, but not the browser Promise implementation, so it allows + * Promise-based code to be tested with MockClock. + * + * However, we also want to run promises if the MockClock is no longer in + * control so we schedule a backup "setTimeout" to the unmocked timeout if + * provided. + * + * @param {function(function())=} opt_realSetTimeout */ -ol.xml.isDocumentIE_ = function(value) { - return goog.isObject(value) && value.nodeType == goog.dom.NodeType.DOCUMENT; +goog.async.run.forceNextTick = function(opt_realSetTimeout) { + goog.async.run.schedule_ = function() { + goog.async.nextTick(goog.async.run.processWorkQueue); + if (opt_realSetTimeout) { + opt_realSetTimeout(goog.async.run.processWorkQueue); + } + }; }; /** - * @param {?} value Value. - * @return {boolean} Is document. + * The function used to schedule work asynchronousely. + * @private {function()} */ -ol.xml.isDocument = goog.userAgent.IE ? - ol.xml.isDocumentIE_ : ol.xml.isDocument_; +goog.async.run.schedule_; -/** - * @param {?} value Value. - * @private - * @return {boolean} Is node. - */ -ol.xml.isNode_ = function(value) { - return value instanceof Node; -}; +/** @private {boolean} */ +goog.async.run.workQueueScheduled_ = false; -/** - * @param {?} value Value. - * @private - * @return {boolean} Is node. - */ -ol.xml.isNodeIE_ = function(value) { - return goog.isObject(value) && value.nodeType !== undefined; -}; +/** @private {!goog.async.WorkQueue} */ +goog.async.run.workQueue_ = new goog.async.WorkQueue(); -/** - * @param {?} value Value. - * @return {boolean} Is node. - */ -ol.xml.isNode = goog.userAgent.IE ? ol.xml.isNodeIE_ : ol.xml.isNode_; +if (goog.DEBUG) { + /** + * Reset the work queue. + * @private + */ + goog.async.run.resetQueue_ = function() { + goog.async.run.workQueueScheduled_ = false; + goog.async.run.workQueue_ = new goog.async.WorkQueue(); + }; + + // If there is a clock implemenation in use for testing + // and it is reset, reset the queue. + goog.testing.watchers.watchClockReset(goog.async.run.resetQueue_); +} /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {string} Value - * @private + * Run any pending goog.async.run work items. This function is not intended + * for general use, but for use by entry point handlers to run items ahead of + * goog.async.nextTick. */ -ol.xml.getAttributeNS_ = function(node, namespaceURI, name) { - return node.getAttributeNS(namespaceURI, name) || ''; +goog.async.run.processWorkQueue = function() { + // NOTE: additional work queue items may be added while processing. + var item = null; + while (item = goog.async.run.workQueue_.remove()) { + try { + item.fn.call(item.scope); + } catch (e) { + goog.async.throwException(e); + } + goog.async.run.workQueue_.returnUnused(item); + } + + // There are no more work items, allow processing to be scheduled again. + goog.async.run.workQueueScheduled_ = false; }; +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +goog.provide('goog.promise.Resolver'); + + /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {string} Value - * @private + * Resolver interface for promises. The resolver is a convenience interface that + * bundles the promise and its associated resolve and reject functions together, + * for cases where the resolver needs to be persisted internally. + * + * @interface + * @template TYPE */ -ol.xml.getAttributeNSActiveX_ = function(node, namespaceURI, name) { - var attributeValue = ''; - var attributeNode = ol.xml.getAttributeNodeNS(node, namespaceURI, name); - if (attributeNode !== undefined) { - attributeValue = attributeNode.nodeValue; - } - return attributeValue; -}; +goog.promise.Resolver = function() {}; /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {string} Value + * The promise that created this resolver. + * @type {!goog.Promise<TYPE>} */ -ol.xml.getAttributeNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.getAttributeNS_ : ol.xml.getAttributeNSActiveX_; +goog.promise.Resolver.prototype.promise; /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {?Node} Attribute node or null if none found. - * @private + * Resolves this resolver with the specified value. + * @type {function((TYPE|goog.Promise<TYPE>|Thenable)=)} */ -ol.xml.getAttributeNodeNS_ = function(node, namespaceURI, name) { - return node.getAttributeNodeNS(namespaceURI, name); -}; +goog.promise.Resolver.prototype.resolve; /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {?Node} Attribute node or null if none found. - * @private + * Rejects this resolver with the specified reason. + * @type {function(*=): void} */ -ol.xml.getAttributeNodeNSActiveX_ = function(node, namespaceURI, name) { - var attributeNode = null; - var attributes = node.attributes; - var potentialNode, fullName; - for (var i = 0, len = attributes.length; i < len; ++i) { - potentialNode = attributes[i]; - if (potentialNode.namespaceURI == namespaceURI) { - fullName = (potentialNode.prefix) ? - (potentialNode.prefix + ':' + name) : name; - if (fullName == potentialNode.nodeName) { - attributeNode = potentialNode; - break; - } +goog.promise.Resolver.prototype.reject; + +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +goog.provide('goog.Promise'); + +goog.require('goog.Thenable'); +goog.require('goog.asserts'); +goog.require('goog.async.FreeList'); +goog.require('goog.async.run'); +goog.require('goog.async.throwException'); +goog.require('goog.debug.Error'); +goog.require('goog.promise.Resolver'); + + + +/** + * Promises provide a result that may be resolved asynchronously. A Promise may + * be resolved by being fulfilled with a fulfillment value, rejected with a + * rejection reason, or blocked by another Promise. A Promise is said to be + * settled if it is either fulfilled or rejected. Once settled, the Promise + * result is immutable. + * + * Promises may represent results of any type, including undefined. Rejection + * reasons are typically Errors, but may also be of any type. Closure Promises + * allow for optional type annotations that enforce that fulfillment values are + * of the appropriate types at compile time. + * + * The result of a Promise is accessible by calling {@code then} and registering + * {@code onFulfilled} and {@code onRejected} callbacks. Once the Promise + * is settled, the relevant callbacks are invoked with the fulfillment value or + * rejection reason as argument. Callbacks are always invoked in the order they + * were registered, even when additional {@code then} calls are made from inside + * another callback. A callback is always run asynchronously sometime after the + * scope containing the registering {@code then} invocation has returned. + * + * If a Promise is resolved with another Promise, the first Promise will block + * until the second is settled, and then assumes the same result as the second + * Promise. This allows Promises to depend on the results of other Promises, + * linking together multiple asynchronous operations. + * + * This implementation is compatible with the Promises/A+ specification and + * passes that specification's conformance test suite. A Closure Promise may be + * resolved with a Promise instance (or sufficiently compatible Promise-like + * object) created by other Promise implementations. From the specification, + * Promise-like objects are known as "Thenables". + * + * @see http://promisesaplus.com/ + * + * @param {function( + * this:RESOLVER_CONTEXT, + * function((TYPE|IThenable<TYPE>|Thenable)=), + * function(*=)): void} resolver + * Initialization function that is invoked immediately with {@code resolve} + * and {@code reject} functions as arguments. The Promise is resolved or + * rejected with the first argument passed to either function. + * @param {RESOLVER_CONTEXT=} opt_context An optional context for executing the + * resolver function. If unspecified, the resolver function will be executed + * in the default scope. + * @constructor + * @struct + * @final + * @implements {goog.Thenable<TYPE>} + * @template TYPE,RESOLVER_CONTEXT + */ +goog.Promise = function(resolver, opt_context) { + /** + * The internal state of this Promise. Either PENDING, FULFILLED, REJECTED, or + * BLOCKED. + * @private {goog.Promise.State_} + */ + this.state_ = goog.Promise.State_.PENDING; + + /** + * The settled result of the Promise. Immutable once set with either a + * fulfillment value or rejection reason. + * @private {*} + */ + this.result_ = undefined; + + /** + * For Promises created by calling {@code then()}, the originating parent. + * @private {goog.Promise} + */ + this.parent_ = null; + + /** + * The linked list of {@code onFulfilled} and {@code onRejected} callbacks + * added to this Promise by calls to {@code then()}. + * @private {?goog.Promise.CallbackEntry_} + */ + this.callbackEntries_ = null; + + /** + * The tail of the linked list of {@code onFulfilled} and {@code onRejected} + * callbacks added to this Promise by calls to {@code then()}. + * @private {?goog.Promise.CallbackEntry_} + */ + this.callbackEntriesTail_ = null; + + /** + * Whether the Promise is in the queue of Promises to execute. + * @private {boolean} + */ + this.executing_ = false; + + if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { + /** + * A timeout ID used when the {@code UNHANDLED_REJECTION_DELAY} is greater + * than 0 milliseconds. The ID is set when the Promise is rejected, and + * cleared only if an {@code onRejected} callback is invoked for the + * Promise (or one of its descendants) before the delay is exceeded. + * + * If the rejection is not handled before the timeout completes, the + * rejection reason is passed to the unhandled rejection handler. + * @private {number} + */ + this.unhandledRejectionId_ = 0; + } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { + /** + * When the {@code UNHANDLED_REJECTION_DELAY} is set to 0 milliseconds, a + * boolean that is set if the Promise is rejected, and reset to false if an + * {@code onRejected} callback is invoked for the Promise (or one of its + * descendants). If the rejection is not handled before the next timestep, + * the rejection reason is passed to the unhandled rejection handler. + * @private {boolean} + */ + this.hadUnhandledRejection_ = false; + } + + if (goog.Promise.LONG_STACK_TRACES) { + /** + * A list of stack trace frames pointing to the locations where this Promise + * was created or had callbacks added to it. Saved to add additional context + * to stack traces when an exception is thrown. + * @private {!Array<string>} + */ + this.stack_ = []; + this.addStackTrace_(new Error('created')); + + /** + * Index of the most recently executed stack frame entry. + * @private {number} + */ + this.currentStep_ = 0; + } + + // As an optimization, we can skip this if resolver is goog.nullFunction. + // This value is passed internally when creating a promise which will be + // resolved through a more optimized path. + if (resolver != goog.nullFunction) { + try { + var self = this; + resolver.call( + opt_context, + function(value) { + self.resolve_(goog.Promise.State_.FULFILLED, value); + }, + function(reason) { + if (goog.DEBUG && + !(reason instanceof goog.Promise.CancellationError)) { + try { + // Promise was rejected. Step up one call frame to see why. + if (reason instanceof Error) { + throw reason; + } else { + throw new Error('Promise rejected.'); + } + } catch (e) { + // Only thrown so browser dev tools can catch rejections of + // promises when the option to break on caught exceptions is + // activated. + } + } + self.resolve_(goog.Promise.State_.REJECTED, reason); + }); + } catch (e) { + this.resolve_(goog.Promise.State_.REJECTED, e); } } - return attributeNode; }; /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @return {?Node} Attribute node or null if none found. + * @define {boolean} Whether traces of {@code then} calls should be included in + * exceptions thrown */ -ol.xml.getAttributeNodeNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.getAttributeNodeNS_ : ol.xml.getAttributeNodeNSActiveX_; +goog.define('goog.Promise.LONG_STACK_TRACES', false); /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @param {string|number} value Value. - * @private + * @define {number} The delay in milliseconds before a rejected Promise's reason + * is passed to the rejection handler. By default, the rejection handler + * rethrows the rejection reason so that it appears in the developer console or + * {@code window.onerror} handler. + * + * Rejections are rethrown as quickly as possible by default. A negative value + * disables rejection handling entirely. */ -ol.xml.setAttributeNS_ = function(node, namespaceURI, name, value) { - node.setAttributeNS(namespaceURI, name, value); -}; +goog.define('goog.Promise.UNHANDLED_REJECTION_DELAY', 0); /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @param {string|number} value Value. + * The possible internal states for a Promise. These states are not directly + * observable to external callers. + * @enum {number} * @private */ -ol.xml.setAttributeNSActiveX_ = function(node, namespaceURI, name, value) { - if (namespaceURI) { - var attribute = node.ownerDocument.createNode(2, name, namespaceURI); - attribute.nodeValue = value; - node.setAttributeNode(attribute); - } else { - node.setAttribute(name, value); - } +goog.Promise.State_ = { + /** The Promise is waiting for resolution. */ + PENDING: 0, + + /** The Promise is blocked waiting for the result of another Thenable. */ + BLOCKED: 1, + + /** The Promise has been resolved with a fulfillment value. */ + FULFILLED: 2, + + /** The Promise has been resolved with a rejection reason. */ + REJECTED: 3 }; + /** - * @param {Node} node Node. - * @param {?string} namespaceURI Namespace URI. - * @param {string} name Attribute name. - * @param {string|number} value Value. + * Entries in the callback chain. Each call to {@code then}, + * {@code thenCatch}, or {@code thenAlways} creates an entry containing the + * functions that may be invoked once the Promise is settled. + * + * @private @final @struct @constructor */ -ol.xml.setAttributeNS = - (document.implementation && document.implementation.createDocument) ? - ol.xml.setAttributeNS_ : ol.xml.setAttributeNSActiveX_; +goog.Promise.CallbackEntry_ = function() { + /** @type {?goog.Promise} */ + this.child = null; + /** @type {Function} */ + this.onFulfilled = null; + /** @type {Function} */ + this.onRejected = null; + /** @type {?} */ + this.context = null; + /** @type {?goog.Promise.CallbackEntry_} */ + this.next = null; + /** + * A boolean value to indicate this is a "thenAlways" callback entry. + * Unlike a normal "then/thenVoid" a "thenAlways doesn't participate + * in "cancel" considerations but is simply an observer and requires + * special handling. + * @type {boolean} + */ + this.always = false; +}; -/** - * Parse an XML string to an XML Document. - * @param {string} xml XML. - * @return {Document} Document. - * @api - */ -ol.xml.parse = function(xml) { - return new DOMParser().parseFromString(xml, 'application/xml'); + +/** clear the object prior to reuse */ +goog.Promise.CallbackEntry_.prototype.reset = function() { + this.child = null; + this.onFulfilled = null; + this.onRejected = null; + this.context = null; + this.always = false; }; /** - * Make an array extender function for extending the array at the top of the - * object stack. - * @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)} - * valueReader Value reader. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T + * @define {number} The number of currently unused objects to keep around for + * reuse. */ -ol.xml.makeArrayExtender = function(valueReader, opt_this) { - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this, node, objectStack); - if (value !== undefined) { - goog.asserts.assert(goog.isArray(value), - 'valueReader function is expected to return an array of values'); - var array = /** @type {Array.<*>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(array), - 'objectStack is supposed to be an array of arrays'); - goog.array.extend(array, value); - } - }); -}; +goog.define('goog.Promise.DEFAULT_MAX_UNUSED', 100); + + +/** @const @private {goog.async.FreeList<!goog.Promise.CallbackEntry_>} */ +goog.Promise.freelist_ = new goog.async.FreeList( + function() { + return new goog.Promise.CallbackEntry_(); + }, + function(item) { + item.reset(); + }, + goog.Promise.DEFAULT_MAX_UNUSED); /** - * Make an array pusher function for pushing to the array at the top of the - * object stack. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T + * @param {Function} onFulfilled + * @param {Function} onRejected + * @param {?} context + * @return {!goog.Promise.CallbackEntry_} + * @private */ -ol.xml.makeArrayPusher = function(valueReader, opt_this) { - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - var array = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isArray(array), - 'objectStack is supposed to be an array of arrays'); - array.push(value); - } - }); +goog.Promise.getCallbackEntry_ = function(onFulfilled, onRejected, context) { + var entry = goog.Promise.freelist_.get(); + entry.onFulfilled = onFulfilled; + entry.onRejected = onRejected; + entry.context = context; + return entry; }; /** - * Make an object stack replacer function for replacing the object at the - * top of the stack. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T + * @param {!goog.Promise.CallbackEntry_} entry + * @private */ -ol.xml.makeReplacer = function(valueReader, opt_this) { - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - objectStack[objectStack.length - 1] = value; - } - }); +goog.Promise.returnEntry_ = function(entry) { + goog.Promise.freelist_.put(entry); }; +// NOTE: this is the same template expression as is used for +// goog.IThenable.prototype.then + + /** - * Make an object property pusher function for adding a property to the - * object at the top of the stack. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {string=} opt_property Property. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T - */ -ol.xml.makeObjectPropertyPusher = - function(valueReader, opt_property, opt_this) { - goog.asserts.assert(valueReader !== undefined, - 'undefined valueReader, expected function(this: T, Node, Array.<*>)'); - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - var object = /** @type {Object} */ - (objectStack[objectStack.length - 1]); - var property = opt_property !== undefined ? - opt_property : node.localName; - goog.asserts.assert(goog.isObject(object), - 'entity from stack was not an object'); - var array = goog.object.setIfUndefined(object, property, []); - array.push(value); - } - }); + * @param {VALUE=} opt_value + * @return {RESULT} A new Promise that is immediately resolved + * with the given value. If the input value is already a goog.Promise, it + * will be returned immediately without creating a new instance. + * @template VALUE + * @template RESULT := type('goog.Promise', + * cond(isUnknown(VALUE), unknown(), + * mapunion(VALUE, (V) => + * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), + * templateTypeOf(V, 0), + * cond(sub(V, 'Thenable'), + * unknown(), + * V))))) + * =: + */ +goog.Promise.resolve = function(opt_value) { + if (opt_value instanceof goog.Promise) { + // Avoid creating a new object if we already have a promise object + // of the correct type. + return opt_value; + } + + // Passing goog.nullFunction will cause the constructor to take an optimized + // path that skips calling the resolver function. + var promise = new goog.Promise(goog.nullFunction); + promise.resolve_(goog.Promise.State_.FULFILLED, opt_value); + return promise; }; /** - * Make an object property setter function. - * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. - * @param {string=} opt_property Property. - * @param {T=} opt_this The object to use as `this` in `valueReader`. - * @return {ol.xml.Parser} Parser. - * @template T + * @param {*=} opt_reason + * @return {!goog.Promise} A new Promise that is immediately rejected with the + * given reason. */ -ol.xml.makeObjectPropertySetter = - function(valueReader, opt_property, opt_this) { - goog.asserts.assert(valueReader !== undefined, - 'undefined valueReader, expected function(this: T, Node, Array.<*>)'); - return ( - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - */ - function(node, objectStack) { - var value = valueReader.call(opt_this !== undefined ? opt_this : this, - node, objectStack); - if (value !== undefined) { - var object = /** @type {Object} */ - (objectStack[objectStack.length - 1]); - var property = opt_property !== undefined ? - opt_property : node.localName; - goog.asserts.assert(goog.isObject(object), - 'entity from stack was not an object'); - object[property] = value; - } - }); +goog.Promise.reject = function(opt_reason) { + return new goog.Promise(function(resolve, reject) { + reject(opt_reason); + }); }; /** - * Create a serializer that appends nodes written by its `nodeWriter` to its - * designated parent. The parent is the `node` of the - * {@link ol.xml.NodeStackItem} at the top of the `objectStack`. - * @param {function(this: T, Node, V, Array.<*>)} - * nodeWriter Node writer. - * @param {T=} opt_this The object to use as `this` in `nodeWriter`. - * @return {ol.xml.Serializer} Serializer. - * @template T, V + * This is identical to + * {@code goog.Promise.resolve(value).then(onFulfilled, onRejected)}, but it + * avoids creating an unnecessary wrapper Promise when {@code value} is already + * thenable. + * + * @param {?(goog.Thenable<TYPE>|Thenable|TYPE)} value + * @param {function(TYPE): ?} onFulfilled + * @param {function(*): *} onRejected + * @template TYPE + * @private */ -ol.xml.makeChildAppender = function(nodeWriter, opt_this) { - return function(node, value, objectStack) { - nodeWriter.call(opt_this !== undefined ? opt_this : this, - node, value, objectStack); - var parent = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(parent), - 'entity from stack was not an object'); - var parentNode = parent.node; - goog.asserts.assert(ol.xml.isNode(parentNode) || - ol.xml.isDocument(parentNode), - 'expected parentNode %s to be a Node or a Document', parentNode); - parentNode.appendChild(node); - }; +goog.Promise.resolveThen_ = function(value, onFulfilled, onRejected) { + var isThenable = goog.Promise.maybeThen_( + value, onFulfilled, onRejected, null); + if (!isThenable) { + goog.async.run(goog.partial(onFulfilled, value)); + } }; /** - * Create a serializer that calls the provided `nodeWriter` from - * {@link ol.xml.serialize}. This can be used by the parent writer to have the - * 'nodeWriter' called with an array of values when the `nodeWriter` was - * designed to serialize a single item. An example would be a LineString - * geometry writer, which could be reused for writing MultiLineString - * geometries. - * @param {function(this: T, Node, V, Array.<*>)} - * nodeWriter Node writer. - * @param {T=} opt_this The object to use as `this` in `nodeWriter`. - * @return {ol.xml.Serializer} Serializer. - * @template T, V + * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} + * promises + * @return {!goog.Promise<TYPE>} A Promise that receives the result of the + * first Promise (or Promise-like) input to settle immediately after it + * settles. + * @template TYPE */ -ol.xml.makeArraySerializer = function(nodeWriter, opt_this) { - var serializersNS, nodeFactory; - return function(node, value, objectStack) { - if (serializersNS === undefined) { - serializersNS = {}; - var serializers = {}; - serializers[node.localName] = nodeWriter; - serializersNS[node.namespaceURI] = serializers; - nodeFactory = ol.xml.makeSimpleNodeFactory(node.localName); +goog.Promise.race = function(promises) { + return new goog.Promise(function(resolve, reject) { + if (!promises.length) { + resolve(undefined); } - ol.xml.serialize(serializersNS, nodeFactory, value, objectStack); - }; + for (var i = 0, promise; i < promises.length; i++) { + promise = promises[i]; + goog.Promise.resolveThen_(promise, resolve, reject); + } + }); }; /** - * Create a node factory which can use the `opt_keys` passed to - * {@link ol.xml.serialize} or {@link ol.xml.pushSerializeAndPop} as node names, - * or a fixed node name. The namespace of the created nodes can either be fixed, - * or the parent namespace will be used. - * @param {string=} opt_nodeName Fixed node name which will be used for all - * created nodes. If not provided, the 3rd argument to the resulting node - * factory needs to be provided and will be the nodeName. - * @param {string=} opt_namespaceURI Fixed namespace URI which will be used for - * all created nodes. If not provided, the namespace of the parent node will - * be used. - * @return {function(*, Array.<*>, string=): (Node|undefined)} Node factory. + * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} + * promises + * @return {!goog.Promise<!Array<TYPE>>} A Promise that receives a list of + * every fulfilled value once every input Promise (or Promise-like) is + * successfully fulfilled, or is rejected with the first rejection reason + * immediately after it is rejected. + * @template TYPE */ -ol.xml.makeSimpleNodeFactory = function(opt_nodeName, opt_namespaceURI) { - var fixedNodeName = opt_nodeName; - return ( - /** - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node} Node. - */ - function(value, objectStack, opt_nodeName) { - var context = objectStack[objectStack.length - 1]; - var node = context.node; - goog.asserts.assert(ol.xml.isNode(node) || ol.xml.isDocument(node), - 'expected node %s to be a Node or a Document', node); - var nodeName = fixedNodeName; - if (nodeName === undefined) { - nodeName = opt_nodeName; - } - var namespaceURI = opt_namespaceURI; - if (opt_namespaceURI === undefined) { - namespaceURI = node.namespaceURI; - } - goog.asserts.assert(nodeName !== undefined, 'nodeName was undefined'); - return ol.xml.createElementNS(namespaceURI, nodeName); - } - ); -}; +goog.Promise.all = function(promises) { + return new goog.Promise(function(resolve, reject) { + var toFulfill = promises.length; + var values = []; + if (!toFulfill) { + resolve(values); + return; + } -/** - * A node factory that creates a node using the parent's `namespaceURI` and the - * `nodeName` passed by {@link ol.xml.serialize} or - * {@link ol.xml.pushSerializeAndPop} to the node factory. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - */ -ol.xml.OBJECT_PROPERTY_NODE_FACTORY = ol.xml.makeSimpleNodeFactory(); + var onFulfill = function(index, value) { + toFulfill--; + values[index] = value; + if (toFulfill == 0) { + resolve(values); + } + }; + var onReject = function(reason) { + reject(reason); + }; -/** - * Create an array of `values` to be used with {@link ol.xml.serialize} or - * {@link ol.xml.pushSerializeAndPop}, where `orderedKeys` has to be provided as - * `opt_key` argument. - * @param {Object.<string, V>} object Key-value pairs for the sequence. Keys can - * be a subset of the `orderedKeys`. - * @param {Array.<string>} orderedKeys Keys in the order of the sequence. - * @return {Array.<V>} Values in the order of the sequence. The resulting array - * has the same length as the `orderedKeys` array. Values that are not - * present in `object` will be `undefined` in the resulting array. - * @template V - */ -ol.xml.makeSequence = function(object, orderedKeys) { - var length = orderedKeys.length; - var sequence = new Array(length); - for (var i = 0; i < length; ++i) { - sequence[i] = object[orderedKeys[i]]; - } - return sequence; + for (var i = 0, promise; i < promises.length; i++) { + promise = promises[i]; + goog.Promise.resolveThen_( + promise, goog.partial(onFulfill, i), onReject); + } + }); }; /** - * Create a namespaced structure, using the same values for each namespace. - * This can be used as a starting point for versioned parsers, when only a few - * values are version specific. - * @param {Array.<string>} namespaceURIs Namespace URIs. - * @param {T} structure Structure. - * @param {Object.<string, T>=} opt_structureNS Namespaced structure to add to. - * @return {Object.<string, T>} Namespaced structure. - * @template T + * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} + * promises + * @return {!goog.Promise<!Array<{ + * fulfilled: boolean, + * value: (TYPE|undefined), + * reason: (*|undefined)}>>} A Promise that resolves with a list of + * result objects once all input Promises (or Promise-like) have + * settled. Each result object contains a 'fulfilled' boolean indicating + * whether an input Promise was fulfilled or rejected. For fulfilled + * Promises, the resulting value is stored in the 'value' field. For + * rejected Promises, the rejection reason is stored in the 'reason' + * field. + * @template TYPE */ -ol.xml.makeStructureNS = function(namespaceURIs, structure, opt_structureNS) { - /** - * @type {Object.<string, *>} - */ - var structureNS = opt_structureNS !== undefined ? opt_structureNS : {}; - var i, ii; - for (i = 0, ii = namespaceURIs.length; i < ii; ++i) { - structureNS[namespaceURIs[i]] = structure; - } - return structureNS; -}; +goog.Promise.allSettled = function(promises) { + return new goog.Promise(function(resolve, reject) { + var toSettle = promises.length; + var results = []; + if (!toSettle) { + resolve(results); + return; + } -/** - * Parse a node using the parsers and object stack. - * @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS - * Parsers by namespace. - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @param {*=} opt_this The object to use as `this`. - */ -ol.xml.parseNode = function(parsersNS, node, objectStack, opt_this) { - var n; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var parsers = parsersNS[n.namespaceURI]; - if (parsers !== undefined) { - var parser = parsers[n.localName]; - if (parser !== undefined) { - parser.call(opt_this, n, objectStack); + var onSettled = function(index, fulfilled, result) { + toSettle--; + results[index] = fulfilled ? + {fulfilled: true, value: result} : + {fulfilled: false, reason: result}; + if (toSettle == 0) { + resolve(results); } + }; + + for (var i = 0, promise; i < promises.length; i++) { + promise = promises[i]; + goog.Promise.resolveThen_(promise, + goog.partial(onSettled, i, true /* fulfilled */), + goog.partial(onSettled, i, false /* fulfilled */)); } - } + }); }; /** - * Push an object on top of the stack, parse and return the popped object. - * @param {T} object Object. - * @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS - * Parsers by namespace. - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @param {*=} opt_this The object to use as `this`. - * @return {T} Object. - * @template T + * @param {!Array<?(goog.Promise<TYPE>|goog.Thenable<TYPE>|Thenable|*)>} + * promises + * @return {!goog.Promise<TYPE>} A Promise that receives the value of the first + * input to be fulfilled, or is rejected with a list of every rejection + * reason if all inputs are rejected. + * @template TYPE */ -ol.xml.pushParseAndPop = function( - object, parsersNS, node, objectStack, opt_this) { - objectStack.push(object); - ol.xml.parseNode(parsersNS, node, objectStack, opt_this); - return objectStack.pop(); -}; +goog.Promise.firstFulfilled = function(promises) { + return new goog.Promise(function(resolve, reject) { + var toReject = promises.length; + var reasons = []; + if (!toReject) { + resolve(undefined); + return; + } -/** - * Walk through an array of `values` and call a serializer for each value. - * @param {Object.<string, Object.<string, ol.xml.Serializer>>} serializersNS - * Namespaced serializers. - * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory - * Node factory. The `nodeFactory` creates the node whose namespace and name - * will be used to choose a node writer from `serializersNS`. This - * separation allows us to decide what kind of node to create, depending on - * the value we want to serialize. An example for this would be different - * geometry writers based on the geometry type. - * @param {Array.<*>} values Values to serialize. An example would be an array - * of {@link ol.Feature} instances. - * @param {Array.<*>} objectStack Node stack. - * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the - * `nodeFactory`. This is used for serializing object literals where the - * node name relates to the property key. The array length of `opt_keys` has - * to match the length of `values`. For serializing a sequence, `opt_keys` - * determines the order of the sequence. - * @param {T=} opt_this The object to use as `this` for the node factory and - * serializers. - * @template T - */ -ol.xml.serialize = function( - serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) { - var length = (opt_keys !== undefined ? opt_keys : values).length; - var value, node; - for (var i = 0; i < length; ++i) { - value = values[i]; - if (value !== undefined) { - node = nodeFactory.call(opt_this, value, objectStack, - opt_keys !== undefined ? opt_keys[i] : undefined); - if (node !== undefined) { - serializersNS[node.namespaceURI][node.localName] - .call(opt_this, node, value, objectStack); + var onFulfill = function(value) { + resolve(value); + }; + + var onReject = function(index, reason) { + toReject--; + reasons[index] = reason; + if (toReject == 0) { + reject(reasons); } + }; + + for (var i = 0, promise; i < promises.length; i++) { + promise = promises[i]; + goog.Promise.resolveThen_( + promise, onFulfill, goog.partial(onReject, i)); } - } + }); }; /** - * @param {O} object Object. - * @param {Object.<string, Object.<string, ol.xml.Serializer>>} serializersNS - * Namespaced serializers. - * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory - * Node factory. The `nodeFactory` creates the node whose namespace and name - * will be used to choose a node writer from `serializersNS`. This - * separation allows us to decide what kind of node to create, depending on - * the value we want to serialize. An example for this would be different - * geometry writers based on the geometry type. - * @param {Array.<*>} values Values to serialize. An example would be an array - * of {@link ol.Feature} instances. - * @param {Array.<*>} objectStack Node stack. - * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the - * `nodeFactory`. This is used for serializing object literals where the - * node name relates to the property key. The array length of `opt_keys` has - * to match the length of `values`. For serializing a sequence, `opt_keys` - * determines the order of the sequence. - * @param {T=} opt_this The object to use as `this` for the node factory and - * serializers. - * @return {O|undefined} Object. - * @template O, T + * @return {!goog.promise.Resolver<TYPE>} Resolver wrapping the promise and its + * resolve / reject functions. Resolving or rejecting the resolver + * resolves or rejects the promise. + * @template TYPE */ -ol.xml.pushSerializeAndPop = function(object, - serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) { - objectStack.push(object); - ol.xml.serialize( - serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this); - return objectStack.pop(); +goog.Promise.withResolver = function() { + var resolve, reject; + var promise = new goog.Promise(function(rs, rj) { + resolve = rs; + reject = rj; + }); + return new goog.Promise.Resolver_(promise, resolve, reject); }; -goog.provide('ol.FeatureLoader'); -goog.provide('ol.FeatureUrlFunction'); -goog.provide('ol.featureloader'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo'); -goog.require('goog.net.XhrIo.ResponseType'); -goog.require('ol.TileState'); -goog.require('ol.format.FormatType'); -goog.require('ol.xml'); - /** - * {@link ol.source.Vector} sources use a function of this type to load - * features. + * Adds callbacks that will operate on the result of the Promise, returning a + * new child Promise. * - * This function takes an {@link ol.Extent} representing the area to be loaded, - * a `{number}` representing the resolution (map units per pixel) and an - * {@link ol.proj.Projection} for the projection as arguments. `this` within - * the function is bound to the {@link ol.source.Vector} it's called from. + * If the Promise is fulfilled, the {@code onFulfilled} callback will be invoked + * with the fulfillment value as argument, and the child Promise will be + * fulfilled with the return value of the callback. If the callback throws an + * exception, the child Promise will be rejected with the thrown value instead. * - * The function is responsible for loading the features and adding them to the - * source. - * @api - * @typedef {function(this:ol.source.Vector, ol.Extent, number, - * ol.proj.Projection)} + * If the Promise is rejected, the {@code onRejected} callback will be invoked + * with the rejection reason as argument, and the child Promise will be resolved + * with the return value or rejected with the thrown value of the callback. + * + * @override */ -ol.FeatureLoader; +goog.Promise.prototype.then = function( + opt_onFulfilled, opt_onRejected, opt_context) { + + if (opt_onFulfilled != null) { + goog.asserts.assertFunction(opt_onFulfilled, + 'opt_onFulfilled should be a function.'); + } + if (opt_onRejected != null) { + goog.asserts.assertFunction(opt_onRejected, + 'opt_onRejected should be a function. Did you pass opt_context ' + + 'as the second argument instead of the third?'); + } + if (goog.Promise.LONG_STACK_TRACES) { + this.addStackTrace_(new Error('then')); + } -/** - * {@link ol.source.Vector} sources use a function of this type to get the url - * to load features from. - * - * This function takes an {@link ol.Extent} representing the area to be loaded, - * a `{number}` representing the resolution (map units per pixel) and an - * {@link ol.proj.Projection} for the projection as arguments and returns a - * `{string}` representing the URL. - * @api - * @typedef {function(ol.Extent, number, ol.proj.Projection) : string} - */ -ol.FeatureUrlFunction; + return this.addChildPromise_( + goog.isFunction(opt_onFulfilled) ? opt_onFulfilled : null, + goog.isFunction(opt_onRejected) ? opt_onRejected : null, + opt_context); +}; +goog.Thenable.addImplementation(goog.Promise); /** - * @param {string|ol.FeatureUrlFunction} url Feature URL service. - * @param {ol.format.Feature} format Feature format. - * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection)|function(this:ol.source.Vector, Array.<ol.Feature>)} success - * Function called with the loaded features and optionally with the data - * projection. Called with the vector tile or source as `this`. - * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure - * Function called when loading failed. Called with the vector tile or - * source as `this`. - * @return {ol.FeatureLoader} The feature loader. + * Adds callbacks that will operate on the result of the Promise without + * returning a child Promise (unlike "then"). + * + * If the Promise is fulfilled, the {@code onFulfilled} callback will be invoked + * with the fulfillment value as argument. + * + * If the Promise is rejected, the {@code onRejected} callback will be invoked + * with the rejection reason as argument. + * + * @param {?(function(this:THIS, TYPE):?)=} opt_onFulfilled A + * function that will be invoked with the fulfillment value if the Promise + * is fulfilled. + * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will + * be invoked with the rejection reason if the Promise is rejected. + * @param {THIS=} opt_context An optional context object that will be the + * execution context for the callbacks. By default, functions are executed + * with the default this. + * @package + * @template THIS */ -ol.featureloader.loadFeaturesXhr = function(url, format, success, failure) { - return ( - /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {ol.proj.Projection} projection Projection. - * @this {ol.source.Vector|ol.VectorTile} - */ - function(extent, resolution, projection) { - var xhrIo = new goog.net.XhrIo(); - xhrIo.setResponseType( - format.getType() == ol.format.FormatType.ARRAY_BUFFER ? - goog.net.XhrIo.ResponseType.ARRAY_BUFFER : - goog.net.XhrIo.ResponseType.TEXT); - goog.events.listen(xhrIo, goog.net.EventType.COMPLETE, - /** - * @param {Event} event Event. - * @private - * @this {ol.source.Vector} - */ - function(event) { - var xhrIo = event.target; - goog.asserts.assertInstanceof(xhrIo, goog.net.XhrIo, - 'event.target/xhrIo is an instance of goog.net.XhrIo'); - if (xhrIo.isSuccess()) { - var type = format.getType(); - /** @type {Document|Node|Object|string|undefined} */ - var source; - if (type == ol.format.FormatType.JSON) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.TEXT) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.XML) { - if (!goog.userAgent.IE) { - source = xhrIo.getResponseXml(); - } - if (!source) { - source = ol.xml.parse(xhrIo.getResponseText()); - } - } else if (type == ol.format.FormatType.ARRAY_BUFFER) { - source = xhrIo.getResponse(); - } else { - goog.asserts.fail('unexpected format type'); - } - if (source) { - var features = format.readFeatures(source, - {featureProjection: projection}); - if (ol.ENABLE_VECTOR_TILE && success.length == 2) { - success.call(this, features, format.readProjection(source)); - } else { - success.call(this, features); - } - } else { - goog.asserts.fail('undefined or null source'); - } - } else { - failure.call(this); - } - goog.dispose(xhrIo); - }, false, this); - if (goog.isFunction(url)) { - xhrIo.send(url(extent, resolution, projection)); - } else { - xhrIo.send(url); - } +goog.Promise.prototype.thenVoid = function( + opt_onFulfilled, opt_onRejected, opt_context) { - }); -}; + if (opt_onFulfilled != null) { + goog.asserts.assertFunction(opt_onFulfilled, + 'opt_onFulfilled should be a function.'); + } + if (opt_onRejected != null) { + goog.asserts.assertFunction(opt_onRejected, + 'opt_onRejected should be a function. Did you pass opt_context ' + + 'as the second argument instead of the third?'); + } + if (goog.Promise.LONG_STACK_TRACES) { + this.addStackTrace_(new Error('then')); + } -/** - * Create an XHR feature loader for a `url` and `format`. The feature loader - * loads features (with XHR), parses the features, and adds them to the - * vector tile. - * @param {string|ol.FeatureUrlFunction} url Feature URL service. - * @param {ol.format.Feature} format Feature format. - * @return {ol.FeatureLoader} The feature loader. - * @api - */ -ol.featureloader.tile = function(url, format) { - return ol.featureloader.loadFeaturesXhr(url, format, - /** - * @param {Array.<ol.Feature>} features The loaded features. - * @param {ol.proj.Projection} projection Data projection. - * @this {ol.VectorTile} - */ - function(features, projection) { - this.setProjection(projection); - this.setFeatures(features); - }, - /** - * @this {ol.VectorTile} - */ - function() { - this.setState(ol.TileState.ERROR); - }); + // Note: no default rejection handler is provided here as we need to + // distinguish unhandled rejections. + this.addCallbackEntry_(goog.Promise.getCallbackEntry_( + opt_onFulfilled || goog.nullFunction, + opt_onRejected || null, + opt_context)); }; /** - * Create an XHR feature loader for a `url` and `format`. The feature loader - * loads features (with XHR), parses the features, and adds them to the - * vector source. - * @param {string|ol.FeatureUrlFunction} url Feature URL service. - * @param {ol.format.Feature} format Feature format. - * @return {ol.FeatureLoader} The feature loader. - * @api + * Adds a callback that will be invoked when the Promise is settled (fulfilled + * or rejected). The callback receives no argument, and no new child Promise is + * created. This is useful for ensuring that cleanup takes place after certain + * asynchronous operations. Callbacks added with {@code thenAlways} will be + * executed in the same order with other calls to {@code then}, + * {@code thenAlways}, or {@code thenCatch}. + * + * Since it does not produce a new child Promise, cancellation propagation is + * not prevented by adding callbacks with {@code thenAlways}. A Promise that has + * a cleanup handler added with {@code thenAlways} will be canceled if all of + * its children created by {@code then} (or {@code thenCatch}) are canceled. + * Additionally, since any rejections are not passed to the callback, it does + * not stop the unhandled rejection handler from running. + * + * @param {function(this:THIS): void} onSettled A function that will be invoked + * when the Promise is settled (fulfilled or rejected). + * @param {THIS=} opt_context An optional context object that will be the + * execution context for the callbacks. By default, functions are executed + * in the global scope. + * @return {!goog.Promise<TYPE>} This Promise, for chaining additional calls. + * @template THIS */ -ol.featureloader.xhr = function(url, format) { - return ol.featureloader.loadFeaturesXhr(url, format, - /** - * @param {Array.<ol.Feature>} features The loaded features. - * @this {ol.source.Vector} - */ - function(features) { - this.addFeatures(features); - }, /* FIXME handle error */ ol.nullFunction); -}; - -goog.provide('ol.LoadingStrategy'); -goog.provide('ol.loadingstrategy'); - -goog.require('ol.TileCoord'); - +goog.Promise.prototype.thenAlways = function(onSettled, opt_context) { + if (goog.Promise.LONG_STACK_TRACES) { + this.addStackTrace_(new Error('thenAlways')); + } -/** - * @typedef {function(ol.Extent, number): Array.<ol.Extent>} - * @api - */ -ol.LoadingStrategy; + var entry = goog.Promise.getCallbackEntry_(onSettled, onSettled, opt_context); + entry.always = true; + this.addCallbackEntry_(entry); + return this; +}; /** - * Strategy function for loading all features with a single request. - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {Array.<ol.Extent>} Extents. - * @api + * Adds a callback that will be invoked only if the Promise is rejected. This + * is equivalent to {@code then(null, onRejected)}. + * + * @param {!function(this:THIS, *): *} onRejected A function that will be + * invoked with the rejection reason if the Promise is rejected. + * @param {THIS=} opt_context An optional context object that will be the + * execution context for the callbacks. By default, functions are executed + * in the global scope. + * @return {!goog.Promise} A new Promise that will receive the result of the + * callback. + * @template THIS */ -ol.loadingstrategy.all = function(extent, resolution) { - return [[-Infinity, -Infinity, Infinity, Infinity]]; +goog.Promise.prototype.thenCatch = function(onRejected, opt_context) { + if (goog.Promise.LONG_STACK_TRACES) { + this.addStackTrace_(new Error('thenCatch')); + } + return this.addChildPromise_(null, onRejected, opt_context); }; /** - * Strategy function for loading features based on the view's extent and - * resolution. - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {Array.<ol.Extent>} Extents. - * @api + * Cancels the Promise if it is still pending by rejecting it with a cancel + * Error. No action is performed if the Promise is already resolved. + * + * All child Promises of the canceled Promise will be rejected with the same + * cancel error, as with normal Promise rejection. If the Promise to be canceled + * is the only child of a pending Promise, the parent Promise will also be + * canceled. Cancellation may propagate upward through multiple generations. + * + * @param {string=} opt_message An optional debugging message for describing the + * cancellation reason. */ -ol.loadingstrategy.bbox = function(extent, resolution) { - return [extent]; +goog.Promise.prototype.cancel = function(opt_message) { + if (this.state_ == goog.Promise.State_.PENDING) { + goog.async.run(function() { + var err = new goog.Promise.CancellationError(opt_message); + this.cancelInternal_(err); + }, this); + } }; /** - * Creates a strategy function for loading features based on a tile grid. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {function(ol.Extent, number): Array.<ol.Extent>} Loading strategy. - * @api + * Cancels this Promise with the given error. + * + * @param {!Error} err The cancellation error. + * @private */ -ol.loadingstrategy.tile = function(tileGrid) { - return ( - /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {Array.<ol.Extent>} Extents. - */ - function(extent, resolution) { - var z = tileGrid.getZForResolution(resolution); - var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - /** @type {Array.<ol.Extent>} */ - var extents = []; - /** @type {ol.TileCoord} */ - var tileCoord = [z, 0, 0]; - for (tileCoord[1] = tileRange.minX; tileCoord[1] <= tileRange.maxX; - ++tileCoord[1]) { - for (tileCoord[2] = tileRange.minY; tileCoord[2] <= tileRange.maxY; - ++tileCoord[2]) { - extents.push(tileGrid.getTileCoordExtent(tileCoord)); - } - } - return extents; - }); +goog.Promise.prototype.cancelInternal_ = function(err) { + if (this.state_ == goog.Promise.State_.PENDING) { + if (this.parent_) { + // Cancel the Promise and remove it from the parent's child list. + this.parent_.cancelChild_(this, err); + this.parent_ = null; + } else { + this.resolve_(goog.Promise.State_.REJECTED, err); + } + } }; -goog.provide('ol.structs.RBush'); - -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.ext.rbush'); -goog.require('ol.extent'); - - /** - * Wrapper around the RBush by Vladimir Agafonkin. + * Cancels a child Promise from the list of callback entries. If the Promise has + * not already been resolved, reject it with a cancel error. If there are no + * other children in the list of callback entries, propagate the cancellation + * by canceling this Promise as well. * - * @constructor - * @param {number=} opt_maxEntries Max entries. - * @see https://github.com/mourner/rbush - * @struct - * @template T + * @param {!goog.Promise} childPromise The Promise to cancel. + * @param {!Error} err The cancel error to use for rejecting the Promise. + * @private */ -ol.structs.RBush = function(opt_maxEntries) { +goog.Promise.prototype.cancelChild_ = function(childPromise, err) { + if (!this.callbackEntries_) { + return; + } + var childCount = 0; + var childEntry = null; + var beforeChildEntry = null; - /** - * @private - */ - this.rbush_ = ol.ext.rbush(opt_maxEntries); + // Find the callback entry for the childPromise, and count whether there are + // additional child Promises. + for (var entry = this.callbackEntries_; entry; entry = entry.next) { + if (!entry.always) { + childCount++; + if (entry.child == childPromise) { + childEntry = entry; + } + if (childEntry && childCount > 1) { + break; + } + } + if (!childEntry) { + beforeChildEntry = entry; + } + } - /** - * A mapping between the objects added to this rbush wrapper - * and the objects that are actually added to the internal rbush. - * @private - * @type {Object.<number, Object>} - */ - this.items_ = {}; + // Can a child entry be missing? - if (goog.DEBUG) { - /** - * @private - * @type {number} - */ - this.readers_ = 0; + // If the child Promise was the only child, cancel this Promise as well. + // Otherwise, reject only the child Promise with the cancel error. + if (childEntry) { + if (this.state_ == goog.Promise.State_.PENDING && childCount == 1) { + this.cancelInternal_(err); + } else { + if (beforeChildEntry) { + this.removeEntryAfter_(beforeChildEntry); + } else { + this.popEntry_(); + } + + this.executeCallback_( + childEntry, goog.Promise.State_.REJECTED, err); + } } }; /** - * Insert a value into the RBush. - * @param {ol.Extent} extent Extent. - * @param {T} value Value. + * Adds a callback entry to the current Promise, and schedules callback + * execution if the Promise has already been settled. + * + * @param {goog.Promise.CallbackEntry_} callbackEntry Record containing + * {@code onFulfilled} and {@code onRejected} callbacks to execute after + * the Promise is settled. + * @private */ -ol.structs.RBush.prototype.insert = function(extent, value) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not insert value while reading'); +goog.Promise.prototype.addCallbackEntry_ = function(callbackEntry) { + if (!this.hasEntry_() && + (this.state_ == goog.Promise.State_.FULFILLED || + this.state_ == goog.Promise.State_.REJECTED)) { + this.scheduleCallbacks_(); } - var item = [ - extent[0], - extent[1], - extent[2], - extent[3], - value - ]; - this.rbush_.insert(item); - // remember the object that was added to the internal rbush - goog.asserts.assert( - !goog.object.containsKey(this.items_, goog.getUid(value)), - 'uid (%s) of value (%s) already exists', goog.getUid(value), value); - this.items_[goog.getUid(value)] = item; + this.queueEntry_(callbackEntry); }; /** - * Bulk-insert values into the RBush. - * @param {Array.<ol.Extent>} extents Extents. - * @param {Array.<T>} values Values. + * Creates a child Promise and adds it to the callback entry list. The result of + * the child Promise is determined by the state of the parent Promise and the + * result of the {@code onFulfilled} or {@code onRejected} callbacks as + * specified in the Promise resolution procedure. + * + * @see http://promisesaplus.com/#the__method + * + * @param {?function(this:THIS, TYPE): + * (RESULT|goog.Promise<RESULT>|Thenable)} onFulfilled A callback that + * will be invoked if the Promise is fullfilled, or null. + * @param {?function(this:THIS, *): *} onRejected A callback that will be + * invoked if the Promise is rejected, or null. + * @param {THIS=} opt_context An optional execution context for the callbacks. + * in the default calling context. + * @return {!goog.Promise} The child Promise. + * @template RESULT,THIS + * @private */ -ol.structs.RBush.prototype.load = function(extents, values) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not insert values while reading'); - } - goog.asserts.assert(extents.length === values.length, - 'extens and values must have same length (%s === %s)', - extents.length, values.length); - - var items = new Array(values.length); - for (var i = 0, l = values.length; i < l; i++) { - var extent = extents[i]; - var value = values[i]; +goog.Promise.prototype.addChildPromise_ = function( + onFulfilled, onRejected, opt_context) { - var item = [ - extent[0], - extent[1], - extent[2], - extent[3], - value - ]; - items[i] = item; - goog.asserts.assert( - !goog.object.containsKey(this.items_, goog.getUid(value)), - 'uid (%s) of value (%s) already exists', goog.getUid(value), value); - this.items_[goog.getUid(value)] = item; - } - this.rbush_.load(items); -}; + /** @type {goog.Promise.CallbackEntry_} */ + var callbackEntry = goog.Promise.getCallbackEntry_(null, null, null); + callbackEntry.child = new goog.Promise(function(resolve, reject) { + // Invoke onFulfilled, or resolve with the parent's value if absent. + callbackEntry.onFulfilled = onFulfilled ? function(value) { + try { + var result = onFulfilled.call(opt_context, value); + resolve(result); + } catch (err) { + reject(err); + } + } : resolve; -/** - * Remove a value from the RBush. - * @param {T} value Value. - * @return {boolean} Removed. - */ -ol.structs.RBush.prototype.remove = function(value) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not remove value while reading'); - } - var uid = goog.getUid(value); - goog.asserts.assert(goog.object.containsKey(this.items_, uid), - 'uid (%s) of value (%s) does not exist', uid, value); + // Invoke onRejected, or reject with the parent's reason if absent. + callbackEntry.onRejected = onRejected ? function(reason) { + try { + var result = onRejected.call(opt_context, reason); + if (!goog.isDef(result) && + reason instanceof goog.Promise.CancellationError) { + // Propagate cancellation to children if no other result is returned. + reject(reason); + } else { + resolve(result); + } + } catch (err) { + reject(err); + } + } : reject; + }); - // get the object in which the value was wrapped when adding to the - // internal rbush. then use that object to do the removal. - var item = this.items_[uid]; - delete this.items_[uid]; - return this.rbush_.remove(item) !== null; + callbackEntry.child.parent_ = this; + this.addCallbackEntry_(callbackEntry); + return callbackEntry.child; }; /** - * Update the extent of a value in the RBush. - * @param {ol.Extent} extent Extent. - * @param {T} value Value. + * Unblocks the Promise and fulfills it with the given value. + * + * @param {TYPE} value + * @private */ -ol.structs.RBush.prototype.update = function(extent, value) { - var uid = goog.getUid(value); - goog.asserts.assert(goog.object.containsKey(this.items_, uid), - 'uid (%s) of value (%s) does not exist', uid, value); - - var item = this.items_[uid]; - if (!ol.extent.equals(item.slice(0, 4), extent)) { - if (goog.DEBUG && this.readers_) { - throw new Error('Can not update extent while reading'); - } - this.remove(value); - this.insert(extent, value); - } +goog.Promise.prototype.unblockAndFulfill_ = function(value) { + goog.asserts.assert(this.state_ == goog.Promise.State_.BLOCKED); + this.state_ = goog.Promise.State_.PENDING; + this.resolve_(goog.Promise.State_.FULFILLED, value); }; /** - * Return all values in the RBush. - * @return {Array.<T>} All. + * Unblocks the Promise and rejects it with the given rejection reason. + * + * @param {*} reason + * @private */ -ol.structs.RBush.prototype.getAll = function() { - var items = this.rbush_.all(); - return items.map(function(item) { - return item[4]; - }); +goog.Promise.prototype.unblockAndReject_ = function(reason) { + goog.asserts.assert(this.state_ == goog.Promise.State_.BLOCKED); + this.state_ = goog.Promise.State_.PENDING; + this.resolve_(goog.Promise.State_.REJECTED, reason); }; /** - * Return all values in the given extent. - * @param {ol.Extent} extent Extent. - * @return {Array.<T>} All in extent. + * Attempts to resolve a Promise with a given resolution state and value. This + * is a no-op if the given Promise has already been resolved. + * + * If the given result is a Thenable (such as another Promise), the Promise will + * be settled with the same state and result as the Thenable once it is itself + * settled. + * + * If the given result is not a Thenable, the Promise will be settled (fulfilled + * or rejected) with that result based on the given state. + * + * @see http://promisesaplus.com/#the_promise_resolution_procedure + * + * @param {goog.Promise.State_} state + * @param {*} x The result to apply to the Promise. + * @private */ -ol.structs.RBush.prototype.getInExtent = function(extent) { - var items = this.rbush_.search(extent); - return items.map(function(item) { - return item[4]; - }); -}; +goog.Promise.prototype.resolve_ = function(state, x) { + if (this.state_ != goog.Promise.State_.PENDING) { + return; + } + if (this == x) { + state = goog.Promise.State_.REJECTED; + x = new TypeError('Promise cannot resolve to itself'); + } -/** - * Calls a callback function with each value in the tree. - * If the callback returns a truthy value, this value is returned without - * checking the rest of the tree. - * @param {function(this: S, T): *} callback Callback. - * @param {S=} opt_this The object to use as `this` in `callback`. - * @return {*} Callback return value. - * @template S - */ -ol.structs.RBush.prototype.forEach = function(callback, opt_this) { - if (goog.DEBUG) { - ++this.readers_; - try { - return this.forEach_(this.getAll(), callback, opt_this); - } finally { - --this.readers_; - } - } else { - return this.forEach_(this.getAll(), callback, opt_this); + this.state_ = goog.Promise.State_.BLOCKED; + var isThenable = goog.Promise.maybeThen_( + x, this.unblockAndFulfill_, this.unblockAndReject_, this); + if (isThenable) { + return; + } + + this.result_ = x; + this.state_ = state; + // Since we can no longer be canceled, remove link to parent, so that the + // child promise does not keep the parent promise alive. + this.parent_ = null; + this.scheduleCallbacks_(); + + if (state == goog.Promise.State_.REJECTED && + !(x instanceof goog.Promise.CancellationError)) { + goog.Promise.addUnhandledRejection_(this, x); } }; /** - * Calls a callback function with each value in the provided extent. - * @param {ol.Extent} extent Extent. - * @param {function(this: S, T): *} callback Callback. - * @param {S=} opt_this The object to use as `this` in `callback`. - * @return {*} Callback return value. - * @template S + * Invokes the "then" method of an input value if that value is a Thenable. This + * is a no-op if the value is not thenable. + * + * @param {*} value A potentially thenable value. + * @param {!Function} onFulfilled + * @param {!Function} onRejected + * @param {*} context + * @return {boolean} Whether the input value was thenable. + * @private */ -ol.structs.RBush.prototype.forEachInExtent = - function(extent, callback, opt_this) { - if (goog.DEBUG) { - ++this.readers_; +goog.Promise.maybeThen_ = function(value, onFulfilled, onRejected, context) { + if (value instanceof goog.Promise) { + value.thenVoid(onFulfilled, onRejected, context); + return true; + } else if (goog.Thenable.isImplementedBy(value)) { + value = /** @type {!goog.Thenable} */ (value); + value.then(onFulfilled, onRejected, context); + return true; + } else if (goog.isObject(value)) { try { - return this.forEach_(this.getInExtent(extent), callback, opt_this); - } finally { - --this.readers_; + var then = value['then']; + if (goog.isFunction(then)) { + goog.Promise.tryThen_( + value, then, onFulfilled, onRejected, context); + return true; + } + } catch (e) { + onRejected.call(context, e); + return true; } - } else { - return this.forEach_(this.getInExtent(extent), callback, opt_this); } + + return false; }; /** - * @param {Array.<T>} values Values. - * @param {function(this: S, T): *} callback Callback. - * @param {S=} opt_this The object to use as `this` in `callback`. + * Attempts to call the {@code then} method on an object in the hopes that it is + * a Promise-compatible instance. This allows interoperation between different + * Promise implementations, however a non-compliant object may cause a Promise + * to hang indefinitely. If the {@code then} method throws an exception, the + * dependent Promise will be rejected with the thrown value. + * + * @see http://promisesaplus.com/#point-70 + * + * @param {Thenable} thenable An object with a {@code then} method that may be + * compatible with the Promise/A+ specification. + * @param {!Function} then The {@code then} method of the Thenable object. + * @param {!Function} onFulfilled + * @param {!Function} onRejected + * @param {*} context * @private - * @return {*} Callback return value. - * @template S */ -ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) { - var result; - for (var i = 0, l = values.length; i < l; i++) { - result = callback.call(opt_this, values[i]); - if (result) { - return result; +goog.Promise.tryThen_ = function( + thenable, then, onFulfilled, onRejected, context) { + + var called = false; + var resolve = function(value) { + if (!called) { + called = true; + onFulfilled.call(context, value); } - } - return result; -}; + }; + var reject = function(reason) { + if (!called) { + called = true; + onRejected.call(context, reason); + } + }; -/** - * @return {boolean} Is empty. - */ -ol.structs.RBush.prototype.isEmpty = function() { - return goog.object.isEmpty(this.items_); + try { + then.call(thenable, resolve, reject); + } catch (e) { + reject(e); + } }; /** - * Remove all values from the RBush. + * Executes the pending callbacks of a settled Promise after a timeout. + * + * Section 2.2.4 of the Promises/A+ specification requires that Promise + * callbacks must only be invoked from a call stack that only contains Promise + * implementation code, which we accomplish by invoking callback execution after + * a timeout. If {@code startExecution_} is called multiple times for the same + * Promise, the callback chain will be evaluated only once. Additional callbacks + * may be added during the evaluation phase, and will be executed in the same + * event loop. + * + * All Promises added to the waiting list during the same browser event loop + * will be executed in one batch to avoid using a separate timeout per Promise. + * + * @private */ -ol.structs.RBush.prototype.clear = function() { - this.rbush_.clear(); - this.items_ = {}; +goog.Promise.prototype.scheduleCallbacks_ = function() { + if (!this.executing_) { + this.executing_ = true; + goog.async.run(this.executeCallbacks_, this); + } }; /** - * @param {ol.Extent=} opt_extent Extent. - * @return {!ol.Extent} Extent. + * @return {boolean} Whether there are any pending callbacks queued. + * @private */ -ol.structs.RBush.prototype.getExtent = function(opt_extent) { - // FIXME add getExtent() to rbush - return this.rbush_.data.bbox; +goog.Promise.prototype.hasEntry_ = function() { + return !!this.callbackEntries_; }; -// FIXME bulk feature upload - suppress events -// FIXME make change-detection more refined (notably, geometry hint) - -goog.provide('ol.source.Vector'); -goog.provide('ol.source.VectorEvent'); -goog.provide('ol.source.VectorEventType'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Extent'); -goog.require('ol.Feature'); -goog.require('ol.FeatureLoader'); -goog.require('ol.LoadingStrategy'); -goog.require('ol.ObjectEventType'); -goog.require('ol.extent'); -goog.require('ol.featureloader'); -goog.require('ol.loadingstrategy'); -goog.require('ol.proj'); -goog.require('ol.source.Source'); -goog.require('ol.source.State'); -goog.require('ol.structs.RBush'); - /** - * @enum {string} + * @param {goog.Promise.CallbackEntry_} entry + * @private */ -ol.source.VectorEventType = { - /** - * Triggered when a feature is added to the source. - * @event ol.source.VectorEvent#addfeature - * @api stable - */ - ADDFEATURE: 'addfeature', - - /** - * Triggered when a feature is updated. - * @event ol.source.VectorEvent#changefeature - * @api - */ - CHANGEFEATURE: 'changefeature', - - /** - * Triggered when the clear method is called on the source. - * @event ol.source.VectorEvent#clear - * @api - */ - CLEAR: 'clear', +goog.Promise.prototype.queueEntry_ = function(entry) { + goog.asserts.assert(entry.onFulfilled != null); - /** - * Triggered when a feature is removed from the source. - * See {@link ol.source.Vector#clear source.clear()} for exceptions. - * @event ol.source.VectorEvent#removefeature - * @api stable - */ - REMOVEFEATURE: 'removefeature' + if (this.callbackEntriesTail_) { + this.callbackEntriesTail_.next = entry; + this.callbackEntriesTail_ = entry; + } else { + // It the work queue was empty set the head too. + this.callbackEntries_ = entry; + this.callbackEntriesTail_ = entry; + } }; - /** - * @classdesc - * Provides a source of features for vector layers. Vector features provided - * by this source are suitable for editing. See {@link ol.source.VectorTile} for - * vector data that is optimized for rendering. - * - * @constructor - * @extends {ol.source.Source} - * @fires ol.source.VectorEvent - * @param {olx.source.VectorOptions=} opt_options Vector source options. - * @api stable + * @return {goog.Promise.CallbackEntry_} entry + * @private */ -ol.source.Vector = function(opt_options) { - - var options = opt_options || {}; - - goog.base(this, { - attributions: options.attributions, - logo: options.logo, - projection: undefined, - state: ol.source.State.READY, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); - - /** - * @private - * @type {ol.FeatureLoader} - */ - this.loader_ = ol.nullFunction; - - if (options.loader !== undefined) { - this.loader_ = options.loader; - } else if (options.url !== undefined) { - goog.asserts.assert(options.format !== undefined, - 'format must be set when url is set'); - // create a XHR feature loader for "url" and "format" - this.loader_ = ol.featureloader.xhr(options.url, options.format); +goog.Promise.prototype.popEntry_ = function() { + var entry = null; + if (this.callbackEntries_) { + entry = this.callbackEntries_; + this.callbackEntries_ = entry.next; + entry.next = null; + } + // It the work queue is empty clear the tail too. + if (!this.callbackEntries_) { + this.callbackEntriesTail_ = null; } - /** - * @private - * @type {ol.LoadingStrategy} - */ - this.strategy_ = options.strategy !== undefined ? options.strategy : - ol.loadingstrategy.all; - - var useSpatialIndex = - options.useSpatialIndex !== undefined ? options.useSpatialIndex : true; - - /** - * @private - * @type {ol.structs.RBush.<ol.Feature>} - */ - this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null; - - /** - * @private - * @type {ol.structs.RBush.<{extent: ol.Extent}>} - */ - this.loadedExtentsRtree_ = new ol.structs.RBush(); - - /** - * @private - * @type {Object.<string, ol.Feature>} - */ - this.nullGeometryFeatures_ = {}; - - /** - * A lookup of features by id (the return from feature.getId()). - * @private - * @type {Object.<string, ol.Feature>} - */ - this.idIndex_ = {}; - - /** - * A lookup of features without id (keyed by goog.getUid(feature)). - * @private - * @type {Object.<string, ol.Feature>} - */ - this.undefIdIndex_ = {}; - - /** - * @private - * @type {Object.<string, Array.<goog.events.Key>>} - */ - this.featureChangeKeys_ = {}; + if (entry != null) { + goog.asserts.assert(entry.onFulfilled != null); + } + return entry; +}; - /** - * @private - * @type {ol.Collection.<ol.Feature>} - */ - this.featuresCollection_ = null; - var collection, features; - if (options.features instanceof ol.Collection) { - collection = options.features; - features = collection.getArray(); - } else if (goog.isArray(options.features)) { - features = options.features; - } - if (!useSpatialIndex && collection === undefined) { - collection = new ol.Collection(features); - } - if (features !== undefined) { - this.addFeaturesInternal(features); - } - if (collection !== undefined) { - this.bindFeaturesCollection_(collection); +/** + * @param {goog.Promise.CallbackEntry_} previous + * @private + */ +goog.Promise.prototype.removeEntryAfter_ = function(previous) { + goog.asserts.assert(this.callbackEntries_); + goog.asserts.assert(previous != null); + // If the last entry is being removed, update the tail + if (previous.next == this.callbackEntriesTail_) { + this.callbackEntriesTail_ = previous; } + previous.next = previous.next.next; }; -goog.inherits(ol.source.Vector, ol.source.Source); /** - * Add a single feature to the source. If you want to add a batch of features - * at once, call {@link ol.source.Vector#addFeatures source.addFeatures()} - * instead. - * @param {ol.Feature} feature Feature to add. - * @api stable + * Executes all pending callbacks for this Promise. + * + * @private */ -ol.source.Vector.prototype.addFeature = function(feature) { - this.addFeatureInternal(feature); - this.changed(); +goog.Promise.prototype.executeCallbacks_ = function() { + var entry = null; + while (entry = this.popEntry_()) { + if (goog.Promise.LONG_STACK_TRACES) { + this.currentStep_++; + } + this.executeCallback_(entry, this.state_, this.result_); + } + this.executing_ = false; }; /** - * Add a feature without firing a `change` event. - * @param {ol.Feature} feature Feature. - * @protected + * Executes a pending callback for this Promise. Invokes an {@code onFulfilled} + * or {@code onRejected} callback based on the settled state of the Promise. + * + * @param {!goog.Promise.CallbackEntry_} callbackEntry An entry containing the + * onFulfilled and/or onRejected callbacks for this step. + * @param {goog.Promise.State_} state The resolution status of the Promise, + * either FULFILLED or REJECTED. + * @param {*} result The settled result of the Promise. + * @private */ -ol.source.Vector.prototype.addFeatureInternal = function(feature) { - var featureKey = goog.getUid(feature).toString(); - - if (!this.addToIndex_(featureKey, feature)) { - return; +goog.Promise.prototype.executeCallback_ = function( + callbackEntry, state, result) { + // Cancel an unhandled rejection if the then/thenVoid call had an onRejected. + if (state == goog.Promise.State_.REJECTED && + callbackEntry.onRejected && !callbackEntry.always) { + this.removeUnhandledRejection_(); } - this.setupChangeEvents_(featureKey, feature); - - var geometry = feature.getGeometry(); - if (geometry) { - var extent = geometry.getExtent(); - if (this.featuresRtree_) { - this.featuresRtree_.insert(extent, feature); - } + if (callbackEntry.child) { + // When the parent is settled, the child no longer needs to hold on to it, + // as the parent can no longer be canceled. + callbackEntry.child.parent_ = null; + goog.Promise.invokeCallback_(callbackEntry, state, result); } else { - this.nullGeometryFeatures_[featureKey] = feature; + // Callbacks created with thenAlways or thenVoid do not have the rejection + // handling code normally set up in the child Promise. + try { + callbackEntry.always ? + callbackEntry.onFulfilled.call(callbackEntry.context) : + goog.Promise.invokeCallback_(callbackEntry, state, result); + } catch (err) { + goog.Promise.handleRejection_.call(null, err); + } } - - this.dispatchEvent( - new ol.source.VectorEvent(ol.source.VectorEventType.ADDFEATURE, feature)); + goog.Promise.returnEntry_(callbackEntry); }; /** - * @param {string} featureKey - * @param {ol.Feature} feature + * Executes the onFulfilled or onRejected callback for a callbackEntry. + * + * @param {!goog.Promise.CallbackEntry_} callbackEntry + * @param {goog.Promise.State_} state + * @param {*} result * @private */ -ol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) { - goog.asserts.assert(!(featureKey in this.featureChangeKeys_), - 'key (%s) not yet registered in featureChangeKey', featureKey); - this.featureChangeKeys_[featureKey] = [ - goog.events.listen(feature, - goog.events.EventType.CHANGE, - this.handleFeatureChange_, false, this), - goog.events.listen(feature, - ol.ObjectEventType.PROPERTYCHANGE, - this.handleFeatureChange_, false, this) - ]; +goog.Promise.invokeCallback_ = function(callbackEntry, state, result) { + if (state == goog.Promise.State_.FULFILLED) { + callbackEntry.onFulfilled.call(callbackEntry.context, result); + } else if (callbackEntry.onRejected) { + callbackEntry.onRejected.call(callbackEntry.context, result); + } }; /** - * @param {string} featureKey - * @param {ol.Feature} feature - * @return {boolean} `true` if the feature is "valid", in the sense that it is - * also a candidate for insertion into the Rtree, otherwise `false`. - * @private + * Records a stack trace entry for functions that call {@code then} or the + * Promise constructor. May be disabled by unsetting {@code LONG_STACK_TRACES}. + * + * @param {!Error} err An Error object created by the calling function for + * providing a stack trace. + * @private */ -ol.source.Vector.prototype.addToIndex_ = function(featureKey, feature) { - var valid = true; - var id = feature.getId(); - if (id !== undefined) { - if (!(id.toString() in this.idIndex_)) { - this.idIndex_[id.toString()] = feature; - } else { - valid = false; - } - } else { - goog.asserts.assert(!(featureKey in this.undefIdIndex_), - 'Feature already added to the source'); - this.undefIdIndex_[featureKey] = feature; +goog.Promise.prototype.addStackTrace_ = function(err) { + if (goog.Promise.LONG_STACK_TRACES && goog.isString(err.stack)) { + // Extract the third line of the stack trace, which is the entry for the + // user function that called into Promise code. + var trace = err.stack.split('\n', 4)[3]; + var message = err.message; + + // Pad the message to align the traces. + message += Array(11 - message.length).join(' '); + this.stack_.push(message + trace); } - return valid; }; /** - * Add a batch of features to the source. - * @param {Array.<ol.Feature>} features Features to add. - * @api stable + * Adds extra stack trace information to an exception for the list of + * asynchronous {@code then} calls that have been run for this Promise. Stack + * trace information is recorded in {@see #addStackTrace_}, and appended to + * rethrown errors when {@code LONG_STACK_TRACES} is enabled. + * + * @param {*} err An unhandled exception captured during callback execution. + * @private */ -ol.source.Vector.prototype.addFeatures = function(features) { - this.addFeaturesInternal(features); - this.changed(); +goog.Promise.prototype.appendLongStack_ = function(err) { + if (goog.Promise.LONG_STACK_TRACES && + err && goog.isString(err.stack) && this.stack_.length) { + var longTrace = ['Promise trace:']; + + for (var promise = this; promise; promise = promise.parent_) { + for (var i = this.currentStep_; i >= 0; i--) { + longTrace.push(promise.stack_[i]); + } + longTrace.push('Value: ' + + '[' + (promise.state_ == goog.Promise.State_.REJECTED ? + 'REJECTED' : 'FULFILLED') + '] ' + + '<' + String(promise.result_) + '>'); + } + err.stack += '\n\n' + longTrace.join('\n'); + } }; /** - * Add features without firing a `change` event. - * @param {Array.<ol.Feature>} features Features. - * @protected + * Marks this rejected Promise as having being handled. Also marks any parent + * Promises in the rejected state as handled. The rejection handler will no + * longer be invoked for this Promise (if it has not been called already). + * + * @private */ -ol.source.Vector.prototype.addFeaturesInternal = function(features) { - var featureKey, i, length, feature; - - var extents = []; - var newFeatures = []; - var geometryFeatures = []; - - for (i = 0, length = features.length; i < length; i++) { - feature = features[i]; - featureKey = goog.getUid(feature).toString(); - if (this.addToIndex_(featureKey, feature)) { - newFeatures.push(feature); +goog.Promise.prototype.removeUnhandledRejection_ = function() { + if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { + for (var p = this; p && p.unhandledRejectionId_; p = p.parent_) { + goog.global.clearTimeout(p.unhandledRejectionId_); + p.unhandledRejectionId_ = 0; } - } - - for (i = 0, length = newFeatures.length; i < length; i++) { - feature = newFeatures[i]; - featureKey = goog.getUid(feature).toString(); - this.setupChangeEvents_(featureKey, feature); - - var geometry = feature.getGeometry(); - if (geometry) { - var extent = geometry.getExtent(); - extents.push(extent); - geometryFeatures.push(feature); - } else { - this.nullGeometryFeatures_[featureKey] = feature; + } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { + for (var p = this; p && p.hadUnhandledRejection_; p = p.parent_) { + p.hadUnhandledRejection_ = false; } } - if (this.featuresRtree_) { - this.featuresRtree_.load(extents, geometryFeatures); - } - - for (i = 0, length = newFeatures.length; i < length; i++) { - this.dispatchEvent(new ol.source.VectorEvent( - ol.source.VectorEventType.ADDFEATURE, newFeatures[i])); - } }; /** - * @param {!ol.Collection.<ol.Feature>} collection Collection. + * Marks this rejected Promise as unhandled. If no {@code onRejected} callback + * is called for this Promise before the {@code UNHANDLED_REJECTION_DELAY} + * expires, the reason will be passed to the unhandled rejection handler. The + * handler typically rethrows the rejection reason so that it becomes visible in + * the developer console. + * + * @param {!goog.Promise} promise The rejected Promise. + * @param {*} reason The Promise rejection reason. * @private */ -ol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) { - goog.asserts.assert(!this.featuresCollection_, - 'bindFeaturesCollection can only be called once'); - var modifyingCollection = false; - goog.events.listen(this, ol.source.VectorEventType.ADDFEATURE, - function(evt) { - if (!modifyingCollection) { - modifyingCollection = true; - collection.push(evt.feature); - modifyingCollection = false; - } - }); - goog.events.listen(this, ol.source.VectorEventType.REMOVEFEATURE, - function(evt) { - if (!modifyingCollection) { - modifyingCollection = true; - collection.remove(evt.feature); - modifyingCollection = false; - } - }); - goog.events.listen(collection, ol.CollectionEventType.ADD, - function(evt) { - if (!modifyingCollection) { - var feature = evt.element; - goog.asserts.assertInstanceof(feature, ol.Feature); - modifyingCollection = true; - this.addFeature(feature); - modifyingCollection = false; - } - }, false, this); - goog.events.listen(collection, ol.CollectionEventType.REMOVE, - function(evt) { - if (!modifyingCollection) { - var feature = evt.element; - goog.asserts.assertInstanceof(feature, ol.Feature); - modifyingCollection = true; - this.removeFeature(feature); - modifyingCollection = false; - } - }, false, this); - this.featuresCollection_ = collection; +goog.Promise.addUnhandledRejection_ = function(promise, reason) { + if (goog.Promise.UNHANDLED_REJECTION_DELAY > 0) { + promise.unhandledRejectionId_ = goog.global.setTimeout(function() { + promise.appendLongStack_(reason); + goog.Promise.handleRejection_.call(null, reason); + }, goog.Promise.UNHANDLED_REJECTION_DELAY); + + } else if (goog.Promise.UNHANDLED_REJECTION_DELAY == 0) { + promise.hadUnhandledRejection_ = true; + goog.async.run(function() { + if (promise.hadUnhandledRejection_) { + promise.appendLongStack_(reason); + goog.Promise.handleRejection_.call(null, reason); + } + }); + } }; /** - * Remove all features from the source. - * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events. - * @api stable + * A method that is invoked with the rejection reasons for Promises that are + * rejected but have no {@code onRejected} callbacks registered yet. + * @type {function(*)} + * @private */ -ol.source.Vector.prototype.clear = function(opt_fast) { - if (opt_fast) { - for (var featureId in this.featureChangeKeys_) { - var keys = this.featureChangeKeys_[featureId]; - keys.forEach(goog.events.unlistenByKey); - } - if (!this.featuresCollection_) { - this.featureChangeKeys_ = {}; - this.idIndex_ = {}; - this.undefIdIndex_ = {}; - } - } else { - var rmFeatureInternal = this.removeFeatureInternal; - if (this.featuresRtree_) { - this.featuresRtree_.forEach(rmFeatureInternal, this); - goog.object.forEach(this.nullGeometryFeatures_, rmFeatureInternal, this); - } - } - if (this.featuresCollection_) { - this.featuresCollection_.clear(); - } - goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_), - 'featureChangeKeys is an empty object now'); - goog.asserts.assert(goog.object.isEmpty(this.idIndex_), - 'idIndex is an empty object now'); - goog.asserts.assert(goog.object.isEmpty(this.undefIdIndex_), - 'undefIdIndex is an empty object now'); +goog.Promise.handleRejection_ = goog.async.throwException; - if (this.featuresRtree_) { - this.featuresRtree_.clear(); - } - this.loadedExtentsRtree_.clear(); - this.nullGeometryFeatures_ = {}; - var clearEvent = new ol.source.VectorEvent(ol.source.VectorEventType.CLEAR); - this.dispatchEvent(clearEvent); - this.changed(); +/** + * Sets a handler that will be called with reasons from unhandled rejected + * Promises. If the rejected Promise (or one of its descendants) has an + * {@code onRejected} callback registered, the rejection will be considered + * handled, and the rejection handler will not be called. + * + * By default, unhandled rejections are rethrown so that the error may be + * captured by the developer console or a {@code window.onerror} handler. + * + * @param {function(*)} handler A function that will be called with reasons from + * rejected Promises. Defaults to {@code goog.async.throwException}. + */ +goog.Promise.setUnhandledRejectionHandler = function(handler) { + goog.Promise.handleRejection_ = handler; }; + /** - * Iterate through all features on the source, calling the provided callback - * with each one. If the callback returns any "truthy" value, iteration will - * stop and the function will return the same value. + * Error used as a rejection reason for canceled Promises. * - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * on the source. Return a truthy value to stop iteration. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - * @api stable + * @param {string=} opt_message + * @constructor + * @extends {goog.debug.Error} + * @final */ -ol.source.Vector.prototype.forEachFeature = function(callback, opt_this) { - if (this.featuresRtree_) { - return this.featuresRtree_.forEach(callback, opt_this); - } else if (this.featuresCollection_) { - return this.featuresCollection_.forEach(callback, opt_this); - } +goog.Promise.CancellationError = function(opt_message) { + goog.Promise.CancellationError.base(this, 'constructor', opt_message); }; +goog.inherits(goog.Promise.CancellationError, goog.debug.Error); + + +/** @override */ +goog.Promise.CancellationError.prototype.name = 'cancel'; + /** - * Iterate through all features whose geometries contain the provided - * coordinate, calling the callback with each feature. If the callback returns - * a "truthy" value, iteration will stop and the function will return the same - * value. + * Internal implementation of the resolver interface. * - * @param {ol.Coordinate} coordinate Coordinate. - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * whose goemetry contains the provided coordinate. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S + * @param {!goog.Promise<TYPE>} promise + * @param {function((TYPE|goog.Promise<TYPE>|Thenable)=)} resolve + * @param {function(*=): void} reject + * @implements {goog.promise.Resolver<TYPE>} + * @final @struct + * @constructor + * @private + * @template TYPE */ -ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect = - function(coordinate, callback, opt_this) { - var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]]; - return this.forEachFeatureInExtent(extent, function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, 'feature geometry is defined and not null'); - if (geometry.containsCoordinate(coordinate)) { - return callback.call(opt_this, feature); - } else { - return undefined; - } - }); +goog.Promise.Resolver_ = function(promise, resolve, reject) { + /** @const */ + this.promise = promise; + + /** @const */ + this.resolve = resolve; + + /** @const */ + this.reject = reject; }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Iterate through all features whose bounding box intersects the provided - * extent (note that the feature's geometry may not intersect the extent), - * calling the callback with each feature. If the callback returns a "truthy" - * value, iteration will stop and the function will return the same value. - * - * If you are interested in features whose geometry intersects an extent, call - * the {@link ol.source.Vector#forEachFeatureIntersectingExtent - * source.forEachFeatureIntersectingExtent()} method instead. + * @fileoverview A timer class to which other classes and objects can + * listen on. This is only an abstraction above setInterval. * - * When `useSpatialIndex` is set to false, this method will loop through all - * features, equivalent to {@link ol.source.Vector#forEachFeature}. + * @see ../demos/timers.html + */ + +goog.provide('goog.Timer'); + +goog.require('goog.Promise'); +goog.require('goog.events.EventTarget'); + + + +/** + * Class for handling timing events. * - * @param {ol.Extent} extent Extent. - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * whose bounding box intersects the provided extent. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - * @api + * @param {number=} opt_interval Number of ms between ticks (Default: 1ms). + * @param {Object=} opt_timerObject An object that has setTimeout, setInterval, + * clearTimeout and clearInterval (eg Window). + * @constructor + * @extends {goog.events.EventTarget} */ -ol.source.Vector.prototype.forEachFeatureInExtent = - function(extent, callback, opt_this) { - if (this.featuresRtree_) { - return this.featuresRtree_.forEachInExtent(extent, callback, opt_this); - } else if (this.featuresCollection_) { - return this.featuresCollection_.forEach(callback, opt_this); - } +goog.Timer = function(opt_interval, opt_timerObject) { + goog.events.EventTarget.call(this); + + /** + * Number of ms between ticks + * @type {number} + * @private + */ + this.interval_ = opt_interval || 1; + + /** + * An object that implements setTimeout, setInterval, clearTimeout and + * clearInterval. We default to the window object. Changing this on + * goog.Timer.prototype changes the object for all timer instances which can + * be useful if your environment has some other implementation of timers than + * the window object. + * @type {Object} + * @private + */ + this.timerObject_ = opt_timerObject || goog.Timer.defaultTimerObject; + + /** + * Cached tick_ bound to the object for later use in the timer. + * @type {Function} + * @private + */ + this.boundTick_ = goog.bind(this.tick_, this); + + /** + * Firefox browser often fires the timer event sooner + * (sometimes MUCH sooner) than the requested timeout. So we + * compare the time to when the event was last fired, and + * reschedule if appropriate. See also goog.Timer.intervalScale + * @type {number} + * @private + */ + this.last_ = goog.now(); }; +goog.inherits(goog.Timer, goog.events.EventTarget); /** - * Iterate through all features whose geometry intersects the provided extent, - * calling the callback with each feature. If the callback returns a "truthy" - * value, iteration will stop and the function will return the same value. + * Maximum timeout value. * - * If you only want to test for bounding box intersection, call the - * {@link ol.source.Vector#forEachFeatureInExtent - * source.forEachFeatureInExtent()} method instead. + * Timeout values too big to fit into a signed 32-bit integer may cause + * overflow in FF, Safari, and Chrome, resulting in the timeout being + * scheduled immediately. It makes more sense simply not to schedule these + * timeouts, since 24.8 days is beyond a reasonable expectation for the + * browser to stay open. * - * @param {ol.Extent} extent Extent. - * @param {function(this: T, ol.Feature): S} callback Called with each feature - * whose geometry intersects the provided extent. - * @param {T=} opt_this The object to use as `this` in the callback. - * @return {S|undefined} The return value from the last call to the callback. - * @template T,S - * @api + * @type {number} + * @private */ -ol.source.Vector.prototype.forEachFeatureIntersectingExtent = - function(extent, callback, opt_this) { - return this.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - * @return {S|undefined} - * @template S - */ - function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, - 'feature geometry is defined and not null'); - if (geometry.intersectsExtent(extent)) { - var result = callback.call(opt_this, feature); - if (result) { - return result; - } - } - }); -}; +goog.Timer.MAX_TIMEOUT_ = 2147483647; /** - * Get the features collection associated with this source. Will be `null` - * unless the source was configured with `useSpatialIndex` set to `false`, or - * with an {@link ol.Collection} as `features`. - * @return {ol.Collection.<ol.Feature>} - * @api + * A timer ID that cannot be returned by any known implmentation of + * Window.setTimeout. Passing this value to window.clearTimeout should + * therefore be a no-op. + * + * @const {number} + * @private */ -ol.source.Vector.prototype.getFeaturesCollection = function() { - return this.featuresCollection_; -}; +goog.Timer.INVALID_TIMEOUT_ID_ = -1; /** - * Get all features on the source. - * @return {Array.<ol.Feature>} Features. - * @api stable + * Whether this timer is enabled + * @type {boolean} */ -ol.source.Vector.prototype.getFeatures = function() { - var features; - if (this.featuresCollection_) { - features = this.featuresCollection_.getArray(); - } else if (this.featuresRtree_) { - features = this.featuresRtree_.getAll(); - if (!goog.object.isEmpty(this.nullGeometryFeatures_)) { - goog.array.extend( - features, goog.object.getValues(this.nullGeometryFeatures_)); - } - } - goog.asserts.assert(features !== undefined, - 'Neither featuresRtree_ nor featuresCollection_ are available'); - return features; -}; +goog.Timer.prototype.enabled = false; /** - * Get all features whose geometry intersects the provided coordinate. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {Array.<ol.Feature>} Features. - * @api stable + * An object that implements setTimout, setInterval, clearTimeout and + * clearInterval. We default to the global object. Changing + * goog.Timer.defaultTimerObject changes the object for all timer instances + * which can be useful if your environment has some other implementation of + * timers you'd like to use. + * @type {Object} */ -ol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) { - var features = []; - this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) { - features.push(feature); - }); - return features; -}; +goog.Timer.defaultTimerObject = goog.global; /** - * Get all features in the provided extent. Note that this returns all features - * whose bounding boxes intersect the given extent (so it may include features - * whose geometries do not intersect the extent). - * - * This method is not available when the source is configured with - * `useSpatialIndex` set to `false`. - * @param {ol.Extent} extent Extent. - * @return {Array.<ol.Feature>} Features. - * @api + * A variable that controls the timer error correction. If the + * timer is called before the requested interval times + * intervalScale, which often happens on mozilla, the timer is + * rescheduled. See also this.last_ + * @type {number} */ -ol.source.Vector.prototype.getFeaturesInExtent = function(extent) { - goog.asserts.assert(this.featuresRtree_, - 'getFeaturesInExtent does not work when useSpatialIndex is set to false'); - return this.featuresRtree_.getInExtent(extent); -}; +goog.Timer.intervalScale = 0.8; /** - * Get the closest feature to the provided coordinate. - * - * This method is not available when the source is configured with - * `useSpatialIndex` set to `false`. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Feature} Closest feature. - * @api stable + * Variable for storing the result of setInterval + * @type {?number} + * @private */ -ol.source.Vector.prototype.getClosestFeatureToCoordinate = - function(coordinate) { - // Find the closest feature using branch and bound. We start searching an - // infinite extent, and find the distance from the first feature found. This - // becomes the closest feature. We then compute a smaller extent which any - // closer feature must intersect. We continue searching with this smaller - // extent, trying to find a closer feature. Every time we find a closer - // feature, we update the extent being searched so that any even closer - // feature must intersect it. We continue until we run out of features. - var x = coordinate[0]; - var y = coordinate[1]; - var closestFeature = null; - var closestPoint = [NaN, NaN]; - var minSquaredDistance = Infinity; - var extent = [-Infinity, -Infinity, Infinity, Infinity]; - goog.asserts.assert(this.featuresRtree_, - 'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' + - 'to false'); - this.featuresRtree_.forEachInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, - 'feature geometry is defined and not null'); - var previousMinSquaredDistance = minSquaredDistance; - minSquaredDistance = geometry.closestPointXY( - x, y, closestPoint, minSquaredDistance); - if (minSquaredDistance < previousMinSquaredDistance) { - closestFeature = feature; - // This is sneaky. Reduce the extent that it is currently being - // searched while the R-Tree traversal using this same extent object - // is still in progress. This is safe because the new extent is - // strictly contained by the old extent. - var minDistance = Math.sqrt(minSquaredDistance); - extent[0] = x - minDistance; - extent[1] = y - minDistance; - extent[2] = x + minDistance; - extent[3] = y + minDistance; - } - }); - return closestFeature; -}; +goog.Timer.prototype.timer_ = null; /** - * Get the extent of the features currently in the source. - * - * This method is not available when the source is configured with - * `useSpatialIndex` set to `false`. - * @return {!ol.Extent} Extent. - * @api stable + * Gets the interval of the timer. + * @return {number} interval Number of ms between ticks. */ -ol.source.Vector.prototype.getExtent = function() { - goog.asserts.assert(this.featuresRtree_, - 'getExtent does not work when useSpatialIndex is set to false'); - return this.featuresRtree_.getExtent(); +goog.Timer.prototype.getInterval = function() { + return this.interval_; }; /** - * Get a feature by its identifier (the value returned by feature.getId()). - * Note that the index treats string and numeric identifiers as the same. So - * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`. - * - * @param {string|number} id Feature identifier. - * @return {ol.Feature} The feature (or `null` if not found). - * @api stable + * Sets the interval of the timer. + * @param {number} interval Number of ms between ticks. */ -ol.source.Vector.prototype.getFeatureById = function(id) { - var feature = this.idIndex_[id.toString()]; - return feature !== undefined ? feature : null; +goog.Timer.prototype.setInterval = function(interval) { + this.interval_ = interval; + if (this.timer_ && this.enabled) { + // Stop and then start the timer to reset the interval. + this.stop(); + this.start(); + } else if (this.timer_) { + this.stop(); + } }; /** - * @param {goog.events.Event} event Event. + * Callback for the setTimeout used by the timer * @private */ -ol.source.Vector.prototype.handleFeatureChange_ = function(event) { - var feature = /** @type {ol.Feature} */ (event.target); - var featureKey = goog.getUid(feature).toString(); - var geometry = feature.getGeometry(); - if (!geometry) { - if (!(featureKey in this.nullGeometryFeatures_)) { - if (this.featuresRtree_) { - this.featuresRtree_.remove(feature); - } - this.nullGeometryFeatures_[featureKey] = feature; - } - } else { - var extent = geometry.getExtent(); - if (featureKey in this.nullGeometryFeatures_) { - delete this.nullGeometryFeatures_[featureKey]; - if (this.featuresRtree_) { - this.featuresRtree_.insert(extent, feature); - } - } else { - if (this.featuresRtree_) { - this.featuresRtree_.update(extent, feature); - } +goog.Timer.prototype.tick_ = function() { + if (this.enabled) { + var elapsed = goog.now() - this.last_; + if (elapsed > 0 && + elapsed < this.interval_ * goog.Timer.intervalScale) { + this.timer_ = this.timerObject_.setTimeout(this.boundTick_, + this.interval_ - elapsed); + return; } - } - var id = feature.getId(); - var removed; - if (id !== undefined) { - var sid = id.toString(); - if (featureKey in this.undefIdIndex_) { - delete this.undefIdIndex_[featureKey]; - this.idIndex_[sid] = feature; - } else { - if (this.idIndex_[sid] !== feature) { - removed = this.removeFromIdIndex_(feature); - goog.asserts.assert(removed, - 'Expected feature to be removed from index'); - this.idIndex_[sid] = feature; - } + + // Prevents setInterval from registering a duplicate timeout when called + // in the timer event handler. + if (this.timer_) { + this.timerObject_.clearTimeout(this.timer_); + this.timer_ = null; } - } else { - if (!(featureKey in this.undefIdIndex_)) { - removed = this.removeFromIdIndex_(feature); - goog.asserts.assert(removed, - 'Expected feature to be removed from index'); - this.undefIdIndex_[featureKey] = feature; - } else { - goog.asserts.assert(this.undefIdIndex_[featureKey] === feature, - 'feature keyed under %s in undefIdKeys', featureKey); + + this.dispatchTick(); + // The timer could be stopped in the timer event handler. + if (this.enabled) { + this.timer_ = this.timerObject_.setTimeout(this.boundTick_, + this.interval_); + this.last_ = goog.now(); } } - this.changed(); - this.dispatchEvent(new ol.source.VectorEvent( - ol.source.VectorEventType.CHANGEFEATURE, feature)); }; /** - * @return {boolean} Is empty. + * Dispatches the TICK event. This is its own method so subclasses can override. */ -ol.source.Vector.prototype.isEmpty = function() { - return this.featuresRtree_.isEmpty() && - goog.object.isEmpty(this.nullGeometryFeatures_); +goog.Timer.prototype.dispatchTick = function() { + this.dispatchEvent(goog.Timer.TICK); }; /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {ol.proj.Projection} projection Projection. + * Starts the timer. */ -ol.source.Vector.prototype.loadFeatures = function( - extent, resolution, projection) { - var loadedExtentsRtree = this.loadedExtentsRtree_; - var extentsToLoad = this.strategy_(extent, resolution); - var i, ii; - for (i = 0, ii = extentsToLoad.length; i < ii; ++i) { - var extentToLoad = extentsToLoad[i]; - var alreadyLoaded = loadedExtentsRtree.forEachInExtent(extentToLoad, - /** - * @param {{extent: ol.Extent}} object Object. - * @return {boolean} Contains. - */ - function(object) { - return ol.extent.containsExtent(object.extent, extentToLoad); - }); - if (!alreadyLoaded) { - this.loader_.call(this, extentToLoad, resolution, projection); - loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()}); - } +goog.Timer.prototype.start = function() { + this.enabled = true; + + // If there is no interval already registered, start it now + if (!this.timer_) { + // IMPORTANT! + // window.setInterval in FireFox has a bug - it fires based on + // absolute time, rather than on relative time. What this means + // is that if a computer is sleeping/hibernating for 24 hours + // and the timer interval was configured to fire every 1000ms, + // then after the PC wakes up the timer will fire, in rapid + // succession, 3600*24 times. + // This bug is described here and is already fixed, but it will + // take time to propagate, so for now I am switching this over + // to setTimeout logic. + // https://bugzilla.mozilla.org/show_bug.cgi?id=376643 + // + this.timer_ = this.timerObject_.setTimeout(this.boundTick_, + this.interval_); + this.last_ = goog.now(); } }; /** - * Remove a single feature from the source. If you want to remove all features - * at once, use the {@link ol.source.Vector#clear source.clear()} method - * instead. - * @param {ol.Feature} feature Feature to remove. - * @api stable + * Stops the timer. */ -ol.source.Vector.prototype.removeFeature = function(feature) { - var featureKey = goog.getUid(feature).toString(); - if (featureKey in this.nullGeometryFeatures_) { - delete this.nullGeometryFeatures_[featureKey]; - } else { - if (this.featuresRtree_) { - this.featuresRtree_.remove(feature); - } +goog.Timer.prototype.stop = function() { + this.enabled = false; + if (this.timer_) { + this.timerObject_.clearTimeout(this.timer_); + this.timer_ = null; } - this.removeFeatureInternal(feature); - this.changed(); }; -/** - * Remove feature without firing a `change` event. - * @param {ol.Feature} feature Feature. - * @protected - */ -ol.source.Vector.prototype.removeFeatureInternal = function(feature) { - var featureKey = goog.getUid(feature).toString(); - goog.asserts.assert(featureKey in this.featureChangeKeys_, - 'featureKey exists in featureChangeKeys'); - this.featureChangeKeys_[featureKey].forEach(goog.events.unlistenByKey); - delete this.featureChangeKeys_[featureKey]; - var id = feature.getId(); - if (id !== undefined) { - delete this.idIndex_[id.toString()]; - } else { - delete this.undefIdIndex_[featureKey]; - } - this.dispatchEvent(new ol.source.VectorEvent( - ol.source.VectorEventType.REMOVEFEATURE, feature)); +/** @override */ +goog.Timer.prototype.disposeInternal = function() { + goog.Timer.superClass_.disposeInternal.call(this); + this.stop(); + delete this.timerObject_; }; /** - * Remove a feature from the id index. Called internally when the feature id - * may have changed. - * @param {ol.Feature} feature The feature. - * @return {boolean} Removed the feature from the index. - * @private + * Constant for the timer's event type + * @type {string} */ -ol.source.Vector.prototype.removeFromIdIndex_ = function(feature) { - var removed = false; - for (var id in this.idIndex_) { - if (this.idIndex_[id] === feature) { - delete this.idIndex_[id]; - removed = true; - break; - } - } - return removed; -}; - +goog.Timer.TICK = 'tick'; /** - * @classdesc - * Events emitted by {@link ol.source.Vector} instances are instances of this - * type. + * Calls the given function once, after the optional pause. * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.VectorEvent} - * @param {string} type Type. - * @param {ol.Feature=} opt_feature Feature. + * The function is always called asynchronously, even if the delay is 0. This + * is a common trick to schedule a function to run after a batch of browser + * event processing. + * + * @param {function(this:SCOPE)|{handleEvent:function()}|null} listener Function + * or object that has a handleEvent method. + * @param {number=} opt_delay Milliseconds to wait; default is 0. + * @param {SCOPE=} opt_handler Object in whose scope to call the listener. + * @return {number} A handle to the timer ID. + * @template SCOPE */ -ol.source.VectorEvent = function(type, opt_feature) { +goog.Timer.callOnce = function(listener, opt_delay, opt_handler) { + if (goog.isFunction(listener)) { + if (opt_handler) { + listener = goog.bind(listener, opt_handler); + } + } else if (listener && typeof listener.handleEvent == 'function') { + // using typeof to prevent strict js warning + listener = goog.bind(listener.handleEvent, listener); + } else { + throw Error('Invalid listener argument'); + } - goog.base(this, type); + if (opt_delay > goog.Timer.MAX_TIMEOUT_) { + // Timeouts greater than MAX_INT return immediately due to integer + // overflow in many browsers. Since MAX_INT is 24.8 days, just don't + // schedule anything at all. + return goog.Timer.INVALID_TIMEOUT_ID_; + } else { + return goog.Timer.defaultTimerObject.setTimeout( + listener, opt_delay || 0); + } +}; - /** - * The feature being added or removed. - * @type {ol.Feature|undefined} - * @api stable - */ - this.feature = opt_feature; +/** + * Clears a timeout initiated by callOnce + * @param {?number} timerId a timer ID. + */ +goog.Timer.clear = function(timerId) { + goog.Timer.defaultTimerObject.clearTimeout(timerId); }; -goog.inherits(ol.source.VectorEvent, goog.events.Event); - -goog.provide('ol.source.ImageVector'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.vec.Mat4'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.vector'); -goog.require('ol.source.ImageCanvas'); -goog.require('ol.source.Vector'); -goog.require('ol.style.Style'); -goog.require('ol.vec.Mat4'); +/** + * @param {number} delay Milliseconds to wait. + * @param {(RESULT|goog.Thenable<RESULT>|Thenable)=} opt_result The value + * with which the promise will be resolved. + * @return {!goog.Promise<RESULT>} A promise that will be resolved after + * the specified delay, unless it is canceled first. + * @template RESULT + */ +goog.Timer.promise = function(delay, opt_result) { + var timerKey = null; + return new goog.Promise(function(resolve, reject) { + timerKey = goog.Timer.callOnce(function() { + resolve(opt_result); + }, delay); + if (timerKey == goog.Timer.INVALID_TIMEOUT_ID_) { + reject(new Error('Failed to schedule timer.')); + } + }).thenCatch(function(error) { + // Clear the timer. The most likely reason is "cancel" signal. + goog.Timer.clear(timerKey); + throw error; + }); +}; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @classdesc - * An image source whose images are canvas elements into which vector features - * read from a vector source (`ol.source.Vector`) are drawn. An - * `ol.source.ImageVector` object is to be used as the `source` of an image - * layer (`ol.layer.Image`). Image layers are rotated, scaled, and translated, - * as opposed to being re-rendered, during animations and interactions. So, like - * any other image layer, an image layer configured with an - * `ol.source.ImageVector` will exhibit this behaviour. This is in contrast to a - * vector layer, where vector features are re-drawn during animations and - * interactions. - * - * @constructor - * @extends {ol.source.ImageCanvas} - * @param {olx.source.ImageVectorOptions} options Options. - * @api + * @fileoverview JSON utility functions. + * @author arv@google.com (Erik Arvidsson) */ -ol.source.ImageVector = function(options) { - /** - * @private - * @type {ol.source.Vector} - */ - this.source_ = options.source; - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); +goog.provide('goog.json'); +goog.provide('goog.json.Replacer'); +goog.provide('goog.json.Reviver'); +goog.provide('goog.json.Serializer'); - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.canvasContext_ = ol.dom.createCanvasContext2D(); - /** - * @private - * @type {ol.Size} - */ - this.canvasSize_ = [0, 0]; +/** + * @define {boolean} If true, use the native JSON parsing API. + * NOTE(ruilopes): EXPERIMENTAL, handle with care. Setting this to true might + * break your code. The default {@code goog.json.parse} implementation is able + * to handle invalid JSON, such as JSPB. + */ +goog.define('goog.json.USE_NATIVE_JSON', false); - /** - * @private - * @type {ol.render.canvas.ReplayGroup} - */ - this.replayGroup_ = null; - goog.base(this, { - attributions: options.attributions, - canvasFunction: goog.bind(this.canvasFunctionInternal_, this), - logo: options.logo, - projection: options.projection, - ratio: options.ratio, - resolutions: options.resolutions, - state: this.source_.getState() - }); +/** + * Tests if a string is an invalid JSON string. This only ensures that we are + * not using any invalid characters + * @param {string} s The string to test. + * @return {boolean} True if the input is a valid JSON string. + */ +goog.json.isValid = function(s) { + // All empty whitespace is not valid. + if (/^\s*$/.test(s)) { + return false; + } - /** - * User provided style. - * @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * @private - */ - this.style_ = null; + // This is taken from http://www.json.org/json2.js which is released to the + // public domain. + // Changes: We dissallow \u2028 Line separator and \u2029 Paragraph separator + // inside strings. We also treat \u2028 and \u2029 as whitespace which they + // are in the RFC but IE and Safari does not match \s to these so we need to + // include them in the reg exps in all places where whitespace is allowed. + // We allowed \x7f inside strings because some tools don't escape it, + // e.g. http://www.json.org/java/org/json/JSONObject.java - /** - * Style function for use within the library. - * @type {ol.style.StyleFunction|undefined} - * @private - */ - this.styleFunction_ = undefined; + // Parsing happens in three stages. In the first stage, we run the text + // against regular expressions that look for non-JSON patterns. We are + // especially concerned with '()' and 'new' because they can cause invocation, + // and '=' because it can cause mutation. But just to be safe, we want to + // reject all unexpected forms. - this.setStyle(options.style); + // We split the first stage into 4 regexp operations in order to work around + // crippling inefficiencies in IE's and Safari's regexp engines. First we + // replace all backslash pairs with '@' (a non-JSON character). Second, we + // replace all simple value tokens with ']' characters. Third, we delete all + // open brackets that follow a colon or comma or that begin the text. Finally, + // we look to see that the remaining characters are only whitespace or ']' or + // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - goog.events.listen(this.source_, goog.events.EventType.CHANGE, - this.handleSourceChange_, undefined, this); + // Don't make these static since they have the global flag. + var backslashesRe = /\\["\\\/bfnrtu]/g; + var simpleValuesRe = + /"[^"\\\n\r\u2028\u2029\x00-\x08\x0a-\x1f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; + var openBracketsRe = /(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g; + var remainderRe = /^[\],:{}\s\u2028\u2029]*$/; + return remainderRe.test(s.replace(backslashesRe, '@'). + replace(simpleValuesRe, ']'). + replace(openBracketsRe, '')); }; -goog.inherits(ol.source.ImageVector, ol.source.ImageCanvas); /** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Size} size Size. - * @param {ol.proj.Projection} projection Projection; - * @return {HTMLCanvasElement} Canvas element. - * @private - */ -ol.source.ImageVector.prototype.canvasFunctionInternal_ = - function(extent, resolution, pixelRatio, size, projection) { - - var replayGroup = new ol.render.canvas.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, - resolution); + * Parses a JSON string and returns the result. This throws an exception if + * the string is an invalid JSON string. + * + * Note that this is very slow on large strings. If you trust the source of + * the string then you should use unsafeParse instead. + * + * @param {*} s The JSON string to parse. + * @throws Error if s is invalid JSON. + * @return {Object} The object generated from the JSON string, or null. + */ +goog.json.parse = goog.json.USE_NATIVE_JSON ? + /** @type {function(*):Object} */ (goog.global['JSON']['parse']) : + function(s) { + var o = String(s); + if (goog.json.isValid(o)) { + /** @preserveTry */ + try { + return /** @type {Object} */ (eval('(' + o + ')')); + } catch (ex) { + } + } + throw Error('Invalid JSON string: ' + o); + }; - this.source_.loadFeatures(extent, resolution, projection); - var loading = false; - this.source_.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - loading = loading || - this.renderFeature_(feature, resolution, pixelRatio, replayGroup); - }, this); - replayGroup.finish(); +/** + * Parses a JSON string and returns the result. This uses eval so it is open + * to security issues and it should only be used if you trust the source. + * + * @param {string} s The JSON string to parse. + * @return {Object} The object generated from the JSON string. + */ +goog.json.unsafeParse = goog.json.USE_NATIVE_JSON ? + /** @type {function(string):Object} */ (goog.global['JSON']['parse']) : + function(s) { + return /** @type {Object} */ (eval('(' + s + ')')); + }; - if (loading) { - return null; - } - if (this.canvasSize_[0] != size[0] || this.canvasSize_[1] != size[1]) { - this.canvasContext_.canvas.width = size[0]; - this.canvasContext_.canvas.height = size[1]; - this.canvasSize_[0] = size[0]; - this.canvasSize_[1] = size[1]; - } else { - this.canvasContext_.clearRect(0, 0, size[0], size[1]); - } +/** + * JSON replacer, as defined in Section 15.12.3 of the ES5 spec. + * @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3 + * + * TODO(nicksantos): Array should also be a valid replacer. + * + * @typedef {function(this:Object, string, *): *} + */ +goog.json.Replacer; - var transform = this.getTransform_(ol.extent.getCenter(extent), - resolution, pixelRatio, size); - replayGroup.replay(this.canvasContext_, pixelRatio, transform, 0, {}); - this.replayGroup_ = replayGroup; +/** + * JSON reviver, as defined in Section 15.12.2 of the ES5 spec. + * @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3 + * + * @typedef {function(this:Object, string, *): *} + */ +goog.json.Reviver; + + +/** + * Serializes an object or a value to a JSON string. + * + * @param {*} object The object to serialize. + * @param {?goog.json.Replacer=} opt_replacer A replacer function + * called for each (key, value) pair that determines how the value + * should be serialized. By defult, this just returns the value + * and allows default serialization to kick in. + * @throws Error if there are loops in the object graph. + * @return {string} A JSON string representation of the input. + */ +goog.json.serialize = goog.json.USE_NATIVE_JSON ? + /** @type {function(*, ?goog.json.Replacer=):string} */ + (goog.global['JSON']['stringify']) : + function(object, opt_replacer) { + // NOTE(nicksantos): Currently, we never use JSON.stringify. + // + // The last time I evaluated this, JSON.stringify had subtle bugs and + // behavior differences on all browsers, and the performance win was not + // large enough to justify all the issues. This may change in the future + // as browser implementations get better. + // + // assertSerialize in json_test contains if branches for the cases + // that fail. + return new goog.json.Serializer(opt_replacer).serialize(object); + }; - return this.canvasContext_.canvas; -}; /** - * @inheritDoc + * Class that is used to serialize JSON objects to a string. + * @param {?goog.json.Replacer=} opt_replacer Replacer. + * @constructor */ -ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function( - coordinate, resolution, rotation, skippedFeatureUids, callback) { - if (!this.replayGroup_) { - return undefined; - } else { - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate( - coordinate, resolution, 0, skippedFeatureUids, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'passed a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback(feature); - } - }); - } +goog.json.Serializer = function(opt_replacer) { + /** + * @type {goog.json.Replacer|null|undefined} + * @private + */ + this.replacer_ = opt_replacer; }; /** - * Get a reference to the wrapped source. - * @return {ol.source.Vector} Source. - * @api + * Serializes an object or a value to a JSON string. + * + * @param {*} object The object to serialize. + * @throws Error if there are loops in the object graph. + * @return {string} A JSON string representation of the input. */ -ol.source.ImageVector.prototype.getSource = function() { - return this.source_; +goog.json.Serializer.prototype.serialize = function(object) { + var sb = []; + this.serializeInternal(object, sb); + return sb.join(''); }; /** - * Get the style for features. This returns whatever was passed to the `style` - * option at construction or to the `setStyle` method. - * @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} - * Layer style. - * @api stable + * Serializes a generic value to a JSON string + * @protected + * @param {*} object The object to serialize. + * @param {Array<string>} sb Array used as a string builder. + * @throws Error if there are loops in the object graph. */ -ol.source.ImageVector.prototype.getStyle = function() { - return this.style_; +goog.json.Serializer.prototype.serializeInternal = function(object, sb) { + if (object == null) { + // undefined == null so this branch covers undefined as well as null + sb.push('null'); + return; + } + + if (typeof object == 'object') { + if (goog.isArray(object)) { + this.serializeArray(object, sb); + return; + } else if (object instanceof String || + object instanceof Number || + object instanceof Boolean) { + object = object.valueOf(); + // Fall through to switch below. + } else { + this.serializeObject_(/** @type {Object} */ (object), sb); + return; + } + } + + switch (typeof object) { + case 'string': + this.serializeString_(object, sb); + break; + case 'number': + this.serializeNumber_(object, sb); + break; + case 'boolean': + sb.push(object); + break; + case 'function': + sb.push('null'); + break; + default: + throw Error('Unknown type: ' + typeof object); + } }; /** - * Get the style function. - * @return {ol.style.StyleFunction|undefined} Layer style function. - * @api stable + * Character mappings used internally for goog.string.quote + * @private + * @type {!Object} */ -ol.source.ImageVector.prototype.getStyleFunction = function() { - return this.styleFunction_; +goog.json.Serializer.charToJsonCharCache_ = { + '\"': '\\"', + '\\': '\\\\', + '/': '\\/', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + + '\x0B': '\\u000b' // '\v' is not supported in JScript }; /** - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Size} size Size. - * @return {!goog.vec.Mat4.Number} Transform. + * Regular expression used to match characters that need to be replaced. + * The S60 browser has a bug where unicode characters are not matched by + * regular expressions. The condition below detects such behaviour and + * adjusts the regular expression accordingly. * @private + * @type {!RegExp} */ -ol.source.ImageVector.prototype.getTransform_ = - function(center, resolution, pixelRatio, size) { - return ol.vec.Mat4.makeTransform2D(this.transform_, - size[0] / 2, size[1] / 2, - pixelRatio / resolution, -pixelRatio / resolution, - 0, - -center[0], -center[1]); -}; +goog.json.Serializer.charsToReplace_ = /\uffff/.test('\uffff') ? + /[\\\"\x00-\x1f\x7f-\uffff]/g : /[\\\"\x00-\x1f\x7f-\xff]/g; /** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. + * Serializes a string to a JSON string * @private + * @param {string} s The string to serialize. + * @param {Array<string>} sb Array used as a string builder. */ -ol.source.ImageVector.prototype.handleImageChange_ = - function(event) { - this.changed(); +goog.json.Serializer.prototype.serializeString_ = function(s, sb) { + // The official JSON implementation does not work with international + // characters. + sb.push('"', s.replace(goog.json.Serializer.charsToReplace_, function(c) { + // caching the result improves performance by a factor 2-3 + var rv = goog.json.Serializer.charToJsonCharCache_[c]; + if (!rv) { + rv = '\\u' + (c.charCodeAt(0) | 0x10000).toString(16).substr(1); + goog.json.Serializer.charToJsonCharCache_[c] = rv; + } + return rv; + }), '"'); }; /** + * Serializes a number to a JSON string * @private + * @param {number} n The number to serialize. + * @param {Array<string>} sb Array used as a string builder. */ -ol.source.ImageVector.prototype.handleSourceChange_ = function() { - // setState will trigger a CHANGE event, so we always rely - // change events by calling setState. - this.setState(this.source_.getState()); +goog.json.Serializer.prototype.serializeNumber_ = function(n, sb) { + sb.push(isFinite(n) && !isNaN(n) ? n : 'null'); }; /** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - * @private + * Serializes an array to a JSON string + * @param {Array<string>} arr The array to serialize. + * @param {Array<string>} sb Array used as a string builder. + * @protected */ -ol.source.ImageVector.prototype.renderFeature_ = - function(feature, resolution, pixelRatio, replayGroup) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else if (this.styleFunction_) { - styles = this.styleFunction_(feature, resolution); - } - if (!styles) { - return false; - } - var i, ii, loading = false; - for (i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleImageChange_, this) || loading; +goog.json.Serializer.prototype.serializeArray = function(arr, sb) { + var l = arr.length; + sb.push('['); + var sep = ''; + for (var i = 0; i < l; i++) { + sb.push(sep); + + var value = arr[i]; + this.serializeInternal( + this.replacer_ ? this.replacer_.call(arr, String(i), value) : value, + sb); + + sep = ','; } - return loading; + sb.push(']'); }; /** - * Set the style for features. This can be a single style object, an array - * of styles, or a function that takes a feature and resolution and returns - * an array of styles. If it is `undefined` the default style is used. If - * it is `null` the layer has no style (a `null` style), so only features - * that have their own styles will be rendered in the layer. See - * {@link ol.style} for information on the default style. - * @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined} - * style Layer style. - * @api stable + * Serializes an object to a JSON string + * @private + * @param {Object} obj The object to serialize. + * @param {Array<string>} sb Array used as a string builder. */ -ol.source.ImageVector.prototype.setStyle = function(style) { - this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction; - this.styleFunction_ = !style ? - undefined : ol.style.createStyleFunction(this.style_); - this.changed(); +goog.json.Serializer.prototype.serializeObject_ = function(obj, sb) { + sb.push('{'); + var sep = ''; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + var value = obj[key]; + // Skip functions. + if (typeof value != 'function') { + sb.push(sep); + this.serializeString_(key, sb); + sb.push(':'); + + this.serializeInternal( + this.replacer_ ? this.replacer_.call(obj, key, value) : value, + sb); + + sep = ','; + } + } + } + sb.push('}'); }; -goog.provide('ol.renderer.canvas.ImageLayer'); +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ImageBase'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.proj'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.source.ImageVector'); -goog.require('ol.vec.Mat4'); +/** + * @fileoverview Error codes shared between goog.net.IframeIo and + * goog.net.XhrIo. + */ +goog.provide('goog.net.ErrorCode'); /** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.Image} imageLayer Single image layer. + * Error codes + * @enum {number} */ -ol.renderer.canvas.ImageLayer = function(imageLayer) { +goog.net.ErrorCode = { - goog.base(this, imageLayer); + /** + * There is no error condition. + */ + NO_ERROR: 0, /** - * @private - * @type {?ol.ImageBase} + * The most common error from iframeio, unfortunately, is that the browser + * responded with an error page that is classed as a different domain. The + * situations, are when a browser error page is shown -- 404, access denied, + * DNS failure, connection reset etc.) + * */ - this.image_ = null; + ACCESS_DENIED: 1, /** - * @private - * @type {!goog.vec.Mat4.Number} + * Currently the only case where file not found will be caused is when the + * code is running on the local file system and a non-IE browser makes a + * request to a file that doesn't exist. */ - this.imageTransform_ = goog.vec.Mat4.createNumber(); + FILE_NOT_FOUND: 2, /** - * @private - * @type {?goog.vec.Mat4.Number} + * If Firefox shows a browser error page, such as a connection reset by + * server or access denied, then it will fail silently without the error or + * load handlers firing. */ - this.imageTransformInv_ = null; + FF_SILENT_ERROR: 3, /** - * @private - * @type {CanvasRenderingContext2D} + * Custom error provided by the client through the error check hook. */ - this.hitCanvasContext_ = null; + CUSTOM_ERROR: 4, -}; -goog.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.Layer); + /** + * Exception was thrown while processing the request. + */ + EXCEPTION: 5, + /** + * The Http response returned a non-successful http status code. + */ + HTTP_ERROR: 6, -/** - * @inheritDoc - */ -ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var layer = this.getLayer(); - var source = layer.getSource(); - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var skippedFeatureUids = frameState.skippedFeatureUids; - return source.forEachFeatureAtCoordinate( - coordinate, resolution, rotation, skippedFeatureUids, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - return callback.call(thisArg, feature, layer); - }); + /** + * The request was aborted. + */ + ABORT: 7, + + /** + * The request timed out. + */ + TIMEOUT: 8, + + /** + * The resource is not available offline. + */ + OFFLINE: 9 }; /** - * @inheritDoc + * Returns a friendly error message for an error code. These messages are for + * debugging and are not localized. + * @param {goog.net.ErrorCode} errorCode An error code. + * @return {string} A message for debugging. */ -ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.getImage()) { - return undefined; - } +goog.net.ErrorCode.getDebugMessage = function(errorCode) { + switch (errorCode) { + case goog.net.ErrorCode.NO_ERROR: + return 'No Error'; - if (this.getLayer().getSource() instanceof ol.source.ImageVector) { - // for ImageVector sources use the original hit-detection logic, - // so that for example also transparent polygons are detected - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); + case goog.net.ErrorCode.ACCESS_DENIED: + return 'Access denied to content document'; - if (hasFeature) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } else { - // for all other image sources directly check the image - if (!this.imageTransformInv_) { - this.imageTransformInv_ = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); - } + case goog.net.ErrorCode.FILE_NOT_FOUND: + return 'File not found'; - var pixelOnCanvas = - this.getPixelOnCanvas(pixel, this.imageTransformInv_); + case goog.net.ErrorCode.FF_SILENT_ERROR: + return 'Firefox silently errored'; - if (!this.hitCanvasContext_) { - this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); - } + case goog.net.ErrorCode.CUSTOM_ERROR: + return 'Application custom error'; - this.hitCanvasContext_.clearRect(0, 0, 1, 1); - this.hitCanvasContext_.drawImage( - this.getImage(), pixelOnCanvas[0], pixelOnCanvas[1], 1, 1, 0, 0, 1, 1); + case goog.net.ErrorCode.EXCEPTION: + return 'An exception occurred'; - var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } + case goog.net.ErrorCode.HTTP_ERROR: + return 'Http response at 400 or 500 level'; + + case goog.net.ErrorCode.ABORT: + return 'Request was aborted'; + + case goog.net.ErrorCode.TIMEOUT: + return 'Request timed out'; + + case goog.net.ErrorCode.OFFLINE: + return 'The resource is not available offline'; + + default: + return 'Unrecognized error code'; } }; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @inheritDoc + * @fileoverview Constants for HTTP status codes. */ -ol.renderer.canvas.ImageLayer.prototype.getImage = function() { - return !this.image_ ? null : this.image_.getImage(); -}; + +goog.provide('goog.net.HttpStatus'); /** - * @inheritDoc + * HTTP Status Codes defined in RFC 2616 and RFC 6585. + * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + * @see http://tools.ietf.org/html/rfc6585 + * @enum {number} */ -ol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() { - return this.imageTransform_; +goog.net.HttpStatus = { + // Informational 1xx + CONTINUE: 100, + SWITCHING_PROTOCOLS: 101, + + // Successful 2xx + OK: 200, + CREATED: 201, + ACCEPTED: 202, + NON_AUTHORITATIVE_INFORMATION: 203, + NO_CONTENT: 204, + RESET_CONTENT: 205, + PARTIAL_CONTENT: 206, + + // Redirection 3xx + MULTIPLE_CHOICES: 300, + MOVED_PERMANENTLY: 301, + FOUND: 302, + SEE_OTHER: 303, + NOT_MODIFIED: 304, + USE_PROXY: 305, + TEMPORARY_REDIRECT: 307, + + // Client Error 4xx + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + PAYMENT_REQUIRED: 402, + FORBIDDEN: 403, + NOT_FOUND: 404, + METHOD_NOT_ALLOWED: 405, + NOT_ACCEPTABLE: 406, + PROXY_AUTHENTICATION_REQUIRED: 407, + REQUEST_TIMEOUT: 408, + CONFLICT: 409, + GONE: 410, + LENGTH_REQUIRED: 411, + PRECONDITION_FAILED: 412, + REQUEST_ENTITY_TOO_LARGE: 413, + REQUEST_URI_TOO_LONG: 414, + UNSUPPORTED_MEDIA_TYPE: 415, + REQUEST_RANGE_NOT_SATISFIABLE: 416, + EXPECTATION_FAILED: 417, + PRECONDITION_REQUIRED: 428, + TOO_MANY_REQUESTS: 429, + REQUEST_HEADER_FIELDS_TOO_LARGE: 431, + + // Server Error 5xx + INTERNAL_SERVER_ERROR: 500, + NOT_IMPLEMENTED: 501, + BAD_GATEWAY: 502, + SERVICE_UNAVAILABLE: 503, + GATEWAY_TIMEOUT: 504, + HTTP_VERSION_NOT_SUPPORTED: 505, + NETWORK_AUTHENTICATION_REQUIRED: 511, + + /* + * IE returns this code for 204 due to its use of URLMon, which returns this + * code for 'Operation Aborted'. The status text is 'Unknown', the response + * headers are ''. Known to occur on IE 6 on XP through IE9 on Win7. + */ + QUIRK_IE_NO_CONTENT: 1223 }; /** - * @inheritDoc + * Returns whether the given status should be considered successful. + * + * Successful codes are OK (200), CREATED (201), ACCEPTED (202), + * NO CONTENT (204), PARTIAL CONTENT (206), NOT MODIFIED (304), + * and IE's no content code (1223). + * + * @param {number} status The status code to test. + * @return {boolean} Whether the status code should be considered successful. */ -ol.renderer.canvas.ImageLayer.prototype.prepareFrame = - function(frameState, layerState) { +goog.net.HttpStatus.isSuccess = function(status) { + switch (status) { + case goog.net.HttpStatus.OK: + case goog.net.HttpStatus.CREATED: + case goog.net.HttpStatus.ACCEPTED: + case goog.net.HttpStatus.NO_CONTENT: + case goog.net.HttpStatus.PARTIAL_CONTENT: + case goog.net.HttpStatus.NOT_MODIFIED: + case goog.net.HttpStatus.QUIRK_IE_NO_CONTENT: + return true; - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewResolution = viewState.resolution; - var viewRotation = viewState.rotation; + default: + return false; + } +}; - var image; - var imageLayer = this.getLayer(); - goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, - 'layer is an instance of ol.layer.Image'); - var imageSource = imageLayer.getSource(); +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - var hints = frameState.viewHints; +goog.provide('goog.net.XhrLike'); - var renderedExtent = frameState.extent; - if (layerState.extent !== undefined) { - renderedExtent = ol.extent.getIntersection( - renderedExtent, layerState.extent); - } - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && - !ol.extent.isEmpty(renderedExtent)) { - var projection = viewState.projection; - if (!ol.ENABLE_RASTER_REPROJECTION) { - var sourceProjection = imageSource.getProjection(); - if (sourceProjection) { - goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), - 'projection and sourceProjection are equivalent'); - projection = sourceProjection; - } - } - image = imageSource.getImage( - renderedExtent, viewResolution, pixelRatio, projection); - if (image) { - var loaded = this.loadImage(image); - if (loaded) { - this.image_ = image; - } - } - } - if (this.image_) { - image = this.image_; - var imageExtent = image.getExtent(); - var imageResolution = image.getResolution(); - var imagePixelRatio = image.getPixelRatio(); - var scale = pixelRatio * imageResolution / - (viewResolution * imagePixelRatio); - ol.vec.Mat4.makeTransform2D(this.imageTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - scale, scale, - viewRotation, - imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution, - imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution); - this.imageTransformInv_ = null; - this.updateAttributions(frameState.attributions, image.getAttributions()); - this.updateLogos(frameState, imageSource); - } +/** + * Interface for the common parts of XMLHttpRequest. + * + * Mostly copied from externs/w3c_xml.js. + * + * @interface + * @see http://www.w3.org/TR/XMLHttpRequest/ + */ +goog.net.XhrLike = function() {}; - return true; -}; -// FIXME find correct globalCompositeOperation -// FIXME optimize :-) +/** + * Typedef that refers to either native or custom-implemented XHR objects. + * @typedef {!goog.net.XhrLike|!XMLHttpRequest} + */ +goog.net.XhrLike.OrNative; -goog.provide('ol.renderer.canvas.TileLayer'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Size'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Tile'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); +/** + * @type {function()|null|undefined} + * @see http://www.w3.org/TR/XMLHttpRequest/#handler-xhr-onreadystatechange + */ +goog.net.XhrLike.prototype.onreadystatechange; +/** + * @type {string} + * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute + */ +goog.net.XhrLike.prototype.responseText; + /** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.Tile} tileLayer Tile layer. + * @type {Document} + * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsexml-attribute */ -ol.renderer.canvas.TileLayer = function(tileLayer) { +goog.net.XhrLike.prototype.responseXML; - goog.base(this, tileLayer); - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; +/** + * @type {number} + * @see http://www.w3.org/TR/XMLHttpRequest/#readystate + */ +goog.net.XhrLike.prototype.readyState; - /** - * @private - * @type {ol.Size} - */ - this.canvasSize_ = null; - /** - * @private - * @type {boolean} - */ - this.canvasTooBig_ = false; +/** + * @type {number} + * @see http://www.w3.org/TR/XMLHttpRequest/#status + */ +goog.net.XhrLike.prototype.status; - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = null; - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.imageTransform_ = goog.vec.Mat4.createNumber(); +/** + * @type {string} + * @see http://www.w3.org/TR/XMLHttpRequest/#statustext + */ +goog.net.XhrLike.prototype.statusText; - /** - * @private - * @type {?goog.vec.Mat4.Number} - */ - this.imageTransformInv_ = null; - /** - * @private - * @type {number} - */ - this.renderedCanvasZ_ = NaN; +/** + * @param {string} method + * @param {string} url + * @param {?boolean=} opt_async + * @param {?string=} opt_user + * @param {?string=} opt_password + * @see http://www.w3.org/TR/XMLHttpRequest/#the-open()-method + */ +goog.net.XhrLike.prototype.open = function(method, url, opt_async, opt_user, + opt_password) {}; - /** - * @private - * @type {number} - */ - this.renderedTileWidth_ = NaN; - /** - * @private - * @type {number} - */ - this.renderedTileHeight_ = NaN; +/** + * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} opt_data + * @see http://www.w3.org/TR/XMLHttpRequest/#the-send()-method + */ +goog.net.XhrLike.prototype.send = function(opt_data) {}; - /** - * @private - * @type {ol.TileRange} - */ - this.renderedCanvasTileRange_ = null; - /** - * @private - * @type {Array.<ol.Tile|undefined>} - */ - this.renderedTiles_ = null; +/** + * @see http://www.w3.org/TR/XMLHttpRequest/#the-abort()-method + */ +goog.net.XhrLike.prototype.abort = function() {}; - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; -}; -goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); +/** + * @param {string} header + * @param {string} value + * @see http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method + */ +goog.net.XhrLike.prototype.setRequestHeader = function(header, value) {}; /** - * @inheritDoc + * @param {string} header + * @return {string} + * @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method */ -ol.renderer.canvas.TileLayer.prototype.getImage = function() { - return this.canvas_; -}; +goog.net.XhrLike.prototype.getResponseHeader = function(header) {}; /** - * @inheritDoc + * @return {string} + * @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method */ -ol.renderer.canvas.TileLayer.prototype.getImageTransform = function() { - return this.imageTransform_; -}; +goog.net.XhrLike.prototype.getAllResponseHeaders = function() {}; +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @inheritDoc + * @fileoverview Interface for a factory for creating XMLHttpRequest objects + * and metadata about them. + * @author dbk@google.com (David Barrett-Kahn) */ -ol.renderer.canvas.TileLayer.prototype.prepareFrame = - function(frameState, layerState) { - // - // Warning! You're entering a dangerous zone! - // - // The canvas tile layer renderering is highly optimized, hence - // the complexity of this function. For best performance we try - // to minimize the number of pixels to update on the canvas. This - // includes: - // - // - Only drawing pixels that will be visible. - // - Not re-drawing pixels/tiles that are already correct. - // - Minimizing calls to clearRect. - // - Never shrink the canvas. Just make it bigger when necessary. - // Re-sizing the canvas also clears it, which further means - // re-creating it (expensive). - // - // The various steps performed by this functions: - // - // - Create a canvas element if none has been created yet. - // - // - Make the canvas bigger if it's too small. Note that we never shrink - // the canvas, we just make it bigger when necessary, when rotating for - // example. Note also that the canvas always contains a whole number - // of tiles. - // - // - Invalidate the canvas tile range (renderedCanvasTileRange_ = null) - // if (1) the canvas has been enlarged, or (2) the zoom level changes, - // or (3) the canvas tile range doesn't contain the required tile - // range. This canvas tile range invalidation thing is related to - // an optimization where we attempt to redraw as few pixels as - // possible on each prepareFrame call. - // - // - If the canvas tile range has been invalidated we reset - // renderedCanvasTileRange_ and reset the renderedTiles_ array. - // The renderedTiles_ array is the structure used to determine - // the canvas pixels that need not be redrawn from one prepareFrame - // call to another. It records while tile has been rendered at - // which position in the canvas. - // - // - We then determine the tiles to draw on the canvas. Tiles for - // the target resolution may not be loaded yet. In that case we - // use low-resolution/interim tiles if loaded already. And, if - // for a non-yet-loaded tile we haven't found a corresponding - // low-resolution tile we indicate that the pixels for that - // tile must be cleared on the canvas. Note: determining the - // interim tiles is based on tile extents instead of tile - // coords, this is to be able to handler irregular tile grids. - // - // - We're now ready to render. We start by calling clearRect - // for the tiles that aren't loaded yet and are not fully covered - // by a low-resolution tile (if they're loaded, we'll draw them; - // if they're fully covered by a low-resolution tile then there's - // no need to clear). We then render the tiles "back to front", - // i.e. starting with the low-resolution tiles. - // - // - After rendering some bookkeeping is performed (updateUsedTiles, - // etc.). manageTilePyramid is what enqueue tiles in the tile - // queue for loading. - // - // - The last step involves updating the image transform matrix, - // which will be used by the map renderer for the final - // composition and positioning. - // +goog.provide('goog.net.XmlHttpFactory'); - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var projection = viewState.projection; +/** @suppress {extraRequire} Typedef. */ +goog.require('goog.net.XhrLike'); - var tileLayer = this.getLayer(); - goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, - 'layer is an instance of ol.layer.Tile'); - var tileSource = tileLayer.getSource(); - var tileGrid = tileSource.getTileGridForProjection(projection); - var tileGutter = tileSource.getGutter(); - var z = tileGrid.getZForResolution(viewState.resolution); - var tilePixelSize = - tileSource.getTilePixelSize(z, frameState.pixelRatio, projection); - var tilePixelRatio = tilePixelSize[0] / - ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; - var tileResolution = tileGrid.getResolution(z); - var tilePixelResolution = tileResolution / tilePixelRatio; - var center = viewState.center; - var extent; - if (tileResolution == viewState.resolution) { - center = this.snapCenterToPixel(center, tileResolution, frameState.size); - extent = ol.extent.getForViewAndSize( - center, tileResolution, viewState.rotation, frameState.size); - } else { - extent = frameState.extent; - } - if (layerState.extent !== undefined) { - extent = ol.extent.getIntersection(extent, layerState.extent); - } - if (ol.extent.isEmpty(extent)) { - // Return false to prevent the rendering of the layer. - return false; - } - var tileRange = tileGrid.getTileRangeForExtentAndResolution( - extent, tileResolution); +/** + * Abstract base class for an XmlHttpRequest factory. + * @constructor + */ +goog.net.XmlHttpFactory = function() { +}; - var canvasWidth = tilePixelSize[0] * tileRange.getWidth(); - var canvasHeight = tilePixelSize[1] * tileRange.getHeight(); - var canvas, context; - if (!this.canvas_) { - goog.asserts.assert(!this.canvasSize_, - 'canvasSize is null (because canvas is null)'); - goog.asserts.assert(!this.context_, - 'context is null (because canvas is null)'); - goog.asserts.assert(!this.renderedCanvasTileRange_, - 'renderedCanvasTileRange is null (because canvas is null)'); - context = ol.dom.createCanvasContext2D(canvasWidth, canvasHeight); - this.canvas_ = context.canvas; - this.canvasSize_ = [canvasWidth, canvasHeight]; - this.context_ = context; - this.canvasTooBig_ = - !ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_); - } else { - goog.asserts.assert(this.canvasSize_, - 'non-null canvasSize (because canvas is not null)'); - goog.asserts.assert(this.context_, - 'non-null context (because canvas is not null)'); - canvas = this.canvas_; - context = this.context_; - if (this.canvasSize_[0] < canvasWidth || - this.canvasSize_[1] < canvasHeight || - this.renderedTileWidth_ !== tilePixelSize[0] || - this.renderedTileHeight_ !== tilePixelSize[1] || - (this.canvasTooBig_ && (this.canvasSize_[0] > canvasWidth || - this.canvasSize_[1] > canvasHeight))) { - // Canvas is too small or tileSize has changed, resize it. - // We never shrink the canvas, unless - // we know that the current canvas size exceeds the maximum size - canvas.width = canvasWidth; - canvas.height = canvasHeight; - this.canvasSize_ = [canvasWidth, canvasHeight]; - this.canvasTooBig_ = - !ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_); - this.renderedCanvasTileRange_ = null; - } else { - canvasWidth = this.canvasSize_[0]; - canvasHeight = this.canvasSize_[1]; - if (z != this.renderedCanvasZ_ || - !this.renderedCanvasTileRange_.containsTileRange(tileRange)) { - this.renderedCanvasTileRange_ = null; - } - } - } +/** + * Cache of options - we only actually call internalGetOptions once. + * @type {Object} + * @private + */ +goog.net.XmlHttpFactory.prototype.cachedOptions_ = null; - var canvasTileRange, canvasTileRangeWidth, minX, minY; - if (!this.renderedCanvasTileRange_) { - canvasTileRangeWidth = canvasWidth / tilePixelSize[0]; - var canvasTileRangeHeight = canvasHeight / tilePixelSize[1]; - minX = tileRange.minX - - Math.floor((canvasTileRangeWidth - tileRange.getWidth()) / 2); - minY = tileRange.minY - - Math.floor((canvasTileRangeHeight - tileRange.getHeight()) / 2); - this.renderedCanvasZ_ = z; - this.renderedTileWidth_ = tilePixelSize[0]; - this.renderedTileHeight_ = tilePixelSize[1]; - this.renderedCanvasTileRange_ = new ol.TileRange( - minX, minX + canvasTileRangeWidth - 1, - minY, minY + canvasTileRangeHeight - 1); - this.renderedTiles_ = - new Array(canvasTileRangeWidth * canvasTileRangeHeight); - canvasTileRange = this.renderedCanvasTileRange_; - } else { - canvasTileRange = this.renderedCanvasTileRange_; - canvasTileRangeWidth = canvasTileRange.getWidth(); - } - goog.asserts.assert(canvasTileRange.containsTileRange(tileRange), - 'tileRange is contained in canvasTileRange'); +/** + * @return {!goog.net.XhrLike.OrNative} A new XhrLike instance. + */ +goog.net.XmlHttpFactory.prototype.createInstance = goog.abstractMethod; - /** - * @type {Object.<number, Object.<string, ol.Tile>>} - */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - /** @type {Array.<ol.Tile>} */ - var tilesToClear = []; - var findLoadedTiles = this.createLoadedTileFinder( - tileSource, projection, tilesToDrawByZ); +/** + * @return {Object} Options describing how xhr objects obtained from this + * factory should be used. + */ +goog.net.XmlHttpFactory.prototype.getOptions = function() { + return this.cachedOptions_ || + (this.cachedOptions_ = this.internalGetOptions()); +}; - var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); - var tmpExtent = ol.extent.createEmpty(); - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, fullyLoaded, tile, x, y; - var drawableTile = ( - /** - * @param {!ol.Tile} tile Tile. - * @return {boolean} Tile is selected. - */ - function(tile) { - var tileState = tile.getState(); - return tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - tileState == ol.TileState.ERROR && !useInterimTilesOnError; - }); - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - if (!drawableTile(tile) && tile.interimTile) { - tile = tile.interimTile; - } - goog.asserts.assert(tile); - if (drawableTile(tile)) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - // FIXME we do not need to clear the tile if it is fully covered by its - // children - tilesToClear.push(tile); - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } +/** + * Override this method in subclasses to preserve the caching offered by + * getOptions(). + * @return {Object} Options describing how xhr objects obtained from this + * factory should be used. + * @protected + */ +goog.net.XmlHttpFactory.prototype.internalGetOptions = goog.abstractMethod; - } - } +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - var i, ii; - for (i = 0, ii = tilesToClear.length; i < ii; ++i) { - tile = tilesToClear[i]; - x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX); - y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]); - context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]); - } +/** + * @fileoverview Implementation of XmlHttpFactory which allows construction from + * simple factory methods. + * @author dbk@google.com (David Barrett-Kahn) + */ - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - goog.array.sort(zs); - var opaque = tileSource.getOpaque(); - var origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( - [z, canvasTileRange.minX, canvasTileRange.maxY], - tmpExtent)); - var currentZ, index, scale, tileCoordKey, tileExtent, tileState, tilesToDraw; - var ix, iy, interimTileRange, maxX, maxY; - var height, width; - for (i = 0, ii = zs.length; i < ii; ++i) { - currentZ = zs[i]; - tilePixelSize = - tileSource.getTilePixelSize(currentZ, pixelRatio, projection); - tilesToDraw = tilesToDrawByZ[currentZ]; - if (currentZ == z) { - for (tileCoordKey in tilesToDraw) { - tile = tilesToDraw[tileCoordKey]; - index = - (tile.tileCoord[2] - canvasTileRange.minY) * canvasTileRangeWidth + - (tile.tileCoord[1] - canvasTileRange.minX); - if (this.renderedTiles_[index] != tile) { - x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX); - y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]); - tileState = tile.getState(); - if (tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && !useInterimTilesOnError) || - !opaque) { - context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]); - } - if (tileState == ol.TileState.LOADED) { - context.drawImage(tile.getImage(), - tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1], - x, y, tilePixelSize[0], tilePixelSize[1]); - } - this.renderedTiles_[index] = tile; - } - } - } else { - scale = tileGrid.getResolution(currentZ) / tileResolution; - for (tileCoordKey in tilesToDraw) { - tile = tilesToDraw[tileCoordKey]; - tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); - x = (tileExtent[0] - origin[0]) / tilePixelResolution; - y = (origin[1] - tileExtent[3]) / tilePixelResolution; - width = scale * tilePixelSize[0]; - height = scale * tilePixelSize[1]; - tileState = tile.getState(); - if (tileState == ol.TileState.EMPTY || !opaque) { - context.clearRect(x, y, width, height); - } - if (tileState == ol.TileState.LOADED) { - context.drawImage(tile.getImage(), - tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1], - x, y, width, height); - } - interimTileRange = - tileGrid.getTileRangeForExtentAndZ(tileExtent, z, tmpTileRange); - minX = Math.max(interimTileRange.minX, canvasTileRange.minX); - maxX = Math.min(interimTileRange.maxX, canvasTileRange.maxX); - minY = Math.max(interimTileRange.minY, canvasTileRange.minY); - maxY = Math.min(interimTileRange.maxY, canvasTileRange.maxY); - for (ix = minX; ix <= maxX; ++ix) { - for (iy = minY; iy <= maxY; ++iy) { - index = (iy - canvasTileRange.minY) * canvasTileRangeWidth + - (ix - canvasTileRange.minX); - this.renderedTiles_[index] = undefined; - } - } - } - } - } +goog.provide('goog.net.WrapperXmlHttpFactory'); - this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); - this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, - projection, extent, z, tileLayer.getPreload()); - this.scheduleExpireCache(frameState, tileSource); - this.updateLogos(frameState, tileSource); +/** @suppress {extraRequire} Typedef. */ +goog.require('goog.net.XhrLike'); +goog.require('goog.net.XmlHttpFactory'); - ol.vec.Mat4.makeTransform2D(this.imageTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio * tilePixelResolution / viewState.resolution, - pixelRatio * tilePixelResolution / viewState.resolution, - viewState.rotation, - (origin[0] - center[0]) / tilePixelResolution, - (center[1] - origin[1]) / tilePixelResolution); - this.imageTransformInv_ = null; - return true; + +/** + * An xhr factory subclass which can be constructed using two factory methods. + * This exists partly to allow the preservation of goog.net.XmlHttp.setFactory() + * with an unchanged signature. + * @param {function():!goog.net.XhrLike.OrNative} xhrFactory + * A function which returns a new XHR object. + * @param {function():!Object} optionsFactory A function which returns the + * options associated with xhr objects from this factory. + * @extends {goog.net.XmlHttpFactory} + * @constructor + * @final + */ +goog.net.WrapperXmlHttpFactory = function(xhrFactory, optionsFactory) { + goog.net.XmlHttpFactory.call(this); + + /** + * XHR factory method. + * @type {function() : !goog.net.XhrLike.OrNative} + * @private + */ + this.xhrFactory_ = xhrFactory; + + /** + * Options factory method. + * @type {function() : !Object} + * @private + */ + this.optionsFactory_ = optionsFactory; +}; +goog.inherits(goog.net.WrapperXmlHttpFactory, goog.net.XmlHttpFactory); + + +/** @override */ +goog.net.WrapperXmlHttpFactory.prototype.createInstance = function() { + return this.xhrFactory_(); +}; + + +/** @override */ +goog.net.WrapperXmlHttpFactory.prototype.getOptions = function() { + return this.optionsFactory_(); }; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + /** - * @inheritDoc + * @fileoverview Low level handling of XMLHttpRequest. + * @author arv@google.com (Erik Arvidsson) + * @author dbk@google.com (David Barrett-Kahn) */ -ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.context_) { - return undefined; - } - if (!this.imageTransformInv_) { - this.imageTransformInv_ = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); - } +goog.provide('goog.net.DefaultXmlHttpFactory'); +goog.provide('goog.net.XmlHttp'); +goog.provide('goog.net.XmlHttp.OptionType'); +goog.provide('goog.net.XmlHttp.ReadyState'); +goog.provide('goog.net.XmlHttpDefines'); - var pixelOnCanvas = - this.getPixelOnCanvas(pixel, this.imageTransformInv_); +goog.require('goog.asserts'); +goog.require('goog.net.WrapperXmlHttpFactory'); +goog.require('goog.net.XmlHttpFactory'); - var imageData = this.context_.getImageData( - pixelOnCanvas[0], pixelOnCanvas[1], 1, 1).data; - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } +/** + * Static class for creating XMLHttpRequest objects. + * @return {!goog.net.XhrLike.OrNative} A new XMLHttpRequest object. + */ +goog.net.XmlHttp = function() { + return goog.net.XmlHttp.factory_.createInstance(); }; -goog.provide('ol.renderer.canvas.VectorLayer'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.renderer.vector'); -goog.require('ol.source.Vector'); +/** + * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to + * true bypasses the ActiveX probing code. + * NOTE(ruilopes): Due to the way JSCompiler works, this define *will not* strip + * out the ActiveX probing code from binaries. To achieve this, use + * {@code goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR} instead. + * TODO(ruilopes): Collapse both defines. + */ +goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false); +/** @const */ +goog.net.XmlHttpDefines = {}; + /** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.Vector} vectorLayer Vector layer. + * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to + * true eliminates the ActiveX probing code. */ -ol.renderer.canvas.VectorLayer = function(vectorLayer) { +goog.define('goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR', false); - goog.base(this, vectorLayer); +/** + * Gets the options to use with the XMLHttpRequest objects obtained using + * the static methods. + * @return {Object} The options. + */ +goog.net.XmlHttp.getOptions = function() { + return goog.net.XmlHttp.factory_.getOptions(); +}; + + +/** + * Type of options that an XmlHttp object can have. + * @enum {number} + */ +goog.net.XmlHttp.OptionType = { /** - * @private - * @type {boolean} + * Whether a goog.nullFunction should be used to clear the onreadystatechange + * handler instead of null. */ - this.dirty_ = false; + USE_NULL_FUNCTION: 0, /** - * @private - * @type {number} + * NOTE(user): In IE if send() errors on a *local* request the readystate + * is still changed to COMPLETE. We need to ignore it and allow the + * try/catch around send() to pick up the error. */ - this.renderedRevision_ = -1; + LOCAL_REQUEST_ERROR: 1 +}; + +/** + * Status constants for XMLHTTP, matches: + * http://msdn.microsoft.com/library/default.asp?url=/library/ + * en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp + * @enum {number} + */ +goog.net.XmlHttp.ReadyState = { /** - * @private - * @type {number} + * Constant for when xmlhttprequest.readyState is uninitialized */ - this.renderedResolution_ = NaN; + UNINITIALIZED: 0, /** - * @private - * @type {ol.Extent} + * Constant for when xmlhttprequest.readyState is loading. */ - this.renderedExtent_ = ol.extent.createEmpty(); + LOADING: 1, /** - * @private - * @type {function(ol.Feature, ol.Feature): number|null} + * Constant for when xmlhttprequest.readyState is loaded. */ - this.renderedRenderOrder_ = null; + LOADED: 2, /** - * @private - * @type {ol.render.canvas.ReplayGroup} + * Constant for when xmlhttprequest.readyState is in an interactive state. */ - this.replayGroup_ = null; + INTERACTIVE: 3, /** - * @private - * @type {CanvasRenderingContext2D} + * Constant for when xmlhttprequest.readyState is completed */ - this.context_ = ol.dom.createCanvasContext2D(); + COMPLETE: 4 +}; + + +/** + * The global factory instance for creating XMLHttpRequest objects. + * @type {goog.net.XmlHttpFactory} + * @private + */ +goog.net.XmlHttp.factory_; + +/** + * Sets the factories for creating XMLHttpRequest objects and their options. + * @param {Function} factory The factory for XMLHttpRequest objects. + * @param {Function} optionsFactory The factory for options. + * @deprecated Use setGlobalFactory instead. + */ +goog.net.XmlHttp.setFactory = function(factory, optionsFactory) { + goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( + goog.asserts.assert(factory), + goog.asserts.assert(optionsFactory))); }; -goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer); /** - * @inheritDoc + * Sets the global factory object. + * @param {!goog.net.XmlHttpFactory} factory New global factory object. */ -ol.renderer.canvas.VectorLayer.prototype.composeFrame = - function(frameState, layerState, context) { +goog.net.XmlHttp.setGlobalFactory = function(factory) { + goog.net.XmlHttp.factory_ = factory; +}; - var extent = frameState.extent; - var pixelRatio = frameState.pixelRatio; - var skippedFeatureUids = layerState.managed ? - frameState.skippedFeatureUids : {}; - var viewState = frameState.viewState; - var projection = viewState.projection; - var rotation = viewState.rotation; - var projectionExtent = projection.getExtent(); - var vectorSource = this.getLayer().getSource(); - goog.asserts.assertInstanceof(vectorSource, ol.source.Vector); - var transform = this.getTransform(frameState, 0); - this.dispatchPreComposeEvent(context, frameState, transform); +/** + * Default factory to use when creating xhr objects. You probably shouldn't be + * instantiating this directly, but rather using it via goog.net.XmlHttp. + * @extends {goog.net.XmlHttpFactory} + * @constructor + */ +goog.net.DefaultXmlHttpFactory = function() { + goog.net.XmlHttpFactory.call(this); +}; +goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory); - var replayGroup = this.replayGroup_; - if (replayGroup && !replayGroup.isEmpty()) { - var layer = this.getLayer(); - var replayContext; - if (layer.hasListener(ol.render.EventType.RENDER)) { - // resize and clear - this.context_.canvas.width = context.canvas.width; - this.context_.canvas.height = context.canvas.height; - replayContext = this.context_; - } else { - replayContext = context; - } - // for performance reasons, context.save / context.restore is not used - // to save and restore the transformation matrix and the opacity. - // see http://jsperf.com/context-save-restore-versus-variable - var alpha = replayContext.globalAlpha; - replayContext.globalAlpha = layerState.opacity; - replayGroup.replay(replayContext, pixelRatio, transform, rotation, - skippedFeatureUids); - if (vectorSource.getWrapX() && projection.canWrapX() && - !ol.extent.containsExtent(projectionExtent, extent)) { - var startX = extent[0]; - var worldWidth = ol.extent.getWidth(projectionExtent); - var world = 0; - var offsetX; - while (startX < projectionExtent[0]) { - --world; - offsetX = worldWidth * world; - transform = this.getTransform(frameState, offsetX); - replayGroup.replay(replayContext, pixelRatio, transform, rotation, - skippedFeatureUids); - startX += worldWidth; - } - world = 0; - startX = extent[2]; - while (startX > projectionExtent[2]) { - ++world; - offsetX = worldWidth * world; - transform = this.getTransform(frameState, offsetX); - replayGroup.replay(replayContext, pixelRatio, transform, rotation, - skippedFeatureUids); - startX -= worldWidth; - } - // restore original transform for render and compose events - transform = this.getTransform(frameState, 0); - } - - if (replayContext != context) { - this.dispatchRenderEvent(replayContext, frameState, transform); - context.drawImage(replayContext.canvas, 0, 0); - } - replayContext.globalAlpha = alpha; +/** @override */ +goog.net.DefaultXmlHttpFactory.prototype.createInstance = function() { + var progId = this.getProgId_(); + if (progId) { + return new ActiveXObject(progId); + } else { + return new XMLHttpRequest(); } - - this.dispatchPostComposeEvent(context, frameState, transform); - }; -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - if (!this.replayGroup_) { - return undefined; - } else { - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var layer = this.getLayer(); - var layerState = frameState.layerStates[goog.getUid(layer)]; - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, - rotation, layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); +/** @override */ +goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() { + var progId = this.getProgId_(); + var options = {}; + if (progId) { + options[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] = true; + options[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] = true; } + return options; }; /** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. + * The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized. + * @type {string|undefined} * @private */ -ol.renderer.canvas.VectorLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); -}; +goog.net.DefaultXmlHttpFactory.prototype.ieProgId_; /** - * @inheritDoc + * Initialize the private state used by other functions. + * @return {string} The ActiveX PROG ID string to use to create xhr's in IE. + * @private */ -ol.renderer.canvas.VectorLayer.prototype.prepareFrame = - function(frameState, layerState) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - var vectorSource = vectorLayer.getSource(); - - this.updateAttributions( - frameState.attributions, vectorSource.getAttributions()); - this.updateLogos(frameState, vectorSource); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); - var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - - var frameStateExtent = frameState.extent; - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var vectorLayerRevision = vectorLayer.getRevision(); - var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); - var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); - - if (vectorLayerRenderOrder === undefined) { - vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; - } - - var extent = ol.extent.buffer(frameStateExtent, - vectorLayerRenderBuffer * resolution); - var projectionExtent = viewState.projection.getExtent(); - - if (vectorSource.getWrapX() && viewState.projection.canWrapX() && - !ol.extent.containsExtent(projectionExtent, frameState.extent)) { - // For the replay group, we need an extent that intersects the real world - // (-180° to +180°). To support geometries in a coordinate range from -540° - // to +540°, we add at least 1 world width on each side of the projection - // extent. If the viewport is wider than the world, we need to add half of - // the viewport width to make sure we cover the whole viewport. - var worldWidth = ol.extent.getWidth(projectionExtent); - var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth); - extent[0] = projectionExtent[0] - buffer; - extent[2] = projectionExtent[2] + buffer; - } - - if (!this.dirty_ && - this.renderedResolution_ == resolution && - this.renderedRevision_ == vectorLayerRevision && - this.renderedRenderOrder_ == vectorLayerRenderOrder && - ol.extent.containsExtent(this.renderedExtent_, extent)) { - return true; +goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() { + if (goog.net.XmlHttp.ASSUME_NATIVE_XHR || + goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR) { + return ''; } - // FIXME dispose of old replayGroup in post render - goog.dispose(this.replayGroup_); - this.replayGroup_ = null; - - this.dirty_ = false; - - var replayGroup = - new ol.render.canvas.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, - resolution, vectorLayer.getRenderBuffer()); - vectorSource.loadFeatures(extent, resolution, projection); - var renderFeature = - /** - * @param {ol.Feature} feature Feature. - * @this {ol.renderer.canvas.VectorLayer} - */ - function(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = vectorLayer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); + // The following blog post describes what PROG IDs to use to create the + // XMLHTTP object in Internet Explorer: + // http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx + // However we do not (yet) fully trust that this will be OK for old versions + // of IE on Win9x so we therefore keep the last 2. + if (!this.ieProgId_ && typeof XMLHttpRequest == 'undefined' && + typeof ActiveXObject != 'undefined') { + // Candidate Active X types. + var ACTIVE_X_IDENTS = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', + 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP']; + for (var i = 0; i < ACTIVE_X_IDENTS.length; i++) { + var candidate = ACTIVE_X_IDENTS[i]; + /** @preserveTry */ + try { + new ActiveXObject(candidate); + // NOTE(user): cannot assign progid and return candidate in one line + // because JSCompiler complaings: BUG 658126 + this.ieProgId_ = candidate; + return candidate; + } catch (e) { + // do nothing; try next choice } } - if (styles) { - var dirty = this.renderFeature( - feature, resolution, pixelRatio, styles, replayGroup); - this.dirty_ = this.dirty_ || dirty; - } - }; - if (vectorLayerRenderOrder) { - /** @type {Array.<ol.Feature>} */ - var features = []; - vectorSource.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - features.push(feature); - }, this); - goog.array.sort(features, vectorLayerRenderOrder); - features.forEach(renderFeature, this); - } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); - } - replayGroup.finish(); - this.renderedResolution_ = resolution; - this.renderedRevision_ = vectorLayerRevision; - this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; - this.replayGroup_ = replayGroup; + // couldn't find any matches + throw Error('Could not create ActiveXObject. ActiveX might be disabled,' + + ' or MSXML might not be installed'); + } - return true; + return /** @type {string} */ (this.ieProgId_); }; -/** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. - */ -ol.renderer.canvas.VectorLayer.prototype.renderFeature = - function(feature, resolution, pixelRatio, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - return loading; -}; - -goog.provide('ol.TileLoadFunctionType'); -goog.provide('ol.TileVectorLoadFunctionType'); +//Set the global factory to an instance of the default factory. +goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory()); +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * A function that takes an {@link ol.Tile} for the tile and a - * `{string}` for the url as arguments. + * @fileoverview Wrapper class for handling XmlHttpRequests. * - * @typedef {function(ol.Tile, string)} - * @api - */ -ol.TileLoadFunctionType; - - -/** - * A function that is called with a tile url for the features to load and - * a callback that takes the loaded features as argument. + * One off requests can be sent through goog.net.XhrIo.send() or an + * instance can be created to send multiple requests. Each request uses its + * own XmlHttpRequest object and handles clearing of the event callback to + * ensure no leaks. + * + * XhrIo is event based, it dispatches events on success, failure, finishing, + * ready-state change, or progress. + * + * The ready-state or timeout event fires first, followed by + * a generic completed event. Then the abort, error, or success event + * is fired as appropriate. Progress events are fired as they are + * received. Lastly, the ready event will fire to indicate that the + * object may be used to make another request. + * + * The error event may also be called before completed and + * ready-state-change if the XmlHttpRequest.open() or .send() methods throw. + * + * This class does not support multiple requests, queuing, or prioritization. + * + * When progress events are supported by the browser, and progress is + * enabled via .setProgressEventsEnabled(true), the + * goog.net.EventType.PROGRESS event will be the re-dispatched browser + * progress event. + * + * Tested = IE6, FF1.5, Safari, Opera 8.5 + * + * TODO(user): Error cases aren't playing nicely in Safari. * - * @typedef {function(string, function(Array.<ol.Feature>))} - * @api */ -ol.TileVectorLoadFunctionType; -goog.provide('ol.VectorTile'); -goog.require('ol.Tile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileLoadFunctionType'); -goog.require('ol.TileState'); +goog.provide('goog.net.XhrIo'); +goog.provide('goog.net.XhrIo.ResponseType'); +goog.require('goog.Timer'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.debug.entryPointRegistry'); +goog.require('goog.events.EventTarget'); +goog.require('goog.json'); +goog.require('goog.log'); +goog.require('goog.net.ErrorCode'); +goog.require('goog.net.EventType'); +goog.require('goog.net.HttpStatus'); +goog.require('goog.net.XmlHttp'); +goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.structs'); +goog.require('goog.structs.Map'); +goog.require('goog.uri.utils'); +goog.require('goog.userAgent'); -/** - * @typedef {{ - * dirty: boolean, - * renderedRenderOrder: (null|function(ol.Feature, ol.Feature):number), - * renderedRevision: number, - * replayGroup: ol.render.IReplayGroup}} - */ -ol.TileReplayState; +goog.forwardDeclare('goog.Uri'); /** + * Basic class for handling XMLHttpRequests. + * @param {goog.net.XmlHttpFactory=} opt_xmlHttpFactory Factory to use when + * creating XMLHttpRequest objects. * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Data source url. - * @param {ol.format.Feature} format Feature format. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. + * @extends {goog.events.EventTarget} */ -ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) { - - goog.base(this, tileCoord, state); +goog.net.XhrIo = function(opt_xmlHttpFactory) { + goog.net.XhrIo.base(this, 'constructor'); /** - * @private - * @type {ol.format.Feature} + * Map of default headers to add to every request, use: + * XhrIo.headers.set(name, value) + * @type {!goog.structs.Map} */ - this.format_ = format; + this.headers = new goog.structs.Map(); /** - * @private - * @type {Array.<ol.Feature>} + * Optional XmlHttpFactory + * @private {goog.net.XmlHttpFactory} */ - this.features_ = null; + this.xmlHttpFactory_ = opt_xmlHttpFactory || null; /** - * @private - * @type {ol.FeatureLoader} + * Whether XMLHttpRequest is active. A request is active from the time send() + * is called until onReadyStateChange() is complete, or error() or abort() + * is called. + * @private {boolean} */ - this.loader_; + this.active_ = false; /** - * @private - * @type {ol.proj.Projection} + * The XMLHttpRequest object that is being used for the transfer. + * @private {?goog.net.XhrLike.OrNative} */ - this.projection_ = null; + this.xhr_ = null; /** - * @private - * @type {ol.TileReplayState} + * The options to use with the current XMLHttpRequest object. + * @private {Object} */ - this.replayState_ = { - dirty: false, - renderedRenderOrder: null, - renderedRevision: -1, - replayGroup: null - }; + this.xhrOptions_ = null; /** - * @private - * @type {ol.TileLoadFunctionType} + * Last URL that was requested. + * @private {string|goog.Uri} */ - this.tileLoadFunction_ = tileLoadFunction; + this.lastUri_ = ''; /** - * @private - * @type {string} + * Method for the last request. + * @private {string} */ - this.url_ = src; + this.lastMethod_ = ''; -}; -goog.inherits(ol.VectorTile, ol.Tile); + /** + * Last error code. + * @private {!goog.net.ErrorCode} + */ + this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; + /** + * Last error message. + * @private {Error|string} + */ + this.lastError_ = ''; -/** - * @inheritDoc - */ -ol.VectorTile.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); -}; + /** + * Used to ensure that we don't dispatch an multiple ERROR events. This can + * happen in IE when it does a synchronous load and one error is handled in + * the ready statte change and one is handled due to send() throwing an + * exception. + * @private {boolean} + */ + this.errorDispatched_ = false; + /** + * Used to make sure we don't fire the complete event from inside a send call. + * @private {boolean} + */ + this.inSend_ = false; -/** - * Get the feature format assigned for reading this tile's features. - * @return {ol.format.Feature} Feature format. - * @api - */ -ol.VectorTile.prototype.getFormat = function() { - return this.format_; -}; + /** + * Used in determining if a call to {@link #onReadyStateChange_} is from + * within a call to this.xhr_.open. + * @private {boolean} + */ + this.inOpen_ = false; + /** + * Used in determining if a call to {@link #onReadyStateChange_} is from + * within a call to this.xhr_.abort. + * @private {boolean} + */ + this.inAbort_ = false; -/** - * @return {Array.<ol.Feature>} Features. - */ -ol.VectorTile.prototype.getFeatures = function() { - return this.features_; -}; + /** + * Number of milliseconds after which an incomplete request will be aborted + * and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no timeout + * is set. + * @private {number} + */ + this.timeoutInterval_ = 0; + /** + * Timer to track request timeout. + * @private {?number} + */ + this.timeoutId_ = null; -/** - * @return {ol.TileReplayState} - */ -ol.VectorTile.prototype.getReplayState = function() { - return this.replayState_; -}; + /** + * The requested type for the response. The empty string means use the default + * XHR behavior. + * @private {goog.net.XhrIo.ResponseType} + */ + this.responseType_ = goog.net.XhrIo.ResponseType.DEFAULT; + /** + * Whether a "credentialed" request is to be sent (one that is aware of + * cookies and authentication). This is applicable only for cross-domain + * requests and more recent browsers that support this part of the HTTP Access + * Control standard. + * + * @see http://www.w3.org/TR/XMLHttpRequest/#the-withcredentials-attribute + * + * @private {boolean} + */ + this.withCredentials_ = false; -/** - * @inheritDoc - */ -ol.VectorTile.prototype.getKey = function() { - return this.url_; + /** + * Whether progress events are enabled for this request. This is + * disabled by default because setting a progress event handler + * causes pre-flight OPTIONS requests to be sent for CORS requests, + * even in cases where a pre-flight request would not otherwise be + * sent. + * + * @see http://xhr.spec.whatwg.org/#security-considerations + * + * Note that this can cause problems for Firefox 22 and below, as an + * older "LSProgressEvent" will be dispatched by the browser. That + * progress event is no longer supported, and can lead to failures, + * including throwing exceptions. + * + * @see http://bugzilla.mozilla.org/show_bug.cgi?id=845631 + * @see b/23469793 + * + * @private {boolean} + */ + this.progressEventsEnabled_ = false; + + /** + * True if we can use XMLHttpRequest's timeout directly. + * @private {boolean} + */ + this.useXhr2Timeout_ = false; }; +goog.inherits(goog.net.XhrIo, goog.events.EventTarget); /** - * @return {ol.proj.Projection} Projection. + * Response types that may be requested for XMLHttpRequests. + * @enum {string} + * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute */ -ol.VectorTile.prototype.getProjection = function() { - return this.projection_; +goog.net.XhrIo.ResponseType = { + DEFAULT: '', + TEXT: 'text', + DOCUMENT: 'document', + // Not supported as of Chrome 10.0.612.1 dev + BLOB: 'blob', + ARRAY_BUFFER: 'arraybuffer' }; /** - * Load the tile. + * A reference to the XhrIo logger + * @private {goog.debug.Logger} + * @const */ -ol.VectorTile.prototype.load = function() { - if (this.state == ol.TileState.IDLE) { - this.setState(ol.TileState.LOADING); - this.tileLoadFunction_(this, this.url_); - this.loader_(null, NaN, null); - } -}; +goog.net.XhrIo.prototype.logger_ = + goog.log.getLogger('goog.net.XhrIo'); /** - * @param {Array.<ol.Feature>} features Features. + * The Content-Type HTTP header name + * @type {string} */ -ol.VectorTile.prototype.setFeatures = function(features) { - this.features_ = features; - this.setState(ol.TileState.LOADED); -}; +goog.net.XhrIo.CONTENT_TYPE_HEADER = 'Content-Type'; /** - * @param {ol.proj.Projection} projection Projection. + * The pattern matching the 'http' and 'https' URI schemes + * @type {!RegExp} */ -ol.VectorTile.prototype.setProjection = function(projection) { - this.projection_ = projection; -}; +goog.net.XhrIo.HTTP_SCHEME_PATTERN = /^https?$/i; /** - * @param {ol.TileState} tileState Tile state. + * The methods that typically come along with form data. We set different + * headers depending on whether the HTTP action is one of these. */ -ol.VectorTile.prototype.setState = function(tileState) { - this.state = tileState; - this.changed(); -}; +goog.net.XhrIo.METHODS_WITH_FORM_DATA = ['POST', 'PUT']; /** - * Set the feature loader for reading this tile's features. - * @param {ol.FeatureLoader} loader Feature loader. - * @api + * The Content-Type HTTP header value for a url-encoded form + * @type {string} */ -ol.VectorTile.prototype.setLoader = function(loader) { - this.loader_ = loader; -}; - -goog.provide('ol.TileUrlFunction'); -goog.provide('ol.TileUrlFunctionType'); - -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('ol.TileCoord'); -goog.require('ol.tilecoord'); +goog.net.XhrIo.FORM_CONTENT_TYPE = + 'application/x-www-form-urlencoded;charset=utf-8'; /** - * {@link ol.source.Tile} sources use a function of this type to get the url - * that provides a tile for a given tile coordinate. + * The XMLHttpRequest Level two timeout delay ms property name. * - * This function takes an {@link ol.TileCoord} for the tile coordinate, a - * `{number}` representing the pixel ratio and an {@link ol.proj.Projection} for - * the projection as arguments and returns a `{string}` representing the tile - * URL, or undefined if no tile should be requested for the passed tile - * coordinate. + * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute * - * @typedef {function(ol.TileCoord, number, - * ol.proj.Projection): (string|undefined)} - * @api + * @private {string} + * @const */ -ol.TileUrlFunctionType; +goog.net.XhrIo.XHR2_TIMEOUT_ = 'timeout'; /** - * @typedef {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=): - * ol.TileCoord} + * The XMLHttpRequest Level two ontimeout handler property name. + * + * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute + * + * @private {string} + * @const */ -ol.TileCoordTransformType; +goog.net.XhrIo.XHR2_ON_TIMEOUT_ = 'ontimeout'; /** - * @param {string} template Template. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {ol.TileUrlFunctionType} Tile URL function. + * All non-disposed instances of goog.net.XhrIo created + * by {@link goog.net.XhrIo.send} are in this Array. + * @see goog.net.XhrIo.cleanup + * @private {!Array<!goog.net.XhrIo>} */ -ol.TileUrlFunction.createFromTemplate = function(template, tileGrid) { - var zRegEx = /\{z\}/g; - var xRegEx = /\{x\}/g; - var yRegEx = /\{y\}/g; - var dashYRegEx = /\{-y\}/g; - return ( - /** - * @param {ol.TileCoord} tileCoord Tile Coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - return template.replace(zRegEx, tileCoord[0].toString()) - .replace(xRegEx, tileCoord[1].toString()) - .replace(yRegEx, function() { - var y = -tileCoord[2] - 1; - return y.toString(); - }) - .replace(dashYRegEx, function() { - var z = tileCoord[0]; - var range = tileGrid.getFullTileRange(z); - goog.asserts.assert(range, - 'The {-y} template requires a tile grid with extent'); - var y = range.getHeight() + tileCoord[2]; - return y.toString(); - }); - } - }); -}; +goog.net.XhrIo.sendInstances_ = []; /** - * @param {Array.<string>} templates Templates. - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @return {ol.TileUrlFunctionType} Tile URL function. + * Static send that creates a short lived instance of XhrIo to send the + * request. + * @see goog.net.XhrIo.cleanup + * @param {string|goog.Uri} url Uri to make request to. + * @param {?function(this:goog.net.XhrIo, ?)=} opt_callback Callback function + * for when request is complete. + * @param {string=} opt_method Send method, default: GET. + * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} + * opt_content Body data. + * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the + * request. + * @param {number=} opt_timeoutInterval Number of milliseconds after which an + * incomplete request will be aborted; 0 means no timeout is set. + * @param {boolean=} opt_withCredentials Whether to send credentials with the + * request. Default to false. See {@link goog.net.XhrIo#setWithCredentials}. + * @return {!goog.net.XhrIo} The sent XhrIo. */ -ol.TileUrlFunction.createFromTemplates = function(templates, tileGrid) { - var len = templates.length; - var tileUrlFunctions = new Array(len); - for (var i = 0; i < len; ++i) { - tileUrlFunctions[i] = ol.TileUrlFunction.createFromTemplate( - templates[i], tileGrid); +goog.net.XhrIo.send = function(url, opt_callback, opt_method, opt_content, + opt_headers, opt_timeoutInterval, + opt_withCredentials) { + var x = new goog.net.XhrIo(); + goog.net.XhrIo.sendInstances_.push(x); + if (opt_callback) { + x.listen(goog.net.EventType.COMPLETE, opt_callback); } - return ol.TileUrlFunction.createFromTileUrlFunctions(tileUrlFunctions); -}; - - -/** - * @param {Array.<ol.TileUrlFunctionType>} tileUrlFunctions Tile URL Functions. - * @return {ol.TileUrlFunctionType} Tile URL function. - */ -ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) { - goog.asserts.assert(tileUrlFunctions.length > 0, - 'Length of tile url functions should be greater than 0'); - if (tileUrlFunctions.length === 1) { - return tileUrlFunctions[0]; + x.listenOnce(goog.net.EventType.READY, x.cleanupSend_); + if (opt_timeoutInterval) { + x.setTimeoutInterval(opt_timeoutInterval); } - return ( - /** - * @param {ol.TileCoord} tileCoord Tile Coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - var h = ol.tilecoord.hash(tileCoord); - var index = goog.math.modulo(h, tileUrlFunctions.length); - return tileUrlFunctions[index](tileCoord, pixelRatio, projection); - } - }); -}; - - -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ -ol.TileUrlFunction.nullTileUrlFunction = - function(tileCoord, pixelRatio, projection) { - return undefined; + if (opt_withCredentials) { + x.setWithCredentials(opt_withCredentials); + } + x.send(url, opt_method, opt_content, opt_headers); + return x; }; /** - * @param {string} url URL. - * @return {Array.<string>} Array of urls. + * Disposes all non-disposed instances of goog.net.XhrIo created by + * {@link goog.net.XhrIo.send}. + * {@link goog.net.XhrIo.send} cleans up the goog.net.XhrIo instance + * it creates when the request completes or fails. However, if + * the request never completes, then the goog.net.XhrIo is not disposed. + * This can occur if the window is unloaded before the request completes. + * We could have {@link goog.net.XhrIo.send} return the goog.net.XhrIo + * it creates and make the client of {@link goog.net.XhrIo.send} be + * responsible for disposing it in this case. However, this makes things + * significantly more complicated for the client, and the whole point + * of {@link goog.net.XhrIo.send} is that it's simple and easy to use. + * Clients of {@link goog.net.XhrIo.send} should call + * {@link goog.net.XhrIo.cleanup} when doing final + * cleanup on window unload. */ -ol.TileUrlFunction.expandUrl = function(url) { - var urls = []; - var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url); - if (match) { - var startCharCode = match[1].charCodeAt(0); - var stopCharCode = match[2].charCodeAt(0); - var charCode; - for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) { - urls.push(url.replace(match[0], String.fromCharCode(charCode))); - } - } else { - urls.push(url); +goog.net.XhrIo.cleanup = function() { + var instances = goog.net.XhrIo.sendInstances_; + while (instances.length) { + instances.pop().dispose(); } - return urls; }; -goog.provide('ol.source.UrlTile'); - -goog.require('goog.events'); -goog.require('ol.TileLoadFunctionType'); -goog.require('ol.TileState'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.TileUrlFunctionType'); -goog.require('ol.proj'); -goog.require('ol.source.Tile'); -goog.require('ol.source.TileEvent'); - /** - * @typedef {{attributions: (Array.<ol.Attribution>|undefined), - * extent: (ol.Extent|undefined), - * logo: (string|olx.LogoOptions|undefined), - * opaque: (boolean|undefined), - * projection: ol.proj.ProjectionLike, - * state: (ol.source.State|string|undefined), - * tileGrid: (ol.tilegrid.TileGrid|undefined), - * tileLoadFunction: ol.TileLoadFunctionType, - * tilePixelRatio: (number|undefined), - * tileUrlFunction: (ol.TileUrlFunctionType|undefined), - * url: (string|undefined), - * urls: (Array.<string>|undefined), - * wrapX: (boolean|undefined)}} + * Installs exception protection for all entry point introduced by + * goog.net.XhrIo instances which are not protected by + * {@link goog.debug.ErrorHandler#protectWindowSetTimeout}, + * {@link goog.debug.ErrorHandler#protectWindowSetInterval}, or + * {@link goog.events.protectBrowserEventEntryPoint}. + * + * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to + * protect the entry point(s). */ -ol.source.UrlTileOptions; - +goog.net.XhrIo.protectEntryPoints = function(errorHandler) { + goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = + errorHandler.protectEntryPoint( + goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); +}; /** - * @classdesc - * Base class for sources providing tiles divided into a tile grid over http. - * - * @constructor - * @fires ol.source.TileEvent - * @extends {ol.source.Tile} - * @param {ol.source.UrlTileOptions} options Image tile options. + * Disposes of the specified goog.net.XhrIo created by + * {@link goog.net.XhrIo.send} and removes it from + * {@link goog.net.XhrIo.pendingStaticSendInstances_}. + * @private */ -ol.source.UrlTile = function(options) { - - goog.base(this, { - attributions: options.attributions, - cacheSize: options.cacheSize, - extent: options.extent, - logo: options.logo, - opaque: options.opaque, - projection: options.projection, - state: options.state ? - /** @type {ol.source.State} */ (options.state) : undefined, - tileGrid: options.tileGrid, - tilePixelRatio: options.tilePixelRatio, - wrapX: options.wrapX - }); - - /** - * @protected - * @type {ol.TileLoadFunctionType} - */ - this.tileLoadFunction = options.tileLoadFunction; - - /** - * @protected - * @type {ol.TileUrlFunctionType} - */ - this.tileUrlFunction = options.tileUrlFunction ? - options.tileUrlFunction : - ol.TileUrlFunction.nullTileUrlFunction; - - /** - * @protected - * @type {!Array.<string>|null} - */ - this.urls = null; - - if (options.urls) { - if (options.tileUrlFunction) { - this.urls = options.urls; - } else { - this.setUrls(options.urls); - } - } else if (options.url) { - this.setUrl(options.url); - } - if (options.tileUrlFunction) { - this.setTileUrlFunction(options.tileUrlFunction); - } - +goog.net.XhrIo.prototype.cleanupSend_ = function() { + this.dispose(); + goog.array.remove(goog.net.XhrIo.sendInstances_, this); }; -goog.inherits(ol.source.UrlTile, ol.source.Tile); /** - * Return the tile load function of the source. - * @return {ol.TileLoadFunctionType} TileLoadFunction - * @api + * Returns the number of milliseconds after which an incomplete request will be + * aborted, or 0 if no timeout is set. + * @return {number} Timeout interval in milliseconds. */ -ol.source.UrlTile.prototype.getTileLoadFunction = function() { - return this.tileLoadFunction; +goog.net.XhrIo.prototype.getTimeoutInterval = function() { + return this.timeoutInterval_; }; /** - * Return the tile URL function of the source. - * @return {ol.TileUrlFunctionType} TileUrlFunction - * @api + * Sets the number of milliseconds after which an incomplete request will be + * aborted and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no + * timeout is set. + * @param {number} ms Timeout interval in milliseconds; 0 means none. */ -ol.source.UrlTile.prototype.getTileUrlFunction = function() { - return this.tileUrlFunction; +goog.net.XhrIo.prototype.setTimeoutInterval = function(ms) { + this.timeoutInterval_ = Math.max(0, ms); }; /** - * Return the URLs used for this source. - * When a tileUrlFunction is used instead of url or urls, - * null will be returned. - * @return {!Array.<string>|null} URLs. - * @api + * Sets the desired type for the response. At time of writing, this is only + * supported in very recent versions of WebKit (10.0.612.1 dev and later). + * + * If this is used, the response may only be accessed via {@link #getResponse}. + * + * @param {goog.net.XhrIo.ResponseType} type The desired type for the response. */ -ol.source.UrlTile.prototype.getUrls = function() { - return this.urls; +goog.net.XhrIo.prototype.setResponseType = function(type) { + this.responseType_ = type; }; /** - * Handle tile change events. - * @param {goog.events.Event} event Event. - * @protected + * Gets the desired type for the response. + * @return {goog.net.XhrIo.ResponseType} The desired type for the response. */ -ol.source.UrlTile.prototype.handleTileChange = function(event) { - var tile = /** @type {ol.Tile} */ (event.target); - switch (tile.getState()) { - case ol.TileState.LOADING: - this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADSTART, tile)); - break; - case ol.TileState.LOADED: - this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADEND, tile)); - break; - case ol.TileState.ERROR: - this.dispatchEvent( - new ol.source.TileEvent(ol.source.TileEventType.TILELOADERROR, tile)); - break; - } +goog.net.XhrIo.prototype.getResponseType = function() { + return this.responseType_; }; /** - * Set the tile load function of the source. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - * @api + * Sets whether a "credentialed" request that is aware of cookie and + * authentication information should be made. This option is only supported by + * browsers that support HTTP Access Control. As of this writing, this option + * is not supported in IE. + * + * @param {boolean} withCredentials Whether this should be a "credentialed" + * request. */ -ol.source.UrlTile.prototype.setTileLoadFunction = function(tileLoadFunction) { - this.tileCache.clear(); - this.tileLoadFunction = tileLoadFunction; - this.changed(); +goog.net.XhrIo.prototype.setWithCredentials = function(withCredentials) { + this.withCredentials_ = withCredentials; }; /** - * Set the tile URL function of the source. - * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function. - * @api + * Gets whether a "credentialed" request is to be sent. + * @return {boolean} The desired type for the response. */ -ol.source.UrlTile.prototype.setTileUrlFunction = function(tileUrlFunction) { - // FIXME It should be possible to be more intelligent and avoid clearing the - // FIXME cache. The tile URL function would need to be incorporated into the - // FIXME cache key somehow. - this.tileCache.clear(); - this.tileUrlFunction = tileUrlFunction; - this.changed(); +goog.net.XhrIo.prototype.getWithCredentials = function() { + return this.withCredentials_; }; /** - * Set the URL to use for requests. - * @param {string} url URL. - * @api stable + * Sets whether progress events are enabled for this request. Note + * that progress events require pre-flight OPTIONS request handling + * for CORS requests, and may cause trouble with older browsers. See + * progressEventsEnabled_ for details. + * @param {boolean} enabled Whether progress events should be enabled. */ -ol.source.UrlTile.prototype.setUrl = function(url) { - this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( - ol.TileUrlFunction.expandUrl(url), this.tileGrid)); - this.urls = [url]; +goog.net.XhrIo.prototype.setProgressEventsEnabled = function(enabled) { + this.progressEventsEnabled_ = enabled; }; /** - * Set the URLs to use for requests. - * @param {Array.<string>} urls URLs. - * @api stable + * Gets whether progress events are enabled. + * @return {boolean} Whether progress events are enabled for this request. */ -ol.source.UrlTile.prototype.setUrls = function(urls) { - this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( - urls, this.tileGrid)); - this.urls = urls; +goog.net.XhrIo.prototype.getProgressEventsEnabled = function() { + return this.progressEventsEnabled_; }; /** - * @inheritDoc + * Instance send that actually uses XMLHttpRequest to make a server call. + * @param {string|goog.Uri} url Uri to make request to. + * @param {string=} opt_method Send method, default: GET. + * @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} + * opt_content Body data. + * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the + * request. */ -ol.source.UrlTile.prototype.useTile = function(z, x, y) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - this.tileCache.get(tileCoordKey); +goog.net.XhrIo.prototype.send = function(url, opt_method, opt_content, + opt_headers) { + if (this.xhr_) { + throw Error('[goog.net.XhrIo] Object is active with another request=' + + this.lastUri_ + '; newUri=' + url); } -}; -goog.provide('ol.source.VectorTile'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.TileState'); -goog.require('ol.VectorTile'); -goog.require('ol.featureloader'); -goog.require('ol.source.UrlTile'); + var method = opt_method ? opt_method.toUpperCase() : 'GET'; + this.lastUri_ = url; + this.lastError_ = ''; + this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; + this.lastMethod_ = method; + this.errorDispatched_ = false; + this.active_ = true; + // Use the factory to create the XHR object and options + this.xhr_ = this.createXhr(); + this.xhrOptions_ = this.xmlHttpFactory_ ? + this.xmlHttpFactory_.getOptions() : goog.net.XmlHttp.getOptions(); -/** - * @classdesc - * Class for layer sources providing vector data divided into a tile grid, to be - * used with {@link ol.layer.VectorTile}. Although this source receives tiles - * with vector features from the server, it is not meant for feature editing. - * Features are optimized for rendering, their geometries are clipped at or near - * tile boundaries and simplified for a view resolution. See - * {@link ol.source.Vector} for vector sources that are suitable for feature - * editing. - * - * @constructor - * @fires ol.source.TileEvent - * @extends {ol.source.UrlTile} - * @param {olx.source.VectorTileOptions} options Vector tile options. - * @api - */ -ol.source.VectorTile = function(options) { + // Set up the onreadystatechange callback + this.xhr_.onreadystatechange = goog.bind(this.onReadyStateChange_, this); - goog.base(this, { - attributions: options.attributions, - cacheSize: ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK / 16, - extent: options.extent, - logo: options.logo, - opaque: options.opaque, - projection: options.projection, - state: options.state ? - /** @type {ol.source.State} */ (options.state) : undefined, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction ? - options.tileLoadFunction : ol.source.VectorTile.defaultTileLoadFunction, - tileUrlFunction: options.tileUrlFunction, - tilePixelRatio: options.tilePixelRatio, - url: options.url, - urls: options.urls, - wrapX: options.wrapX === undefined ? true : options.wrapX - }); + // Set up upload/download progress events, if progress events are supported. + if (this.getProgressEventsEnabled() && 'onprogress' in this.xhr_) { + this.xhr_.onprogress = goog.bind(this.onProgressHandler_, this); + if (this.xhr_.upload) { + this.xhr_.upload.onprogress = goog.bind(this.onProgressHandler_, this); + } + } /** - * @private - * @type {ol.format.Feature} + * Try to open the XMLHttpRequest (always async), if an error occurs here it + * is generally permission denied + * @preserveTry */ - this.format_ = options.format ? options.format : null; + try { + goog.log.fine(this.logger_, this.formatMsg_('Opening Xhr')); + this.inOpen_ = true; + this.xhr_.open(method, String(url), true); // Always async! + this.inOpen_ = false; + } catch (err) { + goog.log.fine(this.logger_, + this.formatMsg_('Error opening Xhr: ' + err.message)); + this.error_(goog.net.ErrorCode.EXCEPTION, err); + return; + } - /** - * @protected - * @type {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string, - * ol.format.Feature, ol.TileLoadFunctionType)} - */ - this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile; + // We can't use null since this won't allow requests with form data to have a + // content length specified which will cause some proxies to return a 411 + // error. + var content = opt_content || ''; -}; -goog.inherits(ol.source.VectorTile, ol.source.UrlTile); + var headers = this.headers.clone(); + // Add headers specific to this request + if (opt_headers) { + goog.structs.forEach(opt_headers, function(value, key) { + headers.set(key, value); + }); + } -/** - * @inheritDoc - */ -ol.source.VectorTile.prototype.getTile = - function(z, x, y, pixelRatio, projection) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); - } else { - goog.asserts.assert(projection, 'argument projection is truthy'); - var tileCoord = [z, x, y]; - var urlTileCoord = this.getTileCoordForTileUrlFunction( - tileCoord, projection); - var tileUrl = urlTileCoord ? - this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined; - var tile = new this.tileClass( - tileCoord, - tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, - tileUrl !== undefined ? tileUrl : '', - this.format_, - this.tileLoadFunction); - goog.events.listen(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); + // Find whether a content type header is set, ignoring case. + // HTTP header names are case-insensitive. See: + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + var contentTypeKey = goog.array.find(headers.getKeys(), + goog.net.XhrIo.isContentTypeHeader_); - this.tileCache.set(tileCoordKey, tile); - return tile; + var contentIsFormData = (goog.global['FormData'] && + (content instanceof goog.global['FormData'])); + if (goog.array.contains(goog.net.XhrIo.METHODS_WITH_FORM_DATA, method) && + !contentTypeKey && !contentIsFormData) { + // For requests typically with form data, default to the url-encoded form + // content type unless this is a FormData request. For FormData, + // the browser will automatically add a multipart/form-data content type + // with an appropriate multipart boundary. + headers.set(goog.net.XhrIo.CONTENT_TYPE_HEADER, + goog.net.XhrIo.FORM_CONTENT_TYPE); } -}; + // Add the headers to the Xhr object + headers.forEach(function(value, key) { + this.xhr_.setRequestHeader(key, value); + }, this); -/** - * @param {ol.VectorTile} vectorTile Vector tile. - * @param {string} url URL. - */ -ol.source.VectorTile.defaultTileLoadFunction = function(vectorTile, url) { - vectorTile.setLoader(ol.featureloader.tile(url, vectorTile.getFormat())); -}; + if (this.responseType_) { + this.xhr_.responseType = this.responseType_; + } -goog.provide('ol.renderer.canvas.VectorTileLayer'); + if (goog.object.containsKey(this.xhr_, 'withCredentials')) { + this.xhr_.withCredentials = this.withCredentials_; + } -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Feature'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.VectorTile'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.VectorTile'); -goog.require('ol.proj.Units'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.renderer.vector'); -goog.require('ol.size'); -goog.require('ol.source.VectorTile'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); + /** + * Try to send the request, or other wise report an error (404 not found). + * @preserveTry + */ + try { + this.cleanUpTimeoutTimer_(); // Paranoid, should never be running. + if (this.timeoutInterval_ > 0) { + this.useXhr2Timeout_ = goog.net.XhrIo.shouldUseXhr2Timeout_(this.xhr_); + goog.log.fine(this.logger_, this.formatMsg_('Will abort after ' + + this.timeoutInterval_ + 'ms if incomplete, xhr2 ' + + this.useXhr2Timeout_)); + if (this.useXhr2Timeout_) { + this.xhr_[goog.net.XhrIo.XHR2_TIMEOUT_] = this.timeoutInterval_; + this.xhr_[goog.net.XhrIo.XHR2_ON_TIMEOUT_] = + goog.bind(this.timeout_, this); + } else { + this.timeoutId_ = goog.Timer.callOnce(this.timeout_, + this.timeoutInterval_, this); + } + } + goog.log.fine(this.logger_, this.formatMsg_('Sending request')); + this.inSend_ = true; + this.xhr_.send(content); + this.inSend_ = false; + } catch (err) { + goog.log.fine(this.logger_, this.formatMsg_('Send error: ' + err.message)); + this.error_(goog.net.ErrorCode.EXCEPTION, err); + } +}; /** - * @constructor - * @extends {ol.renderer.canvas.Layer} - * @param {ol.layer.VectorTile} layer VectorTile layer. + * Determines if the argument is an XMLHttpRequest that supports the level 2 + * timeout value and event. + * + * Currently, FF 21.0 OS X has the fields but won't actually call the timeout + * handler. Perhaps the confusion in the bug referenced below hasn't + * entirely been resolved. + * + * @see http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute + * @see https://bugzilla.mozilla.org/show_bug.cgi?id=525816 + * + * @param {!goog.net.XhrLike.OrNative} xhr The request. + * @return {boolean} True if the request supports level 2 timeout. + * @private */ -ol.renderer.canvas.VectorTileLayer = function(layer) { - - goog.base(this, layer); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); +goog.net.XhrIo.shouldUseXhr2Timeout_ = function(xhr) { + return goog.userAgent.IE && + goog.userAgent.isVersionOrHigher(9) && + goog.isNumber(xhr[goog.net.XhrIo.XHR2_TIMEOUT_]) && + goog.isDef(xhr[goog.net.XhrIo.XHR2_ON_TIMEOUT_]); +}; - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - /** - * @private - * @type {Array.<ol.VectorTile>} - */ - this.renderedTiles_ = []; +/** + * @param {string} header An HTTP header key. + * @return {boolean} Whether the key is a content type header (ignoring + * case. + * @private + */ +goog.net.XhrIo.isContentTypeHeader_ = function(header) { + return goog.string.caseInsensitiveEquals( + goog.net.XhrIo.CONTENT_TYPE_HEADER, header); +}; - /** - * @private - * @type {ol.Extent} - */ - this.tmpExtent_ = ol.extent.createEmpty(); - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [NaN, NaN]; +/** + * Creates a new XHR object. + * @return {!goog.net.XhrLike.OrNative} The newly created XHR object. + * @protected + */ +goog.net.XhrIo.prototype.createXhr = function() { + return this.xmlHttpFactory_ ? + this.xmlHttpFactory_.createInstance() : goog.net.XmlHttp(); +}; - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.tmpTransform_ = goog.vec.Mat4.createNumber(); +/** + * The request didn't complete after {@link goog.net.XhrIo#timeoutInterval_} + * milliseconds; raises a {@link goog.net.EventType.TIMEOUT} event and aborts + * the request. + * @private + */ +goog.net.XhrIo.prototype.timeout_ = function() { + if (typeof goog == 'undefined') { + // If goog is undefined then the callback has occurred as the application + // is unloading and will error. Thus we let it silently fail. + } else if (this.xhr_) { + this.lastError_ = 'Timed out after ' + this.timeoutInterval_ + + 'ms, aborting'; + this.lastErrorCode_ = goog.net.ErrorCode.TIMEOUT; + goog.log.fine(this.logger_, this.formatMsg_(this.lastError_)); + this.dispatchEvent(goog.net.EventType.TIMEOUT); + this.abort(goog.net.ErrorCode.TIMEOUT); + } }; -goog.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.Layer); /** - * @inheritDoc + * Something errorred, so inactivate, fire error callback and clean up + * @param {goog.net.ErrorCode} errorCode The error code. + * @param {Error} err The error object. + * @private */ -ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = - function(frameState, layerState, context) { +goog.net.XhrIo.prototype.error_ = function(errorCode, err) { + this.active_ = false; + if (this.xhr_) { + this.inAbort_ = true; + this.xhr_.abort(); // Ensures XHR isn't hung (FF) + this.inAbort_ = false; + } + this.lastError_ = err; + this.lastErrorCode_ = errorCode; + this.dispatchErrors_(); + this.cleanUpXhr_(); +}; - var pixelRatio = frameState.pixelRatio; - var skippedFeatureUids = layerState.managed ? - frameState.skippedFeatureUids : {}; - var viewState = frameState.viewState; - var center = viewState.center; - var projection = viewState.projection; - var resolution = viewState.resolution; - var rotation = viewState.rotation; - var layer = this.getLayer(); - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - var transform = this.getTransform(frameState, 0); +/** + * Dispatches COMPLETE and ERROR in case of an error. This ensures that we do + * not dispatch multiple error events. + * @private + */ +goog.net.XhrIo.prototype.dispatchErrors_ = function() { + if (!this.errorDispatched_) { + this.errorDispatched_ = true; + this.dispatchEvent(goog.net.EventType.COMPLETE); + this.dispatchEvent(goog.net.EventType.ERROR); + } +}; - this.dispatchPreComposeEvent(context, frameState, transform); - var replayContext; - if (layer.hasListener(ol.render.EventType.RENDER)) { - // resize and clear - this.context_.canvas.width = context.canvas.width; - this.context_.canvas.height = context.canvas.height; - replayContext = this.context_; - } else { - replayContext = context; +/** + * Abort the current XMLHttpRequest + * @param {goog.net.ErrorCode=} opt_failureCode Optional error code to use - + * defaults to ABORT. + */ +goog.net.XhrIo.prototype.abort = function(opt_failureCode) { + if (this.xhr_ && this.active_) { + goog.log.fine(this.logger_, this.formatMsg_('Aborting')); + this.active_ = false; + this.inAbort_ = true; + this.xhr_.abort(); + this.inAbort_ = false; + this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT; + this.dispatchEvent(goog.net.EventType.COMPLETE); + this.dispatchEvent(goog.net.EventType.ABORT); + this.cleanUpXhr_(); } - // for performance reasons, context.save / context.restore is not used - // to save and restore the transformation matrix and the opacity. - // see http://jsperf.com/context-save-restore-versus-variable - var alpha = replayContext.globalAlpha; - replayContext.globalAlpha = layerState.opacity; +}; - var tilesToDraw = this.renderedTiles_; - var tileGrid = source.getTileGrid(); - var currentZ, i, ii, origin, tile, tileSize; - var tilePixelRatio, tilePixelResolution, tilePixelSize, tileResolution; - for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { - tile = tilesToDraw[i]; - currentZ = tile.getTileCoord()[0]; - tileSize = tileGrid.getTileSize(currentZ); - tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); - tilePixelRatio = tilePixelSize[0] / - ol.size.toSize(tileSize, this.tmpSize_)[0]; - tileResolution = tileGrid.getResolution(currentZ); - tilePixelResolution = tileResolution / tilePixelRatio; - if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) { - origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( - tile.getTileCoord(), this.tmpExtent_)); - transform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, - pixelRatio * frameState.size[0] / 2, - pixelRatio * frameState.size[1] / 2, - pixelRatio * tilePixelResolution / resolution, - pixelRatio * tilePixelResolution / resolution, - viewState.rotation, - (origin[0] - center[0]) / tilePixelResolution, - (center[1] - origin[1]) / tilePixelResolution); +/** + * Nullifies all callbacks to reduce risks of leaks. + * @override + * @protected + */ +goog.net.XhrIo.prototype.disposeInternal = function() { + if (this.xhr_) { + // We explicitly do not call xhr_.abort() unless active_ is still true. + // This is to avoid unnecessarily aborting a successful request when + // dispose() is called in a callback triggered by a complete response, but + // in which browser cleanup has not yet finished. + // (See http://b/issue?id=1684217.) + if (this.active_) { + this.active_ = false; + this.inAbort_ = true; + this.xhr_.abort(); + this.inAbort_ = false; } - tile.getReplayState().replayGroup.replay(replayContext, pixelRatio, - transform, rotation, skippedFeatureUids); + this.cleanUpXhr_(true); } - transform = this.getTransform(frameState, 0); + goog.net.XhrIo.base(this, 'disposeInternal'); +}; - if (replayContext != context) { - this.dispatchRenderEvent(replayContext, frameState, transform); - context.drawImage(replayContext.canvas, 0, 0); - } - replayContext.globalAlpha = alpha; - this.dispatchPostComposeEvent(context, frameState, transform); +/** + * Internal handler for the XHR object's readystatechange event. This method + * checks the status and the readystate and fires the correct callbacks. + * If the request has ended, the handlers are cleaned up and the XHR object is + * nullified. + * @private + */ +goog.net.XhrIo.prototype.onReadyStateChange_ = function() { + if (this.isDisposed()) { + // This method is the target of an untracked goog.Timer.callOnce(). + return; + } + if (!this.inOpen_ && !this.inSend_ && !this.inAbort_) { + // Were not being called from within a call to this.xhr_.send + // this.xhr_.abort, or this.xhr_.open, so this is an entry point + this.onReadyStateChangeEntryPoint_(); + } else { + this.onReadyStateChangeHelper_(); + } }; /** - * @param {ol.VectorTile} tile Tile. - * @param {ol.layer.VectorTile} layer Vector tile layer. - * @param {number} pixelRatio Pixel ratio. + * Used to protect the onreadystatechange handler entry point. Necessary + * as {#onReadyStateChange_} maybe called from within send or abort, this + * method is only called when {#onReadyStateChange_} is called as an + * entry point. + * {@see #protectEntryPoints} + * @private */ -ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, - layer, pixelRatio) { - var revision = layer.getRevision(); - var renderOrder = layer.getRenderOrder() || null; +goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = function() { + this.onReadyStateChangeHelper_(); +}; - var replayState = tile.getReplayState(); - if (!replayState.dirty && replayState.renderedRevision == revision && - replayState.renderedRenderOrder == renderOrder) { + +/** + * Helper for {@link #onReadyStateChange_}. This is used so that + * entry point calls to {@link #onReadyStateChange_} can be routed through + * {@link #onReadyStateChangeEntryPoint_}. + * @private + */ +goog.net.XhrIo.prototype.onReadyStateChangeHelper_ = function() { + if (!this.active_) { + // can get called inside abort call return; } - // FIXME dispose of old replayGroup in post render - goog.dispose(replayState.replayGroup); - replayState.replayGroup = null; - replayState.dirty = false; + if (typeof goog == 'undefined') { + // NOTE(user): If goog is undefined then the callback has occurred as the + // application is unloading and will error. Thus we let it silently fail. + + } else if ( + this.xhrOptions_[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] && + this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE && + this.getStatus() == 2) { + // NOTE(user): In IE if send() errors on a *local* request the readystate + // is still changed to COMPLETE. We need to ignore it and allow the + // try/catch around send() to pick up the error. + goog.log.fine(this.logger_, this.formatMsg_( + 'Local request error detected and ignored')); - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - var tileGrid = source.getTileGrid(); - var tileCoord = tile.getTileCoord(); - var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; - var extent; - if (pixelSpace) { - var tilePixelSize = source.getTilePixelSize(tileCoord[0], pixelRatio, - tile.getProjection()); - extent = [0, 0, tilePixelSize[0], tilePixelSize[1]]; } else { - extent = tileGrid.getTileCoordExtent(tileCoord); - } - var resolution = tileGrid.getResolution(tileCoord[0]); - var tileResolution = pixelSpace ? source.getTilePixelRatio() : resolution; - replayState.dirty = false; - var replayGroup = new ol.render.canvas.ReplayGroup(0, extent, - tileResolution, layer.getRenderBuffer()); - var squaredTolerance = ol.renderer.vector.getSquaredTolerance( - tileResolution, pixelRatio); - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @this {ol.renderer.canvas.VectorTileLayer} - */ - function renderFeature(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - goog.asserts.assertInstanceof(feature, ol.Feature, 'Got an ol.Feature'); - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = layer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - if (!goog.isArray(styles)) { - styles = [styles]; - } - var dirty = this.renderFeature(feature, squaredTolerance, styles, - replayGroup); - this.dirty_ = this.dirty_ || dirty; - replayState.dirty = replayState.dirty || dirty; + // In IE when the response has been cached we sometimes get the callback + // from inside the send call and this usually breaks code that assumes that + // XhrIo is asynchronous. If that is the case we delay the callback + // using a timer. + if (this.inSend_ && + this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE) { + goog.Timer.callOnce(this.onReadyStateChange_, 0, this); + return; } - } - - var features = tile.getFeatures(); - if (renderOrder && renderOrder !== replayState.renderedRenderOrder) { - features.sort(renderOrder); - } - features.forEach(renderFeature, this); - - replayGroup.finish(); - replayState.renderedRevision = revision; - replayState.renderedRenderOrder = renderOrder; - replayState.replayGroup = replayGroup; -}; + this.dispatchEvent(goog.net.EventType.READY_STATE_CHANGE); + // readyState indicates the transfer has finished + if (this.isComplete()) { + goog.log.fine(this.logger_, this.formatMsg_('Request complete')); -/** - * @inheritDoc - */ -ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var layer = this.getLayer(); - var layerState = frameState.layerStates[goog.getUid(layer)]; - /** @type {Object.<string, boolean>} */ - var features = {}; + this.active_ = false; - var replayables = this.renderedTiles_; - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - var tileGrid = source.getTileGrid(); - var found, tileSpaceCoordinate; - var i, ii, origin, replayGroup; - var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution; - for (i = 0, ii = replayables.length; i < ii; ++i) { - tile = replayables[i]; - tileCoord = tile.getTileCoord(); - tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord, - this.tmpExtent_); - if (!ol.extent.containsCoordinate(tileExtent, coordinate)) { - continue; - } - if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) { - origin = ol.extent.getTopLeft(tileExtent); - tilePixelRatio = source.getTilePixelRatio(); - tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio; - tileSpaceCoordinate = [ - (coordinate[0] - origin[0]) / tileResolution, - (origin[1] - coordinate[1]) / tileResolution - ]; - resolution = tilePixelRatio; - } else { - tileSpaceCoordinate = coordinate; + try { + // Call the specific callbacks for success or failure. Only call the + // success if the status is 200 (HTTP_OK) or 304 (HTTP_CACHED) + if (this.isSuccess()) { + this.dispatchEvent(goog.net.EventType.COMPLETE); + this.dispatchEvent(goog.net.EventType.SUCCESS); + } else { + this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; + this.lastError_ = + this.getStatusText() + ' [' + this.getStatus() + ']'; + this.dispatchErrors_(); + } + } finally { + this.cleanUpXhr_(); + } } - replayGroup = tile.getReplayState().replayGroup; - found = found || replayGroup.forEachFeatureAtCoordinate( - tileSpaceCoordinate, resolution, rotation, - layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); } - return found; }; /** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. + * Internal handler for the XHR object's onprogress event. + * @param {!ProgressEvent} e XHR progress event. * @private */ -ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); +goog.net.XhrIo.prototype.onProgressHandler_ = function(e) { + goog.asserts.assert(e.type === goog.net.EventType.PROGRESS, + 'goog.net.EventType.PROGRESS is of the same type as raw XHR progress.'); + // Redispatch the progress event. + this.dispatchEvent(e); }; /** - * @inheritDoc + * Remove the listener to protect against leaks, and nullify the XMLHttpRequest + * object. + * @param {boolean=} opt_fromDispose If this is from the dispose (don't want to + * fire any events). + * @private */ -ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = - function(frameState, layerState) { - var layer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(layer, ol.layer.VectorTile, - 'layer is an instance of ol.layer.VectorTile'); - var source = layer.getSource(); - goog.asserts.assertInstanceof(source, ol.source.VectorTile, - 'Source is an ol.source.VectorTile'); - - this.updateAttributions( - frameState.attributions, source.getAttributions()); - this.updateLogos(frameState, source); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = layer.getUpdateWhileAnimating(); - var updateWhileInteracting = layer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - - var extent = frameState.extent; - if (layerState.extent) { - extent = ol.extent.getIntersection(extent, layerState.extent); - } - if (ol.extent.isEmpty(extent)) { - // Return false to prevent the rendering of the layer. - return false; - } - - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - - var tileGrid = source.getTileGrid(); - var resolutions = tileGrid.getResolutions(); - var z = resolutions.length - 1; - while (z > 0 && resolutions[z] < resolution) { - --z; - } - var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - this.updateUsedTiles(frameState.usedTiles, source, z, tileRange); - this.manageTilePyramid(frameState, source, tileGrid, pixelRatio, - projection, extent, z, layer.getPreload()); - this.scheduleExpireCache(frameState, source); - - /** - * @type {Object.<number, Object.<string, ol.VectorTile>>} - */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - - var findLoadedTiles = this.createLoadedTileFinder(source, projection, - tilesToDrawByZ); - - var useInterimTilesOnError = layer.getUseInterimTilesOnError(); - - var tmpExtent = this.tmpExtent_; - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, fullyLoaded, tile, tileState, x, y; - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - - tile = source.getTile(z, x, y, pixelRatio, projection); - goog.asserts.assertInstanceof(tile, ol.VectorTile, - 'Tile is an ol.VectorTile'); - tileState = tile.getState(); - if (tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && !useInterimTilesOnError)) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } +goog.net.XhrIo.prototype.cleanUpXhr_ = function(opt_fromDispose) { + if (this.xhr_) { + // Cancel any pending timeout event handler. + this.cleanUpTimeoutTimer_(); - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } + // Save reference so we can mark it as closed after the READY event. The + // READY event may trigger another request, thus we must nullify this.xhr_ + var xhr = this.xhr_; + var clearedOnReadyStateChange = + this.xhrOptions_[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] ? + goog.nullFunction : null; + this.xhr_ = null; + this.xhrOptions_ = null; + if (!opt_fromDispose) { + this.dispatchEvent(goog.net.EventType.READY); } - } - this.dirty_ = false; - - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - zs.sort(); - var replayables = []; - var i, ii, currentZ, tileCoordKey, tilesToDraw; - for (i = 0, ii = zs.length; i < ii; ++i) { - currentZ = zs[i]; - tilesToDraw = tilesToDrawByZ[currentZ]; - for (tileCoordKey in tilesToDraw) { - tile = tilesToDraw[tileCoordKey]; - if (tile.getState() == ol.TileState.LOADED) { - replayables.push(tile); - this.createReplayGroup(tile, layer, pixelRatio); - } + try { + // NOTE(user): Not nullifying in FireFox can still leak if the callbacks + // are defined in the same scope as the instance of XhrIo. But, IE doesn't + // allow you to set the onreadystatechange to NULL so nullFunction is + // used. + xhr.onreadystatechange = clearedOnReadyStateChange; + } catch (e) { + // This seems to occur with a Gears HTTP request. Delayed the setting of + // this onreadystatechange until after READY is sent out and catching the + // error to see if we can track down the problem. + goog.log.error(this.logger_, + 'Problem encountered resetting onreadystatechange: ' + e.message); } } - - this.renderedTiles_ = replayables; - - return true; }; /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {number} squaredTolerance Squared tolerance. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. + * Make sure the timeout timer isn't running. + * @private */ -ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = - function(feature, squaredTolerance, styles, replayGroup) { - if (!styles) { - return false; +goog.net.XhrIo.prototype.cleanUpTimeoutTimer_ = function() { + if (this.xhr_ && this.useXhr2Timeout_) { + this.xhr_[goog.net.XhrIo.XHR2_ON_TIMEOUT_] = null; } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], squaredTolerance, - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, squaredTolerance, - this.handleStyleImageChange_, this) || loading; + if (goog.isNumber(this.timeoutId_)) { + goog.Timer.clear(this.timeoutId_); + this.timeoutId_ = null; } - return loading; }; -// FIXME offset panning - -goog.provide('ol.renderer.canvas.Map'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.RendererType'); -goog.require('ol.css'); -goog.require('ol.dom'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.layer.VectorTile'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.canvas.ImageLayer'); -goog.require('ol.renderer.canvas.Layer'); -goog.require('ol.renderer.canvas.TileLayer'); -goog.require('ol.renderer.canvas.VectorLayer'); -goog.require('ol.renderer.canvas.VectorTileLayer'); -goog.require('ol.source.State'); -goog.require('ol.vec.Mat4'); - - /** - * @constructor - * @extends {ol.renderer.Map} - * @param {Element} container Container. - * @param {ol.Map} map Map. + * @return {boolean} Whether there is an active request. */ -ol.renderer.canvas.Map = function(container, map) { - - goog.base(this, container, map); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = this.context_.canvas; - - this.canvas_.style.width = '100%'; - this.canvas_.style.height = '100%'; - this.canvas_.className = ol.css.CLASS_UNSELECTABLE; - goog.dom.insertChildAt(container, this.canvas_, 0); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; +goog.net.XhrIo.prototype.isActive = function() { + return !!this.xhr_; +}; - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); +/** + * @return {boolean} Whether the request has completed. + */ +goog.net.XhrIo.prototype.isComplete = function() { + return this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE; }; -goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map); /** - * @inheritDoc + * @return {boolean} Whether the request completed with a success. */ -ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) { - if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { - return new ol.renderer.canvas.ImageLayer(layer); - } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { - return new ol.renderer.canvas.TileLayer(layer); - } else if (ol.ENABLE_VECTOR_TILE && layer instanceof ol.layer.VectorTile) { - return new ol.renderer.canvas.VectorTileLayer(layer); - } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { - return new ol.renderer.canvas.VectorLayer(layer); - } else { - goog.asserts.fail('unexpected layer configuration'); - return null; - } +goog.net.XhrIo.prototype.isSuccess = function() { + var status = this.getStatus(); + // A zero status code is considered successful for local files. + return goog.net.HttpStatus.isSuccess(status) || + status === 0 && !this.isLastUriEffectiveSchemeHttp_(); }; /** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. + * @return {boolean} whether the effective scheme of the last URI that was + * fetched was 'http' or 'https'. * @private */ -ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ = - function(type, frameState) { - var map = this.getMap(); - var context = this.context_; - if (map.hasListener(type)) { - var extent = frameState.extent; - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var rotation = viewState.rotation; +goog.net.XhrIo.prototype.isLastUriEffectiveSchemeHttp_ = function() { + var scheme = goog.uri.utils.getEffectiveScheme(String(this.lastUri_)); + return goog.net.XhrIo.HTTP_SCHEME_PATTERN.test(scheme); +}; - var transform = this.getTransform(frameState); - var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio, - extent, transform, rotation); - var composeEvent = new ol.render.Event(type, map, vectorContext, - frameState, context, null); - map.dispatchEvent(composeEvent); +/** + * Get the readystate from the Xhr object + * Will only return correct result when called from the context of a callback + * @return {goog.net.XmlHttp.ReadyState} goog.net.XmlHttp.ReadyState.*. + */ +goog.net.XhrIo.prototype.getReadyState = function() { + return this.xhr_ ? + /** @type {goog.net.XmlHttp.ReadyState} */ (this.xhr_.readyState) : + goog.net.XmlHttp.ReadyState.UNINITIALIZED; +}; - vectorContext.flush(); + +/** + * Get the status from the Xhr object + * Will only return correct result when called from the context of a callback + * @return {number} Http status. + */ +goog.net.XhrIo.prototype.getStatus = function() { + /** + * IE doesn't like you checking status until the readystate is greater than 2 + * (i.e. it is receiving or complete). The try/catch is used for when the + * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. + * @preserveTry + */ + try { + return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? + this.xhr_.status : -1; + } catch (e) { + return -1; } }; /** - * @param {olx.FrameState} frameState Frame state. - * @protected - * @return {!goog.vec.Mat4.Number} Transform. + * Get the status text from the Xhr object + * Will only return correct result when called from the context of a callback + * @return {string} Status text. */ -ol.renderer.canvas.Map.prototype.getTransform = function(frameState) { - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var resolution = viewState.resolution; - return ol.vec.Mat4.makeTransform2D(this.transform_, - this.canvas_.width / 2, this.canvas_.height / 2, - pixelRatio / resolution, -pixelRatio / resolution, - -viewState.rotation, - -viewState.center[0], -viewState.center[1]); +goog.net.XhrIo.prototype.getStatusText = function() { + /** + * IE doesn't like you checking status until the readystate is greater than 2 + * (i.e. it is recieving or complete). The try/catch is used for when the + * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. + * @preserveTry + */ + try { + return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? + this.xhr_.statusText : ''; + } catch (e) { + goog.log.fine(this.logger_, 'Can not get status: ' + e.message); + return ''; + } }; /** - * @inheritDoc + * Get the last Uri that was requested + * @return {string} Last Uri. */ -ol.renderer.canvas.Map.prototype.getType = function() { - return ol.RendererType.CANVAS; +goog.net.XhrIo.prototype.getLastUri = function() { + return String(this.lastUri_); }; /** - * @inheritDoc + * Get the response text from the Xhr object + * Will only return correct result when called from the context of a callback. + * @return {string} Result from the server, or '' if no result available. */ -ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { - - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, false); - this.renderedVisible_ = false; - } - return; +goog.net.XhrIo.prototype.getResponseText = function() { + /** @preserveTry */ + try { + return this.xhr_ ? this.xhr_.responseText : ''; + } catch (e) { + // http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute + // states that responseText should return '' (and responseXML null) + // when the state is not LOADING or DONE. Instead, IE can + // throw unexpected exceptions, for example when a request is aborted + // or no data is available yet. + goog.log.fine(this.logger_, 'Can not get responseText: ' + e.message); + return ''; } +}; - var context = this.context_; - var width = frameState.size[0] * frameState.pixelRatio; - var height = frameState.size[1] * frameState.pixelRatio; - if (this.canvas_.width != width || this.canvas_.height != height) { - this.canvas_.width = width; - this.canvas_.height = height; - } else { - context.clearRect(0, 0, this.canvas_.width, this.canvas_.height); + +/** + * Get the response body from the Xhr object. This property is only available + * in IE since version 7 according to MSDN: + * http://msdn.microsoft.com/en-us/library/ie/ms534368(v=vs.85).aspx + * Will only return correct result when called from the context of a callback. + * + * One option is to construct a VBArray from the returned object and convert + * it to a JavaScript array using the toArray method: + * {@code (new window['VBArray'](xhrIo.getResponseBody())).toArray()} + * This will result in an array of numbers in the range of [0..255] + * + * Another option is to use the VBScript CStr method to convert it into a + * string as outlined in http://stackoverflow.com/questions/1919972 + * + * @return {Object} Binary result from the server or null if not available. + */ +goog.net.XhrIo.prototype.getResponseBody = function() { + /** @preserveTry */ + try { + if (this.xhr_ && 'responseBody' in this.xhr_) { + return this.xhr_['responseBody']; + } + } catch (e) { + // IE can throw unexpected exceptions, for example when a request is aborted + // or no data is yet available. + goog.log.fine(this.logger_, 'Can not get responseBody: ' + e.message); } + return null; +}; - this.calculateMatrices2D(frameState); - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); +/** + * Get the response XML from the Xhr object + * Will only return correct result when called from the context of a callback. + * @return {Document} The DOM Document representing the XML file, or null + * if no result available. + */ +goog.net.XhrIo.prototype.getResponseXml = function() { + /** @preserveTry */ + try { + return this.xhr_ ? this.xhr_.responseXML : null; + } catch (e) { + goog.log.fine(this.logger_, 'Can not get responseXML: ' + e.message); + return null; + } +}; - var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - var viewResolution = frameState.viewState.resolution; - var i, ii, layer, layerRenderer, layerState; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerState = layerStatesArray[i]; - layer = layerState.layer; - layerRenderer = this.getLayerRenderer(layer); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.canvas.Layer, - 'layerRenderer is an instance of ol.renderer.canvas.Layer'); - if (!ol.layer.Layer.visibleAtResolution(layerState, viewResolution) || - layerState.sourceState != ol.source.State.READY) { - continue; - } - if (layerRenderer.prepareFrame(frameState, layerState)) { - layerRenderer.composeFrame(frameState, layerState, context); - } +/** + * Get the response and evaluates it as JSON from the Xhr object + * Will only return correct result when called from the context of a callback + * @param {string=} opt_xssiPrefix Optional XSSI prefix string to use for + * stripping of the response before parsing. This needs to be set only if + * your backend server prepends the same prefix string to the JSON response. + * @return {Object|undefined} JavaScript object. + */ +goog.net.XhrIo.prototype.getResponseJson = function(opt_xssiPrefix) { + if (!this.xhr_) { + return undefined; } - this.dispatchComposeEvent_( - ol.render.EventType.POSTCOMPOSE, frameState); - - if (!this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, true); - this.renderedVisible_ = true; + var responseText = this.xhr_.responseText; + if (opt_xssiPrefix && responseText.indexOf(opt_xssiPrefix) == 0) { + responseText = responseText.substring(opt_xssiPrefix.length); } - this.scheduleRemoveUnusedLayerRenderers(frameState); - this.scheduleExpireIconCache(frameState); + return goog.json.parse(responseText); }; -goog.provide('ol.renderer.dom.Layer'); - -goog.require('ol'); -goog.require('ol.layer.Layer'); -goog.require('ol.renderer.Layer'); +/** + * Get the response as the type specificed by {@link #setResponseType}. At time + * of writing, this is only directly supported in very recent versions of WebKit + * (10.0.612.1 dev and later). If the field is not supported directly, we will + * try to emulate it. + * + * Emulating the response means following the rules laid out at + * http://www.w3.org/TR/XMLHttpRequest/#the-response-attribute + * + * On browsers with no support for this (Chrome < 10, Firefox < 4, etc), only + * response types of DEFAULT or TEXT may be used, and the response returned will + * be the text response. + * + * On browsers with Mozilla's draft support for array buffers (Firefox 4, 5), + * only response types of DEFAULT, TEXT, and ARRAY_BUFFER may be used, and the + * response returned will be either the text response or the Mozilla + * implementation of the array buffer response. + * + * On browsers will full support, any valid response type supported by the + * browser may be used, and the response provided by the browser will be + * returned. + * + * @return {*} The response. + */ +goog.net.XhrIo.prototype.getResponse = function() { + /** @preserveTry */ + try { + if (!this.xhr_) { + return null; + } + if ('response' in this.xhr_) { + return this.xhr_.response; + } + switch (this.responseType_) { + case goog.net.XhrIo.ResponseType.DEFAULT: + case goog.net.XhrIo.ResponseType.TEXT: + return this.xhr_.responseText; + // DOCUMENT and BLOB don't need to be handled here because they are + // introduced in the same spec that adds the .response field, and would + // have been caught above. + // ARRAY_BUFFER needs an implementation for Firefox 4, where it was + // implemented using a draft spec rather than the final spec. + case goog.net.XhrIo.ResponseType.ARRAY_BUFFER: + if ('mozResponseArrayBuffer' in this.xhr_) { + return this.xhr_.mozResponseArrayBuffer; + } + } + // Fell through to a response type that is not supported on this browser. + goog.log.error(this.logger_, + 'Response type ' + this.responseType_ + ' is not ' + + 'supported on this browser'); + return null; + } catch (e) { + goog.log.fine(this.logger_, 'Can not get response: ' + e.message); + return null; + } +}; /** - * @constructor - * @extends {ol.renderer.Layer} - * @param {ol.layer.Layer} layer Layer. - * @param {!Element} target Target. + * Get the value of the response-header with the given name from the Xhr object + * Will only return correct result when called from the context of a callback + * and the request has completed + * @param {string} key The name of the response-header to retrieve. + * @return {string|undefined} The value of the response-header named key. */ -ol.renderer.dom.Layer = function(layer, target) { - - goog.base(this, layer); +goog.net.XhrIo.prototype.getResponseHeader = function(key) { + return this.xhr_ && this.isComplete() ? + this.xhr_.getResponseHeader(key) : undefined; +}; - /** - * @type {!Element} - * @protected - */ - this.target = target; +/** + * Gets the text of all the headers in the response. + * Will only return correct result when called from the context of a callback + * and the request has completed. + * @return {string} The value of the response headers or empty string. + */ +goog.net.XhrIo.prototype.getAllResponseHeaders = function() { + return this.xhr_ && this.isComplete() ? + this.xhr_.getAllResponseHeaders() : ''; }; -goog.inherits(ol.renderer.dom.Layer, ol.renderer.Layer); /** - * Clear rendered elements. + * Returns all response headers as a key-value map. + * Multiple values for the same header key can be combined into one, + * separated by a comma and a space. + * Note that the native getResponseHeader method for retrieving a single header + * does a case insensitive match on the header name. This method does not + * include any case normalization logic, it will just return a key-value + * representation of the headers. + * See: http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method + * @return {!Object<string, string>} An object with the header keys as keys + * and header values as values. */ -ol.renderer.dom.Layer.prototype.clearFrame = ol.nullFunction; +goog.net.XhrIo.prototype.getResponseHeaders = function() { + var headersObject = {}; + var headersArray = this.getAllResponseHeaders().split('\r\n'); + for (var i = 0; i < headersArray.length; i++) { + if (goog.string.isEmptyOrWhitespace(headersArray[i])) { + continue; + } + var keyValue = goog.string.splitLimit(headersArray[i], ': ', 2); + if (headersObject[keyValue[0]]) { + headersObject[keyValue[0]] += ', ' + keyValue[1]; + } else { + headersObject[keyValue[0]] = keyValue[1]; + } + } + return headersObject; +}; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. + * Get the last error message + * @return {goog.net.ErrorCode} Last error code. */ -ol.renderer.dom.Layer.prototype.composeFrame = ol.nullFunction; +goog.net.XhrIo.prototype.getLastErrorCode = function() { + return this.lastErrorCode_; +}; /** - * @return {!Element} Target. + * Get the last error message + * @return {string} Last error message. */ -ol.renderer.dom.Layer.prototype.getTarget = function() { - return this.target; +goog.net.XhrIo.prototype.getLastError = function() { + return goog.isString(this.lastError_) ? this.lastError_ : + String(this.lastError_); }; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @return {boolean} whether composeFrame should be called. + * Adds the last method, status and URI to the message. This is used to add + * this information to the logging calls. + * @param {string} msg The message text that we want to add the extra text to. + * @return {string} The message with the extra text appended. + * @private */ -ol.renderer.dom.Layer.prototype.prepareFrame = goog.abstractMethod; +goog.net.XhrIo.prototype.formatMsg_ = function(msg) { + return msg + ' [' + this.lastMethod_ + ' ' + this.lastUri_ + ' ' + + this.getStatus() + ']'; +}; -goog.provide('ol.renderer.dom.ImageLayer'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ImageBase'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.proj'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.vec.Mat4'); +// Register the xhr handler as an entry point, so that +// it can be monitored for exception handling, etc. +goog.debug.entryPointRegistry.register( + /** + * @param {function(!Function): !Function} transformer The transforming + * function. + */ + function(transformer) { + goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = + transformer(goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); + }); +goog.provide('ol.format.FormatType'); /** - * @constructor - * @extends {ol.renderer.dom.Layer} - * @param {ol.layer.Image} imageLayer Image layer. + * @enum {string} */ -ol.renderer.dom.ImageLayer = function(imageLayer) { - var target = goog.dom.createElement('DIV'); - target.style.position = 'absolute'; +ol.format.FormatType = { + ARRAY_BUFFER: 'arraybuffer', + JSON: 'json', + TEXT: 'text', + XML: 'xml' +}; - goog.base(this, imageLayer, target); +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - /** - * The last rendered image. - * @private - * @type {?ol.ImageBase} - */ - this.image_ = null; +/** + * @fileoverview + * XML utilities. + * + */ - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumberIdentity(); +goog.provide('goog.dom.xml'); -}; -goog.inherits(ol.renderer.dom.ImageLayer, ol.renderer.dom.Layer); +goog.require('goog.dom'); +goog.require('goog.dom.NodeType'); +goog.require('goog.userAgent'); /** - * @inheritDoc + * Max XML size for MSXML2. Used to prevent potential DoS attacks. + * @type {number} */ -ol.renderer.dom.ImageLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var layer = this.getLayer(); - var source = layer.getSource(); - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var skippedFeatureUids = frameState.skippedFeatureUids; - return source.forEachFeatureAtCoordinate( - coordinate, resolution, rotation, skippedFeatureUids, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - return callback.call(thisArg, feature, layer); - }); -}; +goog.dom.xml.MAX_XML_SIZE_KB = 2 * 1024; // In kB /** - * @inheritDoc + * Max XML size for MSXML2. Used to prevent potential DoS attacks. + * @type {number} */ -ol.renderer.dom.ImageLayer.prototype.clearFrame = function() { - goog.dom.removeChildren(this.target); - this.image_ = null; -}; +goog.dom.xml.MAX_ELEMENT_DEPTH = 256; // Same default as MSXML6. /** - * @inheritDoc + * Check for ActiveXObject support by the browser. + * @return {boolean} true if browser has ActiveXObject support. + * @private */ -ol.renderer.dom.ImageLayer.prototype.prepareFrame = - function(frameState, layerState) { +goog.dom.xml.hasActiveXObjectSupport_ = function() { + if (!goog.userAgent.IE) { + // Avoid raising useless exception in case code is not compiled + // and browser is not MSIE. + return false; + } + try { + // Due to lot of changes in IE 9, 10 & 11 behaviour and ActiveX being + // totally disableable using MSIE's security level, trying to create the + // ActiveXOjbect is a lot more reliable than testing for the existance of + // window.ActiveXObject + new ActiveXObject('MSXML2.DOMDocument'); + return true; + } catch (e) { + return false; + } +}; - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewResolution = viewState.resolution; - var viewRotation = viewState.rotation; - var image = this.image_; - var imageLayer = this.getLayer(); - goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, - 'layer is an instance of ol.layer.Image'); - var imageSource = imageLayer.getSource(); +/** + * True if browser has ActiveXObject support. + * Possible override if this test become wrong in coming IE versions. + * @type {boolean} + */ +goog.dom.xml.ACTIVEX_SUPPORT = + goog.userAgent.IE && goog.dom.xml.hasActiveXObjectSupport_(); - var hints = frameState.viewHints; - var renderedExtent = frameState.extent; - if (layerState.extent !== undefined) { - renderedExtent = ol.extent.getIntersection( - renderedExtent, layerState.extent); +/** + * Creates an XML document appropriate for the current JS runtime + * @param {string=} opt_rootTagName The root tag name. + * @param {string=} opt_namespaceUri Namespace URI of the document element. + * @param {boolean=} opt_preferActiveX Whether to default to ActiveXObject to + * create Document in IE. Use this if you need xpath support in IE (e.g., + * selectSingleNode or selectNodes), but be aware that the ActiveXObject does + * not support various DOM-specific Document methods and attributes. + * @return {Document} The new document. + * @throws {Error} if browser does not support creating new documents or + * namespace is provided without a root tag name. + */ +goog.dom.xml.createDocument = function(opt_rootTagName, opt_namespaceUri, + opt_preferActiveX) { + if (opt_namespaceUri && !opt_rootTagName) { + throw Error("Can't create document with namespace and no root tag"); } - - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && - !ol.extent.isEmpty(renderedExtent)) { - var projection = viewState.projection; - if (!ol.ENABLE_RASTER_REPROJECTION) { - var sourceProjection = imageSource.getProjection(); - if (sourceProjection) { - goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), - 'projection and sourceProjection are equivalent'); - projection = sourceProjection; - } - } - var image_ = imageSource.getImage(renderedExtent, viewResolution, - frameState.pixelRatio, projection); - if (image_) { - var loaded = this.loadImage(image_); - if (loaded) { - image = image_; + // If document.implementation.createDocument is available and they haven't + // explicitly opted to use ActiveXObject when possible. + if (document.implementation && document.implementation.createDocument && + !(goog.dom.xml.ACTIVEX_SUPPORT && opt_preferActiveX)) { + return document.implementation.createDocument(opt_namespaceUri || '', + opt_rootTagName || '', null); + } else if (goog.dom.xml.ACTIVEX_SUPPORT) { + var doc = goog.dom.xml.createMsXmlDocument_(); + if (doc) { + if (opt_rootTagName) { + doc.appendChild(doc.createNode(goog.dom.NodeType.ELEMENT, + opt_rootTagName, + opt_namespaceUri || '')); } + return doc; } } - - if (image) { - var imageExtent = image.getExtent(); - var imageResolution = image.getResolution(); - var transform = goog.vec.Mat4.createNumber(); - ol.vec.Mat4.makeTransform2D(transform, - frameState.size[0] / 2, frameState.size[1] / 2, - imageResolution / viewResolution, imageResolution / viewResolution, - viewRotation, - (imageExtent[0] - viewCenter[0]) / imageResolution, - (viewCenter[1] - imageExtent[3]) / imageResolution); - if (image != this.image_) { - var imageElement = image.getImage(this); - // Bootstrap sets the style max-width: 100% for all images, which breaks - // prevents the image from being displayed in FireFox. Workaround by - // overriding the max-width style. - imageElement.style.maxWidth = 'none'; - imageElement.style.position = 'absolute'; - goog.dom.removeChildren(this.target); - this.target.appendChild(imageElement); - this.image_ = image; - } - this.setTransform_(transform); - this.updateAttributions(frameState.attributions, image.getAttributions()); - this.updateLogos(frameState, imageSource); - } - - return true; + throw Error('Your browser does not support creating new documents'); }; /** - * @param {goog.vec.Mat4.Number} transform Transform. - * @private + * Creates an XML document from a string + * @param {string} xml The text. + * @param {boolean=} opt_preferActiveX Whether to default to ActiveXObject to + * create Document in IE. Use this if you need xpath support in IE (e.g., + * selectSingleNode or selectNodes), but be aware that the ActiveXObject does + * not support various DOM-specific Document methods and attributes. + * @return {Document} XML document from the text. + * @throws {Error} if browser does not support loading XML documents. */ -ol.renderer.dom.ImageLayer.prototype.setTransform_ = function(transform) { - if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { - ol.dom.transformElement2D(this.target, transform, 6); - goog.vec.Mat4.setFromArray(this.transform_, transform); +goog.dom.xml.loadXml = function(xml, opt_preferActiveX) { + if (typeof DOMParser != 'undefined' && + !(goog.dom.xml.ACTIVEX_SUPPORT && opt_preferActiveX)) { + return new DOMParser().parseFromString(xml, 'application/xml'); + } else if (goog.dom.xml.ACTIVEX_SUPPORT) { + var doc = goog.dom.xml.createMsXmlDocument_(); + doc.loadXML(xml); + return doc; } + throw Error('Your browser does not support loading xml documents'); }; -// FIXME probably need to reset TileLayerZ if offsets get too large -// FIXME when zooming out, preserve higher Z divs to avoid white flash -goog.provide('ol.renderer.dom.TileLayer'); +/** + * Serializes an XML document or subtree to string. + * @param {Document|Element} xml The document or the root node of the subtree. + * @return {string} The serialized XML. + * @throws {Error} if browser does not support XML serialization. + */ +goog.dom.xml.serialize = function(xml) { + // Compatible with IE/ActiveXObject. + var text = xml.xml; + if (text) { + return text; + } + // Compatible with Firefox, Opera and WebKit. + if (typeof XMLSerializer != 'undefined') { + return new XMLSerializer().serializeToString(xml); + } + throw Error('Your browser does not support serializing XML documents'); +}; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.Coordinate'); -goog.require('ol.TileCoord'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Tile'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); -goog.require('ol.tilegrid.TileGrid'); -goog.require('ol.vec.Mat4'); +/** + * Selects a single node using an Xpath expression and a root node + * @param {Node} node The root node. + * @param {string} path Xpath selector. + * @return {Node} The selected node, or null if no matching node. + */ +goog.dom.xml.selectSingleNode = function(node, path) { + if (typeof node.selectSingleNode != 'undefined') { + var doc = goog.dom.getOwnerDocument(node); + if (typeof doc.setProperty != 'undefined') { + doc.setProperty('SelectionLanguage', 'XPath'); + } + return node.selectSingleNode(path); + } else if (document.implementation.hasFeature('XPath', '3.0')) { + var doc = goog.dom.getOwnerDocument(node); + var resolver = doc.createNSResolver(doc.documentElement); + var result = doc.evaluate(path, node, resolver, + XPathResult.FIRST_ORDERED_NODE_TYPE, null); + return result.singleNodeValue; + } + // This browser does not support xpath for the given node. If IE, ensure XML + // Document was created using ActiveXObject + // TODO(joeltine): This should throw instead of return null. + return null; +}; /** - * @constructor - * @extends {ol.renderer.dom.Layer} - * @param {ol.layer.Tile} tileLayer Tile layer. + * Selects multiple nodes using an Xpath expression and a root node + * @param {Node} node The root node. + * @param {string} path Xpath selector. + * @return {(NodeList|Array<Node>)} The selected nodes, or empty array if no + * matching nodes. */ -ol.renderer.dom.TileLayer = function(tileLayer) { - - var target = goog.dom.createElement('DIV'); - target.style.position = 'absolute'; - - goog.base(this, tileLayer, target); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - - /** - * @private - * @type {number} - */ - this.renderedOpacity_ = 1; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; - - /** - * @private - * @type {!Object.<number, ol.renderer.dom.TileLayerZ_>} - */ - this.tileLayerZs_ = {}; - +goog.dom.xml.selectNodes = function(node, path) { + if (typeof node.selectNodes != 'undefined') { + var doc = goog.dom.getOwnerDocument(node); + if (typeof doc.setProperty != 'undefined') { + doc.setProperty('SelectionLanguage', 'XPath'); + } + return node.selectNodes(path); + } else if (document.implementation.hasFeature('XPath', '3.0')) { + var doc = goog.dom.getOwnerDocument(node); + var resolver = doc.createNSResolver(doc.documentElement); + var nodes = doc.evaluate(path, node, resolver, + XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + var results = []; + var count = nodes.snapshotLength; + for (var i = 0; i < count; i++) { + results.push(nodes.snapshotItem(i)); + } + return results; + } else { + // This browser does not support xpath for the given node. If IE, ensure XML + // Document was created using ActiveXObject. + // TODO(joeltine): This should throw instead of return empty array. + return []; + } }; -goog.inherits(ol.renderer.dom.TileLayer, ol.renderer.dom.Layer); /** - * @inheritDoc + * Sets multiple attributes on an element. Differs from goog.dom.setProperties + * in that it exclusively uses the element's setAttributes method. Use this + * when you need to ensure that the exact property is available as an attribute + * and can be read later by the native getAttribute method. + * @param {!Element} element XML or DOM element to set attributes on. + * @param {!Object<string, string>} attributes Map of property:value pairs. */ -ol.renderer.dom.TileLayer.prototype.clearFrame = function() { - goog.dom.removeChildren(this.target); - this.renderedRevision_ = 0; +goog.dom.xml.setAttributes = function(element, attributes) { + for (var key in attributes) { + if (attributes.hasOwnProperty(key)) { + element.setAttribute(key, attributes[key]); + } + } }; /** - * @inheritDoc + * Creates an instance of the MSXML2.DOMDocument. + * @return {Document} The new document. + * @private */ -ol.renderer.dom.TileLayer.prototype.prepareFrame = - function(frameState, layerState) { - - if (!layerState.visible) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.target, false); - this.renderedVisible_ = false; +goog.dom.xml.createMsXmlDocument_ = function() { + var doc = new ActiveXObject('MSXML2.DOMDocument'); + if (doc) { + // Prevent potential vulnerabilities exposed by MSXML2, see + // http://b/1707300 and http://wiki/Main/ISETeamXMLAttacks for details. + doc.resolveExternals = false; + doc.validateOnParse = false; + // Add a try catch block because accessing these properties will throw an + // error on unsupported MSXML versions. This affects Windows machines + // running IE6 or IE7 that are on XP SP2 or earlier without MSXML updates. + // See http://msdn.microsoft.com/en-us/library/ms766391(VS.85).aspx for + // specific details on which MSXML versions support these properties. + try { + doc.setProperty('ProhibitDTD', true); + doc.setProperty('MaxXMLSize', goog.dom.xml.MAX_XML_SIZE_KB); + doc.setProperty('MaxElementDepth', goog.dom.xml.MAX_ELEMENT_DEPTH); + } catch (e) { + // No-op. } - return true; - } - - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var projection = viewState.projection; - - var tileLayer = this.getLayer(); - goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, - 'layer is an instance of ol.layer.Tile'); - var tileSource = tileLayer.getSource(); - var tileGrid = tileSource.getTileGridForProjection(projection); - var tileGutter = tileSource.getGutter(); - var z = tileGrid.getZForResolution(viewState.resolution); - var tileResolution = tileGrid.getResolution(z); - var center = viewState.center; - var extent; - if (tileResolution == viewState.resolution) { - center = this.snapCenterToPixel(center, tileResolution, frameState.size); - extent = ol.extent.getForViewAndSize( - center, tileResolution, viewState.rotation, frameState.size); - } else { - extent = frameState.extent; } + return doc; +}; - if (layerState.extent !== undefined) { - extent = ol.extent.getIntersection(extent, layerState.extent); - } +goog.provide('ol.xml'); - var tileRange = tileGrid.getTileRangeForExtentAndResolution( - extent, tileResolution); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.dom.xml'); +goog.require('goog.object'); +goog.require('goog.userAgent'); - /** @type {Object.<number, Object.<string, ol.Tile>>} */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; - var findLoadedTiles = this.createLoadedTileFinder( - tileSource, projection, tilesToDrawByZ); +/** + * When using {@link ol.xml.makeChildAppender} or + * {@link ol.xml.makeSimpleNodeFactory}, the top `objectStack` item needs to + * have this structure. + * @typedef {{node:Node}} + */ +ol.xml.NodeStackItem; - var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); - var tmpExtent = ol.extent.createEmpty(); - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, drawable, fullyLoaded, tile, tileState, x, y; - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - tileState = tile.getState(); - drawable = tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - tileState == ol.TileState.ERROR && !useInterimTilesOnError; - if (!drawable && tile.interimTile) { - tile = tile.interimTile; - } - goog.asserts.assert(tile); - tileState = tile.getState(); - if (tileState == ol.TileState.LOADED) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } else if (tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && - !useInterimTilesOnError)) { - continue; - } - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } +/** + * @typedef {function(Node, Array.<*>)} + */ +ol.xml.Parser; - } - } +/** + * @typedef {function(Node, *, Array.<*>)} + */ +ol.xml.Serializer; - // If the tile source revision changes, we destroy the existing DOM structure - // so that a new one will be created. It would be more efficient to modify - // the existing structure. - var tileLayerZ, tileLayerZKey; - if (this.renderedRevision_ != tileSource.getRevision()) { - for (tileLayerZKey in this.tileLayerZs_) { - tileLayerZ = this.tileLayerZs_[+tileLayerZKey]; - goog.dom.removeNode(tileLayerZ.target); - } - this.tileLayerZs_ = {}; - this.renderedRevision_ = tileSource.getRevision(); - } - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - goog.array.sort(zs); +/** + * This document should be used when creating nodes for XML serializations. This + * document is also used by {@link ol.xml.createElementNS} and + * {@link ol.xml.setAttributeNS} + * @const + * @type {Document} + */ +ol.xml.DOCUMENT = goog.dom.xml.createDocument(); - /** @type {Object.<number, boolean>} */ - var newTileLayerZKeys = {}; - var iz, iziz, tileCoordKey, tileCoordOrigin, tilesToDraw; - for (iz = 0, iziz = zs.length; iz < iziz; ++iz) { - tileLayerZKey = zs[iz]; - if (tileLayerZKey in this.tileLayerZs_) { - tileLayerZ = this.tileLayerZs_[tileLayerZKey]; - } else { - tileCoordOrigin = - tileGrid.getTileCoordForCoordAndZ(center, tileLayerZKey); - tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin); - newTileLayerZKeys[tileLayerZKey] = true; - this.tileLayerZs_[tileLayerZKey] = tileLayerZ; - } - tilesToDraw = tilesToDrawByZ[tileLayerZKey]; - for (tileCoordKey in tilesToDraw) { - tileLayerZ.addTile(tilesToDraw[tileCoordKey], tileGutter); - } - tileLayerZ.finalizeAddTiles(); - } +/** + * @param {string} namespaceURI Namespace URI. + * @param {string} qualifiedName Qualified name. + * @return {Node} Node. + * @private + */ +ol.xml.createElementNS_ = function(namespaceURI, qualifiedName) { + return ol.xml.DOCUMENT.createElementNS(namespaceURI, qualifiedName); +}; - /** @type {Array.<number>} */ - var tileLayerZKeys = Object.keys(this.tileLayerZs_).map(Number); - goog.array.sort(tileLayerZKeys); - var i, ii, j, origin, resolution; - var transform = goog.vec.Mat4.createNumber(); - for (i = 0, ii = tileLayerZKeys.length; i < ii; ++i) { - tileLayerZKey = tileLayerZKeys[i]; - tileLayerZ = this.tileLayerZs_[tileLayerZKey]; - if (!(tileLayerZKey in tilesToDrawByZ)) { - goog.dom.removeNode(tileLayerZ.target); - delete this.tileLayerZs_[tileLayerZKey]; - continue; - } - resolution = tileLayerZ.getResolution(); - origin = tileLayerZ.getOrigin(); - ol.vec.Mat4.makeTransform2D(transform, - frameState.size[0] / 2, frameState.size[1] / 2, - resolution / viewState.resolution, - resolution / viewState.resolution, - viewState.rotation, - (origin[0] - center[0]) / resolution, - (center[1] - origin[1]) / resolution); - tileLayerZ.setTransform(transform); - if (tileLayerZKey in newTileLayerZKeys) { - for (j = tileLayerZKey - 1; j >= 0; --j) { - if (j in this.tileLayerZs_) { - goog.dom.insertSiblingAfter( - tileLayerZ.target, this.tileLayerZs_[j].target); - break; - } - } - if (j < 0) { - goog.dom.insertChildAt(this.target, tileLayerZ.target, 0); - } - } else { - if (!frameState.viewHints[ol.ViewHint.ANIMATING] && - !frameState.viewHints[ol.ViewHint.INTERACTING]) { - tileLayerZ.removeTilesOutsideExtent(extent, tmpTileRange); - } - } +/** + * @param {string} namespaceURI Namespace URI. + * @param {string} qualifiedName Qualified name. + * @return {Node} Node. + * @private + */ +ol.xml.createElementNSActiveX_ = function(namespaceURI, qualifiedName) { + if (!namespaceURI) { + namespaceURI = ''; } + return ol.xml.DOCUMENT.createNode(1, qualifiedName, namespaceURI); +}; - if (layerState.opacity != this.renderedOpacity_) { - this.target.style.opacity = layerState.opacity; - this.renderedOpacity_ = layerState.opacity; - } - if (layerState.visible && !this.renderedVisible_) { - goog.style.setElementShown(this.target, true); - this.renderedVisible_ = true; - } +/** + * @param {string} namespaceURI Namespace URI. + * @param {string} qualifiedName Qualified name. + * @return {Node} Node. + */ +ol.xml.createElementNS = + (document.implementation && document.implementation.createDocument) ? + ol.xml.createElementNS_ : ol.xml.createElementNSActiveX_; - this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); - this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, - projection, extent, z, tileLayer.getPreload()); - this.scheduleExpireCache(frameState, tileSource); - this.updateLogos(frameState, tileSource); - return true; +/** + * Recursively grab all text content of child nodes into a single string. + * @param {Node} node Node. + * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line + * breaks. + * @return {string} All text content. + * @api + */ +ol.xml.getAllTextContent = function(node, normalizeWhitespace) { + return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join(''); }; - /** - * @constructor + * Recursively grab all text content of child nodes into a single string. + * @param {Node} node Node. + * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line + * breaks. + * @param {Array.<String|string>} accumulator Accumulator. * @private - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {ol.TileCoord} tileCoordOrigin Tile coord origin. + * @return {Array.<String|string>} Accumulator. */ -ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) { - - /** - * @type {!Element} - */ - this.target = goog.dom.createElement('DIV'); - this.target.style.position = 'absolute'; - this.target.style.width = '100%'; - this.target.style.height = '100%'; - - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.tileGrid_ = tileGrid; - - /** - * @private - * @type {ol.TileCoord} - */ - this.tileCoordOrigin_ = tileCoordOrigin; - - /** - * @private - * @type {ol.Coordinate} - */ - this.origin_ = - ol.extent.getTopLeft(tileGrid.getTileCoordExtent(tileCoordOrigin)); - - /** - * @private - * @type {number} - */ - this.resolution_ = tileGrid.getResolution(tileCoordOrigin[0]); - - /** - * @private - * @type {Object.<string, ol.Tile>} - */ - this.tiles_ = {}; - - /** - * @private - * @type {DocumentFragment} - */ - this.documentFragment_ = null; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumberIdentity(); +ol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) { + if (node.nodeType == goog.dom.NodeType.CDATA_SECTION || + node.nodeType == goog.dom.NodeType.TEXT) { + if (normalizeWhitespace) { + // FIXME understand why goog.dom.getTextContent_ uses String here + accumulator.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, '')); + } else { + accumulator.push(node.nodeValue); + } + } else { + var n; + for (n = node.firstChild; n; n = n.nextSibling) { + ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator); + } + } + return accumulator; +}; - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; +/** + * @param {Node} node Node. + * @private + * @return {string} Local name. + */ +ol.xml.getLocalName_ = function(node) { + return node.localName; }; /** - * @param {ol.Tile} tile Tile. - * @param {number} tileGutter Tile gutter. + * @param {Node} node Node. + * @private + * @return {string} Local name. */ -ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile, tileGutter) { - var tileCoord = tile.tileCoord; - var tileCoordZ = tileCoord[0]; - var tileCoordX = tileCoord[1]; - var tileCoordY = tileCoord[2]; - goog.asserts.assert(tileCoordZ == this.tileCoordOrigin_[0], - 'tileCoordZ matches z of tileCoordOrigin'); - var tileCoordKey = ol.tilecoord.toString(tileCoord); - if (tileCoordKey in this.tiles_) { - return; - } - var tileSize = ol.size.toSize( - this.tileGrid_.getTileSize(tileCoordZ), this.tmpSize_); - var image = tile.getImage(this); - var imageStyle = image.style; - // Bootstrap sets the style max-width: 100% for all images, which - // prevents the tile from being displayed in FireFox. Workaround - // by overriding the max-width style. - imageStyle.maxWidth = 'none'; - var tileElement; - var tileElementStyle; - if (tileGutter > 0) { - tileElement = goog.dom.createElement('DIV'); - tileElementStyle = tileElement.style; - tileElementStyle.overflow = 'hidden'; - tileElementStyle.width = tileSize[0] + 'px'; - tileElementStyle.height = tileSize[1] + 'px'; - imageStyle.position = 'absolute'; - imageStyle.left = -tileGutter + 'px'; - imageStyle.top = -tileGutter + 'px'; - imageStyle.width = (tileSize[0] + 2 * tileGutter) + 'px'; - imageStyle.height = (tileSize[1] + 2 * tileGutter) + 'px'; - tileElement.appendChild(image); - } else { - imageStyle.width = tileSize[0] + 'px'; - imageStyle.height = tileSize[1] + 'px'; - tileElement = image; - tileElementStyle = imageStyle; - } - tileElementStyle.position = 'absolute'; - tileElementStyle.left = - ((tileCoordX - this.tileCoordOrigin_[1]) * tileSize[0]) + 'px'; - tileElementStyle.top = - ((this.tileCoordOrigin_[2] - tileCoordY) * tileSize[1]) + 'px'; - if (!this.documentFragment_) { - this.documentFragment_ = document.createDocumentFragment(); +ol.xml.getLocalNameIE_ = function(node) { + var localName = node.localName; + if (localName !== undefined) { + return localName; } - this.documentFragment_.appendChild(tileElement); - this.tiles_[tileCoordKey] = tile; + var baseName = node.baseName; + goog.asserts.assert(baseName, + 'Failed to get localName/baseName of node %s', node); + return baseName; }; /** - * FIXME empty description for jsdoc + * @param {Node} node Node. + * @return {string} Local name. */ -ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() { - if (this.documentFragment_) { - this.target.appendChild(this.documentFragment_); - this.documentFragment_ = null; - } -}; +ol.xml.getLocalName = goog.userAgent.IE ? + ol.xml.getLocalNameIE_ : ol.xml.getLocalName_; /** - * @return {ol.Coordinate} Origin. + * @param {?} value Value. + * @private + * @return {boolean} Is document. */ -ol.renderer.dom.TileLayerZ_.prototype.getOrigin = function() { - return this.origin_; +ol.xml.isDocument_ = function(value) { + return value instanceof Document; }; /** - * @return {number} Resolution. + * @param {?} value Value. + * @private + * @return {boolean} Is document. */ -ol.renderer.dom.TileLayerZ_.prototype.getResolution = function() { - return this.resolution_; +ol.xml.isDocumentIE_ = function(value) { + return goog.isObject(value) && value.nodeType == goog.dom.NodeType.DOCUMENT; }; /** - * @param {ol.Extent} extent Extent. - * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. + * @param {?} value Value. + * @return {boolean} Is document. */ -ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent = - function(extent, opt_tileRange) { - var tileRange = this.tileGrid_.getTileRangeForExtentAndZ( - extent, this.tileCoordOrigin_[0], opt_tileRange); - /** @type {Array.<ol.Tile>} */ - var tilesToRemove = []; - var tile, tileCoordKey; - for (tileCoordKey in this.tiles_) { - tile = this.tiles_[tileCoordKey]; - if (!tileRange.contains(tile.tileCoord)) { - tilesToRemove.push(tile); - } - } - var i, ii; - for (i = 0, ii = tilesToRemove.length; i < ii; ++i) { - tile = tilesToRemove[i]; - tileCoordKey = ol.tilecoord.toString(tile.tileCoord); - goog.dom.removeNode(tile.getImage(this)); - delete this.tiles_[tileCoordKey]; - } -}; +ol.xml.isDocument = goog.userAgent.IE ? + ol.xml.isDocumentIE_ : ol.xml.isDocument_; /** - * @param {goog.vec.Mat4.Number} transform Transform. + * @param {?} value Value. + * @private + * @return {boolean} Is node. */ -ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) { - if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { - ol.dom.transformElement2D(this.target, transform, 6); - goog.vec.Mat4.setFromArray(this.transform_, transform); - } +ol.xml.isNode_ = function(value) { + return value instanceof Node; }; -goog.provide('ol.renderer.dom.VectorLayer'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.render.canvas.ReplayGroup'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.renderer.vector'); -goog.require('ol.vec.Mat4'); - - /** - * @constructor - * @extends {ol.renderer.dom.Layer} - * @param {ol.layer.Vector} vectorLayer Vector layer. + * @param {?} value Value. + * @private + * @return {boolean} Is node. */ -ol.renderer.dom.VectorLayer = function(vectorLayer) { - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - - var target = this.context_.canvas; - // Bootstrap sets the style max-width: 100% for all images, which breaks - // prevents the image from being displayed in FireFox. Workaround by - // overriding the max-width style. - target.style.maxWidth = 'none'; - target.style.position = 'absolute'; - - goog.base(this, vectorLayer, target); - - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; - - /** - * @private - * @type {number} - */ - this.renderedResolution_ = NaN; - - /** - * @private - * @type {ol.Extent} - */ - this.renderedExtent_ = ol.extent.createEmpty(); - - /** - * @private - * @type {function(ol.Feature, ol.Feature): number|null} - */ - this.renderedRenderOrder_ = null; - - /** - * @private - * @type {ol.render.canvas.ReplayGroup} - */ - this.replayGroup_ = null; - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.elementTransform_ = goog.vec.Mat4.createNumber(); - +ol.xml.isNodeIE_ = function(value) { + return goog.isObject(value) && value.nodeType !== undefined; }; -goog.inherits(ol.renderer.dom.VectorLayer, ol.renderer.dom.Layer); /** - * @inheritDoc + * @param {?} value Value. + * @return {boolean} Is node. */ -ol.renderer.dom.VectorLayer.prototype.composeFrame = - function(frameState, layerState) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewRotation = viewState.rotation; - var viewResolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var viewWidth = frameState.size[0]; - var viewHeight = frameState.size[1]; - var imageWidth = viewWidth * pixelRatio; - var imageHeight = viewHeight * pixelRatio; - - var transform = ol.vec.Mat4.makeTransform2D(this.transform_, - pixelRatio * viewWidth / 2, - pixelRatio * viewHeight / 2, - pixelRatio / viewResolution, - -pixelRatio / viewResolution, - -viewRotation, - -viewCenter[0], -viewCenter[1]); - - var context = this.context_; +ol.xml.isNode = goog.userAgent.IE ? ol.xml.isNodeIE_ : ol.xml.isNode_; - // Clear the canvas and set the correct size - context.canvas.width = imageWidth; - context.canvas.height = imageHeight; - var elementTransform = ol.vec.Mat4.makeTransform2D(this.elementTransform_, - 0, 0, - 1 / pixelRatio, 1 / pixelRatio, - 0, - -(imageWidth - viewWidth) / 2 * pixelRatio, - -(imageHeight - viewHeight) / 2 * pixelRatio); - ol.dom.transformElement2D(context.canvas, elementTransform, 6); +/** + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @return {string} Value + * @private + */ +ol.xml.getAttributeNS_ = function(node, namespaceURI, name) { + return node.getAttributeNS(namespaceURI, name) || ''; +}; - this.dispatchEvent_(ol.render.EventType.PRECOMPOSE, frameState, transform); - var replayGroup = this.replayGroup_; +/** + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @return {string} Value + * @private + */ +ol.xml.getAttributeNSActiveX_ = function(node, namespaceURI, name) { + var attributeValue = ''; + var attributeNode = ol.xml.getAttributeNodeNS(node, namespaceURI, name); + if (attributeNode !== undefined) { + attributeValue = attributeNode.nodeValue; + } + return attributeValue; +}; - if (replayGroup && !replayGroup.isEmpty()) { - context.globalAlpha = layerState.opacity; - replayGroup.replay(context, pixelRatio, transform, viewRotation, - layerState.managed ? frameState.skippedFeatureUids : {}); +/** + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @return {string} Value + */ +ol.xml.getAttributeNS = + (document.implementation && document.implementation.createDocument) ? + ol.xml.getAttributeNS_ : ol.xml.getAttributeNSActiveX_; - this.dispatchEvent_(ol.render.EventType.RENDER, frameState, transform); - } - this.dispatchEvent_(ol.render.EventType.POSTCOMPOSE, frameState, transform); +/** + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @return {?Node} Attribute node or null if none found. + * @private + */ +ol.xml.getAttributeNodeNS_ = function(node, namespaceURI, name) { + return node.getAttributeNodeNS(namespaceURI, name); }; /** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @param {goog.vec.Mat4.Number} transform Transform. + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @return {?Node} Attribute node or null if none found. * @private */ -ol.renderer.dom.VectorLayer.prototype.dispatchEvent_ = - function(type, frameState, transform) { - var context = this.context_; - var layer = this.getLayer(); - if (layer.hasListener(type)) { - var render = new ol.render.canvas.Immediate( - context, frameState.pixelRatio, frameState.extent, transform, - frameState.viewState.rotation); - var event = new ol.render.Event(type, layer, render, frameState, - context, null); - layer.dispatchEvent(event); - render.flush(); +ol.xml.getAttributeNodeNSActiveX_ = function(node, namespaceURI, name) { + var attributeNode = null; + var attributes = node.attributes; + var potentialNode, fullName; + for (var i = 0, len = attributes.length; i < len; ++i) { + potentialNode = attributes[i]; + if (potentialNode.namespaceURI == namespaceURI) { + fullName = (potentialNode.prefix) ? + (potentialNode.prefix + ':' + name) : name; + if (fullName == potentialNode.nodeName) { + attributeNode = potentialNode; + break; + } + } } + return attributeNode; }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @return {?Node} Attribute node or null if none found. */ -ol.renderer.dom.VectorLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - if (!this.replayGroup_) { - return undefined; - } else { - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var layer = this.getLayer(); - var layerState = frameState.layerStates[goog.getUid(layer)]; - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, - rotation, layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); - } -}; +ol.xml.getAttributeNodeNS = + (document.implementation && document.implementation.createDocument) ? + ol.xml.getAttributeNodeNS_ : ol.xml.getAttributeNodeNSActiveX_; /** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @param {string|number} value Value. * @private */ -ol.renderer.dom.VectorLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); +ol.xml.setAttributeNS_ = function(node, namespaceURI, name, value) { + node.setAttributeNS(namespaceURI, name, value); }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @param {string|number} value Value. + * @private */ -ol.renderer.dom.VectorLayer.prototype.prepareFrame = - function(frameState, layerState) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - var vectorSource = vectorLayer.getSource(); - - this.updateAttributions( - frameState.attributions, vectorSource.getAttributions()); - this.updateLogos(frameState, vectorSource); - - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); - var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); - - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; +ol.xml.setAttributeNSActiveX_ = function(node, namespaceURI, name, value) { + if (namespaceURI) { + var attribute = node.ownerDocument.createNode(2, name, namespaceURI); + attribute.nodeValue = value; + node.setAttributeNode(attribute); + } else { + node.setAttribute(name, value); } +}; - var frameStateExtent = frameState.extent; - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var vectorLayerRevision = vectorLayer.getRevision(); - var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); - var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); - - if (vectorLayerRenderOrder === undefined) { - vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; - } - var extent = ol.extent.buffer(frameStateExtent, - vectorLayerRenderBuffer * resolution); +/** + * @param {Node} node Node. + * @param {?string} namespaceURI Namespace URI. + * @param {string} name Attribute name. + * @param {string|number} value Value. + */ +ol.xml.setAttributeNS = + (document.implementation && document.implementation.createDocument) ? + ol.xml.setAttributeNS_ : ol.xml.setAttributeNSActiveX_; - if (!this.dirty_ && - this.renderedResolution_ == resolution && - this.renderedRevision_ == vectorLayerRevision && - this.renderedRenderOrder_ == vectorLayerRenderOrder && - ol.extent.containsExtent(this.renderedExtent_, extent)) { - return true; - } - // FIXME dispose of old replayGroup in post render - goog.dispose(this.replayGroup_); - this.replayGroup_ = null; +/** + * Parse an XML string to an XML Document. + * @param {string} xml XML. + * @return {Document} Document. + * @api + */ +ol.xml.parse = function(xml) { + return new DOMParser().parseFromString(xml, 'application/xml'); +}; - this.dirty_ = false; - var replayGroup = - new ol.render.canvas.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, - resolution, vectorLayer.getRenderBuffer()); - vectorSource.loadFeatures(extent, resolution, projection); - var renderFeature = +/** + * Make an array extender function for extending the array at the top of the + * object stack. + * @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)} + * valueReader Value reader. + * @param {T=} opt_this The object to use as `this` in `valueReader`. + * @return {ol.xml.Parser} Parser. + * @template T + */ +ol.xml.makeArrayExtender = function(valueReader, opt_this) { + return ( /** - * @param {ol.Feature} feature Feature. - * @this {ol.renderer.dom.VectorLayer} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. */ - function(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = vectorLayer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - var dirty = this.renderFeature( - feature, resolution, pixelRatio, styles, replayGroup); - this.dirty_ = this.dirty_ || dirty; - } - }; - if (vectorLayerRenderOrder) { - /** @type {Array.<ol.Feature>} */ - var features = []; - vectorSource.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - features.push(feature); - }, this); - goog.array.sort(features, vectorLayerRenderOrder); - features.forEach(renderFeature, this); - } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); - } - replayGroup.finish(); - - this.renderedResolution_ = resolution; - this.renderedRevision_ = vectorLayerRevision; - this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; - this.replayGroup_ = replayGroup; - - return true; + function(node, objectStack) { + var value = valueReader.call(opt_this, node, objectStack); + if (value !== undefined) { + goog.asserts.assert(goog.isArray(value), + 'valueReader function is expected to return an array of values'); + var array = /** @type {Array.<*>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(array), + 'objectStack is supposed to be an array of arrays'); + goog.array.extend(array, value); + } + }); }; /** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. + * Make an array pusher function for pushing to the array at the top of the + * object stack. + * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. + * @param {T=} opt_this The object to use as `this` in `valueReader`. + * @return {ol.xml.Parser} Parser. + * @template T */ -ol.renderer.dom.VectorLayer.prototype.renderFeature = - function(feature, resolution, pixelRatio, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - return loading; +ol.xml.makeArrayPusher = function(valueReader, opt_this) { + return ( + /** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + */ + function(node, objectStack) { + var value = valueReader.call(opt_this !== undefined ? opt_this : this, + node, objectStack); + if (value !== undefined) { + var array = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isArray(array), + 'objectStack is supposed to be an array of arrays'); + array.push(value); + } + }); }; -goog.provide('ol.renderer.dom.Map'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol'); -goog.require('ol.RendererType'); -goog.require('ol.css'); -goog.require('ol.dom'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.canvas.Immediate'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.dom.ImageLayer'); -goog.require('ol.renderer.dom.Layer'); -goog.require('ol.renderer.dom.TileLayer'); -goog.require('ol.renderer.dom.VectorLayer'); -goog.require('ol.source.State'); -goog.require('ol.vec.Mat4'); - - /** - * @constructor - * @extends {ol.renderer.Map} - * @param {Element} container Container. - * @param {ol.Map} map Map. + * Make an object stack replacer function for replacing the object at the + * top of the stack. + * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. + * @param {T=} opt_this The object to use as `this` in `valueReader`. + * @return {ol.xml.Parser} Parser. + * @template T */ -ol.renderer.dom.Map = function(container, map) { - - goog.base(this, container, map); - - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = ol.dom.createCanvasContext2D(); - var canvas = this.context_.canvas; - canvas.style.position = 'absolute'; - canvas.style.width = '100%'; - canvas.style.height = '100%'; - canvas.className = ol.css.CLASS_UNSELECTABLE; - goog.dom.insertChildAt(container, canvas, 0); - - /** - * @private - * @type {!goog.vec.Mat4.Number} - */ - this.transform_ = goog.vec.Mat4.createNumber(); - - /** - * @type {!Element} - * @private - */ - this.layersPane_ = goog.dom.createElement('DIV'); - this.layersPane_.className = ol.css.CLASS_UNSELECTABLE; - var style = this.layersPane_.style; - style.position = 'absolute'; - style.width = '100%'; - style.height = '100%'; - - // prevent the img context menu on mobile devices - goog.events.listen(this.layersPane_, goog.events.EventType.TOUCHSTART, - goog.events.Event.preventDefault); - - goog.dom.insertChildAt(container, this.layersPane_, 0); - - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; - +ol.xml.makeReplacer = function(valueReader, opt_this) { + return ( + /** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + */ + function(node, objectStack) { + var value = valueReader.call(opt_this !== undefined ? opt_this : this, + node, objectStack); + if (value !== undefined) { + objectStack[objectStack.length - 1] = value; + } + }); }; -goog.inherits(ol.renderer.dom.Map, ol.renderer.Map); /** - * @inheritDoc + * Make an object property pusher function for adding a property to the + * object at the top of the stack. + * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. + * @param {string=} opt_property Property. + * @param {T=} opt_this The object to use as `this` in `valueReader`. + * @return {ol.xml.Parser} Parser. + * @template T */ -ol.renderer.dom.Map.prototype.disposeInternal = function() { - goog.dom.removeNode(this.layersPane_); - goog.base(this, 'disposeInternal'); +ol.xml.makeObjectPropertyPusher = + function(valueReader, opt_property, opt_this) { + goog.asserts.assert(valueReader !== undefined, + 'undefined valueReader, expected function(this: T, Node, Array.<*>)'); + return ( + /** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + */ + function(node, objectStack) { + var value = valueReader.call(opt_this !== undefined ? opt_this : this, + node, objectStack); + if (value !== undefined) { + var object = /** @type {Object} */ + (objectStack[objectStack.length - 1]); + var property = opt_property !== undefined ? + opt_property : node.localName; + goog.asserts.assert(goog.isObject(object), + 'entity from stack was not an object'); + var array = goog.object.setIfUndefined(object, property, []); + array.push(value); + } + }); }; /** - * @inheritDoc + * Make an object property setter function. + * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader. + * @param {string=} opt_property Property. + * @param {T=} opt_this The object to use as `this` in `valueReader`. + * @return {ol.xml.Parser} Parser. + * @template T */ -ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { - var layerRenderer; - if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { - layerRenderer = new ol.renderer.dom.ImageLayer(layer); - } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { - layerRenderer = new ol.renderer.dom.TileLayer(layer); - } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { - layerRenderer = new ol.renderer.dom.VectorLayer(layer); - } else { - goog.asserts.fail('unexpected layer configuration'); - return null; - } - return layerRenderer; +ol.xml.makeObjectPropertySetter = + function(valueReader, opt_property, opt_this) { + goog.asserts.assert(valueReader !== undefined, + 'undefined valueReader, expected function(this: T, Node, Array.<*>)'); + return ( + /** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + */ + function(node, objectStack) { + var value = valueReader.call(opt_this !== undefined ? opt_this : this, + node, objectStack); + if (value !== undefined) { + var object = /** @type {Object} */ + (objectStack[objectStack.length - 1]); + var property = opt_property !== undefined ? + opt_property : node.localName; + goog.asserts.assert(goog.isObject(object), + 'entity from stack was not an object'); + object[property] = value; + } + }); }; /** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @private + * Create a serializer that appends nodes written by its `nodeWriter` to its + * designated parent. The parent is the `node` of the + * {@link ol.xml.NodeStackItem} at the top of the `objectStack`. + * @param {function(this: T, Node, V, Array.<*>)} + * nodeWriter Node writer. + * @param {T=} opt_this The object to use as `this` in `nodeWriter`. + * @return {ol.xml.Serializer} Serializer. + * @template T, V */ -ol.renderer.dom.Map.prototype.dispatchComposeEvent_ = - function(type, frameState) { - var map = this.getMap(); - if (map.hasListener(type)) { - var extent = frameState.extent; - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var rotation = viewState.rotation; - var context = this.context_; - var canvas = context.canvas; - - ol.vec.Mat4.makeTransform2D(this.transform_, - canvas.width / 2, - canvas.height / 2, - pixelRatio / viewState.resolution, - -pixelRatio / viewState.resolution, - -viewState.rotation, - -viewState.center[0], -viewState.center[1]); - var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio, - extent, this.transform_, rotation); - var composeEvent = new ol.render.Event(type, map, vectorContext, - frameState, context, null); - map.dispatchEvent(composeEvent); - vectorContext.flush(); - } +ol.xml.makeChildAppender = function(nodeWriter, opt_this) { + return function(node, value, objectStack) { + nodeWriter.call(opt_this !== undefined ? opt_this : this, + node, value, objectStack); + var parent = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(parent), + 'entity from stack was not an object'); + var parentNode = parent.node; + goog.asserts.assert(ol.xml.isNode(parentNode) || + ol.xml.isDocument(parentNode), + 'expected parentNode %s to be a Node or a Document', parentNode); + parentNode.appendChild(node); + }; }; /** - * @inheritDoc + * Create a serializer that calls the provided `nodeWriter` from + * {@link ol.xml.serialize}. This can be used by the parent writer to have the + * 'nodeWriter' called with an array of values when the `nodeWriter` was + * designed to serialize a single item. An example would be a LineString + * geometry writer, which could be reused for writing MultiLineString + * geometries. + * @param {function(this: T, Node, V, Array.<*>)} + * nodeWriter Node writer. + * @param {T=} opt_this The object to use as `this` in `nodeWriter`. + * @return {ol.xml.Serializer} Serializer. + * @template T, V */ -ol.renderer.dom.Map.prototype.getType = function() { - return ol.RendererType.DOM; +ol.xml.makeArraySerializer = function(nodeWriter, opt_this) { + var serializersNS, nodeFactory; + return function(node, value, objectStack) { + if (serializersNS === undefined) { + serializersNS = {}; + var serializers = {}; + serializers[node.localName] = nodeWriter; + serializersNS[node.namespaceURI] = serializers; + nodeFactory = ol.xml.makeSimpleNodeFactory(node.localName); + } + ol.xml.serialize(serializersNS, nodeFactory, value, objectStack); + }; }; /** - * @inheritDoc + * Create a node factory which can use the `opt_keys` passed to + * {@link ol.xml.serialize} or {@link ol.xml.pushSerializeAndPop} as node names, + * or a fixed node name. The namespace of the created nodes can either be fixed, + * or the parent namespace will be used. + * @param {string=} opt_nodeName Fixed node name which will be used for all + * created nodes. If not provided, the 3rd argument to the resulting node + * factory needs to be provided and will be the nodeName. + * @param {string=} opt_namespaceURI Fixed namespace URI which will be used for + * all created nodes. If not provided, the namespace of the parent node will + * be used. + * @return {function(*, Array.<*>, string=): (Node|undefined)} Node factory. */ -ol.renderer.dom.Map.prototype.renderFrame = function(frameState) { - - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.layersPane_, false); - this.renderedVisible_ = false; - } - return; - } - - var map = this.getMap(); - if (map.hasListener(ol.render.EventType.PRECOMPOSE) || - map.hasListener(ol.render.EventType.POSTCOMPOSE)) { - var canvas = this.context_.canvas; - var pixelRatio = frameState.pixelRatio; - canvas.width = frameState.size[0] * pixelRatio; - canvas.height = frameState.size[1] * pixelRatio; - } - - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); - - var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - - var viewResolution = frameState.viewState.resolution; - var i, ii, layer, layerRenderer, layerState; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerState = layerStatesArray[i]; - layer = layerState.layer; - layerRenderer = /** @type {ol.renderer.dom.Layer} */ ( - this.getLayerRenderer(layer)); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer, - 'renderer is an instance of ol.renderer.dom.Layer'); - goog.dom.insertChildAt(this.layersPane_, layerRenderer.getTarget(), i); - if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerState.sourceState == ol.source.State.READY) { - if (layerRenderer.prepareFrame(frameState, layerState)) { - layerRenderer.composeFrame(frameState, layerState); +ol.xml.makeSimpleNodeFactory = function(opt_nodeName, opt_namespaceURI) { + var fixedNodeName = opt_nodeName; + return ( + /** + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node} Node. + */ + function(value, objectStack, opt_nodeName) { + var context = objectStack[objectStack.length - 1]; + var node = context.node; + goog.asserts.assert(ol.xml.isNode(node) || ol.xml.isDocument(node), + 'expected node %s to be a Node or a Document', node); + var nodeName = fixedNodeName; + if (nodeName === undefined) { + nodeName = opt_nodeName; + } + var namespaceURI = opt_namespaceURI; + if (opt_namespaceURI === undefined) { + namespaceURI = node.namespaceURI; + } + goog.asserts.assert(nodeName !== undefined, 'nodeName was undefined'); + return ol.xml.createElementNS(namespaceURI, nodeName); } - } else { - layerRenderer.clearFrame(); - } - } - - var layerStates = frameState.layerStates; - var layerKey; - for (layerKey in this.getLayerRenderers()) { - if (!(layerKey in layerStates)) { - layerRenderer = this.getLayerRendererByKey(layerKey); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer, - 'renderer is an instance of ol.renderer.dom.Layer'); - goog.dom.removeNode(layerRenderer.getTarget()); - } - } - - if (!this.renderedVisible_) { - goog.style.setElementShown(this.layersPane_, true); - this.renderedVisible_ = true; - } - - this.calculateMatrices2D(frameState); - this.scheduleRemoveUnusedLayerRenderers(frameState); - this.scheduleExpireIconCache(frameState); - - this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState); + ); }; -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview Constants used by the WebGL rendering, including all of the - * constants used from the WebGL context. For example, instead of using - * context.ARRAY_BUFFER, your code can use - * goog.webgl.ARRAY_BUFFER. The benefits for doing this include allowing - * the compiler to optimize your code so that the compiled code does not have to - * contain large strings to reference these properties, and reducing runtime - * property access. - * - * Values are taken from the WebGL Spec: - * https://www.khronos.org/registry/webgl/specs/1.0/#WEBGLRENDERINGCONTEXT - */ - -goog.provide('goog.webgl'); - - -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_BUFFER_BIT = 0x00000100; - /** + * A node factory that creates a node using the parent's `namespaceURI` and the + * `nodeName` passed by {@link ol.xml.serialize} or + * {@link ol.xml.pushSerializeAndPop} to the node factory. * @const - * @type {number} + * @type {function(*, Array.<*>, string=): (Node|undefined)} */ -goog.webgl.STENCIL_BUFFER_BIT = 0x00000400; +ol.xml.OBJECT_PROPERTY_NODE_FACTORY = ol.xml.makeSimpleNodeFactory(); /** - * @const - * @type {number} + * Create an array of `values` to be used with {@link ol.xml.serialize} or + * {@link ol.xml.pushSerializeAndPop}, where `orderedKeys` has to be provided as + * `opt_key` argument. + * @param {Object.<string, V>} object Key-value pairs for the sequence. Keys can + * be a subset of the `orderedKeys`. + * @param {Array.<string>} orderedKeys Keys in the order of the sequence. + * @return {Array.<V>} Values in the order of the sequence. The resulting array + * has the same length as the `orderedKeys` array. Values that are not + * present in `object` will be `undefined` in the resulting array. + * @template V */ -goog.webgl.COLOR_BUFFER_BIT = 0x00004000; +ol.xml.makeSequence = function(object, orderedKeys) { + var length = orderedKeys.length; + var sequence = new Array(length); + for (var i = 0; i < length; ++i) { + sequence[i] = object[orderedKeys[i]]; + } + return sequence; +}; /** - * @const - * @type {number} + * Create a namespaced structure, using the same values for each namespace. + * This can be used as a starting point for versioned parsers, when only a few + * values are version specific. + * @param {Array.<string>} namespaceURIs Namespace URIs. + * @param {T} structure Structure. + * @param {Object.<string, T>=} opt_structureNS Namespaced structure to add to. + * @return {Object.<string, T>} Namespaced structure. + * @template T */ -goog.webgl.POINTS = 0x0000; +ol.xml.makeStructureNS = function(namespaceURIs, structure, opt_structureNS) { + /** + * @type {Object.<string, *>} + */ + var structureNS = opt_structureNS !== undefined ? opt_structureNS : {}; + var i, ii; + for (i = 0, ii = namespaceURIs.length; i < ii; ++i) { + structureNS[namespaceURIs[i]] = structure; + } + return structureNS; +}; /** - * @const - * @type {number} + * Parse a node using the parsers and object stack. + * @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS + * Parsers by namespace. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @param {*=} opt_this The object to use as `this`. */ -goog.webgl.LINES = 0x0001; +ol.xml.parseNode = function(parsersNS, node, objectStack, opt_this) { + var n; + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + var parsers = parsersNS[n.namespaceURI]; + if (parsers !== undefined) { + var parser = parsers[n.localName]; + if (parser !== undefined) { + parser.call(opt_this, n, objectStack); + } + } + } +}; /** - * @const - * @type {number} + * Push an object on top of the stack, parse and return the popped object. + * @param {T} object Object. + * @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS + * Parsers by namespace. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @param {*=} opt_this The object to use as `this`. + * @return {T} Object. + * @template T */ -goog.webgl.LINE_LOOP = 0x0002; +ol.xml.pushParseAndPop = function( + object, parsersNS, node, objectStack, opt_this) { + objectStack.push(object); + ol.xml.parseNode(parsersNS, node, objectStack, opt_this); + return objectStack.pop(); +}; /** - * @const - * @type {number} + * Walk through an array of `values` and call a serializer for each value. + * @param {Object.<string, Object.<string, ol.xml.Serializer>>} serializersNS + * Namespaced serializers. + * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory + * Node factory. The `nodeFactory` creates the node whose namespace and name + * will be used to choose a node writer from `serializersNS`. This + * separation allows us to decide what kind of node to create, depending on + * the value we want to serialize. An example for this would be different + * geometry writers based on the geometry type. + * @param {Array.<*>} values Values to serialize. An example would be an array + * of {@link ol.Feature} instances. + * @param {Array.<*>} objectStack Node stack. + * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the + * `nodeFactory`. This is used for serializing object literals where the + * node name relates to the property key. The array length of `opt_keys` has + * to match the length of `values`. For serializing a sequence, `opt_keys` + * determines the order of the sequence. + * @param {T=} opt_this The object to use as `this` for the node factory and + * serializers. + * @template T */ -goog.webgl.LINE_STRIP = 0x0003; +ol.xml.serialize = function( + serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) { + var length = (opt_keys !== undefined ? opt_keys : values).length; + var value, node; + for (var i = 0; i < length; ++i) { + value = values[i]; + if (value !== undefined) { + node = nodeFactory.call(opt_this, value, objectStack, + opt_keys !== undefined ? opt_keys[i] : undefined); + if (node !== undefined) { + serializersNS[node.namespaceURI][node.localName] + .call(opt_this, node, value, objectStack); + } + } + } +}; /** - * @const - * @type {number} - */ -goog.webgl.TRIANGLES = 0x0004; - - -/** - * @const - * @type {number} + * @param {O} object Object. + * @param {Object.<string, Object.<string, ol.xml.Serializer>>} serializersNS + * Namespaced serializers. + * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory + * Node factory. The `nodeFactory` creates the node whose namespace and name + * will be used to choose a node writer from `serializersNS`. This + * separation allows us to decide what kind of node to create, depending on + * the value we want to serialize. An example for this would be different + * geometry writers based on the geometry type. + * @param {Array.<*>} values Values to serialize. An example would be an array + * of {@link ol.Feature} instances. + * @param {Array.<*>} objectStack Node stack. + * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the + * `nodeFactory`. This is used for serializing object literals where the + * node name relates to the property key. The array length of `opt_keys` has + * to match the length of `values`. For serializing a sequence, `opt_keys` + * determines the order of the sequence. + * @param {T=} opt_this The object to use as `this` for the node factory and + * serializers. + * @return {O|undefined} Object. + * @template O, T */ -goog.webgl.TRIANGLE_STRIP = 0x0005; +ol.xml.pushSerializeAndPop = function(object, + serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) { + objectStack.push(object); + ol.xml.serialize( + serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this); + return objectStack.pop(); +}; +goog.provide('ol.FeatureLoader'); +goog.provide('ol.FeatureUrlFunction'); +goog.provide('ol.featureloader'); -/** - * @const - * @type {number} - */ -goog.webgl.TRIANGLE_FAN = 0x0006; +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.net.EventType'); +goog.require('goog.net.XhrIo'); +goog.require('goog.net.XhrIo.ResponseType'); +goog.require('ol.TileState'); +goog.require('ol.format.FormatType'); +goog.require('ol.xml'); /** - * @const - * @type {number} + * {@link ol.source.Vector} sources use a function of this type to load + * features. + * + * This function takes an {@link ol.Extent} representing the area to be loaded, + * a `{number}` representing the resolution (map units per pixel) and an + * {@link ol.proj.Projection} for the projection as arguments. `this` within + * the function is bound to the {@link ol.source.Vector} it's called from. + * + * The function is responsible for loading the features and adding them to the + * source. + * @api + * @typedef {function(this:ol.source.Vector, ol.Extent, number, + * ol.proj.Projection)} */ -goog.webgl.ZERO = 0; +ol.FeatureLoader; /** - * @const - * @type {number} + * {@link ol.source.Vector} sources use a function of this type to get the url + * to load features from. + * + * This function takes an {@link ol.Extent} representing the area to be loaded, + * a `{number}` representing the resolution (map units per pixel) and an + * {@link ol.proj.Projection} for the projection as arguments and returns a + * `{string}` representing the URL. + * @api + * @typedef {function(ol.Extent, number, ol.proj.Projection) : string} */ -goog.webgl.ONE = 1; +ol.FeatureUrlFunction; /** - * @const - * @type {number} + * @param {string|ol.FeatureUrlFunction} url Feature URL service. + * @param {ol.format.Feature} format Feature format. + * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection)|function(this:ol.source.Vector, Array.<ol.Feature>)} success + * Function called with the loaded features and optionally with the data + * projection. Called with the vector tile or source as `this`. + * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure + * Function called when loading failed. Called with the vector tile or + * source as `this`. + * @return {ol.FeatureLoader} The feature loader. */ -goog.webgl.SRC_COLOR = 0x0300; - +ol.featureloader.loadFeaturesXhr = function(url, format, success, failure) { + return ( + /** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {ol.proj.Projection} projection Projection. + * @this {ol.source.Vector|ol.VectorTile} + */ + function(extent, resolution, projection) { + var xhrIo = new goog.net.XhrIo(); + xhrIo.setResponseType( + format.getType() == ol.format.FormatType.ARRAY_BUFFER ? + goog.net.XhrIo.ResponseType.ARRAY_BUFFER : + goog.net.XhrIo.ResponseType.TEXT); + goog.events.listen(xhrIo, goog.net.EventType.COMPLETE, + /** + * @param {Event} event Event. + * @private + * @this {ol.source.Vector} + */ + function(event) { + var xhrIo = event.target; + goog.asserts.assertInstanceof(xhrIo, goog.net.XhrIo, + 'event.target/xhrIo is an instance of goog.net.XhrIo'); + if (xhrIo.isSuccess()) { + var type = format.getType(); + /** @type {Document|Node|Object|string|undefined} */ + var source; + if (type == ol.format.FormatType.JSON) { + source = xhrIo.getResponseText(); + } else if (type == ol.format.FormatType.TEXT) { + source = xhrIo.getResponseText(); + } else if (type == ol.format.FormatType.XML) { + if (!goog.userAgent.IE) { + source = xhrIo.getResponseXml(); + } + if (!source) { + source = ol.xml.parse(xhrIo.getResponseText()); + } + } else if (type == ol.format.FormatType.ARRAY_BUFFER) { + source = xhrIo.getResponse(); + } else { + goog.asserts.fail('unexpected format type'); + } + if (source) { + var features = format.readFeatures(source, + {featureProjection: projection}); + if (ol.ENABLE_VECTOR_TILE && success.length == 2) { + success.call(this, features, format.readProjection(source)); + } else { + success.call(this, features); + } + } else { + goog.asserts.fail('undefined or null source'); + } + } else { + failure.call(this); + } + goog.dispose(xhrIo); + }, false, this); + if (goog.isFunction(url)) { + xhrIo.send(url(extent, resolution, projection)); + } else { + xhrIo.send(url); + } -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_SRC_COLOR = 0x0301; + }); +}; /** - * @const - * @type {number} + * Create an XHR feature loader for a `url` and `format`. The feature loader + * loads features (with XHR), parses the features, and adds them to the + * vector tile. + * @param {string|ol.FeatureUrlFunction} url Feature URL service. + * @param {ol.format.Feature} format Feature format. + * @return {ol.FeatureLoader} The feature loader. + * @api */ -goog.webgl.SRC_ALPHA = 0x0302; +ol.featureloader.tile = function(url, format) { + return ol.featureloader.loadFeaturesXhr(url, format, + /** + * @param {Array.<ol.Feature>} features The loaded features. + * @param {ol.proj.Projection} projection Data projection. + * @this {ol.VectorTile} + */ + function(features, projection) { + this.setProjection(projection); + this.setFeatures(features); + }, + /** + * @this {ol.VectorTile} + */ + function() { + this.setState(ol.TileState.ERROR); + }); +}; /** - * @const - * @type {number} + * Create an XHR feature loader for a `url` and `format`. The feature loader + * loads features (with XHR), parses the features, and adds them to the + * vector source. + * @param {string|ol.FeatureUrlFunction} url Feature URL service. + * @param {ol.format.Feature} format Feature format. + * @return {ol.FeatureLoader} The feature loader. + * @api */ -goog.webgl.ONE_MINUS_SRC_ALPHA = 0x0303; +ol.featureloader.xhr = function(url, format) { + return ol.featureloader.loadFeaturesXhr(url, format, + /** + * @param {Array.<ol.Feature>} features The loaded features. + * @this {ol.source.Vector} + */ + function(features) { + this.addFeatures(features); + }, /* FIXME handle error */ ol.nullFunction); +}; +goog.provide('ol.LoadingStrategy'); +goog.provide('ol.loadingstrategy'); -/** - * @const - * @type {number} - */ -goog.webgl.DST_ALPHA = 0x0304; +goog.require('ol.TileCoord'); /** - * @const - * @type {number} + * @typedef {function(ol.Extent, number): Array.<ol.Extent>} + * @api */ -goog.webgl.ONE_MINUS_DST_ALPHA = 0x0305; +ol.LoadingStrategy; /** - * @const - * @type {number} + * Strategy function for loading all features with a single request. + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @return {Array.<ol.Extent>} Extents. + * @api */ -goog.webgl.DST_COLOR = 0x0306; +ol.loadingstrategy.all = function(extent, resolution) { + return [[-Infinity, -Infinity, Infinity, Infinity]]; +}; /** - * @const - * @type {number} + * Strategy function for loading features based on the view's extent and + * resolution. + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @return {Array.<ol.Extent>} Extents. + * @api */ -goog.webgl.ONE_MINUS_DST_COLOR = 0x0307; +ol.loadingstrategy.bbox = function(extent, resolution) { + return [extent]; +}; /** - * @const - * @type {number} + * Creates a strategy function for loading features based on a tile grid. + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @return {function(ol.Extent, number): Array.<ol.Extent>} Loading strategy. + * @api */ -goog.webgl.SRC_ALPHA_SATURATE = 0x0308; - +ol.loadingstrategy.tile = function(tileGrid) { + return ( + /** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @return {Array.<ol.Extent>} Extents. + */ + function(extent, resolution) { + var z = tileGrid.getZForResolution(resolution); + var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + /** @type {Array.<ol.Extent>} */ + var extents = []; + /** @type {ol.TileCoord} */ + var tileCoord = [z, 0, 0]; + for (tileCoord[1] = tileRange.minX; tileCoord[1] <= tileRange.maxX; + ++tileCoord[1]) { + for (tileCoord[2] = tileRange.minY; tileCoord[2] <= tileRange.maxY; + ++tileCoord[2]) { + extents.push(tileGrid.getTileCoordExtent(tileCoord)); + } + } + return extents; + }); +}; +goog.provide('ol.ext.rbush'); +/** @typedef {function(*)} */ +ol.ext.rbush; +(function() { +var exports = {}; +var module = {exports: exports}; +var define; /** - * @const - * @type {number} + * @fileoverview + * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} */ -goog.webgl.FUNC_ADD = 0x8006; +/* + (c) 2015, Vladimir Agafonkin + RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles. + https://github.com/mourner/rbush +*/ +(function () { 'use strict'; -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_EQUATION = 0x8009; +function rbush(maxEntries, format) { + // jshint newcap: false, validthis: true + if (!(this instanceof rbush)) return new rbush(maxEntries, format); -/** - * Same as BLEND_EQUATION - * @const - * @type {number} - */ -goog.webgl.BLEND_EQUATION_RGB = 0x8009; + // max entries in a node is 9 by default; min node fill is 40% for best performance + this._maxEntries = Math.max(4, maxEntries || 9); + this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); + if (format) { + this._initFormat(format); + } -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_EQUATION_ALPHA = 0x883D; + this.clear(); +} +rbush.prototype = { -/** - * @const - * @type {number} - */ -goog.webgl.FUNC_SUBTRACT = 0x800A; + all: function () { + return this._all(this.data, []); + }, + search: function (bbox) { -/** - * @const - * @type {number} - */ -goog.webgl.FUNC_REVERSE_SUBTRACT = 0x800B; + var node = this.data, + result = [], + toBBox = this.toBBox; + if (!intersects(bbox, node.bbox)) return result; -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_DST_RGB = 0x80C8; + var nodesToSearch = [], + i, len, child, childBBox; + while (node) { + for (i = 0, len = node.children.length; i < len; i++) { -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_SRC_RGB = 0x80C9; + child = node.children[i]; + childBBox = node.leaf ? toBBox(child) : child.bbox; + if (intersects(bbox, childBBox)) { + if (node.leaf) result.push(child); + else if (contains(bbox, childBBox)) this._all(child, result); + else nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_DST_ALPHA = 0x80CA; + return result; + }, + collides: function (bbox) { -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_SRC_ALPHA = 0x80CB; + var node = this.data, + toBBox = this.toBBox; + if (!intersects(bbox, node.bbox)) return false; -/** - * @const - * @type {number} - */ -goog.webgl.CONSTANT_COLOR = 0x8001; + var nodesToSearch = [], + i, len, child, childBBox; + while (node) { + for (i = 0, len = node.children.length; i < len; i++) { -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_CONSTANT_COLOR = 0x8002; + child = node.children[i]; + childBBox = node.leaf ? toBBox(child) : child.bbox; + if (intersects(bbox, childBBox)) { + if (node.leaf || contains(bbox, childBBox)) return true; + nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } -/** - * @const - * @type {number} - */ -goog.webgl.CONSTANT_ALPHA = 0x8003; + return false; + }, + load: function (data) { + if (!(data && data.length)) return this; -/** - * @const - * @type {number} - */ -goog.webgl.ONE_MINUS_CONSTANT_ALPHA = 0x8004; + if (data.length < this._minEntries) { + for (var i = 0, len = data.length; i < len; i++) { + this.insert(data[i]); + } + return this; + } + // recursively build the tree with the given data from stratch using OMT algorithm + var node = this._build(data.slice(), 0, data.length - 1, 0); -/** - * @const - * @type {number} - */ -goog.webgl.BLEND_COLOR = 0x8005; + if (!this.data.children.length) { + // save as is if tree is empty + this.data = node; + } else if (this.data.height === node.height) { + // split root if trees have the same height + this._splitRoot(this.data, node); -/** - * @const - * @type {number} - */ -goog.webgl.ARRAY_BUFFER = 0x8892; + } else { + if (this.data.height < node.height) { + // swap trees if inserted one is bigger + var tmpNode = this.data; + this.data = node; + node = tmpNode; + } + // insert the small tree into the large tree at appropriate level + this._insert(node, this.data.height - node.height - 1, true); + } -/** - * @const - * @type {number} - */ -goog.webgl.ELEMENT_ARRAY_BUFFER = 0x8893; + return this; + }, + insert: function (item) { + if (item) this._insert(item, this.data.height - 1); + return this; + }, -/** - * @const - * @type {number} - */ -goog.webgl.ARRAY_BUFFER_BINDING = 0x8894; + clear: function () { + this.data = { + children: [], + height: 1, + bbox: empty(), + leaf: true + }; + return this; + }, + remove: function (item) { + if (!item) return this; -/** - * @const - * @type {number} - */ -goog.webgl.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + var node = this.data, + bbox = this.toBBox(item), + path = [], + indexes = [], + i, parent, index, goingUp; + // depth-first iterative tree traversal + while (node || path.length) { -/** - * @const - * @type {number} - */ -goog.webgl.STREAM_DRAW = 0x88E0; + if (!node) { // go up + node = path.pop(); + parent = path[path.length - 1]; + i = indexes.pop(); + goingUp = true; + } + if (node.leaf) { // check current node + index = node.children.indexOf(item); -/** - * @const - * @type {number} - */ -goog.webgl.STATIC_DRAW = 0x88E4; - - -/** - * @const - * @type {number} - */ -goog.webgl.DYNAMIC_DRAW = 0x88E8; + if (index !== -1) { + // item found, remove the item and condense tree upwards + node.children.splice(index, 1); + path.push(node); + this._condense(path); + return this; + } + } + if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down + path.push(node); + indexes.push(i); + i = 0; + parent = node; + node = node.children[0]; -/** - * @const - * @type {number} - */ -goog.webgl.BUFFER_SIZE = 0x8764; + } else if (parent) { // go right + i++; + node = parent.children[i]; + goingUp = false; + } else node = null; // nothing found + } -/** - * @const - * @type {number} - */ -goog.webgl.BUFFER_USAGE = 0x8765; + return this; + }, + toBBox: function (item) { return item; }, -/** - * @const - * @type {number} - */ -goog.webgl.CURRENT_VERTEX_ATTRIB = 0x8626; + compareMinX: function (a, b) { return a[0] - b[0]; }, + compareMinY: function (a, b) { return a[1] - b[1]; }, + toJSON: function () { return this.data; }, -/** - * @const - * @type {number} - */ -goog.webgl.FRONT = 0x0404; + fromJSON: function (data) { + this.data = data; + return this; + }, + _all: function (node, result) { + var nodesToSearch = []; + while (node) { + if (node.leaf) result.push.apply(result, node.children); + else nodesToSearch.push.apply(nodesToSearch, node.children); -/** - * @const - * @type {number} - */ -goog.webgl.BACK = 0x0405; + node = nodesToSearch.pop(); + } + return result; + }, + _build: function (items, left, right, height) { -/** - * @const - * @type {number} - */ -goog.webgl.FRONT_AND_BACK = 0x0408; + var N = right - left + 1, + M = this._maxEntries, + node; + if (N <= M) { + // reached leaf level; return leaf + node = { + children: items.slice(left, right + 1), + height: 1, + bbox: null, + leaf: true + }; + calcBBox(node, this.toBBox); + return node; + } -/** - * @const - * @type {number} - */ -goog.webgl.CULL_FACE = 0x0B44; + if (!height) { + // target height of the bulk-loaded tree + height = Math.ceil(Math.log(N) / Math.log(M)); + // target number of root entries to maximize storage utilization + M = Math.ceil(N / Math.pow(M, height - 1)); + } -/** - * @const - * @type {number} - */ -goog.webgl.BLEND = 0x0BE2; + // TODO eliminate recursion? + node = { + children: [], + height: height, + bbox: null + }; -/** - * @const - * @type {number} - */ -goog.webgl.DITHER = 0x0BD0; + // split the items into M mostly square tiles + var N2 = Math.ceil(N / M), + N1 = N2 * Math.ceil(Math.sqrt(M)), + i, j, right2, right3; -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_TEST = 0x0B90; + multiSelect(items, left, right, N1, this.compareMinX); + for (i = left; i <= right; i += N1) { -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_TEST = 0x0B71; + right2 = Math.min(i + N1 - 1, right); + multiSelect(items, i, right2, N2, this.compareMinY); -/** - * @const - * @type {number} - */ -goog.webgl.SCISSOR_TEST = 0x0C11; + for (j = i; j <= right2; j += N2) { + right3 = Math.min(j + N2 - 1, right2); -/** - * @const - * @type {number} - */ -goog.webgl.POLYGON_OFFSET_FILL = 0x8037; + // pack each entry recursively + node.children.push(this._build(items, j, right3, height - 1)); + } + } + calcBBox(node, this.toBBox); -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_ALPHA_TO_COVERAGE = 0x809E; + return node; + }, + _chooseSubtree: function (bbox, node, level, path) { -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_COVERAGE = 0x80A0; + var i, len, child, targetNode, area, enlargement, minArea, minEnlargement; + while (true) { + path.push(node); -/** - * @const - * @type {number} - */ -goog.webgl.NO_ERROR = 0; + if (node.leaf || path.length - 1 === level) break; + minArea = minEnlargement = Infinity; -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_ENUM = 0x0500; + for (i = 0, len = node.children.length; i < len; i++) { + child = node.children[i]; + area = bboxArea(child.bbox); + enlargement = enlargedArea(bbox, child.bbox) - area; + // choose entry with the least area enlargement + if (enlargement < minEnlargement) { + minEnlargement = enlargement; + minArea = area < minArea ? area : minArea; + targetNode = child; -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_VALUE = 0x0501; + } else if (enlargement === minEnlargement) { + // otherwise choose one with the smallest area + if (area < minArea) { + minArea = area; + targetNode = child; + } + } + } + node = targetNode; + } -/** - * @const - * @type {number} - */ -goog.webgl.INVALID_OPERATION = 0x0502; + return node; + }, + _insert: function (item, level, isNode) { -/** - * @const - * @type {number} - */ -goog.webgl.OUT_OF_MEMORY = 0x0505; + var toBBox = this.toBBox, + bbox = isNode ? item.bbox : toBBox(item), + insertPath = []; + // find the best node for accommodating the item, saving all nodes along the path too + var node = this._chooseSubtree(bbox, this.data, level, insertPath); -/** - * @const - * @type {number} - */ -goog.webgl.CW = 0x0900; + // put the item into the node + node.children.push(item); + extend(node.bbox, bbox); + // split on node overflow; propagate upwards if necessary + while (level >= 0) { + if (insertPath[level].children.length > this._maxEntries) { + this._split(insertPath, level); + level--; + } else break; + } -/** - * @const - * @type {number} - */ -goog.webgl.CCW = 0x0901; + // adjust bboxes along the insertion path + this._adjustParentBBoxes(bbox, insertPath, level); + }, + // split overflowed node into two + _split: function (insertPath, level) { -/** - * @const - * @type {number} - */ -goog.webgl.LINE_WIDTH = 0x0B21; + var node = insertPath[level], + M = node.children.length, + m = this._minEntries; + this._chooseSplitAxis(node, m, M); -/** - * @const - * @type {number} - */ -goog.webgl.ALIASED_POINT_SIZE_RANGE = 0x846D; + var splitIndex = this._chooseSplitIndex(node, m, M); + var newNode = { + children: node.children.splice(splitIndex, node.children.length - splitIndex), + height: node.height + }; -/** - * @const - * @type {number} - */ -goog.webgl.ALIASED_LINE_WIDTH_RANGE = 0x846E; + if (node.leaf) newNode.leaf = true; + calcBBox(node, this.toBBox); + calcBBox(newNode, this.toBBox); -/** - * @const - * @type {number} - */ -goog.webgl.CULL_FACE_MODE = 0x0B45; + if (level) insertPath[level - 1].children.push(newNode); + else this._splitRoot(node, newNode); + }, + _splitRoot: function (node, newNode) { + // split root node + this.data = { + children: [node, newNode], + height: node.height + 1 + }; + calcBBox(this.data, this.toBBox); + }, -/** - * @const - * @type {number} - */ -goog.webgl.FRONT_FACE = 0x0B46; + _chooseSplitIndex: function (node, m, M) { + var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index; -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_RANGE = 0x0B70; + minOverlap = minArea = Infinity; + for (i = m; i <= M - m; i++) { + bbox1 = distBBox(node, 0, i, this.toBBox); + bbox2 = distBBox(node, i, M, this.toBBox); -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_WRITEMASK = 0x0B72; + overlap = intersectionArea(bbox1, bbox2); + area = bboxArea(bbox1) + bboxArea(bbox2); + // choose distribution with minimum overlap + if (overlap < minOverlap) { + minOverlap = overlap; + index = i; -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_CLEAR_VALUE = 0x0B73; + minArea = area < minArea ? area : minArea; + } else if (overlap === minOverlap) { + // otherwise choose distribution with minimum area + if (area < minArea) { + minArea = area; + index = i; + } + } + } -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_FUNC = 0x0B74; + return index; + }, + // sorts node children by the best axis for split + _chooseSplitAxis: function (node, m, M) { -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_CLEAR_VALUE = 0x0B91; + var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX, + compareMinY = node.leaf ? this.compareMinY : compareNodeMinY, + xMargin = this._allDistMargin(node, m, M, compareMinX), + yMargin = this._allDistMargin(node, m, M, compareMinY); + // if total distributions margin value is minimal for x, sort by minX, + // otherwise it's already sorted by minY + if (xMargin < yMargin) node.children.sort(compareMinX); + }, -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_FUNC = 0x0B92; + // total margin of all possible split distributions where each node is at least m full + _allDistMargin: function (node, m, M, compare) { + node.children.sort(compare); -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_FAIL = 0x0B94; + var toBBox = this.toBBox, + leftBBox = distBBox(node, 0, m, toBBox), + rightBBox = distBBox(node, M - m, M, toBBox), + margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), + i, child; + for (i = m; i < M - m; i++) { + child = node.children[i]; + extend(leftBBox, node.leaf ? toBBox(child) : child.bbox); + margin += bboxMargin(leftBBox); + } -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_PASS_DEPTH_FAIL = 0x0B95; + for (i = M - m - 1; i >= m; i--) { + child = node.children[i]; + extend(rightBBox, node.leaf ? toBBox(child) : child.bbox); + margin += bboxMargin(rightBBox); + } + return margin; + }, -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_PASS_DEPTH_PASS = 0x0B96; + _adjustParentBBoxes: function (bbox, path, level) { + // adjust bboxes along the given tree path + for (var i = level; i >= 0; i--) { + extend(path[i].bbox, bbox); + } + }, + _condense: function (path) { + // go through the path, removing empty nodes and updating bboxes + for (var i = path.length - 1, siblings; i >= 0; i--) { + if (path[i].children.length === 0) { + if (i > 0) { + siblings = path[i - 1].children; + siblings.splice(siblings.indexOf(path[i]), 1); -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_REF = 0x0B97; + } else this.clear(); + } else calcBBox(path[i], this.toBBox); + } + }, -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_VALUE_MASK = 0x0B93; + _initFormat: function (format) { + // data format (minX, minY, maxX, maxY accessors) + // uses eval-type function compilation instead of just accepting a toBBox function + // because the algorithms are very sensitive to sorting functions performance, + // so they should be dead simple and without inner calls -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_WRITEMASK = 0x0B98; + // jshint evil: true + var compareArr = ['return a', ' - b', ';']; -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_FUNC = 0x8800; + this.compareMinX = new Function('a', 'b', compareArr.join(format[0])); + this.compareMinY = new Function('a', 'b', compareArr.join(format[1])); + this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];'); + } +}; -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_FAIL = 0x8801; +// calculate node's bbox from bboxes of its children +function calcBBox(node, toBBox) { + node.bbox = distBBox(node, 0, node.children.length, toBBox); +} -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802; +// min bounding rectangle of node children from k to p-1 +function distBBox(node, k, p, toBBox) { + var bbox = empty(); + for (var i = k, child; i < p; i++) { + child = node.children[i]; + extend(bbox, node.leaf ? toBBox(child) : child.bbox); + } -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803; + return bbox; +} +function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; } -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_REF = 0x8CA3; +function extend(a, b) { + a[0] = Math.min(a[0], b[0]); + a[1] = Math.min(a[1], b[1]); + a[2] = Math.max(a[2], b[2]); + a[3] = Math.max(a[3], b[3]); + return a; +} +function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; } +function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; } -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_VALUE_MASK = 0x8CA4; +function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); } +function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); } +function enlargedArea(a, b) { + return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) * + (Math.max(b[3], a[3]) - Math.min(b[1], a[1])); +} -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BACK_WRITEMASK = 0x8CA5; +function intersectionArea(a, b) { + var minX = Math.max(a[0], b[0]), + minY = Math.max(a[1], b[1]), + maxX = Math.min(a[2], b[2]), + maxY = Math.min(a[3], b[3]); + return Math.max(0, maxX - minX) * + Math.max(0, maxY - minY); +} -/** - * @const - * @type {number} - */ -goog.webgl.VIEWPORT = 0x0BA2; +function contains(a, b) { + return a[0] <= b[0] && + a[1] <= b[1] && + b[2] <= a[2] && + b[3] <= a[3]; +} +function intersects(a, b) { + return b[0] <= a[2] && + b[1] <= a[3] && + b[2] >= a[0] && + b[3] >= a[1]; +} -/** - * @const - * @type {number} - */ -goog.webgl.SCISSOR_BOX = 0x0C10; +// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; +// combines selection algorithm with binary divide & conquer approach +function multiSelect(arr, left, right, n, compare) { + var stack = [left, right], + mid; -/** - * @const - * @type {number} - */ -goog.webgl.COLOR_CLEAR_VALUE = 0x0C22; + while (stack.length) { + right = stack.pop(); + left = stack.pop(); + if (right - left <= n) continue; -/** - * @const - * @type {number} - */ -goog.webgl.COLOR_WRITEMASK = 0x0C23; + mid = left + Math.ceil((right - left) / n / 2) * n; + select(arr, left, right, mid, compare); + stack.push(left, mid, mid, right); + } +} -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_ALIGNMENT = 0x0CF5; +// Floyd-Rivest selection algorithm: +// sort an array between left and right (inclusive) so that the smallest k elements come first (unordered) +function select(arr, left, right, k, compare) { + var n, i, z, s, sd, newLeft, newRight, t, j; + while (right > left) { + if (right - left > 600) { + n = right - left + 1; + i = k - left + 1; + z = Math.log(n); + s = 0.5 * Math.exp(2 * z / 3); + sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1); + newLeft = Math.max(left, Math.floor(k - i * s / n + sd)); + newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd)); + select(arr, newLeft, newRight, k, compare); + } -/** - * @const - * @type {number} - */ -goog.webgl.PACK_ALIGNMENT = 0x0D05; + t = arr[k]; + i = left; + j = right; + swap(arr, left, k); + if (compare(arr[right], t) > 0) swap(arr, left, right); -/** - * @const - * @type {number} - */ -goog.webgl.MAX_TEXTURE_SIZE = 0x0D33; + while (i < j) { + swap(arr, i, j); + i++; + j--; + while (compare(arr[i], t) < 0) i++; + while (compare(arr[j], t) > 0) j--; + } + if (compare(arr[left], t) === 0) swap(arr, left, j); + else { + j++; + swap(arr, j, right); + } -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VIEWPORT_DIMS = 0x0D3A; + if (j <= k) left = j + 1; + if (k <= j) right = j - 1; + } +} +function swap(arr, i, j) { + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} -/** - * @const - * @type {number} - */ -goog.webgl.SUBPIXEL_BITS = 0x0D50; +// export as AMD/CommonJS module or global variable +if (typeof define === 'function' && define.amd) define('rbush', function() { return rbush; }); +else if (typeof module !== 'undefined') module.exports = rbush; +else if (typeof self !== 'undefined') self.rbush = rbush; +else window.rbush = rbush; -/** - * @const - * @type {number} - */ -goog.webgl.RED_BITS = 0x0D52; +})(); +ol.ext.rbush = module.exports; +})(); -/** - * @const - * @type {number} - */ -goog.webgl.GREEN_BITS = 0x0D53; +goog.provide('ol.structs.RBush'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol.ext.rbush'); +goog.require('ol.extent'); -/** - * @const - * @type {number} - */ -goog.webgl.BLUE_BITS = 0x0D54; /** - * @const - * @type {number} + * Wrapper around the RBush by Vladimir Agafonkin. + * + * @constructor + * @param {number=} opt_maxEntries Max entries. + * @see https://github.com/mourner/rbush + * @struct + * @template T */ -goog.webgl.ALPHA_BITS = 0x0D55; - +ol.structs.RBush = function(opt_maxEntries) { -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_BITS = 0x0D56; + /** + * @private + */ + this.rbush_ = ol.ext.rbush(opt_maxEntries); + /** + * A mapping between the objects added to this rbush wrapper + * and the objects that are actually added to the internal rbush. + * @private + * @type {Object.<number, Object>} + */ + this.items_ = {}; -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_BITS = 0x0D57; + if (goog.DEBUG) { + /** + * @private + * @type {number} + */ + this.readers_ = 0; + } +}; /** - * @const - * @type {number} + * Insert a value into the RBush. + * @param {ol.Extent} extent Extent. + * @param {T} value Value. */ -goog.webgl.POLYGON_OFFSET_UNITS = 0x2A00; +ol.structs.RBush.prototype.insert = function(extent, value) { + if (goog.DEBUG && this.readers_) { + throw new Error('Can not insert value while reading'); + } + var item = [ + extent[0], + extent[1], + extent[2], + extent[3], + value + ]; + this.rbush_.insert(item); + // remember the object that was added to the internal rbush + goog.asserts.assert( + !goog.object.containsKey(this.items_, goog.getUid(value)), + 'uid (%s) of value (%s) already exists', goog.getUid(value), value); + this.items_[goog.getUid(value)] = item; +}; /** - * @const - * @type {number} + * Bulk-insert values into the RBush. + * @param {Array.<ol.Extent>} extents Extents. + * @param {Array.<T>} values Values. */ -goog.webgl.POLYGON_OFFSET_FACTOR = 0x8038; +ol.structs.RBush.prototype.load = function(extents, values) { + if (goog.DEBUG && this.readers_) { + throw new Error('Can not insert values while reading'); + } + goog.asserts.assert(extents.length === values.length, + 'extens and values must have same length (%s === %s)', + extents.length, values.length); + var items = new Array(values.length); + for (var i = 0, l = values.length; i < l; i++) { + var extent = extents[i]; + var value = values[i]; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_BINDING_2D = 0x8069; + var item = [ + extent[0], + extent[1], + extent[2], + extent[3], + value + ]; + items[i] = item; + goog.asserts.assert( + !goog.object.containsKey(this.items_, goog.getUid(value)), + 'uid (%s) of value (%s) already exists', goog.getUid(value), value); + this.items_[goog.getUid(value)] = item; + } + this.rbush_.load(items); +}; /** - * @const - * @type {number} + * Remove a value from the RBush. + * @param {T} value Value. + * @return {boolean} Removed. */ -goog.webgl.SAMPLE_BUFFERS = 0x80A8; - +ol.structs.RBush.prototype.remove = function(value) { + if (goog.DEBUG && this.readers_) { + throw new Error('Can not remove value while reading'); + } + var uid = goog.getUid(value); + goog.asserts.assert(goog.object.containsKey(this.items_, uid), + 'uid (%s) of value (%s) does not exist', uid, value); -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLES = 0x80A9; + // get the object in which the value was wrapped when adding to the + // internal rbush. then use that object to do the removal. + var item = this.items_[uid]; + delete this.items_[uid]; + return this.rbush_.remove(item) !== null; +}; /** - * @const - * @type {number} + * Update the extent of a value in the RBush. + * @param {ol.Extent} extent Extent. + * @param {T} value Value. */ -goog.webgl.SAMPLE_COVERAGE_VALUE = 0x80AA; - +ol.structs.RBush.prototype.update = function(extent, value) { + var uid = goog.getUid(value); + goog.asserts.assert(goog.object.containsKey(this.items_, uid), + 'uid (%s) of value (%s) does not exist', uid, value); -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLE_COVERAGE_INVERT = 0x80AB; + var item = this.items_[uid]; + if (!ol.extent.equals(item.slice(0, 4), extent)) { + if (goog.DEBUG && this.readers_) { + throw new Error('Can not update extent while reading'); + } + this.remove(value); + this.insert(extent, value); + } +}; /** - * @const - * @type {number} + * Return all values in the RBush. + * @return {Array.<T>} All. */ -goog.webgl.COMPRESSED_TEXTURE_FORMATS = 0x86A3; +ol.structs.RBush.prototype.getAll = function() { + var items = this.rbush_.all(); + return items.map(function(item) { + return item[4]; + }); +}; /** - * @const - * @type {number} + * Return all values in the given extent. + * @param {ol.Extent} extent Extent. + * @return {Array.<T>} All in extent. */ -goog.webgl.DONT_CARE = 0x1100; +ol.structs.RBush.prototype.getInExtent = function(extent) { + var items = this.rbush_.search(extent); + return items.map(function(item) { + return item[4]; + }); +}; /** - * @const - * @type {number} + * Calls a callback function with each value in the tree. + * If the callback returns a truthy value, this value is returned without + * checking the rest of the tree. + * @param {function(this: S, T): *} callback Callback. + * @param {S=} opt_this The object to use as `this` in `callback`. + * @return {*} Callback return value. + * @template S */ -goog.webgl.FASTEST = 0x1101; +ol.structs.RBush.prototype.forEach = function(callback, opt_this) { + if (goog.DEBUG) { + ++this.readers_; + try { + return this.forEach_(this.getAll(), callback, opt_this); + } finally { + --this.readers_; + } + } else { + return this.forEach_(this.getAll(), callback, opt_this); + } +}; /** - * @const - * @type {number} + * Calls a callback function with each value in the provided extent. + * @param {ol.Extent} extent Extent. + * @param {function(this: S, T): *} callback Callback. + * @param {S=} opt_this The object to use as `this` in `callback`. + * @return {*} Callback return value. + * @template S */ -goog.webgl.NICEST = 0x1102; +ol.structs.RBush.prototype.forEachInExtent = + function(extent, callback, opt_this) { + if (goog.DEBUG) { + ++this.readers_; + try { + return this.forEach_(this.getInExtent(extent), callback, opt_this); + } finally { + --this.readers_; + } + } else { + return this.forEach_(this.getInExtent(extent), callback, opt_this); + } +}; /** - * @const - * @type {number} + * @param {Array.<T>} values Values. + * @param {function(this: S, T): *} callback Callback. + * @param {S=} opt_this The object to use as `this` in `callback`. + * @private + * @return {*} Callback return value. + * @template S */ -goog.webgl.GENERATE_MIPMAP_HINT = 0x8192; +ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) { + var result; + for (var i = 0, l = values.length; i < l; i++) { + result = callback.call(opt_this, values[i]); + if (result) { + return result; + } + } + return result; +}; /** - * @const - * @type {number} + * @return {boolean} Is empty. */ -goog.webgl.BYTE = 0x1400; +ol.structs.RBush.prototype.isEmpty = function() { + return goog.object.isEmpty(this.items_); +}; /** - * @const - * @type {number} + * Remove all values from the RBush. */ -goog.webgl.UNSIGNED_BYTE = 0x1401; +ol.structs.RBush.prototype.clear = function() { + this.rbush_.clear(); + this.items_ = {}; +}; /** - * @const - * @type {number} + * @param {ol.Extent=} opt_extent Extent. + * @return {!ol.Extent} Extent. */ -goog.webgl.SHORT = 0x1402; - +ol.structs.RBush.prototype.getExtent = function(opt_extent) { + // FIXME add getExtent() to rbush + return this.rbush_.data.bbox; +}; -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT = 0x1403; +// FIXME bulk feature upload - suppress events +// FIXME make change-detection more refined (notably, geometry hint) +goog.provide('ol.source.Vector'); +goog.provide('ol.source.VectorEvent'); +goog.provide('ol.source.VectorEventType'); -/** - * @const - * @type {number} - */ -goog.webgl.INT = 0x1404; +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Collection'); +goog.require('ol.CollectionEventType'); +goog.require('ol.Extent'); +goog.require('ol.Feature'); +goog.require('ol.FeatureLoader'); +goog.require('ol.LoadingStrategy'); +goog.require('ol.ObjectEventType'); +goog.require('ol.extent'); +goog.require('ol.featureloader'); +goog.require('ol.loadingstrategy'); +goog.require('ol.proj'); +goog.require('ol.source.Source'); +goog.require('ol.source.State'); +goog.require('ol.structs.RBush'); /** - * @const - * @type {number} + * @enum {string} */ -goog.webgl.UNSIGNED_INT = 0x1405; +ol.source.VectorEventType = { + /** + * Triggered when a feature is added to the source. + * @event ol.source.VectorEvent#addfeature + * @api stable + */ + ADDFEATURE: 'addfeature', + /** + * Triggered when a feature is updated. + * @event ol.source.VectorEvent#changefeature + * @api + */ + CHANGEFEATURE: 'changefeature', -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT = 0x1406; + /** + * Triggered when the clear method is called on the source. + * @event ol.source.VectorEvent#clear + * @api + */ + CLEAR: 'clear', + /** + * Triggered when a feature is removed from the source. + * See {@link ol.source.Vector#clear source.clear()} for exceptions. + * @event ol.source.VectorEvent#removefeature + * @api stable + */ + REMOVEFEATURE: 'removefeature' +}; -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_COMPONENT = 0x1902; /** - * @const - * @type {number} + * @classdesc + * Provides a source of features for vector layers. Vector features provided + * by this source are suitable for editing. See {@link ol.source.VectorTile} for + * vector data that is optimized for rendering. + * + * @constructor + * @extends {ol.source.Source} + * @fires ol.source.VectorEvent + * @param {olx.source.VectorOptions=} opt_options Vector source options. + * @api stable */ -goog.webgl.ALPHA = 0x1906; +ol.source.Vector = function(opt_options) { + var options = opt_options || {}; -/** - * @const - * @type {number} - */ -goog.webgl.RGB = 0x1907; + goog.base(this, { + attributions: options.attributions, + logo: options.logo, + projection: undefined, + state: ol.source.State.READY, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); + /** + * @private + * @type {ol.FeatureLoader} + */ + this.loader_ = ol.nullFunction; -/** - * @const - * @type {number} - */ -goog.webgl.RGBA = 0x1908; - + if (options.loader !== undefined) { + this.loader_ = options.loader; + } else if (options.url !== undefined) { + goog.asserts.assert(options.format !== undefined, + 'format must be set when url is set'); + // create a XHR feature loader for "url" and "format" + this.loader_ = ol.featureloader.xhr(options.url, options.format); + } -/** - * @const - * @type {number} - */ -goog.webgl.LUMINANCE = 0x1909; + /** + * @private + * @type {ol.LoadingStrategy} + */ + this.strategy_ = options.strategy !== undefined ? options.strategy : + ol.loadingstrategy.all; + var useSpatialIndex = + options.useSpatialIndex !== undefined ? options.useSpatialIndex : true; -/** - * @const - * @type {number} - */ -goog.webgl.LUMINANCE_ALPHA = 0x190A; + /** + * @private + * @type {ol.structs.RBush.<ol.Feature>} + */ + this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null; + /** + * @private + * @type {ol.structs.RBush.<{extent: ol.Extent}>} + */ + this.loadedExtentsRtree_ = new ol.structs.RBush(); -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT_4_4_4_4 = 0x8033; + /** + * @private + * @type {Object.<string, ol.Feature>} + */ + this.nullGeometryFeatures_ = {}; + /** + * A lookup of features by id (the return from feature.getId()). + * @private + * @type {Object.<string, ol.Feature>} + */ + this.idIndex_ = {}; -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT_5_5_5_1 = 0x8034; + /** + * A lookup of features without id (keyed by goog.getUid(feature)). + * @private + * @type {Object.<string, ol.Feature>} + */ + this.undefIdIndex_ = {}; + /** + * @private + * @type {Object.<string, Array.<goog.events.Key>>} + */ + this.featureChangeKeys_ = {}; -/** - * @const - * @type {number} - */ -goog.webgl.UNSIGNED_SHORT_5_6_5 = 0x8363; + /** + * @private + * @type {ol.Collection.<ol.Feature>} + */ + this.featuresCollection_ = null; + var collection, features; + if (options.features instanceof ol.Collection) { + collection = options.features; + features = collection.getArray(); + } else if (goog.isArray(options.features)) { + features = options.features; + } + if (!useSpatialIndex && collection === undefined) { + collection = new ol.Collection(features); + } + if (features !== undefined) { + this.addFeaturesInternal(features); + } + if (collection !== undefined) { + this.bindFeaturesCollection_(collection); + } -/** - * @const - * @type {number} - */ -goog.webgl.FRAGMENT_SHADER = 0x8B30; +}; +goog.inherits(ol.source.Vector, ol.source.Source); /** - * @const - * @type {number} + * Add a single feature to the source. If you want to add a batch of features + * at once, call {@link ol.source.Vector#addFeatures source.addFeatures()} + * instead. + * @param {ol.Feature} feature Feature to add. + * @api stable */ -goog.webgl.VERTEX_SHADER = 0x8B31; +ol.source.Vector.prototype.addFeature = function(feature) { + this.addFeatureInternal(feature); + this.changed(); +}; /** - * @const - * @type {number} + * Add a feature without firing a `change` event. + * @param {ol.Feature} feature Feature. + * @protected */ -goog.webgl.MAX_VERTEX_ATTRIBS = 0x8869; +ol.source.Vector.prototype.addFeatureInternal = function(feature) { + var featureKey = goog.getUid(feature).toString(); + if (!this.addToIndex_(featureKey, feature)) { + return; + } -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; + this.setupChangeEvents_(featureKey, feature); + var geometry = feature.getGeometry(); + if (geometry) { + var extent = geometry.getExtent(); + if (this.featuresRtree_) { + this.featuresRtree_.insert(extent, feature); + } + } else { + this.nullGeometryFeatures_[featureKey] = feature; + } -/** - * @const - * @type {number} - */ -goog.webgl.MAX_VARYING_VECTORS = 0x8DFC; + this.dispatchEvent( + new ol.source.VectorEvent(ol.source.VectorEventType.ADDFEATURE, feature)); +}; /** - * @const - * @type {number} + * @param {string} featureKey + * @param {ol.Feature} feature + * @private */ -goog.webgl.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; +ol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) { + goog.asserts.assert(!(featureKey in this.featureChangeKeys_), + 'key (%s) not yet registered in featureChangeKey', featureKey); + this.featureChangeKeys_[featureKey] = [ + goog.events.listen(feature, + goog.events.EventType.CHANGE, + this.handleFeatureChange_, false, this), + goog.events.listen(feature, + ol.ObjectEventType.PROPERTYCHANGE, + this.handleFeatureChange_, false, this) + ]; +}; /** - * @const - * @type {number} + * @param {string} featureKey + * @param {ol.Feature} feature + * @return {boolean} `true` if the feature is "valid", in the sense that it is + * also a candidate for insertion into the Rtree, otherwise `false`. + * @private */ -goog.webgl.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; +ol.source.Vector.prototype.addToIndex_ = function(featureKey, feature) { + var valid = true; + var id = feature.getId(); + if (id !== undefined) { + if (!(id.toString() in this.idIndex_)) { + this.idIndex_[id.toString()] = feature; + } else { + valid = false; + } + } else { + goog.asserts.assert(!(featureKey in this.undefIdIndex_), + 'Feature already added to the source'); + this.undefIdIndex_[featureKey] = feature; + } + return valid; +}; /** - * @const - * @type {number} + * Add a batch of features to the source. + * @param {Array.<ol.Feature>} features Features to add. + * @api stable */ -goog.webgl.MAX_TEXTURE_IMAGE_UNITS = 0x8872; +ol.source.Vector.prototype.addFeatures = function(features) { + this.addFeaturesInternal(features); + this.changed(); +}; /** - * @const - * @type {number} + * Add features without firing a `change` event. + * @param {Array.<ol.Feature>} features Features. + * @protected */ -goog.webgl.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; +ol.source.Vector.prototype.addFeaturesInternal = function(features) { + var featureKey, i, length, feature; + var extents = []; + var newFeatures = []; + var geometryFeatures = []; -/** - * @const - * @type {number} - */ -goog.webgl.SHADER_TYPE = 0x8B4F; + for (i = 0, length = features.length; i < length; i++) { + feature = features[i]; + featureKey = goog.getUid(feature).toString(); + if (this.addToIndex_(featureKey, feature)) { + newFeatures.push(feature); + } + } + for (i = 0, length = newFeatures.length; i < length; i++) { + feature = newFeatures[i]; + featureKey = goog.getUid(feature).toString(); + this.setupChangeEvents_(featureKey, feature); -/** - * @const - * @type {number} - */ -goog.webgl.DELETE_STATUS = 0x8B80; + var geometry = feature.getGeometry(); + if (geometry) { + var extent = geometry.getExtent(); + extents.push(extent); + geometryFeatures.push(feature); + } else { + this.nullGeometryFeatures_[featureKey] = feature; + } + } + if (this.featuresRtree_) { + this.featuresRtree_.load(extents, geometryFeatures); + } + + for (i = 0, length = newFeatures.length; i < length; i++) { + this.dispatchEvent(new ol.source.VectorEvent( + ol.source.VectorEventType.ADDFEATURE, newFeatures[i])); + } +}; /** - * @const - * @type {number} + * @param {!ol.Collection.<ol.Feature>} collection Collection. + * @private */ -goog.webgl.LINK_STATUS = 0x8B82; +ol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) { + goog.asserts.assert(!this.featuresCollection_, + 'bindFeaturesCollection can only be called once'); + var modifyingCollection = false; + goog.events.listen(this, ol.source.VectorEventType.ADDFEATURE, + function(evt) { + if (!modifyingCollection) { + modifyingCollection = true; + collection.push(evt.feature); + modifyingCollection = false; + } + }); + goog.events.listen(this, ol.source.VectorEventType.REMOVEFEATURE, + function(evt) { + if (!modifyingCollection) { + modifyingCollection = true; + collection.remove(evt.feature); + modifyingCollection = false; + } + }); + goog.events.listen(collection, ol.CollectionEventType.ADD, + function(evt) { + if (!modifyingCollection) { + var feature = evt.element; + goog.asserts.assertInstanceof(feature, ol.Feature); + modifyingCollection = true; + this.addFeature(feature); + modifyingCollection = false; + } + }, false, this); + goog.events.listen(collection, ol.CollectionEventType.REMOVE, + function(evt) { + if (!modifyingCollection) { + var feature = evt.element; + goog.asserts.assertInstanceof(feature, ol.Feature); + modifyingCollection = true; + this.removeFeature(feature); + modifyingCollection = false; + } + }, false, this); + this.featuresCollection_ = collection; +}; /** - * @const - * @type {number} + * Remove all features from the source. + * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events. + * @api stable */ -goog.webgl.VALIDATE_STATUS = 0x8B83; +ol.source.Vector.prototype.clear = function(opt_fast) { + if (opt_fast) { + for (var featureId in this.featureChangeKeys_) { + var keys = this.featureChangeKeys_[featureId]; + keys.forEach(goog.events.unlistenByKey); + } + if (!this.featuresCollection_) { + this.featureChangeKeys_ = {}; + this.idIndex_ = {}; + this.undefIdIndex_ = {}; + } + } else { + var rmFeatureInternal = this.removeFeatureInternal; + if (this.featuresRtree_) { + this.featuresRtree_.forEach(rmFeatureInternal, this); + goog.object.forEach(this.nullGeometryFeatures_, rmFeatureInternal, this); + } + } + if (this.featuresCollection_) { + this.featuresCollection_.clear(); + } + goog.asserts.assert(goog.object.isEmpty(this.featureChangeKeys_), + 'featureChangeKeys is an empty object now'); + goog.asserts.assert(goog.object.isEmpty(this.idIndex_), + 'idIndex is an empty object now'); + goog.asserts.assert(goog.object.isEmpty(this.undefIdIndex_), + 'undefIdIndex is an empty object now'); + if (this.featuresRtree_) { + this.featuresRtree_.clear(); + } + this.loadedExtentsRtree_.clear(); + this.nullGeometryFeatures_ = {}; -/** - * @const - * @type {number} - */ -goog.webgl.ATTACHED_SHADERS = 0x8B85; + var clearEvent = new ol.source.VectorEvent(ol.source.VectorEventType.CLEAR); + this.dispatchEvent(clearEvent); + this.changed(); +}; /** - * @const - * @type {number} + * Iterate through all features on the source, calling the provided callback + * with each one. If the callback returns any "truthy" value, iteration will + * stop and the function will return the same value. + * + * @param {function(this: T, ol.Feature): S} callback Called with each feature + * on the source. Return a truthy value to stop iteration. + * @param {T=} opt_this The object to use as `this` in the callback. + * @return {S|undefined} The return value from the last call to the callback. + * @template T,S + * @api stable */ -goog.webgl.ACTIVE_UNIFORMS = 0x8B86; +ol.source.Vector.prototype.forEachFeature = function(callback, opt_this) { + if (this.featuresRtree_) { + return this.featuresRtree_.forEach(callback, opt_this); + } else if (this.featuresCollection_) { + return this.featuresCollection_.forEach(callback, opt_this); + } +}; /** - * @const - * @type {number} + * Iterate through all features whose geometries contain the provided + * coordinate, calling the callback with each feature. If the callback returns + * a "truthy" value, iteration will stop and the function will return the same + * value. + * + * @param {ol.Coordinate} coordinate Coordinate. + * @param {function(this: T, ol.Feature): S} callback Called with each feature + * whose goemetry contains the provided coordinate. + * @param {T=} opt_this The object to use as `this` in the callback. + * @return {S|undefined} The return value from the last call to the callback. + * @template T,S */ -goog.webgl.ACTIVE_ATTRIBUTES = 0x8B89; +ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect = + function(coordinate, callback, opt_this) { + var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]]; + return this.forEachFeatureInExtent(extent, function(feature) { + var geometry = feature.getGeometry(); + goog.asserts.assert(geometry, 'feature geometry is defined and not null'); + if (geometry.containsCoordinate(coordinate)) { + return callback.call(opt_this, feature); + } else { + return undefined; + } + }); +}; /** - * @const - * @type {number} + * Iterate through all features whose bounding box intersects the provided + * extent (note that the feature's geometry may not intersect the extent), + * calling the callback with each feature. If the callback returns a "truthy" + * value, iteration will stop and the function will return the same value. + * + * If you are interested in features whose geometry intersects an extent, call + * the {@link ol.source.Vector#forEachFeatureIntersectingExtent + * source.forEachFeatureIntersectingExtent()} method instead. + * + * When `useSpatialIndex` is set to false, this method will loop through all + * features, equivalent to {@link ol.source.Vector#forEachFeature}. + * + * @param {ol.Extent} extent Extent. + * @param {function(this: T, ol.Feature): S} callback Called with each feature + * whose bounding box intersects the provided extent. + * @param {T=} opt_this The object to use as `this` in the callback. + * @return {S|undefined} The return value from the last call to the callback. + * @template T,S + * @api */ -goog.webgl.SHADING_LANGUAGE_VERSION = 0x8B8C; +ol.source.Vector.prototype.forEachFeatureInExtent = + function(extent, callback, opt_this) { + if (this.featuresRtree_) { + return this.featuresRtree_.forEachInExtent(extent, callback, opt_this); + } else if (this.featuresCollection_) { + return this.featuresCollection_.forEach(callback, opt_this); + } +}; /** - * @const - * @type {number} + * Iterate through all features whose geometry intersects the provided extent, + * calling the callback with each feature. If the callback returns a "truthy" + * value, iteration will stop and the function will return the same value. + * + * If you only want to test for bounding box intersection, call the + * {@link ol.source.Vector#forEachFeatureInExtent + * source.forEachFeatureInExtent()} method instead. + * + * @param {ol.Extent} extent Extent. + * @param {function(this: T, ol.Feature): S} callback Called with each feature + * whose geometry intersects the provided extent. + * @param {T=} opt_this The object to use as `this` in the callback. + * @return {S|undefined} The return value from the last call to the callback. + * @template T,S + * @api */ -goog.webgl.CURRENT_PROGRAM = 0x8B8D; +ol.source.Vector.prototype.forEachFeatureIntersectingExtent = + function(extent, callback, opt_this) { + return this.forEachFeatureInExtent(extent, + /** + * @param {ol.Feature} feature Feature. + * @return {S|undefined} + * @template S + */ + function(feature) { + var geometry = feature.getGeometry(); + goog.asserts.assert(geometry, + 'feature geometry is defined and not null'); + if (geometry.intersectsExtent(extent)) { + var result = callback.call(opt_this, feature); + if (result) { + return result; + } + } + }); +}; /** - * @const - * @type {number} + * Get the features collection associated with this source. Will be `null` + * unless the source was configured with `useSpatialIndex` set to `false`, or + * with an {@link ol.Collection} as `features`. + * @return {ol.Collection.<ol.Feature>} + * @api */ -goog.webgl.NEVER = 0x0200; +ol.source.Vector.prototype.getFeaturesCollection = function() { + return this.featuresCollection_; +}; /** - * @const - * @type {number} + * Get all features on the source. + * @return {Array.<ol.Feature>} Features. + * @api stable */ -goog.webgl.LESS = 0x0201; +ol.source.Vector.prototype.getFeatures = function() { + var features; + if (this.featuresCollection_) { + features = this.featuresCollection_.getArray(); + } else if (this.featuresRtree_) { + features = this.featuresRtree_.getAll(); + if (!goog.object.isEmpty(this.nullGeometryFeatures_)) { + goog.array.extend( + features, goog.object.getValues(this.nullGeometryFeatures_)); + } + } + goog.asserts.assert(features !== undefined, + 'Neither featuresRtree_ nor featuresCollection_ are available'); + return features; +}; /** - * @const - * @type {number} + * Get all features whose geometry intersects the provided coordinate. + * @param {ol.Coordinate} coordinate Coordinate. + * @return {Array.<ol.Feature>} Features. + * @api stable */ -goog.webgl.EQUAL = 0x0202; +ol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) { + var features = []; + this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) { + features.push(feature); + }); + return features; +}; /** - * @const - * @type {number} - */ -goog.webgl.LEQUAL = 0x0203; + * Get all features in the provided extent. Note that this returns all features + * whose bounding boxes intersect the given extent (so it may include features + * whose geometries do not intersect the extent). + * + * This method is not available when the source is configured with + * `useSpatialIndex` set to `false`. + * @param {ol.Extent} extent Extent. + * @return {Array.<ol.Feature>} Features. + * @api + */ +ol.source.Vector.prototype.getFeaturesInExtent = function(extent) { + goog.asserts.assert(this.featuresRtree_, + 'getFeaturesInExtent does not work when useSpatialIndex is set to false'); + return this.featuresRtree_.getInExtent(extent); +}; /** - * @const - * @type {number} + * Get the closest feature to the provided coordinate. + * + * This method is not available when the source is configured with + * `useSpatialIndex` set to `false`. + * @param {ol.Coordinate} coordinate Coordinate. + * @return {ol.Feature} Closest feature. + * @api stable */ -goog.webgl.GREATER = 0x0204; +ol.source.Vector.prototype.getClosestFeatureToCoordinate = + function(coordinate) { + // Find the closest feature using branch and bound. We start searching an + // infinite extent, and find the distance from the first feature found. This + // becomes the closest feature. We then compute a smaller extent which any + // closer feature must intersect. We continue searching with this smaller + // extent, trying to find a closer feature. Every time we find a closer + // feature, we update the extent being searched so that any even closer + // feature must intersect it. We continue until we run out of features. + var x = coordinate[0]; + var y = coordinate[1]; + var closestFeature = null; + var closestPoint = [NaN, NaN]; + var minSquaredDistance = Infinity; + var extent = [-Infinity, -Infinity, Infinity, Infinity]; + goog.asserts.assert(this.featuresRtree_, + 'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' + + 'to false'); + this.featuresRtree_.forEachInExtent(extent, + /** + * @param {ol.Feature} feature Feature. + */ + function(feature) { + var geometry = feature.getGeometry(); + goog.asserts.assert(geometry, + 'feature geometry is defined and not null'); + var previousMinSquaredDistance = minSquaredDistance; + minSquaredDistance = geometry.closestPointXY( + x, y, closestPoint, minSquaredDistance); + if (minSquaredDistance < previousMinSquaredDistance) { + closestFeature = feature; + // This is sneaky. Reduce the extent that it is currently being + // searched while the R-Tree traversal using this same extent object + // is still in progress. This is safe because the new extent is + // strictly contained by the old extent. + var minDistance = Math.sqrt(minSquaredDistance); + extent[0] = x - minDistance; + extent[1] = y - minDistance; + extent[2] = x + minDistance; + extent[3] = y + minDistance; + } + }); + return closestFeature; +}; /** - * @const - * @type {number} + * Get the extent of the features currently in the source. + * + * This method is not available when the source is configured with + * `useSpatialIndex` set to `false`. + * @return {!ol.Extent} Extent. + * @api stable */ -goog.webgl.NOTEQUAL = 0x0205; +ol.source.Vector.prototype.getExtent = function() { + goog.asserts.assert(this.featuresRtree_, + 'getExtent does not work when useSpatialIndex is set to false'); + return this.featuresRtree_.getExtent(); +}; /** - * @const - * @type {number} + * Get a feature by its identifier (the value returned by feature.getId()). + * Note that the index treats string and numeric identifiers as the same. So + * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`. + * + * @param {string|number} id Feature identifier. + * @return {ol.Feature} The feature (or `null` if not found). + * @api stable */ -goog.webgl.GEQUAL = 0x0206; +ol.source.Vector.prototype.getFeatureById = function(id) { + var feature = this.idIndex_[id.toString()]; + return feature !== undefined ? feature : null; +}; /** - * @const - * @type {number} + * @param {goog.events.Event} event Event. + * @private */ -goog.webgl.ALWAYS = 0x0207; +ol.source.Vector.prototype.handleFeatureChange_ = function(event) { + var feature = /** @type {ol.Feature} */ (event.target); + var featureKey = goog.getUid(feature).toString(); + var geometry = feature.getGeometry(); + if (!geometry) { + if (!(featureKey in this.nullGeometryFeatures_)) { + if (this.featuresRtree_) { + this.featuresRtree_.remove(feature); + } + this.nullGeometryFeatures_[featureKey] = feature; + } + } else { + var extent = geometry.getExtent(); + if (featureKey in this.nullGeometryFeatures_) { + delete this.nullGeometryFeatures_[featureKey]; + if (this.featuresRtree_) { + this.featuresRtree_.insert(extent, feature); + } + } else { + if (this.featuresRtree_) { + this.featuresRtree_.update(extent, feature); + } + } + } + var id = feature.getId(); + var removed; + if (id !== undefined) { + var sid = id.toString(); + if (featureKey in this.undefIdIndex_) { + delete this.undefIdIndex_[featureKey]; + this.idIndex_[sid] = feature; + } else { + if (this.idIndex_[sid] !== feature) { + removed = this.removeFromIdIndex_(feature); + goog.asserts.assert(removed, + 'Expected feature to be removed from index'); + this.idIndex_[sid] = feature; + } + } + } else { + if (!(featureKey in this.undefIdIndex_)) { + removed = this.removeFromIdIndex_(feature); + goog.asserts.assert(removed, + 'Expected feature to be removed from index'); + this.undefIdIndex_[featureKey] = feature; + } else { + goog.asserts.assert(this.undefIdIndex_[featureKey] === feature, + 'feature keyed under %s in undefIdKeys', featureKey); + } + } + this.changed(); + this.dispatchEvent(new ol.source.VectorEvent( + ol.source.VectorEventType.CHANGEFEATURE, feature)); +}; /** - * @const - * @type {number} + * @return {boolean} Is empty. */ -goog.webgl.KEEP = 0x1E00; +ol.source.Vector.prototype.isEmpty = function() { + return this.featuresRtree_.isEmpty() && + goog.object.isEmpty(this.nullGeometryFeatures_); +}; /** - * @const - * @type {number} + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {ol.proj.Projection} projection Projection. */ -goog.webgl.REPLACE = 0x1E01; +ol.source.Vector.prototype.loadFeatures = function( + extent, resolution, projection) { + var loadedExtentsRtree = this.loadedExtentsRtree_; + var extentsToLoad = this.strategy_(extent, resolution); + var i, ii; + for (i = 0, ii = extentsToLoad.length; i < ii; ++i) { + var extentToLoad = extentsToLoad[i]; + var alreadyLoaded = loadedExtentsRtree.forEachInExtent(extentToLoad, + /** + * @param {{extent: ol.Extent}} object Object. + * @return {boolean} Contains. + */ + function(object) { + return ol.extent.containsExtent(object.extent, extentToLoad); + }); + if (!alreadyLoaded) { + this.loader_.call(this, extentToLoad, resolution, projection); + loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()}); + } + } +}; /** - * @const - * @type {number} + * Remove a single feature from the source. If you want to remove all features + * at once, use the {@link ol.source.Vector#clear source.clear()} method + * instead. + * @param {ol.Feature} feature Feature to remove. + * @api stable */ -goog.webgl.INCR = 0x1E02; +ol.source.Vector.prototype.removeFeature = function(feature) { + var featureKey = goog.getUid(feature).toString(); + if (featureKey in this.nullGeometryFeatures_) { + delete this.nullGeometryFeatures_[featureKey]; + } else { + if (this.featuresRtree_) { + this.featuresRtree_.remove(feature); + } + } + this.removeFeatureInternal(feature); + this.changed(); +}; /** - * @const - * @type {number} + * Remove feature without firing a `change` event. + * @param {ol.Feature} feature Feature. + * @protected */ -goog.webgl.DECR = 0x1E03; +ol.source.Vector.prototype.removeFeatureInternal = function(feature) { + var featureKey = goog.getUid(feature).toString(); + goog.asserts.assert(featureKey in this.featureChangeKeys_, + 'featureKey exists in featureChangeKeys'); + this.featureChangeKeys_[featureKey].forEach(goog.events.unlistenByKey); + delete this.featureChangeKeys_[featureKey]; + var id = feature.getId(); + if (id !== undefined) { + delete this.idIndex_[id.toString()]; + } else { + delete this.undefIdIndex_[featureKey]; + } + this.dispatchEvent(new ol.source.VectorEvent( + ol.source.VectorEventType.REMOVEFEATURE, feature)); +}; /** - * @const - * @type {number} + * Remove a feature from the id index. Called internally when the feature id + * may have changed. + * @param {ol.Feature} feature The feature. + * @return {boolean} Removed the feature from the index. + * @private */ -goog.webgl.INVERT = 0x150A; +ol.source.Vector.prototype.removeFromIdIndex_ = function(feature) { + var removed = false; + for (var id in this.idIndex_) { + if (this.idIndex_[id] === feature) { + delete this.idIndex_[id]; + removed = true; + break; + } + } + return removed; +}; + /** - * @const - * @type {number} + * @classdesc + * Events emitted by {@link ol.source.Vector} instances are instances of this + * type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.source.VectorEvent} + * @param {string} type Type. + * @param {ol.Feature=} opt_feature Feature. */ -goog.webgl.INCR_WRAP = 0x8507; +ol.source.VectorEvent = function(type, opt_feature) { + goog.base(this, type); -/** - * @const - * @type {number} - */ -goog.webgl.DECR_WRAP = 0x8508; + /** + * The feature being added or removed. + * @type {ol.Feature|undefined} + * @api stable + */ + this.feature = opt_feature; +}; +goog.inherits(ol.source.VectorEvent, goog.events.Event); -/** - * @const - * @type {number} - */ -goog.webgl.VENDOR = 0x1F00; +goog.provide('ol.source.ImageVector'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.vec.Mat4'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.render.canvas.ReplayGroup'); +goog.require('ol.renderer.vector'); +goog.require('ol.source.ImageCanvas'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Style'); +goog.require('ol.vec.Mat4'); -/** - * @const - * @type {number} - */ -goog.webgl.RENDERER = 0x1F01; /** - * @const - * @type {number} + * @classdesc + * An image source whose images are canvas elements into which vector features + * read from a vector source (`ol.source.Vector`) are drawn. An + * `ol.source.ImageVector` object is to be used as the `source` of an image + * layer (`ol.layer.Image`). Image layers are rotated, scaled, and translated, + * as opposed to being re-rendered, during animations and interactions. So, like + * any other image layer, an image layer configured with an + * `ol.source.ImageVector` will exhibit this behaviour. This is in contrast to a + * vector layer, where vector features are re-drawn during animations and + * interactions. + * + * @constructor + * @extends {ol.source.ImageCanvas} + * @param {olx.source.ImageVectorOptions} options Options. + * @api */ -goog.webgl.VERSION = 0x1F02; +ol.source.ImageVector = function(options) { + /** + * @private + * @type {ol.source.Vector} + */ + this.source_ = options.source; -/** - * @const - * @type {number} - */ -goog.webgl.NEAREST = 0x2600; + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.transform_ = goog.vec.Mat4.createNumber(); + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.canvasContext_ = ol.dom.createCanvasContext2D(); -/** - * @const - * @type {number} - */ -goog.webgl.LINEAR = 0x2601; + /** + * @private + * @type {ol.Size} + */ + this.canvasSize_ = [0, 0]; + /** + * @private + * @type {ol.render.canvas.ReplayGroup} + */ + this.replayGroup_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.NEAREST_MIPMAP_NEAREST = 0x2700; + goog.base(this, { + attributions: options.attributions, + canvasFunction: goog.bind(this.canvasFunctionInternal_, this), + logo: options.logo, + projection: options.projection, + ratio: options.ratio, + resolutions: options.resolutions, + state: this.source_.getState() + }); + /** + * User provided style. + * @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} + * @private + */ + this.style_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.LINEAR_MIPMAP_NEAREST = 0x2701; + /** + * Style function for use within the library. + * @type {ol.style.StyleFunction|undefined} + * @private + */ + this.styleFunction_ = undefined; + this.setStyle(options.style); -/** - * @const - * @type {number} - */ -goog.webgl.NEAREST_MIPMAP_LINEAR = 0x2702; + goog.events.listen(this.source_, goog.events.EventType.CHANGE, + this.handleSourceChange_, undefined, this); + +}; +goog.inherits(ol.source.ImageVector, ol.source.ImageCanvas); /** - * @const - * @type {number} + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.Size} size Size. + * @param {ol.proj.Projection} projection Projection; + * @return {HTMLCanvasElement} Canvas element. + * @private */ -goog.webgl.LINEAR_MIPMAP_LINEAR = 0x2703; +ol.source.ImageVector.prototype.canvasFunctionInternal_ = + function(extent, resolution, pixelRatio, size, projection) { + var replayGroup = new ol.render.canvas.ReplayGroup( + ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, + resolution); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_MAG_FILTER = 0x2800; + this.source_.loadFeatures(extent, resolution, projection); + var loading = false; + this.source_.forEachFeatureInExtent(extent, + /** + * @param {ol.Feature} feature Feature. + */ + function(feature) { + loading = loading || + this.renderFeature_(feature, resolution, pixelRatio, replayGroup); + }, this); + replayGroup.finish(); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_MIN_FILTER = 0x2801; + if (loading) { + return null; + } + if (this.canvasSize_[0] != size[0] || this.canvasSize_[1] != size[1]) { + this.canvasContext_.canvas.width = size[0]; + this.canvasContext_.canvas.height = size[1]; + this.canvasSize_[0] = size[0]; + this.canvasSize_[1] = size[1]; + } else { + this.canvasContext_.clearRect(0, 0, size[0], size[1]); + } -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_WRAP_S = 0x2802; + var transform = this.getTransform_(ol.extent.getCenter(extent), + resolution, pixelRatio, size); + replayGroup.replay(this.canvasContext_, pixelRatio, transform, 0, {}); + this.replayGroup_ = replayGroup; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_WRAP_T = 0x2803; + return this.canvasContext_.canvas; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE_2D = 0x0DE1; +ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function( + coordinate, resolution, rotation, skippedFeatureUids, callback) { + if (!this.replayGroup_) { + return undefined; + } else { + /** @type {Object.<string, boolean>} */ + var features = {}; + return this.replayGroup_.forEachFeatureAtCoordinate( + coordinate, resolution, 0, skippedFeatureUids, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + goog.asserts.assert(feature !== undefined, 'passed a feature'); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback(feature); + } + }); + } +}; /** - * @const - * @type {number} + * Get a reference to the wrapped source. + * @return {ol.source.Vector} Source. + * @api */ -goog.webgl.TEXTURE = 0x1702; +ol.source.ImageVector.prototype.getSource = function() { + return this.source_; +}; /** - * @const - * @type {number} + * Get the style for features. This returns whatever was passed to the `style` + * option at construction or to the `setStyle` method. + * @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} + * Layer style. + * @api stable */ -goog.webgl.TEXTURE_CUBE_MAP = 0x8513; +ol.source.ImageVector.prototype.getStyle = function() { + return this.style_; +}; /** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_BINDING_CUBE_MAP = 0x8514; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; - - -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; - - -/** - * @const - * @type {number} + * Get the style function. + * @return {ol.style.StyleFunction|undefined} Layer style function. + * @api stable */ -goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; +ol.source.ImageVector.prototype.getStyleFunction = function() { + return this.styleFunction_; +}; /** - * @const - * @type {number} + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.Size} size Size. + * @return {!goog.vec.Mat4.Number} Transform. + * @private */ -goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; +ol.source.ImageVector.prototype.getTransform_ = + function(center, resolution, pixelRatio, size) { + return ol.vec.Mat4.makeTransform2D(this.transform_, + size[0] / 2, size[1] / 2, + pixelRatio / resolution, -pixelRatio / resolution, + 0, + -center[0], -center[1]); +}; /** - * @const - * @type {number} + * Handle changes in image style state. + * @param {goog.events.Event} event Image style change event. + * @private */ -goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; +ol.source.ImageVector.prototype.handleImageChange_ = + function(event) { + this.changed(); +}; /** - * @const - * @type {number} + * @private */ -goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; +ol.source.ImageVector.prototype.handleSourceChange_ = function() { + // setState will trigger a CHANGE event, so we always rely + // change events by calling setState. + this.setState(this.source_.getState()); +}; /** - * @const - * @type {number} + * @param {ol.Feature} feature Feature. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. + * @return {boolean} `true` if an image is loading. + * @private */ -goog.webgl.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; +ol.source.ImageVector.prototype.renderFeature_ = + function(feature, resolution, pixelRatio, replayGroup) { + var styles; + var styleFunction = feature.getStyleFunction(); + if (styleFunction) { + styles = styleFunction.call(feature, resolution); + } else if (this.styleFunction_) { + styles = this.styleFunction_(feature, resolution); + } + if (!styles) { + return false; + } + var i, ii, loading = false; + for (i = 0, ii = styles.length; i < ii; ++i) { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles[i], + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleImageChange_, this) || loading; + } + return loading; +}; /** - * @const - * @type {number} + * Set the style for features. This can be a single style object, an array + * of styles, or a function that takes a feature and resolution and returns + * an array of styles. If it is `undefined` the default style is used. If + * it is `null` the layer has no style (a `null` style), so only features + * that have their own styles will be rendered in the layer. See + * {@link ol.style} for information on the default style. + * @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined} + * style Layer style. + * @api stable */ -goog.webgl.TEXTURE0 = 0x84C0; - +ol.source.ImageVector.prototype.setStyle = function(style) { + this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction; + this.styleFunction_ = !style ? + undefined : ol.style.createStyleFunction(this.style_); + this.changed(); +}; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE1 = 0x84C1; +goog.provide('ol.renderer.canvas.ImageLayer'); +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('goog.vec.Mat4'); +goog.require('ol.ImageBase'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Image'); +goog.require('ol.proj'); +goog.require('ol.renderer.canvas.Layer'); +goog.require('ol.source.ImageVector'); +goog.require('ol.vec.Mat4'); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE2 = 0x84C2; /** - * @const - * @type {number} + * @constructor + * @extends {ol.renderer.canvas.Layer} + * @param {ol.layer.Image} imageLayer Single image layer. */ -goog.webgl.TEXTURE3 = 0x84C3; +ol.renderer.canvas.ImageLayer = function(imageLayer) { + goog.base(this, imageLayer); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE4 = 0x84C4; + /** + * @private + * @type {?ol.ImageBase} + */ + this.image_ = null; + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.imageTransform_ = goog.vec.Mat4.createNumber(); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE5 = 0x84C5; + /** + * @private + * @type {?goog.vec.Mat4.Number} + */ + this.imageTransformInv_ = null; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.hitCanvasContext_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE6 = 0x84C6; +}; +goog.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.Layer); /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE7 = 0x84C7; +ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + var layer = this.getLayer(); + var source = layer.getSource(); + var resolution = frameState.viewState.resolution; + var rotation = frameState.viewState.rotation; + var skippedFeatureUids = frameState.skippedFeatureUids; + return source.forEachFeatureAtCoordinate( + coordinate, resolution, rotation, skippedFeatureUids, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + return callback.call(thisArg, feature, layer); + }); +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE8 = 0x84C8; +ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg) { + if (!this.getImage()) { + return undefined; + } + if (this.getLayer().getSource() instanceof ol.source.ImageVector) { + // for ImageVector sources use the original hit-detection logic, + // so that for example also transparent polygons are detected + var coordinate = pixel.slice(); + ol.vec.Mat4.multVec2( + frameState.pixelToCoordinateMatrix, coordinate, coordinate); + var hasFeature = this.forEachFeatureAtCoordinate( + coordinate, frameState, goog.functions.TRUE, this); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE9 = 0x84C9; + if (hasFeature) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } + } else { + // for all other image sources directly check the image + if (!this.imageTransformInv_) { + this.imageTransformInv_ = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); + } + var pixelOnCanvas = + this.getPixelOnCanvas(pixel, this.imageTransformInv_); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE10 = 0x84CA; + if (!this.hitCanvasContext_) { + this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); + } + this.hitCanvasContext_.clearRect(0, 0, 1, 1); + this.hitCanvasContext_.drawImage( + this.getImage(), pixelOnCanvas[0], pixelOnCanvas[1], 1, 1, 0, 0, 1, 1); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE11 = 0x84CB; + var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; + if (imageData[3] > 0) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } + } +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE12 = 0x84CC; +ol.renderer.canvas.ImageLayer.prototype.getImage = function() { + return !this.image_ ? null : this.image_.getImage(); +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE13 = 0x84CD; +ol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() { + return this.imageTransform_; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE14 = 0x84CE; - +ol.renderer.canvas.ImageLayer.prototype.prepareFrame = + function(frameState, layerState) { -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE15 = 0x84CF; + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var viewCenter = viewState.center; + var viewResolution = viewState.resolution; + var viewRotation = viewState.rotation; + var image; + var imageLayer = this.getLayer(); + goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, + 'layer is an instance of ol.layer.Image'); + var imageSource = imageLayer.getSource(); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE16 = 0x84D0; + var hints = frameState.viewHints; + var renderedExtent = frameState.extent; + if (layerState.extent !== undefined) { + renderedExtent = ol.extent.getIntersection( + renderedExtent, layerState.extent); + } -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE17 = 0x84D1; + if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && + !ol.extent.isEmpty(renderedExtent)) { + var projection = viewState.projection; + if (!ol.ENABLE_RASTER_REPROJECTION) { + var sourceProjection = imageSource.getProjection(); + if (sourceProjection) { + goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), + 'projection and sourceProjection are equivalent'); + projection = sourceProjection; + } + } + image = imageSource.getImage( + renderedExtent, viewResolution, pixelRatio, projection); + if (image) { + var loaded = this.loadImage(image); + if (loaded) { + this.image_ = image; + } + } + } + if (this.image_) { + image = this.image_; + var imageExtent = image.getExtent(); + var imageResolution = image.getResolution(); + var imagePixelRatio = image.getPixelRatio(); + var scale = pixelRatio * imageResolution / + (viewResolution * imagePixelRatio); + ol.vec.Mat4.makeTransform2D(this.imageTransform_, + pixelRatio * frameState.size[0] / 2, + pixelRatio * frameState.size[1] / 2, + scale, scale, + viewRotation, + imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution, + imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution); + this.imageTransformInv_ = null; + this.updateAttributions(frameState.attributions, image.getAttributions()); + this.updateLogos(frameState, imageSource); + } -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE18 = 0x84D2; + return true; +}; +// FIXME find correct globalCompositeOperation +// FIXME optimize :-) -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE19 = 0x84D3; +goog.provide('ol.renderer.canvas.TileLayer'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Size'); +goog.require('ol.TileRange'); +goog.require('ol.TileState'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Tile'); +goog.require('ol.renderer.canvas.Layer'); +goog.require('ol.size'); +goog.require('ol.tilecoord'); +goog.require('ol.vec.Mat4'); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE20 = 0x84D4; /** - * @const - * @type {number} + * @constructor + * @extends {ol.renderer.canvas.Layer} + * @param {ol.layer.Tile} tileLayer Tile layer. */ -goog.webgl.TEXTURE21 = 0x84D5; +ol.renderer.canvas.TileLayer = function(tileLayer) { + goog.base(this, tileLayer); -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE22 = 0x84D6; + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = null; + /** + * @private + * @type {ol.Size} + */ + this.canvasSize_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE23 = 0x84D7; + /** + * @private + * @type {boolean} + */ + this.canvasTooBig_ = false; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE24 = 0x84D8; + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.imageTransform_ = goog.vec.Mat4.createNumber(); + /** + * @private + * @type {?goog.vec.Mat4.Number} + */ + this.imageTransformInv_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE25 = 0x84D9; + /** + * @private + * @type {number} + */ + this.renderedCanvasZ_ = NaN; + /** + * @private + * @type {number} + */ + this.renderedTileWidth_ = NaN; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE26 = 0x84DA; + /** + * @private + * @type {number} + */ + this.renderedTileHeight_ = NaN; + /** + * @private + * @type {ol.TileRange} + */ + this.renderedCanvasTileRange_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE27 = 0x84DB; + /** + * @private + * @type {Array.<ol.Tile|undefined>} + */ + this.renderedTiles_ = null; + /** + * @private + * @type {ol.Size} + */ + this.tmpSize_ = [0, 0]; -/** - * @const - * @type {number} - */ -goog.webgl.TEXTURE28 = 0x84DC; +}; +goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE29 = 0x84DD; +ol.renderer.canvas.TileLayer.prototype.getImage = function() { + return this.canvas_; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE30 = 0x84DE; +ol.renderer.canvas.TileLayer.prototype.getImageTransform = function() { + return this.imageTransform_; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.TEXTURE31 = 0x84DF; - +ol.renderer.canvas.TileLayer.prototype.prepareFrame = + function(frameState, layerState) { -/** - * @const - * @type {number} - */ -goog.webgl.ACTIVE_TEXTURE = 0x84E0; + // + // Warning! You're entering a dangerous zone! + // + // The canvas tile layer renderering is highly optimized, hence + // the complexity of this function. For best performance we try + // to minimize the number of pixels to update on the canvas. This + // includes: + // + // - Only drawing pixels that will be visible. + // - Not re-drawing pixels/tiles that are already correct. + // - Minimizing calls to clearRect. + // - Never shrink the canvas. Just make it bigger when necessary. + // Re-sizing the canvas also clears it, which further means + // re-creating it (expensive). + // + // The various steps performed by this functions: + // + // - Create a canvas element if none has been created yet. + // + // - Make the canvas bigger if it's too small. Note that we never shrink + // the canvas, we just make it bigger when necessary, when rotating for + // example. Note also that the canvas always contains a whole number + // of tiles. + // + // - Invalidate the canvas tile range (renderedCanvasTileRange_ = null) + // if (1) the canvas has been enlarged, or (2) the zoom level changes, + // or (3) the canvas tile range doesn't contain the required tile + // range. This canvas tile range invalidation thing is related to + // an optimization where we attempt to redraw as few pixels as + // possible on each prepareFrame call. + // + // - If the canvas tile range has been invalidated we reset + // renderedCanvasTileRange_ and reset the renderedTiles_ array. + // The renderedTiles_ array is the structure used to determine + // the canvas pixels that need not be redrawn from one prepareFrame + // call to another. It records while tile has been rendered at + // which position in the canvas. + // + // - We then determine the tiles to draw on the canvas. Tiles for + // the target resolution may not be loaded yet. In that case we + // use low-resolution/interim tiles if loaded already. And, if + // for a non-yet-loaded tile we haven't found a corresponding + // low-resolution tile we indicate that the pixels for that + // tile must be cleared on the canvas. Note: determining the + // interim tiles is based on tile extents instead of tile + // coords, this is to be able to handler irregular tile grids. + // + // - We're now ready to render. We start by calling clearRect + // for the tiles that aren't loaded yet and are not fully covered + // by a low-resolution tile (if they're loaded, we'll draw them; + // if they're fully covered by a low-resolution tile then there's + // no need to clear). We then render the tiles "back to front", + // i.e. starting with the low-resolution tiles. + // + // - After rendering some bookkeeping is performed (updateUsedTiles, + // etc.). manageTilePyramid is what enqueue tiles in the tile + // queue for loading. + // + // - The last step involves updating the image transform matrix, + // which will be used by the map renderer for the final + // composition and positioning. + // + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var projection = viewState.projection; -/** - * @const - * @type {number} - */ -goog.webgl.REPEAT = 0x2901; + var tileLayer = this.getLayer(); + goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, + 'layer is an instance of ol.layer.Tile'); + var tileSource = tileLayer.getSource(); + var tileGrid = tileSource.getTileGridForProjection(projection); + var tileGutter = tileSource.getGutter(); + var z = tileGrid.getZForResolution(viewState.resolution); + var tilePixelSize = + tileSource.getTilePixelSize(z, frameState.pixelRatio, projection); + var tilePixelRatio = tilePixelSize[0] / + ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; + var tileResolution = tileGrid.getResolution(z); + var tilePixelResolution = tileResolution / tilePixelRatio; + var center = viewState.center; + var extent; + if (tileResolution == viewState.resolution) { + center = this.snapCenterToPixel(center, tileResolution, frameState.size); + extent = ol.extent.getForViewAndSize( + center, tileResolution, viewState.rotation, frameState.size); + } else { + extent = frameState.extent; + } + if (layerState.extent !== undefined) { + extent = ol.extent.getIntersection(extent, layerState.extent); + } + if (ol.extent.isEmpty(extent)) { + // Return false to prevent the rendering of the layer. + return false; + } -/** - * @const - * @type {number} - */ -goog.webgl.CLAMP_TO_EDGE = 0x812F; + var tileRange = tileGrid.getTileRangeForExtentAndResolution( + extent, tileResolution); + var canvasWidth = tilePixelSize[0] * tileRange.getWidth(); + var canvasHeight = tilePixelSize[1] * tileRange.getHeight(); -/** - * @const - * @type {number} - */ -goog.webgl.MIRRORED_REPEAT = 0x8370; + var canvas, context; + if (!this.canvas_) { + goog.asserts.assert(!this.canvasSize_, + 'canvasSize is null (because canvas is null)'); + goog.asserts.assert(!this.context_, + 'context is null (because canvas is null)'); + goog.asserts.assert(!this.renderedCanvasTileRange_, + 'renderedCanvasTileRange is null (because canvas is null)'); + context = ol.dom.createCanvasContext2D(canvasWidth, canvasHeight); + this.canvas_ = context.canvas; + this.canvasSize_ = [canvasWidth, canvasHeight]; + this.context_ = context; + this.canvasTooBig_ = + !ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_); + } else { + goog.asserts.assert(this.canvasSize_, + 'non-null canvasSize (because canvas is not null)'); + goog.asserts.assert(this.context_, + 'non-null context (because canvas is not null)'); + canvas = this.canvas_; + context = this.context_; + if (this.canvasSize_[0] < canvasWidth || + this.canvasSize_[1] < canvasHeight || + this.renderedTileWidth_ !== tilePixelSize[0] || + this.renderedTileHeight_ !== tilePixelSize[1] || + (this.canvasTooBig_ && (this.canvasSize_[0] > canvasWidth || + this.canvasSize_[1] > canvasHeight))) { + // Canvas is too small or tileSize has changed, resize it. + // We never shrink the canvas, unless + // we know that the current canvas size exceeds the maximum size + canvas.width = canvasWidth; + canvas.height = canvasHeight; + this.canvasSize_ = [canvasWidth, canvasHeight]; + this.canvasTooBig_ = + !ol.renderer.canvas.Layer.testCanvasSize(this.canvasSize_); + this.renderedCanvasTileRange_ = null; + } else { + canvasWidth = this.canvasSize_[0]; + canvasHeight = this.canvasSize_[1]; + if (z != this.renderedCanvasZ_ || + !this.renderedCanvasTileRange_.containsTileRange(tileRange)) { + this.renderedCanvasTileRange_ = null; + } + } + } + var canvasTileRange, canvasTileRangeWidth, minX, minY; + if (!this.renderedCanvasTileRange_) { + canvasTileRangeWidth = canvasWidth / tilePixelSize[0]; + var canvasTileRangeHeight = canvasHeight / tilePixelSize[1]; + minX = tileRange.minX - + Math.floor((canvasTileRangeWidth - tileRange.getWidth()) / 2); + minY = tileRange.minY - + Math.floor((canvasTileRangeHeight - tileRange.getHeight()) / 2); + this.renderedCanvasZ_ = z; + this.renderedTileWidth_ = tilePixelSize[0]; + this.renderedTileHeight_ = tilePixelSize[1]; + this.renderedCanvasTileRange_ = new ol.TileRange( + minX, minX + canvasTileRangeWidth - 1, + minY, minY + canvasTileRangeHeight - 1); + this.renderedTiles_ = + new Array(canvasTileRangeWidth * canvasTileRangeHeight); + canvasTileRange = this.renderedCanvasTileRange_; + } else { + canvasTileRange = this.renderedCanvasTileRange_; + canvasTileRangeWidth = canvasTileRange.getWidth(); + } -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_VEC2 = 0x8B50; + goog.asserts.assert(canvasTileRange.containsTileRange(tileRange), + 'tileRange is contained in canvasTileRange'); + /** + * @type {Object.<number, Object.<string, ol.Tile>>} + */ + var tilesToDrawByZ = {}; + tilesToDrawByZ[z] = {}; + /** @type {Array.<ol.Tile>} */ + var tilesToClear = []; -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_VEC3 = 0x8B51; + var findLoadedTiles = this.createLoadedTileFinder( + tileSource, projection, tilesToDrawByZ); + var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_VEC4 = 0x8B52; + var tmpExtent = ol.extent.createEmpty(); + var tmpTileRange = new ol.TileRange(0, 0, 0, 0); + var childTileRange, fullyLoaded, tile, x, y; + var drawableTile = ( + /** + * @param {!ol.Tile} tile Tile. + * @return {boolean} Tile is selected. + */ + function(tile) { + var tileState = tile.getState(); + return tileState == ol.TileState.LOADED || + tileState == ol.TileState.EMPTY || + tileState == ol.TileState.ERROR && !useInterimTilesOnError; + }); + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + tile = tileSource.getTile(z, x, y, pixelRatio, projection); + if (!drawableTile(tile) && tile.interimTile) { + tile = tile.interimTile; + } + goog.asserts.assert(tile); + if (drawableTile(tile)) { + tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; + continue; + } + fullyLoaded = tileGrid.forEachTileCoordParentTileRange( + tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); + if (!fullyLoaded) { + // FIXME we do not need to clear the tile if it is fully covered by its + // children + tilesToClear.push(tile); + childTileRange = tileGrid.getTileCoordChildTileRange( + tile.tileCoord, tmpTileRange, tmpExtent); + if (childTileRange) { + findLoadedTiles(z + 1, childTileRange); + } + } + } + } -/** - * @const - * @type {number} - */ -goog.webgl.INT_VEC2 = 0x8B53; + var i, ii; + for (i = 0, ii = tilesToClear.length; i < ii; ++i) { + tile = tilesToClear[i]; + x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX); + y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]); + context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]); + } + /** @type {Array.<number>} */ + var zs = Object.keys(tilesToDrawByZ).map(Number); + goog.array.sort(zs); + var opaque = tileSource.getOpaque(); + var origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( + [z, canvasTileRange.minX, canvasTileRange.maxY], + tmpExtent)); + var currentZ, index, scale, tileCoordKey, tileExtent, tileState, tilesToDraw; + var ix, iy, interimTileRange, maxX, maxY; + var height, width; + for (i = 0, ii = zs.length; i < ii; ++i) { + currentZ = zs[i]; + tilePixelSize = + tileSource.getTilePixelSize(currentZ, pixelRatio, projection); + tilesToDraw = tilesToDrawByZ[currentZ]; + if (currentZ == z) { + for (tileCoordKey in tilesToDraw) { + tile = tilesToDraw[tileCoordKey]; + index = + (tile.tileCoord[2] - canvasTileRange.minY) * canvasTileRangeWidth + + (tile.tileCoord[1] - canvasTileRange.minX); + if (this.renderedTiles_[index] != tile) { + x = tilePixelSize[0] * (tile.tileCoord[1] - canvasTileRange.minX); + y = tilePixelSize[1] * (canvasTileRange.maxY - tile.tileCoord[2]); + tileState = tile.getState(); + if (tileState == ol.TileState.EMPTY || + (tileState == ol.TileState.ERROR && !useInterimTilesOnError) || + !opaque) { + context.clearRect(x, y, tilePixelSize[0], tilePixelSize[1]); + } + if (tileState == ol.TileState.LOADED) { + context.drawImage(tile.getImage(), + tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1], + x, y, tilePixelSize[0], tilePixelSize[1]); + } + this.renderedTiles_[index] = tile; + } + } + } else { + scale = tileGrid.getResolution(currentZ) / tileResolution; + for (tileCoordKey in tilesToDraw) { + tile = tilesToDraw[tileCoordKey]; + tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); + x = (tileExtent[0] - origin[0]) / tilePixelResolution; + y = (origin[1] - tileExtent[3]) / tilePixelResolution; + width = scale * tilePixelSize[0]; + height = scale * tilePixelSize[1]; + tileState = tile.getState(); + if (tileState == ol.TileState.EMPTY || !opaque) { + context.clearRect(x, y, width, height); + } + if (tileState == ol.TileState.LOADED) { + context.drawImage(tile.getImage(), + tileGutter, tileGutter, tilePixelSize[0], tilePixelSize[1], + x, y, width, height); + } + interimTileRange = + tileGrid.getTileRangeForExtentAndZ(tileExtent, z, tmpTileRange); + minX = Math.max(interimTileRange.minX, canvasTileRange.minX); + maxX = Math.min(interimTileRange.maxX, canvasTileRange.maxX); + minY = Math.max(interimTileRange.minY, canvasTileRange.minY); + maxY = Math.min(interimTileRange.maxY, canvasTileRange.maxY); + for (ix = minX; ix <= maxX; ++ix) { + for (iy = minY; iy <= maxY; ++iy) { + index = (iy - canvasTileRange.minY) * canvasTileRangeWidth + + (ix - canvasTileRange.minX); + this.renderedTiles_[index] = undefined; + } + } + } + } + } -/** - * @const - * @type {number} - */ -goog.webgl.INT_VEC3 = 0x8B54; + this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); + this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, + projection, extent, z, tileLayer.getPreload()); + this.scheduleExpireCache(frameState, tileSource); + this.updateLogos(frameState, tileSource); + ol.vec.Mat4.makeTransform2D(this.imageTransform_, + pixelRatio * frameState.size[0] / 2, + pixelRatio * frameState.size[1] / 2, + pixelRatio * tilePixelResolution / viewState.resolution, + pixelRatio * tilePixelResolution / viewState.resolution, + viewState.rotation, + (origin[0] - center[0]) / tilePixelResolution, + (center[1] - origin[1]) / tilePixelResolution); + this.imageTransformInv_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.INT_VEC4 = 0x8B55; + return true; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.BOOL = 0x8B56; - +ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg) { + if (!this.context_) { + return undefined; + } -/** - * @const - * @type {number} - */ -goog.webgl.BOOL_VEC2 = 0x8B57; + if (!this.imageTransformInv_) { + this.imageTransformInv_ = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_); + } + var pixelOnCanvas = + this.getPixelOnCanvas(pixel, this.imageTransformInv_); -/** - * @const - * @type {number} - */ -goog.webgl.BOOL_VEC3 = 0x8B58; + var imageData = this.context_.getImageData( + pixelOnCanvas[0], pixelOnCanvas[1], 1, 1).data; + if (imageData[3] > 0) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } +}; -/** - * @const - * @type {number} - */ -goog.webgl.BOOL_VEC4 = 0x8B59; +goog.provide('ol.renderer.canvas.VectorLayer'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Vector'); +goog.require('ol.render.EventType'); +goog.require('ol.render.canvas.ReplayGroup'); +goog.require('ol.renderer.canvas.Layer'); +goog.require('ol.renderer.vector'); +goog.require('ol.source.Vector'); -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_MAT2 = 0x8B5A; /** - * @const - * @type {number} + * @constructor + * @extends {ol.renderer.canvas.Layer} + * @param {ol.layer.Vector} vectorLayer Vector layer. */ -goog.webgl.FLOAT_MAT3 = 0x8B5B; - +ol.renderer.canvas.VectorLayer = function(vectorLayer) { -/** - * @const - * @type {number} - */ -goog.webgl.FLOAT_MAT4 = 0x8B5C; + goog.base(this, vectorLayer); + /** + * @private + * @type {boolean} + */ + this.dirty_ = false; -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLER_2D = 0x8B5E; + /** + * @private + * @type {number} + */ + this.renderedRevision_ = -1; + /** + * @private + * @type {number} + */ + this.renderedResolution_ = NaN; -/** - * @const - * @type {number} - */ -goog.webgl.SAMPLER_CUBE = 0x8B60; + /** + * @private + * @type {ol.Extent} + */ + this.renderedExtent_ = ol.extent.createEmpty(); + /** + * @private + * @type {function(ol.Feature, ol.Feature): number|null} + */ + this.renderedRenderOrder_ = null; -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622; + /** + * @private + * @type {ol.render.canvas.ReplayGroup} + */ + this.replayGroup_ = null; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = ol.dom.createCanvasContext2D(); -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623; +}; +goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer); /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624; +ol.renderer.canvas.VectorLayer.prototype.composeFrame = + function(frameState, layerState, context) { + var extent = frameState.extent; + var pixelRatio = frameState.pixelRatio; + var skippedFeatureUids = layerState.managed ? + frameState.skippedFeatureUids : {}; + var viewState = frameState.viewState; + var projection = viewState.projection; + var rotation = viewState.rotation; + var projectionExtent = projection.getExtent(); + var vectorSource = this.getLayer().getSource(); + goog.asserts.assertInstanceof(vectorSource, ol.source.Vector); -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625; + var transform = this.getTransform(frameState, 0); + this.dispatchPreComposeEvent(context, frameState, transform); -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A; + var replayGroup = this.replayGroup_; + if (replayGroup && !replayGroup.isEmpty()) { + var layer = this.getLayer(); + var replayContext; + if (layer.hasListener(ol.render.EventType.RENDER)) { + // resize and clear + this.context_.canvas.width = context.canvas.width; + this.context_.canvas.height = context.canvas.height; + replayContext = this.context_; + } else { + replayContext = context; + } + // for performance reasons, context.save / context.restore is not used + // to save and restore the transformation matrix and the opacity. + // see http://jsperf.com/context-save-restore-versus-variable + var alpha = replayContext.globalAlpha; + replayContext.globalAlpha = layerState.opacity; + replayGroup.replay(replayContext, pixelRatio, transform, rotation, + skippedFeatureUids); + if (vectorSource.getWrapX() && projection.canWrapX() && + !ol.extent.containsExtent(projectionExtent, extent)) { + var startX = extent[0]; + var worldWidth = ol.extent.getWidth(projectionExtent); + var world = 0; + var offsetX; + while (startX < projectionExtent[0]) { + --world; + offsetX = worldWidth * world; + transform = this.getTransform(frameState, offsetX); + replayGroup.replay(replayContext, pixelRatio, transform, rotation, + skippedFeatureUids); + startX += worldWidth; + } + world = 0; + startX = extent[2]; + while (startX > projectionExtent[2]) { + ++world; + offsetX = worldWidth * world; + transform = this.getTransform(frameState, offsetX); + replayGroup.replay(replayContext, pixelRatio, transform, rotation, + skippedFeatureUids); + startX -= worldWidth; + } + // restore original transform for render and compose events + transform = this.getTransform(frameState, 0); + } -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; + if (replayContext != context) { + this.dispatchRenderEvent(replayContext, frameState, transform); + context.drawImage(replayContext.canvas, 0, 0); + } + replayContext.globalAlpha = alpha; + } + this.dispatchPostComposeEvent(context, frameState, transform); -/** - * @const - * @type {number} - */ -goog.webgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.COMPILE_STATUS = 0x8B81; +ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + if (!this.replayGroup_) { + return undefined; + } else { + var resolution = frameState.viewState.resolution; + var rotation = frameState.viewState.rotation; + var layer = this.getLayer(); + var layerState = frameState.layerStates[goog.getUid(layer)]; + /** @type {Object.<string, boolean>} */ + var features = {}; + return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, + rotation, layerState.managed ? frameState.skippedFeatureUids : {}, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + goog.asserts.assert(feature !== undefined, 'received a feature'); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback.call(thisArg, feature, layer); + } + }); + } +}; /** - * @const - * @type {number} + * Handle changes in image style state. + * @param {goog.events.Event} event Image style change event. + * @private */ -goog.webgl.LOW_FLOAT = 0x8DF0; +ol.renderer.canvas.VectorLayer.prototype.handleStyleImageChange_ = + function(event) { + this.renderIfReadyAndVisible(); +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.MEDIUM_FLOAT = 0x8DF1; +ol.renderer.canvas.VectorLayer.prototype.prepareFrame = + function(frameState, layerState) { + var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); + goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, + 'layer is an instance of ol.layer.Vector'); + var vectorSource = vectorLayer.getSource(); -/** - * @const - * @type {number} - */ -goog.webgl.HIGH_FLOAT = 0x8DF2; + this.updateAttributions( + frameState.attributions, vectorSource.getAttributions()); + this.updateLogos(frameState, vectorSource); + var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; + var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; + var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); + var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); -/** - * @const - * @type {number} - */ -goog.webgl.LOW_INT = 0x8DF3; + if (!this.dirty_ && (!updateWhileAnimating && animating) || + (!updateWhileInteracting && interacting)) { + return true; + } + var frameStateExtent = frameState.extent; + var viewState = frameState.viewState; + var projection = viewState.projection; + var resolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var vectorLayerRevision = vectorLayer.getRevision(); + var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); + var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); -/** - * @const - * @type {number} - */ -goog.webgl.MEDIUM_INT = 0x8DF4; + if (vectorLayerRenderOrder === undefined) { + vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; + } + var extent = ol.extent.buffer(frameStateExtent, + vectorLayerRenderBuffer * resolution); + var projectionExtent = viewState.projection.getExtent(); -/** - * @const - * @type {number} - */ -goog.webgl.HIGH_INT = 0x8DF5; + if (vectorSource.getWrapX() && viewState.projection.canWrapX() && + !ol.extent.containsExtent(projectionExtent, frameState.extent)) { + // For the replay group, we need an extent that intersects the real world + // (-180° to +180°). To support geometries in a coordinate range from -540° + // to +540°, we add at least 1 world width on each side of the projection + // extent. If the viewport is wider than the world, we need to add half of + // the viewport width to make sure we cover the whole viewport. + var worldWidth = ol.extent.getWidth(projectionExtent); + var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth); + extent[0] = projectionExtent[0] - buffer; + extent[2] = projectionExtent[2] + buffer; + } + if (!this.dirty_ && + this.renderedResolution_ == resolution && + this.renderedRevision_ == vectorLayerRevision && + this.renderedRenderOrder_ == vectorLayerRenderOrder && + ol.extent.containsExtent(this.renderedExtent_, extent)) { + return true; + } -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER = 0x8D40; + // FIXME dispose of old replayGroup in post render + goog.dispose(this.replayGroup_); + this.replayGroup_ = null; + this.dirty_ = false; -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER = 0x8D41; + var replayGroup = + new ol.render.canvas.ReplayGroup( + ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, + resolution, vectorLayer.getRenderBuffer()); + vectorSource.loadFeatures(extent, resolution, projection); + var renderFeature = + /** + * @param {ol.Feature} feature Feature. + * @this {ol.renderer.canvas.VectorLayer} + */ + function(feature) { + var styles; + var styleFunction = feature.getStyleFunction(); + if (styleFunction) { + styles = styleFunction.call(feature, resolution); + } else { + styleFunction = vectorLayer.getStyleFunction(); + if (styleFunction) { + styles = styleFunction(feature, resolution); + } + } + if (styles) { + var dirty = this.renderFeature( + feature, resolution, pixelRatio, styles, replayGroup); + this.dirty_ = this.dirty_ || dirty; + } + }; + if (vectorLayerRenderOrder) { + /** @type {Array.<ol.Feature>} */ + var features = []; + vectorSource.forEachFeatureInExtent(extent, + /** + * @param {ol.Feature} feature Feature. + */ + function(feature) { + features.push(feature); + }, this); + goog.array.sort(features, vectorLayerRenderOrder); + features.forEach(renderFeature, this); + } else { + vectorSource.forEachFeatureInExtent(extent, renderFeature, this); + } + replayGroup.finish(); + this.renderedResolution_ = resolution; + this.renderedRevision_ = vectorLayerRevision; + this.renderedRenderOrder_ = vectorLayerRenderOrder; + this.renderedExtent_ = extent; + this.replayGroup_ = replayGroup; -/** - * @const - * @type {number} - */ -goog.webgl.RGBA4 = 0x8056; + return true; +}; /** - * @const - * @type {number} + * @param {ol.Feature} feature Feature. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of + * styles. + * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. + * @return {boolean} `true` if an image is loading. */ -goog.webgl.RGB5_A1 = 0x8057; +ol.renderer.canvas.VectorLayer.prototype.renderFeature = + function(feature, resolution, pixelRatio, styles, replayGroup) { + if (!styles) { + return false; + } + var loading = false; + if (goog.isArray(styles)) { + for (var i = 0, ii = styles.length; i < ii; ++i) { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles[i], + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleStyleImageChange_, this) || loading; + } + } else { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles, + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleStyleImageChange_, this) || loading; + } + return loading; +}; +goog.provide('ol.VectorTile'); -/** - * @const - * @type {number} - */ -goog.webgl.RGB565 = 0x8D62; +goog.require('ol.Tile'); +goog.require('ol.TileCoord'); +goog.require('ol.TileLoadFunctionType'); +goog.require('ol.TileState'); /** - * @const - * @type {number} + * @typedef {{ + * dirty: boolean, + * renderedRenderOrder: (null|function(ol.Feature, ol.Feature):number), + * renderedRevision: number, + * replayGroup: ol.render.IReplayGroup}} */ -goog.webgl.DEPTH_COMPONENT16 = 0x81A5; - +ol.TileReplayState; -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_INDEX = 0x1901; /** - * @const - * @type {number} + * @constructor + * @extends {ol.Tile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.TileState} state State. + * @param {string} src Data source url. + * @param {ol.format.Feature} format Feature format. + * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. */ -goog.webgl.STENCIL_INDEX8 = 0x8D48; - +ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) { -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_STENCIL = 0x84F9; + goog.base(this, tileCoord, state); + /** + * @private + * @type {ol.format.Feature} + */ + this.format_ = format; -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_WIDTH = 0x8D42; + /** + * @private + * @type {Array.<ol.Feature>} + */ + this.features_ = null; + /** + * @private + * @type {ol.FeatureLoader} + */ + this.loader_; -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_HEIGHT = 0x8D43; + /** + * @private + * @type {ol.proj.Projection} + */ + this.projection_ = null; + /** + * @private + * @type {ol.TileReplayState} + */ + this.replayState_ = { + dirty: false, + renderedRenderOrder: null, + renderedRevision: -1, + replayGroup: null + }; -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44; + /** + * @private + * @type {ol.TileLoadFunctionType} + */ + this.tileLoadFunction_ = tileLoadFunction; + /** + * @private + * @type {string} + */ + this.url_ = src; -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_RED_SIZE = 0x8D50; +}; +goog.inherits(ol.VectorTile, ol.Tile); /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.RENDERBUFFER_GREEN_SIZE = 0x8D51; +ol.VectorTile.prototype.disposeInternal = function() { + goog.base(this, 'disposeInternal'); +}; /** - * @const - * @type {number} + * Get the feature format assigned for reading this tile's features. + * @return {ol.format.Feature} Feature format. + * @api */ -goog.webgl.RENDERBUFFER_BLUE_SIZE = 0x8D52; +ol.VectorTile.prototype.getFormat = function() { + return this.format_; +}; /** - * @const - * @type {number} + * @return {Array.<ol.Feature>} Features. */ -goog.webgl.RENDERBUFFER_ALPHA_SIZE = 0x8D53; +ol.VectorTile.prototype.getFeatures = function() { + return this.features_; +}; /** - * @const - * @type {number} + * @return {ol.TileReplayState} */ -goog.webgl.RENDERBUFFER_DEPTH_SIZE = 0x8D54; +ol.VectorTile.prototype.getReplayState = function() { + return this.replayState_; +}; /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.RENDERBUFFER_STENCIL_SIZE = 0x8D55; +ol.VectorTile.prototype.getKey = function() { + return this.url_; +}; /** - * @const - * @type {number} + * @return {ol.proj.Projection} Projection. */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0; +ol.VectorTile.prototype.getProjection = function() { + return this.projection_; +}; /** - * @const - * @type {number} + * Load the tile. */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1; +ol.VectorTile.prototype.load = function() { + if (this.state == ol.TileState.IDLE) { + this.setState(ol.TileState.LOADING); + this.tileLoadFunction_(this, this.url_); + this.loader_(null, NaN, null); + } +}; /** - * @const - * @type {number} + * @param {Array.<ol.Feature>} features Features. */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2; +ol.VectorTile.prototype.setFeatures = function(features) { + this.features_ = features; + this.setState(ol.TileState.LOADED); +}; /** - * @const - * @type {number} + * @param {ol.proj.Projection} projection Projection. */ -goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3; +ol.VectorTile.prototype.setProjection = function(projection) { + this.projection_ = projection; +}; /** - * @const - * @type {number} + * @param {ol.TileState} tileState Tile state. */ -goog.webgl.COLOR_ATTACHMENT0 = 0x8CE0; +ol.VectorTile.prototype.setState = function(tileState) { + this.state = tileState; + this.changed(); +}; /** - * @const - * @type {number} + * Set the feature loader for reading this tile's features. + * @param {ol.FeatureLoader} loader Feature loader. + * @api */ -goog.webgl.DEPTH_ATTACHMENT = 0x8D00; - +ol.VectorTile.prototype.setLoader = function(loader) { + this.loader_ = loader; +}; -/** - * @const - * @type {number} - */ -goog.webgl.STENCIL_ATTACHMENT = 0x8D20; +goog.provide('ol.source.VectorTile'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.TileState'); +goog.require('ol.VectorTile'); +goog.require('ol.featureloader'); +goog.require('ol.source.UrlTile'); -/** - * @const - * @type {number} - */ -goog.webgl.DEPTH_STENCIL_ATTACHMENT = 0x821A; /** - * @const - * @type {number} + * @classdesc + * Class for layer sources providing vector data divided into a tile grid, to be + * used with {@link ol.layer.VectorTile}. Although this source receives tiles + * with vector features from the server, it is not meant for feature editing. + * Features are optimized for rendering, their geometries are clipped at or near + * tile boundaries and simplified for a view resolution. See + * {@link ol.source.Vector} for vector sources that are suitable for feature + * editing. + * + * @constructor + * @fires ol.source.TileEvent + * @extends {ol.source.UrlTile} + * @param {olx.source.VectorTileOptions} options Vector tile options. + * @api */ -goog.webgl.NONE = 0; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_COMPLETE = 0x8CD5; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_UNSUPPORTED = 0x8CDD; - - -/** - * @const - * @type {number} - */ -goog.webgl.FRAMEBUFFER_BINDING = 0x8CA6; +ol.source.VectorTile = function(options) { + goog.base(this, { + attributions: options.attributions, + cacheSize: ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK / 16, + extent: options.extent, + logo: options.logo, + opaque: options.opaque, + projection: options.projection, + state: options.state ? + /** @type {ol.source.State} */ (options.state) : undefined, + tileGrid: options.tileGrid, + tileLoadFunction: options.tileLoadFunction ? + options.tileLoadFunction : ol.source.VectorTile.defaultTileLoadFunction, + tileUrlFunction: options.tileUrlFunction, + tilePixelRatio: options.tilePixelRatio, + url: options.url, + urls: options.urls, + wrapX: options.wrapX === undefined ? true : options.wrapX + }); -/** - * @const - * @type {number} - */ -goog.webgl.RENDERBUFFER_BINDING = 0x8CA7; + /** + * @private + * @type {ol.format.Feature} + */ + this.format_ = options.format ? options.format : null; + /** + * @protected + * @type {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string, + * ol.format.Feature, ol.TileLoadFunctionType)} + */ + this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile; -/** - * @const - * @type {number} - */ -goog.webgl.MAX_RENDERBUFFER_SIZE = 0x84E8; +}; +goog.inherits(ol.source.VectorTile, ol.source.UrlTile); /** - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.INVALID_FRAMEBUFFER_OPERATION = 0x0506; - +ol.source.VectorTile.prototype.getTile = + function(z, x, y, pixelRatio, projection) { + var tileCoordKey = this.getKeyZXY(z, x, y); + if (this.tileCache.containsKey(tileCoordKey)) { + return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); + } else { + goog.asserts.assert(projection, 'argument projection is truthy'); + var tileCoord = [z, x, y]; + var urlTileCoord = this.getTileCoordForTileUrlFunction( + tileCoord, projection); + var tileUrl = urlTileCoord ? + this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined; + var tile = new this.tileClass( + tileCoord, + tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, + tileUrl !== undefined ? tileUrl : '', + this.format_, + this.tileLoadFunction); + goog.events.listen(tile, goog.events.EventType.CHANGE, + this.handleTileChange, false, this); -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_FLIP_Y_WEBGL = 0x9240; + this.tileCache.set(tileCoordKey, tile); + return tile; + } +}; /** - * @const - * @type {number} + * @param {ol.VectorTile} vectorTile Vector tile. + * @param {string} url URL. */ -goog.webgl.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; - +ol.source.VectorTile.defaultTileLoadFunction = function(vectorTile, url) { + vectorTile.setLoader(ol.featureloader.tile(url, vectorTile.getFormat())); +}; -/** - * @const - * @type {number} - */ -goog.webgl.CONTEXT_LOST_WEBGL = 0x9242; +goog.provide('ol.renderer.canvas.VectorTileLayer'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Feature'); +goog.require('ol.TileRange'); +goog.require('ol.TileState'); +goog.require('ol.VectorTile'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.VectorTile'); +goog.require('ol.proj.Units'); +goog.require('ol.render.EventType'); +goog.require('ol.render.canvas.ReplayGroup'); +goog.require('ol.renderer.canvas.Layer'); +goog.require('ol.renderer.vector'); +goog.require('ol.size'); +goog.require('ol.source.VectorTile'); +goog.require('ol.tilecoord'); +goog.require('ol.vec.Mat4'); -/** - * @const - * @type {number} - */ -goog.webgl.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; /** - * @const - * @type {number} + * @constructor + * @extends {ol.renderer.canvas.Layer} + * @param {ol.layer.VectorTile} layer VectorTile layer. */ -goog.webgl.BROWSER_DEFAULT_WEBGL = 0x9244; +ol.renderer.canvas.VectorTileLayer = function(layer) { + goog.base(this, layer); -/** - * From the OES_texture_half_float extension. - * http://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/ - * @const - * @type {number} - */ -goog.webgl.HALF_FLOAT_OES = 0x8D61; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = ol.dom.createCanvasContext2D(); + /** + * @private + * @type {boolean} + */ + this.dirty_ = false; -/** - * From the OES_standard_derivatives extension. - * http://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/ - * @const - * @type {number} - */ -goog.webgl.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B; + /** + * @private + * @type {Array.<ol.VectorTile>} + */ + this.renderedTiles_ = []; + /** + * @private + * @type {ol.Extent} + */ + this.tmpExtent_ = ol.extent.createEmpty(); -/** - * From the OES_vertex_array_object extension. - * http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ - * @const - * @type {number} - */ -goog.webgl.VERTEX_ARRAY_BINDING_OES = 0x85B5; + /** + * @private + * @type {ol.Size} + */ + this.tmpSize_ = [NaN, NaN]; + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.tmpTransform_ = goog.vec.Mat4.createNumber(); -/** - * From the WEBGL_debug_renderer_info extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/ - * @const - * @type {number} - */ -goog.webgl.UNMASKED_VENDOR_WEBGL = 0x9245; +}; +goog.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.Layer); /** - * From the WEBGL_debug_renderer_info extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/ - * @const - * @type {number} + * @inheritDoc */ -goog.webgl.UNMASKED_RENDERER_WEBGL = 0x9246; - +ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = + function(frameState, layerState, context) { -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; + var pixelRatio = frameState.pixelRatio; + var skippedFeatureUids = layerState.managed ? + frameState.skippedFeatureUids : {}; + var viewState = frameState.viewState; + var center = viewState.center; + var projection = viewState.projection; + var resolution = viewState.resolution; + var rotation = viewState.rotation; + var layer = this.getLayer(); + var source = layer.getSource(); + goog.asserts.assertInstanceof(source, ol.source.VectorTile, + 'Source is an ol.source.VectorTile'); + var transform = this.getTransform(frameState, 0); -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; + this.dispatchPreComposeEvent(context, frameState, transform); + var replayContext; + if (layer.hasListener(ol.render.EventType.RENDER)) { + // resize and clear + this.context_.canvas.width = context.canvas.width; + this.context_.canvas.height = context.canvas.height; + replayContext = this.context_; + } else { + replayContext = context; + } + // for performance reasons, context.save / context.restore is not used + // to save and restore the transformation matrix and the opacity. + // see http://jsperf.com/context-save-restore-versus-variable + var alpha = replayContext.globalAlpha; + replayContext.globalAlpha = layerState.opacity; -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; + var tilesToDraw = this.renderedTiles_; + var tileGrid = source.getTileGrid(); + var currentZ, i, ii, origin, tile, tileSize; + var tilePixelRatio, tilePixelResolution, tilePixelSize, tileResolution; + for (i = 0, ii = tilesToDraw.length; i < ii; ++i) { + tile = tilesToDraw[i]; + currentZ = tile.getTileCoord()[0]; + tileSize = tileGrid.getTileSize(currentZ); + tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection); + tilePixelRatio = tilePixelSize[0] / + ol.size.toSize(tileSize, this.tmpSize_)[0]; + tileResolution = tileGrid.getResolution(currentZ); + tilePixelResolution = tileResolution / tilePixelRatio; + if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) { + origin = ol.extent.getTopLeft(tileGrid.getTileCoordExtent( + tile.getTileCoord(), this.tmpExtent_)); + transform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_, + pixelRatio * frameState.size[0] / 2, + pixelRatio * frameState.size[1] / 2, + pixelRatio * tilePixelResolution / resolution, + pixelRatio * tilePixelResolution / resolution, + viewState.rotation, + (origin[0] - center[0]) / tilePixelResolution, + (center[1] - origin[1]) / tilePixelResolution); + } + tile.getReplayState().replayGroup.replay(replayContext, pixelRatio, + transform, rotation, skippedFeatureUids); + } -/** - * From the WEBGL_compressed_texture_s3tc extension. - * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ - * @const - * @type {number} - */ -goog.webgl.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; + transform = this.getTransform(frameState, 0); + if (replayContext != context) { + this.dispatchRenderEvent(replayContext, frameState, transform); + context.drawImage(replayContext.canvas, 0, 0); + } + replayContext.globalAlpha = alpha; -/** - * From the EXT_texture_filter_anisotropic extension. - * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/ - * @const - * @type {number} - */ -goog.webgl.TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; + this.dispatchPostComposeEvent(context, frameState, transform); +}; /** - * From the EXT_texture_filter_anisotropic extension. - * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/ - * @const - * @type {number} + * @param {ol.VectorTile} tile Tile. + * @param {ol.layer.VectorTile} layer Vector tile layer. + * @param {number} pixelRatio Pixel ratio. */ -goog.webgl.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; - -goog.provide('ol.webgl.Fragment'); -goog.provide('ol.webgl.Shader'); -goog.provide('ol.webgl.Vertex'); -goog.provide('ol.webgl.shader'); - -goog.require('goog.functions'); -goog.require('goog.webgl'); -goog.require('ol.webgl'); +ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, + layer, pixelRatio) { + var revision = layer.getRevision(); + var renderOrder = layer.getRenderOrder() || null; + var replayState = tile.getReplayState(); + if (!replayState.dirty && replayState.renderedRevision == revision && + replayState.renderedRenderOrder == renderOrder) { + return; + } + // FIXME dispose of old replayGroup in post render + goog.dispose(replayState.replayGroup); + replayState.replayGroup = null; + replayState.dirty = false; -/** - * @constructor - * @param {string} source Source. - * @struct - */ -ol.webgl.Shader = function(source) { + var source = layer.getSource(); + goog.asserts.assertInstanceof(source, ol.source.VectorTile, + 'Source is an ol.source.VectorTile'); + var tileGrid = source.getTileGrid(); + var tileCoord = tile.getTileCoord(); + var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS; + var extent; + if (pixelSpace) { + var tilePixelSize = source.getTilePixelSize(tileCoord[0], pixelRatio, + tile.getProjection()); + extent = [0, 0, tilePixelSize[0], tilePixelSize[1]]; + } else { + extent = tileGrid.getTileCoordExtent(tileCoord); + } + var resolution = tileGrid.getResolution(tileCoord[0]); + var tileResolution = pixelSpace ? source.getTilePixelRatio() : resolution; + replayState.dirty = false; + var replayGroup = new ol.render.canvas.ReplayGroup(0, extent, + tileResolution, layer.getRenderBuffer()); + var squaredTolerance = ol.renderer.vector.getSquaredTolerance( + tileResolution, pixelRatio); /** - * @private - * @type {string} + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @this {ol.renderer.canvas.VectorTileLayer} */ - this.source_ = source; - -}; - + function renderFeature(feature) { + var styles; + var styleFunction = feature.getStyleFunction(); + if (styleFunction) { + goog.asserts.assertInstanceof(feature, ol.Feature, 'Got an ol.Feature'); + styles = styleFunction.call(feature, resolution); + } else { + styleFunction = layer.getStyleFunction(); + if (styleFunction) { + styles = styleFunction(feature, resolution); + } + } + if (styles) { + if (!goog.isArray(styles)) { + styles = [styles]; + } + var dirty = this.renderFeature(feature, squaredTolerance, styles, + replayGroup); + this.dirty_ = this.dirty_ || dirty; + replayState.dirty = replayState.dirty || dirty; + } + } -/** - * @return {number} Type. - */ -ol.webgl.Shader.prototype.getType = goog.abstractMethod; + var features = tile.getFeatures(); + if (renderOrder && renderOrder !== replayState.renderedRenderOrder) { + features.sort(renderOrder); + } + features.forEach(renderFeature, this); + replayGroup.finish(); -/** - * @return {string} Source. - */ -ol.webgl.Shader.prototype.getSource = function() { - return this.source_; + replayState.renderedRevision = revision; + replayState.renderedRenderOrder = renderOrder; + replayState.replayGroup = replayGroup; }; /** - * @return {boolean} Is animated? + * @inheritDoc */ -ol.webgl.Shader.prototype.isAnimated = goog.functions.FALSE; +ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + var resolution = frameState.viewState.resolution; + var rotation = frameState.viewState.rotation; + var layer = this.getLayer(); + var layerState = frameState.layerStates[goog.getUid(layer)]; + /** @type {Object.<string, boolean>} */ + var features = {}; + var replayables = this.renderedTiles_; + var source = layer.getSource(); + goog.asserts.assertInstanceof(source, ol.source.VectorTile, + 'Source is an ol.source.VectorTile'); + var tileGrid = source.getTileGrid(); + var found, tileSpaceCoordinate; + var i, ii, origin, replayGroup; + var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution; + for (i = 0, ii = replayables.length; i < ii; ++i) { + tile = replayables[i]; + tileCoord = tile.getTileCoord(); + tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord, + this.tmpExtent_); + if (!ol.extent.containsCoordinate(tileExtent, coordinate)) { + continue; + } + if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) { + origin = ol.extent.getTopLeft(tileExtent); + tilePixelRatio = source.getTilePixelRatio(); + tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio; + tileSpaceCoordinate = [ + (coordinate[0] - origin[0]) / tileResolution, + (origin[1] - coordinate[1]) / tileResolution + ]; + resolution = tilePixelRatio; + } else { + tileSpaceCoordinate = coordinate; + } + replayGroup = tile.getReplayState().replayGroup; + found = found || replayGroup.forEachFeatureAtCoordinate( + tileSpaceCoordinate, resolution, rotation, + layerState.managed ? frameState.skippedFeatureUids : {}, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + goog.asserts.assert(feature, 'received a feature'); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback.call(thisArg, feature, layer); + } + }); + } + return found; +}; /** - * @constructor - * @extends {ol.webgl.Shader} - * @param {string} source Source. - * @struct + * Handle changes in image style state. + * @param {goog.events.Event} event Image style change event. + * @private */ -ol.webgl.shader.Fragment = function(source) { - goog.base(this, source); +ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = + function(event) { + this.renderIfReadyAndVisible(); }; -goog.inherits(ol.webgl.shader.Fragment, ol.webgl.Shader); /** * @inheritDoc */ -ol.webgl.shader.Fragment.prototype.getType = function() { - return goog.webgl.FRAGMENT_SHADER; -}; - - - -/** - * @constructor - * @extends {ol.webgl.Shader} - * @param {string} source Source. - * @struct - */ -ol.webgl.shader.Vertex = function(source) { - goog.base(this, source); -}; -goog.inherits(ol.webgl.shader.Vertex, ol.webgl.Shader); +ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = + function(frameState, layerState) { + var layer = /** @type {ol.layer.Vector} */ (this.getLayer()); + goog.asserts.assertInstanceof(layer, ol.layer.VectorTile, + 'layer is an instance of ol.layer.VectorTile'); + var source = layer.getSource(); + goog.asserts.assertInstanceof(source, ol.source.VectorTile, + 'Source is an ol.source.VectorTile'); + this.updateAttributions( + frameState.attributions, source.getAttributions()); + this.updateLogos(frameState, source); -/** - * @inheritDoc - */ -ol.webgl.shader.Vertex.prototype.getType = function() { - return goog.webgl.VERTEX_SHADER; -}; + var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; + var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; + var updateWhileAnimating = layer.getUpdateWhileAnimating(); + var updateWhileInteracting = layer.getUpdateWhileInteracting(); -// This file is automatically generated, do not edit -goog.provide('ol.render.webgl.imagereplay.shader.Default'); -goog.provide('ol.render.webgl.imagereplay.shader.Default.Locations'); -goog.provide('ol.render.webgl.imagereplay.shader.DefaultFragment'); -goog.provide('ol.render.webgl.imagereplay.shader.DefaultVertex'); + if (!this.dirty_ && (!updateWhileAnimating && animating) || + (!updateWhileInteracting && interacting)) { + return true; + } -goog.require('ol.webgl.shader'); + var extent = frameState.extent; + if (layerState.extent) { + extent = ol.extent.getIntersection(extent, layerState.extent); + } + if (ol.extent.isEmpty(extent)) { + // Return false to prevent the rendering of the layer. + return false; + } + var viewState = frameState.viewState; + var projection = viewState.projection; + var resolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var tileGrid = source.getTileGrid(); + var resolutions = tileGrid.getResolutions(); + var z = resolutions.length - 1; + while (z > 0 && resolutions[z] < resolution) { + --z; + } + var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + this.updateUsedTiles(frameState.usedTiles, source, z, tileRange); + this.manageTilePyramid(frameState, source, tileGrid, pixelRatio, + projection, extent, z, layer.getPreload()); + this.scheduleExpireCache(frameState, source); -/** - * @constructor - * @extends {ol.webgl.shader.Fragment} - * @struct - */ -ol.render.webgl.imagereplay.shader.DefaultFragment = function() { - goog.base(this, ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE); -}; -goog.inherits(ol.render.webgl.imagereplay.shader.DefaultFragment, ol.webgl.shader.Fragment); -goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultFragment); + /** + * @type {Object.<number, Object.<string, ol.VectorTile>>} + */ + var tilesToDrawByZ = {}; + tilesToDrawByZ[z] = {}; + var findLoadedTiles = this.createLoadedTileFinder(source, projection, + tilesToDrawByZ); -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultFragment.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'; + var useInterimTilesOnError = layer.getUseInterimTilesOnError(); + var tmpExtent = this.tmpExtent_; + var tmpTileRange = new ol.TileRange(0, 0, 0, 0); + var childTileRange, fullyLoaded, tile, tileState, x, y; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultFragment.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;}'; + tile = source.getTile(z, x, y, pixelRatio, projection); + goog.asserts.assertInstanceof(tile, ol.VectorTile, + 'Tile is an ol.VectorTile'); + tileState = tile.getState(); + if (tileState == ol.TileState.LOADED || + tileState == ol.TileState.EMPTY || + (tileState == ol.TileState.ERROR && !useInterimTilesOnError)) { + tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; + continue; + } + + fullyLoaded = tileGrid.forEachTileCoordParentTileRange( + tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); + if (!fullyLoaded) { + childTileRange = tileGrid.getTileCoordChildTileRange( + tile.tileCoord, tmpTileRange, tmpExtent); + if (childTileRange) { + findLoadedTiles(z + 1, childTileRange); + } + } + } + } -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE = goog.DEBUG ? - ol.render.webgl.imagereplay.shader.DefaultFragment.DEBUG_SOURCE : - ol.render.webgl.imagereplay.shader.DefaultFragment.OPTIMIZED_SOURCE; + this.dirty_ = false; + /** @type {Array.<number>} */ + var zs = Object.keys(tilesToDrawByZ).map(Number); + zs.sort(); + var replayables = []; + var i, ii, currentZ, tileCoordKey, tilesToDraw; + for (i = 0, ii = zs.length; i < ii; ++i) { + currentZ = zs[i]; + tilesToDraw = tilesToDrawByZ[currentZ]; + for (tileCoordKey in tilesToDraw) { + tile = tilesToDraw[tileCoordKey]; + if (tile.getState() == ol.TileState.LOADED) { + replayables.push(tile); + this.createReplayGroup(tile, layer, pixelRatio); + } + } + } + this.renderedTiles_ = replayables; -/** - * @constructor - * @extends {ol.webgl.shader.Vertex} - * @struct - */ -ol.render.webgl.imagereplay.shader.DefaultVertex = function() { - goog.base(this, ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE); + return true; }; -goog.inherits(ol.render.webgl.imagereplay.shader.DefaultVertex, ol.webgl.shader.Vertex); -goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultVertex); /** - * @const - * @type {string} + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {number} squaredTolerance Squared tolerance. + * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of + * styles. + * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. + * @return {boolean} `true` if an image is loading. */ -ol.render.webgl.imagereplay.shader.DefaultVertex.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.);\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + offsets;\n v_texCoord = a_texCoord;\n v_opacity = a_opacity;\n}\n\n\n'; - +ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = + function(feature, squaredTolerance, styles, replayGroup) { + if (!styles) { + return false; + } + var loading = false; + if (goog.isArray(styles)) { + for (var i = 0, ii = styles.length; i < ii; ++i) { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles[i], squaredTolerance, + this.handleStyleImageChange_, this) || loading; + } + } else { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles, squaredTolerance, + this.handleStyleImageChange_, this) || loading; + } + return loading; +}; -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultVertex.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.);gl_Position=h*vec4(c,0.,1.)+offsets;a=d;b=f;}'; +// FIXME offset panning +goog.provide('ol.renderer.canvas.Map'); -/** - * @const - * @type {string} - */ -ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE = goog.DEBUG ? - ol.render.webgl.imagereplay.shader.DefaultVertex.DEBUG_SOURCE : - ol.render.webgl.imagereplay.shader.DefaultVertex.OPTIMIZED_SOURCE; +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.style'); +goog.require('goog.vec.Mat4'); +goog.require('ol'); +goog.require('ol.RendererType'); +goog.require('ol.css'); +goog.require('ol.dom'); +goog.require('ol.layer.Image'); +goog.require('ol.layer.Layer'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.layer.VectorTile'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.canvas.Immediate'); +goog.require('ol.renderer.Map'); +goog.require('ol.renderer.canvas.ImageLayer'); +goog.require('ol.renderer.canvas.Layer'); +goog.require('ol.renderer.canvas.TileLayer'); +goog.require('ol.renderer.canvas.VectorLayer'); +goog.require('ol.renderer.canvas.VectorTileLayer'); +goog.require('ol.source.State'); +goog.require('ol.vec.Mat4'); /** * @constructor - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLProgram} program Program. - * @struct + * @extends {ol.renderer.Map} + * @param {Element} container Container. + * @param {ol.Map} map Map. */ -ol.render.webgl.imagereplay.shader.Default.Locations = function(gl, program) { +ol.renderer.canvas.Map = function(container, map) { - /** - * @type {WebGLUniformLocation} - */ - this.u_image = gl.getUniformLocation( - program, goog.DEBUG ? 'u_image' : 'l'); + goog.base(this, container, map); /** - * @type {WebGLUniformLocation} + * @private + * @type {CanvasRenderingContext2D} */ - this.u_offsetRotateMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_offsetRotateMatrix' : 'j'); + this.context_ = ol.dom.createCanvasContext2D(); /** - * @type {WebGLUniformLocation} + * @private + * @type {HTMLCanvasElement} */ - this.u_offsetScaleMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_offsetScaleMatrix' : 'i'); + this.canvas_ = this.context_.canvas; - /** - * @type {WebGLUniformLocation} - */ - this.u_opacity = gl.getUniformLocation( - program, goog.DEBUG ? 'u_opacity' : 'k'); + this.canvas_.style.width = '100%'; + this.canvas_.style.height = '100%'; + this.canvas_.className = ol.css.CLASS_UNSELECTABLE; + goog.dom.insertChildAt(container, this.canvas_, 0); /** - * @type {WebGLUniformLocation} + * @private + * @type {boolean} */ - this.u_projectionMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_projectionMatrix' : 'h'); + this.renderedVisible_ = true; /** - * @type {number} + * @private + * @type {!goog.vec.Mat4.Number} */ - this.a_offsets = gl.getAttribLocation( - program, goog.DEBUG ? 'a_offsets' : 'e'); + this.transform_ = goog.vec.Mat4.createNumber(); - /** - * @type {number} - */ - this.a_opacity = gl.getAttribLocation( - program, goog.DEBUG ? 'a_opacity' : 'f'); +}; +goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map); - /** - * @type {number} - */ - this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'c'); - /** - * @type {number} - */ - this.a_rotateWithView = gl.getAttribLocation( - program, goog.DEBUG ? 'a_rotateWithView' : 'g'); +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) { + if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { + return new ol.renderer.canvas.ImageLayer(layer); + } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { + return new ol.renderer.canvas.TileLayer(layer); + } else if (ol.ENABLE_VECTOR_TILE && layer instanceof ol.layer.VectorTile) { + return new ol.renderer.canvas.VectorTileLayer(layer); + } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { + return new ol.renderer.canvas.VectorLayer(layer); + } else { + goog.asserts.fail('unexpected layer configuration'); + return null; + } +}; - /** - * @type {number} - */ - this.a_texCoord = gl.getAttribLocation( - program, goog.DEBUG ? 'a_texCoord' : 'd'); + +/** + * @param {ol.render.EventType} type Event type. + * @param {olx.FrameState} frameState Frame state. + * @private + */ +ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ = + function(type, frameState) { + var map = this.getMap(); + var context = this.context_; + if (map.hasListener(type)) { + var extent = frameState.extent; + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var rotation = viewState.rotation; + + var transform = this.getTransform(frameState); + + var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio, + extent, transform, rotation); + var composeEvent = new ol.render.Event(type, map, vectorContext, + frameState, context, null); + map.dispatchEvent(composeEvent); + + vectorContext.flush(); + } }; -goog.provide('ol.webgl.Buffer'); -goog.require('goog.webgl'); -goog.require('ol'); +/** + * @param {olx.FrameState} frameState Frame state. + * @protected + * @return {!goog.vec.Mat4.Number} Transform. + */ +ol.renderer.canvas.Map.prototype.getTransform = function(frameState) { + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var resolution = viewState.resolution; + return ol.vec.Mat4.makeTransform2D(this.transform_, + this.canvas_.width / 2, this.canvas_.height / 2, + pixelRatio / resolution, -pixelRatio / resolution, + -viewState.rotation, + -viewState.center[0], -viewState.center[1]); +}; /** - * @enum {number} + * @inheritDoc */ -ol.webgl.BufferUsage = { - STATIC_DRAW: goog.webgl.STATIC_DRAW, - STREAM_DRAW: goog.webgl.STREAM_DRAW, - DYNAMIC_DRAW: goog.webgl.DYNAMIC_DRAW +ol.renderer.canvas.Map.prototype.getType = function() { + return ol.RendererType.CANVAS; +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { + + if (!frameState) { + if (this.renderedVisible_) { + goog.style.setElementShown(this.canvas_, false); + this.renderedVisible_ = false; + } + return; + } + + var context = this.context_; + var width = frameState.size[0] * frameState.pixelRatio; + var height = frameState.size[1] * frameState.pixelRatio; + if (this.canvas_.width != width || this.canvas_.height != height) { + this.canvas_.width = width; + this.canvas_.height = height; + } else { + context.clearRect(0, 0, this.canvas_.width, this.canvas_.height); + } + + this.calculateMatrices2D(frameState); + + this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); + + var layerStatesArray = frameState.layerStatesArray; + goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); + + var viewResolution = frameState.viewState.resolution; + var i, ii, layer, layerRenderer, layerState; + for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { + layerState = layerStatesArray[i]; + layer = layerState.layer; + layerRenderer = this.getLayerRenderer(layer); + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.canvas.Layer, + 'layerRenderer is an instance of ol.renderer.canvas.Layer'); + if (!ol.layer.Layer.visibleAtResolution(layerState, viewResolution) || + layerState.sourceState != ol.source.State.READY) { + continue; + } + if (layerRenderer.prepareFrame(frameState, layerState)) { + layerRenderer.composeFrame(frameState, layerState, context); + } + } + + this.dispatchComposeEvent_( + ol.render.EventType.POSTCOMPOSE, frameState); + + if (!this.renderedVisible_) { + goog.style.setElementShown(this.canvas_, true); + this.renderedVisible_ = true; + } + + this.scheduleRemoveUnusedLayerRenderers(frameState); + this.scheduleExpireIconCache(frameState); }; +goog.provide('ol.renderer.dom.Layer'); + +goog.require('ol'); +goog.require('ol.layer.Layer'); +goog.require('ol.renderer.Layer'); + /** * @constructor - * @param {Array.<number>=} opt_arr Array. - * @param {number=} opt_usage Usage. - * @struct + * @extends {ol.renderer.Layer} + * @param {ol.layer.Layer} layer Layer. + * @param {!Element} target Target. */ -ol.webgl.Buffer = function(opt_arr, opt_usage) { +ol.renderer.dom.Layer = function(layer, target) { - /** - * @private - * @type {Array.<number>} - */ - this.arr_ = opt_arr !== undefined ? opt_arr : []; + goog.base(this, layer); /** - * @private - * @type {number} + * @type {!Element} + * @protected */ - this.usage_ = opt_usage !== undefined ? - opt_usage : ol.webgl.BufferUsage.STATIC_DRAW; + this.target = target; }; +goog.inherits(ol.renderer.dom.Layer, ol.renderer.Layer); /** - * @return {Array.<number>} Array. + * Clear rendered elements. */ -ol.webgl.Buffer.prototype.getArray = function() { - return this.arr_; -}; +ol.renderer.dom.Layer.prototype.clearFrame = ol.nullFunction; /** - * @return {number} Usage. + * @param {olx.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. */ -ol.webgl.Buffer.prototype.getUsage = function() { - return this.usage_; -}; +ol.renderer.dom.Layer.prototype.composeFrame = ol.nullFunction; -goog.provide('ol.webgl.Context'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.log'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.array'); -goog.require('ol.webgl.Buffer'); -goog.require('ol.webgl.WebGLContextEventType'); +/** + * @return {!Element} Target. + */ +ol.renderer.dom.Layer.prototype.getTarget = function() { + return this.target; +}; /** - * @typedef {{buf: ol.webgl.Buffer, - * buffer: WebGLBuffer}} + * @param {olx.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. + * @return {boolean} whether composeFrame should be called. */ -ol.webgl.BufferCacheEntry; +ol.renderer.dom.Layer.prototype.prepareFrame = goog.abstractMethod; + +goog.provide('ol.renderer.dom.ImageLayer'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.vec.Mat4'); +goog.require('ol.ImageBase'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Image'); +goog.require('ol.proj'); +goog.require('ol.renderer.dom.Layer'); +goog.require('ol.vec.Mat4'); /** - * @classdesc - * A WebGL context for accessing low-level WebGL capabilities. - * * @constructor - * @extends {goog.events.EventTarget} - * @param {HTMLCanvasElement} canvas Canvas. - * @param {WebGLRenderingContext} gl GL. + * @extends {ol.renderer.dom.Layer} + * @param {ol.layer.Image} imageLayer Image layer. */ -ol.webgl.Context = function(canvas, gl) { +ol.renderer.dom.ImageLayer = function(imageLayer) { + var target = goog.dom.createElement('DIV'); + target.style.position = 'absolute'; + + goog.base(this, imageLayer, target); /** + * The last rendered image. * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = canvas; - - /** - * @private - * @type {WebGLRenderingContext} - */ - this.gl_ = gl; - - /** - * @private - * @type {Object.<number, ol.webgl.BufferCacheEntry>} - */ - this.bufferCache_ = {}; - - /** - * @private - * @type {Object.<number, WebGLShader>} - */ - this.shaderCache_ = {}; - - /** - * @private - * @type {Object.<string, WebGLProgram>} - */ - this.programCache_ = {}; - - /** - * @private - * @type {WebGLProgram} - */ - this.currentProgram_ = null; - - /** - * @private - * @type {WebGLFramebuffer} - */ - this.hitDetectionFramebuffer_ = null; - - /** - * @private - * @type {WebGLTexture} + * @type {?ol.ImageBase} */ - this.hitDetectionTexture_ = null; + this.image_ = null; /** * @private - * @type {WebGLRenderbuffer} - */ - this.hitDetectionRenderbuffer_ = null; - - /** - * @type {boolean} + * @type {goog.vec.Mat4.Number} */ - this.hasOESElementIndexUint = ol.array.includes( - ol.WEBGL_EXTENSIONS, 'OES_element_index_uint'); - - // use the OES_element_index_uint extension if available - if (this.hasOESElementIndexUint) { - var ext = gl.getExtension('OES_element_index_uint'); - goog.asserts.assert(ext, - 'Failed to get extension "OES_element_index_uint"'); - } - - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST, - this.handleWebGLContextLost, false, this); - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED, - this.handleWebGLContextRestored, false, this); - -}; - + this.transform_ = goog.vec.Mat4.createNumberIdentity(); -/** - * Just bind the buffer if it's in the cache. Otherwise create - * the WebGL buffer, bind it, populate it, and add an entry to - * the cache. - * @param {number} target Target. - * @param {ol.webgl.Buffer} buf Buffer. - */ -ol.webgl.Context.prototype.bindBuffer = function(target, buf) { - var gl = this.getGL(); - var arr = buf.getArray(); - var bufferKey = goog.getUid(buf); - if (bufferKey in this.bufferCache_) { - var bufferCacheEntry = this.bufferCache_[bufferKey]; - gl.bindBuffer(target, bufferCacheEntry.buffer); - } else { - var buffer = gl.createBuffer(); - gl.bindBuffer(target, buffer); - goog.asserts.assert(target == goog.webgl.ARRAY_BUFFER || - target == goog.webgl.ELEMENT_ARRAY_BUFFER, - 'target is supposed to be an ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER'); - var /** @type {ArrayBufferView} */ arrayBuffer; - if (target == goog.webgl.ARRAY_BUFFER) { - arrayBuffer = new Float32Array(arr); - } else if (target == goog.webgl.ELEMENT_ARRAY_BUFFER) { - arrayBuffer = this.hasOESElementIndexUint ? - new Uint32Array(arr) : new Uint16Array(arr); - } else { - goog.asserts.fail(); - } - gl.bufferData(target, arrayBuffer, buf.getUsage()); - this.bufferCache_[bufferKey] = { - buf: buf, - buffer: buffer - }; - } }; +goog.inherits(ol.renderer.dom.ImageLayer, ol.renderer.dom.Layer); /** - * @param {ol.webgl.Buffer} buf Buffer. + * @inheritDoc */ -ol.webgl.Context.prototype.deleteBuffer = function(buf) { - var gl = this.getGL(); - var bufferKey = goog.getUid(buf); - goog.asserts.assert(bufferKey in this.bufferCache_, - 'attempted to delete uncached buffer'); - var bufferCacheEntry = this.bufferCache_[bufferKey]; - if (!gl.isContextLost()) { - gl.deleteBuffer(bufferCacheEntry.buffer); - } - delete this.bufferCache_[bufferKey]; +ol.renderer.dom.ImageLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + var layer = this.getLayer(); + var source = layer.getSource(); + var resolution = frameState.viewState.resolution; + var rotation = frameState.viewState.rotation; + var skippedFeatureUids = frameState.skippedFeatureUids; + return source.forEachFeatureAtCoordinate( + coordinate, resolution, rotation, skippedFeatureUids, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + return callback.call(thisArg, feature, layer); + }); }; /** * @inheritDoc */ -ol.webgl.Context.prototype.disposeInternal = function() { - var gl = this.getGL(); - if (!gl.isContextLost()) { - goog.object.forEach(this.bufferCache_, function(bufferCacheEntry) { - gl.deleteBuffer(bufferCacheEntry.buffer); - }); - goog.object.forEach(this.programCache_, function(program) { - gl.deleteProgram(program); - }); - goog.object.forEach(this.shaderCache_, function(shader) { - gl.deleteShader(shader); - }); - // delete objects for hit-detection - gl.deleteFramebuffer(this.hitDetectionFramebuffer_); - gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_); - gl.deleteTexture(this.hitDetectionTexture_); - } +ol.renderer.dom.ImageLayer.prototype.clearFrame = function() { + goog.dom.removeChildren(this.target); + this.image_ = null; }; /** - * @return {HTMLCanvasElement} Canvas. + * @inheritDoc */ -ol.webgl.Context.prototype.getCanvas = function() { - return this.canvas_; -}; +ol.renderer.dom.ImageLayer.prototype.prepareFrame = + function(frameState, layerState) { + var viewState = frameState.viewState; + var viewCenter = viewState.center; + var viewResolution = viewState.resolution; + var viewRotation = viewState.rotation; -/** - * Get the WebGL rendering context - * @return {WebGLRenderingContext} The rendering context. - * @api - */ -ol.webgl.Context.prototype.getGL = function() { - return this.gl_; -}; + var image = this.image_; + var imageLayer = this.getLayer(); + goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, + 'layer is an instance of ol.layer.Image'); + var imageSource = imageLayer.getSource(); + var hints = frameState.viewHints; -/** - * Get the frame buffer for hit detection. - * @return {WebGLFramebuffer} The hit detection frame buffer. - */ -ol.webgl.Context.prototype.getHitDetectionFramebuffer = function() { - if (!this.hitDetectionFramebuffer_) { - this.initHitDetectionFramebuffer_(); + var renderedExtent = frameState.extent; + if (layerState.extent !== undefined) { + renderedExtent = ol.extent.getIntersection( + renderedExtent, layerState.extent); } - return this.hitDetectionFramebuffer_; -}; - -/** - * Get shader from the cache if it's in the cache. Otherwise, create - * the WebGL shader, compile it, and add entry to cache. - * @param {ol.webgl.Shader} shaderObject Shader object. - * @return {WebGLShader} Shader. - */ -ol.webgl.Context.prototype.getShader = function(shaderObject) { - var shaderKey = goog.getUid(shaderObject); - if (shaderKey in this.shaderCache_) { - return this.shaderCache_[shaderKey]; - } else { - var gl = this.getGL(); - var shader = gl.createShader(shaderObject.getType()); - gl.shaderSource(shader, shaderObject.getSource()); - gl.compileShader(shader); - if (goog.DEBUG) { - if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) && - !gl.isContextLost()) { - goog.log.error(this.logger_, gl.getShaderInfoLog(shader)); + if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && + !ol.extent.isEmpty(renderedExtent)) { + var projection = viewState.projection; + if (!ol.ENABLE_RASTER_REPROJECTION) { + var sourceProjection = imageSource.getProjection(); + if (sourceProjection) { + goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), + 'projection and sourceProjection are equivalent'); + projection = sourceProjection; } } - goog.asserts.assert( - gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) || - gl.isContextLost(), - 'illegal state, shader not compiled or context lost'); - this.shaderCache_[shaderKey] = shader; - return shader; - } -}; - - -/** - * Get the program from the cache if it's in the cache. Otherwise create - * the WebGL program, attach the shaders to it, and add an entry to the - * cache. - * @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader. - * @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader. - * @return {WebGLProgram} Program. - */ -ol.webgl.Context.prototype.getProgram = function( - fragmentShaderObject, vertexShaderObject) { - var programKey = - goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject); - if (programKey in this.programCache_) { - return this.programCache_[programKey]; - } else { - var gl = this.getGL(); - var program = gl.createProgram(); - gl.attachShader(program, this.getShader(fragmentShaderObject)); - gl.attachShader(program, this.getShader(vertexShaderObject)); - gl.linkProgram(program); - if (goog.DEBUG) { - if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) && - !gl.isContextLost()) { - goog.log.error(this.logger_, gl.getProgramInfoLog(program)); + var image_ = imageSource.getImage(renderedExtent, viewResolution, + frameState.pixelRatio, projection); + if (image_) { + var loaded = this.loadImage(image_); + if (loaded) { + image = image_; } } - goog.asserts.assert( - gl.getProgramParameter(program, goog.webgl.LINK_STATUS) || - gl.isContextLost(), - 'illegal state, shader not linked or context lost'); - this.programCache_[programKey] = program; - return program; } -}; - - -/** - * FIXME empy description for jsdoc - */ -ol.webgl.Context.prototype.handleWebGLContextLost = function() { - goog.object.clear(this.bufferCache_); - goog.object.clear(this.shaderCache_); - goog.object.clear(this.programCache_); - this.currentProgram_ = null; - this.hitDetectionFramebuffer_ = null; - this.hitDetectionTexture_ = null; - this.hitDetectionRenderbuffer_ = null; -}; - - -/** - * FIXME empy description for jsdoc - */ -ol.webgl.Context.prototype.handleWebGLContextRestored = function() { -}; - - -/** - * Creates a 1x1 pixel framebuffer for the hit-detection. - * @private - */ -ol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() { - var gl = this.gl_; - var framebuffer = gl.createFramebuffer(); - gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); - - var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1); - var renderbuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1); - gl.framebufferTexture2D( - gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, - gl.RENDERBUFFER, renderbuffer); - - gl.bindTexture(gl.TEXTURE_2D, null); - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - this.hitDetectionFramebuffer_ = framebuffer; - this.hitDetectionTexture_ = texture; - this.hitDetectionRenderbuffer_ = renderbuffer; -}; - - -/** - * Use a program. If the program is already in use, this will return `false`. - * @param {WebGLProgram} program Program. - * @return {boolean} Changed. - * @api - */ -ol.webgl.Context.prototype.useProgram = function(program) { - if (program == this.currentProgram_) { - return false; - } else { - var gl = this.getGL(); - gl.useProgram(program); - this.currentProgram_ = program; - return true; + if (image) { + var imageExtent = image.getExtent(); + var imageResolution = image.getResolution(); + var transform = goog.vec.Mat4.createNumber(); + ol.vec.Mat4.makeTransform2D(transform, + frameState.size[0] / 2, frameState.size[1] / 2, + imageResolution / viewResolution, imageResolution / viewResolution, + viewRotation, + (imageExtent[0] - viewCenter[0]) / imageResolution, + (viewCenter[1] - imageExtent[3]) / imageResolution); + if (image != this.image_) { + var imageElement = image.getImage(this); + // Bootstrap sets the style max-width: 100% for all images, which breaks + // prevents the image from being displayed in FireFox. Workaround by + // overriding the max-width style. + imageElement.style.maxWidth = 'none'; + imageElement.style.position = 'absolute'; + goog.dom.removeChildren(this.target); + this.target.appendChild(imageElement); + this.image_ = image; + } + this.setTransform_(transform); + this.updateAttributions(frameState.attributions, image.getAttributions()); + this.updateLogos(frameState, imageSource); } -}; - -/** - * @private - * @type {goog.log.Logger} - */ -ol.webgl.Context.prototype.logger_ = goog.log.getLogger('ol.webgl.Context'); + return true; +}; /** - * @param {WebGLRenderingContext} gl WebGL rendering context. - * @param {number=} opt_wrapS wrapS. - * @param {number=} opt_wrapT wrapT. - * @return {WebGLTexture} + * @param {goog.vec.Mat4.Number} transform Transform. * @private */ -ol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) { - var texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - - if (opt_wrapS !== undefined) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, opt_wrapS); - } - if (opt_wrapT !== undefined) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, opt_wrapT); +ol.renderer.dom.ImageLayer.prototype.setTransform_ = function(transform) { + if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { + ol.dom.transformElement2D(this.target, transform, 6); + goog.vec.Mat4.setFromArray(this.transform_, transform); } - - return texture; -}; - - -/** - * @param {WebGLRenderingContext} gl WebGL rendering context. - * @param {number} width Width. - * @param {number} height Height. - * @param {number=} opt_wrapS wrapS. - * @param {number=} opt_wrapT wrapT. - * @return {WebGLTexture} - */ -ol.webgl.Context.createEmptyTexture = function( - gl, width, height, opt_wrapS, opt_wrapT) { - var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT); - gl.texImage2D( - gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, - null); - - return texture; }; +// FIXME probably need to reset TileLayerZ if offsets get too large +// FIXME when zooming out, preserve higher Z divs to avoid white flash -/** - * @param {WebGLRenderingContext} gl WebGL rendering context. - * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image. - * @param {number=} opt_wrapS wrapS. - * @param {number=} opt_wrapT wrapT. - * @return {WebGLTexture} - */ -ol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) { - var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT); - gl.texImage2D( - gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); - - return texture; -}; - -goog.provide('ol.render.webgl.ImageReplay'); -goog.provide('ol.render.webgl.ReplayGroup'); +goog.provide('ol.renderer.dom.TileLayer'); +goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.object'); +goog.require('goog.dom'); +goog.require('goog.style'); goog.require('goog.vec.Mat4'); +goog.require('ol'); +goog.require('ol.Coordinate'); +goog.require('ol.TileCoord'); +goog.require('ol.TileRange'); +goog.require('ol.TileState'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); goog.require('ol.extent'); -goog.require('ol.render.IReplayGroup'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.webgl.imagereplay.shader.Default'); -goog.require('ol.render.webgl.imagereplay.shader.Default.Locations'); -goog.require('ol.render.webgl.imagereplay.shader.DefaultFragment'); -goog.require('ol.render.webgl.imagereplay.shader.DefaultVertex'); +goog.require('ol.layer.Tile'); +goog.require('ol.renderer.dom.Layer'); +goog.require('ol.size'); +goog.require('ol.tilecoord'); +goog.require('ol.tilegrid.TileGrid'); goog.require('ol.vec.Mat4'); -goog.require('ol.webgl.Buffer'); -goog.require('ol.webgl.Context'); /** * @constructor - * @extends {ol.render.VectorContext} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @protected - * @struct + * @extends {ol.renderer.dom.Layer} + * @param {ol.layer.Tile} tileLayer Tile layer. */ -ol.render.webgl.ImageReplay = function(tolerance, maxExtent) { - goog.base(this); +ol.renderer.dom.TileLayer = function(tileLayer) { - /** - * @type {number|undefined} - * @private - */ - this.anchorX_ = undefined; + var target = goog.dom.createElement('DIV'); + target.style.position = 'absolute'; - /** - * @type {number|undefined} - * @private - */ - this.anchorY_ = undefined; + goog.base(this, tileLayer, target); /** - * The origin of the coordinate system for the point coordinates sent to - * the GPU. To eliminate jitter caused by precision problems in the GPU - * we use the "Rendering Relative to Eye" technique described in the "3D - * Engine Design for Virtual Globes" book. * @private - * @type {ol.Coordinate} + * @type {boolean} */ - this.origin_ = ol.extent.getCenter(maxExtent); + this.renderedVisible_ = true; /** - * @type {Array.<number>} * @private + * @type {number} */ - this.groupIndices_ = []; + this.renderedOpacity_ = 1; /** - * @type {Array.<number>} * @private + * @type {number} */ - this.hitDetectionGroupIndices_ = []; + this.renderedRevision_ = 0; /** - * @type {number|undefined} * @private + * @type {!Object.<number, ol.renderer.dom.TileLayerZ_>} */ - this.height_ = undefined; + this.tileLayerZs_ = {}; - /** - * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} - * @private - */ - this.images_ = []; +}; +goog.inherits(ol.renderer.dom.TileLayer, ol.renderer.dom.Layer); - /** - * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} - * @private - */ - this.hitDetectionImages_ = []; - /** - * @type {number|undefined} - * @private - */ - this.imageHeight_ = undefined; +/** + * @inheritDoc + */ +ol.renderer.dom.TileLayer.prototype.clearFrame = function() { + goog.dom.removeChildren(this.target); + this.renderedRevision_ = 0; +}; - /** - * @type {number|undefined} - * @private - */ - this.imageWidth_ = undefined; - /** - * @type {Array.<number>} - * @private - */ - this.indices_ = []; +/** + * @inheritDoc + */ +ol.renderer.dom.TileLayer.prototype.prepareFrame = + function(frameState, layerState) { + + if (!layerState.visible) { + if (this.renderedVisible_) { + goog.style.setElementShown(this.target, false); + this.renderedVisible_ = false; + } + return true; + } + + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var projection = viewState.projection; + + var tileLayer = this.getLayer(); + goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, + 'layer is an instance of ol.layer.Tile'); + var tileSource = tileLayer.getSource(); + var tileGrid = tileSource.getTileGridForProjection(projection); + var tileGutter = tileSource.getGutter(); + var z = tileGrid.getZForResolution(viewState.resolution); + var tileResolution = tileGrid.getResolution(z); + var center = viewState.center; + var extent; + if (tileResolution == viewState.resolution) { + center = this.snapCenterToPixel(center, tileResolution, frameState.size); + extent = ol.extent.getForViewAndSize( + center, tileResolution, viewState.rotation, frameState.size); + } else { + extent = frameState.extent; + } + + if (layerState.extent !== undefined) { + extent = ol.extent.getIntersection(extent, layerState.extent); + } + + var tileRange = tileGrid.getTileRangeForExtentAndResolution( + extent, tileResolution); + + /** @type {Object.<number, Object.<string, ol.Tile>>} */ + var tilesToDrawByZ = {}; + tilesToDrawByZ[z] = {}; + + var findLoadedTiles = this.createLoadedTileFinder( + tileSource, projection, tilesToDrawByZ); + + var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); + + var tmpExtent = ol.extent.createEmpty(); + var tmpTileRange = new ol.TileRange(0, 0, 0, 0); + var childTileRange, drawable, fullyLoaded, tile, tileState, x, y; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + tile = tileSource.getTile(z, x, y, pixelRatio, projection); + tileState = tile.getState(); + drawable = tileState == ol.TileState.LOADED || + tileState == ol.TileState.EMPTY || + tileState == ol.TileState.ERROR && !useInterimTilesOnError; + if (!drawable && tile.interimTile) { + tile = tile.interimTile; + } + goog.asserts.assert(tile); + tileState = tile.getState(); + if (tileState == ol.TileState.LOADED) { + tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; + continue; + } else if (tileState == ol.TileState.EMPTY || + (tileState == ol.TileState.ERROR && + !useInterimTilesOnError)) { + continue; + } + fullyLoaded = tileGrid.forEachTileCoordParentTileRange( + tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); + if (!fullyLoaded) { + childTileRange = tileGrid.getTileCoordChildTileRange( + tile.tileCoord, tmpTileRange, tmpExtent); + if (childTileRange) { + findLoadedTiles(z + 1, childTileRange); + } + } + + } + + } + + // If the tile source revision changes, we destroy the existing DOM structure + // so that a new one will be created. It would be more efficient to modify + // the existing structure. + var tileLayerZ, tileLayerZKey; + if (this.renderedRevision_ != tileSource.getRevision()) { + for (tileLayerZKey in this.tileLayerZs_) { + tileLayerZ = this.tileLayerZs_[+tileLayerZKey]; + goog.dom.removeNode(tileLayerZ.target); + } + this.tileLayerZs_ = {}; + this.renderedRevision_ = tileSource.getRevision(); + } + + /** @type {Array.<number>} */ + var zs = Object.keys(tilesToDrawByZ).map(Number); + goog.array.sort(zs); + + /** @type {Object.<number, boolean>} */ + var newTileLayerZKeys = {}; + + var iz, iziz, tileCoordKey, tileCoordOrigin, tilesToDraw; + for (iz = 0, iziz = zs.length; iz < iziz; ++iz) { + tileLayerZKey = zs[iz]; + if (tileLayerZKey in this.tileLayerZs_) { + tileLayerZ = this.tileLayerZs_[tileLayerZKey]; + } else { + tileCoordOrigin = + tileGrid.getTileCoordForCoordAndZ(center, tileLayerZKey); + tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin); + newTileLayerZKeys[tileLayerZKey] = true; + this.tileLayerZs_[tileLayerZKey] = tileLayerZ; + } + tilesToDraw = tilesToDrawByZ[tileLayerZKey]; + for (tileCoordKey in tilesToDraw) { + tileLayerZ.addTile(tilesToDraw[tileCoordKey], tileGutter); + } + tileLayerZ.finalizeAddTiles(); + } + + /** @type {Array.<number>} */ + var tileLayerZKeys = Object.keys(this.tileLayerZs_).map(Number); + goog.array.sort(tileLayerZKeys); + + var i, ii, j, origin, resolution; + var transform = goog.vec.Mat4.createNumber(); + for (i = 0, ii = tileLayerZKeys.length; i < ii; ++i) { + tileLayerZKey = tileLayerZKeys[i]; + tileLayerZ = this.tileLayerZs_[tileLayerZKey]; + if (!(tileLayerZKey in tilesToDrawByZ)) { + goog.dom.removeNode(tileLayerZ.target); + delete this.tileLayerZs_[tileLayerZKey]; + continue; + } + resolution = tileLayerZ.getResolution(); + origin = tileLayerZ.getOrigin(); + ol.vec.Mat4.makeTransform2D(transform, + frameState.size[0] / 2, frameState.size[1] / 2, + resolution / viewState.resolution, + resolution / viewState.resolution, + viewState.rotation, + (origin[0] - center[0]) / resolution, + (center[1] - origin[1]) / resolution); + tileLayerZ.setTransform(transform); + if (tileLayerZKey in newTileLayerZKeys) { + for (j = tileLayerZKey - 1; j >= 0; --j) { + if (j in this.tileLayerZs_) { + goog.dom.insertSiblingAfter( + tileLayerZ.target, this.tileLayerZs_[j].target); + break; + } + } + if (j < 0) { + goog.dom.insertChildAt(this.target, tileLayerZ.target, 0); + } + } else { + if (!frameState.viewHints[ol.ViewHint.ANIMATING] && + !frameState.viewHints[ol.ViewHint.INTERACTING]) { + tileLayerZ.removeTilesOutsideExtent(extent, tmpTileRange); + } + } + } + + if (layerState.opacity != this.renderedOpacity_) { + this.target.style.opacity = layerState.opacity; + this.renderedOpacity_ = layerState.opacity; + } + + if (layerState.visible && !this.renderedVisible_) { + goog.style.setElementShown(this.target, true); + this.renderedVisible_ = true; + } + + this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); + this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio, + projection, extent, z, tileLayer.getPreload()); + this.scheduleExpireCache(frameState, tileSource); + this.updateLogos(frameState, tileSource); + + return true; +}; + + + +/** + * @constructor + * @private + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @param {ol.TileCoord} tileCoordOrigin Tile coord origin. + */ +ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) { /** - * @type {ol.webgl.Buffer} - * @private + * @type {!Element} */ - this.indicesBuffer_ = null; + this.target = goog.dom.createElement('DIV'); + this.target.style.position = 'absolute'; + this.target.style.width = '100%'; + this.target.style.height = '100%'; /** * @private - * @type {ol.render.webgl.imagereplay.shader.Default.Locations} + * @type {ol.tilegrid.TileGrid} */ - this.defaultLocations_ = null; + this.tileGrid_ = tileGrid; /** * @private - * @type {number|undefined} + * @type {ol.TileCoord} */ - this.opacity_ = undefined; + this.tileCoordOrigin_ = tileCoordOrigin; /** - * @type {!goog.vec.Mat4.Number} * @private + * @type {ol.Coordinate} */ - this.offsetRotateMatrix_ = goog.vec.Mat4.createNumberIdentity(); + this.origin_ = + ol.extent.getTopLeft(tileGrid.getTileCoordExtent(tileCoordOrigin)); /** - * @type {!goog.vec.Mat4.Number} * @private + * @type {number} */ - this.offsetScaleMatrix_ = goog.vec.Mat4.createNumberIdentity(); + this.resolution_ = tileGrid.getResolution(tileCoordOrigin[0]); /** - * @type {number|undefined} * @private + * @type {Object.<string, ol.Tile>} */ - this.originX_ = undefined; + this.tiles_ = {}; /** - * @type {number|undefined} * @private + * @type {DocumentFragment} */ - this.originY_ = undefined; + this.documentFragment_ = null; /** - * @type {!goog.vec.Mat4.Number} * @private + * @type {goog.vec.Mat4.Number} */ - this.projectionMatrix_ = goog.vec.Mat4.createNumberIdentity(); + this.transform_ = goog.vec.Mat4.createNumberIdentity(); /** * @private - * @type {boolean|undefined} + * @type {ol.Size} */ - this.rotateWithView_ = undefined; + this.tmpSize_ = [0, 0]; + +}; + + +/** + * @param {ol.Tile} tile Tile. + * @param {number} tileGutter Tile gutter. + */ +ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile, tileGutter) { + var tileCoord = tile.tileCoord; + var tileCoordZ = tileCoord[0]; + var tileCoordX = tileCoord[1]; + var tileCoordY = tileCoord[2]; + goog.asserts.assert(tileCoordZ == this.tileCoordOrigin_[0], + 'tileCoordZ matches z of tileCoordOrigin'); + var tileCoordKey = ol.tilecoord.toString(tileCoord); + if (tileCoordKey in this.tiles_) { + return; + } + var tileSize = ol.size.toSize( + this.tileGrid_.getTileSize(tileCoordZ), this.tmpSize_); + var image = tile.getImage(this); + var imageStyle = image.style; + // Bootstrap sets the style max-width: 100% for all images, which + // prevents the tile from being displayed in FireFox. Workaround + // by overriding the max-width style. + imageStyle.maxWidth = 'none'; + var tileElement; + var tileElementStyle; + if (tileGutter > 0) { + tileElement = goog.dom.createElement('DIV'); + tileElementStyle = tileElement.style; + tileElementStyle.overflow = 'hidden'; + tileElementStyle.width = tileSize[0] + 'px'; + tileElementStyle.height = tileSize[1] + 'px'; + imageStyle.position = 'absolute'; + imageStyle.left = -tileGutter + 'px'; + imageStyle.top = -tileGutter + 'px'; + imageStyle.width = (tileSize[0] + 2 * tileGutter) + 'px'; + imageStyle.height = (tileSize[1] + 2 * tileGutter) + 'px'; + tileElement.appendChild(image); + } else { + imageStyle.width = tileSize[0] + 'px'; + imageStyle.height = tileSize[1] + 'px'; + tileElement = image; + tileElementStyle = imageStyle; + } + tileElementStyle.position = 'absolute'; + tileElementStyle.left = + ((tileCoordX - this.tileCoordOrigin_[1]) * tileSize[0]) + 'px'; + tileElementStyle.top = + ((this.tileCoordOrigin_[2] - tileCoordY) * tileSize[1]) + 'px'; + if (!this.documentFragment_) { + this.documentFragment_ = document.createDocumentFragment(); + } + this.documentFragment_.appendChild(tileElement); + this.tiles_[tileCoordKey] = tile; +}; + + +/** + * FIXME empty description for jsdoc + */ +ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() { + if (this.documentFragment_) { + this.target.appendChild(this.documentFragment_); + this.documentFragment_ = null; + } +}; + + +/** + * @return {ol.Coordinate} Origin. + */ +ol.renderer.dom.TileLayerZ_.prototype.getOrigin = function() { + return this.origin_; +}; + + +/** + * @return {number} Resolution. + */ +ol.renderer.dom.TileLayerZ_.prototype.getResolution = function() { + return this.resolution_; +}; + + +/** + * @param {ol.Extent} extent Extent. + * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object. + */ +ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent = + function(extent, opt_tileRange) { + var tileRange = this.tileGrid_.getTileRangeForExtentAndZ( + extent, this.tileCoordOrigin_[0], opt_tileRange); + /** @type {Array.<ol.Tile>} */ + var tilesToRemove = []; + var tile, tileCoordKey; + for (tileCoordKey in this.tiles_) { + tile = this.tiles_[tileCoordKey]; + if (!tileRange.contains(tile.tileCoord)) { + tilesToRemove.push(tile); + } + } + var i, ii; + for (i = 0, ii = tilesToRemove.length; i < ii; ++i) { + tile = tilesToRemove[i]; + tileCoordKey = ol.tilecoord.toString(tile.tileCoord); + goog.dom.removeNode(tile.getImage(this)); + delete this.tiles_[tileCoordKey]; + } +}; + + +/** + * @param {goog.vec.Mat4.Number} transform Transform. + */ +ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) { + if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { + ol.dom.transformElement2D(this.target, transform, 6); + goog.vec.Mat4.setFromArray(this.transform_, transform); + } +}; + +goog.provide('ol.renderer.dom.VectorLayer'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.vec.Mat4'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Vector'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.canvas.Immediate'); +goog.require('ol.render.canvas.ReplayGroup'); +goog.require('ol.renderer.dom.Layer'); +goog.require('ol.renderer.vector'); +goog.require('ol.vec.Mat4'); + + + +/** + * @constructor + * @extends {ol.renderer.dom.Layer} + * @param {ol.layer.Vector} vectorLayer Vector layer. + */ +ol.renderer.dom.VectorLayer = function(vectorLayer) { /** * @private - * @type {number|undefined} + * @type {CanvasRenderingContext2D} */ - this.rotation_ = undefined; + this.context_ = ol.dom.createCanvasContext2D(); + + var target = this.context_.canvas; + // Bootstrap sets the style max-width: 100% for all images, which breaks + // prevents the image from being displayed in FireFox. Workaround by + // overriding the max-width style. + target.style.maxWidth = 'none'; + target.style.position = 'absolute'; + + goog.base(this, vectorLayer, target); /** * @private - * @type {number|undefined} + * @type {boolean} */ - this.scale_ = undefined; + this.dirty_ = false; /** - * @type {Array.<WebGLTexture>} * @private + * @type {number} */ - this.textures_ = []; + this.renderedRevision_ = -1; /** - * @type {Array.<WebGLTexture>} * @private + * @type {number} */ - this.hitDetectionTextures_ = []; + this.renderedResolution_ = NaN; /** - * @type {Array.<number>} * @private + * @type {ol.Extent} */ - this.vertices_ = []; + this.renderedExtent_ = ol.extent.createEmpty(); /** - * @type {ol.webgl.Buffer} * @private + * @type {function(ol.Feature, ol.Feature): number|null} */ - this.verticesBuffer_ = null; + this.renderedRenderOrder_ = null; /** - * Start index per feature (the index). - * @type {Array.<number>} * @private + * @type {ol.render.canvas.ReplayGroup} */ - this.startIndices_ = []; + this.replayGroup_ = null; /** - * Start index per feature (the feature). - * @type {Array.<ol.Feature>} * @private + * @type {goog.vec.Mat4.Number} */ - this.startIndicesFeature_ = []; + this.transform_ = goog.vec.Mat4.createNumber(); /** - * @type {number|undefined} * @private + * @type {goog.vec.Mat4.Number} */ - this.width_ = undefined; -}; -goog.inherits(ol.render.webgl.ImageReplay, ol.render.VectorContext); - + this.elementTransform_ = goog.vec.Mat4.createNumber(); -/** - * @param {ol.webgl.Context} context WebGL context. - * @return {function()} Delete resources function. - */ -ol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction = - function(context) { - // We only delete our stuff here. The shaders and the program may - // be used by other ImageReplay instances (for other layers). And - // they will be deleted when disposing of the ol.webgl.Context - // object. - goog.asserts.assert(this.verticesBuffer_, - 'verticesBuffer must not be null'); - goog.asserts.assert(this.indicesBuffer_, - 'indicesBuffer must not be null'); - var verticesBuffer = this.verticesBuffer_; - var indicesBuffer = this.indicesBuffer_; - var textures = this.textures_; - var hitDetectionTextures = this.hitDetectionTextures_; - var gl = context.getGL(); - return function() { - if (!gl.isContextLost()) { - var i, ii; - for (i = 0, ii = textures.length; i < ii; ++i) { - gl.deleteTexture(textures[i]); - } - for (i = 0, ii = hitDetectionTextures.length; i < ii; ++i) { - gl.deleteTexture(hitDetectionTextures[i]); - } - } - context.deleteBuffer(verticesBuffer); - context.deleteBuffer(indicesBuffer); - }; }; +goog.inherits(ol.renderer.dom.VectorLayer, ol.renderer.dom.Layer); /** * @inheritDoc */ -ol.render.webgl.ImageReplay.prototype.drawAsync = goog.abstractMethod; +ol.renderer.dom.VectorLayer.prototype.composeFrame = + function(frameState, layerState) { + var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); + goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, + 'layer is an instance of ol.layer.Vector'); -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} My end. - * @private - */ -ol.render.webgl.ImageReplay.prototype.drawCoordinates_ = - function(flatCoordinates, offset, end, stride) { - goog.asserts.assert(this.anchorX_ !== undefined, 'anchorX is defined'); - goog.asserts.assert(this.anchorY_ !== undefined, 'anchorY is defined'); - goog.asserts.assert(this.height_ !== undefined, 'height is defined'); - goog.asserts.assert(this.imageHeight_ !== undefined, - 'imageHeight is defined'); - goog.asserts.assert(this.imageWidth_ !== undefined, 'imageWidth is defined'); - goog.asserts.assert(this.opacity_ !== undefined, 'opacity is defined'); - goog.asserts.assert(this.originX_ !== undefined, 'originX is defined'); - goog.asserts.assert(this.originY_ !== undefined, 'originY is defined'); - goog.asserts.assert(this.rotateWithView_ !== undefined, - 'rotateWithView is defined'); - goog.asserts.assert(this.rotation_ !== undefined, 'rotation is defined'); - goog.asserts.assert(this.scale_ !== undefined, 'scale is defined'); - goog.asserts.assert(this.width_ !== undefined, 'width is defined'); - var anchorX = this.anchorX_; - var anchorY = this.anchorY_; - var height = this.height_; - var imageHeight = this.imageHeight_; - var imageWidth = this.imageWidth_; - var opacity = this.opacity_; - var originX = this.originX_; - var originY = this.originY_; - var rotateWithView = this.rotateWithView_ ? 1.0 : 0.0; - var rotation = this.rotation_; - var scale = this.scale_; - var width = this.width_; - var cos = Math.cos(rotation); - var sin = Math.sin(rotation); - var numIndices = this.indices_.length; - var numVertices = this.vertices_.length; - var i, n, offsetX, offsetY, x, y; - for (i = offset; i < end; i += stride) { - x = flatCoordinates[i] - this.origin_[0]; - y = flatCoordinates[i + 1] - this.origin_[1]; + var viewState = frameState.viewState; + var viewCenter = viewState.center; + var viewRotation = viewState.rotation; + var viewResolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var viewWidth = frameState.size[0]; + var viewHeight = frameState.size[1]; + var imageWidth = viewWidth * pixelRatio; + var imageHeight = viewHeight * pixelRatio; - // There are 4 vertices per [x, y] point, one for each corner of the - // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if - // WebGL supported Geometry Shaders (which can emit new vertices), but that - // is not currently the case. - // - // And each vertex includes 8 values: the x and y coordinates, the x and - // y offsets used to calculate the position of the corner, the u and - // v texture coordinates for the corner, the opacity, and whether the - // the image should be rotated with the view (rotateWithView). + var transform = ol.vec.Mat4.makeTransform2D(this.transform_, + pixelRatio * viewWidth / 2, + pixelRatio * viewHeight / 2, + pixelRatio / viewResolution, + -pixelRatio / viewResolution, + -viewRotation, + -viewCenter[0], -viewCenter[1]); - n = numVertices / 8; + var context = this.context_; - // bottom-left corner - offsetX = -scale * anchorX; - offsetY = -scale * (height - anchorY); - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = originX / imageWidth; - this.vertices_[numVertices++] = (originY + height) / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; + // Clear the canvas and set the correct size + context.canvas.width = imageWidth; + context.canvas.height = imageHeight; - // bottom-right corner - offsetX = scale * (width - anchorX); - offsetY = -scale * (height - anchorY); - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = (originX + width) / imageWidth; - this.vertices_[numVertices++] = (originY + height) / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; + var elementTransform = ol.vec.Mat4.makeTransform2D(this.elementTransform_, + 0, 0, + 1 / pixelRatio, 1 / pixelRatio, + 0, + -(imageWidth - viewWidth) / 2 * pixelRatio, + -(imageHeight - viewHeight) / 2 * pixelRatio); + ol.dom.transformElement2D(context.canvas, elementTransform, 6); - // top-right corner - offsetX = scale * (width - anchorX); - offsetY = scale * anchorY; - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = (originX + width) / imageWidth; - this.vertices_[numVertices++] = originY / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; + this.dispatchEvent_(ol.render.EventType.PRECOMPOSE, frameState, transform); - // top-left corner - offsetX = -scale * anchorX; - offsetY = scale * anchorY; - this.vertices_[numVertices++] = x; - this.vertices_[numVertices++] = y; - this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; - this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; - this.vertices_[numVertices++] = originX / imageWidth; - this.vertices_[numVertices++] = originY / imageHeight; - this.vertices_[numVertices++] = opacity; - this.vertices_[numVertices++] = rotateWithView; + var replayGroup = this.replayGroup_; - this.indices_[numIndices++] = n; - this.indices_[numIndices++] = n + 1; - this.indices_[numIndices++] = n + 2; - this.indices_[numIndices++] = n; - this.indices_[numIndices++] = n + 2; - this.indices_[numIndices++] = n + 3; + if (replayGroup && !replayGroup.isEmpty()) { + + context.globalAlpha = layerState.opacity; + replayGroup.replay(context, pixelRatio, transform, viewRotation, + layerState.managed ? frameState.skippedFeatureUids : {}); + + this.dispatchEvent_(ol.render.EventType.RENDER, frameState, transform); } - return numVertices; + this.dispatchEvent_(ol.render.EventType.POSTCOMPOSE, frameState, transform); }; /** - * @inheritDoc + * @param {ol.render.EventType} type Event type. + * @param {olx.FrameState} frameState Frame state. + * @param {goog.vec.Mat4.Number} transform Transform. + * @private */ -ol.render.webgl.ImageReplay.prototype.drawMultiPointGeometry = - function(multiPointGeometry, feature) { - this.startIndices_.push(this.indices_.length); - this.startIndicesFeature_.push(feature); - var flatCoordinates = multiPointGeometry.getFlatCoordinates(); - var stride = multiPointGeometry.getStride(); - this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); +ol.renderer.dom.VectorLayer.prototype.dispatchEvent_ = + function(type, frameState, transform) { + var context = this.context_; + var layer = this.getLayer(); + if (layer.hasListener(type)) { + var render = new ol.render.canvas.Immediate( + context, frameState.pixelRatio, frameState.extent, transform, + frameState.viewState.rotation); + var event = new ol.render.Event(type, layer, render, frameState, + context, null); + layer.dispatchEvent(event); + render.flush(); + } }; /** * @inheritDoc */ -ol.render.webgl.ImageReplay.prototype.drawPointGeometry = - function(pointGeometry, feature) { - this.startIndices_.push(this.indices_.length); - this.startIndicesFeature_.push(feature); - var flatCoordinates = pointGeometry.getFlatCoordinates(); - var stride = pointGeometry.getStride(); - this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); +ol.renderer.dom.VectorLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + if (!this.replayGroup_) { + return undefined; + } else { + var resolution = frameState.viewState.resolution; + var rotation = frameState.viewState.rotation; + var layer = this.getLayer(); + var layerState = frameState.layerStates[goog.getUid(layer)]; + /** @type {Object.<string, boolean>} */ + var features = {}; + return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, + rotation, layerState.managed ? frameState.skippedFeatureUids : {}, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + goog.asserts.assert(feature !== undefined, 'received a feature'); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback.call(thisArg, feature, layer); + } + }); + } }; /** - * @param {ol.webgl.Context} context Context. + * Handle changes in image style state. + * @param {goog.events.Event} event Image style change event. + * @private */ -ol.render.webgl.ImageReplay.prototype.finish = function(context) { - var gl = context.getGL(); +ol.renderer.dom.VectorLayer.prototype.handleStyleImageChange_ = + function(event) { + this.renderIfReadyAndVisible(); +}; - this.groupIndices_.push(this.indices_.length); - goog.asserts.assert(this.images_.length === this.groupIndices_.length, - 'number of images and groupIndices match'); - this.hitDetectionGroupIndices_.push(this.indices_.length); - goog.asserts.assert(this.hitDetectionImages_.length === - this.hitDetectionGroupIndices_.length, - 'number of hitDetectionImages and hitDetectionGroupIndices match'); - // create, bind, and populate the vertices buffer - this.verticesBuffer_ = new ol.webgl.Buffer(this.vertices_); - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); +/** + * @inheritDoc + */ +ol.renderer.dom.VectorLayer.prototype.prepareFrame = + function(frameState, layerState) { - var indices = this.indices_; - var bits = context.hasOESElementIndexUint ? 32 : 16; - goog.asserts.assert(indices[indices.length - 1] < Math.pow(2, bits), - 'Too large element index detected [%s] (OES_element_index_uint "%s")', - indices[indices.length - 1], context.hasOESElementIndexUint); + var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); + goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, + 'layer is an instance of ol.layer.Vector'); + var vectorSource = vectorLayer.getSource(); - // create, bind, and populate the indices buffer - this.indicesBuffer_ = new ol.webgl.Buffer(indices); - context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); + this.updateAttributions( + frameState.attributions, vectorSource.getAttributions()); + this.updateLogos(frameState, vectorSource); - // create textures - /** @type {Object.<string, WebGLTexture>} */ - var texturePerImage = {}; + var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; + var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; + var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); + var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); - this.createTextures_(this.textures_, this.images_, texturePerImage, gl); - goog.asserts.assert(this.textures_.length === this.groupIndices_.length, - 'number of textures and groupIndices match'); + if (!this.dirty_ && (!updateWhileAnimating && animating) || + (!updateWhileInteracting && interacting)) { + return true; + } - this.createTextures_(this.hitDetectionTextures_, this.hitDetectionImages_, - texturePerImage, gl); - goog.asserts.assert(this.hitDetectionTextures_.length === - this.hitDetectionGroupIndices_.length, - 'number of hitDetectionTextures and hitDetectionGroupIndices match'); + var frameStateExtent = frameState.extent; + var viewState = frameState.viewState; + var projection = viewState.projection; + var resolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var vectorLayerRevision = vectorLayer.getRevision(); + var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); + var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); - this.anchorX_ = undefined; - this.anchorY_ = undefined; - this.height_ = undefined; - this.images_ = null; - this.hitDetectionImages_ = null; - this.imageHeight_ = undefined; - this.imageWidth_ = undefined; - this.indices_ = null; - this.opacity_ = undefined; - this.originX_ = undefined; - this.originY_ = undefined; - this.rotateWithView_ = undefined; - this.rotation_ = undefined; - this.scale_ = undefined; - this.vertices_ = null; - this.width_ = undefined; -}; + if (vectorLayerRenderOrder === undefined) { + vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; + } + var extent = ol.extent.buffer(frameStateExtent, + vectorLayerRenderBuffer * resolution); -/** - * @private - * @param {Array.<WebGLTexture>} textures Textures. - * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images - * Images. - * @param {Object.<string, WebGLTexture>} texturePerImage Texture cache. - * @param {WebGLRenderingContext} gl Gl. - */ -ol.render.webgl.ImageReplay.prototype.createTextures_ = - function(textures, images, texturePerImage, gl) { - goog.asserts.assert(textures.length === 0, - 'upon creation, textures is empty'); + if (!this.dirty_ && + this.renderedResolution_ == resolution && + this.renderedRevision_ == vectorLayerRevision && + this.renderedRenderOrder_ == vectorLayerRenderOrder && + ol.extent.containsExtent(this.renderedExtent_, extent)) { + return true; + } - var texture, image, uid, i; - var ii = images.length; - for (i = 0; i < ii; ++i) { - image = images[i]; + // FIXME dispose of old replayGroup in post render + goog.dispose(this.replayGroup_); + this.replayGroup_ = null; - uid = goog.getUid(image).toString(); - if (goog.object.containsKey(texturePerImage, uid)) { - texture = texturePerImage[uid]; + this.dirty_ = false; + + var replayGroup = + new ol.render.canvas.ReplayGroup( + ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, + resolution, vectorLayer.getRenderBuffer()); + vectorSource.loadFeatures(extent, resolution, projection); + var renderFeature = + /** + * @param {ol.Feature} feature Feature. + * @this {ol.renderer.dom.VectorLayer} + */ + function(feature) { + var styles; + var styleFunction = feature.getStyleFunction(); + if (styleFunction) { + styles = styleFunction.call(feature, resolution); } else { - texture = ol.webgl.Context.createTexture( - gl, image, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); - texturePerImage[uid] = texture; + styleFunction = vectorLayer.getStyleFunction(); + if (styleFunction) { + styles = styleFunction(feature, resolution); + } } - textures[i] = texture; + if (styles) { + var dirty = this.renderFeature( + feature, resolution, pixelRatio, styles, replayGroup); + this.dirty_ = this.dirty_ || dirty; + } + }; + if (vectorLayerRenderOrder) { + /** @type {Array.<ol.Feature>} */ + var features = []; + vectorSource.forEachFeatureInExtent(extent, + /** + * @param {ol.Feature} feature Feature. + */ + function(feature) { + features.push(feature); + }, this); + goog.array.sort(features, vectorLayerRenderOrder); + features.forEach(renderFeature, this); + } else { + vectorSource.forEachFeatureInExtent(extent, renderFeature, this); } + replayGroup.finish(); + + this.renderedResolution_ = resolution; + this.renderedRevision_ = vectorLayerRevision; + this.renderedRenderOrder_ = vectorLayerRenderOrder; + this.renderedExtent_ = extent; + this.replayGroup_ = replayGroup; + + return true; }; /** - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. + * @param {ol.Feature} feature Feature. * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T + * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of + * styles. + * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. + * @return {boolean} `true` if an image is loading. */ -ol.render.webgl.ImageReplay.prototype.replay = function(context, - center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash, - featureCallback, oneByOne, opt_hitExtent) { - var gl = context.getGL(); - - // bind the vertices buffer - goog.asserts.assert(this.verticesBuffer_, - 'verticesBuffer must not be null'); - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); - - // bind the indices buffer - goog.asserts.assert(this.indicesBuffer_, - 'indecesBuffer must not be null'); - context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); - - // get the program - var fragmentShader = - ol.render.webgl.imagereplay.shader.DefaultFragment.getInstance(); - var vertexShader = - ol.render.webgl.imagereplay.shader.DefaultVertex.getInstance(); - var program = context.getProgram(fragmentShader, vertexShader); - - // get the locations - var locations; - if (!this.defaultLocations_) { - locations = - new ol.render.webgl.imagereplay.shader.Default.Locations(gl, program); - this.defaultLocations_ = locations; +ol.renderer.dom.VectorLayer.prototype.renderFeature = + function(feature, resolution, pixelRatio, styles, replayGroup) { + if (!styles) { + return false; + } + var loading = false; + if (goog.isArray(styles)) { + for (var i = 0, ii = styles.length; i < ii; ++i) { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles[i], + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleStyleImageChange_, this) || loading; + } } else { - locations = this.defaultLocations_; + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles, + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleStyleImageChange_, this) || loading; } + return loading; +}; - // use the program (FIXME: use the return value) - context.useProgram(program); - - // enable the vertex attrib arrays - gl.enableVertexAttribArray(locations.a_position); - gl.vertexAttribPointer(locations.a_position, 2, goog.webgl.FLOAT, - false, 32, 0); +goog.provide('ol.renderer.dom.Map'); - gl.enableVertexAttribArray(locations.a_offsets); - gl.vertexAttribPointer(locations.a_offsets, 2, goog.webgl.FLOAT, - false, 32, 8); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.style'); +goog.require('goog.vec.Mat4'); +goog.require('ol'); +goog.require('ol.RendererType'); +goog.require('ol.css'); +goog.require('ol.dom'); +goog.require('ol.layer.Image'); +goog.require('ol.layer.Layer'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.canvas.Immediate'); +goog.require('ol.renderer.Map'); +goog.require('ol.renderer.dom.ImageLayer'); +goog.require('ol.renderer.dom.Layer'); +goog.require('ol.renderer.dom.TileLayer'); +goog.require('ol.renderer.dom.VectorLayer'); +goog.require('ol.source.State'); +goog.require('ol.vec.Mat4'); - gl.enableVertexAttribArray(locations.a_texCoord); - gl.vertexAttribPointer(locations.a_texCoord, 2, goog.webgl.FLOAT, - false, 32, 16); - gl.enableVertexAttribArray(locations.a_opacity); - gl.vertexAttribPointer(locations.a_opacity, 1, goog.webgl.FLOAT, - false, 32, 24); - gl.enableVertexAttribArray(locations.a_rotateWithView); - gl.vertexAttribPointer(locations.a_rotateWithView, 1, goog.webgl.FLOAT, - false, 32, 28); +/** + * @constructor + * @extends {ol.renderer.Map} + * @param {Element} container Container. + * @param {ol.Map} map Map. + */ +ol.renderer.dom.Map = function(container, map) { - // set the "uniform" values - var projectionMatrix = this.projectionMatrix_; - ol.vec.Mat4.makeTransform2D(projectionMatrix, - 0.0, 0.0, - 2 / (resolution * size[0]), - 2 / (resolution * size[1]), - -rotation, - -(center[0] - this.origin_[0]), -(center[1] - this.origin_[1])); + goog.base(this, container, map); - var offsetScaleMatrix = this.offsetScaleMatrix_; - goog.vec.Mat4.makeScale(offsetScaleMatrix, 2 / size[0], 2 / size[1], 1); + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = ol.dom.createCanvasContext2D(); + var canvas = this.context_.canvas; + canvas.style.position = 'absolute'; + canvas.style.width = '100%'; + canvas.style.height = '100%'; + canvas.className = ol.css.CLASS_UNSELECTABLE; + goog.dom.insertChildAt(container, canvas, 0); - var offsetRotateMatrix = this.offsetRotateMatrix_; - goog.vec.Mat4.makeIdentity(offsetRotateMatrix); - if (rotation !== 0) { - goog.vec.Mat4.rotateZ(offsetRotateMatrix, -rotation); - } + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.transform_ = goog.vec.Mat4.createNumber(); - gl.uniformMatrix4fv(locations.u_projectionMatrix, false, projectionMatrix); - gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false, offsetScaleMatrix); - gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false, - offsetRotateMatrix); - gl.uniform1f(locations.u_opacity, opacity); + /** + * @type {!Element} + * @private + */ + this.layersPane_ = goog.dom.createElement('DIV'); + this.layersPane_.className = ol.css.CLASS_UNSELECTABLE; + var style = this.layersPane_.style; + style.position = 'absolute'; + style.width = '100%'; + style.height = '100%'; - // draw! - var result; - if (featureCallback === undefined) { - this.drawReplay_(gl, context, skippedFeaturesHash, - this.textures_, this.groupIndices_); - } else { - // draw feature by feature for the hit-detection - result = this.drawHitDetectionReplay_(gl, context, skippedFeaturesHash, - featureCallback, oneByOne, opt_hitExtent); - } + // prevent the img context menu on mobile devices + goog.events.listen(this.layersPane_, goog.events.EventType.TOUCHSTART, + goog.events.Event.preventDefault); - // disable the vertex attrib arrays - gl.disableVertexAttribArray(locations.a_position); - gl.disableVertexAttribArray(locations.a_offsets); - gl.disableVertexAttribArray(locations.a_texCoord); - gl.disableVertexAttribArray(locations.a_opacity); - gl.disableVertexAttribArray(locations.a_rotateWithView); + goog.dom.insertChildAt(container, this.layersPane_, 0); + + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = true; - return result; }; +goog.inherits(ol.renderer.dom.Map, ol.renderer.Map); /** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.<WebGLTexture>} textures Textures. - * @param {Array.<number>} groupIndices Texture group indices. + * @inheritDoc */ -ol.render.webgl.ImageReplay.prototype.drawReplay_ = - function(gl, context, skippedFeaturesHash, textures, groupIndices) { - goog.asserts.assert(textures.length === groupIndices.length, - 'number of textures and groupIndeces match'); - var elementType = context.hasOESElementIndexUint ? - goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; - var elementSize = context.hasOESElementIndexUint ? 4 : 2; - - if (!goog.object.isEmpty(skippedFeaturesHash)) { - this.drawReplaySkipping_( - gl, skippedFeaturesHash, textures, groupIndices, - elementType, elementSize); - } else { - var i, ii, start; - for (i = 0, ii = textures.length, start = 0; i < ii; ++i) { - gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]); - var end = groupIndices[i]; - this.drawElements_(gl, start, end, elementType, elementSize); - start = end; - } - } +ol.renderer.dom.Map.prototype.disposeInternal = function() { + goog.dom.removeNode(this.layersPane_); + goog.base(this, 'disposeInternal'); }; /** - * Draw the replay while paying attention to skipped features. - * - * This functions creates groups of features that can be drawn to together, - * so that the number of `drawElements` calls is minimized. - * - * For example given the following texture groups: - * - * Group 1: A B C - * Group 2: D [E] F G - * - * If feature E should be skipped, the following `drawElements` calls will be - * made: - * - * drawElements with feature A, B and C - * drawElements with feature D - * drawElements with feature F and G - * - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {Array.<WebGLTexture>} textures Textures. - * @param {Array.<number>} groupIndices Texture group indices. - * @param {number} elementType Element type. - * @param {number} elementSize Element Size. + * @inheritDoc */ -ol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ = - function(gl, skippedFeaturesHash, textures, groupIndices, - elementType, elementSize) { - var featureIndex = 0; - - var i, ii; - for (i = 0, ii = textures.length; i < ii; ++i) { - gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]); - var groupStart = (i > 0) ? groupIndices[i - 1] : 0; - var groupEnd = groupIndices[i]; - - var start = groupStart; - var end = groupStart; - while (featureIndex < this.startIndices_.length && - this.startIndices_[featureIndex] <= groupEnd) { - var feature = this.startIndicesFeature_[featureIndex]; - - var featureUid = goog.getUid(feature).toString(); - if (skippedFeaturesHash[featureUid] !== undefined) { - // feature should be skipped - if (start !== end) { - // draw the features so far - this.drawElements_(gl, start, end, elementType, elementSize); - } - // continue with the next feature - start = (featureIndex === this.startIndices_.length - 1) ? - groupEnd : this.startIndices_[featureIndex + 1]; - end = start; - } else { - // the feature is not skipped, augment the end index - end = (featureIndex === this.startIndices_.length - 1) ? - groupEnd : this.startIndices_[featureIndex + 1]; - } - featureIndex++; - } - - if (start !== end) { - // draw the remaining features (in case there was no skipped feature - // in this texture group, all features of a group are drawn together) - this.drawElements_(gl, start, end, elementType, elementSize); - } +ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { + var layerRenderer; + if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { + layerRenderer = new ol.renderer.dom.ImageLayer(layer); + } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { + layerRenderer = new ol.renderer.dom.TileLayer(layer); + } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { + layerRenderer = new ol.renderer.dom.VectorLayer(layer); + } else { + goog.asserts.fail('unexpected layer configuration'); + return null; } + return layerRenderer; }; /** + * @param {ol.render.EventType} type Event type. + * @param {olx.FrameState} frameState Frame state. * @private - * @param {WebGLRenderingContext} gl gl. - * @param {number} start Start index. - * @param {number} end End index. - * @param {number} elementType Element type. - * @param {number} elementSize Element Size. */ -ol.render.webgl.ImageReplay.prototype.drawElements_ = function( - gl, start, end, elementType, elementSize) { - var numItems = end - start; - var offsetInBytes = start * elementSize; - gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes); -}; - +ol.renderer.dom.Map.prototype.dispatchComposeEvent_ = + function(type, frameState) { + var map = this.getMap(); + if (map.hasListener(type)) { + var extent = frameState.extent; + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var rotation = viewState.rotation; + var context = this.context_; + var canvas = context.canvas; -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T - */ -ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplay_ = - function(gl, context, skippedFeaturesHash, featureCallback, oneByOne, - opt_hitExtent) { - if (!oneByOne) { - // draw all hit-detection features in "once" (by texture group) - return this.drawHitDetectionReplayAll_(gl, context, - skippedFeaturesHash, featureCallback); - } else { - // draw hit-detection features one by one - return this.drawHitDetectionReplayOneByOne_(gl, context, - skippedFeaturesHash, featureCallback, opt_hitExtent); + ol.vec.Mat4.makeTransform2D(this.transform_, + canvas.width / 2, + canvas.height / 2, + pixelRatio / viewState.resolution, + -pixelRatio / viewState.resolution, + -viewState.rotation, + -viewState.center[0], -viewState.center[1]); + var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio, + extent, this.transform_, rotation); + var composeEvent = new ol.render.Event(type, map, vectorContext, + frameState, context, null); + map.dispatchEvent(composeEvent); + vectorContext.flush(); } }; /** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @return {T|undefined} Callback result. - * @template T + * @inheritDoc */ -ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayAll_ = - function(gl, context, skippedFeaturesHash, featureCallback) { - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - this.drawReplay_(gl, context, skippedFeaturesHash, - this.hitDetectionTextures_, this.hitDetectionGroupIndices_); - - var result = featureCallback(null); - if (result) { - return result; - } else { - return undefined; - } +ol.renderer.dom.Map.prototype.getType = function() { + return ol.RendererType.DOM; }; /** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {ol.webgl.Context} context Context. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T + * @inheritDoc */ -ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne_ = - function(gl, context, skippedFeaturesHash, featureCallback, - opt_hitExtent) { - goog.asserts.assert(this.hitDetectionTextures_.length === - this.hitDetectionGroupIndices_.length, - 'number of hitDetectionTextures and hitDetectionGroupIndices match'); - var elementType = context.hasOESElementIndexUint ? - goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; - var elementSize = context.hasOESElementIndexUint ? 4 : 2; - - var i, groupStart, start, end, feature, featureUid; - var featureIndex = this.startIndices_.length - 1; - for (i = this.hitDetectionTextures_.length - 1; i >= 0; --i) { - gl.bindTexture(goog.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]); - groupStart = (i > 0) ? this.hitDetectionGroupIndices_[i - 1] : 0; - end = this.hitDetectionGroupIndices_[i]; - - // draw all features for this texture group - while (featureIndex >= 0 && - this.startIndices_[featureIndex] >= groupStart) { - start = this.startIndices_[featureIndex]; - feature = this.startIndicesFeature_[featureIndex]; - featureUid = goog.getUid(feature).toString(); - - if (skippedFeaturesHash[featureUid] === undefined && - feature.getGeometry() && - (opt_hitExtent === undefined || ol.extent.intersects( - /** @type {Array<number>} */ (opt_hitExtent), - feature.getGeometry().getExtent()))) { - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - this.drawElements_(gl, start, end, elementType, elementSize); - - var result = featureCallback(feature); - if (result) { - return result; - } - } +ol.renderer.dom.Map.prototype.renderFrame = function(frameState) { - end = start; - featureIndex--; + if (!frameState) { + if (this.renderedVisible_) { + goog.style.setElementShown(this.layersPane_, false); + this.renderedVisible_ = false; } + return; } - return undefined; -}; - -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.setFillStrokeStyle = goog.abstractMethod; + var map = this.getMap(); + if (map.hasListener(ol.render.EventType.PRECOMPOSE) || + map.hasListener(ol.render.EventType.POSTCOMPOSE)) { + var canvas = this.context_.canvas; + var pixelRatio = frameState.pixelRatio; + canvas.width = frameState.size[0] * pixelRatio; + canvas.height = frameState.size[1] * pixelRatio; + } + this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); -/** - * @inheritDoc - */ -ol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) { - var anchor = imageStyle.getAnchor(); - var image = imageStyle.getImage(1); - var imageSize = imageStyle.getImageSize(); - var hitDetectionImage = imageStyle.getHitDetectionImage(1); - var hitDetectionImageSize = imageStyle.getHitDetectionImageSize(); - var opacity = imageStyle.getOpacity(); - var origin = imageStyle.getOrigin(); - var rotateWithView = imageStyle.getRotateWithView(); - var rotation = imageStyle.getRotation(); - var size = imageStyle.getSize(); - var scale = imageStyle.getScale(); - goog.asserts.assert(anchor, 'imageStyle anchor is not null'); - goog.asserts.assert(image, 'imageStyle image is not null'); - goog.asserts.assert(imageSize, - 'imageStyle imageSize is not null'); - goog.asserts.assert(hitDetectionImage, - 'imageStyle hitDetectionImage is not null'); - goog.asserts.assert(hitDetectionImageSize, - 'imageStyle hitDetectionImageSize is not null'); - goog.asserts.assert(opacity !== undefined, 'imageStyle opacity is defined'); - goog.asserts.assert(origin, 'imageStyle origin is not null'); - goog.asserts.assert(rotateWithView !== undefined, - 'imageStyle rotateWithView is defined'); - goog.asserts.assert(rotation !== undefined, 'imageStyle rotation is defined'); - goog.asserts.assert(size, 'imageStyle size is not null'); - goog.asserts.assert(scale !== undefined, 'imageStyle scale is defined'); + var layerStatesArray = frameState.layerStatesArray; + goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - var currentImage; - if (this.images_.length === 0) { - this.images_.push(image); - } else { - currentImage = this.images_[this.images_.length - 1]; - if (goog.getUid(currentImage) != goog.getUid(image)) { - this.groupIndices_.push(this.indices_.length); - goog.asserts.assert(this.groupIndices_.length === this.images_.length, - 'number of groupIndices and images match'); - this.images_.push(image); + var viewResolution = frameState.viewState.resolution; + var i, ii, layer, layerRenderer, layerState; + for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { + layerState = layerStatesArray[i]; + layer = layerState.layer; + layerRenderer = /** @type {ol.renderer.dom.Layer} */ ( + this.getLayerRenderer(layer)); + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer, + 'renderer is an instance of ol.renderer.dom.Layer'); + goog.dom.insertChildAt(this.layersPane_, layerRenderer.getTarget(), i); + if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && + layerState.sourceState == ol.source.State.READY) { + if (layerRenderer.prepareFrame(frameState, layerState)) { + layerRenderer.composeFrame(frameState, layerState); + } + } else { + layerRenderer.clearFrame(); } } - if (this.hitDetectionImages_.length === 0) { - this.hitDetectionImages_.push(hitDetectionImage); - } else { - currentImage = - this.hitDetectionImages_[this.hitDetectionImages_.length - 1]; - if (goog.getUid(currentImage) != goog.getUid(hitDetectionImage)) { - this.hitDetectionGroupIndices_.push(this.indices_.length); - goog.asserts.assert(this.hitDetectionGroupIndices_.length === - this.hitDetectionImages_.length, - 'number of hitDetectionGroupIndices and hitDetectionImages match'); - this.hitDetectionImages_.push(hitDetectionImage); + var layerStates = frameState.layerStates; + var layerKey; + for (layerKey in this.getLayerRenderers()) { + if (!(layerKey in layerStates)) { + layerRenderer = this.getLayerRendererByKey(layerKey); + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer, + 'renderer is an instance of ol.renderer.dom.Layer'); + goog.dom.removeNode(layerRenderer.getTarget()); } } - this.anchorX_ = anchor[0]; - this.anchorY_ = anchor[1]; - this.height_ = size[1]; - this.imageHeight_ = imageSize[1]; - this.imageWidth_ = imageSize[0]; - this.opacity_ = opacity; - this.originX_ = origin[0]; - this.originY_ = origin[1]; - this.rotation_ = rotation; - this.rotateWithView_ = rotateWithView; - this.scale_ = scale; - this.width_ = size[0]; + if (!this.renderedVisible_) { + goog.style.setElementShown(this.layersPane_, true); + this.renderedVisible_ = true; + } + + this.calculateMatrices2D(frameState); + this.scheduleRemoveUnusedLayerRenderers(frameState); + this.scheduleExpireIconCache(frameState); + + this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState); }; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * @constructor - * @implements {ol.render.IReplayGroup} - * @param {number} tolerance Tolerance. - * @param {ol.Extent} maxExtent Max extent. - * @param {number=} opt_renderBuffer Render buffer. - * @struct + * @fileoverview Constants used by the WebGL rendering, including all of the + * constants used from the WebGL context. For example, instead of using + * context.ARRAY_BUFFER, your code can use + * goog.webgl.ARRAY_BUFFER. The benefits for doing this include allowing + * the compiler to optimize your code so that the compiled code does not have to + * contain large strings to reference these properties, and reducing runtime + * property access. + * + * Values are taken from the WebGL Spec: + * https://www.khronos.org/registry/webgl/specs/1.0/#WEBGLRENDERINGCONTEXT */ -ol.render.webgl.ReplayGroup = function( - tolerance, maxExtent, opt_renderBuffer) { - - /** - * @type {ol.Extent} - * @private - */ - this.maxExtent_ = maxExtent; - - /** - * @type {number} - * @private - */ - this.tolerance_ = tolerance; - /** - * @type {number|undefined} - * @private - */ - this.renderBuffer_ = opt_renderBuffer; +goog.provide('goog.webgl'); - /** - * ImageReplay only is supported at this point. - * @type {Object.<ol.render.ReplayType, ol.render.webgl.ImageReplay>} - * @private - */ - this.replays_ = {}; -}; +/** + * @const + * @type {number} + */ +goog.webgl.DEPTH_BUFFER_BIT = 0x00000100; /** - * @param {ol.webgl.Context} context WebGL context. - * @return {function()} Delete resources function. + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = - function(context) { - var functions = []; - var replayKey; - for (replayKey in this.replays_) { - functions.push( - this.replays_[replayKey].getDeleteResourcesFunction(context)); - } - return goog.functions.sequence.apply(null, functions); -}; +goog.webgl.STENCIL_BUFFER_BIT = 0x00000400; /** - * @param {ol.webgl.Context} context Context. + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.finish = function(context) { - var replayKey; - for (replayKey in this.replays_) { - this.replays_[replayKey].finish(context); - } -}; +goog.webgl.COLOR_BUFFER_BIT = 0x00004000; /** - * @inheritDoc + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.getReplay = - function(zIndex, replayType) { - var replay = this.replays_[replayType]; - if (replay === undefined) { - var constructor = ol.render.webgl.BATCH_CONSTRUCTORS_[replayType]; - goog.asserts.assert(constructor !== undefined, - replayType + - ' constructor missing from ol.render.webgl.BATCH_CONSTRUCTORS_'); - replay = new constructor(this.tolerance_, this.maxExtent_); - this.replays_[replayType] = replay; - } - return replay; -}; +goog.webgl.POINTS = 0x0000; /** - * @inheritDoc + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.isEmpty = function() { - return goog.object.isEmpty(this.replays_); -}; +goog.webgl.LINES = 0x0001; /** - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.replay = function(context, - center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash) { - var i, ii, replay; - for (i = 0, ii = ol.render.REPLAY_ORDER.length; i < ii; ++i) { - replay = this.replays_[ol.render.REPLAY_ORDER[i]]; - if (replay !== undefined) { - replay.replay(context, - center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash, - undefined, false); - } - } -}; +goog.webgl.LINE_LOOP = 0x0002; /** - * @private - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. - * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. - * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting - * this extent are checked. - * @return {T|undefined} Callback result. - * @template T + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context, - center, resolution, rotation, size, pixelRatio, opacity, - skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) { - var i, replay, result; - for (i = ol.render.REPLAY_ORDER.length - 1; i >= 0; --i) { - replay = this.replays_[ol.render.REPLAY_ORDER[i]]; - if (replay !== undefined) { - result = replay.replay(context, - center, resolution, rotation, size, pixelRatio, opacity, - skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent); - if (result) { - return result; - } - } - } - return undefined; -}; +goog.webgl.LINE_STRIP = 0x0003; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @param {function(ol.Feature): T|undefined} callback Feature callback. - * @return {T|undefined} Callback result. - * @template T + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( - coordinate, context, center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash, - callback) { - var gl = context.getGL(); - gl.bindFramebuffer( - gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); - - - /** - * @type {ol.Extent} - */ - var hitExtent; - if (this.renderBuffer_ !== undefined) { - // build an extent around the coordinate, so that only features that - // intersect this extent are checked - hitExtent = ol.extent.buffer( - ol.extent.createOrUpdateFromCoordinate(coordinate), - resolution * this.renderBuffer_); - } - - return this.replayHitDetection_(context, - coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_, - pixelRatio, opacity, skippedFeaturesHash, - /** - * @param {ol.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - var imageData = new Uint8Array(4); - gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData); - - if (imageData[3] > 0) { - var result = callback(feature); - if (result) { - return result; - } - } - }, true, hitExtent); -}; +goog.webgl.TRIANGLES = 0x0004; /** - * @param {ol.Coordinate} coordinate Coordinate. - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {number} opacity Global opacity. - * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features - * to skip. - * @return {boolean} Is there a feature at the given coordinate? + * @const + * @type {number} */ -ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function( - coordinate, context, center, resolution, rotation, size, pixelRatio, - opacity, skippedFeaturesHash) { - var gl = context.getGL(); - gl.bindFramebuffer( - gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); +goog.webgl.TRIANGLE_STRIP = 0x0005; - var hasFeature = this.replayHitDetection_(context, - coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_, - pixelRatio, opacity, skippedFeaturesHash, - /** - * @param {ol.Feature} feature Feature. - * @return {boolean} Is there a feature? - */ - function(feature) { - var imageData = new Uint8Array(4); - gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData); - return imageData[3] > 0; - }, false); - return hasFeature !== undefined; -}; +/** + * @const + * @type {number} + */ +goog.webgl.TRIANGLE_FAN = 0x0006; /** * @const - * @private - * @type {Object.<ol.render.ReplayType, - * function(new: ol.render.webgl.ImageReplay, number, - * ol.Extent)>} + * @type {number} */ -ol.render.webgl.BATCH_CONSTRUCTORS_ = { - 'Image': ol.render.webgl.ImageReplay -}; +goog.webgl.ZERO = 0; /** * @const - * @private - * @type {Array.<number>} + * @type {number} */ -ol.render.webgl.HIT_DETECTION_SIZE_ = [1, 1]; +goog.webgl.ONE = 1; -goog.provide('ol.render.webgl.Immediate'); -goog.require('goog.array'); -goog.require('ol.extent'); -goog.require('ol.render.VectorContext'); -goog.require('ol.render.webgl.ImageReplay'); -goog.require('ol.render.webgl.ReplayGroup'); +/** + * @const + * @type {number} + */ +goog.webgl.SRC_COLOR = 0x0300; /** - * @constructor - * @extends {ol.render.VectorContext} - * @param {ol.webgl.Context} context Context. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} rotation Rotation. - * @param {ol.Size} size Size. - * @param {ol.Extent} extent Extent. - * @param {number} pixelRatio Pixel ratio. - * @struct + * @const + * @type {number} */ -ol.render.webgl.Immediate = function(context, - center, resolution, rotation, size, extent, pixelRatio) { - goog.base(this); - - /** - * @private - */ - this.context_ = context; +goog.webgl.ONE_MINUS_SRC_COLOR = 0x0301; - /** - * @private - */ - this.center_ = center; - /** - * @private - */ - this.extent_ = extent; +/** + * @const + * @type {number} + */ +goog.webgl.SRC_ALPHA = 0x0302; - /** - * @private - */ - this.pixelRatio_ = pixelRatio; - /** - * @private - */ - this.size_ = size; +/** + * @const + * @type {number} + */ +goog.webgl.ONE_MINUS_SRC_ALPHA = 0x0303; - /** - * @private - */ - this.rotation_ = rotation; - /** - * @private - */ - this.resolution_ = resolution; +/** + * @const + * @type {number} + */ +goog.webgl.DST_ALPHA = 0x0304; - /** - * @private - * @type {ol.style.Image} - */ - this.imageStyle_ = null; - /** - * @private - * @type {!Object.<string, - * Array.<function(ol.render.webgl.Immediate)>>} - */ - this.callbacksByZIndex_ = {}; -}; -goog.inherits(ol.render.webgl.Immediate, ol.render.VectorContext); +/** + * @const + * @type {number} + */ +goog.webgl.ONE_MINUS_DST_ALPHA = 0x0305; /** - * FIXME: empty description for jsdoc + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.flush = function() { - /** @type {Array.<number>} */ - var zs = Object.keys(this.callbacksByZIndex_).map(Number); - goog.array.sort(zs); - var i, ii, callbacks, j, jj; - for (i = 0, ii = zs.length; i < ii; ++i) { - callbacks = this.callbacksByZIndex_[zs[i].toString()]; - for (j = 0, jj = callbacks.length; j < jj; ++j) { - callbacks[j](this); - } - } -}; +goog.webgl.DST_COLOR = 0x0306; /** - * Register a function to be called for rendering at a given zIndex. The - * function will be called asynchronously. The callback will receive a - * reference to {@link ol.render.canvas.Immediate} context for drawing. - * @param {number} zIndex Z index. - * @param {function(ol.render.webgl.Immediate)} callback Callback. - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawAsync = function(zIndex, callback) { - var zIndexKey = zIndex.toString(); - var callbacks = this.callbacksByZIndex_[zIndexKey]; - if (callbacks !== undefined) { - callbacks.push(callback); - } else { - this.callbacksByZIndex_[zIndexKey] = [callback]; - } -}; +goog.webgl.ONE_MINUS_DST_COLOR = 0x0307; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawCircleGeometry = - function(circleGeometry, data) { -}; +goog.webgl.SRC_ALPHA_SATURATE = 0x0308; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) { - var geometry = style.getGeometryFunction()(feature); - if (!geometry || - !ol.extent.intersects(this.extent_, geometry.getExtent())) { - return; - } - var zIndex = style.getZIndex(); - if (zIndex === undefined) { - zIndex = 0; - } - this.drawAsync(zIndex, function(render) { - render.setFillStrokeStyle(style.getFill(), style.getStroke()); - render.setImageStyle(style.getImage()); - render.setTextStyle(style.getText()); - var type = geometry.getType(); - var renderGeometry = ol.render.webgl.Immediate.GEOMETRY_RENDERERS_[type]; - // Do not assert since all kinds of geometries are not handled yet. - // In spite, render what we support. - if (renderGeometry) { - renderGeometry.call(render, geometry, null); - } - }); -}; +goog.webgl.FUNC_ADD = 0x8006; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry = - function(geometryCollectionGeometry, data) { - var geometries = geometryCollectionGeometry.getGeometriesArray(); - var renderers = ol.render.webgl.Immediate.GEOMETRY_RENDERERS_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometry = geometries[i]; - var geometryRenderer = renderers[geometry.getType()]; - // Do not assert since all kinds of geometries are not handled yet. - // In order to support hierarchies, delegate instead what we can to - // valid renderers. - if (geometryRenderer) { - geometryRenderer.call(this, geometry, data); - } - } -}; +goog.webgl.BLEND_EQUATION = 0x8009; /** - * @inheritDoc - * @api + * Same as BLEND_EQUATION + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawPointGeometry = - function(pointGeometry, data) { - var context = this.context_; - var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_); - var replay = /** @type {ol.render.webgl.ImageReplay} */ ( - replayGroup.getReplay(0, ol.render.ReplayType.IMAGE)); - replay.setImageStyle(this.imageStyle_); - replay.drawPointGeometry(pointGeometry, data); - replay.finish(context); - // default colors - var opacity = 1; - var skippedFeatures = {}; - var featureCallback; - var oneByOne = false; - replay.replay(this.context_, this.center_, this.resolution_, this.rotation_, - this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback, - oneByOne); - replay.getDeleteResourcesFunction(context)(); -}; +goog.webgl.BLEND_EQUATION_RGB = 0x8009; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawLineStringGeometry = - function(lineStringGeometry, data) { -}; +goog.webgl.BLEND_EQUATION_ALPHA = 0x883D; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawMultiLineStringGeometry = - function(multiLineStringGeometry, data) { -}; +goog.webgl.FUNC_SUBTRACT = 0x800A; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawMultiPointGeometry = - function(multiPointGeometry, data) { - var context = this.context_; - var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_); - var replay = /** @type {ol.render.webgl.ImageReplay} */ ( - replayGroup.getReplay(0, ol.render.ReplayType.IMAGE)); - replay.setImageStyle(this.imageStyle_); - replay.drawMultiPointGeometry(multiPointGeometry, data); - replay.finish(context); - var opacity = 1; - var skippedFeatures = {}; - var featureCallback; - var oneByOne = false; - replay.replay(this.context_, this.center_, this.resolution_, this.rotation_, - this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback, - oneByOne); - replay.getDeleteResourcesFunction(context)(); -}; +goog.webgl.FUNC_REVERSE_SUBTRACT = 0x800B; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawMultiPolygonGeometry = - function(multiPolygonGeometry, data) { -}; +goog.webgl.BLEND_DST_RGB = 0x80C8; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawPolygonGeometry = - function(polygonGeometry, data) { -}; +goog.webgl.BLEND_SRC_RGB = 0x80C9; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.drawText = - function(flatCoordinates, offset, end, stride, geometry, data) { -}; +goog.webgl.BLEND_DST_ALPHA = 0x80CA; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.setFillStrokeStyle = - function(fillStyle, strokeStyle) { -}; +goog.webgl.BLEND_SRC_ALPHA = 0x80CB; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) { - this.imageStyle_ = imageStyle; -}; +goog.webgl.CONSTANT_COLOR = 0x8001; /** - * @inheritDoc - * @api + * @const + * @type {number} */ -ol.render.webgl.Immediate.prototype.setTextStyle = function(textStyle) { -}; +goog.webgl.ONE_MINUS_CONSTANT_COLOR = 0x8002; /** * @const - * @private - * @type {Object.<ol.geom.GeometryType, - * function(this: ol.render.webgl.Immediate, - * (ol.geom.Geometry|ol.render.Feature), Object)>} + * @type {number} */ -ol.render.webgl.Immediate.GEOMETRY_RENDERERS_ = { - 'Point': ol.render.webgl.Immediate.prototype.drawPointGeometry, - 'MultiPoint': ol.render.webgl.Immediate.prototype.drawMultiPointGeometry, - 'GeometryCollection': - ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry -}; - -// This file is automatically generated, do not edit -goog.provide('ol.renderer.webgl.map.shader.Default'); -goog.provide('ol.renderer.webgl.map.shader.Default.Locations'); -goog.provide('ol.renderer.webgl.map.shader.DefaultFragment'); -goog.provide('ol.renderer.webgl.map.shader.DefaultVertex'); +goog.webgl.CONSTANT_ALPHA = 0x8003; -goog.require('ol.webgl.shader'); +/** + * @const + * @type {number} + */ +goog.webgl.ONE_MINUS_CONSTANT_ALPHA = 0x8004; /** - * @constructor - * @extends {ol.webgl.shader.Fragment} - * @struct + * @const + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultFragment = function() { - goog.base(this, ol.renderer.webgl.map.shader.DefaultFragment.SOURCE); -}; -goog.inherits(ol.renderer.webgl.map.shader.DefaultFragment, ol.webgl.shader.Fragment); -goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultFragment); +goog.webgl.BLEND_COLOR = 0x8005; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultFragment.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'; +goog.webgl.ARRAY_BUFFER = 0x8892; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultFragment.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;}'; +goog.webgl.ELEMENT_ARRAY_BUFFER = 0x8893; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultFragment.SOURCE = goog.DEBUG ? - ol.renderer.webgl.map.shader.DefaultFragment.DEBUG_SOURCE : - ol.renderer.webgl.map.shader.DefaultFragment.OPTIMIZED_SOURCE; - +goog.webgl.ARRAY_BUFFER_BINDING = 0x8894; /** - * @constructor - * @extends {ol.webgl.shader.Vertex} - * @struct + * @const + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultVertex = function() { - goog.base(this, ol.renderer.webgl.map.shader.DefaultVertex.SOURCE); -}; -goog.inherits(ol.renderer.webgl.map.shader.DefaultVertex, ol.webgl.shader.Vertex); -goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultVertex); +goog.webgl.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultVertex.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'; +goog.webgl.STREAM_DRAW = 0x88E0; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultVertex.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;}'; +goog.webgl.STATIC_DRAW = 0x88E4; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.map.shader.DefaultVertex.SOURCE = goog.DEBUG ? - ol.renderer.webgl.map.shader.DefaultVertex.DEBUG_SOURCE : - ol.renderer.webgl.map.shader.DefaultVertex.OPTIMIZED_SOURCE; - +goog.webgl.DYNAMIC_DRAW = 0x88E8; /** - * @constructor - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLProgram} program Program. - * @struct + * @const + * @type {number} */ -ol.renderer.webgl.map.shader.Default.Locations = function(gl, program) { - - /** - * @type {WebGLUniformLocation} - */ - this.u_opacity = gl.getUniformLocation( - program, goog.DEBUG ? 'u_opacity' : 'f'); +goog.webgl.BUFFER_SIZE = 0x8764; - /** - * @type {WebGLUniformLocation} - */ - this.u_projectionMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_projectionMatrix' : 'e'); - /** - * @type {WebGLUniformLocation} - */ - this.u_texCoordMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_texCoordMatrix' : 'd'); +/** + * @const + * @type {number} + */ +goog.webgl.BUFFER_USAGE = 0x8765; - /** - * @type {WebGLUniformLocation} - */ - this.u_texture = gl.getUniformLocation( - program, goog.DEBUG ? 'u_texture' : 'g'); - /** - * @type {number} - */ - this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'b'); +/** + * @const + * @type {number} + */ +goog.webgl.CURRENT_VERTEX_ATTRIB = 0x8626; - /** - * @type {number} - */ - this.a_texCoord = gl.getAttribLocation( - program, goog.DEBUG ? 'a_texCoord' : 'c'); -}; -goog.provide('ol.renderer.webgl.Layer'); +/** + * @const + * @type {number} + */ +goog.webgl.FRONT = 0x0404; -goog.require('goog.vec.Mat4'); -goog.require('goog.webgl'); -goog.require('ol.layer.Layer'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.webgl.Immediate'); -goog.require('ol.renderer.Layer'); -goog.require('ol.renderer.webgl.map.shader.Default'); -goog.require('ol.renderer.webgl.map.shader.Default.Locations'); -goog.require('ol.renderer.webgl.map.shader.DefaultFragment'); -goog.require('ol.renderer.webgl.map.shader.DefaultVertex'); -goog.require('ol.webgl.Buffer'); -goog.require('ol.webgl.Context'); +/** + * @const + * @type {number} + */ +goog.webgl.BACK = 0x0405; /** - * @constructor - * @extends {ol.renderer.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Layer} layer Layer. + * @const + * @type {number} */ -ol.renderer.webgl.Layer = function(mapRenderer, layer) { +goog.webgl.FRONT_AND_BACK = 0x0408; - goog.base(this, layer); - /** - * @protected - * @type {ol.renderer.webgl.Map} - */ - this.mapRenderer = mapRenderer; +/** + * @const + * @type {number} + */ +goog.webgl.CULL_FACE = 0x0B44; - /** - * @private - * @type {ol.webgl.Buffer} - */ - this.arrayBuffer_ = new ol.webgl.Buffer([ - -1, -1, 0, 0, - 1, -1, 1, 0, - -1, 1, 0, 1, - 1, 1, 1, 1 - ]); - /** - * @protected - * @type {WebGLTexture} - */ - this.texture = null; +/** + * @const + * @type {number} + */ +goog.webgl.BLEND = 0x0BE2; - /** - * @protected - * @type {WebGLFramebuffer} - */ - this.framebuffer = null; - /** - * @protected - * @type {number|undefined} - */ - this.framebufferDimension = undefined; +/** + * @const + * @type {number} + */ +goog.webgl.DITHER = 0x0BD0; - /** - * @protected - * @type {!goog.vec.Mat4.Number} - */ - this.texCoordMatrix = goog.vec.Mat4.createNumber(); - /** - * @protected - * @type {!goog.vec.Mat4.Number} - */ - this.projectionMatrix = goog.vec.Mat4.createNumberIdentity(); +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_TEST = 0x0B90; - /** - * @private - * @type {ol.renderer.webgl.map.shader.Default.Locations} - */ - this.defaultLocations_ = null; -}; -goog.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer); +/** + * @const + * @type {number} + */ +goog.webgl.DEPTH_TEST = 0x0B71; /** - * @param {olx.FrameState} frameState Frame state. - * @param {number} framebufferDimension Framebuffer dimension. - * @protected + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.bindFramebuffer = - function(frameState, framebufferDimension) { +goog.webgl.SCISSOR_TEST = 0x0C11; - var gl = this.mapRenderer.getGL(); - if (this.framebufferDimension === undefined || - this.framebufferDimension != framebufferDimension) { +/** + * @const + * @type {number} + */ +goog.webgl.POLYGON_OFFSET_FILL = 0x8037; - frameState.postRenderFunctions.push( - goog.partial( - /** - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLFramebuffer} framebuffer Framebuffer. - * @param {WebGLTexture} texture Texture. - */ - function(gl, framebuffer, texture) { - if (!gl.isContextLost()) { - gl.deleteFramebuffer(framebuffer); - gl.deleteTexture(texture); - } - }, gl, this.framebuffer, this.texture)); - var texture = ol.webgl.Context.createEmptyTexture( - gl, framebufferDimension, framebufferDimension); +/** + * @const + * @type {number} + */ +goog.webgl.SAMPLE_ALPHA_TO_COVERAGE = 0x809E; - var framebuffer = gl.createFramebuffer(); - gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer); - gl.framebufferTexture2D(goog.webgl.FRAMEBUFFER, - goog.webgl.COLOR_ATTACHMENT0, goog.webgl.TEXTURE_2D, texture, 0); - this.texture = texture; - this.framebuffer = framebuffer; - this.framebufferDimension = framebufferDimension; +/** + * @const + * @type {number} + */ +goog.webgl.SAMPLE_COVERAGE = 0x80A0; - } else { - gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, this.framebuffer); - } -}; +/** + * @const + * @type {number} + */ +goog.webgl.NO_ERROR = 0; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {ol.webgl.Context} context Context. + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.composeFrame = - function(frameState, layerState, context) { +goog.webgl.INVALID_ENUM = 0x0500; - this.dispatchComposeEvent_( - ol.render.EventType.PRECOMPOSE, context, frameState); - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.arrayBuffer_); +/** + * @const + * @type {number} + */ +goog.webgl.INVALID_VALUE = 0x0501; - var gl = context.getGL(); - var fragmentShader = - ol.renderer.webgl.map.shader.DefaultFragment.getInstance(); - var vertexShader = ol.renderer.webgl.map.shader.DefaultVertex.getInstance(); +/** + * @const + * @type {number} + */ +goog.webgl.INVALID_OPERATION = 0x0502; - var program = context.getProgram(fragmentShader, vertexShader); - var locations; - if (!this.defaultLocations_) { - locations = - new ol.renderer.webgl.map.shader.Default.Locations(gl, program); - this.defaultLocations_ = locations; - } else { - locations = this.defaultLocations_; - } +/** + * @const + * @type {number} + */ +goog.webgl.OUT_OF_MEMORY = 0x0505; - if (context.useProgram(program)) { - gl.enableVertexAttribArray(locations.a_position); - gl.vertexAttribPointer( - locations.a_position, 2, goog.webgl.FLOAT, false, 16, 0); - gl.enableVertexAttribArray(locations.a_texCoord); - gl.vertexAttribPointer( - locations.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); - gl.uniform1i(locations.u_texture, 0); - } - gl.uniformMatrix4fv( - locations.u_texCoordMatrix, false, this.getTexCoordMatrix()); - gl.uniformMatrix4fv(locations.u_projectionMatrix, false, - this.getProjectionMatrix()); - gl.uniform1f(locations.u_opacity, layerState.opacity); - gl.bindTexture(goog.webgl.TEXTURE_2D, this.getTexture()); - gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); +/** + * @const + * @type {number} + */ +goog.webgl.CW = 0x0900; - this.dispatchComposeEvent_( - ol.render.EventType.POSTCOMPOSE, context, frameState); -}; +/** + * @const + * @type {number} + */ +goog.webgl.CCW = 0x0901; /** - * @param {ol.render.EventType} type Event type. - * @param {ol.webgl.Context} context WebGL context. - * @param {olx.FrameState} frameState Frame state. - * @private + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ = - function(type, context, frameState) { - var layer = this.getLayer(); - if (layer.hasListener(type)) { - var viewState = frameState.viewState; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var extent = frameState.extent; - var center = viewState.center; - var rotation = viewState.rotation; - var size = frameState.size; - - var render = new ol.render.webgl.Immediate( - context, center, resolution, rotation, size, extent, pixelRatio); - var composeEvent = new ol.render.Event( - type, layer, render, frameState, null, context); - layer.dispatchEvent(composeEvent); - } -}; +goog.webgl.LINE_WIDTH = 0x0B21; /** - * @return {!goog.vec.Mat4.Number} Matrix. + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.getTexCoordMatrix = function() { - return this.texCoordMatrix; -}; +goog.webgl.ALIASED_POINT_SIZE_RANGE = 0x846D; /** - * @return {WebGLTexture} Texture. + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.getTexture = function() { - return this.texture; -}; +goog.webgl.ALIASED_LINE_WIDTH_RANGE = 0x846E; /** - * @return {!goog.vec.Mat4.Number} Matrix. + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.getProjectionMatrix = function() { - return this.projectionMatrix; -}; +goog.webgl.CULL_FACE_MODE = 0x0B45; /** - * Handle webglcontextlost. + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() { - this.texture = null; - this.framebuffer = null; - this.framebufferDimension = undefined; -}; +goog.webgl.FRONT_FACE = 0x0B46; /** - * @param {olx.FrameState} frameState Frame state. - * @param {ol.layer.LayerState} layerState Layer state. - * @param {ol.webgl.Context} context Context. - * @return {boolean} whether composeFrame should be called. + * @const + * @type {number} */ -ol.renderer.webgl.Layer.prototype.prepareFrame = goog.abstractMethod; +goog.webgl.DEPTH_RANGE = 0x0B70; -goog.provide('ol.renderer.webgl.ImageLayer'); -goog.require('goog.asserts'); -goog.require('goog.functions'); -goog.require('goog.vec.Mat4'); -goog.require('goog.webgl'); -goog.require('ol.Coordinate'); -goog.require('ol.Extent'); -goog.require('ol.ImageBase'); -goog.require('ol.ViewHint'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.proj'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.source.ImageVector'); -goog.require('ol.vec.Mat4'); -goog.require('ol.webgl.Context'); +/** + * @const + * @type {number} + */ +goog.webgl.DEPTH_WRITEMASK = 0x0B72; + +/** + * @const + * @type {number} + */ +goog.webgl.DEPTH_CLEAR_VALUE = 0x0B73; /** - * @constructor - * @extends {ol.renderer.webgl.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Image} imageLayer Tile layer. + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) { +goog.webgl.DEPTH_FUNC = 0x0B74; - goog.base(this, mapRenderer, imageLayer); - /** - * The last rendered image. - * @private - * @type {?ol.ImageBase} - */ - this.image_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_CLEAR_VALUE = 0x0B91; - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.hitCanvasContext_ = null; - /** - * @private - * @type {?goog.vec.Mat4.Number} - */ - this.hitTransformationMatrix_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_FUNC = 0x0B92; -}; -goog.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer); + +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_FAIL = 0x0B94; /** - * @param {ol.ImageBase} image Image. - * @private - * @return {WebGLTexture} Texture. + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) { +goog.webgl.STENCIL_PASS_DEPTH_FAIL = 0x0B95; - // We meet the conditions to work with non-power of two textures. - // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support - // http://learningwebgl.com/blog/?p=2101 - var imageElement = image.getImage(); - var gl = this.mapRenderer.getGL(); +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_PASS_DEPTH_PASS = 0x0B96; - return ol.webgl.Context.createTexture( - gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); -}; + +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_REF = 0x0B97; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - var layer = this.getLayer(); - var source = layer.getSource(); - var resolution = frameState.viewState.resolution; - var rotation = frameState.viewState.rotation; - var skippedFeatureUids = frameState.skippedFeatureUids; - return source.forEachFeatureAtCoordinate( - coordinate, resolution, rotation, skippedFeatureUids, +goog.webgl.STENCIL_VALUE_MASK = 0x0B93; - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - return callback.call(thisArg, feature, layer); - }); -}; + +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_WRITEMASK = 0x0B98; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.prepareFrame = - function(frameState, layerState, context) { +goog.webgl.STENCIL_BACK_FUNC = 0x8800; - var gl = this.mapRenderer.getGL(); - var pixelRatio = frameState.pixelRatio; - var viewState = frameState.viewState; - var viewCenter = viewState.center; - var viewResolution = viewState.resolution; - var viewRotation = viewState.rotation; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_BACK_FAIL = 0x8801; - var image = this.image_; - var texture = this.texture; - var imageLayer = this.getLayer(); - goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, - 'layer is an instance of ol.layer.Image'); - var imageSource = imageLayer.getSource(); - var hints = frameState.viewHints; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802; - var renderedExtent = frameState.extent; - if (layerState.extent !== undefined) { - renderedExtent = ol.extent.getIntersection( - renderedExtent, layerState.extent); - } - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && - !ol.extent.isEmpty(renderedExtent)) { - var projection = viewState.projection; - if (!ol.ENABLE_RASTER_REPROJECTION) { - var sourceProjection = imageSource.getProjection(); - if (sourceProjection) { - goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), - 'projection and sourceProjection are equivalent'); - projection = sourceProjection; - } - } - var image_ = imageSource.getImage(renderedExtent, viewResolution, - pixelRatio, projection); - if (image_) { - var loaded = this.loadImage(image_); - if (loaded) { - image = image_; - texture = this.createTexture_(image_); - if (this.texture) { - frameState.postRenderFunctions.push( - goog.partial( - /** - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLTexture} texture Texture. - */ - function(gl, texture) { - if (!gl.isContextLost()) { - gl.deleteTexture(texture); - } - }, gl, this.texture)); - } - } - } - } - if (image) { - goog.asserts.assert(texture, 'texture is truthy'); +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803; - var canvas = this.mapRenderer.getContext().getCanvas(); - this.updateProjectionMatrix_(canvas.width, canvas.height, - pixelRatio, viewCenter, viewResolution, viewRotation, - image.getExtent()); - this.hitTransformationMatrix_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_BACK_REF = 0x8CA3; - // Translate and scale to flip the Y coord. - var texCoordMatrix = this.texCoordMatrix; - goog.vec.Mat4.makeIdentity(texCoordMatrix); - goog.vec.Mat4.scale(texCoordMatrix, 1, -1, 1); - goog.vec.Mat4.translate(texCoordMatrix, 0, -1, 0); - this.image_ = image; - this.texture = texture; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_BACK_VALUE_MASK = 0x8CA4; - this.updateAttributions(frameState.attributions, image.getAttributions()); - this.updateLogos(frameState, imageSource); - } - return true; -}; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_BACK_WRITEMASK = 0x8CA5; /** - * @param {number} canvasWidth Canvas width. - * @param {number} canvasHeight Canvas height. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.Coordinate} viewCenter View center. - * @param {number} viewResolution View resolution. - * @param {number} viewRotation View rotation. - * @param {ol.Extent} imageExtent Image extent. - * @private + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = - function(canvasWidth, canvasHeight, pixelRatio, - viewCenter, viewResolution, viewRotation, imageExtent) { - - var canvasExtentWidth = canvasWidth * viewResolution; - var canvasExtentHeight = canvasHeight * viewResolution; +goog.webgl.VIEWPORT = 0x0BA2; - var projectionMatrix = this.projectionMatrix; - goog.vec.Mat4.makeIdentity(projectionMatrix); - goog.vec.Mat4.scale(projectionMatrix, - pixelRatio * 2 / canvasExtentWidth, - pixelRatio * 2 / canvasExtentHeight, 1); - goog.vec.Mat4.rotateZ(projectionMatrix, -viewRotation); - goog.vec.Mat4.translate(projectionMatrix, - imageExtent[0] - viewCenter[0], - imageExtent[1] - viewCenter[1], - 0); - goog.vec.Mat4.scale(projectionMatrix, - (imageExtent[2] - imageExtent[0]) / 2, - (imageExtent[3] - imageExtent[1]) / 2, - 1); - goog.vec.Mat4.translate(projectionMatrix, 1, 1, 0); -}; +/** + * @const + * @type {number} + */ +goog.webgl.SCISSOR_BOX = 0x0C10; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState) { - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); - return hasFeature !== undefined; -}; +goog.webgl.COLOR_CLEAR_VALUE = 0x0C22; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.image_ || !this.image_.getImage()) { - return undefined; - } +goog.webgl.COLOR_WRITEMASK = 0x0C23; - if (this.getLayer().getSource() instanceof ol.source.ImageVector) { - // for ImageVector sources use the original hit-detection logic, - // so that for example also transparent polygons are detected - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - var hasFeature = this.forEachFeatureAtCoordinate( - coordinate, frameState, goog.functions.TRUE, this); - if (hasFeature) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } else { - var imageSize = - [this.image_.getImage().width, this.image_.getImage().height]; +/** + * @const + * @type {number} + */ +goog.webgl.UNPACK_ALIGNMENT = 0x0CF5; - if (!this.hitTransformationMatrix_) { - this.hitTransformationMatrix_ = this.getHitTransformationMatrix_( - frameState.size, imageSize); - } - var pixelOnFrameBuffer = [0, 0]; - ol.vec.Mat4.multVec2( - this.hitTransformationMatrix_, pixel, pixelOnFrameBuffer); +/** + * @const + * @type {number} + */ +goog.webgl.PACK_ALIGNMENT = 0x0D05; - if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] || - pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) { - // outside the image, no need to check - return undefined; - } - if (!this.hitCanvasContext_) { - this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); - } +/** + * @const + * @type {number} + */ +goog.webgl.MAX_TEXTURE_SIZE = 0x0D33; - this.hitCanvasContext_.clearRect(0, 0, 1, 1); - this.hitCanvasContext_.drawImage(this.image_.getImage(), - pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1); - var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } - } -}; +/** + * @const + * @type {number} + */ +goog.webgl.MAX_VIEWPORT_DIMS = 0x0D3A; /** - * The transformation matrix to get the pixel on the image for a - * pixel on the map. - * @param {ol.Size} mapSize - * @param {ol.Size} imageSize - * @return {goog.vec.Mat4.Number} - * @private + * @const + * @type {number} */ -ol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ = - function(mapSize, imageSize) { - // the first matrix takes a map pixel, flips the y-axis and scales to - // a range between -1 ... 1 - var mapCoordMatrix = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.makeIdentity(mapCoordMatrix); - goog.vec.Mat4.translate(mapCoordMatrix, -1, -1, 0); - goog.vec.Mat4.scale(mapCoordMatrix, 2 / mapSize[0], 2 / mapSize[1], 1); - goog.vec.Mat4.translate(mapCoordMatrix, 0, mapSize[1], 0); - goog.vec.Mat4.scale(mapCoordMatrix, 1, -1, 1); - - // the second matrix is the inverse of the projection matrix used in the - // shader for drawing - var projectionMatrixInv = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.invert(this.projectionMatrix, projectionMatrixInv); +goog.webgl.SUBPIXEL_BITS = 0x0D50; - // the third matrix scales to the image dimensions and flips the y-axis again - var imageCoordMatrix = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.makeIdentity(imageCoordMatrix); - goog.vec.Mat4.translate(imageCoordMatrix, 0, imageSize[1], 0); - goog.vec.Mat4.scale(imageCoordMatrix, 1, -1, 1); - goog.vec.Mat4.scale(imageCoordMatrix, imageSize[0] / 2, imageSize[1] / 2, 1); - goog.vec.Mat4.translate(imageCoordMatrix, 1, 1, 0); - var transformMatrix = goog.vec.Mat4.createNumber(); - goog.vec.Mat4.multMat( - imageCoordMatrix, projectionMatrixInv, transformMatrix); - goog.vec.Mat4.multMat( - transformMatrix, mapCoordMatrix, transformMatrix); +/** + * @const + * @type {number} + */ +goog.webgl.RED_BITS = 0x0D52; - return transformMatrix; -}; -// This file is automatically generated, do not edit -goog.provide('ol.renderer.webgl.tilelayer.shader'); -goog.provide('ol.renderer.webgl.tilelayer.shader.Locations'); -goog.provide('ol.renderer.webgl.tilelayer.shader.Fragment'); -goog.provide('ol.renderer.webgl.tilelayer.shader.Vertex'); +/** + * @const + * @type {number} + */ +goog.webgl.GREEN_BITS = 0x0D53; -goog.require('ol.webgl.shader'); +/** + * @const + * @type {number} + */ +goog.webgl.BLUE_BITS = 0x0D54; /** - * @constructor - * @extends {ol.webgl.shader.Fragment} - * @struct + * @const + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.Fragment = function() { - goog.base(this, ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE); -}; -goog.inherits(ol.renderer.webgl.tilelayer.shader.Fragment, ol.webgl.shader.Fragment); -goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Fragment); +goog.webgl.ALPHA_BITS = 0x0D55; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.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'; +goog.webgl.DEPTH_BITS = 0x0D56; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}'; +goog.webgl.STENCIL_BITS = 0x0D57; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE = goog.DEBUG ? - ol.renderer.webgl.tilelayer.shader.Fragment.DEBUG_SOURCE : - ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE; +goog.webgl.POLYGON_OFFSET_UNITS = 0x2A00; + +/** + * @const + * @type {number} + */ +goog.webgl.POLYGON_OFFSET_FACTOR = 0x8038; /** - * @constructor - * @extends {ol.webgl.shader.Vertex} - * @struct + * @const + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.Vertex = function() { - goog.base(this, ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE); -}; -goog.inherits(ol.renderer.webgl.tilelayer.shader.Vertex, ol.webgl.shader.Vertex); -goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Vertex); +goog.webgl.TEXTURE_BINDING_2D = 0x8069; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.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'; +goog.webgl.SAMPLE_BUFFERS = 0x80A8; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.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;}'; +goog.webgl.SAMPLES = 0x80A9; /** * @const - * @type {string} + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE = goog.DEBUG ? - ol.renderer.webgl.tilelayer.shader.Vertex.DEBUG_SOURCE : - ol.renderer.webgl.tilelayer.shader.Vertex.OPTIMIZED_SOURCE; +goog.webgl.SAMPLE_COVERAGE_VALUE = 0x80AA; +/** + * @const + * @type {number} + */ +goog.webgl.SAMPLE_COVERAGE_INVERT = 0x80AB; + /** - * @constructor - * @param {WebGLRenderingContext} gl GL. - * @param {WebGLProgram} program Program. - * @struct + * @const + * @type {number} */ -ol.renderer.webgl.tilelayer.shader.Locations = function(gl, program) { +goog.webgl.COMPRESSED_TEXTURE_FORMATS = 0x86A3; - /** - * @type {WebGLUniformLocation} - */ - this.u_texture = gl.getUniformLocation( - program, goog.DEBUG ? 'u_texture' : 'e'); - /** - * @type {WebGLUniformLocation} - */ - this.u_tileOffset = gl.getUniformLocation( - program, goog.DEBUG ? 'u_tileOffset' : 'd'); +/** + * @const + * @type {number} + */ +goog.webgl.DONT_CARE = 0x1100; - /** - * @type {number} - */ - this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'b'); - /** - * @type {number} - */ - this.a_texCoord = gl.getAttribLocation( - program, goog.DEBUG ? 'a_texCoord' : 'c'); -}; +/** + * @const + * @type {number} + */ +goog.webgl.FASTEST = 0x1101; -// FIXME large resolutions lead to too large framebuffers :-( -// FIXME animated shaders! check in redraw -goog.provide('ol.renderer.webgl.TileLayer'); +/** + * @const + * @type {number} + */ +goog.webgl.NICEST = 0x1102; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.vec.Mat4'); -goog.require('goog.vec.Vec4'); -goog.require('goog.webgl'); -goog.require('ol.TileRange'); -goog.require('ol.TileState'); -goog.require('ol.extent'); -goog.require('ol.layer.Tile'); -goog.require('ol.math'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.renderer.webgl.tilelayer.shader.Fragment'); -goog.require('ol.renderer.webgl.tilelayer.shader.Locations'); -goog.require('ol.renderer.webgl.tilelayer.shader.Vertex'); -goog.require('ol.size'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); -goog.require('ol.webgl.Buffer'); +/** + * @const + * @type {number} + */ +goog.webgl.GENERATE_MIPMAP_HINT = 0x8192; /** - * @constructor - * @extends {ol.renderer.webgl.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Tile} tileLayer Tile layer. + * @const + * @type {number} */ -ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) { +goog.webgl.BYTE = 0x1400; - goog.base(this, mapRenderer, tileLayer); - /** - * @private - * @type {ol.webgl.shader.Fragment} - */ - this.fragmentShader_ = - ol.renderer.webgl.tilelayer.shader.Fragment.getInstance(); +/** + * @const + * @type {number} + */ +goog.webgl.UNSIGNED_BYTE = 0x1401; - /** - * @private - * @type {ol.webgl.shader.Vertex} - */ - this.vertexShader_ = ol.renderer.webgl.tilelayer.shader.Vertex.getInstance(); - /** - * @private - * @type {ol.renderer.webgl.tilelayer.shader.Locations} - */ - this.locations_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.SHORT = 0x1402; - /** - * @private - * @type {ol.webgl.Buffer} - */ - this.renderArrayBuffer_ = new ol.webgl.Buffer([ - 0, 0, 0, 1, - 1, 0, 1, 1, - 0, 1, 0, 0, - 1, 1, 1, 0 - ]); - /** - * @private - * @type {ol.TileRange} - */ - this.renderedTileRange_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.UNSIGNED_SHORT = 0x1403; - /** - * @private - * @type {ol.Extent} - */ - this.renderedFramebufferExtent_ = null; - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; +/** + * @const + * @type {number} + */ +goog.webgl.INT = 0x1404; - /** - * @private - * @type {ol.Size} - */ - this.tmpSize_ = [0, 0]; -}; -goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer); +/** + * @const + * @type {number} + */ +goog.webgl.UNSIGNED_INT = 0x1405; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() { - var context = this.mapRenderer.getContext(); - context.deleteBuffer(this.renderArrayBuffer_); - goog.base(this, 'disposeInternal'); -}; +goog.webgl.FLOAT = 0x1406; /** - * Create a function that adds loaded tiles to the tile lookup. - * @param {ol.source.Tile} source Tile source. - * @param {ol.proj.Projection} projection Projection of the tiles. - * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded - * tiles by zoom level. - * @return {function(number, ol.TileRange):boolean} A function that can be - * called with a zoom level and a tile range to add loaded tiles to the - * lookup. - * @protected + * @const + * @type {number} */ -ol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder = - function(source, projection, tiles) { - var mapRenderer = this.mapRenderer; - - return ( - /** - * @param {number} zoom Zoom level. - * @param {ol.TileRange} tileRange Tile range. - * @return {boolean} The tile range is fully loaded. - */ - function(zoom, tileRange) { - return source.forEachLoadedTile(projection, zoom, - tileRange, function(tile) { - var loaded = mapRenderer.isTileTextureLoaded(tile); - if (loaded) { - if (!tiles[zoom]) { - tiles[zoom] = {}; - } - tiles[zoom][tile.tileCoord.toString()] = tile; - } - return loaded; - }); - }); -}; +goog.webgl.DEPTH_COMPONENT = 0x1902; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() { - goog.base(this, 'handleWebGLContextLost'); - this.locations_ = null; -}; +goog.webgl.ALPHA = 0x1906; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.TileLayer.prototype.prepareFrame = - function(frameState, layerState, context) { - - var mapRenderer = this.mapRenderer; - var gl = context.getGL(); +goog.webgl.RGB = 0x1907; - var viewState = frameState.viewState; - var projection = viewState.projection; - var tileLayer = this.getLayer(); - goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, - 'layer is an instance of ol.layer.Tile'); - var tileSource = tileLayer.getSource(); - var tileGrid = tileSource.getTileGridForProjection(projection); - var z = tileGrid.getZForResolution(viewState.resolution); - var tileResolution = tileGrid.getResolution(z); +/** + * @const + * @type {number} + */ +goog.webgl.RGBA = 0x1908; - var tilePixelSize = - tileSource.getTilePixelSize(z, frameState.pixelRatio, projection); - var pixelRatio = tilePixelSize[0] / - ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; - var tilePixelResolution = tileResolution / pixelRatio; - var tileGutter = tileSource.getGutter(); - var center = viewState.center; - var extent; - if (tileResolution == viewState.resolution) { - center = this.snapCenterToPixel(center, tileResolution, frameState.size); - extent = ol.extent.getForViewAndSize( - center, tileResolution, viewState.rotation, frameState.size); - } else { - extent = frameState.extent; - } - var tileRange = tileGrid.getTileRangeForExtentAndResolution( - extent, tileResolution); +/** + * @const + * @type {number} + */ +goog.webgl.LUMINANCE = 0x1909; - var framebufferExtent; - if (this.renderedTileRange_ && - this.renderedTileRange_.equals(tileRange) && - this.renderedRevision_ == tileSource.getRevision()) { - framebufferExtent = this.renderedFramebufferExtent_; - } else { - var tileRangeSize = tileRange.getSize(); +/** + * @const + * @type {number} + */ +goog.webgl.LUMINANCE_ALPHA = 0x190A; - var maxDimension = Math.max( - tileRangeSize[0] * tilePixelSize[0], - tileRangeSize[1] * tilePixelSize[1]); - var framebufferDimension = ol.math.roundUpToPowerOfTwo(maxDimension); - var framebufferExtentDimension = tilePixelResolution * framebufferDimension; - var origin = tileGrid.getOrigin(z); - var minX = origin[0] + - tileRange.minX * tilePixelSize[0] * tilePixelResolution; - var minY = origin[1] + - tileRange.minY * tilePixelSize[1] * tilePixelResolution; - framebufferExtent = [ - minX, minY, - minX + framebufferExtentDimension, minY + framebufferExtentDimension - ]; - this.bindFramebuffer(frameState, framebufferDimension); - gl.viewport(0, 0, framebufferDimension, framebufferDimension); +/** + * @const + * @type {number} + */ +goog.webgl.UNSIGNED_SHORT_4_4_4_4 = 0x8033; - gl.clearColor(0, 0, 0, 0); - gl.clear(goog.webgl.COLOR_BUFFER_BIT); - gl.disable(goog.webgl.BLEND); - var program = context.getProgram(this.fragmentShader_, this.vertexShader_); - context.useProgram(program); - if (!this.locations_) { - this.locations_ = - new ol.renderer.webgl.tilelayer.shader.Locations(gl, program); - } +/** + * @const + * @type {number} + */ +goog.webgl.UNSIGNED_SHORT_5_5_5_1 = 0x8034; - context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.renderArrayBuffer_); - gl.enableVertexAttribArray(this.locations_.a_position); - gl.vertexAttribPointer( - this.locations_.a_position, 2, goog.webgl.FLOAT, false, 16, 0); - gl.enableVertexAttribArray(this.locations_.a_texCoord); - gl.vertexAttribPointer( - this.locations_.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); - gl.uniform1i(this.locations_.u_texture, 0); - /** - * @type {Object.<number, Object.<string, ol.Tile>>} - */ - var tilesToDrawByZ = {}; - tilesToDrawByZ[z] = {}; +/** + * @const + * @type {number} + */ +goog.webgl.UNSIGNED_SHORT_5_6_5 = 0x8363; - var findLoadedTiles = this.createLoadedTileFinder( - tileSource, projection, tilesToDrawByZ); - var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); - var allTilesLoaded = true; - var tmpExtent = ol.extent.createEmpty(); - var tmpTileRange = new ol.TileRange(0, 0, 0, 0); - var childTileRange, drawable, fullyLoaded, tile, tileState; - var x, y, tileExtent; - for (x = tileRange.minX; x <= tileRange.maxX; ++x) { - for (y = tileRange.minY; y <= tileRange.maxY; ++y) { +/** + * @const + * @type {number} + */ +goog.webgl.FRAGMENT_SHADER = 0x8B30; - tile = tileSource.getTile(z, x, y, pixelRatio, projection); - if (layerState.extent !== undefined) { - // ignore tiles outside layer extent - tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); - if (!ol.extent.intersects(tileExtent, layerState.extent)) { - continue; - } - } - tileState = tile.getState(); - drawable = tileState == ol.TileState.LOADED || - tileState == ol.TileState.EMPTY || - tileState == ol.TileState.ERROR && !useInterimTilesOnError; - if (!drawable && tile.interimTile) { - tile = tile.interimTile; - } - goog.asserts.assert(tile); - tileState = tile.getState(); - if (tileState == ol.TileState.LOADED) { - if (mapRenderer.isTileTextureLoaded(tile)) { - tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; - continue; - } - } else if (tileState == ol.TileState.EMPTY || - (tileState == ol.TileState.ERROR && - !useInterimTilesOnError)) { - continue; - } - allTilesLoaded = false; - fullyLoaded = tileGrid.forEachTileCoordParentTileRange( - tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); - if (!fullyLoaded) { - childTileRange = tileGrid.getTileCoordChildTileRange( - tile.tileCoord, tmpTileRange, tmpExtent); - if (childTileRange) { - findLoadedTiles(z + 1, childTileRange); - } - } +/** + * @const + * @type {number} + */ +goog.webgl.VERTEX_SHADER = 0x8B31; - } - } +/** + * @const + * @type {number} + */ +goog.webgl.MAX_VERTEX_ATTRIBS = 0x8869; - /** @type {Array.<number>} */ - var zs = Object.keys(tilesToDrawByZ).map(Number); - goog.array.sort(zs); - var u_tileOffset = goog.vec.Vec4.createFloat32(); - var i, ii, sx, sy, tileKey, tilesToDraw, tx, ty; - for (i = 0, ii = zs.length; i < ii; ++i) { - tilesToDraw = tilesToDrawByZ[zs[i]]; - for (tileKey in tilesToDraw) { - tile = tilesToDraw[tileKey]; - tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); - sx = 2 * (tileExtent[2] - tileExtent[0]) / - framebufferExtentDimension; - sy = 2 * (tileExtent[3] - tileExtent[1]) / - framebufferExtentDimension; - tx = 2 * (tileExtent[0] - framebufferExtent[0]) / - framebufferExtentDimension - 1; - ty = 2 * (tileExtent[1] - framebufferExtent[1]) / - framebufferExtentDimension - 1; - goog.vec.Vec4.setFromValues(u_tileOffset, sx, sy, tx, ty); - gl.uniform4fv(this.locations_.u_tileOffset, u_tileOffset); - mapRenderer.bindTileTexture(tile, tilePixelSize, - tileGutter * pixelRatio, goog.webgl.LINEAR, goog.webgl.LINEAR); - gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); - } - } - if (allTilesLoaded) { - this.renderedTileRange_ = tileRange; - this.renderedFramebufferExtent_ = framebufferExtent; - this.renderedRevision_ = tileSource.getRevision(); - } else { - this.renderedTileRange_ = null; - this.renderedFramebufferExtent_ = null; - this.renderedRevision_ = -1; - frameState.animate = true; - } +/** + * @const + * @type {number} + */ +goog.webgl.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; - } - this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); - var tileTextureQueue = mapRenderer.getTileTextureQueue(); - this.manageTilePyramid( - frameState, tileSource, tileGrid, pixelRatio, projection, extent, z, - tileLayer.getPreload(), - /** - * @param {ol.Tile} tile Tile. - */ - function(tile) { - if (tile.getState() == ol.TileState.LOADED && - !mapRenderer.isTileTextureLoaded(tile) && - !tileTextureQueue.isKeyQueued(tile.getKey())) { - tileTextureQueue.enqueue([ - tile, - tileGrid.getTileCoordCenter(tile.tileCoord), - tileGrid.getResolution(tile.tileCoord[0]), - tilePixelSize, tileGutter * pixelRatio - ]); - } - }, this); - this.scheduleExpireCache(frameState, tileSource); - this.updateLogos(frameState, tileSource); +/** + * @const + * @type {number} + */ +goog.webgl.MAX_VARYING_VECTORS = 0x8DFC; - var texCoordMatrix = this.texCoordMatrix; - goog.vec.Mat4.makeIdentity(texCoordMatrix); - goog.vec.Mat4.translate(texCoordMatrix, - (center[0] - framebufferExtent[0]) / - (framebufferExtent[2] - framebufferExtent[0]), - (center[1] - framebufferExtent[1]) / - (framebufferExtent[3] - framebufferExtent[1]), - 0); - if (viewState.rotation !== 0) { - goog.vec.Mat4.rotateZ(texCoordMatrix, viewState.rotation); - } - goog.vec.Mat4.scale(texCoordMatrix, - frameState.size[0] * viewState.resolution / - (framebufferExtent[2] - framebufferExtent[0]), - frameState.size[1] * viewState.resolution / - (framebufferExtent[3] - framebufferExtent[1]), - 1); - goog.vec.Mat4.translate(texCoordMatrix, - -0.5, - -0.5, - 0); - return true; -}; +/** + * @const + * @type {number} + */ +goog.webgl.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - if (!this.framebuffer) { - return undefined; - } - - var pixelOnMapScaled = [ - pixel[0] / frameState.size[0], - (frameState.size[1] - pixel[1]) / frameState.size[1]]; +goog.webgl.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; - var pixelOnFrameBufferScaled = [0, 0]; - ol.vec.Mat4.multVec2( - this.texCoordMatrix, pixelOnMapScaled, pixelOnFrameBufferScaled); - var pixelOnFrameBuffer = [ - pixelOnFrameBufferScaled[0] * this.framebufferDimension, - pixelOnFrameBufferScaled[1] * this.framebufferDimension]; - var gl = this.mapRenderer.getContext().getGL(); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); - var imageData = new Uint8Array(4); - gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, - gl.RGBA, gl.UNSIGNED_BYTE, imageData); +/** + * @const + * @type {number} + */ +goog.webgl.MAX_TEXTURE_IMAGE_UNITS = 0x8872; - if (imageData[3] > 0) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } -}; -goog.provide('ol.renderer.webgl.VectorLayer'); +/** + * @const + * @type {number} + */ +goog.webgl.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('ol.ViewHint'); -goog.require('ol.extent'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.webgl.ReplayGroup'); -goog.require('ol.renderer.vector'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.vec.Mat4'); +/** + * @const + * @type {number} + */ +goog.webgl.SHADER_TYPE = 0x8B4F; /** - * @constructor - * @extends {ol.renderer.webgl.Layer} - * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. - * @param {ol.layer.Vector} vectorLayer Vector layer. + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) { - - goog.base(this, mapRenderer, vectorLayer); +goog.webgl.DELETE_STATUS = 0x8B80; - /** - * @private - * @type {boolean} - */ - this.dirty_ = false; - /** - * @private - * @type {number} - */ - this.renderedRevision_ = -1; +/** + * @const + * @type {number} + */ +goog.webgl.LINK_STATUS = 0x8B82; - /** - * @private - * @type {number} - */ - this.renderedResolution_ = NaN; - /** - * @private - * @type {ol.Extent} - */ - this.renderedExtent_ = ol.extent.createEmpty(); +/** + * @const + * @type {number} + */ +goog.webgl.VALIDATE_STATUS = 0x8B83; - /** - * @private - * @type {function(ol.Feature, ol.Feature): number|null} - */ - this.renderedRenderOrder_ = null; - /** - * @private - * @type {ol.render.webgl.ReplayGroup} - */ - this.replayGroup_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.ATTACHED_SHADERS = 0x8B85; - /** - * The last layer state. - * @private - * @type {?ol.layer.LayerState} - */ - this.layerState_ = null; -}; -goog.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer); +/** + * @const + * @type {number} + */ +goog.webgl.ACTIVE_UNIFORMS = 0x8B86; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.composeFrame = - function(frameState, layerState, context) { - this.layerState_ = layerState; - var viewState = frameState.viewState; - var replayGroup = this.replayGroup_; - if (replayGroup && !replayGroup.isEmpty()) { - replayGroup.replay(context, - viewState.center, viewState.resolution, viewState.rotation, - frameState.size, frameState.pixelRatio, layerState.opacity, - layerState.managed ? frameState.skippedFeatureUids : {}); - } +goog.webgl.ACTIVE_ATTRIBUTES = 0x8B89; -}; + +/** + * @const + * @type {number} + */ +goog.webgl.SHADING_LANGUAGE_VERSION = 0x8B8C; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() { - var replayGroup = this.replayGroup_; - if (replayGroup) { - var context = this.mapRenderer.getContext(); - replayGroup.getDeleteResourcesFunction(context)(); - this.replayGroup_ = null; - } - goog.base(this, 'disposeInternal'); -}; +goog.webgl.CURRENT_PROGRAM = 0x8B8D; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg) { - if (!this.replayGroup_ || !this.layerState_) { - return undefined; - } else { - var context = this.mapRenderer.getContext(); - var viewState = frameState.viewState; - var layer = this.getLayer(); - var layerState = this.layerState_; - /** @type {Object.<string, boolean>} */ - var features = {}; - return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, - context, viewState.center, viewState.resolution, viewState.rotation, - frameState.size, frameState.pixelRatio, layerState.opacity, - layerState.managed ? frameState.skippedFeatureUids : {}, - /** - * @param {ol.Feature} feature Feature. - * @return {?} Callback result. - */ - function(feature) { - goog.asserts.assert(feature !== undefined, 'received a feature'); - var key = goog.getUid(feature).toString(); - if (!(key in features)) { - features[key] = true; - return callback.call(thisArg, feature, layer); - } - }); - } -}; +goog.webgl.NEVER = 0x0200; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState) { - if (!this.replayGroup_ || !this.layerState_) { - return false; - } else { - var context = this.mapRenderer.getContext(); - var viewState = frameState.viewState; - var layerState = this.layerState_; - return this.replayGroup_.hasFeatureAtCoordinate(coordinate, - context, viewState.center, viewState.resolution, viewState.rotation, - frameState.size, frameState.pixelRatio, layerState.opacity, - frameState.skippedFeatureUids); - } -}; +goog.webgl.LESS = 0x0201; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg) { - var coordinate = pixel.slice(); - ol.vec.Mat4.multVec2( - frameState.pixelToCoordinateMatrix, coordinate, coordinate); - var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState); - - if (hasFeature) { - return callback.call(thisArg, this.getLayer()); - } else { - return undefined; - } -}; +goog.webgl.EQUAL = 0x0202; /** - * Handle changes in image style state. - * @param {goog.events.Event} event Image style change event. - * @private + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.handleStyleImageChange_ = - function(event) { - this.renderIfReadyAndVisible(); -}; +goog.webgl.LEQUAL = 0x0203; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.prepareFrame = - function(frameState, layerState, context) { - - var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); - goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, - 'layer is an instance of ol.layer.Vector'); - var vectorSource = vectorLayer.getSource(); +goog.webgl.GREATER = 0x0204; - this.updateAttributions( - frameState.attributions, vectorSource.getAttributions()); - this.updateLogos(frameState, vectorSource); - var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; - var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; - var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); - var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); +/** + * @const + * @type {number} + */ +goog.webgl.NOTEQUAL = 0x0205; - if (!this.dirty_ && (!updateWhileAnimating && animating) || - (!updateWhileInteracting && interacting)) { - return true; - } - var frameStateExtent = frameState.extent; - var viewState = frameState.viewState; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var vectorLayerRevision = vectorLayer.getRevision(); - var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); - var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); +/** + * @const + * @type {number} + */ +goog.webgl.GEQUAL = 0x0206; - if (vectorLayerRenderOrder === undefined) { - vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; - } - var extent = ol.extent.buffer(frameStateExtent, - vectorLayerRenderBuffer * resolution); +/** + * @const + * @type {number} + */ +goog.webgl.ALWAYS = 0x0207; - if (!this.dirty_ && - this.renderedResolution_ == resolution && - this.renderedRevision_ == vectorLayerRevision && - this.renderedRenderOrder_ == vectorLayerRenderOrder && - ol.extent.containsExtent(this.renderedExtent_, extent)) { - return true; - } - if (this.replayGroup_) { - frameState.postRenderFunctions.push( - this.replayGroup_.getDeleteResourcesFunction(context)); - } +/** + * @const + * @type {number} + */ +goog.webgl.KEEP = 0x1E00; - this.dirty_ = false; - var replayGroup = new ol.render.webgl.ReplayGroup( - ol.renderer.vector.getTolerance(resolution, pixelRatio), - extent, vectorLayer.getRenderBuffer()); - vectorSource.loadFeatures(extent, resolution, projection); - var renderFeature = - /** - * @param {ol.Feature} feature Feature. - * @this {ol.renderer.webgl.VectorLayer} - */ - function(feature) { - var styles; - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - styles = styleFunction.call(feature, resolution); - } else { - styleFunction = vectorLayer.getStyleFunction(); - if (styleFunction) { - styles = styleFunction(feature, resolution); - } - } - if (styles) { - var dirty = this.renderFeature( - feature, resolution, pixelRatio, styles, replayGroup); - this.dirty_ = this.dirty_ || dirty; - } - }; - if (vectorLayerRenderOrder) { - /** @type {Array.<ol.Feature>} */ - var features = []; - vectorSource.forEachFeatureInExtent(extent, - /** - * @param {ol.Feature} feature Feature. - */ - function(feature) { - features.push(feature); - }, this); - goog.array.sort(features, vectorLayerRenderOrder); - features.forEach(renderFeature, this); - } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); - } - replayGroup.finish(context); +/** + * @const + * @type {number} + */ +goog.webgl.REPLACE = 0x1E01; - this.renderedResolution_ = resolution; - this.renderedRevision_ = vectorLayerRevision; - this.renderedRenderOrder_ = vectorLayerRenderOrder; - this.renderedExtent_ = extent; - this.replayGroup_ = replayGroup; - return true; -}; +/** + * @const + * @type {number} + */ +goog.webgl.INCR = 0x1E02; /** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of - * styles. - * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group. - * @return {boolean} `true` if an image is loading. + * @const + * @type {number} */ -ol.renderer.webgl.VectorLayer.prototype.renderFeature = - function(feature, resolution, pixelRatio, styles, replayGroup) { - if (!styles) { - return false; - } - var loading = false; - if (goog.isArray(styles)) { - for (var i = 0, ii = styles.length; i < ii; ++i) { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles[i], - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - } else { - loading = ol.renderer.vector.renderFeature( - replayGroup, feature, styles, - ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), - this.handleStyleImageChange_, this) || loading; - } - return loading; -}; - -// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE) +goog.webgl.DECR = 0x1E03; -goog.provide('ol.renderer.webgl.Map'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.log'); -goog.require('goog.log.Logger'); -goog.require('goog.object'); -goog.require('goog.style'); -goog.require('goog.webgl'); -goog.require('ol'); -goog.require('ol.RendererType'); -goog.require('ol.css'); -goog.require('ol.dom'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Layer'); -goog.require('ol.layer.Tile'); -goog.require('ol.layer.Vector'); -goog.require('ol.render.Event'); -goog.require('ol.render.EventType'); -goog.require('ol.render.webgl.Immediate'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.webgl.ImageLayer'); -goog.require('ol.renderer.webgl.Layer'); -goog.require('ol.renderer.webgl.TileLayer'); -goog.require('ol.renderer.webgl.VectorLayer'); -goog.require('ol.source.State'); -goog.require('ol.structs.LRUCache'); -goog.require('ol.structs.PriorityQueue'); -goog.require('ol.webgl'); -goog.require('ol.webgl.Context'); -goog.require('ol.webgl.WebGLContextEventType'); +/** + * @const + * @type {number} + */ +goog.webgl.INVERT = 0x150A; /** - * @typedef {{magFilter: number, minFilter: number, texture: WebGLTexture}} + * @const + * @type {number} */ -ol.renderer.webgl.TextureCacheEntry; - +goog.webgl.INCR_WRAP = 0x8507; /** - * @constructor - * @extends {ol.renderer.Map} - * @param {Element} container Container. - * @param {ol.Map} map Map. + * @const + * @type {number} */ -ol.renderer.webgl.Map = function(container, map) { +goog.webgl.DECR_WRAP = 0x8508; - goog.base(this, container, map); - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - this.canvas_.style.width = '100%'; - this.canvas_.style.height = '100%'; - this.canvas_.className = ol.css.CLASS_UNSELECTABLE; - goog.dom.insertChildAt(container, this.canvas_, 0); +/** + * @const + * @type {number} + */ +goog.webgl.VENDOR = 0x1F00; - /** - * @private - * @type {number} - */ - this.clipTileCanvasWidth_ = 0; - /** - * @private - * @type {number} - */ - this.clipTileCanvasHeight_ = 0; +/** + * @const + * @type {number} + */ +goog.webgl.RENDERER = 0x1F01; - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.clipTileContext_ = ol.dom.createCanvasContext2D(); - /** - * @private - * @type {boolean} - */ - this.renderedVisible_ = true; +/** + * @const + * @type {number} + */ +goog.webgl.VERSION = 0x1F02; - /** - * @private - * @type {WebGLRenderingContext} - */ - this.gl_ = ol.webgl.getContext(this.canvas_, { - antialias: true, - depth: false, - failIfMajorPerformanceCaveat: true, - preserveDrawingBuffer: false, - stencil: true - }); - goog.asserts.assert(this.gl_, 'got a WebGLRenderingContext'); - /** - * @private - * @type {ol.webgl.Context} - */ - this.context_ = new ol.webgl.Context(this.canvas_, this.gl_); +/** + * @const + * @type {number} + */ +goog.webgl.NEAREST = 0x2600; - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST, - this.handleWebGLContextLost, false, this); - goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED, - this.handleWebGLContextRestored, false, this); - /** - * @private - * @type {ol.structs.LRUCache.<ol.renderer.webgl.TextureCacheEntry|null>} - */ - this.textureCache_ = new ol.structs.LRUCache(); +/** + * @const + * @type {number} + */ +goog.webgl.LINEAR = 0x2601; - /** - * @private - * @type {ol.Coordinate} - */ - this.focus_ = null; - /** - * @private - * @type {ol.structs.PriorityQueue.<Array>} - */ - this.tileTextureQueue_ = new ol.structs.PriorityQueue( - goog.bind( - /** - * @param {Array.<*>} element Element. - * @return {number} Priority. - * @this {ol.renderer.webgl.Map} - */ - function(element) { - var tileCenter = /** @type {ol.Coordinate} */ (element[1]); - var tileResolution = /** @type {number} */ (element[2]); - var deltaX = tileCenter[0] - this.focus_[0]; - var deltaY = tileCenter[1] - this.focus_[1]; - return 65536 * Math.log(tileResolution) + - Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution; - }, this), - /** - * @param {Array.<*>} element Element. - * @return {string} Key. - */ - function(element) { - return /** @type {ol.Tile} */ (element[0]).getKey(); - }); +/** + * @const + * @type {number} + */ +goog.webgl.NEAREST_MIPMAP_NEAREST = 0x2700; - /** - * @private - * @type {ol.PostRenderFunction} - */ - this.loadNextTileTexture_ = goog.bind( - function(map, frameState) { - if (!this.tileTextureQueue_.isEmpty()) { - this.tileTextureQueue_.reprioritize(); - var element = this.tileTextureQueue_.dequeue(); - var tile = /** @type {ol.Tile} */ (element[0]); - var tileSize = /** @type {ol.Size} */ (element[3]); - var tileGutter = /** @type {number} */ (element[4]); - this.bindTileTexture( - tile, tileSize, tileGutter, goog.webgl.LINEAR, goog.webgl.LINEAR); - } - }, this); - /** - * @private - * @type {number} - */ - this.textureCacheFrameMarkerCount_ = 0; +/** + * @const + * @type {number} + */ +goog.webgl.LINEAR_MIPMAP_NEAREST = 0x2701; - this.initializeGL_(); -}; -goog.inherits(ol.renderer.webgl.Map, ol.renderer.Map); +/** + * @const + * @type {number} + */ +goog.webgl.NEAREST_MIPMAP_LINEAR = 0x2702; /** - * @param {ol.Tile} tile Tile. - * @param {ol.Size} tileSize Tile size. - * @param {number} tileGutter Tile gutter. - * @param {number} magFilter Mag filter. - * @param {number} minFilter Min filter. + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.bindTileTexture = - function(tile, tileSize, tileGutter, magFilter, minFilter) { - var gl = this.getGL(); - var tileKey = tile.getKey(); - if (this.textureCache_.containsKey(tileKey)) { - var textureCacheEntry = this.textureCache_.get(tileKey); - goog.asserts.assert(textureCacheEntry, - 'a texture cache entry exists for key %s', tileKey); - gl.bindTexture(goog.webgl.TEXTURE_2D, textureCacheEntry.texture); - if (textureCacheEntry.magFilter != magFilter) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter); - textureCacheEntry.magFilter = magFilter; - } - if (textureCacheEntry.minFilter != minFilter) { - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, minFilter); - textureCacheEntry.minFilter = minFilter; - } - } else { - var texture = gl.createTexture(); - gl.bindTexture(goog.webgl.TEXTURE_2D, texture); - if (tileGutter > 0) { - var clipTileCanvas = this.clipTileContext_.canvas; - var clipTileContext = this.clipTileContext_; - if (this.clipTileCanvasWidth_ !== tileSize[0] || - this.clipTileCanvasHeight_ !== tileSize[1]) { - clipTileCanvas.width = tileSize[0]; - clipTileCanvas.height = tileSize[1]; - this.clipTileCanvasWidth_ = tileSize[0]; - this.clipTileCanvasHeight_ = tileSize[1]; - } else { - clipTileContext.clearRect(0, 0, tileSize[0], tileSize[1]); - } - clipTileContext.drawImage(tile.getImage(), tileGutter, tileGutter, - tileSize[0], tileSize[1], 0, 0, tileSize[0], tileSize[1]); - gl.texImage2D(goog.webgl.TEXTURE_2D, 0, - goog.webgl.RGBA, goog.webgl.RGBA, - goog.webgl.UNSIGNED_BYTE, clipTileCanvas); - } else { - gl.texImage2D(goog.webgl.TEXTURE_2D, 0, - goog.webgl.RGBA, goog.webgl.RGBA, - goog.webgl.UNSIGNED_BYTE, tile.getImage()); - } - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter); - gl.texParameteri( - goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER, minFilter); - gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, - goog.webgl.CLAMP_TO_EDGE); - gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, - goog.webgl.CLAMP_TO_EDGE); - this.textureCache_.set(tileKey, { - texture: texture, - magFilter: magFilter, - minFilter: minFilter - }); - } -}; +goog.webgl.LINEAR_MIPMAP_LINEAR = 0x2703; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) { - if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { - return new ol.renderer.webgl.ImageLayer(this, layer); - } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { - return new ol.renderer.webgl.TileLayer(this, layer); - } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { - return new ol.renderer.webgl.VectorLayer(this, layer); - } else { - goog.asserts.fail('unexpected layer configuration'); - return null; - } -}; +goog.webgl.TEXTURE_MAG_FILTER = 0x2800; /** - * @param {ol.render.EventType} type Event type. - * @param {olx.FrameState} frameState Frame state. - * @private + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ = - function(type, frameState) { - var map = this.getMap(); - if (map.hasListener(type)) { - var context = this.context_; +goog.webgl.TEXTURE_MIN_FILTER = 0x2801; - var extent = frameState.extent; - var size = frameState.size; - var viewState = frameState.viewState; - var pixelRatio = frameState.pixelRatio; - var resolution = viewState.resolution; - var center = viewState.center; - var rotation = viewState.rotation; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE_WRAP_S = 0x2802; - var vectorContext = new ol.render.webgl.Immediate(context, - center, resolution, rotation, size, extent, pixelRatio); - var composeEvent = new ol.render.Event(type, map, vectorContext, - frameState, null, context); - map.dispatchEvent(composeEvent); - vectorContext.flush(); - } -}; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE_WRAP_T = 0x2803; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.disposeInternal = function() { - var gl = this.getGL(); - if (!gl.isContextLost()) { - this.textureCache_.forEach( - /** - * @param {?ol.renderer.webgl.TextureCacheEntry} textureCacheEntry - * Texture cache entry. - */ - function(textureCacheEntry) { - if (textureCacheEntry) { - gl.deleteTexture(textureCacheEntry.texture); - } - }); - } - goog.dispose(this.context_); - goog.base(this, 'disposeInternal'); -}; +goog.webgl.TEXTURE_2D = 0x0DE1; /** - * @param {ol.Map} map Map. - * @param {olx.FrameState} frameState Frame state. - * @private + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.expireCache_ = function(map, frameState) { - var gl = this.getGL(); - var textureCacheEntry; - while (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ > - ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) { - textureCacheEntry = this.textureCache_.peekLast(); - if (!textureCacheEntry) { - if (+this.textureCache_.peekLastKey() == frameState.index) { - break; - } else { - --this.textureCacheFrameMarkerCount_; - } - } else { - gl.deleteTexture(textureCacheEntry.texture); - } - this.textureCache_.pop(); - } -}; +goog.webgl.TEXTURE = 0x1702; /** - * @return {ol.webgl.Context} + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.getContext = function() { - return this.context_; -}; +goog.webgl.TEXTURE_CUBE_MAP = 0x8513; /** - * @return {WebGLRenderingContext} GL. + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.getGL = function() { - return this.gl_; -}; +goog.webgl.TEXTURE_BINDING_CUBE_MAP = 0x8514; /** - * @return {ol.structs.PriorityQueue.<Array>} Tile texture queue. + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.getTileTextureQueue = function() { - return this.tileTextureQueue_; -}; +goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.getType = function() { - return ol.RendererType.WEBGL; -}; +goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; /** - * @param {goog.events.Event} event Event. - * @protected + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.handleWebGLContextLost = function(event) { - event.preventDefault(); - this.textureCache_.clear(); - this.textureCacheFrameMarkerCount_ = 0; - goog.object.forEach(this.getLayerRenderers(), - /** - * @param {ol.renderer.Layer} layerRenderer Layer renderer. - * @param {string} key Key. - * @param {Object.<string, ol.renderer.Layer>} object Object. - */ - function(layerRenderer, key, object) { - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, - 'renderer is an instance of ol.renderer.webgl.Layer'); - layerRenderer.handleWebGLContextLost(); - }); -}; +goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; /** - * @protected + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.handleWebGLContextRestored = function() { - this.initializeGL_(); - this.getMap().render(); -}; +goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; /** - * @private + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.initializeGL_ = function() { - var gl = this.gl_; - gl.activeTexture(goog.webgl.TEXTURE0); - gl.blendFuncSeparate( - goog.webgl.SRC_ALPHA, goog.webgl.ONE_MINUS_SRC_ALPHA, - goog.webgl.ONE, goog.webgl.ONE_MINUS_SRC_ALPHA); - gl.disable(goog.webgl.CULL_FACE); - gl.disable(goog.webgl.DEPTH_TEST); - gl.disable(goog.webgl.SCISSOR_TEST); - gl.disable(goog.webgl.STENCIL_TEST); -}; +goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; /** - * @param {ol.Tile} tile Tile. - * @return {boolean} Is tile texture loaded. + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) { - return this.textureCache_.containsKey(tile.getKey()); -}; +goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; /** - * @private - * @type {goog.log.Logger} + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.logger_ = - goog.log.getLogger('ol.renderer.webgl.Map'); +goog.webgl.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { +goog.webgl.TEXTURE0 = 0x84C0; - var context = this.getContext(); - var gl = this.getGL(); - if (gl.isContextLost()) { - return false; - } +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE1 = 0x84C1; - if (!frameState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, false); - this.renderedVisible_ = false; - } - return false; - } - this.focus_ = frameState.focus; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE2 = 0x84C2; - this.textureCache_.set((-frameState.index).toString(), null); - ++this.textureCacheFrameMarkerCount_; - this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE3 = 0x84C3; - /** @type {Array.<ol.layer.LayerState>} */ - var layerStatesToDraw = []; - var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); - var viewResolution = frameState.viewState.resolution; - var i, ii, layerRenderer, layerState; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerState = layerStatesArray[i]; - if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && - layerState.sourceState == ol.source.State.READY) { - layerRenderer = this.getLayerRenderer(layerState.layer); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, - 'renderer is an instance of ol.renderer.webgl.Layer'); - if (layerRenderer.prepareFrame(frameState, layerState, context)) { - layerStatesToDraw.push(layerState); - } - } - } +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE4 = 0x84C4; - var width = frameState.size[0] * frameState.pixelRatio; - var height = frameState.size[1] * frameState.pixelRatio; - if (this.canvas_.width != width || this.canvas_.height != height) { - this.canvas_.width = width; - this.canvas_.height = height; - } - gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, null); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE5 = 0x84C5; - gl.clearColor(0, 0, 0, 0); - gl.clear(goog.webgl.COLOR_BUFFER_BIT); - gl.enable(goog.webgl.BLEND); - gl.viewport(0, 0, this.canvas_.width, this.canvas_.height); - for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) { - layerState = layerStatesToDraw[i]; - layerRenderer = this.getLayerRenderer(layerState.layer); - goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, - 'renderer is an instance of ol.renderer.webgl.Layer'); - layerRenderer.composeFrame(frameState, layerState, context); - } +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE6 = 0x84C6; - if (!this.renderedVisible_) { - goog.style.setElementShown(this.canvas_, true); - this.renderedVisible_ = true; - } - this.calculateMatrices2D(frameState); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE7 = 0x84C7; - if (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ > - ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) { - frameState.postRenderFunctions.push(goog.bind(this.expireCache_, this)); - } - if (!this.tileTextureQueue_.isEmpty()) { - frameState.postRenderFunctions.push(this.loadNextTileTexture_); - frameState.animate = true; - } +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE8 = 0x84C8; - this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState); - this.scheduleRemoveUnusedLayerRenderers(frameState); - this.scheduleExpireIconCache(frameState); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE9 = 0x84C9; -}; + +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE10 = 0x84CA; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate = - function(coordinate, frameState, callback, thisArg, - layerFilter, thisArg2) { - var result; +goog.webgl.TEXTURE11 = 0x84CB; - if (this.getGL().isContextLost()) { - return false; - } - var viewState = frameState.viewState; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE12 = 0x84CC; - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && - layerFilter.call(thisArg2, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - result = layerRenderer.forEachFeatureAtCoordinate( - coordinate, frameState, callback, thisArg); - if (result) { - return result; - } - } - } - return undefined; -}; + +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE13 = 0x84CD; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate = - function(coordinate, frameState, layerFilter, thisArg) { - var hasFeature = false; +goog.webgl.TEXTURE14 = 0x84CE; - if (this.getGL().isContextLost()) { - return false; - } - var viewState = frameState.viewState; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE15 = 0x84CF; - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && - layerFilter.call(thisArg, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - hasFeature = - layerRenderer.hasFeatureAtCoordinate(coordinate, frameState); - if (hasFeature) { - return true; - } - } - } - return hasFeature; -}; + +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE16 = 0x84D0; /** - * @inheritDoc + * @const + * @type {number} */ -ol.renderer.webgl.Map.prototype.forEachLayerAtPixel = - function(pixel, frameState, callback, thisArg, - layerFilter, thisArg2) { - if (this.getGL().isContextLost()) { - return false; - } +goog.webgl.TEXTURE17 = 0x84D1; - var viewState = frameState.viewState; - var result; - var layerStates = frameState.layerStatesArray; - var numLayers = layerStates.length; - var i; - for (i = numLayers - 1; i >= 0; --i) { - var layerState = layerStates[i]; - var layer = layerState.layer; - if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && - layerFilter.call(thisArg, layer)) { - var layerRenderer = this.getLayerRenderer(layer); - result = layerRenderer.forEachLayerAtPixel( - pixel, frameState, callback, thisArg); - if (result) { - return result; - } - } - } - return undefined; -}; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE18 = 0x84D2; -// FIXME recheck layer/map projection compatibility when projection changes -// FIXME layer renderers should skip when they can't reproject -// FIXME add tilt and height? -goog.provide('ol.Map'); -goog.provide('ol.MapProperty'); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE19 = 0x84D3; -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.async.AnimationDelay'); -goog.require('goog.async.nextTick'); -goog.require('goog.debug.Console'); -goog.require('goog.dom'); -goog.require('goog.dom.ViewportSizeMonitor'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.events.KeyHandler'); -goog.require('goog.events.KeyHandler.EventType'); -goog.require('goog.events.MouseWheelHandler'); -goog.require('goog.events.MouseWheelHandler.EventType'); -goog.require('goog.functions'); -goog.require('goog.log'); -goog.require('goog.log.Level'); -goog.require('goog.object'); -goog.require('goog.style'); -goog.require('goog.vec.Mat4'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEventType'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserEventHandler'); -goog.require('ol.MapEvent'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); -goog.require('ol.ObjectEvent'); -goog.require('ol.ObjectEventType'); -goog.require('ol.Pixel'); -goog.require('ol.PostRenderFunction'); -goog.require('ol.PreRenderFunction'); -goog.require('ol.RendererType'); -goog.require('ol.Size'); -goog.require('ol.TileQueue'); -goog.require('ol.View'); -goog.require('ol.ViewHint'); -goog.require('ol.control'); -goog.require('ol.extent'); -goog.require('ol.has'); -goog.require('ol.interaction'); -goog.require('ol.layer.Base'); -goog.require('ol.layer.Group'); -goog.require('ol.proj'); -goog.require('ol.proj.common'); -goog.require('ol.renderer.Map'); -goog.require('ol.renderer.canvas.Map'); -goog.require('ol.renderer.dom.Map'); -goog.require('ol.renderer.webgl.Map'); -goog.require('ol.size'); -goog.require('ol.structs.PriorityQueue'); -goog.require('ol.tilecoord'); -goog.require('ol.vec.Mat4'); + +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE20 = 0x84D4; /** * @const - * @type {string} + * @type {number} */ -ol.OL3_URL = 'http://openlayers.org/'; +goog.webgl.TEXTURE21 = 0x84D5; /** * @const - * @type {string} + * @type {number} */ -ol.OL3_LOGO_URL = 'data:image/png;base64,' + - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBI' + - 'WXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAA' + - 'AhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszW' + - 'WMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvY' + - 'asvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvX' + - 'H1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1Vk' + - 'bMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW' + - '2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLP' + - 'VcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqT' + - 'acrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaar' + - 'ldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+Hi' + - 'zeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDn' + - 'BAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSF' + - 'hYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJ' + - 'REFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxC' + - 'Brb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe' + - '0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8' + - 'a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7a' + - 'hgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCn' + - 'B3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDg' + - 'q82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC'; +goog.webgl.TEXTURE22 = 0x84D6; /** - * @type {Array.<ol.RendererType>} * @const + * @type {number} */ -ol.DEFAULT_RENDERER_TYPES = [ - ol.RendererType.CANVAS, - ol.RendererType.WEBGL, - ol.RendererType.DOM -]; +goog.webgl.TEXTURE23 = 0x84D7; /** - * @enum {string} + * @const + * @type {number} */ -ol.MapProperty = { - LAYERGROUP: 'layergroup', - SIZE: 'size', - TARGET: 'target', - VIEW: 'view' -}; +goog.webgl.TEXTURE24 = 0x84D8; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE25 = 0x84D9; + /** - * @classdesc - * The map is the core component of OpenLayers. For a map to render, a view, - * one or more layers, and a target container are needed: - * - * var map = new ol.Map({ - * view: new ol.View({ - * center: [0, 0], - * zoom: 1 - * }), - * layers: [ - * new ol.layer.Tile({ - * source: new ol.source.MapQuest({layer: 'osm'}) - * }) - * ], - * target: 'map' - * }); - * - * The above snippet creates a map using a {@link ol.layer.Tile} to display - * {@link ol.source.MapQuest} OSM data and render it to a DOM element with the - * id `map`. - * - * The constructor places a viewport container (with CSS class name - * `ol-viewport`) in the target element (see `getViewport()`), and then two - * further elements within the viewport: one with CSS class name - * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with - * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent` - * option of {@link ol.Overlay} for the difference). The map itself is placed in - * a further element within the viewport, either DOM or Canvas, depending on the - * renderer. - * - * Layers are stored as a `ol.Collection` in layerGroups. A top-level group is - * provided by the library. This is what is accessed by `getLayerGroup` and - * `setLayerGroup`. Layers entered in the options are added to this group, and - * `addLayer` and `removeLayer` change the layer collection in the group. - * `getLayers` is a convenience function for `getLayerGroup().getLayers()`. - * Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers - * entered in the options or added with `addLayer` can be groups, which can - * contain further groups, and so on. - * - * @constructor - * @extends {ol.Object} - * @param {olx.MapOptions} options Map options. - * @fires ol.MapBrowserEvent - * @fires ol.MapEvent - * @fires ol.render.Event#postcompose - * @fires ol.render.Event#precompose - * @api stable + * @const + * @type {number} */ -ol.Map = function(options) { +goog.webgl.TEXTURE26 = 0x84DA; - goog.base(this); - var optionsInternal = ol.Map.createOptionsInternal(options); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE27 = 0x84DB; - /** - * @type {boolean} - * @private - */ - this.loadTilesWhileAnimating_ = - options.loadTilesWhileAnimating !== undefined ? - options.loadTilesWhileAnimating : false; - /** - * @type {boolean} - * @private - */ - this.loadTilesWhileInteracting_ = - options.loadTilesWhileInteracting !== undefined ? - options.loadTilesWhileInteracting : false; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE28 = 0x84DC; - /** - * @private - * @type {number} - */ - this.pixelRatio_ = options.pixelRatio !== undefined ? - options.pixelRatio : ol.has.DEVICE_PIXEL_RATIO; - /** - * @private - * @type {Object.<string, string>} - */ - this.logos_ = optionsInternal.logos; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE29 = 0x84DD; - /** - * @private - * @type {goog.async.AnimationDelay} - */ - this.animationDelay_ = - new goog.async.AnimationDelay(this.renderFrame_, undefined, this); - this.registerDisposable(this.animationDelay_); - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber(); +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE30 = 0x84DE; - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber(); - /** - * @private - * @type {number} - */ - this.frameIndex_ = 0; +/** + * @const + * @type {number} + */ +goog.webgl.TEXTURE31 = 0x84DF; - /** - * @private - * @type {?olx.FrameState} - */ - this.frameState_ = null; - /** - * The extent at the previous 'moveend' event. - * @private - * @type {ol.Extent} - */ - this.previousExtent_ = ol.extent.createEmpty(); +/** + * @const + * @type {number} + */ +goog.webgl.ACTIVE_TEXTURE = 0x84E0; - /** - * @private - * @type {goog.events.Key} - */ - this.viewPropertyListenerKey_ = null; - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.layerGroupPropertyListenerKeys_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.REPEAT = 0x2901; - /** - * @private - * @type {Element} - */ - this.viewport_ = goog.dom.createDom('DIV', 'ol-viewport'); - this.viewport_.style.position = 'relative'; - this.viewport_.style.overflow = 'hidden'; - this.viewport_.style.width = '100%'; - this.viewport_.style.height = '100%'; - // prevent page zoom on IE >= 10 browsers - this.viewport_.style.msTouchAction = 'none'; - this.viewport_.style.touchAction = 'none'; - if (ol.has.TOUCH) { - goog.dom.classlist.add(this.viewport_, 'ol-touch'); - } - /** - * @private - * @type {Element} - */ - this.overlayContainer_ = goog.dom.createDom('DIV', - 'ol-overlaycontainer'); - this.viewport_.appendChild(this.overlayContainer_); +/** + * @const + * @type {number} + */ +goog.webgl.CLAMP_TO_EDGE = 0x812F; - /** - * @private - * @type {Element} - */ - this.overlayContainerStopEvent_ = goog.dom.createDom('DIV', - 'ol-overlaycontainer-stopevent'); - goog.events.listen(this.overlayContainerStopEvent_, [ - goog.events.EventType.CLICK, - goog.events.EventType.DBLCLICK, - goog.events.EventType.MOUSEDOWN, - goog.events.EventType.TOUCHSTART, - goog.events.EventType.MSPOINTERDOWN, - ol.MapBrowserEvent.EventType.POINTERDOWN, - goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel' - ], goog.events.Event.stopPropagation); - this.viewport_.appendChild(this.overlayContainerStopEvent_); - var mapBrowserEventHandler = new ol.MapBrowserEventHandler(this); - goog.events.listen(mapBrowserEventHandler, - goog.object.getValues(ol.MapBrowserEvent.EventType), - this.handleMapBrowserEvent, false, this); - this.registerDisposable(mapBrowserEventHandler); +/** + * @const + * @type {number} + */ +goog.webgl.MIRRORED_REPEAT = 0x8370; - /** - * @private - * @type {Element|Document} - */ - this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget; - /** - * @private - * @type {goog.events.KeyHandler} - */ - this.keyHandler_ = new goog.events.KeyHandler(); - goog.events.listen(this.keyHandler_, goog.events.KeyHandler.EventType.KEY, - this.handleBrowserEvent, false, this); - this.registerDisposable(this.keyHandler_); +/** + * @const + * @type {number} + */ +goog.webgl.FLOAT_VEC2 = 0x8B50; - var mouseWheelHandler = new goog.events.MouseWheelHandler(this.viewport_); - goog.events.listen(mouseWheelHandler, - goog.events.MouseWheelHandler.EventType.MOUSEWHEEL, - this.handleBrowserEvent, false, this); - this.registerDisposable(mouseWheelHandler); - /** - * @type {ol.Collection.<ol.control.Control>} - * @private - */ - this.controls_ = optionsInternal.controls; +/** + * @const + * @type {number} + */ +goog.webgl.FLOAT_VEC3 = 0x8B51; - /** - * @type {ol.Collection.<ol.interaction.Interaction>} - * @private - */ - this.interactions_ = optionsInternal.interactions; - /** - * @type {ol.Collection.<ol.Overlay>} - * @private - */ - this.overlays_ = optionsInternal.overlays; +/** + * @const + * @type {number} + */ +goog.webgl.FLOAT_VEC4 = 0x8B52; - /** - * A lookup of overlays by id. - * @private - * @type {Object.<string, ol.Overlay>} - */ - this.overlayIdIndex_ = {}; - /** - * @type {ol.renderer.Map} - * @private - */ - this.renderer_ = - new optionsInternal.rendererConstructor(this.viewport_, this); - this.registerDisposable(this.renderer_); +/** + * @const + * @type {number} + */ +goog.webgl.INT_VEC2 = 0x8B53; - /** - * @type {goog.dom.ViewportSizeMonitor} - * @private - */ - this.viewportSizeMonitor_ = new goog.dom.ViewportSizeMonitor(); - this.registerDisposable(this.viewportSizeMonitor_); - /** - * @type {goog.events.Key} - * @private - */ - this.viewportResizeListenerKey_ = null; +/** + * @const + * @type {number} + */ +goog.webgl.INT_VEC3 = 0x8B54; - /** - * @private - * @type {ol.Coordinate} - */ - this.focus_ = null; - /** - * @private - * @type {Array.<ol.PreRenderFunction>} - */ - this.preRenderFunctions_ = []; +/** + * @const + * @type {number} + */ +goog.webgl.INT_VEC4 = 0x8B55; - /** - * @private - * @type {Array.<ol.PostRenderFunction>} - */ - this.postRenderFunctions_ = []; - /** - * @private - * @type {ol.TileQueue} - */ - this.tileQueue_ = new ol.TileQueue( - goog.bind(this.getTilePriority, this), - goog.bind(this.handleTileChange_, this)); +/** + * @const + * @type {number} + */ +goog.webgl.BOOL = 0x8B56; - /** - * Uids of features to skip at rendering time. - * @type {Object.<string, boolean>} - * @private - */ - this.skippedFeatureUids_ = {}; - goog.events.listen( - this, ol.Object.getChangeEventType(ol.MapProperty.LAYERGROUP), - this.handleLayerGroupChanged_, false, this); - goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.VIEW), - this.handleViewChanged_, false, this); - goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.SIZE), - this.handleSizeChanged_, false, this); - goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.TARGET), - this.handleTargetChanged_, false, this); +/** + * @const + * @type {number} + */ +goog.webgl.BOOL_VEC2 = 0x8B57; - // setProperties will trigger the rendering of the map if the map - // is "defined" already. - this.setProperties(optionsInternal.values); - this.controls_.forEach( - /** - * @param {ol.control.Control} control Control. - * @this {ol.Map} - */ - function(control) { - control.setMap(this); - }, this); +/** + * @const + * @type {number} + */ +goog.webgl.BOOL_VEC3 = 0x8B58; - goog.events.listen(this.controls_, ol.CollectionEventType.ADD, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(this); - }, false, this); - goog.events.listen(this.controls_, ol.CollectionEventType.REMOVE, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(null); - }, false, this); +/** + * @const + * @type {number} + */ +goog.webgl.BOOL_VEC4 = 0x8B59; - this.interactions_.forEach( - /** - * @param {ol.interaction.Interaction} interaction Interaction. - * @this {ol.Map} - */ - function(interaction) { - interaction.setMap(this); - }, this); - goog.events.listen(this.interactions_, ol.CollectionEventType.ADD, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(this); - }, false, this); +/** + * @const + * @type {number} + */ +goog.webgl.FLOAT_MAT2 = 0x8B5A; - goog.events.listen(this.interactions_, ol.CollectionEventType.REMOVE, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - event.element.setMap(null); - }, false, this); - this.overlays_.forEach(this.addOverlayInternal_, this); +/** + * @const + * @type {number} + */ +goog.webgl.FLOAT_MAT3 = 0x8B5B; - goog.events.listen(this.overlays_, ol.CollectionEventType.ADD, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - this.addOverlayInternal_(/** @type {ol.Overlay} */ (event.element)); - }, false, this); - goog.events.listen(this.overlays_, ol.CollectionEventType.REMOVE, - /** - * @param {ol.CollectionEvent} event Collection event. - */ - function(event) { - var id = event.element.getId(); - if (id !== undefined) { - delete this.overlayIdIndex_[id.toString()]; - } - event.element.setMap(null); - }, false, this); +/** + * @const + * @type {number} + */ +goog.webgl.FLOAT_MAT4 = 0x8B5C; -}; -goog.inherits(ol.Map, ol.Object); + +/** + * @const + * @type {number} + */ +goog.webgl.SAMPLER_2D = 0x8B5E; /** - * Add the given control to the map. - * @param {ol.control.Control} control Control. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.addControl = function(control) { - var controls = this.getControls(); - goog.asserts.assert(controls !== undefined, 'controls should be defined'); - controls.push(control); -}; +goog.webgl.SAMPLER_CUBE = 0x8B60; /** - * Add the given interaction to the map. - * @param {ol.interaction.Interaction} interaction Interaction to add. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.addInteraction = function(interaction) { - var interactions = this.getInteractions(); - goog.asserts.assert(interactions !== undefined, - 'interactions should be defined'); - interactions.push(interaction); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622; /** - * Adds the given layer to the top of this map. If you want to add a layer - * elsewhere in the stack, use `getLayers()` and the methods available on - * {@link ol.Collection}. - * @param {ol.layer.Base} layer Layer. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.addLayer = function(layer) { - var layers = this.getLayerGroup().getLayers(); - layers.push(layer); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623; /** - * Add the given overlay to the map. - * @param {ol.Overlay} overlay Overlay. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.addOverlay = function(overlay) { - var overlays = this.getOverlays(); - goog.asserts.assert(overlays !== undefined, 'overlays should be defined'); - overlays.push(overlay); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624; /** - * This deals with map's overlay collection changes. - * @param {ol.Overlay} overlay Overlay. - * @private + * @const + * @type {number} */ -ol.Map.prototype.addOverlayInternal_ = function(overlay) { - var id = overlay.getId(); - if (id !== undefined) { - this.overlayIdIndex_[id.toString()] = overlay; - } - overlay.setMap(this); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625; /** - * Add functions to be called before rendering. This can be used for attaching - * animations before updating the map's view. The {@link ol.animation} - * namespace provides several static methods for creating prerender functions. - * @param {...ol.PreRenderFunction} var_args Any number of pre-render functions. - * @api + * @const + * @type {number} */ -ol.Map.prototype.beforeRender = function(var_args) { - this.render(); - Array.prototype.push.apply(this.preRenderFunctions_, arguments); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A; /** - * @param {ol.PreRenderFunction} preRenderFunction Pre-render function. - * @return {boolean} Whether the preRenderFunction has been found and removed. + * @const + * @type {number} */ -ol.Map.prototype.removePreRenderFunction = function(preRenderFunction) { - return goog.array.remove(this.preRenderFunctions_, preRenderFunction); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; /** - * - * @inheritDoc + * @const + * @type {number} */ -ol.Map.prototype.disposeInternal = function() { - goog.dom.removeNode(this.viewport_); - goog.base(this, 'disposeInternal'); -}; +goog.webgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; /** - * Detect features that intersect a pixel on the viewport, and execute a - * callback with each intersecting feature. Layers included in the detection can - * be configured through `opt_layerFilter`. - * @param {ol.Pixel} pixel Pixel. - * @param {function(this: S, (ol.Feature|ol.render.Feature), - * ol.layer.Layer): T} callback Feature callback. The callback will be - * called with two arguments. The first argument is one - * {@link ol.Feature feature} or - * {@link ol.render.Feature render feature} at the pixel, the second is - * the {@link ol.layer.Layer layer} of the feature and will be null for - * unmanaged layers. To stop detection, callback functions can return a - * truthy value. - * @param {S=} opt_this Value to use as `this` when executing `callback`. - * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer - * filter function. The filter function will receive one argument, the - * {@link ol.layer.Layer layer-candidate} and it should return a boolean - * value. Only layers which are visible and for which this function returns - * `true` will be tested for features. By default, all visible layers will - * be tested. - * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result, i.e. the return value of last - * callback execution, or the first truthy callback return value. - * @template S,T,U - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.forEachFeatureAtPixel = - function(pixel, callback, opt_this, opt_layerFilter, opt_this2) { - if (!this.frameState_) { - return; - } - var coordinate = this.getCoordinateFromPixel(pixel); - var thisArg = opt_this !== undefined ? opt_this : null; - var layerFilter = opt_layerFilter !== undefined ? - opt_layerFilter : goog.functions.TRUE; - var thisArg2 = opt_this2 !== undefined ? opt_this2 : null; - return this.renderer_.forEachFeatureAtCoordinate( - coordinate, this.frameState_, callback, thisArg, - layerFilter, thisArg2); -}; +goog.webgl.COMPILE_STATUS = 0x8B81; /** - * Detect layers that have a color value at a pixel on the viewport, and - * execute a callback with each matching layer. Layers included in the - * detection can be configured through `opt_layerFilter`. - * @param {ol.Pixel} pixel Pixel. - * @param {function(this: S, ol.layer.Layer): T} callback Layer - * callback. Will receive one argument, the {@link ol.layer.Layer layer} - * that contains the color pixel. To stop detection, callback functions can - * return a truthy value. - * @param {S=} opt_this Value to use as `this` when executing `callback`. - * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer - * filter function. The filter function will receive one argument, the - * {@link ol.layer.Layer layer-candidate} and it should return a boolean - * value. Only layers which are visible and for which this function returns - * `true` will be tested for features. By default, all visible layers will - * be tested. - * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`. - * @return {T|undefined} Callback result, i.e. the return value of last - * callback execution, or the first truthy callback return value. - * @template S,T,U - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.forEachLayerAtPixel = - function(pixel, callback, opt_this, opt_layerFilter, opt_this2) { - if (!this.frameState_) { - return; - } - var thisArg = opt_this !== undefined ? opt_this : null; - var layerFilter = opt_layerFilter !== undefined ? - opt_layerFilter : goog.functions.TRUE; - var thisArg2 = opt_this2 !== undefined ? opt_this2 : null; - return this.renderer_.forEachLayerAtPixel( - pixel, this.frameState_, callback, thisArg, - layerFilter, thisArg2); -}; +goog.webgl.LOW_FLOAT = 0x8DF0; /** - * Detect if features intersect a pixel on the viewport. Layers included in the - * detection can be configured through `opt_layerFilter`. - * @param {ol.Pixel} pixel Pixel. - * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer - * filter function. The filter function will receive one argument, the - * {@link ol.layer.Layer layer-candidate} and it should return a boolean - * value. Only layers which are visible and for which this function returns - * `true` will be tested for features. By default, all visible layers will - * be tested. - * @param {U=} opt_this Value to use as `this` when executing `layerFilter`. - * @return {boolean} Is there a feature at the given pixel? - * @template U - * @api + * @const + * @type {number} */ -ol.Map.prototype.hasFeatureAtPixel = - function(pixel, opt_layerFilter, opt_this) { - if (!this.frameState_) { - return false; - } - var coordinate = this.getCoordinateFromPixel(pixel); - var layerFilter = opt_layerFilter !== undefined ? - opt_layerFilter : goog.functions.TRUE; - var thisArg = opt_this !== undefined ? opt_this : null; - return this.renderer_.hasFeatureAtCoordinate( - coordinate, this.frameState_, layerFilter, thisArg); -}; +goog.webgl.MEDIUM_FLOAT = 0x8DF1; /** - * Returns the geographical coordinate for a browser event. - * @param {Event} event Event. - * @return {ol.Coordinate} Coordinate. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getEventCoordinate = function(event) { - return this.getCoordinateFromPixel(this.getEventPixel(event)); -}; +goog.webgl.HIGH_FLOAT = 0x8DF2; /** - * Returns the map pixel position for a browser event relative to the viewport. - * @param {Event} event Event. - * @return {ol.Pixel} Pixel. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getEventPixel = function(event) { - var eventPosition = goog.style.getRelativePosition(event, this.viewport_); - return [eventPosition.x, eventPosition.y]; -}; +goog.webgl.LOW_INT = 0x8DF3; /** - * Get the target in which this map is rendered. - * Note that this returns what is entered as an option or in setTarget: - * if that was an element, it returns an element; if a string, it returns that. - * @return {Element|string|undefined} The Element or id of the Element that the - * map is rendered in. - * @observable - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getTarget = function() { - return /** @type {Element|string|undefined} */ ( - this.get(ol.MapProperty.TARGET)); -}; +goog.webgl.MEDIUM_INT = 0x8DF4; /** - * Get the DOM element into which this map is rendered. In contrast to - * `getTarget` this method always return an `Element`, or `null` if the - * map has no target. - * @return {Element} The element that the map is rendered in. - * @api + * @const + * @type {number} */ -ol.Map.prototype.getTargetElement = function() { - var target = this.getTarget(); - return target !== undefined ? goog.dom.getElement(target) : null; -}; +goog.webgl.HIGH_INT = 0x8DF5; /** - * Get the coordinate for a given pixel. This returns a coordinate in the - * map view projection. - * @param {ol.Pixel} pixel Pixel position in the map viewport. - * @return {ol.Coordinate} The coordinate for the pixel position. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getCoordinateFromPixel = function(pixel) { - var frameState = this.frameState_; - if (!frameState) { - return null; - } else { - var vec2 = pixel.slice(); - return ol.vec.Mat4.multVec2(frameState.pixelToCoordinateMatrix, vec2, vec2); - } -}; +goog.webgl.FRAMEBUFFER = 0x8D40; /** - * Get the map controls. Modifying this collection changes the controls - * associated with the map. - * @return {ol.Collection.<ol.control.Control>} Controls. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getControls = function() { - return this.controls_; -}; +goog.webgl.RENDERBUFFER = 0x8D41; /** - * Get the map overlays. Modifying this collection changes the overlays - * associated with the map. - * @return {ol.Collection.<ol.Overlay>} Overlays. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getOverlays = function() { - return this.overlays_; -}; +goog.webgl.RGBA4 = 0x8056; /** - * Get an overlay by its identifier (the value returned by overlay.getId()). - * Note that the index treats string and numeric identifiers as the same. So - * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`. - * @param {string|number} id Overlay identifier. - * @return {ol.Overlay} Overlay. - * @api + * @const + * @type {number} */ -ol.Map.prototype.getOverlayById = function(id) { - var overlay = this.overlayIdIndex_[id.toString()]; - return overlay !== undefined ? overlay : null; -}; +goog.webgl.RGB5_A1 = 0x8057; /** - * Get the map interactions. Modifying this collection changes the interactions - * associated with the map. - * - * Interactions are used for e.g. pan, zoom and rotate. - * @return {ol.Collection.<ol.interaction.Interaction>} Interactions. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getInteractions = function() { - return this.interactions_; -}; +goog.webgl.RGB565 = 0x8D62; /** - * Get the layergroup associated with this map. - * @return {ol.layer.Group} A layer group containing the layers in this map. - * @observable - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getLayerGroup = function() { - return /** @type {ol.layer.Group} */ (this.get(ol.MapProperty.LAYERGROUP)); -}; +goog.webgl.DEPTH_COMPONENT16 = 0x81A5; /** - * Get the collection of layers associated with this map. - * @return {!ol.Collection.<ol.layer.Base>} Layers. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getLayers = function() { - var layers = this.getLayerGroup().getLayers(); - return layers; -}; +goog.webgl.STENCIL_INDEX = 0x1901; /** - * Get the pixel for a coordinate. This takes a coordinate in the map view - * projection and returns the corresponding pixel. - * @param {ol.Coordinate} coordinate A map coordinate. - * @return {ol.Pixel} A pixel position in the map viewport. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getPixelFromCoordinate = function(coordinate) { - var frameState = this.frameState_; - if (!frameState) { - return null; - } else { - var vec2 = coordinate.slice(0, 2); - return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2); - } -}; +goog.webgl.STENCIL_INDEX8 = 0x8D48; /** - * Get the map renderer. - * @return {ol.renderer.Map} Renderer + * @const + * @type {number} */ -ol.Map.prototype.getRenderer = function() { - return this.renderer_; -}; +goog.webgl.DEPTH_STENCIL = 0x84F9; /** - * Get the size of this map. - * @return {ol.Size|undefined} The size in pixels of the map in the DOM. - * @observable - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getSize = function() { - return /** @type {ol.Size|undefined} */ (this.get(ol.MapProperty.SIZE)); -}; +goog.webgl.RENDERBUFFER_WIDTH = 0x8D42; /** - * Get the view associated with this map. A view manages properties such as - * center and resolution. - * @return {ol.View} The view that controls this map. - * @observable - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getView = function() { - return /** @type {ol.View} */ (this.get(ol.MapProperty.VIEW)); -}; +goog.webgl.RENDERBUFFER_HEIGHT = 0x8D43; /** - * Get the element that serves as the map viewport. - * @return {Element} Viewport. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.getViewport = function() { - return this.viewport_; -}; +goog.webgl.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44; /** - * Get the element that serves as the container for overlays. Elements added to - * this container will let mousedown and touchstart events through to the map, - * so clicks and gestures on an overlay will trigger {@link ol.MapBrowserEvent} - * events. - * @return {Element} The map's overlay container. + * @const + * @type {number} */ -ol.Map.prototype.getOverlayContainer = function() { - return this.overlayContainer_; -}; +goog.webgl.RENDERBUFFER_RED_SIZE = 0x8D50; /** - * Get the element that serves as a container for overlays that don't allow - * event propagation. Elements added to this container won't let mousedown and - * touchstart events through to the map, so clicks and gestures on an overlay - * don't trigger any {@link ol.MapBrowserEvent}. - * @return {Element} The map's overlay container that stops events. + * @const + * @type {number} */ -ol.Map.prototype.getOverlayContainerStopEvent = function() { - return this.overlayContainerStopEvent_; -}; +goog.webgl.RENDERBUFFER_GREEN_SIZE = 0x8D51; /** - * @param {ol.Tile} tile Tile. - * @param {string} tileSourceKey Tile source key. - * @param {ol.Coordinate} tileCenter Tile center. - * @param {number} tileResolution Tile resolution. - * @return {number} Tile priority. + * @const + * @type {number} */ -ol.Map.prototype.getTilePriority = - function(tile, tileSourceKey, tileCenter, tileResolution) { - // Filter out tiles at higher zoom levels than the current zoom level, or that - // are outside the visible extent. - var frameState = this.frameState_; - if (!frameState || !(tileSourceKey in frameState.wantedTiles)) { - return ol.structs.PriorityQueue.DROP; - } - var coordKey = ol.tilecoord.toString(tile.tileCoord); - if (!frameState.wantedTiles[tileSourceKey][coordKey]) { - return ol.structs.PriorityQueue.DROP; - } - // Prioritize the highest zoom level tiles closest to the focus. - // Tiles at higher zoom levels are prioritized using Math.log(tileResolution). - // Within a zoom level, tiles are prioritized by the distance in pixels - // between the center of the tile and the focus. The factor of 65536 means - // that the prioritization should behave as desired for tiles up to - // 65536 * Math.log(2) = 45426 pixels from the focus. - var deltaX = tileCenter[0] - frameState.focus[0]; - var deltaY = tileCenter[1] - frameState.focus[1]; - return 65536 * Math.log(tileResolution) + - Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution; -}; +goog.webgl.RENDERBUFFER_BLUE_SIZE = 0x8D52; /** - * @param {goog.events.BrowserEvent} browserEvent Browser event. - * @param {string=} opt_type Type. + * @const + * @type {number} */ -ol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) { - var type = opt_type || browserEvent.type; - var mapBrowserEvent = new ol.MapBrowserEvent(type, this, browserEvent); - this.handleMapBrowserEvent(mapBrowserEvent); -}; +goog.webgl.RENDERBUFFER_ALPHA_SIZE = 0x8D53; /** - * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle. + * @const + * @type {number} */ -ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) { - if (!this.frameState_) { - // With no view defined, we cannot translate pixels into geographical - // coordinates so interactions cannot be used. - return; - } - this.focus_ = mapBrowserEvent.coordinate; - mapBrowserEvent.frameState = this.frameState_; - var interactions = this.getInteractions(); - goog.asserts.assert(interactions !== undefined, - 'interactions should be defined'); - var interactionsArray = interactions.getArray(); - var i; - if (this.dispatchEvent(mapBrowserEvent) !== false) { - for (i = interactionsArray.length - 1; i >= 0; i--) { - var interaction = interactionsArray[i]; - if (!interaction.getActive()) { - continue; - } - var cont = interaction.handleEvent(mapBrowserEvent); - if (!cont) { - break; - } - } - } -}; +goog.webgl.RENDERBUFFER_DEPTH_SIZE = 0x8D54; /** - * @protected + * @const + * @type {number} */ -ol.Map.prototype.handlePostRender = function() { +goog.webgl.RENDERBUFFER_STENCIL_SIZE = 0x8D55; - var frameState = this.frameState_; - // Manage the tile queue - // Image loads are expensive and a limited resource, so try to use them - // efficiently: - // * When the view is static we allow a large number of parallel tile loads - // to complete the frame as quickly as possible. - // * When animating or interacting, image loads can cause janks, so we reduce - // the maximum number of loads per frame and limit the number of parallel - // tile loads to remain reactive to view changes and to reduce the chance of - // loading tiles that will quickly disappear from view. - var tileQueue = this.tileQueue_; - if (!tileQueue.isEmpty()) { - var maxTotalLoading = 16; - var maxNewLoads = maxTotalLoading; - var tileSourceCount = 0; - if (frameState) { - var hints = frameState.viewHints; - if (hints[ol.ViewHint.ANIMATING]) { - maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0; - maxNewLoads = 2; - } - if (hints[ol.ViewHint.INTERACTING]) { - maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0; - maxNewLoads = 2; - } - tileSourceCount = goog.object.getCount(frameState.wantedTiles); - } - maxTotalLoading *= tileSourceCount; - maxNewLoads *= tileSourceCount; - if (tileQueue.getTilesLoading() < maxTotalLoading) { - tileQueue.reprioritize(); // FIXME only call if view has changed - tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); - } - } +/** + * @const + * @type {number} + */ +goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0; - var postRenderFunctions = this.postRenderFunctions_; - var i, ii; - for (i = 0, ii = postRenderFunctions.length; i < ii; ++i) { - postRenderFunctions[i](this, frameState); - } - postRenderFunctions.length = 0; -}; + +/** + * @const + * @type {number} + */ +goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1; /** - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleSizeChanged_ = function() { - this.render(); -}; +goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2; /** - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleTargetChanged_ = function() { - // target may be undefined, null, a string or an Element. - // If it's a string we convert it to an Element before proceeding. - // If it's not now an Element we remove the viewport from the DOM. - // If it's an Element we append the viewport element to it. +goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3; - var targetElement = this.getTargetElement(); - this.keyHandler_.detach(); +/** + * @const + * @type {number} + */ +goog.webgl.COLOR_ATTACHMENT0 = 0x8CE0; - if (!targetElement) { - goog.dom.removeNode(this.viewport_); - if (this.viewportResizeListenerKey_) { - goog.events.unlistenByKey(this.viewportResizeListenerKey_); - this.viewportResizeListenerKey_ = null; - } - } else { - targetElement.appendChild(this.viewport_); - var keyboardEventTarget = !this.keyboardEventTarget_ ? - targetElement : this.keyboardEventTarget_; - this.keyHandler_.attach(keyboardEventTarget); +/** + * @const + * @type {number} + */ +goog.webgl.DEPTH_ATTACHMENT = 0x8D00; - if (!this.viewportResizeListenerKey_) { - this.viewportResizeListenerKey_ = goog.events.listen( - this.viewportSizeMonitor_, goog.events.EventType.RESIZE, - this.updateSize, false, this); - } - } - this.updateSize(); - // updateSize calls setSize, so no need to call this.render - // ourselves here. -}; +/** + * @const + * @type {number} + */ +goog.webgl.STENCIL_ATTACHMENT = 0x8D20; /** - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleTileChange_ = function() { - this.render(); -}; +goog.webgl.DEPTH_STENCIL_ATTACHMENT = 0x821A; /** - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleViewPropertyChanged_ = function() { - this.render(); -}; +goog.webgl.NONE = 0; /** - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleViewChanged_ = function() { - if (this.viewPropertyListenerKey_) { - goog.events.unlistenByKey(this.viewPropertyListenerKey_); - this.viewPropertyListenerKey_ = null; - } - var view = this.getView(); - if (view) { - this.viewPropertyListenerKey_ = goog.events.listen( - view, ol.ObjectEventType.PROPERTYCHANGE, - this.handleViewPropertyChanged_, false, this); - } - this.render(); -}; +goog.webgl.FRAMEBUFFER_COMPLETE = 0x8CD5; /** - * @param {goog.events.Event} event Event. - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleLayerGroupMemberChanged_ = function(event) { - goog.asserts.assertInstanceof(event, goog.events.Event, - 'event should be an Event'); - this.render(); -}; +goog.webgl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6; /** - * @param {ol.ObjectEvent} event Event. - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleLayerGroupPropertyChanged_ = function(event) { - goog.asserts.assertInstanceof(event, ol.ObjectEvent, - 'event should be an ol.ObjectEvent'); - this.render(); -}; +goog.webgl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7; /** - * @private + * @const + * @type {number} */ -ol.Map.prototype.handleLayerGroupChanged_ = function() { - if (this.layerGroupPropertyListenerKeys_) { - this.layerGroupPropertyListenerKeys_.forEach(goog.events.unlistenByKey); - this.layerGroupPropertyListenerKeys_ = null; - } - var layerGroup = this.getLayerGroup(); - if (layerGroup) { - this.layerGroupPropertyListenerKeys_ = [ - goog.events.listen( - layerGroup, ol.ObjectEventType.PROPERTYCHANGE, - this.handleLayerGroupPropertyChanged_, false, this), - goog.events.listen( - layerGroup, goog.events.EventType.CHANGE, - this.handleLayerGroupMemberChanged_, false, this) - ]; - } - this.render(); -}; +goog.webgl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9; /** - * Returns `true` if the map is defined, `false` otherwise. The map is defined - * if it is contained in `document`, visible, has non-zero height and width, and - * has a defined view. - * @return {boolean} Is defined. + * @const + * @type {number} */ -ol.Map.prototype.isDef = function() { - if (!goog.dom.contains(document, this.viewport_)) { - return false; - } - if (!goog.style.isElementShown(this.viewport_)) { - return false; - } - var size = this.getSize(); - if (!size || size[0] <= 0 || size[1] <= 0) { - return false; - } - var view = this.getView(); - if (!view || !view.isDef()) { - return false; - } - return true; -}; +goog.webgl.FRAMEBUFFER_UNSUPPORTED = 0x8CDD; /** - * @return {boolean} Is rendered. + * @const + * @type {number} */ -ol.Map.prototype.isRendered = function() { - return !!this.frameState_; -}; +goog.webgl.FRAMEBUFFER_BINDING = 0x8CA6; /** - * Requests an immediate render in a synchronous manner. - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.renderSync = function() { - this.animationDelay_.fire(); -}; +goog.webgl.RENDERBUFFER_BINDING = 0x8CA7; /** - * Request a map rendering (at the next animation frame). - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.render = function() { - if (!this.animationDelay_.isActive()) { - this.animationDelay_.start(); - } -}; +goog.webgl.MAX_RENDERBUFFER_SIZE = 0x84E8; /** - * Remove the given control from the map. - * @param {ol.control.Control} control Control. - * @return {ol.control.Control|undefined} The removed control (or undefined - * if the control was not found). - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.removeControl = function(control) { - var controls = this.getControls(); - goog.asserts.assert(controls !== undefined, 'controls should be defined'); - return controls.remove(control); -}; +goog.webgl.INVALID_FRAMEBUFFER_OPERATION = 0x0506; /** - * Remove the given interaction from the map. - * @param {ol.interaction.Interaction} interaction Interaction to remove. - * @return {ol.interaction.Interaction|undefined} The removed interaction (or - * undefined if the interaction was not found). - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.removeInteraction = function(interaction) { - var interactions = this.getInteractions(); - goog.asserts.assert(interactions !== undefined, - 'interactions should be defined'); - return interactions.remove(interaction); -}; +goog.webgl.UNPACK_FLIP_Y_WEBGL = 0x9240; /** - * Removes the given layer from the map. - * @param {ol.layer.Base} layer Layer. - * @return {ol.layer.Base|undefined} The removed layer (or undefined if the - * layer was not found). - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.removeLayer = function(layer) { - var layers = this.getLayerGroup().getLayers(); - return layers.remove(layer); -}; +goog.webgl.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; /** - * Remove the given overlay from the map. - * @param {ol.Overlay} overlay Overlay. - * @return {ol.Overlay|undefined} The removed overlay (or undefined - * if the overlay was not found). - * @api stable + * @const + * @type {number} */ -ol.Map.prototype.removeOverlay = function(overlay) { - var overlays = this.getOverlays(); - goog.asserts.assert(overlays !== undefined, 'overlays should be defined'); - return overlays.remove(overlay); -}; +goog.webgl.CONTEXT_LOST_WEBGL = 0x9242; /** - * @param {number} time Time. - * @private + * @const + * @type {number} */ -ol.Map.prototype.renderFrame_ = function(time) { +goog.webgl.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; - var i, ii, viewState; - var size = this.getSize(); - var view = this.getView(); - /** @type {?olx.FrameState} */ - var frameState = null; - if (size !== undefined && ol.size.hasArea(size) && - view && view.isDef()) { - var viewHints = view.getHints(); - var layerStatesArray = this.getLayerGroup().getLayerStatesArray(); - var layerStates = {}; - for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i]; - } - viewState = view.getState(); - frameState = /** @type {olx.FrameState} */ ({ - animate: false, - attributions: {}, - coordinateToPixelMatrix: this.coordinateToPixelMatrix_, - extent: null, - focus: !this.focus_ ? viewState.center : this.focus_, - index: this.frameIndex_++, - layerStates: layerStates, - layerStatesArray: layerStatesArray, - logos: goog.object.clone(this.logos_), - pixelRatio: this.pixelRatio_, - pixelToCoordinateMatrix: this.pixelToCoordinateMatrix_, - postRenderFunctions: [], - size: size, - skippedFeatureUids: this.skippedFeatureUids_, - tileQueue: this.tileQueue_, - time: time, - usedTiles: {}, - viewState: viewState, - viewHints: viewHints, - wantedTiles: {} - }); - } +/** + * @const + * @type {number} + */ +goog.webgl.BROWSER_DEFAULT_WEBGL = 0x9244; - if (frameState) { - var preRenderFunctions = this.preRenderFunctions_; - var n = 0, preRenderFunction; - for (i = 0, ii = preRenderFunctions.length; i < ii; ++i) { - preRenderFunction = preRenderFunctions[i]; - if (preRenderFunction(this, frameState)) { - preRenderFunctions[n++] = preRenderFunction; - } - } - preRenderFunctions.length = n; - frameState.extent = ol.extent.getForViewAndSize(viewState.center, - viewState.resolution, viewState.rotation, frameState.size); - } +/** + * From the OES_texture_half_float extension. + * http://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/ + * @const + * @type {number} + */ +goog.webgl.HALF_FLOAT_OES = 0x8D61; - this.frameState_ = frameState; - this.renderer_.renderFrame(frameState); - if (frameState) { - if (frameState.animate) { - this.render(); - } - Array.prototype.push.apply( - this.postRenderFunctions_, frameState.postRenderFunctions); +/** + * From the OES_standard_derivatives extension. + * http://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/ + * @const + * @type {number} + */ +goog.webgl.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B; - var idle = this.preRenderFunctions_.length === 0 && - !frameState.viewHints[ol.ViewHint.ANIMATING] && - !frameState.viewHints[ol.ViewHint.INTERACTING] && - !ol.extent.equals(frameState.extent, this.previousExtent_); - if (idle) { - this.dispatchEvent( - new ol.MapEvent(ol.MapEventType.MOVEEND, this, frameState)); - ol.extent.clone(frameState.extent, this.previousExtent_); - } - } +/** + * From the OES_vertex_array_object extension. + * http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/ + * @const + * @type {number} + */ +goog.webgl.VERTEX_ARRAY_BINDING_OES = 0x85B5; - this.dispatchEvent( - new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState)); - goog.async.nextTick(this.handlePostRender, this); +/** + * From the WEBGL_debug_renderer_info extension. + * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/ + * @const + * @type {number} + */ +goog.webgl.UNMASKED_VENDOR_WEBGL = 0x9245; -}; + +/** + * From the WEBGL_debug_renderer_info extension. + * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/ + * @const + * @type {number} + */ +goog.webgl.UNMASKED_RENDERER_WEBGL = 0x9246; /** - * Sets the layergroup of this map. - * @param {ol.layer.Group} layerGroup A layer group containing the layers in - * this map. - * @observable - * @api stable + * From the WEBGL_compressed_texture_s3tc extension. + * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ + * @const + * @type {number} */ -ol.Map.prototype.setLayerGroup = function(layerGroup) { - this.set(ol.MapProperty.LAYERGROUP, layerGroup); -}; +goog.webgl.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; /** - * Set the size of this map. - * @param {ol.Size|undefined} size The size in pixels of the map in the DOM. - * @observable - * @api + * From the WEBGL_compressed_texture_s3tc extension. + * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ + * @const + * @type {number} */ -ol.Map.prototype.setSize = function(size) { - this.set(ol.MapProperty.SIZE, size); -}; +goog.webgl.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; /** - * Set the target element to render this map into. - * @param {Element|string|undefined} target The Element or id of the Element - * that the map is rendered in. - * @observable - * @api stable + * From the WEBGL_compressed_texture_s3tc extension. + * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ + * @const + * @type {number} */ -ol.Map.prototype.setTarget = function(target) { - this.set(ol.MapProperty.TARGET, target); -}; +goog.webgl.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; /** - * Set the view for this map. - * @param {ol.View} view The view that controls this map. - * @observable - * @api stable + * From the WEBGL_compressed_texture_s3tc extension. + * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ + * @const + * @type {number} */ -ol.Map.prototype.setView = function(view) { - this.set(ol.MapProperty.VIEW, view); +goog.webgl.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; + + +/** + * From the EXT_texture_filter_anisotropic extension. + * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/ + * @const + * @type {number} + */ +goog.webgl.TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; + + +/** + * From the EXT_texture_filter_anisotropic extension. + * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/ + * @const + * @type {number} + */ +goog.webgl.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; + +goog.provide('ol.webgl.Fragment'); +goog.provide('ol.webgl.Shader'); +goog.provide('ol.webgl.Vertex'); +goog.provide('ol.webgl.shader'); + +goog.require('goog.functions'); +goog.require('goog.webgl'); +goog.require('ol.webgl'); + + + +/** + * @constructor + * @param {string} source Source. + * @struct + */ +ol.webgl.Shader = function(source) { + + /** + * @private + * @type {string} + */ + this.source_ = source; + }; /** - * @param {ol.Feature} feature Feature. + * @return {number} Type. */ -ol.Map.prototype.skipFeature = function(feature) { - var featureUid = goog.getUid(feature).toString(); - this.skippedFeatureUids_[featureUid] = true; - this.render(); +ol.webgl.Shader.prototype.getType = goog.abstractMethod; + + +/** + * @return {string} Source. + */ +ol.webgl.Shader.prototype.getSource = function() { + return this.source_; }; /** - * Force a recalculation of the map viewport size. This should be called when - * third-party code changes the size of the map viewport. - * @api stable + * @return {boolean} Is animated? */ -ol.Map.prototype.updateSize = function() { - var targetElement = this.getTargetElement(); +ol.webgl.Shader.prototype.isAnimated = goog.functions.FALSE; - if (!targetElement) { - this.setSize(undefined); - } else { - var size = goog.style.getContentBoxSize(targetElement); - this.setSize([size.width, size.height]); - } + + +/** + * @constructor + * @extends {ol.webgl.Shader} + * @param {string} source Source. + * @struct + */ +ol.webgl.shader.Fragment = function(source) { + goog.base(this, source); }; +goog.inherits(ol.webgl.shader.Fragment, ol.webgl.Shader); /** - * @param {ol.Feature} feature Feature. + * @inheritDoc */ -ol.Map.prototype.unskipFeature = function(feature) { - var featureUid = goog.getUid(feature).toString(); - delete this.skippedFeatureUids_[featureUid]; - this.render(); +ol.webgl.shader.Fragment.prototype.getType = function() { + return goog.webgl.FRAGMENT_SHADER; }; + /** - * @typedef {{controls: ol.Collection.<ol.control.Control>, - * interactions: ol.Collection.<ol.interaction.Interaction>, - * keyboardEventTarget: (Element|Document), - * logos: Object.<string, string>, - * overlays: ol.Collection.<ol.Overlay>, - * rendererConstructor: - * function(new: ol.renderer.Map, Element, ol.Map), - * values: Object.<string, *>}} + * @constructor + * @extends {ol.webgl.Shader} + * @param {string} source Source. + * @struct */ -ol.MapOptionsInternal; +ol.webgl.shader.Vertex = function(source) { + goog.base(this, source); +}; +goog.inherits(ol.webgl.shader.Vertex, ol.webgl.Shader); /** - * @param {olx.MapOptions} options Map options. - * @return {ol.MapOptionsInternal} Internal map options. + * @inheritDoc */ -ol.Map.createOptionsInternal = function(options) { +ol.webgl.shader.Vertex.prototype.getType = function() { + return goog.webgl.VERTEX_SHADER; +}; - /** - * @type {Element|Document} - */ - var keyboardEventTarget = null; - if (options.keyboardEventTarget !== undefined) { - // cannot use goog.dom.getElement because its argument cannot be - // of type Document - keyboardEventTarget = goog.isString(options.keyboardEventTarget) ? - document.getElementById(options.keyboardEventTarget) : - options.keyboardEventTarget; - } +// This file is automatically generated, do not edit +goog.provide('ol.render.webgl.imagereplay.shader.Default'); +goog.provide('ol.render.webgl.imagereplay.shader.Default.Locations'); +goog.provide('ol.render.webgl.imagereplay.shader.DefaultFragment'); +goog.provide('ol.render.webgl.imagereplay.shader.DefaultVertex'); - /** - * @type {Object.<string, *>} - */ - var values = {}; +goog.require('ol.webgl.shader'); - var logos = {}; - if (options.logo === undefined || - (goog.isBoolean(options.logo) && options.logo)) { - logos[ol.OL3_LOGO_URL] = ol.OL3_URL; - } else { - var logo = options.logo; - if (goog.isString(logo)) { - logos[logo] = ''; - } else if (goog.isObject(logo)) { - goog.asserts.assertString(logo.href, 'logo.href should be a string'); - goog.asserts.assertString(logo.src, 'logo.src should be a string'); - logos[logo.src] = logo.href; - } - } - var layerGroup = (options.layers instanceof ol.layer.Group) ? - options.layers : new ol.layer.Group({layers: options.layers}); - values[ol.MapProperty.LAYERGROUP] = layerGroup; - values[ol.MapProperty.TARGET] = options.target; +/** + * @constructor + * @extends {ol.webgl.shader.Fragment} + * @struct + */ +ol.render.webgl.imagereplay.shader.DefaultFragment = function() { + goog.base(this, ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE); +}; +goog.inherits(ol.render.webgl.imagereplay.shader.DefaultFragment, ol.webgl.shader.Fragment); +goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultFragment); - values[ol.MapProperty.VIEW] = options.view !== undefined ? - options.view : new ol.View(); - /** - * @type {function(new: ol.renderer.Map, Element, ol.Map)} - */ - var rendererConstructor = ol.renderer.Map; +/** + * @const + * @type {string} + */ +ol.render.webgl.imagereplay.shader.DefaultFragment.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'; - /** - * @type {Array.<ol.RendererType>} - */ - var rendererTypes; - if (options.renderer !== undefined) { - if (goog.isArray(options.renderer)) { - rendererTypes = options.renderer; - } else if (goog.isString(options.renderer)) { - rendererTypes = [options.renderer]; - } else { - goog.asserts.fail('Incorrect format for renderer option'); - } - } else { - rendererTypes = ol.DEFAULT_RENDERER_TYPES; - } - var i, ii; - for (i = 0, ii = rendererTypes.length; i < ii; ++i) { - /** @type {ol.RendererType} */ - var rendererType = rendererTypes[i]; - if (ol.ENABLE_CANVAS && rendererType == ol.RendererType.CANVAS) { - if (ol.has.CANVAS) { - rendererConstructor = ol.renderer.canvas.Map; - break; - } - } else if (ol.ENABLE_DOM && rendererType == ol.RendererType.DOM) { - if (ol.has.DOM) { - rendererConstructor = ol.renderer.dom.Map; - break; - } - } else if (ol.ENABLE_WEBGL && rendererType == ol.RendererType.WEBGL) { - if (ol.has.WEBGL) { - rendererConstructor = ol.renderer.webgl.Map; - break; - } - } - } +/** + * @const + * @type {string} + */ +ol.render.webgl.imagereplay.shader.DefaultFragment.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;}'; - var controls; - if (options.controls !== undefined) { - if (goog.isArray(options.controls)) { - controls = new ol.Collection(options.controls.slice()); - } else { - goog.asserts.assertInstanceof(options.controls, ol.Collection, - 'options.controls should be an ol.Collection'); - controls = options.controls; - } - } else { - controls = ol.control.defaults(); - } - var interactions; - if (options.interactions !== undefined) { - if (goog.isArray(options.interactions)) { - interactions = new ol.Collection(options.interactions.slice()); - } else { - goog.asserts.assertInstanceof(options.interactions, ol.Collection, - 'options.interactions should be an ol.Collection'); - interactions = options.interactions; - } - } else { - interactions = ol.interaction.defaults(); - } +/** + * @const + * @type {string} + */ +ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE = goog.DEBUG ? + ol.render.webgl.imagereplay.shader.DefaultFragment.DEBUG_SOURCE : + ol.render.webgl.imagereplay.shader.DefaultFragment.OPTIMIZED_SOURCE; - var overlays; - if (options.overlays !== undefined) { - if (goog.isArray(options.overlays)) { - overlays = new ol.Collection(options.overlays.slice()); - } else { - goog.asserts.assertInstanceof(options.overlays, ol.Collection, - 'options.overlays should be an ol.Collection'); - overlays = options.overlays; - } - } else { - overlays = new ol.Collection(); - } - return { - controls: controls, - interactions: interactions, - keyboardEventTarget: keyboardEventTarget, - logos: logos, - overlays: overlays, - rendererConstructor: rendererConstructor, - values: values - }; +/** + * @constructor + * @extends {ol.webgl.shader.Vertex} + * @struct + */ +ol.render.webgl.imagereplay.shader.DefaultVertex = function() { + goog.base(this, ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE); }; +goog.inherits(ol.render.webgl.imagereplay.shader.DefaultVertex, ol.webgl.shader.Vertex); +goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultVertex); -ol.proj.common.add(); - - -if (goog.DEBUG) { - (function() { - goog.debug.Console.autoInstall(); - var logger = goog.log.getLogger('ol'); - logger.setLevel(goog.log.Level.FINEST); - })(); -} - -goog.provide('ol.Overlay'); -goog.provide('ol.OverlayPositioning'); -goog.provide('ol.OverlayProperty'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.style'); -goog.require('ol.Coordinate'); -goog.require('ol.Map'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); -goog.require('ol.animation'); -goog.require('ol.dom'); -goog.require('ol.extent'); +/** + * @const + * @type {string} + */ +ol.render.webgl.imagereplay.shader.DefaultVertex.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.);\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + offsets;\n v_texCoord = a_texCoord;\n v_opacity = a_opacity;\n}\n\n\n'; /** - * @enum {string} + * @const + * @type {string} */ -ol.OverlayProperty = { - ELEMENT: 'element', - MAP: 'map', - OFFSET: 'offset', - POSITION: 'position', - POSITIONING: 'positioning' -}; +ol.render.webgl.imagereplay.shader.DefaultVertex.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.);gl_Position=h*vec4(c,0.,1.)+offsets;a=d;b=f;}'; /** - * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, - * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, - * `'top-center'`, `'top-right'` - * @enum {string} - * @api stable + * @const + * @type {string} */ -ol.OverlayPositioning = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_CENTER: 'bottom-center', - BOTTOM_RIGHT: 'bottom-right', - CENTER_LEFT: 'center-left', - CENTER_CENTER: 'center-center', - CENTER_RIGHT: 'center-right', - TOP_LEFT: 'top-left', - TOP_CENTER: 'top-center', - TOP_RIGHT: 'top-right' -}; +ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE = goog.DEBUG ? + ol.render.webgl.imagereplay.shader.DefaultVertex.DEBUG_SOURCE : + ol.render.webgl.imagereplay.shader.DefaultVertex.OPTIMIZED_SOURCE; /** - * @classdesc - * An element to be displayed over the map and attached to a single map - * location. Like {@link ol.control.Control}, Overlays are visible widgets. - * Unlike Controls, they are not in a fixed position on the screen, but are tied - * to a geographical coordinate, so panning the map will move an Overlay but not - * a Control. - * - * Example: - * - * var popup = new ol.Overlay({ - * element: document.getElementById('popup') - * }); - * popup.setPosition(coordinate); - * map.addOverlay(popup); - * * @constructor - * @extends {ol.Object} - * @param {olx.OverlayOptions} options Overlay options. - * @api stable + * @param {WebGLRenderingContext} gl GL. + * @param {WebGLProgram} program Program. + * @struct */ -ol.Overlay = function(options) { +ol.render.webgl.imagereplay.shader.Default.Locations = function(gl, program) { - goog.base(this); + /** + * @type {WebGLUniformLocation} + */ + this.u_image = gl.getUniformLocation( + program, goog.DEBUG ? 'u_image' : 'l'); /** - * @private - * @type {number|string|undefined} + * @type {WebGLUniformLocation} */ - this.id_ = options.id; + this.u_offsetRotateMatrix = gl.getUniformLocation( + program, goog.DEBUG ? 'u_offsetRotateMatrix' : 'j'); /** - * @private - * @type {boolean} + * @type {WebGLUniformLocation} */ - this.insertFirst_ = options.insertFirst !== undefined ? - options.insertFirst : true; + this.u_offsetScaleMatrix = gl.getUniformLocation( + program, goog.DEBUG ? 'u_offsetScaleMatrix' : 'i'); /** - * @private - * @type {boolean} + * @type {WebGLUniformLocation} */ - this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true; + this.u_opacity = gl.getUniformLocation( + program, goog.DEBUG ? 'u_opacity' : 'k'); /** - * @private - * @type {Element} + * @type {WebGLUniformLocation} */ - this.element_ = goog.dom.createDom('DIV', { - 'class': 'ol-overlay-container' - }); - this.element_.style.position = 'absolute'; + this.u_projectionMatrix = gl.getUniformLocation( + program, goog.DEBUG ? 'u_projectionMatrix' : 'h'); /** - * @protected - * @type {boolean} + * @type {number} */ - this.autoPan = options.autoPan !== undefined ? options.autoPan : false; + this.a_offsets = gl.getAttribLocation( + program, goog.DEBUG ? 'a_offsets' : 'e'); /** - * @private - * @type {olx.animation.PanOptions} + * @type {number} */ - this.autoPanAnimation_ = options.autoPanAnimation !== undefined ? - options.autoPanAnimation : /** @type {olx.animation.PanOptions} */ ({}); + this.a_opacity = gl.getAttribLocation( + program, goog.DEBUG ? 'a_opacity' : 'f'); /** - * @private * @type {number} */ - this.autoPanMargin_ = options.autoPanMargin !== undefined ? - options.autoPanMargin : 20; + this.a_position = gl.getAttribLocation( + program, goog.DEBUG ? 'a_position' : 'c'); /** - * @private - * @type {{bottom_: string, - * left_: string, - * right_: string, - * top_: string, - * visible: boolean}} + * @type {number} */ - this.rendered_ = { - bottom_: '', - left_: '', - right_: '', - top_: '', - visible: true - }; + this.a_rotateWithView = gl.getAttribLocation( + program, goog.DEBUG ? 'a_rotateWithView' : 'g'); /** - * @private - * @type {goog.events.Key} + * @type {number} */ - this.mapPostrenderListenerKey_ = null; + this.a_texCoord = gl.getAttribLocation( + program, goog.DEBUG ? 'a_texCoord' : 'd'); +}; - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT), - this.handleElementChanged, false, this); +goog.provide('ol.webgl.Buffer'); - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP), - this.handleMapChanged, false, this); +goog.require('goog.webgl'); +goog.require('ol'); - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET), - this.handleOffsetChanged, false, this); - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION), - this.handlePositionChanged, false, this); +/** + * @enum {number} + */ +ol.webgl.BufferUsage = { + STATIC_DRAW: goog.webgl.STATIC_DRAW, + STREAM_DRAW: goog.webgl.STREAM_DRAW, + DYNAMIC_DRAW: goog.webgl.DYNAMIC_DRAW +}; - goog.events.listen( - this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING), - this.handlePositioningChanged, false, this); - if (options.element !== undefined) { - this.setElement(options.element); - } - this.setOffset(options.offset !== undefined ? options.offset : [0, 0]); +/** + * @constructor + * @param {Array.<number>=} opt_arr Array. + * @param {number=} opt_usage Usage. + * @struct + */ +ol.webgl.Buffer = function(opt_arr, opt_usage) { - this.setPositioning(options.positioning !== undefined ? - /** @type {ol.OverlayPositioning} */ (options.positioning) : - ol.OverlayPositioning.TOP_LEFT); + /** + * @private + * @type {Array.<number>} + */ + this.arr_ = opt_arr !== undefined ? opt_arr : []; - if (options.position !== undefined) { - this.setPosition(options.position); - } + /** + * @private + * @type {number} + */ + this.usage_ = opt_usage !== undefined ? + opt_usage : ol.webgl.BufferUsage.STATIC_DRAW; }; -goog.inherits(ol.Overlay, ol.Object); /** - * Get the DOM element of this overlay. - * @return {Element|undefined} The Element containing the overlay. - * @observable - * @api stable + * @return {Array.<number>} Array. */ -ol.Overlay.prototype.getElement = function() { - return /** @type {Element|undefined} */ ( - this.get(ol.OverlayProperty.ELEMENT)); +ol.webgl.Buffer.prototype.getArray = function() { + return this.arr_; }; /** - * Get the overlay identifier which is set on constructor. - * @return {number|string|undefined} Id. - * @api + * @return {number} Usage. */ -ol.Overlay.prototype.getId = function() { - return this.id_; +ol.webgl.Buffer.prototype.getUsage = function() { + return this.usage_; }; +goog.provide('ol.webgl.Context'); -/** - * Get the map associated with this overlay. - * @return {ol.Map|undefined} The map that the overlay is part of. - * @observable - * @api stable - */ -ol.Overlay.prototype.getMap = function() { - return /** @type {ol.Map|undefined} */ ( - this.get(ol.OverlayProperty.MAP)); -}; +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.log'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.array'); +goog.require('ol.webgl.Buffer'); +goog.require('ol.webgl.WebGLContextEventType'); /** - * Get the offset of this overlay. - * @return {Array.<number>} The offset. - * @observable - * @api stable + * @typedef {{buf: ol.webgl.Buffer, + * buffer: WebGLBuffer}} */ -ol.Overlay.prototype.getOffset = function() { - return /** @type {Array.<number>} */ ( - this.get(ol.OverlayProperty.OFFSET)); -}; - +ol.webgl.BufferCacheEntry; -/** - * Get the current position of this overlay. - * @return {ol.Coordinate|undefined} The spatial point that the overlay is - * anchored at. - * @observable - * @api stable - */ -ol.Overlay.prototype.getPosition = function() { - return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.OverlayProperty.POSITION)); -}; /** - * Get the current positioning of this overlay. - * @return {ol.OverlayPositioning} How the overlay is positioned - * relative to its point on the map. - * @observable - * @api stable + * @classdesc + * A WebGL context for accessing low-level WebGL capabilities. + * + * @constructor + * @extends {goog.events.EventTarget} + * @param {HTMLCanvasElement} canvas Canvas. + * @param {WebGLRenderingContext} gl GL. */ -ol.Overlay.prototype.getPositioning = function() { - return /** @type {ol.OverlayPositioning} */ ( - this.get(ol.OverlayProperty.POSITIONING)); -}; +ol.webgl.Context = function(canvas, gl) { + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = canvas; -/** - * @protected - */ -ol.Overlay.prototype.handleElementChanged = function() { - goog.dom.removeChildren(this.element_); - var element = this.getElement(); - if (element) { - goog.dom.append(/** @type {!Node} */ (this.element_), element); - } -}; + /** + * @private + * @type {WebGLRenderingContext} + */ + this.gl_ = gl; + /** + * @private + * @type {Object.<number, ol.webgl.BufferCacheEntry>} + */ + this.bufferCache_ = {}; -/** - * @protected - */ -ol.Overlay.prototype.handleMapChanged = function() { - if (this.mapPostrenderListenerKey_) { - goog.dom.removeNode(this.element_); - goog.events.unlistenByKey(this.mapPostrenderListenerKey_); - this.mapPostrenderListenerKey_ = null; - } - var map = this.getMap(); - if (map) { - this.mapPostrenderListenerKey_ = goog.events.listen(map, - ol.MapEventType.POSTRENDER, this.render, false, this); - this.updatePixelPosition(); - var container = this.stopEvent_ ? - map.getOverlayContainerStopEvent() : map.getOverlayContainer(); - if (this.insertFirst_) { - goog.dom.insertChildAt(/** @type {!Element} */ ( - container), this.element_, 0); - } else { - goog.dom.append(/** @type {!Node} */ (container), this.element_); - } - } -}; + /** + * @private + * @type {Object.<number, WebGLShader>} + */ + this.shaderCache_ = {}; + /** + * @private + * @type {Object.<string, WebGLProgram>} + */ + this.programCache_ = {}; -/** - * @protected - */ -ol.Overlay.prototype.render = function() { - this.updatePixelPosition(); -}; + /** + * @private + * @type {WebGLProgram} + */ + this.currentProgram_ = null; + /** + * @private + * @type {WebGLFramebuffer} + */ + this.hitDetectionFramebuffer_ = null; -/** - * @protected - */ -ol.Overlay.prototype.handleOffsetChanged = function() { - this.updatePixelPosition(); -}; + /** + * @private + * @type {WebGLTexture} + */ + this.hitDetectionTexture_ = null; + /** + * @private + * @type {WebGLRenderbuffer} + */ + this.hitDetectionRenderbuffer_ = null; -/** - * @protected - */ -ol.Overlay.prototype.handlePositionChanged = function() { - this.updatePixelPosition(); - if (this.get(ol.OverlayProperty.POSITION) !== undefined && this.autoPan) { - this.panIntoView_(); + /** + * @type {boolean} + */ + this.hasOESElementIndexUint = ol.array.includes( + ol.WEBGL_EXTENSIONS, 'OES_element_index_uint'); + + // use the OES_element_index_uint extension if available + if (this.hasOESElementIndexUint) { + var ext = gl.getExtension('OES_element_index_uint'); + goog.asserts.assert(ext, + 'Failed to get extension "OES_element_index_uint"'); } -}; + goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST, + this.handleWebGLContextLost, false, this); + goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED, + this.handleWebGLContextRestored, false, this); -/** - * @protected - */ -ol.Overlay.prototype.handlePositioningChanged = function() { - this.updatePixelPosition(); }; /** - * Set the DOM element to be associated with this overlay. - * @param {Element|undefined} element The Element containing the overlay. - * @observable - * @api stable + * Just bind the buffer if it's in the cache. Otherwise create + * the WebGL buffer, bind it, populate it, and add an entry to + * the cache. + * @param {number} target Target. + * @param {ol.webgl.Buffer} buf Buffer. */ -ol.Overlay.prototype.setElement = function(element) { - this.set(ol.OverlayProperty.ELEMENT, element); -}; - - -/** - * Set the map to be associated with this overlay. - * @param {ol.Map|undefined} map The map that the overlay is part of. - * @observable - * @api stable +ol.webgl.Context.prototype.bindBuffer = function(target, buf) { + var gl = this.getGL(); + var arr = buf.getArray(); + var bufferKey = goog.getUid(buf); + if (bufferKey in this.bufferCache_) { + var bufferCacheEntry = this.bufferCache_[bufferKey]; + gl.bindBuffer(target, bufferCacheEntry.buffer); + } else { + var buffer = gl.createBuffer(); + gl.bindBuffer(target, buffer); + goog.asserts.assert(target == goog.webgl.ARRAY_BUFFER || + target == goog.webgl.ELEMENT_ARRAY_BUFFER, + 'target is supposed to be an ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER'); + var /** @type {ArrayBufferView} */ arrayBuffer; + if (target == goog.webgl.ARRAY_BUFFER) { + arrayBuffer = new Float32Array(arr); + } else if (target == goog.webgl.ELEMENT_ARRAY_BUFFER) { + arrayBuffer = this.hasOESElementIndexUint ? + new Uint32Array(arr) : new Uint16Array(arr); + } else { + goog.asserts.fail(); + } + gl.bufferData(target, arrayBuffer, buf.getUsage()); + this.bufferCache_[bufferKey] = { + buf: buf, + buffer: buffer + }; + } +}; + + +/** + * @param {ol.webgl.Buffer} buf Buffer. */ -ol.Overlay.prototype.setMap = function(map) { - this.set(ol.OverlayProperty.MAP, map); +ol.webgl.Context.prototype.deleteBuffer = function(buf) { + var gl = this.getGL(); + var bufferKey = goog.getUid(buf); + goog.asserts.assert(bufferKey in this.bufferCache_, + 'attempted to delete uncached buffer'); + var bufferCacheEntry = this.bufferCache_[bufferKey]; + if (!gl.isContextLost()) { + gl.deleteBuffer(bufferCacheEntry.buffer); + } + delete this.bufferCache_[bufferKey]; }; /** - * Set the offset for this overlay. - * @param {Array.<number>} offset Offset. - * @observable - * @api stable + * @inheritDoc */ -ol.Overlay.prototype.setOffset = function(offset) { - this.set(ol.OverlayProperty.OFFSET, offset); +ol.webgl.Context.prototype.disposeInternal = function() { + var gl = this.getGL(); + if (!gl.isContextLost()) { + goog.object.forEach(this.bufferCache_, function(bufferCacheEntry) { + gl.deleteBuffer(bufferCacheEntry.buffer); + }); + goog.object.forEach(this.programCache_, function(program) { + gl.deleteProgram(program); + }); + goog.object.forEach(this.shaderCache_, function(shader) { + gl.deleteShader(shader); + }); + // delete objects for hit-detection + gl.deleteFramebuffer(this.hitDetectionFramebuffer_); + gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_); + gl.deleteTexture(this.hitDetectionTexture_); + } }; /** - * Set the position for this overlay. If the position is `undefined` the - * overlay is hidden. - * @param {ol.Coordinate|undefined} position The spatial point that the overlay - * is anchored at. - * @observable - * @api stable + * @return {HTMLCanvasElement} Canvas. */ -ol.Overlay.prototype.setPosition = function(position) { - this.set(ol.OverlayProperty.POSITION, position); +ol.webgl.Context.prototype.getCanvas = function() { + return this.canvas_; }; /** - * Pan the map so that the overlay is entirely visible in the current viewport - * (if necessary). - * @private + * Get the WebGL rendering context + * @return {WebGLRenderingContext} The rendering context. + * @api */ -ol.Overlay.prototype.panIntoView_ = function() { - goog.asserts.assert(this.autoPan, 'this.autoPan should be true'); - var map = this.getMap(); +ol.webgl.Context.prototype.getGL = function() { + return this.gl_; +}; - if (map === undefined || !map.getTargetElement()) { - return; - } - var mapRect = this.getRect_(map.getTargetElement(), map.getSize()); - var element = this.getElement(); - goog.asserts.assert(element, 'element should be defined'); - var overlayRect = this.getRect_(element, - [ol.dom.outerWidth(element), ol.dom.outerHeight(element)]); +/** + * Get the frame buffer for hit detection. + * @return {WebGLFramebuffer} The hit detection frame buffer. + */ +ol.webgl.Context.prototype.getHitDetectionFramebuffer = function() { + if (!this.hitDetectionFramebuffer_) { + this.initHitDetectionFramebuffer_(); + } + return this.hitDetectionFramebuffer_; +}; - var margin = this.autoPanMargin_; - if (!ol.extent.containsExtent(mapRect, overlayRect)) { - // the overlay is not completely inside the viewport, so pan the map - var offsetLeft = overlayRect[0] - mapRect[0]; - var offsetRight = mapRect[2] - overlayRect[2]; - var offsetTop = overlayRect[1] - mapRect[1]; - var offsetBottom = mapRect[3] - overlayRect[3]; - var delta = [0, 0]; - if (offsetLeft < 0) { - // move map to the left - delta[0] = offsetLeft - margin; - } else if (offsetRight < 0) { - // move map to the right - delta[0] = Math.abs(offsetRight) + margin; - } - if (offsetTop < 0) { - // move map up - delta[1] = offsetTop - margin; - } else if (offsetBottom < 0) { - // move map down - delta[1] = Math.abs(offsetBottom) + margin; +/** + * Get shader from the cache if it's in the cache. Otherwise, create + * the WebGL shader, compile it, and add entry to cache. + * @param {ol.webgl.Shader} shaderObject Shader object. + * @return {WebGLShader} Shader. + */ +ol.webgl.Context.prototype.getShader = function(shaderObject) { + var shaderKey = goog.getUid(shaderObject); + if (shaderKey in this.shaderCache_) { + return this.shaderCache_[shaderKey]; + } else { + var gl = this.getGL(); + var shader = gl.createShader(shaderObject.getType()); + gl.shaderSource(shader, shaderObject.getSource()); + gl.compileShader(shader); + if (goog.DEBUG) { + if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) && + !gl.isContextLost()) { + goog.log.error(this.logger_, gl.getShaderInfoLog(shader)); + } } + goog.asserts.assert( + gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) || + gl.isContextLost(), + 'illegal state, shader not compiled or context lost'); + this.shaderCache_[shaderKey] = shader; + return shader; + } +}; - if (delta[0] !== 0 || delta[1] !== 0) { - var center = map.getView().getCenter(); - goog.asserts.assert(center !== undefined, 'center should be defined'); - var centerPx = map.getPixelFromCoordinate(center); - var newCenterPx = [ - centerPx[0] + delta[0], - centerPx[1] + delta[1] - ]; - if (this.autoPanAnimation_) { - this.autoPanAnimation_.source = center; - map.beforeRender(ol.animation.pan(this.autoPanAnimation_)); +/** + * Get the program from the cache if it's in the cache. Otherwise create + * the WebGL program, attach the shaders to it, and add an entry to the + * cache. + * @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader. + * @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader. + * @return {WebGLProgram} Program. + */ +ol.webgl.Context.prototype.getProgram = function( + fragmentShaderObject, vertexShaderObject) { + var programKey = + goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject); + if (programKey in this.programCache_) { + return this.programCache_[programKey]; + } else { + var gl = this.getGL(); + var program = gl.createProgram(); + gl.attachShader(program, this.getShader(fragmentShaderObject)); + gl.attachShader(program, this.getShader(vertexShaderObject)); + gl.linkProgram(program); + if (goog.DEBUG) { + if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) && + !gl.isContextLost()) { + goog.log.error(this.logger_, gl.getProgramInfoLog(program)); } - map.getView().setCenter(map.getCoordinateFromPixel(newCenterPx)); } + goog.asserts.assert( + gl.getProgramParameter(program, goog.webgl.LINK_STATUS) || + gl.isContextLost(), + 'illegal state, shader not linked or context lost'); + this.programCache_[programKey] = program; + return program; } }; /** - * Get the extent of an element relative to the document - * @param {Element|undefined} element The element. - * @param {ol.Size|undefined} size The size of the element. - * @return {ol.Extent} - * @private + * FIXME empy description for jsdoc */ -ol.Overlay.prototype.getRect_ = function(element, size) { - goog.asserts.assert(element, 'element should be defined'); - goog.asserts.assert(size !== undefined, 'size should be defined'); +ol.webgl.Context.prototype.handleWebGLContextLost = function() { + goog.object.clear(this.bufferCache_); + goog.object.clear(this.shaderCache_); + goog.object.clear(this.programCache_); + this.currentProgram_ = null; + this.hitDetectionFramebuffer_ = null; + this.hitDetectionTexture_ = null; + this.hitDetectionRenderbuffer_ = null; +}; - var offset = goog.style.getPageOffset(element); - return [ - offset.x, - offset.y, - offset.x + size[0], - offset.y + size[1] - ]; + +/** + * FIXME empy description for jsdoc + */ +ol.webgl.Context.prototype.handleWebGLContextRestored = function() { }; /** - * Set the positioning for this overlay. - * @param {ol.OverlayPositioning} positioning how the overlay is - * positioned relative to its point on the map. - * @observable - * @api stable + * Creates a 1x1 pixel framebuffer for the hit-detection. + * @private */ -ol.Overlay.prototype.setPositioning = function(positioning) { - this.set(ol.OverlayProperty.POSITIONING, positioning); +ol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() { + var gl = this.gl_; + var framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); + + var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1); + var renderbuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1); + gl.framebufferTexture2D( + gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, + gl.RENDERBUFFER, renderbuffer); + + gl.bindTexture(gl.TEXTURE_2D, null); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + + this.hitDetectionFramebuffer_ = framebuffer; + this.hitDetectionTexture_ = texture; + this.hitDetectionRenderbuffer_ = renderbuffer; }; /** - * Modify the visibility of the element. - * @param {boolean} visible - * @protected + * Use a program. If the program is already in use, this will return `false`. + * @param {WebGLProgram} program Program. + * @return {boolean} Changed. + * @api */ -ol.Overlay.prototype.setVisible = function(visible) { - if (this.rendered_.visible !== visible) { - goog.style.setElementShown(this.element_, visible); - this.rendered_.visible = visible; +ol.webgl.Context.prototype.useProgram = function(program) { + if (program == this.currentProgram_) { + return false; + } else { + var gl = this.getGL(); + gl.useProgram(program); + this.currentProgram_ = program; + return true; } }; /** - * Update pixel position. - * @protected + * @private + * @type {goog.log.Logger} */ -ol.Overlay.prototype.updatePixelPosition = function() { - var map = this.getMap(); - var position = this.getPosition(); - if (map === undefined || !map.isRendered() || position === undefined) { - this.setVisible(false); - return; +ol.webgl.Context.prototype.logger_ = goog.log.getLogger('ol.webgl.Context'); + + +/** + * @param {WebGLRenderingContext} gl WebGL rendering context. + * @param {number=} opt_wrapS wrapS. + * @param {number=} opt_wrapT wrapT. + * @return {WebGLTexture} + * @private + */ +ol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) { + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + + if (opt_wrapS !== undefined) { + gl.texParameteri( + goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, opt_wrapS); + } + if (opt_wrapT !== undefined) { + gl.texParameteri( + goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, opt_wrapT); } - var pixel = map.getPixelFromCoordinate(position); - var mapSize = map.getSize(); - this.updateRenderedPosition(pixel, mapSize); + return texture; }; /** - * @param {ol.Pixel} pixel - * @param {ol.Size|undefined} mapSize - * @protected + * @param {WebGLRenderingContext} gl WebGL rendering context. + * @param {number} width Width. + * @param {number} height Height. + * @param {number=} opt_wrapS wrapS. + * @param {number=} opt_wrapT wrapT. + * @return {WebGLTexture} */ -ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { - goog.asserts.assert(pixel, 'pixel should not be null'); - goog.asserts.assert(mapSize !== undefined, 'mapSize should be defined'); - var style = this.element_.style; - var offset = this.getOffset(); - goog.asserts.assert(goog.isArray(offset), 'offset should be an array'); +ol.webgl.Context.createEmptyTexture = function( + gl, width, height, opt_wrapS, opt_wrapT) { + var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT); + gl.texImage2D( + gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, + null); - var positioning = this.getPositioning(); - goog.asserts.assert(positioning !== undefined, - 'positioning should be defined'); + return texture; +}; - var offsetX = offset[0]; - var offsetY = offset[1]; - if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT || - positioning == ol.OverlayPositioning.CENTER_RIGHT || - positioning == ol.OverlayPositioning.TOP_RIGHT) { - if (this.rendered_.left_ !== '') { - this.rendered_.left_ = style.left = ''; - } - var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px'; - if (this.rendered_.right_ != right) { - this.rendered_.right_ = style.right = right; - } - } else { - if (this.rendered_.right_ !== '') { - this.rendered_.right_ = style.right = ''; - } - if (positioning == ol.OverlayPositioning.BOTTOM_CENTER || - positioning == ol.OverlayPositioning.CENTER_CENTER || - positioning == ol.OverlayPositioning.TOP_CENTER) { - offsetX -= goog.style.getSize(this.element_).width / 2; - } - var left = Math.round(pixel[0] + offsetX) + 'px'; - if (this.rendered_.left_ != left) { - this.rendered_.left_ = style.left = left; - } - } - if (positioning == ol.OverlayPositioning.BOTTOM_LEFT || - positioning == ol.OverlayPositioning.BOTTOM_CENTER || - positioning == ol.OverlayPositioning.BOTTOM_RIGHT) { - if (this.rendered_.top_ !== '') { - this.rendered_.top_ = style.top = ''; - } - var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px'; - if (this.rendered_.bottom_ != bottom) { - this.rendered_.bottom_ = style.bottom = bottom; - } - } else { - if (this.rendered_.bottom_ !== '') { - this.rendered_.bottom_ = style.bottom = ''; - } - if (positioning == ol.OverlayPositioning.CENTER_LEFT || - positioning == ol.OverlayPositioning.CENTER_CENTER || - positioning == ol.OverlayPositioning.CENTER_RIGHT) { - offsetY -= goog.style.getSize(this.element_).height / 2; - } - var top = Math.round(pixel[1] + offsetY) + 'px'; - if (this.rendered_.top_ != top) { - this.rendered_.top_ = style.top = top; - } - } - this.setVisible(true); +/** + * @param {WebGLRenderingContext} gl WebGL rendering context. + * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image. + * @param {number=} opt_wrapS wrapS. + * @param {number=} opt_wrapT wrapT. + * @return {WebGLTexture} + */ +ol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) { + var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT); + gl.texImage2D( + gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + + return texture; }; -goog.provide('ol.control.OverviewMap'); +goog.provide('ol.render.webgl.ImageReplay'); +goog.provide('ol.render.webgl.ReplayGroup'); goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.math.Size'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.Map'); -goog.require('ol.MapEventType'); -goog.require('ol.Object'); -goog.require('ol.ObjectEventType'); -goog.require('ol.Overlay'); -goog.require('ol.OverlayPositioning'); -goog.require('ol.View'); -goog.require('ol.ViewProperty'); -goog.require('ol.control.Control'); -goog.require('ol.coordinate'); -goog.require('ol.css'); +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('goog.vec.Mat4'); goog.require('ol.extent'); +goog.require('ol.render.IReplayGroup'); +goog.require('ol.render.VectorContext'); +goog.require('ol.render.webgl.imagereplay.shader.Default'); +goog.require('ol.render.webgl.imagereplay.shader.Default.Locations'); +goog.require('ol.render.webgl.imagereplay.shader.DefaultFragment'); +goog.require('ol.render.webgl.imagereplay.shader.DefaultVertex'); +goog.require('ol.vec.Mat4'); +goog.require('ol.webgl.Buffer'); +goog.require('ol.webgl.Context'); /** - * Create a new control with a map acting as an overview map for an other - * defined map. * @constructor - * @extends {ol.control.Control} - * @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options. - * @api + * @extends {ol.render.VectorContext} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Max extent. + * @protected + * @struct */ -ol.control.OverviewMap = function(opt_options) { - - var options = opt_options ? opt_options : {}; +ol.render.webgl.ImageReplay = function(tolerance, maxExtent) { + goog.base(this); /** - * @type {boolean} + * @type {number|undefined} * @private */ - this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true; + this.anchorX_ = undefined; /** + * @type {number|undefined} * @private - * @type {boolean} */ - this.collapsible_ = options.collapsible !== undefined ? - options.collapsible : true; - - if (!this.collapsible_) { - this.collapsed_ = false; - } - - var className = options.className ? options.className : 'ol-overviewmap'; - - var tipLabel = options.tipLabel ? options.tipLabel : 'Overview map'; - - var collapseLabel = options.collapseLabel ? options.collapseLabel : '\u00AB'; + this.anchorY_ = undefined; /** + * The origin of the coordinate system for the point coordinates sent to + * the GPU. To eliminate jitter caused by precision problems in the GPU + * we use the "Rendering Relative to Eye" technique described in the "3D + * Engine Design for Virtual Globes" book. * @private - * @type {Node} + * @type {ol.Coordinate} */ - this.collapseLabel_ = goog.isString(collapseLabel) ? - goog.dom.createDom('SPAN', {}, collapseLabel) : - collapseLabel; - - var label = options.label ? options.label : '\u00BB'; + this.origin_ = ol.extent.getCenter(maxExtent); /** + * @type {Array.<number>} * @private - * @type {Node} */ - this.label_ = goog.isString(label) ? - goog.dom.createDom('SPAN', {}, label) : - label; - - var activeLabel = (this.collapsible_ && !this.collapsed_) ? - this.collapseLabel_ : this.label_; - var button = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'title': tipLabel - }, activeLabel); - - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); - - var ovmapDiv = goog.dom.createDom('DIV', 'ol-overviewmap-map'); + this.groupIndices_ = []; /** - * @type {ol.Map} + * @type {Array.<number>} * @private */ - this.ovmap_ = new ol.Map({ - controls: new ol.Collection(), - interactions: new ol.Collection(), - target: ovmapDiv, - view: options.view - }); - var ovmap = this.ovmap_; + this.hitDetectionGroupIndices_ = []; - if (options.layers) { - options.layers.forEach( - /** - * @param {ol.layer.Layer} layer Layer. - */ - function(layer) { - ovmap.addLayer(layer); - }, this); - } + /** + * @type {number|undefined} + * @private + */ + this.height_ = undefined; - var box = goog.dom.createDom('DIV', 'ol-overviewmap-box'); + /** + * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} + * @private + */ + this.images_ = []; /** - * @type {ol.Overlay} + * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} * @private */ - this.boxOverlay_ = new ol.Overlay({ - position: [0, 0], - positioning: ol.OverlayPositioning.BOTTOM_LEFT, - element: box - }); - this.ovmap_.addOverlay(this.boxOverlay_); + this.hitDetectionImages_ = []; - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL + - (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') + - (this.collapsible_ ? '' : ' ol-uncollapsible'); - var element = goog.dom.createDom('DIV', - cssClasses, ovmapDiv, button); + /** + * @type {number|undefined} + * @private + */ + this.imageHeight_ = undefined; - var render = options.render ? options.render : ol.control.OverviewMap.render; + /** + * @type {number|undefined} + * @private + */ + this.imageWidth_ = undefined; - goog.base(this, { - element: element, - render: render, - target: options.target - }); -}; -goog.inherits(ol.control.OverviewMap, ol.control.Control); + /** + * @type {Array.<number>} + * @private + */ + this.indices_ = []; + /** + * @type {ol.webgl.Buffer} + * @private + */ + this.indicesBuffer_ = null; -/** - * @inheritDoc - * @api - */ -ol.control.OverviewMap.prototype.setMap = function(map) { - var oldMap = this.getMap(); - if (map === oldMap) { - return; - } - if (oldMap) { - var oldView = oldMap.getView(); - if (oldView) { - this.unbindView_(oldView); - } - } - goog.base(this, 'setMap', map); + /** + * @private + * @type {ol.render.webgl.imagereplay.shader.Default.Locations} + */ + this.defaultLocations_ = null; - if (map) { - this.listenerKeys.push(goog.events.listen( - map, ol.ObjectEventType.PROPERTYCHANGE, - this.handleMapPropertyChange_, false, this)); + /** + * @private + * @type {number|undefined} + */ + this.opacity_ = undefined; - // TODO: to really support map switching, this would need to be reworked - if (this.ovmap_.getLayers().getLength() === 0) { - this.ovmap_.setLayerGroup(map.getLayerGroup()); - } + /** + * @type {!goog.vec.Mat4.Number} + * @private + */ + this.offsetRotateMatrix_ = goog.vec.Mat4.createNumberIdentity(); - var view = map.getView(); - if (view) { - this.bindView_(view); - if (view.isDef()) { - this.ovmap_.updateSize(); - this.resetExtent_(); - } - } - } -}; + /** + * @type {!goog.vec.Mat4.Number} + * @private + */ + this.offsetScaleMatrix_ = goog.vec.Mat4.createNumberIdentity(); + + /** + * @type {number|undefined} + * @private + */ + this.originX_ = undefined; + /** + * @type {number|undefined} + * @private + */ + this.originY_ = undefined; -/** - * Handle map property changes. This only deals with changes to the map's view. - * @param {ol.ObjectEvent} event The propertychange event. - * @private - */ -ol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) { - if (event.key === ol.MapProperty.VIEW) { - var oldView = /** @type {ol.View} */ (event.oldValue); - if (oldView) { - this.unbindView_(oldView); - } - var newView = this.getMap().getView(); - this.bindView_(newView); - } -}; + /** + * @type {!goog.vec.Mat4.Number} + * @private + */ + this.projectionMatrix_ = goog.vec.Mat4.createNumberIdentity(); + /** + * @private + * @type {boolean|undefined} + */ + this.rotateWithView_ = undefined; -/** - * Register listeners for view property changes. - * @param {ol.View} view The view. - * @private - */ -ol.control.OverviewMap.prototype.bindView_ = function(view) { - goog.events.listen(view, - ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), - this.handleRotationChanged_, false, this); -}; + /** + * @private + * @type {number|undefined} + */ + this.rotation_ = undefined; + /** + * @private + * @type {number|undefined} + */ + this.scale_ = undefined; -/** - * Unregister listeners for view property changes. - * @param {ol.View} view The view. - * @private - */ -ol.control.OverviewMap.prototype.unbindView_ = function(view) { - goog.events.unlisten(view, - ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), - this.handleRotationChanged_, false, this); + /** + * @type {Array.<WebGLTexture>} + * @private + */ + this.textures_ = []; + + /** + * @type {Array.<WebGLTexture>} + * @private + */ + this.hitDetectionTextures_ = []; + + /** + * @type {Array.<number>} + * @private + */ + this.vertices_ = []; + + /** + * @type {ol.webgl.Buffer} + * @private + */ + this.verticesBuffer_ = null; + + /** + * Start index per feature (the index). + * @type {Array.<number>} + * @private + */ + this.startIndices_ = []; + + /** + * Start index per feature (the feature). + * @type {Array.<ol.Feature>} + * @private + */ + this.startIndicesFeature_ = []; + + /** + * @type {number|undefined} + * @private + */ + this.width_ = undefined; }; +goog.inherits(ol.render.webgl.ImageReplay, ol.render.VectorContext); /** - * Handle rotation changes to the main map. - * TODO: This should rotate the extent rectrangle instead of the - * overview map's view. - * @private + * @param {ol.webgl.Context} context WebGL context. + * @return {function()} Delete resources function. */ -ol.control.OverviewMap.prototype.handleRotationChanged_ = function() { - this.ovmap_.getView().setRotation(this.getMap().getView().getRotation()); +ol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction = + function(context) { + // We only delete our stuff here. The shaders and the program may + // be used by other ImageReplay instances (for other layers). And + // they will be deleted when disposing of the ol.webgl.Context + // object. + goog.asserts.assert(this.verticesBuffer_, + 'verticesBuffer must not be null'); + goog.asserts.assert(this.indicesBuffer_, + 'indicesBuffer must not be null'); + var verticesBuffer = this.verticesBuffer_; + var indicesBuffer = this.indicesBuffer_; + var textures = this.textures_; + var hitDetectionTextures = this.hitDetectionTextures_; + var gl = context.getGL(); + return function() { + if (!gl.isContextLost()) { + var i, ii; + for (i = 0, ii = textures.length; i < ii; ++i) { + gl.deleteTexture(textures[i]); + } + for (i = 0, ii = hitDetectionTextures.length; i < ii; ++i) { + gl.deleteTexture(hitDetectionTextures[i]); + } + } + context.deleteBuffer(verticesBuffer); + context.deleteBuffer(indicesBuffer); + }; }; /** - * Update the overview map element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.OverviewMap} - * @api + * @inheritDoc */ -ol.control.OverviewMap.render = function(mapEvent) { - this.validateExtent_(); - this.updateBox_(); -}; +ol.render.webgl.ImageReplay.prototype.drawAsync = goog.abstractMethod; /** - * Reset the overview map extent if the box size (width or - * height) is less than the size of the overview map size times minRatio - * or is greater than the size of the overview size times maxRatio. - * - * If the map extent was not reset, the box size can fits in the defined - * ratio sizes. This method then checks if is contained inside the overview - * map current extent. If not, recenter the overview map to the current - * main map center location. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {number} My end. * @private */ -ol.control.OverviewMap.prototype.validateExtent_ = function() { - var map = this.getMap(); - var ovmap = this.ovmap_; - - if (!map.isRendered() || !ovmap.isRendered()) { - return; - } +ol.render.webgl.ImageReplay.prototype.drawCoordinates_ = + function(flatCoordinates, offset, end, stride) { + goog.asserts.assert(this.anchorX_ !== undefined, 'anchorX is defined'); + goog.asserts.assert(this.anchorY_ !== undefined, 'anchorY is defined'); + goog.asserts.assert(this.height_ !== undefined, 'height is defined'); + goog.asserts.assert(this.imageHeight_ !== undefined, + 'imageHeight is defined'); + goog.asserts.assert(this.imageWidth_ !== undefined, 'imageWidth is defined'); + goog.asserts.assert(this.opacity_ !== undefined, 'opacity is defined'); + goog.asserts.assert(this.originX_ !== undefined, 'originX is defined'); + goog.asserts.assert(this.originY_ !== undefined, 'originY is defined'); + goog.asserts.assert(this.rotateWithView_ !== undefined, + 'rotateWithView is defined'); + goog.asserts.assert(this.rotation_ !== undefined, 'rotation is defined'); + goog.asserts.assert(this.scale_ !== undefined, 'scale is defined'); + goog.asserts.assert(this.width_ !== undefined, 'width is defined'); + var anchorX = this.anchorX_; + var anchorY = this.anchorY_; + var height = this.height_; + var imageHeight = this.imageHeight_; + var imageWidth = this.imageWidth_; + var opacity = this.opacity_; + var originX = this.originX_; + var originY = this.originY_; + var rotateWithView = this.rotateWithView_ ? 1.0 : 0.0; + var rotation = this.rotation_; + var scale = this.scale_; + var width = this.width_; + var cos = Math.cos(rotation); + var sin = Math.sin(rotation); + var numIndices = this.indices_.length; + var numVertices = this.vertices_.length; + var i, n, offsetX, offsetY, x, y; + for (i = offset; i < end; i += stride) { + x = flatCoordinates[i] - this.origin_[0]; + y = flatCoordinates[i + 1] - this.origin_[1]; - var mapSize = map.getSize(); - goog.asserts.assertArray(mapSize, 'mapSize should be an array'); + // There are 4 vertices per [x, y] point, one for each corner of the + // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if + // WebGL supported Geometry Shaders (which can emit new vertices), but that + // is not currently the case. + // + // And each vertex includes 8 values: the x and y coordinates, the x and + // y offsets used to calculate the position of the corner, the u and + // v texture coordinates for the corner, the opacity, and whether the + // the image should be rotated with the view (rotateWithView). - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - var extent = view.calculateExtent(mapSize); + n = numVertices / 8; - var ovmapSize = ovmap.getSize(); - goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); + // bottom-left corner + offsetX = -scale * anchorX; + offsetY = -scale * (height - anchorY); + this.vertices_[numVertices++] = x; + this.vertices_[numVertices++] = y; + this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; + this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; + this.vertices_[numVertices++] = originX / imageWidth; + this.vertices_[numVertices++] = (originY + height) / imageHeight; + this.vertices_[numVertices++] = opacity; + this.vertices_[numVertices++] = rotateWithView; - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - var ovextent = ovview.calculateExtent(ovmapSize); + // bottom-right corner + offsetX = scale * (width - anchorX); + offsetY = -scale * (height - anchorY); + this.vertices_[numVertices++] = x; + this.vertices_[numVertices++] = y; + this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; + this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; + this.vertices_[numVertices++] = (originX + width) / imageWidth; + this.vertices_[numVertices++] = (originY + height) / imageHeight; + this.vertices_[numVertices++] = opacity; + this.vertices_[numVertices++] = rotateWithView; - var topLeftPixel = - ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent)); - var bottomRightPixel = - ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent)); - var boxSize = new goog.math.Size( - Math.abs(topLeftPixel[0] - bottomRightPixel[0]), - Math.abs(topLeftPixel[1] - bottomRightPixel[1])); + // top-right corner + offsetX = scale * (width - anchorX); + offsetY = scale * anchorY; + this.vertices_[numVertices++] = x; + this.vertices_[numVertices++] = y; + this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; + this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; + this.vertices_[numVertices++] = (originX + width) / imageWidth; + this.vertices_[numVertices++] = originY / imageHeight; + this.vertices_[numVertices++] = opacity; + this.vertices_[numVertices++] = rotateWithView; - var ovmapWidth = ovmapSize[0]; - var ovmapHeight = ovmapSize[1]; + // top-left corner + offsetX = -scale * anchorX; + offsetY = scale * anchorY; + this.vertices_[numVertices++] = x; + this.vertices_[numVertices++] = y; + this.vertices_[numVertices++] = offsetX * cos - offsetY * sin; + this.vertices_[numVertices++] = offsetX * sin + offsetY * cos; + this.vertices_[numVertices++] = originX / imageWidth; + this.vertices_[numVertices++] = originY / imageHeight; + this.vertices_[numVertices++] = opacity; + this.vertices_[numVertices++] = rotateWithView; - if (boxSize.width < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO || - boxSize.height < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO || - boxSize.width > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO || - boxSize.height > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) { - this.resetExtent_(); - } else if (!ol.extent.containsExtent(ovextent, extent)) { - this.recenter_(); + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = n + 1; + this.indices_[numIndices++] = n + 2; + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = n + 2; + this.indices_[numIndices++] = n + 3; } + + return numVertices; }; /** - * Reset the overview map extent to half calculated min and max ratio times - * the extent of the main map. - * @private + * @inheritDoc */ -ol.control.OverviewMap.prototype.resetExtent_ = function() { - if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) { - return; - } - - var map = this.getMap(); - var ovmap = this.ovmap_; - - var mapSize = map.getSize(); - goog.asserts.assertArray(mapSize, 'mapSize should be an array'); - - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - var extent = view.calculateExtent(mapSize); - - var ovmapSize = ovmap.getSize(); - goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - - // get how many times the current map overview could hold different - // box sizes using the min and max ratio, pick the step in the middle used - // to calculate the extent from the main map to set it to the overview map, - var steps = Math.log( - ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2; - var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO); - ol.extent.scaleFromCenter(extent, ratio); - ovview.fit(extent, ovmapSize); +ol.render.webgl.ImageReplay.prototype.drawMultiPointGeometry = + function(multiPointGeometry, feature) { + this.startIndices_.push(this.indices_.length); + this.startIndicesFeature_.push(feature); + var flatCoordinates = multiPointGeometry.getFlatCoordinates(); + var stride = multiPointGeometry.getStride(); + this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); }; /** - * Set the center of the overview map to the map center without changing its - * resolution. - * @private + * @inheritDoc */ -ol.control.OverviewMap.prototype.recenter_ = function() { - var map = this.getMap(); - var ovmap = this.ovmap_; - - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); - - ovview.setCenter(view.getCenter()); +ol.render.webgl.ImageReplay.prototype.drawPointGeometry = + function(pointGeometry, feature) { + this.startIndices_.push(this.indices_.length); + this.startIndicesFeature_.push(feature); + var flatCoordinates = pointGeometry.getFlatCoordinates(); + var stride = pointGeometry.getStride(); + this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); }; /** - * Update the box using the main map extent - * @private + * @param {ol.webgl.Context} context Context. */ -ol.control.OverviewMap.prototype.updateBox_ = function() { - var map = this.getMap(); - var ovmap = this.ovmap_; +ol.render.webgl.ImageReplay.prototype.finish = function(context) { + var gl = context.getGL(); - if (!map.isRendered() || !ovmap.isRendered()) { - return; - } + this.groupIndices_.push(this.indices_.length); + goog.asserts.assert(this.images_.length === this.groupIndices_.length, + 'number of images and groupIndices match'); + this.hitDetectionGroupIndices_.push(this.indices_.length); + goog.asserts.assert(this.hitDetectionImages_.length === + this.hitDetectionGroupIndices_.length, + 'number of hitDetectionImages and hitDetectionGroupIndices match'); - var mapSize = map.getSize(); - goog.asserts.assertArray(mapSize, 'mapSize should be an array'); + // create, bind, and populate the vertices buffer + this.verticesBuffer_ = new ol.webgl.Buffer(this.vertices_); + context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); - - var ovview = ovmap.getView(); - goog.asserts.assert(ovview, 'ovview should be defined'); + var indices = this.indices_; + var bits = context.hasOESElementIndexUint ? 32 : 16; + goog.asserts.assert(indices[indices.length - 1] < Math.pow(2, bits), + 'Too large element index detected [%s] (OES_element_index_uint "%s")', + indices[indices.length - 1], context.hasOESElementIndexUint); - var ovmapSize = ovmap.getSize(); - goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); + // create, bind, and populate the indices buffer + this.indicesBuffer_ = new ol.webgl.Buffer(indices); + context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); - var rotation = view.getRotation(); - goog.asserts.assert(rotation !== undefined, 'rotation should be defined'); + // create textures + /** @type {Object.<string, WebGLTexture>} */ + var texturePerImage = {}; - var overlay = this.boxOverlay_; - var box = this.boxOverlay_.getElement(); - var extent = view.calculateExtent(mapSize); - var ovresolution = ovview.getResolution(); - var bottomLeft = ol.extent.getBottomLeft(extent); - var topRight = ol.extent.getTopRight(extent); + this.createTextures_(this.textures_, this.images_, texturePerImage, gl); + goog.asserts.assert(this.textures_.length === this.groupIndices_.length, + 'number of textures and groupIndices match'); - // set position using bottom left coordinates - var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft); - overlay.setPosition(rotateBottomLeft); + this.createTextures_(this.hitDetectionTextures_, this.hitDetectionImages_, + texturePerImage, gl); + goog.asserts.assert(this.hitDetectionTextures_.length === + this.hitDetectionGroupIndices_.length, + 'number of hitDetectionTextures and hitDetectionGroupIndices match'); - // set box size calculated from map extent size and overview map resolution - if (box) { - var boxWidth = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution); - var boxHeight = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution); - goog.style.setBorderBoxSize(box, new goog.math.Size( - boxWidth, boxHeight)); - } + this.anchorX_ = undefined; + this.anchorY_ = undefined; + this.height_ = undefined; + this.images_ = null; + this.hitDetectionImages_ = null; + this.imageHeight_ = undefined; + this.imageWidth_ = undefined; + this.indices_ = null; + this.opacity_ = undefined; + this.originX_ = undefined; + this.originY_ = undefined; + this.rotateWithView_ = undefined; + this.rotation_ = undefined; + this.scale_ = undefined; + this.vertices_ = null; + this.width_ = undefined; }; /** - * @param {number} rotation Target rotation. - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor. * @private + * @param {Array.<WebGLTexture>} textures Textures. + * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images + * Images. + * @param {Object.<string, WebGLTexture>} texturePerImage Texture cache. + * @param {WebGLRenderingContext} gl Gl. */ -ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function( - rotation, coordinate) { - var coordinateRotate; - - var map = this.getMap(); - var view = map.getView(); - goog.asserts.assert(view, 'view should be defined'); +ol.render.webgl.ImageReplay.prototype.createTextures_ = + function(textures, images, texturePerImage, gl) { + goog.asserts.assert(textures.length === 0, + 'upon creation, textures is empty'); - var currentCenter = view.getCenter(); + var texture, image, uid, i; + var ii = images.length; + for (i = 0; i < ii; ++i) { + image = images[i]; - if (currentCenter) { - coordinateRotate = [ - coordinate[0] - currentCenter[0], - coordinate[1] - currentCenter[1] - ]; - ol.coordinate.rotate(coordinateRotate, rotation); - ol.coordinate.add(coordinateRotate, currentCenter); + uid = goog.getUid(image).toString(); + if (goog.object.containsKey(texturePerImage, uid)) { + texture = texturePerImage[uid]; + } else { + texture = ol.webgl.Context.createTexture( + gl, image, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); + texturePerImage[uid] = texture; + } + textures[i] = texture; } - return coordinateRotate; }; /** - * @param {goog.events.BrowserEvent} event The event to handle - * @private + * @param {ol.webgl.Context} context Context. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {number} pixelRatio Pixel ratio. + * @param {number} opacity Global opacity. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. + * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. + * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting + * this extent are checked. + * @return {T|undefined} Callback result. + * @template T */ -ol.control.OverviewMap.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleToggle_(); -}; +ol.render.webgl.ImageReplay.prototype.replay = function(context, + center, resolution, rotation, size, pixelRatio, + opacity, skippedFeaturesHash, + featureCallback, oneByOne, opt_hitExtent) { + var gl = context.getGL(); + + // bind the vertices buffer + goog.asserts.assert(this.verticesBuffer_, + 'verticesBuffer must not be null'); + context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); + // bind the indices buffer + goog.asserts.assert(this.indicesBuffer_, + 'indecesBuffer must not be null'); + context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); -/** - * @private - */ -ol.control.OverviewMap.prototype.handleToggle_ = function() { - goog.dom.classlist.toggle(this.element, 'ol-collapsed'); - if (this.collapsed_) { - goog.dom.replaceNode(this.collapseLabel_, this.label_); + // get the program + var fragmentShader = + ol.render.webgl.imagereplay.shader.DefaultFragment.getInstance(); + var vertexShader = + ol.render.webgl.imagereplay.shader.DefaultVertex.getInstance(); + var program = context.getProgram(fragmentShader, vertexShader); + + // get the locations + var locations; + if (!this.defaultLocations_) { + locations = + new ol.render.webgl.imagereplay.shader.Default.Locations(gl, program); + this.defaultLocations_ = locations; } else { - goog.dom.replaceNode(this.label_, this.collapseLabel_); + locations = this.defaultLocations_; } - this.collapsed_ = !this.collapsed_; - // manage overview map if it had not been rendered before and control - // is expanded - var ovmap = this.ovmap_; - if (!this.collapsed_ && !ovmap.isRendered()) { - ovmap.updateSize(); - this.resetExtent_(); - goog.events.listenOnce(ovmap, ol.MapEventType.POSTRENDER, - function(event) { - this.updateBox_(); - }, - false, this); - } -}; + // use the program (FIXME: use the return value) + context.useProgram(program); + // enable the vertex attrib arrays + gl.enableVertexAttribArray(locations.a_position); + gl.vertexAttribPointer(locations.a_position, 2, goog.webgl.FLOAT, + false, 32, 0); -/** - * Return `true` if the overview map is collapsible, `false` otherwise. - * @return {boolean} True if the widget is collapsible. - * @api stable - */ -ol.control.OverviewMap.prototype.getCollapsible = function() { - return this.collapsible_; -}; + gl.enableVertexAttribArray(locations.a_offsets); + gl.vertexAttribPointer(locations.a_offsets, 2, goog.webgl.FLOAT, + false, 32, 8); + gl.enableVertexAttribArray(locations.a_texCoord); + gl.vertexAttribPointer(locations.a_texCoord, 2, goog.webgl.FLOAT, + false, 32, 16); -/** - * Set whether the overview map should be collapsible. - * @param {boolean} collapsible True if the widget is collapsible. - * @api stable - */ -ol.control.OverviewMap.prototype.setCollapsible = function(collapsible) { - if (this.collapsible_ === collapsible) { - return; + gl.enableVertexAttribArray(locations.a_opacity); + gl.vertexAttribPointer(locations.a_opacity, 1, goog.webgl.FLOAT, + false, 32, 24); + + gl.enableVertexAttribArray(locations.a_rotateWithView); + gl.vertexAttribPointer(locations.a_rotateWithView, 1, goog.webgl.FLOAT, + false, 32, 28); + + // set the "uniform" values + var projectionMatrix = this.projectionMatrix_; + ol.vec.Mat4.makeTransform2D(projectionMatrix, + 0.0, 0.0, + 2 / (resolution * size[0]), + 2 / (resolution * size[1]), + -rotation, + -(center[0] - this.origin_[0]), -(center[1] - this.origin_[1])); + + var offsetScaleMatrix = this.offsetScaleMatrix_; + goog.vec.Mat4.makeScale(offsetScaleMatrix, 2 / size[0], 2 / size[1], 1); + + var offsetRotateMatrix = this.offsetRotateMatrix_; + goog.vec.Mat4.makeIdentity(offsetRotateMatrix); + if (rotation !== 0) { + goog.vec.Mat4.rotateZ(offsetRotateMatrix, -rotation); } - this.collapsible_ = collapsible; - goog.dom.classlist.toggle(this.element, 'ol-uncollapsible'); - if (!collapsible && this.collapsed_) { - this.handleToggle_(); + + gl.uniformMatrix4fv(locations.u_projectionMatrix, false, projectionMatrix); + gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false, offsetScaleMatrix); + gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false, + offsetRotateMatrix); + gl.uniform1f(locations.u_opacity, opacity); + + // draw! + var result; + if (featureCallback === undefined) { + this.drawReplay_(gl, context, skippedFeaturesHash, + this.textures_, this.groupIndices_); + } else { + // draw feature by feature for the hit-detection + result = this.drawHitDetectionReplay_(gl, context, skippedFeaturesHash, + featureCallback, oneByOne, opt_hitExtent); } + + // disable the vertex attrib arrays + gl.disableVertexAttribArray(locations.a_position); + gl.disableVertexAttribArray(locations.a_offsets); + gl.disableVertexAttribArray(locations.a_texCoord); + gl.disableVertexAttribArray(locations.a_opacity); + gl.disableVertexAttribArray(locations.a_rotateWithView); + + return result; }; /** - * Collapse or expand the overview map according to the passed parameter. Will - * not do anything if the overview map isn't collapsible or if the current - * collapsed state is already the one requested. - * @param {boolean} collapsed True if the widget is collapsed. - * @api stable + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {ol.webgl.Context} context Context. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {Array.<WebGLTexture>} textures Textures. + * @param {Array.<number>} groupIndices Texture group indices. */ -ol.control.OverviewMap.prototype.setCollapsed = function(collapsed) { - if (!this.collapsible_ || this.collapsed_ === collapsed) { - return; +ol.render.webgl.ImageReplay.prototype.drawReplay_ = + function(gl, context, skippedFeaturesHash, textures, groupIndices) { + goog.asserts.assert(textures.length === groupIndices.length, + 'number of textures and groupIndeces match'); + var elementType = context.hasOESElementIndexUint ? + goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; + var elementSize = context.hasOESElementIndexUint ? 4 : 2; + + if (!goog.object.isEmpty(skippedFeaturesHash)) { + this.drawReplaySkipping_( + gl, skippedFeaturesHash, textures, groupIndices, + elementType, elementSize); + } else { + var i, ii, start; + for (i = 0, ii = textures.length, start = 0; i < ii; ++i) { + gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]); + var end = groupIndices[i]; + this.drawElements_(gl, start, end, elementType, elementSize); + start = end; + } } - this.handleToggle_(); }; /** - * Determine if the overview map is collapsed. - * @return {boolean} The overview map is collapsed. - * @api stable + * Draw the replay while paying attention to skipped features. + * + * This functions creates groups of features that can be drawn to together, + * so that the number of `drawElements` calls is minimized. + * + * For example given the following texture groups: + * + * Group 1: A B C + * Group 2: D [E] F G + * + * If feature E should be skipped, the following `drawElements` calls will be + * made: + * + * drawElements with feature A, B and C + * drawElements with feature D + * drawElements with feature F and G + * + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {Array.<WebGLTexture>} textures Textures. + * @param {Array.<number>} groupIndices Texture group indices. + * @param {number} elementType Element type. + * @param {number} elementSize Element Size. */ -ol.control.OverviewMap.prototype.getCollapsed = function() { - return this.collapsed_; +ol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ = + function(gl, skippedFeaturesHash, textures, groupIndices, + elementType, elementSize) { + var featureIndex = 0; + + var i, ii; + for (i = 0, ii = textures.length; i < ii; ++i) { + gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]); + var groupStart = (i > 0) ? groupIndices[i - 1] : 0; + var groupEnd = groupIndices[i]; + + var start = groupStart; + var end = groupStart; + while (featureIndex < this.startIndices_.length && + this.startIndices_[featureIndex] <= groupEnd) { + var feature = this.startIndicesFeature_[featureIndex]; + + var featureUid = goog.getUid(feature).toString(); + if (skippedFeaturesHash[featureUid] !== undefined) { + // feature should be skipped + if (start !== end) { + // draw the features so far + this.drawElements_(gl, start, end, elementType, elementSize); + } + // continue with the next feature + start = (featureIndex === this.startIndices_.length - 1) ? + groupEnd : this.startIndices_[featureIndex + 1]; + end = start; + } else { + // the feature is not skipped, augment the end index + end = (featureIndex === this.startIndices_.length - 1) ? + groupEnd : this.startIndices_[featureIndex + 1]; + } + featureIndex++; + } + + if (start !== end) { + // draw the remaining features (in case there was no skipped feature + // in this texture group, all features of a group are drawn together) + this.drawElements_(gl, start, end, elementType, elementSize); + } + } }; /** - * Return the overview map. - * @return {ol.Map} Overview map. - * @api + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {number} start Start index. + * @param {number} end End index. + * @param {number} elementType Element type. + * @param {number} elementSize Element Size. */ -ol.control.OverviewMap.prototype.getOverviewMap = function() { - return this.ovmap_; +ol.render.webgl.ImageReplay.prototype.drawElements_ = function( + gl, start, end, elementType, elementSize) { + var numItems = end - start; + var offsetInBytes = start * elementSize; + gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes); }; -goog.provide('ol.control.ScaleLine'); -goog.provide('ol.control.ScaleLineProperty'); -goog.provide('ol.control.ScaleLineUnits'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.style'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.TransformFunction'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.proj.METERS_PER_UNIT'); -goog.require('ol.proj.Units'); -goog.require('ol.sphere.NORMAL'); - /** - * @enum {string} + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {ol.webgl.Context} context Context. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. + * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. + * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting + * this extent are checked. + * @return {T|undefined} Callback result. + * @template T */ -ol.control.ScaleLineProperty = { - UNITS: 'units' +ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplay_ = + function(gl, context, skippedFeaturesHash, featureCallback, oneByOne, + opt_hitExtent) { + if (!oneByOne) { + // draw all hit-detection features in "once" (by texture group) + return this.drawHitDetectionReplayAll_(gl, context, + skippedFeaturesHash, featureCallback); + } else { + // draw hit-detection features one by one + return this.drawHitDetectionReplayOneByOne_(gl, context, + skippedFeaturesHash, featureCallback, opt_hitExtent); + } }; /** - * Units for the scale line. Supported values are `'degrees'`, `'imperial'`, - * `'nautical'`, `'metric'`, `'us'`. - * @enum {string} - * @api stable + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {ol.webgl.Context} context Context. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. + * @return {T|undefined} Callback result. + * @template T */ -ol.control.ScaleLineUnits = { - DEGREES: 'degrees', - IMPERIAL: 'imperial', - NAUTICAL: 'nautical', - METRIC: 'metric', - US: 'us' -}; +ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayAll_ = + function(gl, context, skippedFeaturesHash, featureCallback) { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + this.drawReplay_(gl, context, skippedFeaturesHash, + this.hitDetectionTextures_, this.hitDetectionGroupIndices_); + var result = featureCallback(null); + if (result) { + return result; + } else { + return undefined; + } +}; /** - * @classdesc - * A control displaying rough x-axis distances, calculated for the center of the - * viewport. - * No scale line will be shown when the x-axis distance cannot be calculated in - * the view projection (e.g. at or beyond the poles in EPSG:4326). - * By default the scale line will show in the bottom left portion of the map, - * but this can be changed by using the css selector `.ol-scale-line`. - * - * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ScaleLineOptions=} opt_options Scale line options. - * @api stable + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {ol.webgl.Context} context Context. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. + * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting + * this extent are checked. + * @return {T|undefined} Callback result. + * @template T */ -ol.control.ScaleLine = function(opt_options) { +ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne_ = + function(gl, context, skippedFeaturesHash, featureCallback, + opt_hitExtent) { + goog.asserts.assert(this.hitDetectionTextures_.length === + this.hitDetectionGroupIndices_.length, + 'number of hitDetectionTextures and hitDetectionGroupIndices match'); + var elementType = context.hasOESElementIndexUint ? + goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; + var elementSize = context.hasOESElementIndexUint ? 4 : 2; - var options = opt_options ? opt_options : {}; + var i, groupStart, start, end, feature, featureUid; + var featureIndex = this.startIndices_.length - 1; + for (i = this.hitDetectionTextures_.length - 1; i >= 0; --i) { + gl.bindTexture(goog.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]); + groupStart = (i > 0) ? this.hitDetectionGroupIndices_[i - 1] : 0; + end = this.hitDetectionGroupIndices_[i]; - var className = options.className ? options.className : 'ol-scale-line'; + // draw all features for this texture group + while (featureIndex >= 0 && + this.startIndices_[featureIndex] >= groupStart) { + start = this.startIndices_[featureIndex]; + feature = this.startIndicesFeature_[featureIndex]; + featureUid = goog.getUid(feature).toString(); - /** - * @private - * @type {Element} - */ - this.innerElement_ = goog.dom.createDom('DIV', - className + '-inner'); + if (skippedFeaturesHash[featureUid] === undefined && + feature.getGeometry() && + (opt_hitExtent === undefined || ol.extent.intersects( + /** @type {Array<number>} */ (opt_hitExtent), + feature.getGeometry().getExtent()))) { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + this.drawElements_(gl, start, end, elementType, elementSize); - /** - * @private - * @type {Element} - */ - this.element_ = goog.dom.createDom('DIV', - className + ' ' + ol.css.CLASS_UNSELECTABLE, this.innerElement_); + var result = featureCallback(feature); + if (result) { + return result; + } + } - /** - * @private - * @type {?olx.ViewState} - */ - this.viewState_ = null; + end = start; + featureIndex--; + } + } + return undefined; +}; - /** - * @private - * @type {number} - */ - this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64; + +/** + * @inheritDoc + */ +ol.render.webgl.ImageReplay.prototype.setFillStrokeStyle = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) { + var anchor = imageStyle.getAnchor(); + var image = imageStyle.getImage(1); + var imageSize = imageStyle.getImageSize(); + var hitDetectionImage = imageStyle.getHitDetectionImage(1); + var hitDetectionImageSize = imageStyle.getHitDetectionImageSize(); + var opacity = imageStyle.getOpacity(); + var origin = imageStyle.getOrigin(); + var rotateWithView = imageStyle.getRotateWithView(); + var rotation = imageStyle.getRotation(); + var size = imageStyle.getSize(); + var scale = imageStyle.getScale(); + goog.asserts.assert(anchor, 'imageStyle anchor is not null'); + goog.asserts.assert(image, 'imageStyle image is not null'); + goog.asserts.assert(imageSize, + 'imageStyle imageSize is not null'); + goog.asserts.assert(hitDetectionImage, + 'imageStyle hitDetectionImage is not null'); + goog.asserts.assert(hitDetectionImageSize, + 'imageStyle hitDetectionImageSize is not null'); + goog.asserts.assert(opacity !== undefined, 'imageStyle opacity is defined'); + goog.asserts.assert(origin, 'imageStyle origin is not null'); + goog.asserts.assert(rotateWithView !== undefined, + 'imageStyle rotateWithView is defined'); + goog.asserts.assert(rotation !== undefined, 'imageStyle rotation is defined'); + goog.asserts.assert(size, 'imageStyle size is not null'); + goog.asserts.assert(scale !== undefined, 'imageStyle scale is defined'); + + var currentImage; + if (this.images_.length === 0) { + this.images_.push(image); + } else { + currentImage = this.images_[this.images_.length - 1]; + if (goog.getUid(currentImage) != goog.getUid(image)) { + this.groupIndices_.push(this.indices_.length); + goog.asserts.assert(this.groupIndices_.length === this.images_.length, + 'number of groupIndices and images match'); + this.images_.push(image); + } + } + + if (this.hitDetectionImages_.length === 0) { + this.hitDetectionImages_.push(hitDetectionImage); + } else { + currentImage = + this.hitDetectionImages_[this.hitDetectionImages_.length - 1]; + if (goog.getUid(currentImage) != goog.getUid(hitDetectionImage)) { + this.hitDetectionGroupIndices_.push(this.indices_.length); + goog.asserts.assert(this.hitDetectionGroupIndices_.length === + this.hitDetectionImages_.length, + 'number of hitDetectionGroupIndices and hitDetectionImages match'); + this.hitDetectionImages_.push(hitDetectionImage); + } + } + + this.anchorX_ = anchor[0]; + this.anchorY_ = anchor[1]; + this.height_ = size[1]; + this.imageHeight_ = imageSize[1]; + this.imageWidth_ = imageSize[0]; + this.opacity_ = opacity; + this.originX_ = origin[0]; + this.originY_ = origin[1]; + this.rotation_ = rotation; + this.rotateWithView_ = rotateWithView; + this.scale_ = scale; + this.width_ = size[0]; +}; + + + +/** + * @constructor + * @implements {ol.render.IReplayGroup} + * @param {number} tolerance Tolerance. + * @param {ol.Extent} maxExtent Max extent. + * @param {number=} opt_renderBuffer Render buffer. + * @struct + */ +ol.render.webgl.ReplayGroup = function( + tolerance, maxExtent, opt_renderBuffer) { /** + * @type {ol.Extent} * @private - * @type {boolean} */ - this.renderedVisible_ = false; + this.maxExtent_ = maxExtent; /** + * @type {number} * @private - * @type {number|undefined} */ - this.renderedWidth_ = undefined; + this.tolerance_ = tolerance; /** + * @type {number|undefined} * @private - * @type {string} */ - this.renderedHTML_ = ''; + this.renderBuffer_ = opt_renderBuffer; /** + * ImageReplay only is supported at this point. + * @type {Object.<ol.render.ReplayType, ol.render.webgl.ImageReplay>} * @private - * @type {?ol.TransformFunction} */ - this.toEPSG4326_ = null; - - var render = options.render ? options.render : ol.control.ScaleLine.render; - - goog.base(this, { - element: this.element_, - render: render, - target: options.target - }); - - goog.events.listen( - this, ol.Object.getChangeEventType(ol.control.ScaleLineProperty.UNITS), - this.handleUnitsChanged_, false, this); - - this.setUnits(/** @type {ol.control.ScaleLineUnits} */ (options.units) || - ol.control.ScaleLineUnits.METRIC); + this.replays_ = {}; }; -goog.inherits(ol.control.ScaleLine, ol.control.Control); /** - * @const - * @type {Array.<number>} + * @param {ol.webgl.Context} context WebGL context. + * @return {function()} Delete resources function. */ -ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5]; +ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = + function(context) { + var functions = []; + var replayKey; + for (replayKey in this.replays_) { + functions.push( + this.replays_[replayKey].getDeleteResourcesFunction(context)); + } + return goog.functions.sequence.apply(null, functions); +}; /** - * Return the units to use in the scale line. - * @return {ol.control.ScaleLineUnits|undefined} The units to use in the scale - * line. - * @observable - * @api stable + * @param {ol.webgl.Context} context Context. */ -ol.control.ScaleLine.prototype.getUnits = function() { - return /** @type {ol.control.ScaleLineUnits|undefined} */ ( - this.get(ol.control.ScaleLineProperty.UNITS)); +ol.render.webgl.ReplayGroup.prototype.finish = function(context) { + var replayKey; + for (replayKey in this.replays_) { + this.replays_[replayKey].finish(context); + } }; /** - * Update the scale line element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.ScaleLine} - * @api + * @inheritDoc */ -ol.control.ScaleLine.render = function(mapEvent) { - var frameState = mapEvent.frameState; - if (!frameState) { - this.viewState_ = null; - } else { - this.viewState_ = frameState.viewState; +ol.render.webgl.ReplayGroup.prototype.getReplay = + function(zIndex, replayType) { + var replay = this.replays_[replayType]; + if (replay === undefined) { + var constructor = ol.render.webgl.BATCH_CONSTRUCTORS_[replayType]; + goog.asserts.assert(constructor !== undefined, + replayType + + ' constructor missing from ol.render.webgl.BATCH_CONSTRUCTORS_'); + replay = new constructor(this.tolerance_, this.maxExtent_); + this.replays_[replayType] = replay; } - this.updateElement_(); + return replay; }; /** - * @private + * @inheritDoc */ -ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() { - this.updateElement_(); +ol.render.webgl.ReplayGroup.prototype.isEmpty = function() { + return goog.object.isEmpty(this.replays_); }; /** - * Set the units to use in the scale line. - * @param {ol.control.ScaleLineUnits} units The units to use in the scale line. - * @observable - * @api stable + * @param {ol.webgl.Context} context Context. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {number} pixelRatio Pixel ratio. + * @param {number} opacity Global opacity. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. */ -ol.control.ScaleLine.prototype.setUnits = function(units) { - this.set(ol.control.ScaleLineProperty.UNITS, units); +ol.render.webgl.ReplayGroup.prototype.replay = function(context, + center, resolution, rotation, size, pixelRatio, + opacity, skippedFeaturesHash) { + var i, ii, replay; + for (i = 0, ii = ol.render.REPLAY_ORDER.length; i < ii; ++i) { + replay = this.replays_[ol.render.REPLAY_ORDER[i]]; + if (replay !== undefined) { + replay.replay(context, + center, resolution, rotation, size, pixelRatio, + opacity, skippedFeaturesHash, + undefined, false); + } + } }; /** * @private + * @param {ol.webgl.Context} context Context. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {number} pixelRatio Pixel ratio. + * @param {number} opacity Global opacity. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. + * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. + * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting + * this extent are checked. + * @return {T|undefined} Callback result. + * @template T */ -ol.control.ScaleLine.prototype.updateElement_ = function() { - var viewState = this.viewState_; - - if (!viewState) { - if (this.renderedVisible_) { - goog.style.setElementShown(this.element_, false); - this.renderedVisible_ = false; +ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context, + center, resolution, rotation, size, pixelRatio, opacity, + skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) { + var i, replay, result; + for (i = ol.render.REPLAY_ORDER.length - 1; i >= 0; --i) { + replay = this.replays_[ol.render.REPLAY_ORDER[i]]; + if (replay !== undefined) { + result = replay.replay(context, + center, resolution, rotation, size, pixelRatio, opacity, + skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent); + if (result) { + return result; + } } - return; } + return undefined; +}; - var center = viewState.center; - var projection = viewState.projection; - var pointResolution = - projection.getPointResolution(viewState.resolution, center); - var projectionUnits = projection.getUnits(); - - var cosLatitude; - var units = this.getUnits(); - if (projectionUnits == ol.proj.Units.DEGREES && - (units == ol.control.ScaleLineUnits.METRIC || - units == ol.control.ScaleLineUnits.IMPERIAL || - units == ol.control.ScaleLineUnits.US || - units == ol.control.ScaleLineUnits.NAUTICAL)) { - - // Convert pointResolution from degrees to meters - this.toEPSG4326_ = null; - cosLatitude = Math.cos(ol.math.toRadians(center[1])); - pointResolution *= Math.PI * cosLatitude * ol.sphere.NORMAL.radius / 180; - projectionUnits = ol.proj.Units.METERS; - } else if (projectionUnits != ol.proj.Units.DEGREES && - units == ol.control.ScaleLineUnits.DEGREES) { +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {ol.webgl.Context} context Context. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {number} pixelRatio Pixel ratio. + * @param {number} opacity Global opacity. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @param {function(ol.Feature): T|undefined} callback Feature callback. + * @return {T|undefined} Callback result. + * @template T + */ +ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( + coordinate, context, center, resolution, rotation, size, pixelRatio, + opacity, skippedFeaturesHash, + callback) { + var gl = context.getGL(); + gl.bindFramebuffer( + gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); - // Convert pointResolution from other units to degrees - if (!this.toEPSG4326_) { - this.toEPSG4326_ = ol.proj.getTransformFromProjections( - projection, ol.proj.get('EPSG:4326')); - } - cosLatitude = Math.cos(ol.math.toRadians(this.toEPSG4326_(center)[1])); - var radius = ol.sphere.NORMAL.radius; - goog.asserts.assert(ol.proj.METERS_PER_UNIT[projectionUnits], - 'Meters per unit should be defined for the projection unit'); - radius /= ol.proj.METERS_PER_UNIT[projectionUnits]; - pointResolution *= 180 / (Math.PI * cosLatitude * radius); - projectionUnits = ol.proj.Units.DEGREES; - } else { - this.toEPSG4326_ = null; + /** + * @type {ol.Extent} + */ + var hitExtent; + if (this.renderBuffer_ !== undefined) { + // build an extent around the coordinate, so that only features that + // intersect this extent are checked + hitExtent = ol.extent.buffer( + ol.extent.createOrUpdateFromCoordinate(coordinate), + resolution * this.renderBuffer_); } - goog.asserts.assert( - ((units == ol.control.ScaleLineUnits.METRIC || - units == ol.control.ScaleLineUnits.IMPERIAL || - units == ol.control.ScaleLineUnits.US || - units == ol.control.ScaleLineUnits.NAUTICAL) && - projectionUnits == ol.proj.Units.METERS) || - (units == ol.control.ScaleLineUnits.DEGREES && - projectionUnits == ol.proj.Units.DEGREES), - 'Scale line units and projection units should match'); + return this.replayHitDetection_(context, + coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_, + pixelRatio, opacity, skippedFeaturesHash, + /** + * @param {ol.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + var imageData = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData); - var nominalCount = this.minWidth_ * pointResolution; - var suffix = ''; - if (units == ol.control.ScaleLineUnits.DEGREES) { - if (nominalCount < 1 / 60) { - suffix = '\u2033'; // seconds - pointResolution *= 3600; - } else if (nominalCount < 1) { - suffix = '\u2032'; // minutes - pointResolution *= 60; - } else { - suffix = '\u00b0'; // degrees - } - } else if (units == ol.control.ScaleLineUnits.IMPERIAL) { - if (nominalCount < 0.9144) { - suffix = 'in'; - pointResolution /= 0.0254; - } else if (nominalCount < 1609.344) { - suffix = 'ft'; - pointResolution /= 0.3048; - } else { - suffix = 'mi'; - pointResolution /= 1609.344; - } - } else if (units == ol.control.ScaleLineUnits.NAUTICAL) { - pointResolution /= 1852; - suffix = 'nm'; - } else if (units == ol.control.ScaleLineUnits.METRIC) { - if (nominalCount < 1) { - suffix = 'mm'; - pointResolution *= 1000; - } else if (nominalCount < 1000) { - suffix = 'm'; - } else { - suffix = 'km'; - pointResolution /= 1000; - } - } else if (units == ol.control.ScaleLineUnits.US) { - if (nominalCount < 0.9144) { - suffix = 'in'; - pointResolution *= 39.37; - } else if (nominalCount < 1609.344) { - suffix = 'ft'; - pointResolution /= 0.30480061; - } else { - suffix = 'mi'; - pointResolution /= 1609.3472; - } - } else { - goog.asserts.fail('Scale line element cannot be updated'); - } + if (imageData[3] > 0) { + var result = callback(feature); + if (result) { + return result; + } + } + }, true, hitExtent); +}; - var i = 3 * Math.floor( - Math.log(this.minWidth_ * pointResolution) / Math.log(10)); - var count, width; - while (true) { - count = ol.control.ScaleLine.LEADING_DIGITS[i % 3] * - Math.pow(10, Math.floor(i / 3)); - width = Math.round(count / pointResolution); - if (isNaN(width)) { - goog.style.setElementShown(this.element_, false); - this.renderedVisible_ = false; - return; - } else if (width >= this.minWidth_) { - break; - } - ++i; - } - var html = count + ' ' + suffix; - if (this.renderedHTML_ != html) { - this.innerElement_.innerHTML = html; - this.renderedHTML_ = html; - } +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @param {ol.webgl.Context} context Context. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {number} pixelRatio Pixel ratio. + * @param {number} opacity Global opacity. + * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features + * to skip. + * @return {boolean} Is there a feature at the given coordinate? + */ +ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function( + coordinate, context, center, resolution, rotation, size, pixelRatio, + opacity, skippedFeaturesHash) { + var gl = context.getGL(); + gl.bindFramebuffer( + gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); - if (this.renderedWidth_ != width) { - this.innerElement_.style.width = width + 'px'; - this.renderedWidth_ = width; - } + var hasFeature = this.replayHitDetection_(context, + coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_, + pixelRatio, opacity, skippedFeaturesHash, + /** + * @param {ol.Feature} feature Feature. + * @return {boolean} Is there a feature? + */ + function(feature) { + var imageData = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData); + return imageData[3] > 0; + }, false); + + return hasFeature !== undefined; +}; - if (!this.renderedVisible_) { - goog.style.setElementShown(this.element_, true); - this.renderedVisible_ = true; - } +/** + * @const + * @private + * @type {Object.<ol.render.ReplayType, + * function(new: ol.render.webgl.ImageReplay, number, + * ol.Extent)>} + */ +ol.render.webgl.BATCH_CONSTRUCTORS_ = { + 'Image': ol.render.webgl.ImageReplay }; -// Copyright 2005 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Class to create objects which want to handle multiple events - * and have their listeners easily cleaned up via a dispose method. - * - * Example: - * <pre> - * function Something() { - * Something.base(this); - * - * ... set up object ... - * - * // Add event listeners - * this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar); - * this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand); - * this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse); - * this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover); - * this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover); - * } - * goog.inherits(Something, goog.events.EventHandler); - * - * Something.prototype.disposeInternal = function() { - * Something.base(this, 'disposeInternal'); - * goog.dom.removeNode(this.container); - * }; - * - * - * // Then elsewhere: - * - * var activeSomething = null; - * function openSomething() { - * activeSomething = new Something(); - * } - * - * function closeSomething() { - * if (activeSomething) { - * activeSomething.dispose(); // Remove event listeners - * activeSomething = null; - * } - * } - * </pre> - * + * @const + * @private + * @type {Array.<number>} */ +ol.render.webgl.HIT_DETECTION_SIZE_ = [1, 1]; -goog.provide('goog.events.EventHandler'); - -goog.require('goog.Disposable'); -goog.require('goog.events'); -goog.require('goog.object'); - -goog.forwardDeclare('goog.events.EventWrapper'); +goog.provide('ol.render.webgl.Immediate'); +goog.require('goog.array'); +goog.require('ol.extent'); +goog.require('ol.render.VectorContext'); +goog.require('ol.render.webgl.ImageReplay'); +goog.require('ol.render.webgl.ReplayGroup'); /** - * Super class for objects that want to easily manage a number of event - * listeners. It allows a short cut to listen and also provides a quick way - * to remove all events listeners belonging to this object. - * @param {SCOPE=} opt_scope Object in whose scope to call the listeners. * @constructor - * @extends {goog.Disposable} - * @template SCOPE + * @extends {ol.render.VectorContext} + * @param {ol.webgl.Context} context Context. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {ol.Size} size Size. + * @param {ol.Extent} extent Extent. + * @param {number} pixelRatio Pixel ratio. + * @struct */ -goog.events.EventHandler = function(opt_scope) { - goog.Disposable.call(this); - // TODO(mknichel): Rename this to this.scope_ and fix the classes in google3 - // that access this private variable. :( - this.handler_ = opt_scope; +ol.render.webgl.Immediate = function(context, + center, resolution, rotation, size, extent, pixelRatio) { + goog.base(this); /** - * Keys for events that are being listened to. - * @type {!Object<!goog.events.Key>} * @private */ - this.keys_ = {}; + this.context_ = context; + + /** + * @private + */ + this.center_ = center; + + /** + * @private + */ + this.extent_ = extent; + + /** + * @private + */ + this.pixelRatio_ = pixelRatio; + + /** + * @private + */ + this.size_ = size; + + /** + * @private + */ + this.rotation_ = rotation; + + /** + * @private + */ + this.resolution_ = resolution; + + /** + * @private + * @type {ol.style.Image} + */ + this.imageStyle_ = null; + + /** + * @private + * @type {!Object.<string, + * Array.<function(ol.render.webgl.Immediate)>>} + */ + this.callbacksByZIndex_ = {}; }; -goog.inherits(goog.events.EventHandler, goog.Disposable); +goog.inherits(ol.render.webgl.Immediate, ol.render.VectorContext); /** - * Utility array used to unify the cases of listening for an array of types - * and listening for a single event, without using recursion or allocating - * an array each time. - * @type {!Array<string>} - * @const - * @private + * FIXME: empty description for jsdoc */ -goog.events.EventHandler.typeArray_ = []; +ol.render.webgl.Immediate.prototype.flush = function() { + /** @type {Array.<number>} */ + var zs = Object.keys(this.callbacksByZIndex_).map(Number); + goog.array.sort(zs); + var i, ii, callbacks, j, jj; + for (i = 0, ii = zs.length; i < ii; ++i) { + callbacks = this.callbacksByZIndex_[zs[i].toString()]; + for (j = 0, jj = callbacks.length; j < jj; ++j) { + callbacks[j](this); + } + } +}; /** - * Listen to an event on a Listenable. If the function is omitted then the - * EventHandler's handleEvent method will be used. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} - * opt_fn Optional callback function to be used as the listener or an object - * with handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ + * Register a function to be called for rendering at a given zIndex. The + * function will be called asynchronously. The callback will receive a + * reference to {@link ol.render.canvas.Immediate} context for drawing. + * @param {number} zIndex Z index. + * @param {function(ol.render.webgl.Immediate)} callback Callback. + * @api */ -goog.events.EventHandler.prototype.listen = function( - src, type, opt_fn, opt_capture) { - return this.listen_(src, type, opt_fn, opt_capture); +ol.render.webgl.Immediate.prototype.drawAsync = function(zIndex, callback) { + var zIndexKey = zIndex.toString(); + var callbacks = this.callbacksByZIndex_[zIndexKey]; + if (callbacks !== undefined) { + callbacks.push(callback); + } else { + this.callbacksByZIndex_[zIndexKey] = [callback]; + } }; /** - * Listen to an event on a Listenable. If the function is omitted then the - * EventHandler's handleEvent method will be used. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| - * null|undefined} fn Optional callback function to be used as the - * listener or an object with handleEvent function. - * @param {boolean|undefined} capture Optional whether to use capture phase. - * @param {T} scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template T,EVENTOBJ + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenWithScope = function( - src, type, fn, capture, scope) { - // TODO(mknichel): Deprecate this function. - return this.listen_(src, type, fn, capture, scope); +ol.render.webgl.Immediate.prototype.drawCircleGeometry = + function(circleGeometry, data) { }; /** - * Listen to an event on a Listenable. If the function is omitted then the - * EventHandler's handleEvent method will be used. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @param {Object=} opt_scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ - * @private + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listen_ = function(src, type, opt_fn, - opt_capture, - opt_scope) { - if (!goog.isArray(type)) { - if (type) { - goog.events.EventHandler.typeArray_[0] = type.toString(); - } - type = goog.events.EventHandler.typeArray_; +ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) { + var geometry = style.getGeometryFunction()(feature); + if (!geometry || + !ol.extent.intersects(this.extent_, geometry.getExtent())) { + return; } - for (var i = 0; i < type.length; i++) { - var listenerObj = goog.events.listen( - src, type[i], opt_fn || this.handleEvent, - opt_capture || false, - opt_scope || this.handler_ || this); - - if (!listenerObj) { - // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT - // (goog.events.CaptureSimulationMode) in IE8-, it will return null - // value. - return this; - } - - var key = listenerObj.key; - this.keys_[key] = listenerObj; + var zIndex = style.getZIndex(); + if (zIndex === undefined) { + zIndex = 0; } - - return this; + this.drawAsync(zIndex, function(render) { + render.setFillStrokeStyle(style.getFill(), style.getStroke()); + render.setImageStyle(style.getImage()); + render.setTextStyle(style.getText()); + var type = geometry.getType(); + var renderGeometry = ol.render.webgl.Immediate.GEOMETRY_RENDERERS_[type]; + // Do not assert since all kinds of geometries are not handled yet. + // In spite, render what we support. + if (renderGeometry) { + renderGeometry.call(render, geometry, null); + } + }); }; /** - * Listen to an event on a Listenable. If the function is omitted, then the - * EventHandler's handleEvent method will be used. After the event has fired the - * event listener is removed from the target. If an array of event types is - * provided, each event type will be listened to once. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenOnce = function( - src, type, opt_fn, opt_capture) { - return this.listenOnce_(src, type, opt_fn, opt_capture); +ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry = + function(geometryCollectionGeometry, data) { + var geometries = geometryCollectionGeometry.getGeometriesArray(); + var renderers = ol.render.webgl.Immediate.GEOMETRY_RENDERERS_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometry = geometries[i]; + var geometryRenderer = renderers[geometry.getType()]; + // Do not assert since all kinds of geometries are not handled yet. + // In order to support hierarchies, delegate instead what we can to + // valid renderers. + if (geometryRenderer) { + geometryRenderer.call(this, geometry, data); + } + } }; /** - * Listen to an event on a Listenable. If the function is omitted, then the - * EventHandler's handleEvent method will be used. After the event has fired the - * event listener is removed from the target. If an array of event types is - * provided, each event type will be listened to once. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| - * null|undefined} fn Optional callback function to be used as the - * listener or an object with handleEvent function. - * @param {boolean|undefined} capture Optional whether to use capture phase. - * @param {T} scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template T,EVENTOBJ + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenOnceWithScope = function( - src, type, fn, capture, scope) { - // TODO(mknichel): Deprecate this function. - return this.listenOnce_(src, type, fn, capture, scope); +ol.render.webgl.Immediate.prototype.drawPointGeometry = + function(pointGeometry, data) { + var context = this.context_; + var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_); + var replay = /** @type {ol.render.webgl.ImageReplay} */ ( + replayGroup.getReplay(0, ol.render.ReplayType.IMAGE)); + replay.setImageStyle(this.imageStyle_); + replay.drawPointGeometry(pointGeometry, data); + replay.finish(context); + // default colors + var opacity = 1; + var skippedFeatures = {}; + var featureCallback; + var oneByOne = false; + replay.replay(this.context_, this.center_, this.resolution_, this.rotation_, + this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback, + oneByOne); + replay.getDeleteResourcesFunction(context)(); }; /** - * Listen to an event on a Listenable. If the function is omitted, then the - * EventHandler's handleEvent method will be used. After the event has fired - * the event listener is removed from the target. If an array of event types is - * provided, each event type will be listened to once. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type to listen for or array of event types. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @param {Object=} opt_scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template EVENTOBJ - * @private + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenOnce_ = function( - src, type, opt_fn, opt_capture, opt_scope) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - this.listenOnce_(src, type[i], opt_fn, opt_capture, opt_scope); - } - } else { - var listenerObj = goog.events.listenOnce( - src, type, opt_fn || this.handleEvent, opt_capture, - opt_scope || this.handler_ || this); - if (!listenerObj) { - // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT - // (goog.events.CaptureSimulationMode) in IE8-, it will return null - // value. - return this; - } - - var key = listenerObj.key; - this.keys_[key] = listenerObj; - } - - return this; +ol.render.webgl.Immediate.prototype.drawLineStringGeometry = + function(lineStringGeometry, data) { }; /** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.EventTarget}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.EventTarget} src The node to listen to - * events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener - * Callback method, or an object with a handleEvent function. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenWithWrapper = function( - src, wrapper, listener, opt_capt) { - // TODO(mknichel): Remove the opt_scope from this function and then - // templatize it. - return this.listenWithWrapper_(src, wrapper, listener, opt_capt); +ol.render.webgl.Immediate.prototype.drawMultiLineStringGeometry = + function(multiLineStringGeometry, data) { }; /** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.EventTarget}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.EventTarget} src The node to listen to - * events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null} - * listener Optional callback function to be used as the - * listener or an object with handleEvent function. - * @param {boolean|undefined} capture Optional whether to use capture phase. - * @param {T} scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @template T + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenWithWrapperAndScope = function( - src, wrapper, listener, capture, scope) { - // TODO(mknichel): Deprecate this function. - return this.listenWithWrapper_(src, wrapper, listener, capture, scope); +ol.render.webgl.Immediate.prototype.drawMultiPointGeometry = + function(multiPointGeometry, data) { + var context = this.context_; + var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_); + var replay = /** @type {ol.render.webgl.ImageReplay} */ ( + replayGroup.getReplay(0, ol.render.ReplayType.IMAGE)); + replay.setImageStyle(this.imageStyle_); + replay.drawMultiPointGeometry(multiPointGeometry, data); + replay.finish(context); + var opacity = 1; + var skippedFeatures = {}; + var featureCallback; + var oneByOne = false; + replay.replay(this.context_, this.center_, this.resolution_, this.rotation_, + this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback, + oneByOne); + replay.getDeleteResourcesFunction(context)(); }; /** - * Adds an event listener with a specific event wrapper on a DOM Node or an - * object that has implemented {@link goog.events.EventTarget}. A listener can - * only be added once to an object. - * - * @param {EventTarget|goog.events.EventTarget} src The node to listen to - * events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback - * method, or an object with a handleEvent function. - * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to - * false). - * @param {Object=} opt_scope Element in whose scope to call the listener. - * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for - * chaining of calls. - * @private + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.listenWithWrapper_ = function( - src, wrapper, listener, opt_capt, opt_scope) { - wrapper.listen(src, listener, opt_capt, opt_scope || this.handler_ || this, - this); - return this; +ol.render.webgl.Immediate.prototype.drawMultiPolygonGeometry = + function(multiPolygonGeometry, data) { }; /** - * @return {number} Number of listeners registered by this handler. + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.getListenerCount = function() { - var count = 0; - for (var key in this.keys_) { - if (Object.prototype.hasOwnProperty.call(this.keys_, key)) { - count++; - } - } - return count; +ol.render.webgl.Immediate.prototype.drawPolygonGeometry = + function(polygonGeometry, data) { }; /** - * Unlistens on an event. - * @param {goog.events.ListenableType} src Event source. - * @param {string|Array<string>| - * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} - * type Event type or array of event types to unlisten to. - * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn - * Optional callback function to be used as the listener or an object with - * handleEvent function. - * @param {boolean=} opt_capture Optional whether to use capture phase. - * @param {Object=} opt_scope Object in whose scope to call the listener. - * @return {!goog.events.EventHandler} This object, allowing for chaining of - * calls. - * @template EVENTOBJ + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn, - opt_capture, - opt_scope) { - if (goog.isArray(type)) { - for (var i = 0; i < type.length; i++) { - this.unlisten(src, type[i], opt_fn, opt_capture, opt_scope); - } - } else { - var listener = goog.events.getListener(src, type, - opt_fn || this.handleEvent, - opt_capture, opt_scope || this.handler_ || this); +ol.render.webgl.Immediate.prototype.drawText = + function(flatCoordinates, offset, end, stride, geometry, data) { +}; - if (listener) { - goog.events.unlistenByKey(listener); - delete this.keys_[listener.key]; - } - } - return this; +/** + * @inheritDoc + * @api + */ +ol.render.webgl.Immediate.prototype.setFillStrokeStyle = + function(fillStyle, strokeStyle) { }; /** - * Removes an event listener which was added with listenWithWrapper(). - * - * @param {EventTarget|goog.events.EventTarget} src The target to stop - * listening to events on. - * @param {goog.events.EventWrapper} wrapper Event wrapper to use. - * @param {function(?):?|{handleEvent:function(?):?}|null} listener The - * listener function to remove. - * @param {boolean=} opt_capt In DOM-compliant browsers, this determines - * whether the listener is fired during the capture or bubble phase of the - * event. - * @param {Object=} opt_scope Element in whose scope to call the listener. - * @return {!goog.events.EventHandler} This object, allowing for chaining of - * calls. + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper, - listener, opt_capt, opt_scope) { - wrapper.unlisten(src, listener, opt_capt, - opt_scope || this.handler_ || this, this); - return this; +ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) { + this.imageStyle_ = imageStyle; }; /** - * Unlistens to all events. + * @inheritDoc + * @api */ -goog.events.EventHandler.prototype.removeAll = function() { - goog.object.forEach(this.keys_, function(listenerObj, key) { - if (this.keys_.hasOwnProperty(key)) { - goog.events.unlistenByKey(listenerObj); - } - }, this); - - this.keys_ = {}; +ol.render.webgl.Immediate.prototype.setTextStyle = function(textStyle) { }; /** - * Disposes of this EventHandler and removes all listeners that it registered. - * @override - * @protected + * @const + * @private + * @type {Object.<ol.geom.GeometryType, + * function(this: ol.render.webgl.Immediate, + * (ol.geom.Geometry|ol.render.Feature), Object)>} */ -goog.events.EventHandler.prototype.disposeInternal = function() { - goog.events.EventHandler.superClass_.disposeInternal.call(this); - this.removeAll(); +ol.render.webgl.Immediate.GEOMETRY_RENDERERS_ = { + 'Point': ol.render.webgl.Immediate.prototype.drawPointGeometry, + 'MultiPoint': ol.render.webgl.Immediate.prototype.drawMultiPointGeometry, + 'GeometryCollection': + ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry }; +// This file is automatically generated, do not edit +goog.provide('ol.renderer.webgl.map.shader.Default'); +goog.provide('ol.renderer.webgl.map.shader.Default.Locations'); +goog.provide('ol.renderer.webgl.map.shader.DefaultFragment'); +goog.provide('ol.renderer.webgl.map.shader.DefaultVertex'); + +goog.require('ol.webgl.shader'); + + /** - * Default event handler - * @param {goog.events.Event} e Event object. + * @constructor + * @extends {ol.webgl.shader.Fragment} + * @struct */ -goog.events.EventHandler.prototype.handleEvent = function(e) { - throw Error('EventHandler.handleEvent not implemented'); +ol.renderer.webgl.map.shader.DefaultFragment = function() { + goog.base(this, ol.renderer.webgl.map.shader.DefaultFragment.SOURCE); }; +goog.inherits(ol.renderer.webgl.map.shader.DefaultFragment, ol.webgl.shader.Fragment); +goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultFragment); -// Copyright 2012 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Bidi utility functions. - * + * @const + * @type {string} */ - -goog.provide('goog.style.bidi'); - -goog.require('goog.dom'); -goog.require('goog.style'); -goog.require('goog.userAgent'); +ol.renderer.webgl.map.shader.DefaultFragment.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'; /** - * Returns the normalized scrollLeft position for a scrolled element. - * @param {Element} element The scrolled element. - * @return {number} The number of pixels the element is scrolled. 0 indicates - * that the element is not scrolled at all (which, in general, is the - * left-most position in ltr and the right-most position in rtl). + * @const + * @type {string} */ -goog.style.bidi.getScrollLeft = function(element) { - var isRtl = goog.style.isRightToLeft(element); - if (isRtl && goog.userAgent.GECKO) { - // ScrollLeft starts at 0 and then goes negative as the element is scrolled - // towards the left. - return -element.scrollLeft; - } else if (isRtl && - !(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8'))) { - // ScrollLeft starts at the maximum positive value and decreases towards - // 0 as the element is scrolled towards the left. However, for overflow - // visible, there is no scrollLeft and the value always stays correctly at 0 - var overflowX = goog.style.getComputedOverflowX(element); - if (overflowX == 'visible') { - return element.scrollLeft; - } else { - return element.scrollWidth - element.clientWidth - element.scrollLeft; - } - } - // ScrollLeft behavior is identical in rtl and ltr, it starts at 0 and - // increases as the element is scrolled away from the start. - return element.scrollLeft; -}; +ol.renderer.webgl.map.shader.DefaultFragment.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;}'; /** - * Returns the "offsetStart" of an element, analagous to offsetLeft but - * normalized for right-to-left environments and various browser - * inconsistencies. This value returned can always be passed to setScrollOffset - * to scroll to an element's left edge in a left-to-right offsetParent or - * right edge in a right-to-left offsetParent. - * - * For example, here offsetStart is 10px in an LTR environment and 5px in RTL: - * - * <pre> - * | xxxxxxxxxx | - * ^^^^^^^^^^ ^^^^ ^^^^^ - * 10px elem 5px - * </pre> - * - * If an element is positioned before the start of its offsetParent, the - * startOffset may be negative. This can be used with setScrollOffset to - * reliably scroll to an element: - * - * <pre> - * var scrollOffset = goog.style.bidi.getOffsetStart(element); - * goog.style.bidi.setScrollOffset(element.offsetParent, scrollOffset); - * </pre> - * - * @see setScrollOffset - * - * @param {Element} element The element for which we need to determine the - * offsetStart position. - * @return {number} The offsetStart for that element. + * @const + * @type {string} */ -goog.style.bidi.getOffsetStart = function(element) { - element = /** @type {!HTMLElement} */ (element); - var offsetLeftForReal = element.offsetLeft; - - // The element might not have an offsetParent. - // For example, the node might not be attached to the DOM tree, - // and position:fixed children do not have an offset parent. - // Just try to do the best we can with what we have. - var bestParent = element.offsetParent; - - if (!bestParent && goog.style.getComputedPosition(element) == 'fixed') { - bestParent = goog.dom.getOwnerDocument(element).documentElement; - } - - // Just give up in this case. - if (!bestParent) { - return offsetLeftForReal; - } - - if (goog.userAgent.GECKO) { - // When calculating an element's offsetLeft, Firefox erroneously subtracts - // the border width from the actual distance. So we need to add it back. - var borderWidths = goog.style.getBorderBox(bestParent); - offsetLeftForReal += borderWidths.left; - } else if (goog.userAgent.isDocumentModeOrHigher(8) && - !goog.userAgent.isDocumentModeOrHigher(9)) { - // When calculating an element's offsetLeft, IE8/9-Standards Mode - // erroneously adds the border width to the actual distance. So we need to - // subtract it. - var borderWidths = goog.style.getBorderBox(bestParent); - offsetLeftForReal -= borderWidths.left; - } - - if (goog.style.isRightToLeft(bestParent)) { - // Right edge of the element relative to the left edge of its parent. - var elementRightOffset = offsetLeftForReal + element.offsetWidth; - - // Distance from the parent's right edge to the element's right edge. - return bestParent.clientWidth - elementRightOffset; - } +ol.renderer.webgl.map.shader.DefaultFragment.SOURCE = goog.DEBUG ? + ol.renderer.webgl.map.shader.DefaultFragment.DEBUG_SOURCE : + ol.renderer.webgl.map.shader.DefaultFragment.OPTIMIZED_SOURCE; - return offsetLeftForReal; -}; /** - * Sets the element's scrollLeft attribute so it is correctly scrolled by - * offsetStart pixels. This takes into account whether the element is RTL and - * the nuances of different browsers. To scroll to the "beginning" of an - * element use getOffsetStart to obtain the element's offsetStart value and then - * pass the value to setScrollOffset. - * @see getOffsetStart - * @param {Element} element The element to set scrollLeft on. - * @param {number} offsetStart The number of pixels to scroll the element. - * If this value is < 0, 0 is used. + * @constructor + * @extends {ol.webgl.shader.Vertex} + * @struct */ -goog.style.bidi.setScrollOffset = function(element, offsetStart) { - offsetStart = Math.max(offsetStart, 0); - // In LTR and in "mirrored" browser RTL (such as IE), we set scrollLeft to - // the number of pixels to scroll. - // Otherwise, in RTL, we need to account for different browser behavior. - if (!goog.style.isRightToLeft(element)) { - element.scrollLeft = offsetStart; - } else if (goog.userAgent.GECKO) { - // Negative scroll-left positions in RTL. - element.scrollLeft = -offsetStart; - } else if (!(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8'))) { - // Take the current scrollLeft value and move to the right by the - // offsetStart to get to the left edge of the element, and then by - // the clientWidth of the element to get to the right edge. - element.scrollLeft = - element.scrollWidth - offsetStart - element.clientWidth; - } else { - element.scrollLeft = offsetStart; - } +ol.renderer.webgl.map.shader.DefaultVertex = function() { + goog.base(this, ol.renderer.webgl.map.shader.DefaultVertex.SOURCE); }; +goog.inherits(ol.renderer.webgl.map.shader.DefaultVertex, ol.webgl.shader.Vertex); +goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultVertex); /** - * Sets the element's left style attribute in LTR or right style attribute in - * RTL. Also clears the left attribute in RTL and the right attribute in LTR. - * @param {Element} elem The element to position. - * @param {number} left The left position in LTR; will be set as right in RTL. - * @param {?number} top The top position. If null only the left/right is set. - * @param {boolean} isRtl Whether we are in RTL mode. + * @const + * @type {string} */ -goog.style.bidi.setPosition = function(elem, left, top, isRtl) { - if (!goog.isNull(top)) { - elem.style.top = top + 'px'; - } - if (isRtl) { - elem.style.right = left + 'px'; - elem.style.left = ''; - } else { - elem.style.left = left + 'px'; - elem.style.right = ''; - } -}; +ol.renderer.webgl.map.shader.DefaultVertex.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'; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Drag Utilities. - * - * Provides extensible functionality for drag & drop behaviour. - * - * @see ../demos/drag.html - * @see ../demos/dragger.html + * @const + * @type {string} */ +ol.renderer.webgl.map.shader.DefaultVertex.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;}'; -goog.provide('goog.fx.DragEvent'); -goog.provide('goog.fx.Dragger'); -goog.provide('goog.fx.Dragger.EventType'); - -goog.require('goog.dom'); -goog.require('goog.dom.TagName'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.math.Coordinate'); -goog.require('goog.math.Rect'); -goog.require('goog.style'); -goog.require('goog.style.bidi'); -goog.require('goog.userAgent'); +/** + * @const + * @type {string} + */ +ol.renderer.webgl.map.shader.DefaultVertex.SOURCE = goog.DEBUG ? + ol.renderer.webgl.map.shader.DefaultVertex.DEBUG_SOURCE : + ol.renderer.webgl.map.shader.DefaultVertex.OPTIMIZED_SOURCE; /** - * A class that allows mouse or touch-based dragging (moving) of an element - * - * @param {Element} target The element that will be dragged. - * @param {Element=} opt_handle An optional handle to control the drag, if null - * the target is used. - * @param {goog.math.Rect=} opt_limits Object containing left, top, width, - * and height. - * - * @extends {goog.events.EventTarget} * @constructor + * @param {WebGLRenderingContext} gl GL. + * @param {WebGLProgram} program Program. * @struct */ -goog.fx.Dragger = function(target, opt_handle, opt_limits) { - goog.fx.Dragger.base(this, 'constructor'); - - /** - * Reference to drag target element. - * @type {?Element} - */ - this.target = target; +ol.renderer.webgl.map.shader.Default.Locations = function(gl, program) { /** - * Reference to the handler that initiates the drag. - * @type {?Element} + * @type {WebGLUniformLocation} */ - this.handle = opt_handle || target; + this.u_opacity = gl.getUniformLocation( + program, goog.DEBUG ? 'u_opacity' : 'f'); /** - * Object representing the limits of the drag region. - * @type {goog.math.Rect} + * @type {WebGLUniformLocation} */ - this.limits = opt_limits || new goog.math.Rect(NaN, NaN, NaN, NaN); + this.u_projectionMatrix = gl.getUniformLocation( + program, goog.DEBUG ? 'u_projectionMatrix' : 'e'); /** - * Reference to a document object to use for the events. - * @private {Document} + * @type {WebGLUniformLocation} */ - this.document_ = goog.dom.getOwnerDocument(target); - - /** @private {!goog.events.EventHandler} */ - this.eventHandler_ = new goog.events.EventHandler(this); - this.registerDisposable(this.eventHandler_); + this.u_texCoordMatrix = gl.getUniformLocation( + program, goog.DEBUG ? 'u_texCoordMatrix' : 'd'); /** - * Whether the element is rendered right-to-left. We initialize this lazily. - * @private {boolean|undefined}} + * @type {WebGLUniformLocation} */ - this.rightToLeft_; + this.u_texture = gl.getUniformLocation( + program, goog.DEBUG ? 'u_texture' : 'g'); /** - * Current x position of mouse or touch relative to viewport. * @type {number} */ - this.clientX = 0; + this.a_position = gl.getAttribLocation( + program, goog.DEBUG ? 'a_position' : 'b'); /** - * Current y position of mouse or touch relative to viewport. * @type {number} */ - this.clientY = 0; + this.a_texCoord = gl.getAttribLocation( + program, goog.DEBUG ? 'a_texCoord' : 'c'); +}; - /** - * Current x position of mouse or touch relative to screen. Deprecated because - * it doesn't take into affect zoom level or pixel density. - * @type {number} - * @deprecated Consider switching to clientX instead. - */ - this.screenX = 0; +goog.provide('ol.renderer.webgl.Layer'); - /** - * Current y position of mouse or touch relative to screen. Deprecated because - * it doesn't take into affect zoom level or pixel density. - * @type {number} - * @deprecated Consider switching to clientY instead. - */ - this.screenY = 0; +goog.require('goog.vec.Mat4'); +goog.require('goog.webgl'); +goog.require('ol.layer.Layer'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.webgl.Immediate'); +goog.require('ol.renderer.Layer'); +goog.require('ol.renderer.webgl.map.shader.Default'); +goog.require('ol.renderer.webgl.map.shader.Default.Locations'); +goog.require('ol.renderer.webgl.map.shader.DefaultFragment'); +goog.require('ol.renderer.webgl.map.shader.DefaultVertex'); +goog.require('ol.webgl.Buffer'); +goog.require('ol.webgl.Context'); - /** - * The x position where the first mousedown or touchstart occurred. - * @type {number} - */ - this.startX = 0; - /** - * The y position where the first mousedown or touchstart occurred. - * @type {number} - */ - this.startY = 0; - /** - * Current x position of drag relative to target's parent. - * @type {number} - */ - this.deltaX = 0; +/** + * @constructor + * @extends {ol.renderer.Layer} + * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. + * @param {ol.layer.Layer} layer Layer. + */ +ol.renderer.webgl.Layer = function(mapRenderer, layer) { - /** - * Current y position of drag relative to target's parent. - * @type {number} - */ - this.deltaY = 0; + goog.base(this, layer); /** - * The current page scroll value. - * @type {?goog.math.Coordinate} + * @protected + * @type {ol.renderer.webgl.Map} */ - this.pageScroll; + this.mapRenderer = mapRenderer; /** - * Whether dragging is currently enabled. - * @private {boolean} + * @private + * @type {ol.webgl.Buffer} */ - this.enabled_ = true; + this.arrayBuffer_ = new ol.webgl.Buffer([ + -1, -1, 0, 0, + 1, -1, 1, 0, + -1, 1, 0, 1, + 1, 1, 1, 1 + ]); /** - * Whether object is currently being dragged. - * @private {boolean} + * @protected + * @type {WebGLTexture} */ - this.dragging_ = false; + this.texture = null; /** - * Whether mousedown should be default prevented. - * @private {boolean} - **/ - this.preventMouseDown_ = true; + * @protected + * @type {WebGLFramebuffer} + */ + this.framebuffer = null; /** - * The amount of distance, in pixels, after which a mousedown or touchstart is - * considered a drag. - * @private {number} + * @protected + * @type {number|undefined} */ - this.hysteresisDistanceSquared_ = 0; + this.framebufferDimension = undefined; /** - * The SCROLL event target used to make drag element follow scrolling. - * @private {?EventTarget} + * @protected + * @type {!goog.vec.Mat4.Number} */ - this.scrollTarget_; + this.texCoordMatrix = goog.vec.Mat4.createNumber(); /** - * Whether IE drag events cancelling is on. - * @private {boolean} + * @protected + * @type {!goog.vec.Mat4.Number} */ - this.ieDragStartCancellingOn_ = false; + this.projectionMatrix = goog.vec.Mat4.createNumberIdentity(); /** - * Whether the dragger implements the changes described in http://b/6324964, - * making it truly RTL. This is a temporary flag to allow clients to - * transition to the new behavior at their convenience. At some point it will - * be the default. - * @private {boolean} + * @private + * @type {ol.renderer.webgl.map.shader.Default.Locations} */ - this.useRightPositioningForRtl_ = false; + this.defaultLocations_ = null; - // Add listener. Do not use the event handler here since the event handler is - // used for listeners added and removed during the drag operation. - goog.events.listen(this.handle, - [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN], - this.startDrag, false, this); }; -goog.inherits(goog.fx.Dragger, goog.events.EventTarget); -// Dragger is meant to be extended, but defines most properties on its -// prototype, thus making it unsuitable for sealing. -goog.tagUnsealableClass(goog.fx.Dragger); +goog.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer); /** - * Whether setCapture is supported by the browser. - * @type {boolean} - * @private + * @param {olx.FrameState} frameState Frame state. + * @param {number} framebufferDimension Framebuffer dimension. + * @protected */ -goog.fx.Dragger.HAS_SET_CAPTURE_ = - // IE and Gecko after 1.9.3 has setCapture - // WebKit does not yet: https://bugs.webkit.org/show_bug.cgi?id=27330 - goog.userAgent.IE || - goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.3'); +ol.renderer.webgl.Layer.prototype.bindFramebuffer = + function(frameState, framebufferDimension) { + var gl = this.mapRenderer.getGL(); -/** - * Creates copy of node being dragged. This is a utility function to be used - * wherever it is inappropriate for the original source to follow the mouse - * cursor itself. - * - * @param {Element} sourceEl Element to copy. - * @return {!Element} The clone of {@code sourceEl}. - */ -goog.fx.Dragger.cloneNode = function(sourceEl) { - var clonedEl = /** @type {Element} */ (sourceEl.cloneNode(true)), - origTexts = sourceEl.getElementsByTagName(goog.dom.TagName.TEXTAREA), - dragTexts = clonedEl.getElementsByTagName(goog.dom.TagName.TEXTAREA); - // Cloning does not copy the current value of textarea elements, so correct - // this manually. - for (var i = 0; i < origTexts.length; i++) { - dragTexts[i].value = origTexts[i].value; - } - switch (sourceEl.tagName) { - case goog.dom.TagName.TR: - return goog.dom.createDom(goog.dom.TagName.TABLE, null, - goog.dom.createDom(goog.dom.TagName.TBODY, - null, clonedEl)); - case goog.dom.TagName.TD: - case goog.dom.TagName.TH: - return goog.dom.createDom( - goog.dom.TagName.TABLE, null, goog.dom.createDom( - goog.dom.TagName.TBODY, null, goog.dom.createDom( - goog.dom.TagName.TR, null, clonedEl))); - case goog.dom.TagName.TEXTAREA: - clonedEl.value = sourceEl.value; - default: - return clonedEl; + if (this.framebufferDimension === undefined || + this.framebufferDimension != framebufferDimension) { + + frameState.postRenderFunctions.push( + goog.partial( + /** + * @param {WebGLRenderingContext} gl GL. + * @param {WebGLFramebuffer} framebuffer Framebuffer. + * @param {WebGLTexture} texture Texture. + */ + function(gl, framebuffer, texture) { + if (!gl.isContextLost()) { + gl.deleteFramebuffer(framebuffer); + gl.deleteTexture(texture); + } + }, gl, this.framebuffer, this.texture)); + + var texture = ol.webgl.Context.createEmptyTexture( + gl, framebufferDimension, framebufferDimension); + + var framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer); + gl.framebufferTexture2D(goog.webgl.FRAMEBUFFER, + goog.webgl.COLOR_ATTACHMENT0, goog.webgl.TEXTURE_2D, texture, 0); + + this.texture = texture; + this.framebuffer = framebuffer; + this.framebufferDimension = framebufferDimension; + + } else { + gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, this.framebuffer); } + }; /** - * Constants for event names. - * @enum {string} + * @param {olx.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. + * @param {ol.webgl.Context} context Context. */ -goog.fx.Dragger.EventType = { - // The drag action was canceled before the START event. Possible reasons: - // disabled dragger, dragging with the right mouse button or releasing the - // button before reaching the hysteresis distance. - EARLY_CANCEL: 'earlycancel', - START: 'start', - BEFOREDRAG: 'beforedrag', - DRAG: 'drag', - END: 'end' -}; +ol.renderer.webgl.Layer.prototype.composeFrame = + function(frameState, layerState, context) { + + this.dispatchComposeEvent_( + ol.render.EventType.PRECOMPOSE, context, frameState); + context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.arrayBuffer_); -/** - * Turns on/off true RTL behavior. This should be called immediately after - * construction. This is a temporary flag to allow clients to transition - * to the new component at their convenience. At some point true will be the - * default. - * @param {boolean} useRightPositioningForRtl True if "right" should be used for - * positioning, false if "left" should be used for positioning. - */ -goog.fx.Dragger.prototype.enableRightPositioningForRtl = - function(useRightPositioningForRtl) { - this.useRightPositioningForRtl_ = useRightPositioningForRtl; -}; + var gl = context.getGL(); + + var fragmentShader = + ol.renderer.webgl.map.shader.DefaultFragment.getInstance(); + var vertexShader = ol.renderer.webgl.map.shader.DefaultVertex.getInstance(); + var program = context.getProgram(fragmentShader, vertexShader); + + var locations; + if (!this.defaultLocations_) { + locations = + new ol.renderer.webgl.map.shader.Default.Locations(gl, program); + this.defaultLocations_ = locations; + } else { + locations = this.defaultLocations_; + } + + if (context.useProgram(program)) { + gl.enableVertexAttribArray(locations.a_position); + gl.vertexAttribPointer( + locations.a_position, 2, goog.webgl.FLOAT, false, 16, 0); + gl.enableVertexAttribArray(locations.a_texCoord); + gl.vertexAttribPointer( + locations.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); + gl.uniform1i(locations.u_texture, 0); + } + + gl.uniformMatrix4fv( + locations.u_texCoordMatrix, false, this.getTexCoordMatrix()); + gl.uniformMatrix4fv(locations.u_projectionMatrix, false, + this.getProjectionMatrix()); + gl.uniform1f(locations.u_opacity, layerState.opacity); + gl.bindTexture(goog.webgl.TEXTURE_2D, this.getTexture()); + gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); + + this.dispatchComposeEvent_( + ol.render.EventType.POSTCOMPOSE, context, frameState); -/** - * Returns the event handler, intended for subclass use. - * @return {!goog.events.EventHandler<T>} The event handler. - * @this {T} - * @template T - */ -goog.fx.Dragger.prototype.getHandler = function() { - // TODO(user): templated "this" values currently result in "this" being - // "unknown" in the body of the function. - var self = /** @type {goog.fx.Dragger} */ (this); - return self.eventHandler_; }; /** - * Sets (or reset) the Drag limits after a Dragger is created. - * @param {goog.math.Rect?} limits Object containing left, top, width, - * height for new Dragger limits. If target is right-to-left and - * enableRightPositioningForRtl(true) is called, then rect is interpreted as - * right, top, width, and height. + * @param {ol.render.EventType} type Event type. + * @param {ol.webgl.Context} context WebGL context. + * @param {olx.FrameState} frameState Frame state. + * @private */ -goog.fx.Dragger.prototype.setLimits = function(limits) { - this.limits = limits || new goog.math.Rect(NaN, NaN, NaN, NaN); +ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ = + function(type, context, frameState) { + var layer = this.getLayer(); + if (layer.hasListener(type)) { + var viewState = frameState.viewState; + var resolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var extent = frameState.extent; + var center = viewState.center; + var rotation = viewState.rotation; + var size = frameState.size; + + var render = new ol.render.webgl.Immediate( + context, center, resolution, rotation, size, extent, pixelRatio); + var composeEvent = new ol.render.Event( + type, layer, render, frameState, null, context); + layer.dispatchEvent(composeEvent); + } }; /** - * Sets the distance the user has to drag the element before a drag operation is - * started. - * @param {number} distance The number of pixels after which a mousedown and - * move is considered a drag. + * @return {!goog.vec.Mat4.Number} Matrix. */ -goog.fx.Dragger.prototype.setHysteresis = function(distance) { - this.hysteresisDistanceSquared_ = Math.pow(distance, 2); +ol.renderer.webgl.Layer.prototype.getTexCoordMatrix = function() { + return this.texCoordMatrix; }; /** - * Gets the distance the user has to drag the element before a drag operation is - * started. - * @return {number} distance The number of pixels after which a mousedown and - * move is considered a drag. + * @return {WebGLTexture} Texture. */ -goog.fx.Dragger.prototype.getHysteresis = function() { - return Math.sqrt(this.hysteresisDistanceSquared_); +ol.renderer.webgl.Layer.prototype.getTexture = function() { + return this.texture; }; /** - * Sets the SCROLL event target to make drag element follow scrolling. - * - * @param {EventTarget} scrollTarget The event target that dispatches SCROLL - * events. + * @return {!goog.vec.Mat4.Number} Matrix. */ -goog.fx.Dragger.prototype.setScrollTarget = function(scrollTarget) { - this.scrollTarget_ = scrollTarget; +ol.renderer.webgl.Layer.prototype.getProjectionMatrix = function() { + return this.projectionMatrix; }; /** - * Enables cancelling of built-in IE drag events. - * @param {boolean} cancelIeDragStart Whether to enable cancelling of IE - * dragstart event. + * Handle webglcontextlost. */ -goog.fx.Dragger.prototype.setCancelIeDragStart = function(cancelIeDragStart) { - this.ieDragStartCancellingOn_ = cancelIeDragStart; +ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() { + this.texture = null; + this.framebuffer = null; + this.framebufferDimension = undefined; }; /** - * @return {boolean} Whether the dragger is enabled. + * @param {olx.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. + * @param {ol.webgl.Context} context Context. + * @return {boolean} whether composeFrame should be called. */ -goog.fx.Dragger.prototype.getEnabled = function() { - return this.enabled_; -}; +ol.renderer.webgl.Layer.prototype.prepareFrame = goog.abstractMethod; + +goog.provide('ol.renderer.webgl.ImageLayer'); + +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('goog.vec.Mat4'); +goog.require('goog.webgl'); +goog.require('ol.Coordinate'); +goog.require('ol.Extent'); +goog.require('ol.ImageBase'); +goog.require('ol.ViewHint'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.layer.Image'); +goog.require('ol.proj'); +goog.require('ol.renderer.webgl.Layer'); +goog.require('ol.source.ImageVector'); +goog.require('ol.vec.Mat4'); +goog.require('ol.webgl.Context'); + /** - * Set whether dragger is enabled - * @param {boolean} enabled Whether dragger is enabled. + * @constructor + * @extends {ol.renderer.webgl.Layer} + * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. + * @param {ol.layer.Image} imageLayer Tile layer. */ -goog.fx.Dragger.prototype.setEnabled = function(enabled) { - this.enabled_ = enabled; +ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) { + + goog.base(this, mapRenderer, imageLayer); + + /** + * The last rendered image. + * @private + * @type {?ol.ImageBase} + */ + this.image_ = null; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.hitCanvasContext_ = null; + + /** + * @private + * @type {?goog.vec.Mat4.Number} + */ + this.hitTransformationMatrix_ = null; + }; +goog.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer); /** - * Set whether mousedown should be default prevented. - * @param {boolean} preventMouseDown Whether mousedown should be default - * prevented. + * @param {ol.ImageBase} image Image. + * @private + * @return {WebGLTexture} Texture. */ -goog.fx.Dragger.prototype.setPreventMouseDown = function(preventMouseDown) { - this.preventMouseDown_ = preventMouseDown; -}; +ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) { + // We meet the conditions to work with non-power of two textures. + // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support + // http://learningwebgl.com/blog/?p=2101 -/** @override */ -goog.fx.Dragger.prototype.disposeInternal = function() { - goog.fx.Dragger.superClass_.disposeInternal.call(this); - goog.events.unlisten(this.handle, - [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN], - this.startDrag, false, this); - this.cleanUpAfterDragging_(); + var imageElement = image.getImage(); + var gl = this.mapRenderer.getGL(); - this.target = null; - this.handle = null; + return ol.webgl.Context.createTexture( + gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); }; /** - * Whether the DOM element being manipulated is rendered right-to-left. - * @return {boolean} True if the DOM element is rendered right-to-left, false - * otherwise. - * @private + * @inheritDoc */ -goog.fx.Dragger.prototype.isRightToLeft_ = function() { - if (!goog.isDef(this.rightToLeft_)) { - this.rightToLeft_ = goog.style.isRightToLeft(this.target); - } - return this.rightToLeft_; +ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + var layer = this.getLayer(); + var source = layer.getSource(); + var resolution = frameState.viewState.resolution; + var rotation = frameState.viewState.rotation; + var skippedFeatureUids = frameState.skippedFeatureUids; + return source.forEachFeatureAtCoordinate( + coordinate, resolution, rotation, skippedFeatureUids, + + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + return callback.call(thisArg, feature, layer); + }); }; /** - * Event handler that is used to start the drag - * @param {goog.events.BrowserEvent} e Event object. + * @inheritDoc */ -goog.fx.Dragger.prototype.startDrag = function(e) { - var isMouseDown = e.type == goog.events.EventType.MOUSEDOWN; +ol.renderer.webgl.ImageLayer.prototype.prepareFrame = + function(frameState, layerState, context) { - // Dragger.startDrag() can be called by AbstractDragDrop with a mousemove - // event and IE does not report pressed mouse buttons on mousemove. Also, - // it does not make sense to check for the button if the user is already - // dragging. + var gl = this.mapRenderer.getGL(); - if (this.enabled_ && !this.dragging_ && - (!isMouseDown || e.isMouseActionButton())) { - if (this.hysteresisDistanceSquared_ == 0) { - if (this.fireDragStart_(e)) { - this.dragging_ = true; - if (this.preventMouseDown_) { - e.preventDefault(); + var pixelRatio = frameState.pixelRatio; + var viewState = frameState.viewState; + var viewCenter = viewState.center; + var viewResolution = viewState.resolution; + var viewRotation = viewState.rotation; + + var image = this.image_; + var texture = this.texture; + var imageLayer = this.getLayer(); + goog.asserts.assertInstanceof(imageLayer, ol.layer.Image, + 'layer is an instance of ol.layer.Image'); + var imageSource = imageLayer.getSource(); + + var hints = frameState.viewHints; + + var renderedExtent = frameState.extent; + if (layerState.extent !== undefined) { + renderedExtent = ol.extent.getIntersection( + renderedExtent, layerState.extent); + } + if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] && + !ol.extent.isEmpty(renderedExtent)) { + var projection = viewState.projection; + if (!ol.ENABLE_RASTER_REPROJECTION) { + var sourceProjection = imageSource.getProjection(); + if (sourceProjection) { + goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection), + 'projection and sourceProjection are equivalent'); + projection = sourceProjection; + } + } + var image_ = imageSource.getImage(renderedExtent, viewResolution, + pixelRatio, projection); + if (image_) { + var loaded = this.loadImage(image_); + if (loaded) { + image = image_; + texture = this.createTexture_(image_); + if (this.texture) { + frameState.postRenderFunctions.push( + goog.partial( + /** + * @param {WebGLRenderingContext} gl GL. + * @param {WebGLTexture} texture Texture. + */ + function(gl, texture) { + if (!gl.isContextLost()) { + gl.deleteTexture(texture); + } + }, gl, this.texture)); } - } else { - // If the start drag is cancelled, don't setup for a drag. - return; } - } else if (this.preventMouseDown_) { - // Need to preventDefault for hysteresis to prevent page getting selected. - e.preventDefault(); } - this.setupDragHandlers(); - - this.clientX = this.startX = e.clientX; - this.clientY = this.startY = e.clientY; - this.screenX = e.screenX; - this.screenY = e.screenY; - this.computeInitialPosition(); - this.pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll(); - } else { - this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL); } -}; + if (image) { + goog.asserts.assert(texture, 'texture is truthy'); -/** - * Sets up event handlers when dragging starts. - * @protected - */ -goog.fx.Dragger.prototype.setupDragHandlers = function() { - var doc = this.document_; - var docEl = doc.documentElement; - // Use bubbling when we have setCapture since we got reports that IE has - // problems with the capturing events in combination with setCapture. - var useCapture = !goog.fx.Dragger.HAS_SET_CAPTURE_; + var canvas = this.mapRenderer.getContext().getCanvas(); - this.eventHandler_.listen(doc, - [goog.events.EventType.TOUCHMOVE, goog.events.EventType.MOUSEMOVE], - this.handleMove_, useCapture); - this.eventHandler_.listen(doc, - [goog.events.EventType.TOUCHEND, goog.events.EventType.MOUSEUP], - this.endDrag, useCapture); + this.updateProjectionMatrix_(canvas.width, canvas.height, + pixelRatio, viewCenter, viewResolution, viewRotation, + image.getExtent()); + this.hitTransformationMatrix_ = null; - if (goog.fx.Dragger.HAS_SET_CAPTURE_) { - docEl.setCapture(false); - this.eventHandler_.listen(docEl, - goog.events.EventType.LOSECAPTURE, - this.endDrag); - } else { - // Make sure we stop the dragging if the window loses focus. - // Don't use capture in this listener because we only want to end the drag - // if the actual window loses focus. Since blur events do not bubble we use - // a bubbling listener on the window. - this.eventHandler_.listen(goog.dom.getWindow(doc), - goog.events.EventType.BLUR, - this.endDrag); - } + // Translate and scale to flip the Y coord. + var texCoordMatrix = this.texCoordMatrix; + goog.vec.Mat4.makeIdentity(texCoordMatrix); + goog.vec.Mat4.scale(texCoordMatrix, 1, -1, 1); + goog.vec.Mat4.translate(texCoordMatrix, 0, -1, 0); - if (goog.userAgent.IE && this.ieDragStartCancellingOn_) { - // Cancel IE's 'ondragstart' event. - this.eventHandler_.listen(doc, goog.events.EventType.DRAGSTART, - goog.events.Event.preventDefault); - } + this.image_ = image; + this.texture = texture; - if (this.scrollTarget_) { - this.eventHandler_.listen(this.scrollTarget_, goog.events.EventType.SCROLL, - this.onScroll_, useCapture); + this.updateAttributions(frameState.attributions, image.getAttributions()); + this.updateLogos(frameState, imageSource); } + + return true; }; /** - * Fires a goog.fx.Dragger.EventType.START event. - * @param {goog.events.BrowserEvent} e Browser event that triggered the drag. - * @return {boolean} False iff preventDefault was called on the DragEvent. + * @param {number} canvasWidth Canvas width. + * @param {number} canvasHeight Canvas height. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.Coordinate} viewCenter View center. + * @param {number} viewResolution View resolution. + * @param {number} viewRotation View rotation. + * @param {ol.Extent} imageExtent Image extent. * @private */ -goog.fx.Dragger.prototype.fireDragStart_ = function(e) { - return this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.START, this, e.clientX, e.clientY, e)); +ol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = + function(canvasWidth, canvasHeight, pixelRatio, + viewCenter, viewResolution, viewRotation, imageExtent) { + + var canvasExtentWidth = canvasWidth * viewResolution; + var canvasExtentHeight = canvasHeight * viewResolution; + + var projectionMatrix = this.projectionMatrix; + goog.vec.Mat4.makeIdentity(projectionMatrix); + goog.vec.Mat4.scale(projectionMatrix, + pixelRatio * 2 / canvasExtentWidth, + pixelRatio * 2 / canvasExtentHeight, 1); + goog.vec.Mat4.rotateZ(projectionMatrix, -viewRotation); + goog.vec.Mat4.translate(projectionMatrix, + imageExtent[0] - viewCenter[0], + imageExtent[1] - viewCenter[1], + 0); + goog.vec.Mat4.scale(projectionMatrix, + (imageExtent[2] - imageExtent[0]) / 2, + (imageExtent[3] - imageExtent[1]) / 2, + 1); + goog.vec.Mat4.translate(projectionMatrix, 1, 1, 0); + }; /** - * Unregisters the event handlers that are only active during dragging, and - * releases mouse capture. - * @private + * @inheritDoc */ -goog.fx.Dragger.prototype.cleanUpAfterDragging_ = function() { - this.eventHandler_.removeAll(); - if (goog.fx.Dragger.HAS_SET_CAPTURE_) { - this.document_.releaseCapture(); - } +ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = + function(coordinate, frameState) { + var hasFeature = this.forEachFeatureAtCoordinate( + coordinate, frameState, goog.functions.TRUE, this); + return hasFeature !== undefined; }; /** - * Event handler that is used to end the drag. - * @param {goog.events.BrowserEvent} e Event object. - * @param {boolean=} opt_dragCanceled Whether the drag has been canceled. + * @inheritDoc */ -goog.fx.Dragger.prototype.endDrag = function(e, opt_dragCanceled) { - this.cleanUpAfterDragging_(); - - if (this.dragging_) { - this.dragging_ = false; - - var x = this.limitX(this.deltaX); - var y = this.limitY(this.deltaY); - var dragCanceled = opt_dragCanceled || - e.type == goog.events.EventType.TOUCHCANCEL; - this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.END, this, e.clientX, e.clientY, e, x, y, - dragCanceled)); - } else { - this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL); - } -}; +ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg) { + if (!this.image_ || !this.image_.getImage()) { + return undefined; + } + if (this.getLayer().getSource() instanceof ol.source.ImageVector) { + // for ImageVector sources use the original hit-detection logic, + // so that for example also transparent polygons are detected + var coordinate = pixel.slice(); + ol.vec.Mat4.multVec2( + frameState.pixelToCoordinateMatrix, coordinate, coordinate); + var hasFeature = this.forEachFeatureAtCoordinate( + coordinate, frameState, goog.functions.TRUE, this); -/** - * Event handler that is used to end the drag by cancelling it. - * @param {goog.events.BrowserEvent} e Event object. - */ -goog.fx.Dragger.prototype.endDragCancel = function(e) { - this.endDrag(e, true); -}; + if (hasFeature) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } + } else { + var imageSize = + [this.image_.getImage().width, this.image_.getImage().height]; + if (!this.hitTransformationMatrix_) { + this.hitTransformationMatrix_ = this.getHitTransformationMatrix_( + frameState.size, imageSize); + } -/** - * Event handler that is used on mouse / touch move to update the drag - * @param {goog.events.BrowserEvent} e Event object. - * @private - */ -goog.fx.Dragger.prototype.handleMove_ = function(e) { - if (this.enabled_) { - // dx in right-to-left cases is relative to the right. - var sign = this.useRightPositioningForRtl_ && - this.isRightToLeft_() ? -1 : 1; - var dx = sign * (e.clientX - this.clientX); - var dy = e.clientY - this.clientY; - this.clientX = e.clientX; - this.clientY = e.clientY; - this.screenX = e.screenX; - this.screenY = e.screenY; + var pixelOnFrameBuffer = [0, 0]; + ol.vec.Mat4.multVec2( + this.hitTransformationMatrix_, pixel, pixelOnFrameBuffer); - if (!this.dragging_) { - var diffX = this.startX - this.clientX; - var diffY = this.startY - this.clientY; - var distance = diffX * diffX + diffY * diffY; - if (distance > this.hysteresisDistanceSquared_) { - if (this.fireDragStart_(e)) { - this.dragging_ = true; - } else { - // DragListGroup disposes of the dragger if BEFOREDRAGSTART is - // canceled. - if (!this.isDisposed()) { - this.endDrag(e); - } - return; - } - } + if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] || + pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) { + // outside the image, no need to check + return undefined; } - var pos = this.calculatePosition_(dx, dy); - var x = pos.x; - var y = pos.y; - - if (this.dragging_) { + if (!this.hitCanvasContext_) { + this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1); + } - var rv = this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.BEFOREDRAG, this, e.clientX, e.clientY, - e, x, y)); + this.hitCanvasContext_.clearRect(0, 0, 1, 1); + this.hitCanvasContext_.drawImage(this.image_.getImage(), + pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1); - // Only do the defaultAction and dispatch drag event if predrag didn't - // prevent default - if (rv) { - this.doDrag(e, x, y, false); - e.preventDefault(); - } + var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data; + if (imageData[3] > 0) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; } } }; /** - * Calculates the drag position. - * - * @param {number} dx The horizontal movement delta. - * @param {number} dy The vertical movement delta. - * @return {!goog.math.Coordinate} The newly calculated drag element position. + * The transformation matrix to get the pixel on the image for a + * pixel on the map. + * @param {ol.Size} mapSize + * @param {ol.Size} imageSize + * @return {goog.vec.Mat4.Number} * @private */ -goog.fx.Dragger.prototype.calculatePosition_ = function(dx, dy) { - // Update the position for any change in body scrolling - var pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll(); - dx += pageScroll.x - this.pageScroll.x; - dy += pageScroll.y - this.pageScroll.y; - this.pageScroll = pageScroll; +ol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ = + function(mapSize, imageSize) { + // the first matrix takes a map pixel, flips the y-axis and scales to + // a range between -1 ... 1 + var mapCoordMatrix = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.makeIdentity(mapCoordMatrix); + goog.vec.Mat4.translate(mapCoordMatrix, -1, -1, 0); + goog.vec.Mat4.scale(mapCoordMatrix, 2 / mapSize[0], 2 / mapSize[1], 1); + goog.vec.Mat4.translate(mapCoordMatrix, 0, mapSize[1], 0); + goog.vec.Mat4.scale(mapCoordMatrix, 1, -1, 1); - this.deltaX += dx; - this.deltaY += dy; + // the second matrix is the inverse of the projection matrix used in the + // shader for drawing + var projectionMatrixInv = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.invert(this.projectionMatrix, projectionMatrixInv); - var x = this.limitX(this.deltaX); - var y = this.limitY(this.deltaY); - return new goog.math.Coordinate(x, y); + // the third matrix scales to the image dimensions and flips the y-axis again + var imageCoordMatrix = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.makeIdentity(imageCoordMatrix); + goog.vec.Mat4.translate(imageCoordMatrix, 0, imageSize[1], 0); + goog.vec.Mat4.scale(imageCoordMatrix, 1, -1, 1); + goog.vec.Mat4.scale(imageCoordMatrix, imageSize[0] / 2, imageSize[1] / 2, 1); + goog.vec.Mat4.translate(imageCoordMatrix, 1, 1, 0); + + var transformMatrix = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.multMat( + imageCoordMatrix, projectionMatrixInv, transformMatrix); + goog.vec.Mat4.multMat( + transformMatrix, mapCoordMatrix, transformMatrix); + + return transformMatrix; }; +// This file is automatically generated, do not edit +goog.provide('ol.renderer.webgl.tilelayer.shader'); +goog.provide('ol.renderer.webgl.tilelayer.shader.Locations'); +goog.provide('ol.renderer.webgl.tilelayer.shader.Fragment'); +goog.provide('ol.renderer.webgl.tilelayer.shader.Vertex'); + +goog.require('ol.webgl.shader'); + + /** - * Event handler for scroll target scrolling. - * @param {goog.events.BrowserEvent} e The event. - * @private + * @constructor + * @extends {ol.webgl.shader.Fragment} + * @struct */ -goog.fx.Dragger.prototype.onScroll_ = function(e) { - var pos = this.calculatePosition_(0, 0); - e.clientX = this.clientX; - e.clientY = this.clientY; - this.doDrag(e, pos.x, pos.y, true); +ol.renderer.webgl.tilelayer.shader.Fragment = function() { + goog.base(this, ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE); }; +goog.inherits(ol.renderer.webgl.tilelayer.shader.Fragment, ol.webgl.shader.Fragment); +goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Fragment); /** - * @param {goog.events.BrowserEvent} e The closure object - * representing the browser event that caused a drag event. - * @param {number} x The new horizontal position for the drag element. - * @param {number} y The new vertical position for the drag element. - * @param {boolean} dragFromScroll Whether dragging was caused by scrolling - * the associated scroll target. - * @protected + * @const + * @type {string} */ -goog.fx.Dragger.prototype.doDrag = function(e, x, y, dragFromScroll) { - this.defaultAction(x, y); - this.dispatchEvent(new goog.fx.DragEvent( - goog.fx.Dragger.EventType.DRAG, this, e.clientX, e.clientY, e, x, y)); -}; +ol.renderer.webgl.tilelayer.shader.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'; /** - * Returns the 'real' x after limits are applied (allows for some - * limits to be undefined). - * @param {number} x X-coordinate to limit. - * @return {number} The 'real' X-coordinate after limits are applied. + * @const + * @type {string} */ -goog.fx.Dragger.prototype.limitX = function(x) { - var rect = this.limits; - var left = !isNaN(rect.left) ? rect.left : null; - var width = !isNaN(rect.width) ? rect.width : 0; - var maxX = left != null ? left + width : Infinity; - var minX = left != null ? left : -Infinity; - return Math.min(maxX, Math.max(minX, x)); -}; +ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}'; /** - * Returns the 'real' y after limits are applied (allows for some - * limits to be undefined). - * @param {number} y Y-coordinate to limit. - * @return {number} The 'real' Y-coordinate after limits are applied. + * @const + * @type {string} */ -goog.fx.Dragger.prototype.limitY = function(y) { - var rect = this.limits; - var top = !isNaN(rect.top) ? rect.top : null; - var height = !isNaN(rect.height) ? rect.height : 0; - var maxY = top != null ? top + height : Infinity; - var minY = top != null ? top : -Infinity; - return Math.min(maxY, Math.max(minY, y)); -}; +ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE = goog.DEBUG ? + ol.renderer.webgl.tilelayer.shader.Fragment.DEBUG_SOURCE : + ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE; + /** - * Overridable function for computing the initial position of the target - * before dragging begins. - * @protected + * @constructor + * @extends {ol.webgl.shader.Vertex} + * @struct */ -goog.fx.Dragger.prototype.computeInitialPosition = function() { - this.deltaX = this.useRightPositioningForRtl_ ? - goog.style.bidi.getOffsetStart(this.target) : - /** @type {!HTMLElement} */ (this.target).offsetLeft; - this.deltaY = /** @type {!HTMLElement} */ (this.target).offsetTop; +ol.renderer.webgl.tilelayer.shader.Vertex = function() { + goog.base(this, ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE); }; +goog.inherits(ol.renderer.webgl.tilelayer.shader.Vertex, ol.webgl.shader.Vertex); +goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Vertex); /** - * Overridable function for handling the default action of the drag behaviour. - * Normally this is simply moving the element to x,y though in some cases it - * might be used to resize the layer. This is basically a shortcut to - * implementing a default ondrag event handler. - * @param {number} x X-coordinate for target element. In right-to-left, x this - * is the number of pixels the target should be moved to from the right. - * @param {number} y Y-coordinate for target element. + * @const + * @type {string} */ -goog.fx.Dragger.prototype.defaultAction = function(x, y) { - if (this.useRightPositioningForRtl_ && this.isRightToLeft_()) { - this.target.style.right = x + 'px'; - } else { - this.target.style.left = x + 'px'; - } - this.target.style.top = y + 'px'; -}; +ol.renderer.webgl.tilelayer.shader.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'; /** - * @return {boolean} Whether the dragger is currently in the midst of a drag. + * @const + * @type {string} */ -goog.fx.Dragger.prototype.isDragging = function() { - return this.dragging_; -}; +ol.renderer.webgl.tilelayer.shader.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;}'; + + +/** + * @const + * @type {string} + */ +ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE = goog.DEBUG ? + ol.renderer.webgl.tilelayer.shader.Vertex.DEBUG_SOURCE : + ol.renderer.webgl.tilelayer.shader.Vertex.OPTIMIZED_SOURCE; /** - * Object representing a drag event - * @param {string} type Event type. - * @param {goog.fx.Dragger} dragobj Drag object initiating event. - * @param {number} clientX X-coordinate relative to the viewport. - * @param {number} clientY Y-coordinate relative to the viewport. - * @param {goog.events.BrowserEvent} browserEvent The closure object - * representing the browser event that caused this drag event. - * @param {number=} opt_actX Optional actual x for drag if it has been limited. - * @param {number=} opt_actY Optional actual y for drag if it has been limited. - * @param {boolean=} opt_dragCanceled Whether the drag has been canceled. * @constructor + * @param {WebGLRenderingContext} gl GL. + * @param {WebGLProgram} program Program. * @struct - * @extends {goog.events.Event} */ -goog.fx.DragEvent = function(type, dragobj, clientX, clientY, browserEvent, - opt_actX, opt_actY, opt_dragCanceled) { - goog.events.Event.call(this, type); - - /** - * X-coordinate relative to the viewport - * @type {number} - */ - this.clientX = clientX; +ol.renderer.webgl.tilelayer.shader.Locations = function(gl, program) { /** - * Y-coordinate relative to the viewport - * @type {number} + * @type {WebGLUniformLocation} */ - this.clientY = clientY; + this.u_texture = gl.getUniformLocation( + program, goog.DEBUG ? 'u_texture' : 'e'); /** - * The closure object representing the browser event that caused this drag - * event. - * @type {goog.events.BrowserEvent} + * @type {WebGLUniformLocation} */ - this.browserEvent = browserEvent; + this.u_tileOffset = gl.getUniformLocation( + program, goog.DEBUG ? 'u_tileOffset' : 'd'); /** - * The real x-position of the drag if it has been limited * @type {number} */ - this.left = goog.isDef(opt_actX) ? opt_actX : dragobj.deltaX; + this.a_position = gl.getAttribLocation( + program, goog.DEBUG ? 'a_position' : 'b'); /** - * The real y-position of the drag if it has been limited * @type {number} */ - this.top = goog.isDef(opt_actY) ? opt_actY : dragobj.deltaY; - - /** - * Reference to the drag object for this event - * @type {goog.fx.Dragger} - */ - this.dragger = dragobj; - - /** - * Whether drag was canceled with this event. Used to differentiate between - * a legitimate drag END that can result in an action and a drag END which is - * a result of a drag cancelation. For now it can happen 1) with drag END - * event on FireFox when user drags the mouse out of the window, 2) with - * drag END event on IE7 which is generated on MOUSEMOVE event when user - * moves the mouse into the document after the mouse button has been - * released, 3) when TOUCHCANCEL is raised instead of TOUCHEND (on touch - * events). - * @type {boolean} - */ - this.dragCanceled = !!opt_dragCanceled; + this.a_texCoord = gl.getAttribLocation( + program, goog.DEBUG ? 'a_texCoord' : 'c'); }; -goog.inherits(goog.fx.DragEvent, goog.events.Event); -// FIXME should possibly show tooltip when dragging? +// FIXME large resolutions lead to too large framebuffers :-( +// FIXME animated shaders! check in redraw -goog.provide('ol.control.ZoomSlider'); +goog.provide('ol.renderer.webgl.TileLayer'); +goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.fx.DragEvent'); -goog.require('goog.fx.Dragger'); -goog.require('goog.fx.Dragger.EventType'); -goog.require('goog.math.Rect'); -goog.require('goog.style'); -goog.require('ol.Size'); -goog.require('ol.ViewHint'); -goog.require('ol.animation'); -goog.require('ol.control.Control'); -goog.require('ol.css'); -goog.require('ol.easing'); +goog.require('goog.vec.Mat4'); +goog.require('goog.vec.Vec4'); +goog.require('goog.webgl'); +goog.require('ol.TileRange'); +goog.require('ol.TileState'); +goog.require('ol.extent'); +goog.require('ol.layer.Tile'); goog.require('ol.math'); +goog.require('ol.renderer.webgl.Layer'); +goog.require('ol.renderer.webgl.tilelayer.shader.Fragment'); +goog.require('ol.renderer.webgl.tilelayer.shader.Locations'); +goog.require('ol.renderer.webgl.tilelayer.shader.Vertex'); +goog.require('ol.size'); +goog.require('ol.tilecoord'); +goog.require('ol.vec.Mat4'); +goog.require('ol.webgl.Buffer'); /** - * @classdesc - * A slider type of control for zooming. - * - * Example: - * - * map.addControl(new ol.control.ZoomSlider()); - * * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options. - * @api stable + * @extends {ol.renderer.webgl.Layer} + * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. + * @param {ol.layer.Tile} tileLayer Tile layer. */ -ol.control.ZoomSlider = function(opt_options) { +ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) { - var options = opt_options ? opt_options : {}; + goog.base(this, mapRenderer, tileLayer); /** - * Will hold the current resolution of the view. - * - * @type {number|undefined} * @private + * @type {ol.webgl.shader.Fragment} */ - this.currentResolution_ = undefined; + this.fragmentShader_ = + ol.renderer.webgl.tilelayer.shader.Fragment.getInstance(); /** - * The direction of the slider. Will be determined from actual display of the - * container and defaults to ol.control.ZoomSlider.direction.VERTICAL. - * - * @type {ol.control.ZoomSlider.direction} * @private + * @type {ol.webgl.shader.Vertex} */ - this.direction_ = ol.control.ZoomSlider.direction.VERTICAL; + this.vertexShader_ = ol.renderer.webgl.tilelayer.shader.Vertex.getInstance(); /** - * The calculated thumb size (border box plus margins). Set when initSlider_ - * is called. - * @type {ol.Size} * @private + * @type {ol.renderer.webgl.tilelayer.shader.Locations} */ - this.thumbSize_ = null; + this.locations_ = null; /** - * Whether the slider is initialized. - * @type {boolean} * @private + * @type {ol.webgl.Buffer} */ - this.sliderInitialized_ = false; + this.renderArrayBuffer_ = new ol.webgl.Buffer([ + 0, 0, 0, 1, + 1, 0, 1, 1, + 0, 1, 0, 0, + 1, 1, 1, 0 + ]); /** * @private - * @type {number} + * @type {ol.TileRange} */ - this.duration_ = options.duration !== undefined ? options.duration : 200; + this.renderedTileRange_ = null; - var className = options.className ? options.className : 'ol-zoomslider'; - var thumbElement = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'class': className + '-thumb ' + ol.css.CLASS_UNSELECTABLE - }); - var containerElement = goog.dom.createDom('DIV', - [className, ol.css.CLASS_UNSELECTABLE, ol.css.CLASS_CONTROL], - thumbElement); + /** + * @private + * @type {ol.Extent} + */ + this.renderedFramebufferExtent_ = null; /** - * @type {goog.fx.Dragger} * @private + * @type {number} */ - this.dragger_ = new goog.fx.Dragger(thumbElement); - this.registerDisposable(this.dragger_); + this.renderedRevision_ = -1; - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START, - this.handleDraggerStart_, false, this); - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG, - this.handleDraggerDrag_, false, this); - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END, - this.handleDraggerEnd_, false, this); + /** + * @private + * @type {ol.Size} + */ + this.tmpSize_ = [0, 0]; - goog.events.listen(containerElement, goog.events.EventType.CLICK, - this.handleContainerClick_, false, this); - goog.events.listen(thumbElement, goog.events.EventType.CLICK, - goog.events.Event.stopPropagation); +}; +goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer); - var render = options.render ? options.render : ol.control.ZoomSlider.render; - goog.base(this, { - element: containerElement, - render: render - }); +/** + * @inheritDoc + */ +ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() { + var context = this.mapRenderer.getContext(); + context.deleteBuffer(this.renderArrayBuffer_); + goog.base(this, 'disposeInternal'); }; -goog.inherits(ol.control.ZoomSlider, ol.control.Control); /** - * The enum for available directions. - * - * @enum {number} + * Create a function that adds loaded tiles to the tile lookup. + * @param {ol.source.Tile} source Tile source. + * @param {ol.proj.Projection} projection Projection of the tiles. + * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded + * tiles by zoom level. + * @return {function(number, ol.TileRange):boolean} A function that can be + * called with a zoom level and a tile range to add loaded tiles to the + * lookup. + * @protected */ -ol.control.ZoomSlider.direction = { - VERTICAL: 0, - HORIZONTAL: 1 +ol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder = + function(source, projection, tiles) { + var mapRenderer = this.mapRenderer; + + return ( + /** + * @param {number} zoom Zoom level. + * @param {ol.TileRange} tileRange Tile range. + * @return {boolean} The tile range is fully loaded. + */ + function(zoom, tileRange) { + return source.forEachLoadedTile(projection, zoom, + tileRange, function(tile) { + var loaded = mapRenderer.isTileTextureLoaded(tile); + if (loaded) { + if (!tiles[zoom]) { + tiles[zoom] = {}; + } + tiles[zoom][tile.tileCoord.toString()] = tile; + } + return loaded; + }); + }); }; /** * @inheritDoc */ -ol.control.ZoomSlider.prototype.setMap = function(map) { - goog.base(this, 'setMap', map); - if (map) { - map.render(); - } +ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() { + goog.base(this, 'handleWebGLContextLost'); + this.locations_ = null; }; /** - * Initializes the slider element. This will determine and set this controls - * direction_ and also constrain the dragging of the thumb to always be within - * the bounds of the container. - * - * @private + * @inheritDoc */ -ol.control.ZoomSlider.prototype.initSlider_ = function() { - var container = this.element; - var containerSize = goog.style.getSize(container); +ol.renderer.webgl.TileLayer.prototype.prepareFrame = + function(frameState, layerState, context) { - var thumb = goog.dom.getFirstElementChild(container); - var thumbMargins = goog.style.getMarginBox(thumb); - var thumbBorderBoxSize = goog.style.getBorderBoxSize(thumb); - var thumbWidth = thumbBorderBoxSize.width + - thumbMargins.right + thumbMargins.left; - var thumbHeight = thumbBorderBoxSize.height + - thumbMargins.top + thumbMargins.bottom; - this.thumbSize_ = [thumbWidth, thumbHeight]; + var mapRenderer = this.mapRenderer; + var gl = context.getGL(); - var width = containerSize.width - thumbWidth; - var height = containerSize.height - thumbHeight; + var viewState = frameState.viewState; + var projection = viewState.projection; - var limits; - if (containerSize.width > containerSize.height) { - this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL; - limits = new goog.math.Rect(0, 0, width, 0); + var tileLayer = this.getLayer(); + goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile, + 'layer is an instance of ol.layer.Tile'); + var tileSource = tileLayer.getSource(); + var tileGrid = tileSource.getTileGridForProjection(projection); + var z = tileGrid.getZForResolution(viewState.resolution); + var tileResolution = tileGrid.getResolution(z); + + var tilePixelSize = + tileSource.getTilePixelSize(z, frameState.pixelRatio, projection); + var pixelRatio = tilePixelSize[0] / + ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0]; + var tilePixelResolution = tileResolution / pixelRatio; + var tileGutter = tileSource.getGutter(); + + var center = viewState.center; + var extent; + if (tileResolution == viewState.resolution) { + center = this.snapCenterToPixel(center, tileResolution, frameState.size); + extent = ol.extent.getForViewAndSize( + center, tileResolution, viewState.rotation, frameState.size); } else { - this.direction_ = ol.control.ZoomSlider.direction.VERTICAL; - limits = new goog.math.Rect(0, 0, 0, height); + extent = frameState.extent; } - this.dragger_.setLimits(limits); - this.sliderInitialized_ = true; -}; + var tileRange = tileGrid.getTileRangeForExtentAndResolution( + extent, tileResolution); + var framebufferExtent; + if (this.renderedTileRange_ && + this.renderedTileRange_.equals(tileRange) && + this.renderedRevision_ == tileSource.getRevision()) { + framebufferExtent = this.renderedFramebufferExtent_; + } else { -/** - * Update the zoomslider element. - * @param {ol.MapEvent} mapEvent Map event. - * @this {ol.control.ZoomSlider} - * @api - */ -ol.control.ZoomSlider.render = function(mapEvent) { - if (!mapEvent.frameState) { - return; - } - goog.asserts.assert(mapEvent.frameState.viewState, - 'viewState should be defined'); - if (!this.sliderInitialized_) { - this.initSlider_(); - } - var res = mapEvent.frameState.viewState.resolution; - if (res !== this.currentResolution_) { - this.currentResolution_ = res; - this.setThumbPosition_(res); - } -}; + var tileRangeSize = tileRange.getSize(); + var maxDimension = Math.max( + tileRangeSize[0] * tilePixelSize[0], + tileRangeSize[1] * tilePixelSize[1]); + var framebufferDimension = ol.math.roundUpToPowerOfTwo(maxDimension); + var framebufferExtentDimension = tilePixelResolution * framebufferDimension; + var origin = tileGrid.getOrigin(z); + var minX = origin[0] + + tileRange.minX * tilePixelSize[0] * tilePixelResolution; + var minY = origin[1] + + tileRange.minY * tilePixelSize[1] * tilePixelResolution; + framebufferExtent = [ + minX, minY, + minX + framebufferExtentDimension, minY + framebufferExtentDimension + ]; -/** - * @param {goog.events.BrowserEvent} browserEvent The browser event to handle. - * @private - */ -ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) { - var map = this.getMap(); - var view = map.getView(); - var currentResolution = view.getResolution(); - goog.asserts.assert(currentResolution, - 'currentResolution should be defined'); - map.beforeRender(ol.animation.zoom({ - resolution: currentResolution, - duration: this.duration_, - easing: ol.easing.easeOut - })); - var relativePosition = this.getRelativePosition_( - browserEvent.offsetX - this.thumbSize_[0] / 2, - browserEvent.offsetY - this.thumbSize_[1] / 2); - var resolution = this.getResolutionForPosition_(relativePosition); - view.setResolution(view.constrainResolution(resolution)); -}; + this.bindFramebuffer(frameState, framebufferDimension); + gl.viewport(0, 0, framebufferDimension, framebufferDimension); + gl.clearColor(0, 0, 0, 0); + gl.clear(goog.webgl.COLOR_BUFFER_BIT); + gl.disable(goog.webgl.BLEND); -/** - * Handle dragger start events. - * @param {goog.fx.DragEvent} event The drag event. - * @private - */ -ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) { - this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1); -}; + var program = context.getProgram(this.fragmentShader_, this.vertexShader_); + context.useProgram(program); + if (!this.locations_) { + this.locations_ = + new ol.renderer.webgl.tilelayer.shader.Locations(gl, program); + } + context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.renderArrayBuffer_); + gl.enableVertexAttribArray(this.locations_.a_position); + gl.vertexAttribPointer( + this.locations_.a_position, 2, goog.webgl.FLOAT, false, 16, 0); + gl.enableVertexAttribArray(this.locations_.a_texCoord); + gl.vertexAttribPointer( + this.locations_.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); + gl.uniform1i(this.locations_.u_texture, 0); -/** - * Handle dragger drag events. - * - * @param {goog.fx.DragEvent} event The drag event. - * @private - */ -ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) { - var relativePosition = this.getRelativePosition_(event.left, event.top); - this.currentResolution_ = this.getResolutionForPosition_(relativePosition); - this.getMap().getView().setResolution(this.currentResolution_); -}; + /** + * @type {Object.<number, Object.<string, ol.Tile>>} + */ + var tilesToDrawByZ = {}; + tilesToDrawByZ[z] = {}; + var findLoadedTiles = this.createLoadedTileFinder( + tileSource, projection, tilesToDrawByZ); -/** - * Handle dragger end events. - * @param {goog.fx.DragEvent} event The drag event. - * @private - */ -ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) { - var map = this.getMap(); - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - goog.asserts.assert(this.currentResolution_, - 'this.currentResolution_ should be defined'); - map.beforeRender(ol.animation.zoom({ - resolution: this.currentResolution_, - duration: this.duration_, - easing: ol.easing.easeOut - })); - var resolution = view.constrainResolution(this.currentResolution_); - view.setResolution(resolution); -}; + var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); + var allTilesLoaded = true; + var tmpExtent = ol.extent.createEmpty(); + var tmpTileRange = new ol.TileRange(0, 0, 0, 0); + var childTileRange, drawable, fullyLoaded, tile, tileState; + var x, y, tileExtent; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + + tile = tileSource.getTile(z, x, y, pixelRatio, projection); + if (layerState.extent !== undefined) { + // ignore tiles outside layer extent + tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); + if (!ol.extent.intersects(tileExtent, layerState.extent)) { + continue; + } + } + tileState = tile.getState(); + drawable = tileState == ol.TileState.LOADED || + tileState == ol.TileState.EMPTY || + tileState == ol.TileState.ERROR && !useInterimTilesOnError; + if (!drawable && tile.interimTile) { + tile = tile.interimTile; + } + goog.asserts.assert(tile); + tileState = tile.getState(); + if (tileState == ol.TileState.LOADED) { + if (mapRenderer.isTileTextureLoaded(tile)) { + tilesToDrawByZ[z][ol.tilecoord.toString(tile.tileCoord)] = tile; + continue; + } + } else if (tileState == ol.TileState.EMPTY || + (tileState == ol.TileState.ERROR && + !useInterimTilesOnError)) { + continue; + } + allTilesLoaded = false; + fullyLoaded = tileGrid.forEachTileCoordParentTileRange( + tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent); + if (!fullyLoaded) { + childTileRange = tileGrid.getTileCoordChildTileRange( + tile.tileCoord, tmpTileRange, tmpExtent); + if (childTileRange) { + findLoadedTiles(z + 1, childTileRange); + } + } -/** - * Positions the thumb inside its container according to the given resolution. - * - * @param {number} res The res. - * @private - */ -ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) { - var position = this.getPositionForResolution_(res); - var dragger = this.dragger_; - var thumb = goog.dom.getFirstElementChild(this.element); + } + + } + + /** @type {Array.<number>} */ + var zs = Object.keys(tilesToDrawByZ).map(Number); + goog.array.sort(zs); + var u_tileOffset = goog.vec.Vec4.createFloat32(); + var i, ii, sx, sy, tileKey, tilesToDraw, tx, ty; + for (i = 0, ii = zs.length; i < ii; ++i) { + tilesToDraw = tilesToDrawByZ[zs[i]]; + for (tileKey in tilesToDraw) { + tile = tilesToDraw[tileKey]; + tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent); + sx = 2 * (tileExtent[2] - tileExtent[0]) / + framebufferExtentDimension; + sy = 2 * (tileExtent[3] - tileExtent[1]) / + framebufferExtentDimension; + tx = 2 * (tileExtent[0] - framebufferExtent[0]) / + framebufferExtentDimension - 1; + ty = 2 * (tileExtent[1] - framebufferExtent[1]) / + framebufferExtentDimension - 1; + goog.vec.Vec4.setFromValues(u_tileOffset, sx, sy, tx, ty); + gl.uniform4fv(this.locations_.u_tileOffset, u_tileOffset); + mapRenderer.bindTileTexture(tile, tilePixelSize, + tileGutter * pixelRatio, goog.webgl.LINEAR, goog.webgl.LINEAR); + gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); + } + } + + if (allTilesLoaded) { + this.renderedTileRange_ = tileRange; + this.renderedFramebufferExtent_ = framebufferExtent; + this.renderedRevision_ = tileSource.getRevision(); + } else { + this.renderedTileRange_ = null; + this.renderedFramebufferExtent_ = null; + this.renderedRevision_ = -1; + frameState.animate = true; + } - if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) { - var left = dragger.limits.left + dragger.limits.width * position; - goog.style.setPosition(thumb, left); - } else { - var top = dragger.limits.top + dragger.limits.height * position; - goog.style.setPosition(thumb, dragger.limits.left, top); } -}; + this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange); + var tileTextureQueue = mapRenderer.getTileTextureQueue(); + this.manageTilePyramid( + frameState, tileSource, tileGrid, pixelRatio, projection, extent, z, + tileLayer.getPreload(), + /** + * @param {ol.Tile} tile Tile. + */ + function(tile) { + if (tile.getState() == ol.TileState.LOADED && + !mapRenderer.isTileTextureLoaded(tile) && + !tileTextureQueue.isKeyQueued(tile.getKey())) { + tileTextureQueue.enqueue([ + tile, + tileGrid.getTileCoordCenter(tile.tileCoord), + tileGrid.getResolution(tile.tileCoord[0]), + tilePixelSize, tileGutter * pixelRatio + ]); + } + }, this); + this.scheduleExpireCache(frameState, tileSource); + this.updateLogos(frameState, tileSource); -/** - * Calculates the relative position of the thumb given x and y offsets. The - * relative position scales from 0 to 1. The x and y offsets are assumed to be - * in pixel units within the dragger limits. - * - * @param {number} x Pixel position relative to the left of the slider. - * @param {number} y Pixel position relative to the top of the slider. - * @return {number} The relative position of the thumb. - * @private - */ -ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) { - var draggerLimits = this.dragger_.limits; - var amount; - if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) { - amount = (x - draggerLimits.left) / draggerLimits.width; - } else { - amount = (y - draggerLimits.top) / draggerLimits.height; + var texCoordMatrix = this.texCoordMatrix; + goog.vec.Mat4.makeIdentity(texCoordMatrix); + goog.vec.Mat4.translate(texCoordMatrix, + (center[0] - framebufferExtent[0]) / + (framebufferExtent[2] - framebufferExtent[0]), + (center[1] - framebufferExtent[1]) / + (framebufferExtent[3] - framebufferExtent[1]), + 0); + if (viewState.rotation !== 0) { + goog.vec.Mat4.rotateZ(texCoordMatrix, viewState.rotation); } - return ol.math.clamp(amount, 0, 1); + goog.vec.Mat4.scale(texCoordMatrix, + frameState.size[0] * viewState.resolution / + (framebufferExtent[2] - framebufferExtent[0]), + frameState.size[1] * viewState.resolution / + (framebufferExtent[3] - framebufferExtent[1]), + 1); + goog.vec.Mat4.translate(texCoordMatrix, + -0.5, + -0.5, + 0); + + return true; }; /** - * Calculates the corresponding resolution of the thumb given its relative - * position (where 0 is the minimum and 1 is the maximum). - * - * @param {number} position The relative position of the thumb. - * @return {number} The corresponding resolution. - * @private + * @inheritDoc */ -ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) { - var fn = this.getMap().getView().getResolutionForValueFunction(); - return fn(1 - position); -}; +ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg) { + if (!this.framebuffer) { + return undefined; + } + var pixelOnMapScaled = [ + pixel[0] / frameState.size[0], + (frameState.size[1] - pixel[1]) / frameState.size[1]]; -/** - * Determines the relative position of the slider for the given resolution. A - * relative position of 0 corresponds to the minimum view resolution. A - * relative position of 1 corresponds to the maximum view resolution. - * - * @param {number} res The resolution. - * @return {number} The relative position value (between 0 and 1). - * @private - */ -ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) { - var fn = this.getMap().getView().getValueForResolutionFunction(); - return 1 - fn(res); + var pixelOnFrameBufferScaled = [0, 0]; + ol.vec.Mat4.multVec2( + this.texCoordMatrix, pixelOnMapScaled, pixelOnFrameBufferScaled); + var pixelOnFrameBuffer = [ + pixelOnFrameBufferScaled[0] * this.framebufferDimension, + pixelOnFrameBufferScaled[1] * this.framebufferDimension]; + + var gl = this.mapRenderer.getContext().getGL(); + gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); + var imageData = new Uint8Array(4); + gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, + gl.RGBA, gl.UNSIGNED_BYTE, imageData); + + if (imageData[3] > 0) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } }; -goog.provide('ol.control.ZoomToExtent'); +goog.provide('ol.renderer.webgl.VectorLayer'); +goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.dom'); goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.control.Control'); -goog.require('ol.css'); +goog.require('ol.ViewHint'); +goog.require('ol.extent'); +goog.require('ol.layer.Vector'); +goog.require('ol.render.webgl.ReplayGroup'); +goog.require('ol.renderer.vector'); +goog.require('ol.renderer.webgl.Layer'); +goog.require('ol.vec.Mat4'); /** - * @classdesc - * A button control which, when pressed, changes the map view to a specific - * extent. To style this control use the css selector `.ol-zoom-extent`. - * * @constructor - * @extends {ol.control.Control} - * @param {olx.control.ZoomToExtentOptions=} opt_options Options. - * @api stable + * @extends {ol.renderer.webgl.Layer} + * @param {ol.renderer.webgl.Map} mapRenderer Map renderer. + * @param {ol.layer.Vector} vectorLayer Vector layer. */ -ol.control.ZoomToExtent = function(opt_options) { - var options = opt_options ? opt_options : {}; +ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) { + + goog.base(this, mapRenderer, vectorLayer); /** - * @type {ol.Extent} * @private + * @type {boolean} */ - this.extent_ = options.extent ? options.extent : null; + this.dirty_ = false; - var className = options.className ? options.className : - 'ol-zoom-extent'; + /** + * @private + * @type {number} + */ + this.renderedRevision_ = -1; - var label = options.label ? options.label : 'E'; - var tipLabel = options.tipLabel ? - options.tipLabel : 'Fit to extent'; - var button = goog.dom.createDom('BUTTON', { - 'type': 'button', - 'title': tipLabel - }, label); + /** + * @private + * @type {number} + */ + this.renderedResolution_ = NaN; - goog.events.listen(button, goog.events.EventType.CLICK, - this.handleClick_, false, this); + /** + * @private + * @type {ol.Extent} + */ + this.renderedExtent_ = ol.extent.createEmpty(); - var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + - ol.css.CLASS_CONTROL; - var element = goog.dom.createDom('DIV', cssClasses, button); + /** + * @private + * @type {function(ol.Feature, ol.Feature): number|null} + */ + this.renderedRenderOrder_ = null; + + /** + * @private + * @type {ol.render.webgl.ReplayGroup} + */ + this.replayGroup_ = null; + + /** + * The last layer state. + * @private + * @type {?ol.layer.LayerState} + */ + this.layerState_ = null; - goog.base(this, { - element: element, - target: options.target - }); }; -goog.inherits(ol.control.ZoomToExtent, ol.control.Control); +goog.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer); /** - * @param {goog.events.BrowserEvent} event The event to handle - * @private + * @inheritDoc */ -ol.control.ZoomToExtent.prototype.handleClick_ = function(event) { - event.preventDefault(); - this.handleZoomToExtent_(); +ol.renderer.webgl.VectorLayer.prototype.composeFrame = + function(frameState, layerState, context) { + this.layerState_ = layerState; + var viewState = frameState.viewState; + var replayGroup = this.replayGroup_; + if (replayGroup && !replayGroup.isEmpty()) { + replayGroup.replay(context, + viewState.center, viewState.resolution, viewState.rotation, + frameState.size, frameState.pixelRatio, layerState.opacity, + layerState.managed ? frameState.skippedFeatureUids : {}); + } + }; /** - * @private + * @inheritDoc */ -ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() { - var map = this.getMap(); - var view = map.getView(); - var extent = !this.extent_ ? - view.getProjection().getExtent() : this.extent_; - var size = map.getSize(); - goog.asserts.assert(size, 'size should be defined'); - view.fit(extent, size); +ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() { + var replayGroup = this.replayGroup_; + if (replayGroup) { + var context = this.mapRenderer.getContext(); + replayGroup.getDeleteResourcesFunction(context)(); + this.replayGroup_ = null; + } + goog.base(this, 'disposeInternal'); }; -goog.provide('ol.DeviceOrientation'); -goog.provide('ol.DeviceOrientationProperty'); - -goog.require('goog.events'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.has'); -goog.require('ol.math'); - /** - * @enum {string} + * @inheritDoc */ -ol.DeviceOrientationProperty = { - ALPHA: 'alpha', - BETA: 'beta', - GAMMA: 'gamma', - HEADING: 'heading', - TRACKING: 'tracking' +ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg) { + if (!this.replayGroup_ || !this.layerState_) { + return undefined; + } else { + var context = this.mapRenderer.getContext(); + var viewState = frameState.viewState; + var layer = this.getLayer(); + var layerState = this.layerState_; + /** @type {Object.<string, boolean>} */ + var features = {}; + return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, + context, viewState.center, viewState.resolution, viewState.rotation, + frameState.size, frameState.pixelRatio, layerState.opacity, + layerState.managed ? frameState.skippedFeatureUids : {}, + /** + * @param {ol.Feature} feature Feature. + * @return {?} Callback result. + */ + function(feature) { + goog.asserts.assert(feature !== undefined, 'received a feature'); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback.call(thisArg, feature, layer); + } + }); + } }; - /** - * @classdesc - * The ol.DeviceOrientation class provides access to information from - * DeviceOrientation events. See the [HTML 5 DeviceOrientation Specification]( - * http://www.w3.org/TR/orientation-event/) for more details. - * - * Many new computers, and especially mobile phones - * and tablets, provide hardware support for device orientation. Web - * developers targeting mobile devices will be especially interested in this - * class. - * - * Device orientation data are relative to a common starting point. For mobile - * devices, the starting point is to lay your phone face up on a table with the - * top of the phone pointing north. This represents the zero state. All - * angles are then relative to this state. For computers, it is the same except - * the screen is open at 90 degrees. - * - * Device orientation is reported as three angles - `alpha`, `beta`, and - * `gamma` - relative to the starting position along the three planar axes X, Y - * and Z. The X axis runs from the left edge to the right edge through the - * middle of the device. Similarly, the Y axis runs from the bottom to the top - * of the device through the middle. The Z axis runs from the back to the front - * through the middle. In the starting position, the X axis points to the - * right, the Y axis points away from you and the Z axis points straight up - * from the device lying flat. - * - * The three angles representing the device orientation are relative to the - * three axes. `alpha` indicates how much the device has been rotated around the - * Z axis, which is commonly interpreted as the compass heading (see note - * below). `beta` indicates how much the device has been rotated around the X - * axis, or how much it is tilted from front to back. `gamma` indicates how - * much the device has been rotated around the Y axis, or how much it is tilted - * from left to right. - * - * For most browsers, the `alpha` value returns the compass heading so if the - * device points north, it will be 0. With Safari on iOS, the 0 value of - * `alpha` is calculated from when device orientation was first requested. - * ol.DeviceOrientation provides the `heading` property which normalizes this - * behavior across all browsers for you. - * - * It is important to note that the HTML 5 DeviceOrientation specification - * indicates that `alpha`, `beta` and `gamma` are in degrees while the - * equivalent properties in ol.DeviceOrientation are in radians for consistency - * with all other uses of angles throughout OpenLayers. - * - * @see http://www.w3.org/TR/orientation-event/ - * - * To get notified of device orientation changes, register a listener for the - * generic `change` event on your `ol.DeviceOrientation` instance. - * - * @constructor - * @extends {ol.Object} - * @param {olx.DeviceOrientationOptions=} opt_options Options. - * @api + * @inheritDoc */ -ol.DeviceOrientation = function(opt_options) { - - goog.base(this); - - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {goog.events.Key} - */ - this.listenerKey_ = null; - - goog.events.listen(this, - ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING), - this.handleTrackingChanged_, false, this); - - this.setTracking(options.tracking !== undefined ? options.tracking : false); - +ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = + function(coordinate, frameState) { + if (!this.replayGroup_ || !this.layerState_) { + return false; + } else { + var context = this.mapRenderer.getContext(); + var viewState = frameState.viewState; + var layerState = this.layerState_; + return this.replayGroup_.hasFeatureAtCoordinate(coordinate, + context, viewState.center, viewState.resolution, viewState.rotation, + frameState.size, frameState.pixelRatio, layerState.opacity, + frameState.skippedFeatureUids); + } }; -goog.inherits(ol.DeviceOrientation, ol.Object); /** * @inheritDoc */ -ol.DeviceOrientation.prototype.disposeInternal = function() { - this.setTracking(false); - goog.base(this, 'disposeInternal'); +ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg) { + var coordinate = pixel.slice(); + ol.vec.Mat4.multVec2( + frameState.pixelToCoordinateMatrix, coordinate, coordinate); + var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState); + + if (hasFeature) { + return callback.call(thisArg, this.getLayer()); + } else { + return undefined; + } }; /** + * Handle changes in image style state. + * @param {goog.events.Event} event Image style change event. * @private - * @param {goog.events.BrowserEvent} browserEvent Event. */ -ol.DeviceOrientation.prototype.orientationChange_ = function(browserEvent) { - var event = /** @type {DeviceOrientationEvent} */ - (browserEvent.getBrowserEvent()); - if (event.alpha !== null) { - var alpha = ol.math.toRadians(event.alpha); - this.set(ol.DeviceOrientationProperty.ALPHA, alpha); - // event.absolute is undefined in iOS. - if (goog.isBoolean(event.absolute) && event.absolute) { - this.set(ol.DeviceOrientationProperty.HEADING, alpha); - } else if (goog.isNumber(event.webkitCompassHeading) && - event.webkitCompassAccuracy != -1) { - var heading = ol.math.toRadians(event.webkitCompassHeading); - this.set(ol.DeviceOrientationProperty.HEADING, heading); - } - } - if (event.beta !== null) { - this.set(ol.DeviceOrientationProperty.BETA, - ol.math.toRadians(event.beta)); - } - if (event.gamma !== null) { - this.set(ol.DeviceOrientationProperty.GAMMA, - ol.math.toRadians(event.gamma)); - } - this.changed(); +ol.renderer.webgl.VectorLayer.prototype.handleStyleImageChange_ = + function(event) { + this.renderIfReadyAndVisible(); }; /** - * Rotation around the device z-axis (in radians). - * @return {number|undefined} The euler angle in radians of the device from the - * standard Z axis. - * @observable - * @api + * @inheritDoc */ -ol.DeviceOrientation.prototype.getAlpha = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.ALPHA)); -}; +ol.renderer.webgl.VectorLayer.prototype.prepareFrame = + function(frameState, layerState, context) { + var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer()); + goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector, + 'layer is an instance of ol.layer.Vector'); + var vectorSource = vectorLayer.getSource(); -/** - * Rotation around the device x-axis (in radians). - * @return {number|undefined} The euler angle in radians of the device from the - * planar X axis. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getBeta = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.BETA)); -}; + this.updateAttributions( + frameState.attributions, vectorSource.getAttributions()); + this.updateLogos(frameState, vectorSource); + var animating = frameState.viewHints[ol.ViewHint.ANIMATING]; + var interacting = frameState.viewHints[ol.ViewHint.INTERACTING]; + var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); + var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); -/** - * Rotation around the device y-axis (in radians). - * @return {number|undefined} The euler angle in radians of the device from the - * planar Y axis. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getGamma = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.GAMMA)); -}; + if (!this.dirty_ && (!updateWhileAnimating && animating) || + (!updateWhileInteracting && interacting)) { + return true; + } + var frameStateExtent = frameState.extent; + var viewState = frameState.viewState; + var projection = viewState.projection; + var resolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var vectorLayerRevision = vectorLayer.getRevision(); + var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); + var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); -/** - * The heading of the device relative to north (in radians). - * @return {number|undefined} The heading of the device relative to north, in - * radians, normalizing for different browser behavior. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getHeading = function() { - return /** @type {number|undefined} */ ( - this.get(ol.DeviceOrientationProperty.HEADING)); -}; + if (vectorLayerRenderOrder === undefined) { + vectorLayerRenderOrder = ol.renderer.vector.defaultOrder; + } + var extent = ol.extent.buffer(frameStateExtent, + vectorLayerRenderBuffer * resolution); -/** - * Determine if orientation is being tracked. - * @return {boolean} Changes in device orientation are being tracked. - * @observable - * @api - */ -ol.DeviceOrientation.prototype.getTracking = function() { - return /** @type {boolean} */ ( - this.get(ol.DeviceOrientationProperty.TRACKING)); -}; + if (!this.dirty_ && + this.renderedResolution_ == resolution && + this.renderedRevision_ == vectorLayerRevision && + this.renderedRenderOrder_ == vectorLayerRenderOrder && + ol.extent.containsExtent(this.renderedExtent_, extent)) { + return true; + } + if (this.replayGroup_) { + frameState.postRenderFunctions.push( + this.replayGroup_.getDeleteResourcesFunction(context)); + } -/** - * @private - */ -ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() { - if (ol.has.DEVICE_ORIENTATION) { - var tracking = this.getTracking(); - if (tracking && !this.listenerKey_) { - this.listenerKey_ = goog.events.listen(goog.global, 'deviceorientation', - this.orientationChange_, false, this); - } else if (!tracking && this.listenerKey_) { - goog.events.unlistenByKey(this.listenerKey_); - this.listenerKey_ = null; + this.dirty_ = false; + + var replayGroup = new ol.render.webgl.ReplayGroup( + ol.renderer.vector.getTolerance(resolution, pixelRatio), + extent, vectorLayer.getRenderBuffer()); + vectorSource.loadFeatures(extent, resolution, projection); + var renderFeature = + /** + * @param {ol.Feature} feature Feature. + * @this {ol.renderer.webgl.VectorLayer} + */ + function(feature) { + var styles; + var styleFunction = feature.getStyleFunction(); + if (styleFunction) { + styles = styleFunction.call(feature, resolution); + } else { + styleFunction = vectorLayer.getStyleFunction(); + if (styleFunction) { + styles = styleFunction(feature, resolution); + } + } + if (styles) { + var dirty = this.renderFeature( + feature, resolution, pixelRatio, styles, replayGroup); + this.dirty_ = this.dirty_ || dirty; } + }; + if (vectorLayerRenderOrder) { + /** @type {Array.<ol.Feature>} */ + var features = []; + vectorSource.forEachFeatureInExtent(extent, + /** + * @param {ol.Feature} feature Feature. + */ + function(feature) { + features.push(feature); + }, this); + goog.array.sort(features, vectorLayerRenderOrder); + features.forEach(renderFeature, this); + } else { + vectorSource.forEachFeatureInExtent(extent, renderFeature, this); } + replayGroup.finish(context); + + this.renderedResolution_ = resolution; + this.renderedRevision_ = vectorLayerRevision; + this.renderedRenderOrder_ = vectorLayerRenderOrder; + this.renderedExtent_ = extent; + this.replayGroup_ = replayGroup; + + return true; }; /** - * Enable or disable tracking of device orientation events. - * @param {boolean} tracking The status of tracking changes to alpha, beta and - * gamma. If true, changes are tracked and reported immediately. - * @observable - * @api + * @param {ol.Feature} feature Feature. + * @param {number} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of + * styles. + * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group. + * @return {boolean} `true` if an image is loading. */ -ol.DeviceOrientation.prototype.setTracking = function(tracking) { - this.set(ol.DeviceOrientationProperty.TRACKING, tracking); +ol.renderer.webgl.VectorLayer.prototype.renderFeature = + function(feature, resolution, pixelRatio, styles, replayGroup) { + if (!styles) { + return false; + } + var loading = false; + if (goog.isArray(styles)) { + for (var i = 0, ii = styles.length; i < ii; ++i) { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles[i], + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleStyleImageChange_, this) || loading; + } + } else { + loading = ol.renderer.vector.renderFeature( + replayGroup, feature, styles, + ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio), + this.handleStyleImageChange_, this) || loading; + } + return loading; }; -goog.provide('ol.format.Feature'); +// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE) -goog.require('ol.geom.Geometry'); -goog.require('ol.proj'); +goog.provide('ol.renderer.webgl.Map'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.log'); +goog.require('goog.log.Logger'); +goog.require('goog.object'); +goog.require('goog.style'); +goog.require('goog.webgl'); +goog.require('ol'); +goog.require('ol.RendererType'); +goog.require('ol.css'); +goog.require('ol.dom'); +goog.require('ol.layer.Image'); +goog.require('ol.layer.Layer'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.webgl.Immediate'); +goog.require('ol.renderer.Map'); +goog.require('ol.renderer.webgl.ImageLayer'); +goog.require('ol.renderer.webgl.Layer'); +goog.require('ol.renderer.webgl.TileLayer'); +goog.require('ol.renderer.webgl.VectorLayer'); +goog.require('ol.source.State'); +goog.require('ol.structs.LRUCache'); +goog.require('ol.structs.PriorityQueue'); +goog.require('ol.webgl'); +goog.require('ol.webgl.Context'); +goog.require('ol.webgl.WebGLContextEventType'); /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for feature formats. - * {ol.format.Feature} subclasses provide the ability to decode and encode - * {@link ol.Feature} objects from a variety of commonly used geospatial - * file formats. See the documentation for each format for more details. - * - * @constructor - * @api stable + * @typedef {{magFilter: number, minFilter: number, texture: WebGLTexture}} */ -ol.format.Feature = function() { - - /** - * @protected - * @type {ol.proj.Projection} - */ - this.defaultDataProjection = null; +ol.renderer.webgl.TextureCacheEntry; -}; /** - * @return {Array.<string>} Extensions. + * @constructor + * @extends {ol.renderer.Map} + * @param {Element} container Container. + * @param {ol.Map} map Map. */ -ol.format.Feature.prototype.getExtensions = goog.abstractMethod; +ol.renderer.webgl.Map = function(container, map) { + goog.base(this, container, map); -/** - * Adds the data projection to the read options. - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {olx.format.ReadOptions|undefined} Options. - * @protected - */ -ol.format.Feature.prototype.getReadOptions = function(source, opt_options) { - var options; - if (opt_options) { - options = { - dataProjection: opt_options.dataProjection ? - opt_options.dataProjection : this.readProjection(source), - featureProjection: opt_options.featureProjection - }; - } - return this.adaptOptions(options); -}; + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + this.canvas_.style.width = '100%'; + this.canvas_.style.height = '100%'; + this.canvas_.className = ol.css.CLASS_UNSELECTABLE; + goog.dom.insertChildAt(container, this.canvas_, 0); + /** + * @private + * @type {number} + */ + this.clipTileCanvasWidth_ = 0; -/** - * Sets the `defaultDataProjection` on the options, if no `dataProjection` - * is set. - * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options - * Options. - * @protected - * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined} - * Updated options. - */ -ol.format.Feature.prototype.adaptOptions = function(options) { - var updatedOptions; - if (options) { - updatedOptions = { - featureProjection: options.featureProjection, - dataProjection: options.dataProjection ? - options.dataProjection : this.defaultDataProjection, - rightHanded: options.rightHanded - }; - } - return updatedOptions; -}; + /** + * @private + * @type {number} + */ + this.clipTileCanvasHeight_ = 0; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.clipTileContext_ = ol.dom.createCanvasContext2D(); -/** - * @return {ol.format.FormatType} Format. - */ -ol.format.Feature.prototype.getType = goog.abstractMethod; - - -/** - * Read a single feature from a source. - * - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - */ -ol.format.Feature.prototype.readFeature = goog.abstractMethod; - - -/** - * Read all features from a source. - * - * @param {Document|Node|ArrayBuffer|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - */ -ol.format.Feature.prototype.readFeatures = goog.abstractMethod; + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = true; + /** + * @private + * @type {WebGLRenderingContext} + */ + this.gl_ = ol.webgl.getContext(this.canvas_, { + antialias: true, + depth: false, + failIfMajorPerformanceCaveat: true, + preserveDrawingBuffer: false, + stencil: true + }); + goog.asserts.assert(this.gl_, 'got a WebGLRenderingContext'); -/** - * Read a single geometry from a source. - * - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - */ -ol.format.Feature.prototype.readGeometry = goog.abstractMethod; + /** + * @private + * @type {ol.webgl.Context} + */ + this.context_ = new ol.webgl.Context(this.canvas_, this.gl_); + goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST, + this.handleWebGLContextLost, false, this); + goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED, + this.handleWebGLContextRestored, false, this); -/** - * Read the projection from a source. - * - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - */ -ol.format.Feature.prototype.readProjection = goog.abstractMethod; + /** + * @private + * @type {ol.structs.LRUCache.<ol.renderer.webgl.TextureCacheEntry|null>} + */ + this.textureCache_ = new ol.structs.LRUCache(); + /** + * @private + * @type {ol.Coordinate} + */ + this.focus_ = null; -/** - * Encode a feature in this format. - * - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - */ -ol.format.Feature.prototype.writeFeature = goog.abstractMethod; + /** + * @private + * @type {ol.structs.PriorityQueue.<Array>} + */ + this.tileTextureQueue_ = new ol.structs.PriorityQueue( + goog.bind( + /** + * @param {Array.<*>} element Element. + * @return {number} Priority. + * @this {ol.renderer.webgl.Map} + */ + function(element) { + var tileCenter = /** @type {ol.Coordinate} */ (element[1]); + var tileResolution = /** @type {number} */ (element[2]); + var deltaX = tileCenter[0] - this.focus_[0]; + var deltaY = tileCenter[1] - this.focus_[1]; + return 65536 * Math.log(tileResolution) + + Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution; + }, this), + /** + * @param {Array.<*>} element Element. + * @return {string} Key. + */ + function(element) { + return /** @type {ol.Tile} */ (element[0]).getKey(); + }); + /** + * @private + * @type {ol.PostRenderFunction} + */ + this.loadNextTileTexture_ = goog.bind( + function(map, frameState) { + if (!this.tileTextureQueue_.isEmpty()) { + this.tileTextureQueue_.reprioritize(); + var element = this.tileTextureQueue_.dequeue(); + var tile = /** @type {ol.Tile} */ (element[0]); + var tileSize = /** @type {ol.Size} */ (element[3]); + var tileGutter = /** @type {number} */ (element[4]); + this.bindTileTexture( + tile, tileSize, tileGutter, goog.webgl.LINEAR, goog.webgl.LINEAR); + } + }, this); -/** - * Encode an array of features in this format. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - */ -ol.format.Feature.prototype.writeFeatures = goog.abstractMethod; + /** + * @private + * @type {number} + */ + this.textureCacheFrameMarkerCount_ = 0; + this.initializeGL_(); -/** - * Write a single geometry in this format. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. - */ -ol.format.Feature.prototype.writeGeometry = goog.abstractMethod; +}; +goog.inherits(ol.renderer.webgl.Map, ol.renderer.Map); /** - * @param {ol.geom.Geometry|ol.Extent} geometry Geometry. - * @param {boolean} write Set to true for writing, false for reading. - * @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options - * Options. - * @return {ol.geom.Geometry|ol.Extent} Transformed geometry. - * @protected + * @param {ol.Tile} tile Tile. + * @param {ol.Size} tileSize Tile size. + * @param {number} tileGutter Tile gutter. + * @param {number} magFilter Mag filter. + * @param {number} minFilter Min filter. */ -ol.format.Feature.transformWithOptions = function( - geometry, write, opt_options) { - var featureProjection = opt_options ? - ol.proj.get(opt_options.featureProjection) : null; - var dataProjection = opt_options ? - ol.proj.get(opt_options.dataProjection) : null; - if (featureProjection && dataProjection && - !ol.proj.equivalent(featureProjection, dataProjection)) { - if (geometry instanceof ol.geom.Geometry) { - return (write ? geometry.clone() : geometry).transform( - write ? featureProjection : dataProjection, - write ? dataProjection : featureProjection); - } else { - // FIXME this is necessary because ol.format.GML treats extents - // as geometries - return ol.proj.transformExtent( - write ? geometry.slice() : geometry, - write ? featureProjection : dataProjection, - write ? dataProjection : featureProjection); +ol.renderer.webgl.Map.prototype.bindTileTexture = + function(tile, tileSize, tileGutter, magFilter, minFilter) { + var gl = this.getGL(); + var tileKey = tile.getKey(); + if (this.textureCache_.containsKey(tileKey)) { + var textureCacheEntry = this.textureCache_.get(tileKey); + goog.asserts.assert(textureCacheEntry, + 'a texture cache entry exists for key %s', tileKey); + gl.bindTexture(goog.webgl.TEXTURE_2D, textureCacheEntry.texture); + if (textureCacheEntry.magFilter != magFilter) { + gl.texParameteri( + goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter); + textureCacheEntry.magFilter = magFilter; + } + if (textureCacheEntry.minFilter != minFilter) { + gl.texParameteri( + goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, minFilter); + textureCacheEntry.minFilter = minFilter; } } else { - return geometry; + var texture = gl.createTexture(); + gl.bindTexture(goog.webgl.TEXTURE_2D, texture); + if (tileGutter > 0) { + var clipTileCanvas = this.clipTileContext_.canvas; + var clipTileContext = this.clipTileContext_; + if (this.clipTileCanvasWidth_ !== tileSize[0] || + this.clipTileCanvasHeight_ !== tileSize[1]) { + clipTileCanvas.width = tileSize[0]; + clipTileCanvas.height = tileSize[1]; + this.clipTileCanvasWidth_ = tileSize[0]; + this.clipTileCanvasHeight_ = tileSize[1]; + } else { + clipTileContext.clearRect(0, 0, tileSize[0], tileSize[1]); + } + clipTileContext.drawImage(tile.getImage(), tileGutter, tileGutter, + tileSize[0], tileSize[1], 0, 0, tileSize[0], tileSize[1]); + gl.texImage2D(goog.webgl.TEXTURE_2D, 0, + goog.webgl.RGBA, goog.webgl.RGBA, + goog.webgl.UNSIGNED_BYTE, clipTileCanvas); + } else { + gl.texImage2D(goog.webgl.TEXTURE_2D, 0, + goog.webgl.RGBA, goog.webgl.RGBA, + goog.webgl.UNSIGNED_BYTE, tile.getImage()); + } + gl.texParameteri( + goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter); + gl.texParameteri( + goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER, minFilter); + gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, + goog.webgl.CLAMP_TO_EDGE); + gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, + goog.webgl.CLAMP_TO_EDGE); + this.textureCache_.set(tileKey, { + texture: texture, + magFilter: magFilter, + minFilter: minFilter + }); } }; -goog.provide('ol.format.JSONFeature'); - -goog.require('goog.asserts'); -goog.require('goog.json'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); - - /** - * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for JSON feature formats. - * - * @constructor - * @extends {ol.format.Feature} + * @inheritDoc */ -ol.format.JSONFeature = function() { - goog.base(this); +ol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) { + if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { + return new ol.renderer.webgl.ImageLayer(this, layer); + } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) { + return new ol.renderer.webgl.TileLayer(this, layer); + } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) { + return new ol.renderer.webgl.VectorLayer(this, layer); + } else { + goog.asserts.fail('unexpected layer configuration'); + return null; + } }; -goog.inherits(ol.format.JSONFeature, ol.format.Feature); /** - * @param {Document|Node|Object|string} source Source. + * @param {ol.render.EventType} type Event type. + * @param {olx.FrameState} frameState Frame state. * @private - * @return {Object} Object. */ -ol.format.JSONFeature.prototype.getObject_ = function(source) { - if (goog.isObject(source)) { - return source; - } else if (goog.isString(source)) { - var object = goog.json.parse(source); - return object ? object : null; - } else { - goog.asserts.fail(); - return null; +ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ = + function(type, frameState) { + var map = this.getMap(); + if (map.hasListener(type)) { + var context = this.context_; + + var extent = frameState.extent; + var size = frameState.size; + var viewState = frameState.viewState; + var pixelRatio = frameState.pixelRatio; + + var resolution = viewState.resolution; + var center = viewState.center; + var rotation = viewState.rotation; + + var vectorContext = new ol.render.webgl.Immediate(context, + center, resolution, rotation, size, extent, pixelRatio); + var composeEvent = new ol.render.Event(type, map, vectorContext, + frameState, null, context); + map.dispatchEvent(composeEvent); + + vectorContext.flush(); } }; @@ -89753,3521 +88079,20959 @@ ol.format.JSONFeature.prototype.getObject_ = function(source) { /** * @inheritDoc */ -ol.format.JSONFeature.prototype.getType = function() { - return ol.format.FormatType.JSON; +ol.renderer.webgl.Map.prototype.disposeInternal = function() { + var gl = this.getGL(); + if (!gl.isContextLost()) { + this.textureCache_.forEach( + /** + * @param {?ol.renderer.webgl.TextureCacheEntry} textureCacheEntry + * Texture cache entry. + */ + function(textureCacheEntry) { + if (textureCacheEntry) { + gl.deleteTexture(textureCacheEntry.texture); + } + }); + } + goog.dispose(this.context_); + goog.base(this, 'disposeInternal'); }; /** - * @inheritDoc + * @param {ol.Map} map Map. + * @param {olx.FrameState} frameState Frame state. + * @private */ -ol.format.JSONFeature.prototype.readFeature = function(source, opt_options) { - return this.readFeatureFromObject( - this.getObject_(source), this.getReadOptions(source, opt_options)); +ol.renderer.webgl.Map.prototype.expireCache_ = function(map, frameState) { + var gl = this.getGL(); + var textureCacheEntry; + while (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ > + ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) { + textureCacheEntry = this.textureCache_.peekLast(); + if (!textureCacheEntry) { + if (+this.textureCache_.peekLastKey() == frameState.index) { + break; + } else { + --this.textureCacheFrameMarkerCount_; + } + } else { + gl.deleteTexture(textureCacheEntry.texture); + } + this.textureCache_.pop(); + } }; /** - * @inheritDoc + * @return {ol.webgl.Context} */ -ol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) { - return this.readFeaturesFromObject( - this.getObject_(source), this.getReadOptions(source, opt_options)); +ol.renderer.webgl.Map.prototype.getContext = function() { + return this.context_; }; /** - * @param {Object} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.Feature} Feature. + * @return {WebGLRenderingContext} GL. */ -ol.format.JSONFeature.prototype.readFeatureFromObject = goog.abstractMethod; +ol.renderer.webgl.Map.prototype.getGL = function() { + return this.gl_; +}; /** - * @param {Object} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {Array.<ol.Feature>} Features. + * @return {ol.structs.PriorityQueue.<Array>} Tile texture queue. */ -ol.format.JSONFeature.prototype.readFeaturesFromObject = goog.abstractMethod; +ol.renderer.webgl.Map.prototype.getTileTextureQueue = function() { + return this.tileTextureQueue_; +}; /** * @inheritDoc */ -ol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) { - return this.readGeometryFromObject( - this.getObject_(source), this.getReadOptions(source, opt_options)); +ol.renderer.webgl.Map.prototype.getType = function() { + return ol.RendererType.WEBGL; }; /** - * @param {Object} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. + * @param {goog.events.Event} event Event. * @protected - * @return {ol.geom.Geometry} Geometry. */ -ol.format.JSONFeature.prototype.readGeometryFromObject = goog.abstractMethod; +ol.renderer.webgl.Map.prototype.handleWebGLContextLost = function(event) { + event.preventDefault(); + this.textureCache_.clear(); + this.textureCacheFrameMarkerCount_ = 0; + goog.object.forEach(this.getLayerRenderers(), + /** + * @param {ol.renderer.Layer} layerRenderer Layer renderer. + * @param {string} key Key. + * @param {Object.<string, ol.renderer.Layer>} object Object. + */ + function(layerRenderer, key, object) { + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, + 'renderer is an instance of ol.renderer.webgl.Layer'); + layerRenderer.handleWebGLContextLost(); + }); +}; /** - * @inheritDoc + * @protected */ -ol.format.JSONFeature.prototype.readProjection = function(source) { - return this.readProjectionFromObject(this.getObject_(source)); +ol.renderer.webgl.Map.prototype.handleWebGLContextRestored = function() { + this.initializeGL_(); + this.getMap().render(); }; /** - * @param {Object} object Object. - * @protected - * @return {ol.proj.Projection} Projection. + * @private */ -ol.format.JSONFeature.prototype.readProjectionFromObject = goog.abstractMethod; +ol.renderer.webgl.Map.prototype.initializeGL_ = function() { + var gl = this.gl_; + gl.activeTexture(goog.webgl.TEXTURE0); + gl.blendFuncSeparate( + goog.webgl.SRC_ALPHA, goog.webgl.ONE_MINUS_SRC_ALPHA, + goog.webgl.ONE, goog.webgl.ONE_MINUS_SRC_ALPHA); + gl.disable(goog.webgl.CULL_FACE); + gl.disable(goog.webgl.DEPTH_TEST); + gl.disable(goog.webgl.SCISSOR_TEST); + gl.disable(goog.webgl.STENCIL_TEST); +}; /** - * @inheritDoc + * @param {ol.Tile} tile Tile. + * @return {boolean} Is tile texture loaded. */ -ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) { - return goog.json.serialize(this.writeFeatureObject(feature, opt_options)); +ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) { + return this.textureCache_.containsKey(tile.getKey()); }; /** - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. + * @private + * @type {goog.log.Logger} */ -ol.format.JSONFeature.prototype.writeFeatureObject = goog.abstractMethod; +ol.renderer.webgl.Map.prototype.logger_ = + goog.log.getLogger('ol.renderer.webgl.Map'); /** * @inheritDoc */ -ol.format.JSONFeature.prototype.writeFeatures = function( - features, opt_options) { - return goog.json.serialize(this.writeFeaturesObject(features, opt_options)); -}; +ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { + var context = this.getContext(); + var gl = this.getGL(); -/** - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - */ -ol.format.JSONFeature.prototype.writeFeaturesObject = goog.abstractMethod; + if (gl.isContextLost()) { + return false; + } + if (!frameState) { + if (this.renderedVisible_) { + goog.style.setElementShown(this.canvas_, false); + this.renderedVisible_ = false; + } + return false; + } -/** - * @inheritDoc - */ -ol.format.JSONFeature.prototype.writeGeometry = function( - geometry, opt_options) { - return goog.json.serialize(this.writeGeometryObject(geometry, opt_options)); -}; + this.focus_ = frameState.focus; + this.textureCache_.set((-frameState.index).toString(), null); + ++this.textureCacheFrameMarkerCount_; -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - */ -ol.format.JSONFeature.prototype.writeGeometryObject = goog.abstractMethod; + this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); -goog.provide('ol.geom.flat.interpolate'); + /** @type {Array.<ol.layer.LayerState>} */ + var layerStatesToDraw = []; + var layerStatesArray = frameState.layerStatesArray; + goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.math'); + var viewResolution = frameState.viewState.resolution; + var i, ii, layerRenderer, layerState; + for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { + layerState = layerStatesArray[i]; + if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) && + layerState.sourceState == ol.source.State.READY) { + layerRenderer = this.getLayerRenderer(layerState.layer); + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, + 'renderer is an instance of ol.renderer.webgl.Layer'); + if (layerRenderer.prepareFrame(frameState, layerState, context)) { + layerStatesToDraw.push(layerState); + } + } + } + var width = frameState.size[0] * frameState.pixelRatio; + var height = frameState.size[1] * frameState.pixelRatio; + if (this.canvas_.width != width || this.canvas_.height != height) { + this.canvas_.width = width; + this.canvas_.height = height; + } -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} fraction Fraction. - * @param {Array.<number>=} opt_dest Destination. - * @return {Array.<number>} Destination. - */ -ol.geom.flat.interpolate.lineString = - function(flatCoordinates, offset, end, stride, fraction, opt_dest) { - // FIXME interpolate extra dimensions - goog.asserts.assert(0 <= fraction && fraction <= 1, - 'fraction should be in between 0 and 1'); - var pointX = NaN; - var pointY = NaN; - var n = (end - offset) / stride; - if (n === 0) { - goog.asserts.fail('n cannot be 0'); - } else if (n == 1) { - pointX = flatCoordinates[offset]; - pointY = flatCoordinates[offset + 1]; - } else if (n == 2) { - pointX = (1 - fraction) * flatCoordinates[offset] + - fraction * flatCoordinates[offset + stride]; - pointY = (1 - fraction) * flatCoordinates[offset + 1] + - fraction * flatCoordinates[offset + stride + 1]; - } else { - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - var length = 0; - var cumulativeLengths = [0]; - var i; - for (i = offset + stride; i < end; i += stride) { - var x2 = flatCoordinates[i]; - var y2 = flatCoordinates[i + 1]; - length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); - cumulativeLengths.push(length); - x1 = x2; - y1 = y2; - } - var target = fraction * length; - var index = goog.array.binarySearch(cumulativeLengths, target); - if (index < 0) { - var t = (target - cumulativeLengths[-index - 2]) / - (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]); - var o = offset + (-index - 2) * stride; - pointX = goog.math.lerp( - flatCoordinates[o], flatCoordinates[o + stride], t); - pointY = goog.math.lerp( - flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t); - } else { - pointX = flatCoordinates[offset + index * stride]; - pointY = flatCoordinates[offset + index * stride + 1]; - } + gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, null); + + gl.clearColor(0, 0, 0, 0); + gl.clear(goog.webgl.COLOR_BUFFER_BIT); + gl.enable(goog.webgl.BLEND); + gl.viewport(0, 0, this.canvas_.width, this.canvas_.height); + + for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) { + layerState = layerStatesToDraw[i]; + layerRenderer = this.getLayerRenderer(layerState.layer); + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer, + 'renderer is an instance of ol.renderer.webgl.Layer'); + layerRenderer.composeFrame(frameState, layerState, context); } - if (opt_dest) { - opt_dest[0] = pointX; - opt_dest[1] = pointY; - return opt_dest; - } else { - return [pointX, pointY]; + + if (!this.renderedVisible_) { + goog.style.setElementShown(this.canvas_, true); + this.renderedVisible_ = true; } + + this.calculateMatrices2D(frameState); + + if (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ > + ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) { + frameState.postRenderFunctions.push(goog.bind(this.expireCache_, this)); + } + + if (!this.tileTextureQueue_.isEmpty()) { + frameState.postRenderFunctions.push(this.loadNextTileTexture_); + frameState.animate = true; + } + + this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState); + + this.scheduleRemoveUnusedLayerRenderers(frameState); + this.scheduleExpireIconCache(frameState); + }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} m M. - * @param {boolean} extrapolate Extrapolate. - * @return {ol.Coordinate} Coordinate. + * @inheritDoc */ -ol.geom.flat.lineStringCoordinateAtM = - function(flatCoordinates, offset, end, stride, m, extrapolate) { - if (end == offset) { - return null; - } - var coordinate; - if (m < flatCoordinates[offset + stride - 1]) { - if (extrapolate) { - coordinate = flatCoordinates.slice(offset, offset + stride); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } - } else if (flatCoordinates[end - 1] < m) { - if (extrapolate) { - coordinate = flatCoordinates.slice(end - stride, end); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } - } - // FIXME use O(1) search - if (m == flatCoordinates[offset + stride - 1]) { - return flatCoordinates.slice(offset, offset + stride); - } - var lo = offset / stride; - var hi = end / stride; - while (lo < hi) { - var mid = (lo + hi) >> 1; - if (m < flatCoordinates[(mid + 1) * stride - 1]) { - hi = mid; - } else { - lo = mid + 1; - } - } - var m0 = flatCoordinates[lo * stride - 1]; - if (m == m0) { - return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride); +ol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate = + function(coordinate, frameState, callback, thisArg, + layerFilter, thisArg2) { + var result; + + if (this.getGL().isContextLost()) { + return false; } - var m1 = flatCoordinates[(lo + 1) * stride - 1]; - goog.asserts.assert(m0 < m, 'm0 should be less than m'); - goog.asserts.assert(m <= m1, 'm should be less than or equal to m1'); - var t = (m - m0) / (m1 - m0); - coordinate = []; + + var viewState = frameState.viewState; + + var layerStates = frameState.layerStatesArray; + var numLayers = layerStates.length; var i; - for (i = 0; i < stride - 1; ++i) { - coordinate.push(goog.math.lerp(flatCoordinates[(lo - 1) * stride + i], - flatCoordinates[lo * stride + i], t)); + for (i = numLayers - 1; i >= 0; --i) { + var layerState = layerStates[i]; + var layer = layerState.layer; + if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && + layerFilter.call(thisArg2, layer)) { + var layerRenderer = this.getLayerRenderer(layer); + result = layerRenderer.forEachFeatureAtCoordinate( + coordinate, frameState, callback, thisArg); + if (result) { + return result; + } + } } - coordinate.push(m); - goog.asserts.assert(coordinate.length == stride, - 'length of coordinate array should match stride'); - return coordinate; + return undefined; }; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<number>} ends Ends. - * @param {number} stride Stride. - * @param {number} m M. - * @param {boolean} extrapolate Extrapolate. - * @param {boolean} interpolate Interpolate. - * @return {ol.Coordinate} Coordinate. + * @inheritDoc */ -ol.geom.flat.lineStringsCoordinateAtM = function( - flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) { - if (interpolate) { - return ol.geom.flat.lineStringCoordinateAtM( - flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate); +ol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate = + function(coordinate, frameState, layerFilter, thisArg) { + var hasFeature = false; + + if (this.getGL().isContextLost()) { + return false; } - var coordinate; - if (m < flatCoordinates[stride - 1]) { - if (extrapolate) { - coordinate = flatCoordinates.slice(0, stride); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; + + var viewState = frameState.viewState; + + var layerStates = frameState.layerStatesArray; + var numLayers = layerStates.length; + var i; + for (i = numLayers - 1; i >= 0; --i) { + var layerState = layerStates[i]; + var layer = layerState.layer; + if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && + layerFilter.call(thisArg, layer)) { + var layerRenderer = this.getLayerRenderer(layer); + hasFeature = + layerRenderer.hasFeatureAtCoordinate(coordinate, frameState); + if (hasFeature) { + return true; + } } } - if (flatCoordinates[flatCoordinates.length - 1] < m) { - if (extrapolate) { - coordinate = flatCoordinates.slice(flatCoordinates.length - stride); - coordinate[stride - 1] = m; - return coordinate; - } else { - return null; - } + return hasFeature; +}; + + +/** + * @inheritDoc + */ +ol.renderer.webgl.Map.prototype.forEachLayerAtPixel = + function(pixel, frameState, callback, thisArg, + layerFilter, thisArg2) { + if (this.getGL().isContextLost()) { + return false; } - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - if (offset == end) { - continue; - } - if (m < flatCoordinates[offset + stride - 1]) { - return null; - } else if (m <= flatCoordinates[end - 1]) { - return ol.geom.flat.lineStringCoordinateAtM( - flatCoordinates, offset, end, stride, m, false); + + var viewState = frameState.viewState; + var result; + + var layerStates = frameState.layerStatesArray; + var numLayers = layerStates.length; + var i; + for (i = numLayers - 1; i >= 0; --i) { + var layerState = layerStates[i]; + var layer = layerState.layer; + if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) && + layerFilter.call(thisArg, layer)) { + var layerRenderer = this.getLayerRenderer(layer); + result = layerRenderer.forEachLayerAtPixel( + pixel, frameState, callback, thisArg); + if (result) { + return result; + } } - offset = end; } - goog.asserts.fail( - 'ol.geom.flat.lineStringsCoordinateAtM should have returned'); - return null; + return undefined; }; -goog.provide('ol.geom.flat.length'); +// FIXME recheck layer/map projection compatibility when projection changes +// FIXME layer renderers should skip when they can't reproject +// FIXME add tilt and height? + +goog.provide('ol.Map'); +goog.provide('ol.MapProperty'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.async.AnimationDelay'); +goog.require('goog.async.nextTick'); +goog.require('goog.debug.Console'); +goog.require('goog.dom'); +goog.require('goog.dom.ViewportSizeMonitor'); +goog.require('goog.dom.classlist'); +goog.require('goog.events'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.events.KeyHandler'); +goog.require('goog.events.KeyHandler.EventType'); +goog.require('goog.events.MouseWheelHandler'); +goog.require('goog.events.MouseWheelHandler.EventType'); +goog.require('goog.functions'); +goog.require('goog.log'); +goog.require('goog.log.Level'); +goog.require('goog.object'); +goog.require('goog.style'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Collection'); +goog.require('ol.CollectionEventType'); +goog.require('ol.MapBrowserEvent'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.MapBrowserEventHandler'); +goog.require('ol.MapEvent'); +goog.require('ol.MapEventType'); +goog.require('ol.Object'); +goog.require('ol.ObjectEvent'); +goog.require('ol.ObjectEventType'); +goog.require('ol.Pixel'); +goog.require('ol.PostRenderFunction'); +goog.require('ol.PreRenderFunction'); +goog.require('ol.RendererType'); +goog.require('ol.Size'); +goog.require('ol.TileQueue'); +goog.require('ol.View'); +goog.require('ol.ViewHint'); +goog.require('ol.control'); +goog.require('ol.extent'); +goog.require('ol.has'); +goog.require('ol.interaction'); +goog.require('ol.layer.Base'); +goog.require('ol.layer.Group'); +goog.require('ol.proj'); +goog.require('ol.proj.common'); +goog.require('ol.renderer.Map'); +goog.require('ol.renderer.canvas.Map'); +goog.require('ol.renderer.dom.Map'); +goog.require('ol.renderer.webgl.Map'); +goog.require('ol.size'); +goog.require('ol.structs.PriorityQueue'); +goog.require('ol.tilecoord'); +goog.require('ol.vec.Mat4'); /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Length. + * @const + * @type {string} */ -ol.geom.flat.length.lineString = - function(flatCoordinates, offset, end, stride) { - var x1 = flatCoordinates[offset]; - var y1 = flatCoordinates[offset + 1]; - var length = 0; - var i; - for (i = offset + stride; i < end; i += stride) { - var x2 = flatCoordinates[i]; - var y2 = flatCoordinates[i + 1]; - length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); - x1 = x2; - y1 = y2; - } - return length; -}; +ol.OL3_URL = 'http://openlayers.org/'; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Perimeter. + * @const + * @type {string} */ -ol.geom.flat.length.linearRing = - function(flatCoordinates, offset, end, stride) { - var perimeter = - ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride); - var dx = flatCoordinates[end - stride] - flatCoordinates[offset]; - var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1]; - perimeter += Math.sqrt(dx * dx + dy * dy); - return perimeter; -}; +ol.OL3_LOGO_URL = 'data:image/png;base64,' + + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBI' + + 'WXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAA' + + 'AhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszW' + + 'WMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvY' + + 'asvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvX' + + 'H1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1Vk' + + 'bMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW' + + '2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLP' + + 'VcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqT' + + 'acrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaar' + + 'ldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+Hi' + + 'zeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDn' + + 'BAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSF' + + 'hYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJ' + + 'REFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxC' + + 'Brb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe' + + '0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8' + + 'a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7a' + + 'hgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCn' + + 'B3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDg' + + 'q82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC'; -goog.provide('ol.geom.LineString'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interpolate'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.length'); -goog.require('ol.geom.flat.segments'); -goog.require('ol.geom.flat.simplify'); +/** + * @type {Array.<ol.RendererType>} + * @const + */ +ol.DEFAULT_RENDERER_TYPES = [ + ol.RendererType.CANVAS, + ol.RendererType.WEBGL, + ol.RendererType.DOM +]; + + +/** + * @enum {string} + */ +ol.MapProperty = { + LAYERGROUP: 'layergroup', + SIZE: 'size', + TARGET: 'target', + VIEW: 'view' +}; /** * @classdesc - * Linestring geometry. + * The map is the core component of OpenLayers. For a map to render, a view, + * one or more layers, and a target container are needed: + * + * var map = new ol.Map({ + * view: new ol.View({ + * center: [0, 0], + * zoom: 1 + * }), + * layers: [ + * new ol.layer.Tile({ + * source: new ol.source.MapQuest({layer: 'osm'}) + * }) + * ], + * target: 'map' + * }); + * + * The above snippet creates a map using a {@link ol.layer.Tile} to display + * {@link ol.source.MapQuest} OSM data and render it to a DOM element with the + * id `map`. + * + * The constructor places a viewport container (with CSS class name + * `ol-viewport`) in the target element (see `getViewport()`), and then two + * further elements within the viewport: one with CSS class name + * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with + * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent` + * option of {@link ol.Overlay} for the difference). The map itself is placed in + * a further element within the viewport, either DOM or Canvas, depending on the + * renderer. + * + * Layers are stored as a `ol.Collection` in layerGroups. A top-level group is + * provided by the library. This is what is accessed by `getLayerGroup` and + * `setLayerGroup`. Layers entered in the options are added to this group, and + * `addLayer` and `removeLayer` change the layer collection in the group. + * `getLayers` is a convenience function for `getLayerGroup().getLayers()`. + * Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers + * entered in the options or added with `addLayer` can be groups, which can + * contain further groups, and so on. * * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @extends {ol.Object} + * @param {olx.MapOptions} options Map options. + * @fires ol.MapBrowserEvent + * @fires ol.MapEvent + * @fires ol.render.Event#postcompose + * @fires ol.render.Event#precompose * @api stable */ -ol.geom.LineString = function(coordinates, opt_layout) { +ol.Map = function(options) { goog.base(this); + var optionsInternal = ol.Map.createOptionsInternal(options); + /** + * @type {boolean} * @private - * @type {ol.Coordinate} */ - this.flatMidpoint_ = null; + this.loadTilesWhileAnimating_ = + options.loadTilesWhileAnimating !== undefined ? + options.loadTilesWhileAnimating : false; /** + * @type {boolean} * @private - * @type {number} */ - this.flatMidpointRevision_ = -1; + this.loadTilesWhileInteracting_ = + options.loadTilesWhileInteracting !== undefined ? + options.loadTilesWhileInteracting : false; /** * @private * @type {number} */ - this.maxDelta_ = -1; + this.pixelRatio_ = options.pixelRatio !== undefined ? + options.pixelRatio : ol.has.DEVICE_PIXEL_RATIO; /** * @private - * @type {number} + * @type {Object.<string, string>} */ - this.maxDeltaRevision_ = -1; + this.logos_ = optionsInternal.logos; - this.setCoordinates(coordinates, opt_layout); + /** + * @private + * @type {goog.async.AnimationDelay} + */ + this.animationDelay_ = + new goog.async.AnimationDelay(this.renderFrame_, undefined, this); + this.registerDisposable(this.animationDelay_); -}; -goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry); + /** + * @private + * @type {goog.vec.Mat4.Number} + */ + this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber(); + /** + * @private + * @type {goog.vec.Mat4.Number} + */ + this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber(); -/** - * Append the passed coordinate to the coordinates of the linestring. - * @param {ol.Coordinate} coordinate Coordinate. - * @api stable - */ -ol.geom.LineString.prototype.appendCoordinate = function(coordinate) { - goog.asserts.assert(coordinate.length == this.stride, - 'length of coordinate array should match stride'); - if (!this.flatCoordinates) { - this.flatCoordinates = coordinate.slice(); - } else { - goog.array.extend(this.flatCoordinates, coordinate); + /** + * @private + * @type {number} + */ + this.frameIndex_ = 0; + + /** + * @private + * @type {?olx.FrameState} + */ + this.frameState_ = null; + + /** + * The extent at the previous 'moveend' event. + * @private + * @type {ol.Extent} + */ + this.previousExtent_ = ol.extent.createEmpty(); + + /** + * @private + * @type {goog.events.Key} + */ + this.viewPropertyListenerKey_ = null; + + /** + * @private + * @type {Array.<goog.events.Key>} + */ + this.layerGroupPropertyListenerKeys_ = null; + + /** + * @private + * @type {Element} + */ + this.viewport_ = goog.dom.createDom('DIV', 'ol-viewport'); + this.viewport_.style.position = 'relative'; + this.viewport_.style.overflow = 'hidden'; + this.viewport_.style.width = '100%'; + this.viewport_.style.height = '100%'; + // prevent page zoom on IE >= 10 browsers + this.viewport_.style.msTouchAction = 'none'; + this.viewport_.style.touchAction = 'none'; + if (ol.has.TOUCH) { + goog.dom.classlist.add(this.viewport_, 'ol-touch'); } - this.changed(); -}; + /** + * @private + * @type {Element} + */ + this.overlayContainer_ = goog.dom.createDom('DIV', + 'ol-overlaycontainer'); + this.viewport_.appendChild(this.overlayContainer_); + + /** + * @private + * @type {Element} + */ + this.overlayContainerStopEvent_ = goog.dom.createDom('DIV', + 'ol-overlaycontainer-stopevent'); + goog.events.listen(this.overlayContainerStopEvent_, [ + goog.events.EventType.CLICK, + goog.events.EventType.DBLCLICK, + goog.events.EventType.MOUSEDOWN, + goog.events.EventType.TOUCHSTART, + goog.events.EventType.MSPOINTERDOWN, + ol.MapBrowserEvent.EventType.POINTERDOWN, + goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel' + ], goog.events.Event.stopPropagation); + this.viewport_.appendChild(this.overlayContainerStopEvent_); + + var mapBrowserEventHandler = new ol.MapBrowserEventHandler(this); + goog.events.listen(mapBrowserEventHandler, + goog.object.getValues(ol.MapBrowserEvent.EventType), + this.handleMapBrowserEvent, false, this); + this.registerDisposable(mapBrowserEventHandler); + + /** + * @private + * @type {Element|Document} + */ + this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget; + + /** + * @private + * @type {goog.events.KeyHandler} + */ + this.keyHandler_ = new goog.events.KeyHandler(); + goog.events.listen(this.keyHandler_, goog.events.KeyHandler.EventType.KEY, + this.handleBrowserEvent, false, this); + this.registerDisposable(this.keyHandler_); + + var mouseWheelHandler = new goog.events.MouseWheelHandler(this.viewport_); + goog.events.listen(mouseWheelHandler, + goog.events.MouseWheelHandler.EventType.MOUSEWHEEL, + this.handleBrowserEvent, false, this); + this.registerDisposable(mouseWheelHandler); + + /** + * @type {ol.Collection.<ol.control.Control>} + * @private + */ + this.controls_ = optionsInternal.controls; + + /** + * @type {ol.Collection.<ol.interaction.Interaction>} + * @private + */ + this.interactions_ = optionsInternal.interactions; + + /** + * @type {ol.Collection.<ol.Overlay>} + * @private + */ + this.overlays_ = optionsInternal.overlays; + + /** + * A lookup of overlays by id. + * @private + * @type {Object.<string, ol.Overlay>} + */ + this.overlayIdIndex_ = {}; + + /** + * @type {ol.renderer.Map} + * @private + */ + this.renderer_ = + new optionsInternal.rendererConstructor(this.viewport_, this); + this.registerDisposable(this.renderer_); + + /** + * @type {goog.dom.ViewportSizeMonitor} + * @private + */ + this.viewportSizeMonitor_ = new goog.dom.ViewportSizeMonitor(); + this.registerDisposable(this.viewportSizeMonitor_); + + /** + * @type {goog.events.Key} + * @private + */ + this.viewportResizeListenerKey_ = null; + + /** + * @private + * @type {ol.Coordinate} + */ + this.focus_ = null; + + /** + * @private + * @type {Array.<ol.PreRenderFunction>} + */ + this.preRenderFunctions_ = []; + + /** + * @private + * @type {Array.<ol.PostRenderFunction>} + */ + this.postRenderFunctions_ = []; + + /** + * @private + * @type {ol.TileQueue} + */ + this.tileQueue_ = new ol.TileQueue( + goog.bind(this.getTilePriority, this), + goog.bind(this.handleTileChange_, this)); + + /** + * Uids of features to skip at rendering time. + * @type {Object.<string, boolean>} + * @private + */ + this.skippedFeatureUids_ = {}; + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.MapProperty.LAYERGROUP), + this.handleLayerGroupChanged_, false, this); + goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.VIEW), + this.handleViewChanged_, false, this); + goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.SIZE), + this.handleSizeChanged_, false, this); + goog.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.TARGET), + this.handleTargetChanged_, false, this); + + // setProperties will trigger the rendering of the map if the map + // is "defined" already. + this.setProperties(optionsInternal.values); + + this.controls_.forEach( + /** + * @param {ol.control.Control} control Control. + * @this {ol.Map} + */ + function(control) { + control.setMap(this); + }, this); + + goog.events.listen(this.controls_, ol.CollectionEventType.ADD, + /** + * @param {ol.CollectionEvent} event Collection event. + */ + function(event) { + event.element.setMap(this); + }, false, this); + + goog.events.listen(this.controls_, ol.CollectionEventType.REMOVE, + /** + * @param {ol.CollectionEvent} event Collection event. + */ + function(event) { + event.element.setMap(null); + }, false, this); + + this.interactions_.forEach( + /** + * @param {ol.interaction.Interaction} interaction Interaction. + * @this {ol.Map} + */ + function(interaction) { + interaction.setMap(this); + }, this); + + goog.events.listen(this.interactions_, ol.CollectionEventType.ADD, + /** + * @param {ol.CollectionEvent} event Collection event. + */ + function(event) { + event.element.setMap(this); + }, false, this); + + goog.events.listen(this.interactions_, ol.CollectionEventType.REMOVE, + /** + * @param {ol.CollectionEvent} event Collection event. + */ + function(event) { + event.element.setMap(null); + }, false, this); + + this.overlays_.forEach(this.addOverlayInternal_, this); + + goog.events.listen(this.overlays_, ol.CollectionEventType.ADD, + /** + * @param {ol.CollectionEvent} event Collection event. + */ + function(event) { + this.addOverlayInternal_(/** @type {ol.Overlay} */ (event.element)); + }, false, this); + + goog.events.listen(this.overlays_, ol.CollectionEventType.REMOVE, + /** + * @param {ol.CollectionEvent} event Collection event. + */ + function(event) { + var id = event.element.getId(); + if (id !== undefined) { + delete this.overlayIdIndex_[id.toString()]; + } + event.element.setMap(null); + }, false, this); -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.LineString} Clone. - * @api stable - */ -ol.geom.LineString.prototype.clone = function() { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return lineString; }; +goog.inherits(ol.Map, ol.Object); /** - * @inheritDoc + * Add the given control to the map. + * @param {ol.control.Control} control Control. + * @api stable */ -ol.geom.LineString.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getClosestPoint( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - this.maxDelta_, false, x, y, closestPoint, minSquaredDistance); +ol.Map.prototype.addControl = function(control) { + var controls = this.getControls(); + goog.asserts.assert(controls !== undefined, 'controls should be defined'); + controls.push(control); }; /** - * Iterate over each segment, calling the provided callback. - * If the callback returns a truthy value the function returns that - * value immediately. Otherwise the function returns `false`. - * - * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function - * called for each segment. - * @param {S=} opt_this The object to be used as the value of 'this' - * within callback. - * @return {T|boolean} Value. - * @template T,S - * @api + * Add the given interaction to the map. + * @param {ol.interaction.Interaction} interaction Interaction to add. + * @api stable */ -ol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) { - return ol.geom.flat.segments.forEach(this.flatCoordinates, 0, - this.flatCoordinates.length, this.stride, callback, opt_this); +ol.Map.prototype.addInteraction = function(interaction) { + var interactions = this.getInteractions(); + goog.asserts.assert(interactions !== undefined, + 'interactions should be defined'); + interactions.push(interaction); }; /** - * Returns the coordinate at `m` using linear interpolation, or `null` if no - * such coordinate exists. - * - * `opt_extrapolate` controls extrapolation beyond the range of Ms in the - * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first - * M will return the first coordinate and Ms greater than the last M will - * return the last coordinate. - * - * @param {number} m M. - * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`. - * @return {ol.Coordinate} Coordinate. + * Adds the given layer to the top of this map. If you want to add a layer + * elsewhere in the stack, use `getLayers()` and the methods available on + * {@link ol.Collection}. + * @param {ol.layer.Base} layer Layer. * @api stable */ -ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) { - if (this.layout != ol.geom.GeometryLayout.XYM && - this.layout != ol.geom.GeometryLayout.XYZM) { - return null; - } - var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false; - return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0, - this.flatCoordinates.length, this.stride, m, extrapolate); +ol.Map.prototype.addLayer = function(layer) { + var layers = this.getLayerGroup().getLayers(); + layers.push(layer); }; /** - * Return the coordinates of the linestring. - * @return {Array.<ol.Coordinate>} Coordinates. + * Add the given overlay to the map. + * @param {ol.Overlay} overlay Overlay. * @api stable */ -ol.geom.LineString.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); +ol.Map.prototype.addOverlay = function(overlay) { + var overlays = this.getOverlays(); + goog.asserts.assert(overlays !== undefined, 'overlays should be defined'); + overlays.push(overlay); }; /** - * Return the length of the linestring on projected plane. - * @return {number} Length (on projected plane). - * @api stable + * This deals with map's overlay collection changes. + * @param {ol.Overlay} overlay Overlay. + * @private */ -ol.geom.LineString.prototype.getLength = function() { - return ol.geom.flat.length.lineString( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); +ol.Map.prototype.addOverlayInternal_ = function(overlay) { + var id = overlay.getId(); + if (id !== undefined) { + this.overlayIdIndex_[id.toString()] = overlay; + } + overlay.setMap(this); }; /** - * @return {Array.<number>} Flat midpoint. + * Add functions to be called before rendering. This can be used for attaching + * animations before updating the map's view. The {@link ol.animation} + * namespace provides several static methods for creating prerender functions. + * @param {...ol.PreRenderFunction} var_args Any number of pre-render functions. + * @api */ -ol.geom.LineString.prototype.getFlatMidpoint = function() { - if (this.flatMidpointRevision_ != this.getRevision()) { - this.flatMidpoint_ = ol.geom.flat.interpolate.lineString( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - 0.5, this.flatMidpoint_); - this.flatMidpointRevision_ = this.getRevision(); - } - return this.flatMidpoint_; +ol.Map.prototype.beforeRender = function(var_args) { + this.render(); + Array.prototype.push.apply(this.preRenderFunctions_, arguments); }; /** - * @inheritDoc + * @param {ol.PreRenderFunction} preRenderFunction Pre-render function. + * @return {boolean} Whether the preRenderFunction has been found and removed. */ -ol.geom.LineString.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - squaredTolerance, simplifiedFlatCoordinates, 0); - var simplifiedLineString = new ol.geom.LineString(null); - simplifiedLineString.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates); - return simplifiedLineString; +ol.Map.prototype.removePreRenderFunction = function(preRenderFunction) { + return goog.array.remove(this.preRenderFunctions_, preRenderFunction); }; /** + * * @inheritDoc - * @api stable */ -ol.geom.LineString.prototype.getType = function() { - return ol.geom.GeometryType.LINE_STRING; +ol.Map.prototype.disposeInternal = function() { + goog.dom.removeNode(this.viewport_); + goog.base(this, 'disposeInternal'); }; /** - * @inheritDoc + * Detect features that intersect a pixel on the viewport, and execute a + * callback with each intersecting feature. Layers included in the detection can + * be configured through `opt_layerFilter`. + * @param {ol.Pixel} pixel Pixel. + * @param {function(this: S, (ol.Feature|ol.render.Feature), + * ol.layer.Layer): T} callback Feature callback. The callback will be + * called with two arguments. The first argument is one + * {@link ol.Feature feature} or + * {@link ol.render.Feature render feature} at the pixel, the second is + * the {@link ol.layer.Layer layer} of the feature and will be null for + * unmanaged layers. To stop detection, callback functions can return a + * truthy value. + * @param {S=} opt_this Value to use as `this` when executing `callback`. + * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer + * filter function. The filter function will receive one argument, the + * {@link ol.layer.Layer layer-candidate} and it should return a boolean + * value. Only layers which are visible and for which this function returns + * `true` will be tested for features. By default, all visible layers will + * be tested. + * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`. + * @return {T|undefined} Callback result, i.e. the return value of last + * callback execution, or the first truthy callback return value. + * @template S,T,U * @api stable */ -ol.geom.LineString.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.lineString( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, - extent); +ol.Map.prototype.forEachFeatureAtPixel = + function(pixel, callback, opt_this, opt_layerFilter, opt_this2) { + if (!this.frameState_) { + return; + } + var coordinate = this.getCoordinateFromPixel(pixel); + var thisArg = opt_this !== undefined ? opt_this : null; + var layerFilter = opt_layerFilter !== undefined ? + opt_layerFilter : goog.functions.TRUE; + var thisArg2 = opt_this2 !== undefined ? opt_this2 : null; + return this.renderer_.forEachFeatureAtCoordinate( + coordinate, this.frameState_, callback, thisArg, + layerFilter, thisArg2); }; /** - * Set the coordinates of the linestring. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * Detect layers that have a color value at a pixel on the viewport, and + * execute a callback with each matching layer. Layers included in the + * detection can be configured through `opt_layerFilter`. + * @param {ol.Pixel} pixel Pixel. + * @param {function(this: S, ol.layer.Layer): T} callback Layer + * callback. Will receive one argument, the {@link ol.layer.Layer layer} + * that contains the color pixel. To stop detection, callback functions can + * return a truthy value. + * @param {S=} opt_this Value to use as `this` when executing `callback`. + * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer + * filter function. The filter function will receive one argument, the + * {@link ol.layer.Layer layer-candidate} and it should return a boolean + * value. Only layers which are visible and for which this function returns + * `true` will be tested for features. By default, all visible layers will + * be tested. + * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`. + * @return {T|undefined} Callback result, i.e. the return value of last + * callback execution, or the first truthy callback return value. + * @template S,T,U * @api stable */ -ol.geom.LineString.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 1); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); +ol.Map.prototype.forEachLayerAtPixel = + function(pixel, callback, opt_this, opt_layerFilter, opt_this2) { + if (!this.frameState_) { + return; } + var thisArg = opt_this !== undefined ? opt_this : null; + var layerFilter = opt_layerFilter !== undefined ? + opt_layerFilter : goog.functions.TRUE; + var thisArg2 = opt_this2 !== undefined ? opt_this2 : null; + return this.renderer_.forEachLayerAtPixel( + pixel, this.frameState_, callback, thisArg, + layerFilter, thisArg2); }; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. + * Detect if features intersect a pixel on the viewport. Layers included in the + * detection can be configured through `opt_layerFilter`. + * @param {ol.Pixel} pixel Pixel. + * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer + * filter function. The filter function will receive one argument, the + * {@link ol.layer.Layer layer-candidate} and it should return a boolean + * value. Only layers which are visible and for which this function returns + * `true` will be tested for features. By default, all visible layers will + * be tested. + * @param {U=} opt_this Value to use as `this` when executing `layerFilter`. + * @return {boolean} Is there a feature at the given pixel? + * @template U + * @api */ -ol.geom.LineString.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); +ol.Map.prototype.hasFeatureAtPixel = + function(pixel, opt_layerFilter, opt_this) { + if (!this.frameState_) { + return false; + } + var coordinate = this.getCoordinateFromPixel(pixel); + var layerFilter = opt_layerFilter !== undefined ? + opt_layerFilter : goog.functions.TRUE; + var thisArg = opt_this !== undefined ? opt_this : null; + return this.renderer_.hasFeatureAtCoordinate( + coordinate, this.frameState_, layerFilter, thisArg); }; -goog.provide('ol.geom.MultiLineString'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interpolate'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.simplify'); - - /** - * @classdesc - * Multi-linestring geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * Returns the geographical coordinate for a browser event. + * @param {Event} event Event. + * @return {ol.Coordinate} Coordinate. * @api stable */ -ol.geom.MultiLineString = function(coordinates, opt_layout) { +ol.Map.prototype.getEventCoordinate = function(event) { + return this.getCoordinateFromPixel(this.getEventPixel(event)); +}; - goog.base(this); - /** - * @type {Array.<number>} - * @private - */ - this.ends_ = []; +/** + * Returns the map pixel position for a browser event relative to the viewport. + * @param {Event} event Event. + * @return {ol.Pixel} Pixel. + * @api stable + */ +ol.Map.prototype.getEventPixel = function(event) { + var eventPosition = goog.style.getRelativePosition(event, this.viewport_); + return [eventPosition.x, eventPosition.y]; +}; - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; +/** + * Get the target in which this map is rendered. + * Note that this returns what is entered as an option or in setTarget: + * if that was an element, it returns an element; if a string, it returns that. + * @return {Element|string|undefined} The Element or id of the Element that the + * map is rendered in. + * @observable + * @api stable + */ +ol.Map.prototype.getTarget = function() { + return /** @type {Element|string|undefined} */ ( + this.get(ol.MapProperty.TARGET)); +}; - this.setCoordinates(coordinates, opt_layout); +/** + * Get the DOM element into which this map is rendered. In contrast to + * `getTarget` this method always return an `Element`, or `null` if the + * map has no target. + * @return {Element} The element that the map is rendered in. + * @api + */ +ol.Map.prototype.getTargetElement = function() { + var target = this.getTarget(); + return target !== undefined ? goog.dom.getElement(target) : null; }; -goog.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry); /** - * Append the passed linestring to the multilinestring. - * @param {ol.geom.LineString} lineString LineString. + * Get the coordinate for a given pixel. This returns a coordinate in the + * map view projection. + * @param {ol.Pixel} pixel Pixel position in the map viewport. + * @return {ol.Coordinate} The coordinate for the pixel position. * @api stable */ -ol.geom.MultiLineString.prototype.appendLineString = function(lineString) { - goog.asserts.assert(lineString.getLayout() == this.layout, - 'layout of lineString should match the layout'); - if (!this.flatCoordinates) { - this.flatCoordinates = lineString.getFlatCoordinates().slice(); +ol.Map.prototype.getCoordinateFromPixel = function(pixel) { + var frameState = this.frameState_; + if (!frameState) { + return null; } else { - goog.array.extend( - this.flatCoordinates, lineString.getFlatCoordinates().slice()); + var vec2 = pixel.slice(); + return ol.vec.Mat4.multVec2(frameState.pixelToCoordinateMatrix, vec2, vec2); } - this.ends_.push(this.flatCoordinates.length); - this.changed(); }; /** - * Make a complete copy of the geometry. - * @return {!ol.geom.MultiLineString} Clone. + * Get the map controls. Modifying this collection changes the controls + * associated with the map. + * @return {ol.Collection.<ol.control.Control>} Controls. * @api stable */ -ol.geom.MultiLineString.prototype.clone = function() { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(), this.ends_.slice()); - return multiLineString; +ol.Map.prototype.getControls = function() { + return this.controls_; }; /** - * @inheritDoc + * Get the map overlays. Modifying this collection changes the overlays + * associated with the map. + * @return {ol.Collection.<ol.Overlay>} Overlays. + * @api stable */ -ol.geom.MultiLineString.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta( - this.flatCoordinates, 0, this.ends_, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getsClosestPoint( - this.flatCoordinates, 0, this.ends_, this.stride, - this.maxDelta_, false, x, y, closestPoint, minSquaredDistance); +ol.Map.prototype.getOverlays = function() { + return this.overlays_; }; /** - * Returns the coordinate at `m` using linear interpolation, or `null` if no - * such coordinate exists. - * - * `opt_extrapolate` controls extrapolation beyond the range of Ms in the - * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first - * M will return the first coordinate and Ms greater than the last M will - * return the last coordinate. - * - * `opt_interpolate` controls interpolation between consecutive LineStrings - * within the MultiLineString. If `opt_interpolate` is `true` the coordinates - * will be linearly interpolated between the last coordinate of one LineString - * and the first coordinate of the next LineString. If `opt_interpolate` is - * `false` then the function will return `null` for Ms falling between - * LineStrings. + * Get an overlay by its identifier (the value returned by overlay.getId()). + * Note that the index treats string and numeric identifiers as the same. So + * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`. + * @param {string|number} id Overlay identifier. + * @return {ol.Overlay} Overlay. + * @api + */ +ol.Map.prototype.getOverlayById = function(id) { + var overlay = this.overlayIdIndex_[id.toString()]; + return overlay !== undefined ? overlay : null; +}; + + +/** + * Get the map interactions. Modifying this collection changes the interactions + * associated with the map. * - * @param {number} m M. - * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`. - * @param {boolean=} opt_interpolate Interpolate. Default is `false`. - * @return {ol.Coordinate} Coordinate. + * Interactions are used for e.g. pan, zoom and rotate. + * @return {ol.Collection.<ol.interaction.Interaction>} Interactions. * @api stable */ -ol.geom.MultiLineString.prototype.getCoordinateAtM = - function(m, opt_extrapolate, opt_interpolate) { - if ((this.layout != ol.geom.GeometryLayout.XYM && - this.layout != ol.geom.GeometryLayout.XYZM) || - this.flatCoordinates.length === 0) { - return null; - } - var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false; - var interpolate = opt_interpolate !== undefined ? opt_interpolate : false; - return ol.geom.flat.lineStringsCoordinateAtM(this.flatCoordinates, 0, - this.ends_, this.stride, m, extrapolate, interpolate); +ol.Map.prototype.getInteractions = function() { + return this.interactions_; }; /** - * Return the coordinates of the multilinestring. - * @return {Array.<Array.<ol.Coordinate>>} Coordinates. + * Get the layergroup associated with this map. + * @return {ol.layer.Group} A layer group containing the layers in this map. + * @observable * @api stable */ -ol.geom.MultiLineString.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinatess( - this.flatCoordinates, 0, this.ends_, this.stride); +ol.Map.prototype.getLayerGroup = function() { + return /** @type {ol.layer.Group} */ (this.get(ol.MapProperty.LAYERGROUP)); }; /** - * @return {Array.<number>} Ends. + * Get the collection of layers associated with this map. + * @return {!ol.Collection.<ol.layer.Base>} Layers. + * @api stable */ -ol.geom.MultiLineString.prototype.getEnds = function() { - return this.ends_; +ol.Map.prototype.getLayers = function() { + var layers = this.getLayerGroup().getLayers(); + return layers; }; /** - * Return the linestring at the specified index. - * @param {number} index Index. - * @return {ol.geom.LineString} LineString. + * Get the pixel for a coordinate. This takes a coordinate in the map view + * projection and returns the corresponding pixel. + * @param {ol.Coordinate} coordinate A map coordinate. + * @return {ol.Pixel} A pixel position in the map viewport. * @api stable */ -ol.geom.MultiLineString.prototype.getLineString = function(index) { - goog.asserts.assert(0 <= index && index < this.ends_.length, - 'index should be in between 0 and length of the this.ends_ array'); - if (index < 0 || this.ends_.length <= index) { +ol.Map.prototype.getPixelFromCoordinate = function(coordinate) { + var frameState = this.frameState_; + if (!frameState) { return null; + } else { + var vec2 = coordinate.slice(0, 2); + return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2); } - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice( - index === 0 ? 0 : this.ends_[index - 1], this.ends_[index])); - return lineString; }; /** - * Return the linestrings of this multilinestring. - * @return {Array.<ol.geom.LineString>} LineStrings. - * @api stable + * Get the map renderer. + * @return {ol.renderer.Map} Renderer */ -ol.geom.MultiLineString.prototype.getLineStrings = function() { - var flatCoordinates = this.flatCoordinates; - var ends = this.ends_; - var layout = this.layout; - /** @type {Array.<ol.geom.LineString>} */ - var lineStrings = []; - var offset = 0; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end)); - lineStrings.push(lineString); - offset = end; - } - return lineStrings; +ol.Map.prototype.getRenderer = function() { + return this.renderer_; }; /** - * @return {Array.<number>} Flat midpoints. + * Get the size of this map. + * @return {ol.Size|undefined} The size in pixels of the map in the DOM. + * @observable + * @api stable */ -ol.geom.MultiLineString.prototype.getFlatMidpoints = function() { - var midpoints = []; - var flatCoordinates = this.flatCoordinates; - var offset = 0; - var ends = this.ends_; - var stride = this.stride; - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - var end = ends[i]; - var midpoint = ol.geom.flat.interpolate.lineString( - flatCoordinates, offset, end, stride, 0.5); - goog.array.extend(midpoints, midpoint); - offset = end; - } - return midpoints; +ol.Map.prototype.getSize = function() { + return /** @type {ol.Size|undefined} */ (this.get(ol.MapProperty.SIZE)); }; /** - * @inheritDoc + * Get the view associated with this map. A view manages properties such as + * center and resolution. + * @return {ol.View} The view that controls this map. + * @observable + * @api stable */ -ol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - var simplifiedEnds = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers( - this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance, - simplifiedFlatCoordinates, 0, simplifiedEnds); - var simplifiedMultiLineString = new ol.geom.MultiLineString(null); - simplifiedMultiLineString.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds); - return simplifiedMultiLineString; +ol.Map.prototype.getView = function() { + return /** @type {ol.View} */ (this.get(ol.MapProperty.VIEW)); }; /** - * @inheritDoc + * Get the element that serves as the map viewport. + * @return {Element} Viewport. * @api stable */ -ol.geom.MultiLineString.prototype.getType = function() { - return ol.geom.GeometryType.MULTI_LINE_STRING; +ol.Map.prototype.getViewport = function() { + return this.viewport_; }; /** - * @inheritDoc - * @api stable + * Get the element that serves as the container for overlays. Elements added to + * this container will let mousedown and touchstart events through to the map, + * so clicks and gestures on an overlay will trigger {@link ol.MapBrowserEvent} + * events. + * @return {Element} The map's overlay container. */ -ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.lineStrings( - this.flatCoordinates, 0, this.ends_, this.stride, extent); +ol.Map.prototype.getOverlayContainer = function() { + return this.overlayContainer_; }; /** - * Set the coordinates of the multilinestring. - * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * Get the element that serves as a container for overlays that don't allow + * event propagation. Elements added to this container won't let mousedown and + * touchstart events through to the map, so clicks and gestures on an overlay + * don't trigger any {@link ol.MapBrowserEvent}. + * @return {Element} The map's overlay container that stops events. */ -ol.geom.MultiLineString.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_); - } else { - this.setLayout(opt_layout, coordinates, 2); - if (!this.flatCoordinates) { - this.flatCoordinates = []; +ol.Map.prototype.getOverlayContainerStopEvent = function() { + return this.overlayContainerStopEvent_; +}; + + +/** + * @param {ol.Tile} tile Tile. + * @param {string} tileSourceKey Tile source key. + * @param {ol.Coordinate} tileCenter Tile center. + * @param {number} tileResolution Tile resolution. + * @return {number} Tile priority. + */ +ol.Map.prototype.getTilePriority = + function(tile, tileSourceKey, tileCenter, tileResolution) { + // Filter out tiles at higher zoom levels than the current zoom level, or that + // are outside the visible extent. + var frameState = this.frameState_; + if (!frameState || !(tileSourceKey in frameState.wantedTiles)) { + return ol.structs.PriorityQueue.DROP; + } + var coordKey = ol.tilecoord.toString(tile.tileCoord); + if (!frameState.wantedTiles[tileSourceKey][coordKey]) { + return ol.structs.PriorityQueue.DROP; + } + // Prioritize the highest zoom level tiles closest to the focus. + // Tiles at higher zoom levels are prioritized using Math.log(tileResolution). + // Within a zoom level, tiles are prioritized by the distance in pixels + // between the center of the tile and the focus. The factor of 65536 means + // that the prioritization should behave as desired for tiles up to + // 65536 * Math.log(2) = 45426 pixels from the focus. + var deltaX = tileCenter[0] - frameState.focus[0]; + var deltaY = tileCenter[1] - frameState.focus[1]; + return 65536 * Math.log(tileResolution) + + Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution; +}; + + +/** + * @param {goog.events.BrowserEvent} browserEvent Browser event. + * @param {string=} opt_type Type. + */ +ol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) { + var type = opt_type || browserEvent.type; + var mapBrowserEvent = new ol.MapBrowserEvent(type, this, browserEvent); + this.handleMapBrowserEvent(mapBrowserEvent); +}; + + +/** + * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle. + */ +ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) { + if (!this.frameState_) { + // With no view defined, we cannot translate pixels into geographical + // coordinates so interactions cannot be used. + return; + } + this.focus_ = mapBrowserEvent.coordinate; + mapBrowserEvent.frameState = this.frameState_; + var interactions = this.getInteractions(); + goog.asserts.assert(interactions !== undefined, + 'interactions should be defined'); + var interactionsArray = interactions.getArray(); + var i; + if (this.dispatchEvent(mapBrowserEvent) !== false) { + for (i = interactionsArray.length - 1; i >= 0; i--) { + var interaction = interactionsArray[i]; + if (!interaction.getActive()) { + continue; + } + var cont = interaction.handleEvent(mapBrowserEvent); + if (!cont) { + break; + } } - var ends = ol.geom.flat.deflate.coordinatess( - this.flatCoordinates, 0, coordinates, this.stride, this.ends_); - this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; - this.changed(); } }; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Array.<number>} ends Ends. + * @protected */ -ol.geom.MultiLineString.prototype.setFlatCoordinates = - function(layout, flatCoordinates, ends) { - if (!flatCoordinates) { - goog.asserts.assert(ends && ends.length === 0, - 'ends must be truthy and ends.length should be 0'); - } else if (ends.length === 0) { - goog.asserts.assert(flatCoordinates.length === 0, - 'flatCoordinates should be an empty array'); - } else { - goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], - 'length of flatCoordinates array should match the last value of ends'); +ol.Map.prototype.handlePostRender = function() { + + var frameState = this.frameState_; + + // Manage the tile queue + // Image loads are expensive and a limited resource, so try to use them + // efficiently: + // * When the view is static we allow a large number of parallel tile loads + // to complete the frame as quickly as possible. + // * When animating or interacting, image loads can cause janks, so we reduce + // the maximum number of loads per frame and limit the number of parallel + // tile loads to remain reactive to view changes and to reduce the chance of + // loading tiles that will quickly disappear from view. + var tileQueue = this.tileQueue_; + if (!tileQueue.isEmpty()) { + var maxTotalLoading = 16; + var maxNewLoads = maxTotalLoading; + var tileSourceCount = 0; + if (frameState) { + var hints = frameState.viewHints; + if (hints[ol.ViewHint.ANIMATING]) { + maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0; + maxNewLoads = 2; + } + if (hints[ol.ViewHint.INTERACTING]) { + maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0; + maxNewLoads = 2; + } + tileSourceCount = goog.object.getCount(frameState.wantedTiles); + } + maxTotalLoading *= tileSourceCount; + maxNewLoads *= tileSourceCount; + if (tileQueue.getTilesLoading() < maxTotalLoading) { + tileQueue.reprioritize(); // FIXME only call if view has changed + tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); + } + } + + var postRenderFunctions = this.postRenderFunctions_; + var i, ii; + for (i = 0, ii = postRenderFunctions.length; i < ii; ++i) { + postRenderFunctions[i](this, frameState); + } + postRenderFunctions.length = 0; +}; + + +/** + * @private + */ +ol.Map.prototype.handleSizeChanged_ = function() { + this.render(); +}; + + +/** + * @private + */ +ol.Map.prototype.handleTargetChanged_ = function() { + // target may be undefined, null, a string or an Element. + // If it's a string we convert it to an Element before proceeding. + // If it's not now an Element we remove the viewport from the DOM. + // If it's an Element we append the viewport element to it. + + var targetElement = this.getTargetElement(); + + this.keyHandler_.detach(); + + if (!targetElement) { + goog.dom.removeNode(this.viewport_); + if (this.viewportResizeListenerKey_) { + goog.events.unlistenByKey(this.viewportResizeListenerKey_); + this.viewportResizeListenerKey_ = null; + } + } else { + targetElement.appendChild(this.viewport_); + + var keyboardEventTarget = !this.keyboardEventTarget_ ? + targetElement : this.keyboardEventTarget_; + this.keyHandler_.attach(keyboardEventTarget); + + if (!this.viewportResizeListenerKey_) { + this.viewportResizeListenerKey_ = goog.events.listen( + this.viewportSizeMonitor_, goog.events.EventType.RESIZE, + this.updateSize, false, this); + } + } + + this.updateSize(); + // updateSize calls setSize, so no need to call this.render + // ourselves here. +}; + + +/** + * @private + */ +ol.Map.prototype.handleTileChange_ = function() { + this.render(); +}; + + +/** + * @private + */ +ol.Map.prototype.handleViewPropertyChanged_ = function() { + this.render(); +}; + + +/** + * @private + */ +ol.Map.prototype.handleViewChanged_ = function() { + if (this.viewPropertyListenerKey_) { + goog.events.unlistenByKey(this.viewPropertyListenerKey_); + this.viewPropertyListenerKey_ = null; + } + var view = this.getView(); + if (view) { + this.viewPropertyListenerKey_ = goog.events.listen( + view, ol.ObjectEventType.PROPERTYCHANGE, + this.handleViewPropertyChanged_, false, this); + } + this.render(); +}; + + +/** + * @param {goog.events.Event} event Event. + * @private + */ +ol.Map.prototype.handleLayerGroupMemberChanged_ = function(event) { + goog.asserts.assertInstanceof(event, goog.events.Event, + 'event should be an Event'); + this.render(); +}; + + +/** + * @param {ol.ObjectEvent} event Event. + * @private + */ +ol.Map.prototype.handleLayerGroupPropertyChanged_ = function(event) { + goog.asserts.assertInstanceof(event, ol.ObjectEvent, + 'event should be an ol.ObjectEvent'); + this.render(); +}; + + +/** + * @private + */ +ol.Map.prototype.handleLayerGroupChanged_ = function() { + if (this.layerGroupPropertyListenerKeys_) { + this.layerGroupPropertyListenerKeys_.forEach(goog.events.unlistenByKey); + this.layerGroupPropertyListenerKeys_ = null; + } + var layerGroup = this.getLayerGroup(); + if (layerGroup) { + this.layerGroupPropertyListenerKeys_ = [ + goog.events.listen( + layerGroup, ol.ObjectEventType.PROPERTYCHANGE, + this.handleLayerGroupPropertyChanged_, false, this), + goog.events.listen( + layerGroup, goog.events.EventType.CHANGE, + this.handleLayerGroupMemberChanged_, false, this) + ]; + } + this.render(); +}; + + +/** + * Returns `true` if the map is defined, `false` otherwise. The map is defined + * if it is contained in `document`, visible, has non-zero height and width, and + * has a defined view. + * @return {boolean} Is defined. + */ +ol.Map.prototype.isDef = function() { + if (!goog.dom.contains(document, this.viewport_)) { + return false; + } + if (!goog.style.isElementShown(this.viewport_)) { + return false; + } + var size = this.getSize(); + if (!size || size[0] <= 0 || size[1] <= 0) { + return false; + } + var view = this.getView(); + if (!view || !view.isDef()) { + return false; + } + return true; +}; + + +/** + * @return {boolean} Is rendered. + */ +ol.Map.prototype.isRendered = function() { + return !!this.frameState_; +}; + + +/** + * Requests an immediate render in a synchronous manner. + * @api stable + */ +ol.Map.prototype.renderSync = function() { + this.animationDelay_.fire(); +}; + + +/** + * Request a map rendering (at the next animation frame). + * @api stable + */ +ol.Map.prototype.render = function() { + if (!this.animationDelay_.isActive()) { + this.animationDelay_.start(); + } +}; + + +/** + * Remove the given control from the map. + * @param {ol.control.Control} control Control. + * @return {ol.control.Control|undefined} The removed control (or undefined + * if the control was not found). + * @api stable + */ +ol.Map.prototype.removeControl = function(control) { + var controls = this.getControls(); + goog.asserts.assert(controls !== undefined, 'controls should be defined'); + return controls.remove(control); +}; + + +/** + * Remove the given interaction from the map. + * @param {ol.interaction.Interaction} interaction Interaction to remove. + * @return {ol.interaction.Interaction|undefined} The removed interaction (or + * undefined if the interaction was not found). + * @api stable + */ +ol.Map.prototype.removeInteraction = function(interaction) { + var interactions = this.getInteractions(); + goog.asserts.assert(interactions !== undefined, + 'interactions should be defined'); + return interactions.remove(interaction); +}; + + +/** + * Removes the given layer from the map. + * @param {ol.layer.Base} layer Layer. + * @return {ol.layer.Base|undefined} The removed layer (or undefined if the + * layer was not found). + * @api stable + */ +ol.Map.prototype.removeLayer = function(layer) { + var layers = this.getLayerGroup().getLayers(); + return layers.remove(layer); +}; + + +/** + * Remove the given overlay from the map. + * @param {ol.Overlay} overlay Overlay. + * @return {ol.Overlay|undefined} The removed overlay (or undefined + * if the overlay was not found). + * @api stable + */ +ol.Map.prototype.removeOverlay = function(overlay) { + var overlays = this.getOverlays(); + goog.asserts.assert(overlays !== undefined, 'overlays should be defined'); + return overlays.remove(overlay); +}; + + +/** + * @param {number} time Time. + * @private + */ +ol.Map.prototype.renderFrame_ = function(time) { + + var i, ii, viewState; + + var size = this.getSize(); + var view = this.getView(); + /** @type {?olx.FrameState} */ + var frameState = null; + if (size !== undefined && ol.size.hasArea(size) && + view && view.isDef()) { + var viewHints = view.getHints(); + var layerStatesArray = this.getLayerGroup().getLayerStatesArray(); + var layerStates = {}; + for (i = 0, ii = layerStatesArray.length; i < ii; ++i) { + layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i]; + } + viewState = view.getState(); + frameState = /** @type {olx.FrameState} */ ({ + animate: false, + attributions: {}, + coordinateToPixelMatrix: this.coordinateToPixelMatrix_, + extent: null, + focus: !this.focus_ ? viewState.center : this.focus_, + index: this.frameIndex_++, + layerStates: layerStates, + layerStatesArray: layerStatesArray, + logos: goog.object.clone(this.logos_), + pixelRatio: this.pixelRatio_, + pixelToCoordinateMatrix: this.pixelToCoordinateMatrix_, + postRenderFunctions: [], + size: size, + skippedFeatureUids: this.skippedFeatureUids_, + tileQueue: this.tileQueue_, + time: time, + usedTiles: {}, + viewState: viewState, + viewHints: viewHints, + wantedTiles: {} + }); + } + + if (frameState) { + var preRenderFunctions = this.preRenderFunctions_; + var n = 0, preRenderFunction; + for (i = 0, ii = preRenderFunctions.length; i < ii; ++i) { + preRenderFunction = preRenderFunctions[i]; + if (preRenderFunction(this, frameState)) { + preRenderFunctions[n++] = preRenderFunction; + } + } + preRenderFunctions.length = n; + + frameState.extent = ol.extent.getForViewAndSize(viewState.center, + viewState.resolution, viewState.rotation, frameState.size); + } + + this.frameState_ = frameState; + this.renderer_.renderFrame(frameState); + + if (frameState) { + if (frameState.animate) { + this.render(); + } + Array.prototype.push.apply( + this.postRenderFunctions_, frameState.postRenderFunctions); + + var idle = this.preRenderFunctions_.length === 0 && + !frameState.viewHints[ol.ViewHint.ANIMATING] && + !frameState.viewHints[ol.ViewHint.INTERACTING] && + !ol.extent.equals(frameState.extent, this.previousExtent_); + + if (idle) { + this.dispatchEvent( + new ol.MapEvent(ol.MapEventType.MOVEEND, this, frameState)); + ol.extent.clone(frameState.extent, this.previousExtent_); + } + } + + this.dispatchEvent( + new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState)); + + goog.async.nextTick(this.handlePostRender, this); + +}; + + +/** + * Sets the layergroup of this map. + * @param {ol.layer.Group} layerGroup A layer group containing the layers in + * this map. + * @observable + * @api stable + */ +ol.Map.prototype.setLayerGroup = function(layerGroup) { + this.set(ol.MapProperty.LAYERGROUP, layerGroup); +}; + + +/** + * Set the size of this map. + * @param {ol.Size|undefined} size The size in pixels of the map in the DOM. + * @observable + * @api + */ +ol.Map.prototype.setSize = function(size) { + this.set(ol.MapProperty.SIZE, size); +}; + + +/** + * Set the target element to render this map into. + * @param {Element|string|undefined} target The Element or id of the Element + * that the map is rendered in. + * @observable + * @api stable + */ +ol.Map.prototype.setTarget = function(target) { + this.set(ol.MapProperty.TARGET, target); +}; + + +/** + * Set the view for this map. + * @param {ol.View} view The view that controls this map. + * @observable + * @api stable + */ +ol.Map.prototype.setView = function(view) { + this.set(ol.MapProperty.VIEW, view); +}; + + +/** + * @param {ol.Feature} feature Feature. + */ +ol.Map.prototype.skipFeature = function(feature) { + var featureUid = goog.getUid(feature).toString(); + this.skippedFeatureUids_[featureUid] = true; + this.render(); +}; + + +/** + * Force a recalculation of the map viewport size. This should be called when + * third-party code changes the size of the map viewport. + * @api stable + */ +ol.Map.prototype.updateSize = function() { + var targetElement = this.getTargetElement(); + + if (!targetElement) { + this.setSize(undefined); + } else { + var size = goog.style.getContentBoxSize(targetElement); + this.setSize([size.width, size.height]); + } +}; + + +/** + * @param {ol.Feature} feature Feature. + */ +ol.Map.prototype.unskipFeature = function(feature) { + var featureUid = goog.getUid(feature).toString(); + delete this.skippedFeatureUids_[featureUid]; + this.render(); +}; + + +/** + * @typedef {{controls: ol.Collection.<ol.control.Control>, + * interactions: ol.Collection.<ol.interaction.Interaction>, + * keyboardEventTarget: (Element|Document), + * logos: Object.<string, string>, + * overlays: ol.Collection.<ol.Overlay>, + * rendererConstructor: + * function(new: ol.renderer.Map, Element, ol.Map), + * values: Object.<string, *>}} + */ +ol.MapOptionsInternal; + + +/** + * @param {olx.MapOptions} options Map options. + * @return {ol.MapOptionsInternal} Internal map options. + */ +ol.Map.createOptionsInternal = function(options) { + + /** + * @type {Element|Document} + */ + var keyboardEventTarget = null; + if (options.keyboardEventTarget !== undefined) { + // cannot use goog.dom.getElement because its argument cannot be + // of type Document + keyboardEventTarget = goog.isString(options.keyboardEventTarget) ? + document.getElementById(options.keyboardEventTarget) : + options.keyboardEventTarget; + } + + /** + * @type {Object.<string, *>} + */ + var values = {}; + + var logos = {}; + if (options.logo === undefined || + (goog.isBoolean(options.logo) && options.logo)) { + logos[ol.OL3_LOGO_URL] = ol.OL3_URL; + } else { + var logo = options.logo; + if (goog.isString(logo)) { + logos[logo] = ''; + } else if (goog.isObject(logo)) { + goog.asserts.assertString(logo.href, 'logo.href should be a string'); + goog.asserts.assertString(logo.src, 'logo.src should be a string'); + logos[logo.src] = logo.href; + } + } + + var layerGroup = (options.layers instanceof ol.layer.Group) ? + options.layers : new ol.layer.Group({layers: options.layers}); + values[ol.MapProperty.LAYERGROUP] = layerGroup; + + values[ol.MapProperty.TARGET] = options.target; + + values[ol.MapProperty.VIEW] = options.view !== undefined ? + options.view : new ol.View(); + + /** + * @type {function(new: ol.renderer.Map, Element, ol.Map)} + */ + var rendererConstructor = ol.renderer.Map; + + /** + * @type {Array.<ol.RendererType>} + */ + var rendererTypes; + if (options.renderer !== undefined) { + if (goog.isArray(options.renderer)) { + rendererTypes = options.renderer; + } else if (goog.isString(options.renderer)) { + rendererTypes = [options.renderer]; + } else { + goog.asserts.fail('Incorrect format for renderer option'); + } + } else { + rendererTypes = ol.DEFAULT_RENDERER_TYPES; + } + + var i, ii; + for (i = 0, ii = rendererTypes.length; i < ii; ++i) { + /** @type {ol.RendererType} */ + var rendererType = rendererTypes[i]; + if (ol.ENABLE_CANVAS && rendererType == ol.RendererType.CANVAS) { + if (ol.has.CANVAS) { + rendererConstructor = ol.renderer.canvas.Map; + break; + } + } else if (ol.ENABLE_DOM && rendererType == ol.RendererType.DOM) { + if (ol.has.DOM) { + rendererConstructor = ol.renderer.dom.Map; + break; + } + } else if (ol.ENABLE_WEBGL && rendererType == ol.RendererType.WEBGL) { + if (ol.has.WEBGL) { + rendererConstructor = ol.renderer.webgl.Map; + break; + } + } + } + + var controls; + if (options.controls !== undefined) { + if (goog.isArray(options.controls)) { + controls = new ol.Collection(options.controls.slice()); + } else { + goog.asserts.assertInstanceof(options.controls, ol.Collection, + 'options.controls should be an ol.Collection'); + controls = options.controls; + } + } else { + controls = ol.control.defaults(); + } + + var interactions; + if (options.interactions !== undefined) { + if (goog.isArray(options.interactions)) { + interactions = new ol.Collection(options.interactions.slice()); + } else { + goog.asserts.assertInstanceof(options.interactions, ol.Collection, + 'options.interactions should be an ol.Collection'); + interactions = options.interactions; + } + } else { + interactions = ol.interaction.defaults(); + } + + var overlays; + if (options.overlays !== undefined) { + if (goog.isArray(options.overlays)) { + overlays = new ol.Collection(options.overlays.slice()); + } else { + goog.asserts.assertInstanceof(options.overlays, ol.Collection, + 'options.overlays should be an ol.Collection'); + overlays = options.overlays; + } + } else { + overlays = new ol.Collection(); + } + + return { + controls: controls, + interactions: interactions, + keyboardEventTarget: keyboardEventTarget, + logos: logos, + overlays: overlays, + rendererConstructor: rendererConstructor, + values: values + }; + +}; + + +ol.proj.common.add(); + + +if (goog.DEBUG) { + (function() { + goog.debug.Console.autoInstall(); + var logger = goog.log.getLogger('ol'); + logger.setLevel(goog.log.Level.FINEST); + })(); +} + +goog.provide('ol.Overlay'); +goog.provide('ol.OverlayPositioning'); +goog.provide('ol.OverlayProperty'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.style'); +goog.require('ol.Coordinate'); +goog.require('ol.Map'); +goog.require('ol.MapEventType'); +goog.require('ol.Object'); +goog.require('ol.animation'); +goog.require('ol.dom'); +goog.require('ol.extent'); + + +/** + * @enum {string} + */ +ol.OverlayProperty = { + ELEMENT: 'element', + MAP: 'map', + OFFSET: 'offset', + POSITION: 'position', + POSITIONING: 'positioning' +}; + + +/** + * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, + * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, + * `'top-center'`, `'top-right'` + * @enum {string} + * @api stable + */ +ol.OverlayPositioning = { + BOTTOM_LEFT: 'bottom-left', + BOTTOM_CENTER: 'bottom-center', + BOTTOM_RIGHT: 'bottom-right', + CENTER_LEFT: 'center-left', + CENTER_CENTER: 'center-center', + CENTER_RIGHT: 'center-right', + TOP_LEFT: 'top-left', + TOP_CENTER: 'top-center', + TOP_RIGHT: 'top-right' +}; + + + +/** + * @classdesc + * An element to be displayed over the map and attached to a single map + * location. Like {@link ol.control.Control}, Overlays are visible widgets. + * Unlike Controls, they are not in a fixed position on the screen, but are tied + * to a geographical coordinate, so panning the map will move an Overlay but not + * a Control. + * + * Example: + * + * var popup = new ol.Overlay({ + * element: document.getElementById('popup') + * }); + * popup.setPosition(coordinate); + * map.addOverlay(popup); + * + * @constructor + * @extends {ol.Object} + * @param {olx.OverlayOptions} options Overlay options. + * @api stable + */ +ol.Overlay = function(options) { + + goog.base(this); + + /** + * @private + * @type {number|string|undefined} + */ + this.id_ = options.id; + + /** + * @private + * @type {boolean} + */ + this.insertFirst_ = options.insertFirst !== undefined ? + options.insertFirst : true; + + /** + * @private + * @type {boolean} + */ + this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true; + + /** + * @private + * @type {Element} + */ + this.element_ = goog.dom.createDom('DIV', { + 'class': 'ol-overlay-container' + }); + this.element_.style.position = 'absolute'; + + /** + * @protected + * @type {boolean} + */ + this.autoPan = options.autoPan !== undefined ? options.autoPan : false; + + /** + * @private + * @type {olx.animation.PanOptions} + */ + this.autoPanAnimation_ = options.autoPanAnimation !== undefined ? + options.autoPanAnimation : /** @type {olx.animation.PanOptions} */ ({}); + + /** + * @private + * @type {number} + */ + this.autoPanMargin_ = options.autoPanMargin !== undefined ? + options.autoPanMargin : 20; + + /** + * @private + * @type {{bottom_: string, + * left_: string, + * right_: string, + * top_: string, + * visible: boolean}} + */ + this.rendered_ = { + bottom_: '', + left_: '', + right_: '', + top_: '', + visible: true + }; + + /** + * @private + * @type {goog.events.Key} + */ + this.mapPostrenderListenerKey_ = null; + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT), + this.handleElementChanged, false, this); + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP), + this.handleMapChanged, false, this); + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET), + this.handleOffsetChanged, false, this); + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION), + this.handlePositionChanged, false, this); + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING), + this.handlePositioningChanged, false, this); + + if (options.element !== undefined) { + this.setElement(options.element); + } + + this.setOffset(options.offset !== undefined ? options.offset : [0, 0]); + + this.setPositioning(options.positioning !== undefined ? + /** @type {ol.OverlayPositioning} */ (options.positioning) : + ol.OverlayPositioning.TOP_LEFT); + + if (options.position !== undefined) { + this.setPosition(options.position); + } + +}; +goog.inherits(ol.Overlay, ol.Object); + + +/** + * Get the DOM element of this overlay. + * @return {Element|undefined} The Element containing the overlay. + * @observable + * @api stable + */ +ol.Overlay.prototype.getElement = function() { + return /** @type {Element|undefined} */ ( + this.get(ol.OverlayProperty.ELEMENT)); +}; + + +/** + * Get the overlay identifier which is set on constructor. + * @return {number|string|undefined} Id. + * @api + */ +ol.Overlay.prototype.getId = function() { + return this.id_; +}; + + +/** + * Get the map associated with this overlay. + * @return {ol.Map|undefined} The map that the overlay is part of. + * @observable + * @api stable + */ +ol.Overlay.prototype.getMap = function() { + return /** @type {ol.Map|undefined} */ ( + this.get(ol.OverlayProperty.MAP)); +}; + + +/** + * Get the offset of this overlay. + * @return {Array.<number>} The offset. + * @observable + * @api stable + */ +ol.Overlay.prototype.getOffset = function() { + return /** @type {Array.<number>} */ ( + this.get(ol.OverlayProperty.OFFSET)); +}; + + +/** + * Get the current position of this overlay. + * @return {ol.Coordinate|undefined} The spatial point that the overlay is + * anchored at. + * @observable + * @api stable + */ +ol.Overlay.prototype.getPosition = function() { + return /** @type {ol.Coordinate|undefined} */ ( + this.get(ol.OverlayProperty.POSITION)); +}; + + +/** + * Get the current positioning of this overlay. + * @return {ol.OverlayPositioning} How the overlay is positioned + * relative to its point on the map. + * @observable + * @api stable + */ +ol.Overlay.prototype.getPositioning = function() { + return /** @type {ol.OverlayPositioning} */ ( + this.get(ol.OverlayProperty.POSITIONING)); +}; + + +/** + * @protected + */ +ol.Overlay.prototype.handleElementChanged = function() { + goog.dom.removeChildren(this.element_); + var element = this.getElement(); + if (element) { + goog.dom.append(/** @type {!Node} */ (this.element_), element); + } +}; + + +/** + * @protected + */ +ol.Overlay.prototype.handleMapChanged = function() { + if (this.mapPostrenderListenerKey_) { + goog.dom.removeNode(this.element_); + goog.events.unlistenByKey(this.mapPostrenderListenerKey_); + this.mapPostrenderListenerKey_ = null; + } + var map = this.getMap(); + if (map) { + this.mapPostrenderListenerKey_ = goog.events.listen(map, + ol.MapEventType.POSTRENDER, this.render, false, this); + this.updatePixelPosition(); + var container = this.stopEvent_ ? + map.getOverlayContainerStopEvent() : map.getOverlayContainer(); + if (this.insertFirst_) { + goog.dom.insertChildAt(/** @type {!Element} */ ( + container), this.element_, 0); + } else { + goog.dom.append(/** @type {!Node} */ (container), this.element_); + } + } +}; + + +/** + * @protected + */ +ol.Overlay.prototype.render = function() { + this.updatePixelPosition(); +}; + + +/** + * @protected + */ +ol.Overlay.prototype.handleOffsetChanged = function() { + this.updatePixelPosition(); +}; + + +/** + * @protected + */ +ol.Overlay.prototype.handlePositionChanged = function() { + this.updatePixelPosition(); + if (this.get(ol.OverlayProperty.POSITION) !== undefined && this.autoPan) { + this.panIntoView_(); + } +}; + + +/** + * @protected + */ +ol.Overlay.prototype.handlePositioningChanged = function() { + this.updatePixelPosition(); +}; + + +/** + * Set the DOM element to be associated with this overlay. + * @param {Element|undefined} element The Element containing the overlay. + * @observable + * @api stable + */ +ol.Overlay.prototype.setElement = function(element) { + this.set(ol.OverlayProperty.ELEMENT, element); +}; + + +/** + * Set the map to be associated with this overlay. + * @param {ol.Map|undefined} map The map that the overlay is part of. + * @observable + * @api stable + */ +ol.Overlay.prototype.setMap = function(map) { + this.set(ol.OverlayProperty.MAP, map); +}; + + +/** + * Set the offset for this overlay. + * @param {Array.<number>} offset Offset. + * @observable + * @api stable + */ +ol.Overlay.prototype.setOffset = function(offset) { + this.set(ol.OverlayProperty.OFFSET, offset); +}; + + +/** + * Set the position for this overlay. If the position is `undefined` the + * overlay is hidden. + * @param {ol.Coordinate|undefined} position The spatial point that the overlay + * is anchored at. + * @observable + * @api stable + */ +ol.Overlay.prototype.setPosition = function(position) { + this.set(ol.OverlayProperty.POSITION, position); +}; + + +/** + * Pan the map so that the overlay is entirely visible in the current viewport + * (if necessary). + * @private + */ +ol.Overlay.prototype.panIntoView_ = function() { + goog.asserts.assert(this.autoPan, 'this.autoPan should be true'); + var map = this.getMap(); + + if (map === undefined || !map.getTargetElement()) { + return; + } + + var mapRect = this.getRect_(map.getTargetElement(), map.getSize()); + var element = this.getElement(); + goog.asserts.assert(element, 'element should be defined'); + var overlayRect = this.getRect_(element, + [ol.dom.outerWidth(element), ol.dom.outerHeight(element)]); + + var margin = this.autoPanMargin_; + if (!ol.extent.containsExtent(mapRect, overlayRect)) { + // the overlay is not completely inside the viewport, so pan the map + var offsetLeft = overlayRect[0] - mapRect[0]; + var offsetRight = mapRect[2] - overlayRect[2]; + var offsetTop = overlayRect[1] - mapRect[1]; + var offsetBottom = mapRect[3] - overlayRect[3]; + + var delta = [0, 0]; + if (offsetLeft < 0) { + // move map to the left + delta[0] = offsetLeft - margin; + } else if (offsetRight < 0) { + // move map to the right + delta[0] = Math.abs(offsetRight) + margin; + } + if (offsetTop < 0) { + // move map up + delta[1] = offsetTop - margin; + } else if (offsetBottom < 0) { + // move map down + delta[1] = Math.abs(offsetBottom) + margin; + } + + if (delta[0] !== 0 || delta[1] !== 0) { + var center = map.getView().getCenter(); + goog.asserts.assert(center !== undefined, 'center should be defined'); + var centerPx = map.getPixelFromCoordinate(center); + var newCenterPx = [ + centerPx[0] + delta[0], + centerPx[1] + delta[1] + ]; + + if (this.autoPanAnimation_) { + this.autoPanAnimation_.source = center; + map.beforeRender(ol.animation.pan(this.autoPanAnimation_)); + } + map.getView().setCenter(map.getCoordinateFromPixel(newCenterPx)); + } + } +}; + + +/** + * Get the extent of an element relative to the document + * @param {Element|undefined} element The element. + * @param {ol.Size|undefined} size The size of the element. + * @return {ol.Extent} + * @private + */ +ol.Overlay.prototype.getRect_ = function(element, size) { + goog.asserts.assert(element, 'element should be defined'); + goog.asserts.assert(size !== undefined, 'size should be defined'); + + var offset = goog.style.getPageOffset(element); + return [ + offset.x, + offset.y, + offset.x + size[0], + offset.y + size[1] + ]; +}; + + +/** + * Set the positioning for this overlay. + * @param {ol.OverlayPositioning} positioning how the overlay is + * positioned relative to its point on the map. + * @observable + * @api stable + */ +ol.Overlay.prototype.setPositioning = function(positioning) { + this.set(ol.OverlayProperty.POSITIONING, positioning); +}; + + +/** + * Modify the visibility of the element. + * @param {boolean} visible + * @protected + */ +ol.Overlay.prototype.setVisible = function(visible) { + if (this.rendered_.visible !== visible) { + goog.style.setElementShown(this.element_, visible); + this.rendered_.visible = visible; + } +}; + + +/** + * Update pixel position. + * @protected + */ +ol.Overlay.prototype.updatePixelPosition = function() { + var map = this.getMap(); + var position = this.getPosition(); + if (map === undefined || !map.isRendered() || position === undefined) { + this.setVisible(false); + return; + } + + var pixel = map.getPixelFromCoordinate(position); + var mapSize = map.getSize(); + this.updateRenderedPosition(pixel, mapSize); +}; + + +/** + * @param {ol.Pixel} pixel + * @param {ol.Size|undefined} mapSize + * @protected + */ +ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) { + goog.asserts.assert(pixel, 'pixel should not be null'); + goog.asserts.assert(mapSize !== undefined, 'mapSize should be defined'); + var style = this.element_.style; + var offset = this.getOffset(); + goog.asserts.assert(goog.isArray(offset), 'offset should be an array'); + + var positioning = this.getPositioning(); + goog.asserts.assert(positioning !== undefined, + 'positioning should be defined'); + + var offsetX = offset[0]; + var offsetY = offset[1]; + if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT || + positioning == ol.OverlayPositioning.CENTER_RIGHT || + positioning == ol.OverlayPositioning.TOP_RIGHT) { + if (this.rendered_.left_ !== '') { + this.rendered_.left_ = style.left = ''; + } + var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px'; + if (this.rendered_.right_ != right) { + this.rendered_.right_ = style.right = right; + } + } else { + if (this.rendered_.right_ !== '') { + this.rendered_.right_ = style.right = ''; + } + if (positioning == ol.OverlayPositioning.BOTTOM_CENTER || + positioning == ol.OverlayPositioning.CENTER_CENTER || + positioning == ol.OverlayPositioning.TOP_CENTER) { + offsetX -= goog.style.getSize(this.element_).width / 2; + } + var left = Math.round(pixel[0] + offsetX) + 'px'; + if (this.rendered_.left_ != left) { + this.rendered_.left_ = style.left = left; + } + } + if (positioning == ol.OverlayPositioning.BOTTOM_LEFT || + positioning == ol.OverlayPositioning.BOTTOM_CENTER || + positioning == ol.OverlayPositioning.BOTTOM_RIGHT) { + if (this.rendered_.top_ !== '') { + this.rendered_.top_ = style.top = ''; + } + var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px'; + if (this.rendered_.bottom_ != bottom) { + this.rendered_.bottom_ = style.bottom = bottom; + } + } else { + if (this.rendered_.bottom_ !== '') { + this.rendered_.bottom_ = style.bottom = ''; + } + if (positioning == ol.OverlayPositioning.CENTER_LEFT || + positioning == ol.OverlayPositioning.CENTER_CENTER || + positioning == ol.OverlayPositioning.CENTER_RIGHT) { + offsetY -= goog.style.getSize(this.element_).height / 2; + } + var top = Math.round(pixel[1] + offsetY) + 'px'; + if (this.rendered_.top_ != top) { + this.rendered_.top_ = style.top = top; + } + } + + this.setVisible(true); +}; + +goog.provide('ol.control.OverviewMap'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.dom.classlist'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.math.Size'); +goog.require('goog.style'); +goog.require('ol'); +goog.require('ol.Collection'); +goog.require('ol.Map'); +goog.require('ol.MapEventType'); +goog.require('ol.Object'); +goog.require('ol.ObjectEventType'); +goog.require('ol.Overlay'); +goog.require('ol.OverlayPositioning'); +goog.require('ol.View'); +goog.require('ol.ViewProperty'); +goog.require('ol.control.Control'); +goog.require('ol.coordinate'); +goog.require('ol.css'); +goog.require('ol.extent'); + + + +/** + * Create a new control with a map acting as an overview map for an other + * defined map. + * @constructor + * @extends {ol.control.Control} + * @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options. + * @api + */ +ol.control.OverviewMap = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + /** + * @type {boolean} + * @private + */ + this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true; + + /** + * @private + * @type {boolean} + */ + this.collapsible_ = options.collapsible !== undefined ? + options.collapsible : true; + + if (!this.collapsible_) { + this.collapsed_ = false; + } + + var className = options.className ? options.className : 'ol-overviewmap'; + + var tipLabel = options.tipLabel ? options.tipLabel : 'Overview map'; + + var collapseLabel = options.collapseLabel ? options.collapseLabel : '\u00AB'; + + /** + * @private + * @type {Node} + */ + this.collapseLabel_ = goog.isString(collapseLabel) ? + goog.dom.createDom('SPAN', {}, collapseLabel) : + collapseLabel; + + var label = options.label ? options.label : '\u00BB'; + + /** + * @private + * @type {Node} + */ + this.label_ = goog.isString(label) ? + goog.dom.createDom('SPAN', {}, label) : + label; + + var activeLabel = (this.collapsible_ && !this.collapsed_) ? + this.collapseLabel_ : this.label_; + var button = goog.dom.createDom('BUTTON', { + 'type': 'button', + 'title': tipLabel + }, activeLabel); + + goog.events.listen(button, goog.events.EventType.CLICK, + this.handleClick_, false, this); + + var ovmapDiv = goog.dom.createDom('DIV', 'ol-overviewmap-map'); + + /** + * @type {ol.Map} + * @private + */ + this.ovmap_ = new ol.Map({ + controls: new ol.Collection(), + interactions: new ol.Collection(), + target: ovmapDiv, + view: options.view + }); + var ovmap = this.ovmap_; + + if (options.layers) { + options.layers.forEach( + /** + * @param {ol.layer.Layer} layer Layer. + */ + function(layer) { + ovmap.addLayer(layer); + }, this); + } + + var box = goog.dom.createDom('DIV', 'ol-overviewmap-box'); + + /** + * @type {ol.Overlay} + * @private + */ + this.boxOverlay_ = new ol.Overlay({ + position: [0, 0], + positioning: ol.OverlayPositioning.BOTTOM_LEFT, + element: box + }); + this.ovmap_.addOverlay(this.boxOverlay_); + + var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + + ol.css.CLASS_CONTROL + + (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') + + (this.collapsible_ ? '' : ' ol-uncollapsible'); + var element = goog.dom.createDom('DIV', + cssClasses, ovmapDiv, button); + + var render = options.render ? options.render : ol.control.OverviewMap.render; + + goog.base(this, { + element: element, + render: render, + target: options.target + }); +}; +goog.inherits(ol.control.OverviewMap, ol.control.Control); + + +/** + * @inheritDoc + * @api + */ +ol.control.OverviewMap.prototype.setMap = function(map) { + var oldMap = this.getMap(); + if (map === oldMap) { + return; + } + if (oldMap) { + var oldView = oldMap.getView(); + if (oldView) { + this.unbindView_(oldView); + } + } + goog.base(this, 'setMap', map); + + if (map) { + this.listenerKeys.push(goog.events.listen( + map, ol.ObjectEventType.PROPERTYCHANGE, + this.handleMapPropertyChange_, false, this)); + + // TODO: to really support map switching, this would need to be reworked + if (this.ovmap_.getLayers().getLength() === 0) { + this.ovmap_.setLayerGroup(map.getLayerGroup()); + } + + var view = map.getView(); + if (view) { + this.bindView_(view); + if (view.isDef()) { + this.ovmap_.updateSize(); + this.resetExtent_(); + } + } + } +}; + + +/** + * Handle map property changes. This only deals with changes to the map's view. + * @param {ol.ObjectEvent} event The propertychange event. + * @private + */ +ol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) { + if (event.key === ol.MapProperty.VIEW) { + var oldView = /** @type {ol.View} */ (event.oldValue); + if (oldView) { + this.unbindView_(oldView); + } + var newView = this.getMap().getView(); + this.bindView_(newView); + } +}; + + +/** + * Register listeners for view property changes. + * @param {ol.View} view The view. + * @private + */ +ol.control.OverviewMap.prototype.bindView_ = function(view) { + goog.events.listen(view, + ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), + this.handleRotationChanged_, false, this); +}; + + +/** + * Unregister listeners for view property changes. + * @param {ol.View} view The view. + * @private + */ +ol.control.OverviewMap.prototype.unbindView_ = function(view) { + goog.events.unlisten(view, + ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), + this.handleRotationChanged_, false, this); +}; + + +/** + * Handle rotation changes to the main map. + * TODO: This should rotate the extent rectrangle instead of the + * overview map's view. + * @private + */ +ol.control.OverviewMap.prototype.handleRotationChanged_ = function() { + this.ovmap_.getView().setRotation(this.getMap().getView().getRotation()); +}; + + +/** + * Update the overview map element. + * @param {ol.MapEvent} mapEvent Map event. + * @this {ol.control.OverviewMap} + * @api + */ +ol.control.OverviewMap.render = function(mapEvent) { + this.validateExtent_(); + this.updateBox_(); +}; + + +/** + * Reset the overview map extent if the box size (width or + * height) is less than the size of the overview map size times minRatio + * or is greater than the size of the overview size times maxRatio. + * + * If the map extent was not reset, the box size can fits in the defined + * ratio sizes. This method then checks if is contained inside the overview + * map current extent. If not, recenter the overview map to the current + * main map center location. + * @private + */ +ol.control.OverviewMap.prototype.validateExtent_ = function() { + var map = this.getMap(); + var ovmap = this.ovmap_; + + if (!map.isRendered() || !ovmap.isRendered()) { + return; + } + + var mapSize = map.getSize(); + goog.asserts.assertArray(mapSize, 'mapSize should be an array'); + + var view = map.getView(); + goog.asserts.assert(view, 'view should be defined'); + var extent = view.calculateExtent(mapSize); + + var ovmapSize = ovmap.getSize(); + goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); + + var ovview = ovmap.getView(); + goog.asserts.assert(ovview, 'ovview should be defined'); + var ovextent = ovview.calculateExtent(ovmapSize); + + var topLeftPixel = + ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent)); + var bottomRightPixel = + ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent)); + var boxSize = new goog.math.Size( + Math.abs(topLeftPixel[0] - bottomRightPixel[0]), + Math.abs(topLeftPixel[1] - bottomRightPixel[1])); + + var ovmapWidth = ovmapSize[0]; + var ovmapHeight = ovmapSize[1]; + + if (boxSize.width < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO || + boxSize.height < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO || + boxSize.width > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO || + boxSize.height > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) { + this.resetExtent_(); + } else if (!ol.extent.containsExtent(ovextent, extent)) { + this.recenter_(); + } +}; + + +/** + * Reset the overview map extent to half calculated min and max ratio times + * the extent of the main map. + * @private + */ +ol.control.OverviewMap.prototype.resetExtent_ = function() { + if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) { + return; + } + + var map = this.getMap(); + var ovmap = this.ovmap_; + + var mapSize = map.getSize(); + goog.asserts.assertArray(mapSize, 'mapSize should be an array'); + + var view = map.getView(); + goog.asserts.assert(view, 'view should be defined'); + var extent = view.calculateExtent(mapSize); + + var ovmapSize = ovmap.getSize(); + goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); + + var ovview = ovmap.getView(); + goog.asserts.assert(ovview, 'ovview should be defined'); + + // get how many times the current map overview could hold different + // box sizes using the min and max ratio, pick the step in the middle used + // to calculate the extent from the main map to set it to the overview map, + var steps = Math.log( + ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2; + var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO); + ol.extent.scaleFromCenter(extent, ratio); + ovview.fit(extent, ovmapSize); +}; + + +/** + * Set the center of the overview map to the map center without changing its + * resolution. + * @private + */ +ol.control.OverviewMap.prototype.recenter_ = function() { + var map = this.getMap(); + var ovmap = this.ovmap_; + + var view = map.getView(); + goog.asserts.assert(view, 'view should be defined'); + + var ovview = ovmap.getView(); + goog.asserts.assert(ovview, 'ovview should be defined'); + + ovview.setCenter(view.getCenter()); +}; + + +/** + * Update the box using the main map extent + * @private + */ +ol.control.OverviewMap.prototype.updateBox_ = function() { + var map = this.getMap(); + var ovmap = this.ovmap_; + + if (!map.isRendered() || !ovmap.isRendered()) { + return; + } + + var mapSize = map.getSize(); + goog.asserts.assertArray(mapSize, 'mapSize should be an array'); + + var view = map.getView(); + goog.asserts.assert(view, 'view should be defined'); + + var ovview = ovmap.getView(); + goog.asserts.assert(ovview, 'ovview should be defined'); + + var ovmapSize = ovmap.getSize(); + goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array'); + + var rotation = view.getRotation(); + goog.asserts.assert(rotation !== undefined, 'rotation should be defined'); + + var overlay = this.boxOverlay_; + var box = this.boxOverlay_.getElement(); + var extent = view.calculateExtent(mapSize); + var ovresolution = ovview.getResolution(); + var bottomLeft = ol.extent.getBottomLeft(extent); + var topRight = ol.extent.getTopRight(extent); + + // set position using bottom left coordinates + var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft); + overlay.setPosition(rotateBottomLeft); + + // set box size calculated from map extent size and overview map resolution + if (box) { + var boxWidth = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution); + var boxHeight = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution); + goog.style.setBorderBoxSize(box, new goog.math.Size( + boxWidth, boxHeight)); + } +}; + + +/** + * @param {number} rotation Target rotation. + * @param {ol.Coordinate} coordinate Coordinate. + * @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor. + * @private + */ +ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function( + rotation, coordinate) { + var coordinateRotate; + + var map = this.getMap(); + var view = map.getView(); + goog.asserts.assert(view, 'view should be defined'); + + var currentCenter = view.getCenter(); + + if (currentCenter) { + coordinateRotate = [ + coordinate[0] - currentCenter[0], + coordinate[1] - currentCenter[1] + ]; + ol.coordinate.rotate(coordinateRotate, rotation); + ol.coordinate.add(coordinateRotate, currentCenter); + } + return coordinateRotate; +}; + + +/** + * @param {goog.events.BrowserEvent} event The event to handle + * @private + */ +ol.control.OverviewMap.prototype.handleClick_ = function(event) { + event.preventDefault(); + this.handleToggle_(); +}; + + +/** + * @private + */ +ol.control.OverviewMap.prototype.handleToggle_ = function() { + goog.dom.classlist.toggle(this.element, 'ol-collapsed'); + if (this.collapsed_) { + goog.dom.replaceNode(this.collapseLabel_, this.label_); + } else { + goog.dom.replaceNode(this.label_, this.collapseLabel_); + } + this.collapsed_ = !this.collapsed_; + + // manage overview map if it had not been rendered before and control + // is expanded + var ovmap = this.ovmap_; + if (!this.collapsed_ && !ovmap.isRendered()) { + ovmap.updateSize(); + this.resetExtent_(); + goog.events.listenOnce(ovmap, ol.MapEventType.POSTRENDER, + function(event) { + this.updateBox_(); + }, + false, this); + } +}; + + +/** + * Return `true` if the overview map is collapsible, `false` otherwise. + * @return {boolean} True if the widget is collapsible. + * @api stable + */ +ol.control.OverviewMap.prototype.getCollapsible = function() { + return this.collapsible_; +}; + + +/** + * Set whether the overview map should be collapsible. + * @param {boolean} collapsible True if the widget is collapsible. + * @api stable + */ +ol.control.OverviewMap.prototype.setCollapsible = function(collapsible) { + if (this.collapsible_ === collapsible) { + return; + } + this.collapsible_ = collapsible; + goog.dom.classlist.toggle(this.element, 'ol-uncollapsible'); + if (!collapsible && this.collapsed_) { + this.handleToggle_(); + } +}; + + +/** + * Collapse or expand the overview map according to the passed parameter. Will + * not do anything if the overview map isn't collapsible or if the current + * collapsed state is already the one requested. + * @param {boolean} collapsed True if the widget is collapsed. + * @api stable + */ +ol.control.OverviewMap.prototype.setCollapsed = function(collapsed) { + if (!this.collapsible_ || this.collapsed_ === collapsed) { + return; + } + this.handleToggle_(); +}; + + +/** + * Determine if the overview map is collapsed. + * @return {boolean} The overview map is collapsed. + * @api stable + */ +ol.control.OverviewMap.prototype.getCollapsed = function() { + return this.collapsed_; +}; + + +/** + * Return the overview map. + * @return {ol.Map} Overview map. + * @api + */ +ol.control.OverviewMap.prototype.getOverviewMap = function() { + return this.ovmap_; +}; + +goog.provide('ol.control.ScaleLine'); +goog.provide('ol.control.ScaleLineProperty'); +goog.provide('ol.control.ScaleLineUnits'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.style'); +goog.require('ol'); +goog.require('ol.Object'); +goog.require('ol.TransformFunction'); +goog.require('ol.control.Control'); +goog.require('ol.css'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.proj.METERS_PER_UNIT'); +goog.require('ol.proj.Units'); +goog.require('ol.sphere.NORMAL'); + + +/** + * @enum {string} + */ +ol.control.ScaleLineProperty = { + UNITS: 'units' +}; + + +/** + * Units for the scale line. Supported values are `'degrees'`, `'imperial'`, + * `'nautical'`, `'metric'`, `'us'`. + * @enum {string} + * @api stable + */ +ol.control.ScaleLineUnits = { + DEGREES: 'degrees', + IMPERIAL: 'imperial', + NAUTICAL: 'nautical', + METRIC: 'metric', + US: 'us' +}; + + + +/** + * @classdesc + * A control displaying rough x-axis distances, calculated for the center of the + * viewport. + * No scale line will be shown when the x-axis distance cannot be calculated in + * the view projection (e.g. at or beyond the poles in EPSG:4326). + * By default the scale line will show in the bottom left portion of the map, + * but this can be changed by using the css selector `.ol-scale-line`. + * + * @constructor + * @extends {ol.control.Control} + * @param {olx.control.ScaleLineOptions=} opt_options Scale line options. + * @api stable + */ +ol.control.ScaleLine = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + var className = options.className ? options.className : 'ol-scale-line'; + + /** + * @private + * @type {Element} + */ + this.innerElement_ = goog.dom.createDom('DIV', + className + '-inner'); + + /** + * @private + * @type {Element} + */ + this.element_ = goog.dom.createDom('DIV', + className + ' ' + ol.css.CLASS_UNSELECTABLE, this.innerElement_); + + /** + * @private + * @type {?olx.ViewState} + */ + this.viewState_ = null; + + /** + * @private + * @type {number} + */ + this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64; + + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = false; + + /** + * @private + * @type {number|undefined} + */ + this.renderedWidth_ = undefined; + + /** + * @private + * @type {string} + */ + this.renderedHTML_ = ''; + + /** + * @private + * @type {?ol.TransformFunction} + */ + this.toEPSG4326_ = null; + + var render = options.render ? options.render : ol.control.ScaleLine.render; + + goog.base(this, { + element: this.element_, + render: render, + target: options.target + }); + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.control.ScaleLineProperty.UNITS), + this.handleUnitsChanged_, false, this); + + this.setUnits(/** @type {ol.control.ScaleLineUnits} */ (options.units) || + ol.control.ScaleLineUnits.METRIC); + +}; +goog.inherits(ol.control.ScaleLine, ol.control.Control); + + +/** + * @const + * @type {Array.<number>} + */ +ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5]; + + +/** + * Return the units to use in the scale line. + * @return {ol.control.ScaleLineUnits|undefined} The units to use in the scale + * line. + * @observable + * @api stable + */ +ol.control.ScaleLine.prototype.getUnits = function() { + return /** @type {ol.control.ScaleLineUnits|undefined} */ ( + this.get(ol.control.ScaleLineProperty.UNITS)); +}; + + +/** + * Update the scale line element. + * @param {ol.MapEvent} mapEvent Map event. + * @this {ol.control.ScaleLine} + * @api + */ +ol.control.ScaleLine.render = function(mapEvent) { + var frameState = mapEvent.frameState; + if (!frameState) { + this.viewState_ = null; + } else { + this.viewState_ = frameState.viewState; + } + this.updateElement_(); +}; + + +/** + * @private + */ +ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() { + this.updateElement_(); +}; + + +/** + * Set the units to use in the scale line. + * @param {ol.control.ScaleLineUnits} units The units to use in the scale line. + * @observable + * @api stable + */ +ol.control.ScaleLine.prototype.setUnits = function(units) { + this.set(ol.control.ScaleLineProperty.UNITS, units); +}; + + +/** + * @private + */ +ol.control.ScaleLine.prototype.updateElement_ = function() { + var viewState = this.viewState_; + + if (!viewState) { + if (this.renderedVisible_) { + goog.style.setElementShown(this.element_, false); + this.renderedVisible_ = false; + } + return; + } + + var center = viewState.center; + var projection = viewState.projection; + var pointResolution = + projection.getPointResolution(viewState.resolution, center); + var projectionUnits = projection.getUnits(); + + var cosLatitude; + var units = this.getUnits(); + if (projectionUnits == ol.proj.Units.DEGREES && + (units == ol.control.ScaleLineUnits.METRIC || + units == ol.control.ScaleLineUnits.IMPERIAL || + units == ol.control.ScaleLineUnits.US || + units == ol.control.ScaleLineUnits.NAUTICAL)) { + + // Convert pointResolution from degrees to meters + this.toEPSG4326_ = null; + cosLatitude = Math.cos(ol.math.toRadians(center[1])); + pointResolution *= Math.PI * cosLatitude * ol.sphere.NORMAL.radius / 180; + projectionUnits = ol.proj.Units.METERS; + + } else if (projectionUnits != ol.proj.Units.DEGREES && + units == ol.control.ScaleLineUnits.DEGREES) { + + // Convert pointResolution from other units to degrees + if (!this.toEPSG4326_) { + this.toEPSG4326_ = ol.proj.getTransformFromProjections( + projection, ol.proj.get('EPSG:4326')); + } + cosLatitude = Math.cos(ol.math.toRadians(this.toEPSG4326_(center)[1])); + var radius = ol.sphere.NORMAL.radius; + goog.asserts.assert(ol.proj.METERS_PER_UNIT[projectionUnits], + 'Meters per unit should be defined for the projection unit'); + radius /= ol.proj.METERS_PER_UNIT[projectionUnits]; + pointResolution *= 180 / (Math.PI * cosLatitude * radius); + projectionUnits = ol.proj.Units.DEGREES; + + } else { + this.toEPSG4326_ = null; + } + + goog.asserts.assert( + ((units == ol.control.ScaleLineUnits.METRIC || + units == ol.control.ScaleLineUnits.IMPERIAL || + units == ol.control.ScaleLineUnits.US || + units == ol.control.ScaleLineUnits.NAUTICAL) && + projectionUnits == ol.proj.Units.METERS) || + (units == ol.control.ScaleLineUnits.DEGREES && + projectionUnits == ol.proj.Units.DEGREES), + 'Scale line units and projection units should match'); + + var nominalCount = this.minWidth_ * pointResolution; + var suffix = ''; + if (units == ol.control.ScaleLineUnits.DEGREES) { + if (nominalCount < 1 / 60) { + suffix = '\u2033'; // seconds + pointResolution *= 3600; + } else if (nominalCount < 1) { + suffix = '\u2032'; // minutes + pointResolution *= 60; + } else { + suffix = '\u00b0'; // degrees + } + } else if (units == ol.control.ScaleLineUnits.IMPERIAL) { + if (nominalCount < 0.9144) { + suffix = 'in'; + pointResolution /= 0.0254; + } else if (nominalCount < 1609.344) { + suffix = 'ft'; + pointResolution /= 0.3048; + } else { + suffix = 'mi'; + pointResolution /= 1609.344; + } + } else if (units == ol.control.ScaleLineUnits.NAUTICAL) { + pointResolution /= 1852; + suffix = 'nm'; + } else if (units == ol.control.ScaleLineUnits.METRIC) { + if (nominalCount < 1) { + suffix = 'mm'; + pointResolution *= 1000; + } else if (nominalCount < 1000) { + suffix = 'm'; + } else { + suffix = 'km'; + pointResolution /= 1000; + } + } else if (units == ol.control.ScaleLineUnits.US) { + if (nominalCount < 0.9144) { + suffix = 'in'; + pointResolution *= 39.37; + } else if (nominalCount < 1609.344) { + suffix = 'ft'; + pointResolution /= 0.30480061; + } else { + suffix = 'mi'; + pointResolution /= 1609.3472; + } + } else { + goog.asserts.fail('Scale line element cannot be updated'); + } + + var i = 3 * Math.floor( + Math.log(this.minWidth_ * pointResolution) / Math.log(10)); + var count, width; + while (true) { + count = ol.control.ScaleLine.LEADING_DIGITS[i % 3] * + Math.pow(10, Math.floor(i / 3)); + width = Math.round(count / pointResolution); + if (isNaN(width)) { + goog.style.setElementShown(this.element_, false); + this.renderedVisible_ = false; + return; + } else if (width >= this.minWidth_) { + break; + } + ++i; + } + + var html = count + ' ' + suffix; + if (this.renderedHTML_ != html) { + this.innerElement_.innerHTML = html; + this.renderedHTML_ = html; + } + + if (this.renderedWidth_ != width) { + this.innerElement_.style.width = width + 'px'; + this.renderedWidth_ = width; + } + + if (!this.renderedVisible_) { + goog.style.setElementShown(this.element_, true); + this.renderedVisible_ = true; + } + +}; + +// Copyright 2005 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Class to create objects which want to handle multiple events + * and have their listeners easily cleaned up via a dispose method. + * + * Example: + * <pre> + * function Something() { + * Something.base(this); + * + * ... set up object ... + * + * // Add event listeners + * this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar); + * this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand); + * this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse); + * this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover); + * this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover); + * } + * goog.inherits(Something, goog.events.EventHandler); + * + * Something.prototype.disposeInternal = function() { + * Something.base(this, 'disposeInternal'); + * goog.dom.removeNode(this.container); + * }; + * + * + * // Then elsewhere: + * + * var activeSomething = null; + * function openSomething() { + * activeSomething = new Something(); + * } + * + * function closeSomething() { + * if (activeSomething) { + * activeSomething.dispose(); // Remove event listeners + * activeSomething = null; + * } + * } + * </pre> + * + */ + +goog.provide('goog.events.EventHandler'); + +goog.require('goog.Disposable'); +goog.require('goog.events'); +goog.require('goog.object'); + +goog.forwardDeclare('goog.events.EventWrapper'); + + + +/** + * Super class for objects that want to easily manage a number of event + * listeners. It allows a short cut to listen and also provides a quick way + * to remove all events listeners belonging to this object. + * @param {SCOPE=} opt_scope Object in whose scope to call the listeners. + * @constructor + * @extends {goog.Disposable} + * @template SCOPE + */ +goog.events.EventHandler = function(opt_scope) { + goog.Disposable.call(this); + // TODO(mknichel): Rename this to this.scope_ and fix the classes in google3 + // that access this private variable. :( + this.handler_ = opt_scope; + + /** + * Keys for events that are being listened to. + * @type {!Object<!goog.events.Key>} + * @private + */ + this.keys_ = {}; +}; +goog.inherits(goog.events.EventHandler, goog.Disposable); + + +/** + * Utility array used to unify the cases of listening for an array of types + * and listening for a single event, without using recursion or allocating + * an array each time. + * @type {!Array<string>} + * @const + * @private + */ +goog.events.EventHandler.typeArray_ = []; + + +/** + * Listen to an event on a Listenable. If the function is omitted then the + * EventHandler's handleEvent method will be used. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} + * opt_fn Optional callback function to be used as the listener or an object + * with handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + */ +goog.events.EventHandler.prototype.listen = function( + src, type, opt_fn, opt_capture) { + return this.listen_(src, type, opt_fn, opt_capture); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted then the + * EventHandler's handleEvent method will be used. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| + * null|undefined} fn Optional callback function to be used as the + * listener or an object with handleEvent function. + * @param {boolean|undefined} capture Optional whether to use capture phase. + * @param {T} scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template T,EVENTOBJ + */ +goog.events.EventHandler.prototype.listenWithScope = function( + src, type, fn, capture, scope) { + // TODO(mknichel): Deprecate this function. + return this.listen_(src, type, fn, capture, scope); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted then the + * EventHandler's handleEvent method will be used. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @param {Object=} opt_scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + * @private + */ +goog.events.EventHandler.prototype.listen_ = function(src, type, opt_fn, + opt_capture, + opt_scope) { + if (!goog.isArray(type)) { + if (type) { + goog.events.EventHandler.typeArray_[0] = type.toString(); + } + type = goog.events.EventHandler.typeArray_; + } + for (var i = 0; i < type.length; i++) { + var listenerObj = goog.events.listen( + src, type[i], opt_fn || this.handleEvent, + opt_capture || false, + opt_scope || this.handler_ || this); + + if (!listenerObj) { + // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT + // (goog.events.CaptureSimulationMode) in IE8-, it will return null + // value. + return this; + } + + var key = listenerObj.key; + this.keys_[key] = listenerObj; + } + + return this; +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted, then the + * EventHandler's handleEvent method will be used. After the event has fired the + * event listener is removed from the target. If an array of event types is + * provided, each event type will be listened to once. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + */ +goog.events.EventHandler.prototype.listenOnce = function( + src, type, opt_fn, opt_capture) { + return this.listenOnce_(src, type, opt_fn, opt_capture); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted, then the + * EventHandler's handleEvent method will be used. After the event has fired the + * event listener is removed from the target. If an array of event types is + * provided, each event type will be listened to once. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}| + * null|undefined} fn Optional callback function to be used as the + * listener or an object with handleEvent function. + * @param {boolean|undefined} capture Optional whether to use capture phase. + * @param {T} scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template T,EVENTOBJ + */ +goog.events.EventHandler.prototype.listenOnceWithScope = function( + src, type, fn, capture, scope) { + // TODO(mknichel): Deprecate this function. + return this.listenOnce_(src, type, fn, capture, scope); +}; + + +/** + * Listen to an event on a Listenable. If the function is omitted, then the + * EventHandler's handleEvent method will be used. After the event has fired + * the event listener is removed from the target. If an array of event types is + * provided, each event type will be listened to once. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type to listen for or array of event types. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @param {Object=} opt_scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template EVENTOBJ + * @private + */ +goog.events.EventHandler.prototype.listenOnce_ = function( + src, type, opt_fn, opt_capture, opt_scope) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + this.listenOnce_(src, type[i], opt_fn, opt_capture, opt_scope); + } + } else { + var listenerObj = goog.events.listenOnce( + src, type, opt_fn || this.handleEvent, opt_capture, + opt_scope || this.handler_ || this); + if (!listenerObj) { + // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT + // (goog.events.CaptureSimulationMode) in IE8-, it will return null + // value. + return this; + } + + var key = listenerObj.key; + this.keys_[key] = listenerObj; + } + + return this; +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.EventTarget}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.EventTarget} src The node to listen to + * events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener + * Callback method, or an object with a handleEvent function. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + */ +goog.events.EventHandler.prototype.listenWithWrapper = function( + src, wrapper, listener, opt_capt) { + // TODO(mknichel): Remove the opt_scope from this function and then + // templatize it. + return this.listenWithWrapper_(src, wrapper, listener, opt_capt); +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.EventTarget}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.EventTarget} src The node to listen to + * events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null} + * listener Optional callback function to be used as the + * listener or an object with handleEvent function. + * @param {boolean|undefined} capture Optional whether to use capture phase. + * @param {T} scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @template T + */ +goog.events.EventHandler.prototype.listenWithWrapperAndScope = function( + src, wrapper, listener, capture, scope) { + // TODO(mknichel): Deprecate this function. + return this.listenWithWrapper_(src, wrapper, listener, capture, scope); +}; + + +/** + * Adds an event listener with a specific event wrapper on a DOM Node or an + * object that has implemented {@link goog.events.EventTarget}. A listener can + * only be added once to an object. + * + * @param {EventTarget|goog.events.EventTarget} src The node to listen to + * events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback + * method, or an object with a handleEvent function. + * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to + * false). + * @param {Object=} opt_scope Element in whose scope to call the listener. + * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for + * chaining of calls. + * @private + */ +goog.events.EventHandler.prototype.listenWithWrapper_ = function( + src, wrapper, listener, opt_capt, opt_scope) { + wrapper.listen(src, listener, opt_capt, opt_scope || this.handler_ || this, + this); + return this; +}; + + +/** + * @return {number} Number of listeners registered by this handler. + */ +goog.events.EventHandler.prototype.getListenerCount = function() { + var count = 0; + for (var key in this.keys_) { + if (Object.prototype.hasOwnProperty.call(this.keys_, key)) { + count++; + } + } + return count; +}; + + +/** + * Unlistens on an event. + * @param {goog.events.ListenableType} src Event source. + * @param {string|Array<string>| + * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>} + * type Event type or array of event types to unlisten to. + * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn + * Optional callback function to be used as the listener or an object with + * handleEvent function. + * @param {boolean=} opt_capture Optional whether to use capture phase. + * @param {Object=} opt_scope Object in whose scope to call the listener. + * @return {!goog.events.EventHandler} This object, allowing for chaining of + * calls. + * @template EVENTOBJ + */ +goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn, + opt_capture, + opt_scope) { + if (goog.isArray(type)) { + for (var i = 0; i < type.length; i++) { + this.unlisten(src, type[i], opt_fn, opt_capture, opt_scope); + } + } else { + var listener = goog.events.getListener(src, type, + opt_fn || this.handleEvent, + opt_capture, opt_scope || this.handler_ || this); + + if (listener) { + goog.events.unlistenByKey(listener); + delete this.keys_[listener.key]; + } + } + + return this; +}; + + +/** + * Removes an event listener which was added with listenWithWrapper(). + * + * @param {EventTarget|goog.events.EventTarget} src The target to stop + * listening to events on. + * @param {goog.events.EventWrapper} wrapper Event wrapper to use. + * @param {function(?):?|{handleEvent:function(?):?}|null} listener The + * listener function to remove. + * @param {boolean=} opt_capt In DOM-compliant browsers, this determines + * whether the listener is fired during the capture or bubble phase of the + * event. + * @param {Object=} opt_scope Element in whose scope to call the listener. + * @return {!goog.events.EventHandler} This object, allowing for chaining of + * calls. + */ +goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper, + listener, opt_capt, opt_scope) { + wrapper.unlisten(src, listener, opt_capt, + opt_scope || this.handler_ || this, this); + return this; +}; + + +/** + * Unlistens to all events. + */ +goog.events.EventHandler.prototype.removeAll = function() { + goog.object.forEach(this.keys_, function(listenerObj, key) { + if (this.keys_.hasOwnProperty(key)) { + goog.events.unlistenByKey(listenerObj); + } + }, this); + + this.keys_ = {}; +}; + + +/** + * Disposes of this EventHandler and removes all listeners that it registered. + * @override + * @protected + */ +goog.events.EventHandler.prototype.disposeInternal = function() { + goog.events.EventHandler.superClass_.disposeInternal.call(this); + this.removeAll(); +}; + + +/** + * Default event handler + * @param {goog.events.Event} e Event object. + */ +goog.events.EventHandler.prototype.handleEvent = function(e) { + throw Error('EventHandler.handleEvent not implemented'); +}; + +// Copyright 2012 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Bidi utility functions. + * + */ + +goog.provide('goog.style.bidi'); + +goog.require('goog.dom'); +goog.require('goog.style'); +goog.require('goog.userAgent'); + + +/** + * Returns the normalized scrollLeft position for a scrolled element. + * @param {Element} element The scrolled element. + * @return {number} The number of pixels the element is scrolled. 0 indicates + * that the element is not scrolled at all (which, in general, is the + * left-most position in ltr and the right-most position in rtl). + */ +goog.style.bidi.getScrollLeft = function(element) { + var isRtl = goog.style.isRightToLeft(element); + if (isRtl && goog.userAgent.GECKO) { + // ScrollLeft starts at 0 and then goes negative as the element is scrolled + // towards the left. + return -element.scrollLeft; + } else if (isRtl && + !(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8'))) { + // ScrollLeft starts at the maximum positive value and decreases towards + // 0 as the element is scrolled towards the left. However, for overflow + // visible, there is no scrollLeft and the value always stays correctly at 0 + var overflowX = goog.style.getComputedOverflowX(element); + if (overflowX == 'visible') { + return element.scrollLeft; + } else { + return element.scrollWidth - element.clientWidth - element.scrollLeft; + } + } + // ScrollLeft behavior is identical in rtl and ltr, it starts at 0 and + // increases as the element is scrolled away from the start. + return element.scrollLeft; +}; + + +/** + * Returns the "offsetStart" of an element, analagous to offsetLeft but + * normalized for right-to-left environments and various browser + * inconsistencies. This value returned can always be passed to setScrollOffset + * to scroll to an element's left edge in a left-to-right offsetParent or + * right edge in a right-to-left offsetParent. + * + * For example, here offsetStart is 10px in an LTR environment and 5px in RTL: + * + * <pre> + * | xxxxxxxxxx | + * ^^^^^^^^^^ ^^^^ ^^^^^ + * 10px elem 5px + * </pre> + * + * If an element is positioned before the start of its offsetParent, the + * startOffset may be negative. This can be used with setScrollOffset to + * reliably scroll to an element: + * + * <pre> + * var scrollOffset = goog.style.bidi.getOffsetStart(element); + * goog.style.bidi.setScrollOffset(element.offsetParent, scrollOffset); + * </pre> + * + * @see setScrollOffset + * + * @param {Element} element The element for which we need to determine the + * offsetStart position. + * @return {number} The offsetStart for that element. + */ +goog.style.bidi.getOffsetStart = function(element) { + element = /** @type {!HTMLElement} */ (element); + var offsetLeftForReal = element.offsetLeft; + + // The element might not have an offsetParent. + // For example, the node might not be attached to the DOM tree, + // and position:fixed children do not have an offset parent. + // Just try to do the best we can with what we have. + var bestParent = element.offsetParent; + + if (!bestParent && goog.style.getComputedPosition(element) == 'fixed') { + bestParent = goog.dom.getOwnerDocument(element).documentElement; + } + + // Just give up in this case. + if (!bestParent) { + return offsetLeftForReal; + } + + if (goog.userAgent.GECKO) { + // When calculating an element's offsetLeft, Firefox erroneously subtracts + // the border width from the actual distance. So we need to add it back. + var borderWidths = goog.style.getBorderBox(bestParent); + offsetLeftForReal += borderWidths.left; + } else if (goog.userAgent.isDocumentModeOrHigher(8) && + !goog.userAgent.isDocumentModeOrHigher(9)) { + // When calculating an element's offsetLeft, IE8/9-Standards Mode + // erroneously adds the border width to the actual distance. So we need to + // subtract it. + var borderWidths = goog.style.getBorderBox(bestParent); + offsetLeftForReal -= borderWidths.left; + } + + if (goog.style.isRightToLeft(bestParent)) { + // Right edge of the element relative to the left edge of its parent. + var elementRightOffset = offsetLeftForReal + element.offsetWidth; + + // Distance from the parent's right edge to the element's right edge. + return bestParent.clientWidth - elementRightOffset; + } + + return offsetLeftForReal; +}; + + +/** + * Sets the element's scrollLeft attribute so it is correctly scrolled by + * offsetStart pixels. This takes into account whether the element is RTL and + * the nuances of different browsers. To scroll to the "beginning" of an + * element use getOffsetStart to obtain the element's offsetStart value and then + * pass the value to setScrollOffset. + * @see getOffsetStart + * @param {Element} element The element to set scrollLeft on. + * @param {number} offsetStart The number of pixels to scroll the element. + * If this value is < 0, 0 is used. + */ +goog.style.bidi.setScrollOffset = function(element, offsetStart) { + offsetStart = Math.max(offsetStart, 0); + // In LTR and in "mirrored" browser RTL (such as IE), we set scrollLeft to + // the number of pixels to scroll. + // Otherwise, in RTL, we need to account for different browser behavior. + if (!goog.style.isRightToLeft(element)) { + element.scrollLeft = offsetStart; + } else if (goog.userAgent.GECKO) { + // Negative scroll-left positions in RTL. + element.scrollLeft = -offsetStart; + } else if (!(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8'))) { + // Take the current scrollLeft value and move to the right by the + // offsetStart to get to the left edge of the element, and then by + // the clientWidth of the element to get to the right edge. + element.scrollLeft = + element.scrollWidth - offsetStart - element.clientWidth; + } else { + element.scrollLeft = offsetStart; + } +}; + + +/** + * Sets the element's left style attribute in LTR or right style attribute in + * RTL. Also clears the left attribute in RTL and the right attribute in LTR. + * @param {Element} elem The element to position. + * @param {number} left The left position in LTR; will be set as right in RTL. + * @param {?number} top The top position. If null only the left/right is set. + * @param {boolean} isRtl Whether we are in RTL mode. + */ +goog.style.bidi.setPosition = function(elem, left, top, isRtl) { + if (!goog.isNull(top)) { + elem.style.top = top + 'px'; + } + if (isRtl) { + elem.style.right = left + 'px'; + elem.style.left = ''; + } else { + elem.style.left = left + 'px'; + elem.style.right = ''; + } +}; + +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Drag Utilities. + * + * Provides extensible functionality for drag & drop behaviour. + * + * @see ../demos/drag.html + * @see ../demos/dragger.html + */ + + +goog.provide('goog.fx.DragEvent'); +goog.provide('goog.fx.Dragger'); +goog.provide('goog.fx.Dragger.EventType'); + +goog.require('goog.dom'); +goog.require('goog.dom.TagName'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventHandler'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('goog.math.Coordinate'); +goog.require('goog.math.Rect'); +goog.require('goog.style'); +goog.require('goog.style.bidi'); +goog.require('goog.userAgent'); + + + +/** + * A class that allows mouse or touch-based dragging (moving) of an element + * + * @param {Element} target The element that will be dragged. + * @param {Element=} opt_handle An optional handle to control the drag, if null + * the target is used. + * @param {goog.math.Rect=} opt_limits Object containing left, top, width, + * and height. + * + * @extends {goog.events.EventTarget} + * @constructor + * @struct + */ +goog.fx.Dragger = function(target, opt_handle, opt_limits) { + goog.fx.Dragger.base(this, 'constructor'); + + /** + * Reference to drag target element. + * @type {?Element} + */ + this.target = target; + + /** + * Reference to the handler that initiates the drag. + * @type {?Element} + */ + this.handle = opt_handle || target; + + /** + * Object representing the limits of the drag region. + * @type {goog.math.Rect} + */ + this.limits = opt_limits || new goog.math.Rect(NaN, NaN, NaN, NaN); + + /** + * Reference to a document object to use for the events. + * @private {Document} + */ + this.document_ = goog.dom.getOwnerDocument(target); + + /** @private {!goog.events.EventHandler} */ + this.eventHandler_ = new goog.events.EventHandler(this); + this.registerDisposable(this.eventHandler_); + + /** + * Whether the element is rendered right-to-left. We initialize this lazily. + * @private {boolean|undefined}} + */ + this.rightToLeft_; + + /** + * Current x position of mouse or touch relative to viewport. + * @type {number} + */ + this.clientX = 0; + + /** + * Current y position of mouse or touch relative to viewport. + * @type {number} + */ + this.clientY = 0; + + /** + * Current x position of mouse or touch relative to screen. Deprecated because + * it doesn't take into affect zoom level or pixel density. + * @type {number} + * @deprecated Consider switching to clientX instead. + */ + this.screenX = 0; + + /** + * Current y position of mouse or touch relative to screen. Deprecated because + * it doesn't take into affect zoom level or pixel density. + * @type {number} + * @deprecated Consider switching to clientY instead. + */ + this.screenY = 0; + + /** + * The x position where the first mousedown or touchstart occurred. + * @type {number} + */ + this.startX = 0; + + /** + * The y position where the first mousedown or touchstart occurred. + * @type {number} + */ + this.startY = 0; + + /** + * Current x position of drag relative to target's parent. + * @type {number} + */ + this.deltaX = 0; + + /** + * Current y position of drag relative to target's parent. + * @type {number} + */ + this.deltaY = 0; + + /** + * The current page scroll value. + * @type {?goog.math.Coordinate} + */ + this.pageScroll; + + /** + * Whether dragging is currently enabled. + * @private {boolean} + */ + this.enabled_ = true; + + /** + * Whether object is currently being dragged. + * @private {boolean} + */ + this.dragging_ = false; + + /** + * Whether mousedown should be default prevented. + * @private {boolean} + **/ + this.preventMouseDown_ = true; + + /** + * The amount of distance, in pixels, after which a mousedown or touchstart is + * considered a drag. + * @private {number} + */ + this.hysteresisDistanceSquared_ = 0; + + /** + * The SCROLL event target used to make drag element follow scrolling. + * @private {?EventTarget} + */ + this.scrollTarget_; + + /** + * Whether IE drag events cancelling is on. + * @private {boolean} + */ + this.ieDragStartCancellingOn_ = false; + + /** + * Whether the dragger implements the changes described in http://b/6324964, + * making it truly RTL. This is a temporary flag to allow clients to + * transition to the new behavior at their convenience. At some point it will + * be the default. + * @private {boolean} + */ + this.useRightPositioningForRtl_ = false; + + // Add listener. Do not use the event handler here since the event handler is + // used for listeners added and removed during the drag operation. + goog.events.listen(this.handle, + [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN], + this.startDrag, false, this); +}; +goog.inherits(goog.fx.Dragger, goog.events.EventTarget); +// Dragger is meant to be extended, but defines most properties on its +// prototype, thus making it unsuitable for sealing. +goog.tagUnsealableClass(goog.fx.Dragger); + + +/** + * Whether setCapture is supported by the browser. + * @type {boolean} + * @private + */ +goog.fx.Dragger.HAS_SET_CAPTURE_ = + // IE and Gecko after 1.9.3 has setCapture + // WebKit does not yet: https://bugs.webkit.org/show_bug.cgi?id=27330 + goog.userAgent.IE || + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.3'); + + +/** + * Creates copy of node being dragged. This is a utility function to be used + * wherever it is inappropriate for the original source to follow the mouse + * cursor itself. + * + * @param {Element} sourceEl Element to copy. + * @return {!Element} The clone of {@code sourceEl}. + */ +goog.fx.Dragger.cloneNode = function(sourceEl) { + var clonedEl = /** @type {Element} */ (sourceEl.cloneNode(true)), + origTexts = sourceEl.getElementsByTagName(goog.dom.TagName.TEXTAREA), + dragTexts = clonedEl.getElementsByTagName(goog.dom.TagName.TEXTAREA); + // Cloning does not copy the current value of textarea elements, so correct + // this manually. + for (var i = 0; i < origTexts.length; i++) { + dragTexts[i].value = origTexts[i].value; + } + switch (sourceEl.tagName) { + case goog.dom.TagName.TR: + return goog.dom.createDom(goog.dom.TagName.TABLE, null, + goog.dom.createDom(goog.dom.TagName.TBODY, + null, clonedEl)); + case goog.dom.TagName.TD: + case goog.dom.TagName.TH: + return goog.dom.createDom( + goog.dom.TagName.TABLE, null, goog.dom.createDom( + goog.dom.TagName.TBODY, null, goog.dom.createDom( + goog.dom.TagName.TR, null, clonedEl))); + case goog.dom.TagName.TEXTAREA: + clonedEl.value = sourceEl.value; + default: + return clonedEl; + } +}; + + +/** + * Constants for event names. + * @enum {string} + */ +goog.fx.Dragger.EventType = { + // The drag action was canceled before the START event. Possible reasons: + // disabled dragger, dragging with the right mouse button or releasing the + // button before reaching the hysteresis distance. + EARLY_CANCEL: 'earlycancel', + START: 'start', + BEFOREDRAG: 'beforedrag', + DRAG: 'drag', + END: 'end' +}; + + +/** + * Turns on/off true RTL behavior. This should be called immediately after + * construction. This is a temporary flag to allow clients to transition + * to the new component at their convenience. At some point true will be the + * default. + * @param {boolean} useRightPositioningForRtl True if "right" should be used for + * positioning, false if "left" should be used for positioning. + */ +goog.fx.Dragger.prototype.enableRightPositioningForRtl = + function(useRightPositioningForRtl) { + this.useRightPositioningForRtl_ = useRightPositioningForRtl; +}; + + +/** + * Returns the event handler, intended for subclass use. + * @return {!goog.events.EventHandler<T>} The event handler. + * @this {T} + * @template T + */ +goog.fx.Dragger.prototype.getHandler = function() { + // TODO(user): templated "this" values currently result in "this" being + // "unknown" in the body of the function. + var self = /** @type {goog.fx.Dragger} */ (this); + return self.eventHandler_; +}; + + +/** + * Sets (or reset) the Drag limits after a Dragger is created. + * @param {goog.math.Rect?} limits Object containing left, top, width, + * height for new Dragger limits. If target is right-to-left and + * enableRightPositioningForRtl(true) is called, then rect is interpreted as + * right, top, width, and height. + */ +goog.fx.Dragger.prototype.setLimits = function(limits) { + this.limits = limits || new goog.math.Rect(NaN, NaN, NaN, NaN); +}; + + +/** + * Sets the distance the user has to drag the element before a drag operation is + * started. + * @param {number} distance The number of pixels after which a mousedown and + * move is considered a drag. + */ +goog.fx.Dragger.prototype.setHysteresis = function(distance) { + this.hysteresisDistanceSquared_ = Math.pow(distance, 2); +}; + + +/** + * Gets the distance the user has to drag the element before a drag operation is + * started. + * @return {number} distance The number of pixels after which a mousedown and + * move is considered a drag. + */ +goog.fx.Dragger.prototype.getHysteresis = function() { + return Math.sqrt(this.hysteresisDistanceSquared_); +}; + + +/** + * Sets the SCROLL event target to make drag element follow scrolling. + * + * @param {EventTarget} scrollTarget The event target that dispatches SCROLL + * events. + */ +goog.fx.Dragger.prototype.setScrollTarget = function(scrollTarget) { + this.scrollTarget_ = scrollTarget; +}; + + +/** + * Enables cancelling of built-in IE drag events. + * @param {boolean} cancelIeDragStart Whether to enable cancelling of IE + * dragstart event. + */ +goog.fx.Dragger.prototype.setCancelIeDragStart = function(cancelIeDragStart) { + this.ieDragStartCancellingOn_ = cancelIeDragStart; +}; + + +/** + * @return {boolean} Whether the dragger is enabled. + */ +goog.fx.Dragger.prototype.getEnabled = function() { + return this.enabled_; +}; + + +/** + * Set whether dragger is enabled + * @param {boolean} enabled Whether dragger is enabled. + */ +goog.fx.Dragger.prototype.setEnabled = function(enabled) { + this.enabled_ = enabled; +}; + + +/** + * Set whether mousedown should be default prevented. + * @param {boolean} preventMouseDown Whether mousedown should be default + * prevented. + */ +goog.fx.Dragger.prototype.setPreventMouseDown = function(preventMouseDown) { + this.preventMouseDown_ = preventMouseDown; +}; + + +/** @override */ +goog.fx.Dragger.prototype.disposeInternal = function() { + goog.fx.Dragger.superClass_.disposeInternal.call(this); + goog.events.unlisten(this.handle, + [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN], + this.startDrag, false, this); + this.cleanUpAfterDragging_(); + + this.target = null; + this.handle = null; +}; + + +/** + * Whether the DOM element being manipulated is rendered right-to-left. + * @return {boolean} True if the DOM element is rendered right-to-left, false + * otherwise. + * @private + */ +goog.fx.Dragger.prototype.isRightToLeft_ = function() { + if (!goog.isDef(this.rightToLeft_)) { + this.rightToLeft_ = goog.style.isRightToLeft(this.target); + } + return this.rightToLeft_; +}; + + +/** + * Event handler that is used to start the drag + * @param {goog.events.BrowserEvent} e Event object. + */ +goog.fx.Dragger.prototype.startDrag = function(e) { + var isMouseDown = e.type == goog.events.EventType.MOUSEDOWN; + + // Dragger.startDrag() can be called by AbstractDragDrop with a mousemove + // event and IE does not report pressed mouse buttons on mousemove. Also, + // it does not make sense to check for the button if the user is already + // dragging. + + if (this.enabled_ && !this.dragging_ && + (!isMouseDown || e.isMouseActionButton())) { + if (this.hysteresisDistanceSquared_ == 0) { + if (this.fireDragStart_(e)) { + this.dragging_ = true; + if (this.preventMouseDown_) { + e.preventDefault(); + } + } else { + // If the start drag is cancelled, don't setup for a drag. + return; + } + } else if (this.preventMouseDown_) { + // Need to preventDefault for hysteresis to prevent page getting selected. + e.preventDefault(); + } + this.setupDragHandlers(); + + this.clientX = this.startX = e.clientX; + this.clientY = this.startY = e.clientY; + this.screenX = e.screenX; + this.screenY = e.screenY; + this.computeInitialPosition(); + this.pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll(); + } else { + this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL); + } +}; + + +/** + * Sets up event handlers when dragging starts. + * @protected + */ +goog.fx.Dragger.prototype.setupDragHandlers = function() { + var doc = this.document_; + var docEl = doc.documentElement; + // Use bubbling when we have setCapture since we got reports that IE has + // problems with the capturing events in combination with setCapture. + var useCapture = !goog.fx.Dragger.HAS_SET_CAPTURE_; + + this.eventHandler_.listen(doc, + [goog.events.EventType.TOUCHMOVE, goog.events.EventType.MOUSEMOVE], + this.handleMove_, useCapture); + this.eventHandler_.listen(doc, + [goog.events.EventType.TOUCHEND, goog.events.EventType.MOUSEUP], + this.endDrag, useCapture); + + if (goog.fx.Dragger.HAS_SET_CAPTURE_) { + docEl.setCapture(false); + this.eventHandler_.listen(docEl, + goog.events.EventType.LOSECAPTURE, + this.endDrag); + } else { + // Make sure we stop the dragging if the window loses focus. + // Don't use capture in this listener because we only want to end the drag + // if the actual window loses focus. Since blur events do not bubble we use + // a bubbling listener on the window. + this.eventHandler_.listen(goog.dom.getWindow(doc), + goog.events.EventType.BLUR, + this.endDrag); + } + + if (goog.userAgent.IE && this.ieDragStartCancellingOn_) { + // Cancel IE's 'ondragstart' event. + this.eventHandler_.listen(doc, goog.events.EventType.DRAGSTART, + goog.events.Event.preventDefault); + } + + if (this.scrollTarget_) { + this.eventHandler_.listen(this.scrollTarget_, goog.events.EventType.SCROLL, + this.onScroll_, useCapture); + } +}; + + +/** + * Fires a goog.fx.Dragger.EventType.START event. + * @param {goog.events.BrowserEvent} e Browser event that triggered the drag. + * @return {boolean} False iff preventDefault was called on the DragEvent. + * @private + */ +goog.fx.Dragger.prototype.fireDragStart_ = function(e) { + return this.dispatchEvent(new goog.fx.DragEvent( + goog.fx.Dragger.EventType.START, this, e.clientX, e.clientY, e)); +}; + + +/** + * Unregisters the event handlers that are only active during dragging, and + * releases mouse capture. + * @private + */ +goog.fx.Dragger.prototype.cleanUpAfterDragging_ = function() { + this.eventHandler_.removeAll(); + if (goog.fx.Dragger.HAS_SET_CAPTURE_) { + this.document_.releaseCapture(); + } +}; + + +/** + * Event handler that is used to end the drag. + * @param {goog.events.BrowserEvent} e Event object. + * @param {boolean=} opt_dragCanceled Whether the drag has been canceled. + */ +goog.fx.Dragger.prototype.endDrag = function(e, opt_dragCanceled) { + this.cleanUpAfterDragging_(); + + if (this.dragging_) { + this.dragging_ = false; + + var x = this.limitX(this.deltaX); + var y = this.limitY(this.deltaY); + var dragCanceled = opt_dragCanceled || + e.type == goog.events.EventType.TOUCHCANCEL; + this.dispatchEvent(new goog.fx.DragEvent( + goog.fx.Dragger.EventType.END, this, e.clientX, e.clientY, e, x, y, + dragCanceled)); + } else { + this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL); + } +}; + + +/** + * Event handler that is used to end the drag by cancelling it. + * @param {goog.events.BrowserEvent} e Event object. + */ +goog.fx.Dragger.prototype.endDragCancel = function(e) { + this.endDrag(e, true); +}; + + +/** + * Event handler that is used on mouse / touch move to update the drag + * @param {goog.events.BrowserEvent} e Event object. + * @private + */ +goog.fx.Dragger.prototype.handleMove_ = function(e) { + if (this.enabled_) { + // dx in right-to-left cases is relative to the right. + var sign = this.useRightPositioningForRtl_ && + this.isRightToLeft_() ? -1 : 1; + var dx = sign * (e.clientX - this.clientX); + var dy = e.clientY - this.clientY; + this.clientX = e.clientX; + this.clientY = e.clientY; + this.screenX = e.screenX; + this.screenY = e.screenY; + + if (!this.dragging_) { + var diffX = this.startX - this.clientX; + var diffY = this.startY - this.clientY; + var distance = diffX * diffX + diffY * diffY; + if (distance > this.hysteresisDistanceSquared_) { + if (this.fireDragStart_(e)) { + this.dragging_ = true; + } else { + // DragListGroup disposes of the dragger if BEFOREDRAGSTART is + // canceled. + if (!this.isDisposed()) { + this.endDrag(e); + } + return; + } + } + } + + var pos = this.calculatePosition_(dx, dy); + var x = pos.x; + var y = pos.y; + + if (this.dragging_) { + + var rv = this.dispatchEvent(new goog.fx.DragEvent( + goog.fx.Dragger.EventType.BEFOREDRAG, this, e.clientX, e.clientY, + e, x, y)); + + // Only do the defaultAction and dispatch drag event if predrag didn't + // prevent default + if (rv) { + this.doDrag(e, x, y, false); + e.preventDefault(); + } + } + } +}; + + +/** + * Calculates the drag position. + * + * @param {number} dx The horizontal movement delta. + * @param {number} dy The vertical movement delta. + * @return {!goog.math.Coordinate} The newly calculated drag element position. + * @private + */ +goog.fx.Dragger.prototype.calculatePosition_ = function(dx, dy) { + // Update the position for any change in body scrolling + var pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll(); + dx += pageScroll.x - this.pageScroll.x; + dy += pageScroll.y - this.pageScroll.y; + this.pageScroll = pageScroll; + + this.deltaX += dx; + this.deltaY += dy; + + var x = this.limitX(this.deltaX); + var y = this.limitY(this.deltaY); + return new goog.math.Coordinate(x, y); +}; + + +/** + * Event handler for scroll target scrolling. + * @param {goog.events.BrowserEvent} e The event. + * @private + */ +goog.fx.Dragger.prototype.onScroll_ = function(e) { + var pos = this.calculatePosition_(0, 0); + e.clientX = this.clientX; + e.clientY = this.clientY; + this.doDrag(e, pos.x, pos.y, true); +}; + + +/** + * @param {goog.events.BrowserEvent} e The closure object + * representing the browser event that caused a drag event. + * @param {number} x The new horizontal position for the drag element. + * @param {number} y The new vertical position for the drag element. + * @param {boolean} dragFromScroll Whether dragging was caused by scrolling + * the associated scroll target. + * @protected + */ +goog.fx.Dragger.prototype.doDrag = function(e, x, y, dragFromScroll) { + this.defaultAction(x, y); + this.dispatchEvent(new goog.fx.DragEvent( + goog.fx.Dragger.EventType.DRAG, this, e.clientX, e.clientY, e, x, y)); +}; + + +/** + * Returns the 'real' x after limits are applied (allows for some + * limits to be undefined). + * @param {number} x X-coordinate to limit. + * @return {number} The 'real' X-coordinate after limits are applied. + */ +goog.fx.Dragger.prototype.limitX = function(x) { + var rect = this.limits; + var left = !isNaN(rect.left) ? rect.left : null; + var width = !isNaN(rect.width) ? rect.width : 0; + var maxX = left != null ? left + width : Infinity; + var minX = left != null ? left : -Infinity; + return Math.min(maxX, Math.max(minX, x)); +}; + + +/** + * Returns the 'real' y after limits are applied (allows for some + * limits to be undefined). + * @param {number} y Y-coordinate to limit. + * @return {number} The 'real' Y-coordinate after limits are applied. + */ +goog.fx.Dragger.prototype.limitY = function(y) { + var rect = this.limits; + var top = !isNaN(rect.top) ? rect.top : null; + var height = !isNaN(rect.height) ? rect.height : 0; + var maxY = top != null ? top + height : Infinity; + var minY = top != null ? top : -Infinity; + return Math.min(maxY, Math.max(minY, y)); +}; + + +/** + * Overridable function for computing the initial position of the target + * before dragging begins. + * @protected + */ +goog.fx.Dragger.prototype.computeInitialPosition = function() { + this.deltaX = this.useRightPositioningForRtl_ ? + goog.style.bidi.getOffsetStart(this.target) : + /** @type {!HTMLElement} */ (this.target).offsetLeft; + this.deltaY = /** @type {!HTMLElement} */ (this.target).offsetTop; +}; + + +/** + * Overridable function for handling the default action of the drag behaviour. + * Normally this is simply moving the element to x,y though in some cases it + * might be used to resize the layer. This is basically a shortcut to + * implementing a default ondrag event handler. + * @param {number} x X-coordinate for target element. In right-to-left, x this + * is the number of pixels the target should be moved to from the right. + * @param {number} y Y-coordinate for target element. + */ +goog.fx.Dragger.prototype.defaultAction = function(x, y) { + if (this.useRightPositioningForRtl_ && this.isRightToLeft_()) { + this.target.style.right = x + 'px'; + } else { + this.target.style.left = x + 'px'; + } + this.target.style.top = y + 'px'; +}; + + +/** + * @return {boolean} Whether the dragger is currently in the midst of a drag. + */ +goog.fx.Dragger.prototype.isDragging = function() { + return this.dragging_; +}; + + + +/** + * Object representing a drag event + * @param {string} type Event type. + * @param {goog.fx.Dragger} dragobj Drag object initiating event. + * @param {number} clientX X-coordinate relative to the viewport. + * @param {number} clientY Y-coordinate relative to the viewport. + * @param {goog.events.BrowserEvent} browserEvent The closure object + * representing the browser event that caused this drag event. + * @param {number=} opt_actX Optional actual x for drag if it has been limited. + * @param {number=} opt_actY Optional actual y for drag if it has been limited. + * @param {boolean=} opt_dragCanceled Whether the drag has been canceled. + * @constructor + * @struct + * @extends {goog.events.Event} + */ +goog.fx.DragEvent = function(type, dragobj, clientX, clientY, browserEvent, + opt_actX, opt_actY, opt_dragCanceled) { + goog.events.Event.call(this, type); + + /** + * X-coordinate relative to the viewport + * @type {number} + */ + this.clientX = clientX; + + /** + * Y-coordinate relative to the viewport + * @type {number} + */ + this.clientY = clientY; + + /** + * The closure object representing the browser event that caused this drag + * event. + * @type {goog.events.BrowserEvent} + */ + this.browserEvent = browserEvent; + + /** + * The real x-position of the drag if it has been limited + * @type {number} + */ + this.left = goog.isDef(opt_actX) ? opt_actX : dragobj.deltaX; + + /** + * The real y-position of the drag if it has been limited + * @type {number} + */ + this.top = goog.isDef(opt_actY) ? opt_actY : dragobj.deltaY; + + /** + * Reference to the drag object for this event + * @type {goog.fx.Dragger} + */ + this.dragger = dragobj; + + /** + * Whether drag was canceled with this event. Used to differentiate between + * a legitimate drag END that can result in an action and a drag END which is + * a result of a drag cancelation. For now it can happen 1) with drag END + * event on FireFox when user drags the mouse out of the window, 2) with + * drag END event on IE7 which is generated on MOUSEMOVE event when user + * moves the mouse into the document after the mouse button has been + * released, 3) when TOUCHCANCEL is raised instead of TOUCHEND (on touch + * events). + * @type {boolean} + */ + this.dragCanceled = !!opt_dragCanceled; +}; +goog.inherits(goog.fx.DragEvent, goog.events.Event); + +// FIXME should possibly show tooltip when dragging? + +goog.provide('ol.control.ZoomSlider'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.fx.DragEvent'); +goog.require('goog.fx.Dragger'); +goog.require('goog.fx.Dragger.EventType'); +goog.require('goog.math.Rect'); +goog.require('goog.style'); +goog.require('ol.Size'); +goog.require('ol.ViewHint'); +goog.require('ol.animation'); +goog.require('ol.control.Control'); +goog.require('ol.css'); +goog.require('ol.easing'); +goog.require('ol.math'); + + + +/** + * @classdesc + * A slider type of control for zooming. + * + * Example: + * + * map.addControl(new ol.control.ZoomSlider()); + * + * @constructor + * @extends {ol.control.Control} + * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options. + * @api stable + */ +ol.control.ZoomSlider = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + /** + * Will hold the current resolution of the view. + * + * @type {number|undefined} + * @private + */ + this.currentResolution_ = undefined; + + /** + * The direction of the slider. Will be determined from actual display of the + * container and defaults to ol.control.ZoomSlider.direction.VERTICAL. + * + * @type {ol.control.ZoomSlider.direction} + * @private + */ + this.direction_ = ol.control.ZoomSlider.direction.VERTICAL; + + /** + * The calculated thumb size (border box plus margins). Set when initSlider_ + * is called. + * @type {ol.Size} + * @private + */ + this.thumbSize_ = null; + + /** + * Whether the slider is initialized. + * @type {boolean} + * @private + */ + this.sliderInitialized_ = false; + + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 200; + + var className = options.className ? options.className : 'ol-zoomslider'; + var thumbElement = goog.dom.createDom('BUTTON', { + 'type': 'button', + 'class': className + '-thumb ' + ol.css.CLASS_UNSELECTABLE + }); + var containerElement = goog.dom.createDom('DIV', + [className, ol.css.CLASS_UNSELECTABLE, ol.css.CLASS_CONTROL], + thumbElement); + + /** + * @type {goog.fx.Dragger} + * @private + */ + this.dragger_ = new goog.fx.Dragger(thumbElement); + this.registerDisposable(this.dragger_); + + goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START, + this.handleDraggerStart_, false, this); + goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG, + this.handleDraggerDrag_, false, this); + goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END, + this.handleDraggerEnd_, false, this); + + goog.events.listen(containerElement, goog.events.EventType.CLICK, + this.handleContainerClick_, false, this); + goog.events.listen(thumbElement, goog.events.EventType.CLICK, + goog.events.Event.stopPropagation); + + var render = options.render ? options.render : ol.control.ZoomSlider.render; + + goog.base(this, { + element: containerElement, + render: render + }); +}; +goog.inherits(ol.control.ZoomSlider, ol.control.Control); + + +/** + * The enum for available directions. + * + * @enum {number} + */ +ol.control.ZoomSlider.direction = { + VERTICAL: 0, + HORIZONTAL: 1 +}; + + +/** + * @inheritDoc + */ +ol.control.ZoomSlider.prototype.setMap = function(map) { + goog.base(this, 'setMap', map); + if (map) { + map.render(); + } +}; + + +/** + * Initializes the slider element. This will determine and set this controls + * direction_ and also constrain the dragging of the thumb to always be within + * the bounds of the container. + * + * @private + */ +ol.control.ZoomSlider.prototype.initSlider_ = function() { + var container = this.element; + var containerSize = goog.style.getSize(container); + + var thumb = goog.dom.getFirstElementChild(container); + var thumbMargins = goog.style.getMarginBox(thumb); + var thumbBorderBoxSize = goog.style.getBorderBoxSize(thumb); + var thumbWidth = thumbBorderBoxSize.width + + thumbMargins.right + thumbMargins.left; + var thumbHeight = thumbBorderBoxSize.height + + thumbMargins.top + thumbMargins.bottom; + this.thumbSize_ = [thumbWidth, thumbHeight]; + + var width = containerSize.width - thumbWidth; + var height = containerSize.height - thumbHeight; + + var limits; + if (containerSize.width > containerSize.height) { + this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL; + limits = new goog.math.Rect(0, 0, width, 0); + } else { + this.direction_ = ol.control.ZoomSlider.direction.VERTICAL; + limits = new goog.math.Rect(0, 0, 0, height); + } + this.dragger_.setLimits(limits); + this.sliderInitialized_ = true; +}; + + +/** + * Update the zoomslider element. + * @param {ol.MapEvent} mapEvent Map event. + * @this {ol.control.ZoomSlider} + * @api + */ +ol.control.ZoomSlider.render = function(mapEvent) { + if (!mapEvent.frameState) { + return; + } + goog.asserts.assert(mapEvent.frameState.viewState, + 'viewState should be defined'); + if (!this.sliderInitialized_) { + this.initSlider_(); + } + var res = mapEvent.frameState.viewState.resolution; + if (res !== this.currentResolution_) { + this.currentResolution_ = res; + this.setThumbPosition_(res); + } +}; + + +/** + * @param {goog.events.BrowserEvent} browserEvent The browser event to handle. + * @private + */ +ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) { + var map = this.getMap(); + var view = map.getView(); + var currentResolution = view.getResolution(); + goog.asserts.assert(currentResolution, + 'currentResolution should be defined'); + map.beforeRender(ol.animation.zoom({ + resolution: currentResolution, + duration: this.duration_, + easing: ol.easing.easeOut + })); + var relativePosition = this.getRelativePosition_( + browserEvent.offsetX - this.thumbSize_[0] / 2, + browserEvent.offsetY - this.thumbSize_[1] / 2); + var resolution = this.getResolutionForPosition_(relativePosition); + view.setResolution(view.constrainResolution(resolution)); +}; + + +/** + * Handle dragger start events. + * @param {goog.fx.DragEvent} event The drag event. + * @private + */ +ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) { + this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1); +}; + + +/** + * Handle dragger drag events. + * + * @param {goog.fx.DragEvent} event The drag event. + * @private + */ +ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) { + var relativePosition = this.getRelativePosition_(event.left, event.top); + this.currentResolution_ = this.getResolutionForPosition_(relativePosition); + this.getMap().getView().setResolution(this.currentResolution_); +}; + + +/** + * Handle dragger end events. + * @param {goog.fx.DragEvent} event The drag event. + * @private + */ +ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) { + var map = this.getMap(); + var view = map.getView(); + view.setHint(ol.ViewHint.INTERACTING, -1); + goog.asserts.assert(this.currentResolution_, + 'this.currentResolution_ should be defined'); + map.beforeRender(ol.animation.zoom({ + resolution: this.currentResolution_, + duration: this.duration_, + easing: ol.easing.easeOut + })); + var resolution = view.constrainResolution(this.currentResolution_); + view.setResolution(resolution); +}; + + +/** + * Positions the thumb inside its container according to the given resolution. + * + * @param {number} res The res. + * @private + */ +ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) { + var position = this.getPositionForResolution_(res); + var dragger = this.dragger_; + var thumb = goog.dom.getFirstElementChild(this.element); + + if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) { + var left = dragger.limits.left + dragger.limits.width * position; + goog.style.setPosition(thumb, left); + } else { + var top = dragger.limits.top + dragger.limits.height * position; + goog.style.setPosition(thumb, dragger.limits.left, top); + } +}; + + +/** + * Calculates the relative position of the thumb given x and y offsets. The + * relative position scales from 0 to 1. The x and y offsets are assumed to be + * in pixel units within the dragger limits. + * + * @param {number} x Pixel position relative to the left of the slider. + * @param {number} y Pixel position relative to the top of the slider. + * @return {number} The relative position of the thumb. + * @private + */ +ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) { + var draggerLimits = this.dragger_.limits; + var amount; + if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) { + amount = (x - draggerLimits.left) / draggerLimits.width; + } else { + amount = (y - draggerLimits.top) / draggerLimits.height; + } + return ol.math.clamp(amount, 0, 1); +}; + + +/** + * Calculates the corresponding resolution of the thumb given its relative + * position (where 0 is the minimum and 1 is the maximum). + * + * @param {number} position The relative position of the thumb. + * @return {number} The corresponding resolution. + * @private + */ +ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) { + var fn = this.getMap().getView().getResolutionForValueFunction(); + return fn(1 - position); +}; + + +/** + * Determines the relative position of the slider for the given resolution. A + * relative position of 0 corresponds to the minimum view resolution. A + * relative position of 1 corresponds to the maximum view resolution. + * + * @param {number} res The resolution. + * @return {number} The relative position value (between 0 and 1). + * @private + */ +ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) { + var fn = this.getMap().getView().getValueForResolutionFunction(); + return 1 - fn(res); +}; + +goog.provide('ol.control.ZoomToExtent'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.control.Control'); +goog.require('ol.css'); + + + +/** + * @classdesc + * A button control which, when pressed, changes the map view to a specific + * extent. To style this control use the css selector `.ol-zoom-extent`. + * + * @constructor + * @extends {ol.control.Control} + * @param {olx.control.ZoomToExtentOptions=} opt_options Options. + * @api stable + */ +ol.control.ZoomToExtent = function(opt_options) { + var options = opt_options ? opt_options : {}; + + /** + * @type {ol.Extent} + * @private + */ + this.extent_ = options.extent ? options.extent : null; + + var className = options.className ? options.className : + 'ol-zoom-extent'; + + var label = options.label ? options.label : 'E'; + var tipLabel = options.tipLabel ? + options.tipLabel : 'Fit to extent'; + var button = goog.dom.createDom('BUTTON', { + 'type': 'button', + 'title': tipLabel + }, label); + + goog.events.listen(button, goog.events.EventType.CLICK, + this.handleClick_, false, this); + + var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + + ol.css.CLASS_CONTROL; + var element = goog.dom.createDom('DIV', cssClasses, button); + + goog.base(this, { + element: element, + target: options.target + }); +}; +goog.inherits(ol.control.ZoomToExtent, ol.control.Control); + + +/** + * @param {goog.events.BrowserEvent} event The event to handle + * @private + */ +ol.control.ZoomToExtent.prototype.handleClick_ = function(event) { + event.preventDefault(); + this.handleZoomToExtent_(); +}; + + +/** + * @private + */ +ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() { + var map = this.getMap(); + var view = map.getView(); + var extent = !this.extent_ ? + view.getProjection().getExtent() : this.extent_; + var size = map.getSize(); + goog.asserts.assert(size, 'size should be defined'); + view.fit(extent, size); +}; + +goog.provide('ol.DeviceOrientation'); +goog.provide('ol.DeviceOrientationProperty'); + +goog.require('goog.events'); +goog.require('ol'); +goog.require('ol.Object'); +goog.require('ol.has'); +goog.require('ol.math'); + + +/** + * @enum {string} + */ +ol.DeviceOrientationProperty = { + ALPHA: 'alpha', + BETA: 'beta', + GAMMA: 'gamma', + HEADING: 'heading', + TRACKING: 'tracking' +}; + + + +/** + * @classdesc + * The ol.DeviceOrientation class provides access to information from + * DeviceOrientation events. See the [HTML 5 DeviceOrientation Specification]( + * http://www.w3.org/TR/orientation-event/) for more details. + * + * Many new computers, and especially mobile phones + * and tablets, provide hardware support for device orientation. Web + * developers targeting mobile devices will be especially interested in this + * class. + * + * Device orientation data are relative to a common starting point. For mobile + * devices, the starting point is to lay your phone face up on a table with the + * top of the phone pointing north. This represents the zero state. All + * angles are then relative to this state. For computers, it is the same except + * the screen is open at 90 degrees. + * + * Device orientation is reported as three angles - `alpha`, `beta`, and + * `gamma` - relative to the starting position along the three planar axes X, Y + * and Z. The X axis runs from the left edge to the right edge through the + * middle of the device. Similarly, the Y axis runs from the bottom to the top + * of the device through the middle. The Z axis runs from the back to the front + * through the middle. In the starting position, the X axis points to the + * right, the Y axis points away from you and the Z axis points straight up + * from the device lying flat. + * + * The three angles representing the device orientation are relative to the + * three axes. `alpha` indicates how much the device has been rotated around the + * Z axis, which is commonly interpreted as the compass heading (see note + * below). `beta` indicates how much the device has been rotated around the X + * axis, or how much it is tilted from front to back. `gamma` indicates how + * much the device has been rotated around the Y axis, or how much it is tilted + * from left to right. + * + * For most browsers, the `alpha` value returns the compass heading so if the + * device points north, it will be 0. With Safari on iOS, the 0 value of + * `alpha` is calculated from when device orientation was first requested. + * ol.DeviceOrientation provides the `heading` property which normalizes this + * behavior across all browsers for you. + * + * It is important to note that the HTML 5 DeviceOrientation specification + * indicates that `alpha`, `beta` and `gamma` are in degrees while the + * equivalent properties in ol.DeviceOrientation are in radians for consistency + * with all other uses of angles throughout OpenLayers. + * + * @see http://www.w3.org/TR/orientation-event/ + * + * To get notified of device orientation changes, register a listener for the + * generic `change` event on your `ol.DeviceOrientation` instance. + * + * @constructor + * @extends {ol.Object} + * @param {olx.DeviceOrientationOptions=} opt_options Options. + * @api + */ +ol.DeviceOrientation = function(opt_options) { + + goog.base(this); + + var options = opt_options ? opt_options : {}; + + /** + * @private + * @type {goog.events.Key} + */ + this.listenerKey_ = null; + + goog.events.listen(this, + ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING), + this.handleTrackingChanged_, false, this); + + this.setTracking(options.tracking !== undefined ? options.tracking : false); + +}; +goog.inherits(ol.DeviceOrientation, ol.Object); + + +/** + * @inheritDoc + */ +ol.DeviceOrientation.prototype.disposeInternal = function() { + this.setTracking(false); + goog.base(this, 'disposeInternal'); +}; + + +/** + * @private + * @param {goog.events.BrowserEvent} browserEvent Event. + */ +ol.DeviceOrientation.prototype.orientationChange_ = function(browserEvent) { + var event = /** @type {DeviceOrientationEvent} */ + (browserEvent.getBrowserEvent()); + if (event.alpha !== null) { + var alpha = ol.math.toRadians(event.alpha); + this.set(ol.DeviceOrientationProperty.ALPHA, alpha); + // event.absolute is undefined in iOS. + if (goog.isBoolean(event.absolute) && event.absolute) { + this.set(ol.DeviceOrientationProperty.HEADING, alpha); + } else if (goog.isNumber(event.webkitCompassHeading) && + event.webkitCompassAccuracy != -1) { + var heading = ol.math.toRadians(event.webkitCompassHeading); + this.set(ol.DeviceOrientationProperty.HEADING, heading); + } + } + if (event.beta !== null) { + this.set(ol.DeviceOrientationProperty.BETA, + ol.math.toRadians(event.beta)); + } + if (event.gamma !== null) { + this.set(ol.DeviceOrientationProperty.GAMMA, + ol.math.toRadians(event.gamma)); + } + this.changed(); +}; + + +/** + * Rotation around the device z-axis (in radians). + * @return {number|undefined} The euler angle in radians of the device from the + * standard Z axis. + * @observable + * @api + */ +ol.DeviceOrientation.prototype.getAlpha = function() { + return /** @type {number|undefined} */ ( + this.get(ol.DeviceOrientationProperty.ALPHA)); +}; + + +/** + * Rotation around the device x-axis (in radians). + * @return {number|undefined} The euler angle in radians of the device from the + * planar X axis. + * @observable + * @api + */ +ol.DeviceOrientation.prototype.getBeta = function() { + return /** @type {number|undefined} */ ( + this.get(ol.DeviceOrientationProperty.BETA)); +}; + + +/** + * Rotation around the device y-axis (in radians). + * @return {number|undefined} The euler angle in radians of the device from the + * planar Y axis. + * @observable + * @api + */ +ol.DeviceOrientation.prototype.getGamma = function() { + return /** @type {number|undefined} */ ( + this.get(ol.DeviceOrientationProperty.GAMMA)); +}; + + +/** + * The heading of the device relative to north (in radians). + * @return {number|undefined} The heading of the device relative to north, in + * radians, normalizing for different browser behavior. + * @observable + * @api + */ +ol.DeviceOrientation.prototype.getHeading = function() { + return /** @type {number|undefined} */ ( + this.get(ol.DeviceOrientationProperty.HEADING)); +}; + + +/** + * Determine if orientation is being tracked. + * @return {boolean} Changes in device orientation are being tracked. + * @observable + * @api + */ +ol.DeviceOrientation.prototype.getTracking = function() { + return /** @type {boolean} */ ( + this.get(ol.DeviceOrientationProperty.TRACKING)); +}; + + +/** + * @private + */ +ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() { + if (ol.has.DEVICE_ORIENTATION) { + var tracking = this.getTracking(); + if (tracking && !this.listenerKey_) { + this.listenerKey_ = goog.events.listen(goog.global, 'deviceorientation', + this.orientationChange_, false, this); + } else if (!tracking && this.listenerKey_) { + goog.events.unlistenByKey(this.listenerKey_); + this.listenerKey_ = null; + } + } +}; + + +/** + * Enable or disable tracking of device orientation events. + * @param {boolean} tracking The status of tracking changes to alpha, beta and + * gamma. If true, changes are tracked and reported immediately. + * @observable + * @api + */ +ol.DeviceOrientation.prototype.setTracking = function(tracking) { + this.set(ol.DeviceOrientationProperty.TRACKING, tracking); +}; + +goog.provide('ol.format.Feature'); + +goog.require('ol.geom.Geometry'); +goog.require('ol.proj'); + + + +/** + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for feature formats. + * {ol.format.Feature} subclasses provide the ability to decode and encode + * {@link ol.Feature} objects from a variety of commonly used geospatial + * file formats. See the documentation for each format for more details. + * + * @constructor + * @api stable + */ +ol.format.Feature = function() { + + /** + * @protected + * @type {ol.proj.Projection} + */ + this.defaultDataProjection = null; + +}; + + +/** + * @return {Array.<string>} Extensions. + */ +ol.format.Feature.prototype.getExtensions = goog.abstractMethod; + + +/** + * Adds the data projection to the read options. + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Options. + * @return {olx.format.ReadOptions|undefined} Options. + * @protected + */ +ol.format.Feature.prototype.getReadOptions = function(source, opt_options) { + var options; + if (opt_options) { + options = { + dataProjection: opt_options.dataProjection ? + opt_options.dataProjection : this.readProjection(source), + featureProjection: opt_options.featureProjection + }; + } + return this.adaptOptions(options); +}; + + +/** + * Sets the `defaultDataProjection` on the options, if no `dataProjection` + * is set. + * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options + * Options. + * @protected + * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined} + * Updated options. + */ +ol.format.Feature.prototype.adaptOptions = function(options) { + var updatedOptions; + if (options) { + updatedOptions = { + featureProjection: options.featureProjection, + dataProjection: options.dataProjection ? + options.dataProjection : this.defaultDataProjection, + rightHanded: options.rightHanded + }; + } + return updatedOptions; +}; + + +/** + * @return {ol.format.FormatType} Format. + */ +ol.format.Feature.prototype.getType = goog.abstractMethod; + + +/** + * Read a single feature from a source. + * + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + */ +ol.format.Feature.prototype.readFeature = goog.abstractMethod; + + +/** + * Read all features from a source. + * + * @param {Document|Node|ArrayBuffer|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + */ +ol.format.Feature.prototype.readFeatures = goog.abstractMethod; + + +/** + * Read a single geometry from a source. + * + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.Feature.prototype.readGeometry = goog.abstractMethod; + + +/** + * Read the projection from a source. + * + * @param {Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. + */ +ol.format.Feature.prototype.readProjection = goog.abstractMethod; + + +/** + * Encode a feature in this format. + * + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} Result. + */ +ol.format.Feature.prototype.writeFeature = goog.abstractMethod; + + +/** + * Encode an array of features in this format. + * + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} Result. + */ +ol.format.Feature.prototype.writeFeatures = goog.abstractMethod; + + +/** + * Write a single geometry in this format. + * + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} Result. + */ +ol.format.Feature.prototype.writeGeometry = goog.abstractMethod; + + +/** + * @param {ol.geom.Geometry|ol.Extent} geometry Geometry. + * @param {boolean} write Set to true for writing, false for reading. + * @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options + * Options. + * @return {ol.geom.Geometry|ol.Extent} Transformed geometry. + * @protected + */ +ol.format.Feature.transformWithOptions = function( + geometry, write, opt_options) { + var featureProjection = opt_options ? + ol.proj.get(opt_options.featureProjection) : null; + var dataProjection = opt_options ? + ol.proj.get(opt_options.dataProjection) : null; + if (featureProjection && dataProjection && + !ol.proj.equivalent(featureProjection, dataProjection)) { + if (geometry instanceof ol.geom.Geometry) { + return (write ? geometry.clone() : geometry).transform( + write ? featureProjection : dataProjection, + write ? dataProjection : featureProjection); + } else { + // FIXME this is necessary because ol.format.GML treats extents + // as geometries + return ol.proj.transformExtent( + write ? geometry.slice() : geometry, + write ? featureProjection : dataProjection, + write ? dataProjection : featureProjection); + } + } else { + return geometry; + } +}; + +goog.provide('ol.format.JSONFeature'); + +goog.require('goog.asserts'); +goog.require('goog.json'); +goog.require('ol.format.Feature'); +goog.require('ol.format.FormatType'); + + + +/** + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for JSON feature formats. + * + * @constructor + * @extends {ol.format.Feature} + */ +ol.format.JSONFeature = function() { + goog.base(this); +}; +goog.inherits(ol.format.JSONFeature, ol.format.Feature); + + +/** + * @param {Document|Node|Object|string} source Source. + * @private + * @return {Object} Object. + */ +ol.format.JSONFeature.prototype.getObject_ = function(source) { + if (goog.isObject(source)) { + return source; + } else if (goog.isString(source)) { + var object = goog.json.parse(source); + return object ? object : null; + } else { + goog.asserts.fail(); + return null; + } +}; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.getType = function() { + return ol.format.FormatType.JSON; +}; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.readFeature = function(source, opt_options) { + return this.readFeatureFromObject( + this.getObject_(source), this.getReadOptions(source, opt_options)); +}; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) { + return this.readFeaturesFromObject( + this.getObject_(source), this.getReadOptions(source, opt_options)); +}; + + +/** + * @param {Object} object Object. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @protected + * @return {ol.Feature} Feature. + */ +ol.format.JSONFeature.prototype.readFeatureFromObject = goog.abstractMethod; + + +/** + * @param {Object} object Object. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @protected + * @return {Array.<ol.Feature>} Features. + */ +ol.format.JSONFeature.prototype.readFeaturesFromObject = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) { + return this.readGeometryFromObject( + this.getObject_(source), this.getReadOptions(source, opt_options)); +}; + + +/** + * @param {Object} object Object. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @protected + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.JSONFeature.prototype.readGeometryFromObject = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.readProjection = function(source) { + return this.readProjectionFromObject(this.getObject_(source)); +}; + + +/** + * @param {Object} object Object. + * @protected + * @return {ol.proj.Projection} Projection. + */ +ol.format.JSONFeature.prototype.readProjectionFromObject = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) { + return goog.json.serialize(this.writeFeatureObject(feature, opt_options)); +}; + + +/** + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} Object. + */ +ol.format.JSONFeature.prototype.writeFeatureObject = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.writeFeatures = function( + features, opt_options) { + return goog.json.serialize(this.writeFeaturesObject(features, opt_options)); +}; + + +/** + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} Object. + */ +ol.format.JSONFeature.prototype.writeFeaturesObject = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.JSONFeature.prototype.writeGeometry = function( + geometry, opt_options) { + return goog.json.serialize(this.writeGeometryObject(geometry, opt_options)); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} Object. + */ +ol.format.JSONFeature.prototype.writeGeometryObject = goog.abstractMethod; + +goog.provide('ol.geom.flat.interpolate'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.math'); + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} fraction Fraction. + * @param {Array.<number>=} opt_dest Destination. + * @return {Array.<number>} Destination. + */ +ol.geom.flat.interpolate.lineString = + function(flatCoordinates, offset, end, stride, fraction, opt_dest) { + // FIXME interpolate extra dimensions + goog.asserts.assert(0 <= fraction && fraction <= 1, + 'fraction should be in between 0 and 1'); + var pointX = NaN; + var pointY = NaN; + var n = (end - offset) / stride; + if (n === 0) { + goog.asserts.fail('n cannot be 0'); + } else if (n == 1) { + pointX = flatCoordinates[offset]; + pointY = flatCoordinates[offset + 1]; + } else if (n == 2) { + pointX = (1 - fraction) * flatCoordinates[offset] + + fraction * flatCoordinates[offset + stride]; + pointY = (1 - fraction) * flatCoordinates[offset + 1] + + fraction * flatCoordinates[offset + stride + 1]; + } else { + var x1 = flatCoordinates[offset]; + var y1 = flatCoordinates[offset + 1]; + var length = 0; + var cumulativeLengths = [0]; + var i; + for (i = offset + stride; i < end; i += stride) { + var x2 = flatCoordinates[i]; + var y2 = flatCoordinates[i + 1]; + length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); + cumulativeLengths.push(length); + x1 = x2; + y1 = y2; + } + var target = fraction * length; + var index = goog.array.binarySearch(cumulativeLengths, target); + if (index < 0) { + var t = (target - cumulativeLengths[-index - 2]) / + (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]); + var o = offset + (-index - 2) * stride; + pointX = goog.math.lerp( + flatCoordinates[o], flatCoordinates[o + stride], t); + pointY = goog.math.lerp( + flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t); + } else { + pointX = flatCoordinates[offset + index * stride]; + pointY = flatCoordinates[offset + index * stride + 1]; + } + } + if (opt_dest) { + opt_dest[0] = pointX; + opt_dest[1] = pointY; + return opt_dest; + } else { + return [pointX, pointY]; + } +}; + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} m M. + * @param {boolean} extrapolate Extrapolate. + * @return {ol.Coordinate} Coordinate. + */ +ol.geom.flat.lineStringCoordinateAtM = + function(flatCoordinates, offset, end, stride, m, extrapolate) { + if (end == offset) { + return null; + } + var coordinate; + if (m < flatCoordinates[offset + stride - 1]) { + if (extrapolate) { + coordinate = flatCoordinates.slice(offset, offset + stride); + coordinate[stride - 1] = m; + return coordinate; + } else { + return null; + } + } else if (flatCoordinates[end - 1] < m) { + if (extrapolate) { + coordinate = flatCoordinates.slice(end - stride, end); + coordinate[stride - 1] = m; + return coordinate; + } else { + return null; + } + } + // FIXME use O(1) search + if (m == flatCoordinates[offset + stride - 1]) { + return flatCoordinates.slice(offset, offset + stride); + } + var lo = offset / stride; + var hi = end / stride; + while (lo < hi) { + var mid = (lo + hi) >> 1; + if (m < flatCoordinates[(mid + 1) * stride - 1]) { + hi = mid; + } else { + lo = mid + 1; + } + } + var m0 = flatCoordinates[lo * stride - 1]; + if (m == m0) { + return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride); + } + var m1 = flatCoordinates[(lo + 1) * stride - 1]; + goog.asserts.assert(m0 < m, 'm0 should be less than m'); + goog.asserts.assert(m <= m1, 'm should be less than or equal to m1'); + var t = (m - m0) / (m1 - m0); + coordinate = []; + var i; + for (i = 0; i < stride - 1; ++i) { + coordinate.push(goog.math.lerp(flatCoordinates[(lo - 1) * stride + i], + flatCoordinates[lo * stride + i], t)); + } + coordinate.push(m); + goog.asserts.assert(coordinate.length == stride, + 'length of coordinate array should match stride'); + return coordinate; +}; + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<number>} ends Ends. + * @param {number} stride Stride. + * @param {number} m M. + * @param {boolean} extrapolate Extrapolate. + * @param {boolean} interpolate Interpolate. + * @return {ol.Coordinate} Coordinate. + */ +ol.geom.flat.lineStringsCoordinateAtM = function( + flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) { + if (interpolate) { + return ol.geom.flat.lineStringCoordinateAtM( + flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate); + } + var coordinate; + if (m < flatCoordinates[stride - 1]) { + if (extrapolate) { + coordinate = flatCoordinates.slice(0, stride); + coordinate[stride - 1] = m; + return coordinate; + } else { + return null; + } + } + if (flatCoordinates[flatCoordinates.length - 1] < m) { + if (extrapolate) { + coordinate = flatCoordinates.slice(flatCoordinates.length - stride); + coordinate[stride - 1] = m; + return coordinate; + } else { + return null; + } + } + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + if (offset == end) { + continue; + } + if (m < flatCoordinates[offset + stride - 1]) { + return null; + } else if (m <= flatCoordinates[end - 1]) { + return ol.geom.flat.lineStringCoordinateAtM( + flatCoordinates, offset, end, stride, m, false); + } + offset = end; + } + goog.asserts.fail( + 'ol.geom.flat.lineStringsCoordinateAtM should have returned'); + return null; +}; + +goog.provide('ol.geom.flat.length'); + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {number} Length. + */ +ol.geom.flat.length.lineString = + function(flatCoordinates, offset, end, stride) { + var x1 = flatCoordinates[offset]; + var y1 = flatCoordinates[offset + 1]; + var length = 0; + var i; + for (i = offset + stride; i < end; i += stride) { + var x2 = flatCoordinates[i]; + var y2 = flatCoordinates[i + 1]; + length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); + x1 = x2; + y1 = y2; + } + return length; +}; + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {number} Perimeter. + */ +ol.geom.flat.length.linearRing = + function(flatCoordinates, offset, end, stride) { + var perimeter = + ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride); + var dx = flatCoordinates[end - stride] - flatCoordinates[offset]; + var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1]; + perimeter += Math.sqrt(dx * dx + dy * dy); + return perimeter; +}; + +goog.provide('ol.geom.LineString'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('ol'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.geom.flat.interpolate'); +goog.require('ol.geom.flat.intersectsextent'); +goog.require('ol.geom.flat.length'); +goog.require('ol.geom.flat.segments'); +goog.require('ol.geom.flat.simplify'); + + + +/** + * @classdesc + * Linestring geometry. + * + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.LineString = function(coordinates, opt_layout) { + + goog.base(this); + + /** + * @private + * @type {ol.Coordinate} + */ + this.flatMidpoint_ = null; + + /** + * @private + * @type {number} + */ + this.flatMidpointRevision_ = -1; + + /** + * @private + * @type {number} + */ + this.maxDelta_ = -1; + + /** + * @private + * @type {number} + */ + this.maxDeltaRevision_ = -1; + + this.setCoordinates(coordinates, opt_layout); + +}; +goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry); + + +/** + * Append the passed coordinate to the coordinates of the linestring. + * @param {ol.Coordinate} coordinate Coordinate. + * @api stable + */ +ol.geom.LineString.prototype.appendCoordinate = function(coordinate) { + goog.asserts.assert(coordinate.length == this.stride, + 'length of coordinate array should match stride'); + if (!this.flatCoordinates) { + this.flatCoordinates = coordinate.slice(); + } else { + goog.array.extend(this.flatCoordinates, coordinate); + } + this.changed(); +}; + + +/** + * Make a complete copy of the geometry. + * @return {!ol.geom.LineString} Clone. + * @api stable + */ +ol.geom.LineString.prototype.clone = function() { + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return lineString; +}; + + +/** + * @inheritDoc + */ +ol.geom.LineString.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + if (this.maxDeltaRevision_ != this.getRevision()) { + this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0)); + this.maxDeltaRevision_ = this.getRevision(); + } + return ol.geom.flat.closest.getClosestPoint( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + this.maxDelta_, false, x, y, closestPoint, minSquaredDistance); +}; + + +/** + * Iterate over each segment, calling the provided callback. + * If the callback returns a truthy value the function returns that + * value immediately. Otherwise the function returns `false`. + * + * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function + * called for each segment. + * @param {S=} opt_this The object to be used as the value of 'this' + * within callback. + * @return {T|boolean} Value. + * @template T,S + * @api + */ +ol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) { + return ol.geom.flat.segments.forEach(this.flatCoordinates, 0, + this.flatCoordinates.length, this.stride, callback, opt_this); +}; + + +/** + * Returns the coordinate at `m` using linear interpolation, or `null` if no + * such coordinate exists. + * + * `opt_extrapolate` controls extrapolation beyond the range of Ms in the + * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first + * M will return the first coordinate and Ms greater than the last M will + * return the last coordinate. + * + * @param {number} m M. + * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`. + * @return {ol.Coordinate} Coordinate. + * @api stable + */ +ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) { + if (this.layout != ol.geom.GeometryLayout.XYM && + this.layout != ol.geom.GeometryLayout.XYZM) { + return null; + } + var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false; + return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0, + this.flatCoordinates.length, this.stride, m, extrapolate); +}; + + +/** + * Return the coordinates of the linestring. + * @return {Array.<ol.Coordinate>} Coordinates. + * @api stable + */ +ol.geom.LineString.prototype.getCoordinates = function() { + return ol.geom.flat.inflate.coordinates( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); +}; + + +/** + * Return the length of the linestring on projected plane. + * @return {number} Length (on projected plane). + * @api stable + */ +ol.geom.LineString.prototype.getLength = function() { + return ol.geom.flat.length.lineString( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); +}; + + +/** + * @return {Array.<number>} Flat midpoint. + */ +ol.geom.LineString.prototype.getFlatMidpoint = function() { + if (this.flatMidpointRevision_ != this.getRevision()) { + this.flatMidpoint_ = ol.geom.flat.interpolate.lineString( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + 0.5, this.flatMidpoint_); + this.flatMidpointRevision_ = this.getRevision(); + } + return this.flatMidpoint_; +}; + + +/** + * @inheritDoc + */ +ol.geom.LineString.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + var simplifiedFlatCoordinates = []; + simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + squaredTolerance, simplifiedFlatCoordinates, 0); + var simplifiedLineString = new ol.geom.LineString(null); + simplifiedLineString.setFlatCoordinates( + ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates); + return simplifiedLineString; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.LineString.prototype.getType = function() { + return ol.geom.GeometryType.LINE_STRING; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.LineString.prototype.intersectsExtent = function(extent) { + return ol.geom.flat.intersectsextent.lineString( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, + extent); +}; + + +/** + * Set the coordinates of the linestring. + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.LineString.prototype.setCoordinates = + function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); + } else { + this.setLayout(opt_layout, coordinates, 1); + if (!this.flatCoordinates) { + this.flatCoordinates = []; + } + this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( + this.flatCoordinates, 0, coordinates, this.stride); + this.changed(); + } +}; + + +/** + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. + */ +ol.geom.LineString.prototype.setFlatCoordinates = + function(layout, flatCoordinates) { + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.changed(); +}; + +goog.provide('ol.geom.MultiLineString'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('ol'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.geom.flat.interpolate'); +goog.require('ol.geom.flat.intersectsextent'); +goog.require('ol.geom.flat.simplify'); + + + +/** + * @classdesc + * Multi-linestring geometry. + * + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.MultiLineString = function(coordinates, opt_layout) { + + goog.base(this); + + /** + * @type {Array.<number>} + * @private + */ + this.ends_ = []; + + /** + * @private + * @type {number} + */ + this.maxDelta_ = -1; + + /** + * @private + * @type {number} + */ + this.maxDeltaRevision_ = -1; + + this.setCoordinates(coordinates, opt_layout); + +}; +goog.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry); + + +/** + * Append the passed linestring to the multilinestring. + * @param {ol.geom.LineString} lineString LineString. + * @api stable + */ +ol.geom.MultiLineString.prototype.appendLineString = function(lineString) { + goog.asserts.assert(lineString.getLayout() == this.layout, + 'layout of lineString should match the layout'); + if (!this.flatCoordinates) { + this.flatCoordinates = lineString.getFlatCoordinates().slice(); + } else { + goog.array.extend( + this.flatCoordinates, lineString.getFlatCoordinates().slice()); + } + this.ends_.push(this.flatCoordinates.length); + this.changed(); +}; + + +/** + * Make a complete copy of the geometry. + * @return {!ol.geom.MultiLineString} Clone. + * @api stable + */ +ol.geom.MultiLineString.prototype.clone = function() { + var multiLineString = new ol.geom.MultiLineString(null); + multiLineString.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(), this.ends_.slice()); + return multiLineString; +}; + + +/** + * @inheritDoc + */ +ol.geom.MultiLineString.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + if (this.maxDeltaRevision_ != this.getRevision()) { + this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta( + this.flatCoordinates, 0, this.ends_, this.stride, 0)); + this.maxDeltaRevision_ = this.getRevision(); + } + return ol.geom.flat.closest.getsClosestPoint( + this.flatCoordinates, 0, this.ends_, this.stride, + this.maxDelta_, false, x, y, closestPoint, minSquaredDistance); +}; + + +/** + * Returns the coordinate at `m` using linear interpolation, or `null` if no + * such coordinate exists. + * + * `opt_extrapolate` controls extrapolation beyond the range of Ms in the + * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first + * M will return the first coordinate and Ms greater than the last M will + * return the last coordinate. + * + * `opt_interpolate` controls interpolation between consecutive LineStrings + * within the MultiLineString. If `opt_interpolate` is `true` the coordinates + * will be linearly interpolated between the last coordinate of one LineString + * and the first coordinate of the next LineString. If `opt_interpolate` is + * `false` then the function will return `null` for Ms falling between + * LineStrings. + * + * @param {number} m M. + * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`. + * @param {boolean=} opt_interpolate Interpolate. Default is `false`. + * @return {ol.Coordinate} Coordinate. + * @api stable + */ +ol.geom.MultiLineString.prototype.getCoordinateAtM = + function(m, opt_extrapolate, opt_interpolate) { + if ((this.layout != ol.geom.GeometryLayout.XYM && + this.layout != ol.geom.GeometryLayout.XYZM) || + this.flatCoordinates.length === 0) { + return null; + } + var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false; + var interpolate = opt_interpolate !== undefined ? opt_interpolate : false; + return ol.geom.flat.lineStringsCoordinateAtM(this.flatCoordinates, 0, + this.ends_, this.stride, m, extrapolate, interpolate); +}; + + +/** + * Return the coordinates of the multilinestring. + * @return {Array.<Array.<ol.Coordinate>>} Coordinates. + * @api stable + */ +ol.geom.MultiLineString.prototype.getCoordinates = function() { + return ol.geom.flat.inflate.coordinatess( + this.flatCoordinates, 0, this.ends_, this.stride); +}; + + +/** + * @return {Array.<number>} Ends. + */ +ol.geom.MultiLineString.prototype.getEnds = function() { + return this.ends_; +}; + + +/** + * Return the linestring at the specified index. + * @param {number} index Index. + * @return {ol.geom.LineString} LineString. + * @api stable + */ +ol.geom.MultiLineString.prototype.getLineString = function(index) { + goog.asserts.assert(0 <= index && index < this.ends_.length, + 'index should be in between 0 and length of the this.ends_ array'); + if (index < 0 || this.ends_.length <= index) { + return null; + } + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice( + index === 0 ? 0 : this.ends_[index - 1], this.ends_[index])); + return lineString; +}; + + +/** + * Return the linestrings of this multilinestring. + * @return {Array.<ol.geom.LineString>} LineStrings. + * @api stable + */ +ol.geom.MultiLineString.prototype.getLineStrings = function() { + var flatCoordinates = this.flatCoordinates; + var ends = this.ends_; + var layout = this.layout; + /** @type {Array.<ol.geom.LineString>} */ + var lineStrings = []; + var offset = 0; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end)); + lineStrings.push(lineString); + offset = end; + } + return lineStrings; +}; + + +/** + * @return {Array.<number>} Flat midpoints. + */ +ol.geom.MultiLineString.prototype.getFlatMidpoints = function() { + var midpoints = []; + var flatCoordinates = this.flatCoordinates; + var offset = 0; + var ends = this.ends_; + var stride = this.stride; + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + var end = ends[i]; + var midpoint = ol.geom.flat.interpolate.lineString( + flatCoordinates, offset, end, stride, 0.5); + goog.array.extend(midpoints, midpoint); + offset = end; + } + return midpoints; +}; + + +/** + * @inheritDoc + */ +ol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + var simplifiedFlatCoordinates = []; + var simplifiedEnds = []; + simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers( + this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance, + simplifiedFlatCoordinates, 0, simplifiedEnds); + var simplifiedMultiLineString = new ol.geom.MultiLineString(null); + simplifiedMultiLineString.setFlatCoordinates( + ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds); + return simplifiedMultiLineString; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.MultiLineString.prototype.getType = function() { + return ol.geom.GeometryType.MULTI_LINE_STRING; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) { + return ol.geom.flat.intersectsextent.lineStrings( + this.flatCoordinates, 0, this.ends_, this.stride, extent); +}; + + +/** + * Set the coordinates of the multilinestring. + * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.MultiLineString.prototype.setCoordinates = + function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_); + } else { + this.setLayout(opt_layout, coordinates, 2); + if (!this.flatCoordinates) { + this.flatCoordinates = []; + } + var ends = ol.geom.flat.deflate.coordinatess( + this.flatCoordinates, 0, coordinates, this.stride, this.ends_); + this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; + this.changed(); + } +}; + + +/** + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {Array.<number>} ends Ends. + */ +ol.geom.MultiLineString.prototype.setFlatCoordinates = + function(layout, flatCoordinates, ends) { + if (!flatCoordinates) { + goog.asserts.assert(ends && ends.length === 0, + 'ends must be truthy and ends.length should be 0'); + } else if (ends.length === 0) { + goog.asserts.assert(flatCoordinates.length === 0, + 'flatCoordinates should be an empty array'); + } else { + goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], + 'length of flatCoordinates array should match the last value of ends'); + } + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.ends_ = ends; + this.changed(); +}; + + +/** + * @param {Array.<ol.geom.LineString>} lineStrings LineStrings. + */ +ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) { + var layout = this.getLayout(); + var flatCoordinates = []; + var ends = []; + var i, ii; + for (i = 0, ii = lineStrings.length; i < ii; ++i) { + var lineString = lineStrings[i]; + if (i === 0) { + layout = lineString.getLayout(); + } else { + // FIXME better handle the case of non-matching layouts + goog.asserts.assert(lineString.getLayout() == layout, + 'layout of lineString should match layout'); + } + goog.array.extend(flatCoordinates, lineString.getFlatCoordinates()); + ends.push(flatCoordinates.length); + } + this.setFlatCoordinates(layout, flatCoordinates, ends); +}; + +goog.provide('ol.geom.MultiPoint'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.math'); + + + +/** + * @classdesc + * Multi-point geometry. + * + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.MultiPoint = function(coordinates, opt_layout) { + goog.base(this); + this.setCoordinates(coordinates, opt_layout); +}; +goog.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry); + + +/** + * Append the passed point to this multipoint. + * @param {ol.geom.Point} point Point. + * @api stable + */ +ol.geom.MultiPoint.prototype.appendPoint = function(point) { + goog.asserts.assert(point.getLayout() == this.layout, + 'the layout of point should match layout'); + if (!this.flatCoordinates) { + this.flatCoordinates = point.getFlatCoordinates().slice(); + } else { + goog.array.extend(this.flatCoordinates, point.getFlatCoordinates()); + } + this.changed(); +}; + + +/** + * Make a complete copy of the geometry. + * @return {!ol.geom.MultiPoint} Clone. + * @api stable + */ +ol.geom.MultiPoint.prototype.clone = function() { + var multiPoint = new ol.geom.MultiPoint(null); + multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return multiPoint; +}; + + +/** + * @inheritDoc + */ +ol.geom.MultiPoint.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + var flatCoordinates = this.flatCoordinates; + var stride = this.stride; + var i, ii, j; + for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { + var squaredDistance = ol.math.squaredDistance( + x, y, flatCoordinates[i], flatCoordinates[i + 1]); + if (squaredDistance < minSquaredDistance) { + minSquaredDistance = squaredDistance; + for (j = 0; j < stride; ++j) { + closestPoint[j] = flatCoordinates[i + j]; + } + closestPoint.length = stride; + } + } + return minSquaredDistance; +}; + + +/** + * Return the coordinates of the multipoint. + * @return {Array.<ol.Coordinate>} Coordinates. + * @api stable + */ +ol.geom.MultiPoint.prototype.getCoordinates = function() { + return ol.geom.flat.inflate.coordinates( + this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); +}; + + +/** + * Return the point at the specified index. + * @param {number} index Index. + * @return {ol.geom.Point} Point. + * @api stable + */ +ol.geom.MultiPoint.prototype.getPoint = function(index) { + var n = !this.flatCoordinates ? + 0 : this.flatCoordinates.length / this.stride; + goog.asserts.assert(0 <= index && index < n, + 'index should be in between 0 and n'); + if (index < 0 || n <= index) { + return null; + } + var point = new ol.geom.Point(null); + point.setFlatCoordinates(this.layout, this.flatCoordinates.slice( + index * this.stride, (index + 1) * this.stride)); + return point; +}; + + +/** + * Return the points of this multipoint. + * @return {Array.<ol.geom.Point>} Points. + * @api stable + */ +ol.geom.MultiPoint.prototype.getPoints = function() { + var flatCoordinates = this.flatCoordinates; + var layout = this.layout; + var stride = this.stride; + /** @type {Array.<ol.geom.Point>} */ + var points = []; + var i, ii; + for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { + var point = new ol.geom.Point(null); + point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride)); + points.push(point); + } + return points; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.MultiPoint.prototype.getType = function() { + return ol.geom.GeometryType.MULTI_POINT; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) { + var flatCoordinates = this.flatCoordinates; + var stride = this.stride; + var i, ii, x, y; + for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { + x = flatCoordinates[i]; + y = flatCoordinates[i + 1]; + if (ol.extent.containsXY(extent, x, y)) { + return true; + } + } + return false; +}; + + +/** + * Set the coordinates of the multipoint. + * @param {Array.<ol.Coordinate>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.MultiPoint.prototype.setCoordinates = + function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); + } else { + this.setLayout(opt_layout, coordinates, 1); + if (!this.flatCoordinates) { + this.flatCoordinates = []; + } + this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( + this.flatCoordinates, 0, coordinates, this.stride); + this.changed(); + } +}; + + +/** + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. + */ +ol.geom.MultiPoint.prototype.setFlatCoordinates = + function(layout, flatCoordinates) { + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.changed(); +}; + +goog.provide('ol.geom.flat.center'); + +goog.require('ol.extent'); + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.<Array.<number>>} endss Endss. + * @param {number} stride Stride. + * @return {Array.<number>} Flat centers. + */ +ol.geom.flat.center.linearRingss = + function(flatCoordinates, offset, endss, stride) { + var flatCenters = []; + var i, ii; + var extent = ol.extent.createEmpty(); + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + extent = ol.extent.createOrUpdateFromFlatCoordinates( + flatCoordinates, offset, ends[0], stride); + flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2); + offset = ends[ends.length - 1]; + } + return flatCenters; +}; + +goog.provide('ol.geom.MultiPolygon'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.Polygon'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.area'); +goog.require('ol.geom.flat.center'); +goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.contains'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.geom.flat.interiorpoint'); +goog.require('ol.geom.flat.intersectsextent'); +goog.require('ol.geom.flat.orient'); +goog.require('ol.geom.flat.simplify'); + + + +/** + * @classdesc + * Multi-polygon geometry. + * + * @constructor + * @extends {ol.geom.SimpleGeometry} + * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.MultiPolygon = function(coordinates, opt_layout) { + + goog.base(this); + + /** + * @type {Array.<Array.<number>>} + * @private + */ + this.endss_ = []; + + /** + * @private + * @type {number} + */ + this.flatInteriorPointsRevision_ = -1; + + /** + * @private + * @type {Array.<number>} + */ + this.flatInteriorPoints_ = null; + + /** + * @private + * @type {number} + */ + this.maxDelta_ = -1; + + /** + * @private + * @type {number} + */ + this.maxDeltaRevision_ = -1; + + /** + * @private + * @type {number} + */ + this.orientedRevision_ = -1; + + /** + * @private + * @type {Array.<number>} + */ + this.orientedFlatCoordinates_ = null; + + this.setCoordinates(coordinates, opt_layout); + +}; +goog.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry); + + +/** + * Append the passed polygon to this multipolygon. + * @param {ol.geom.Polygon} polygon Polygon. + * @api stable + */ +ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) { + goog.asserts.assert(polygon.getLayout() == this.layout, + 'layout of polygon should match layout'); + /** @type {Array.<number>} */ + var ends; + if (!this.flatCoordinates) { + this.flatCoordinates = polygon.getFlatCoordinates().slice(); + ends = polygon.getEnds().slice(); + this.endss_.push(); + } else { + var offset = this.flatCoordinates.length; + goog.array.extend(this.flatCoordinates, polygon.getFlatCoordinates()); + ends = polygon.getEnds().slice(); + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + ends[i] += offset; + } + } + this.endss_.push(ends); + this.changed(); +}; + + +/** + * Make a complete copy of the geometry. + * @return {!ol.geom.MultiPolygon} Clone. + * @api stable + */ +ol.geom.MultiPolygon.prototype.clone = function() { + var multiPolygon = new ol.geom.MultiPolygon(null); + var newEndss = /** @type {Array.<Array.<number>>} */ + (goog.object.unsafeClone(this.endss_)); + multiPolygon.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(), newEndss); + return multiPolygon; +}; + + +/** + * @inheritDoc + */ +ol.geom.MultiPolygon.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + if (this.maxDeltaRevision_ != this.getRevision()) { + this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta( + this.flatCoordinates, 0, this.endss_, this.stride, 0)); + this.maxDeltaRevision_ = this.getRevision(); + } + return ol.geom.flat.closest.getssClosestPoint( + this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, + this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); +}; + + +/** + * @inheritDoc + */ +ol.geom.MultiPolygon.prototype.containsXY = function(x, y) { + return ol.geom.flat.contains.linearRingssContainsXY( + this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y); +}; + + +/** + * Return the area of the multipolygon on projected plane. + * @return {number} Area (on projected plane). + * @api stable + */ +ol.geom.MultiPolygon.prototype.getArea = function() { + return ol.geom.flat.area.linearRingss( + this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride); +}; + + +/** + * Get the coordinate array for this geometry. This array has the structure + * of a GeoJSON coordinate array for multi-polygons. + * + * @param {boolean=} opt_right Orient coordinates according to the right-hand + * rule (counter-clockwise for exterior and clockwise for interior rings). + * If `false`, coordinates will be oriented according to the left-hand rule + * (clockwise for exterior and counter-clockwise for interior rings). + * By default, coordinate orientation will depend on how the geometry was + * constructed. + * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates. + * @api stable + */ +ol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) { + var flatCoordinates; + if (opt_right !== undefined) { + flatCoordinates = this.getOrientedFlatCoordinates().slice(); + ol.geom.flat.orient.orientLinearRingss( + flatCoordinates, 0, this.endss_, this.stride, opt_right); + } else { + flatCoordinates = this.flatCoordinates; + } + + return ol.geom.flat.inflate.coordinatesss( + flatCoordinates, 0, this.endss_, this.stride); +}; + + +/** + * @return {Array.<Array.<number>>} Endss. + */ +ol.geom.MultiPolygon.prototype.getEndss = function() { + return this.endss_; +}; + + +/** + * @return {Array.<number>} Flat interior points. + */ +ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() { + if (this.flatInteriorPointsRevision_ != this.getRevision()) { + var flatCenters = ol.geom.flat.center.linearRingss( + this.flatCoordinates, 0, this.endss_, this.stride); + this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss( + this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, + flatCenters); + this.flatInteriorPointsRevision_ = this.getRevision(); + } + return this.flatInteriorPoints_; +}; + + +/** + * Return the interior points as {@link ol.geom.MultiPoint multipoint}. + * @return {ol.geom.MultiPoint} Interior points. + * @api stable + */ +ol.geom.MultiPolygon.prototype.getInteriorPoints = function() { + var interiorPoints = new ol.geom.MultiPoint(null); + interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY, + this.getFlatInteriorPoints().slice()); + return interiorPoints; +}; + + +/** + * @return {Array.<number>} Oriented flat coordinates. + */ +ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() { + if (this.orientedRevision_ != this.getRevision()) { + var flatCoordinates = this.flatCoordinates; + if (ol.geom.flat.orient.linearRingssAreOriented( + flatCoordinates, 0, this.endss_, this.stride)) { + this.orientedFlatCoordinates_ = flatCoordinates; + } else { + this.orientedFlatCoordinates_ = flatCoordinates.slice(); + this.orientedFlatCoordinates_.length = + ol.geom.flat.orient.orientLinearRingss( + this.orientedFlatCoordinates_, 0, this.endss_, this.stride); + } + this.orientedRevision_ = this.getRevision(); + } + return this.orientedFlatCoordinates_; +}; + + +/** + * @inheritDoc + */ +ol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + var simplifiedFlatCoordinates = []; + var simplifiedEndss = []; + simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess( + this.flatCoordinates, 0, this.endss_, this.stride, + Math.sqrt(squaredTolerance), + simplifiedFlatCoordinates, 0, simplifiedEndss); + var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null); + simplifiedMultiPolygon.setFlatCoordinates( + ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss); + return simplifiedMultiPolygon; +}; + + +/** + * Return the polygon at the specified index. + * @param {number} index Index. + * @return {ol.geom.Polygon} Polygon. + * @api stable + */ +ol.geom.MultiPolygon.prototype.getPolygon = function(index) { + goog.asserts.assert(0 <= index && index < this.endss_.length, + 'index should be in between 0 and the length of this.endss_'); + if (index < 0 || this.endss_.length <= index) { + return null; + } + var offset; + if (index === 0) { + offset = 0; + } else { + var prevEnds = this.endss_[index - 1]; + offset = prevEnds[prevEnds.length - 1]; + } + var ends = this.endss_[index].slice(); + var end = ends[ends.length - 1]; + if (offset !== 0) { + var i, ii; + for (i = 0, ii = ends.length; i < ii; ++i) { + ends[i] -= offset; + } + } + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(offset, end), ends); + return polygon; +}; + + +/** + * Return the polygons of this multipolygon. + * @return {Array.<ol.geom.Polygon>} Polygons. + * @api stable + */ +ol.geom.MultiPolygon.prototype.getPolygons = function() { + var layout = this.layout; + var flatCoordinates = this.flatCoordinates; + var endss = this.endss_; + var polygons = []; + var offset = 0; + var i, ii, j, jj; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i].slice(); + var end = ends[ends.length - 1]; + if (offset !== 0) { + for (j = 0, jj = ends.length; j < jj; ++j) { + ends[j] -= offset; + } + } + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates( + layout, flatCoordinates.slice(offset, end), ends); + polygons.push(polygon); + offset = end; + } + return polygons; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.MultiPolygon.prototype.getType = function() { + return ol.geom.GeometryType.MULTI_POLYGON; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) { + return ol.geom.flat.intersectsextent.linearRingss( + this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent); +}; + + +/** + * Set the coordinates of the multipolygon. + * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api stable + */ +ol.geom.MultiPolygon.prototype.setCoordinates = + function(coordinates, opt_layout) { + if (!coordinates) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_); + } else { + this.setLayout(opt_layout, coordinates, 3); + if (!this.flatCoordinates) { + this.flatCoordinates = []; + } + var endss = ol.geom.flat.deflate.coordinatesss( + this.flatCoordinates, 0, coordinates, this.stride, this.endss_); + if (endss.length === 0) { + this.flatCoordinates.length = 0; + } else { + var lastEnds = endss[endss.length - 1]; + this.flatCoordinates.length = lastEnds.length === 0 ? + 0 : lastEnds[lastEnds.length - 1]; + } + this.changed(); + } +}; + + +/** + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {Array.<Array.<number>>} endss Endss. + */ +ol.geom.MultiPolygon.prototype.setFlatCoordinates = + function(layout, flatCoordinates, endss) { + goog.asserts.assert(endss, 'endss must be truthy'); + if (!flatCoordinates || flatCoordinates.length === 0) { + goog.asserts.assert(endss.length === 0, 'the length of endss should be 0'); + } else { + goog.asserts.assert(endss.length > 0, 'endss cannot be an empty array'); + var ends = endss[endss.length - 1]; + goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], + 'the length of flatCoordinates should be the last value of ends'); + } + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.endss_ = endss; + this.changed(); +}; + + +/** + * @param {Array.<ol.geom.Polygon>} polygons Polygons. + */ +ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) { + var layout = this.getLayout(); + var flatCoordinates = []; + var endss = []; + var i, ii, ends; + for (i = 0, ii = polygons.length; i < ii; ++i) { + var polygon = polygons[i]; + if (i === 0) { + layout = polygon.getLayout(); + } else { + // FIXME better handle the case of non-matching layouts + goog.asserts.assert(polygon.getLayout() == layout, + 'layout of polygon should be layout'); + } + var offset = flatCoordinates.length; + ends = polygon.getEnds(); + var j, jj; + for (j = 0, jj = ends.length; j < jj; ++j) { + ends[j] += offset; + } + goog.array.extend(flatCoordinates, polygon.getFlatCoordinates()); + endss.push(ends); + } + this.setFlatCoordinates(layout, flatCoordinates, endss); +}; + +goog.provide('ol.format.EsriJSON'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol.Feature'); +goog.require('ol.extent'); +goog.require('ol.format.Feature'); +goog.require('ol.format.JSONFeature'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.geom.flat.orient'); +goog.require('ol.proj'); + + + +/** + * @classdesc + * Feature format for reading and writing data in the EsriJSON format. + * + * @constructor + * @extends {ol.format.JSONFeature} + * @param {olx.format.EsriJSONOptions=} opt_options Options. + * @api + */ +ol.format.EsriJSON = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this); + + /** + * Name of the geometry attribute for features. + * @type {string|undefined} + * @private + */ + this.geometryName_ = options.geometryName; + +}; +goog.inherits(ol.format.EsriJSON, ol.format.JSONFeature); + + +/** + * @param {EsriJSONGeometry} object Object. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @private + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.EsriJSON.readGeometry_ = function(object, opt_options) { + if (!object) { + return null; + } + var type; + if (goog.isNumber(object.x) && goog.isNumber(object.y)) { + type = ol.geom.GeometryType.POINT; + } else if (object.points) { + type = ol.geom.GeometryType.MULTI_POINT; + } else if (object.paths) { + if (object.paths.length === 1) { + type = ol.geom.GeometryType.LINE_STRING; + } else { + type = ol.geom.GeometryType.MULTI_LINE_STRING; + } + } else if (object.rings) { + var layout = ol.format.EsriJSON.getGeometryLayout_(object); + var rings = ol.format.EsriJSON.convertRings_(object.rings, layout); + object = /** @type {EsriJSONGeometry} */(goog.object.clone(object)); + if (rings.length === 1) { + type = ol.geom.GeometryType.POLYGON; + object.rings = rings[0]; + } else { + type = ol.geom.GeometryType.MULTI_POLYGON; + object.rings = rings; + } + } + goog.asserts.assert(type, 'geometry type should be defined'); + var geometryReader = ol.format.EsriJSON.GEOMETRY_READERS_[type]; + goog.asserts.assert(geometryReader, + 'geometryReader should be defined'); + return /** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions( + geometryReader(object), false, opt_options)); +}; + + +/** + * Determines inner and outer rings. + * Checks if any polygons in this array contain any other polygons in this + * array. It is used for checking for holes. + * Logic inspired by: https://github.com/Esri/terraformer-arcgis-parser + * @param {Array.<!Array.<!Array.<number>>>} rings Rings. + * @param {ol.geom.GeometryLayout} layout Geometry layout. + * @private + * @return {Array.<!Array.<!Array.<number>>>} Transoformed rings. + */ +ol.format.EsriJSON.convertRings_ = function(rings, layout) { + var outerRings = []; + var holes = []; + var i, ii; + for (i = 0, ii = rings.length; i < ii; ++i) { + var flatRing = goog.array.flatten(rings[i]); + // is this ring an outer ring? is it clockwise? + var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0, + flatRing.length, layout.length); + if (clockwise) { + outerRings.push([rings[i]]); + } else { + holes.push(rings[i]); + } + } + while (holes.length) { + var hole = holes.shift(); + var matched = false; + // loop over all outer rings and see if they contain our hole. + for (i = outerRings.length - 1; i >= 0; i--) { + var outerRing = outerRings[i][0]; + if (ol.extent.containsExtent(new ol.geom.LinearRing( + outerRing).getExtent(), + new ol.geom.LinearRing(hole).getExtent())) { + // the hole is contained push it into our polygon + outerRings[i].push(hole); + matched = true; + break; + } + } + if (!matched) { + // no outer rings contain this hole turn it into and outer + // ring (reverse it) + outerRings.push([hole.reverse()]); + } + } + return outerRings; +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.Geometry} Point. + */ +ol.format.EsriJSON.readPointGeometry_ = function(object) { + goog.asserts.assert(goog.isNumber(object.x), 'object.x should be number'); + goog.asserts.assert(goog.isNumber(object.y), 'object.y should be number'); + var point; + if (object.m !== undefined && object.z !== undefined) { + point = new ol.geom.Point([object.x, object.y, object.z, object.m], + ol.geom.GeometryLayout.XYZM); + } else if (object.z !== undefined) { + point = new ol.geom.Point([object.x, object.y, object.z], + ol.geom.GeometryLayout.XYZ); + } else if (object.m !== undefined) { + point = new ol.geom.Point([object.x, object.y, object.m], + ol.geom.GeometryLayout.XYM); + } else { + point = new ol.geom.Point([object.x, object.y]); + } + return point; +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.Geometry} LineString. + */ +ol.format.EsriJSON.readLineStringGeometry_ = function(object) { + goog.asserts.assert(goog.isArray(object.paths), + 'object.paths should be an array'); + goog.asserts.assert(object.paths.length === 1, + 'object.paths array length should be 1'); + var layout = ol.format.EsriJSON.getGeometryLayout_(object); + return new ol.geom.LineString(object.paths[0], layout); +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.Geometry} MultiLineString. + */ +ol.format.EsriJSON.readMultiLineStringGeometry_ = function(object) { + goog.asserts.assert(goog.isArray(object.paths), + 'object.paths should be an array'); + goog.asserts.assert(object.paths.length > 1, + 'object.paths array length should be more than 1'); + var layout = ol.format.EsriJSON.getGeometryLayout_(object); + return new ol.geom.MultiLineString(object.paths, layout); +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.GeometryLayout} The geometry layout to use. + */ +ol.format.EsriJSON.getGeometryLayout_ = function(object) { + var layout = ol.geom.GeometryLayout.XY; + if (object.hasZ === true && object.hasM === true) { + layout = ol.geom.GeometryLayout.XYZM; + } else if (object.hasZ === true) { + layout = ol.geom.GeometryLayout.XYZ; + } else if (object.hasM === true) { + layout = ol.geom.GeometryLayout.XYM; + } + return layout; +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.Geometry} MultiPoint. + */ +ol.format.EsriJSON.readMultiPointGeometry_ = function(object) { + goog.asserts.assert(object.points, 'object.points should be defined'); + var layout = ol.format.EsriJSON.getGeometryLayout_(object); + return new ol.geom.MultiPoint(object.points, layout); +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.Geometry} MultiPolygon. + */ +ol.format.EsriJSON.readMultiPolygonGeometry_ = function(object) { + goog.asserts.assert(object.rings); + goog.asserts.assert(object.rings.length > 1, + 'object.rings should have length larger than 1'); + var layout = ol.format.EsriJSON.getGeometryLayout_(object); + return new ol.geom.MultiPolygon( + /** @type {Array.<Array.<Array.<Array.<number>>>>} */(object.rings), + layout); +}; + + +/** + * @param {EsriJSONGeometry} object Object. + * @private + * @return {ol.geom.Geometry} Polygon. + */ +ol.format.EsriJSON.readPolygonGeometry_ = function(object) { + goog.asserts.assert(object.rings); + var layout = ol.format.EsriJSON.getGeometryLayout_(object); + return new ol.geom.Polygon(object.rings, layout); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONGeometry} EsriJSON geometry. + */ +ol.format.EsriJSON.writePointGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.Point, + 'geometry should be an ol.geom.Point'); + var coordinates = geometry.getCoordinates(); + var layout = geometry.getLayout(); + if (layout === ol.geom.GeometryLayout.XYZ) { + return /** @type {EsriJSONPoint} */ ({ + x: coordinates[0], + y: coordinates[1], + z: coordinates[2] + }); + } else if (layout === ol.geom.GeometryLayout.XYM) { + return /** @type {EsriJSONPoint} */ ({ + x: coordinates[0], + y: coordinates[1], + m: coordinates[2] + }); + } else if (layout === ol.geom.GeometryLayout.XYZM) { + return /** @type {EsriJSONPoint} */ ({ + x: coordinates[0], + y: coordinates[1], + z: coordinates[2], + m: coordinates[3] + }); + } else if (layout === ol.geom.GeometryLayout.XY) { + return /** @type {EsriJSONPoint} */ ({ + x: coordinates[0], + y: coordinates[1] + }); + } else { + goog.asserts.fail('Unknown geometry layout'); + } +}; + + +/** + * @param {ol.geom.SimpleGeometry} geometry Geometry. + * @private + * @return {Object} Object with boolean hasZ and hasM keys. + */ +ol.format.EsriJSON.getHasZM_ = function(geometry) { + var layout = geometry.getLayout(); + return { + hasZ: (layout === ol.geom.GeometryLayout.XYZ || + layout === ol.geom.GeometryLayout.XYZM), + hasM: (layout === ol.geom.GeometryLayout.XYM || + layout === ol.geom.GeometryLayout.XYZM) + }; +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONPolyline} EsriJSON geometry. + */ +ol.format.EsriJSON.writeLineStringGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.LineString, + 'geometry should be an ol.geom.LineString'); + var hasZM = ol.format.EsriJSON.getHasZM_(geometry); + return /** @type {EsriJSONPolyline} */ ({ + hasZ: hasZM.hasZ, + hasM: hasZM.hasM, + paths: [geometry.getCoordinates()] + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONPolygon} EsriJSON geometry. + */ +ol.format.EsriJSON.writePolygonGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, + 'geometry should be an ol.geom.Polygon'); + // Esri geometries use the left-hand rule + var hasZM = ol.format.EsriJSON.getHasZM_(geometry); + return /** @type {EsriJSONPolygon} */ ({ + hasZ: hasZM.hasZ, + hasM: hasZM.hasM, + rings: geometry.getCoordinates(false) + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONPolyline} EsriJSON geometry. + */ +ol.format.EsriJSON.writeMultiLineStringGeometry_ = + function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, + 'geometry should be an ol.geom.MultiLineString'); + var hasZM = ol.format.EsriJSON.getHasZM_(geometry); + return /** @type {EsriJSONPolyline} */ ({ + hasZ: hasZM.hasZ, + hasM: hasZM.hasM, + paths: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONMultipoint} EsriJSON geometry. + */ +ol.format.EsriJSON.writeMultiPointGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, + 'geometry should be an ol.geom.MultiPoint'); + var hasZM = ol.format.EsriJSON.getHasZM_(geometry); + return /** @type {EsriJSONMultipoint} */ ({ + hasZ: hasZM.hasZ, + hasM: hasZM.hasM, + points: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONPolygon} EsriJSON geometry. + */ +ol.format.EsriJSON.writeMultiPolygonGeometry_ = function(geometry, + opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, + 'geometry should be an ol.geom.MultiPolygon'); + var hasZM = ol.format.EsriJSON.getHasZM_(geometry); + var coordinates = geometry.getCoordinates(false); + var output = []; + for (var i = 0; i < coordinates.length; i++) { + for (var x = coordinates[i].length - 1; x >= 0; x--) { + output.push(coordinates[i][x]); + } + } + return /** @type {EsriJSONPolygon} */ ({ + hasZ: hasZM.hasZ, + hasM: hasZM.hasM, + rings: output + }); +}; + + +/** + * @const + * @private + * @type {Object.<ol.geom.GeometryType, function(EsriJSONGeometry): ol.geom.Geometry>} + */ +ol.format.EsriJSON.GEOMETRY_READERS_ = {}; +ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POINT] = + ol.format.EsriJSON.readPointGeometry_; +ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.LINE_STRING] = + ol.format.EsriJSON.readLineStringGeometry_; +ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POLYGON] = + ol.format.EsriJSON.readPolygonGeometry_; +ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POINT] = + ol.format.EsriJSON.readMultiPointGeometry_; +ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_LINE_STRING] = + ol.format.EsriJSON.readMultiLineStringGeometry_; +ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POLYGON] = + ol.format.EsriJSON.readMultiPolygonGeometry_; + + +/** + * @const + * @private + * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (EsriJSONGeometry)>} + */ +ol.format.EsriJSON.GEOMETRY_WRITERS_ = {}; +ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POINT] = + ol.format.EsriJSON.writePointGeometry_; +ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.LINE_STRING] = + ol.format.EsriJSON.writeLineStringGeometry_; +ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POLYGON] = + ol.format.EsriJSON.writePolygonGeometry_; +ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POINT] = + ol.format.EsriJSON.writeMultiPointGeometry_; +ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_LINE_STRING] = + ol.format.EsriJSON.writeMultiLineStringGeometry_; +ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POLYGON] = + ol.format.EsriJSON.writeMultiPolygonGeometry_; + + +/** + * Read a feature from a EsriJSON Feature source. Only works for Feature, + * use `readFeatures` to read FeatureCollection source. + * + * @function + * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @api + */ +ol.format.EsriJSON.prototype.readFeature; + + +/** + * Read all features from a EsriJSON source. Works with both Feature and + * FeatureCollection sources. + * + * @function + * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api + */ +ol.format.EsriJSON.prototype.readFeatures; + + +/** + * @inheritDoc + */ +ol.format.EsriJSON.prototype.readFeatureFromObject = function( + object, opt_options) { + var esriJSONFeature = /** @type {EsriJSONFeature} */ (object); + goog.asserts.assert(esriJSONFeature.geometry || + esriJSONFeature.attributes, + 'geometry or attributes should be defined'); + var geometry = ol.format.EsriJSON.readGeometry_(esriJSONFeature.geometry, + opt_options); + var feature = new ol.Feature(); + if (this.geometryName_) { + feature.setGeometryName(this.geometryName_); + } + feature.setGeometry(geometry); + if (opt_options && opt_options.idField && + esriJSONFeature.attributes[opt_options.idField]) { + goog.asserts.assert( + goog.isNumber(esriJSONFeature.attributes[opt_options.idField]), + 'objectIdFieldName value should be a number'); + feature.setId(/** @type {number} */( + esriJSONFeature.attributes[opt_options.idField])); + } + if (esriJSONFeature.attributes) { + feature.setProperties(esriJSONFeature.attributes); + } + return feature; +}; + + +/** + * @inheritDoc + */ +ol.format.EsriJSON.prototype.readFeaturesFromObject = function( + object, opt_options) { + var esriJSONObject = /** @type {EsriJSONObject} */ (object); + var options = opt_options ? opt_options : {}; + if (esriJSONObject.features) { + var esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */ + (object); + /** @type {Array.<ol.Feature>} */ + var features = []; + var esriJSONFeatures = esriJSONFeatureCollection.features; + var i, ii; + options.idField = object.objectIdFieldName; + for (i = 0, ii = esriJSONFeatures.length; i < ii; ++i) { + features.push(this.readFeatureFromObject(esriJSONFeatures[i], + options)); + } + return features; + } else { + return [this.readFeatureFromObject(object, options)]; + } +}; + + +/** + * Read a geometry from a EsriJSON source. + * + * @function + * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.geom.Geometry} Geometry. + * @api + */ +ol.format.EsriJSON.prototype.readGeometry; + + +/** + * @inheritDoc + */ +ol.format.EsriJSON.prototype.readGeometryFromObject = function( + object, opt_options) { + return ol.format.EsriJSON.readGeometry_( + /** @type {EsriJSONGeometry} */ (object), opt_options); +}; + + +/** + * Read the projection from a EsriJSON source. + * + * @function + * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. + * @api + */ +ol.format.EsriJSON.prototype.readProjection; + + +/** + * @inheritDoc + */ +ol.format.EsriJSON.prototype.readProjectionFromObject = function(object) { + var esriJSONObject = /** @type {EsriJSONObject} */ (object); + if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) { + var crs = esriJSONObject.spatialReference.wkid; + return ol.proj.get('EPSG:' + crs); + } else { + return null; + } +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {EsriJSONGeometry} EsriJSON geometry. + */ +ol.format.EsriJSON.writeGeometry_ = function(geometry, opt_options) { + var geometryWriter = ol.format.EsriJSON.GEOMETRY_WRITERS_[geometry.getType()]; + goog.asserts.assert(geometryWriter, 'geometryWriter should be defined'); + return geometryWriter(/** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions(geometry, true, opt_options)), + opt_options); +}; + + +/** + * Encode a geometry as a EsriJSON string. + * + * @function + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} EsriJSON. + * @api + */ +ol.format.EsriJSON.prototype.writeGeometry; + + +/** + * Encode a geometry as a EsriJSON object. + * + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {EsriJSONGeometry} Object. + * @api + */ +ol.format.EsriJSON.prototype.writeGeometryObject = function(geometry, + opt_options) { + return ol.format.EsriJSON.writeGeometry_(geometry, + this.adaptOptions(opt_options)); +}; + + +/** + * Encode a feature as a EsriJSON Feature string. + * + * @function + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} EsriJSON. + * @api + */ +ol.format.EsriJSON.prototype.writeFeature; + + +/** + * Encode a feature as a esriJSON Feature object. + * + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} Object. + * @api + */ +ol.format.EsriJSON.prototype.writeFeatureObject = function( + feature, opt_options) { + opt_options = this.adaptOptions(opt_options); + var object = {}; + var geometry = feature.getGeometry(); + if (geometry) { + object['geometry'] = + ol.format.EsriJSON.writeGeometry_(geometry, opt_options); + } + var properties = feature.getProperties(); + delete properties[feature.getGeometryName()]; + if (!goog.object.isEmpty(properties)) { + object['attributes'] = properties; + } else { + object['attributes'] = {}; + } + if (opt_options && opt_options.featureProjection) { + object['spatialReference'] = /** @type {EsriJSONCRS} */({ + wkid: ol.proj.get( + opt_options.featureProjection).getCode().split(':').pop() + }); + } + return object; +}; + + +/** + * Encode an array of features as EsriJSON. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} EsriJSON. + * @api + */ +ol.format.EsriJSON.prototype.writeFeatures; + + +/** + * Encode an array of features as a EsriJSON object. + * + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} EsriJSON Object. + * @api + */ +ol.format.EsriJSON.prototype.writeFeaturesObject = + function(features, opt_options) { + opt_options = this.adaptOptions(opt_options); + var objects = []; + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + objects.push(this.writeFeatureObject(features[i], opt_options)); + } + return /** @type {EsriJSONFeatureCollection} */ ({ + 'features': objects + }); +}; + +goog.provide('ol.geom.GeometryCollection'); + +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol.extent'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryType'); + + + +/** + * @classdesc + * An array of {@link ol.geom.Geometry} objects. + * + * @constructor + * @extends {ol.geom.Geometry} + * @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries. + * @api stable + */ +ol.geom.GeometryCollection = function(opt_geometries) { + + goog.base(this); + + /** + * @private + * @type {Array.<ol.geom.Geometry>} + */ + this.geometries_ = opt_geometries ? opt_geometries : null; + + this.listenGeometriesChange_(); +}; +goog.inherits(ol.geom.GeometryCollection, ol.geom.Geometry); + + +/** + * @param {Array.<ol.geom.Geometry>} geometries Geometries. + * @private + * @return {Array.<ol.geom.Geometry>} Cloned geometries. + */ +ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) { + var clonedGeometries = []; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + clonedGeometries.push(geometries[i].clone()); + } + return clonedGeometries; +}; + + +/** + * @private + */ +ol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() { + var i, ii; + if (!this.geometries_) { + return; + } + for (i = 0, ii = this.geometries_.length; i < ii; ++i) { + goog.events.unlisten( + this.geometries_[i], goog.events.EventType.CHANGE, + this.changed, false, this); + } +}; + + +/** + * @private + */ +ol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() { + var i, ii; + if (!this.geometries_) { + return; + } + for (i = 0, ii = this.geometries_.length; i < ii; ++i) { + goog.events.listen( + this.geometries_[i], goog.events.EventType.CHANGE, + this.changed, false, this); + } +}; + + +/** + * Make a complete copy of the geometry. + * @return {!ol.geom.GeometryCollection} Clone. + * @api stable + */ +ol.geom.GeometryCollection.prototype.clone = function() { + var geometryCollection = new ol.geom.GeometryCollection(null); + geometryCollection.setGeometries(this.geometries_); + return geometryCollection; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + minSquaredDistance = geometries[i].closestPointXY( + x, y, closestPoint, minSquaredDistance); + } + return minSquaredDistance; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.containsXY = function(x, y) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + if (geometries[i].containsXY(x, y)) { + return true; + } + } + return false; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.computeExtent = function(extent) { + ol.extent.createOrUpdateEmpty(extent); + var geometries = this.geometries_; + for (var i = 0, ii = geometries.length; i < ii; ++i) { + ol.extent.extend(extent, geometries[i].getExtent()); + } + return extent; +}; + + +/** + * Return the geometries that make up this geometry collection. + * @return {Array.<ol.geom.Geometry>} Geometries. + * @api stable + */ +ol.geom.GeometryCollection.prototype.getGeometries = function() { + return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_); +}; + + +/** + * @return {Array.<ol.geom.Geometry>} Geometries. + */ +ol.geom.GeometryCollection.prototype.getGeometriesArray = function() { + return this.geometries_; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.getSimplifiedGeometry = + function(squaredTolerance) { + if (this.simplifiedGeometryRevision != this.getRevision()) { + goog.object.clear(this.simplifiedGeometryCache); + this.simplifiedGeometryMaxMinSquaredTolerance = 0; + this.simplifiedGeometryRevision = this.getRevision(); + } + if (squaredTolerance < 0 || + (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && + squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) { + return this; + } + var key = squaredTolerance.toString(); + if (this.simplifiedGeometryCache.hasOwnProperty(key)) { + return this.simplifiedGeometryCache[key]; + } else { + var simplifiedGeometries = []; + var geometries = this.geometries_; + var simplified = false; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometry = geometries[i]; + var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); + simplifiedGeometries.push(simplifiedGeometry); + if (simplifiedGeometry !== geometry) { + simplified = true; + } + } + if (simplified) { + var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null); + simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries); + this.simplifiedGeometryCache[key] = simplifiedGeometryCollection; + return simplifiedGeometryCollection; + } else { + this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; + return this; + } + } +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.GeometryCollection.prototype.getType = function() { + return ol.geom.GeometryType.GEOMETRY_COLLECTION; +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + if (geometries[i].intersectsExtent(extent)) { + return true; + } + } + return false; +}; + + +/** + * @return {boolean} Is empty. + */ +ol.geom.GeometryCollection.prototype.isEmpty = function() { + return this.geometries_.length === 0; +}; + + +/** + * Set the geometries that make up this geometry collection. + * @param {Array.<ol.geom.Geometry>} geometries Geometries. + * @api stable + */ +ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) { + this.setGeometriesArray( + ol.geom.GeometryCollection.cloneGeometries_(geometries)); +}; + + +/** + * @param {Array.<ol.geom.Geometry>} geometries Geometries. + */ +ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) { + this.unlistenGeometriesChange_(); + this.geometries_ = geometries; + this.listenGeometriesChange_(); + this.changed(); +}; + + +/** + * @inheritDoc + * @api stable + */ +ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + geometries[i].applyTransform(transformFn); + } + this.changed(); +}; + + +/** + * Translate the geometry. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @api + */ +ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + geometries[i].translate(deltaX, deltaY); + } + this.changed(); +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.disposeInternal = function() { + this.unlistenGeometriesChange_(); + goog.base(this, 'disposeInternal'); +}; + +// TODO: serialize dataProjection as crs member when writing +// see https://github.com/openlayers/ol3/issues/2078 + +goog.provide('ol.format.GeoJSON'); + +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol.Feature'); +goog.require('ol.format.Feature'); +goog.require('ol.format.JSONFeature'); +goog.require('ol.geom.GeometryCollection'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.proj'); + + + +/** + * @classdesc + * Feature format for reading and writing data in the GeoJSON format. + * + * @constructor + * @extends {ol.format.JSONFeature} + * @param {olx.format.GeoJSONOptions=} opt_options Options. + * @api stable + */ +ol.format.GeoJSON = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this); + + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get( + options.defaultDataProjection ? + options.defaultDataProjection : 'EPSG:4326'); + + + /** + * Name of the geometry attribute for features. + * @type {string|undefined} + * @private + */ + this.geometryName_ = options.geometryName; + +}; +goog.inherits(ol.format.GeoJSON, ol.format.JSONFeature); + + +/** + * @const + * @type {Array.<string>} + * @private + */ +ol.format.GeoJSON.EXTENSIONS_ = ['.geojson']; + + +/** + * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @private + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.GeoJSON.readGeometry_ = function(object, opt_options) { + if (!object) { + return null; + } + var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type]; + goog.asserts.assert(geometryReader, 'geometryReader should be defined'); + return /** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions( + geometryReader(object), false, opt_options)); +}; + + +/** + * @param {GeoJSONGeometryCollection} object Object. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @private + * @return {ol.geom.GeometryCollection} Geometry collection. + */ +ol.format.GeoJSON.readGeometryCollectionGeometry_ = function( + object, opt_options) { + goog.asserts.assert(object.type == 'GeometryCollection', + 'object.type should be GeometryCollection'); + var geometries = object.geometries.map( + /** + * @param {GeoJSONGeometry} geometry Geometry. + * @return {ol.geom.Geometry} geometry Geometry. + */ + function(geometry) { + return ol.format.GeoJSON.readGeometry_(geometry, opt_options); + }); + return new ol.geom.GeometryCollection(geometries); +}; + + +/** + * @param {GeoJSONGeometry} object Object. + * @private + * @return {ol.geom.Point} Point. + */ +ol.format.GeoJSON.readPointGeometry_ = function(object) { + goog.asserts.assert(object.type == 'Point', + 'object.type should be Point'); + return new ol.geom.Point(object.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} object Object. + * @private + * @return {ol.geom.LineString} LineString. + */ +ol.format.GeoJSON.readLineStringGeometry_ = function(object) { + goog.asserts.assert(object.type == 'LineString', + 'object.type should be LineString'); + return new ol.geom.LineString(object.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} object Object. + * @private + * @return {ol.geom.MultiLineString} MultiLineString. + */ +ol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) { + goog.asserts.assert(object.type == 'MultiLineString', + 'object.type should be MultiLineString'); + return new ol.geom.MultiLineString(object.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} object Object. + * @private + * @return {ol.geom.MultiPoint} MultiPoint. + */ +ol.format.GeoJSON.readMultiPointGeometry_ = function(object) { + goog.asserts.assert(object.type == 'MultiPoint', + 'object.type should be MultiPoint'); + return new ol.geom.MultiPoint(object.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} object Object. + * @private + * @return {ol.geom.MultiPolygon} MultiPolygon. + */ +ol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) { + goog.asserts.assert(object.type == 'MultiPolygon', + 'object.type should be MultiPolygon'); + return new ol.geom.MultiPolygon(object.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} object Object. + * @private + * @return {ol.geom.Polygon} Polygon. + */ +ol.format.GeoJSON.readPolygonGeometry_ = function(object) { + goog.asserts.assert(object.type == 'Polygon', + 'object.type should be Polygon'); + return new ol.geom.Polygon(object.coordinates); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry. + */ +ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) { + var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()]; + goog.asserts.assert(geometryWriter, 'geometryWriter should be defined'); + return geometryWriter(/** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions(geometry, true, opt_options)), + opt_options); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @private + * @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection. + */ +ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) { + return /** @type {GeoJSONGeometryCollection} */ ({ + type: 'GeometryCollection', + geometries: [] + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometryCollection} GeoJSON geometry collection. + */ +ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function( + geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection, + 'geometry should be an ol.geom.GeometryCollection'); + var geometries = geometry.getGeometriesArray().map(function(geometry) { + return ol.format.GeoJSON.writeGeometry_(geometry, opt_options); + }); + return /** @type {GeoJSONGeometryCollection} */ ({ + type: 'GeometryCollection', + geometries: geometries + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry} GeoJSON geometry. + */ +ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.LineString, + 'geometry should be an ol.geom.LineString'); + return /** @type {GeoJSONGeometry} */ ({ + type: 'LineString', + coordinates: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry} GeoJSON geometry. + */ +ol.format.GeoJSON.writeMultiLineStringGeometry_ = + function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, + 'geometry should be an ol.geom.MultiLineString'); + return /** @type {GeoJSONGeometry} */ ({ + type: 'MultiLineString', + coordinates: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry} GeoJSON geometry. + */ +ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, + 'geometry should be an ol.geom.MultiPoint'); + return /** @type {GeoJSONGeometry} */ ({ + type: 'MultiPoint', + coordinates: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry} GeoJSON geometry. + */ +ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, + 'geometry should be an ol.geom.MultiPolygon'); + var right; + if (opt_options) { + right = opt_options.rightHanded; + } + return /** @type {GeoJSONGeometry} */ ({ + type: 'MultiPolygon', + coordinates: geometry.getCoordinates(right) + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry} GeoJSON geometry. + */ +ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.Point, + 'geometry should be an ol.geom.Point'); + return /** @type {GeoJSONGeometry} */ ({ + type: 'Point', + coordinates: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @private + * @return {GeoJSONGeometry} GeoJSON geometry. + */ +ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, + 'geometry should be an ol.geom.Polygon'); + var right; + if (opt_options) { + right = opt_options.rightHanded; + } + return /** @type {GeoJSONGeometry} */ ({ + type: 'Polygon', + coordinates: geometry.getCoordinates(right) + }); +}; + + +/** + * @const + * @private + * @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>} + */ +ol.format.GeoJSON.GEOMETRY_READERS_ = { + 'Point': ol.format.GeoJSON.readPointGeometry_, + 'LineString': ol.format.GeoJSON.readLineStringGeometry_, + 'Polygon': ol.format.GeoJSON.readPolygonGeometry_, + 'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_, + 'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_, + 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_, + 'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_ +}; + + +/** + * @const + * @private + * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>} + */ +ol.format.GeoJSON.GEOMETRY_WRITERS_ = { + 'Point': ol.format.GeoJSON.writePointGeometry_, + 'LineString': ol.format.GeoJSON.writeLineStringGeometry_, + 'Polygon': ol.format.GeoJSON.writePolygonGeometry_, + 'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_, + 'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_, + 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_, + 'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_, + 'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ +}; + + +/** + * @inheritDoc + */ +ol.format.GeoJSON.prototype.getExtensions = function() { + return ol.format.GeoJSON.EXTENSIONS_; +}; + + +/** + * Read a feature from a GeoJSON Feature source. Only works for Feature, + * use `readFeatures` to read FeatureCollection source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @api stable + */ +ol.format.GeoJSON.prototype.readFeature; + + +/** + * Read all features from a GeoJSON source. Works with both Feature and + * FeatureCollection sources. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api stable + */ +ol.format.GeoJSON.prototype.readFeatures; + + +/** + * @inheritDoc + */ +ol.format.GeoJSON.prototype.readFeatureFromObject = function( + object, opt_options) { + var geoJSONFeature = /** @type {GeoJSONFeature} */ (object); + goog.asserts.assert(geoJSONFeature.type == 'Feature', + 'geoJSONFeature.type should be Feature'); + var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry, + opt_options); + var feature = new ol.Feature(); + if (this.geometryName_) { + feature.setGeometryName(this.geometryName_); + } + feature.setGeometry(geometry); + if (geoJSONFeature.id !== undefined) { + feature.setId(geoJSONFeature.id); + } + if (geoJSONFeature.properties) { + feature.setProperties(geoJSONFeature.properties); + } + return feature; +}; + + +/** + * @inheritDoc + */ +ol.format.GeoJSON.prototype.readFeaturesFromObject = function( + object, opt_options) { + var geoJSONObject = /** @type {GeoJSONObject} */ (object); + if (geoJSONObject.type == 'Feature') { + return [this.readFeatureFromObject(object, opt_options)]; + } else if (geoJSONObject.type == 'FeatureCollection') { + var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */ + (object); + /** @type {Array.<ol.Feature>} */ + var features = []; + var geoJSONFeatures = geoJSONFeatureCollection.features; + var i, ii; + for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) { + features.push(this.readFeatureFromObject(geoJSONFeatures[i], + opt_options)); + } + return features; + } else { + goog.asserts.fail('Unknown geoJSONObject.type: ' + geoJSONObject.type); + return []; + } +}; + + +/** + * Read a geometry from a GeoJSON source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.geom.Geometry} Geometry. + * @api stable + */ +ol.format.GeoJSON.prototype.readGeometry; + + +/** + * @inheritDoc + */ +ol.format.GeoJSON.prototype.readGeometryFromObject = function( + object, opt_options) { + return ol.format.GeoJSON.readGeometry_( + /** @type {GeoJSONGeometry} */ (object), opt_options); +}; + + +/** + * Read the projection from a GeoJSON source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. + * @api stable + */ +ol.format.GeoJSON.prototype.readProjection; + + +/** + * @inheritDoc + */ +ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) { + var geoJSONObject = /** @type {GeoJSONObject} */ (object); + var crs = geoJSONObject.crs; + if (crs) { + if (crs.type == 'name') { + return ol.proj.get(crs.properties.name); + } else if (crs.type == 'EPSG') { + // 'EPSG' is not part of the GeoJSON specification, but is generated by + // GeoServer. + // TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996 + // is fixed and widely deployed. + return ol.proj.get('EPSG:' + crs.properties.code); + } else { + goog.asserts.fail('Unknown crs.type: ' + crs.type); + return null; + } + } else { + return this.defaultDataProjection; + } +}; + + +/** + * Encode a feature as a GeoJSON Feature string. + * + * @function + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} GeoJSON. + * @api stable + */ +ol.format.GeoJSON.prototype.writeFeature; + + +/** + * Encode a feature as a GeoJSON Feature object. + * + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} Object. + * @api stable + */ +ol.format.GeoJSON.prototype.writeFeatureObject = function( + feature, opt_options) { + opt_options = this.adaptOptions(opt_options); + var object = { + 'type': 'Feature' + }; + var id = feature.getId(); + if (id !== undefined) { + object['id'] = id; + } + var geometry = feature.getGeometry(); + if (geometry) { + object['geometry'] = + ol.format.GeoJSON.writeGeometry_(geometry, opt_options); + } else { + object['geometry'] = null; + } + var properties = feature.getProperties(); + delete properties[feature.getGeometryName()]; + if (!goog.object.isEmpty(properties)) { + object['properties'] = properties; + } else { + object['properties'] = null; + } + return object; +}; + + +/** + * Encode an array of features as GeoJSON. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} GeoJSON. + * @api stable + */ +ol.format.GeoJSON.prototype.writeFeatures; + + +/** + * Encode an array of features as a GeoJSON object. + * + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {Object} GeoJSON Object. + * @api stable + */ +ol.format.GeoJSON.prototype.writeFeaturesObject = + function(features, opt_options) { + opt_options = this.adaptOptions(opt_options); + var objects = []; + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + objects.push(this.writeFeatureObject(features[i], opt_options)); + } + return /** @type {GeoJSONFeatureCollection} */ ({ + type: 'FeatureCollection', + features: objects + }); +}; + + +/** + * Encode a geometry as a GeoJSON string. + * + * @function + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} GeoJSON. + * @api stable + */ +ol.format.GeoJSON.prototype.writeGeometry; + + +/** + * Encode a geometry as a GeoJSON object. + * + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object. + * @api stable + */ +ol.format.GeoJSON.prototype.writeGeometryObject = function(geometry, + opt_options) { + return ol.format.GeoJSON.writeGeometry_(geometry, + this.adaptOptions(opt_options)); +}; + +goog.provide('ol.format.XMLFeature'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.dom.xml'); +goog.require('ol.format.Feature'); +goog.require('ol.format.FormatType'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for XML feature formats. + * + * @constructor + * @extends {ol.format.Feature} + */ +ol.format.XMLFeature = function() { + goog.base(this); +}; +goog.inherits(ol.format.XMLFeature, ol.format.Feature); + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.getType = function() { + return ol.format.FormatType.XML; +}; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.readFeature = function(source, opt_options) { + if (ol.xml.isDocument(source)) { + return this.readFeatureFromDocument( + /** @type {Document} */ (source), opt_options); + } else if (ol.xml.isNode(source)) { + return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readFeatureFromDocument(doc, opt_options); + } else { + goog.asserts.fail('Unknown source type'); + return null; + } +}; + + +/** + * @param {Document} doc Document. + * @param {olx.format.ReadOptions=} opt_options Options. + * @return {ol.Feature} Feature. + */ +ol.format.XMLFeature.prototype.readFeatureFromDocument = function( + doc, opt_options) { + var features = this.readFeaturesFromDocument(doc, opt_options); + if (features.length > 0) { + return features[0]; + } else { + return null; + } +}; + + +/** + * @param {Node} node Node. + * @param {olx.format.ReadOptions=} opt_options Options. + * @return {ol.Feature} Feature. + */ +ol.format.XMLFeature.prototype.readFeatureFromNode = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) { + if (ol.xml.isDocument(source)) { + return this.readFeaturesFromDocument( + /** @type {Document} */ (source), opt_options); + } else if (ol.xml.isNode(source)) { + return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readFeaturesFromDocument(doc, opt_options); + } else { + goog.asserts.fail('Unknown source type'); + return []; + } +}; + + +/** + * @param {Document} doc Document. + * @param {olx.format.ReadOptions=} opt_options Options. + * @protected + * @return {Array.<ol.Feature>} Features. + */ +ol.format.XMLFeature.prototype.readFeaturesFromDocument = function( + doc, opt_options) { + /** @type {Array.<ol.Feature>} */ + var features = []; + var n; + for (n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + goog.array.extend(features, this.readFeaturesFromNode(n, opt_options)); + } + } + return features; +}; + + +/** + * @param {Node} node Node. + * @param {olx.format.ReadOptions=} opt_options Options. + * @protected + * @return {Array.<ol.Feature>} Features. + */ +ol.format.XMLFeature.prototype.readFeaturesFromNode = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) { + if (ol.xml.isDocument(source)) { + return this.readGeometryFromDocument( + /** @type {Document} */ (source), opt_options); + } else if (ol.xml.isNode(source)) { + return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readGeometryFromDocument(doc, opt_options); + } else { + goog.asserts.fail('Unknown source type'); + return null; + } +}; + + +/** + * @param {Document} doc Document. + * @param {olx.format.ReadOptions=} opt_options Options. + * @protected + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.XMLFeature.prototype.readGeometryFromDocument = goog.abstractMethod; + + +/** + * @param {Node} node Node. + * @param {olx.format.ReadOptions=} opt_options Options. + * @protected + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.XMLFeature.prototype.readGeometryFromNode = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.readProjection = function(source) { + if (ol.xml.isDocument(source)) { + return this.readProjectionFromDocument(/** @type {Document} */ (source)); + } else if (ol.xml.isNode(source)) { + return this.readProjectionFromNode(/** @type {Node} */ (source)); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readProjectionFromDocument(doc); + } else { + goog.asserts.fail('Unknown source type'); + return null; + } +}; + + +/** + * @param {Document} doc Document. + * @protected + * @return {ol.proj.Projection} Projection. + */ +ol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) { + return this.defaultDataProjection; +}; + + +/** + * @param {Node} node Node. + * @protected + * @return {ol.proj.Projection} Projection. + */ +ol.format.XMLFeature.prototype.readProjectionFromNode = function(node) { + return this.defaultDataProjection; +}; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) { + var node = this.writeFeatureNode(feature, opt_options); + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + return goog.dom.xml.serialize(/** @type {Element} */(node)); +}; + + +/** + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Options. + * @protected + * @return {Node} Node. + */ +ol.format.XMLFeature.prototype.writeFeatureNode = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) { + var node = this.writeFeaturesNode(features, opt_options); + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + return goog.dom.xml.serialize(/** @type {Element} */(node)); +}; + + +/** + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + */ +ol.format.XMLFeature.prototype.writeFeaturesNode = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) { + var node = this.writeGeometryNode(geometry, opt_options); + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + return goog.dom.xml.serialize(/** @type {Element} */(node)); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + */ +ol.format.XMLFeature.prototype.writeGeometryNode = goog.abstractMethod; + +// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part +// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect +// envelopes/extents, only geometries! +goog.provide('ol.format.GMLBase'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('goog.string'); +goog.require('ol.Feature'); +goog.require('ol.format.Feature'); +goog.require('ol.format.XMLFeature'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Feature base format for reading and writing data in the GML format. + * This class cannot be instantiated, it contains only base content that + * is shared with versioned format classes ol.format.GML2 and + * ol.format.GML3. + * + * @constructor + * @param {olx.format.GMLOptions=} opt_options + * Optional configuration object. + * @extends {ol.format.XMLFeature} + */ +ol.format.GMLBase = function(opt_options) { + var options = /** @type {olx.format.GMLOptions} */ + (opt_options ? opt_options : {}); + + /** + * @protected + * @type {Array.<string>|string|undefined} + */ + this.featureType = options.featureType; + + /** + * @protected + * @type {Object.<string, string>|string|undefined} + */ + this.featureNS = options.featureNS; + + /** + * @protected + * @type {string} + */ + this.srsName = options.srsName; + + /** + * @protected + * @type {string} + */ + this.schemaLocation = ''; + + /** + * @type {Object.<string, Object.<string, Object>>} + */ + this.FEATURE_COLLECTION_PARSERS = {}; + this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = { + 'featureMember': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readFeaturesInternal), + 'featureMembers': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readFeaturesInternal) + }; + + goog.base(this); +}; +goog.inherits(ol.format.GMLBase, ol.format.XMLFeature); + + +/** + * @const + * @type {string} + */ +ol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml'; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Array.<ol.Feature>} Features. + */ +ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + var localName = ol.xml.getLocalName(node); + var features; + if (localName == 'FeatureCollection') { + if (node.namespaceURI === 'http://www.opengis.net/wfs') { + features = ol.xml.pushParseAndPop([], + this.FEATURE_COLLECTION_PARSERS, node, + objectStack, this); + } else { + features = ol.xml.pushParseAndPop(null, + this.FEATURE_COLLECTION_PARSERS, node, + objectStack, this); + } + } else if (localName == 'featureMembers' || localName == 'featureMember') { + var context = objectStack[0]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featureType = context['featureType']; + var featureNS = context['featureNS']; + var i, ii, prefix = 'p', defaultPrefix = 'p0'; + if (!featureType && node.childNodes) { + featureType = [], featureNS = {}; + for (i = 0, ii = node.childNodes.length; i < ii; ++i) { + var child = node.childNodes[i]; + if (child.nodeType === 1) { + var ft = child.nodeName.split(':').pop(); + if (featureType.indexOf(ft) === -1) { + var key; + if (!goog.object.contains(featureNS, child.namespaceURI)) { + key = prefix + goog.object.getCount(featureNS); + featureNS[key] = child.namespaceURI; + } else { + key = goog.object.findKey(featureNS, function(value) { + return value === child.namespaceURI; + }); + } + featureType.push(key + ':' + ft); + } + } + } + context['featureType'] = featureType; + context['featureNS'] = featureNS; + } + if (goog.isString(featureNS)) { + var ns = featureNS; + featureNS = {}; + featureNS[defaultPrefix] = ns; + } + var parsersNS = {}; + var featureTypes = goog.isArray(featureType) ? featureType : [featureType]; + for (var p in featureNS) { + var parsers = {}; + for (i = 0, ii = featureTypes.length; i < ii; ++i) { + var featurePrefix = featureTypes[i].indexOf(':') === -1 ? + defaultPrefix : featureTypes[i].split(':')[0]; + if (featurePrefix === p) { + parsers[featureTypes[i].split(':').pop()] = + (localName == 'featureMembers') ? + ol.xml.makeArrayPusher(this.readFeatureElement, this) : + ol.xml.makeReplacer(this.readFeatureElement, this); + } + } + parsersNS[featureNS[p]] = parsers; + } + features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack); + } + if (!features) { + features = []; + } + return features; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.Geometry|undefined} Geometry. + */ +ol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) { + var context = objectStack[0]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + context['srsName'] = node.firstElementChild.getAttribute('srsName'); + var geometry = ol.xml.pushParseAndPop(/** @type {ol.geom.Geometry} */(null), + this.GEOMETRY_PARSERS_, node, objectStack, this); + if (geometry) { + return /** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions(geometry, false, context)); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.Feature} Feature. + */ +ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) { + var n; + var fid = node.getAttribute('fid') || + ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id'); + var values = {}, geometryName; + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + var localName = ol.xml.getLocalName(n); + // Assume attribute elements have one child node and that the child + // is a text or CDATA node (to be treated as text). + // Otherwise assume it is a geometry node. + if (n.childNodes.length === 0 || + (n.childNodes.length === 1 && + (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) { + var value = ol.xml.getAllTextContent(n, false); + if (goog.string.isEmpty(value)) { + value = undefined; + } + values[localName] = value; + } else { + // boundedBy is an extent and must not be considered as a geometry + if (localName !== 'boundedBy') { + geometryName = localName; + } + values[localName] = this.readGeometryElement(n, objectStack); + } + } + var feature = new ol.Feature(values); + if (geometryName) { + feature.setGeometryName(geometryName); + } + if (fid) { + feature.setId(fid); + } + return feature; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.Point|undefined} Point. + */ +ol.format.GMLBase.prototype.readPoint = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Point', 'localName should be Point'); + var flatCoordinates = + this.readFlatCoordinatesFromNode_(node, objectStack); + if (flatCoordinates) { + var point = new ol.geom.Point(null); + goog.asserts.assert(flatCoordinates.length == 3, + 'flatCoordinates should have a length of 3'); + point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + return point; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.MultiPoint|undefined} MultiPoint. + */ +ol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'MultiPoint', + 'localName should be MultiPoint'); + var coordinates = ol.xml.pushParseAndPop( + /** @type {Array.<Array.<number>>} */ ([]), + this.MULTIPOINT_PARSERS_, node, objectStack, this); + if (coordinates) { + return new ol.geom.MultiPoint(coordinates); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.MultiLineString|undefined} MultiLineString. + */ +ol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'MultiLineString', + 'localName should be MultiLineString'); + var lineStrings = ol.xml.pushParseAndPop( + /** @type {Array.<ol.geom.LineString>} */ ([]), + this.MULTILINESTRING_PARSERS_, node, objectStack, this); + if (lineStrings) { + var multiLineString = new ol.geom.MultiLineString(null); + multiLineString.setLineStrings(lineStrings); + return multiLineString; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.MultiPolygon|undefined} MultiPolygon. + */ +ol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'MultiPolygon', + 'localName should be MultiPolygon'); + var polygons = ol.xml.pushParseAndPop( + /** @type {Array.<ol.geom.Polygon>} */ ([]), + this.MULTIPOLYGON_PARSERS_, node, objectStack, this); + if (polygons) { + var multiPolygon = new ol.geom.MultiPolygon(null); + multiPolygon.setPolygons(polygons); + return multiPolygon; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'pointMember' || + node.localName == 'pointMembers', + 'localName should be pointMember or pointMembers'); + ol.xml.parseNode(this.POINTMEMBER_PARSERS_, + node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GMLBase.prototype.lineStringMemberParser_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'lineStringMember' || + node.localName == 'lineStringMembers', + 'localName should be LineStringMember or LineStringMembers'); + ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_, + node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GMLBase.prototype.polygonMemberParser_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'polygonMember' || + node.localName == 'polygonMembers', + 'localName should be polygonMember or polygonMembers'); + ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node, + objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.LineString|undefined} LineString. + */ +ol.format.GMLBase.prototype.readLineString = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LineString', + 'localName should be LineString'); + var flatCoordinates = + this.readFlatCoordinatesFromNode_(node, objectStack); + if (flatCoordinates) { + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + return lineString; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>|undefined} LinearRing flat coordinates. + */ +ol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LinearRing', + 'localName should be LinearRing'); + var ring = ol.xml.pushParseAndPop(/** @type {Array.<number>} */(null), + this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, + objectStack, this); + if (ring) { + return ring; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.LinearRing|undefined} LinearRing. + */ +ol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LinearRing', + 'localName should be LinearRing'); + var flatCoordinates = + this.readFlatCoordinatesFromNode_(node, objectStack); + if (flatCoordinates) { + var ring = new ol.geom.LinearRing(null); + ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + return ring; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.geom.Polygon|undefined} Polygon. + */ +ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Polygon', + 'localName should be Polygon'); + var flatLinearRings = ol.xml.pushParseAndPop( + /** @type {Array.<Array.<number>>} */ ([null]), + this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this); + if (flatLinearRings && flatLinearRings[0]) { + var polygon = new ol.geom.Polygon(null); + var flatCoordinates = flatLinearRings[0]; + var ends = [flatCoordinates.length]; + var i, ii; + for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { + goog.array.extend(flatCoordinates, flatLinearRings[i]); + ends.push(flatCoordinates.length); + } + polygon.setFlatCoordinates( + ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); + return polygon; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>} Flat coordinates. + */ +ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop( + null, + this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, + objectStack, this)); +}; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'pointMember': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.pointMemberParser_), + 'pointMembers': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.pointMemberParser_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'lineStringMember': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.lineStringMemberParser_), + 'lineStringMembers': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.lineStringMemberParser_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'polygonMember': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.polygonMemberParser_), + 'polygonMembers': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.polygonMemberParser_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'Point': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'LineString': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.readLineString) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'Polygon': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.readPolygon) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @protected + */ +ol.format.GMLBase.prototype.RING_PARSERS = Object({ + 'http://www.opengis.net/gml' : { + 'LinearRing': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readFlatLinearRing_) + } +}); + + +/** + * @inheritDoc + */ +ol.format.GMLBase.prototype.readGeometryFromNode = + function(node, opt_options) { + var geometry = this.readGeometryElement(node, + [this.getReadOptions(node, opt_options ? opt_options : {})]); + return geometry ? geometry : null; +}; + + +/** + * Read all features from a GML FeatureCollection. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Options. + * @return {Array.<ol.Feature>} Features. + * @api stable + */ +ol.format.GMLBase.prototype.readFeatures; + + +/** + * @inheritDoc + */ +ol.format.GMLBase.prototype.readFeaturesFromNode = + function(node, opt_options) { + var options = { + featureType: this.featureType, + featureNS: this.featureNS + }; + if (opt_options) { + goog.object.extend(options, this.getReadOptions(node, opt_options)); + } + return this.readFeaturesInternal(node, [options]); +}; + + +/** + * @inheritDoc + */ +ol.format.GMLBase.prototype.readProjectionFromNode = function(node) { + return ol.proj.get(this.srsName_ ? this.srsName_ : + node.firstElementChild.getAttribute('srsName')); +}; + +goog.provide('ol.format.XSD'); + +goog.require('goog.asserts'); +goog.require('goog.string'); +goog.require('ol'); +goog.require('ol.xml'); + + +/** + * @const + * @type {string} + */ +ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema'; + + +/** + * @param {Node} node Node. + * @return {boolean|undefined} Boolean. + */ +ol.format.XSD.readBoolean = function(node) { + var s = ol.xml.getAllTextContent(node, false); + return ol.format.XSD.readBooleanString(s); +}; + + +/** + * @param {string} string String. + * @return {boolean|undefined} Boolean. + */ +ol.format.XSD.readBooleanString = function(string) { + var m = /^\s*(true|1)|(false|0)\s*$/.exec(string); + if (m) { + return m[1] !== undefined || false; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {number|undefined} DateTime in seconds. + */ +ol.format.XSD.readDateTime = function(node) { + var s = ol.xml.getAllTextContent(node, false); + var re = + /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/; + var m = re.exec(s); + if (m) { + var year = parseInt(m[1], 10); + var month = parseInt(m[2], 10) - 1; + var day = parseInt(m[3], 10); + var hour = parseInt(m[4], 10); + var minute = parseInt(m[5], 10); + var second = parseInt(m[6], 10); + var dateTime = Date.UTC(year, month, day, hour, minute, second) / 1000; + if (m[7] != 'Z') { + var sign = m[8] == '-' ? -1 : 1; + dateTime += sign * 60 * parseInt(m[9], 10); + if (m[10] !== undefined) { + dateTime += sign * 60 * 60 * parseInt(m[10], 10); + } + } + return dateTime; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {number|undefined} Decimal. + */ +ol.format.XSD.readDecimal = function(node) { + var s = ol.xml.getAllTextContent(node, false); + return ol.format.XSD.readDecimalString(s); +}; + + +/** + * @param {string} string String. + * @return {number|undefined} Decimal. + */ +ol.format.XSD.readDecimalString = function(string) { + // FIXME check spec + var m = /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(string); + if (m) { + return parseFloat(m[1]); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {number|undefined} Non negative integer. + */ +ol.format.XSD.readNonNegativeInteger = function(node) { + var s = ol.xml.getAllTextContent(node, false); + return ol.format.XSD.readNonNegativeIntegerString(s); +}; + + +/** + * @param {string} string String. + * @return {number|undefined} Non negative integer. + */ +ol.format.XSD.readNonNegativeIntegerString = function(string) { + var m = /^\s*(\d+)\s*$/.exec(string); + if (m) { + return parseInt(m[1], 10); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {string|undefined} String. + */ +ol.format.XSD.readString = function(node) { + return ol.xml.getAllTextContent(node, false).trim(); +}; + + +/** + * @param {Node} node Node to append a TextNode with the boolean to. + * @param {boolean} bool Boolean. + */ +ol.format.XSD.writeBooleanTextNode = function(node, bool) { + ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0'); +}; + + +/** + * @param {Node} node Node to append a TextNode with the dateTime to. + * @param {number} dateTime DateTime in seconds. + */ +ol.format.XSD.writeDateTimeTextNode = function(node, dateTime) { + var date = new Date(dateTime * 1000); + var string = date.getUTCFullYear() + '-' + + goog.string.padNumber(date.getUTCMonth() + 1, 2) + '-' + + goog.string.padNumber(date.getUTCDate(), 2) + 'T' + + goog.string.padNumber(date.getUTCHours(), 2) + ':' + + goog.string.padNumber(date.getUTCMinutes(), 2) + ':' + + goog.string.padNumber(date.getUTCSeconds(), 2) + 'Z'; + node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); +}; + + +/** + * @param {Node} node Node to append a TextNode with the decimal to. + * @param {number} decimal Decimal. + */ +ol.format.XSD.writeDecimalTextNode = function(node, decimal) { + var string = decimal.toPrecision(); + node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); +}; + + +/** + * @param {Node} node Node to append a TextNode with the decimal to. + * @param {number} nonNegativeInteger Non negative integer. + */ +ol.format.XSD.writeNonNegativeIntegerTextNode = + function(node, nonNegativeInteger) { + goog.asserts.assert(nonNegativeInteger >= 0, 'value should be more than 0'); + goog.asserts.assert(nonNegativeInteger == (nonNegativeInteger | 0), + 'value should be an integer value'); + var string = nonNegativeInteger.toString(); + node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); +}; + + +/** + * @param {Node} node Node to append a TextNode with the string to. + * @param {string} string String. + */ +ol.format.XSD.writeStringTextNode = function(node, string) { + node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); +}; + +goog.provide('ol.format.GML2'); + +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('ol.extent'); +goog.require('ol.format.GMLBase'); +goog.require('ol.format.XSD'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @classdesc + * Feature format for reading and writing data in the GML format, + * version 2.1.2. + * + * @constructor + * @param {olx.format.GMLOptions=} opt_options Optional configuration object. + * @extends {ol.format.GMLBase} + * @api + */ +ol.format.GML2 = function(opt_options) { + var options = /** @type {olx.format.GMLOptions} */ + (opt_options ? opt_options : {}); + + goog.base(this, options); + + this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][ + 'featureMember'] = + ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal); + + /** + * @inheritDoc + */ + this.schemaLocation = options.schemaLocation ? + options.schemaLocation : ol.format.GML2.schemaLocation_; + +}; +goog.inherits(ol.format.GML2, ol.format.GMLBase); + + +/** + * @const + * @type {string} + * @private + */ +ol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS + + ' http://schemas.opengis.net/gml/2.1.2/feature.xsd'; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>|undefined} Flat coordinates. + */ +ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) { + var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, ''); + var context = objectStack[0]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var containerSrs = context['srsName']; + var containerDimension = node.parentNode.getAttribute('srsDimension'); + var axisOrientation = 'enu'; + if (containerSrs) { + var proj = ol.proj.get(containerSrs); + axisOrientation = proj.getAxisOrientation(); + } + var coords = s.split(/[\s,]+/); + // The "dimension" attribute is from the GML 3.0.1 spec. + var dim = 2; + if (node.getAttribute('srsDimension')) { + dim = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('srsDimension')); + } else if (node.getAttribute('dimension')) { + dim = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('dimension')); + } else if (containerDimension) { + dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); + } + var x, y, z; + var flatCoordinates = []; + for (var i = 0, ii = coords.length; i < ii; i += dim) { + x = parseFloat(coords[i]); + y = parseFloat(coords[i + 1]); + z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; + if (axisOrientation.substr(0, 2) === 'en') { + flatCoordinates.push(x, y, z); + } else { + flatCoordinates.push(y, x, z); + } + } + return flatCoordinates; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Extent|undefined} Envelope. + */ +ol.format.GML2.prototype.readBox_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Box', 'localName should be Box'); + var flatCoordinates = ol.xml.pushParseAndPop( + /** @type {Array.<number>} */ ([null]), + this.BOX_PARSERS_, node, objectStack, this); + return ol.extent.createOrUpdate(flatCoordinates[1][0], + flatCoordinates[1][1], flatCoordinates[1][3], + flatCoordinates[1][4]); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GML2.prototype.innerBoundaryIsParser_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'innerBoundaryIs', + 'localName should be innerBoundaryIs'); + var flatLinearRing = ol.xml.pushParseAndPop( + /** @type {Array.<number>|undefined} */ (undefined), + this.RING_PARSERS, node, objectStack, this); + if (flatLinearRing) { + var flatLinearRings = /** @type {Array.<Array.<number>>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(flatLinearRings), + 'flatLinearRings should be an array'); + goog.asserts.assert(flatLinearRings.length > 0, + 'flatLinearRings should have an array length larger than 0'); + flatLinearRings.push(flatLinearRing); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GML2.prototype.outerBoundaryIsParser_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'outerBoundaryIs', + 'localName should be outerBoundaryIs'); + var flatLinearRing = ol.xml.pushParseAndPop( + /** @type {Array.<number>|undefined} */ (undefined), + this.RING_PARSERS, node, objectStack, this); + if (flatLinearRing) { + var flatLinearRings = /** @type {Array.<Array.<number>>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(flatLinearRings), + 'flatLinearRings should be an array'); + goog.asserts.assert(flatLinearRings.length > 0, + 'flatLinearRings should have an array length larger than 0'); + flatLinearRings[0] = flatLinearRing; + } +}; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'coordinates': ol.xml.makeReplacer( + ol.format.GML2.prototype.readFlatCoordinates_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_, + 'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_ + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML2.prototype.BOX_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'coordinates': ol.xml.makeArrayPusher( + ol.format.GML2.prototype.readFlatCoordinates_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML2.prototype.GEOMETRY_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint), + 'MultiPoint': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readMultiPoint), + 'LineString': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readLineString), + 'MultiLineString': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readMultiLineString), + 'LinearRing' : ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readLinearRing), + 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon), + 'MultiPolygon': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readMultiPolygon), + 'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_) + } +}); + +goog.provide('ol.format.GML'); +goog.provide('ol.format.GML3'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Feature'); +goog.require('ol.extent'); +goog.require('ol.format.Feature'); +goog.require('ol.format.GMLBase'); +goog.require('ol.format.XSD'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @classdesc + * Feature format for reading and writing data in the GML format + * version 3.1.1. + * Currently only supports GML 3.1.1 Simple Features profile. + * + * @constructor + * @param {olx.format.GMLOptions=} opt_options + * Optional configuration object. + * @extends {ol.format.GMLBase} + * @api + */ +ol.format.GML3 = function(opt_options) { + var options = /** @type {olx.format.GMLOptions} */ + (opt_options ? opt_options : {}); + + goog.base(this, options); + + /** + * @private + * @type {boolean} + */ + this.surface_ = options.surface !== undefined ? options.surface : false; + + /** + * @private + * @type {boolean} + */ + this.curve_ = options.curve !== undefined ? options.curve : false; + + /** + * @private + * @type {boolean} + */ + this.multiCurve_ = options.multiCurve !== undefined ? + options.multiCurve : true; + + /** + * @private + * @type {boolean} + */ + this.multiSurface_ = options.multiSurface !== undefined ? + options.multiSurface : true; + + /** + * @inheritDoc + */ + this.schemaLocation = options.schemaLocation ? + options.schemaLocation : ol.format.GML3.schemaLocation_; + +}; +goog.inherits(ol.format.GML3, ol.format.GMLBase); + + +/** + * @const + * @type {string} + * @private + */ +ol.format.GML3.schemaLocation_ = ol.format.GMLBase.GMLNS + + ' http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + + '1.0.0/gmlsf.xsd'; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.MultiLineString|undefined} MultiLineString. + */ +ol.format.GML3.prototype.readMultiCurve_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'MultiCurve', + 'localName should be MultiCurve'); + var lineStrings = ol.xml.pushParseAndPop( + /** @type {Array.<ol.geom.LineString>} */ ([]), + this.MULTICURVE_PARSERS_, node, objectStack, this); + if (lineStrings) { + var multiLineString = new ol.geom.MultiLineString(null); + multiLineString.setLineStrings(lineStrings); + return multiLineString; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.MultiPolygon|undefined} MultiPolygon. + */ +ol.format.GML3.prototype.readMultiSurface_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'MultiSurface', + 'localName should be MultiSurface'); + var polygons = ol.xml.pushParseAndPop( + /** @type {Array.<ol.geom.Polygon>} */ ([]), + this.MULTISURFACE_PARSERS_, node, objectStack, this); + if (polygons) { + var multiPolygon = new ol.geom.MultiPolygon(null); + multiPolygon.setPolygons(polygons); + return multiPolygon; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GML3.prototype.curveMemberParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'curveMember' || + node.localName == 'curveMembers', + 'localName should be curveMember or curveMembers'); + ol.xml.parseNode(this.CURVEMEMBER_PARSERS_, node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GML3.prototype.surfaceMemberParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'surfaceMember' || + node.localName == 'surfaceMembers', + 'localName should be surfaceMember or surfaceMembers'); + ol.xml.parseNode(this.SURFACEMEMBER_PARSERS_, + node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<(Array.<number>)>|undefined} flat coordinates. + */ +ol.format.GML3.prototype.readPatch_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'patches', + 'localName should be patches'); + return ol.xml.pushParseAndPop( + /** @type {Array.<Array.<number>>} */ ([null]), + this.PATCHES_PARSERS_, node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>|undefined} flat coordinates. + */ +ol.format.GML3.prototype.readSegment_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'segments', + 'localName should be segments'); + return ol.xml.pushParseAndPop( + /** @type {Array.<number>} */ ([null]), + this.SEGMENTS_PARSERS_, node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<(Array.<number>)>|undefined} flat coordinates. + */ +ol.format.GML3.prototype.readPolygonPatch_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'npde.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'PolygonPatch', + 'localName should be PolygonPatch'); + return ol.xml.pushParseAndPop( + /** @type {Array.<Array.<number>>} */ ([null]), + this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>|undefined} flat coordinates. + */ +ol.format.GML3.prototype.readLineStringSegment_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LineStringSegment', + 'localName should be LineStringSegment'); + return ol.xml.pushParseAndPop( + /** @type {Array.<number>} */ ([null]), + this.GEOMETRY_FLAT_COORDINATES_PARSERS_, + node, objectStack, this); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GML3.prototype.interiorParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'interior', + 'localName should be interior'); + var flatLinearRing = ol.xml.pushParseAndPop( + /** @type {Array.<number>|undefined} */ (undefined), + this.RING_PARSERS, node, objectStack, this); + if (flatLinearRing) { + var flatLinearRings = /** @type {Array.<Array.<number>>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(flatLinearRings), + 'flatLinearRings should be an array'); + goog.asserts.assert(flatLinearRings.length > 0, + 'flatLinearRings should have an array length of 1 or more'); + flatLinearRings.push(flatLinearRing); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GML3.prototype.exteriorParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'exterior', + 'localName should be exterior'); + var flatLinearRing = ol.xml.pushParseAndPop( + /** @type {Array.<number>|undefined} */ (undefined), + this.RING_PARSERS, node, objectStack, this); + if (flatLinearRing) { + var flatLinearRings = /** @type {Array.<Array.<number>>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(flatLinearRings), + 'flatLinearRings should be an array'); + goog.asserts.assert(flatLinearRings.length > 0, + 'flatLinearRings should have an array length of 1 or more'); + flatLinearRings[0] = flatLinearRing; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.Polygon|undefined} Polygon. + */ +ol.format.GML3.prototype.readSurface_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Surface', + 'localName should be Surface'); + var flatLinearRings = ol.xml.pushParseAndPop( + /** @type {Array.<Array.<number>>} */ ([null]), + this.SURFACE_PARSERS_, node, objectStack, this); + if (flatLinearRings && flatLinearRings[0]) { + var polygon = new ol.geom.Polygon(null); + var flatCoordinates = flatLinearRings[0]; + var ends = [flatCoordinates.length]; + var i, ii; + for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { + goog.array.extend(flatCoordinates, flatLinearRings[i]); + ends.push(flatCoordinates.length); + } + polygon.setFlatCoordinates( + ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); + return polygon; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.LineString|undefined} LineString. + */ +ol.format.GML3.prototype.readCurve_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Curve', 'localName should be Curve'); + var flatCoordinates = ol.xml.pushParseAndPop( + /** @type {Array.<number>} */ ([null]), + this.CURVE_PARSERS_, node, objectStack, this); + if (flatCoordinates) { + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + return lineString; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Extent|undefined} Envelope. + */ +ol.format.GML3.prototype.readEnvelope_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Envelope', + 'localName should be Envelope'); + var flatCoordinates = ol.xml.pushParseAndPop( + /** @type {Array.<number>} */ ([null]), + this.ENVELOPE_PARSERS_, node, objectStack, this); + return ol.extent.createOrUpdate(flatCoordinates[1][0], + flatCoordinates[1][1], flatCoordinates[2][0], + flatCoordinates[2][1]); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>|undefined} Flat coordinates. + */ +ol.format.GML3.prototype.readFlatPos_ = function(node, objectStack) { + var s = ol.xml.getAllTextContent(node, false); + var re = /^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/; + /** @type {Array.<number>} */ + var flatCoordinates = []; + var m; + while ((m = re.exec(s))) { + flatCoordinates.push(parseFloat(m[1])); + s = s.substr(m[0].length); + } + if (s !== '') { + return undefined; + } + var context = objectStack[0]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var containerSrs = context['srsName']; + var axisOrientation = 'enu'; + if (containerSrs) { + var proj = ol.proj.get(containerSrs); + axisOrientation = proj.getAxisOrientation(); + } + if (axisOrientation === 'neu') { + var i, ii; + for (i = 0, ii = flatCoordinates.length; i < ii; i += 3) { + var y = flatCoordinates[i]; + var x = flatCoordinates[i + 1]; + flatCoordinates[i] = x; + flatCoordinates[i + 1] = y; + } + } + var len = flatCoordinates.length; + if (len == 2) { + flatCoordinates.push(0); + } + if (len === 0) { + return undefined; + } + return flatCoordinates; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>|undefined} Flat coordinates. + */ +ol.format.GML3.prototype.readFlatPosList_ = function(node, objectStack) { + var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, ''); + var context = objectStack[0]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var containerSrs = context['srsName']; + var containerDimension = node.parentNode.getAttribute('srsDimension'); + var axisOrientation = 'enu'; + if (containerSrs) { + var proj = ol.proj.get(containerSrs); + axisOrientation = proj.getAxisOrientation(); + } + var coords = s.split(/\s+/); + // The "dimension" attribute is from the GML 3.0.1 spec. + var dim = 2; + if (node.getAttribute('srsDimension')) { + dim = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('srsDimension')); + } else if (node.getAttribute('dimension')) { + dim = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('dimension')); + } else if (containerDimension) { + dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); + } + var x, y, z; + var flatCoordinates = []; + for (var i = 0, ii = coords.length; i < ii; i += dim) { + x = parseFloat(coords[i]); + y = parseFloat(coords[i + 1]); + z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; + if (axisOrientation.substr(0, 2) === 'en') { + flatCoordinates.push(x, y, z); + } else { + flatCoordinates.push(y, x, z); + } + } + return flatCoordinates; +}; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'pos': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPos_), + 'posList': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPosList_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'interior': ol.format.GML3.prototype.interiorParser_, + 'exterior': ol.format.GML3.prototype.exteriorParser_ + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.GEOMETRY_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint), + 'MultiPoint': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readMultiPoint), + 'LineString': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readLineString), + 'MultiLineString': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readMultiLineString), + 'LinearRing' : ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readLinearRing), + 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon), + 'MultiPolygon': ol.xml.makeReplacer( + ol.format.GMLBase.prototype.readMultiPolygon), + 'Surface': ol.xml.makeReplacer(ol.format.GML3.prototype.readSurface_), + 'MultiSurface': ol.xml.makeReplacer( + ol.format.GML3.prototype.readMultiSurface_), + 'Curve': ol.xml.makeReplacer(ol.format.GML3.prototype.readCurve_), + 'MultiCurve': ol.xml.makeReplacer( + ol.format.GML3.prototype.readMultiCurve_), + 'Envelope': ol.xml.makeReplacer(ol.format.GML3.prototype.readEnvelope_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.MULTICURVE_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'curveMember': ol.xml.makeArrayPusher( + ol.format.GML3.prototype.curveMemberParser_), + 'curveMembers': ol.xml.makeArrayPusher( + ol.format.GML3.prototype.curveMemberParser_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.MULTISURFACE_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'surfaceMember': ol.xml.makeArrayPusher( + ol.format.GML3.prototype.surfaceMemberParser_), + 'surfaceMembers': ol.xml.makeArrayPusher( + ol.format.GML3.prototype.surfaceMemberParser_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.CURVEMEMBER_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'LineString': ol.xml.makeArrayPusher( + ol.format.GMLBase.prototype.readLineString), + 'Curve': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readCurve_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.SURFACEMEMBER_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'Polygon': ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readPolygon), + 'Surface': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readSurface_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.SURFACE_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'patches': ol.xml.makeReplacer(ol.format.GML3.prototype.readPatch_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.CURVE_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'segments': ol.xml.makeReplacer(ol.format.GML3.prototype.readSegment_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.ENVELOPE_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'lowerCorner': ol.xml.makeArrayPusher( + ol.format.GML3.prototype.readFlatPosList_), + 'upperCorner': ol.xml.makeArrayPusher( + ol.format.GML3.prototype.readFlatPosList_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.PATCHES_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'PolygonPatch': ol.xml.makeReplacer( + ol.format.GML3.prototype.readPolygonPatch_) + } +}); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GML3.prototype.SEGMENTS_PARSERS_ = Object({ + 'http://www.opengis.net/gml' : { + 'LineStringSegment': ol.xml.makeReplacer( + ol.format.GML3.prototype.readLineStringSegment_) + } +}); + + +/** + * @param {Node} node Node. + * @param {ol.geom.Point} value Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writePos_ = function(node, value, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + var axisOrientation = 'enu'; + if (srsName) { + axisOrientation = ol.proj.get(srsName).getAxisOrientation(); + } + var point = value.getCoordinates(); + var coords; + // only 2d for simple features profile + if (axisOrientation.substr(0, 2) === 'en') { + coords = (point[0] + ' ' + point[1]); + } else { + coords = (point[1] + ' ' + point[0]); + } + ol.format.XSD.writeStringTextNode(node, coords); +}; + + +/** + * @param {Array.<number>} point Point geometry. + * @param {string=} opt_srsName Optional srsName + * @return {string} + * @private + */ +ol.format.GML3.prototype.getCoords_ = function(point, opt_srsName) { + var axisOrientation = 'enu'; + if (opt_srsName) { + axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation(); + } + return ((axisOrientation.substr(0, 2) === 'en') ? + point[0] + ' ' + point[1] : + point[1] + ' ' + point[0]); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writePosList_ = function(node, value, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + // only 2d for simple features profile + var points = value.getCoordinates(); + var len = points.length; + var parts = new Array(len); + var point; + for (var i = 0; i < len; ++i) { + point = points[i]; + parts[i] = this.getCoords_(point, srsName); + } + ol.format.XSD.writeStringTextNode(node, parts.join(' ')); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Point} geometry Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writePoint_ = function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + if (srsName) { + node.setAttribute('srsName', srsName); + } + var pos = ol.xml.createElementNS(node.namespaceURI, 'pos'); + node.appendChild(pos); + this.writePos_(pos, geometry, objectStack); +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GML3.ENVELOPE_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.Extent} extent Extent. + * @param {Array.<*>} objectStack Node stack. + */ +ol.format.GML3.prototype.writeEnvelope = function(node, extent, objectStack) { + goog.asserts.assert(extent.length == 4, 'extent should have 4 items'); + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + if (srsName) { + node.setAttribute('srsName', srsName); + } + var keys = ['lowerCorner', 'upperCorner']; + var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]]; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node}), ol.format.GML3.ENVELOPE_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + values, + objectStack, keys, this); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LinearRing} geometry LinearRing geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeLinearRing_ = + function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + if (srsName) { + node.setAttribute('srsName', srsName); + } + var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); + node.appendChild(posList); + this.writePosList_(posList, geometry, objectStack); +}; + + +/** + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node} Node. + * @private + */ +ol.format.GML3.prototype.RING_NODE_FACTORY_ = + function(value, objectStack, opt_nodeName) { + var context = objectStack[objectStack.length - 1]; + var parentNode = context.node; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var exteriorWritten = context['exteriorWritten']; + if (exteriorWritten === undefined) { + context['exteriorWritten'] = true; + } + return ol.xml.createElementNS(parentNode.namespaceURI, + exteriorWritten !== undefined ? 'interior' : 'exterior'); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} geometry Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeSurfaceOrPolygon_ = + function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + if (node.nodeName !== 'PolygonPatch' && srsName) { + node.setAttribute('srsName', srsName); + } + if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') { + var rings = geometry.getLinearRings(); + ol.xml.pushSerializeAndPop( + {node: node, srsName: srsName}, + ol.format.GML3.RING_SERIALIZERS_, + this.RING_NODE_FACTORY_, + rings, objectStack, undefined, this); + } else if (node.nodeName === 'Surface') { + var patches = ol.xml.createElementNS(node.namespaceURI, 'patches'); + node.appendChild(patches); + this.writeSurfacePatches_( + patches, geometry, objectStack); + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} geometry LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeCurveOrLineString_ = + function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + if (node.nodeName !== 'LineStringSegment' && srsName) { + node.setAttribute('srsName', srsName); + } + if (node.nodeName === 'LineString' || + node.nodeName === 'LineStringSegment') { + var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); + node.appendChild(posList); + this.writePosList_(posList, geometry, objectStack); + } else if (node.nodeName === 'Curve') { + var segments = ol.xml.createElementNS(node.namespaceURI, 'segments'); + node.appendChild(segments); + this.writeCurveSegments_(segments, + geometry, objectStack); + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_ = + function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + var surface = context['surface']; + if (srsName) { + node.setAttribute('srsName', srsName); + } + var polygons = geometry.getPolygons(); + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, + ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_, + this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons, + objectStack, undefined, this); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.MultiPoint} geometry MultiPoint geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeMultiPoint_ = function(node, geometry, + objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + if (srsName) { + node.setAttribute('srsName', srsName); + } + var points = geometry.getPoints(); + ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, + ol.format.GML3.POINTMEMBER_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('pointMember'), points, + objectStack, undefined, this); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.MultiLineString} geometry MultiLineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeMultiCurveOrLineString_ = + function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var srsName = context['srsName']; + var curve = context['curve']; + if (srsName) { + node.setAttribute('srsName', srsName); + } + var lines = geometry.getLineStrings(); + ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, + ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_, + this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines, + objectStack, undefined, this); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LinearRing} ring LinearRing geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeRing_ = function(node, ring, objectStack) { + var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing'); + node.appendChild(linearRing); + this.writeLinearRing_(linearRing, ring, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} polygon Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeSurfaceOrPolygonMember_ = + function(node, polygon, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var child = this.GEOMETRY_NODE_FACTORY_( + polygon, objectStack); + if (child) { + node.appendChild(child); + this.writeSurfaceOrPolygon_(child, polygon, objectStack); + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Point} point Point geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writePointMember_ = + function(node, point, objectStack) { + var child = ol.xml.createElementNS(node.namespaceURI, 'Point'); + node.appendChild(child); + this.writePoint_(child, point, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} line LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeLineStringOrCurveMember_ = + function(node, line, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack); + if (child) { + node.appendChild(child); + this.writeCurveOrLineString_(child, line, objectStack); + } +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} polygon Polygon geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeSurfacePatches_ = + function(node, polygon, objectStack) { + var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch'); + node.appendChild(child); + this.writeSurfaceOrPolygon_(child, polygon, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} line LineString geometry. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeCurveSegments_ = + function(node, line, objectStack) { + var child = ol.xml.createElementNS(node.namespaceURI, + 'LineStringSegment'); + node.appendChild(child); + this.writeCurveOrLineString_(child, line, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Geometry|ol.Extent} geometry Geometry. + * @param {Array.<*>} objectStack Node stack. + */ +ol.format.GML3.prototype.writeGeometryElement = + function(node, geometry, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var item = goog.object.clone(context); + item.node = node; + var value; + if (goog.isArray(geometry)) { + if (context.dataProjection) { + value = ol.proj.transformExtent( + geometry, context.featureProjection, context.dataProjection); + } else { + value = geometry; + } + } else { + goog.asserts.assertInstanceof(geometry, ol.geom.Geometry, + 'geometry should be an ol.geom.Geometry'); + value = + ol.format.Feature.transformWithOptions(geometry, true, context); + } + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + (item), ol.format.GML3.GEOMETRY_SERIALIZERS_, + this.GEOMETRY_NODE_FACTORY_, [value], + objectStack, undefined, this); +}; + + +/** + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Node stack. + */ +ol.format.GML3.prototype.writeFeatureElement = + function(node, feature, objectStack) { + var fid = feature.getId(); + if (fid) { + node.setAttribute('fid', fid); + } + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featureNS = context['featureNS']; + var geometryName = feature.getGeometryName(); + if (!context.serializers) { + context.serializers = {}; + context.serializers[featureNS] = {}; + } + var properties = feature.getProperties(); + var keys = [], values = []; + for (var key in properties) { + var value = properties[key]; + if (value !== null) { + keys.push(key); + values.push(value); + if (key == geometryName || value instanceof ol.geom.Geometry) { + if (!(key in context.serializers[featureNS])) { + context.serializers[featureNS][key] = ol.xml.makeChildAppender( + this.writeGeometryElement, this); + } + } else { + if (!(key in context.serializers[featureNS])) { + context.serializers[featureNS][key] = ol.xml.makeChildAppender( + ol.format.XSD.writeStringTextNode); + } + } + } + } + var item = goog.object.clone(context); + item.node = node; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + (item), context.serializers, + ol.xml.makeSimpleNodeFactory(undefined, featureNS), + values, + objectStack, keys); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<ol.Feature>} features Features. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GML3.prototype.writeFeatureMembers_ = + function(node, features, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featureType = context['featureType']; + var featureNS = context['featureNS']; + var serializers = {}; + serializers[featureNS] = {}; + serializers[featureNS][featureType] = ol.xml.makeChildAppender( + this.writeFeatureElement, this); + var item = goog.object.clone(context); + item.node = node; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + (item), + serializers, + ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, + objectStack); +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'surfaceMember': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeSurfaceOrPolygonMember_), + 'polygonMember': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeSurfaceOrPolygonMember_) + } +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GML3.POINTMEMBER_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'pointMember': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writePointMember_) + } +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'lineStringMember': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeLineStringOrCurveMember_), + 'curveMember': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeLineStringOrCurveMember_) + } +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GML3.RING_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'exterior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_), + 'interior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_) + } +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GML3.GEOMETRY_SERIALIZERS_ = { + 'http://www.opengis.net/gml': { + 'Curve': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeCurveOrLineString_), + 'MultiCurve': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeMultiCurveOrLineString_), + 'Point': ol.xml.makeChildAppender(ol.format.GML3.prototype.writePoint_), + 'MultiPoint': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeMultiPoint_), + 'LineString': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeCurveOrLineString_), + 'MultiLineString': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeMultiCurveOrLineString_), + 'LinearRing': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeLinearRing_), + 'Polygon': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeSurfaceOrPolygon_), + 'MultiPolygon': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_), + 'Surface': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeSurfaceOrPolygon_), + 'MultiSurface': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_), + 'Envelope': ol.xml.makeChildAppender( + ol.format.GML3.prototype.writeEnvelope) + } +}; + + +/** + * @const + * @type {Object.<string, string>} + * @private + */ +ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = { + 'MultiLineString': 'lineStringMember', + 'MultiCurve': 'curveMember', + 'MultiPolygon': 'polygonMember', + 'MultiSurface': 'surfaceMember' +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML3.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = + function(value, objectStack, opt_nodeName) { + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode), + 'parentNode should be a node'); + return ol.xml.createElementNS('http://www.opengis.net/gml', + ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]); +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GML3.prototype.GEOMETRY_NODE_FACTORY_ = + function(value, objectStack, opt_nodeName) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var multiSurface = context['multiSurface']; + var surface = context['surface']; + var curve = context['curve']; + var multiCurve = context['multiCurve']; + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode), + 'parentNode should be a node'); + var nodeName; + if (!goog.isArray(value)) { + goog.asserts.assertInstanceof(value, ol.geom.Geometry, + 'value should be an ol.geom.Geometry'); + nodeName = value.getType(); + if (nodeName === 'MultiPolygon' && multiSurface === true) { + nodeName = 'MultiSurface'; + } else if (nodeName === 'Polygon' && surface === true) { + nodeName = 'Surface'; + } else if (nodeName === 'LineString' && curve === true) { + nodeName = 'Curve'; + } else if (nodeName === 'MultiLineString' && multiCurve === true) { + nodeName = 'MultiCurve'; + } + } else { + nodeName = 'Envelope'; + } + return ol.xml.createElementNS('http://www.opengis.net/gml', + nodeName); +}; + + +/** + * Encode a geometry in GML 3.1.1 Simple Features. + * + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + * @api + */ +ol.format.GML3.prototype.writeGeometryNode = function(geometry, opt_options) { + opt_options = this.adaptOptions(opt_options); + var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); + var context = {node: geom, srsName: this.srsName, + curve: this.curve_, surface: this.surface_, + multiSurface: this.multiSurface_, multiCurve: this.multiCurve_}; + if (opt_options) { + goog.object.extend(context, opt_options); + } + this.writeGeometryElement(geom, geometry, [context]); + return geom; +}; + + +/** + * Encode an array of features in GML 3.1.1 Simple Features. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {string} Result. + * @api stable + */ +ol.format.GML3.prototype.writeFeatures; + + +/** + * Encode an array of features in the GML 3.1.1 format as an XML node. + * + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + * @api + */ +ol.format.GML3.prototype.writeFeaturesNode = function(features, opt_options) { + opt_options = this.adaptOptions(opt_options); + var node = ol.xml.createElementNS('http://www.opengis.net/gml', + 'featureMembers'); + ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation', this.schemaLocation); + var context = { + srsName: this.srsName, + curve: this.curve_, + surface: this.surface_, + multiSurface: this.multiSurface_, + multiCurve: this.multiCurve_, + featureNS: this.featureNS, + featureType: this.featureType + }; + if (opt_options) { + goog.object.extend(context, opt_options); + } + this.writeFeatureMembers_(node, features, [context]); + return node; +}; + + + +/** + * @classdesc + * Feature format for reading and writing data in the GML format + * version 3.1.1. + * Currently only supports GML 3.1.1 Simple Features profile. + * + * @constructor + * @param {olx.format.GMLOptions=} opt_options + * Optional configuration object. + * @extends {ol.format.GMLBase} + * @api stable + */ +ol.format.GML = ol.format.GML3; + + +/** + * Encode an array of features in GML 3.1.1 Simple Features. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {string} Result. + * @api stable + */ +ol.format.GML.prototype.writeFeatures; + + +/** + * Encode an array of features in the GML 3.1.1 format as an XML node. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + * @api + */ +ol.format.GML.prototype.writeFeaturesNode; + +goog.provide('ol.format.GPX'); + +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('ol.Feature'); +goog.require('ol.array'); +goog.require('ol.format.Feature'); +goog.require('ol.format.XMLFeature'); +goog.require('ol.format.XSD'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.Point'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @classdesc + * Feature format for reading and writing data in the GPX format. + * + * @constructor + * @extends {ol.format.XMLFeature} + * @param {olx.format.GPXOptions=} opt_options Options. + * @api stable + */ +ol.format.GPX = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this); + + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + + /** + * @type {function(ol.Feature, Node)|undefined} + * @private + */ + this.readExtensions_ = options.readExtensions; +}; +goog.inherits(ol.format.GPX, ol.format.XMLFeature); + + +/** + * @const + * @private + * @type {Array.<string>} + */ +ol.format.GPX.NAMESPACE_URIS_ = [ + null, + 'http://www.topografix.com/GPX/1/0', + 'http://www.topografix.com/GPX/1/1' +]; + + +/** + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {Node} node Node. + * @param {Object} values Values. + * @private + * @return {Array.<number>} Flat coordinates. + */ +ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + flatCoordinates.push( + parseFloat(node.getAttribute('lon')), + parseFloat(node.getAttribute('lat'))); + if ('ele' in values) { + flatCoordinates.push(/** @type {number} */ (values['ele'])); + delete values['ele']; + } else { + flatCoordinates.push(0); + } + if ('time' in values) { + flatCoordinates.push(/** @type {number} */ (values['time'])); + delete values['time']; + } else { + flatCoordinates.push(0); + } + return flatCoordinates; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseLink_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'link', 'localName should be link'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var href = node.getAttribute('href'); + if (href !== null) { + values['link'] = href; + } + ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseExtensions_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'extensions', + 'localName should be extensions'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + values['extensionsNode_'] = node; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseRtePt_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'rtept', 'localName should be rtept'); + var values = ol.xml.pushParseAndPop( + {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack); + if (values) { + var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var flatCoordinates = /** @type {Array.<number>} */ + (rteValues['flatCoordinates']); + ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseTrkPt_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'trkpt', 'localName should be trkpt'); + var values = ol.xml.pushParseAndPop( + {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack); + if (values) { + var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var flatCoordinates = /** @type {Array.<number>} */ + (trkValues['flatCoordinates']); + ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseTrkSeg_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'trkseg', + 'localName should be trkseg'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack); + var flatCoordinates = /** @type {Array.<number>} */ + (values['flatCoordinates']); + var ends = /** @type {Array.<number>} */ (values['ends']); + ends.push(flatCoordinates.length); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Track. + */ +ol.format.GPX.readRte_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'rte', 'localName should be rte'); + var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); + var values = ol.xml.pushParseAndPop({ + 'flatCoordinates': [] + }, ol.format.GPX.RTE_PARSERS_, node, objectStack); + if (!values) { + return undefined; + } + var flatCoordinates = /** @type {Array.<number>} */ + (values['flatCoordinates']); + delete values['flatCoordinates']; + var geometry = new ol.geom.LineString(null); + geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); + ol.format.Feature.transformWithOptions(geometry, false, options); + var feature = new ol.Feature(geometry); + feature.setProperties(values); + return feature; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Track. + */ +ol.format.GPX.readTrk_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'trk', 'localName should be trk'); + var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); + var values = ol.xml.pushParseAndPop({ + 'flatCoordinates': [], + 'ends': [] + }, ol.format.GPX.TRK_PARSERS_, node, objectStack); + if (!values) { + return undefined; + } + var flatCoordinates = /** @type {Array.<number>} */ + (values['flatCoordinates']); + delete values['flatCoordinates']; + var ends = /** @type {Array.<number>} */ (values['ends']); + delete values['ends']; + var geometry = new ol.geom.MultiLineString(null); + geometry.setFlatCoordinates( + ol.geom.GeometryLayout.XYZM, flatCoordinates, ends); + ol.format.Feature.transformWithOptions(geometry, false, options); + var feature = new ol.Feature(geometry); + feature.setProperties(values); + return feature; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Waypoint. + */ +ol.format.GPX.readWpt_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'wpt', 'localName should be wpt'); + var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); + var values = ol.xml.pushParseAndPop( + {}, ol.format.GPX.WPT_PARSERS_, node, objectStack); + if (!values) { + return undefined; + } + var coordinates = ol.format.GPX.appendCoordinate_([], node, values); + var geometry = new ol.geom.Point( + coordinates, ol.geom.GeometryLayout.XYZM); + ol.format.Feature.transformWithOptions(geometry, false, options); + var feature = new ol.Feature(geometry); + feature.setProperties(values); + return feature; +}; + + +/** + * @const + * @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>} + * @private + */ +ol.format.GPX.FEATURE_READER_ = { + 'rte': ol.format.GPX.readRte_, + 'trk': ol.format.GPX.readTrk_, + 'wpt': ol.format.GPX.readWpt_ +}; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_), + 'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_), + 'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'text': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'), + 'type': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType') + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'link': ol.format.GPX.parseLink_, + 'number': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), + 'extensions': ol.format.GPX.parseExtensions_, + 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'rtept': ol.format.GPX.parseRtePt_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'link': ol.format.GPX.parseLink_, + 'number': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), + 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'extensions': ol.format.GPX.parseExtensions_, + 'trkseg': ol.format.GPX.parseTrkSeg_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'trkpt': ol.format.GPX.parseTrkPt_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.GPX.WPT_PARSERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime), + 'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'link': ol.format.GPX.parseLink_, + 'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'sat': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'ageofdgpsdata': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'dgpsid': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), + 'extensions': ol.format.GPX.parseExtensions_ + }); + + +/** + * @param {Array.<ol.Feature>} features + * @private + */ +ol.format.GPX.prototype.handleReadExtensions_ = function(features) { + if (!features) { + features = []; + } + for (var i = 0, ii = features.length; i < ii; ++i) { + var feature = features[i]; + if (this.readExtensions_) { + var extensionsNode = feature.get('extensionsNode_') || null; + this.readExtensions_(feature, extensionsNode); + } + feature.set('extensionsNode_', undefined); + } +}; + + +/** + * Read the first feature from a GPX source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @api stable + */ +ol.format.GPX.prototype.readFeature; + + +/** + * @inheritDoc + */ +ol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) { + return null; + } + var featureReader = ol.format.GPX.FEATURE_READER_[node.localName]; + if (!featureReader) { + return null; + } + var feature = featureReader(node, [this.getReadOptions(node, opt_options)]); + if (!feature) { + return null; + } + this.handleReadExtensions_([feature]); + return feature; +}; + + +/** + * Read all features from a GPX source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api stable + */ +ol.format.GPX.prototype.readFeatures; + + +/** + * @inheritDoc + */ +ol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) { + return []; + } + if (node.localName == 'gpx') { + var features = ol.xml.pushParseAndPop( + /** @type {Array.<ol.Feature>} */ ([]), ol.format.GPX.GPX_PARSERS_, + node, [this.getReadOptions(node, opt_options)]); + if (features) { + this.handleReadExtensions_(features); + return features; + } else { + return []; + } + } + return []; +}; + + +/** + * Read the projection from a GPX source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. + * @api stable + */ +ol.format.GPX.prototype.readProjection; + + +/** + * @param {Node} node Node. + * @param {string} value Value for the link's `href` attribute. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.GPX.writeLink_ = function(node, value, objectStack) { + node.setAttribute('href', value); + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var properties = context['properties']; + var link = [ + properties['linkText'], + properties['linkType'] + ]; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ ({node: node}), + ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + link, objectStack, ol.format.GPX.LINK_SEQUENCE_); +}; + + +/** + * @param {Node} node Node. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var parentNode = context.node; + goog.asserts.assert(ol.xml.isNode(parentNode), + 'parentNode should be an XML node'); + var namespaceURI = parentNode.namespaceURI; + var properties = context['properties']; + //FIXME Projection handling + ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]); + ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]); + var geometryLayout = context['geometryLayout']; + /* jshint -W086 */ + switch (geometryLayout) { + case ol.geom.GeometryLayout.XYZM: + if (coordinate[3] !== 0) { + properties['time'] = coordinate[3]; + } + case ol.geom.GeometryLayout.XYZ: + if (coordinate[2] !== 0) { + properties['ele'] = coordinate[2]; + } + break; + case ol.geom.GeometryLayout.XYM: + if (coordinate[2] !== 0) { + properties['time'] = coordinate[2]; + } + } + /* jshint +W086 */ + var orderedKeys = ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: node, 'properties': properties}), + ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.writeRte_ = function(node, feature, objectStack) { + var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); + var properties = feature.getProperties(); + var context = {node: node, 'properties': properties}; + var geometry = feature.getGeometry(); + if (geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.LineString, + 'geometry should be an ol.geom.LineString'); + geometry = /** @type {ol.geom.LineString} */ + (ol.format.Feature.transformWithOptions(geometry, true, options)); + context['geometryLayout'] = geometry.getLayout(); + properties['rtept'] = geometry.getCoordinates(); + } + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), + ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.writeTrk_ = function(node, feature, objectStack) { + var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); + var properties = feature.getProperties(); + var context = {node: node, 'properties': properties}; + var geometry = feature.getGeometry(); + if (geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, + 'geometry should be an ol.geom.MultiLineString'); + geometry = /** @type {ol.geom.MultiLineString} */ + (ol.format.Feature.transformWithOptions(geometry, true, options)); + properties['trkseg'] = geometry.getLineStrings(); + } + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), + ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LineString} lineString LineString. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) { + var context = {node: node, 'geometryLayout': lineString.getLayout(), + 'properties': {}}; + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), + ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_, + lineString.getCoordinates(), objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.writeWpt_ = function(node, feature, objectStack) { + var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + context['properties'] = feature.getProperties(); + var geometry = feature.getGeometry(); + if (geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.Point, + 'geometry should be an ol.geom.Point'); + geometry = /** @type {ol.geom.Point} */ + (ol.format.Feature.transformWithOptions(geometry, true, options)); + context['geometryLayout'] = geometry.getLayout(); + ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack); + } +}; + + +/** + * @const + * @type {Array.<string>} + * @private + */ +ol.format.GPX.LINK_SEQUENCE_ = ['text', 'type']; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, [ + 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), + 'number': ol.xml.makeChildAppender( + ol.format.XSD.writeNonNegativeIntegerTextNode), + 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender( + ol.format.GPX.writeWptType_)) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, [ + 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), + 'number': ol.xml.makeChildAppender( + ol.format.XSD.writeNonNegativeIntegerTextNode), + 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender( + ol.format.GPX.writeTrkSeg_)) + }); + + +/** + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt'); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, [ + 'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src', + 'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop', + 'ageofdgpsdata', 'dgpsid' + ]); + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode), + 'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'geoidheight': ol.xml.makeChildAppender( + ol.format.XSD.writeDecimalTextNode), + 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), + 'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'sat': ol.xml.makeChildAppender( + ol.format.XSD.writeNonNegativeIntegerTextNode), + 'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'ageofdgpsdata': ol.xml.makeChildAppender( + ol.format.XSD.writeDecimalTextNode), + 'dgpsid': ol.xml.makeChildAppender( + ol.format.XSD.writeNonNegativeIntegerTextNode) + }); + + +/** + * @const + * @type {Object.<string, string>} + * @private + */ +ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = { + 'Point': 'wpt', + 'LineString': 'rte', + 'MultiLineString': 'trk' +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { + goog.asserts.assertInstanceof(value, ol.Feature, + 'value should be an ol.Feature'); + var geometry = value.getGeometry(); + if (geometry) { + var nodeName = ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()]; + if (nodeName) { + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode), + 'parentNode should be an XML node'); + return ol.xml.createElementNS(parentNode.namespaceURI, nodeName); + } + } +}; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_), + 'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_), + 'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_) + }); + + +/** + * Encode an array of features in the GPX format. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} Result. + * @api stable + */ +ol.format.GPX.prototype.writeFeatures; + + +/** + * Encode an array of features in the GPX format as an XML node. + * + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + * @api + */ +ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) { + opt_options = this.adaptOptions(opt_options); + //FIXME Serialize metadata + var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx'); + + ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ + ({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_, + ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]); + return gpx; +}; + +// Copyright 2013 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Utilities for string newlines. + * @author nnaze@google.com (Nathan Naze) + */ + + +/** + * Namespace for string utilities + */ +goog.provide('goog.string.newlines'); +goog.provide('goog.string.newlines.Line'); + +goog.require('goog.array'); + + +/** + * Splits a string into lines, properly handling universal newlines. + * @param {string} str String to split. + * @param {boolean=} opt_keepNewlines Whether to keep the newlines in the + * resulting strings. Defaults to false. + * @return {!Array<string>} String split into lines. + */ +goog.string.newlines.splitLines = function(str, opt_keepNewlines) { + var lines = goog.string.newlines.getLines(str); + return goog.array.map(lines, function(line) { + return opt_keepNewlines ? line.getFullLine() : line.getContent(); + }); +}; + + + +/** + * Line metadata class that records the start/end indicies of lines + * in a string. Can be used to implement common newline use cases such as + * splitLines() or determining line/column of an index in a string. + * Also implements methods to get line contents. + * + * Indexes are expressed as string indicies into string.substring(), inclusive + * at the start, exclusive at the end. + * + * Create an array of these with goog.string.newlines.getLines(). + * @param {string} string The original string. + * @param {number} startLineIndex The index of the start of the line. + * @param {number} endContentIndex The index of the end of the line, excluding + * newlines. + * @param {number} endLineIndex The index of the end of the line, index + * newlines. + * @constructor + * @struct + * @final + */ +goog.string.newlines.Line = function(string, startLineIndex, + endContentIndex, endLineIndex) { + /** + * The original string. + * @type {string} + */ + this.string = string; + + /** + * Index of the start of the line. + * @type {number} + */ + this.startLineIndex = startLineIndex; + + /** + * Index of the end of the line, excluding any newline characters. + * Index is the first character after the line, suitable for + * String.substring(). + * @type {number} + */ + this.endContentIndex = endContentIndex; + + /** + * Index of the end of the line, excluding any newline characters. + * Index is the first character after the line, suitable for + * String.substring(). + * @type {number} + */ + + this.endLineIndex = endLineIndex; +}; + + +/** + * @return {string} The content of the line, excluding any newline characters. + */ +goog.string.newlines.Line.prototype.getContent = function() { + return this.string.substring(this.startLineIndex, this.endContentIndex); +}; + + +/** + * @return {string} The full line, including any newline characters. + */ +goog.string.newlines.Line.prototype.getFullLine = function() { + return this.string.substring(this.startLineIndex, this.endLineIndex); +}; + + +/** + * @return {string} The newline characters, if any ('\n', \r', '\r\n', '', etc). + */ +goog.string.newlines.Line.prototype.getNewline = function() { + return this.string.substring(this.endContentIndex, this.endLineIndex); +}; + + +/** + * Splits a string into an array of line metadata. + * @param {string} str String to split. + * @return {!Array<!goog.string.newlines.Line>} Array of line metadata. + */ +goog.string.newlines.getLines = function(str) { + // We use the constructor because literals are evaluated only once in + // < ES 3.1. + // See http://www.mail-archive.com/es-discuss@mozilla.org/msg01796.html + var re = RegExp('\r\n|\r|\n', 'g'); + var sliceIndex = 0; + var result; + var lines = []; + + while (result = re.exec(str)) { + var line = new goog.string.newlines.Line( + str, sliceIndex, result.index, result.index + result[0].length); + lines.push(line); + + // remember where to start the slice from + sliceIndex = re.lastIndex; + } + + // If the string does not end with a newline, add the last line. + if (sliceIndex < str.length) { + var line = new goog.string.newlines.Line( + str, sliceIndex, str.length, str.length); + lines.push(line); + } + + return lines; +}; + +goog.provide('ol.format.TextFeature'); + +goog.require('goog.asserts'); +goog.require('ol.format.Feature'); +goog.require('ol.format.FormatType'); + + + +/** + * @classdesc + * Abstract base class; normally only used for creating subclasses and not + * instantiated in apps. + * Base class for text feature formats. + * + * @constructor + * @extends {ol.format.Feature} + */ +ol.format.TextFeature = function() { + goog.base(this); +}; +goog.inherits(ol.format.TextFeature, ol.format.Feature); + + +/** + * @param {Document|Node|Object|string} source Source. + * @private + * @return {string} Text. + */ +ol.format.TextFeature.prototype.getText_ = function(source) { + if (goog.isString(source)) { + return source; + } else { + goog.asserts.fail(); + return ''; + } +}; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.getType = function() { + return ol.format.FormatType.TEXT; +}; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.readFeature = function(source, opt_options) { + return this.readFeatureFromText( + this.getText_(source), this.adaptOptions(opt_options)); +}; + + +/** + * @param {string} text Text. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @protected + * @return {ol.Feature} Feature. + */ +ol.format.TextFeature.prototype.readFeatureFromText = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) { + return this.readFeaturesFromText( + this.getText_(source), this.adaptOptions(opt_options)); +}; + + +/** + * @param {string} text Text. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @protected + * @return {Array.<ol.Feature>} Features. + */ +ol.format.TextFeature.prototype.readFeaturesFromText = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) { + return this.readGeometryFromText( + this.getText_(source), this.adaptOptions(opt_options)); +}; + + +/** + * @param {string} text Text. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @protected + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.TextFeature.prototype.readGeometryFromText = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.readProjection = function(source) { + return this.readProjectionFromText(this.getText_(source)); +}; + + +/** + * @param {string} text Text. + * @protected + * @return {ol.proj.Projection} Projection. + */ +ol.format.TextFeature.prototype.readProjectionFromText = function(text) { + return this.defaultDataProjection; +}; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) { + return this.writeFeatureText(feature, this.adaptOptions(opt_options)); +}; + + +/** + * @param {ol.Feature} feature Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @protected + * @return {string} Text. + */ +ol.format.TextFeature.prototype.writeFeatureText = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.writeFeatures = function( + features, opt_options) { + return this.writeFeaturesText(features, this.adaptOptions(opt_options)); +}; + + +/** + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @protected + * @return {string} Text. + */ +ol.format.TextFeature.prototype.writeFeaturesText = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.format.TextFeature.prototype.writeGeometry = function( + geometry, opt_options) { + return this.writeGeometryText(geometry, this.adaptOptions(opt_options)); +}; + + +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @protected + * @return {string} Text. + */ +ol.format.TextFeature.prototype.writeGeometryText = goog.abstractMethod; + +goog.provide('ol.format.IGC'); +goog.provide('ol.format.IGCZ'); + +goog.require('goog.asserts'); +goog.require('goog.string'); +goog.require('goog.string.newlines'); +goog.require('ol.Feature'); +goog.require('ol.format.Feature'); +goog.require('ol.format.TextFeature'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.proj'); + + +/** + * IGC altitude/z. One of 'barometric', 'gps', 'none'. + * @enum {string} + * @api + */ +ol.format.IGCZ = { + BAROMETRIC: 'barometric', + GPS: 'gps', + NONE: 'none' +}; + + + +/** + * @classdesc + * Feature format for `*.igc` flight recording files. + * + * @constructor + * @extends {ol.format.TextFeature} + * @param {olx.format.IGCOptions=} opt_options Options. + * @api + */ +ol.format.IGC = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this); + + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + + /** + * @private + * @type {ol.format.IGCZ} + */ + this.altitudeMode_ = options.altitudeMode ? + options.altitudeMode : ol.format.IGCZ.NONE; + +}; +goog.inherits(ol.format.IGC, ol.format.TextFeature); + + +/** + * @const + * @type {Array.<string>} + * @private + */ +ol.format.IGC.EXTENSIONS_ = ['.igc']; + + +/** + * @const + * @type {RegExp} + * @private + */ +ol.format.IGC.B_RECORD_RE_ = + /^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/; + + +/** + * @const + * @type {RegExp} + * @private + */ +ol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/; + + +/** + * @const + * @type {RegExp} + * @private + */ +ol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\d{2})(\d{2})(\d{2})/; + + +/** + * @inheritDoc + */ +ol.format.IGC.prototype.getExtensions = function() { + return ol.format.IGC.EXTENSIONS_; +}; + + +/** + * Read the feature from the IGC source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @api + */ +ol.format.IGC.prototype.readFeature; + + +/** + * @inheritDoc + */ +ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) { + var altitudeMode = this.altitudeMode_; + var lines = goog.string.newlines.splitLines(text); + /** @type {Object.<string, string>} */ + var properties = {}; + var flatCoordinates = []; + var year = 2000; + var month = 0; + var day = 1; + var i, ii; + for (i = 0, ii = lines.length; i < ii; ++i) { + var line = lines[i]; + var m; + if (line.charAt(0) == 'B') { + m = ol.format.IGC.B_RECORD_RE_.exec(line); + if (m) { + var hour = parseInt(m[1], 10); + var minute = parseInt(m[2], 10); + var second = parseInt(m[3], 10); + var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000; + if (m[6] == 'S') { + y = -y; + } + var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000; + if (m[9] == 'W') { + x = -x; + } + flatCoordinates.push(x, y); + if (altitudeMode != ol.format.IGCZ.NONE) { + var z; + if (altitudeMode == ol.format.IGCZ.GPS) { + z = parseInt(m[11], 10); + } else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) { + z = parseInt(m[12], 10); + } else { + goog.asserts.fail(); + z = 0; + } + flatCoordinates.push(z); + } + var dateTime = Date.UTC(year, month, day, hour, minute, second); + flatCoordinates.push(dateTime / 1000); + } + } else if (line.charAt(0) == 'H') { + m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line); + if (m) { + day = parseInt(m[1], 10); + month = parseInt(m[2], 10) - 1; + year = 2000 + parseInt(m[3], 10); + } else { + m = ol.format.IGC.H_RECORD_RE_.exec(line); + if (m) { + properties[m[1]] = m[2].trim(); + m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line); + } + } + } + } + if (flatCoordinates.length === 0) { + return null; + } + var lineString = new ol.geom.LineString(null); + var layout = altitudeMode == ol.format.IGCZ.NONE ? + ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM; + lineString.setFlatCoordinates(layout, flatCoordinates); + var feature = new ol.Feature(ol.format.Feature.transformWithOptions( + lineString, false, opt_options)); + feature.setProperties(properties); + return feature; +}; + + +/** + * Read the feature from the source. As IGC sources contain a single + * feature, this will return the feature in an array. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api + */ +ol.format.IGC.prototype.readFeatures; + + +/** + * @inheritDoc + */ +ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) { + var feature = this.readFeatureFromText(text, opt_options); + if (feature) { + return [feature]; + } else { + return []; + } +}; + + +/** + * Read the projection from the IGC source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. + * @api + */ +ol.format.IGC.prototype.readProjection; + +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Class for parsing and formatting URIs. + * + * Use goog.Uri(string) to parse a URI string. Use goog.Uri.create(...) to + * create a new instance of the goog.Uri object from Uri parts. + * + * e.g: <code>var myUri = new goog.Uri(window.location);</code> + * + * Implements RFC 3986 for parsing/formatting URIs. + * http://www.ietf.org/rfc/rfc3986.txt + * + * Some changes have been made to the interface (more like .NETs), though the + * internal representation is now of un-encoded parts, this will change the + * behavior slightly. + * + */ + +goog.provide('goog.Uri'); +goog.provide('goog.Uri.QueryData'); + +goog.require('goog.array'); +goog.require('goog.string'); +goog.require('goog.structs'); +goog.require('goog.structs.Map'); +goog.require('goog.uri.utils'); +goog.require('goog.uri.utils.ComponentIndex'); +goog.require('goog.uri.utils.StandardQueryParam'); + + + +/** + * This class contains setters and getters for the parts of the URI. + * The <code>getXyz</code>/<code>setXyz</code> methods return the decoded part + * -- so<code>goog.Uri.parse('/foo%20bar').getPath()</code> will return the + * decoded path, <code>/foo bar</code>. + * + * Reserved characters (see RFC 3986 section 2.2) can be present in + * their percent-encoded form in scheme, domain, and path URI components and + * will not be auto-decoded. For example: + * <code>goog.Uri.parse('rel%61tive/path%2fto/resource').getPath()</code> will + * return <code>relative/path%2fto/resource</code>. + * + * The constructor accepts an optional unparsed, raw URI string. The parser + * is relaxed, so special characters that aren't escaped but don't cause + * ambiguities will not cause parse failures. + * + * All setters return <code>this</code> and so may be chained, a la + * <code>goog.Uri.parse('/foo').setFragment('part').toString()</code>. + * + * @param {*=} opt_uri Optional string URI to parse + * (use goog.Uri.create() to create a URI from parts), or if + * a goog.Uri is passed, a clone is created. + * @param {boolean=} opt_ignoreCase If true, #getParameterValue will ignore + * the case of the parameter name. + * + * @throws URIError If opt_uri is provided and URI is malformed (that is, + * if decodeURIComponent fails on any of the URI components). + * @constructor + * @struct + */ +goog.Uri = function(opt_uri, opt_ignoreCase) { + /** + * Scheme such as "http". + * @private {string} + */ + this.scheme_ = ''; + + /** + * User credentials in the form "username:password". + * @private {string} + */ + this.userInfo_ = ''; + + /** + * Domain part, e.g. "www.google.com". + * @private {string} + */ + this.domain_ = ''; + + /** + * Port, e.g. 8080. + * @private {?number} + */ + this.port_ = null; + + /** + * Path, e.g. "/tests/img.png". + * @private {string} + */ + this.path_ = ''; + + /** + * The fragment without the #. + * @private {string} + */ + this.fragment_ = ''; + + /** + * Whether or not this Uri should be treated as Read Only. + * @private {boolean} + */ + this.isReadOnly_ = false; + + /** + * Whether or not to ignore case when comparing query params. + * @private {boolean} + */ + this.ignoreCase_ = false; + + /** + * Object representing query data. + * @private {!goog.Uri.QueryData} + */ + this.queryData_; + + // Parse in the uri string + var m; + if (opt_uri instanceof goog.Uri) { + this.ignoreCase_ = goog.isDef(opt_ignoreCase) ? + opt_ignoreCase : opt_uri.getIgnoreCase(); + this.setScheme(opt_uri.getScheme()); + this.setUserInfo(opt_uri.getUserInfo()); + this.setDomain(opt_uri.getDomain()); + this.setPort(opt_uri.getPort()); + this.setPath(opt_uri.getPath()); + this.setQueryData(opt_uri.getQueryData().clone()); + this.setFragment(opt_uri.getFragment()); + } else if (opt_uri && (m = goog.uri.utils.split(String(opt_uri)))) { + this.ignoreCase_ = !!opt_ignoreCase; + + // Set the parts -- decoding as we do so. + // COMPATABILITY NOTE - In IE, unmatched fields may be empty strings, + // whereas in other browsers they will be undefined. + this.setScheme(m[goog.uri.utils.ComponentIndex.SCHEME] || '', true); + this.setUserInfo(m[goog.uri.utils.ComponentIndex.USER_INFO] || '', true); + this.setDomain(m[goog.uri.utils.ComponentIndex.DOMAIN] || '', true); + this.setPort(m[goog.uri.utils.ComponentIndex.PORT]); + this.setPath(m[goog.uri.utils.ComponentIndex.PATH] || '', true); + this.setQueryData(m[goog.uri.utils.ComponentIndex.QUERY_DATA] || '', true); + this.setFragment(m[goog.uri.utils.ComponentIndex.FRAGMENT] || '', true); + + } else { + this.ignoreCase_ = !!opt_ignoreCase; + this.queryData_ = new goog.Uri.QueryData(null, null, this.ignoreCase_); + } +}; + + +/** + * If true, we preserve the type of query parameters set programmatically. + * + * This means that if you set a parameter to a boolean, and then call + * getParameterValue, you will get a boolean back. + * + * If false, we will coerce parameters to strings, just as they would + * appear in real URIs. + * + * TODO(nicksantos): Remove this once people have time to fix all tests. + * + * @type {boolean} + */ +goog.Uri.preserveParameterTypesCompatibilityFlag = false; + + +/** + * Parameter name added to stop caching. + * @type {string} + */ +goog.Uri.RANDOM_PARAM = goog.uri.utils.StandardQueryParam.RANDOM; + + +/** + * @return {string} The string form of the url. + * @override + */ +goog.Uri.prototype.toString = function() { + var out = []; + + var scheme = this.getScheme(); + if (scheme) { + out.push(goog.Uri.encodeSpecialChars_( + scheme, goog.Uri.reDisallowedInSchemeOrUserInfo_, true), ':'); + } + + var domain = this.getDomain(); + if (domain || scheme == 'file') { + out.push('//'); + + var userInfo = this.getUserInfo(); + if (userInfo) { + out.push(goog.Uri.encodeSpecialChars_( + userInfo, goog.Uri.reDisallowedInSchemeOrUserInfo_, true), '@'); + } + + out.push(goog.Uri.removeDoubleEncoding_(goog.string.urlEncode(domain))); + + var port = this.getPort(); + if (port != null) { + out.push(':', String(port)); + } + } + + var path = this.getPath(); + if (path) { + if (this.hasDomain() && path.charAt(0) != '/') { + out.push('/'); + } + out.push(goog.Uri.encodeSpecialChars_( + path, + path.charAt(0) == '/' ? + goog.Uri.reDisallowedInAbsolutePath_ : + goog.Uri.reDisallowedInRelativePath_, + true)); + } + + var query = this.getEncodedQuery(); + if (query) { + out.push('?', query); + } + + var fragment = this.getFragment(); + if (fragment) { + out.push('#', goog.Uri.encodeSpecialChars_( + fragment, goog.Uri.reDisallowedInFragment_)); + } + return out.join(''); +}; + + +/** + * Resolves the given relative URI (a goog.Uri object), using the URI + * represented by this instance as the base URI. + * + * There are several kinds of relative URIs:<br> + * 1. foo - replaces the last part of the path, the whole query and fragment<br> + * 2. /foo - replaces the the path, the query and fragment<br> + * 3. //foo - replaces everything from the domain on. foo is a domain name<br> + * 4. ?foo - replace the query and fragment<br> + * 5. #foo - replace the fragment only + * + * Additionally, if relative URI has a non-empty path, all ".." and "." + * segments will be resolved, as described in RFC 3986. + * + * @param {!goog.Uri} relativeUri The relative URI to resolve. + * @return {!goog.Uri} The resolved URI. + */ +goog.Uri.prototype.resolve = function(relativeUri) { + + var absoluteUri = this.clone(); + + // we satisfy these conditions by looking for the first part of relativeUri + // that is not blank and applying defaults to the rest + + var overridden = relativeUri.hasScheme(); + + if (overridden) { + absoluteUri.setScheme(relativeUri.getScheme()); + } else { + overridden = relativeUri.hasUserInfo(); + } + + if (overridden) { + absoluteUri.setUserInfo(relativeUri.getUserInfo()); + } else { + overridden = relativeUri.hasDomain(); + } + + if (overridden) { + absoluteUri.setDomain(relativeUri.getDomain()); + } else { + overridden = relativeUri.hasPort(); + } + + var path = relativeUri.getPath(); + if (overridden) { + absoluteUri.setPort(relativeUri.getPort()); + } else { + overridden = relativeUri.hasPath(); + if (overridden) { + // resolve path properly + if (path.charAt(0) != '/') { + // path is relative + if (this.hasDomain() && !this.hasPath()) { + // RFC 3986, section 5.2.3, case 1 + path = '/' + path; + } else { + // RFC 3986, section 5.2.3, case 2 + var lastSlashIndex = absoluteUri.getPath().lastIndexOf('/'); + if (lastSlashIndex != -1) { + path = absoluteUri.getPath().substr(0, lastSlashIndex + 1) + path; + } + } + } + path = goog.Uri.removeDotSegments(path); + } + } + + if (overridden) { + absoluteUri.setPath(path); + } else { + overridden = relativeUri.hasQuery(); + } + + if (overridden) { + absoluteUri.setQueryData(relativeUri.getDecodedQuery()); + } else { + overridden = relativeUri.hasFragment(); + } + + if (overridden) { + absoluteUri.setFragment(relativeUri.getFragment()); + } + + return absoluteUri; +}; + + +/** + * Clones the URI instance. + * @return {!goog.Uri} New instance of the URI object. + */ +goog.Uri.prototype.clone = function() { + return new goog.Uri(this); +}; + + +/** + * @return {string} The encoded scheme/protocol for the URI. + */ +goog.Uri.prototype.getScheme = function() { + return this.scheme_; +}; + + +/** + * Sets the scheme/protocol. + * @throws URIError If opt_decode is true and newScheme is malformed (that is, + * if decodeURIComponent fails). + * @param {string} newScheme New scheme value. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setScheme = function(newScheme, opt_decode) { + this.enforceReadOnly(); + this.scheme_ = opt_decode ? goog.Uri.decodeOrEmpty_(newScheme, true) : + newScheme; + + // remove an : at the end of the scheme so somebody can pass in + // window.location.protocol + if (this.scheme_) { + this.scheme_ = this.scheme_.replace(/:$/, ''); + } + return this; +}; + + +/** + * @return {boolean} Whether the scheme has been set. + */ +goog.Uri.prototype.hasScheme = function() { + return !!this.scheme_; +}; + + +/** + * @return {string} The decoded user info. + */ +goog.Uri.prototype.getUserInfo = function() { + return this.userInfo_; +}; + + +/** + * Sets the userInfo. + * @throws URIError If opt_decode is true and newUserInfo is malformed (that is, + * if decodeURIComponent fails). + * @param {string} newUserInfo New userInfo value. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setUserInfo = function(newUserInfo, opt_decode) { + this.enforceReadOnly(); + this.userInfo_ = opt_decode ? goog.Uri.decodeOrEmpty_(newUserInfo) : + newUserInfo; + return this; +}; + + +/** + * @return {boolean} Whether the user info has been set. + */ +goog.Uri.prototype.hasUserInfo = function() { + return !!this.userInfo_; +}; + + +/** + * @return {string} The decoded domain. + */ +goog.Uri.prototype.getDomain = function() { + return this.domain_; +}; + + +/** + * Sets the domain. + * @throws URIError If opt_decode is true and newDomain is malformed (that is, + * if decodeURIComponent fails). + * @param {string} newDomain New domain value. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setDomain = function(newDomain, opt_decode) { + this.enforceReadOnly(); + this.domain_ = opt_decode ? goog.Uri.decodeOrEmpty_(newDomain, true) : + newDomain; + return this; +}; + + +/** + * @return {boolean} Whether the domain has been set. + */ +goog.Uri.prototype.hasDomain = function() { + return !!this.domain_; +}; + + +/** + * @return {?number} The port number. + */ +goog.Uri.prototype.getPort = function() { + return this.port_; +}; + + +/** + * Sets the port number. + * @param {*} newPort Port number. Will be explicitly casted to a number. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setPort = function(newPort) { + this.enforceReadOnly(); + + if (newPort) { + newPort = Number(newPort); + if (isNaN(newPort) || newPort < 0) { + throw Error('Bad port number ' + newPort); + } + this.port_ = newPort; + } else { + this.port_ = null; + } + + return this; +}; + + +/** + * @return {boolean} Whether the port has been set. + */ +goog.Uri.prototype.hasPort = function() { + return this.port_ != null; +}; + + +/** + * @return {string} The decoded path. + */ +goog.Uri.prototype.getPath = function() { + return this.path_; +}; + + +/** + * Sets the path. + * @throws URIError If opt_decode is true and newPath is malformed (that is, + * if decodeURIComponent fails). + * @param {string} newPath New path value. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setPath = function(newPath, opt_decode) { + this.enforceReadOnly(); + this.path_ = opt_decode ? goog.Uri.decodeOrEmpty_(newPath, true) : newPath; + return this; +}; + + +/** + * @return {boolean} Whether the path has been set. + */ +goog.Uri.prototype.hasPath = function() { + return !!this.path_; +}; + + +/** + * @return {boolean} Whether the query string has been set. + */ +goog.Uri.prototype.hasQuery = function() { + return this.queryData_.toString() !== ''; +}; + + +/** + * Sets the query data. + * @param {goog.Uri.QueryData|string|undefined} queryData QueryData object. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * Applies only if queryData is a string. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setQueryData = function(queryData, opt_decode) { + this.enforceReadOnly(); + + if (queryData instanceof goog.Uri.QueryData) { + this.queryData_ = queryData; + this.queryData_.setIgnoreCase(this.ignoreCase_); + } else { + if (!opt_decode) { + // QueryData accepts encoded query string, so encode it if + // opt_decode flag is not true. + queryData = goog.Uri.encodeSpecialChars_(queryData, + goog.Uri.reDisallowedInQuery_); + } + this.queryData_ = new goog.Uri.QueryData(queryData, null, this.ignoreCase_); + } + + return this; +}; + + +/** + * Sets the URI query. + * @param {string} newQuery New query value. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setQuery = function(newQuery, opt_decode) { + return this.setQueryData(newQuery, opt_decode); +}; + + +/** + * @return {string} The encoded URI query, not including the ?. + */ +goog.Uri.prototype.getEncodedQuery = function() { + return this.queryData_.toString(); +}; + + +/** + * @return {string} The decoded URI query, not including the ?. + */ +goog.Uri.prototype.getDecodedQuery = function() { + return this.queryData_.toDecodedString(); +}; + + +/** + * Returns the query data. + * @return {!goog.Uri.QueryData} QueryData object. + */ +goog.Uri.prototype.getQueryData = function() { + return this.queryData_; +}; + + +/** + * @return {string} The encoded URI query, not including the ?. + * + * Warning: This method, unlike other getter methods, returns encoded + * value, instead of decoded one. + */ +goog.Uri.prototype.getQuery = function() { + return this.getEncodedQuery(); +}; + + +/** + * Sets the value of the named query parameters, clearing previous values for + * that key. + * + * @param {string} key The parameter to set. + * @param {*} value The new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setParameterValue = function(key, value) { + this.enforceReadOnly(); + this.queryData_.set(key, value); + return this; +}; + + +/** + * Sets the values of the named query parameters, clearing previous values for + * that key. Not new values will currently be moved to the end of the query + * string. + * + * So, <code>goog.Uri.parse('foo?a=b&c=d&e=f').setParameterValues('c', ['new']) + * </code> yields <tt>foo?a=b&e=f&c=new</tt>.</p> + * + * @param {string} key The parameter to set. + * @param {*} values The new values. If values is a single + * string then it will be treated as the sole value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setParameterValues = function(key, values) { + this.enforceReadOnly(); + + if (!goog.isArray(values)) { + values = [String(values)]; + } + + this.queryData_.setValues(key, values); + + return this; +}; + + +/** + * Returns the value<b>s</b> for a given cgi parameter as a list of decoded + * query parameter values. + * @param {string} name The parameter to get values for. + * @return {!Array<?>} The values for a given cgi parameter as a list of + * decoded query parameter values. + */ +goog.Uri.prototype.getParameterValues = function(name) { + return this.queryData_.getValues(name); +}; + + +/** + * Returns the first value for a given cgi parameter or undefined if the given + * parameter name does not appear in the query string. + * @param {string} paramName Unescaped parameter name. + * @return {string|undefined} The first value for a given cgi parameter or + * undefined if the given parameter name does not appear in the query + * string. + */ +goog.Uri.prototype.getParameterValue = function(paramName) { + // NOTE(nicksantos): This type-cast is a lie when + // preserveParameterTypesCompatibilityFlag is set to true. + // But this should only be set to true in tests. + return /** @type {string|undefined} */ (this.queryData_.get(paramName)); +}; + + +/** + * @return {string} The URI fragment, not including the #. + */ +goog.Uri.prototype.getFragment = function() { + return this.fragment_; +}; + + +/** + * Sets the URI fragment. + * @throws URIError If opt_decode is true and newFragment is malformed (that is, + * if decodeURIComponent fails). + * @param {string} newFragment New fragment value. + * @param {boolean=} opt_decode Optional param for whether to decode new value. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.setFragment = function(newFragment, opt_decode) { + this.enforceReadOnly(); + this.fragment_ = opt_decode ? goog.Uri.decodeOrEmpty_(newFragment) : + newFragment; + return this; +}; + + +/** + * @return {boolean} Whether the URI has a fragment set. + */ +goog.Uri.prototype.hasFragment = function() { + return !!this.fragment_; +}; + + +/** + * Returns true if this has the same domain as that of uri2. + * @param {!goog.Uri} uri2 The URI object to compare to. + * @return {boolean} true if same domain; false otherwise. + */ +goog.Uri.prototype.hasSameDomainAs = function(uri2) { + return ((!this.hasDomain() && !uri2.hasDomain()) || + this.getDomain() == uri2.getDomain()) && + ((!this.hasPort() && !uri2.hasPort()) || + this.getPort() == uri2.getPort()); +}; + + +/** + * Adds a random parameter to the Uri. + * @return {!goog.Uri} Reference to this Uri object. + */ +goog.Uri.prototype.makeUnique = function() { + this.enforceReadOnly(); + this.setParameterValue(goog.Uri.RANDOM_PARAM, goog.string.getRandomString()); + + return this; +}; + + +/** + * Removes the named query parameter. + * + * @param {string} key The parameter to remove. + * @return {!goog.Uri} Reference to this URI object. + */ +goog.Uri.prototype.removeParameter = function(key) { + this.enforceReadOnly(); + this.queryData_.remove(key); + return this; +}; + + +/** + * Sets whether Uri is read only. If this goog.Uri is read-only, + * enforceReadOnly_ will be called at the start of any function that may modify + * this Uri. + * @param {boolean} isReadOnly whether this goog.Uri should be read only. + * @return {!goog.Uri} Reference to this Uri object. + */ +goog.Uri.prototype.setReadOnly = function(isReadOnly) { + this.isReadOnly_ = isReadOnly; + return this; +}; + + +/** + * @return {boolean} Whether the URI is read only. + */ +goog.Uri.prototype.isReadOnly = function() { + return this.isReadOnly_; +}; + + +/** + * Checks if this Uri has been marked as read only, and if so, throws an error. + * This should be called whenever any modifying function is called. + */ +goog.Uri.prototype.enforceReadOnly = function() { + if (this.isReadOnly_) { + throw Error('Tried to modify a read-only Uri'); + } +}; + + +/** + * Sets whether to ignore case. + * NOTE: If there are already key/value pairs in the QueryData, and + * ignoreCase_ is set to false, the keys will all be lower-cased. + * @param {boolean} ignoreCase whether this goog.Uri should ignore case. + * @return {!goog.Uri} Reference to this Uri object. + */ +goog.Uri.prototype.setIgnoreCase = function(ignoreCase) { + this.ignoreCase_ = ignoreCase; + if (this.queryData_) { + this.queryData_.setIgnoreCase(ignoreCase); + } + return this; +}; + + +/** + * @return {boolean} Whether to ignore case. + */ +goog.Uri.prototype.getIgnoreCase = function() { + return this.ignoreCase_; +}; + + +//============================================================================== +// Static members +//============================================================================== + + +/** + * Creates a uri from the string form. Basically an alias of new goog.Uri(). + * If a Uri object is passed to parse then it will return a clone of the object. + * + * @throws URIError If parsing the URI is malformed. The passed URI components + * should all be parseable by decodeURIComponent. + * @param {*} uri Raw URI string or instance of Uri + * object. + * @param {boolean=} opt_ignoreCase Whether to ignore the case of parameter + * names in #getParameterValue. + * @return {!goog.Uri} The new URI object. + */ +goog.Uri.parse = function(uri, opt_ignoreCase) { + return uri instanceof goog.Uri ? + uri.clone() : new goog.Uri(uri, opt_ignoreCase); +}; + + +/** + * Creates a new goog.Uri object from unencoded parts. + * + * @param {?string=} opt_scheme Scheme/protocol or full URI to parse. + * @param {?string=} opt_userInfo username:password. + * @param {?string=} opt_domain www.google.com. + * @param {?number=} opt_port 9830. + * @param {?string=} opt_path /some/path/to/a/file.html. + * @param {string|goog.Uri.QueryData=} opt_query a=1&b=2. + * @param {?string=} opt_fragment The fragment without the #. + * @param {boolean=} opt_ignoreCase Whether to ignore parameter name case in + * #getParameterValue. + * + * @return {!goog.Uri} The new URI object. + */ +goog.Uri.create = function(opt_scheme, opt_userInfo, opt_domain, opt_port, + opt_path, opt_query, opt_fragment, opt_ignoreCase) { + + var uri = new goog.Uri(null, opt_ignoreCase); + + // Only set the parts if they are defined and not empty strings. + opt_scheme && uri.setScheme(opt_scheme); + opt_userInfo && uri.setUserInfo(opt_userInfo); + opt_domain && uri.setDomain(opt_domain); + opt_port && uri.setPort(opt_port); + opt_path && uri.setPath(opt_path); + opt_query && uri.setQueryData(opt_query); + opt_fragment && uri.setFragment(opt_fragment); + + return uri; +}; + + +/** + * Resolves a relative Uri against a base Uri, accepting both strings and + * Uri objects. + * + * @param {*} base Base Uri. + * @param {*} rel Relative Uri. + * @return {!goog.Uri} Resolved uri. + */ +goog.Uri.resolve = function(base, rel) { + if (!(base instanceof goog.Uri)) { + base = goog.Uri.parse(base); + } + + if (!(rel instanceof goog.Uri)) { + rel = goog.Uri.parse(rel); + } + + return base.resolve(rel); +}; + + +/** + * Removes dot segments in given path component, as described in + * RFC 3986, section 5.2.4. + * + * @param {string} path A non-empty path component. + * @return {string} Path component with removed dot segments. + */ +goog.Uri.removeDotSegments = function(path) { + if (path == '..' || path == '.') { + return ''; + + } else if (!goog.string.contains(path, './') && + !goog.string.contains(path, '/.')) { + // This optimization detects uris which do not contain dot-segments, + // and as a consequence do not require any processing. + return path; + + } else { + var leadingSlash = goog.string.startsWith(path, '/'); + var segments = path.split('/'); + var out = []; + + for (var pos = 0; pos < segments.length; ) { + var segment = segments[pos++]; + + if (segment == '.') { + if (leadingSlash && pos == segments.length) { + out.push(''); + } + } else if (segment == '..') { + if (out.length > 1 || out.length == 1 && out[0] != '') { + out.pop(); + } + if (leadingSlash && pos == segments.length) { + out.push(''); + } + } else { + out.push(segment); + leadingSlash = true; + } + } + + return out.join('/'); + } +}; + + +/** + * Decodes a value or returns the empty string if it isn't defined or empty. + * @throws URIError If decodeURIComponent fails to decode val. + * @param {string|undefined} val Value to decode. + * @param {boolean=} opt_preserveReserved If true, restricted characters will + * not be decoded. + * @return {string} Decoded value. + * @private + */ +goog.Uri.decodeOrEmpty_ = function(val, opt_preserveReserved) { + // Don't use UrlDecode() here because val is not a query parameter. + if (!val) { + return ''; + } + + // decodeURI has the same output for '%2f' and '%252f'. We double encode %25 + // so that we can distinguish between the 2 inputs. This is later undone by + // removeDoubleEncoding_. + return opt_preserveReserved ? + decodeURI(val.replace(/%25/g, '%2525')) : decodeURIComponent(val); +}; + + +/** + * If unescapedPart is non null, then escapes any characters in it that aren't + * valid characters in a url and also escapes any special characters that + * appear in extra. + * + * @param {*} unescapedPart The string to encode. + * @param {RegExp} extra A character set of characters in [\01-\177]. + * @param {boolean=} opt_removeDoubleEncoding If true, remove double percent + * encoding. + * @return {?string} null iff unescapedPart == null. + * @private + */ +goog.Uri.encodeSpecialChars_ = function(unescapedPart, extra, + opt_removeDoubleEncoding) { + if (goog.isString(unescapedPart)) { + var encoded = encodeURI(unescapedPart). + replace(extra, goog.Uri.encodeChar_); + if (opt_removeDoubleEncoding) { + // encodeURI double-escapes %XX sequences used to represent restricted + // characters in some URI components, remove the double escaping here. + encoded = goog.Uri.removeDoubleEncoding_(encoded); + } + return encoded; + } + return null; +}; + + +/** + * Converts a character in [\01-\177] to its unicode character equivalent. + * @param {string} ch One character string. + * @return {string} Encoded string. + * @private + */ +goog.Uri.encodeChar_ = function(ch) { + var n = ch.charCodeAt(0); + return '%' + ((n >> 4) & 0xf).toString(16) + (n & 0xf).toString(16); +}; + + +/** + * Removes double percent-encoding from a string. + * @param {string} doubleEncodedString String + * @return {string} String with double encoding removed. + * @private + */ +goog.Uri.removeDoubleEncoding_ = function(doubleEncodedString) { + return doubleEncodedString.replace(/%25([0-9a-fA-F]{2})/g, '%$1'); +}; + + +/** + * Regular expression for characters that are disallowed in the scheme or + * userInfo part of the URI. + * @type {RegExp} + * @private + */ +goog.Uri.reDisallowedInSchemeOrUserInfo_ = /[#\/\?@]/g; + + +/** + * Regular expression for characters that are disallowed in a relative path. + * Colon is included due to RFC 3986 3.3. + * @type {RegExp} + * @private + */ +goog.Uri.reDisallowedInRelativePath_ = /[\#\?:]/g; + + +/** + * Regular expression for characters that are disallowed in an absolute path. + * @type {RegExp} + * @private + */ +goog.Uri.reDisallowedInAbsolutePath_ = /[\#\?]/g; + + +/** + * Regular expression for characters that are disallowed in the query. + * @type {RegExp} + * @private + */ +goog.Uri.reDisallowedInQuery_ = /[\#\?@]/g; + + +/** + * Regular expression for characters that are disallowed in the fragment. + * @type {RegExp} + * @private + */ +goog.Uri.reDisallowedInFragment_ = /#/g; + + +/** + * Checks whether two URIs have the same domain. + * @param {string} uri1String First URI string. + * @param {string} uri2String Second URI string. + * @return {boolean} true if the two URIs have the same domain; false otherwise. + */ +goog.Uri.haveSameDomain = function(uri1String, uri2String) { + // Differs from goog.uri.utils.haveSameDomain, since this ignores scheme. + // TODO(gboyer): Have this just call goog.uri.util.haveSameDomain. + var pieces1 = goog.uri.utils.split(uri1String); + var pieces2 = goog.uri.utils.split(uri2String); + return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] == + pieces2[goog.uri.utils.ComponentIndex.DOMAIN] && + pieces1[goog.uri.utils.ComponentIndex.PORT] == + pieces2[goog.uri.utils.ComponentIndex.PORT]; +}; + + + +/** + * Class used to represent URI query parameters. It is essentially a hash of + * name-value pairs, though a name can be present more than once. + * + * Has the same interface as the collections in goog.structs. + * + * @param {?string=} opt_query Optional encoded query string to parse into + * the object. + * @param {goog.Uri=} opt_uri Optional uri object that should have its + * cache invalidated when this object updates. Deprecated -- this + * is no longer required. + * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter + * name in #get. + * @constructor + * @struct + * @final + */ +goog.Uri.QueryData = function(opt_query, opt_uri, opt_ignoreCase) { + /** + * The map containing name/value or name/array-of-values pairs. + * May be null if it requires parsing from the query string. + * + * We need to use a Map because we cannot guarantee that the key names will + * not be problematic for IE. + * + * @private {goog.structs.Map<string, !Array<*>>} + */ + this.keyMap_ = null; + + /** + * The number of params, or null if it requires computing. + * @private {?number} + */ + this.count_ = null; + + /** + * Encoded query string, or null if it requires computing from the key map. + * @private {?string} + */ + this.encodedQuery_ = opt_query || null; + + /** + * If true, ignore the case of the parameter name in #get. + * @private {boolean} + */ + this.ignoreCase_ = !!opt_ignoreCase; +}; + + +/** + * If the underlying key map is not yet initialized, it parses the + * query string and fills the map with parsed data. + * @private + */ +goog.Uri.QueryData.prototype.ensureKeyMapInitialized_ = function() { + if (!this.keyMap_) { + this.keyMap_ = new goog.structs.Map(); + this.count_ = 0; + if (this.encodedQuery_) { + var self = this; + goog.uri.utils.parseQueryData(this.encodedQuery_, function(name, value) { + self.add(goog.string.urlDecode(name), value); + }); + } + } +}; + + +/** + * Creates a new query data instance from a map of names and values. + * + * @param {!goog.structs.Map<string, ?>|!Object} map Map of string parameter + * names to parameter value. If parameter value is an array, it is + * treated as if the key maps to each individual value in the + * array. + * @param {goog.Uri=} opt_uri URI object that should have its cache + * invalidated when this object updates. + * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter + * name in #get. + * @return {!goog.Uri.QueryData} The populated query data instance. + */ +goog.Uri.QueryData.createFromMap = function(map, opt_uri, opt_ignoreCase) { + var keys = goog.structs.getKeys(map); + if (typeof keys == 'undefined') { + throw Error('Keys are undefined'); + } + + var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase); + var values = goog.structs.getValues(map); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var value = values[i]; + if (!goog.isArray(value)) { + queryData.add(key, value); + } else { + queryData.setValues(key, value); + } + } + return queryData; +}; + + +/** + * Creates a new query data instance from parallel arrays of parameter names + * and values. Allows for duplicate parameter names. Throws an error if the + * lengths of the arrays differ. + * + * @param {!Array<string>} keys Parameter names. + * @param {!Array<?>} values Parameter values. + * @param {goog.Uri=} opt_uri URI object that should have its cache + * invalidated when this object updates. + * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter + * name in #get. + * @return {!goog.Uri.QueryData} The populated query data instance. + */ +goog.Uri.QueryData.createFromKeysValues = function( + keys, values, opt_uri, opt_ignoreCase) { + if (keys.length != values.length) { + throw Error('Mismatched lengths for keys/values'); + } + var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase); + for (var i = 0; i < keys.length; i++) { + queryData.add(keys[i], values[i]); + } + return queryData; +}; + + +/** + * @return {?number} The number of parameters. + */ +goog.Uri.QueryData.prototype.getCount = function() { + this.ensureKeyMapInitialized_(); + return this.count_; +}; + + +/** + * Adds a key value pair. + * @param {string} key Name. + * @param {*} value Value. + * @return {!goog.Uri.QueryData} Instance of this object. + */ +goog.Uri.QueryData.prototype.add = function(key, value) { + this.ensureKeyMapInitialized_(); + this.invalidateCache_(); + + key = this.getKeyName_(key); + var values = this.keyMap_.get(key); + if (!values) { + this.keyMap_.set(key, (values = [])); + } + values.push(value); + this.count_++; + return this; +}; + + +/** + * Removes all the params with the given key. + * @param {string} key Name. + * @return {boolean} Whether any parameter was removed. + */ +goog.Uri.QueryData.prototype.remove = function(key) { + this.ensureKeyMapInitialized_(); + + key = this.getKeyName_(key); + if (this.keyMap_.containsKey(key)) { + this.invalidateCache_(); + + // Decrement parameter count. + this.count_ -= this.keyMap_.get(key).length; + return this.keyMap_.remove(key); + } + return false; +}; + + +/** + * Clears the parameters. + */ +goog.Uri.QueryData.prototype.clear = function() { + this.invalidateCache_(); + this.keyMap_ = null; + this.count_ = 0; +}; + + +/** + * @return {boolean} Whether we have any parameters. + */ +goog.Uri.QueryData.prototype.isEmpty = function() { + this.ensureKeyMapInitialized_(); + return this.count_ == 0; +}; + + +/** + * Whether there is a parameter with the given name + * @param {string} key The parameter name to check for. + * @return {boolean} Whether there is a parameter with the given name. + */ +goog.Uri.QueryData.prototype.containsKey = function(key) { + this.ensureKeyMapInitialized_(); + key = this.getKeyName_(key); + return this.keyMap_.containsKey(key); +}; + + +/** + * Whether there is a parameter with the given value. + * @param {*} value The value to check for. + * @return {boolean} Whether there is a parameter with the given value. + */ +goog.Uri.QueryData.prototype.containsValue = function(value) { + // NOTE(arv): This solution goes through all the params even if it was the + // first param. We can get around this by not reusing code or by switching to + // iterators. + var vals = this.getValues(); + return goog.array.contains(vals, value); +}; + + +/** + * Returns all the keys of the parameters. If a key is used multiple times + * it will be included multiple times in the returned array + * @return {!Array<string>} All the keys of the parameters. + */ +goog.Uri.QueryData.prototype.getKeys = function() { + this.ensureKeyMapInitialized_(); + // We need to get the values to know how many keys to add. + var vals = /** @type {!Array<*>} */ (this.keyMap_.getValues()); + var keys = this.keyMap_.getKeys(); + var rv = []; + for (var i = 0; i < keys.length; i++) { + var val = vals[i]; + for (var j = 0; j < val.length; j++) { + rv.push(keys[i]); + } + } + return rv; +}; + + +/** + * Returns all the values of the parameters with the given name. If the query + * data has no such key this will return an empty array. If no key is given + * all values wil be returned. + * @param {string=} opt_key The name of the parameter to get the values for. + * @return {!Array<?>} All the values of the parameters with the given name. + */ +goog.Uri.QueryData.prototype.getValues = function(opt_key) { + this.ensureKeyMapInitialized_(); + var rv = []; + if (goog.isString(opt_key)) { + if (this.containsKey(opt_key)) { + rv = goog.array.concat(rv, this.keyMap_.get(this.getKeyName_(opt_key))); + } + } else { + // Return all values. + var values = this.keyMap_.getValues(); + for (var i = 0; i < values.length; i++) { + rv = goog.array.concat(rv, values[i]); + } + } + return rv; +}; + + +/** + * Sets a key value pair and removes all other keys with the same value. + * + * @param {string} key Name. + * @param {*} value Value. + * @return {!goog.Uri.QueryData} Instance of this object. + */ +goog.Uri.QueryData.prototype.set = function(key, value) { + this.ensureKeyMapInitialized_(); + this.invalidateCache_(); + + // TODO(chrishenry): This could be better written as + // this.remove(key), this.add(key, value), but that would reorder + // the key (since the key is first removed and then added at the + // end) and we would have to fix unit tests that depend on key + // ordering. + key = this.getKeyName_(key); + if (this.containsKey(key)) { + this.count_ -= this.keyMap_.get(key).length; + } + this.keyMap_.set(key, [value]); + this.count_++; + return this; +}; + + +/** + * Returns the first value associated with the key. If the query data has no + * such key this will return undefined or the optional default. + * @param {string} key The name of the parameter to get the value for. + * @param {*=} opt_default The default value to return if the query data + * has no such key. + * @return {*} The first string value associated with the key, or opt_default + * if there's no value. + */ +goog.Uri.QueryData.prototype.get = function(key, opt_default) { + var values = key ? this.getValues(key) : []; + if (goog.Uri.preserveParameterTypesCompatibilityFlag) { + return values.length > 0 ? values[0] : opt_default; + } else { + return values.length > 0 ? String(values[0]) : opt_default; + } +}; + + +/** + * Sets the values for a key. If the key already exists, this will + * override all of the existing values that correspond to the key. + * @param {string} key The key to set values for. + * @param {!Array<?>} values The values to set. + */ +goog.Uri.QueryData.prototype.setValues = function(key, values) { + this.remove(key); + + if (values.length > 0) { + this.invalidateCache_(); + this.keyMap_.set(this.getKeyName_(key), goog.array.clone(values)); + this.count_ += values.length; + } +}; + + +/** + * @return {string} Encoded query string. + * @override + */ +goog.Uri.QueryData.prototype.toString = function() { + if (this.encodedQuery_) { + return this.encodedQuery_; + } + + if (!this.keyMap_) { + return ''; + } + + var sb = []; + + // In the past, we use this.getKeys() and this.getVals(), but that + // generates a lot of allocations as compared to simply iterating + // over the keys. + var keys = this.keyMap_.getKeys(); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var encodedKey = goog.string.urlEncode(key); + var val = this.getValues(key); + for (var j = 0; j < val.length; j++) { + var param = encodedKey; + // Ensure that null and undefined are encoded into the url as + // literal strings. + if (val[j] !== '') { + param += '=' + goog.string.urlEncode(val[j]); + } + sb.push(param); + } + } + + return this.encodedQuery_ = sb.join('&'); +}; + + +/** + * @throws URIError If URI is malformed (that is, if decodeURIComponent fails on + * any of the URI components). + * @return {string} Decoded query string. + */ +goog.Uri.QueryData.prototype.toDecodedString = function() { + return goog.Uri.decodeOrEmpty_(this.toString()); +}; + + +/** + * Invalidate the cache. + * @private + */ +goog.Uri.QueryData.prototype.invalidateCache_ = function() { + this.encodedQuery_ = null; +}; + + +/** + * Removes all keys that are not in the provided list. (Modifies this object.) + * @param {Array<string>} keys The desired keys. + * @return {!goog.Uri.QueryData} a reference to this object. + */ +goog.Uri.QueryData.prototype.filterKeys = function(keys) { + this.ensureKeyMapInitialized_(); + this.keyMap_.forEach( + function(value, key) { + if (!goog.array.contains(keys, key)) { + this.remove(key); + } + }, this); + return this; +}; + + +/** + * Clone the query data instance. + * @return {!goog.Uri.QueryData} New instance of the QueryData object. + */ +goog.Uri.QueryData.prototype.clone = function() { + var rv = new goog.Uri.QueryData(); + rv.encodedQuery_ = this.encodedQuery_; + if (this.keyMap_) { + rv.keyMap_ = this.keyMap_.clone(); + rv.count_ = this.count_; + } + return rv; +}; + + +/** + * Helper function to get the key name from a JavaScript object. Converts + * the object to a string, and to lower case if necessary. + * @private + * @param {*} arg The object to get a key name from. + * @return {string} valid key name which can be looked up in #keyMap_. + */ +goog.Uri.QueryData.prototype.getKeyName_ = function(arg) { + var keyName = String(arg); + if (this.ignoreCase_) { + keyName = keyName.toLowerCase(); + } + return keyName; +}; + + +/** + * Ignore case in parameter names. + * NOTE: If there are already key/value pairs in the QueryData, and + * ignoreCase_ is set to false, the keys will all be lower-cased. + * @param {boolean} ignoreCase whether this goog.Uri should ignore case. + */ +goog.Uri.QueryData.prototype.setIgnoreCase = function(ignoreCase) { + var resetKeys = ignoreCase && !this.ignoreCase_; + if (resetKeys) { + this.ensureKeyMapInitialized_(); + this.invalidateCache_(); + this.keyMap_.forEach( + function(value, key) { + var lowerCase = key.toLowerCase(); + if (key != lowerCase) { + this.remove(key); + this.setValues(lowerCase, value); + } + }, this); + } + this.ignoreCase_ = ignoreCase; +}; + + +/** + * Extends a query data object with another query data or map like object. This + * operates 'in-place', it does not create a new QueryData object. + * + * @param {...(goog.Uri.QueryData|goog.structs.Map<?, ?>|Object)} var_args + * The object from which key value pairs will be copied. + */ +goog.Uri.QueryData.prototype.extend = function(var_args) { + for (var i = 0; i < arguments.length; i++) { + var data = arguments[i]; + goog.structs.forEach(data, + /** @this {goog.Uri.QueryData} */ + function(value, key) { + this.add(key, value); + }, this); + } +}; + +goog.provide('ol.style.Text'); + + +goog.require('ol.style.Fill'); + + + +/** + * @classdesc + * Set text style for vector features. + * + * @constructor + * @param {olx.style.TextOptions=} opt_options Options. + * @api + */ +ol.style.Text = function(opt_options) { + + var options = opt_options || {}; + + /** + * @private + * @type {string|undefined} + */ + this.font_ = options.font; + + /** + * @private + * @type {number|undefined} + */ + this.rotation_ = options.rotation; + + /** + * @private + * @type {number|undefined} + */ + this.scale_ = options.scale; + + /** + * @private + * @type {string|undefined} + */ + this.text_ = options.text; + + /** + * @private + * @type {string|undefined} + */ + this.textAlign_ = options.textAlign; + + /** + * @private + * @type {string|undefined} + */ + this.textBaseline_ = options.textBaseline; + + /** + * @private + * @type {ol.style.Fill} + */ + this.fill_ = options.fill !== undefined ? options.fill : + new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_}); + + /** + * @private + * @type {ol.style.Stroke} + */ + this.stroke_ = options.stroke !== undefined ? options.stroke : null; + + /** + * @private + * @type {number} + */ + this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0; + + /** + * @private + * @type {number} + */ + this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0; +}; + + +/** + * The default fill color to use if no fill was set at construction time; a + * blackish `#333`. + * + * @const {string} + * @private + */ +ol.style.Text.DEFAULT_FILL_COLOR_ = '#333'; + + +/** + * Get the font name. + * @return {string|undefined} Font. + * @api + */ +ol.style.Text.prototype.getFont = function() { + return this.font_; +}; + + +/** + * Get the x-offset for the text. + * @return {number} Horizontal text offset. + * @api + */ +ol.style.Text.prototype.getOffsetX = function() { + return this.offsetX_; +}; + + +/** + * Get the y-offset for the text. + * @return {number} Vertical text offset. + * @api + */ +ol.style.Text.prototype.getOffsetY = function() { + return this.offsetY_; +}; + + +/** + * Get the fill style for the text. + * @return {ol.style.Fill} Fill style. + * @api + */ +ol.style.Text.prototype.getFill = function() { + return this.fill_; +}; + + +/** + * Get the text rotation. + * @return {number|undefined} Rotation. + * @api + */ +ol.style.Text.prototype.getRotation = function() { + return this.rotation_; +}; + + +/** + * Get the text scale. + * @return {number|undefined} Scale. + * @api + */ +ol.style.Text.prototype.getScale = function() { + return this.scale_; +}; + + +/** + * Get the stroke style for the text. + * @return {ol.style.Stroke} Stroke style. + * @api + */ +ol.style.Text.prototype.getStroke = function() { + return this.stroke_; +}; + + +/** + * Get the text to be rendered. + * @return {string|undefined} Text. + * @api + */ +ol.style.Text.prototype.getText = function() { + return this.text_; +}; + + +/** + * Get the text alignment. + * @return {string|undefined} Text align. + * @api + */ +ol.style.Text.prototype.getTextAlign = function() { + return this.textAlign_; +}; + + +/** + * Get the text baseline. + * @return {string|undefined} Text baseline. + * @api + */ +ol.style.Text.prototype.getTextBaseline = function() { + return this.textBaseline_; +}; + + +/** + * Set the font. + * + * @param {string|undefined} font Font. + * @api + */ +ol.style.Text.prototype.setFont = function(font) { + this.font_ = font; +}; + + +/** + * Set the x offset. + * + * @param {number} offsetX Horizontal text offset. + * @api + */ +ol.style.Text.prototype.setOffsetX = function(offsetX) { + this.offsetX_ = offsetX; +}; + + +/** + * Set the y offset. + * + * @param {number} offsetY Vertical text offset. + * @api + */ +ol.style.Text.prototype.setOffsetY = function(offsetY) { + this.offsetY_ = offsetY; +}; + + +/** + * Set the fill. + * + * @param {ol.style.Fill} fill Fill style. + * @api + */ +ol.style.Text.prototype.setFill = function(fill) { + this.fill_ = fill; +}; + + +/** + * Set the rotation. + * + * @param {number|undefined} rotation Rotation. + * @api + */ +ol.style.Text.prototype.setRotation = function(rotation) { + this.rotation_ = rotation; +}; + + +/** + * Set the scale. + * + * @param {number|undefined} scale Scale. + * @api + */ +ol.style.Text.prototype.setScale = function(scale) { + this.scale_ = scale; +}; + + +/** + * Set the stroke. + * + * @param {ol.style.Stroke} stroke Stroke style. + * @api + */ +ol.style.Text.prototype.setStroke = function(stroke) { + this.stroke_ = stroke; +}; + + +/** + * Set the text. + * + * @param {string|undefined} text Text. + * @api + */ +ol.style.Text.prototype.setText = function(text) { + this.text_ = text; +}; + + +/** + * Set the text alignment. + * + * @param {string|undefined} textAlign Text align. + * @api + */ +ol.style.Text.prototype.setTextAlign = function(textAlign) { + this.textAlign_ = textAlign; +}; + + +/** + * Set the text baseline. + * + * @param {string|undefined} textBaseline Text baseline. + * @api + */ +ol.style.Text.prototype.setTextBaseline = function(textBaseline) { + this.textBaseline_ = textBaseline; +}; + +// FIXME http://earth.google.com/kml/1.0 namespace? +// FIXME why does node.getAttribute return an unknown type? +// FIXME text +// FIXME serialize arbitrary feature properties +// FIXME don't parse style if extractStyles is false + +goog.provide('ol.format.KML'); + +goog.require('goog.Uri'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Feature'); +goog.require('ol.FeatureStyleFunction'); +goog.require('ol.array'); +goog.require('ol.color'); +goog.require('ol.format.Feature'); +goog.require('ol.format.XMLFeature'); +goog.require('ol.format.XSD'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryCollection'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Icon'); +goog.require('ol.style.IconAnchorUnits'); +goog.require('ol.style.IconOrigin'); +goog.require('ol.style.Image'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); +goog.require('ol.style.Text'); +goog.require('ol.xml'); + + +/** + * @typedef {{x: number, xunits: (ol.style.IconAnchorUnits|undefined), + * y: number, yunits: (ol.style.IconAnchorUnits|undefined)}} + */ +ol.format.KMLVec2_; + + +/** + * @typedef {{flatCoordinates: Array.<number>, + * whens: Array.<number>}} + */ +ol.format.KMLGxTrackObject_; + + + +/** + * @classdesc + * Feature format for reading and writing data in the KML format. + * + * @constructor + * @extends {ol.format.XMLFeature} + * @param {olx.format.KMLOptions=} opt_options Options. + * @api stable + */ +ol.format.KML = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this); + + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + + /** + * @private + * @type {Array.<ol.style.Style>} + */ + this.defaultStyle_ = options.defaultStyle ? + options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_; + + /** + * @private + * @type {boolean} + */ + this.extractStyles_ = options.extractStyles !== undefined ? + options.extractStyles : true; + + /** + * @private + * @type {boolean} + */ + this.writeStyles_ = options.writeStyles !== undefined ? + options.writeStyles : true; + + /** + * @private + * @type {Object.<string, (Array.<ol.style.Style>|string)>} + */ + this.sharedStyles_ = {}; + + /** + * @private + * @type {boolean} + */ + this.showPointNames_ = options.showPointNames !== undefined ? + options.showPointNames : true; + +}; +goog.inherits(ol.format.KML, ol.format.XMLFeature); + + +/** + * @const + * @type {Array.<string>} + * @private + */ +ol.format.KML.EXTENSIONS_ = ['.kml']; + + +/** + * @const + * @type {Array.<string>} + * @private + */ +ol.format.KML.GX_NAMESPACE_URIS_ = [ + 'http://www.google.com/kml/ext/2.2' +]; + + +/** + * @const + * @type {Array.<string>} + * @private + */ +ol.format.KML.NAMESPACE_URIS_ = [ + null, + 'http://earth.google.com/kml/2.0', + 'http://earth.google.com/kml/2.1', + 'http://earth.google.com/kml/2.2', + 'http://www.opengis.net/kml/2.2' +]; + + +/** + * @const + * @type {string} + * @private + */ +ol.format.KML.SCHEMA_LOCATION_ = 'http://www.opengis.net/kml/2.2 ' + + 'https://developers.google.com/kml/schema/kml22gx.xsd'; + + +/** + * @const + * @type {ol.Color} + * @private + */ +ol.format.KML.DEFAULT_COLOR_ = [255, 255, 255, 1]; + + +/** + * @const + * @type {ol.style.Fill} + * @private + */ +ol.format.KML.DEFAULT_FILL_STYLE_ = new ol.style.Fill({ + color: ol.format.KML.DEFAULT_COLOR_ +}); + + +/** + * @const + * @type {ol.Size} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_ = [20, 2]; // FIXME maybe [8, 32] ? + + +/** + * @const + * @type {ol.style.IconAnchorUnits} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ = + ol.style.IconAnchorUnits.PIXELS; + + +/** + * @const + * @type {ol.style.IconAnchorUnits} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ = + ol.style.IconAnchorUnits.PIXELS; + + +/** + * @const + * @type {ol.Size} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_ = [64, 64]; + + +/** + * @const + * @type {string} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ = + 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png'; + + +/** + * @const + * @type {number} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_ = 0.5; + + +/** + * @const + * @type {ol.style.Image} + * @private + */ +ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({ + anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_, + anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, + anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_, + anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_, + crossOrigin: 'anonymous', + rotation: 0, + scale: ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_, + size: ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_, + src: ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ +}); + + +/** + * @const + * @type {ol.style.Stroke} + * @private + */ +ol.format.KML.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({ + color: ol.format.KML.DEFAULT_COLOR_, + width: 1 +}); + + +/** + * @const + * @type {ol.style.Stroke} + * @private + */ +ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_ = new ol.style.Stroke({ + color: [51, 51, 51, 1], + width: 2 +}); + + +/** + * @const + * @type {ol.style.Text} + * @private + */ +ol.format.KML.DEFAULT_TEXT_STYLE_ = new ol.style.Text({ + font: 'bold 16px Helvetica', + fill: ol.format.KML.DEFAULT_FILL_STYLE_, + stroke: ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_, + scale: 0.8 +}); + + +/** + * @const + * @type {ol.style.Style} + * @private + */ +ol.format.KML.DEFAULT_STYLE_ = new ol.style.Style({ + fill: ol.format.KML.DEFAULT_FILL_STYLE_, + image: ol.format.KML.DEFAULT_IMAGE_STYLE_, + text: ol.format.KML.DEFAULT_TEXT_STYLE_, + stroke: ol.format.KML.DEFAULT_STROKE_STYLE_, + zIndex: 0 +}); + + +/** + * @const + * @type {Array.<ol.style.Style>} + * @private + */ +ol.format.KML.DEFAULT_STYLE_ARRAY_ = [ol.format.KML.DEFAULT_STYLE_]; + + +/** + * @const + * @type {Object.<string, ol.style.IconAnchorUnits>} + * @private + */ +ol.format.KML.ICON_ANCHOR_UNITS_MAP_ = { + 'fraction': ol.style.IconAnchorUnits.FRACTION, + 'pixels': ol.style.IconAnchorUnits.PIXELS +}; + + +/** + * @param {ol.style.Style|undefined} foundStyle Style. + * @param {string} name Name. + * @return {ol.style.Style} style Style. + * @private + */ +ol.format.KML.createNameStyleFunction_ = function(foundStyle, name) { + /** @type {?ol.style.Text} */ + var textStyle = null; + var textOffset = [0, 0]; + var textAlign = 'start'; + if (foundStyle.getImage()) { + var imageSize = foundStyle.getImage().getImageSize(); + if (imageSize && imageSize.length == 2) { + // Offset the label to be centered to the right of the icon, if there is + // one. + textOffset[0] = foundStyle.getImage().getScale() * imageSize[0] / 2; + textOffset[1] = -foundStyle.getImage().getScale() * imageSize[1] / 2; + textAlign = 'left'; + } + } + if (!goog.object.isEmpty(foundStyle.getText())) { + textStyle = /** @type {ol.style.Text} */ + (goog.object.clone(foundStyle.getText())); + textStyle.setText(name); + textStyle.setTextAlign(textAlign); + textStyle.setOffsetX(textOffset[0]); + textStyle.setOffsetY(textOffset[1]); + } else { + textStyle = new ol.style.Text({ + text: name, + offsetX: textOffset[0], + offsetY: textOffset[1], + textAlign: textAlign + }); + } + var nameStyle = new ol.style.Style({ + text: textStyle + }); + return nameStyle; +}; + + +/** + * @param {Array.<ol.style.Style>|undefined} style Style. + * @param {string} styleUrl Style URL. + * @param {Array.<ol.style.Style>} defaultStyle Default style. + * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles Shared + * styles. + * @param {boolean|undefined} showPointNames true to show names for point + * placemarks. + * @return {ol.FeatureStyleFunction} Feature style function. + * @private + */ +ol.format.KML.createFeatureStyleFunction_ = function(style, styleUrl, + defaultStyle, sharedStyles, showPointNames) { + + return ( + /** + * @param {number} resolution Resolution. + * @return {Array.<ol.style.Style>} Style. + * @this {ol.Feature} + */ + function(resolution) { + var drawName = showPointNames; + /** @type {ol.style.Style|undefined} */ + var nameStyle; + /** @type {string} */ + var name = ''; + if (drawName) { + if (this.getGeometry()) { + drawName = (this.getGeometry().getType() === + ol.geom.GeometryType.POINT); + } + } + + if (drawName) { + name = /** @type {string} */ (this.getProperties()['name']); + drawName = drawName && name; + } + + if (style) { + if (drawName) { + nameStyle = ol.format.KML.createNameStyleFunction_(style[0], + name); + return style.concat(nameStyle); + } + return style; + } + if (styleUrl) { + var foundStyle = ol.format.KML.findStyle_(styleUrl, defaultStyle, + sharedStyles); + if (drawName) { + nameStyle = ol.format.KML.createNameStyleFunction_(foundStyle[0], + name); + return foundStyle.concat(nameStyle); + } + return foundStyle; + } + if (drawName) { + nameStyle = ol.format.KML.createNameStyleFunction_(defaultStyle[0], + name); + return defaultStyle.concat(nameStyle); + } + return defaultStyle; + }); +}; + + +/** + * @param {Array.<ol.style.Style>|string|undefined} styleValue Style value. + * @param {Array.<ol.style.Style>} defaultStyle Default style. + * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles + * Shared styles. + * @return {Array.<ol.style.Style>} Style. + * @private + */ +ol.format.KML.findStyle_ = function(styleValue, defaultStyle, sharedStyles) { + if (goog.isArray(styleValue)) { + return styleValue; + } else if (goog.isString(styleValue)) { + // KML files in the wild occasionally forget the leading `#` on styleUrls + // defined in the same document. Add a leading `#` if it enables to find + // a style. + if (!(styleValue in sharedStyles) && ('#' + styleValue in sharedStyles)) { + styleValue = '#' + styleValue; + } + return ol.format.KML.findStyle_( + sharedStyles[styleValue], defaultStyle, sharedStyles); + } else { + return defaultStyle; + } +}; + + +/** + * @param {Node} node Node. + * @private + * @return {ol.Color|undefined} Color. + */ +ol.format.KML.readColor_ = function(node) { + var s = ol.xml.getAllTextContent(node, false); + // The KML specification states that colors should not include a leading `#` + // but we tolerate them. + var m = /^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(s); + if (m) { + var hexColor = m[1]; + return [ + parseInt(hexColor.substr(6, 2), 16), + parseInt(hexColor.substr(4, 2), 16), + parseInt(hexColor.substr(2, 2), 16), + parseInt(hexColor.substr(0, 2), 16) / 255 + ]; + + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @private + * @return {Array.<number>|undefined} Flat coordinates. + */ +ol.format.KML.readFlatCoordinates_ = function(node) { + var s = ol.xml.getAllTextContent(node, false); + var flatCoordinates = []; + // The KML specification states that coordinate tuples should not include + // spaces, but we tolerate them. + var re = + /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i; + var m; + while ((m = re.exec(s))) { + var x = parseFloat(m[1]); + var y = parseFloat(m[2]); + var z = m[3] ? parseFloat(m[3]) : 0; + flatCoordinates.push(x, y, z); + s = s.substr(m[0].length); + } + if (s !== '') { + return undefined; + } + return flatCoordinates; +}; + + +/** + * @param {Node} node Node. + * @private + * @return {string|undefined} Style URL. + */ +ol.format.KML.readStyleUrl_ = function(node) { + var s = ol.xml.getAllTextContent(node, false).trim(); + if (node.baseURI) { + return goog.Uri.resolve(node.baseURI, s).toString(); + } else { + return s; + } + +}; + + +/** + * @param {Node} node Node. + * @private + * @return {string} URI. + */ +ol.format.KML.readURI_ = function(node) { + var s = ol.xml.getAllTextContent(node, false); + if (node.baseURI) { + return goog.Uri.resolve(node.baseURI, s.trim()).toString(); + } else { + return s.trim(); + } +}; + + +/** + * @param {Node} node Node. + * @private + * @return {ol.format.KMLVec2_} Vec2. + */ +ol.format.KML.readVec2_ = function(node) { + var xunits = node.getAttribute('xunits'); + var yunits = node.getAttribute('yunits'); + return { + x: parseFloat(node.getAttribute('x')), + xunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[xunits], + y: parseFloat(node.getAttribute('y')), + yunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[yunits] + }; +}; + + +/** + * @param {Node} node Node. + * @private + * @return {number|undefined} Scale. + */ +ol.format.KML.readScale_ = function(node) { + var number = ol.format.XSD.readDecimal(node); + if (number !== undefined) { + return Math.sqrt(number); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<ol.style.Style>|string|undefined} StyleMap. + */ +ol.format.KML.readStyleMapValue_ = function(node, objectStack) { + return ol.xml.pushParseAndPop( + /** @type {Array.<ol.style.Style>|string|undefined} */ (undefined), + ol.format.KML.STYLE_MAP_PARSERS_, node, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.IconStyleParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be an ELEMENT'); + goog.asserts.assert(node.localName == 'IconStyle', + 'localName should be IconStyle'); + // FIXME refreshMode + // FIXME refreshInterval + // FIXME viewRefreshTime + // FIXME viewBoundScale + // FIXME viewFormat + // FIXME httpQuery + var object = ol.xml.pushParseAndPop( + {}, ol.format.KML.ICON_STYLE_PARSERS_, node, objectStack); + if (!object) { + return; + } + var styleObject = /** @type {Object} */ (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isObject(styleObject), + 'styleObject should be an Object'); + var IconObject = 'Icon' in object ? object['Icon'] : {}; + var src; + var href = /** @type {string|undefined} */ + (IconObject['href']); + if (href) { + src = href; + } else { + src = ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_; + } + var anchor, anchorXUnits, anchorYUnits; + var hotSpot = /** @type {ol.format.KMLVec2_|undefined} */ + (object['hotSpot']); + if (hotSpot) { + anchor = [hotSpot.x, hotSpot.y]; + anchorXUnits = hotSpot.xunits; + anchorYUnits = hotSpot.yunits; + } else if (src === ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) { + anchor = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_; + anchorXUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_; + anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_; + } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) { + anchor = [0.5, 0]; + anchorXUnits = ol.style.IconAnchorUnits.FRACTION; + anchorYUnits = ol.style.IconAnchorUnits.FRACTION; + } + + var offset; + var x = /** @type {number|undefined} */ + (IconObject['x']); + var y = /** @type {number|undefined} */ + (IconObject['y']); + if (x !== undefined && y !== undefined) { + offset = [x, y]; + } + + var size; + var w = /** @type {number|undefined} */ + (IconObject['w']); + var h = /** @type {number|undefined} */ + (IconObject['h']); + if (w !== undefined && h !== undefined) { + size = [w, h]; + } + + var rotation; + var heading = /** @type {number} */ + (object['heading']); + if (heading !== undefined) { + rotation = ol.math.toRadians(heading); + } + + var scale = /** @type {number|undefined} */ + (object['scale']); + if (src == ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) { + size = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_; + if (scale === undefined) { + scale = ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_; + } + } + + var imageStyle = new ol.style.Icon({ + anchor: anchor, + anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, + anchorXUnits: anchorXUnits, + anchorYUnits: anchorYUnits, + crossOrigin: 'anonymous', // FIXME should this be configurable? + offset: offset, + offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT, + rotation: rotation, + scale: scale, + size: size, + src: src + }); + styleObject['imageStyle'] = imageStyle; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.LabelStyleParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LabelStyle', + 'localName should be LabelStyle'); + // FIXME colorMode + var object = ol.xml.pushParseAndPop( + {}, ol.format.KML.LABEL_STYLE_PARSERS_, node, objectStack); + if (!object) { + return; + } + var styleObject = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(styleObject), + 'styleObject should be an Object'); + var textStyle = new ol.style.Text({ + fill: new ol.style.Fill({ + color: /** @type {ol.Color} */ + ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_) + }), + scale: /** @type {number|undefined} */ + (object['scale']) + }); + styleObject['textStyle'] = textStyle; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.LineStyleParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LineStyle', + 'localName should be LineStyle'); + // FIXME colorMode + // FIXME gx:outerColor + // FIXME gx:outerWidth + // FIXME gx:physicalWidth + // FIXME gx:labelVisibility + var object = ol.xml.pushParseAndPop( + {}, ol.format.KML.LINE_STYLE_PARSERS_, node, objectStack); + if (!object) { + return; + } + var styleObject = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(styleObject), + 'styleObject should be an Object'); + var strokeStyle = new ol.style.Stroke({ + color: /** @type {ol.Color} */ + ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_), + width: /** @type {number} */ ('width' in object ? object['width'] : 1) + }); + styleObject['strokeStyle'] = strokeStyle; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.PolyStyleParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'PolyStyle', + 'localName should be PolyStyle'); + // FIXME colorMode + var object = ol.xml.pushParseAndPop( + {}, ol.format.KML.POLY_STYLE_PARSERS_, node, objectStack); + if (!object) { + return; + } + var styleObject = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(styleObject), + 'styleObject should be an Object'); + var fillStyle = new ol.style.Fill({ + color: /** @type {ol.Color} */ + ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_) + }); + styleObject['fillStyle'] = fillStyle; + var fill = /** @type {boolean|undefined} */ (object['fill']); + if (fill !== undefined) { + styleObject['fill'] = fill; + } + var outline = + /** @type {boolean|undefined} */ (object['outline']); + if (outline !== undefined) { + styleObject['outline'] = outline; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>} LinearRing flat coordinates. + */ +ol.format.KML.readFlatLinearRing_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LinearRing', + 'localName should be LinearRing'); + return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop( + null, ol.format.KML.FLAT_LINEAR_RING_PARSERS_, node, objectStack)); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.gxCoordParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(ol.array.includes( + ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), + 'namespaceURI of the node should be known to the KML parser'); + goog.asserts.assert(node.localName == 'coord', 'localName should be coord'); + var gxTrackObject = /** @type {ol.format.KMLGxTrackObject_} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isObject(gxTrackObject), + 'gxTrackObject should be an Object'); + var flatCoordinates = gxTrackObject.flatCoordinates; + var s = ol.xml.getAllTextContent(node, false); + var re = + /^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i; + var m = re.exec(s); + if (m) { + var x = parseFloat(m[1]); + var y = parseFloat(m[2]); + var z = parseFloat(m[3]); + flatCoordinates.push(x, y, z, 0); + } else { + flatCoordinates.push(0, 0, 0, 0); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.MultiLineString|undefined} MultiLineString. + */ +ol.format.KML.readGxMultiTrack_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(ol.array.includes( + ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), + 'namespaceURI of the node should be known to the KML parser'); + goog.asserts.assert(node.localName == 'MultiTrack', + 'localName should be MultiTrack'); + var lineStrings = ol.xml.pushParseAndPop( + /** @type {Array.<ol.geom.LineString>} */ ([]), + ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_, node, objectStack); + if (!lineStrings) { + return undefined; + } + var multiLineString = new ol.geom.MultiLineString(null); + multiLineString.setLineStrings(lineStrings); + return multiLineString; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.LineString|undefined} LineString. + */ +ol.format.KML.readGxTrack_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(ol.array.includes( + ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), + 'namespaceURI of the node should be known to the KML parser'); + goog.asserts.assert(node.localName == 'Track', 'localName should be Track'); + var gxTrackObject = ol.xml.pushParseAndPop( + /** @type {ol.format.KMLGxTrackObject_} */ ({ + flatCoordinates: [], + whens: [] + }), ol.format.KML.GX_TRACK_PARSERS_, node, objectStack); + if (!gxTrackObject) { + return undefined; + } + var flatCoordinates = gxTrackObject.flatCoordinates; + var whens = gxTrackObject.whens; + goog.asserts.assert(flatCoordinates.length / 4 == whens.length, + 'the length of the flatCoordinates array divided by 4 should be the ' + + 'length of the whens array'); + var i, ii; + for (i = 0, ii = Math.min(flatCoordinates.length, whens.length); i < ii; + ++i) { + flatCoordinates[4 * i + 3] = whens[i]; + } + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); + return lineString; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object} Icon object. + */ +ol.format.KML.readIcon_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Icon', 'localName should be Icon'); + var iconObject = ol.xml.pushParseAndPop( + {}, ol.format.KML.ICON_PARSERS_, node, objectStack); + if (iconObject) { + return iconObject; + } else { + return null; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<number>} Flat coordinates. + */ +ol.format.KML.readFlatCoordinatesFromNode_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop(null, + ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack)); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.LineString|undefined} LineString. + */ +ol.format.KML.readLineString_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LineString', + 'localName should be LineString'); + var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), + ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, + objectStack); + var flatCoordinates = + ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); + if (flatCoordinates) { + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + lineString.setProperties(properties); + return lineString; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.Polygon|undefined} Polygon. + */ +ol.format.KML.readLinearRing_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'LinearRing', + 'localName should be LinearRing'); + var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), + ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, + objectStack); + var flatCoordinates = + ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); + if (flatCoordinates) { + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates, + [flatCoordinates.length]); + polygon.setProperties(properties); + return polygon; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.Geometry} Geometry. + */ +ol.format.KML.readMultiGeometry_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'MultiGeometry', + 'localName should be MultiGeometry'); + var geometries = ol.xml.pushParseAndPop( + /** @type {Array.<ol.geom.Geometry>} */ ([]), + ol.format.KML.MULTI_GEOMETRY_PARSERS_, node, objectStack); + if (!geometries) { + return null; + } + if (geometries.length === 0) { + return new ol.geom.GeometryCollection(geometries); + } + var homogeneous = true; + var type = geometries[0].getType(); + var geometry, i, ii; + for (i = 1, ii = geometries.length; i < ii; ++i) { + geometry = geometries[i]; + if (geometry.getType() != type) { + homogeneous = false; + break; + } + } + if (homogeneous) { + /** @type {ol.geom.GeometryLayout} */ + var layout; + /** @type {Array.<number>} */ + var flatCoordinates; + if (type == ol.geom.GeometryType.POINT) { + var point = geometries[0]; + goog.asserts.assertInstanceof(point, ol.geom.Point, + 'point should be an ol.geom.Point'); + layout = point.getLayout(); + flatCoordinates = point.getFlatCoordinates(); + for (i = 1, ii = geometries.length; i < ii; ++i) { + geometry = geometries[i]; + goog.asserts.assertInstanceof(geometry, ol.geom.Point, + 'geometry should be an ol.geom.Point'); + goog.asserts.assert(geometry.getLayout() == layout, + 'geometry layout should be consistent'); + goog.array.extend(flatCoordinates, geometry.getFlatCoordinates()); + } + var multiPoint = new ol.geom.MultiPoint(null); + multiPoint.setFlatCoordinates(layout, flatCoordinates); + ol.format.KML.setCommonGeometryProperties_(multiPoint, geometries); + return multiPoint; + } else if (type == ol.geom.GeometryType.LINE_STRING) { + var multiLineString = new ol.geom.MultiLineString(null); + multiLineString.setLineStrings(geometries); + ol.format.KML.setCommonGeometryProperties_(multiLineString, geometries); + return multiLineString; + } else if (type == ol.geom.GeometryType.POLYGON) { + var multiPolygon = new ol.geom.MultiPolygon(null); + multiPolygon.setPolygons(geometries); + ol.format.KML.setCommonGeometryProperties_(multiPolygon, geometries); + return multiPolygon; + } else if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) { + return new ol.geom.GeometryCollection(geometries); + } else { + goog.asserts.fail('Unexpected type: ' + type); + return null; + } + } else { + return new ol.geom.GeometryCollection(geometries); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.Point|undefined} Point. + */ +ol.format.KML.readPoint_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Point', 'localName should be Point'); + var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), + ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, + objectStack); + var flatCoordinates = + ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); + if (flatCoordinates) { + var point = new ol.geom.Point(null); + goog.asserts.assert(flatCoordinates.length == 3, + 'flatCoordinates should have a length of 3'); + point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); + point.setProperties(properties); + return point; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.geom.Polygon|undefined} Polygon. + */ +ol.format.KML.readPolygon_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Polygon', + 'localName should be Polygon'); + var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), + ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, + objectStack); + var flatLinearRings = ol.xml.pushParseAndPop( + /** @type {Array.<Array.<number>>} */ ([null]), + ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack); + if (flatLinearRings && flatLinearRings[0]) { + var polygon = new ol.geom.Polygon(null); + var flatCoordinates = flatLinearRings[0]; + var ends = [flatCoordinates.length]; + var i, ii; + for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { + goog.array.extend(flatCoordinates, flatLinearRings[i]); + ends.push(flatCoordinates.length); + } + polygon.setFlatCoordinates( + ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); + polygon.setProperties(properties); + return polygon; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<ol.style.Style>} Style. + */ +ol.format.KML.readStyle_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); + var styleObject = ol.xml.pushParseAndPop( + {}, ol.format.KML.STYLE_PARSERS_, node, objectStack); + if (!styleObject) { + return null; + } + var fillStyle = /** @type {ol.style.Fill} */ + ('fillStyle' in styleObject ? + styleObject['fillStyle'] : ol.format.KML.DEFAULT_FILL_STYLE_); + var fill = /** @type {boolean|undefined} */ (styleObject['fill']); + if (fill !== undefined && !fill) { + fillStyle = null; + } + var imageStyle = /** @type {ol.style.Image} */ + ('imageStyle' in styleObject ? + styleObject['imageStyle'] : ol.format.KML.DEFAULT_IMAGE_STYLE_); + var textStyle = /** @type {ol.style.Text} */ + ('textStyle' in styleObject ? + styleObject['textStyle'] : ol.format.KML.DEFAULT_TEXT_STYLE_); + var strokeStyle = /** @type {ol.style.Stroke} */ + ('strokeStyle' in styleObject ? + styleObject['strokeStyle'] : ol.format.KML.DEFAULT_STROKE_STYLE_); + var outline = /** @type {boolean|undefined} */ + (styleObject['outline']); + if (outline !== undefined && !outline) { + strokeStyle = null; + } + return [new ol.style.Style({ + fill: fillStyle, + image: imageStyle, + stroke: strokeStyle, + text: textStyle, + zIndex: undefined // FIXME + })]; +}; + + +/** + * Reads an array of geometries and creates arrays for common geometry + * properties. Then sets them to the multi geometry. + * @param {ol.geom.MultiPoint|ol.geom.MultiLineString|ol.geom.MultiPolygon} + * multiGeometry + * @param {Array.<ol.geom.Geometry>} geometries + * @private + */ +ol.format.KML.setCommonGeometryProperties_ = function(multiGeometry, + geometries) { + var ii = geometries.length; + var extrudes = new Array(geometries.length); + var altitudeModes = new Array(geometries.length); + var geometry, i, hasExtrude, hasAltitudeMode; + hasExtrude = hasAltitudeMode = false; + for (i = 0; i < ii; ++i) { + geometry = geometries[i]; + extrudes[i] = geometry.get('extrude'); + altitudeModes[i] = geometry.get('altitudeMode'); + hasExtrude = hasExtrude || extrudes[i] !== undefined; + hasAltitudeMode = hasAltitudeMode || altitudeModes[i]; + } + if (hasExtrude) { + multiGeometry.set('extrude', extrudes); + } + if (hasAltitudeMode) { + multiGeometry.set('altitudeMode', altitudeModes); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.DataParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Data', 'localName should be Data'); + var name = node.getAttribute('name'); + if (name !== null) { + var data = ol.xml.pushParseAndPop( + undefined, ol.format.KML.DATA_PARSERS_, node, objectStack); + if (data) { + var featureObject = + /** @type {Object} */ (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isObject(featureObject), + 'featureObject should be an Object'); + featureObject[name] = data; + } + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.ExtendedDataParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ExtendedData', + 'localName should be ExtendedData'); + ol.xml.parseNode(ol.format.KML.EXTENDED_DATA_PARSERS_, node, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.PairDataParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Pair', 'localName should be Pair'); + var pairObject = ol.xml.pushParseAndPop( + {}, ol.format.KML.PAIR_PARSERS_, node, objectStack); + if (!pairObject) { + return; + } + var key = /** @type {string|undefined} */ + (pairObject['key']); + if (key && key == 'normal') { + var styleUrl = /** @type {string|undefined} */ + (pairObject['styleUrl']); + if (styleUrl) { + objectStack[objectStack.length - 1] = styleUrl; + } + var Style = /** @type {ol.style.Style} */ + (pairObject['Style']); + if (Style) { + objectStack[objectStack.length - 1] = Style; + } + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.PlacemarkStyleMapParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'StyleMap', + 'localName should be StyleMap'); + var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack); + if (!styleMapValue) { + return; + } + var placemarkObject = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(placemarkObject), + 'placemarkObject should be an Object'); + if (goog.isArray(styleMapValue)) { + placemarkObject['Style'] = styleMapValue; + } else if (goog.isString(styleMapValue)) { + placemarkObject['styleUrl'] = styleMapValue; + } else { + goog.asserts.fail('styleMapValue has an unknown type'); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.SchemaDataParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'SchemaData', + 'localName should be SchemaData'); + ol.xml.parseNode(ol.format.KML.SCHEMA_DATA_PARSERS_, node, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.SimpleDataParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'SimpleData', + 'localName should be SimpleData'); + var name = node.getAttribute('name'); + if (name !== null) { + var data = ol.format.XSD.readString(node); + var featureObject = + /** @type {Object} */ (objectStack[objectStack.length - 1]); + featureObject[name] = data; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.innerBoundaryIsParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'innerBoundaryIs', + 'localName should be innerBoundaryIs'); + var flatLinearRing = ol.xml.pushParseAndPop( + /** @type {Array.<number>|undefined} */ (undefined), + ol.format.KML.INNER_BOUNDARY_IS_PARSERS_, node, objectStack); + if (flatLinearRing) { + var flatLinearRings = /** @type {Array.<Array.<number>>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(flatLinearRings), + 'flatLinearRings should be an array'); + goog.asserts.assert(flatLinearRings.length > 0, + 'flatLinearRings array should not be empty'); + flatLinearRings.push(flatLinearRing); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.outerBoundaryIsParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'outerBoundaryIs', + 'localName should be outerBoundaryIs'); + var flatLinearRing = ol.xml.pushParseAndPop( + /** @type {Array.<number>|undefined} */ (undefined), + ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_, node, objectStack); + if (flatLinearRing) { + var flatLinearRings = /** @type {Array.<Array.<number>>} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isArray(flatLinearRings), + 'flatLinearRings should be an array'); + goog.asserts.assert(flatLinearRings.length > 0, + 'flatLinearRings array should not be empty'); + flatLinearRings[0] = flatLinearRing; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.LinkParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Link', 'localName should be Link'); + ol.xml.parseNode(ol.format.KML.LINK_PARSERS_, node, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.whenParser_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'when', 'localName should be when'); + var gxTrackObject = /** @type {ol.format.KMLGxTrackObject_} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isObject(gxTrackObject), + 'gxTrackObject should be an Object'); + var whens = gxTrackObject.whens; + var s = ol.xml.getAllTextContent(node, false); + var re = + /^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/; + var m = re.exec(s); + if (m) { + var year = parseInt(m[1], 10); + var month = m[3] ? parseInt(m[3], 10) - 1 : 0; + var day = m[5] ? parseInt(m[5], 10) : 1; + var hour = m[7] ? parseInt(m[7], 10) : 0; + var minute = m[8] ? parseInt(m[8], 10) : 0; + var second = m[9] ? parseInt(m[9], 10) : 0; + var when = Date.UTC(year, month, day, hour, minute, second); + if (m[10] && m[10] != 'Z') { + var sign = m[11] == '-' ? -1 : 1; + when += sign * 60 * parseInt(m[12], 10); + if (m[13]) { + when += sign * 60 * 60 * parseInt(m[13], 10); + } + } + whens.push(when); + } else { + whens.push(0); + } +}; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.DATA_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'value': ol.xml.makeReplacer(ol.format.XSD.readString) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.EXTENDED_DATA_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Data': ol.format.KML.DataParser_, + 'SchemaData': ol.format.KML.SchemaDataParser_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'extrude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), + 'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.FLAT_LINEAR_RING_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'innerBoundaryIs': ol.format.KML.innerBoundaryIsParser_, + 'outerBoundaryIs': ol.format.KML.outerBoundaryIsParser_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.GX_TRACK_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'when': ol.format.KML.whenParser_ + }, ol.xml.makeStructureNS( + ol.format.KML.GX_NAMESPACE_URIS_, { + 'coord': ol.format.KML.gxCoordParser_ + })); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.ICON_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_) + }, ol.xml.makeStructureNS( + ol.format.KML.GX_NAMESPACE_URIS_, { + 'x': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'y': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'w': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'h': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal) + })); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.ICON_STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Icon': ol.xml.makeObjectPropertySetter(ol.format.KML.readIcon_), + 'heading': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'hotSpot': ol.xml.makeObjectPropertySetter(ol.format.KML.readVec2_), + 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.INNER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.LABEL_STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), + 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.LINE_STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), + 'width': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.MULTI_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'LineString': ol.xml.makeArrayPusher(ol.format.KML.readLineString_), + 'LinearRing': ol.xml.makeArrayPusher(ol.format.KML.readLinearRing_), + 'MultiGeometry': ol.xml.makeArrayPusher(ol.format.KML.readMultiGeometry_), + 'Point': ol.xml.makeArrayPusher(ol.format.KML.readPoint_), + 'Polygon': ol.xml.makeArrayPusher(ol.format.KML.readPolygon_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.GX_NAMESPACE_URIS_, { + 'Track': ol.xml.makeArrayPusher(ol.format.KML.readGxTrack_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.NETWORK_LINK_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'ExtendedData': ol.format.KML.ExtendedDataParser_, + 'Link': ol.format.KML.LinkParser_, + 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), + 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.LINK_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.PAIR_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_), + 'key': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyleUrl_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.PLACEMARK_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'ExtendedData': ol.format.KML.ExtendedDataParser_, + 'MultiGeometry': ol.xml.makeObjectPropertySetter( + ol.format.KML.readMultiGeometry_, 'geometry'), + 'LineString': ol.xml.makeObjectPropertySetter( + ol.format.KML.readLineString_, 'geometry'), + 'LinearRing': ol.xml.makeObjectPropertySetter( + ol.format.KML.readLinearRing_, 'geometry'), + 'Point': ol.xml.makeObjectPropertySetter( + ol.format.KML.readPoint_, 'geometry'), + 'Polygon': ol.xml.makeObjectPropertySetter( + ol.format.KML.readPolygon_, 'geometry'), + 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_), + 'StyleMap': ol.format.KML.PlacemarkStyleMapParser_, + 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), + 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_), + 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) + }, ol.xml.makeStructureNS( + ol.format.KML.GX_NAMESPACE_URIS_, { + 'MultiTrack': ol.xml.makeObjectPropertySetter( + ol.format.KML.readGxMultiTrack_, 'geometry'), + 'Track': ol.xml.makeObjectPropertySetter( + ol.format.KML.readGxTrack_, 'geometry') + } + )); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.POLY_STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), + 'fill': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), + 'outline': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.SCHEMA_DATA_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'SimpleData': ol.format.KML.SimpleDataParser_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'IconStyle': ol.format.KML.IconStyleParser_, + 'LabelStyle': ol.format.KML.LabelStyleParser_, + 'LineStyle': ol.format.KML.LineStyleParser_, + 'PolyStyle': ol.format.KML.PolyStyleParser_ + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.KML.STYLE_MAP_PARSERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Pair': ol.format.KML.PairDataParser_ + }); + + +/** + * @inheritDoc + */ +ol.format.KML.prototype.getExtensions = function() { + return ol.format.KML.EXTENSIONS_; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Array.<ol.Feature>|undefined} Features. + */ +ol.format.KML.prototype.readDocumentOrFolder_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + var localName = ol.xml.getLocalName(node); + goog.asserts.assert(localName == 'Document' || localName == 'Folder', + 'localName should be Document or Folder'); + // FIXME use scope somehow + var parsersNS = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Document': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this), + 'Folder': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this), + 'Placemark': ol.xml.makeArrayPusher(this.readPlacemark_, this), + 'Style': goog.bind(this.readSharedStyle_, this), + 'StyleMap': goog.bind(this.readSharedStyleMap_, this) + }); + var features = ol.xml.pushParseAndPop(/** @type {Array.<ol.Feature>} */ ([]), + parsersNS, node, objectStack, this); + if (features) { + return features; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Feature. + */ +ol.format.KML.prototype.readPlacemark_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Placemark', + 'localName should be Placemark'); + var object = ol.xml.pushParseAndPop({'geometry': null}, + ol.format.KML.PLACEMARK_PARSERS_, node, objectStack); + if (!object) { + return undefined; + } + var feature = new ol.Feature(); + var id = node.getAttribute('id'); + if (id !== null) { + feature.setId(id); + } + var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); + + var geometry = object['geometry']; + if (geometry) { + ol.format.Feature.transformWithOptions(geometry, false, options); + } + feature.setGeometry(geometry); + delete object['geometry']; + + if (this.extractStyles_) { + var style = object['Style']; + var styleUrl = object['styleUrl']; + var styleFunction = ol.format.KML.createFeatureStyleFunction_( + style, styleUrl, this.defaultStyle_, this.sharedStyles_, + this.showPointNames_); + feature.setStyle(styleFunction); + } + delete object['Style']; + // we do not remove the styleUrl property from the object, so it + // gets stored on feature when setProperties is called + + feature.setProperties(object); + + return feature; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); + var id = node.getAttribute('id'); + if (id !== null) { + var style = ol.format.KML.readStyle_(node, objectStack); + if (style) { + var styleUri; + if (node.baseURI) { + styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString(); + } else { + styleUri = '#' + id; + } + this.sharedStyles_[styleUri] = style; + } + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'StyleMap', + 'localName should be StyleMap'); + var id = node.getAttribute('id'); + if (id === null) { + return; + } + var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack); + if (!styleMapValue) { + return; + } + var styleUri; + if (node.baseURI) { + styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString(); + } else { + styleUri = '#' + id; + } + this.sharedStyles_[styleUri] = styleMapValue; +}; + + +/** + * Read the first feature from a KML source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @api stable + */ +ol.format.KML.prototype.readFeature; + + +/** + * @inheritDoc + */ +ol.format.KML.prototype.readFeatureFromNode = function(node, opt_options) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) { + return null; + } + goog.asserts.assert(node.localName == 'Placemark', + 'localName should be Placemark'); + var feature = this.readPlacemark_( + node, [this.getReadOptions(node, opt_options)]); + if (feature) { + return feature; + } else { + return null; + } +}; + + +/** + * Read all features from a KML source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api stable + */ +ol.format.KML.prototype.readFeatures; + + +/** + * @inheritDoc + */ +ol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) { + return []; + } + var features; + var localName = ol.xml.getLocalName(node); + if (localName == 'Document' || localName == 'Folder') { + features = this.readDocumentOrFolder_( + node, [this.getReadOptions(node, opt_options)]); + if (features) { + return features; + } else { + return []; + } + } else if (localName == 'Placemark') { + var feature = this.readPlacemark_( + node, [this.getReadOptions(node, opt_options)]); + if (feature) { + return [feature]; + } else { + return []; + } + } else if (localName == 'kml') { + features = []; + var n; + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + var fs = this.readFeaturesFromNode(n, opt_options); + if (fs) { + goog.array.extend(features, fs); + } + } + return features; + } else { + return []; + } +}; + + +/** + * Read the name of the KML. + * + * @param {Document|Node|string} source Souce. + * @return {string|undefined} Name. + * @api stable + */ +ol.format.KML.prototype.readName = function(source) { + if (ol.xml.isDocument(source)) { + return this.readNameFromDocument(/** @type {Document} */ (source)); + } else if (ol.xml.isNode(source)) { + return this.readNameFromNode(/** @type {Node} */ (source)); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readNameFromDocument(doc); + } else { + goog.asserts.fail('Unknown type for source'); + return undefined; + } +}; + + +/** + * @param {Document} doc Document. + * @return {string|undefined} Name. + */ +ol.format.KML.prototype.readNameFromDocument = function(doc) { + var n; + for (n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + var name = this.readNameFromNode(n); + if (name) { + return name; + } + } + } + return undefined; +}; + + +/** + * @param {Node} node Node. + * @return {string|undefined} Name. + */ +ol.format.KML.prototype.readNameFromNode = function(node) { + var n; + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && + n.localName == 'name') { + return ol.format.XSD.readString(n); + } + } + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + var localName = ol.xml.getLocalName(n); + if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && + (localName == 'Document' || + localName == 'Folder' || + localName == 'Placemark' || + localName == 'kml')) { + var name = this.readNameFromNode(n); + if (name) { + return name; + } + } + } + return undefined; +}; + + +/** + * Read the network links of the KML. + * + * @param {Document|Node|string} source Source. + * @return {Array.<Object>} Network links. + * @api + */ +ol.format.KML.prototype.readNetworkLinks = function(source) { + var networkLinks = []; + if (ol.xml.isDocument(source)) { + goog.array.extend(networkLinks, this.readNetworkLinksFromDocument( + /** @type {Document} */ (source))); + } else if (ol.xml.isNode(source)) { + goog.array.extend(networkLinks, this.readNetworkLinksFromNode( + /** @type {Node} */ (source))); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + goog.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc)); + } else { + goog.asserts.fail('unknown type for source'); + } + return networkLinks; +}; + + +/** + * @param {Document} doc Document. + * @return {Array.<Object>} Network links. + */ +ol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) { + var n, networkLinks = []; + for (n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); + } + } + return networkLinks; +}; + + +/** + * @param {Node} node Node. + * @return {Array.<Object>} Network links. + */ +ol.format.KML.prototype.readNetworkLinksFromNode = function(node) { + var n, networkLinks = []; + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && + n.localName == 'NetworkLink') { + var obj = ol.xml.pushParseAndPop({}, ol.format.KML.NETWORK_LINK_PARSERS_, + n, []); + networkLinks.push(obj); + } + } + for (n = node.firstElementChild; n; n = n.nextElementSibling) { + var localName = ol.xml.getLocalName(n); + if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && + (localName == 'Document' || + localName == 'Folder' || + localName == 'kml')) { + goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); + } + } + return networkLinks; +}; + + +/** + * Read the projection from a KML source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. + * @api stable + */ +ol.format.KML.prototype.readProjection; + + +/** + * @param {Node} node Node to append a TextNode with the color to. + * @param {ol.Color|string} color Color. + * @private + */ +ol.format.KML.writeColorTextNode_ = function(node, color) { + var rgba = ol.color.asArray(color); + var opacity = (rgba.length == 4) ? rgba[3] : 1; + var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]]; + var i; + for (i = 0; i < 4; ++i) { + var hex = parseInt(abgr[i], 10).toString(16); + abgr[i] = (hex.length == 1) ? '0' + hex : hex; + } + ol.format.XSD.writeStringTextNode(node, abgr.join('')); +}; + + +/** + * @param {Node} node Node to append a TextNode with the coordinates to. + * @param {Array.<number>} coordinates Coordinates. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeCoordinatesTextNode_ = + function(node, coordinates, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + + var layout = context['layout']; + var stride = context['stride']; + + var dimension; + if (layout == ol.geom.GeometryLayout.XY || + layout == ol.geom.GeometryLayout.XYM) { + dimension = 2; + } else if (layout == ol.geom.GeometryLayout.XYZ || + layout == ol.geom.GeometryLayout.XYZM) { + dimension = 3; + } else { + goog.asserts.fail('Unknown geometry layout'); + } + + var d, i; + var ii = coordinates.length; + var text = ''; + if (ii > 0) { + text += coordinates[0]; + for (d = 1; d < dimension; ++d) { + text += ',' + coordinates[d]; + } + for (i = stride; i < ii; i += stride) { + text += ' ' + coordinates[i]; + for (d = 1; d < dimension; ++d) { + text += ',' + coordinates[i + d]; + } + } + } + ol.format.XSD.writeStringTextNode(node, text); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<ol.Feature>} features Features. + * @param {Array.<*>} objectStack Object stack. + * @this {ol.format.KML} + * @private + */ +ol.format.KML.writeDocument_ = function(node, features, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_, + ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack, undefined, + this); +}; + + +/** + * @param {Node} node Node. + * @param {Object} icon Icon object. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeIcon_ = function(node, icon, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(icon, orderedKeys); + ol.xml.pushSerializeAndPop(context, + ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, + values, objectStack, orderedKeys); + orderedKeys = + ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]]; + values = ol.xml.makeSequence(icon, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_, + ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.style.Icon} style Icon style. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeIconStyle_ = function(node, style, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + var properties = {}; + var src = style.getSrc(); + var size = style.getSize(); + var iconImageSize = style.getImageSize(); + var iconProperties = { + 'href': src + }; + + if (size) { + iconProperties['w'] = size[0]; + iconProperties['h'] = size[1]; + var anchor = style.getAnchor(); // top-left + var origin = style.getOrigin(); // top-left + + if (origin && iconImageSize && origin[0] !== 0 && origin[1] !== size[1]) { + iconProperties['x'] = origin[0]; + iconProperties['y'] = iconImageSize[1] - (origin[1] + size[1]); + } + + if (anchor && anchor[0] !== 0 && anchor[1] !== size[1]) { + var /** @type {ol.format.KMLVec2_} */ hotSpot = { + x: anchor[0], + xunits: ol.style.IconAnchorUnits.PIXELS, + y: size[1] - anchor[1], + yunits: ol.style.IconAnchorUnits.PIXELS + }; + properties['hotSpot'] = hotSpot; + } + } + + properties['Icon'] = iconProperties; + + var scale = style.getScale(); + if (scale !== 1) { + properties['scale'] = scale; + } + + var rotation = style.getRotation(); + if (rotation !== 0) { + properties['heading'] = rotation; // 0-360 + } + + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.style.Text} style style. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeLabelStyle_ = function(node, style, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + var properties = {}; + var fill = style.getFill(); + if (fill) { + properties['color'] = fill.getColor(); + } + var scale = style.getScale(); + if (scale && scale !== 1) { + properties['scale'] = scale; + } + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = + ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.style.Stroke} style style. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeLineStyle_ = function(node, style, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + var properties = { + 'color': style.getColor(), + 'width': style.getWidth() + }; + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Geometry} geometry Geometry. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeMultiGeometry_ = + function(node, geometry, objectStack) { + goog.asserts.assert( + (geometry instanceof ol.geom.MultiPoint) || + (geometry instanceof ol.geom.MultiLineString) || + (geometry instanceof ol.geom.MultiPolygon), + 'geometry should be one of: ol.geom.MultiPoint, ' + + 'ol.geom.MultiLineString or ol.geom.MultiPolygon'); + /** @type {ol.xml.NodeStackItem} */ + var context = {node: node}; + var type = geometry.getType(); + /** @type {Array.<ol.geom.Geometry>} */ + var geometries; + /** @type {function(*, Array.<*>, string=): (Node|undefined)} */ + var factory; + if (type == ol.geom.GeometryType.MULTI_POINT) { + geometries = + (/** @type {ol.geom.MultiPoint} */ (geometry)).getPoints(); + factory = ol.format.KML.POINT_NODE_FACTORY_; + } else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) { + geometries = + (/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings(); + factory = ol.format.KML.LINE_STRING_NODE_FACTORY_; + } else if (type == ol.geom.GeometryType.MULTI_POLYGON) { + geometries = + (/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons(); + factory = ol.format.KML.POLYGON_NODE_FACTORY_; + } else { + goog.asserts.fail('Unknown geometry type: ' + type); + } + ol.xml.pushSerializeAndPop(context, + ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory, + geometries, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.LinearRing} linearRing Linear ring. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + ol.xml.pushSerializeAndPop(context, + ol.format.KML.BOUNDARY_IS_SERIALIZERS_, + ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack); +}; + + +/** + * FIXME currently we do serialize arbitrary/custom feature properties + * (ExtendedData). + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Object stack. + * @this {ol.format.KML} + * @private + */ +ol.format.KML.writePlacemark_ = function(node, feature, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + + // set id + if (feature.getId()) { + node.setAttribute('id', feature.getId()); + } + + // serialize properties (properties unknown to KML are not serialized) + var properties = feature.getProperties(); + + var styleFunction = feature.getStyleFunction(); + if (styleFunction) { + // FIXME the styles returned by the style function are supposed to be + // resolution-independent here + var styles = styleFunction.call(feature, 0); + if (styles && styles.length > 0) { + var style = styles[0]; + if (this.writeStyles_) { + properties['Style'] = styles[0]; + } + var textStyle = style.getText(); + if (textStyle) { + properties['name'] = textStyle.getText(); + } + } + } + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); + + // serialize geometry + var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); + var geometry = feature.getGeometry(); + if (geometry) { + geometry = + ol.format.Feature.transformWithOptions(geometry, true, options); + } + ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_, + ol.format.KML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.SimpleGeometry} geometry Geometry. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) { + goog.asserts.assert( + (geometry instanceof ol.geom.Point) || + (geometry instanceof ol.geom.LineString) || + (geometry instanceof ol.geom.LinearRing), + 'geometry should be one of ol.geom.Point, ol.geom.LineString ' + + 'or ol.geom.LinearRing'); + var flatCoordinates = geometry.getFlatCoordinates(); + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + context['layout'] = geometry.getLayout(); + context['stride'] = geometry.getStride(); + ol.xml.pushSerializeAndPop(context, + ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_, + ol.format.KML.COORDINATES_NODE_FACTORY_, + [flatCoordinates], objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.geom.Polygon} polygon Polygon. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writePolygon_ = function(node, polygon, objectStack) { + goog.asserts.assertInstanceof(polygon, ol.geom.Polygon, + 'polygon should be an ol.geom.Polygon'); + var linearRings = polygon.getLinearRings(); + goog.asserts.assert(linearRings.length > 0, + 'linearRings should not be empty'); + var outerRing = linearRings.shift(); + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + // inner rings + ol.xml.pushSerializeAndPop(context, + ol.format.KML.POLYGON_SERIALIZERS_, + ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_, + linearRings, objectStack); + // outer ring + ol.xml.pushSerializeAndPop(context, + ol.format.KML.POLYGON_SERIALIZERS_, + ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_, + [outerRing], objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {ol.style.Fill} style Style. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writePolyStyle_ = function(node, style, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_, + ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack); +}; + + +/** + * @param {Node} node Node to append a TextNode with the scale to. + * @param {number|undefined} scale Scale. + * @private + */ +ol.format.KML.writeScaleTextNode_ = function(node, scale) { + ol.format.XSD.writeDecimalTextNode(node, scale * scale); +}; + + +/** + * @param {Node} node Node. + * @param {ol.style.Style} style Style. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.KML.writeStyle_ = function(node, style, objectStack) { + var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; + var properties = {}; + var fillStyle = style.getFill(); + var strokeStyle = style.getStroke(); + var imageStyle = style.getImage(); + var textStyle = style.getText(); + if (imageStyle instanceof ol.style.Icon) { + properties['IconStyle'] = imageStyle; + } + if (textStyle) { + properties['LabelStyle'] = textStyle; + } + if (strokeStyle) { + properties['LineStyle'] = strokeStyle; + } + if (fillStyle) { + properties['PolyStyle'] = fillStyle; + } + var parentNode = objectStack[objectStack.length - 1].node; + var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); +}; + + +/** + * @param {Node} node Node to append a TextNode with the Vec2 to. + * @param {ol.format.KMLVec2_} vec2 Vec2. + * @private + */ +ol.format.KML.writeVec2_ = function(node, vec2) { + node.setAttribute('x', vec2.x); + node.setAttribute('y', vec2.y); + node.setAttribute('xunits', vec2.xunits); + node.setAttribute('yunits', vec2.yunits); +}; + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'Document', 'Placemark' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_), + 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_) + }); + + +/** + * @const + * @type {Object.<string, string>} + * @private + */ +ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = { + 'Point': 'Point', + 'LineString': 'LineString', + 'LinearRing': 'LinearRing', + 'Polygon': 'Polygon', + 'MultiPoint': 'MultiGeometry', + 'MultiLineString': 'MultiGeometry', + 'MultiPolygon': 'MultiGeometry' +}; + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'href' + ], + ol.xml.makeStructureNS( + ol.format.KML.GX_NAMESPACE_URIS_, [ + 'x', 'y', 'w', 'h' + ])); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) + }, ol.xml.makeStructureNS( + ol.format.KML.GX_NAMESPACE_URIS_, { + 'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode) + })); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'scale', 'heading', 'Icon', 'hotSpot' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_), + 'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), + 'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_), + 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'color', 'scale' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_), + 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'color', 'width' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_), + 'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'LinearRing': ol.xml.makeChildAppender( + ol.format.KML.writePrimitiveGeometry_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'LineString': ol.xml.makeChildAppender( + ol.format.KML.writePrimitiveGeometry_), + 'Point': ol.xml.makeChildAppender( + ol.format.KML.writePrimitiveGeometry_), + 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'name', 'open', 'visibility', 'address', 'phoneNumber', 'description', + 'styleUrl', 'Style' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'MultiGeometry': ol.xml.makeChildAppender( + ol.format.KML.writeMultiGeometry_), + 'LineString': ol.xml.makeChildAppender( + ol.format.KML.writePrimitiveGeometry_), + 'LinearRing': ol.xml.makeChildAppender( + ol.format.KML.writePrimitiveGeometry_), + 'Point': ol.xml.makeChildAppender( + ol.format.KML.writePrimitiveGeometry_), + 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_), + 'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_), + 'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'description': ol.xml.makeChildAppender( + ol.format.XSD.writeStringTextNode), + 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'open': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode), + 'phoneNumber': ol.xml.makeChildAppender( + ol.format.XSD.writeStringTextNode), + 'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), + 'visibility': ol.xml.makeChildAppender( + ol.format.XSD.writeBooleanTextNode) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'coordinates': ol.xml.makeChildAppender( + ol.format.KML.writeCoordinatesTextNode_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'outerBoundaryIs': ol.xml.makeChildAppender( + ol.format.KML.writeBoundaryIs_), + 'innerBoundaryIs': ol.xml.makeChildAppender( + ol.format.KML.writeBoundaryIs_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_) + }); + + +/** + * @const + * @type {Object.<string, Array.<string>>} + * @private + */ +ol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, [ + 'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle' + ]); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( + ol.format.KML.NAMESPACE_URIS_, { + 'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_), + 'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_), + 'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_), + 'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_) + }); + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { + return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0], + 'gx:' + opt_nodeName); +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack, + opt_nodeName) { + goog.asserts.assertInstanceof(value, ol.Feature, + 'value should be an ol.Feature'); + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode), + 'parentNode should be an XML node'); + return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark'); +}; + + +/** + * @const + * @param {*} value Value. + * @param {Array.<*>} objectStack Object stack. + * @param {string=} opt_nodeName Node name. + * @return {Node|undefined} Node. + * @private + */ +ol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, + opt_nodeName) { + if (value) { + goog.asserts.assertInstanceof(value, ol.geom.Geometry, + 'value should be an ol.geom.Geometry'); + var parentNode = objectStack[objectStack.length - 1].node; + goog.asserts.assert(ol.xml.isNode(parentNode), + 'parentNode should be an XML node'); + return ol.xml.createElementNS(parentNode.namespaceURI, + ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[value.getType()]); + } +}; + + +/** + * A factory for creating coordinates nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color'); + + +/** + * A factory for creating coordinates nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.COORDINATES_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('coordinates'); + + +/** + * A factory for creating innerBoundaryIs nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('innerBoundaryIs'); + + +/** + * A factory for creating Point nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.POINT_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('Point'); + + +/** + * A factory for creating LineString nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.LINE_STRING_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('LineString'); + + +/** + * A factory for creating LinearRing nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.LINEAR_RING_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('LinearRing'); + + +/** + * A factory for creating Polygon nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.POLYGON_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('Polygon'); + + +/** + * A factory for creating outerBoundaryIs nodes. + * @const + * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @private + */ +ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ = + ol.xml.makeSimpleNodeFactory('outerBoundaryIs'); + + +/** + * Encode an array of features in the KML format. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {string} Result. + * @api stable + */ +ol.format.KML.prototype.writeFeatures; + + +/** + * Encode an array of features in the KML format as an XML node. + * + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Options. + * @return {Node} Node. + * @api + */ +ol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) { + opt_options = this.adaptOptions(opt_options); + var kml = ol.xml.createElementNS(ol.format.KML.NAMESPACE_URIS_[4], 'kml'); + var xmlnsUri = 'http://www.w3.org/2000/xmlns/'; + var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance'; + ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:gx', + ol.format.KML.GX_NAMESPACE_URIS_[0]); + ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri); + ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation', + ol.format.KML.SCHEMA_LOCATION_); + + var /** @type {ol.xml.NodeStackItem} */ context = {node: kml}; + var properties = {}; + if (features.length > 1) { + properties['Document'] = features; + } else if (features.length == 1) { + properties['Placemark'] = features[0]; + } + var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI]; + var values = ol.xml.makeSequence(properties, orderedKeys); + ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_, + ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [opt_options], orderedKeys, + this); + return kml; +}; + +goog.provide('ol.ext.pbf'); +/** @typedef {function(*)} */ +ol.ext.pbf; +(function() { +var exports = {}; +var module = {exports: exports}; +var define; +/** + * @fileoverview + * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pbf = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ +'use strict'; + +// lightweight Buffer shim for pbf browser build +// based on code from github.com/feross/buffer (MIT-licensed) + +module.exports = Buffer; + +var ieee754 = _dereq_('ieee754'); + +var BufferMethods; + +function Buffer(length) { + var arr; + if (length && length.length) { + arr = length; + length = arr.length; + } + var buf = new Uint8Array(length || 0); + if (arr) buf.set(arr); + + buf.readUInt32LE = BufferMethods.readUInt32LE; + buf.writeUInt32LE = BufferMethods.writeUInt32LE; + buf.readInt32LE = BufferMethods.readInt32LE; + buf.writeInt32LE = BufferMethods.writeInt32LE; + buf.readFloatLE = BufferMethods.readFloatLE; + buf.writeFloatLE = BufferMethods.writeFloatLE; + buf.readDoubleLE = BufferMethods.readDoubleLE; + buf.writeDoubleLE = BufferMethods.writeDoubleLE; + buf.toString = BufferMethods.toString; + buf.write = BufferMethods.write; + buf.slice = BufferMethods.slice; + buf.copy = BufferMethods.copy; + + buf._isBuffer = true; + return buf; +} + +var lastStr, lastStrEncoded; + +BufferMethods = { + readUInt32LE: function(pos) { + return ((this[pos]) | + (this[pos + 1] << 8) | + (this[pos + 2] << 16)) + + (this[pos + 3] * 0x1000000); + }, + + writeUInt32LE: function(val, pos) { + this[pos] = val; + this[pos + 1] = (val >>> 8); + this[pos + 2] = (val >>> 16); + this[pos + 3] = (val >>> 24); + }, + + readInt32LE: function(pos) { + return ((this[pos]) | + (this[pos + 1] << 8) | + (this[pos + 2] << 16)) + + (this[pos + 3] << 24); + }, + + readFloatLE: function(pos) { return ieee754.read(this, pos, true, 23, 4); }, + readDoubleLE: function(pos) { return ieee754.read(this, pos, true, 52, 8); }, + + writeFloatLE: function(val, pos) { return ieee754.write(this, val, pos, true, 23, 4); }, + writeDoubleLE: function(val, pos) { return ieee754.write(this, val, pos, true, 52, 8); }, + + toString: function(encoding, start, end) { + var str = '', + tmp = ''; + + start = start || 0; + end = Math.min(this.length, end || this.length); + + for (var i = start; i < end; i++) { + var ch = this[i]; + if (ch <= 0x7F) { + str += decodeURIComponent(tmp) + String.fromCharCode(ch); + tmp = ''; + } else { + tmp += '%' + ch.toString(16); + } + } + + str += decodeURIComponent(tmp); + + return str; + }, + + write: function(str, pos) { + var bytes = str === lastStr ? lastStrEncoded : encodeString(str); + for (var i = 0; i < bytes.length; i++) { + this[pos + i] = bytes[i]; + } + }, + + slice: function(start, end) { + return this.subarray(start, end); + }, + + copy: function(buf, pos) { + pos = pos || 0; + for (var i = 0; i < this.length; i++) { + buf[pos + i] = this[i]; + } + } +}; + +BufferMethods.writeInt32LE = BufferMethods.writeUInt32LE; + +Buffer.byteLength = function(str) { + lastStr = str; + lastStrEncoded = encodeString(str); + return lastStrEncoded.length; +}; + +Buffer.isBuffer = function(buf) { + return !!(buf && buf._isBuffer); +}; + +function encodeString(str) { + var length = str.length, + bytes = []; + + for (var i = 0, c, lead; i < length; i++) { + c = str.charCodeAt(i); // code point + + if (c > 0xD7FF && c < 0xE000) { + + if (lead) { + if (c < 0xDC00) { + bytes.push(0xEF, 0xBF, 0xBD); + lead = c; + continue; + + } else { + c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000; + lead = null; + } + + } else { + if (c > 0xDBFF || (i + 1 === length)) bytes.push(0xEF, 0xBF, 0xBD); + else lead = c; + + continue; + } + + } else if (lead) { + bytes.push(0xEF, 0xBF, 0xBD); + lead = null; + } + + if (c < 0x80) bytes.push(c); + else if (c < 0x800) bytes.push(c >> 0x6 | 0xC0, c & 0x3F | 0x80); + else if (c < 0x10000) bytes.push(c >> 0xC | 0xE0, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); + else bytes.push(c >> 0x12 | 0xF0, c >> 0xC & 0x3F | 0x80, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80); + } + return bytes; +} + +},{"ieee754":3}],2:[function(_dereq_,module,exports){ +(function (global){ +'use strict'; + +module.exports = Pbf; + +var Buffer = global.Buffer || _dereq_('./buffer'); + +function Pbf(buf) { + this.buf = !Buffer.isBuffer(buf) ? new Buffer(buf || 0) : buf; + this.pos = 0; + this.length = this.buf.length; +} + +Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum +Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64 +Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields +Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32 + +var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), + SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32, + POW_2_63 = Math.pow(2, 63); + +Pbf.prototype = { + + destroy: function() { + this.buf = null; + }, + + // === READING ================================================================= + + readFields: function(readField, result, end) { + end = end || this.length; + + while (this.pos < end) { + var val = this.readVarint(), + tag = val >> 3, + startPos = this.pos; + + readField(tag, result, this); + + if (this.pos === startPos) this.skip(val); + } + return result; + }, + + readMessage: function(readField, result) { + return this.readFields(readField, result, this.readVarint() + this.pos); + }, + + readFixed32: function() { + var val = this.buf.readUInt32LE(this.pos); + this.pos += 4; + return val; + }, + + readSFixed32: function() { + var val = this.buf.readInt32LE(this.pos); + this.pos += 4; + return val; + }, + + // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed) + + readFixed64: function() { + var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readSFixed64: function() { + var val = this.buf.readUInt32LE(this.pos) + this.buf.readInt32LE(this.pos + 4) * SHIFT_LEFT_32; + this.pos += 8; + return val; + }, + + readFloat: function() { + var val = this.buf.readFloatLE(this.pos); + this.pos += 4; + return val; + }, + + readDouble: function() { + var val = this.buf.readDoubleLE(this.pos); + this.pos += 8; + return val; + }, + + readVarint: function() { + var buf = this.buf, + val, b, b0, b1, b2, b3; + + b0 = buf[this.pos++]; if (b0 < 0x80) return b0; b0 = b0 & 0x7f; + b1 = buf[this.pos++]; if (b1 < 0x80) return b0 | b1 << 7; b1 = (b1 & 0x7f) << 7; + b2 = buf[this.pos++]; if (b2 < 0x80) return b0 | b1 | b2 << 14; b2 = (b2 & 0x7f) << 14; + b3 = buf[this.pos++]; if (b3 < 0x80) return b0 | b1 | b2 | b3 << 21; + + val = b0 | b1 | b2 | (b3 & 0x7f) << 21; + + b = buf[this.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val; + b = buf[this.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val; + b = buf[this.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val; + b = buf[this.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val; + b = buf[this.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val; + b = buf[this.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val; + + throw new Error('Expected varint not more than 10 bytes'); + }, + + readVarint64: function() { + var startPos = this.pos, + val = this.readVarint(); + + if (val < POW_2_63) return val; + + var pos = this.pos - 2; + while (this.buf[pos] === 0xff) pos--; + if (pos < startPos) pos = startPos; + + val = 0; + for (var i = 0; i < pos - startPos + 1; i++) { + var b = ~this.buf[startPos + i] & 0x7f; + val += i < 4 ? b << i * 7 : b * Math.pow(2, i * 7); + } + + return -val - 1; + }, + + readSVarint: function() { + var num = this.readVarint(); + return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding + }, + + readBoolean: function() { + return Boolean(this.readVarint()); + }, + + readString: function() { + var end = this.readVarint() + this.pos, + str = this.buf.toString('utf8', this.pos, end); + this.pos = end; + return str; + }, + + readBytes: function() { + var end = this.readVarint() + this.pos, + buffer = this.buf.slice(this.pos, end); + this.pos = end; + return buffer; + }, + + // verbose for performance reasons; doesn't affect gzipped size + + readPackedVarint: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readVarint()); + return arr; + }, + readPackedSVarint: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readSVarint()); + return arr; + }, + readPackedBoolean: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readBoolean()); + return arr; + }, + readPackedFloat: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readFloat()); + return arr; + }, + readPackedDouble: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readDouble()); + return arr; + }, + readPackedFixed32: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readFixed32()); + return arr; + }, + readPackedSFixed32: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readSFixed32()); + return arr; + }, + readPackedFixed64: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readFixed64()); + return arr; + }, + readPackedSFixed64: function() { + var end = this.readVarint() + this.pos, arr = []; + while (this.pos < end) arr.push(this.readSFixed64()); + return arr; + }, + + skip: function(val) { + var type = val & 0x7; + if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} + else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos; + else if (type === Pbf.Fixed32) this.pos += 4; + else if (type === Pbf.Fixed64) this.pos += 8; + else throw new Error('Unimplemented type: ' + type); + }, + + // === WRITING ================================================================= + + writeTag: function(tag, type) { + this.writeVarint((tag << 3) | type); + }, + + realloc: function(min) { + var length = this.length || 16; + + while (length < this.pos + min) length *= 2; + + if (length !== this.length) { + var buf = new Buffer(length); + this.buf.copy(buf); + this.buf = buf; + this.length = length; + } + }, + + finish: function() { + this.length = this.pos; + this.pos = 0; + return this.buf.slice(0, this.length); + }, + + writeFixed32: function(val) { + this.realloc(4); + this.buf.writeUInt32LE(val, this.pos); + this.pos += 4; + }, + + writeSFixed32: function(val) { + this.realloc(4); + this.buf.writeInt32LE(val, this.pos); + this.pos += 4; + }, + + writeFixed64: function(val) { + this.realloc(8); + this.buf.writeInt32LE(val & -1, this.pos); + this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeSFixed64: function(val) { + this.realloc(8); + this.buf.writeInt32LE(val & -1, this.pos); + this.buf.writeInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); + this.pos += 8; + }, + + writeVarint: function(val) { + val = +val; + + if (val <= 0x7f) { + this.realloc(1); + this.buf[this.pos++] = val; + + } else if (val <= 0x3fff) { + this.realloc(2); + this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; + this.buf[this.pos++] = ((val >>> 7) & 0x7f); + + } else if (val <= 0x1fffff) { + this.realloc(3); + this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; + this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; + this.buf[this.pos++] = ((val >>> 14) & 0x7f); + + } else if (val <= 0xfffffff) { + this.realloc(4); + this.buf[this.pos++] = ((val >>> 0) & 0x7f) | 0x80; + this.buf[this.pos++] = ((val >>> 7) & 0x7f) | 0x80; + this.buf[this.pos++] = ((val >>> 14) & 0x7f) | 0x80; + this.buf[this.pos++] = ((val >>> 21) & 0x7f); + + } else { + var pos = this.pos; + while (val >= 0x80) { + this.realloc(1); + this.buf[this.pos++] = (val & 0xff) | 0x80; + val /= 0x80; + } + this.realloc(1); + this.buf[this.pos++] = val | 0; + if (this.pos - pos > 10) throw new Error('Given varint doesn\'t fit into 10 bytes'); + } + }, + + writeSVarint: function(val) { + this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2); + }, + + writeBoolean: function(val) { + this.writeVarint(Boolean(val)); + }, + + writeString: function(str) { + str = String(str); + var bytes = Buffer.byteLength(str); + this.writeVarint(bytes); + this.realloc(bytes); + this.buf.write(str, this.pos); + this.pos += bytes; + }, + + writeFloat: function(val) { + this.realloc(4); + this.buf.writeFloatLE(val, this.pos); + this.pos += 4; + }, + + writeDouble: function(val) { + this.realloc(8); + this.buf.writeDoubleLE(val, this.pos); + this.pos += 8; + }, + + writeBytes: function(buffer) { + var len = buffer.length; + this.writeVarint(len); + this.realloc(len); + for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i]; + }, + + writeRawMessage: function(fn, obj) { + this.pos++; // reserve 1 byte for short message length + + // write the message directly to the buffer and see how much was written + var startPos = this.pos; + fn(obj, this); + var len = this.pos - startPos; + + var varintLen = + len <= 0x7f ? 1 : + len <= 0x3fff ? 2 : + len <= 0x1fffff ? 3 : + len <= 0xfffffff ? 4 : Math.ceil(Math.log(len) / (Math.LN2 * 7)); + + // if 1 byte isn't enough for encoding message length, shift the data to the right + if (varintLen > 1) { + this.realloc(varintLen - 1); + for (var i = this.pos - 1; i >= startPos; i--) this.buf[i + varintLen - 1] = this.buf[i]; + } + + // finally, write the message length in the reserved place and restore the position + this.pos = startPos - 1; + this.writeVarint(len); + this.pos += len; + }, + + writeMessage: function(tag, fn, obj) { + this.writeTag(tag, Pbf.Bytes); + this.writeRawMessage(fn, obj); + }, + + writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); }, + writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); }, + writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); }, + writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); }, + writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); }, + writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); }, + writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); }, + writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); }, + writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); }, + + writeBytesField: function(tag, buffer) { + this.writeTag(tag, Pbf.Bytes); + this.writeBytes(buffer); + }, + writeFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFixed32(val); + }, + writeSFixed32Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeSFixed32(val); + }, + writeFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeFixed64(val); + }, + writeSFixed64Field: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeSFixed64(val); + }, + writeVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeVarint(val); + }, + writeSVarintField: function(tag, val) { + this.writeTag(tag, Pbf.Varint); + this.writeSVarint(val); + }, + writeStringField: function(tag, str) { + this.writeTag(tag, Pbf.Bytes); + this.writeString(str); + }, + writeFloatField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed32); + this.writeFloat(val); + }, + writeDoubleField: function(tag, val) { + this.writeTag(tag, Pbf.Fixed64); + this.writeDouble(val); + }, + writeBooleanField: function(tag, val) { + this.writeVarintField(tag, Boolean(val)); + } +}; + +function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); } +function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); } +function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); } +function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); } +function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); } +function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); } +function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); } +function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); } +function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); } + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./buffer":1}],3:[function(_dereq_,module,exports){ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias } - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.ends_ = ends; - this.changed(); -}; + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + value = Math.abs(value) -/** - * @param {Array.<ol.geom.LineString>} lineStrings LineStrings. - */ -ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) { - var layout = this.getLayout(); - var flatCoordinates = []; - var ends = []; - var i, ii; - for (i = 0, ii = lineStrings.length; i < ii; ++i) { - var lineString = lineStrings[i]; - if (i === 0) { - layout = lineString.getLayout(); + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c } else { - // FIXME better handle the case of non-matching layouts - goog.asserts.assert(lineString.getLayout() == layout, - 'layout of lineString should match layout'); + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 } - goog.array.extend(flatCoordinates, lineString.getFlatCoordinates()); - ends.push(flatCoordinates.length); } - this.setFlatCoordinates(layout, flatCoordinates, ends); -}; -goog.provide('ol.geom.MultiPoint'); + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.math'); + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + buffer[offset + i - d] |= s * 128 +} +},{}]},{},[2])(2) +}); +ol.ext.pbf = module.exports; +})(); +goog.provide('ol.ext.vectortile'); +/** @typedef {function(*)} */ +ol.ext.vectortile; +(function() { +var exports = {}; +var module = {exports: exports}; +var define; /** - * @classdesc - * Multi-point geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable + * @fileoverview + * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} */ -ol.geom.MultiPoint = function(coordinates, opt_layout) { - goog.base(this); - this.setCoordinates(coordinates, opt_layout); -}; -goog.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry); - +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vectortile = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ +module.exports.VectorTile = _dereq_('./lib/vectortile.js'); +module.exports.VectorTileFeature = _dereq_('./lib/vectortilefeature.js'); +module.exports.VectorTileLayer = _dereq_('./lib/vectortilelayer.js'); -/** - * Append the passed point to this multipoint. - * @param {ol.geom.Point} point Point. - * @api stable - */ -ol.geom.MultiPoint.prototype.appendPoint = function(point) { - goog.asserts.assert(point.getLayout() == this.layout, - 'the layout of point should match layout'); - if (!this.flatCoordinates) { - this.flatCoordinates = point.getFlatCoordinates().slice(); - } else { - goog.array.extend(this.flatCoordinates, point.getFlatCoordinates()); - } - this.changed(); -}; +},{"./lib/vectortile.js":2,"./lib/vectortilefeature.js":3,"./lib/vectortilelayer.js":4}],2:[function(_dereq_,module,exports){ +'use strict'; +var VectorTileLayer = _dereq_('./vectortilelayer'); -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.MultiPoint} Clone. - * @api stable - */ -ol.geom.MultiPoint.prototype.clone = function() { - var multiPoint = new ol.geom.MultiPoint(null); - multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return multiPoint; -}; +module.exports = VectorTile; +function VectorTile(pbf, end) { + this.layers = pbf.readFields(readTile, {}, end); +} -/** - * @inheritDoc - */ -ol.geom.MultiPoint.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - var flatCoordinates = this.flatCoordinates; - var stride = this.stride; - var i, ii, j; - for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { - var squaredDistance = ol.math.squaredDistance( - x, y, flatCoordinates[i], flatCoordinates[i + 1]); - if (squaredDistance < minSquaredDistance) { - minSquaredDistance = squaredDistance; - for (j = 0; j < stride; ++j) { - closestPoint[j] = flatCoordinates[i + j]; - } - closestPoint.length = stride; +function readTile(tag, layers, pbf) { + if (tag === 3) { + var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); + if (layer.length) layers[layer.name] = layer; } - } - return minSquaredDistance; -}; - - -/** - * Return the coordinates of the multipoint. - * @return {Array.<ol.Coordinate>} Coordinates. - * @api stable - */ -ol.geom.MultiPoint.prototype.getCoordinates = function() { - return ol.geom.flat.inflate.coordinates( - this.flatCoordinates, 0, this.flatCoordinates.length, this.stride); -}; +} -/** - * Return the point at the specified index. - * @param {number} index Index. - * @return {ol.geom.Point} Point. - * @api stable - */ -ol.geom.MultiPoint.prototype.getPoint = function(index) { - var n = !this.flatCoordinates ? - 0 : this.flatCoordinates.length / this.stride; - goog.asserts.assert(0 <= index && index < n, - 'index should be in between 0 and n'); - if (index < 0 || n <= index) { - return null; - } - var point = new ol.geom.Point(null); - point.setFlatCoordinates(this.layout, this.flatCoordinates.slice( - index * this.stride, (index + 1) * this.stride)); - return point; -}; +},{"./vectortilelayer":4}],3:[function(_dereq_,module,exports){ +'use strict'; +var Point = _dereq_('point-geometry'); -/** - * Return the points of this multipoint. - * @return {Array.<ol.geom.Point>} Points. - * @api stable - */ -ol.geom.MultiPoint.prototype.getPoints = function() { - var flatCoordinates = this.flatCoordinates; - var layout = this.layout; - var stride = this.stride; - /** @type {Array.<ol.geom.Point>} */ - var points = []; - var i, ii; - for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { - var point = new ol.geom.Point(null); - point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride)); - points.push(point); - } - return points; -}; +module.exports = VectorTileFeature; +function VectorTileFeature(pbf, end, extent, keys, values) { + // Public + this.properties = {}; + this.extent = extent; + this.type = 0; -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPoint.prototype.getType = function() { - return ol.geom.GeometryType.MULTI_POINT; -}; + // Private + this._pbf = pbf; + this._geometry = -1; + this._keys = keys; + this._values = values; + pbf.readFields(readFeature, this, end); +} -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) { - var flatCoordinates = this.flatCoordinates; - var stride = this.stride; - var i, ii, x, y; - for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) { - x = flatCoordinates[i]; - y = flatCoordinates[i + 1]; - if (ol.extent.containsXY(extent, x, y)) { - return true; - } - } - return false; -}; +function readFeature(tag, feature, pbf) { + if (tag == 1) feature._id = pbf.readVarint(); + else if (tag == 2) readTag(pbf, feature); + else if (tag == 3) feature.type = pbf.readVarint(); + else if (tag == 4) feature._geometry = pbf.pos; +} +function readTag(pbf, feature) { + var end = pbf.readVarint() + pbf.pos; -/** - * Set the coordinates of the multipoint. - * @param {Array.<ol.Coordinate>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPoint.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, coordinates, 1); - if (!this.flatCoordinates) { - this.flatCoordinates = []; + while (pbf.pos < end) { + var key = feature._keys[pbf.readVarint()], + value = feature._values[pbf.readVarint()]; + feature.properties[key] = value; } - this.flatCoordinates.length = ol.geom.flat.deflate.coordinates( - this.flatCoordinates, 0, coordinates, this.stride); - this.changed(); - } -}; - +} -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - */ -ol.geom.MultiPoint.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; +VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon']; -goog.provide('ol.geom.flat.center'); +VectorTileFeature.prototype.loadGeometry = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; -goog.require('ol.extent'); + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + lines = [], + line; + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } -/** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.<Array.<number>>} endss Endss. - * @param {number} stride Stride. - * @return {Array.<number>} Flat centers. - */ -ol.geom.flat.center.linearRingss = - function(flatCoordinates, offset, endss, stride) { - var flatCenters = []; - var i, ii; - var extent = ol.extent.createEmpty(); - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - extent = ol.extent.createOrUpdateFromFlatCoordinates( - flatCoordinates, offset, ends[0], stride); - flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2); - offset = ends[ends.length - 1]; - } - return flatCenters; -}; + length--; -goog.provide('ol.geom.MultiPolygon'); + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.area'); -goog.require('ol.geom.flat.center'); -goog.require('ol.geom.flat.closest'); -goog.require('ol.geom.flat.contains'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.geom.flat.interiorpoint'); -goog.require('ol.geom.flat.intersectsextent'); -goog.require('ol.geom.flat.orient'); -goog.require('ol.geom.flat.simplify'); + if (cmd === 1) { // moveTo + if (line) lines.push(line); + line = []; + } + line.push(new Point(x, y)); + } else if (cmd === 7) { -/** - * @classdesc - * Multi-polygon geometry. - * - * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPolygon = function(coordinates, opt_layout) { + // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90 + if (line) { + line.push(line[0].clone()); // closePolygon + } - goog.base(this); + } else { + throw new Error('unknown command ' + cmd); + } + } - /** - * @type {Array.<Array.<number>>} - * @private - */ - this.endss_ = []; + if (line) lines.push(line); - /** - * @private - * @type {number} - */ - this.flatInteriorPointsRevision_ = -1; + return lines; +}; - /** - * @private - * @type {Array.<number>} - */ - this.flatInteriorPoints_ = null; +VectorTileFeature.prototype.bbox = function() { + var pbf = this._pbf; + pbf.pos = this._geometry; - /** - * @private - * @type {number} - */ - this.maxDelta_ = -1; + var end = pbf.readVarint() + pbf.pos, + cmd = 1, + length = 0, + x = 0, + y = 0, + x1 = Infinity, + x2 = -Infinity, + y1 = Infinity, + y2 = -Infinity; - /** - * @private - * @type {number} - */ - this.maxDeltaRevision_ = -1; + while (pbf.pos < end) { + if (!length) { + var cmdLen = pbf.readVarint(); + cmd = cmdLen & 0x7; + length = cmdLen >> 3; + } - /** - * @private - * @type {number} - */ - this.orientedRevision_ = -1; + length--; - /** - * @private - * @type {Array.<number>} - */ - this.orientedFlatCoordinates_ = null; + if (cmd === 1 || cmd === 2) { + x += pbf.readSVarint(); + y += pbf.readSVarint(); + if (x < x1) x1 = x; + if (x > x2) x2 = x; + if (y < y1) y1 = y; + if (y > y2) y2 = y; - this.setCoordinates(coordinates, opt_layout); + } else if (cmd !== 7) { + throw new Error('unknown command ' + cmd); + } + } + return [x1, y1, x2, y2]; }; -goog.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry); +VectorTileFeature.prototype.toGeoJSON = function(x, y, z) { + var size = this.extent * Math.pow(2, z), + x0 = this.extent * x, + y0 = this.extent * y, + coords = this.loadGeometry(), + type = VectorTileFeature.types[this.type]; -/** - * Append the passed polygon to this multipolygon. - * @param {ol.geom.Polygon} polygon Polygon. - * @api stable - */ -ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) { - goog.asserts.assert(polygon.getLayout() == this.layout, - 'layout of polygon should match layout'); - /** @type {Array.<number>} */ - var ends; - if (!this.flatCoordinates) { - this.flatCoordinates = polygon.getFlatCoordinates().slice(); - ends = polygon.getEnds().slice(); - this.endss_.push(); - } else { - var offset = this.flatCoordinates.length; - goog.array.extend(this.flatCoordinates, polygon.getFlatCoordinates()); - ends = polygon.getEnds().slice(); - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - ends[i] += offset; + for (var i = 0; i < coords.length; i++) { + var line = coords[i]; + for (var j = 0; j < line.length; j++) { + var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; + line[j] = [ + (p.x + x0) * 360 / size - 180, + 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90 + ]; + } + } + + if (type === 'Point' && coords.length === 1) { + coords = coords[0][0]; + } else if (type === 'Point') { + coords = coords[0]; + type = 'MultiPoint'; + } else if (type === 'LineString' && coords.length === 1) { + coords = coords[0]; + } else if (type === 'LineString') { + type = 'MultiLineString'; } - } - this.endss_.push(ends); - this.changed(); + + return { + type: "Feature", + geometry: { + type: type, + coordinates: coords + }, + properties: this.properties + }; }; +},{"point-geometry":5}],4:[function(_dereq_,module,exports){ +'use strict'; -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.MultiPolygon} Clone. - * @api stable - */ -ol.geom.MultiPolygon.prototype.clone = function() { - var multiPolygon = new ol.geom.MultiPolygon(null); - var newEndss = /** @type {Array.<Array.<number>>} */ - (goog.object.unsafeClone(this.endss_)); - multiPolygon.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(), newEndss); - return multiPolygon; -}; +var VectorTileFeature = _dereq_('./vectortilefeature.js'); +module.exports = VectorTileLayer; -/** - * @inheritDoc - */ -ol.geom.MultiPolygon.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - if (this.maxDeltaRevision_ != this.getRevision()) { - this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta( - this.flatCoordinates, 0, this.endss_, this.stride, 0)); - this.maxDeltaRevision_ = this.getRevision(); - } - return ol.geom.flat.closest.getssClosestPoint( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, - this.maxDelta_, true, x, y, closestPoint, minSquaredDistance); -}; +function VectorTileLayer(pbf, end) { + // Public + this.version = 1; + this.name = null; + this.extent = 4096; + this.length = 0; + // Private + this._pbf = pbf; + this._keys = []; + this._values = []; + this._features = []; -/** - * @inheritDoc - */ -ol.geom.MultiPolygon.prototype.containsXY = function(x, y) { - return ol.geom.flat.contains.linearRingssContainsXY( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y); -}; + pbf.readFields(readLayer, this, end); + this.length = this._features.length; +} -/** - * Return the area of the multipolygon on projected plane. - * @return {number} Area (on projected plane). - * @api stable - */ -ol.geom.MultiPolygon.prototype.getArea = function() { - return ol.geom.flat.area.linearRingss( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride); -}; +function readLayer(tag, layer, pbf) { + if (tag === 15) layer.version = pbf.readVarint(); + else if (tag === 1) layer.name = pbf.readString(); + else if (tag === 5) layer.extent = pbf.readVarint(); + else if (tag === 2) layer._features.push(pbf.pos); + else if (tag === 3) layer._keys.push(pbf.readString()); + else if (tag === 4) layer._values.push(readValueMessage(pbf)); +} +function readValueMessage(pbf) { + var value = null, + end = pbf.readVarint() + pbf.pos; -/** - * Get the coordinate array for this geometry. This array has the structure - * of a GeoJSON coordinate array for multi-polygons. - * - * @param {boolean=} opt_right Orient coordinates according to the right-hand - * rule (counter-clockwise for exterior and clockwise for interior rings). - * If `false`, coordinates will be oriented according to the left-hand rule - * (clockwise for exterior and counter-clockwise for interior rings). - * By default, coordinate orientation will depend on how the geometry was - * constructed. - * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) { - var flatCoordinates; - if (opt_right !== undefined) { - flatCoordinates = this.getOrientedFlatCoordinates().slice(); - ol.geom.flat.orient.orientLinearRingss( - flatCoordinates, 0, this.endss_, this.stride, opt_right); - } else { - flatCoordinates = this.flatCoordinates; - } + while (pbf.pos < end) { + var tag = pbf.readVarint() >> 3; - return ol.geom.flat.inflate.coordinatesss( - flatCoordinates, 0, this.endss_, this.stride); -}; + value = tag === 1 ? pbf.readString() : + tag === 2 ? pbf.readFloat() : + tag === 3 ? pbf.readDouble() : + tag === 4 ? pbf.readVarint64() : + tag === 5 ? pbf.readVarint() : + tag === 6 ? pbf.readSVarint() : + tag === 7 ? pbf.readBoolean() : null; + } + return value; +} -/** - * @return {Array.<Array.<number>>} Endss. - */ -ol.geom.MultiPolygon.prototype.getEndss = function() { - return this.endss_; -}; +// return feature `i` from this layer as a `VectorTileFeature` +VectorTileLayer.prototype.feature = function(i) { + if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds'); + this._pbf.pos = this._features[i]; -/** - * @return {Array.<number>} Flat interior points. - */ -ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() { - if (this.flatInteriorPointsRevision_ != this.getRevision()) { - var flatCenters = ol.geom.flat.center.linearRingss( - this.flatCoordinates, 0, this.endss_, this.stride); - this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, - flatCenters); - this.flatInteriorPointsRevision_ = this.getRevision(); - } - return this.flatInteriorPoints_; + var end = this._pbf.readVarint() + this._pbf.pos; + return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); }; +},{"./vectortilefeature.js":3}],5:[function(_dereq_,module,exports){ +'use strict'; -/** - * Return the interior points as {@link ol.geom.MultiPoint multipoint}. - * @return {ol.geom.MultiPoint} Interior points. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getInteriorPoints = function() { - var interiorPoints = new ol.geom.MultiPoint(null); - interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY, - this.getFlatInteriorPoints().slice()); - return interiorPoints; -}; +module.exports = Point; +function Point(x, y) { + this.x = x; + this.y = y; +} -/** - * @return {Array.<number>} Oriented flat coordinates. - */ -ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() { - if (this.orientedRevision_ != this.getRevision()) { - var flatCoordinates = this.flatCoordinates; - if (ol.geom.flat.orient.linearRingssAreOriented( - flatCoordinates, 0, this.endss_, this.stride)) { - this.orientedFlatCoordinates_ = flatCoordinates; - } else { - this.orientedFlatCoordinates_ = flatCoordinates.slice(); - this.orientedFlatCoordinates_.length = - ol.geom.flat.orient.orientLinearRingss( - this.orientedFlatCoordinates_, 0, this.endss_, this.stride); - } - this.orientedRevision_ = this.getRevision(); - } - return this.orientedFlatCoordinates_; -}; +Point.prototype = { + clone: function() { return new Point(this.x, this.y); }, + add: function(p) { return this.clone()._add(p); }, + sub: function(p) { return this.clone()._sub(p); }, + mult: function(k) { return this.clone()._mult(k); }, + div: function(k) { return this.clone()._div(k); }, + rotate: function(a) { return this.clone()._rotate(a); }, + matMult: function(m) { return this.clone()._matMult(m); }, + unit: function() { return this.clone()._unit(); }, + perp: function() { return this.clone()._perp(); }, + round: function() { return this.clone()._round(); }, -/** - * @inheritDoc - */ -ol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - var simplifiedFlatCoordinates = []; - var simplifiedEndss = []; - simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess( - this.flatCoordinates, 0, this.endss_, this.stride, - Math.sqrt(squaredTolerance), - simplifiedFlatCoordinates, 0, simplifiedEndss); - var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null); - simplifiedMultiPolygon.setFlatCoordinates( - ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss); - return simplifiedMultiPolygon; -}; + mag: function() { + return Math.sqrt(this.x * this.x + this.y * this.y); + }, + equals: function(p) { + return this.x === p.x && + this.y === p.y; + }, -/** - * Return the polygon at the specified index. - * @param {number} index Index. - * @return {ol.geom.Polygon} Polygon. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getPolygon = function(index) { - goog.asserts.assert(0 <= index && index < this.endss_.length, - 'index should be in between 0 and the length of this.endss_'); - if (index < 0 || this.endss_.length <= index) { - return null; - } - var offset; - if (index === 0) { - offset = 0; - } else { - var prevEnds = this.endss_[index - 1]; - offset = prevEnds[prevEnds.length - 1]; - } - var ends = this.endss_[index].slice(); - var end = ends[ends.length - 1]; - if (offset !== 0) { - var i, ii; - for (i = 0, ii = ends.length; i < ii; ++i) { - ends[i] -= offset; - } - } - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - this.layout, this.flatCoordinates.slice(offset, end), ends); - return polygon; -}; + dist: function(p) { + return Math.sqrt(this.distSqr(p)); + }, + distSqr: function(p) { + var dx = p.x - this.x, + dy = p.y - this.y; + return dx * dx + dy * dy; + }, -/** - * Return the polygons of this multipolygon. - * @return {Array.<ol.geom.Polygon>} Polygons. - * @api stable - */ -ol.geom.MultiPolygon.prototype.getPolygons = function() { - var layout = this.layout; - var flatCoordinates = this.flatCoordinates; - var endss = this.endss_; - var polygons = []; - var offset = 0; - var i, ii, j, jj; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i].slice(); - var end = ends[ends.length - 1]; - if (offset !== 0) { - for (j = 0, jj = ends.length; j < jj; ++j) { - ends[j] -= offset; - } - } - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates( - layout, flatCoordinates.slice(offset, end), ends); - polygons.push(polygon); - offset = end; - } - return polygons; -}; + angle: function() { + return Math.atan2(this.y, this.x); + }, + angleTo: function(b) { + return Math.atan2(this.y - b.y, this.x - b.x); + }, -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPolygon.prototype.getType = function() { - return ol.geom.GeometryType.MULTI_POLYGON; -}; + angleWith: function(b) { + return this.angleWithSep(b.x, b.y); + }, + // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ. + angleWithSep: function(x, y) { + return Math.atan2( + this.x * y - this.y * x, + this.x * x + this.y * y); + }, -/** - * @inheritDoc - * @api stable - */ -ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) { - return ol.geom.flat.intersectsextent.linearRingss( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent); -}; + _matMult: function(m) { + var x = m[0] * this.x + m[1] * this.y, + y = m[2] * this.x + m[3] * this.y; + this.x = x; + this.y = y; + return this; + }, + _add: function(p) { + this.x += p.x; + this.y += p.y; + return this; + }, -/** - * Set the coordinates of the multipolygon. - * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api stable - */ -ol.geom.MultiPolygon.prototype.setCoordinates = - function(coordinates, opt_layout) { - if (!coordinates) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_); - } else { - this.setLayout(opt_layout, coordinates, 3); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - var endss = ol.geom.flat.deflate.coordinatesss( - this.flatCoordinates, 0, coordinates, this.stride, this.endss_); - if (endss.length === 0) { - this.flatCoordinates.length = 0; - } else { - var lastEnds = endss[endss.length - 1]; - this.flatCoordinates.length = lastEnds.length === 0 ? - 0 : lastEnds[lastEnds.length - 1]; - } - this.changed(); - } -}; + _sub: function(p) { + this.x -= p.x; + this.y -= p.y; + return this; + }, + _mult: function(k) { + this.x *= k; + this.y *= k; + return this; + }, -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Array.<Array.<number>>} endss Endss. - */ -ol.geom.MultiPolygon.prototype.setFlatCoordinates = - function(layout, flatCoordinates, endss) { - goog.asserts.assert(endss, 'endss must be truthy'); - if (!flatCoordinates || flatCoordinates.length === 0) { - goog.asserts.assert(endss.length === 0, 'the length of endss should be 0'); - } else { - goog.asserts.assert(endss.length > 0, 'endss cannot be an empty array'); - var ends = endss[endss.length - 1]; - goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1], - 'the length of flatCoordinates should be the last value of ends'); - } - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.endss_ = endss; - this.changed(); -}; + _div: function(k) { + this.x /= k; + this.y /= k; + return this; + }, + _unit: function() { + this._div(this.mag()); + return this; + }, -/** - * @param {Array.<ol.geom.Polygon>} polygons Polygons. - */ -ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) { - var layout = this.getLayout(); - var flatCoordinates = []; - var endss = []; - var i, ii, ends; - for (i = 0, ii = polygons.length; i < ii; ++i) { - var polygon = polygons[i]; - if (i === 0) { - layout = polygon.getLayout(); - } else { - // FIXME better handle the case of non-matching layouts - goog.asserts.assert(polygon.getLayout() == layout, - 'layout of polygon should be layout'); + _perp: function() { + var y = this.y; + this.y = this.x; + this.x = -y; + return this; + }, + + _rotate: function(angle) { + var cos = Math.cos(angle), + sin = Math.sin(angle), + x = cos * this.x - sin * this.y, + y = sin * this.x + cos * this.y; + this.x = x; + this.y = y; + return this; + }, + + _round: function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; } - var offset = flatCoordinates.length; - ends = polygon.getEnds(); - var j, jj; - for (j = 0, jj = ends.length; j < jj; ++j) { - ends[j] += offset; +}; + +// constructs Point from an array if necessary +Point.convert = function (a) { + if (a instanceof Point) { + return a; } - goog.array.extend(flatCoordinates, polygon.getFlatCoordinates()); - endss.push(ends); - } - this.setFlatCoordinates(layout, flatCoordinates, endss); + if (Array.isArray(a)) { + return new Point(a[0], a[1]); + } + return a; }; -goog.provide('ol.format.EsriJSON'); +},{}]},{},[1])(1) +}); +ol.ext.vectortile = module.exports; +})(); + +//FIXME Implement projection handling + +goog.provide('ol.format.MVT'); -goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.object'); goog.require('ol.Feature'); -goog.require('ol.extent'); +goog.require('ol.ext.pbf'); +goog.require('ol.ext.vectortile'); goog.require('ol.format.Feature'); -goog.require('ol.format.JSONFeature'); +goog.require('ol.format.FormatType'); +goog.require('ol.geom.Geometry'); goog.require('ol.geom.GeometryLayout'); goog.require('ol.geom.GeometryType'); goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); goog.require('ol.geom.Point'); goog.require('ol.geom.Polygon'); -goog.require('ol.geom.flat.orient'); goog.require('ol.proj'); +goog.require('ol.proj.Projection'); +goog.require('ol.proj.Units'); +goog.require('ol.render.Feature'); /** * @classdesc - * Feature format for reading and writing data in the EsriJSON format. + * Feature format for reading data in the Mapbox MVT format. * * @constructor - * @extends {ol.format.JSONFeature} - * @param {olx.format.EsriJSONOptions=} opt_options Options. + * @extends {ol.format.Feature} + * @param {olx.format.MVTOptions=} opt_options Options. * @api */ -ol.format.EsriJSON = function(opt_options) { +ol.format.MVT = function(opt_options) { + + goog.base(this); var options = opt_options ? opt_options : {}; - goog.base(this); + /** + * @type {ol.proj.Projection} + */ + this.defaultDataProjection = new ol.proj.Projection({ + code: 'EPSG:3857', + units: ol.proj.Units.TILE_PIXELS + }); + + /** + * @private + * @type {function((ol.geom.Geometry|Object.<string, *>)=)| + * function(ol.geom.GeometryType,Array.<number>, + * (Array.<number>|Array.<Array.<number>>),Object.<string, *>)} + */ + this.featureClass_ = options.featureClass ? + options.featureClass : ol.render.Feature; + + /** + * @private + * @type {string} + */ + this.geometryName_ = options.geometryName ? + options.geometryName : 'geometry'; + + /** + * @private + * @type {string} + */ + this.layerName_ = options.layerName ? options.layerName : 'layer'; /** - * Name of the geometry attribute for features. - * @type {string|undefined} * @private + * @type {Array.<string>} */ - this.geometryName_ = options.geometryName; + this.layers_ = options.layers ? options.layers : null; }; -goog.inherits(ol.format.EsriJSON, ol.format.JSONFeature); +goog.inherits(ol.format.MVT, ol.format.Feature); /** - * @param {EsriJSONGeometry} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @private - * @return {ol.geom.Geometry} Geometry. + * @inheritDoc */ -ol.format.EsriJSON.readGeometry_ = function(object, opt_options) { - if (!object) { - return null; - } - var type; - if (goog.isNumber(object.x) && goog.isNumber(object.y)) { - type = ol.geom.GeometryType.POINT; - } else if (object.points) { - type = ol.geom.GeometryType.MULTI_POINT; - } else if (object.paths) { - if (object.paths.length === 1) { - type = ol.geom.GeometryType.LINE_STRING; - } else { - type = ol.geom.GeometryType.MULTI_LINE_STRING; - } - } else if (object.rings) { - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - var rings = ol.format.EsriJSON.convertRings_(object.rings, layout); - object = /** @type {EsriJSONGeometry} */(goog.object.clone(object)); - if (rings.length === 1) { - type = ol.geom.GeometryType.POLYGON; - object.rings = rings[0]; - } else { - type = ol.geom.GeometryType.MULTI_POLYGON; - object.rings = rings; - } - } - goog.asserts.assert(type, 'geometry type should be defined'); - var geometryReader = ol.format.EsriJSON.GEOMETRY_READERS_[type]; - goog.asserts.assert(geometryReader, - 'geometryReader should be defined'); - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions( - geometryReader(object), false, opt_options)); +ol.format.MVT.prototype.getType = function() { + return ol.format.FormatType.ARRAY_BUFFER; }; /** - * Determines inner and outer rings. - * Checks if any polygons in this array contain any other polygons in this - * array. It is used for checking for holes. - * Logic inspired by: https://github.com/Esri/terraformer-arcgis-parser - * @param {Array.<!Array.<!Array.<number>>>} rings Rings. - * @param {ol.geom.GeometryLayout} layout Geometry layout. * @private - * @return {Array.<!Array.<!Array.<number>>>} Transoformed rings. + * @param {Object} rawFeature Raw Mapbox feature. + * @param {string} layer Layer. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. */ -ol.format.EsriJSON.convertRings_ = function(rings, layout) { - var outerRings = []; - var holes = []; - var i, ii; - for (i = 0, ii = rings.length; i < ii; ++i) { - var flatRing = goog.array.flatten(rings[i]); - // is this ring an outer ring? is it clockwise? - var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0, - flatRing.length, layout.length); - if (clockwise) { - outerRings.push([rings[i]]); - } else { - holes.push(rings[i]); - } - } - while (holes.length) { - var hole = holes.shift(); - var matched = false; - // loop over all outer rings and see if they contain our hole. - for (i = outerRings.length - 1; i >= 0; i--) { - var outerRing = outerRings[i][0]; - if (ol.extent.containsExtent(new ol.geom.LinearRing( - outerRing).getExtent(), - new ol.geom.LinearRing(hole).getExtent())) { - // the hole is contained push it into our polygon - outerRings[i].push(hole); - matched = true; - break; - } - } - if (!matched) { - // no outer rings contain this hole turn it into and outer - // ring (reverse it) - outerRings.push([hole.reverse()]); - } +ol.format.MVT.prototype.readFeature_ = function( + rawFeature, layer, opt_options) { + var feature = new this.featureClass_(); + var values = rawFeature.properties; + values[this.layerName_] = layer; + var geometry = ol.format.Feature.transformWithOptions( + ol.format.MVT.readGeometry_(rawFeature), false, + this.adaptOptions(opt_options)); + if (geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.Geometry); + values[this.geometryName_] = geometry; } - return outerRings; + feature.setProperties(values); + feature.setGeometryName(this.geometryName_); + return feature; }; /** - * @param {EsriJSONGeometry} object Object. * @private - * @return {ol.geom.Geometry} Point. + * @param {Object} rawFeature Raw Mapbox feature. + * @param {string} layer Layer. + * @return {ol.render.Feature} Feature. */ -ol.format.EsriJSON.readPointGeometry_ = function(object) { - goog.asserts.assert(goog.isNumber(object.x), 'object.x should be number'); - goog.asserts.assert(goog.isNumber(object.y), 'object.y should be number'); - var point; - if (object.m !== undefined && object.z !== undefined) { - point = new ol.geom.Point([object.x, object.y, object.z, object.m], - ol.geom.GeometryLayout.XYZM); - } else if (object.z !== undefined) { - point = new ol.geom.Point([object.x, object.y, object.z], - ol.geom.GeometryLayout.XYZ); - } else if (object.m !== undefined) { - point = new ol.geom.Point([object.x, object.y, object.m], - ol.geom.GeometryLayout.XYM); - } else { - point = new ol.geom.Point([object.x, object.y]); +ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) { + var coords = rawFeature.loadGeometry(); + var ends = []; + var flatCoordinates = []; + ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends); + + var type = rawFeature.type; + /** @type {ol.geom.GeometryType} */ + var geometryType; + if (type === 1) { + geometryType = coords.length === 1 ? + ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT; + } else if (type === 2) { + if (coords.length === 1) { + geometryType = ol.geom.GeometryType.LINE_STRING; + } else { + geometryType = ol.geom.GeometryType.MULTI_LINE_STRING; + } + } else if (type === 3) { + geometryType = ol.geom.GeometryType.POLYGON; } - return point; -}; + var values = rawFeature.properties; + values[this.layerName_] = layer; -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} LineString. - */ -ol.format.EsriJSON.readLineStringGeometry_ = function(object) { - goog.asserts.assert(goog.isArray(object.paths), - 'object.paths should be an array'); - goog.asserts.assert(object.paths.length === 1, - 'object.paths array length should be 1'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.LineString(object.paths[0], layout); + return new this.featureClass_(geometryType, flatCoordinates, ends, values); }; /** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} MultiLineString. + * @inheritDoc */ -ol.format.EsriJSON.readMultiLineStringGeometry_ = function(object) { - goog.asserts.assert(goog.isArray(object.paths), - 'object.paths should be an array'); - goog.asserts.assert(object.paths.length > 1, - 'object.paths array length should be more than 1'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.MultiLineString(object.paths, layout); -}; +ol.format.MVT.prototype.readFeatures = function(source, opt_options) { + goog.asserts.assertInstanceof(source, ArrayBuffer); + var layers = this.layers_; -/** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.GeometryLayout} The geometry layout to use. - */ -ol.format.EsriJSON.getGeometryLayout_ = function(object) { - var layout = ol.geom.GeometryLayout.XY; - if (object.hasZ === true && object.hasM === true) { - layout = ol.geom.GeometryLayout.XYZM; - } else if (object.hasZ === true) { - layout = ol.geom.GeometryLayout.XYZ; - } else if (object.hasM === true) { - layout = ol.geom.GeometryLayout.XYM; + var pbf = new ol.ext.pbf(source); + var tile = new ol.ext.vectortile.VectorTile(pbf); + var features = []; + var featureClass = this.featureClass_; + var layer, feature; + for (var name in tile.layers) { + if (layers && layers.indexOf(name) == -1) { + continue; + } + layer = tile.layers[name]; + + for (var i = 0, ii = layer.length; i < ii; ++i) { + if (featureClass === ol.render.Feature) { + feature = this.readRenderFeature_(layer.feature(i), name); + } else { + feature = this.readFeature_(layer.feature(i), name, opt_options); + } + features.push(feature); + } } - return layout; + + return features; }; /** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} MultiPoint. + * @inheritDoc */ -ol.format.EsriJSON.readMultiPointGeometry_ = function(object) { - goog.asserts.assert(object.points, 'object.points should be defined'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.MultiPoint(object.points, layout); +ol.format.MVT.prototype.readProjection = function(source) { + return this.defaultDataProjection; }; /** - * @param {EsriJSONGeometry} object Object. - * @private - * @return {ol.geom.Geometry} MultiPolygon. + * Sets the layers that features will be read from. + * @param {Array.<string>} layers Layers. + * @api */ -ol.format.EsriJSON.readMultiPolygonGeometry_ = function(object) { - goog.asserts.assert(object.rings); - goog.asserts.assert(object.rings.length > 1, - 'object.rings should have length larger than 1'); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.MultiPolygon( - /** @type {Array.<Array.<Array.<Array.<number>>>>} */(object.rings), - layout); +ol.format.MVT.prototype.setLayers = function(layers) { + this.layers_ = layers; }; /** - * @param {EsriJSONGeometry} object Object. * @private - * @return {ol.geom.Geometry} Polygon. + * @param {Object} coords Raw feature coordinates. + * @param {Array.<number>} flatCoordinates Flat coordinates to be populated by + * this function. + * @param {Array.<number>} ends Ends to be populated by this function. */ -ol.format.EsriJSON.readPolygonGeometry_ = function(object) { - goog.asserts.assert(object.rings); - var layout = ol.format.EsriJSON.getGeometryLayout_(object); - return new ol.geom.Polygon(object.rings, layout); +ol.format.MVT.calculateFlatCoordinates_ = function( + coords, flatCoordinates, ends) { + var end = 0; + var line, coord; + for (var i = 0, ii = coords.length; i < ii; ++i) { + line = coords[i]; + for (var j = 0, jj = line.length; j < jj; ++j) { + coord = line[j]; + // Non-tilespace coords can be calculated here when a TileGrid and + // TileCoord are known. + flatCoordinates.push(coord.x, coord.y); + } + end += 2 * j; + ends.push(end); + } }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. * @private - * @return {EsriJSONGeometry} EsriJSON geometry. + * @param {Object} rawFeature Raw Mapbox feature. + * @return {ol.geom.Geometry} Geometry. */ -ol.format.EsriJSON.writePointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - var coordinates = geometry.getCoordinates(); - var layout = geometry.getLayout(); - if (layout === ol.geom.GeometryLayout.XYZ) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1], - z: coordinates[2] - }); - } else if (layout === ol.geom.GeometryLayout.XYM) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1], - m: coordinates[2] - }); - } else if (layout === ol.geom.GeometryLayout.XYZM) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1], - z: coordinates[2], - m: coordinates[3] - }); - } else if (layout === ol.geom.GeometryLayout.XY) { - return /** @type {EsriJSONPoint} */ ({ - x: coordinates[0], - y: coordinates[1] - }); - } else { - goog.asserts.fail('Unknown geometry layout'); +ol.format.MVT.readGeometry_ = function(rawFeature) { + var type = rawFeature.type; + if (type === 0) { + return null; } -}; + var coords = rawFeature.loadGeometry(); + var ends = []; + var flatCoordinates = []; + ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends); -/** - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @private - * @return {Object} Object with boolean hasZ and hasM keys. - */ -ol.format.EsriJSON.getHasZM_ = function(geometry) { - var layout = geometry.getLayout(); - return { - hasZ: (layout === ol.geom.GeometryLayout.XYZ || - layout === ol.geom.GeometryLayout.XYZM), - hasM: (layout === ol.geom.GeometryLayout.XYM || - layout === ol.geom.GeometryLayout.XYZM) - }; + var geom; + if (type === 1) { + geom = coords.length === 1 ? + new ol.geom.Point(null) : new ol.geom.MultiPoint(null); + } else if (type === 2) { + if (coords.length === 1) { + geom = new ol.geom.LineString(null); + } else { + geom = new ol.geom.MultiLineString(null); + } + } else if (type === 3) { + geom = new ol.geom.Polygon(null); + } + + geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, + ends); + + return geom; }; +// FIXME add typedef for stack state objects +goog.provide('ol.format.OSMXML'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol.Feature'); +goog.require('ol.format.Feature'); +goog.require('ol.format.XMLFeature'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONPolyline} EsriJSON geometry. + * @classdesc + * Feature format for reading data in the + * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML). + * + * @constructor + * @extends {ol.format.XMLFeature} + * @api stable */ -ol.format.EsriJSON.writeLineStringGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONPolyline} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - paths: [geometry.getCoordinates()] - }); +ol.format.OSMXML = function() { + goog.base(this); + + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); }; +goog.inherits(ol.format.OSMXML, ol.format.XMLFeature); /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. + * @const + * @type {Array.<string>} * @private - * @return {EsriJSONPolygon} EsriJSON geometry. */ -ol.format.EsriJSON.writePolygonGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - // Esri geometries use the left-hand rule - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONPolygon} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - rings: geometry.getCoordinates(false) - }); -}; +ol.format.OSMXML.EXTENSIONS_ = ['.osm']; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONPolyline} EsriJSON geometry. + * @inheritDoc */ -ol.format.EsriJSON.writeMultiLineStringGeometry_ = - function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONPolyline} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - paths: geometry.getCoordinates() - }); +ol.format.OSMXML.prototype.getExtensions = function() { + return ol.format.OSMXML.EXTENSIONS_; }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private - * @return {EsriJSONMultipoint} EsriJSON geometry. */ -ol.format.EsriJSON.writeMultiPointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, - 'geometry should be an ol.geom.MultiPoint'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - return /** @type {EsriJSONMultipoint} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - points: geometry.getCoordinates() - }); +ol.format.OSMXML.readNode_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'node', 'localName should be node'); + var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); + var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var id = node.getAttribute('id'); + var coordinates = /** @type {Array.<number>} */ ([ + parseFloat(node.getAttribute('lon')), + parseFloat(node.getAttribute('lat')) + ]); + state.nodes[id] = coordinates; + + var values = ol.xml.pushParseAndPop({ + tags: {} + }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack); + if (!goog.object.isEmpty(values.tags)) { + var geometry = new ol.geom.Point(coordinates); + ol.format.Feature.transformWithOptions(geometry, false, options); + var feature = new ol.Feature(geometry); + feature.setId(id); + feature.setProperties(values.tags); + state.features.push(feature); + } }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private - * @return {EsriJSONPolygon} EsriJSON geometry. */ -ol.format.EsriJSON.writeMultiPolygonGeometry_ = function(geometry, - opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, - 'geometry should be an ol.geom.MultiPolygon'); - var hasZM = ol.format.EsriJSON.getHasZM_(geometry); - var coordinates = geometry.getCoordinates(false); - var output = []; - for (var i = 0; i < coordinates.length; i++) { - for (var x = coordinates[i].length - 1; x >= 0; x--) { - output.push(coordinates[i][x]); - } +ol.format.OSMXML.readWay_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'way', 'localName should be way'); + var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); + var id = node.getAttribute('id'); + var values = ol.xml.pushParseAndPop({ + ndrefs: [], + tags: {} + }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack); + var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var flatCoordinates = /** @type {Array.<number>} */ ([]); + for (var i = 0, ii = values.ndrefs.length; i < ii; i++) { + var point = state.nodes[values.ndrefs[i]]; + goog.array.extend(flatCoordinates, point); } - return /** @type {EsriJSONPolygon} */ ({ - hasZ: hasZM.hasZ, - hasM: hasZM.hasM, - rings: output - }); + var geometry; + if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) { + // closed way + geometry = new ol.geom.Polygon(null); + geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, + [flatCoordinates.length]); + } else { + geometry = new ol.geom.LineString(null); + geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); + } + ol.format.Feature.transformWithOptions(geometry, false, options); + var feature = new ol.Feature(geometry); + feature.setId(id); + feature.setProperties(values.tags); + state.features.push(feature); }; /** - * @const + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private - * @type {Object.<ol.geom.GeometryType, function(EsriJSONGeometry): ol.geom.Geometry>} + * @return {ol.Feature|undefined} Track. */ -ol.format.EsriJSON.GEOMETRY_READERS_ = {}; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POINT] = - ol.format.EsriJSON.readPointGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.LINE_STRING] = - ol.format.EsriJSON.readLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POLYGON] = - ol.format.EsriJSON.readPolygonGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POINT] = - ol.format.EsriJSON.readMultiPointGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_LINE_STRING] = - ol.format.EsriJSON.readMultiLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POLYGON] = - ol.format.EsriJSON.readMultiPolygonGeometry_; +ol.format.OSMXML.readNd_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'nd', 'localName should be nd'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + values.ndrefs.push(node.getAttribute('ref')); +}; /** - * @const + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private - * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (EsriJSONGeometry)>} + * @return {ol.Feature|undefined} Track. */ -ol.format.EsriJSON.GEOMETRY_WRITERS_ = {}; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POINT] = - ol.format.EsriJSON.writePointGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.LINE_STRING] = - ol.format.EsriJSON.writeLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POLYGON] = - ol.format.EsriJSON.writePolygonGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POINT] = - ol.format.EsriJSON.writeMultiPointGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_LINE_STRING] = - ol.format.EsriJSON.writeMultiLineStringGeometry_; -ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POLYGON] = - ol.format.EsriJSON.writeMultiPolygonGeometry_; +ol.format.OSMXML.readTag_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'tag', 'localName should be tag'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + values.tags[node.getAttribute('k')] = node.getAttribute('v'); +}; /** - * Read a feature from a EsriJSON Feature source. Only works for Feature, - * use `readFeatures` to read FeatureCollection source. - * - * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api + * @const + * @private + * @type {Array.<string>} */ -ol.format.EsriJSON.prototype.readFeature; +ol.format.OSMXML.NAMESPACE_URIS_ = [ + null +]; /** - * Read all features from a EsriJSON source. Works with both Feature and - * FeatureCollection sources. - * - * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.format.EsriJSON.prototype.readFeatures; +ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OSMXML.NAMESPACE_URIS_, { + 'nd': ol.format.OSMXML.readNd_, + 'tag': ol.format.OSMXML.readTag_ + }); /** - * @inheritDoc + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.format.EsriJSON.prototype.readFeatureFromObject = function( - object, opt_options) { - var esriJSONFeature = /** @type {EsriJSONFeature} */ (object); - goog.asserts.assert(esriJSONFeature.geometry || - esriJSONFeature.attributes, - 'geometry or attributes should be defined'); - var geometry = ol.format.EsriJSON.readGeometry_(esriJSONFeature.geometry, - opt_options); - var feature = new ol.Feature(); - if (this.geometryName_) { - feature.setGeometryName(this.geometryName_); - } - feature.setGeometry(geometry); - if (opt_options && opt_options.idField && - esriJSONFeature.attributes[opt_options.idField]) { - goog.asserts.assert( - goog.isNumber(esriJSONFeature.attributes[opt_options.idField]), - 'objectIdFieldName value should be a number'); - feature.setId(/** @type {number} */( - esriJSONFeature.attributes[opt_options.idField])); - } - if (esriJSONFeature.attributes) { - feature.setProperties(esriJSONFeature.attributes); - } - return feature; -}; +ol.format.OSMXML.PARSERS_ = ol.xml.makeStructureNS( + ol.format.OSMXML.NAMESPACE_URIS_, { + 'node': ol.format.OSMXML.readNode_, + 'way': ol.format.OSMXML.readWay_ + }); /** - * @inheritDoc + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.format.EsriJSON.prototype.readFeaturesFromObject = function( - object, opt_options) { - var esriJSONObject = /** @type {EsriJSONObject} */ (object); - var options = opt_options ? opt_options : {}; - if (esriJSONObject.features) { - var esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */ - (object); - /** @type {Array.<ol.Feature>} */ - var features = []; - var esriJSONFeatures = esriJSONFeatureCollection.features; - var i, ii; - options.idField = object.objectIdFieldName; - for (i = 0, ii = esriJSONFeatures.length; i < ii; ++i) { - features.push(this.readFeatureFromObject(esriJSONFeatures[i], - options)); - } - return features; - } else { - return [this.readFeatureFromObject(object, options)]; - } -}; +ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OSMXML.NAMESPACE_URIS_, { + 'tag': ol.format.OSMXML.readTag_ + }); /** - * Read a geometry from a EsriJSON source. + * Read all features from an OSM source. * * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @param {Document|Node|Object|string} source Source. * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api + * @return {Array.<ol.Feature>} Features. + * @api stable */ -ol.format.EsriJSON.prototype.readGeometry; +ol.format.OSMXML.prototype.readFeatures; /** * @inheritDoc */ -ol.format.EsriJSON.prototype.readGeometryFromObject = function( - object, opt_options) { - return ol.format.EsriJSON.readGeometry_( - /** @type {EsriJSONGeometry} */ (object), opt_options); +ol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + var options = this.getReadOptions(node, opt_options); + if (node.localName == 'osm') { + var state = ol.xml.pushParseAndPop({ + nodes: {}, + features: [] + }, ol.format.OSMXML.PARSERS_, node, [options]); + if (state.features) { + return state.features; + } + } + return []; }; /** - * Read the projection from a EsriJSON source. + * Read the projection from an OSM source. * * @function - * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @param {Document|Node|Object|string} source Source. * @return {ol.proj.Projection} Projection. - * @api + * @api stable */ -ol.format.EsriJSON.prototype.readProjection; +ol.format.OSMXML.prototype.readProjection; + +goog.provide('ol.format.XLink'); /** - * @inheritDoc + * @const + * @type {string} */ -ol.format.EsriJSON.prototype.readProjectionFromObject = function(object) { - var esriJSONObject = /** @type {EsriJSONObject} */ (object); - if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) { - var crs = esriJSONObject.spatialReference.wkid; - return ol.proj.get('EPSG:' + crs); - } else { - return null; - } -}; +ol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink'; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {EsriJSONGeometry} EsriJSON geometry. + * @param {Node} node Node. + * @return {boolean|undefined} Boolean. */ -ol.format.EsriJSON.writeGeometry_ = function(geometry, opt_options) { - var geometryWriter = ol.format.EsriJSON.GEOMETRY_WRITERS_[geometry.getType()]; - goog.asserts.assert(geometryWriter, 'geometryWriter should be defined'); - return geometryWriter(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, true, opt_options)), - opt_options); +ol.format.XLink.readHref = function(node) { + return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href'); }; +goog.provide('ol.format.XML'); -/** - * Encode a geometry as a EsriJSON string. - * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} EsriJSON. - * @api - */ -ol.format.EsriJSON.prototype.writeGeometry; - +goog.require('goog.asserts'); +goog.require('ol.xml'); -/** - * Encode a geometry as a EsriJSON object. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {EsriJSONGeometry} Object. - * @api - */ -ol.format.EsriJSON.prototype.writeGeometryObject = function(geometry, - opt_options) { - return ol.format.EsriJSON.writeGeometry_(geometry, - this.adaptOptions(opt_options)); -}; /** - * Encode a feature as a EsriJSON Feature string. + * @classdesc + * Generic format for reading non-feature XML data * - * @function - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} EsriJSON. - * @api + * @constructor */ -ol.format.EsriJSON.prototype.writeFeature; +ol.format.XML = function() { +}; /** - * Encode a feature as a esriJSON Feature object. - * - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. - * @api + * @param {Document|Node|string} source Source. + * @return {Object} */ -ol.format.EsriJSON.prototype.writeFeatureObject = function( - feature, opt_options) { - opt_options = this.adaptOptions(opt_options); - var object = {}; - var geometry = feature.getGeometry(); - if (geometry) { - object['geometry'] = - ol.format.EsriJSON.writeGeometry_(geometry, opt_options); - } - var properties = feature.getProperties(); - delete properties[feature.getGeometryName()]; - if (!goog.object.isEmpty(properties)) { - object['attributes'] = properties; +ol.format.XML.prototype.read = function(source) { + if (ol.xml.isDocument(source)) { + return this.readFromDocument(/** @type {Document} */ (source)); + } else if (ol.xml.isNode(source)) { + return this.readFromNode(/** @type {Node} */ (source)); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readFromDocument(doc); } else { - object['attributes'] = {}; - } - if (opt_options && opt_options.featureProjection) { - object['spatialReference'] = /** @type {EsriJSONCRS} */({ - wkid: ol.proj.get( - opt_options.featureProjection).getCode().split(':').pop() - }); + goog.asserts.fail(); + return null; } - return object; }; /** - * Encode an array of features as EsriJSON. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} EsriJSON. - * @api + * @param {Document} doc Document. + * @return {Object} */ -ol.format.EsriJSON.prototype.writeFeatures; +ol.format.XML.prototype.readFromDocument = goog.abstractMethod; /** - * Encode an array of features as a EsriJSON object. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} EsriJSON Object. - * @api + * @param {Node} node Node. + * @return {Object} */ -ol.format.EsriJSON.prototype.writeFeaturesObject = - function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var objects = []; - var i, ii; - for (i = 0, ii = features.length; i < ii; ++i) { - objects.push(this.writeFeatureObject(features[i], opt_options)); - } - return /** @type {EsriJSONFeatureCollection} */ ({ - 'features': objects - }); -}; +ol.format.XML.prototype.readFromNode = goog.abstractMethod; -goog.provide('ol.geom.GeometryCollection'); +goog.provide('ol.format.OWS'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryType'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('ol.format.XLink'); +goog.require('ol.format.XML'); +goog.require('ol.format.XSD'); +goog.require('ol.xml'); /** - * @classdesc - * An array of {@link ol.geom.Geometry} objects. - * * @constructor - * @extends {ol.geom.Geometry} - * @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries. - * @api stable + * @extends {ol.format.XML} */ -ol.geom.GeometryCollection = function(opt_geometries) { - +ol.format.OWS = function() { goog.base(this); +}; +goog.inherits(ol.format.OWS, ol.format.XML); - /** - * @private - * @type {Array.<ol.geom.Geometry>} - */ - this.geometries_ = opt_geometries ? opt_geometries : null; - this.listenGeometriesChange_(); +/** + * @param {Document} doc Document. + * @return {Object} OWS object. + */ +ol.format.OWS.prototype.readFromDocument = function(doc) { + goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, + 'doc.nodeType should be DOCUMENT'); + for (var n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + return this.readFromNode(n); + } + } + return null; }; -goog.inherits(ol.geom.GeometryCollection, ol.geom.Geometry); /** - * @param {Array.<ol.geom.Geometry>} geometries Geometries. + * @param {Node} node Node. + * @return {Object} OWS object. + */ +ol.format.OWS.prototype.readFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + var owsObject = ol.xml.pushParseAndPop({}, + ol.format.OWS.PARSERS_, node, []); + return owsObject ? owsObject : null; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private - * @return {Array.<ol.geom.Geometry>} Cloned geometries. + * @return {Object|undefined} */ -ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) { - var clonedGeometries = []; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - clonedGeometries.push(geometries[i].clone()); - } - return clonedGeometries; +ol.format.OWS.readAddress_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Address', + 'localName should be Address'); + return ol.xml.pushParseAndPop({}, + ol.format.OWS.ADDRESS_PARSERS_, node, objectStack); }; /** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() { - var i, ii; - if (!this.geometries_) { - return; - } - for (i = 0, ii = this.geometries_.length; i < ii; ++i) { - goog.events.unlisten( - this.geometries_[i], goog.events.EventType.CHANGE, - this.changed, false, this); - } +ol.format.OWS.readAllowedValues_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'AllowedValues', + 'localName should be AllowedValues'); + return ol.xml.pushParseAndPop({}, + ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack); }; /** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() { - var i, ii; - if (!this.geometries_) { - return; - } - for (i = 0, ii = this.geometries_.length; i < ii; ++i) { - goog.events.listen( - this.geometries_[i], goog.events.EventType.CHANGE, - this.changed, false, this); +ol.format.OWS.readConstraint_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Constraint', + 'localName should be Constraint'); + var name = node.getAttribute('name'); + if (!name) { + return undefined; } + return ol.xml.pushParseAndPop({'name': name}, + ol.format.OWS.CONSTRAINT_PARSERS_, node, + objectStack); }; /** - * Make a complete copy of the geometry. - * @return {!ol.geom.GeometryCollection} Clone. - * @api stable + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.clone = function() { - var geometryCollection = new ol.geom.GeometryCollection(null); - geometryCollection.setGeometries(this.geometries_); - return geometryCollection; +ol.format.OWS.readContactInfo_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ContactInfo', + 'localName should be ContactInfo'); + return ol.xml.pushParseAndPop({}, + ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack); }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - if (minSquaredDistance < - ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { - return minSquaredDistance; - } - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - minSquaredDistance = geometries[i].closestPointXY( - x, y, closestPoint, minSquaredDistance); - } - return minSquaredDistance; +ol.format.OWS.readDcp_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'DCP', 'localName should be DCP'); + return ol.xml.pushParseAndPop({}, + ol.format.OWS.DCP_PARSERS_, node, objectStack); }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.containsXY = function(x, y) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - if (geometries[i].containsXY(x, y)) { - return true; - } +ol.format.OWS.readGet_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Get', 'localName should be Get'); + var href = ol.format.XLink.readHref(node); + if (!href) { + return undefined; } - return false; + return ol.xml.pushParseAndPop({'href': href}, + ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack); }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.computeExtent = function(extent) { - ol.extent.createOrUpdateEmpty(extent); - var geometries = this.geometries_; - for (var i = 0, ii = geometries.length; i < ii; ++i) { - ol.extent.extend(extent, geometries[i].getExtent()); - } - return extent; +ol.format.OWS.readHttp_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP'); + return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_, + node, objectStack); }; /** - * Return the geometries that make up this geometry collection. - * @return {Array.<ol.geom.Geometry>} Geometries. - * @api stable + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.getGeometries = function() { - return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_); +ol.format.OWS.readOperation_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Operation', + 'localName should be Operation'); + var name = node.getAttribute('name'); + var value = ol.xml.pushParseAndPop({}, + ol.format.OWS.OPERATION_PARSERS_, node, objectStack); + if (!value) { + return undefined; + } + var object = /** @type {Object} */ + (objectStack[objectStack.length - 1]); + goog.asserts.assert(goog.isObject(object), 'object should be an Object'); + object[name] = value; + }; /** - * @return {Array.<ol.geom.Geometry>} Geometries. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.getGeometriesArray = function() { - return this.geometries_; +ol.format.OWS.readOperationsMetadata_ = function(node, + objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'OperationsMetadata', + 'localName should be OperationsMetadata'); + return ol.xml.pushParseAndPop({}, + ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node, + objectStack); }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.getSimplifiedGeometry = - function(squaredTolerance) { - if (this.simplifiedGeometryRevision != this.getRevision()) { - goog.object.clear(this.simplifiedGeometryCache); - this.simplifiedGeometryMaxMinSquaredTolerance = 0; - this.simplifiedGeometryRevision = this.getRevision(); - } - if (squaredTolerance < 0 || - (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && - squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) { - return this; - } - var key = squaredTolerance.toString(); - if (this.simplifiedGeometryCache.hasOwnProperty(key)) { - return this.simplifiedGeometryCache[key]; - } else { - var simplifiedGeometries = []; - var geometries = this.geometries_; - var simplified = false; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - var geometry = geometries[i]; - var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); - simplifiedGeometries.push(simplifiedGeometry); - if (simplifiedGeometry !== geometry) { - simplified = true; - } - } - if (simplified) { - var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null); - simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries); - this.simplifiedGeometryCache[key] = simplifiedGeometryCollection; - return simplifiedGeometryCollection; - } else { - this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; - return this; - } - } +ol.format.OWS.readPhone_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Phone', 'localName should be Phone'); + return ol.xml.pushParseAndPop({}, + ol.format.OWS.PHONE_PARSERS_, node, objectStack); }; /** - * @inheritDoc - * @api stable + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.getType = function() { - return ol.geom.GeometryType.GEOMETRY_COLLECTION; +ol.format.OWS.readServiceIdentification_ = function(node, + objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ServiceIdentification', + 'localName should be ServiceIdentification'); + return ol.xml.pushParseAndPop( + {}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node, + objectStack); }; /** - * @inheritDoc - * @api stable + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - if (geometries[i].intersectsExtent(extent)) { - return true; - } - } - return false; +ol.format.OWS.readServiceContact_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ServiceContact', + 'localName should be ServiceContact'); + return ol.xml.pushParseAndPop( + {}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node, + objectStack); }; /** - * @return {boolean} Is empty. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} */ -ol.geom.GeometryCollection.prototype.isEmpty = function() { - return this.geometries_.length === 0; +ol.format.OWS.readServiceProvider_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ServiceProvider', + 'localName should be ServiceProvider'); + return ol.xml.pushParseAndPop( + {}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node, + objectStack); }; /** - * Set the geometries that make up this geometry collection. - * @param {Array.<ol.geom.Geometry>} geometries Geometries. - * @api stable + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {string|undefined} */ -ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) { - this.setGeometriesArray( - ol.geom.GeometryCollection.cloneGeometries_(geometries)); +ol.format.OWS.readValue_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Value', 'localName should be Value'); + return ol.format.XSD.readString(node); }; /** - * @param {Array.<ol.geom.Geometry>} geometries Geometries. + * @const + * @type {Array.<string>} + * @private */ -ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) { - this.unlistenGeometriesChange_(); - this.geometries_ = geometries; - this.listenGeometriesChange_(); - this.changed(); -}; +ol.format.OWS.NAMESPACE_URIS_ = [ + null, + 'http://www.opengis.net/ows/1.1' +]; /** - * @inheritDoc - * @api stable + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - geometries[i].applyTransform(transformFn); - } - this.changed(); -}; +ol.format.OWS.PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'ServiceIdentification': ol.xml.makeObjectPropertySetter( + ol.format.OWS.readServiceIdentification_), + 'ServiceProvider': ol.xml.makeObjectPropertySetter( + ol.format.OWS.readServiceProvider_), + 'OperationsMetadata': ol.xml.makeObjectPropertySetter( + ol.format.OWS.readOperationsMetadata_) + }); /** - * Translate the geometry. - * @param {number} deltaX Delta X. - * @param {number} deltaY Delta Y. - * @api + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) { - var geometries = this.geometries_; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - geometries[i].translate(deltaX, deltaY); - } - this.changed(); -}; +ol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'DeliveryPoint': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'AdministrativeArea': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'ElectronicMailAddress': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + }); /** - * @inheritDoc + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.geom.GeometryCollection.prototype.disposeInternal = function() { - this.unlistenGeometriesChange_(); - goog.base(this, 'disposeInternal'); -}; +ol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_) + }); -// TODO: serialize dataProjection as crs member when writing -// see https://github.com/openlayers/ol3/issues/2078 -goog.provide('ol.format.GeoJSON'); +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'AllowedValues': ol.xml.makeObjectPropertySetter( + ol.format.OWS.readAllowedValues_) + }); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.JSONFeature'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_), + 'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_) + }); /** - * @classdesc - * Feature format for reading and writing data in the GeoJSON format. - * - * @constructor - * @extends {ol.format.JSONFeature} - * @param {olx.format.GeoJSONOptions=} opt_options Options. - * @api stable + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private */ -ol.format.GeoJSON = function(opt_options) { +ol.format.OWS.DCP_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_) + }); - var options = opt_options ? opt_options : {}; - goog.base(this); +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.OWS.HTTP_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_), + 'Post': undefined // TODO + }); - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get( - options.defaultDataProjection ? - options.defaultDataProjection : 'EPSG:4326'); +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_) + }); - /** - * Name of the geometry attribute for features. - * @type {string|undefined} - * @private - */ - this.geometryName_ = options.geometryName; -}; -goog.inherits(ol.format.GeoJSON, ol.format.JSONFeature); +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Operation': ol.format.OWS.readOperation_ + }); /** * @const - * @type {Array.<string>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GeoJSON.EXTENSIONS_ = ['.geojson']; +ol.format.OWS.PHONE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) + }); /** - * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private - * @return {ol.geom.Geometry} Geometry. */ -ol.format.GeoJSON.readGeometry_ = function(object, opt_options) { - if (!object) { - return null; - } - var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type]; - goog.asserts.assert(geometryReader, 'geometryReader should be defined'); - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions( - geometryReader(object), false, opt_options)); -}; +ol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Constraint': ol.xml.makeObjectPropertyPusher( + ol.format.OWS.readConstraint_) + }); /** - * @param {GeoJSONGeometryCollection} object Object. - * @param {olx.format.ReadOptions=} opt_options Read options. + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private - * @return {ol.geom.GeometryCollection} Geometry collection. */ -ol.format.GeoJSON.readGeometryCollectionGeometry_ = function( - object, opt_options) { - goog.asserts.assert(object.type == 'GeometryCollection', - 'object.type should be GeometryCollection'); - var geometries = object.geometries.map( - /** - * @param {GeoJSONGeometry} geometry Geometry. - * @return {ol.geom.Geometry} geometry Geometry. - */ - function(geometry) { - return ol.format.GeoJSON.readGeometry_(geometry, opt_options); - }); - return new ol.geom.GeometryCollection(geometries); -}; +ol.format.OWS.SERVICE_CONTACT_PARSERS_ = + ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'IndividualName': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'ContactInfo': ol.xml.makeObjectPropertySetter( + ol.format.OWS.readContactInfo_) + }); /** - * @param {GeoJSONGeometry} object Object. + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private - * @return {ol.geom.Point} Point. */ -ol.format.GeoJSON.readPointGeometry_ = function(object) { - goog.asserts.assert(object.type == 'Point', - 'object.type should be Point'); - return new ol.geom.Point(object.coordinates); -}; +ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ = + ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'ServiceTypeVersion': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) + }); /** - * @param {GeoJSONGeometry} object Object. + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private - * @return {ol.geom.LineString} LineString. */ -ol.format.GeoJSON.readLineStringGeometry_ = function(object) { - goog.asserts.assert(object.type == 'LineString', - 'object.type should be LineString'); - return new ol.geom.LineString(object.coordinates); -}; +ol.format.OWS.SERVICE_PROVIDER_PARSERS_ = + ol.xml.makeStructureNS( + ol.format.OWS.NAMESPACE_URIS_, { + 'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref), + 'ServiceContact': ol.xml.makeObjectPropertySetter( + ol.format.OWS.readServiceContact_) + }); + +goog.provide('ol.geom.flat.flip'); + +goog.require('goog.asserts'); /** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.MultiLineString} MultiLineString. + * @param {Array.<number>} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {Array.<number>=} opt_dest Destination. + * @param {number=} opt_destOffset Destination offset. + * @return {Array.<number>} Flat coordinates. */ -ol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) { - goog.asserts.assert(object.type == 'MultiLineString', - 'object.type should be MultiLineString'); - return new ol.geom.MultiLineString(object.coordinates); +ol.geom.flat.flip.flipXY = + function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) { + var dest, destOffset; + if (opt_dest !== undefined) { + dest = opt_dest; + destOffset = opt_destOffset !== undefined ? opt_destOffset : 0; + } else { + goog.asserts.assert(opt_destOffset === undefined, + 'opt_destOffSet should be defined'); + dest = []; + destOffset = 0; + } + var j, k; + for (j = offset; j < end; ) { + var x = flatCoordinates[j++]; + dest[destOffset++] = flatCoordinates[j++]; + dest[destOffset++] = x; + for (k = 2; k < stride; ++k) { + dest[destOffset++] = flatCoordinates[j++]; + } + } + dest.length = destOffset; + return dest; }; +goog.provide('ol.format.Polyline'); + +goog.require('goog.asserts'); +goog.require('ol.Feature'); +goog.require('ol.format.Feature'); +goog.require('ol.format.TextFeature'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.flip'); +goog.require('ol.geom.flat.inflate'); +goog.require('ol.proj'); + + /** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.MultiPoint} MultiPoint. + * @classdesc + * Feature format for reading and writing data in the Encoded + * Polyline Algorithm Format. + * + * @constructor + * @extends {ol.format.TextFeature} + * @param {olx.format.PolylineOptions=} opt_options + * Optional configuration object. + * @api stable */ -ol.format.GeoJSON.readMultiPointGeometry_ = function(object) { - goog.asserts.assert(object.type == 'MultiPoint', - 'object.type should be MultiPoint'); - return new ol.geom.MultiPoint(object.coordinates); -}; +ol.format.Polyline = function(opt_options) { + + var options = opt_options ? opt_options : {}; + goog.base(this); -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.MultiPolygon} MultiPolygon. - */ -ol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) { - goog.asserts.assert(object.type == 'MultiPolygon', - 'object.type should be MultiPolygon'); - return new ol.geom.MultiPolygon(object.coordinates); -}; + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + /** + * @private + * @type {number} + */ + this.factor_ = options.factor ? options.factor : 1e5; -/** - * @param {GeoJSONGeometry} object Object. - * @private - * @return {ol.geom.Polygon} Polygon. - */ -ol.format.GeoJSON.readPolygonGeometry_ = function(object) { - goog.asserts.assert(object.type == 'Polygon', - 'object.type should be Polygon'); - return new ol.geom.Polygon(object.coordinates); + /** + * @private + * @type {ol.geom.GeometryLayout} + */ + this.geometryLayout_ = options.geometryLayout ? + options.geometryLayout : ol.geom.GeometryLayout.XY; }; +goog.inherits(ol.format.Polyline, ol.format.TextFeature); /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry. + * Encode a list of n-dimensional points and return an encoded string + * + * Attention: This function will modify the passed array! + * + * @param {Array.<number>} numbers A list of n-dimensional points. + * @param {number} stride The number of dimension of the points in the list. + * @param {number=} opt_factor The factor by which the numbers will be + * multiplied. The remaining decimal places will get rounded away. + * Default is `1e5`. + * @return {string} The encoded string. + * @api */ -ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) { - var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()]; - goog.asserts.assert(geometryWriter, 'geometryWriter should be defined'); - return geometryWriter(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, true, opt_options)), - opt_options); -}; +ol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) { + var factor = opt_factor ? opt_factor : 1e5; + var d; + var lastNumbers = new Array(stride); + for (d = 0; d < stride; ++d) { + lastNumbers[d] = 0; + } -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @private - * @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection. - */ -ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) { - return /** @type {GeoJSONGeometryCollection} */ ({ - type: 'GeometryCollection', - geometries: [] - }); -}; + var i, ii; + for (i = 0, ii = numbers.length; i < ii;) { + for (d = 0; d < stride; ++d, ++i) { + var num = numbers[i]; + var delta = num - lastNumbers[d]; + lastNumbers[d] = num; + numbers[i] = delta; + } + } -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometryCollection} GeoJSON geometry collection. - */ -ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function( - geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection, - 'geometry should be an ol.geom.GeometryCollection'); - var geometries = geometry.getGeometriesArray().map(function(geometry) { - return ol.format.GeoJSON.writeGeometry_(geometry, opt_options); - }); - return /** @type {GeoJSONGeometryCollection} */ ({ - type: 'GeometryCollection', - geometries: geometries - }); + return ol.format.Polyline.encodeFloats(numbers, factor); }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. + * Decode a list of n-dimensional points from an encoded string + * + * @param {string} encoded An encoded string. + * @param {number} stride The number of dimension of the points in the + * encoded string. + * @param {number=} opt_factor The factor by which the resulting numbers will + * be divided. Default is `1e5`. + * @return {Array.<number>} A list of n-dimensional points. + * @api */ -ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'LineString', - coordinates: geometry.getCoordinates() - }); -}; +ol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) { + var factor = opt_factor ? opt_factor : 1e5; + var d; + /** @type {Array.<number>} */ + var lastNumbers = new Array(stride); + for (d = 0; d < stride; ++d) { + lastNumbers[d] = 0; + } -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writeMultiLineStringGeometry_ = - function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'MultiLineString', - coordinates: geometry.getCoordinates() - }); -}; + var numbers = ol.format.Polyline.decodeFloats(encoded, factor); + var i, ii; + for (i = 0, ii = numbers.length; i < ii;) { + for (d = 0; d < stride; ++d, ++i) { + lastNumbers[d] += numbers[i]; -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. - */ -ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, - 'geometry should be an ol.geom.MultiPoint'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'MultiPoint', - coordinates: geometry.getCoordinates() - }); + numbers[i] = lastNumbers[d]; + } + } + + return numbers; }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. + * Encode a list of floating point numbers and return an encoded string + * + * Attention: This function will modify the passed array! + * + * @param {Array.<number>} numbers A list of floating point numbers. + * @param {number=} opt_factor The factor by which the numbers will be + * multiplied. The remaining decimal places will get rounded away. + * Default is `1e5`. + * @return {string} The encoded string. + * @api */ -ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, - 'geometry should be an ol.geom.MultiPolygon'); - var right; - if (opt_options) { - right = opt_options.rightHanded; +ol.format.Polyline.encodeFloats = function(numbers, opt_factor) { + var factor = opt_factor ? opt_factor : 1e5; + var i, ii; + for (i = 0, ii = numbers.length; i < ii; ++i) { + numbers[i] = Math.round(numbers[i] * factor); } - return /** @type {GeoJSONGeometry} */ ({ - type: 'MultiPolygon', - coordinates: geometry.getCoordinates(right) - }); + + return ol.format.Polyline.encodeSignedIntegers(numbers); }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. + * Decode a list of floating point numbers from an encoded string + * + * @param {string} encoded An encoded string. + * @param {number=} opt_factor The factor by which the result will be divided. + * Default is `1e5`. + * @return {Array.<number>} A list of floating point numbers. + * @api */ -ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - return /** @type {GeoJSONGeometry} */ ({ - type: 'Point', - coordinates: geometry.getCoordinates() - }); +ol.format.Polyline.decodeFloats = function(encoded, opt_factor) { + var factor = opt_factor ? opt_factor : 1e5; + var numbers = ol.format.Polyline.decodeSignedIntegers(encoded); + var i, ii; + for (i = 0, ii = numbers.length; i < ii; ++i) { + numbers[i] /= factor; + } + return numbers; }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @private - * @return {GeoJSONGeometry} GeoJSON geometry. + * Encode a list of signed integers and return an encoded string + * + * Attention: This function will modify the passed array! + * + * @param {Array.<number>} numbers A list of signed integers. + * @return {string} The encoded string. */ -ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - var right; - if (opt_options) { - right = opt_options.rightHanded; +ol.format.Polyline.encodeSignedIntegers = function(numbers) { + var i, ii; + for (i = 0, ii = numbers.length; i < ii; ++i) { + var num = numbers[i]; + numbers[i] = (num < 0) ? ~(num << 1) : (num << 1); } - return /** @type {GeoJSONGeometry} */ ({ - type: 'Polygon', - coordinates: geometry.getCoordinates(right) - }); + return ol.format.Polyline.encodeUnsignedIntegers(numbers); }; /** - * @const - * @private - * @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>} + * Decode a list of signed integers from an encoded string + * + * @param {string} encoded An encoded string. + * @return {Array.<number>} A list of signed integers. */ -ol.format.GeoJSON.GEOMETRY_READERS_ = { - 'Point': ol.format.GeoJSON.readPointGeometry_, - 'LineString': ol.format.GeoJSON.readLineStringGeometry_, - 'Polygon': ol.format.GeoJSON.readPolygonGeometry_, - 'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_, - 'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_, - 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_, - 'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_ +ol.format.Polyline.decodeSignedIntegers = function(encoded) { + var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded); + var i, ii; + for (i = 0, ii = numbers.length; i < ii; ++i) { + var num = numbers[i]; + numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); + } + return numbers; }; /** - * @const - * @private - * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>} + * Encode a list of unsigned integers and return an encoded string + * + * @param {Array.<number>} numbers A list of unsigned integers. + * @return {string} The encoded string. */ -ol.format.GeoJSON.GEOMETRY_WRITERS_ = { - 'Point': ol.format.GeoJSON.writePointGeometry_, - 'LineString': ol.format.GeoJSON.writeLineStringGeometry_, - 'Polygon': ol.format.GeoJSON.writePolygonGeometry_, - 'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_, - 'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_, - 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_, - 'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_, - 'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ +ol.format.Polyline.encodeUnsignedIntegers = function(numbers) { + var encoded = ''; + var i, ii; + for (i = 0, ii = numbers.length; i < ii; ++i) { + encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]); + } + return encoded; }; /** - * @inheritDoc + * Decode a list of unsigned integers from an encoded string + * + * @param {string} encoded An encoded string. + * @return {Array.<number>} A list of unsigned integers. */ -ol.format.GeoJSON.prototype.getExtensions = function() { - return ol.format.GeoJSON.EXTENSIONS_; +ol.format.Polyline.decodeUnsignedIntegers = function(encoded) { + var numbers = []; + var current = 0; + var shift = 0; + var i, ii; + for (i = 0, ii = encoded.length; i < ii; ++i) { + var b = encoded.charCodeAt(i) - 63; + current |= (b & 0x1f) << shift; + if (b < 0x20) { + numbers.push(current); + current = 0; + shift = 0; + } else { + shift += 5; + } + } + return numbers; }; /** - * Read a feature from a GeoJSON Feature source. Only works for Feature, - * use `readFeatures` to read FeatureCollection source. + * Encode one single unsigned integer and return an encoded string * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable + * @param {number} num Unsigned integer that should be encoded. + * @return {string} The encoded string. */ -ol.format.GeoJSON.prototype.readFeature; +ol.format.Polyline.encodeUnsignedInteger = function(num) { + var value, encoded = ''; + while (num >= 0x20) { + value = (0x20 | (num & 0x1f)) + 63; + encoded += String.fromCharCode(value); + num >>= 5; + } + value = num + 63; + encoded += String.fromCharCode(value); + return encoded; +}; /** - * Read all features from a GeoJSON source. Works with both Feature and - * FeatureCollection sources. + * Read the feature from the Polyline source. The coordinates are assumed to be + * in two dimensions and in latitude, longitude order. * * @function * @param {Document|Node|Object|string} source Source. * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. + * @return {ol.Feature} Feature. * @api stable */ -ol.format.GeoJSON.prototype.readFeatures; - - -/** - * @inheritDoc - */ -ol.format.GeoJSON.prototype.readFeatureFromObject = function( - object, opt_options) { - var geoJSONFeature = /** @type {GeoJSONFeature} */ (object); - goog.asserts.assert(geoJSONFeature.type == 'Feature', - 'geoJSONFeature.type should be Feature'); - var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry, - opt_options); - var feature = new ol.Feature(); - if (this.geometryName_) { - feature.setGeometryName(this.geometryName_); - } - feature.setGeometry(geometry); - if (geoJSONFeature.id !== undefined) { - feature.setId(geoJSONFeature.id); - } - if (geoJSONFeature.properties) { - feature.setProperties(geoJSONFeature.properties); - } - return feature; -}; +ol.format.Polyline.prototype.readFeature; /** * @inheritDoc */ -ol.format.GeoJSON.prototype.readFeaturesFromObject = function( - object, opt_options) { - var geoJSONObject = /** @type {GeoJSONObject} */ (object); - if (geoJSONObject.type == 'Feature') { - return [this.readFeatureFromObject(object, opt_options)]; - } else if (geoJSONObject.type == 'FeatureCollection') { - var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */ - (object); - /** @type {Array.<ol.Feature>} */ - var features = []; - var geoJSONFeatures = geoJSONFeatureCollection.features; - var i, ii; - for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) { - features.push(this.readFeatureFromObject(geoJSONFeatures[i], - opt_options)); - } - return features; - } else { - goog.asserts.fail('Unknown geoJSONObject.type: ' + geoJSONObject.type); - return []; - } +ol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) { + var geometry = this.readGeometryFromText(text, opt_options); + return new ol.Feature(geometry); }; /** - * Read a geometry from a GeoJSON source. + * Read the feature from the source. As Polyline sources contain a single + * feature, this will return the feature in an array. * * @function * @param {Document|Node|Object|string} source Source. * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. + * @return {Array.<ol.Feature>} Features. * @api stable */ -ol.format.GeoJSON.prototype.readGeometry; +ol.format.Polyline.prototype.readFeatures; /** * @inheritDoc */ -ol.format.GeoJSON.prototype.readGeometryFromObject = function( - object, opt_options) { - return ol.format.GeoJSON.readGeometry_( - /** @type {GeoJSONGeometry} */ (object), opt_options); +ol.format.Polyline.prototype.readFeaturesFromText = + function(text, opt_options) { + var feature = this.readFeatureFromText(text, opt_options); + return [feature]; }; /** - * Read the projection from a GeoJSON source. + * Read the geometry from the source. * * @function * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.geom.Geometry} Geometry. * @api stable */ -ol.format.GeoJSON.prototype.readProjection; +ol.format.Polyline.prototype.readGeometry; /** * @inheritDoc */ -ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) { - var geoJSONObject = /** @type {GeoJSONObject} */ (object); - var crs = geoJSONObject.crs; - if (crs) { - if (crs.type == 'name') { - return ol.proj.get(crs.properties.name); - } else if (crs.type == 'EPSG') { - // 'EPSG' is not part of the GeoJSON specification, but is generated by - // GeoServer. - // TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996 - // is fixed and widely deployed. - return ol.proj.get('EPSG:' + crs.properties.code); - } else { - goog.asserts.fail('Unknown crs.type: ' + crs.type); - return null; - } - } else { - return this.defaultDataProjection; - } +ol.format.Polyline.prototype.readGeometryFromText = + function(text, opt_options) { + var stride = ol.geom.SimpleGeometry.getStrideForLayout(this.geometryLayout_); + var flatCoordinates = ol.format.Polyline.decodeDeltas( + text, stride, this.factor_); + ol.geom.flat.flip.flipXY( + flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates); + var coordinates = ol.geom.flat.inflate.coordinates( + flatCoordinates, 0, flatCoordinates.length, stride); + + return /** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions( + new ol.geom.LineString(coordinates, this.geometryLayout_), false, + this.adaptOptions(opt_options))); }; /** - * Encode a feature as a GeoJSON Feature string. + * Read the projection from a Polyline source. * * @function - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} GeoJSON. - * @api stable - */ -ol.format.GeoJSON.prototype.writeFeature; - - -/** - * Encode a feature as a GeoJSON Feature object. - * - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} Object. + * @param {Document|Node|Object|string} source Source. + * @return {ol.proj.Projection} Projection. * @api stable */ -ol.format.GeoJSON.prototype.writeFeatureObject = function( - feature, opt_options) { - opt_options = this.adaptOptions(opt_options); - var object = { - 'type': 'Feature' - }; - var id = feature.getId(); - if (id !== undefined) { - object['id'] = id; - } - var geometry = feature.getGeometry(); - if (geometry) { - object['geometry'] = - ol.format.GeoJSON.writeGeometry_(geometry, opt_options); - } else { - object['geometry'] = null; - } - var properties = feature.getProperties(); - delete properties[feature.getGeometryName()]; - if (!goog.object.isEmpty(properties)) { - object['properties'] = properties; - } else { - object['properties'] = null; - } - return object; -}; +ol.format.Polyline.prototype.readProjection; /** - * Encode an array of features as GeoJSON. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} GeoJSON. - * @api stable + * @inheritDoc */ -ol.format.GeoJSON.prototype.writeFeatures; +ol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) { + var geometry = feature.getGeometry(); + if (geometry) { + return this.writeGeometryText(geometry, opt_options); + } else { + goog.asserts.fail('geometry needs to be defined'); + return ''; + } +}; /** - * Encode an array of features as a GeoJSON object. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {Object} GeoJSON Object. - * @api stable + * @inheritDoc */ -ol.format.GeoJSON.prototype.writeFeaturesObject = +ol.format.Polyline.prototype.writeFeaturesText = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var objects = []; - var i, ii; - for (i = 0, ii = features.length; i < ii; ++i) { - objects.push(this.writeFeatureObject(features[i], opt_options)); - } - return /** @type {GeoJSONFeatureCollection} */ ({ - type: 'FeatureCollection', - features: objects - }); + goog.asserts.assert(features.length == 1, + 'features array should have 1 item'); + return this.writeFeatureText(features[0], opt_options); }; /** - * Encode a geometry as a GeoJSON string. + * Write a single geometry in Polyline format. * * @function * @param {ol.geom.Geometry} geometry Geometry. * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} GeoJSON. + * @return {string} Geometry. * @api stable */ -ol.format.GeoJSON.prototype.writeGeometry; +ol.format.Polyline.prototype.writeGeometry; /** - * Encode a geometry as a GeoJSON object. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object. - * @api stable + * @inheritDoc */ -ol.format.GeoJSON.prototype.writeGeometryObject = function(geometry, - opt_options) { - return ol.format.GeoJSON.writeGeometry_(geometry, - this.adaptOptions(opt_options)); +ol.format.Polyline.prototype.writeGeometryText = + function(geometry, opt_options) { + goog.asserts.assertInstanceof(geometry, ol.geom.LineString, + 'geometry should be an ol.geom.LineString'); + geometry = /** @type {ol.geom.LineString} */ + (ol.format.Feature.transformWithOptions( + geometry, true, this.adaptOptions(opt_options))); + var flatCoordinates = geometry.getFlatCoordinates(); + var stride = geometry.getStride(); + ol.geom.flat.flip.flipXY( + flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates); + return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_); }; -goog.provide('ol.format.XMLFeature'); +goog.provide('ol.format.TopoJSON'); -goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.xml'); +goog.require('goog.object'); +goog.require('ol.Feature'); goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); +goog.require('ol.format.JSONFeature'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); goog.require('ol.proj'); -goog.require('ol.xml'); /** * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for XML feature formats. + * Feature format for reading data in the TopoJSON format. * * @constructor - * @extends {ol.format.Feature} + * @extends {ol.format.JSONFeature} + * @param {olx.format.TopoJSONOptions=} opt_options Options. + * @api stable */ -ol.format.XMLFeature = function() { +ol.format.TopoJSON = function(opt_options) { + + var options = opt_options ? opt_options : {}; + goog.base(this); -}; -goog.inherits(ol.format.XMLFeature, ol.format.Feature); + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get( + options.defaultDataProjection ? + options.defaultDataProjection : 'EPSG:4326'); -/** - * @inheritDoc - */ -ol.format.XMLFeature.prototype.getType = function() { - return ol.format.FormatType.XML; }; +goog.inherits(ol.format.TopoJSON, ol.format.JSONFeature); /** - * @inheritDoc + * @const {Array.<string>} + * @private */ -ol.format.XMLFeature.prototype.readFeature = function(source, opt_options) { - if (ol.xml.isDocument(source)) { - return this.readFeatureFromDocument( - /** @type {Document} */ (source), opt_options); - } else if (ol.xml.isNode(source)) { - return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFeatureFromDocument(doc, opt_options); - } else { - goog.asserts.fail('Unknown source type'); - return null; - } -}; +ol.format.TopoJSON.EXTENSIONS_ = ['.topojson']; /** - * @param {Document} doc Document. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {ol.Feature} Feature. + * Concatenate arcs into a coordinate array. + * @param {Array.<number>} indices Indices of arcs to concatenate. Negative + * values indicate arcs need to be reversed. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already + * transformed). + * @return {Array.<ol.Coordinate>} Coordinates array. + * @private */ -ol.format.XMLFeature.prototype.readFeatureFromDocument = function( - doc, opt_options) { - var features = this.readFeaturesFromDocument(doc, opt_options); - if (features.length > 0) { - return features[0]; - } else { - return null; +ol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) { + /** @type {Array.<ol.Coordinate>} */ + var coordinates = []; + var index, arc; + var i, ii; + var j, jj; + for (i = 0, ii = indices.length; i < ii; ++i) { + index = indices[i]; + if (i > 0) { + // splicing together arcs, discard last point + coordinates.pop(); + } + if (index >= 0) { + // forward arc + arc = arcs[index]; + } else { + // reverse arc + arc = arcs[~index].slice().reverse(); + } + coordinates.push.apply(coordinates, arc); + } + // provide fresh copies of coordinate arrays + for (j = 0, jj = coordinates.length; j < jj; ++j) { + coordinates[j] = coordinates[j].slice(); } + return coordinates; }; /** - * @param {Node} node Node. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {ol.Feature} Feature. + * Create a point from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON object. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @return {ol.geom.Point} Geometry. + * @private */ -ol.format.XMLFeature.prototype.readFeatureFromNode = goog.abstractMethod; +ol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) { + var coordinates = object.coordinates; + if (scale && translate) { + ol.format.TopoJSON.transformVertex_(coordinates, scale, translate); + } + return new ol.geom.Point(coordinates); +}; /** - * @inheritDoc + * Create a multi-point from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON object. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @return {ol.geom.MultiPoint} Geometry. + * @private */ -ol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) { - if (ol.xml.isDocument(source)) { - return this.readFeaturesFromDocument( - /** @type {Document} */ (source), opt_options); - } else if (ol.xml.isNode(source)) { - return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFeaturesFromDocument(doc, opt_options); - } else { - goog.asserts.fail('Unknown source type'); - return []; +ol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale, + translate) { + var coordinates = object.coordinates; + var i, ii; + if (scale && translate) { + for (i = 0, ii = coordinates.length; i < ii; ++i) { + ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate); + } } + return new ol.geom.MultiPoint(coordinates); }; /** - * @param {Document} doc Document. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {Array.<ol.Feature>} Features. + * Create a linestring from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON object. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @return {ol.geom.LineString} Geometry. + * @private */ -ol.format.XMLFeature.prototype.readFeaturesFromDocument = function( - doc, opt_options) { - /** @type {Array.<ol.Feature>} */ - var features = []; - var n; - for (n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - goog.array.extend(features, this.readFeaturesFromNode(n, opt_options)); - } - } - return features; +ol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) { + var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs); + return new ol.geom.LineString(coordinates); }; /** - * @param {Node} node Node. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {Array.<ol.Feature>} Features. + * Create a multi-linestring from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON object. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @return {ol.geom.MultiLineString} Geometry. + * @private */ -ol.format.XMLFeature.prototype.readFeaturesFromNode = goog.abstractMethod; +ol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) { + var coordinates = []; + var i, ii; + for (i = 0, ii = object.arcs.length; i < ii; ++i) { + coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs); + } + return new ol.geom.MultiLineString(coordinates); +}; /** - * @inheritDoc + * Create a polygon from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON object. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @return {ol.geom.Polygon} Geometry. + * @private */ -ol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) { - if (ol.xml.isDocument(source)) { - return this.readGeometryFromDocument( - /** @type {Document} */ (source), opt_options); - } else if (ol.xml.isNode(source)) { - return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readGeometryFromDocument(doc, opt_options); - } else { - goog.asserts.fail('Unknown source type'); - return null; +ol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) { + var coordinates = []; + var i, ii; + for (i = 0, ii = object.arcs.length; i < ii; ++i) { + coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs); } + return new ol.geom.Polygon(coordinates); }; /** - * @param {Document} doc Document. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {ol.geom.Geometry} Geometry. + * Create a multi-polygon from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON object. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @return {ol.geom.MultiPolygon} Geometry. + * @private */ -ol.format.XMLFeature.prototype.readGeometryFromDocument = goog.abstractMethod; +ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) { + var coordinates = []; + var polyArray, ringCoords, j, jj; + var i, ii; + for (i = 0, ii = object.arcs.length; i < ii; ++i) { + // for each polygon + polyArray = object.arcs[i]; + ringCoords = []; + for (j = 0, jj = polyArray.length; j < jj; ++j) { + // for each ring + ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs); + } + coordinates[i] = ringCoords; + } + return new ol.geom.MultiPolygon(coordinates); +}; /** - * @param {Node} node Node. - * @param {olx.format.ReadOptions=} opt_options Options. - * @protected - * @return {ol.geom.Geometry} Geometry. + * @inheritDoc */ -ol.format.XMLFeature.prototype.readGeometryFromNode = goog.abstractMethod; +ol.format.TopoJSON.prototype.getExtensions = function() { + return ol.format.TopoJSON.EXTENSIONS_; +}; /** - * @inheritDoc + * Create features from a TopoJSON GeometryCollection object. + * + * @param {TopoJSONGeometryCollection} collection TopoJSON Geometry + * object. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Array of features. + * @private */ -ol.format.XMLFeature.prototype.readProjection = function(source) { - if (ol.xml.isDocument(source)) { - return this.readProjectionFromDocument(/** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readProjectionFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readProjectionFromDocument(doc); - } else { - goog.asserts.fail('Unknown source type'); - return null; +ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function( + collection, arcs, scale, translate, opt_options) { + var geometries = collection.geometries; + var features = []; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + features[i] = ol.format.TopoJSON.readFeatureFromGeometry_( + geometries[i], arcs, scale, translate, opt_options); } + return features; }; /** - * @param {Document} doc Document. - * @protected - * @return {ol.proj.Projection} Projection. + * Create a feature from a TopoJSON geometry object. + * + * @param {TopoJSONGeometry} object TopoJSON geometry object. + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @private */ -ol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) { - return this.defaultDataProjection; +ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs, + scale, translate, opt_options) { + var geometry; + var type = object.type; + var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type]; + goog.asserts.assert(geometryReader, 'geometryReader should be defined'); + if ((type === 'Point') || (type === 'MultiPoint')) { + geometry = geometryReader(object, scale, translate); + } else { + geometry = geometryReader(object, arcs); + } + var feature = new ol.Feature(); + feature.setGeometry(/** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions(geometry, false, opt_options))); + if (object.id !== undefined) { + feature.setId(object.id); + } + if (object.properties) { + feature.setProperties(object.properties); + } + return feature; }; /** - * @param {Node} node Node. - * @protected - * @return {ol.proj.Projection} Projection. + * Read all features from a TopoJSON source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @return {Array.<ol.Feature>} Features. + * @api stable */ -ol.format.XMLFeature.prototype.readProjectionFromNode = function(node) { - return this.defaultDataProjection; -}; +ol.format.TopoJSON.prototype.readFeatures; /** * @inheritDoc */ -ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) { - var node = this.writeFeatureNode(feature, opt_options); - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return goog.dom.xml.serialize(/** @type {Element} */(node)); +ol.format.TopoJSON.prototype.readFeaturesFromObject = function( + object, opt_options) { + if (object.type == 'Topology') { + var topoJSONTopology = /** @type {TopoJSONTopology} */ (object); + var transform, scale = null, translate = null; + if (topoJSONTopology.transform) { + transform = topoJSONTopology.transform; + scale = transform.scale; + translate = transform.translate; + } + var arcs = topoJSONTopology.arcs; + if (transform) { + ol.format.TopoJSON.transformArcs_(arcs, scale, translate); + } + /** @type {Array.<ol.Feature>} */ + var features = []; + var topoJSONFeatures = goog.object.getValues(topoJSONTopology.objects); + var i, ii; + var feature; + for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) { + if (topoJSONFeatures[i].type === 'GeometryCollection') { + feature = /** @type {TopoJSONGeometryCollection} */ + (topoJSONFeatures[i]); + features.push.apply(features, + ol.format.TopoJSON.readFeaturesFromGeometryCollection_( + feature, arcs, scale, translate, opt_options)); + } else { + feature = /** @type {TopoJSONGeometry} */ + (topoJSONFeatures[i]); + features.push(ol.format.TopoJSON.readFeatureFromGeometry_( + feature, arcs, scale, translate, opt_options)); + } + } + return features; + } else { + return []; + } }; /** - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Options. - * @protected - * @return {Node} Node. + * Apply a linear transform to array of arcs. The provided array of arcs is + * modified in place. + * + * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @private */ -ol.format.XMLFeature.prototype.writeFeatureNode = goog.abstractMethod; +ol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) { + var i, ii; + for (i = 0, ii = arcs.length; i < ii; ++i) { + ol.format.TopoJSON.transformArc_(arcs[i], scale, translate); + } +}; /** - * @inheritDoc + * Apply a linear transform to an arc. The provided arc is modified in place. + * + * @param {Array.<ol.Coordinate>} arc Arc. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @private */ -ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) { - var node = this.writeFeaturesNode(features, opt_options); - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return goog.dom.xml.serialize(/** @type {Element} */(node)); +ol.format.TopoJSON.transformArc_ = function(arc, scale, translate) { + var x = 0; + var y = 0; + var vertex; + var i, ii; + for (i = 0, ii = arc.length; i < ii; ++i) { + vertex = arc[i]; + x += vertex[0]; + y += vertex[1]; + vertex[0] = x; + vertex[1] = y; + ol.format.TopoJSON.transformVertex_(vertex, scale, translate); + } }; /** - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. + * Apply a linear transform to a vertex. The provided vertex is modified in + * place. + * + * @param {ol.Coordinate} vertex Vertex. + * @param {Array.<number>} scale Scale for each dimension. + * @param {Array.<number>} translate Translation for each dimension. + * @private */ -ol.format.XMLFeature.prototype.writeFeaturesNode = goog.abstractMethod; +ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) { + vertex[0] = vertex[0] * scale[0] + translate[0]; + vertex[1] = vertex[1] * scale[1] + translate[1]; +}; /** - * @inheritDoc + * Read the projection from a TopoJSON source. + * + * @function + * @param {Document|Node|Object|string} object Source. + * @return {ol.proj.Projection} Projection. + * @api stable */ -ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) { - var node = this.writeGeometryNode(geometry, opt_options); - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return goog.dom.xml.serialize(/** @type {Element} */(node)); +ol.format.TopoJSON.prototype.readProjection = function(object) { + return this.defaultDataProjection; }; - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. + +/** + * @const + * @private + * @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>} */ -ol.format.XMLFeature.prototype.writeGeometryNode = goog.abstractMethod; +ol.format.TopoJSON.GEOMETRY_READERS_ = { + 'Point': ol.format.TopoJSON.readPointGeometry_, + 'LineString': ol.format.TopoJSON.readLineStringGeometry_, + 'Polygon': ol.format.TopoJSON.readPolygonGeometry_, + 'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_, + 'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_, + 'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_ +}; -// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part -// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect -// envelopes/extents, only geometries! -goog.provide('ol.format.GMLBase'); +goog.provide('ol.format.WFS'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); -goog.require('goog.string'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); +goog.require('ol'); +goog.require('ol.format.GML3'); +goog.require('ol.format.GMLBase'); goog.require('ol.format.XMLFeature'); +goog.require('ol.format.XSD'); goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); goog.require('ol.proj'); goog.require('ol.xml'); @@ -93275,441 +109039,241 @@ goog.require('ol.xml'); /** * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Feature base format for reading and writing data in the GML format. - * This class cannot be instantiated, it contains only base content that - * is shared with versioned format classes ol.format.GML2 and - * ol.format.GML3. + * Feature format for reading and writing data in the WFS format. + * By default, supports WFS version 1.1.0. You can pass a GML format + * as option if you want to read a WFS that contains GML2 (WFS 1.0.0). + * Also see {@link ol.format.GMLBase} which is used by this format. * * @constructor - * @param {olx.format.GMLOptions=} opt_options + * @param {olx.format.WFSOptions=} opt_options * Optional configuration object. * @extends {ol.format.XMLFeature} + * @api stable */ -ol.format.GMLBase = function(opt_options) { - var options = /** @type {olx.format.GMLOptions} */ - (opt_options ? opt_options : {}); +ol.format.WFS = function(opt_options) { + var options = opt_options ? opt_options : {}; /** - * @protected + * @private * @type {Array.<string>|string|undefined} */ - this.featureType = options.featureType; + this.featureType_ = options.featureType; /** - * @protected + * @private * @type {Object.<string, string>|string|undefined} */ - this.featureNS = options.featureNS; + this.featureNS_ = options.featureNS; /** - * @protected - * @type {string} + * @private + * @type {ol.format.GMLBase} */ - this.srsName = options.srsName; + this.gmlFormat_ = options.gmlFormat ? + options.gmlFormat : new ol.format.GML3(); /** - * @protected + * @private * @type {string} */ - this.schemaLocation = ''; - - /** - * @type {Object.<string, Object.<string, Object>>} - */ - this.FEATURE_COLLECTION_PARSERS = {}; - this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = { - 'featureMember': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readFeaturesInternal), - 'featureMembers': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readFeaturesInternal) - }; + this.schemaLocation_ = options.schemaLocation ? + options.schemaLocation : ol.format.WFS.SCHEMA_LOCATION; goog.base(this); }; -goog.inherits(ol.format.GMLBase, ol.format.XMLFeature); +goog.inherits(ol.format.WFS, ol.format.XMLFeature); /** * @const * @type {string} */ -ol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml'; +ol.format.WFS.FEATURE_PREFIX = 'feature'; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<ol.Feature>} Features. + * @const + * @type {string} */ -ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var localName = ol.xml.getLocalName(node); - var features; - if (localName == 'FeatureCollection') { - if (node.namespaceURI === 'http://www.opengis.net/wfs') { - features = ol.xml.pushParseAndPop([], - this.FEATURE_COLLECTION_PARSERS, node, - objectStack, this); - } else { - features = ol.xml.pushParseAndPop(null, - this.FEATURE_COLLECTION_PARSERS, node, - objectStack, this); - } - } else if (localName == 'featureMembers' || localName == 'featureMember') { - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featureNS = context['featureNS']; - var i, ii, prefix = 'p', defaultPrefix = 'p0'; - if (!featureType && node.childNodes) { - featureType = [], featureNS = {}; - for (i = 0, ii = node.childNodes.length; i < ii; ++i) { - var child = node.childNodes[i]; - if (child.nodeType === 1) { - var ft = child.nodeName.split(':').pop(); - if (featureType.indexOf(ft) === -1) { - var key; - if (!goog.object.contains(featureNS, child.namespaceURI)) { - key = prefix + goog.object.getCount(featureNS); - featureNS[key] = child.namespaceURI; - } else { - key = goog.object.findKey(featureNS, function(value) { - return value === child.namespaceURI; - }); - } - featureType.push(key + ':' + ft); - } - } - } - context['featureType'] = featureType; - context['featureNS'] = featureNS; - } - if (goog.isString(featureNS)) { - var ns = featureNS; - featureNS = {}; - featureNS[defaultPrefix] = ns; - } - var parsersNS = {}; - var featureTypes = goog.isArray(featureType) ? featureType : [featureType]; - for (var p in featureNS) { - var parsers = {}; - for (i = 0, ii = featureTypes.length; i < ii; ++i) { - var featurePrefix = featureTypes[i].indexOf(':') === -1 ? - defaultPrefix : featureTypes[i].split(':')[0]; - if (featurePrefix === p) { - parsers[featureTypes[i].split(':').pop()] = - (localName == 'featureMembers') ? - ol.xml.makeArrayPusher(this.readFeatureElement, this) : - ol.xml.makeReplacer(this.readFeatureElement, this); - } - } - parsersNS[featureNS[p]] = parsers; - } - features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack); - } - if (!features) { - features = []; - } - return features; -}; +ol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/'; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.Geometry|undefined} Geometry. + * Number of features; bounds/extent. + * @typedef {{numberOfFeatures: number, + * bounds: ol.Extent}} + * @api stable */ -ol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) { - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - context['srsName'] = node.firstElementChild.getAttribute('srsName'); - var geometry = ol.xml.pushParseAndPop(/** @type {ol.geom.Geometry} */(null), - this.GEOMETRY_PARSERS_, node, objectStack, this); - if (geometry) { - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, false, context)); - } else { - return undefined; - } -}; +ol.format.WFS.FeatureCollectionMetadata; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.Feature} Feature. + * Total deleted; total inserted; total updated; array of insert ids. + * @typedef {{totalDeleted: number, + * totalInserted: number, + * totalUpdated: number, + * insertIds: Array.<string>}} + * @api stable */ -ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) { - var n; - var fid = node.getAttribute('fid') || - ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id'); - var values = {}, geometryName; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var localName = ol.xml.getLocalName(n); - // Assume attribute elements have one child node and that the child - // is a text or CDATA node (to be treated as text). - // Otherwise assume it is a geometry node. - if (n.childNodes.length === 0 || - (n.childNodes.length === 1 && - (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) { - var value = ol.xml.getAllTextContent(n, false); - if (goog.string.isEmpty(value)) { - value = undefined; - } - values[localName] = value; - } else { - // boundedBy is an extent and must not be considered as a geometry - if (localName !== 'boundedBy') { - geometryName = localName; - } - values[localName] = this.readGeometryElement(n, objectStack); - } - } - var feature = new ol.Feature(values); - if (geometryName) { - feature.setGeometryName(geometryName); - } - if (fid) { - feature.setId(fid); - } - return feature; -}; +ol.format.WFS.TransactionResponse; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.Point|undefined} Point. + * @const + * @type {string} */ -ol.format.GMLBase.prototype.readPoint = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Point', 'localName should be Point'); - var flatCoordinates = - this.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var point = new ol.geom.Point(null); - goog.asserts.assert(flatCoordinates.length == 3, - 'flatCoordinates should have a length of 3'); - point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return point; - } -}; +ol.format.WFS.SCHEMA_LOCATION = 'http://www.opengis.net/wfs ' + + 'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd'; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.MultiPoint|undefined} MultiPoint. + * Read all features from a WFS FeatureCollection. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api stable */ -ol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiPoint', - 'localName should be MultiPoint'); - var coordinates = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([]), - this.MULTIPOINT_PARSERS_, node, objectStack, this); - if (coordinates) { - return new ol.geom.MultiPoint(coordinates); - } else { - return undefined; - } -}; +ol.format.WFS.prototype.readFeatures; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.MultiLineString|undefined} MultiLineString. + * @inheritDoc */ -ol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiLineString', - 'localName should be MultiLineString'); - var lineStrings = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.LineString>} */ ([]), - this.MULTILINESTRING_PARSERS_, node, objectStack, this); - if (lineStrings) { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(lineStrings); - return multiLineString; - } else { - return undefined; +ol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) { + var context = { + 'featureType': this.featureType_, + 'featureNS': this.featureNS_ + }; + goog.object.extend(context, this.getReadOptions(node, + opt_options ? opt_options : {})); + var objectStack = [context]; + this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][ + 'featureMember'] = + ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal); + var features = ol.xml.pushParseAndPop([], + this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node, + objectStack, this.gmlFormat_); + if (!features) { + features = []; } + return features; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.MultiPolygon|undefined} MultiPolygon. + * Read transaction response of the source. + * + * @param {Document|Node|Object|string} source Source. + * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. + * @api stable */ -ol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiPolygon', - 'localName should be MultiPolygon'); - var polygons = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.Polygon>} */ ([]), - this.MULTIPOLYGON_PARSERS_, node, objectStack, this); - if (polygons) { - var multiPolygon = new ol.geom.MultiPolygon(null); - multiPolygon.setPolygons(polygons); - return multiPolygon; +ol.format.WFS.prototype.readTransactionResponse = function(source) { + if (ol.xml.isDocument(source)) { + return this.readTransactionResponseFromDocument( + /** @type {Document} */ (source)); + } else if (ol.xml.isNode(source)) { + return this.readTransactionResponseFromNode(/** @type {Node} */ (source)); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readTransactionResponseFromDocument(doc); } else { + goog.asserts.fail('Unknown source type'); return undefined; } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'pointMember' || - node.localName == 'pointMembers', - 'localName should be pointMember or pointMembers'); - ol.xml.parseNode(this.POINTMEMBER_PARSERS_, - node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.GMLBase.prototype.lineStringMemberParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'lineStringMember' || - node.localName == 'lineStringMembers', - 'localName should be LineStringMember or LineStringMembers'); - ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_, - node, objectStack, this); -}; - - -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Read feature collection metadata of the source. + * + * @param {Document|Node|Object|string} source Source. + * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} + * FeatureCollection metadata. + * @api stable */ -ol.format.GMLBase.prototype.polygonMemberParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'polygonMember' || - node.localName == 'polygonMembers', - 'localName should be polygonMember or polygonMembers'); - ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node, - objectStack, this); +ol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) { + if (ol.xml.isDocument(source)) { + return this.readFeatureCollectionMetadataFromDocument( + /** @type {Document} */ (source)); + } else if (ol.xml.isNode(source)) { + return this.readFeatureCollectionMetadataFromNode( + /** @type {Node} */ (source)); + } else if (goog.isString(source)) { + var doc = ol.xml.parse(source); + return this.readFeatureCollectionMetadataFromDocument(doc); + } else { + goog.asserts.fail('Unknown source type'); + return undefined; + } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.LineString|undefined} LineString. + * @param {Document} doc Document. + * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} + * FeatureCollection metadata. */ -ol.format.GMLBase.prototype.readLineString = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineString', - 'localName should be LineString'); - var flatCoordinates = - this.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return lineString; - } else { - return undefined; +ol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument = + function(doc) { + goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, + 'doc.nodeType should be DOCUMENT'); + for (var n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + return this.readFeatureCollectionMetadataFromNode(n); + } } + return undefined; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private - * @return {Array.<number>|undefined} LinearRing flat coordinates. */ -ol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - var ring = ol.xml.pushParseAndPop(/** @type {Array.<number>} */(null), - this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, - objectStack, this); - if (ring) { - return ring; - } else { - return undefined; +ol.format.WFS.FEATURE_COLLECTION_PARSERS_ = { + 'http://www.opengis.net/gml': { + 'boundedBy': ol.xml.makeObjectPropertySetter( + ol.format.GMLBase.prototype.readGeometryElement, 'bounds') } }; /** * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.LinearRing|undefined} LinearRing. + * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} + * FeatureCollection metadata. */ -ol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) { +ol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - var flatCoordinates = - this.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var ring = new ol.geom.LinearRing(null); - ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return ring; - } else { - return undefined; - } + goog.asserts.assert(node.localName == 'FeatureCollection', + 'localName should be FeatureCollection'); + var result = {}; + var value = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('numberOfFeatures')); + result['numberOfFeatures'] = value; + return ol.xml.pushParseAndPop( + /** @type {ol.format.WFS.FeatureCollectionMetadata} */ (result), + ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.geom.Polygon|undefined} Polygon. - */ -ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Polygon', - 'localName should be Polygon'); - var flatLinearRings = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this); - if (flatLinearRings && flatLinearRings[0]) { - var polygon = new ol.geom.Polygon(null); - var flatCoordinates = flatLinearRings[0]; - var ends = [flatCoordinates.length]; - var i, ii; - for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); - ends.push(flatCoordinates.length); - } - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); - return polygon; - } else { - return undefined; + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = { + 'http://www.opengis.net/wfs': { + 'totalInserted': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'totalUpdated': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'totalDeleted': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger) } }; @@ -93717,17 +109281,12 @@ ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) { /** * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Transaction Summary. * @private - * @return {Array.<number>} Flat coordinates. */ -ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop( - null, - this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, - objectStack, this)); +ol.format.WFS.readTransactionSummary_ = function(node, objectStack) { + return ol.xml.pushParseAndPop( + {}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack); }; @@ -93736,29 +109295,23 @@ ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'pointMember': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.pointMemberParser_), - 'pointMembers': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.pointMemberParser_) +ol.format.WFS.OGC_FID_PARSERS_ = { + 'http://www.opengis.net/ogc': { + 'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) { + return node.getAttribute('fid'); + }) } -}); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private */ -ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'lineStringMember': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.lineStringMemberParser_), - 'lineStringMembers': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.lineStringMemberParser_) - } -}); +ol.format.WFS.fidParser_ = function(node, objectStack) { + ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack); +}; /** @@ -93766,27 +109319,23 @@ ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = Object({ * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'polygonMember': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.polygonMemberParser_), - 'polygonMembers': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.polygonMemberParser_) +ol.format.WFS.INSERT_RESULTS_PARSERS_ = { + 'http://www.opengis.net/wfs': { + 'Feature': ol.format.WFS.fidParser_ } -}); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Array.<string>|undefined} Insert results. * @private */ -ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Point': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_) - } -}); +ol.format.WFS.readInsertResults_ = function(node, objectStack) { + return ol.xml.pushParseAndPop( + [], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack); +}; /** @@ -93794,2161 +109343,2127 @@ ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = Object({ * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'LineString': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readLineString) +ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = { + 'http://www.opengis.net/wfs': { + 'TransactionSummary': ol.xml.makeObjectPropertySetter( + ol.format.WFS.readTransactionSummary_, 'transactionSummary'), + 'InsertResults': ol.xml.makeObjectPropertySetter( + ol.format.WFS.readInsertResults_, 'insertIds') } -}); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @param {Document} doc Document. + * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. */ -ol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Polygon': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readPolygon) +ol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) { + goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, + 'doc.nodeType should be DOCUMENT'); + for (var n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + return this.readTransactionResponseFromNode(n); + } } -}); + return undefined; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @protected + * @param {Node} node Node. + * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. */ -ol.format.GMLBase.prototype.RING_PARSERS = Object({ - 'http://www.opengis.net/gml' : { - 'LinearRing': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readFlatLinearRing_) - } -}); +ol.format.WFS.prototype.readTransactionResponseFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'TransactionResponse', + 'localName should be TransactionResponse'); + return ol.xml.pushParseAndPop( + /** @type {ol.format.WFS.TransactionResponse} */({}), + ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []); +}; /** - * @inheritDoc + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private */ -ol.format.GMLBase.prototype.readGeometryFromNode = - function(node, opt_options) { - var geometry = this.readGeometryElement(node, - [this.getReadOptions(node, opt_options ? opt_options : {})]); - return geometry ? geometry : null; +ol.format.WFS.QUERY_SERIALIZERS_ = { + 'http://www.opengis.net/wfs': { + 'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) + } }; /** - * Read all features from a GML FeatureCollection. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {Array.<ol.Feature>} Features. - * @api stable + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.GMLBase.prototype.readFeatures; +ol.format.WFS.writeFeature_ = function(node, feature, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featureType = context['featureType']; + var featureNS = context['featureNS']; + var child = ol.xml.createElementNS(featureNS, featureType); + node.appendChild(child); + ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack); +}; /** - * @inheritDoc + * @param {Node} node Node. + * @param {number|string} fid Feature identifier. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.GMLBase.prototype.readFeaturesFromNode = - function(node, opt_options) { - var options = { - featureType: this.featureType, - featureNS: this.featureNS - }; - if (opt_options) { - goog.object.extend(options, this.getReadOptions(node, opt_options)); - } - return this.readFeaturesInternal(node, [options]); +ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) { + var filter = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter'); + var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'FeatureId'); + filter.appendChild(child); + child.setAttribute('fid', fid); + node.appendChild(filter); }; /** - * @inheritDoc + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.GMLBase.prototype.readProjectionFromNode = function(node) { - return ol.proj.get(this.srsName_ ? this.srsName_ : - node.firstElementChild.getAttribute('srsName')); +ol.format.WFS.writeDelete_ = function(node, feature, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featureType = context['featureType']; + var featurePrefix = context['featurePrefix']; + featurePrefix = featurePrefix ? featurePrefix : + ol.format.WFS.FEATURE_PREFIX; + var featureNS = context['featureNS']; + node.setAttribute('typeName', featurePrefix + ':' + featureType); + ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, + featureNS); + var fid = feature.getId(); + if (fid) { + ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); + } }; -goog.provide('ol.format.XSD'); -goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('ol'); -goog.require('ol.xml'); +/** + * @param {Node} node Node. + * @param {ol.Feature} feature Feature. + * @param {Array.<*>} objectStack Node stack. + * @private + */ +ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featureType = context['featureType']; + var featurePrefix = context['featurePrefix']; + featurePrefix = featurePrefix ? featurePrefix : + ol.format.WFS.FEATURE_PREFIX; + var featureNS = context['featureNS']; + node.setAttribute('typeName', featurePrefix + ':' + featureType); + ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, + featureNS); + var fid = feature.getId(); + if (fid) { + var keys = feature.getKeys(); + var values = []; + for (var i = 0, ii = keys.length; i < ii; i++) { + var value = feature.get(keys[i]); + if (value !== undefined) { + values.push({name: keys[i], value: value}); + } + } + ol.xml.pushSerializeAndPop({node: node, srsName: + context['srsName']}, + ol.format.WFS.TRANSACTION_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('Property'), values, + objectStack); + ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); + } +}; /** - * @const - * @type {string} + * @param {Node} node Node. + * @param {Object} pair Property name and value. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema'; +ol.format.WFS.writeProperty_ = function(node, pair, objectStack) { + var name = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Name'); + node.appendChild(name); + ol.format.XSD.writeStringTextNode(name, pair.name); + if (pair.value !== undefined && pair.value !== null) { + var value = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Value'); + node.appendChild(value); + if (pair.value instanceof ol.geom.Geometry) { + ol.format.GML3.prototype.writeGeometryElement(value, + pair.value, objectStack); + } else { + ol.format.XSD.writeStringTextNode(value, pair.value); + } + } +}; /** * @param {Node} node Node. - * @return {boolean|undefined} Boolean. + * @param {{vendorId: string, safeToIgnore: boolean, value: string}} + * nativeElement The native element. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.XSD.readBoolean = function(node) { - var s = ol.xml.getAllTextContent(node, false); - return ol.format.XSD.readBooleanString(s); +ol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) { + if (nativeElement.vendorId) { + node.setAttribute('vendorId', nativeElement.vendorId); + } + if (nativeElement.safeToIgnore !== undefined) { + node.setAttribute('safeToIgnore', nativeElement.safeToIgnore); + } + if (nativeElement.value !== undefined) { + ol.format.XSD.writeStringTextNode(node, nativeElement.value); + } }; /** - * @param {string} string String. - * @return {boolean|undefined} Boolean. + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private */ -ol.format.XSD.readBooleanString = function(string) { - var m = /^\s*(true|1)|(false|0)\s*$/.exec(string); - if (m) { - return m[1] !== undefined || false; - } else { - return undefined; +ol.format.WFS.TRANSACTION_SERIALIZERS_ = { + 'http://www.opengis.net/wfs': { + 'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_), + 'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_), + 'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_), + 'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_), + 'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_) } }; /** * @param {Node} node Node. - * @return {number|undefined} DateTime in seconds. + * @param {string} featureType Feature type. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.XSD.readDateTime = function(node) { - var s = ol.xml.getAllTextContent(node, false); - var re = - /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/; - var m = re.exec(s); - if (m) { - var year = parseInt(m[1], 10); - var month = parseInt(m[2], 10) - 1; - var day = parseInt(m[3], 10); - var hour = parseInt(m[4], 10); - var minute = parseInt(m[5], 10); - var second = parseInt(m[6], 10); - var dateTime = Date.UTC(year, month, day, hour, minute, second) / 1000; - if (m[7] != 'Z') { - var sign = m[8] == '-' ? -1 : 1; - dateTime += sign * 60 * parseInt(m[9], 10); - if (m[10] !== undefined) { - dateTime += sign * 60 * 60 * parseInt(m[10], 10); - } - } - return dateTime; - } else { - return undefined; +ol.format.WFS.writeQuery_ = function(node, featureType, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var featurePrefix = context['featurePrefix']; + var featureNS = context['featureNS']; + var propertyNames = context['propertyNames']; + var srsName = context['srsName']; + var prefix = featurePrefix ? featurePrefix + ':' : ''; + node.setAttribute('typeName', prefix + featureType); + if (srsName) { + node.setAttribute('srsName', srsName); + } + if (featureNS) { + ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, + featureNS); + } + var item = goog.object.clone(context); + item.node = node; + ol.xml.pushSerializeAndPop(item, + ol.format.WFS.QUERY_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames, + objectStack); + var bbox = context['bbox']; + if (bbox) { + var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter'); + ol.format.WFS.writeOgcBBOX_(child, bbox, objectStack); + node.appendChild(child); } }; /** * @param {Node} node Node. - * @return {number|undefined} Decimal. + * @param {string} value PropertyName value. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.XSD.readDecimal = function(node) { - var s = ol.xml.getAllTextContent(node, false); - return ol.format.XSD.readDecimalString(s); +ol.format.WFS.writeOgcPropertyName_ = function(node, value, objectStack) { + var property = ol.xml.createElementNS('http://www.opengis.net/ogc', + 'PropertyName'); + ol.format.XSD.writeStringTextNode(property, value); + node.appendChild(property); }; /** - * @param {string} string String. - * @return {number|undefined} Decimal. + * @param {Node} node Node. + * @param {ol.Extent} bbox Bounding box. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.XSD.readDecimalString = function(string) { - // FIXME check spec - var m = /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(string); - if (m) { - return parseFloat(m[1]); - } else { - return undefined; +ol.format.WFS.writeOgcBBOX_ = function(node, bbox, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var geometryName = context['geometryName']; + var bboxNode = ol.xml.createElementNS('http://www.opengis.net/ogc', 'BBOX'); + node.appendChild(bboxNode); + ol.format.WFS.writeOgcPropertyName_(bboxNode, geometryName, objectStack); + ol.format.GML3.prototype.writeGeometryElement(bboxNode, bbox, objectStack); +}; + + +/** + * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @private + */ +ol.format.WFS.GETFEATURE_SERIALIZERS_ = { + 'http://www.opengis.net/wfs': { + 'Query': ol.xml.makeChildAppender( + ol.format.WFS.writeQuery_) } }; /** * @param {Node} node Node. - * @return {number|undefined} Non negative integer. + * @param {Array.<{string}>} featureTypes Feature types. + * @param {Array.<*>} objectStack Node stack. + * @private */ -ol.format.XSD.readNonNegativeInteger = function(node) { - var s = ol.xml.getAllTextContent(node, false); - return ol.format.XSD.readNonNegativeIntegerString(s); +ol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) { + var context = objectStack[objectStack.length - 1]; + goog.asserts.assert(goog.isObject(context), 'context should be an Object'); + var item = goog.object.clone(context); + item.node = node; + ol.xml.pushSerializeAndPop(item, + ol.format.WFS.GETFEATURE_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('Query'), featureTypes, + objectStack); }; /** - * @param {string} string String. - * @return {number|undefined} Non negative integer. + * Encode format as WFS `GetFeature` and return the Node. + * + * @param {olx.format.WFSWriteGetFeatureOptions} options Options. + * @return {Node} Result. + * @api stable */ -ol.format.XSD.readNonNegativeIntegerString = function(string) { - var m = /^\s*(\d+)\s*$/.exec(string); - if (m) { - return parseInt(m[1], 10); - } else { - return undefined; +ol.format.WFS.prototype.writeGetFeature = function(options) { + var node = ol.xml.createElementNS('http://www.opengis.net/wfs', + 'GetFeature'); + node.setAttribute('service', 'WFS'); + node.setAttribute('version', '1.1.0'); + if (options) { + if (options.handle) { + node.setAttribute('handle', options.handle); + } + if (options.outputFormat) { + node.setAttribute('outputFormat', options.outputFormat); + } + if (options.maxFeatures !== undefined) { + node.setAttribute('maxFeatures', options.maxFeatures); + } + if (options.resultType) { + node.setAttribute('resultType', options.resultType); + } + if (options.startIndex !== undefined) { + node.setAttribute('startIndex', options.startIndex); + } + if (options.count !== undefined) { + node.setAttribute('count', options.count); + } + } + ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation', this.schemaLocation_); + var context = { + node: node, + srsName: options.srsName, + featureNS: options.featureNS ? options.featureNS : this.featureNS_, + featurePrefix: options.featurePrefix, + geometryName: options.geometryName, + bbox: options.bbox, + propertyNames: options.propertyNames ? options.propertyNames : [] + }; + goog.asserts.assert(goog.isArray(options.featureTypes), + 'options.featureTypes should be an array'); + ol.format.WFS.writeGetFeature_(node, options.featureTypes, [context]); + return node; +}; + + +/** + * Encode format as WFS `Transaction` and return the Node. + * + * @param {Array.<ol.Feature>} inserts The features to insert. + * @param {Array.<ol.Feature>} updates The features to update. + * @param {Array.<ol.Feature>} deletes The features to delete. + * @param {olx.format.WFSWriteTransactionOptions} options Write options. + * @return {Node} Result. + * @api stable + */ +ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes, + options) { + var objectStack = []; + var node = ol.xml.createElementNS('http://www.opengis.net/wfs', + 'Transaction'); + node.setAttribute('service', 'WFS'); + node.setAttribute('version', '1.1.0'); + var baseObj, obj; + if (options) { + baseObj = options.gmlOptions ? options.gmlOptions : {}; + if (options.handle) { + node.setAttribute('handle', options.handle); + } + } + ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation', this.schemaLocation_); + if (inserts) { + obj = {node: node, featureNS: options.featureNS, + featureType: options.featureType, featurePrefix: options.featurePrefix}; + goog.object.extend(obj, baseObj); + ol.xml.pushSerializeAndPop(obj, + ol.format.WFS.TRANSACTION_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('Insert'), inserts, + objectStack); + } + if (updates) { + obj = {node: node, featureNS: options.featureNS, + featureType: options.featureType, featurePrefix: options.featurePrefix}; + goog.object.extend(obj, baseObj); + ol.xml.pushSerializeAndPop(obj, + ol.format.WFS.TRANSACTION_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('Update'), updates, + objectStack); } + if (deletes) { + ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS, + featureType: options.featureType, featurePrefix: options.featurePrefix}, + ol.format.WFS.TRANSACTION_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('Delete'), deletes, + objectStack); + } + if (options.nativeElements) { + ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS, + featureType: options.featureType, featurePrefix: options.featurePrefix}, + ol.format.WFS.TRANSACTION_SERIALIZERS_, + ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements, + objectStack); + } + return node; }; /** - * @param {Node} node Node. - * @return {string|undefined} String. - */ -ol.format.XSD.readString = function(node) { - return ol.xml.getAllTextContent(node, false).trim(); -}; - - -/** - * @param {Node} node Node to append a TextNode with the boolean to. - * @param {boolean} bool Boolean. - */ -ol.format.XSD.writeBooleanTextNode = function(node, bool) { - ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0'); -}; - - -/** - * @param {Node} node Node to append a TextNode with the dateTime to. - * @param {number} dateTime DateTime in seconds. + * Read the projection from a WFS source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @return {?ol.proj.Projection} Projection. + * @api stable */ -ol.format.XSD.writeDateTimeTextNode = function(node, dateTime) { - var date = new Date(dateTime * 1000); - var string = date.getUTCFullYear() + '-' + - goog.string.padNumber(date.getUTCMonth() + 1, 2) + '-' + - goog.string.padNumber(date.getUTCDate(), 2) + 'T' + - goog.string.padNumber(date.getUTCHours(), 2) + ':' + - goog.string.padNumber(date.getUTCMinutes(), 2) + ':' + - goog.string.padNumber(date.getUTCSeconds(), 2) + 'Z'; - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); -}; +ol.format.WFS.prototype.readProjection; /** - * @param {Node} node Node to append a TextNode with the decimal to. - * @param {number} decimal Decimal. + * @inheritDoc */ -ol.format.XSD.writeDecimalTextNode = function(node, decimal) { - var string = decimal.toPrecision(); - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); +ol.format.WFS.prototype.readProjectionFromDocument = function(doc) { + goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, + 'doc.nodeType should be a DOCUMENT'); + for (var n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + return this.readProjectionFromNode(n); + } + } + return null; }; /** - * @param {Node} node Node to append a TextNode with the decimal to. - * @param {number} nonNegativeInteger Non negative integer. + * @inheritDoc */ -ol.format.XSD.writeNonNegativeIntegerTextNode = - function(node, nonNegativeInteger) { - goog.asserts.assert(nonNegativeInteger >= 0, 'value should be more than 0'); - goog.asserts.assert(nonNegativeInteger == (nonNegativeInteger | 0), - 'value should be an integer value'); - var string = nonNegativeInteger.toString(); - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); -}; +ol.format.WFS.prototype.readProjectionFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'FeatureCollection', + 'localName should be FeatureCollection'); + if (node.firstElementChild && + node.firstElementChild.firstElementChild) { + node = node.firstElementChild.firstElementChild; + for (var n = node.firstElementChild; n; n = n.nextElementSibling) { + if (!(n.childNodes.length === 0 || + (n.childNodes.length === 1 && + n.firstChild.nodeType === 3))) { + var objectStack = [{}]; + this.gmlFormat_.readGeometryElement(n, objectStack); + return ol.proj.get(objectStack.pop().srsName); + } + } + } -/** - * @param {Node} node Node to append a TextNode with the string to. - * @param {string} string String. - */ -ol.format.XSD.writeStringTextNode = function(node, string) { - node.appendChild(ol.xml.DOCUMENT.createTextNode(string)); + return null; }; -goog.provide('ol.format.GML2'); +goog.provide('ol.format.WKT'); goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.extent'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.XSD'); -goog.require('ol.proj'); -goog.require('ol.xml'); +goog.require('ol'); +goog.require('ol.Feature'); +goog.require('ol.format.Feature'); +goog.require('ol.format.TextFeature'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryCollection'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); /** * @classdesc - * Feature format for reading and writing data in the GML format, - * version 2.1.2. + * Geometry format for reading and writing data in the `WellKnownText` (WKT) + * format. * * @constructor - * @param {olx.format.GMLOptions=} opt_options Optional configuration object. - * @extends {ol.format.GMLBase} - * @api + * @extends {ol.format.TextFeature} + * @param {olx.format.WKTOptions=} opt_options Options. + * @api stable */ -ol.format.GML2 = function(opt_options) { - var options = /** @type {olx.format.GMLOptions} */ - (opt_options ? opt_options : {}); +ol.format.WKT = function(opt_options) { - goog.base(this, options); + var options = opt_options ? opt_options : {}; - this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][ - 'featureMember'] = - ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal); + goog.base(this); /** - * @inheritDoc + * Split GeometryCollection into multiple features. + * @type {boolean} + * @private */ - this.schemaLocation = options.schemaLocation ? - options.schemaLocation : ol.format.GML2.schemaLocation_; + this.splitCollection_ = options.splitCollection !== undefined ? + options.splitCollection : false; }; -goog.inherits(ol.format.GML2, ol.format.GMLBase); +goog.inherits(ol.format.WKT, ol.format.TextFeature); /** * @const * @type {string} - * @private */ -ol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS + - ' http://schemas.opengis.net/gml/2.1.2/feature.xsd'; +ol.format.WKT.EMPTY = 'EMPTY'; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.geom.Point} geom Point geometry. + * @return {string} Coordinates part of Point as WKT. * @private - * @return {Array.<number>|undefined} Flat coordinates. */ -ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) { - var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, ''); - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var containerSrs = context['srsName']; - var containerDimension = node.parentNode.getAttribute('srsDimension'); - var axisOrientation = 'enu'; - if (containerSrs) { - var proj = ol.proj.get(containerSrs); - axisOrientation = proj.getAxisOrientation(); - } - var coords = s.split(/[\s,]+/); - // The "dimension" attribute is from the GML 3.0.1 spec. - var dim = 2; - if (node.getAttribute('srsDimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('srsDimension')); - } else if (node.getAttribute('dimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('dimension')); - } else if (containerDimension) { - dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); - } - var x, y, z; - var flatCoordinates = []; - for (var i = 0, ii = coords.length; i < ii; i += dim) { - x = parseFloat(coords[i]); - y = parseFloat(coords[i + 1]); - z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; - if (axisOrientation.substr(0, 2) === 'en') { - flatCoordinates.push(x, y, z); - } else { - flatCoordinates.push(y, x, z); - } +ol.format.WKT.encodePointGeometry_ = function(geom) { + var coordinates = geom.getCoordinates(); + if (coordinates.length === 0) { + return ''; } - return flatCoordinates; + return coordinates[0] + ' ' + coordinates[1]; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.geom.MultiPoint} geom MultiPoint geometry. + * @return {string} Coordinates part of MultiPoint as WKT. * @private - * @return {ol.Extent|undefined} Envelope. */ -ol.format.GML2.prototype.readBox_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Box', 'localName should be Box'); - var flatCoordinates = ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.BOX_PARSERS_, node, objectStack, this); - return ol.extent.createOrUpdate(flatCoordinates[1][0], - flatCoordinates[1][1], flatCoordinates[1][3], - flatCoordinates[1][4]); +ol.format.WKT.encodeMultiPointGeometry_ = function(geom) { + var array = []; + var components = geom.getPoints(); + for (var i = 0, ii = components.length; i < ii; ++i) { + array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')'); + } + return array.join(','); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.geom.GeometryCollection} geom GeometryCollection geometry. + * @return {string} Coordinates part of GeometryCollection as WKT. * @private */ -ol.format.GML2.prototype.innerBoundaryIsParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'innerBoundaryIs', - 'localName should be innerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length larger than 0'); - flatLinearRings.push(flatLinearRing); +ol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) { + var array = []; + var geoms = geom.getGeometries(); + for (var i = 0, ii = geoms.length; i < ii; ++i) { + array.push(ol.format.WKT.encode_(geoms[i])); } + return array.join(','); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry. + * @return {string} Coordinates part of LineString as WKT. * @private */ -ol.format.GML2.prototype.outerBoundaryIsParser_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'outerBoundaryIs', - 'localName should be outerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length larger than 0'); - flatLinearRings[0] = flatLinearRing; +ol.format.WKT.encodeLineStringGeometry_ = function(geom) { + var coordinates = geom.getCoordinates(); + var array = []; + for (var i = 0, ii = coordinates.length; i < ii; ++i) { + array.push(coordinates[i][0] + ' ' + coordinates[i][1]); } + return array.join(','); }; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.geom.MultiLineString} geom MultiLineString geometry. + * @return {string} Coordinates part of MultiLineString as WKT. * @private */ -ol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'coordinates': ol.xml.makeReplacer( - ol.format.GML2.prototype.readFlatCoordinates_) +ol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) { + var array = []; + var components = geom.getLineStrings(); + for (var i = 0, ii = components.length; i < ii; ++i) { + array.push('(' + ol.format.WKT.encodeLineStringGeometry_( + components[i]) + ')'); } -}); + return array.join(','); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.geom.Polygon} geom Polygon geometry. + * @return {string} Coordinates part of Polygon as WKT. * @private */ -ol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_, - 'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_ +ol.format.WKT.encodePolygonGeometry_ = function(geom) { + var array = []; + var rings = geom.getLinearRings(); + for (var i = 0, ii = rings.length; i < ii; ++i) { + array.push('(' + ol.format.WKT.encodeLineStringGeometry_( + rings[i]) + ')'); } -}); + return array.join(','); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.geom.MultiPolygon} geom MultiPolygon geometry. + * @return {string} Coordinates part of MultiPolygon as WKT. * @private */ -ol.format.GML2.prototype.BOX_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'coordinates': ol.xml.makeArrayPusher( - ol.format.GML2.prototype.readFlatCoordinates_) +ol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) { + var array = []; + var components = geom.getPolygons(); + for (var i = 0, ii = components.length; i < ii; ++i) { + array.push('(' + ol.format.WKT.encodePolygonGeometry_( + components[i]) + ')'); } -}); + return array.join(','); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * Encode a geometry as WKT. + * @param {ol.geom.Geometry} geom The geometry to encode. + * @return {string} WKT string for the geometry. * @private */ -ol.format.GML2.prototype.GEOMETRY_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint), - 'MultiPoint': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPoint), - 'LineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLineString), - 'MultiLineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiLineString), - 'LinearRing' : ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLinearRing), - 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon), - 'MultiPolygon': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPolygon), - 'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_) +ol.format.WKT.encode_ = function(geom) { + var type = geom.getType(); + var geometryEncoder = ol.format.WKT.GeometryEncoder_[type]; + goog.asserts.assert(geometryEncoder, 'geometryEncoder should be defined'); + var enc = geometryEncoder(geom); + type = type.toUpperCase(); + if (enc.length === 0) { + return type + ' ' + ol.format.WKT.EMPTY; } -}); - -goog.provide('ol.format.GML'); -goog.provide('ol.format.GML3'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Feature'); -goog.require('ol.extent'); -goog.require('ol.format.Feature'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.xml'); - + return type + '(' + enc + ')'; +}; /** - * @classdesc - * Feature format for reading and writing data in the GML format - * version 3.1.1. - * Currently only supports GML 3.1.1 Simple Features profile. - * - * @constructor - * @param {olx.format.GMLOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.GMLBase} - * @api + * @const + * @type {Object.<string, function(ol.geom.Geometry): string>} + * @private */ -ol.format.GML3 = function(opt_options) { - var options = /** @type {olx.format.GMLOptions} */ - (opt_options ? opt_options : {}); - - goog.base(this, options); - - /** - * @private - * @type {boolean} - */ - this.surface_ = options.surface !== undefined ? options.surface : false; - - /** - * @private - * @type {boolean} - */ - this.curve_ = options.curve !== undefined ? options.curve : false; - - /** - * @private - * @type {boolean} - */ - this.multiCurve_ = options.multiCurve !== undefined ? - options.multiCurve : true; - - /** - * @private - * @type {boolean} - */ - this.multiSurface_ = options.multiSurface !== undefined ? - options.multiSurface : true; - - /** - * @inheritDoc - */ - this.schemaLocation = options.schemaLocation ? - options.schemaLocation : ol.format.GML3.schemaLocation_; - +ol.format.WKT.GeometryEncoder_ = { + 'Point': ol.format.WKT.encodePointGeometry_, + 'LineString': ol.format.WKT.encodeLineStringGeometry_, + 'Polygon': ol.format.WKT.encodePolygonGeometry_, + 'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_, + 'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_, + 'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_, + 'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_ }; -goog.inherits(ol.format.GML3, ol.format.GMLBase); /** - * @const - * @type {string} + * Parse a WKT string. + * @param {string} wkt WKT string. + * @return {ol.geom.Geometry|ol.geom.GeometryCollection|undefined} + * The geometry created. * @private */ -ol.format.GML3.schemaLocation_ = ol.format.GMLBase.GMLNS + - ' http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' + - '1.0.0/gmlsf.xsd'; +ol.format.WKT.prototype.parse_ = function(wkt) { + var lexer = new ol.format.WKT.Lexer(wkt); + var parser = new ol.format.WKT.Parser(lexer); + return parser.parse(); +}; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.MultiLineString|undefined} MultiLineString. + * Read a feature from a WKT source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.Feature} Feature. + * @api stable */ -ol.format.GML3.prototype.readMultiCurve_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiCurve', - 'localName should be MultiCurve'); - var lineStrings = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.LineString>} */ ([]), - this.MULTICURVE_PARSERS_, node, objectStack, this); - if (lineStrings) { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(lineStrings); - return multiLineString; - } else { - return undefined; - } -}; +ol.format.WKT.prototype.readFeature; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.MultiPolygon|undefined} MultiPolygon. + * @inheritDoc */ -ol.format.GML3.prototype.readMultiSurface_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiSurface', - 'localName should be MultiSurface'); - var polygons = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.Polygon>} */ ([]), - this.MULTISURFACE_PARSERS_, node, objectStack, this); - if (polygons) { - var multiPolygon = new ol.geom.MultiPolygon(null); - multiPolygon.setPolygons(polygons); - return multiPolygon; - } else { - return undefined; +ol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) { + var geom = this.readGeometryFromText(text, opt_options); + if (geom) { + var feature = new ol.Feature(); + feature.setGeometry(geom); + return feature; } + return null; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Read all features from a WKT source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {Array.<ol.Feature>} Features. + * @api stable */ -ol.format.GML3.prototype.curveMemberParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'curveMember' || - node.localName == 'curveMembers', - 'localName should be curveMember or curveMembers'); - ol.xml.parseNode(this.CURVEMEMBER_PARSERS_, node, objectStack, this); -}; +ol.format.WKT.prototype.readFeatures; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @inheritDoc */ -ol.format.GML3.prototype.surfaceMemberParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'surfaceMember' || - node.localName == 'surfaceMembers', - 'localName should be surfaceMember or surfaceMembers'); - ol.xml.parseNode(this.SURFACEMEMBER_PARSERS_, - node, objectStack, this); +ol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) { + var geometries = []; + var geometry = this.readGeometryFromText(text, opt_options); + if (this.splitCollection_ && + geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) { + geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry)) + .getGeometriesArray(); + } else { + geometries = [geometry]; + } + var feature, features = []; + for (var i = 0, ii = geometries.length; i < ii; ++i) { + feature = new ol.Feature(); + feature.setGeometry(geometries[i]); + features.push(feature); + } + return features; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<(Array.<number>)>|undefined} flat coordinates. + * Read a single geometry from a WKT source. + * + * @function + * @param {Document|Node|Object|string} source Source. + * @param {olx.format.ReadOptions=} opt_options Read options. + * @return {ol.geom.Geometry} Geometry. + * @api stable */ -ol.format.GML3.prototype.readPatch_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'patches', - 'localName should be patches'); - return ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.PATCHES_PARSERS_, node, objectStack, this); -}; +ol.format.WKT.prototype.readGeometry; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} flat coordinates. + * @inheritDoc */ -ol.format.GML3.prototype.readSegment_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'segments', - 'localName should be segments'); - return ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.SEGMENTS_PARSERS_, node, objectStack, this); +ol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) { + var geometry = this.parse_(text); + if (geometry) { + return /** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions(geometry, false, opt_options)); + } else { + return null; + } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<(Array.<number>)>|undefined} flat coordinates. + * Encode a feature as a WKT string. + * + * @function + * @param {ol.Feature} feature Feature. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} WKT string. + * @api stable */ -ol.format.GML3.prototype.readPolygonPatch_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'npde.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'PolygonPatch', - 'localName should be PolygonPatch'); - return ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this); -}; +ol.format.WKT.prototype.writeFeature; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} flat coordinates. + * @inheritDoc */ -ol.format.GML3.prototype.readLineStringSegment_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineStringSegment', - 'localName should be LineStringSegment'); - return ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.GEOMETRY_FLAT_COORDINATES_PARSERS_, - node, objectStack, this); +ol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) { + var geometry = feature.getGeometry(); + if (geometry) { + return this.writeGeometryText(geometry, opt_options); + } + return ''; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Encode an array of features as a WKT string. + * + * @function + * @param {Array.<ol.Feature>} features Features. + * @param {olx.format.WriteOptions=} opt_options Write options. + * @return {string} WKT string. + * @api stable */ -ol.format.GML3.prototype.interiorParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'interior', - 'localName should be interior'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length of 1 or more'); - flatLinearRings.push(flatLinearRing); - } -}; +ol.format.WKT.prototype.writeFeatures; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @inheritDoc */ -ol.format.GML3.prototype.exteriorParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'exterior', - 'localName should be exterior'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - this.RING_PARSERS, node, objectStack, this); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings should have an array length of 1 or more'); - flatLinearRings[0] = flatLinearRing; +ol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) { + if (features.length == 1) { + return this.writeFeatureText(features[0], opt_options); + } + var geometries = []; + for (var i = 0, ii = features.length; i < ii; ++i) { + geometries.push(features[i].getGeometry()); } + var collection = new ol.geom.GeometryCollection(geometries); + return this.writeGeometryText(collection, opt_options); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Polygon|undefined} Polygon. + * Write a single geometry as a WKT string. + * + * @function + * @param {ol.geom.Geometry} geometry Geometry. + * @return {string} WKT string. + * @api stable */ -ol.format.GML3.prototype.readSurface_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Surface', - 'localName should be Surface'); - var flatLinearRings = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - this.SURFACE_PARSERS_, node, objectStack, this); - if (flatLinearRings && flatLinearRings[0]) { - var polygon = new ol.geom.Polygon(null); - var flatCoordinates = flatLinearRings[0]; - var ends = [flatCoordinates.length]; - var i, ii; - for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); - ends.push(flatCoordinates.length); - } - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); - return polygon; - } else { - return undefined; - } -}; +ol.format.WKT.prototype.writeGeometry; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.LineString|undefined} LineString. + * @inheritDoc */ -ol.format.GML3.prototype.readCurve_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Curve', 'localName should be Curve'); - var flatCoordinates = ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.CURVE_PARSERS_, node, objectStack, this); - if (flatCoordinates) { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - return lineString; - } else { - return undefined; - } +ol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) { + return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ ( + ol.format.Feature.transformWithOptions(geometry, true, opt_options))); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Extent|undefined} Envelope. + * @typedef {{type: number, value: (number|string|undefined), position: number}} */ -ol.format.GML3.prototype.readEnvelope_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Envelope', - 'localName should be Envelope'); - var flatCoordinates = ol.xml.pushParseAndPop( - /** @type {Array.<number>} */ ([null]), - this.ENVELOPE_PARSERS_, node, objectStack, this); - return ol.extent.createOrUpdate(flatCoordinates[1][0], - flatCoordinates[1][1], flatCoordinates[2][0], - flatCoordinates[2][1]); -}; +ol.format.WKT.Token; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} Flat coordinates. + * @const + * @enum {number} */ -ol.format.GML3.prototype.readFlatPos_ = function(node, objectStack) { - var s = ol.xml.getAllTextContent(node, false); - var re = /^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/; - /** @type {Array.<number>} */ - var flatCoordinates = []; - var m; - while ((m = re.exec(s))) { - flatCoordinates.push(parseFloat(m[1])); - s = s.substr(m[0].length); - } - if (s !== '') { - return undefined; - } - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var containerSrs = context['srsName']; - var axisOrientation = 'enu'; - if (containerSrs) { - var proj = ol.proj.get(containerSrs); - axisOrientation = proj.getAxisOrientation(); - } - if (axisOrientation === 'neu') { - var i, ii; - for (i = 0, ii = flatCoordinates.length; i < ii; i += 3) { - var y = flatCoordinates[i]; - var x = flatCoordinates[i + 1]; - flatCoordinates[i] = x; - flatCoordinates[i + 1] = y; - } - } - var len = flatCoordinates.length; - if (len == 2) { - flatCoordinates.push(0); - } - if (len === 0) { - return undefined; - } - return flatCoordinates; +ol.format.WKT.TokenType = { + TEXT: 1, + LEFT_PAREN: 2, + RIGHT_PAREN: 3, + NUMBER: 4, + COMMA: 5, + EOF: 6 }; + /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>|undefined} Flat coordinates. + * Class to tokenize a WKT string. + * @param {string} wkt WKT string. + * @constructor + * @protected */ -ol.format.GML3.prototype.readFlatPosList_ = function(node, objectStack) { - var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, ''); - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var containerSrs = context['srsName']; - var containerDimension = node.parentNode.getAttribute('srsDimension'); - var axisOrientation = 'enu'; - if (containerSrs) { - var proj = ol.proj.get(containerSrs); - axisOrientation = proj.getAxisOrientation(); - } - var coords = s.split(/\s+/); - // The "dimension" attribute is from the GML 3.0.1 spec. - var dim = 2; - if (node.getAttribute('srsDimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('srsDimension')); - } else if (node.getAttribute('dimension')) { - dim = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('dimension')); - } else if (containerDimension) { - dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension); - } - var x, y, z; - var flatCoordinates = []; - for (var i = 0, ii = coords.length; i < ii; i += dim) { - x = parseFloat(coords[i]); - y = parseFloat(coords[i + 1]); - z = (dim === 3) ? parseFloat(coords[i + 2]) : 0; - if (axisOrientation.substr(0, 2) === 'en') { - flatCoordinates.push(x, y, z); - } else { - flatCoordinates.push(y, x, z); - } - } - return flatCoordinates; +ol.format.WKT.Lexer = function(wkt) { + + /** + * @type {string} + */ + this.wkt = wkt; + + /** + * @type {number} + * @private + */ + this.index_ = -1; }; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {string} c Character. + * @return {boolean} Whether the character is alphabetic. * @private */ -ol.format.GML3.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'pos': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPos_), - 'posList': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPosList_) - } -}); +ol.format.WKT.Lexer.prototype.isAlpha_ = function(c) { + return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {string} c Character. + * @param {boolean=} opt_decimal Whether the string number + * contains a dot, i.e. is a decimal number. + * @return {boolean} Whether the character is numeric. * @private */ -ol.format.GML3.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'interior': ol.format.GML3.prototype.interiorParser_, - 'exterior': ol.format.GML3.prototype.exteriorParser_ - } -}); +ol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) { + var decimal = opt_decimal !== undefined ? opt_decimal : false; + return c >= '0' && c <= '9' || c == '.' && !decimal; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {string} c Character. + * @return {boolean} Whether the character is whitespace. * @private */ -ol.format.GML3.prototype.GEOMETRY_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint), - 'MultiPoint': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPoint), - 'LineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLineString), - 'MultiLineString': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiLineString), - 'LinearRing' : ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readLinearRing), - 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon), - 'MultiPolygon': ol.xml.makeReplacer( - ol.format.GMLBase.prototype.readMultiPolygon), - 'Surface': ol.xml.makeReplacer(ol.format.GML3.prototype.readSurface_), - 'MultiSurface': ol.xml.makeReplacer( - ol.format.GML3.prototype.readMultiSurface_), - 'Curve': ol.xml.makeReplacer(ol.format.GML3.prototype.readCurve_), - 'MultiCurve': ol.xml.makeReplacer( - ol.format.GML3.prototype.readMultiCurve_), - 'Envelope': ol.xml.makeReplacer(ol.format.GML3.prototype.readEnvelope_) - } -}); +ol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) { + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @return {string} Next string character. * @private */ -ol.format.GML3.prototype.MULTICURVE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'curveMember': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.curveMemberParser_), - 'curveMembers': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.curveMemberParser_) - } -}); +ol.format.WKT.Lexer.prototype.nextChar_ = function() { + return this.wkt.charAt(++this.index_); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Fetch and return the next token. + * @return {!ol.format.WKT.Token} Next string token. */ -ol.format.GML3.prototype.MULTISURFACE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'surfaceMember': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.surfaceMemberParser_), - 'surfaceMembers': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.surfaceMemberParser_) +ol.format.WKT.Lexer.prototype.nextToken = function() { + var c = this.nextChar_(); + var token = {position: this.index_, value: c}; + + if (c == '(') { + token.type = ol.format.WKT.TokenType.LEFT_PAREN; + } else if (c == ',') { + token.type = ol.format.WKT.TokenType.COMMA; + } else if (c == ')') { + token.type = ol.format.WKT.TokenType.RIGHT_PAREN; + } else if (this.isNumeric_(c) || c == '-') { + token.type = ol.format.WKT.TokenType.NUMBER; + token.value = this.readNumber_(); + } else if (this.isAlpha_(c)) { + token.type = ol.format.WKT.TokenType.TEXT; + token.value = this.readText_(); + } else if (this.isWhiteSpace_(c)) { + return this.nextToken(); + } else if (c === '') { + token.type = ol.format.WKT.TokenType.EOF; + } else { + throw new Error('Unexpected character: ' + c); } -}); + + return token; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @return {number} Numeric token value. * @private */ -ol.format.GML3.prototype.CURVEMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'LineString': ol.xml.makeArrayPusher( - ol.format.GMLBase.prototype.readLineString), - 'Curve': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readCurve_) - } -}); +ol.format.WKT.Lexer.prototype.readNumber_ = function() { + var c, index = this.index_; + var decimal = false; + var scientificNotation = false; + do { + if (c == '.') { + decimal = true; + } else if (c == 'e' || c == 'E') { + scientificNotation = true; + } + c = this.nextChar_(); + } while ( + this.isNumeric_(c, decimal) || + // if we haven't detected a scientific number before, 'e' or 'E' + // hint that we should continue to read + !scientificNotation && (c == 'e' || c == 'E') || + // once we know that we have a scientific number, both '-' and '+' + // are allowed + scientificNotation && (c == '-' || c == '+') + ); + return parseFloat(this.wkt.substring(index, this.index_--)); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @return {string} String token value. * @private */ -ol.format.GML3.prototype.SURFACEMEMBER_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'Polygon': ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readPolygon), - 'Surface': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readSurface_) - } -}); +ol.format.WKT.Lexer.prototype.readText_ = function() { + var c, index = this.index_; + do { + c = this.nextChar_(); + } while (this.isAlpha_(c)); + return this.wkt.substring(index, this.index_--).toUpperCase(); +}; + /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Class to parse the tokens from the WKT string. + * @param {ol.format.WKT.Lexer} lexer + * @constructor + * @protected */ -ol.format.GML3.prototype.SURFACE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'patches': ol.xml.makeReplacer(ol.format.GML3.prototype.readPatch_) - } -}); +ol.format.WKT.Parser = function(lexer) { + + /** + * @type {ol.format.WKT.Lexer} + * @private + */ + this.lexer_ = lexer; + + /** + * @type {ol.format.WKT.Token} + * @private + */ + this.token_; + + /** + * @type {number} + * @private + */ + this.dimension_ = 2; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * Fetch the next token form the lexer and replace the active token. * @private */ -ol.format.GML3.prototype.CURVE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'segments': ol.xml.makeReplacer(ol.format.GML3.prototype.readSegment_) - } -}); +ol.format.WKT.Parser.prototype.consume_ = function() { + this.token_ = this.lexer_.nextToken(); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * If the given type matches the current token, consume it. + * @param {ol.format.WKT.TokenType.<number>} type Token type. + * @return {boolean} Whether the token matches the given type. */ -ol.format.GML3.prototype.ENVELOPE_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'lowerCorner': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.readFlatPosList_), - 'upperCorner': ol.xml.makeArrayPusher( - ol.format.GML3.prototype.readFlatPosList_) +ol.format.WKT.Parser.prototype.match = function(type) { + var isMatch = this.token_.type == type; + if (isMatch) { + this.consume_(); } -}); + return isMatch; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Try to parse the tokens provided by the lexer. + * @return {ol.geom.Geometry|ol.geom.GeometryCollection} The geometry. */ -ol.format.GML3.prototype.PATCHES_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'PolygonPatch': ol.xml.makeReplacer( - ol.format.GML3.prototype.readPolygonPatch_) - } -}); +ol.format.WKT.Parser.prototype.parse = function() { + this.consume_(); + var geometry = this.parseGeometry_(); + goog.asserts.assert(this.token_.type == ol.format.WKT.TokenType.EOF, + 'token type should be end of file'); + return geometry; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @return {!(ol.geom.Geometry|ol.geom.GeometryCollection)} The geometry. * @private */ -ol.format.GML3.prototype.SEGMENTS_PARSERS_ = Object({ - 'http://www.opengis.net/gml' : { - 'LineStringSegment': ol.xml.makeReplacer( - ol.format.GML3.prototype.readLineStringSegment_) +ol.format.WKT.Parser.prototype.parseGeometry_ = function() { + var token = this.token_; + if (this.match(ol.format.WKT.TokenType.TEXT)) { + var geomType = token.value; + if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) { + var geometries = this.parseGeometryCollectionText_(); + return new ol.geom.GeometryCollection(geometries); + } else { + var parser = ol.format.WKT.Parser.GeometryParser_[geomType]; + var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType]; + if (!parser || !ctor) { + throw new Error('Invalid geometry type: ' + geomType); + } + var coordinates = parser.call(this); + return new ctor(coordinates); + } } -}); + throw new Error(this.formatErrorMessage_()); +}; /** - * @param {Node} node Node. - * @param {ol.geom.Point} value Point geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<ol.geom.Geometry>} A collection of geometries. * @private */ -ol.format.GML3.prototype.writePos_ = function(node, value, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - var axisOrientation = 'enu'; - if (srsName) { - axisOrientation = ol.proj.get(srsName).getAxisOrientation(); - } - var point = value.getCoordinates(); - var coords; - // only 2d for simple features profile - if (axisOrientation.substr(0, 2) === 'en') { - coords = (point[0] + ' ' + point[1]); - } else { - coords = (point[1] + ' ' + point[0]); +ol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var geometries = []; + do { + geometries.push(this.parseGeometry_()); + } while (this.match(ol.format.WKT.TokenType.COMMA)); + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return geometries; + } + } else if (this.isEmptyGeometry_()) { + return []; } - ol.format.XSD.writeStringTextNode(node, coords); + throw new Error(this.formatErrorMessage_()); }; /** - * @param {Array.<number>} point Point geometry. - * @param {string=} opt_srsName Optional srsName - * @return {string} + * @return {Array.<number>} All values in a point. * @private */ -ol.format.GML3.prototype.getCoords_ = function(point, opt_srsName) { - var axisOrientation = 'enu'; - if (opt_srsName) { - axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation(); +ol.format.WKT.Parser.prototype.parsePointText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var coordinates = this.parsePoint_(); + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return coordinates; + } + } else if (this.isEmptyGeometry_()) { + return null; } - return ((axisOrientation.substr(0, 2) === 'en') ? - point[0] + ' ' + point[1] : - point[1] + ' ' + point[0]); + throw new Error(this.formatErrorMessage_()); }; /** - * @param {Node} node Node. - * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} All points in a linestring. * @private */ -ol.format.GML3.prototype.writePosList_ = function(node, value, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - // only 2d for simple features profile - var points = value.getCoordinates(); - var len = points.length; - var parts = new Array(len); - var point; - for (var i = 0; i < len; ++i) { - point = points[i]; - parts[i] = this.getCoords_(point, srsName); +ol.format.WKT.Parser.prototype.parseLineStringText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var coordinates = this.parsePointList_(); + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return coordinates; + } + } else if (this.isEmptyGeometry_()) { + return []; } - ol.format.XSD.writeStringTextNode(node, parts.join(' ')); + throw new Error(this.formatErrorMessage_()); }; /** - * @param {Node} node Node. - * @param {ol.geom.Point} geometry Point geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} All points in a polygon. * @private */ -ol.format.GML3.prototype.writePoint_ = function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); +ol.format.WKT.Parser.prototype.parsePolygonText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var coordinates = this.parseLineStringTextList_(); + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return coordinates; + } + } else if (this.isEmptyGeometry_()) { + return []; } - var pos = ol.xml.createElementNS(node.namespaceURI, 'pos'); - node.appendChild(pos); - this.writePos_(pos, geometry, objectStack); + throw new Error(this.formatErrorMessage_()); }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @return {!Array.<!Array.<number>>} All points in a multipoint. * @private */ -ol.format.GML3.ENVELOPE_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) +ol.format.WKT.Parser.prototype.parseMultiPointText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var coordinates; + if (this.token_.type == ol.format.WKT.TokenType.LEFT_PAREN) { + coordinates = this.parsePointTextList_(); + } else { + coordinates = this.parsePointList_(); + } + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return coordinates; + } + } else if (this.isEmptyGeometry_()) { + return []; } + throw new Error(this.formatErrorMessage_()); }; /** - * @param {Node} node Node. - * @param {ol.Extent} extent Extent. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} All linestring points + * in a multilinestring. + * @private */ -ol.format.GML3.prototype.writeEnvelope = function(node, extent, objectStack) { - goog.asserts.assert(extent.length == 4, 'extent should have 4 items'); - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); +ol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var coordinates = this.parseLineStringTextList_(); + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return coordinates; + } + } else if (this.isEmptyGeometry_()) { + return []; } - var keys = ['lowerCorner', 'upperCorner']; - var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]]; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node}), ol.format.GML3.ENVELOPE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, - objectStack, keys, this); + throw new Error(this.formatErrorMessage_()); }; /** - * @param {Node} node Node. - * @param {ol.geom.LinearRing} geometry LinearRing geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} All polygon points in a multipolygon. * @private */ -ol.format.GML3.prototype.writeLinearRing_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); +ol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() { + if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { + var coordinates = this.parsePolygonTextList_(); + if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { + return coordinates; + } + } else if (this.isEmptyGeometry_()) { + return []; } - var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); - node.appendChild(posList); - this.writePosList_(posList, geometry, objectStack); + throw new Error(this.formatErrorMessage_()); }; /** - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node} Node. + * @return {!Array.<number>} A point. * @private */ -ol.format.GML3.prototype.RING_NODE_FACTORY_ = - function(value, objectStack, opt_nodeName) { - var context = objectStack[objectStack.length - 1]; - var parentNode = context.node; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var exteriorWritten = context['exteriorWritten']; - if (exteriorWritten === undefined) { - context['exteriorWritten'] = true; +ol.format.WKT.Parser.prototype.parsePoint_ = function() { + var coordinates = []; + for (var i = 0; i < this.dimension_; ++i) { + var token = this.token_; + if (this.match(ol.format.WKT.TokenType.NUMBER)) { + coordinates.push(token.value); + } else { + break; + } } - return ol.xml.createElementNS(parentNode.namespaceURI, - exteriorWritten !== undefined ? 'interior' : 'exterior'); + if (coordinates.length == this.dimension_) { + return coordinates; + } + throw new Error(this.formatErrorMessage_()); }; /** - * @param {Node} node Node. - * @param {ol.geom.Polygon} geometry Polygon geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} An array of points. * @private */ -ol.format.GML3.prototype.writeSurfaceOrPolygon_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (node.nodeName !== 'PolygonPatch' && srsName) { - node.setAttribute('srsName', srsName); - } - if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') { - var rings = geometry.getLinearRings(); - ol.xml.pushSerializeAndPop( - {node: node, srsName: srsName}, - ol.format.GML3.RING_SERIALIZERS_, - this.RING_NODE_FACTORY_, - rings, objectStack, undefined, this); - } else if (node.nodeName === 'Surface') { - var patches = ol.xml.createElementNS(node.namespaceURI, 'patches'); - node.appendChild(patches); - this.writeSurfacePatches_( - patches, geometry, objectStack); +ol.format.WKT.Parser.prototype.parsePointList_ = function() { + var coordinates = [this.parsePoint_()]; + while (this.match(ol.format.WKT.TokenType.COMMA)) { + coordinates.push(this.parsePoint_()); } + return coordinates; }; /** - * @param {Node} node Node. - * @param {ol.geom.LineString} geometry LineString geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} An array of points. * @private */ -ol.format.GML3.prototype.writeCurveOrLineString_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (node.nodeName !== 'LineStringSegment' && srsName) { - node.setAttribute('srsName', srsName); - } - if (node.nodeName === 'LineString' || - node.nodeName === 'LineStringSegment') { - var posList = ol.xml.createElementNS(node.namespaceURI, 'posList'); - node.appendChild(posList); - this.writePosList_(posList, geometry, objectStack); - } else if (node.nodeName === 'Curve') { - var segments = ol.xml.createElementNS(node.namespaceURI, 'segments'); - node.appendChild(segments); - this.writeCurveSegments_(segments, - geometry, objectStack); +ol.format.WKT.Parser.prototype.parsePointTextList_ = function() { + var coordinates = [this.parsePointText_()]; + while (this.match(ol.format.WKT.TokenType.COMMA)) { + coordinates.push(this.parsePointText_()); } + return coordinates; }; /** - * @param {Node} node Node. - * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} An array of points. * @private */ -ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - var surface = context['surface']; - if (srsName) { - node.setAttribute('srsName', srsName); +ol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() { + var coordinates = [this.parseLineStringText_()]; + while (this.match(ol.format.WKT.TokenType.COMMA)) { + coordinates.push(this.parseLineStringText_()); } - var polygons = geometry.getPolygons(); - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface}, - ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_, - this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons, - objectStack, undefined, this); + return coordinates; }; /** - * @param {Node} node Node. - * @param {ol.geom.MultiPoint} geometry MultiPoint geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {!Array.<!Array.<number>>} An array of points. * @private */ -ol.format.GML3.prototype.writeMultiPoint_ = function(node, geometry, - objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - if (srsName) { - node.setAttribute('srsName', srsName); +ol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() { + var coordinates = [this.parsePolygonText_()]; + while (this.match(ol.format.WKT.TokenType.COMMA)) { + coordinates.push(this.parsePolygonText_()); } - var points = geometry.getPoints(); - ol.xml.pushSerializeAndPop({node: node, srsName: srsName}, - ol.format.GML3.POINTMEMBER_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('pointMember'), points, - objectStack, undefined, this); + return coordinates; }; /** - * @param {Node} node Node. - * @param {ol.geom.MultiLineString} geometry MultiLineString geometry. - * @param {Array.<*>} objectStack Node stack. + * @return {boolean} Whether the token implies an empty geometry. * @private */ -ol.format.GML3.prototype.writeMultiCurveOrLineString_ = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var srsName = context['srsName']; - var curve = context['curve']; - if (srsName) { - node.setAttribute('srsName', srsName); +ol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() { + var isEmpty = this.token_.type == ol.format.WKT.TokenType.TEXT && + this.token_.value == ol.format.WKT.EMPTY; + if (isEmpty) { + this.consume_(); } - var lines = geometry.getLineStrings(); - ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve}, - ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_, - this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines, - objectStack, undefined, this); + return isEmpty; }; /** - * @param {Node} node Node. - * @param {ol.geom.LinearRing} ring LinearRing geometry. - * @param {Array.<*>} objectStack Node stack. + * Create an error message for an unexpected token error. + * @return {string} Error message. * @private */ -ol.format.GML3.prototype.writeRing_ = function(node, ring, objectStack) { - var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing'); - node.appendChild(linearRing); - this.writeLinearRing_(linearRing, ring, objectStack); +ol.format.WKT.Parser.prototype.formatErrorMessage_ = function() { + return 'Unexpected `' + this.token_.value + '` at position ' + + this.token_.position + ' in `' + this.lexer_.wkt + '`'; }; /** - * @param {Node} node Node. - * @param {ol.geom.Polygon} polygon Polygon geometry. - * @param {Array.<*>} objectStack Node stack. + * @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout.<string>=)} * @private */ -ol.format.GML3.prototype.writeSurfaceOrPolygonMember_ = - function(node, polygon, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var child = this.GEOMETRY_NODE_FACTORY_( - polygon, objectStack); - if (child) { - node.appendChild(child); - this.writeSurfaceOrPolygon_(child, polygon, objectStack); - } +ol.format.WKT.Parser.GeometryConstructor_ = { + 'POINT': ol.geom.Point, + 'LINESTRING': ol.geom.LineString, + 'POLYGON': ol.geom.Polygon, + 'MULTIPOINT': ol.geom.MultiPoint, + 'MULTILINESTRING': ol.geom.MultiLineString, + 'MULTIPOLYGON': ol.geom.MultiPolygon }; /** - * @param {Node} node Node. - * @param {ol.geom.Point} point Point geometry. - * @param {Array.<*>} objectStack Node stack. + * @enum {(function(): Array)} * @private */ -ol.format.GML3.prototype.writePointMember_ = - function(node, point, objectStack) { - var child = ol.xml.createElementNS(node.namespaceURI, 'Point'); - node.appendChild(child); - this.writePoint_(child, point, objectStack); +ol.format.WKT.Parser.GeometryParser_ = { + 'POINT': ol.format.WKT.Parser.prototype.parsePointText_, + 'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_, + 'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_, + 'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_, + 'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_, + 'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_ }; +goog.provide('ol.format.WMSCapabilities'); + +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.format.XLink'); +goog.require('ol.format.XML'); +goog.require('ol.format.XSD'); +goog.require('ol.xml'); + + /** - * @param {Node} node Node. - * @param {ol.geom.LineString} line LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private + * @classdesc + * Format for reading WMS capabilities data + * + * @constructor + * @extends {ol.format.XML} + * @api */ -ol.format.GML3.prototype.writeLineStringOrCurveMember_ = - function(node, line, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack); - if (child) { - node.appendChild(child); - this.writeCurveOrLineString_(child, line, objectStack); - } -}; +ol.format.WMSCapabilities = function() { + goog.base(this); -/** - * @param {Node} node Node. - * @param {ol.geom.Polygon} polygon Polygon geometry. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.GML3.prototype.writeSurfacePatches_ = - function(node, polygon, objectStack) { - var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch'); - node.appendChild(child); - this.writeSurfaceOrPolygon_(child, polygon, objectStack); + /** + * @type {string|undefined} + */ + this.version = undefined; }; +goog.inherits(ol.format.WMSCapabilities, ol.format.XML); /** - * @param {Node} node Node. - * @param {ol.geom.LineString} line LineString geometry. - * @param {Array.<*>} objectStack Node stack. - * @private + * Read a WMS capabilities document. + * + * @function + * @param {Document|Node|string} source The XML source. + * @return {Object} An object representing the WMS capabilities. + * @api */ -ol.format.GML3.prototype.writeCurveSegments_ = - function(node, line, objectStack) { - var child = ol.xml.createElementNS(node.namespaceURI, - 'LineStringSegment'); - node.appendChild(child); - this.writeCurveOrLineString_(child, line, objectStack); -}; +ol.format.WMSCapabilities.prototype.read; /** - * @param {Node} node Node. - * @param {ol.geom.Geometry|ol.Extent} geometry Geometry. - * @param {Array.<*>} objectStack Node stack. + * @param {Document} doc Document. + * @return {Object} WMS Capability object. */ -ol.format.GML3.prototype.writeGeometryElement = - function(node, geometry, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var item = goog.object.clone(context); - item.node = node; - var value; - if (goog.isArray(geometry)) { - if (context.dataProjection) { - value = ol.proj.transformExtent( - geometry, context.featureProjection, context.dataProjection); - } else { - value = geometry; +ol.format.WMSCapabilities.prototype.readFromDocument = function(doc) { + goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, + 'doc.nodeType should be DOCUMENT'); + for (var n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + return this.readFromNode(n); } - } else { - goog.asserts.assertInstanceof(geometry, ol.geom.Geometry, - 'geometry should be an ol.geom.Geometry'); - value = - ol.format.Feature.transformWithOptions(geometry, true, context); } - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), ol.format.GML3.GEOMETRY_SERIALIZERS_, - this.GEOMETRY_NODE_FACTORY_, [value], - objectStack, undefined, this); + return null; }; /** * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. + * @return {Object} WMS Capability object. */ -ol.format.GML3.prototype.writeFeatureElement = - function(node, feature, objectStack) { - var fid = feature.getId(); - if (fid) { - node.setAttribute('fid', fid); - } - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureNS = context['featureNS']; - var geometryName = feature.getGeometryName(); - if (!context.serializers) { - context.serializers = {}; - context.serializers[featureNS] = {}; - } - var properties = feature.getProperties(); - var keys = [], values = []; - for (var key in properties) { - var value = properties[key]; - if (value !== null) { - keys.push(key); - values.push(value); - if (key == geometryName || value instanceof ol.geom.Geometry) { - if (!(key in context.serializers[featureNS])) { - context.serializers[featureNS][key] = ol.xml.makeChildAppender( - this.writeGeometryElement, this); - } - } else { - if (!(key in context.serializers[featureNS])) { - context.serializers[featureNS][key] = ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode); - } - } - } - } - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), context.serializers, - ol.xml.makeSimpleNodeFactory(undefined, featureNS), - values, - objectStack, keys); +ol.format.WMSCapabilities.prototype.readFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'WMS_Capabilities' || + node.localName == 'WMT_MS_Capabilities', + 'localName should be WMS_Capabilities or WMT_MS_Capabilities'); + this.version = node.getAttribute('version').trim(); + goog.asserts.assertString(this.version, 'this.version should be a string'); + var wmsCapabilityObject = ol.xml.pushParseAndPop({ + 'version': this.version + }, ol.format.WMSCapabilities.PARSERS_, node, []); + return wmsCapabilityObject ? wmsCapabilityObject : null; }; /** - * @param {Node} node Node. - * @param {Array.<ol.Feature>} features Features. - * @param {Array.<*>} objectStack Node stack. * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Attribution object. */ -ol.format.GML3.prototype.writeFeatureMembers_ = - function(node, features, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featureNS = context['featureNS']; - var serializers = {}; - serializers[featureNS] = {}; - serializers[featureNS][featureType] = ol.xml.makeChildAppender( - this.writeFeatureElement, this); - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - (item), - serializers, - ol.xml.makeSimpleNodeFactory(featureType, featureNS), features, - objectStack); +ol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Attribution', + 'localName should be Attribution'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack); }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object} Bounding box object. */ -ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'surfaceMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygonMember_), - 'polygonMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygonMember_) - } +ol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'BoundingBox', + 'localName should be BoundingBox'); + + var extent = [ + ol.format.XSD.readDecimalString(node.getAttribute('minx')), + ol.format.XSD.readDecimalString(node.getAttribute('miny')), + ol.format.XSD.readDecimalString(node.getAttribute('maxx')), + ol.format.XSD.readDecimalString(node.getAttribute('maxy')) + ]; + + var resolutions = [ + ol.format.XSD.readDecimalString(node.getAttribute('resx')), + ol.format.XSD.readDecimalString(node.getAttribute('resy')) + ]; + + return { + 'crs': node.getAttribute('CRS'), + 'extent': extent, + 'res': resolutions + }; }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {ol.Extent|undefined} Bounding box object. */ -ol.format.GML3.POINTMEMBER_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'pointMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writePointMember_) +ol.format.WMSCapabilities.readEXGeographicBoundingBox_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'EX_GeographicBoundingBox', + 'localName should be EX_GeographicBoundingBox'); + var geographicBoundingBox = ol.xml.pushParseAndPop( + {}, + ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_, + node, objectStack); + if (!geographicBoundingBox) { + return undefined; + } + var westBoundLongitude = /** @type {number|undefined} */ + (geographicBoundingBox['westBoundLongitude']); + var southBoundLatitude = /** @type {number|undefined} */ + (geographicBoundingBox['southBoundLatitude']); + var eastBoundLongitude = /** @type {number|undefined} */ + (geographicBoundingBox['eastBoundLongitude']); + var northBoundLatitude = /** @type {number|undefined} */ + (geographicBoundingBox['northBoundLatitude']); + if (westBoundLongitude === undefined || southBoundLatitude === undefined || + eastBoundLongitude === undefined || northBoundLatitude === undefined) { + return undefined; } + return /** @type {ol.Extent} */ ([ + westBoundLongitude, southBoundLatitude, + eastBoundLongitude, northBoundLatitude + ]); }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private + * @return {Object|undefined} Capability object. */ -ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'lineStringMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeLineStringOrCurveMember_), - 'curveMember': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeLineStringOrCurveMember_) - } +ol.format.WMSCapabilities.readCapability_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Capability', + 'localName should be Capability'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack); }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private + * @return {Object|undefined} Service object. */ -ol.format.GML3.RING_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'exterior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_), - 'interior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_) - } +ol.format.WMSCapabilities.readService_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Service', + 'localName should be Service'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack); }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private + * @return {Object|undefined} Contact information object. */ -ol.format.GML3.GEOMETRY_SERIALIZERS_ = { - 'http://www.opengis.net/gml': { - 'Curve': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeCurveOrLineString_), - 'MultiCurve': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiCurveOrLineString_), - 'Point': ol.xml.makeChildAppender(ol.format.GML3.prototype.writePoint_), - 'MultiPoint': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiPoint_), - 'LineString': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeCurveOrLineString_), - 'MultiLineString': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiCurveOrLineString_), - 'LinearRing': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeLinearRing_), - 'Polygon': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygon_), - 'MultiPolygon': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_), - 'Surface': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeSurfaceOrPolygon_), - 'MultiSurface': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_), - 'Envelope': ol.xml.makeChildAppender( - ol.format.GML3.prototype.writeEnvelope) - } +ol.format.WMSCapabilities.readContactInformation_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType shpuld be ELEMENT'); + goog.asserts.assert(node.localName == 'ContactInformation', + 'localName should be ContactInformation'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_, + node, objectStack); }; /** - * @const - * @type {Object.<string, string>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. * @private + * @return {Object|undefined} Contact person object. */ -ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = { - 'MultiLineString': 'lineStringMember', - 'MultiCurve': 'curveMember', - 'MultiPolygon': 'polygonMember', - 'MultiSurface': 'surfaceMember' +ol.format.WMSCapabilities.readContactPersonPrimary_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ContactPersonPrimary', + 'localName should be ContactPersonPrimary'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_, + node, objectStack); }; /** - * @const - * @param {*} value Value. + * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. * @private + * @return {Object|undefined} Contact address object. */ -ol.format.GML3.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = - function(value, objectStack, opt_nodeName) { - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be a node'); - return ol.xml.createElementNS('http://www.opengis.net/gml', - ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]); +ol.format.WMSCapabilities.readContactAddress_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'ContactAddress', + 'localName should be ContactAddress'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_, + node, objectStack); }; /** - * @const - * @param {*} value Value. + * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. * @private + * @return {Array.<string>|undefined} Format array. */ -ol.format.GML3.prototype.GEOMETRY_NODE_FACTORY_ = - function(value, objectStack, opt_nodeName) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var multiSurface = context['multiSurface']; - var surface = context['surface']; - var curve = context['curve']; - var multiCurve = context['multiCurve']; - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be a node'); - var nodeName; - if (!goog.isArray(value)) { - goog.asserts.assertInstanceof(value, ol.geom.Geometry, - 'value should be an ol.geom.Geometry'); - nodeName = value.getType(); - if (nodeName === 'MultiPolygon' && multiSurface === true) { - nodeName = 'MultiSurface'; - } else if (nodeName === 'Polygon' && surface === true) { - nodeName = 'Surface'; - } else if (nodeName === 'LineString' && curve === true) { - nodeName = 'Curve'; - } else if (nodeName === 'MultiLineString' && multiCurve === true) { - nodeName = 'MultiCurve'; - } - } else { - nodeName = 'Envelope'; - } - return ol.xml.createElementNS('http://www.opengis.net/gml', - nodeName); +ol.format.WMSCapabilities.readException_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Exception', + 'localName should be Exception'); + return ol.xml.pushParseAndPop( + [], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack); }; /** - * Encode a geometry in GML 3.1.1 Simple Features. - * - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {Object|undefined} Layer object. */ -ol.format.GML3.prototype.writeGeometryNode = function(geometry, opt_options) { - opt_options = this.adaptOptions(opt_options); - var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom'); - var context = {node: geom, srsName: this.srsName, - curve: this.curve_, surface: this.surface_, - multiSurface: this.multiSurface_, multiCurve: this.multiCurve_}; - if (opt_options) { - goog.object.extend(context, opt_options); - } - this.writeGeometryElement(geom, geometry, [context]); - return geom; +ol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack); }; /** - * Encode an array of features in GML 3.1.1 Simple Features. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {string} Result. - * @api stable + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Layer object. */ -ol.format.GML3.prototype.writeFeatures; +ol.format.WMSCapabilities.readLayer_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); + var parentLayerObject = /** @type {Object.<string,*>} */ + (objectStack[objectStack.length - 1]); + var layerObject = /** @type {Object.<string,*>} */ (ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack)); -/** - * Encode an array of features in the GML 3.1.1 format as an XML node. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.GML3.prototype.writeFeaturesNode = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var node = ol.xml.createElementNS('http://www.opengis.net/gml', - 'featureMembers'); - ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', this.schemaLocation); - var context = { - srsName: this.srsName, - curve: this.curve_, - surface: this.surface_, - multiSurface: this.multiSurface_, - multiCurve: this.multiCurve_, - featureNS: this.featureNS, - featureType: this.featureType - }; - if (opt_options) { - goog.object.extend(context, opt_options); + if (!layerObject) { + return undefined; } - this.writeFeatureMembers_(node, features, [context]); - return node; -}; - - + var queryable = + ol.format.XSD.readBooleanString(node.getAttribute('queryable')); + if (queryable === undefined) { + queryable = parentLayerObject['queryable']; + } + layerObject['queryable'] = queryable !== undefined ? queryable : false; -/** - * @classdesc - * Feature format for reading and writing data in the GML format - * version 3.1.1. - * Currently only supports GML 3.1.1 Simple Features profile. - * - * @constructor - * @param {olx.format.GMLOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.GMLBase} - * @api stable - */ -ol.format.GML = ol.format.GML3; + var cascaded = ol.format.XSD.readNonNegativeIntegerString( + node.getAttribute('cascaded')); + if (cascaded === undefined) { + cascaded = parentLayerObject['cascaded']; + } + layerObject['cascaded'] = cascaded; + var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque')); + if (opaque === undefined) { + opaque = parentLayerObject['opaque']; + } + layerObject['opaque'] = opaque !== undefined ? opaque : false; -/** - * Encode an array of features in GML 3.1.1 Simple Features. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {string} Result. - * @api stable - */ -ol.format.GML.prototype.writeFeatures; + var noSubsets = + ol.format.XSD.readBooleanString(node.getAttribute('noSubsets')); + if (noSubsets === undefined) { + noSubsets = parentLayerObject['noSubsets']; + } + layerObject['noSubsets'] = noSubsets !== undefined ? noSubsets : false; + var fixedWidth = + ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth')); + if (!fixedWidth) { + fixedWidth = parentLayerObject['fixedWidth']; + } + layerObject['fixedWidth'] = fixedWidth; -/** - * Encode an array of features in the GML 3.1.1 format as an XML node. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api - */ -ol.format.GML.prototype.writeFeaturesNode; + var fixedHeight = + ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight')); + if (!fixedHeight) { + fixedHeight = parentLayerObject['fixedHeight']; + } + layerObject['fixedHeight'] = fixedHeight; -goog.provide('ol.format.GPX'); + // See 7.2.4.8 + var addKeys = ['Style', 'CRS', 'AuthorityURL']; + addKeys.forEach(function(key) { + if (key in parentLayerObject) { + var childValue = goog.object.setIfUndefined(layerObject, key, []); + childValue = childValue.concat(parentLayerObject[key]); + layerObject[key] = childValue; + } + }); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.Feature'); -goog.require('ol.array'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.Point'); -goog.require('ol.proj'); -goog.require('ol.xml'); + var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension', + 'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator']; + replaceKeys.forEach(function(key) { + if (!(key in layerObject)) { + var parentValue = parentLayerObject[key]; + layerObject[key] = parentValue; + } + }); + return layerObject; +}; /** - * @classdesc - * Feature format for reading and writing data in the GPX format. - * - * @constructor - * @extends {ol.format.XMLFeature} - * @param {olx.format.GPXOptions=} opt_options Options. - * @api stable + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object} Dimension object. */ -ol.format.GPX = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); +ol.format.WMSCapabilities.readDimension_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Dimension', + 'localName should be Dimension'); + var dimensionObject = { + 'name': node.getAttribute('name'), + 'units': node.getAttribute('units'), + 'unitSymbol': node.getAttribute('unitSymbol'), + 'default': node.getAttribute('default'), + 'multipleValues': ol.format.XSD.readBooleanString( + node.getAttribute('multipleValues')), + 'nearestValue': ol.format.XSD.readBooleanString( + node.getAttribute('nearestValue')), + 'current': ol.format.XSD.readBooleanString(node.getAttribute('current')), + 'values': ol.format.XSD.readString(node) + }; + return dimensionObject; +}; - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); - /** - * @type {function(ol.Feature, Node)|undefined} - * @private - */ - this.readExtensions_ = options.readExtensions; +/** + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Online resource object. + */ +ol.format.WMSCapabilities.readFormatOnlineresource_ = + function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_, + node, objectStack); }; -goog.inherits(ol.format.GPX, ol.format.XMLFeature); /** - * @const * @private - * @type {Array.<string>} + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Request object. */ -ol.format.GPX.NAMESPACE_URIS_ = [ - null, - 'http://www.topografix.com/GPX/1/0', - 'http://www.topografix.com/GPX/1/1' -]; +ol.format.WMSCapabilities.readRequest_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Request', + 'localName should be Request'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack); +}; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {Node} node Node. - * @param {Object} values Values. * @private - * @return {Array.<number>} Flat coordinates. + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} DCP type object. */ -ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) { +ol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - flatCoordinates.push( - parseFloat(node.getAttribute('lon')), - parseFloat(node.getAttribute('lat'))); - if ('ele' in values) { - flatCoordinates.push(/** @type {number} */ (values['ele'])); - delete values['ele']; - } else { - flatCoordinates.push(0); - } - if ('time' in values) { - flatCoordinates.push(/** @type {number} */ (values['time'])); - delete values['time']; - } else { - flatCoordinates.push(0); - } - return flatCoordinates; + goog.asserts.assert(node.localName == 'DCPType', + 'localName should be DCPType'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack); }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} HTTP object. */ -ol.format.GPX.parseLink_ = function(node, objectStack) { +ol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'link', 'localName should be link'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var href = node.getAttribute('href'); - if (href !== null) { - values['link'] = href; - } - ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack); + goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack); }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Operation type object. */ -ol.format.GPX.parseExtensions_ = function(node, objectStack) { +ol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'extensions', - 'localName should be extensions'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - values['extensionsNode_'] = node; + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack); }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Online resource object. */ -ol.format.GPX.parseRtePt_ = function(node, objectStack) { +ol.format.WMSCapabilities.readSizedFormatOnlineresource_ = + function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'rtept', 'localName should be rtept'); - var values = ol.xml.pushParseAndPop( - {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack); - if (values) { - var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var flatCoordinates = /** @type {Array.<number>} */ - (rteValues['flatCoordinates']); - ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); + var formatOnlineresource = + ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); + if (formatOnlineresource) { + var size = [ + ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')), + ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height')) + ]; + formatOnlineresource['size'] = size; + return formatOnlineresource; } + return undefined; }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Authority URL object. */ -ol.format.GPX.parseTrkPt_ = function(node, objectStack) { +ol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'trkpt', 'localName should be trkpt'); - var values = ol.xml.pushParseAndPop( - {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack); - if (values) { - var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var flatCoordinates = /** @type {Array.<number>} */ - (trkValues['flatCoordinates']); - ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); + goog.asserts.assert(node.localName == 'AuthorityURL', + 'localName should be AuthorityURL'); + var authorityObject = + ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); + if (authorityObject) { + authorityObject['name'] = node.getAttribute('name'); + return authorityObject; } + return undefined; }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Metadata URL object. */ -ol.format.GPX.parseTrkSeg_ = function(node, objectStack) { +ol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'trkseg', - 'localName should be trkseg'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack); - var flatCoordinates = /** @type {Array.<number>} */ - (values['flatCoordinates']); - var ends = /** @type {Array.<number>} */ (values['ends']); - ends.push(flatCoordinates.length); + goog.asserts.assert(node.localName == 'MetadataURL', + 'localName should be MetadataURL'); + var metadataObject = + ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); + if (metadataObject) { + metadataObject['type'] = node.getAttribute('type'); + return metadataObject; + } + return undefined; }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Track. + * @return {Object|undefined} Style object. */ -ol.format.GPX.readRte_ = function(node, objectStack) { +ol.format.WMSCapabilities.readStyle_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'rte', 'localName should be rte'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var values = ol.xml.pushParseAndPop({ - 'flatCoordinates': [] - }, ol.format.GPX.RTE_PARSERS_, node, objectStack); - if (!values) { - return undefined; - } - var flatCoordinates = /** @type {Array.<number>} */ - (values['flatCoordinates']); - delete values['flatCoordinates']; - var geometry = new ol.geom.LineString(null); - geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setProperties(values); - return feature; + goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); + return ol.xml.pushParseAndPop( + {}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack); }; /** + * @private * @param {Node} node Node. * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Track. + * @return {Array.<string>|undefined} Keyword list. */ -ol.format.GPX.readTrk_ = function(node, objectStack) { +ol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) { goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'trk', 'localName should be trk'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var values = ol.xml.pushParseAndPop({ - 'flatCoordinates': [], - 'ends': [] - }, ol.format.GPX.TRK_PARSERS_, node, objectStack); - if (!values) { - return undefined; - } - var flatCoordinates = /** @type {Array.<number>} */ - (values['flatCoordinates']); - delete values['flatCoordinates']; - var ends = /** @type {Array.<number>} */ (values['ends']); - delete values['ends']; - var geometry = new ol.geom.MultiLineString(null); - geometry.setFlatCoordinates( - ol.geom.GeometryLayout.XYZM, flatCoordinates, ends); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setProperties(values); - return feature; + goog.asserts.assert(node.localName == 'KeywordList', + 'localName should be KeywordList'); + return ol.xml.pushParseAndPop( + [], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @const + * @private + * @type {Array.<string>} + */ +ol.format.WMSCapabilities.NAMESPACE_URIS_ = [ + null, + 'http://www.opengis.net/wms' +]; + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Service': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readService_), + 'Capability': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readCapability_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Request': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readRequest_), + 'Exception': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readException_), + 'Layer': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readCapabilityLayer_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'KeywordList': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readKeywordList_), + 'OnlineResource': ol.xml.makeObjectPropertySetter( + ol.format.XLink.readHref), + 'ContactInformation': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readContactInformation_), + 'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'AccessConstraints': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'LayerLimit': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MaxWidth': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MaxHeight': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'ContactPersonPrimary': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readContactPersonPrimary_), + 'ContactPosition': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'ContactAddress': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readContactAddress_), + 'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'ContactPerson': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'ContactOrganization': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'StateOrProvince': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'KeywordList': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readKeywordList_), + 'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), + 'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readEXGeographicBoundingBox_), + 'BoundingBox': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readBoundingBox_), + 'Dimension': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readDimension_), + 'Attribution': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readAttribution_), + 'AuthorityURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readAuthorityURL_), + 'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), + 'MetadataURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readMetadataURL_), + 'DataURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readFormatOnlineresource_), + 'FeatureListURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readFormatOnlineresource_), + 'Style': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readStyle_), + 'MinScaleDenominator': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal), + 'MaxScaleDenominator': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal), + 'Layer': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readLayer_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @private + */ +ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'OnlineResource': ol.xml.makeObjectPropertySetter( + ol.format.XLink.readHref), + 'LogoURL': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readSizedFormatOnlineresource_) + }); + + +/** + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private - * @return {ol.Feature|undefined} Waypoint. */ -ol.format.GPX.readWpt_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'wpt', 'localName should be wpt'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var values = ol.xml.pushParseAndPop( - {}, ol.format.GPX.WPT_PARSERS_, node, objectStack); - if (!values) { - return undefined; - } - var coordinates = ol.format.GPX.appendCoordinate_([], node, values); - var geometry = new ol.geom.Point( - coordinates, ol.geom.GeometryLayout.XYZM); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setProperties(values); - return feature; -}; +ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ = + ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'westBoundLongitude': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal), + 'eastBoundLongitude': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal), + 'southBoundLatitude': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal), + 'northBoundLatitude': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal) + }); /** * @const - * @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.FEATURE_READER_ = { - 'rte': ol.format.GPX.readRte_, - 'trk': ol.format.GPX.readTrk_, - 'wpt': ol.format.GPX.readWpt_ -}; +ol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'GetCapabilities': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readOperationType_), + 'GetMap': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readOperationType_), + 'GetFeatureInfo': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readOperationType_) + }); /** @@ -95956,11 +111471,11 @@ ol.format.GPX.FEATURE_READER_ = { * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_), - 'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_), - 'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_) +ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), + 'DCPType': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readDCPType_) }); @@ -95969,12 +111484,10 @@ ol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS( * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'text': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'), - 'type': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType') +ol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'HTTP': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readHTTP_) }); @@ -95983,18 +111496,12 @@ ol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS( * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'link': ol.format.GPX.parseLink_, - 'number': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), - 'extensions': ol.format.GPX.parseExtensions_, - 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'rtept': ol.format.GPX.parseRtePt_ +ol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Get': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readFormatOnlineresource_), + 'Post': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readFormatOnlineresource_) }); @@ -96003,10 +111510,17 @@ ol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS( * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) +ol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'LegendURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMSCapabilities.readSizedFormatOnlineresource_), + 'StyleSheetURL': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readFormatOnlineresource_), + 'StyleURL': ol.xml.makeObjectPropertySetter( + ol.format.WMSCapabilities.readFormatOnlineresource_) }); @@ -96015,18 +111529,11 @@ ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS( * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'link': ol.format.GPX.parseLink_, - 'number': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), - 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'extensions': ol.format.GPX.parseExtensions_, - 'trkseg': ol.format.GPX.parseTrkSeg_ +ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ = + ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'OnlineResource': ol.xml.makeObjectPropertySetter( + ol.format.XLink.readHref) }); @@ -96035,8591 +111542,9481 @@ ol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS( * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'trkpt': ol.format.GPX.parseTrkPt_ +ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMSCapabilities.NAMESPACE_URIS_, { + 'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString) }); +goog.provide('ol.format.WMSGetFeatureInfo'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol.format.GML2'); +goog.require('ol.format.XMLFeature'); +goog.require('ol.xml'); + + + +/** + * @classdesc + * Format for reading WMSGetFeatureInfo format. It uses + * {@link ol.format.GML2} to read features. + * + * @constructor + * @extends {ol.format.XMLFeature} + * @api + */ +ol.format.WMSGetFeatureInfo = function() { + + /** + * @private + * @type {string} + */ + this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver'; + + + /** + * @private + * @type {ol.format.GML2} + */ + this.gmlFormat_ = new ol.format.GML2(); + + goog.base(this); +}; +goog.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature); + /** * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @type {string} * @private */ -ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) - }); +ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature'; /** * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @type {string} * @private */ -ol.format.GPX.WPT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime), - 'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'link': ol.format.GPX.parseLink_, - 'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'sat': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'ageofdgpsdata': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'dgpsid': - ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), - 'extensions': ol.format.GPX.parseExtensions_ - }); +ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer'; /** - * @param {Array.<ol.Feature>} features + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Array.<ol.Feature>} Features. * @private */ -ol.format.GPX.prototype.handleReadExtensions_ = function(features) { - if (!features) { - features = []; +ol.format.WMSGetFeatureInfo.prototype.readFeatures_ = + function(node, objectStack) { + + node.namespaceURI = this.featureNS_; + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + var localName = ol.xml.getLocalName(node); + /** @type {Array.<ol.Feature>} */ + var features = []; + if (node.childNodes.length === 0) { + return features; } - for (var i = 0, ii = features.length; i < ii; ++i) { - var feature = features[i]; - if (this.readExtensions_) { - var extensionsNode = feature.get('extensionsNode_') || null; - this.readExtensions_(feature, extensionsNode); + if (localName == 'msGMLOutput') { + for (var i = 0, ii = node.childNodes.length; i < ii; i++) { + var layer = node.childNodes[i]; + if (layer.nodeType !== goog.dom.NodeType.ELEMENT) { + continue; + } + var context = objectStack[0]; + goog.asserts.assert(goog.isObject(context), + 'context should be an Object'); + + goog.asserts.assert(layer.localName.indexOf( + ol.format.WMSGetFeatureInfo.layerIdentifier_) >= 0, + 'localName of layer node should match layerIdentifier'); + + var toRemove = ol.format.WMSGetFeatureInfo.layerIdentifier_; + var featureType = layer.localName.replace(toRemove, '') + + ol.format.WMSGetFeatureInfo.featureIdentifier_; + + context['featureType'] = featureType; + context['featureNS'] = this.featureNS_; + + var parsers = {}; + parsers[featureType] = ol.xml.makeArrayPusher( + this.gmlFormat_.readFeatureElement, this.gmlFormat_); + var parsersNS = ol.xml.makeStructureNS( + [context['featureNS'], null], parsers); + layer.namespaceURI = this.featureNS_; + var layerFeatures = ol.xml.pushParseAndPop( + [], parsersNS, layer, objectStack, this.gmlFormat_); + if (layerFeatures) { + goog.array.extend(features, layerFeatures); + } + } + } + if (localName == 'FeatureCollection') { + var gmlFeatures = ol.xml.pushParseAndPop([], + this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node, + [{}], this.gmlFormat_); + if (gmlFeatures) { + features = gmlFeatures; } - feature.set('extensionsNode_', undefined); } + return features; }; /** - * Read the first feature from a GPX source. + * Read all features from a WMSGetFeatureInfo response. * * @function * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. + * @param {olx.format.ReadOptions=} opt_options Options. + * @return {Array.<ol.Feature>} Features. * @api stable */ -ol.format.GPX.prototype.readFeature; +ol.format.WMSGetFeatureInfo.prototype.readFeatures; /** * @inheritDoc */ -ol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) { - return null; - } - var featureReader = ol.format.GPX.FEATURE_READER_[node.localName]; - if (!featureReader) { - return null; - } - var feature = featureReader(node, [this.getReadOptions(node, opt_options)]); - if (!feature) { - return null; +ol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode = + function(node, opt_options) { + var options = { + 'featureType': this.featureType, + 'featureNS': this.featureNS + }; + if (opt_options) { + goog.object.extend(options, this.getReadOptions(node, opt_options)); } - this.handleReadExtensions_([feature]); - return feature; + return this.readFeatures_(node, [options]); }; +goog.provide('ol.format.WMTSCapabilities'); + +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('ol.extent'); +goog.require('ol.format.OWS'); +goog.require('ol.format.XLink'); +goog.require('ol.format.XML'); +goog.require('ol.format.XSD'); +goog.require('ol.xml'); + + /** - * Read all features from a GPX source. + * @classdesc + * Format for reading WMTS capabilities data. + * + * @constructor + * @extends {ol.format.XML} + * @api + */ +ol.format.WMTSCapabilities = function() { + goog.base(this); + + /** + * @type {ol.format.OWS} + * @private + */ + this.owsParser_ = new ol.format.OWS(); +}; +goog.inherits(ol.format.WMTSCapabilities, ol.format.XML); + + +/** + * Read a WMTS capabilities document. * * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable + * @param {Document|Node|string} source The XML source. + * @return {Object} An object representing the WMTS capabilities. + * @api */ -ol.format.GPX.prototype.readFeatures; +ol.format.WMTSCapabilities.prototype.read; /** - * @inheritDoc + * @param {Document} doc Document. + * @return {Object} WMTS Capability object. */ -ol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) { - return []; - } - if (node.localName == 'gpx') { - var features = ol.xml.pushParseAndPop( - /** @type {Array.<ol.Feature>} */ ([]), ol.format.GPX.GPX_PARSERS_, - node, [this.getReadOptions(node, opt_options)]); - if (features) { - this.handleReadExtensions_(features); - return features; - } else { - return []; +ol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) { + goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, + 'doc.nodeType should be DOCUMENT'); + for (var n = doc.firstChild; n; n = n.nextSibling) { + if (n.nodeType == goog.dom.NodeType.ELEMENT) { + return this.readFromNode(n); } } - return []; + return null; }; /** - * Read the projection from a GPX source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable + * @param {Node} node Node. + * @return {Object} WMTS Capability object. */ -ol.format.GPX.prototype.readProjection; +ol.format.WMTSCapabilities.prototype.readFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Capabilities', + 'localName should be Capabilities'); + this.version = node.getAttribute('version').trim(); + goog.asserts.assertString(this.version, 'this.version should be a string'); + var WMTSCapabilityObject = this.owsParser_.readFromNode(node); + if (!WMTSCapabilityObject) { + return null; + } + WMTSCapabilityObject['version'] = this.version; + WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject, + ol.format.WMTSCapabilities.PARSERS_, node, []); + return WMTSCapabilityObject ? WMTSCapabilityObject : null; +}; /** + * @private * @param {Node} node Node. - * @param {string} value Value for the link's `href` attribute. - * @param {Array.<*>} objectStack Node stack. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Attribution object. + */ +ol.format.WMTSCapabilities.readContents_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Contents', + 'localName should be Contents'); + + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack); +}; + + +/** * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Layers object. */ -ol.format.GPX.writeLink_ = function(node, value, objectStack) { - node.setAttribute('href', value); - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var properties = context['properties']; - var link = [ - properties['linkText'], - properties['linkType'] - ]; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ ({node: node}), - ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - link, objectStack, ol.format.GPX.LINK_SEQUENCE_); +ol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, + 'node.nodeType should be ELEMENT'); + goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack); }; /** + * @private * @param {Node} node Node. - * @param {ol.Coordinate} coordinate Coordinate. * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Tile Matrix Set object. + */ +ol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) { + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack); +}; + + +/** * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Style object. */ -ol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var parentNode = context.node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - var namespaceURI = parentNode.namespaceURI; - var properties = context['properties']; - //FIXME Projection handling - ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]); - ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]); - var geometryLayout = context['geometryLayout']; - /* jshint -W086 */ - switch (geometryLayout) { - case ol.geom.GeometryLayout.XYZM: - if (coordinate[3] !== 0) { - properties['time'] = coordinate[3]; - } - case ol.geom.GeometryLayout.XYZ: - if (coordinate[2] !== 0) { - properties['ele'] = coordinate[2]; - } - break; - case ol.geom.GeometryLayout.XYM: - if (coordinate[2] !== 0) { - properties['time'] = coordinate[2]; - } +ol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) { + var style = ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack); + if (!style) { + return undefined; } - /* jshint +W086 */ - var orderedKeys = ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: node, 'properties': properties}), - ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); + var isDefault = node.getAttribute('isDefault') === 'true'; + style['isDefault'] = isDefault; + return style; + +}; + + +/** + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Tile Matrix Set Link object. + */ +ol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node, + objectStack) { + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack); +}; + + +/** + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} Dimension object. + */ +ol.format.WMTSCapabilities.readDimensions_ = function(node, objectStack) { + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.DIMENSION_PARSERS_, node, objectStack); }; /** + * @private * @param {Node} node Node. - * @param {ol.Feature} feature Feature. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Resource URL object. */ -ol.format.GPX.writeRte_ = function(node, feature, objectStack) { - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var properties = feature.getProperties(); - var context = {node: node, 'properties': properties}; - var geometry = feature.getGeometry(); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - geometry = /** @type {ol.geom.LineString} */ - (ol.format.Feature.transformWithOptions(geometry, true, options)); - context['geometryLayout'] = geometry.getLayout(); - properties['rtept'] = geometry.getCoordinates(); +ol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) { + var format = node.getAttribute('format'); + var template = node.getAttribute('template'); + var resourceType = node.getAttribute('resourceType'); + var resource = {}; + if (format) { + resource['format'] = format; } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), - ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); + if (template) { + resource['template'] = template; + } + if (resourceType) { + resource['resourceType'] = resourceType; + } + return resource; }; /** + * @private * @param {Node} node Node. - * @param {ol.Feature} feature Feature. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} WGS84 BBox object. */ -ol.format.GPX.writeTrk_ = function(node, feature, objectStack) { - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var properties = feature.getProperties(); - var context = {node: node, 'properties': properties}; - var geometry = feature.getGeometry(); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - geometry = /** @type {ol.geom.MultiLineString} */ - (ol.format.Feature.transformWithOptions(geometry, true, options)); - properties['trkseg'] = geometry.getLineStrings(); +ol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) { + var coordinates = ol.xml.pushParseAndPop([], + ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack); + if (coordinates.length != 2) { + return undefined; } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), - ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); + return ol.extent.boundingExtent(coordinates); }; /** + * @private * @param {Node} node Node. - * @param {ol.geom.LineString} lineString LineString. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Legend object. */ -ol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) { - var context = {node: node, 'geometryLayout': lineString.getLayout(), - 'properties': {}}; - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context), - ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_, - lineString.getCoordinates(), objectStack); +ol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) { + var legend = {}; + legend['format'] = node.getAttribute('format'); + legend['href'] = ol.format.XLink.readHref(node); + return legend; }; /** + * @private * @param {Node} node Node. - * @param {ol.Feature} feature Feature. * @param {Array.<*>} objectStack Object stack. - * @private + * @return {Object|undefined} Coordinates object. */ -ol.format.GPX.writeWpt_ = function(node, feature, objectStack) { - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - context['properties'] = feature.getProperties(); - var geometry = feature.getGeometry(); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - geometry = /** @type {ol.geom.Point} */ - (ol.format.Feature.transformWithOptions(geometry, true, options)); - context['geometryLayout'] = geometry.getLayout(); - ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack); +ol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) { + var coordinates = ol.format.XSD.readString(node).split(' '); + if (!coordinates || coordinates.length != 2) { + return undefined; + } + var x = +coordinates[0]; + var y = +coordinates[1]; + if (isNaN(x) || isNaN(y)) { + return undefined; } + return [x, y]; +}; + + +/** + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} TileMatrix object. + */ +ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) { + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack); }; /** * @const + * @private * @type {Array.<string>} + */ +ol.format.WMTSCapabilities.NAMESPACE_URIS_ = [ + null, + 'http://www.opengis.net/wmts/1.0' +]; + + +/** + * @const * @private + * @type {Array.<string>} */ -ol.format.GPX.LINK_SEQUENCE_ = ['text', 'type']; +ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [ + null, + 'http://www.opengis.net/ows/1.1' +]; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) +ol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'Contents': ol.xml.makeObjectPropertySetter( + ol.format.WMTSCapabilities.readContents_) }); /** * @const - * @type {Object.<string, Array.<string>>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, [ - 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept' - ]); +ol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'Layer': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readLayer_), + 'TileMatrixSet': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readTileMatrixSet_) + }); /** * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), - 'number': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender( - ol.format.GPX.writeWptType_)) - }); +ol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'Style': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readStyle_), + 'Format': ol.xml.makeObjectPropertyPusher( + ol.format.XSD.readString), + 'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readTileMatrixSetLink_), + 'Dimension': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readDimensions_), + 'ResourceURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readResourceUrl_) + }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { + 'Title': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'Abstract': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'WGS84BoundingBox': ol.xml.makeObjectPropertySetter( + ol.format.WMTSCapabilities.readWgs84BoundingBox_), + 'Identifier': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + })); /** * @const - * @type {Object.<string, Array.<string>>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, [ - 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg' - ]); +ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'LegendURL': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readLegendUrl_) + }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { + 'Title': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'Identifier': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + })); /** * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), - 'number': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender( - ol.format.GPX.writeTrkSeg_)) +ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'TileMatrixSet': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) }); /** * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt'); +ol.format.WMTSCapabilities.DIMENSION_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'Default': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'Value': ol.xml.makeObjectPropertyPusher( + ol.format.XSD.readString) + }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { + 'Identifier': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + })); /** * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_) +ol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { + 'LowerCorner': ol.xml.makeArrayPusher( + ol.format.WMTSCapabilities.readCoordinates_), + 'UpperCorner': ol.xml.makeArrayPusher( + ol.format.WMTSCapabilities.readCoordinates_) }); /** * @const - * @type {Object.<string, Array.<string>>} + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, [ - 'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src', - 'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop', - 'ageofdgpsdata', 'dgpsid' - ]); +ol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'WellKnownScaleSet': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'TileMatrix': ol.xml.makeObjectPropertyPusher( + ol.format.WMTSCapabilities.readTileMatrix_) + }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { + 'SupportedCRS': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'Identifier': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + })); /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @const + * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode), - 'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'geoidheight': ol.xml.makeChildAppender( - ol.format.XSD.writeDecimalTextNode), - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_), - 'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'sat': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode), - 'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'ageofdgpsdata': ol.xml.makeChildAppender( - ol.format.XSD.writeDecimalTextNode), - 'dgpsid': ol.xml.makeChildAppender( - ol.format.XSD.writeNonNegativeIntegerTextNode) - }); +ol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'TopLeftCorner': ol.xml.makeObjectPropertySetter( + ol.format.WMTSCapabilities.readCoordinates_), + 'ScaleDenominator': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readDecimal), + 'TileWidth': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'TileHeight': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MatrixWidth': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MatrixHeight': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger) + }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { + 'Identifier': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString) + })); + +goog.provide('ol.sphere.WGS84'); + +goog.require('ol.Sphere'); + + +/** + * A sphere with radius equal to the semi-major axis of the WGS84 ellipsoid. + * @const + * @type {ol.Sphere} + */ +ol.sphere.WGS84 = new ol.Sphere(6378137); + +// FIXME handle geolocation not supported + +goog.provide('ol.Geolocation'); +goog.provide('ol.GeolocationProperty'); + +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.Coordinate'); +goog.require('ol.Object'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.Polygon'); +goog.require('ol.has'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.sphere.WGS84'); + + +/** + * @enum {string} + */ +ol.GeolocationProperty = { + ACCURACY: 'accuracy', + ACCURACY_GEOMETRY: 'accuracyGeometry', + ALTITUDE: 'altitude', + ALTITUDE_ACCURACY: 'altitudeAccuracy', + HEADING: 'heading', + POSITION: 'position', + PROJECTION: 'projection', + SPEED: 'speed', + TRACKING: 'tracking', + TRACKING_OPTIONS: 'trackingOptions' +}; + + + +/** + * @classdesc + * Helper class for providing HTML5 Geolocation capabilities. + * The [Geolocation API](http://www.w3.org/TR/geolocation-API/) + * is used to locate a user's position. + * + * To get notified of position changes, register a listener for the generic + * `change` event on your instance of `ol.Geolocation`. + * + * Example: + * + * var geolocation = new ol.Geolocation({ + * // take the projection to use from the map's view + * projection: view.getProjection() + * }); + * // listen to changes in position + * geolocation.on('change', function(evt) { + * window.console.log(geolocation.getPosition()); + * }); + * + * @constructor + * @extends {ol.Object} + * @param {olx.GeolocationOptions=} opt_options Options. + * @api stable + */ +ol.Geolocation = function(opt_options) { + + goog.base(this); + + var options = opt_options || {}; + + /** + * The unprojected (EPSG:4326) device position. + * @private + * @type {ol.Coordinate} + */ + this.position_ = null; + + /** + * @private + * @type {ol.TransformFunction} + */ + this.transform_ = ol.proj.identityTransform; + + /** + * @private + * @type {number|undefined} + */ + this.watchId_ = undefined; + + goog.events.listen( + this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION), + this.handleProjectionChanged_, false, this); + goog.events.listen( + this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING), + this.handleTrackingChanged_, false, this); + + if (options.projection !== undefined) { + this.setProjection(ol.proj.get(options.projection)); + } + if (options.trackingOptions !== undefined) { + this.setTrackingOptions(options.trackingOptions); + } + + this.setTracking(options.tracking !== undefined ? options.tracking : false); + +}; +goog.inherits(ol.Geolocation, ol.Object); + + +/** + * @inheritDoc + */ +ol.Geolocation.prototype.disposeInternal = function() { + this.setTracking(false); + goog.base(this, 'disposeInternal'); +}; + + +/** + * @private + */ +ol.Geolocation.prototype.handleProjectionChanged_ = function() { + var projection = this.getProjection(); + if (projection) { + this.transform_ = ol.proj.getTransformFromProjections( + ol.proj.get('EPSG:4326'), projection); + if (this.position_) { + this.set( + ol.GeolocationProperty.POSITION, this.transform_(this.position_)); + } + } +}; + + +/** + * @private + */ +ol.Geolocation.prototype.handleTrackingChanged_ = function() { + if (ol.has.GEOLOCATION) { + var tracking = this.getTracking(); + if (tracking && this.watchId_ === undefined) { + this.watchId_ = goog.global.navigator.geolocation.watchPosition( + goog.bind(this.positionChange_, this), + goog.bind(this.positionError_, this), + this.getTrackingOptions()); + } else if (!tracking && this.watchId_ !== undefined) { + goog.global.navigator.geolocation.clearWatch(this.watchId_); + this.watchId_ = undefined; + } + } +}; + + +/** + * @private + * @param {GeolocationPosition} position position event. + */ +ol.Geolocation.prototype.positionChange_ = function(position) { + var coords = position.coords; + this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy); + this.set(ol.GeolocationProperty.ALTITUDE, + coords.altitude === null ? undefined : coords.altitude); + this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY, + coords.altitudeAccuracy === null ? + undefined : coords.altitudeAccuracy); + this.set(ol.GeolocationProperty.HEADING, coords.heading === null ? + undefined : ol.math.toRadians(coords.heading)); + if (!this.position_) { + this.position_ = [coords.longitude, coords.latitude]; + } else { + this.position_[0] = coords.longitude; + this.position_[1] = coords.latitude; + } + var projectedPosition = this.transform_(this.position_); + this.set(ol.GeolocationProperty.POSITION, projectedPosition); + this.set(ol.GeolocationProperty.SPEED, + coords.speed === null ? undefined : coords.speed); + var geometry = ol.geom.Polygon.circular( + ol.sphere.WGS84, this.position_, coords.accuracy); + geometry.applyTransform(this.transform_); + this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry); + this.changed(); +}; /** - * @const - * @type {Object.<string, string>} * @private + * @param {GeolocationPositionError} error error object. */ -ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = { - 'Point': 'wpt', - 'LineString': 'rte', - 'MultiLineString': 'trk' +ol.Geolocation.prototype.positionError_ = function(error) { + error.type = goog.events.EventType.ERROR; + this.setTracking(false); + this.dispatchEvent(error); }; /** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private + * Get the accuracy of the position in meters. + * @return {number|undefined} The accuracy of the position measurement in + * meters. + * @observable + * @api stable */ -ol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { - goog.asserts.assertInstanceof(value, ol.Feature, - 'value should be an ol.Feature'); - var geometry = value.getGeometry(); - if (geometry) { - var nodeName = ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()]; - if (nodeName) { - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - return ol.xml.createElementNS(parentNode.namespaceURI, nodeName); - } - } +ol.Geolocation.prototype.getAccuracy = function() { + return /** @type {number|undefined} */ ( + this.get(ol.GeolocationProperty.ACCURACY)); }; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * Get a geometry of the position accuracy. + * @return {?ol.geom.Geometry} A geometry of the position accuracy. + * @observable + * @api stable */ -ol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.GPX.NAMESPACE_URIS_, { - 'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_), - 'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_), - 'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_) - }); +ol.Geolocation.prototype.getAccuracyGeometry = function() { + return /** @type {?ol.geom.Geometry} */ ( + this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null); +}; /** - * Encode an array of features in the GPX format. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Result. + * Get the altitude associated with the position. + * @return {number|undefined} The altitude of the position in meters above mean + * sea level. + * @observable * @api stable */ -ol.format.GPX.prototype.writeFeatures; +ol.Geolocation.prototype.getAltitude = function() { + return /** @type {number|undefined} */ ( + this.get(ol.GeolocationProperty.ALTITUDE)); +}; /** - * Encode an array of features in the GPX format as an XML node. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api + * Get the altitude accuracy of the position. + * @return {number|undefined} The accuracy of the altitude measurement in + * meters. + * @observable + * @api stable */ -ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - //FIXME Serialize metadata - var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx'); - - ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ - ({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_, - ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]); - return gpx; +ol.Geolocation.prototype.getAltitudeAccuracy = function() { + return /** @type {number|undefined} */ ( + this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY)); }; -// Copyright 2013 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. /** - * @fileoverview Utilities for string newlines. - * @author nnaze@google.com (Nathan Naze) + * Get the heading as radians clockwise from North. + * @return {number|undefined} The heading of the device in radians from north. + * @observable + * @api stable */ +ol.Geolocation.prototype.getHeading = function() { + return /** @type {number|undefined} */ ( + this.get(ol.GeolocationProperty.HEADING)); +}; /** - * Namespace for string utilities + * Get the position of the device. + * @return {ol.Coordinate|undefined} The current position of the device reported + * in the current projection. + * @observable + * @api stable */ -goog.provide('goog.string.newlines'); -goog.provide('goog.string.newlines.Line'); - -goog.require('goog.array'); +ol.Geolocation.prototype.getPosition = function() { + return /** @type {ol.Coordinate|undefined} */ ( + this.get(ol.GeolocationProperty.POSITION)); +}; /** - * Splits a string into lines, properly handling universal newlines. - * @param {string} str String to split. - * @param {boolean=} opt_keepNewlines Whether to keep the newlines in the - * resulting strings. Defaults to false. - * @return {!Array<string>} String split into lines. + * Get the projection associated with the position. + * @return {ol.proj.Projection|undefined} The projection the position is + * reported in. + * @observable + * @api stable */ -goog.string.newlines.splitLines = function(str, opt_keepNewlines) { - var lines = goog.string.newlines.getLines(str); - return goog.array.map(lines, function(line) { - return opt_keepNewlines ? line.getFullLine() : line.getContent(); - }); +ol.Geolocation.prototype.getProjection = function() { + return /** @type {ol.proj.Projection|undefined} */ ( + this.get(ol.GeolocationProperty.PROJECTION)); }; - /** - * Line metadata class that records the start/end indicies of lines - * in a string. Can be used to implement common newline use cases such as - * splitLines() or determining line/column of an index in a string. - * Also implements methods to get line contents. - * - * Indexes are expressed as string indicies into string.substring(), inclusive - * at the start, exclusive at the end. - * - * Create an array of these with goog.string.newlines.getLines(). - * @param {string} string The original string. - * @param {number} startLineIndex The index of the start of the line. - * @param {number} endContentIndex The index of the end of the line, excluding - * newlines. - * @param {number} endLineIndex The index of the end of the line, index - * newlines. - * @constructor - * @struct - * @final + * Get the speed in meters per second. + * @return {number|undefined} The instantaneous speed of the device in meters + * per second. + * @observable + * @api stable */ -goog.string.newlines.Line = function(string, startLineIndex, - endContentIndex, endLineIndex) { - /** - * The original string. - * @type {string} - */ - this.string = string; - - /** - * Index of the start of the line. - * @type {number} - */ - this.startLineIndex = startLineIndex; - - /** - * Index of the end of the line, excluding any newline characters. - * Index is the first character after the line, suitable for - * String.substring(). - * @type {number} - */ - this.endContentIndex = endContentIndex; - - /** - * Index of the end of the line, excluding any newline characters. - * Index is the first character after the line, suitable for - * String.substring(). - * @type {number} - */ - - this.endLineIndex = endLineIndex; +ol.Geolocation.prototype.getSpeed = function() { + return /** @type {number|undefined} */ ( + this.get(ol.GeolocationProperty.SPEED)); }; /** - * @return {string} The content of the line, excluding any newline characters. + * Determine if the device location is being tracked. + * @return {boolean} The device location is being tracked. + * @observable + * @api stable */ -goog.string.newlines.Line.prototype.getContent = function() { - return this.string.substring(this.startLineIndex, this.endContentIndex); +ol.Geolocation.prototype.getTracking = function() { + return /** @type {boolean} */ ( + this.get(ol.GeolocationProperty.TRACKING)); }; /** - * @return {string} The full line, including any newline characters. + * Get the tracking options. + * @see http://www.w3.org/TR/geolocation-API/#position-options + * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by + * the [HTML5 Geolocation spec + * ](http://www.w3.org/TR/geolocation-API/#position_options_interface). + * @observable + * @api stable */ -goog.string.newlines.Line.prototype.getFullLine = function() { - return this.string.substring(this.startLineIndex, this.endLineIndex); +ol.Geolocation.prototype.getTrackingOptions = function() { + return /** @type {GeolocationPositionOptions|undefined} */ ( + this.get(ol.GeolocationProperty.TRACKING_OPTIONS)); }; /** - * @return {string} The newline characters, if any ('\n', \r', '\r\n', '', etc). + * Set the projection to use for transforming the coordinates. + * @param {ol.proj.Projection} projection The projection the position is + * reported in. + * @observable + * @api stable */ -goog.string.newlines.Line.prototype.getNewline = function() { - return this.string.substring(this.endContentIndex, this.endLineIndex); +ol.Geolocation.prototype.setProjection = function(projection) { + this.set(ol.GeolocationProperty.PROJECTION, projection); }; /** - * Splits a string into an array of line metadata. - * @param {string} str String to split. - * @return {!Array<!goog.string.newlines.Line>} Array of line metadata. + * Enable or disable tracking. + * @param {boolean} tracking Enable tracking. + * @observable + * @api stable */ -goog.string.newlines.getLines = function(str) { - // We use the constructor because literals are evaluated only once in - // < ES 3.1. - // See http://www.mail-archive.com/es-discuss@mozilla.org/msg01796.html - var re = RegExp('\r\n|\r|\n', 'g'); - var sliceIndex = 0; - var result; - var lines = []; - - while (result = re.exec(str)) { - var line = new goog.string.newlines.Line( - str, sliceIndex, result.index, result.index + result[0].length); - lines.push(line); - - // remember where to start the slice from - sliceIndex = re.lastIndex; - } +ol.Geolocation.prototype.setTracking = function(tracking) { + this.set(ol.GeolocationProperty.TRACKING, tracking); +}; - // If the string does not end with a newline, add the last line. - if (sliceIndex < str.length) { - var line = new goog.string.newlines.Line( - str, sliceIndex, str.length, str.length); - lines.push(line); - } - return lines; +/** + * Set the tracking options. + * @see http://www.w3.org/TR/geolocation-API/#position-options + * @param {GeolocationPositionOptions} options PositionOptions as defined by the + * [HTML5 Geolocation spec + * ](http://www.w3.org/TR/geolocation-API/#position_options_interface). + * @observable + * @api stable + */ +ol.Geolocation.prototype.setTrackingOptions = function(options) { + this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options); }; -goog.provide('ol.format.TextFeature'); +goog.provide('ol.geom.Circle'); goog.require('goog.asserts'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.geom.flat.deflate'); +goog.require('ol.proj'); /** * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. - * Base class for text feature formats. + * Circle geometry. * * @constructor - * @extends {ol.format.Feature} + * @extends {ol.geom.SimpleGeometry} + * @param {ol.Coordinate} center Center. + * @param {number=} opt_radius Radius. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api */ -ol.format.TextFeature = function() { +ol.geom.Circle = function(center, opt_radius, opt_layout) { goog.base(this); + var radius = opt_radius ? opt_radius : 0; + this.setCenterAndRadius(center, radius, opt_layout); }; -goog.inherits(ol.format.TextFeature, ol.format.Feature); +goog.inherits(ol.geom.Circle, ol.geom.SimpleGeometry); /** - * @param {Document|Node|Object|string} source Source. - * @private - * @return {string} Text. + * Make a complete copy of the geometry. + * @return {!ol.geom.Circle} Clone. + * @api */ -ol.format.TextFeature.prototype.getText_ = function(source) { - if (goog.isString(source)) { - return source; - } else { - goog.asserts.fail(); - return ''; - } +ol.geom.Circle.prototype.clone = function() { + var circle = new ol.geom.Circle(null); + circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return circle; }; /** * @inheritDoc */ -ol.format.TextFeature.prototype.getType = function() { - return ol.format.FormatType.TEXT; +ol.geom.Circle.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + var flatCoordinates = this.flatCoordinates; + var dx = x - flatCoordinates[0]; + var dy = y - flatCoordinates[1]; + var squaredDistance = dx * dx + dy * dy; + if (squaredDistance < minSquaredDistance) { + var i; + if (squaredDistance === 0) { + for (i = 0; i < this.stride; ++i) { + closestPoint[i] = flatCoordinates[i]; + } + } else { + var delta = this.getRadius() / Math.sqrt(squaredDistance); + closestPoint[0] = flatCoordinates[0] + delta * dx; + closestPoint[1] = flatCoordinates[1] + delta * dy; + for (i = 2; i < this.stride; ++i) { + closestPoint[i] = flatCoordinates[i]; + } + } + closestPoint.length = this.stride; + return squaredDistance; + } else { + return minSquaredDistance; + } }; /** * @inheritDoc */ -ol.format.TextFeature.prototype.readFeature = function(source, opt_options) { - return this.readFeatureFromText( - this.getText_(source), this.adaptOptions(opt_options)); +ol.geom.Circle.prototype.containsXY = function(x, y) { + var flatCoordinates = this.flatCoordinates; + var dx = x - flatCoordinates[0]; + var dy = y - flatCoordinates[1]; + return dx * dx + dy * dy <= this.getRadiusSquared_(); }; /** - * @param {string} text Text. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.Feature} Feature. + * Return the center of the circle as {@link ol.Coordinate coordinate}. + * @return {ol.Coordinate} Center. + * @api */ -ol.format.TextFeature.prototype.readFeatureFromText = goog.abstractMethod; +ol.geom.Circle.prototype.getCenter = function() { + return this.flatCoordinates.slice(0, this.stride); +}; /** * @inheritDoc */ -ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) { - return this.readFeaturesFromText( - this.getText_(source), this.adaptOptions(opt_options)); +ol.geom.Circle.prototype.computeExtent = function(extent) { + var flatCoordinates = this.flatCoordinates; + var radius = flatCoordinates[this.stride] - flatCoordinates[0]; + return ol.extent.createOrUpdate( + flatCoordinates[0] - radius, flatCoordinates[1] - radius, + flatCoordinates[0] + radius, flatCoordinates[1] + radius, + extent); }; /** - * @param {string} text Text. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {Array.<ol.Feature>} Features. - */ -ol.format.TextFeature.prototype.readFeaturesFromText = goog.abstractMethod; - - -/** - * @inheritDoc + * Return the radius of the circle. + * @return {number} Radius. + * @api */ -ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) { - return this.readGeometryFromText( - this.getText_(source), this.adaptOptions(opt_options)); +ol.geom.Circle.prototype.getRadius = function() { + return Math.sqrt(this.getRadiusSquared_()); }; /** - * @param {string} text Text. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @protected - * @return {ol.geom.Geometry} Geometry. + * @private + * @return {number} Radius squared. */ -ol.format.TextFeature.prototype.readGeometryFromText = goog.abstractMethod; +ol.geom.Circle.prototype.getRadiusSquared_ = function() { + var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0]; + var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1]; + return dx * dx + dy * dy; +}; /** * @inheritDoc + * @api */ -ol.format.TextFeature.prototype.readProjection = function(source) { - return this.readProjectionFromText(this.getText_(source)); +ol.geom.Circle.prototype.getType = function() { + return ol.geom.GeometryType.CIRCLE; }; /** - * @param {string} text Text. - * @protected - * @return {ol.proj.Projection} Projection. + * @inheritDoc + * @api stable */ -ol.format.TextFeature.prototype.readProjectionFromText = function(text) { - return this.defaultDataProjection; -}; +ol.geom.Circle.prototype.intersectsExtent = function(extent) { + var circleExtent = this.getExtent(); + if (ol.extent.intersects(extent, circleExtent)) { + var center = this.getCenter(); + if (extent[0] <= center[0] && extent[2] >= center[0]) { + return true; + } + if (extent[1] <= center[1] && extent[3] >= center[1]) { + return true; + } + + return ol.extent.forEachCorner(extent, this.containsCoordinate, this); + } + return false; -/** - * @inheritDoc - */ -ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) { - return this.writeFeatureText(feature, this.adaptOptions(opt_options)); }; /** - * @param {ol.Feature} feature Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @protected - * @return {string} Text. + * Set the center of the circle as {@link ol.Coordinate coordinate}. + * @param {ol.Coordinate} center Center. + * @api */ -ol.format.TextFeature.prototype.writeFeatureText = goog.abstractMethod; +ol.geom.Circle.prototype.setCenter = function(center) { + var stride = this.stride; + goog.asserts.assert(center.length == stride, + 'center array length should match stride'); + var radius = this.flatCoordinates[stride] - this.flatCoordinates[0]; + var flatCoordinates = center.slice(); + flatCoordinates[stride] = flatCoordinates[0] + radius; + var i; + for (i = 1; i < stride; ++i) { + flatCoordinates[stride + i] = center[i]; + } + this.setFlatCoordinates(this.layout, flatCoordinates); +}; /** - * @inheritDoc + * Set the center (as {@link ol.Coordinate coordinate}) and the radius (as + * number) of the circle. + * @param {ol.Coordinate} center Center. + * @param {number} radius Radius. + * @param {ol.geom.GeometryLayout=} opt_layout Layout. + * @api */ -ol.format.TextFeature.prototype.writeFeatures = function( - features, opt_options) { - return this.writeFeaturesText(features, this.adaptOptions(opt_options)); +ol.geom.Circle.prototype.setCenterAndRadius = + function(center, radius, opt_layout) { + if (!center) { + this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); + } else { + this.setLayout(opt_layout, center, 0); + if (!this.flatCoordinates) { + this.flatCoordinates = []; + } + /** @type {Array.<number>} */ + var flatCoordinates = this.flatCoordinates; + var offset = ol.geom.flat.deflate.coordinate( + flatCoordinates, 0, center, this.stride); + flatCoordinates[offset++] = flatCoordinates[0] + radius; + var i, ii; + for (i = 1, ii = this.stride; i < ii; ++i) { + flatCoordinates[offset++] = flatCoordinates[i]; + } + flatCoordinates.length = offset; + this.changed(); + } }; /** - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @protected - * @return {string} Text. + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.<number>} flatCoordinates Flat coordinates. */ -ol.format.TextFeature.prototype.writeFeaturesText = goog.abstractMethod; +ol.geom.Circle.prototype.setFlatCoordinates = + function(layout, flatCoordinates) { + this.setFlatCoordinatesInternal(layout, flatCoordinates); + this.changed(); +}; /** - * @inheritDoc + * Set the radius of the circle. The radius is in the units of the projection. + * @param {number} radius Radius. + * @api */ -ol.format.TextFeature.prototype.writeGeometry = function( - geometry, opt_options) { - return this.writeGeometryText(geometry, this.adaptOptions(opt_options)); +ol.geom.Circle.prototype.setRadius = function(radius) { + goog.asserts.assert(this.flatCoordinates, + 'truthy this.flatCoordinates expected'); + this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius; + this.changed(); }; /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @protected - * @return {string} Text. + * Transform each coordinate of the circle from one coordinate reference system + * to another. The geometry is modified in place. + * If you do not want the geometry modified in place, first clone() it and + * then use this function on the clone. + * + * Internally a circle is currently represented by two points: the center of + * the circle `[cx, cy]`, and the point to the right of the circle + * `[cx + r, cy]`. This `transform` function just transforms these two points. + * So the resulting geometry is also a circle, and that circle does not + * correspond to the shape that would be obtained by transforming every point + * of the original circle. + * + * @param {ol.proj.ProjectionLike} source The current projection. Can be a + * string identifier or a {@link ol.proj.Projection} object. + * @param {ol.proj.ProjectionLike} destination The desired projection. Can be a + * string identifier or a {@link ol.proj.Projection} object. + * @return {ol.geom.Circle} This geometry. Note that original geometry is + * modified in place. + * @function + * @api stable */ -ol.format.TextFeature.prototype.writeGeometryText = goog.abstractMethod; +ol.geom.Circle.prototype.transform; -goog.provide('ol.format.IGC'); -goog.provide('ol.format.IGCZ'); +goog.provide('ol.geom.flat.geodesic'); goog.require('goog.asserts'); -goog.require('goog.string'); -goog.require('goog.string.newlines'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.TextFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); +goog.require('goog.object'); +goog.require('ol.TransformFunction'); +goog.require('ol.math'); goog.require('ol.proj'); /** - * IGC altitude/z. One of 'barometric', 'gps', 'none'. - * @enum {string} - * @api + * @private + * @param {function(number): ol.Coordinate} interpolate Interpolate function. + * @param {ol.TransformFunction} transform Transform from longitude/latitude to + * projected coordinates. + * @param {number} squaredTolerance Squared tolerance. + * @return {Array.<number>} Flat coordinates. */ -ol.format.IGCZ = { - BAROMETRIC: 'barometric', - GPS: 'gps', - NONE: 'none' -}; +ol.geom.flat.geodesic.line_ = + function(interpolate, transform, squaredTolerance) { + // FIXME reduce garbage generation + // FIXME optimize stack operations + /** @type {Array.<number>} */ + var flatCoordinates = []; + var geoA = interpolate(0); + var geoB = interpolate(1); -/** - * @classdesc - * Feature format for `*.igc` flight recording files. - * - * @constructor - * @extends {ol.format.TextFeature} - * @param {olx.format.IGCOptions=} opt_options Options. - * @api - */ -ol.format.IGC = function(opt_options) { + var a = transform(geoA); + var b = transform(geoB); - var options = opt_options ? opt_options : {}; + /** @type {Array.<ol.Coordinate>} */ + var geoStack = [geoB, geoA]; + /** @type {Array.<ol.Coordinate>} */ + var stack = [b, a]; + /** @type {Array.<number>} */ + var fractionStack = [1, 0]; - goog.base(this); + /** @type {Object.<string, boolean>} */ + var fractions = {}; - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); + var maxIterations = 1e5; + var geoM, m, fracA, fracB, fracM, key; - /** - * @private - * @type {ol.format.IGCZ} - */ - this.altitudeMode_ = options.altitudeMode ? - options.altitudeMode : ol.format.IGCZ.NONE; + while (--maxIterations > 0 && fractionStack.length > 0) { + // Pop the a coordinate off the stack + fracA = fractionStack.pop(); + geoA = geoStack.pop(); + a = stack.pop(); + // Add the a coordinate if it has not been added yet + key = fracA.toString(); + if (!goog.object.containsKey(fractions, key)) { + flatCoordinates.push(a[0], a[1]); + fractions[key] = true; + } + // Pop the b coordinate off the stack + fracB = fractionStack.pop(); + geoB = geoStack.pop(); + b = stack.pop(); + // Find the m point between the a and b coordinates + fracM = (fracA + fracB) / 2; + geoM = interpolate(fracM); + m = transform(geoM); + if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1], + b[0], b[1]) < squaredTolerance) { + // If the m point is sufficiently close to the straight line, then we + // discard it. Just use the b coordinate and move on to the next line + // segment. + flatCoordinates.push(b[0], b[1]); + key = fracB.toString(); + goog.asserts.assert(!goog.object.containsKey(fractions, key), + 'fractions object should contain key : ' + key); + fractions[key] = true; + } else { + // Otherwise, we need to subdivide the current line segment. Split it + // into two and push the two line segments onto the stack. + fractionStack.push(fracB, fracM, fracM, fracA); + stack.push(b, m, m, a); + geoStack.push(geoB, geoM, geoM, geoA); + } + } + goog.asserts.assert(maxIterations > 0, + 'maxIterations should be more than 0'); + return flatCoordinates; }; -goog.inherits(ol.format.IGC, ol.format.TextFeature); /** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.IGC.EXTENSIONS_ = ['.igc']; - +* Generate a great-circle arcs between two lat/lon points. +* @param {number} lon1 Longitude 1 in degrees. +* @param {number} lat1 Latitude 1 in degrees. +* @param {number} lon2 Longitude 2 in degrees. +* @param {number} lat2 Latitude 2 in degrees. + * @param {ol.proj.Projection} projection Projection. +* @param {number} squaredTolerance Squared tolerance. +* @return {Array.<number>} Flat coordinates. +*/ +ol.geom.flat.geodesic.greatCircleArc = function( + lon1, lat1, lon2, lat2, projection, squaredTolerance) { -/** - * @const - * @type {RegExp} - * @private - */ -ol.format.IGC.B_RECORD_RE_ = - /^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/; + var geoProjection = ol.proj.get('EPSG:4326'); + var cosLat1 = Math.cos(ol.math.toRadians(lat1)); + var sinLat1 = Math.sin(ol.math.toRadians(lat1)); + var cosLat2 = Math.cos(ol.math.toRadians(lat2)); + var sinLat2 = Math.sin(ol.math.toRadians(lat2)); + var cosDeltaLon = Math.cos(ol.math.toRadians(lon2 - lon1)); + var sinDeltaLon = Math.sin(ol.math.toRadians(lon2 - lon1)); + var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon; -/** - * @const - * @type {RegExp} - * @private - */ -ol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/; + return ol.geom.flat.geodesic.line_( + /** + * @param {number} frac Fraction. + * @return {ol.Coordinate} Coordinate. + */ + function(frac) { + if (1 <= d) { + return [lon2, lat2]; + } + var D = frac * Math.acos(d); + var cosD = Math.cos(D); + var sinD = Math.sin(D); + var y = sinDeltaLon * cosLat2; + var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon; + var theta = Math.atan2(y, x); + var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta)); + var lon = ol.math.toRadians(lon1) + + Math.atan2(Math.sin(theta) * sinD * cosLat1, + cosD - sinLat1 * Math.sin(lat)); + return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)]; + }, ol.proj.getTransform(geoProjection, projection), squaredTolerance); +}; /** - * @const - * @type {RegExp} - * @private + * Generate a meridian (line at constant longitude). + * @param {number} lon Longitude. + * @param {number} lat1 Latitude 1. + * @param {number} lat2 Latitude 2. + * @param {ol.proj.Projection} projection Projection. + * @param {number} squaredTolerance Squared tolerance. + * @return {Array.<number>} Flat coordinates. */ -ol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\d{2})(\d{2})(\d{2})/; +ol.geom.flat.geodesic.meridian = + function(lon, lat1, lat2, projection, squaredTolerance) { + var epsg4326Projection = ol.proj.get('EPSG:4326'); + return ol.geom.flat.geodesic.line_( + /** + * @param {number} frac Fraction. + * @return {ol.Coordinate} Coordinate. + */ + function(frac) { + return [lon, lat1 + ((lat2 - lat1) * frac)]; + }, + ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance); +}; /** - * @inheritDoc + * Generate a parallel (line at constant latitude). + * @param {number} lat Latitude. + * @param {number} lon1 Longitude 1. + * @param {number} lon2 Longitude 2. + * @param {ol.proj.Projection} projection Projection. + * @param {number} squaredTolerance Squared tolerance. + * @return {Array.<number>} Flat coordinates. */ -ol.format.IGC.prototype.getExtensions = function() { - return ol.format.IGC.EXTENSIONS_; +ol.geom.flat.geodesic.parallel = + function(lat, lon1, lon2, projection, squaredTolerance) { + var epsg4326Projection = ol.proj.get('EPSG:4326'); + return ol.geom.flat.geodesic.line_( + /** + * @param {number} frac Fraction. + * @return {ol.Coordinate} Coordinate. + */ + function(frac) { + return [lon1 + ((lon2 - lon1) * frac), lat]; + }, + ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance); }; +goog.provide('ol.Graticule'); -/** - * Read the feature from the IGC source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api - */ -ol.format.IGC.prototype.readFeature; - +goog.require('goog.asserts'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.flat.geodesic'); +goog.require('ol.math'); +goog.require('ol.proj'); +goog.require('ol.render.EventType'); +goog.require('ol.style.Stroke'); -/** - * @inheritDoc - */ -ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) { - var altitudeMode = this.altitudeMode_; - var lines = goog.string.newlines.splitLines(text); - /** @type {Object.<string, string>} */ - var properties = {}; - var flatCoordinates = []; - var year = 2000; - var month = 0; - var day = 1; - var i, ii; - for (i = 0, ii = lines.length; i < ii; ++i) { - var line = lines[i]; - var m; - if (line.charAt(0) == 'B') { - m = ol.format.IGC.B_RECORD_RE_.exec(line); - if (m) { - var hour = parseInt(m[1], 10); - var minute = parseInt(m[2], 10); - var second = parseInt(m[3], 10); - var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000; - if (m[6] == 'S') { - y = -y; - } - var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000; - if (m[9] == 'W') { - x = -x; - } - flatCoordinates.push(x, y); - if (altitudeMode != ol.format.IGCZ.NONE) { - var z; - if (altitudeMode == ol.format.IGCZ.GPS) { - z = parseInt(m[11], 10); - } else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) { - z = parseInt(m[12], 10); - } else { - goog.asserts.fail(); - z = 0; - } - flatCoordinates.push(z); - } - var dateTime = Date.UTC(year, month, day, hour, minute, second); - flatCoordinates.push(dateTime / 1000); - } - } else if (line.charAt(0) == 'H') { - m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line); - if (m) { - day = parseInt(m[1], 10); - month = parseInt(m[2], 10) - 1; - year = 2000 + parseInt(m[3], 10); - } else { - m = ol.format.IGC.H_RECORD_RE_.exec(line); - if (m) { - properties[m[1]] = m[2].trim(); - m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line); - } - } - } - } - if (flatCoordinates.length === 0) { - return null; - } - var lineString = new ol.geom.LineString(null); - var layout = altitudeMode == ol.format.IGCZ.NONE ? - ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM; - lineString.setFlatCoordinates(layout, flatCoordinates); - var feature = new ol.Feature(ol.format.Feature.transformWithOptions( - lineString, false, opt_options)); - feature.setProperties(properties); - return feature; -}; /** - * Read the feature from the source. As IGC sources contain a single - * feature, this will return the feature in an array. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. + * Render a grid for a coordinate system on a map. + * @constructor + * @param {olx.GraticuleOptions=} opt_options Options. * @api */ -ol.format.IGC.prototype.readFeatures; +ol.Graticule = function(opt_options) { + var options = opt_options || {}; -/** - * @inheritDoc - */ -ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) { - var feature = this.readFeatureFromText(text, opt_options); - if (feature) { - return [feature]; - } else { - return []; - } -}; + /** + * @type {ol.Map} + * @private + */ + this.map_ = null; + /** + * @type {ol.proj.Projection} + * @private + */ + this.projection_ = null; -/** - * Read the projection from the IGC source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api - */ -ol.format.IGC.prototype.readProjection; + /** + * @type {number} + * @private + */ + this.maxLat_ = Infinity; -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. + /** + * @type {number} + * @private + */ + this.maxLon_ = Infinity; -/** - * @fileoverview Class for parsing and formatting URIs. - * - * Use goog.Uri(string) to parse a URI string. Use goog.Uri.create(...) to - * create a new instance of the goog.Uri object from Uri parts. - * - * e.g: <code>var myUri = new goog.Uri(window.location);</code> - * - * Implements RFC 3986 for parsing/formatting URIs. - * http://www.ietf.org/rfc/rfc3986.txt - * - * Some changes have been made to the interface (more like .NETs), though the - * internal representation is now of un-encoded parts, this will change the - * behavior slightly. - * - */ + /** + * @type {number} + * @private + */ + this.minLat_ = -Infinity; -goog.provide('goog.Uri'); -goog.provide('goog.Uri.QueryData'); + /** + * @type {number} + * @private + */ + this.minLon_ = -Infinity; -goog.require('goog.array'); -goog.require('goog.string'); -goog.require('goog.structs'); -goog.require('goog.structs.Map'); -goog.require('goog.uri.utils'); -goog.require('goog.uri.utils.ComponentIndex'); -goog.require('goog.uri.utils.StandardQueryParam'); + /** + * @type {number} + * @private + */ + this.maxLatP_ = Infinity; + /** + * @type {number} + * @private + */ + this.maxLonP_ = Infinity; + /** + * @type {number} + * @private + */ + this.minLatP_ = -Infinity; -/** - * This class contains setters and getters for the parts of the URI. - * The <code>getXyz</code>/<code>setXyz</code> methods return the decoded part - * -- so<code>goog.Uri.parse('/foo%20bar').getPath()</code> will return the - * decoded path, <code>/foo bar</code>. - * - * Reserved characters (see RFC 3986 section 2.2) can be present in - * their percent-encoded form in scheme, domain, and path URI components and - * will not be auto-decoded. For example: - * <code>goog.Uri.parse('rel%61tive/path%2fto/resource').getPath()</code> will - * return <code>relative/path%2fto/resource</code>. - * - * The constructor accepts an optional unparsed, raw URI string. The parser - * is relaxed, so special characters that aren't escaped but don't cause - * ambiguities will not cause parse failures. - * - * All setters return <code>this</code> and so may be chained, a la - * <code>goog.Uri.parse('/foo').setFragment('part').toString()</code>. - * - * @param {*=} opt_uri Optional string URI to parse - * (use goog.Uri.create() to create a URI from parts), or if - * a goog.Uri is passed, a clone is created. - * @param {boolean=} opt_ignoreCase If true, #getParameterValue will ignore - * the case of the parameter name. - * - * @throws URIError If opt_uri is provided and URI is malformed (that is, - * if decodeURIComponent fails on any of the URI components). - * @constructor - * @struct - */ -goog.Uri = function(opt_uri, opt_ignoreCase) { /** - * Scheme such as "http". - * @private {string} + * @type {number} + * @private */ - this.scheme_ = ''; + this.minLonP_ = -Infinity; /** - * User credentials in the form "username:password". - * @private {string} + * @type {number} + * @private */ - this.userInfo_ = ''; + this.targetSize_ = options.targetSize !== undefined ? + options.targetSize : 100; /** - * Domain part, e.g. "www.google.com". - * @private {string} + * @type {number} + * @private */ - this.domain_ = ''; + this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100; + goog.asserts.assert(this.maxLines_ > 0, + 'this.maxLines_ should be more than 0'); /** - * Port, e.g. 8080. - * @private {?number} + * @type {Array.<ol.geom.LineString>} + * @private */ - this.port_ = null; + this.meridians_ = []; /** - * Path, e.g. "/tests/img.png". - * @private {string} + * @type {Array.<ol.geom.LineString>} + * @private */ - this.path_ = ''; + this.parallels_ = []; /** - * The fragment without the #. - * @private {string} + * @type {ol.style.Stroke} + * @private */ - this.fragment_ = ''; + this.strokeStyle_ = options.strokeStyle !== undefined ? + options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_; /** - * Whether or not this Uri should be treated as Read Only. - * @private {boolean} + * @type {ol.TransformFunction|undefined} + * @private */ - this.isReadOnly_ = false; + this.fromLonLatTransform_ = undefined; /** - * Whether or not to ignore case when comparing query params. - * @private {boolean} + * @type {ol.TransformFunction|undefined} + * @private */ - this.ignoreCase_ = false; + this.toLonLatTransform_ = undefined; /** - * Object representing query data. - * @private {!goog.Uri.QueryData} + * @type {ol.Coordinate} + * @private */ - this.queryData_; - - // Parse in the uri string - var m; - if (opt_uri instanceof goog.Uri) { - this.ignoreCase_ = goog.isDef(opt_ignoreCase) ? - opt_ignoreCase : opt_uri.getIgnoreCase(); - this.setScheme(opt_uri.getScheme()); - this.setUserInfo(opt_uri.getUserInfo()); - this.setDomain(opt_uri.getDomain()); - this.setPort(opt_uri.getPort()); - this.setPath(opt_uri.getPath()); - this.setQueryData(opt_uri.getQueryData().clone()); - this.setFragment(opt_uri.getFragment()); - } else if (opt_uri && (m = goog.uri.utils.split(String(opt_uri)))) { - this.ignoreCase_ = !!opt_ignoreCase; - - // Set the parts -- decoding as we do so. - // COMPATABILITY NOTE - In IE, unmatched fields may be empty strings, - // whereas in other browsers they will be undefined. - this.setScheme(m[goog.uri.utils.ComponentIndex.SCHEME] || '', true); - this.setUserInfo(m[goog.uri.utils.ComponentIndex.USER_INFO] || '', true); - this.setDomain(m[goog.uri.utils.ComponentIndex.DOMAIN] || '', true); - this.setPort(m[goog.uri.utils.ComponentIndex.PORT]); - this.setPath(m[goog.uri.utils.ComponentIndex.PATH] || '', true); - this.setQueryData(m[goog.uri.utils.ComponentIndex.QUERY_DATA] || '', true); - this.setFragment(m[goog.uri.utils.ComponentIndex.FRAGMENT] || '', true); + this.projectionCenterLonLat_ = null; - } else { - this.ignoreCase_ = !!opt_ignoreCase; - this.queryData_ = new goog.Uri.QueryData(null, null, this.ignoreCase_); - } + this.setMap(options.map !== undefined ? options.map : null); }; /** - * If true, we preserve the type of query parameters set programmatically. - * - * This means that if you set a parameter to a boolean, and then call - * getParameterValue, you will get a boolean back. - * - * If false, we will coerce parameters to strings, just as they would - * appear in real URIs. - * - * TODO(nicksantos): Remove this once people have time to fix all tests. - * - * @type {boolean} + * @type {ol.style.Stroke} + * @private + * @const */ -goog.Uri.preserveParameterTypesCompatibilityFlag = false; +ol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({ + color: 'rgba(0,0,0,0.2)' +}); /** - * Parameter name added to stop caching. - * @type {string} + * TODO can be configurable + * @type {Array.<number>} + * @private */ -goog.Uri.RANDOM_PARAM = goog.uri.utils.StandardQueryParam.RANDOM; +ol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, + 0.01, 0.005, 0.002, 0.001]; /** - * @return {string} The string form of the url. - * @override + * @param {number} lon Longitude. + * @param {number} minLat Minimal latitude. + * @param {number} maxLat Maximal latitude. + * @param {number} squaredTolerance Squared tolerance. + * @param {ol.Extent} extent Extent. + * @param {number} index Index. + * @return {number} Index. + * @private */ -goog.Uri.prototype.toString = function() { - var out = []; - - var scheme = this.getScheme(); - if (scheme) { - out.push(goog.Uri.encodeSpecialChars_( - scheme, goog.Uri.reDisallowedInSchemeOrUserInfo_, true), ':'); +ol.Graticule.prototype.addMeridian_ = + function(lon, minLat, maxLat, squaredTolerance, extent, index) { + var lineString = this.getMeridian_(lon, minLat, maxLat, + squaredTolerance, index); + if (ol.extent.intersects(lineString.getExtent(), extent)) { + this.meridians_[index++] = lineString; } + return index; +}; - var domain = this.getDomain(); - if (domain || scheme == 'file') { - out.push('//'); - - var userInfo = this.getUserInfo(); - if (userInfo) { - out.push(goog.Uri.encodeSpecialChars_( - userInfo, goog.Uri.reDisallowedInSchemeOrUserInfo_, true), '@'); - } - - out.push(goog.Uri.removeDoubleEncoding_(goog.string.urlEncode(domain))); - var port = this.getPort(); - if (port != null) { - out.push(':', String(port)); - } +/** + * @param {number} lat Latitude. + * @param {number} minLon Minimal longitude. + * @param {number} maxLon Maximal longitude. + * @param {number} squaredTolerance Squared tolerance. + * @param {ol.Extent} extent Extent. + * @param {number} index Index. + * @return {number} Index. + * @private + */ +ol.Graticule.prototype.addParallel_ = + function(lat, minLon, maxLon, squaredTolerance, extent, index) { + var lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, + index); + if (ol.extent.intersects(lineString.getExtent(), extent)) { + this.parallels_[index++] = lineString; } + return index; +}; - var path = this.getPath(); - if (path) { - if (this.hasDomain() && path.charAt(0) != '/') { - out.push('/'); - } - out.push(goog.Uri.encodeSpecialChars_( - path, - path.charAt(0) == '/' ? - goog.Uri.reDisallowedInAbsolutePath_ : - goog.Uri.reDisallowedInRelativePath_, - true)); - } - var query = this.getEncodedQuery(); - if (query) { - out.push('?', query); - } +/** + * @param {ol.Extent} extent Extent. + * @param {ol.Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} squaredTolerance Squared tolerance. + * @private + */ +ol.Graticule.prototype.createGraticule_ = + function(extent, center, resolution, squaredTolerance) { - var fragment = this.getFragment(); - if (fragment) { - out.push('#', goog.Uri.encodeSpecialChars_( - fragment, goog.Uri.reDisallowedInFragment_)); + var interval = this.getInterval_(resolution); + if (interval == -1) { + this.meridians_.length = this.parallels_.length = 0; + return; } - return out.join(''); -}; + var centerLonLat = this.toLonLatTransform_(center); + var centerLon = centerLonLat[0]; + var centerLat = centerLonLat[1]; + var maxLines = this.maxLines_; + var cnt, idx, lat, lon; -/** - * Resolves the given relative URI (a goog.Uri object), using the URI - * represented by this instance as the base URI. - * - * There are several kinds of relative URIs:<br> - * 1. foo - replaces the last part of the path, the whole query and fragment<br> - * 2. /foo - replaces the the path, the query and fragment<br> - * 3. //foo - replaces everything from the domain on. foo is a domain name<br> - * 4. ?foo - replace the query and fragment<br> - * 5. #foo - replace the fragment only - * - * Additionally, if relative URI has a non-empty path, all ".." and "." - * segments will be resolved, as described in RFC 3986. - * - * @param {!goog.Uri} relativeUri The relative URI to resolve. - * @return {!goog.Uri} The resolved URI. - */ -goog.Uri.prototype.resolve = function(relativeUri) { + var validExtent = [ + Math.max(extent[0], this.minLonP_), + Math.max(extent[1], this.minLatP_), + Math.min(extent[2], this.maxLonP_), + Math.min(extent[3], this.maxLatP_) + ]; - var absoluteUri = this.clone(); + validExtent = ol.proj.transformExtent(validExtent, this.projection_, + 'EPSG:4326'); + var maxLat = validExtent[3]; + var maxLon = validExtent[2]; + var minLat = validExtent[1]; + var minLon = validExtent[0]; - // we satisfy these conditions by looking for the first part of relativeUri - // that is not blank and applying defaults to the rest + // Create meridians - var overridden = relativeUri.hasScheme(); + centerLon = Math.floor(centerLon / interval) * interval; + lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_); - if (overridden) { - absoluteUri.setScheme(relativeUri.getScheme()); - } else { - overridden = relativeUri.hasUserInfo(); - } + idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0); - if (overridden) { - absoluteUri.setUserInfo(relativeUri.getUserInfo()); - } else { - overridden = relativeUri.hasDomain(); + cnt = 0; + while (lon != this.minLon_ && cnt++ < maxLines) { + lon = Math.max(lon - interval, this.minLon_); + idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx); } - if (overridden) { - absoluteUri.setDomain(relativeUri.getDomain()); - } else { - overridden = relativeUri.hasPort(); - } + lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_); - var path = relativeUri.getPath(); - if (overridden) { - absoluteUri.setPort(relativeUri.getPort()); - } else { - overridden = relativeUri.hasPath(); - if (overridden) { - // resolve path properly - if (path.charAt(0) != '/') { - // path is relative - if (this.hasDomain() && !this.hasPath()) { - // RFC 3986, section 5.2.3, case 1 - path = '/' + path; - } else { - // RFC 3986, section 5.2.3, case 2 - var lastSlashIndex = absoluteUri.getPath().lastIndexOf('/'); - if (lastSlashIndex != -1) { - path = absoluteUri.getPath().substr(0, lastSlashIndex + 1) + path; - } - } - } - path = goog.Uri.removeDotSegments(path); - } + cnt = 0; + while (lon != this.maxLon_ && cnt++ < maxLines) { + lon = Math.min(lon + interval, this.maxLon_); + idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx); } - if (overridden) { - absoluteUri.setPath(path); - } else { - overridden = relativeUri.hasQuery(); - } + this.meridians_.length = idx; - if (overridden) { - absoluteUri.setQueryData(relativeUri.getDecodedQuery()); - } else { - overridden = relativeUri.hasFragment(); + // Create parallels + + centerLat = Math.floor(centerLat / interval) * interval; + lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_); + + idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0); + + cnt = 0; + while (lat != this.minLat_ && cnt++ < maxLines) { + lat = Math.max(lat - interval, this.minLat_); + idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx); } - if (overridden) { - absoluteUri.setFragment(relativeUri.getFragment()); + lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_); + + cnt = 0; + while (lat != this.maxLat_ && cnt++ < maxLines) { + lat = Math.min(lat + interval, this.maxLat_); + idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx); } - return absoluteUri; + this.parallels_.length = idx; + }; /** - * Clones the URI instance. - * @return {!goog.Uri} New instance of the URI object. + * @param {number} resolution Resolution. + * @return {number} The interval in degrees. + * @private */ -goog.Uri.prototype.clone = function() { - return new goog.Uri(this); +ol.Graticule.prototype.getInterval_ = function(resolution) { + var centerLon = this.projectionCenterLonLat_[0]; + var centerLat = this.projectionCenterLonLat_[1]; + var interval = -1; + var i, ii, delta, dist; + var target = Math.pow(this.targetSize_ * resolution, 2); + /** @type {Array.<number>} **/ + var p1 = []; + /** @type {Array.<number>} **/ + var p2 = []; + for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) { + delta = ol.Graticule.intervals_[i] / 2; + p1[0] = centerLon - delta; + p1[1] = centerLat - delta; + p2[0] = centerLon + delta; + p2[1] = centerLat + delta; + this.fromLonLatTransform_(p1, p1); + this.fromLonLatTransform_(p2, p2); + dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2); + if (dist <= target) { + break; + } + interval = ol.Graticule.intervals_[i]; + } + return interval; }; /** - * @return {string} The encoded scheme/protocol for the URI. + * Get the map associated with this graticule. + * @return {ol.Map} The map. + * @api */ -goog.Uri.prototype.getScheme = function() { - return this.scheme_; +ol.Graticule.prototype.getMap = function() { + return this.map_; }; /** - * Sets the scheme/protocol. - * @throws URIError If opt_decode is true and newScheme is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newScheme New scheme value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. + * @param {number} lon Longitude. + * @param {number} minLat Minimal latitude. + * @param {number} maxLat Maximal latitude. + * @param {number} squaredTolerance Squared tolerance. + * @return {ol.geom.LineString} The meridian line string. + * @param {number} index Index. + * @private */ -goog.Uri.prototype.setScheme = function(newScheme, opt_decode) { - this.enforceReadOnly(); - this.scheme_ = opt_decode ? goog.Uri.decodeOrEmpty_(newScheme, true) : - newScheme; +ol.Graticule.prototype.getMeridian_ = function(lon, minLat, maxLat, + squaredTolerance, index) { + goog.asserts.assert(lon >= this.minLon_, + 'lon should be larger than or equal to this.minLon_'); + goog.asserts.assert(lon <= this.maxLon_, + 'lon should be smaller than or equal to this.maxLon_'); + var flatCoordinates = ol.geom.flat.geodesic.meridian(lon, + minLat, maxLat, this.projection_, squaredTolerance); + goog.asserts.assert(flatCoordinates.length > 0, + 'flatCoordinates cannot be empty'); + var lineString = this.meridians_[index] !== undefined ? + this.meridians_[index] : new ol.geom.LineString(null); + lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); + return lineString; +}; - // remove an : at the end of the scheme so somebody can pass in - // window.location.protocol - if (this.scheme_) { - this.scheme_ = this.scheme_.replace(/:$/, ''); - } - return this; + +/** + * Get the list of meridians. Meridians are lines of equal longitude. + * @return {Array.<ol.geom.LineString>} The meridians. + * @api + */ +ol.Graticule.prototype.getMeridians = function() { + return this.meridians_; }; /** - * @return {boolean} Whether the scheme has been set. + * @param {number} lat Latitude. + * @param {number} minLon Minimal longitude. + * @param {number} maxLon Maximal longitude. + * @param {number} squaredTolerance Squared tolerance. + * @return {ol.geom.LineString} The parallel line string. + * @param {number} index Index. + * @private */ -goog.Uri.prototype.hasScheme = function() { - return !!this.scheme_; +ol.Graticule.prototype.getParallel_ = function(lat, minLon, maxLon, + squaredTolerance, index) { + goog.asserts.assert(lat >= this.minLat_, + 'lat should be larger than or equal to this.minLat_'); + goog.asserts.assert(lat <= this.maxLat_, + 'lat should be smaller than or equal to this.maxLat_'); + var flatCoordinates = ol.geom.flat.geodesic.parallel(lat, + this.minLon_, this.maxLon_, this.projection_, squaredTolerance); + goog.asserts.assert(flatCoordinates.length > 0, + 'flatCoordinates cannot be empty'); + var lineString = this.parallels_[index] !== undefined ? + this.parallels_[index] : new ol.geom.LineString(null); + lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); + return lineString; }; /** - * @return {string} The decoded user info. + * Get the list of parallels. Pallels are lines of equal latitude. + * @return {Array.<ol.geom.LineString>} The parallels. + * @api */ -goog.Uri.prototype.getUserInfo = function() { - return this.userInfo_; +ol.Graticule.prototype.getParallels = function() { + return this.parallels_; }; /** - * Sets the userInfo. - * @throws URIError If opt_decode is true and newUserInfo is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newUserInfo New userInfo value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. + * @param {ol.render.Event} e Event. + * @private */ -goog.Uri.prototype.setUserInfo = function(newUserInfo, opt_decode) { - this.enforceReadOnly(); - this.userInfo_ = opt_decode ? goog.Uri.decodeOrEmpty_(newUserInfo) : - newUserInfo; - return this; +ol.Graticule.prototype.handlePostCompose_ = function(e) { + var vectorContext = e.vectorContext; + var frameState = e.frameState; + var extent = frameState.extent; + var viewState = frameState.viewState; + var center = viewState.center; + var projection = viewState.projection; + var resolution = viewState.resolution; + var pixelRatio = frameState.pixelRatio; + var squaredTolerance = + resolution * resolution / (4 * pixelRatio * pixelRatio); + + var updateProjectionInfo = !this.projection_ || + !ol.proj.equivalent(this.projection_, projection); + + if (updateProjectionInfo) { + this.updateProjectionInfo_(projection); + } + + //Fix the extent if wrapped. + //(note: this is the same extent as vectorContext.extent_) + var offsetX = 0; + if (projection.canWrapX()) { + var projectionExtent = projection.getExtent(); + var worldWidth = ol.extent.getWidth(projectionExtent); + var x = frameState.focus[0]; + if (x < projectionExtent[0] || x > projectionExtent[2]) { + var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth); + offsetX = worldWidth * worldsAway; + extent = [ + extent[0] + offsetX, extent[1], + extent[2] + offsetX, extent[3] + ]; + } + } + + this.createGraticule_(extent, center, resolution, squaredTolerance); + + // Draw the lines + vectorContext.setFillStrokeStyle(null, this.strokeStyle_); + var i, l, line; + for (i = 0, l = this.meridians_.length; i < l; ++i) { + line = this.meridians_[i]; + vectorContext.drawLineStringGeometry(line, null); + } + for (i = 0, l = this.parallels_.length; i < l; ++i) { + line = this.parallels_[i]; + vectorContext.drawLineStringGeometry(line, null); + } }; -/** - * @return {boolean} Whether the user info has been set. - */ -goog.Uri.prototype.hasUserInfo = function() { - return !!this.userInfo_; -}; +/** + * @param {ol.proj.Projection} projection Projection. + * @private + */ +ol.Graticule.prototype.updateProjectionInfo_ = function(projection) { + goog.asserts.assert(projection, 'projection cannot be null'); + + var epsg4326Projection = ol.proj.get('EPSG:4326'); + + var extent = projection.getExtent(); + var worldExtent = projection.getWorldExtent(); + var worldExtentP = ol.proj.transformExtent(worldExtent, + epsg4326Projection, projection); + + var maxLat = worldExtent[3]; + var maxLon = worldExtent[2]; + var minLat = worldExtent[1]; + var minLon = worldExtent[0]; + + var maxLatP = worldExtentP[3]; + var maxLonP = worldExtentP[2]; + var minLatP = worldExtentP[1]; + var minLonP = worldExtentP[0]; + + goog.asserts.assert(extent, 'extent cannot be null'); + goog.asserts.assert(maxLat !== undefined, 'maxLat should be defined'); + goog.asserts.assert(maxLon !== undefined, 'maxLon should be defined'); + goog.asserts.assert(minLat !== undefined, 'minLat should be defined'); + goog.asserts.assert(minLon !== undefined, 'minLon should be defined'); + + goog.asserts.assert(maxLatP !== undefined, + 'projected maxLat should be defined'); + goog.asserts.assert(maxLonP !== undefined, + 'projected maxLon should be defined'); + goog.asserts.assert(minLatP !== undefined, + 'projected minLat should be defined'); + goog.asserts.assert(minLonP !== undefined, + 'projected minLon should be defined'); + this.maxLat_ = maxLat; + this.maxLon_ = maxLon; + this.minLat_ = minLat; + this.minLon_ = minLon; -/** - * @return {string} The decoded domain. - */ -goog.Uri.prototype.getDomain = function() { - return this.domain_; -}; + this.maxLatP_ = maxLatP; + this.maxLonP_ = maxLonP; + this.minLatP_ = minLatP; + this.minLonP_ = minLonP; -/** - * Sets the domain. - * @throws URIError If opt_decode is true and newDomain is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newDomain New domain value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setDomain = function(newDomain, opt_decode) { - this.enforceReadOnly(); - this.domain_ = opt_decode ? goog.Uri.decodeOrEmpty_(newDomain, true) : - newDomain; - return this; -}; + this.fromLonLatTransform_ = ol.proj.getTransform( + epsg4326Projection, projection); + this.toLonLatTransform_ = ol.proj.getTransform( + projection, epsg4326Projection); -/** - * @return {boolean} Whether the domain has been set. - */ -goog.Uri.prototype.hasDomain = function() { - return !!this.domain_; + this.projectionCenterLonLat_ = this.toLonLatTransform_( + ol.extent.getCenter(extent)); + + this.projection_ = projection; }; /** - * @return {?number} The port number. + * Set the map for this graticule. The graticule will be rendered on the + * provided map. + * @param {ol.Map} map Map. + * @api */ -goog.Uri.prototype.getPort = function() { - return this.port_; +ol.Graticule.prototype.setMap = function(map) { + if (this.map_) { + this.map_.un(ol.render.EventType.POSTCOMPOSE, + this.handlePostCompose_, this); + this.map_.render(); + } + if (map) { + map.on(ol.render.EventType.POSTCOMPOSE, + this.handlePostCompose_, this); + map.render(); + } + this.map_ = map; }; +goog.provide('ol.Image'); -/** - * Sets the port number. - * @param {*} newPort Port number. Will be explicitly casted to a number. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setPort = function(newPort) { - this.enforceReadOnly(); - - if (newPort) { - newPort = Number(newPort); - if (isNaN(newPort) || newPort < 0) { - throw Error('Bad port number ' + newPort); - } - this.port_ = newPort; - } else { - this.port_ = null; - } +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol.ImageBase'); +goog.require('ol.ImageState'); +goog.require('ol.extent'); - return this; -}; /** - * @return {boolean} Whether the port has been set. + * @constructor + * @extends {ol.ImageBase} + * @param {ol.Extent} extent Extent. + * @param {number|undefined} resolution Resolution. + * @param {number} pixelRatio Pixel ratio. + * @param {Array.<ol.Attribution>} attributions Attributions. + * @param {string} src Image source URI. + * @param {?string} crossOrigin Cross origin. + * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. */ -goog.Uri.prototype.hasPort = function() { - return this.port_ != null; -}; +ol.Image = function(extent, resolution, pixelRatio, attributions, src, + crossOrigin, imageLoadFunction) { + goog.base(this, extent, resolution, pixelRatio, ol.ImageState.IDLE, + attributions); -/** - * @return {string} The decoded path. - */ -goog.Uri.prototype.getPath = function() { - return this.path_; -}; + /** + * @private + * @type {string} + */ + this.src_ = src; + /** + * @private + * @type {HTMLCanvasElement|Image|HTMLVideoElement} + */ + this.image_ = new Image(); + if (crossOrigin !== null) { + this.image_.crossOrigin = crossOrigin; + } -/** - * Sets the path. - * @throws URIError If opt_decode is true and newPath is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newPath New path value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setPath = function(newPath, opt_decode) { - this.enforceReadOnly(); - this.path_ = opt_decode ? goog.Uri.decodeOrEmpty_(newPath, true) : newPath; - return this; -}; + /** + * @private + * @type {Object.<number, (HTMLCanvasElement|Image|HTMLVideoElement)>} + */ + this.imageByContext_ = {}; + /** + * @private + * @type {Array.<goog.events.Key>} + */ + this.imageListenerKeys_ = null; -/** - * @return {boolean} Whether the path has been set. - */ -goog.Uri.prototype.hasPath = function() { - return !!this.path_; -}; + /** + * @protected + * @type {ol.ImageState} + */ + this.state = ol.ImageState.IDLE; + /** + * @private + * @type {ol.ImageLoadFunctionType} + */ + this.imageLoadFunction_ = imageLoadFunction; -/** - * @return {boolean} Whether the query string has been set. - */ -goog.Uri.prototype.hasQuery = function() { - return this.queryData_.toString() !== ''; }; +goog.inherits(ol.Image, ol.ImageBase); /** - * Sets the query data. - * @param {goog.Uri.QueryData|string|undefined} queryData QueryData object. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * Applies only if queryData is a string. - * @return {!goog.Uri} Reference to this URI object. + * Get the HTML image element (may be a Canvas, Image, or Video). + * @param {Object=} opt_context Object. + * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image. + * @api */ -goog.Uri.prototype.setQueryData = function(queryData, opt_decode) { - this.enforceReadOnly(); - - if (queryData instanceof goog.Uri.QueryData) { - this.queryData_ = queryData; - this.queryData_.setIgnoreCase(this.ignoreCase_); - } else { - if (!opt_decode) { - // QueryData accepts encoded query string, so encode it if - // opt_decode flag is not true. - queryData = goog.Uri.encodeSpecialChars_(queryData, - goog.Uri.reDisallowedInQuery_); +ol.Image.prototype.getImage = function(opt_context) { + if (opt_context !== undefined) { + var image; + var key = goog.getUid(opt_context); + if (key in this.imageByContext_) { + return this.imageByContext_[key]; + } else if (goog.object.isEmpty(this.imageByContext_)) { + image = this.image_; + } else { + image = /** @type {Image} */ (this.image_.cloneNode(false)); } - this.queryData_ = new goog.Uri.QueryData(queryData, null, this.ignoreCase_); + this.imageByContext_[key] = image; + return image; + } else { + return this.image_; } - - return this; }; /** - * Sets the URI query. - * @param {string} newQuery New query value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. + * Tracks loading or read errors. + * + * @private */ -goog.Uri.prototype.setQuery = function(newQuery, opt_decode) { - return this.setQueryData(newQuery, opt_decode); +ol.Image.prototype.handleImageError_ = function() { + this.state = ol.ImageState.ERROR; + this.unlistenImage_(); + this.changed(); }; /** - * @return {string} The encoded URI query, not including the ?. + * Tracks successful image load. + * + * @private */ -goog.Uri.prototype.getEncodedQuery = function() { - return this.queryData_.toString(); +ol.Image.prototype.handleImageLoad_ = function() { + if (this.resolution === undefined) { + this.resolution = ol.extent.getHeight(this.extent) / this.image_.height; + } + this.state = ol.ImageState.LOADED; + this.unlistenImage_(); + this.changed(); }; /** - * @return {string} The decoded URI query, not including the ?. + * Load not yet loaded URI. */ -goog.Uri.prototype.getDecodedQuery = function() { - return this.queryData_.toDecodedString(); +ol.Image.prototype.load = function() { + if (this.state == ol.ImageState.IDLE) { + this.state = ol.ImageState.LOADING; + this.changed(); + goog.asserts.assert(!this.imageListenerKeys_, + 'this.imageListenerKeys_ should be null'); + this.imageListenerKeys_ = [ + goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, + this.handleImageError_, false, this), + goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, + this.handleImageLoad_, false, this) + ]; + this.imageLoadFunction_(this, this.src_); + } }; /** - * Returns the query data. - * @return {!goog.Uri.QueryData} QueryData object. + * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image. */ -goog.Uri.prototype.getQueryData = function() { - return this.queryData_; +ol.Image.prototype.setImage = function(image) { + this.image_ = image; }; /** - * @return {string} The encoded URI query, not including the ?. + * Discards event handlers which listen for load completion or errors. * - * Warning: This method, unlike other getter methods, returns encoded - * value, instead of decoded one. + * @private */ -goog.Uri.prototype.getQuery = function() { - return this.getEncodedQuery(); +ol.Image.prototype.unlistenImage_ = function() { + goog.asserts.assert(this.imageListenerKeys_, + 'this.imageListenerKeys_ should not be null'); + this.imageListenerKeys_.forEach(goog.events.unlistenByKey); + this.imageListenerKeys_ = null; }; +goog.provide('ol.ImageLoadFunctionType'); + /** - * Sets the value of the named query parameters, clearing previous values for - * that key. + * A function that takes an {@link ol.Image} for the image and a `{string}` for + * the src as arguments. It is supposed to make it so the underlying image + * {@link ol.Image#getImage} is assigned the content specified by the src. If + * not specified, the default is * - * @param {string} key The parameter to set. - * @param {*} value The new value. - * @return {!goog.Uri} Reference to this URI object. + * function(image, src) { + * image.getImage().src = src; + * } + * + * Providing a custom `imageLoadFunction` can be useful to load images with + * post requests or - in general - through XHR requests, where the src of the + * image element would be set to a data URI when the content is loaded. + * + * @typedef {function(ol.Image, string)} + * @api */ -goog.Uri.prototype.setParameterValue = function(key, value) { - this.enforceReadOnly(); - this.queryData_.set(key, value); - return this; -}; +ol.ImageLoadFunctionType; +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Sets the values of the named query parameters, clearing previous values for - * that key. Not new values will currently be moved to the end of the query - * string. - * - * So, <code>goog.Uri.parse('foo?a=b&c=d&e=f').setParameterValues('c', ['new']) - * </code> yields <tt>foo?a=b&e=f&c=new</tt>.</p> + * @fileoverview Provides a files drag and drop event detector. It works on + * HTML5 browsers. * - * @param {string} key The parameter to set. - * @param {*} values The new values. If values is a single - * string then it will be treated as the sole value. - * @return {!goog.Uri} Reference to this URI object. + * @see ../demos/filedrophandler.html */ -goog.Uri.prototype.setParameterValues = function(key, values) { - this.enforceReadOnly(); - - if (!goog.isArray(values)) { - values = [String(values)]; - } - - this.queryData_.setValues(key, values); - return this; -}; +goog.provide('goog.events.FileDropHandler'); +goog.provide('goog.events.FileDropHandler.EventType'); +goog.require('goog.array'); +goog.require('goog.dom'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.EventHandler'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('goog.log'); +goog.require('goog.log.Level'); -/** - * Returns the value<b>s</b> for a given cgi parameter as a list of decoded - * query parameter values. - * @param {string} name The parameter to get values for. - * @return {!Array<?>} The values for a given cgi parameter as a list of - * decoded query parameter values. - */ -goog.Uri.prototype.getParameterValues = function(name) { - return this.queryData_.getValues(name); -}; /** - * Returns the first value for a given cgi parameter or undefined if the given - * parameter name does not appear in the query string. - * @param {string} paramName Unescaped parameter name. - * @return {string|undefined} The first value for a given cgi parameter or - * undefined if the given parameter name does not appear in the query - * string. + * A files drag and drop event detector. Gets an {@code element} as parameter + * and fires {@code goog.events.FileDropHandler.EventType.DROP} event when files + * are dropped in the {@code element}. + * + * @param {Element|Document} element The element or document to listen on. + * @param {boolean=} opt_preventDropOutside Whether to prevent a drop on the + * area outside the {@code element}. Default false. + * @constructor + * @extends {goog.events.EventTarget} + * @final */ -goog.Uri.prototype.getParameterValue = function(paramName) { - // NOTE(nicksantos): This type-cast is a lie when - // preserveParameterTypesCompatibilityFlag is set to true. - // But this should only be set to true in tests. - return /** @type {string|undefined} */ (this.queryData_.get(paramName)); -}; - +goog.events.FileDropHandler = function(element, opt_preventDropOutside) { + goog.events.EventTarget.call(this); -/** - * @return {string} The URI fragment, not including the #. - */ -goog.Uri.prototype.getFragment = function() { - return this.fragment_; -}; + /** + * Handler for drag/drop events. + * @type {!goog.events.EventHandler<!goog.events.FileDropHandler>} + * @private + */ + this.eventHandler_ = new goog.events.EventHandler(this); + var doc = element; + if (opt_preventDropOutside) { + doc = goog.dom.getOwnerDocument(element); + } -/** - * Sets the URI fragment. - * @throws URIError If opt_decode is true and newFragment is malformed (that is, - * if decodeURIComponent fails). - * @param {string} newFragment New fragment value. - * @param {boolean=} opt_decode Optional param for whether to decode new value. - * @return {!goog.Uri} Reference to this URI object. - */ -goog.Uri.prototype.setFragment = function(newFragment, opt_decode) { - this.enforceReadOnly(); - this.fragment_ = opt_decode ? goog.Uri.decodeOrEmpty_(newFragment) : - newFragment; - return this; -}; + // Add dragenter listener to the owner document of the element. + this.eventHandler_.listen(doc, + goog.events.EventType.DRAGENTER, + this.onDocDragEnter_); + // Add dragover listener to the owner document of the element only if the + // document is not the element itself. + if (doc != element) { + this.eventHandler_.listen(doc, + goog.events.EventType.DRAGOVER, + this.onDocDragOver_); + } -/** - * @return {boolean} Whether the URI has a fragment set. - */ -goog.Uri.prototype.hasFragment = function() { - return !!this.fragment_; + // Add dragover and drop listeners to the element. + this.eventHandler_.listen(element, + goog.events.EventType.DRAGOVER, + this.onElemDragOver_); + this.eventHandler_.listen(element, + goog.events.EventType.DROP, + this.onElemDrop_); }; +goog.inherits(goog.events.FileDropHandler, goog.events.EventTarget); /** - * Returns true if this has the same domain as that of uri2. - * @param {!goog.Uri} uri2 The URI object to compare to. - * @return {boolean} true if same domain; false otherwise. + * Whether the drag event contains files. It is initialized only in the + * dragenter event. It is used in all the drag events to prevent default actions + * only if the drag contains files. Preventing default actions is necessary to + * go from dragenter to dragover and from dragover to drop. However we do not + * always want to prevent default actions, e.g. when the user drags text or + * links on a text area we should not prevent the browser default action that + * inserts the text in the text area. It is also necessary to stop propagation + * when handling drag events on the element to prevent them from propagating + * to the document. + * @private + * @type {boolean} */ -goog.Uri.prototype.hasSameDomainAs = function(uri2) { - return ((!this.hasDomain() && !uri2.hasDomain()) || - this.getDomain() == uri2.getDomain()) && - ((!this.hasPort() && !uri2.hasPort()) || - this.getPort() == uri2.getPort()); -}; +goog.events.FileDropHandler.prototype.dndContainsFiles_ = false; /** - * Adds a random parameter to the Uri. - * @return {!goog.Uri} Reference to this Uri object. + * A logger, used to help us debug the algorithm. + * @type {goog.log.Logger} + * @private */ -goog.Uri.prototype.makeUnique = function() { - this.enforceReadOnly(); - this.setParameterValue(goog.Uri.RANDOM_PARAM, goog.string.getRandomString()); - - return this; -}; +goog.events.FileDropHandler.prototype.logger_ = + goog.log.getLogger('goog.events.FileDropHandler'); /** - * Removes the named query parameter. - * - * @param {string} key The parameter to remove. - * @return {!goog.Uri} Reference to this URI object. + * The types of events fired by this class. + * @enum {string} */ -goog.Uri.prototype.removeParameter = function(key) { - this.enforceReadOnly(); - this.queryData_.remove(key); - return this; +goog.events.FileDropHandler.EventType = { + DROP: goog.events.EventType.DROP }; -/** - * Sets whether Uri is read only. If this goog.Uri is read-only, - * enforceReadOnly_ will be called at the start of any function that may modify - * this Uri. - * @param {boolean} isReadOnly whether this goog.Uri should be read only. - * @return {!goog.Uri} Reference to this Uri object. - */ -goog.Uri.prototype.setReadOnly = function(isReadOnly) { - this.isReadOnly_ = isReadOnly; - return this; +/** @override */ +goog.events.FileDropHandler.prototype.disposeInternal = function() { + goog.events.FileDropHandler.superClass_.disposeInternal.call(this); + this.eventHandler_.dispose(); }; /** - * @return {boolean} Whether the URI is read only. + * Dispatches the DROP event. + * @param {goog.events.BrowserEvent} e The underlying browser event. + * @private */ -goog.Uri.prototype.isReadOnly = function() { - return this.isReadOnly_; +goog.events.FileDropHandler.prototype.dispatch_ = function(e) { + goog.log.fine(this.logger_, 'Firing DROP event...'); + var event = new goog.events.BrowserEvent(e.getBrowserEvent()); + event.type = goog.events.FileDropHandler.EventType.DROP; + this.dispatchEvent(event); }; /** - * Checks if this Uri has been marked as read only, and if so, throws an error. - * This should be called whenever any modifying function is called. + * Handles dragenter on the document. + * @param {goog.events.BrowserEvent} e The dragenter event. + * @private */ -goog.Uri.prototype.enforceReadOnly = function() { - if (this.isReadOnly_) { - throw Error('Tried to modify a read-only Uri'); +goog.events.FileDropHandler.prototype.onDocDragEnter_ = function(e) { + goog.log.log(this.logger_, goog.log.Level.FINER, + '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); + var dt = e.getBrowserEvent().dataTransfer; + // Check whether the drag event contains files. + this.dndContainsFiles_ = !!(dt && + ((dt.types && + (goog.array.contains(dt.types, 'Files') || + goog.array.contains(dt.types, 'public.file-url'))) || + (dt.files && dt.files.length > 0))); + // If it does + if (this.dndContainsFiles_) { + // Prevent default actions. + e.preventDefault(); } + goog.log.log(this.logger_, goog.log.Level.FINER, + 'dndContainsFiles_: ' + this.dndContainsFiles_); }; /** - * Sets whether to ignore case. - * NOTE: If there are already key/value pairs in the QueryData, and - * ignoreCase_ is set to false, the keys will all be lower-cased. - * @param {boolean} ignoreCase whether this goog.Uri should ignore case. - * @return {!goog.Uri} Reference to this Uri object. + * Handles dragging something over the document. + * @param {goog.events.BrowserEvent} e The dragover event. + * @private */ -goog.Uri.prototype.setIgnoreCase = function(ignoreCase) { - this.ignoreCase_ = ignoreCase; - if (this.queryData_) { - this.queryData_.setIgnoreCase(ignoreCase); +goog.events.FileDropHandler.prototype.onDocDragOver_ = function(e) { + goog.log.log(this.logger_, goog.log.Level.FINEST, + '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); + if (this.dndContainsFiles_) { + // Prevent default actions. + e.preventDefault(); + // Disable the drop on the document outside the drop zone. + var dt = e.getBrowserEvent().dataTransfer; + dt.dropEffect = 'none'; } - return this; }; /** - * @return {boolean} Whether to ignore case. + * Handles dragging something over the element (drop zone). + * @param {goog.events.BrowserEvent} e The dragover event. + * @private */ -goog.Uri.prototype.getIgnoreCase = function() { - return this.ignoreCase_; -}; - +goog.events.FileDropHandler.prototype.onElemDragOver_ = function(e) { + goog.log.log(this.logger_, goog.log.Level.FINEST, + '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); + if (this.dndContainsFiles_) { + // Prevent default actions and stop the event from propagating further to + // the document. Both lines are needed! (See comment above). + e.preventDefault(); + e.stopPropagation(); + // Allow the drop on the drop zone. + var dt = e.getBrowserEvent().dataTransfer; -//============================================================================== -// Static members -//============================================================================== + // IE bug #811625 (https://goo.gl/UWuxX0) will throw error SCRIPT65535 + // when attempting to set property effectAllowed on IE10+. + // See more: https://github.com/google/closure-library/issues/485. + try { + dt.effectAllowed = 'all'; + } catch (err) { + } + dt.dropEffect = 'copy'; + } +}; /** - * Creates a uri from the string form. Basically an alias of new goog.Uri(). - * If a Uri object is passed to parse then it will return a clone of the object. - * - * @throws URIError If parsing the URI is malformed. The passed URI components - * should all be parseable by decodeURIComponent. - * @param {*} uri Raw URI string or instance of Uri - * object. - * @param {boolean=} opt_ignoreCase Whether to ignore the case of parameter - * names in #getParameterValue. - * @return {!goog.Uri} The new URI object. + * Handles dropping something onto the element (drop zone). + * @param {goog.events.BrowserEvent} e The drop event. + * @private */ -goog.Uri.parse = function(uri, opt_ignoreCase) { - return uri instanceof goog.Uri ? - uri.clone() : new goog.Uri(uri, opt_ignoreCase); +goog.events.FileDropHandler.prototype.onElemDrop_ = function(e) { + goog.log.log(this.logger_, goog.log.Level.FINER, + '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); + // If the drag and drop event contains files. + if (this.dndContainsFiles_) { + // Prevent default actions and stop the event from propagating further to + // the document. Both lines are needed! (See comment above). + e.preventDefault(); + e.stopPropagation(); + // Dispatch DROP event. + this.dispatch_(e); + } }; +// Copyright 2007 Bob Ippolito. All Rights Reserved. +// Modifications Copyright 2009 The Closure Library Authors. All Rights +// Reserved. + +/** + * @license Portions of this code are from MochiKit, received by + * The Closure Authors under the MIT license. All other code is Copyright + * 2005-2009 The Closure Authors. All Rights Reserved. + */ /** - * Creates a new goog.Uri object from unencoded parts. + * @fileoverview Classes for tracking asynchronous operations and handling the + * results. The Deferred object here is patterned after the Deferred object in + * the Twisted python networking framework. * - * @param {?string=} opt_scheme Scheme/protocol or full URI to parse. - * @param {?string=} opt_userInfo username:password. - * @param {?string=} opt_domain www.google.com. - * @param {?number=} opt_port 9830. - * @param {?string=} opt_path /some/path/to/a/file.html. - * @param {string|goog.Uri.QueryData=} opt_query a=1&b=2. - * @param {?string=} opt_fragment The fragment without the #. - * @param {boolean=} opt_ignoreCase Whether to ignore parameter name case in - * #getParameterValue. + * See: http://twistedmatrix.com/projects/core/documentation/howto/defer.html * - * @return {!goog.Uri} The new URI object. + * Based on the Dojo code which in turn is based on the MochiKit code. + * + * @author arv@google.com (Erik Arvidsson) + * @author brenneman@google.com (Shawn Brenneman) */ -goog.Uri.create = function(opt_scheme, opt_userInfo, opt_domain, opt_port, - opt_path, opt_query, opt_fragment, opt_ignoreCase) { - var uri = new goog.Uri(null, opt_ignoreCase); +goog.provide('goog.async.Deferred'); +goog.provide('goog.async.Deferred.AlreadyCalledError'); +goog.provide('goog.async.Deferred.CanceledError'); - // Only set the parts if they are defined and not empty strings. - opt_scheme && uri.setScheme(opt_scheme); - opt_userInfo && uri.setUserInfo(opt_userInfo); - opt_domain && uri.setDomain(opt_domain); - opt_port && uri.setPort(opt_port); - opt_path && uri.setPath(opt_path); - opt_query && uri.setQueryData(opt_query); - opt_fragment && uri.setFragment(opt_fragment); +goog.require('goog.Promise'); +goog.require('goog.Thenable'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.debug.Error'); - return uri; -}; /** - * Resolves a relative Uri against a base Uri, accepting both strings and - * Uri objects. + * A Deferred represents the result of an asynchronous operation. A Deferred + * instance has no result when it is created, and is "fired" (given an initial + * result) by calling {@code callback} or {@code errback}. * - * @param {*} base Base Uri. - * @param {*} rel Relative Uri. - * @return {!goog.Uri} Resolved uri. + * Once fired, the result is passed through a sequence of callback functions + * registered with {@code addCallback} or {@code addErrback}. The functions may + * mutate the result before it is passed to the next function in the sequence. + * + * Callbacks and errbacks may be added at any time, including after the Deferred + * has been "fired". If there are no pending actions in the execution sequence + * of a fired Deferred, any new callback functions will be called with the last + * computed result. Adding a callback function is the only way to access the + * result of the Deferred. + * + * If a Deferred operation is canceled, an optional user-provided cancellation + * function is invoked which may perform any special cleanup, followed by firing + * the Deferred's errback sequence with a {@code CanceledError}. If the + * Deferred has already fired, cancellation is ignored. + * + * Deferreds may be templated to a specific type they produce using generics + * with syntax such as: + * <code> + * /** @type {goog.async.Deferred<string>} */ + * var d = new goog.async.Deferred(); + * // Compiler can infer that foo is a string. + * d.addCallback(function(foo) {...}); + * d.callback('string'); // Checked to be passed a string + * </code> + * Since deferreds are often used to produce different values across a chain, + * the type information is not propagated across chains, but rather only + * associated with specifically cast objects. + * + * @param {Function=} opt_onCancelFunction A function that will be called if the + * Deferred is canceled. If provided, this function runs before the + * Deferred is fired with a {@code CanceledError}. + * @param {Object=} opt_defaultScope The default object context to call + * callbacks and errbacks in. + * @constructor + * @implements {goog.Thenable<VALUE>} + * @template VALUE */ -goog.Uri.resolve = function(base, rel) { - if (!(base instanceof goog.Uri)) { - base = goog.Uri.parse(base); - } +goog.async.Deferred = function(opt_onCancelFunction, opt_defaultScope) { + /** + * Entries in the sequence are arrays containing a callback, an errback, and + * an optional scope. The callback or errback in an entry may be null. + * @type {!Array<!Array>} + * @private + */ + this.sequence_ = []; - if (!(rel instanceof goog.Uri)) { - rel = goog.Uri.parse(rel); - } + /** + * Optional function that will be called if the Deferred is canceled. + * @type {Function|undefined} + * @private + */ + this.onCancelFunction_ = opt_onCancelFunction; - return base.resolve(rel); -}; + /** + * The default scope to execute callbacks and errbacks in. + * @type {Object} + * @private + */ + this.defaultScope_ = opt_defaultScope || null; + /** + * Whether the Deferred has been fired. + * @type {boolean} + * @private + */ + this.fired_ = false; -/** - * Removes dot segments in given path component, as described in - * RFC 3986, section 5.2.4. - * - * @param {string} path A non-empty path component. - * @return {string} Path component with removed dot segments. - */ -goog.Uri.removeDotSegments = function(path) { - if (path == '..' || path == '.') { - return ''; + /** + * Whether the last result in the execution sequence was an error. + * @type {boolean} + * @private + */ + this.hadError_ = false; - } else if (!goog.string.contains(path, './') && - !goog.string.contains(path, '/.')) { - // This optimization detects uris which do not contain dot-segments, - // and as a consequence do not require any processing. - return path; + /** + * The current Deferred result, updated as callbacks and errbacks are + * executed. + * @type {*} + * @private + */ + this.result_ = undefined; - } else { - var leadingSlash = goog.string.startsWith(path, '/'); - var segments = path.split('/'); - var out = []; + /** + * Whether the Deferred is blocked waiting on another Deferred to fire. If a + * callback or errback returns a Deferred as a result, the execution sequence + * is blocked until that Deferred result becomes available. + * @type {boolean} + * @private + */ + this.blocked_ = false; - for (var pos = 0; pos < segments.length; ) { - var segment = segments[pos++]; + /** + * Whether this Deferred is blocking execution of another Deferred. If this + * instance was returned as a result in another Deferred's execution + * sequence,that other Deferred becomes blocked until this instance's + * execution sequence completes. No additional callbacks may be added to a + * Deferred once it is blocking another instance. + * @type {boolean} + * @private + */ + this.blocking_ = false; - if (segment == '.') { - if (leadingSlash && pos == segments.length) { - out.push(''); - } - } else if (segment == '..') { - if (out.length > 1 || out.length == 1 && out[0] != '') { - out.pop(); - } - if (leadingSlash && pos == segments.length) { - out.push(''); - } - } else { - out.push(segment); - leadingSlash = true; + /** + * Whether the Deferred has been canceled without having a custom cancel + * function. + * @type {boolean} + * @private + */ + this.silentlyCanceled_ = false; + + /** + * If an error is thrown during Deferred execution with no errback to catch + * it, the error is rethrown after a timeout. Reporting the error after a + * timeout allows execution to continue in the calling context (empty when + * no error is scheduled). + * @type {number} + * @private + */ + this.unhandledErrorId_ = 0; + + /** + * If this Deferred was created by branch(), this will be the "parent" + * Deferred. + * @type {goog.async.Deferred} + * @private + */ + this.parent_ = null; + + /** + * The number of Deferred objects that have been branched off this one. This + * will be decremented whenever a branch is fired or canceled. + * @type {number} + * @private + */ + this.branches_ = 0; + + if (goog.async.Deferred.LONG_STACK_TRACES) { + /** + * Holds the stack trace at time of deferred creation if the JS engine + * provides the Error.captureStackTrace API. + * @private {?string} + */ + this.constructorStack_ = null; + if (Error.captureStackTrace) { + var target = { stack: '' }; + Error.captureStackTrace(target, goog.async.Deferred); + // Check if Error.captureStackTrace worked. It fails in gjstest. + if (typeof target.stack == 'string') { + // Remove first line and force stringify to prevent memory leak due to + // holding on to actual stack frames. + this.constructorStack_ = target.stack.replace(/^[^\n]*\n/, ''); } } - - return out.join('/'); } }; /** - * Decodes a value or returns the empty string if it isn't defined or empty. - * @throws URIError If decodeURIComponent fails to decode val. - * @param {string|undefined} val Value to decode. - * @param {boolean=} opt_preserveReserved If true, restricted characters will - * not be decoded. - * @return {string} Decoded value. - * @private + * @define {boolean} Whether unhandled errors should always get rethrown to the + * global scope. Defaults to the value of goog.DEBUG. */ -goog.Uri.decodeOrEmpty_ = function(val, opt_preserveReserved) { - // Don't use UrlDecode() here because val is not a query parameter. - if (!val) { - return ''; - } +goog.define('goog.async.Deferred.STRICT_ERRORS', false); - // decodeURI has the same output for '%2f' and '%252f'. We double encode %25 - // so that we can distinguish between the 2 inputs. This is later undone by - // removeDoubleEncoding_. - return opt_preserveReserved ? - decodeURI(val.replace(/%25/g, '%2525')) : decodeURIComponent(val); -}; + +/** + * @define {boolean} Whether to attempt to make stack traces long. Defaults to + * the value of goog.DEBUG. + */ +goog.define('goog.async.Deferred.LONG_STACK_TRACES', false); /** - * If unescapedPart is non null, then escapes any characters in it that aren't - * valid characters in a url and also escapes any special characters that - * appear in extra. + * Cancels a Deferred that has not yet been fired, or is blocked on another + * deferred operation. If this Deferred is waiting for a blocking Deferred to + * fire, the blocking Deferred will also be canceled. * - * @param {*} unescapedPart The string to encode. - * @param {RegExp} extra A character set of characters in [\01-\177]. - * @param {boolean=} opt_removeDoubleEncoding If true, remove double percent - * encoding. - * @return {?string} null iff unescapedPart == null. - * @private + * If this Deferred was created by calling branch() on a parent Deferred with + * opt_propagateCancel set to true, the parent may also be canceled. If + * opt_deepCancel is set, cancel() will be called on the parent (as well as any + * other ancestors if the parent is also a branch). If one or more branches were + * created with opt_propagateCancel set to true, the parent will be canceled if + * cancel() is called on all of those branches. + * + * @param {boolean=} opt_deepCancel If true, cancels this Deferred's parent even + * if cancel() hasn't been called on some of the parent's branches. Has no + * effect on a branch without opt_propagateCancel set to true. */ -goog.Uri.encodeSpecialChars_ = function(unescapedPart, extra, - opt_removeDoubleEncoding) { - if (goog.isString(unescapedPart)) { - var encoded = encodeURI(unescapedPart). - replace(extra, goog.Uri.encodeChar_); - if (opt_removeDoubleEncoding) { - // encodeURI double-escapes %XX sequences used to represent restricted - // characters in some URI components, remove the double escaping here. - encoded = goog.Uri.removeDoubleEncoding_(encoded); +goog.async.Deferred.prototype.cancel = function(opt_deepCancel) { + if (!this.hasFired()) { + if (this.parent_) { + // Get rid of the parent reference before potentially running the parent's + // canceler function to ensure that this cancellation isn't + // double-counted. + var parent = this.parent_; + delete this.parent_; + if (opt_deepCancel) { + parent.cancel(opt_deepCancel); + } else { + parent.branchCancel_(); + } } - return encoded; + + if (this.onCancelFunction_) { + // Call in user-specified scope. + this.onCancelFunction_.call(this.defaultScope_, this); + } else { + this.silentlyCanceled_ = true; + } + if (!this.hasFired()) { + this.errback(new goog.async.Deferred.CanceledError(this)); + } + } else if (this.result_ instanceof goog.async.Deferred) { + this.result_.cancel(); } - return null; }; /** - * Converts a character in [\01-\177] to its unicode character equivalent. - * @param {string} ch One character string. - * @return {string} Encoded string. + * Handle a single branch being canceled. Once all branches are canceled, this + * Deferred will be canceled as well. + * * @private */ -goog.Uri.encodeChar_ = function(ch) { - var n = ch.charCodeAt(0); - return '%' + ((n >> 4) & 0xf).toString(16) + (n & 0xf).toString(16); +goog.async.Deferred.prototype.branchCancel_ = function() { + this.branches_--; + if (this.branches_ <= 0) { + this.cancel(); + } }; /** - * Removes double percent-encoding from a string. - * @param {string} doubleEncodedString String - * @return {string} String with double encoding removed. + * Called after a blocking Deferred fires. Unblocks this Deferred and resumes + * its execution sequence. + * + * @param {boolean} isSuccess Whether the result is a success or an error. + * @param {*} res The result of the blocking Deferred. * @private */ -goog.Uri.removeDoubleEncoding_ = function(doubleEncodedString) { - return doubleEncodedString.replace(/%25([0-9a-fA-F]{2})/g, '%$1'); +goog.async.Deferred.prototype.continue_ = function(isSuccess, res) { + this.blocked_ = false; + this.updateResult_(isSuccess, res); }; /** - * Regular expression for characters that are disallowed in the scheme or - * userInfo part of the URI. - * @type {RegExp} + * Updates the current result based on the success or failure of the last action + * in the execution sequence. + * + * @param {boolean} isSuccess Whether the new result is a success or an error. + * @param {*} res The result. * @private */ -goog.Uri.reDisallowedInSchemeOrUserInfo_ = /[#\/\?@]/g; +goog.async.Deferred.prototype.updateResult_ = function(isSuccess, res) { + this.fired_ = true; + this.result_ = res; + this.hadError_ = !isSuccess; + this.fire_(); +}; /** - * Regular expression for characters that are disallowed in a relative path. - * Colon is included due to RFC 3986 3.3. - * @type {RegExp} + * Verifies that the Deferred has not yet been fired. + * * @private + * @throws {Error} If this has already been fired. */ -goog.Uri.reDisallowedInRelativePath_ = /[\#\?:]/g; +goog.async.Deferred.prototype.check_ = function() { + if (this.hasFired()) { + if (!this.silentlyCanceled_) { + throw new goog.async.Deferred.AlreadyCalledError(this); + } + this.silentlyCanceled_ = false; + } +}; + + +/** + * Fire the execution sequence for this Deferred by passing the starting result + * to the first registered callback. + * @param {VALUE=} opt_result The starting result. + */ +goog.async.Deferred.prototype.callback = function(opt_result) { + this.check_(); + this.assertNotDeferred_(opt_result); + this.updateResult_(true /* isSuccess */, opt_result); +}; /** - * Regular expression for characters that are disallowed in an absolute path. - * @type {RegExp} - * @private + * Fire the execution sequence for this Deferred by passing the starting error + * result to the first registered errback. + * @param {*=} opt_result The starting error. */ -goog.Uri.reDisallowedInAbsolutePath_ = /[\#\?]/g; +goog.async.Deferred.prototype.errback = function(opt_result) { + this.check_(); + this.assertNotDeferred_(opt_result); + this.makeStackTraceLong_(opt_result); + this.updateResult_(false /* isSuccess */, opt_result); +}; /** - * Regular expression for characters that are disallowed in the query. - * @type {RegExp} + * Attempt to make the error's stack trace be long in that it contains the + * stack trace from the point where the deferred was created on top of the + * current stack trace to give additional context. + * @param {*} error * @private */ -goog.Uri.reDisallowedInQuery_ = /[\#\?@]/g; +goog.async.Deferred.prototype.makeStackTraceLong_ = function(error) { + if (!goog.async.Deferred.LONG_STACK_TRACES) { + return; + } + if (this.constructorStack_ && goog.isObject(error) && error.stack && + // Stack looks like it was system generated. See + // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi + (/^[^\n]+(\n [^\n]+)+/).test(error.stack)) { + error.stack = error.stack + '\nDEFERRED OPERATION:\n' + + this.constructorStack_; + } +}; /** - * Regular expression for characters that are disallowed in the fragment. - * @type {RegExp} + * Asserts that an object is not a Deferred. + * @param {*} obj The object to test. + * @throws {Error} Throws an exception if the object is a Deferred. * @private */ -goog.Uri.reDisallowedInFragment_ = /#/g; +goog.async.Deferred.prototype.assertNotDeferred_ = function(obj) { + goog.asserts.assert( + !(obj instanceof goog.async.Deferred), + 'An execution sequence may not be initiated with a blocking Deferred.'); +}; /** - * Checks whether two URIs have the same domain. - * @param {string} uri1String First URI string. - * @param {string} uri2String Second URI string. - * @return {boolean} true if the two URIs have the same domain; false otherwise. + * Register a callback function to be called with a successful result. If no + * value is returned by the callback function, the result value is unchanged. If + * a new value is returned, it becomes the Deferred result and will be passed to + * the next callback in the execution sequence. + * + * If the function throws an error, the error becomes the new result and will be + * passed to the next errback in the execution chain. + * + * If the function returns a Deferred, the execution sequence will be blocked + * until that Deferred fires. Its result will be passed to the next callback (or + * errback if it is an error result) in this Deferred's execution sequence. + * + * @param {!function(this:T,VALUE):?} cb The function to be called with a + * successful result. + * @param {T=} opt_scope An optional scope to call the callback in. + * @return {!goog.async.Deferred} This Deferred. + * @template T */ -goog.Uri.haveSameDomain = function(uri1String, uri2String) { - // Differs from goog.uri.utils.haveSameDomain, since this ignores scheme. - // TODO(gboyer): Have this just call goog.uri.util.haveSameDomain. - var pieces1 = goog.uri.utils.split(uri1String); - var pieces2 = goog.uri.utils.split(uri2String); - return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] == - pieces2[goog.uri.utils.ComponentIndex.DOMAIN] && - pieces1[goog.uri.utils.ComponentIndex.PORT] == - pieces2[goog.uri.utils.ComponentIndex.PORT]; +goog.async.Deferred.prototype.addCallback = function(cb, opt_scope) { + return this.addCallbacks(cb, null, opt_scope); }; - /** - * Class used to represent URI query parameters. It is essentially a hash of - * name-value pairs, though a name can be present more than once. + * Register a callback function to be called with an error result. If no value + * is returned by the function, the error result is unchanged. If a new error + * value is returned or thrown, that error becomes the Deferred result and will + * be passed to the next errback in the execution sequence. * - * Has the same interface as the collections in goog.structs. + * If the errback function handles the error by returning a non-error value, + * that result will be passed to the next normal callback in the sequence. * - * @param {?string=} opt_query Optional encoded query string to parse into - * the object. - * @param {goog.Uri=} opt_uri Optional uri object that should have its - * cache invalidated when this object updates. Deprecated -- this - * is no longer required. - * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter - * name in #get. - * @constructor - * @struct - * @final + * If the function returns a Deferred, the execution sequence will be blocked + * until that Deferred fires. Its result will be passed to the next callback (or + * errback if it is an error result) in this Deferred's execution sequence. + * + * @param {!function(this:T,?):?} eb The function to be called on an + * unsuccessful result. + * @param {T=} opt_scope An optional scope to call the errback in. + * @return {!goog.async.Deferred<VALUE>} This Deferred. + * @template T */ -goog.Uri.QueryData = function(opt_query, opt_uri, opt_ignoreCase) { - /** - * The map containing name/value or name/array-of-values pairs. - * May be null if it requires parsing from the query string. - * - * We need to use a Map because we cannot guarantee that the key names will - * not be problematic for IE. - * - * @private {goog.structs.Map<string, !Array<*>>} - */ - this.keyMap_ = null; - - /** - * The number of params, or null if it requires computing. - * @private {?number} - */ - this.count_ = null; - - /** - * Encoded query string, or null if it requires computing from the key map. - * @private {?string} - */ - this.encodedQuery_ = opt_query || null; - - /** - * If true, ignore the case of the parameter name in #get. - * @private {boolean} - */ - this.ignoreCase_ = !!opt_ignoreCase; +goog.async.Deferred.prototype.addErrback = function(eb, opt_scope) { + return this.addCallbacks(null, eb, opt_scope); }; /** - * If the underlying key map is not yet initialized, it parses the - * query string and fills the map with parsed data. - * @private + * Registers one function as both a callback and errback. + * + * @param {!function(this:T,?):?} f The function to be called on any result. + * @param {T=} opt_scope An optional scope to call the function in. + * @return {!goog.async.Deferred} This Deferred. + * @template T */ -goog.Uri.QueryData.prototype.ensureKeyMapInitialized_ = function() { - if (!this.keyMap_) { - this.keyMap_ = new goog.structs.Map(); - this.count_ = 0; - if (this.encodedQuery_) { - var self = this; - goog.uri.utils.parseQueryData(this.encodedQuery_, function(name, value) { - self.add(goog.string.urlDecode(name), value); - }); - } - } +goog.async.Deferred.prototype.addBoth = function(f, opt_scope) { + return this.addCallbacks(f, f, opt_scope); }; /** - * Creates a new query data instance from a map of names and values. + * Like addBoth, but propagates uncaught exceptions in the errback. * - * @param {!goog.structs.Map<string, ?>|!Object} map Map of string parameter - * names to parameter value. If parameter value is an array, it is - * treated as if the key maps to each individual value in the - * array. - * @param {goog.Uri=} opt_uri URI object that should have its cache - * invalidated when this object updates. - * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter - * name in #get. - * @return {!goog.Uri.QueryData} The populated query data instance. + * @param {function(this:T,?):?} f The function to be called on any result. + * @param {T=} opt_scope An optional scope to call the function in. + * @return {!goog.async.Deferred<VALUE>} This Deferred. + * @template T */ -goog.Uri.QueryData.createFromMap = function(map, opt_uri, opt_ignoreCase) { - var keys = goog.structs.getKeys(map); - if (typeof keys == 'undefined') { - throw Error('Keys are undefined'); - } - - var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase); - var values = goog.structs.getValues(map); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = values[i]; - if (!goog.isArray(value)) { - queryData.add(key, value); - } else { - queryData.setValues(key, value); +goog.async.Deferred.prototype.addFinally = function(f, opt_scope) { + var self = this; + return this.addCallbacks(f, function(err) { + var result = f.call(self, err); + if (!goog.isDef(result)) { + throw err; } - } - return queryData; + return result; + }, opt_scope); }; /** - * Creates a new query data instance from parallel arrays of parameter names - * and values. Allows for duplicate parameter names. Throws an error if the - * lengths of the arrays differ. + * Registers a callback function and an errback function at the same position + * in the execution sequence. Only one of these functions will execute, + * depending on the error state during the execution sequence. * - * @param {!Array<string>} keys Parameter names. - * @param {!Array<?>} values Parameter values. - * @param {goog.Uri=} opt_uri URI object that should have its cache - * invalidated when this object updates. - * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter - * name in #get. - * @return {!goog.Uri.QueryData} The populated query data instance. + * NOTE: This is not equivalent to {@code def.addCallback().addErrback()}! If + * the callback is invoked, the errback will be skipped, and vice versa. + * + * @param {?(function(this:T,VALUE):?)} cb The function to be called on a + * successful result. + * @param {?(function(this:T,?):?)} eb The function to be called on an + * unsuccessful result. + * @param {T=} opt_scope An optional scope to call the functions in. + * @return {!goog.async.Deferred} This Deferred. + * @template T */ -goog.Uri.QueryData.createFromKeysValues = function( - keys, values, opt_uri, opt_ignoreCase) { - if (keys.length != values.length) { - throw Error('Mismatched lengths for keys/values'); - } - var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase); - for (var i = 0; i < keys.length; i++) { - queryData.add(keys[i], values[i]); +goog.async.Deferred.prototype.addCallbacks = function(cb, eb, opt_scope) { + goog.asserts.assert(!this.blocking_, 'Blocking Deferreds can not be re-used'); + this.sequence_.push([cb, eb, opt_scope]); + if (this.hasFired()) { + this.fire_(); } - return queryData; + return this; }; /** - * @return {?number} The number of parameters. + * Implements {@see goog.Thenable} for seamless integration with + * {@see goog.Promise}. + * Deferred results are mutable and may represent multiple values over + * their lifetime. Calling {@code then} on a Deferred returns a Promise + * with the result of the Deferred at that point in its callback chain. + * Note that if the Deferred result is never mutated, and only + * {@code then} calls are made, the Deferred will behave like a Promise. + * + * @override */ -goog.Uri.QueryData.prototype.getCount = function() { - this.ensureKeyMapInitialized_(); - return this.count_; +goog.async.Deferred.prototype.then = function(opt_onFulfilled, opt_onRejected, + opt_context) { + var resolve, reject; + var promise = new goog.Promise(function(res, rej) { + // Copying resolvers to outer scope, so that they are available when the + // deferred callback fires (which may be synchronous). + resolve = res; + reject = rej; + }); + this.addCallbacks(resolve, function(reason) { + if (reason instanceof goog.async.Deferred.CanceledError) { + promise.cancel(); + } else { + reject(reason); + } + }); + return promise.then(opt_onFulfilled, opt_onRejected, opt_context); }; +goog.Thenable.addImplementation(goog.async.Deferred); /** - * Adds a key value pair. - * @param {string} key Name. - * @param {*} value Value. - * @return {!goog.Uri.QueryData} Instance of this object. + * Links another Deferred to the end of this Deferred's execution sequence. The + * result of this execution sequence will be passed as the starting result for + * the chained Deferred, invoking either its first callback or errback. + * + * @param {!goog.async.Deferred} otherDeferred The Deferred to chain. + * @return {!goog.async.Deferred} This Deferred. */ -goog.Uri.QueryData.prototype.add = function(key, value) { - this.ensureKeyMapInitialized_(); - this.invalidateCache_(); - - key = this.getKeyName_(key); - var values = this.keyMap_.get(key); - if (!values) { - this.keyMap_.set(key, (values = [])); - } - values.push(value); - this.count_++; +goog.async.Deferred.prototype.chainDeferred = function(otherDeferred) { + this.addCallbacks( + otherDeferred.callback, otherDeferred.errback, otherDeferred); return this; }; /** - * Removes all the params with the given key. - * @param {string} key Name. - * @return {boolean} Whether any parameter was removed. + * Makes this Deferred wait for another Deferred's execution sequence to + * complete before continuing. + * + * This is equivalent to adding a callback that returns {@code otherDeferred}, + * but doesn't prevent additional callbacks from being added to + * {@code otherDeferred}. + * + * @param {!goog.async.Deferred|!goog.Thenable} otherDeferred The Deferred + * to wait for. + * @return {!goog.async.Deferred} This Deferred. */ -goog.Uri.QueryData.prototype.remove = function(key) { - this.ensureKeyMapInitialized_(); - - key = this.getKeyName_(key); - if (this.keyMap_.containsKey(key)) { - this.invalidateCache_(); - - // Decrement parameter count. - this.count_ -= this.keyMap_.get(key).length; - return this.keyMap_.remove(key); +goog.async.Deferred.prototype.awaitDeferred = function(otherDeferred) { + if (!(otherDeferred instanceof goog.async.Deferred)) { + // The Thenable case. + return this.addCallback(function() { + return otherDeferred; + }); } - return false; + return this.addCallback(goog.bind(otherDeferred.branch, otherDeferred)); }; /** - * Clears the parameters. + * Creates a branch off this Deferred's execution sequence, and returns it as a + * new Deferred. The branched Deferred's starting result will be shared with the + * parent at the point of the branch, even if further callbacks are added to the + * parent. + * + * All branches at the same stage in the execution sequence will receive the + * same starting value. + * + * @param {boolean=} opt_propagateCancel If cancel() is called on every child + * branch created with opt_propagateCancel, the parent will be canceled as + * well. + * @return {!goog.async.Deferred<VALUE>} A Deferred that will be started with + * the computed result from this stage in the execution sequence. */ -goog.Uri.QueryData.prototype.clear = function() { - this.invalidateCache_(); - this.keyMap_ = null; - this.count_ = 0; +goog.async.Deferred.prototype.branch = function(opt_propagateCancel) { + var d = new goog.async.Deferred(); + this.chainDeferred(d); + if (opt_propagateCancel) { + d.parent_ = this; + this.branches_++; + } + return d; }; /** - * @return {boolean} Whether we have any parameters. + * @return {boolean} Whether the execution sequence has been started on this + * Deferred by invoking {@code callback} or {@code errback}. */ -goog.Uri.QueryData.prototype.isEmpty = function() { - this.ensureKeyMapInitialized_(); - return this.count_ == 0; +goog.async.Deferred.prototype.hasFired = function() { + return this.fired_; }; /** - * Whether there is a parameter with the given name - * @param {string} key The parameter name to check for. - * @return {boolean} Whether there is a parameter with the given name. + * @param {*} res The latest result in the execution sequence. + * @return {boolean} Whether the current result is an error that should cause + * the next errback to fire. May be overridden by subclasses to handle + * special error types. + * @protected */ -goog.Uri.QueryData.prototype.containsKey = function(key) { - this.ensureKeyMapInitialized_(); - key = this.getKeyName_(key); - return this.keyMap_.containsKey(key); +goog.async.Deferred.prototype.isError = function(res) { + return res instanceof Error; }; /** - * Whether there is a parameter with the given value. - * @param {*} value The value to check for. - * @return {boolean} Whether there is a parameter with the given value. + * @return {boolean} Whether an errback exists in the remaining sequence. + * @private */ -goog.Uri.QueryData.prototype.containsValue = function(value) { - // NOTE(arv): This solution goes through all the params even if it was the - // first param. We can get around this by not reusing code or by switching to - // iterators. - var vals = this.getValues(); - return goog.array.contains(vals, value); +goog.async.Deferred.prototype.hasErrback_ = function() { + return goog.array.some(this.sequence_, function(sequenceRow) { + // The errback is the second element in the array. + return goog.isFunction(sequenceRow[1]); + }); }; /** - * Returns all the keys of the parameters. If a key is used multiple times - * it will be included multiple times in the returned array - * @return {!Array<string>} All the keys of the parameters. + * Exhausts the execution sequence while a result is available. The result may + * be modified by callbacks or errbacks, and execution will block if the + * returned result is an incomplete Deferred. + * + * @private */ -goog.Uri.QueryData.prototype.getKeys = function() { - this.ensureKeyMapInitialized_(); - // We need to get the values to know how many keys to add. - var vals = /** @type {!Array<*>} */ (this.keyMap_.getValues()); - var keys = this.keyMap_.getKeys(); - var rv = []; - for (var i = 0; i < keys.length; i++) { - var val = vals[i]; - for (var j = 0; j < val.length; j++) { - rv.push(keys[i]); - } +goog.async.Deferred.prototype.fire_ = function() { + if (this.unhandledErrorId_ && this.hasFired() && this.hasErrback_()) { + // It is possible to add errbacks after the Deferred has fired. If a new + // errback is added immediately after the Deferred encountered an unhandled + // error, but before that error is rethrown, the error is unscheduled. + goog.async.Deferred.unscheduleError_(this.unhandledErrorId_); + this.unhandledErrorId_ = 0; } - return rv; -}; - -/** - * Returns all the values of the parameters with the given name. If the query - * data has no such key this will return an empty array. If no key is given - * all values wil be returned. - * @param {string=} opt_key The name of the parameter to get the values for. - * @return {!Array<?>} All the values of the parameters with the given name. - */ -goog.Uri.QueryData.prototype.getValues = function(opt_key) { - this.ensureKeyMapInitialized_(); - var rv = []; - if (goog.isString(opt_key)) { - if (this.containsKey(opt_key)) { - rv = goog.array.concat(rv, this.keyMap_.get(this.getKeyName_(opt_key))); - } - } else { - // Return all values. - var values = this.keyMap_.getValues(); - for (var i = 0; i < values.length; i++) { - rv = goog.array.concat(rv, values[i]); - } + if (this.parent_) { + this.parent_.branches_--; + delete this.parent_; } - return rv; -}; - - -/** - * Sets a key value pair and removes all other keys with the same value. - * - * @param {string} key Name. - * @param {*} value Value. - * @return {!goog.Uri.QueryData} Instance of this object. - */ -goog.Uri.QueryData.prototype.set = function(key, value) { - this.ensureKeyMapInitialized_(); - this.invalidateCache_(); - // TODO(chrishenry): This could be better written as - // this.remove(key), this.add(key, value), but that would reorder - // the key (since the key is first removed and then added at the - // end) and we would have to fix unit tests that depend on key - // ordering. - key = this.getKeyName_(key); - if (this.containsKey(key)) { - this.count_ -= this.keyMap_.get(key).length; - } - this.keyMap_.set(key, [value]); - this.count_++; - return this; -}; + var res = this.result_; + var unhandledException = false; + var isNewlyBlocked = false; + while (this.sequence_.length && !this.blocked_) { + var sequenceEntry = this.sequence_.shift(); -/** - * Returns the first value associated with the key. If the query data has no - * such key this will return undefined or the optional default. - * @param {string} key The name of the parameter to get the value for. - * @param {*=} opt_default The default value to return if the query data - * has no such key. - * @return {*} The first string value associated with the key, or opt_default - * if there's no value. - */ -goog.Uri.QueryData.prototype.get = function(key, opt_default) { - var values = key ? this.getValues(key) : []; - if (goog.Uri.preserveParameterTypesCompatibilityFlag) { - return values.length > 0 ? values[0] : opt_default; - } else { - return values.length > 0 ? String(values[0]) : opt_default; - } -}; + var callback = sequenceEntry[0]; + var errback = sequenceEntry[1]; + var scope = sequenceEntry[2]; + var f = this.hadError_ ? errback : callback; + if (f) { + /** @preserveTry */ + try { + var ret = f.call(scope || this.defaultScope_, res); -/** - * Sets the values for a key. If the key already exists, this will - * override all of the existing values that correspond to the key. - * @param {string} key The key to set values for. - * @param {!Array<?>} values The values to set. - */ -goog.Uri.QueryData.prototype.setValues = function(key, values) { - this.remove(key); + // If no result, then use previous result. + if (goog.isDef(ret)) { + // Bubble up the error as long as the return value hasn't changed. + this.hadError_ = this.hadError_ && (ret == res || this.isError(ret)); + this.result_ = res = ret; + } - if (values.length > 0) { - this.invalidateCache_(); - this.keyMap_.set(this.getKeyName_(key), goog.array.clone(values)); - this.count_ += values.length; - } -}; + if (goog.Thenable.isImplementedBy(res) || + (typeof goog.global['Promise'] === 'function' && + res instanceof goog.global['Promise'])) { + isNewlyBlocked = true; + this.blocked_ = true; + } + } catch (ex) { + res = ex; + this.hadError_ = true; + this.makeStackTraceLong_(res); -/** - * @return {string} Encoded query string. - * @override - */ -goog.Uri.QueryData.prototype.toString = function() { - if (this.encodedQuery_) { - return this.encodedQuery_; + if (!this.hasErrback_()) { + // If an error is thrown with no additional errbacks in the queue, + // prepare to rethrow the error. + unhandledException = true; + } + } + } } - if (!this.keyMap_) { - return ''; - } + this.result_ = res; - var sb = []; + if (isNewlyBlocked) { + var onCallback = goog.bind(this.continue_, this, true /* isSuccess */); + var onErrback = goog.bind(this.continue_, this, false /* isSuccess */); - // In the past, we use this.getKeys() and this.getVals(), but that - // generates a lot of allocations as compared to simply iterating - // over the keys. - var keys = this.keyMap_.getKeys(); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var encodedKey = goog.string.urlEncode(key); - var val = this.getValues(key); - for (var j = 0; j < val.length; j++) { - var param = encodedKey; - // Ensure that null and undefined are encoded into the url as - // literal strings. - if (val[j] !== '') { - param += '=' + goog.string.urlEncode(val[j]); - } - sb.push(param); + if (res instanceof goog.async.Deferred) { + res.addCallbacks(onCallback, onErrback); + res.blocking_ = true; + } else { + res.then(onCallback, onErrback); } + } else if (goog.async.Deferred.STRICT_ERRORS && this.isError(res) && + !(res instanceof goog.async.Deferred.CanceledError)) { + this.hadError_ = true; + unhandledException = true; } - return this.encodedQuery_ = sb.join('&'); + if (unhandledException) { + // Rethrow the unhandled error after a timeout. Execution will continue, but + // the error will be seen by global handlers and the user. The throw will + // be canceled if another errback is appended before the timeout executes. + // The error's original stack trace is preserved where available. + this.unhandledErrorId_ = goog.async.Deferred.scheduleError_(res); + } }; /** - * @throws URIError If URI is malformed (that is, if decodeURIComponent fails on - * any of the URI components). - * @return {string} Decoded query string. + * Creates a Deferred that has an initial result. + * + * @param {*=} opt_result The result. + * @return {!goog.async.Deferred} The new Deferred. */ -goog.Uri.QueryData.prototype.toDecodedString = function() { - return goog.Uri.decodeOrEmpty_(this.toString()); +goog.async.Deferred.succeed = function(opt_result) { + var d = new goog.async.Deferred(); + d.callback(opt_result); + return d; }; /** - * Invalidate the cache. - * @private + * Creates a Deferred that fires when the given promise resolves. + * Use only during migration to Promises. + * + * @param {!goog.Promise<T>} promise + * @return {!goog.async.Deferred<T>} The new Deferred. + * @template T */ -goog.Uri.QueryData.prototype.invalidateCache_ = function() { - this.encodedQuery_ = null; +goog.async.Deferred.fromPromise = function(promise) { + var d = new goog.async.Deferred(); + d.callback(); + d.addCallback(function() { + return promise; + }); + return d; }; /** - * Removes all keys that are not in the provided list. (Modifies this object.) - * @param {Array<string>} keys The desired keys. - * @return {!goog.Uri.QueryData} a reference to this object. + * Creates a Deferred that has an initial error result. + * + * @param {*} res The error result. + * @return {!goog.async.Deferred} The new Deferred. */ -goog.Uri.QueryData.prototype.filterKeys = function(keys) { - this.ensureKeyMapInitialized_(); - this.keyMap_.forEach( - function(value, key) { - if (!goog.array.contains(keys, key)) { - this.remove(key); - } - }, this); - return this; +goog.async.Deferred.fail = function(res) { + var d = new goog.async.Deferred(); + d.errback(res); + return d; }; /** - * Clone the query data instance. - * @return {!goog.Uri.QueryData} New instance of the QueryData object. + * Creates a Deferred that has already been canceled. + * + * @return {!goog.async.Deferred} The new Deferred. */ -goog.Uri.QueryData.prototype.clone = function() { - var rv = new goog.Uri.QueryData(); - rv.encodedQuery_ = this.encodedQuery_; - if (this.keyMap_) { - rv.keyMap_ = this.keyMap_.clone(); - rv.count_ = this.count_; - } - return rv; +goog.async.Deferred.canceled = function() { + var d = new goog.async.Deferred(); + d.cancel(); + return d; }; /** - * Helper function to get the key name from a JavaScript object. Converts - * the object to a string, and to lower case if necessary. - * @private - * @param {*} arg The object to get a key name from. - * @return {string} valid key name which can be looked up in #keyMap_. + * Normalizes values that may or may not be Deferreds. + * + * If the input value is a Deferred, the Deferred is branched (so the original + * execution sequence is not modified) and the input callback added to the new + * branch. The branch is returned to the caller. + * + * If the input value is not a Deferred, the callback will be executed + * immediately and an already firing Deferred will be returned to the caller. + * + * In the following (contrived) example, if <code>isImmediate</code> is true + * then 3 is alerted immediately, otherwise 6 is alerted after a 2-second delay. + * + * <pre> + * var value; + * if (isImmediate) { + * value = 3; + * } else { + * value = new goog.async.Deferred(); + * setTimeout(function() { value.callback(6); }, 2000); + * } + * + * var d = goog.async.Deferred.when(value, alert); + * </pre> + * + * @param {*} value Deferred or normal value to pass to the callback. + * @param {!function(this:T, ?):?} callback The callback to execute. + * @param {T=} opt_scope An optional scope to call the callback in. + * @return {!goog.async.Deferred} A new Deferred that will call the input + * callback with the input value. + * @template T */ -goog.Uri.QueryData.prototype.getKeyName_ = function(arg) { - var keyName = String(arg); - if (this.ignoreCase_) { - keyName = keyName.toLowerCase(); +goog.async.Deferred.when = function(value, callback, opt_scope) { + if (value instanceof goog.async.Deferred) { + return value.branch(true).addCallback(callback, opt_scope); + } else { + return goog.async.Deferred.succeed(value).addCallback(callback, opt_scope); } - return keyName; }; -/** - * Ignore case in parameter names. - * NOTE: If there are already key/value pairs in the QueryData, and - * ignoreCase_ is set to false, the keys will all be lower-cased. - * @param {boolean} ignoreCase whether this goog.Uri should ignore case. - */ -goog.Uri.QueryData.prototype.setIgnoreCase = function(ignoreCase) { - var resetKeys = ignoreCase && !this.ignoreCase_; - if (resetKeys) { - this.ensureKeyMapInitialized_(); - this.invalidateCache_(); - this.keyMap_.forEach( - function(value, key) { - var lowerCase = key.toLowerCase(); - if (key != lowerCase) { - this.remove(key); - this.setValues(lowerCase, value); - } - }, this); - } - this.ignoreCase_ = ignoreCase; -}; - /** - * Extends a query data object with another query data or map like object. This - * operates 'in-place', it does not create a new QueryData object. + * An error sub class that is used when a Deferred has already been called. + * @param {!goog.async.Deferred} deferred The Deferred. * - * @param {...(goog.Uri.QueryData|goog.structs.Map<?, ?>|Object)} var_args - * The object from which key value pairs will be copied. + * @constructor + * @extends {goog.debug.Error} */ -goog.Uri.QueryData.prototype.extend = function(var_args) { - for (var i = 0; i < arguments.length; i++) { - var data = arguments[i]; - goog.structs.forEach(data, - /** @this {goog.Uri.QueryData} */ - function(value, key) { - this.add(key, value); - }, this); - } +goog.async.Deferred.AlreadyCalledError = function(deferred) { + goog.debug.Error.call(this); + + /** + * The Deferred that raised this error. + * @type {goog.async.Deferred} + */ + this.deferred = deferred; }; +goog.inherits(goog.async.Deferred.AlreadyCalledError, goog.debug.Error); -goog.provide('ol.style.Text'); + +/** @override */ +goog.async.Deferred.AlreadyCalledError.prototype.message = + 'Deferred has already fired'; -goog.require('ol.style.Fill'); +/** @override */ +goog.async.Deferred.AlreadyCalledError.prototype.name = 'AlreadyCalledError'; /** - * @classdesc - * Set text style for vector features. + * An error sub class that is used when a Deferred is canceled. * + * @param {!goog.async.Deferred} deferred The Deferred object. * @constructor - * @param {olx.style.TextOptions=} opt_options Options. - * @api + * @extends {goog.debug.Error} */ -ol.style.Text = function(opt_options) { - - var options = opt_options || {}; - - /** - * @private - * @type {string|undefined} - */ - this.font_ = options.font; +goog.async.Deferred.CanceledError = function(deferred) { + goog.debug.Error.call(this); /** - * @private - * @type {number|undefined} + * The Deferred that raised this error. + * @type {goog.async.Deferred} */ - this.rotation_ = options.rotation; + this.deferred = deferred; +}; +goog.inherits(goog.async.Deferred.CanceledError, goog.debug.Error); - /** - * @private - * @type {number|undefined} - */ - this.scale_ = options.scale; - /** - * @private - * @type {string|undefined} - */ - this.text_ = options.text; +/** @override */ +goog.async.Deferred.CanceledError.prototype.message = 'Deferred was canceled'; - /** - * @private - * @type {string|undefined} - */ - this.textAlign_ = options.textAlign; - /** - * @private - * @type {string|undefined} - */ - this.textBaseline_ = options.textBaseline; +/** @override */ +goog.async.Deferred.CanceledError.prototype.name = 'CanceledError'; - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : - new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_}); - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; - /** - * @private - * @type {number} - */ - this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0; +/** + * Wrapper around errors that are scheduled to be thrown by failing deferreds + * after a timeout. + * + * @param {*} error Error from a failing deferred. + * @constructor + * @final + * @private + * @struct + */ +goog.async.Deferred.Error_ = function(error) { + /** @const @private {number} */ + this.id_ = goog.global.setTimeout(goog.bind(this.throwError, this), 0); - /** - * @private - * @type {number} - */ - this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0; + /** @const @private {*} */ + this.error_ = error; }; /** - * The default fill color to use if no fill was set at construction time; a - * blackish `#333`. - * - * @const {string} - * @private + * Actually throws the error and removes it from the list of pending + * deferred errors. */ -ol.style.Text.DEFAULT_FILL_COLOR_ = '#333'; +goog.async.Deferred.Error_.prototype.throwError = function() { + goog.asserts.assert(goog.async.Deferred.errorMap_[this.id_], + 'Cannot throw an error that is not scheduled.'); + delete goog.async.Deferred.errorMap_[this.id_]; + throw this.error_; +}; /** - * Get the font name. - * @return {string|undefined} Font. - * @api + * Resets the error throw timer. */ -ol.style.Text.prototype.getFont = function() { - return this.font_; +goog.async.Deferred.Error_.prototype.resetTimer = function() { + goog.global.clearTimeout(this.id_); }; /** - * Get the x-offset for the text. - * @return {number} Horizontal text offset. - * @api + * Map of unhandled errors scheduled to be rethrown in a future timestep. + * @private {!Object<number|string, goog.async.Deferred.Error_>} */ -ol.style.Text.prototype.getOffsetX = function() { - return this.offsetX_; -}; +goog.async.Deferred.errorMap_ = {}; /** - * Get the y-offset for the text. - * @return {number} Vertical text offset. - * @api + * Schedules an error to be thrown after a delay. + * @param {*} error Error from a failing deferred. + * @return {number} Id of the error. + * @private */ -ol.style.Text.prototype.getOffsetY = function() { - return this.offsetY_; +goog.async.Deferred.scheduleError_ = function(error) { + var deferredError = new goog.async.Deferred.Error_(error); + goog.async.Deferred.errorMap_[deferredError.id_] = deferredError; + return deferredError.id_; }; /** - * Get the fill style for the text. - * @return {ol.style.Fill} Fill style. - * @api + * Unschedules an error from being thrown. + * @param {number} id Id of the deferred error to unschedule. + * @private */ -ol.style.Text.prototype.getFill = function() { - return this.fill_; +goog.async.Deferred.unscheduleError_ = function(id) { + var error = goog.async.Deferred.errorMap_[id]; + if (error) { + error.resetTimer(); + delete goog.async.Deferred.errorMap_[id]; + } }; /** - * Get the text rotation. - * @return {number|undefined} Rotation. - * @api + * Asserts that there are no pending deferred errors. If there are any + * scheduled errors, one will be thrown immediately to make this function fail. */ -ol.style.Text.prototype.getRotation = function() { - return this.rotation_; +goog.async.Deferred.assertNoErrors = function() { + var map = goog.async.Deferred.errorMap_; + for (var key in map) { + var error = map[key]; + error.resetTimer(); + error.throwError(); + } }; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Get the text scale. - * @return {number|undefined} Scale. - * @api + * @fileoverview A wrapper for the HTML5 FileError object. + * */ -ol.style.Text.prototype.getScale = function() { - return this.scale_; -}; + +goog.provide('goog.fs.Error'); +goog.provide('goog.fs.Error.ErrorCode'); + +goog.require('goog.debug.Error'); +goog.require('goog.object'); +goog.require('goog.string'); + /** - * Get the stroke style for the text. - * @return {ol.style.Stroke} Stroke style. - * @api + * A filesystem error. Since the filesystem API is asynchronous, stack traces + * are less useful for identifying where errors come from, so this includes a + * large amount of metadata in the message. + * + * @param {!DOMError} error + * @param {string} action The action being undertaken when the error was raised. + * @constructor + * @extends {goog.debug.Error} + * @final */ -ol.style.Text.prototype.getStroke = function() { - return this.stroke_; +goog.fs.Error = function(error, action) { + /** @type {string} */ + this.name; + + /** + * @type {goog.fs.Error.ErrorCode} + * @deprecated Use the 'name' or 'message' field instead. + */ + this.code; + + if (goog.isDef(error.name)) { + this.name = error.name; + // TODO(user): Remove warning suppression after JSCompiler stops + // firing a spurious warning here. + /** @suppress {deprecated} */ + this.code = goog.fs.Error.getCodeFromName_(error.name); + } else { + this.code = error.code; + this.name = goog.fs.Error.getNameFromCode_(error.code); + } + goog.fs.Error.base(this, 'constructor', + goog.string.subs('%s %s', this.name, action)); }; +goog.inherits(goog.fs.Error, goog.debug.Error); /** - * Get the text to be rendered. - * @return {string|undefined} Text. - * @api + * Names of errors that may be thrown by the File API, the File System API, or + * the File Writer API. + * + * @see http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException + * @see http://www.w3.org/TR/file-system-api/#definitions + * @see http://dev.w3.org/2009/dap/file-system/file-writer.html#definitions + * @enum {string} */ -ol.style.Text.prototype.getText = function() { - return this.text_; +goog.fs.Error.ErrorName = { + ABORT: 'AbortError', + ENCODING: 'EncodingError', + INVALID_MODIFICATION: 'InvalidModificationError', + INVALID_STATE: 'InvalidStateError', + NOT_FOUND: 'NotFoundError', + NOT_READABLE: 'NotReadableError', + NO_MODIFICATION_ALLOWED: 'NoModificationAllowedError', + PATH_EXISTS: 'PathExistsError', + QUOTA_EXCEEDED: 'QuotaExceededError', + SECURITY: 'SecurityError', + SYNTAX: 'SyntaxError', + TYPE_MISMATCH: 'TypeMismatchError' }; /** - * Get the text alignment. - * @return {string|undefined} Text align. - * @api + * Error codes for file errors. + * @see http://www.w3.org/TR/file-system-api/#idl-def-FileException + * + * @enum {number} + * @deprecated Use the 'name' or 'message' attribute instead. */ -ol.style.Text.prototype.getTextAlign = function() { - return this.textAlign_; +goog.fs.Error.ErrorCode = { + NOT_FOUND: 1, + SECURITY: 2, + ABORT: 3, + NOT_READABLE: 4, + ENCODING: 5, + NO_MODIFICATION_ALLOWED: 6, + INVALID_STATE: 7, + SYNTAX: 8, + INVALID_MODIFICATION: 9, + QUOTA_EXCEEDED: 10, + TYPE_MISMATCH: 11, + PATH_EXISTS: 12 }; /** - * Get the text baseline. - * @return {string|undefined} Text baseline. - * @api + * @param {goog.fs.Error.ErrorCode} code + * @return {string} name + * @private */ -ol.style.Text.prototype.getTextBaseline = function() { - return this.textBaseline_; +goog.fs.Error.getNameFromCode_ = function(code) { + var name = goog.object.findKey(goog.fs.Error.NameToCodeMap_, function(c) { + return code == c; + }); + if (!goog.isDef(name)) { + throw new Error('Invalid code: ' + code); + } + return name; }; /** - * Set the font. - * - * @param {string|undefined} font Font. - * @api + * Returns the code that corresponds to the given name. + * @param {string} name + * @return {goog.fs.Error.ErrorCode} code + * @private */ -ol.style.Text.prototype.setFont = function(font) { - this.font_ = font; +goog.fs.Error.getCodeFromName_ = function(name) { + return goog.fs.Error.NameToCodeMap_[name]; }; /** - * Set the x offset. - * - * @param {number} offsetX Horizontal text offset. - * @api + * Mapping from error names to values from the ErrorCode enum. + * @see http://www.w3.org/TR/file-system-api/#definitions. + * @private {!Object<string, goog.fs.Error.ErrorCode>} */ -ol.style.Text.prototype.setOffsetX = function(offsetX) { - this.offsetX_ = offsetX; -}; +goog.fs.Error.NameToCodeMap_ = goog.object.create( + goog.fs.Error.ErrorName.ABORT, + goog.fs.Error.ErrorCode.ABORT, + goog.fs.Error.ErrorName.ENCODING, + goog.fs.Error.ErrorCode.ENCODING, -/** - * Set the y offset. - * - * @param {number} offsetY Vertical text offset. - * @api - */ -ol.style.Text.prototype.setOffsetY = function(offsetY) { - this.offsetY_ = offsetY; -}; + goog.fs.Error.ErrorName.INVALID_MODIFICATION, + goog.fs.Error.ErrorCode.INVALID_MODIFICATION, + goog.fs.Error.ErrorName.INVALID_STATE, + goog.fs.Error.ErrorCode.INVALID_STATE, -/** - * Set the fill. - * - * @param {ol.style.Fill} fill Fill style. - * @api - */ -ol.style.Text.prototype.setFill = function(fill) { - this.fill_ = fill; -}; + goog.fs.Error.ErrorName.NOT_FOUND, + goog.fs.Error.ErrorCode.NOT_FOUND, + + goog.fs.Error.ErrorName.NOT_READABLE, + goog.fs.Error.ErrorCode.NOT_READABLE, + + goog.fs.Error.ErrorName.NO_MODIFICATION_ALLOWED, + goog.fs.Error.ErrorCode.NO_MODIFICATION_ALLOWED, + + goog.fs.Error.ErrorName.PATH_EXISTS, + goog.fs.Error.ErrorCode.PATH_EXISTS, + + goog.fs.Error.ErrorName.QUOTA_EXCEEDED, + goog.fs.Error.ErrorCode.QUOTA_EXCEEDED, + goog.fs.Error.ErrorName.SECURITY, + goog.fs.Error.ErrorCode.SECURITY, + + goog.fs.Error.ErrorName.SYNTAX, + goog.fs.Error.ErrorCode.SYNTAX, + + goog.fs.Error.ErrorName.TYPE_MISMATCH, + goog.fs.Error.ErrorCode.TYPE_MISMATCH); + +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Set the rotation. + * @fileoverview A wrapper for the HTML5 File ProgressEvent objects. * - * @param {number|undefined} rotation Rotation. - * @api */ -ol.style.Text.prototype.setRotation = function(rotation) { - this.rotation_ = rotation; -}; +goog.provide('goog.fs.ProgressEvent'); + +goog.require('goog.events.Event'); + /** - * Set the scale. + * A wrapper for the progress events emitted by the File APIs. * - * @param {number|undefined} scale Scale. - * @api + * @param {!ProgressEvent} event The underlying event object. + * @param {!Object} target The file access object emitting the event. + * @extends {goog.events.Event} + * @constructor + * @final */ -ol.style.Text.prototype.setScale = function(scale) { - this.scale_ = scale; +goog.fs.ProgressEvent = function(event, target) { + goog.fs.ProgressEvent.base(this, 'constructor', event.type, target); + + /** + * The underlying event object. + * @type {!ProgressEvent} + * @private + */ + this.event_ = event; }; +goog.inherits(goog.fs.ProgressEvent, goog.events.Event); /** - * Set the stroke. - * - * @param {ol.style.Stroke} stroke Stroke style. - * @api + * @return {boolean} Whether or not the total size of the of the file being + * saved is known. */ -ol.style.Text.prototype.setStroke = function(stroke) { - this.stroke_ = stroke; +goog.fs.ProgressEvent.prototype.isLengthComputable = function() { + return this.event_.lengthComputable; }; /** - * Set the text. - * - * @param {string|undefined} text Text. - * @api + * @return {number} The number of bytes saved so far. */ -ol.style.Text.prototype.setText = function(text) { - this.text_ = text; +goog.fs.ProgressEvent.prototype.getLoaded = function() { + return this.event_.loaded; }; /** - * Set the text alignment. - * - * @param {string|undefined} textAlign Text align. - * @api + * @return {number} The total number of bytes in the file being saved. */ -ol.style.Text.prototype.setTextAlign = function(textAlign) { - this.textAlign_ = textAlign; +goog.fs.ProgressEvent.prototype.getTotal = function() { + return this.event_.total; }; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Set the text baseline. + * @fileoverview A wrapper for the HTML5 FileReader object. * - * @param {string|undefined} textBaseline Text baseline. - * @api */ -ol.style.Text.prototype.setTextBaseline = function(textBaseline) { - this.textBaseline_ = textBaseline; -}; -// FIXME http://earth.google.com/kml/1.0 namespace? -// FIXME why does node.getAttribute return an unknown type? -// FIXME text -// FIXME serialize arbitrary feature properties -// FIXME don't parse style if extractStyles is false +goog.provide('goog.fs.FileReader'); +goog.provide('goog.fs.FileReader.EventType'); +goog.provide('goog.fs.FileReader.ReadyState'); -goog.provide('ol.format.KML'); +goog.require('goog.async.Deferred'); +goog.require('goog.events.EventTarget'); +goog.require('goog.fs.Error'); +goog.require('goog.fs.ProgressEvent'); -goog.require('goog.Uri'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Feature'); -goog.require('ol.FeatureStyleFunction'); -goog.require('ol.array'); -goog.require('ol.color'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.LinearRing'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Icon'); -goog.require('ol.style.IconAnchorUnits'); -goog.require('ol.style.IconOrigin'); -goog.require('ol.style.Image'); -goog.require('ol.style.Stroke'); -goog.require('ol.style.Style'); -goog.require('ol.style.Text'); -goog.require('ol.xml'); /** - * @typedef {{x: number, xunits: (ol.style.IconAnchorUnits|undefined), - * y: number, yunits: (ol.style.IconAnchorUnits|undefined)}} + * An object for monitoring the reading of files. This emits ProgressEvents of + * the types listed in {@link goog.fs.FileReader.EventType}. + * + * @constructor + * @extends {goog.events.EventTarget} + * @final */ -ol.format.KMLVec2_; - +goog.fs.FileReader = function() { + goog.fs.FileReader.base(this, 'constructor'); -/** - * @typedef {{flatCoordinates: Array.<number>, - * whens: Array.<number>}} - */ -ol.format.KMLGxTrackObject_; + /** + * The underlying FileReader object. + * + * @type {!FileReader} + * @private + */ + this.reader_ = new FileReader(); + this.reader_.onloadstart = goog.bind(this.dispatchProgressEvent_, this); + this.reader_.onprogress = goog.bind(this.dispatchProgressEvent_, this); + this.reader_.onload = goog.bind(this.dispatchProgressEvent_, this); + this.reader_.onabort = goog.bind(this.dispatchProgressEvent_, this); + this.reader_.onerror = goog.bind(this.dispatchProgressEvent_, this); + this.reader_.onloadend = goog.bind(this.dispatchProgressEvent_, this); +}; +goog.inherits(goog.fs.FileReader, goog.events.EventTarget); /** - * @classdesc - * Feature format for reading and writing data in the KML format. + * Possible states for a FileReader. * - * @constructor - * @extends {ol.format.XMLFeature} - * @param {olx.format.KMLOptions=} opt_options Options. - * @api stable + * @enum {number} */ -ol.format.KML = function(opt_options) { - - var options = opt_options ? opt_options : {}; +goog.fs.FileReader.ReadyState = { + /** + * The object has been constructed, but there is no pending read. + */ + INIT: 0, + /** + * Data is being read. + */ + LOADING: 1, + /** + * The data has been read from the file, the read was aborted, or an error + * occurred. + */ + DONE: 2 +}; - goog.base(this); +/** + * Events emitted by a FileReader. + * + * @enum {string} + */ +goog.fs.FileReader.EventType = { /** - * @inheritDoc + * Emitted when the reading begins. readyState will be LOADING. */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); - + LOAD_START: 'loadstart', /** - * @private - * @type {Array.<ol.style.Style>} + * Emitted when progress has been made in reading the file. readyState will be + * LOADING. */ - this.defaultStyle_ = options.defaultStyle ? - options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_; - + PROGRESS: 'progress', /** - * @private - * @type {boolean} + * Emitted when the data has been successfully read. readyState will be + * LOADING. */ - this.extractStyles_ = options.extractStyles !== undefined ? - options.extractStyles : true; - + LOAD: 'load', /** - * @private - * @type {boolean} + * Emitted when the reading has been aborted. readyState will be LOADING. */ - this.writeStyles_ = options.writeStyles !== undefined ? - options.writeStyles : true; - + ABORT: 'abort', /** - * @private - * @type {Object.<string, (Array.<ol.style.Style>|string)>} + * Emitted when an error is encountered or the reading has been aborted. + * readyState will be LOADING. */ - this.sharedStyles_ = {}; - + ERROR: 'error', /** - * @private - * @type {boolean} + * Emitted when the reading is finished, whether successfully or not. + * readyState will be DONE. */ - this.showPointNames_ = options.showPointNames !== undefined ? - options.showPointNames : true; - + LOAD_END: 'loadend' }; -goog.inherits(ol.format.KML, ol.format.XMLFeature); - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.KML.EXTENSIONS_ = ['.kml']; - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.KML.GX_NAMESPACE_URIS_ = [ - 'http://www.google.com/kml/ext/2.2' -]; - - -/** - * @const - * @type {Array.<string>} - * @private - */ -ol.format.KML.NAMESPACE_URIS_ = [ - null, - 'http://earth.google.com/kml/2.0', - 'http://earth.google.com/kml/2.1', - 'http://earth.google.com/kml/2.2', - 'http://www.opengis.net/kml/2.2' -]; - - -/** - * @const - * @type {string} - * @private - */ -ol.format.KML.SCHEMA_LOCATION_ = 'http://www.opengis.net/kml/2.2 ' + - 'https://developers.google.com/kml/schema/kml22gx.xsd'; /** - * @const - * @type {ol.Color} - * @private + * Abort the reading of the file. */ -ol.format.KML.DEFAULT_COLOR_ = [255, 255, 255, 1]; +goog.fs.FileReader.prototype.abort = function() { + try { + this.reader_.abort(); + } catch (e) { + throw new goog.fs.Error(e, 'aborting read'); + } +}; /** - * @const - * @type {ol.style.Fill} - * @private + * @return {goog.fs.FileReader.ReadyState} The current state of the FileReader. */ -ol.format.KML.DEFAULT_FILL_STYLE_ = new ol.style.Fill({ - color: ol.format.KML.DEFAULT_COLOR_ -}); +goog.fs.FileReader.prototype.getReadyState = function() { + return /** @type {goog.fs.FileReader.ReadyState} */ (this.reader_.readyState); +}; /** - * @const - * @type {ol.Size} - * @private + * @return {*} The result of the file read. */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_ = [20, 2]; // FIXME maybe [8, 32] ? +goog.fs.FileReader.prototype.getResult = function() { + return this.reader_.result; +}; /** - * @const - * @type {ol.style.IconAnchorUnits} - * @private + * @return {goog.fs.Error} The error encountered while reading, if any. */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ = - ol.style.IconAnchorUnits.PIXELS; +goog.fs.FileReader.prototype.getError = function() { + return this.reader_.error && + new goog.fs.Error(this.reader_.error, 'reading file'); +}; /** - * @const - * @type {ol.style.IconAnchorUnits} + * Wrap a progress event emitted by the underlying file reader and re-emit it. + * + * @param {!ProgressEvent} event The underlying event. * @private */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ = - ol.style.IconAnchorUnits.PIXELS; +goog.fs.FileReader.prototype.dispatchProgressEvent_ = function(event) { + this.dispatchEvent(new goog.fs.ProgressEvent(event, this)); +}; -/** - * @const - * @type {ol.Size} - * @private - */ -ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_ = [64, 64]; +/** @override */ +goog.fs.FileReader.prototype.disposeInternal = function() { + goog.fs.FileReader.base(this, 'disposeInternal'); + delete this.reader_; +}; /** - * @const - * @type {string} - * @private + * Starts reading a blob as a binary string. + * @param {!Blob} blob The blob to read. */ -ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ = - 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png'; +goog.fs.FileReader.prototype.readAsBinaryString = function(blob) { + this.reader_.readAsBinaryString(blob); +}; /** - * @const - * @type {number} - * @private + * Reads a blob as a binary string. + * @param {!Blob} blob The blob to read. + * @return {!goog.async.Deferred} The deferred Blob contents as a binary string. + * If an error occurs, the errback is called with a {@link goog.fs.Error}. */ -ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_ = 0.5; +goog.fs.FileReader.readAsBinaryString = function(blob) { + var reader = new goog.fs.FileReader(); + var d = goog.fs.FileReader.createDeferred_(reader); + reader.readAsBinaryString(blob); + return d; +}; /** - * @const - * @type {ol.style.Image} - * @private + * Starts reading a blob as an array buffer. + * @param {!Blob} blob The blob to read. */ -ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({ - anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_, - anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, - anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_, - anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_, - crossOrigin: 'anonymous', - rotation: 0, - scale: ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_, - size: ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_, - src: ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ -}); +goog.fs.FileReader.prototype.readAsArrayBuffer = function(blob) { + this.reader_.readAsArrayBuffer(blob); +}; /** - * @const - * @type {ol.style.Stroke} - * @private + * Reads a blob as an array buffer. + * @param {!Blob} blob The blob to read. + * @return {!goog.async.Deferred} The deferred Blob contents as an array buffer. + * If an error occurs, the errback is called with a {@link goog.fs.Error}. */ -ol.format.KML.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({ - color: ol.format.KML.DEFAULT_COLOR_, - width: 1 -}); +goog.fs.FileReader.readAsArrayBuffer = function(blob) { + var reader = new goog.fs.FileReader(); + var d = goog.fs.FileReader.createDeferred_(reader); + reader.readAsArrayBuffer(blob); + return d; +}; /** - * @const - * @type {ol.style.Stroke} - * @private - */ -ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_ = new ol.style.Stroke({ - color: [51, 51, 51, 1], - width: 2 -}); + * Starts reading a blob as text. + * @param {!Blob} blob The blob to read. + * @param {string=} opt_encoding The name of the encoding to use. + */ +goog.fs.FileReader.prototype.readAsText = function(blob, opt_encoding) { + this.reader_.readAsText(blob, opt_encoding); +}; /** - * @const - * @type {ol.style.Text} - * @private + * Reads a blob as text. + * @param {!Blob} blob The blob to read. + * @param {string=} opt_encoding The name of the encoding to use. + * @return {!goog.async.Deferred} The deferred Blob contents as text. + * If an error occurs, the errback is called with a {@link goog.fs.Error}. */ -ol.format.KML.DEFAULT_TEXT_STYLE_ = new ol.style.Text({ - font: 'bold 16px Helvetica', - fill: ol.format.KML.DEFAULT_FILL_STYLE_, - stroke: ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_, - scale: 0.8 -}); +goog.fs.FileReader.readAsText = function(blob, opt_encoding) { + var reader = new goog.fs.FileReader(); + var d = goog.fs.FileReader.createDeferred_(reader); + reader.readAsText(blob, opt_encoding); + return d; +}; /** - * @const - * @type {ol.style.Style} - * @private + * Starts reading a blob as a data URL. + * @param {!Blob} blob The blob to read. */ -ol.format.KML.DEFAULT_STYLE_ = new ol.style.Style({ - fill: ol.format.KML.DEFAULT_FILL_STYLE_, - image: ol.format.KML.DEFAULT_IMAGE_STYLE_, - text: ol.format.KML.DEFAULT_TEXT_STYLE_, - stroke: ol.format.KML.DEFAULT_STROKE_STYLE_, - zIndex: 0 -}); +goog.fs.FileReader.prototype.readAsDataUrl = function(blob) { + this.reader_.readAsDataURL(blob); +}; /** - * @const - * @type {Array.<ol.style.Style>} - * @private + * Reads a blob as a data URL. + * @param {!Blob} blob The blob to read. + * @return {!goog.async.Deferred} The deferred Blob contents as a data URL. + * If an error occurs, the errback is called with a {@link goog.fs.Error}. */ -ol.format.KML.DEFAULT_STYLE_ARRAY_ = [ol.format.KML.DEFAULT_STYLE_]; +goog.fs.FileReader.readAsDataUrl = function(blob) { + var reader = new goog.fs.FileReader(); + var d = goog.fs.FileReader.createDeferred_(reader); + reader.readAsDataUrl(blob); + return d; +}; /** - * @const - * @type {Object.<string, ol.style.IconAnchorUnits>} + * Creates a new deferred object for the results of a read method. + * @param {goog.fs.FileReader} reader The reader to create a deferred for. + * @return {!goog.async.Deferred} The deferred results. * @private */ -ol.format.KML.ICON_ANCHOR_UNITS_MAP_ = { - 'fraction': ol.style.IconAnchorUnits.FRACTION, - 'pixels': ol.style.IconAnchorUnits.PIXELS +goog.fs.FileReader.createDeferred_ = function(reader) { + var deferred = new goog.async.Deferred(); + reader.listen(goog.fs.FileReader.EventType.LOAD_END, + goog.partial(function(d, r, e) { + var result = r.getResult(); + var error = r.getError(); + if (result != null && !error) { + d.callback(result); + } else { + d.errback(error); + } + r.dispose(); + }, deferred, reader)); + return deferred; }; +// FIXME should handle all geo-referenced data, not just vector data + +goog.provide('ol.interaction.DragAndDrop'); +goog.provide('ol.interaction.DragAndDropEvent'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.FileDropHandler'); +goog.require('goog.events.FileDropHandler.EventType'); +goog.require('goog.fs.FileReader'); +goog.require('goog.functions'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.proj'); + + /** - * @param {ol.style.Style|undefined} foundStyle Style. - * @param {string} name Name. - * @return {ol.style.Style} style Style. - * @private + * @classdesc + * Handles input of vector data by drag and drop. + * + * @constructor + * @extends {ol.interaction.Interaction} + * @fires ol.interaction.DragAndDropEvent + * @param {olx.interaction.DragAndDropOptions=} opt_options Options. + * @api stable */ -ol.format.KML.createNameStyleFunction_ = function(foundStyle, name) { - /** @type {?ol.style.Text} */ - var textStyle = null; - var textOffset = [0, 0]; - var textAlign = 'start'; - if (foundStyle.getImage()) { - var imageSize = foundStyle.getImage().getImageSize(); - if (imageSize && imageSize.length == 2) { - // Offset the label to be centered to the right of the icon, if there is - // one. - textOffset[0] = foundStyle.getImage().getScale() * imageSize[0] / 2; - textOffset[1] = -foundStyle.getImage().getScale() * imageSize[1] / 2; - textAlign = 'left'; - } - } - if (!goog.object.isEmpty(foundStyle.getText())) { - textStyle = /** @type {ol.style.Text} */ - (goog.object.clone(foundStyle.getText())); - textStyle.setText(name); - textStyle.setTextAlign(textAlign); - textStyle.setOffsetX(textOffset[0]); - textStyle.setOffsetY(textOffset[1]); - } else { - textStyle = new ol.style.Text({ - text: name, - offsetX: textOffset[0], - offsetY: textOffset[1], - textAlign: textAlign - }); - } - var nameStyle = new ol.style.Style({ - text: textStyle +ol.interaction.DragAndDrop = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this, { + handleEvent: ol.interaction.DragAndDrop.handleEvent }); - return nameStyle; -}; + /** + * @private + * @type {Array.<function(new: ol.format.Feature)>} + */ + this.formatConstructors_ = options.formatConstructors ? + options.formatConstructors : []; -/** - * @param {Array.<ol.style.Style>|undefined} style Style. - * @param {string} styleUrl Style URL. - * @param {Array.<ol.style.Style>} defaultStyle Default style. - * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles Shared - * styles. - * @param {boolean|undefined} showPointNames true to show names for point - * placemarks. - * @return {ol.FeatureStyleFunction} Feature style function. - * @private - */ -ol.format.KML.createFeatureStyleFunction_ = function(style, styleUrl, - defaultStyle, sharedStyles, showPointNames) { + /** + * @private + * @type {ol.proj.Projection} + */ + this.projection_ = options.projection ? + ol.proj.get(options.projection) : null; - return ( - /** - * @param {number} resolution Resolution. - * @return {Array.<ol.style.Style>} Style. - * @this {ol.Feature} - */ - function(resolution) { - var drawName = showPointNames; - /** @type {ol.style.Style|undefined} */ - var nameStyle; - /** @type {string} */ - var name = ''; - if (drawName) { - if (this.getGeometry()) { - drawName = (this.getGeometry().getType() === - ol.geom.GeometryType.POINT); - } - } + /** + * @private + * @type {goog.events.FileDropHandler} + */ + this.fileDropHandler_ = null; - if (drawName) { - name = /** @type {string} */ (this.getProperties()['name']); - drawName = drawName && name; - } + /** + * @private + * @type {goog.events.Key|undefined} + */ + this.dropListenKey_ = undefined; - if (style) { - if (drawName) { - nameStyle = ol.format.KML.createNameStyleFunction_(style[0], - name); - return style.concat(nameStyle); - } - return style; - } - if (styleUrl) { - var foundStyle = ol.format.KML.findStyle_(styleUrl, defaultStyle, - sharedStyles); - if (drawName) { - nameStyle = ol.format.KML.createNameStyleFunction_(foundStyle[0], - name); - return foundStyle.concat(nameStyle); - } - return foundStyle; - } - if (drawName) { - nameStyle = ol.format.KML.createNameStyleFunction_(defaultStyle[0], - name); - return defaultStyle.concat(nameStyle); - } - return defaultStyle; - }); }; +goog.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction); /** - * @param {Array.<ol.style.Style>|string|undefined} styleValue Style value. - * @param {Array.<ol.style.Style>} defaultStyle Default style. - * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles - * Shared styles. - * @return {Array.<ol.style.Style>} Style. - * @private + * @inheritDoc */ -ol.format.KML.findStyle_ = function(styleValue, defaultStyle, sharedStyles) { - if (goog.isArray(styleValue)) { - return styleValue; - } else if (goog.isString(styleValue)) { - // KML files in the wild occasionally forget the leading `#` on styleUrls - // defined in the same document. Add a leading `#` if it enables to find - // a style. - if (!(styleValue in sharedStyles) && ('#' + styleValue in sharedStyles)) { - styleValue = '#' + styleValue; - } - return ol.format.KML.findStyle_( - sharedStyles[styleValue], defaultStyle, sharedStyles); - } else { - return defaultStyle; +ol.interaction.DragAndDrop.prototype.disposeInternal = function() { + if (this.dropListenKey_) { + goog.events.unlistenByKey(this.dropListenKey_); } + goog.base(this, 'disposeInternal'); }; /** - * @param {Node} node Node. + * @param {goog.events.BrowserEvent} event Event. * @private - * @return {ol.Color|undefined} Color. */ -ol.format.KML.readColor_ = function(node) { - var s = ol.xml.getAllTextContent(node, false); - // The KML specification states that colors should not include a leading `#` - // but we tolerate them. - var m = /^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(s); - if (m) { - var hexColor = m[1]; - return [ - parseInt(hexColor.substr(6, 2), 16), - parseInt(hexColor.substr(4, 2), 16), - parseInt(hexColor.substr(2, 2), 16), - parseInt(hexColor.substr(0, 2), 16) / 255 - ]; - - } else { - return undefined; +ol.interaction.DragAndDrop.prototype.handleDrop_ = function(event) { + var files = event.getBrowserEvent().dataTransfer.files; + var i, ii, file; + for (i = 0, ii = files.length; i < ii; ++i) { + file = files[i]; + // The empty string param is a workaround for + // https://code.google.com/p/closure-library/issues/detail?id=524 + var reader = goog.fs.FileReader.readAsText(file, ''); + reader.addCallback(goog.partial(this.handleResult_, file), this); } }; /** - * @param {Node} node Node. + * @param {File} file File. + * @param {string} result Result. * @private - * @return {Array.<number>|undefined} Flat coordinates. */ -ol.format.KML.readFlatCoordinates_ = function(node) { - var s = ol.xml.getAllTextContent(node, false); - var flatCoordinates = []; - // The KML specification states that coordinate tuples should not include - // spaces, but we tolerate them. - var re = - /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i; - var m; - while ((m = re.exec(s))) { - var x = parseFloat(m[1]); - var y = parseFloat(m[2]); - var z = m[3] ? parseFloat(m[3]) : 0; - flatCoordinates.push(x, y, z); - s = s.substr(m[0].length); +ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, result) { + var map = this.getMap(); + goog.asserts.assert(map, 'map must be set'); + var projection = this.projection_; + if (!projection) { + var view = map.getView(); + goog.asserts.assert(view, 'map must have view'); + projection = view.getProjection(); + goog.asserts.assert(projection !== undefined, + 'projection should be defined'); } - if (s !== '') { - return undefined; + var formatConstructors = this.formatConstructors_; + var features = []; + var i, ii; + for (i = 0, ii = formatConstructors.length; i < ii; ++i) { + var formatConstructor = formatConstructors[i]; + var format = new formatConstructor(); + var readFeatures = this.tryReadFeatures_(format, result); + if (readFeatures) { + var featureProjection = format.readProjection(result); + var transform = ol.proj.getTransform(featureProjection, projection); + var j, jj; + for (j = 0, jj = readFeatures.length; j < jj; ++j) { + var feature = readFeatures[j]; + var geometry = feature.getGeometry(); + if (geometry) { + geometry.applyTransform(transform); + } + features.push(feature); + } + } } - return flatCoordinates; + this.dispatchEvent( + new ol.interaction.DragAndDropEvent( + ol.interaction.DragAndDropEventType.ADD_FEATURES, this, file, + features, projection)); }; /** - * @param {Node} node Node. - * @private - * @return {string|undefined} Style URL. + * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and + * neither prevents the browser default nor stops event propagation. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.DragAndDrop} + * @api */ -ol.format.KML.readStyleUrl_ = function(node) { - var s = ol.xml.getAllTextContent(node, false).trim(); - if (node.baseURI) { - return goog.Uri.resolve(node.baseURI, s).toString(); - } else { - return s; - } - -}; +ol.interaction.DragAndDrop.handleEvent = goog.functions.TRUE; /** - * @param {Node} node Node. - * @private - * @return {string} URI. + * @inheritDoc */ -ol.format.KML.readURI_ = function(node) { - var s = ol.xml.getAllTextContent(node, false); - if (node.baseURI) { - return goog.Uri.resolve(node.baseURI, s.trim()).toString(); - } else { - return s.trim(); +ol.interaction.DragAndDrop.prototype.setMap = function(map) { + if (this.dropListenKey_) { + goog.events.unlistenByKey(this.dropListenKey_); + this.dropListenKey_ = undefined; + } + if (this.fileDropHandler_) { + goog.dispose(this.fileDropHandler_); + this.fileDropHandler_ = null; + } + goog.asserts.assert(this.dropListenKey_ === undefined, + 'this.dropListenKey_ should be undefined'); + goog.base(this, 'setMap', map); + if (map) { + this.fileDropHandler_ = new goog.events.FileDropHandler(map.getViewport()); + this.dropListenKey_ = goog.events.listen( + this.fileDropHandler_, goog.events.FileDropHandler.EventType.DROP, + this.handleDrop_, false, this); } }; /** - * @param {Node} node Node. + * @param {ol.format.Feature} format Format. + * @param {string} text Text. * @private - * @return {ol.format.KMLVec2_} Vec2. + * @return {Array.<ol.Feature>} Features. */ -ol.format.KML.readVec2_ = function(node) { - var xunits = node.getAttribute('xunits'); - var yunits = node.getAttribute('yunits'); - return { - x: parseFloat(node.getAttribute('x')), - xunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[xunits], - y: parseFloat(node.getAttribute('y')), - yunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[yunits] - }; +ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text) { + try { + return format.readFeatures(text); + } catch (e) { + return null; + } }; /** - * @param {Node} node Node. - * @private - * @return {number|undefined} Scale. + * @enum {string} */ -ol.format.KML.readScale_ = function(node) { - var number = ol.format.XSD.readDecimal(node); - if (number !== undefined) { - return Math.sqrt(number); - } else { - return undefined; - } +ol.interaction.DragAndDropEventType = { + /** + * Triggered when features are added + * @event ol.interaction.DragAndDropEvent#addfeatures + * @api stable + */ + ADD_FEATURES: 'addfeatures' }; + /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<ol.style.Style>|string|undefined} StyleMap. + * @classdesc + * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances + * of this type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.interaction.DragAndDropEvent} + * @param {ol.interaction.DragAndDropEventType} type Type. + * @param {Object} target Target. + * @param {File} file File. + * @param {Array.<ol.Feature>=} opt_features Features. + * @param {ol.proj.Projection=} opt_projection Projection. */ -ol.format.KML.readStyleMapValue_ = function(node, objectStack) { - return ol.xml.pushParseAndPop( - /** @type {Array.<ol.style.Style>|string|undefined} */ (undefined), - ol.format.KML.STYLE_MAP_PARSERS_, node, objectStack); -}; +ol.interaction.DragAndDropEvent = + function(type, target, file, opt_features, opt_projection) { + goog.base(this, type, target); -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - */ -ol.format.KML.IconStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be an ELEMENT'); - goog.asserts.assert(node.localName == 'IconStyle', - 'localName should be IconStyle'); - // FIXME refreshMode - // FIXME refreshInterval - // FIXME viewRefreshTime - // FIXME viewBoundScale - // FIXME viewFormat - // FIXME httpQuery - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.ICON_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = /** @type {Object} */ (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var IconObject = 'Icon' in object ? object['Icon'] : {}; - var src; - var href = /** @type {string|undefined} */ - (IconObject['href']); - if (href) { - src = href; - } else { - src = ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_; - } - var anchor, anchorXUnits, anchorYUnits; - var hotSpot = /** @type {ol.format.KMLVec2_|undefined} */ - (object['hotSpot']); - if (hotSpot) { - anchor = [hotSpot.x, hotSpot.y]; - anchorXUnits = hotSpot.xunits; - anchorYUnits = hotSpot.yunits; - } else if (src === ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) { - anchor = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_; - anchorXUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_; - anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_; - } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) { - anchor = [0.5, 0]; - anchorXUnits = ol.style.IconAnchorUnits.FRACTION; - anchorYUnits = ol.style.IconAnchorUnits.FRACTION; - } + /** + * The features parsed from dropped data. + * @type {Array.<ol.Feature>|undefined} + * @api stable + */ + this.features = opt_features; + + /** + * The dropped file. + * @type {File} + * @api stable + */ + this.file = file; + + /** + * The feature projection. + * @type {ol.proj.Projection|undefined} + * @api + */ + this.projection = opt_projection; - var offset; - var x = /** @type {number|undefined} */ - (IconObject['x']); - var y = /** @type {number|undefined} */ - (IconObject['y']); - if (x !== undefined && y !== undefined) { - offset = [x, y]; - } +}; +goog.inherits(ol.interaction.DragAndDropEvent, goog.events.Event); - var size; - var w = /** @type {number|undefined} */ - (IconObject['w']); - var h = /** @type {number|undefined} */ - (IconObject['h']); - if (w !== undefined && h !== undefined) { - size = [w, h]; - } +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - var rotation; - var heading = /** @type {number} */ - (object['heading']); - if (heading !== undefined) { - rotation = ol.math.toRadians(heading); - } +/** + * @fileoverview Defines a 2-element vector class that can be used for + * coordinate math, useful for animation systems and point manipulation. + * + * Vec2 objects inherit from goog.math.Coordinate and may be used wherever a + * Coordinate is required. Where appropriate, Vec2 functions accept both Vec2 + * and Coordinate objects as input. + * + * @author brenneman@google.com (Shawn Brenneman) + */ - var scale = /** @type {number|undefined} */ - (object['scale']); - if (src == ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) { - size = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_; - if (scale === undefined) { - scale = ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_; - } - } +goog.provide('goog.math.Vec2'); + +goog.require('goog.math'); +goog.require('goog.math.Coordinate'); - var imageStyle = new ol.style.Icon({ - anchor: anchor, - anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT, - anchorXUnits: anchorXUnits, - anchorYUnits: anchorYUnits, - crossOrigin: 'anonymous', // FIXME should this be configurable? - offset: offset, - offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT, - rotation: rotation, - scale: scale, - size: size, - src: src - }); - styleObject['imageStyle'] = imageStyle; -}; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Class for a two-dimensional vector object and assorted functions useful for + * manipulating points. + * + * @param {number} x The x coordinate for the vector. + * @param {number} y The y coordinate for the vector. + * @struct + * @constructor + * @extends {goog.math.Coordinate} */ -ol.format.KML.LabelStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LabelStyle', - 'localName should be LabelStyle'); - // FIXME colorMode - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.LABEL_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var textStyle = new ol.style.Text({ - fill: new ol.style.Fill({ - color: /** @type {ol.Color} */ - ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_) - }), - scale: /** @type {number|undefined} */ - (object['scale']) - }); - styleObject['textStyle'] = textStyle; +goog.math.Vec2 = function(x, y) { + /** + * X-value + * @type {number} + */ + this.x = x; + + /** + * Y-value + * @type {number} + */ + this.y = y; }; +goog.inherits(goog.math.Vec2, goog.math.Coordinate); /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @return {!goog.math.Vec2} A random unit-length vector. */ -ol.format.KML.LineStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineStyle', - 'localName should be LineStyle'); - // FIXME colorMode - // FIXME gx:outerColor - // FIXME gx:outerWidth - // FIXME gx:physicalWidth - // FIXME gx:labelVisibility - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.LINE_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var strokeStyle = new ol.style.Stroke({ - color: /** @type {ol.Color} */ - ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_), - width: /** @type {number} */ ('width' in object ? object['width'] : 1) - }); - styleObject['strokeStyle'] = strokeStyle; +goog.math.Vec2.randomUnit = function() { + var angle = Math.random() * Math.PI * 2; + return new goog.math.Vec2(Math.cos(angle), Math.sin(angle)); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @return {!goog.math.Vec2} A random vector inside the unit-disc. */ -ol.format.KML.PolyStyleParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'PolyStyle', - 'localName should be PolyStyle'); - // FIXME colorMode - var object = ol.xml.pushParseAndPop( - {}, ol.format.KML.POLY_STYLE_PARSERS_, node, objectStack); - if (!object) { - return; - } - var styleObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(styleObject), - 'styleObject should be an Object'); - var fillStyle = new ol.style.Fill({ - color: /** @type {ol.Color} */ - ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_) - }); - styleObject['fillStyle'] = fillStyle; - var fill = /** @type {boolean|undefined} */ (object['fill']); - if (fill !== undefined) { - styleObject['fill'] = fill; - } - var outline = - /** @type {boolean|undefined} */ (object['outline']); - if (outline !== undefined) { - styleObject['outline'] = outline; - } +goog.math.Vec2.random = function() { + var mag = Math.sqrt(Math.random()); + var angle = Math.random() * Math.PI * 2; + + return new goog.math.Vec2(Math.cos(angle) * mag, Math.sin(angle) * mag); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>} LinearRing flat coordinates. + * Returns a new Vec2 object from a given coordinate. + * @param {!goog.math.Coordinate} a The coordinate. + * @return {!goog.math.Vec2} A new vector object. */ -ol.format.KML.readFlatLinearRing_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop( - null, ol.format.KML.FLAT_LINEAR_RING_PARSERS_, node, objectStack)); +goog.math.Vec2.fromCoordinate = function(a) { + return new goog.math.Vec2(a.x, a.y); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @return {!goog.math.Vec2} A new vector with the same coordinates as this one. + * @override */ -ol.format.KML.gxCoordParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(ol.array.includes( - ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), - 'namespaceURI of the node should be known to the KML parser'); - goog.asserts.assert(node.localName == 'coord', 'localName should be coord'); - var gxTrackObject = /** @type {ol.format.KMLGxTrackObject_} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(gxTrackObject), - 'gxTrackObject should be an Object'); - var flatCoordinates = gxTrackObject.flatCoordinates; - var s = ol.xml.getAllTextContent(node, false); - var re = - /^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i; - var m = re.exec(s); - if (m) { - var x = parseFloat(m[1]); - var y = parseFloat(m[2]); - var z = parseFloat(m[3]); - flatCoordinates.push(x, y, z, 0); - } else { - flatCoordinates.push(0, 0, 0, 0); - } +goog.math.Vec2.prototype.clone = function() { + return new goog.math.Vec2(this.x, this.y); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.MultiLineString|undefined} MultiLineString. + * Returns the magnitude of the vector measured from the origin. + * @return {number} The length of the vector. */ -ol.format.KML.readGxMultiTrack_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(ol.array.includes( - ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), - 'namespaceURI of the node should be known to the KML parser'); - goog.asserts.assert(node.localName == 'MultiTrack', - 'localName should be MultiTrack'); - var lineStrings = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.LineString>} */ ([]), - ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_, node, objectStack); - if (!lineStrings) { - return undefined; - } - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(lineStrings); - return multiLineString; +goog.math.Vec2.prototype.magnitude = function() { + return Math.sqrt(this.x * this.x + this.y * this.y); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.LineString|undefined} LineString. + * Returns the squared magnitude of the vector measured from the origin. + * NOTE(brenneman): Leaving out the square root is not a significant + * optimization in JavaScript. + * @return {number} The length of the vector, squared. */ -ol.format.KML.readGxTrack_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(ol.array.includes( - ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI), - 'namespaceURI of the node should be known to the KML parser'); - goog.asserts.assert(node.localName == 'Track', 'localName should be Track'); - var gxTrackObject = ol.xml.pushParseAndPop( - /** @type {ol.format.KMLGxTrackObject_} */ ({ - flatCoordinates: [], - whens: [] - }), ol.format.KML.GX_TRACK_PARSERS_, node, objectStack); - if (!gxTrackObject) { - return undefined; - } - var flatCoordinates = gxTrackObject.flatCoordinates; - var whens = gxTrackObject.whens; - goog.asserts.assert(flatCoordinates.length / 4 == whens.length, - 'the length of the flatCoordinates array divided by 4 should be the ' + - 'length of the whens array'); - var i, ii; - for (i = 0, ii = Math.min(flatCoordinates.length, whens.length); i < ii; - ++i) { - flatCoordinates[4 * i + 3] = whens[i]; - } - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); - return lineString; +goog.math.Vec2.prototype.squaredMagnitude = function() { + return this.x * this.x + this.y * this.y; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object} Icon object. + * @return {!goog.math.Vec2} This coordinate after scaling. + * @override */ -ol.format.KML.readIcon_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Icon', 'localName should be Icon'); - var iconObject = ol.xml.pushParseAndPop( - {}, ol.format.KML.ICON_PARSERS_, node, objectStack); - if (iconObject) { - return iconObject; - } else { - return null; - } -}; +goog.math.Vec2.prototype.scale = + /** @type {function(number, number=):!goog.math.Vec2} */ + (goog.math.Coordinate.prototype.scale); /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<number>} Flat coordinates. + * Reverses the sign of the vector. Equivalent to scaling the vector by -1. + * @return {!goog.math.Vec2} The inverted vector. */ -ol.format.KML.readFlatCoordinatesFromNode_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop(null, - ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack)); +goog.math.Vec2.prototype.invert = function() { + this.x = -this.x; + this.y = -this.y; + return this; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.LineString|undefined} LineString. + * Normalizes the current vector to have a magnitude of 1. + * @return {!goog.math.Vec2} The normalized vector. */ -ol.format.KML.readLineString_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LineString', - 'localName should be LineString'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatCoordinates = - ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var lineString = new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - lineString.setProperties(properties); - return lineString; - } else { - return undefined; - } +goog.math.Vec2.prototype.normalize = function() { + return this.scale(1 / this.magnitude()); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Polygon|undefined} Polygon. + * Adds another vector to this vector in-place. + * @param {!goog.math.Coordinate} b The vector to add. + * @return {!goog.math.Vec2} This vector with {@code b} added. */ -ol.format.KML.readLinearRing_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'LinearRing', - 'localName should be LinearRing'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatCoordinates = - ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var polygon = new ol.geom.Polygon(null); - polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates, - [flatCoordinates.length]); - polygon.setProperties(properties); - return polygon; - } else { - return undefined; - } +goog.math.Vec2.prototype.add = function(b) { + this.x += b.x; + this.y += b.y; + return this; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Geometry} Geometry. + * Subtracts another vector from this vector in-place. + * @param {!goog.math.Coordinate} b The vector to subtract. + * @return {!goog.math.Vec2} This vector with {@code b} subtracted. */ -ol.format.KML.readMultiGeometry_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MultiGeometry', - 'localName should be MultiGeometry'); - var geometries = ol.xml.pushParseAndPop( - /** @type {Array.<ol.geom.Geometry>} */ ([]), - ol.format.KML.MULTI_GEOMETRY_PARSERS_, node, objectStack); - if (!geometries) { - return null; - } - if (geometries.length === 0) { - return new ol.geom.GeometryCollection(geometries); - } - var homogeneous = true; - var type = geometries[0].getType(); - var geometry, i, ii; - for (i = 1, ii = geometries.length; i < ii; ++i) { - geometry = geometries[i]; - if (geometry.getType() != type) { - homogeneous = false; - break; - } - } - if (homogeneous) { - /** @type {ol.geom.GeometryLayout} */ - var layout; - /** @type {Array.<number>} */ - var flatCoordinates; - if (type == ol.geom.GeometryType.POINT) { - var point = geometries[0]; - goog.asserts.assertInstanceof(point, ol.geom.Point, - 'point should be an ol.geom.Point'); - layout = point.getLayout(); - flatCoordinates = point.getFlatCoordinates(); - for (i = 1, ii = geometries.length; i < ii; ++i) { - geometry = geometries[i]; - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - goog.asserts.assert(geometry.getLayout() == layout, - 'geometry layout should be consistent'); - goog.array.extend(flatCoordinates, geometry.getFlatCoordinates()); - } - var multiPoint = new ol.geom.MultiPoint(null); - multiPoint.setFlatCoordinates(layout, flatCoordinates); - ol.format.KML.setCommonGeometryProperties_(multiPoint, geometries); - return multiPoint; - } else if (type == ol.geom.GeometryType.LINE_STRING) { - var multiLineString = new ol.geom.MultiLineString(null); - multiLineString.setLineStrings(geometries); - ol.format.KML.setCommonGeometryProperties_(multiLineString, geometries); - return multiLineString; - } else if (type == ol.geom.GeometryType.POLYGON) { - var multiPolygon = new ol.geom.MultiPolygon(null); - multiPolygon.setPolygons(geometries); - ol.format.KML.setCommonGeometryProperties_(multiPolygon, geometries); - return multiPolygon; - } else if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) { - return new ol.geom.GeometryCollection(geometries); - } else { - goog.asserts.fail('Unexpected type: ' + type); - return null; - } - } else { - return new ol.geom.GeometryCollection(geometries); - } +goog.math.Vec2.prototype.subtract = function(b) { + this.x -= b.x; + this.y -= b.y; + return this; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Point|undefined} Point. + * Rotates this vector in-place by a given angle, specified in radians. + * @param {number} angle The angle, in radians. + * @return {!goog.math.Vec2} This vector rotated {@code angle} radians. */ -ol.format.KML.readPoint_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Point', 'localName should be Point'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatCoordinates = - ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack); - if (flatCoordinates) { - var point = new ol.geom.Point(null); - goog.asserts.assert(flatCoordinates.length == 3, - 'flatCoordinates should have a length of 3'); - point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates); - point.setProperties(properties); - return point; - } else { - return undefined; - } +goog.math.Vec2.prototype.rotate = function(angle) { + var cos = Math.cos(angle); + var sin = Math.sin(angle); + var newX = this.x * cos - this.y * sin; + var newY = this.y * cos + this.x * sin; + this.x = newX; + this.y = newY; + return this; +}; + + +/** + * Rotates a vector by a given angle, specified in radians, relative to a given + * axis rotation point. The returned vector is a newly created instance - no + * in-place changes are done. + * @param {!goog.math.Vec2} v A vector. + * @param {!goog.math.Vec2} axisPoint The rotation axis point. + * @param {number} angle The angle, in radians. + * @return {!goog.math.Vec2} The rotated vector in a newly created instance. + */ +goog.math.Vec2.rotateAroundPoint = function(v, axisPoint, angle) { + var res = v.clone(); + return res.subtract(axisPoint).rotate(angle).add(axisPoint); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.geom.Polygon|undefined} Polygon. + * Compares this vector with another for equality. + * @param {!goog.math.Vec2} b The other vector. + * @return {boolean} Whether this vector has the same x and y as the given + * vector. */ -ol.format.KML.readPolygon_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Polygon', - 'localName should be Polygon'); - var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}), - ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node, - objectStack); - var flatLinearRings = ol.xml.pushParseAndPop( - /** @type {Array.<Array.<number>>} */ ([null]), - ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack); - if (flatLinearRings && flatLinearRings[0]) { - var polygon = new ol.geom.Polygon(null); - var flatCoordinates = flatLinearRings[0]; - var ends = [flatCoordinates.length]; - var i, ii; - for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); - ends.push(flatCoordinates.length); - } - polygon.setFlatCoordinates( - ol.geom.GeometryLayout.XYZ, flatCoordinates, ends); - polygon.setProperties(properties); - return polygon; - } else { - return undefined; - } +goog.math.Vec2.prototype.equals = function(b) { + return this == b || !!b && this.x == b.x && this.y == b.y; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Array.<ol.style.Style>} Style. + * Returns the distance between two vectors. + * @param {!goog.math.Coordinate} a The first vector. + * @param {!goog.math.Coordinate} b The second vector. + * @return {number} The distance. */ -ol.format.KML.readStyle_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); - var styleObject = ol.xml.pushParseAndPop( - {}, ol.format.KML.STYLE_PARSERS_, node, objectStack); - if (!styleObject) { - return null; - } - var fillStyle = /** @type {ol.style.Fill} */ - ('fillStyle' in styleObject ? - styleObject['fillStyle'] : ol.format.KML.DEFAULT_FILL_STYLE_); - var fill = /** @type {boolean|undefined} */ (styleObject['fill']); - if (fill !== undefined && !fill) { - fillStyle = null; - } - var imageStyle = /** @type {ol.style.Image} */ - ('imageStyle' in styleObject ? - styleObject['imageStyle'] : ol.format.KML.DEFAULT_IMAGE_STYLE_); - var textStyle = /** @type {ol.style.Text} */ - ('textStyle' in styleObject ? - styleObject['textStyle'] : ol.format.KML.DEFAULT_TEXT_STYLE_); - var strokeStyle = /** @type {ol.style.Stroke} */ - ('strokeStyle' in styleObject ? - styleObject['strokeStyle'] : ol.format.KML.DEFAULT_STROKE_STYLE_); - var outline = /** @type {boolean|undefined} */ - (styleObject['outline']); - if (outline !== undefined && !outline) { - strokeStyle = null; - } - return [new ol.style.Style({ - fill: fillStyle, - image: imageStyle, - stroke: strokeStyle, - text: textStyle, - zIndex: undefined // FIXME - })]; -}; +goog.math.Vec2.distance = goog.math.Coordinate.distance; /** - * Reads an array of geometries and creates arrays for common geometry - * properties. Then sets them to the multi geometry. - * @param {ol.geom.MultiPoint|ol.geom.MultiLineString|ol.geom.MultiPolygon} - * multiGeometry - * @param {Array.<ol.geom.Geometry>} geometries - * @private + * Returns the squared distance between two vectors. + * @param {!goog.math.Coordinate} a The first vector. + * @param {!goog.math.Coordinate} b The second vector. + * @return {number} The squared distance. */ -ol.format.KML.setCommonGeometryProperties_ = function(multiGeometry, - geometries) { - var ii = geometries.length; - var extrudes = new Array(geometries.length); - var altitudeModes = new Array(geometries.length); - var geometry, i, hasExtrude, hasAltitudeMode; - hasExtrude = hasAltitudeMode = false; - for (i = 0; i < ii; ++i) { - geometry = geometries[i]; - extrudes[i] = geometry.get('extrude'); - altitudeModes[i] = geometry.get('altitudeMode'); - hasExtrude = hasExtrude || extrudes[i] !== undefined; - hasAltitudeMode = hasAltitudeMode || altitudeModes[i]; - } - if (hasExtrude) { - multiGeometry.set('extrude', extrudes); - } - if (hasAltitudeMode) { - multiGeometry.set('altitudeMode', altitudeModes); - } -}; +goog.math.Vec2.squaredDistance = goog.math.Coordinate.squaredDistance; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Compares vectors for equality. + * @param {!goog.math.Coordinate} a The first vector. + * @param {!goog.math.Coordinate} b The second vector. + * @return {boolean} Whether the vectors have the same x and y coordinates. */ -ol.format.KML.DataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Data', 'localName should be Data'); - var name = node.getAttribute('name'); - if (name !== null) { - var data = ol.xml.pushParseAndPop( - undefined, ol.format.KML.DATA_PARSERS_, node, objectStack); - if (data) { - var featureObject = - /** @type {Object} */ (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(featureObject), - 'featureObject should be an Object'); - featureObject[name] = data; - } - } -}; +goog.math.Vec2.equals = goog.math.Coordinate.equals; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Returns the sum of two vectors as a new Vec2. + * @param {!goog.math.Coordinate} a The first vector. + * @param {!goog.math.Coordinate} b The second vector. + * @return {!goog.math.Vec2} The sum vector. */ -ol.format.KML.ExtendedDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ExtendedData', - 'localName should be ExtendedData'); - ol.xml.parseNode(ol.format.KML.EXTENDED_DATA_PARSERS_, node, objectStack); +goog.math.Vec2.sum = function(a, b) { + return new goog.math.Vec2(a.x + b.x, a.y + b.y); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Returns the difference between two vectors as a new Vec2. + * @param {!goog.math.Coordinate} a The first vector. + * @param {!goog.math.Coordinate} b The second vector. + * @return {!goog.math.Vec2} The difference vector. */ -ol.format.KML.PairDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Pair', 'localName should be Pair'); - var pairObject = ol.xml.pushParseAndPop( - {}, ol.format.KML.PAIR_PARSERS_, node, objectStack); - if (!pairObject) { - return; - } - var key = /** @type {string|undefined} */ - (pairObject['key']); - if (key && key == 'normal') { - var styleUrl = /** @type {string|undefined} */ - (pairObject['styleUrl']); - if (styleUrl) { - objectStack[objectStack.length - 1] = styleUrl; - } - var Style = /** @type {ol.style.Style} */ - (pairObject['Style']); - if (Style) { - objectStack[objectStack.length - 1] = Style; - } - } +goog.math.Vec2.difference = function(a, b) { + return new goog.math.Vec2(a.x - b.x, a.y - b.y); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Returns the dot-product of two vectors. + * @param {!goog.math.Coordinate} a The first vector. + * @param {!goog.math.Coordinate} b The second vector. + * @return {number} The dot-product of the two vectors. */ -ol.format.KML.PlacemarkStyleMapParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'StyleMap', - 'localName should be StyleMap'); - var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack); - if (!styleMapValue) { - return; - } - var placemarkObject = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(placemarkObject), - 'placemarkObject should be an Object'); - if (goog.isArray(styleMapValue)) { - placemarkObject['Style'] = styleMapValue; - } else if (goog.isString(styleMapValue)) { - placemarkObject['styleUrl'] = styleMapValue; - } else { - goog.asserts.fail('styleMapValue has an unknown type'); - } +goog.math.Vec2.dot = function(a, b) { + return a.x * b.x + a.y * b.y; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Returns the determinant of two vectors. + * @param {!goog.math.Vec2} a The first vector. + * @param {!goog.math.Vec2} b The second vector. + * @return {number} The determinant of the two vectors. */ -ol.format.KML.SchemaDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'SchemaData', - 'localName should be SchemaData'); - ol.xml.parseNode(ol.format.KML.SCHEMA_DATA_PARSERS_, node, objectStack); +goog.math.Vec2.determinant = function(a, b) { + return a.x * b.y - a.y * b.x; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Returns a new Vec2 that is the linear interpolant between vectors a and b at + * scale-value x. + * @param {!goog.math.Coordinate} a Vector a. + * @param {!goog.math.Coordinate} b Vector b. + * @param {number} x The proportion between a and b. + * @return {!goog.math.Vec2} The interpolated vector. */ -ol.format.KML.SimpleDataParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'SimpleData', - 'localName should be SimpleData'); - var name = node.getAttribute('name'); - if (name !== null) { - var data = ol.format.XSD.readString(node); - var featureObject = - /** @type {Object} */ (objectStack[objectStack.length - 1]); - featureObject[name] = data; - } +goog.math.Vec2.lerp = function(a, b, x) { + return new goog.math.Vec2(goog.math.lerp(a.x, b.x, x), + goog.math.lerp(a.y, b.y, x)); }; +goog.provide('ol.interaction.DragRotateAndZoom'); + +goog.require('goog.math.Vec2'); +goog.require('ol'); +goog.require('ol.ViewHint'); +goog.require('ol.events.ConditionType'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.interaction.Pointer'); + + /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @classdesc + * Allows the user to zoom and rotate the map by clicking and dragging + * on the map. By default, this interaction is limited to when the shift + * key is held down. + * + * This interaction is only supported for mouse devices. + * + * And this interaction is not included in the default interactions. + * + * @constructor + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.DragRotateAndZoomOptions=} opt_options Options. + * @api stable */ -ol.format.KML.innerBoundaryIsParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'innerBoundaryIs', - 'localName should be innerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - ol.format.KML.INNER_BOUNDARY_IS_PARSERS_, node, objectStack); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings array should not be empty'); - flatLinearRings.push(flatLinearRing); - } +ol.interaction.DragRotateAndZoom = function(opt_options) { + + var options = opt_options ? opt_options : {}; + + goog.base(this, { + handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_, + handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_, + handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_ + }); + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = options.condition ? + options.condition : ol.events.condition.shiftKeyOnly; + + /** + * @private + * @type {number|undefined} + */ + this.lastAngle_ = undefined; + + /** + * @private + * @type {number|undefined} + */ + this.lastMagnitude_ = undefined; + + /** + * @private + * @type {number} + */ + this.lastScaleDelta_ = 0; + + /** + * @private + * @type {number} + */ + this.duration_ = options.duration !== undefined ? options.duration : 400; + }; +goog.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Pointer); /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragRotateAndZoom} * @private */ -ol.format.KML.outerBoundaryIsParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'outerBoundaryIs', - 'localName should be outerBoundaryIs'); - var flatLinearRing = ol.xml.pushParseAndPop( - /** @type {Array.<number>|undefined} */ (undefined), - ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_, node, objectStack); - if (flatLinearRing) { - var flatLinearRings = /** @type {Array.<Array.<number>>} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isArray(flatLinearRings), - 'flatLinearRings should be an array'); - goog.asserts.assert(flatLinearRings.length > 0, - 'flatLinearRings array should not be empty'); - flatLinearRings[0] = flatLinearRing; +ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return; + } + + var map = mapBrowserEvent.map; + var size = map.getSize(); + var offset = mapBrowserEvent.pixel; + var delta = new goog.math.Vec2( + offset[0] - size[0] / 2, + size[1] / 2 - offset[1]); + var theta = Math.atan2(delta.y, delta.x); + var magnitude = delta.magnitude(); + var view = map.getView(); + map.render(); + if (this.lastAngle_ !== undefined) { + var angleDelta = theta - this.lastAngle_; + ol.interaction.Interaction.rotateWithoutConstraints( + map, view, view.getRotation() - angleDelta); + } + this.lastAngle_ = theta; + if (this.lastMagnitude_ !== undefined) { + var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude); + ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution); + } + if (this.lastMagnitude_ !== undefined) { + this.lastScaleDelta_ = this.lastMagnitude_ / magnitude; } + this.lastMagnitude_ = magnitude; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragRotateAndZoom} * @private */ -ol.format.KML.LinkParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Link', 'localName should be Link'); - ol.xml.parseNode(ol.format.KML.LINK_PARSERS_, node, objectStack); +ol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return true; + } + + var map = mapBrowserEvent.map; + var view = map.getView(); + view.setHint(ol.ViewHint.INTERACTING, -1); + var direction = this.lastScaleDelta_ - 1; + ol.interaction.Interaction.rotate(map, view, view.getRotation()); + ol.interaction.Interaction.zoom(map, view, view.getResolution(), + undefined, this.duration_, direction); + this.lastScaleDelta_ = 0; + return false; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragRotateAndZoom} * @private */ -ol.format.KML.whenParser_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'when', 'localName should be when'); - var gxTrackObject = /** @type {ol.format.KMLGxTrackObject_} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(gxTrackObject), - 'gxTrackObject should be an Object'); - var whens = gxTrackObject.whens; - var s = ol.xml.getAllTextContent(node, false); - var re = - /^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/; - var m = re.exec(s); - if (m) { - var year = parseInt(m[1], 10); - var month = m[3] ? parseInt(m[3], 10) - 1 : 0; - var day = m[5] ? parseInt(m[5], 10) : 1; - var hour = m[7] ? parseInt(m[7], 10) : 0; - var minute = m[8] ? parseInt(m[8], 10) : 0; - var second = m[9] ? parseInt(m[9], 10) : 0; - var when = Date.UTC(year, month, day, hour, minute, second); - if (m[10] && m[10] != 'Z') { - var sign = m[11] == '-' ? -1 : 1; - when += sign * 60 * parseInt(m[12], 10); - if (m[13]) { - when += sign * 60 * 60 * parseInt(m[13], 10); - } - } - whens.push(when); +ol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) { + if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { + return false; + } + + if (this.condition_(mapBrowserEvent)) { + mapBrowserEvent.map.getView().setHint(ol.ViewHint.INTERACTING, 1); + this.lastAngle_ = undefined; + this.lastMagnitude_ = undefined; + return true; } else { - whens.push(0); + return false; } }; +goog.provide('ol.interaction.Draw'); +goog.provide('ol.interaction.DrawEvent'); +goog.provide('ol.interaction.DrawEventType'); +goog.provide('ol.interaction.DrawGeometryFunctionType'); +goog.provide('ol.interaction.DrawMode'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('ol.Collection'); +goog.require('ol.Coordinate'); +goog.require('ol.Feature'); +goog.require('ol.MapBrowserEvent'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.Object'); +goog.require('ol.coordinate'); +goog.require('ol.events.condition'); +goog.require('ol.geom.Circle'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.interaction.InteractionProperty'); +goog.require('ol.interaction.Pointer'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); + /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @enum {string} */ -ol.format.KML.DATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'value': ol.xml.makeReplacer(ol.format.XSD.readString) - }); +ol.interaction.DrawEventType = { + /** + * Triggered upon feature draw start + * @event ol.interaction.DrawEvent#drawstart + * @api stable + */ + DRAWSTART: 'drawstart', + /** + * Triggered upon feature draw end + * @event ol.interaction.DrawEvent#drawend + * @api stable + */ + DRAWEND: 'drawend' +}; + /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @classdesc + * Events emitted by {@link ol.interaction.Draw} instances are instances of + * this type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.DrawEvent} + * @param {ol.interaction.DrawEventType} type Type. + * @param {ol.Feature} feature The feature drawn. */ -ol.format.KML.EXTENDED_DATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Data': ol.format.KML.DataParser_, - 'SchemaData': ol.format.KML.SchemaDataParser_ - }); +ol.interaction.DrawEvent = function(type, feature) { + goog.base(this, type); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'extrude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); + /** + * The feature being drawn. + * @type {ol.Feature} + * @api stable + */ + this.feature = feature; +}; +goog.inherits(ol.interaction.DrawEvent, goog.events.Event); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.FLAT_LINEAR_RING_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_) - }); /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @classdesc + * Interaction for drawing feature geometries. + * + * @constructor + * @extends {ol.interaction.Pointer} + * @fires ol.interaction.DrawEvent + * @param {olx.interaction.DrawOptions} options Options. + * @api stable */ -ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'innerBoundaryIs': ol.format.KML.innerBoundaryIsParser_, - 'outerBoundaryIs': ol.format.KML.outerBoundaryIsParser_ - }); +ol.interaction.Draw = function(options) { + goog.base(this, { + handleDownEvent: ol.interaction.Draw.handleDownEvent_, + handleEvent: ol.interaction.Draw.handleEvent, + handleUpEvent: ol.interaction.Draw.handleUpEvent_ + }); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.GX_TRACK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'when': ol.format.KML.whenParser_ - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'coord': ol.format.KML.gxCoordParser_ - })); + /** + * @type {ol.Pixel} + * @private + */ + this.downPx_ = null; + /** + * @type {boolean} + * @private + */ + this.freehand_ = false; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_) - }); + /** + * Target source for drawn features. + * @type {ol.source.Vector} + * @private + */ + this.source_ = options.source ? options.source : null; + /** + * Target collection for drawn features. + * @type {ol.Collection.<ol.Feature>} + * @private + */ + this.features_ = options.features ? options.features : null; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.ICON_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_) - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'x': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'y': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'w': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'h': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal) - })); + /** + * Pixel distance for snapping. + * @type {number} + * @private + */ + this.snapTolerance_ = options.snapTolerance ? options.snapTolerance : 12; + /** + * Geometry type. + * @type {ol.geom.GeometryType} + * @private + */ + this.type_ = options.type; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.ICON_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Icon': ol.xml.makeObjectPropertySetter(ol.format.KML.readIcon_), - 'heading': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), - 'hotSpot': ol.xml.makeObjectPropertySetter(ol.format.KML.readVec2_), - 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_) - }); + /** + * Drawing mode (derived from geometry type. + * @type {ol.interaction.DrawMode} + * @private + */ + this.mode_ = ol.interaction.Draw.getMode_(this.type_); + /** + * The number of points that must be drawn before a polygon ring or line + * string can be finished. The default is 3 for polygon rings and 2 for + * line strings. + * @type {number} + * @private + */ + this.minPoints_ = options.minPoints ? + options.minPoints : + (this.mode_ === ol.interaction.DrawMode.POLYGON ? 3 : 2); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.INNER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_) - }); + /** + * The number of points that can be drawn before a polygon ring or line string + * is finished. The default is no restriction. + * @type {number} + * @private + */ + this.maxPoints_ = options.maxPoints ? options.maxPoints : Infinity; + var geometryFunction = options.geometryFunction; + if (!geometryFunction) { + if (this.type_ === ol.geom.GeometryType.CIRCLE) { + /** + * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates + * @param {ol.geom.SimpleGeometry=} opt_geometry + * @return {ol.geom.SimpleGeometry} + */ + geometryFunction = function(coordinates, opt_geometry) { + var circle = opt_geometry ? opt_geometry : + new ol.geom.Circle([NaN, NaN]); + goog.asserts.assertInstanceof(circle, ol.geom.Circle, + 'geometry must be an ol.geom.Circle'); + var squaredLength = ol.coordinate.squaredDistance( + coordinates[0], coordinates[1]); + circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength)); + return circle; + }; + } else { + var Constructor; + var mode = this.mode_; + if (mode === ol.interaction.DrawMode.POINT) { + Constructor = ol.geom.Point; + } else if (mode === ol.interaction.DrawMode.LINE_STRING) { + Constructor = ol.geom.LineString; + } else if (mode === ol.interaction.DrawMode.POLYGON) { + Constructor = ol.geom.Polygon; + } + /** + * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates + * @param {ol.geom.SimpleGeometry=} opt_geometry + * @return {ol.geom.SimpleGeometry} + */ + geometryFunction = function(coordinates, opt_geometry) { + var geometry = opt_geometry; + if (geometry) { + geometry.setCoordinates(coordinates); + } else { + geometry = new Constructor(coordinates); + } + return geometry; + }; + } + } -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.LABEL_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), - 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_) - }); + /** + * @type {ol.interaction.DrawGeometryFunctionType} + * @private + */ + this.geometryFunction_ = geometryFunction; + /** + * Finish coordinate for the feature (first point for polygons, last point for + * linestrings). + * @type {ol.Coordinate} + * @private + */ + this.finishCoordinate_ = null; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.LINE_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), - 'width': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal) - }); + /** + * Sketch feature. + * @type {ol.Feature} + * @private + */ + this.sketchFeature_ = null; + /** + * Sketch point. + * @type {ol.Feature} + * @private + */ + this.sketchPoint_ = null; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.MULTI_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LineString': ol.xml.makeArrayPusher(ol.format.KML.readLineString_), - 'LinearRing': ol.xml.makeArrayPusher(ol.format.KML.readLinearRing_), - 'MultiGeometry': ol.xml.makeArrayPusher(ol.format.KML.readMultiGeometry_), - 'Point': ol.xml.makeArrayPusher(ol.format.KML.readPoint_), - 'Polygon': ol.xml.makeArrayPusher(ol.format.KML.readPolygon_) - }); + /** + * Sketch coordinates. Used when drawing a line or polygon. + * @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} + * @private + */ + this.sketchCoords_ = null; + /** + * Sketch line. Used when drawing polygon. + * @type {ol.Feature} + * @private + */ + this.sketchLine_ = null; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'Track': ol.xml.makeArrayPusher(ol.format.KML.readGxTrack_) - }); + /** + * Sketch line coordinates. Used when drawing a polygon or circle. + * @type {Array.<ol.Coordinate>} + * @private + */ + this.sketchLineCoords_ = null; + + /** + * Squared tolerance for handling up events. If the squared distance + * between a down and up event is greater than this tolerance, up events + * will not be handled. + * @type {number} + * @private + */ + this.squaredClickTolerance_ = options.clickTolerance ? + options.clickTolerance * options.clickTolerance : 36; + + /** + * Draw overlay where our sketch features are drawn. + * @type {ol.layer.Vector} + * @private + */ + this.overlay_ = new ol.layer.Vector({ + source: new ol.source.Vector({ + useSpatialIndex: false, + wrapX: options.wrapX ? options.wrapX : false + }), + style: options.style ? options.style : + ol.interaction.Draw.getDefaultStyleFunction() + }); + + /** + * Name of the geometry attribute for newly created features. + * @type {string|undefined} + * @private + */ + this.geometryName_ = options.geometryName; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = options.condition ? + options.condition : ol.events.condition.noModifierKeys; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.freehandCondition_ = options.freehandCondition ? + options.freehandCondition : ol.events.condition.shiftKeyOnly; + + goog.events.listen(this, + ol.Object.getChangeEventType(ol.interaction.InteractionProperty.ACTIVE), + this.updateState_, false, this); + +}; +goog.inherits(ol.interaction.Draw, ol.interaction.Pointer); /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @return {ol.style.StyleFunction} Styles. */ -ol.format.KML.NETWORK_LINK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'ExtendedData': ol.format.KML.ExtendedDataParser_, - 'Link': ol.format.KML.LinkParser_, - 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) - }); +ol.interaction.Draw.getDefaultStyleFunction = function() { + var styles = ol.style.createDefaultEditingStyles(); + return function(feature, resolution) { + return styles[feature.getGeometry().getType()]; + }; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @inheritDoc */ -ol.format.KML.LINK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_) - }); +ol.interaction.Draw.prototype.setMap = function(map) { + goog.base(this, 'setMap', map); + this.updateState_(); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Handles the {@link ol.MapBrowserEvent map browser event} and may actually + * draw or finish the drawing. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.Draw} + * @api */ -ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_) - }); +ol.interaction.Draw.handleEvent = function(mapBrowserEvent) { + var pass = !this.freehand_; + if (this.freehand_ && + mapBrowserEvent.type === ol.MapBrowserEvent.EventType.POINTERDRAG) { + this.addToDrawing_(mapBrowserEvent); + pass = false; + } else if (mapBrowserEvent.type === + ol.MapBrowserEvent.EventType.POINTERMOVE) { + pass = this.handlePointerMove_(mapBrowserEvent); + } else if (mapBrowserEvent.type === ol.MapBrowserEvent.EventType.DBLCLICK) { + pass = false; + } + return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && pass; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.MapBrowserPointerEvent} event Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.Draw} * @private */ -ol.format.KML.PAIR_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_), - 'key': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyleUrl_) - }); +ol.interaction.Draw.handleDownEvent_ = function(event) { + if (this.condition_(event)) { + this.downPx_ = event.pixel; + return true; + } else if ((this.mode_ === ol.interaction.DrawMode.LINE_STRING || + this.mode_ === ol.interaction.DrawMode.POLYGON) && + this.freehandCondition_(event)) { + this.downPx_ = event.pixel; + this.freehand_ = true; + if (!this.finishCoordinate_) { + this.startDrawing_(event); + } + return true; + } else { + return false; + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.MapBrowserPointerEvent} event Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.Draw} * @private */ -ol.format.KML.PLACEMARK_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'ExtendedData': ol.format.KML.ExtendedDataParser_, - 'MultiGeometry': ol.xml.makeObjectPropertySetter( - ol.format.KML.readMultiGeometry_, 'geometry'), - 'LineString': ol.xml.makeObjectPropertySetter( - ol.format.KML.readLineString_, 'geometry'), - 'LinearRing': ol.xml.makeObjectPropertySetter( - ol.format.KML.readLinearRing_, 'geometry'), - 'Point': ol.xml.makeObjectPropertySetter( - ol.format.KML.readPoint_, 'geometry'), - 'Polygon': ol.xml.makeObjectPropertySetter( - ol.format.KML.readPolygon_, 'geometry'), - 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_), - 'StyleMap': ol.format.KML.PlacemarkStyleMapParser_, - 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_), - 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'MultiTrack': ol.xml.makeObjectPropertySetter( - ol.format.KML.readGxMultiTrack_, 'geometry'), - 'Track': ol.xml.makeObjectPropertySetter( - ol.format.KML.readGxTrack_, 'geometry') - } - )); +ol.interaction.Draw.handleUpEvent_ = function(event) { + this.freehand_ = false; + var downPx = this.downPx_; + var clickPx = event.pixel; + var dx = downPx[0] - clickPx[0]; + var dy = downPx[1] - clickPx[1]; + var squaredDistance = dx * dx + dy * dy; + var pass = true; + if (squaredDistance <= this.squaredClickTolerance_) { + this.handlePointerMove_(event); + if (!this.finishCoordinate_) { + this.startDrawing_(event); + if (this.mode_ === ol.interaction.DrawMode.POINT) { + this.finishDrawing(); + } + } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { + this.finishDrawing(); + } else if (this.atFinish_(event)) { + this.finishDrawing(); + } else { + this.addToDrawing_(event); + } + pass = false; + } + return pass; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * Handle move events. + * @param {ol.MapBrowserEvent} event A move event. + * @return {boolean} Pass the event to other interactions. * @private */ -ol.format.KML.POLY_STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_), - 'fill': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean), - 'outline': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean) - }); +ol.interaction.Draw.prototype.handlePointerMove_ = function(event) { + if (this.finishCoordinate_) { + this.modifyDrawing_(event); + } else { + this.createOrUpdateSketchPoint_(event); + } + return true; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * Determine if an event is within the snapping tolerance of the start coord. + * @param {ol.MapBrowserEvent} event Event. + * @return {boolean} The event is within the snapping tolerance of the start. * @private */ -ol.format.KML.SCHEMA_DATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'SimpleData': ol.format.KML.SimpleDataParser_ - }); +ol.interaction.Draw.prototype.atFinish_ = function(event) { + var at = false; + if (this.sketchFeature_) { + var potentiallyDone = false; + var potentiallyFinishCoordinates = [this.finishCoordinate_]; + if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { + potentiallyDone = this.sketchCoords_.length > this.minPoints_; + } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { + potentiallyDone = this.sketchCoords_[0].length > + this.minPoints_; + potentiallyFinishCoordinates = [this.sketchCoords_[0][0], + this.sketchCoords_[0][this.sketchCoords_[0].length - 2]]; + } + if (potentiallyDone) { + var map = event.map; + for (var i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) { + var finishCoordinate = potentiallyFinishCoordinates[i]; + var finishPixel = map.getPixelFromCoordinate(finishCoordinate); + var pixel = event.pixel; + var dx = pixel[0] - finishPixel[0]; + var dy = pixel[1] - finishPixel[1]; + var freehand = this.freehand_ && this.freehandCondition_(event); + var snapTolerance = freehand ? 1 : this.snapTolerance_; + at = Math.sqrt(dx * dx + dy * dy) <= snapTolerance; + if (at) { + this.finishCoordinate_ = finishCoordinate; + break; + } + } + } + } + return at; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.MapBrowserEvent} event Event. * @private */ -ol.format.KML.STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'IconStyle': ol.format.KML.IconStyleParser_, - 'LabelStyle': ol.format.KML.LabelStyleParser_, - 'LineStyle': ol.format.KML.LineStyleParser_, - 'PolyStyle': ol.format.KML.PolyStyleParser_ - }); +ol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) { + var coordinates = event.coordinate.slice(); + if (!this.sketchPoint_) { + this.sketchPoint_ = new ol.Feature(new ol.geom.Point(coordinates)); + this.updateSketchFeatures_(); + } else { + var sketchPointGeom = this.sketchPoint_.getGeometry(); + goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point, + 'sketchPointGeom should be an ol.geom.Point'); + sketchPointGeom.setCoordinates(coordinates); + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * Start the drawing. + * @param {ol.MapBrowserEvent} event Event. * @private */ -ol.format.KML.STYLE_MAP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Pair': ol.format.KML.PairDataParser_ - }); +ol.interaction.Draw.prototype.startDrawing_ = function(event) { + var start = event.coordinate; + this.finishCoordinate_ = start; + if (this.mode_ === ol.interaction.DrawMode.POINT) { + this.sketchCoords_ = start.slice(); + } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { + this.sketchCoords_ = [[start.slice(), start.slice()]]; + this.sketchLineCoords_ = this.sketchCoords_[0]; + } else { + this.sketchCoords_ = [start.slice(), start.slice()]; + if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { + this.sketchLineCoords_ = this.sketchCoords_; + } + } + if (this.sketchLineCoords_) { + this.sketchLine_ = new ol.Feature( + new ol.geom.LineString(this.sketchLineCoords_)); + } + var geometry = this.geometryFunction_(this.sketchCoords_); + goog.asserts.assert(geometry !== undefined, 'geometry should be defined'); + this.sketchFeature_ = new ol.Feature(); + if (this.geometryName_) { + this.sketchFeature_.setGeometryName(this.geometryName_); + } + this.sketchFeature_.setGeometry(geometry); + this.updateSketchFeatures_(); + this.dispatchEvent(new ol.interaction.DrawEvent( + ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_)); +}; /** - * @inheritDoc + * Modify the drawing. + * @param {ol.MapBrowserEvent} event Event. + * @private */ -ol.format.KML.prototype.getExtensions = function() { - return ol.format.KML.EXTENSIONS_; +ol.interaction.Draw.prototype.modifyDrawing_ = function(event) { + var coordinate = event.coordinate; + var geometry = this.sketchFeature_.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, + 'geometry should be ol.geom.SimpleGeometry or subclass'); + var coordinates, last; + if (this.mode_ === ol.interaction.DrawMode.POINT) { + last = this.sketchCoords_; + } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { + coordinates = this.sketchCoords_[0]; + last = coordinates[coordinates.length - 1]; + if (this.atFinish_(event)) { + // snap to finish + coordinate = this.finishCoordinate_.slice(); + } + } else { + coordinates = this.sketchCoords_; + last = coordinates[coordinates.length - 1]; + } + last[0] = coordinate[0]; + last[1] = coordinate[1]; + goog.asserts.assert(this.sketchCoords_, 'sketchCoords_ expected'); + this.geometryFunction_(this.sketchCoords_, geometry); + if (this.sketchPoint_) { + var sketchPointGeom = this.sketchPoint_.getGeometry(); + goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point, + 'sketchPointGeom should be an ol.geom.Point'); + sketchPointGeom.setCoordinates(coordinate); + } + var sketchLineGeom; + if (geometry instanceof ol.geom.Polygon && + this.mode_ !== ol.interaction.DrawMode.POLYGON) { + if (!this.sketchLine_) { + this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null)); + } + var ring = geometry.getLinearRing(0); + sketchLineGeom = this.sketchLine_.getGeometry(); + goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, + 'sketchLineGeom must be an ol.geom.LineString'); + sketchLineGeom.setFlatCoordinates( + ring.getLayout(), ring.getFlatCoordinates()); + } else if (this.sketchLineCoords_) { + sketchLineGeom = this.sketchLine_.getGeometry(); + goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, + 'sketchLineGeom must be an ol.geom.LineString'); + sketchLineGeom.setCoordinates(this.sketchLineCoords_); + } + this.updateSketchFeatures_(); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Add a new coordinate to the drawing. + * @param {ol.MapBrowserEvent} event Event. * @private - * @return {Array.<ol.Feature>|undefined} Features. */ -ol.format.KML.prototype.readDocumentOrFolder_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var localName = ol.xml.getLocalName(node); - goog.asserts.assert(localName == 'Document' || localName == 'Folder', - 'localName should be Document or Folder'); - // FIXME use scope somehow - var parsersNS = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Document': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this), - 'Folder': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this), - 'Placemark': ol.xml.makeArrayPusher(this.readPlacemark_, this), - 'Style': goog.bind(this.readSharedStyle_, this), - 'StyleMap': goog.bind(this.readSharedStyleMap_, this) - }); - var features = ol.xml.pushParseAndPop(/** @type {Array.<ol.Feature>} */ ([]), - parsersNS, node, objectStack, this); - if (features) { - return features; - } else { - return undefined; +ol.interaction.Draw.prototype.addToDrawing_ = function(event) { + var coordinate = event.coordinate; + var geometry = this.sketchFeature_.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, + 'geometry must be an ol.geom.SimpleGeometry'); + var done; + var coordinates; + if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { + this.finishCoordinate_ = coordinate.slice(); + coordinates = this.sketchCoords_; + coordinates.push(coordinate.slice()); + done = coordinates.length > this.maxPoints_; + this.geometryFunction_(coordinates, geometry); + } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { + coordinates = this.sketchCoords_[0]; + coordinates.push(coordinate.slice()); + done = coordinates.length > this.maxPoints_; + if (done) { + this.finishCoordinate_ = coordinates[0]; + } + this.geometryFunction_(this.sketchCoords_, geometry); + } + this.updateSketchFeatures_(); + if (done) { + this.finishDrawing(); } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {ol.Feature|undefined} Feature. + * Remove last point of the feature currently being drawn. + * @api */ -ol.format.KML.prototype.readPlacemark_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Placemark', - 'localName should be Placemark'); - var object = ol.xml.pushParseAndPop({'geometry': null}, - ol.format.KML.PLACEMARK_PARSERS_, node, objectStack); - if (!object) { - return undefined; +ol.interaction.Draw.prototype.removeLastPoint = function() { + var geometry = this.sketchFeature_.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, + 'geometry must be an ol.geom.SimpleGeometry'); + var coordinates, sketchLineGeom; + if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { + coordinates = this.sketchCoords_; + coordinates.splice(-2, 1); + this.geometryFunction_(coordinates, geometry); + } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { + coordinates = this.sketchCoords_[0]; + coordinates.splice(-2, 1); + sketchLineGeom = this.sketchLine_.getGeometry(); + goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, + 'sketchLineGeom must be an ol.geom.LineString'); + sketchLineGeom.setCoordinates(coordinates); + this.geometryFunction_(this.sketchCoords_, geometry); } - var feature = new ol.Feature(); - var id = node.getAttribute('id'); - if (id !== null) { - feature.setId(id); + + if (coordinates.length === 0) { + this.finishCoordinate_ = null; } - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var geometry = object['geometry']; - if (geometry) { - ol.format.Feature.transformWithOptions(geometry, false, options); + this.updateSketchFeatures_(); +}; + + +/** + * Stop drawing and add the sketch feature to the target layer. + * The {@link ol.interaction.DrawEventType.DRAWEND} event is dispatched before + * inserting the feature. + * @api + */ +ol.interaction.Draw.prototype.finishDrawing = function() { + var sketchFeature = this.abortDrawing_(); + goog.asserts.assert(sketchFeature, 'sketchFeature expected to be truthy'); + var coordinates = this.sketchCoords_; + var geometry = sketchFeature.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, + 'geometry must be an ol.geom.SimpleGeometry'); + if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { + // remove the redundant last point + coordinates.pop(); + this.geometryFunction_(coordinates, geometry); + } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { + // When we finish drawing a polygon on the last point, + // the last coordinate is duplicated as for LineString + // we force the replacement by the first point + coordinates[0].pop(); + coordinates[0].push(coordinates[0][0]); + this.geometryFunction_(coordinates, geometry); } - feature.setGeometry(geometry); - delete object['geometry']; - if (this.extractStyles_) { - var style = object['Style']; - var styleUrl = object['styleUrl']; - var styleFunction = ol.format.KML.createFeatureStyleFunction_( - style, styleUrl, this.defaultStyle_, this.sharedStyles_, - this.showPointNames_); - feature.setStyle(styleFunction); + // cast multi-part geometries + if (this.type_ === ol.geom.GeometryType.MULTI_POINT) { + sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates])); + } else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) { + sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates])); + } else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) { + sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates])); } - delete object['Style']; - // we do not remove the styleUrl property from the object, so it - // gets stored on feature when setProperties is called - feature.setProperties(object); + // First dispatch event to allow full set up of feature + this.dispatchEvent(new ol.interaction.DrawEvent( + ol.interaction.DrawEventType.DRAWEND, sketchFeature)); - return feature; + // Then insert feature + if (this.features_) { + this.features_.push(sketchFeature); + } + if (this.source_) { + this.source_.addFeature(sketchFeature); + } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Stop drawing without adding the sketch feature to the target layer. + * @return {ol.Feature} The sketch feature (or null if none). * @private */ -ol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); - var id = node.getAttribute('id'); - if (id !== null) { - var style = ol.format.KML.readStyle_(node, objectStack); - if (style) { - var styleUri; - if (node.baseURI) { - styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString(); - } else { - styleUri = '#' + id; - } - this.sharedStyles_[styleUri] = style; - } +ol.interaction.Draw.prototype.abortDrawing_ = function() { + this.finishCoordinate_ = null; + var sketchFeature = this.sketchFeature_; + if (sketchFeature) { + this.sketchFeature_ = null; + this.sketchPoint_ = null; + this.sketchLine_ = null; + this.overlay_.getSource().clear(true); } + return sketchFeature; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Extend an existing geometry by adding additional points. This only works + * on features with `LineString` geometries, where the interaction will + * extend lines by adding points to the end of the coordinates array. + * @param {!ol.Feature} feature Feature to be extended. + * @api */ -ol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'StyleMap', - 'localName should be StyleMap'); - var id = node.getAttribute('id'); - if (id === null) { - return; - } - var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack); - if (!styleMapValue) { - return; - } - var styleUri; - if (node.baseURI) { - styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString(); - } else { - styleUri = '#' + id; - } - this.sharedStyles_[styleUri] = styleMapValue; +ol.interaction.Draw.prototype.extend = function(feature) { + var geometry = feature.getGeometry(); + goog.asserts.assert(this.mode_ == ol.interaction.DrawMode.LINE_STRING, + 'interaction mode must be "line"'); + goog.asserts.assert(geometry, 'feature must have a geometry'); + goog.asserts.assert(geometry.getType() == ol.geom.GeometryType.LINE_STRING, + 'feature geometry must be a line string'); + var lineString = /** @type {ol.geom.LineString} */ (geometry); + this.sketchFeature_ = feature; + this.sketchCoords_ = lineString.getCoordinates(); + var last = this.sketchCoords_[this.sketchCoords_.length - 1]; + this.finishCoordinate_ = last.slice(); + this.sketchCoords_.push(last.slice()); + this.updateSketchFeatures_(); + this.dispatchEvent(new ol.interaction.DrawEvent( + ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_)); }; /** - * Read the first feature from a KML source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable + * @inheritDoc */ -ol.format.KML.prototype.readFeature; +ol.interaction.Draw.prototype.shouldStopEvent = goog.functions.FALSE; /** - * @inheritDoc + * Redraw the sketch features. + * @private */ -ol.format.KML.prototype.readFeatureFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) { - return null; +ol.interaction.Draw.prototype.updateSketchFeatures_ = function() { + var sketchFeatures = []; + if (this.sketchFeature_) { + sketchFeatures.push(this.sketchFeature_); } - goog.asserts.assert(node.localName == 'Placemark', - 'localName should be Placemark'); - var feature = this.readPlacemark_( - node, [this.getReadOptions(node, opt_options)]); - if (feature) { - return feature; - } else { - return null; + if (this.sketchLine_) { + sketchFeatures.push(this.sketchLine_); + } + if (this.sketchPoint_) { + sketchFeatures.push(this.sketchPoint_); } + var overlaySource = this.overlay_.getSource(); + overlaySource.clear(true); + overlaySource.addFeatures(sketchFeatures); }; /** - * Read all features from a KML source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable + * @private */ -ol.format.KML.prototype.readFeatures; +ol.interaction.Draw.prototype.updateState_ = function() { + var map = this.getMap(); + var active = this.getActive(); + if (!map || !active) { + this.abortDrawing_(); + } + this.overlay_.setMap(active ? map : null); +}; /** - * @inheritDoc + * Create a `geometryFunction` for `mode: 'Circle'` that will create a regular + * polygon with a user specified number of sides and start angle instead of an + * `ol.geom.Circle` geometry. + * @param {number=} opt_sides Number of sides of the regular polygon. Default is + * 32. + * @param {number=} opt_angle Angle of the first point in radians. 0 means East. + * Default is the angle defined by the heading from the center of the + * regular polygon to the current pointer position. + * @return {ol.interaction.DrawGeometryFunctionType} Function that draws a + * polygon. + * @api */ -ol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) { - return []; - } - var features; - var localName = ol.xml.getLocalName(node); - if (localName == 'Document' || localName == 'Folder') { - features = this.readDocumentOrFolder_( - node, [this.getReadOptions(node, opt_options)]); - if (features) { - return features; - } else { - return []; - } - } else if (localName == 'Placemark') { - var feature = this.readPlacemark_( - node, [this.getReadOptions(node, opt_options)]); - if (feature) { - return [feature]; - } else { - return []; - } - } else if (localName == 'kml') { - features = []; - var n; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var fs = this.readFeaturesFromNode(n, opt_options); - if (fs) { - goog.array.extend(features, fs); +ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) { + return ( + /** + * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates + * @param {ol.geom.SimpleGeometry=} opt_geometry + * @return {ol.geom.SimpleGeometry} + */ + function(coordinates, opt_geometry) { + var center = coordinates[0]; + var end = coordinates[1]; + var radius = Math.sqrt( + ol.coordinate.squaredDistance(center, end)); + var geometry = opt_geometry ? opt_geometry : + ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides); + goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, + 'geometry must be a polygon'); + var angle = opt_angle ? opt_angle : + Math.atan((end[1] - center[1]) / (end[0] - center[0])); + ol.geom.Polygon.makeRegular(geometry, center, radius, angle); + return geometry; } - } - return features; - } else { - return []; - } + ); }; /** - * Read the name of the KML. - * - * @param {Document|Node|string} source Souce. - * @return {string|undefined} Name. - * @api stable + * Get the drawing mode. The mode for mult-part geometries is the same as for + * their single-part cousins. + * @param {ol.geom.GeometryType} type Geometry type. + * @return {ol.interaction.DrawMode} Drawing mode. + * @private */ -ol.format.KML.prototype.readName = function(source) { - if (ol.xml.isDocument(source)) { - return this.readNameFromDocument(/** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readNameFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readNameFromDocument(doc); - } else { - goog.asserts.fail('Unknown type for source'); - return undefined; +ol.interaction.Draw.getMode_ = function(type) { + var mode; + if (type === ol.geom.GeometryType.POINT || + type === ol.geom.GeometryType.MULTI_POINT) { + mode = ol.interaction.DrawMode.POINT; + } else if (type === ol.geom.GeometryType.LINE_STRING || + type === ol.geom.GeometryType.MULTI_LINE_STRING) { + mode = ol.interaction.DrawMode.LINE_STRING; + } else if (type === ol.geom.GeometryType.POLYGON || + type === ol.geom.GeometryType.MULTI_POLYGON) { + mode = ol.interaction.DrawMode.POLYGON; + } else if (type === ol.geom.GeometryType.CIRCLE) { + mode = ol.interaction.DrawMode.CIRCLE; } + goog.asserts.assert(mode !== undefined, 'mode should be defined'); + return mode; }; /** - * @param {Document} doc Document. - * @return {string|undefined} Name. + * Function that takes coordinates and an optional existing geometry as + * arguments, and returns a geometry. The optional existing geometry is the + * geometry that is returned when the function is called without a second + * argument. + * @typedef {function(!(ol.Coordinate|Array.<ol.Coordinate>| + * Array.<Array.<ol.Coordinate>>), ol.geom.SimpleGeometry=): + * ol.geom.SimpleGeometry} + * @api */ -ol.format.KML.prototype.readNameFromDocument = function(doc) { - var n; - for (n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - var name = this.readNameFromNode(n); - if (name) { - return name; - } - } - } - return undefined; -}; +ol.interaction.DrawGeometryFunctionType; /** - * @param {Node} node Node. - * @return {string|undefined} Name. + * Draw mode. This collapses multi-part geometry types with their single-part + * cousins. + * @enum {string} */ -ol.format.KML.prototype.readNameFromNode = function(node) { - var n; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - n.localName == 'name') { - return ol.format.XSD.readString(n); - } - } - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var localName = ol.xml.getLocalName(n); - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - (localName == 'Document' || - localName == 'Folder' || - localName == 'Placemark' || - localName == 'kml')) { - var name = this.readNameFromNode(n); - if (name) { - return name; - } - } - } - return undefined; +ol.interaction.DrawMode = { + POINT: 'Point', + LINE_STRING: 'LineString', + POLYGON: 'Polygon', + CIRCLE: 'Circle' }; +goog.provide('ol.interaction.Modify'); +goog.provide('ol.interaction.ModifyEvent'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); +goog.require('goog.functions'); +goog.require('ol'); +goog.require('ol.Collection'); +goog.require('ol.CollectionEventType'); +goog.require('ol.Feature'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.MapBrowserPointerEvent'); +goog.require('ol.ViewHint'); +goog.require('ol.coordinate'); +goog.require('ol.events.condition'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.interaction.Pointer'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); +goog.require('ol.structs.RBush'); + /** - * Read the network links of the KML. - * - * @param {Document|Node|string} source Source. - * @return {Array.<Object>} Network links. - * @api + * @enum {string} */ -ol.format.KML.prototype.readNetworkLinks = function(source) { - var networkLinks = []; - if (ol.xml.isDocument(source)) { - goog.array.extend(networkLinks, this.readNetworkLinksFromDocument( - /** @type {Document} */ (source))); - } else if (ol.xml.isNode(source)) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode( - /** @type {Node} */ (source))); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - goog.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc)); - } else { - goog.asserts.fail('unknown type for source'); - } - return networkLinks; +ol.ModifyEventType = { + /** + * Triggered upon feature modification start + * @event ol.interaction.ModifyEvent#modifystart + * @api + */ + MODIFYSTART: 'modifystart', + /** + * Triggered upon feature modification end + * @event ol.interaction.ModifyEvent#modifyend + * @api + */ + MODIFYEND: 'modifyend' }; + /** - * @param {Document} doc Document. - * @return {Array.<Object>} Network links. + * @classdesc + * Events emitted by {@link ol.interaction.Modify} instances are instances of + * this type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.ModifyEvent} + * @param {ol.ModifyEventType} type Type. + * @param {ol.Collection.<ol.Feature>} features The features modified. + * @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated + * {@link ol.MapBrowserPointerEvent}. */ -ol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) { - var n, networkLinks = []; - for (n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); - } - } - return networkLinks; +ol.interaction.ModifyEvent = function(type, features, mapBrowserPointerEvent) { + + goog.base(this, type); + + /** + * The features being modified. + * @type {ol.Collection.<ol.Feature>} + * @api + */ + this.features = features; + + /** + * Associated {@link ol.MapBrowserPointerEvent}. + * @type {ol.MapBrowserPointerEvent} + * @api + */ + this.mapBrowserPointerEvent = mapBrowserPointerEvent; }; +goog.inherits(ol.interaction.ModifyEvent, goog.events.Event); /** - * @param {Node} node Node. - * @return {Array.<Object>} Network links. + * @typedef {{depth: (Array.<number>|undefined), + * feature: ol.Feature, + * geometry: ol.geom.SimpleGeometry, + * index: (number|undefined), + * segment: Array.<ol.Extent>}} */ -ol.format.KML.prototype.readNetworkLinksFromNode = function(node) { - var n, networkLinks = []; - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - n.localName == 'NetworkLink') { - var obj = ol.xml.pushParseAndPop({}, ol.format.KML.NETWORK_LINK_PARSERS_, - n, []); - networkLinks.push(obj); - } - } - for (n = node.firstElementChild; n; n = n.nextElementSibling) { - var localName = ol.xml.getLocalName(n); - if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) && - (localName == 'Document' || - localName == 'Folder' || - localName == 'kml')) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); - } - } - return networkLinks; -}; +ol.interaction.SegmentDataType; + /** - * Read the projection from a KML source. + * @classdesc + * Interaction for modifying feature geometries. * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable + * @constructor + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.ModifyOptions} options Options. + * @fires ol.interaction.ModifyEvent + * @api */ -ol.format.KML.prototype.readProjection; +ol.interaction.Modify = function(options) { + + goog.base(this, { + handleDownEvent: ol.interaction.Modify.handleDownEvent_, + handleDragEvent: ol.interaction.Modify.handleDragEvent_, + handleEvent: ol.interaction.Modify.handleEvent, + handleUpEvent: ol.interaction.Modify.handleUpEvent_ + }); + + /** + * @type {ol.events.ConditionType} + * @private + */ + this.deleteCondition_ = options.deleteCondition ? + options.deleteCondition : + /** @type {ol.events.ConditionType} */ (goog.functions.and( + ol.events.condition.noModifierKeys, + ol.events.condition.singleClick)); + + /** + * Editing vertex. + * @type {ol.Feature} + * @private + */ + this.vertexFeature_ = null; + + /** + * Segments intersecting {@link this.vertexFeature_} by segment uid. + * @type {Object.<string, boolean>} + * @private + */ + this.vertexSegments_ = null; + + /** + * @type {ol.Pixel} + * @private + */ + this.lastPixel_ = [0, 0]; + + /** + * Tracks if the next `singleclick` event should be ignored to prevent + * accidental deletion right after vertex creation. + * @type {boolean} + * @private + */ + this.ignoreNextSingleClick_ = false; + + /** + * @type {boolean} + * @private + */ + this.modified_ = false; + + /** + * Segment RTree for each layer + * @type {ol.structs.RBush.<ol.interaction.SegmentDataType>} + * @private + */ + this.rBush_ = new ol.structs.RBush(); + + /** + * @type {number} + * @private + */ + this.pixelTolerance_ = options.pixelTolerance !== undefined ? + options.pixelTolerance : 10; + + /** + * @type {boolean} + * @private + */ + this.snappedToVertex_ = false; + + /** + * Indicate whether the interaction is currently changing a feature's + * coordinates. + * @type {boolean} + * @private + */ + this.changingFeature_ = false; + + /** + * @type {Array} + * @private + */ + this.dragSegments_ = null; + + /** + * Draw overlay where sketch features are drawn. + * @type {ol.layer.Vector} + * @private + */ + this.overlay_ = new ol.layer.Vector({ + source: new ol.source.Vector({ + useSpatialIndex: false, + wrapX: !!options.wrapX + }), + style: options.style ? options.style : + ol.interaction.Modify.getDefaultStyleFunction(), + updateWhileAnimating: true, + updateWhileInteracting: true + }); + + /** + * @const + * @private + * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>} + */ + this.SEGMENT_WRITERS_ = { + 'Point': this.writePointGeometry_, + 'LineString': this.writeLineStringGeometry_, + 'LinearRing': this.writeLineStringGeometry_, + 'Polygon': this.writePolygonGeometry_, + 'MultiPoint': this.writeMultiPointGeometry_, + 'MultiLineString': this.writeMultiLineStringGeometry_, + 'MultiPolygon': this.writeMultiPolygonGeometry_, + 'GeometryCollection': this.writeGeometryCollectionGeometry_ + }; + + /** + * @type {ol.Collection.<ol.Feature>} + * @private + */ + this.features_ = options.features; + + this.features_.forEach(this.addFeature_, this); + goog.events.listen(this.features_, ol.CollectionEventType.ADD, + this.handleFeatureAdd_, false, this); + goog.events.listen(this.features_, ol.CollectionEventType.REMOVE, + this.handleFeatureRemove_, false, this); + +}; +goog.inherits(ol.interaction.Modify, ol.interaction.Pointer); /** - * @param {Node} node Node to append a TextNode with the color to. - * @param {ol.Color|string} color Color. + * @param {ol.Feature} feature Feature. * @private */ -ol.format.KML.writeColorTextNode_ = function(node, color) { - var rgba = ol.color.asArray(color); - var opacity = (rgba.length == 4) ? rgba[3] : 1; - var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]]; - var i; - for (i = 0; i < 4; ++i) { - var hex = parseInt(abgr[i], 10).toString(16); - abgr[i] = (hex.length == 1) ? '0' + hex : hex; +ol.interaction.Modify.prototype.addFeature_ = function(feature) { + var geometry = feature.getGeometry(); + if (geometry.getType() in this.SEGMENT_WRITERS_) { + this.SEGMENT_WRITERS_[geometry.getType()].call(this, feature, geometry); } - ol.format.XSD.writeStringTextNode(node, abgr.join('')); + var map = this.getMap(); + if (map) { + this.handlePointerAtPixel_(this.lastPixel_, map); + } + goog.events.listen(feature, goog.events.EventType.CHANGE, + this.handleFeatureChange_, false, this); }; /** - * @param {Node} node Node to append a TextNode with the coordinates to. - * @param {Array.<number>} coordinates Coordinates. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} evt Map browser event * @private */ -ol.format.KML.writeCoordinatesTextNode_ = - function(node, coordinates, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - - var layout = context['layout']; - var stride = context['stride']; - - var dimension; - if (layout == ol.geom.GeometryLayout.XY || - layout == ol.geom.GeometryLayout.XYM) { - dimension = 2; - } else if (layout == ol.geom.GeometryLayout.XYZ || - layout == ol.geom.GeometryLayout.XYZM) { - dimension = 3; - } else { - goog.asserts.fail('Unknown geometry layout'); +ol.interaction.Modify.prototype.willModifyFeatures_ = function(evt) { + if (!this.modified_) { + this.modified_ = true; + this.dispatchEvent(new ol.interaction.ModifyEvent( + ol.ModifyEventType.MODIFYSTART, this.features_, evt)); } +}; - var d, i; - var ii = coordinates.length; - var text = ''; - if (ii > 0) { - text += coordinates[0]; - for (d = 1; d < dimension; ++d) { - text += ',' + coordinates[d]; - } - for (i = stride; i < ii; i += stride) { - text += ' ' + coordinates[i]; - for (d = 1; d < dimension; ++d) { - text += ',' + coordinates[i + d]; - } - } + +/** + * @param {ol.Feature} feature Feature. + * @private + */ +ol.interaction.Modify.prototype.removeFeature_ = function(feature) { + this.removeFeatureSegmentData_(feature); + // Remove the vertex feature if the collection of canditate features + // is empty. + if (this.vertexFeature_ && this.features_.getLength() === 0) { + this.overlay_.getSource().removeFeature(this.vertexFeature_); + this.vertexFeature_ = null; } - ol.format.XSD.writeStringTextNode(node, text); + goog.events.unlisten(feature, goog.events.EventType.CHANGE, + this.handleFeatureChange_, false, this); }; /** - * @param {Node} node Node. - * @param {Array.<ol.Feature>} features Features. - * @param {Array.<*>} objectStack Object stack. - * @this {ol.format.KML} + * @param {ol.Feature} feature Feature. * @private */ -ol.format.KML.writeDocument_ = function(node, features, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_, - ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack, undefined, - this); +ol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) { + var rBush = this.rBush_; + var /** @type {Array.<ol.interaction.SegmentDataType>} */ nodesToRemove = []; + rBush.forEach( + /** + * @param {ol.interaction.SegmentDataType} node RTree node. + */ + function(node) { + if (feature === node.feature) { + nodesToRemove.push(node); + } + }); + for (var i = nodesToRemove.length - 1; i >= 0; --i) { + rBush.remove(nodesToRemove[i]); + } }; /** - * @param {Node} node Node. - * @param {Object} icon Icon object. - * @param {Array.<*>} objectStack Object stack. - * @private + * @inheritDoc */ -ol.format.KML.writeIcon_ = function(node, icon, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(icon, orderedKeys); - ol.xml.pushSerializeAndPop(context, - ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY, - values, objectStack, orderedKeys); - orderedKeys = - ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]]; - values = ol.xml.makeSequence(icon, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_, - ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys); +ol.interaction.Modify.prototype.setMap = function(map) { + this.overlay_.setMap(map); + goog.base(this, 'setMap', map); }; /** - * @param {Node} node Node. - * @param {ol.style.Icon} style Icon style. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.CollectionEvent} evt Event. * @private */ -ol.format.KML.writeIconStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = {}; - var src = style.getSrc(); - var size = style.getSize(); - var iconImageSize = style.getImageSize(); - var iconProperties = { - 'href': src - }; - - if (size) { - iconProperties['w'] = size[0]; - iconProperties['h'] = size[1]; - var anchor = style.getAnchor(); // top-left - var origin = style.getOrigin(); // top-left - - if (origin && iconImageSize && origin[0] !== 0 && origin[1] !== size[1]) { - iconProperties['x'] = origin[0]; - iconProperties['y'] = iconImageSize[1] - (origin[1] + size[1]); - } - - if (anchor && anchor[0] !== 0 && anchor[1] !== size[1]) { - var /** @type {ol.format.KMLVec2_} */ hotSpot = { - x: anchor[0], - xunits: ol.style.IconAnchorUnits.PIXELS, - y: size[1] - anchor[1], - yunits: ol.style.IconAnchorUnits.PIXELS - }; - properties['hotSpot'] = hotSpot; - } - } - - properties['Icon'] = iconProperties; +ol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) { + var feature = evt.element; + goog.asserts.assertInstanceof(feature, ol.Feature, + 'feature should be an ol.Feature'); + this.addFeature_(feature); +}; - var scale = style.getScale(); - if (scale !== 1) { - properties['scale'] = scale; - } - var rotation = style.getRotation(); - if (rotation !== 0) { - properties['heading'] = rotation; // 0-360 +/** + * @param {goog.events.Event} evt Event. + * @private + */ +ol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) { + if (!this.changingFeature_) { + var feature = /** @type {ol.Feature} */ (evt.target); + this.removeFeature_(feature); + this.addFeature_(feature); } - - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); }; /** - * @param {Node} node Node. - * @param {ol.style.Text} style style. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.CollectionEvent} evt Event. * @private */ -ol.format.KML.writeLabelStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = {}; - var fill = style.getFill(); - if (fill) { - properties['color'] = fill.getColor(); - } - var scale = style.getScale(); - if (scale && scale !== 1) { - properties['scale'] = scale; - } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = - ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); +ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) { + var feature = /** @type {ol.Feature} */ (evt.element); + this.removeFeature_(feature); }; /** - * @param {Node} node Node. - * @param {ol.style.Stroke} style style. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.Point} geometry Geometry. * @private */ -ol.format.KML.writeLineStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = { - 'color': style.getColor(), - 'width': style.getWidth() - }; - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); +ol.interaction.Modify.prototype.writePointGeometry_ = + function(feature, geometry) { + var coordinates = geometry.getCoordinates(); + var segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + feature: feature, + geometry: geometry, + segment: [coordinates, coordinates] + }); + this.rBush_.insert(geometry.getExtent(), segmentData); }; /** - * @param {Node} node Node. - * @param {ol.geom.Geometry} geometry Geometry. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.MultiPoint} geometry Geometry. * @private */ -ol.format.KML.writeMultiGeometry_ = - function(node, geometry, objectStack) { - goog.asserts.assert( - (geometry instanceof ol.geom.MultiPoint) || - (geometry instanceof ol.geom.MultiLineString) || - (geometry instanceof ol.geom.MultiPolygon), - 'geometry should be one of: ol.geom.MultiPoint, ' + - 'ol.geom.MultiLineString or ol.geom.MultiPolygon'); - /** @type {ol.xml.NodeStackItem} */ - var context = {node: node}; - var type = geometry.getType(); - /** @type {Array.<ol.geom.Geometry>} */ - var geometries; - /** @type {function(*, Array.<*>, string=): (Node|undefined)} */ - var factory; - if (type == ol.geom.GeometryType.MULTI_POINT) { - geometries = - (/** @type {ol.geom.MultiPoint} */ (geometry)).getPoints(); - factory = ol.format.KML.POINT_NODE_FACTORY_; - } else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) { - geometries = - (/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings(); - factory = ol.format.KML.LINE_STRING_NODE_FACTORY_; - } else if (type == ol.geom.GeometryType.MULTI_POLYGON) { - geometries = - (/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons(); - factory = ol.format.KML.POLYGON_NODE_FACTORY_; - } else { - goog.asserts.fail('Unknown geometry type: ' + type); +ol.interaction.Modify.prototype.writeMultiPointGeometry_ = + function(feature, geometry) { + var points = geometry.getCoordinates(); + var coordinates, i, ii, segmentData; + for (i = 0, ii = points.length; i < ii; ++i) { + coordinates = points[i]; + segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + feature: feature, + geometry: geometry, + depth: [i], + index: i, + segment: [coordinates, coordinates] + }); + this.rBush_.insert(geometry.getExtent(), segmentData); } - ol.xml.pushSerializeAndPop(context, - ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory, - geometries, objectStack); }; /** - * @param {Node} node Node. - * @param {ol.geom.LinearRing} linearRing Linear ring. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.LineString} geometry Geometry. * @private */ -ol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - ol.xml.pushSerializeAndPop(context, - ol.format.KML.BOUNDARY_IS_SERIALIZERS_, - ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack); +ol.interaction.Modify.prototype.writeLineStringGeometry_ = + function(feature, geometry) { + var coordinates = geometry.getCoordinates(); + var i, ii, segment, segmentData; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + feature: feature, + geometry: geometry, + index: i, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); + } }; /** - * FIXME currently we do serialize arbitrary/custom feature properties - * (ExtendedData). - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Object stack. - * @this {ol.format.KML} + * @param {ol.Feature} feature Feature + * @param {ol.geom.MultiLineString} geometry Geometry. * @private */ -ol.format.KML.writePlacemark_ = function(node, feature, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - - // set id - if (feature.getId()) { - node.setAttribute('id', feature.getId()); +ol.interaction.Modify.prototype.writeMultiLineStringGeometry_ = + function(feature, geometry) { + var lines = geometry.getCoordinates(); + var coordinates, i, ii, j, jj, segment, segmentData; + for (j = 0, jj = lines.length; j < jj; ++j) { + coordinates = lines[j]; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + feature: feature, + geometry: geometry, + depth: [j], + index: i, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); + } } +}; - // serialize properties (properties unknown to KML are not serialized) - var properties = feature.getProperties(); - var styleFunction = feature.getStyleFunction(); - if (styleFunction) { - // FIXME the styles returned by the style function are supposed to be - // resolution-independent here - var styles = styleFunction.call(feature, 0); - if (styles && styles.length > 0) { - var style = styles[0]; - if (this.writeStyles_) { - properties['Style'] = styles[0]; - } - var textStyle = style.getText(); - if (textStyle) { - properties['name'] = textStyle.getText(); - } +/** + * @param {ol.Feature} feature Feature + * @param {ol.geom.Polygon} geometry Geometry. + * @private + */ +ol.interaction.Modify.prototype.writePolygonGeometry_ = + function(feature, geometry) { + var rings = geometry.getCoordinates(); + var coordinates, i, ii, j, jj, segment, segmentData; + for (j = 0, jj = rings.length; j < jj; ++j) { + coordinates = rings[j]; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + feature: feature, + geometry: geometry, + depth: [j], + index: i, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); } } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); - - // serialize geometry - var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]); - var geometry = feature.getGeometry(); - if (geometry) { - geometry = - ol.format.Feature.transformWithOptions(geometry, true, options); - } - ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_, - ol.format.KML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack); }; /** - * @param {Node} node Node. - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.MultiPolygon} geometry Geometry. * @private */ -ol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) { - goog.asserts.assert( - (geometry instanceof ol.geom.Point) || - (geometry instanceof ol.geom.LineString) || - (geometry instanceof ol.geom.LinearRing), - 'geometry should be one of ol.geom.Point, ol.geom.LineString ' + - 'or ol.geom.LinearRing'); - var flatCoordinates = geometry.getFlatCoordinates(); - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - context['layout'] = geometry.getLayout(); - context['stride'] = geometry.getStride(); - ol.xml.pushSerializeAndPop(context, - ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_, - ol.format.KML.COORDINATES_NODE_FACTORY_, - [flatCoordinates], objectStack); +ol.interaction.Modify.prototype.writeMultiPolygonGeometry_ = + function(feature, geometry) { + var polygons = geometry.getCoordinates(); + var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData; + for (k = 0, kk = polygons.length; k < kk; ++k) { + rings = polygons[k]; + for (j = 0, jj = rings.length; j < jj; ++j) { + coordinates = rings[j]; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + feature: feature, + geometry: geometry, + depth: [j, k], + index: i, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); + } + } + } }; /** - * @param {Node} node Node. - * @param {ol.geom.Polygon} polygon Polygon. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.GeometryCollection} geometry Geometry. * @private */ -ol.format.KML.writePolygon_ = function(node, polygon, objectStack) { - goog.asserts.assertInstanceof(polygon, ol.geom.Polygon, - 'polygon should be an ol.geom.Polygon'); - var linearRings = polygon.getLinearRings(); - goog.asserts.assert(linearRings.length > 0, - 'linearRings should not be empty'); - var outerRing = linearRings.shift(); - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - // inner rings - ol.xml.pushSerializeAndPop(context, - ol.format.KML.POLYGON_SERIALIZERS_, - ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_, - linearRings, objectStack); - // outer ring - ol.xml.pushSerializeAndPop(context, - ol.format.KML.POLYGON_SERIALIZERS_, - ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_, - [outerRing], objectStack); +ol.interaction.Modify.prototype.writeGeometryCollectionGeometry_ = + function(feature, geometry) { + var i, geometries = geometry.getGeometriesArray(); + for (i = 0; i < geometries.length; ++i) { + this.SEGMENT_WRITERS_[geometries[i].getType()].call( + this, feature, geometries[i]); + } }; /** - * @param {Node} node Node. - * @param {ol.style.Fill} style Style. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Coordinate} coordinates Coordinates. + * @return {ol.Feature} Vertex feature. * @private */ -ol.format.KML.writePolyStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_, - ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack); +ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = + function(coordinates) { + var vertexFeature = this.vertexFeature_; + if (!vertexFeature) { + vertexFeature = new ol.Feature(new ol.geom.Point(coordinates)); + this.vertexFeature_ = vertexFeature; + this.overlay_.getSource().addFeature(vertexFeature); + } else { + var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry()); + geometry.setCoordinates(coordinates); + } + return vertexFeature; }; /** - * @param {Node} node Node to append a TextNode with the scale to. - * @param {number|undefined} scale Scale. + * @param {ol.interaction.SegmentDataType} a + * @param {ol.interaction.SegmentDataType} b + * @return {number} * @private */ -ol.format.KML.writeScaleTextNode_ = function(node, scale) { - ol.format.XSD.writeDecimalTextNode(node, scale * scale); +ol.interaction.Modify.compareIndexes_ = function(a, b) { + return a.index - b.index; }; /** - * @param {Node} node Node. - * @param {ol.style.Style} style Style. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} evt Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.Modify} * @private */ -ol.format.KML.writeStyle_ = function(node, style, objectStack) { - var /** @type {ol.xml.NodeStackItem} */ context = {node: node}; - var properties = {}; - var fillStyle = style.getFill(); - var strokeStyle = style.getStroke(); - var imageStyle = style.getImage(); - var textStyle = style.getText(); - if (imageStyle instanceof ol.style.Icon) { - properties['IconStyle'] = imageStyle; - } - if (textStyle) { - properties['LabelStyle'] = textStyle; - } - if (strokeStyle) { - properties['LineStyle'] = strokeStyle; - } - if (fillStyle) { - properties['PolyStyle'] = fillStyle; +ol.interaction.Modify.handleDownEvent_ = function(evt) { + this.handlePointerAtPixel_(evt.pixel, evt.map); + this.dragSegments_ = []; + this.modified_ = false; + var vertexFeature = this.vertexFeature_; + if (vertexFeature) { + var insertVertices = []; + var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry()); + var vertex = geometry.getCoordinates(); + var vertexExtent = ol.extent.boundingExtent([vertex]); + var segmentDataMatches = this.rBush_.getInExtent(vertexExtent); + var componentSegments = {}; + segmentDataMatches.sort(ol.interaction.Modify.compareIndexes_); + for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) { + var segmentDataMatch = segmentDataMatches[i]; + var segment = segmentDataMatch.segment; + var uid = goog.getUid(segmentDataMatch.feature); + var depth = segmentDataMatch.depth; + if (depth) { + uid += '-' + depth.join('-'); // separate feature components + } + if (!componentSegments[uid]) { + componentSegments[uid] = new Array(2); + } + if (ol.coordinate.equals(segment[0], vertex) && + !componentSegments[uid][0]) { + this.dragSegments_.push([segmentDataMatch, 0]); + componentSegments[uid][0] = segmentDataMatch; + } else if (ol.coordinate.equals(segment[1], vertex) && + !componentSegments[uid][1]) { + + // prevent dragging closed linestrings by the connecting node + if ((segmentDataMatch.geometry.getType() === + ol.geom.GeometryType.LINE_STRING || + segmentDataMatch.geometry.getType() === + ol.geom.GeometryType.MULTI_LINE_STRING) && + componentSegments[uid][0] && + componentSegments[uid][0].index === 0) { + continue; + } + + this.dragSegments_.push([segmentDataMatch, 1]); + componentSegments[uid][1] = segmentDataMatch; + } else if (goog.getUid(segment) in this.vertexSegments_ && + (!componentSegments[uid][0] && !componentSegments[uid][1])) { + insertVertices.push([segmentDataMatch, vertex]); + } + } + if (insertVertices.length) { + this.willModifyFeatures_(evt); + } + for (i = insertVertices.length - 1; i >= 0; --i) { + this.insertVertex_.apply(this, insertVertices[i]); + } } - var parentNode = objectStack[objectStack.length - 1].node; - var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys); + return !!this.vertexFeature_; }; /** - * @param {Node} node Node to append a TextNode with the Vec2 to. - * @param {ol.format.KMLVec2_} vec2 Vec2. + * @param {ol.MapBrowserPointerEvent} evt Event. + * @this {ol.interaction.Modify} * @private */ -ol.format.KML.writeVec2_ = function(node, vec2) { - node.setAttribute('x', vec2.x); - node.setAttribute('y', vec2.y); - node.setAttribute('xunits', vec2.xunits); - node.setAttribute('yunits', vec2.yunits); +ol.interaction.Modify.handleDragEvent_ = function(evt) { + this.ignoreNextSingleClick_ = false; + this.willModifyFeatures_(evt); + + var vertex = evt.coordinate; + for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) { + var dragSegment = this.dragSegments_[i]; + var segmentData = dragSegment[0]; + var depth = segmentData.depth; + var geometry = segmentData.geometry; + var coordinates = geometry.getCoordinates(); + var segment = segmentData.segment; + var index = dragSegment[1]; + + while (vertex.length < geometry.getStride()) { + vertex.push(0); + } + + switch (geometry.getType()) { + case ol.geom.GeometryType.POINT: + coordinates = vertex; + segment[0] = segment[1] = vertex; + break; + case ol.geom.GeometryType.MULTI_POINT: + coordinates[segmentData.index] = vertex; + segment[0] = segment[1] = vertex; + break; + case ol.geom.GeometryType.LINE_STRING: + coordinates[segmentData.index + index] = vertex; + segment[index] = vertex; + break; + case ol.geom.GeometryType.MULTI_LINE_STRING: + coordinates[depth[0]][segmentData.index + index] = vertex; + segment[index] = vertex; + break; + case ol.geom.GeometryType.POLYGON: + coordinates[depth[0]][segmentData.index + index] = vertex; + segment[index] = vertex; + break; + case ol.geom.GeometryType.MULTI_POLYGON: + coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex; + segment[index] = vertex; + break; + } + + this.setGeometryCoordinates_(geometry, coordinates); + } + this.createOrUpdateVertexFeature_(vertex); }; /** - * @const - * @type {Object.<string, Array.<string>>} + * @param {ol.MapBrowserPointerEvent} evt Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.Modify} * @private */ -ol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'Document', 'Placemark' - ]); +ol.interaction.Modify.handleUpEvent_ = function(evt) { + var segmentData; + for (var i = this.dragSegments_.length - 1; i >= 0; --i) { + segmentData = this.dragSegments_[i][0]; + this.rBush_.update(ol.extent.boundingExtent(segmentData.segment), + segmentData); + } + if (this.modified_) { + this.dispatchEvent(new ol.interaction.ModifyEvent( + ol.ModifyEventType.MODIFYEND, this.features_, evt)); + this.modified_ = false; + } + return false; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * Handles the {@link ol.MapBrowserEvent map browser event} and may modify the + * geometry. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.Modify} + * @api */ -ol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_), - 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_) - }); - +ol.interaction.Modify.handleEvent = function(mapBrowserEvent) { + if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) { + return true; + } -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_) - }); + var handled; + if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] && + mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE && + !this.handlingDownUpSequence) { + this.handlePointerMove_(mapBrowserEvent); + } + if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) { + if (mapBrowserEvent.type != ol.MapBrowserEvent.EventType.SINGLECLICK || + !this.ignoreNextSingleClick_) { + var geometry = this.vertexFeature_.getGeometry(); + goog.asserts.assertInstanceof(geometry, ol.geom.Point, + 'geometry should be an ol.geom.Point'); + this.willModifyFeatures_(mapBrowserEvent); + handled = this.removeVertex_(); + this.dispatchEvent(new ol.interaction.ModifyEvent( + ol.ModifyEventType.MODIFYEND, this.features_, mapBrowserEvent)); + this.modified_ = false; + } else { + handled = true; + } + } + if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK) { + this.ignoreNextSingleClick_ = false; + } -/** - * @const - * @type {Object.<string, string>} - * @private - */ -ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = { - 'Point': 'Point', - 'LineString': 'LineString', - 'LinearRing': 'LinearRing', - 'Polygon': 'Polygon', - 'MultiPoint': 'MultiGeometry', - 'MultiLineString': 'MultiGeometry', - 'MultiPolygon': 'MultiGeometry' + return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && + !handled; }; /** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'href' - ], - ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, [ - 'x', 'y', 'w', 'h' - ])); - - -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) - }, ol.xml.makeStructureNS( - ol.format.KML.GX_NAMESPACE_URIS_, { - 'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode) - })); - - -/** - * @const - * @type {Object.<string, Array.<string>>} + * @param {ol.MapBrowserEvent} evt Event. * @private */ -ol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'scale', 'heading', 'Icon', 'hotSpot' - ]); +ol.interaction.Modify.prototype.handlePointerMove_ = function(evt) { + this.lastPixel_ = evt.pixel; + this.handlePointerAtPixel_(evt.pixel, evt.map); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {ol.Pixel} pixel Pixel + * @param {ol.Map} map Map. * @private */ -ol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_), - 'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode), - 'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_), - 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_) - }); +ol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) { + var pixelCoordinate = map.getCoordinateFromPixel(pixel); + var sortByDistance = function(a, b) { + return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a.segment) - + ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b.segment); + }; + var lowerLeft = map.getCoordinateFromPixel( + [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]); + var upperRight = map.getCoordinateFromPixel( + [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]); + var box = ol.extent.boundingExtent([lowerLeft, upperRight]); -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'color', 'scale' - ]); + var rBush = this.rBush_; + var nodes = rBush.getInExtent(box); + if (nodes.length > 0) { + nodes.sort(sortByDistance); + var node = nodes[0]; + var closestSegment = node.segment; + var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, + closestSegment)); + var vertexPixel = map.getPixelFromCoordinate(vertex); + if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= + this.pixelTolerance_) { + var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); + var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); + var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); + var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); + var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); + this.snappedToVertex_ = dist <= this.pixelTolerance_; + if (this.snappedToVertex_) { + vertex = squaredDist1 > squaredDist2 ? + closestSegment[1] : closestSegment[0]; + } + this.createOrUpdateVertexFeature_(vertex); + var vertexSegments = {}; + vertexSegments[goog.getUid(closestSegment)] = true; + var segment; + for (var i = 1, ii = nodes.length; i < ii; ++i) { + segment = nodes[i].segment; + if ((ol.coordinate.equals(closestSegment[0], segment[0]) && + ol.coordinate.equals(closestSegment[1], segment[1]) || + (ol.coordinate.equals(closestSegment[0], segment[1]) && + ol.coordinate.equals(closestSegment[1], segment[0])))) { + vertexSegments[goog.getUid(segment)] = true; + } else { + break; + } + } + this.vertexSegments_ = vertexSegments; + return; + } + } + if (this.vertexFeature_) { + this.overlay_.getSource().removeFeature(this.vertexFeature_); + this.vertexFeature_ = null; + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {ol.interaction.SegmentDataType} segmentData Segment data. + * @param {ol.Coordinate} vertex Vertex. * @private */ -ol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_), - 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_) - }); +ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) { + var segment = segmentData.segment; + var feature = segmentData.feature; + var geometry = segmentData.geometry; + var depth = segmentData.depth; + var index = segmentData.index; + var coordinates; + while (vertex.length < geometry.getStride()) { + vertex.push(0); + } -/** - * @const - * @type {Object.<string, Array.<string>>} - * @private - */ -ol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'color', 'width' - ]); + switch (geometry.getType()) { + case ol.geom.GeometryType.MULTI_LINE_STRING: + goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, + 'geometry should be an ol.geom.MultiLineString'); + coordinates = geometry.getCoordinates(); + coordinates[depth[0]].splice(index + 1, 0, vertex); + break; + case ol.geom.GeometryType.POLYGON: + goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, + 'geometry should be an ol.geom.Polygon'); + coordinates = geometry.getCoordinates(); + coordinates[depth[0]].splice(index + 1, 0, vertex); + break; + case ol.geom.GeometryType.MULTI_POLYGON: + goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, + 'geometry should be an ol.geom.MultiPolygon'); + coordinates = geometry.getCoordinates(); + coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex); + break; + case ol.geom.GeometryType.LINE_STRING: + goog.asserts.assertInstanceof(geometry, ol.geom.LineString, + 'geometry should be an ol.geom.LineString'); + coordinates = geometry.getCoordinates(); + coordinates.splice(index + 1, 0, vertex); + break; + default: + return; + } + this.setGeometryCoordinates_(geometry, coordinates); + var rTree = this.rBush_; + goog.asserts.assert(segment !== undefined, 'segment should be defined'); + rTree.remove(segmentData); + goog.asserts.assert(index !== undefined, 'index should be defined'); + this.updateSegmentIndices_(geometry, index, depth, 1); + var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + segment: [segment[0], vertex], + feature: feature, + geometry: geometry, + depth: depth, + index: index + }); + rTree.insert(ol.extent.boundingExtent(newSegmentData.segment), + newSegmentData); + this.dragSegments_.push([newSegmentData, 1]); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_), - 'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode) - }); + var newSegmentData2 = /** @type {ol.interaction.SegmentDataType} */ ({ + segment: [vertex, segment[1]], + feature: feature, + geometry: geometry, + depth: depth, + index: index + 1 + }); + rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment), + newSegmentData2); + this.dragSegments_.push([newSegmentData2, 0]); + this.ignoreNextSingleClick_ = true; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * Removes a vertex from all matching features. + * @return {boolean} True when a vertex was removed. * @private */ -ol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LinearRing': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_) - }); +ol.interaction.Modify.prototype.removeVertex_ = function() { + var dragSegments = this.dragSegments_; + var segmentsByFeature = {}; + var component, coordinates, dragSegment, geometry, i, index, left; + var newIndex, newSegment, right, segmentData, uid, deleted; + for (i = dragSegments.length - 1; i >= 0; --i) { + dragSegment = dragSegments[i]; + segmentData = dragSegment[0]; + geometry = segmentData.geometry; + coordinates = geometry.getCoordinates(); + uid = goog.getUid(segmentData.feature); + if (segmentData.depth) { + // separate feature components + uid += '-' + segmentData.depth.join('-'); + } + left = right = index = undefined; + if (dragSegment[1] === 0) { + right = segmentData; + index = segmentData.index; + } else if (dragSegment[1] == 1) { + left = segmentData; + index = segmentData.index + 1; + } + if (!(uid in segmentsByFeature)) { + segmentsByFeature[uid] = [left, right, index]; + } + newSegment = segmentsByFeature[uid]; + if (left !== undefined) { + newSegment[0] = left; + } + if (right !== undefined) { + newSegment[1] = right; + } + if (newSegment[0] !== undefined && newSegment[1] !== undefined) { + component = coordinates; + deleted = false; + newIndex = index - 1; + switch (geometry.getType()) { + case ol.geom.GeometryType.MULTI_LINE_STRING: + coordinates[segmentData.depth[0]].splice(index, 1); + deleted = true; + break; + case ol.geom.GeometryType.LINE_STRING: + coordinates.splice(index, 1); + deleted = true; + break; + case ol.geom.GeometryType.MULTI_POLYGON: + component = component[segmentData.depth[1]]; + /* falls through */ + case ol.geom.GeometryType.POLYGON: + component = component[segmentData.depth[0]]; + if (component.length > 4) { + if (index == component.length - 1) { + index = 0; + } + component.splice(index, 1); + deleted = true; + if (index === 0) { + // close the ring again + component.pop(); + component.push(component[0]); + newIndex = component.length - 1; + } + } + break; + } + if (deleted) { + this.rBush_.remove(newSegment[0]); + this.rBush_.remove(newSegment[1]); + this.setGeometryCoordinates_(geometry, coordinates); + goog.asserts.assert(newIndex >= 0, 'newIndex should be larger than 0'); + var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ + depth: segmentData.depth, + feature: segmentData.feature, + geometry: segmentData.geometry, + index: newIndex, + segment: [newSegment[0].segment[0], newSegment[1].segment[1]] + }); + this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment), + newSegmentData); + this.updateSegmentIndices_(geometry, index, segmentData.depth, -1); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'LineString': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Point': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_) - }); + if (this.vertexFeature_) { + this.overlay_.getSource().removeFeature(this.vertexFeature_); + this.vertexFeature_ = null; + } + } + } + } + return true; +}; /** - * @const - * @type {Object.<string, Array.<string>>} + * @param {ol.geom.SimpleGeometry} geometry Geometry. + * @param {Array} coordinates Coordinates. * @private */ -ol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'name', 'open', 'visibility', 'address', 'phoneNumber', 'description', - 'styleUrl', 'Style' - ]); +ol.interaction.Modify.prototype.setGeometryCoordinates_ = + function(geometry, coordinates) { + this.changingFeature_ = true; + geometry.setCoordinates(coordinates); + this.changingFeature_ = false; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {ol.geom.SimpleGeometry} geometry Geometry. + * @param {number} index Index. + * @param {Array.<number>|undefined} depth Depth. + * @param {number} delta Delta (1 or -1). * @private */ -ol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'MultiGeometry': ol.xml.makeChildAppender( - ol.format.KML.writeMultiGeometry_), - 'LineString': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'LinearRing': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Point': ol.xml.makeChildAppender( - ol.format.KML.writePrimitiveGeometry_), - 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_), - 'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_), - 'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'description': ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode), - 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'open': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode), - 'phoneNumber': ol.xml.makeChildAppender( - ol.format.XSD.writeStringTextNode), - 'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode), - 'visibility': ol.xml.makeChildAppender( - ol.format.XSD.writeBooleanTextNode) - }); +ol.interaction.Modify.prototype.updateSegmentIndices_ = function( + geometry, index, depth, delta) { + this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) { + if (segmentDataMatch.geometry === geometry && + (depth === undefined || segmentDataMatch.depth === undefined || + goog.array.equals( + /** @type {null|{length: number}} */ (segmentDataMatch.depth), + depth)) && + segmentDataMatch.index > index) { + segmentDataMatch.index += delta; + } + }); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * @return {ol.style.StyleFunction} Styles. */ -ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'coordinates': ol.xml.makeChildAppender( - ol.format.KML.writeCoordinatesTextNode_) - }); +ol.interaction.Modify.getDefaultStyleFunction = function() { + var style = ol.style.createDefaultEditingStyles(); + return function(feature, resolution) { + return style[ol.geom.GeometryType.POINT]; + }; +}; +goog.provide('ol.interaction.Select'); +goog.provide('ol.interaction.SelectEvent'); +goog.provide('ol.interaction.SelectEventType'); +goog.provide('ol.interaction.SelectFilterFunction'); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private - */ -ol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'outerBoundaryIs': ol.xml.makeChildAppender( - ol.format.KML.writeBoundaryIs_), - 'innerBoundaryIs': ol.xml.makeChildAppender( - ol.format.KML.writeBoundaryIs_) - }); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('ol.CollectionEventType'); +goog.require('ol.Feature'); +goog.require('ol.array'); +goog.require('ol.events.condition'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * @enum {string} */ -ol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_) - }); +ol.interaction.SelectEventType = { + /** + * Triggered when feature(s) has been (de)selected. + * @event ol.interaction.SelectEvent#select + * @api + */ + SELECT: 'select' +}; /** - * @const - * @type {Object.<string, Array.<string>>} - * @private + * A function that takes an {@link ol.Feature} or {@link ol.render.Feature} and + * an {@link ol.layer.Layer} and returns `true` if the feature may be selected + * or `false` otherwise. + * @typedef {function((ol.Feature|ol.render.Feature), ol.layer.Layer): + * boolean} + * @api */ -ol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, [ - 'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle' - ]); +ol.interaction.SelectFilterFunction; + /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * @classdesc + * Events emitted by {@link ol.interaction.Select} instances are instances of + * this type. + * + * @param {string} type The event type. + * @param {Array.<ol.Feature>} selected Selected features. + * @param {Array.<ol.Feature>} deselected Deselected features. + * @param {ol.MapBrowserEvent} mapBrowserEvent Associated + * {@link ol.MapBrowserEvent}. + * @implements {oli.SelectEvent} + * @extends {goog.events.Event} + * @constructor */ -ol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS( - ol.format.KML.NAMESPACE_URIS_, { - 'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_), - 'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_), - 'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_), - 'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_) - }); +ol.interaction.SelectEvent = + function(type, selected, deselected, mapBrowserEvent) { + goog.base(this, type); + /** + * Selected features array. + * @type {Array.<ol.Feature>} + * @api + */ + this.selected = selected; -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) { - return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0], - 'gx:' + opt_nodeName); + /** + * Deselected features array. + * @type {Array.<ol.Feature>} + * @api + */ + this.deselected = deselected; + + /** + * Associated {@link ol.MapBrowserEvent}. + * @type {ol.MapBrowserEvent} + * @api + */ + this.mapBrowserEvent = mapBrowserEvent; }; +goog.inherits(ol.interaction.SelectEvent, goog.events.Event); + /** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private + * @classdesc + * Interaction for selecting vector features. By default, selected features are + * styled differently, so this interaction can be used for visual highlighting, + * as well as selecting features for other actions, such as modification or + * output. There are three ways of controlling which features are selected: + * using the browser event as defined by the `condition` and optionally the + * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a + * further feature filter using the `filter` option. + * + * Selected features are added to an internal unmanaged layer. + * + * @constructor + * @extends {ol.interaction.Interaction} + * @param {olx.interaction.SelectOptions=} opt_options Options. + * @fires ol.interaction.SelectEvent + * @api stable */ -ol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack, - opt_nodeName) { - goog.asserts.assertInstanceof(value, ol.Feature, - 'value should be an ol.Feature'); - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark'); -}; +ol.interaction.Select = function(opt_options) { + goog.base(this, { + handleEvent: ol.interaction.Select.handleEvent + }); -/** - * @const - * @param {*} value Value. - * @param {Array.<*>} objectStack Object stack. - * @param {string=} opt_nodeName Node name. - * @return {Node|undefined} Node. - * @private - */ -ol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, - opt_nodeName) { - if (value) { - goog.asserts.assertInstanceof(value, ol.geom.Geometry, - 'value should be an ol.geom.Geometry'); - var parentNode = objectStack[objectStack.length - 1].node; - goog.asserts.assert(ol.xml.isNode(parentNode), - 'parentNode should be an XML node'); - return ol.xml.createElementNS(parentNode.namespaceURI, - ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[value.getType()]); + var options = opt_options ? opt_options : {}; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = options.condition ? + options.condition : ol.events.condition.singleClick; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.addCondition_ = options.addCondition ? + options.addCondition : ol.events.condition.never; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.removeCondition_ = options.removeCondition ? + options.removeCondition : ol.events.condition.never; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.toggleCondition_ = options.toggleCondition ? + options.toggleCondition : ol.events.condition.shiftKeyOnly; + + /** + * @private + * @type {boolean} + */ + this.multi_ = options.multi ? options.multi : false; + + /** + * @private + * @type {ol.interaction.SelectFilterFunction} + */ + this.filter_ = options.filter ? options.filter : + goog.functions.TRUE; + + var layerFilter; + if (options.layers) { + if (goog.isFunction(options.layers)) { + layerFilter = options.layers; + } else { + var layers = options.layers; + layerFilter = + /** + * @param {ol.layer.Layer} layer Layer. + * @return {boolean} Include. + */ + function(layer) { + return ol.array.includes(layers, layer); + }; + } + } else { + layerFilter = goog.functions.TRUE; } -}; + /** + * @private + * @type {function(ol.layer.Layer): boolean} + */ + this.layerFilter_ = layerFilter; -/** - * A factory for creating coordinates nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private - */ -ol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color'); + /** + * An association between selected feature (key) + * and layer (value) + * @private + * @type {Object.<number, ol.layer.Layer>} + */ + this.featureLayerAssociation_ = {}; + + /** + * @private + * @type {ol.layer.Vector} + */ + this.featureOverlay_ = new ol.layer.Vector({ + source: new ol.source.Vector({ + useSpatialIndex: false, + features: options.features, + wrapX: options.wrapX + }), + style: options.style ? options.style : + ol.interaction.Select.getDefaultStyleFunction(), + updateWhileAnimating: true, + updateWhileInteracting: true + }); + + var features = this.featureOverlay_.getSource().getFeaturesCollection(); + goog.events.listen(features, ol.CollectionEventType.ADD, + this.addFeature_, false, this); + goog.events.listen(features, ol.CollectionEventType.REMOVE, + this.removeFeature_, false, this); + +}; +goog.inherits(ol.interaction.Select, ol.interaction.Interaction); /** - * A factory for creating coordinates nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {ol.layer.Layer} layer Layer. * @private */ -ol.format.KML.COORDINATES_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('coordinates'); +ol.interaction.Select.prototype.addFeatureLayerAssociation_ = + function(feature, layer) { + var key = goog.getUid(feature); + this.featureLayerAssociation_[key] = layer; +}; /** - * A factory for creating innerBoundaryIs nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private + * Get the selected features. + * @return {ol.Collection.<ol.Feature>} Features collection. + * @api stable */ -ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('innerBoundaryIs'); +ol.interaction.Select.prototype.getFeatures = function() { + return this.featureOverlay_.getSource().getFeaturesCollection(); +}; /** - * A factory for creating Point nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private + * Returns the associated {@link ol.layer.Vector vectorlayer} of + * the (last) selected feature. Note that this will not work with any + * programmatic method like pushing features to + * {@link ol.interaction.Select#getFeatures collection}. + * @param {ol.Feature|ol.render.Feature} feature Feature + * @return {ol.layer.Vector} Layer. + * @api */ -ol.format.KML.POINT_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('Point'); +ol.interaction.Select.prototype.getLayer = function(feature) { + goog.asserts.assertInstanceof(feature, ol.Feature, + 'feature should be an ol.Feature'); + var key = goog.getUid(feature); + return /** @type {ol.layer.Vector} */ (this.featureLayerAssociation_[key]); +}; /** - * A factory for creating LineString nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private + * Handles the {@link ol.MapBrowserEvent map browser event} and may change the + * selected state of features. + * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. + * @return {boolean} `false` to stop event propagation. + * @this {ol.interaction.Select} + * @api */ -ol.format.KML.LINE_STRING_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('LineString'); +ol.interaction.Select.handleEvent = function(mapBrowserEvent) { + if (!this.condition_(mapBrowserEvent)) { + return true; + } + var add = this.addCondition_(mapBrowserEvent); + var remove = this.removeCondition_(mapBrowserEvent); + var toggle = this.toggleCondition_(mapBrowserEvent); + var set = !add && !remove && !toggle; + var map = mapBrowserEvent.map; + var features = this.featureOverlay_.getSource().getFeaturesCollection(); + var /** @type {!Array.<ol.Feature>} */ deselected = []; + var /** @type {!Array.<ol.Feature>} */ selected = []; + var change = false; + if (set) { + // Replace the currently selected feature(s) with the feature(s) at the + // pixel, or clear the selected feature(s) if there is no feature at + // the pixel. + map.forEachFeatureAtPixel(mapBrowserEvent.pixel, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {ol.layer.Layer} layer Layer. + */ + function(feature, layer) { + if (layer && this.filter_(feature, layer)) { + selected.push(feature); + this.addFeatureLayerAssociation_(feature, layer); + return !this.multi_; + } + }, this, this.layerFilter_); + if (selected.length > 0 && features.getLength() == 1 && + features.item(0) == selected[0]) { + // No change + } else { + change = true; + if (features.getLength() !== 0) { + deselected = Array.prototype.concat(features.getArray()); + features.clear(); + } + features.extend(selected); + // Modify object this.featureLayerAssociation_ + if (selected.length === 0) { + goog.object.clear(this.featureLayerAssociation_); + } else { + if (deselected.length > 0) { + deselected.forEach(function(feature) { + this.removeFeatureLayerAssociation_(feature); + }, this); + } + } + } + } else { + // Modify the currently selected feature(s). + map.forEachFeatureAtPixel(mapBrowserEvent.pixel, + /** + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @param {ol.layer.Layer} layer Layer. + */ + function(feature, layer) { + if (!ol.array.includes(features.getArray(), feature)) { + if (add || toggle) { + if (this.filter_(feature, layer)) { + selected.push(feature); + this.addFeatureLayerAssociation_(feature, layer); + } + } + } else { + if (remove || toggle) { + deselected.push(feature); + this.removeFeatureLayerAssociation_(feature); + } + } + }, this, this.layerFilter_); + var i; + for (i = deselected.length - 1; i >= 0; --i) { + features.remove(deselected[i]); + } + features.extend(selected); + if (selected.length > 0 || deselected.length > 0) { + change = true; + } + } + if (change) { + this.dispatchEvent( + new ol.interaction.SelectEvent(ol.interaction.SelectEventType.SELECT, + selected, deselected, mapBrowserEvent)); + } + return ol.events.condition.pointerMove(mapBrowserEvent); +}; /** - * A factory for creating LinearRing nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private + * Remove the interaction from its current map, if any, and attach it to a new + * map, if any. Pass `null` to just remove the interaction from the current map. + * @param {ol.Map} map Map. + * @api stable */ -ol.format.KML.LINEAR_RING_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('LinearRing'); +ol.interaction.Select.prototype.setMap = function(map) { + var currentMap = this.getMap(); + var selectedFeatures = + this.featureOverlay_.getSource().getFeaturesCollection(); + if (!goog.isNull(currentMap)) { + selectedFeatures.forEach(currentMap.unskipFeature, currentMap); + } + goog.base(this, 'setMap', map); + this.featureOverlay_.setMap(map); + if (!goog.isNull(map)) { + selectedFeatures.forEach(map.skipFeature, map); + } +}; /** - * A factory for creating Polygon nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} - * @private + * @return {ol.style.StyleFunction} Styles. */ -ol.format.KML.POLYGON_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('Polygon'); +ol.interaction.Select.getDefaultStyleFunction = function() { + var styles = ol.style.createDefaultEditingStyles(); + goog.array.extend(styles[ol.geom.GeometryType.POLYGON], + styles[ol.geom.GeometryType.LINE_STRING]); + goog.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION], + styles[ol.geom.GeometryType.LINE_STRING]); + + return function(feature, resolution) { + return styles[feature.getGeometry().getType()]; + }; +}; /** - * A factory for creating outerBoundaryIs nodes. - * @const - * @type {function(*, Array.<*>, string=): (Node|undefined)} + * @param {ol.CollectionEvent} evt Event. * @private */ -ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ = - ol.xml.makeSimpleNodeFactory('outerBoundaryIs'); +ol.interaction.Select.prototype.addFeature_ = function(evt) { + var feature = evt.element; + var map = this.getMap(); + goog.asserts.assertInstanceof(feature, ol.Feature, + 'feature should be an ol.Feature'); + if (!goog.isNull(map)) { + map.skipFeature(feature); + } +}; /** - * Encode an array of features in the KML format. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {string} Result. - * @api stable + * @param {ol.CollectionEvent} evt Event. + * @private */ -ol.format.KML.prototype.writeFeatures; +ol.interaction.Select.prototype.removeFeature_ = function(evt) { + var feature = evt.element; + var map = this.getMap(); + goog.asserts.assertInstanceof(feature, ol.Feature, + 'feature should be an ol.Feature'); + if (!goog.isNull(map)) { + map.unskipFeature(feature); + } +}; /** - * Encode an array of features in the KML format as an XML node. - * - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Options. - * @return {Node} Node. - * @api + * @param {ol.Feature|ol.render.Feature} feature Feature. + * @private */ -ol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) { - opt_options = this.adaptOptions(opt_options); - var kml = ol.xml.createElementNS(ol.format.KML.NAMESPACE_URIS_[4], 'kml'); - var xmlnsUri = 'http://www.w3.org/2000/xmlns/'; - var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance'; - ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:gx', - ol.format.KML.GX_NAMESPACE_URIS_[0]); - ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri); - ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation', - ol.format.KML.SCHEMA_LOCATION_); - - var /** @type {ol.xml.NodeStackItem} */ context = {node: kml}; - var properties = {}; - if (features.length > 1) { - properties['Document'] = features; - } else if (features.length == 1) { - properties['Placemark'] = features[0]; - } - var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI]; - var values = ol.xml.makeSequence(properties, orderedKeys); - ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_, - ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [opt_options], orderedKeys, - this); - return kml; +ol.interaction.Select.prototype.removeFeatureLayerAssociation_ = + function(feature) { + var key = goog.getUid(feature); + delete this.featureLayerAssociation_[key]; }; -//FIXME Implement projection handling - -goog.provide('ol.format.MVT'); +goog.provide('ol.interaction.Snap'); +goog.provide('ol.interaction.SnapProperty'); goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Collection'); +goog.require('ol.CollectionEvent'); +goog.require('ol.CollectionEventType'); +goog.require('ol.Extent'); goog.require('ol.Feature'); -goog.require('ol.ext.pbf'); -goog.require('ol.ext.vectortile'); -goog.require('ol.format.Feature'); -goog.require('ol.format.FormatType'); +goog.require('ol.Object'); +goog.require('ol.Observable'); +goog.require('ol.coordinate'); +goog.require('ol.extent'); goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.proj.Projection'); -goog.require('ol.proj.Units'); -goog.require('ol.render.Feature'); +goog.require('ol.interaction.Pointer'); +goog.require('ol.source.Vector'); +goog.require('ol.source.VectorEvent'); +goog.require('ol.source.VectorEventType'); +goog.require('ol.structs.RBush'); /** * @classdesc - * Feature format for reading data in the Mapbox MVT format. + * Handles snapping of vector features while modifying or drawing them. The + * features can come from a {@link ol.source.Vector} or {@link ol.Collection} + * Any interaction object that allows the user to interact + * with the features using the mouse can benefit from the snapping, as long + * as it is added before. + * + * The snap interaction modifies map browser event `coordinate` and `pixel` + * properties to force the snap to occur to any interaction that them. + * + * Example: + * + * var snap = new ol.interaction.Snap({ + * source: source + * }); * * @constructor - * @extends {ol.format.Feature} - * @param {olx.format.MVTOptions=} opt_options Options. + * @extends {ol.interaction.Pointer} + * @param {olx.interaction.SnapOptions=} opt_options Options. * @api */ -ol.format.MVT = function(opt_options) { +ol.interaction.Snap = function(opt_options) { - goog.base(this); + goog.base(this, { + handleEvent: ol.interaction.Snap.handleEvent_, + handleDownEvent: goog.functions.TRUE, + handleUpEvent: ol.interaction.Snap.handleUpEvent_ + }); var options = opt_options ? opt_options : {}; /** - * @type {ol.proj.Projection} + * @type {ol.source.Vector} + * @private */ - this.defaultDataProjection = new ol.proj.Projection({ - code: 'EPSG:3857', - units: ol.proj.Units.TILE_PIXELS - }); + this.source_ = options.source ? options.source : null; /** + * @type {ol.Collection.<ol.Feature>} * @private - * @type {function((ol.geom.Geometry|Object.<string, *>)=)| - * function(ol.geom.GeometryType,Array.<number>, - * (Array.<number>|Array.<Array.<number>>),Object.<string, *>)} */ - this.featureClass_ = options.featureClass ? - options.featureClass : ol.render.Feature; + this.features_ = options.features ? options.features : null; /** + * @type {Array.<goog.events.Key>} * @private - * @type {string} */ - this.geometryName_ = options.geometryName ? - options.geometryName : 'geometry'; + this.featuresListenerKeys_ = []; /** + * @type {Object.<number, goog.events.Key>} * @private - * @type {string} */ - this.layerName_ = options.layerName ? options.layerName : 'layer'; + this.geometryChangeListenerKeys_ = {}; /** + * @type {Object.<number, goog.events.Key>} * @private - * @type {Array.<string>} */ - this.layers_ = options.layers ? options.layers : null; + this.geometryModifyListenerKeys_ = {}; + + /** + * Extents are preserved so indexed segment can be quickly removed + * when its feature geometry changes + * @type {Object.<number, ol.Extent>} + * @private + */ + this.indexedFeaturesExtents_ = {}; + + /** + * If a feature geometry changes while a pointer drag|move event occurs, the + * feature doesn't get updated right away. It will be at the next 'pointerup' + * event fired. + * @type {Object.<number, ol.Feature>} + * @private + */ + this.pendingFeatures_ = {}; + + /** + * Used for distance sorting in sortByDistance_ + * @type {ol.Coordinate} + * @private + */ + this.pixelCoordinate_ = null; + + /** + * @type {number} + * @private + */ + this.pixelTolerance_ = options.pixelTolerance !== undefined ? + options.pixelTolerance : 10; + + /** + * @type {function(ol.interaction.Snap.SegmentDataType, ol.interaction.Snap.SegmentDataType): number} + * @private + */ + this.sortByDistance_ = goog.bind(ol.interaction.Snap.sortByDistance, this); + + + /** + * Segment RTree for each layer + * @type {ol.structs.RBush.<ol.interaction.Snap.SegmentDataType>} + * @private + */ + this.rBush_ = new ol.structs.RBush(); + + /** + * @const + * @private + * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>} + */ + this.SEGMENT_WRITERS_ = { + 'Point': this.writePointGeometry_, + 'LineString': this.writeLineStringGeometry_, + 'LinearRing': this.writeLineStringGeometry_, + 'Polygon': this.writePolygonGeometry_, + 'MultiPoint': this.writeMultiPointGeometry_, + 'MultiLineString': this.writeMultiLineStringGeometry_, + 'MultiPolygon': this.writeMultiPolygonGeometry_, + 'GeometryCollection': this.writeGeometryCollectionGeometry_ + }; }; -goog.inherits(ol.format.MVT, ol.format.Feature); +goog.inherits(ol.interaction.Snap, ol.interaction.Pointer); /** - * @inheritDoc + * Add a feature to the collection of features that we may snap to. + * @param {ol.Feature} feature Feature. + * @param {boolean=} opt_listen Whether to listen to the geometry change or not + * Defaults to `true`. + * @api */ -ol.format.MVT.prototype.getType = function() { - return ol.format.FormatType.ARRAY_BUFFER; +ol.interaction.Snap.prototype.addFeature = function(feature, opt_listen) { + var listen = opt_listen !== undefined ? opt_listen : true; + var geometry = feature.getGeometry(); + var segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()]; + if (segmentWriter) { + var feature_uid = goog.getUid(feature); + this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent( + ol.extent.createEmpty()); + segmentWriter.call(this, feature, geometry); + + if (listen) { + this.geometryModifyListenerKeys_[feature_uid] = geometry.on( + goog.events.EventType.CHANGE, + goog.bind(this.handleGeometryModify_, this, feature), + this); + this.geometryChangeListenerKeys_[feature_uid] = feature.on( + ol.Object.getChangeEventType(feature.getGeometryName()), + this.handleGeometryChange_, this); + } + } }; /** + * @param {ol.Feature} feature Feature. * @private - * @param {Object} rawFeature Raw Mapbox feature. - * @param {string} layer Layer. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. */ -ol.format.MVT.prototype.readFeature_ = function( - rawFeature, layer, opt_options) { - var feature = new this.featureClass_(); - var values = rawFeature.properties; - values[this.layerName_] = layer; - var geometry = ol.format.Feature.transformWithOptions( - ol.format.MVT.readGeometry_(rawFeature), false, - this.adaptOptions(opt_options)); - if (geometry) { - goog.asserts.assertInstanceof(geometry, ol.geom.Geometry); - values[this.geometryName_] = geometry; - } - feature.setProperties(values); - feature.setGeometryName(this.geometryName_); - return feature; +ol.interaction.Snap.prototype.forEachFeatureAdd_ = function(feature) { + this.addFeature(feature); }; /** + * @param {ol.Feature} feature Feature. * @private - * @param {Object} rawFeature Raw Mapbox feature. - * @param {string} layer Layer. - * @return {ol.render.Feature} Feature. */ -ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) { - var coords = rawFeature.loadGeometry(); - var ends = []; - var flatCoordinates = []; - ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends); - - var type = rawFeature.type; - /** @type {ol.geom.GeometryType} */ - var geometryType; - if (type === 1) { - geometryType = coords.length === 1 ? - ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT; - } else if (type === 2) { - if (coords.length === 1) { - geometryType = ol.geom.GeometryType.LINE_STRING; - } else { - geometryType = ol.geom.GeometryType.MULTI_LINE_STRING; - } - } else if (type === 3) { - geometryType = ol.geom.GeometryType.POLYGON; - } - - var values = rawFeature.properties; - values[this.layerName_] = layer; - - return new this.featureClass_(geometryType, flatCoordinates, ends, values); +ol.interaction.Snap.prototype.forEachFeatureRemove_ = function(feature) { + this.removeFeature(feature); }; /** - * @inheritDoc + * @return {ol.Collection.<ol.Feature>|Array.<ol.Feature>} + * @private */ -ol.format.MVT.prototype.readFeatures = function(source, opt_options) { - goog.asserts.assertInstanceof(source, ArrayBuffer); - - var layers = this.layers_; - - var pbf = new ol.ext.pbf(source); - var tile = new ol.ext.vectortile.VectorTile(pbf); - var features = []; - var featureClass = this.featureClass_; - var layer, feature; - for (var name in tile.layers) { - if (layers && layers.indexOf(name) == -1) { - continue; - } - layer = tile.layers[name]; - - for (var i = 0, ii = layer.length; i < ii; ++i) { - if (featureClass === ol.render.Feature) { - feature = this.readRenderFeature_(layer.feature(i), name); - } else { - feature = this.readFeature_(layer.feature(i), name, opt_options); - } - features.push(feature); - } +ol.interaction.Snap.prototype.getFeatures_ = function() { + var features; + if (this.features_) { + features = this.features_; + } else if (this.source_) { + features = this.source_.getFeatures(); } - + goog.asserts.assert(features !== undefined, 'features should be defined'); return features; }; /** - * @inheritDoc + * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event. + * @private */ -ol.format.MVT.prototype.readProjection = function(source) { - return this.defaultDataProjection; +ol.interaction.Snap.prototype.handleFeatureAdd_ = function(evt) { + var feature; + if (evt instanceof ol.source.VectorEvent) { + feature = evt.feature; + } else if (evt instanceof ol.CollectionEvent) { + feature = evt.element; + } + goog.asserts.assertInstanceof(feature, ol.Feature, + 'feature should be an ol.Feature'); + this.addFeature(feature); }; /** - * Sets the layers that features will be read from. - * @param {Array.<string>} layers Layers. - * @api + * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event. + * @private */ -ol.format.MVT.prototype.setLayers = function(layers) { - this.layers_ = layers; +ol.interaction.Snap.prototype.handleFeatureRemove_ = function(evt) { + var feature; + if (evt instanceof ol.source.VectorEvent) { + feature = evt.feature; + } else if (evt instanceof ol.CollectionEvent) { + feature = evt.element; + } + goog.asserts.assertInstanceof(feature, ol.Feature, + 'feature should be an ol.Feature'); + this.removeFeature(feature); }; /** + * @param {goog.events.Event} evt Event. * @private - * @param {Object} coords Raw feature coordinates. - * @param {Array.<number>} flatCoordinates Flat coordinates to be populated by - * this function. - * @param {Array.<number>} ends Ends to be populated by this function. */ -ol.format.MVT.calculateFlatCoordinates_ = function( - coords, flatCoordinates, ends) { - var end = 0; - var line, coord; - for (var i = 0, ii = coords.length; i < ii; ++i) { - line = coords[i]; - for (var j = 0, jj = line.length; j < jj; ++j) { - coord = line[j]; - // Non-tilespace coords can be calculated here when a TileGrid and - // TileCoord are known. - flatCoordinates.push(coord.x, coord.y); - } - end += 2 * j; - ends.push(end); - } +ol.interaction.Snap.prototype.handleGeometryChange_ = function(evt) { + var feature = evt.currentTarget; + goog.asserts.assertInstanceof(feature, ol.Feature); + this.removeFeature(feature, true); + this.addFeature(feature, true); }; /** + * @param {ol.Feature} feature Feature which geometry was modified. + * @param {goog.events.Event} evt Event. * @private - * @param {Object} rawFeature Raw Mapbox feature. - * @return {ol.geom.Geometry} Geometry. */ -ol.format.MVT.readGeometry_ = function(rawFeature) { - var type = rawFeature.type; - if (type === 0) { - return null; - } - - var coords = rawFeature.loadGeometry(); - var ends = []; - var flatCoordinates = []; - ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends); - - var geom; - if (type === 1) { - geom = coords.length === 1 ? - new ol.geom.Point(null) : new ol.geom.MultiPoint(null); - } else if (type === 2) { - if (coords.length === 1) { - geom = new ol.geom.LineString(null); - } else { - geom = new ol.geom.MultiLineString(null); +ol.interaction.Snap.prototype.handleGeometryModify_ = function(feature, evt) { + if (this.handlingDownUpSequence) { + var uid = goog.getUid(feature); + if (!(uid in this.pendingFeatures_)) { + this.pendingFeatures_[uid] = feature; } - } else if (type === 3) { - geom = new ol.geom.Polygon(null); + } else { + this.updateFeature_(feature); } - - geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, - ends); - - return geom; }; -// FIXME add typedef for stack state objects -goog.provide('ol.format.OSMXML'); - -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); -goog.require('ol.xml'); - - /** - * @classdesc - * Feature format for reading data in the - * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML). - * - * @constructor - * @extends {ol.format.XMLFeature} - * @api stable + * Remove a feature from the collection of features that we may snap to. + * @param {ol.Feature} feature Feature + * @param {boolean=} opt_unlisten Whether to unlisten to the geometry change + * or not. Defaults to `true`. + * @api */ -ol.format.OSMXML = function() { - goog.base(this); +ol.interaction.Snap.prototype.removeFeature = function(feature, opt_unlisten) { + var unlisten = opt_unlisten !== undefined ? opt_unlisten : true; + var feature_uid = goog.getUid(feature); + var extent = this.indexedFeaturesExtents_[feature_uid]; + if (extent) { + var rBush = this.rBush_; + var i, nodesToRemove = []; + rBush.forEachInExtent(extent, function(node) { + if (feature === node.feature) { + nodesToRemove.push(node); + } + }); + for (i = nodesToRemove.length - 1; i >= 0; --i) { + rBush.remove(nodesToRemove[i]); + } + if (unlisten) { + ol.Observable.unByKey(this.geometryModifyListenerKeys_[feature_uid]); + delete this.geometryModifyListenerKeys_[feature_uid]; - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); + ol.Observable.unByKey(this.geometryChangeListenerKeys_[feature_uid]); + delete this.geometryChangeListenerKeys_[feature_uid]; + } + } }; -goog.inherits(ol.format.OSMXML, ol.format.XMLFeature); /** - * @const - * @type {Array.<string>} - * @private + * @inheritDoc */ -ol.format.OSMXML.EXTENSIONS_ = ['.osm']; +ol.interaction.Snap.prototype.setMap = function(map) { + var currentMap = this.getMap(); + var keys = this.featuresListenerKeys_; + var features = this.getFeatures_(); + + if (currentMap) { + keys.forEach(ol.Observable.unByKey); + keys.length = 0; + features.forEach(this.forEachFeatureRemove_, this); + } + + goog.base(this, 'setMap', map); + + if (map) { + if (this.features_) { + keys.push(this.features_.on(ol.CollectionEventType.ADD, + this.handleFeatureAdd_, this)); + keys.push(this.features_.on(ol.CollectionEventType.REMOVE, + this.handleFeatureRemove_, this)); + } else if (this.source_) { + keys.push(this.source_.on(ol.source.VectorEventType.ADDFEATURE, + this.handleFeatureAdd_, this)); + keys.push(this.source_.on(ol.source.VectorEventType.REMOVEFEATURE, + this.handleFeatureRemove_, this)); + } + features.forEach(this.forEachFeatureAdd_, this); + } +}; /** * @inheritDoc */ -ol.format.OSMXML.prototype.getExtensions = function() { - return ol.format.OSMXML.EXTENSIONS_; -}; +ol.interaction.Snap.prototype.shouldStopEvent = goog.functions.FALSE; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * @param {ol.Pixel} pixel Pixel + * @param {ol.Coordinate} pixelCoordinate Coordinate + * @param {ol.Map} map Map. + * @return {ol.interaction.Snap.ResultType} Snap result */ -ol.format.OSMXML.readNode_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'node', 'localName should be node'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var id = node.getAttribute('id'); - var coordinates = /** @type {Array.<number>} */ ([ - parseFloat(node.getAttribute('lon')), - parseFloat(node.getAttribute('lat')) - ]); - state.nodes[id] = coordinates; +ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) { - var values = ol.xml.pushParseAndPop({ - tags: {} - }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack); - if (!goog.object.isEmpty(values.tags)) { - var geometry = new ol.geom.Point(coordinates); - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setId(id); - feature.setProperties(values.tags); - state.features.push(feature); + var lowerLeft = map.getCoordinateFromPixel( + [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]); + var upperRight = map.getCoordinateFromPixel( + [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]); + var box = ol.extent.boundingExtent([lowerLeft, upperRight]); + + var segments = this.rBush_.getInExtent(box); + var snappedToVertex = false; + var snapped = false; + var vertex = null; + var vertexPixel = null; + if (segments.length > 0) { + this.pixelCoordinate_ = pixelCoordinate; + segments.sort(this.sortByDistance_); + var closestSegment = segments[0].segment; + vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, + closestSegment)); + vertexPixel = map.getPixelFromCoordinate(vertex); + if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= + this.pixelTolerance_) { + snapped = true; + var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); + var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); + var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); + var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); + var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); + snappedToVertex = dist <= this.pixelTolerance_; + if (snappedToVertex) { + vertex = squaredDist1 > squaredDist2 ? + closestSegment[1] : closestSegment[0]; + vertexPixel = map.getPixelFromCoordinate(vertex); + vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])]; + } + } } + return /** @type {ol.interaction.Snap.ResultType} */ ({ + snapped: snapped, + vertex: vertex, + vertexPixel: vertexPixel + }); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature * @private */ -ol.format.OSMXML.readWay_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'way', 'localName should be way'); - var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]); - var id = node.getAttribute('id'); - var values = ol.xml.pushParseAndPop({ - ndrefs: [], - tags: {} - }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack); - var state = /** @type {Object} */ (objectStack[objectStack.length - 1]); - var flatCoordinates = /** @type {Array.<number>} */ ([]); - for (var i = 0, ii = values.ndrefs.length; i < ii; i++) { - var point = state.nodes[values.ndrefs[i]]; - goog.array.extend(flatCoordinates, point); - } - var geometry; - if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) { - // closed way - geometry = new ol.geom.Polygon(null); - geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates, - [flatCoordinates.length]); - } else { - geometry = new ol.geom.LineString(null); - geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); - } - ol.format.Feature.transformWithOptions(geometry, false, options); - var feature = new ol.Feature(geometry); - feature.setId(id); - feature.setProperties(values.tags); - state.features.push(feature); +ol.interaction.Snap.prototype.updateFeature_ = function(feature) { + this.removeFeature(feature, false); + this.addFeature(feature, false); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.GeometryCollection} geometry Geometry. * @private - * @return {ol.Feature|undefined} Track. */ -ol.format.OSMXML.readNd_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'nd', 'localName should be nd'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - values.ndrefs.push(node.getAttribute('ref')); +ol.interaction.Snap.prototype.writeGeometryCollectionGeometry_ = + function(feature, geometry) { + var i, geometries = geometry.getGeometriesArray(); + for (i = 0; i < geometries.length; ++i) { + this.SEGMENT_WRITERS_[geometries[i].getType()].call( + this, feature, geometries[i]); + } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.Feature} feature Feature + * @param {ol.geom.LineString} geometry Geometry. * @private - * @return {ol.Feature|undefined} Track. */ -ol.format.OSMXML.readTag_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'tag', 'localName should be tag'); - var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); - values.tags[node.getAttribute('k')] = node.getAttribute('v'); +ol.interaction.Snap.prototype.writeLineStringGeometry_ = + function(feature, geometry) { + var coordinates = geometry.getCoordinates(); + var i, ii, segment, segmentData; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ + feature: feature, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); + } }; /** - * @const + * @param {ol.Feature} feature Feature + * @param {ol.geom.MultiLineString} geometry Geometry. * @private - * @type {Array.<string>} */ -ol.format.OSMXML.NAMESPACE_URIS_ = [ - null -]; +ol.interaction.Snap.prototype.writeMultiLineStringGeometry_ = + function(feature, geometry) { + var lines = geometry.getCoordinates(); + var coordinates, i, ii, j, jj, segment, segmentData; + for (j = 0, jj = lines.length; j < jj; ++j) { + coordinates = lines[j]; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ + feature: feature, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); + } + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.Feature} feature Feature + * @param {ol.geom.MultiPoint} geometry Geometry. * @private */ -ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OSMXML.NAMESPACE_URIS_, { - 'nd': ol.format.OSMXML.readNd_, - 'tag': ol.format.OSMXML.readTag_ +ol.interaction.Snap.prototype.writeMultiPointGeometry_ = + function(feature, geometry) { + var points = geometry.getCoordinates(); + var coordinates, i, ii, segmentData; + for (i = 0, ii = points.length; i < ii; ++i) { + coordinates = points[i]; + segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ + feature: feature, + segment: [coordinates, coordinates] }); + this.rBush_.insert(geometry.getExtent(), segmentData); + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.Feature} feature Feature + * @param {ol.geom.MultiPolygon} geometry Geometry. * @private */ -ol.format.OSMXML.PARSERS_ = ol.xml.makeStructureNS( - ol.format.OSMXML.NAMESPACE_URIS_, { - 'node': ol.format.OSMXML.readNode_, - 'way': ol.format.OSMXML.readWay_ - }); +ol.interaction.Snap.prototype.writeMultiPolygonGeometry_ = + function(feature, geometry) { + var polygons = geometry.getCoordinates(); + var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData; + for (k = 0, kk = polygons.length; k < kk; ++k) { + rings = polygons[k]; + for (j = 0, jj = rings.length; j < jj; ++j) { + coordinates = rings[j]; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ + feature: feature, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); + } + } + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.Feature} feature Feature + * @param {ol.geom.Point} geometry Geometry. * @private */ -ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OSMXML.NAMESPACE_URIS_, { - 'tag': ol.format.OSMXML.readTag_ - }); - - -/** - * Read all features from an OSM source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.OSMXML.prototype.readFeatures; +ol.interaction.Snap.prototype.writePointGeometry_ = + function(feature, geometry) { + var coordinates = geometry.getCoordinates(); + var segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ + feature: feature, + segment: [coordinates, coordinates] + }); + this.rBush_.insert(geometry.getExtent(), segmentData); +}; /** - * @inheritDoc + * @param {ol.Feature} feature Feature + * @param {ol.geom.Polygon} geometry Geometry. + * @private */ -ol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var options = this.getReadOptions(node, opt_options); - if (node.localName == 'osm') { - var state = ol.xml.pushParseAndPop({ - nodes: {}, - features: [] - }, ol.format.OSMXML.PARSERS_, node, [options]); - if (state.features) { - return state.features; +ol.interaction.Snap.prototype.writePolygonGeometry_ = + function(feature, geometry) { + var rings = geometry.getCoordinates(); + var coordinates, i, ii, j, jj, segment, segmentData; + for (j = 0, jj = rings.length; j < jj; ++j) { + coordinates = rings[j]; + for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { + segment = coordinates.slice(i, i + 2); + segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ + feature: feature, + segment: segment + }); + this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); } } - return []; }; /** - * Read the projection from an OSM source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable + * @typedef {{ + * snapped: {boolean}, + * vertex: (ol.Coordinate|null), + * vertexPixel: (ol.Pixel|null) + * }} */ -ol.format.OSMXML.prototype.readProjection; - -goog.provide('ol.format.XLink'); +ol.interaction.Snap.ResultType; /** - * @const - * @type {string} + * @typedef {{ + * feature: ol.Feature, + * segment: Array.<ol.Coordinate> + * }} */ -ol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink'; +ol.interaction.Snap.SegmentDataType; /** - * @param {Node} node Node. - * @return {boolean|undefined} Boolean. + * Handle all pointer events events. + * @param {ol.MapBrowserEvent} evt A move event. + * @return {boolean} Pass the event to other interactions. + * @this {ol.interaction.Snap} + * @private */ -ol.format.XLink.readHref = function(node) { - return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href'); +ol.interaction.Snap.handleEvent_ = function(evt) { + var result = this.snapTo(evt.pixel, evt.coordinate, evt.map); + if (result.snapped) { + evt.coordinate = result.vertex.slice(0, 2); + evt.pixel = result.vertexPixel; + } + return ol.interaction.Pointer.handleEvent.call(this, evt); }; -goog.provide('ol.format.XML'); - -goog.require('goog.asserts'); -goog.require('ol.xml'); - - /** - * @classdesc - * Generic format for reading non-feature XML data - * - * @constructor + * @param {ol.MapBrowserPointerEvent} evt Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.Snap} + * @private */ -ol.format.XML = function() { +ol.interaction.Snap.handleUpEvent_ = function(evt) { + var featuresToUpdate = goog.object.getValues(this.pendingFeatures_); + if (featuresToUpdate.length) { + featuresToUpdate.forEach(this.updateFeature_, this); + this.pendingFeatures_ = {}; + } + return false; }; /** - * @param {Document|Node|string} source Source. - * @return {Object} + * Sort segments by distance, helper function + * @param {ol.interaction.Snap.SegmentDataType} a + * @param {ol.interaction.Snap.SegmentDataType} b + * @return {number} + * @this {ol.interaction.Snap} */ -ol.format.XML.prototype.read = function(source) { - if (ol.xml.isDocument(source)) { - return this.readFromDocument(/** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFromDocument(doc); - } else { - goog.asserts.fail(); - return null; - } +ol.interaction.Snap.sortByDistance = function(a, b) { + return ol.coordinate.squaredDistanceToSegment( + this.pixelCoordinate_, a.segment) - + ol.coordinate.squaredDistanceToSegment( + this.pixelCoordinate_, b.segment); }; +goog.provide('ol.interaction.Translate'); +goog.provide('ol.interaction.TranslateEvent'); -/** - * @param {Document} doc Document. - * @return {Object} - */ -ol.format.XML.prototype.readFromDocument = goog.abstractMethod; +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('ol.array'); +goog.require('ol.interaction.Pointer'); /** - * @param {Node} node Node. - * @return {Object} + * @enum {string} */ -ol.format.XML.prototype.readFromNode = goog.abstractMethod; - -goog.provide('ol.format.OWS'); - -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('ol.format.XLink'); -goog.require('ol.format.XML'); -goog.require('ol.format.XSD'); -goog.require('ol.xml'); +ol.interaction.TranslateEventType = { + /** + * Triggered upon feature translation start. + * @event ol.interaction.TranslateEvent#translatestart + * @api + */ + TRANSLATESTART: 'translatestart', + /** + * Triggered upon feature translation. + * @event ol.interaction.TranslateEvent#translating + * @api + */ + TRANSLATING: 'translating', + /** + * Triggered upon feature translation end. + * @event ol.interaction.TranslateEvent#translateend + * @api + */ + TRANSLATEEND: 'translateend' +}; /** + * @classdesc + * Events emitted by {@link ol.interaction.Translate} instances are instances of + * this type. + * * @constructor - * @extends {ol.format.XML} + * @extends {goog.events.Event} + * @implements {oli.interaction.TranslateEvent} + * @param {ol.interaction.TranslateEventType} type Type. + * @param {ol.Collection.<ol.Feature>} features The features translated. + * @param {ol.Coordinate} coordinate The event coordinate. */ -ol.format.OWS = function() { - goog.base(this); -}; -goog.inherits(ol.format.OWS, ol.format.XML); - +ol.interaction.TranslateEvent = function(type, features, coordinate) { -/** - * @param {Document} doc Document. - * @return {Object} OWS object. - */ -ol.format.OWS.prototype.readFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFromNode(n); - } - } - return null; -}; + goog.base(this, type); + /** + * The features being translated. + * @type {ol.Collection.<ol.Feature>} + * @api + */ + this.features = features; -/** - * @param {Node} node Node. - * @return {Object} OWS object. - */ -ol.format.OWS.prototype.readFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var owsObject = ol.xml.pushParseAndPop({}, - ol.format.OWS.PARSERS_, node, []); - return owsObject ? owsObject : null; + /** + * The coordinate of the drag event. + * @const + * @type {ol.Coordinate} + * @api + */ + this.coordinate = coordinate; }; +goog.inherits(ol.interaction.TranslateEvent, goog.events.Event); -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readAddress_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Address', - 'localName should be Address'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.ADDRESS_PARSERS_, node, objectStack); -}; - /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} + * @classdesc + * Interaction for translating (moving) features. + * + * @constructor + * @extends {ol.interaction.Pointer} + * @fires ol.interaction.TranslateEvent + * @param {olx.interaction.TranslateOptions} options Options. + * @api */ -ol.format.OWS.readAllowedValues_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'AllowedValues', - 'localName should be AllowedValues'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack); -}; +ol.interaction.Translate = function(options) { + goog.base(this, { + handleDownEvent: ol.interaction.Translate.handleDownEvent_, + handleDragEvent: ol.interaction.Translate.handleDragEvent_, + handleMoveEvent: ol.interaction.Translate.handleMoveEvent_, + handleUpEvent: ol.interaction.Translate.handleUpEvent_ + }); -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readConstraint_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Constraint', - 'localName should be Constraint'); - var name = node.getAttribute('name'); - if (!name) { - return undefined; - } - return ol.xml.pushParseAndPop({'name': name}, - ol.format.OWS.CONSTRAINT_PARSERS_, node, - objectStack); -}; + /** + * @type {string|undefined} + * @private + */ + this.previousCursor_ = undefined; -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readContactInfo_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactInfo', - 'localName should be ContactInfo'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack); -}; + /** + * The last position we translated to. + * @type {ol.Coordinate} + * @private + */ + this.lastCoordinate_ = null; -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readDcp_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'DCP', 'localName should be DCP'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.DCP_PARSERS_, node, objectStack); + /** + * @type {ol.Collection.<ol.Feature>} + * @private + */ + this.features_ = options.features !== undefined ? options.features : null; + + /** + * @type {ol.Feature} + * @private + */ + this.lastFeature_ = null; }; +goog.inherits(ol.interaction.Translate, ol.interaction.Pointer); /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} event Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.Translate} * @private - * @return {Object|undefined} */ -ol.format.OWS.readGet_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Get', 'localName should be Get'); - var href = ol.format.XLink.readHref(node); - if (!href) { - return undefined; +ol.interaction.Translate.handleDownEvent_ = function(event) { + this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map); + if (!this.lastCoordinate_ && this.lastFeature_) { + this.lastCoordinate_ = event.coordinate; + ol.interaction.Translate.handleMoveEvent_.call(this, event); + this.dispatchEvent( + new ol.interaction.TranslateEvent( + ol.interaction.TranslateEventType.TRANSLATESTART, this.features_, + event.coordinate)); + return true; } - return ol.xml.pushParseAndPop({'href': href}, - ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack); + return false; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} event Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.Translate} * @private - * @return {Object|undefined} */ -ol.format.OWS.readHttp_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP'); - return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_, - node, objectStack); +ol.interaction.Translate.handleUpEvent_ = function(event) { + if (this.lastCoordinate_) { + this.lastCoordinate_ = null; + ol.interaction.Translate.handleMoveEvent_.call(this, event); + this.dispatchEvent( + new ol.interaction.TranslateEvent( + ol.interaction.TranslateEventType.TRANSLATEEND, this.features_, + event.coordinate)); + return true; + } + return false; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserPointerEvent} event Event. + * @this {ol.interaction.Translate} * @private - * @return {Object|undefined} */ -ol.format.OWS.readOperation_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Operation', - 'localName should be Operation'); - var name = node.getAttribute('name'); - var value = ol.xml.pushParseAndPop({}, - ol.format.OWS.OPERATION_PARSERS_, node, objectStack); - if (!value) { - return undefined; - } - var object = /** @type {Object} */ - (objectStack[objectStack.length - 1]); - goog.asserts.assert(goog.isObject(object), 'object should be an Object'); - object[name] = value; +ol.interaction.Translate.handleDragEvent_ = function(event) { + if (this.lastCoordinate_) { + var newCoordinate = event.coordinate; + var deltaX = newCoordinate[0] - this.lastCoordinate_[0]; + var deltaY = newCoordinate[1] - this.lastCoordinate_[1]; + if (this.features_) { + this.features_.forEach(function(feature) { + var geom = feature.getGeometry(); + geom.translate(deltaX, deltaY); + feature.setGeometry(geom); + }); + } else if (this.lastFeature_) { + var geom = this.lastFeature_.getGeometry(); + geom.translate(deltaX, deltaY); + this.lastFeature_.setGeometry(geom); + } + + this.lastCoordinate_ = newCoordinate; + this.dispatchEvent( + new ol.interaction.TranslateEvent( + ol.interaction.TranslateEventType.TRANSLATING, this.features_, + newCoordinate)); + } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * @param {ol.MapBrowserEvent} event Event. + * @this {ol.interaction.Translate} * @private - * @return {Object|undefined} */ -ol.format.OWS.readOperationsMetadata_ = function(node, - objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'OperationsMetadata', - 'localName should be OperationsMetadata'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node, - objectStack); -}; +ol.interaction.Translate.handleMoveEvent_ = function(event) + { + var elem = event.map.getTargetElement(); + var intersectingFeature = event.map.forEachFeatureAtPixel(event.pixel, + function(feature) { + return feature; + }); + if (intersectingFeature) { + var isSelected = false; -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readPhone_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Phone', 'localName should be Phone'); - return ol.xml.pushParseAndPop({}, - ol.format.OWS.PHONE_PARSERS_, node, objectStack); -}; + if (this.features_ && + ol.array.includes(this.features_.getArray(), intersectingFeature)) { + isSelected = true; + } + this.previousCursor_ = elem.style.cursor; -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readServiceIdentification_ = function(node, - objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ServiceIdentification', - 'localName should be ServiceIdentification'); - return ol.xml.pushParseAndPop( - {}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node, - objectStack); -}; + // WebKit browsers don't support the grab icons without a prefix + elem.style.cursor = this.lastCoordinate_ ? + '-webkit-grabbing' : (isSelected ? '-webkit-grab' : 'pointer'); + // Thankfully, attempting to set the standard ones will silently fail, + // keeping the prefixed icons + elem.style.cursor = !this.lastCoordinate_ ? + 'grabbing' : (isSelected ? 'grab' : 'pointer'); -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} - */ -ol.format.OWS.readServiceContact_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ServiceContact', - 'localName should be ServiceContact'); - return ol.xml.pushParseAndPop( - {}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node, - objectStack); + } else { + elem.style.cursor = this.previousCursor_ !== undefined ? + this.previousCursor_ : ''; + this.previousCursor_ = undefined; + } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Tests to see if the given coordinates intersects any of our selected + * features. + * @param {ol.Pixel} pixel Pixel coordinate to test for intersection. + * @param {ol.Map} map Map to test the intersection on. + * @return {ol.Feature} Returns the feature found at the specified pixel + * coordinates. * @private - * @return {Object|undefined} */ -ol.format.OWS.readServiceProvider_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ServiceProvider', - 'localName should be ServiceProvider'); - return ol.xml.pushParseAndPop( - {}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node, - objectStack); +ol.interaction.Translate.prototype.featuresAtPixel_ = function(pixel, map) { + var found = null; + + var intersectingFeature = map.forEachFeatureAtPixel(pixel, + function(feature) { + return feature; + }); + + if (this.features_ && + ol.array.includes(this.features_.getArray(), intersectingFeature)) { + found = intersectingFeature; + } + + return found; }; +goog.provide('ol.layer.Heatmap'); + +goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.object'); +goog.require('ol'); +goog.require('ol.Object'); +goog.require('ol.dom'); +goog.require('ol.layer.Vector'); +goog.require('ol.math'); +goog.require('ol.render.EventType'); +goog.require('ol.style.Icon'); +goog.require('ol.style.Style'); + /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {string|undefined} + * @enum {string} */ -ol.format.OWS.readValue_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Value', 'localName should be Value'); - return ol.format.XSD.readString(node); +ol.layer.HeatmapLayerProperty = { + BLUR: 'blur', + GRADIENT: 'gradient', + RADIUS: 'radius' }; + /** - * @const - * @type {Array.<string>} - * @private + * @classdesc + * Layer for rendering vector data as a heatmap. + * Note that any property set in the options is set as a {@link ol.Object} + * property on the layer object; for example, setting `title: 'My Title'` in the + * options means that `title` is observable, and has get/set accessors. + * + * @constructor + * @extends {ol.layer.Vector} + * @fires ol.render.Event + * @param {olx.layer.HeatmapOptions=} opt_options Options. + * @api */ -ol.format.OWS.NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/ows/1.1' -]; +ol.layer.Heatmap = function(opt_options) { + var options = opt_options ? opt_options : {}; + var baseOptions = goog.object.clone(options); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'ServiceIdentification': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readServiceIdentification_), - 'ServiceProvider': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readServiceProvider_), - 'OperationsMetadata': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readOperationsMetadata_) - }); + delete baseOptions.gradient; + delete baseOptions.radius; + delete baseOptions.blur; + delete baseOptions.shadow; + delete baseOptions.weight; + goog.base(this, /** @type {olx.layer.VectorOptions} */ (baseOptions)); + /** + * @private + * @type {Uint8ClampedArray} + */ + this.gradient_ = null; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'DeliveryPoint': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'AdministrativeArea': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ElectronicMailAddress': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); + /** + * @private + * @type {number} + */ + this.shadow_ = options.shadow !== undefined ? options.shadow : 250; + /** + * @private + * @type {string|undefined} + */ + this.circleImage_ = undefined; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_) - }); + /** + * @private + * @type {Array.<Array.<ol.style.Style>>} + */ + this.styleCache_ = null; + goog.events.listen(this, + ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT), + this.handleGradientChanged_, false, this); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'AllowedValues': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readAllowedValues_) - }); + this.setGradient(options.gradient ? + options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT); + this.setBlur(options.blur !== undefined ? options.blur : 15); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_), - 'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_) - }); + this.setRadius(options.radius !== undefined ? options.radius : 8); + goog.events.listen(this, [ + ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.BLUR), + ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.RADIUS) + ], this.handleStyleChanged_, false, this); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.DCP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_) - }); + this.handleStyleChanged_(); + var weight = options.weight ? options.weight : 'weight'; + var weightFunction; + if (goog.isString(weight)) { + weightFunction = function(feature) { + return feature.get(weight); + }; + } else { + weightFunction = weight; + } + goog.asserts.assert(goog.isFunction(weightFunction), + 'weightFunction should be a function'); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.OWS.HTTP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_), - 'Post': undefined // TODO - }); + this.setStyle(goog.bind(function(feature, resolution) { + goog.asserts.assert(this.styleCache_, 'this.styleCache_ expected'); + goog.asserts.assert(this.circleImage_ !== undefined, + 'this.circleImage_ should be defined'); + var weight = weightFunction(feature); + var opacity = weight !== undefined ? ol.math.clamp(weight, 0, 1) : 1; + // cast to 8 bits + var index = (255 * opacity) | 0; + var style = this.styleCache_[index]; + if (!style) { + style = [ + new ol.style.Style({ + image: new ol.style.Icon({ + opacity: opacity, + src: this.circleImage_ + }) + }) + ]; + this.styleCache_[index] = style; + } + return style; + }, this)); + + // For performance reasons, don't sort the features before rendering. + // The render order is not relevant for a heatmap representation. + this.setRenderOrder(null); + + goog.events.listen(this, ol.render.EventType.RENDER, + this.handleRender_, false, this); + +}; +goog.inherits(ol.layer.Heatmap, ol.layer.Vector); /** * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @type {Array.<string>} */ -ol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_) - }); +ol.layer.Heatmap.DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00']; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {Array.<string>} colors + * @return {Uint8ClampedArray} * @private */ -ol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Operation': ol.format.OWS.readOperation_ - }); +ol.layer.Heatmap.createGradient_ = function(colors) { + var width = 1; + var height = 256; + var context = ol.dom.createCanvasContext2D(width, height); + + var gradient = context.createLinearGradient(0, 0, width, height); + var step = 1 / (colors.length - 1); + for (var i = 0, ii = colors.length; i < ii; ++i) { + gradient.addColorStop(i * step, colors[i]); + } + + context.fillStyle = gradient; + context.fillRect(0, 0, width, height); + + return context.getImageData(0, 0, width, height).data; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @return {string} * @private */ -ol.format.OWS.PHONE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); +ol.layer.Heatmap.prototype.createCircle_ = function() { + var radius = this.getRadius(); + var blur = this.getBlur(); + goog.asserts.assert(radius !== undefined && blur !== undefined, + 'radius and blur should be defined'); + var halfSize = radius + blur + 1; + var size = 2 * halfSize; + var context = ol.dom.createCanvasContext2D(size, size); + context.shadowOffsetX = context.shadowOffsetY = this.shadow_; + context.shadowBlur = blur; + context.shadowColor = '#000'; + context.beginPath(); + var center = halfSize - this.shadow_; + context.arc(center, center, radius, 0, Math.PI * 2, true); + context.fill(); + return context.canvas.toDataURL(); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Return the blur size in pixels. + * @return {number} Blur size in pixels. + * @api + * @observable */ -ol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Constraint': ol.xml.makeObjectPropertyPusher( - ol.format.OWS.readConstraint_) - }); +ol.layer.Heatmap.prototype.getBlur = function() { + return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.BLUR)); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Return the gradient colors as array of strings. + * @return {Array.<string>} Colors. + * @api + * @observable */ -ol.format.OWS.SERVICE_CONTACT_PARSERS_ = - ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'IndividualName': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ContactInfo': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readContactInfo_) - }); +ol.layer.Heatmap.prototype.getGradient = function() { + return /** @type {Array.<string>} */ ( + this.get(ol.layer.HeatmapLayerProperty.GRADIENT)); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Return the size of the radius in pixels. + * @return {number} Radius size in pixel. + * @api + * @observable */ -ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ = - ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ServiceTypeVersion': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); +ol.layer.Heatmap.prototype.getRadius = function() { + return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.RADIUS)); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.OWS.SERVICE_PROVIDER_PARSERS_ = - ol.xml.makeStructureNS( - ol.format.OWS.NAMESPACE_URIS_, { - 'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref), - 'ServiceContact': ol.xml.makeObjectPropertySetter( - ol.format.OWS.readServiceContact_) - }); +ol.layer.Heatmap.prototype.handleGradientChanged_ = function() { + this.gradient_ = ol.layer.Heatmap.createGradient_(this.getGradient()); +}; -goog.provide('ol.geom.flat.flip'); -goog.require('goog.asserts'); +/** + * @private + */ +ol.layer.Heatmap.prototype.handleStyleChanged_ = function() { + this.circleImage_ = this.createCircle_(); + this.styleCache_ = new Array(256); + this.changed(); +}; /** - * @param {Array.<number>} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {Array.<number>=} opt_dest Destination. - * @param {number=} opt_destOffset Destination offset. - * @return {Array.<number>} Flat coordinates. + * @param {ol.render.Event} event Post compose event + * @private */ -ol.geom.flat.flip.flipXY = - function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) { - var dest, destOffset; - if (opt_dest !== undefined) { - dest = opt_dest; - destOffset = opt_destOffset !== undefined ? opt_destOffset : 0; - } else { - goog.asserts.assert(opt_destOffset === undefined, - 'opt_destOffSet should be defined'); - dest = []; - destOffset = 0; - } - var j, k; - for (j = offset; j < end; ) { - var x = flatCoordinates[j++]; - dest[destOffset++] = flatCoordinates[j++]; - dest[destOffset++] = x; - for (k = 2; k < stride; ++k) { - dest[destOffset++] = flatCoordinates[j++]; +ol.layer.Heatmap.prototype.handleRender_ = function(event) { + goog.asserts.assert(event.type == ol.render.EventType.RENDER, + 'event.type should be RENDER'); + goog.asserts.assert(this.gradient_, 'this.gradient_ expected'); + var context = event.context; + var canvas = context.canvas; + var image = context.getImageData(0, 0, canvas.width, canvas.height); + var view8 = image.data; + var i, ii, alpha; + for (i = 0, ii = view8.length; i < ii; i += 4) { + alpha = view8[i + 3] * 4; + if (alpha) { + view8[i] = this.gradient_[alpha]; + view8[i + 1] = this.gradient_[alpha + 1]; + view8[i + 2] = this.gradient_[alpha + 2]; } } - dest.length = destOffset; - return dest; + context.putImageData(image, 0, 0); }; -goog.provide('ol.format.Polyline'); - -goog.require('goog.asserts'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.TextFeature'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.flip'); -goog.require('ol.geom.flat.inflate'); -goog.require('ol.proj'); +/** + * Set the blur size in pixels. + * @param {number} blur Blur size in pixels. + * @api + * @observable + */ +ol.layer.Heatmap.prototype.setBlur = function(blur) { + this.set(ol.layer.HeatmapLayerProperty.BLUR, blur); +}; /** - * @classdesc - * Feature format for reading and writing data in the Encoded - * Polyline Algorithm Format. - * - * @constructor - * @extends {ol.format.TextFeature} - * @param {olx.format.PolylineOptions=} opt_options - * Optional configuration object. - * @api stable + * Set the gradient colors as array of strings. + * @param {Array.<string>} colors Gradient. + * @api + * @observable */ -ol.format.Polyline = function(opt_options) { +ol.layer.Heatmap.prototype.setGradient = function(colors) { + this.set(ol.layer.HeatmapLayerProperty.GRADIENT, colors); +}; - var options = opt_options ? opt_options : {}; - goog.base(this); +/** + * Set the size of the radius in pixels. + * @param {number} radius Radius size in pixel. + * @api + * @observable + */ +ol.layer.Heatmap.prototype.setRadius = function(radius) { + this.set(ol.layer.HeatmapLayerProperty.RADIUS, radius); +}; - /** - * @inheritDoc - */ - this.defaultDataProjection = ol.proj.get('EPSG:4326'); +goog.provide('ol.raster.Operation'); +goog.provide('ol.raster.OperationType'); - /** - * @private - * @type {number} - */ - this.factor_ = options.factor ? options.factor : 1e5; - /** - * @private - * @type {ol.geom.GeometryLayout} - */ - this.geometryLayout_ = options.geometryLayout ? - options.geometryLayout : ol.geom.GeometryLayout.XY; +/** + * Raster operation type. Supported values are `'pixel'` and `'image'`. + * @enum {string} + * @api + */ +ol.raster.OperationType = { + PIXEL: 'pixel', + IMAGE: 'image' }; -goog.inherits(ol.format.Polyline, ol.format.TextFeature); /** - * Encode a list of n-dimensional points and return an encoded string - * - * Attention: This function will modify the passed array! + * A function that takes an array of input data, performs some operation, and + * returns an array of ouput data. For `'pixel'` type operations, functions + * will be called with an array of {@link ol.raster.Pixel} data and should + * return an array of the same. For `'image'` type operations, functions will + * be called with an array of {@link ImageData + * https://developer.mozilla.org/en-US/docs/Web/API/ImageData} and should return + * an array of the same. The operations are called with a second "data" + * argument, which can be used for storage. The data object is accessible + * from raster events, where it can be initialized in "beforeoperations" and + * accessed again in "afteroperations". * - * @param {Array.<number>} numbers A list of n-dimensional points. - * @param {number} stride The number of dimension of the points in the list. - * @param {number=} opt_factor The factor by which the numbers will be - * multiplied. The remaining decimal places will get rounded away. - * Default is `1e5`. - * @return {string} The encoded string. + * @typedef {function((Array.<ol.raster.Pixel>|Array.<ImageData>), Object): + * (Array.<ol.raster.Pixel>|Array.<ImageData>)} * @api */ -ol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var d; - - var lastNumbers = new Array(stride); - for (d = 0; d < stride; ++d) { - lastNumbers[d] = 0; - } +ol.raster.Operation; - var i, ii; - for (i = 0, ii = numbers.length; i < ii;) { - for (d = 0; d < stride; ++d, ++i) { - var num = numbers[i]; - var delta = num - lastNumbers[d]; - lastNumbers[d] = num; +goog.provide('ol.raster.Pixel'); - numbers[i] = delta; - } - } - return ol.format.Polyline.encodeFloats(numbers, factor); -}; +/** + * An array of numbers representing pixel values. + * @typedef {Array.<number>} ol.raster.Pixel + * @api + */ +ol.raster.Pixel; +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /** - * Decode a list of n-dimensional points from an encoded string + * @fileoverview A utility to load JavaScript files via DOM script tags. + * Refactored from goog.net.Jsonp. Works cross-domain. * - * @param {string} encoded An encoded string. - * @param {number} stride The number of dimension of the points in the - * encoded string. - * @param {number=} opt_factor The factor by which the resulting numbers will - * be divided. Default is `1e5`. - * @return {Array.<number>} A list of n-dimensional points. - * @api */ -ol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var d; - - /** @type {Array.<number>} */ - var lastNumbers = new Array(stride); - for (d = 0; d < stride; ++d) { - lastNumbers[d] = 0; - } - var numbers = ol.format.Polyline.decodeFloats(encoded, factor); +goog.provide('goog.net.jsloader'); +goog.provide('goog.net.jsloader.Error'); +goog.provide('goog.net.jsloader.ErrorCode'); +goog.provide('goog.net.jsloader.Options'); - var i, ii; - for (i = 0, ii = numbers.length; i < ii;) { - for (d = 0; d < stride; ++d, ++i) { - lastNumbers[d] += numbers[i]; +goog.require('goog.array'); +goog.require('goog.async.Deferred'); +goog.require('goog.debug.Error'); +goog.require('goog.dom'); +goog.require('goog.dom.TagName'); +goog.require('goog.object'); - numbers[i] = lastNumbers[d]; - } - } - return numbers; -}; +/** + * The name of the property of goog.global under which the JavaScript + * verification object is stored by the loaded script. + * @private {string} + */ +goog.net.jsloader.GLOBAL_VERIFY_OBJS_ = 'closure_verification'; /** - * Encode a list of floating point numbers and return an encoded string - * - * Attention: This function will modify the passed array! - * - * @param {Array.<number>} numbers A list of floating point numbers. - * @param {number=} opt_factor The factor by which the numbers will be - * multiplied. The remaining decimal places will get rounded away. - * Default is `1e5`. - * @return {string} The encoded string. - * @api + * The default length of time, in milliseconds, we are prepared to wait for a + * load request to complete. + * @type {number} */ -ol.format.Polyline.encodeFloats = function(numbers, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - numbers[i] = Math.round(numbers[i] * factor); - } - - return ol.format.Polyline.encodeSignedIntegers(numbers); -}; +goog.net.jsloader.DEFAULT_TIMEOUT = 5000; /** - * Decode a list of floating point numbers from an encoded string + * Optional parameters for goog.net.jsloader.send. + * timeout: The length of time, in milliseconds, we are prepared to wait + * for a load request to complete. Default it 5 seconds. + * document: The HTML document under which to load the JavaScript. Default is + * the current document. + * cleanupWhenDone: If true clean up the script tag after script completes to + * load. This is important if you just want to read data from the JavaScript + * and then throw it away. Default is false. + * attributes: Additional attributes to set on the script tag. * - * @param {string} encoded An encoded string. - * @param {number=} opt_factor The factor by which the result will be divided. - * Default is `1e5`. - * @return {Array.<number>} A list of floating point numbers. - * @api + * @typedef {{ + * timeout: (number|undefined), + * document: (HTMLDocument|undefined), + * cleanupWhenDone: (boolean|undefined), + * attributes: (!Object<string, string>|undefined) + * }} */ -ol.format.Polyline.decodeFloats = function(encoded, opt_factor) { - var factor = opt_factor ? opt_factor : 1e5; - var numbers = ol.format.Polyline.decodeSignedIntegers(encoded); - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - numbers[i] /= factor; - } - return numbers; -}; +goog.net.jsloader.Options; /** - * Encode a list of signed integers and return an encoded string - * - * Attention: This function will modify the passed array! - * - * @param {Array.<number>} numbers A list of signed integers. - * @return {string} The encoded string. + * Scripts (URIs) waiting to be loaded. + * @private {!Array<string>} */ -ol.format.Polyline.encodeSignedIntegers = function(numbers) { - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - var num = numbers[i]; - numbers[i] = (num < 0) ? ~(num << 1) : (num << 1); - } - return ol.format.Polyline.encodeUnsignedIntegers(numbers); -}; +goog.net.jsloader.scriptsToLoad_ = []; /** - * Decode a list of signed integers from an encoded string - * - * @param {string} encoded An encoded string. - * @return {Array.<number>} A list of signed integers. + * The deferred result of loading the URIs in scriptsToLoad_. + * We need to return this to a caller that wants to load URIs while + * a deferred is already working on them. + * @private {!goog.async.Deferred<null>} */ -ol.format.Polyline.decodeSignedIntegers = function(encoded) { - var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded); - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - var num = numbers[i]; - numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); - } - return numbers; -}; +goog.net.jsloader.scriptLoadingDeferred_; /** - * Encode a list of unsigned integers and return an encoded string + * Loads and evaluates the JavaScript files at the specified URIs, guaranteeing + * the order of script loads. * - * @param {Array.<number>} numbers A list of unsigned integers. - * @return {string} The encoded string. + * Because we have to load the scripts in serial (load script 1, exec script 1, + * load script 2, exec script 2, and so on), this will be slower than doing + * the network fetches in parallel. + * + * If you need to load a large number of scripts but dependency order doesn't + * matter, you should just call goog.net.jsloader.load N times. + * + * If you need to load a large number of scripts on the same domain, + * you may want to use goog.module.ModuleLoader. + * + * @param {Array<string>} uris The URIs to load. + * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See + * goog.net.jsloader.options documentation for details. + * @return {!goog.async.Deferred} The deferred result, that may be used to add + * callbacks */ -ol.format.Polyline.encodeUnsignedIntegers = function(numbers) { - var encoded = ''; - var i, ii; - for (i = 0, ii = numbers.length; i < ii; ++i) { - encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]); +goog.net.jsloader.loadMany = function(uris, opt_options) { + // Loading the scripts in serial introduces asynchronosity into the flow. + // Therefore, there are race conditions where client A can kick off the load + // sequence for client B, even though client A's scripts haven't all been + // loaded yet. + // + // To work around this issue, all module loads share a queue. + if (!uris.length) { + return goog.async.Deferred.succeed(null); } - return encoded; -}; + var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length; + goog.array.extend(goog.net.jsloader.scriptsToLoad_, uris); + if (isAnotherModuleLoading) { + // jsloader is still loading some other scripts. + // In order to prevent the race condition noted above, we just add + // these URIs to the end of the scripts' queue and return the deferred + // result of the ongoing script load, so the caller knows when they + // finish loading. + return goog.net.jsloader.scriptLoadingDeferred_; + } -/** - * Decode a list of unsigned integers from an encoded string - * - * @param {string} encoded An encoded string. - * @return {Array.<number>} A list of unsigned integers. - */ -ol.format.Polyline.decodeUnsignedIntegers = function(encoded) { - var numbers = []; - var current = 0; - var shift = 0; - var i, ii; - for (i = 0, ii = encoded.length; i < ii; ++i) { - var b = encoded.charCodeAt(i) - 63; - current |= (b & 0x1f) << shift; - if (b < 0x20) { - numbers.push(current); - current = 0; - shift = 0; - } else { - shift += 5; + uris = goog.net.jsloader.scriptsToLoad_; + var popAndLoadNextScript = function() { + var uri = uris.shift(); + var deferred = goog.net.jsloader.load(uri, opt_options); + if (uris.length) { + deferred.addBoth(popAndLoadNextScript); } - } - return numbers; + return deferred; + }; + goog.net.jsloader.scriptLoadingDeferred_ = popAndLoadNextScript(); + return goog.net.jsloader.scriptLoadingDeferred_; }; /** - * Encode one single unsigned integer and return an encoded string + * Loads and evaluates a JavaScript file. + * When the script loads, a user callback is called. + * It is the client's responsibility to verify that the script ran successfully. * - * @param {number} num Unsigned integer that should be encoded. - * @return {string} The encoded string. + * @param {string} uri The URI of the JavaScript. + * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See + * goog.net.jsloader.Options documentation for details. + * @return {!goog.async.Deferred} The deferred result, that may be used to add + * callbacks and/or cancel the transmission. + * The error callback will be called with a single goog.net.jsloader.Error + * parameter. */ -ol.format.Polyline.encodeUnsignedInteger = function(num) { - var value, encoded = ''; - while (num >= 0x20) { - value = (0x20 | (num & 0x1f)) + 63; - encoded += String.fromCharCode(value); - num >>= 5; +goog.net.jsloader.load = function(uri, opt_options) { + var options = opt_options || {}; + var doc = options.document || document; + + var script = goog.dom.createElement(goog.dom.TagName.SCRIPT); + var request = {script_: script, timeout_: undefined}; + var deferred = new goog.async.Deferred(goog.net.jsloader.cancel_, request); + + // Set a timeout. + var timeout = null; + var timeoutDuration = goog.isDefAndNotNull(options.timeout) ? + options.timeout : goog.net.jsloader.DEFAULT_TIMEOUT; + if (timeoutDuration > 0) { + timeout = window.setTimeout(function() { + goog.net.jsloader.cleanup_(script, true); + deferred.errback(new goog.net.jsloader.Error( + goog.net.jsloader.ErrorCode.TIMEOUT, + 'Timeout reached for loading script ' + uri)); + }, timeoutDuration); + request.timeout_ = timeout; } - value = num + 63; - encoded += String.fromCharCode(value); - return encoded; -}; + // Hang the user callback to be called when the script completes to load. + // NOTE(user): This callback will be called in IE even upon error. In any + // case it is the client's responsibility to verify that the script ran + // successfully. + script.onload = script.onreadystatechange = function() { + if (!script.readyState || script.readyState == 'loaded' || + script.readyState == 'complete') { + var removeScriptNode = options.cleanupWhenDone || false; + goog.net.jsloader.cleanup_(script, removeScriptNode, timeout); + deferred.callback(null); + } + }; -/** - * Read the feature from the Polyline source. The coordinates are assumed to be - * in two dimensions and in latitude, longitude order. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.Polyline.prototype.readFeature; + // Add an error callback. + // NOTE(user): Not supported in IE. + script.onerror = function() { + goog.net.jsloader.cleanup_(script, true, timeout); + deferred.errback(new goog.net.jsloader.Error( + goog.net.jsloader.ErrorCode.LOAD_ERROR, + 'Error while loading script ' + uri)); + }; + var properties = options.attributes || {}; + goog.object.extend(properties, { + 'type': 'text/javascript', + 'charset': 'UTF-8', + // NOTE(user): Safari never loads the script if we don't set + // the src attribute before appending. + 'src': uri + }); + goog.dom.setProperties(script, properties); + var scriptParent = goog.net.jsloader.getScriptParentElement_(doc); + scriptParent.appendChild(script); -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) { - var geometry = this.readGeometryFromText(text, opt_options); - return new ol.Feature(geometry); + return deferred; }; /** - * Read the feature from the source. As Polyline sources contain a single - * feature, this will return the feature in an array. + * Loads a JavaScript file and verifies it was evaluated successfully, using a + * verification object. + * The verification object is set by the loaded JavaScript at the end of the + * script. + * We verify this object was set and return its value in the success callback. + * If the object is not defined we trigger an error callback. * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable + * @param {string} uri The URI of the JavaScript. + * @param {string} verificationObjName The name of the verification object that + * the loaded script should set. + * @param {goog.net.jsloader.Options} options Optional parameters. See + * goog.net.jsloader.Options documentation for details. + * @return {!goog.async.Deferred} The deferred result, that may be used to add + * callbacks and/or cancel the transmission. + * The success callback will be called with a single parameter containing + * the value of the verification object. + * The error callback will be called with a single goog.net.jsloader.Error + * parameter. */ -ol.format.Polyline.prototype.readFeatures; - +goog.net.jsloader.loadAndVerify = function(uri, verificationObjName, options) { + // Define the global objects variable. + if (!goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]) { + goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_] = {}; + } + var verifyObjs = goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]; -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.readFeaturesFromText = - function(text, opt_options) { - var feature = this.readFeatureFromText(text, opt_options); - return [feature]; -}; + // Verify that the expected object does not exist yet. + if (goog.isDef(verifyObjs[verificationObjName])) { + // TODO(user): Error or reset variable? + return goog.async.Deferred.fail(new goog.net.jsloader.Error( + goog.net.jsloader.ErrorCode.VERIFY_OBJECT_ALREADY_EXISTS, + 'Verification object ' + verificationObjName + ' already defined.')); + } + // Send request to load the JavaScript. + var sendDeferred = goog.net.jsloader.load(uri, options); -/** - * Read the geometry from the source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api stable - */ -ol.format.Polyline.prototype.readGeometry; + // Create a deferred object wrapping the send result. + var deferred = new goog.async.Deferred( + goog.bind(sendDeferred.cancel, sendDeferred)); + // Call user back with object that was set by the script. + sendDeferred.addCallback(function() { + var result = verifyObjs[verificationObjName]; + if (goog.isDef(result)) { + deferred.callback(result); + delete verifyObjs[verificationObjName]; + } else { + // Error: script was not loaded properly. + deferred.errback(new goog.net.jsloader.Error( + goog.net.jsloader.ErrorCode.VERIFY_ERROR, + 'Script ' + uri + ' loaded, but verification object ' + + verificationObjName + ' was not defined.')); + } + }); -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.readGeometryFromText = - function(text, opt_options) { - var stride = ol.geom.SimpleGeometry.getStrideForLayout(this.geometryLayout_); - var flatCoordinates = ol.format.Polyline.decodeDeltas( - text, stride, this.factor_); - ol.geom.flat.flip.flipXY( - flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates); - var coordinates = ol.geom.flat.inflate.coordinates( - flatCoordinates, 0, flatCoordinates.length, stride); + // Pass error to new deferred object. + sendDeferred.addErrback(function(error) { + if (goog.isDef(verifyObjs[verificationObjName])) { + delete verifyObjs[verificationObjName]; + } + deferred.errback(error); + }); - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions( - new ol.geom.LineString(coordinates, this.geometryLayout_), false, - this.adaptOptions(opt_options))); + return deferred; }; /** - * Read the projection from a Polyline source. + * Gets the DOM element under which we should add new script elements. + * How? Take the first head element, and if not found take doc.documentElement, + * which always exists. * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {ol.proj.Projection} Projection. - * @api stable - */ -ol.format.Polyline.prototype.readProjection; - - -/** - * @inheritDoc + * @param {!HTMLDocument} doc The relevant document. + * @return {!Element} The script parent element. + * @private */ -ol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) { - var geometry = feature.getGeometry(); - if (geometry) { - return this.writeGeometryText(geometry, opt_options); +goog.net.jsloader.getScriptParentElement_ = function(doc) { + var headElements = doc.getElementsByTagName(goog.dom.TagName.HEAD); + if (!headElements || goog.array.isEmpty(headElements)) { + return doc.documentElement; } else { - goog.asserts.fail('geometry needs to be defined'); - return ''; + return headElements[0]; } }; /** - * @inheritDoc + * Cancels a given request. + * @this {{script_: Element, timeout_: number}} The request context. + * @private */ -ol.format.Polyline.prototype.writeFeaturesText = - function(features, opt_options) { - goog.asserts.assert(features.length == 1, - 'features array should have 1 item'); - return this.writeFeatureText(features[0], opt_options); +goog.net.jsloader.cancel_ = function() { + var request = this; + if (request && request.script_) { + var scriptNode = request.script_; + if (scriptNode && scriptNode.tagName == goog.dom.TagName.SCRIPT) { + goog.net.jsloader.cleanup_(scriptNode, true, request.timeout_); + } + } }; /** - * Write a single geometry in Polyline format. + * Removes the script node and the timeout. * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} Geometry. - * @api stable + * @param {Node} scriptNode The node to be cleaned up. + * @param {boolean} removeScriptNode If true completely remove the script node. + * @param {?number=} opt_timeout The timeout handler to cleanup. + * @private */ -ol.format.Polyline.prototype.writeGeometry; +goog.net.jsloader.cleanup_ = function(scriptNode, removeScriptNode, + opt_timeout) { + if (goog.isDefAndNotNull(opt_timeout)) { + goog.global.clearTimeout(opt_timeout); + } + scriptNode.onload = goog.nullFunction; + scriptNode.onerror = goog.nullFunction; + scriptNode.onreadystatechange = goog.nullFunction; -/** - * @inheritDoc - */ -ol.format.Polyline.prototype.writeGeometryText = - function(geometry, opt_options) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - geometry = /** @type {ol.geom.LineString} */ - (ol.format.Feature.transformWithOptions( - geometry, true, this.adaptOptions(opt_options))); - var flatCoordinates = geometry.getFlatCoordinates(); - var stride = geometry.getStride(); - ol.geom.flat.flip.flipXY( - flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates); - return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_); + // Do this after a delay (removing the script node of a running script can + // confuse older IEs). + if (removeScriptNode) { + window.setTimeout(function() { + goog.dom.removeNode(scriptNode); + }, 0); + } }; -goog.provide('ol.format.TopoJSON'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.JSONFeature'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.proj'); +/** + * Possible error codes for jsloader. + * @enum {number} + */ +goog.net.jsloader.ErrorCode = { + LOAD_ERROR: 0, + TIMEOUT: 1, + VERIFY_ERROR: 2, + VERIFY_OBJECT_ALREADY_EXISTS: 3 +}; /** - * @classdesc - * Feature format for reading data in the TopoJSON format. + * A jsloader error. * + * @param {goog.net.jsloader.ErrorCode} code The error code. + * @param {string=} opt_message Additional message. * @constructor - * @extends {ol.format.JSONFeature} - * @param {olx.format.TopoJSONOptions=} opt_options Options. - * @api stable + * @extends {goog.debug.Error} + * @final */ -ol.format.TopoJSON = function(opt_options) { - - var options = opt_options ? opt_options : {}; - - goog.base(this); +goog.net.jsloader.Error = function(code, opt_message) { + var msg = 'Jsloader error (code #' + code + ')'; + if (opt_message) { + msg += ': ' + opt_message; + } + goog.net.jsloader.Error.base(this, 'constructor', msg); /** - * @inheritDoc + * The code for this error. + * + * @type {goog.net.jsloader.ErrorCode} */ - this.defaultDataProjection = ol.proj.get( - options.defaultDataProjection ? - options.defaultDataProjection : 'EPSG:4326'); - + this.code = code; }; -goog.inherits(ol.format.TopoJSON, ol.format.JSONFeature); - +goog.inherits(goog.net.jsloader.Error, goog.debug.Error); -/** - * @const {Array.<string>} - * @private - */ -ol.format.TopoJSON.EXTENSIONS_ = ['.topojson']; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// The original file lives here: http://go/cross_domain_channel.js /** - * Concatenate arcs into a coordinate array. - * @param {Array.<number>} indices Indices of arcs to concatenate. Negative - * values indicate arcs need to be reversed. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already - * transformed). - * @return {Array.<ol.Coordinate>} Coordinates array. - * @private + * @fileoverview Implements a cross-domain communication channel. A + * typical web page is prevented by browser security from sending + * request, such as a XMLHttpRequest, to other servers than the ones + * from which it came. The Jsonp class provides a workaround by + * using dynamically generated script tags. Typical usage:. + * + * var jsonp = new goog.net.Jsonp(new goog.Uri('http://my.host.com/servlet')); + * var payload = { 'foo': 1, 'bar': true }; + * jsonp.send(payload, function(reply) { alert(reply) }); + * + * This script works in all browsers that are currently supported by + * the Google Maps API, which is IE 6.0+, Firefox 0.8+, Safari 1.2.4+, + * Netscape 7.1+, Mozilla 1.4+, Opera 8.02+. + * */ -ol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) { - /** @type {Array.<ol.Coordinate>} */ - var coordinates = []; - var index, arc; - var i, ii; - var j, jj; - for (i = 0, ii = indices.length; i < ii; ++i) { - index = indices[i]; - if (i > 0) { - // splicing together arcs, discard last point - coordinates.pop(); - } - if (index >= 0) { - // forward arc - arc = arcs[index]; - } else { - // reverse arc - arc = arcs[~index].slice().reverse(); - } - coordinates.push.apply(coordinates, arc); - } - // provide fresh copies of coordinate arrays - for (j = 0, jj = coordinates.length; j < jj; ++j) { - coordinates[j] = coordinates[j].slice(); - } - return coordinates; -}; +goog.provide('goog.net.Jsonp'); -/** - * Create a point from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @return {ol.geom.Point} Geometry. - * @private - */ -ol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) { - var coordinates = object.coordinates; - if (scale && translate) { - ol.format.TopoJSON.transformVertex_(coordinates, scale, translate); - } - return new ol.geom.Point(coordinates); -}; +goog.require('goog.Uri'); +goog.require('goog.net.jsloader'); +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// This class allows us (Google) to send data from non-Google and thus +// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return +// anything sensitive, such as session or cookie specific data. Return +// only data that you want parties external to Google to have. Also +// NEVER use this method to send data from web pages to untrusted +// servers, or redirects to unknown servers (www.google.com/cache, +// /q=xx&btnl, /url, www.googlepages.com, etc.) +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -/** - * Create a multi-point from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @return {ol.geom.MultiPoint} Geometry. - * @private - */ -ol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale, - translate) { - var coordinates = object.coordinates; - var i, ii; - if (scale && translate) { - for (i = 0, ii = coordinates.length; i < ii; ++i) { - ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate); - } - } - return new ol.geom.MultiPoint(coordinates); -}; /** - * Create a linestring from a TopoJSON geometry object. + * Creates a new cross domain channel that sends data to the specified + * host URL. By default, if no reply arrives within 5s, the channel + * assumes the call failed to complete successfully. * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.LineString} Geometry. - * @private + * @param {goog.Uri|string} uri The Uri of the server side code that receives + * data posted through this channel (e.g., + * "http://maps.google.com/maps/geo"). + * + * @param {string=} opt_callbackParamName The parameter name that is used to + * specify the callback. Defaults to "callback". + * + * @constructor + * @final */ -ol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) { - var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs); - return new ol.geom.LineString(coordinates); -}; +goog.net.Jsonp = function(uri, opt_callbackParamName) { + /** + * The uri_ object will be used to encode the payload that is sent to the + * server. + * @type {goog.Uri} + * @private + */ + this.uri_ = new goog.Uri(uri); + /** + * This is the callback parameter name that is added to the uri. + * @type {string} + * @private + */ + this.callbackParamName_ = opt_callbackParamName ? + opt_callbackParamName : 'callback'; -/** - * Create a multi-linestring from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.MultiLineString} Geometry. - * @private - */ -ol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) { - var coordinates = []; - var i, ii; - for (i = 0, ii = object.arcs.length; i < ii; ++i) { - coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs); - } - return new ol.geom.MultiLineString(coordinates); + /** + * The length of time, in milliseconds, this channel is prepared + * to wait for for a request to complete. The default value is 5 seconds. + * @type {number} + * @private + */ + this.timeout_ = 5000; }; /** - * Create a polygon from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.Polygon} Geometry. - * @private + * The name of the property of goog.global under which the callback is + * stored. */ -ol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) { - var coordinates = []; - var i, ii; - for (i = 0, ii = object.arcs.length; i < ii; ++i) { - coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs); - } - return new ol.geom.Polygon(coordinates); -}; +goog.net.Jsonp.CALLBACKS = '_callbacks_'; /** - * Create a multi-polygon from a TopoJSON geometry object. - * - * @param {TopoJSONGeometry} object TopoJSON object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @return {ol.geom.MultiPolygon} Geometry. + * Used to generate unique callback IDs. The counter must be global because + * all channels share a common callback object. * @private */ -ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) { - var coordinates = []; - var polyArray, ringCoords, j, jj; - var i, ii; - for (i = 0, ii = object.arcs.length; i < ii; ++i) { - // for each polygon - polyArray = object.arcs[i]; - ringCoords = []; - for (j = 0, jj = polyArray.length; j < jj; ++j) { - // for each ring - ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs); - } - coordinates[i] = ringCoords; - } - return new ol.geom.MultiPolygon(coordinates); -}; +goog.net.Jsonp.scriptCounter_ = 0; /** - * @inheritDoc + * Sets the length of time, in milliseconds, this channel is prepared + * to wait for for a request to complete. If the call is not competed + * within the set time span, it is assumed to have failed. To wait + * indefinitely for a request to complete set the timout to a negative + * number. + * + * @param {number} timeout The length of time before calls are + * interrupted. */ -ol.format.TopoJSON.prototype.getExtensions = function() { - return ol.format.TopoJSON.EXTENSIONS_; +goog.net.Jsonp.prototype.setRequestTimeout = function(timeout) { + this.timeout_ = timeout; }; /** - * Create features from a TopoJSON GeometryCollection object. + * Returns the current timeout value, in milliseconds. * - * @param {TopoJSONGeometryCollection} collection TopoJSON Geometry - * object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Array of features. - * @private - */ -ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function( - collection, arcs, scale, translate, opt_options) { - var geometries = collection.geometries; - var features = []; - var i, ii; - for (i = 0, ii = geometries.length; i < ii; ++i) { - features[i] = ol.format.TopoJSON.readFeatureFromGeometry_( - geometries[i], arcs, scale, translate, opt_options); - } - return features; + * @return {number} The timeout value. + */ +goog.net.Jsonp.prototype.getRequestTimeout = function() { + return this.timeout_; }; /** - * Create a feature from a TopoJSON geometry object. + * Sends the given payload to the URL specified at the construction + * time. The reply is delivered to the given replyCallback. If the + * errorCallback is specified and the reply does not arrive within the + * timeout period set on this channel, the errorCallback is invoked + * with the original payload. * - * @param {TopoJSONGeometry} object TopoJSON geometry object. - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @private + * If no reply callback is specified, then the response is expected to + * consist of calls to globally registered functions. No &callback= + * URL parameter will be sent in the request, and the script element + * will be cleaned up after the timeout. + * + * @param {Object=} opt_payload Name-value pairs. If given, these will be + * added as parameters to the supplied URI as GET parameters to the + * given server URI. + * + * @param {Function=} opt_replyCallback A function expecting one + * argument, called when the reply arrives, with the response data. + * + * @param {Function=} opt_errorCallback A function expecting one + * argument, called on timeout, with the payload (if given), otherwise + * null. + * + * @param {string=} opt_callbackParamValue Value to be used as the + * parameter value for the callback parameter (callbackParamName). + * To be used when the value needs to be fixed by the client for a + * particular request, to make use of the cached responses for the request. + * NOTE: If multiple requests are made with the same + * opt_callbackParamValue, only the last call will work whenever the + * response comes back. + * + * @return {!Object} A request descriptor that may be used to cancel this + * transmission, or null, if the message may not be cancelled. */ -ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs, - scale, translate, opt_options) { - var geometry; - var type = object.type; - var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type]; - goog.asserts.assert(geometryReader, 'geometryReader should be defined'); - if ((type === 'Point') || (type === 'MultiPoint')) { - geometry = geometryReader(object, scale, translate); - } else { - geometry = geometryReader(object, arcs); +goog.net.Jsonp.prototype.send = function(opt_payload, + opt_replyCallback, + opt_errorCallback, + opt_callbackParamValue) { + + var payload = opt_payload || null; + + var id = opt_callbackParamValue || + '_' + (goog.net.Jsonp.scriptCounter_++).toString(36) + + goog.now().toString(36); + + if (!goog.global[goog.net.Jsonp.CALLBACKS]) { + goog.global[goog.net.Jsonp.CALLBACKS] = {}; } - var feature = new ol.Feature(); - feature.setGeometry(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, false, opt_options))); - if (object.id !== undefined) { - feature.setId(object.id); + + // Create a new Uri object onto which this payload will be added + var uri = this.uri_.clone(); + if (payload) { + goog.net.Jsonp.addPayloadToUri_(payload, uri); } - if (object.properties) { - feature.setProperties(object.properties); + + if (opt_replyCallback) { + var reply = goog.net.Jsonp.newReplyHandler_(id, opt_replyCallback); + goog.global[goog.net.Jsonp.CALLBACKS][id] = reply; + + uri.setParameterValues(this.callbackParamName_, + goog.net.Jsonp.CALLBACKS + '.' + id); } - return feature; -}; + var deferred = goog.net.jsloader.load(uri.toString(), + {timeout: this.timeout_, cleanupWhenDone: true}); + var error = goog.net.Jsonp.newErrorHandler_(id, payload, opt_errorCallback); + deferred.addErrback(error); -/** - * Read all features from a TopoJSON source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.TopoJSON.prototype.readFeatures; + return {id_: id, deferred_: deferred}; +}; /** - * @inheritDoc + * Cancels a given request. The request must be exactly the object returned by + * the send method. + * + * @param {Object} request The request object returned by the send method. */ -ol.format.TopoJSON.prototype.readFeaturesFromObject = function( - object, opt_options) { - if (object.type == 'Topology') { - var topoJSONTopology = /** @type {TopoJSONTopology} */ (object); - var transform, scale = null, translate = null; - if (topoJSONTopology.transform) { - transform = topoJSONTopology.transform; - scale = transform.scale; - translate = transform.translate; - } - var arcs = topoJSONTopology.arcs; - if (transform) { - ol.format.TopoJSON.transformArcs_(arcs, scale, translate); +goog.net.Jsonp.prototype.cancel = function(request) { + if (request) { + if (request.deferred_) { + request.deferred_.cancel(); } - /** @type {Array.<ol.Feature>} */ - var features = []; - var topoJSONFeatures = goog.object.getValues(topoJSONTopology.objects); - var i, ii; - var feature; - for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) { - if (topoJSONFeatures[i].type === 'GeometryCollection') { - feature = /** @type {TopoJSONGeometryCollection} */ - (topoJSONFeatures[i]); - features.push.apply(features, - ol.format.TopoJSON.readFeaturesFromGeometryCollection_( - feature, arcs, scale, translate, opt_options)); - } else { - feature = /** @type {TopoJSONGeometry} */ - (topoJSONFeatures[i]); - features.push(ol.format.TopoJSON.readFeatureFromGeometry_( - feature, arcs, scale, translate, opt_options)); - } + if (request.id_) { + goog.net.Jsonp.cleanup_(request.id_, false); } - return features; - } else { - return []; } }; /** - * Apply a linear transform to array of arcs. The provided array of arcs is - * modified in place. + * Creates a timeout callback that calls the given timeoutCallback with the + * original payload. * - * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. + * @param {string} id The id of the script node. + * @param {Object} payload The payload that was sent to the server. + * @param {Function=} opt_errorCallback The function called on timeout. + * @return {!Function} A zero argument function that handles callback duties. * @private */ -ol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) { - var i, ii; - for (i = 0, ii = arcs.length; i < ii; ++i) { - ol.format.TopoJSON.transformArc_(arcs[i], scale, translate); - } +goog.net.Jsonp.newErrorHandler_ = function(id, + payload, + opt_errorCallback) { + /** + * When we call across domains with a request, this function is the + * timeout handler. Once it's done executing the user-specified + * error-handler, it removes the script node and original function. + */ + return function() { + goog.net.Jsonp.cleanup_(id, false); + if (opt_errorCallback) { + opt_errorCallback(payload); + } + }; }; /** - * Apply a linear transform to an arc. The provided arc is modified in place. + * Creates a reply callback that calls the given replyCallback with data + * returned by the server. * - * @param {Array.<ol.Coordinate>} arc Arc. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. + * @param {string} id The id of the script node. + * @param {Function} replyCallback The function called on reply. + * @return {!Function} A reply callback function. * @private */ -ol.format.TopoJSON.transformArc_ = function(arc, scale, translate) { - var x = 0; - var y = 0; - var vertex; - var i, ii; - for (i = 0, ii = arc.length; i < ii; ++i) { - vertex = arc[i]; - x += vertex[0]; - y += vertex[1]; - vertex[0] = x; - vertex[1] = y; - ol.format.TopoJSON.transformVertex_(vertex, scale, translate); - } +goog.net.Jsonp.newReplyHandler_ = function(id, replyCallback) { + /** + * This function is the handler for the all-is-well response. It + * clears the error timeout handler, calls the user's handler, then + * removes the script node and itself. + * + * @param {...Object} var_args The response data sent from the server. + */ + var handler = function(var_args) { + goog.net.Jsonp.cleanup_(id, true); + replyCallback.apply(undefined, arguments); + }; + return handler; }; /** - * Apply a linear transform to a vertex. The provided vertex is modified in - * place. + * Removes the script node and reply handler with the given id. * - * @param {ol.Coordinate} vertex Vertex. - * @param {Array.<number>} scale Scale for each dimension. - * @param {Array.<number>} translate Translation for each dimension. + * @param {string} id The id of the script node to be removed. + * @param {boolean} deleteReplyHandler If true, delete the reply handler + * instead of setting it to nullFunction (if we know the callback could + * never be called again). * @private */ -ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) { - vertex[0] = vertex[0] * scale[0] + translate[0]; - vertex[1] = vertex[1] * scale[1] + translate[1]; +goog.net.Jsonp.cleanup_ = function(id, deleteReplyHandler) { + if (goog.global[goog.net.Jsonp.CALLBACKS][id]) { + if (deleteReplyHandler) { + delete goog.global[goog.net.Jsonp.CALLBACKS][id]; + } else { + // Removing the script tag doesn't necessarily prevent the script + // from firing, so we make the callback a noop. + goog.global[goog.net.Jsonp.CALLBACKS][id] = goog.nullFunction; + } + } }; /** - * Read the projection from a TopoJSON source. + * Returns URL encoded payload. The payload should be a map of name-value + * pairs, in the form {"foo": 1, "bar": true, ...}. If the map is empty, + * the URI will be unchanged. * - * @function - * @param {Document|Node|Object|string} object Source. - * @return {ol.proj.Projection} Projection. - * @api stable + * <p>The method uses hasOwnProperty() to assure the properties are on the + * object, not on its prototype. + * + * @param {!Object} payload A map of value name pairs to be encoded. + * A value may be specified as an array, in which case a query parameter + * will be created for each value, e.g.: + * {"foo": [1,2]} will encode to "foo=1&foo=2". + * + * @param {!goog.Uri} uri A Uri object onto which the payload key value pairs + * will be encoded. + * + * @return {!goog.Uri} A reference to the Uri sent as a parameter. + * @private */ -ol.format.TopoJSON.prototype.readProjection = function(object) { - return this.defaultDataProjection; +goog.net.Jsonp.addPayloadToUri_ = function(payload, uri) { + for (var name in payload) { + // NOTE(user): Safari/1.3 doesn't have hasOwnProperty(). In that + // case, we iterate over all properties as a very lame workaround. + if (!payload.hasOwnProperty || payload.hasOwnProperty(name)) { + uri.setParameterValues(name, payload[name]); + } + } + return uri; }; -/** - * @const - * @private - * @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>} - */ -ol.format.TopoJSON.GEOMETRY_READERS_ = { - 'Point': ol.format.TopoJSON.readPointGeometry_, - 'LineString': ol.format.TopoJSON.readLineStringGeometry_, - 'Polygon': ol.format.TopoJSON.readPolygonGeometry_, - 'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_, - 'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_, - 'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_ -}; +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// This class allows us (Google) to send data from non-Google and thus +// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return +// anything sensitive, such as session or cookie specific data. Return +// only data that you want parties external to Google to have. Also +// NEVER use this method to send data from web pages to untrusted +// servers, or redirects to unknown servers (www.google.com/cache, +// /q=xx&btnl, /url, www.googlepages.com, etc.) +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -goog.provide('ol.format.WFS'); +goog.provide('ol.source.BingMaps'); +goog.require('goog.Uri'); goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.format.GML3'); -goog.require('ol.format.GMLBase'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.format.XSD'); -goog.require('ol.geom.Geometry'); +goog.require('goog.net.Jsonp'); +goog.require('ol.Attribution'); +goog.require('ol.TileRange'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.extent'); goog.require('ol.proj'); -goog.require('ol.xml'); +goog.require('ol.source.State'); +goog.require('ol.source.TileImage'); +goog.require('ol.tilecoord'); /** * @classdesc - * Feature format for reading and writing data in the WFS format. - * By default, supports WFS version 1.1.0. You can pass a GML format - * as option if you want to read a WFS that contains GML2 (WFS 1.0.0). - * Also see {@link ol.format.GMLBase} which is used by this format. + * Layer source for Bing Maps tile data. * * @constructor - * @param {olx.format.WFSOptions=} opt_options - * Optional configuration object. - * @extends {ol.format.XMLFeature} + * @extends {ol.source.TileImage} + * @param {olx.source.BingMapsOptions} options Bing Maps options. * @api stable */ -ol.format.WFS = function(opt_options) { - var options = opt_options ? opt_options : {}; - - /** - * @private - * @type {Array.<string>|string|undefined} - */ - this.featureType_ = options.featureType; +ol.source.BingMaps = function(options) { - /** - * @private - * @type {Object.<string, string>|string|undefined} - */ - this.featureNS_ = options.featureNS; + goog.base(this, { + crossOrigin: 'anonymous', + opaque: true, + projection: ol.proj.get('EPSG:3857'), + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + state: ol.source.State.LOADING, + tileLoadFunction: options.tileLoadFunction, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); /** * @private - * @type {ol.format.GMLBase} + * @type {string} */ - this.gmlFormat_ = options.gmlFormat ? - options.gmlFormat : new ol.format.GML3(); + this.culture_ = options.culture !== undefined ? options.culture : 'en-us'; /** * @private - * @type {string} + * @type {number} */ - this.schemaLocation_ = options.schemaLocation ? - options.schemaLocation : ol.format.WFS.SCHEMA_LOCATION; - - goog.base(this); -}; -goog.inherits(ol.format.WFS, ol.format.XMLFeature); - - -/** - * @const - * @type {string} - */ -ol.format.WFS.FEATURE_PREFIX = 'feature'; - - -/** - * @const - * @type {string} - */ -ol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/'; - + this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1; -/** - * Number of features; bounds/extent. - * @typedef {{numberOfFeatures: number, - * bounds: ol.Extent}} - * @api stable - */ -ol.format.WFS.FeatureCollectionMetadata; + var uri = new goog.Uri( + 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + + options.imagerySet); + var jsonp = new goog.net.Jsonp(uri, 'jsonp'); + jsonp.send({ + 'include': 'ImageryProviders', + 'uriScheme': 'https', + 'key': options.key + }, goog.bind(this.handleImageryMetadataResponse, this)); -/** - * Total deleted; total inserted; total updated; array of insert ids. - * @typedef {{totalDeleted: number, - * totalInserted: number, - * totalUpdated: number, - * insertIds: Array.<string>}} - * @api stable - */ -ol.format.WFS.TransactionResponse; +}; +goog.inherits(ol.source.BingMaps, ol.source.TileImage); /** + * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’ + * Terms Of Use. * @const - * @type {string} + * @type {ol.Attribution} + * @api */ -ol.format.WFS.SCHEMA_LOCATION = 'http://www.opengis.net/wfs ' + - 'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd'; +ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({ + html: '<a class="ol-attribution-bing-tos" ' + + 'href="http://www.microsoft.com/maps/product/terms.html">' + + 'Terms of Use</a>' +}); /** - * Read all features from a WFS FeatureCollection. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable + * @param {BingMapsImageryMetadataResponse} response Response. */ -ol.format.WFS.prototype.readFeatures; +ol.source.BingMaps.prototype.handleImageryMetadataResponse = + function(response) { + if (response.statusCode != 200 || + response.statusDescription != 'OK' || + response.authenticationResultCode != 'ValidCredentials' || + response.resourceSets.length != 1 || + response.resourceSets[0].resources.length != 1) { + this.setState(ol.source.State.ERROR); + return; + } -/** - * @inheritDoc - */ -ol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) { - var context = { - 'featureType': this.featureType_, - 'featureNS': this.featureNS_ - }; - goog.object.extend(context, this.getReadOptions(node, - opt_options ? opt_options : {})); - var objectStack = [context]; - this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][ - 'featureMember'] = - ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal); - var features = ol.xml.pushParseAndPop([], - this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node, - objectStack, this.gmlFormat_); - if (!features) { - features = []; + var brandLogoUri = response.brandLogoUri; + if (brandLogoUri.indexOf('https') == -1) { + brandLogoUri = brandLogoUri.replace('http', 'https'); } - return features; -}; + //var copyright = response.copyright; // FIXME do we need to display this? + var resource = response.resourceSets[0].resources[0]; + goog.asserts.assert(resource.imageWidth == resource.imageHeight, + 'resource has imageWidth equal to imageHeight, i.e. is square'); + var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_; + var sourceProjection = this.getProjection(); + var extent = ol.tilegrid.extentFromProjection(sourceProjection); + var tileSize = resource.imageWidth == resource.imageHeight ? + resource.imageWidth : [resource.imageWidth, resource.imageHeight]; + var tileGrid = ol.tilegrid.createXYZ({ + extent: extent, + minZoom: resource.zoomMin, + maxZoom: maxZoom, + tileSize: tileSize + }); + this.tileGrid = tileGrid; -/** - * Read transaction response of the source. - * - * @param {Document|Node|Object|string} source Source. - * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. - * @api stable - */ -ol.format.WFS.prototype.readTransactionResponse = function(source) { - if (ol.xml.isDocument(source)) { - return this.readTransactionResponseFromDocument( - /** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readTransactionResponseFromNode(/** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readTransactionResponseFromDocument(doc); - } else { - goog.asserts.fail('Unknown source type'); - return undefined; - } -}; + var culture = this.culture_; + this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( + resource.imageUrlSubdomains.map(function(subdomain) { + var quadKeyTileCoord = [0, 0, 0]; + var imageUrl = resource.imageUrl + .replace('{subdomain}', subdomain) + .replace('{culture}', culture); + return ( + /** + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. + */ + function(tileCoord, pixelRatio, projection) { + goog.asserts.assert(ol.proj.equivalent( + projection, sourceProjection), + 'projections are equivalent'); + if (!tileCoord) { + return undefined; + } else { + ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1], + -tileCoord[2] - 1, quadKeyTileCoord); + return imageUrl.replace('{quadkey}', ol.tilecoord.quadKey( + quadKeyTileCoord)); + } + }); + })); + if (resource.imageryProviders) { + var transform = ol.proj.getTransformFromProjections( + ol.proj.get('EPSG:4326'), this.getProjection()); -/** - * Read feature collection metadata of the source. - * - * @param {Document|Node|Object|string} source Source. - * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} - * FeatureCollection metadata. - * @api stable - */ -ol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) { - if (ol.xml.isDocument(source)) { - return this.readFeatureCollectionMetadataFromDocument( - /** @type {Document} */ (source)); - } else if (ol.xml.isNode(source)) { - return this.readFeatureCollectionMetadataFromNode( - /** @type {Node} */ (source)); - } else if (goog.isString(source)) { - var doc = ol.xml.parse(source); - return this.readFeatureCollectionMetadataFromDocument(doc); - } else { - goog.asserts.fail('Unknown source type'); - return undefined; + var attributions = resource.imageryProviders.map(function(imageryProvider) { + var html = imageryProvider.attribution; + /** @type {Object.<string, Array.<ol.TileRange>>} */ + var tileRanges = {}; + imageryProvider.coverageAreas.forEach(function(coverageArea) { + var minZ = coverageArea.zoomMin; + var maxZ = Math.min(coverageArea.zoomMax, maxZoom); + var bbox = coverageArea.bbox; + var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]]; + var extent = ol.extent.applyTransform(epsg4326Extent, transform); + var tileRange, z, zKey; + for (z = minZ; z <= maxZ; ++z) { + zKey = z.toString(); + tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + if (zKey in tileRanges) { + tileRanges[zKey].push(tileRange); + } else { + tileRanges[zKey] = [tileRange]; + } + } + }); + return new ol.Attribution({html: html, tileRanges: tileRanges}); + }); + attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION); + this.setAttributions(attributions); } -}; + this.setLogo(brandLogoUri); + + this.setState(ol.source.State.READY); -/** - * @param {Document} doc Document. - * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} - * FeatureCollection metadata. - */ -ol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument = - function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFeatureCollectionMetadataFromNode(n); - } - } - return undefined; }; +// FIXME keep cluster cache by resolution ? +// FIXME distance not respected because of the centroid -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.FEATURE_COLLECTION_PARSERS_ = { - 'http://www.opengis.net/gml': { - 'boundedBy': ol.xml.makeObjectPropertySetter( - ol.format.GMLBase.prototype.readGeometryElement, 'bounds') - } -}; +goog.provide('ol.source.Cluster'); +goog.require('goog.asserts'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('ol.Feature'); +goog.require('ol.coordinate'); +goog.require('ol.extent'); +goog.require('ol.geom.Point'); +goog.require('ol.source.Vector'); -/** - * @param {Node} node Node. - * @return {ol.format.WFS.FeatureCollectionMetadata|undefined} - * FeatureCollection metadata. - */ -ol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'FeatureCollection', - 'localName should be FeatureCollection'); - var result = {}; - var value = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('numberOfFeatures')); - result['numberOfFeatures'] = value; - return ol.xml.pushParseAndPop( - /** @type {ol.format.WFS.FeatureCollectionMetadata} */ (result), - ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_); -}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @classdesc + * Layer source to cluster vector data. + * + * @constructor + * @param {olx.source.ClusterOptions} options + * @extends {ol.source.Vector} + * @api */ -ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = { - 'http://www.opengis.net/wfs': { - 'totalInserted': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'totalUpdated': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'totalDeleted': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger) - } -}; +ol.source.Cluster = function(options) { + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + logo: options.logo, + projection: options.projection, + wrapX: options.wrapX + }); + /** + * @type {number|undefined} + * @private + */ + this.resolution_ = undefined; -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Transaction Summary. - * @private - */ -ol.format.WFS.readTransactionSummary_ = function(node, objectStack) { - return ol.xml.pushParseAndPop( - {}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack); -}; + /** + * @type {number} + * @private + */ + this.distance_ = options.distance !== undefined ? options.distance : 20; + /** + * @type {Array.<ol.Feature>} + * @private + */ + this.features_ = []; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WFS.OGC_FID_PARSERS_ = { - 'http://www.opengis.net/ogc': { - 'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) { - return node.getAttribute('fid'); - }) - } + /** + * @type {ol.source.Vector} + * @private + */ + this.source_ = options.source; + + this.source_.on(goog.events.EventType.CHANGE, + ol.source.Cluster.prototype.onSourceChange_, this); }; +goog.inherits(ol.source.Cluster, ol.source.Vector); /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private + * Get a reference to the wrapped source. + * @return {ol.source.Vector} Source. + * @api */ -ol.format.WFS.fidParser_ = function(node, objectStack) { - ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack); +ol.source.Cluster.prototype.getSource = function() { + return this.source_; }; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @inheritDoc */ -ol.format.WFS.INSERT_RESULTS_PARSERS_ = { - 'http://www.opengis.net/wfs': { - 'Feature': ol.format.WFS.fidParser_ +ol.source.Cluster.prototype.loadFeatures = function(extent, resolution, + projection) { + this.source_.loadFeatures(extent, resolution, projection); + if (resolution !== this.resolution_) { + this.clear(); + this.resolution_ = resolution; + this.cluster_(); + this.addFeatures(this.features_); } }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<string>|undefined} Insert results. + * handle the source changing * @private */ -ol.format.WFS.readInsertResults_ = function(node, objectStack) { - return ol.xml.pushParseAndPop( - [], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack); +ol.source.Cluster.prototype.onSourceChange_ = function() { + this.clear(); + this.cluster_(); + this.addFeatures(this.features_); + this.changed(); }; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = { - 'http://www.opengis.net/wfs': { - 'TransactionSummary': ol.xml.makeObjectPropertySetter( - ol.format.WFS.readTransactionSummary_, 'transactionSummary'), - 'InsertResults': ol.xml.makeObjectPropertySetter( - ol.format.WFS.readInsertResults_, 'insertIds') +ol.source.Cluster.prototype.cluster_ = function() { + if (this.resolution_ === undefined) { + return; } -}; + this.features_.length = 0; + var extent = ol.extent.createEmpty(); + var mapDistance = this.distance_ * this.resolution_; + var features = this.source_.getFeatures(); + /** + * @type {Object.<string, boolean>} + */ + var clustered = {}; -/** - * @param {Document} doc Document. - * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. - */ -ol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readTransactionResponseFromNode(n); + for (var i = 0, ii = features.length; i < ii; i++) { + var feature = features[i]; + if (!goog.object.containsKey(clustered, goog.getUid(feature).toString())) { + var geometry = feature.getGeometry(); + goog.asserts.assert(geometry instanceof ol.geom.Point, + 'feature geometry is a ol.geom.Point instance'); + var coordinates = geometry.getCoordinates(); + ol.extent.createOrUpdateFromCoordinate(coordinates, extent); + ol.extent.buffer(extent, mapDistance, extent); + + var neighbors = this.source_.getFeaturesInExtent(extent); + goog.asserts.assert(neighbors.length >= 1, 'at least one neighbor found'); + neighbors = neighbors.filter(function(neighbor) { + var uid = goog.getUid(neighbor).toString(); + if (!goog.object.containsKey(clustered, uid)) { + clustered[uid] = true; + return true; + } else { + return false; + } + }); + this.features_.push(this.createCluster_(neighbors)); } } - return undefined; -}; - - -/** - * @param {Node} node Node. - * @return {ol.format.WFS.TransactionResponse|undefined} Transaction response. - */ -ol.format.WFS.prototype.readTransactionResponseFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'TransactionResponse', - 'localName should be TransactionResponse'); - return ol.xml.pushParseAndPop( - /** @type {ol.format.WFS.TransactionResponse} */({}), - ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []); + goog.asserts.assert( + goog.object.getCount(clustered) == this.source_.getFeatures().length, + 'number of clustered equals number of features in the source'); }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} + * @param {Array.<ol.Feature>} features Features + * @return {ol.Feature} * @private */ -ol.format.WFS.QUERY_SERIALIZERS_ = { - 'http://www.opengis.net/wfs': { - 'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode) +ol.source.Cluster.prototype.createCluster_ = function(features) { + var length = features.length; + var centroid = [0, 0]; + for (var i = 0; i < length; i++) { + var geometry = features[i].getGeometry(); + goog.asserts.assert(geometry instanceof ol.geom.Point, + 'feature geometry is a ol.geom.Point instance'); + var coordinates = geometry.getCoordinates(); + ol.coordinate.add(centroid, coordinates); } + ol.coordinate.scale(centroid, 1 / length); + + var cluster = new ol.Feature(new ol.geom.Point(centroid)); + cluster.set('features', features); + return cluster; }; +goog.provide('ol.source.ImageMapGuide'); + +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('goog.uri.utils'); +goog.require('ol.Image'); +goog.require('ol.ImageLoadFunctionType'); +goog.require('ol.extent'); +goog.require('ol.source.Image'); -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeFeature_ = function(node, feature, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featureNS = context['featureNS']; - var child = ol.xml.createElementNS(featureNS, featureType); - node.appendChild(child); - ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack); -}; /** - * @param {Node} node Node. - * @param {number|string} fid Feature identifier. - * @param {Array.<*>} objectStack Node stack. - * @private + * @classdesc + * Source for images from Mapguide servers + * + * @constructor + * @fires ol.source.ImageEvent + * @extends {ol.source.Image} + * @param {olx.source.ImageMapGuideOptions} options Options. + * @api stable */ -ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) { - var filter = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter'); - var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'FeatureId'); - filter.appendChild(child); - child.setAttribute('fid', fid); - node.appendChild(filter); -}; +ol.source.ImageMapGuide = function(options) { + goog.base(this, { + projection: options.projection, + resolutions: options.resolutions + }); -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeDelete_ = function(node, feature, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featurePrefix = context['featurePrefix']; - featurePrefix = featurePrefix ? featurePrefix : - ol.format.WFS.FEATURE_PREFIX; - var featureNS = context['featureNS']; - node.setAttribute('typeName', featurePrefix + ':' + featureType); - ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, - featureNS); - var fid = feature.getId(); - if (fid) { - ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); - } -}; + /** + * @private + * @type {?string} + */ + this.crossOrigin_ = + options.crossOrigin !== undefined ? options.crossOrigin : null; + /** + * @private + * @type {number} + */ + this.displayDpi_ = options.displayDpi !== undefined ? + options.displayDpi : 96; -/** - * @param {Node} node Node. - * @param {ol.Feature} feature Feature. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featureType = context['featureType']; - var featurePrefix = context['featurePrefix']; - featurePrefix = featurePrefix ? featurePrefix : - ol.format.WFS.FEATURE_PREFIX; - var featureNS = context['featureNS']; - node.setAttribute('typeName', featurePrefix + ':' + featureType); - ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, - featureNS); - var fid = feature.getId(); - if (fid) { - var keys = feature.getKeys(); - var values = []; - for (var i = 0, ii = keys.length; i < ii; i++) { - var value = feature.get(keys[i]); - if (value !== undefined) { - values.push({name: keys[i], value: value}); - } - } - ol.xml.pushSerializeAndPop({node: node, srsName: - context['srsName']}, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Property'), values, - objectStack); - ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack); - } -}; + /** + * @private + * @type {Object} + */ + this.params_ = options.params !== undefined ? options.params : {}; + /** + * @private + * @type {string|undefined} + */ + this.url_ = options.url; -/** - * @param {Node} node Node. - * @param {Object} pair Property name and value. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeProperty_ = function(node, pair, objectStack) { - var name = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Name'); - node.appendChild(name); - ol.format.XSD.writeStringTextNode(name, pair.name); - if (pair.value !== undefined && pair.value !== null) { - var value = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Value'); - node.appendChild(value); - if (pair.value instanceof ol.geom.Geometry) { - ol.format.GML3.prototype.writeGeometryElement(value, - pair.value, objectStack); - } else { - ol.format.XSD.writeStringTextNode(value, pair.value); - } - } -}; + /** + * @private + * @type {ol.ImageLoadFunctionType} + */ + this.imageLoadFunction_ = options.imageLoadFunction !== undefined ? + options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; + /** + * @private + * @type {boolean} + */ + this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; + + /** + * @private + * @type {number} + */ + this.metersPerUnit_ = options.metersPerUnit !== undefined ? + options.metersPerUnit : 1; + + /** + * @private + * @type {number} + */ + this.ratio_ = options.ratio !== undefined ? options.ratio : 1; + + /** + * @private + * @type {boolean} + */ + this.useOverlay_ = options.useOverlay !== undefined ? + options.useOverlay : false; + + /** + * @private + * @type {ol.Image} + */ + this.image_ = null; + + /** + * @private + * @type {number} + */ + this.renderedRevision_ = 0; -/** - * @param {Node} node Node. - * @param {{vendorId: string, safeToIgnore: boolean, value: string}} - * nativeElement The native element. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) { - if (nativeElement.vendorId) { - node.setAttribute('vendorId', nativeElement.vendorId); - } - if (nativeElement.safeToIgnore !== undefined) { - node.setAttribute('safeToIgnore', nativeElement.safeToIgnore); - } - if (nativeElement.value !== undefined) { - ol.format.XSD.writeStringTextNode(node, nativeElement.value); - } }; +goog.inherits(ol.source.ImageMapGuide, ol.source.Image); /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * Get the user-provided params, i.e. those passed to the constructor through + * the "params" option, and possibly updated using the updateParams method. + * @return {Object} Params. + * @api stable */ -ol.format.WFS.TRANSACTION_SERIALIZERS_ = { - 'http://www.opengis.net/wfs': { - 'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_), - 'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_), - 'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_), - 'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_), - 'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_) - } +ol.source.ImageMapGuide.prototype.getParams = function() { + return this.params_; }; /** - * @param {Node} node Node. - * @param {string} featureType Feature type. - * @param {Array.<*>} objectStack Node stack. - * @private + * @inheritDoc */ -ol.format.WFS.writeQuery_ = function(node, featureType, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var featurePrefix = context['featurePrefix']; - var featureNS = context['featureNS']; - var propertyNames = context['propertyNames']; - var srsName = context['srsName']; - var prefix = featurePrefix ? featurePrefix + ':' : ''; - node.setAttribute('typeName', prefix + featureType); - if (srsName) { - node.setAttribute('srsName', srsName); - } - if (featureNS) { - ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix, - featureNS); +ol.source.ImageMapGuide.prototype.getImageInternal = + function(extent, resolution, pixelRatio, projection) { + resolution = this.findNearestResolution(resolution); + pixelRatio = this.hidpi_ ? pixelRatio : 1; + + var image = this.image_; + if (image && + this.renderedRevision_ == this.getRevision() && + image.getResolution() == resolution && + image.getPixelRatio() == pixelRatio && + ol.extent.containsExtent(image.getExtent(), extent)) { + return image; } - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(item, - ol.format.WFS.QUERY_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames, - objectStack); - var bbox = context['bbox']; - if (bbox) { - var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter'); - ol.format.WFS.writeOgcBBOX_(child, bbox, objectStack); - node.appendChild(child); + + if (this.ratio_ != 1) { + extent = extent.slice(); + ol.extent.scaleFromCenter(extent, this.ratio_); } -}; + var width = ol.extent.getWidth(extent) / resolution; + var height = ol.extent.getHeight(extent) / resolution; + var size = [width * pixelRatio, height * pixelRatio]; + if (this.url_ !== undefined) { + var imageUrl = this.getUrl(this.url_, this.params_, extent, size, + projection); + image = new ol.Image(extent, resolution, pixelRatio, + this.getAttributions(), imageUrl, this.crossOrigin_, + this.imageLoadFunction_); + goog.events.listen(image, goog.events.EventType.CHANGE, + this.handleImageChange, false, this); + } else { + image = null; + } + this.image_ = image; + this.renderedRevision_ = this.getRevision(); -/** - * @param {Node} node Node. - * @param {string} value PropertyName value. - * @param {Array.<*>} objectStack Node stack. - * @private - */ -ol.format.WFS.writeOgcPropertyName_ = function(node, value, objectStack) { - var property = ol.xml.createElementNS('http://www.opengis.net/ogc', - 'PropertyName'); - ol.format.XSD.writeStringTextNode(property, value); - node.appendChild(property); + return image; }; /** - * @param {Node} node Node. - * @param {ol.Extent} bbox Bounding box. - * @param {Array.<*>} objectStack Node stack. - * @private + * Return the image load function of the source. + * @return {ol.ImageLoadFunctionType} The image load function. + * @api */ -ol.format.WFS.writeOgcBBOX_ = function(node, bbox, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var geometryName = context['geometryName']; - var bboxNode = ol.xml.createElementNS('http://www.opengis.net/ogc', 'BBOX'); - node.appendChild(bboxNode); - ol.format.WFS.writeOgcPropertyName_(bboxNode, geometryName, objectStack); - ol.format.GML3.prototype.writeGeometryElement(bboxNode, bbox, objectStack); +ol.source.ImageMapGuide.prototype.getImageLoadFunction = function() { + return this.imageLoadFunction_; }; /** - * @type {Object.<string, Object.<string, ol.xml.Serializer>>} - * @private + * @param {ol.Extent} extent The map extents. + * @param {ol.Size} size The viewport size. + * @param {number} metersPerUnit The meters-per-unit value. + * @param {number} dpi The display resolution. + * @return {number} The computed map scale. */ -ol.format.WFS.GETFEATURE_SERIALIZERS_ = { - 'http://www.opengis.net/wfs': { - 'Query': ol.xml.makeChildAppender( - ol.format.WFS.writeQuery_) +ol.source.ImageMapGuide.getScale = function(extent, size, metersPerUnit, dpi) { + var mcsW = ol.extent.getWidth(extent); + var mcsH = ol.extent.getHeight(extent); + var devW = size[0]; + var devH = size[1]; + var mpp = 0.0254 / dpi; + if (devH * mcsW > devW * mcsH) { + return mcsW * metersPerUnit / (devW * mpp); // width limited + } else { + return mcsH * metersPerUnit / (devH * mpp); // height limited } }; /** - * @param {Node} node Node. - * @param {Array.<{string}>} featureTypes Feature types. - * @param {Array.<*>} objectStack Node stack. - * @private + * Update the user-provided params. + * @param {Object} params Params. + * @api stable */ -ol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) { - var context = objectStack[objectStack.length - 1]; - goog.asserts.assert(goog.isObject(context), 'context should be an Object'); - var item = goog.object.clone(context); - item.node = node; - ol.xml.pushSerializeAndPop(item, - ol.format.WFS.GETFEATURE_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Query'), featureTypes, - objectStack); +ol.source.ImageMapGuide.prototype.updateParams = function(params) { + goog.object.extend(this.params_, params); + this.changed(); }; /** - * Encode format as WFS `GetFeature` and return the Node. - * - * @param {olx.format.WFSWriteGetFeatureOptions} options Options. - * @return {Node} Result. - * @api stable + * @param {string} baseUrl The mapagent url. + * @param {Object.<string, string|number>} params Request parameters. + * @param {ol.Extent} extent Extent. + * @param {ol.Size} size Size. + * @param {ol.proj.Projection} projection Projection. + * @return {string} The mapagent map image request URL. */ -ol.format.WFS.prototype.writeGetFeature = function(options) { - var node = ol.xml.createElementNS('http://www.opengis.net/wfs', - 'GetFeature'); - node.setAttribute('service', 'WFS'); - node.setAttribute('version', '1.1.0'); - if (options) { - if (options.handle) { - node.setAttribute('handle', options.handle); - } - if (options.outputFormat) { - node.setAttribute('outputFormat', options.outputFormat); - } - if (options.maxFeatures !== undefined) { - node.setAttribute('maxFeatures', options.maxFeatures); - } - if (options.resultType) { - node.setAttribute('resultType', options.resultType); - } - if (options.startIndex !== undefined) { - node.setAttribute('startIndex', options.startIndex); - } - if (options.count !== undefined) { - node.setAttribute('count', options.count); - } - } - ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', this.schemaLocation_); - var context = { - node: node, - srsName: options.srsName, - featureNS: options.featureNS ? options.featureNS : this.featureNS_, - featurePrefix: options.featurePrefix, - geometryName: options.geometryName, - bbox: options.bbox, - propertyNames: options.propertyNames ? options.propertyNames : [] +ol.source.ImageMapGuide.prototype.getUrl = + function(baseUrl, params, extent, size, projection) { + var scale = ol.source.ImageMapGuide.getScale(extent, size, + this.metersPerUnit_, this.displayDpi_); + var center = ol.extent.getCenter(extent); + var baseParams = { + 'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE', + 'VERSION': '2.0.0', + 'LOCALE': 'en', + 'CLIENTAGENT': 'ol.source.ImageMapGuide source', + 'CLIP': '1', + 'SETDISPLAYDPI': this.displayDpi_, + 'SETDISPLAYWIDTH': Math.round(size[0]), + 'SETDISPLAYHEIGHT': Math.round(size[1]), + 'SETVIEWSCALE': scale, + 'SETVIEWCENTERX': center[0], + 'SETVIEWCENTERY': center[1] }; - goog.asserts.assert(goog.isArray(options.featureTypes), - 'options.featureTypes should be an array'); - ol.format.WFS.writeGetFeature_(node, options.featureTypes, [context]); - return node; + goog.object.extend(baseParams, params); + return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams); }; /** - * Encode format as WFS `Transaction` and return the Node. - * - * @param {Array.<ol.Feature>} inserts The features to insert. - * @param {Array.<ol.Feature>} updates The features to update. - * @param {Array.<ol.Feature>} deletes The features to delete. - * @param {olx.format.WFSWriteTransactionOptions} options Write options. - * @return {Node} Result. - * @api stable + * Set the image load function of the MapGuide source. + * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. + * @api */ -ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes, - options) { - var objectStack = []; - var node = ol.xml.createElementNS('http://www.opengis.net/wfs', - 'Transaction'); - node.setAttribute('service', 'WFS'); - node.setAttribute('version', '1.1.0'); - var baseObj, obj; - if (options) { - baseObj = options.gmlOptions ? options.gmlOptions : {}; - if (options.handle) { - node.setAttribute('handle', options.handle); - } - } - ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation', this.schemaLocation_); - if (inserts) { - obj = {node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}; - goog.object.extend(obj, baseObj); - ol.xml.pushSerializeAndPop(obj, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Insert'), inserts, - objectStack); - } - if (updates) { - obj = {node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}; - goog.object.extend(obj, baseObj); - ol.xml.pushSerializeAndPop(obj, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Update'), updates, - objectStack); - } - if (deletes) { - ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Delete'), deletes, - objectStack); - } - if (options.nativeElements) { - ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS, - featureType: options.featureType, featurePrefix: options.featurePrefix}, - ol.format.WFS.TRANSACTION_SERIALIZERS_, - ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements, - objectStack); - } - return node; +ol.source.ImageMapGuide.prototype.setImageLoadFunction = function( + imageLoadFunction) { + this.image_ = null; + this.imageLoadFunction_ = imageLoadFunction; + this.changed(); }; +goog.provide('ol.source.ImageStatic'); + +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('ol.Image'); +goog.require('ol.ImageLoadFunctionType'); +goog.require('ol.ImageState'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.source.Image'); + + /** - * Read the projection from a WFS source. + * @classdesc + * A layer source for displaying a single, static image. * - * @function - * @param {Document|Node|Object|string} source Source. - * @return {?ol.proj.Projection} Projection. + * @constructor + * @extends {ol.source.Image} + * @param {olx.source.ImageStaticOptions} options Options. * @api stable */ -ol.format.WFS.prototype.readProjection; +ol.source.ImageStatic = function(options) { + + var attributions = options.attributions !== undefined ? + options.attributions : null; + + var imageExtent = options.imageExtent; + + var crossOrigin = options.crossOrigin !== undefined ? + options.crossOrigin : null; + + var /** @type {ol.ImageLoadFunctionType} */ imageLoadFunction = + options.imageLoadFunction !== undefined ? + options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; + + goog.base(this, { + attributions: attributions, + logo: options.logo, + projection: ol.proj.get(options.projection) + }); + + /** + * @private + * @type {ol.Image} + */ + this.image_ = new ol.Image(imageExtent, undefined, 1, attributions, + options.url, crossOrigin, imageLoadFunction); + + /** + * @private + * @type {ol.Size} + */ + this.imageSize_ = options.imageSize ? options.imageSize : null; + + goog.events.listen(this.image_, goog.events.EventType.CHANGE, + this.handleImageChange, false, this); + +}; +goog.inherits(ol.source.ImageStatic, ol.source.Image); /** * @inheritDoc */ -ol.format.WFS.prototype.readProjectionFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be a DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readProjectionFromNode(n); - } +ol.source.ImageStatic.prototype.getImageInternal = + function(extent, resolution, pixelRatio, projection) { + if (ol.extent.intersects(extent, this.image_.getExtent())) { + return this.image_; } return null; }; @@ -104628,4062 +121025,4002 @@ ol.format.WFS.prototype.readProjectionFromDocument = function(doc) { /** * @inheritDoc */ -ol.format.WFS.prototype.readProjectionFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'FeatureCollection', - 'localName should be FeatureCollection'); - - if (node.firstElementChild && - node.firstElementChild.firstElementChild) { - node = node.firstElementChild.firstElementChild; - for (var n = node.firstElementChild; n; n = n.nextElementSibling) { - if (!(n.childNodes.length === 0 || - (n.childNodes.length === 1 && - n.firstChild.nodeType === 3))) { - var objectStack = [{}]; - this.gmlFormat_.readGeometryElement(n, objectStack); - return ol.proj.get(objectStack.pop().srsName); - } +ol.source.ImageStatic.prototype.handleImageChange = function(evt) { + if (this.image_.getState() == ol.ImageState.LOADED) { + var imageExtent = this.image_.getExtent(); + var image = this.image_.getImage(); + var imageWidth, imageHeight; + if (this.imageSize_) { + imageWidth = this.imageSize_[0]; + imageHeight = this.imageSize_[1]; + } else { + imageWidth = image.width; + imageHeight = image.height; + } + var resolution = ol.extent.getHeight(imageExtent) / imageHeight; + var targetWidth = Math.ceil(ol.extent.getWidth(imageExtent) / resolution); + if (targetWidth != imageWidth) { + var canvas = /** @type {HTMLCanvasElement} */ + (document.createElement('canvas')); + canvas.width = targetWidth; + canvas.height = /** @type {number} */ (imageHeight); + var context = canvas.getContext('2d'); + context.drawImage(image, 0, 0, imageWidth, imageHeight, + 0, 0, canvas.width, canvas.height); + this.image_.setImage(canvas); } } + goog.base(this, 'handleImageChange', evt); +}; - return null; +goog.provide('ol.source.wms'); +goog.provide('ol.source.wms.ServerType'); + + +/** + * Available server types: `'carmentaserver'`, `'geoserver'`, `'mapserver'`, + * `'qgis'`. These are servers that have vendor parameters beyond the WMS + * specification that OpenLayers can make use of. + * @enum {string} + * @api + */ +ol.source.wms.ServerType = { + CARMENTA_SERVER: 'carmentaserver', + GEOSERVER: 'geoserver', + MAPSERVER: 'mapserver', + QGIS: 'qgis' }; -goog.provide('ol.format.WKT'); +// FIXME cannot be shared between maps with different projections + +goog.provide('ol.source.ImageWMS'); goog.require('goog.asserts'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.uri.utils'); goog.require('ol'); -goog.require('ol.Feature'); -goog.require('ol.format.Feature'); -goog.require('ol.format.TextFeature'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.GeometryCollection'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); +goog.require('ol.Image'); +goog.require('ol.ImageLoadFunctionType'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.source.Image'); +goog.require('ol.source.wms'); +goog.require('ol.source.wms.ServerType'); /** * @classdesc - * Geometry format for reading and writing data in the `WellKnownText` (WKT) - * format. + * Source for WMS servers providing single, untiled images. * * @constructor - * @extends {ol.format.TextFeature} - * @param {olx.format.WKTOptions=} opt_options Options. + * @fires ol.source.ImageEvent + * @extends {ol.source.Image} + * @param {olx.source.ImageWMSOptions=} opt_options Options. * @api stable */ -ol.format.WKT = function(opt_options) { +ol.source.ImageWMS = function(opt_options) { - var options = opt_options ? opt_options : {}; + var options = opt_options || {}; - goog.base(this); + goog.base(this, { + attributions: options.attributions, + logo: options.logo, + projection: options.projection, + resolutions: options.resolutions + }); + + /** + * @private + * @type {?string} + */ + this.crossOrigin_ = + options.crossOrigin !== undefined ? options.crossOrigin : null; + + /** + * @private + * @type {string|undefined} + */ + this.url_ = options.url; + + /** + * @private + * @type {ol.ImageLoadFunctionType} + */ + this.imageLoadFunction_ = options.imageLoadFunction !== undefined ? + options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; + + /** + * @private + * @type {Object} + */ + this.params_ = options.params; + + /** + * @private + * @type {boolean} + */ + this.v13_ = true; + this.updateV13_(); + + /** + * @private + * @type {ol.source.wms.ServerType|undefined} + */ + this.serverType_ = + /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType); /** - * Split GeometryCollection into multiple features. - * @type {boolean} * @private + * @type {boolean} */ - this.splitCollection_ = options.splitCollection !== undefined ? - options.splitCollection : false; + this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; -}; -goog.inherits(ol.format.WKT, ol.format.TextFeature); + /** + * @private + * @type {ol.Image} + */ + this.image_ = null; + /** + * @private + * @type {ol.Size} + */ + this.imageSize_ = [0, 0]; -/** - * @const - * @type {string} - */ -ol.format.WKT.EMPTY = 'EMPTY'; + /** + * @private + * @type {number} + */ + this.renderedRevision_ = 0; + /** + * @private + * @type {number} + */ + this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5; -/** - * @param {ol.geom.Point} geom Point geometry. - * @return {string} Coordinates part of Point as WKT. - * @private - */ -ol.format.WKT.encodePointGeometry_ = function(geom) { - var coordinates = geom.getCoordinates(); - if (coordinates.length === 0) { - return ''; - } - return coordinates[0] + ' ' + coordinates[1]; }; +goog.inherits(ol.source.ImageWMS, ol.source.Image); /** - * @param {ol.geom.MultiPoint} geom MultiPoint geometry. - * @return {string} Coordinates part of MultiPoint as WKT. + * @const + * @type {ol.Size} * @private */ -ol.format.WKT.encodeMultiPointGeometry_ = function(geom) { - var array = []; - var components = geom.getPoints(); - for (var i = 0, ii = components.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')'); - } - return array.join(','); -}; +ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101]; /** - * @param {ol.geom.GeometryCollection} geom GeometryCollection geometry. - * @return {string} Coordinates part of GeometryCollection as WKT. - * @private + * Return the GetFeatureInfo URL for the passed coordinate, resolution, and + * projection. Return `undefined` if the GetFeatureInfo URL cannot be + * constructed. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {ol.proj.ProjectionLike} projection Projection. + * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should + * be provided. If `QUERY_LAYERS` is not provided then the layers specified + * in the `LAYERS` parameter will be used. `VERSION` should not be + * specified here. + * @return {string|undefined} GetFeatureInfo URL. + * @api stable */ -ol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) { - var array = []; - var geoms = geom.getGeometries(); - for (var i = 0, ii = geoms.length; i < ii; ++i) { - array.push(ol.format.WKT.encode_(geoms[i])); - } - return array.join(','); -}; +ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = + function(coordinate, resolution, projection, params) { + goog.asserts.assert(!('VERSION' in params), + 'key VERSION is not allowed in params'); -/** - * @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry. - * @return {string} Coordinates part of LineString as WKT. - * @private - */ -ol.format.WKT.encodeLineStringGeometry_ = function(geom) { - var coordinates = geom.getCoordinates(); - var array = []; - for (var i = 0, ii = coordinates.length; i < ii; ++i) { - array.push(coordinates[i][0] + ' ' + coordinates[i][1]); + if (this.url_ === undefined) { + return undefined; } - return array.join(','); -}; + var extent = ol.extent.getForViewAndSize( + coordinate, resolution, 0, + ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_); -/** - * @param {ol.geom.MultiLineString} geom MultiLineString geometry. - * @return {string} Coordinates part of MultiLineString as WKT. - * @private - */ -ol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) { - var array = []; - var components = geom.getLineStrings(); - for (var i = 0, ii = components.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodeLineStringGeometry_( - components[i]) + ')'); - } - return array.join(','); -}; + var baseParams = { + 'SERVICE': 'WMS', + 'VERSION': ol.DEFAULT_WMS_VERSION, + 'REQUEST': 'GetFeatureInfo', + 'FORMAT': 'image/png', + 'TRANSPARENT': true, + 'QUERY_LAYERS': this.params_['LAYERS'] + }; + goog.object.extend(baseParams, this.params_, params); + var x = Math.floor((coordinate[0] - extent[0]) / resolution); + var y = Math.floor((extent[3] - coordinate[1]) / resolution); + baseParams[this.v13_ ? 'I' : 'X'] = x; + baseParams[this.v13_ ? 'J' : 'Y'] = y; -/** - * @param {ol.geom.Polygon} geom Polygon geometry. - * @return {string} Coordinates part of Polygon as WKT. - * @private - */ -ol.format.WKT.encodePolygonGeometry_ = function(geom) { - var array = []; - var rings = geom.getLinearRings(); - for (var i = 0, ii = rings.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodeLineStringGeometry_( - rings[i]) + ')'); - } - return array.join(','); + return this.getRequestUrl_( + extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_, + 1, ol.proj.get(projection), baseParams); }; /** - * @param {ol.geom.MultiPolygon} geom MultiPolygon geometry. - * @return {string} Coordinates part of MultiPolygon as WKT. - * @private + * Get the user-provided params, i.e. those passed to the constructor through + * the "params" option, and possibly updated using the updateParams method. + * @return {Object} Params. + * @api stable */ -ol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) { - var array = []; - var components = geom.getPolygons(); - for (var i = 0, ii = components.length; i < ii; ++i) { - array.push('(' + ol.format.WKT.encodePolygonGeometry_( - components[i]) + ')'); - } - return array.join(','); +ol.source.ImageWMS.prototype.getParams = function() { + return this.params_; }; /** - * Encode a geometry as WKT. - * @param {ol.geom.Geometry} geom The geometry to encode. - * @return {string} WKT string for the geometry. - * @private + * @inheritDoc */ -ol.format.WKT.encode_ = function(geom) { - var type = geom.getType(); - var geometryEncoder = ol.format.WKT.GeometryEncoder_[type]; - goog.asserts.assert(geometryEncoder, 'geometryEncoder should be defined'); - var enc = geometryEncoder(geom); - type = type.toUpperCase(); - if (enc.length === 0) { - return type + ' ' + ol.format.WKT.EMPTY; - } - return type + '(' + enc + ')'; -}; - +ol.source.ImageWMS.prototype.getImageInternal = + function(extent, resolution, pixelRatio, projection) { -/** - * @const - * @type {Object.<string, function(ol.geom.Geometry): string>} - * @private - */ -ol.format.WKT.GeometryEncoder_ = { - 'Point': ol.format.WKT.encodePointGeometry_, - 'LineString': ol.format.WKT.encodeLineStringGeometry_, - 'Polygon': ol.format.WKT.encodePolygonGeometry_, - 'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_, - 'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_, - 'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_, - 'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_ -}; + if (this.url_ === undefined) { + return null; + } + resolution = this.findNearestResolution(resolution); -/** - * Parse a WKT string. - * @param {string} wkt WKT string. - * @return {ol.geom.Geometry|ol.geom.GeometryCollection|undefined} - * The geometry created. - * @private - */ -ol.format.WKT.prototype.parse_ = function(wkt) { - var lexer = new ol.format.WKT.Lexer(wkt); - var parser = new ol.format.WKT.Parser(lexer); - return parser.parse(); -}; + if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) { + pixelRatio = 1; + } + extent = extent.slice(); + var centerX = (extent[0] + extent[2]) / 2; + var centerY = (extent[1] + extent[3]) / 2; -/** - * Read a feature from a WKT source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.Feature} Feature. - * @api stable - */ -ol.format.WKT.prototype.readFeature; + var imageResolution = resolution / pixelRatio; + var imageWidth = ol.extent.getWidth(extent) / imageResolution; + var imageHeight = ol.extent.getHeight(extent) / imageResolution; + var image = this.image_; + if (image && + this.renderedRevision_ == this.getRevision() && + image.getResolution() == resolution && + image.getPixelRatio() == pixelRatio && + ol.extent.containsExtent(image.getExtent(), extent)) { + return image; + } -/** - * @inheritDoc - */ -ol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) { - var geom = this.readGeometryFromText(text, opt_options); - if (geom) { - var feature = new ol.Feature(); - feature.setGeometry(geom); - return feature; + if (this.ratio_ != 1) { + var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2; + var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2; + extent[0] = centerX - halfWidth; + extent[1] = centerY - halfHeight; + extent[2] = centerX + halfWidth; + extent[3] = centerY + halfHeight; } - return null; -}; + var params = { + 'SERVICE': 'WMS', + 'VERSION': ol.DEFAULT_WMS_VERSION, + 'REQUEST': 'GetMap', + 'FORMAT': 'image/png', + 'TRANSPARENT': true + }; + goog.object.extend(params, this.params_); -/** - * Read all features from a WKT source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {Array.<ol.Feature>} Features. - * @api stable - */ -ol.format.WKT.prototype.readFeatures; + this.imageSize_[0] = Math.ceil(imageWidth * this.ratio_); + this.imageSize_[1] = Math.ceil(imageHeight * this.ratio_); + var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio, + projection, params); -/** - * @inheritDoc - */ -ol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) { - var geometries = []; - var geometry = this.readGeometryFromText(text, opt_options); - if (this.splitCollection_ && - geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) { - geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry)) - .getGeometriesArray(); - } else { - geometries = [geometry]; - } - var feature, features = []; - for (var i = 0, ii = geometries.length; i < ii; ++i) { - feature = new ol.Feature(); - feature.setGeometry(geometries[i]); - features.push(feature); - } - return features; -}; + this.image_ = new ol.Image(extent, resolution, pixelRatio, + this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_); + this.renderedRevision_ = this.getRevision(); -/** - * Read a single geometry from a WKT source. - * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Read options. - * @return {ol.geom.Geometry} Geometry. - * @api stable - */ -ol.format.WKT.prototype.readGeometry; + goog.events.listen(this.image_, goog.events.EventType.CHANGE, + this.handleImageChange, false, this); + return this.image_; -/** - * @inheritDoc - */ -ol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) { - var geometry = this.parse_(text); - if (geometry) { - return /** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, false, opt_options)); - } else { - return null; - } }; /** - * Encode a feature as a WKT string. - * - * @function - * @param {ol.Feature} feature Feature. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} WKT string. - * @api stable - */ -ol.format.WKT.prototype.writeFeature; - - -/** - * @inheritDoc + * Return the image load function of the source. + * @return {ol.ImageLoadFunctionType} The image load function. + * @api */ -ol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) { - var geometry = feature.getGeometry(); - if (geometry) { - return this.writeGeometryText(geometry, opt_options); - } - return ''; +ol.source.ImageWMS.prototype.getImageLoadFunction = function() { + return this.imageLoadFunction_; }; /** - * Encode an array of features as a WKT string. - * - * @function - * @param {Array.<ol.Feature>} features Features. - * @param {olx.format.WriteOptions=} opt_options Write options. - * @return {string} WKT string. - * @api stable + * @param {ol.Extent} extent Extent. + * @param {ol.Size} size Size. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @param {Object} params Params. + * @return {string} Request URL. + * @private */ -ol.format.WKT.prototype.writeFeatures; +ol.source.ImageWMS.prototype.getRequestUrl_ = + function(extent, size, pixelRatio, projection, params) { + goog.asserts.assert(this.url_ !== undefined, 'url is defined'); -/** - * @inheritDoc - */ -ol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) { - if (features.length == 1) { - return this.writeFeatureText(features[0], opt_options); - } - var geometries = []; - for (var i = 0, ii = features.length; i < ii; ++i) { - geometries.push(features[i].getGeometry()); + params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode(); + + if (!('STYLES' in this.params_)) { + /* jshint -W053 */ + params['STYLES'] = new String(''); + /* jshint +W053 */ } - var collection = new ol.geom.GeometryCollection(geometries); - return this.writeGeometryText(collection, opt_options); -}; + if (pixelRatio != 1) { + switch (this.serverType_) { + case ol.source.wms.ServerType.GEOSERVER: + var dpi = (90 * pixelRatio + 0.5) | 0; + if ('FORMAT_OPTIONS' in params) { + params['FORMAT_OPTIONS'] += ';dpi:' + dpi; + } else { + params['FORMAT_OPTIONS'] = 'dpi:' + dpi; + } + break; + case ol.source.wms.ServerType.MAPSERVER: + params['MAP_RESOLUTION'] = 90 * pixelRatio; + break; + case ol.source.wms.ServerType.CARMENTA_SERVER: + case ol.source.wms.ServerType.QGIS: + params['DPI'] = 90 * pixelRatio; + break; + default: + goog.asserts.fail('unknown serverType configured'); + break; + } + } -/** - * Write a single geometry as a WKT string. - * - * @function - * @param {ol.geom.Geometry} geometry Geometry. - * @return {string} WKT string. - * @api stable - */ -ol.format.WKT.prototype.writeGeometry; + params['WIDTH'] = size[0]; + params['HEIGHT'] = size[1]; + var axisOrientation = projection.getAxisOrientation(); + var bbox; + if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') { + bbox = [extent[1], extent[0], extent[3], extent[2]]; + } else { + bbox = extent; + } + params['BBOX'] = bbox.join(','); -/** - * @inheritDoc - */ -ol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) { - return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ ( - ol.format.Feature.transformWithOptions(geometry, true, opt_options))); + return goog.uri.utils.appendParamsFromMap(this.url_, params); }; /** - * @typedef {{type: number, value: (number|string|undefined), position: number}} - */ -ol.format.WKT.Token; - - -/** - * @const - * @enum {number} + * Return the URL used for this WMS source. + * @return {string|undefined} URL. + * @api stable */ -ol.format.WKT.TokenType = { - TEXT: 1, - LEFT_PAREN: 2, - RIGHT_PAREN: 3, - NUMBER: 4, - COMMA: 5, - EOF: 6 +ol.source.ImageWMS.prototype.getUrl = function() { + return this.url_; }; - /** - * Class to tokenize a WKT string. - * @param {string} wkt WKT string. - * @constructor - * @protected + * Set the image load function of the source. + * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. + * @api */ -ol.format.WKT.Lexer = function(wkt) { - - /** - * @type {string} - */ - this.wkt = wkt; - - /** - * @type {number} - * @private - */ - this.index_ = -1; +ol.source.ImageWMS.prototype.setImageLoadFunction = function( + imageLoadFunction) { + this.image_ = null; + this.imageLoadFunction_ = imageLoadFunction; + this.changed(); }; /** - * @param {string} c Character. - * @return {boolean} Whether the character is alphabetic. - * @private + * Set the URL to use for requests. + * @param {string|undefined} url URL. + * @api stable */ -ol.format.WKT.Lexer.prototype.isAlpha_ = function(c) { - return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; +ol.source.ImageWMS.prototype.setUrl = function(url) { + if (url != this.url_) { + this.url_ = url; + this.image_ = null; + this.changed(); + } }; /** - * @param {string} c Character. - * @param {boolean=} opt_decimal Whether the string number - * contains a dot, i.e. is a decimal number. - * @return {boolean} Whether the character is numeric. - * @private + * Update the user-provided params. + * @param {Object} params Params. + * @api stable */ -ol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) { - var decimal = opt_decimal !== undefined ? opt_decimal : false; - return c >= '0' && c <= '9' || c == '.' && !decimal; +ol.source.ImageWMS.prototype.updateParams = function(params) { + goog.object.extend(this.params_, params); + this.updateV13_(); + this.image_ = null; + this.changed(); }; /** - * @param {string} c Character. - * @return {boolean} Whether the character is whitespace. * @private */ -ol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) { - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +ol.source.ImageWMS.prototype.updateV13_ = function() { + var version = + goog.object.get(this.params_, 'VERSION', ol.DEFAULT_WMS_VERSION); + this.v13_ = goog.string.compareVersions(version, '1.3') >= 0; }; +goog.provide('ol.source.XYZ'); + +goog.require('ol.source.TileImage'); + + /** - * @return {string} Next string character. - * @private + * @classdesc + * Layer source for tile data with URLs in a set XYZ format that are + * defined in a URL template. By default, this follows the widely-used + * Google grid where `x` 0 and `y` 0 are in the top left. Grids like + * TMS where `x` 0 and `y` 0 are in the bottom left can be used by + * using the `{-y}` placeholder in the URL template, so long as the + * source does not have a custom tile grid. In this case, + * {@link ol.source.TileImage} can be used with a `tileUrlFunction` + * such as: + * + * tileUrlFunction: function(coordinate) { + * return 'http://mapserver.com/' + coordinate[0] + '/' + + * coordinate[1] + '/' + coordinate[2] + '.png'; + * } + * + * + * @constructor + * @extends {ol.source.TileImage} + * @param {olx.source.XYZOptions} options XYZ options. + * @api stable */ -ol.format.WKT.Lexer.prototype.nextChar_ = function() { - return this.wkt.charAt(++this.index_); +ol.source.XYZ = function(options) { + var projection = options.projection !== undefined ? + options.projection : 'EPSG:3857'; + + var tileGrid = options.tileGrid !== undefined ? options.tileGrid : + ol.tilegrid.createXYZ({ + extent: ol.tilegrid.extentFromProjection(projection), + maxZoom: options.maxZoom, + tileSize: options.tileSize + }); + + goog.base(this, { + attributions: options.attributions, + crossOrigin: options.crossOrigin, + logo: options.logo, + projection: projection, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileGrid: tileGrid, + tileLoadFunction: options.tileLoadFunction, + tilePixelRatio: options.tilePixelRatio, + tileUrlFunction: options.tileUrlFunction, + url: options.url, + urls: options.urls, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); + }; +goog.inherits(ol.source.XYZ, ol.source.TileImage); + +goog.provide('ol.source.OSM'); + +goog.require('ol.Attribution'); +goog.require('ol.source.XYZ'); + /** - * Fetch and return the next token. - * @return {!ol.format.WKT.Token} Next string token. + * @classdesc + * Layer source for the OpenStreetMap tile server. + * + * @constructor + * @extends {ol.source.XYZ} + * @param {olx.source.OSMOptions=} opt_options Open Street Map options. + * @api stable */ -ol.format.WKT.Lexer.prototype.nextToken = function() { - var c = this.nextChar_(); - var token = {position: this.index_, value: c}; +ol.source.OSM = function(opt_options) { - if (c == '(') { - token.type = ol.format.WKT.TokenType.LEFT_PAREN; - } else if (c == ',') { - token.type = ol.format.WKT.TokenType.COMMA; - } else if (c == ')') { - token.type = ol.format.WKT.TokenType.RIGHT_PAREN; - } else if (this.isNumeric_(c) || c == '-') { - token.type = ol.format.WKT.TokenType.NUMBER; - token.value = this.readNumber_(); - } else if (this.isAlpha_(c)) { - token.type = ol.format.WKT.TokenType.TEXT; - token.value = this.readText_(); - } else if (this.isWhiteSpace_(c)) { - return this.nextToken(); - } else if (c === '') { - token.type = ol.format.WKT.TokenType.EOF; + var options = opt_options || {}; + + var attributions; + if (options.attributions !== undefined) { + attributions = options.attributions; } else { - throw new Error('Unexpected character: ' + c); + attributions = [ol.source.OSM.ATTRIBUTION]; } - return token; -}; + var crossOrigin = options.crossOrigin !== undefined ? + options.crossOrigin : 'anonymous'; + var url = options.url !== undefined ? + options.url : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + + goog.base(this, { + attributions: attributions, + crossOrigin: crossOrigin, + opaque: true, + maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileLoadFunction: options.tileLoadFunction, + url: url, + wrapX: options.wrapX + }); -/** - * @return {number} Numeric token value. - * @private - */ -ol.format.WKT.Lexer.prototype.readNumber_ = function() { - var c, index = this.index_; - var decimal = false; - var scientificNotation = false; - do { - if (c == '.') { - decimal = true; - } else if (c == 'e' || c == 'E') { - scientificNotation = true; - } - c = this.nextChar_(); - } while ( - this.isNumeric_(c, decimal) || - // if we haven't detected a scientific number before, 'e' or 'E' - // hint that we should continue to read - !scientificNotation && (c == 'e' || c == 'E') || - // once we know that we have a scientific number, both '-' and '+' - // are allowed - scientificNotation && (c == '-' || c == '+') - ); - return parseFloat(this.wkt.substring(index, this.index_--)); }; +goog.inherits(ol.source.OSM, ol.source.XYZ); /** - * @return {string} String token value. - * @private + * The attribution containing a link to the OpenStreetMap Copyright and License + * page. + * @const + * @type {ol.Attribution} + * @api */ -ol.format.WKT.Lexer.prototype.readText_ = function() { - var c, index = this.index_; - do { - c = this.nextChar_(); - } while (this.isAlpha_(c)); - return this.wkt.substring(index, this.index_--).toUpperCase(); -}; +ol.source.OSM.ATTRIBUTION = new ol.Attribution({ + html: '© ' + + '<a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' + + 'contributors.' +}); + +goog.provide('ol.source.MapQuest'); + +goog.require('goog.asserts'); +goog.require('ol.Attribution'); +goog.require('ol.source.OSM'); +goog.require('ol.source.XYZ'); /** - * Class to parse the tokens from the WKT string. - * @param {ol.format.WKT.Lexer} lexer + * @classdesc + * Layer source for the MapQuest tile server. + * * @constructor - * @protected + * @extends {ol.source.XYZ} + * @param {olx.source.MapQuestOptions=} opt_options MapQuest options. + * @api stable */ -ol.format.WKT.Parser = function(lexer) { +ol.source.MapQuest = function(opt_options) { - /** - * @type {ol.format.WKT.Lexer} - * @private - */ - this.lexer_ = lexer; + var options = opt_options || {}; + goog.asserts.assert(options.layer in ol.source.MapQuestConfig, + 'known layer configured'); - /** - * @type {ol.format.WKT.Token} - * @private - */ - this.token_; + var layerConfig = ol.source.MapQuestConfig[options.layer]; /** - * @type {number} + * Layer. Possible values are `osm`, `sat`, and `hyb`. + * @type {string} * @private */ - this.dimension_ = 2; -}; - + this.layer_ = options.layer; -/** - * Fetch the next token form the lexer and replace the active token. - * @private - */ -ol.format.WKT.Parser.prototype.consume_ = function() { - this.token_ = this.lexer_.nextToken(); -}; + var url = options.url !== undefined ? options.url : + 'https://otile{1-4}-s.mqcdn.com/tiles/1.0.0/' + + this.layer_ + '/{z}/{x}/{y}.jpg'; + goog.base(this, { + attributions: layerConfig.attributions, + crossOrigin: 'anonymous', + logo: 'https://developer.mapquest.com/content/osm/mq_logo.png', + maxZoom: layerConfig.maxZoom, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + opaque: true, + tileLoadFunction: options.tileLoadFunction, + url: url + }); -/** - * If the given type matches the current token, consume it. - * @param {ol.format.WKT.TokenType.<number>} type Token type. - * @return {boolean} Whether the token matches the given type. - */ -ol.format.WKT.Parser.prototype.match = function(type) { - var isMatch = this.token_.type == type; - if (isMatch) { - this.consume_(); - } - return isMatch; }; +goog.inherits(ol.source.MapQuest, ol.source.XYZ); /** - * Try to parse the tokens provided by the lexer. - * @return {ol.geom.Geometry|ol.geom.GeometryCollection} The geometry. + * @const + * @type {ol.Attribution} */ -ol.format.WKT.Parser.prototype.parse = function() { - this.consume_(); - var geometry = this.parseGeometry_(); - goog.asserts.assert(this.token_.type == ol.format.WKT.TokenType.EOF, - 'token type should be end of file'); - return geometry; -}; +ol.source.MapQuest.TILE_ATTRIBUTION = new ol.Attribution({ + html: 'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a>' +}); /** - * @return {!(ol.geom.Geometry|ol.geom.GeometryCollection)} The geometry. - * @private + * @type {Object.<string, {maxZoom: number, attributions: (Array.<ol.Attribution>)}>} */ -ol.format.WKT.Parser.prototype.parseGeometry_ = function() { - var token = this.token_; - if (this.match(ol.format.WKT.TokenType.TEXT)) { - var geomType = token.value; - if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) { - var geometries = this.parseGeometryCollectionText_(); - return new ol.geom.GeometryCollection(geometries); - } else { - var parser = ol.format.WKT.Parser.GeometryParser_[geomType]; - var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType]; - if (!parser || !ctor) { - throw new Error('Invalid geometry type: ' + geomType); - } - var coordinates = parser.call(this); - return new ctor(coordinates); - } +ol.source.MapQuestConfig = { + 'osm': { + maxZoom: 19, + attributions: [ + ol.source.MapQuest.TILE_ATTRIBUTION, + ol.source.OSM.ATTRIBUTION + ] + }, + 'sat': { + maxZoom: 18, + attributions: [ + ol.source.MapQuest.TILE_ATTRIBUTION, + new ol.Attribution({ + html: 'Portions Courtesy NASA/JPL-Caltech and ' + + 'U.S. Depart. of Agriculture, Farm Service Agency' + }) + ] + }, + 'hyb': { + maxZoom: 18, + attributions: [ + ol.source.MapQuest.TILE_ATTRIBUTION, + ol.source.OSM.ATTRIBUTION + ] } - throw new Error(this.formatErrorMessage_()); }; /** - * @return {!Array.<ol.geom.Geometry>} A collection of geometries. - * @private + * Get the layer of the source, either `osm`, `sat`, or `hyb`. + * @return {string} Layer. + * @api */ -ol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var geometries = []; - do { - geometries.push(this.parseGeometry_()); - } while (this.match(ol.format.WKT.TokenType.COMMA)); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return geometries; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); +ol.source.MapQuest.prototype.getLayer = function() { + return this.layer_; }; - +goog.provide('ol.ext.pixelworks'); +/** @typedef {function(*)} */ +ol.ext.pixelworks; +(function() { +var exports = {}; +var module = {exports: exports}; +var define; /** - * @return {Array.<number>} All values in a point. - * @private + * @fileoverview + * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility} */ -ol.format.WKT.Parser.prototype.parsePointText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parsePoint_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return null; - } - throw new Error(this.formatErrorMessage_()); -}; - +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixelworks = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ +var Processor = _dereq_('./processor'); -/** - * @return {!Array.<!Array.<number>>} All points in a linestring. - * @private - */ -ol.format.WKT.Parser.prototype.parseLineStringText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parsePointList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; +exports.Processor = Processor; +},{"./processor":2}],2:[function(_dereq_,module,exports){ +/* eslint-disable dot-notation */ /** - * @return {!Array.<!Array.<number>>} All points in a polygon. - * @private + * Create a function for running operations. + * @param {function(Array, Object):*} operation The operation. + * @return {function(Object):ArrayBuffer} A function that takes an object with + * buffers, meta, imageOps, width, and height properties and returns an array + * buffer. */ -ol.format.WKT.Parser.prototype.parsePolygonText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parseLineStringTextList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; +function createMinion(operation) { + return function(data) { + // bracket notation for minification support + var buffers = data['buffers']; + var meta = data['meta']; + var imageOps = data['imageOps']; + var width = data['width']; + var height = data['height']; + var numBuffers = buffers.length; + var numBytes = buffers[0].byteLength; + var output, b; -/** - * @return {!Array.<!Array.<number>>} All points in a multipoint. - * @private - */ -ol.format.WKT.Parser.prototype.parseMultiPointText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates; - if (this.token_.type == ol.format.WKT.TokenType.LEFT_PAREN) { - coordinates = this.parsePointTextList_(); + if (imageOps) { + var images = new Array(numBuffers); + for (b = 0; b < numBuffers; ++b) { + images[b] = new ImageData( + new Uint8ClampedArray(buffers[b]), width, height); + } + output = operation(images, meta).data; } else { - coordinates = this.parsePointList_(); - } - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; + output = new Uint8ClampedArray(numBytes); + var arrays = new Array(numBuffers); + var pixels = new Array(numBuffers); + for (b = 0; b < numBuffers; ++b) { + arrays[b] = new Uint8ClampedArray(buffers[b]); + pixels[b] = [0, 0, 0, 0]; + } + for (var i = 0; i < numBytes; i += 4) { + for (var j = 0; j < numBuffers; ++j) { + var array = arrays[j]; + pixels[j][0] = array[i]; + pixels[j][1] = array[i + 1]; + pixels[j][2] = array[i + 2]; + pixels[j][3] = array[i + 3]; + } + var pixel = operation(pixels, meta); + output[i] = pixel[0]; + output[i + 1] = pixel[1]; + output[i + 2] = pixel[2]; + output[i + 3] = pixel[3]; + } } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - + return output.buffer; + }; +} /** - * @return {!Array.<!Array.<number>>} All linestring points - * in a multilinestring. - * @private + * Create a worker for running operations. + * @param {Object} config Configuration. + * @param {function(Object)} onMessage Called with a message event. + * @return {Worker} The worker. */ -ol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parseLineStringTextList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; - +function createWorker(config, onMessage) { + var lib = Object.keys(config.lib || {}).map(function(name) { + return 'var ' + name + ' = ' + config.lib[name].toString() + ';'; + }); -/** - * @return {!Array.<!Array.<number>>} All polygon points in a multipolygon. - * @private - */ -ol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() { - if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) { - var coordinates = this.parsePolygonTextList_(); - if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) { - return coordinates; - } - } else if (this.isEmptyGeometry_()) { - return []; - } - throw new Error(this.formatErrorMessage_()); -}; + var lines = lib.concat([ + 'var __minion__ = (' + createMinion.toString() + ')(', + config.operation.toString(), + ');', + 'self.addEventListener("message", function(__event__) {', + 'var buffer = __minion__(__event__.data);', + 'self.postMessage({buffer: buffer, meta: __event__.data.meta}, [buffer]);', + '});' + ]); + var blob = new Blob(lines, {type: 'text/javascript'}); + var source = URL.createObjectURL(blob); + var worker = new Worker(source); + worker.addEventListener('message', onMessage); + return worker; +} /** - * @return {!Array.<number>} A point. - * @private + * Create a faux worker for running operations. + * @param {Object} config Configuration. + * @param {function(Object)} onMessage Called with a message event. + * @return {Object} The faux worker. */ -ol.format.WKT.Parser.prototype.parsePoint_ = function() { - var coordinates = []; - for (var i = 0; i < this.dimension_; ++i) { - var token = this.token_; - if (this.match(ol.format.WKT.TokenType.NUMBER)) { - coordinates.push(token.value); - } else { - break; +function createFauxWorker(config, onMessage) { + var minion = createMinion(config.operation); + return { + postMessage: function(data) { + setTimeout(function() { + onMessage({data: {buffer: minion(data), meta: data.meta}}); + }, 0); } - } - if (coordinates.length == this.dimension_) { - return coordinates; - } - throw new Error(this.formatErrorMessage_()); -}; - + }; +} /** - * @return {!Array.<!Array.<number>>} An array of points. - * @private + * A processor runs pixel or image operations in workers. + * @param {Object} config Configuration. */ -ol.format.WKT.Parser.prototype.parsePointList_ = function() { - var coordinates = [this.parsePoint_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parsePoint_()); +function Processor(config) { + this._imageOps = !!config.imageOps; + var threads; + if (config.threads === 0) { + threads = 0; + } else if (this._imageOps) { + threads = 1; + } else { + threads = config.threads || 1; } - return coordinates; -}; - + var workers = []; + if (threads) { + for (var i = 0; i < threads; ++i) { + workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i)); + } + } else { + workers[0] = createFauxWorker(config, this._onWorkerMessage.bind(this, 0)); + } + this._workers = workers; + this._queue = []; + this._maxQueueLength = config.queue || Infinity; + this._running = 0; + this._dataLookup = {}; + this._job = null; +} /** - * @return {!Array.<!Array.<number>>} An array of points. - * @private + * Run operation on input data. + * @param {Array.<Array|ImageData>} inputs Array of pixels or image data + * (depending on the operation type). + * @param {Object} meta A user data object. This is passed to all operations + * and must be serializable. + * @param {function(Error, ImageData, Object)} callback Called when work + * completes. The first argument is any error. The second is the ImageData + * generated by operations. The third is the user data object. */ -ol.format.WKT.Parser.prototype.parsePointTextList_ = function() { - var coordinates = [this.parsePointText_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parsePointText_()); - } - return coordinates; +Processor.prototype.process = function(inputs, meta, callback) { + this._enqueue({ + inputs: inputs, + meta: meta, + callback: callback + }); + this._dispatch(); }; - /** - * @return {!Array.<!Array.<number>>} An array of points. - * @private + * Stop responding to any completed work and destroy the processor. */ -ol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() { - var coordinates = [this.parseLineStringText_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parseLineStringText_()); +Processor.prototype.destroy = function() { + for (var key in this) { + this[key] = null; } - return coordinates; + this._destroyed = true; }; - /** - * @return {!Array.<!Array.<number>>} An array of points. - * @private + * Add a job to the queue. + * @param {Object} job The job. */ -ol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() { - var coordinates = [this.parsePolygonText_()]; - while (this.match(ol.format.WKT.TokenType.COMMA)) { - coordinates.push(this.parsePolygonText_()); +Processor.prototype._enqueue = function(job) { + this._queue.push(job); + while (this._queue.length > this._maxQueueLength) { + this._queue.shift().callback(null, null); } - return coordinates; }; - /** - * @return {boolean} Whether the token implies an empty geometry. - * @private + * Dispatch a job. */ -ol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() { - var isEmpty = this.token_.type == ol.format.WKT.TokenType.TEXT && - this.token_.value == ol.format.WKT.EMPTY; - if (isEmpty) { - this.consume_(); +Processor.prototype._dispatch = function() { + if (this._running === 0 && this._queue.length > 0) { + var job = this._job = this._queue.shift(); + var width = job.inputs[0].width; + var height = job.inputs[0].height; + var buffers = job.inputs.map(function(input) { + return input.data.buffer; + }); + var threads = this._workers.length; + this._running = threads; + if (threads === 1) { + this._workers[0].postMessage({ + 'buffers': buffers, + 'meta': job.meta, + 'imageOps': this._imageOps, + 'width': width, + 'height': height + }, buffers); + } else { + var length = job.inputs[0].data.length; + var segmentLength = 4 * Math.ceil(length / 4 / threads); + for (var i = 0; i < threads; ++i) { + var offset = i * segmentLength; + var slices = []; + for (var j = 0, jj = buffers.length; j < jj; ++j) { + slices.push(buffers[i].slice(offset, offset + segmentLength)); + } + this._workers[i].postMessage({ + 'buffers': slices, + 'meta': job.meta, + 'imageOps': this._imageOps, + 'width': width, + 'height': height + }, slices); + } + } } - return isEmpty; }; - /** - * Create an error message for an unexpected token error. - * @return {string} Error message. - * @private + * Handle messages from the worker. + * @param {number} index The worker index. + * @param {Object} event The message event. */ -ol.format.WKT.Parser.prototype.formatErrorMessage_ = function() { - return 'Unexpected `' + this.token_.value + '` at position ' + - this.token_.position + ' in `' + this.lexer_.wkt + '`'; +Processor.prototype._onWorkerMessage = function(index, event) { + if (this._destroyed) { + return; + } + this._dataLookup[index] = event.data; + --this._running; + if (this._running === 0) { + this._resolveJob(); + } }; - /** - * @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout.<string>=)} - * @private + * Resolve a job. If there are no more worker threads, the processor callback + * will be called. */ -ol.format.WKT.Parser.GeometryConstructor_ = { - 'POINT': ol.geom.Point, - 'LINESTRING': ol.geom.LineString, - 'POLYGON': ol.geom.Polygon, - 'MULTIPOINT': ol.geom.MultiPoint, - 'MULTILINESTRING': ol.geom.MultiLineString, - 'MULTIPOLYGON': ol.geom.MultiPolygon +Processor.prototype._resolveJob = function() { + var job = this._job; + var threads = this._workers.length; + var data, meta; + if (threads === 1) { + data = new Uint8ClampedArray(this._dataLookup[0]['buffer']); + meta = this._dataLookup[0]['meta']; + } else { + var length = job.inputs[0].data.length; + data = new Uint8ClampedArray(length); + meta = new Array(length); + var segmentLength = 4 * Math.ceil(length / 4 / threads); + for (var i = 0; i < threads; ++i) { + var buffer = this._dataLookup[i]['buffer']; + var offset = i * segmentLength; + data.set(new Uint8ClampedArray(buffer), offset); + meta[i] = this._dataLookup[i]['meta']; + } + } + this._job = null; + this._dataLookup = {}; + job.callback(null, + new ImageData(data, job.inputs[0].width, job.inputs[0].height), meta); + this._dispatch(); }; +module.exports = Processor; -/** - * @enum {(function(): Array)} - * @private - */ -ol.format.WKT.Parser.GeometryParser_ = { - 'POINT': ol.format.WKT.Parser.prototype.parsePointText_, - 'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_, - 'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_, - 'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_, - 'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_, - 'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_ -}; +},{}]},{},[1])(1) +}); +ol.ext.pixelworks = module.exports; +})(); -goog.provide('ol.format.WMSCapabilities'); +goog.provide('ol.source.Raster'); +goog.provide('ol.source.RasterEvent'); +goog.provide('ol.source.RasterEventType'); goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); +goog.require('goog.events'); +goog.require('goog.events.Event'); +goog.require('goog.events.EventType'); goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.format.XLink'); -goog.require('ol.format.XML'); -goog.require('ol.format.XSD'); -goog.require('ol.xml'); +goog.require('goog.vec.Mat4'); +goog.require('ol.ImageCanvas'); +goog.require('ol.TileQueue'); +goog.require('ol.dom'); +goog.require('ol.ext.pixelworks'); +goog.require('ol.extent'); +goog.require('ol.layer.Image'); +goog.require('ol.layer.Tile'); +goog.require('ol.raster.OperationType'); +goog.require('ol.renderer.canvas.ImageLayer'); +goog.require('ol.renderer.canvas.TileLayer'); +goog.require('ol.source.Image'); +goog.require('ol.source.State'); +goog.require('ol.source.Tile'); /** * @classdesc - * Format for reading WMS capabilities data + * A source that transforms data from any number of input sources using an array + * of {@link ol.raster.Operation} functions to transform input pixel values into + * output pixel values. * * @constructor - * @extends {ol.format.XML} + * @extends {ol.source.Image} + * @param {olx.source.RasterOptions} options Options. * @api */ -ol.format.WMSCapabilities = function() { - - goog.base(this); +ol.source.Raster = function(options) { /** - * @type {string|undefined} + * @private + * @type {*} */ - this.version = undefined; -}; -goog.inherits(ol.format.WMSCapabilities, ol.format.XML); + this.worker_ = null; + /** + * @private + * @type {ol.raster.OperationType} + */ + this.operationType_ = options.operationType !== undefined ? + options.operationType : ol.raster.OperationType.PIXEL; -/** - * Read a WMS capabilities document. - * - * @function - * @param {Document|Node|string} source The XML source. - * @return {Object} An object representing the WMS capabilities. - * @api - */ -ol.format.WMSCapabilities.prototype.read; + /** + * @private + * @type {number} + */ + this.threads_ = options.threads !== undefined ? options.threads : 1; + /** + * @private + * @type {Array.<ol.renderer.canvas.Layer>} + */ + this.renderers_ = ol.source.Raster.createRenderers_(options.sources); -/** - * @param {Document} doc Document. - * @return {Object} WMS Capability object. - */ -ol.format.WMSCapabilities.prototype.readFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFromNode(n); - } + for (var r = 0, rr = this.renderers_.length; r < rr; ++r) { + goog.events.listen(this.renderers_[r], goog.events.EventType.CHANGE, + this.changed, false, this); } - return null; -}; + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.canvasContext_ = ol.dom.createCanvasContext2D(); -/** - * @param {Node} node Node. - * @return {Object} WMS Capability object. - */ -ol.format.WMSCapabilities.prototype.readFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'WMS_Capabilities' || - node.localName == 'WMT_MS_Capabilities', - 'localName should be WMS_Capabilities or WMT_MS_Capabilities'); - this.version = node.getAttribute('version').trim(); - goog.asserts.assertString(this.version, 'this.version should be a string'); - var wmsCapabilityObject = ol.xml.pushParseAndPop({ - 'version': this.version - }, ol.format.WMSCapabilities.PARSERS_, node, []); - return wmsCapabilityObject ? wmsCapabilityObject : null; -}; + /** + * @private + * @type {ol.TileQueue} + */ + this.tileQueue_ = new ol.TileQueue( + function() { return 1; }, + goog.bind(this.changed, this)); + var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_); + var layerStates = {}; + for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) { + layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i]; + } -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Attribution object. - */ -ol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Attribution', - 'localName should be Attribution'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack); -}; + /** + * The most recently rendered state. + * @type {?ol.source.Raster.RenderedState} + * @private + */ + this.renderedState_ = null; + /** + * The most recently rendered image canvas. + * @type {ol.ImageCanvas} + * @private + */ + this.renderedImageCanvas_ = null; -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object} Bounding box object. - */ -ol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'BoundingBox', - 'localName should be BoundingBox'); + /** + * @private + * @type {olx.FrameState} + */ + this.frameState_ = { + animate: false, + attributions: {}, + coordinateToPixelMatrix: goog.vec.Mat4.createNumber(), + extent: null, + focus: null, + index: 0, + layerStates: layerStates, + layerStatesArray: layerStatesArray, + logos: {}, + pixelRatio: 1, + pixelToCoordinateMatrix: goog.vec.Mat4.createNumber(), + postRenderFunctions: [], + size: [0, 0], + skippedFeatureUids: {}, + tileQueue: this.tileQueue_, + time: Date.now(), + usedTiles: {}, + viewState: /** @type {olx.ViewState} */ ({ + rotation: 0 + }), + viewHints: [], + wantedTiles: {} + }; - var extent = [ - ol.format.XSD.readDecimalString(node.getAttribute('minx')), - ol.format.XSD.readDecimalString(node.getAttribute('miny')), - ol.format.XSD.readDecimalString(node.getAttribute('maxx')), - ol.format.XSD.readDecimalString(node.getAttribute('maxy')) - ]; + goog.base(this, {}); - var resolutions = [ - ol.format.XSD.readDecimalString(node.getAttribute('resx')), - ol.format.XSD.readDecimalString(node.getAttribute('resy')) - ]; + if (options.operation !== undefined) { + this.setOperation(options.operation, options.lib); + } - return { - 'crs': node.getAttribute('CRS'), - 'extent': extent, - 'res': resolutions - }; }; +goog.inherits(ol.source.Raster, ol.source.Image); /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {ol.Extent|undefined} Bounding box object. + * Set the operation. + * @param {ol.raster.Operation} operation New operation. + * @param {Object=} opt_lib Functions that will be available to operations run + * in a worker. + * @api */ -ol.format.WMSCapabilities.readEXGeographicBoundingBox_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'EX_GeographicBoundingBox', - 'localName should be EX_GeographicBoundingBox'); - var geographicBoundingBox = ol.xml.pushParseAndPop( - {}, - ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_, - node, objectStack); - if (!geographicBoundingBox) { - return undefined; - } - var westBoundLongitude = /** @type {number|undefined} */ - (geographicBoundingBox['westBoundLongitude']); - var southBoundLatitude = /** @type {number|undefined} */ - (geographicBoundingBox['southBoundLatitude']); - var eastBoundLongitude = /** @type {number|undefined} */ - (geographicBoundingBox['eastBoundLongitude']); - var northBoundLatitude = /** @type {number|undefined} */ - (geographicBoundingBox['northBoundLatitude']); - if (westBoundLongitude === undefined || southBoundLatitude === undefined || - eastBoundLongitude === undefined || northBoundLatitude === undefined) { - return undefined; - } - return /** @type {ol.Extent} */ ([ - westBoundLongitude, southBoundLatitude, - eastBoundLongitude, northBoundLatitude - ]); +ol.source.Raster.prototype.setOperation = function(operation, opt_lib) { + this.worker_ = new ol.ext.pixelworks.Processor({ + operation: operation, + imageOps: this.operationType_ === ol.raster.OperationType.IMAGE, + queue: 1, + lib: opt_lib, + threads: this.threads_ + }); + this.changed(); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Update the stored frame state. + * @param {ol.Extent} extent The view extent (in map units). + * @param {number} resolution The view resolution. + * @param {ol.proj.Projection} projection The view projection. + * @return {olx.FrameState} The updated frame state. * @private - * @return {Object|undefined} Capability object. */ -ol.format.WMSCapabilities.readCapability_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Capability', - 'localName should be Capability'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack); -}; +ol.source.Raster.prototype.updateFrameState_ = + function(extent, resolution, projection) { + var frameState = /** @type {olx.FrameState} */ ( + goog.object.clone(this.frameState_)); -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Service object. - */ -ol.format.WMSCapabilities.readService_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Service', - 'localName should be Service'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack); + frameState.viewState = /** @type {olx.ViewState} */ ( + goog.object.clone(frameState.viewState)); + + var center = ol.extent.getCenter(extent); + var width = Math.round(ol.extent.getWidth(extent) / resolution); + var height = Math.round(ol.extent.getHeight(extent) / resolution); + + frameState.extent = extent; + frameState.focus = ol.extent.getCenter(extent); + frameState.size[0] = width; + frameState.size[1] = height; + + var viewState = frameState.viewState; + viewState.center = center; + viewState.projection = projection; + viewState.resolution = resolution; + return frameState; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Determine if the most recently rendered image canvas is dirty. + * @param {ol.Extent} extent The requested extent. + * @param {number} resolution The requested resolution. + * @return {boolean} The image is dirty. * @private - * @return {Object|undefined} Contact information object. */ -ol.format.WMSCapabilities.readContactInformation_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType shpuld be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactInformation', - 'localName should be ContactInformation'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_, - node, objectStack); +ol.source.Raster.prototype.isDirty_ = function(extent, resolution) { + var state = this.renderedState_; + return !state || + this.getRevision() !== state.revision || + resolution !== state.resolution || + !ol.extent.equals(extent, state.extent); }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Contact person object. + * @inheritDoc */ -ol.format.WMSCapabilities.readContactPersonPrimary_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactPersonPrimary', - 'localName should be ContactPersonPrimary'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_, - node, objectStack); -}; +ol.source.Raster.prototype.getImage = + function(extent, resolution, pixelRatio, projection) { + if (!this.allSourcesReady_()) { + return null; + } -/** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @private - * @return {Object|undefined} Contact address object. - */ -ol.format.WMSCapabilities.readContactAddress_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'ContactAddress', - 'localName should be ContactAddress'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_, - node, objectStack); + if (!this.isDirty_(extent, resolution)) { + return this.renderedImageCanvas_; + } + + var context = this.canvasContext_; + var canvas = context.canvas; + + var width = Math.round(ol.extent.getWidth(extent) / resolution); + var height = Math.round(ol.extent.getHeight(extent) / resolution); + + if (width !== canvas.width || + height !== canvas.height) { + canvas.width = width; + canvas.height = height; + } + + var frameState = this.updateFrameState_(extent, resolution, projection); + + var imageCanvas = new ol.ImageCanvas( + extent, resolution, 1, this.getAttributions(), canvas, + this.composeFrame_.bind(this, frameState)); + + this.renderedImageCanvas_ = imageCanvas; + + this.renderedState_ = { + extent: extent, + resolution: resolution, + revision: this.getRevision() + }; + + return imageCanvas; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Determine if all sources are ready. + * @return {boolean} All sources are ready. * @private - * @return {Array.<string>|undefined} Format array. */ -ol.format.WMSCapabilities.readException_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Exception', - 'localName should be Exception'); - return ol.xml.pushParseAndPop( - [], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack); +ol.source.Raster.prototype.allSourcesReady_ = function() { + var ready = true; + var source; + for (var i = 0, ii = this.renderers_.length; i < ii; ++i) { + source = this.renderers_[i].getLayer().getSource(); + if (source.getState() !== ol.source.State.READY) { + ready = false; + break; + } + } + return ready; }; /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. + * Compose the frame. This renders data from all sources, runs pixel-wise + * operations, and renders the result to the stored canvas context. + * @param {olx.FrameState} frameState The frame state. + * @param {function(Error)} callback Called when composition is complete. * @private - * @return {Object|undefined} Layer object. */ -ol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack); +ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) { + var len = this.renderers_.length; + var imageDatas = new Array(len); + for (var i = 0; i < len; ++i) { + var imageData = ol.source.Raster.getImageData_( + this.renderers_[i], frameState, frameState.layerStatesArray[i]); + if (imageData) { + imageDatas[i] = imageData; + } else { + // image not yet ready + return; + } + } + + var data = {}; + this.dispatchEvent(new ol.source.RasterEvent( + ol.source.RasterEventType.BEFOREOPERATIONS, frameState, data)); + + this.worker_.process(imageDatas, data, + this.onWorkerComplete_.bind(this, frameState, callback)); + + frameState.tileQueue.loadMoreTiles(16, 16); }; /** + * Called when pixel processing is complete. + * @param {olx.FrameState} frameState The frame state. + * @param {function(Error)} callback Called when rendering is complete. + * @param {Error} err Any error during processing. + * @param {ImageData} output The output image data. + * @param {Object} data The user data. * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Layer object. */ -ol.format.WMSCapabilities.readLayer_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); - var parentLayerObject = /** @type {Object.<string,*>} */ - (objectStack[objectStack.length - 1]); - - var layerObject = /** @type {Object.<string,*>} */ (ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack)); - - if (!layerObject) { - return undefined; +ol.source.Raster.prototype.onWorkerComplete_ = + function(frameState, callback, err, output, data) { + if (err) { + callback(err); + return; } - var queryable = - ol.format.XSD.readBooleanString(node.getAttribute('queryable')); - if (queryable === undefined) { - queryable = parentLayerObject['queryable']; + if (!output) { + // job aborted + return; } - layerObject['queryable'] = queryable !== undefined ? queryable : false; - var cascaded = ol.format.XSD.readNonNegativeIntegerString( - node.getAttribute('cascaded')); - if (cascaded === undefined) { - cascaded = parentLayerObject['cascaded']; - } - layerObject['cascaded'] = cascaded; + this.dispatchEvent(new ol.source.RasterEvent( + ol.source.RasterEventType.AFTEROPERATIONS, frameState, data)); - var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque')); - if (opaque === undefined) { - opaque = parentLayerObject['opaque']; + var resolution = frameState.viewState.resolution / frameState.pixelRatio; + if (!this.isDirty_(frameState.extent, resolution)) { + this.canvasContext_.putImageData(output, 0, 0); } - layerObject['opaque'] = opaque !== undefined ? opaque : false; - var noSubsets = - ol.format.XSD.readBooleanString(node.getAttribute('noSubsets')); - if (noSubsets === undefined) { - noSubsets = parentLayerObject['noSubsets']; - } - layerObject['noSubsets'] = noSubsets !== undefined ? noSubsets : false; + callback(null); +}; - var fixedWidth = - ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth')); - if (!fixedWidth) { - fixedWidth = parentLayerObject['fixedWidth']; - } - layerObject['fixedWidth'] = fixedWidth; - var fixedHeight = - ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight')); - if (!fixedHeight) { - fixedHeight = parentLayerObject['fixedHeight']; +/** + * Get image data from a renderer. + * @param {ol.renderer.canvas.Layer} renderer Layer renderer. + * @param {olx.FrameState} frameState The frame state. + * @param {ol.layer.LayerState} layerState The layer state. + * @return {ImageData} The image data. + * @private + */ +ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) { + renderer.prepareFrame(frameState, layerState); + // We should be able to call renderer.composeFrame(), but this is inefficient + // for tiled sources (we've already rendered to an intermediate canvas in the + // prepareFrame call and we don't need to render again to the output canvas). + // TODO: make all canvas renderers render to a single canvas + var image = renderer.getImage(); + if (!image) { + return null; } - layerObject['fixedHeight'] = fixedHeight; - - // See 7.2.4.8 - var addKeys = ['Style', 'CRS', 'AuthorityURL']; - addKeys.forEach(function(key) { - if (key in parentLayerObject) { - var childValue = goog.object.setIfUndefined(layerObject, key, []); - childValue = childValue.concat(parentLayerObject[key]); - layerObject[key] = childValue; + var imageTransform = renderer.getImageTransform(); + var dx = Math.round(goog.vec.Mat4.getElement(imageTransform, 0, 3)); + var dy = Math.round(goog.vec.Mat4.getElement(imageTransform, 1, 3)); + var width = frameState.size[0]; + var height = frameState.size[1]; + if (image instanceof Image) { + if (!ol.source.Raster.context_) { + ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); + } else { + var canvas = ol.source.Raster.context_.canvas; + if (canvas.width !== width || canvas.height !== height) { + ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); + } else { + ol.source.Raster.context_.clearRect(0, 0, width, height); + } } - }); + var dw = Math.round( + image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0)); + var dh = Math.round( + image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1)); + ol.source.Raster.context_.drawImage(image, dx, dy, dw, dh); + return ol.source.Raster.context_.getImageData(0, 0, width, height); + } else { + return image.getContext('2d').getImageData(-dx, -dy, width, height); + } +}; - var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension', - 'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator']; - replaceKeys.forEach(function(key) { - if (!(key in layerObject)) { - var parentValue = parentLayerObject[key]; - layerObject[key] = parentValue; - } - }); - return layerObject; -}; +/** + * A reusable canvas context. + * @type {CanvasRenderingContext2D} + * @private + */ +ol.source.Raster.context_ = null; /** + * Get a list of layer states from a list of renderers. + * @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers. + * @return {Array.<ol.layer.LayerState>} The layer states. * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object} Dimension object. */ -ol.format.WMSCapabilities.readDimension_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Dimension', - 'localName should be Dimension'); - var dimensionObject = { - 'name': node.getAttribute('name'), - 'units': node.getAttribute('units'), - 'unitSymbol': node.getAttribute('unitSymbol'), - 'default': node.getAttribute('default'), - 'multipleValues': ol.format.XSD.readBooleanString( - node.getAttribute('multipleValues')), - 'nearestValue': ol.format.XSD.readBooleanString( - node.getAttribute('nearestValue')), - 'current': ol.format.XSD.readBooleanString(node.getAttribute('current')), - 'values': ol.format.XSD.readString(node) - }; - return dimensionObject; +ol.source.Raster.getLayerStatesArray_ = function(renderers) { + return renderers.map(function(renderer) { + return renderer.getLayer().getLayerState(); + }); }; /** + * Create renderers for all sources. + * @param {Array.<ol.source.Source>} sources The sources. + * @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers. * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Online resource object. */ -ol.format.WMSCapabilities.readFormatOnlineresource_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_, - node, objectStack); +ol.source.Raster.createRenderers_ = function(sources) { + var len = sources.length; + var renderers = new Array(len); + for (var i = 0; i < len; ++i) { + renderers[i] = ol.source.Raster.createRenderer_(sources[i]); + } + return renderers; }; /** + * Create a renderer for the provided source. + * @param {ol.source.Source} source The source. + * @return {ol.renderer.canvas.Layer} The renderer. * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Request object. */ -ol.format.WMSCapabilities.readRequest_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Request', - 'localName should be Request'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack); +ol.source.Raster.createRenderer_ = function(source) { + var renderer = null; + if (source instanceof ol.source.Tile) { + renderer = ol.source.Raster.createTileRenderer_(source); + } else if (source instanceof ol.source.Image) { + renderer = ol.source.Raster.createImageRenderer_(source); + } else { + goog.asserts.fail('Unsupported source type: ' + source); + } + return renderer; }; /** + * Create an image renderer for the provided source. + * @param {ol.source.Image} source The source. + * @return {ol.renderer.canvas.Layer} The renderer. * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} DCP type object. */ -ol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'DCPType', - 'localName should be DCPType'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack); +ol.source.Raster.createImageRenderer_ = function(source) { + var layer = new ol.layer.Image({source: source}); + return new ol.renderer.canvas.ImageLayer(layer); }; /** + * Create a tile renderer for the provided source. + * @param {ol.source.Tile} source The source. + * @return {ol.renderer.canvas.Layer} The renderer. * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} HTTP object. */ -ol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack); +ol.source.Raster.createTileRenderer_ = function(source) { + var layer = new ol.layer.Tile({source: source}); + return new ol.renderer.canvas.TileLayer(layer); }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Operation type object. + * @typedef {{revision: number, + * resolution: number, + * extent: ol.Extent}} */ -ol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack); +ol.source.Raster.RenderedState; + + + +/** + * @classdesc + * Events emitted by {@link ol.source.Raster} instances are instances of this + * type. + * + * @constructor + * @extends {goog.events.Event} + * @implements {oli.source.RasterEvent} + * @param {string} type Type. + * @param {olx.FrameState} frameState The frame state. + * @param {Object} data An object made available to operations. + */ +ol.source.RasterEvent = function(type, frameState, data) { + goog.base(this, type); + + /** + * The raster extent. + * @type {ol.Extent} + * @api + */ + this.extent = frameState.extent; + + /** + * The pixel resolution (map units per pixel). + * @type {number} + * @api + */ + this.resolution = frameState.viewState.resolution / frameState.pixelRatio; + + /** + * An object made available to all operations. This can be used by operations + * as a storage object (e.g. for calculating statistics). + * @type {Object} + * @api + */ + this.data = data; + }; +goog.inherits(ol.source.RasterEvent, goog.events.Event); /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Online resource object. + * @enum {string} */ -ol.format.WMSCapabilities.readSizedFormatOnlineresource_ = - function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var formatOnlineresource = - ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); - if (formatOnlineresource) { - var size = [ - ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')), - ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height')) - ]; - formatOnlineresource['size'] = size; - return formatOnlineresource; +ol.source.RasterEventType = { + /** + * Triggered before operations are run. + * @event ol.source.RasterEvent#beforeoperations + * @api + */ + BEFOREOPERATIONS: 'beforeoperations', + + /** + * Triggered after operations are run. + * @event ol.source.RasterEvent#afteroperations + * @api + */ + AFTEROPERATIONS: 'afteroperations' +}; + +goog.provide('ol.source.Stamen'); + +goog.require('goog.asserts'); +goog.require('ol.Attribution'); +goog.require('ol.source.OSM'); +goog.require('ol.source.XYZ'); + + +/** + * @type {Object.<string, {extension: string, opaque: boolean}>} + */ +ol.source.StamenLayerConfig = { + 'terrain': { + extension: 'jpg', + opaque: true + }, + 'terrain-background': { + extension: 'jpg', + opaque: true + }, + 'terrain-labels': { + extension: 'png', + opaque: false + }, + 'terrain-lines': { + extension: 'png', + opaque: false + }, + 'toner-background': { + extension: 'png', + opaque: true + }, + 'toner': { + extension: 'png', + opaque: true + }, + 'toner-hybrid': { + extension: 'png', + opaque: false + }, + 'toner-labels': { + extension: 'png', + opaque: false + }, + 'toner-lines': { + extension: 'png', + opaque: false + }, + 'toner-lite': { + extension: 'png', + opaque: true + }, + 'watercolor': { + extension: 'jpg', + opaque: true } - return undefined; }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Authority URL object. + * @type {Object.<string, {minZoom: number, maxZoom: number}>} */ -ol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'AuthorityURL', - 'localName should be AuthorityURL'); - var authorityObject = - ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); - if (authorityObject) { - authorityObject['name'] = node.getAttribute('name'); - return authorityObject; +ol.source.StamenProviderConfig = { + 'terrain': { + minZoom: 4, + maxZoom: 18 + }, + 'toner': { + minZoom: 0, + maxZoom: 20 + }, + 'watercolor': { + minZoom: 3, + maxZoom: 16 } - return undefined; }; + /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Metadata URL object. + * @classdesc + * Layer source for the Stamen tile server. + * + * @constructor + * @extends {ol.source.XYZ} + * @param {olx.source.StamenOptions} options Stamen options. + * @api stable */ -ol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'MetadataURL', - 'localName should be MetadataURL'); - var metadataObject = - ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack); - if (metadataObject) { - metadataObject['type'] = node.getAttribute('type'); - return metadataObject; - } - return undefined; -}; +ol.source.Stamen = function(options) { + var i = options.layer.indexOf('-'); + var provider = i == -1 ? options.layer : options.layer.slice(0, i); + goog.asserts.assert(provider in ol.source.StamenProviderConfig, + 'known provider configured'); + var providerConfig = ol.source.StamenProviderConfig[provider]; -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Style object. - */ -ol.format.WMSCapabilities.readStyle_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Style', 'localName should be Style'); - return ol.xml.pushParseAndPop( - {}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack); -}; + goog.asserts.assert(options.layer in ol.source.StamenLayerConfig, + 'known layer configured'); + var layerConfig = ol.source.StamenLayerConfig[options.layer]; + + var url = options.url !== undefined ? options.url : + 'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer + + '/{z}/{x}/{y}.' + layerConfig.extension; + goog.base(this, { + attributions: ol.source.Stamen.ATTRIBUTIONS, + crossOrigin: 'anonymous', + maxZoom: providerConfig.maxZoom, + // FIXME uncomment the following when tilegrid supports minZoom + //minZoom: providerConfig.minZoom, + opaque: layerConfig.opaque, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileLoadFunction: options.tileLoadFunction, + url: url + }); -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<string>|undefined} Keyword list. - */ -ol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'KeywordList', - 'localName should be KeywordList'); - return ol.xml.pushParseAndPop( - [], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack); }; +goog.inherits(ol.source.Stamen, ol.source.XYZ); /** * @const - * @private - * @type {Array.<string>} + * @type {Array.<ol.Attribution>} */ -ol.format.WMSCapabilities.NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/wms' +ol.source.Stamen.ATTRIBUTIONS = [ + new ol.Attribution({ + html: 'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, ' + + 'under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY' + + ' 3.0</a>.' + }), + ol.source.OSM.ATTRIBUTION ]; +goog.provide('ol.source.TileArcGISRest'); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Service': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readService_), - 'Capability': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readCapability_) - }); - +goog.require('goog.asserts'); +goog.require('goog.math'); +goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.uri.utils'); +goog.require('ol'); +goog.require('ol.TileCoord'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.size'); +goog.require('ol.source.TileImage'); +goog.require('ol.tilecoord'); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Request': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readRequest_), - 'Exception': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readException_), - 'Layer': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readCapabilityLayer_) - }); /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @classdesc + * Layer source for tile data from ArcGIS Rest services. Map and Image + * Services are supported. + * + * For cached ArcGIS services, better performance is available using the + * {@link ol.source.XYZ} data source. + * + * @constructor + * @extends {ol.source.TileImage} + * @param {olx.source.TileArcGISRestOptions=} opt_options Tile ArcGIS Rest + * options. + * @api */ -ol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'KeywordList': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readKeywordList_), - 'OnlineResource': ol.xml.makeObjectPropertySetter( - ol.format.XLink.readHref), - 'ContactInformation': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readContactInformation_), - 'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'AccessConstraints': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'LayerLimit': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MaxWidth': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MaxHeight': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger) - }); +ol.source.TileArcGISRest = function(opt_options) { + var options = opt_options || {}; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'ContactPersonPrimary': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readContactPersonPrimary_), - 'ContactPosition': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactAddress': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readContactAddress_), - 'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); + var params = options.params !== undefined ? options.params : {}; + goog.base(this, { + attributions: options.attributions, + crossOrigin: options.crossOrigin, + logo: options.logo, + projection: options.projection, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileGrid: options.tileGrid, + tileLoadFunction: options.tileLoadFunction, + tileUrlFunction: goog.bind(this.tileUrlFunction_, this), + url: options.url, + urls: options.urls, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'ContactPerson': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'ContactOrganization': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); + /** + * @private + * @type {Object} + */ + this.params_ = params; + /** + * @private + * @type {ol.Extent} + */ + this.tmpExtent_ = ol.extent.createEmpty(); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'StateOrProvince': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString) - }); +}; +goog.inherits(ol.source.TileArcGISRest, ol.source.TileImage); /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Get the user-provided params, i.e. those passed to the constructor through + * the "params" option, and possibly updated using the updateParams method. + * @return {Object} Params. + * @api */ -ol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString) - }); +ol.source.TileArcGISRest.prototype.getParams = function() { + return this.params_; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.Size} tileSize Tile size. + * @param {ol.Extent} tileExtent Tile extent. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @param {Object} params Params. + * @return {string|undefined} Request URL. * @private */ -ol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'KeywordList': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readKeywordList_), - 'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), - 'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readEXGeographicBoundingBox_), - 'BoundingBox': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readBoundingBox_), - 'Dimension': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readDimension_), - 'Attribution': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readAttribution_), - 'AuthorityURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readAuthorityURL_), - 'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), - 'MetadataURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readMetadataURL_), - 'DataURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'FeatureListURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'Style': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readStyle_), - 'MinScaleDenominator': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'MaxScaleDenominator': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'Layer': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readLayer_) - }); - +ol.source.TileArcGISRest.prototype.getRequestUrl_ = + function(tileCoord, tileSize, tileExtent, + pixelRatio, projection, params) { -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'OnlineResource': ol.xml.makeObjectPropertySetter( - ol.format.XLink.readHref), - 'LogoURL': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readSizedFormatOnlineresource_) - }); + var urls = this.urls; + if (!urls) { + return undefined; + } + // ArcGIS Server only wants the numeric portion of the projection ID. + var srid = projection.getCode().split(':').pop(); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ = - ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'westBoundLongitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'eastBoundLongitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'southBoundLatitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'northBoundLatitude': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal) - }); + params['SIZE'] = tileSize[0] + ',' + tileSize[1]; + params['BBOX'] = tileExtent.join(','); + params['BBOXSR'] = srid; + params['IMAGESR'] = srid; + params['DPI'] = Math.round(90 * pixelRatio); + var url; + if (urls.length == 1) { + url = urls[0]; + } else { + var index = goog.math.modulo(ol.tilecoord.hash(tileCoord), urls.length); + url = urls[index]; + } -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'GetCapabilities': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readOperationType_), - 'GetMap': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readOperationType_), - 'GetFeatureInfo': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readOperationType_) - }); + if (!goog.string.endsWith(url, '/')) { + url = url + '/'; + } + // If a MapServer, use export. If an ImageServer, use exportImage. + if (goog.string.endsWith(url, 'MapServer/')) { + url = url + 'export'; + } + else if (goog.string.endsWith(url, 'ImageServer/')) { + url = url + 'exportImage'; + } + else { + goog.asserts.fail('Unknown Rest Service', url); + } -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString), - 'DCPType': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readDCPType_) - }); + return goog.uri.utils.appendParamsFromMap(url, params); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @param {number} z Z. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.Size} Size. */ -ol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'HTTP': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readHTTP_) - }); +ol.source.TileArcGISRest.prototype.getTilePixelSize = + function(z, pixelRatio, projection) { + var tileSize = goog.base(this, 'getTilePixelSize', z, pixelRatio, projection); + if (pixelRatio == 1) { + return tileSize; + } else { + return ol.size.scale(tileSize, pixelRatio, this.tmpSize); + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. * @private */ -ol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Get': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'Post': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_) - }); +ol.source.TileArcGISRest.prototype.tileUrlFunction_ = + function(tileCoord, pixelRatio, projection) { + var tileGrid = this.getTileGrid(); + if (!tileGrid) { + tileGrid = this.getTileGridForProjection(projection); + } -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'LegendURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMSCapabilities.readSizedFormatOnlineresource_), - 'StyleSheetURL': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_), - 'StyleURL': ol.xml.makeObjectPropertySetter( - ol.format.WMSCapabilities.readFormatOnlineresource_) - }); + if (tileGrid.getResolutions().length <= tileCoord[0]) { + return undefined; + } + var tileExtent = tileGrid.getTileCoordExtent( + tileCoord, this.tmpExtent_); + var tileSize = ol.size.toSize( + tileGrid.getTileSize(tileCoord[0]), this.tmpSize); -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ = - ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), - 'OnlineResource': ol.xml.makeObjectPropertySetter( - ol.format.XLink.readHref) - }); + if (pixelRatio != 1) { + tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize); + } + + // Apply default params and override with user specified values. + var baseParams = { + 'F': 'image', + 'FORMAT': 'PNG32', + 'TRANSPARENT': true + }; + goog.object.extend(baseParams, this.params_); + + return this.getRequestUrl_(tileCoord, tileSize, tileExtent, + pixelRatio, projection, baseParams); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Update the user-provided params. + * @param {Object} params Params. + * @api stable */ -ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMSCapabilities.NAMESPACE_URIS_, { - 'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString) - }); +ol.source.TileArcGISRest.prototype.updateParams = function(params) { + goog.object.extend(this.params_, params); + this.changed(); +}; -goog.provide('ol.format.WMSGetFeatureInfo'); +goog.provide('ol.source.TileDebug'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); -goog.require('goog.object'); -goog.require('ol.format.GML2'); -goog.require('ol.format.XMLFeature'); -goog.require('ol.xml'); +goog.require('ol.Tile'); +goog.require('ol.TileCoord'); +goog.require('ol.TileState'); +goog.require('ol.dom'); +goog.require('ol.size'); +goog.require('ol.source.Tile'); +goog.require('ol.tilecoord'); /** - * @classdesc - * Format for reading WMSGetFeatureInfo format. It uses - * {@link ol.format.GML2} to read features. - * * @constructor - * @extends {ol.format.XMLFeature} - * @api + * @extends {ol.Tile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.Size} tileSize Tile size. + * @param {string} text Text. + * @private */ -ol.format.WMSGetFeatureInfo = function() { +ol.DebugTile_ = function(tileCoord, tileSize, text) { + + goog.base(this, tileCoord, ol.TileState.LOADED); /** * @private - * @type {string} + * @type {ol.Size} */ - this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver'; + this.tileSize_ = tileSize; + /** + * @private + * @type {string} + */ + this.text_ = text; /** * @private - * @type {ol.format.GML2} + * @type {Object.<number, HTMLCanvasElement>} */ - this.gmlFormat_ = new ol.format.GML2(); + this.canvasByContext_ = {}; - goog.base(this); }; -goog.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature); - - -/** - * @const - * @type {string} - * @private - */ -ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature'; - - -/** - * @const - * @type {string} - * @private - */ -ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer'; +goog.inherits(ol.DebugTile_, ol.Tile); /** - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Array.<ol.Feature>} Features. - * @private + * Get the image element for this tile. + * @param {Object=} opt_context Optional context. Only used by the DOM + * renderer. + * @return {HTMLCanvasElement} Image. */ -ol.format.WMSGetFeatureInfo.prototype.readFeatures_ = - function(node, objectStack) { +ol.DebugTile_.prototype.getImage = function(opt_context) { + var key = opt_context !== undefined ? goog.getUid(opt_context) : -1; + if (key in this.canvasByContext_) { + return this.canvasByContext_[key]; + } else { - node.namespaceURI = this.featureNS_; - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - var localName = ol.xml.getLocalName(node); - /** @type {Array.<ol.Feature>} */ - var features = []; - if (node.childNodes.length === 0) { - return features; - } - if (localName == 'msGMLOutput') { - for (var i = 0, ii = node.childNodes.length; i < ii; i++) { - var layer = node.childNodes[i]; - if (layer.nodeType !== goog.dom.NodeType.ELEMENT) { - continue; - } - var context = objectStack[0]; - goog.asserts.assert(goog.isObject(context), - 'context should be an Object'); + var tileSize = this.tileSize_; + var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]); - goog.asserts.assert(layer.localName.indexOf( - ol.format.WMSGetFeatureInfo.layerIdentifier_) >= 0, - 'localName of layer node should match layerIdentifier'); + context.strokeStyle = 'black'; + context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); - var toRemove = ol.format.WMSGetFeatureInfo.layerIdentifier_; - var featureType = layer.localName.replace(toRemove, '') + - ol.format.WMSGetFeatureInfo.featureIdentifier_; + context.fillStyle = 'black'; + context.textAlign = 'center'; + context.textBaseline = 'middle'; + context.font = '24px sans-serif'; + context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2); - context['featureType'] = featureType; - context['featureNS'] = this.featureNS_; + this.canvasByContext_[key] = context.canvas; + return context.canvas; - var parsers = {}; - parsers[featureType] = ol.xml.makeArrayPusher( - this.gmlFormat_.readFeatureElement, this.gmlFormat_); - var parsersNS = ol.xml.makeStructureNS( - [context['featureNS'], null], parsers); - layer.namespaceURI = this.featureNS_; - var layerFeatures = ol.xml.pushParseAndPop( - [], parsersNS, layer, objectStack, this.gmlFormat_); - if (layerFeatures) { - goog.array.extend(features, layerFeatures); - } - } - } - if (localName == 'FeatureCollection') { - var gmlFeatures = ol.xml.pushParseAndPop([], - this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node, - [{}], this.gmlFormat_); - if (gmlFeatures) { - features = gmlFeatures; - } } - return features; }; + /** - * Read all features from a WMSGetFeatureInfo response. + * @classdesc + * A pseudo tile source, which does not fetch tiles from a server, but renders + * a grid outline for the tile grid/projection along with the coordinates for + * each tile. See examples/canvas-tiles for an example. * - * @function - * @param {Document|Node|Object|string} source Source. - * @param {olx.format.ReadOptions=} opt_options Options. - * @return {Array.<ol.Feature>} Features. - * @api stable + * Uses Canvas context2d, so requires Canvas support. + * + * @constructor + * @extends {ol.source.Tile} + * @param {olx.source.TileDebugOptions} options Debug tile options. + * @api */ -ol.format.WMSGetFeatureInfo.prototype.readFeatures; +ol.source.TileDebug = function(options) { + + goog.base(this, { + opaque: false, + projection: options.projection, + tileGrid: options.tileGrid, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); + +}; +goog.inherits(ol.source.TileDebug, ol.source.Tile); /** * @inheritDoc */ -ol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode = - function(node, opt_options) { - var options = { - 'featureType': this.featureType, - 'featureNS': this.featureNS - }; - if (opt_options) { - goog.object.extend(options, this.getReadOptions(node, opt_options)); +ol.source.TileDebug.prototype.getTile = function(z, x, y) { + var tileCoordKey = this.getKeyZXY(z, x, y); + if (this.tileCache.containsKey(tileCoordKey)) { + return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey)); + } else { + var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z)); + var tileCoord = [z, x, y]; + var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord); + var text = !textTileCoord ? '' : ol.tilecoord.toString( + this.getTileCoordForTileUrlFunction(textTileCoord)); + var tile = new ol.DebugTile_(tileCoord, tileSize, text); + this.tileCache.set(tileCoordKey, tile); + return tile; } - return this.readFeatures_(node, [options]); }; -goog.provide('ol.format.WMTSCapabilities'); +// FIXME check order of async callbacks + +/** + * @see http://mapbox.com/developers/api/ + */ + +goog.provide('ol.source.TileJSON'); +goog.provide('ol.tilejson'); goog.require('goog.asserts'); -goog.require('goog.dom.NodeType'); +goog.require('goog.net.Jsonp'); +goog.require('ol.Attribution'); +goog.require('ol.TileRange'); +goog.require('ol.TileUrlFunction'); goog.require('ol.extent'); -goog.require('ol.format.OWS'); -goog.require('ol.format.XLink'); -goog.require('ol.format.XML'); -goog.require('ol.format.XSD'); -goog.require('ol.xml'); +goog.require('ol.proj'); +goog.require('ol.source.State'); +goog.require('ol.source.TileImage'); /** * @classdesc - * Format for reading WMTS capabilities data. + * Layer source for tile data in TileJSON format. * * @constructor - * @extends {ol.format.XML} - * @api + * @extends {ol.source.TileImage} + * @param {olx.source.TileJSONOptions} options TileJSON options. + * @api stable */ -ol.format.WMTSCapabilities = function() { - goog.base(this); +ol.source.TileJSON = function(options) { + + goog.base(this, { + attributions: options.attributions, + crossOrigin: options.crossOrigin, + projection: ol.proj.get('EPSG:3857'), + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + state: ol.source.State.LOADING, + tileLoadFunction: options.tileLoadFunction, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); + + var request = new goog.net.Jsonp(options.url); + request.send(undefined, goog.bind(this.handleTileJSONResponse, this), + goog.bind(this.handleTileJSONError, this)); - /** - * @type {ol.format.OWS} - * @private - */ - this.owsParser_ = new ol.format.OWS(); }; -goog.inherits(ol.format.WMTSCapabilities, ol.format.XML); +goog.inherits(ol.source.TileJSON, ol.source.TileImage); /** - * Read a WMTS capabilities document. - * - * @function - * @param {Document|Node|string} source The XML source. - * @return {Object} An object representing the WMTS capabilities. - * @api + * @protected + * @param {TileJSON} tileJSON Tile JSON. */ -ol.format.WMTSCapabilities.prototype.read; +ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) { + var epsg4326Projection = ol.proj.get('EPSG:4326'); -/** - * @param {Document} doc Document. - * @return {Object} WMTS Capability object. - */ -ol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) { - goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT, - 'doc.nodeType should be DOCUMENT'); - for (var n = doc.firstChild; n; n = n.nextSibling) { - if (n.nodeType == goog.dom.NodeType.ELEMENT) { - return this.readFromNode(n); - } + var sourceProjection = this.getProjection(); + var extent; + if (tileJSON.bounds !== undefined) { + var transform = ol.proj.getTransformFromProjections( + epsg4326Projection, sourceProjection); + extent = ol.extent.applyTransform(tileJSON.bounds, transform); } - return null; -}; - -/** - * @param {Node} node Node. - * @return {Object} WMTS Capability object. - */ -ol.format.WMTSCapabilities.prototype.readFromNode = function(node) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Capabilities', - 'localName should be Capabilities'); - this.version = node.getAttribute('version').trim(); - goog.asserts.assertString(this.version, 'this.version should be a string'); - var WMTSCapabilityObject = this.owsParser_.readFromNode(node); - if (!WMTSCapabilityObject) { - return null; + if (tileJSON.scheme !== undefined) { + goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"'); } - WMTSCapabilityObject['version'] = this.version; - WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject, - ol.format.WMTSCapabilities.PARSERS_, node, []); - return WMTSCapabilityObject ? WMTSCapabilityObject : null; -}; + var minZoom = tileJSON.minzoom || 0; + var maxZoom = tileJSON.maxzoom || 22; + var tileGrid = ol.tilegrid.createXYZ({ + extent: ol.tilegrid.extentFromProjection(sourceProjection), + maxZoom: maxZoom, + minZoom: minZoom + }); + this.tileGrid = tileGrid; + this.tileUrlFunction = + ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid); -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Attribution object. - */ -ol.format.WMTSCapabilities.readContents_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Contents', - 'localName should be Contents'); + if (tileJSON.attribution !== undefined && !this.getAttributions()) { + var attributionExtent = extent !== undefined ? + extent : epsg4326Projection.getExtent(); + /** @type {Object.<string, Array.<ol.TileRange>>} */ + var tileRanges = {}; + var z, zKey; + for (z = minZoom; z <= maxZoom; ++z) { + zKey = z.toString(); + tileRanges[zKey] = + [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; + } + this.setAttributions([ + new ol.Attribution({ + html: tileJSON.attribution, + tileRanges: tileRanges + }) + ]); + } + + this.setState(ol.source.State.READY); - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack); }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Layers object. + * @protected */ -ol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) { - goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT, - 'node.nodeType should be ELEMENT'); - goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer'); - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack); +ol.source.TileJSON.prototype.handleTileJSONError = function() { + this.setState(ol.source.State.ERROR); }; +goog.provide('ol.source.TileUTFGrid'); + +goog.require('goog.asserts'); +goog.require('goog.async.nextTick'); +goog.require('goog.events'); +goog.require('goog.events.EventType'); +goog.require('goog.net.Jsonp'); +goog.require('ol.Attribution'); +goog.require('ol.Tile'); +goog.require('ol.TileState'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.source.State'); +goog.require('ol.source.Tile'); -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Tile Matrix Set object. - */ -ol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack); -}; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Style object. + * @classdesc + * Layer source for UTFGrid interaction data loaded from TileJSON format. + * + * @constructor + * @extends {ol.source.Tile} + * @param {olx.source.TileUTFGridOptions} options Source options. + * @api */ -ol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) { - var style = ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack); - if (!style) { - return undefined; - } - var isDefault = node.getAttribute('isDefault') === 'true'; - style['isDefault'] = isDefault; - return style; +ol.source.TileUTFGrid = function(options) { + goog.base(this, { + projection: ol.proj.get('EPSG:3857'), + state: ol.source.State.LOADING + }); -}; + /** + * @private + * @type {boolean} + */ + this.preemptive_ = options.preemptive !== undefined ? + options.preemptive : true; + /** + * @private + * @type {!ol.TileUrlFunctionType} + */ + this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction; -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Tile Matrix Set Link object. - */ -ol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node, - objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack); + /** + * @private + * @type {string|undefined} + */ + this.template_ = undefined; + + var request = new goog.net.Jsonp(options.url); + request.send(undefined, goog.bind(this.handleTileJSONResponse, this)); }; +goog.inherits(ol.source.TileUTFGrid, ol.source.Tile); /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Dimension object. + * Return the template from TileJSON. + * @return {string|undefined} The template from TileJSON. + * @api */ -ol.format.WMTSCapabilities.readDimensions_ = function(node, objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.DIMENSION_PARSERS_, node, objectStack); +ol.source.TileUTFGrid.prototype.getTemplate = function() { + return this.template_; }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Resource URL object. + * Calls the callback (synchronously by default) with the available data + * for given coordinate and resolution (or `null` if not yet loaded or + * in case of an error). + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {function(this: T, Object)} callback Callback. + * @param {T=} opt_this The object to use as `this` in the callback. + * @param {boolean=} opt_request If `true` the callback is always async. + * The tile data is requested if not yet loaded. + * @template T + * @api */ -ol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) { - var format = node.getAttribute('format'); - var template = node.getAttribute('template'); - var resourceType = node.getAttribute('resourceType'); - var resource = {}; - if (format) { - resource['format'] = format; - } - if (template) { - resource['template'] = template; - } - if (resourceType) { - resource['resourceType'] = resourceType; +ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function( + coordinate, resolution, callback, opt_this, opt_request) { + if (this.tileGrid) { + var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution( + coordinate, resolution); + var tile = /** @type {!ol.source.TileUTFGridTile_} */(this.getTile( + tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection())); + tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request); + } else { + if (opt_request === true) { + goog.async.nextTick(function() { + callback.call(opt_this, null); + }); + } else { + callback.call(opt_this, null); + } } - return resource; }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} WGS84 BBox object. + * TODO: very similar to ol.source.TileJSON#handleTileJSONResponse + * @protected + * @param {TileJSON} tileJSON Tile JSON. */ -ol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) { - var coordinates = ol.xml.pushParseAndPop([], - ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack); - if (coordinates.length != 2) { - return undefined; +ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) { + + var epsg4326Projection = ol.proj.get('EPSG:4326'); + + var sourceProjection = this.getProjection(); + var extent; + if (tileJSON.bounds !== undefined) { + var transform = ol.proj.getTransformFromProjections( + epsg4326Projection, sourceProjection); + extent = ol.extent.applyTransform(tileJSON.bounds, transform); } - return ol.extent.boundingExtent(coordinates); -}; + if (tileJSON.scheme !== undefined) { + goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"'); + } + var minZoom = tileJSON.minzoom || 0; + var maxZoom = tileJSON.maxzoom || 22; + var tileGrid = ol.tilegrid.createXYZ({ + extent: ol.tilegrid.extentFromProjection(sourceProjection), + maxZoom: maxZoom, + minZoom: minZoom + }); + this.tileGrid = tileGrid; + + this.template_ = tileJSON.template; + + var grids = tileJSON.grids; + if (!grids) { + this.setState(ol.source.State.ERROR); + return; + } + + this.tileUrlFunction_ = + ol.TileUrlFunction.createFromTemplates(grids, tileGrid); + + if (tileJSON.attribution !== undefined) { + var attributionExtent = extent !== undefined ? + extent : epsg4326Projection.getExtent(); + /** @type {Object.<string, Array.<ol.TileRange>>} */ + var tileRanges = {}; + var z, zKey; + for (z = minZoom; z <= maxZoom; ++z) { + zKey = z.toString(); + tileRanges[zKey] = + [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; + } + this.setAttributions([ + new ol.Attribution({ + html: tileJSON.attribution, + tileRanges: tileRanges + }) + ]); + } + + this.setState(ol.source.State.READY); -/** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Legend object. - */ -ol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) { - var legend = {}; - legend['format'] = node.getAttribute('format'); - legend['href'] = ol.format.XLink.readHref(node); - return legend; }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} Coordinates object. + * @inheritDoc */ -ol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) { - var coordinates = ol.format.XSD.readString(node).split(' '); - if (!coordinates || coordinates.length != 2) { - return undefined; - } - var x = +coordinates[0]; - var y = +coordinates[1]; - if (isNaN(x) || isNaN(y)) { - return undefined; +ol.source.TileUTFGrid.prototype.getTile = + function(z, x, y, pixelRatio, projection) { + var tileCoordKey = this.getKeyZXY(z, x, y); + if (this.tileCache.containsKey(tileCoordKey)) { + return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); + } else { + goog.asserts.assert(projection, 'argument projection is truthy'); + var tileCoord = [z, x, y]; + var urlTileCoord = + this.getTileCoordForTileUrlFunction(tileCoord, projection); + var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection); + var tile = new ol.source.TileUTFGridTile_( + tileCoord, + tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, + tileUrl !== undefined ? tileUrl : '', + this.tileGrid.getTileCoordExtent(tileCoord), + this.preemptive_); + this.tileCache.set(tileCoordKey, tile); + return tile; } - return [x, y]; }; /** - * @private - * @param {Node} node Node. - * @param {Array.<*>} objectStack Object stack. - * @return {Object|undefined} TileMatrix object. + * @inheritDoc */ -ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) { - return ol.xml.pushParseAndPop({}, - ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack); +ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) { + var tileCoordKey = this.getKeyZXY(z, x, y); + if (this.tileCache.containsKey(tileCoordKey)) { + this.tileCache.get(tileCoordKey); + } }; + /** - * @const + * @constructor + * @extends {ol.Tile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.TileState} state State. + * @param {string} src Image source URI. + * @param {ol.Extent} extent Extent of the tile. + * @param {boolean} preemptive Load the tile when visible (before it's needed). * @private - * @type {Array.<string>} */ -ol.format.WMTSCapabilities.NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/wmts/1.0' -]; +ol.source.TileUTFGridTile_ = + function(tileCoord, state, src, extent, preemptive) { + goog.base(this, tileCoord, state); -/** - * @const - * @private - * @type {Array.<string>} - */ -ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [ - null, - 'http://www.opengis.net/ows/1.1' -]; + /** + * @private + * @type {string} + */ + this.src_ = src; + /** + * @private + * @type {ol.Extent} + */ + this.extent_ = extent; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Contents': ol.xml.makeObjectPropertySetter( - ol.format.WMTSCapabilities.readContents_) - }); + /** + * @private + * @type {boolean} + */ + this.preemptive_ = preemptive; + /** + * @private + * @type {Array.<string>} + */ + this.grid_ = null; -/** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private - */ -ol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Layer': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readLayer_), - 'TileMatrixSet': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readTileMatrixSet_) - }); + /** + * @private + * @type {Array.<string>} + */ + this.keys_ = null; + + /** + * @private + * @type {Object.<string, Object>|undefined} + */ + this.data_ = null; +}; +goog.inherits(ol.source.TileUTFGridTile_, ol.Tile); /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Get the image element for this tile. + * @param {Object=} opt_context Optional context. Only used for the DOM + * renderer. + * @return {Image} Image. */ -ol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Style': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readStyle_), - 'Format': ol.xml.makeObjectPropertyPusher( - ol.format.XSD.readString), - 'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readTileMatrixSetLink_), - 'Dimension': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readDimensions_), - 'ResourceURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readResourceUrl_) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Abstract': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'WGS84BoundingBox': ol.xml.makeObjectPropertySetter( - ol.format.WMTSCapabilities.readWgs84BoundingBox_), - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); +ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) { + return null; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Synchronously returns data at given coordinate (if available). + * @param {ol.Coordinate} coordinate Coordinate. + * @return {Object} */ -ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'LegendURL': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readLegendUrl_) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Title': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); +ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) { + if (!this.grid_ || !this.keys_ || !this.data_) { + return null; + } + var xRelative = (coordinate[0] - this.extent_[0]) / + (this.extent_[2] - this.extent_[0]); + var yRelative = (coordinate[1] - this.extent_[1]) / + (this.extent_[3] - this.extent_[1]); + + var row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)]; + + if (!goog.isString(row)) { + return null; + } + + var code = row.charCodeAt(Math.floor(xRelative * row.length)); + if (code >= 93) { + code--; + } + if (code >= 35) { + code--; + } + code -= 32; + + return (code in this.keys_) ? this.data_[this.keys_[code]] : null; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * Calls the callback (synchronously by default) with the available data + * for given coordinate (or `null` if not yet loaded). + * @param {ol.Coordinate} coordinate Coordinate. + * @param {function(this: T, Object)} callback Callback. + * @param {T=} opt_this The object to use as `this` in the callback. + * @param {boolean=} opt_request If `true` the callback is always async. + * The tile data is requested if not yet loaded. + * @template T */ -ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'TileMatrixSet': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - }); +ol.source.TileUTFGridTile_.prototype.forDataAtCoordinate = + function(coordinate, callback, opt_this, opt_request) { + if (this.state == ol.TileState.IDLE && opt_request === true) { + goog.events.listenOnce(this, goog.events.EventType.CHANGE, function(e) { + callback.call(opt_this, this.getData(coordinate)); + }, false, this); + this.loadInternal_(); + } else { + if (opt_request === true) { + goog.async.nextTick(function() { + callback.call(opt_this, this.getData(coordinate)); + }, this); + } else { + callback.call(opt_this, this.getData(coordinate)); + } + } +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} - * @private + * @inheritDoc */ -ol.format.WMTSCapabilities.DIMENSION_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'Default': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Value': ol.xml.makeObjectPropertyPusher( - ol.format.XSD.readString) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); +ol.source.TileUTFGridTile_.prototype.getKey = function() { + return this.src_; +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'LowerCorner': ol.xml.makeArrayPusher( - ol.format.WMTSCapabilities.readCoordinates_), - 'UpperCorner': ol.xml.makeArrayPusher( - ol.format.WMTSCapabilities.readCoordinates_) - }); +ol.source.TileUTFGridTile_.prototype.handleError_ = function() { + this.state = ol.TileState.ERROR; + this.changed(); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} + * @param {!UTFGridJSON} json * @private */ -ol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'WellKnownScaleSet': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'TileMatrix': ol.xml.makeObjectPropertyPusher( - ol.format.WMTSCapabilities.readTileMatrix_) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'SupportedCRS': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString), - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); +ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) { + this.grid_ = json.grid; + this.keys_ = json.keys; + this.data_ = json.data; + + this.state = ol.TileState.EMPTY; + this.changed(); +}; /** - * @const - * @type {Object.<string, Object.<string, ol.xml.Parser>>} * @private */ -ol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeStructureNS( - ol.format.WMTSCapabilities.NAMESPACE_URIS_, { - 'TopLeftCorner': ol.xml.makeObjectPropertySetter( - ol.format.WMTSCapabilities.readCoordinates_), - 'ScaleDenominator': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readDecimal), - 'TileWidth': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'TileHeight': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MatrixWidth': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger), - 'MatrixHeight': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readNonNegativeInteger) - }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, { - 'Identifier': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) - })); - -goog.provide('ol.sphere.WGS84'); - -goog.require('ol.Sphere'); +ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() { + if (this.state == ol.TileState.IDLE) { + this.state = ol.TileState.LOADING; + var request = new goog.net.Jsonp(this.src_); + request.send(undefined, goog.bind(this.handleLoad_, this), + goog.bind(this.handleError_, this)); + } +}; /** - * A sphere with radius equal to the semi-major axis of the WGS84 ellipsoid. - * @const - * @type {ol.Sphere} + * Load not yet loaded URI. */ -ol.sphere.WGS84 = new ol.Sphere(6378137); +ol.source.TileUTFGridTile_.prototype.load = function() { + if (this.preemptive_) { + this.loadInternal_(); + } +}; -// FIXME handle geolocation not supported +// FIXME add minZoom support +// FIXME add date line wrap (tile coord transform) +// FIXME cannot be shared between maps with different projections -goog.provide('ol.Geolocation'); -goog.provide('ol.GeolocationProperty'); +goog.provide('ol.source.TileWMS'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.Coordinate'); -goog.require('ol.Object'); -goog.require('ol.geom.Geometry'); -goog.require('ol.geom.Polygon'); -goog.require('ol.has'); -goog.require('ol.math'); +goog.require('goog.asserts'); +goog.require('goog.math'); +goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.uri.utils'); +goog.require('ol'); +goog.require('ol.TileCoord'); +goog.require('ol.extent'); goog.require('ol.proj'); -goog.require('ol.sphere.WGS84'); - - -/** - * @enum {string} - */ -ol.GeolocationProperty = { - ACCURACY: 'accuracy', - ACCURACY_GEOMETRY: 'accuracyGeometry', - ALTITUDE: 'altitude', - ALTITUDE_ACCURACY: 'altitudeAccuracy', - HEADING: 'heading', - POSITION: 'position', - PROJECTION: 'projection', - SPEED: 'speed', - TRACKING: 'tracking', - TRACKING_OPTIONS: 'trackingOptions' -}; +goog.require('ol.size'); +goog.require('ol.source.TileImage'); +goog.require('ol.source.wms'); +goog.require('ol.source.wms.ServerType'); +goog.require('ol.tilecoord'); /** * @classdesc - * Helper class for providing HTML5 Geolocation capabilities. - * The [Geolocation API](http://www.w3.org/TR/geolocation-API/) - * is used to locate a user's position. - * - * To get notified of position changes, register a listener for the generic - * `change` event on your instance of `ol.Geolocation`. - * - * Example: - * - * var geolocation = new ol.Geolocation({ - * // take the projection to use from the map's view - * projection: view.getProjection() - * }); - * // listen to changes in position - * geolocation.on('change', function(evt) { - * window.console.log(geolocation.getPosition()); - * }); + * Layer source for tile data from WMS servers. * * @constructor - * @extends {ol.Object} - * @param {olx.GeolocationOptions=} opt_options Options. + * @extends {ol.source.TileImage} + * @param {olx.source.TileWMSOptions=} opt_options Tile WMS options. * @api stable */ -ol.Geolocation = function(opt_options) { +ol.source.TileWMS = function(opt_options) { + + var options = opt_options || {}; + + var params = options.params !== undefined ? options.params : {}; + + var transparent = goog.object.get(params, 'TRANSPARENT', true); + + goog.base(this, { + attributions: options.attributions, + crossOrigin: options.crossOrigin, + logo: options.logo, + opaque: !transparent, + projection: options.projection, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileGrid: options.tileGrid, + tileLoadFunction: options.tileLoadFunction, + tileUrlFunction: goog.bind(this.tileUrlFunction_, this), + url: options.url, + urls: options.urls, + wrapX: options.wrapX !== undefined ? options.wrapX : true + }); + + /** + * @private + * @type {number} + */ + this.gutter_ = options.gutter !== undefined ? options.gutter : 0; + + /** + * @private + * @type {Object} + */ + this.params_ = params; - goog.base(this); + /** + * @private + * @type {boolean} + */ + this.v13_ = true; - var options = opt_options || {}; + /** + * @private + * @type {ol.source.wms.ServerType|undefined} + */ + this.serverType_ = + /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType); /** - * The unprojected (EPSG:4326) device position. * @private - * @type {ol.Coordinate} + * @type {boolean} */ - this.position_ = null; + this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; /** * @private - * @type {ol.TransformFunction} + * @type {string} */ - this.transform_ = ol.proj.identityTransform; + this.coordKeyPrefix_ = ''; + this.resetCoordKeyPrefix_(); /** * @private - * @type {number|undefined} + * @type {ol.Extent} */ - this.watchId_ = undefined; + this.tmpExtent_ = ol.extent.createEmpty(); - goog.events.listen( - this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION), - this.handleProjectionChanged_, false, this); - goog.events.listen( - this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING), - this.handleTrackingChanged_, false, this); + this.updateV13_(); - if (options.projection !== undefined) { - this.setProjection(ol.proj.get(options.projection)); +}; +goog.inherits(ol.source.TileWMS, ol.source.TileImage); + + +/** + * Return the GetFeatureInfo URL for the passed coordinate, resolution, and + * projection. Return `undefined` if the GetFeatureInfo URL cannot be + * constructed. + * @param {ol.Coordinate} coordinate Coordinate. + * @param {number} resolution Resolution. + * @param {ol.proj.ProjectionLike} projection Projection. + * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should + * be provided. If `QUERY_LAYERS` is not provided then the layers specified + * in the `LAYERS` parameter will be used. `VERSION` should not be + * specified here. + * @return {string|undefined} GetFeatureInfo URL. + * @api stable + */ +ol.source.TileWMS.prototype.getGetFeatureInfoUrl = + function(coordinate, resolution, projection, params) { + + goog.asserts.assert(!('VERSION' in params), + 'key VERSION is not allowed in params'); + + var projectionObj = ol.proj.get(projection); + + var tileGrid = this.getTileGrid(); + if (!tileGrid) { + tileGrid = this.getTileGridForProjection(projectionObj); } - if (options.trackingOptions !== undefined) { - this.setTrackingOptions(options.trackingOptions); + + var tileCoord = tileGrid.getTileCoordForCoordAndResolution( + coordinate, resolution); + + if (tileGrid.getResolutions().length <= tileCoord[0]) { + return undefined; } - this.setTracking(options.tracking !== undefined ? options.tracking : false); + var tileResolution = tileGrid.getResolution(tileCoord[0]); + var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_); + var tileSize = ol.size.toSize( + tileGrid.getTileSize(tileCoord[0]), this.tmpSize); + + var gutter = this.gutter_; + if (gutter !== 0) { + tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize); + tileExtent = ol.extent.buffer(tileExtent, + tileResolution * gutter, tileExtent); + } + + var baseParams = { + 'SERVICE': 'WMS', + 'VERSION': ol.DEFAULT_WMS_VERSION, + 'REQUEST': 'GetFeatureInfo', + 'FORMAT': 'image/png', + 'TRANSPARENT': true, + 'QUERY_LAYERS': this.params_['LAYERS'] + }; + goog.object.extend(baseParams, this.params_, params); + + var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution); + var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution); + + baseParams[this.v13_ ? 'I' : 'X'] = x; + baseParams[this.v13_ ? 'J' : 'Y'] = y; + return this.getRequestUrl_(tileCoord, tileSize, tileExtent, + 1, projectionObj, baseParams); }; -goog.inherits(ol.Geolocation, ol.Object); /** * @inheritDoc */ -ol.Geolocation.prototype.disposeInternal = function() { - this.setTracking(false); - goog.base(this, 'disposeInternal'); +ol.source.TileWMS.prototype.getGutter = function() { + return this.gutter_; }; /** - * @private + * @inheritDoc */ -ol.Geolocation.prototype.handleProjectionChanged_ = function() { - var projection = this.getProjection(); - if (projection) { - this.transform_ = ol.proj.getTransformFromProjections( - ol.proj.get('EPSG:4326'), projection); - if (this.position_) { - this.set( - ol.GeolocationProperty.POSITION, this.transform_(this.position_)); - } - } +ol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) { + return this.coordKeyPrefix_ + goog.base(this, 'getKeyZXY', z, x, y); }; /** - * @private + * Get the user-provided params, i.e. those passed to the constructor through + * the "params" option, and possibly updated using the updateParams method. + * @return {Object} Params. + * @api stable */ -ol.Geolocation.prototype.handleTrackingChanged_ = function() { - if (ol.has.GEOLOCATION) { - var tracking = this.getTracking(); - if (tracking && this.watchId_ === undefined) { - this.watchId_ = goog.global.navigator.geolocation.watchPosition( - goog.bind(this.positionChange_, this), - goog.bind(this.positionError_, this), - this.getTrackingOptions()); - } else if (!tracking && this.watchId_ !== undefined) { - goog.global.navigator.geolocation.clearWatch(this.watchId_); - this.watchId_ = undefined; - } - } +ol.source.TileWMS.prototype.getParams = function() { + return this.params_; }; /** + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.Size} tileSize Tile size. + * @param {ol.Extent} tileExtent Tile extent. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @param {Object} params Params. + * @return {string|undefined} Request URL. * @private - * @param {GeolocationPosition} position position event. */ -ol.Geolocation.prototype.positionChange_ = function(position) { - var coords = position.coords; - this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy); - this.set(ol.GeolocationProperty.ALTITUDE, - coords.altitude === null ? undefined : coords.altitude); - this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY, - coords.altitudeAccuracy === null ? - undefined : coords.altitudeAccuracy); - this.set(ol.GeolocationProperty.HEADING, coords.heading === null ? - undefined : ol.math.toRadians(coords.heading)); - if (!this.position_) { - this.position_ = [coords.longitude, coords.latitude]; +ol.source.TileWMS.prototype.getRequestUrl_ = + function(tileCoord, tileSize, tileExtent, + pixelRatio, projection, params) { + + var urls = this.urls; + if (!urls) { + return undefined; + } + + params['WIDTH'] = tileSize[0]; + params['HEIGHT'] = tileSize[1]; + + params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode(); + + if (!('STYLES' in this.params_)) { + /* jshint -W053 */ + params['STYLES'] = new String(''); + /* jshint +W053 */ + } + + if (pixelRatio != 1) { + switch (this.serverType_) { + case ol.source.wms.ServerType.GEOSERVER: + var dpi = (90 * pixelRatio + 0.5) | 0; + if ('FORMAT_OPTIONS' in params) { + params['FORMAT_OPTIONS'] += ';dpi:' + dpi; + } else { + params['FORMAT_OPTIONS'] = 'dpi:' + dpi; + } + break; + case ol.source.wms.ServerType.MAPSERVER: + params['MAP_RESOLUTION'] = 90 * pixelRatio; + break; + case ol.source.wms.ServerType.CARMENTA_SERVER: + case ol.source.wms.ServerType.QGIS: + params['DPI'] = 90 * pixelRatio; + break; + default: + goog.asserts.fail('unknown serverType configured'); + break; + } + } + + var axisOrientation = projection.getAxisOrientation(); + var bbox = tileExtent; + if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') { + var tmp; + tmp = tileExtent[0]; + bbox[0] = tileExtent[1]; + bbox[1] = tmp; + tmp = tileExtent[2]; + bbox[2] = tileExtent[3]; + bbox[3] = tmp; + } + params['BBOX'] = bbox.join(','); + + var url; + if (urls.length == 1) { + url = urls[0]; } else { - this.position_[0] = coords.longitude; - this.position_[1] = coords.latitude; + var index = goog.math.modulo(ol.tilecoord.hash(tileCoord), urls.length); + url = urls[index]; } - var projectedPosition = this.transform_(this.position_); - this.set(ol.GeolocationProperty.POSITION, projectedPosition); - this.set(ol.GeolocationProperty.SPEED, - coords.speed === null ? undefined : coords.speed); - var geometry = ol.geom.Polygon.circular( - ol.sphere.WGS84, this.position_, coords.accuracy); - geometry.applyTransform(this.transform_); - this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry); - this.changed(); + return goog.uri.utils.appendParamsFromMap(url, params); }; /** - * @private - * @param {GeolocationPositionError} error error object. + * @param {number} z Z. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {ol.Size} Size. */ -ol.Geolocation.prototype.positionError_ = function(error) { - error.type = goog.events.EventType.ERROR; - this.setTracking(false); - this.dispatchEvent(error); +ol.source.TileWMS.prototype.getTilePixelSize = + function(z, pixelRatio, projection) { + var tileSize = goog.base(this, 'getTilePixelSize', z, pixelRatio, projection); + if (pixelRatio == 1 || !this.hidpi_ || this.serverType_ === undefined) { + return tileSize; + } else { + return ol.size.scale(tileSize, pixelRatio, this.tmpSize); + } }; /** - * Get the accuracy of the position in meters. - * @return {number|undefined} The accuracy of the position measurement in - * meters. - * @observable - * @api stable + * @private */ -ol.Geolocation.prototype.getAccuracy = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ACCURACY)); -}; +ol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() { + var i = 0; + var res = []; + + if (this.urls) { + var j, jj; + for (j = 0, jj = this.urls.length; j < jj; ++j) { + res[i++] = this.urls[j]; + } + } + var key; + for (key in this.params_) { + res[i++] = key + '-' + this.params_[key]; + } -/** - * Get a geometry of the position accuracy. - * @return {?ol.geom.Geometry} A geometry of the position accuracy. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getAccuracyGeometry = function() { - return /** @type {?ol.geom.Geometry} */ ( - this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null); + this.coordKeyPrefix_ = res.join('#'); }; /** - * Get the altitude associated with the position. - * @return {number|undefined} The altitude of the position in meters above mean - * sea level. - * @observable - * @api stable + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. + * @private */ -ol.Geolocation.prototype.getAltitude = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ALTITUDE)); -}; +ol.source.TileWMS.prototype.tileUrlFunction_ = + function(tileCoord, pixelRatio, projection) { + var tileGrid = this.getTileGrid(); + if (!tileGrid) { + tileGrid = this.getTileGridForProjection(projection); + } -/** - * Get the altitude accuracy of the position. - * @return {number|undefined} The accuracy of the altitude measurement in - * meters. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getAltitudeAccuracy = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY)); -}; + if (tileGrid.getResolutions().length <= tileCoord[0]) { + return undefined; + } + if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) { + pixelRatio = 1; + } -/** - * Get the heading as radians clockwise from North. - * @return {number|undefined} The heading of the device in radians from north. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getHeading = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.HEADING)); -}; + var tileResolution = tileGrid.getResolution(tileCoord[0]); + var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_); + var tileSize = ol.size.toSize( + tileGrid.getTileSize(tileCoord[0]), this.tmpSize); + var gutter = this.gutter_; + if (gutter !== 0) { + tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize); + tileExtent = ol.extent.buffer(tileExtent, + tileResolution * gutter, tileExtent); + } -/** - * Get the position of the device. - * @return {ol.Coordinate|undefined} The current position of the device reported - * in the current projection. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getPosition = function() { - return /** @type {ol.Coordinate|undefined} */ ( - this.get(ol.GeolocationProperty.POSITION)); -}; + if (pixelRatio != 1) { + tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize); + } + var baseParams = { + 'SERVICE': 'WMS', + 'VERSION': ol.DEFAULT_WMS_VERSION, + 'REQUEST': 'GetMap', + 'FORMAT': 'image/png', + 'TRANSPARENT': true + }; + goog.object.extend(baseParams, this.params_); -/** - * Get the projection associated with the position. - * @return {ol.proj.Projection|undefined} The projection the position is - * reported in. - * @observable - * @api stable - */ -ol.Geolocation.prototype.getProjection = function() { - return /** @type {ol.proj.Projection|undefined} */ ( - this.get(ol.GeolocationProperty.PROJECTION)); + return this.getRequestUrl_(tileCoord, tileSize, tileExtent, + pixelRatio, projection, baseParams); }; /** - * Get the speed in meters per second. - * @return {number|undefined} The instantaneous speed of the device in meters - * per second. - * @observable + * Update the user-provided params. + * @param {Object} params Params. * @api stable */ -ol.Geolocation.prototype.getSpeed = function() { - return /** @type {number|undefined} */ ( - this.get(ol.GeolocationProperty.SPEED)); +ol.source.TileWMS.prototype.updateParams = function(params) { + goog.object.extend(this.params_, params); + this.resetCoordKeyPrefix_(); + this.updateV13_(); + this.changed(); }; /** - * Determine if the device location is being tracked. - * @return {boolean} The device location is being tracked. - * @observable - * @api stable + * @private */ -ol.Geolocation.prototype.getTracking = function() { - return /** @type {boolean} */ ( - this.get(ol.GeolocationProperty.TRACKING)); +ol.source.TileWMS.prototype.updateV13_ = function() { + var version = + goog.object.get(this.params_, 'VERSION', ol.DEFAULT_WMS_VERSION); + this.v13_ = goog.string.compareVersions(version, '1.3') >= 0; }; +goog.provide('ol.source.Zoomify'); -/** - * Get the tracking options. - * @see http://www.w3.org/TR/geolocation-API/#position-options - * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by - * the [HTML5 Geolocation spec - * ](http://www.w3.org/TR/geolocation-API/#position_options_interface). - * @observable - * @api stable - */ -ol.Geolocation.prototype.getTrackingOptions = function() { - return /** @type {GeolocationPositionOptions|undefined} */ ( - this.get(ol.GeolocationProperty.TRACKING_OPTIONS)); -}; +goog.require('goog.asserts'); +goog.require('ol'); +goog.require('ol.ImageTile'); +goog.require('ol.TileCoord'); +goog.require('ol.TileState'); +goog.require('ol.dom'); +goog.require('ol.extent'); +goog.require('ol.proj'); +goog.require('ol.source.TileImage'); +goog.require('ol.tilegrid.TileGrid'); /** - * Set the projection to use for transforming the coordinates. - * @param {ol.proj.Projection} projection The projection the position is - * reported in. - * @observable - * @api stable + * @enum {string} */ -ol.Geolocation.prototype.setProjection = function(projection) { - this.set(ol.GeolocationProperty.PROJECTION, projection); +ol.source.ZoomifyTierSizeCalculation = { + DEFAULT: 'default', + TRUNCATED: 'truncated' }; + /** - * Enable or disable tracking. - * @param {boolean} tracking Enable tracking. - * @observable + * @classdesc + * Layer source for tile data in Zoomify format. + * + * @constructor + * @extends {ol.source.TileImage} + * @param {olx.source.ZoomifyOptions=} opt_options Options. * @api stable */ -ol.Geolocation.prototype.setTracking = function(tracking) { - this.set(ol.GeolocationProperty.TRACKING, tracking); -}; +ol.source.Zoomify = function(opt_options) { + + var options = opt_options || {}; + + var size = options.size; + var tierSizeCalculation = options.tierSizeCalculation !== undefined ? + options.tierSizeCalculation : + ol.source.ZoomifyTierSizeCalculation.DEFAULT; + + var imageWidth = size[0]; + var imageHeight = size[1]; + var tierSizeInTiles = []; + var tileSize = ol.DEFAULT_TILE_SIZE; + + switch (tierSizeCalculation) { + case ol.source.ZoomifyTierSizeCalculation.DEFAULT: + while (imageWidth > tileSize || imageHeight > tileSize) { + tierSizeInTiles.push([ + Math.ceil(imageWidth / tileSize), + Math.ceil(imageHeight / tileSize) + ]); + tileSize += tileSize; + } + break; + case ol.source.ZoomifyTierSizeCalculation.TRUNCATED: + var width = imageWidth; + var height = imageHeight; + while (width > tileSize || height > tileSize) { + tierSizeInTiles.push([ + Math.ceil(width / tileSize), + Math.ceil(height / tileSize) + ]); + width >>= 1; + height >>= 1; + } + break; + default: + goog.asserts.fail(); + break; + } + + tierSizeInTiles.push([1, 1]); + tierSizeInTiles.reverse(); + + var resolutions = [1]; + var tileCountUpToTier = [0]; + var i, ii; + for (i = 1, ii = tierSizeInTiles.length; i < ii; i++) { + resolutions.push(1 << i); + tileCountUpToTier.push( + tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] + + tileCountUpToTier[i - 1] + ); + } + resolutions.reverse(); + + var extent = [0, -size[1], size[0], 0]; + var tileGrid = new ol.tilegrid.TileGrid({ + extent: extent, + origin: ol.extent.getTopLeft(extent), + resolutions: resolutions + }); + var url = options.url; -/** - * Set the tracking options. - * @see http://www.w3.org/TR/geolocation-API/#position-options - * @param {GeolocationPositionOptions} options PositionOptions as defined by the - * [HTML5 Geolocation spec - * ](http://www.w3.org/TR/geolocation-API/#position_options_interface). - * @observable - * @api stable - */ -ol.Geolocation.prototype.setTrackingOptions = function(options) { - this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options); -}; + /** + * @this {ol.source.TileImage} + * @param {ol.TileCoord} tileCoord Tile Coordinate. + * @param {number} pixelRatio Pixel ratio. + * @param {ol.proj.Projection} projection Projection. + * @return {string|undefined} Tile URL. + */ + function tileUrlFunction(tileCoord, pixelRatio, projection) { + if (!tileCoord) { + return undefined; + } else { + var tileCoordZ = tileCoord[0]; + var tileCoordX = tileCoord[1]; + var tileCoordY = -tileCoord[2] - 1; + var tileIndex = + tileCoordX + + tileCoordY * tierSizeInTiles[tileCoordZ][0] + + tileCountUpToTier[tileCoordZ]; + var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0; + return url + 'TileGroup' + tileGroup + '/' + + tileCoordZ + '-' + tileCoordX + '-' + tileCoordY + '.jpg'; + } + } -goog.provide('ol.geom.Circle'); + goog.base(this, { + attributions: options.attributions, + crossOrigin: options.crossOrigin, + logo: options.logo, + reprojectionErrorThreshold: options.reprojectionErrorThreshold, + tileClass: ol.source.ZoomifyTile_, + tileGrid: tileGrid, + tileUrlFunction: tileUrlFunction + }); -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.geom.flat.deflate'); -goog.require('ol.proj'); +}; +goog.inherits(ol.source.Zoomify, ol.source.TileImage); /** - * @classdesc - * Circle geometry. - * * @constructor - * @extends {ol.geom.SimpleGeometry} - * @param {ol.Coordinate} center Center. - * @param {number=} opt_radius Radius. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api + * @extends {ol.ImageTile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.TileState} state State. + * @param {string} src Image source URI. + * @param {?string} crossOrigin Cross origin. + * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. + * @private */ -ol.geom.Circle = function(center, opt_radius, opt_layout) { - goog.base(this); - var radius = opt_radius ? opt_radius : 0; - this.setCenterAndRadius(center, radius, opt_layout); -}; -goog.inherits(ol.geom.Circle, ol.geom.SimpleGeometry); +ol.source.ZoomifyTile_ = function( + tileCoord, state, src, crossOrigin, tileLoadFunction) { + goog.base(this, tileCoord, state, src, crossOrigin, tileLoadFunction); + + /** + * @private + * @type {Object.<string, + * HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} + */ + this.zoomifyImageByContext_ = {}; -/** - * Make a complete copy of the geometry. - * @return {!ol.geom.Circle} Clone. - * @api - */ -ol.geom.Circle.prototype.clone = function() { - var circle = new ol.geom.Circle(null); - circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); - return circle; }; +goog.inherits(ol.source.ZoomifyTile_, ol.ImageTile); /** * @inheritDoc */ -ol.geom.Circle.prototype.closestPointXY = - function(x, y, closestPoint, minSquaredDistance) { - var flatCoordinates = this.flatCoordinates; - var dx = x - flatCoordinates[0]; - var dy = y - flatCoordinates[1]; - var squaredDistance = dx * dx + dy * dy; - if (squaredDistance < minSquaredDistance) { - var i; - if (squaredDistance === 0) { - for (i = 0; i < this.stride; ++i) { - closestPoint[i] = flatCoordinates[i]; +ol.source.ZoomifyTile_.prototype.getImage = function(opt_context) { + var tileSize = ol.DEFAULT_TILE_SIZE; + var key = opt_context !== undefined ? + goog.getUid(opt_context).toString() : ''; + if (key in this.zoomifyImageByContext_) { + return this.zoomifyImageByContext_[key]; + } else { + var image = goog.base(this, 'getImage', opt_context); + if (this.state == ol.TileState.LOADED) { + if (image.width == tileSize && image.height == tileSize) { + this.zoomifyImageByContext_[key] = image; + return image; + } else { + var context = ol.dom.createCanvasContext2D(tileSize, tileSize); + context.drawImage(image, 0, 0); + this.zoomifyImageByContext_[key] = context.canvas; + return context.canvas; } } else { - var delta = this.getRadius() / Math.sqrt(squaredDistance); - closestPoint[0] = flatCoordinates[0] + delta * dx; - closestPoint[1] = flatCoordinates[1] + delta * dy; - for (i = 2; i < this.stride; ++i) { - closestPoint[i] = flatCoordinates[i]; - } + return image; } - closestPoint.length = this.stride; - return squaredDistance; - } else { - return minSquaredDistance; } }; +goog.provide('ol.style.Atlas'); +goog.provide('ol.style.AtlasManager'); + +goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('ol'); + /** - * @inheritDoc + * Provides information for an image inside an atlas manager. + * `offsetX` and `offsetY` is the position of the image inside + * the atlas image `image` and the position of the hit-detection image + * inside the hit-detection atlas image `hitImage`. + * @typedef {{offsetX: number, offsetY: number, image: HTMLCanvasElement, + * hitImage: HTMLCanvasElement}} */ -ol.geom.Circle.prototype.containsXY = function(x, y) { - var flatCoordinates = this.flatCoordinates; - var dx = x - flatCoordinates[0]; - var dy = y - flatCoordinates[1]; - return dx * dx + dy * dy <= this.getRadiusSquared_(); -}; +ol.style.AtlasManagerInfo; + /** - * Return the center of the circle as {@link ol.Coordinate coordinate}. - * @return {ol.Coordinate} Center. + * Manages the creation of image atlases. + * + * Images added to this manager will be inserted into an atlas, which + * will be used for rendering. + * The `size` given in the constructor is the size for the first + * atlas. After that, when new atlases are created, they will have + * twice the size as the latest atlas (until `maxSize` is reached). + * + * If an application uses many images or very large images, it is recommended + * to set a higher `size` value to avoid the creation of too many atlases. + * + * @constructor + * @struct * @api + * @param {olx.style.AtlasManagerOptions=} opt_options Options. */ -ol.geom.Circle.prototype.getCenter = function() { - return this.flatCoordinates.slice(0, this.stride); -}; +ol.style.AtlasManager = function(opt_options) { + var options = opt_options || {}; -/** - * @inheritDoc - */ -ol.geom.Circle.prototype.computeExtent = function(extent) { - var flatCoordinates = this.flatCoordinates; - var radius = flatCoordinates[this.stride] - flatCoordinates[0]; - return ol.extent.createOrUpdate( - flatCoordinates[0] - radius, flatCoordinates[1] - radius, - flatCoordinates[0] + radius, flatCoordinates[1] + radius, - extent); + /** + * The size in pixels of the latest atlas image. + * @private + * @type {number} + */ + this.currentSize_ = options.initialSize !== undefined ? + options.initialSize : ol.INITIAL_ATLAS_SIZE; + + /** + * The maximum size in pixels of atlas images. + * @private + * @type {number} + */ + this.maxSize_ = options.maxSize !== undefined ? + options.maxSize : ol.MAX_ATLAS_SIZE != -1 ? + ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ? + ol.WEBGL_MAX_TEXTURE_SIZE : 2048; + + /** + * The size in pixels between images. + * @private + * @type {number} + */ + this.space_ = options.space !== undefined ? options.space : 1; + + /** + * @private + * @type {Array.<ol.style.Atlas>} + */ + this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)]; + + /** + * The size in pixels of the latest atlas image for hit-detection images. + * @private + * @type {number} + */ + this.currentHitSize_ = this.currentSize_; + + /** + * @private + * @type {Array.<ol.style.Atlas>} + */ + this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)]; }; /** - * Return the radius of the circle. - * @return {number} Radius. - * @api + * @param {string} id The identifier of the entry to check. + * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the + * entry, or `null` if the entry is not part of the atlas manager. */ -ol.geom.Circle.prototype.getRadius = function() { - return Math.sqrt(this.getRadiusSquared_()); +ol.style.AtlasManager.prototype.getInfo = function(id) { + /** @type {?ol.style.AtlasInfo} */ + var info = this.getInfo_(this.atlases_, id); + + if (!info) { + return null; + } + /** @type {?ol.style.AtlasInfo} */ + var hitInfo = this.getInfo_(this.hitAtlases_, id); + goog.asserts.assert(hitInfo, 'hitInfo must not be null'); + + return this.mergeInfos_(info, hitInfo); }; /** * @private - * @return {number} Radius squared. + * @param {Array.<ol.style.Atlas>} atlases The atlases to search. + * @param {string} id The identifier of the entry to check. + * @return {?ol.style.AtlasInfo} The position and atlas image for the entry, + * or `null` if the entry is not part of the atlases. */ -ol.geom.Circle.prototype.getRadiusSquared_ = function() { - var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0]; - var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1]; - return dx * dx + dy * dy; +ol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) { + var atlas, info, i, ii; + for (i = 0, ii = atlases.length; i < ii; ++i) { + atlas = atlases[i]; + info = atlas.get(id); + if (info) { + return info; + } + } + return null; }; /** - * @inheritDoc - * @api + * @private + * @param {ol.style.AtlasInfo} info The info for the real image. + * @param {ol.style.AtlasInfo} hitInfo The info for the hit-detection + * image. + * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the + * entry, or `null` if the entry is not part of the atlases. */ -ol.geom.Circle.prototype.getType = function() { - return ol.geom.GeometryType.CIRCLE; +ol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) { + goog.asserts.assert(info.offsetX === hitInfo.offsetX, + 'in order to merge, offsetX of info and hitInfo must be equal'); + goog.asserts.assert(info.offsetY === hitInfo.offsetY, + 'in order to merge, offsetY of info and hitInfo must be equal'); + return /** @type {ol.style.AtlasManagerInfo} */ ({ + offsetX: info.offsetX, + offsetY: info.offsetY, + image: info.image, + hitImage: hitInfo.image + }); }; /** - * @inheritDoc - * @api stable + * Add an image to the atlas manager. + * + * If an entry for the given id already exists, the entry will + * be overridden (but the space on the atlas graphic will not be freed). + * + * If `renderHitCallback` is provided, the image (or the hit-detection version + * of the image) will be rendered into a separate hit-detection atlas image. + * + * @param {string} id The identifier of the entry to add. + * @param {number} width The width. + * @param {number} height The height. + * @param {function(CanvasRenderingContext2D, number, number)} renderCallback + * Called to render the new image onto an atlas image. + * @param {function(CanvasRenderingContext2D, number, number)=} + * opt_renderHitCallback Called to render a hit-detection image onto a hit + * detection atlas image. + * @param {Object=} opt_this Value to use as `this` when executing + * `renderCallback` and `renderHitCallback`. + * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the + * entry, or `null` if the image is too big. */ -ol.geom.Circle.prototype.intersectsExtent = function(extent) { - var circleExtent = this.getExtent(); - if (ol.extent.intersects(extent, circleExtent)) { - var center = this.getCenter(); - - if (extent[0] <= center[0] && extent[2] >= center[0]) { - return true; - } - if (extent[1] <= center[1] && extent[3] >= center[1]) { - return true; - } +ol.style.AtlasManager.prototype.add = + function(id, width, height, + renderCallback, opt_renderHitCallback, opt_this) { + if (width + this.space_ > this.maxSize_ || + height + this.space_ > this.maxSize_) { + return null; + } - return ol.extent.forEachCorner(extent, this.containsCoordinate, this); + /** @type {?ol.style.AtlasInfo} */ + var info = this.add_(false, + id, width, height, renderCallback, opt_this); + if (!info) { + return null; } - return false; -}; + // even if no hit-detection entry is requested, we insert a fake entry into + // the hit-detection atlas, to make sure that the offset is the same for + // the original image and the hit-detection image. + var renderHitCallback = opt_renderHitCallback !== undefined ? + opt_renderHitCallback : goog.functions.NULL; + /** @type {?ol.style.AtlasInfo} */ + var hitInfo = this.add_(true, + id, width, height, renderHitCallback, opt_this); + goog.asserts.assert(hitInfo, 'hitInfo must not be null'); -/** - * Set the center of the circle as {@link ol.Coordinate coordinate}. - * @param {ol.Coordinate} center Center. - * @api - */ -ol.geom.Circle.prototype.setCenter = function(center) { - var stride = this.stride; - goog.asserts.assert(center.length == stride, - 'center array length should match stride'); - var radius = this.flatCoordinates[stride] - this.flatCoordinates[0]; - var flatCoordinates = center.slice(); - flatCoordinates[stride] = flatCoordinates[0] + radius; - var i; - for (i = 1; i < stride; ++i) { - flatCoordinates[stride + i] = center[i]; - } - this.setFlatCoordinates(this.layout, flatCoordinates); + return this.mergeInfos_(info, hitInfo); }; /** - * Set the center (as {@link ol.Coordinate coordinate}) and the radius (as - * number) of the circle. - * @param {ol.Coordinate} center Center. - * @param {number} radius Radius. - * @param {ol.geom.GeometryLayout=} opt_layout Layout. - * @api + * @private + * @param {boolean} isHitAtlas If the hit-detection atlases are used. + * @param {string} id The identifier of the entry to add. + * @param {number} width The width. + * @param {number} height The height. + * @param {function(CanvasRenderingContext2D, number, number)} renderCallback + * Called to render the new image onto an atlas image. + * @param {Object=} opt_this Value to use as `this` when executing + * `renderCallback` and `renderHitCallback`. + * @return {?ol.style.AtlasInfo} The position and atlas image for the entry, + * or `null` if the image is too big. */ -ol.geom.Circle.prototype.setCenterAndRadius = - function(center, radius, opt_layout) { - if (!center) { - this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null); - } else { - this.setLayout(opt_layout, center, 0); - if (!this.flatCoordinates) { - this.flatCoordinates = []; - } - /** @type {Array.<number>} */ - var flatCoordinates = this.flatCoordinates; - var offset = ol.geom.flat.deflate.coordinate( - flatCoordinates, 0, center, this.stride); - flatCoordinates[offset++] = flatCoordinates[0] + radius; - var i, ii; - for (i = 1, ii = this.stride; i < ii; ++i) { - flatCoordinates[offset++] = flatCoordinates[i]; +ol.style.AtlasManager.prototype.add_ = + function(isHitAtlas, id, width, height, + renderCallback, opt_this) { + var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_; + var atlas, info, i, ii; + for (i = 0, ii = atlases.length; i < ii; ++i) { + atlas = atlases[i]; + info = atlas.add(id, width, height, renderCallback, opt_this); + if (info) { + return info; + } else if (!info && i === ii - 1) { + // the entry could not be added to one of the existing atlases, + // create a new atlas that is twice as big and try to add to this one. + var size; + if (isHitAtlas) { + size = Math.min(this.currentHitSize_ * 2, this.maxSize_); + this.currentHitSize_ = size; + } else { + size = Math.min(this.currentSize_ * 2, this.maxSize_); + this.currentSize_ = size; + } + atlas = new ol.style.Atlas(size, this.space_); + atlases.push(atlas); + // run the loop another time + ++ii; } - flatCoordinates.length = offset; - this.changed(); } + goog.asserts.fail('Failed to add to atlasmanager'); }; /** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.<number>} flatCoordinates Flat coordinates. + * Provides information for an image inside an atlas. + * `offsetX` and `offsetY` are the position of the image inside + * the atlas image `image`. + * @typedef {{offsetX: number, offsetY: number, image: HTMLCanvasElement}} */ -ol.geom.Circle.prototype.setFlatCoordinates = - function(layout, flatCoordinates) { - this.setFlatCoordinatesInternal(layout, flatCoordinates); - this.changed(); -}; - +ol.style.AtlasInfo; -/** - * Set the radius of the circle. The radius is in the units of the projection. - * @param {number} radius Radius. - * @api - */ -ol.geom.Circle.prototype.setRadius = function(radius) { - goog.asserts.assert(this.flatCoordinates, - 'truthy this.flatCoordinates expected'); - this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius; - this.changed(); -}; /** - * Transform each coordinate of the circle from one coordinate reference system - * to another. The geometry is modified in place. - * If you do not want the geometry modified in place, first clone() it and - * then use this function on the clone. + * This class facilitates the creation of image atlases. * - * Internally a circle is currently represented by two points: the center of - * the circle `[cx, cy]`, and the point to the right of the circle - * `[cx + r, cy]`. This `transform` function just transforms these two points. - * So the resulting geometry is also a circle, and that circle does not - * correspond to the shape that would be obtained by transforming every point - * of the original circle. + * Images added to an atlas will be rendered onto a single + * atlas canvas. The distribution of images on the canvas is + * managed with the bin packing algorithm described in: + * http://www.blackpawn.com/texts/lightmaps/ * - * @param {ol.proj.ProjectionLike} source The current projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @param {ol.proj.ProjectionLike} destination The desired projection. Can be a - * string identifier or a {@link ol.proj.Projection} object. - * @return {ol.geom.Circle} This geometry. Note that original geometry is - * modified in place. - * @function - * @api stable + * @constructor + * @struct + * @param {number} size The size in pixels of the sprite image. + * @param {number} space The space in pixels between images. + * Because texture coordinates are float values, the edges of + * images might not be completely correct (in a way that the + * edges overlap when being rendered). To avoid this we add a + * padding around each image. */ -ol.geom.Circle.prototype.transform; +ol.style.Atlas = function(size, space) { -goog.provide('ol.geom.flat.geodesic'); + /** + * @private + * @type {number} + */ + this.space_ = space; + + /** + * @private + * @type {Array.<ol.style.Atlas.Block>} + */ + this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}]; + + /** + * @private + * @type {Object.<string, ol.style.AtlasInfo>} + */ + this.entries_ = {}; + + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + this.canvas_.width = size; + this.canvas_.height = size; -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('ol.TransformFunction'); -goog.require('ol.math'); -goog.require('ol.proj'); + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = /** @type {CanvasRenderingContext2D} */ + (this.canvas_.getContext('2d')); +}; /** - * @private - * @param {function(number): ol.Coordinate} interpolate Interpolate function. - * @param {ol.TransformFunction} transform Transform from longitude/latitude to - * projected coordinates. - * @param {number} squaredTolerance Squared tolerance. - * @return {Array.<number>} Flat coordinates. + * @param {string} id The identifier of the entry to check. + * @return {?ol.style.AtlasInfo} */ -ol.geom.flat.geodesic.line_ = - function(interpolate, transform, squaredTolerance) { - // FIXME reduce garbage generation - // FIXME optimize stack operations - - /** @type {Array.<number>} */ - var flatCoordinates = []; - - var geoA = interpolate(0); - var geoB = interpolate(1); +ol.style.Atlas.prototype.get = function(id) { + return /** @type {?ol.style.AtlasInfo} */ ( + goog.object.get(this.entries_, id, null)); +}; - var a = transform(geoA); - var b = transform(geoB); - /** @type {Array.<ol.Coordinate>} */ - var geoStack = [geoB, geoA]; - /** @type {Array.<ol.Coordinate>} */ - var stack = [b, a]; - /** @type {Array.<number>} */ - var fractionStack = [1, 0]; +/** + * @param {string} id The identifier of the entry to add. + * @param {number} width The width. + * @param {number} height The height. + * @param {function(CanvasRenderingContext2D, number, number)} renderCallback + * Called to render the new image onto an atlas image. + * @param {Object=} opt_this Value to use as `this` when executing + * `renderCallback`. + * @return {?ol.style.AtlasInfo} The position and atlas image for the entry. + */ +ol.style.Atlas.prototype.add = + function(id, width, height, renderCallback, opt_this) { + var block, i, ii; + for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) { + block = this.emptyBlocks_[i]; + if (block.width >= width + this.space_ && + block.height >= height + this.space_) { + // we found a block that is big enough for our entry + var entry = { + offsetX: block.x + this.space_, + offsetY: block.y + this.space_, + image: this.canvas_ + }; + this.entries_[id] = entry; - /** @type {Object.<string, boolean>} */ - var fractions = {}; + // render the image on the atlas image + renderCallback.call(opt_this, this.context_, + block.x + this.space_, block.y + this.space_); - var maxIterations = 1e5; - var geoM, m, fracA, fracB, fracM, key; + // split the block after the insertion, either horizontally or vertically + this.split_(i, block, width + this.space_, height + this.space_); - while (--maxIterations > 0 && fractionStack.length > 0) { - // Pop the a coordinate off the stack - fracA = fractionStack.pop(); - geoA = geoStack.pop(); - a = stack.pop(); - // Add the a coordinate if it has not been added yet - key = fracA.toString(); - if (!goog.object.containsKey(fractions, key)) { - flatCoordinates.push(a[0], a[1]); - fractions[key] = true; - } - // Pop the b coordinate off the stack - fracB = fractionStack.pop(); - geoB = geoStack.pop(); - b = stack.pop(); - // Find the m point between the a and b coordinates - fracM = (fracA + fracB) / 2; - geoM = interpolate(fracM); - m = transform(geoM); - if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1], - b[0], b[1]) < squaredTolerance) { - // If the m point is sufficiently close to the straight line, then we - // discard it. Just use the b coordinate and move on to the next line - // segment. - flatCoordinates.push(b[0], b[1]); - key = fracB.toString(); - goog.asserts.assert(!goog.object.containsKey(fractions, key), - 'fractions object should contain key : ' + key); - fractions[key] = true; - } else { - // Otherwise, we need to subdivide the current line segment. Split it - // into two and push the two line segments onto the stack. - fractionStack.push(fracB, fracM, fracM, fracA); - stack.push(b, m, m, a); - geoStack.push(geoB, geoM, geoM, geoA); + return entry; } } - goog.asserts.assert(maxIterations > 0, - 'maxIterations should be more than 0'); - return flatCoordinates; + // there is no space for the new entry in this atlas + return null; }; /** -* Generate a great-circle arcs between two lat/lon points. -* @param {number} lon1 Longitude 1 in degrees. -* @param {number} lat1 Latitude 1 in degrees. -* @param {number} lon2 Longitude 2 in degrees. -* @param {number} lat2 Latitude 2 in degrees. - * @param {ol.proj.Projection} projection Projection. -* @param {number} squaredTolerance Squared tolerance. -* @return {Array.<number>} Flat coordinates. -*/ -ol.geom.flat.geodesic.greatCircleArc = function( - lon1, lat1, lon2, lat2, projection, squaredTolerance) { + * @private + * @param {number} index The index of the block. + * @param {ol.style.Atlas.Block} block The block to split. + * @param {number} width The width of the entry to insert. + * @param {number} height The height of the entry to insert. + */ +ol.style.Atlas.prototype.split_ = + function(index, block, width, height) { + var deltaWidth = block.width - width; + var deltaHeight = block.height - height; - var geoProjection = ol.proj.get('EPSG:4326'); + /** @type {ol.style.Atlas.Block} */ + var newBlock1; + /** @type {ol.style.Atlas.Block} */ + var newBlock2; - var cosLat1 = Math.cos(ol.math.toRadians(lat1)); - var sinLat1 = Math.sin(ol.math.toRadians(lat1)); - var cosLat2 = Math.cos(ol.math.toRadians(lat2)); - var sinLat2 = Math.sin(ol.math.toRadians(lat2)); - var cosDeltaLon = Math.cos(ol.math.toRadians(lon2 - lon1)); - var sinDeltaLon = Math.sin(ol.math.toRadians(lon2 - lon1)); - var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon; + if (deltaWidth > deltaHeight) { + // split vertically + // block right of the inserted entry + newBlock1 = { + x: block.x + width, + y: block.y, + width: block.width - width, + height: block.height + }; - return ol.geom.flat.geodesic.line_( - /** - * @param {number} frac Fraction. - * @return {ol.Coordinate} Coordinate. - */ - function(frac) { - if (1 <= d) { - return [lon2, lat2]; - } - var D = frac * Math.acos(d); - var cosD = Math.cos(D); - var sinD = Math.sin(D); - var y = sinDeltaLon * cosLat2; - var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon; - var theta = Math.atan2(y, x); - var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta)); - var lon = ol.math.toRadians(lon1) + - Math.atan2(Math.sin(theta) * sinD * cosLat1, - cosD - sinLat1 * Math.sin(lat)); - return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)]; - }, ol.proj.getTransform(geoProjection, projection), squaredTolerance); + // block below the inserted entry + newBlock2 = { + x: block.x, + y: block.y + height, + width: width, + height: block.height - height + }; + this.updateBlocks_(index, newBlock1, newBlock2); + } else { + // split horizontally + // block right of the inserted entry + newBlock1 = { + x: block.x + width, + y: block.y, + width: block.width - width, + height: height + }; + + // block below the inserted entry + newBlock2 = { + x: block.x, + y: block.y + height, + width: block.width, + height: block.height - height + }; + this.updateBlocks_(index, newBlock1, newBlock2); + } }; /** - * Generate a meridian (line at constant longitude). - * @param {number} lon Longitude. - * @param {number} lat1 Latitude 1. - * @param {number} lat2 Latitude 2. - * @param {ol.proj.Projection} projection Projection. - * @param {number} squaredTolerance Squared tolerance. - * @return {Array.<number>} Flat coordinates. + * Remove the old block and insert new blocks at the same array position. + * The new blocks are inserted at the same position, so that splitted + * blocks (that are potentially smaller) are filled first. + * @private + * @param {number} index The index of the block to remove. + * @param {ol.style.Atlas.Block} newBlock1 The 1st block to add. + * @param {ol.style.Atlas.Block} newBlock2 The 2nd block to add. */ -ol.geom.flat.geodesic.meridian = - function(lon, lat1, lat2, projection, squaredTolerance) { - var epsg4326Projection = ol.proj.get('EPSG:4326'); - return ol.geom.flat.geodesic.line_( - /** - * @param {number} frac Fraction. - * @return {ol.Coordinate} Coordinate. - */ - function(frac) { - return [lon, lat1 + ((lat2 - lat1) * frac)]; - }, - ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance); +ol.style.Atlas.prototype.updateBlocks_ = + function(index, newBlock1, newBlock2) { + var args = [index, 1]; + if (newBlock1.width > 0 && newBlock1.height > 0) { + args.push(newBlock1); + } + if (newBlock2.width > 0 && newBlock2.height > 0) { + args.push(newBlock2); + } + this.emptyBlocks_.splice.apply(this.emptyBlocks_, args); }; /** - * Generate a parallel (line at constant latitude). - * @param {number} lat Latitude. - * @param {number} lon1 Longitude 1. - * @param {number} lon2 Longitude 2. - * @param {ol.proj.Projection} projection Projection. - * @param {number} squaredTolerance Squared tolerance. - * @return {Array.<number>} Flat coordinates. + * @typedef {{x: number, y: number, width: number, height: number}} */ -ol.geom.flat.geodesic.parallel = - function(lat, lon1, lon2, projection, squaredTolerance) { - var epsg4326Projection = ol.proj.get('EPSG:4326'); - return ol.geom.flat.geodesic.line_( - /** - * @param {number} frac Fraction. - * @return {ol.Coordinate} Coordinate. - */ - function(frac) { - return [lon1 + ((lon2 - lon1) * frac), lat]; - }, - ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance); -}; +ol.style.Atlas.Block; -goog.provide('ol.Graticule'); +goog.provide('ol.style.RegularShape'); goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryLayout'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.flat.geodesic'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.render.EventType'); +goog.require('goog.dom'); +goog.require('ol'); +goog.require('ol.color'); +goog.require('ol.has'); +goog.require('ol.render.canvas'); +goog.require('ol.structs.IHasChecksum'); +goog.require('ol.style.AtlasManager'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Image'); +goog.require('ol.style.ImageState'); goog.require('ol.style.Stroke'); /** - * Render a grid for a coordinate system on a map. + * @classdesc + * Set regular shape style for vector features. The resulting shape will be + * a regular polygon when `radius` is provided, or a star when `radius1` and + * `radius2` are provided. + * * @constructor - * @param {olx.GraticuleOptions=} opt_options Options. + * @param {olx.style.RegularShapeOptions} options Options. + * @extends {ol.style.Image} + * @implements {ol.structs.IHasChecksum} * @api */ -ol.Graticule = function(opt_options) { - - var options = opt_options || {}; +ol.style.RegularShape = function(options) { - /** - * @type {ol.Map} - * @private - */ - this.map_ = null; + goog.asserts.assert( + options.radius !== undefined || options.radius1 !== undefined, + 'must provide either "radius" or "radius1"'); /** - * @type {ol.proj.Projection} * @private + * @type {Array.<string>} */ - this.projection_ = null; + this.checksums_ = null; /** - * @type {number} * @private + * @type {HTMLCanvasElement} */ - this.maxLat_ = Infinity; + this.canvas_ = null; /** - * @type {number} * @private + * @type {HTMLCanvasElement} */ - this.maxLon_ = Infinity; + this.hitDetectionCanvas_ = null; /** - * @type {number} * @private + * @type {ol.style.Fill} */ - this.minLat_ = -Infinity; + this.fill_ = options.fill !== undefined ? options.fill : null; /** - * @type {number} * @private + * @type {Array.<number>} */ - this.minLon_ = -Infinity; + this.origin_ = [0, 0]; /** - * @type {number} * @private - */ - this.maxLatP_ = Infinity; - - /** * @type {number} - * @private */ - this.maxLonP_ = Infinity; + this.points_ = options.points; /** - * @type {number} * @private - */ - this.minLatP_ = -Infinity; - - /** * @type {number} - * @private */ - this.minLonP_ = -Infinity; + this.radius_ = /** @type {number} */ (options.radius !== undefined ? + options.radius : options.radius1); /** - * @type {number} * @private - */ - this.targetSize_ = options.targetSize !== undefined ? - options.targetSize : 100; - - /** * @type {number} - * @private */ - this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100; - goog.asserts.assert(this.maxLines_ > 0, - 'this.maxLines_ should be more than 0'); + this.radius2_ = + options.radius2 !== undefined ? options.radius2 : this.radius_; /** - * @type {Array.<ol.geom.LineString>} * @private + * @type {number} */ - this.meridians_ = []; + this.angle_ = options.angle !== undefined ? options.angle : 0; /** - * @type {Array.<ol.geom.LineString>} * @private + * @type {ol.style.Stroke} */ - this.parallels_ = []; + this.stroke_ = options.stroke !== undefined ? options.stroke : null; /** - * @type {ol.style.Stroke} * @private + * @type {Array.<number>} */ - this.strokeStyle_ = options.strokeStyle !== undefined ? - options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_; + this.anchor_ = null; /** - * @type {ol.TransformFunction|undefined} * @private + * @type {ol.Size} */ - this.fromLonLatTransform_ = undefined; + this.size_ = null; /** - * @type {ol.TransformFunction|undefined} * @private + * @type {ol.Size} */ - this.toLonLatTransform_ = undefined; + this.imageSize_ = null; /** - * @type {ol.Coordinate} * @private - */ - this.projectionCenterLonLat_ = null; - - this.setMap(options.map !== undefined ? options.map : null); -}; - - -/** - * @type {ol.style.Stroke} - * @private - * @const - */ -ol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({ - color: 'rgba(0,0,0,0.2)' -}); - - -/** - * TODO can be configurable - * @type {Array.<number>} - * @private - */ -ol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, - 0.01, 0.005, 0.002, 0.001]; - - -/** - * @param {number} lon Longitude. - * @param {number} minLat Minimal latitude. - * @param {number} maxLat Maximal latitude. - * @param {number} squaredTolerance Squared tolerance. - * @param {ol.Extent} extent Extent. - * @param {number} index Index. - * @return {number} Index. - * @private - */ -ol.Graticule.prototype.addMeridian_ = - function(lon, minLat, maxLat, squaredTolerance, extent, index) { - var lineString = this.getMeridian_(lon, minLat, maxLat, - squaredTolerance, index); - if (ol.extent.intersects(lineString.getExtent(), extent)) { - this.meridians_[index++] = lineString; - } - return index; -}; - - -/** - * @param {number} lat Latitude. - * @param {number} minLon Minimal longitude. - * @param {number} maxLon Maximal longitude. - * @param {number} squaredTolerance Squared tolerance. - * @param {ol.Extent} extent Extent. - * @param {number} index Index. - * @return {number} Index. - * @private - */ -ol.Graticule.prototype.addParallel_ = - function(lat, minLon, maxLon, squaredTolerance, extent, index) { - var lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, - index); - if (ol.extent.intersects(lineString.getExtent(), extent)) { - this.parallels_[index++] = lineString; - } - return index; -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Coordinate} center Center. - * @param {number} resolution Resolution. - * @param {number} squaredTolerance Squared tolerance. - * @private - */ -ol.Graticule.prototype.createGraticule_ = - function(extent, center, resolution, squaredTolerance) { - - var interval = this.getInterval_(resolution); - if (interval == -1) { - this.meridians_.length = this.parallels_.length = 0; - return; - } - - var centerLonLat = this.toLonLatTransform_(center); - var centerLon = centerLonLat[0]; - var centerLat = centerLonLat[1]; - var maxLines = this.maxLines_; - var cnt, idx, lat, lon; - - var validExtent = [ - Math.max(extent[0], this.minLonP_), - Math.max(extent[1], this.minLatP_), - Math.min(extent[2], this.maxLonP_), - Math.min(extent[3], this.maxLatP_) - ]; - - validExtent = ol.proj.transformExtent(validExtent, this.projection_, - 'EPSG:4326'); - var maxLat = validExtent[3]; - var maxLon = validExtent[2]; - var minLat = validExtent[1]; - var minLon = validExtent[0]; - - // Create meridians - - centerLon = Math.floor(centerLon / interval) * interval; - lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_); - - idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0); - - cnt = 0; - while (lon != this.minLon_ && cnt++ < maxLines) { - lon = Math.max(lon - interval, this.minLon_); - idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx); - } - - lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_); - - cnt = 0; - while (lon != this.maxLon_ && cnt++ < maxLines) { - lon = Math.min(lon + interval, this.maxLon_); - idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx); - } - - this.meridians_.length = idx; - - // Create parallels - - centerLat = Math.floor(centerLat / interval) * interval; - lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_); + * @type {ol.Size} + */ + this.hitDetectionImageSize_ = null; - idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0); + this.render_(options.atlasManager); - cnt = 0; - while (lat != this.minLat_ && cnt++ < maxLines) { - lat = Math.max(lat - interval, this.minLat_); - idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx); - } + /** + * @type {boolean} + */ + var snapToPixel = options.snapToPixel !== undefined ? + options.snapToPixel : true; - lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_); + goog.base(this, { + opacity: 1, + rotateWithView: false, + rotation: options.rotation !== undefined ? options.rotation : 0, + scale: 1, + snapToPixel: snapToPixel + }); - cnt = 0; - while (lat != this.maxLat_ && cnt++ < maxLines) { - lat = Math.min(lat + interval, this.maxLat_); - idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx); - } +}; +goog.inherits(ol.style.RegularShape, ol.style.Image); - this.parallels_.length = idx; +/** + * @inheritDoc + * @api + */ +ol.style.RegularShape.prototype.getAnchor = function() { + return this.anchor_; }; /** - * @param {number} resolution Resolution. - * @return {number} The interval in degrees. - * @private + * Get the angle used in generating the shape. + * @return {number} Shape's rotation in radians. + * @api */ -ol.Graticule.prototype.getInterval_ = function(resolution) { - var centerLon = this.projectionCenterLonLat_[0]; - var centerLat = this.projectionCenterLonLat_[1]; - var interval = -1; - var i, ii, delta, dist; - var target = Math.pow(this.targetSize_ * resolution, 2); - /** @type {Array.<number>} **/ - var p1 = []; - /** @type {Array.<number>} **/ - var p2 = []; - for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) { - delta = ol.Graticule.intervals_[i] / 2; - p1[0] = centerLon - delta; - p1[1] = centerLat - delta; - p2[0] = centerLon + delta; - p2[1] = centerLat + delta; - this.fromLonLatTransform_(p1, p1); - this.fromLonLatTransform_(p2, p2); - dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2); - if (dist <= target) { - break; - } - interval = ol.Graticule.intervals_[i]; - } - return interval; +ol.style.RegularShape.prototype.getAngle = function() { + return this.angle_; }; /** - * Get the map associated with this graticule. - * @return {ol.Map} The map. + * Get the fill style for the shape. + * @return {ol.style.Fill} Fill style. * @api */ -ol.Graticule.prototype.getMap = function() { - return this.map_; +ol.style.RegularShape.prototype.getFill = function() { + return this.fill_; }; /** - * @param {number} lon Longitude. - * @param {number} minLat Minimal latitude. - * @param {number} maxLat Maximal latitude. - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.LineString} The meridian line string. - * @param {number} index Index. - * @private + * @inheritDoc */ -ol.Graticule.prototype.getMeridian_ = function(lon, minLat, maxLat, - squaredTolerance, index) { - goog.asserts.assert(lon >= this.minLon_, - 'lon should be larger than or equal to this.minLon_'); - goog.asserts.assert(lon <= this.maxLon_, - 'lon should be smaller than or equal to this.maxLon_'); - var flatCoordinates = ol.geom.flat.geodesic.meridian(lon, - minLat, maxLat, this.projection_, squaredTolerance); - goog.asserts.assert(flatCoordinates.length > 0, - 'flatCoordinates cannot be empty'); - var lineString = this.meridians_[index] !== undefined ? - this.meridians_[index] : new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); - return lineString; +ol.style.RegularShape.prototype.getHitDetectionImage = function(pixelRatio) { + return this.hitDetectionCanvas_; }; /** - * Get the list of meridians. Meridians are lines of equal longitude. - * @return {Array.<ol.geom.LineString>} The meridians. + * @inheritDoc * @api */ -ol.Graticule.prototype.getMeridians = function() { - return this.meridians_; +ol.style.RegularShape.prototype.getImage = function(pixelRatio) { + return this.canvas_; }; /** - * @param {number} lat Latitude. - * @param {number} minLon Minimal longitude. - * @param {number} maxLon Maximal longitude. - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.LineString} The parallel line string. - * @param {number} index Index. - * @private + * @inheritDoc */ -ol.Graticule.prototype.getParallel_ = function(lat, minLon, maxLon, - squaredTolerance, index) { - goog.asserts.assert(lat >= this.minLat_, - 'lat should be larger than or equal to this.minLat_'); - goog.asserts.assert(lat <= this.maxLat_, - 'lat should be smaller than or equal to this.maxLat_'); - var flatCoordinates = ol.geom.flat.geodesic.parallel(lat, - this.minLon_, this.maxLon_, this.projection_, squaredTolerance); - goog.asserts.assert(flatCoordinates.length > 0, - 'flatCoordinates cannot be empty'); - var lineString = this.parallels_[index] !== undefined ? - this.parallels_[index] : new ol.geom.LineString(null); - lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates); - return lineString; +ol.style.RegularShape.prototype.getImageSize = function() { + return this.imageSize_; }; /** - * Get the list of parallels. Pallels are lines of equal latitude. - * @return {Array.<ol.geom.LineString>} The parallels. - * @api + * @inheritDoc */ -ol.Graticule.prototype.getParallels = function() { - return this.parallels_; +ol.style.RegularShape.prototype.getHitDetectionImageSize = function() { + return this.hitDetectionImageSize_; }; /** - * @param {ol.render.Event} e Event. - * @private + * @inheritDoc */ -ol.Graticule.prototype.handlePostCompose_ = function(e) { - var vectorContext = e.vectorContext; - var frameState = e.frameState; - var extent = frameState.extent; - var viewState = frameState.viewState; - var center = viewState.center; - var projection = viewState.projection; - var resolution = viewState.resolution; - var pixelRatio = frameState.pixelRatio; - var squaredTolerance = - resolution * resolution / (4 * pixelRatio * pixelRatio); - - var updateProjectionInfo = !this.projection_ || - !ol.proj.equivalent(this.projection_, projection); - - if (updateProjectionInfo) { - this.updateProjectionInfo_(projection); - } - - //Fix the extent if wrapped. - //(note: this is the same extent as vectorContext.extent_) - var offsetX = 0; - if (projection.canWrapX()) { - var projectionExtent = projection.getExtent(); - var worldWidth = ol.extent.getWidth(projectionExtent); - var x = frameState.focus[0]; - if (x < projectionExtent[0] || x > projectionExtent[2]) { - var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth); - offsetX = worldWidth * worldsAway; - extent = [ - extent[0] + offsetX, extent[1], - extent[2] + offsetX, extent[3] - ]; - } - } - - this.createGraticule_(extent, center, resolution, squaredTolerance); - - // Draw the lines - vectorContext.setFillStrokeStyle(null, this.strokeStyle_); - var i, l, line; - for (i = 0, l = this.meridians_.length; i < l; ++i) { - line = this.meridians_[i]; - vectorContext.drawLineStringGeometry(line, null); - } - for (i = 0, l = this.parallels_.length; i < l; ++i) { - line = this.parallels_[i]; - vectorContext.drawLineStringGeometry(line, null); - } +ol.style.RegularShape.prototype.getImageState = function() { + return ol.style.ImageState.LOADED; }; /** - * @param {ol.proj.Projection} projection Projection. - * @private + * @inheritDoc + * @api */ -ol.Graticule.prototype.updateProjectionInfo_ = function(projection) { - goog.asserts.assert(projection, 'projection cannot be null'); - - var epsg4326Projection = ol.proj.get('EPSG:4326'); - - var extent = projection.getExtent(); - var worldExtent = projection.getWorldExtent(); - var worldExtentP = ol.proj.transformExtent(worldExtent, - epsg4326Projection, projection); - - var maxLat = worldExtent[3]; - var maxLon = worldExtent[2]; - var minLat = worldExtent[1]; - var minLon = worldExtent[0]; - - var maxLatP = worldExtentP[3]; - var maxLonP = worldExtentP[2]; - var minLatP = worldExtentP[1]; - var minLonP = worldExtentP[0]; - - goog.asserts.assert(extent, 'extent cannot be null'); - goog.asserts.assert(maxLat !== undefined, 'maxLat should be defined'); - goog.asserts.assert(maxLon !== undefined, 'maxLon should be defined'); - goog.asserts.assert(minLat !== undefined, 'minLat should be defined'); - goog.asserts.assert(minLon !== undefined, 'minLon should be defined'); - - goog.asserts.assert(maxLatP !== undefined, - 'projected maxLat should be defined'); - goog.asserts.assert(maxLonP !== undefined, - 'projected maxLon should be defined'); - goog.asserts.assert(minLatP !== undefined, - 'projected minLat should be defined'); - goog.asserts.assert(minLonP !== undefined, - 'projected minLon should be defined'); - - this.maxLat_ = maxLat; - this.maxLon_ = maxLon; - this.minLat_ = minLat; - this.minLon_ = minLon; - - this.maxLatP_ = maxLatP; - this.maxLonP_ = maxLonP; - this.minLatP_ = minLatP; - this.minLonP_ = minLonP; - - - this.fromLonLatTransform_ = ol.proj.getTransform( - epsg4326Projection, projection); - - this.toLonLatTransform_ = ol.proj.getTransform( - projection, epsg4326Projection); - - this.projectionCenterLonLat_ = this.toLonLatTransform_( - ol.extent.getCenter(extent)); - - this.projection_ = projection; +ol.style.RegularShape.prototype.getOrigin = function() { + return this.origin_; }; /** - * Set the map for this graticule. The graticule will be rendered on the - * provided map. - * @param {ol.Map} map Map. + * Get the number of points for generating the shape. + * @return {number} Number of points for stars and regular polygons. * @api */ -ol.Graticule.prototype.setMap = function(map) { - if (this.map_) { - this.map_.un(ol.render.EventType.POSTCOMPOSE, - this.handlePostCompose_, this); - this.map_.render(); - } - if (map) { - map.on(ol.render.EventType.POSTCOMPOSE, - this.handlePostCompose_, this); - map.render(); - } - this.map_ = map; +ol.style.RegularShape.prototype.getPoints = function() { + return this.points_; }; -goog.provide('ol.Image'); - -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.ImageBase'); -goog.require('ol.ImageState'); -goog.require('ol.extent'); - - /** - * @constructor - * @extends {ol.ImageBase} - * @param {ol.Extent} extent Extent. - * @param {number|undefined} resolution Resolution. - * @param {number} pixelRatio Pixel ratio. - * @param {Array.<ol.Attribution>} attributions Attributions. - * @param {string} src Image source URI. - * @param {?string} crossOrigin Cross origin. - * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. + * Get the (primary) radius for the shape. + * @return {number} Radius. + * @api */ -ol.Image = function(extent, resolution, pixelRatio, attributions, src, - crossOrigin, imageLoadFunction) { - - goog.base(this, extent, resolution, pixelRatio, ol.ImageState.IDLE, - attributions); - - /** - * @private - * @type {string} - */ - this.src_ = src; - - /** - * @private - * @type {HTMLCanvasElement|Image|HTMLVideoElement} - */ - this.image_ = new Image(); - if (crossOrigin !== null) { - this.image_.crossOrigin = crossOrigin; - } - - /** - * @private - * @type {Object.<number, (HTMLCanvasElement|Image|HTMLVideoElement)>} - */ - this.imageByContext_ = {}; - - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.imageListenerKeys_ = null; - - /** - * @protected - * @type {ol.ImageState} - */ - this.state = ol.ImageState.IDLE; - - /** - * @private - * @type {ol.ImageLoadFunctionType} - */ - this.imageLoadFunction_ = imageLoadFunction; - +ol.style.RegularShape.prototype.getRadius = function() { + return this.radius_; }; -goog.inherits(ol.Image, ol.ImageBase); /** - * Get the HTML image element (may be a Canvas, Image, or Video). - * @param {Object=} opt_context Object. - * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image. + * Get the secondary radius for the shape. + * @return {number} Radius2. * @api */ -ol.Image.prototype.getImage = function(opt_context) { - if (opt_context !== undefined) { - var image; - var key = goog.getUid(opt_context); - if (key in this.imageByContext_) { - return this.imageByContext_[key]; - } else if (goog.object.isEmpty(this.imageByContext_)) { - image = this.image_; - } else { - image = /** @type {Image} */ (this.image_.cloneNode(false)); - } - this.imageByContext_[key] = image; - return image; - } else { - return this.image_; - } +ol.style.RegularShape.prototype.getRadius2 = function() { + return this.radius2_; }; /** - * Tracks loading or read errors. - * - * @private + * @inheritDoc + * @api */ -ol.Image.prototype.handleImageError_ = function() { - this.state = ol.ImageState.ERROR; - this.unlistenImage_(); - this.changed(); +ol.style.RegularShape.prototype.getSize = function() { + return this.size_; }; /** - * Tracks successful image load. - * - * @private + * Get the stroke style for the shape. + * @return {ol.style.Stroke} Stroke style. + * @api */ -ol.Image.prototype.handleImageLoad_ = function() { - if (this.resolution === undefined) { - this.resolution = ol.extent.getHeight(this.extent) / this.image_.height; - } - this.state = ol.ImageState.LOADED; - this.unlistenImage_(); - this.changed(); +ol.style.RegularShape.prototype.getStroke = function() { + return this.stroke_; }; /** - * Load not yet loaded URI. + * @inheritDoc */ -ol.Image.prototype.load = function() { - if (this.state == ol.ImageState.IDLE) { - this.state = ol.ImageState.LOADING; - this.changed(); - goog.asserts.assert(!this.imageListenerKeys_, - 'this.imageListenerKeys_ should be null'); - this.imageListenerKeys_ = [ - goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, - this.handleImageError_, false, this), - goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, - this.handleImageLoad_, false, this) - ]; - this.imageLoadFunction_(this, this.src_); - } -}; +ol.style.RegularShape.prototype.listenImageChange = ol.nullFunction; /** - * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image. + * @inheritDoc */ -ol.Image.prototype.setImage = function(image) { - this.image_ = image; -}; +ol.style.RegularShape.prototype.load = ol.nullFunction; /** - * Discards event handlers which listen for load completion or errors. - * - * @private + * @inheritDoc */ -ol.Image.prototype.unlistenImage_ = function() { - goog.asserts.assert(this.imageListenerKeys_, - 'this.imageListenerKeys_ should not be null'); - this.imageListenerKeys_.forEach(goog.events.unlistenByKey); - this.imageListenerKeys_ = null; -}; +ol.style.RegularShape.prototype.unlistenImageChange = ol.nullFunction; -goog.provide('ol.ImageLoadFunctionType'); + +/** + * @typedef {{ + * strokeStyle: (string|undefined), + * strokeWidth: number, + * size: number, + * lineCap: string, + * lineDash: Array.<number>, + * lineJoin: string, + * miterLimit: number + * }} + */ +ol.style.RegularShape.RenderOptions; /** - * A function that takes an {@link ol.Image} for the image and a `{string}` for - * the src as arguments. It is supposed to make it so the underlying image - * {@link ol.Image#getImage} is assigned the content specified by the src. If - * not specified, the default is - * - * function(image, src) { - * image.getImage().src = src; - * } - * - * Providing a custom `imageLoadFunction` can be useful to load images with - * post requests or - in general - through XHR requests, where the src of the - * image element would be set to a data URI when the content is loaded. - * - * @typedef {function(ol.Image, string)} - * @api + * @private + * @param {ol.style.AtlasManager|undefined} atlasManager */ -ol.ImageLoadFunctionType; +ol.style.RegularShape.prototype.render_ = function(atlasManager) { + var imageSize; + var lineCap = ''; + var lineJoin = ''; + var miterLimit = 0; + var lineDash = null; + var strokeStyle; + var strokeWidth = 0; -goog.provide('ol.ImageTile'); + if (this.stroke_) { + strokeStyle = ol.color.asString(this.stroke_.getColor()); + strokeWidth = this.stroke_.getWidth(); + if (strokeWidth === undefined) { + strokeWidth = ol.render.canvas.defaultLineWidth; + } + lineDash = this.stroke_.getLineDash(); + if (!ol.has.CANVAS_LINE_DASH) { + lineDash = null; + } + lineJoin = this.stroke_.getLineJoin(); + if (lineJoin === undefined) { + lineJoin = ol.render.canvas.defaultLineJoin; + } + lineCap = this.stroke_.getLineCap(); + if (lineCap === undefined) { + lineCap = ol.render.canvas.defaultLineCap; + } + miterLimit = this.stroke_.getMiterLimit(); + if (miterLimit === undefined) { + miterLimit = ol.render.canvas.defaultMiterLimit; + } + } -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.Tile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileLoadFunctionType'); -goog.require('ol.TileState'); + var size = 2 * (this.radius_ + strokeWidth) + 1; + + /** @type {ol.style.RegularShape.RenderOptions} */ + var renderOptions = { + strokeStyle: strokeStyle, + strokeWidth: strokeWidth, + size: size, + lineCap: lineCap, + lineDash: lineDash, + lineJoin: lineJoin, + miterLimit: miterLimit + }; + if (atlasManager === undefined) { + // no atlas manager is used, create a new canvas + this.canvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + this.canvas_.height = size; + this.canvas_.width = size; -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Image source URI. - * @param {?string} crossOrigin Cross origin. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - */ -ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) { + // canvas.width and height are rounded to the closest integer + size = this.canvas_.width; + imageSize = size; - goog.base(this, tileCoord, state); + var context = /** @type {CanvasRenderingContext2D} */ + (this.canvas_.getContext('2d')); + this.draw_(renderOptions, context, 0, 0); - /** - * Image URI - * - * @private - * @type {string} - */ - this.src_ = src; + this.createHitDetectionCanvas_(renderOptions); + } else { + // an atlas manager is used, add the symbol to an atlas + size = Math.round(size); - /** - * @private - * @type {Image} - */ - this.image_ = new Image(); - if (crossOrigin !== null) { - this.image_.crossOrigin = crossOrigin; - } + var hasCustomHitDetectionImage = !this.fill_; + var renderHitDetectionCallback; + if (hasCustomHitDetectionImage) { + // render the hit-detection image into a separate atlas image + renderHitDetectionCallback = + goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); + } - /** - * @private - * @type {Object.<number, Image>} - */ - this.imageByContext_ = {}; + var id = this.getChecksum(); + var info = atlasManager.add( + id, size, size, goog.bind(this.draw_, this, renderOptions), + renderHitDetectionCallback); + goog.asserts.assert(info, 'shape size is too large'); - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.imageListenerKeys_ = null; + this.canvas_ = info.image; + this.origin_ = [info.offsetX, info.offsetY]; + imageSize = info.image.width; - /** - * @private - * @type {ol.TileLoadFunctionType} - */ - this.tileLoadFunction_ = tileLoadFunction; + if (hasCustomHitDetectionImage) { + this.hitDetectionCanvas_ = info.hitImage; + this.hitDetectionImageSize_ = + [info.hitImage.width, info.hitImage.height]; + } else { + this.hitDetectionCanvas_ = this.canvas_; + this.hitDetectionImageSize_ = [imageSize, imageSize]; + } + } + this.anchor_ = [size / 2, size / 2]; + this.size_ = [size, size]; + this.imageSize_ = [imageSize, imageSize]; }; -goog.inherits(ol.ImageTile, ol.Tile); /** - * @inheritDoc + * @private + * @param {ol.style.RegularShape.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). */ -ol.ImageTile.prototype.disposeInternal = function() { - if (this.state == ol.TileState.LOADING) { - this.unlistenImage_(); +ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) { + var i, angle0, radiusC; + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); + + // then move to (x, y) + context.translate(x, y); + + context.beginPath(); + if (this.radius2_ !== this.radius_) { + this.points_ = 2 * this.points_; } - if (this.interimTile) { - goog.dispose(this.interimTile); + for (i = 0; i <= this.points_; i++) { + angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; + radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; + context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0), + renderOptions.size / 2 + radiusC * Math.sin(angle0)); } - goog.base(this, 'disposeInternal'); -}; - -/** - * Get the image element for this tile. - * @inheritDoc - * @api - */ -ol.ImageTile.prototype.getImage = function(opt_context) { - if (opt_context !== undefined) { - var image; - var key = goog.getUid(opt_context); - if (key in this.imageByContext_) { - return this.imageByContext_[key]; - } else if (goog.object.isEmpty(this.imageByContext_)) { - image = this.image_; - } else { - image = /** @type {Image} */ (this.image_.cloneNode(false)); + if (this.fill_) { + context.fillStyle = ol.color.asString(this.fill_.getColor()); + context.fill(); + } + if (this.stroke_) { + context.strokeStyle = renderOptions.strokeStyle; + context.lineWidth = renderOptions.strokeWidth; + if (renderOptions.lineDash) { + context.setLineDash(renderOptions.lineDash); } - this.imageByContext_[key] = image; - return image; - } else { - return this.image_; + context.lineCap = renderOptions.lineCap; + context.lineJoin = renderOptions.lineJoin; + context.miterLimit = renderOptions.miterLimit; + context.stroke(); } + context.closePath(); }; /** - * @inheritDoc + * @private + * @param {ol.style.RegularShape.RenderOptions} renderOptions */ -ol.ImageTile.prototype.getKey = function() { - return this.src_; -}; +ol.style.RegularShape.prototype.createHitDetectionCanvas_ = + function(renderOptions) { + this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; + if (this.fill_) { + this.hitDetectionCanvas_ = this.canvas_; + return; + } + // if no fill style is set, create an extra hit-detection image with a + // default fill style + this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement('CANVAS')); + var canvas = this.hitDetectionCanvas_; -/** - * Tracks loading or read errors. - * - * @private - */ -ol.ImageTile.prototype.handleImageError_ = function() { - this.state = ol.TileState.ERROR; - this.unlistenImage_(); - this.changed(); + canvas.height = renderOptions.size; + canvas.width = renderOptions.size; + + var context = /** @type {CanvasRenderingContext2D} */ + (canvas.getContext('2d')); + this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); }; /** - * Tracks successful image load. - * * @private + * @param {ol.style.RegularShape.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). */ -ol.ImageTile.prototype.handleImageLoad_ = function() { - if (this.image_.naturalWidth && this.image_.naturalHeight) { - this.state = ol.TileState.LOADED; - } else { - this.state = ol.TileState.EMPTY; - } - this.unlistenImage_(); - this.changed(); -}; +ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = + function(renderOptions, context, x, y) { + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); + // then move to (x, y) + context.translate(x, y); -/** - * Load not yet loaded URI. - */ -ol.ImageTile.prototype.load = function() { - if (this.state == ol.TileState.IDLE) { - this.state = ol.TileState.LOADING; - this.changed(); - goog.asserts.assert(!this.imageListenerKeys_, - 'this.imageListenerKeys_ should be null'); - this.imageListenerKeys_ = [ - goog.events.listenOnce(this.image_, goog.events.EventType.ERROR, - this.handleImageError_, false, this), - goog.events.listenOnce(this.image_, goog.events.EventType.LOAD, - this.handleImageLoad_, false, this) - ]; - this.tileLoadFunction_(this, this.src_); + context.beginPath(); + if (this.radius2_ !== this.radius_) { + this.points_ = 2 * this.points_; } + var i, radiusC, angle0; + for (i = 0; i <= this.points_; i++) { + angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; + radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; + context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0), + renderOptions.size / 2 + radiusC * Math.sin(angle0)); + } + + context.fillStyle = ol.render.canvas.defaultFillStyle; + context.fill(); + if (this.stroke_) { + context.strokeStyle = renderOptions.strokeStyle; + context.lineWidth = renderOptions.strokeWidth; + if (renderOptions.lineDash) { + context.setLineDash(renderOptions.lineDash); + } + context.stroke(); + } + context.closePath(); }; /** - * Discards event handlers which listen for load completion or errors. - * - * @private + * @inheritDoc */ -ol.ImageTile.prototype.unlistenImage_ = function() { - goog.asserts.assert(this.imageListenerKeys_, - 'this.imageListenerKeys_ should not be null'); - this.imageListenerKeys_.forEach(goog.events.unlistenByKey); - this.imageListenerKeys_ = null; +ol.style.RegularShape.prototype.getChecksum = function() { + var strokeChecksum = this.stroke_ ? + this.stroke_.getChecksum() : '-'; + var fillChecksum = this.fill_ ? + this.fill_.getChecksum() : '-'; + + var recalculate = !this.checksums_ || + (strokeChecksum != this.checksums_[1] || + fillChecksum != this.checksums_[2] || + this.radius_ != this.checksums_[3] || + this.radius2_ != this.checksums_[4] || + this.angle_ != this.checksums_[5] || + this.points_ != this.checksums_[6]); + + if (recalculate) { + var checksum = 'r' + strokeChecksum + fillChecksum + + (this.radius_ !== undefined ? this.radius_.toString() : '-') + + (this.radius2_ !== undefined ? this.radius2_.toString() : '-') + + (this.angle_ !== undefined ? this.angle_.toString() : '-') + + (this.points_ !== undefined ? this.points_.toString() : '-'); + this.checksums_ = [checksum, strokeChecksum, fillChecksum, + this.radius_, this.radius2_, this.angle_, this.points_]; + } + + return this.checksums_[0]; }; -// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// Copyright 2009 The Closure Library Authors. +// All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108696,16629 +125033,12750 @@ ol.ImageTile.prototype.unlistenImage_ = function() { // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// +// This file has been auto-generated by GenJsDeps, please do not edit. + +goog.addDependency('demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'], ['goog.ui.equation.EquationEditorDialog']); +goog.addDependency('demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'], ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']); +goog.addDependency('demos/editor/helloworlddialog.js', ['goog.demos.editor.HelloWorldDialog', 'goog.demos.editor.HelloWorldDialog.OkEvent'], ['goog.dom.TagName', 'goog.events.Event', 'goog.string', 'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder', 'goog.ui.editor.AbstractDialog.EventType']); +goog.addDependency('demos/editor/helloworlddialogplugin.js', ['goog.demos.editor.HelloWorldDialogPlugin', 'goog.demos.editor.HelloWorldDialogPlugin.Command'], ['goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName', 'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range', 'goog.functions', 'goog.ui.editor.AbstractDialog.EventType']); /** - * @fileoverview Provides a files drag and drop event detector. It works on - * HTML5 browsers. - * - * @see ../demos/filedrophandler.html + * @fileoverview Custom exports file. + * @suppress {checkVars, extraRequire} */ -goog.provide('goog.events.FileDropHandler'); -goog.provide('goog.events.FileDropHandler.EventType'); +goog.require('ol'); +goog.require('ol.Attribution'); +goog.require('ol.Collection'); +goog.require('ol.CollectionEvent'); +goog.require('ol.CollectionEventType'); +goog.require('ol.Color'); +goog.require('ol.Coordinate'); +goog.require('ol.CoordinateFormatType'); +goog.require('ol.DeviceOrientation'); +goog.require('ol.DeviceOrientationProperty'); +goog.require('ol.DragBoxEvent'); +goog.require('ol.Extent'); +goog.require('ol.Feature'); +goog.require('ol.FeatureLoader'); +goog.require('ol.FeatureStyleFunction'); +goog.require('ol.FeatureUrlFunction'); +goog.require('ol.Geolocation'); +goog.require('ol.GeolocationProperty'); +goog.require('ol.Graticule'); +goog.require('ol.Image'); +goog.require('ol.ImageTile'); +goog.require('ol.Kinetic'); +goog.require('ol.LoadingStrategy'); +goog.require('ol.Map'); +goog.require('ol.MapBrowserEvent'); +goog.require('ol.MapBrowserEvent.EventType'); +goog.require('ol.MapBrowserEventHandler'); +goog.require('ol.MapBrowserPointerEvent'); +goog.require('ol.MapEvent'); +goog.require('ol.MapEventType'); +goog.require('ol.MapProperty'); +goog.require('ol.Object'); +goog.require('ol.ObjectEvent'); +goog.require('ol.ObjectEventType'); +goog.require('ol.Observable'); +goog.require('ol.Overlay'); +goog.require('ol.OverlayPositioning'); +goog.require('ol.OverlayProperty'); +goog.require('ol.Size'); +goog.require('ol.Sphere'); +goog.require('ol.Tile'); +goog.require('ol.TileState'); +goog.require('ol.VectorTile'); +goog.require('ol.View'); +goog.require('ol.ViewHint'); +goog.require('ol.ViewProperty'); +goog.require('ol.animation'); +goog.require('ol.color'); +goog.require('ol.control'); +goog.require('ol.control.Attribution'); +goog.require('ol.control.Control'); +goog.require('ol.control.FullScreen'); +goog.require('ol.control.MousePosition'); +goog.require('ol.control.OverviewMap'); +goog.require('ol.control.Rotate'); +goog.require('ol.control.ScaleLine'); +goog.require('ol.control.ScaleLineProperty'); +goog.require('ol.control.ScaleLineUnits'); +goog.require('ol.control.Zoom'); +goog.require('ol.control.ZoomSlider'); +goog.require('ol.control.ZoomToExtent'); +goog.require('ol.coordinate'); +goog.require('ol.easing'); +goog.require('ol.events.ConditionType'); +goog.require('ol.events.condition'); +goog.require('ol.extent'); +goog.require('ol.extent.Corner'); +goog.require('ol.extent.Relationship'); +goog.require('ol.featureloader'); +goog.require('ol.format.EsriJSON'); +goog.require('ol.format.Feature'); +goog.require('ol.format.GML'); +goog.require('ol.format.GML2'); +goog.require('ol.format.GML3'); +goog.require('ol.format.GMLBase'); +goog.require('ol.format.GPX'); +goog.require('ol.format.GeoJSON'); +goog.require('ol.format.IGC'); +goog.require('ol.format.IGCZ'); +goog.require('ol.format.KML'); +goog.require('ol.format.MVT'); +goog.require('ol.format.OSMXML'); +goog.require('ol.format.Polyline'); +goog.require('ol.format.TopoJSON'); +goog.require('ol.format.WFS'); +goog.require('ol.format.WKT'); +goog.require('ol.format.WMSCapabilities'); +goog.require('ol.format.WMSGetFeatureInfo'); +goog.require('ol.format.WMTSCapabilities'); +goog.require('ol.geom.Circle'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryCollection'); +goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.geom.SimpleGeometry'); +goog.require('ol.has'); +goog.require('ol.interaction'); +goog.require('ol.interaction.DoubleClickZoom'); +goog.require('ol.interaction.DragAndDrop'); +goog.require('ol.interaction.DragAndDropEvent'); +goog.require('ol.interaction.DragBox'); +goog.require('ol.interaction.DragPan'); +goog.require('ol.interaction.DragRotate'); +goog.require('ol.interaction.DragRotateAndZoom'); +goog.require('ol.interaction.DragZoom'); +goog.require('ol.interaction.Draw'); +goog.require('ol.interaction.DrawEvent'); +goog.require('ol.interaction.DrawEventType'); +goog.require('ol.interaction.DrawGeometryFunctionType'); +goog.require('ol.interaction.DrawMode'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.interaction.InteractionProperty'); +goog.require('ol.interaction.KeyboardPan'); +goog.require('ol.interaction.KeyboardZoom'); +goog.require('ol.interaction.Modify'); +goog.require('ol.interaction.ModifyEvent'); +goog.require('ol.interaction.MouseWheelZoom'); +goog.require('ol.interaction.PinchRotate'); +goog.require('ol.interaction.PinchZoom'); +goog.require('ol.interaction.Pointer'); +goog.require('ol.interaction.Select'); +goog.require('ol.interaction.SelectEvent'); +goog.require('ol.interaction.SelectEventType'); +goog.require('ol.interaction.SelectFilterFunction'); +goog.require('ol.interaction.Snap'); +goog.require('ol.interaction.SnapProperty'); +goog.require('ol.interaction.Translate'); +goog.require('ol.interaction.TranslateEvent'); +goog.require('ol.layer.Base'); +goog.require('ol.layer.Group'); +goog.require('ol.layer.Heatmap'); +goog.require('ol.layer.Image'); +goog.require('ol.layer.Layer'); +goog.require('ol.layer.LayerProperty'); +goog.require('ol.layer.LayerState'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.layer.VectorTile'); +goog.require('ol.loadingstrategy'); +goog.require('ol.proj'); +goog.require('ol.proj.METERS_PER_UNIT'); +goog.require('ol.proj.Projection'); +goog.require('ol.proj.ProjectionLike'); +goog.require('ol.proj.Units'); +goog.require('ol.proj.common'); +goog.require('ol.render.Event'); +goog.require('ol.render.EventType'); +goog.require('ol.render.Feature'); +goog.require('ol.render.VectorContext'); +goog.require('ol.render.canvas.Immediate'); +goog.require('ol.render.webgl.Immediate'); +goog.require('ol.size'); +goog.require('ol.source.BingMaps'); +goog.require('ol.source.Cluster'); +goog.require('ol.source.Image'); +goog.require('ol.source.ImageCanvas'); +goog.require('ol.source.ImageEvent'); +goog.require('ol.source.ImageMapGuide'); +goog.require('ol.source.ImageStatic'); +goog.require('ol.source.ImageVector'); +goog.require('ol.source.ImageWMS'); +goog.require('ol.source.MapQuest'); +goog.require('ol.source.OSM'); +goog.require('ol.source.Raster'); +goog.require('ol.source.RasterEvent'); +goog.require('ol.source.RasterEventType'); +goog.require('ol.source.Source'); +goog.require('ol.source.Stamen'); +goog.require('ol.source.State'); +goog.require('ol.source.Tile'); +goog.require('ol.source.TileArcGISRest'); +goog.require('ol.source.TileDebug'); +goog.require('ol.source.TileEvent'); +goog.require('ol.source.TileImage'); +goog.require('ol.source.TileJSON'); +goog.require('ol.source.TileOptions'); +goog.require('ol.source.TileUTFGrid'); +goog.require('ol.source.TileWMS'); +goog.require('ol.source.UrlTile'); +goog.require('ol.source.Vector'); +goog.require('ol.source.VectorEvent'); +goog.require('ol.source.VectorEventType'); +goog.require('ol.source.VectorTile'); +goog.require('ol.source.WMTS'); +goog.require('ol.source.WMTSRequestEncoding'); +goog.require('ol.source.XYZ'); +goog.require('ol.source.Zoomify'); +goog.require('ol.style.Atlas'); +goog.require('ol.style.AtlasManager'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.GeometryFunction'); +goog.require('ol.style.Icon'); +goog.require('ol.style.IconAnchorUnits'); +goog.require('ol.style.IconImageCache'); +goog.require('ol.style.IconOrigin'); +goog.require('ol.style.Image'); +goog.require('ol.style.ImageState'); +goog.require('ol.style.RegularShape'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); +goog.require('ol.style.StyleFunction'); +goog.require('ol.style.Text'); +goog.require('ol.style.defaultGeometryFunction'); +goog.require('ol.tilegrid.TileGrid'); +goog.require('ol.tilegrid.WMTS'); +goog.require('ol.tilejson'); +goog.require('ol.webgl.Context'); +goog.require('ol.xml'); +goog.require('olcs.AbstractSynchronizer'); +goog.require('olcs.AutoRenderLoop'); +goog.require('olcs.Camera'); +goog.require('olcs.DragBox'); +goog.require('olcs.DragBoxEventType'); +goog.require('olcs.FeatureConverter'); +goog.require('olcs.GaRasterSynchronizer'); +goog.require('olcs.OLCesium'); +goog.require('olcs.RasterSynchronizer'); +goog.require('olcs.VectorSynchronizer'); +goog.require('olcs.core'); + + +goog.exportSymbol( + 'ol.animation.bounce', + ol.animation.bounce); + +goog.exportSymbol( + 'ol.animation.pan', + ol.animation.pan); + +goog.exportSymbol( + 'ol.animation.rotate', + ol.animation.rotate); + +goog.exportSymbol( + 'ol.animation.zoom', + ol.animation.zoom); + +goog.exportSymbol( + 'ol.Attribution', + ol.Attribution); + +goog.exportProperty( + ol.Attribution.prototype, + 'getHTML', + ol.Attribution.prototype.getHTML); + +goog.exportProperty( + ol.CollectionEvent.prototype, + 'element', + ol.CollectionEvent.prototype.element); + +goog.exportSymbol( + 'ol.Collection', + ol.Collection); + +goog.exportProperty( + ol.Collection.prototype, + 'clear', + ol.Collection.prototype.clear); + +goog.exportProperty( + ol.Collection.prototype, + 'extend', + ol.Collection.prototype.extend); + +goog.exportProperty( + ol.Collection.prototype, + 'forEach', + ol.Collection.prototype.forEach); + +goog.exportProperty( + ol.Collection.prototype, + 'getArray', + ol.Collection.prototype.getArray); + +goog.exportProperty( + ol.Collection.prototype, + 'item', + ol.Collection.prototype.item); + +goog.exportProperty( + ol.Collection.prototype, + 'getLength', + ol.Collection.prototype.getLength); + +goog.exportProperty( + ol.Collection.prototype, + 'insertAt', + ol.Collection.prototype.insertAt); + +goog.exportProperty( + ol.Collection.prototype, + 'pop', + ol.Collection.prototype.pop); + +goog.exportProperty( + ol.Collection.prototype, + 'push', + ol.Collection.prototype.push); + +goog.exportProperty( + ol.Collection.prototype, + 'remove', + ol.Collection.prototype.remove); + +goog.exportProperty( + ol.Collection.prototype, + 'removeAt', + ol.Collection.prototype.removeAt); + +goog.exportProperty( + ol.Collection.prototype, + 'setAt', + ol.Collection.prototype.setAt); + +goog.exportSymbol( + 'ol.coordinate.add', + ol.coordinate.add); + +goog.exportSymbol( + 'ol.coordinate.createStringXY', + ol.coordinate.createStringXY); + +goog.exportSymbol( + 'ol.coordinate.format', + ol.coordinate.format); + +goog.exportSymbol( + 'ol.coordinate.rotate', + ol.coordinate.rotate); + +goog.exportSymbol( + 'ol.coordinate.toStringHDMS', + ol.coordinate.toStringHDMS); + +goog.exportSymbol( + 'ol.coordinate.toStringXY', + ol.coordinate.toStringXY); + +goog.exportSymbol( + 'ol.DeviceOrientation', + ol.DeviceOrientation); + +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getAlpha', + ol.DeviceOrientation.prototype.getAlpha); + +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getBeta', + ol.DeviceOrientation.prototype.getBeta); + +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getGamma', + ol.DeviceOrientation.prototype.getGamma); + +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getHeading', + ol.DeviceOrientation.prototype.getHeading); + +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getTracking', + ol.DeviceOrientation.prototype.getTracking); + +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'setTracking', + ol.DeviceOrientation.prototype.setTracking); + +goog.exportSymbol( + 'ol.easing.easeIn', + ol.easing.easeIn); + +goog.exportSymbol( + 'ol.easing.easeOut', + ol.easing.easeOut); + +goog.exportSymbol( + 'ol.easing.inAndOut', + ol.easing.inAndOut); -goog.require('goog.array'); -goog.require('goog.dom'); -goog.require('goog.events.BrowserEvent'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.log'); -goog.require('goog.log.Level'); +goog.exportSymbol( + 'ol.easing.linear', + ol.easing.linear); +goog.exportSymbol( + 'ol.easing.upAndDown', + ol.easing.upAndDown); +goog.exportSymbol( + 'ol.extent.boundingExtent', + ol.extent.boundingExtent); -/** - * A files drag and drop event detector. Gets an {@code element} as parameter - * and fires {@code goog.events.FileDropHandler.EventType.DROP} event when files - * are dropped in the {@code element}. - * - * @param {Element|Document} element The element or document to listen on. - * @param {boolean=} opt_preventDropOutside Whether to prevent a drop on the - * area outside the {@code element}. Default false. - * @constructor - * @extends {goog.events.EventTarget} - * @final - */ -goog.events.FileDropHandler = function(element, opt_preventDropOutside) { - goog.events.EventTarget.call(this); +goog.exportSymbol( + 'ol.extent.buffer', + ol.extent.buffer); - /** - * Handler for drag/drop events. - * @type {!goog.events.EventHandler<!goog.events.FileDropHandler>} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); +goog.exportSymbol( + 'ol.extent.containsCoordinate', + ol.extent.containsCoordinate); - var doc = element; - if (opt_preventDropOutside) { - doc = goog.dom.getOwnerDocument(element); - } +goog.exportSymbol( + 'ol.extent.containsExtent', + ol.extent.containsExtent); - // Add dragenter listener to the owner document of the element. - this.eventHandler_.listen(doc, - goog.events.EventType.DRAGENTER, - this.onDocDragEnter_); +goog.exportSymbol( + 'ol.extent.containsXY', + ol.extent.containsXY); - // Add dragover listener to the owner document of the element only if the - // document is not the element itself. - if (doc != element) { - this.eventHandler_.listen(doc, - goog.events.EventType.DRAGOVER, - this.onDocDragOver_); - } +goog.exportSymbol( + 'ol.extent.createEmpty', + ol.extent.createEmpty); - // Add dragover and drop listeners to the element. - this.eventHandler_.listen(element, - goog.events.EventType.DRAGOVER, - this.onElemDragOver_); - this.eventHandler_.listen(element, - goog.events.EventType.DROP, - this.onElemDrop_); -}; -goog.inherits(goog.events.FileDropHandler, goog.events.EventTarget); +goog.exportSymbol( + 'ol.extent.equals', + ol.extent.equals); +goog.exportSymbol( + 'ol.extent.extend', + ol.extent.extend); -/** - * Whether the drag event contains files. It is initialized only in the - * dragenter event. It is used in all the drag events to prevent default actions - * only if the drag contains files. Preventing default actions is necessary to - * go from dragenter to dragover and from dragover to drop. However we do not - * always want to prevent default actions, e.g. when the user drags text or - * links on a text area we should not prevent the browser default action that - * inserts the text in the text area. It is also necessary to stop propagation - * when handling drag events on the element to prevent them from propagating - * to the document. - * @private - * @type {boolean} - */ -goog.events.FileDropHandler.prototype.dndContainsFiles_ = false; +goog.exportSymbol( + 'ol.extent.getBottomLeft', + ol.extent.getBottomLeft); +goog.exportSymbol( + 'ol.extent.getBottomRight', + ol.extent.getBottomRight); -/** - * A logger, used to help us debug the algorithm. - * @type {goog.log.Logger} - * @private - */ -goog.events.FileDropHandler.prototype.logger_ = - goog.log.getLogger('goog.events.FileDropHandler'); +goog.exportSymbol( + 'ol.extent.getCenter', + ol.extent.getCenter); +goog.exportSymbol( + 'ol.extent.getHeight', + ol.extent.getHeight); -/** - * The types of events fired by this class. - * @enum {string} - */ -goog.events.FileDropHandler.EventType = { - DROP: goog.events.EventType.DROP -}; +goog.exportSymbol( + 'ol.extent.getIntersection', + ol.extent.getIntersection); +goog.exportSymbol( + 'ol.extent.getSize', + ol.extent.getSize); -/** @override */ -goog.events.FileDropHandler.prototype.disposeInternal = function() { - goog.events.FileDropHandler.superClass_.disposeInternal.call(this); - this.eventHandler_.dispose(); -}; +goog.exportSymbol( + 'ol.extent.getTopLeft', + ol.extent.getTopLeft); +goog.exportSymbol( + 'ol.extent.getTopRight', + ol.extent.getTopRight); -/** - * Dispatches the DROP event. - * @param {goog.events.BrowserEvent} e The underlying browser event. - * @private - */ -goog.events.FileDropHandler.prototype.dispatch_ = function(e) { - goog.log.fine(this.logger_, 'Firing DROP event...'); - var event = new goog.events.BrowserEvent(e.getBrowserEvent()); - event.type = goog.events.FileDropHandler.EventType.DROP; - this.dispatchEvent(event); -}; +goog.exportSymbol( + 'ol.extent.getWidth', + ol.extent.getWidth); +goog.exportSymbol( + 'ol.extent.intersects', + ol.extent.intersects); -/** - * Handles dragenter on the document. - * @param {goog.events.BrowserEvent} e The dragenter event. - * @private - */ -goog.events.FileDropHandler.prototype.onDocDragEnter_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINER, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - var dt = e.getBrowserEvent().dataTransfer; - // Check whether the drag event contains files. - this.dndContainsFiles_ = !!(dt && - ((dt.types && - (goog.array.contains(dt.types, 'Files') || - goog.array.contains(dt.types, 'public.file-url'))) || - (dt.files && dt.files.length > 0))); - // If it does - if (this.dndContainsFiles_) { - // Prevent default actions. - e.preventDefault(); - } - goog.log.log(this.logger_, goog.log.Level.FINER, - 'dndContainsFiles_: ' + this.dndContainsFiles_); -}; +goog.exportSymbol( + 'ol.extent.isEmpty', + ol.extent.isEmpty); +goog.exportSymbol( + 'ol.extent.applyTransform', + ol.extent.applyTransform); -/** - * Handles dragging something over the document. - * @param {goog.events.BrowserEvent} e The dragover event. - * @private - */ -goog.events.FileDropHandler.prototype.onDocDragOver_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINEST, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - if (this.dndContainsFiles_) { - // Prevent default actions. - e.preventDefault(); - // Disable the drop on the document outside the drop zone. - var dt = e.getBrowserEvent().dataTransfer; - dt.dropEffect = 'none'; - } -}; +goog.exportSymbol( + 'ol.Feature', + ol.Feature); +goog.exportProperty( + ol.Feature.prototype, + 'clone', + ol.Feature.prototype.clone); -/** - * Handles dragging something over the element (drop zone). - * @param {goog.events.BrowserEvent} e The dragover event. - * @private - */ -goog.events.FileDropHandler.prototype.onElemDragOver_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINEST, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - if (this.dndContainsFiles_) { - // Prevent default actions and stop the event from propagating further to - // the document. Both lines are needed! (See comment above). - e.preventDefault(); - e.stopPropagation(); - // Allow the drop on the drop zone. - var dt = e.getBrowserEvent().dataTransfer; +goog.exportProperty( + ol.Feature.prototype, + 'getGeometry', + ol.Feature.prototype.getGeometry); - // IE bug #811625 (https://goo.gl/UWuxX0) will throw error SCRIPT65535 - // when attempting to set property effectAllowed on IE10+. - // See more: https://github.com/google/closure-library/issues/485. - try { - dt.effectAllowed = 'all'; - } catch (err) { - } - dt.dropEffect = 'copy'; - } -}; +goog.exportProperty( + ol.Feature.prototype, + 'getId', + ol.Feature.prototype.getId); +goog.exportProperty( + ol.Feature.prototype, + 'getGeometryName', + ol.Feature.prototype.getGeometryName); -/** - * Handles dropping something onto the element (drop zone). - * @param {goog.events.BrowserEvent} e The drop event. - * @private - */ -goog.events.FileDropHandler.prototype.onElemDrop_ = function(e) { - goog.log.log(this.logger_, goog.log.Level.FINER, - '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type); - // If the drag and drop event contains files. - if (this.dndContainsFiles_) { - // Prevent default actions and stop the event from propagating further to - // the document. Both lines are needed! (See comment above). - e.preventDefault(); - e.stopPropagation(); - // Dispatch DROP event. - this.dispatch_(e); - } -}; +goog.exportProperty( + ol.Feature.prototype, + 'getStyle', + ol.Feature.prototype.getStyle); -// Copyright 2007 Bob Ippolito. All Rights Reserved. -// Modifications Copyright 2009 The Closure Library Authors. All Rights -// Reserved. +goog.exportProperty( + ol.Feature.prototype, + 'getStyleFunction', + ol.Feature.prototype.getStyleFunction); -/** - * @license Portions of this code are from MochiKit, received by - * The Closure Authors under the MIT license. All other code is Copyright - * 2005-2009 The Closure Authors. All Rights Reserved. - */ +goog.exportProperty( + ol.Feature.prototype, + 'setGeometry', + ol.Feature.prototype.setGeometry); -/** - * @fileoverview Classes for tracking asynchronous operations and handling the - * results. The Deferred object here is patterned after the Deferred object in - * the Twisted python networking framework. - * - * See: http://twistedmatrix.com/projects/core/documentation/howto/defer.html - * - * Based on the Dojo code which in turn is based on the MochiKit code. - * - * @author arv@google.com (Erik Arvidsson) - * @author brenneman@google.com (Shawn Brenneman) - */ +goog.exportProperty( + ol.Feature.prototype, + 'setStyle', + ol.Feature.prototype.setStyle); -goog.provide('goog.async.Deferred'); -goog.provide('goog.async.Deferred.AlreadyCalledError'); -goog.provide('goog.async.Deferred.CanceledError'); +goog.exportProperty( + ol.Feature.prototype, + 'setId', + ol.Feature.prototype.setId); -goog.require('goog.Promise'); -goog.require('goog.Thenable'); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.debug.Error'); +goog.exportProperty( + ol.Feature.prototype, + 'setGeometryName', + ol.Feature.prototype.setGeometryName); +goog.exportSymbol( + 'ol.featureloader.tile', + ol.featureloader.tile); +goog.exportSymbol( + 'ol.featureloader.xhr', + ol.featureloader.xhr); -/** - * A Deferred represents the result of an asynchronous operation. A Deferred - * instance has no result when it is created, and is "fired" (given an initial - * result) by calling {@code callback} or {@code errback}. - * - * Once fired, the result is passed through a sequence of callback functions - * registered with {@code addCallback} or {@code addErrback}. The functions may - * mutate the result before it is passed to the next function in the sequence. - * - * Callbacks and errbacks may be added at any time, including after the Deferred - * has been "fired". If there are no pending actions in the execution sequence - * of a fired Deferred, any new callback functions will be called with the last - * computed result. Adding a callback function is the only way to access the - * result of the Deferred. - * - * If a Deferred operation is canceled, an optional user-provided cancellation - * function is invoked which may perform any special cleanup, followed by firing - * the Deferred's errback sequence with a {@code CanceledError}. If the - * Deferred has already fired, cancellation is ignored. - * - * Deferreds may be templated to a specific type they produce using generics - * with syntax such as: - * <code> - * /** @type {goog.async.Deferred<string>} */ - * var d = new goog.async.Deferred(); - * // Compiler can infer that foo is a string. - * d.addCallback(function(foo) {...}); - * d.callback('string'); // Checked to be passed a string - * </code> - * Since deferreds are often used to produce different values across a chain, - * the type information is not propagated across chains, but rather only - * associated with specifically cast objects. - * - * @param {Function=} opt_onCancelFunction A function that will be called if the - * Deferred is canceled. If provided, this function runs before the - * Deferred is fired with a {@code CanceledError}. - * @param {Object=} opt_defaultScope The default object context to call - * callbacks and errbacks in. - * @constructor - * @implements {goog.Thenable<VALUE>} - * @template VALUE - */ -goog.async.Deferred = function(opt_onCancelFunction, opt_defaultScope) { - /** - * Entries in the sequence are arrays containing a callback, an errback, and - * an optional scope. The callback or errback in an entry may be null. - * @type {!Array<!Array>} - * @private - */ - this.sequence_ = []; +goog.exportSymbol( + 'ol.Geolocation', + ol.Geolocation); - /** - * Optional function that will be called if the Deferred is canceled. - * @type {Function|undefined} - * @private - */ - this.onCancelFunction_ = opt_onCancelFunction; +goog.exportProperty( + ol.Geolocation.prototype, + 'getAccuracy', + ol.Geolocation.prototype.getAccuracy); - /** - * The default scope to execute callbacks and errbacks in. - * @type {Object} - * @private - */ - this.defaultScope_ = opt_defaultScope || null; +goog.exportProperty( + ol.Geolocation.prototype, + 'getAccuracyGeometry', + ol.Geolocation.prototype.getAccuracyGeometry); - /** - * Whether the Deferred has been fired. - * @type {boolean} - * @private - */ - this.fired_ = false; +goog.exportProperty( + ol.Geolocation.prototype, + 'getAltitude', + ol.Geolocation.prototype.getAltitude); - /** - * Whether the last result in the execution sequence was an error. - * @type {boolean} - * @private - */ - this.hadError_ = false; +goog.exportProperty( + ol.Geolocation.prototype, + 'getAltitudeAccuracy', + ol.Geolocation.prototype.getAltitudeAccuracy); - /** - * The current Deferred result, updated as callbacks and errbacks are - * executed. - * @type {*} - * @private - */ - this.result_ = undefined; +goog.exportProperty( + ol.Geolocation.prototype, + 'getHeading', + ol.Geolocation.prototype.getHeading); - /** - * Whether the Deferred is blocked waiting on another Deferred to fire. If a - * callback or errback returns a Deferred as a result, the execution sequence - * is blocked until that Deferred result becomes available. - * @type {boolean} - * @private - */ - this.blocked_ = false; +goog.exportProperty( + ol.Geolocation.prototype, + 'getPosition', + ol.Geolocation.prototype.getPosition); - /** - * Whether this Deferred is blocking execution of another Deferred. If this - * instance was returned as a result in another Deferred's execution - * sequence,that other Deferred becomes blocked until this instance's - * execution sequence completes. No additional callbacks may be added to a - * Deferred once it is blocking another instance. - * @type {boolean} - * @private - */ - this.blocking_ = false; +goog.exportProperty( + ol.Geolocation.prototype, + 'getProjection', + ol.Geolocation.prototype.getProjection); - /** - * Whether the Deferred has been canceled without having a custom cancel - * function. - * @type {boolean} - * @private - */ - this.silentlyCanceled_ = false; +goog.exportProperty( + ol.Geolocation.prototype, + 'getSpeed', + ol.Geolocation.prototype.getSpeed); - /** - * If an error is thrown during Deferred execution with no errback to catch - * it, the error is rethrown after a timeout. Reporting the error after a - * timeout allows execution to continue in the calling context (empty when - * no error is scheduled). - * @type {number} - * @private - */ - this.unhandledErrorId_ = 0; +goog.exportProperty( + ol.Geolocation.prototype, + 'getTracking', + ol.Geolocation.prototype.getTracking); - /** - * If this Deferred was created by branch(), this will be the "parent" - * Deferred. - * @type {goog.async.Deferred} - * @private - */ - this.parent_ = null; +goog.exportProperty( + ol.Geolocation.prototype, + 'getTrackingOptions', + ol.Geolocation.prototype.getTrackingOptions); - /** - * The number of Deferred objects that have been branched off this one. This - * will be decremented whenever a branch is fired or canceled. - * @type {number} - * @private - */ - this.branches_ = 0; +goog.exportProperty( + ol.Geolocation.prototype, + 'setProjection', + ol.Geolocation.prototype.setProjection); - if (goog.async.Deferred.LONG_STACK_TRACES) { - /** - * Holds the stack trace at time of deferred creation if the JS engine - * provides the Error.captureStackTrace API. - * @private {?string} - */ - this.constructorStack_ = null; - if (Error.captureStackTrace) { - var target = { stack: '' }; - Error.captureStackTrace(target, goog.async.Deferred); - // Check if Error.captureStackTrace worked. It fails in gjstest. - if (typeof target.stack == 'string') { - // Remove first line and force stringify to prevent memory leak due to - // holding on to actual stack frames. - this.constructorStack_ = target.stack.replace(/^[^\n]*\n/, ''); - } - } - } -}; +goog.exportProperty( + ol.Geolocation.prototype, + 'setTracking', + ol.Geolocation.prototype.setTracking); +goog.exportProperty( + ol.Geolocation.prototype, + 'setTrackingOptions', + ol.Geolocation.prototype.setTrackingOptions); -/** - * @define {boolean} Whether unhandled errors should always get rethrown to the - * global scope. Defaults to the value of goog.DEBUG. - */ -goog.define('goog.async.Deferred.STRICT_ERRORS', false); +goog.exportSymbol( + 'ol.Graticule', + ol.Graticule); +goog.exportProperty( + ol.Graticule.prototype, + 'getMap', + ol.Graticule.prototype.getMap); -/** - * @define {boolean} Whether to attempt to make stack traces long. Defaults to - * the value of goog.DEBUG. - */ -goog.define('goog.async.Deferred.LONG_STACK_TRACES', false); +goog.exportProperty( + ol.Graticule.prototype, + 'getMeridians', + ol.Graticule.prototype.getMeridians); +goog.exportProperty( + ol.Graticule.prototype, + 'getParallels', + ol.Graticule.prototype.getParallels); -/** - * Cancels a Deferred that has not yet been fired, or is blocked on another - * deferred operation. If this Deferred is waiting for a blocking Deferred to - * fire, the blocking Deferred will also be canceled. - * - * If this Deferred was created by calling branch() on a parent Deferred with - * opt_propagateCancel set to true, the parent may also be canceled. If - * opt_deepCancel is set, cancel() will be called on the parent (as well as any - * other ancestors if the parent is also a branch). If one or more branches were - * created with opt_propagateCancel set to true, the parent will be canceled if - * cancel() is called on all of those branches. - * - * @param {boolean=} opt_deepCancel If true, cancels this Deferred's parent even - * if cancel() hasn't been called on some of the parent's branches. Has no - * effect on a branch without opt_propagateCancel set to true. - */ -goog.async.Deferred.prototype.cancel = function(opt_deepCancel) { - if (!this.hasFired()) { - if (this.parent_) { - // Get rid of the parent reference before potentially running the parent's - // canceler function to ensure that this cancellation isn't - // double-counted. - var parent = this.parent_; - delete this.parent_; - if (opt_deepCancel) { - parent.cancel(opt_deepCancel); - } else { - parent.branchCancel_(); - } - } +goog.exportProperty( + ol.Graticule.prototype, + 'setMap', + ol.Graticule.prototype.setMap); - if (this.onCancelFunction_) { - // Call in user-specified scope. - this.onCancelFunction_.call(this.defaultScope_, this); - } else { - this.silentlyCanceled_ = true; - } - if (!this.hasFired()) { - this.errback(new goog.async.Deferred.CanceledError(this)); - } - } else if (this.result_ instanceof goog.async.Deferred) { - this.result_.cancel(); - } -}; +goog.exportSymbol( + 'ol.has.DEVICE_PIXEL_RATIO', + ol.has.DEVICE_PIXEL_RATIO); +goog.exportSymbol( + 'ol.has.CANVAS', + ol.has.CANVAS); -/** - * Handle a single branch being canceled. Once all branches are canceled, this - * Deferred will be canceled as well. - * - * @private - */ -goog.async.Deferred.prototype.branchCancel_ = function() { - this.branches_--; - if (this.branches_ <= 0) { - this.cancel(); - } -}; +goog.exportSymbol( + 'ol.has.DEVICE_ORIENTATION', + ol.has.DEVICE_ORIENTATION); +goog.exportSymbol( + 'ol.has.GEOLOCATION', + ol.has.GEOLOCATION); -/** - * Called after a blocking Deferred fires. Unblocks this Deferred and resumes - * its execution sequence. - * - * @param {boolean} isSuccess Whether the result is a success or an error. - * @param {*} res The result of the blocking Deferred. - * @private - */ -goog.async.Deferred.prototype.continue_ = function(isSuccess, res) { - this.blocked_ = false; - this.updateResult_(isSuccess, res); -}; +goog.exportSymbol( + 'ol.has.TOUCH', + ol.has.TOUCH); +goog.exportSymbol( + 'ol.has.WEBGL', + ol.has.WEBGL); -/** - * Updates the current result based on the success or failure of the last action - * in the execution sequence. - * - * @param {boolean} isSuccess Whether the new result is a success or an error. - * @param {*} res The result. - * @private - */ -goog.async.Deferred.prototype.updateResult_ = function(isSuccess, res) { - this.fired_ = true; - this.result_ = res; - this.hadError_ = !isSuccess; - this.fire_(); -}; +goog.exportProperty( + ol.Image.prototype, + 'getImage', + ol.Image.prototype.getImage); +goog.exportProperty( + ol.ImageTile.prototype, + 'getImage', + ol.ImageTile.prototype.getImage); -/** - * Verifies that the Deferred has not yet been fired. - * - * @private - * @throws {Error} If this has already been fired. - */ -goog.async.Deferred.prototype.check_ = function() { - if (this.hasFired()) { - if (!this.silentlyCanceled_) { - throw new goog.async.Deferred.AlreadyCalledError(this); - } - this.silentlyCanceled_ = false; - } -}; +goog.exportSymbol( + 'ol.Kinetic', + ol.Kinetic); +goog.exportSymbol( + 'ol.loadingstrategy.all', + ol.loadingstrategy.all); -/** - * Fire the execution sequence for this Deferred by passing the starting result - * to the first registered callback. - * @param {VALUE=} opt_result The starting result. - */ -goog.async.Deferred.prototype.callback = function(opt_result) { - this.check_(); - this.assertNotDeferred_(opt_result); - this.updateResult_(true /* isSuccess */, opt_result); -}; +goog.exportSymbol( + 'ol.loadingstrategy.bbox', + ol.loadingstrategy.bbox); +goog.exportSymbol( + 'ol.loadingstrategy.tile', + ol.loadingstrategy.tile); -/** - * Fire the execution sequence for this Deferred by passing the starting error - * result to the first registered errback. - * @param {*=} opt_result The starting error. - */ -goog.async.Deferred.prototype.errback = function(opt_result) { - this.check_(); - this.assertNotDeferred_(opt_result); - this.makeStackTraceLong_(opt_result); - this.updateResult_(false /* isSuccess */, opt_result); -}; +goog.exportSymbol( + 'ol.Map', + ol.Map); +goog.exportProperty( + ol.Map.prototype, + 'addControl', + ol.Map.prototype.addControl); -/** - * Attempt to make the error's stack trace be long in that it contains the - * stack trace from the point where the deferred was created on top of the - * current stack trace to give additional context. - * @param {*} error - * @private - */ -goog.async.Deferred.prototype.makeStackTraceLong_ = function(error) { - if (!goog.async.Deferred.LONG_STACK_TRACES) { - return; - } - if (this.constructorStack_ && goog.isObject(error) && error.stack && - // Stack looks like it was system generated. See - // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi - (/^[^\n]+(\n [^\n]+)+/).test(error.stack)) { - error.stack = error.stack + '\nDEFERRED OPERATION:\n' + - this.constructorStack_; - } -}; +goog.exportProperty( + ol.Map.prototype, + 'addInteraction', + ol.Map.prototype.addInteraction); +goog.exportProperty( + ol.Map.prototype, + 'addLayer', + ol.Map.prototype.addLayer); -/** - * Asserts that an object is not a Deferred. - * @param {*} obj The object to test. - * @throws {Error} Throws an exception if the object is a Deferred. - * @private - */ -goog.async.Deferred.prototype.assertNotDeferred_ = function(obj) { - goog.asserts.assert( - !(obj instanceof goog.async.Deferred), - 'An execution sequence may not be initiated with a blocking Deferred.'); -}; +goog.exportProperty( + ol.Map.prototype, + 'addOverlay', + ol.Map.prototype.addOverlay); +goog.exportProperty( + ol.Map.prototype, + 'beforeRender', + ol.Map.prototype.beforeRender); -/** - * Register a callback function to be called with a successful result. If no - * value is returned by the callback function, the result value is unchanged. If - * a new value is returned, it becomes the Deferred result and will be passed to - * the next callback in the execution sequence. - * - * If the function throws an error, the error becomes the new result and will be - * passed to the next errback in the execution chain. - * - * If the function returns a Deferred, the execution sequence will be blocked - * until that Deferred fires. Its result will be passed to the next callback (or - * errback if it is an error result) in this Deferred's execution sequence. - * - * @param {!function(this:T,VALUE):?} cb The function to be called with a - * successful result. - * @param {T=} opt_scope An optional scope to call the callback in. - * @return {!goog.async.Deferred} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addCallback = function(cb, opt_scope) { - return this.addCallbacks(cb, null, opt_scope); -}; +goog.exportProperty( + ol.Map.prototype, + 'forEachFeatureAtPixel', + ol.Map.prototype.forEachFeatureAtPixel); +goog.exportProperty( + ol.Map.prototype, + 'forEachLayerAtPixel', + ol.Map.prototype.forEachLayerAtPixel); -/** - * Register a callback function to be called with an error result. If no value - * is returned by the function, the error result is unchanged. If a new error - * value is returned or thrown, that error becomes the Deferred result and will - * be passed to the next errback in the execution sequence. - * - * If the errback function handles the error by returning a non-error value, - * that result will be passed to the next normal callback in the sequence. - * - * If the function returns a Deferred, the execution sequence will be blocked - * until that Deferred fires. Its result will be passed to the next callback (or - * errback if it is an error result) in this Deferred's execution sequence. - * - * @param {!function(this:T,?):?} eb The function to be called on an - * unsuccessful result. - * @param {T=} opt_scope An optional scope to call the errback in. - * @return {!goog.async.Deferred<VALUE>} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addErrback = function(eb, opt_scope) { - return this.addCallbacks(null, eb, opt_scope); -}; +goog.exportProperty( + ol.Map.prototype, + 'hasFeatureAtPixel', + ol.Map.prototype.hasFeatureAtPixel); +goog.exportProperty( + ol.Map.prototype, + 'getEventCoordinate', + ol.Map.prototype.getEventCoordinate); -/** - * Registers one function as both a callback and errback. - * - * @param {!function(this:T,?):?} f The function to be called on any result. - * @param {T=} opt_scope An optional scope to call the function in. - * @return {!goog.async.Deferred} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addBoth = function(f, opt_scope) { - return this.addCallbacks(f, f, opt_scope); -}; +goog.exportProperty( + ol.Map.prototype, + 'getEventPixel', + ol.Map.prototype.getEventPixel); +goog.exportProperty( + ol.Map.prototype, + 'getTarget', + ol.Map.prototype.getTarget); -/** - * Like addBoth, but propagates uncaught exceptions in the errback. - * - * @param {function(this:T,?):?} f The function to be called on any result. - * @param {T=} opt_scope An optional scope to call the function in. - * @return {!goog.async.Deferred<VALUE>} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addFinally = function(f, opt_scope) { - var self = this; - return this.addCallbacks(f, function(err) { - var result = f.call(self, err); - if (!goog.isDef(result)) { - throw err; - } - return result; - }, opt_scope); -}; +goog.exportProperty( + ol.Map.prototype, + 'getTargetElement', + ol.Map.prototype.getTargetElement); +goog.exportProperty( + ol.Map.prototype, + 'getCoordinateFromPixel', + ol.Map.prototype.getCoordinateFromPixel); -/** - * Registers a callback function and an errback function at the same position - * in the execution sequence. Only one of these functions will execute, - * depending on the error state during the execution sequence. - * - * NOTE: This is not equivalent to {@code def.addCallback().addErrback()}! If - * the callback is invoked, the errback will be skipped, and vice versa. - * - * @param {?(function(this:T,VALUE):?)} cb The function to be called on a - * successful result. - * @param {?(function(this:T,?):?)} eb The function to be called on an - * unsuccessful result. - * @param {T=} opt_scope An optional scope to call the functions in. - * @return {!goog.async.Deferred} This Deferred. - * @template T - */ -goog.async.Deferred.prototype.addCallbacks = function(cb, eb, opt_scope) { - goog.asserts.assert(!this.blocking_, 'Blocking Deferreds can not be re-used'); - this.sequence_.push([cb, eb, opt_scope]); - if (this.hasFired()) { - this.fire_(); - } - return this; -}; +goog.exportProperty( + ol.Map.prototype, + 'getControls', + ol.Map.prototype.getControls); +goog.exportProperty( + ol.Map.prototype, + 'getOverlays', + ol.Map.prototype.getOverlays); -/** - * Implements {@see goog.Thenable} for seamless integration with - * {@see goog.Promise}. - * Deferred results are mutable and may represent multiple values over - * their lifetime. Calling {@code then} on a Deferred returns a Promise - * with the result of the Deferred at that point in its callback chain. - * Note that if the Deferred result is never mutated, and only - * {@code then} calls are made, the Deferred will behave like a Promise. - * - * @override - */ -goog.async.Deferred.prototype.then = function(opt_onFulfilled, opt_onRejected, - opt_context) { - var resolve, reject; - var promise = new goog.Promise(function(res, rej) { - // Copying resolvers to outer scope, so that they are available when the - // deferred callback fires (which may be synchronous). - resolve = res; - reject = rej; - }); - this.addCallbacks(resolve, function(reason) { - if (reason instanceof goog.async.Deferred.CanceledError) { - promise.cancel(); - } else { - reject(reason); - } - }); - return promise.then(opt_onFulfilled, opt_onRejected, opt_context); -}; -goog.Thenable.addImplementation(goog.async.Deferred); +goog.exportProperty( + ol.Map.prototype, + 'getOverlayById', + ol.Map.prototype.getOverlayById); +goog.exportProperty( + ol.Map.prototype, + 'getInteractions', + ol.Map.prototype.getInteractions); -/** - * Links another Deferred to the end of this Deferred's execution sequence. The - * result of this execution sequence will be passed as the starting result for - * the chained Deferred, invoking either its first callback or errback. - * - * @param {!goog.async.Deferred} otherDeferred The Deferred to chain. - * @return {!goog.async.Deferred} This Deferred. - */ -goog.async.Deferred.prototype.chainDeferred = function(otherDeferred) { - this.addCallbacks( - otherDeferred.callback, otherDeferred.errback, otherDeferred); - return this; -}; +goog.exportProperty( + ol.Map.prototype, + 'getLayerGroup', + ol.Map.prototype.getLayerGroup); +goog.exportProperty( + ol.Map.prototype, + 'getLayers', + ol.Map.prototype.getLayers); -/** - * Makes this Deferred wait for another Deferred's execution sequence to - * complete before continuing. - * - * This is equivalent to adding a callback that returns {@code otherDeferred}, - * but doesn't prevent additional callbacks from being added to - * {@code otherDeferred}. - * - * @param {!goog.async.Deferred|!goog.Thenable} otherDeferred The Deferred - * to wait for. - * @return {!goog.async.Deferred} This Deferred. - */ -goog.async.Deferred.prototype.awaitDeferred = function(otherDeferred) { - if (!(otherDeferred instanceof goog.async.Deferred)) { - // The Thenable case. - return this.addCallback(function() { - return otherDeferred; - }); - } - return this.addCallback(goog.bind(otherDeferred.branch, otherDeferred)); -}; +goog.exportProperty( + ol.Map.prototype, + 'getPixelFromCoordinate', + ol.Map.prototype.getPixelFromCoordinate); +goog.exportProperty( + ol.Map.prototype, + 'getSize', + ol.Map.prototype.getSize); -/** - * Creates a branch off this Deferred's execution sequence, and returns it as a - * new Deferred. The branched Deferred's starting result will be shared with the - * parent at the point of the branch, even if further callbacks are added to the - * parent. - * - * All branches at the same stage in the execution sequence will receive the - * same starting value. - * - * @param {boolean=} opt_propagateCancel If cancel() is called on every child - * branch created with opt_propagateCancel, the parent will be canceled as - * well. - * @return {!goog.async.Deferred<VALUE>} A Deferred that will be started with - * the computed result from this stage in the execution sequence. - */ -goog.async.Deferred.prototype.branch = function(opt_propagateCancel) { - var d = new goog.async.Deferred(); - this.chainDeferred(d); - if (opt_propagateCancel) { - d.parent_ = this; - this.branches_++; - } - return d; -}; +goog.exportProperty( + ol.Map.prototype, + 'getView', + ol.Map.prototype.getView); +goog.exportProperty( + ol.Map.prototype, + 'getViewport', + ol.Map.prototype.getViewport); -/** - * @return {boolean} Whether the execution sequence has been started on this - * Deferred by invoking {@code callback} or {@code errback}. - */ -goog.async.Deferred.prototype.hasFired = function() { - return this.fired_; -}; +goog.exportProperty( + ol.Map.prototype, + 'renderSync', + ol.Map.prototype.renderSync); +goog.exportProperty( + ol.Map.prototype, + 'render', + ol.Map.prototype.render); -/** - * @param {*} res The latest result in the execution sequence. - * @return {boolean} Whether the current result is an error that should cause - * the next errback to fire. May be overridden by subclasses to handle - * special error types. - * @protected - */ -goog.async.Deferred.prototype.isError = function(res) { - return res instanceof Error; -}; +goog.exportProperty( + ol.Map.prototype, + 'removeControl', + ol.Map.prototype.removeControl); +goog.exportProperty( + ol.Map.prototype, + 'removeInteraction', + ol.Map.prototype.removeInteraction); -/** - * @return {boolean} Whether an errback exists in the remaining sequence. - * @private - */ -goog.async.Deferred.prototype.hasErrback_ = function() { - return goog.array.some(this.sequence_, function(sequenceRow) { - // The errback is the second element in the array. - return goog.isFunction(sequenceRow[1]); - }); -}; +goog.exportProperty( + ol.Map.prototype, + 'removeLayer', + ol.Map.prototype.removeLayer); +goog.exportProperty( + ol.Map.prototype, + 'removeOverlay', + ol.Map.prototype.removeOverlay); -/** - * Exhausts the execution sequence while a result is available. The result may - * be modified by callbacks or errbacks, and execution will block if the - * returned result is an incomplete Deferred. - * - * @private - */ -goog.async.Deferred.prototype.fire_ = function() { - if (this.unhandledErrorId_ && this.hasFired() && this.hasErrback_()) { - // It is possible to add errbacks after the Deferred has fired. If a new - // errback is added immediately after the Deferred encountered an unhandled - // error, but before that error is rethrown, the error is unscheduled. - goog.async.Deferred.unscheduleError_(this.unhandledErrorId_); - this.unhandledErrorId_ = 0; - } +goog.exportProperty( + ol.Map.prototype, + 'setLayerGroup', + ol.Map.prototype.setLayerGroup); - if (this.parent_) { - this.parent_.branches_--; - delete this.parent_; - } +goog.exportProperty( + ol.Map.prototype, + 'setSize', + ol.Map.prototype.setSize); - var res = this.result_; - var unhandledException = false; - var isNewlyBlocked = false; +goog.exportProperty( + ol.Map.prototype, + 'setTarget', + ol.Map.prototype.setTarget); - while (this.sequence_.length && !this.blocked_) { - var sequenceEntry = this.sequence_.shift(); +goog.exportProperty( + ol.Map.prototype, + 'setView', + ol.Map.prototype.setView); - var callback = sequenceEntry[0]; - var errback = sequenceEntry[1]; - var scope = sequenceEntry[2]; +goog.exportProperty( + ol.Map.prototype, + 'updateSize', + ol.Map.prototype.updateSize); - var f = this.hadError_ ? errback : callback; - if (f) { - /** @preserveTry */ - try { - var ret = f.call(scope || this.defaultScope_, res); +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'originalEvent', + ol.MapBrowserEvent.prototype.originalEvent); - // If no result, then use previous result. - if (goog.isDef(ret)) { - // Bubble up the error as long as the return value hasn't changed. - this.hadError_ = this.hadError_ && (ret == res || this.isError(ret)); - this.result_ = res = ret; - } +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'pixel', + ol.MapBrowserEvent.prototype.pixel); - if (goog.Thenable.isImplementedBy(res) || - (typeof goog.global['Promise'] === 'function' && - res instanceof goog.global['Promise'])) { - isNewlyBlocked = true; - this.blocked_ = true; - } +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'coordinate', + ol.MapBrowserEvent.prototype.coordinate); - } catch (ex) { - res = ex; - this.hadError_ = true; - this.makeStackTraceLong_(res); +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'dragging', + ol.MapBrowserEvent.prototype.dragging); - if (!this.hasErrback_()) { - // If an error is thrown with no additional errbacks in the queue, - // prepare to rethrow the error. - unhandledException = true; - } - } - } - } +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'preventDefault', + ol.MapBrowserEvent.prototype.preventDefault); - this.result_ = res; +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'stopPropagation', + ol.MapBrowserEvent.prototype.stopPropagation); - if (isNewlyBlocked) { - var onCallback = goog.bind(this.continue_, this, true /* isSuccess */); - var onErrback = goog.bind(this.continue_, this, false /* isSuccess */); +goog.exportProperty( + ol.MapEvent.prototype, + 'map', + ol.MapEvent.prototype.map); - if (res instanceof goog.async.Deferred) { - res.addCallbacks(onCallback, onErrback); - res.blocking_ = true; - } else { - res.then(onCallback, onErrback); - } - } else if (goog.async.Deferred.STRICT_ERRORS && this.isError(res) && - !(res instanceof goog.async.Deferred.CanceledError)) { - this.hadError_ = true; - unhandledException = true; - } +goog.exportProperty( + ol.MapEvent.prototype, + 'frameState', + ol.MapEvent.prototype.frameState); - if (unhandledException) { - // Rethrow the unhandled error after a timeout. Execution will continue, but - // the error will be seen by global handlers and the user. The throw will - // be canceled if another errback is appended before the timeout executes. - // The error's original stack trace is preserved where available. - this.unhandledErrorId_ = goog.async.Deferred.scheduleError_(res); - } -}; +goog.exportProperty( + ol.ObjectEvent.prototype, + 'key', + ol.ObjectEvent.prototype.key); +goog.exportProperty( + ol.ObjectEvent.prototype, + 'oldValue', + ol.ObjectEvent.prototype.oldValue); -/** - * Creates a Deferred that has an initial result. - * - * @param {*=} opt_result The result. - * @return {!goog.async.Deferred} The new Deferred. - */ -goog.async.Deferred.succeed = function(opt_result) { - var d = new goog.async.Deferred(); - d.callback(opt_result); - return d; -}; +goog.exportSymbol( + 'ol.Object', + ol.Object); +goog.exportProperty( + ol.Object.prototype, + 'get', + ol.Object.prototype.get); -/** - * Creates a Deferred that fires when the given promise resolves. - * Use only during migration to Promises. - * - * @param {!goog.Promise<T>} promise - * @return {!goog.async.Deferred<T>} The new Deferred. - * @template T - */ -goog.async.Deferred.fromPromise = function(promise) { - var d = new goog.async.Deferred(); - d.callback(); - d.addCallback(function() { - return promise; - }); - return d; -}; +goog.exportProperty( + ol.Object.prototype, + 'getKeys', + ol.Object.prototype.getKeys); +goog.exportProperty( + ol.Object.prototype, + 'getProperties', + ol.Object.prototype.getProperties); -/** - * Creates a Deferred that has an initial error result. - * - * @param {*} res The error result. - * @return {!goog.async.Deferred} The new Deferred. - */ -goog.async.Deferred.fail = function(res) { - var d = new goog.async.Deferred(); - d.errback(res); - return d; -}; +goog.exportProperty( + ol.Object.prototype, + 'set', + ol.Object.prototype.set); +goog.exportProperty( + ol.Object.prototype, + 'setProperties', + ol.Object.prototype.setProperties); -/** - * Creates a Deferred that has already been canceled. - * - * @return {!goog.async.Deferred} The new Deferred. - */ -goog.async.Deferred.canceled = function() { - var d = new goog.async.Deferred(); - d.cancel(); - return d; -}; +goog.exportProperty( + ol.Object.prototype, + 'unset', + ol.Object.prototype.unset); +goog.exportSymbol( + 'ol.Observable', + ol.Observable); -/** - * Normalizes values that may or may not be Deferreds. - * - * If the input value is a Deferred, the Deferred is branched (so the original - * execution sequence is not modified) and the input callback added to the new - * branch. The branch is returned to the caller. - * - * If the input value is not a Deferred, the callback will be executed - * immediately and an already firing Deferred will be returned to the caller. - * - * In the following (contrived) example, if <code>isImmediate</code> is true - * then 3 is alerted immediately, otherwise 6 is alerted after a 2-second delay. - * - * <pre> - * var value; - * if (isImmediate) { - * value = 3; - * } else { - * value = new goog.async.Deferred(); - * setTimeout(function() { value.callback(6); }, 2000); - * } - * - * var d = goog.async.Deferred.when(value, alert); - * </pre> - * - * @param {*} value Deferred or normal value to pass to the callback. - * @param {!function(this:T, ?):?} callback The callback to execute. - * @param {T=} opt_scope An optional scope to call the callback in. - * @return {!goog.async.Deferred} A new Deferred that will call the input - * callback with the input value. - * @template T - */ -goog.async.Deferred.when = function(value, callback, opt_scope) { - if (value instanceof goog.async.Deferred) { - return value.branch(true).addCallback(callback, opt_scope); - } else { - return goog.async.Deferred.succeed(value).addCallback(callback, opt_scope); - } -}; +goog.exportSymbol( + 'ol.Observable.unByKey', + ol.Observable.unByKey); + +goog.exportProperty( + ol.Observable.prototype, + 'changed', + ol.Observable.prototype.changed); + +goog.exportProperty( + ol.Observable.prototype, + 'dispatchEvent', + ol.Observable.prototype.dispatchEvent); + +goog.exportProperty( + ol.Observable.prototype, + 'getRevision', + ol.Observable.prototype.getRevision); + +goog.exportProperty( + ol.Observable.prototype, + 'on', + ol.Observable.prototype.on); + +goog.exportProperty( + ol.Observable.prototype, + 'once', + ol.Observable.prototype.once); +goog.exportProperty( + ol.Observable.prototype, + 'un', + ol.Observable.prototype.un); +goog.exportProperty( + ol.Observable.prototype, + 'unByKey', + ol.Observable.prototype.unByKey); -/** - * An error sub class that is used when a Deferred has already been called. - * @param {!goog.async.Deferred} deferred The Deferred. - * - * @constructor - * @extends {goog.debug.Error} - */ -goog.async.Deferred.AlreadyCalledError = function(deferred) { - goog.debug.Error.call(this); +goog.exportSymbol( + 'ol.inherits', + ol.inherits); - /** - * The Deferred that raised this error. - * @type {goog.async.Deferred} - */ - this.deferred = deferred; -}; -goog.inherits(goog.async.Deferred.AlreadyCalledError, goog.debug.Error); +goog.exportSymbol( + 'ol.Overlay', + ol.Overlay); +goog.exportProperty( + ol.Overlay.prototype, + 'getElement', + ol.Overlay.prototype.getElement); -/** @override */ -goog.async.Deferred.AlreadyCalledError.prototype.message = - 'Deferred has already fired'; +goog.exportProperty( + ol.Overlay.prototype, + 'getId', + ol.Overlay.prototype.getId); +goog.exportProperty( + ol.Overlay.prototype, + 'getMap', + ol.Overlay.prototype.getMap); -/** @override */ -goog.async.Deferred.AlreadyCalledError.prototype.name = 'AlreadyCalledError'; +goog.exportProperty( + ol.Overlay.prototype, + 'getOffset', + ol.Overlay.prototype.getOffset); +goog.exportProperty( + ol.Overlay.prototype, + 'getPosition', + ol.Overlay.prototype.getPosition); +goog.exportProperty( + ol.Overlay.prototype, + 'getPositioning', + ol.Overlay.prototype.getPositioning); -/** - * An error sub class that is used when a Deferred is canceled. - * - * @param {!goog.async.Deferred} deferred The Deferred object. - * @constructor - * @extends {goog.debug.Error} - */ -goog.async.Deferred.CanceledError = function(deferred) { - goog.debug.Error.call(this); +goog.exportProperty( + ol.Overlay.prototype, + 'setElement', + ol.Overlay.prototype.setElement); - /** - * The Deferred that raised this error. - * @type {goog.async.Deferred} - */ - this.deferred = deferred; -}; -goog.inherits(goog.async.Deferred.CanceledError, goog.debug.Error); +goog.exportProperty( + ol.Overlay.prototype, + 'setMap', + ol.Overlay.prototype.setMap); +goog.exportProperty( + ol.Overlay.prototype, + 'setOffset', + ol.Overlay.prototype.setOffset); -/** @override */ -goog.async.Deferred.CanceledError.prototype.message = 'Deferred was canceled'; +goog.exportProperty( + ol.Overlay.prototype, + 'setPosition', + ol.Overlay.prototype.setPosition); +goog.exportProperty( + ol.Overlay.prototype, + 'setPositioning', + ol.Overlay.prototype.setPositioning); -/** @override */ -goog.async.Deferred.CanceledError.prototype.name = 'CanceledError'; +goog.exportSymbol( + 'ol.size.toSize', + ol.size.toSize); +goog.exportProperty( + ol.Tile.prototype, + 'getTileCoord', + ol.Tile.prototype.getTileCoord); +goog.exportProperty( + ol.VectorTile.prototype, + 'getFormat', + ol.VectorTile.prototype.getFormat); -/** - * Wrapper around errors that are scheduled to be thrown by failing deferreds - * after a timeout. - * - * @param {*} error Error from a failing deferred. - * @constructor - * @final - * @private - * @struct - */ -goog.async.Deferred.Error_ = function(error) { - /** @const @private {number} */ - this.id_ = goog.global.setTimeout(goog.bind(this.throwError, this), 0); +goog.exportProperty( + ol.VectorTile.prototype, + 'setLoader', + ol.VectorTile.prototype.setLoader); - /** @const @private {*} */ - this.error_ = error; -}; +goog.exportSymbol( + 'ol.View', + ol.View); +goog.exportProperty( + ol.View.prototype, + 'constrainCenter', + ol.View.prototype.constrainCenter); -/** - * Actually throws the error and removes it from the list of pending - * deferred errors. - */ -goog.async.Deferred.Error_.prototype.throwError = function() { - goog.asserts.assert(goog.async.Deferred.errorMap_[this.id_], - 'Cannot throw an error that is not scheduled.'); - delete goog.async.Deferred.errorMap_[this.id_]; - throw this.error_; -}; +goog.exportProperty( + ol.View.prototype, + 'constrainResolution', + ol.View.prototype.constrainResolution); +goog.exportProperty( + ol.View.prototype, + 'constrainRotation', + ol.View.prototype.constrainRotation); -/** - * Resets the error throw timer. - */ -goog.async.Deferred.Error_.prototype.resetTimer = function() { - goog.global.clearTimeout(this.id_); -}; +goog.exportProperty( + ol.View.prototype, + 'getCenter', + ol.View.prototype.getCenter); +goog.exportProperty( + ol.View.prototype, + 'calculateExtent', + ol.View.prototype.calculateExtent); -/** - * Map of unhandled errors scheduled to be rethrown in a future timestep. - * @private {!Object<number|string, goog.async.Deferred.Error_>} - */ -goog.async.Deferred.errorMap_ = {}; +goog.exportProperty( + ol.View.prototype, + 'getProjection', + ol.View.prototype.getProjection); +goog.exportProperty( + ol.View.prototype, + 'getResolution', + ol.View.prototype.getResolution); -/** - * Schedules an error to be thrown after a delay. - * @param {*} error Error from a failing deferred. - * @return {number} Id of the error. - * @private - */ -goog.async.Deferred.scheduleError_ = function(error) { - var deferredError = new goog.async.Deferred.Error_(error); - goog.async.Deferred.errorMap_[deferredError.id_] = deferredError; - return deferredError.id_; -}; +goog.exportProperty( + ol.View.prototype, + 'getRotation', + ol.View.prototype.getRotation); +goog.exportProperty( + ol.View.prototype, + 'getZoom', + ol.View.prototype.getZoom); -/** - * Unschedules an error from being thrown. - * @param {number} id Id of the deferred error to unschedule. - * @private - */ -goog.async.Deferred.unscheduleError_ = function(id) { - var error = goog.async.Deferred.errorMap_[id]; - if (error) { - error.resetTimer(); - delete goog.async.Deferred.errorMap_[id]; - } -}; +goog.exportProperty( + ol.View.prototype, + 'fit', + ol.View.prototype.fit); +goog.exportProperty( + ol.View.prototype, + 'centerOn', + ol.View.prototype.centerOn); -/** - * Asserts that there are no pending deferred errors. If there are any - * scheduled errors, one will be thrown immediately to make this function fail. - */ -goog.async.Deferred.assertNoErrors = function() { - var map = goog.async.Deferred.errorMap_; - for (var key in map) { - var error = map[key]; - error.resetTimer(); - error.throwError(); - } -}; +goog.exportProperty( + ol.View.prototype, + 'rotate', + ol.View.prototype.rotate); -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.exportProperty( + ol.View.prototype, + 'setCenter', + ol.View.prototype.setCenter); -/** - * @fileoverview A wrapper for the HTML5 FileError object. - * - */ +goog.exportProperty( + ol.View.prototype, + 'setResolution', + ol.View.prototype.setResolution); -goog.provide('goog.fs.Error'); -goog.provide('goog.fs.Error.ErrorCode'); +goog.exportProperty( + ol.View.prototype, + 'setRotation', + ol.View.prototype.setRotation); -goog.require('goog.debug.Error'); -goog.require('goog.object'); -goog.require('goog.string'); +goog.exportProperty( + ol.View.prototype, + 'setZoom', + ol.View.prototype.setZoom); +goog.exportSymbol( + 'ol.xml.getAllTextContent', + ol.xml.getAllTextContent); +goog.exportSymbol( + 'ol.xml.parse', + ol.xml.parse); -/** - * A filesystem error. Since the filesystem API is asynchronous, stack traces - * are less useful for identifying where errors come from, so this includes a - * large amount of metadata in the message. - * - * @param {!DOMError} error - * @param {string} action The action being undertaken when the error was raised. - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.fs.Error = function(error, action) { - /** @type {string} */ - this.name; +goog.exportProperty( + ol.webgl.Context.prototype, + 'getGL', + ol.webgl.Context.prototype.getGL); - /** - * @type {goog.fs.Error.ErrorCode} - * @deprecated Use the 'name' or 'message' field instead. - */ - this.code; +goog.exportProperty( + ol.webgl.Context.prototype, + 'useProgram', + ol.webgl.Context.prototype.useProgram); - if (goog.isDef(error.name)) { - this.name = error.name; - // TODO(user): Remove warning suppression after JSCompiler stops - // firing a spurious warning here. - /** @suppress {deprecated} */ - this.code = goog.fs.Error.getCodeFromName_(error.name); - } else { - this.code = error.code; - this.name = goog.fs.Error.getNameFromCode_(error.code); - } - goog.fs.Error.base(this, 'constructor', - goog.string.subs('%s %s', this.name, action)); -}; -goog.inherits(goog.fs.Error, goog.debug.Error); +goog.exportSymbol( + 'ol.tilegrid.TileGrid', + ol.tilegrid.TileGrid); +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getMaxZoom', + ol.tilegrid.TileGrid.prototype.getMaxZoom); -/** - * Names of errors that may be thrown by the File API, the File System API, or - * the File Writer API. - * - * @see http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException - * @see http://www.w3.org/TR/file-system-api/#definitions - * @see http://dev.w3.org/2009/dap/file-system/file-writer.html#definitions - * @enum {string} - */ -goog.fs.Error.ErrorName = { - ABORT: 'AbortError', - ENCODING: 'EncodingError', - INVALID_MODIFICATION: 'InvalidModificationError', - INVALID_STATE: 'InvalidStateError', - NOT_FOUND: 'NotFoundError', - NOT_READABLE: 'NotReadableError', - NO_MODIFICATION_ALLOWED: 'NoModificationAllowedError', - PATH_EXISTS: 'PathExistsError', - QUOTA_EXCEEDED: 'QuotaExceededError', - SECURITY: 'SecurityError', - SYNTAX: 'SyntaxError', - TYPE_MISMATCH: 'TypeMismatchError' -}; +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getMinZoom', + ol.tilegrid.TileGrid.prototype.getMinZoom); +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getOrigin', + ol.tilegrid.TileGrid.prototype.getOrigin); -/** - * Error codes for file errors. - * @see http://www.w3.org/TR/file-system-api/#idl-def-FileException - * - * @enum {number} - * @deprecated Use the 'name' or 'message' attribute instead. - */ -goog.fs.Error.ErrorCode = { - NOT_FOUND: 1, - SECURITY: 2, - ABORT: 3, - NOT_READABLE: 4, - ENCODING: 5, - NO_MODIFICATION_ALLOWED: 6, - INVALID_STATE: 7, - SYNTAX: 8, - INVALID_MODIFICATION: 9, - QUOTA_EXCEEDED: 10, - TYPE_MISMATCH: 11, - PATH_EXISTS: 12 -}; +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getResolution', + ol.tilegrid.TileGrid.prototype.getResolution); +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getResolutions', + ol.tilegrid.TileGrid.prototype.getResolutions); -/** - * @param {goog.fs.Error.ErrorCode} code - * @return {string} name - * @private - */ -goog.fs.Error.getNameFromCode_ = function(code) { - var name = goog.object.findKey(goog.fs.Error.NameToCodeMap_, function(c) { - return code == c; - }); - if (!goog.isDef(name)) { - throw new Error('Invalid code: ' + code); - } - return name; -}; +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getTileCoordExtent', + ol.tilegrid.TileGrid.prototype.getTileCoordExtent); +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getTileCoordForCoordAndResolution', + ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution); -/** - * Returns the code that corresponds to the given name. - * @param {string} name - * @return {goog.fs.Error.ErrorCode} code - * @private - */ -goog.fs.Error.getCodeFromName_ = function(name) { - return goog.fs.Error.NameToCodeMap_[name]; -}; +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getTileCoordForCoordAndZ', + ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ); +goog.exportProperty( + ol.tilegrid.TileGrid.prototype, + 'getTileSize', + ol.tilegrid.TileGrid.prototype.getTileSize); -/** - * Mapping from error names to values from the ErrorCode enum. - * @see http://www.w3.org/TR/file-system-api/#definitions. - * @private {!Object<string, goog.fs.Error.ErrorCode>} - */ -goog.fs.Error.NameToCodeMap_ = goog.object.create( - goog.fs.Error.ErrorName.ABORT, - goog.fs.Error.ErrorCode.ABORT, +goog.exportSymbol( + 'ol.tilegrid.createXYZ', + ol.tilegrid.createXYZ); - goog.fs.Error.ErrorName.ENCODING, - goog.fs.Error.ErrorCode.ENCODING, +goog.exportSymbol( + 'ol.tilegrid.WMTS', + ol.tilegrid.WMTS); - goog.fs.Error.ErrorName.INVALID_MODIFICATION, - goog.fs.Error.ErrorCode.INVALID_MODIFICATION, +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getMatrixIds', + ol.tilegrid.WMTS.prototype.getMatrixIds); - goog.fs.Error.ErrorName.INVALID_STATE, - goog.fs.Error.ErrorCode.INVALID_STATE, +goog.exportSymbol( + 'ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet', + ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet); - goog.fs.Error.ErrorName.NOT_FOUND, - goog.fs.Error.ErrorCode.NOT_FOUND, +goog.exportSymbol( + 'ol.style.AtlasManager', + ol.style.AtlasManager); - goog.fs.Error.ErrorName.NOT_READABLE, - goog.fs.Error.ErrorCode.NOT_READABLE, +goog.exportSymbol( + 'ol.style.Circle', + ol.style.Circle); - goog.fs.Error.ErrorName.NO_MODIFICATION_ALLOWED, - goog.fs.Error.ErrorCode.NO_MODIFICATION_ALLOWED, +goog.exportProperty( + ol.style.Circle.prototype, + 'getFill', + ol.style.Circle.prototype.getFill); - goog.fs.Error.ErrorName.PATH_EXISTS, - goog.fs.Error.ErrorCode.PATH_EXISTS, +goog.exportProperty( + ol.style.Circle.prototype, + 'getImage', + ol.style.Circle.prototype.getImage); - goog.fs.Error.ErrorName.QUOTA_EXCEEDED, - goog.fs.Error.ErrorCode.QUOTA_EXCEEDED, +goog.exportProperty( + ol.style.Circle.prototype, + 'getRadius', + ol.style.Circle.prototype.getRadius); - goog.fs.Error.ErrorName.SECURITY, - goog.fs.Error.ErrorCode.SECURITY, +goog.exportProperty( + ol.style.Circle.prototype, + 'getStroke', + ol.style.Circle.prototype.getStroke); - goog.fs.Error.ErrorName.SYNTAX, - goog.fs.Error.ErrorCode.SYNTAX, +goog.exportSymbol( + 'ol.style.Fill', + ol.style.Fill); - goog.fs.Error.ErrorName.TYPE_MISMATCH, - goog.fs.Error.ErrorCode.TYPE_MISMATCH); +goog.exportProperty( + ol.style.Fill.prototype, + 'getColor', + ol.style.Fill.prototype.getColor); -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.exportProperty( + ol.style.Fill.prototype, + 'setColor', + ol.style.Fill.prototype.setColor); -/** - * @fileoverview A wrapper for the HTML5 File ProgressEvent objects. - * - */ -goog.provide('goog.fs.ProgressEvent'); +goog.exportSymbol( + 'ol.style.Icon', + ol.style.Icon); -goog.require('goog.events.Event'); +goog.exportProperty( + ol.style.Icon.prototype, + 'getAnchor', + ol.style.Icon.prototype.getAnchor); +goog.exportProperty( + ol.style.Icon.prototype, + 'getImage', + ol.style.Icon.prototype.getImage); +goog.exportProperty( + ol.style.Icon.prototype, + 'getOrigin', + ol.style.Icon.prototype.getOrigin); -/** - * A wrapper for the progress events emitted by the File APIs. - * - * @param {!ProgressEvent} event The underlying event object. - * @param {!Object} target The file access object emitting the event. - * @extends {goog.events.Event} - * @constructor - * @final - */ -goog.fs.ProgressEvent = function(event, target) { - goog.fs.ProgressEvent.base(this, 'constructor', event.type, target); +goog.exportProperty( + ol.style.Icon.prototype, + 'getSrc', + ol.style.Icon.prototype.getSrc); - /** - * The underlying event object. - * @type {!ProgressEvent} - * @private - */ - this.event_ = event; -}; -goog.inherits(goog.fs.ProgressEvent, goog.events.Event); +goog.exportProperty( + ol.style.Icon.prototype, + 'getSize', + ol.style.Icon.prototype.getSize); +goog.exportProperty( + ol.style.Icon.prototype, + 'load', + ol.style.Icon.prototype.load); -/** - * @return {boolean} Whether or not the total size of the of the file being - * saved is known. - */ -goog.fs.ProgressEvent.prototype.isLengthComputable = function() { - return this.event_.lengthComputable; -}; +goog.exportSymbol( + 'ol.style.Image', + ol.style.Image); +goog.exportProperty( + ol.style.Image.prototype, + 'getOpacity', + ol.style.Image.prototype.getOpacity); -/** - * @return {number} The number of bytes saved so far. - */ -goog.fs.ProgressEvent.prototype.getLoaded = function() { - return this.event_.loaded; -}; +goog.exportProperty( + ol.style.Image.prototype, + 'getRotateWithView', + ol.style.Image.prototype.getRotateWithView); +goog.exportProperty( + ol.style.Image.prototype, + 'getRotation', + ol.style.Image.prototype.getRotation); -/** - * @return {number} The total number of bytes in the file being saved. - */ -goog.fs.ProgressEvent.prototype.getTotal = function() { - return this.event_.total; -}; +goog.exportProperty( + ol.style.Image.prototype, + 'getScale', + ol.style.Image.prototype.getScale); -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.exportProperty( + ol.style.Image.prototype, + 'getSnapToPixel', + ol.style.Image.prototype.getSnapToPixel); -/** - * @fileoverview A wrapper for the HTML5 FileReader object. - * - */ +goog.exportProperty( + ol.style.Image.prototype, + 'setOpacity', + ol.style.Image.prototype.setOpacity); -goog.provide('goog.fs.FileReader'); -goog.provide('goog.fs.FileReader.EventType'); -goog.provide('goog.fs.FileReader.ReadyState'); +goog.exportProperty( + ol.style.Image.prototype, + 'setRotation', + ol.style.Image.prototype.setRotation); -goog.require('goog.async.Deferred'); -goog.require('goog.events.EventTarget'); -goog.require('goog.fs.Error'); -goog.require('goog.fs.ProgressEvent'); +goog.exportProperty( + ol.style.Image.prototype, + 'setScale', + ol.style.Image.prototype.setScale); +goog.exportSymbol( + 'ol.style.RegularShape', + ol.style.RegularShape); +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getAnchor', + ol.style.RegularShape.prototype.getAnchor); -/** - * An object for monitoring the reading of files. This emits ProgressEvents of - * the types listed in {@link goog.fs.FileReader.EventType}. - * - * @constructor - * @extends {goog.events.EventTarget} - * @final - */ -goog.fs.FileReader = function() { - goog.fs.FileReader.base(this, 'constructor'); +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getAngle', + ol.style.RegularShape.prototype.getAngle); - /** - * The underlying FileReader object. - * - * @type {!FileReader} - * @private - */ - this.reader_ = new FileReader(); +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getFill', + ol.style.RegularShape.prototype.getFill); - this.reader_.onloadstart = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onprogress = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onload = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onabort = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onerror = goog.bind(this.dispatchProgressEvent_, this); - this.reader_.onloadend = goog.bind(this.dispatchProgressEvent_, this); -}; -goog.inherits(goog.fs.FileReader, goog.events.EventTarget); +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getImage', + ol.style.RegularShape.prototype.getImage); +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getOrigin', + ol.style.RegularShape.prototype.getOrigin); -/** - * Possible states for a FileReader. - * - * @enum {number} - */ -goog.fs.FileReader.ReadyState = { - /** - * The object has been constructed, but there is no pending read. - */ - INIT: 0, - /** - * Data is being read. - */ - LOADING: 1, - /** - * The data has been read from the file, the read was aborted, or an error - * occurred. - */ - DONE: 2 -}; +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getPoints', + ol.style.RegularShape.prototype.getPoints); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getRadius', + ol.style.RegularShape.prototype.getRadius); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getRadius2', + ol.style.RegularShape.prototype.getRadius2); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getSize', + ol.style.RegularShape.prototype.getSize); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getStroke', + ol.style.RegularShape.prototype.getStroke); + +goog.exportSymbol( + 'ol.style.Stroke', + ol.style.Stroke); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'getColor', + ol.style.Stroke.prototype.getColor); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'getLineCap', + ol.style.Stroke.prototype.getLineCap); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'getLineDash', + ol.style.Stroke.prototype.getLineDash); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'getLineJoin', + ol.style.Stroke.prototype.getLineJoin); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'getMiterLimit', + ol.style.Stroke.prototype.getMiterLimit); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'getWidth', + ol.style.Stroke.prototype.getWidth); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'setColor', + ol.style.Stroke.prototype.setColor); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'setLineCap', + ol.style.Stroke.prototype.setLineCap); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'setLineDash', + ol.style.Stroke.prototype.setLineDash); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'setLineJoin', + ol.style.Stroke.prototype.setLineJoin); + +goog.exportProperty( + ol.style.Stroke.prototype, + 'setMiterLimit', + ol.style.Stroke.prototype.setMiterLimit); +goog.exportProperty( + ol.style.Stroke.prototype, + 'setWidth', + ol.style.Stroke.prototype.setWidth); -/** - * Events emitted by a FileReader. - * - * @enum {string} - */ -goog.fs.FileReader.EventType = { - /** - * Emitted when the reading begins. readyState will be LOADING. - */ - LOAD_START: 'loadstart', - /** - * Emitted when progress has been made in reading the file. readyState will be - * LOADING. - */ - PROGRESS: 'progress', - /** - * Emitted when the data has been successfully read. readyState will be - * LOADING. - */ - LOAD: 'load', - /** - * Emitted when the reading has been aborted. readyState will be LOADING. - */ - ABORT: 'abort', - /** - * Emitted when an error is encountered or the reading has been aborted. - * readyState will be LOADING. - */ - ERROR: 'error', - /** - * Emitted when the reading is finished, whether successfully or not. - * readyState will be DONE. - */ - LOAD_END: 'loadend' -}; +goog.exportSymbol( + 'ol.style.Style', + ol.style.Style); +goog.exportProperty( + ol.style.Style.prototype, + 'getGeometry', + ol.style.Style.prototype.getGeometry); -/** - * Abort the reading of the file. - */ -goog.fs.FileReader.prototype.abort = function() { - try { - this.reader_.abort(); - } catch (e) { - throw new goog.fs.Error(e, 'aborting read'); - } -}; +goog.exportProperty( + ol.style.Style.prototype, + 'getGeometryFunction', + ol.style.Style.prototype.getGeometryFunction); +goog.exportProperty( + ol.style.Style.prototype, + 'getFill', + ol.style.Style.prototype.getFill); -/** - * @return {goog.fs.FileReader.ReadyState} The current state of the FileReader. - */ -goog.fs.FileReader.prototype.getReadyState = function() { - return /** @type {goog.fs.FileReader.ReadyState} */ (this.reader_.readyState); -}; +goog.exportProperty( + ol.style.Style.prototype, + 'getImage', + ol.style.Style.prototype.getImage); +goog.exportProperty( + ol.style.Style.prototype, + 'getStroke', + ol.style.Style.prototype.getStroke); -/** - * @return {*} The result of the file read. - */ -goog.fs.FileReader.prototype.getResult = function() { - return this.reader_.result; -}; +goog.exportProperty( + ol.style.Style.prototype, + 'getText', + ol.style.Style.prototype.getText); +goog.exportProperty( + ol.style.Style.prototype, + 'getZIndex', + ol.style.Style.prototype.getZIndex); -/** - * @return {goog.fs.Error} The error encountered while reading, if any. - */ -goog.fs.FileReader.prototype.getError = function() { - return this.reader_.error && - new goog.fs.Error(this.reader_.error, 'reading file'); -}; +goog.exportProperty( + ol.style.Style.prototype, + 'setGeometry', + ol.style.Style.prototype.setGeometry); +goog.exportProperty( + ol.style.Style.prototype, + 'setZIndex', + ol.style.Style.prototype.setZIndex); -/** - * Wrap a progress event emitted by the underlying file reader and re-emit it. - * - * @param {!ProgressEvent} event The underlying event. - * @private - */ -goog.fs.FileReader.prototype.dispatchProgressEvent_ = function(event) { - this.dispatchEvent(new goog.fs.ProgressEvent(event, this)); -}; +goog.exportSymbol( + 'ol.style.Text', + ol.style.Text); +goog.exportProperty( + ol.style.Text.prototype, + 'getFont', + ol.style.Text.prototype.getFont); -/** @override */ -goog.fs.FileReader.prototype.disposeInternal = function() { - goog.fs.FileReader.base(this, 'disposeInternal'); - delete this.reader_; -}; +goog.exportProperty( + ol.style.Text.prototype, + 'getOffsetX', + ol.style.Text.prototype.getOffsetX); +goog.exportProperty( + ol.style.Text.prototype, + 'getOffsetY', + ol.style.Text.prototype.getOffsetY); -/** - * Starts reading a blob as a binary string. - * @param {!Blob} blob The blob to read. - */ -goog.fs.FileReader.prototype.readAsBinaryString = function(blob) { - this.reader_.readAsBinaryString(blob); -}; +goog.exportProperty( + ol.style.Text.prototype, + 'getFill', + ol.style.Text.prototype.getFill); +goog.exportProperty( + ol.style.Text.prototype, + 'getRotation', + ol.style.Text.prototype.getRotation); -/** - * Reads a blob as a binary string. - * @param {!Blob} blob The blob to read. - * @return {!goog.async.Deferred} The deferred Blob contents as a binary string. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsBinaryString = function(blob) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsBinaryString(blob); - return d; -}; +goog.exportProperty( + ol.style.Text.prototype, + 'getScale', + ol.style.Text.prototype.getScale); +goog.exportProperty( + ol.style.Text.prototype, + 'getStroke', + ol.style.Text.prototype.getStroke); -/** - * Starts reading a blob as an array buffer. - * @param {!Blob} blob The blob to read. - */ -goog.fs.FileReader.prototype.readAsArrayBuffer = function(blob) { - this.reader_.readAsArrayBuffer(blob); -}; +goog.exportProperty( + ol.style.Text.prototype, + 'getText', + ol.style.Text.prototype.getText); +goog.exportProperty( + ol.style.Text.prototype, + 'getTextAlign', + ol.style.Text.prototype.getTextAlign); -/** - * Reads a blob as an array buffer. - * @param {!Blob} blob The blob to read. - * @return {!goog.async.Deferred} The deferred Blob contents as an array buffer. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsArrayBuffer = function(blob) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsArrayBuffer(blob); - return d; -}; +goog.exportProperty( + ol.style.Text.prototype, + 'getTextBaseline', + ol.style.Text.prototype.getTextBaseline); +goog.exportProperty( + ol.style.Text.prototype, + 'setFont', + ol.style.Text.prototype.setFont); -/** - * Starts reading a blob as text. - * @param {!Blob} blob The blob to read. - * @param {string=} opt_encoding The name of the encoding to use. - */ -goog.fs.FileReader.prototype.readAsText = function(blob, opt_encoding) { - this.reader_.readAsText(blob, opt_encoding); -}; +goog.exportProperty( + ol.style.Text.prototype, + 'setOffsetX', + ol.style.Text.prototype.setOffsetX); +goog.exportProperty( + ol.style.Text.prototype, + 'setOffsetY', + ol.style.Text.prototype.setOffsetY); -/** - * Reads a blob as text. - * @param {!Blob} blob The blob to read. - * @param {string=} opt_encoding The name of the encoding to use. - * @return {!goog.async.Deferred} The deferred Blob contents as text. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsText = function(blob, opt_encoding) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsText(blob, opt_encoding); - return d; -}; +goog.exportProperty( + ol.style.Text.prototype, + 'setFill', + ol.style.Text.prototype.setFill); +goog.exportProperty( + ol.style.Text.prototype, + 'setRotation', + ol.style.Text.prototype.setRotation); -/** - * Starts reading a blob as a data URL. - * @param {!Blob} blob The blob to read. - */ -goog.fs.FileReader.prototype.readAsDataUrl = function(blob) { - this.reader_.readAsDataURL(blob); -}; +goog.exportProperty( + ol.style.Text.prototype, + 'setScale', + ol.style.Text.prototype.setScale); +goog.exportProperty( + ol.style.Text.prototype, + 'setStroke', + ol.style.Text.prototype.setStroke); -/** - * Reads a blob as a data URL. - * @param {!Blob} blob The blob to read. - * @return {!goog.async.Deferred} The deferred Blob contents as a data URL. - * If an error occurs, the errback is called with a {@link goog.fs.Error}. - */ -goog.fs.FileReader.readAsDataUrl = function(blob) { - var reader = new goog.fs.FileReader(); - var d = goog.fs.FileReader.createDeferred_(reader); - reader.readAsDataUrl(blob); - return d; -}; +goog.exportProperty( + ol.style.Text.prototype, + 'setText', + ol.style.Text.prototype.setText); +goog.exportProperty( + ol.style.Text.prototype, + 'setTextAlign', + ol.style.Text.prototype.setTextAlign); -/** - * Creates a new deferred object for the results of a read method. - * @param {goog.fs.FileReader} reader The reader to create a deferred for. - * @return {!goog.async.Deferred} The deferred results. - * @private - */ -goog.fs.FileReader.createDeferred_ = function(reader) { - var deferred = new goog.async.Deferred(); - reader.listen(goog.fs.FileReader.EventType.LOAD_END, - goog.partial(function(d, r, e) { - var result = r.getResult(); - var error = r.getError(); - if (result != null && !error) { - d.callback(result); - } else { - d.errback(error); - } - r.dispose(); - }, deferred, reader)); - return deferred; -}; +goog.exportProperty( + ol.style.Text.prototype, + 'setTextBaseline', + ol.style.Text.prototype.setTextBaseline); -// FIXME should handle all geo-referenced data, not just vector data +goog.exportSymbol( + 'ol.Sphere', + ol.Sphere); -goog.provide('ol.interaction.DragAndDrop'); -goog.provide('ol.interaction.DragAndDropEvent'); +goog.exportProperty( + ol.Sphere.prototype, + 'geodesicArea', + ol.Sphere.prototype.geodesicArea); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.FileDropHandler'); -goog.require('goog.events.FileDropHandler.EventType'); -goog.require('goog.fs.FileReader'); -goog.require('goog.functions'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.proj'); +goog.exportProperty( + ol.Sphere.prototype, + 'haversineDistance', + ol.Sphere.prototype.haversineDistance); +goog.exportSymbol( + 'ol.source.BingMaps', + ol.source.BingMaps); +goog.exportSymbol( + 'ol.source.BingMaps.TOS_ATTRIBUTION', + ol.source.BingMaps.TOS_ATTRIBUTION); -/** - * @classdesc - * Handles input of vector data by drag and drop. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @fires ol.interaction.DragAndDropEvent - * @param {olx.interaction.DragAndDropOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragAndDrop = function(opt_options) { +goog.exportSymbol( + 'ol.source.Cluster', + ol.source.Cluster); - var options = opt_options ? opt_options : {}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'getSource', + ol.source.Cluster.prototype.getSource); - goog.base(this, { - handleEvent: ol.interaction.DragAndDrop.handleEvent - }); +goog.exportSymbol( + 'ol.source.ImageCanvas', + ol.source.ImageCanvas); - /** - * @private - * @type {Array.<function(new: ol.format.Feature)>} - */ - this.formatConstructors_ = options.formatConstructors ? - options.formatConstructors : []; +goog.exportSymbol( + 'ol.source.ImageMapGuide', + ol.source.ImageMapGuide); - /** - * @private - * @type {ol.proj.Projection} - */ - this.projection_ = options.projection ? - ol.proj.get(options.projection) : null; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getParams', + ol.source.ImageMapGuide.prototype.getParams); - /** - * @private - * @type {goog.events.FileDropHandler} - */ - this.fileDropHandler_ = null; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getImageLoadFunction', + ol.source.ImageMapGuide.prototype.getImageLoadFunction); - /** - * @private - * @type {goog.events.Key|undefined} - */ - this.dropListenKey_ = undefined; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'updateParams', + ol.source.ImageMapGuide.prototype.updateParams); -}; -goog.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'setImageLoadFunction', + ol.source.ImageMapGuide.prototype.setImageLoadFunction); +goog.exportSymbol( + 'ol.source.Image', + ol.source.Image); -/** - * @inheritDoc - */ -ol.interaction.DragAndDrop.prototype.disposeInternal = function() { - if (this.dropListenKey_) { - goog.events.unlistenByKey(this.dropListenKey_); - } - goog.base(this, 'disposeInternal'); -}; +goog.exportProperty( + ol.source.ImageEvent.prototype, + 'image', + ol.source.ImageEvent.prototype.image); +goog.exportSymbol( + 'ol.source.ImageStatic', + ol.source.ImageStatic); -/** - * @param {goog.events.BrowserEvent} event Event. - * @private - */ -ol.interaction.DragAndDrop.prototype.handleDrop_ = function(event) { - var files = event.getBrowserEvent().dataTransfer.files; - var i, ii, file; - for (i = 0, ii = files.length; i < ii; ++i) { - file = files[i]; - // The empty string param is a workaround for - // https://code.google.com/p/closure-library/issues/detail?id=524 - var reader = goog.fs.FileReader.readAsText(file, ''); - reader.addCallback(goog.partial(this.handleResult_, file), this); - } -}; +goog.exportSymbol( + 'ol.source.ImageVector', + ol.source.ImageVector); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getSource', + ol.source.ImageVector.prototype.getSource); -/** - * @param {File} file File. - * @param {string} result Result. - * @private - */ -ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, result) { - var map = this.getMap(); - goog.asserts.assert(map, 'map must be set'); - var projection = this.projection_; - if (!projection) { - var view = map.getView(); - goog.asserts.assert(view, 'map must have view'); - projection = view.getProjection(); - goog.asserts.assert(projection !== undefined, - 'projection should be defined'); - } - var formatConstructors = this.formatConstructors_; - var features = []; - var i, ii; - for (i = 0, ii = formatConstructors.length; i < ii; ++i) { - var formatConstructor = formatConstructors[i]; - var format = new formatConstructor(); - var readFeatures = this.tryReadFeatures_(format, result); - if (readFeatures) { - var featureProjection = format.readProjection(result); - var transform = ol.proj.getTransform(featureProjection, projection); - var j, jj; - for (j = 0, jj = readFeatures.length; j < jj; ++j) { - var feature = readFeatures[j]; - var geometry = feature.getGeometry(); - if (geometry) { - geometry.applyTransform(transform); - } - features.push(feature); - } - } - } - this.dispatchEvent( - new ol.interaction.DragAndDropEvent( - ol.interaction.DragAndDropEventType.ADD_FEATURES, this, file, - features, projection)); -}; +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getStyle', + ol.source.ImageVector.prototype.getStyle); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getStyleFunction', + ol.source.ImageVector.prototype.getStyleFunction); -/** - * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and - * neither prevents the browser default nor stops event propagation. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.DragAndDrop} - * @api - */ -ol.interaction.DragAndDrop.handleEvent = goog.functions.TRUE; +goog.exportProperty( + ol.source.ImageVector.prototype, + 'setStyle', + ol.source.ImageVector.prototype.setStyle); +goog.exportSymbol( + 'ol.source.ImageWMS', + ol.source.ImageWMS); -/** - * @inheritDoc - */ -ol.interaction.DragAndDrop.prototype.setMap = function(map) { - if (this.dropListenKey_) { - goog.events.unlistenByKey(this.dropListenKey_); - this.dropListenKey_ = undefined; - } - if (this.fileDropHandler_) { - goog.dispose(this.fileDropHandler_); - this.fileDropHandler_ = null; - } - goog.asserts.assert(this.dropListenKey_ === undefined, - 'this.dropListenKey_ should be undefined'); - goog.base(this, 'setMap', map); - if (map) { - this.fileDropHandler_ = new goog.events.FileDropHandler(map.getViewport()); - this.dropListenKey_ = goog.events.listen( - this.fileDropHandler_, goog.events.FileDropHandler.EventType.DROP, - this.handleDrop_, false, this); - } -}; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getGetFeatureInfoUrl', + ol.source.ImageWMS.prototype.getGetFeatureInfoUrl); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getParams', + ol.source.ImageWMS.prototype.getParams); -/** - * @param {ol.format.Feature} format Format. - * @param {string} text Text. - * @private - * @return {Array.<ol.Feature>} Features. - */ -ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text) { - try { - return format.readFeatures(text); - } catch (e) { - return null; - } -}; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getImageLoadFunction', + ol.source.ImageWMS.prototype.getImageLoadFunction); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getUrl', + ol.source.ImageWMS.prototype.getUrl); -/** - * @enum {string} - */ -ol.interaction.DragAndDropEventType = { - /** - * Triggered when features are added - * @event ol.interaction.DragAndDropEvent#addfeatures - * @api stable - */ - ADD_FEATURES: 'addfeatures' -}; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'setImageLoadFunction', + ol.source.ImageWMS.prototype.setImageLoadFunction); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'setUrl', + ol.source.ImageWMS.prototype.setUrl); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'updateParams', + ol.source.ImageWMS.prototype.updateParams); -/** - * @classdesc - * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances - * of this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.interaction.DragAndDropEvent} - * @param {ol.interaction.DragAndDropEventType} type Type. - * @param {Object} target Target. - * @param {File} file File. - * @param {Array.<ol.Feature>=} opt_features Features. - * @param {ol.proj.Projection=} opt_projection Projection. - */ -ol.interaction.DragAndDropEvent = - function(type, target, file, opt_features, opt_projection) { +goog.exportSymbol( + 'ol.source.MapQuest', + ol.source.MapQuest); - goog.base(this, type, target); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getLayer', + ol.source.MapQuest.prototype.getLayer); - /** - * The features parsed from dropped data. - * @type {Array.<ol.Feature>|undefined} - * @api stable - */ - this.features = opt_features; +goog.exportSymbol( + 'ol.source.OSM', + ol.source.OSM); - /** - * The dropped file. - * @type {File} - * @api stable - */ - this.file = file; +goog.exportSymbol( + 'ol.source.OSM.ATTRIBUTION', + ol.source.OSM.ATTRIBUTION); - /** - * The feature projection. - * @type {ol.proj.Projection|undefined} - * @api - */ - this.projection = opt_projection; +goog.exportSymbol( + 'ol.source.Raster', + ol.source.Raster); -}; -goog.inherits(ol.interaction.DragAndDropEvent, goog.events.Event); +goog.exportProperty( + ol.source.Raster.prototype, + 'setOperation', + ol.source.Raster.prototype.setOperation); -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.exportProperty( + ol.source.RasterEvent.prototype, + 'extent', + ol.source.RasterEvent.prototype.extent); -/** - * @fileoverview Defines a 2-element vector class that can be used for - * coordinate math, useful for animation systems and point manipulation. - * - * Vec2 objects inherit from goog.math.Coordinate and may be used wherever a - * Coordinate is required. Where appropriate, Vec2 functions accept both Vec2 - * and Coordinate objects as input. - * - * @author brenneman@google.com (Shawn Brenneman) - */ +goog.exportProperty( + ol.source.RasterEvent.prototype, + 'resolution', + ol.source.RasterEvent.prototype.resolution); -goog.provide('goog.math.Vec2'); +goog.exportProperty( + ol.source.RasterEvent.prototype, + 'data', + ol.source.RasterEvent.prototype.data); -goog.require('goog.math'); -goog.require('goog.math.Coordinate'); +goog.exportSymbol( + 'ol.source.Source', + ol.source.Source); +goog.exportProperty( + ol.source.Source.prototype, + 'getAttributions', + ol.source.Source.prototype.getAttributions); +goog.exportProperty( + ol.source.Source.prototype, + 'getLogo', + ol.source.Source.prototype.getLogo); -/** - * Class for a two-dimensional vector object and assorted functions useful for - * manipulating points. - * - * @param {number} x The x coordinate for the vector. - * @param {number} y The y coordinate for the vector. - * @struct - * @constructor - * @extends {goog.math.Coordinate} - */ -goog.math.Vec2 = function(x, y) { - /** - * X-value - * @type {number} - */ - this.x = x; +goog.exportProperty( + ol.source.Source.prototype, + 'getProjection', + ol.source.Source.prototype.getProjection); + +goog.exportProperty( + ol.source.Source.prototype, + 'getState', + ol.source.Source.prototype.getState); + +goog.exportProperty( + ol.source.Source.prototype, + 'setAttributions', + ol.source.Source.prototype.setAttributions); + +goog.exportSymbol( + 'ol.source.Stamen', + ol.source.Stamen); + +goog.exportSymbol( + 'ol.source.TileArcGISRest', + ol.source.TileArcGISRest); + +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getParams', + ol.source.TileArcGISRest.prototype.getParams); - /** - * Y-value - * @type {number} - */ - this.y = y; -}; -goog.inherits(goog.math.Vec2, goog.math.Coordinate); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'updateParams', + ol.source.TileArcGISRest.prototype.updateParams); +goog.exportSymbol( + 'ol.source.TileDebug', + ol.source.TileDebug); -/** - * @return {!goog.math.Vec2} A random unit-length vector. - */ -goog.math.Vec2.randomUnit = function() { - var angle = Math.random() * Math.PI * 2; - return new goog.math.Vec2(Math.cos(angle), Math.sin(angle)); -}; +goog.exportSymbol( + 'ol.source.TileImage', + ol.source.TileImage); +goog.exportProperty( + ol.source.TileImage.prototype, + 'setRenderReprojectionEdges', + ol.source.TileImage.prototype.setRenderReprojectionEdges); -/** - * @return {!goog.math.Vec2} A random vector inside the unit-disc. - */ -goog.math.Vec2.random = function() { - var mag = Math.sqrt(Math.random()); - var angle = Math.random() * Math.PI * 2; +goog.exportProperty( + ol.source.TileImage.prototype, + 'setTileGridForProjection', + ol.source.TileImage.prototype.setTileGridForProjection); - return new goog.math.Vec2(Math.cos(angle) * mag, Math.sin(angle) * mag); -}; +goog.exportSymbol( + 'ol.source.TileJSON', + ol.source.TileJSON); +goog.exportSymbol( + 'ol.source.Tile', + ol.source.Tile); -/** - * Returns a new Vec2 object from a given coordinate. - * @param {!goog.math.Coordinate} a The coordinate. - * @return {!goog.math.Vec2} A new vector object. - */ -goog.math.Vec2.fromCoordinate = function(a) { - return new goog.math.Vec2(a.x, a.y); -}; +goog.exportProperty( + ol.source.Tile.prototype, + 'getTileGrid', + ol.source.Tile.prototype.getTileGrid); +goog.exportProperty( + ol.source.TileEvent.prototype, + 'tile', + ol.source.TileEvent.prototype.tile); -/** - * @return {!goog.math.Vec2} A new vector with the same coordinates as this one. - * @override - */ -goog.math.Vec2.prototype.clone = function() { - return new goog.math.Vec2(this.x, this.y); -}; +goog.exportSymbol( + 'ol.source.TileUTFGrid', + ol.source.TileUTFGrid); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getTemplate', + ol.source.TileUTFGrid.prototype.getTemplate); -/** - * Returns the magnitude of the vector measured from the origin. - * @return {number} The length of the vector. - */ -goog.math.Vec2.prototype.magnitude = function() { - return Math.sqrt(this.x * this.x + this.y * this.y); -}; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'forDataAtCoordinateAndResolution', + ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution); +goog.exportSymbol( + 'ol.source.TileWMS', + ol.source.TileWMS); -/** - * Returns the squared magnitude of the vector measured from the origin. - * NOTE(brenneman): Leaving out the square root is not a significant - * optimization in JavaScript. - * @return {number} The length of the vector, squared. - */ -goog.math.Vec2.prototype.squaredMagnitude = function() { - return this.x * this.x + this.y * this.y; -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getGetFeatureInfoUrl', + ol.source.TileWMS.prototype.getGetFeatureInfoUrl); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getParams', + ol.source.TileWMS.prototype.getParams); -/** - * @return {!goog.math.Vec2} This coordinate after scaling. - * @override - */ -goog.math.Vec2.prototype.scale = - /** @type {function(number, number=):!goog.math.Vec2} */ - (goog.math.Coordinate.prototype.scale); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'updateParams', + ol.source.TileWMS.prototype.updateParams); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getTileLoadFunction', + ol.source.UrlTile.prototype.getTileLoadFunction); -/** - * Reverses the sign of the vector. Equivalent to scaling the vector by -1. - * @return {!goog.math.Vec2} The inverted vector. - */ -goog.math.Vec2.prototype.invert = function() { - this.x = -this.x; - this.y = -this.y; - return this; -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getTileUrlFunction', + ol.source.UrlTile.prototype.getTileUrlFunction); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getUrls', + ol.source.UrlTile.prototype.getUrls); -/** - * Normalizes the current vector to have a magnitude of 1. - * @return {!goog.math.Vec2} The normalized vector. - */ -goog.math.Vec2.prototype.normalize = function() { - return this.scale(1 / this.magnitude()); -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'setTileLoadFunction', + ol.source.UrlTile.prototype.setTileLoadFunction); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'setTileUrlFunction', + ol.source.UrlTile.prototype.setTileUrlFunction); -/** - * Adds another vector to this vector in-place. - * @param {!goog.math.Coordinate} b The vector to add. - * @return {!goog.math.Vec2} This vector with {@code b} added. - */ -goog.math.Vec2.prototype.add = function(b) { - this.x += b.x; - this.y += b.y; - return this; -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'setUrl', + ol.source.UrlTile.prototype.setUrl); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'setUrls', + ol.source.UrlTile.prototype.setUrls); -/** - * Subtracts another vector from this vector in-place. - * @param {!goog.math.Coordinate} b The vector to subtract. - * @return {!goog.math.Vec2} This vector with {@code b} subtracted. - */ -goog.math.Vec2.prototype.subtract = function(b) { - this.x -= b.x; - this.y -= b.y; - return this; -}; +goog.exportSymbol( + 'ol.source.Vector', + ol.source.Vector); +goog.exportProperty( + ol.source.Vector.prototype, + 'addFeature', + ol.source.Vector.prototype.addFeature); -/** - * Rotates this vector in-place by a given angle, specified in radians. - * @param {number} angle The angle, in radians. - * @return {!goog.math.Vec2} This vector rotated {@code angle} radians. - */ -goog.math.Vec2.prototype.rotate = function(angle) { - var cos = Math.cos(angle); - var sin = Math.sin(angle); - var newX = this.x * cos - this.y * sin; - var newY = this.y * cos + this.x * sin; - this.x = newX; - this.y = newY; - return this; -}; +goog.exportProperty( + ol.source.Vector.prototype, + 'addFeatures', + ol.source.Vector.prototype.addFeatures); +goog.exportProperty( + ol.source.Vector.prototype, + 'clear', + ol.source.Vector.prototype.clear); -/** - * Rotates a vector by a given angle, specified in radians, relative to a given - * axis rotation point. The returned vector is a newly created instance - no - * in-place changes are done. - * @param {!goog.math.Vec2} v A vector. - * @param {!goog.math.Vec2} axisPoint The rotation axis point. - * @param {number} angle The angle, in radians. - * @return {!goog.math.Vec2} The rotated vector in a newly created instance. - */ -goog.math.Vec2.rotateAroundPoint = function(v, axisPoint, angle) { - var res = v.clone(); - return res.subtract(axisPoint).rotate(angle).add(axisPoint); -}; +goog.exportProperty( + ol.source.Vector.prototype, + 'forEachFeature', + ol.source.Vector.prototype.forEachFeature); +goog.exportProperty( + ol.source.Vector.prototype, + 'forEachFeatureInExtent', + ol.source.Vector.prototype.forEachFeatureInExtent); -/** - * Compares this vector with another for equality. - * @param {!goog.math.Vec2} b The other vector. - * @return {boolean} Whether this vector has the same x and y as the given - * vector. - */ -goog.math.Vec2.prototype.equals = function(b) { - return this == b || !!b && this.x == b.x && this.y == b.y; -}; +goog.exportProperty( + ol.source.Vector.prototype, + 'forEachFeatureIntersectingExtent', + ol.source.Vector.prototype.forEachFeatureIntersectingExtent); +goog.exportProperty( + ol.source.Vector.prototype, + 'getFeaturesCollection', + ol.source.Vector.prototype.getFeaturesCollection); -/** - * Returns the distance between two vectors. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {number} The distance. - */ -goog.math.Vec2.distance = goog.math.Coordinate.distance; +goog.exportProperty( + ol.source.Vector.prototype, + 'getFeatures', + ol.source.Vector.prototype.getFeatures); +goog.exportProperty( + ol.source.Vector.prototype, + 'getFeaturesAtCoordinate', + ol.source.Vector.prototype.getFeaturesAtCoordinate); -/** - * Returns the squared distance between two vectors. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {number} The squared distance. - */ -goog.math.Vec2.squaredDistance = goog.math.Coordinate.squaredDistance; +goog.exportProperty( + ol.source.Vector.prototype, + 'getFeaturesInExtent', + ol.source.Vector.prototype.getFeaturesInExtent); +goog.exportProperty( + ol.source.Vector.prototype, + 'getClosestFeatureToCoordinate', + ol.source.Vector.prototype.getClosestFeatureToCoordinate); -/** - * Compares vectors for equality. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {boolean} Whether the vectors have the same x and y coordinates. - */ -goog.math.Vec2.equals = goog.math.Coordinate.equals; +goog.exportProperty( + ol.source.Vector.prototype, + 'getExtent', + ol.source.Vector.prototype.getExtent); +goog.exportProperty( + ol.source.Vector.prototype, + 'getFeatureById', + ol.source.Vector.prototype.getFeatureById); -/** - * Returns the sum of two vectors as a new Vec2. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {!goog.math.Vec2} The sum vector. - */ -goog.math.Vec2.sum = function(a, b) { - return new goog.math.Vec2(a.x + b.x, a.y + b.y); -}; +goog.exportProperty( + ol.source.Vector.prototype, + 'removeFeature', + ol.source.Vector.prototype.removeFeature); +goog.exportProperty( + ol.source.VectorEvent.prototype, + 'feature', + ol.source.VectorEvent.prototype.feature); -/** - * Returns the difference between two vectors as a new Vec2. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {!goog.math.Vec2} The difference vector. - */ -goog.math.Vec2.difference = function(a, b) { - return new goog.math.Vec2(a.x - b.x, a.y - b.y); -}; +goog.exportSymbol( + 'ol.source.VectorTile', + ol.source.VectorTile); +goog.exportSymbol( + 'ol.source.WMTS', + ol.source.WMTS); -/** - * Returns the dot-product of two vectors. - * @param {!goog.math.Coordinate} a The first vector. - * @param {!goog.math.Coordinate} b The second vector. - * @return {number} The dot-product of the two vectors. - */ -goog.math.Vec2.dot = function(a, b) { - return a.x * b.x + a.y * b.y; -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getDimensions', + ol.source.WMTS.prototype.getDimensions); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getFormat', + ol.source.WMTS.prototype.getFormat); -/** - * Returns the determinant of two vectors. - * @param {!goog.math.Vec2} a The first vector. - * @param {!goog.math.Vec2} b The second vector. - * @return {number} The determinant of the two vectors. - */ -goog.math.Vec2.determinant = function(a, b) { - return a.x * b.y - a.y * b.x; -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getLayer', + ol.source.WMTS.prototype.getLayer); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getMatrixSet', + ol.source.WMTS.prototype.getMatrixSet); -/** - * Returns a new Vec2 that is the linear interpolant between vectors a and b at - * scale-value x. - * @param {!goog.math.Coordinate} a Vector a. - * @param {!goog.math.Coordinate} b Vector b. - * @param {number} x The proportion between a and b. - * @return {!goog.math.Vec2} The interpolated vector. - */ -goog.math.Vec2.lerp = function(a, b, x) { - return new goog.math.Vec2(goog.math.lerp(a.x, b.x, x), - goog.math.lerp(a.y, b.y, x)); -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getRequestEncoding', + ol.source.WMTS.prototype.getRequestEncoding); -goog.provide('ol.interaction.DragRotateAndZoom'); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getStyle', + ol.source.WMTS.prototype.getStyle); -goog.require('goog.math.Vec2'); -goog.require('ol'); -goog.require('ol.ViewHint'); -goog.require('ol.events.ConditionType'); -goog.require('ol.events.condition'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.interaction.Pointer'); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getVersion', + ol.source.WMTS.prototype.getVersion); +goog.exportProperty( + ol.source.WMTS.prototype, + 'updateDimensions', + ol.source.WMTS.prototype.updateDimensions); +goog.exportSymbol( + 'ol.source.WMTS.optionsFromCapabilities', + ol.source.WMTS.optionsFromCapabilities); -/** - * @classdesc - * Allows the user to zoom and rotate the map by clicking and dragging - * on the map. By default, this interaction is limited to when the shift - * key is held down. - * - * This interaction is only supported for mouse devices. - * - * And this interaction is not included in the default interactions. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.DragRotateAndZoomOptions=} opt_options Options. - * @api stable - */ -ol.interaction.DragRotateAndZoom = function(opt_options) { +goog.exportSymbol( + 'ol.source.XYZ', + ol.source.XYZ); - var options = opt_options ? opt_options : {}; +goog.exportSymbol( + 'ol.source.Zoomify', + ol.source.Zoomify); - goog.base(this, { - handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_, - handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_, - handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_ - }); +goog.exportProperty( + ol.render.Event.prototype, + 'vectorContext', + ol.render.Event.prototype.vectorContext); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.shiftKeyOnly; +goog.exportProperty( + ol.render.Event.prototype, + 'frameState', + ol.render.Event.prototype.frameState); - /** - * @private - * @type {number|undefined} - */ - this.lastAngle_ = undefined; +goog.exportProperty( + ol.render.Event.prototype, + 'context', + ol.render.Event.prototype.context); - /** - * @private - * @type {number|undefined} - */ - this.lastMagnitude_ = undefined; +goog.exportProperty( + ol.render.Event.prototype, + 'glContext', + ol.render.Event.prototype.glContext); - /** - * @private - * @type {number} - */ - this.lastScaleDelta_ = 0; +goog.exportProperty( + ol.render.Feature.prototype, + 'get', + ol.render.Feature.prototype.get); - /** - * @private - * @type {number} - */ - this.duration_ = options.duration !== undefined ? options.duration : 400; +goog.exportProperty( + ol.render.Feature.prototype, + 'getExtent', + ol.render.Feature.prototype.getExtent); -}; -goog.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Pointer); +goog.exportProperty( + ol.render.Feature.prototype, + 'getGeometry', + ol.render.Feature.prototype.getGeometry); +goog.exportProperty( + ol.render.Feature.prototype, + 'getProperties', + ol.render.Feature.prototype.getProperties); -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @this {ol.interaction.DragRotateAndZoom} - * @private - */ -ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return; - } +goog.exportProperty( + ol.render.Feature.prototype, + 'getType', + ol.render.Feature.prototype.getType); - var map = mapBrowserEvent.map; - var size = map.getSize(); - var offset = mapBrowserEvent.pixel; - var delta = new goog.math.Vec2( - offset[0] - size[0] / 2, - size[1] / 2 - offset[1]); - var theta = Math.atan2(delta.y, delta.x); - var magnitude = delta.magnitude(); - var view = map.getView(); - map.render(); - if (this.lastAngle_ !== undefined) { - var angleDelta = theta - this.lastAngle_; - ol.interaction.Interaction.rotateWithoutConstraints( - map, view, view.getRotation() - angleDelta); - } - this.lastAngle_ = theta; - if (this.lastMagnitude_ !== undefined) { - var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude); - ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution); - } - if (this.lastMagnitude_ !== undefined) { - this.lastScaleDelta_ = this.lastMagnitude_ / magnitude; - } - this.lastMagnitude_ = magnitude; -}; +goog.exportSymbol( + 'ol.render.VectorContext', + ol.render.VectorContext); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawAsync', + ol.render.webgl.Immediate.prototype.drawAsync); -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.DragRotateAndZoom} - * @private - */ -ol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return true; - } +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawCircleGeometry', + ol.render.webgl.Immediate.prototype.drawCircleGeometry); - var map = mapBrowserEvent.map; - var view = map.getView(); - view.setHint(ol.ViewHint.INTERACTING, -1); - var direction = this.lastScaleDelta_ - 1; - ol.interaction.Interaction.rotate(map, view, view.getRotation()); - ol.interaction.Interaction.zoom(map, view, view.getResolution(), - undefined, this.duration_, direction); - this.lastScaleDelta_ = 0; - return false; -}; +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawFeature', + ol.render.webgl.Immediate.prototype.drawFeature); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawGeometryCollectionGeometry', + ol.render.webgl.Immediate.prototype.drawGeometryCollectionGeometry); -/** - * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.DragRotateAndZoom} - * @private - */ -ol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) { - if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { - return false; - } +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawPointGeometry', + ol.render.webgl.Immediate.prototype.drawPointGeometry); - if (this.condition_(mapBrowserEvent)) { - mapBrowserEvent.map.getView().setHint(ol.ViewHint.INTERACTING, 1); - this.lastAngle_ = undefined; - this.lastMagnitude_ = undefined; - return true; - } else { - return false; - } -}; +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawLineStringGeometry', + ol.render.webgl.Immediate.prototype.drawLineStringGeometry); -goog.provide('ol.interaction.Draw'); -goog.provide('ol.interaction.DrawEvent'); -goog.provide('ol.interaction.DrawEventType'); -goog.provide('ol.interaction.DrawGeometryFunctionType'); -goog.provide('ol.interaction.DrawMode'); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawMultiLineStringGeometry', + ol.render.webgl.Immediate.prototype.drawMultiLineStringGeometry); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('ol.Collection'); -goog.require('ol.Coordinate'); -goog.require('ol.Feature'); -goog.require('ol.MapBrowserEvent'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.Object'); -goog.require('ol.coordinate'); -goog.require('ol.events.condition'); -goog.require('ol.geom.Circle'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('ol.interaction.InteractionProperty'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.layer.Vector'); -goog.require('ol.source.Vector'); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawMultiPointGeometry', + ol.render.webgl.Immediate.prototype.drawMultiPointGeometry); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawMultiPolygonGeometry', + ol.render.webgl.Immediate.prototype.drawMultiPolygonGeometry); -/** - * @enum {string} - */ -ol.interaction.DrawEventType = { - /** - * Triggered upon feature draw start - * @event ol.interaction.DrawEvent#drawstart - * @api stable - */ - DRAWSTART: 'drawstart', - /** - * Triggered upon feature draw end - * @event ol.interaction.DrawEvent#drawend - * @api stable - */ - DRAWEND: 'drawend' -}; +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawPolygonGeometry', + ol.render.webgl.Immediate.prototype.drawPolygonGeometry); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'drawText', + ol.render.webgl.Immediate.prototype.drawText); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'setFillStrokeStyle', + ol.render.webgl.Immediate.prototype.setFillStrokeStyle); -/** - * @classdesc - * Events emitted by {@link ol.interaction.Draw} instances are instances of - * this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.DrawEvent} - * @param {ol.interaction.DrawEventType} type Type. - * @param {ol.Feature} feature The feature drawn. - */ -ol.interaction.DrawEvent = function(type, feature) { +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'setImageStyle', + ol.render.webgl.Immediate.prototype.setImageStyle); - goog.base(this, type); +goog.exportProperty( + ol.render.webgl.Immediate.prototype, + 'setTextStyle', + ol.render.webgl.Immediate.prototype.setTextStyle); - /** - * The feature being drawn. - * @type {ol.Feature} - * @api stable - */ - this.feature = feature; +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawAsync', + ol.render.canvas.Immediate.prototype.drawAsync); -}; -goog.inherits(ol.interaction.DrawEvent, goog.events.Event); +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawCircleGeometry', + ol.render.canvas.Immediate.prototype.drawCircleGeometry); + +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawFeature', + ol.render.canvas.Immediate.prototype.drawFeature); +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawPointGeometry', + ol.render.canvas.Immediate.prototype.drawPointGeometry); +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawMultiPointGeometry', + ol.render.canvas.Immediate.prototype.drawMultiPointGeometry); -/** - * @classdesc - * Interaction for drawing feature geometries. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @fires ol.interaction.DrawEvent - * @param {olx.interaction.DrawOptions} options Options. - * @api stable - */ -ol.interaction.Draw = function(options) { +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawLineStringGeometry', + ol.render.canvas.Immediate.prototype.drawLineStringGeometry); - goog.base(this, { - handleDownEvent: ol.interaction.Draw.handleDownEvent_, - handleEvent: ol.interaction.Draw.handleEvent, - handleUpEvent: ol.interaction.Draw.handleUpEvent_ - }); +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawMultiLineStringGeometry', + ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry); - /** - * @type {ol.Pixel} - * @private - */ - this.downPx_ = null; +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawPolygonGeometry', + ol.render.canvas.Immediate.prototype.drawPolygonGeometry); + +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'drawMultiPolygonGeometry', + ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry); + +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'setFillStrokeStyle', + ol.render.canvas.Immediate.prototype.setFillStrokeStyle); + +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'setImageStyle', + ol.render.canvas.Immediate.prototype.setImageStyle); - /** - * @type {boolean} - * @private - */ - this.freehand_ = false; +goog.exportProperty( + ol.render.canvas.Immediate.prototype, + 'setTextStyle', + ol.render.canvas.Immediate.prototype.setTextStyle); - /** - * Target source for drawn features. - * @type {ol.source.Vector} - * @private - */ - this.source_ = options.source ? options.source : null; +goog.exportSymbol( + 'ol.proj.common.add', + ol.proj.common.add); - /** - * Target collection for drawn features. - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features ? options.features : null; +goog.exportSymbol( + 'ol.proj.METERS_PER_UNIT', + ol.proj.METERS_PER_UNIT); - /** - * Pixel distance for snapping. - * @type {number} - * @private - */ - this.snapTolerance_ = options.snapTolerance ? options.snapTolerance : 12; +goog.exportSymbol( + 'ol.proj.Projection', + ol.proj.Projection); - /** - * Geometry type. - * @type {ol.geom.GeometryType} - * @private - */ - this.type_ = options.type; +goog.exportProperty( + ol.proj.Projection.prototype, + 'getCode', + ol.proj.Projection.prototype.getCode); - /** - * Drawing mode (derived from geometry type. - * @type {ol.interaction.DrawMode} - * @private - */ - this.mode_ = ol.interaction.Draw.getMode_(this.type_); +goog.exportProperty( + ol.proj.Projection.prototype, + 'getExtent', + ol.proj.Projection.prototype.getExtent); - /** - * The number of points that must be drawn before a polygon ring or line - * string can be finished. The default is 3 for polygon rings and 2 for - * line strings. - * @type {number} - * @private - */ - this.minPoints_ = options.minPoints ? - options.minPoints : - (this.mode_ === ol.interaction.DrawMode.POLYGON ? 3 : 2); +goog.exportProperty( + ol.proj.Projection.prototype, + 'getUnits', + ol.proj.Projection.prototype.getUnits); - /** - * The number of points that can be drawn before a polygon ring or line string - * is finished. The default is no restriction. - * @type {number} - * @private - */ - this.maxPoints_ = options.maxPoints ? options.maxPoints : Infinity; +goog.exportProperty( + ol.proj.Projection.prototype, + 'getMetersPerUnit', + ol.proj.Projection.prototype.getMetersPerUnit); - var geometryFunction = options.geometryFunction; - if (!geometryFunction) { - if (this.type_ === ol.geom.GeometryType.CIRCLE) { - /** - * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates - * @param {ol.geom.SimpleGeometry=} opt_geometry - * @return {ol.geom.SimpleGeometry} - */ - geometryFunction = function(coordinates, opt_geometry) { - var circle = opt_geometry ? opt_geometry : - new ol.geom.Circle([NaN, NaN]); - goog.asserts.assertInstanceof(circle, ol.geom.Circle, - 'geometry must be an ol.geom.Circle'); - var squaredLength = ol.coordinate.squaredDistance( - coordinates[0], coordinates[1]); - circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength)); - return circle; - }; - } else { - var Constructor; - var mode = this.mode_; - if (mode === ol.interaction.DrawMode.POINT) { - Constructor = ol.geom.Point; - } else if (mode === ol.interaction.DrawMode.LINE_STRING) { - Constructor = ol.geom.LineString; - } else if (mode === ol.interaction.DrawMode.POLYGON) { - Constructor = ol.geom.Polygon; - } - /** - * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates - * @param {ol.geom.SimpleGeometry=} opt_geometry - * @return {ol.geom.SimpleGeometry} - */ - geometryFunction = function(coordinates, opt_geometry) { - var geometry = opt_geometry; - if (geometry) { - geometry.setCoordinates(coordinates); - } else { - geometry = new Constructor(coordinates); - } - return geometry; - }; - } - } +goog.exportProperty( + ol.proj.Projection.prototype, + 'getWorldExtent', + ol.proj.Projection.prototype.getWorldExtent); - /** - * @type {ol.interaction.DrawGeometryFunctionType} - * @private - */ - this.geometryFunction_ = geometryFunction; +goog.exportProperty( + ol.proj.Projection.prototype, + 'isGlobal', + ol.proj.Projection.prototype.isGlobal); - /** - * Finish coordinate for the feature (first point for polygons, last point for - * linestrings). - * @type {ol.Coordinate} - * @private - */ - this.finishCoordinate_ = null; +goog.exportProperty( + ol.proj.Projection.prototype, + 'setGlobal', + ol.proj.Projection.prototype.setGlobal); - /** - * Sketch feature. - * @type {ol.Feature} - * @private - */ - this.sketchFeature_ = null; +goog.exportProperty( + ol.proj.Projection.prototype, + 'setExtent', + ol.proj.Projection.prototype.setExtent); - /** - * Sketch point. - * @type {ol.Feature} - * @private - */ - this.sketchPoint_ = null; +goog.exportProperty( + ol.proj.Projection.prototype, + 'setWorldExtent', + ol.proj.Projection.prototype.setWorldExtent); - /** - * Sketch coordinates. Used when drawing a line or polygon. - * @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} - * @private - */ - this.sketchCoords_ = null; +goog.exportProperty( + ol.proj.Projection.prototype, + 'setGetPointResolution', + ol.proj.Projection.prototype.setGetPointResolution); - /** - * Sketch line. Used when drawing polygon. - * @type {ol.Feature} - * @private - */ - this.sketchLine_ = null; +goog.exportProperty( + ol.proj.Projection.prototype, + 'getPointResolution', + ol.proj.Projection.prototype.getPointResolution); - /** - * Sketch line coordinates. Used when drawing a polygon or circle. - * @type {Array.<ol.Coordinate>} - * @private - */ - this.sketchLineCoords_ = null; +goog.exportSymbol( + 'ol.proj.addEquivalentProjections', + ol.proj.addEquivalentProjections); - /** - * Squared tolerance for handling up events. If the squared distance - * between a down and up event is greater than this tolerance, up events - * will not be handled. - * @type {number} - * @private - */ - this.squaredClickTolerance_ = options.clickTolerance ? - options.clickTolerance * options.clickTolerance : 36; +goog.exportSymbol( + 'ol.proj.addProjection', + ol.proj.addProjection); - /** - * Draw overlay where our sketch features are drawn. - * @type {ol.layer.Vector} - * @private - */ - this.overlay_ = new ol.layer.Vector({ - source: new ol.source.Vector({ - useSpatialIndex: false, - wrapX: options.wrapX ? options.wrapX : false - }), - style: options.style ? options.style : - ol.interaction.Draw.getDefaultStyleFunction() - }); +goog.exportSymbol( + 'ol.proj.addCoordinateTransforms', + ol.proj.addCoordinateTransforms); - /** - * Name of the geometry attribute for newly created features. - * @type {string|undefined} - * @private - */ - this.geometryName_ = options.geometryName; +goog.exportSymbol( + 'ol.proj.fromLonLat', + ol.proj.fromLonLat); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.noModifierKeys; +goog.exportSymbol( + 'ol.proj.toLonLat', + ol.proj.toLonLat); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.freehandCondition_ = options.freehandCondition ? - options.freehandCondition : ol.events.condition.shiftKeyOnly; +goog.exportSymbol( + 'ol.proj.get', + ol.proj.get); - goog.events.listen(this, - ol.Object.getChangeEventType(ol.interaction.InteractionProperty.ACTIVE), - this.updateState_, false, this); +goog.exportSymbol( + 'ol.proj.getTransform', + ol.proj.getTransform); -}; -goog.inherits(ol.interaction.Draw, ol.interaction.Pointer); +goog.exportSymbol( + 'ol.proj.transform', + ol.proj.transform); +goog.exportSymbol( + 'ol.proj.transformExtent', + ol.proj.transformExtent); -/** - * @return {ol.style.StyleFunction} Styles. - */ -ol.interaction.Draw.getDefaultStyleFunction = function() { - var styles = ol.style.createDefaultEditingStyles(); - return function(feature, resolution) { - return styles[feature.getGeometry().getType()]; - }; -}; +goog.exportSymbol( + 'ol.layer.Heatmap', + ol.layer.Heatmap); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getBlur', + ol.layer.Heatmap.prototype.getBlur); -/** - * @inheritDoc - */ -ol.interaction.Draw.prototype.setMap = function(map) { - goog.base(this, 'setMap', map); - this.updateState_(); -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getGradient', + ol.layer.Heatmap.prototype.getGradient); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getRadius', + ol.layer.Heatmap.prototype.getRadius); -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may actually - * draw or finish the drawing. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Draw} - * @api - */ -ol.interaction.Draw.handleEvent = function(mapBrowserEvent) { - var pass = !this.freehand_; - if (this.freehand_ && - mapBrowserEvent.type === ol.MapBrowserEvent.EventType.POINTERDRAG) { - this.addToDrawing_(mapBrowserEvent); - pass = false; - } else if (mapBrowserEvent.type === - ol.MapBrowserEvent.EventType.POINTERMOVE) { - pass = this.handlePointerMove_(mapBrowserEvent); - } else if (mapBrowserEvent.type === ol.MapBrowserEvent.EventType.DBLCLICK) { - pass = false; - } - return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && pass; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setBlur', + ol.layer.Heatmap.prototype.setBlur); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setGradient', + ol.layer.Heatmap.prototype.setGradient); -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.Draw} - * @private - */ -ol.interaction.Draw.handleDownEvent_ = function(event) { - if (this.condition_(event)) { - this.downPx_ = event.pixel; - return true; - } else if ((this.mode_ === ol.interaction.DrawMode.LINE_STRING || - this.mode_ === ol.interaction.DrawMode.POLYGON) && - this.freehandCondition_(event)) { - this.downPx_ = event.pixel; - this.freehand_ = true; - if (!this.finishCoordinate_) { - this.startDrawing_(event); - } - return true; - } else { - return false; - } -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setRadius', + ol.layer.Heatmap.prototype.setRadius); +goog.exportSymbol( + 'ol.layer.Image', + ol.layer.Image); -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Draw} - * @private - */ -ol.interaction.Draw.handleUpEvent_ = function(event) { - this.freehand_ = false; - var downPx = this.downPx_; - var clickPx = event.pixel; - var dx = downPx[0] - clickPx[0]; - var dy = downPx[1] - clickPx[1]; - var squaredDistance = dx * dx + dy * dy; - var pass = true; - if (squaredDistance <= this.squaredClickTolerance_) { - this.handlePointerMove_(event); - if (!this.finishCoordinate_) { - this.startDrawing_(event); - if (this.mode_ === ol.interaction.DrawMode.POINT) { - this.finishDrawing(); - } - } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - this.finishDrawing(); - } else if (this.atFinish_(event)) { - this.finishDrawing(); - } else { - this.addToDrawing_(event); - } - pass = false; - } - return pass; -}; +goog.exportProperty( + ol.layer.Image.prototype, + 'getSource', + ol.layer.Image.prototype.getSource); +goog.exportSymbol( + 'ol.layer.Layer', + ol.layer.Layer); -/** - * Handle move events. - * @param {ol.MapBrowserEvent} event A move event. - * @return {boolean} Pass the event to other interactions. - * @private - */ -ol.interaction.Draw.prototype.handlePointerMove_ = function(event) { - if (this.finishCoordinate_) { - this.modifyDrawing_(event); - } else { - this.createOrUpdateSketchPoint_(event); - } - return true; -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'getSource', + ol.layer.Layer.prototype.getSource); +goog.exportProperty( + ol.layer.Layer.prototype, + 'setMap', + ol.layer.Layer.prototype.setMap); -/** - * Determine if an event is within the snapping tolerance of the start coord. - * @param {ol.MapBrowserEvent} event Event. - * @return {boolean} The event is within the snapping tolerance of the start. - * @private - */ -ol.interaction.Draw.prototype.atFinish_ = function(event) { - var at = false; - if (this.sketchFeature_) { - var potentiallyDone = false; - var potentiallyFinishCoordinates = [this.finishCoordinate_]; - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - potentiallyDone = this.sketchCoords_.length > this.minPoints_; - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - potentiallyDone = this.sketchCoords_[0].length > - this.minPoints_; - potentiallyFinishCoordinates = [this.sketchCoords_[0][0], - this.sketchCoords_[0][this.sketchCoords_[0].length - 2]]; - } - if (potentiallyDone) { - var map = event.map; - for (var i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) { - var finishCoordinate = potentiallyFinishCoordinates[i]; - var finishPixel = map.getPixelFromCoordinate(finishCoordinate); - var pixel = event.pixel; - var dx = pixel[0] - finishPixel[0]; - var dy = pixel[1] - finishPixel[1]; - var freehand = this.freehand_ && this.freehandCondition_(event); - var snapTolerance = freehand ? 1 : this.snapTolerance_; - at = Math.sqrt(dx * dx + dy * dy) <= snapTolerance; - if (at) { - this.finishCoordinate_ = finishCoordinate; - break; - } - } - } - } - return at; -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'setSource', + ol.layer.Layer.prototype.setSource); +goog.exportSymbol( + 'ol.layer.Base', + ol.layer.Base); -/** - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) { - var coordinates = event.coordinate.slice(); - if (!this.sketchPoint_) { - this.sketchPoint_ = new ol.Feature(new ol.geom.Point(coordinates)); - this.updateSketchFeatures_(); - } else { - var sketchPointGeom = this.sketchPoint_.getGeometry(); - goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point, - 'sketchPointGeom should be an ol.geom.Point'); - sketchPointGeom.setCoordinates(coordinates); - } -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'getExtent', + ol.layer.Base.prototype.getExtent); +goog.exportProperty( + ol.layer.Base.prototype, + 'getMaxResolution', + ol.layer.Base.prototype.getMaxResolution); -/** - * Start the drawing. - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.startDrawing_ = function(event) { - var start = event.coordinate; - this.finishCoordinate_ = start; - if (this.mode_ === ol.interaction.DrawMode.POINT) { - this.sketchCoords_ = start.slice(); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - this.sketchCoords_ = [[start.slice(), start.slice()]]; - this.sketchLineCoords_ = this.sketchCoords_[0]; - } else { - this.sketchCoords_ = [start.slice(), start.slice()]; - if (this.mode_ === ol.interaction.DrawMode.CIRCLE) { - this.sketchLineCoords_ = this.sketchCoords_; - } - } - if (this.sketchLineCoords_) { - this.sketchLine_ = new ol.Feature( - new ol.geom.LineString(this.sketchLineCoords_)); - } - var geometry = this.geometryFunction_(this.sketchCoords_); - goog.asserts.assert(geometry !== undefined, 'geometry should be defined'); - this.sketchFeature_ = new ol.Feature(); - if (this.geometryName_) { - this.sketchFeature_.setGeometryName(this.geometryName_); - } - this.sketchFeature_.setGeometry(geometry); - this.updateSketchFeatures_(); - this.dispatchEvent(new ol.interaction.DrawEvent( - ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_)); -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'getMinResolution', + ol.layer.Base.prototype.getMinResolution); +goog.exportProperty( + ol.layer.Base.prototype, + 'getOpacity', + ol.layer.Base.prototype.getOpacity); -/** - * Modify the drawing. - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.modifyDrawing_ = function(event) { - var coordinate = event.coordinate; - var geometry = this.sketchFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry should be ol.geom.SimpleGeometry or subclass'); - var coordinates, last; - if (this.mode_ === ol.interaction.DrawMode.POINT) { - last = this.sketchCoords_; - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - coordinates = this.sketchCoords_[0]; - last = coordinates[coordinates.length - 1]; - if (this.atFinish_(event)) { - // snap to finish - coordinate = this.finishCoordinate_.slice(); - } - } else { - coordinates = this.sketchCoords_; - last = coordinates[coordinates.length - 1]; - } - last[0] = coordinate[0]; - last[1] = coordinate[1]; - goog.asserts.assert(this.sketchCoords_, 'sketchCoords_ expected'); - this.geometryFunction_(this.sketchCoords_, geometry); - if (this.sketchPoint_) { - var sketchPointGeom = this.sketchPoint_.getGeometry(); - goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point, - 'sketchPointGeom should be an ol.geom.Point'); - sketchPointGeom.setCoordinates(coordinate); - } - var sketchLineGeom; - if (geometry instanceof ol.geom.Polygon && - this.mode_ !== ol.interaction.DrawMode.POLYGON) { - if (!this.sketchLine_) { - this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null)); - } - var ring = geometry.getLinearRing(0); - sketchLineGeom = this.sketchLine_.getGeometry(); - goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, - 'sketchLineGeom must be an ol.geom.LineString'); - sketchLineGeom.setFlatCoordinates( - ring.getLayout(), ring.getFlatCoordinates()); - } else if (this.sketchLineCoords_) { - sketchLineGeom = this.sketchLine_.getGeometry(); - goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, - 'sketchLineGeom must be an ol.geom.LineString'); - sketchLineGeom.setCoordinates(this.sketchLineCoords_); - } - this.updateSketchFeatures_(); -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'getVisible', + ol.layer.Base.prototype.getVisible); +goog.exportProperty( + ol.layer.Base.prototype, + 'getZIndex', + ol.layer.Base.prototype.getZIndex); -/** - * Add a new coordinate to the drawing. - * @param {ol.MapBrowserEvent} event Event. - * @private - */ -ol.interaction.Draw.prototype.addToDrawing_ = function(event) { - var coordinate = event.coordinate; - var geometry = this.sketchFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry must be an ol.geom.SimpleGeometry'); - var done; - var coordinates; - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - this.finishCoordinate_ = coordinate.slice(); - coordinates = this.sketchCoords_; - coordinates.push(coordinate.slice()); - done = coordinates.length > this.maxPoints_; - this.geometryFunction_(coordinates, geometry); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - coordinates = this.sketchCoords_[0]; - coordinates.push(coordinate.slice()); - done = coordinates.length > this.maxPoints_; - if (done) { - this.finishCoordinate_ = coordinates[0]; - } - this.geometryFunction_(this.sketchCoords_, geometry); - } - this.updateSketchFeatures_(); - if (done) { - this.finishDrawing(); - } -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'setExtent', + ol.layer.Base.prototype.setExtent); + +goog.exportProperty( + ol.layer.Base.prototype, + 'setMaxResolution', + ol.layer.Base.prototype.setMaxResolution); +goog.exportProperty( + ol.layer.Base.prototype, + 'setMinResolution', + ol.layer.Base.prototype.setMinResolution); -/** - * Remove last point of the feature currently being drawn. - * @api - */ -ol.interaction.Draw.prototype.removeLastPoint = function() { - var geometry = this.sketchFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry must be an ol.geom.SimpleGeometry'); - var coordinates, sketchLineGeom; - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - coordinates = this.sketchCoords_; - coordinates.splice(-2, 1); - this.geometryFunction_(coordinates, geometry); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - coordinates = this.sketchCoords_[0]; - coordinates.splice(-2, 1); - sketchLineGeom = this.sketchLine_.getGeometry(); - goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString, - 'sketchLineGeom must be an ol.geom.LineString'); - sketchLineGeom.setCoordinates(coordinates); - this.geometryFunction_(this.sketchCoords_, geometry); - } +goog.exportProperty( + ol.layer.Base.prototype, + 'setOpacity', + ol.layer.Base.prototype.setOpacity); - if (coordinates.length === 0) { - this.finishCoordinate_ = null; - } +goog.exportProperty( + ol.layer.Base.prototype, + 'setVisible', + ol.layer.Base.prototype.setVisible); - this.updateSketchFeatures_(); -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'setZIndex', + ol.layer.Base.prototype.setZIndex); +goog.exportSymbol( + 'ol.layer.Group', + ol.layer.Group); -/** - * Stop drawing and add the sketch feature to the target layer. - * The {@link ol.interaction.DrawEventType.DRAWEND} event is dispatched before - * inserting the feature. - * @api - */ -ol.interaction.Draw.prototype.finishDrawing = function() { - var sketchFeature = this.abortDrawing_(); - goog.asserts.assert(sketchFeature, 'sketchFeature expected to be truthy'); - var coordinates = this.sketchCoords_; - var geometry = sketchFeature.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry, - 'geometry must be an ol.geom.SimpleGeometry'); - if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) { - // remove the redundant last point - coordinates.pop(); - this.geometryFunction_(coordinates, geometry); - } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) { - // When we finish drawing a polygon on the last point, - // the last coordinate is duplicated as for LineString - // we force the replacement by the first point - coordinates[0].pop(); - coordinates[0].push(coordinates[0][0]); - this.geometryFunction_(coordinates, geometry); - } +goog.exportProperty( + ol.layer.Group.prototype, + 'getLayers', + ol.layer.Group.prototype.getLayers); - // cast multi-part geometries - if (this.type_ === ol.geom.GeometryType.MULTI_POINT) { - sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates])); - } else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) { - sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates])); - } else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) { - sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates])); - } +goog.exportProperty( + ol.layer.Group.prototype, + 'setLayers', + ol.layer.Group.prototype.setLayers); - // First dispatch event to allow full set up of feature - this.dispatchEvent(new ol.interaction.DrawEvent( - ol.interaction.DrawEventType.DRAWEND, sketchFeature)); +goog.exportSymbol( + 'ol.layer.Tile', + ol.layer.Tile); - // Then insert feature - if (this.features_) { - this.features_.push(sketchFeature); - } - if (this.source_) { - this.source_.addFeature(sketchFeature); - } -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'getPreload', + ol.layer.Tile.prototype.getPreload); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getSource', + ol.layer.Tile.prototype.getSource); -/** - * Stop drawing without adding the sketch feature to the target layer. - * @return {ol.Feature} The sketch feature (or null if none). - * @private - */ -ol.interaction.Draw.prototype.abortDrawing_ = function() { - this.finishCoordinate_ = null; - var sketchFeature = this.sketchFeature_; - if (sketchFeature) { - this.sketchFeature_ = null; - this.sketchPoint_ = null; - this.sketchLine_ = null; - this.overlay_.getSource().clear(true); - } - return sketchFeature; -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'setPreload', + ol.layer.Tile.prototype.setPreload); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getUseInterimTilesOnError', + ol.layer.Tile.prototype.getUseInterimTilesOnError); -/** - * Extend an existing geometry by adding additional points. This only works - * on features with `LineString` geometries, where the interaction will - * extend lines by adding points to the end of the coordinates array. - * @param {!ol.Feature} feature Feature to be extended. - * @api - */ -ol.interaction.Draw.prototype.extend = function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(this.mode_ == ol.interaction.DrawMode.LINE_STRING, - 'interaction mode must be "line"'); - goog.asserts.assert(geometry, 'feature must have a geometry'); - goog.asserts.assert(geometry.getType() == ol.geom.GeometryType.LINE_STRING, - 'feature geometry must be a line string'); - var lineString = /** @type {ol.geom.LineString} */ (geometry); - this.sketchFeature_ = feature; - this.sketchCoords_ = lineString.getCoordinates(); - var last = this.sketchCoords_[this.sketchCoords_.length - 1]; - this.finishCoordinate_ = last.slice(); - this.sketchCoords_.push(last.slice()); - this.updateSketchFeatures_(); - this.dispatchEvent(new ol.interaction.DrawEvent( - ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_)); -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'setUseInterimTilesOnError', + ol.layer.Tile.prototype.setUseInterimTilesOnError); +goog.exportSymbol( + 'ol.layer.Vector', + ol.layer.Vector); -/** - * @inheritDoc - */ -ol.interaction.Draw.prototype.shouldStopEvent = goog.functions.FALSE; +goog.exportProperty( + ol.layer.Vector.prototype, + 'getSource', + ol.layer.Vector.prototype.getSource); +goog.exportProperty( + ol.layer.Vector.prototype, + 'getStyle', + ol.layer.Vector.prototype.getStyle); -/** - * Redraw the sketch features. - * @private - */ -ol.interaction.Draw.prototype.updateSketchFeatures_ = function() { - var sketchFeatures = []; - if (this.sketchFeature_) { - sketchFeatures.push(this.sketchFeature_); - } - if (this.sketchLine_) { - sketchFeatures.push(this.sketchLine_); - } - if (this.sketchPoint_) { - sketchFeatures.push(this.sketchPoint_); - } - var overlaySource = this.overlay_.getSource(); - overlaySource.clear(true); - overlaySource.addFeatures(sketchFeatures); -}; +goog.exportProperty( + ol.layer.Vector.prototype, + 'getStyleFunction', + ol.layer.Vector.prototype.getStyleFunction); +goog.exportProperty( + ol.layer.Vector.prototype, + 'setStyle', + ol.layer.Vector.prototype.setStyle); -/** - * @private - */ -ol.interaction.Draw.prototype.updateState_ = function() { - var map = this.getMap(); - var active = this.getActive(); - if (!map || !active) { - this.abortDrawing_(); - } - this.overlay_.setMap(active ? map : null); -}; +goog.exportSymbol( + 'ol.layer.VectorTile', + ol.layer.VectorTile); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getPreload', + ol.layer.VectorTile.prototype.getPreload); -/** - * Create a `geometryFunction` for `mode: 'Circle'` that will create a regular - * polygon with a user specified number of sides and start angle instead of an - * `ol.geom.Circle` geometry. - * @param {number=} opt_sides Number of sides of the regular polygon. Default is - * 32. - * @param {number=} opt_angle Angle of the first point in radians. 0 means East. - * Default is the angle defined by the heading from the center of the - * regular polygon to the current pointer position. - * @return {ol.interaction.DrawGeometryFunctionType} Function that draws a - * polygon. - * @api - */ -ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) { - return ( - /** - * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates - * @param {ol.geom.SimpleGeometry=} opt_geometry - * @return {ol.geom.SimpleGeometry} - */ - function(coordinates, opt_geometry) { - var center = coordinates[0]; - var end = coordinates[1]; - var radius = Math.sqrt( - ol.coordinate.squaredDistance(center, end)); - var geometry = opt_geometry ? opt_geometry : - ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides); - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry must be a polygon'); - var angle = opt_angle ? opt_angle : - Math.atan((end[1] - center[1]) / (end[0] - center[0])); - ol.geom.Polygon.makeRegular(geometry, center, radius, angle); - return geometry; - } - ); -}; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getSource', + ol.layer.VectorTile.prototype.getSource); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getUseInterimTilesOnError', + ol.layer.VectorTile.prototype.getUseInterimTilesOnError); -/** - * Get the drawing mode. The mode for mult-part geometries is the same as for - * their single-part cousins. - * @param {ol.geom.GeometryType} type Geometry type. - * @return {ol.interaction.DrawMode} Drawing mode. - * @private - */ -ol.interaction.Draw.getMode_ = function(type) { - var mode; - if (type === ol.geom.GeometryType.POINT || - type === ol.geom.GeometryType.MULTI_POINT) { - mode = ol.interaction.DrawMode.POINT; - } else if (type === ol.geom.GeometryType.LINE_STRING || - type === ol.geom.GeometryType.MULTI_LINE_STRING) { - mode = ol.interaction.DrawMode.LINE_STRING; - } else if (type === ol.geom.GeometryType.POLYGON || - type === ol.geom.GeometryType.MULTI_POLYGON) { - mode = ol.interaction.DrawMode.POLYGON; - } else if (type === ol.geom.GeometryType.CIRCLE) { - mode = ol.interaction.DrawMode.CIRCLE; - } - goog.asserts.assert(mode !== undefined, 'mode should be defined'); - return mode; -}; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setPreload', + ol.layer.VectorTile.prototype.setPreload); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setUseInterimTilesOnError', + ol.layer.VectorTile.prototype.setUseInterimTilesOnError); -/** - * Function that takes coordinates and an optional existing geometry as - * arguments, and returns a geometry. The optional existing geometry is the - * geometry that is returned when the function is called without a second - * argument. - * @typedef {function(!(ol.Coordinate|Array.<ol.Coordinate>| - * Array.<Array.<ol.Coordinate>>), ol.geom.SimpleGeometry=): - * ol.geom.SimpleGeometry} - * @api - */ -ol.interaction.DrawGeometryFunctionType; +goog.exportSymbol( + 'ol.interaction.DoubleClickZoom', + ol.interaction.DoubleClickZoom); +goog.exportSymbol( + 'ol.interaction.DoubleClickZoom.handleEvent', + ol.interaction.DoubleClickZoom.handleEvent); -/** - * Draw mode. This collapses multi-part geometry types with their single-part - * cousins. - * @enum {string} - */ -ol.interaction.DrawMode = { - POINT: 'Point', - LINE_STRING: 'LineString', - POLYGON: 'Polygon', - CIRCLE: 'Circle' -}; +goog.exportSymbol( + 'ol.interaction.DragAndDrop', + ol.interaction.DragAndDrop); -goog.provide('ol.interaction.Modify'); -goog.provide('ol.interaction.ModifyEvent'); +goog.exportSymbol( + 'ol.interaction.DragAndDrop.handleEvent', + ol.interaction.DragAndDrop.handleEvent); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.functions'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Feature'); -goog.require('ol.MapBrowserEvent.EventType'); -goog.require('ol.MapBrowserPointerEvent'); -goog.require('ol.ViewHint'); -goog.require('ol.coordinate'); -goog.require('ol.events.condition'); -goog.require('ol.extent'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.MultiLineString'); -goog.require('ol.geom.MultiPoint'); -goog.require('ol.geom.MultiPolygon'); -goog.require('ol.geom.Point'); -goog.require('ol.geom.Polygon'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.layer.Vector'); -goog.require('ol.source.Vector'); -goog.require('ol.structs.RBush'); +goog.exportProperty( + ol.interaction.DragAndDropEvent.prototype, + 'features', + ol.interaction.DragAndDropEvent.prototype.features); +goog.exportProperty( + ol.interaction.DragAndDropEvent.prototype, + 'file', + ol.interaction.DragAndDropEvent.prototype.file); -/** - * @enum {string} - */ -ol.ModifyEventType = { - /** - * Triggered upon feature modification start - * @event ol.interaction.ModifyEvent#modifystart - * @api - */ - MODIFYSTART: 'modifystart', - /** - * Triggered upon feature modification end - * @event ol.interaction.ModifyEvent#modifyend - * @api - */ - MODIFYEND: 'modifyend' -}; +goog.exportProperty( + ol.interaction.DragAndDropEvent.prototype, + 'projection', + ol.interaction.DragAndDropEvent.prototype.projection); +goog.exportProperty( + ol.DragBoxEvent.prototype, + 'coordinate', + ol.DragBoxEvent.prototype.coordinate); +goog.exportSymbol( + 'ol.interaction.DragBox', + ol.interaction.DragBox); -/** - * @classdesc - * Events emitted by {@link ol.interaction.Modify} instances are instances of - * this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.ModifyEvent} - * @param {ol.ModifyEventType} type Type. - * @param {ol.Collection.<ol.Feature>} features The features modified. - * @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated - * {@link ol.MapBrowserPointerEvent}. - */ -ol.interaction.ModifyEvent = function(type, features, mapBrowserPointerEvent) { +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'getGeometry', + ol.interaction.DragBox.prototype.getGeometry); - goog.base(this, type); +goog.exportSymbol( + 'ol.interaction.DragPan', + ol.interaction.DragPan); - /** - * The features being modified. - * @type {ol.Collection.<ol.Feature>} - * @api - */ - this.features = features; +goog.exportSymbol( + 'ol.interaction.DragRotateAndZoom', + ol.interaction.DragRotateAndZoom); - /** - * Associated {@link ol.MapBrowserPointerEvent}. - * @type {ol.MapBrowserPointerEvent} - * @api - */ - this.mapBrowserPointerEvent = mapBrowserPointerEvent; -}; -goog.inherits(ol.interaction.ModifyEvent, goog.events.Event); +goog.exportSymbol( + 'ol.interaction.DragRotate', + ol.interaction.DragRotate); +goog.exportSymbol( + 'ol.interaction.DragZoom', + ol.interaction.DragZoom); -/** - * @typedef {{depth: (Array.<number>|undefined), - * feature: ol.Feature, - * geometry: ol.geom.SimpleGeometry, - * index: (number|undefined), - * segment: Array.<ol.Extent>}} - */ -ol.interaction.SegmentDataType; +goog.exportProperty( + ol.interaction.DrawEvent.prototype, + 'feature', + ol.interaction.DrawEvent.prototype.feature); +goog.exportSymbol( + 'ol.interaction.Draw', + ol.interaction.Draw); +goog.exportSymbol( + 'ol.interaction.Draw.handleEvent', + ol.interaction.Draw.handleEvent); -/** - * @classdesc - * Interaction for modifying feature geometries. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.ModifyOptions} options Options. - * @fires ol.interaction.ModifyEvent - * @api - */ -ol.interaction.Modify = function(options) { +goog.exportProperty( + ol.interaction.Draw.prototype, + 'removeLastPoint', + ol.interaction.Draw.prototype.removeLastPoint); - goog.base(this, { - handleDownEvent: ol.interaction.Modify.handleDownEvent_, - handleDragEvent: ol.interaction.Modify.handleDragEvent_, - handleEvent: ol.interaction.Modify.handleEvent, - handleUpEvent: ol.interaction.Modify.handleUpEvent_ - }); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'finishDrawing', + ol.interaction.Draw.prototype.finishDrawing); - /** - * @type {ol.events.ConditionType} - * @private - */ - this.deleteCondition_ = options.deleteCondition ? - options.deleteCondition : - /** @type {ol.events.ConditionType} */ (goog.functions.and( - ol.events.condition.noModifierKeys, - ol.events.condition.singleClick)); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'extend', + ol.interaction.Draw.prototype.extend); - /** - * Editing vertex. - * @type {ol.Feature} - * @private - */ - this.vertexFeature_ = null; +goog.exportSymbol( + 'ol.interaction.Draw.createRegularPolygon', + ol.interaction.Draw.createRegularPolygon); - /** - * Segments intersecting {@link this.vertexFeature_} by segment uid. - * @type {Object.<string, boolean>} - * @private - */ - this.vertexSegments_ = null; +goog.exportSymbol( + 'ol.interaction.Interaction', + ol.interaction.Interaction); - /** - * @type {ol.Pixel} - * @private - */ - this.lastPixel_ = [0, 0]; +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'getActive', + ol.interaction.Interaction.prototype.getActive); - /** - * Tracks if the next `singleclick` event should be ignored to prevent - * accidental deletion right after vertex creation. - * @type {boolean} - * @private - */ - this.ignoreNextSingleClick_ = false; +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'setActive', + ol.interaction.Interaction.prototype.setActive); - /** - * @type {boolean} - * @private - */ - this.modified_ = false; +goog.exportSymbol( + 'ol.interaction.defaults', + ol.interaction.defaults); - /** - * Segment RTree for each layer - * @type {ol.structs.RBush.<ol.interaction.SegmentDataType>} - * @private - */ - this.rBush_ = new ol.structs.RBush(); +goog.exportSymbol( + 'ol.interaction.KeyboardPan', + ol.interaction.KeyboardPan); - /** - * @type {number} - * @private - */ - this.pixelTolerance_ = options.pixelTolerance !== undefined ? - options.pixelTolerance : 10; +goog.exportSymbol( + 'ol.interaction.KeyboardPan.handleEvent', + ol.interaction.KeyboardPan.handleEvent); - /** - * @type {boolean} - * @private - */ - this.snappedToVertex_ = false; +goog.exportSymbol( + 'ol.interaction.KeyboardZoom', + ol.interaction.KeyboardZoom); - /** - * Indicate whether the interaction is currently changing a feature's - * coordinates. - * @type {boolean} - * @private - */ - this.changingFeature_ = false; +goog.exportSymbol( + 'ol.interaction.KeyboardZoom.handleEvent', + ol.interaction.KeyboardZoom.handleEvent); - /** - * @type {Array} - * @private - */ - this.dragSegments_ = null; +goog.exportProperty( + ol.interaction.ModifyEvent.prototype, + 'features', + ol.interaction.ModifyEvent.prototype.features); - /** - * Draw overlay where sketch features are drawn. - * @type {ol.layer.Vector} - * @private - */ - this.overlay_ = new ol.layer.Vector({ - source: new ol.source.Vector({ - useSpatialIndex: false, - wrapX: !!options.wrapX - }), - style: options.style ? options.style : - ol.interaction.Modify.getDefaultStyleFunction(), - updateWhileAnimating: true, - updateWhileInteracting: true - }); +goog.exportProperty( + ol.interaction.ModifyEvent.prototype, + 'mapBrowserPointerEvent', + ol.interaction.ModifyEvent.prototype.mapBrowserPointerEvent); - /** - * @const - * @private - * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>} - */ - this.SEGMENT_WRITERS_ = { - 'Point': this.writePointGeometry_, - 'LineString': this.writeLineStringGeometry_, - 'LinearRing': this.writeLineStringGeometry_, - 'Polygon': this.writePolygonGeometry_, - 'MultiPoint': this.writeMultiPointGeometry_, - 'MultiLineString': this.writeMultiLineStringGeometry_, - 'MultiPolygon': this.writeMultiPolygonGeometry_, - 'GeometryCollection': this.writeGeometryCollectionGeometry_ - }; +goog.exportSymbol( + 'ol.interaction.Modify', + ol.interaction.Modify); - /** - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features; +goog.exportSymbol( + 'ol.interaction.Modify.handleEvent', + ol.interaction.Modify.handleEvent); + +goog.exportSymbol( + 'ol.interaction.MouseWheelZoom', + ol.interaction.MouseWheelZoom); + +goog.exportSymbol( + 'ol.interaction.MouseWheelZoom.handleEvent', + ol.interaction.MouseWheelZoom.handleEvent); + +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'setMouseAnchor', + ol.interaction.MouseWheelZoom.prototype.setMouseAnchor); + +goog.exportSymbol( + 'ol.interaction.PinchRotate', + ol.interaction.PinchRotate); + +goog.exportSymbol( + 'ol.interaction.PinchZoom', + ol.interaction.PinchZoom); + +goog.exportSymbol( + 'ol.interaction.Pointer', + ol.interaction.Pointer); + +goog.exportSymbol( + 'ol.interaction.Pointer.handleEvent', + ol.interaction.Pointer.handleEvent); + +goog.exportProperty( + ol.interaction.SelectEvent.prototype, + 'selected', + ol.interaction.SelectEvent.prototype.selected); + +goog.exportProperty( + ol.interaction.SelectEvent.prototype, + 'deselected', + ol.interaction.SelectEvent.prototype.deselected); + +goog.exportProperty( + ol.interaction.SelectEvent.prototype, + 'mapBrowserEvent', + ol.interaction.SelectEvent.prototype.mapBrowserEvent); + +goog.exportSymbol( + 'ol.interaction.Select', + ol.interaction.Select); + +goog.exportProperty( + ol.interaction.Select.prototype, + 'getFeatures', + ol.interaction.Select.prototype.getFeatures); + +goog.exportProperty( + ol.interaction.Select.prototype, + 'getLayer', + ol.interaction.Select.prototype.getLayer); - this.features_.forEach(this.addFeature_, this); - goog.events.listen(this.features_, ol.CollectionEventType.ADD, - this.handleFeatureAdd_, false, this); - goog.events.listen(this.features_, ol.CollectionEventType.REMOVE, - this.handleFeatureRemove_, false, this); +goog.exportSymbol( + 'ol.interaction.Select.handleEvent', + ol.interaction.Select.handleEvent); -}; -goog.inherits(ol.interaction.Modify, ol.interaction.Pointer); +goog.exportProperty( + ol.interaction.Select.prototype, + 'setMap', + ol.interaction.Select.prototype.setMap); +goog.exportSymbol( + 'ol.interaction.Snap', + ol.interaction.Snap); -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Modify.prototype.addFeature_ = function(feature) { - var geometry = feature.getGeometry(); - if (geometry.getType() in this.SEGMENT_WRITERS_) { - this.SEGMENT_WRITERS_[geometry.getType()].call(this, feature, geometry); - } - var map = this.getMap(); - if (map) { - this.handlePointerAtPixel_(this.lastPixel_, map); - } - goog.events.listen(feature, goog.events.EventType.CHANGE, - this.handleFeatureChange_, false, this); -}; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'addFeature', + ol.interaction.Snap.prototype.addFeature); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'removeFeature', + ol.interaction.Snap.prototype.removeFeature); -/** - * @param {ol.MapBrowserPointerEvent} evt Map browser event - * @private - */ -ol.interaction.Modify.prototype.willModifyFeatures_ = function(evt) { - if (!this.modified_) { - this.modified_ = true; - this.dispatchEvent(new ol.interaction.ModifyEvent( - ol.ModifyEventType.MODIFYSTART, this.features_, evt)); - } -}; +goog.exportProperty( + ol.interaction.TranslateEvent.prototype, + 'features', + ol.interaction.TranslateEvent.prototype.features); +goog.exportProperty( + ol.interaction.TranslateEvent.prototype, + 'coordinate', + ol.interaction.TranslateEvent.prototype.coordinate); -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Modify.prototype.removeFeature_ = function(feature) { - this.removeFeatureSegmentData_(feature); - // Remove the vertex feature if the collection of canditate features - // is empty. - if (this.vertexFeature_ && this.features_.getLength() === 0) { - this.overlay_.getSource().removeFeature(this.vertexFeature_); - this.vertexFeature_ = null; - } - goog.events.unlisten(feature, goog.events.EventType.CHANGE, - this.handleFeatureChange_, false, this); -}; +goog.exportSymbol( + 'ol.interaction.Translate', + ol.interaction.Translate); +goog.exportSymbol( + 'ol.geom.Circle', + ol.geom.Circle); -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) { - var rBush = this.rBush_; - var /** @type {Array.<ol.interaction.SegmentDataType>} */ nodesToRemove = []; - rBush.forEach( - /** - * @param {ol.interaction.SegmentDataType} node RTree node. - */ - function(node) { - if (feature === node.feature) { - nodesToRemove.push(node); - } - }); - for (var i = nodesToRemove.length - 1; i >= 0; --i) { - rBush.remove(nodesToRemove[i]); - } -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'clone', + ol.geom.Circle.prototype.clone); +goog.exportProperty( + ol.geom.Circle.prototype, + 'getCenter', + ol.geom.Circle.prototype.getCenter); -/** - * @inheritDoc - */ -ol.interaction.Modify.prototype.setMap = function(map) { - this.overlay_.setMap(map); - goog.base(this, 'setMap', map); -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'getRadius', + ol.geom.Circle.prototype.getRadius); +goog.exportProperty( + ol.geom.Circle.prototype, + 'getType', + ol.geom.Circle.prototype.getType); -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) { - var feature = evt.element; - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - this.addFeature_(feature); -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'intersectsExtent', + ol.geom.Circle.prototype.intersectsExtent); +goog.exportProperty( + ol.geom.Circle.prototype, + 'setCenter', + ol.geom.Circle.prototype.setCenter); -/** - * @param {goog.events.Event} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) { - if (!this.changingFeature_) { - var feature = /** @type {ol.Feature} */ (evt.target); - this.removeFeature_(feature); - this.addFeature_(feature); - } -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'setCenterAndRadius', + ol.geom.Circle.prototype.setCenterAndRadius); +goog.exportProperty( + ol.geom.Circle.prototype, + 'setRadius', + ol.geom.Circle.prototype.setRadius); -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) { - var feature = /** @type {ol.Feature} */ (evt.element); - this.removeFeature_(feature); -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'transform', + ol.geom.Circle.prototype.transform); +goog.exportSymbol( + 'ol.geom.Geometry', + ol.geom.Geometry); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Point} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writePointGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); -}; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'getClosestPoint', + ol.geom.Geometry.prototype.getClosestPoint); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'getExtent', + ol.geom.Geometry.prototype.getExtent); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPoint} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeMultiPointGeometry_ = - function(feature, geometry) { - var points = geometry.getCoordinates(); - var coordinates, i, ii, segmentData; - for (i = 0, ii = points.length; i < ii; ++i) { - coordinates = points[i]; - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [i], - index: i, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); - } -}; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'simplify', + ol.geom.Geometry.prototype.simplify); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'transform', + ol.geom.Geometry.prototype.transform); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.LineString} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeLineStringGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var i, ii, segment, segmentData; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } -}; +goog.exportSymbol( + 'ol.geom.GeometryCollection', + ol.geom.GeometryCollection); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'clone', + ol.geom.GeometryCollection.prototype.clone); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiLineString} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeMultiLineStringGeometry_ = - function(feature, geometry) { - var lines = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = lines.length; j < jj; ++j) { - coordinates = lines[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [j], - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getGeometries', + ol.geom.GeometryCollection.prototype.getGeometries); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getType', + ol.geom.GeometryCollection.prototype.getType); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Polygon} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writePolygonGeometry_ = - function(feature, geometry) { - var rings = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [j], - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'intersectsExtent', + ol.geom.GeometryCollection.prototype.intersectsExtent); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'setGeometries', + ol.geom.GeometryCollection.prototype.setGeometries); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPolygon} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeMultiPolygonGeometry_ = - function(feature, geometry) { - var polygons = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData; - for (k = 0, kk = polygons.length; k < kk; ++k) { - rings = polygons[k]; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - feature: feature, - geometry: geometry, - depth: [j, k], - index: i, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } - } -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'applyTransform', + ol.geom.GeometryCollection.prototype.applyTransform); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'translate', + ol.geom.GeometryCollection.prototype.translate); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.GeometryCollection} geometry Geometry. - * @private - */ -ol.interaction.Modify.prototype.writeGeometryCollectionGeometry_ = - function(feature, geometry) { - var i, geometries = geometry.getGeometriesArray(); - for (i = 0; i < geometries.length; ++i) { - this.SEGMENT_WRITERS_[geometries[i].getType()].call( - this, feature, geometries[i]); - } -}; +goog.exportSymbol( + 'ol.geom.LinearRing', + ol.geom.LinearRing); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'clone', + ol.geom.LinearRing.prototype.clone); -/** - * @param {ol.Coordinate} coordinates Coordinates. - * @return {ol.Feature} Vertex feature. - * @private - */ -ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = - function(coordinates) { - var vertexFeature = this.vertexFeature_; - if (!vertexFeature) { - vertexFeature = new ol.Feature(new ol.geom.Point(coordinates)); - this.vertexFeature_ = vertexFeature; - this.overlay_.getSource().addFeature(vertexFeature); - } else { - var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry()); - geometry.setCoordinates(coordinates); - } - return vertexFeature; -}; +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getArea', + ol.geom.LinearRing.prototype.getArea); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getCoordinates', + ol.geom.LinearRing.prototype.getCoordinates); -/** - * @param {ol.interaction.SegmentDataType} a - * @param {ol.interaction.SegmentDataType} b - * @return {number} - * @private - */ -ol.interaction.Modify.compareIndexes_ = function(a, b) { - return a.index - b.index; -}; +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getType', + ol.geom.LinearRing.prototype.getType); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'setCoordinates', + ol.geom.LinearRing.prototype.setCoordinates); -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.Modify} - * @private - */ -ol.interaction.Modify.handleDownEvent_ = function(evt) { - this.handlePointerAtPixel_(evt.pixel, evt.map); - this.dragSegments_ = []; - this.modified_ = false; - var vertexFeature = this.vertexFeature_; - if (vertexFeature) { - var insertVertices = []; - var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry()); - var vertex = geometry.getCoordinates(); - var vertexExtent = ol.extent.boundingExtent([vertex]); - var segmentDataMatches = this.rBush_.getInExtent(vertexExtent); - var componentSegments = {}; - segmentDataMatches.sort(ol.interaction.Modify.compareIndexes_); - for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) { - var segmentDataMatch = segmentDataMatches[i]; - var segment = segmentDataMatch.segment; - var uid = goog.getUid(segmentDataMatch.feature); - var depth = segmentDataMatch.depth; - if (depth) { - uid += '-' + depth.join('-'); // separate feature components - } - if (!componentSegments[uid]) { - componentSegments[uid] = new Array(2); - } - if (ol.coordinate.equals(segment[0], vertex) && - !componentSegments[uid][0]) { - this.dragSegments_.push([segmentDataMatch, 0]); - componentSegments[uid][0] = segmentDataMatch; - } else if (ol.coordinate.equals(segment[1], vertex) && - !componentSegments[uid][1]) { +goog.exportSymbol( + 'ol.geom.LineString', + ol.geom.LineString); - // prevent dragging closed linestrings by the connecting node - if ((segmentDataMatch.geometry.getType() === - ol.geom.GeometryType.LINE_STRING || - segmentDataMatch.geometry.getType() === - ol.geom.GeometryType.MULTI_LINE_STRING) && - componentSegments[uid][0] && - componentSegments[uid][0].index === 0) { - continue; - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'appendCoordinate', + ol.geom.LineString.prototype.appendCoordinate); - this.dragSegments_.push([segmentDataMatch, 1]); - componentSegments[uid][1] = segmentDataMatch; - } else if (goog.getUid(segment) in this.vertexSegments_ && - (!componentSegments[uid][0] && !componentSegments[uid][1])) { - insertVertices.push([segmentDataMatch, vertex]); - } - } - if (insertVertices.length) { - this.willModifyFeatures_(evt); - } - for (i = insertVertices.length - 1; i >= 0; --i) { - this.insertVertex_.apply(this, insertVertices[i]); - } - } - return !!this.vertexFeature_; -}; +goog.exportProperty( + ol.geom.LineString.prototype, + 'clone', + ol.geom.LineString.prototype.clone); +goog.exportProperty( + ol.geom.LineString.prototype, + 'forEachSegment', + ol.geom.LineString.prototype.forEachSegment); -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @this {ol.interaction.Modify} - * @private - */ -ol.interaction.Modify.handleDragEvent_ = function(evt) { - this.ignoreNextSingleClick_ = false; - this.willModifyFeatures_(evt); +goog.exportProperty( + ol.geom.LineString.prototype, + 'getCoordinateAtM', + ol.geom.LineString.prototype.getCoordinateAtM); - var vertex = evt.coordinate; - for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) { - var dragSegment = this.dragSegments_[i]; - var segmentData = dragSegment[0]; - var depth = segmentData.depth; - var geometry = segmentData.geometry; - var coordinates = geometry.getCoordinates(); - var segment = segmentData.segment; - var index = dragSegment[1]; +goog.exportProperty( + ol.geom.LineString.prototype, + 'getCoordinates', + ol.geom.LineString.prototype.getCoordinates); - while (vertex.length < geometry.getStride()) { - vertex.push(0); - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'getLength', + ol.geom.LineString.prototype.getLength); - switch (geometry.getType()) { - case ol.geom.GeometryType.POINT: - coordinates = vertex; - segment[0] = segment[1] = vertex; - break; - case ol.geom.GeometryType.MULTI_POINT: - coordinates[segmentData.index] = vertex; - segment[0] = segment[1] = vertex; - break; - case ol.geom.GeometryType.LINE_STRING: - coordinates[segmentData.index + index] = vertex; - segment[index] = vertex; - break; - case ol.geom.GeometryType.MULTI_LINE_STRING: - coordinates[depth[0]][segmentData.index + index] = vertex; - segment[index] = vertex; - break; - case ol.geom.GeometryType.POLYGON: - coordinates[depth[0]][segmentData.index + index] = vertex; - segment[index] = vertex; - break; - case ol.geom.GeometryType.MULTI_POLYGON: - coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex; - segment[index] = vertex; - break; - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'getType', + ol.geom.LineString.prototype.getType); - this.setGeometryCoordinates_(geometry, coordinates); - } - this.createOrUpdateVertexFeature_(vertex); -}; +goog.exportProperty( + ol.geom.LineString.prototype, + 'intersectsExtent', + ol.geom.LineString.prototype.intersectsExtent); +goog.exportProperty( + ol.geom.LineString.prototype, + 'setCoordinates', + ol.geom.LineString.prototype.setCoordinates); -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Modify} - * @private - */ -ol.interaction.Modify.handleUpEvent_ = function(evt) { - var segmentData; - for (var i = this.dragSegments_.length - 1; i >= 0; --i) { - segmentData = this.dragSegments_[i][0]; - this.rBush_.update(ol.extent.boundingExtent(segmentData.segment), - segmentData); - } - if (this.modified_) { - this.dispatchEvent(new ol.interaction.ModifyEvent( - ol.ModifyEventType.MODIFYEND, this.features_, evt)); - this.modified_ = false; - } - return false; -}; +goog.exportSymbol( + 'ol.geom.MultiLineString', + ol.geom.MultiLineString); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'appendLineString', + ol.geom.MultiLineString.prototype.appendLineString); -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may modify the - * geometry. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Modify} - * @api - */ -ol.interaction.Modify.handleEvent = function(mapBrowserEvent) { - if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) { - return true; - } +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'clone', + ol.geom.MultiLineString.prototype.clone); - var handled; - if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] && - mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE && - !this.handlingDownUpSequence) { - this.handlePointerMove_(mapBrowserEvent); - } - if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) { - if (mapBrowserEvent.type != ol.MapBrowserEvent.EventType.SINGLECLICK || - !this.ignoreNextSingleClick_) { - var geometry = this.vertexFeature_.getGeometry(); - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); - this.willModifyFeatures_(mapBrowserEvent); - handled = this.removeVertex_(); - this.dispatchEvent(new ol.interaction.ModifyEvent( - ol.ModifyEventType.MODIFYEND, this.features_, mapBrowserEvent)); - this.modified_ = false; - } else { - handled = true; - } - } +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getCoordinateAtM', + ol.geom.MultiLineString.prototype.getCoordinateAtM); - if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK) { - this.ignoreNextSingleClick_ = false; - } +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getCoordinates', + ol.geom.MultiLineString.prototype.getCoordinates); - return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && - !handled; -}; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getLineString', + ol.geom.MultiLineString.prototype.getLineString); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getLineStrings', + ol.geom.MultiLineString.prototype.getLineStrings); -/** - * @param {ol.MapBrowserEvent} evt Event. - * @private - */ -ol.interaction.Modify.prototype.handlePointerMove_ = function(evt) { - this.lastPixel_ = evt.pixel; - this.handlePointerAtPixel_(evt.pixel, evt.map); -}; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getType', + ol.geom.MultiLineString.prototype.getType); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'intersectsExtent', + ol.geom.MultiLineString.prototype.intersectsExtent); -/** - * @param {ol.Pixel} pixel Pixel - * @param {ol.Map} map Map. - * @private - */ -ol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) { - var pixelCoordinate = map.getCoordinateFromPixel(pixel); - var sortByDistance = function(a, b) { - return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a.segment) - - ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b.segment); - }; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'setCoordinates', + ol.geom.MultiLineString.prototype.setCoordinates); - var lowerLeft = map.getCoordinateFromPixel( - [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]); - var upperRight = map.getCoordinateFromPixel( - [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]); - var box = ol.extent.boundingExtent([lowerLeft, upperRight]); +goog.exportSymbol( + 'ol.geom.MultiPoint', + ol.geom.MultiPoint); - var rBush = this.rBush_; - var nodes = rBush.getInExtent(box); - if (nodes.length > 0) { - nodes.sort(sortByDistance); - var node = nodes[0]; - var closestSegment = node.segment; - var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, - closestSegment)); - var vertexPixel = map.getPixelFromCoordinate(vertex); - if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= - this.pixelTolerance_) { - var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); - var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); - var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); - var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); - var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); - this.snappedToVertex_ = dist <= this.pixelTolerance_; - if (this.snappedToVertex_) { - vertex = squaredDist1 > squaredDist2 ? - closestSegment[1] : closestSegment[0]; - } - this.createOrUpdateVertexFeature_(vertex); - var vertexSegments = {}; - vertexSegments[goog.getUid(closestSegment)] = true; - var segment; - for (var i = 1, ii = nodes.length; i < ii; ++i) { - segment = nodes[i].segment; - if ((ol.coordinate.equals(closestSegment[0], segment[0]) && - ol.coordinate.equals(closestSegment[1], segment[1]) || - (ol.coordinate.equals(closestSegment[0], segment[1]) && - ol.coordinate.equals(closestSegment[1], segment[0])))) { - vertexSegments[goog.getUid(segment)] = true; - } else { - break; - } - } - this.vertexSegments_ = vertexSegments; - return; - } - } - if (this.vertexFeature_) { - this.overlay_.getSource().removeFeature(this.vertexFeature_); - this.vertexFeature_ = null; - } -}; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'appendPoint', + ol.geom.MultiPoint.prototype.appendPoint); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'clone', + ol.geom.MultiPoint.prototype.clone); -/** - * @param {ol.interaction.SegmentDataType} segmentData Segment data. - * @param {ol.Coordinate} vertex Vertex. - * @private - */ -ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) { - var segment = segmentData.segment; - var feature = segmentData.feature; - var geometry = segmentData.geometry; - var depth = segmentData.depth; - var index = segmentData.index; - var coordinates; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getCoordinates', + ol.geom.MultiPoint.prototype.getCoordinates); - while (vertex.length < geometry.getStride()) { - vertex.push(0); - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getPoint', + ol.geom.MultiPoint.prototype.getPoint); - switch (geometry.getType()) { - case ol.geom.GeometryType.MULTI_LINE_STRING: - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); - coordinates = geometry.getCoordinates(); - coordinates[depth[0]].splice(index + 1, 0, vertex); - break; - case ol.geom.GeometryType.POLYGON: - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); - coordinates = geometry.getCoordinates(); - coordinates[depth[0]].splice(index + 1, 0, vertex); - break; - case ol.geom.GeometryType.MULTI_POLYGON: - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon, - 'geometry should be an ol.geom.MultiPolygon'); - coordinates = geometry.getCoordinates(); - coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex); - break; - case ol.geom.GeometryType.LINE_STRING: - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); - coordinates = geometry.getCoordinates(); - coordinates.splice(index + 1, 0, vertex); - break; - default: - return; - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getPoints', + ol.geom.MultiPoint.prototype.getPoints); - this.setGeometryCoordinates_(geometry, coordinates); - var rTree = this.rBush_; - goog.asserts.assert(segment !== undefined, 'segment should be defined'); - rTree.remove(segmentData); - goog.asserts.assert(index !== undefined, 'index should be defined'); - this.updateSegmentIndices_(geometry, index, depth, 1); - var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - segment: [segment[0], vertex], - feature: feature, - geometry: geometry, - depth: depth, - index: index - }); - rTree.insert(ol.extent.boundingExtent(newSegmentData.segment), - newSegmentData); - this.dragSegments_.push([newSegmentData, 1]); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getType', + ol.geom.MultiPoint.prototype.getType); - var newSegmentData2 = /** @type {ol.interaction.SegmentDataType} */ ({ - segment: [vertex, segment[1]], - feature: feature, - geometry: geometry, - depth: depth, - index: index + 1 - }); - rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment), - newSegmentData2); - this.dragSegments_.push([newSegmentData2, 0]); - this.ignoreNextSingleClick_ = true; -}; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'intersectsExtent', + ol.geom.MultiPoint.prototype.intersectsExtent); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'setCoordinates', + ol.geom.MultiPoint.prototype.setCoordinates); -/** - * Removes a vertex from all matching features. - * @return {boolean} True when a vertex was removed. - * @private - */ -ol.interaction.Modify.prototype.removeVertex_ = function() { - var dragSegments = this.dragSegments_; - var segmentsByFeature = {}; - var component, coordinates, dragSegment, geometry, i, index, left; - var newIndex, newSegment, right, segmentData, uid, deleted; - for (i = dragSegments.length - 1; i >= 0; --i) { - dragSegment = dragSegments[i]; - segmentData = dragSegment[0]; - geometry = segmentData.geometry; - coordinates = geometry.getCoordinates(); - uid = goog.getUid(segmentData.feature); - if (segmentData.depth) { - // separate feature components - uid += '-' + segmentData.depth.join('-'); - } - left = right = index = undefined; - if (dragSegment[1] === 0) { - right = segmentData; - index = segmentData.index; - } else if (dragSegment[1] == 1) { - left = segmentData; - index = segmentData.index + 1; - } - if (!(uid in segmentsByFeature)) { - segmentsByFeature[uid] = [left, right, index]; - } - newSegment = segmentsByFeature[uid]; - if (left !== undefined) { - newSegment[0] = left; - } - if (right !== undefined) { - newSegment[1] = right; - } - if (newSegment[0] !== undefined && newSegment[1] !== undefined) { - component = coordinates; - deleted = false; - newIndex = index - 1; - switch (geometry.getType()) { - case ol.geom.GeometryType.MULTI_LINE_STRING: - coordinates[segmentData.depth[0]].splice(index, 1); - deleted = true; - break; - case ol.geom.GeometryType.LINE_STRING: - coordinates.splice(index, 1); - deleted = true; - break; - case ol.geom.GeometryType.MULTI_POLYGON: - component = component[segmentData.depth[1]]; - /* falls through */ - case ol.geom.GeometryType.POLYGON: - component = component[segmentData.depth[0]]; - if (component.length > 4) { - if (index == component.length - 1) { - index = 0; - } - component.splice(index, 1); - deleted = true; - if (index === 0) { - // close the ring again - component.pop(); - component.push(component[0]); - newIndex = component.length - 1; - } - } - break; - } +goog.exportSymbol( + 'ol.geom.MultiPolygon', + ol.geom.MultiPolygon); - if (deleted) { - this.rBush_.remove(newSegment[0]); - this.rBush_.remove(newSegment[1]); - this.setGeometryCoordinates_(geometry, coordinates); - goog.asserts.assert(newIndex >= 0, 'newIndex should be larger than 0'); - var newSegmentData = /** @type {ol.interaction.SegmentDataType} */ ({ - depth: segmentData.depth, - feature: segmentData.feature, - geometry: segmentData.geometry, - index: newIndex, - segment: [newSegment[0].segment[0], newSegment[1].segment[1]] - }); - this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment), - newSegmentData); - this.updateSegmentIndices_(geometry, index, segmentData.depth, -1); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'appendPolygon', + ol.geom.MultiPolygon.prototype.appendPolygon); - if (this.vertexFeature_) { - this.overlay_.getSource().removeFeature(this.vertexFeature_); - this.vertexFeature_ = null; - } - } - } - } - return true; -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'clone', + ol.geom.MultiPolygon.prototype.clone); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getArea', + ol.geom.MultiPolygon.prototype.getArea); -/** - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @param {Array} coordinates Coordinates. - * @private - */ -ol.interaction.Modify.prototype.setGeometryCoordinates_ = - function(geometry, coordinates) { - this.changingFeature_ = true; - geometry.setCoordinates(coordinates); - this.changingFeature_ = false; -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getCoordinates', + ol.geom.MultiPolygon.prototype.getCoordinates); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getInteriorPoints', + ol.geom.MultiPolygon.prototype.getInteriorPoints); -/** - * @param {ol.geom.SimpleGeometry} geometry Geometry. - * @param {number} index Index. - * @param {Array.<number>|undefined} depth Depth. - * @param {number} delta Delta (1 or -1). - * @private - */ -ol.interaction.Modify.prototype.updateSegmentIndices_ = function( - geometry, index, depth, delta) { - this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) { - if (segmentDataMatch.geometry === geometry && - (depth === undefined || segmentDataMatch.depth === undefined || - goog.array.equals( - /** @type {null|{length: number}} */ (segmentDataMatch.depth), - depth)) && - segmentDataMatch.index > index) { - segmentDataMatch.index += delta; - } - }); -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getPolygon', + ol.geom.MultiPolygon.prototype.getPolygon); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getPolygons', + ol.geom.MultiPolygon.prototype.getPolygons); -/** - * @return {ol.style.StyleFunction} Styles. - */ -ol.interaction.Modify.getDefaultStyleFunction = function() { - var style = ol.style.createDefaultEditingStyles(); - return function(feature, resolution) { - return style[ol.geom.GeometryType.POINT]; - }; -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getType', + ol.geom.MultiPolygon.prototype.getType); -goog.provide('ol.interaction.Select'); -goog.provide('ol.interaction.SelectEvent'); -goog.provide('ol.interaction.SelectEventType'); -goog.provide('ol.interaction.SelectFilterFunction'); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'intersectsExtent', + ol.geom.MultiPolygon.prototype.intersectsExtent); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Feature'); -goog.require('ol.array'); -goog.require('ol.events.condition'); -goog.require('ol.geom.GeometryType'); -goog.require('ol.interaction.Interaction'); -goog.require('ol.layer.Vector'); -goog.require('ol.source.Vector'); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'setCoordinates', + ol.geom.MultiPolygon.prototype.setCoordinates); +goog.exportSymbol( + 'ol.geom.Point', + ol.geom.Point); -/** - * @enum {string} - */ -ol.interaction.SelectEventType = { - /** - * Triggered when feature(s) has been (de)selected. - * @event ol.interaction.SelectEvent#select - * @api - */ - SELECT: 'select' -}; +goog.exportProperty( + ol.geom.Point.prototype, + 'clone', + ol.geom.Point.prototype.clone); +goog.exportProperty( + ol.geom.Point.prototype, + 'getCoordinates', + ol.geom.Point.prototype.getCoordinates); -/** - * A function that takes an {@link ol.Feature} or {@link ol.render.Feature} and - * an {@link ol.layer.Layer} and returns `true` if the feature may be selected - * or `false` otherwise. - * @typedef {function((ol.Feature|ol.render.Feature), ol.layer.Layer): - * boolean} - * @api - */ -ol.interaction.SelectFilterFunction; +goog.exportProperty( + ol.geom.Point.prototype, + 'getType', + ol.geom.Point.prototype.getType); +goog.exportProperty( + ol.geom.Point.prototype, + 'intersectsExtent', + ol.geom.Point.prototype.intersectsExtent); +goog.exportProperty( + ol.geom.Point.prototype, + 'setCoordinates', + ol.geom.Point.prototype.setCoordinates); -/** - * @classdesc - * Events emitted by {@link ol.interaction.Select} instances are instances of - * this type. - * - * @param {string} type The event type. - * @param {Array.<ol.Feature>} selected Selected features. - * @param {Array.<ol.Feature>} deselected Deselected features. - * @param {ol.MapBrowserEvent} mapBrowserEvent Associated - * {@link ol.MapBrowserEvent}. - * @implements {oli.SelectEvent} - * @extends {goog.events.Event} - * @constructor - */ -ol.interaction.SelectEvent = - function(type, selected, deselected, mapBrowserEvent) { - goog.base(this, type); +goog.exportSymbol( + 'ol.geom.Polygon', + ol.geom.Polygon); - /** - * Selected features array. - * @type {Array.<ol.Feature>} - * @api - */ - this.selected = selected; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'appendLinearRing', + ol.geom.Polygon.prototype.appendLinearRing); - /** - * Deselected features array. - * @type {Array.<ol.Feature>} - * @api - */ - this.deselected = deselected; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'clone', + ol.geom.Polygon.prototype.clone); - /** - * Associated {@link ol.MapBrowserEvent}. - * @type {ol.MapBrowserEvent} - * @api - */ - this.mapBrowserEvent = mapBrowserEvent; -}; -goog.inherits(ol.interaction.SelectEvent, goog.events.Event); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getArea', + ol.geom.Polygon.prototype.getArea); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getCoordinates', + ol.geom.Polygon.prototype.getCoordinates); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getInteriorPoint', + ol.geom.Polygon.prototype.getInteriorPoint); -/** - * @classdesc - * Interaction for selecting vector features. By default, selected features are - * styled differently, so this interaction can be used for visual highlighting, - * as well as selecting features for other actions, such as modification or - * output. There are three ways of controlling which features are selected: - * using the browser event as defined by the `condition` and optionally the - * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a - * further feature filter using the `filter` option. - * - * Selected features are added to an internal unmanaged layer. - * - * @constructor - * @extends {ol.interaction.Interaction} - * @param {olx.interaction.SelectOptions=} opt_options Options. - * @fires ol.interaction.SelectEvent - * @api stable - */ -ol.interaction.Select = function(opt_options) { +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getLinearRingCount', + ol.geom.Polygon.prototype.getLinearRingCount); - goog.base(this, { - handleEvent: ol.interaction.Select.handleEvent - }); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getLinearRing', + ol.geom.Polygon.prototype.getLinearRing); - var options = opt_options ? opt_options : {}; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getLinearRings', + ol.geom.Polygon.prototype.getLinearRings); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.condition_ = options.condition ? - options.condition : ol.events.condition.singleClick; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getType', + ol.geom.Polygon.prototype.getType); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.addCondition_ = options.addCondition ? - options.addCondition : ol.events.condition.never; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'intersectsExtent', + ol.geom.Polygon.prototype.intersectsExtent); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.removeCondition_ = options.removeCondition ? - options.removeCondition : ol.events.condition.never; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'setCoordinates', + ol.geom.Polygon.prototype.setCoordinates); - /** - * @private - * @type {ol.events.ConditionType} - */ - this.toggleCondition_ = options.toggleCondition ? - options.toggleCondition : ol.events.condition.shiftKeyOnly; +goog.exportSymbol( + 'ol.geom.Polygon.circular', + ol.geom.Polygon.circular); - /** - * @private - * @type {boolean} - */ - this.multi_ = options.multi ? options.multi : false; +goog.exportSymbol( + 'ol.geom.Polygon.fromExtent', + ol.geom.Polygon.fromExtent); - /** - * @private - * @type {ol.interaction.SelectFilterFunction} - */ - this.filter_ = options.filter ? options.filter : - goog.functions.TRUE; +goog.exportSymbol( + 'ol.geom.Polygon.fromCircle', + ol.geom.Polygon.fromCircle); - var layerFilter; - if (options.layers) { - if (goog.isFunction(options.layers)) { - layerFilter = options.layers; - } else { - var layers = options.layers; - layerFilter = - /** - * @param {ol.layer.Layer} layer Layer. - * @return {boolean} Include. - */ - function(layer) { - return ol.array.includes(layers, layer); - }; - } - } else { - layerFilter = goog.functions.TRUE; - } +goog.exportSymbol( + 'ol.geom.SimpleGeometry', + ol.geom.SimpleGeometry); - /** - * @private - * @type {function(ol.layer.Layer): boolean} - */ - this.layerFilter_ = layerFilter; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getFirstCoordinate', + ol.geom.SimpleGeometry.prototype.getFirstCoordinate); - /** - * An association between selected feature (key) - * and layer (value) - * @private - * @type {Object.<number, ol.layer.Layer>} - */ - this.featureLayerAssociation_ = {}; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getLastCoordinate', + ol.geom.SimpleGeometry.prototype.getLastCoordinate); - /** - * @private - * @type {ol.layer.Vector} - */ - this.featureOverlay_ = new ol.layer.Vector({ - source: new ol.source.Vector({ - useSpatialIndex: false, - features: options.features, - wrapX: options.wrapX - }), - style: options.style ? options.style : - ol.interaction.Select.getDefaultStyleFunction(), - updateWhileAnimating: true, - updateWhileInteracting: true - }); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getLayout', + ol.geom.SimpleGeometry.prototype.getLayout); - var features = this.featureOverlay_.getSource().getFeaturesCollection(); - goog.events.listen(features, ol.CollectionEventType.ADD, - this.addFeature_, false, this); - goog.events.listen(features, ol.CollectionEventType.REMOVE, - this.removeFeature_, false, this); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'applyTransform', + ol.geom.SimpleGeometry.prototype.applyTransform); -}; -goog.inherits(ol.interaction.Select, ol.interaction.Interaction); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'translate', + ol.geom.SimpleGeometry.prototype.translate); +goog.exportSymbol( + 'ol.format.EsriJSON', + ol.format.EsriJSON); -/** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.layer.Layer} layer Layer. - * @private - */ -ol.interaction.Select.prototype.addFeatureLayerAssociation_ = - function(feature, layer) { - var key = goog.getUid(feature); - this.featureLayerAssociation_[key] = layer; -}; +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'readFeature', + ol.format.EsriJSON.prototype.readFeature); +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'readFeatures', + ol.format.EsriJSON.prototype.readFeatures); -/** - * Get the selected features. - * @return {ol.Collection.<ol.Feature>} Features collection. - * @api stable - */ -ol.interaction.Select.prototype.getFeatures = function() { - return this.featureOverlay_.getSource().getFeaturesCollection(); -}; +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'readGeometry', + ol.format.EsriJSON.prototype.readGeometry); +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'readProjection', + ol.format.EsriJSON.prototype.readProjection); -/** - * Returns the associated {@link ol.layer.Vector vectorlayer} of - * the (last) selected feature. Note that this will not work with any - * programmatic method like pushing features to - * {@link ol.interaction.Select#getFeatures collection}. - * @param {ol.Feature|ol.render.Feature} feature Feature - * @return {ol.layer.Vector} Layer. - * @api - */ -ol.interaction.Select.prototype.getLayer = function(feature) { - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - var key = goog.getUid(feature); - return /** @type {ol.layer.Vector} */ (this.featureLayerAssociation_[key]); -}; +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'writeGeometry', + ol.format.EsriJSON.prototype.writeGeometry); +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'writeGeometryObject', + ol.format.EsriJSON.prototype.writeGeometryObject); -/** - * Handles the {@link ol.MapBrowserEvent map browser event} and may change the - * selected state of features. - * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. - * @return {boolean} `false` to stop event propagation. - * @this {ol.interaction.Select} - * @api - */ -ol.interaction.Select.handleEvent = function(mapBrowserEvent) { - if (!this.condition_(mapBrowserEvent)) { - return true; - } - var add = this.addCondition_(mapBrowserEvent); - var remove = this.removeCondition_(mapBrowserEvent); - var toggle = this.toggleCondition_(mapBrowserEvent); - var set = !add && !remove && !toggle; - var map = mapBrowserEvent.map; - var features = this.featureOverlay_.getSource().getFeaturesCollection(); - var /** @type {!Array.<ol.Feature>} */ deselected = []; - var /** @type {!Array.<ol.Feature>} */ selected = []; - var change = false; - if (set) { - // Replace the currently selected feature(s) with the feature(s) at the - // pixel, or clear the selected feature(s) if there is no feature at - // the pixel. - map.forEachFeatureAtPixel(mapBrowserEvent.pixel, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.layer.Layer} layer Layer. - */ - function(feature, layer) { - if (layer && this.filter_(feature, layer)) { - selected.push(feature); - this.addFeatureLayerAssociation_(feature, layer); - return !this.multi_; - } - }, this, this.layerFilter_); - if (selected.length > 0 && features.getLength() == 1 && - features.item(0) == selected[0]) { - // No change - } else { - change = true; - if (features.getLength() !== 0) { - deselected = Array.prototype.concat(features.getArray()); - features.clear(); - } - features.extend(selected); - // Modify object this.featureLayerAssociation_ - if (selected.length === 0) { - goog.object.clear(this.featureLayerAssociation_); - } else { - if (deselected.length > 0) { - deselected.forEach(function(feature) { - this.removeFeatureLayerAssociation_(feature); - }, this); - } - } - } - } else { - // Modify the currently selected feature(s). - map.forEachFeatureAtPixel(mapBrowserEvent.pixel, - /** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @param {ol.layer.Layer} layer Layer. - */ - function(feature, layer) { - if (!ol.array.includes(features.getArray(), feature)) { - if (add || toggle) { - if (this.filter_(feature, layer)) { - selected.push(feature); - this.addFeatureLayerAssociation_(feature, layer); - } - } - } else { - if (remove || toggle) { - deselected.push(feature); - this.removeFeatureLayerAssociation_(feature); - } - } - }, this, this.layerFilter_); - var i; - for (i = deselected.length - 1; i >= 0; --i) { - features.remove(deselected[i]); - } - features.extend(selected); - if (selected.length > 0 || deselected.length > 0) { - change = true; - } - } - if (change) { - this.dispatchEvent( - new ol.interaction.SelectEvent(ol.interaction.SelectEventType.SELECT, - selected, deselected, mapBrowserEvent)); - } - return ol.events.condition.pointerMove(mapBrowserEvent); -}; +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'writeFeature', + ol.format.EsriJSON.prototype.writeFeature); +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'writeFeatureObject', + ol.format.EsriJSON.prototype.writeFeatureObject); -/** - * Remove the interaction from its current map, if any, and attach it to a new - * map, if any. Pass `null` to just remove the interaction from the current map. - * @param {ol.Map} map Map. - * @api stable - */ -ol.interaction.Select.prototype.setMap = function(map) { - var currentMap = this.getMap(); - var selectedFeatures = - this.featureOverlay_.getSource().getFeaturesCollection(); - if (!goog.isNull(currentMap)) { - selectedFeatures.forEach(currentMap.unskipFeature, currentMap); - } - goog.base(this, 'setMap', map); - this.featureOverlay_.setMap(map); - if (!goog.isNull(map)) { - selectedFeatures.forEach(map.skipFeature, map); - } -}; +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'writeFeatures', + ol.format.EsriJSON.prototype.writeFeatures); +goog.exportProperty( + ol.format.EsriJSON.prototype, + 'writeFeaturesObject', + ol.format.EsriJSON.prototype.writeFeaturesObject); -/** - * @return {ol.style.StyleFunction} Styles. - */ -ol.interaction.Select.getDefaultStyleFunction = function() { - var styles = ol.style.createDefaultEditingStyles(); - goog.array.extend(styles[ol.geom.GeometryType.POLYGON], - styles[ol.geom.GeometryType.LINE_STRING]); - goog.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION], - styles[ol.geom.GeometryType.LINE_STRING]); +goog.exportSymbol( + 'ol.format.Feature', + ol.format.Feature); - return function(feature, resolution) { - return styles[feature.getGeometry().getType()]; - }; -}; +goog.exportSymbol( + 'ol.format.GeoJSON', + ol.format.GeoJSON); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'readFeature', + ol.format.GeoJSON.prototype.readFeature); -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Select.prototype.addFeature_ = function(evt) { - var feature = evt.element; - var map = this.getMap(); - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - if (!goog.isNull(map)) { - map.skipFeature(feature); - } -}; +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'readFeatures', + ol.format.GeoJSON.prototype.readFeatures); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'readGeometry', + ol.format.GeoJSON.prototype.readGeometry); -/** - * @param {ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Select.prototype.removeFeature_ = function(evt) { - var feature = evt.element; - var map = this.getMap(); - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - if (!goog.isNull(map)) { - map.unskipFeature(feature); - } -}; +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'readProjection', + ol.format.GeoJSON.prototype.readProjection); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'writeFeature', + ol.format.GeoJSON.prototype.writeFeature); -/** - * @param {ol.Feature|ol.render.Feature} feature Feature. - * @private - */ -ol.interaction.Select.prototype.removeFeatureLayerAssociation_ = - function(feature) { - var key = goog.getUid(feature); - delete this.featureLayerAssociation_[key]; -}; +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'writeFeatureObject', + ol.format.GeoJSON.prototype.writeFeatureObject); -goog.provide('ol.interaction.Snap'); -goog.provide('ol.interaction.SnapProperty'); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'writeFeatures', + ol.format.GeoJSON.prototype.writeFeatures); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Collection'); -goog.require('ol.CollectionEvent'); -goog.require('ol.CollectionEventType'); -goog.require('ol.Extent'); -goog.require('ol.Feature'); -goog.require('ol.Object'); -goog.require('ol.Observable'); -goog.require('ol.coordinate'); -goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); -goog.require('ol.interaction.Pointer'); -goog.require('ol.source.Vector'); -goog.require('ol.source.VectorEvent'); -goog.require('ol.source.VectorEventType'); -goog.require('ol.structs.RBush'); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'writeFeaturesObject', + ol.format.GeoJSON.prototype.writeFeaturesObject); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'writeGeometry', + ol.format.GeoJSON.prototype.writeGeometry); +goog.exportProperty( + ol.format.GeoJSON.prototype, + 'writeGeometryObject', + ol.format.GeoJSON.prototype.writeGeometryObject); -/** - * @classdesc - * Handles snapping of vector features while modifying or drawing them. The - * features can come from a {@link ol.source.Vector} or {@link ol.Collection} - * Any interaction object that allows the user to interact - * with the features using the mouse can benefit from the snapping, as long - * as it is added before. - * - * The snap interaction modifies map browser event `coordinate` and `pixel` - * properties to force the snap to occur to any interaction that them. - * - * Example: - * - * var snap = new ol.interaction.Snap({ - * source: source - * }); - * - * @constructor - * @extends {ol.interaction.Pointer} - * @param {olx.interaction.SnapOptions=} opt_options Options. - * @api - */ -ol.interaction.Snap = function(opt_options) { +goog.exportSymbol( + 'ol.format.GPX', + ol.format.GPX); - goog.base(this, { - handleEvent: ol.interaction.Snap.handleEvent_, - handleDownEvent: goog.functions.TRUE, - handleUpEvent: ol.interaction.Snap.handleUpEvent_ - }); +goog.exportProperty( + ol.format.GPX.prototype, + 'readFeature', + ol.format.GPX.prototype.readFeature); - var options = opt_options ? opt_options : {}; +goog.exportProperty( + ol.format.GPX.prototype, + 'readFeatures', + ol.format.GPX.prototype.readFeatures); - /** - * @type {ol.source.Vector} - * @private - */ - this.source_ = options.source ? options.source : null; +goog.exportProperty( + ol.format.GPX.prototype, + 'readProjection', + ol.format.GPX.prototype.readProjection); - /** - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features ? options.features : null; +goog.exportProperty( + ol.format.GPX.prototype, + 'writeFeatures', + ol.format.GPX.prototype.writeFeatures); - /** - * @type {Array.<goog.events.Key>} - * @private - */ - this.featuresListenerKeys_ = []; +goog.exportProperty( + ol.format.GPX.prototype, + 'writeFeaturesNode', + ol.format.GPX.prototype.writeFeaturesNode); - /** - * @type {Object.<number, goog.events.Key>} - * @private - */ - this.geometryChangeListenerKeys_ = {}; +goog.exportSymbol( + 'ol.format.IGC', + ol.format.IGC); - /** - * @type {Object.<number, goog.events.Key>} - * @private - */ - this.geometryModifyListenerKeys_ = {}; +goog.exportProperty( + ol.format.IGC.prototype, + 'readFeature', + ol.format.IGC.prototype.readFeature); - /** - * Extents are preserved so indexed segment can be quickly removed - * when its feature geometry changes - * @type {Object.<number, ol.Extent>} - * @private - */ - this.indexedFeaturesExtents_ = {}; +goog.exportProperty( + ol.format.IGC.prototype, + 'readFeatures', + ol.format.IGC.prototype.readFeatures); - /** - * If a feature geometry changes while a pointer drag|move event occurs, the - * feature doesn't get updated right away. It will be at the next 'pointerup' - * event fired. - * @type {Object.<number, ol.Feature>} - * @private - */ - this.pendingFeatures_ = {}; +goog.exportProperty( + ol.format.IGC.prototype, + 'readProjection', + ol.format.IGC.prototype.readProjection); - /** - * Used for distance sorting in sortByDistance_ - * @type {ol.Coordinate} - * @private - */ - this.pixelCoordinate_ = null; +goog.exportSymbol( + 'ol.format.KML', + ol.format.KML); - /** - * @type {number} - * @private - */ - this.pixelTolerance_ = options.pixelTolerance !== undefined ? - options.pixelTolerance : 10; +goog.exportProperty( + ol.format.KML.prototype, + 'readFeature', + ol.format.KML.prototype.readFeature); - /** - * @type {function(ol.interaction.Snap.SegmentDataType, ol.interaction.Snap.SegmentDataType): number} - * @private - */ - this.sortByDistance_ = goog.bind(ol.interaction.Snap.sortByDistance, this); +goog.exportProperty( + ol.format.KML.prototype, + 'readFeatures', + ol.format.KML.prototype.readFeatures); +goog.exportProperty( + ol.format.KML.prototype, + 'readName', + ol.format.KML.prototype.readName); - /** - * Segment RTree for each layer - * @type {ol.structs.RBush.<ol.interaction.Snap.SegmentDataType>} - * @private - */ - this.rBush_ = new ol.structs.RBush(); +goog.exportProperty( + ol.format.KML.prototype, + 'readNetworkLinks', + ol.format.KML.prototype.readNetworkLinks); +goog.exportProperty( + ol.format.KML.prototype, + 'readProjection', + ol.format.KML.prototype.readProjection); - /** - * @const - * @private - * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>} - */ - this.SEGMENT_WRITERS_ = { - 'Point': this.writePointGeometry_, - 'LineString': this.writeLineStringGeometry_, - 'LinearRing': this.writeLineStringGeometry_, - 'Polygon': this.writePolygonGeometry_, - 'MultiPoint': this.writeMultiPointGeometry_, - 'MultiLineString': this.writeMultiLineStringGeometry_, - 'MultiPolygon': this.writeMultiPolygonGeometry_, - 'GeometryCollection': this.writeGeometryCollectionGeometry_ - }; -}; -goog.inherits(ol.interaction.Snap, ol.interaction.Pointer); +goog.exportProperty( + ol.format.KML.prototype, + 'writeFeatures', + ol.format.KML.prototype.writeFeatures); +goog.exportProperty( + ol.format.KML.prototype, + 'writeFeaturesNode', + ol.format.KML.prototype.writeFeaturesNode); -/** - * Add a feature to the collection of features that we may snap to. - * @param {ol.Feature} feature Feature. - * @param {boolean=} opt_listen Whether to listen to the geometry change or not - * Defaults to `true`. - * @api - */ -ol.interaction.Snap.prototype.addFeature = function(feature, opt_listen) { - var listen = opt_listen !== undefined ? opt_listen : true; - var geometry = feature.getGeometry(); - var segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()]; - if (segmentWriter) { - var feature_uid = goog.getUid(feature); - this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent( - ol.extent.createEmpty()); - segmentWriter.call(this, feature, geometry); +goog.exportSymbol( + 'ol.format.MVT', + ol.format.MVT); - if (listen) { - this.geometryModifyListenerKeys_[feature_uid] = geometry.on( - goog.events.EventType.CHANGE, - goog.bind(this.handleGeometryModify_, this, feature), - this); - this.geometryChangeListenerKeys_[feature_uid] = feature.on( - ol.Object.getChangeEventType(feature.getGeometryName()), - this.handleGeometryChange_, this); - } - } -}; +goog.exportProperty( + ol.format.MVT.prototype, + 'setLayers', + ol.format.MVT.prototype.setLayers); +goog.exportSymbol( + 'ol.format.OSMXML', + ol.format.OSMXML); -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Snap.prototype.forEachFeatureAdd_ = function(feature) { - this.addFeature(feature); -}; +goog.exportProperty( + ol.format.OSMXML.prototype, + 'readFeatures', + ol.format.OSMXML.prototype.readFeatures); +goog.exportProperty( + ol.format.OSMXML.prototype, + 'readProjection', + ol.format.OSMXML.prototype.readProjection); -/** - * @param {ol.Feature} feature Feature. - * @private - */ -ol.interaction.Snap.prototype.forEachFeatureRemove_ = function(feature) { - this.removeFeature(feature); -}; +goog.exportSymbol( + 'ol.format.Polyline', + ol.format.Polyline); +goog.exportSymbol( + 'ol.format.Polyline.encodeDeltas', + ol.format.Polyline.encodeDeltas); -/** - * @return {ol.Collection.<ol.Feature>|Array.<ol.Feature>} - * @private - */ -ol.interaction.Snap.prototype.getFeatures_ = function() { - var features; - if (this.features_) { - features = this.features_; - } else if (this.source_) { - features = this.source_.getFeatures(); - } - goog.asserts.assert(features !== undefined, 'features should be defined'); - return features; -}; +goog.exportSymbol( + 'ol.format.Polyline.decodeDeltas', + ol.format.Polyline.decodeDeltas); +goog.exportSymbol( + 'ol.format.Polyline.encodeFloats', + ol.format.Polyline.encodeFloats); -/** - * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleFeatureAdd_ = function(evt) { - var feature; - if (evt instanceof ol.source.VectorEvent) { - feature = evt.feature; - } else if (evt instanceof ol.CollectionEvent) { - feature = evt.element; - } - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - this.addFeature(feature); -}; +goog.exportSymbol( + 'ol.format.Polyline.decodeFloats', + ol.format.Polyline.decodeFloats); +goog.exportProperty( + ol.format.Polyline.prototype, + 'readFeature', + ol.format.Polyline.prototype.readFeature); -/** - * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleFeatureRemove_ = function(evt) { - var feature; - if (evt instanceof ol.source.VectorEvent) { - feature = evt.feature; - } else if (evt instanceof ol.CollectionEvent) { - feature = evt.element; - } - goog.asserts.assertInstanceof(feature, ol.Feature, - 'feature should be an ol.Feature'); - this.removeFeature(feature); -}; +goog.exportProperty( + ol.format.Polyline.prototype, + 'readFeatures', + ol.format.Polyline.prototype.readFeatures); +goog.exportProperty( + ol.format.Polyline.prototype, + 'readGeometry', + ol.format.Polyline.prototype.readGeometry); -/** - * @param {goog.events.Event} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleGeometryChange_ = function(evt) { - var feature = evt.currentTarget; - goog.asserts.assertInstanceof(feature, ol.Feature); - this.removeFeature(feature, true); - this.addFeature(feature, true); -}; +goog.exportProperty( + ol.format.Polyline.prototype, + 'readProjection', + ol.format.Polyline.prototype.readProjection); +goog.exportProperty( + ol.format.Polyline.prototype, + 'writeGeometry', + ol.format.Polyline.prototype.writeGeometry); -/** - * @param {ol.Feature} feature Feature which geometry was modified. - * @param {goog.events.Event} evt Event. - * @private - */ -ol.interaction.Snap.prototype.handleGeometryModify_ = function(feature, evt) { - if (this.handlingDownUpSequence) { - var uid = goog.getUid(feature); - if (!(uid in this.pendingFeatures_)) { - this.pendingFeatures_[uid] = feature; - } - } else { - this.updateFeature_(feature); - } -}; +goog.exportSymbol( + 'ol.format.TopoJSON', + ol.format.TopoJSON); +goog.exportProperty( + ol.format.TopoJSON.prototype, + 'readFeatures', + ol.format.TopoJSON.prototype.readFeatures); -/** - * Remove a feature from the collection of features that we may snap to. - * @param {ol.Feature} feature Feature - * @param {boolean=} opt_unlisten Whether to unlisten to the geometry change - * or not. Defaults to `true`. - * @api - */ -ol.interaction.Snap.prototype.removeFeature = function(feature, opt_unlisten) { - var unlisten = opt_unlisten !== undefined ? opt_unlisten : true; - var feature_uid = goog.getUid(feature); - var extent = this.indexedFeaturesExtents_[feature_uid]; - if (extent) { - var rBush = this.rBush_; - var i, nodesToRemove = []; - rBush.forEachInExtent(extent, function(node) { - if (feature === node.feature) { - nodesToRemove.push(node); - } - }); - for (i = nodesToRemove.length - 1; i >= 0; --i) { - rBush.remove(nodesToRemove[i]); - } - if (unlisten) { - ol.Observable.unByKey(this.geometryModifyListenerKeys_[feature_uid]); - delete this.geometryModifyListenerKeys_[feature_uid]; +goog.exportProperty( + ol.format.TopoJSON.prototype, + 'readProjection', + ol.format.TopoJSON.prototype.readProjection); + +goog.exportSymbol( + 'ol.format.WFS', + ol.format.WFS); + +goog.exportProperty( + ol.format.WFS.prototype, + 'readFeatures', + ol.format.WFS.prototype.readFeatures); - ol.Observable.unByKey(this.geometryChangeListenerKeys_[feature_uid]); - delete this.geometryChangeListenerKeys_[feature_uid]; - } - } -}; +goog.exportProperty( + ol.format.WFS.prototype, + 'readTransactionResponse', + ol.format.WFS.prototype.readTransactionResponse); +goog.exportProperty( + ol.format.WFS.prototype, + 'readFeatureCollectionMetadata', + ol.format.WFS.prototype.readFeatureCollectionMetadata); -/** - * @inheritDoc - */ -ol.interaction.Snap.prototype.setMap = function(map) { - var currentMap = this.getMap(); - var keys = this.featuresListenerKeys_; - var features = this.getFeatures_(); +goog.exportProperty( + ol.format.WFS.prototype, + 'writeGetFeature', + ol.format.WFS.prototype.writeGetFeature); - if (currentMap) { - keys.forEach(ol.Observable.unByKey); - keys.length = 0; - features.forEach(this.forEachFeatureRemove_, this); - } +goog.exportProperty( + ol.format.WFS.prototype, + 'writeTransaction', + ol.format.WFS.prototype.writeTransaction); - goog.base(this, 'setMap', map); +goog.exportProperty( + ol.format.WFS.prototype, + 'readProjection', + ol.format.WFS.prototype.readProjection); - if (map) { - if (this.features_) { - keys.push(this.features_.on(ol.CollectionEventType.ADD, - this.handleFeatureAdd_, this)); - keys.push(this.features_.on(ol.CollectionEventType.REMOVE, - this.handleFeatureRemove_, this)); - } else if (this.source_) { - keys.push(this.source_.on(ol.source.VectorEventType.ADDFEATURE, - this.handleFeatureAdd_, this)); - keys.push(this.source_.on(ol.source.VectorEventType.REMOVEFEATURE, - this.handleFeatureRemove_, this)); - } - features.forEach(this.forEachFeatureAdd_, this); - } -}; +goog.exportSymbol( + 'ol.format.WKT', + ol.format.WKT); +goog.exportProperty( + ol.format.WKT.prototype, + 'readFeature', + ol.format.WKT.prototype.readFeature); -/** - * @inheritDoc - */ -ol.interaction.Snap.prototype.shouldStopEvent = goog.functions.FALSE; +goog.exportProperty( + ol.format.WKT.prototype, + 'readFeatures', + ol.format.WKT.prototype.readFeatures); +goog.exportProperty( + ol.format.WKT.prototype, + 'readGeometry', + ol.format.WKT.prototype.readGeometry); -/** - * @param {ol.Pixel} pixel Pixel - * @param {ol.Coordinate} pixelCoordinate Coordinate - * @param {ol.Map} map Map. - * @return {ol.interaction.Snap.ResultType} Snap result - */ -ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) { +goog.exportProperty( + ol.format.WKT.prototype, + 'writeFeature', + ol.format.WKT.prototype.writeFeature); - var lowerLeft = map.getCoordinateFromPixel( - [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]); - var upperRight = map.getCoordinateFromPixel( - [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]); - var box = ol.extent.boundingExtent([lowerLeft, upperRight]); +goog.exportProperty( + ol.format.WKT.prototype, + 'writeFeatures', + ol.format.WKT.prototype.writeFeatures); - var segments = this.rBush_.getInExtent(box); - var snappedToVertex = false; - var snapped = false; - var vertex = null; - var vertexPixel = null; - if (segments.length > 0) { - this.pixelCoordinate_ = pixelCoordinate; - segments.sort(this.sortByDistance_); - var closestSegment = segments[0].segment; - vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, - closestSegment)); - vertexPixel = map.getPixelFromCoordinate(vertex); - if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= - this.pixelTolerance_) { - snapped = true; - var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); - var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); - var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); - var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); - var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); - snappedToVertex = dist <= this.pixelTolerance_; - if (snappedToVertex) { - vertex = squaredDist1 > squaredDist2 ? - closestSegment[1] : closestSegment[0]; - vertexPixel = map.getPixelFromCoordinate(vertex); - vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])]; - } - } - } - return /** @type {ol.interaction.Snap.ResultType} */ ({ - snapped: snapped, - vertex: vertex, - vertexPixel: vertexPixel - }); -}; +goog.exportProperty( + ol.format.WKT.prototype, + 'writeGeometry', + ol.format.WKT.prototype.writeGeometry); +goog.exportSymbol( + 'ol.format.WMSCapabilities', + ol.format.WMSCapabilities); -/** - * @param {ol.Feature} feature Feature - * @private - */ -ol.interaction.Snap.prototype.updateFeature_ = function(feature) { - this.removeFeature(feature, false); - this.addFeature(feature, false); -}; +goog.exportProperty( + ol.format.WMSCapabilities.prototype, + 'read', + ol.format.WMSCapabilities.prototype.read); +goog.exportSymbol( + 'ol.format.WMSGetFeatureInfo', + ol.format.WMSGetFeatureInfo); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.GeometryCollection} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeGeometryCollectionGeometry_ = - function(feature, geometry) { - var i, geometries = geometry.getGeometriesArray(); - for (i = 0; i < geometries.length; ++i) { - this.SEGMENT_WRITERS_[geometries[i].getType()].call( - this, feature, geometries[i]); - } -}; +goog.exportProperty( + ol.format.WMSGetFeatureInfo.prototype, + 'readFeatures', + ol.format.WMSGetFeatureInfo.prototype.readFeatures); +goog.exportSymbol( + 'ol.format.WMTSCapabilities', + ol.format.WMTSCapabilities); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.LineString} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeLineStringGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var i, ii, segment, segmentData; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } -}; +goog.exportProperty( + ol.format.WMTSCapabilities.prototype, + 'read', + ol.format.WMTSCapabilities.prototype.read); +goog.exportSymbol( + 'ol.format.GML2', + ol.format.GML2); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiLineString} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeMultiLineStringGeometry_ = - function(feature, geometry) { - var lines = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = lines.length; j < jj; ++j) { - coordinates = lines[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; +goog.exportSymbol( + 'ol.format.GML3', + ol.format.GML3); +goog.exportProperty( + ol.format.GML3.prototype, + 'writeGeometryNode', + ol.format.GML3.prototype.writeGeometryNode); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPoint} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeMultiPointGeometry_ = - function(feature, geometry) { - var points = geometry.getCoordinates(); - var coordinates, i, ii, segmentData; - for (i = 0, ii = points.length; i < ii; ++i) { - coordinates = points[i]; - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); - } -}; +goog.exportProperty( + ol.format.GML3.prototype, + 'writeFeatures', + ol.format.GML3.prototype.writeFeatures); +goog.exportProperty( + ol.format.GML3.prototype, + 'writeFeaturesNode', + ol.format.GML3.prototype.writeFeaturesNode); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.MultiPolygon} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writeMultiPolygonGeometry_ = - function(feature, geometry) { - var polygons = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData; - for (k = 0, kk = polygons.length; k < kk; ++k) { - rings = polygons[k]; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } - } -}; +goog.exportSymbol( + 'ol.format.GML', + ol.format.GML); +goog.exportProperty( + ol.format.GML.prototype, + 'writeFeatures', + ol.format.GML.prototype.writeFeatures); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Point} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writePointGeometry_ = - function(feature, geometry) { - var coordinates = geometry.getCoordinates(); - var segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: [coordinates, coordinates] - }); - this.rBush_.insert(geometry.getExtent(), segmentData); -}; +goog.exportProperty( + ol.format.GML.prototype, + 'writeFeaturesNode', + ol.format.GML.prototype.writeFeaturesNode); +goog.exportProperty( + ol.format.GMLBase.prototype, + 'readFeatures', + ol.format.GMLBase.prototype.readFeatures); -/** - * @param {ol.Feature} feature Feature - * @param {ol.geom.Polygon} geometry Geometry. - * @private - */ -ol.interaction.Snap.prototype.writePolygonGeometry_ = - function(feature, geometry) { - var rings = geometry.getCoordinates(); - var coordinates, i, ii, j, jj, segment, segmentData; - for (j = 0, jj = rings.length; j < jj; ++j) { - coordinates = rings[j]; - for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { - segment = coordinates.slice(i, i + 2); - segmentData = /** @type {ol.interaction.Snap.SegmentDataType} */ ({ - feature: feature, - segment: segment - }); - this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData); - } - } -}; +goog.exportSymbol( + 'ol.events.condition.altKeyOnly', + ol.events.condition.altKeyOnly); +goog.exportSymbol( + 'ol.events.condition.altShiftKeysOnly', + ol.events.condition.altShiftKeysOnly); -/** - * @typedef {{ - * snapped: {boolean}, - * vertex: (ol.Coordinate|null), - * vertexPixel: (ol.Pixel|null) - * }} - */ -ol.interaction.Snap.ResultType; +goog.exportSymbol( + 'ol.events.condition.always', + ol.events.condition.always); +goog.exportSymbol( + 'ol.events.condition.click', + ol.events.condition.click); -/** - * @typedef {{ - * feature: ol.Feature, - * segment: Array.<ol.Coordinate> - * }} - */ -ol.interaction.Snap.SegmentDataType; +goog.exportSymbol( + 'ol.events.condition.never', + ol.events.condition.never); +goog.exportSymbol( + 'ol.events.condition.pointerMove', + ol.events.condition.pointerMove); -/** - * Handle all pointer events events. - * @param {ol.MapBrowserEvent} evt A move event. - * @return {boolean} Pass the event to other interactions. - * @this {ol.interaction.Snap} - * @private - */ -ol.interaction.Snap.handleEvent_ = function(evt) { - var result = this.snapTo(evt.pixel, evt.coordinate, evt.map); - if (result.snapped) { - evt.coordinate = result.vertex.slice(0, 2); - evt.pixel = result.vertexPixel; - } - return ol.interaction.Pointer.handleEvent.call(this, evt); -}; +goog.exportSymbol( + 'ol.events.condition.singleClick', + ol.events.condition.singleClick); +goog.exportSymbol( + 'ol.events.condition.doubleClick', + ol.events.condition.doubleClick); -/** - * @param {ol.MapBrowserPointerEvent} evt Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Snap} - * @private - */ -ol.interaction.Snap.handleUpEvent_ = function(evt) { - var featuresToUpdate = goog.object.getValues(this.pendingFeatures_); - if (featuresToUpdate.length) { - featuresToUpdate.forEach(this.updateFeature_, this); - this.pendingFeatures_ = {}; - } - return false; -}; +goog.exportSymbol( + 'ol.events.condition.noModifierKeys', + ol.events.condition.noModifierKeys); +goog.exportSymbol( + 'ol.events.condition.platformModifierKeyOnly', + ol.events.condition.platformModifierKeyOnly); -/** - * Sort segments by distance, helper function - * @param {ol.interaction.Snap.SegmentDataType} a - * @param {ol.interaction.Snap.SegmentDataType} b - * @return {number} - * @this {ol.interaction.Snap} - */ -ol.interaction.Snap.sortByDistance = function(a, b) { - return ol.coordinate.squaredDistanceToSegment( - this.pixelCoordinate_, a.segment) - - ol.coordinate.squaredDistanceToSegment( - this.pixelCoordinate_, b.segment); -}; +goog.exportSymbol( + 'ol.events.condition.shiftKeyOnly', + ol.events.condition.shiftKeyOnly); -goog.provide('ol.interaction.Translate'); -goog.provide('ol.interaction.TranslateEvent'); +goog.exportSymbol( + 'ol.events.condition.targetNotEditable', + ol.events.condition.targetNotEditable); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('ol.array'); -goog.require('ol.interaction.Pointer'); +goog.exportSymbol( + 'ol.events.condition.mouseOnly', + ol.events.condition.mouseOnly); +goog.exportSymbol( + 'ol.control.Attribution', + ol.control.Attribution); -/** - * @enum {string} - */ -ol.interaction.TranslateEventType = { - /** - * Triggered upon feature translation start. - * @event ol.interaction.TranslateEvent#translatestart - * @api - */ - TRANSLATESTART: 'translatestart', - /** - * Triggered upon feature translation. - * @event ol.interaction.TranslateEvent#translating - * @api - */ - TRANSLATING: 'translating', - /** - * Triggered upon feature translation end. - * @event ol.interaction.TranslateEvent#translateend - * @api - */ - TRANSLATEEND: 'translateend' -}; +goog.exportSymbol( + 'ol.control.Attribution.render', + ol.control.Attribution.render); +goog.exportProperty( + ol.control.Attribution.prototype, + 'getCollapsible', + ol.control.Attribution.prototype.getCollapsible); +goog.exportProperty( + ol.control.Attribution.prototype, + 'setCollapsible', + ol.control.Attribution.prototype.setCollapsible); -/** - * @classdesc - * Events emitted by {@link ol.interaction.Translate} instances are instances of - * this type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.interaction.TranslateEvent} - * @param {ol.interaction.TranslateEventType} type Type. - * @param {ol.Collection.<ol.Feature>} features The features translated. - * @param {ol.Coordinate} coordinate The event coordinate. - */ -ol.interaction.TranslateEvent = function(type, features, coordinate) { +goog.exportProperty( + ol.control.Attribution.prototype, + 'setCollapsed', + ol.control.Attribution.prototype.setCollapsed); - goog.base(this, type); +goog.exportProperty( + ol.control.Attribution.prototype, + 'getCollapsed', + ol.control.Attribution.prototype.getCollapsed); - /** - * The features being translated. - * @type {ol.Collection.<ol.Feature>} - * @api - */ - this.features = features; +goog.exportSymbol( + 'ol.control.Control', + ol.control.Control); - /** - * The coordinate of the drag event. - * @const - * @type {ol.Coordinate} - * @api - */ - this.coordinate = coordinate; -}; -goog.inherits(ol.interaction.TranslateEvent, goog.events.Event); +goog.exportProperty( + ol.control.Control.prototype, + 'getMap', + ol.control.Control.prototype.getMap); +goog.exportProperty( + ol.control.Control.prototype, + 'setMap', + ol.control.Control.prototype.setMap); +goog.exportProperty( + ol.control.Control.prototype, + 'setTarget', + ol.control.Control.prototype.setTarget); -/** - * @classdesc - * Interaction for translating (moving) features. - * - * @constructor - * @extends {ol.interaction.Pointer} - * @fires ol.interaction.TranslateEvent - * @param {olx.interaction.TranslateOptions} options Options. - * @api - */ -ol.interaction.Translate = function(options) { - goog.base(this, { - handleDownEvent: ol.interaction.Translate.handleDownEvent_, - handleDragEvent: ol.interaction.Translate.handleDragEvent_, - handleMoveEvent: ol.interaction.Translate.handleMoveEvent_, - handleUpEvent: ol.interaction.Translate.handleUpEvent_ - }); +goog.exportSymbol( + 'ol.control.defaults', + ol.control.defaults); +goog.exportSymbol( + 'ol.control.FullScreen', + ol.control.FullScreen); - /** - * @type {string|undefined} - * @private - */ - this.previousCursor_ = undefined; +goog.exportSymbol( + 'ol.control.MousePosition', + ol.control.MousePosition); +goog.exportSymbol( + 'ol.control.MousePosition.render', + ol.control.MousePosition.render); - /** - * The last position we translated to. - * @type {ol.Coordinate} - * @private - */ - this.lastCoordinate_ = null; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'getCoordinateFormat', + ol.control.MousePosition.prototype.getCoordinateFormat); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'getProjection', + ol.control.MousePosition.prototype.getProjection); - /** - * @type {ol.Collection.<ol.Feature>} - * @private - */ - this.features_ = options.features !== undefined ? options.features : null; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'setMap', + ol.control.MousePosition.prototype.setMap); - /** - * @type {ol.Feature} - * @private - */ - this.lastFeature_ = null; -}; -goog.inherits(ol.interaction.Translate, ol.interaction.Pointer); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'setCoordinateFormat', + ol.control.MousePosition.prototype.setCoordinateFormat); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'setProjection', + ol.control.MousePosition.prototype.setProjection); -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Start drag sequence? - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleDownEvent_ = function(event) { - this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map); - if (!this.lastCoordinate_ && this.lastFeature_) { - this.lastCoordinate_ = event.coordinate; - ol.interaction.Translate.handleMoveEvent_.call(this, event); - this.dispatchEvent( - new ol.interaction.TranslateEvent( - ol.interaction.TranslateEventType.TRANSLATESTART, this.features_, - event.coordinate)); - return true; - } - return false; -}; +goog.exportSymbol( + 'ol.control.OverviewMap', + ol.control.OverviewMap); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'setMap', + ol.control.OverviewMap.prototype.setMap); -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @return {boolean} Stop drag sequence? - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleUpEvent_ = function(event) { - if (this.lastCoordinate_) { - this.lastCoordinate_ = null; - ol.interaction.Translate.handleMoveEvent_.call(this, event); - this.dispatchEvent( - new ol.interaction.TranslateEvent( - ol.interaction.TranslateEventType.TRANSLATEEND, this.features_, - event.coordinate)); - return true; - } - return false; -}; +goog.exportSymbol( + 'ol.control.OverviewMap.render', + ol.control.OverviewMap.render); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getCollapsible', + ol.control.OverviewMap.prototype.getCollapsible); -/** - * @param {ol.MapBrowserPointerEvent} event Event. - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleDragEvent_ = function(event) { - if (this.lastCoordinate_) { - var newCoordinate = event.coordinate; - var deltaX = newCoordinate[0] - this.lastCoordinate_[0]; - var deltaY = newCoordinate[1] - this.lastCoordinate_[1]; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'setCollapsible', + ol.control.OverviewMap.prototype.setCollapsible); + +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'setCollapsed', + ol.control.OverviewMap.prototype.setCollapsed); + +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getCollapsed', + ol.control.OverviewMap.prototype.getCollapsed); + +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getOverviewMap', + ol.control.OverviewMap.prototype.getOverviewMap); + +goog.exportSymbol( + 'ol.control.Rotate', + ol.control.Rotate); + +goog.exportSymbol( + 'ol.control.Rotate.render', + ol.control.Rotate.render); + +goog.exportSymbol( + 'ol.control.ScaleLine', + ol.control.ScaleLine); + +goog.exportProperty( + ol.control.ScaleLine.prototype, + 'getUnits', + ol.control.ScaleLine.prototype.getUnits); + +goog.exportSymbol( + 'ol.control.ScaleLine.render', + ol.control.ScaleLine.render); + +goog.exportProperty( + ol.control.ScaleLine.prototype, + 'setUnits', + ol.control.ScaleLine.prototype.setUnits); + +goog.exportSymbol( + 'ol.control.Zoom', + ol.control.Zoom); + +goog.exportSymbol( + 'ol.control.ZoomSlider', + ol.control.ZoomSlider); + +goog.exportSymbol( + 'ol.control.ZoomSlider.render', + ol.control.ZoomSlider.render); - if (this.features_) { - this.features_.forEach(function(feature) { - var geom = feature.getGeometry(); - geom.translate(deltaX, deltaY); - feature.setGeometry(geom); - }); - } else if (this.lastFeature_) { - var geom = this.lastFeature_.getGeometry(); - geom.translate(deltaX, deltaY); - this.lastFeature_.setGeometry(geom); - } +goog.exportSymbol( + 'ol.control.ZoomToExtent', + ol.control.ZoomToExtent); - this.lastCoordinate_ = newCoordinate; - this.dispatchEvent( - new ol.interaction.TranslateEvent( - ol.interaction.TranslateEventType.TRANSLATING, this.features_, - newCoordinate)); - } -}; +goog.exportSymbol( + 'ol.color.asArray', + ol.color.asArray); +goog.exportSymbol( + 'ol.color.asString', + ol.color.asString); -/** - * @param {ol.MapBrowserEvent} event Event. - * @this {ol.interaction.Translate} - * @private - */ -ol.interaction.Translate.handleMoveEvent_ = function(event) - { - var elem = event.map.getTargetElement(); - var intersectingFeature = event.map.forEachFeatureAtPixel(event.pixel, - function(feature) { - return feature; - }); +goog.exportSymbol( + 'olcs.AbstractSynchronizer', + olcs.AbstractSynchronizer); - if (intersectingFeature) { - var isSelected = false; +goog.exportProperty( + olcs.AbstractSynchronizer.prototype, + 'synchronize', + olcs.AbstractSynchronizer.prototype.synchronize); - if (this.features_ && - ol.array.includes(this.features_.getArray(), intersectingFeature)) { - isSelected = true; - } +goog.exportProperty( + olcs.AutoRenderLoop.prototype, + 'restartRenderLoop', + olcs.AutoRenderLoop.prototype.restartRenderLoop); - this.previousCursor_ = elem.style.cursor; +goog.exportProperty( + olcs.AutoRenderLoop.prototype, + 'setDebug', + olcs.AutoRenderLoop.prototype.setDebug); - // WebKit browsers don't support the grab icons without a prefix - elem.style.cursor = this.lastCoordinate_ ? - '-webkit-grabbing' : (isSelected ? '-webkit-grab' : 'pointer'); +goog.exportSymbol( + 'olcs.Camera', + olcs.Camera); - // Thankfully, attempting to set the standard ones will silently fail, - // keeping the prefixed icons - elem.style.cursor = !this.lastCoordinate_ ? - 'grabbing' : (isSelected ? 'grab' : 'pointer'); +goog.exportProperty( + olcs.Camera.prototype, + 'setHeading', + olcs.Camera.prototype.setHeading); - } else { - elem.style.cursor = this.previousCursor_ !== undefined ? - this.previousCursor_ : ''; - this.previousCursor_ = undefined; - } -}; +goog.exportProperty( + olcs.Camera.prototype, + 'getHeading', + olcs.Camera.prototype.getHeading); +goog.exportProperty( + olcs.Camera.prototype, + 'setTilt', + olcs.Camera.prototype.setTilt); -/** - * Tests to see if the given coordinates intersects any of our selected - * features. - * @param {ol.Pixel} pixel Pixel coordinate to test for intersection. - * @param {ol.Map} map Map to test the intersection on. - * @return {ol.Feature} Returns the feature found at the specified pixel - * coordinates. - * @private - */ -ol.interaction.Translate.prototype.featuresAtPixel_ = function(pixel, map) { - var found = null; +goog.exportProperty( + olcs.Camera.prototype, + 'getTilt', + olcs.Camera.prototype.getTilt); - var intersectingFeature = map.forEachFeatureAtPixel(pixel, - function(feature) { - return feature; - }); +goog.exportProperty( + olcs.Camera.prototype, + 'setDistance', + olcs.Camera.prototype.setDistance); - if (this.features_ && - ol.array.includes(this.features_.getArray(), intersectingFeature)) { - found = intersectingFeature; - } +goog.exportProperty( + olcs.Camera.prototype, + 'getDistance', + olcs.Camera.prototype.getDistance); - return found; -}; +goog.exportProperty( + olcs.Camera.prototype, + 'setCenter', + olcs.Camera.prototype.setCenter); -goog.provide('ol.layer.Heatmap'); +goog.exportProperty( + olcs.Camera.prototype, + 'getCenter', + olcs.Camera.prototype.getCenter); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.object'); -goog.require('ol'); -goog.require('ol.Object'); -goog.require('ol.dom'); -goog.require('ol.layer.Vector'); -goog.require('ol.math'); -goog.require('ol.render.EventType'); -goog.require('ol.style.Icon'); -goog.require('ol.style.Style'); +goog.exportProperty( + olcs.Camera.prototype, + 'setPosition', + olcs.Camera.prototype.setPosition); +goog.exportProperty( + olcs.Camera.prototype, + 'getPosition', + olcs.Camera.prototype.getPosition); -/** - * @enum {string} - */ -ol.layer.HeatmapLayerProperty = { - BLUR: 'blur', - GRADIENT: 'gradient', - RADIUS: 'radius' -}; +goog.exportProperty( + olcs.Camera.prototype, + 'setAltitude', + olcs.Camera.prototype.setAltitude); +goog.exportProperty( + olcs.Camera.prototype, + 'getAltitude', + olcs.Camera.prototype.getAltitude); +goog.exportProperty( + olcs.Camera.prototype, + 'lookAt', + olcs.Camera.prototype.lookAt); -/** - * @classdesc - * Layer for rendering vector data as a heatmap. - * Note that any property set in the options is set as a {@link ol.Object} - * property on the layer object; for example, setting `title: 'My Title'` in the - * options means that `title` is observable, and has get/set accessors. - * - * @constructor - * @extends {ol.layer.Vector} - * @fires ol.render.Event - * @param {olx.layer.HeatmapOptions=} opt_options Options. - * @api - */ -ol.layer.Heatmap = function(opt_options) { - var options = opt_options ? opt_options : {}; +goog.exportProperty( + olcs.Camera.prototype, + 'readFromView', + olcs.Camera.prototype.readFromView); - var baseOptions = goog.object.clone(options); +goog.exportProperty( + olcs.Camera.prototype, + 'updateView', + olcs.Camera.prototype.updateView); - delete baseOptions.gradient; - delete baseOptions.radius; - delete baseOptions.blur; - delete baseOptions.shadow; - delete baseOptions.weight; - goog.base(this, /** @type {olx.layer.VectorOptions} */ (baseOptions)); +goog.exportSymbol( + 'olcs.core.computePixelSizeAtCoordinate', + olcs.core.computePixelSizeAtCoordinate); - /** - * @private - * @type {Uint8ClampedArray} - */ - this.gradient_ = null; +goog.exportSymbol( + 'olcs.core.applyHeightOffsetToGeometry', + olcs.core.applyHeightOffsetToGeometry); - /** - * @private - * @type {number} - */ - this.shadow_ = options.shadow !== undefined ? options.shadow : 250; +goog.exportSymbol( + 'olcs.core.rotateAroundAxis', + olcs.core.rotateAroundAxis); - /** - * @private - * @type {string|undefined} - */ - this.circleImage_ = undefined; +goog.exportSymbol( + 'olcs.core.setHeadingUsingBottomCenter', + olcs.core.setHeadingUsingBottomCenter); - /** - * @private - * @type {Array.<Array.<ol.style.Style>>} - */ - this.styleCache_ = null; +goog.exportSymbol( + 'olcs.core.pickOnTerrainOrEllipsoid', + olcs.core.pickOnTerrainOrEllipsoid); - goog.events.listen(this, - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT), - this.handleGradientChanged_, false, this); +goog.exportSymbol( + 'olcs.core.pickBottomPoint', + olcs.core.pickBottomPoint); - this.setGradient(options.gradient ? - options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT); +goog.exportSymbol( + 'olcs.core.pickCenterPoint', + olcs.core.pickCenterPoint); - this.setBlur(options.blur !== undefined ? options.blur : 15); +goog.exportSymbol( + 'olcs.core.computeSignedTiltAngleOnGlobe', + olcs.core.computeSignedTiltAngleOnGlobe); - this.setRadius(options.radius !== undefined ? options.radius : 8); +goog.exportSymbol( + 'olcs.core.computeAngleToZenith', + olcs.core.computeAngleToZenith); - goog.events.listen(this, [ - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.BLUR), - ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.RADIUS) - ], this.handleStyleChanged_, false, this); +goog.exportSymbol( + 'olcs.core.lookAt', + olcs.core.lookAt); - this.handleStyleChanged_(); +goog.exportSymbol( + 'olcs.core.extentToRectangle', + olcs.core.extentToRectangle); - var weight = options.weight ? options.weight : 'weight'; - var weightFunction; - if (goog.isString(weight)) { - weightFunction = function(feature) { - return feature.get(weight); - }; - } else { - weightFunction = weight; - } - goog.asserts.assert(goog.isFunction(weightFunction), - 'weightFunction should be a function'); +goog.exportSymbol( + 'olcs.core.tileLayerToImageryLayer', + olcs.core.tileLayerToImageryLayer); - this.setStyle(goog.bind(function(feature, resolution) { - goog.asserts.assert(this.styleCache_, 'this.styleCache_ expected'); - goog.asserts.assert(this.circleImage_ !== undefined, - 'this.circleImage_ should be defined'); - var weight = weightFunction(feature); - var opacity = weight !== undefined ? ol.math.clamp(weight, 0, 1) : 1; - // cast to 8 bits - var index = (255 * opacity) | 0; - var style = this.styleCache_[index]; - if (!style) { - style = [ - new ol.style.Style({ - image: new ol.style.Icon({ - opacity: opacity, - src: this.circleImage_ - }) - }) - ]; - this.styleCache_[index] = style; - } - return style; - }, this)); +goog.exportSymbol( + 'olcs.core.updateCesiumLayerProperties', + olcs.core.updateCesiumLayerProperties); - // For performance reasons, don't sort the features before rendering. - // The render order is not relevant for a heatmap representation. - this.setRenderOrder(null); +goog.exportSymbol( + 'olcs.core.ol4326CoordinateToCesiumCartesian', + olcs.core.ol4326CoordinateToCesiumCartesian); - goog.events.listen(this, ol.render.EventType.RENDER, - this.handleRender_, false, this); +goog.exportSymbol( + 'olcs.core.ol4326CoordinateArrayToCsCartesians', + olcs.core.ol4326CoordinateArrayToCsCartesians); -}; -goog.inherits(ol.layer.Heatmap, ol.layer.Vector); +goog.exportSymbol( + 'olcs.core.olGeometryCloneTo4326', + olcs.core.olGeometryCloneTo4326); +goog.exportSymbol( + 'olcs.core.convertColorToCesium', + olcs.core.convertColorToCesium); -/** - * @const - * @type {Array.<string>} - */ -ol.layer.Heatmap.DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00']; +goog.exportSymbol( + 'olcs.DragBox', + olcs.DragBox); +goog.exportProperty( + olcs.DragBox.prototype, + 'setScene', + olcs.DragBox.prototype.setScene); -/** - * @param {Array.<string>} colors - * @return {Uint8ClampedArray} - * @private - */ -ol.layer.Heatmap.createGradient_ = function(colors) { - var width = 1; - var height = 256; - var context = ol.dom.createCanvasContext2D(width, height); +goog.exportProperty( + olcs.DragBox.prototype, + 'listen', + olcs.DragBox.prototype.listen); - var gradient = context.createLinearGradient(0, 0, width, height); - var step = 1 / (colors.length - 1); - for (var i = 0, ii = colors.length; i < ii; ++i) { - gradient.addColorStop(i * step, colors[i]); - } +goog.exportSymbol( + 'olcs.FeatureConverter', + olcs.FeatureConverter); - context.fillStyle = gradient; - context.fillRect(0, 0, width, height); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'csAddBillboard', + olcs.FeatureConverter.prototype.csAddBillboard); - return context.getImageData(0, 0, width, height).data; -}; +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olCircleGeometryToCesium', + olcs.FeatureConverter.prototype.olCircleGeometryToCesium); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olLineStringGeometryToCesium', + olcs.FeatureConverter.prototype.olLineStringGeometryToCesium); -/** - * @return {string} - * @private - */ -ol.layer.Heatmap.prototype.createCircle_ = function() { - var radius = this.getRadius(); - var blur = this.getBlur(); - goog.asserts.assert(radius !== undefined && blur !== undefined, - 'radius and blur should be defined'); - var halfSize = radius + blur + 1; - var size = 2 * halfSize; - var context = ol.dom.createCanvasContext2D(size, size); - context.shadowOffsetX = context.shadowOffsetY = this.shadow_; - context.shadowBlur = blur; - context.shadowColor = '#000'; - context.beginPath(); - var center = halfSize - this.shadow_; - context.arc(center, center, radius, 0, Math.PI * 2, true); - context.fill(); - return context.canvas.toDataURL(); -}; +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olPolygonGeometryToCesium', + olcs.FeatureConverter.prototype.olPolygonGeometryToCesium); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'getHeightReference', + olcs.FeatureConverter.prototype.getHeightReference); -/** - * Return the blur size in pixels. - * @return {number} Blur size in pixels. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.getBlur = function() { - return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.BLUR)); -}; +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olPointGeometryToCesium', + olcs.FeatureConverter.prototype.olPointGeometryToCesium); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olMultiGeometryToCesium', + olcs.FeatureConverter.prototype.olMultiGeometryToCesium); -/** - * Return the gradient colors as array of strings. - * @return {Array.<string>} Colors. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.getGradient = function() { - return /** @type {Array.<string>} */ ( - this.get(ol.layer.HeatmapLayerProperty.GRADIENT)); -}; +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olGeometry4326TextPartToCesium', + olcs.FeatureConverter.prototype.olGeometry4326TextPartToCesium); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olStyleToCesium', + olcs.FeatureConverter.prototype.olStyleToCesium); -/** - * Return the size of the radius in pixels. - * @return {number} Radius size in pixel. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.getRadius = function() { - return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.RADIUS)); -}; +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'computePlainStyle', + olcs.FeatureConverter.prototype.computePlainStyle); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olFeatureToCesium', + olcs.FeatureConverter.prototype.olFeatureToCesium); -/** - * @private - */ -ol.layer.Heatmap.prototype.handleGradientChanged_ = function() { - this.gradient_ = ol.layer.Heatmap.createGradient_(this.getGradient()); -}; +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'olVectorLayerToCesium', + olcs.FeatureConverter.prototype.olVectorLayerToCesium); +goog.exportProperty( + olcs.FeatureConverter.prototype, + 'convert', + olcs.FeatureConverter.prototype.convert); -/** - * @private - */ -ol.layer.Heatmap.prototype.handleStyleChanged_ = function() { - this.circleImage_ = this.createCircle_(); - this.styleCache_ = new Array(256); - this.changed(); -}; +goog.exportSymbol( + 'olcs.OLCesium', + olcs.OLCesium); +goog.exportProperty( + olcs.OLCesium.prototype, + 'getCamera', + olcs.OLCesium.prototype.getCamera); -/** - * @param {ol.render.Event} event Post compose event - * @private - */ -ol.layer.Heatmap.prototype.handleRender_ = function(event) { - goog.asserts.assert(event.type == ol.render.EventType.RENDER, - 'event.type should be RENDER'); - goog.asserts.assert(this.gradient_, 'this.gradient_ expected'); - var context = event.context; - var canvas = context.canvas; - var image = context.getImageData(0, 0, canvas.width, canvas.height); - var view8 = image.data; - var i, ii, alpha; - for (i = 0, ii = view8.length; i < ii; i += 4) { - alpha = view8[i + 3] * 4; - if (alpha) { - view8[i] = this.gradient_[alpha]; - view8[i + 1] = this.gradient_[alpha + 1]; - view8[i + 2] = this.gradient_[alpha + 2]; - } - } - context.putImageData(image, 0, 0); -}; +goog.exportProperty( + olcs.OLCesium.prototype, + 'getOlMap', + olcs.OLCesium.prototype.getOlMap); + +goog.exportProperty( + olcs.OLCesium.prototype, + 'getCesiumScene', + olcs.OLCesium.prototype.getCesiumScene); + +goog.exportProperty( + olcs.OLCesium.prototype, + 'getDataSources', + olcs.OLCesium.prototype.getDataSources); +goog.exportProperty( + olcs.OLCesium.prototype, + 'getEnabled', + olcs.OLCesium.prototype.getEnabled); -/** - * Set the blur size in pixels. - * @param {number} blur Blur size in pixels. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.setBlur = function(blur) { - this.set(ol.layer.HeatmapLayerProperty.BLUR, blur); -}; +goog.exportProperty( + olcs.OLCesium.prototype, + 'setEnabled', + olcs.OLCesium.prototype.setEnabled); +goog.exportProperty( + olcs.OLCesium.prototype, + 'warmUp', + olcs.OLCesium.prototype.warmUp); -/** - * Set the gradient colors as array of strings. - * @param {Array.<string>} colors Gradient. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.setGradient = function(colors) { - this.set(ol.layer.HeatmapLayerProperty.GRADIENT, colors); -}; +goog.exportProperty( + olcs.OLCesium.prototype, + 'setBlockCesiumRendering', + olcs.OLCesium.prototype.setBlockCesiumRendering); +goog.exportProperty( + olcs.OLCesium.prototype, + 'enableAutoRenderLoop', + olcs.OLCesium.prototype.enableAutoRenderLoop); -/** - * Set the size of the radius in pixels. - * @param {number} radius Radius size in pixel. - * @api - * @observable - */ -ol.layer.Heatmap.prototype.setRadius = function(radius) { - this.set(ol.layer.HeatmapLayerProperty.RADIUS, radius); -}; +goog.exportProperty( + olcs.OLCesium.prototype, + 'getAutoRenderLoop', + olcs.OLCesium.prototype.getAutoRenderLoop); -goog.provide('ol.raster.Operation'); -goog.provide('ol.raster.OperationType'); +goog.exportProperty( + olcs.OLCesium.prototype, + 'setResolutionScale', + olcs.OLCesium.prototype.setResolutionScale); +goog.exportSymbol( + 'olcs.RasterSynchronizer', + olcs.RasterSynchronizer); -/** - * Raster operation type. Supported values are `'pixel'` and `'image'`. - * @enum {string} - * @api - */ -ol.raster.OperationType = { - PIXEL: 'pixel', - IMAGE: 'image' -}; +goog.exportSymbol( + 'olcs.VectorSynchronizer', + olcs.VectorSynchronizer); +goog.exportSymbol( + 'olcs.GaRasterSynchronizer', + olcs.GaRasterSynchronizer); -/** - * A function that takes an array of input data, performs some operation, and - * returns an array of ouput data. For `'pixel'` type operations, functions - * will be called with an array of {@link ol.raster.Pixel} data and should - * return an array of the same. For `'image'` type operations, functions will - * be called with an array of {@link ImageData - * https://developer.mozilla.org/en-US/docs/Web/API/ImageData} and should return - * an array of the same. The operations are called with a second "data" - * argument, which can be used for storage. The data object is accessible - * from raster events, where it can be initialized in "beforeoperations" and - * accessed again in "afteroperations". - * - * @typedef {function((Array.<ol.raster.Pixel>|Array.<ImageData>), Object): - * (Array.<ol.raster.Pixel>|Array.<ImageData>)} - * @api - */ -ol.raster.Operation; +goog.exportProperty( + ol.Object.prototype, + 'changed', + ol.Object.prototype.changed); -goog.provide('ol.raster.Pixel'); +goog.exportProperty( + ol.Object.prototype, + 'dispatchEvent', + ol.Object.prototype.dispatchEvent); +goog.exportProperty( + ol.Object.prototype, + 'getRevision', + ol.Object.prototype.getRevision); -/** - * An array of numbers representing pixel values. - * @typedef {Array.<number>} ol.raster.Pixel - * @api - */ -ol.raster.Pixel; +goog.exportProperty( + ol.Object.prototype, + 'on', + ol.Object.prototype.on); -goog.provide('ol.reproj.Tile'); -goog.provide('ol.reproj.TileFunctionType'); +goog.exportProperty( + ol.Object.prototype, + 'once', + ol.Object.prototype.once); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.math'); -goog.require('goog.object'); -goog.require('ol.Tile'); -goog.require('ol.TileState'); -goog.require('ol.extent'); -goog.require('ol.math'); -goog.require('ol.proj'); -goog.require('ol.reproj'); -goog.require('ol.reproj.Triangulation'); +goog.exportProperty( + ol.Object.prototype, + 'un', + ol.Object.prototype.un); +goog.exportProperty( + ol.Object.prototype, + 'unByKey', + ol.Object.prototype.unByKey); -/** - * @typedef {function(number, number, number, number) : ol.Tile} - */ -ol.reproj.TileFunctionType; +goog.exportProperty( + ol.Collection.prototype, + 'get', + ol.Collection.prototype.get); +goog.exportProperty( + ol.Collection.prototype, + 'getKeys', + ol.Collection.prototype.getKeys); +goog.exportProperty( + ol.Collection.prototype, + 'getProperties', + ol.Collection.prototype.getProperties); -/** - * @classdesc - * Class encapsulating single reprojected tile. - * See {@link ol.source.TileImage}. - * - * @constructor - * @extends {ol.Tile} - * @param {ol.proj.Projection} sourceProj Source projection. - * @param {ol.tilegrid.TileGrid} sourceTileGrid Source tile grid. - * @param {ol.proj.Projection} targetProj Target projection. - * @param {ol.tilegrid.TileGrid} targetTileGrid Target tile grid. - * @param {number} z Zoom level. - * @param {number} x X. - * @param {number} y Y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.reproj.TileFunctionType} getTileFunction - * Function returning source tiles (z, x, y, pixelRatio). - * @param {number=} opt_errorThreshold Acceptable reprojection error (in px). - * @param {boolean=} opt_renderEdges Render reprojection edges. - */ -ol.reproj.Tile = function(sourceProj, sourceTileGrid, - targetProj, targetTileGrid, z, x, y, pixelRatio, getTileFunction, - opt_errorThreshold, - opt_renderEdges) { - goog.base(this, [z, x, y], ol.TileState.IDLE); +goog.exportProperty( + ol.Collection.prototype, + 'set', + ol.Collection.prototype.set); - /** - * @private - * @type {boolean} - */ - this.renderEdges_ = opt_renderEdges !== undefined ? opt_renderEdges : false; +goog.exportProperty( + ol.Collection.prototype, + 'setProperties', + ol.Collection.prototype.setProperties); - /** - * @private - * @type {number} - */ - this.pixelRatio_ = pixelRatio; +goog.exportProperty( + ol.Collection.prototype, + 'unset', + ol.Collection.prototype.unset); - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; +goog.exportProperty( + ol.Collection.prototype, + 'changed', + ol.Collection.prototype.changed); - /** - * @private - * @type {Object.<number, HTMLCanvasElement>} - */ - this.canvasByContext_ = {}; +goog.exportProperty( + ol.Collection.prototype, + 'dispatchEvent', + ol.Collection.prototype.dispatchEvent); - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.sourceTileGrid_ = sourceTileGrid; +goog.exportProperty( + ol.Collection.prototype, + 'getRevision', + ol.Collection.prototype.getRevision); - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.targetTileGrid_ = targetTileGrid; +goog.exportProperty( + ol.Collection.prototype, + 'on', + ol.Collection.prototype.on); - /** - * @private - * @type {!Array.<ol.Tile>} - */ - this.sourceTiles_ = []; +goog.exportProperty( + ol.Collection.prototype, + 'once', + ol.Collection.prototype.once); - /** - * @private - * @type {Array.<goog.events.Key>} - */ - this.sourcesListenerKeys_ = null; +goog.exportProperty( + ol.Collection.prototype, + 'un', + ol.Collection.prototype.un); - /** - * @private - * @type {number} - */ - this.sourceZ_ = 0; +goog.exportProperty( + ol.Collection.prototype, + 'unByKey', + ol.Collection.prototype.unByKey); - var targetExtent = targetTileGrid.getTileCoordExtent(this.getTileCoord()); - var maxTargetExtent = this.targetTileGrid_.getExtent(); - var maxSourceExtent = this.sourceTileGrid_.getExtent(); +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'get', + ol.DeviceOrientation.prototype.get); - var limitedTargetExtent = maxTargetExtent ? - ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent; +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getKeys', + ol.DeviceOrientation.prototype.getKeys); - if (ol.extent.getArea(limitedTargetExtent) === 0) { - // Tile is completely outside range -> EMPTY - // TODO: is it actually correct that the source even creates the tile ? - this.state = ol.TileState.EMPTY; - return; - } +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getProperties', + ol.DeviceOrientation.prototype.getProperties); - var sourceProjExtent = sourceProj.getExtent(); - if (sourceProjExtent) { - if (!maxSourceExtent) { - maxSourceExtent = sourceProjExtent; - } else { - maxSourceExtent = ol.extent.getIntersection( - maxSourceExtent, sourceProjExtent); - } - } +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'set', + ol.DeviceOrientation.prototype.set); - var targetResolution = targetTileGrid.getResolution(z); +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'setProperties', + ol.DeviceOrientation.prototype.setProperties); - var targetCenter = ol.extent.getCenter(limitedTargetExtent); - var sourceResolution = ol.reproj.calculateSourceResolution( - sourceProj, targetProj, targetCenter, targetResolution); +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'unset', + ol.DeviceOrientation.prototype.unset); - if (!goog.math.isFiniteNumber(sourceResolution) || sourceResolution <= 0) { - // invalid sourceResolution -> EMPTY - // probably edges of the projections when no extent is defined - this.state = ol.TileState.EMPTY; - return; - } +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'changed', + ol.DeviceOrientation.prototype.changed); - var errorThresholdInPixels = opt_errorThreshold !== undefined ? - opt_errorThreshold : ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD; +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'dispatchEvent', + ol.DeviceOrientation.prototype.dispatchEvent); - /** - * @private - * @type {!ol.reproj.Triangulation} - */ - this.triangulation_ = new ol.reproj.Triangulation( - sourceProj, targetProj, limitedTargetExtent, maxSourceExtent, - sourceResolution * errorThresholdInPixels); +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'getRevision', + ol.DeviceOrientation.prototype.getRevision); - if (this.triangulation_.getTriangles().length === 0) { - // no valid triangles -> EMPTY - this.state = ol.TileState.EMPTY; - return; - } +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'on', + ol.DeviceOrientation.prototype.on); - this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution); - var sourceExtent = this.triangulation_.calculateSourceExtent(); +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'once', + ol.DeviceOrientation.prototype.once); - if (maxSourceExtent) { - if (sourceProj.canWrapX()) { - sourceExtent[1] = ol.math.clamp( - sourceExtent[1], maxSourceExtent[1], maxSourceExtent[3]); - sourceExtent[3] = ol.math.clamp( - sourceExtent[3], maxSourceExtent[1], maxSourceExtent[3]); - } else { - sourceExtent = ol.extent.getIntersection(sourceExtent, maxSourceExtent); - } - } +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'un', + ol.DeviceOrientation.prototype.un); - if (!ol.extent.getArea(sourceExtent)) { - this.state = ol.TileState.EMPTY; - } else { - var sourceRange = sourceTileGrid.getTileRangeForExtentAndZ( - sourceExtent, this.sourceZ_); +goog.exportProperty( + ol.DeviceOrientation.prototype, + 'unByKey', + ol.DeviceOrientation.prototype.unByKey); - var tilesRequired = sourceRange.getWidth() * sourceRange.getHeight(); - if (!goog.asserts.assert( - tilesRequired < ol.RASTER_REPROJECTION_MAX_SOURCE_TILES, - 'reasonable number of tiles is required')) { - this.state = ol.TileState.ERROR; - return; - } - for (var srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) { - for (var srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) { - var tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio); - if (tile) { - this.sourceTiles_.push(tile); - } - } - } +goog.exportProperty( + ol.Feature.prototype, + 'get', + ol.Feature.prototype.get); - if (this.sourceTiles_.length === 0) { - this.state = ol.TileState.EMPTY; - } - } -}; -goog.inherits(ol.reproj.Tile, ol.Tile); +goog.exportProperty( + ol.Feature.prototype, + 'getKeys', + ol.Feature.prototype.getKeys); +goog.exportProperty( + ol.Feature.prototype, + 'getProperties', + ol.Feature.prototype.getProperties); -/** - * @inheritDoc - */ -ol.reproj.Tile.prototype.disposeInternal = function() { - if (this.state == ol.TileState.LOADING) { - this.unlistenSources_(); - } - goog.base(this, 'disposeInternal'); -}; +goog.exportProperty( + ol.Feature.prototype, + 'set', + ol.Feature.prototype.set); +goog.exportProperty( + ol.Feature.prototype, + 'setProperties', + ol.Feature.prototype.setProperties); -/** - * @inheritDoc - */ -ol.reproj.Tile.prototype.getImage = function(opt_context) { - if (opt_context !== undefined) { - var image; - var key = goog.getUid(opt_context); - if (key in this.canvasByContext_) { - return this.canvasByContext_[key]; - } else if (goog.object.isEmpty(this.canvasByContext_)) { - image = this.canvas_; - } else { - image = /** @type {HTMLCanvasElement} */ (this.canvas_.cloneNode(false)); - } - this.canvasByContext_[key] = image; - return image; - } else { - return this.canvas_; - } -}; +goog.exportProperty( + ol.Feature.prototype, + 'unset', + ol.Feature.prototype.unset); +goog.exportProperty( + ol.Feature.prototype, + 'changed', + ol.Feature.prototype.changed); -/** - * @private - */ -ol.reproj.Tile.prototype.reproject_ = function() { - var sources = []; - this.sourceTiles_.forEach(function(tile, i, arr) { - if (tile && tile.getState() == ol.TileState.LOADED) { - sources.push({ - extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord), - image: tile.getImage() - }); - } - }, this); - this.sourceTiles_.length = 0; +goog.exportProperty( + ol.Feature.prototype, + 'dispatchEvent', + ol.Feature.prototype.dispatchEvent); - var tileCoord = this.getTileCoord(); - var z = tileCoord[0]; - var size = this.targetTileGrid_.getTileSize(z); - var width = goog.isNumber(size) ? size : size[0]; - var height = goog.isNumber(size) ? size : size[1]; - var targetResolution = this.targetTileGrid_.getResolution(z); - var sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_); +goog.exportProperty( + ol.Feature.prototype, + 'getRevision', + ol.Feature.prototype.getRevision); - var targetExtent = this.targetTileGrid_.getTileCoordExtent(tileCoord); - this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_, - sourceResolution, this.sourceTileGrid_.getExtent(), - targetResolution, targetExtent, this.triangulation_, sources, - this.renderEdges_); +goog.exportProperty( + ol.Feature.prototype, + 'on', + ol.Feature.prototype.on); - this.state = ol.TileState.LOADED; - this.changed(); -}; +goog.exportProperty( + ol.Feature.prototype, + 'once', + ol.Feature.prototype.once); +goog.exportProperty( + ol.Feature.prototype, + 'un', + ol.Feature.prototype.un); -/** - * @inheritDoc - */ -ol.reproj.Tile.prototype.load = function() { - if (this.state == ol.TileState.IDLE) { - this.state = ol.TileState.LOADING; - this.changed(); +goog.exportProperty( + ol.Feature.prototype, + 'unByKey', + ol.Feature.prototype.unByKey); - var leftToLoad = 0; +goog.exportProperty( + ol.Geolocation.prototype, + 'get', + ol.Geolocation.prototype.get); - goog.asserts.assert(!this.sourcesListenerKeys_, - 'this.sourcesListenerKeys_ should be null'); +goog.exportProperty( + ol.Geolocation.prototype, + 'getKeys', + ol.Geolocation.prototype.getKeys); - this.sourcesListenerKeys_ = []; - this.sourceTiles_.forEach(function(tile, i, arr) { - var state = tile.getState(); - if (state == ol.TileState.IDLE || state == ol.TileState.LOADING) { - leftToLoad++; +goog.exportProperty( + ol.Geolocation.prototype, + 'getProperties', + ol.Geolocation.prototype.getProperties); - var sourceListenKey; - sourceListenKey = tile.listen(goog.events.EventType.CHANGE, - function(e) { - var state = tile.getState(); - if (state == ol.TileState.LOADED || - state == ol.TileState.ERROR || - state == ol.TileState.EMPTY) { - goog.events.unlistenByKey(sourceListenKey); - leftToLoad--; - goog.asserts.assert(leftToLoad >= 0, - 'leftToLoad should not be negative'); - if (leftToLoad === 0) { - this.unlistenSources_(); - this.reproject_(); - } - } - }, false, this); - this.sourcesListenerKeys_.push(sourceListenKey); - } - }, this); +goog.exportProperty( + ol.Geolocation.prototype, + 'set', + ol.Geolocation.prototype.set); - this.sourceTiles_.forEach(function(tile, i, arr) { - var state = tile.getState(); - if (state == ol.TileState.IDLE) { - tile.load(); - } - }); +goog.exportProperty( + ol.Geolocation.prototype, + 'setProperties', + ol.Geolocation.prototype.setProperties); - if (leftToLoad === 0) { - this.reproject_(); - } - } -}; +goog.exportProperty( + ol.Geolocation.prototype, + 'unset', + ol.Geolocation.prototype.unset); +goog.exportProperty( + ol.Geolocation.prototype, + 'changed', + ol.Geolocation.prototype.changed); -/** - * @private - */ -ol.reproj.Tile.prototype.unlistenSources_ = function() { - goog.asserts.assert(this.sourcesListenerKeys_, - 'this.sourcesListenerKeys_ should not be null'); - this.sourcesListenerKeys_.forEach(goog.events.unlistenByKey); - this.sourcesListenerKeys_ = null; -}; +goog.exportProperty( + ol.Geolocation.prototype, + 'dispatchEvent', + ol.Geolocation.prototype.dispatchEvent); -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.exportProperty( + ol.Geolocation.prototype, + 'getRevision', + ol.Geolocation.prototype.getRevision); -/** - * @fileoverview A utility to load JavaScript files via DOM script tags. - * Refactored from goog.net.Jsonp. Works cross-domain. - * - */ +goog.exportProperty( + ol.Geolocation.prototype, + 'on', + ol.Geolocation.prototype.on); -goog.provide('goog.net.jsloader'); -goog.provide('goog.net.jsloader.Error'); -goog.provide('goog.net.jsloader.ErrorCode'); -goog.provide('goog.net.jsloader.Options'); +goog.exportProperty( + ol.Geolocation.prototype, + 'once', + ol.Geolocation.prototype.once); -goog.require('goog.array'); -goog.require('goog.async.Deferred'); -goog.require('goog.debug.Error'); -goog.require('goog.dom'); -goog.require('goog.dom.TagName'); -goog.require('goog.object'); +goog.exportProperty( + ol.Geolocation.prototype, + 'un', + ol.Geolocation.prototype.un); +goog.exportProperty( + ol.Geolocation.prototype, + 'unByKey', + ol.Geolocation.prototype.unByKey); -/** - * The name of the property of goog.global under which the JavaScript - * verification object is stored by the loaded script. - * @private {string} - */ -goog.net.jsloader.GLOBAL_VERIFY_OBJS_ = 'closure_verification'; +goog.exportProperty( + ol.ImageTile.prototype, + 'getTileCoord', + ol.ImageTile.prototype.getTileCoord); +goog.exportProperty( + ol.Map.prototype, + 'get', + ol.Map.prototype.get); -/** - * The default length of time, in milliseconds, we are prepared to wait for a - * load request to complete. - * @type {number} - */ -goog.net.jsloader.DEFAULT_TIMEOUT = 5000; +goog.exportProperty( + ol.Map.prototype, + 'getKeys', + ol.Map.prototype.getKeys); +goog.exportProperty( + ol.Map.prototype, + 'getProperties', + ol.Map.prototype.getProperties); -/** - * Optional parameters for goog.net.jsloader.send. - * timeout: The length of time, in milliseconds, we are prepared to wait - * for a load request to complete. Default it 5 seconds. - * document: The HTML document under which to load the JavaScript. Default is - * the current document. - * cleanupWhenDone: If true clean up the script tag after script completes to - * load. This is important if you just want to read data from the JavaScript - * and then throw it away. Default is false. - * attributes: Additional attributes to set on the script tag. - * - * @typedef {{ - * timeout: (number|undefined), - * document: (HTMLDocument|undefined), - * cleanupWhenDone: (boolean|undefined), - * attributes: (!Object<string, string>|undefined) - * }} - */ -goog.net.jsloader.Options; +goog.exportProperty( + ol.Map.prototype, + 'set', + ol.Map.prototype.set); + +goog.exportProperty( + ol.Map.prototype, + 'setProperties', + ol.Map.prototype.setProperties); + +goog.exportProperty( + ol.Map.prototype, + 'unset', + ol.Map.prototype.unset); + +goog.exportProperty( + ol.Map.prototype, + 'changed', + ol.Map.prototype.changed); + +goog.exportProperty( + ol.Map.prototype, + 'dispatchEvent', + ol.Map.prototype.dispatchEvent); +goog.exportProperty( + ol.Map.prototype, + 'getRevision', + ol.Map.prototype.getRevision); -/** - * Scripts (URIs) waiting to be loaded. - * @private {!Array<string>} - */ -goog.net.jsloader.scriptsToLoad_ = []; +goog.exportProperty( + ol.Map.prototype, + 'on', + ol.Map.prototype.on); +goog.exportProperty( + ol.Map.prototype, + 'once', + ol.Map.prototype.once); -/** - * The deferred result of loading the URIs in scriptsToLoad_. - * We need to return this to a caller that wants to load URIs while - * a deferred is already working on them. - * @private {!goog.async.Deferred<null>} - */ -goog.net.jsloader.scriptLoadingDeferred_; +goog.exportProperty( + ol.Map.prototype, + 'un', + ol.Map.prototype.un); +goog.exportProperty( + ol.Map.prototype, + 'unByKey', + ol.Map.prototype.unByKey); -/** - * Loads and evaluates the JavaScript files at the specified URIs, guaranteeing - * the order of script loads. - * - * Because we have to load the scripts in serial (load script 1, exec script 1, - * load script 2, exec script 2, and so on), this will be slower than doing - * the network fetches in parallel. - * - * If you need to load a large number of scripts but dependency order doesn't - * matter, you should just call goog.net.jsloader.load N times. - * - * If you need to load a large number of scripts on the same domain, - * you may want to use goog.module.ModuleLoader. - * - * @param {Array<string>} uris The URIs to load. - * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See - * goog.net.jsloader.options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks - */ -goog.net.jsloader.loadMany = function(uris, opt_options) { - // Loading the scripts in serial introduces asynchronosity into the flow. - // Therefore, there are race conditions where client A can kick off the load - // sequence for client B, even though client A's scripts haven't all been - // loaded yet. - // - // To work around this issue, all module loads share a queue. - if (!uris.length) { - return goog.async.Deferred.succeed(null); - } +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'map', + ol.MapBrowserEvent.prototype.map); - var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length; - goog.array.extend(goog.net.jsloader.scriptsToLoad_, uris); - if (isAnotherModuleLoading) { - // jsloader is still loading some other scripts. - // In order to prevent the race condition noted above, we just add - // these URIs to the end of the scripts' queue and return the deferred - // result of the ongoing script load, so the caller knows when they - // finish loading. - return goog.net.jsloader.scriptLoadingDeferred_; - } +goog.exportProperty( + ol.MapBrowserEvent.prototype, + 'frameState', + ol.MapBrowserEvent.prototype.frameState); - uris = goog.net.jsloader.scriptsToLoad_; - var popAndLoadNextScript = function() { - var uri = uris.shift(); - var deferred = goog.net.jsloader.load(uri, opt_options); - if (uris.length) { - deferred.addBoth(popAndLoadNextScript); - } - return deferred; - }; - goog.net.jsloader.scriptLoadingDeferred_ = popAndLoadNextScript(); - return goog.net.jsloader.scriptLoadingDeferred_; -}; +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'originalEvent', + ol.MapBrowserPointerEvent.prototype.originalEvent); +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'pixel', + ol.MapBrowserPointerEvent.prototype.pixel); -/** - * Loads and evaluates a JavaScript file. - * When the script loads, a user callback is called. - * It is the client's responsibility to verify that the script ran successfully. - * - * @param {string} uri The URI of the JavaScript. - * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See - * goog.net.jsloader.Options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks and/or cancel the transmission. - * The error callback will be called with a single goog.net.jsloader.Error - * parameter. - */ -goog.net.jsloader.load = function(uri, opt_options) { - var options = opt_options || {}; - var doc = options.document || document; +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'coordinate', + ol.MapBrowserPointerEvent.prototype.coordinate); - var script = goog.dom.createElement(goog.dom.TagName.SCRIPT); - var request = {script_: script, timeout_: undefined}; - var deferred = new goog.async.Deferred(goog.net.jsloader.cancel_, request); +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'dragging', + ol.MapBrowserPointerEvent.prototype.dragging); - // Set a timeout. - var timeout = null; - var timeoutDuration = goog.isDefAndNotNull(options.timeout) ? - options.timeout : goog.net.jsloader.DEFAULT_TIMEOUT; - if (timeoutDuration > 0) { - timeout = window.setTimeout(function() { - goog.net.jsloader.cleanup_(script, true); - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.TIMEOUT, - 'Timeout reached for loading script ' + uri)); - }, timeoutDuration); - request.timeout_ = timeout; - } +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'preventDefault', + ol.MapBrowserPointerEvent.prototype.preventDefault); - // Hang the user callback to be called when the script completes to load. - // NOTE(user): This callback will be called in IE even upon error. In any - // case it is the client's responsibility to verify that the script ran - // successfully. - script.onload = script.onreadystatechange = function() { - if (!script.readyState || script.readyState == 'loaded' || - script.readyState == 'complete') { - var removeScriptNode = options.cleanupWhenDone || false; - goog.net.jsloader.cleanup_(script, removeScriptNode, timeout); - deferred.callback(null); - } - }; +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'stopPropagation', + ol.MapBrowserPointerEvent.prototype.stopPropagation); - // Add an error callback. - // NOTE(user): Not supported in IE. - script.onerror = function() { - goog.net.jsloader.cleanup_(script, true, timeout); - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.LOAD_ERROR, - 'Error while loading script ' + uri)); - }; +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'map', + ol.MapBrowserPointerEvent.prototype.map); - var properties = options.attributes || {}; - goog.object.extend(properties, { - 'type': 'text/javascript', - 'charset': 'UTF-8', - // NOTE(user): Safari never loads the script if we don't set - // the src attribute before appending. - 'src': uri - }); - goog.dom.setProperties(script, properties); - var scriptParent = goog.net.jsloader.getScriptParentElement_(doc); - scriptParent.appendChild(script); +goog.exportProperty( + ol.MapBrowserPointerEvent.prototype, + 'frameState', + ol.MapBrowserPointerEvent.prototype.frameState); - return deferred; -}; +goog.exportProperty( + ol.Overlay.prototype, + 'get', + ol.Overlay.prototype.get); +goog.exportProperty( + ol.Overlay.prototype, + 'getKeys', + ol.Overlay.prototype.getKeys); -/** - * Loads a JavaScript file and verifies it was evaluated successfully, using a - * verification object. - * The verification object is set by the loaded JavaScript at the end of the - * script. - * We verify this object was set and return its value in the success callback. - * If the object is not defined we trigger an error callback. - * - * @param {string} uri The URI of the JavaScript. - * @param {string} verificationObjName The name of the verification object that - * the loaded script should set. - * @param {goog.net.jsloader.Options} options Optional parameters. See - * goog.net.jsloader.Options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks and/or cancel the transmission. - * The success callback will be called with a single parameter containing - * the value of the verification object. - * The error callback will be called with a single goog.net.jsloader.Error - * parameter. - */ -goog.net.jsloader.loadAndVerify = function(uri, verificationObjName, options) { - // Define the global objects variable. - if (!goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]) { - goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_] = {}; - } - var verifyObjs = goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]; +goog.exportProperty( + ol.Overlay.prototype, + 'getProperties', + ol.Overlay.prototype.getProperties); - // Verify that the expected object does not exist yet. - if (goog.isDef(verifyObjs[verificationObjName])) { - // TODO(user): Error or reset variable? - return goog.async.Deferred.fail(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.VERIFY_OBJECT_ALREADY_EXISTS, - 'Verification object ' + verificationObjName + ' already defined.')); - } +goog.exportProperty( + ol.Overlay.prototype, + 'set', + ol.Overlay.prototype.set); - // Send request to load the JavaScript. - var sendDeferred = goog.net.jsloader.load(uri, options); +goog.exportProperty( + ol.Overlay.prototype, + 'setProperties', + ol.Overlay.prototype.setProperties); - // Create a deferred object wrapping the send result. - var deferred = new goog.async.Deferred( - goog.bind(sendDeferred.cancel, sendDeferred)); +goog.exportProperty( + ol.Overlay.prototype, + 'unset', + ol.Overlay.prototype.unset); - // Call user back with object that was set by the script. - sendDeferred.addCallback(function() { - var result = verifyObjs[verificationObjName]; - if (goog.isDef(result)) { - deferred.callback(result); - delete verifyObjs[verificationObjName]; - } else { - // Error: script was not loaded properly. - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.VERIFY_ERROR, - 'Script ' + uri + ' loaded, but verification object ' + - verificationObjName + ' was not defined.')); - } - }); +goog.exportProperty( + ol.Overlay.prototype, + 'changed', + ol.Overlay.prototype.changed); - // Pass error to new deferred object. - sendDeferred.addErrback(function(error) { - if (goog.isDef(verifyObjs[verificationObjName])) { - delete verifyObjs[verificationObjName]; - } - deferred.errback(error); - }); +goog.exportProperty( + ol.Overlay.prototype, + 'dispatchEvent', + ol.Overlay.prototype.dispatchEvent); - return deferred; -}; +goog.exportProperty( + ol.Overlay.prototype, + 'getRevision', + ol.Overlay.prototype.getRevision); +goog.exportProperty( + ol.Overlay.prototype, + 'on', + ol.Overlay.prototype.on); -/** - * Gets the DOM element under which we should add new script elements. - * How? Take the first head element, and if not found take doc.documentElement, - * which always exists. - * - * @param {!HTMLDocument} doc The relevant document. - * @return {!Element} The script parent element. - * @private - */ -goog.net.jsloader.getScriptParentElement_ = function(doc) { - var headElements = doc.getElementsByTagName(goog.dom.TagName.HEAD); - if (!headElements || goog.array.isEmpty(headElements)) { - return doc.documentElement; - } else { - return headElements[0]; - } -}; +goog.exportProperty( + ol.Overlay.prototype, + 'once', + ol.Overlay.prototype.once); +goog.exportProperty( + ol.Overlay.prototype, + 'un', + ol.Overlay.prototype.un); -/** - * Cancels a given request. - * @this {{script_: Element, timeout_: number}} The request context. - * @private - */ -goog.net.jsloader.cancel_ = function() { - var request = this; - if (request && request.script_) { - var scriptNode = request.script_; - if (scriptNode && scriptNode.tagName == goog.dom.TagName.SCRIPT) { - goog.net.jsloader.cleanup_(scriptNode, true, request.timeout_); - } - } -}; +goog.exportProperty( + ol.Overlay.prototype, + 'unByKey', + ol.Overlay.prototype.unByKey); +goog.exportProperty( + ol.VectorTile.prototype, + 'getTileCoord', + ol.VectorTile.prototype.getTileCoord); -/** - * Removes the script node and the timeout. - * - * @param {Node} scriptNode The node to be cleaned up. - * @param {boolean} removeScriptNode If true completely remove the script node. - * @param {?number=} opt_timeout The timeout handler to cleanup. - * @private - */ -goog.net.jsloader.cleanup_ = function(scriptNode, removeScriptNode, - opt_timeout) { - if (goog.isDefAndNotNull(opt_timeout)) { - goog.global.clearTimeout(opt_timeout); - } +goog.exportProperty( + ol.View.prototype, + 'get', + ol.View.prototype.get); - scriptNode.onload = goog.nullFunction; - scriptNode.onerror = goog.nullFunction; - scriptNode.onreadystatechange = goog.nullFunction; +goog.exportProperty( + ol.View.prototype, + 'getKeys', + ol.View.prototype.getKeys); - // Do this after a delay (removing the script node of a running script can - // confuse older IEs). - if (removeScriptNode) { - window.setTimeout(function() { - goog.dom.removeNode(scriptNode); - }, 0); - } -}; +goog.exportProperty( + ol.View.prototype, + 'getProperties', + ol.View.prototype.getProperties); +goog.exportProperty( + ol.View.prototype, + 'set', + ol.View.prototype.set); -/** - * Possible error codes for jsloader. - * @enum {number} - */ -goog.net.jsloader.ErrorCode = { - LOAD_ERROR: 0, - TIMEOUT: 1, - VERIFY_ERROR: 2, - VERIFY_OBJECT_ALREADY_EXISTS: 3 -}; +goog.exportProperty( + ol.View.prototype, + 'setProperties', + ol.View.prototype.setProperties); +goog.exportProperty( + ol.View.prototype, + 'unset', + ol.View.prototype.unset); +goog.exportProperty( + ol.View.prototype, + 'changed', + ol.View.prototype.changed); -/** - * A jsloader error. - * - * @param {goog.net.jsloader.ErrorCode} code The error code. - * @param {string=} opt_message Additional message. - * @constructor - * @extends {goog.debug.Error} - * @final - */ -goog.net.jsloader.Error = function(code, opt_message) { - var msg = 'Jsloader error (code #' + code + ')'; - if (opt_message) { - msg += ': ' + opt_message; - } - goog.net.jsloader.Error.base(this, 'constructor', msg); +goog.exportProperty( + ol.View.prototype, + 'dispatchEvent', + ol.View.prototype.dispatchEvent); - /** - * The code for this error. - * - * @type {goog.net.jsloader.ErrorCode} - */ - this.code = code; -}; -goog.inherits(goog.net.jsloader.Error, goog.debug.Error); +goog.exportProperty( + ol.View.prototype, + 'getRevision', + ol.View.prototype.getRevision); -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +goog.exportProperty( + ol.View.prototype, + 'on', + ol.View.prototype.on); -// The original file lives here: http://go/cross_domain_channel.js +goog.exportProperty( + ol.View.prototype, + 'once', + ol.View.prototype.once); -/** - * @fileoverview Implements a cross-domain communication channel. A - * typical web page is prevented by browser security from sending - * request, such as a XMLHttpRequest, to other servers than the ones - * from which it came. The Jsonp class provides a workaround by - * using dynamically generated script tags. Typical usage:. - * - * var jsonp = new goog.net.Jsonp(new goog.Uri('http://my.host.com/servlet')); - * var payload = { 'foo': 1, 'bar': true }; - * jsonp.send(payload, function(reply) { alert(reply) }); - * - * This script works in all browsers that are currently supported by - * the Google Maps API, which is IE 6.0+, Firefox 0.8+, Safari 1.2.4+, - * Netscape 7.1+, Mozilla 1.4+, Opera 8.02+. - * - */ +goog.exportProperty( + ol.View.prototype, + 'un', + ol.View.prototype.un); -goog.provide('goog.net.Jsonp'); +goog.exportProperty( + ol.View.prototype, + 'unByKey', + ol.View.prototype.unByKey); -goog.require('goog.Uri'); -goog.require('goog.net.jsloader'); +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getMaxZoom', + ol.tilegrid.WMTS.prototype.getMaxZoom); -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -// -// This class allows us (Google) to send data from non-Google and thus -// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return -// anything sensitive, such as session or cookie specific data. Return -// only data that you want parties external to Google to have. Also -// NEVER use this method to send data from web pages to untrusted -// servers, or redirects to unknown servers (www.google.com/cache, -// /q=xx&btnl, /url, www.googlepages.com, etc.) -// -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getMinZoom', + ol.tilegrid.WMTS.prototype.getMinZoom); +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getOrigin', + ol.tilegrid.WMTS.prototype.getOrigin); +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getResolution', + ol.tilegrid.WMTS.prototype.getResolution); -/** - * Creates a new cross domain channel that sends data to the specified - * host URL. By default, if no reply arrives within 5s, the channel - * assumes the call failed to complete successfully. - * - * @param {goog.Uri|string} uri The Uri of the server side code that receives - * data posted through this channel (e.g., - * "http://maps.google.com/maps/geo"). - * - * @param {string=} opt_callbackParamName The parameter name that is used to - * specify the callback. Defaults to "callback". - * - * @constructor - * @final - */ -goog.net.Jsonp = function(uri, opt_callbackParamName) { - /** - * The uri_ object will be used to encode the payload that is sent to the - * server. - * @type {goog.Uri} - * @private - */ - this.uri_ = new goog.Uri(uri); +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getResolutions', + ol.tilegrid.WMTS.prototype.getResolutions); - /** - * This is the callback parameter name that is added to the uri. - * @type {string} - * @private - */ - this.callbackParamName_ = opt_callbackParamName ? - opt_callbackParamName : 'callback'; +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getTileCoordExtent', + ol.tilegrid.WMTS.prototype.getTileCoordExtent); - /** - * The length of time, in milliseconds, this channel is prepared - * to wait for for a request to complete. The default value is 5 seconds. - * @type {number} - * @private - */ - this.timeout_ = 5000; -}; +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getTileCoordForCoordAndResolution', + ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndResolution); +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getTileCoordForCoordAndZ', + ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndZ); -/** - * The name of the property of goog.global under which the callback is - * stored. - */ -goog.net.Jsonp.CALLBACKS = '_callbacks_'; +goog.exportProperty( + ol.tilegrid.WMTS.prototype, + 'getTileSize', + ol.tilegrid.WMTS.prototype.getTileSize); +goog.exportProperty( + ol.style.Circle.prototype, + 'getOpacity', + ol.style.Circle.prototype.getOpacity); -/** - * Used to generate unique callback IDs. The counter must be global because - * all channels share a common callback object. - * @private - */ -goog.net.Jsonp.scriptCounter_ = 0; +goog.exportProperty( + ol.style.Circle.prototype, + 'getRotateWithView', + ol.style.Circle.prototype.getRotateWithView); +goog.exportProperty( + ol.style.Circle.prototype, + 'getRotation', + ol.style.Circle.prototype.getRotation); -/** - * Sets the length of time, in milliseconds, this channel is prepared - * to wait for for a request to complete. If the call is not competed - * within the set time span, it is assumed to have failed. To wait - * indefinitely for a request to complete set the timout to a negative - * number. - * - * @param {number} timeout The length of time before calls are - * interrupted. - */ -goog.net.Jsonp.prototype.setRequestTimeout = function(timeout) { - this.timeout_ = timeout; -}; +goog.exportProperty( + ol.style.Circle.prototype, + 'getScale', + ol.style.Circle.prototype.getScale); +goog.exportProperty( + ol.style.Circle.prototype, + 'getSnapToPixel', + ol.style.Circle.prototype.getSnapToPixel); -/** - * Returns the current timeout value, in milliseconds. - * - * @return {number} The timeout value. - */ -goog.net.Jsonp.prototype.getRequestTimeout = function() { - return this.timeout_; -}; +goog.exportProperty( + ol.style.Circle.prototype, + 'setOpacity', + ol.style.Circle.prototype.setOpacity); +goog.exportProperty( + ol.style.Circle.prototype, + 'setRotation', + ol.style.Circle.prototype.setRotation); -/** - * Sends the given payload to the URL specified at the construction - * time. The reply is delivered to the given replyCallback. If the - * errorCallback is specified and the reply does not arrive within the - * timeout period set on this channel, the errorCallback is invoked - * with the original payload. - * - * If no reply callback is specified, then the response is expected to - * consist of calls to globally registered functions. No &callback= - * URL parameter will be sent in the request, and the script element - * will be cleaned up after the timeout. - * - * @param {Object=} opt_payload Name-value pairs. If given, these will be - * added as parameters to the supplied URI as GET parameters to the - * given server URI. - * - * @param {Function=} opt_replyCallback A function expecting one - * argument, called when the reply arrives, with the response data. - * - * @param {Function=} opt_errorCallback A function expecting one - * argument, called on timeout, with the payload (if given), otherwise - * null. - * - * @param {string=} opt_callbackParamValue Value to be used as the - * parameter value for the callback parameter (callbackParamName). - * To be used when the value needs to be fixed by the client for a - * particular request, to make use of the cached responses for the request. - * NOTE: If multiple requests are made with the same - * opt_callbackParamValue, only the last call will work whenever the - * response comes back. - * - * @return {!Object} A request descriptor that may be used to cancel this - * transmission, or null, if the message may not be cancelled. - */ -goog.net.Jsonp.prototype.send = function(opt_payload, - opt_replyCallback, - opt_errorCallback, - opt_callbackParamValue) { +goog.exportProperty( + ol.style.Circle.prototype, + 'setScale', + ol.style.Circle.prototype.setScale); - var payload = opt_payload || null; +goog.exportProperty( + ol.style.Icon.prototype, + 'getOpacity', + ol.style.Icon.prototype.getOpacity); - var id = opt_callbackParamValue || - '_' + (goog.net.Jsonp.scriptCounter_++).toString(36) + - goog.now().toString(36); +goog.exportProperty( + ol.style.Icon.prototype, + 'getRotateWithView', + ol.style.Icon.prototype.getRotateWithView); + +goog.exportProperty( + ol.style.Icon.prototype, + 'getRotation', + ol.style.Icon.prototype.getRotation); + +goog.exportProperty( + ol.style.Icon.prototype, + 'getScale', + ol.style.Icon.prototype.getScale); + +goog.exportProperty( + ol.style.Icon.prototype, + 'getSnapToPixel', + ol.style.Icon.prototype.getSnapToPixel); + +goog.exportProperty( + ol.style.Icon.prototype, + 'setOpacity', + ol.style.Icon.prototype.setOpacity); + +goog.exportProperty( + ol.style.Icon.prototype, + 'setRotation', + ol.style.Icon.prototype.setRotation); + +goog.exportProperty( + ol.style.Icon.prototype, + 'setScale', + ol.style.Icon.prototype.setScale); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getOpacity', + ol.style.RegularShape.prototype.getOpacity); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getRotateWithView', + ol.style.RegularShape.prototype.getRotateWithView); + +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getRotation', + ol.style.RegularShape.prototype.getRotation); - if (!goog.global[goog.net.Jsonp.CALLBACKS]) { - goog.global[goog.net.Jsonp.CALLBACKS] = {}; - } +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getScale', + ol.style.RegularShape.prototype.getScale); - // Create a new Uri object onto which this payload will be added - var uri = this.uri_.clone(); - if (payload) { - goog.net.Jsonp.addPayloadToUri_(payload, uri); - } +goog.exportProperty( + ol.style.RegularShape.prototype, + 'getSnapToPixel', + ol.style.RegularShape.prototype.getSnapToPixel); - if (opt_replyCallback) { - var reply = goog.net.Jsonp.newReplyHandler_(id, opt_replyCallback); - goog.global[goog.net.Jsonp.CALLBACKS][id] = reply; +goog.exportProperty( + ol.style.RegularShape.prototype, + 'setOpacity', + ol.style.RegularShape.prototype.setOpacity); - uri.setParameterValues(this.callbackParamName_, - goog.net.Jsonp.CALLBACKS + '.' + id); - } +goog.exportProperty( + ol.style.RegularShape.prototype, + 'setRotation', + ol.style.RegularShape.prototype.setRotation); - var deferred = goog.net.jsloader.load(uri.toString(), - {timeout: this.timeout_, cleanupWhenDone: true}); - var error = goog.net.Jsonp.newErrorHandler_(id, payload, opt_errorCallback); - deferred.addErrback(error); +goog.exportProperty( + ol.style.RegularShape.prototype, + 'setScale', + ol.style.RegularShape.prototype.setScale); - return {id_: id, deferred_: deferred}; -}; +goog.exportProperty( + ol.source.Source.prototype, + 'get', + ol.source.Source.prototype.get); +goog.exportProperty( + ol.source.Source.prototype, + 'getKeys', + ol.source.Source.prototype.getKeys); -/** - * Cancels a given request. The request must be exactly the object returned by - * the send method. - * - * @param {Object} request The request object returned by the send method. - */ -goog.net.Jsonp.prototype.cancel = function(request) { - if (request) { - if (request.deferred_) { - request.deferred_.cancel(); - } - if (request.id_) { - goog.net.Jsonp.cleanup_(request.id_, false); - } - } -}; +goog.exportProperty( + ol.source.Source.prototype, + 'getProperties', + ol.source.Source.prototype.getProperties); +goog.exportProperty( + ol.source.Source.prototype, + 'set', + ol.source.Source.prototype.set); -/** - * Creates a timeout callback that calls the given timeoutCallback with the - * original payload. - * - * @param {string} id The id of the script node. - * @param {Object} payload The payload that was sent to the server. - * @param {Function=} opt_errorCallback The function called on timeout. - * @return {!Function} A zero argument function that handles callback duties. - * @private - */ -goog.net.Jsonp.newErrorHandler_ = function(id, - payload, - opt_errorCallback) { - /** - * When we call across domains with a request, this function is the - * timeout handler. Once it's done executing the user-specified - * error-handler, it removes the script node and original function. - */ - return function() { - goog.net.Jsonp.cleanup_(id, false); - if (opt_errorCallback) { - opt_errorCallback(payload); - } - }; -}; +goog.exportProperty( + ol.source.Source.prototype, + 'setProperties', + ol.source.Source.prototype.setProperties); +goog.exportProperty( + ol.source.Source.prototype, + 'unset', + ol.source.Source.prototype.unset); -/** - * Creates a reply callback that calls the given replyCallback with data - * returned by the server. - * - * @param {string} id The id of the script node. - * @param {Function} replyCallback The function called on reply. - * @return {!Function} A reply callback function. - * @private - */ -goog.net.Jsonp.newReplyHandler_ = function(id, replyCallback) { - /** - * This function is the handler for the all-is-well response. It - * clears the error timeout handler, calls the user's handler, then - * removes the script node and itself. - * - * @param {...Object} var_args The response data sent from the server. - */ - var handler = function(var_args) { - goog.net.Jsonp.cleanup_(id, true); - replyCallback.apply(undefined, arguments); - }; - return handler; -}; +goog.exportProperty( + ol.source.Source.prototype, + 'changed', + ol.source.Source.prototype.changed); +goog.exportProperty( + ol.source.Source.prototype, + 'dispatchEvent', + ol.source.Source.prototype.dispatchEvent); -/** - * Removes the script node and reply handler with the given id. - * - * @param {string} id The id of the script node to be removed. - * @param {boolean} deleteReplyHandler If true, delete the reply handler - * instead of setting it to nullFunction (if we know the callback could - * never be called again). - * @private - */ -goog.net.Jsonp.cleanup_ = function(id, deleteReplyHandler) { - if (goog.global[goog.net.Jsonp.CALLBACKS][id]) { - if (deleteReplyHandler) { - delete goog.global[goog.net.Jsonp.CALLBACKS][id]; - } else { - // Removing the script tag doesn't necessarily prevent the script - // from firing, so we make the callback a noop. - goog.global[goog.net.Jsonp.CALLBACKS][id] = goog.nullFunction; - } - } -}; +goog.exportProperty( + ol.source.Source.prototype, + 'getRevision', + ol.source.Source.prototype.getRevision); +goog.exportProperty( + ol.source.Source.prototype, + 'on', + ol.source.Source.prototype.on); -/** - * Returns URL encoded payload. The payload should be a map of name-value - * pairs, in the form {"foo": 1, "bar": true, ...}. If the map is empty, - * the URI will be unchanged. - * - * <p>The method uses hasOwnProperty() to assure the properties are on the - * object, not on its prototype. - * - * @param {!Object} payload A map of value name pairs to be encoded. - * A value may be specified as an array, in which case a query parameter - * will be created for each value, e.g.: - * {"foo": [1,2]} will encode to "foo=1&foo=2". - * - * @param {!goog.Uri} uri A Uri object onto which the payload key value pairs - * will be encoded. - * - * @return {!goog.Uri} A reference to the Uri sent as a parameter. - * @private - */ -goog.net.Jsonp.addPayloadToUri_ = function(payload, uri) { - for (var name in payload) { - // NOTE(user): Safari/1.3 doesn't have hasOwnProperty(). In that - // case, we iterate over all properties as a very lame workaround. - if (!payload.hasOwnProperty || payload.hasOwnProperty(name)) { - uri.setParameterValues(name, payload[name]); - } - } - return uri; -}; +goog.exportProperty( + ol.source.Source.prototype, + 'once', + ol.source.Source.prototype.once); +goog.exportProperty( + ol.source.Source.prototype, + 'un', + ol.source.Source.prototype.un); -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -// -// This class allows us (Google) to send data from non-Google and thus -// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return -// anything sensitive, such as session or cookie specific data. Return -// only data that you want parties external to Google to have. Also -// NEVER use this method to send data from web pages to untrusted -// servers, or redirects to unknown servers (www.google.com/cache, -// /q=xx&btnl, /url, www.googlepages.com, etc.) -// -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +goog.exportProperty( + ol.source.Source.prototype, + 'unByKey', + ol.source.Source.prototype.unByKey); -goog.provide('ol.source.TileImage'); +goog.exportProperty( + ol.source.Tile.prototype, + 'getAttributions', + ol.source.Tile.prototype.getAttributions); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.ImageTile'); -goog.require('ol.TileCache'); -goog.require('ol.TileState'); -goog.require('ol.proj'); -goog.require('ol.reproj.Tile'); -goog.require('ol.source.UrlTile'); +goog.exportProperty( + ol.source.Tile.prototype, + 'getLogo', + ol.source.Tile.prototype.getLogo); +goog.exportProperty( + ol.source.Tile.prototype, + 'getProjection', + ol.source.Tile.prototype.getProjection); +goog.exportProperty( + ol.source.Tile.prototype, + 'getState', + ol.source.Tile.prototype.getState); -/** - * @classdesc - * Base class for sources providing images divided into a tile grid. - * - * @constructor - * @fires ol.source.TileEvent - * @extends {ol.source.UrlTile} - * @param {olx.source.TileImageOptions} options Image tile options. - * @api - */ -ol.source.TileImage = function(options) { +goog.exportProperty( + ol.source.Tile.prototype, + 'setAttributions', + ol.source.Tile.prototype.setAttributions); - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - opaque: options.opaque, - projection: options.projection, - state: options.state !== undefined ? - /** @type {ol.source.State} */ (options.state) : undefined, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction ? - options.tileLoadFunction : ol.source.TileImage.defaultTileLoadFunction, - tilePixelRatio: options.tilePixelRatio, - tileUrlFunction: options.tileUrlFunction, - url: options.url, - urls: options.urls, - wrapX: options.wrapX - }); +goog.exportProperty( + ol.source.Tile.prototype, + 'get', + ol.source.Tile.prototype.get); - /** - * @protected - * @type {?string} - */ - this.crossOrigin = - options.crossOrigin !== undefined ? options.crossOrigin : null; +goog.exportProperty( + ol.source.Tile.prototype, + 'getKeys', + ol.source.Tile.prototype.getKeys); - /** - * @protected - * @type {function(new: ol.ImageTile, ol.TileCoord, ol.TileState, string, - * ?string, ol.TileLoadFunctionType)} - */ - this.tileClass = options.tileClass !== undefined ? - options.tileClass : ol.ImageTile; +goog.exportProperty( + ol.source.Tile.prototype, + 'getProperties', + ol.source.Tile.prototype.getProperties); - /** - * @protected - * @type {Object.<string, ol.TileCache>} - */ - this.tileCacheForProjection = {}; +goog.exportProperty( + ol.source.Tile.prototype, + 'set', + ol.source.Tile.prototype.set); - /** - * @protected - * @type {Object.<string, ol.tilegrid.TileGrid>} - */ - this.tileGridForProjection = {}; +goog.exportProperty( + ol.source.Tile.prototype, + 'setProperties', + ol.source.Tile.prototype.setProperties); - /** - * @private - * @type {number|undefined} - */ - this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold; +goog.exportProperty( + ol.source.Tile.prototype, + 'unset', + ol.source.Tile.prototype.unset); - /** - * @private - * @type {boolean} - */ - this.renderReprojectionEdges_ = false; -}; -goog.inherits(ol.source.TileImage, ol.source.UrlTile); +goog.exportProperty( + ol.source.Tile.prototype, + 'changed', + ol.source.Tile.prototype.changed); +goog.exportProperty( + ol.source.Tile.prototype, + 'dispatchEvent', + ol.source.Tile.prototype.dispatchEvent); -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.canExpireCache = function() { - if (!ol.ENABLE_RASTER_REPROJECTION) { - return goog.base(this, 'canExpireCache'); - } - var canExpire = this.tileCache.canExpireCache(); - if (canExpire) { - return true; - } else { - return goog.object.some(this.tileCacheForProjection, function(tileCache) { - return tileCache.canExpireCache(); - }); - } -}; +goog.exportProperty( + ol.source.Tile.prototype, + 'getRevision', + ol.source.Tile.prototype.getRevision); +goog.exportProperty( + ol.source.Tile.prototype, + 'on', + ol.source.Tile.prototype.on); -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.expireCache = function(projection, usedTiles) { - if (!ol.ENABLE_RASTER_REPROJECTION) { - goog.base(this, 'expireCache', projection, usedTiles); - return; - } - var usedTileCache = this.getTileCacheForProjection(projection); +goog.exportProperty( + ol.source.Tile.prototype, + 'once', + ol.source.Tile.prototype.once); - this.tileCache.expireCache(this.tileCache == usedTileCache ? usedTiles : {}); - goog.object.forEach(this.tileCacheForProjection, function(tileCache) { - tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {}); - }); -}; +goog.exportProperty( + ol.source.Tile.prototype, + 'un', + ol.source.Tile.prototype.un); +goog.exportProperty( + ol.source.Tile.prototype, + 'unByKey', + ol.source.Tile.prototype.unByKey); -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.getTileGridForProjection = function(projection) { - if (!ol.ENABLE_RASTER_REPROJECTION) { - return goog.base(this, 'getTileGridForProjection', projection); - } - var thisProj = this.getProjection(); - if (this.tileGrid && - (!thisProj || ol.proj.equivalent(thisProj, projection))) { - return this.tileGrid; - } else { - var projKey = goog.getUid(projection).toString(); - if (!(projKey in this.tileGridForProjection)) { - this.tileGridForProjection[projKey] = - ol.tilegrid.getForProjection(projection); - } - return this.tileGridForProjection[projKey]; - } -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getTileGrid', + ol.source.UrlTile.prototype.getTileGrid); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getAttributions', + ol.source.UrlTile.prototype.getAttributions); -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.getTileCacheForProjection = function(projection) { - if (!ol.ENABLE_RASTER_REPROJECTION) { - return goog.base(this, 'getTileCacheForProjection', projection); - } - var thisProj = this.getProjection(); - if (!thisProj || ol.proj.equivalent(thisProj, projection)) { - return this.tileCache; - } else { - var projKey = goog.getUid(projection).toString(); - if (!(projKey in this.tileCacheForProjection)) { - this.tileCacheForProjection[projKey] = new ol.TileCache(); - } - return this.tileCacheForProjection[projKey]; - } -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getLogo', + ol.source.UrlTile.prototype.getLogo); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getProjection', + ol.source.UrlTile.prototype.getProjection); -/** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {string} key The key set on the tile. - * @return {ol.Tile} Tile. - * @private - */ -ol.source.TileImage.prototype.createTile_ = - function(z, x, y, pixelRatio, projection, key) { - var tileCoord = [z, x, y]; - var urlTileCoord = this.getTileCoordForTileUrlFunction( - tileCoord, projection); - var tileUrl = urlTileCoord ? - this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined; - var tile = new this.tileClass( - tileCoord, - tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, - tileUrl !== undefined ? tileUrl : '', - this.crossOrigin, - this.tileLoadFunction); - tile.key = key; - goog.events.listen(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); - return tile; -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getState', + ol.source.UrlTile.prototype.getState); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'setAttributions', + ol.source.UrlTile.prototype.setAttributions); -/** - * @inheritDoc - */ -ol.source.TileImage.prototype.getTile = - function(z, x, y, pixelRatio, projection) { - if (!ol.ENABLE_RASTER_REPROJECTION || - !this.getProjection() || - !projection || - ol.proj.equivalent(this.getProjection(), projection)) { - return this.getTileInternal(z, x, y, pixelRatio, projection); - } else { - var cache = this.getTileCacheForProjection(projection); - var tileCoordKey = this.getKeyZXY(z, x, y); - if (cache.containsKey(tileCoordKey)) { - return /** @type {!ol.Tile} */ (cache.get(tileCoordKey)); - } else { - var sourceProjection = this.getProjection(); - var sourceTileGrid = this.getTileGridForProjection(sourceProjection); - var targetTileGrid = this.getTileGridForProjection(projection); - var tile = new ol.reproj.Tile( - sourceProjection, sourceTileGrid, - projection, targetTileGrid, - z, x, y, this.getTilePixelRatio(), - goog.bind(function(z, x, y, pixelRatio) { - return this.getTileInternal(z, x, y, pixelRatio, sourceProjection); - }, this), this.reprojectionErrorThreshold_, - this.renderReprojectionEdges_); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'get', + ol.source.UrlTile.prototype.get); - cache.set(tileCoordKey, tile); - return tile; - } - } -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getKeys', + ol.source.UrlTile.prototype.getKeys); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getProperties', + ol.source.UrlTile.prototype.getProperties); -/** - * @param {number} z Tile coordinate z. - * @param {number} x Tile coordinate x. - * @param {number} y Tile coordinate y. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {!ol.Tile} Tile. - * @protected - */ -ol.source.TileImage.prototype.getTileInternal = - function(z, x, y, pixelRatio, projection) { - var /** @type {ol.Tile} */ tile = null; - var tileCoordKey = this.getKeyZXY(z, x, y); - var paramsKey = this.getKeyParams(); - if (!this.tileCache.containsKey(tileCoordKey)) { - goog.asserts.assert(projection, 'argument projection is truthy'); - tile = this.createTile_(z, x, y, pixelRatio, projection, paramsKey); - this.tileCache.set(tileCoordKey, tile); - } else { - tile = /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); - if (tile.key != paramsKey) { - // The source's params changed. If the tile has an interim tile and if we - // can use it then we use it. Otherwise we create a new tile. In both - // cases we attempt to assign an interim tile to the new tile. - var /** @type {ol.Tile} */ interimTile = tile; - if (tile.interimTile && tile.interimTile.key == paramsKey) { - goog.asserts.assert(tile.interimTile.getState() == ol.TileState.LOADED); - goog.asserts.assert(tile.interimTile.interimTile === null); - tile = tile.interimTile; - if (interimTile.getState() == ol.TileState.LOADED) { - tile.interimTile = interimTile; - } - } else { - tile = this.createTile_(z, x, y, pixelRatio, projection, paramsKey); - if (interimTile.getState() == ol.TileState.LOADED) { - tile.interimTile = interimTile; - } else if (interimTile.interimTile && - interimTile.interimTile.getState() == ol.TileState.LOADED) { - tile.interimTile = interimTile.interimTile; - interimTile.interimTile = null; - } - } - if (tile.interimTile) { - tile.interimTile.interimTile = null; - } - this.tileCache.replace(tileCoordKey, tile); - } - } - goog.asserts.assert(tile); - return tile; -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'set', + ol.source.UrlTile.prototype.set); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'setProperties', + ol.source.UrlTile.prototype.setProperties); -/** - * Sets whether to render reprojection edges or not (usually for debugging). - * @param {boolean} render Render the edges. - * @api - */ -ol.source.TileImage.prototype.setRenderReprojectionEdges = function(render) { - if (!ol.ENABLE_RASTER_REPROJECTION || - this.renderReprojectionEdges_ == render) { - return; - } - this.renderReprojectionEdges_ = render; - goog.object.forEach(this.tileCacheForProjection, function(tileCache) { - tileCache.clear(); - }); - this.changed(); -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'unset', + ol.source.UrlTile.prototype.unset); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'changed', + ol.source.UrlTile.prototype.changed); -/** - * Sets the tile grid to use when reprojecting the tiles to the given - * projection instead of the default tile grid for the projection. - * - * This can be useful when the default tile grid cannot be created - * (e.g. projection has no extent defined) or - * for optimization reasons (custom tile size, resolutions, ...). - * - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {ol.tilegrid.TileGrid} tilegrid Tile grid to use for the projection. - * @api - */ -ol.source.TileImage.prototype.setTileGridForProjection = - function(projection, tilegrid) { - if (ol.ENABLE_RASTER_REPROJECTION) { - var proj = ol.proj.get(projection); - if (proj) { - var projKey = goog.getUid(proj).toString(); - if (!(projKey in this.tileGridForProjection)) { - this.tileGridForProjection[projKey] = tilegrid; - } - } - } -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'dispatchEvent', + ol.source.UrlTile.prototype.dispatchEvent); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'getRevision', + ol.source.UrlTile.prototype.getRevision); -/** - * @param {ol.ImageTile} imageTile Image tile. - * @param {string} src Source. - */ -ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) { - imageTile.getImage().src = src; -}; +goog.exportProperty( + ol.source.UrlTile.prototype, + 'on', + ol.source.UrlTile.prototype.on); -goog.provide('ol.source.BingMaps'); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'once', + ol.source.UrlTile.prototype.once); -goog.require('goog.Uri'); -goog.require('goog.asserts'); -goog.require('goog.net.Jsonp'); -goog.require('ol.Attribution'); -goog.require('ol.TileRange'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilecoord'); +goog.exportProperty( + ol.source.UrlTile.prototype, + 'un', + ol.source.UrlTile.prototype.un); + +goog.exportProperty( + ol.source.UrlTile.prototype, + 'unByKey', + ol.source.UrlTile.prototype.unByKey); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getTileLoadFunction', + ol.source.TileImage.prototype.getTileLoadFunction); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getTileUrlFunction', + ol.source.TileImage.prototype.getTileUrlFunction); -/** - * @classdesc - * Layer source for Bing Maps tile data. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.BingMapsOptions} options Bing Maps options. - * @api stable - */ -ol.source.BingMaps = function(options) { +goog.exportProperty( + ol.source.TileImage.prototype, + 'getUrls', + ol.source.TileImage.prototype.getUrls); - goog.base(this, { - crossOrigin: 'anonymous', - opaque: true, - projection: ol.proj.get('EPSG:3857'), - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - state: ol.source.State.LOADING, - tileLoadFunction: options.tileLoadFunction, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); +goog.exportProperty( + ol.source.TileImage.prototype, + 'setTileLoadFunction', + ol.source.TileImage.prototype.setTileLoadFunction); - /** - * @private - * @type {string} - */ - this.culture_ = options.culture !== undefined ? options.culture : 'en-us'; +goog.exportProperty( + ol.source.TileImage.prototype, + 'setTileUrlFunction', + ol.source.TileImage.prototype.setTileUrlFunction); - /** - * @private - * @type {number} - */ - this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1; +goog.exportProperty( + ol.source.TileImage.prototype, + 'setUrl', + ol.source.TileImage.prototype.setUrl); - var uri = new goog.Uri( - 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' + - options.imagerySet); +goog.exportProperty( + ol.source.TileImage.prototype, + 'setUrls', + ol.source.TileImage.prototype.setUrls); - var jsonp = new goog.net.Jsonp(uri, 'jsonp'); - jsonp.send({ - 'include': 'ImageryProviders', - 'uriScheme': 'https', - 'key': options.key - }, goog.bind(this.handleImageryMetadataResponse, this)); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getTileGrid', + ol.source.TileImage.prototype.getTileGrid); -}; -goog.inherits(ol.source.BingMaps, ol.source.TileImage); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getAttributions', + ol.source.TileImage.prototype.getAttributions); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getLogo', + ol.source.TileImage.prototype.getLogo); -/** - * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’ - * Terms Of Use. - * @const - * @type {ol.Attribution} - * @api - */ -ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({ - html: '<a class="ol-attribution-bing-tos" ' + - 'href="http://www.microsoft.com/maps/product/terms.html">' + - 'Terms of Use</a>' -}); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getProjection', + ol.source.TileImage.prototype.getProjection); +goog.exportProperty( + ol.source.TileImage.prototype, + 'getState', + ol.source.TileImage.prototype.getState); -/** - * @param {BingMapsImageryMetadataResponse} response Response. - */ -ol.source.BingMaps.prototype.handleImageryMetadataResponse = - function(response) { +goog.exportProperty( + ol.source.TileImage.prototype, + 'setAttributions', + ol.source.TileImage.prototype.setAttributions); - if (response.statusCode != 200 || - response.statusDescription != 'OK' || - response.authenticationResultCode != 'ValidCredentials' || - response.resourceSets.length != 1 || - response.resourceSets[0].resources.length != 1) { - this.setState(ol.source.State.ERROR); - return; - } +goog.exportProperty( + ol.source.TileImage.prototype, + 'get', + ol.source.TileImage.prototype.get); - var brandLogoUri = response.brandLogoUri; - if (brandLogoUri.indexOf('https') == -1) { - brandLogoUri = brandLogoUri.replace('http', 'https'); - } - //var copyright = response.copyright; // FIXME do we need to display this? - var resource = response.resourceSets[0].resources[0]; - goog.asserts.assert(resource.imageWidth == resource.imageHeight, - 'resource has imageWidth equal to imageHeight, i.e. is square'); - var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_; +goog.exportProperty( + ol.source.TileImage.prototype, + 'getKeys', + ol.source.TileImage.prototype.getKeys); - var sourceProjection = this.getProjection(); - var extent = ol.tilegrid.extentFromProjection(sourceProjection); - var tileSize = resource.imageWidth == resource.imageHeight ? - resource.imageWidth : [resource.imageWidth, resource.imageHeight]; - var tileGrid = ol.tilegrid.createXYZ({ - extent: extent, - minZoom: resource.zoomMin, - maxZoom: maxZoom, - tileSize: tileSize - }); - this.tileGrid = tileGrid; +goog.exportProperty( + ol.source.TileImage.prototype, + 'getProperties', + ol.source.TileImage.prototype.getProperties); - var culture = this.culture_; - this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( - resource.imageUrlSubdomains.map(function(subdomain) { - var quadKeyTileCoord = [0, 0, 0]; - var imageUrl = resource.imageUrl - .replace('{subdomain}', subdomain) - .replace('{culture}', culture); - return ( - /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - goog.asserts.assert(ol.proj.equivalent( - projection, sourceProjection), - 'projections are equivalent'); - if (!tileCoord) { - return undefined; - } else { - ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1], - -tileCoord[2] - 1, quadKeyTileCoord); - return imageUrl.replace('{quadkey}', ol.tilecoord.quadKey( - quadKeyTileCoord)); - } - }); - })); +goog.exportProperty( + ol.source.TileImage.prototype, + 'set', + ol.source.TileImage.prototype.set); - if (resource.imageryProviders) { - var transform = ol.proj.getTransformFromProjections( - ol.proj.get('EPSG:4326'), this.getProjection()); +goog.exportProperty( + ol.source.TileImage.prototype, + 'setProperties', + ol.source.TileImage.prototype.setProperties); - var attributions = resource.imageryProviders.map(function(imageryProvider) { - var html = imageryProvider.attribution; - /** @type {Object.<string, Array.<ol.TileRange>>} */ - var tileRanges = {}; - imageryProvider.coverageAreas.forEach(function(coverageArea) { - var minZ = coverageArea.zoomMin; - var maxZ = Math.min(coverageArea.zoomMax, maxZoom); - var bbox = coverageArea.bbox; - var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]]; - var extent = ol.extent.applyTransform(epsg4326Extent, transform); - var tileRange, z, zKey; - for (z = minZ; z <= maxZ; ++z) { - zKey = z.toString(); - tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); - if (zKey in tileRanges) { - tileRanges[zKey].push(tileRange); - } else { - tileRanges[zKey] = [tileRange]; - } - } - }); - return new ol.Attribution({html: html, tileRanges: tileRanges}); - }); - attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION); - this.setAttributions(attributions); - } +goog.exportProperty( + ol.source.TileImage.prototype, + 'unset', + ol.source.TileImage.prototype.unset); - this.setLogo(brandLogoUri); +goog.exportProperty( + ol.source.TileImage.prototype, + 'changed', + ol.source.TileImage.prototype.changed); - this.setState(ol.source.State.READY); +goog.exportProperty( + ol.source.TileImage.prototype, + 'dispatchEvent', + ol.source.TileImage.prototype.dispatchEvent); -}; +goog.exportProperty( + ol.source.TileImage.prototype, + 'getRevision', + ol.source.TileImage.prototype.getRevision); -// FIXME keep cluster cache by resolution ? -// FIXME distance not respected because of the centroid +goog.exportProperty( + ol.source.TileImage.prototype, + 'on', + ol.source.TileImage.prototype.on); -goog.provide('ol.source.Cluster'); +goog.exportProperty( + ol.source.TileImage.prototype, + 'once', + ol.source.TileImage.prototype.once); -goog.require('goog.asserts'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('ol.Feature'); -goog.require('ol.coordinate'); -goog.require('ol.extent'); -goog.require('ol.geom.Point'); -goog.require('ol.source.Vector'); +goog.exportProperty( + ol.source.TileImage.prototype, + 'un', + ol.source.TileImage.prototype.un); +goog.exportProperty( + ol.source.TileImage.prototype, + 'unByKey', + ol.source.TileImage.prototype.unByKey); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setRenderReprojectionEdges', + ol.source.BingMaps.prototype.setRenderReprojectionEdges); -/** - * @classdesc - * Layer source to cluster vector data. - * - * @constructor - * @param {olx.source.ClusterOptions} options - * @extends {ol.source.Vector} - * @api - */ -ol.source.Cluster = function(options) { - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection, - wrapX: options.wrapX - }); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setTileGridForProjection', + ol.source.BingMaps.prototype.setTileGridForProjection); - /** - * @type {number|undefined} - * @private - */ - this.resolution_ = undefined; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getTileLoadFunction', + ol.source.BingMaps.prototype.getTileLoadFunction); - /** - * @type {number} - * @private - */ - this.distance_ = options.distance !== undefined ? options.distance : 20; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getTileUrlFunction', + ol.source.BingMaps.prototype.getTileUrlFunction); - /** - * @type {Array.<ol.Feature>} - * @private - */ - this.features_ = []; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getUrls', + ol.source.BingMaps.prototype.getUrls); - /** - * @type {ol.source.Vector} - * @private - */ - this.source_ = options.source; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setTileLoadFunction', + ol.source.BingMaps.prototype.setTileLoadFunction); - this.source_.on(goog.events.EventType.CHANGE, - ol.source.Cluster.prototype.onSourceChange_, this); -}; -goog.inherits(ol.source.Cluster, ol.source.Vector); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setTileUrlFunction', + ol.source.BingMaps.prototype.setTileUrlFunction); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setUrl', + ol.source.BingMaps.prototype.setUrl); -/** - * Get a reference to the wrapped source. - * @return {ol.source.Vector} Source. - * @api - */ -ol.source.Cluster.prototype.getSource = function() { - return this.source_; -}; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setUrls', + ol.source.BingMaps.prototype.setUrls); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getTileGrid', + ol.source.BingMaps.prototype.getTileGrid); -/** - * @inheritDoc - */ -ol.source.Cluster.prototype.loadFeatures = function(extent, resolution, - projection) { - this.source_.loadFeatures(extent, resolution, projection); - if (resolution !== this.resolution_) { - this.clear(); - this.resolution_ = resolution; - this.cluster_(); - this.addFeatures(this.features_); - } -}; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getAttributions', + ol.source.BingMaps.prototype.getAttributions); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getLogo', + ol.source.BingMaps.prototype.getLogo); -/** - * handle the source changing - * @private - */ -ol.source.Cluster.prototype.onSourceChange_ = function() { - this.clear(); - this.cluster_(); - this.addFeatures(this.features_); - this.changed(); -}; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getProjection', + ol.source.BingMaps.prototype.getProjection); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getState', + ol.source.BingMaps.prototype.getState); -/** - * @private - */ -ol.source.Cluster.prototype.cluster_ = function() { - if (this.resolution_ === undefined) { - return; - } - this.features_.length = 0; - var extent = ol.extent.createEmpty(); - var mapDistance = this.distance_ * this.resolution_; - var features = this.source_.getFeatures(); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setAttributions', + ol.source.BingMaps.prototype.setAttributions); - /** - * @type {Object.<string, boolean>} - */ - var clustered = {}; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'get', + ol.source.BingMaps.prototype.get); - for (var i = 0, ii = features.length; i < ii; i++) { - var feature = features[i]; - if (!goog.object.containsKey(clustered, goog.getUid(feature).toString())) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry instanceof ol.geom.Point, - 'feature geometry is a ol.geom.Point instance'); - var coordinates = geometry.getCoordinates(); - ol.extent.createOrUpdateFromCoordinate(coordinates, extent); - ol.extent.buffer(extent, mapDistance, extent); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getKeys', + ol.source.BingMaps.prototype.getKeys); - var neighbors = this.source_.getFeaturesInExtent(extent); - goog.asserts.assert(neighbors.length >= 1, 'at least one neighbor found'); - neighbors = neighbors.filter(function(neighbor) { - var uid = goog.getUid(neighbor).toString(); - if (!goog.object.containsKey(clustered, uid)) { - clustered[uid] = true; - return true; - } else { - return false; - } - }); - this.features_.push(this.createCluster_(neighbors)); - } - } - goog.asserts.assert( - goog.object.getCount(clustered) == this.source_.getFeatures().length, - 'number of clustered equals number of features in the source'); -}; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getProperties', + ol.source.BingMaps.prototype.getProperties); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'set', + ol.source.BingMaps.prototype.set); -/** - * @param {Array.<ol.Feature>} features Features - * @return {ol.Feature} - * @private - */ -ol.source.Cluster.prototype.createCluster_ = function(features) { - var length = features.length; - var centroid = [0, 0]; - for (var i = 0; i < length; i++) { - var geometry = features[i].getGeometry(); - goog.asserts.assert(geometry instanceof ol.geom.Point, - 'feature geometry is a ol.geom.Point instance'); - var coordinates = geometry.getCoordinates(); - ol.coordinate.add(centroid, coordinates); - } - ol.coordinate.scale(centroid, 1 / length); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'setProperties', + ol.source.BingMaps.prototype.setProperties); - var cluster = new ol.Feature(new ol.geom.Point(centroid)); - cluster.set('features', features); - return cluster; -}; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'unset', + ol.source.BingMaps.prototype.unset); -goog.provide('ol.source.ImageMapGuide'); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'changed', + ol.source.BingMaps.prototype.changed); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.uri.utils'); -goog.require('ol.Image'); -goog.require('ol.ImageLoadFunctionType'); -goog.require('ol.extent'); -goog.require('ol.source.Image'); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'dispatchEvent', + ol.source.BingMaps.prototype.dispatchEvent); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'getRevision', + ol.source.BingMaps.prototype.getRevision); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'on', + ol.source.BingMaps.prototype.on); -/** - * @classdesc - * Source for images from Mapguide servers - * - * @constructor - * @fires ol.source.ImageEvent - * @extends {ol.source.Image} - * @param {olx.source.ImageMapGuideOptions} options Options. - * @api stable - */ -ol.source.ImageMapGuide = function(options) { +goog.exportProperty( + ol.source.BingMaps.prototype, + 'once', + ol.source.BingMaps.prototype.once); - goog.base(this, { - projection: options.projection, - resolutions: options.resolutions - }); +goog.exportProperty( + ol.source.BingMaps.prototype, + 'un', + ol.source.BingMaps.prototype.un); - /** - * @private - * @type {?string} - */ - this.crossOrigin_ = - options.crossOrigin !== undefined ? options.crossOrigin : null; +goog.exportProperty( + ol.source.BingMaps.prototype, + 'unByKey', + ol.source.BingMaps.prototype.unByKey); - /** - * @private - * @type {number} - */ - this.displayDpi_ = options.displayDpi !== undefined ? - options.displayDpi : 96; +goog.exportProperty( + ol.source.Vector.prototype, + 'getAttributions', + ol.source.Vector.prototype.getAttributions); - /** - * @private - * @type {Object} - */ - this.params_ = options.params !== undefined ? options.params : {}; +goog.exportProperty( + ol.source.Vector.prototype, + 'getLogo', + ol.source.Vector.prototype.getLogo); - /** - * @private - * @type {string|undefined} - */ - this.url_ = options.url; +goog.exportProperty( + ol.source.Vector.prototype, + 'getProjection', + ol.source.Vector.prototype.getProjection); - /** - * @private - * @type {ol.ImageLoadFunctionType} - */ - this.imageLoadFunction_ = options.imageLoadFunction !== undefined ? - options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; +goog.exportProperty( + ol.source.Vector.prototype, + 'getState', + ol.source.Vector.prototype.getState); - /** - * @private - * @type {boolean} - */ - this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; +goog.exportProperty( + ol.source.Vector.prototype, + 'setAttributions', + ol.source.Vector.prototype.setAttributions); - /** - * @private - * @type {number} - */ - this.metersPerUnit_ = options.metersPerUnit !== undefined ? - options.metersPerUnit : 1; +goog.exportProperty( + ol.source.Vector.prototype, + 'get', + ol.source.Vector.prototype.get); - /** - * @private - * @type {number} - */ - this.ratio_ = options.ratio !== undefined ? options.ratio : 1; +goog.exportProperty( + ol.source.Vector.prototype, + 'getKeys', + ol.source.Vector.prototype.getKeys); - /** - * @private - * @type {boolean} - */ - this.useOverlay_ = options.useOverlay !== undefined ? - options.useOverlay : false; +goog.exportProperty( + ol.source.Vector.prototype, + 'getProperties', + ol.source.Vector.prototype.getProperties); - /** - * @private - * @type {ol.Image} - */ - this.image_ = null; +goog.exportProperty( + ol.source.Vector.prototype, + 'set', + ol.source.Vector.prototype.set); - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; +goog.exportProperty( + ol.source.Vector.prototype, + 'setProperties', + ol.source.Vector.prototype.setProperties); -}; -goog.inherits(ol.source.ImageMapGuide, ol.source.Image); +goog.exportProperty( + ol.source.Vector.prototype, + 'unset', + ol.source.Vector.prototype.unset); +goog.exportProperty( + ol.source.Vector.prototype, + 'changed', + ol.source.Vector.prototype.changed); -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api stable - */ -ol.source.ImageMapGuide.prototype.getParams = function() { - return this.params_; -}; +goog.exportProperty( + ol.source.Vector.prototype, + 'dispatchEvent', + ol.source.Vector.prototype.dispatchEvent); +goog.exportProperty( + ol.source.Vector.prototype, + 'getRevision', + ol.source.Vector.prototype.getRevision); -/** - * @inheritDoc - */ -ol.source.ImageMapGuide.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - resolution = this.findNearestResolution(resolution); - pixelRatio = this.hidpi_ ? pixelRatio : 1; +goog.exportProperty( + ol.source.Vector.prototype, + 'on', + ol.source.Vector.prototype.on); - var image = this.image_; - if (image && - this.renderedRevision_ == this.getRevision() && - image.getResolution() == resolution && - image.getPixelRatio() == pixelRatio && - ol.extent.containsExtent(image.getExtent(), extent)) { - return image; - } +goog.exportProperty( + ol.source.Vector.prototype, + 'once', + ol.source.Vector.prototype.once); - if (this.ratio_ != 1) { - extent = extent.slice(); - ol.extent.scaleFromCenter(extent, this.ratio_); - } - var width = ol.extent.getWidth(extent) / resolution; - var height = ol.extent.getHeight(extent) / resolution; - var size = [width * pixelRatio, height * pixelRatio]; +goog.exportProperty( + ol.source.Vector.prototype, + 'un', + ol.source.Vector.prototype.un); - if (this.url_ !== undefined) { - var imageUrl = this.getUrl(this.url_, this.params_, extent, size, - projection); - image = new ol.Image(extent, resolution, pixelRatio, - this.getAttributions(), imageUrl, this.crossOrigin_, - this.imageLoadFunction_); - goog.events.listen(image, goog.events.EventType.CHANGE, - this.handleImageChange, false, this); - } else { - image = null; - } - this.image_ = image; - this.renderedRevision_ = this.getRevision(); +goog.exportProperty( + ol.source.Vector.prototype, + 'unByKey', + ol.source.Vector.prototype.unByKey); - return image; -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'addFeature', + ol.source.Cluster.prototype.addFeature); +goog.exportProperty( + ol.source.Cluster.prototype, + 'addFeatures', + ol.source.Cluster.prototype.addFeatures); -/** - * Return the image load function of the source. - * @return {ol.ImageLoadFunctionType} The image load function. - * @api - */ -ol.source.ImageMapGuide.prototype.getImageLoadFunction = function() { - return this.imageLoadFunction_; -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'clear', + ol.source.Cluster.prototype.clear); + +goog.exportProperty( + ol.source.Cluster.prototype, + 'forEachFeature', + ol.source.Cluster.prototype.forEachFeature); + +goog.exportProperty( + ol.source.Cluster.prototype, + 'forEachFeatureInExtent', + ol.source.Cluster.prototype.forEachFeatureInExtent); + +goog.exportProperty( + ol.source.Cluster.prototype, + 'forEachFeatureIntersectingExtent', + ol.source.Cluster.prototype.forEachFeatureIntersectingExtent); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getFeaturesCollection', + ol.source.Cluster.prototype.getFeaturesCollection); -/** - * @param {ol.Extent} extent The map extents. - * @param {ol.Size} size The viewport size. - * @param {number} metersPerUnit The meters-per-unit value. - * @param {number} dpi The display resolution. - * @return {number} The computed map scale. - */ -ol.source.ImageMapGuide.getScale = function(extent, size, metersPerUnit, dpi) { - var mcsW = ol.extent.getWidth(extent); - var mcsH = ol.extent.getHeight(extent); - var devW = size[0]; - var devH = size[1]; - var mpp = 0.0254 / dpi; - if (devH * mcsW > devW * mcsH) { - return mcsW * metersPerUnit / (devW * mpp); // width limited - } else { - return mcsH * metersPerUnit / (devH * mpp); // height limited - } -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'getFeatures', + ol.source.Cluster.prototype.getFeatures); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getFeaturesAtCoordinate', + ol.source.Cluster.prototype.getFeaturesAtCoordinate); -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.ImageMapGuide.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.changed(); -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'getFeaturesInExtent', + ol.source.Cluster.prototype.getFeaturesInExtent); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getClosestFeatureToCoordinate', + ol.source.Cluster.prototype.getClosestFeatureToCoordinate); -/** - * @param {string} baseUrl The mapagent url. - * @param {Object.<string, string|number>} params Request parameters. - * @param {ol.Extent} extent Extent. - * @param {ol.Size} size Size. - * @param {ol.proj.Projection} projection Projection. - * @return {string} The mapagent map image request URL. - */ -ol.source.ImageMapGuide.prototype.getUrl = - function(baseUrl, params, extent, size, projection) { - var scale = ol.source.ImageMapGuide.getScale(extent, size, - this.metersPerUnit_, this.displayDpi_); - var center = ol.extent.getCenter(extent); - var baseParams = { - 'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE', - 'VERSION': '2.0.0', - 'LOCALE': 'en', - 'CLIENTAGENT': 'ol.source.ImageMapGuide source', - 'CLIP': '1', - 'SETDISPLAYDPI': this.displayDpi_, - 'SETDISPLAYWIDTH': Math.round(size[0]), - 'SETDISPLAYHEIGHT': Math.round(size[1]), - 'SETVIEWSCALE': scale, - 'SETVIEWCENTERX': center[0], - 'SETVIEWCENTERY': center[1] - }; - goog.object.extend(baseParams, params); - return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams); -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'getExtent', + ol.source.Cluster.prototype.getExtent); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getFeatureById', + ol.source.Cluster.prototype.getFeatureById); -/** - * Set the image load function of the MapGuide source. - * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. - * @api - */ -ol.source.ImageMapGuide.prototype.setImageLoadFunction = function( - imageLoadFunction) { - this.image_ = null; - this.imageLoadFunction_ = imageLoadFunction; - this.changed(); -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'removeFeature', + ol.source.Cluster.prototype.removeFeature); -goog.provide('ol.source.ImageStatic'); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getAttributions', + ol.source.Cluster.prototype.getAttributions); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('ol.Image'); -goog.require('ol.ImageLoadFunctionType'); -goog.require('ol.ImageState'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.Image'); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getLogo', + ol.source.Cluster.prototype.getLogo); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getProjection', + ol.source.Cluster.prototype.getProjection); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getState', + ol.source.Cluster.prototype.getState); -/** - * @classdesc - * A layer source for displaying a single, static image. - * - * @constructor - * @extends {ol.source.Image} - * @param {olx.source.ImageStaticOptions} options Options. - * @api stable - */ -ol.source.ImageStatic = function(options) { +goog.exportProperty( + ol.source.Cluster.prototype, + 'setAttributions', + ol.source.Cluster.prototype.setAttributions); - var attributions = options.attributions !== undefined ? - options.attributions : null; +goog.exportProperty( + ol.source.Cluster.prototype, + 'get', + ol.source.Cluster.prototype.get); - var imageExtent = options.imageExtent; +goog.exportProperty( + ol.source.Cluster.prototype, + 'getKeys', + ol.source.Cluster.prototype.getKeys); - var crossOrigin = options.crossOrigin !== undefined ? - options.crossOrigin : null; +goog.exportProperty( + ol.source.Cluster.prototype, + 'getProperties', + ol.source.Cluster.prototype.getProperties); - var /** @type {ol.ImageLoadFunctionType} */ imageLoadFunction = - options.imageLoadFunction !== undefined ? - options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; +goog.exportProperty( + ol.source.Cluster.prototype, + 'set', + ol.source.Cluster.prototype.set); - goog.base(this, { - attributions: attributions, - logo: options.logo, - projection: ol.proj.get(options.projection) - }); +goog.exportProperty( + ol.source.Cluster.prototype, + 'setProperties', + ol.source.Cluster.prototype.setProperties); - /** - * @private - * @type {ol.Image} - */ - this.image_ = new ol.Image(imageExtent, undefined, 1, attributions, - options.url, crossOrigin, imageLoadFunction); +goog.exportProperty( + ol.source.Cluster.prototype, + 'unset', + ol.source.Cluster.prototype.unset); - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = options.imageSize ? options.imageSize : null; +goog.exportProperty( + ol.source.Cluster.prototype, + 'changed', + ol.source.Cluster.prototype.changed); - goog.events.listen(this.image_, goog.events.EventType.CHANGE, - this.handleImageChange, false, this); +goog.exportProperty( + ol.source.Cluster.prototype, + 'dispatchEvent', + ol.source.Cluster.prototype.dispatchEvent); -}; -goog.inherits(ol.source.ImageStatic, ol.source.Image); +goog.exportProperty( + ol.source.Cluster.prototype, + 'getRevision', + ol.source.Cluster.prototype.getRevision); +goog.exportProperty( + ol.source.Cluster.prototype, + 'on', + ol.source.Cluster.prototype.on); -/** - * @inheritDoc - */ -ol.source.ImageStatic.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { - if (ol.extent.intersects(extent, this.image_.getExtent())) { - return this.image_; - } - return null; -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'once', + ol.source.Cluster.prototype.once); +goog.exportProperty( + ol.source.Cluster.prototype, + 'un', + ol.source.Cluster.prototype.un); -/** - * @inheritDoc - */ -ol.source.ImageStatic.prototype.handleImageChange = function(evt) { - if (this.image_.getState() == ol.ImageState.LOADED) { - var imageExtent = this.image_.getExtent(); - var image = this.image_.getImage(); - var imageWidth, imageHeight; - if (this.imageSize_) { - imageWidth = this.imageSize_[0]; - imageHeight = this.imageSize_[1]; - } else { - imageWidth = image.width; - imageHeight = image.height; - } - var resolution = ol.extent.getHeight(imageExtent) / imageHeight; - var targetWidth = Math.ceil(ol.extent.getWidth(imageExtent) / resolution); - if (targetWidth != imageWidth) { - var canvas = /** @type {HTMLCanvasElement} */ - (document.createElement('canvas')); - canvas.width = targetWidth; - canvas.height = /** @type {number} */ (imageHeight); - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0, imageWidth, imageHeight, - 0, 0, canvas.width, canvas.height); - this.image_.setImage(canvas); - } - } - goog.base(this, 'handleImageChange', evt); -}; +goog.exportProperty( + ol.source.Cluster.prototype, + 'unByKey', + ol.source.Cluster.prototype.unByKey); -goog.provide('ol.source.wms'); -goog.provide('ol.source.wms.ServerType'); +goog.exportProperty( + ol.source.Image.prototype, + 'getAttributions', + ol.source.Image.prototype.getAttributions); +goog.exportProperty( + ol.source.Image.prototype, + 'getLogo', + ol.source.Image.prototype.getLogo); -/** - * Available server types: `'carmentaserver'`, `'geoserver'`, `'mapserver'`, - * `'qgis'`. These are servers that have vendor parameters beyond the WMS - * specification that OpenLayers can make use of. - * @enum {string} - * @api - */ -ol.source.wms.ServerType = { - CARMENTA_SERVER: 'carmentaserver', - GEOSERVER: 'geoserver', - MAPSERVER: 'mapserver', - QGIS: 'qgis' -}; +goog.exportProperty( + ol.source.Image.prototype, + 'getProjection', + ol.source.Image.prototype.getProjection); -// FIXME cannot be shared between maps with different projections +goog.exportProperty( + ol.source.Image.prototype, + 'getState', + ol.source.Image.prototype.getState); -goog.provide('ol.source.ImageWMS'); +goog.exportProperty( + ol.source.Image.prototype, + 'setAttributions', + ol.source.Image.prototype.setAttributions); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.uri.utils'); -goog.require('ol'); -goog.require('ol.Image'); -goog.require('ol.ImageLoadFunctionType'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.Image'); -goog.require('ol.source.wms'); -goog.require('ol.source.wms.ServerType'); +goog.exportProperty( + ol.source.Image.prototype, + 'get', + ol.source.Image.prototype.get); +goog.exportProperty( + ol.source.Image.prototype, + 'getKeys', + ol.source.Image.prototype.getKeys); +goog.exportProperty( + ol.source.Image.prototype, + 'getProperties', + ol.source.Image.prototype.getProperties); -/** - * @classdesc - * Source for WMS servers providing single, untiled images. - * - * @constructor - * @fires ol.source.ImageEvent - * @extends {ol.source.Image} - * @param {olx.source.ImageWMSOptions=} opt_options Options. - * @api stable - */ -ol.source.ImageWMS = function(opt_options) { +goog.exportProperty( + ol.source.Image.prototype, + 'set', + ol.source.Image.prototype.set); - var options = opt_options || {}; +goog.exportProperty( + ol.source.Image.prototype, + 'setProperties', + ol.source.Image.prototype.setProperties); - goog.base(this, { - attributions: options.attributions, - logo: options.logo, - projection: options.projection, - resolutions: options.resolutions - }); +goog.exportProperty( + ol.source.Image.prototype, + 'unset', + ol.source.Image.prototype.unset); - /** - * @private - * @type {?string} - */ - this.crossOrigin_ = - options.crossOrigin !== undefined ? options.crossOrigin : null; +goog.exportProperty( + ol.source.Image.prototype, + 'changed', + ol.source.Image.prototype.changed); - /** - * @private - * @type {string|undefined} - */ - this.url_ = options.url; +goog.exportProperty( + ol.source.Image.prototype, + 'dispatchEvent', + ol.source.Image.prototype.dispatchEvent); - /** - * @private - * @type {ol.ImageLoadFunctionType} - */ - this.imageLoadFunction_ = options.imageLoadFunction !== undefined ? - options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction; +goog.exportProperty( + ol.source.Image.prototype, + 'getRevision', + ol.source.Image.prototype.getRevision); - /** - * @private - * @type {Object} - */ - this.params_ = options.params; +goog.exportProperty( + ol.source.Image.prototype, + 'on', + ol.source.Image.prototype.on); - /** - * @private - * @type {boolean} - */ - this.v13_ = true; - this.updateV13_(); +goog.exportProperty( + ol.source.Image.prototype, + 'once', + ol.source.Image.prototype.once); - /** - * @private - * @type {ol.source.wms.ServerType|undefined} - */ - this.serverType_ = - /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType); +goog.exportProperty( + ol.source.Image.prototype, + 'un', + ol.source.Image.prototype.un); - /** - * @private - * @type {boolean} - */ - this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; +goog.exportProperty( + ol.source.Image.prototype, + 'unByKey', + ol.source.Image.prototype.unByKey); - /** - * @private - * @type {ol.Image} - */ - this.image_ = null; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getAttributions', + ol.source.ImageCanvas.prototype.getAttributions); - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = [0, 0]; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getLogo', + ol.source.ImageCanvas.prototype.getLogo); - /** - * @private - * @type {number} - */ - this.renderedRevision_ = 0; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getProjection', + ol.source.ImageCanvas.prototype.getProjection); - /** - * @private - * @type {number} - */ - this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getState', + ol.source.ImageCanvas.prototype.getState); -}; -goog.inherits(ol.source.ImageWMS, ol.source.Image); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'setAttributions', + ol.source.ImageCanvas.prototype.setAttributions); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'get', + ol.source.ImageCanvas.prototype.get); -/** - * @const - * @type {ol.Size} - * @private - */ -ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101]; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getKeys', + ol.source.ImageCanvas.prototype.getKeys); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getProperties', + ol.source.ImageCanvas.prototype.getProperties); -/** - * Return the GetFeatureInfo URL for the passed coordinate, resolution, and - * projection. Return `undefined` if the GetFeatureInfo URL cannot be - * constructed. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should - * be provided. If `QUERY_LAYERS` is not provided then the layers specified - * in the `LAYERS` parameter will be used. `VERSION` should not be - * specified here. - * @return {string|undefined} GetFeatureInfo URL. - * @api stable - */ -ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = - function(coordinate, resolution, projection, params) { +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'set', + ol.source.ImageCanvas.prototype.set); - goog.asserts.assert(!('VERSION' in params), - 'key VERSION is not allowed in params'); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'setProperties', + ol.source.ImageCanvas.prototype.setProperties); - if (this.url_ === undefined) { - return undefined; - } +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'unset', + ol.source.ImageCanvas.prototype.unset); - var extent = ol.extent.getForViewAndSize( - coordinate, resolution, 0, - ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'changed', + ol.source.ImageCanvas.prototype.changed); - var baseParams = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetFeatureInfo', - 'FORMAT': 'image/png', - 'TRANSPARENT': true, - 'QUERY_LAYERS': this.params_['LAYERS'] - }; - goog.object.extend(baseParams, this.params_, params); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'dispatchEvent', + ol.source.ImageCanvas.prototype.dispatchEvent); - var x = Math.floor((coordinate[0] - extent[0]) / resolution); - var y = Math.floor((extent[3] - coordinate[1]) / resolution); - baseParams[this.v13_ ? 'I' : 'X'] = x; - baseParams[this.v13_ ? 'J' : 'Y'] = y; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'getRevision', + ol.source.ImageCanvas.prototype.getRevision); - return this.getRequestUrl_( - extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_, - 1, ol.proj.get(projection), baseParams); -}; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'on', + ol.source.ImageCanvas.prototype.on); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'once', + ol.source.ImageCanvas.prototype.once); -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api stable - */ -ol.source.ImageWMS.prototype.getParams = function() { - return this.params_; -}; +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'un', + ol.source.ImageCanvas.prototype.un); +goog.exportProperty( + ol.source.ImageCanvas.prototype, + 'unByKey', + ol.source.ImageCanvas.prototype.unByKey); -/** - * @inheritDoc - */ -ol.source.ImageWMS.prototype.getImageInternal = - function(extent, resolution, pixelRatio, projection) { +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getAttributions', + ol.source.ImageMapGuide.prototype.getAttributions); - if (this.url_ === undefined) { - return null; - } +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getLogo', + ol.source.ImageMapGuide.prototype.getLogo); - resolution = this.findNearestResolution(resolution); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getProjection', + ol.source.ImageMapGuide.prototype.getProjection); - if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) { - pixelRatio = 1; - } +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getState', + ol.source.ImageMapGuide.prototype.getState); - extent = extent.slice(); - var centerX = (extent[0] + extent[2]) / 2; - var centerY = (extent[1] + extent[3]) / 2; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'setAttributions', + ol.source.ImageMapGuide.prototype.setAttributions); - var imageResolution = resolution / pixelRatio; - var imageWidth = ol.extent.getWidth(extent) / imageResolution; - var imageHeight = ol.extent.getHeight(extent) / imageResolution; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'get', + ol.source.ImageMapGuide.prototype.get); - var image = this.image_; - if (image && - this.renderedRevision_ == this.getRevision() && - image.getResolution() == resolution && - image.getPixelRatio() == pixelRatio && - ol.extent.containsExtent(image.getExtent(), extent)) { - return image; - } +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getKeys', + ol.source.ImageMapGuide.prototype.getKeys); - if (this.ratio_ != 1) { - var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2; - var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2; - extent[0] = centerX - halfWidth; - extent[1] = centerY - halfHeight; - extent[2] = centerX + halfWidth; - extent[3] = centerY + halfHeight; - } +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getProperties', + ol.source.ImageMapGuide.prototype.getProperties); - var params = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetMap', - 'FORMAT': 'image/png', - 'TRANSPARENT': true - }; - goog.object.extend(params, this.params_); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'set', + ol.source.ImageMapGuide.prototype.set); - this.imageSize_[0] = Math.ceil(imageWidth * this.ratio_); - this.imageSize_[1] = Math.ceil(imageHeight * this.ratio_); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'setProperties', + ol.source.ImageMapGuide.prototype.setProperties); - var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio, - projection, params); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'unset', + ol.source.ImageMapGuide.prototype.unset); - this.image_ = new ol.Image(extent, resolution, pixelRatio, - this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'changed', + ol.source.ImageMapGuide.prototype.changed); - this.renderedRevision_ = this.getRevision(); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'dispatchEvent', + ol.source.ImageMapGuide.prototype.dispatchEvent); - goog.events.listen(this.image_, goog.events.EventType.CHANGE, - this.handleImageChange, false, this); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'getRevision', + ol.source.ImageMapGuide.prototype.getRevision); - return this.image_; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'on', + ol.source.ImageMapGuide.prototype.on); -}; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'once', + ol.source.ImageMapGuide.prototype.once); +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'un', + ol.source.ImageMapGuide.prototype.un); -/** - * Return the image load function of the source. - * @return {ol.ImageLoadFunctionType} The image load function. - * @api - */ -ol.source.ImageWMS.prototype.getImageLoadFunction = function() { - return this.imageLoadFunction_; -}; +goog.exportProperty( + ol.source.ImageMapGuide.prototype, + 'unByKey', + ol.source.ImageMapGuide.prototype.unByKey); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getAttributions', + ol.source.ImageStatic.prototype.getAttributions); -/** - * @param {ol.Extent} extent Extent. - * @param {ol.Size} size Size. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {Object} params Params. - * @return {string} Request URL. - * @private - */ -ol.source.ImageWMS.prototype.getRequestUrl_ = - function(extent, size, pixelRatio, projection, params) { +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getLogo', + ol.source.ImageStatic.prototype.getLogo); - goog.asserts.assert(this.url_ !== undefined, 'url is defined'); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getProjection', + ol.source.ImageStatic.prototype.getProjection); - params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode(); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getState', + ol.source.ImageStatic.prototype.getState); - if (!('STYLES' in this.params_)) { - /* jshint -W053 */ - params['STYLES'] = new String(''); - /* jshint +W053 */ - } +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'setAttributions', + ol.source.ImageStatic.prototype.setAttributions); - if (pixelRatio != 1) { - switch (this.serverType_) { - case ol.source.wms.ServerType.GEOSERVER: - var dpi = (90 * pixelRatio + 0.5) | 0; - if ('FORMAT_OPTIONS' in params) { - params['FORMAT_OPTIONS'] += ';dpi:' + dpi; - } else { - params['FORMAT_OPTIONS'] = 'dpi:' + dpi; - } - break; - case ol.source.wms.ServerType.MAPSERVER: - params['MAP_RESOLUTION'] = 90 * pixelRatio; - break; - case ol.source.wms.ServerType.CARMENTA_SERVER: - case ol.source.wms.ServerType.QGIS: - params['DPI'] = 90 * pixelRatio; - break; - default: - goog.asserts.fail('unknown serverType configured'); - break; - } - } +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'get', + ol.source.ImageStatic.prototype.get); + +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getKeys', + ol.source.ImageStatic.prototype.getKeys); + +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getProperties', + ol.source.ImageStatic.prototype.getProperties); - params['WIDTH'] = size[0]; - params['HEIGHT'] = size[1]; +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'set', + ol.source.ImageStatic.prototype.set); - var axisOrientation = projection.getAxisOrientation(); - var bbox; - if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') { - bbox = [extent[1], extent[0], extent[3], extent[2]]; - } else { - bbox = extent; - } - params['BBOX'] = bbox.join(','); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'setProperties', + ol.source.ImageStatic.prototype.setProperties); - return goog.uri.utils.appendParamsFromMap(this.url_, params); -}; +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'unset', + ol.source.ImageStatic.prototype.unset); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'changed', + ol.source.ImageStatic.prototype.changed); -/** - * Return the URL used for this WMS source. - * @return {string|undefined} URL. - * @api stable - */ -ol.source.ImageWMS.prototype.getUrl = function() { - return this.url_; -}; +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'dispatchEvent', + ol.source.ImageStatic.prototype.dispatchEvent); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'getRevision', + ol.source.ImageStatic.prototype.getRevision); -/** - * Set the image load function of the source. - * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function. - * @api - */ -ol.source.ImageWMS.prototype.setImageLoadFunction = function( - imageLoadFunction) { - this.image_ = null; - this.imageLoadFunction_ = imageLoadFunction; - this.changed(); -}; +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'on', + ol.source.ImageStatic.prototype.on); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'once', + ol.source.ImageStatic.prototype.once); -/** - * Set the URL to use for requests. - * @param {string|undefined} url URL. - * @api stable - */ -ol.source.ImageWMS.prototype.setUrl = function(url) { - if (url != this.url_) { - this.url_ = url; - this.image_ = null; - this.changed(); - } -}; +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'un', + ol.source.ImageStatic.prototype.un); +goog.exportProperty( + ol.source.ImageStatic.prototype, + 'unByKey', + ol.source.ImageStatic.prototype.unByKey); -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.ImageWMS.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.updateV13_(); - this.image_ = null; - this.changed(); -}; +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getAttributions', + ol.source.ImageVector.prototype.getAttributions); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getLogo', + ol.source.ImageVector.prototype.getLogo); -/** - * @private - */ -ol.source.ImageWMS.prototype.updateV13_ = function() { - var version = - goog.object.get(this.params_, 'VERSION', ol.DEFAULT_WMS_VERSION); - this.v13_ = goog.string.compareVersions(version, '1.3') >= 0; -}; +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getProjection', + ol.source.ImageVector.prototype.getProjection); -goog.provide('ol.source.XYZ'); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getState', + ol.source.ImageVector.prototype.getState); -goog.require('ol.source.TileImage'); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'setAttributions', + ol.source.ImageVector.prototype.setAttributions); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'get', + ol.source.ImageVector.prototype.get); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getKeys', + ol.source.ImageVector.prototype.getKeys); -/** - * @classdesc - * Layer source for tile data with URLs in a set XYZ format that are - * defined in a URL template. By default, this follows the widely-used - * Google grid where `x` 0 and `y` 0 are in the top left. Grids like - * TMS where `x` 0 and `y` 0 are in the bottom left can be used by - * using the `{-y}` placeholder in the URL template, so long as the - * source does not have a custom tile grid. In this case, - * {@link ol.source.TileImage} can be used with a `tileUrlFunction` - * such as: - * - * tileUrlFunction: function(coordinate) { - * return 'http://mapserver.com/' + coordinate[0] + '/' + - * coordinate[1] + '/' + coordinate[2] + '.png'; - * } - * - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.XYZOptions} options XYZ options. - * @api stable - */ -ol.source.XYZ = function(options) { - var projection = options.projection !== undefined ? - options.projection : 'EPSG:3857'; +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getProperties', + ol.source.ImageVector.prototype.getProperties); - var tileGrid = options.tileGrid !== undefined ? options.tileGrid : - ol.tilegrid.createXYZ({ - extent: ol.tilegrid.extentFromProjection(projection), - maxZoom: options.maxZoom, - tileSize: options.tileSize - }); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'set', + ol.source.ImageVector.prototype.set); - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - projection: projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileGrid: tileGrid, - tileLoadFunction: options.tileLoadFunction, - tilePixelRatio: options.tilePixelRatio, - tileUrlFunction: options.tileUrlFunction, - url: options.url, - urls: options.urls, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'setProperties', + ol.source.ImageVector.prototype.setProperties); -}; -goog.inherits(ol.source.XYZ, ol.source.TileImage); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'unset', + ol.source.ImageVector.prototype.unset); -goog.provide('ol.source.OSM'); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'changed', + ol.source.ImageVector.prototype.changed); -goog.require('ol.Attribution'); -goog.require('ol.source.XYZ'); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'dispatchEvent', + ol.source.ImageVector.prototype.dispatchEvent); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'getRevision', + ol.source.ImageVector.prototype.getRevision); +goog.exportProperty( + ol.source.ImageVector.prototype, + 'on', + ol.source.ImageVector.prototype.on); -/** - * @classdesc - * Layer source for the OpenStreetMap tile server. - * - * @constructor - * @extends {ol.source.XYZ} - * @param {olx.source.OSMOptions=} opt_options Open Street Map options. - * @api stable - */ -ol.source.OSM = function(opt_options) { +goog.exportProperty( + ol.source.ImageVector.prototype, + 'once', + ol.source.ImageVector.prototype.once); - var options = opt_options || {}; +goog.exportProperty( + ol.source.ImageVector.prototype, + 'un', + ol.source.ImageVector.prototype.un); - var attributions; - if (options.attributions !== undefined) { - attributions = options.attributions; - } else { - attributions = [ol.source.OSM.ATTRIBUTION]; - } +goog.exportProperty( + ol.source.ImageVector.prototype, + 'unByKey', + ol.source.ImageVector.prototype.unByKey); - var crossOrigin = options.crossOrigin !== undefined ? - options.crossOrigin : 'anonymous'; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getAttributions', + ol.source.ImageWMS.prototype.getAttributions); - var url = options.url !== undefined ? - options.url : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getLogo', + ol.source.ImageWMS.prototype.getLogo); - goog.base(this, { - attributions: attributions, - crossOrigin: crossOrigin, - opaque: true, - maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileLoadFunction: options.tileLoadFunction, - url: url, - wrapX: options.wrapX - }); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getProjection', + ol.source.ImageWMS.prototype.getProjection); -}; -goog.inherits(ol.source.OSM, ol.source.XYZ); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getState', + ol.source.ImageWMS.prototype.getState); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'setAttributions', + ol.source.ImageWMS.prototype.setAttributions); -/** - * The attribution containing a link to the OpenStreetMap Copyright and License - * page. - * @const - * @type {ol.Attribution} - * @api - */ -ol.source.OSM.ATTRIBUTION = new ol.Attribution({ - html: '© ' + - '<a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' + - 'contributors.' -}); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'get', + ol.source.ImageWMS.prototype.get); -goog.provide('ol.source.MapQuest'); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getKeys', + ol.source.ImageWMS.prototype.getKeys); -goog.require('goog.asserts'); -goog.require('ol.Attribution'); -goog.require('ol.source.OSM'); -goog.require('ol.source.XYZ'); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getProperties', + ol.source.ImageWMS.prototype.getProperties); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'set', + ol.source.ImageWMS.prototype.set); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'setProperties', + ol.source.ImageWMS.prototype.setProperties); -/** - * @classdesc - * Layer source for the MapQuest tile server. - * - * @constructor - * @extends {ol.source.XYZ} - * @param {olx.source.MapQuestOptions=} opt_options MapQuest options. - * @api stable - */ -ol.source.MapQuest = function(opt_options) { +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'unset', + ol.source.ImageWMS.prototype.unset); - var options = opt_options || {}; - goog.asserts.assert(options.layer in ol.source.MapQuestConfig, - 'known layer configured'); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'changed', + ol.source.ImageWMS.prototype.changed); - var layerConfig = ol.source.MapQuestConfig[options.layer]; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'dispatchEvent', + ol.source.ImageWMS.prototype.dispatchEvent); - /** - * Layer. Possible values are `osm`, `sat`, and `hyb`. - * @type {string} - * @private - */ - this.layer_ = options.layer; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'getRevision', + ol.source.ImageWMS.prototype.getRevision); - var url = options.url !== undefined ? options.url : - 'https://otile{1-4}-s.mqcdn.com/tiles/1.0.0/' + - this.layer_ + '/{z}/{x}/{y}.jpg'; +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'on', + ol.source.ImageWMS.prototype.on); - goog.base(this, { - attributions: layerConfig.attributions, - crossOrigin: 'anonymous', - logo: 'https://developer.mapquest.com/content/osm/mq_logo.png', - maxZoom: layerConfig.maxZoom, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - opaque: true, - tileLoadFunction: options.tileLoadFunction, - url: url - }); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'once', + ol.source.ImageWMS.prototype.once); -}; -goog.inherits(ol.source.MapQuest, ol.source.XYZ); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'un', + ol.source.ImageWMS.prototype.un); +goog.exportProperty( + ol.source.ImageWMS.prototype, + 'unByKey', + ol.source.ImageWMS.prototype.unByKey); -/** - * @const - * @type {ol.Attribution} - */ -ol.source.MapQuest.TILE_ATTRIBUTION = new ol.Attribution({ - html: 'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a>' -}); +goog.exportProperty( + ol.source.XYZ.prototype, + 'setRenderReprojectionEdges', + ol.source.XYZ.prototype.setRenderReprojectionEdges); +goog.exportProperty( + ol.source.XYZ.prototype, + 'setTileGridForProjection', + ol.source.XYZ.prototype.setTileGridForProjection); -/** - * @type {Object.<string, {maxZoom: number, attributions: (Array.<ol.Attribution>)}>} - */ -ol.source.MapQuestConfig = { - 'osm': { - maxZoom: 19, - attributions: [ - ol.source.MapQuest.TILE_ATTRIBUTION, - ol.source.OSM.ATTRIBUTION - ] - }, - 'sat': { - maxZoom: 18, - attributions: [ - ol.source.MapQuest.TILE_ATTRIBUTION, - new ol.Attribution({ - html: 'Portions Courtesy NASA/JPL-Caltech and ' + - 'U.S. Depart. of Agriculture, Farm Service Agency' - }) - ] - }, - 'hyb': { - maxZoom: 18, - attributions: [ - ol.source.MapQuest.TILE_ATTRIBUTION, - ol.source.OSM.ATTRIBUTION - ] - } -}; +goog.exportProperty( + ol.source.XYZ.prototype, + 'getTileLoadFunction', + ol.source.XYZ.prototype.getTileLoadFunction); +goog.exportProperty( + ol.source.XYZ.prototype, + 'getTileUrlFunction', + ol.source.XYZ.prototype.getTileUrlFunction); -/** - * Get the layer of the source, either `osm`, `sat`, or `hyb`. - * @return {string} Layer. - * @api - */ -ol.source.MapQuest.prototype.getLayer = function() { - return this.layer_; -}; +goog.exportProperty( + ol.source.XYZ.prototype, + 'getUrls', + ol.source.XYZ.prototype.getUrls); -goog.provide('ol.source.Raster'); -goog.provide('ol.source.RasterEvent'); -goog.provide('ol.source.RasterEventType'); +goog.exportProperty( + ol.source.XYZ.prototype, + 'setTileLoadFunction', + ol.source.XYZ.prototype.setTileLoadFunction); -goog.require('goog.asserts'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventType'); -goog.require('goog.object'); -goog.require('goog.vec.Mat4'); -goog.require('ol.ImageCanvas'); -goog.require('ol.TileQueue'); -goog.require('ol.dom'); -goog.require('ol.ext.pixelworks'); -goog.require('ol.extent'); -goog.require('ol.layer.Image'); -goog.require('ol.layer.Tile'); -goog.require('ol.raster.OperationType'); -goog.require('ol.renderer.canvas.ImageLayer'); -goog.require('ol.renderer.canvas.TileLayer'); -goog.require('ol.source.Image'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); +goog.exportProperty( + ol.source.XYZ.prototype, + 'setTileUrlFunction', + ol.source.XYZ.prototype.setTileUrlFunction); +goog.exportProperty( + ol.source.XYZ.prototype, + 'setUrl', + ol.source.XYZ.prototype.setUrl); +goog.exportProperty( + ol.source.XYZ.prototype, + 'setUrls', + ol.source.XYZ.prototype.setUrls); -/** - * @classdesc - * A source that transforms data from any number of input sources using an array - * of {@link ol.raster.Operation} functions to transform input pixel values into - * output pixel values. - * - * @constructor - * @extends {ol.source.Image} - * @param {olx.source.RasterOptions} options Options. - * @api - */ -ol.source.Raster = function(options) { +goog.exportProperty( + ol.source.XYZ.prototype, + 'getTileGrid', + ol.source.XYZ.prototype.getTileGrid); - /** - * @private - * @type {*} - */ - this.worker_ = null; +goog.exportProperty( + ol.source.XYZ.prototype, + 'getAttributions', + ol.source.XYZ.prototype.getAttributions); - /** - * @private - * @type {ol.raster.OperationType} - */ - this.operationType_ = options.operationType !== undefined ? - options.operationType : ol.raster.OperationType.PIXEL; +goog.exportProperty( + ol.source.XYZ.prototype, + 'getLogo', + ol.source.XYZ.prototype.getLogo); - /** - * @private - * @type {number} - */ - this.threads_ = options.threads !== undefined ? options.threads : 1; +goog.exportProperty( + ol.source.XYZ.prototype, + 'getProjection', + ol.source.XYZ.prototype.getProjection); - /** - * @private - * @type {Array.<ol.renderer.canvas.Layer>} - */ - this.renderers_ = ol.source.Raster.createRenderers_(options.sources); +goog.exportProperty( + ol.source.XYZ.prototype, + 'getState', + ol.source.XYZ.prototype.getState); - for (var r = 0, rr = this.renderers_.length; r < rr; ++r) { - goog.events.listen(this.renderers_[r], goog.events.EventType.CHANGE, - this.changed, false, this); - } +goog.exportProperty( + ol.source.XYZ.prototype, + 'setAttributions', + ol.source.XYZ.prototype.setAttributions); - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.canvasContext_ = ol.dom.createCanvasContext2D(); +goog.exportProperty( + ol.source.XYZ.prototype, + 'get', + ol.source.XYZ.prototype.get); - /** - * @private - * @type {ol.TileQueue} - */ - this.tileQueue_ = new ol.TileQueue( - function() { return 1; }, - goog.bind(this.changed, this)); +goog.exportProperty( + ol.source.XYZ.prototype, + 'getKeys', + ol.source.XYZ.prototype.getKeys); - var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_); - var layerStates = {}; - for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) { - layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i]; - } +goog.exportProperty( + ol.source.XYZ.prototype, + 'getProperties', + ol.source.XYZ.prototype.getProperties); - /** - * The most recently rendered state. - * @type {?ol.source.Raster.RenderedState} - * @private - */ - this.renderedState_ = null; +goog.exportProperty( + ol.source.XYZ.prototype, + 'set', + ol.source.XYZ.prototype.set); - /** - * The most recently rendered image canvas. - * @type {ol.ImageCanvas} - * @private - */ - this.renderedImageCanvas_ = null; +goog.exportProperty( + ol.source.XYZ.prototype, + 'setProperties', + ol.source.XYZ.prototype.setProperties); - /** - * @private - * @type {olx.FrameState} - */ - this.frameState_ = { - animate: false, - attributions: {}, - coordinateToPixelMatrix: goog.vec.Mat4.createNumber(), - extent: null, - focus: null, - index: 0, - layerStates: layerStates, - layerStatesArray: layerStatesArray, - logos: {}, - pixelRatio: 1, - pixelToCoordinateMatrix: goog.vec.Mat4.createNumber(), - postRenderFunctions: [], - size: [0, 0], - skippedFeatureUids: {}, - tileQueue: this.tileQueue_, - time: Date.now(), - usedTiles: {}, - viewState: /** @type {olx.ViewState} */ ({ - rotation: 0 - }), - viewHints: [], - wantedTiles: {} - }; +goog.exportProperty( + ol.source.XYZ.prototype, + 'unset', + ol.source.XYZ.prototype.unset); - goog.base(this, {}); +goog.exportProperty( + ol.source.XYZ.prototype, + 'changed', + ol.source.XYZ.prototype.changed); - if (options.operation !== undefined) { - this.setOperation(options.operation, options.lib); - } +goog.exportProperty( + ol.source.XYZ.prototype, + 'dispatchEvent', + ol.source.XYZ.prototype.dispatchEvent); -}; -goog.inherits(ol.source.Raster, ol.source.Image); +goog.exportProperty( + ol.source.XYZ.prototype, + 'getRevision', + ol.source.XYZ.prototype.getRevision); +goog.exportProperty( + ol.source.XYZ.prototype, + 'on', + ol.source.XYZ.prototype.on); -/** - * Set the operation. - * @param {ol.raster.Operation} operation New operation. - * @param {Object=} opt_lib Functions that will be available to operations run - * in a worker. - * @api - */ -ol.source.Raster.prototype.setOperation = function(operation, opt_lib) { - this.worker_ = new ol.ext.pixelworks.Processor({ - operation: operation, - imageOps: this.operationType_ === ol.raster.OperationType.IMAGE, - queue: 1, - lib: opt_lib, - threads: this.threads_ - }); - this.changed(); -}; +goog.exportProperty( + ol.source.XYZ.prototype, + 'once', + ol.source.XYZ.prototype.once); +goog.exportProperty( + ol.source.XYZ.prototype, + 'un', + ol.source.XYZ.prototype.un); -/** - * Update the stored frame state. - * @param {ol.Extent} extent The view extent (in map units). - * @param {number} resolution The view resolution. - * @param {ol.proj.Projection} projection The view projection. - * @return {olx.FrameState} The updated frame state. - * @private - */ -ol.source.Raster.prototype.updateFrameState_ = - function(extent, resolution, projection) { +goog.exportProperty( + ol.source.XYZ.prototype, + 'unByKey', + ol.source.XYZ.prototype.unByKey); - var frameState = /** @type {olx.FrameState} */ ( - goog.object.clone(this.frameState_)); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setRenderReprojectionEdges', + ol.source.MapQuest.prototype.setRenderReprojectionEdges); - frameState.viewState = /** @type {olx.ViewState} */ ( - goog.object.clone(frameState.viewState)); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setTileGridForProjection', + ol.source.MapQuest.prototype.setTileGridForProjection); - var center = ol.extent.getCenter(extent); - var width = Math.round(ol.extent.getWidth(extent) / resolution); - var height = Math.round(ol.extent.getHeight(extent) / resolution); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getTileLoadFunction', + ol.source.MapQuest.prototype.getTileLoadFunction); - frameState.extent = extent; - frameState.focus = ol.extent.getCenter(extent); - frameState.size[0] = width; - frameState.size[1] = height; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getTileUrlFunction', + ol.source.MapQuest.prototype.getTileUrlFunction); - var viewState = frameState.viewState; - viewState.center = center; - viewState.projection = projection; - viewState.resolution = resolution; - return frameState; -}; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getUrls', + ol.source.MapQuest.prototype.getUrls); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setTileLoadFunction', + ol.source.MapQuest.prototype.setTileLoadFunction); -/** - * Determine if the most recently rendered image canvas is dirty. - * @param {ol.Extent} extent The requested extent. - * @param {number} resolution The requested resolution. - * @return {boolean} The image is dirty. - * @private - */ -ol.source.Raster.prototype.isDirty_ = function(extent, resolution) { - var state = this.renderedState_; - return !state || - this.getRevision() !== state.revision || - resolution !== state.resolution || - !ol.extent.equals(extent, state.extent); -}; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setTileUrlFunction', + ol.source.MapQuest.prototype.setTileUrlFunction); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setUrl', + ol.source.MapQuest.prototype.setUrl); -/** - * @inheritDoc - */ -ol.source.Raster.prototype.getImage = - function(extent, resolution, pixelRatio, projection) { +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setUrls', + ol.source.MapQuest.prototype.setUrls); + +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getTileGrid', + ol.source.MapQuest.prototype.getTileGrid); - if (!this.allSourcesReady_()) { - return null; - } +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getAttributions', + ol.source.MapQuest.prototype.getAttributions); - if (!this.isDirty_(extent, resolution)) { - return this.renderedImageCanvas_; - } +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getLogo', + ol.source.MapQuest.prototype.getLogo); - var context = this.canvasContext_; - var canvas = context.canvas; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getProjection', + ol.source.MapQuest.prototype.getProjection); - var width = Math.round(ol.extent.getWidth(extent) / resolution); - var height = Math.round(ol.extent.getHeight(extent) / resolution); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getState', + ol.source.MapQuest.prototype.getState); - if (width !== canvas.width || - height !== canvas.height) { - canvas.width = width; - canvas.height = height; - } +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setAttributions', + ol.source.MapQuest.prototype.setAttributions); - var frameState = this.updateFrameState_(extent, resolution, projection); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'get', + ol.source.MapQuest.prototype.get); - var imageCanvas = new ol.ImageCanvas( - extent, resolution, 1, this.getAttributions(), canvas, - this.composeFrame_.bind(this, frameState)); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getKeys', + ol.source.MapQuest.prototype.getKeys); - this.renderedImageCanvas_ = imageCanvas; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getProperties', + ol.source.MapQuest.prototype.getProperties); - this.renderedState_ = { - extent: extent, - resolution: resolution, - revision: this.getRevision() - }; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'set', + ol.source.MapQuest.prototype.set); - return imageCanvas; -}; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'setProperties', + ol.source.MapQuest.prototype.setProperties); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'unset', + ol.source.MapQuest.prototype.unset); -/** - * Determine if all sources are ready. - * @return {boolean} All sources are ready. - * @private - */ -ol.source.Raster.prototype.allSourcesReady_ = function() { - var ready = true; - var source; - for (var i = 0, ii = this.renderers_.length; i < ii; ++i) { - source = this.renderers_[i].getLayer().getSource(); - if (source.getState() !== ol.source.State.READY) { - ready = false; - break; - } - } - return ready; -}; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'changed', + ol.source.MapQuest.prototype.changed); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'dispatchEvent', + ol.source.MapQuest.prototype.dispatchEvent); -/** - * Compose the frame. This renders data from all sources, runs pixel-wise - * operations, and renders the result to the stored canvas context. - * @param {olx.FrameState} frameState The frame state. - * @param {function(Error)} callback Called when composition is complete. - * @private - */ -ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) { - var len = this.renderers_.length; - var imageDatas = new Array(len); - for (var i = 0; i < len; ++i) { - var imageData = ol.source.Raster.getImageData_( - this.renderers_[i], frameState, frameState.layerStatesArray[i]); - if (imageData) { - imageDatas[i] = imageData; - } else { - // image not yet ready - return; - } - } +goog.exportProperty( + ol.source.MapQuest.prototype, + 'getRevision', + ol.source.MapQuest.prototype.getRevision); - var data = {}; - this.dispatchEvent(new ol.source.RasterEvent( - ol.source.RasterEventType.BEFOREOPERATIONS, frameState, data)); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'on', + ol.source.MapQuest.prototype.on); - this.worker_.process(imageDatas, data, - this.onWorkerComplete_.bind(this, frameState, callback)); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'once', + ol.source.MapQuest.prototype.once); - frameState.tileQueue.loadMoreTiles(16, 16); -}; +goog.exportProperty( + ol.source.MapQuest.prototype, + 'un', + ol.source.MapQuest.prototype.un); +goog.exportProperty( + ol.source.MapQuest.prototype, + 'unByKey', + ol.source.MapQuest.prototype.unByKey); -/** - * Called when pixel processing is complete. - * @param {olx.FrameState} frameState The frame state. - * @param {function(Error)} callback Called when rendering is complete. - * @param {Error} err Any error during processing. - * @param {ImageData} output The output image data. - * @param {Object} data The user data. - * @private - */ -ol.source.Raster.prototype.onWorkerComplete_ = - function(frameState, callback, err, output, data) { - if (err) { - callback(err); - return; - } - if (!output) { - // job aborted - return; - } +goog.exportProperty( + ol.source.OSM.prototype, + 'setRenderReprojectionEdges', + ol.source.OSM.prototype.setRenderReprojectionEdges); - this.dispatchEvent(new ol.source.RasterEvent( - ol.source.RasterEventType.AFTEROPERATIONS, frameState, data)); +goog.exportProperty( + ol.source.OSM.prototype, + 'setTileGridForProjection', + ol.source.OSM.prototype.setTileGridForProjection); - var resolution = frameState.viewState.resolution / frameState.pixelRatio; - if (!this.isDirty_(frameState.extent, resolution)) { - this.canvasContext_.putImageData(output, 0, 0); - } +goog.exportProperty( + ol.source.OSM.prototype, + 'getTileLoadFunction', + ol.source.OSM.prototype.getTileLoadFunction); - callback(null); -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'getTileUrlFunction', + ol.source.OSM.prototype.getTileUrlFunction); +goog.exportProperty( + ol.source.OSM.prototype, + 'getUrls', + ol.source.OSM.prototype.getUrls); -/** - * Get image data from a renderer. - * @param {ol.renderer.canvas.Layer} renderer Layer renderer. - * @param {olx.FrameState} frameState The frame state. - * @param {ol.layer.LayerState} layerState The layer state. - * @return {ImageData} The image data. - * @private - */ -ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) { - renderer.prepareFrame(frameState, layerState); - // We should be able to call renderer.composeFrame(), but this is inefficient - // for tiled sources (we've already rendered to an intermediate canvas in the - // prepareFrame call and we don't need to render again to the output canvas). - // TODO: make all canvas renderers render to a single canvas - var image = renderer.getImage(); - if (!image) { - return null; - } - var imageTransform = renderer.getImageTransform(); - var dx = Math.round(goog.vec.Mat4.getElement(imageTransform, 0, 3)); - var dy = Math.round(goog.vec.Mat4.getElement(imageTransform, 1, 3)); - var width = frameState.size[0]; - var height = frameState.size[1]; - if (image instanceof Image) { - if (!ol.source.Raster.context_) { - ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); - } else { - var canvas = ol.source.Raster.context_.canvas; - if (canvas.width !== width || canvas.height !== height) { - ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height); - } else { - ol.source.Raster.context_.clearRect(0, 0, width, height); - } - } - var dw = Math.round( - image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0)); - var dh = Math.round( - image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1)); - ol.source.Raster.context_.drawImage(image, dx, dy, dw, dh); - return ol.source.Raster.context_.getImageData(0, 0, width, height); - } else { - return image.getContext('2d').getImageData(-dx, -dy, width, height); - } -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'setTileLoadFunction', + ol.source.OSM.prototype.setTileLoadFunction); +goog.exportProperty( + ol.source.OSM.prototype, + 'setTileUrlFunction', + ol.source.OSM.prototype.setTileUrlFunction); -/** - * A reusable canvas context. - * @type {CanvasRenderingContext2D} - * @private - */ -ol.source.Raster.context_ = null; +goog.exportProperty( + ol.source.OSM.prototype, + 'setUrl', + ol.source.OSM.prototype.setUrl); +goog.exportProperty( + ol.source.OSM.prototype, + 'setUrls', + ol.source.OSM.prototype.setUrls); -/** - * Get a list of layer states from a list of renderers. - * @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers. - * @return {Array.<ol.layer.LayerState>} The layer states. - * @private - */ -ol.source.Raster.getLayerStatesArray_ = function(renderers) { - return renderers.map(function(renderer) { - return renderer.getLayer().getLayerState(); - }); -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'getTileGrid', + ol.source.OSM.prototype.getTileGrid); +goog.exportProperty( + ol.source.OSM.prototype, + 'getAttributions', + ol.source.OSM.prototype.getAttributions); -/** - * Create renderers for all sources. - * @param {Array.<ol.source.Source>} sources The sources. - * @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers. - * @private - */ -ol.source.Raster.createRenderers_ = function(sources) { - var len = sources.length; - var renderers = new Array(len); - for (var i = 0; i < len; ++i) { - renderers[i] = ol.source.Raster.createRenderer_(sources[i]); - } - return renderers; -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'getLogo', + ol.source.OSM.prototype.getLogo); +goog.exportProperty( + ol.source.OSM.prototype, + 'getProjection', + ol.source.OSM.prototype.getProjection); -/** - * Create a renderer for the provided source. - * @param {ol.source.Source} source The source. - * @return {ol.renderer.canvas.Layer} The renderer. - * @private - */ -ol.source.Raster.createRenderer_ = function(source) { - var renderer = null; - if (source instanceof ol.source.Tile) { - renderer = ol.source.Raster.createTileRenderer_(source); - } else if (source instanceof ol.source.Image) { - renderer = ol.source.Raster.createImageRenderer_(source); - } else { - goog.asserts.fail('Unsupported source type: ' + source); - } - return renderer; -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'getState', + ol.source.OSM.prototype.getState); +goog.exportProperty( + ol.source.OSM.prototype, + 'setAttributions', + ol.source.OSM.prototype.setAttributions); -/** - * Create an image renderer for the provided source. - * @param {ol.source.Image} source The source. - * @return {ol.renderer.canvas.Layer} The renderer. - * @private - */ -ol.source.Raster.createImageRenderer_ = function(source) { - var layer = new ol.layer.Image({source: source}); - return new ol.renderer.canvas.ImageLayer(layer); -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'get', + ol.source.OSM.prototype.get); +goog.exportProperty( + ol.source.OSM.prototype, + 'getKeys', + ol.source.OSM.prototype.getKeys); -/** - * Create a tile renderer for the provided source. - * @param {ol.source.Tile} source The source. - * @return {ol.renderer.canvas.Layer} The renderer. - * @private - */ -ol.source.Raster.createTileRenderer_ = function(source) { - var layer = new ol.layer.Tile({source: source}); - return new ol.renderer.canvas.TileLayer(layer); -}; +goog.exportProperty( + ol.source.OSM.prototype, + 'getProperties', + ol.source.OSM.prototype.getProperties); +goog.exportProperty( + ol.source.OSM.prototype, + 'set', + ol.source.OSM.prototype.set); -/** - * @typedef {{revision: number, - * resolution: number, - * extent: ol.Extent}} - */ -ol.source.Raster.RenderedState; +goog.exportProperty( + ol.source.OSM.prototype, + 'setProperties', + ol.source.OSM.prototype.setProperties); +goog.exportProperty( + ol.source.OSM.prototype, + 'unset', + ol.source.OSM.prototype.unset); +goog.exportProperty( + ol.source.OSM.prototype, + 'changed', + ol.source.OSM.prototype.changed); -/** - * @classdesc - * Events emitted by {@link ol.source.Raster} instances are instances of this - * type. - * - * @constructor - * @extends {goog.events.Event} - * @implements {oli.source.RasterEvent} - * @param {string} type Type. - * @param {olx.FrameState} frameState The frame state. - * @param {Object} data An object made available to operations. - */ -ol.source.RasterEvent = function(type, frameState, data) { - goog.base(this, type); +goog.exportProperty( + ol.source.OSM.prototype, + 'dispatchEvent', + ol.source.OSM.prototype.dispatchEvent); - /** - * The raster extent. - * @type {ol.Extent} - * @api - */ - this.extent = frameState.extent; +goog.exportProperty( + ol.source.OSM.prototype, + 'getRevision', + ol.source.OSM.prototype.getRevision); - /** - * The pixel resolution (map units per pixel). - * @type {number} - * @api - */ - this.resolution = frameState.viewState.resolution / frameState.pixelRatio; +goog.exportProperty( + ol.source.OSM.prototype, + 'on', + ol.source.OSM.prototype.on); - /** - * An object made available to all operations. This can be used by operations - * as a storage object (e.g. for calculating statistics). - * @type {Object} - * @api - */ - this.data = data; +goog.exportProperty( + ol.source.OSM.prototype, + 'once', + ol.source.OSM.prototype.once); -}; -goog.inherits(ol.source.RasterEvent, goog.events.Event); +goog.exportProperty( + ol.source.OSM.prototype, + 'un', + ol.source.OSM.prototype.un); +goog.exportProperty( + ol.source.OSM.prototype, + 'unByKey', + ol.source.OSM.prototype.unByKey); -/** - * @enum {string} - */ -ol.source.RasterEventType = { - /** - * Triggered before operations are run. - * @event ol.source.RasterEvent#beforeoperations - * @api - */ - BEFOREOPERATIONS: 'beforeoperations', +goog.exportProperty( + ol.source.Raster.prototype, + 'getAttributions', + ol.source.Raster.prototype.getAttributions); - /** - * Triggered after operations are run. - * @event ol.source.RasterEvent#afteroperations - * @api - */ - AFTEROPERATIONS: 'afteroperations' -}; +goog.exportProperty( + ol.source.Raster.prototype, + 'getLogo', + ol.source.Raster.prototype.getLogo); -goog.provide('ol.source.Stamen'); +goog.exportProperty( + ol.source.Raster.prototype, + 'getProjection', + ol.source.Raster.prototype.getProjection); -goog.require('goog.asserts'); -goog.require('ol.Attribution'); -goog.require('ol.source.OSM'); -goog.require('ol.source.XYZ'); +goog.exportProperty( + ol.source.Raster.prototype, + 'getState', + ol.source.Raster.prototype.getState); +goog.exportProperty( + ol.source.Raster.prototype, + 'setAttributions', + ol.source.Raster.prototype.setAttributions); -/** - * @type {Object.<string, {extension: string, opaque: boolean}>} - */ -ol.source.StamenLayerConfig = { - 'terrain': { - extension: 'jpg', - opaque: true - }, - 'terrain-background': { - extension: 'jpg', - opaque: true - }, - 'terrain-labels': { - extension: 'png', - opaque: false - }, - 'terrain-lines': { - extension: 'png', - opaque: false - }, - 'toner-background': { - extension: 'png', - opaque: true - }, - 'toner': { - extension: 'png', - opaque: true - }, - 'toner-hybrid': { - extension: 'png', - opaque: false - }, - 'toner-labels': { - extension: 'png', - opaque: false - }, - 'toner-lines': { - extension: 'png', - opaque: false - }, - 'toner-lite': { - extension: 'png', - opaque: true - }, - 'watercolor': { - extension: 'jpg', - opaque: true - } -}; +goog.exportProperty( + ol.source.Raster.prototype, + 'get', + ol.source.Raster.prototype.get); +goog.exportProperty( + ol.source.Raster.prototype, + 'getKeys', + ol.source.Raster.prototype.getKeys); -/** - * @type {Object.<string, {minZoom: number, maxZoom: number}>} - */ -ol.source.StamenProviderConfig = { - 'terrain': { - minZoom: 4, - maxZoom: 18 - }, - 'toner': { - minZoom: 0, - maxZoom: 20 - }, - 'watercolor': { - minZoom: 3, - maxZoom: 16 - } -}; +goog.exportProperty( + ol.source.Raster.prototype, + 'getProperties', + ol.source.Raster.prototype.getProperties); +goog.exportProperty( + ol.source.Raster.prototype, + 'set', + ol.source.Raster.prototype.set); +goog.exportProperty( + ol.source.Raster.prototype, + 'setProperties', + ol.source.Raster.prototype.setProperties); -/** - * @classdesc - * Layer source for the Stamen tile server. - * - * @constructor - * @extends {ol.source.XYZ} - * @param {olx.source.StamenOptions} options Stamen options. - * @api stable - */ -ol.source.Stamen = function(options) { +goog.exportProperty( + ol.source.Raster.prototype, + 'unset', + ol.source.Raster.prototype.unset); - var i = options.layer.indexOf('-'); - var provider = i == -1 ? options.layer : options.layer.slice(0, i); - goog.asserts.assert(provider in ol.source.StamenProviderConfig, - 'known provider configured'); - var providerConfig = ol.source.StamenProviderConfig[provider]; +goog.exportProperty( + ol.source.Raster.prototype, + 'changed', + ol.source.Raster.prototype.changed); - goog.asserts.assert(options.layer in ol.source.StamenLayerConfig, - 'known layer configured'); - var layerConfig = ol.source.StamenLayerConfig[options.layer]; +goog.exportProperty( + ol.source.Raster.prototype, + 'dispatchEvent', + ol.source.Raster.prototype.dispatchEvent); - var url = options.url !== undefined ? options.url : - 'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer + - '/{z}/{x}/{y}.' + layerConfig.extension; +goog.exportProperty( + ol.source.Raster.prototype, + 'getRevision', + ol.source.Raster.prototype.getRevision); - goog.base(this, { - attributions: ol.source.Stamen.ATTRIBUTIONS, - crossOrigin: 'anonymous', - maxZoom: providerConfig.maxZoom, - // FIXME uncomment the following when tilegrid supports minZoom - //minZoom: providerConfig.minZoom, - opaque: layerConfig.opaque, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileLoadFunction: options.tileLoadFunction, - url: url - }); +goog.exportProperty( + ol.source.Raster.prototype, + 'on', + ol.source.Raster.prototype.on); -}; -goog.inherits(ol.source.Stamen, ol.source.XYZ); +goog.exportProperty( + ol.source.Raster.prototype, + 'once', + ol.source.Raster.prototype.once); +goog.exportProperty( + ol.source.Raster.prototype, + 'un', + ol.source.Raster.prototype.un); -/** - * @const - * @type {Array.<ol.Attribution>} - */ -ol.source.Stamen.ATTRIBUTIONS = [ - new ol.Attribution({ - html: 'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, ' + - 'under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY' + - ' 3.0</a>.' - }), - ol.source.OSM.ATTRIBUTION -]; +goog.exportProperty( + ol.source.Raster.prototype, + 'unByKey', + ol.source.Raster.prototype.unByKey); -goog.provide('ol.source.TileArcGISRest'); +goog.exportProperty( + ol.source.Stamen.prototype, + 'setRenderReprojectionEdges', + ol.source.Stamen.prototype.setRenderReprojectionEdges); -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.uri.utils'); -goog.require('ol'); -goog.require('ol.TileCoord'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.size'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilecoord'); +goog.exportProperty( + ol.source.Stamen.prototype, + 'setTileGridForProjection', + ol.source.Stamen.prototype.setTileGridForProjection); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getTileLoadFunction', + ol.source.Stamen.prototype.getTileLoadFunction); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getTileUrlFunction', + ol.source.Stamen.prototype.getTileUrlFunction); -/** - * @classdesc - * Layer source for tile data from ArcGIS Rest services. Map and Image - * Services are supported. - * - * For cached ArcGIS services, better performance is available using the - * {@link ol.source.XYZ} data source. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.TileArcGISRestOptions=} opt_options Tile ArcGIS Rest - * options. - * @api - */ -ol.source.TileArcGISRest = function(opt_options) { +goog.exportProperty( + ol.source.Stamen.prototype, + 'getUrls', + ol.source.Stamen.prototype.getUrls); - var options = opt_options || {}; +goog.exportProperty( + ol.source.Stamen.prototype, + 'setTileLoadFunction', + ol.source.Stamen.prototype.setTileLoadFunction); - var params = options.params !== undefined ? options.params : {}; +goog.exportProperty( + ol.source.Stamen.prototype, + 'setTileUrlFunction', + ol.source.Stamen.prototype.setTileUrlFunction); - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - projection: options.projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction, - tileUrlFunction: goog.bind(this.tileUrlFunction_, this), - url: options.url, - urls: options.urls, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); +goog.exportProperty( + ol.source.Stamen.prototype, + 'setUrl', + ol.source.Stamen.prototype.setUrl); - /** - * @private - * @type {Object} - */ - this.params_ = params; +goog.exportProperty( + ol.source.Stamen.prototype, + 'setUrls', + ol.source.Stamen.prototype.setUrls); - /** - * @private - * @type {ol.Extent} - */ - this.tmpExtent_ = ol.extent.createEmpty(); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getTileGrid', + ol.source.Stamen.prototype.getTileGrid); -}; -goog.inherits(ol.source.TileArcGISRest, ol.source.TileImage); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getAttributions', + ol.source.Stamen.prototype.getAttributions); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getLogo', + ol.source.Stamen.prototype.getLogo); -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api - */ -ol.source.TileArcGISRest.prototype.getParams = function() { - return this.params_; -}; +goog.exportProperty( + ol.source.Stamen.prototype, + 'getProjection', + ol.source.Stamen.prototype.getProjection); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getState', + ol.source.Stamen.prototype.getState); -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {ol.Extent} tileExtent Tile extent. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {Object} params Params. - * @return {string|undefined} Request URL. - * @private - */ -ol.source.TileArcGISRest.prototype.getRequestUrl_ = - function(tileCoord, tileSize, tileExtent, - pixelRatio, projection, params) { +goog.exportProperty( + ol.source.Stamen.prototype, + 'setAttributions', + ol.source.Stamen.prototype.setAttributions); - var urls = this.urls; - if (!urls) { - return undefined; - } +goog.exportProperty( + ol.source.Stamen.prototype, + 'get', + ol.source.Stamen.prototype.get); - // ArcGIS Server only wants the numeric portion of the projection ID. - var srid = projection.getCode().split(':').pop(); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getKeys', + ol.source.Stamen.prototype.getKeys); - params['SIZE'] = tileSize[0] + ',' + tileSize[1]; - params['BBOX'] = tileExtent.join(','); - params['BBOXSR'] = srid; - params['IMAGESR'] = srid; - params['DPI'] = Math.round(90 * pixelRatio); +goog.exportProperty( + ol.source.Stamen.prototype, + 'getProperties', + ol.source.Stamen.prototype.getProperties); - var url; - if (urls.length == 1) { - url = urls[0]; - } else { - var index = goog.math.modulo(ol.tilecoord.hash(tileCoord), urls.length); - url = urls[index]; - } +goog.exportProperty( + ol.source.Stamen.prototype, + 'set', + ol.source.Stamen.prototype.set); - if (!goog.string.endsWith(url, '/')) { - url = url + '/'; - } +goog.exportProperty( + ol.source.Stamen.prototype, + 'setProperties', + ol.source.Stamen.prototype.setProperties); - // If a MapServer, use export. If an ImageServer, use exportImage. - if (goog.string.endsWith(url, 'MapServer/')) { - url = url + 'export'; - } - else if (goog.string.endsWith(url, 'ImageServer/')) { - url = url + 'exportImage'; - } - else { - goog.asserts.fail('Unknown Rest Service', url); - } +goog.exportProperty( + ol.source.Stamen.prototype, + 'unset', + ol.source.Stamen.prototype.unset); - return goog.uri.utils.appendParamsFromMap(url, params); -}; +goog.exportProperty( + ol.source.Stamen.prototype, + 'changed', + ol.source.Stamen.prototype.changed); +goog.exportProperty( + ol.source.Stamen.prototype, + 'dispatchEvent', + ol.source.Stamen.prototype.dispatchEvent); -/** - * @param {number} z Z. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.Size} Size. - */ -ol.source.TileArcGISRest.prototype.getTilePixelSize = - function(z, pixelRatio, projection) { - var tileSize = goog.base(this, 'getTilePixelSize', z, pixelRatio, projection); - if (pixelRatio == 1) { - return tileSize; - } else { - return ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } -}; +goog.exportProperty( + ol.source.Stamen.prototype, + 'getRevision', + ol.source.Stamen.prototype.getRevision); +goog.exportProperty( + ol.source.Stamen.prototype, + 'on', + ol.source.Stamen.prototype.on); -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - * @private - */ -ol.source.TileArcGISRest.prototype.tileUrlFunction_ = - function(tileCoord, pixelRatio, projection) { +goog.exportProperty( + ol.source.Stamen.prototype, + 'once', + ol.source.Stamen.prototype.once); - var tileGrid = this.getTileGrid(); - if (!tileGrid) { - tileGrid = this.getTileGridForProjection(projection); - } +goog.exportProperty( + ol.source.Stamen.prototype, + 'un', + ol.source.Stamen.prototype.un); - if (tileGrid.getResolutions().length <= tileCoord[0]) { - return undefined; - } +goog.exportProperty( + ol.source.Stamen.prototype, + 'unByKey', + ol.source.Stamen.prototype.unByKey); - var tileExtent = tileGrid.getTileCoordExtent( - tileCoord, this.tmpExtent_); - var tileSize = ol.size.toSize( - tileGrid.getTileSize(tileCoord[0]), this.tmpSize); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setRenderReprojectionEdges', + ol.source.TileArcGISRest.prototype.setRenderReprojectionEdges); - if (pixelRatio != 1) { - tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setTileGridForProjection', + ol.source.TileArcGISRest.prototype.setTileGridForProjection); - // Apply default params and override with user specified values. - var baseParams = { - 'F': 'image', - 'FORMAT': 'PNG32', - 'TRANSPARENT': true - }; - goog.object.extend(baseParams, this.params_); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getTileLoadFunction', + ol.source.TileArcGISRest.prototype.getTileLoadFunction); - return this.getRequestUrl_(tileCoord, tileSize, tileExtent, - pixelRatio, projection, baseParams); -}; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getTileUrlFunction', + ol.source.TileArcGISRest.prototype.getTileUrlFunction); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getUrls', + ol.source.TileArcGISRest.prototype.getUrls); -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.TileArcGISRest.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.changed(); -}; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setTileLoadFunction', + ol.source.TileArcGISRest.prototype.setTileLoadFunction); -goog.provide('ol.source.TileDebug'); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setTileUrlFunction', + ol.source.TileArcGISRest.prototype.setTileUrlFunction); -goog.require('ol.Tile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileState'); -goog.require('ol.dom'); -goog.require('ol.size'); -goog.require('ol.source.Tile'); -goog.require('ol.tilecoord'); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setUrl', + ol.source.TileArcGISRest.prototype.setUrl); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setUrls', + ol.source.TileArcGISRest.prototype.setUrls); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getTileGrid', + ol.source.TileArcGISRest.prototype.getTileGrid); -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {string} text Text. - * @private - */ -ol.DebugTile_ = function(tileCoord, tileSize, text) { +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getAttributions', + ol.source.TileArcGISRest.prototype.getAttributions); - goog.base(this, tileCoord, ol.TileState.LOADED); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getLogo', + ol.source.TileArcGISRest.prototype.getLogo); - /** - * @private - * @type {ol.Size} - */ - this.tileSize_ = tileSize; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getProjection', + ol.source.TileArcGISRest.prototype.getProjection); - /** - * @private - * @type {string} - */ - this.text_ = text; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getState', + ol.source.TileArcGISRest.prototype.getState); - /** - * @private - * @type {Object.<number, HTMLCanvasElement>} - */ - this.canvasByContext_ = {}; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setAttributions', + ol.source.TileArcGISRest.prototype.setAttributions); -}; -goog.inherits(ol.DebugTile_, ol.Tile); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'get', + ol.source.TileArcGISRest.prototype.get); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getKeys', + ol.source.TileArcGISRest.prototype.getKeys); -/** - * Get the image element for this tile. - * @param {Object=} opt_context Optional context. Only used by the DOM - * renderer. - * @return {HTMLCanvasElement} Image. - */ -ol.DebugTile_.prototype.getImage = function(opt_context) { - var key = opt_context !== undefined ? goog.getUid(opt_context) : -1; - if (key in this.canvasByContext_) { - return this.canvasByContext_[key]; - } else { +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getProperties', + ol.source.TileArcGISRest.prototype.getProperties); - var tileSize = this.tileSize_; - var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'set', + ol.source.TileArcGISRest.prototype.set); - context.strokeStyle = 'black'; - context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'setProperties', + ol.source.TileArcGISRest.prototype.setProperties); - context.fillStyle = 'black'; - context.textAlign = 'center'; - context.textBaseline = 'middle'; - context.font = '24px sans-serif'; - context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'unset', + ol.source.TileArcGISRest.prototype.unset); - this.canvasByContext_[key] = context.canvas; - return context.canvas; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'changed', + ol.source.TileArcGISRest.prototype.changed); - } -}; +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'dispatchEvent', + ol.source.TileArcGISRest.prototype.dispatchEvent); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'getRevision', + ol.source.TileArcGISRest.prototype.getRevision); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'on', + ol.source.TileArcGISRest.prototype.on); -/** - * @classdesc - * A pseudo tile source, which does not fetch tiles from a server, but renders - * a grid outline for the tile grid/projection along with the coordinates for - * each tile. See examples/canvas-tiles for an example. - * - * Uses Canvas context2d, so requires Canvas support. - * - * @constructor - * @extends {ol.source.Tile} - * @param {olx.source.TileDebugOptions} options Debug tile options. - * @api - */ -ol.source.TileDebug = function(options) { +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'once', + ol.source.TileArcGISRest.prototype.once); - goog.base(this, { - opaque: false, - projection: options.projection, - tileGrid: options.tileGrid, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'un', + ol.source.TileArcGISRest.prototype.un); -}; -goog.inherits(ol.source.TileDebug, ol.source.Tile); +goog.exportProperty( + ol.source.TileArcGISRest.prototype, + 'unByKey', + ol.source.TileArcGISRest.prototype.unByKey); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getTileGrid', + ol.source.TileDebug.prototype.getTileGrid); -/** - * @inheritDoc - */ -ol.source.TileDebug.prototype.getTile = function(z, x, y) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey)); - } else { - var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z)); - var tileCoord = [z, x, y]; - var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord); - var text = !textTileCoord ? '' : ol.tilecoord.toString( - this.getTileCoordForTileUrlFunction(textTileCoord)); - var tile = new ol.DebugTile_(tileCoord, tileSize, text); - this.tileCache.set(tileCoordKey, tile); - return tile; - } -}; +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getAttributions', + ol.source.TileDebug.prototype.getAttributions); -// FIXME check order of async callbacks +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getLogo', + ol.source.TileDebug.prototype.getLogo); -/** - * @see http://mapbox.com/developers/api/ - */ +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getProjection', + ol.source.TileDebug.prototype.getProjection); -goog.provide('ol.source.TileJSON'); -goog.provide('ol.tilejson'); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getState', + ol.source.TileDebug.prototype.getState); -goog.require('goog.asserts'); -goog.require('goog.net.Jsonp'); -goog.require('ol.Attribution'); -goog.require('ol.TileRange'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.TileImage'); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'setAttributions', + ol.source.TileDebug.prototype.setAttributions); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'get', + ol.source.TileDebug.prototype.get); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getKeys', + ol.source.TileDebug.prototype.getKeys); -/** - * @classdesc - * Layer source for tile data in TileJSON format. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.TileJSONOptions} options TileJSON options. - * @api stable - */ -ol.source.TileJSON = function(options) { +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getProperties', + ol.source.TileDebug.prototype.getProperties); - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - projection: ol.proj.get('EPSG:3857'), - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - state: ol.source.State.LOADING, - tileLoadFunction: options.tileLoadFunction, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'set', + ol.source.TileDebug.prototype.set); - var request = new goog.net.Jsonp(options.url); - request.send(undefined, goog.bind(this.handleTileJSONResponse, this), - goog.bind(this.handleTileJSONError, this)); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'setProperties', + ol.source.TileDebug.prototype.setProperties); -}; -goog.inherits(ol.source.TileJSON, ol.source.TileImage); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'unset', + ol.source.TileDebug.prototype.unset); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'changed', + ol.source.TileDebug.prototype.changed); -/** - * @protected - * @param {TileJSON} tileJSON Tile JSON. - */ -ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) { +goog.exportProperty( + ol.source.TileDebug.prototype, + 'dispatchEvent', + ol.source.TileDebug.prototype.dispatchEvent); - var epsg4326Projection = ol.proj.get('EPSG:4326'); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'getRevision', + ol.source.TileDebug.prototype.getRevision); - var sourceProjection = this.getProjection(); - var extent; - if (tileJSON.bounds !== undefined) { - var transform = ol.proj.getTransformFromProjections( - epsg4326Projection, sourceProjection); - extent = ol.extent.applyTransform(tileJSON.bounds, transform); - } +goog.exportProperty( + ol.source.TileDebug.prototype, + 'on', + ol.source.TileDebug.prototype.on); - if (tileJSON.scheme !== undefined) { - goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"'); - } - var minZoom = tileJSON.minzoom || 0; - var maxZoom = tileJSON.maxzoom || 22; - var tileGrid = ol.tilegrid.createXYZ({ - extent: ol.tilegrid.extentFromProjection(sourceProjection), - maxZoom: maxZoom, - minZoom: minZoom - }); - this.tileGrid = tileGrid; +goog.exportProperty( + ol.source.TileDebug.prototype, + 'once', + ol.source.TileDebug.prototype.once); - this.tileUrlFunction = - ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid); +goog.exportProperty( + ol.source.TileDebug.prototype, + 'un', + ol.source.TileDebug.prototype.un); - if (tileJSON.attribution !== undefined && !this.getAttributions()) { - var attributionExtent = extent !== undefined ? - extent : epsg4326Projection.getExtent(); - /** @type {Object.<string, Array.<ol.TileRange>>} */ - var tileRanges = {}; - var z, zKey; - for (z = minZoom; z <= maxZoom; ++z) { - zKey = z.toString(); - tileRanges[zKey] = - [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; - } - this.setAttributions([ - new ol.Attribution({ - html: tileJSON.attribution, - tileRanges: tileRanges - }) - ]); - } +goog.exportProperty( + ol.source.TileDebug.prototype, + 'unByKey', + ol.source.TileDebug.prototype.unByKey); - this.setState(ol.source.State.READY); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setRenderReprojectionEdges', + ol.source.TileJSON.prototype.setRenderReprojectionEdges); -}; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setTileGridForProjection', + ol.source.TileJSON.prototype.setTileGridForProjection); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getTileLoadFunction', + ol.source.TileJSON.prototype.getTileLoadFunction); -/** - * @protected - */ -ol.source.TileJSON.prototype.handleTileJSONError = function() { - this.setState(ol.source.State.ERROR); -}; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getTileUrlFunction', + ol.source.TileJSON.prototype.getTileUrlFunction); -goog.provide('ol.source.TileUTFGrid'); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getUrls', + ol.source.TileJSON.prototype.getUrls); -goog.require('goog.asserts'); -goog.require('goog.async.nextTick'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.net.Jsonp'); -goog.require('ol.Attribution'); -goog.require('ol.Tile'); -goog.require('ol.TileState'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.Tile'); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setTileLoadFunction', + ol.source.TileJSON.prototype.setTileLoadFunction); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setTileUrlFunction', + ol.source.TileJSON.prototype.setTileUrlFunction); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setUrl', + ol.source.TileJSON.prototype.setUrl); -/** - * @classdesc - * Layer source for UTFGrid interaction data loaded from TileJSON format. - * - * @constructor - * @extends {ol.source.Tile} - * @param {olx.source.TileUTFGridOptions} options Source options. - * @api - */ -ol.source.TileUTFGrid = function(options) { - goog.base(this, { - projection: ol.proj.get('EPSG:3857'), - state: ol.source.State.LOADING - }); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setUrls', + ol.source.TileJSON.prototype.setUrls); - /** - * @private - * @type {boolean} - */ - this.preemptive_ = options.preemptive !== undefined ? - options.preemptive : true; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getTileGrid', + ol.source.TileJSON.prototype.getTileGrid); - /** - * @private - * @type {!ol.TileUrlFunctionType} - */ - this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getAttributions', + ol.source.TileJSON.prototype.getAttributions); - /** - * @private - * @type {string|undefined} - */ - this.template_ = undefined; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getLogo', + ol.source.TileJSON.prototype.getLogo); - var request = new goog.net.Jsonp(options.url); - request.send(undefined, goog.bind(this.handleTileJSONResponse, this)); -}; -goog.inherits(ol.source.TileUTFGrid, ol.source.Tile); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getProjection', + ol.source.TileJSON.prototype.getProjection); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getState', + ol.source.TileJSON.prototype.getState); -/** - * Return the template from TileJSON. - * @return {string|undefined} The template from TileJSON. - * @api - */ -ol.source.TileUTFGrid.prototype.getTemplate = function() { - return this.template_; -}; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setAttributions', + ol.source.TileJSON.prototype.setAttributions); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'get', + ol.source.TileJSON.prototype.get); -/** - * Calls the callback (synchronously by default) with the available data - * for given coordinate and resolution (or `null` if not yet loaded or - * in case of an error). - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {function(this: T, Object)} callback Callback. - * @param {T=} opt_this The object to use as `this` in the callback. - * @param {boolean=} opt_request If `true` the callback is always async. - * The tile data is requested if not yet loaded. - * @template T - * @api - */ -ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function( - coordinate, resolution, callback, opt_this, opt_request) { - if (this.tileGrid) { - var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution( - coordinate, resolution); - var tile = /** @type {!ol.source.TileUTFGridTile_} */(this.getTile( - tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection())); - tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request); - } else { - if (opt_request === true) { - goog.async.nextTick(function() { - callback.call(opt_this, null); - }); - } else { - callback.call(opt_this, null); - } - } -}; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getKeys', + ol.source.TileJSON.prototype.getKeys); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getProperties', + ol.source.TileJSON.prototype.getProperties); -/** - * TODO: very similar to ol.source.TileJSON#handleTileJSONResponse - * @protected - * @param {TileJSON} tileJSON Tile JSON. - */ -ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) { +goog.exportProperty( + ol.source.TileJSON.prototype, + 'set', + ol.source.TileJSON.prototype.set); - var epsg4326Projection = ol.proj.get('EPSG:4326'); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'setProperties', + ol.source.TileJSON.prototype.setProperties); - var sourceProjection = this.getProjection(); - var extent; - if (tileJSON.bounds !== undefined) { - var transform = ol.proj.getTransformFromProjections( - epsg4326Projection, sourceProjection); - extent = ol.extent.applyTransform(tileJSON.bounds, transform); - } +goog.exportProperty( + ol.source.TileJSON.prototype, + 'unset', + ol.source.TileJSON.prototype.unset); - if (tileJSON.scheme !== undefined) { - goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"'); - } - var minZoom = tileJSON.minzoom || 0; - var maxZoom = tileJSON.maxzoom || 22; - var tileGrid = ol.tilegrid.createXYZ({ - extent: ol.tilegrid.extentFromProjection(sourceProjection), - maxZoom: maxZoom, - minZoom: minZoom - }); - this.tileGrid = tileGrid; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'changed', + ol.source.TileJSON.prototype.changed); - this.template_ = tileJSON.template; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'dispatchEvent', + ol.source.TileJSON.prototype.dispatchEvent); - var grids = tileJSON.grids; - if (!grids) { - this.setState(ol.source.State.ERROR); - return; - } +goog.exportProperty( + ol.source.TileJSON.prototype, + 'getRevision', + ol.source.TileJSON.prototype.getRevision); - this.tileUrlFunction_ = - ol.TileUrlFunction.createFromTemplates(grids, tileGrid); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'on', + ol.source.TileJSON.prototype.on); - if (tileJSON.attribution !== undefined) { - var attributionExtent = extent !== undefined ? - extent : epsg4326Projection.getExtent(); - /** @type {Object.<string, Array.<ol.TileRange>>} */ - var tileRanges = {}; - var z, zKey; - for (z = minZoom; z <= maxZoom; ++z) { - zKey = z.toString(); - tileRanges[zKey] = - [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; - } - this.setAttributions([ - new ol.Attribution({ - html: tileJSON.attribution, - tileRanges: tileRanges - }) - ]); - } +goog.exportProperty( + ol.source.TileJSON.prototype, + 'once', + ol.source.TileJSON.prototype.once); - this.setState(ol.source.State.READY); +goog.exportProperty( + ol.source.TileJSON.prototype, + 'un', + ol.source.TileJSON.prototype.un); -}; +goog.exportProperty( + ol.source.TileJSON.prototype, + 'unByKey', + ol.source.TileJSON.prototype.unByKey); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getTileGrid', + ol.source.TileUTFGrid.prototype.getTileGrid); -/** - * @inheritDoc - */ -ol.source.TileUTFGrid.prototype.getTile = - function(z, x, y, pixelRatio, projection) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey)); - } else { - goog.asserts.assert(projection, 'argument projection is truthy'); - var tileCoord = [z, x, y]; - var urlTileCoord = - this.getTileCoordForTileUrlFunction(tileCoord, projection); - var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection); - var tile = new ol.source.TileUTFGridTile_( - tileCoord, - tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY, - tileUrl !== undefined ? tileUrl : '', - this.tileGrid.getTileCoordExtent(tileCoord), - this.preemptive_); - this.tileCache.set(tileCoordKey, tile); - return tile; - } -}; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getAttributions', + ol.source.TileUTFGrid.prototype.getAttributions); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getLogo', + ol.source.TileUTFGrid.prototype.getLogo); -/** - * @inheritDoc - */ -ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) { - var tileCoordKey = this.getKeyZXY(z, x, y); - if (this.tileCache.containsKey(tileCoordKey)) { - this.tileCache.get(tileCoordKey); - } -}; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getProjection', + ol.source.TileUTFGrid.prototype.getProjection); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getState', + ol.source.TileUTFGrid.prototype.getState); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'setAttributions', + ol.source.TileUTFGrid.prototype.setAttributions); -/** - * @constructor - * @extends {ol.Tile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Image source URI. - * @param {ol.Extent} extent Extent of the tile. - * @param {boolean} preemptive Load the tile when visible (before it's needed). - * @private - */ -ol.source.TileUTFGridTile_ = - function(tileCoord, state, src, extent, preemptive) { +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'get', + ol.source.TileUTFGrid.prototype.get); - goog.base(this, tileCoord, state); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getKeys', + ol.source.TileUTFGrid.prototype.getKeys); - /** - * @private - * @type {string} - */ - this.src_ = src; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getProperties', + ol.source.TileUTFGrid.prototype.getProperties); - /** - * @private - * @type {ol.Extent} - */ - this.extent_ = extent; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'set', + ol.source.TileUTFGrid.prototype.set); - /** - * @private - * @type {boolean} - */ - this.preemptive_ = preemptive; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'setProperties', + ol.source.TileUTFGrid.prototype.setProperties); - /** - * @private - * @type {Array.<string>} - */ - this.grid_ = null; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'unset', + ol.source.TileUTFGrid.prototype.unset); - /** - * @private - * @type {Array.<string>} - */ - this.keys_ = null; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'changed', + ol.source.TileUTFGrid.prototype.changed); - /** - * @private - * @type {Object.<string, Object>|undefined} - */ - this.data_ = null; -}; -goog.inherits(ol.source.TileUTFGridTile_, ol.Tile); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'dispatchEvent', + ol.source.TileUTFGrid.prototype.dispatchEvent); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'getRevision', + ol.source.TileUTFGrid.prototype.getRevision); -/** - * Get the image element for this tile. - * @param {Object=} opt_context Optional context. Only used for the DOM - * renderer. - * @return {Image} Image. - */ -ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) { - return null; -}; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'on', + ol.source.TileUTFGrid.prototype.on); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'once', + ol.source.TileUTFGrid.prototype.once); -/** - * Synchronously returns data at given coordinate (if available). - * @param {ol.Coordinate} coordinate Coordinate. - * @return {Object} - */ -ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) { - if (!this.grid_ || !this.keys_ || !this.data_) { - return null; - } - var xRelative = (coordinate[0] - this.extent_[0]) / - (this.extent_[2] - this.extent_[0]); - var yRelative = (coordinate[1] - this.extent_[1]) / - (this.extent_[3] - this.extent_[1]); +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'un', + ol.source.TileUTFGrid.prototype.un); - var row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)]; +goog.exportProperty( + ol.source.TileUTFGrid.prototype, + 'unByKey', + ol.source.TileUTFGrid.prototype.unByKey); - if (!goog.isString(row)) { - return null; - } +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setRenderReprojectionEdges', + ol.source.TileWMS.prototype.setRenderReprojectionEdges); - var code = row.charCodeAt(Math.floor(xRelative * row.length)); - if (code >= 93) { - code--; - } - if (code >= 35) { - code--; - } - code -= 32; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setTileGridForProjection', + ol.source.TileWMS.prototype.setTileGridForProjection); - return (code in this.keys_) ? this.data_[this.keys_[code]] : null; -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getTileLoadFunction', + ol.source.TileWMS.prototype.getTileLoadFunction); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getTileUrlFunction', + ol.source.TileWMS.prototype.getTileUrlFunction); -/** - * Calls the callback (synchronously by default) with the available data - * for given coordinate (or `null` if not yet loaded). - * @param {ol.Coordinate} coordinate Coordinate. - * @param {function(this: T, Object)} callback Callback. - * @param {T=} opt_this The object to use as `this` in the callback. - * @param {boolean=} opt_request If `true` the callback is always async. - * The tile data is requested if not yet loaded. - * @template T - */ -ol.source.TileUTFGridTile_.prototype.forDataAtCoordinate = - function(coordinate, callback, opt_this, opt_request) { - if (this.state == ol.TileState.IDLE && opt_request === true) { - goog.events.listenOnce(this, goog.events.EventType.CHANGE, function(e) { - callback.call(opt_this, this.getData(coordinate)); - }, false, this); - this.loadInternal_(); - } else { - if (opt_request === true) { - goog.async.nextTick(function() { - callback.call(opt_this, this.getData(coordinate)); - }, this); - } else { - callback.call(opt_this, this.getData(coordinate)); - } - } -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getUrls', + ol.source.TileWMS.prototype.getUrls); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setTileLoadFunction', + ol.source.TileWMS.prototype.setTileLoadFunction); -/** - * @inheritDoc - */ -ol.source.TileUTFGridTile_.prototype.getKey = function() { - return this.src_; -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setTileUrlFunction', + ol.source.TileWMS.prototype.setTileUrlFunction); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setUrl', + ol.source.TileWMS.prototype.setUrl); -/** - * @private - */ -ol.source.TileUTFGridTile_.prototype.handleError_ = function() { - this.state = ol.TileState.ERROR; - this.changed(); -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setUrls', + ol.source.TileWMS.prototype.setUrls); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getTileGrid', + ol.source.TileWMS.prototype.getTileGrid); -/** - * @param {!UTFGridJSON} json - * @private - */ -ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) { - this.grid_ = json.grid; - this.keys_ = json.keys; - this.data_ = json.data; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getAttributions', + ol.source.TileWMS.prototype.getAttributions); - this.state = ol.TileState.EMPTY; - this.changed(); -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getLogo', + ol.source.TileWMS.prototype.getLogo); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getProjection', + ol.source.TileWMS.prototype.getProjection); -/** - * @private - */ -ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() { - if (this.state == ol.TileState.IDLE) { - this.state = ol.TileState.LOADING; - var request = new goog.net.Jsonp(this.src_); - request.send(undefined, goog.bind(this.handleLoad_, this), - goog.bind(this.handleError_, this)); - } -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getState', + ol.source.TileWMS.prototype.getState); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setAttributions', + ol.source.TileWMS.prototype.setAttributions); -/** - * Load not yet loaded URI. - */ -ol.source.TileUTFGridTile_.prototype.load = function() { - if (this.preemptive_) { - this.loadInternal_(); - } -}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'get', + ol.source.TileWMS.prototype.get); -// FIXME add minZoom support -// FIXME add date line wrap (tile coord transform) -// FIXME cannot be shared between maps with different projections +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getKeys', + ol.source.TileWMS.prototype.getKeys); -goog.provide('ol.source.TileWMS'); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getProperties', + ol.source.TileWMS.prototype.getProperties); -goog.require('goog.asserts'); -goog.require('goog.math'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.uri.utils'); -goog.require('ol'); -goog.require('ol.TileCoord'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.size'); -goog.require('ol.source.TileImage'); -goog.require('ol.source.wms'); -goog.require('ol.source.wms.ServerType'); -goog.require('ol.tilecoord'); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'set', + ol.source.TileWMS.prototype.set); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'setProperties', + ol.source.TileWMS.prototype.setProperties); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'unset', + ol.source.TileWMS.prototype.unset); -/** - * @classdesc - * Layer source for tile data from WMS servers. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.TileWMSOptions=} opt_options Tile WMS options. - * @api stable - */ -ol.source.TileWMS = function(opt_options) { +goog.exportProperty( + ol.source.TileWMS.prototype, + 'changed', + ol.source.TileWMS.prototype.changed); - var options = opt_options || {}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'dispatchEvent', + ol.source.TileWMS.prototype.dispatchEvent); - var params = options.params !== undefined ? options.params : {}; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'getRevision', + ol.source.TileWMS.prototype.getRevision); - var transparent = goog.object.get(params, 'TRANSPARENT', true); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'on', + ol.source.TileWMS.prototype.on); - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - opaque: !transparent, - projection: options.projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileGrid: options.tileGrid, - tileLoadFunction: options.tileLoadFunction, - tileUrlFunction: goog.bind(this.tileUrlFunction_, this), - url: options.url, - urls: options.urls, - wrapX: options.wrapX !== undefined ? options.wrapX : true - }); +goog.exportProperty( + ol.source.TileWMS.prototype, + 'once', + ol.source.TileWMS.prototype.once); - /** - * @private - * @type {number} - */ - this.gutter_ = options.gutter !== undefined ? options.gutter : 0; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'un', + ol.source.TileWMS.prototype.un); - /** - * @private - * @type {Object} - */ - this.params_ = params; +goog.exportProperty( + ol.source.TileWMS.prototype, + 'unByKey', + ol.source.TileWMS.prototype.unByKey); - /** - * @private - * @type {boolean} - */ - this.v13_ = true; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getTileLoadFunction', + ol.source.VectorTile.prototype.getTileLoadFunction); - /** - * @private - * @type {ol.source.wms.ServerType|undefined} - */ - this.serverType_ = - /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getTileUrlFunction', + ol.source.VectorTile.prototype.getTileUrlFunction); - /** - * @private - * @type {boolean} - */ - this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getUrls', + ol.source.VectorTile.prototype.getUrls); - /** - * @private - * @type {string} - */ - this.coordKeyPrefix_ = ''; - this.resetCoordKeyPrefix_(); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'setTileLoadFunction', + ol.source.VectorTile.prototype.setTileLoadFunction); - /** - * @private - * @type {ol.Extent} - */ - this.tmpExtent_ = ol.extent.createEmpty(); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'setTileUrlFunction', + ol.source.VectorTile.prototype.setTileUrlFunction); - this.updateV13_(); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'setUrl', + ol.source.VectorTile.prototype.setUrl); -}; -goog.inherits(ol.source.TileWMS, ol.source.TileImage); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'setUrls', + ol.source.VectorTile.prototype.setUrls); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getTileGrid', + ol.source.VectorTile.prototype.getTileGrid); -/** - * Return the GetFeatureInfo URL for the passed coordinate, resolution, and - * projection. Return `undefined` if the GetFeatureInfo URL cannot be - * constructed. - * @param {ol.Coordinate} coordinate Coordinate. - * @param {number} resolution Resolution. - * @param {ol.proj.ProjectionLike} projection Projection. - * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should - * be provided. If `QUERY_LAYERS` is not provided then the layers specified - * in the `LAYERS` parameter will be used. `VERSION` should not be - * specified here. - * @return {string|undefined} GetFeatureInfo URL. - * @api stable - */ -ol.source.TileWMS.prototype.getGetFeatureInfoUrl = - function(coordinate, resolution, projection, params) { +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getAttributions', + ol.source.VectorTile.prototype.getAttributions); - goog.asserts.assert(!('VERSION' in params), - 'key VERSION is not allowed in params'); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getLogo', + ol.source.VectorTile.prototype.getLogo); - var projectionObj = ol.proj.get(projection); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getProjection', + ol.source.VectorTile.prototype.getProjection); - var tileGrid = this.getTileGrid(); - if (!tileGrid) { - tileGrid = this.getTileGridForProjection(projectionObj); - } +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getState', + ol.source.VectorTile.prototype.getState); - var tileCoord = tileGrid.getTileCoordForCoordAndResolution( - coordinate, resolution); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'setAttributions', + ol.source.VectorTile.prototype.setAttributions); - if (tileGrid.getResolutions().length <= tileCoord[0]) { - return undefined; - } +goog.exportProperty( + ol.source.VectorTile.prototype, + 'get', + ol.source.VectorTile.prototype.get); - var tileResolution = tileGrid.getResolution(tileCoord[0]); - var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_); - var tileSize = ol.size.toSize( - tileGrid.getTileSize(tileCoord[0]), this.tmpSize); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getKeys', + ol.source.VectorTile.prototype.getKeys); - var gutter = this.gutter_; - if (gutter !== 0) { - tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize); - tileExtent = ol.extent.buffer(tileExtent, - tileResolution * gutter, tileExtent); - } +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getProperties', + ol.source.VectorTile.prototype.getProperties); - var baseParams = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetFeatureInfo', - 'FORMAT': 'image/png', - 'TRANSPARENT': true, - 'QUERY_LAYERS': this.params_['LAYERS'] - }; - goog.object.extend(baseParams, this.params_, params); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'set', + ol.source.VectorTile.prototype.set); - var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution); - var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'setProperties', + ol.source.VectorTile.prototype.setProperties); - baseParams[this.v13_ ? 'I' : 'X'] = x; - baseParams[this.v13_ ? 'J' : 'Y'] = y; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'unset', + ol.source.VectorTile.prototype.unset); - return this.getRequestUrl_(tileCoord, tileSize, tileExtent, - 1, projectionObj, baseParams); -}; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'changed', + ol.source.VectorTile.prototype.changed); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'dispatchEvent', + ol.source.VectorTile.prototype.dispatchEvent); -/** - * @inheritDoc - */ -ol.source.TileWMS.prototype.getGutter = function() { - return this.gutter_; -}; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'getRevision', + ol.source.VectorTile.prototype.getRevision); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'on', + ol.source.VectorTile.prototype.on); -/** - * @inheritDoc - */ -ol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) { - return this.coordKeyPrefix_ + goog.base(this, 'getKeyZXY', z, x, y); -}; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'once', + ol.source.VectorTile.prototype.once); +goog.exportProperty( + ol.source.VectorTile.prototype, + 'un', + ol.source.VectorTile.prototype.un); -/** - * Get the user-provided params, i.e. those passed to the constructor through - * the "params" option, and possibly updated using the updateParams method. - * @return {Object} Params. - * @api stable - */ -ol.source.TileWMS.prototype.getParams = function() { - return this.params_; -}; +goog.exportProperty( + ol.source.VectorTile.prototype, + 'unByKey', + ol.source.VectorTile.prototype.unByKey); +goog.exportProperty( + ol.source.WMTS.prototype, + 'setRenderReprojectionEdges', + ol.source.WMTS.prototype.setRenderReprojectionEdges); -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.Size} tileSize Tile size. - * @param {ol.Extent} tileExtent Tile extent. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @param {Object} params Params. - * @return {string|undefined} Request URL. - * @private - */ -ol.source.TileWMS.prototype.getRequestUrl_ = - function(tileCoord, tileSize, tileExtent, - pixelRatio, projection, params) { +goog.exportProperty( + ol.source.WMTS.prototype, + 'setTileGridForProjection', + ol.source.WMTS.prototype.setTileGridForProjection); - var urls = this.urls; - if (!urls) { - return undefined; - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'getTileLoadFunction', + ol.source.WMTS.prototype.getTileLoadFunction); - params['WIDTH'] = tileSize[0]; - params['HEIGHT'] = tileSize[1]; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getTileUrlFunction', + ol.source.WMTS.prototype.getTileUrlFunction); - params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode(); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getUrls', + ol.source.WMTS.prototype.getUrls); - if (!('STYLES' in this.params_)) { - /* jshint -W053 */ - params['STYLES'] = new String(''); - /* jshint +W053 */ - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'setTileLoadFunction', + ol.source.WMTS.prototype.setTileLoadFunction); - if (pixelRatio != 1) { - switch (this.serverType_) { - case ol.source.wms.ServerType.GEOSERVER: - var dpi = (90 * pixelRatio + 0.5) | 0; - if ('FORMAT_OPTIONS' in params) { - params['FORMAT_OPTIONS'] += ';dpi:' + dpi; - } else { - params['FORMAT_OPTIONS'] = 'dpi:' + dpi; - } - break; - case ol.source.wms.ServerType.MAPSERVER: - params['MAP_RESOLUTION'] = 90 * pixelRatio; - break; - case ol.source.wms.ServerType.CARMENTA_SERVER: - case ol.source.wms.ServerType.QGIS: - params['DPI'] = 90 * pixelRatio; - break; - default: - goog.asserts.fail('unknown serverType configured'); - break; - } - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'setTileUrlFunction', + ol.source.WMTS.prototype.setTileUrlFunction); - var axisOrientation = projection.getAxisOrientation(); - var bbox = tileExtent; - if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') { - var tmp; - tmp = tileExtent[0]; - bbox[0] = tileExtent[1]; - bbox[1] = tmp; - tmp = tileExtent[2]; - bbox[2] = tileExtent[3]; - bbox[3] = tmp; - } - params['BBOX'] = bbox.join(','); +goog.exportProperty( + ol.source.WMTS.prototype, + 'setUrl', + ol.source.WMTS.prototype.setUrl); + +goog.exportProperty( + ol.source.WMTS.prototype, + 'setUrls', + ol.source.WMTS.prototype.setUrls); - var url; - if (urls.length == 1) { - url = urls[0]; - } else { - var index = goog.math.modulo(ol.tilecoord.hash(tileCoord), urls.length); - url = urls[index]; - } - return goog.uri.utils.appendParamsFromMap(url, params); -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getTileGrid', + ol.source.WMTS.prototype.getTileGrid); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getAttributions', + ol.source.WMTS.prototype.getAttributions); -/** - * @param {number} z Z. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {ol.Size} Size. - */ -ol.source.TileWMS.prototype.getTilePixelSize = - function(z, pixelRatio, projection) { - var tileSize = goog.base(this, 'getTilePixelSize', z, pixelRatio, projection); - if (pixelRatio == 1 || !this.hidpi_ || this.serverType_ === undefined) { - return tileSize; - } else { - return ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getLogo', + ol.source.WMTS.prototype.getLogo); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getProjection', + ol.source.WMTS.prototype.getProjection); -/** - * @private - */ -ol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() { - var i = 0; - var res = []; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getState', + ol.source.WMTS.prototype.getState); - if (this.urls) { - var j, jj; - for (j = 0, jj = this.urls.length; j < jj; ++j) { - res[i++] = this.urls[j]; - } - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'setAttributions', + ol.source.WMTS.prototype.setAttributions); - var key; - for (key in this.params_) { - res[i++] = key + '-' + this.params_[key]; - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'get', + ol.source.WMTS.prototype.get); - this.coordKeyPrefix_ = res.join('#'); -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'getKeys', + ol.source.WMTS.prototype.getKeys); +goog.exportProperty( + ol.source.WMTS.prototype, + 'getProperties', + ol.source.WMTS.prototype.getProperties); -/** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - * @private - */ -ol.source.TileWMS.prototype.tileUrlFunction_ = - function(tileCoord, pixelRatio, projection) { +goog.exportProperty( + ol.source.WMTS.prototype, + 'set', + ol.source.WMTS.prototype.set); - var tileGrid = this.getTileGrid(); - if (!tileGrid) { - tileGrid = this.getTileGridForProjection(projection); - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'setProperties', + ol.source.WMTS.prototype.setProperties); - if (tileGrid.getResolutions().length <= tileCoord[0]) { - return undefined; - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'unset', + ol.source.WMTS.prototype.unset); - if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) { - pixelRatio = 1; - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'changed', + ol.source.WMTS.prototype.changed); - var tileResolution = tileGrid.getResolution(tileCoord[0]); - var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_); - var tileSize = ol.size.toSize( - tileGrid.getTileSize(tileCoord[0]), this.tmpSize); +goog.exportProperty( + ol.source.WMTS.prototype, + 'dispatchEvent', + ol.source.WMTS.prototype.dispatchEvent); - var gutter = this.gutter_; - if (gutter !== 0) { - tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize); - tileExtent = ol.extent.buffer(tileExtent, - tileResolution * gutter, tileExtent); - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'getRevision', + ol.source.WMTS.prototype.getRevision); - if (pixelRatio != 1) { - tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize); - } +goog.exportProperty( + ol.source.WMTS.prototype, + 'on', + ol.source.WMTS.prototype.on); - var baseParams = { - 'SERVICE': 'WMS', - 'VERSION': ol.DEFAULT_WMS_VERSION, - 'REQUEST': 'GetMap', - 'FORMAT': 'image/png', - 'TRANSPARENT': true - }; - goog.object.extend(baseParams, this.params_); +goog.exportProperty( + ol.source.WMTS.prototype, + 'once', + ol.source.WMTS.prototype.once); - return this.getRequestUrl_(tileCoord, tileSize, tileExtent, - pixelRatio, projection, baseParams); -}; +goog.exportProperty( + ol.source.WMTS.prototype, + 'un', + ol.source.WMTS.prototype.un); +goog.exportProperty( + ol.source.WMTS.prototype, + 'unByKey', + ol.source.WMTS.prototype.unByKey); -/** - * Update the user-provided params. - * @param {Object} params Params. - * @api stable - */ -ol.source.TileWMS.prototype.updateParams = function(params) { - goog.object.extend(this.params_, params); - this.resetCoordKeyPrefix_(); - this.updateV13_(); - this.changed(); -}; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setRenderReprojectionEdges', + ol.source.Zoomify.prototype.setRenderReprojectionEdges); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setTileGridForProjection', + ol.source.Zoomify.prototype.setTileGridForProjection); -/** - * @private - */ -ol.source.TileWMS.prototype.updateV13_ = function() { - var version = - goog.object.get(this.params_, 'VERSION', ol.DEFAULT_WMS_VERSION); - this.v13_ = goog.string.compareVersions(version, '1.3') >= 0; -}; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getTileLoadFunction', + ol.source.Zoomify.prototype.getTileLoadFunction); -goog.provide('ol.tilegrid.WMTS'); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getTileUrlFunction', + ol.source.Zoomify.prototype.getTileUrlFunction); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('ol.proj'); -goog.require('ol.tilegrid.TileGrid'); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getUrls', + ol.source.Zoomify.prototype.getUrls); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setTileLoadFunction', + ol.source.Zoomify.prototype.setTileLoadFunction); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setTileUrlFunction', + ol.source.Zoomify.prototype.setTileUrlFunction); -/** - * @classdesc - * Set the grid pattern for sources accessing WMTS tiled-image servers. - * - * @constructor - * @extends {ol.tilegrid.TileGrid} - * @param {olx.tilegrid.WMTSOptions} options WMTS options. - * @struct - * @api - */ -ol.tilegrid.WMTS = function(options) { +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setUrl', + ol.source.Zoomify.prototype.setUrl); - goog.asserts.assert( - options.resolutions.length == options.matrixIds.length, - 'options resolutions and matrixIds must have equal length (%s == %s)', - options.resolutions.length, options.matrixIds.length); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setUrls', + ol.source.Zoomify.prototype.setUrls); - /** - * @private - * @type {!Array.<string>} - */ - this.matrixIds_ = options.matrixIds; - // FIXME: should the matrixIds become optionnal? +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getTileGrid', + ol.source.Zoomify.prototype.getTileGrid); - goog.base(this, { - extent: options.extent, - origin: options.origin, - origins: options.origins, - resolutions: options.resolutions, - tileSize: options.tileSize, - tileSizes: options.tileSizes, - sizes: options.sizes - }); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getAttributions', + ol.source.Zoomify.prototype.getAttributions); -}; -goog.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getLogo', + ol.source.Zoomify.prototype.getLogo); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getProjection', + ol.source.Zoomify.prototype.getProjection); -/** - * @param {number} z Z. - * @return {string} MatrixId.. - */ -ol.tilegrid.WMTS.prototype.getMatrixId = function(z) { - goog.asserts.assert(0 <= z && z < this.matrixIds_.length, - 'attempted to retrive matrixId for illegal z (%s)', z); - return this.matrixIds_[z]; -}; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getState', + ol.source.Zoomify.prototype.getState); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setAttributions', + ol.source.Zoomify.prototype.setAttributions); -/** - * Get the list of matrix identifiers. - * @return {Array.<string>} MatrixIds. - * @api - */ -ol.tilegrid.WMTS.prototype.getMatrixIds = function() { - return this.matrixIds_; -}; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'get', + ol.source.Zoomify.prototype.get); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getKeys', + ol.source.Zoomify.prototype.getKeys); -/** - * Create a tile grid from a WMTS capabilities matrix set. - * @param {Object} matrixSet An object representing a matrixSet in the - * capabilities document. - * @param {ol.Extent=} opt_extent An optional extent to restrict the tile - * ranges the server provides. - * @return {ol.tilegrid.WMTS} WMTS tileGrid instance. - * @api - */ -ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = - function(matrixSet, opt_extent) { +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getProperties', + ol.source.Zoomify.prototype.getProperties); - /** @type {!Array.<number>} */ - var resolutions = []; - /** @type {!Array.<string>} */ - var matrixIds = []; - /** @type {!Array.<ol.Coordinate>} */ - var origins = []; - /** @type {!Array.<ol.Size>} */ - var tileSizes = []; - /** @type {!Array.<ol.Size>} */ - var sizes = []; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'set', + ol.source.Zoomify.prototype.set); - var supportedCRSPropName = 'SupportedCRS'; - var matrixIdsPropName = 'TileMatrix'; - var identifierPropName = 'Identifier'; - var scaleDenominatorPropName = 'ScaleDenominator'; - var topLeftCornerPropName = 'TopLeftCorner'; - var tileWidthPropName = 'TileWidth'; - var tileHeightPropName = 'TileHeight'; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'setProperties', + ol.source.Zoomify.prototype.setProperties); - var projection; - projection = ol.proj.get(matrixSet[supportedCRSPropName].replace( - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3')); - var metersPerUnit = projection.getMetersPerUnit(); - // swap origin x and y coordinates if axis orientation is lat/long - var switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne'; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'unset', + ol.source.Zoomify.prototype.unset); - goog.array.sort(matrixSet[matrixIdsPropName], function(a, b) { - return b[scaleDenominatorPropName] - a[scaleDenominatorPropName]; - }); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'changed', + ol.source.Zoomify.prototype.changed); - matrixSet[matrixIdsPropName].forEach(function(elt, index, array) { - matrixIds.push(elt[identifierPropName]); - var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit; - var tileWidth = elt[tileWidthPropName]; - var tileHeight = elt[tileHeightPropName]; - if (switchOriginXY) { - origins.push([elt[topLeftCornerPropName][1], - elt[topLeftCornerPropName][0]]); - } else { - origins.push(elt[topLeftCornerPropName]); - } - resolutions.push(resolution); - tileSizes.push(tileWidth == tileHeight ? - tileWidth : [tileWidth, tileHeight]); - // top-left origin, so height is negative - sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]); - }); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'dispatchEvent', + ol.source.Zoomify.prototype.dispatchEvent); - return new ol.tilegrid.WMTS({ - extent: opt_extent, - origins: origins, - resolutions: resolutions, - matrixIds: matrixIds, - tileSizes: tileSizes, - sizes: sizes - }); -}; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'getRevision', + ol.source.Zoomify.prototype.getRevision); -goog.provide('ol.source.WMTS'); -goog.provide('ol.source.WMTSRequestEncoding'); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'on', + ol.source.Zoomify.prototype.on); -goog.require('goog.array'); -goog.require('goog.asserts'); -goog.require('goog.object'); -goog.require('goog.uri.utils'); -goog.require('ol.TileUrlFunction'); -goog.require('ol.TileUrlFunctionType'); -goog.require('ol.array'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilegrid.WMTS'); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'once', + ol.source.Zoomify.prototype.once); +goog.exportProperty( + ol.source.Zoomify.prototype, + 'un', + ol.source.Zoomify.prototype.un); -/** - * Request encoding. One of 'KVP', 'REST'. - * @enum {string} - * @api - */ -ol.source.WMTSRequestEncoding = { - KVP: 'KVP', // see spec §8 - REST: 'REST' // see spec §10 -}; +goog.exportProperty( + ol.source.Zoomify.prototype, + 'unByKey', + ol.source.Zoomify.prototype.unByKey); +goog.exportProperty( + ol.reproj.Tile.prototype, + 'getTileCoord', + ol.reproj.Tile.prototype.getTileCoord); +goog.exportProperty( + ol.renderer.Layer.prototype, + 'changed', + ol.renderer.Layer.prototype.changed); -/** - * @classdesc - * Layer source for tile data from WMTS servers. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.WMTSOptions} options WMTS options. - * @api stable - */ -ol.source.WMTS = function(options) { +goog.exportProperty( + ol.renderer.Layer.prototype, + 'dispatchEvent', + ol.renderer.Layer.prototype.dispatchEvent); - // TODO: add support for TileMatrixLimits +goog.exportProperty( + ol.renderer.Layer.prototype, + 'getRevision', + ol.renderer.Layer.prototype.getRevision); - /** - * @private - * @type {string} - */ - this.version_ = options.version !== undefined ? options.version : '1.0.0'; +goog.exportProperty( + ol.renderer.Layer.prototype, + 'on', + ol.renderer.Layer.prototype.on); - /** - * @private - * @type {string} - */ - this.format_ = options.format !== undefined ? options.format : 'image/jpeg'; +goog.exportProperty( + ol.renderer.Layer.prototype, + 'once', + ol.renderer.Layer.prototype.once); - /** - * @private - * @type {Object} - */ - this.dimensions_ = options.dimensions !== undefined ? options.dimensions : {}; +goog.exportProperty( + ol.renderer.Layer.prototype, + 'un', + ol.renderer.Layer.prototype.un); - /** - * @private - * @type {string} - */ - this.dimensionsKey_ = ''; - this.resetDimensionsKey_(); +goog.exportProperty( + ol.renderer.Layer.prototype, + 'unByKey', + ol.renderer.Layer.prototype.unByKey); - /** - * @private - * @type {string} - */ - this.layer_ = options.layer; +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'changed', + ol.renderer.webgl.Layer.prototype.changed); - /** - * @private - * @type {string} - */ - this.matrixSet_ = options.matrixSet; +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'dispatchEvent', + ol.renderer.webgl.Layer.prototype.dispatchEvent); - /** - * @private - * @type {string} - */ - this.style_ = options.style; +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'getRevision', + ol.renderer.webgl.Layer.prototype.getRevision); - var urls = options.urls; - if (urls === undefined && options.url !== undefined) { - urls = ol.TileUrlFunction.expandUrl(options.url); - } +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'on', + ol.renderer.webgl.Layer.prototype.on); - // FIXME: should we guess this requestEncoding from options.url(s) - // structure? that would mean KVP only if a template is not provided. +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'once', + ol.renderer.webgl.Layer.prototype.once); - /** - * @private - * @type {ol.source.WMTSRequestEncoding} - */ - this.requestEncoding_ = options.requestEncoding !== undefined ? - /** @type {ol.source.WMTSRequestEncoding} */ (options.requestEncoding) : - ol.source.WMTSRequestEncoding.KVP; +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'un', + ol.renderer.webgl.Layer.prototype.un); - var requestEncoding = this.requestEncoding_; +goog.exportProperty( + ol.renderer.webgl.Layer.prototype, + 'unByKey', + ol.renderer.webgl.Layer.prototype.unByKey); - // FIXME: should we create a default tileGrid? - // we could issue a getCapabilities xhr to retrieve missing configuration - var tileGrid = options.tileGrid; +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'changed', + ol.renderer.webgl.ImageLayer.prototype.changed); - // context property names are lower case to allow for a case insensitive - // replacement as some services use different naming conventions - var context = { - 'layer': this.layer_, - 'style': this.style_, - 'tilematrixset': this.matrixSet_ - }; +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'dispatchEvent', + ol.renderer.webgl.ImageLayer.prototype.dispatchEvent); - if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { - goog.object.extend(context, { - 'Service': 'WMTS', - 'Request': 'GetTile', - 'Version': this.version_, - 'Format': this.format_ - }); - } +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'getRevision', + ol.renderer.webgl.ImageLayer.prototype.getRevision); - var dimensions = this.dimensions_; +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'on', + ol.renderer.webgl.ImageLayer.prototype.on); - /** - * @param {string} template Template. - * @return {ol.TileUrlFunctionType} Tile URL function. - */ - function createFromWMTSTemplate(template) { +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'once', + ol.renderer.webgl.ImageLayer.prototype.once); - // TODO: we may want to create our own appendParams function so that params - // order conforms to wmts spec guidance, and so that we can avoid to escape - // special template params +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'un', + ol.renderer.webgl.ImageLayer.prototype.un); - template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ? - goog.uri.utils.appendParamsFromMap(template, context) : - template.replace(/\{(\w+?)\}/g, function(m, p) { - return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m; - }); +goog.exportProperty( + ol.renderer.webgl.ImageLayer.prototype, + 'unByKey', + ol.renderer.webgl.ImageLayer.prototype.unByKey); - return ( - /** - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - var localContext = { - 'TileMatrix': tileGrid.getMatrixId(tileCoord[0]), - 'TileCol': tileCoord[1], - 'TileRow': -tileCoord[2] - 1 - }; - goog.object.extend(localContext, dimensions); - var url = template; - if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { - url = goog.uri.utils.appendParamsFromMap(url, localContext); - } else { - url = url.replace(/\{(\w+?)\}/g, function(m, p) { - return localContext[p]; - }); - } - return url; - } - }); - } +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'changed', + ol.renderer.webgl.TileLayer.prototype.changed); - var tileUrlFunction = (urls && urls.length > 0) ? - ol.TileUrlFunction.createFromTileUrlFunctions( - urls.map(createFromWMTSTemplate)) : - ol.TileUrlFunction.nullTileUrlFunction; +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'dispatchEvent', + ol.renderer.webgl.TileLayer.prototype.dispatchEvent); - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - projection: options.projection, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileClass: options.tileClass, - tileGrid: tileGrid, - tileLoadFunction: options.tileLoadFunction, - tilePixelRatio: options.tilePixelRatio, - tileUrlFunction: tileUrlFunction, - urls: urls, - wrapX: options.wrapX !== undefined ? options.wrapX : false - }); +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'getRevision', + ol.renderer.webgl.TileLayer.prototype.getRevision); -}; -goog.inherits(ol.source.WMTS, ol.source.TileImage); +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'on', + ol.renderer.webgl.TileLayer.prototype.on); +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'once', + ol.renderer.webgl.TileLayer.prototype.once); -/** - * Get the dimensions, i.e. those passed to the constructor through the - * "dimensions" option, and possibly updated using the updateDimensions - * method. - * @return {Object} Dimensions. - * @api - */ -ol.source.WMTS.prototype.getDimensions = function() { - return this.dimensions_; -}; +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'un', + ol.renderer.webgl.TileLayer.prototype.un); +goog.exportProperty( + ol.renderer.webgl.TileLayer.prototype, + 'unByKey', + ol.renderer.webgl.TileLayer.prototype.unByKey); -/** - * Return the image format of the WMTS source. - * @return {string} Format. - * @api - */ -ol.source.WMTS.prototype.getFormat = function() { - return this.format_; -}; +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'changed', + ol.renderer.webgl.VectorLayer.prototype.changed); +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'dispatchEvent', + ol.renderer.webgl.VectorLayer.prototype.dispatchEvent); -/** - * @inheritDoc - */ -ol.source.WMTS.prototype.getKeyParams = function() { - return this.dimensionsKey_; -}; +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'getRevision', + ol.renderer.webgl.VectorLayer.prototype.getRevision); +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'on', + ol.renderer.webgl.VectorLayer.prototype.on); -/** - * Return the layer of the WMTS source. - * @return {string} Layer. - * @api - */ -ol.source.WMTS.prototype.getLayer = function() { - return this.layer_; -}; +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'once', + ol.renderer.webgl.VectorLayer.prototype.once); +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'un', + ol.renderer.webgl.VectorLayer.prototype.un); -/** - * Return the matrix set of the WMTS source. - * @return {string} MatrixSet. - * @api - */ -ol.source.WMTS.prototype.getMatrixSet = function() { - return this.matrixSet_; -}; +goog.exportProperty( + ol.renderer.webgl.VectorLayer.prototype, + 'unByKey', + ol.renderer.webgl.VectorLayer.prototype.unByKey); + +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'changed', + ol.renderer.dom.Layer.prototype.changed); + +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'dispatchEvent', + ol.renderer.dom.Layer.prototype.dispatchEvent); +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'getRevision', + ol.renderer.dom.Layer.prototype.getRevision); -/** - * Return the request encoding, either "KVP" or "REST". - * @return {ol.source.WMTSRequestEncoding} Request encoding. - * @api - */ -ol.source.WMTS.prototype.getRequestEncoding = function() { - return this.requestEncoding_; -}; +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'on', + ol.renderer.dom.Layer.prototype.on); +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'once', + ol.renderer.dom.Layer.prototype.once); -/** - * Return the style of the WMTS source. - * @return {string} Style. - * @api - */ -ol.source.WMTS.prototype.getStyle = function() { - return this.style_; -}; +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'un', + ol.renderer.dom.Layer.prototype.un); +goog.exportProperty( + ol.renderer.dom.Layer.prototype, + 'unByKey', + ol.renderer.dom.Layer.prototype.unByKey); -/** - * Return the version of the WMTS source. - * @return {string} Version. - * @api - */ -ol.source.WMTS.prototype.getVersion = function() { - return this.version_; -}; +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'changed', + ol.renderer.dom.ImageLayer.prototype.changed); +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'dispatchEvent', + ol.renderer.dom.ImageLayer.prototype.dispatchEvent); -/** - * @private - */ -ol.source.WMTS.prototype.resetDimensionsKey_ = function() { - var i = 0; - var res = []; - for (var key in this.dimensions_) { - res[i++] = key + '-' + this.dimensions_[key]; - } - this.dimensionsKey_ = res.join('/'); -}; +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'getRevision', + ol.renderer.dom.ImageLayer.prototype.getRevision); +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'on', + ol.renderer.dom.ImageLayer.prototype.on); -/** - * Update the dimensions. - * @param {Object} dimensions Dimensions. - * @api - */ -ol.source.WMTS.prototype.updateDimensions = function(dimensions) { - goog.object.extend(this.dimensions_, dimensions); - this.resetDimensionsKey_(); - this.changed(); -}; +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'once', + ol.renderer.dom.ImageLayer.prototype.once); +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'un', + ol.renderer.dom.ImageLayer.prototype.un); -/** - * Generate source options from a capabilities object. - * @param {Object} wmtsCap An object representing the capabilities document. - * @param {Object} config Configuration properties for the layer. Defaults for - * the layer will apply if not provided. - * - * Required config properties: - * layer - {String} The layer identifier. - * - * Optional config properties: - * matrixSet - {String} The matrix set identifier, required if there is - * more than one matrix set in the layer capabilities. - * projection - {String} The desired CRS when no matrixSet is specified. - * eg: "EPSG:3857". If the desired projection is not available, - * an error is thrown. - * requestEncoding - {String} url encoding format for the layer. Default is the - * first tile url format found in the GetCapabilities response. - * style - {String} The name of the style - * format - {String} Image format for the layer. Default is the first - * format returned in the GetCapabilities response. - * @return {olx.source.WMTSOptions} WMTS source options object. - * @api - */ -ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { +goog.exportProperty( + ol.renderer.dom.ImageLayer.prototype, + 'unByKey', + ol.renderer.dom.ImageLayer.prototype.unByKey); - // TODO: add support for TileMatrixLimits - goog.asserts.assert(config['layer'], - 'config "layer" must not be null'); +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'changed', + ol.renderer.dom.TileLayer.prototype.changed); - var layers = wmtsCap['Contents']['Layer']; - var l = goog.array.find(layers, function(elt, index, array) { - return elt['Identifier'] == config['layer']; - }); - goog.asserts.assert(l, 'found a matching layer in Contents/Layer'); +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'dispatchEvent', + ol.renderer.dom.TileLayer.prototype.dispatchEvent); - goog.asserts.assert(l['TileMatrixSetLink'].length > 0, - 'layer has TileMatrixSetLink'); - var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet']; - var idx, matrixSet; - if (l['TileMatrixSetLink'].length > 1) { - if ('projection' in config) { - idx = goog.array.findIndex(l['TileMatrixSetLink'], - function(elt, index, array) { - var tileMatrixSet = goog.array.find(tileMatrixSets, function(el) { - return el['Identifier'] == elt['TileMatrixSet']; - }); - return tileMatrixSet['SupportedCRS'].replace( - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3' - ) == config['projection']; - }); - } else { - idx = goog.array.findIndex(l['TileMatrixSetLink'], - function(elt, index, array) { - return elt['TileMatrixSet'] == config['matrixSet']; - }); - } - } else { - idx = 0; - } - if (idx < 0) { - idx = 0; - } - matrixSet = /** @type {string} */ - (l['TileMatrixSetLink'][idx]['TileMatrixSet']); +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'getRevision', + ol.renderer.dom.TileLayer.prototype.getRevision); - goog.asserts.assert(matrixSet, 'TileMatrixSet must not be null'); +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'on', + ol.renderer.dom.TileLayer.prototype.on); - var format = /** @type {string} */ (l['Format'][0]); - if ('format' in config) { - format = config['format']; - } - idx = goog.array.findIndex(l['Style'], function(elt, index, array) { - if ('style' in config) { - return elt['Title'] == config['style']; - } else { - return elt['isDefault']; - } - }); - if (idx < 0) { - idx = 0; - } - var style = /** @type {string} */ (l['Style'][idx]['Identifier']); +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'once', + ol.renderer.dom.TileLayer.prototype.once); - var dimensions = {}; - if ('Dimension' in l) { - l['Dimension'].forEach(function(elt, index, array) { - var key = elt['Identifier']; - var value = elt['Default']; - if (value !== undefined) { - goog.asserts.assert(ol.array.includes(elt['Value'], value), - 'default value contained in values'); - } else { - value = elt['Value'][0]; - } - goog.asserts.assert(value !== undefined, 'value could be found'); - dimensions[key] = value; - }); - } +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'un', + ol.renderer.dom.TileLayer.prototype.un); - var matrixSets = wmtsCap['Contents']['TileMatrixSet']; - var matrixSetObj = goog.array.find(matrixSets, function(elt, index, array) { - return elt['Identifier'] == matrixSet; - }); - goog.asserts.assert(matrixSetObj, - 'found matrixSet in Contents/TileMatrixSet'); +goog.exportProperty( + ol.renderer.dom.TileLayer.prototype, + 'unByKey', + ol.renderer.dom.TileLayer.prototype.unByKey); - var projection; - if ('projection' in config) { - projection = ol.proj.get(config['projection']); - } else { - projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace( - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3')); - } +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'changed', + ol.renderer.dom.VectorLayer.prototype.changed); - var wgs84BoundingBox = l['WGS84BoundingBox']; - var extent, wrapX; - if (wgs84BoundingBox !== undefined) { - var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent(); - wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] && - wgs84BoundingBox[2] == wgs84ProjectionExtent[2]); - extent = ol.proj.transformExtent( - wgs84BoundingBox, 'EPSG:4326', projection); - var projectionExtent = projection.getExtent(); - if (projectionExtent) { - // If possible, do a sanity check on the extent - it should never be - // bigger than the validity extent of the projection of a matrix set. - if (!ol.extent.containsExtent(projectionExtent, extent)) { - extent = undefined; - } - } - } +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'dispatchEvent', + ol.renderer.dom.VectorLayer.prototype.dispatchEvent); - var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( - matrixSetObj, extent); +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'getRevision', + ol.renderer.dom.VectorLayer.prototype.getRevision); - /** @type {!Array.<string>} */ - var urls = []; - var requestEncoding = config['requestEncoding']; - requestEncoding = requestEncoding !== undefined ? requestEncoding : ''; +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'on', + ol.renderer.dom.VectorLayer.prototype.on); - goog.asserts.assert( - ol.array.includes(['REST', 'RESTful', 'KVP', ''], requestEncoding), - 'requestEncoding (%s) is one of "REST", "RESTful", "KVP" or ""', - requestEncoding); +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'once', + ol.renderer.dom.VectorLayer.prototype.once); - if (!wmtsCap.hasOwnProperty('OperationsMetadata') || - !wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') || - requestEncoding.indexOf('REST') === 0) { - // Add REST tile resource url - requestEncoding = ol.source.WMTSRequestEncoding.REST; - l['ResourceURL'].forEach(function(elt, index, array) { - if (elt['resourceType'] == 'tile') { - format = elt['format']; - urls.push(/** @type {string} */ (elt['template'])); - } - }); - } else { - var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get']; +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'un', + ol.renderer.dom.VectorLayer.prototype.un); - for (var i = 0, ii = gets.length; i < ii; ++i) { - var constraint = goog.array.find(gets[i]['Constraint'], - function(elt, index, array) { - return elt['name'] == 'GetEncoding'; - }); - var encodings = constraint['AllowedValues']['Value']; - if (encodings.length > 0 && ol.array.includes(encodings, 'KVP')) { - requestEncoding = ol.source.WMTSRequestEncoding.KVP; - urls.push(/** @type {string} */ (gets[i]['href'])); - } - } - } - goog.asserts.assert(urls.length > 0, 'At least one URL found'); +goog.exportProperty( + ol.renderer.dom.VectorLayer.prototype, + 'unByKey', + ol.renderer.dom.VectorLayer.prototype.unByKey); - return { - urls: urls, - layer: config['layer'], - matrixSet: matrixSet, - format: format, - projection: projection, - requestEncoding: requestEncoding, - tileGrid: tileGrid, - style: style, - dimensions: dimensions, - wrapX: wrapX - }; +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'changed', + ol.renderer.canvas.Layer.prototype.changed); -}; +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'dispatchEvent', + ol.renderer.canvas.Layer.prototype.dispatchEvent); -goog.provide('ol.source.Zoomify'); +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'getRevision', + ol.renderer.canvas.Layer.prototype.getRevision); -goog.require('goog.asserts'); -goog.require('ol'); -goog.require('ol.ImageTile'); -goog.require('ol.TileCoord'); -goog.require('ol.TileState'); -goog.require('ol.dom'); -goog.require('ol.extent'); -goog.require('ol.proj'); -goog.require('ol.source.TileImage'); -goog.require('ol.tilegrid.TileGrid'); +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'on', + ol.renderer.canvas.Layer.prototype.on); +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'once', + ol.renderer.canvas.Layer.prototype.once); -/** - * @enum {string} - */ -ol.source.ZoomifyTierSizeCalculation = { - DEFAULT: 'default', - TRUNCATED: 'truncated' -}; +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'un', + ol.renderer.canvas.Layer.prototype.un); +goog.exportProperty( + ol.renderer.canvas.Layer.prototype, + 'unByKey', + ol.renderer.canvas.Layer.prototype.unByKey); +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'changed', + ol.renderer.canvas.ImageLayer.prototype.changed); -/** - * @classdesc - * Layer source for tile data in Zoomify format. - * - * @constructor - * @extends {ol.source.TileImage} - * @param {olx.source.ZoomifyOptions=} opt_options Options. - * @api stable - */ -ol.source.Zoomify = function(opt_options) { +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'dispatchEvent', + ol.renderer.canvas.ImageLayer.prototype.dispatchEvent); - var options = opt_options || {}; +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'getRevision', + ol.renderer.canvas.ImageLayer.prototype.getRevision); - var size = options.size; - var tierSizeCalculation = options.tierSizeCalculation !== undefined ? - options.tierSizeCalculation : - ol.source.ZoomifyTierSizeCalculation.DEFAULT; +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'on', + ol.renderer.canvas.ImageLayer.prototype.on); - var imageWidth = size[0]; - var imageHeight = size[1]; - var tierSizeInTiles = []; - var tileSize = ol.DEFAULT_TILE_SIZE; +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'once', + ol.renderer.canvas.ImageLayer.prototype.once); - switch (tierSizeCalculation) { - case ol.source.ZoomifyTierSizeCalculation.DEFAULT: - while (imageWidth > tileSize || imageHeight > tileSize) { - tierSizeInTiles.push([ - Math.ceil(imageWidth / tileSize), - Math.ceil(imageHeight / tileSize) - ]); - tileSize += tileSize; - } - break; - case ol.source.ZoomifyTierSizeCalculation.TRUNCATED: - var width = imageWidth; - var height = imageHeight; - while (width > tileSize || height > tileSize) { - tierSizeInTiles.push([ - Math.ceil(width / tileSize), - Math.ceil(height / tileSize) - ]); - width >>= 1; - height >>= 1; - } - break; - default: - goog.asserts.fail(); - break; - } +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'un', + ol.renderer.canvas.ImageLayer.prototype.un); - tierSizeInTiles.push([1, 1]); - tierSizeInTiles.reverse(); +goog.exportProperty( + ol.renderer.canvas.ImageLayer.prototype, + 'unByKey', + ol.renderer.canvas.ImageLayer.prototype.unByKey); - var resolutions = [1]; - var tileCountUpToTier = [0]; - var i, ii; - for (i = 1, ii = tierSizeInTiles.length; i < ii; i++) { - resolutions.push(1 << i); - tileCountUpToTier.push( - tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] + - tileCountUpToTier[i - 1] - ); - } - resolutions.reverse(); +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'changed', + ol.renderer.canvas.TileLayer.prototype.changed); - var extent = [0, -size[1], size[0], 0]; - var tileGrid = new ol.tilegrid.TileGrid({ - extent: extent, - origin: ol.extent.getTopLeft(extent), - resolutions: resolutions - }); +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'dispatchEvent', + ol.renderer.canvas.TileLayer.prototype.dispatchEvent); - var url = options.url; +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'getRevision', + ol.renderer.canvas.TileLayer.prototype.getRevision); - /** - * @this {ol.source.TileImage} - * @param {ol.TileCoord} tileCoord Tile Coordinate. - * @param {number} pixelRatio Pixel ratio. - * @param {ol.proj.Projection} projection Projection. - * @return {string|undefined} Tile URL. - */ - function tileUrlFunction(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } else { - var tileCoordZ = tileCoord[0]; - var tileCoordX = tileCoord[1]; - var tileCoordY = -tileCoord[2] - 1; - var tileIndex = - tileCoordX + - tileCoordY * tierSizeInTiles[tileCoordZ][0] + - tileCountUpToTier[tileCoordZ]; - var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0; - return url + 'TileGroup' + tileGroup + '/' + - tileCoordZ + '-' + tileCoordX + '-' + tileCoordY + '.jpg'; - } - } +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'on', + ol.renderer.canvas.TileLayer.prototype.on); - goog.base(this, { - attributions: options.attributions, - crossOrigin: options.crossOrigin, - logo: options.logo, - reprojectionErrorThreshold: options.reprojectionErrorThreshold, - tileClass: ol.source.ZoomifyTile_, - tileGrid: tileGrid, - tileUrlFunction: tileUrlFunction - }); +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'once', + ol.renderer.canvas.TileLayer.prototype.once); -}; -goog.inherits(ol.source.Zoomify, ol.source.TileImage); +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'un', + ol.renderer.canvas.TileLayer.prototype.un); +goog.exportProperty( + ol.renderer.canvas.TileLayer.prototype, + 'unByKey', + ol.renderer.canvas.TileLayer.prototype.unByKey); +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'changed', + ol.renderer.canvas.VectorLayer.prototype.changed); -/** - * @constructor - * @extends {ol.ImageTile} - * @param {ol.TileCoord} tileCoord Tile coordinate. - * @param {ol.TileState} state State. - * @param {string} src Image source URI. - * @param {?string} crossOrigin Cross origin. - * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function. - * @private - */ -ol.source.ZoomifyTile_ = function( - tileCoord, state, src, crossOrigin, tileLoadFunction) { +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'dispatchEvent', + ol.renderer.canvas.VectorLayer.prototype.dispatchEvent); - goog.base(this, tileCoord, state, src, crossOrigin, tileLoadFunction); +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'getRevision', + ol.renderer.canvas.VectorLayer.prototype.getRevision); - /** - * @private - * @type {Object.<string, - * HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} - */ - this.zoomifyImageByContext_ = {}; +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'on', + ol.renderer.canvas.VectorLayer.prototype.on); -}; -goog.inherits(ol.source.ZoomifyTile_, ol.ImageTile); +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'once', + ol.renderer.canvas.VectorLayer.prototype.once); +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'un', + ol.renderer.canvas.VectorLayer.prototype.un); -/** - * @inheritDoc - */ -ol.source.ZoomifyTile_.prototype.getImage = function(opt_context) { - var tileSize = ol.DEFAULT_TILE_SIZE; - var key = opt_context !== undefined ? - goog.getUid(opt_context).toString() : ''; - if (key in this.zoomifyImageByContext_) { - return this.zoomifyImageByContext_[key]; - } else { - var image = goog.base(this, 'getImage', opt_context); - if (this.state == ol.TileState.LOADED) { - if (image.width == tileSize && image.height == tileSize) { - this.zoomifyImageByContext_[key] = image; - return image; - } else { - var context = ol.dom.createCanvasContext2D(tileSize, tileSize); - context.drawImage(image, 0, 0); - this.zoomifyImageByContext_[key] = context.canvas; - return context.canvas; - } - } else { - return image; - } - } -}; +goog.exportProperty( + ol.renderer.canvas.VectorLayer.prototype, + 'unByKey', + ol.renderer.canvas.VectorLayer.prototype.unByKey); -goog.provide('ol.style.Atlas'); -goog.provide('ol.style.AtlasManager'); +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'changed', + ol.renderer.canvas.VectorTileLayer.prototype.changed); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.functions'); -goog.require('goog.object'); -goog.require('ol'); +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'dispatchEvent', + ol.renderer.canvas.VectorTileLayer.prototype.dispatchEvent); +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'getRevision', + ol.renderer.canvas.VectorTileLayer.prototype.getRevision); -/** - * Provides information for an image inside an atlas manager. - * `offsetX` and `offsetY` is the position of the image inside - * the atlas image `image` and the position of the hit-detection image - * inside the hit-detection atlas image `hitImage`. - * @typedef {{offsetX: number, offsetY: number, image: HTMLCanvasElement, - * hitImage: HTMLCanvasElement}} - */ -ol.style.AtlasManagerInfo; +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'on', + ol.renderer.canvas.VectorTileLayer.prototype.on); +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'once', + ol.renderer.canvas.VectorTileLayer.prototype.once); +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'un', + ol.renderer.canvas.VectorTileLayer.prototype.un); -/** - * Manages the creation of image atlases. - * - * Images added to this manager will be inserted into an atlas, which - * will be used for rendering. - * The `size` given in the constructor is the size for the first - * atlas. After that, when new atlases are created, they will have - * twice the size as the latest atlas (until `maxSize` is reached). - * - * If an application uses many images or very large images, it is recommended - * to set a higher `size` value to avoid the creation of too many atlases. - * - * @constructor - * @struct - * @api - * @param {olx.style.AtlasManagerOptions=} opt_options Options. - */ -ol.style.AtlasManager = function(opt_options) { +goog.exportProperty( + ol.renderer.canvas.VectorTileLayer.prototype, + 'unByKey', + ol.renderer.canvas.VectorTileLayer.prototype.unByKey); - var options = opt_options || {}; +goog.exportProperty( + ol.layer.Base.prototype, + 'get', + ol.layer.Base.prototype.get); - /** - * The size in pixels of the latest atlas image. - * @private - * @type {number} - */ - this.currentSize_ = options.initialSize !== undefined ? - options.initialSize : ol.INITIAL_ATLAS_SIZE; +goog.exportProperty( + ol.layer.Base.prototype, + 'getKeys', + ol.layer.Base.prototype.getKeys); - /** - * The maximum size in pixels of atlas images. - * @private - * @type {number} - */ - this.maxSize_ = options.maxSize !== undefined ? - options.maxSize : ol.MAX_ATLAS_SIZE != -1 ? - ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ? - ol.WEBGL_MAX_TEXTURE_SIZE : 2048; +goog.exportProperty( + ol.layer.Base.prototype, + 'getProperties', + ol.layer.Base.prototype.getProperties); - /** - * The size in pixels between images. - * @private - * @type {number} - */ - this.space_ = options.space !== undefined ? options.space : 1; +goog.exportProperty( + ol.layer.Base.prototype, + 'set', + ol.layer.Base.prototype.set); - /** - * @private - * @type {Array.<ol.style.Atlas>} - */ - this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)]; +goog.exportProperty( + ol.layer.Base.prototype, + 'setProperties', + ol.layer.Base.prototype.setProperties); + +goog.exportProperty( + ol.layer.Base.prototype, + 'unset', + ol.layer.Base.prototype.unset); + +goog.exportProperty( + ol.layer.Base.prototype, + 'changed', + ol.layer.Base.prototype.changed); - /** - * The size in pixels of the latest atlas image for hit-detection images. - * @private - * @type {number} - */ - this.currentHitSize_ = this.currentSize_; +goog.exportProperty( + ol.layer.Base.prototype, + 'dispatchEvent', + ol.layer.Base.prototype.dispatchEvent); - /** - * @private - * @type {Array.<ol.style.Atlas>} - */ - this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)]; -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'getRevision', + ol.layer.Base.prototype.getRevision); +goog.exportProperty( + ol.layer.Base.prototype, + 'on', + ol.layer.Base.prototype.on); -/** - * @param {string} id The identifier of the entry to check. - * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the - * entry, or `null` if the entry is not part of the atlas manager. - */ -ol.style.AtlasManager.prototype.getInfo = function(id) { - /** @type {?ol.style.AtlasInfo} */ - var info = this.getInfo_(this.atlases_, id); +goog.exportProperty( + ol.layer.Base.prototype, + 'once', + ol.layer.Base.prototype.once); - if (!info) { - return null; - } - /** @type {?ol.style.AtlasInfo} */ - var hitInfo = this.getInfo_(this.hitAtlases_, id); - goog.asserts.assert(hitInfo, 'hitInfo must not be null'); +goog.exportProperty( + ol.layer.Base.prototype, + 'un', + ol.layer.Base.prototype.un); - return this.mergeInfos_(info, hitInfo); -}; +goog.exportProperty( + ol.layer.Base.prototype, + 'unByKey', + ol.layer.Base.prototype.unByKey); +goog.exportProperty( + ol.layer.Layer.prototype, + 'getExtent', + ol.layer.Layer.prototype.getExtent); -/** - * @private - * @param {Array.<ol.style.Atlas>} atlases The atlases to search. - * @param {string} id The identifier of the entry to check. - * @return {?ol.style.AtlasInfo} The position and atlas image for the entry, - * or `null` if the entry is not part of the atlases. - */ -ol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) { - var atlas, info, i, ii; - for (i = 0, ii = atlases.length; i < ii; ++i) { - atlas = atlases[i]; - info = atlas.get(id); - if (info) { - return info; - } - } - return null; -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'getMaxResolution', + ol.layer.Layer.prototype.getMaxResolution); +goog.exportProperty( + ol.layer.Layer.prototype, + 'getMinResolution', + ol.layer.Layer.prototype.getMinResolution); -/** - * @private - * @param {ol.style.AtlasInfo} info The info for the real image. - * @param {ol.style.AtlasInfo} hitInfo The info for the hit-detection - * image. - * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the - * entry, or `null` if the entry is not part of the atlases. - */ -ol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) { - goog.asserts.assert(info.offsetX === hitInfo.offsetX, - 'in order to merge, offsetX of info and hitInfo must be equal'); - goog.asserts.assert(info.offsetY === hitInfo.offsetY, - 'in order to merge, offsetY of info and hitInfo must be equal'); - return /** @type {ol.style.AtlasManagerInfo} */ ({ - offsetX: info.offsetX, - offsetY: info.offsetY, - image: info.image, - hitImage: hitInfo.image - }); -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'getOpacity', + ol.layer.Layer.prototype.getOpacity); +goog.exportProperty( + ol.layer.Layer.prototype, + 'getVisible', + ol.layer.Layer.prototype.getVisible); -/** - * Add an image to the atlas manager. - * - * If an entry for the given id already exists, the entry will - * be overridden (but the space on the atlas graphic will not be freed). - * - * If `renderHitCallback` is provided, the image (or the hit-detection version - * of the image) will be rendered into a separate hit-detection atlas image. - * - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {function(CanvasRenderingContext2D, number, number)=} - * opt_renderHitCallback Called to render a hit-detection image onto a hit - * detection atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback` and `renderHitCallback`. - * @return {?ol.style.AtlasManagerInfo} The position and atlas image for the - * entry, or `null` if the image is too big. - */ -ol.style.AtlasManager.prototype.add = - function(id, width, height, - renderCallback, opt_renderHitCallback, opt_this) { - if (width + this.space_ > this.maxSize_ || - height + this.space_ > this.maxSize_) { - return null; - } +goog.exportProperty( + ol.layer.Layer.prototype, + 'getZIndex', + ol.layer.Layer.prototype.getZIndex); - /** @type {?ol.style.AtlasInfo} */ - var info = this.add_(false, - id, width, height, renderCallback, opt_this); - if (!info) { - return null; - } +goog.exportProperty( + ol.layer.Layer.prototype, + 'setExtent', + ol.layer.Layer.prototype.setExtent); - // even if no hit-detection entry is requested, we insert a fake entry into - // the hit-detection atlas, to make sure that the offset is the same for - // the original image and the hit-detection image. - var renderHitCallback = opt_renderHitCallback !== undefined ? - opt_renderHitCallback : goog.functions.NULL; +goog.exportProperty( + ol.layer.Layer.prototype, + 'setMaxResolution', + ol.layer.Layer.prototype.setMaxResolution); - /** @type {?ol.style.AtlasInfo} */ - var hitInfo = this.add_(true, - id, width, height, renderHitCallback, opt_this); - goog.asserts.assert(hitInfo, 'hitInfo must not be null'); +goog.exportProperty( + ol.layer.Layer.prototype, + 'setMinResolution', + ol.layer.Layer.prototype.setMinResolution); - return this.mergeInfos_(info, hitInfo); -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'setOpacity', + ol.layer.Layer.prototype.setOpacity); +goog.exportProperty( + ol.layer.Layer.prototype, + 'setVisible', + ol.layer.Layer.prototype.setVisible); -/** - * @private - * @param {boolean} isHitAtlas If the hit-detection atlases are used. - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback` and `renderHitCallback`. - * @return {?ol.style.AtlasInfo} The position and atlas image for the entry, - * or `null` if the image is too big. - */ -ol.style.AtlasManager.prototype.add_ = - function(isHitAtlas, id, width, height, - renderCallback, opt_this) { - var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_; - var atlas, info, i, ii; - for (i = 0, ii = atlases.length; i < ii; ++i) { - atlas = atlases[i]; - info = atlas.add(id, width, height, renderCallback, opt_this); - if (info) { - return info; - } else if (!info && i === ii - 1) { - // the entry could not be added to one of the existing atlases, - // create a new atlas that is twice as big and try to add to this one. - var size; - if (isHitAtlas) { - size = Math.min(this.currentHitSize_ * 2, this.maxSize_); - this.currentHitSize_ = size; - } else { - size = Math.min(this.currentSize_ * 2, this.maxSize_); - this.currentSize_ = size; - } - atlas = new ol.style.Atlas(size, this.space_); - atlases.push(atlas); - // run the loop another time - ++ii; - } - } - goog.asserts.fail('Failed to add to atlasmanager'); -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'setZIndex', + ol.layer.Layer.prototype.setZIndex); +goog.exportProperty( + ol.layer.Layer.prototype, + 'get', + ol.layer.Layer.prototype.get); -/** - * Provides information for an image inside an atlas. - * `offsetX` and `offsetY` are the position of the image inside - * the atlas image `image`. - * @typedef {{offsetX: number, offsetY: number, image: HTMLCanvasElement}} - */ -ol.style.AtlasInfo; +goog.exportProperty( + ol.layer.Layer.prototype, + 'getKeys', + ol.layer.Layer.prototype.getKeys); +goog.exportProperty( + ol.layer.Layer.prototype, + 'getProperties', + ol.layer.Layer.prototype.getProperties); +goog.exportProperty( + ol.layer.Layer.prototype, + 'set', + ol.layer.Layer.prototype.set); -/** - * This class facilitates the creation of image atlases. - * - * Images added to an atlas will be rendered onto a single - * atlas canvas. The distribution of images on the canvas is - * managed with the bin packing algorithm described in: - * http://www.blackpawn.com/texts/lightmaps/ - * - * @constructor - * @struct - * @param {number} size The size in pixels of the sprite image. - * @param {number} space The space in pixels between images. - * Because texture coordinates are float values, the edges of - * images might not be completely correct (in a way that the - * edges overlap when being rendered). To avoid this we add a - * padding around each image. - */ -ol.style.Atlas = function(size, space) { +goog.exportProperty( + ol.layer.Layer.prototype, + 'setProperties', + ol.layer.Layer.prototype.setProperties); - /** - * @private - * @type {number} - */ - this.space_ = space; +goog.exportProperty( + ol.layer.Layer.prototype, + 'unset', + ol.layer.Layer.prototype.unset); - /** - * @private - * @type {Array.<ol.style.Atlas.Block>} - */ - this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}]; +goog.exportProperty( + ol.layer.Layer.prototype, + 'changed', + ol.layer.Layer.prototype.changed); - /** - * @private - * @type {Object.<string, ol.style.AtlasInfo>} - */ - this.entries_ = {}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'dispatchEvent', + ol.layer.Layer.prototype.dispatchEvent); - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - this.canvas_.width = size; - this.canvas_.height = size; +goog.exportProperty( + ol.layer.Layer.prototype, + 'getRevision', + ol.layer.Layer.prototype.getRevision); - /** - * @private - * @type {CanvasRenderingContext2D} - */ - this.context_ = /** @type {CanvasRenderingContext2D} */ - (this.canvas_.getContext('2d')); -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'on', + ol.layer.Layer.prototype.on); +goog.exportProperty( + ol.layer.Layer.prototype, + 'once', + ol.layer.Layer.prototype.once); -/** - * @param {string} id The identifier of the entry to check. - * @return {?ol.style.AtlasInfo} - */ -ol.style.Atlas.prototype.get = function(id) { - return /** @type {?ol.style.AtlasInfo} */ ( - goog.object.get(this.entries_, id, null)); -}; +goog.exportProperty( + ol.layer.Layer.prototype, + 'un', + ol.layer.Layer.prototype.un); +goog.exportProperty( + ol.layer.Layer.prototype, + 'unByKey', + ol.layer.Layer.prototype.unByKey); -/** - * @param {string} id The identifier of the entry to add. - * @param {number} width The width. - * @param {number} height The height. - * @param {function(CanvasRenderingContext2D, number, number)} renderCallback - * Called to render the new image onto an atlas image. - * @param {Object=} opt_this Value to use as `this` when executing - * `renderCallback`. - * @return {?ol.style.AtlasInfo} The position and atlas image for the entry. - */ -ol.style.Atlas.prototype.add = - function(id, width, height, renderCallback, opt_this) { - var block, i, ii; - for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) { - block = this.emptyBlocks_[i]; - if (block.width >= width + this.space_ && - block.height >= height + this.space_) { - // we found a block that is big enough for our entry - var entry = { - offsetX: block.x + this.space_, - offsetY: block.y + this.space_, - image: this.canvas_ - }; - this.entries_[id] = entry; +goog.exportProperty( + ol.layer.Vector.prototype, + 'setMap', + ol.layer.Vector.prototype.setMap); - // render the image on the atlas image - renderCallback.call(opt_this, this.context_, - block.x + this.space_, block.y + this.space_); +goog.exportProperty( + ol.layer.Vector.prototype, + 'setSource', + ol.layer.Vector.prototype.setSource); - // split the block after the insertion, either horizontally or vertically - this.split_(i, block, width + this.space_, height + this.space_); +goog.exportProperty( + ol.layer.Vector.prototype, + 'getExtent', + ol.layer.Vector.prototype.getExtent); - return entry; - } - } +goog.exportProperty( + ol.layer.Vector.prototype, + 'getMaxResolution', + ol.layer.Vector.prototype.getMaxResolution); - // there is no space for the new entry in this atlas - return null; -}; +goog.exportProperty( + ol.layer.Vector.prototype, + 'getMinResolution', + ol.layer.Vector.prototype.getMinResolution); +goog.exportProperty( + ol.layer.Vector.prototype, + 'getOpacity', + ol.layer.Vector.prototype.getOpacity); -/** - * @private - * @param {number} index The index of the block. - * @param {ol.style.Atlas.Block} block The block to split. - * @param {number} width The width of the entry to insert. - * @param {number} height The height of the entry to insert. - */ -ol.style.Atlas.prototype.split_ = - function(index, block, width, height) { - var deltaWidth = block.width - width; - var deltaHeight = block.height - height; +goog.exportProperty( + ol.layer.Vector.prototype, + 'getVisible', + ol.layer.Vector.prototype.getVisible); - /** @type {ol.style.Atlas.Block} */ - var newBlock1; - /** @type {ol.style.Atlas.Block} */ - var newBlock2; +goog.exportProperty( + ol.layer.Vector.prototype, + 'getZIndex', + ol.layer.Vector.prototype.getZIndex); - if (deltaWidth > deltaHeight) { - // split vertically - // block right of the inserted entry - newBlock1 = { - x: block.x + width, - y: block.y, - width: block.width - width, - height: block.height - }; +goog.exportProperty( + ol.layer.Vector.prototype, + 'setExtent', + ol.layer.Vector.prototype.setExtent); - // block below the inserted entry - newBlock2 = { - x: block.x, - y: block.y + height, - width: width, - height: block.height - height - }; - this.updateBlocks_(index, newBlock1, newBlock2); - } else { - // split horizontally - // block right of the inserted entry - newBlock1 = { - x: block.x + width, - y: block.y, - width: block.width - width, - height: height - }; +goog.exportProperty( + ol.layer.Vector.prototype, + 'setMaxResolution', + ol.layer.Vector.prototype.setMaxResolution); - // block below the inserted entry - newBlock2 = { - x: block.x, - y: block.y + height, - width: block.width, - height: block.height - height - }; - this.updateBlocks_(index, newBlock1, newBlock2); - } -}; +goog.exportProperty( + ol.layer.Vector.prototype, + 'setMinResolution', + ol.layer.Vector.prototype.setMinResolution); +goog.exportProperty( + ol.layer.Vector.prototype, + 'setOpacity', + ol.layer.Vector.prototype.setOpacity); -/** - * Remove the old block and insert new blocks at the same array position. - * The new blocks are inserted at the same position, so that splitted - * blocks (that are potentially smaller) are filled first. - * @private - * @param {number} index The index of the block to remove. - * @param {ol.style.Atlas.Block} newBlock1 The 1st block to add. - * @param {ol.style.Atlas.Block} newBlock2 The 2nd block to add. - */ -ol.style.Atlas.prototype.updateBlocks_ = - function(index, newBlock1, newBlock2) { - var args = [index, 1]; - if (newBlock1.width > 0 && newBlock1.height > 0) { - args.push(newBlock1); - } - if (newBlock2.width > 0 && newBlock2.height > 0) { - args.push(newBlock2); - } - this.emptyBlocks_.splice.apply(this.emptyBlocks_, args); -}; +goog.exportProperty( + ol.layer.Vector.prototype, + 'setVisible', + ol.layer.Vector.prototype.setVisible); +goog.exportProperty( + ol.layer.Vector.prototype, + 'setZIndex', + ol.layer.Vector.prototype.setZIndex); -/** - * @typedef {{x: number, y: number, width: number, height: number}} - */ -ol.style.Atlas.Block; +goog.exportProperty( + ol.layer.Vector.prototype, + 'get', + ol.layer.Vector.prototype.get); -goog.provide('ol.style.RegularShape'); +goog.exportProperty( + ol.layer.Vector.prototype, + 'getKeys', + ol.layer.Vector.prototype.getKeys); -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('ol'); -goog.require('ol.color'); -goog.require('ol.has'); -goog.require('ol.render.canvas'); -goog.require('ol.structs.IHasChecksum'); -goog.require('ol.style.AtlasManager'); -goog.require('ol.style.Fill'); -goog.require('ol.style.Image'); -goog.require('ol.style.ImageState'); -goog.require('ol.style.Stroke'); +goog.exportProperty( + ol.layer.Vector.prototype, + 'getProperties', + ol.layer.Vector.prototype.getProperties); +goog.exportProperty( + ol.layer.Vector.prototype, + 'set', + ol.layer.Vector.prototype.set); +goog.exportProperty( + ol.layer.Vector.prototype, + 'setProperties', + ol.layer.Vector.prototype.setProperties); -/** - * @classdesc - * Set regular shape style for vector features. The resulting shape will be - * a regular polygon when `radius` is provided, or a star when `radius1` and - * `radius2` are provided. - * - * @constructor - * @param {olx.style.RegularShapeOptions} options Options. - * @extends {ol.style.Image} - * @implements {ol.structs.IHasChecksum} - * @api - */ -ol.style.RegularShape = function(options) { +goog.exportProperty( + ol.layer.Vector.prototype, + 'unset', + ol.layer.Vector.prototype.unset); - goog.asserts.assert( - options.radius !== undefined || options.radius1 !== undefined, - 'must provide either "radius" or "radius1"'); +goog.exportProperty( + ol.layer.Vector.prototype, + 'changed', + ol.layer.Vector.prototype.changed); - /** - * @private - * @type {Array.<string>} - */ - this.checksums_ = null; +goog.exportProperty( + ol.layer.Vector.prototype, + 'dispatchEvent', + ol.layer.Vector.prototype.dispatchEvent); - /** - * @private - * @type {HTMLCanvasElement} - */ - this.canvas_ = null; +goog.exportProperty( + ol.layer.Vector.prototype, + 'getRevision', + ol.layer.Vector.prototype.getRevision); - /** - * @private - * @type {HTMLCanvasElement} - */ - this.hitDetectionCanvas_ = null; +goog.exportProperty( + ol.layer.Vector.prototype, + 'on', + ol.layer.Vector.prototype.on); - /** - * @private - * @type {ol.style.Fill} - */ - this.fill_ = options.fill !== undefined ? options.fill : null; +goog.exportProperty( + ol.layer.Vector.prototype, + 'once', + ol.layer.Vector.prototype.once); - /** - * @private - * @type {Array.<number>} - */ - this.origin_ = [0, 0]; +goog.exportProperty( + ol.layer.Vector.prototype, + 'un', + ol.layer.Vector.prototype.un); - /** - * @private - * @type {number} - */ - this.points_ = options.points; +goog.exportProperty( + ol.layer.Vector.prototype, + 'unByKey', + ol.layer.Vector.prototype.unByKey); - /** - * @private - * @type {number} - */ - this.radius_ = /** @type {number} */ (options.radius !== undefined ? - options.radius : options.radius1); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getSource', + ol.layer.Heatmap.prototype.getSource); - /** - * @private - * @type {number} - */ - this.radius2_ = - options.radius2 !== undefined ? options.radius2 : this.radius_; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getStyle', + ol.layer.Heatmap.prototype.getStyle); - /** - * @private - * @type {number} - */ - this.angle_ = options.angle !== undefined ? options.angle : 0; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getStyleFunction', + ol.layer.Heatmap.prototype.getStyleFunction); - /** - * @private - * @type {ol.style.Stroke} - */ - this.stroke_ = options.stroke !== undefined ? options.stroke : null; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setStyle', + ol.layer.Heatmap.prototype.setStyle); - /** - * @private - * @type {Array.<number>} - */ - this.anchor_ = null; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setMap', + ol.layer.Heatmap.prototype.setMap); - /** - * @private - * @type {ol.Size} - */ - this.size_ = null; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setSource', + ol.layer.Heatmap.prototype.setSource); - /** - * @private - * @type {ol.Size} - */ - this.imageSize_ = null; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getExtent', + ol.layer.Heatmap.prototype.getExtent); - /** - * @private - * @type {ol.Size} - */ - this.hitDetectionImageSize_ = null; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getMaxResolution', + ol.layer.Heatmap.prototype.getMaxResolution); - this.render_(options.atlasManager); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getMinResolution', + ol.layer.Heatmap.prototype.getMinResolution); - /** - * @type {boolean} - */ - var snapToPixel = options.snapToPixel !== undefined ? - options.snapToPixel : true; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getOpacity', + ol.layer.Heatmap.prototype.getOpacity); - goog.base(this, { - opacity: 1, - rotateWithView: false, - rotation: options.rotation !== undefined ? options.rotation : 0, - scale: 1, - snapToPixel: snapToPixel - }); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getVisible', + ol.layer.Heatmap.prototype.getVisible); -}; -goog.inherits(ol.style.RegularShape, ol.style.Image); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getZIndex', + ol.layer.Heatmap.prototype.getZIndex); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setExtent', + ol.layer.Heatmap.prototype.setExtent); -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getAnchor = function() { - return this.anchor_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setMaxResolution', + ol.layer.Heatmap.prototype.setMaxResolution); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setMinResolution', + ol.layer.Heatmap.prototype.setMinResolution); -/** - * Get the angle used in generating the shape. - * @return {number} Shape's rotation in radians. - * @api - */ -ol.style.RegularShape.prototype.getAngle = function() { - return this.angle_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setOpacity', + ol.layer.Heatmap.prototype.setOpacity); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setVisible', + ol.layer.Heatmap.prototype.setVisible); -/** - * Get the fill style for the shape. - * @return {ol.style.Fill} Fill style. - * @api - */ -ol.style.RegularShape.prototype.getFill = function() { - return this.fill_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setZIndex', + ol.layer.Heatmap.prototype.setZIndex); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'get', + ol.layer.Heatmap.prototype.get); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getHitDetectionImage = function(pixelRatio) { - return this.hitDetectionCanvas_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getKeys', + ol.layer.Heatmap.prototype.getKeys); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getProperties', + ol.layer.Heatmap.prototype.getProperties); -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getImage = function(pixelRatio) { - return this.canvas_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'set', + ol.layer.Heatmap.prototype.set); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'setProperties', + ol.layer.Heatmap.prototype.setProperties); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getImageSize = function() { - return this.imageSize_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'unset', + ol.layer.Heatmap.prototype.unset); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'changed', + ol.layer.Heatmap.prototype.changed); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getHitDetectionImageSize = function() { - return this.hitDetectionImageSize_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'dispatchEvent', + ol.layer.Heatmap.prototype.dispatchEvent); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'getRevision', + ol.layer.Heatmap.prototype.getRevision); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getImageState = function() { - return ol.style.ImageState.LOADED; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'on', + ol.layer.Heatmap.prototype.on); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'once', + ol.layer.Heatmap.prototype.once); -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getOrigin = function() { - return this.origin_; -}; +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'un', + ol.layer.Heatmap.prototype.un); +goog.exportProperty( + ol.layer.Heatmap.prototype, + 'unByKey', + ol.layer.Heatmap.prototype.unByKey); -/** - * Get the number of points for generating the shape. - * @return {number} Number of points for stars and regular polygons. - * @api - */ -ol.style.RegularShape.prototype.getPoints = function() { - return this.points_; -}; +goog.exportProperty( + ol.layer.Image.prototype, + 'setMap', + ol.layer.Image.prototype.setMap); +goog.exportProperty( + ol.layer.Image.prototype, + 'setSource', + ol.layer.Image.prototype.setSource); -/** - * Get the (primary) radius for the shape. - * @return {number} Radius. - * @api - */ -ol.style.RegularShape.prototype.getRadius = function() { - return this.radius_; -}; +goog.exportProperty( + ol.layer.Image.prototype, + 'getExtent', + ol.layer.Image.prototype.getExtent); +goog.exportProperty( + ol.layer.Image.prototype, + 'getMaxResolution', + ol.layer.Image.prototype.getMaxResolution); -/** - * Get the secondary radius for the shape. - * @return {number} Radius2. - * @api - */ -ol.style.RegularShape.prototype.getRadius2 = function() { - return this.radius2_; -}; +goog.exportProperty( + ol.layer.Image.prototype, + 'getMinResolution', + ol.layer.Image.prototype.getMinResolution); +goog.exportProperty( + ol.layer.Image.prototype, + 'getOpacity', + ol.layer.Image.prototype.getOpacity); -/** - * @inheritDoc - * @api - */ -ol.style.RegularShape.prototype.getSize = function() { - return this.size_; -}; +goog.exportProperty( + ol.layer.Image.prototype, + 'getVisible', + ol.layer.Image.prototype.getVisible); +goog.exportProperty( + ol.layer.Image.prototype, + 'getZIndex', + ol.layer.Image.prototype.getZIndex); -/** - * Get the stroke style for the shape. - * @return {ol.style.Stroke} Stroke style. - * @api - */ -ol.style.RegularShape.prototype.getStroke = function() { - return this.stroke_; -}; +goog.exportProperty( + ol.layer.Image.prototype, + 'setExtent', + ol.layer.Image.prototype.setExtent); +goog.exportProperty( + ol.layer.Image.prototype, + 'setMaxResolution', + ol.layer.Image.prototype.setMaxResolution); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.listenImageChange = ol.nullFunction; +goog.exportProperty( + ol.layer.Image.prototype, + 'setMinResolution', + ol.layer.Image.prototype.setMinResolution); +goog.exportProperty( + ol.layer.Image.prototype, + 'setOpacity', + ol.layer.Image.prototype.setOpacity); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.load = ol.nullFunction; +goog.exportProperty( + ol.layer.Image.prototype, + 'setVisible', + ol.layer.Image.prototype.setVisible); +goog.exportProperty( + ol.layer.Image.prototype, + 'setZIndex', + ol.layer.Image.prototype.setZIndex); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.unlistenImageChange = ol.nullFunction; +goog.exportProperty( + ol.layer.Image.prototype, + 'get', + ol.layer.Image.prototype.get); +goog.exportProperty( + ol.layer.Image.prototype, + 'getKeys', + ol.layer.Image.prototype.getKeys); -/** - * @typedef {{ - * strokeStyle: (string|undefined), - * strokeWidth: number, - * size: number, - * lineCap: string, - * lineDash: Array.<number>, - * lineJoin: string, - * miterLimit: number - * }} - */ -ol.style.RegularShape.RenderOptions; +goog.exportProperty( + ol.layer.Image.prototype, + 'getProperties', + ol.layer.Image.prototype.getProperties); +goog.exportProperty( + ol.layer.Image.prototype, + 'set', + ol.layer.Image.prototype.set); -/** - * @private - * @param {ol.style.AtlasManager|undefined} atlasManager - */ -ol.style.RegularShape.prototype.render_ = function(atlasManager) { - var imageSize; - var lineCap = ''; - var lineJoin = ''; - var miterLimit = 0; - var lineDash = null; - var strokeStyle; - var strokeWidth = 0; +goog.exportProperty( + ol.layer.Image.prototype, + 'setProperties', + ol.layer.Image.prototype.setProperties); - if (this.stroke_) { - strokeStyle = ol.color.asString(this.stroke_.getColor()); - strokeWidth = this.stroke_.getWidth(); - if (strokeWidth === undefined) { - strokeWidth = ol.render.canvas.defaultLineWidth; - } - lineDash = this.stroke_.getLineDash(); - if (!ol.has.CANVAS_LINE_DASH) { - lineDash = null; - } - lineJoin = this.stroke_.getLineJoin(); - if (lineJoin === undefined) { - lineJoin = ol.render.canvas.defaultLineJoin; - } - lineCap = this.stroke_.getLineCap(); - if (lineCap === undefined) { - lineCap = ol.render.canvas.defaultLineCap; - } - miterLimit = this.stroke_.getMiterLimit(); - if (miterLimit === undefined) { - miterLimit = ol.render.canvas.defaultMiterLimit; - } - } +goog.exportProperty( + ol.layer.Image.prototype, + 'unset', + ol.layer.Image.prototype.unset); - var size = 2 * (this.radius_ + strokeWidth) + 1; +goog.exportProperty( + ol.layer.Image.prototype, + 'changed', + ol.layer.Image.prototype.changed); - /** @type {ol.style.RegularShape.RenderOptions} */ - var renderOptions = { - strokeStyle: strokeStyle, - strokeWidth: strokeWidth, - size: size, - lineCap: lineCap, - lineDash: lineDash, - lineJoin: lineJoin, - miterLimit: miterLimit - }; +goog.exportProperty( + ol.layer.Image.prototype, + 'dispatchEvent', + ol.layer.Image.prototype.dispatchEvent); - if (atlasManager === undefined) { - // no atlas manager is used, create a new canvas - this.canvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); +goog.exportProperty( + ol.layer.Image.prototype, + 'getRevision', + ol.layer.Image.prototype.getRevision); - this.canvas_.height = size; - this.canvas_.width = size; +goog.exportProperty( + ol.layer.Image.prototype, + 'on', + ol.layer.Image.prototype.on); - // canvas.width and height are rounded to the closest integer - size = this.canvas_.width; - imageSize = size; +goog.exportProperty( + ol.layer.Image.prototype, + 'once', + ol.layer.Image.prototype.once); - var context = /** @type {CanvasRenderingContext2D} */ - (this.canvas_.getContext('2d')); - this.draw_(renderOptions, context, 0, 0); +goog.exportProperty( + ol.layer.Image.prototype, + 'un', + ol.layer.Image.prototype.un); - this.createHitDetectionCanvas_(renderOptions); - } else { - // an atlas manager is used, add the symbol to an atlas - size = Math.round(size); +goog.exportProperty( + ol.layer.Image.prototype, + 'unByKey', + ol.layer.Image.prototype.unByKey); - var hasCustomHitDetectionImage = !this.fill_; - var renderHitDetectionCallback; - if (hasCustomHitDetectionImage) { - // render the hit-detection image into a separate atlas image - renderHitDetectionCallback = - goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); - } +goog.exportProperty( + ol.layer.Group.prototype, + 'getExtent', + ol.layer.Group.prototype.getExtent); - var id = this.getChecksum(); - var info = atlasManager.add( - id, size, size, goog.bind(this.draw_, this, renderOptions), - renderHitDetectionCallback); - goog.asserts.assert(info, 'shape size is too large'); +goog.exportProperty( + ol.layer.Group.prototype, + 'getMaxResolution', + ol.layer.Group.prototype.getMaxResolution); - this.canvas_ = info.image; - this.origin_ = [info.offsetX, info.offsetY]; - imageSize = info.image.width; +goog.exportProperty( + ol.layer.Group.prototype, + 'getMinResolution', + ol.layer.Group.prototype.getMinResolution); - if (hasCustomHitDetectionImage) { - this.hitDetectionCanvas_ = info.hitImage; - this.hitDetectionImageSize_ = - [info.hitImage.width, info.hitImage.height]; - } else { - this.hitDetectionCanvas_ = this.canvas_; - this.hitDetectionImageSize_ = [imageSize, imageSize]; - } - } +goog.exportProperty( + ol.layer.Group.prototype, + 'getOpacity', + ol.layer.Group.prototype.getOpacity); - this.anchor_ = [size / 2, size / 2]; - this.size_ = [size, size]; - this.imageSize_ = [imageSize, imageSize]; -}; +goog.exportProperty( + ol.layer.Group.prototype, + 'getVisible', + ol.layer.Group.prototype.getVisible); +goog.exportProperty( + ol.layer.Group.prototype, + 'getZIndex', + ol.layer.Group.prototype.getZIndex); -/** - * @private - * @param {ol.style.RegularShape.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). - */ -ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) { - var i, angle0, radiusC; - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); +goog.exportProperty( + ol.layer.Group.prototype, + 'setExtent', + ol.layer.Group.prototype.setExtent); - // then move to (x, y) - context.translate(x, y); +goog.exportProperty( + ol.layer.Group.prototype, + 'setMaxResolution', + ol.layer.Group.prototype.setMaxResolution); - context.beginPath(); - if (this.radius2_ !== this.radius_) { - this.points_ = 2 * this.points_; - } - for (i = 0; i <= this.points_; i++) { - angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; - radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; - context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0), - renderOptions.size / 2 + radiusC * Math.sin(angle0)); - } +goog.exportProperty( + ol.layer.Group.prototype, + 'setMinResolution', + ol.layer.Group.prototype.setMinResolution); - if (this.fill_) { - context.fillStyle = ol.color.asString(this.fill_.getColor()); - context.fill(); - } - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); - } - context.lineCap = renderOptions.lineCap; - context.lineJoin = renderOptions.lineJoin; - context.miterLimit = renderOptions.miterLimit; - context.stroke(); - } - context.closePath(); -}; +goog.exportProperty( + ol.layer.Group.prototype, + 'setOpacity', + ol.layer.Group.prototype.setOpacity); +goog.exportProperty( + ol.layer.Group.prototype, + 'setVisible', + ol.layer.Group.prototype.setVisible); -/** - * @private - * @param {ol.style.RegularShape.RenderOptions} renderOptions - */ -ol.style.RegularShape.prototype.createHitDetectionCanvas_ = - function(renderOptions) { - this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; - if (this.fill_) { - this.hitDetectionCanvas_ = this.canvas_; - return; - } +goog.exportProperty( + ol.layer.Group.prototype, + 'setZIndex', + ol.layer.Group.prototype.setZIndex); - // if no fill style is set, create an extra hit-detection image with a - // default fill style - this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ - (goog.dom.createElement('CANVAS')); - var canvas = this.hitDetectionCanvas_; +goog.exportProperty( + ol.layer.Group.prototype, + 'get', + ol.layer.Group.prototype.get); - canvas.height = renderOptions.size; - canvas.width = renderOptions.size; +goog.exportProperty( + ol.layer.Group.prototype, + 'getKeys', + ol.layer.Group.prototype.getKeys); - var context = /** @type {CanvasRenderingContext2D} */ - (canvas.getContext('2d')); - this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); -}; +goog.exportProperty( + ol.layer.Group.prototype, + 'getProperties', + ol.layer.Group.prototype.getProperties); +goog.exportProperty( + ol.layer.Group.prototype, + 'set', + ol.layer.Group.prototype.set); -/** - * @private - * @param {ol.style.RegularShape.RenderOptions} renderOptions - * @param {CanvasRenderingContext2D} context - * @param {number} x The origin for the symbol (x). - * @param {number} y The origin for the symbol (y). - */ -ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = - function(renderOptions, context, x, y) { - // reset transform - context.setTransform(1, 0, 0, 1, 0, 0); +goog.exportProperty( + ol.layer.Group.prototype, + 'setProperties', + ol.layer.Group.prototype.setProperties); - // then move to (x, y) - context.translate(x, y); +goog.exportProperty( + ol.layer.Group.prototype, + 'unset', + ol.layer.Group.prototype.unset); - context.beginPath(); - if (this.radius2_ !== this.radius_) { - this.points_ = 2 * this.points_; - } - var i, radiusC, angle0; - for (i = 0; i <= this.points_; i++) { - angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; - radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; - context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0), - renderOptions.size / 2 + radiusC * Math.sin(angle0)); - } +goog.exportProperty( + ol.layer.Group.prototype, + 'changed', + ol.layer.Group.prototype.changed); - context.fillStyle = ol.render.canvas.defaultFillStyle; - context.fill(); - if (this.stroke_) { - context.strokeStyle = renderOptions.strokeStyle; - context.lineWidth = renderOptions.strokeWidth; - if (renderOptions.lineDash) { - context.setLineDash(renderOptions.lineDash); - } - context.stroke(); - } - context.closePath(); -}; +goog.exportProperty( + ol.layer.Group.prototype, + 'dispatchEvent', + ol.layer.Group.prototype.dispatchEvent); +goog.exportProperty( + ol.layer.Group.prototype, + 'getRevision', + ol.layer.Group.prototype.getRevision); -/** - * @inheritDoc - */ -ol.style.RegularShape.prototype.getChecksum = function() { - var strokeChecksum = this.stroke_ ? - this.stroke_.getChecksum() : '-'; - var fillChecksum = this.fill_ ? - this.fill_.getChecksum() : '-'; +goog.exportProperty( + ol.layer.Group.prototype, + 'on', + ol.layer.Group.prototype.on); - var recalculate = !this.checksums_ || - (strokeChecksum != this.checksums_[1] || - fillChecksum != this.checksums_[2] || - this.radius_ != this.checksums_[3] || - this.radius2_ != this.checksums_[4] || - this.angle_ != this.checksums_[5] || - this.points_ != this.checksums_[6]); +goog.exportProperty( + ol.layer.Group.prototype, + 'once', + ol.layer.Group.prototype.once); - if (recalculate) { - var checksum = 'r' + strokeChecksum + fillChecksum + - (this.radius_ !== undefined ? this.radius_.toString() : '-') + - (this.radius2_ !== undefined ? this.radius2_.toString() : '-') + - (this.angle_ !== undefined ? this.angle_.toString() : '-') + - (this.points_ !== undefined ? this.points_.toString() : '-'); - this.checksums_ = [checksum, strokeChecksum, fillChecksum, - this.radius_, this.radius2_, this.angle_, this.points_]; - } +goog.exportProperty( + ol.layer.Group.prototype, + 'un', + ol.layer.Group.prototype.un); - return this.checksums_[0]; -}; +goog.exportProperty( + ol.layer.Group.prototype, + 'unByKey', + ol.layer.Group.prototype.unByKey); -goog.provide('olcs.AbstractSynchronizer'); +goog.exportProperty( + ol.layer.Tile.prototype, + 'setMap', + ol.layer.Tile.prototype.setMap); -goog.require('goog.object'); +goog.exportProperty( + ol.layer.Tile.prototype, + 'setSource', + ol.layer.Tile.prototype.setSource); -goog.require('ol.Observable'); -goog.require('ol.layer.Group'); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getExtent', + ol.layer.Tile.prototype.getExtent); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getMaxResolution', + ol.layer.Tile.prototype.getMaxResolution); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getMinResolution', + ol.layer.Tile.prototype.getMinResolution); -/** - * @param {!ol.Map} map - * @param {!Cesium.Scene} scene - * @constructor - * @template T - * @api - */ -olcs.AbstractSynchronizer = function(map, scene) { - /** - * @type {!ol.Map} - * @protected - */ - this.map = map; +goog.exportProperty( + ol.layer.Tile.prototype, + 'getOpacity', + ol.layer.Tile.prototype.getOpacity); - /** - * @type {ol.View} - * @protected - */ - this.view = map.getView(); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getVisible', + ol.layer.Tile.prototype.getVisible); - /** - * @type {!Cesium.Scene} - * @protected - */ - this.scene = scene; +goog.exportProperty( + ol.layer.Tile.prototype, + 'getZIndex', + ol.layer.Tile.prototype.getZIndex); - /** - * @type {ol.Collection.<ol.layer.Base>} - * @protected - */ - this.olLayers = map.getLayerGroup().getLayers(); +goog.exportProperty( + ol.layer.Tile.prototype, + 'setExtent', + ol.layer.Tile.prototype.setExtent); - /** - * @type {ol.layer.Group} - */ - this.mapLayerGroup = map.getLayerGroup(); +goog.exportProperty( + ol.layer.Tile.prototype, + 'setMaxResolution', + ol.layer.Tile.prototype.setMaxResolution); - /** - * Map of ol3 layer ids (from goog.getUid) to the Cesium ImageryLayers. - * Null value means, that we are unable to create equivalent layers. - * @type {Object.<number, ?Array.<T>>} - * @protected - */ - this.layerMap = {}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'setMinResolution', + ol.layer.Tile.prototype.setMinResolution); - /** - * Map of listen keys for ol3 layer layers ids (from goog.getUid). - * @type {!Object.<number, goog.events.Key>} - * @private - */ - this.olLayerListenKeys_ = {}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'setOpacity', + ol.layer.Tile.prototype.setOpacity); - /** - * Map of listen keys for ol3 layer groups ids (from goog.getUid). - * @type {!Object.<number, !Array.<goog.events.Key>>} - * @private - */ - this.olGroupListenKeys_ = {}; -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'setVisible', + ol.layer.Tile.prototype.setVisible); +goog.exportProperty( + ol.layer.Tile.prototype, + 'setZIndex', + ol.layer.Tile.prototype.setZIndex); -/** - * Destroy all and perform complete synchronization of the layers. - * @api - */ -olcs.AbstractSynchronizer.prototype.synchronize = function() { - this.destroyAll(); - this.addLayers_(this.mapLayerGroup); -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'get', + ol.layer.Tile.prototype.get); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getKeys', + ol.layer.Tile.prototype.getKeys); -/** - * Order counterparts using the same algorithm as the Openlayers renderer: - * z-index then original sequence order. - * @protected - */ -olcs.AbstractSynchronizer.prototype.orderLayers = function() { - // Ordering logics is handled in subclasses. -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'getProperties', + ol.layer.Tile.prototype.getProperties); +goog.exportProperty( + ol.layer.Tile.prototype, + 'set', + ol.layer.Tile.prototype.set); -/** - * Add a layer hierarchy. - * @param {ol.layer.Base} root - * @private - */ -olcs.AbstractSynchronizer.prototype.addLayers_ = function(root) { - /** @type {Array.<!ol.layer.Base>} */ - var fifo = [root]; - while (fifo.length > 0) { - var olLayer = fifo.splice(0, 1)[0]; - var olLayerId = goog.getUid(olLayer); - goog.asserts.assert(!goog.isDef(this.layerMap[olLayerId])); +goog.exportProperty( + ol.layer.Tile.prototype, + 'setProperties', + ol.layer.Tile.prototype.setProperties); - var cesiumObjects = null; - if (olLayer instanceof ol.layer.Group) { - this.listenForGroupChanges_(olLayer); - cesiumObjects = this.createSingleLayerCounterparts(olLayer); - if (!cesiumObjects) { - olLayer.getLayers().forEach(function(l) { - fifo.push(l); - }); - } - } else { - cesiumObjects = this.createSingleLayerCounterparts(olLayer); - } +goog.exportProperty( + ol.layer.Tile.prototype, + 'unset', + ol.layer.Tile.prototype.unset); - // add Cesium layers - if (!goog.isNull(cesiumObjects)) { - this.layerMap[olLayerId] = cesiumObjects; - this.olLayerListenKeys_[olLayerId] = olLayer.on('change:zIndex', - this.orderLayers, this); - cesiumObjects.forEach(function(cesiumObject) { - this.addCesiumObject(cesiumObject); - }, this); - } - } +goog.exportProperty( + ol.layer.Tile.prototype, + 'changed', + ol.layer.Tile.prototype.changed); - this.orderLayers(); -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'dispatchEvent', + ol.layer.Tile.prototype.dispatchEvent); +goog.exportProperty( + ol.layer.Tile.prototype, + 'getRevision', + ol.layer.Tile.prototype.getRevision); -/** - * Remove and destroy a single layer. - * @param {ol.layer.Layer} layer - * @return {boolean} counterpart destroyed - * @private - */ -olcs.AbstractSynchronizer.prototype.removeAndDestroySingleLayer_ = - function(layer) { - var uid = goog.getUid(layer); - var counterparts = this.layerMap[uid]; - if (!!counterparts) { - counterparts.forEach(function(counterpart) { - this.removeSingleCesiumObject(counterpart, false); - this.destroyCesiumObject(counterpart); - }, this); - ol.Observable.unByKey(this.olLayerListenKeys_[uid]); - delete this.olLayerListenKeys_[uid]; - } - delete this.layerMap[uid]; - return !!counterparts; -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'on', + ol.layer.Tile.prototype.on); +goog.exportProperty( + ol.layer.Tile.prototype, + 'once', + ol.layer.Tile.prototype.once); -/** - * Unlisten a single layer group. - * @param {ol.layer.Group} group - * @private - */ -olcs.AbstractSynchronizer.prototype.unlistenSingleGroup_ = - function(group) { - if (group === this.mapLayerGroup) { - return; - } - var uid = goog.getUid(group); - var keys = this.olGroupListenKeys_[uid]; - keys.forEach(function(key) { - ol.Observable.unByKey(key); - }); - delete this.olGroupListenKeys_[uid]; - delete this.layerMap[uid]; -}; +goog.exportProperty( + ol.layer.Tile.prototype, + 'un', + ol.layer.Tile.prototype.un); +goog.exportProperty( + ol.layer.Tile.prototype, + 'unByKey', + ol.layer.Tile.prototype.unByKey); -/** - * Remove layer hierarchy. - * @param {ol.layer.Base} root - * @private - */ -olcs.AbstractSynchronizer.prototype.removeLayer_ = function(root) { - if (!!root) { - var fifo = [root]; - while (fifo.length > 0) { - var olLayer = fifo.splice(0, 1)[0]; - var done = this.removeAndDestroySingleLayer_(olLayer); - if (olLayer instanceof ol.layer.Group) { - this.unlistenSingleGroup_(olLayer); - if (done) { - olLayer.getLayers().forEach(function(l) { - fifo.push(l); - }); - } - } - } - } -}; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getStyle', + ol.layer.VectorTile.prototype.getStyle); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getStyleFunction', + ol.layer.VectorTile.prototype.getStyleFunction); -/** - * Register listeners for single layer group change. - * @param {ol.layer.Group} group - * @private - */ -olcs.AbstractSynchronizer.prototype.listenForGroupChanges_ = function(group) { - var uuid = goog.getUid(group); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setStyle', + ol.layer.VectorTile.prototype.setStyle); - goog.asserts.assert(!goog.isDef(this.olGroupListenKeys_[uuid])); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setMap', + ol.layer.VectorTile.prototype.setMap); - var listenKeyArray = []; - this.olGroupListenKeys_[uuid] = listenKeyArray; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setSource', + ol.layer.VectorTile.prototype.setSource); - // only the keys that need to be relistened when collection changes - var contentKeys = []; - var listenAddRemove = (function() { - var collection = group.getLayers(); - if (goog.isDef(collection)) { - contentKeys = [ - collection.on('add', function(event) { - this.addLayers_(event.element); - }, this), - collection.on('remove', function(event) { - this.removeLayer_(event.element); - }, this) - ]; - listenKeyArray.push.apply(listenKeyArray, contentKeys); - } - }).bind(this); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getExtent', + ol.layer.VectorTile.prototype.getExtent); - listenAddRemove(); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getMaxResolution', + ol.layer.VectorTile.prototype.getMaxResolution); - listenKeyArray.push(group.on('change:layers', function(e) { - contentKeys.forEach(function(el) { - var i = listenKeyArray.indexOf(el); - if (i >= 0) { - listenKeyArray.splice(i, 1); - } - ol.Observable.unByKey(el); - }); - listenAddRemove(); - })); -}; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getMinResolution', + ol.layer.VectorTile.prototype.getMinResolution); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getOpacity', + ol.layer.VectorTile.prototype.getOpacity); -/** - * Destroys all the created Cesium objects. - * @protected - */ -olcs.AbstractSynchronizer.prototype.destroyAll = function() { - this.removeAllCesiumObjects(true); // destroy - goog.object.forEach(this.olGroupListenKeys, function(keys) { - keys.forEach(ol.Observable.unByKey); - }); - goog.object.forEach(this.olLayerListenKeys, ol.Observable.unByKey); - this.olGroupListenKeys = {}; - this.olLayerListenKeys = {}; - this.layerMap = {}; -}; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getVisible', + ol.layer.VectorTile.prototype.getVisible); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getZIndex', + ol.layer.VectorTile.prototype.getZIndex); -/** - * Adds a single Cesium object to the collection. - * @param {!T} object - * @protected - */ -olcs.AbstractSynchronizer.prototype.addCesiumObject = goog.abstractMethod; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setExtent', + ol.layer.VectorTile.prototype.setExtent); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setMaxResolution', + ol.layer.VectorTile.prototype.setMaxResolution); -/** - * @param {!T} object - * @protected - */ -olcs.AbstractSynchronizer.prototype.destroyCesiumObject = goog.abstractMethod; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setMinResolution', + ol.layer.VectorTile.prototype.setMinResolution); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setOpacity', + ol.layer.VectorTile.prototype.setOpacity); -/** - * Remove single Cesium object from the collection. - * @param {!T} object - * @param {boolean} destroy - * @protected - */ -olcs.AbstractSynchronizer.prototype.removeSingleCesiumObject = - goog.abstractMethod; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setVisible', + ol.layer.VectorTile.prototype.setVisible); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setZIndex', + ol.layer.VectorTile.prototype.setZIndex); -/** - * Remove all Cesium objects from the collection. - * @param {boolean} destroy - * @protected - */ -olcs.AbstractSynchronizer.prototype.removeAllCesiumObjects = - goog.abstractMethod; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'get', + ol.layer.VectorTile.prototype.get); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getKeys', + ol.layer.VectorTile.prototype.getKeys); -/** - * @param {!ol.layer.Base} olLayer - * @return {?Array.<T>} - * @protected - */ -olcs.AbstractSynchronizer.prototype.createSingleLayerCounterparts = - goog.abstractMethod; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getProperties', + ol.layer.VectorTile.prototype.getProperties); -// Apache v2 license -// https://github.com/TerriaJS/terriajs/blob/ -// ebd382a8278a817fce316730d9e459bbb9b829e9/lib/Models/Cesium.js +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'set', + ol.layer.VectorTile.prototype.set); -goog.provide('olcs.AutoRenderLoop'); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'setProperties', + ol.layer.VectorTile.prototype.setProperties); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'unset', + ol.layer.VectorTile.prototype.unset); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'changed', + ol.layer.VectorTile.prototype.changed); -/** - * @constructor - * @param {olcs.OLCesium} ol3d - * @param {boolean} debug - */ -olcs.AutoRenderLoop = function(ol3d, debug) { - this.ol3d = ol3d; - this.scene_ = ol3d.getCesiumScene(); - this.verboseRendering = debug; - this._boundNotifyRepaintRequired = this.notifyRepaintRequired.bind(this); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'dispatchEvent', + ol.layer.VectorTile.prototype.dispatchEvent); - this.lastCameraViewMatrix_ = new Cesium.Matrix4(); - this.lastCameraMoveTime_ = 0; - this.stoppedRendering = false; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'getRevision', + ol.layer.VectorTile.prototype.getRevision); - this._removePostRenderListener = this.scene_.postRender.addEventListener( - this.postRender.bind(this)); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'on', + ol.layer.VectorTile.prototype.on); +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'once', + ol.layer.VectorTile.prototype.once); - // Detect available wheel event - this._wheelEvent = ''; - if ('onwheel' in this.scene_.canvas) { - // spec event type - this._wheelEvent = 'wheel'; - } else if (!!document['onmousewheel']) { - // legacy event type - this._wheelEvent = 'mousewheel'; - } else { - // older Firefox - this._wheelEvent = 'DOMMouseScroll'; - } +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'un', + ol.layer.VectorTile.prototype.un); - this._originalLoadWithXhr = Cesium.loadWithXhr.load; - this._originalScheduleTask = Cesium.TaskProcessor.prototype.scheduleTask; - this._originalCameraSetView = Cesium.Camera.prototype.setView; - this._originalCameraMove = Cesium.Camera.prototype.move; - this._originalCameraRotate = Cesium.Camera.prototype.rotate; - this._originalCameraLookAt = Cesium.Camera.prototype.lookAt; - this._originalCameraFlyTo = Cesium.Camera.prototype.flyTo; +goog.exportProperty( + ol.layer.VectorTile.prototype, + 'unByKey', + ol.layer.VectorTile.prototype.unByKey); - this.enable(); -}; +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'get', + ol.interaction.Interaction.prototype.get); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'getKeys', + ol.interaction.Interaction.prototype.getKeys); -/** - * Force a repaint when the mouse moves or the window changes size. - * @param {string} key - * @param {boolean} capture - * @private - */ -olcs.AutoRenderLoop.prototype.repaintOn_ = function(key, capture) { - var canvas = this.scene_.canvas; - canvas.addEventListener(key, this._boundNotifyRepaintRequired, capture); -}; +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'getProperties', + ol.interaction.Interaction.prototype.getProperties); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'set', + ol.interaction.Interaction.prototype.set); -/** - * @param {string} key - * @param {boolean} capture - * @private - */ -olcs.AutoRenderLoop.prototype.removeRepaintOn_ = function(key, capture) { - var canvas = this.scene_.canvas; - canvas.removeEventListener(key, this._boundNotifyRepaintRequired, capture); -}; +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'setProperties', + ol.interaction.Interaction.prototype.setProperties); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'unset', + ol.interaction.Interaction.prototype.unset); -/** - * Enable. - */ -olcs.AutoRenderLoop.prototype.enable = function() { - this.repaintOn_('mousemove', false); - this.repaintOn_('mousedown', false); - this.repaintOn_('mouseup', false); - this.repaintOn_('touchstart', false); - this.repaintOn_('touchend', false); - this.repaintOn_('touchmove', false); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'changed', + ol.interaction.Interaction.prototype.changed); - if (!!window['PointerEvent']) { - this.repaintOn_('pointerdown', false); - this.repaintOn_('pointerup', false); - this.repaintOn_('pointermove', false); - } +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'dispatchEvent', + ol.interaction.Interaction.prototype.dispatchEvent); - this.repaintOn_(this._wheelEvent, false); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'getRevision', + ol.interaction.Interaction.prototype.getRevision); - window.addEventListener('resize', this._boundNotifyRepaintRequired, false); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'on', + ol.interaction.Interaction.prototype.on); - // Hacky way to force a repaint when an async load request completes - var that = this; - Cesium.loadWithXhr.load = function(url, responseType, method, data, - headers, deferred, overrideMimeType, preferText, timeout) { - deferred['promise']['always'](that._boundNotifyRepaintRequired); - that._originalLoadWithXhr(url, responseType, method, data, headers, - deferred, overrideMimeType, preferText, timeout); - }; +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'once', + ol.interaction.Interaction.prototype.once); - // Hacky way to force a repaint when a web worker sends something back. - Cesium.TaskProcessor.prototype.scheduleTask = - function(parameters, transferableObjects) { - var result = that._originalScheduleTask.call(this, parameters, - transferableObjects); +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'un', + ol.interaction.Interaction.prototype.un); - var taskProcessor = this; - if (!taskProcessor._originalWorkerMessageSinkRepaint) { - var worker = taskProcessor['_worker']; - taskProcessor._originalWorkerMessageSinkRepaint = worker.onmessage; - worker.onmessage = function(event) { - taskProcessor._originalWorkerMessageSinkRepaint(event); - that.notifyRepaintRequired(); - }; - } +goog.exportProperty( + ol.interaction.Interaction.prototype, + 'unByKey', + ol.interaction.Interaction.prototype.unByKey); - return result; - }; +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'getActive', + ol.interaction.DoubleClickZoom.prototype.getActive); - Cesium.Camera.prototype.setView = function() { - that._originalCameraSetView.apply(this, arguments); - that.notifyRepaintRequired(); - }; - Cesium.Camera.prototype.move = function() { - that._originalCameraMove.apply(this, arguments); - that.notifyRepaintRequired(); - }; - Cesium.Camera.prototype.rotate = function() { - that._originalCameraRotate.apply(this, arguments); - that.notifyRepaintRequired(); - }; - Cesium.Camera.prototype.lookAt = function() { - that._originalCameraLookAt.apply(this, arguments); - that.notifyRepaintRequired(); - }; - Cesium.Camera.prototype.flyTo = function() { - that._originalCameraFlyTo.apply(this, arguments); - that.notifyRepaintRequired(); - }; +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'setActive', + ol.interaction.DoubleClickZoom.prototype.setActive); - // Listen for changes on the layer group - this.ol3d.getOlMap().getLayerGroup().on('change', - this._boundNotifyRepaintRequired); -}; +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'get', + ol.interaction.DoubleClickZoom.prototype.get); +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'getKeys', + ol.interaction.DoubleClickZoom.prototype.getKeys); -/** - * Disable. - */ -olcs.AutoRenderLoop.prototype.disable = function() { - if (!!this._removePostRenderListener) { - this._removePostRenderListener(); - this._removePostRenderListener = undefined; - } +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'getProperties', + ol.interaction.DoubleClickZoom.prototype.getProperties); - this.removeRepaintOn_('mousemove', false); - this.removeRepaintOn_('mousedown', false); - this.removeRepaintOn_('mouseup', false); - this.removeRepaintOn_('touchstart', false); - this.removeRepaintOn_('touchend', false); - this.removeRepaintOn_('touchmove', false); +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'set', + ol.interaction.DoubleClickZoom.prototype.set); - if (!!window['PointerEvent']) { - this.removeRepaintOn_('pointerdown', false); - this.removeRepaintOn_('pointerup', false); - this.removeRepaintOn_('pointermove', false); - } +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'setProperties', + ol.interaction.DoubleClickZoom.prototype.setProperties); - this.removeRepaintOn_(this._wheelEvent, false); +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'unset', + ol.interaction.DoubleClickZoom.prototype.unset); - window.removeEventListener('resize', this._boundNotifyRepaintRequired, false); +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'changed', + ol.interaction.DoubleClickZoom.prototype.changed); - Cesium.loadWithXhr.load = this._originalLoadWithXhr; - Cesium.TaskProcessor.prototype.scheduleTask = this._originalScheduleTask; - Cesium.Camera.prototype.setView = this._originalCameraSetView; - Cesium.Camera.prototype.move = this._originalCameraMove; - Cesium.Camera.prototype.rotate = this._originalCameraRotate; - Cesium.Camera.prototype.lookAt = this._originalCameraLookAt; - Cesium.Camera.prototype.flyTo = this._originalCameraFlyTo; +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'dispatchEvent', + ol.interaction.DoubleClickZoom.prototype.dispatchEvent); - this.ol3d.getOlMap().getLayerGroup().un('change', - this._boundNotifyRepaintRequired); -}; +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'getRevision', + ol.interaction.DoubleClickZoom.prototype.getRevision); +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'on', + ol.interaction.DoubleClickZoom.prototype.on); -/** - * @param {number} date - */ -olcs.AutoRenderLoop.prototype.postRender = function(date) { - // We can safely stop rendering when: - // - the camera position hasn't changed in over a second, - // - there are no tiles waiting to load, and - // - the clock is not animating - // - there are no tweens in progress +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'once', + ol.interaction.DoubleClickZoom.prototype.once); - var now = Date.now(); +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'un', + ol.interaction.DoubleClickZoom.prototype.un); - var scene = this.scene_; - var camera = scene.camera; +goog.exportProperty( + ol.interaction.DoubleClickZoom.prototype, + 'unByKey', + ol.interaction.DoubleClickZoom.prototype.unByKey); - if (!Cesium.Matrix4.equalsEpsilon(this.lastCameraViewMatrix_, - camera.viewMatrix, 1e-5)) { - this.lastCameraMoveTime_ = now; - } +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'getActive', + ol.interaction.DragAndDrop.prototype.getActive); - var cameraMovedInLastSecond = now - this.lastCameraMoveTime_ < 1000; +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'setActive', + ol.interaction.DragAndDrop.prototype.setActive); - var surface = scene.globe['_surface']; - var tilesWaiting = !surface['_tileProvider'].ready || - surface['_tileLoadQueue'].length > 0 || - surface['_debug']['tilesWaitingForChildren'] > 0; +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'get', + ol.interaction.DragAndDrop.prototype.get); - var tweens = scene['tweens']; - if (!cameraMovedInLastSecond && !tilesWaiting && tweens.length == 0) { - if (this.verboseRendering) { - console.log('stopping rendering @ ' + Date.now()); - } - this.ol3d.setBlockCesiumRendering(true); - this.stoppedRendering = true; - } +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'getKeys', + ol.interaction.DragAndDrop.prototype.getKeys); - Cesium.Matrix4.clone(camera.viewMatrix, this.lastCameraViewMatrix_); -}; +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'getProperties', + ol.interaction.DragAndDrop.prototype.getProperties); +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'set', + ol.interaction.DragAndDrop.prototype.set); -/** - * Restart render loop. - * Force a restart of the render loop. - * @api - */ -olcs.AutoRenderLoop.prototype.restartRenderLoop = function() { - this.notifyRepaintRequired(); -}; +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'setProperties', + ol.interaction.DragAndDrop.prototype.setProperties); +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'unset', + ol.interaction.DragAndDrop.prototype.unset); -/** - * Notifies the viewer that a repaint is required. - */ -olcs.AutoRenderLoop.prototype.notifyRepaintRequired = function() { - if (this.verboseRendering && this.stoppedRendering) { - console.log('starting rendering @ ' + Date.now()); - } - this._lastCameraMoveTime = Date.now(); - // TODO: do not unblock if not blocked by us - this.ol3d.setBlockCesiumRendering(false); - this.stoppedRendering = false; -}; +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'changed', + ol.interaction.DragAndDrop.prototype.changed); + +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'dispatchEvent', + ol.interaction.DragAndDrop.prototype.dispatchEvent); +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'getRevision', + ol.interaction.DragAndDrop.prototype.getRevision); -/** - * @param {boolean} debug - * @api - */ -olcs.AutoRenderLoop.prototype.setDebug = function(debug) { - this.verboseRendering = debug; -}; +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'on', + ol.interaction.DragAndDrop.prototype.on); -goog.provide('olcs.core.OLImageryProvider'); +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'once', + ol.interaction.DragAndDrop.prototype.once); -goog.require('goog.events'); -goog.require('ol.proj'); +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'un', + ol.interaction.DragAndDrop.prototype.un); +goog.exportProperty( + ol.interaction.DragAndDrop.prototype, + 'unByKey', + ol.interaction.DragAndDrop.prototype.unByKey); +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'getActive', + ol.interaction.Pointer.prototype.getActive); -/** - * Special class derived from Cesium.ImageryProvider - * that is connected to the given ol.source.TileImage. - * @param {!ol.source.TileImage} source - * @param {ol.proj.Projection=} opt_fallbackProj Projection to assume if the - * projection of the source - * is not defined. - * @constructor - * @extends {Cesium.ImageryProvider} - */ -olcs.core.OLImageryProvider = function(source, opt_fallbackProj) { - // Do not goog.inherit() or call super constructor from - // Cesium.ImageryProvider since this particular function is a - // 'non instanciable interface' which throws on instanciation. +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'setActive', + ol.interaction.Pointer.prototype.setActive); - /** - * @type {!ol.source.TileImage} - * @private - */ - this.source_ = source; +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'get', + ol.interaction.Pointer.prototype.get); - /** - * @type {?ol.proj.Projection} - * @private - */ - this.projection_ = null; +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'getKeys', + ol.interaction.Pointer.prototype.getKeys); - /** - * @type {?ol.proj.Projection} - * @private - */ - this.fallbackProj_ = goog.isDef(opt_fallbackProj) ? opt_fallbackProj : null; +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'getProperties', + ol.interaction.Pointer.prototype.getProperties); - this.ready_ = false; +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'set', + ol.interaction.Pointer.prototype.set); - this.errorEvent_ = new Cesium.Event(); +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'setProperties', + ol.interaction.Pointer.prototype.setProperties); - this.emptyCanvas_ = goog.dom.createElement(goog.dom.TagName.CANVAS); - this.emptyCanvas_.width = 1; - this.emptyCanvas_.height = 1; +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'unset', + ol.interaction.Pointer.prototype.unset); + +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'changed', + ol.interaction.Pointer.prototype.changed); + +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'dispatchEvent', + ol.interaction.Pointer.prototype.dispatchEvent); + +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'getRevision', + ol.interaction.Pointer.prototype.getRevision); - this.source_.on(goog.events.EventType.CHANGE, function(e) { - this.handleSourceChanged_(); - }, this); - this.handleSourceChanged_(); -}; +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'on', + ol.interaction.Pointer.prototype.on); +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'once', + ol.interaction.Pointer.prototype.once); -// definitions of getters that are required to be present -// in the Cesium.ImageryProvider instance: -Object.defineProperties(olcs.core.OLImageryProvider.prototype, { - ready: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() {return this.ready_;} - }, +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'un', + ol.interaction.Pointer.prototype.un); - rectangle: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() {return this.rectangle_;} - }, +goog.exportProperty( + ol.interaction.Pointer.prototype, + 'unByKey', + ol.interaction.Pointer.prototype.unByKey); - tileWidth: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() { - var tg = this.source_.getTileGrid(); - return !goog.isNull(tg) ? tg.getTileSize(0) : 256; - } - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'getActive', + ol.interaction.DragBox.prototype.getActive); - tileHeight: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() {return this.tileWidth;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'setActive', + ol.interaction.DragBox.prototype.setActive); - maximumLevel: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() { - var tg = this.source_.getTileGrid(); - return !goog.isNull(tg) ? tg.getMaxZoom() : 18; - } - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'get', + ol.interaction.DragBox.prototype.get); - minimumLevel: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() { - // WARNING: Do not use the minimum level (at least until the extent is - // properly set). Cesium assumes the minimumLevel to contain only - // a few tiles and tries to load them all at once -- this can - // freeze and/or crash the browser ! - return 0; - //var tg = this.source_.getTileGrid(); - //return !goog.isNull(tg) ? tg.getMinZoom() : 0; - } - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'getKeys', + ol.interaction.DragBox.prototype.getKeys); - tilingScheme: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() {return this.tilingScheme_;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'getProperties', + ol.interaction.DragBox.prototype.getProperties); - tileDiscardPolicy: { - get: function() {return undefined;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'set', + ol.interaction.DragBox.prototype.set); - errorEvent: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() {return this.errorEvent_;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'setProperties', + ol.interaction.DragBox.prototype.setProperties); - credit: { - get: /** @this {olcs.core.OLImageryProvider} */ - function() {return this.credit_;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'unset', + ol.interaction.DragBox.prototype.unset); - proxy: { - get: function() {return undefined;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'changed', + ol.interaction.DragBox.prototype.changed); - hasAlphaChannel: { - get: function() {return true;} - }, +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'dispatchEvent', + ol.interaction.DragBox.prototype.dispatchEvent); - pickFeatures: { - get: function() {return undefined;} - } -}); +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'getRevision', + ol.interaction.DragBox.prototype.getRevision); +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'on', + ol.interaction.DragBox.prototype.on); -/** - * Checks if the underlying source is ready and cached required data. - * @private - */ -olcs.core.OLImageryProvider.prototype.handleSourceChanged_ = function() { - if (!this.ready_ && this.source_.getState() == 'ready') { - var proj = this.source_.getProjection(); - this.projection_ = goog.isDefAndNotNull(proj) ? proj : this.fallbackProj_; - if (this.projection_ == ol.proj.get('EPSG:4326')) { - this.tilingScheme_ = new Cesium.GeographicTilingScheme(); - } else if (this.projection_ == ol.proj.get('EPSG:3857')) { - this.tilingScheme_ = new Cesium.WebMercatorTilingScheme(); - } else { - return; - } - this.rectangle_ = this.tilingScheme_.rectangle; +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'once', + ol.interaction.DragBox.prototype.once); - var credit = - olcs.core.OLImageryProvider.createCreditForSource(this.source_); - this.credit_ = !goog.isNull(credit) ? credit : undefined; +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'un', + ol.interaction.DragBox.prototype.un); - this.ready_ = true; - } -}; +goog.exportProperty( + ol.interaction.DragBox.prototype, + 'unByKey', + ol.interaction.DragBox.prototype.unByKey); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'getActive', + ol.interaction.DragPan.prototype.getActive); -/** - * Tries to create proper Cesium.Credit for - * the given ol.source.Source as closely as possible. - * @param {!ol.source.Source} source - * @return {?Cesium.Credit} - */ -olcs.core.OLImageryProvider.createCreditForSource = function(source) { - var text = ''; - var attributions = source.getAttributions(); - if (!goog.isNull(attributions)) { - attributions.forEach(function(el) { - // strip html tags (not supported in Cesium) - text += el.getHTML().replace(/<\/?[^>]+(>|$)/g, '') + ' '; - }); - } +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'setActive', + ol.interaction.DragPan.prototype.setActive); - var imageUrl, link; - if (text.length == 0) { - // only use logo if no text is specified - // otherwise the Cesium will automatically skip the text: - // "The text to be displayed on the screen if no imageUrl is specified." - var logo = source.getLogo(); - if (goog.isDef(logo)) { - if (typeof logo == 'string') { - imageUrl = logo; - } else { - imageUrl = logo.src; - link = logo.href; - } - } - } +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'get', + ol.interaction.DragPan.prototype.get); - return (goog.isDef(imageUrl) || text.length > 0) ? - new Cesium.Credit(text, imageUrl, link) : null; -}; +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'getKeys', + ol.interaction.DragPan.prototype.getKeys); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'getProperties', + ol.interaction.DragPan.prototype.getProperties); -/** - * TODO: attributions for individual tile ranges - * @override - */ -olcs.core.OLImageryProvider.prototype.getTileCredits = function(x, y, level) { - return undefined; -}; -goog.exportProperty(olcs.core.OLImageryProvider.prototype, 'getTileCredits', - olcs.core.OLImageryProvider.prototype.getTileCredits); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'set', + ol.interaction.DragPan.prototype.set); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'setProperties', + ol.interaction.DragPan.prototype.setProperties); -/** - * @override - */ -olcs.core.OLImageryProvider.prototype.requestImage = function(x, y, level) { - var tileUrlFunction = this.source_.getTileUrlFunction(); - if (!goog.isNull(tileUrlFunction) && !goog.isNull(this.projection_)) { +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'unset', + ol.interaction.DragPan.prototype.unset); - // Perform mapping of Cesium tile coordinates to ol3 tile coordinates: - // 1) Cesium zoom level 0 is OpenLayers zoom level 1 for EPSG:4326 - var z_ = this.tilingScheme_ instanceof Cesium.GeographicTilingScheme ? - level + 1 : level; - // 2) OpenLayers tile coordinates increase from bottom to top - var y_ = -y - 1; +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'changed', + ol.interaction.DragPan.prototype.changed); - var url = tileUrlFunction([z_, x, y_], 1, this.projection_); - return goog.isDef(url) ? - Cesium.ImageryProvider.loadImage(this, url) : this.emptyCanvas_; - } else { - // return empty canvas to stop Cesium from retrying later - return this.emptyCanvas_; - } -}; -goog.exportProperty(olcs.core.OLImageryProvider.prototype, 'requestImage', - olcs.core.OLImageryProvider.prototype.requestImage); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'dispatchEvent', + ol.interaction.DragPan.prototype.dispatchEvent); -goog.provide('olcs.core'); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'getRevision', + ol.interaction.DragPan.prototype.getRevision); -goog.require('goog.asserts'); -goog.require('goog.async.AnimationDelay'); -goog.require('ol.layer.Tile'); -goog.require('ol.proj'); -goog.require('ol.source.TileImage'); -goog.require('ol.source.WMTS'); -goog.require('olcs.core.OLImageryProvider'); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'on', + ol.interaction.DragPan.prototype.on); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'once', + ol.interaction.DragPan.prototype.once); -/** - * Compute the pixel width and height of a point in meters using the - * camera frustum. - * @param {!Cesium.Scene} scene - * @param {!Cesium.Cartesian3} target - * @return {!Cesium.Cartesian2} the pixel size - * @api - */ -olcs.core.computePixelSizeAtCoordinate = function(scene, target) { - var camera = scene.camera; - var canvas = scene.canvas; - var frustum = camera.frustum; - var canvasDimensions = new Cesium.Cartesian2( - canvas.clientWidth, canvas.clientHeight); - var distance = Cesium.Cartesian3.magnitude(Cesium.Cartesian3.subtract( - camera.position, target, new Cesium.Cartesian3())); - var pixelSize = frustum.getPixelSize(canvasDimensions, distance); - return pixelSize; -}; +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'un', + ol.interaction.DragPan.prototype.un); +goog.exportProperty( + ol.interaction.DragPan.prototype, + 'unByKey', + ol.interaction.DragPan.prototype.unByKey); -/** - * Compute bounding box around a target point. - * @param {!Cesium.Scene} scene - * @param {!Cesium.Cartesian3} target - * @param {number} amount Half the side of the box, in pixels. - * @return {Array<Cesium.Cartographic>} bottom left and top right - * coordinates of the box - */ -olcs.core.computeBoundingBoxAtTarget = function(scene, target, amount) { - var pixelSize = olcs.core.computePixelSizeAtCoordinate(scene, target); - var transform = Cesium.Transforms.eastNorthUpToFixedFrame(target); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'getActive', + ol.interaction.DragRotateAndZoom.prototype.getActive); - var bottomLeft = Cesium.Matrix4.multiplyByPoint( - transform, - new Cesium.Cartesian3(-pixelSize.x * amount, -pixelSize.y * amount, 0), - new Cesium.Cartesian3()); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'setActive', + ol.interaction.DragRotateAndZoom.prototype.setActive); - var topRight = Cesium.Matrix4.multiplyByPoint( - transform, - new Cesium.Cartesian3(pixelSize.x * amount, pixelSize.y * amount, 0), - new Cesium.Cartesian3()); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'get', + ol.interaction.DragRotateAndZoom.prototype.get); - return Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray( - [bottomLeft, topRight]); -}; +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'getKeys', + ol.interaction.DragRotateAndZoom.prototype.getKeys); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'getProperties', + ol.interaction.DragRotateAndZoom.prototype.getProperties); -/** - * - * @param {!ol.geom.Geometry} geometry - * @param {number} height - * @api - */ -olcs.core.applyHeightOffsetToGeometry = function(geometry, height) { - geometry.applyTransform(function(input, output, stride) { - goog.asserts.assert(input === output); - if (goog.isDef(stride) && stride >= 3) { - for (var i = 0; i < output.length; i += stride) { - output[i + 2] = output[i + 2] + height; - } - } - return output; - }); -}; +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'set', + ol.interaction.DragRotateAndZoom.prototype.set); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'setProperties', + ol.interaction.DragRotateAndZoom.prototype.setProperties); -/** - * @param {!Cesium.Camera} camera - * @param {number} angle - * @param {!Cesium.Cartesian3} axis - * @param {!Cesium.Matrix4} transform - * @param {olcsx.core.RotateAroundAxisOption=} opt_options - * @api - */ -olcs.core.rotateAroundAxis = function(camera, angle, axis, transform, - opt_options) { - var clamp = Cesium.Math.clamp; - var defaultValue = Cesium.defaultValue; +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'unset', + ol.interaction.DragRotateAndZoom.prototype.unset); - var options = opt_options || {}; - var duration = defaultValue(options.duration, 500); // ms - var easing = defaultValue(options.easing, ol.easing.linear); - var callback = options.callback; +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'changed', + ol.interaction.DragRotateAndZoom.prototype.changed); - var start = goog.now(); - var lastProgress = 0; - var oldTransform = new Cesium.Matrix4(); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'dispatchEvent', + ol.interaction.DragRotateAndZoom.prototype.dispatchEvent); - var animation = new goog.async.AnimationDelay(function(millis) { - var progress = easing(clamp((millis - start) / duration, 0, 1)); - goog.asserts.assert(progress > lastProgress); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'getRevision', + ol.interaction.DragRotateAndZoom.prototype.getRevision); - camera.transform.clone(oldTransform); - var stepAngle = (progress - lastProgress) * angle; - lastProgress = progress; - camera.lookAtTransform(transform); - camera.rotate(axis, stepAngle); - camera.lookAtTransform(oldTransform); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'on', + ol.interaction.DragRotateAndZoom.prototype.on); - if (progress < 1) { - animation.start(); - } else if (callback) { - callback(); - } - }); - animation.start(); -}; +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'once', + ol.interaction.DragRotateAndZoom.prototype.once); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'un', + ol.interaction.DragRotateAndZoom.prototype.un); -/** - * @param {!Cesium.Scene} scene - * @param {number} heading - * @param {!Cesium.Cartesian3} bottomCenter - * @param {olcsx.core.RotateAroundAxisOption=} opt_options - * @api - */ -olcs.core.setHeadingUsingBottomCenter = function(scene, heading, - bottomCenter, opt_options) { - var camera = scene.camera; - // Compute the camera position to zenith quaternion - var angleToZenith = olcs.core.computeAngleToZenith(scene, bottomCenter); - var axis = camera.right; - var quaternion = Cesium.Quaternion.fromAxisAngle(axis, angleToZenith); - var rotation = Cesium.Matrix3.fromQuaternion(quaternion); +goog.exportProperty( + ol.interaction.DragRotateAndZoom.prototype, + 'unByKey', + ol.interaction.DragRotateAndZoom.prototype.unByKey); - // Get the zenith point from the rotation of the position vector - var vector = new Cesium.Cartesian3(); - Cesium.Cartesian3.subtract(camera.position, bottomCenter, vector); - var zenith = new Cesium.Cartesian3(); - Cesium.Matrix3.multiplyByVector(rotation, vector, zenith); - Cesium.Cartesian3.add(zenith, bottomCenter, zenith); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'getActive', + ol.interaction.DragRotate.prototype.getActive); - // Actually rotate around the zenith normal - var transform = Cesium.Matrix4.fromTranslation(zenith); - var rotateAroundAxis = olcs.core.rotateAroundAxis; - rotateAroundAxis(camera, heading, zenith, transform, opt_options); -}; +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'setActive', + ol.interaction.DragRotate.prototype.setActive); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'get', + ol.interaction.DragRotate.prototype.get); -/** - * Get the 3D position of the given pixel of the canvas. - * @param {!Cesium.Scene} scene - * @param {!Cesium.Cartesian2} pixel - * @return {!Cesium.Cartesian3|undefined} - * @api - */ -olcs.core.pickOnTerrainOrEllipsoid = function(scene, pixel) { - var ray = scene.camera.getPickRay(pixel); - var target = scene.globe.pick(ray, scene); - return target || scene.camera.pickEllipsoid(pixel); -}; +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'getKeys', + ol.interaction.DragRotate.prototype.getKeys); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'getProperties', + ol.interaction.DragRotate.prototype.getProperties); -/** - * Get the 3D position of the point at the bottom-center of the screen. - * @param {!Cesium.Scene} scene - * @return {!Cesium.Cartesian3|undefined} - * @api - */ -olcs.core.pickBottomPoint = function(scene) { - var canvas = scene.canvas; - var bottom = new Cesium.Cartesian2( - canvas.clientWidth / 2, canvas.clientHeight); - return olcs.core.pickOnTerrainOrEllipsoid(scene, bottom); -}; +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'set', + ol.interaction.DragRotate.prototype.set); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'setProperties', + ol.interaction.DragRotate.prototype.setProperties); -/** - * Get the 3D position of the point at the center of the screen. - * @param {!Cesium.Scene} scene - * @return {!Cesium.Cartesian3|undefined} - * @api - */ -olcs.core.pickCenterPoint = function(scene) { - var canvas = scene.canvas; - var center = new Cesium.Cartesian2( - canvas.clientWidth / 2, - canvas.clientHeight / 2); - return olcs.core.pickOnTerrainOrEllipsoid(scene, center); -}; +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'unset', + ol.interaction.DragRotate.prototype.unset); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'changed', + ol.interaction.DragRotate.prototype.changed); -/** - * Compute the signed tilt angle on globe, between the opposite of the - * camera direction and the target normal. Return undefined if there is no - * intersection of the camera direction with the globe. - * @param {!Cesium.Scene} scene - * @return {number|undefined} - * @api - */ -olcs.core.computeSignedTiltAngleOnGlobe = function(scene) { - var camera = scene.camera; - var ray = new Cesium.Ray(camera.position, camera.direction); - var target = scene.globe.pick(ray, scene); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'dispatchEvent', + ol.interaction.DragRotate.prototype.dispatchEvent); - if (!target) { - // no tiles in the area were loaded? - var ellipsoid = Cesium.Ellipsoid.WGS84; - var obj = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid); - if (obj) { - target = Cesium.Ray.getPoint(ray, obj.start); - } - } +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'getRevision', + ol.interaction.DragRotate.prototype.getRevision); - if (!target) { - return undefined; - } +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'on', + ol.interaction.DragRotate.prototype.on); - var normal = new Cesium.Cartesian3(); - Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(target, normal); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'once', + ol.interaction.DragRotate.prototype.once); - var angleBetween = olcs.core.signedAngleBetween; - var angle = angleBetween(camera.direction, normal, camera.right) - Math.PI; - return Cesium.Math.convertLongitudeRange(angle); -}; +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'un', + ol.interaction.DragRotate.prototype.un); +goog.exportProperty( + ol.interaction.DragRotate.prototype, + 'unByKey', + ol.interaction.DragRotate.prototype.unByKey); -/** - * Compute the ray from the camera to the bottom-center of the screen. - * @param {!Cesium.Scene} scene - * @return {!Cesium.Ray} - */ -olcs.core.bottomFovRay = function(scene) { - var camera = scene.camera; - var fovy2 = camera.frustum.fovy / 2; - var direction = camera.direction; - var rotation = Cesium.Quaternion.fromAxisAngle(camera.right, fovy2); - var matrix = Cesium.Matrix3.fromQuaternion(rotation); - var vector = new Cesium.Cartesian3(); - Cesium.Matrix3.multiplyByVector(matrix, direction, vector); - return new Cesium.Ray(camera.position, vector); -}; +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'getGeometry', + ol.interaction.DragZoom.prototype.getGeometry); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'getActive', + ol.interaction.DragZoom.prototype.getActive); -/** - * Compute the angle between two Cartesian3. - * @param {!Cesium.Cartesian3} first - * @param {!Cesium.Cartesian3} second - * @param {!Cesium.Cartesian3} normal Normal to test orientation against. - * @return {number} - */ -olcs.core.signedAngleBetween = function(first, second, normal) { - // We are using the dot for the angle. - // Then the cross and the dot for the sign. - var a = new Cesium.Cartesian3(); - var b = new Cesium.Cartesian3(); - var c = new Cesium.Cartesian3(); - Cesium.Cartesian3.normalize(first, a); - Cesium.Cartesian3.normalize(second, b); - Cesium.Cartesian3.cross(a, b, c); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'setActive', + ol.interaction.DragZoom.prototype.setActive); - var cosine = Cesium.Cartesian3.dot(a, b); - var sine = Cesium.Cartesian3.magnitude(c); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'get', + ol.interaction.DragZoom.prototype.get); - // Sign of the vector product and the orientation normal - var sign = Cesium.Cartesian3.dot(normal, c); - var angle = Math.atan2(sine, cosine); - return sign >= 0 ? angle : -angle; -}; +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'getKeys', + ol.interaction.DragZoom.prototype.getKeys); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'getProperties', + ol.interaction.DragZoom.prototype.getProperties); -/** - * Compute the rotation angle around a given point, needed to reach the - * zenith position. - * At a zenith position, the camera direction is going througth the earth - * center and the frustrum bottom ray is going through the chosen pivot - * point. - * The bottom-center of the screen is a good candidate for the pivot point. - * @param {!Cesium.Scene} scene - * @param {!Cesium.Cartesian3} pivot Point around which the camera rotates. - * @return {number} - * @api - */ -olcs.core.computeAngleToZenith = function(scene, pivot) { - // This angle is the sum of the angles 'fy' and 'a', which are defined - // using the pivot point and its surface normal. - // Zenith | camera - // \ | / - // \fy| / - // \ |a/ - // \|/pivot - var camera = scene.camera; - var fy = camera.frustum.fovy / 2; - var ray = olcs.core.bottomFovRay(scene); - var direction = Cesium.Cartesian3.clone(ray.direction); - Cesium.Cartesian3.negate(direction, direction); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'set', + ol.interaction.DragZoom.prototype.set); - var normal = new Cesium.Cartesian3(); - Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(pivot, normal); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'setProperties', + ol.interaction.DragZoom.prototype.setProperties); - var left = new Cesium.Cartesian3(); - Cesium.Cartesian3.negate(camera.right, left); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'unset', + ol.interaction.DragZoom.prototype.unset); - var a = olcs.core.signedAngleBetween(normal, direction, left); - return a + fy; -}; +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'changed', + ol.interaction.DragZoom.prototype.changed); + +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'dispatchEvent', + ol.interaction.DragZoom.prototype.dispatchEvent); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'getRevision', + ol.interaction.DragZoom.prototype.getRevision); -/** - * Rotate the camera so that its direction goes through the target point. - * If a globe is given, the target height is first interpolated from terrain. - * @param {!Cesium.Camera} camera - * @param {!Cesium.Cartographic} target - * @param {Cesium.Globe=} opt_globe - * @api - */ -olcs.core.lookAt = function(camera, target, opt_globe) { - if (goog.isDef(opt_globe)) { - var height = opt_globe.getHeight(target); - target.height = goog.isDef(height) ? height : 0; - } +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'on', + ol.interaction.DragZoom.prototype.on); - var ellipsoid = Cesium.Ellipsoid.WGS84; - var targetb = ellipsoid.cartographicToCartesian(target); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'once', + ol.interaction.DragZoom.prototype.once); - var position = camera.position; - var up = new Cesium.Cartesian3(); - ellipsoid.geocentricSurfaceNormal(position, up); +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'un', + ol.interaction.DragZoom.prototype.un); - camera.lookAt(position, targetb, up); -}; +goog.exportProperty( + ol.interaction.DragZoom.prototype, + 'unByKey', + ol.interaction.DragZoom.prototype.unByKey); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'getActive', + ol.interaction.Draw.prototype.getActive); -/** - * Convert an OpenLayers extent to a Cesium rectangle. - * @param {ol.Extent} extent Extent. - * @param {ol.proj.ProjectionLike} projection Extent projection. - * @return {Cesium.Rectangle} The corresponding Cesium rectangle. - * @api - */ -olcs.core.extentToRectangle = function(extent, projection) { - if (!goog.isNull(extent) && !goog.isNull(projection)) { - var ext = ol.proj.transformExtent(extent, projection, 'EPSG:4326'); - return Cesium.Rectangle.fromDegrees(ext[0], ext[1], ext[2], ext[3]); - } else { - return null; - } -}; +goog.exportProperty( + ol.interaction.Draw.prototype, + 'setActive', + ol.interaction.Draw.prototype.setActive); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'get', + ol.interaction.Draw.prototype.get); -/** - * Creates Cesium.ImageryLayer best corresponding to the given ol.layer.Layer. - * Only supports raster layers - * @param {!ol.layer.Base} olLayer - * @param {?ol.proj.Projection} viewProj Projection of the view. - * @return {?Cesium.ImageryLayer} null if not possible (or supported) - * @api - */ -olcs.core.tileLayerToImageryLayer = function(olLayer, viewProj) { - if (!(olLayer instanceof ol.layer.Tile)) { - return null; - } +goog.exportProperty( + ol.interaction.Draw.prototype, + 'getKeys', + ol.interaction.Draw.prototype.getKeys); - var provider = null; +goog.exportProperty( + ol.interaction.Draw.prototype, + 'getProperties', + ol.interaction.Draw.prototype.getProperties); - var source = olLayer.getSource(); - // handle special cases before the general synchronization - if (source instanceof ol.source.WMTS) { - // WMTS uses different TileGrid which is not currently supported - return null; - } - if (source instanceof ol.source.TileImage) { - var projection = source.getProjection(); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'set', + ol.interaction.Draw.prototype.set); - if (goog.isNull(projection)) { - // if not explicit, assume the same projection as view - projection = viewProj; - } else if (projection !== viewProj) { - return null; // do not sync layers with projections different than view - } +goog.exportProperty( + ol.interaction.Draw.prototype, + 'setProperties', + ol.interaction.Draw.prototype.setProperties); - var is3857 = projection === ol.proj.get('EPSG:3857'); - var is4326 = projection === ol.proj.get('EPSG:4326'); - if (is3857 || is4326) { - provider = new olcs.core.OLImageryProvider(source, viewProj); - } else { - return null; - } - } else { - // sources other than TileImage are currently not supported - return null; - } +goog.exportProperty( + ol.interaction.Draw.prototype, + 'unset', + ol.interaction.Draw.prototype.unset); - // the provider is always non-null if we got this far +goog.exportProperty( + ol.interaction.Draw.prototype, + 'changed', + ol.interaction.Draw.prototype.changed); - var layerOptions = {}; +goog.exportProperty( + ol.interaction.Draw.prototype, + 'dispatchEvent', + ol.interaction.Draw.prototype.dispatchEvent); - var ext = olLayer.getExtent(); - if (goog.isDefAndNotNull(ext) && !goog.isNull(viewProj)) { - layerOptions.rectangle = olcs.core.extentToRectangle(ext, viewProj); - } +goog.exportProperty( + ol.interaction.Draw.prototype, + 'getRevision', + ol.interaction.Draw.prototype.getRevision); - var cesiumLayer = new Cesium.ImageryLayer(provider, layerOptions); - return cesiumLayer; -}; +goog.exportProperty( + ol.interaction.Draw.prototype, + 'on', + ol.interaction.Draw.prototype.on); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'once', + ol.interaction.Draw.prototype.once); -/** - * Synchronizes the layer rendering properties (opacity, visible) - * to the given Cesium ImageryLayer. - * @param {!ol.layer.Base} olLayer - * @param {!Cesium.ImageryLayer} csLayer - * @api - */ -olcs.core.updateCesiumLayerProperties = function(olLayer, csLayer) { - var opacity = olLayer.getOpacity(); - if (goog.isDef(opacity)) { - csLayer.alpha = opacity; - } - var visible = olLayer.getVisible(); - if (goog.isDef(visible)) { - csLayer.show = visible; - } -}; +goog.exportProperty( + ol.interaction.Draw.prototype, + 'un', + ol.interaction.Draw.prototype.un); +goog.exportProperty( + ol.interaction.Draw.prototype, + 'unByKey', + ol.interaction.Draw.prototype.unByKey); -/** - * Convert a 2D or 3D OpenLayers coordinate to Cesium. - * @param {ol.Coordinate} coordinate Ol3 coordinate. - * @return {!Cesium.Cartesian3} Cesium cartesian coordinate - * @api - */ -olcs.core.ol4326CoordinateToCesiumCartesian = function(coordinate) { - var coo = coordinate; - goog.isDefAndNotNull(coo); - return coo.length > 2 ? - Cesium.Cartesian3.fromDegrees(coo[0], coo[1], coo[2]) : - Cesium.Cartesian3.fromDegrees(coo[0], coo[1]); -}; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'getActive', + ol.interaction.KeyboardPan.prototype.getActive); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'setActive', + ol.interaction.KeyboardPan.prototype.setActive); -/** - * Convert an array of 2D or 3D OpenLayers coordinates to Cesium. - * @param {Array.<!ol.Coordinate>} coordinates Ol3 coordinates. - * @return {!Array.<Cesium.Cartesian3>} Cesium cartesian coordinates - * @api - */ -olcs.core.ol4326CoordinateArrayToCsCartesians = function(coordinates) { - goog.asserts.assert(coordinates !== null); - var toCartesian = olcs.core.ol4326CoordinateToCesiumCartesian; - var cartesians = []; - for (var i = 0; i < coordinates.length; ++i) { - cartesians.push(toCartesian(coordinates[i])); - } - return cartesians; -}; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'get', + ol.interaction.KeyboardPan.prototype.get); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'getKeys', + ol.interaction.KeyboardPan.prototype.getKeys); -/** - * Reproject an OpenLayers geometry to EPSG:4326 if needed. - * The geometry will be cloned only when original projection is not EPSG:4326 - * and the properties will be shallow copied. - * @param {!T} geometry - * @param {!ol.proj.ProjectionLike} projection - * @return {!T} - * @template T - * @api - */ -olcs.core.olGeometryCloneTo4326 = function(geometry, projection) { - goog.asserts.assert(goog.isDef(projection)); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'getProperties', + ol.interaction.KeyboardPan.prototype.getProperties); - var proj4326 = ol.proj.get('EPSG:4326'); - var proj = ol.proj.get(projection); - if (proj !== proj4326) { - var properties = geometry.getProperties(); - geometry = geometry.clone(); - geometry.transform(proj, proj4326); - geometry.setProperties(properties); - } - return geometry; -}; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'set', + ol.interaction.KeyboardPan.prototype.set); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'setProperties', + ol.interaction.KeyboardPan.prototype.setProperties); -/** - * Convert an OpenLayers color to Cesium. - * @param {ol.Color|string} olColor - * @return {!Cesium.Color} - * @api - */ -olcs.core.convertColorToCesium = function(olColor) { - olColor = olColor || 'black'; - if (Array.isArray(olColor)) { - return new Cesium.Color( - Cesium.Color.byteToFloat(olColor[0]), - Cesium.Color.byteToFloat(olColor[1]), - Cesium.Color.byteToFloat(olColor[2]), - olColor[3] - ); - } else if (typeof olColor == 'string') { - return Cesium.Color.fromCssColorString(olColor); - } - goog.asserts.fail('impossible'); -}; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'unset', + ol.interaction.KeyboardPan.prototype.unset); -goog.provide('olcs.Camera'); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'changed', + ol.interaction.KeyboardPan.prototype.changed); -goog.require('goog.events'); -goog.require('ol.Observable'); -goog.require('ol.proj'); -goog.require('olcs.core'); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'dispatchEvent', + ol.interaction.KeyboardPan.prototype.dispatchEvent); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'getRevision', + ol.interaction.KeyboardPan.prototype.getRevision); +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'on', + ol.interaction.KeyboardPan.prototype.on); -/** - * This object takes care of additional 3d-specific properties of the view and - * ensures proper synchronization with the underlying raw Cesium.Camera object. - * @param {!Cesium.Scene} scene - * @param {!ol.Map} map - * @constructor - * @api - */ -olcs.Camera = function(scene, map) { - /** - * @type {!Cesium.Scene} - * @private - */ - this.scene_ = scene; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'once', + ol.interaction.KeyboardPan.prototype.once); - /** - * @type {!Cesium.Camera} - * @private - */ - this.cam_ = scene.camera; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'un', + ol.interaction.KeyboardPan.prototype.un); - /** - * @type {!ol.Map} - * @private - */ - this.map_ = map; +goog.exportProperty( + ol.interaction.KeyboardPan.prototype, + 'unByKey', + ol.interaction.KeyboardPan.prototype.unByKey); - /** - * @type {?ol.View} - * @private - */ - this.view_ = null; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'getActive', + ol.interaction.KeyboardZoom.prototype.getActive); - /** - * @type {?goog.events.Key} - * @private - */ - this.viewListenKey_ = null; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'setActive', + ol.interaction.KeyboardZoom.prototype.setActive); - /** - * @type {!ol.TransformFunction} - * @private - */ - this.toLonLat_ = olcs.Camera.identityProjection; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'get', + ol.interaction.KeyboardZoom.prototype.get); - /** - * @type {!ol.TransformFunction} - * @private - */ - this.fromLonLat_ = olcs.Camera.identityProjection; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'getKeys', + ol.interaction.KeyboardZoom.prototype.getKeys); - /** - * 0 -- topdown, PI/2 -- the horizon - * @type {number} - * @private - */ - this.tilt_ = 0; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'getProperties', + ol.interaction.KeyboardZoom.prototype.getProperties); - /** - * @type {number} - * @private - */ - this.distance_ = 0; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'set', + ol.interaction.KeyboardZoom.prototype.set); - /** - * @type {?Cesium.Matrix4} - * @private - */ - this.lastCameraViewMatrix_ = null; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'setProperties', + ol.interaction.KeyboardZoom.prototype.setProperties); - /** - * This is used to discard change events on view caused by updateView method. - * @type {boolean} - * @private - */ - this.viewUpdateInProgress_ = false; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'unset', + ol.interaction.KeyboardZoom.prototype.unset); - this.map_.on('change:view', function(e) { - this.setView_(this.map_.getView()); - }, this); - this.setView_(this.map_.getView()); -}; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'changed', + ol.interaction.KeyboardZoom.prototype.changed); +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'dispatchEvent', + ol.interaction.KeyboardZoom.prototype.dispatchEvent); -/** - * @param {Array.<number>} input Input coordinate array. - * @param {Array.<number>=} opt_output Output array of coordinate values. - * @param {number=} opt_dimension Dimension. - * @return {Array.<number>} Input coordinate array (same array as input). - */ -olcs.Camera.identityProjection = function(input, opt_output, opt_dimension) { - var dim = opt_dimension || input.length; - if (opt_output) { - for (var i = 0; i < dim; ++i) { - opt_output[i] = input[i]; - } - } - return input; -}; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'getRevision', + ol.interaction.KeyboardZoom.prototype.getRevision); +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'on', + ol.interaction.KeyboardZoom.prototype.on); -/** - * @param {?ol.View} view New view to use. - * @private - */ -olcs.Camera.prototype.setView_ = function(view) { - if (!goog.isNull(this.view_)) { - ol.Observable.unByKey(this.viewListenKey_); - this.viewListenKey_ = null; - } +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'once', + ol.interaction.KeyboardZoom.prototype.once); - this.view_ = view; - if (!goog.isNull(view)) { - var toLonLat = ol.proj.getTransform(view.getProjection(), 'EPSG:4326'); - var fromLonLat = ol.proj.getTransform('EPSG:4326', view.getProjection()); - goog.asserts.assert(toLonLat && fromLonLat); +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'un', + ol.interaction.KeyboardZoom.prototype.un); - this.toLonLat_ = toLonLat; - this.fromLonLat_ = fromLonLat; +goog.exportProperty( + ol.interaction.KeyboardZoom.prototype, + 'unByKey', + ol.interaction.KeyboardZoom.prototype.unByKey); - this.viewListenKey_ = view.on('propertychange', - this.handleViewEvent_, this); - this.readFromView(); - } else { - this.toLonLat_ = olcs.Camera.identityProjection; - this.fromLonLat_ = olcs.Camera.identityProjection; - } -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'getActive', + ol.interaction.Modify.prototype.getActive); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'setActive', + ol.interaction.Modify.prototype.setActive); -/** - * @param {?} e - * @private - */ -olcs.Camera.prototype.handleViewEvent_ = function(e) { - if (!this.viewUpdateInProgress_) { - this.readFromView(); - } -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'get', + ol.interaction.Modify.prototype.get); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'getKeys', + ol.interaction.Modify.prototype.getKeys); -/** - * @param {number} heading In radians. - * @api - */ -olcs.Camera.prototype.setHeading = function(heading) { - if (goog.isNull(this.view_)) { - return; - } +goog.exportProperty( + ol.interaction.Modify.prototype, + 'getProperties', + ol.interaction.Modify.prototype.getProperties); - this.view_.setRotation(heading); -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'set', + ol.interaction.Modify.prototype.set); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'setProperties', + ol.interaction.Modify.prototype.setProperties); -/** - * @return {number|undefined} Heading in radians. - * @api - */ -olcs.Camera.prototype.getHeading = function() { - if (goog.isNull(this.view_)) { - return undefined; - } - var rotation = this.view_.getRotation(); - return goog.isDef(rotation) ? rotation : 0; -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'unset', + ol.interaction.Modify.prototype.unset); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'changed', + ol.interaction.Modify.prototype.changed); -/** - * @param {number} tilt In radians. - * @api - */ -olcs.Camera.prototype.setTilt = function(tilt) { - this.tilt_ = tilt; - this.updateCamera_(); -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'dispatchEvent', + ol.interaction.Modify.prototype.dispatchEvent); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'getRevision', + ol.interaction.Modify.prototype.getRevision); -/** - * @return {number} Tilt in radians. - * @api - */ -olcs.Camera.prototype.getTilt = function() { - return this.tilt_; -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'on', + ol.interaction.Modify.prototype.on); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'once', + ol.interaction.Modify.prototype.once); -/** - * @param {number} distance In meters. - * @api - */ -olcs.Camera.prototype.setDistance = function(distance) { - this.distance_ = distance; - this.updateCamera_(); - this.updateView(); -}; +goog.exportProperty( + ol.interaction.Modify.prototype, + 'un', + ol.interaction.Modify.prototype.un); +goog.exportProperty( + ol.interaction.Modify.prototype, + 'unByKey', + ol.interaction.Modify.prototype.unByKey); -/** - * @return {number} Distance in meters. - * @api - */ -olcs.Camera.prototype.getDistance = function() { - return this.distance_; -}; +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'getActive', + ol.interaction.MouseWheelZoom.prototype.getActive); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'setActive', + ol.interaction.MouseWheelZoom.prototype.setActive); -/** - * Shortcut for ol.View.setCenter(). - * @param {!ol.Coordinate} center Same projection as the ol.View. - * @api - */ -olcs.Camera.prototype.setCenter = function(center) { - if (goog.isNull(this.view_)) { - return; - } - this.view_.setCenter(center); -}; +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'get', + ol.interaction.MouseWheelZoom.prototype.get); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'getKeys', + ol.interaction.MouseWheelZoom.prototype.getKeys); -/** - * Shortcut for ol.View.getCenter(). - * @return {ol.Coordinate|undefined} Same projection as the ol.View. - * @api - */ -olcs.Camera.prototype.getCenter = function() { - if (goog.isNull(this.view_)) { - return undefined; - } - return this.view_.getCenter(); -}; +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'getProperties', + ol.interaction.MouseWheelZoom.prototype.getProperties); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'set', + ol.interaction.MouseWheelZoom.prototype.set); -/** - * Sets the position of the camera. - * @param {!ol.Coordinate} position Same projection as the ol.View. - * @api - */ -olcs.Camera.prototype.setPosition = function(position) { - if (goog.isNull(this.toLonLat_)) { - return; - } - var ll = this.toLonLat_(position); - goog.asserts.assert(!goog.isNull(ll)); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'setProperties', + ol.interaction.MouseWheelZoom.prototype.setProperties); - var carto = new Cesium.Cartographic(goog.math.toRadians(ll[0]), - goog.math.toRadians(ll[1]), - this.getAltitude()); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'unset', + ol.interaction.MouseWheelZoom.prototype.unset); - this.cam_.position = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); - this.updateView(); -}; +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'changed', + ol.interaction.MouseWheelZoom.prototype.changed); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'dispatchEvent', + ol.interaction.MouseWheelZoom.prototype.dispatchEvent); -/** - * Calculates position under the camera. - * @return {!ol.Coordinate|undefined} Same projection as the ol.View. - * @api - */ -olcs.Camera.prototype.getPosition = function() { - if (goog.isNull(this.fromLonLat_)) { - return undefined; - } - var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic( - this.cam_.position); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'getRevision', + ol.interaction.MouseWheelZoom.prototype.getRevision); - var pos = this.fromLonLat_([goog.math.toDegrees(carto.longitude), - goog.math.toDegrees(carto.latitude)]); - goog.asserts.assert(!goog.isNull(pos)); - return pos; -}; +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'on', + ol.interaction.MouseWheelZoom.prototype.on); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'once', + ol.interaction.MouseWheelZoom.prototype.once); -/** - * @param {number} altitude In meters. - * @api - */ -olcs.Camera.prototype.setAltitude = function(altitude) { - var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic( - this.cam_.position); - carto.height = altitude; - this.cam_.position = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'un', + ol.interaction.MouseWheelZoom.prototype.un); - this.updateView(); -}; +goog.exportProperty( + ol.interaction.MouseWheelZoom.prototype, + 'unByKey', + ol.interaction.MouseWheelZoom.prototype.unByKey); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'getActive', + ol.interaction.PinchRotate.prototype.getActive); -/** - * @return {number} Altitude in meters. - * @api - */ -olcs.Camera.prototype.getAltitude = function() { - var carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic( - this.cam_.position); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'setActive', + ol.interaction.PinchRotate.prototype.setActive); - return carto.height; -}; +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'get', + ol.interaction.PinchRotate.prototype.get); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'getKeys', + ol.interaction.PinchRotate.prototype.getKeys); -/** - * Rotates the camera to point at the specified target. - * @param {!ol.Coordinate} position Same projection as the ol.View. - * @api - */ -olcs.Camera.prototype.lookAt = function(position) { - if (goog.isNull(this.toLonLat_)) { - return; - } - var ll = this.toLonLat_(position); - goog.asserts.assert(!goog.isNull(ll)); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'getProperties', + ol.interaction.PinchRotate.prototype.getProperties); + +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'set', + ol.interaction.PinchRotate.prototype.set); + +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'setProperties', + ol.interaction.PinchRotate.prototype.setProperties); + +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'unset', + ol.interaction.PinchRotate.prototype.unset); + +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'changed', + ol.interaction.PinchRotate.prototype.changed); + +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'dispatchEvent', + ol.interaction.PinchRotate.prototype.dispatchEvent); + +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'getRevision', + ol.interaction.PinchRotate.prototype.getRevision); - var carto = Cesium.Cartographic.fromDegrees(ll[0], ll[1]); - olcs.core.lookAt(this.cam_, carto, this.scene_.globe); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'on', + ol.interaction.PinchRotate.prototype.on); - this.updateView(); -}; +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'once', + ol.interaction.PinchRotate.prototype.once); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'un', + ol.interaction.PinchRotate.prototype.un); -/** - * Updates the state of the underlying Cesium.Camera - * according to the current values of the properties. - * @private - */ -olcs.Camera.prototype.updateCamera_ = function() { - if (goog.isNull(this.view_) || goog.isNull(this.toLonLat_)) { - return; - } - var center = this.view_.getCenter(); - if (!center) { - return; - } - var ll = this.toLonLat_(center); - goog.asserts.assert(!goog.isNull(ll)); +goog.exportProperty( + ol.interaction.PinchRotate.prototype, + 'unByKey', + ol.interaction.PinchRotate.prototype.unByKey); - var carto = new Cesium.Cartographic(goog.math.toRadians(ll[0]), - goog.math.toRadians(ll[1])); - if (this.scene_.globe) { - var height = this.scene_.globe.getHeight(carto); - carto.height = goog.isDef(height) ? height : 0; - } +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'getActive', + ol.interaction.PinchZoom.prototype.getActive); - var destination = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'setActive', + ol.interaction.PinchZoom.prototype.setActive); - /** @type {Cesium.optionsOrientation} */ - var orientation = { - pitch: this.tilt_ - Cesium.Math.PI_OVER_TWO, - heading: -this.view_.getRotation(), - roll: undefined - }; - this.cam_.setView({ - destination: destination, - orientation: orientation - }); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'get', + ol.interaction.PinchZoom.prototype.get); - this.cam_.moveBackward(this.distance_); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'getKeys', + ol.interaction.PinchZoom.prototype.getKeys); - this.checkCameraChange(true); -}; +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'getProperties', + ol.interaction.PinchZoom.prototype.getProperties); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'set', + ol.interaction.PinchZoom.prototype.set); -/** - * Calculates the values of the properties from the current ol.View state. - * @api - */ -olcs.Camera.prototype.readFromView = function() { - if (goog.isNull(this.view_) || goog.isNull(this.toLonLat_)) { - return; - } - var center = this.view_.getCenter(); - if (!goog.isDefAndNotNull(center)) { - return; - } - var ll = this.toLonLat_(center); - goog.asserts.assert(!goog.isNull(ll)); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'setProperties', + ol.interaction.PinchZoom.prototype.setProperties); - var resolution = this.view_.getResolution(); - this.distance_ = this.calcDistanceForResolution_( - goog.isDef(resolution) ? resolution : 0, goog.math.toRadians(ll[1])); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'unset', + ol.interaction.PinchZoom.prototype.unset); - this.updateCamera_(); -}; +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'changed', + ol.interaction.PinchZoom.prototype.changed); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'dispatchEvent', + ol.interaction.PinchZoom.prototype.dispatchEvent); -/** - * Calculates the values of the properties from the current Cesium.Camera state. - * Modifies the center, resolution and rotation properties of the view. - * @api - */ -olcs.Camera.prototype.updateView = function() { - if (goog.isNull(this.view_) || goog.isNull(this.fromLonLat_)) { - return; - } - this.viewUpdateInProgress_ = true; +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'getRevision', + ol.interaction.PinchZoom.prototype.getRevision); - // target & distance - var ellipsoid = Cesium.Ellipsoid.WGS84; - var scene = this.scene_; - var target = olcs.core.pickCenterPoint(scene); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'on', + ol.interaction.PinchZoom.prototype.on); - var bestTarget = target; - if (!bestTarget) { - //TODO: how to handle this properly ? - var globe = scene.globe; - var carto = this.cam_.positionCartographic.clone(); - var height = globe.getHeight(carto); - carto.height = goog.isDef(height) ? height : 0; - bestTarget = Cesium.Ellipsoid.WGS84.cartographicToCartesian(carto); - } - this.distance_ = Cesium.Cartesian3.distance(bestTarget, this.cam_.position); - var bestTargetCartographic = ellipsoid.cartesianToCartographic(bestTarget); - this.view_.setCenter(this.fromLonLat_([ - goog.math.toDegrees(bestTargetCartographic.longitude), - goog.math.toDegrees(bestTargetCartographic.latitude)])); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'once', + ol.interaction.PinchZoom.prototype.once); - // resolution - this.view_.setResolution( - this.calcResolutionForDistance_(this.distance_, - bestTargetCartographic ? bestTargetCartographic.latitude : 0)); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'un', + ol.interaction.PinchZoom.prototype.un); +goog.exportProperty( + ol.interaction.PinchZoom.prototype, + 'unByKey', + ol.interaction.PinchZoom.prototype.unByKey); - /* - * Since we are positioning the target, the values of heading and tilt - * need to be calculated _at the target_. - */ - if (target) { - var pos = this.cam_.position; +goog.exportProperty( + ol.interaction.Select.prototype, + 'getActive', + ol.interaction.Select.prototype.getActive); - // normal to the ellipsoid at the target - var targetNormal = new Cesium.Cartesian3(); - ellipsoid.geocentricSurfaceNormal(target, targetNormal); +goog.exportProperty( + ol.interaction.Select.prototype, + 'setActive', + ol.interaction.Select.prototype.setActive); - // vector from the target to the camera - var targetToCamera = new Cesium.Cartesian3(); - Cesium.Cartesian3.subtract(pos, target, targetToCamera); - Cesium.Cartesian3.normalize(targetToCamera, targetToCamera); +goog.exportProperty( + ol.interaction.Select.prototype, + 'get', + ol.interaction.Select.prototype.get); +goog.exportProperty( + ol.interaction.Select.prototype, + 'getKeys', + ol.interaction.Select.prototype.getKeys); - // HEADING - var up = this.cam_.up; - var right = this.cam_.right; - var normal = new Cesium.Cartesian3(-target.y, target.x, 0); // what is it? - var heading = Cesium.Cartesian3.angleBetween(right, normal); - var cross = Cesium.Cartesian3.cross(target, up, new Cesium.Cartesian3()); - var orientation = cross.z; +goog.exportProperty( + ol.interaction.Select.prototype, + 'getProperties', + ol.interaction.Select.prototype.getProperties); - this.view_.setRotation((orientation < 0 ? heading : -heading)); +goog.exportProperty( + ol.interaction.Select.prototype, + 'set', + ol.interaction.Select.prototype.set); - // TILT - var tiltAngle = Math.acos( - Cesium.Cartesian3.dot(targetNormal, targetToCamera)); - this.tilt_ = isNaN(tiltAngle) ? 0 : tiltAngle; - } else { - // fallback when there is no target - this.view_.setRotation(this.cam_.heading); - this.tilt_ = -this.cam_.pitch + Math.PI / 2; - } +goog.exportProperty( + ol.interaction.Select.prototype, + 'setProperties', + ol.interaction.Select.prototype.setProperties); - this.viewUpdateInProgress_ = false; -}; +goog.exportProperty( + ol.interaction.Select.prototype, + 'unset', + ol.interaction.Select.prototype.unset); +goog.exportProperty( + ol.interaction.Select.prototype, + 'changed', + ol.interaction.Select.prototype.changed); -/** - * Check if the underlying camera state has changed and ensure synchronization. - * @param {boolean=} opt_dontSync Do not synchronize the view. - */ -olcs.Camera.prototype.checkCameraChange = function(opt_dontSync) { - var old = this.lastCameraViewMatrix_; - var current = this.cam_.viewMatrix; +goog.exportProperty( + ol.interaction.Select.prototype, + 'dispatchEvent', + ol.interaction.Select.prototype.dispatchEvent); - if (!old || !Cesium.Matrix4.equalsEpsilon(old, current, 1e-5)) { - this.lastCameraViewMatrix_ = current.clone(); - if (opt_dontSync !== true) { - this.updateView(); - } - } -}; +goog.exportProperty( + ol.interaction.Select.prototype, + 'getRevision', + ol.interaction.Select.prototype.getRevision); +goog.exportProperty( + ol.interaction.Select.prototype, + 'on', + ol.interaction.Select.prototype.on); -/** - * @param {number} resolution Number of map units per pixel. - * @param {number} latitude Latitude in radians. - * @return {number} The calculated distance. - * @private - */ -olcs.Camera.prototype.calcDistanceForResolution_ = function(resolution, - latitude) { - var canvas = this.scene_.canvas; - var fovy = this.cam_.frustum.fovy; // vertical field of view - var metersPerUnit = this.view_.getProjection().getMetersPerUnit(); +goog.exportProperty( + ol.interaction.Select.prototype, + 'once', + ol.interaction.Select.prototype.once); - // number of "map units" visible in 2D (vertically) - var visibleMapUnits = resolution * canvas.clientHeight; +goog.exportProperty( + ol.interaction.Select.prototype, + 'un', + ol.interaction.Select.prototype.un); - // The metersPerUnit does not take latitude into account, but it should - // be lower with increasing latitude -- we have to compensate. - // In 3D it is not possible to maintain the resolution at more than one point, - // so it only makes sense to use the latitude of the "target" point. - var relativeCircumference = Math.cos(Math.abs(latitude)); +goog.exportProperty( + ol.interaction.Select.prototype, + 'unByKey', + ol.interaction.Select.prototype.unByKey); - // how many meters should be visible in 3D - var visibleMeters = visibleMapUnits * metersPerUnit * relativeCircumference; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'getActive', + ol.interaction.Snap.prototype.getActive); - // distance required to view the calculated length in meters - // - // fovy/2 - // |\ - // x | \ - // |--\ - // visibleMeters/2 - var requiredDistance = (visibleMeters / 2) / Math.tan(fovy / 2); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'setActive', + ol.interaction.Snap.prototype.setActive); - // NOTE: This calculation is not absolutely precise, because metersPerUnit - // is a great simplification. It does not take ellipsoid/terrain into account. +goog.exportProperty( + ol.interaction.Snap.prototype, + 'get', + ol.interaction.Snap.prototype.get); - return requiredDistance; -}; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'getKeys', + ol.interaction.Snap.prototype.getKeys); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'getProperties', + ol.interaction.Snap.prototype.getProperties); -/** - * @param {number} distance - * @param {number} latitude - * @return {number} The calculated resolution. - * @private - */ -olcs.Camera.prototype.calcResolutionForDistance_ = function(distance, - latitude) { - // See the reverse calculation (calcDistanceForResolution_) for details - var canvas = this.scene_.canvas; - var fovy = this.cam_.frustum.fovy; - var metersPerUnit = this.view_.getProjection().getMetersPerUnit(); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'set', + ol.interaction.Snap.prototype.set); - var visibleMeters = 2 * distance * Math.tan(fovy / 2); - var relativeCircumference = Math.cos(Math.abs(latitude)); - var visibleMapUnits = visibleMeters / metersPerUnit / relativeCircumference; - var resolution = visibleMapUnits / canvas.clientHeight; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'setProperties', + ol.interaction.Snap.prototype.setProperties); - return resolution; -}; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'unset', + ol.interaction.Snap.prototype.unset); -goog.provide('olcs.core.VectorLayerCounterpart'); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'changed', + ol.interaction.Snap.prototype.changed); -goog.require('ol.Observable'); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'dispatchEvent', + ol.interaction.Snap.prototype.dispatchEvent); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'getRevision', + ol.interaction.Snap.prototype.getRevision); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'on', + ol.interaction.Snap.prototype.on); -/** - * Result of the conversion of an OpenLayers layer to Cesium. - * @constructor - * @param {!(ol.proj.Projection|string)} layerProjection - * @param {!Cesium.Scene} scene - */ -olcs.core.VectorLayerCounterpart = function(layerProjection, scene) { - var billboards = new Cesium.BillboardCollection({scene: scene}); - var primitives = new Cesium.PrimitiveCollection(); +goog.exportProperty( + ol.interaction.Snap.prototype, + 'once', + ol.interaction.Snap.prototype.once); - /** - * @type {!Array.<goog.events.Key>} - */ - this.olListenKeys = []; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'un', + ol.interaction.Snap.prototype.un); - this.rootCollection_ = new Cesium.PrimitiveCollection(); - /** - * @type {!olcsx.core.OlFeatureToCesiumContext} - */ - this.context = { - projection: layerProjection, - billboards: billboards, - featureToCesiumMap: {}, - primitives: primitives - }; +goog.exportProperty( + ol.interaction.Snap.prototype, + 'unByKey', + ol.interaction.Snap.prototype.unByKey); - this.rootCollection_.add(billboards); - this.rootCollection_.add(primitives); -}; +goog.exportProperty( + ol.interaction.Translate.prototype, + 'getActive', + ol.interaction.Translate.prototype.getActive); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'setActive', + ol.interaction.Translate.prototype.setActive); -/** - * Unlisten. - */ -olcs.core.VectorLayerCounterpart.prototype.destroy = function() { - this.olListenKeys.forEach(ol.Observable.unByKey); - this.olListenKeys.length = 0; -}; +goog.exportProperty( + ol.interaction.Translate.prototype, + 'get', + ol.interaction.Translate.prototype.get); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'getKeys', + ol.interaction.Translate.prototype.getKeys); -/** - * @return {!Cesium.Primitive} - */ -olcs.core.VectorLayerCounterpart.prototype.getRootPrimitive = function() { - return this.rootCollection_; -}; +goog.exportProperty( + ol.interaction.Translate.prototype, + 'getProperties', + ol.interaction.Translate.prototype.getProperties); -// FIXME: box style -goog.provide('olcs.DragBox'); -goog.provide('olcs.DragBoxEventType'); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'set', + ol.interaction.Translate.prototype.set); -goog.require('goog.asserts'); -goog.require('goog.events.EventTarget'); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'setProperties', + ol.interaction.Translate.prototype.setProperties); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'unset', + ol.interaction.Translate.prototype.unset); -/** - * @enum {string} - */ -olcs.DragBoxEventType = { - /** - * Triggered upon drag box start. - */ - BOXSTART: 'boxstart', - /** - * Triggered upon drag box end. - */ - BOXEND: 'boxend' -}; +goog.exportProperty( + ol.interaction.Translate.prototype, + 'changed', + ol.interaction.Translate.prototype.changed); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'dispatchEvent', + ol.interaction.Translate.prototype.dispatchEvent); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'getRevision', + ol.interaction.Translate.prototype.getRevision); -/** - * @constructor - * @extends {goog.events.EventTarget} - * @param {Object=} opt_options Options. - * @api - */ -olcs.DragBox = function(opt_options) { +goog.exportProperty( + ol.interaction.Translate.prototype, + 'on', + ol.interaction.Translate.prototype.on); - var options = goog.isDef(opt_options) ? opt_options : {}; +goog.exportProperty( + ol.interaction.Translate.prototype, + 'once', + ol.interaction.Translate.prototype.once); - goog.base(this); +goog.exportProperty( + ol.interaction.Translate.prototype, + 'un', + ol.interaction.Translate.prototype.un); - /** - * @private - * @type {Cesium.Scene} - */ - this.scene_ = null; +goog.exportProperty( + ol.interaction.Translate.prototype, + 'unByKey', + ol.interaction.Translate.prototype.unByKey); - /** - * @private - * @type {Cesium.ScreenSpaceEventHandler} - */ - this.handler_ = null; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'get', + ol.geom.Geometry.prototype.get); - /** - * @private - * @type {Cesium.RectanglePrimitive} - */ - this.box_ = new Cesium.RectanglePrimitive({ - asynchronous: false, - rectangle: new Cesium.Rectangle(), - material: Cesium.Material.fromType(Cesium.Material.ColorType) - }); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'getKeys', + ol.geom.Geometry.prototype.getKeys); - // FIXME: configurable - this.box_.material.uniforms.color = new Cesium.Color(0.0, 0.0, 1.0, 0.5); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'getProperties', + ol.geom.Geometry.prototype.getProperties); - /** - * @private - * @type {Cesium.KeyboardEventModifier|undefined} - */ - this.modifier_ = goog.isDef(options.modifier) ? - options.modifier : Cesium.KeyboardEventModifier.SHIFT; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'set', + ol.geom.Geometry.prototype.set); - /** - * @private - * @type {Cesium.Cartographic} - */ - this.startPosition_ = null; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'setProperties', + ol.geom.Geometry.prototype.setProperties); -}; -goog.inherits(olcs.DragBox, goog.events.EventTarget); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'unset', + ol.geom.Geometry.prototype.unset); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'changed', + ol.geom.Geometry.prototype.changed); -/** - * @param {Object} event Mouse down event. - */ -olcs.DragBox.prototype.handleMouseDown = function(event) { - var ellipsoid = this.scene_.globe.ellipsoid; - var ray = this.scene_.camera.getPickRay(event.position); - var intersection = this.scene_.globe.pick(ray, this.scene_); - if (goog.isDef(intersection)) { - this.handler_.setInputAction(this.handleMouseMove.bind(this), - Cesium.ScreenSpaceEventType.MOUSE_MOVE); - this.handler_.setInputAction(this.handleMouseUp.bind(this), - Cesium.ScreenSpaceEventType.LEFT_UP); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'dispatchEvent', + ol.geom.Geometry.prototype.dispatchEvent); - if (goog.isDef(this.modifier_)) { - // listen to the event with and without the modifier to be able to start - // a box with the key pressed and finish it without. - this.handler_.setInputAction(this.handleMouseMove.bind(this), - Cesium.ScreenSpaceEventType.MOUSE_MOVE, this.modifier_); - this.handler_.setInputAction(this.handleMouseUp.bind(this), - Cesium.ScreenSpaceEventType.LEFT_UP, this.modifier_); - } - var cartographic = ellipsoid.cartesianToCartographic(intersection); - var rectangle = this.box_.rectangle; - rectangle.north = rectangle.south = cartographic.latitude; - rectangle.east = rectangle.west = cartographic.longitude; - this.box_.height = cartographic.height; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'getRevision', + ol.geom.Geometry.prototype.getRevision); - this.box_.show = true; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'on', + ol.geom.Geometry.prototype.on); - this.dispatchEvent({ - type: olcs.DragBoxEventType.BOXSTART, - position: cartographic - }); +goog.exportProperty( + ol.geom.Geometry.prototype, + 'once', + ol.geom.Geometry.prototype.once); - goog.asserts.assert(!goog.isNull(this.box_)); - if (!this.scene_.primitives.contains(this.box_)) { - this.scene_.primitives.add(this.box_); - } - this.scene_.screenSpaceCameraController.enableInputs = false; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'un', + ol.geom.Geometry.prototype.un); - this.startPosition_ = cartographic; - } -}; +goog.exportProperty( + ol.geom.Geometry.prototype, + 'unByKey', + ol.geom.Geometry.prototype.unByKey); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getClosestPoint', + ol.geom.SimpleGeometry.prototype.getClosestPoint); -/** - * @param {Object} event Mouse move event. - */ -olcs.DragBox.prototype.handleMouseMove = function(event) { - var ellipsoid = this.scene_.globe.ellipsoid; - var ray = this.scene_.camera.getPickRay(event.endPosition); - var intersection = this.scene_.globe.pick(ray, this.scene_); - if (goog.isDef(intersection)) { - var cartographic = ellipsoid.cartesianToCartographic(intersection); - this.box_.height = Math.max(this.box_.height, cartographic.height); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getExtent', + ol.geom.SimpleGeometry.prototype.getExtent); - if (cartographic.latitude < this.startPosition_.latitude) { - this.box_.rectangle.south = cartographic.latitude; - } else { - this.box_.rectangle.north = cartographic.latitude; - } - if (cartographic.longitude < this.startPosition_.longitude) { - this.box_.rectangle.west = cartographic.longitude; - } else { - this.box_.rectangle.east = cartographic.longitude; - } - } -}; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'simplify', + ol.geom.SimpleGeometry.prototype.simplify); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'transform', + ol.geom.SimpleGeometry.prototype.transform); -/** - * @param {Object} event Mouse up event. - */ -olcs.DragBox.prototype.handleMouseUp = function(event) { - var ellipsoid = this.scene_.globe.ellipsoid; - var ray = this.scene_.camera.getPickRay(event.position); - var intersection = this.scene_.globe.pick(ray, this.scene_); - if (goog.isDef(intersection)) { - var cartographic = ellipsoid.cartesianToCartographic(intersection); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'get', + ol.geom.SimpleGeometry.prototype.get); - this.box_.show = false; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getKeys', + ol.geom.SimpleGeometry.prototype.getKeys); - this.dispatchEvent({ - type: olcs.DragBoxEventType.BOXEND, - position: cartographic - }); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getProperties', + ol.geom.SimpleGeometry.prototype.getProperties); - this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP); - this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE); - if (goog.isDef(this.modifier_)) { - this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP, - this.modifier_); - this.handler_.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE, - this.modifier_); - } - } - this.scene_.screenSpaceCameraController.enableInputs = true; -}; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'set', + ol.geom.SimpleGeometry.prototype.set); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'setProperties', + ol.geom.SimpleGeometry.prototype.setProperties); -/** - * @param {Cesium.Scene} scene Scene. - * @api - */ -olcs.DragBox.prototype.setScene = function(scene) { - if (goog.isNull(scene)) { - goog.asserts.assert(!goog.isNull(this.box_)); - if (this.scene_.primitives.contains(this.box_)) { - this.scene_.primitives.remove(this.box_); - } - if (!goog.isNull(this.handler_)) { - this.handler_.destroy(); - this.handler_ = null; - } - } else { - goog.asserts.assert(scene.canvas); - this.handler_ = new Cesium.ScreenSpaceEventHandler(scene.canvas); - this.handler_.setInputAction(this.handleMouseDown.bind(this), - Cesium.ScreenSpaceEventType.LEFT_DOWN, this.modifier_); - } - this.scene_ = scene; -}; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'unset', + ol.geom.SimpleGeometry.prototype.unset); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'changed', + ol.geom.SimpleGeometry.prototype.changed); -/** - * Adds an event listener. A listener can only be added once to an - * object and if it is added again the key for the listener is - * returned. Note that if the existing listener is a one-off listener - * (registered via listenOnce), it will no longer be a one-off - * listener after a call to listen(). - * - * @param {string|!goog.events.EventId.<EVENTOBJ>} type The event type id. - * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback - * method. - * @param {boolean=} opt_useCapture Whether to fire in capture phase - * (defaults to false). - * @param {SCOPE=} opt_listenerScope Object in whose scope to call the - * listener. - * @return {goog.events.ListenableKey} Unique key for the listener. - * @template SCOPE,EVENTOBJ - * @api - */ -olcs.DragBox.prototype.listen; +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'dispatchEvent', + ol.geom.SimpleGeometry.prototype.dispatchEvent); + +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'getRevision', + ol.geom.SimpleGeometry.prototype.getRevision); + +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'on', + ol.geom.SimpleGeometry.prototype.on); + +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'once', + ol.geom.SimpleGeometry.prototype.once); + +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'un', + ol.geom.SimpleGeometry.prototype.un); -goog.provide('olcs.FeatureConverter'); +goog.exportProperty( + ol.geom.SimpleGeometry.prototype, + 'unByKey', + ol.geom.SimpleGeometry.prototype.unByKey); -goog.require('goog.asserts'); -goog.require('ol.extent'); -goog.require('ol.geom.SimpleGeometry'); -goog.require('olcs.core.VectorLayerCounterpart'); +goog.exportProperty( + ol.geom.Circle.prototype, + 'getFirstCoordinate', + ol.geom.Circle.prototype.getFirstCoordinate); +goog.exportProperty( + ol.geom.Circle.prototype, + 'getLastCoordinate', + ol.geom.Circle.prototype.getLastCoordinate); +goog.exportProperty( + ol.geom.Circle.prototype, + 'getLayout', + ol.geom.Circle.prototype.getLayout); -/** - * Concrete base class for converting from OpenLayers3 vectors to Cesium - * primitives. - * Extending this class is possible provided that the extending class and - * the library are compiled together by the closure compiler. - * @param {!Cesium.Scene} scene Cesium scene. - * @constructor - * @api - */ -olcs.FeatureConverter = function(scene) { +goog.exportProperty( + ol.geom.Circle.prototype, + 'getClosestPoint', + ol.geom.Circle.prototype.getClosestPoint); - /** - * @protected - */ - this.scene = scene; +goog.exportProperty( + ol.geom.Circle.prototype, + 'getExtent', + ol.geom.Circle.prototype.getExtent); - /** - * Bind once to have a unique function for using as a listener - * @type {function(ol.source.VectorEvent)} - * @private - */ - this.boundOnRemoveOrClearFeatureListener_ = - this.onRemoveOrClearFeature_.bind(this); -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'simplify', + ol.geom.Circle.prototype.simplify); +goog.exportProperty( + ol.geom.Circle.prototype, + 'get', + ol.geom.Circle.prototype.get); -/** - * @param {ol.source.VectorEvent} evt - * @private - */ -olcs.FeatureConverter.prototype.onRemoveOrClearFeature_ = function(evt) { - var source = evt.target; - goog.asserts.assertInstanceof(source, ol.source.Vector); +goog.exportProperty( + ol.geom.Circle.prototype, + 'getKeys', + ol.geom.Circle.prototype.getKeys); - var cancellers = source['olcs_cancellers']; - if (cancellers) { - var feature = evt.feature; - if (goog.isDef(feature)) { - // remove - var id = goog.getUid(feature); - var canceller = cancellers[id]; - if (canceller) { - canceller(); - delete cancellers[id]; - } - } else { - // clear - for (var key in cancellers) { - if (cancellers.hasOwnProperty(key)) { - cancellers[key](); - } - } - source['olcs_cancellers'] = {}; - } - } -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'getProperties', + ol.geom.Circle.prototype.getProperties); +goog.exportProperty( + ol.geom.Circle.prototype, + 'set', + ol.geom.Circle.prototype.set); -/** - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature. - * @param {!Cesium.Primitive|Cesium.Label|Cesium.Billboard} primitive - * @protected - */ -olcs.FeatureConverter.prototype.setReferenceForPicking = - function(layer, feature, primitive) { - primitive.olLayer = layer; - primitive.olFeature = feature; -}; +goog.exportProperty( + ol.geom.Circle.prototype, + 'setProperties', + ol.geom.Circle.prototype.setProperties); +goog.exportProperty( + ol.geom.Circle.prototype, + 'unset', + ol.geom.Circle.prototype.unset); -/** - * Basics primitive creation using a color attribute. - * Note that Cesium has 'interior' and outline geometries. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature. - * @param {!ol.geom.Geometry} olGeometry Ol3 geometry. - * @param {!Cesium.Geometry} geometry - * @param {!Cesium.Color} color - * @param {number=} opt_lineWidth - * @return {!Cesium.Primitive} - * @protected - */ -olcs.FeatureConverter.prototype.createColoredPrimitive = - function(layer, feature, olGeometry, geometry, color, opt_lineWidth) { - var createInstance = function(geometry, color) { - return new Cesium.GeometryInstance({ - // always update Cesium externs before adding a property - geometry: geometry, - attributes: { - color: Cesium.ColorGeometryInstanceAttribute.fromColor(color) - } - }); - }; +goog.exportProperty( + ol.geom.Circle.prototype, + 'changed', + ol.geom.Circle.prototype.changed); - var options = { - // always update Cesium externs before adding a property - flat: true, // work with all geometries - renderState: { - depthTest: { - enabled: true - } - } - }; +goog.exportProperty( + ol.geom.Circle.prototype, + 'dispatchEvent', + ol.geom.Circle.prototype.dispatchEvent); - if (goog.isDef(opt_lineWidth)) { - if (!options.renderState) { - options.renderState = {}; - } - options.renderState.lineWidth = opt_lineWidth; - } +goog.exportProperty( + ol.geom.Circle.prototype, + 'getRevision', + ol.geom.Circle.prototype.getRevision); - var instances = createInstance(geometry, color); +goog.exportProperty( + ol.geom.Circle.prototype, + 'on', + ol.geom.Circle.prototype.on); - var heightReference = this.getHeightReference(layer, feature, olGeometry); +goog.exportProperty( + ol.geom.Circle.prototype, + 'once', + ol.geom.Circle.prototype.once); - var primitive; +goog.exportProperty( + ol.geom.Circle.prototype, + 'un', + ol.geom.Circle.prototype.un); - if (heightReference == Cesium.HeightReference.CLAMP_TO_GROUND) { - primitive = new Cesium.GroundPrimitive({ - // always update Cesium externs before adding a property - geometryInstance: instances - }); - } else { - var appearance = new Cesium.PerInstanceColorAppearance(options); - primitive = new Cesium.Primitive({ - // always update Cesium externs before adding a property - geometryInstances: instances, - appearance: appearance - }); - } +goog.exportProperty( + ol.geom.Circle.prototype, + 'unByKey', + ol.geom.Circle.prototype.unByKey); - this.setReferenceForPicking(layer, feature, primitive); - return primitive; -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getClosestPoint', + ol.geom.GeometryCollection.prototype.getClosestPoint); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getExtent', + ol.geom.GeometryCollection.prototype.getExtent); -/** - * Return the fill or stroke color from a plain ol style. - * @param {!ol.style.Style|ol.style.Text} style - * @param {boolean} outline - * @return {!Cesium.Color} - * @protected - */ -olcs.FeatureConverter.prototype.extractColorFromOlStyle = - function(style, outline) { - var fillColor = style.getFill() ? style.getFill().getColor() : null; - var strokeColor = style.getStroke() ? style.getStroke().getColor() : null; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'simplify', + ol.geom.GeometryCollection.prototype.simplify); - var olColor = 'black'; - if (strokeColor && outline) { - olColor = strokeColor; - } else if (fillColor) { - olColor = fillColor; - } +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'transform', + ol.geom.GeometryCollection.prototype.transform); - return olcs.core.convertColorToCesium(olColor); -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'get', + ol.geom.GeometryCollection.prototype.get); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getKeys', + ol.geom.GeometryCollection.prototype.getKeys); -/** - * Return the width of stroke from a plain ol style. - * Use GL aliased line width range constraint. - * @param {!ol.style.Style|ol.style.Text} style - * @return {number} - * @protected - */ -olcs.FeatureConverter.prototype.extractLineWidthFromOlStyle = - function(style) { - var width = style.getStroke() ? style.getStroke().getWidth() : 1; - return Math.min(width, this.scene.maximumAliasedLineWidth); -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getProperties', + ol.geom.GeometryCollection.prototype.getProperties); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'set', + ol.geom.GeometryCollection.prototype.set); -/** - * Create a primitive collection out of two Cesium geometries. - * Only the OpenLayers style colors will be used. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature. - * @param {!ol.geom.Geometry} olGeometry Ol3 geometry. - * @param {!Cesium.Geometry} fillGeometry - * @param {!Cesium.Geometry} outlineGeometry - * @param {!ol.style.Style} olStyle - * @return {!Cesium.PrimitiveCollection} - * @protected - */ -olcs.FeatureConverter.prototype.wrapFillAndOutlineGeometries = - function(layer, feature, olGeometry, fillGeometry, outlineGeometry, - olStyle) { - var fillColor = this.extractColorFromOlStyle(olStyle, false); - var outlineColor = this.extractColorFromOlStyle(olStyle, true); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'setProperties', + ol.geom.GeometryCollection.prototype.setProperties); - var primitives = new Cesium.PrimitiveCollection(); - if (olStyle.getFill()) { - var p = this.createColoredPrimitive(layer, feature, olGeometry, - fillGeometry, fillColor); - primitives.add(p); - } +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'unset', + ol.geom.GeometryCollection.prototype.unset); - if (olStyle.getStroke()) { - var width = this.extractLineWidthFromOlStyle(olStyle); - var p = this.createColoredPrimitive(layer, feature, olGeometry, - outlineGeometry, outlineColor, width); - primitives.add(p); - } +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'changed', + ol.geom.GeometryCollection.prototype.changed); - return primitives; -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'dispatchEvent', + ol.geom.GeometryCollection.prototype.dispatchEvent); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'getRevision', + ol.geom.GeometryCollection.prototype.getRevision); -// Geometry converters -/** - * Create a Cesium primitive if style has a text component. - * Eventually return a PrimitiveCollection including current primitive. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Geometry} geometry - * @param {!ol.style.Style} style - * @param {!Cesium.Primitive} primitive current primitive - * @return {!Cesium.PrimitiveCollection} - * @protected - */ -olcs.FeatureConverter.prototype.addTextStyle = - function(layer, feature, geometry, style, primitive) { - var primitives; - if (!(primitive instanceof Cesium.PrimitiveCollection)) { - primitives = new Cesium.PrimitiveCollection(); - primitives.add(primitive); - } else { - primitives = primitive; - } +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'on', + ol.geom.GeometryCollection.prototype.on); - if (!style.getText()) { - return primitives; - } +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'once', + ol.geom.GeometryCollection.prototype.once); - var text = /** @type {!ol.style.Text} */ (style.getText()); - var label = this.olGeometry4326TextPartToCesium(layer, feature, geometry, - text); - if (label) { - primitives.add(label); - } - return primitives; -}; +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'un', + ol.geom.GeometryCollection.prototype.un); +goog.exportProperty( + ol.geom.GeometryCollection.prototype, + 'unByKey', + ol.geom.GeometryCollection.prototype.unByKey); -/** - * Add a billboard to a Cesium.BillboardCollection. - * Overriding this wrapper allows manipulating the billboard options. - * @param {!Cesium.BillboardCollection} billboards - * @param {!Cesium.optionsBillboardCollectionAdd} bbOptions - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature. - * @param {!ol.geom.Geometry} geometry - * @param {!ol.style.Style} style - * @return {!Cesium.Billboard} newly created billboard - * @api - */ -olcs.FeatureConverter.prototype.csAddBillboard = - function(billboards, bbOptions, layer, feature, geometry, style) { - var bb = billboards.add(bbOptions); - this.setReferenceForPicking(layer, feature, bb); - return bb; -}; +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getFirstCoordinate', + ol.geom.LinearRing.prototype.getFirstCoordinate); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getLastCoordinate', + ol.geom.LinearRing.prototype.getLastCoordinate); -/** - * Convert an OpenLayers circle geometry to Cesium. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Circle} olGeometry Ol3 circle geometry. - * @param {!ol.proj.ProjectionLike} projection - * @param {!ol.style.Style} olStyle - * @return {!Cesium.PrimitiveCollection} primitives - * @api - */ -olcs.FeatureConverter.prototype.olCircleGeometryToCesium = - function(layer, feature, olGeometry, projection, olStyle) { +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getLayout', + ol.geom.LinearRing.prototype.getLayout); - olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); - goog.asserts.assert(olGeometry.getType() == 'Circle'); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getClosestPoint', + ol.geom.LinearRing.prototype.getClosestPoint); - // ol.Coordinate - var center = olGeometry.getCenter(); - var height = center.length == 3 ? center[2] : 0.0; - var point = center.slice(); - point[0] += olGeometry.getRadius(); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getExtent', + ol.geom.LinearRing.prototype.getExtent); - // Cesium - center = olcs.core.ol4326CoordinateToCesiumCartesian(center); - point = olcs.core.ol4326CoordinateToCesiumCartesian(point); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'simplify', + ol.geom.LinearRing.prototype.simplify); - // Accurate computation of straight distance - var radius = Cesium.Cartesian3.distance(center, point); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'transform', + ol.geom.LinearRing.prototype.transform); - var fillGeometry = new Cesium.CircleGeometry({ - // always update Cesium externs before adding a property - center: center, - radius: radius, - height: height - }); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'get', + ol.geom.LinearRing.prototype.get); - var outlineGeometry = new Cesium.CircleOutlineGeometry({ - // always update Cesium externs before adding a property - center: center, - radius: radius, - extrudedHeight: height, - height: height - }); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getKeys', + ol.geom.LinearRing.prototype.getKeys); - var primitives = this.wrapFillAndOutlineGeometries( - layer, feature, olGeometry, fillGeometry, outlineGeometry, olStyle); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getProperties', + ol.geom.LinearRing.prototype.getProperties); - return this.addTextStyle(layer, feature, olGeometry, olStyle, primitives); -}; +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'set', + ol.geom.LinearRing.prototype.set); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'setProperties', + ol.geom.LinearRing.prototype.setProperties); -/** - * Convert an OpenLayers line string geometry to Cesium. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.LineString} olGeometry Ol3 line string geometry. - * @param {!ol.proj.ProjectionLike} projection - * @param {!ol.style.Style} olStyle - * @return {!Cesium.PrimitiveCollection} primitives - * @api - */ -olcs.FeatureConverter.prototype.olLineStringGeometryToCesium = - function(layer, feature, olGeometry, projection, olStyle) { +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'unset', + ol.geom.LinearRing.prototype.unset); - olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); - goog.asserts.assert(olGeometry.getType() == 'LineString'); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'changed', + ol.geom.LinearRing.prototype.changed); - var positions = olcs.core.ol4326CoordinateArrayToCsCartesians( - olGeometry.getCoordinates()); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'dispatchEvent', + ol.geom.LinearRing.prototype.dispatchEvent); - var appearance = new Cesium.PolylineMaterialAppearance({ - // always update Cesium externs before adding a property - material: this.olStyleToCesium(feature, olStyle, true) - }); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'getRevision', + ol.geom.LinearRing.prototype.getRevision); - // Handle both color and width - var outlineGeometry = new Cesium.PolylineGeometry({ - // always update Cesium externs before adding a property - positions: positions, - width: this.extractLineWidthFromOlStyle(olStyle), - vertexFormat: appearance.vertexFormat - }); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'on', + ol.geom.LinearRing.prototype.on); - var outlinePrimitive = new Cesium.Primitive({ - // always update Cesium externs before adding a property - geometryInstances: new Cesium.GeometryInstance({ - geometry: outlineGeometry - }), - appearance: appearance - }); - this.setReferenceForPicking(layer, feature, outlinePrimitive); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'once', + ol.geom.LinearRing.prototype.once); - return this.addTextStyle(layer, feature, olGeometry, olStyle, - outlinePrimitive); -}; +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'un', + ol.geom.LinearRing.prototype.un); +goog.exportProperty( + ol.geom.LinearRing.prototype, + 'unByKey', + ol.geom.LinearRing.prototype.unByKey); -/** - * Convert an OpenLayers polygon geometry to Cesium. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Polygon} olGeometry Ol3 polygon geometry. - * @param {!ol.proj.ProjectionLike} projection - * @param {!ol.style.Style} olStyle - * @return {!Cesium.PrimitiveCollection} primitives - * @api - */ -olcs.FeatureConverter.prototype.olPolygonGeometryToCesium = - function(layer, feature, olGeometry, projection, olStyle) { +goog.exportProperty( + ol.geom.LineString.prototype, + 'getFirstCoordinate', + ol.geom.LineString.prototype.getFirstCoordinate); - olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); - goog.asserts.assert(olGeometry.getType() == 'Polygon'); +goog.exportProperty( + ol.geom.LineString.prototype, + 'getLastCoordinate', + ol.geom.LineString.prototype.getLastCoordinate); - var rings = olGeometry.getLinearRings(); - // always update Cesium externs before adding a property - var hierarchy = {}; - var polygonHierarchy = hierarchy; - goog.asserts.assert(rings.length > 0); +goog.exportProperty( + ol.geom.LineString.prototype, + 'getLayout', + ol.geom.LineString.prototype.getLayout); - for (var i = 0; i < rings.length; ++i) { - var olPos = rings[i].getCoordinates(); - var positions = olcs.core.ol4326CoordinateArrayToCsCartesians(olPos); - goog.asserts.assert(positions && positions.length > 0); - if (i == 0) { - hierarchy.positions = positions; - } else { - hierarchy.holes = { - // always update Cesium externs before adding a property - positions: positions - }; - hierarchy = hierarchy.holes; - } - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'getClosestPoint', + ol.geom.LineString.prototype.getClosestPoint); - var fillGeometry = new Cesium.PolygonGeometry({ - // always update Cesium externs before adding a property - polygonHierarchy: polygonHierarchy, - perPositionHeight: true - }); +goog.exportProperty( + ol.geom.LineString.prototype, + 'getExtent', + ol.geom.LineString.prototype.getExtent); - var outlineGeometry = new Cesium.PolygonOutlineGeometry({ - // always update Cesium externs before adding a property - polygonHierarchy: hierarchy, - perPositionHeight: true - }); +goog.exportProperty( + ol.geom.LineString.prototype, + 'simplify', + ol.geom.LineString.prototype.simplify); - var primitives = this.wrapFillAndOutlineGeometries( - layer, feature, olGeometry, fillGeometry, outlineGeometry, olStyle); +goog.exportProperty( + ol.geom.LineString.prototype, + 'transform', + ol.geom.LineString.prototype.transform); - return this.addTextStyle(layer, feature, olGeometry, olStyle, primitives); -}; +goog.exportProperty( + ol.geom.LineString.prototype, + 'get', + ol.geom.LineString.prototype.get); +goog.exportProperty( + ol.geom.LineString.prototype, + 'getKeys', + ol.geom.LineString.prototype.getKeys); -/** - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Geometry} geometry - * @return {!Cesium.HeightReference} - * @api - */ -olcs.FeatureConverter.prototype.getHeightReference = - function(layer, feature, geometry) { +goog.exportProperty( + ol.geom.LineString.prototype, + 'getProperties', + ol.geom.LineString.prototype.getProperties); - // Read from the geometry - var altitudeMode = geometry.get('altitudeMode'); +goog.exportProperty( + ol.geom.LineString.prototype, + 'set', + ol.geom.LineString.prototype.set); - // Or from the feature - if (!goog.isDef(altitudeMode)) { - altitudeMode = feature.get('altitudeMode'); - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'setProperties', + ol.geom.LineString.prototype.setProperties); - // Or from the layer - if (!goog.isDef(altitudeMode)) { - altitudeMode = layer.get('altitudeMode'); - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'unset', + ol.geom.LineString.prototype.unset); - var heightReference = Cesium.HeightReference.NONE; - if (altitudeMode === 'clampToGround') { - heightReference = Cesium.HeightReference.CLAMP_TO_GROUND; - } else if (altitudeMode === 'relativeToGround') { - heightReference = Cesium.HeightReference.RELATIVE_TO_GROUND; - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'changed', + ol.geom.LineString.prototype.changed); - return heightReference; -}; +goog.exportProperty( + ol.geom.LineString.prototype, + 'dispatchEvent', + ol.geom.LineString.prototype.dispatchEvent); +goog.exportProperty( + ol.geom.LineString.prototype, + 'getRevision', + ol.geom.LineString.prototype.getRevision); -/** - * Convert a point geometry to a Cesium BillboardCollection. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Point} olGeometry Ol3 point geometry. - * @param {!ol.proj.ProjectionLike} projection - * @param {!ol.style.Style} style - * @param {!Cesium.BillboardCollection} billboards - * @param {function(!Cesium.Billboard)=} opt_newBillboardCallback Called when - * the new billboard is added. - * @return {Cesium.Primitive} primitives - * @api - */ -olcs.FeatureConverter.prototype.olPointGeometryToCesium = - function(layer, feature, olGeometry, projection, style, billboards, - opt_newBillboardCallback) { - goog.asserts.assert(olGeometry.getType() == 'Point'); - olGeometry = olcs.core.olGeometryCloneTo4326(olGeometry, projection); +goog.exportProperty( + ol.geom.LineString.prototype, + 'on', + ol.geom.LineString.prototype.on); - var imageStyle = style.getImage(); - if (imageStyle) { - if (imageStyle instanceof ol.style.Icon) { - // make sure the image is scheduled for load - imageStyle.load(); - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'once', + ol.geom.LineString.prototype.once); - var image = imageStyle.getImage(1); // get normal density - var isImageLoaded = function(image) { - return image.src != '' && - image.naturalHeight != 0 && - image.naturalWidth != 0 && - image.complete; - }; - var reallyCreateBillboard = (function() { - if (goog.isNull(image)) { - return; - } - if (!(image instanceof HTMLCanvasElement || - image instanceof Image || - image instanceof HTMLImageElement)) { - return; - } - var center = olGeometry.getCoordinates(); - var position = olcs.core.ol4326CoordinateToCesiumCartesian(center); - var color; - var opacity = imageStyle.getOpacity(); - if (goog.isDef(opacity)) { - color = new Cesium.Color(1.0, 1.0, 1.0, opacity); - } +goog.exportProperty( + ol.geom.LineString.prototype, + 'un', + ol.geom.LineString.prototype.un); - var heightReference = this.getHeightReference(layer, feature, olGeometry); +goog.exportProperty( + ol.geom.LineString.prototype, + 'unByKey', + ol.geom.LineString.prototype.unByKey); - var bbOptions = /** @type {Cesium.optionsBillboardCollectionAdd} */ ({ - // always update Cesium externs before adding a property - image: image, - color: color, - heightReference: heightReference, - verticalOrigin: Cesium.VerticalOrigin.BOTTOM, - position: position - }); - var bb = this.csAddBillboard(billboards, bbOptions, layer, feature, - olGeometry, style); - if (opt_newBillboardCallback) { - opt_newBillboardCallback(bb); - } - }).bind(this); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getFirstCoordinate', + ol.geom.MultiLineString.prototype.getFirstCoordinate); - if (image instanceof Image && !isImageLoaded(image)) { - // Cesium requires the image to be loaded - var cancelled = false; - var source = layer.getSource(); - if (source instanceof ol.source.ImageVector) { - source = source.getSource(); - } - var canceller = function() { - cancelled = true; - }; - source.on(['removefeature', 'clear'], - this.boundOnRemoveOrClearFeatureListener_); - source['olcs_cancellers'] = source['olcs_cancellers'] || {}; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getLastCoordinate', + ol.geom.MultiLineString.prototype.getLastCoordinate); - goog.asserts.assert(!source['olcs_cancellers'][goog.getUid(feature)]); - source['olcs_cancellers'][goog.getUid(feature)] = canceller; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getLayout', + ol.geom.MultiLineString.prototype.getLayout); - var listener = function() { - if (!billboards.isDestroyed() && !cancelled) { - // Create billboard if the feature is still displayed on the map. - reallyCreateBillboard(); - } - }; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getClosestPoint', + ol.geom.MultiLineString.prototype.getClosestPoint); - goog.events.listenOnce(image, 'load', listener); - } else { - reallyCreateBillboard(); - } - } +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getExtent', + ol.geom.MultiLineString.prototype.getExtent); - if (style.getText()) { - return this.addTextStyle(layer, feature, olGeometry, style, - new Cesium.Primitive()); - } else { - return null; - } -}; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'simplify', + ol.geom.MultiLineString.prototype.simplify); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'transform', + ol.geom.MultiLineString.prototype.transform); -/** - * Convert an OpenLayers multi-something geometry to Cesium. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Geometry} geometry Ol3 geometry. - * @param {!ol.proj.ProjectionLike} projection - * @param {!ol.style.Style} olStyle - * @param {!Cesium.BillboardCollection} billboards - * @param {function(!Cesium.Billboard)=} opt_newBillboardCallback Called when - * the new billboard is added. - * @return {Cesium.Primitive} primitives - * @api - */ -olcs.FeatureConverter.prototype.olMultiGeometryToCesium = - function(layer, feature, geometry, projection, olStyle, billboards, - opt_newBillboardCallback) { - // Do not reproject to 4326 now because it will be done later. +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'get', + ol.geom.MultiLineString.prototype.get); - // FIXME: would be better to combine all child geometries in one primitive - // instead we create n primitives for simplicity. - var accumulate = function(geometries, functor) { - var primitives = new Cesium.PrimitiveCollection(); - geometries.forEach(function(geometry) { - primitives.add(functor(layer, feature, geometry, projection, olStyle)); - }); - return primitives; - }; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getKeys', + ol.geom.MultiLineString.prototype.getKeys); - var subgeos; - switch (geometry.getType()) { - case 'MultiPoint': - geometry = /** @type {!ol.geom.MultiPoint} */ (geometry); - subgeos = geometry.getPoints(); - if (olStyle.getText()) { - var primitives = new Cesium.PrimitiveCollection(); - subgeos.forEach(function(geometry) { - goog.asserts.assert(geometry); - var result = this.olPointGeometryToCesium(layer, feature, geometry, - projection, olStyle, billboards, opt_newBillboardCallback); - if (result) { - primitives.add(result); - } - }.bind(this)); - return primitives; - } else { - subgeos.forEach(function(geometry) { - goog.asserts.assert(!goog.isNull(geometry)); - this.olPointGeometryToCesium(layer, feature, geometry, projection, - olStyle, billboards, opt_newBillboardCallback); - }); - return null; - } - case 'MultiLineString': - geometry = /** @type {!ol.geom.MultiLineString} */ (geometry); - subgeos = geometry.getLineStrings(); - return accumulate(subgeos, this.olLineStringGeometryToCesium.bind(this)); - case 'MultiPolygon': - geometry = /** @type {!ol.geom.MultiPolygon} */ (geometry); - subgeos = geometry.getPolygons(); - return accumulate(subgeos, this.olPolygonGeometryToCesium.bind(this)); - default: - goog.asserts.fail('Unhandled multi geometry type' + geometry.getType()); - } -}; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getProperties', + ol.geom.MultiLineString.prototype.getProperties); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'set', + ol.geom.MultiLineString.prototype.set); -/** - * Convert an OpenLayers text style to Cesium. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature.. - * @param {!ol.geom.Geometry} geometry - * @param {!ol.style.Text} style - * @return {Cesium.LabelCollection} Cesium primitive - * @api - */ -olcs.FeatureConverter.prototype.olGeometry4326TextPartToCesium = - function(layer, feature, geometry, style) { - var text = style.getText(); - goog.asserts.assert(goog.isDef(text)); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'setProperties', + ol.geom.MultiLineString.prototype.setProperties); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'unset', + ol.geom.MultiLineString.prototype.unset); - var labels = new Cesium.LabelCollection({scene: this.scene}); - // TODO: export and use the text draw position from ol3 . - // See src/ol/render/vector.js - var extentCenter = ol.extent.getCenter(geometry.getExtent()); - if (geometry instanceof ol.geom.SimpleGeometry) { - var first = geometry.getFirstCoordinate(); - extentCenter[2] = first.length == 3 ? first[2] : 0.0; - } - var options = /** @type {Cesium.optionsLabelCollection} */ ({}); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'changed', + ol.geom.MultiLineString.prototype.changed); - options.position = olcs.core.ol4326CoordinateToCesiumCartesian(extentCenter); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'dispatchEvent', + ol.geom.MultiLineString.prototype.dispatchEvent); - options.text = text; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'getRevision', + ol.geom.MultiLineString.prototype.getRevision); - options.heightReference = this.getHeightReference(layer, feature, geometry); +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'on', + ol.geom.MultiLineString.prototype.on); - var offsetX = style.getOffsetX(); - var offsetY = style.getOffsetY(); - if (offsetX != 0 && offsetY != 0) { - var offset = new Cesium.Cartesian2(offsetX, offsetY); - options.pixelOffset = offset; - } +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'once', + ol.geom.MultiLineString.prototype.once); - var font = style.getFont(); - if (goog.isDefAndNotNull(font)) { - options.font = font; - } +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'un', + ol.geom.MultiLineString.prototype.un); - var labelStyle = undefined; - if (style.getFill()) { - options.fillColor = this.extractColorFromOlStyle(style, false); - labelStyle = Cesium.LabelStyle.FILL; - } - if (style.getStroke()) { - options.outlineWidth = this.extractLineWidthFromOlStyle(style); - options.outlineColor = this.extractColorFromOlStyle(style, true); - labelStyle = Cesium.LabelStyle.OUTLINE; - } - if (style.getFill() && style.getStroke()) { - labelStyle = Cesium.LabelStyle.FILL_AND_OUTLINE; - } - options.style = labelStyle; +goog.exportProperty( + ol.geom.MultiLineString.prototype, + 'unByKey', + ol.geom.MultiLineString.prototype.unByKey); - var horizontalOrigin; - switch (style.getTextAlign()) { - case 'left': - horizontalOrigin = Cesium.HorizontalOrigin.LEFT; - break; - case 'right': - horizontalOrigin = Cesium.HorizontalOrigin.RIGHT; - break; - case 'center': - default: - horizontalOrigin = Cesium.HorizontalOrigin.CENTER; - } - options.horizontalOrigin = horizontalOrigin; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getFirstCoordinate', + ol.geom.MultiPoint.prototype.getFirstCoordinate); - if (style.getTextBaseline()) { - var verticalOrigin; - switch (style.getTextBaseline()) { - case 'top': - verticalOrigin = Cesium.VerticalOrigin.TOP; - break; - case 'middle': - verticalOrigin = Cesium.VerticalOrigin.CENTER; - break; - case 'bottom': - verticalOrigin = Cesium.VerticalOrigin.BOTTOM; - break; - case 'alphabetic': - verticalOrigin = Cesium.VerticalOrigin.TOP; - break; - case 'hanging': - verticalOrigin = Cesium.VerticalOrigin.BOTTOM; - break; - default: - goog.asserts.fail('unhandled baseline ' + style.getTextBaseline()); - } - options.verticalOrigin = verticalOrigin; - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getLastCoordinate', + ol.geom.MultiPoint.prototype.getLastCoordinate); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getLayout', + ol.geom.MultiPoint.prototype.getLayout); - var l = labels.add(options); - this.setReferenceForPicking(layer, feature, l); - return labels; -}; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getClosestPoint', + ol.geom.MultiPoint.prototype.getClosestPoint); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getExtent', + ol.geom.MultiPoint.prototype.getExtent); -/** - * Convert an OpenLayers style to a Cesium Material. - * @param {ol.Feature} feature Ol3 feature.. - * @param {!ol.style.Style} style - * @param {boolean} outline - * @return {Cesium.Material} - * @api - */ -olcs.FeatureConverter.prototype.olStyleToCesium = - function(feature, style, outline) { - var fill = style.getFill(); - var stroke = style.getStroke(); - if ((outline && !stroke) || (!outline && !fill)) { - return null; // FIXME use a default style? Developer error? - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'simplify', + ol.geom.MultiPoint.prototype.simplify); - var color = outline ? stroke.getColor() : fill.getColor(); - color = olcs.core.convertColorToCesium(color); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'transform', + ol.geom.MultiPoint.prototype.transform); - if (outline && stroke.getLineDash()) { - return Cesium.Material.fromType('Stripe', { - // always update Cesium externs before adding a property - horizontal: false, - repeat: 500, // TODO how to calculate this? - evenColor: color, - oddColor: new Cesium.Color(0, 0, 0, 0) // transparent - }); - } else { - return Cesium.Material.fromType('Color', { - // always update Cesium externs before adding a property - color: color - }); - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'get', + ol.geom.MultiPoint.prototype.get); -}; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getKeys', + ol.geom.MultiPoint.prototype.getKeys); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getProperties', + ol.geom.MultiPoint.prototype.getProperties); -/** - * Compute OpenLayers plain style. - * Evaluates style function, blend arrays, get default style. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature - * @param {ol.style.StyleFunction|undefined} fallbackStyle - * @param {number} resolution - * @return {ol.style.Style} null if no style is available - * @api - */ -olcs.FeatureConverter.prototype.computePlainStyle = - function(layer, feature, fallbackStyle, resolution) { - var featureStyle = feature.getStyleFunction(); - var style; - if (goog.isDef(featureStyle)) { - style = featureStyle.call(feature, resolution); - } - if (!goog.isDefAndNotNull(style) && goog.isDefAndNotNull(fallbackStyle)) { - style = fallbackStyle(feature, resolution); - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'set', + ol.geom.MultiPoint.prototype.set); - if (!goog.isDef(style)) { - // The feature must not be displayed - return null; - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'setProperties', + ol.geom.MultiPoint.prototype.setProperties); - goog.asserts.assert(Array.isArray(style)); - // FIXME combine materials as in cesium-materials-pack? - // then this function must return a custom material - // More simply, could blend the colors like described in - // http://en.wikipedia.org/wiki/Alpha_compositing - return style[0]; -}; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'unset', + ol.geom.MultiPoint.prototype.unset); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'changed', + ol.geom.MultiPoint.prototype.changed); -/** - * Convert one OpenLayers feature up to a collection of Cesium primitives. - * @param {ol.layer.Vector|ol.layer.Image} layer - * @param {!ol.Feature} feature Ol3 feature. - * @param {!ol.style.Style} style - * @param {!olcsx.core.OlFeatureToCesiumContext} context - * @param {!ol.geom.Geometry=} opt_geom Geometry to be converted. - * @return {Cesium.Primitive} primitives - * @api - */ -olcs.FeatureConverter.prototype.olFeatureToCesium = - function(layer, feature, style, context, opt_geom) { - var geom = opt_geom || feature.getGeometry(); - var proj = context.projection; - if (!geom) { - // Ol3 features may not have a geometry - // See http://geojson.org/geojson-spec.html#feature-objects - return null; - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'dispatchEvent', + ol.geom.MultiPoint.prototype.dispatchEvent); - var newBillboardAddedCallback = function(bb) { - context.featureToCesiumMap[goog.getUid(feature)] = bb; - }; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'getRevision', + ol.geom.MultiPoint.prototype.getRevision); - switch (geom.getType()) { - case 'GeometryCollection': - var primitives = new Cesium.PrimitiveCollection(); - var collection = /** @type {!ol.geom.GeometryCollection} */ (geom); - // TODO: use getGeometriesArray() instead - collection.getGeometries().forEach(function(geom) { - if (geom) { - var prims = this.olFeatureToCesium(layer, feature, style, context, - geom); - if (prims) { - primitives.add(prims); - } - } - }.bind(this)); - return primitives; - case 'Point': - geom = /** @type {!ol.geom.Point} */ (geom); - var bbs = context.billboards; - var result = this.olPointGeometryToCesium(layer, feature, geom, proj, - style, bbs, newBillboardAddedCallback); - if (!result) { - // no wrapping primitive - return null; - } else { - return result; - } - case 'Circle': - geom = /** @type {!ol.geom.Circle} */ (geom); - return this.olCircleGeometryToCesium(layer, feature, geom, proj, - style); - case 'LineString': - geom = /** @type {!ol.geom.LineString} */ (geom); - return this.olLineStringGeometryToCesium(layer, feature, geom, proj, - style); - case 'Polygon': - geom = /** @type {!ol.geom.Polygon} */ (geom); - return this.olPolygonGeometryToCesium(layer, feature, geom, proj, - style); - case 'MultiPoint': - case 'MultiLineString': - case 'MultiPolygon': - var result = this.olMultiGeometryToCesium(layer, feature, geom, proj, - style, context.billboards, newBillboardAddedCallback); - if (!result) { - // no wrapping primitive - return null; - } else { - return result; - } - case 'LinearRing': - throw new Error('LinearRing should only be part of polygon.'); - default: - throw new Error('Ol geom type not handled : ' + geom.getType()); - } -}; +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'on', + ol.geom.MultiPoint.prototype.on); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'once', + ol.geom.MultiPoint.prototype.once); -/** - * Convert an OpenLayers vector layer to Cesium primitive collection. - * For each feature, the associated primitive will be stored in - * `featurePrimitiveMap`. - * @param {!(ol.layer.Vector|ol.layer.Image)} olLayer - * @param {!ol.View} olView - * @param {!Object.<number, !Cesium.Primitive>} featurePrimitiveMap - * @return {!olcs.core.VectorLayerCounterpart} - * @api - */ -olcs.FeatureConverter.prototype.olVectorLayerToCesium = - function(olLayer, olView, featurePrimitiveMap) { - var source = olLayer.getSource(); - if (source instanceof ol.source.ImageVector) { - source = source.getSource(); - } - var features = source.getFeatures(); - var proj = olView.getProjection(); - var resolution = olView.getResolution(); +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'un', + ol.geom.MultiPoint.prototype.un); - if (!goog.isDef(resolution) || !proj) { - goog.asserts.fail('View not ready'); - // an assertion is not enough for closure to assume resolution and proj - // are defined - throw new Error('View not ready'); - } - var counterpart = new olcs.core.VectorLayerCounterpart(proj, this.scene); - var context = counterpart.context; - for (var i = 0; i < features.length; ++i) { - var feature = features[i]; - if (!goog.isDefAndNotNull(feature)) { - continue; - } - var layerStyle; - if (olLayer instanceof ol.layer.Image) { - layerStyle = olLayer.getSource().getStyleFunction(); - } else { - layerStyle = olLayer.getStyleFunction(); - } - var style = this.computePlainStyle(olLayer, feature, layerStyle, - resolution); - if (!style) { - // only 'render' features with a style - continue; - } - var primitives = this.olFeatureToCesium(olLayer, feature, style, context); - if (!primitives) continue; - featurePrimitiveMap[goog.getUid(feature)] = primitives; - counterpart.getRootPrimitive().add(primitives); - } +goog.exportProperty( + ol.geom.MultiPoint.prototype, + 'unByKey', + ol.geom.MultiPoint.prototype.unByKey); - return counterpart; -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getFirstCoordinate', + ol.geom.MultiPolygon.prototype.getFirstCoordinate); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getLastCoordinate', + ol.geom.MultiPolygon.prototype.getLastCoordinate); -/** - * Convert an OpenLayers feature to Cesium primitive collection. - * @param {!(ol.layer.Vector|ol.layer.Image)} layer - * @param {!ol.View} view - * @param {!ol.Feature} feature - * @param {!olcsx.core.OlFeatureToCesiumContext} context - * @return {Cesium.Primitive} - * @api - */ -olcs.FeatureConverter.prototype.convert = - function(layer, view, feature, context) { - var proj = view.getProjection(); - var resolution = view.getResolution(); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getLayout', + ol.geom.MultiPolygon.prototype.getLayout); - if (!goog.isDef(resolution) || !proj) { - return null; - } +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getClosestPoint', + ol.geom.MultiPolygon.prototype.getClosestPoint); - var layerStyle; - if (layer instanceof ol.layer.Image) { - layerStyle = layer.getSource().getStyleFunction(); - } else { - layerStyle = layer.getStyleFunction(); - } - var style = this.computePlainStyle(layer, feature, layerStyle, resolution); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getExtent', + ol.geom.MultiPolygon.prototype.getExtent); - if (!style) { - // only 'render' features with a style - return null; - } +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'simplify', + ol.geom.MultiPolygon.prototype.simplify); - context.projection = proj; - return this.olFeatureToCesium(layer, feature, style, context); -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'transform', + ol.geom.MultiPolygon.prototype.transform); -goog.provide('olcs.RasterSynchronizer'); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'get', + ol.geom.MultiPolygon.prototype.get); -goog.require('olcs.AbstractSynchronizer'); -goog.require('olcs.core'); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getKeys', + ol.geom.MultiPolygon.prototype.getKeys); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getProperties', + ol.geom.MultiPolygon.prototype.getProperties); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'set', + ol.geom.MultiPolygon.prototype.set); -/** - * This object takes care of one-directional synchronization of - * ol3 raster layers to the given Cesium globe. - * @param {!ol.Map} map - * @param {!Cesium.Scene} scene - * @constructor - * @extends {olcs.AbstractSynchronizer.<Cesium.ImageryLayer>} - * @api - */ -olcs.RasterSynchronizer = function(map, scene) { - /** - * @type {!Cesium.ImageryLayerCollection} - * @private - */ - this.cesiumLayers_ = scene.imageryLayers; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'setProperties', + ol.geom.MultiPolygon.prototype.setProperties); - /** - * @type {!Cesium.ImageryLayerCollection} - * @private - */ - this.ourLayers_ = new Cesium.ImageryLayerCollection(); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'unset', + ol.geom.MultiPolygon.prototype.unset); - goog.base(this, map, scene); -}; -goog.inherits(olcs.RasterSynchronizer, olcs.AbstractSynchronizer); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'changed', + ol.geom.MultiPolygon.prototype.changed); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'dispatchEvent', + ol.geom.MultiPolygon.prototype.dispatchEvent); -/** - * @inheritDoc - */ -olcs.RasterSynchronizer.prototype.addCesiumObject = function(object) { - this.cesiumLayers_.add(object); - this.ourLayers_.add(object); -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'getRevision', + ol.geom.MultiPolygon.prototype.getRevision); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'on', + ol.geom.MultiPolygon.prototype.on); -/** - * @inheritDoc - */ -olcs.RasterSynchronizer.prototype.destroyCesiumObject = function(object) { - object.destroy(); -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'once', + ol.geom.MultiPolygon.prototype.once); +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'un', + ol.geom.MultiPolygon.prototype.un); -/** - * @inheritDoc - */ -olcs.RasterSynchronizer.prototype.removeSingleCesiumObject = - function(object, destroy) { - this.cesiumLayers_.remove(object, destroy); - this.ourLayers_.remove(object, false); -}; +goog.exportProperty( + ol.geom.MultiPolygon.prototype, + 'unByKey', + ol.geom.MultiPolygon.prototype.unByKey); +goog.exportProperty( + ol.geom.Point.prototype, + 'getFirstCoordinate', + ol.geom.Point.prototype.getFirstCoordinate); -/** - * @inheritDoc - */ -olcs.RasterSynchronizer.prototype.removeAllCesiumObjects = function(destroy) { - for (var i = 0; i < this.ourLayers_.length; ++i) { - this.cesiumLayers_.remove(this.ourLayers_.get(i), destroy); - } - this.ourLayers_.removeAll(false); -}; +goog.exportProperty( + ol.geom.Point.prototype, + 'getLastCoordinate', + ol.geom.Point.prototype.getLastCoordinate); +goog.exportProperty( + ol.geom.Point.prototype, + 'getLayout', + ol.geom.Point.prototype.getLayout); -/** - * Creates an array of Cesium.ImageryLayer. - * May be overriden by child classes to implement custom behavior. - * The default implementation handles tiled imageries in EPSG:4326 or - * EPSG:3859. - * @param {!ol.layer.Base} olLayer - * @param {?ol.proj.Projection} viewProj Projection of the view. - * @return {?Array.<!Cesium.ImageryLayer>} array or null if not possible - * (or supported) - * @protected - */ -olcs.RasterSynchronizer.prototype.convertLayerToCesiumImageries = - function(olLayer, viewProj) { - var result = olcs.core.tileLayerToImageryLayer(olLayer, viewProj); - return result ? [result] : null; -}; +goog.exportProperty( + ol.geom.Point.prototype, + 'getClosestPoint', + ol.geom.Point.prototype.getClosestPoint); +goog.exportProperty( + ol.geom.Point.prototype, + 'getExtent', + ol.geom.Point.prototype.getExtent); -/** - * @inheritDoc - */ -olcs.RasterSynchronizer.prototype.createSingleLayerCounterparts = - function(olLayer) { - var viewProj = this.view.getProjection(); - var cesiumObjects = this.convertLayerToCesiumImageries(olLayer, viewProj); - if (!goog.isNull(cesiumObjects)) { - olLayer.on(['change:opacity', 'change:visible'], - function(e) { - // the compiler does not seem to be able to infer this - goog.asserts.assert(!goog.isNull(cesiumObjects)); - for (var i = 0; i < cesiumObjects.length; ++i) { - olcs.core.updateCesiumLayerProperties(olLayer, cesiumObjects[i]); - } - }); +goog.exportProperty( + ol.geom.Point.prototype, + 'simplify', + ol.geom.Point.prototype.simplify); - for (var i = 0; i < cesiumObjects.length; ++i) { - olcs.core.updateCesiumLayerProperties(olLayer, cesiumObjects[i]); - } +goog.exportProperty( + ol.geom.Point.prototype, + 'transform', + ol.geom.Point.prototype.transform); - // there is no way to modify Cesium layer extent, - // we have to recreate when ol3 layer extent changes: - olLayer.on('change:extent', function(e) { - for (var i = 0; i < cesiumObjects.length; ++i) { - this.cesiumLayers_.remove(cesiumObjects[i], true); // destroy - this.ourLayers_.remove(cesiumObjects[i], false); - } - delete this.layerMap[goog.getUid(olLayer)]; // invalidate the map entry - this.synchronize(); - }, this); +goog.exportProperty( + ol.geom.Point.prototype, + 'get', + ol.geom.Point.prototype.get); - olLayer.on('change', function(e) { - // when the source changes, re-add the layer to force update - for (var i = 0; i < cesiumObjects.length; ++i) { - var position = this.cesiumLayers_.indexOf(cesiumObjects[i]); - if (position >= 0) { - this.cesiumLayers_.remove(cesiumObjects[i], false); - this.cesiumLayers_.add(cesiumObjects[i], position); - } - } - }, this); - } +goog.exportProperty( + ol.geom.Point.prototype, + 'getKeys', + ol.geom.Point.prototype.getKeys); - return Array.isArray(cesiumObjects) ? cesiumObjects : null; -}; +goog.exportProperty( + ol.geom.Point.prototype, + 'getProperties', + ol.geom.Point.prototype.getProperties); +goog.exportProperty( + ol.geom.Point.prototype, + 'set', + ol.geom.Point.prototype.set); -/** - * Order counterparts using the same algorithm as the Openlayers renderer: - * z-index then original sequence order. - * @protected - */ -olcs.RasterSynchronizer.prototype.orderLayers = function() { - var layers = []; - var zIndices = {}; - var fifo = [this.mapLayerGroup]; +goog.exportProperty( + ol.geom.Point.prototype, + 'setProperties', + ol.geom.Point.prototype.setProperties); - while (fifo.length > 0) { - var olLayer = fifo.splice(0, 1)[0]; - layers.push(olLayer); - zIndices[goog.getUid(olLayer)] = olLayer.getZIndex(); +goog.exportProperty( + ol.geom.Point.prototype, + 'unset', + ol.geom.Point.prototype.unset); - if (olLayer instanceof ol.layer.Group) { - var sublayers = olLayer.getLayers(); - if (goog.isDef(sublayers)) { - sublayers.forEach(function(el) { - fifo.push(el); - }); - } - } - } +goog.exportProperty( + ol.geom.Point.prototype, + 'changed', + ol.geom.Point.prototype.changed); - goog.array.stableSort(layers, function(layer1, layer2) { - return zIndices[goog.getUid(layer1)] - zIndices[goog.getUid(layer2)]; - }); +goog.exportProperty( + ol.geom.Point.prototype, + 'dispatchEvent', + ol.geom.Point.prototype.dispatchEvent); - layers.forEach(function(olLayer) { - var olLayerId = goog.getUid(olLayer); - var cesiumObjects = this.layerMap[olLayerId]; - if (cesiumObjects) { - cesiumObjects.forEach(this.raiseToTop, this); - } - }, this); -}; +goog.exportProperty( + ol.geom.Point.prototype, + 'getRevision', + ol.geom.Point.prototype.getRevision); +goog.exportProperty( + ol.geom.Point.prototype, + 'on', + ol.geom.Point.prototype.on); -/** - * @param {Cesium.ImageryLayer} counterpart - */ -olcs.RasterSynchronizer.prototype.raiseToTop = function(counterpart) { - this.cesiumLayers_.raiseToTop(counterpart); -}; +goog.exportProperty( + ol.geom.Point.prototype, + 'once', + ol.geom.Point.prototype.once); -goog.provide('olcs.VectorSynchronizer'); +goog.exportProperty( + ol.geom.Point.prototype, + 'un', + ol.geom.Point.prototype.un); -goog.require('ol.layer.Vector'); -goog.require('olcs.AbstractSynchronizer'); -goog.require('olcs.FeatureConverter'); -goog.require('olcs.core'); -goog.require('olcs.core.VectorLayerCounterpart'); +goog.exportProperty( + ol.geom.Point.prototype, + 'unByKey', + ol.geom.Point.prototype.unByKey); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getFirstCoordinate', + ol.geom.Polygon.prototype.getFirstCoordinate); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getLastCoordinate', + ol.geom.Polygon.prototype.getLastCoordinate); -/** - * Unidirectionally synchronize OpenLayers vector layers to Cesium. - * @param {!ol.Map} map - * @param {!Cesium.Scene} scene - * @param {olcs.FeatureConverter=} opt_converter - * @constructor - * @extends {olcs.AbstractSynchronizer.<olcs.core.VectorLayerCounterpart>} - * @api - */ -olcs.VectorSynchronizer = function(map, scene, opt_converter) { +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getLayout', + ol.geom.Polygon.prototype.getLayout); - /** - * @protected - */ - this.converter = opt_converter || new olcs.FeatureConverter(scene); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getClosestPoint', + ol.geom.Polygon.prototype.getClosestPoint); - /** - * @private - */ - this.csAllPrimitives_ = new Cesium.PrimitiveCollection(); - scene.primitives.add(this.csAllPrimitives_); - this.csAllPrimitives_.destroyPrimitives = false; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getExtent', + ol.geom.Polygon.prototype.getExtent); - goog.base(this, map, scene); -}; -goog.inherits(olcs.VectorSynchronizer, olcs.AbstractSynchronizer); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'simplify', + ol.geom.Polygon.prototype.simplify); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'transform', + ol.geom.Polygon.prototype.transform); -/** - * @inheritDoc - */ -olcs.VectorSynchronizer.prototype.addCesiumObject = function(counterpart) { - goog.asserts.assert(!goog.isNull(counterpart)); - counterpart.getRootPrimitive()['counterpart'] = counterpart; - this.csAllPrimitives_.add(counterpart.getRootPrimitive()); -}; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'get', + ol.geom.Polygon.prototype.get); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getKeys', + ol.geom.Polygon.prototype.getKeys); -/** - * @inheritDoc - */ -olcs.VectorSynchronizer.prototype.destroyCesiumObject = function(object) { - object.getRootPrimitive().destroy(); -}; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getProperties', + ol.geom.Polygon.prototype.getProperties); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'set', + ol.geom.Polygon.prototype.set); -/** - * @inheritDoc - */ -olcs.VectorSynchronizer.prototype.removeSingleCesiumObject = - function(object, destroy) { - object.destroy(); - this.csAllPrimitives_.destroyPrimitives = destroy; - this.csAllPrimitives_.remove(object.getRootPrimitive()); - this.csAllPrimitives_.destroyPrimitives = false; -}; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'setProperties', + ol.geom.Polygon.prototype.setProperties); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'unset', + ol.geom.Polygon.prototype.unset); -/** - * @inheritDoc - */ -olcs.VectorSynchronizer.prototype.removeAllCesiumObjects = function(destroy) { - this.csAllPrimitives_.destroyPrimitives = destroy; - if (destroy) { - for (var i = 0; i < this.csAllPrimitives_.length; ++i) { - this.csAllPrimitives_.get(i)['counterpart'].destroy(); - } - } - this.csAllPrimitives_.removeAll(); - this.csAllPrimitives_.destroyPrimitives = false; -}; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'changed', + ol.geom.Polygon.prototype.changed); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'dispatchEvent', + ol.geom.Polygon.prototype.dispatchEvent); -/** - * @inheritDoc - */ -olcs.VectorSynchronizer.prototype.createSingleLayerCounterparts = - function(olLayer) { - if (!(olLayer instanceof ol.layer.Vector) && - !(olLayer instanceof ol.layer.Image && - olLayer.getSource() instanceof ol.source.ImageVector)) { - return null; - } - goog.asserts.assertInstanceof(olLayer, ol.layer.Layer); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'getRevision', + ol.geom.Polygon.prototype.getRevision); - var source = olLayer.getSource(); - if (olLayer.getSource() instanceof ol.source.ImageVector) { - source = olLayer.getSource().getSource(); - } +goog.exportProperty( + ol.geom.Polygon.prototype, + 'on', + ol.geom.Polygon.prototype.on); - goog.asserts.assertInstanceof(source, ol.source.Vector); - goog.asserts.assert(!goog.isNull(this.view)); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'once', + ol.geom.Polygon.prototype.once); - var view = this.view; - var featurePrimitiveMap = {}; - var counterpart = this.converter.olVectorLayerToCesium(olLayer, view, - featurePrimitiveMap); - var csPrimitives = counterpart.getRootPrimitive(); - var olListenKeys = counterpart.olListenKeys; +goog.exportProperty( + ol.geom.Polygon.prototype, + 'un', + ol.geom.Polygon.prototype.un); - csPrimitives.show = olLayer.getVisible(); +goog.exportProperty( + ol.geom.Polygon.prototype, + 'unByKey', + ol.geom.Polygon.prototype.unByKey); - olListenKeys.push(olLayer.on('change:visible', function(e) { - csPrimitives.show = olLayer.getVisible(); - })); +goog.exportProperty( + ol.format.GML2.prototype, + 'readFeatures', + ol.format.GML2.prototype.readFeatures); - var onAddFeature = (function(feature) { - goog.asserts.assert( - (olLayer instanceof ol.layer.Vector) || - (olLayer instanceof ol.layer.Image) - ); - var context = counterpart.context; - var prim = this.converter.convert(olLayer, view, feature, context); - if (prim) { - featurePrimitiveMap[goog.getUid(feature)] = prim; - csPrimitives.add(prim); - } - }).bind(this); +goog.exportProperty( + ol.format.GML3.prototype, + 'readFeatures', + ol.format.GML3.prototype.readFeatures); - var onRemoveFeature = (function(feature) { - var geometry = feature.getGeometry(); - var id = goog.getUid(feature); - if (!geometry || geometry.getType() == 'Point') { - var context = counterpart.context; - var bb = context.featureToCesiumMap[id]; - delete context.featureToCesiumMap[id]; - if (bb instanceof Cesium.Billboard) { - context.billboards.remove(bb); - } - } - var csPrimitive = featurePrimitiveMap[id]; - delete featurePrimitiveMap[id]; - if (goog.isDefAndNotNull(csPrimitive)) { - csPrimitives.remove(csPrimitive); - } - }).bind(this); +goog.exportProperty( + ol.format.GML.prototype, + 'readFeatures', + ol.format.GML.prototype.readFeatures); - olListenKeys.push(source.on('addfeature', function(e) { - goog.asserts.assert(goog.isDefAndNotNull(e.feature)); - onAddFeature(e.feature); - }, this)); +goog.exportProperty( + ol.control.Control.prototype, + 'get', + ol.control.Control.prototype.get); - olListenKeys.push(source.on('removefeature', function(e) { - goog.asserts.assert(goog.isDefAndNotNull(e.feature)); - onRemoveFeature(e.feature); - }, this)); +goog.exportProperty( + ol.control.Control.prototype, + 'getKeys', + ol.control.Control.prototype.getKeys); - olListenKeys.push(source.on('changefeature', function(e) { - var feature = e.feature; - goog.asserts.assert(goog.isDefAndNotNull(feature)); - onRemoveFeature(feature); - onAddFeature(feature); - }, this)); +goog.exportProperty( + ol.control.Control.prototype, + 'getProperties', + ol.control.Control.prototype.getProperties); - return counterpart ? [counterpart] : null; -}; +goog.exportProperty( + ol.control.Control.prototype, + 'set', + ol.control.Control.prototype.set); -goog.provide('olcs.OLCesium'); +goog.exportProperty( + ol.control.Control.prototype, + 'setProperties', + ol.control.Control.prototype.setProperties); -goog.require('goog.async.AnimationDelay'); -goog.require('goog.dom'); -goog.require('olcs.AutoRenderLoop'); -goog.require('olcs.Camera'); -goog.require('olcs.RasterSynchronizer'); -goog.require('olcs.VectorSynchronizer'); +goog.exportProperty( + ol.control.Control.prototype, + 'unset', + ol.control.Control.prototype.unset); +goog.exportProperty( + ol.control.Control.prototype, + 'changed', + ol.control.Control.prototype.changed); +goog.exportProperty( + ol.control.Control.prototype, + 'dispatchEvent', + ol.control.Control.prototype.dispatchEvent); -/** - * @param {!olcsx.OLCesiumOptions} options Options. - * @constructor - * @api - */ -olcs.OLCesium = function(options) { +goog.exportProperty( + ol.control.Control.prototype, + 'getRevision', + ol.control.Control.prototype.getRevision); - /** - * @type {olcs.AutoRenderLoop} - * @private - */ - this.autoRenderLoop_ = null; +goog.exportProperty( + ol.control.Control.prototype, + 'on', + ol.control.Control.prototype.on); - /** - * @type {!ol.Map} - * @private - */ - this.map_ = options.map; +goog.exportProperty( + ol.control.Control.prototype, + 'once', + ol.control.Control.prototype.once); - /** - * @type {number} - * @private - */ - this.resolutionScale_ = 1.0; +goog.exportProperty( + ol.control.Control.prototype, + 'un', + ol.control.Control.prototype.un); - /** - * @type {number} - * @private - */ - this.canvasClientWidth_ = 0.0; +goog.exportProperty( + ol.control.Control.prototype, + 'unByKey', + ol.control.Control.prototype.unByKey); - /** - * @type {number} - * @private - */ - this.canvasClientHeight_ = 0.0; +goog.exportProperty( + ol.control.Attribution.prototype, + 'getMap', + ol.control.Attribution.prototype.getMap); - /** - * @type {boolean} - * @private - */ - this.resolutionScaleChanged_ = true; // force resize +goog.exportProperty( + ol.control.Attribution.prototype, + 'setMap', + ol.control.Attribution.prototype.setMap); - var fillArea = 'position:absolute;top:0;left:0;width:100%;height:100%;'; +goog.exportProperty( + ol.control.Attribution.prototype, + 'setTarget', + ol.control.Attribution.prototype.setTarget); - /** - * @type {!Element} - * @private - */ - this.container_ = goog.dom.createDom(goog.dom.TagName.DIV, - {style: fillArea + 'visibility:hidden;'}); +goog.exportProperty( + ol.control.Attribution.prototype, + 'get', + ol.control.Attribution.prototype.get); - var targetElement = goog.dom.getElement(options.target || null); - if (targetElement) { - goog.dom.appendChild(targetElement, this.container_); - } else { - var vp = this.map_.getViewport(); - var oc = goog.dom.getElementByClass('ol-overlaycontainer', vp); - if (oc) { - goog.dom.insertSiblingBefore(this.container_, oc); - } - } +goog.exportProperty( + ol.control.Attribution.prototype, + 'getKeys', + ol.control.Attribution.prototype.getKeys); - /** - * Whether the Cesium container is placed over the ol map. - * @type {boolean} - * @private - */ - this.isOverMap_ = !goog.isDefAndNotNull(targetElement); +goog.exportProperty( + ol.control.Attribution.prototype, + 'getProperties', + ol.control.Attribution.prototype.getProperties); - /** - * @type {!HTMLCanvasElement} - * @private - */ - this.canvas_ = /** @type {!HTMLCanvasElement} */ - (goog.dom.createDom(goog.dom.TagName.CANVAS, {style: fillArea})); - this.canvas_.oncontextmenu = function() { return false; }; - this.canvas_.onselectstart = function() { return false; }; +goog.exportProperty( + ol.control.Attribution.prototype, + 'set', + ol.control.Attribution.prototype.set); - goog.dom.appendChild(this.container_, this.canvas_); +goog.exportProperty( + ol.control.Attribution.prototype, + 'setProperties', + ol.control.Attribution.prototype.setProperties); - /** - * @type {boolean} - * @private - */ - this.enabled_ = false; +goog.exportProperty( + ol.control.Attribution.prototype, + 'unset', + ol.control.Attribution.prototype.unset); - /** - * @type {!Array.<ol.interaction.Interaction>} - * @private - */ - this.pausedInteractions_ = []; +goog.exportProperty( + ol.control.Attribution.prototype, + 'changed', + ol.control.Attribution.prototype.changed); - /** - * @type {?ol.layer.Group} - * @private - */ - this.hiddenRootGroup_ = null; +goog.exportProperty( + ol.control.Attribution.prototype, + 'dispatchEvent', + ol.control.Attribution.prototype.dispatchEvent); - /** - * @type {!Cesium.Scene} - * @private - */ - this.scene_ = new Cesium.Scene({ - canvas: this.canvas_, - scene3DOnly: true - }); +goog.exportProperty( + ol.control.Attribution.prototype, + 'getRevision', + ol.control.Attribution.prototype.getRevision); - var sscc = this.scene_.screenSpaceCameraController; - sscc.inertiaSpin = 0; - sscc.inertiaTranslate = 0; - sscc.inertiaZoom = 0; +goog.exportProperty( + ol.control.Attribution.prototype, + 'on', + ol.control.Attribution.prototype.on); - sscc.tiltEventTypes.push({ - 'eventType': Cesium.CameraEventType.LEFT_DRAG, - 'modifier': Cesium.KeyboardEventModifier.SHIFT - }); +goog.exportProperty( + ol.control.Attribution.prototype, + 'once', + ol.control.Attribution.prototype.once); - sscc.tiltEventTypes.push({ - 'eventType': Cesium.CameraEventType.LEFT_DRAG, - 'modifier': Cesium.KeyboardEventModifier.ALT - }); +goog.exportProperty( + ol.control.Attribution.prototype, + 'un', + ol.control.Attribution.prototype.un); - sscc.enableLook = false; +goog.exportProperty( + ol.control.Attribution.prototype, + 'unByKey', + ol.control.Attribution.prototype.unByKey); - this.scene_.camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'getMap', + ol.control.FullScreen.prototype.getMap); - /** - * @type {!olcs.Camera} - * @private - */ - this.camera_ = new olcs.Camera(this.scene_, this.map_); +goog.exportProperty( + ol.control.FullScreen.prototype, + 'setMap', + ol.control.FullScreen.prototype.setMap); - /** - * @type {!Cesium.Globe} - * @private - */ - this.globe_ = new Cesium.Globe(Cesium.Ellipsoid.WGS84); - this.scene_.globe = this.globe_; - this.scene_.skyAtmosphere = new Cesium.SkyAtmosphere(); +goog.exportProperty( + ol.control.FullScreen.prototype, + 'setTarget', + ol.control.FullScreen.prototype.setTarget); - this.dataSourceCollection_ = new Cesium.DataSourceCollection(); - this.dataSourceDisplay_ = new Cesium.DataSourceDisplay({ - scene: this.scene_, - dataSourceCollection: this.dataSourceCollection_ - }); +goog.exportProperty( + ol.control.FullScreen.prototype, + 'get', + ol.control.FullScreen.prototype.get); - var synchronizers = goog.isDef(options.createSynchronizers) ? - options.createSynchronizers(this.map_, this.scene_) : - [ - new olcs.RasterSynchronizer(this.map_, this.scene_), - new olcs.VectorSynchronizer(this.map_, this.scene_) - ]; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'getKeys', + ol.control.FullScreen.prototype.getKeys); - // Assures correct canvas size after initialisation - this.handleResize_(); +goog.exportProperty( + ol.control.FullScreen.prototype, + 'getProperties', + ol.control.FullScreen.prototype.getProperties); - for (var i = synchronizers.length - 1; i >= 0; --i) { - synchronizers[i].synchronize(); - } +goog.exportProperty( + ol.control.FullScreen.prototype, + 'set', + ol.control.FullScreen.prototype.set); - if (this.isOverMap_) { - // if in "stacked mode", hide everything except canvas (including credits) - var credits = goog.dom.getNextElementSibling(this.canvas_); - if (goog.isDefAndNotNull(credits)) { - credits.style.display = 'none'; - } - } +goog.exportProperty( + ol.control.FullScreen.prototype, + 'setProperties', + ol.control.FullScreen.prototype.setProperties); - this.cesiumRenderingDelay_ = new goog.async.AnimationDelay(function(time) { - if (!this.blockCesiumRendering_) { - var julianDate = Cesium.JulianDate.now(); - this.scene_.initializeFrame(); - this.handleResize_(); - this.dataSourceDisplay_.update(julianDate); - this.scene_.render(julianDate); - this.enabled_ && this.camera_.checkCameraChange(); - } - this.cesiumRenderingDelay_.start(); - }, undefined, this); +goog.exportProperty( + ol.control.FullScreen.prototype, + 'unset', + ol.control.FullScreen.prototype.unset); - /** - * @private - */ - this.blockCesiumRendering_ = false; -}; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'changed', + ol.control.FullScreen.prototype.changed); +goog.exportProperty( + ol.control.FullScreen.prototype, + 'dispatchEvent', + ol.control.FullScreen.prototype.dispatchEvent); -/** - * @private - */ -olcs.OLCesium.prototype.handleResize_ = function() { - var width = this.canvas_.clientWidth; - var height = this.canvas_.clientHeight; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'getRevision', + ol.control.FullScreen.prototype.getRevision); - if (width === this.canvasClientWidth_ && - height === this.canvasClientHeight_ && - !this.resolutionScaleChanged_) { - return; - } +goog.exportProperty( + ol.control.FullScreen.prototype, + 'on', + ol.control.FullScreen.prototype.on); - var zoomFactor = (window.devicePixelRatio || 1.0) * this.resolutionScale_; - this.resolutionScaleChanged_ = false; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'once', + ol.control.FullScreen.prototype.once); - this.canvasClientWidth_ = width; - this.canvasClientHeight_ = height; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'un', + ol.control.FullScreen.prototype.un); - width *= zoomFactor; - height *= zoomFactor; +goog.exportProperty( + ol.control.FullScreen.prototype, + 'unByKey', + ol.control.FullScreen.prototype.unByKey); - this.canvas_.width = width; - this.canvas_.height = height; - this.scene_.camera.frustum.aspectRatio = width / height; -}; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'getMap', + ol.control.MousePosition.prototype.getMap); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'setMap', + ol.control.MousePosition.prototype.setMap); -/** - * @return {!olcs.Camera} - * @api - */ -olcs.OLCesium.prototype.getCamera = function() { - return this.camera_; -}; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'setTarget', + ol.control.MousePosition.prototype.setTarget); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'get', + ol.control.MousePosition.prototype.get); -/** - * @return {!ol.Map} - * @api - */ -olcs.OLCesium.prototype.getOlMap = function() { - return this.map_; -}; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'getKeys', + ol.control.MousePosition.prototype.getKeys); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'getProperties', + ol.control.MousePosition.prototype.getProperties); -/** - * @return {!Cesium.Scene} - * @api - */ -olcs.OLCesium.prototype.getCesiumScene = function() { - return this.scene_; -}; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'set', + ol.control.MousePosition.prototype.set); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'setProperties', + ol.control.MousePosition.prototype.setProperties); -/** - * @return {!Cesium.DataSourceCollection} - * @api - */ -olcs.OLCesium.prototype.getDataSources = function() { - return this.dataSourceCollection_; -}; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'unset', + ol.control.MousePosition.prototype.unset); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'changed', + ol.control.MousePosition.prototype.changed); -/** - * @return {boolean} - * @api - */ -olcs.OLCesium.prototype.getEnabled = function() { - return this.enabled_; -}; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'dispatchEvent', + ol.control.MousePosition.prototype.dispatchEvent); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'getRevision', + ol.control.MousePosition.prototype.getRevision); -/** - * Enables/disables the Cesium. - * This modifies the visibility style of the container element. - * @param {boolean} enable - * @api - */ -olcs.OLCesium.prototype.setEnabled = function(enable) { - if (this.enabled_ == enable) { - return; - } - this.enabled_ = enable; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'on', + ol.control.MousePosition.prototype.on); - // some Cesium operations are operating with canvas.clientWidth, - // so we can't remove it from DOM or even make display:none; - this.container_.style.visibility = this.enabled_ ? 'visible' : 'hidden'; - if (this.enabled_) { - if (this.isOverMap_) { - var interactions = this.map_.getInteractions(); - interactions.forEach(function(el, i, arr) { - this.pausedInteractions_.push(el); - }, this); - interactions.clear(); +goog.exportProperty( + ol.control.MousePosition.prototype, + 'once', + ol.control.MousePosition.prototype.once); - var rootGroup = this.map_.getLayerGroup(); - if (rootGroup.getVisible()) { - this.hiddenRootGroup_ = rootGroup; - this.hiddenRootGroup_.setVisible(false); - } - } - this.camera_.readFromView(); - this.cesiumRenderingDelay_.start(); - } else { - if (this.isOverMap_) { - var interactions = this.map_.getInteractions(); - this.pausedInteractions_.forEach(function(interaction) { - interactions.push(interaction); - }); - this.pausedInteractions_.length = 0; +goog.exportProperty( + ol.control.MousePosition.prototype, + 'un', + ol.control.MousePosition.prototype.un); - if (!goog.isNull(this.hiddenRootGroup_)) { - this.hiddenRootGroup_.setVisible(true); - this.hiddenRootGroup_ = null; - } - } +goog.exportProperty( + ol.control.MousePosition.prototype, + 'unByKey', + ol.control.MousePosition.prototype.unByKey); - this.camera_.updateView(); - this.cesiumRenderingDelay_.stop(); - } -}; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getMap', + ol.control.OverviewMap.prototype.getMap); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'setMap', + ol.control.OverviewMap.prototype.setMap); -/** - * Preload Cesium so that it is ready when transitioning from 2D to 3D. - * @param {number} height Target height of the camera - * @param {number} timeout Milliseconds after which the warming will stop - * @api -*/ -olcs.OLCesium.prototype.warmUp = function(height, timeout) { - if (this.enabled_) { - // already enabled - return; - } - this.camera_.readFromView(); - var ellipsoid = this.globe_.ellipsoid; - var csCamera = this.scene_.camera; - var position = ellipsoid.cartesianToCartographic(csCamera.position); - if (position.height < height) { - position.height = height; - csCamera.position = ellipsoid.cartographicToCartesian(position); - } - this.cesiumRenderingDelay_.start(); - var that = this; - setTimeout( - function() { !that.enabled_ && that.cesiumRenderingDelay_.stop(); }, - timeout); -}; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'setTarget', + ol.control.OverviewMap.prototype.setTarget); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'get', + ol.control.OverviewMap.prototype.get); -/** - * Block Cesium rendering to save resources. - * @param {boolean} block True to block. - * @api -*/ -olcs.OLCesium.prototype.setBlockCesiumRendering = function(block) { - this.blockCesiumRendering_ = block; -}; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getKeys', + ol.control.OverviewMap.prototype.getKeys); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getProperties', + ol.control.OverviewMap.prototype.getProperties); -/** - * Render the globe only when necessary in order to save resources. - * Experimental. - * @api - */ -olcs.OLCesium.prototype.enableAutoRenderLoop = function() { - if (!this.autoRenderLoop_) { - this.autoRenderLoop_ = new olcs.AutoRenderLoop(this, false); - } -}; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'set', + ol.control.OverviewMap.prototype.set); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'setProperties', + ol.control.OverviewMap.prototype.setProperties); -/** - * Get the autorender loop. - * @return {?olcs.AutoRenderLoop} - * @api -*/ -olcs.OLCesium.prototype.getAutoRenderLoop = function() { - return this.autoRenderLoop_; -}; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'unset', + ol.control.OverviewMap.prototype.unset); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'changed', + ol.control.OverviewMap.prototype.changed); -/** - * The 3D Cesium globe is rendered in a canvas with two different dimensions: - * clientWidth and clientHeight which are the dimension on the screen and - * width and height which are the dimensions of the drawing buffer. - * - * By using a resolution scale lower than 1.0, it is possible to render the - * globe in a buffer smaller than the canvas client dimensions and improve - * performance, at the cost of quality. - * - * Pixel ratio should also be taken into account; by default, a device with - * pixel ratio of 2.0 will have a buffer surface 4 times bigger than the client - * surface. - * - * @param {number} value - * @this {olcs.OLCesium} - * @api - */ -olcs.OLCesium.prototype.setResolutionScale = function(value) { - value = Math.max(0, value); - if (value !== this.resolutionScale_) { - this.resolutionScale_ = Math.max(0, value); - this.resolutionScaleChanged_ = true; - if (this.autoRenderLoop_) { - this.autoRenderLoop_.restartRenderLoop(); - } - } -}; +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'dispatchEvent', + ol.control.OverviewMap.prototype.dispatchEvent); -goog.provide('ga.GaRasterSynchronizer'); -goog.require('olcs.RasterSynchronizer'); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'getRevision', + ol.control.OverviewMap.prototype.getRevision); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'on', + ol.control.OverviewMap.prototype.on); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'once', + ol.control.OverviewMap.prototype.once); -/** - * Handle mapping OL3 2D layers to Cesium 3D Imageries in EPSG:4326. - * @param {!ol.Map} map - * @param {!Cesium.Scene} scene - * @constructor - * @extends {olcs.RasterSynchronizer} - * @api - */ -ga.GaRasterSynchronizer = function(map, scene) { - goog.base(this, map, scene); -}; -goog.inherits(ga.GaRasterSynchronizer, olcs.RasterSynchronizer); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'un', + ol.control.OverviewMap.prototype.un); +goog.exportProperty( + ol.control.OverviewMap.prototype, + 'unByKey', + ol.control.OverviewMap.prototype.unByKey); -/** - * @override - */ -ga.GaRasterSynchronizer.prototype.convertLayerToCesiumImageries = - function(olLayer, viewProj) { +goog.exportProperty( + ol.control.Rotate.prototype, + 'getMap', + ol.control.Rotate.prototype.getMap); - /** - * @type {Cesium.ImageryProvider} - */ - var provider = null; +goog.exportProperty( + ol.control.Rotate.prototype, + 'setMap', + ol.control.Rotate.prototype.setMap); - var isGroup = olLayer instanceof ol.layer.Group; - if (!isGroup && (olLayer.getSource() instanceof ol.source.Vector)) { - return null; - } +goog.exportProperty( + ol.control.Rotate.prototype, + 'setTarget', + ol.control.Rotate.prototype.setTarget); - // Read custom, non standard properties - var factory = olLayer['getCesiumImageryProvider']; - if (!factory) { - // root layer group - return null; - } - provider = factory(); - if (!provider) { - return null; - } +goog.exportProperty( + ol.control.Rotate.prototype, + 'get', + ol.control.Rotate.prototype.get); - // the provider is always non-null if we got this far +goog.exportProperty( + ol.control.Rotate.prototype, + 'getKeys', + ol.control.Rotate.prototype.getKeys); - var providers = Array.isArray(provider) ? provider : [provider]; - return providers.map(function(p) { - return new Cesium.ImageryLayer(p); - }); -}; +goog.exportProperty( + ol.control.Rotate.prototype, + 'getProperties', + ol.control.Rotate.prototype.getProperties); -// Copyright 2009 The Closure Library Authors. -// All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file has been auto-generated by GenJsDeps, please do not edit. +goog.exportProperty( + ol.control.Rotate.prototype, + 'set', + ol.control.Rotate.prototype.set); -goog.addDependency('demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'], ['goog.ui.equation.EquationEditorDialog']); -goog.addDependency('demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'], ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']); -goog.addDependency('demos/editor/helloworlddialog.js', ['goog.demos.editor.HelloWorldDialog', 'goog.demos.editor.HelloWorldDialog.OkEvent'], ['goog.dom.TagName', 'goog.events.Event', 'goog.string', 'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder', 'goog.ui.editor.AbstractDialog.EventType']); -goog.addDependency('demos/editor/helloworlddialogplugin.js', ['goog.demos.editor.HelloWorldDialogPlugin', 'goog.demos.editor.HelloWorldDialogPlugin.Command'], ['goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName', 'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range', 'goog.functions', 'goog.ui.editor.AbstractDialog.EventType']); +goog.exportProperty( + ol.control.Rotate.prototype, + 'setProperties', + ol.control.Rotate.prototype.setProperties); -/** - * @fileoverview Custom exports file. - * @suppress {checkVars, extraRequire} - */ +goog.exportProperty( + ol.control.Rotate.prototype, + 'unset', + ol.control.Rotate.prototype.unset); -goog.require('ga.GaRasterSynchronizer'); -goog.require('olcs.AbstractSynchronizer'); -goog.require('olcs.AutoRenderLoop'); -goog.require('olcs.Camera'); -goog.require('olcs.DragBox'); -goog.require('olcs.DragBoxEventType'); -goog.require('olcs.FeatureConverter'); -goog.require('olcs.OLCesium'); -goog.require('olcs.RasterSynchronizer'); -goog.require('olcs.VectorSynchronizer'); -goog.require('olcs.core'); +goog.exportProperty( + ol.control.Rotate.prototype, + 'changed', + ol.control.Rotate.prototype.changed); +goog.exportProperty( + ol.control.Rotate.prototype, + 'dispatchEvent', + ol.control.Rotate.prototype.dispatchEvent); -goog.exportSymbol( - 'olcs.AbstractSynchronizer', - olcs.AbstractSynchronizer); +goog.exportProperty( + ol.control.Rotate.prototype, + 'getRevision', + ol.control.Rotate.prototype.getRevision); goog.exportProperty( - olcs.AbstractSynchronizer.prototype, - 'synchronize', - olcs.AbstractSynchronizer.prototype.synchronize); + ol.control.Rotate.prototype, + 'on', + ol.control.Rotate.prototype.on); goog.exportProperty( - olcs.AutoRenderLoop.prototype, - 'restartRenderLoop', - olcs.AutoRenderLoop.prototype.restartRenderLoop); + ol.control.Rotate.prototype, + 'once', + ol.control.Rotate.prototype.once); goog.exportProperty( - olcs.AutoRenderLoop.prototype, - 'setDebug', - olcs.AutoRenderLoop.prototype.setDebug); + ol.control.Rotate.prototype, + 'un', + ol.control.Rotate.prototype.un); -goog.exportSymbol( - 'olcs.Camera', - olcs.Camera); +goog.exportProperty( + ol.control.Rotate.prototype, + 'unByKey', + ol.control.Rotate.prototype.unByKey); goog.exportProperty( - olcs.Camera.prototype, - 'setHeading', - olcs.Camera.prototype.setHeading); + ol.control.ScaleLine.prototype, + 'getMap', + ol.control.ScaleLine.prototype.getMap); goog.exportProperty( - olcs.Camera.prototype, - 'getHeading', - olcs.Camera.prototype.getHeading); + ol.control.ScaleLine.prototype, + 'setMap', + ol.control.ScaleLine.prototype.setMap); goog.exportProperty( - olcs.Camera.prototype, - 'setTilt', - olcs.Camera.prototype.setTilt); + ol.control.ScaleLine.prototype, + 'setTarget', + ol.control.ScaleLine.prototype.setTarget); goog.exportProperty( - olcs.Camera.prototype, - 'getTilt', - olcs.Camera.prototype.getTilt); + ol.control.ScaleLine.prototype, + 'get', + ol.control.ScaleLine.prototype.get); goog.exportProperty( - olcs.Camera.prototype, - 'setDistance', - olcs.Camera.prototype.setDistance); + ol.control.ScaleLine.prototype, + 'getKeys', + ol.control.ScaleLine.prototype.getKeys); goog.exportProperty( - olcs.Camera.prototype, - 'getDistance', - olcs.Camera.prototype.getDistance); + ol.control.ScaleLine.prototype, + 'getProperties', + ol.control.ScaleLine.prototype.getProperties); goog.exportProperty( - olcs.Camera.prototype, - 'setCenter', - olcs.Camera.prototype.setCenter); + ol.control.ScaleLine.prototype, + 'set', + ol.control.ScaleLine.prototype.set); goog.exportProperty( - olcs.Camera.prototype, - 'getCenter', - olcs.Camera.prototype.getCenter); + ol.control.ScaleLine.prototype, + 'setProperties', + ol.control.ScaleLine.prototype.setProperties); goog.exportProperty( - olcs.Camera.prototype, - 'setPosition', - olcs.Camera.prototype.setPosition); + ol.control.ScaleLine.prototype, + 'unset', + ol.control.ScaleLine.prototype.unset); goog.exportProperty( - olcs.Camera.prototype, - 'getPosition', - olcs.Camera.prototype.getPosition); + ol.control.ScaleLine.prototype, + 'changed', + ol.control.ScaleLine.prototype.changed); goog.exportProperty( - olcs.Camera.prototype, - 'setAltitude', - olcs.Camera.prototype.setAltitude); + ol.control.ScaleLine.prototype, + 'dispatchEvent', + ol.control.ScaleLine.prototype.dispatchEvent); goog.exportProperty( - olcs.Camera.prototype, - 'getAltitude', - olcs.Camera.prototype.getAltitude); + ol.control.ScaleLine.prototype, + 'getRevision', + ol.control.ScaleLine.prototype.getRevision); goog.exportProperty( - olcs.Camera.prototype, - 'lookAt', - olcs.Camera.prototype.lookAt); + ol.control.ScaleLine.prototype, + 'on', + ol.control.ScaleLine.prototype.on); goog.exportProperty( - olcs.Camera.prototype, - 'readFromView', - olcs.Camera.prototype.readFromView); + ol.control.ScaleLine.prototype, + 'once', + ol.control.ScaleLine.prototype.once); goog.exportProperty( - olcs.Camera.prototype, - 'updateView', - olcs.Camera.prototype.updateView); + ol.control.ScaleLine.prototype, + 'un', + ol.control.ScaleLine.prototype.un); -goog.exportSymbol( - 'olcs.core.computePixelSizeAtCoordinate', - olcs.core.computePixelSizeAtCoordinate); +goog.exportProperty( + ol.control.ScaleLine.prototype, + 'unByKey', + ol.control.ScaleLine.prototype.unByKey); -goog.exportSymbol( - 'olcs.core.applyHeightOffsetToGeometry', - olcs.core.applyHeightOffsetToGeometry); +goog.exportProperty( + ol.control.Zoom.prototype, + 'getMap', + ol.control.Zoom.prototype.getMap); -goog.exportSymbol( - 'olcs.core.rotateAroundAxis', - olcs.core.rotateAroundAxis); +goog.exportProperty( + ol.control.Zoom.prototype, + 'setMap', + ol.control.Zoom.prototype.setMap); -goog.exportSymbol( - 'olcs.core.setHeadingUsingBottomCenter', - olcs.core.setHeadingUsingBottomCenter); +goog.exportProperty( + ol.control.Zoom.prototype, + 'setTarget', + ol.control.Zoom.prototype.setTarget); -goog.exportSymbol( - 'olcs.core.pickOnTerrainOrEllipsoid', - olcs.core.pickOnTerrainOrEllipsoid); +goog.exportProperty( + ol.control.Zoom.prototype, + 'get', + ol.control.Zoom.prototype.get); -goog.exportSymbol( - 'olcs.core.pickBottomPoint', - olcs.core.pickBottomPoint); +goog.exportProperty( + ol.control.Zoom.prototype, + 'getKeys', + ol.control.Zoom.prototype.getKeys); -goog.exportSymbol( - 'olcs.core.pickCenterPoint', - olcs.core.pickCenterPoint); +goog.exportProperty( + ol.control.Zoom.prototype, + 'getProperties', + ol.control.Zoom.prototype.getProperties); -goog.exportSymbol( - 'olcs.core.computeSignedTiltAngleOnGlobe', - olcs.core.computeSignedTiltAngleOnGlobe); +goog.exportProperty( + ol.control.Zoom.prototype, + 'set', + ol.control.Zoom.prototype.set); -goog.exportSymbol( - 'olcs.core.computeAngleToZenith', - olcs.core.computeAngleToZenith); +goog.exportProperty( + ol.control.Zoom.prototype, + 'setProperties', + ol.control.Zoom.prototype.setProperties); -goog.exportSymbol( - 'olcs.core.lookAt', - olcs.core.lookAt); +goog.exportProperty( + ol.control.Zoom.prototype, + 'unset', + ol.control.Zoom.prototype.unset); -goog.exportSymbol( - 'olcs.core.extentToRectangle', - olcs.core.extentToRectangle); +goog.exportProperty( + ol.control.Zoom.prototype, + 'changed', + ol.control.Zoom.prototype.changed); -goog.exportSymbol( - 'olcs.core.tileLayerToImageryLayer', - olcs.core.tileLayerToImageryLayer); +goog.exportProperty( + ol.control.Zoom.prototype, + 'dispatchEvent', + ol.control.Zoom.prototype.dispatchEvent); -goog.exportSymbol( - 'olcs.core.updateCesiumLayerProperties', - olcs.core.updateCesiumLayerProperties); +goog.exportProperty( + ol.control.Zoom.prototype, + 'getRevision', + ol.control.Zoom.prototype.getRevision); -goog.exportSymbol( - 'olcs.core.ol4326CoordinateToCesiumCartesian', - olcs.core.ol4326CoordinateToCesiumCartesian); +goog.exportProperty( + ol.control.Zoom.prototype, + 'on', + ol.control.Zoom.prototype.on); -goog.exportSymbol( - 'olcs.core.ol4326CoordinateArrayToCsCartesians', - olcs.core.ol4326CoordinateArrayToCsCartesians); +goog.exportProperty( + ol.control.Zoom.prototype, + 'once', + ol.control.Zoom.prototype.once); -goog.exportSymbol( - 'olcs.core.olGeometryCloneTo4326', - olcs.core.olGeometryCloneTo4326); +goog.exportProperty( + ol.control.Zoom.prototype, + 'un', + ol.control.Zoom.prototype.un); -goog.exportSymbol( - 'olcs.core.convertColorToCesium', - olcs.core.convertColorToCesium); +goog.exportProperty( + ol.control.Zoom.prototype, + 'unByKey', + ol.control.Zoom.prototype.unByKey); -goog.exportSymbol( - 'olcs.DragBox', - olcs.DragBox); +goog.exportProperty( + ol.control.ZoomSlider.prototype, + 'getMap', + ol.control.ZoomSlider.prototype.getMap); goog.exportProperty( - olcs.DragBox.prototype, - 'setScene', - olcs.DragBox.prototype.setScene); + ol.control.ZoomSlider.prototype, + 'setMap', + ol.control.ZoomSlider.prototype.setMap); goog.exportProperty( - olcs.DragBox.prototype, - 'listen', - olcs.DragBox.prototype.listen); + ol.control.ZoomSlider.prototype, + 'setTarget', + ol.control.ZoomSlider.prototype.setTarget); -goog.exportSymbol( - 'olcs.FeatureConverter', - olcs.FeatureConverter); +goog.exportProperty( + ol.control.ZoomSlider.prototype, + 'get', + ol.control.ZoomSlider.prototype.get); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'csAddBillboard', - olcs.FeatureConverter.prototype.csAddBillboard); + ol.control.ZoomSlider.prototype, + 'getKeys', + ol.control.ZoomSlider.prototype.getKeys); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olCircleGeometryToCesium', - olcs.FeatureConverter.prototype.olCircleGeometryToCesium); + ol.control.ZoomSlider.prototype, + 'getProperties', + ol.control.ZoomSlider.prototype.getProperties); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olLineStringGeometryToCesium', - olcs.FeatureConverter.prototype.olLineStringGeometryToCesium); + ol.control.ZoomSlider.prototype, + 'set', + ol.control.ZoomSlider.prototype.set); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olPolygonGeometryToCesium', - olcs.FeatureConverter.prototype.olPolygonGeometryToCesium); + ol.control.ZoomSlider.prototype, + 'setProperties', + ol.control.ZoomSlider.prototype.setProperties); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'getHeightReference', - olcs.FeatureConverter.prototype.getHeightReference); + ol.control.ZoomSlider.prototype, + 'unset', + ol.control.ZoomSlider.prototype.unset); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olPointGeometryToCesium', - olcs.FeatureConverter.prototype.olPointGeometryToCesium); + ol.control.ZoomSlider.prototype, + 'changed', + ol.control.ZoomSlider.prototype.changed); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olMultiGeometryToCesium', - olcs.FeatureConverter.prototype.olMultiGeometryToCesium); + ol.control.ZoomSlider.prototype, + 'dispatchEvent', + ol.control.ZoomSlider.prototype.dispatchEvent); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olGeometry4326TextPartToCesium', - olcs.FeatureConverter.prototype.olGeometry4326TextPartToCesium); + ol.control.ZoomSlider.prototype, + 'getRevision', + ol.control.ZoomSlider.prototype.getRevision); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olStyleToCesium', - olcs.FeatureConverter.prototype.olStyleToCesium); + ol.control.ZoomSlider.prototype, + 'on', + ol.control.ZoomSlider.prototype.on); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'computePlainStyle', - olcs.FeatureConverter.prototype.computePlainStyle); + ol.control.ZoomSlider.prototype, + 'once', + ol.control.ZoomSlider.prototype.once); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olFeatureToCesium', - olcs.FeatureConverter.prototype.olFeatureToCesium); + ol.control.ZoomSlider.prototype, + 'un', + ol.control.ZoomSlider.prototype.un); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'olVectorLayerToCesium', - olcs.FeatureConverter.prototype.olVectorLayerToCesium); + ol.control.ZoomSlider.prototype, + 'unByKey', + ol.control.ZoomSlider.prototype.unByKey); goog.exportProperty( - olcs.FeatureConverter.prototype, - 'convert', - olcs.FeatureConverter.prototype.convert); + ol.control.ZoomToExtent.prototype, + 'getMap', + ol.control.ZoomToExtent.prototype.getMap); -goog.exportSymbol( - 'olcs.OLCesium', - olcs.OLCesium); +goog.exportProperty( + ol.control.ZoomToExtent.prototype, + 'setMap', + ol.control.ZoomToExtent.prototype.setMap); goog.exportProperty( - olcs.OLCesium.prototype, - 'getCamera', - olcs.OLCesium.prototype.getCamera); + ol.control.ZoomToExtent.prototype, + 'setTarget', + ol.control.ZoomToExtent.prototype.setTarget); goog.exportProperty( - olcs.OLCesium.prototype, - 'getOlMap', - olcs.OLCesium.prototype.getOlMap); + ol.control.ZoomToExtent.prototype, + 'get', + ol.control.ZoomToExtent.prototype.get); goog.exportProperty( - olcs.OLCesium.prototype, - 'getCesiumScene', - olcs.OLCesium.prototype.getCesiumScene); + ol.control.ZoomToExtent.prototype, + 'getKeys', + ol.control.ZoomToExtent.prototype.getKeys); goog.exportProperty( - olcs.OLCesium.prototype, - 'getDataSources', - olcs.OLCesium.prototype.getDataSources); + ol.control.ZoomToExtent.prototype, + 'getProperties', + ol.control.ZoomToExtent.prototype.getProperties); goog.exportProperty( - olcs.OLCesium.prototype, - 'getEnabled', - olcs.OLCesium.prototype.getEnabled); + ol.control.ZoomToExtent.prototype, + 'set', + ol.control.ZoomToExtent.prototype.set); goog.exportProperty( - olcs.OLCesium.prototype, - 'setEnabled', - olcs.OLCesium.prototype.setEnabled); + ol.control.ZoomToExtent.prototype, + 'setProperties', + ol.control.ZoomToExtent.prototype.setProperties); goog.exportProperty( - olcs.OLCesium.prototype, - 'warmUp', - olcs.OLCesium.prototype.warmUp); + ol.control.ZoomToExtent.prototype, + 'unset', + ol.control.ZoomToExtent.prototype.unset); goog.exportProperty( - olcs.OLCesium.prototype, - 'setBlockCesiumRendering', - olcs.OLCesium.prototype.setBlockCesiumRendering); + ol.control.ZoomToExtent.prototype, + 'changed', + ol.control.ZoomToExtent.prototype.changed); goog.exportProperty( - olcs.OLCesium.prototype, - 'enableAutoRenderLoop', - olcs.OLCesium.prototype.enableAutoRenderLoop); + ol.control.ZoomToExtent.prototype, + 'dispatchEvent', + ol.control.ZoomToExtent.prototype.dispatchEvent); goog.exportProperty( - olcs.OLCesium.prototype, - 'getAutoRenderLoop', - olcs.OLCesium.prototype.getAutoRenderLoop); + ol.control.ZoomToExtent.prototype, + 'getRevision', + ol.control.ZoomToExtent.prototype.getRevision); goog.exportProperty( - olcs.OLCesium.prototype, - 'setResolutionScale', - olcs.OLCesium.prototype.setResolutionScale); + ol.control.ZoomToExtent.prototype, + 'on', + ol.control.ZoomToExtent.prototype.on); -goog.exportSymbol( - 'olcs.RasterSynchronizer', - olcs.RasterSynchronizer); +goog.exportProperty( + ol.control.ZoomToExtent.prototype, + 'once', + ol.control.ZoomToExtent.prototype.once); -goog.exportSymbol( - 'olcs.VectorSynchronizer', - olcs.VectorSynchronizer); +goog.exportProperty( + ol.control.ZoomToExtent.prototype, + 'un', + ol.control.ZoomToExtent.prototype.un); -goog.exportSymbol( - 'ga.GaRasterSynchronizer', - ga.GaRasterSynchronizer); +goog.exportProperty( + ol.control.ZoomToExtent.prototype, + 'unByKey', + ol.control.ZoomToExtent.prototype.unByKey); diff --git a/src/lib/ol3cesium.js b/src/lib/ol3cesium.js index 4f46c887e7..62a841c892 100644 --- a/src/lib/ol3cesium.js +++ b/src/lib/ol3cesium.js @@ -1,567 +1,674 @@ -/** - * Cesium - https://github.com/AnalyticalGraphicsInc/cesium - * - * Copyright 2011-2015 Cesium Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Columbus View (Pat. Pend.) - * - * Portions licensed separately. - * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details. - */ -/** - * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: http://github.com/jrburke/almond for details - */ - -/** - @license - when.js - https://github.com/cujojs/when - - MIT License (c) copyright B Cavalier & J Hann - - * A lightweight CommonJS Promises/A and when() implementation - * when is part of the cujo.js family of libraries (http://cujojs.com/) - * - * Licensed under the MIT License at: - * http://www.opensource.org/licenses/mit-license.php - * - * @version 1.7.1 - */ - -/** -@license -mersenne-twister.js - https://gist.github.com/banksean/300494 - - Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The names of its contributors may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @license - * - * Grauw URI utilities - * - * See: http://hg.grauw.nl/grauw-lib/file/tip/src/uri.js - * - * @author Laurens Holst (http://www.grauw.nl/) - * - * Copyright 2012 Laurens Holst - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** -@license -sprintf.js from the php.js project - https://github.com/kvz/phpjs -Directly from https://github.com/kvz/phpjs/blob/master/functions/strings/sprintf.js - -php.js is copyright 2012 Kevin van Zonneveld. - -Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld -(http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White -(http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jack, Jonas -Raoni Soares Silva (http://www.jsfromhell.com), Philip Peterson, Legaev -Andrey, Ates Goral (http://magnetiq.com), Alex, Ratheous, Martijn Wieringa, -Rafa? Kukawski (http://blog.kukawski.pl), lmeyrick -(https://sourceforge.net/projects/bcmath-js/), Nate, Philippe Baumann, -Enrique Gonzalez, Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. -L. Rodrigues (http://www.jsfromhell.com), Ash Searle -(http://hexmen.com/blog/), Jani Hartikainen, travc, Ole Vrijenhoek, -Erkekjetter, Michael Grier, Rafa? Kukawski (http://kukawski.pl), Johnny -Mast (http://www.phpvrouwen.nl), T.Wild, d3x, -http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript, -Rafa? Kukawski (http://blog.kukawski.pl/), stag019, pilus, WebDevHobo -(http://webdevhobo.blogspot.com/), marrtins, GeekFG -(http://geekfg.blogspot.com), Andrea Giammarchi -(http://webreflection.blogspot.com), Arpad Ray (mailto:arpad@php.net), -gorthaur, Paul Smith, Tim de Koning (http://www.kingsquare.nl), Joris, Oleg -Eremeev, Steve Hilder, majak, gettimeofday, KELAN, Josh Fraser -(http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/), -Marc Palau, Martin -(http://www.erlenwiese.de/), Breaking Par Consulting Inc -(http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7), -Chris, Mirek Slugen, saulius, Alfonso Jimenez -(http://www.alfonsojimenez.com), Diplom@t (http://difane.com/), felix, -Mailfaker (http://www.weedem.fr/), Tyler Akins (http://rumkin.com), Caio -Ariede (http://caioariede.com), Robin, Kankrelune -(http://www.webfaktory.info/), Karol Kowalski, Imgen Tata -(http://www.myipdf.com/), mdsjack (http://www.mdsjack.bo.it), Dreamer, -Felix Geisendoerfer (http://www.debuggable.com/felix), Lars Fischer, AJ, -David, Aman Gupta, Michael White, Public Domain -(http://www.json.org/json2.js), Steven Levithan -(http://blog.stevenlevithan.com), Sakimori, Pellentesque Malesuada, -Thunder.m, Dj (http://phpjs.org/functions/htmlentities:425#comment_134018), -Steve Clay, David James, Francois, class_exists, nobbler, T. Wild, Itsacon -(http://www.itsacon.net/), date, Ole Vrijenhoek (http://www.nervous.nl/), -Fox, Raphael (Ao RUDLER), Marco, noname, Mateusz "loonquawl" Zalega, Frank -Forte, Arno, ger, mktime, john (http://www.jd-tech.net), Nick Kolosov -(http://sammy.ru), marc andreu, Scott Cariss, Douglas Crockford -(http://javascript.crockford.com), madipta, Slawomir Kaniecki, -ReverseSyntax, Nathan, Alex Wilson, kenneth, Bayron Guevara, Adam Wallner -(http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix, -Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick -(https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan, -Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H?gfeldt -(http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb, -josh, jd, Pier Paolo Ramon (http://www.mastersoup.com/), P, merabi, Soren -Hansen, Eugene Bulkin (http://doubleaw.com/), Der Simon -(http://innerdom.sourceforge.net/), echo is bad, Ozh, XoraX -(http://www.xorax.info), EdorFaus, JB, J A R, Marc Jansen, Francesco, LH, -Stoyan Kyosev (http://www.svest.org/), nord_ua, omid -(http://phpjs.org/functions/380:380#comment_137122), Brad Touesnard, MeEtc -(http://yass.meetcweb.com), Peter-Paul Koch -(http://www.quirksmode.org/js/beat.html), Olivier Louvignes -(http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, Jalal Berrami, -Martin, JT, David Randall, Thomas Beaucourt (http://www.webapp.fr), taith, -vlado houba, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair -Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger -(http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner -B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong -(http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna, -Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni, -Marco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke -(http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski, -Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke -Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet, -sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen, -Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya -(http://www.premasolutions.com/), Philippe Jausions -(http://pear.php.net/user/jausions), Aidan Lister -(http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp, -strcmp, Taras Bogach, jpfle, Alexander Ermolaev -(http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando, -dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha -(http://www.pedrotainha.com), James, Arnout Kazemier -(http://www.3rd-Eden.com), Chris McMacken, gabriel paderni, Yannoo, -FGFEmperor, baris ozdil, Tod Gentille, Greg Frazier, jakes, 3D-GRAF, Allan -Jensen (http://www.winternet.no), Howard Yeend, Benjamin Lupton, davook, -daniel airton wermann (http://wermann.com.br), Atli T¨®r, Maximusya, Ryan -W Tenney (http://ryan.10e.us), Alexander M Beedie, fearphage -(http://http/my.opera.com/fearphage/), Nathan Sepulveda, Victor, Matteo, -Billy, stensi, Cord, Manish, T.J. Leahy, Riddler -(http://www.frontierwebdev.com/), Rafa? Kukawski, FremyCompany, Matt -Bradley, Tim de Koning, Luis Salazar (http://www.freaky-media.com/), Diogo -Resende, Rival, Andrej Pavlovic, Garagoth, Le Torbi -(http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem, -Russell Walker (http://www.nbill.co.uk/), Jamie Beck -(http://www.terabit.ca/), setcookie, Michael, YUI Library: -http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at -http://hacks.bluesmoon.info/strftime/strftime.js, Ben -(http://benblume.co.uk/), DtTvB -(http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William, -meo, incidence, Cagri Ekin, Amirouche, Amir Habibi -(http://www.residence-mixte.com/), Luke Smith (http://lucassmith.name), -Kheang Hok Chin (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani, -Tony, Yen-Wei Liu, Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben -Bryan - -Licensed under the MIT (MIT-LICENSE.txt) license. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES -OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -*/ - -// Copyright 2012 Google Inc., Apache 2.0 license. - -/** -@license -tween.js - https://github.com/sole/tween.js - -Copyright (c) 2010-2012 Tween.js authors. - -Easing equations Copyright (c) 2001 Robert Penner http://robertpenner.com/easing/ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/** - @license - fontmetrics.js - https://github.com/Pomax/fontmetrics.js - - Copyright (C) 2011 by Mike "Pomax" Kamermans - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -**/ - -/** -@license -topojson - https://github.com/mbostock/topojson - -Copyright (c) 2012, Michael Bostock -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* The name Michael Bostock may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/*! - * Autolinker.js - * 0.17.1 - * - * Copyright(c) 2015 Gregory Jacobs <greg@greg-jacobs.com> - * MIT Licensed. http://www.opensource.org/licenses/mit-license.php - * - * https://github.com/gregjacobs/Autolinker.js - */ - -/** -@license - Copyright (c) 2013 Gildas Lormeau. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, - INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**/ - -/** - * @license - * Copyright (c) 2011 NVIDIA Corporation. All rights reserved. - * - * TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED - * *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS - * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA - * OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS - * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY - * OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, - * EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -/** - * @license - * Copyright (c) 2000-2005, Sean O'Neil (s_p_oneil@hotmail.com) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Modifications made by Analytical Graphics, Inc. - */ - -/** - * @license - * Knockout JavaScript library v3.2.0 - * (c) Steven Sanderson - http://knockoutjs.com/ - * License: MIT (http://www.opensource.org/licenses/mit-license.php) - */ - -/** - * @license - * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5 - * Copyright (c) Steve Sanderson - * MIT license - */ - -!function(){var e,t,r;!function(i){function n(e,t){return C.call(e,t)}function o(e,t){var r,i,n,o,a,s,l,u,c,h,d,p=t&&t.split("/"),m=g.map,f=m&&m["*"]||{};if(e&&"."===e.charAt(0))if(t){for(e=e.split("/"),a=e.length-1,g.nodeIdCompat&&S.test(e[a])&&(e[a]=e[a].replace(S,"")),e=p.slice(0,p.length-1).concat(e),c=0;c<e.length;c+=1)if(d=e[c],"."===d)e.splice(c,1),c-=1;else if(".."===d){if(1===c&&(".."===e[2]||".."===e[0]))break;c>0&&(e.splice(c-1,2),c-=2)}e=e.join("/")}else 0===e.indexOf("./")&&(e=e.substring(2));if((p||f)&&m){for(r=e.split("/"),c=r.length;c>0;c-=1){if(i=r.slice(0,c).join("/"),p)for(h=p.length;h>0;h-=1)if(n=m[p.slice(0,h).join("/")],n&&(n=n[i])){o=n,s=c;break}if(o)break;!l&&f&&f[i]&&(l=f[i],u=c)}!o&&l&&(o=l,s=u),o&&(r.splice(0,s,o),e=r.join("/"))}return e}function a(e,t){return function(){var r=E.call(arguments,0);return"string"!=typeof r[0]&&1===r.length&&r.push(null),p.apply(i,r.concat([e,t]))}}function s(e){return function(t){return o(t,e)}}function l(e){return function(t){v[e]=t}}function u(e){if(n(_,e)){var t=_[e];delete _[e],y[e]=!0,d.apply(i,t)}if(!n(v,e)&&!n(y,e))throw new Error("No "+e);return v[e]}function c(e){var t,r=e?e.indexOf("!"):-1;return r>-1&&(t=e.substring(0,r),e=e.substring(r+1,e.length)),[t,e]}function h(e){return function(){return g&&g.config&&g.config[e]||{}}}var d,p,m,f,v={},_={},g={},y={},C=Object.prototype.hasOwnProperty,E=[].slice,S=/\.js$/;m=function(e,t){var r,i=c(e),n=i[0];return e=i[1],n&&(n=o(n,t),r=u(n)),n?e=r&&r.normalize?r.normalize(e,s(t)):o(e,t):(e=o(e,t),i=c(e),n=i[0],e=i[1],n&&(r=u(n))),{f:n?n+"!"+e:e,n:e,pr:n,p:r}},f={require:function(e){return a(e)},exports:function(e){var t=v[e];return"undefined"!=typeof t?t:v[e]={}},module:function(e){return{id:e,uri:"",exports:v[e],config:h(e)}}},d=function(e,t,r,o){var s,c,h,d,p,g,C=[],E=typeof r;if(o=o||e,"undefined"===E||"function"===E){for(t=!t.length&&r.length?["require","exports","module"]:t,p=0;p<t.length;p+=1)if(d=m(t[p],o),c=d.f,"require"===c)C[p]=f.require(e);else if("exports"===c)C[p]=f.exports(e),g=!0;else if("module"===c)s=C[p]=f.module(e);else if(n(v,c)||n(_,c)||n(y,c))C[p]=u(c);else{if(!d.p)throw new Error(e+" missing "+c);d.p.load(d.n,a(o,!0),l(c),{}),C[p]=v[c]}h=r?r.apply(v[e],C):void 0,e&&(s&&s.exports!==i&&s.exports!==v[e]?v[e]=s.exports:h===i&&g||(v[e]=h))}else e&&(v[e]=r)},e=t=p=function(e,t,r,n,o){if("string"==typeof e)return f[e]?f[e](t):u(m(e,t).f);if(!e.splice){if(g=e,g.deps&&p(g.deps,g.callback),!t)return;t.splice?(e=t,t=r,r=null):e=i}return t=t||function(){},"function"==typeof r&&(r=n,n=o),n?d(i,e,t,r):setTimeout(function(){d(i,e,t,r)},4),p},p.config=function(e){return p(e)},e._defined=v,r=function(e,t,r){if("string"!=typeof e)throw new Error("See almond README: incorrect module build, no module name");t.splice||(r=t,t=[]),n(v,e)||n(_,e)||(_[e]=[e,t,r])},r.amd={jQuery:!0}}(),function(e){"use strict";e("ThirdParty/when",[],function(){function e(e,r,i,n){return t(e).then(r,i,n)}function t(e){var t,r;return e instanceof i?t=e:s(e)?(r=a(),e.then(function(e){r.resolve(e)},function(e){r.reject(e)},function(e){r.progress(e)}),t=r.promise):t=n(e),t}function r(t){return e(t,o)}function i(e){this.then=e}function n(e){var r=new i(function(r){try{return t(r?r(e):e)}catch(i){return o(i)}});return r}function o(e){var r=new i(function(r,i){try{return i?t(i(e)):o(e)}catch(n){return o(n)}});return r}function a(){function e(e,t,r){return d(e,t,r)}function r(e){return m(e)}function n(e){return m(o(e))}function s(e){return p(e)}var l,u,c,h,d,p,m;return u=new i(e),l={then:e,resolve:r,reject:n,progress:s,promise:u,resolver:{resolve:r,reject:n,progress:s}},c=[],h=[],d=function(e,t,r){var i,n;return i=a(),n="function"==typeof r?function(e){try{i.progress(r(e))}catch(t){i.progress(t)}}:function(e){i.progress(e)},c.push(function(r){r.then(e,t).then(i.resolve,i.reject,n)}),h.push(n),i.promise},p=function(e){return f(h,e),e},m=function(e){return e=t(e),d=e.then,m=t,p=_,f(c,e),h=c=E,e},l}function s(e){return e&&"function"==typeof e.then}function l(t,r,i,n,o){return v(2,arguments),e(t,function(t){function s(e){f(e)}function l(e){m(e)}var u,c,h,d,p,m,f,v,g,y;if(g=t.length>>>0,u=Math.max(0,Math.min(r,g)),h=[],c=g-u+1,d=[],p=a(),u)for(v=p.progress,f=function(e){d.push(e),--c||(m=f=_,p.reject(d))},m=function(e){h.push(e),--u||(m=f=_,p.resolve(h))},y=0;g>y;++y)y in t&&e(t[y],l,s,v);else p.resolve(h);return p.then(i,n,o)})}function u(e,t,r,i){function n(e){return t?t(e[0]):e[0]}return l(e,1,n,r,i)}function c(e,t,r,i){return v(1,arguments),d(e,g).then(t,r,i)}function h(){return d(arguments,g)}function d(t,r){return e(t,function(t){var i,n,o,s,l,u;if(o=n=t.length>>>0,i=[],u=a(),o)for(s=function(t,n){e(t,r).then(function(e){i[n]=e,--o||u.resolve(i)},u.reject)},l=0;n>l;l++)l in t?s(t[l],l):--o;else u.resolve(i);return u.promise})}function p(t,r){var i=C.call(arguments,1);return e(t,function(t){var n;return n=t.length,i[0]=function(t,i,o){return e(t,function(t){return e(i,function(e){return r(t,e,o,n)})})},y.apply(t,i)})}function m(t,r,i){var n=arguments.length>2;return e(t,function(e){return e=n?i:e,r.resolve(e),e},function(e){return r.reject(e),o(e)},r.progress)}function f(e,t){for(var r,i=0;r=e[i++];)r(t)}function v(e,t){for(var r,i=t.length;i>e;)if(r=t[--i],null!=r&&"function"!=typeof r)throw new Error("arg "+i+" must be a function")}function _(){}function g(e){return e}var y,C,E;return e.defer=a,e.resolve=t,e.reject=r,e.join=h,e.all=c,e.map=d,e.reduce=p,e.any=u,e.some=l,e.chain=m,e.isPromise=s,i.prototype={always:function(e,t){return this.then(e,e,t)},otherwise:function(e){return this.then(E,e)},"yield":function(e){return this.then(function(){return e})},spread:function(e){return this.then(function(t){return c(t,function(t){return e.apply(E,t)})})}},C=[].slice,y=[].reduce||function(e){var t,r,i,n,o;if(o=0,t=Object(this),n=t.length>>>0,r=arguments,r.length<=1)for(;;){if(o in t){i=t[o++];break}if(++o>=n)throw new TypeError}else i=r[1];for(;n>o;++o)o in t&&(i=e(i,t[o],o,t));return i},e})}("function"==typeof r&&r.amd?r:function(e){"object"==typeof exports?module.exports=e():this.when=e()}),r("Core/defined",[],function(){"use strict";var e=function(e){return void 0!==e};return e}),r("Core/defineProperties",["./defined"],function(e){"use strict";var t=function(){try{return"x"in Object.defineProperty({},"x",{})}catch(e){return!1}}(),r=Object.defineProperties;return t&&e(r)||(r=function(e){return e}),r}),r("Core/DeveloperError",["./defined"],function(e){"use strict";var t=function(e){this.name="DeveloperError",this.message=e;var t;try{throw new Error}catch(r){t=r.stack}this.stack=t};return t.prototype.toString=function(){var t=this.name+": "+this.message;return e(this.stack)&&(t+="\n"+this.stack.toString()),t},t.throwInstantiationError=function(){throw new t("This function defines an interface and should not be called directly.")},t}),r("Core/Credit",["./defined","./defineProperties","./DeveloperError"],function(e,t,r){"use strict";var i=0,n={},o=function(t,r,o){var a=e(o),s=e(r),l=e(t);l||s||(t=o),this._text=t,this._imageUrl=r,this._link=o,this._hasLink=a,this._hasImage=s;var u,c=JSON.stringify([t,r,o]);e(n[c])?u=n[c]:(u=i++,n[c]=u),this._id=u};return t(o.prototype,{text:{get:function(){return this._text}},imageUrl:{get:function(){return this._imageUrl}},link:{get:function(){return this._link}},id:{get:function(){return this._id}}}),o.prototype.hasImage=function(){return this._hasImage},o.prototype.hasLink=function(){return this._hasLink},o.equals=function(t,r){return t===r||e(t)&&e(r)&&t._id===r._id},o.prototype.equals=function(e){return o.equals(this,e)},o}),r("Core/freezeObject",["./defined"],function(e){"use strict";var t=Object.freeze;return e(t)||(t=function(e){return e}),t}),r("Core/defaultValue",["./freezeObject"],function(e){"use strict";var t=function(e,t){return void 0!==e?e:t};return t.EMPTY_OBJECT=e({}),t}),r("ThirdParty/mersenne-twister",[],function(){var e=function(e){void 0==e&&(e=(new Date).getTime()),this.N=624,this.M=397,this.MATRIX_A=2567483615,this.UPPER_MASK=2147483648,this.LOWER_MASK=2147483647,this.mt=new Array(this.N),this.mti=this.N+1,this.init_genrand(e)};return e.prototype.init_genrand=function(e){for(this.mt[0]=e>>>0,this.mti=1;this.mti<this.N;this.mti++){var e=this.mt[this.mti-1]^this.mt[this.mti-1]>>>30;this.mt[this.mti]=(1812433253*((4294901760&e)>>>16)<<16)+1812433253*(65535&e)+this.mti,this.mt[this.mti]>>>=0}},e.prototype.genrand_int32=function(){var e,t=new Array(0,this.MATRIX_A);if(this.mti>=this.N){var r;for(this.mti==this.N+1&&this.init_genrand(5489),r=0;r<this.N-this.M;r++)e=this.mt[r]&this.UPPER_MASK|this.mt[r+1]&this.LOWER_MASK,this.mt[r]=this.mt[r+this.M]^e>>>1^t[1&e];for(;r<this.N-1;r++)e=this.mt[r]&this.UPPER_MASK|this.mt[r+1]&this.LOWER_MASK,this.mt[r]=this.mt[r+(this.M-this.N)]^e>>>1^t[1&e];e=this.mt[this.N-1]&this.UPPER_MASK|this.mt[0]&this.LOWER_MASK,this.mt[this.N-1]=this.mt[this.M-1]^e>>>1^t[1&e],this.mti=0}return e=this.mt[this.mti++],e^=e>>>11,e^=e<<7&2636928640,e^=e<<15&4022730752,e^=e>>>18,e>>>0},e.prototype.random=function(){return this.genrand_int32()*(1/4294967296)},e}),r("Core/Math",["../ThirdParty/mersenne-twister","./defaultValue","./defined","./DeveloperError"],function(e,t,r,i){"use strict";var n={};n.EPSILON1=.1,n.EPSILON2=.01,n.EPSILON3=.001,n.EPSILON4=1e-4,n.EPSILON5=1e-5,n.EPSILON6=1e-6,n.EPSILON7=1e-7,n.EPSILON8=1e-8,n.EPSILON9=1e-9,n.EPSILON10=1e-10,n.EPSILON11=1e-11,n.EPSILON12=1e-12,n.EPSILON13=1e-13,n.EPSILON14=1e-14,n.EPSILON15=1e-15,n.EPSILON16=1e-16,n.EPSILON17=1e-17,n.EPSILON18=1e-18,n.EPSILON19=1e-19,n.EPSILON20=1e-20,n.GRAVITATIONALPARAMETER=3986004418e5,n.SOLAR_RADIUS=6955e5,n.LUNAR_RADIUS=1737400,n.SIXTY_FOUR_KILOBYTES=65536,n.sign=function(e){return e>0?1:0>e?-1:0},n.signNotZero=function(e){return 0>e?-1:1},n.toSNorm=function(e){return Math.round(255*(.5*n.clamp(e,-1,1)+.5))},n.fromSNorm=function(e){return n.clamp(e,0,255)/255*2-1},n.sinh=function(e){var t=Math.pow(Math.E,e),r=Math.pow(Math.E,-1*e);return.5*(t-r)},n.cosh=function(e){var t=Math.pow(Math.E,e),r=Math.pow(Math.E,-1*e);return.5*(t+r)},n.lerp=function(e,t,r){return(1-r)*e+r*t},n.PI=Math.PI,n.ONE_OVER_PI=1/Math.PI,n.PI_OVER_TWO=.5*Math.PI,n.PI_OVER_THREE=Math.PI/3,n.PI_OVER_FOUR=Math.PI/4,n.PI_OVER_SIX=Math.PI/6,n.THREE_PI_OVER_TWO=3*Math.PI*.5,n.TWO_PI=2*Math.PI,n.ONE_OVER_TWO_PI=1/(2*Math.PI),n.RADIANS_PER_DEGREE=Math.PI/180,n.DEGREES_PER_RADIAN=180/Math.PI,n.RADIANS_PER_ARCSECOND=n.RADIANS_PER_DEGREE/3600,n.toRadians=function(e){return e*n.RADIANS_PER_DEGREE},n.toDegrees=function(e){return e*n.DEGREES_PER_RADIAN},n.convertLongitudeRange=function(e){var t=n.TWO_PI,r=e-Math.floor(e/t)*t;return r<-Math.PI?r+t:r>=Math.PI?r-t:r},n.negativePiToPi=function(e){return n.zeroToTwoPi(e+n.PI)-n.PI},n.zeroToTwoPi=function(e){var t=n.mod(e,n.TWO_PI);return Math.abs(t)<n.EPSILON14&&Math.abs(e)>n.EPSILON14?n.TWO_PI:t},n.mod=function(e,t){return(e%t+t)%t},n.equalsEpsilon=function(e,r,i,n){n=t(n,i);var o=Math.abs(e-r);return n>=o||o<=i*Math.max(Math.abs(e),Math.abs(r))};var o=[1];n.factorial=function(e){var t=o.length;if(e>=t)for(var r=o[t-1],i=t;e>=i;i++)o.push(r*i);return o[e]},n.incrementWrap=function(e,r,i){return i=t(i,0),++e,e>r&&(e=i),e},n.isPowerOfTwo=function(e){return 0!==e&&0===(e&e-1)},n.nextPowerOfTwo=function(e){return--e,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e,e},n.clamp=function(e,t,r){return t>e?t:e>r?r:e};var a=new e;return n.setRandomNumberSeed=function(t){a=new e(t)},n.nextRandomNumber=function(){return a.random()},n.acosClamped=function(e){return Math.acos(n.clamp(e,-1,1))},n.asinClamped=function(e){return Math.asin(n.clamp(e,-1,1))},n.chordLength=function(e,t){return 2*t*Math.sin(.5*e)},n.fog=function(e,t){var r=e*t;return 1-Math.exp(-(r*r))},n}),r("Core/Cartesian3",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r,i){this.x=e(t,0),this.y=e(r,0),this.z=e(i,0)};o.fromSpherical=function(r,i){t(i)||(i=new o);var n=r.clock,a=r.cone,s=e(r.magnitude,1),l=s*Math.sin(a);return i.x=l*Math.cos(n),i.y=l*Math.sin(n),i.z=s*Math.cos(a),i},o.fromElements=function(e,r,i,n){return t(n)?(n.x=e,n.y=r,n.z=i,n):new o(e,r,i)},o.clone=function(e,r){return t(e)?t(r)?(r.x=e.x,r.y=e.y,r.z=e.z,r):new o(e.x,e.y,e.z):void 0},o.fromCartesian4=o.clone,o.packedLength=3,o.pack=function(t,r,i){i=e(i,0),r[i++]=t.x,r[i++]=t.y,r[i]=t.z},o.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new o),n.x=r[i++],n.y=r[i++],n.z=r[i],n},o.fromArray=o.unpack,o.maximumComponent=function(e){return Math.max(e.x,e.y,e.z)},o.minimumComponent=function(e){return Math.min(e.x,e.y,e.z)},o.minimumByComponent=function(e,t,r){return r.x=Math.min(e.x,t.x),r.y=Math.min(e.y,t.y),r.z=Math.min(e.z,t.z),r},o.maximumByComponent=function(e,t,r){return r.x=Math.max(e.x,t.x),r.y=Math.max(e.y,t.y),r.z=Math.max(e.z,t.z),r},o.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y+e.z*e.z},o.magnitude=function(e){return Math.sqrt(o.magnitudeSquared(e))};var a=new o;o.distance=function(e,t){return o.subtract(e,t,a),o.magnitude(a)},o.distanceSquared=function(e,t){return o.subtract(e,t,a),o.magnitudeSquared(a)},o.normalize=function(e,t){var r=o.magnitude(e);return t.x=e.x/r,t.y=e.y/r,t.z=e.z/r,t},o.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z},o.multiplyComponents=function(e,t,r){return r.x=e.x*t.x,r.y=e.y*t.y,r.z=e.z*t.z,r},o.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r.z=e.z+t.z,r},o.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r.z=e.z-t.z,r},o.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r.z=e.z*t,r},o.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r.z=e.z/t,r},o.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t},o.abs=function(e,t){return t.x=Math.abs(e.x),t.y=Math.abs(e.y),t.z=Math.abs(e.z),t};var s=new o;o.lerp=function(e,t,r,i){return o.multiplyByScalar(t,r,s),i=o.multiplyByScalar(e,1-r,i),o.add(s,i,i)};var l=new o,u=new o;o.angleBetween=function(e,t){o.normalize(e,l),o.normalize(t,u);var r=o.dot(l,u),i=o.magnitude(o.cross(l,u,l));return Math.atan2(i,r)};var c=new o;o.mostOrthogonalAxis=function(e,t){var r=o.normalize(e,c);return o.abs(r,r),t=r.x<=r.y?r.x<=r.z?o.clone(o.UNIT_X,t):o.clone(o.UNIT_Z,t):r.y<=r.z?o.clone(o.UNIT_Y,t):o.clone(o.UNIT_Z,t)},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.x===r.x&&e.y===r.y&&e.z===r.z},o.equalsArray=function(e,t,r){return e.x===t[r]&&e.y===t[r+1]&&e.z===t[r+2]},o.equalsEpsilon=function(e,r,i,o){return e===r||t(e)&&t(r)&&n.equalsEpsilon(e.x,r.x,i,o)&&n.equalsEpsilon(e.y,r.y,i,o)&&n.equalsEpsilon(e.z,r.z,i,o)},o.cross=function(e,t,r){var i=e.x,n=e.y,o=e.z,a=t.x,s=t.y,l=t.z,u=n*l-o*s,c=o*a-i*l,h=i*s-n*a;return r.x=u,r.y=c,r.z=h,r},o.fromDegrees=function(e,t,r,i,a){var s=n.toRadians(e),l=n.toRadians(t);return o.fromRadians(s,l,r,i,a)};var h=new o,d=new o,p=new o(40680631590769,40680631590769,40408299984661.445);return o.fromRadians=function(r,i,n,a,s){n=e(n,0);var l=t(a)?a.radiiSquared:p,u=Math.cos(i);h.x=u*Math.cos(r),h.y=u*Math.sin(r),h.z=Math.sin(i),h=o.normalize(h,h),o.multiplyComponents(l,h,d);var c=Math.sqrt(o.dot(h,d));return d=o.divideByScalar(d,c,d),h=o.multiplyByScalar(h,n,h),t(s)||(s=new o),o.add(d,h,s)},o.fromDegreesArray=function(e,t,r){for(var i=new Array(e.length),a=0;a<e.length;a++)i[a]=n.toRadians(e[a]);return o.fromRadiansArray(i,t,r)},o.fromRadiansArray=function(e,r,i){var n=e.length;t(i)?i.length=n/2:i=new Array(n/2);for(var a=0;n>a;a+=2){var s=e[a],l=e[a+1];i[a/2]=o.fromRadians(s,l,0,r,i[a/2])}return i},o.fromDegreesArrayHeights=function(e,t,r){for(var i=new Array(e.length),a=0;a<e.length;a+=3)i[a]=n.toRadians(e[a]),i[a+1]=n.toRadians(e[a+1]),i[a+2]=e[a+2];return o.fromRadiansArrayHeights(i,t,r)},o.fromRadiansArrayHeights=function(e,r,i){var n=e.length;t(i)?i.length=n/3:i=new Array(n/3);for(var a=0;n>a;a+=3){var s=e[a],l=e[a+1],u=e[a+2];i[a/3]=o.fromRadians(s,l,u,r,i[a/3])}return i},o.ZERO=i(new o(0,0,0)),o.UNIT_X=i(new o(1,0,0)),o.UNIT_Y=i(new o(0,1,0)),o.UNIT_Z=i(new o(0,0,1)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t,r){return o.equalsEpsilon(this,e,t,r)},o.prototype.toString=function(){return"("+this.x+", "+this.y+", "+this.z+")"},o}),r("Core/Cartographic",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r,i){this.longitude=e(t,0),this.latitude=e(r,0),this.height=e(i,0)};return o.fromRadians=function(r,i,n,a){return n=e(n,0),t(a)?(a.longitude=r,a.latitude=i,a.height=n,a):new o(r,i,n)},o.fromDegrees=function(e,t,r,i){return e=n.toRadians(e),t=n.toRadians(t),o.fromRadians(e,t,r,i)},o.clone=function(e,r){return t(e)?t(r)?(r.longitude=e.longitude,r.latitude=e.latitude,r.height=e.height,r):new o(e.longitude,e.latitude,e.height):void 0},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.longitude===r.longitude&&e.latitude===r.latitude&&e.height===r.height},o.equalsEpsilon=function(e,r,i){return e===r||t(e)&&t(r)&&Math.abs(e.longitude-r.longitude)<=i&&Math.abs(e.latitude-r.latitude)<=i&&Math.abs(e.height-r.height)<=i},o.ZERO=i(new o(0,0,0)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t){return o.equalsEpsilon(this,e,t)},o.prototype.toString=function(){return"("+this.longitude+", "+this.latitude+", "+this.height+")"},o}),r("Core/Ellipsoid",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n,o,a,s){"use strict";function l(t,i,n,o){i=r(i,0),n=r(n,0),o=r(o,0),t._radii=new e(i,n,o),t._radiiSquared=new e(i*i,n*n,o*o),t._radiiToTheFourth=new e(i*i*i*i,n*n*n*n,o*o*o*o),t._oneOverRadii=new e(0===i?0:1/i,0===n?0:1/n,0===o?0:1/o),t._oneOverRadiiSquared=new e(0===i?0:1/(i*i),0===n?0:1/(n*n),0===o?0:1/(o*o)),t._minimumRadius=Math.min(i,n,o),t._maximumRadius=Math.max(i,n,o),t._centerToleranceSquared=s.EPSILON1}var u=function(e,t,r){this._radii=void 0,this._radiiSquared=void 0,this._radiiToTheFourth=void 0,this._oneOverRadii=void 0,this._oneOverRadiiSquared=void 0,this._minimumRadius=void 0,this._maximumRadius=void 0,this._centerToleranceSquared=void 0,l(this,e,t,r)};n(u.prototype,{radii:{get:function(){return this._radii}},radiiSquared:{get:function(){return this._radiiSquared}},radiiToTheFourth:{get:function(){return this._radiiToTheFourth}},oneOverRadii:{get:function(){return this._oneOverRadii}},oneOverRadiiSquared:{get:function(){return this._oneOverRadiiSquared}},minimumRadius:{get:function(){return this._minimumRadius}},maximumRadius:{get:function(){return this._maximumRadius}}}),u.clone=function(t,r){if(!i(t))return void 0;var n=t._radii;return i(r)?(e.clone(n,r._radii),e.clone(t._radiiSquared,r._radiiSquared),e.clone(t._radiiToTheFourth,r._radiiToTheFourth),e.clone(t._oneOverRadii,r._oneOverRadii),e.clone(t._oneOverRadiiSquared,r._oneOverRadiiSquared),r._minimumRadius=t._minimumRadius,r._maximumRadius=t._maximumRadius,r._centerToleranceSquared=t._centerToleranceSquared,r):new u(n.x,n.y,n.z)},u.fromCartesian3=function(e,t){return i(t)||(t=new u),i(e)?(l(t,e.x,e.y,e.z),t):t},u.WGS84=a(new u(6378137,6378137,6356752.314245179)),u.UNIT_SPHERE=a(new u(1,1,1)),u.MOON=a(new u(s.LUNAR_RADIUS,s.LUNAR_RADIUS,s.LUNAR_RADIUS)),u.prototype.clone=function(e){return u.clone(this,e)},u.packedLength=e.packedLength,u.pack=function(t,i,n){n=r(n,0),e.pack(t._radii,i,n)},u.unpack=function(t,i,n){i=r(i,0);var o=e.unpack(t,i);return u.fromCartesian3(o,n)},u.prototype.geocentricSurfaceNormal=e.normalize,u.prototype.geodeticSurfaceNormalCartographic=function(t,r){var n=t.longitude,o=t.latitude,a=Math.cos(o),s=a*Math.cos(n),l=a*Math.sin(n),u=Math.sin(o);return i(r)||(r=new e),r.x=s,r.y=l,r.z=u,e.normalize(r,r)},u.prototype.geodeticSurfaceNormal=function(t,r){return i(r)||(r=new e),r=e.multiplyComponents(t,this._oneOverRadiiSquared,r),e.normalize(r,r)};var c=new e,h=new e;u.prototype.cartographicToCartesian=function(t,r){var n=c,o=h;this.geodeticSurfaceNormalCartographic(t,n),e.multiplyComponents(this._radiiSquared,n,o);var a=Math.sqrt(e.dot(n,o));return e.divideByScalar(o,a,o),e.multiplyByScalar(n,t.height,n),i(r)||(r=new e),e.add(o,n,r)},u.prototype.cartographicArrayToCartesianArray=function(e,t){var r=e.length;i(t)?t.length=r:t=new Array(r);for(var n=0;r>n;n++)t[n]=this.cartographicToCartesian(e[n],t[n]);return t};var d=new e,p=new e,m=new e;u.prototype.cartesianToCartographic=function(r,n){var o=this.scaleToGeodeticSurface(r,p);if(!i(o))return void 0;var a=this.geodeticSurfaceNormal(o,d),l=e.subtract(r,o,m),u=Math.atan2(a.y,a.x),c=Math.asin(a.z),h=s.sign(e.dot(l,r))*e.magnitude(l);return i(n)?(n.longitude=u,n.latitude=c,n.height=h,n):new t(u,c,h)},u.prototype.cartesianArrayToCartographicArray=function(e,t){var r=e.length;i(t)?t.length=r:t=new Array(r);for(var n=0;r>n;++n)t[n]=this.cartesianToCartographic(e[n],t[n]);return t};var f=new e,v=new e;return u.prototype.scaleToGeodeticSurface=function(t,r){var n=t.x,o=t.y,a=t.z,l=this._oneOverRadii,u=l.x,c=l.y,h=l.z,d=n*n*u*u,p=o*o*c*c,m=a*a*h*h,_=d+p+m,g=Math.sqrt(1/_),y=e.multiplyByScalar(t,g,f);if(_<this._centerToleranceSquared)return isFinite(g)?e.clone(y,r):void 0;var C=this._oneOverRadiiSquared,E=C.x,S=C.y,w=C.z,T=v;T.x=y.x*E*2,T.y=y.y*S*2,T.z=y.z*w*2;var b,x,P,A,I,M,D,R,O,N,L,F=(1-g)*e.magnitude(t)/(.5*e.magnitude(T)),B=0;do{F-=B,P=1/(1+F*E),A=1/(1+F*S),I=1/(1+F*w),M=P*P,D=A*A,R=I*I,O=M*P,N=D*A,L=R*I,b=d*M+p*D+m*R-1,x=d*O*E+p*N*S+m*L*w;var V=-2*x;B=b/V}while(Math.abs(b)>s.EPSILON12);return i(r)?(r.x=n*P,r.y=o*A,r.z=a*I,r):new e(n*P,o*A,a*I)},u.prototype.scaleToGeocentricSurface=function(t,r){i(r)||(r=new e);var n=t.x,o=t.y,a=t.z,s=this._oneOverRadiiSquared,l=1/Math.sqrt(n*n*s.x+o*o*s.y+a*a*s.z);return e.multiplyByScalar(t,l,r)},u.prototype.transformPositionToScaledSpace=function(t,r){return i(r)||(r=new e),e.multiplyComponents(t,this._oneOverRadii,r)},u.prototype.transformPositionFromScaledSpace=function(t,r){return i(r)||(r=new e),e.multiplyComponents(t,this._radii,r)},u.prototype.equals=function(t){return this===t||i(t)&&e.equals(this._radii,t._radii)},u.prototype.toString=function(){return this._radii.toString()},u}),r("Core/Event",["./defined","./defineProperties","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this._listeners=[],this._scopes=[],this._toRemove=[],this._insideRaiseEvent=!1};return t(i.prototype,{numberOfListeners:{get:function(){return this._listeners.length-this._toRemove.length}}}),i.prototype.addEventListener=function(e,t){this._listeners.push(e),this._scopes.push(t);var r=this;return function(){r.removeEventListener(e,t)}},i.prototype.removeEventListener=function(e,t){for(var r=this._listeners,i=this._scopes,n=-1,o=0;o<r.length;o++)if(r[o]===e&&i[o]===t){n=o;break}return-1!==n?(this._insideRaiseEvent?(this._toRemove.push(n),r[n]=void 0,i[n]=void 0):(r.splice(n,1),i.splice(n,1)),!0):!1},i.prototype.raiseEvent=function(){this._insideRaiseEvent=!0;var t,r=this._listeners,i=this._scopes,n=r.length;for(t=0;n>t;t++){var o=r[t];e(o)&&r[t].apply(i[t],arguments)}var a=this._toRemove;for(n=a.length,t=0;n>t;t++){var s=a[t];r.splice(s,1),i.splice(s,1)}a.length=0,this._insideRaiseEvent=!1},i}),r("Core/Cartesian2",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r){this.x=e(t,0),this.y=e(r,0)};o.fromElements=function(e,r,i){return t(i)?(i.x=e,i.y=r,i):new o(e,r)},o.clone=function(e,r){return t(e)?t(r)?(r.x=e.x,r.y=e.y,r):new o(e.x,e.y):void 0},o.fromCartesian3=o.clone,o.fromCartesian4=o.clone,o.packedLength=2,o.pack=function(t,r,i){i=e(i,0),r[i++]=t.x,r[i]=t.y},o.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new o),n.x=r[i++],n.y=r[i],n},o.fromArray=o.unpack,o.maximumComponent=function(e){return Math.max(e.x,e.y)},o.minimumComponent=function(e){return Math.min(e.x,e.y)},o.minimumByComponent=function(e,t,r){return r.x=Math.min(e.x,t.x),r.y=Math.min(e.y,t.y),r},o.maximumByComponent=function(e,t,r){return r.x=Math.max(e.x,t.x),r.y=Math.max(e.y,t.y),r},o.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y},o.magnitude=function(e){return Math.sqrt(o.magnitudeSquared(e))};var a=new o;o.distance=function(e,t){return o.subtract(e,t,a),o.magnitude(a)},o.distanceSquared=function(e,t){return o.subtract(e,t,a),o.magnitudeSquared(a)},o.normalize=function(e,t){var r=o.magnitude(e);return t.x=e.x/r,t.y=e.y/r,t},o.dot=function(e,t){return e.x*t.x+e.y*t.y},o.multiplyComponents=function(e,t,r){return r.x=e.x*t.x,r.y=e.y*t.y,r},o.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r},o.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r},o.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r},o.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r},o.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t},o.abs=function(e,t){return t.x=Math.abs(e.x),t.y=Math.abs(e.y),t};var s=new o;o.lerp=function(e,t,r,i){return o.multiplyByScalar(t,r,s),i=o.multiplyByScalar(e,1-r,i),o.add(s,i,i)};var l=new o,u=new o;o.angleBetween=function(e,t){return o.normalize(e,l),o.normalize(t,u),n.acosClamped(o.dot(l,u))};var c=new o;return o.mostOrthogonalAxis=function(e,t){var r=o.normalize(e,c);return o.abs(r,r),t=r.x<=r.y?o.clone(o.UNIT_X,t):o.clone(o.UNIT_Y,t)},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.x===r.x&&e.y===r.y},o.equalsArray=function(e,t,r){return e.x===t[r]&&e.y===t[r+1]},o.equalsEpsilon=function(e,r,i,o){return e===r||t(e)&&t(r)&&n.equalsEpsilon(e.x,r.x,i,o)&&n.equalsEpsilon(e.y,r.y,i,o)},o.ZERO=i(new o(0,0)),o.UNIT_X=i(new o(1,0)),o.UNIT_Y=i(new o(0,1)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t,r){return o.equalsEpsilon(this,e,t,r)},o.prototype.toString=function(){return"("+this.x+", "+this.y+")"},o}),r("Core/GeographicProjection",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){this._ellipsoid=r(e,a.WGS84),this._semimajorAxis=this._ellipsoid.maximumRadius,this._oneOverSemimajorAxis=1/this._semimajorAxis};return n(s.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),s.prototype.project=function(t,r){var n=this._semimajorAxis,o=t.longitude*n,a=t.latitude*n,s=t.height;return i(r)?(r.x=o,r.y=a,r.z=s,r):new e(o,a,s)},s.prototype.unproject=function(e,r){var n=this._oneOverSemimajorAxis,o=e.x*n,a=e.y*n,s=e.z;return i(r)?(r.longitude=o,r.latitude=a,r.height=s,r):new t(o,a,s)},s}),r("Core/Rectangle",["./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./freezeObject","./Math"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,r,i,n){this.west=t(e,0),this.south=t(r,0),this.east=t(i,0),this.north=t(n,0)};i(l.prototype,{width:{get:function(){return l.computeWidth(this)}},height:{get:function(){return l.computeHeight(this)}}}),l.packedLength=4,l.pack=function(e,r,i){i=t(i,0),r[i++]=e.west,r[i++]=e.south,r[i++]=e.east,r[i]=e.north},l.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new l),n.west=e[i++],n.south=e[i++],n.east=e[i++],n.north=e[i],n},l.computeWidth=function(e){var t=e.east,r=e.west;return r>t&&(t+=s.TWO_PI),t-r},l.computeHeight=function(e){return e.north-e.south},l.fromDegrees=function(e,i,n,o,a){return e=s.toRadians(t(e,0)),i=s.toRadians(t(i,0)),n=s.toRadians(t(n,0)),o=s.toRadians(t(o,0)),r(a)?(a.west=e,a.south=i,a.east=n,a.north=o,a):new l(e,i,n,o)},l.fromCartographicArray=function(e,t){for(var i=Number.MAX_VALUE,n=-Number.MAX_VALUE,o=Number.MAX_VALUE,a=-Number.MAX_VALUE,s=0,u=e.length;u>s;s++){var c=e[s];i=Math.min(i,c.longitude),n=Math.max(n,c.longitude),o=Math.min(o,c.latitude),a=Math.max(a,c.latitude)}return r(t)?(t.west=i,t.south=o,t.east=n,t.north=a,t):new l(i,o,n,a)},l.clone=function(e,t){return r(e)?r(t)?(t.west=e.west,t.south=e.south,t.east=e.east,t.north=e.north,t):new l(e.west,e.south,e.east,e.north):void 0},l.prototype.clone=function(e){return l.clone(this,e)},l.prototype.equals=function(e){return l.equals(this,e)},l.equals=function(e,t){return e===t||r(e)&&r(t)&&e.west===t.west&&e.south===t.south&&e.east===t.east&&e.north===t.north},l.prototype.equalsEpsilon=function(e,t){return r(e)&&Math.abs(this.west-e.west)<=t&&Math.abs(this.south-e.south)<=t&&Math.abs(this.east-e.east)<=t&&Math.abs(this.north-e.north)<=t},l.validate=function(e){},l.southwest=function(t,i){return r(i)?(i.longitude=t.west,i.latitude=t.south,i.height=0,i):new e(t.west,t.south)},l.northwest=function(t,i){return r(i)?(i.longitude=t.west,i.latitude=t.north,i.height=0,i):new e(t.west,t.north)},l.northeast=function(t,i){return r(i)?(i.longitude=t.east,i.latitude=t.north,i.height=0,i):new e(t.east,t.north)},l.southeast=function(t,i){return r(i)?(i.longitude=t.east,i.latitude=t.south,i.height=0,i):new e(t.east,t.south)},l.center=function(t,i){var n=t.east,o=t.west;o>n&&(n+=s.TWO_PI);var a=s.negativePiToPi(.5*(o+n)),l=.5*(t.south+t.north);return r(i)?(i.longitude=a,i.latitude=l,i.height=0,i):new e(a,l)},l.intersection=function(e,t,i){var n=e.east,o=e.west,a=t.east,u=t.west;o>n&&a>0?n+=s.TWO_PI:u>a&&n>0&&(a+=s.TWO_PI),o>n&&0>u?u+=s.TWO_PI:u>a&&0>o&&(o+=s.TWO_PI);var c=s.negativePiToPi(Math.max(o,u)),h=s.negativePiToPi(Math.min(n,a));if((e.west<e.east||t.west<t.east)&&c>=h)return void 0;var d=Math.max(e.south,t.south),p=Math.min(e.north,t.north);return d>=p?void 0:r(i)?(i.west=c,i.south=d,i.east=h,i.north=p,i):new l(c,d,h,p)},l.contains=function(e,t){var r=t.longitude,i=t.latitude,n=e.west,o=e.east;return n>o&&(o+=s.TWO_PI,0>r&&(r+=s.TWO_PI)),(r>n||s.equalsEpsilon(r,n,s.EPSILON14))&&(o>r||s.equalsEpsilon(r,o,s.EPSILON14))&&i>=e.south&&i<=e.north};var u=new e;return l.subsample=function(e,i,n,a){i=t(i,o.WGS84),n=t(n,0),r(a)||(a=[]);var c=0,h=e.north,d=e.south,p=e.east,m=e.west,f=u;f.height=n,f.longitude=m,f.latitude=h,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.longitude=p,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.latitude=d,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.longitude=m,a[c]=i.cartographicToCartesian(f,a[c]),c++,0>h?f.latitude=h:d>0?f.latitude=d:f.latitude=0;for(var v=1;8>v;++v)f.longitude=-Math.PI+v*s.PI_OVER_TWO,l.contains(e,f)&&(a[c]=i.cartographicToCartesian(f,a[c]),c++);return 0===f.latitude&&(f.longitude=m,a[c]=i.cartographicToCartesian(f,a[c]),c++,f.longitude=p,a[c]=i.cartographicToCartesian(f,a[c]),c++),a.length=c,a},l.MAX_VALUE=a(new l(-Math.PI,-s.PI_OVER_TWO,Math.PI,s.PI_OVER_TWO)),l}),r("Core/GeographicTilingScheme",["./Cartesian2","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./GeographicProjection","./Math","./Rectangle"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(e){e=t(e,{}),this._ellipsoid=t(e.ellipsoid,o.WGS84),this._rectangle=t(e.rectangle,l.MAX_VALUE),this._projection=new a(this._ellipsoid),this._numberOfLevelZeroTilesX=t(e.numberOfLevelZeroTilesX,2),this._numberOfLevelZeroTilesY=t(e.numberOfLevelZeroTilesY,1)};return i(u.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},rectangle:{get:function(){return this._rectangle}},projection:{get:function(){return this._projection}}}),u.prototype.getNumberOfXTilesAtLevel=function(e){return this._numberOfLevelZeroTilesX<<e},u.prototype.getNumberOfYTilesAtLevel=function(e){return this._numberOfLevelZeroTilesY<<e},u.prototype.rectangleToNativeRectangle=function(e,t){var i=s.toDegrees(e.west),n=s.toDegrees(e.south),o=s.toDegrees(e.east),a=s.toDegrees(e.north);return r(t)?(t.west=i,t.south=n,t.east=o,t.north=a,t):new l(i,n,o,a)},u.prototype.tileXYToNativeRectangle=function(e,t,r,i){var n=this.tileXYToRectangle(e,t,r,i);return n.west=s.toDegrees(n.west),n.south=s.toDegrees(n.south),n.east=s.toDegrees(n.east),n.north=s.toDegrees(n.north),n},u.prototype.tileXYToRectangle=function(e,t,i,n){var o=this._rectangle,a=this.getNumberOfXTilesAtLevel(i),s=this.getNumberOfYTilesAtLevel(i),u=o.width/a,c=e*u+o.west,h=(e+1)*u+o.west,d=o.height/s,p=o.north-t*d,m=o.north-(t+1)*d; -return r(n)||(n=new l(c,m,h,p)),n.west=c,n.south=m,n.east=h,n.north=p,n},u.prototype.positionToTileXY=function(t,i,n){var o=this._rectangle;if(!l.contains(o,t))return void 0;var a=this.getNumberOfXTilesAtLevel(i),u=this.getNumberOfYTilesAtLevel(i),c=o.width/a,h=o.height/u,d=t.longitude;o.east<o.west&&(d+=s.TWO_PI);var p=(d-o.west)/c|0;p>=a&&(p=a-1);var m=(o.north-t.latitude)/h|0;return m>=u&&(m=u-1),r(n)?(n.x=p,n.y=m,n):new e(p,m)},u}),r("Core/getImagePixels",["./defined"],function(e){"use strict";var t={},r=function(r,i,n){e(i)||(i=r.width),e(n)||(n=r.height);var o=t[i];e(o)||(o={},t[i]=o);var a=o[n];if(!e(a)){var s=document.createElement("canvas");s.width=i,s.height=n,a=s.getContext("2d"),a.globalCompositeOperation="copy",o[n]=a}return a.drawImage(r,0,0,i,n),a.getImageData(0,0,i,n).data};return r}),r("Core/HeightmapTessellator",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./freezeObject","./Math","./Rectangle"],function(e,t,r,i,n,o,a,s){"use strict";var l={};return l.DEFAULT_STRUCTURE=o({heightScale:1,heightOffset:0,elementsPerHeight:1,stride:1,elementMultiplier:256,isBigEndian:!1}),l.computeVertices=function(i){var o,u,c,h,d=Math.cos,p=Math.sin,m=Math.sqrt,f=Math.atan,v=Math.exp,_=a.PI_OVER_TWO,g=a.toRadians,y=i.vertices,C=i.heightmap,E=i.width,S=i.height,w=i.skirtHeight,T=t(i.isGeographic,!0),b=t(i.ellipsoid,n.WGS84),x=1/b.maximumRadius,P=i.nativeRectangle,A=i.rectangle;r(A)?(o=A.west,u=A.south,c=A.east,h=A.north):T?(o=g(P.west),u=g(P.south),c=g(P.east),h=g(P.north)):(o=P.west*x,u=_-2*f(v(-P.south*x)),c=P.east*x,h=_-2*f(v(-P.north*x)));var I=t(i.relativeToCenter,e.ZERO),M=t(i.structure,l.DEFAULT_STRUCTURE),D=t(M.heightScale,l.DEFAULT_STRUCTURE.heightScale),R=t(M.heightOffset,l.DEFAULT_STRUCTURE.heightOffset),O=t(M.elementsPerHeight,l.DEFAULT_STRUCTURE.elementsPerHeight),N=t(M.stride,l.DEFAULT_STRUCTURE.stride),L=t(M.elementMultiplier,l.DEFAULT_STRUCTURE.elementMultiplier),F=t(M.isBigEndian,l.DEFAULT_STRUCTURE.isBigEndian),B=s.computeWidth(P)/(E-1),V=s.computeHeight(P)/(S-1),z=b.radiiSquared,k=z.x,U=z.y,G=z.z,W=0,H=65536,q=-65536,j=0,Y=S,X=0,Z=E;w>0&&(--j,++Y,--X,++Z);for(var K=j;Y>K;++K){var J=K;0>J&&(J=0),J>=S&&(J=S-1);var Q=P.north-V*J;Q=T?g(Q):_-2*f(v(-Q*x));for(var $=d(Q),ee=p(Q),te=G*ee,re=(Q-u)/(h-u),ie=X;Z>ie;++ie){var ne=ie;0>ne&&(ne=0),ne>=E&&(ne=E-1);var oe=P.west+B*ne;T?oe=g(oe):oe*=x;var ae,se=J*E*N+ne*N;if(1===O)ae=C[se];else{ae=0;var le;if(F)for(le=0;O>le;++le)ae=ae*L+C[se+le];else for(le=O-1;le>=0;--le)ae=ae*L+C[se+le]}ae=ae*D+R,q=Math.max(q,ae),H=Math.min(H,ae),(ie!==ne||K!==J)&&(ae-=w);var ue=$*d(oe),ce=$*p(oe),he=k*ue,de=U*ce,pe=m(he*ue+de*ce+te*ee),me=1/pe,fe=he*me,ve=de*me,_e=te*me;y[W++]=fe+ue*ae-I.x,y[W++]=ve+ce*ae-I.y,y[W++]=_e+ee*ae-I.z,y[W++]=ae;var ge=(oe-o)/(c-o);y[W++]=ge,y[W++]=re}}return{maximumHeight:q,minimumHeight:H}},l}),r("ThirdParty/Uri",[],function(){function e(t){if(t instanceof e)this.scheme=t.scheme,this.authority=t.authority,this.path=t.path,this.query=t.query,this.fragment=t.fragment;else if(t){var r=i.exec(t);this.scheme=r[1],this.authority=r[2],this.path=r[3],this.query=r[4],this.fragment=r[5]}}function t(e){var t=unescape(e);return o.test(t)?t:e.toUpperCase()}function r(e,t,r,i){return(t||"")+r.toLowerCase()+(i||"")}e.prototype.scheme=null,e.prototype.authority=null,e.prototype.path="",e.prototype.query=null,e.prototype.fragment=null;var i=new RegExp("^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$");e.prototype.getScheme=function(){return this.scheme},e.prototype.getAuthority=function(){return this.authority},e.prototype.getPath=function(){return this.path},e.prototype.getQuery=function(){return this.query},e.prototype.getFragment=function(){return this.fragment},e.prototype.isAbsolute=function(){return!!this.scheme&&!this.fragment},e.prototype.isSameDocumentAs=function(e){return e.scheme==this.scheme&&e.authority==this.authority&&e.path==this.path&&e.query==this.query},e.prototype.equals=function(e){return this.isSameDocumentAs(e)&&e.fragment==this.fragment},e.prototype.normalize=function(){this.removeDotSegments(),this.scheme&&(this.scheme=this.scheme.toLowerCase()),this.authority&&(this.authority=this.authority.replace(a,r).replace(n,t)),this.path&&(this.path=this.path.replace(n,t)),this.query&&(this.query=this.query.replace(n,t)),this.fragment&&(this.fragment=this.fragment.replace(n,t))};var n=/%[0-9a-z]{2}/gi,o=/[a-zA-Z0-9\-\._~]/,a=/(.*@)?([^@:]*)(:.*)?/;return e.prototype.resolve=function(t){var r=new e;return this.scheme?(r.scheme=this.scheme,r.authority=this.authority,r.path=this.path,r.query=this.query):(r.scheme=t.scheme,this.authority?(r.authority=this.authority,r.path=this.path,r.query=this.query):(r.authority=t.authority,""==this.path?(r.path=t.path,r.query=this.query||t.query):("/"==this.path.charAt(0)?(r.path=this.path,r.removeDotSegments()):(t.authority&&""==t.path?r.path="/"+this.path:r.path=t.path.substring(0,t.path.lastIndexOf("/")+1)+this.path,r.removeDotSegments()),r.query=this.query))),r.fragment=this.fragment,r},e.prototype.removeDotSegments=function(){var e,t=this.path.split("/"),r=[],i=""==t[0];i&&t.shift();for(""==t[0]?t.shift():null;t.length;)e=t.shift(),".."==e?r.pop():"."!=e&&r.push(e);("."==e||".."==e)&&r.push(""),i&&r.unshift(""),this.path=r.join("/")},e.prototype.toString=function(){var e="";return this.scheme&&(e+=this.scheme+":"),this.authority&&(e+="//"+this.authority),e+=this.path,this.query&&(e+="?"+this.query),this.fragment&&(e+="#"+this.fragment),e},e}),r("Core/buildModuleUrl",["../ThirdParty/Uri","./defined","./DeveloperError","require"],function(e,t,r,i){"use strict";function n(){for(var e=document.getElementsByTagName("script"),t=0,r=e.length;r>t;++t){var i=e[t].getAttribute("src"),n=h.exec(i);if(null!==n)return n[1]}return void 0}function o(){if(t(l))return l;var i;if(i="undefined"!=typeof CESIUM_BASE_URL?CESIUM_BASE_URL:n(),!t(i))throw new r("Unable to determine Cesium base URL automatically, try defining a global variable called CESIUM_BASE_URL.");return l=new e(i).resolve(new e(document.location.href))}function a(e){return i.toUrl("../"+e)}function s(t){return new e(t).resolve(o()).toString()}var l,u,c,h=/((?:.*\/)|^)cesium[\w-]*\.js(?:\W|$)/i,d=function(e){t(u)||(u=t(i.toUrl)?a:s),t(c)||(c=document.createElement("a"));var r=u(e);return c.href=r,c.href=c.href,c.href};return d._cesiumScriptRegex=h,d.setBaseUrl=function(t){l=new e(t).resolve(new e(document.location.href))},d}),r("Core/destroyObject",["./defaultValue","./DeveloperError"],function(e,t){"use strict";function r(){return!0}var i=function(i,n){function o(){throw new t(n)}n=e(n,"This object was destroyed, i.e., destroy() was called.");for(var a in i)"function"==typeof i[a]&&(i[a]=o);return void(i.isDestroyed=r)};return i}),r("Core/isCrossOriginUrl",["./defined"],function(e){"use strict";var t,r=function(r){e(t)||(t=document.createElement("a")),t.href=window.location.href;var i=t.host,n=t.protocol;return t.href=r,t.href=t.href,n!==t.protocol||i!==t.host};return r}),r("Core/RuntimeError",["./defined"],function(e){"use strict";var t=function(e){this.name="RuntimeError",this.message=e;var t;try{throw new Error}catch(r){t=r.stack}this.stack=t};return t.prototype.toString=function(){var t=this.name+": "+this.message;return e(this.stack)&&(t+="\n"+this.stack.toString()),t},t}),r("Core/TaskProcessor",["../ThirdParty/Uri","../ThirdParty/when","./buildModuleUrl","./defaultValue","./defined","./destroyObject","./DeveloperError","./isCrossOriginUrl","./RuntimeError","require"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(){if(!n(v._canTransferArrayBuffer)){var e=new Worker(d("Workers/transferTypedArrayTest.js"));e.postMessage=i(e.webkitPostMessage,e.postMessage);var r=99,o=new Int8Array([r]);try{e.postMessage({array:o},[o.buffer])}catch(a){return v._canTransferArrayBuffer=!1,v._canTransferArrayBuffer}var s=t.defer();e.onmessage=function(t){var i=t.data.array,o=n(i)&&i[0]===r;s.resolve(o),e.terminate(),v._canTransferArrayBuffer=o},v._canTransferArrayBuffer=s.promise}return v._canTransferArrayBuffer}function h(e,t){--e._activeTasks;var r=t.id;if(n(r)){var i=e._deferreds,o=i[r];if(n(t.error)){var s=t.error;"RuntimeError"===s.name?(s=new l(t.error.message),s.stack=t.error.stack):"DeveloperError"===s.name&&(s=new a(t.error.message),s.stack=t.error.stack),o.reject(s)}else o.resolve(t.result);delete i[r]}}function d(e){var t=r(e);if(s(t)){var i,n='importScripts("'+t+'");';try{i=new Blob([n],{type:"application/javascript"})}catch(o){var a=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,l=new a;l.append(n),i=l.getBlob("application/javascript")}var u=window.URL||window.webkitURL;t=u.createObjectURL(i)}return t}function p(){return n(f)||(f=d("Workers/cesiumWorkerBootstrapper.js")),f}function m(t){var o=new Worker(p());o.postMessage=i(o.webkitPostMessage,o.postMessage);var a={loaderConfig:{},workerModule:v._workerModulePrefix+t._workerName};if(n(v._loaderConfig))a.loaderConfig=v._loaderConfig;else if(n(u.toUrl)){var s=new e("..").resolve(new e(r("Workers/cesiumWorkerBootstrapper.js"))).toString();a.loaderConfig.baseUrl=s}else a.loaderConfig.paths={Workers:r("Workers")};return o.postMessage(a),o.onmessage=function(e){h(t,e.data)},o}var f,v=function(e,t){this._workerName=e,this._maximumActiveTasks=i(t,5),this._activeTasks=0,this._deferreds={},this._nextID=0},_=[];return v.prototype.scheduleTask=function(e,r){if(n(this._worker)||(this._worker=m(this)),this._activeTasks>=this._maximumActiveTasks)return void 0;++this._activeTasks;var i=this;return t(c(),function(o){n(r)?o||(r.length=0):r=_;var a=i._nextID++,s=t.defer();return i._deferreds[a]=s,i._worker.postMessage({id:a,parameters:e,canTransferArrayBuffer:o},r),s.promise})},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){return n(this._worker)&&this._worker.terminate(),o(this)},v._defaultWorkerModulePrefix="Workers/",v._workerModulePrefix=v._defaultWorkerModulePrefix,v._loaderConfig=void 0,v._canTransferArrayBuffer=void 0,v}),r("Core/TerrainMesh",["../Core/defaultValue"],function(e){"use strict";var t=function(t,r,i,n,o,a,s,l,u){this.center=t,this.vertices=r,this.stride=e(l,6),this.indices=i,this.minimumHeight=n,this.maximumHeight=o,this.boundingSphere3D=a,this.occludeePointInScaledSpace=s,this.orientedBoundingBox=u};return t}),r("Core/TerrainProvider",["./defined","./defineProperties","./DeveloperError","./Math"],function(e,t,r,i){"use strict";var n=function(){r.throwInstantiationError()};t(n.prototype,{errorEvent:{get:r.throwInstantiationError},credit:{get:r.throwInstantiationError},tilingScheme:{get:r.throwInstantiationError},ready:{get:r.throwInstantiationError},readyPromise:{get:r.throwInstantiationError},hasWaterMask:{get:r.throwInstantiationError},hasVertexNormals:{get:r.throwInstantiationError}});var o=[];return n.getRegularGridIndices=function(t,r){var i=o[t];e(i)||(o[t]=i=[]);var n=i[r];if(!e(n)){n=i[r]=new Uint16Array((t-1)*(r-1)*6);for(var a=0,s=0,l=0;r-1>l;++l){for(var u=0;t-1>u;++u){var c=a,h=c+t,d=h+1,p=c+1;n[s++]=c,n[s++]=h,n[s++]=p,n[s++]=p,n[s++]=h,n[s++]=d,++a}++a}}return n},n.heightmapTerrainQuality=.25,n.getEstimatedLevelZeroGeometricErrorForAHeightmap=function(e,t,r){return 2*e.maximumRadius*Math.PI*n.heightmapTerrainQuality/(t*r)},n.prototype.requestTileGeometry=r.throwInstantiationError,n.prototype.getLevelMaximumGeometricError=r.throwInstantiationError,n.prototype.getTileDataAvailable=r.throwInstantiationError,n}),r("Core/HeightmapTerrainData",["../ThirdParty/when","./defaultValue","./defined","./defineProperties","./DeveloperError","./GeographicTilingScheme","./HeightmapTessellator","./Math","./Rectangle","./TaskProcessor","./TerrainMesh","./TerrainProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t,r,i,n,o,a,s){var l=1,u=e._width,c=e._height,h=o*(u-1),d=h+u-1,p=a*(c-1),m=p+c-1,f=1<<l;h/=f,d/=f,p/=f,m/=f;var v=r*(u-1),_=i*(c-1);h-=v,d-=v,p-=_,m-=_;var g,C,E=0|h,S=0|d,w=0|p,T=0|m,b=S-E+1,x=T-w+1,P=e._buffer,A=e._structure,I=b*x,M=I*A.stride,D=new P.constructor(M),R=0,O=A.stride;if(O>1)for(C=w;T>=C;++C)for(g=E;S>=g;++g)for(var N=(C*u+g)*O,L=0;O>L;++L)D[R++]=P[N+L];else for(C=w;T>=C;++C)for(g=E;S>=g;++g)D[R++]=P[C*u+g];return new y({buffer:D,width:b,height:x,childTileMask:0,structure:e._structure,createdByUpsampling:!0})}function p(e,t,r,i,n,o,a,l){var u,c,h,d,p=e._width,v=e._height,_=e._structure,C=_.stride,E=e._buffer,S=new E.constructor(p*v*C),w=t.tileXYToRectangle(r,i,n),T=t.tileXYToRectangle(o,a,l);if(C>1){var b=_.elementsPerHeight,x=_.elementMultiplier,P=_.isBigEndian,A=Math.pow(x,b-1);for(c=0;v>c;++c)for(h=s.lerp(T.north,T.south,c/(v-1)),u=0;p>u;++u){d=s.lerp(T.west,T.east,u/(p-1));var I=f(E,b,x,C,P,w,p,v,d,h);g(S,b,x,A,C,P,c*p+u,I)}}else for(c=0;v>c;++c)for(h=s.lerp(T.north,T.south,c/(v-1)),u=0;p>u;++u)d=s.lerp(T.west,T.east,u/(p-1)),S[c*p+u]=m(E,w,p,v,d,h);return new y({buffer:S,width:p,height:v,childTileMask:0,structure:e._structure,createdByUpsampling:!0})}function m(e,t,r,i,n,o){var a=(n-t.west)*(r-1)/(t.east-t.west),s=(o-t.south)*(i-1)/(t.north-t.south),l=0|a,u=l+1;u>=r&&(u=r-1,l=r-2);var c=0|s,h=c+1;h>=i&&(h=i-1,c=i-2);var d=a-l,p=s-c;c=i-1-c,h=i-1-h;var m=e[c*r+l],f=e[c*r+u],_=e[h*r+l],g=e[h*r+u];return v(d,p,m,f,_,g)}function f(e,t,r,i,n,o,a,s,l,u){var c=(l-o.west)*(a-1)/(o.east-o.west),h=(u-o.south)*(s-1)/(o.north-o.south),d=0|c,p=d+1;p>=a&&(p=a-1,d=a-2);var m=0|h,f=m+1;f>=s&&(f=s-1,m=s-2);var g=c-d,y=h-m;m=s-1-m,f=s-1-f;var C=_(e,t,r,i,n,m*a+d),E=_(e,t,r,i,n,m*a+p),S=_(e,t,r,i,n,f*a+d),w=_(e,t,r,i,n,f*a+p);return v(g,y,C,E,S,w)}function v(e,t,r,i,n,o){return e>t?r+e*(i-r)+t*(o-i):r+e*(o-n)+t*(n-r)}function _(e,t,r,i,n,o){o*=i;var a,s=0;if(n)for(a=0;t>a;++a)s=s*r+e[o+a];else for(a=t-1;a>=0;--a)s=s*r+e[o+a];return s}function g(e,t,r,i,n,o,a,s){a*=n;var l;if(o)for(l=0;t>l;++l)e[a+l]=s/i|0,s-=e[a+l]*i,i/=r;else for(l=t-1;l>=0;--l)e[a+l]=s/i|0,s-=e[a+l]*i,i/=r}var y=function(e){this._buffer=e.buffer,this._width=e.width,this._height=e.height,this._childTileMask=t(e.childTileMask,15);var i=a.DEFAULT_STRUCTURE,n=e.structure;r(n)?n!==i&&(n.heightScale=t(n.heightScale,i.heightScale),n.heightOffset=t(n.heightOffset,i.heightOffset),n.elementsPerHeight=t(n.elementsPerHeight,i.elementsPerHeight),n.stride=t(n.stride,i.stride),n.elementMultiplier=t(n.elementMultiplier,i.elementMultiplier),n.isBigEndian=t(n.isBigEndian,i.isBigEndian)):n=i,this._structure=n,this._createdByUpsampling=t(e.createdByUpsampling,!1),this._waterMask=e.waterMask};i(y.prototype,{waterMask:{get:function(){return this._waterMask}}});var C=new u("createVerticesFromHeightmap");return y.prototype.createMesh=function(t,i,n,a){var s=t.ellipsoid,u=t.tileXYToNativeRectangle(i,n,a),d=t.tileXYToRectangle(i,n,a),p=s.cartographicToCartesian(l.center(d)),m=this._structure,f=h.getEstimatedLevelZeroGeometricErrorForAHeightmap(s,this._width,t.getNumberOfXTilesAtLevel(0)),v=f/(1<<a),_=C.scheduleTask({heightmap:this._buffer,structure:m,width:this._width,height:this._height,nativeRectangle:u,rectangle:d,relativeToCenter:p,ellipsoid:s,skirtHeight:Math.min(4*v,1e3),isGeographic:t instanceof o});return r(_)?e(_,function(e){return new c(p,new Float32Array(e.vertices),h.getRegularGridIndices(e.gridWidth,e.gridHeight),e.minimumHeight,e.maximumHeight,e.boundingSphere3D,e.occludeePointInScaledSpace,6,e.orientedBoundingBox)}):void 0},y.prototype.interpolateHeight=function(e,t,r){var i,n=this._width,o=this._height,a=this._structure,s=a.stride;if(s>1){var l=a.elementsPerHeight,u=a.elementMultiplier,c=a.isBigEndian;i=f(this._buffer,l,u,s,c,e,n,o,t,r)}else i=m(this._buffer,e,n,o,t,r);return i*a.heightScale+a.heightOffset},y.prototype.upsample=function(e,t,r,i,n,o,a){var s;return s=this._width%2===1&&this._height%2===1?d(this,e,t,r,i,n,o,a):p(this,e,t,r,i,n,o,a)},y.prototype.isChildAvailable=function(e,t,r,i){var n=2;return r!==2*e&&++n,i!==2*t&&(n-=2),0!==(this._childTileMask&1<<n)},y.prototype.wasCreatedByUpsampling=function(){return this._createdByUpsampling},y}),r("Core/loadImage",["../ThirdParty/when","./defaultValue","./defined","./DeveloperError","./isCrossOriginUrl"],function(e,t,r,i,n){"use strict";var o=/^data:/,a=function(r,i){return i=t(i,!0),e(r,function(t){var r;r=o.test(t)||!i?!1:n(t);var s=e.defer();return a.createImage(t,r,s),s.promise})};return a.createImage=function(e,t,r){var i=new Image;i.onload=function(){r.resolve(i)},i.onerror=function(e){r.reject(e)},t&&(i.crossOrigin=""),i.src=e},a.defaultCreateImage=a.createImage,a}),r("Core/throttleRequestByServer",["../ThirdParty/Uri","../ThirdParty/when","./defaultValue"],function(e,t,r){"use strict";function i(t){var r=new e(t).resolve(o);r.normalize();var i=r.authority;return/:/.test(i)||(i=i+":"+("https"===r.scheme?"443":"80")),i}var n={},o=new e(document.location.href),a=function(e,o){var s=i(e),l=r(n[s],0);return l>=a.maximumRequestsPerServer?void 0:(n[s]=l+1,t(o(e),function(e){return n[s]--,e}).otherwise(function(e){return n[s]--,t.reject(e)}))};return a.maximumRequestsPerServer=6,a}),r("Core/ArcGisImageServerTerrainProvider",["../ThirdParty/when","./Credit","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Event","./GeographicTilingScheme","./getImagePixels","./HeightmapTerrainData","./loadImage","./Math","./TerrainProvider","./throttleRequestByServer"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=function(n){this._url=n.url,this._token=n.token,this._tilingScheme=n.tilingScheme,i(this._tilingScheme)||(this._tilingScheme=new l({ellipsoid:r(n.ellipsoid,a.WGS84)})),this._heightmapWidth=65,this._levelZeroMaximumGeometricError=p.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid,this._heightmapWidth,this._tilingScheme.getNumberOfXTilesAtLevel(0)),this._proxy=n.proxy,this._terrainDataStructure={heightScale:.001,heightOffset:-1e3,elementsPerHeight:3,stride:4,elementMultiplier:256,isBigEndian:!0},this._errorEvent=new s;var o=n.credit;"string"==typeof o&&(o=new t(o)),this._credit=o,this._readyPromise=e.resolve(!0)};return n(f.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return this._credit}},tilingScheme:{get:function(){return this._tilingScheme}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},hasWaterMask:{get:function(){return!1}},hasVertexNormals:{get:function(){return!1}}}),f.prototype.requestTileGeometry=function(t,r,n){var o=this._tilingScheme.tileXYToRectangle(t,r,n),a=(o.east-o.west)/(this._heightmapWidth-1),s=(o.north-o.south)/(this._heightmapWidth-1);o.west-=.5*a,o.east+=.5*a,o.south-=.5*s,o.north+=.5*s;var l=d.toDegrees(o.west)+"%2C"+d.toDegrees(o.south)+"%2C"+d.toDegrees(o.east)+"%2C"+d.toDegrees(o.north),p=this._url+"/exportImage?interpolation=RSP_BilinearInterpolation&format=tiff&f=image&size="+this._heightmapWidth+"%2C"+this._heightmapWidth+"&bboxSR=4326&imageSR=4326&bbox="+l;this._token&&(p+="&token="+this._token);var f=this._proxy;i(f)&&(p=f.getURL(p));var v=m(p,h);if(!i(v))return void 0;var _=this;return e(v,function(e){return new c({buffer:u(e),width:_._heightmapWidth,height:_._heightmapWidth,childTileMask:15,structure:_._terrainDataStructure})})},f.prototype.getLevelMaximumGeometricError=function(e){return this._levelZeroMaximumGeometricError/(1<<e)},f.prototype.getTileDataAvailable=function(e,t,r){return void 0},f}),r("Core/AssociativeArray",["./defined","./defineProperties","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this._array=[],this._hash={}};return t(i.prototype,{length:{get:function(){return this._array.length}},values:{get:function(){return this._array}}}),i.prototype.contains=function(t){return e(this._hash[t])},i.prototype.set=function(e,t){var r=this._hash[e];t!==r&&(this.remove(e),this._hash[e]=t,this._array.push(t))},i.prototype.get=function(e){return this._hash[e]},i.prototype.remove=function(t){var r=this._hash[t],i=e(r);if(i){var n=this._array;n.splice(n.indexOf(r),1),delete this._hash[t]}return i},i.prototype.removeAll=function(){var e=this._array;e.length>0&&(this._hash={},e.length=0)},i}),r("Core/AttributeCompression",["./Cartesian2","./Cartesian3","./defined","./DeveloperError","./Math"],function(e,t,r,i,n){"use strict";var o={};o.octEncode=function(e,t){if(t.x=e.x/(Math.abs(e.x)+Math.abs(e.y)+Math.abs(e.z)),t.y=e.y/(Math.abs(e.x)+Math.abs(e.y)+Math.abs(e.z)),e.z<0){var r=t.x,i=t.y;t.x=(1-Math.abs(i))*n.signNotZero(r),t.y=(1-Math.abs(r))*n.signNotZero(i)}return t.x=n.toSNorm(t.x),t.y=n.toSNorm(t.y),t},o.octDecode=function(e,r,i){if(i.x=n.fromSNorm(e),i.y=n.fromSNorm(r),i.z=1-(Math.abs(i.x)+Math.abs(i.y)),i.z<0){var o=i.x;i.x=(1-Math.abs(i.y))*n.signNotZero(o),i.y=(1-Math.abs(o))*n.signNotZero(i.y)}return t.normalize(i,i)},o.octPackFloat=function(e){return 256*e.x+e.y};var a=new e;return o.octEncodeFloat=function(e){return o.octEncode(e,a),o.octPackFloat(a)},o.octDecodeFloat=function(e,t){var r=e/256,i=Math.floor(r),n=256*(r-i);return o.octDecode(i,n,t)},o.octPack=function(e,t,r,i){var n=o.octEncodeFloat(e),s=o.octEncodeFloat(t),l=o.octEncode(r,a);return i.x=65536*l.x+n,i.y=65536*l.y+s,i},o.octUnpack=function(e,t,r,i){var n=e.x/65536,a=Math.floor(n),s=65536*(n-a);n=e.y/65536;var l=Math.floor(n),u=65536*(n-l);o.octDecodeFloat(s,t),o.octDecodeFloat(u,r),o.octDecode(a,l,i)},o.compressTextureCoordinates=function(e){var t=1===e.x?4095:4096*e.x|0,r=1===e.y?4095:4096*e.y|0;return 4096*t+r},o.decompressTextureCoordinates=function(e,t){var r=e/4096;return t.x=Math.floor(r)/4096,t.y=r-Math.floor(r),t},o}),r("Core/deprecationWarning",["./defined","./DeveloperError"],function(e,t){"use strict";var r={},i=function(t,i){e(r[t])||(r[t]=!0,console.log(i))};return i}),r("Core/Intersect",["./freezeObject"],function(e){"use strict";var t={OUTSIDE:-1,INTERSECTING:0,INSIDE:1};return e(t)}),r("Core/Plane",["./Cartesian3","./defined","./DeveloperError","./freezeObject"],function(e,t,r,i){"use strict";var n=function(t,r){this.normal=e.clone(t),this.distance=r};n.fromPointNormal=function(r,i,o){var a=-e.dot(i,r);return t(o)?(e.clone(i,o.normal),o.distance=a,o):new n(i,a)};var o=new e;return n.fromCartesian4=function(r,i){var a=e.fromCartesian4(r,o),s=r.w;return t(i)?(e.clone(a,i.normal),i.distance=s,i):new n(a,s)},n.getPointDistance=function(t,r){return e.dot(t.normal,r)+t.distance},n.ORIGIN_XY_PLANE=i(new n(e.UNIT_Z,0)),n.ORIGIN_YZ_PLANE=i(new n(e.UNIT_X,0)),n.ORIGIN_ZX_PLANE=i(new n(e.UNIT_Y,0)),n}),r("Core/AxisAlignedBoundingBox",["./Cartesian3","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Intersect","./Plane"],function(e,t,r,i,n,o,a){"use strict";var s=function(i,n,o){this.minimum=e.clone(t(i,e.ZERO)),this.maximum=e.clone(t(n,e.ZERO)),r(o)?o=e.clone(o):(o=e.add(this.minimum,this.maximum,new e),e.multiplyByScalar(o,.5,o)),this.center=o};s.fromPoints=function(t,i){if(r(i)||(i=new s),!r(t)||0===t.length)return i.minimum=e.clone(e.ZERO,i.minimum),i.maximum=e.clone(e.ZERO,i.maximum),i.center=e.clone(e.ZERO,i.center),i;for(var n=t[0].x,o=t[0].y,a=t[0].z,l=t[0].x,u=t[0].y,c=t[0].z,h=t.length,d=1;h>d;d++){var p=t[d],m=p.x,f=p.y,v=p.z;n=Math.min(m,n),l=Math.max(m,l),o=Math.min(f,o),u=Math.max(f,u),a=Math.min(v,a),c=Math.max(v,c)}var _=i.minimum;_.x=n,_.y=o,_.z=a;var g=i.maximum;g.x=l,g.y=u,g.z=c;var y=e.add(_,g,i.center);return e.multiplyByScalar(y,.5,y),i},s.clone=function(t,i){return r(t)?r(i)?(i.minimum=e.clone(t.minimum,i.minimum),i.maximum=e.clone(t.maximum,i.maximum),i.center=e.clone(t.center,i.center),i):new s(t.minimum,t.maximum):void 0},s.equals=function(t,i){return t===i||r(t)&&r(i)&&e.equals(t.center,i.center)&&e.equals(t.minimum,i.minimum)&&e.equals(t.maximum,i.maximum)};var l=new e;return s.intersectPlane=function(t,r){l=e.subtract(t.maximum,t.minimum,l);var i=e.multiplyByScalar(l,.5,l),n=r.normal,a=i.x*Math.abs(n.x)+i.y*Math.abs(n.y)+i.z*Math.abs(n.z),s=e.dot(t.center,n)+r.distance;return s-a>0?o.INSIDE:0>s+a?o.OUTSIDE:o.INTERSECTING},s.prototype.clone=function(e){return s.clone(this,e)},s.prototype.intersectPlane=function(e){return s.intersectPlane(this,e)},s.prototype.equals=function(e){return s.equals(this,e)},s}),r("Core/BingMapsApi",["./defined"],function(e){"use strict";var t={};t.defaultKey=void 0;var r=!1;return t.getKey=function(i){return e(i)?i:e(t.defaultKey)?t.defaultKey:(r||(console.log("This application is using Cesium's default Bing Maps key. Please create a new key for the application as soon as possible and prior to deployment by visiting https://www.bingmapsportal.com/, and provide your key to Cesium by setting the Cesium.BingMapsApi.defaultKey property before constructing the CesiumWidget or any other object that uses the Bing Maps API."),r=!0),"Aj1ony_-Typ-KjG9SJWiKSHY23U1KmK7yAmZa9lDmuF2osXWkcZ22VPsqmCt0TCt")},t}),r("Core/BoundingRectangle",["./Cartesian2","./Cartographic","./defaultValue","./defined","./DeveloperError","./GeographicProjection","./Intersect","./Rectangle"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,t,i,n){this.x=r(e,0),this.y=r(t,0),this.width=r(i,0),this.height=r(n,0)};l.fromPoints=function(e,t){if(i(t)||(t=new l),!i(e)||0===e.length)return t.x=0,t.y=0,t.width=0,t.height=0,t;for(var r=e.length,n=e[0].x,o=e[0].y,a=e[0].x,s=e[0].y,u=1;r>u;u++){var c=e[u],h=c.x,d=c.y;n=Math.min(h,n),a=Math.max(h,a),o=Math.min(d,o),s=Math.max(d,s)}return t.x=n,t.y=o,t.width=a-n,t.height=s-o,t};var u=new o,c=new t,h=new t;return l.fromRectangle=function(t,n,o){if(i(o)||(o=new l),!i(t))return o.x=0,o.y=0,o.width=0,o.height=0,o;n=r(n,u);var a=n.project(s.southwest(t,c)),d=n.project(s.northeast(t,h));return e.subtract(d,a,d),o.x=a.x,o.y=a.y,o.width=d.x,o.height=d.y,o},l.clone=function(e,t){return i(e)?i(t)?(t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,t):new l(e.x,e.y,e.width,e.height):void 0},l.union=function(e,t,r){i(r)||(r=new l);var n=Math.min(e.x,t.x),o=Math.min(e.y,t.y),a=Math.max(e.x+e.width,t.x+t.width),s=Math.max(e.y+e.height,t.y+t.height);return r.x=n,r.y=o,r.width=a-n,r.height=s-o,r},l.expand=function(e,t,r){r=l.clone(e,r);var i=t.x-r.x,n=t.y-r.y;return i>r.width?r.width=i:0>i&&(r.width-=i,r.x=t.x),n>r.height?r.height=n:0>n&&(r.height-=n,r.y=t.y),r},l.intersect=function(e,t){var r=e.x,i=e.y,n=t.x,o=t.y;return r>n+t.width||r+e.width<n||i+e.height<o||i>o+t.height?a.OUTSIDE:a.INTERSECTING},l.equals=function(e,t){return e===t||i(e)&&i(t)&&e.x===t.x&&e.y===t.y&&e.width===t.width&&e.height===t.height},l.prototype.clone=function(e){return l.clone(this,e)},l.prototype.intersect=function(e){return l.intersect(this,e)},l.prototype.equals=function(e){return l.equals(this,e)},l}),r("Core/Interval",["./defaultValue"],function(e){"use strict";var t=function(t,r){this.start=e(t,0),this.stop=e(r,0)};return t}),r("Core/Matrix3",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n,o){"use strict";function a(e){for(var t=0,r=0;9>r;++r){var i=e[r];t+=i*i}return Math.sqrt(t)}function s(e){for(var t=0,r=0;3>r;++r){var i=e[u.getElementIndex(p[r],d[r])];t+=2*i*i}return Math.sqrt(t)}function l(e,t){for(var r=o.EPSILON15,i=0,n=1,a=0;3>a;++a){var s=Math.abs(e[u.getElementIndex(p[a],d[a])]);s>i&&(n=a,i=s)}var l=1,c=0,h=d[n],m=p[n];if(Math.abs(e[u.getElementIndex(m,h)])>r){var f,v=e[u.getElementIndex(m,m)],_=e[u.getElementIndex(h,h)],g=e[u.getElementIndex(m,h)],y=(v-_)/2/g;f=0>y?-1/(-y+Math.sqrt(1+y*y)):1/(y+Math.sqrt(1+y*y)),l=1/Math.sqrt(1+f*f),c=f*l}return t=u.clone(u.IDENTITY,t),t[u.getElementIndex(h,h)]=t[u.getElementIndex(m,m)]=l,t[u.getElementIndex(m,h)]=c,t[u.getElementIndex(h,m)]=-c,t}var u=function(e,r,i,n,o,a,s,l,u){this[0]=t(e,0),this[1]=t(n,0),this[2]=t(s,0),this[3]=t(r,0),this[4]=t(o,0),this[5]=t(l,0),this[6]=t(i,0),this[7]=t(a,0),this[8]=t(u,0)};u.packedLength=9,u.pack=function(e,r,i){i=t(i,0),r[i++]=e[0],r[i++]=e[1],r[i++]=e[2],r[i++]=e[3],r[i++]=e[4],r[i++]=e[5],r[i++]=e[6],r[i++]=e[7],r[i++]=e[8]},u.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new u),n[0]=e[i++],n[1]=e[i++],n[2]=e[i++],n[3]=e[i++],n[4]=e[i++],n[5]=e[i++],n[6]=e[i++],n[7]=e[i++],n[8]=e[i++],n},u.clone=function(e,t){return r(e)?r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t):new u(e[0],e[3],e[6],e[1],e[4],e[7],e[2],e[5],e[8]):void 0},u.fromArray=function(e,i,n){return i=t(i,0),r(n)||(n=new u),n[0]=e[i],n[1]=e[i+1],n[2]=e[i+2],n[3]=e[i+3],n[4]=e[i+4],n[5]=e[i+5],n[6]=e[i+6],n[7]=e[i+7],n[8]=e[i+8],n},u.fromColumnMajorArray=function(e,t){return u.clone(e,t)},u.fromRowMajorArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],t):new u(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8])},u.fromQuaternion=function(e,t){var i=e.x*e.x,n=e.x*e.y,o=e.x*e.z,a=e.x*e.w,s=e.y*e.y,l=e.y*e.z,c=e.y*e.w,h=e.z*e.z,d=e.z*e.w,p=e.w*e.w,m=i-s-h+p,f=2*(n-d),v=2*(o+c),_=2*(n+d),g=-i+s-h+p,y=2*(l-a),C=2*(o-c),E=2*(l+a),S=-i-s+h+p;return r(t)?(t[0]=m,t[1]=_,t[2]=C,t[3]=f,t[4]=g,t[5]=E,t[6]=v,t[7]=y,t[8]=S,t):new u(m,f,v,_,g,y,C,E,S)},u.fromScale=function(e,t){return r(t)?(t[0]=e.x,t[1]=0,t[2]=0,t[3]=0,t[4]=e.y,t[5]=0,t[6]=0,t[7]=0,t[8]=e.z,t):new u(e.x,0,0,0,e.y,0,0,0,e.z)},u.fromUniformScale=function(e,t){return r(t)?(t[0]=e,t[1]=0,t[2]=0,t[3]=0,t[4]=e,t[5]=0,t[6]=0,t[7]=0,t[8]=e,t):new u(e,0,0,0,e,0,0,0,e)},u.fromCrossProduct=function(e,t){return r(t)?(t[0]=0,t[1]=e.z,t[2]=-e.y,t[3]=-e.z,t[4]=0,t[5]=e.x,t[6]=e.y,t[7]=-e.x,t[8]=0,t):new u(0,-e.z,e.y,e.z,0,-e.x,-e.y,e.x,0)},u.fromRotationX=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=i,t[5]=n,t[6]=0,t[7]=-n,t[8]=i,t):new u(1,0,0,0,i,-n,0,n,i)},u.fromRotationY=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=i,t[1]=0,t[2]=-n,t[3]=0,t[4]=1,t[5]=0,t[6]=n,t[7]=0,t[8]=i,t):new u(i,0,n,0,1,0,-n,0,i)},u.fromRotationZ=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=i,t[1]=n,t[2]=0,t[3]=-n,t[4]=i,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t):new u(i,-n,0,n,i,0,0,0,1)},u.toArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t):[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8]]},u.getElementIndex=function(e,t){return 3*e+t},u.getColumn=function(e,t,r){var i=3*t,n=e[i],o=e[i+1],a=e[i+2];return r.x=n,r.y=o,r.z=a,r},u.setColumn=function(e,t,r,i){i=u.clone(e,i);var n=3*t;return i[n]=r.x,i[n+1]=r.y,i[n+2]=r.z,i},u.getRow=function(e,t,r){var i=e[t],n=e[t+3],o=e[t+6];return r.x=i,r.y=n,r.z=o,r},u.setRow=function(e,t,r,i){return i=u.clone(e,i),i[t]=r.x,i[t+3]=r.y,i[t+6]=r.z,i};var c=new e;u.getScale=function(t,r){return r.x=e.magnitude(e.fromElements(t[0],t[1],t[2],c)),r.y=e.magnitude(e.fromElements(t[3],t[4],t[5],c)),r.z=e.magnitude(e.fromElements(t[6],t[7],t[8],c)),r};var h=new e;u.getMaximumScale=function(t){return u.getScale(t,h),e.maximumComponent(h)},u.multiply=function(e,t,r){var i=e[0]*t[0]+e[3]*t[1]+e[6]*t[2],n=e[1]*t[0]+e[4]*t[1]+e[7]*t[2],o=e[2]*t[0]+e[5]*t[1]+e[8]*t[2],a=e[0]*t[3]+e[3]*t[4]+e[6]*t[5],s=e[1]*t[3]+e[4]*t[4]+e[7]*t[5],l=e[2]*t[3]+e[5]*t[4]+e[8]*t[5],u=e[0]*t[6]+e[3]*t[7]+e[6]*t[8],c=e[1]*t[6]+e[4]*t[7]+e[7]*t[8],h=e[2]*t[6]+e[5]*t[7]+e[8]*t[8];return r[0]=i,r[1]=n,r[2]=o,r[3]=a,r[4]=s,r[5]=l,r[6]=u,r[7]=c,r[8]=h,r},u.add=function(e,t,r){return r[0]=e[0]+t[0],r[1]=e[1]+t[1],r[2]=e[2]+t[2],r[3]=e[3]+t[3],r[4]=e[4]+t[4],r[5]=e[5]+t[5],r[6]=e[6]+t[6],r[7]=e[7]+t[7],r[8]=e[8]+t[8],r},u.subtract=function(e,t,r){return r[0]=e[0]-t[0],r[1]=e[1]-t[1],r[2]=e[2]-t[2],r[3]=e[3]-t[3],r[4]=e[4]-t[4],r[5]=e[5]-t[5],r[6]=e[6]-t[6],r[7]=e[7]-t[7],r[8]=e[8]-t[8],r},u.multiplyByVector=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=e[0]*i+e[3]*n+e[6]*o,s=e[1]*i+e[4]*n+e[7]*o,l=e[2]*i+e[5]*n+e[8]*o;return r.x=a,r.y=s,r.z=l,r},u.multiplyByScalar=function(e,t,r){return r[0]=e[0]*t,r[1]=e[1]*t,r[2]=e[2]*t,r[3]=e[3]*t,r[4]=e[4]*t,r[5]=e[5]*t,r[6]=e[6]*t,r[7]=e[7]*t,r[8]=e[8]*t,r},u.multiplyByScale=function(e,t,r){return r[0]=e[0]*t.x,r[1]=e[1]*t.x,r[2]=e[2]*t.x,r[3]=e[3]*t.y,r[4]=e[4]*t.y,r[5]=e[5]*t.y,r[6]=e[6]*t.z,r[7]=e[7]*t.z,r[8]=e[8]*t.z,r},u.negate=function(e,t){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2], -t[3]=-e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=-e[7],t[8]=-e[8],t},u.transpose=function(e,t){var r=e[0],i=e[3],n=e[6],o=e[1],a=e[4],s=e[7],l=e[2],u=e[5],c=e[8];return t[0]=r,t[1]=i,t[2]=n,t[3]=o,t[4]=a,t[5]=s,t[6]=l,t[7]=u,t[8]=c,t};var d=[1,0,0],p=[2,2,1],m=new u,f=new u;return u.computeEigenDecomposition=function(e,t){var i=o.EPSILON20,n=10,c=0,h=0;r(t)||(t={});for(var d=t.unitary=u.clone(u.IDENTITY,t.unitary),p=t.diagonal=u.clone(e,t.diagonal),v=i*a(p);n>h&&s(p)>v;)l(p,m),u.transpose(m,f),u.multiply(p,m,p),u.multiply(f,p,p),u.multiply(d,m,d),++c>2&&(++h,c=0);return t},u.abs=function(e,t){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t[3]=Math.abs(e[3]),t[4]=Math.abs(e[4]),t[5]=Math.abs(e[5]),t[6]=Math.abs(e[6]),t[7]=Math.abs(e[7]),t[8]=Math.abs(e[8]),t},u.determinant=function(e){var t=e[0],r=e[3],i=e[6],n=e[1],o=e[4],a=e[7],s=e[2],l=e[5],u=e[8];return t*(o*u-l*a)+n*(l*i-r*u)+s*(r*a-o*i)},u.inverse=function(e,t){var r=e[0],n=e[1],a=e[2],s=e[3],l=e[4],c=e[5],h=e[6],d=e[7],p=e[8],m=u.determinant(e);if(Math.abs(m)<=o.EPSILON15)throw new i("matrix is not invertible");t[0]=l*p-d*c,t[1]=d*a-n*p,t[2]=n*c-l*a,t[3]=h*c-s*p,t[4]=r*p-h*a,t[5]=s*a-r*c,t[6]=s*d-h*l,t[7]=h*n-r*d,t[8]=r*l-s*n;var f=1/m;return u.multiplyByScalar(t,f,t)},u.equals=function(e,t){return e===t||r(e)&&r(t)&&e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[3]===t[3]&&e[4]===t[4]&&e[5]===t[5]&&e[6]===t[6]&&e[7]===t[7]&&e[8]===t[8]},u.equalsEpsilon=function(e,t,i){return e===t||r(e)&&r(t)&&Math.abs(e[0]-t[0])<=i&&Math.abs(e[1]-t[1])<=i&&Math.abs(e[2]-t[2])<=i&&Math.abs(e[3]-t[3])<=i&&Math.abs(e[4]-t[4])<=i&&Math.abs(e[5]-t[5])<=i&&Math.abs(e[6]-t[6])<=i&&Math.abs(e[7]-t[7])<=i&&Math.abs(e[8]-t[8])<=i},u.IDENTITY=n(new u(1,0,0,0,1,0,0,0,1)),u.ZERO=n(new u(0,0,0,0,0,0,0,0,0)),u.COLUMN0ROW0=0,u.COLUMN0ROW1=1,u.COLUMN0ROW2=2,u.COLUMN1ROW0=3,u.COLUMN1ROW1=4,u.COLUMN1ROW2=5,u.COLUMN2ROW0=6,u.COLUMN2ROW1=7,u.COLUMN2ROW2=8,u.prototype.clone=function(e){return u.clone(this,e)},u.prototype.equals=function(e){return u.equals(this,e)},u.equalsArray=function(e,t,r){return e[0]===t[r]&&e[1]===t[r+1]&&e[2]===t[r+2]&&e[3]===t[r+3]&&e[4]===t[r+4]&&e[5]===t[r+5]&&e[6]===t[r+6]&&e[7]===t[r+7]&&e[8]===t[r+8]},u.prototype.equalsEpsilon=function(e,t){return u.equalsEpsilon(this,e,t)},u.prototype.toString=function(){return"("+this[0]+", "+this[3]+", "+this[6]+")\n("+this[1]+", "+this[4]+", "+this[7]+")\n("+this[2]+", "+this[5]+", "+this[8]+")"},u}),r("Core/Cartesian4",["./defaultValue","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o=function(t,r,i,n){this.x=e(t,0),this.y=e(r,0),this.z=e(i,0),this.w=e(n,0)};o.fromElements=function(e,r,i,n,a){return t(a)?(a.x=e,a.y=r,a.z=i,a.w=n,a):new o(e,r,i,n)},o.fromColor=function(e,r){return t(r)?(r.x=e.red,r.y=e.green,r.z=e.blue,r.w=e.alpha,r):new o(e.red,e.green,e.blue,e.alpha)},o.clone=function(e,r){return t(e)?t(r)?(r.x=e.x,r.y=e.y,r.z=e.z,r.w=e.w,r):new o(e.x,e.y,e.z,e.w):void 0},o.packedLength=4,o.pack=function(t,r,i){i=e(i,0),r[i++]=t.x,r[i++]=t.y,r[i++]=t.z,r[i]=t.w},o.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new o),n.x=r[i++],n.y=r[i++],n.z=r[i++],n.w=r[i],n},o.fromArray=o.unpack,o.maximumComponent=function(e){return Math.max(e.x,e.y,e.z,e.w)},o.minimumComponent=function(e){return Math.min(e.x,e.y,e.z,e.w)},o.minimumByComponent=function(e,t,r){return r.x=Math.min(e.x,t.x),r.y=Math.min(e.y,t.y),r.z=Math.min(e.z,t.z),r.w=Math.min(e.w,t.w),r},o.maximumByComponent=function(e,t,r){return r.x=Math.max(e.x,t.x),r.y=Math.max(e.y,t.y),r.z=Math.max(e.z,t.z),r.w=Math.max(e.w,t.w),r},o.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y+e.z*e.z+e.w*e.w},o.magnitude=function(e){return Math.sqrt(o.magnitudeSquared(e))};var a=new o;o.distance=function(e,t){return o.subtract(e,t,a),o.magnitude(a)},o.distanceSquared=function(e,t){return o.subtract(e,t,a),o.magnitudeSquared(a)},o.normalize=function(e,t){var r=o.magnitude(e);return t.x=e.x/r,t.y=e.y/r,t.z=e.z/r,t.w=e.w/r,t},o.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z+e.w*t.w},o.multiplyComponents=function(e,t,r){return r.x=e.x*t.x,r.y=e.y*t.y,r.z=e.z*t.z,r.w=e.w*t.w,r},o.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r.z=e.z+t.z,r.w=e.w+t.w,r},o.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r.z=e.z-t.z,r.w=e.w-t.w,r},o.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r.z=e.z*t,r.w=e.w*t,r},o.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r.z=e.z/t,r.w=e.w/t,r},o.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t.w=-e.w,t},o.abs=function(e,t){return t.x=Math.abs(e.x),t.y=Math.abs(e.y),t.z=Math.abs(e.z),t.w=Math.abs(e.w),t};var s=new o;o.lerp=function(e,t,r,i){return o.multiplyByScalar(t,r,s),i=o.multiplyByScalar(e,1-r,i),o.add(s,i,i)};var l=new o;return o.mostOrthogonalAxis=function(e,t){var r=o.normalize(e,l);return o.abs(r,r),t=r.x<=r.y?r.x<=r.z?r.x<=r.w?o.clone(o.UNIT_X,t):o.clone(o.UNIT_W,t):r.z<=r.w?o.clone(o.UNIT_Z,t):o.clone(o.UNIT_W,t):r.y<=r.z?r.y<=r.w?o.clone(o.UNIT_Y,t):o.clone(o.UNIT_W,t):r.z<=r.w?o.clone(o.UNIT_Z,t):o.clone(o.UNIT_W,t)},o.equals=function(e,r){return e===r||t(e)&&t(r)&&e.x===r.x&&e.y===r.y&&e.z===r.z&&e.w===r.w},o.equalsArray=function(e,t,r){return e.x===t[r]&&e.y===t[r+1]&&e.z===t[r+2]&&e.w===t[r+3]},o.equalsEpsilon=function(e,r,i,o){return e===r||t(e)&&t(r)&&n.equalsEpsilon(e.x,r.x,i,o)&&n.equalsEpsilon(e.y,r.y,i,o)&&n.equalsEpsilon(e.z,r.z,i,o)&&n.equalsEpsilon(e.w,r.w,i,o)},o.ZERO=i(new o(0,0,0,0)),o.UNIT_X=i(new o(1,0,0,0)),o.UNIT_Y=i(new o(0,1,0,0)),o.UNIT_Z=i(new o(0,0,1,0)),o.UNIT_W=i(new o(0,0,0,1)),o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t,r){return o.equalsEpsilon(this,e,t,r)},o.prototype.toString=function(){return"("+this.x+", "+this.y+", "+this.z+", "+this.w+")"},o}),r("Core/Matrix4",["./Cartesian3","./Cartesian4","./defaultValue","./defined","./DeveloperError","./freezeObject","./Math","./Matrix3","./RuntimeError"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(e,t,i,n,o,a,s,l,u,c,h,d,p,m,f,v){this[0]=r(e,0),this[1]=r(o,0),this[2]=r(u,0),this[3]=r(p,0),this[4]=r(t,0),this[5]=r(a,0),this[6]=r(c,0),this[7]=r(m,0),this[8]=r(i,0),this[9]=r(s,0),this[10]=r(h,0),this[11]=r(f,0),this[12]=r(n,0),this[13]=r(l,0),this[14]=r(d,0),this[15]=r(v,0)};u.packedLength=16,u.pack=function(e,t,i){i=r(i,0),t[i++]=e[0],t[i++]=e[1],t[i++]=e[2],t[i++]=e[3],t[i++]=e[4],t[i++]=e[5],t[i++]=e[6],t[i++]=e[7],t[i++]=e[8],t[i++]=e[9],t[i++]=e[10],t[i++]=e[11],t[i++]=e[12],t[i++]=e[13],t[i++]=e[14],t[i]=e[15]},u.unpack=function(e,t,n){return t=r(t,0),i(n)||(n=new u),n[0]=e[t++],n[1]=e[t++],n[2]=e[t++],n[3]=e[t++],n[4]=e[t++],n[5]=e[t++],n[6]=e[t++],n[7]=e[t++],n[8]=e[t++],n[9]=e[t++],n[10]=e[t++],n[11]=e[t++],n[12]=e[t++],n[13]=e[t++],n[14]=e[t++],n[15]=e[t],n},u.clone=function(e,t){return i(e)?i(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t):new u(e[0],e[4],e[8],e[12],e[1],e[5],e[9],e[13],e[2],e[6],e[10],e[14],e[3],e[7],e[11],e[15]):void 0},u.fromArray=u.unpack,u.fromColumnMajorArray=function(e,t){return u.clone(e,t)},u.fromRowMajorArray=function(e,t){return i(t)?(t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15],t):new u(e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15])},u.fromRotationTranslation=function(t,n,o){return n=r(n,e.ZERO),i(o)?(o[0]=t[0],o[1]=t[1],o[2]=t[2],o[3]=0,o[4]=t[3],o[5]=t[4],o[6]=t[5],o[7]=0,o[8]=t[6],o[9]=t[7],o[10]=t[8],o[11]=0,o[12]=n.x,o[13]=n.y,o[14]=n.z,o[15]=1,o):new u(t[0],t[3],t[6],n.x,t[1],t[4],t[7],n.y,t[2],t[5],t[8],n.z,0,0,0,1)},u.fromTranslationQuaternionRotationScale=function(e,t,r,n){i(n)||(n=new u);var o=r.x,a=r.y,s=r.z,l=t.x*t.x,c=t.x*t.y,h=t.x*t.z,d=t.x*t.w,p=t.y*t.y,m=t.y*t.z,f=t.y*t.w,v=t.z*t.z,_=t.z*t.w,g=t.w*t.w,y=l-p-v+g,C=2*(c-_),E=2*(h+f),S=2*(c+_),w=-l+p-v+g,T=2*(m-d),b=2*(h-f),x=2*(m+d),P=-l-p+v+g;return n[0]=y*o,n[1]=S*o,n[2]=b*o,n[3]=0,n[4]=C*a,n[5]=w*a,n[6]=x*a,n[7]=0,n[8]=E*s,n[9]=T*s,n[10]=P*s,n[11]=0,n[12]=e.x,n[13]=e.y,n[14]=e.z,n[15]=1,n},u.fromTranslation=function(e,t){return u.fromRotationTranslation(s.IDENTITY,e,t)},u.fromScale=function(e,t){return i(t)?(t[0]=e.x,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e.y,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e.z,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t):new u(e.x,0,0,0,0,e.y,0,0,0,0,e.z,0,0,0,0,1)},u.fromUniformScale=function(e,t){return i(t)?(t[0]=e,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=e,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=e,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t):new u(e,0,0,0,0,e,0,0,0,0,e,0,0,0,0,1)};var c=new e,h=new e,d=new e;u.fromCamera=function(t,r){var n=t.eye,o=t.target,a=t.up;e.normalize(e.subtract(o,n,c),c),e.normalize(e.cross(c,a,h),h),e.normalize(e.cross(h,c,d),d);var s=h.x,l=h.y,p=h.z,m=c.x,f=c.y,v=c.z,_=d.x,g=d.y,y=d.z,C=n.x,E=n.y,S=n.z,w=s*-C+l*-E+p*-S,T=_*-C+g*-E+y*-S,b=m*C+f*E+v*S;return i(r)?(r[0]=s,r[1]=_,r[2]=-m,r[3]=0,r[4]=l,r[5]=g,r[6]=-f,r[7]=0,r[8]=p,r[9]=y,r[10]=-v,r[11]=0,r[12]=w,r[13]=T,r[14]=b,r[15]=1,r):new u(s,l,p,w,_,g,y,T,-m,-f,-v,b,0,0,0,1)},u.computePerspectiveFieldOfView=function(e,t,r,i,n){var o=Math.tan(.5*e),a=1/o,s=a/t,l=(i+r)/(r-i),u=2*i*r/(r-i);return n[0]=s,n[1]=0,n[2]=0,n[3]=0,n[4]=0,n[5]=a,n[6]=0,n[7]=0,n[8]=0,n[9]=0,n[10]=l,n[11]=-1,n[12]=0,n[13]=0,n[14]=u,n[15]=0,n},u.computeOrthographicOffCenter=function(e,t,r,i,n,o,a){var s=1/(t-e),l=1/(i-r),u=1/(o-n),c=-(t+e)*s,h=-(i+r)*l,d=-(o+n)*u;return s*=2,l*=2,u*=-2,a[0]=s,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=l,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=u,a[11]=0,a[12]=c,a[13]=h,a[14]=d,a[15]=1,a},u.computePerspectiveOffCenter=function(e,t,r,i,n,o,a){var s=2*n/(t-e),l=2*n/(i-r),u=(t+e)/(t-e),c=(i+r)/(i-r),h=-(o+n)/(o-n),d=-1,p=-2*o*n/(o-n);return a[0]=s,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=l,a[6]=0,a[7]=0,a[8]=u,a[9]=c,a[10]=h,a[11]=d,a[12]=0,a[13]=0,a[14]=p,a[15]=0,a},u.computeInfinitePerspectiveOffCenter=function(e,t,r,i,n,o){var a=2*n/(t-e),s=2*n/(i-r),l=(t+e)/(t-e),u=(i+r)/(i-r),c=-1,h=-1,d=-2*n;return o[0]=a,o[1]=0,o[2]=0,o[3]=0,o[4]=0,o[5]=s,o[6]=0,o[7]=0,o[8]=l,o[9]=u,o[10]=c,o[11]=h,o[12]=0,o[13]=0,o[14]=d,o[15]=0,o},u.computeViewportTransformation=function(e,t,i,n){e=r(e,r.EMPTY_OBJECT);var o=r(e.x,0),a=r(e.y,0),s=r(e.width,0),l=r(e.height,0);t=r(t,0),i=r(i,1);var u=.5*s,c=.5*l,h=.5*(i-t),d=u,p=c,m=h,f=o+u,v=a+c,_=t+h,g=1;return n[0]=d,n[1]=0,n[2]=0,n[3]=0,n[4]=0,n[5]=p,n[6]=0,n[7]=0,n[8]=0,n[9]=0,n[10]=m,n[11]=0,n[12]=f,n[13]=v,n[14]=_,n[15]=g,n},u.toArray=function(e,t){return i(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t):[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8],e[9],e[10],e[11],e[12],e[13],e[14],e[15]]},u.getElementIndex=function(e,t){return 4*e+t},u.getColumn=function(e,t,r){var i=4*t,n=e[i],o=e[i+1],a=e[i+2],s=e[i+3];return r.x=n,r.y=o,r.z=a,r.w=s,r},u.setColumn=function(e,t,r,i){i=u.clone(e,i);var n=4*t;return i[n]=r.x,i[n+1]=r.y,i[n+2]=r.z,i[n+3]=r.w,i},u.setTranslation=function(e,t,r){return r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=e[3],r[4]=e[4],r[5]=e[5],r[6]=e[6],r[7]=e[7],r[8]=e[8],r[9]=e[9],r[10]=e[10],r[11]=e[11],r[12]=t.x,r[13]=t.y,r[14]=t.z,r[15]=e[15],r},u.getRow=function(e,t,r){var i=e[t],n=e[t+4],o=e[t+8],a=e[t+12];return r.x=i,r.y=n,r.z=o,r.w=a,r},u.setRow=function(e,t,r,i){return i=u.clone(e,i),i[t]=r.x,i[t+4]=r.y,i[t+8]=r.z,i[t+12]=r.w,i};var p=new e;u.getScale=function(t,r){return r.x=e.magnitude(e.fromElements(t[0],t[1],t[2],p)),r.y=e.magnitude(e.fromElements(t[4],t[5],t[6],p)),r.z=e.magnitude(e.fromElements(t[8],t[9],t[10],p)),r};var m=new e;u.getMaximumScale=function(t){return u.getScale(t,m),e.maximumComponent(m)},u.multiply=function(e,t,r){var i=e[0],n=e[1],o=e[2],a=e[3],s=e[4],l=e[5],u=e[6],c=e[7],h=e[8],d=e[9],p=e[10],m=e[11],f=e[12],v=e[13],_=e[14],g=e[15],y=t[0],C=t[1],E=t[2],S=t[3],w=t[4],T=t[5],b=t[6],x=t[7],P=t[8],A=t[9],I=t[10],M=t[11],D=t[12],R=t[13],O=t[14],N=t[15],L=i*y+s*C+h*E+f*S,F=n*y+l*C+d*E+v*S,B=o*y+u*C+p*E+_*S,V=a*y+c*C+m*E+g*S,z=i*w+s*T+h*b+f*x,k=n*w+l*T+d*b+v*x,U=o*w+u*T+p*b+_*x,G=a*w+c*T+m*b+g*x,W=i*P+s*A+h*I+f*M,H=n*P+l*A+d*I+v*M,q=o*P+u*A+p*I+_*M,j=a*P+c*A+m*I+g*M,Y=i*D+s*R+h*O+f*N,X=n*D+l*R+d*O+v*N,Z=o*D+u*R+p*O+_*N,K=a*D+c*R+m*O+g*N;return r[0]=L,r[1]=F,r[2]=B,r[3]=V,r[4]=z,r[5]=k,r[6]=U,r[7]=G,r[8]=W,r[9]=H,r[10]=q,r[11]=j,r[12]=Y,r[13]=X,r[14]=Z,r[15]=K,r},u.add=function(e,t,r){return r[0]=e[0]+t[0],r[1]=e[1]+t[1],r[2]=e[2]+t[2],r[3]=e[3]+t[3],r[4]=e[4]+t[4],r[5]=e[5]+t[5],r[6]=e[6]+t[6],r[7]=e[7]+t[7],r[8]=e[8]+t[8],r[9]=e[9]+t[9],r[10]=e[10]+t[10],r[11]=e[11]+t[11],r[12]=e[12]+t[12],r[13]=e[13]+t[13],r[14]=e[14]+t[14],r[15]=e[15]+t[15],r},u.subtract=function(e,t,r){return r[0]=e[0]-t[0],r[1]=e[1]-t[1],r[2]=e[2]-t[2],r[3]=e[3]-t[3],r[4]=e[4]-t[4],r[5]=e[5]-t[5],r[6]=e[6]-t[6],r[7]=e[7]-t[7],r[8]=e[8]-t[8],r[9]=e[9]-t[9],r[10]=e[10]-t[10],r[11]=e[11]-t[11],r[12]=e[12]-t[12],r[13]=e[13]-t[13],r[14]=e[14]-t[14],r[15]=e[15]-t[15],r},u.multiplyTransformation=function(e,t,r){var i=e[0],n=e[1],o=e[2],a=e[4],s=e[5],l=e[6],u=e[8],c=e[9],h=e[10],d=e[12],p=e[13],m=e[14],f=t[0],v=t[1],_=t[2],g=t[4],y=t[5],C=t[6],E=t[8],S=t[9],w=t[10],T=t[12],b=t[13],x=t[14],P=i*f+a*v+u*_,A=n*f+s*v+c*_,I=o*f+l*v+h*_,M=i*g+a*y+u*C,D=n*g+s*y+c*C,R=o*g+l*y+h*C,O=i*E+a*S+u*w,N=n*E+s*S+c*w,L=o*E+l*S+h*w,F=i*T+a*b+u*x+d,B=n*T+s*b+c*x+p,V=o*T+l*b+h*x+m;return r[0]=P,r[1]=A,r[2]=I,r[3]=0,r[4]=M,r[5]=D,r[6]=R,r[7]=0,r[8]=O,r[9]=N,r[10]=L,r[11]=0,r[12]=F,r[13]=B,r[14]=V,r[15]=1,r},u.multiplyByMatrix3=function(e,t,r){var i=e[0],n=e[1],o=e[2],a=e[4],s=e[5],l=e[6],u=e[8],c=e[9],h=e[10],d=t[0],p=t[1],m=t[2],f=t[3],v=t[4],_=t[5],g=t[6],y=t[7],C=t[8],E=i*d+a*p+u*m,S=n*d+s*p+c*m,w=o*d+l*p+h*m,T=i*f+a*v+u*_,b=n*f+s*v+c*_,x=o*f+l*v+h*_,P=i*g+a*y+u*C,A=n*g+s*y+c*C,I=o*g+l*y+h*C;return r[0]=E,r[1]=S,r[2]=w,r[3]=0,r[4]=T,r[5]=b,r[6]=x,r[7]=0,r[8]=P,r[9]=A,r[10]=I,r[11]=0,r[12]=e[12],r[13]=e[13],r[14]=e[14],r[15]=e[15],r},u.multiplyByTranslation=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=i*e[0]+n*e[4]+o*e[8]+e[12],s=i*e[1]+n*e[5]+o*e[9]+e[13],l=i*e[2]+n*e[6]+o*e[10]+e[14];return r[0]=e[0],r[1]=e[1],r[2]=e[2],r[3]=e[3],r[4]=e[4],r[5]=e[5],r[6]=e[6],r[7]=e[7],r[8]=e[8],r[9]=e[9],r[10]=e[10],r[11]=e[11],r[12]=a,r[13]=s,r[14]=l,r[15]=e[15],r};var f=new e;u.multiplyByUniformScale=function(e,t,r){return f.x=t,f.y=t,f.z=t,u.multiplyByScale(e,f,r)},u.multiplyByScale=function(e,t,r){var i=t.x,n=t.y,o=t.z;return 1===i&&1===n&&1===o?u.clone(e,r):(r[0]=i*e[0],r[1]=i*e[1],r[2]=i*e[2],r[3]=0,r[4]=n*e[4],r[5]=n*e[5],r[6]=n*e[6],r[7]=0,r[8]=o*e[8],r[9]=o*e[9],r[10]=o*e[10],r[11]=0,r[12]=e[12],r[13]=e[13],r[14]=e[14],r[15]=1,r)},u.multiplyByVector=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=t.w,s=e[0]*i+e[4]*n+e[8]*o+e[12]*a,l=e[1]*i+e[5]*n+e[9]*o+e[13]*a,u=e[2]*i+e[6]*n+e[10]*o+e[14]*a,c=e[3]*i+e[7]*n+e[11]*o+e[15]*a;return r.x=s,r.y=l,r.z=u,r.w=c,r},u.multiplyByPointAsVector=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=e[0]*i+e[4]*n+e[8]*o,s=e[1]*i+e[5]*n+e[9]*o,l=e[2]*i+e[6]*n+e[10]*o;return r.x=a,r.y=s,r.z=l,r},u.multiplyByPoint=function(e,t,r){var i=t.x,n=t.y,o=t.z,a=e[0]*i+e[4]*n+e[8]*o+e[12],s=e[1]*i+e[5]*n+e[9]*o+e[13],l=e[2]*i+e[6]*n+e[10]*o+e[14];return r.x=a,r.y=s,r.z=l,r},u.multiplyByScalar=function(e,t,r){return r[0]=e[0]*t,r[1]=e[1]*t,r[2]=e[2]*t,r[3]=e[3]*t,r[4]=e[4]*t,r[5]=e[5]*t,r[6]=e[6]*t,r[7]=e[7]*t,r[8]=e[8]*t,r[9]=e[9]*t,r[10]=e[10]*t,r[11]=e[11]*t,r[12]=e[12]*t,r[13]=e[13]*t,r[14]=e[14]*t,r[15]=e[15]*t,r},u.negate=function(e,t){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t[4]=-e[4],t[5]=-e[5],t[6]=-e[6],t[7]=-e[7],t[8]=-e[8],t[9]=-e[9],t[10]=-e[10],t[11]=-e[11],t[12]=-e[12],t[13]=-e[13],t[14]=-e[14],t[15]=-e[15],t},u.transpose=function(e,t){var r=e[1],i=e[2],n=e[3],o=e[6],a=e[7],s=e[11];return t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=r,t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=i,t[9]=o,t[10]=e[10],t[11]=e[14],t[12]=n,t[13]=a,t[14]=s,t[15]=e[15],t},u.abs=function(e,t){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t[3]=Math.abs(e[3]),t[4]=Math.abs(e[4]),t[5]=Math.abs(e[5]),t[6]=Math.abs(e[6]),t[7]=Math.abs(e[7]),t[8]=Math.abs(e[8]),t[9]=Math.abs(e[9]),t[10]=Math.abs(e[10]),t[11]=Math.abs(e[11]),t[12]=Math.abs(e[12]),t[13]=Math.abs(e[13]),t[14]=Math.abs(e[14]),t[15]=Math.abs(e[15]),t},u.equals=function(e,t){return e===t||i(e)&&i(t)&&e[12]===t[12]&&e[13]===t[13]&&e[14]===t[14]&&e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[4]===t[4]&&e[5]===t[5]&&e[6]===t[6]&&e[8]===t[8]&&e[9]===t[9]&&e[10]===t[10]&&e[3]===t[3]&&e[7]===t[7]&&e[11]===t[11]&&e[15]===t[15]},u.equalsEpsilon=function(e,t,r){return e===t||i(e)&&i(t)&&Math.abs(e[0]-t[0])<=r&&Math.abs(e[1]-t[1])<=r&&Math.abs(e[2]-t[2])<=r&&Math.abs(e[3]-t[3])<=r&&Math.abs(e[4]-t[4])<=r&&Math.abs(e[5]-t[5])<=r&&Math.abs(e[6]-t[6])<=r&&Math.abs(e[7]-t[7])<=r&&Math.abs(e[8]-t[8])<=r&&Math.abs(e[9]-t[9])<=r&&Math.abs(e[10]-t[10])<=r&&Math.abs(e[11]-t[11])<=r&&Math.abs(e[12]-t[12])<=r&&Math.abs(e[13]-t[13])<=r&&Math.abs(e[14]-t[14])<=r&&Math.abs(e[15]-t[15])<=r},u.getTranslation=function(e,t){return t.x=e[12],t.y=e[13],t.z=e[14],t},u.getRotation=function(e,t){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t};var v=new s,_=new s,g=new t,y=new t(0,0,0,1);return u.inverse=function(e,r){if(s.equalsEpsilon(u.getRotation(e,v),_,a.EPSILON7)&&t.equals(u.getRow(e,3,g),y))return r[0]=0,r[1]=0,r[2]=0,r[3]=0,r[4]=0,r[5]=0,r[6]=0,r[7]=0,r[8]=0,r[9]=0,r[10]=0,r[11]=0,r[12]=-e[12],r[13]=-e[13],r[14]=-e[14],r[15]=1,r;var i=e[0],n=e[4],o=e[8],c=e[12],h=e[1],d=e[5],p=e[9],m=e[13],f=e[2],C=e[6],E=e[10],S=e[14],w=e[3],T=e[7],b=e[11],x=e[15],P=E*x,A=S*b,I=C*x,M=S*T,D=C*b,R=E*T,O=f*x,N=S*w,L=f*b,F=E*w,B=f*T,V=C*w,z=P*d+M*p+D*m-(A*d+I*p+R*m),k=A*h+O*p+F*m-(P*h+N*p+L*m),U=I*h+N*d+B*m-(M*h+O*d+V*m),G=R*h+L*d+V*p-(D*h+F*d+B*p),W=A*n+I*o+R*c-(P*n+M*o+D*c),H=P*i+N*o+L*c-(A*i+O*o+F*c),q=M*i+O*n+V*c-(I*i+N*n+B*c),j=D*i+F*n+B*o-(R*i+L*n+V*o);P=o*m,A=c*p,I=n*m,M=c*d,D=n*p,R=o*d,O=i*m,N=c*h,L=i*p,F=o*h,B=i*d,V=n*h;var Y=P*T+M*b+D*x-(A*T+I*b+R*x),X=A*w+O*b+F*x-(P*w+N*b+L*x),Z=I*w+N*T+B*x-(M*w+O*T+V*x),K=R*w+L*T+V*b-(D*w+F*T+B*b),J=I*E+R*S+A*C-(D*S+P*C+M*E),Q=L*S+P*f+N*E-(O*E+F*S+A*f),$=O*C+V*S+M*f-(B*S+I*f+N*C),ee=B*E+D*f+F*C-(L*C+V*E+R*f),te=i*z+n*k+o*U+c*G;if(Math.abs(te)<a.EPSILON20)throw new l("matrix is not invertible because its determinate is zero.");return te=1/te,r[0]=z*te,r[1]=k*te,r[2]=U*te,r[3]=G*te,r[4]=W*te,r[5]=H*te,r[6]=q*te,r[7]=j*te,r[8]=Y*te,r[9]=X*te,r[10]=Z*te,r[11]=K*te,r[12]=J*te,r[13]=Q*te,r[14]=$*te,r[15]=ee*te,r},u.inverseTransformation=function(e,t){var r=e[0],i=e[1],n=e[2],o=e[4],a=e[5],s=e[6],l=e[8],u=e[9],c=e[10],h=e[12],d=e[13],p=e[14],m=-r*h-i*d-n*p,f=-o*h-a*d-s*p,v=-l*h-u*d-c*p;return t[0]=r,t[1]=o,t[2]=l,t[3]=0,t[4]=i,t[5]=a,t[6]=u,t[7]=0,t[8]=n,t[9]=s,t[10]=c,t[11]=0,t[12]=m,t[13]=f,t[14]=v,t[15]=1,t},u.IDENTITY=o(new u(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)),u.ZERO=o(new u(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)),u.COLUMN0ROW0=0,u.COLUMN0ROW1=1,u.COLUMN0ROW2=2,u.COLUMN0ROW3=3,u.COLUMN1ROW0=4,u.COLUMN1ROW1=5,u.COLUMN1ROW2=6,u.COLUMN1ROW3=7,u.COLUMN2ROW0=8,u.COLUMN2ROW1=9,u.COLUMN2ROW2=10,u.COLUMN2ROW3=11,u.COLUMN3ROW0=12,u.COLUMN3ROW1=13,u.COLUMN3ROW2=14,u.COLUMN3ROW3=15,u.prototype.clone=function(e){return u.clone(this,e)},u.prototype.equals=function(e){return u.equals(this,e)},u.equalsArray=function(e,t,r){return e[0]===t[r]&&e[1]===t[r+1]&&e[2]===t[r+2]&&e[3]===t[r+3]&&e[4]===t[r+4]&&e[5]===t[r+5]&&e[6]===t[r+6]&&e[7]===t[r+7]&&e[8]===t[r+8]&&e[9]===t[r+9]&&e[10]===t[r+10]&&e[11]===t[r+11]&&e[12]===t[r+12]&&e[13]===t[r+13]&&e[14]===t[r+14]&&e[15]===t[r+15]},u.prototype.equalsEpsilon=function(e,t){return u.equalsEpsilon(this,e,t)},u.prototype.toString=function(){return"("+this[0]+", "+this[4]+", "+this[8]+", "+this[12]+")\n("+this[1]+", "+this[5]+", "+this[9]+", "+this[13]+")\n("+this[2]+", "+this[6]+", "+this[10]+", "+this[14]+")\n("+this[3]+", "+this[7]+", "+this[11]+", "+this[15]+")"},u}),r("Core/BoundingSphere",["./Cartesian3","./Cartographic","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Ellipsoid","./GeographicProjection","./Intersect","./Interval","./Matrix3","./Matrix4","./Plane","./Rectangle"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(t,i){this.center=e.clone(r(t,e.ZERO)),this.radius=r(i,0)},f=new e,v=new e,_=new e,g=new e,y=new e,C=new e,E=new e,S=new e,w=new e,T=new e,b=new e,x=new e;m.fromPoints=function(t,r){if(i(r)||(r=new m),!i(t)||0===t.length)return r.center=e.clone(e.ZERO,r.center),r.radius=0,r;for(var n=e.clone(t[0],E),o=e.clone(n,f),a=e.clone(n,v),s=e.clone(n,_),l=e.clone(n,g),u=e.clone(n,y),c=e.clone(n,C),h=t.length,d=1;h>d;d++){e.clone(t[d],n);var p=n.x,P=n.y,A=n.z;p<o.x&&e.clone(n,o),p>l.x&&e.clone(n,l),P<a.y&&e.clone(n,a),P>u.y&&e.clone(n,u),A<s.z&&e.clone(n,s),A>c.z&&e.clone(n,c)}var I=e.magnitudeSquared(e.subtract(l,o,S)),M=e.magnitudeSquared(e.subtract(u,a,S)),D=e.magnitudeSquared(e.subtract(c,s,S)),R=o,O=l,N=I;M>N&&(N=M,R=a,O=u),D>N&&(N=D,R=s,O=c);var L=w;L.x=.5*(R.x+O.x),L.y=.5*(R.y+O.y),L.z=.5*(R.z+O.z);var F=e.magnitudeSquared(e.subtract(O,L,S)),B=Math.sqrt(F),V=T;V.x=o.x,V.y=a.y,V.z=s.z;var z=b;z.x=l.x,z.y=u.y,z.z=c.z;var k=e.multiplyByScalar(e.add(V,z,S),.5,x),U=0;for(d=0;h>d;d++){e.clone(t[d],n);var G=e.magnitude(e.subtract(n,k,S));G>U&&(U=G);var W=e.magnitudeSquared(e.subtract(n,L,S));if(W>F){var H=Math.sqrt(W);B=.5*(B+H),F=B*B;var q=H-B;L.x=(B*L.x+q*n.x)/H,L.y=(B*L.y+q*n.y)/H,L.z=(B*L.z+q*n.z)/H}}return U>B?(e.clone(L,r.center),r.radius=B):(e.clone(k,r.center),r.radius=U),r};var P=new s,A=new e,I=new e,M=new t,D=new t;m.fromRectangle2D=function(e,t,r){return m.fromRectangleWithHeights2D(e,t,0,0,r)},m.fromRectangleWithHeights2D=function(t,n,o,a,s){if(i(s)||(s=new m),!i(t))return s.center=e.clone(e.ZERO,s.center),s.radius=0,s;n=r(n,P),p.southwest(t,M),M.height=o,p.northeast(t,D),D.height=a;var l=n.project(M,A),u=n.project(D,I),c=u.x-l.x,h=u.y-l.y,d=u.z-l.z;s.radius=.5*Math.sqrt(c*c+h*h+d*d);var f=s.center;return f.x=l.x+.5*c,f.y=l.y+.5*h,f.z=l.z+.5*d,s};var R=[];m.fromRectangle3D=function(e,t,n,o){t=r(t,a.WGS84),n=r(n,0);var s;return i(e)&&(s=p.subsample(e,t,n,R)),m.fromPoints(s,o)},m.fromVertices=function(t,n,o,a){if(i(a)||(a=new m),!i(t)||0===t.length)return a.center=e.clone(e.ZERO,a.center),a.radius=0,a;n=r(n,e.ZERO),o=r(o,3);var s=E;s.x=t[0]+n.x,s.y=t[1]+n.y,s.z=t[2]+n.z;for(var l=e.clone(s,f),u=e.clone(s,v),c=e.clone(s,_),h=e.clone(s,g),d=e.clone(s,y),p=e.clone(s,C),P=t.length,A=0;P>A;A+=o){var I=t[A]+n.x,M=t[A+1]+n.y,D=t[A+2]+n.z;s.x=I,s.y=M,s.z=D,I<l.x&&e.clone(s,l),I>h.x&&e.clone(s,h),M<u.y&&e.clone(s,u),M>d.y&&e.clone(s,d),D<c.z&&e.clone(s,c),D>p.z&&e.clone(s,p)}var R=e.magnitudeSquared(e.subtract(h,l,S)),O=e.magnitudeSquared(e.subtract(d,u,S)),N=e.magnitudeSquared(e.subtract(p,c,S)),L=l,F=h,B=R;O>B&&(B=O,L=u,F=d),N>B&&(B=N,L=c,F=p);var V=w;V.x=.5*(L.x+F.x),V.y=.5*(L.y+F.y),V.z=.5*(L.z+F.z);var z=e.magnitudeSquared(e.subtract(F,V,S)),k=Math.sqrt(z),U=T;U.x=l.x,U.y=u.y,U.z=c.z;var G=b;G.x=h.x,G.y=d.y,G.z=p.z;var W=e.multiplyByScalar(e.add(U,G,S),.5,x),H=0;for(A=0;P>A;A+=o){s.x=t[A]+n.x,s.y=t[A+1]+n.y,s.z=t[A+2]+n.z;var q=e.magnitude(e.subtract(s,W,S));q>H&&(H=q);var j=e.magnitudeSquared(e.subtract(s,V,S));if(j>z){var Y=Math.sqrt(j);k=.5*(k+Y),z=k*k;var X=Y-k;V.x=(k*V.x+X*s.x)/Y,V.y=(k*V.y+X*s.y)/Y,V.z=(k*V.z+X*s.z)/Y}}return H>k?(e.clone(V,a.center),a.radius=k):(e.clone(W,a.center),a.radius=H),a},m.fromCornerPoints=function(t,r,n){i(n)||(n=new m);var o=n.center;return e.add(t,r,o),e.multiplyByScalar(o,.5,o),n.radius=e.distance(o,r),n},m.fromEllipsoid=function(t,r){return i(r)||(r=new m),e.clone(e.ZERO,r.center),r.radius=t.maximumRadius,r};var O=new e;m.fromBoundingSpheres=function(t,r){if(i(r)||(r=new m),!i(t)||0===t.length)return r.center=e.clone(e.ZERO,r.center),r.radius=0,r;var n=t.length;if(1===n)return m.clone(t[0],r);if(2===n)return m.union(t[0],t[1],r);for(var o=[],a=0;n>a;a++)o.push(t[a].center);r=m.fromPoints(o,r);var s=r.center,l=r.radius;for(a=0;n>a;a++){var u=t[a];l=Math.max(l,e.distance(s,u.center,O)+u.radius)}return r.radius=l,r};var N=new e,L=new e,F=new e;m.fromOrientedBoundingBox=function(t,r){i(r)||(r=new m);var n=t.halfAxes,o=c.getColumn(n,0,N),a=c.getColumn(n,1,L),s=c.getColumn(n,2,F),l=e.magnitude(o),u=e.magnitude(a),h=e.magnitude(s);return r.center=e.clone(t.center,r.center),r.radius=Math.max(l,u,h),r},m.clone=function(t,r){return i(t)?i(r)?(r.center=e.clone(t.center,r.center),r.radius=t.radius,r):new m(t.center,t.radius):void 0},m.packedLength=4,m.pack=function(e,t,i){i=r(i,0);var n=e.center;t[i++]=n.x,t[i++]=n.y,t[i++]=n.z,t[i]=e.radius},m.unpack=function(e,t,n){t=r(t,0),i(n)||(n=new m);var o=n.center;return o.x=e[t++],o.y=e[t++],o.z=e[t++],n.radius=e[t],n};var B=new e,V=new e;m.union=function(t,r,n){i(n)||(n=new m);var o=t.center,a=t.radius,s=r.center,l=r.radius,u=e.subtract(s,o,B),c=e.magnitude(u);if(a>=c+l)return t.clone(n),n;if(l>=c+a)return r.clone(n),n;var h=.5*(a+c+l),d=e.multiplyByScalar(u,(-a+h)/c,V);return e.add(d,o,d),e.clone(d,n.center),n.radius=h,n};var z=new e;m.expand=function(t,r,i){i=m.clone(t,i);var n=e.magnitude(e.subtract(r,i.center,z));return n>i.radius&&(i.radius=n),i},m.intersectPlane=function(t,r){var i=t.center,n=t.radius,o=r.normal,a=e.dot(o,i)+r.distance;return-n>a?l.OUTSIDE:n>a?l.INTERSECTING:l.INSIDE},m.transform=function(e,t,r){return i(r)||(r=new m),r.center=h.multiplyByPoint(t,e.center,r.center),r.radius=h.getMaximumScale(t)*e.radius,r};var k=new e;m.distanceSquaredTo=function(t,r){var i=e.subtract(t.center,r,k);return e.magnitudeSquared(i)-t.radius*t.radius},m.transformWithoutScale=function(e,t,r){return i(r)||(r=new m),r.center=h.multiplyByPoint(t,e.center,r.center),r.radius=e.radius,r};var U=new e;m.computePlaneDistances=function(t,r,n,o){i(o)||(o=new u);var a=e.subtract(t.center,r,U),s=e.dot(n,a);return o.start=s-t.radius,o.stop=s+t.radius,o};for(var G=new e,W=new e,H=new e,q=new e,j=new e,Y=new t,X=new Array(8),Z=0;8>Z;++Z)X[Z]=new e;var K=new s;return m.projectTo2D=function(t,i,n){i=r(i,K);var o=i.ellipsoid,a=t.center,s=t.radius,l=o.geodeticSurfaceNormal(a,G),u=e.cross(e.UNIT_Z,l,W);e.normalize(u,u);var c=e.cross(l,u,H);e.normalize(c,c),e.multiplyByScalar(l,s,l),e.multiplyByScalar(c,s,c),e.multiplyByScalar(u,s,u);var h=e.negate(c,j),d=e.negate(u,q),p=X,f=p[0];e.add(l,c,f),e.add(f,u,f),f=p[1],e.add(l,c,f),e.add(f,d,f),f=p[2],e.add(l,h,f),e.add(f,d,f),f=p[3],e.add(l,h,f),e.add(f,u,f),e.negate(l,l),f=p[4],e.add(l,c,f),e.add(f,u,f),f=p[5],e.add(l,c,f),e.add(f,d,f),f=p[6],e.add(l,h,f),e.add(f,d,f),f=p[7],e.add(l,h,f),e.add(f,u,f);for(var v=p.length,_=0;v>_;++_){var g=p[_];e.add(a,g,g);var y=o.cartesianToCartographic(g,Y);i.project(y,g)}n=m.fromPoints(p,n),a=n.center;var C=a.x,E=a.y,S=a.z;return a.x=S,a.y=C,a.z=E,n},m.isOccluded=function(e,t){return!t.isBoundingSphereVisible(e)},m.equals=function(t,r){return t===r||i(t)&&i(r)&&e.equals(t.center,r.center)&&t.radius===r.radius},m.prototype.intersectPlane=function(e){return m.intersectPlane(this,e)},m.prototype.distanceSquaredTo=function(e){return m.distanceSquaredTo(this,e)},m.prototype.computePlaneDistances=function(e,t,r){return m.computePlaneDistances(this,e,t,r)},m.prototype.isOccluded=function(e){return m.isOccluded(this,e)},m.prototype.equals=function(e){return m.equals(this,e)},m.prototype.clone=function(e){return m.clone(this,e)},m}),r("Renderer/WebGLConstants",["../Core/freezeObject"],function(e){"use strict";var t={DEPTH_BUFFER_BIT:256,STENCIL_BUFFER_BIT:1024,COLOR_BUFFER_BIT:16384,POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6,ZERO:0,ONE:1,SRC_COLOR:768,ONE_MINUS_SRC_COLOR:769,SRC_ALPHA:770,ONE_MINUS_SRC_ALPHA:771,DST_ALPHA:772,ONE_MINUS_DST_ALPHA:773,DST_COLOR:774,ONE_MINUS_DST_COLOR:775,SRC_ALPHA_SATURATE:776,FUNC_ADD:32774,BLEND_EQUATION:32777,BLEND_EQUATION_RGB:32777,BLEND_EQUATION_ALPHA:34877,FUNC_SUBTRACT:32778,FUNC_REVERSE_SUBTRACT:32779,BLEND_DST_RGB:32968,BLEND_SRC_RGB:32969,BLEND_DST_ALPHA:32970,BLEND_SRC_ALPHA:32971,CONSTANT_COLOR:32769,ONE_MINUS_CONSTANT_COLOR:32770,CONSTANT_ALPHA:32771,ONE_MINUS_CONSTANT_ALPHA:32772,BLEND_COLOR:32773,ARRAY_BUFFER:34962,ELEMENT_ARRAY_BUFFER:34963,ARRAY_BUFFER_BINDING:34964,ELEMENT_ARRAY_BUFFER_BINDING:34965,STREAM_DRAW:35040,STATIC_DRAW:35044,DYNAMIC_DRAW:35048,BUFFER_SIZE:34660,BUFFER_USAGE:34661,CURRENT_VERTEX_ATTRIB:34342,FRONT:1028,BACK:1029,FRONT_AND_BACK:1032,CULL_FACE:2884,BLEND:3042,DITHER:3024,STENCIL_TEST:2960,DEPTH_TEST:2929,SCISSOR_TEST:3089,POLYGON_OFFSET_FILL:32823,SAMPLE_ALPHA_TO_COVERAGE:32926,SAMPLE_COVERAGE:32928,NO_ERROR:0,INVALID_ENUM:1280,INVALID_VALUE:1281,INVALID_OPERATION:1282,OUT_OF_MEMORY:1285,CW:2304,CCW:2305,LINE_WIDTH:2849,ALIASED_POINT_SIZE_RANGE:33901,ALIASED_LINE_WIDTH_RANGE:33902,CULL_FACE_MODE:2885,FRONT_FACE:2886,DEPTH_RANGE:2928,DEPTH_WRITEMASK:2930,DEPTH_CLEAR_VALUE:2931,DEPTH_FUNC:2932,STENCIL_CLEAR_VALUE:2961,STENCIL_FUNC:2962,STENCIL_FAIL:2964,STENCIL_PASS_DEPTH_FAIL:2965,STENCIL_PASS_DEPTH_PASS:2966,STENCIL_REF:2967,STENCIL_VALUE_MASK:2963,STENCIL_WRITEMASK:2968,STENCIL_BACK_FUNC:34816,STENCIL_BACK_FAIL:34817,STENCIL_BACK_PASS_DEPTH_FAIL:34818,STENCIL_BACK_PASS_DEPTH_PASS:34819,STENCIL_BACK_REF:36003,STENCIL_BACK_VALUE_MASK:36004,STENCIL_BACK_WRITEMASK:36005,VIEWPORT:2978,SCISSOR_BOX:3088,COLOR_CLEAR_VALUE:3106,COLOR_WRITEMASK:3107,UNPACK_ALIGNMENT:3317,PACK_ALIGNMENT:3333,MAX_TEXTURE_SIZE:3379,MAX_VIEWPORT_DIMS:3386,SUBPIXEL_BITS:3408,RED_BITS:3410,GREEN_BITS:3411,BLUE_BITS:3412,ALPHA_BITS:3413,DEPTH_BITS:3414,STENCIL_BITS:3415,POLYGON_OFFSET_UNITS:10752,POLYGON_OFFSET_FACTOR:32824,TEXTURE_BINDING_2D:32873,SAMPLE_BUFFERS:32936,SAMPLES:32937,SAMPLE_COVERAGE_VALUE:32938,SAMPLE_COVERAGE_INVERT:32939,COMPRESSED_TEXTURE_FORMATS:34467,DONT_CARE:4352,FASTEST:4353,NICEST:4354,GENERATE_MIPMAP_HINT:33170,BYTE:5120,UNSIGNED_BYTE:5121,SHORT:5122,UNSIGNED_SHORT:5123,INT:5124,UNSIGNED_INT:5125,FLOAT:5126,DEPTH_COMPONENT:6402,ALPHA:6406,RGB:6407,RGBA:6408,LUMINANCE:6409,LUMINANCE_ALPHA:6410,UNSIGNED_SHORT_4_4_4_4:32819,UNSIGNED_SHORT_5_5_5_1:32820,UNSIGNED_SHORT_5_6_5:33635,FRAGMENT_SHADER:35632,VERTEX_SHADER:35633,MAX_VERTEX_ATTRIBS:34921,MAX_VERTEX_UNIFORM_VECTORS:36347,MAX_VARYING_VECTORS:36348,MAX_COMBINED_TEXTURE_IMAGE_UNITS:35661,MAX_VERTEX_TEXTURE_IMAGE_UNITS:35660,MAX_TEXTURE_IMAGE_UNITS:34930,MAX_FRAGMENT_UNIFORM_VECTORS:36349,SHADER_TYPE:35663,DELETE_STATUS:35712,LINK_STATUS:35714,VALIDATE_STATUS:35715,ATTACHED_SHADERS:35717,ACTIVE_UNIFORMS:35718,ACTIVE_ATTRIBUTES:35721,SHADING_LANGUAGE_VERSION:35724,CURRENT_PROGRAM:35725,NEVER:512,LESS:513,EQUAL:514,LEQUAL:515,GREATER:516,NOTEQUAL:517,GEQUAL:518,ALWAYS:519,KEEP:7680,REPLACE:7681,INCR:7682,DECR:7683,INVERT:5386,INCR_WRAP:34055,DECR_WRAP:34056,VENDOR:7936,RENDERER:7937,VERSION:7938,NEAREST:9728,LINEAR:9729,NEAREST_MIPMAP_NEAREST:9984,LINEAR_MIPMAP_NEAREST:9985,NEAREST_MIPMAP_LINEAR:9986,LINEAR_MIPMAP_LINEAR:9987,TEXTURE_MAG_FILTER:10240,TEXTURE_MIN_FILTER:10241,TEXTURE_WRAP_S:10242,TEXTURE_WRAP_T:10243,TEXTURE_2D:3553,TEXTURE:5890,TEXTURE_CUBE_MAP:34067,TEXTURE_BINDING_CUBE_MAP:34068,TEXTURE_CUBE_MAP_POSITIVE_X:34069,TEXTURE_CUBE_MAP_NEGATIVE_X:34070,TEXTURE_CUBE_MAP_POSITIVE_Y:34071,TEXTURE_CUBE_MAP_NEGATIVE_Y:34072,TEXTURE_CUBE_MAP_POSITIVE_Z:34073,TEXTURE_CUBE_MAP_NEGATIVE_Z:34074,MAX_CUBE_MAP_TEXTURE_SIZE:34076,TEXTURE0:33984,TEXTURE1:33985,TEXTURE2:33986,TEXTURE3:33987,TEXTURE4:33988,TEXTURE5:33989,TEXTURE6:33990,TEXTURE7:33991,TEXTURE8:33992,TEXTURE9:33993,TEXTURE10:33994,TEXTURE11:33995,TEXTURE12:33996,TEXTURE13:33997,TEXTURE14:33998,TEXTURE15:33999,TEXTURE16:34e3,TEXTURE17:34001,TEXTURE18:34002,TEXTURE19:34003,TEXTURE20:34004,TEXTURE21:34005,TEXTURE22:34006,TEXTURE23:34007,TEXTURE24:34008,TEXTURE25:34009,TEXTURE26:34010,TEXTURE27:34011,TEXTURE28:34012,TEXTURE29:34013,TEXTURE30:34014,TEXTURE31:34015,ACTIVE_TEXTURE:34016,REPEAT:10497,CLAMP_TO_EDGE:33071,MIRRORED_REPEAT:33648, -FLOAT_VEC2:35664,FLOAT_VEC3:35665,FLOAT_VEC4:35666,INT_VEC2:35667,INT_VEC3:35668,INT_VEC4:35669,BOOL:35670,BOOL_VEC2:35671,BOOL_VEC3:35672,BOOL_VEC4:35673,FLOAT_MAT2:35674,FLOAT_MAT3:35675,FLOAT_MAT4:35676,SAMPLER_2D:35678,SAMPLER_CUBE:35680,VERTEX_ATTRIB_ARRAY_ENABLED:34338,VERTEX_ATTRIB_ARRAY_SIZE:34339,VERTEX_ATTRIB_ARRAY_STRIDE:34340,VERTEX_ATTRIB_ARRAY_TYPE:34341,VERTEX_ATTRIB_ARRAY_NORMALIZED:34922,VERTEX_ATTRIB_ARRAY_POINTER:34373,VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:34975,IMPLEMENTATION_COLOR_READ_TYPE:35738,IMPLEMENTATION_COLOR_READ_FORMAT:35739,COMPILE_STATUS:35713,LOW_FLOAT:36336,MEDIUM_FLOAT:36337,HIGH_FLOAT:36338,LOW_INT:36339,MEDIUM_INT:36340,HIGH_INT:36341,FRAMEBUFFER:36160,RENDERBUFFER:36161,RGBA4:32854,RGB5_A1:32855,RGB565:36194,DEPTH_COMPONENT16:33189,STENCIL_INDEX:6401,STENCIL_INDEX8:36168,DEPTH_STENCIL:34041,RENDERBUFFER_WIDTH:36162,RENDERBUFFER_HEIGHT:36163,RENDERBUFFER_INTERNAL_FORMAT:36164,RENDERBUFFER_RED_SIZE:36176,RENDERBUFFER_GREEN_SIZE:36177,RENDERBUFFER_BLUE_SIZE:36178,RENDERBUFFER_ALPHA_SIZE:36179,RENDERBUFFER_DEPTH_SIZE:36180,RENDERBUFFER_STENCIL_SIZE:36181,FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:36048,FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:36049,FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:36050,FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:36051,COLOR_ATTACHMENT0:36064,DEPTH_ATTACHMENT:36096,STENCIL_ATTACHMENT:36128,DEPTH_STENCIL_ATTACHMENT:33306,NONE:0,FRAMEBUFFER_COMPLETE:36053,FRAMEBUFFER_INCOMPLETE_ATTACHMENT:36054,FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:36055,FRAMEBUFFER_INCOMPLETE_DIMENSIONS:36057,FRAMEBUFFER_UNSUPPORTED:36061,FRAMEBUFFER_BINDING:36006,RENDERBUFFER_BINDING:36007,MAX_RENDERBUFFER_SIZE:34024,INVALID_FRAMEBUFFER_OPERATION:1286,UNPACK_FLIP_Y_WEBGL:37440,UNPACK_PREMULTIPLY_ALPHA_WEBGL:37441,CONTEXT_LOST_WEBGL:37442,UNPACK_COLORSPACE_CONVERSION_WEBGL:37443,BROWSER_DEFAULT_WEBGL:37444,DOUBLE:5130,READ_BUFFER:3074,UNPACK_ROW_LENGTH:3314,UNPACK_SKIP_ROWS:3315,UNPACK_SKIP_PIXELS:3316,PACK_ROW_LENGTH:3330,PACK_SKIP_ROWS:3331,PACK_SKIP_PIXELS:3332,COLOR:6144,DEPTH:6145,STENCIL:6146,RED:6403,RGB8:32849,RGBA8:32856,RGB10_A2:32857,TEXTURE_BINDING_3D:32874,UNPACK_SKIP_IMAGES:32877,UNPACK_IMAGE_HEIGHT:32878,TEXTURE_3D:32879,TEXTURE_WRAP_R:32882,MAX_3D_TEXTURE_SIZE:32883,UNSIGNED_INT_2_10_10_10_REV:33640,MAX_ELEMENTS_VERTICES:33e3,MAX_ELEMENTS_INDICES:33001,TEXTURE_MIN_LOD:33082,TEXTURE_MAX_LOD:33083,TEXTURE_BASE_LEVEL:33084,TEXTURE_MAX_LEVEL:33085,MIN:32775,MAX:32776,DEPTH_COMPONENT24:33190,MAX_TEXTURE_LOD_BIAS:34045,TEXTURE_COMPARE_MODE:34892,TEXTURE_COMPARE_FUNC:34893,CURRENT_QUERY:34917,QUERY_RESULT:34918,QUERY_RESULT_AVAILABLE:34919,STREAM_READ:35041,STREAM_COPY:35042,STATIC_READ:35045,STATIC_COPY:35046,DYNAMIC_READ:35049,DYNAMIC_COPY:35050,MAX_DRAW_BUFFERS:34852,DRAW_BUFFER0:34853,DRAW_BUFFER1:34854,DRAW_BUFFER2:34855,DRAW_BUFFER3:34856,DRAW_BUFFER4:34857,DRAW_BUFFER5:34858,DRAW_BUFFER6:34859,DRAW_BUFFER7:34860,DRAW_BUFFER8:34861,DRAW_BUFFER9:34862,DRAW_BUFFER10:34863,DRAW_BUFFER11:34864,DRAW_BUFFER12:34865,DRAW_BUFFER13:34866,DRAW_BUFFER14:34867,DRAW_BUFFER15:34868,MAX_FRAGMENT_UNIFORM_COMPONENTS:35657,MAX_VERTEX_UNIFORM_COMPONENTS:35658,SAMPLER_3D:35679,SAMPLER_2D_SHADOW:35682,FRAGMENT_SHADER_DERIVATIVE_HINT:35723,PIXEL_PACK_BUFFER:35051,PIXEL_UNPACK_BUFFER:35052,PIXEL_PACK_BUFFER_BINDING:35053,PIXEL_UNPACK_BUFFER_BINDING:35055,FLOAT_MAT2x3:35685,FLOAT_MAT2x4:35686,FLOAT_MAT3x2:35687,FLOAT_MAT3x4:35688,FLOAT_MAT4x2:35689,FLOAT_MAT4x3:35690,SRGB:35904,SRGB8:35905,SRGB8_ALPHA8:35907,COMPARE_REF_TO_TEXTURE:34894,RGBA32F:34836,RGB32F:34837,RGBA16F:34842,RGB16F:34843,VERTEX_ATTRIB_ARRAY_INTEGER:35069,MAX_ARRAY_TEXTURE_LAYERS:35071,MIN_PROGRAM_TEXEL_OFFSET:35076,MAX_PROGRAM_TEXEL_OFFSET:35077,MAX_VARYING_COMPONENTS:35659,TEXTURE_2D_ARRAY:35866,TEXTURE_BINDING_2D_ARRAY:35869,R11F_G11F_B10F:35898,UNSIGNED_INT_10F_11F_11F_REV:35899,RGB9_E5:35901,UNSIGNED_INT_5_9_9_9_REV:35902,TRANSFORM_FEEDBACK_BUFFER_MODE:35967,MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:35968,TRANSFORM_FEEDBACK_VARYINGS:35971,TRANSFORM_FEEDBACK_BUFFER_START:35972,TRANSFORM_FEEDBACK_BUFFER_SIZE:35973,TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:35976,RASTERIZER_DISCARD:35977,MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:35978,MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:35979,INTERLEAVED_ATTRIBS:35980,SEPARATE_ATTRIBS:35981,TRANSFORM_FEEDBACK_BUFFER:35982,TRANSFORM_FEEDBACK_BUFFER_BINDING:35983,RGBA32UI:36208,RGB32UI:36209,RGBA16UI:36214,RGB16UI:36215,RGBA8UI:36220,RGB8UI:36221,RGBA32I:36226,RGB32I:36227,RGBA16I:36232,RGB16I:36233,RGBA8I:36238,RGB8I:36239,RED_INTEGER:36244,RGB_INTEGER:36248,RGBA_INTEGER:36249,SAMPLER_2D_ARRAY:36289,SAMPLER_2D_ARRAY_SHADOW:36292,SAMPLER_CUBE_SHADOW:36293,UNSIGNED_INT_VEC2:36294,UNSIGNED_INT_VEC3:36295,UNSIGNED_INT_VEC4:36296,INT_SAMPLER_2D:36298,INT_SAMPLER_3D:36299,INT_SAMPLER_CUBE:36300,INT_SAMPLER_2D_ARRAY:36303,UNSIGNED_INT_SAMPLER_2D:36306,UNSIGNED_INT_SAMPLER_3D:36307,UNSIGNED_INT_SAMPLER_CUBE:36308,UNSIGNED_INT_SAMPLER_2D_ARRAY:36311,DEPTH_COMPONENT32F:36012,DEPTH32F_STENCIL8:36013,FLOAT_32_UNSIGNED_INT_24_8_REV:36269,FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:33296,FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:33297,FRAMEBUFFER_ATTACHMENT_RED_SIZE:33298,FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:33299,FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:33300,FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:33301,FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:33302,FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:33303,FRAMEBUFFER_DEFAULT:33304,UNSIGNED_INT_24_8:34042,DEPTH24_STENCIL8:35056,UNSIGNED_NORMALIZED:35863,DRAW_FRAMEBUFFER_BINDING:36006,READ_FRAMEBUFFER:36008,DRAW_FRAMEBUFFER:36009,READ_FRAMEBUFFER_BINDING:36010,RENDERBUFFER_SAMPLES:36011,FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:36052,MAX_COLOR_ATTACHMENTS:36063,COLOR_ATTACHMENT1:36065,COLOR_ATTACHMENT2:36066,COLOR_ATTACHMENT3:36067,COLOR_ATTACHMENT4:36068,COLOR_ATTACHMENT5:36069,COLOR_ATTACHMENT6:36070,COLOR_ATTACHMENT7:36071,COLOR_ATTACHMENT8:36072,COLOR_ATTACHMENT9:36073,COLOR_ATTACHMENT10:36074,COLOR_ATTACHMENT11:36075,COLOR_ATTACHMENT12:36076,COLOR_ATTACHMENT13:36077,COLOR_ATTACHMENT14:36078,COLOR_ATTACHMENT15:36079,FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:36182,MAX_SAMPLES:36183,HALF_FLOAT:5131,RG:33319,RG_INTEGER:33320,R8:33321,RG8:33323,R16F:33325,R32F:33326,RG16F:33327,RG32F:33328,R8I:33329,R8UI:33330,R16I:33331,R16UI:33332,R32I:33333,R32UI:33334,RG8I:33335,RG8UI:33336,RG16I:33337,RG16UI:33338,RG32I:33339,RG32UI:33340,VERTEX_ARRAY_BINDING:34229,R8_SNORM:36756,RG8_SNORM:36757,RGB8_SNORM:36758,RGBA8_SNORM:36759,SIGNED_NORMALIZED:36764,COPY_READ_BUFFER:36662,COPY_WRITE_BUFFER:36663,COPY_READ_BUFFER_BINDING:36662,COPY_WRITE_BUFFER_BINDING:36663,UNIFORM_BUFFER:35345,UNIFORM_BUFFER_BINDING:35368,UNIFORM_BUFFER_START:35369,UNIFORM_BUFFER_SIZE:35370,MAX_VERTEX_UNIFORM_BLOCKS:35371,MAX_FRAGMENT_UNIFORM_BLOCKS:35373,MAX_COMBINED_UNIFORM_BLOCKS:35374,MAX_UNIFORM_BUFFER_BINDINGS:35375,MAX_UNIFORM_BLOCK_SIZE:35376,MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:35377,MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:35379,UNIFORM_BUFFER_OFFSET_ALIGNMENT:35380,ACTIVE_UNIFORM_BLOCKS:35382,UNIFORM_TYPE:35383,UNIFORM_SIZE:35384,UNIFORM_BLOCK_INDEX:35386,UNIFORM_OFFSET:35387,UNIFORM_ARRAY_STRIDE:35388,UNIFORM_MATRIX_STRIDE:35389,UNIFORM_IS_ROW_MAJOR:35390,UNIFORM_BLOCK_BINDING:35391,UNIFORM_BLOCK_DATA_SIZE:35392,UNIFORM_BLOCK_ACTIVE_UNIFORMS:35394,UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:35395,UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:35396,UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:35398,INVALID_INDEX:4294967295,MAX_VERTEX_OUTPUT_COMPONENTS:37154,MAX_FRAGMENT_INPUT_COMPONENTS:37157,MAX_SERVER_WAIT_TIMEOUT:37137,OBJECT_TYPE:37138,SYNC_CONDITION:37139,SYNC_STATUS:37140,SYNC_FLAGS:37141,SYNC_FENCE:37142,SYNC_GPU_COMMANDS_COMPLETE:37143,UNSIGNALED:37144,SIGNALED:37145,ALREADY_SIGNALED:37146,TIMEOUT_EXPIRED:37147,CONDITION_SATISFIED:37148,WAIT_FAILED:37149,SYNC_FLUSH_COMMANDS_BIT:1,VERTEX_ATTRIB_ARRAY_DIVISOR:35070,ANY_SAMPLES_PASSED:35887,ANY_SAMPLES_PASSED_CONSERVATIVE:36202,SAMPLER_BINDING:35097,RGB10_A2UI:36975,INT_2_10_10_10_REV:36255,TRANSFORM_FEEDBACK:36386,TRANSFORM_FEEDBACK_PAUSED:36387,TRANSFORM_FEEDBACK_ACTIVE:36388,TRANSFORM_FEEDBACK_BINDING:36389,COMPRESSED_R11_EAC:37488,COMPRESSED_SIGNED_R11_EAC:37489,COMPRESSED_RG11_EAC:37490,COMPRESSED_SIGNED_RG11_EAC:37491,COMPRESSED_RGB8_ETC2:37492,COMPRESSED_SRGB8_ETC2:37493,COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:37494,COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:37495,COMPRESSED_RGBA8_ETC2_EAC:37496,COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:37497,TEXTURE_IMMUTABLE_FORMAT:37167,MAX_ELEMENT_INDEX:36203,TEXTURE_IMMUTABLE_LEVELS:33503};return e(t)}),r("Core/Fullscreen",["./defined","./defineProperties"],function(e,t){"use strict";var r,i={requestFullscreen:void 0,exitFullscreen:void 0,fullscreenEnabled:void 0,fullscreenElement:void 0,fullscreenchange:void 0,fullscreenerror:void 0},n={};return t(n,{element:{get:function(){return n.supportsFullscreen()?document[i.fullscreenElement]:void 0}},changeEventName:{get:function(){return n.supportsFullscreen()?i.fullscreenchange:void 0}},errorEventName:{get:function(){return n.supportsFullscreen()?i.fullscreenerror:void 0}},enabled:{get:function(){return n.supportsFullscreen()?document[i.fullscreenEnabled]:void 0}},fullscreen:{get:function(){return n.supportsFullscreen()?null!==n.element:void 0}}}),n.supportsFullscreen=function(){if(e(r))return r;r=!1;var t=document.body;if("function"==typeof t.requestFullscreen)return i.requestFullscreen="requestFullscreen",i.exitFullscreen="exitFullscreen",i.fullscreenEnabled="fullscreenEnabled",i.fullscreenElement="fullscreenElement",i.fullscreenchange="fullscreenchange",i.fullscreenerror="fullscreenerror",r=!0;for(var n,o=["webkit","moz","o","ms","khtml"],a=0,s=o.length;s>a;++a){var l=o[a];n=l+"RequestFullscreen","function"==typeof t[n]?(i.requestFullscreen=n,r=!0):(n=l+"RequestFullScreen","function"==typeof t[n]&&(i.requestFullscreen=n,r=!0)),n=l+"ExitFullscreen","function"==typeof document[n]?i.exitFullscreen=n:(n=l+"CancelFullScreen","function"==typeof document[n]&&(i.exitFullscreen=n)),n=l+"FullscreenEnabled",e(document[n])?i.fullscreenEnabled=n:(n=l+"FullScreenEnabled",e(document[n])&&(i.fullscreenEnabled=n)),n=l+"FullscreenElement",e(document[n])?i.fullscreenElement=n:(n=l+"FullScreenElement",e(document[n])&&(i.fullscreenElement=n)),n=l+"fullscreenchange",e(document["on"+n])&&("ms"===l&&(n="MSFullscreenChange"),i.fullscreenchange=n),n=l+"fullscreenerror",e(document["on"+n])&&("ms"===l&&(n="MSFullscreenError"),i.fullscreenerror=n)}return r},n.requestFullscreen=function(e){n.supportsFullscreen()&&e[i.requestFullscreen]()},n.exitFullscreen=function(){n.supportsFullscreen()&&document[i.exitFullscreen]()},n}),r("Core/FeatureDetection",["./defaultValue","./defined","./Fullscreen"],function(e,t,r){"use strict";function i(e){for(var t=e.split("."),r=0,i=t.length;i>r;++r)t[r]=parseInt(t[r],10);return t}function n(){if(!t(v)){v=!1;var e=/ Chrome\/([\.0-9]+)/.exec(navigator.userAgent);null!==e&&(v=!0,_=i(e[1]))}return v}function o(){return n()&&_}function a(){if(!t(g)&&(g=!1,!n()&&/ Safari\/[\.0-9]+/.test(navigator.userAgent))){var e=/ Version\/([\.0-9]+)/.exec(navigator.userAgent);null!==e&&(g=!0,y=i(e[1]))}return g}function s(){return a()&&y}function l(){if(!t(C)){C=!1;var e=/ AppleWebKit\/([\.0-9]+)(\+?)/.exec(navigator.userAgent);null!==e&&(C=!0,E=i(e[1]),E.isNightly=!!e[2])}return C}function u(){return l()&&E}function c(){if(!t(S)){S=!1;var e;"Microsoft Internet Explorer"===navigator.appName?(e=/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(navigator.userAgent),null!==e&&(S=!0,w=i(e[1]))):"Netscape"===navigator.appName&&(e=/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(navigator.userAgent),null!==e&&(S=!0,w=i(e[1])))}return S}function h(){return c()&&w}function d(){if(!t(T)){T=!1;var e=/Firefox\/([\.0-9]+)/.exec(navigator.userAgent);null!==e&&(T=!0,b=i(e[1]))}return T}function p(){return t(x)||(x=/Windows/i.test(navigator.appVersion)),x}function m(){return d()&&b}function f(){return t(P)||(P=t(window.PointerEvent)&&(!t(window.navigator.pointerEnabled)||window.navigator.pointerEnabled)),P}var v,_,g,y,C,E,S,w,T,b,x,P,A={isChrome:n,chromeVersion:o,isSafari:a,safariVersion:s,isWebkit:l,webkitVersion:u,isInternetExplorer:c,internetExplorerVersion:h,isFirefox:d,firefoxVersion:m,isWindows:p,hardwareConcurrency:e(navigator.hardwareConcurrency,3),supportsPointerEvents:f};return A.supportsFullscreen=function(){return r.supportsFullscreen()},A.supportsTypedArrays=function(){return"undefined"!=typeof ArrayBuffer},A.supportsWebWorkers=function(){return"undefined"!=typeof Worker},A}),r("Core/ComponentDatatype",["../Renderer/WebGLConstants","./defaultValue","./defined","./DeveloperError","./FeatureDetection","./freezeObject"],function(e,t,r,i,n,o){"use strict";if(!n.supportsTypedArrays())return{};var a={BYTE:e.BYTE,UNSIGNED_BYTE:e.UNSIGNED_BYTE,SHORT:e.SHORT,UNSIGNED_SHORT:e.UNSIGNED_SHORT,FLOAT:e.FLOAT,DOUBLE:e.DOUBLE};return a.getSizeInBytes=function(e){switch(e){case a.BYTE:return Int8Array.BYTES_PER_ELEMENT;case a.UNSIGNED_BYTE:return Uint8Array.BYTES_PER_ELEMENT;case a.SHORT:return Int16Array.BYTES_PER_ELEMENT;case a.UNSIGNED_SHORT:return Uint16Array.BYTES_PER_ELEMENT;case a.FLOAT:return Float32Array.BYTES_PER_ELEMENT;case a.DOUBLE:return Float64Array.BYTES_PER_ELEMENT;default:throw new i("componentDatatype is not a valid value.")}},a.fromTypedArray=function(e){return e instanceof Int8Array?a.BYTE:e instanceof Uint8Array?a.UNSIGNED_BYTE:e instanceof Int16Array?a.SHORT:e instanceof Uint16Array?a.UNSIGNED_SHORT:e instanceof Float32Array?a.FLOAT:e instanceof Float64Array?a.DOUBLE:void 0},a.validate=function(e){return r(e)&&(e===a.BYTE||e===a.UNSIGNED_BYTE||e===a.SHORT||e===a.UNSIGNED_SHORT||e===a.FLOAT||e===a.DOUBLE)},a.createTypedArray=function(e,t){switch(e){case a.BYTE:return new Int8Array(t);case a.UNSIGNED_BYTE:return new Uint8Array(t);case a.SHORT:return new Int16Array(t);case a.UNSIGNED_SHORT:return new Uint16Array(t);case a.FLOAT:return new Float32Array(t);case a.DOUBLE:return new Float64Array(t);default:throw new i("componentDatatype is not a valid value.")}},a.createArrayBufferView=function(e,r,n,o){switch(n=t(n,0),o=t(o,(r.byteLength-n)/a.getSizeInBytes(e)),e){case a.BYTE:return new Int8Array(r,n,o);case a.UNSIGNED_BYTE:return new Uint8Array(r,n,o);case a.SHORT:return new Int16Array(r,n,o);case a.UNSIGNED_SHORT:return new Uint16Array(r,n,o);case a.FLOAT:return new Float32Array(r,n,o);case a.DOUBLE:return new Float64Array(r,n,o);default:throw new i("componentDatatype is not a valid value.")}},o(a)}),r("Core/GeometryType",["./freezeObject"],function(e){"use strict";var t={NONE:0,TRIANGLES:1,LINES:2,POLYLINES:3};return e(t)}),r("Core/PrimitiveType",["../Renderer/WebGLConstants","./freezeObject"],function(e,t){"use strict";var r={POINTS:e.POINTS,LINES:e.LINES,LINE_LOOP:e.LINE_LOOP,LINE_STRIP:e.LINE_STRIP,TRIANGLES:e.TRIANGLES,TRIANGLE_STRIP:e.TRIANGLE_STRIP,TRIANGLE_FAN:e.TRIANGLE_FAN,validate:function(e){return e===r.POINTS||e===r.LINES||e===r.LINE_LOOP||e===r.LINE_STRIP||e===r.TRIANGLES||e===r.TRIANGLE_STRIP||e===r.TRIANGLE_FAN}};return t(r)}),r("Core/Geometry",["./defaultValue","./defined","./DeveloperError","./GeometryType","./PrimitiveType"],function(e,t,r,i,n){"use strict";var o=function(t){t=e(t,e.EMPTY_OBJECT),this.attributes=t.attributes,this.indices=t.indices,this.primitiveType=e(t.primitiveType,n.TRIANGLES),this.boundingSphere=t.boundingSphere,this.geometryType=e(t.geometryType,i.NONE),this.boundingSphereCV=void 0};return o.computeNumberOfVertices=function(e){var i=-1;for(var n in e.attributes)if(e.attributes.hasOwnProperty(n)&&t(e.attributes[n])&&t(e.attributes[n].values)){var o=e.attributes[n],a=o.values.length/o.componentsPerAttribute;if(i!==a&&-1!==i)throw new r("All attribute lists must have the same number of attributes.");i=a}return i},o}),r("Core/GeometryAttribute",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t){t=e(t,e.EMPTY_OBJECT),this.componentDatatype=t.componentDatatype,this.componentsPerAttribute=t.componentsPerAttribute,this.normalize=e(t.normalize,!1),this.values=t.values};return i}),r("Core/GeometryAttributes",["./defaultValue"],function(e){"use strict";var t=function(t){t=e(t,e.EMPTY_OBJECT),this.position=t.position,this.normal=t.normal,this.st=t.st,this.binormal=t.binormal,this.tangent=t.tangent,this.color=t.color};return t}),r("Core/VertexFormat",["./defaultValue","./defined","./DeveloperError","./freezeObject"],function(e,t,r,i){"use strict";var n=function(t){t=e(t,e.EMPTY_OBJECT),this.position=e(t.position,!1),this.normal=e(t.normal,!1),this.st=e(t.st,!1),this.binormal=e(t.binormal,!1),this.tangent=e(t.tangent,!1),this.color=e(t.color,!1)};return n.POSITION_ONLY=i(new n({position:!0})),n.POSITION_AND_NORMAL=i(new n({position:!0,normal:!0})),n.POSITION_NORMAL_AND_ST=i(new n({position:!0,normal:!0,st:!0})),n.POSITION_AND_ST=i(new n({position:!0,st:!0})),n.POSITION_AND_COLOR=i(new n({position:!0,color:!0})),n.ALL=i(new n({position:!0,normal:!0,st:!0,binormal:!0,tangent:!0})),n.DEFAULT=n.POSITION_NORMAL_AND_ST,n.packedLength=6,n.pack=function(t,r,i){i=e(i,0),r[i++]=t.position?1:0,r[i++]=t.normal?1:0,r[i++]=t.st?1:0,r[i++]=t.binormal?1:0,r[i++]=t.tangent?1:0,r[i++]=t.color?1:0},n.unpack=function(r,i,o){return i=e(i,0),t(o)||(o=new n),o.position=1===r[i++],o.normal=1===r[i++],o.st=1===r[i++],o.binormal=1===r[i++],o.tangent=1===r[i++],o.color=1===r[i++],o},n.clone=function(e,r){return t(e)?(t(r)||(r=new n),r.position=e.position,r.normal=e.normal,r.st=e.st,r.binormal=e.binormal,r.tangent=e.tangent,r.color=e.color,r):void 0},n}),r("Core/BoxGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";var d=new t,p=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.minimum,a=e.maximum;!n(r)&&n(e.minimumCorner)&&(r=e.minimumCorner,o("BoxGeometry","options.minimumCorner is deprecated. Use options.minimum instead.")),!n(a)&&n(e.maximumCorner)&&(a=e.maximumCorner,o("BoxGeometry","options.maximumCorner is deprecated. Use options.maximum instead."));var s=i(e.vertexFormat,h.DEFAULT);this._minimum=t.clone(r),this._maximum=t.clone(a),this._vertexFormat=s,this._workerName="createBoxGeometry"};p.fromDimensions=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.dimensions,n=t.multiplyByScalar(r,.5,new t);return new p({minimum:t.negate(n,new t),maximum:n,vertexFormat:e.vertexFormat})},p.fromAxisAlignedBoundingBox=function(e){if(!n(e))throw new a("boundingBox is required.");return new p({minimum:e.minimum,maximum:e.maximum})},p.fromAxisAlignedBoundingBox=function(e){if(!n(e))throw new a("boundingBox is required.");return new p({minimum:e.minimum,maximum:e.maximum})},p.packedLength=2*t.packedLength+h.packedLength,p.pack=function(e,r,n){n=i(n,0),t.pack(e._minimum,r,n),t.pack(e._maximum,r,n+t.packedLength),h.pack(e._vertexFormat,r,n+2*t.packedLength)};var m=new t,f=new t,v=new h,_={minimum:m,maximum:f,vertexFormat:v};return p.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,m),s=t.unpack(e,r+t.packedLength,f),l=h.unpack(e,r+2*t.packedLength,v);return n(o)?(o._minimum=t.clone(a,o._minimum),o._maximum=t.clone(s,o._maximum),o._vertexFormat=h.clone(l,o._vertexFormat),o):new p(_)},p.createGeometry=function(i){var n,o,a=i._minimum,h=i._maximum,p=i._vertexFormat,m=new u;if(p.position&&(p.st||p.normal||p.binormal||p.tangent)){if(p.position&&(o=new Float64Array(72),o[0]=a.x,o[1]=a.y,o[2]=h.z,o[3]=h.x,o[4]=a.y,o[5]=h.z,o[6]=h.x,o[7]=h.y,o[8]=h.z,o[9]=a.x,o[10]=h.y,o[11]=h.z,o[12]=a.x,o[13]=a.y,o[14]=a.z,o[15]=h.x,o[16]=a.y,o[17]=a.z,o[18]=h.x,o[19]=h.y,o[20]=a.z,o[21]=a.x,o[22]=h.y,o[23]=a.z,o[24]=h.x,o[25]=a.y,o[26]=a.z,o[27]=h.x,o[28]=h.y,o[29]=a.z,o[30]=h.x,o[31]=h.y,o[32]=h.z,o[33]=h.x,o[34]=a.y,o[35]=h.z,o[36]=a.x,o[37]=a.y,o[38]=a.z,o[39]=a.x,o[40]=h.y,o[41]=a.z,o[42]=a.x,o[43]=h.y,o[44]=h.z,o[45]=a.x,o[46]=a.y,o[47]=h.z,o[48]=a.x,o[49]=h.y,o[50]=a.z,o[51]=h.x,o[52]=h.y,o[53]=a.z,o[54]=h.x,o[55]=h.y,o[56]=h.z,o[57]=a.x,o[58]=h.y,o[59]=h.z,o[60]=a.x,o[61]=a.y,o[62]=a.z,o[63]=h.x,o[64]=a.y,o[65]=a.z,o[66]=h.x,o[67]=a.y,o[68]=h.z,o[69]=a.x,o[70]=a.y,o[71]=h.z,m.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:o})),p.normal){var f=new Float32Array(72);f[0]=0,f[1]=0,f[2]=1,f[3]=0,f[4]=0,f[5]=1,f[6]=0,f[7]=0,f[8]=1,f[9]=0,f[10]=0,f[11]=1,f[12]=0,f[13]=0,f[14]=-1,f[15]=0,f[16]=0,f[17]=-1,f[18]=0,f[19]=0,f[20]=-1,f[21]=0,f[22]=0,f[23]=-1,f[24]=1,f[25]=0,f[26]=0,f[27]=1,f[28]=0,f[29]=0,f[30]=1,f[31]=0,f[32]=0,f[33]=1,f[34]=0,f[35]=0,f[36]=-1,f[37]=0,f[38]=0,f[39]=-1,f[40]=0,f[41]=0,f[42]=-1,f[43]=0,f[44]=0,f[45]=-1,f[46]=0,f[47]=0,f[48]=0,f[49]=1,f[50]=0,f[51]=0,f[52]=1,f[53]=0,f[54]=0,f[55]=1,f[56]=0,f[57]=0,f[58]=1,f[59]=0,f[60]=0,f[61]=-1,f[62]=0,f[63]=0,f[64]=-1,f[65]=0,f[66]=0,f[67]=-1,f[68]=0,f[69]=0,f[70]=-1,f[71]=0,m.normal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:f})}if(p.st){var v=new Float32Array(48);v[0]=0,v[1]=0,v[2]=1,v[3]=0,v[4]=1,v[5]=1,v[6]=0,v[7]=1,v[8]=1,v[9]=0,v[10]=0,v[11]=0,v[12]=0,v[13]=1,v[14]=1,v[15]=1,v[16]=0,v[17]=0,v[18]=1,v[19]=0,v[20]=1,v[21]=1,v[22]=0,v[23]=1,v[24]=1,v[25]=0,v[26]=0,v[27]=0,v[28]=0,v[29]=1,v[30]=1,v[31]=1,v[32]=1,v[33]=0,v[34]=0,v[35]=0,v[36]=0,v[37]=1,v[38]=1,v[39]=1,v[40]=0,v[41]=0,v[42]=1,v[43]=0,v[44]=1,v[45]=1,v[46]=0,v[47]=1,m.st=new l({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:v})}if(p.tangent){var _=new Float32Array(72);_[0]=1,_[1]=0,_[2]=0,_[3]=1,_[4]=0,_[5]=0,_[6]=1,_[7]=0,_[8]=0,_[9]=1,_[10]=0,_[11]=0,_[12]=-1,_[13]=0,_[14]=0,_[15]=-1,_[16]=0,_[17]=0,_[18]=-1,_[19]=0,_[20]=0,_[21]=-1,_[22]=0,_[23]=0,_[24]=0,_[25]=1,_[26]=0,_[27]=0,_[28]=1,_[29]=0,_[30]=0,_[31]=1,_[32]=0,_[33]=0,_[34]=1,_[35]=0,_[36]=0,_[37]=-1,_[38]=0,_[39]=0,_[40]=-1,_[41]=0,_[42]=0,_[43]=-1,_[44]=0,_[45]=0,_[46]=-1,_[47]=0,_[48]=-1,_[49]=0,_[50]=0,_[51]=-1,_[52]=0,_[53]=0,_[54]=-1,_[55]=0,_[56]=0,_[57]=-1,_[58]=0,_[59]=0,_[60]=1,_[61]=0,_[62]=0,_[63]=1,_[64]=0,_[65]=0,_[66]=1,_[67]=0,_[68]=0,_[69]=1,_[70]=0,_[71]=0,m.tangent=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:_})}if(p.binormal){var g=new Float32Array(72);g[0]=0,g[1]=1,g[2]=0,g[3]=0,g[4]=1,g[5]=0,g[6]=0,g[7]=1,g[8]=0,g[9]=0,g[10]=1,g[11]=0,g[12]=0,g[13]=1,g[14]=0,g[15]=0,g[16]=1,g[17]=0,g[18]=0,g[19]=1,g[20]=0,g[21]=0,g[22]=1,g[23]=0,g[24]=0,g[25]=0,g[26]=1,g[27]=0,g[28]=0,g[29]=1,g[30]=0,g[31]=0,g[32]=1,g[33]=0,g[34]=0,g[35]=1,g[36]=0,g[37]=0,g[38]=1,g[39]=0,g[40]=0,g[41]=1,g[42]=0,g[43]=0,g[44]=1,g[45]=0,g[46]=0,g[47]=1,g[48]=0,g[49]=0,g[50]=1,g[51]=0,g[52]=0,g[53]=1,g[54]=0,g[55]=0,g[56]=1,g[57]=0,g[58]=0,g[59]=1,g[60]=0,g[61]=0,g[62]=1,g[63]=0,g[64]=0,g[65]=1,g[66]=0,g[67]=0,g[68]=1,g[69]=0,g[70]=0,g[71]=1,m.binormal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:g})}n=new Uint16Array(36),n[0]=0,n[1]=1,n[2]=2,n[3]=0,n[4]=2,n[5]=3,n[6]=6,n[7]=5,n[8]=4,n[9]=7,n[10]=6,n[11]=4,n[12]=8,n[13]=9,n[14]=10,n[15]=8,n[16]=10,n[17]=11,n[18]=14,n[19]=13,n[20]=12,n[21]=15,n[22]=14,n[23]=12,n[24]=18,n[25]=17,n[26]=16,n[27]=19,n[28]=18,n[29]=16,n[30]=20,n[31]=21,n[32]=22,n[33]=20,n[34]=22,n[35]=23}else o=new Float64Array(24),o[0]=a.x,o[1]=a.y,o[2]=a.z,o[3]=h.x,o[4]=a.y,o[5]=a.z,o[6]=h.x,o[7]=h.y,o[8]=a.z,o[9]=a.x,o[10]=h.y,o[11]=a.z,o[12]=a.x,o[13]=a.y,o[14]=h.z,o[15]=h.x,o[16]=a.y,o[17]=h.z,o[18]=h.x,o[19]=h.y,o[20]=h.z,o[21]=a.x,o[22]=h.y,o[23]=h.z,m.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:o}),n=new Uint16Array(36),n[0]=4,n[1]=5,n[2]=6,n[3]=4,n[4]=6,n[5]=7,n[6]=1,n[7]=0,n[8]=3,n[9]=1,n[10]=3,n[11]=2,n[12]=1,n[13]=6,n[14]=5,n[15]=1,n[16]=2,n[17]=6,n[18]=2,n[19]=3,n[20]=7,n[21]=2,n[22]=7,n[23]=6,n[24]=3,n[25]=0,n[26]=4,n[27]=3,n[28]=4,n[29]=7,n[30]=0,n[31]=1,n[32]=5,n[33]=0,n[34]=5,n[35]=4;var y=t.subtract(h,a,d),C=.5*t.magnitude(y);return new s({attributes:m,indices:n,primitiveType:c.TRIANGLES,boundingSphere:new e(t.ZERO,C)})},p}),r("Core/BoxOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./deprecationWarning","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";var h=new t,d=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.minimum,a=e.maximum;!n(r)&&n(e.minimumCorner)&&(r=e.minimumCorner,o("BoxOutlineGeometry","options.minimumCorner is deprecated. Use options.minimum instead.")),!n(a)&&n(e.maximumCorner)&&(a=e.maximumCorner,o("BoxOutlineGeometry","options.maximumCorner is deprecated. Use options.maximum instead.")),this._min=t.clone(r),this._max=t.clone(a),this._workerName="createBoxOutlineGeometry"};d.fromDimensions=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.dimensions,n=t.multiplyByScalar(r,.5,new t);return new d({minimum:t.negate(n,new t),maximum:n})},d.fromAxisAlignedBoundingBox=function(e){if(!n(e))throw new a("boundingBox is required.");return new d({minimum:e.minimum,maximum:e.maximum})},d.packedLength=2*t.packedLength,d.pack=function(e,r,n){n=i(n,0),t.pack(e._min,r,n),t.pack(e._max,r,n+t.packedLength)};var p=new t,m=new t,f={minimum:p,maximum:m};return d.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,p),s=t.unpack(e,r+t.packedLength,m);return n(o)?(o._min=t.clone(a,o._min),o._max=t.clone(s,o._max),o):new d(f)},d.createGeometry=function(i){var n=i._min,o=i._max,a=new u,d=new Uint16Array(24),p=new Float64Array(24);p[0]=n.x,p[1]=n.y,p[2]=n.z,p[3]=o.x,p[4]=n.y,p[5]=n.z,p[6]=o.x,p[7]=o.y,p[8]=n.z,p[9]=n.x,p[10]=o.y,p[11]=n.z,p[12]=n.x,p[13]=n.y,p[14]=o.z,p[15]=o.x,p[16]=n.y,p[17]=o.z,p[18]=o.x,p[19]=o.y,p[20]=o.z,p[21]=n.x,p[22]=o.y,p[23]=o.z,a.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:p}),d[0]=4,d[1]=5,d[2]=5,d[3]=6,d[4]=6,d[5]=7,d[6]=7,d[7]=4,d[8]=0,d[9]=1,d[10]=1,d[11]=2,d[12]=2,d[13]=3,d[14]=3,d[15]=0,d[16]=0,d[17]=4,d[18]=1,d[19]=5,d[20]=2,d[21]=6,d[22]=3,d[23]=7;var m=t.subtract(o,n,h),f=.5*t.magnitude(m);return new s({attributes:a,indices:d,primitiveType:c.LINES,boundingSphere:new e(t.ZERO,f)})},d}),r("Core/Spline",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this.times=void 0,this.points=void 0,r.throwInstantiationError()};return i.prototype.evaluate=r.throwInstantiationError,i.prototype.findTimeInterval=function(t,r){var i=this.times,n=i.length;if(r=e(r,0),t>=i[r]){if(n>r+1&&t<i[r+1])return r;if(n>r+2&&t<i[r+2])return r+1}else if(r-1>=0&&t>=i[r-1])return r-1;var o;if(t>i[r])for(o=r;n-1>o&&!(t>=i[o]&&t<i[o+1]);++o);else for(o=r-1;o>=0&&!(t>=i[o]&&t<i[o+1]);--o);return o===n-1&&(o=n-2),o},i}),r("Core/LinearSpline",["./Cartesian3","./defaultValue","./defined","./defineProperties","./DeveloperError","./Spline"],function(e,t,r,i,n,o){"use strict";var a=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.points,i=e.times;this._times=i,this._points=r,this._lastTimeIndex=0};return i(a.prototype,{times:{get:function(){return this._times}},points:{get:function(){return this._points}}}),a.prototype.findTimeInterval=o.prototype.findTimeInterval,a.prototype.evaluate=function(t,i){var n=this.points,o=this.times,a=this._lastTimeIndex=this.findTimeInterval(t,this._lastTimeIndex),s=(t-o[a])/(o[a+1]-o[a]);return r(i)||(i=new e),e.lerp(n[a],n[a+1],s,i)},a}),r("Core/TridiagonalSystemSolver",["./Cartesian3","./defined","./DeveloperError"],function(e,t,r){"use strict";var i={};return i.solve=function(t,r,i,n){var o,a=new Array(i.length),s=new Array(n.length),l=new Array(n.length);for(o=0;o<s.length;o++)s[o]=new e,l[o]=new e;a[0]=i[0]/r[0],s[0]=e.multiplyByScalar(n[0],1/r[0],s[0]);var u;for(o=1;o<a.length;++o)u=1/(r[o]-a[o-1]*t[o-1]),a[o]=i[o]*u,s[o]=e.subtract(n[o],e.multiplyByScalar(s[o-1],t[o-1],s[o]),s[o]),s[o]=e.multiplyByScalar(s[o],u,s[o]);for(u=1/(r[o]-a[o-1]*t[o-1]),s[o]=e.subtract(n[o],e.multiplyByScalar(s[o-1],t[o-1],s[o]),s[o]),s[o]=e.multiplyByScalar(s[o],u,s[o]),l[l.length-1]=s[s.length-1],o=l.length-2;o>=0;--o)l[o]=e.subtract(s[o],e.multiplyByScalar(l[o+1],a[o],l[o]),l[o]);return l},i}),r("Core/HermiteSpline",["./Cartesian3","./Cartesian4","./defaultValue","./defined","./defineProperties","./DeveloperError","./LinearSpline","./Matrix4","./Spline","./TridiagonalSystemSolver"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(t,r,n){var o=d,a=m,s=p,l=f;o.length=a.length=t.length-1,s.length=l.length=t.length;var c;o[0]=s[0]=1,a[0]=0;var h=l[0];for(i(h)||(h=l[0]=new e),e.clone(r,h),c=1;c<o.length-1;++c)o[c]=a[c]=1,s[c]=4,h=l[c],i(h)||(h=l[c]=new e),e.subtract(t[c+1],t[c-1],h),e.multiplyByScalar(h,3,h);return o[c]=0,a[c]=1,s[c]=4,h=l[c],i(h)||(h=l[c]=new e),e.subtract(t[c+1],t[c-1],h),e.multiplyByScalar(h,3,h),s[c+1]=1,h=l[c+1],i(h)||(h=l[c+1]=new e),e.clone(n,h),u.solve(o,s,a,l)}function h(t){var r=d,n=m,o=p,a=f;r.length=n.length=t.length-1,o.length=a.length=t.length;var s;r[0]=n[0]=1,o[0]=2;var l=a[0];for(i(l)||(l=a[0]=new e),e.subtract(t[1],t[0],l),e.multiplyByScalar(l,3,l),s=1;s<r.length;++s)r[s]=n[s]=1,o[s]=4,l=a[s],i(l)||(l=a[s]=new e),e.subtract(t[s+1],t[s-1],l),e.multiplyByScalar(l,3,l);return o[s]=2,l=a[s],i(l)||(l=a[s]=new e),e.subtract(t[s],t[s-1],l),e.multiplyByScalar(l,3,l),u.solve(r,o,n,a)}var d=[],p=[],m=[],f=[],v=function(e){e=r(e,r.EMPTY_OBJECT);var t=e.points,i=e.times,n=e.inTangents,o=e.outTangents;this._times=i,this._points=t,this._inTangents=n,this._outTangents=o,this._lastTimeIndex=0};n(v.prototype,{times:{get:function(){return this._times}},points:{get:function(){return this._points}},inTangents:{get:function(){return this._inTangents}},outTangents:{get:function(){return this._outTangents}}}),v.createC1=function(e){e=r(e,r.EMPTY_OBJECT);var t=e.times,i=e.points,n=e.tangents,o=n.slice(0,n.length-1),a=n.slice(1,n.length);return new v({times:t,points:i,inTangents:a,outTangents:o})},v.createNaturalCubic=function(e){e=r(e,r.EMPTY_OBJECT);var t=e.times,i=e.points;if(i.length<3)return new a({points:i,times:t});var n=h(i),o=n.slice(0,n.length-1),s=n.slice(1,n.length);return new v({times:t,points:i,inTangents:s,outTangents:o})},v.createClampedCubic=function(e){e=r(e,r.EMPTY_OBJECT);var t=e.times,i=e.points,n=e.firstTangent,o=e.lastTangent;if(i.length<3)return new a({points:i,times:t});var s=c(i,n,o),l=s.slice(0,s.length-1),u=s.slice(1,s.length);return new v({times:t,points:i,inTangents:u,outTangents:l})},v.hermiteCoefficientMatrix=new s(2,-3,0,1,-2,3,0,0,1,-2,1,0,1,-1,0,0),v.prototype.findTimeInterval=l.prototype.findTimeInterval;var _=new t,g=new e;return v.prototype.evaluate=function(t,r){i(r)||(r=new e);var n=this.points,o=this.times,a=this.inTangents,l=this.outTangents,u=this._lastTimeIndex=this.findTimeInterval(t,this._lastTimeIndex),c=(t-o[u])/(o[u+1]-o[u]),h=_;h.z=c,h.y=c*c,h.x=h.y*c,h.w=1;var d=s.multiplyByVector(v.hermiteCoefficientMatrix,h,h);return r=e.multiplyByScalar(n[u],d.x,r),e.multiplyByScalar(n[u+1],d.y,g),e.add(r,g,r),e.multiplyByScalar(l[u],d.z,g),e.add(r,g,r),e.multiplyByScalar(a[u],d.w,g),e.add(r,g,r)},v}),r("Core/CatmullRomSpline",["./Cartesian3","./Cartesian4","./defaultValue","./defined","./defineProperties","./DeveloperError","./HermiteSpline","./Matrix4","./Spline"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(t){var r=t.points,n=t.times;if(r.length<3){var o=n[0],l=1/(n[1]-o),u=r[0],p=r[1];return function(t,r){i(r)||(r=new e);var n=(t-o)*l;return e.lerp(u,p,n,r)}}return function(o,l){i(l)||(l=new e);var u=t._lastTimeIndex=t.findTimeInterval(o,t._lastTimeIndex),p=(o-n[u])/(n[u+1]-n[u]),m=c;m.z=p,m.y=p*p,m.x=m.y*p,m.w=1;var v,_,g,y,C;return 0===u?(v=r[0],_=r[1],g=t.firstTangent,y=e.subtract(r[2],v,h),e.multiplyByScalar(y,.5,y),C=s.multiplyByVector(a.hermiteCoefficientMatrix,m,m)):u===r.length-2?(v=r[u],_=r[u+1],y=t.lastTangent,g=e.subtract(_,r[u-1],h),e.multiplyByScalar(g,.5,g),C=s.multiplyByVector(a.hermiteCoefficientMatrix,m,m)):(v=r[u-1],_=r[u],g=r[u+1],y=r[u+2],C=s.multiplyByVector(f.catmullRomCoefficientMatrix,m,m)),l=e.multiplyByScalar(v,C.x,l),e.multiplyByScalar(_,C.y,d),e.add(l,d,l),e.multiplyByScalar(g,C.z,d),e.add(l,d,l),e.multiplyByScalar(y,C.w,d),e.add(l,d,l)}}var c=new t,h=new e,d=new e,p=new e,m=new e,f=function(t){ -t=r(t,r.EMPTY_OBJECT);var n=t.points,o=t.times,a=t.firstTangent,s=t.lastTangent;if(n.length>2&&(i(a)||(a=p,e.multiplyByScalar(n[1],2,a),e.subtract(a,n[2],a),e.subtract(a,n[0],a),e.multiplyByScalar(a,.5,a)),!i(s))){var l=n.length-1;s=m,e.multiplyByScalar(n[l-1],2,s),e.subtract(n[l],s,s),e.add(s,n[l-2],s),e.multiplyByScalar(s,.5,s)}this._times=o,this._points=n,this._firstTangent=e.clone(a),this._lastTangent=e.clone(s),this._evaluateFunction=u(this),this._lastTimeIndex=0};return n(f.prototype,{times:{get:function(){return this._times}},points:{get:function(){return this._points}},firstTangent:{get:function(){return this._firstTangent}},lastTangent:{get:function(){return this._lastTangent}}}),f.catmullRomCoefficientMatrix=new s(-.5,1,-.5,0,1.5,-2.5,0,1,-1.5,2,.5,0,.5,-.5,0,0),f.prototype.findTimeInterval=l.prototype.findTimeInterval,f.prototype.evaluate=function(e,t){return this._evaluateFunction(e,t)},f}),r("Core/IndexDatatype",["../Renderer/WebGLConstants","./defined","./DeveloperError","./freezeObject","./Math"],function(e,t,r,i,n){"use strict";var o={UNSIGNED_BYTE:e.UNSIGNED_BYTE,UNSIGNED_SHORT:e.UNSIGNED_SHORT,UNSIGNED_INT:e.UNSIGNED_INT};return o.getSizeInBytes=function(e){switch(e){case o.UNSIGNED_BYTE:return Uint8Array.BYTES_PER_ELEMENT;case o.UNSIGNED_SHORT:return Uint16Array.BYTES_PER_ELEMENT;case o.UNSIGNED_INT:return Uint32Array.BYTES_PER_ELEMENT}},o.validate=function(e){return t(e)&&(e===o.UNSIGNED_BYTE||e===o.UNSIGNED_SHORT||e===o.UNSIGNED_INT)},o.createTypedArray=function(e,t){return e>=n.SIXTY_FOUR_KILOBYTES?new Uint32Array(t):new Uint16Array(t)},o.createTypedArrayFromArrayBuffer=function(e,t,r,i){return e>=n.SIXTY_FOUR_KILOBYTES?new Uint32Array(t,r,i):new Uint16Array(t,r,i)},i(o)}),r("Core/definedNotNull",[],function(){"use strict";var e=function(e){return void 0!==e&&null!==e};return e}),r("Core/joinUrls",["../ThirdParty/Uri","./defaultValue","./defined","./definedNotNull","./DeveloperError"],function(e,t,r,i,n){"use strict";var o=function(n,o,a){a=t(a,!0),n instanceof e||(n=new e(n)),o instanceof e||(o=new e(o)),i(o.authority)&&!i(o.scheme)&&("undefined"!=typeof document&&r(document.location)&&r(document.location.href)?o.scheme=new e(document.location.href).scheme:o.scheme=n.scheme);var s=n;o.isAbsolute()&&(s=o);var l="";i(s.scheme)&&(l+=s.scheme+":"),i(s.authority)&&(l+="//"+s.authority,""!==s.path&&(l=l.replace(/\/?$/,"/"),s.path=s.path.replace(/^\/?/g,""))),l+=s===n?a?n.path.replace(/\/?$/,"/")+o.path.replace(/^\/?/g,""):n.path+o.path:o.path;var u=i(n.query),c=i(o.query);u&&c?l+="?"+n.query+"&"+o.query:u&&!c?l+="?"+n.query:!u&&c&&(l+="?"+o.query);var h=i(o.fragment);return i(n.fragment)&&!h?l+="#"+n.fragment:h&&(l+="#"+o.fragment),l};return o}),r("Core/parseResponseHeaders",[],function(){"use strict";var e=function(e){var t={};if(!e)return t;for(var r=e.split("\r\n"),i=0;i<r.length;++i){var n=r[i],o=n.indexOf(": ");if(o>0){var a=n.substring(0,o),s=n.substring(o+2);t[a]=s}}return t};return e}),r("Core/RequestErrorEvent",["./defined","./parseResponseHeaders"],function(e,t){"use strict";var r=function(e,r,i){this.statusCode=e,this.response=r,this.responseHeaders=i,"string"==typeof this.responseHeaders&&(this.responseHeaders=t(this.responseHeaders))};return r.prototype.toString=function(){var t="Request has failed.";return e(this.statusCode)&&(t+=" Status Code: "+this.statusCode),t},r}),r("Core/loadWithXhr",["../ThirdParty/when","./defaultValue","./defined","./DeveloperError","./RequestErrorEvent","./RuntimeError"],function(e,t,r,i,n,o){"use strict";function a(e,t){var r=decodeURIComponent(t);return e?atob(r):r}function s(e,t){for(var r=a(e,t),i=new ArrayBuffer(r.length),n=new Uint8Array(i),o=0;o<r.length;o++)n[o]=r.charCodeAt(o);return i}function l(e,r){r=t(r,"");var n=e[1],o=!!e[2],l=e[3];switch(r){case"":case"text":return a(o,l);case"arraybuffer":return s(o,l);case"blob":var u=s(o,l);return new Blob([u],{type:n});case"document":var c=new DOMParser;return c.parseFromString(a(o,l),n);case"json":return JSON.parse(a(o,l));default:throw new i("Unhandled responseType: "+r)}}var u=function(r){r=t(r,t.EMPTY_OBJECT);var i=r.responseType,n=t(r.method,"GET"),o=r.data,a=r.headers,s=r.overrideMimeType;return e(r.url,function(t){var r=e.defer();return u.load(t,i,n,o,a,r,s),r.promise})},c=/^data:(.*?)(;base64)?,(.*)$/;return u.load=function(e,t,i,a,s,u,h){var d=c.exec(e);if(null!==d)return void u.resolve(l(d,t));var p=new XMLHttpRequest;if(r(h)&&r(p.overrideMimeType)&&p.overrideMimeType(h),p.open(i,e,!0),r(s))for(var m in s)s.hasOwnProperty(m)&&p.setRequestHeader(m,s[m]);r(t)&&(p.responseType=t),p.onload=function(){200===p.status?r(p.response)?u.resolve(p.response):r(p.responseXML)&&p.responseXML.hasChildNodes()?u.resolve(p.responseXML):r(p.responseText)?u.resolve(p.responseText):u.reject(new o("unknown XMLHttpRequest response type.")):u.reject(new n(p.status,p.response,p.getAllResponseHeaders()))},p.onerror=function(e){u.reject(new n)},p.send(a)},u.defaultLoad=u.load,u}),r("Core/loadArrayBuffer",["./loadWithXhr"],function(e){"use strict";var t=function(t,r){return e({url:t,responseType:"arraybuffer",headers:r})};return t}),r("Core/clone",["./defaultValue"],function(e){"use strict";var t=function(r,i){if(null===r||"object"!=typeof r)return r;i=e(i,!1);var n=new r.constructor;for(var o in r)if(r.hasOwnProperty(o)){var a=r[o];i&&(a=t(a,i)),n[o]=a}return n};return t}),r("Core/loadText",["./loadWithXhr"],function(e){"use strict";var t=function(t,r){return e({url:t,headers:r})};return t}),r("Core/loadJson",["./clone","./defined","./DeveloperError","./loadText"],function(e,t,r,i){"use strict";var n={Accept:"application/json,*/*;q=0.01"},o=function(r,o){return t(o)?t(o.Accept)||(o=e(o),o.Accept=n.Accept):o=n,i(r,o).then(function(e){return JSON.parse(e)})};return o}),r("Core/QuadraticRealPolynomial",["./DeveloperError","./Math"],function(e,t){"use strict";function r(e,r,i){var n=e+r;return t.sign(e)!==t.sign(r)&&Math.abs(n/Math.max(Math.abs(e),Math.abs(r)))<i?0:n}var i={};return i.computeDiscriminant=function(e,t,r){var i=t*t-4*e*r;return i},i.computeRealRoots=function(e,i,n){var o;if(0===e)return 0===i?[]:[-n/i];if(0===i){if(0===n)return[0,0];var a=Math.abs(n),s=Math.abs(e);if(s>a&&a/s<t.EPSILON14)return[0,0];if(a>s&&s/a<t.EPSILON14)return[];if(o=-n/e,0>o)return[];var l=Math.sqrt(o);return[-l,l]}if(0===n)return o=-i/e,0>o?[o,0]:[0,o];var u=i*i,c=4*e*n,h=r(u,-c,t.EPSILON14);if(0>h)return[];var d=-.5*r(i,t.sign(i)*Math.sqrt(h),t.EPSILON14);return i>0?[d/e,n/d]:[n/d,d/e]},i}),r("Core/CubicRealPolynomial",["./DeveloperError","./QuadraticRealPolynomial"],function(e,t){"use strict";function r(e,t,r,i){var n,o,a=e,s=t/3,l=r/3,u=i,c=a*l,h=s*u,d=s*s,p=l*l,m=a*l-d,f=a*u-s*l,v=s*u-p,_=4*m*v-f*f;if(0>_){var g,y,C;d*h>=c*p?(g=a,y=m,C=-2*s*m+a*f):(g=u,y=v,C=-u*f+2*l*v);var E=0>C?-1:1,S=-E*Math.abs(g)*Math.sqrt(-_);o=-C+S;var w=o/2,T=0>w?-Math.pow(-w,1/3):Math.pow(w,1/3),b=o===S?-T:-y/T;return n=0>=y?T+b:-C/(T*T+b*b+y),d*h>=c*p?[(n-s)/a]:[-u/(n+l)]}var x=m,P=-2*s*m+a*f,A=v,I=-u*f+2*l*v,M=Math.sqrt(_),D=Math.sqrt(3)/2,R=Math.abs(Math.atan2(a*M,-P)/3);n=2*Math.sqrt(-x);var O=Math.cos(R);o=n*O;var N=n*(-O/2-D*Math.sin(R)),L=o+N>2*s?o-s:N-s,F=a,B=L/F;R=Math.abs(Math.atan2(u*M,-I)/3),n=2*Math.sqrt(-A),O=Math.cos(R),o=n*O,N=n*(-O/2-D*Math.sin(R));var V=-u,z=2*l>o+N?o+l:N+l,k=V/z,U=F*z,G=-L*z-F*V,W=L*V,H=(l*G-s*W)/(-s*G+l*U);return H>=B?k>=B?k>=H?[B,H,k]:[B,k,H]:[k,B,H]:k>=B?[H,B,k]:k>=H?[H,k,B]:[k,H,B]}var i={};return i.computeDiscriminant=function(e,t,r,i){var n=e*e,o=t*t,a=r*r,s=i*i,l=18*e*t*r*i+o*a-27*n*s-4*(e*a*r+o*t*i);return l},i.computeRealRoots=function(e,i,n,o){var a,s;if(0===e)return t.computeRealRoots(i,n,o);if(0===i){if(0===n){if(0===o)return[0,0,0];s=-o/e;var l=0>s?-Math.pow(-s,1/3):Math.pow(s,1/3);return[l,l,l]}return 0===o?(a=t.computeRealRoots(e,0,n),0===a.Length?[0]:[a[0],0,a[1]]):r(e,0,n,o)}return 0===n?0===o?(s=-i/e,0>s?[s,0,0]:[0,0,s]):r(e,i,0,o):0===o?(a=t.computeRealRoots(e,i,n),0===a.length?[0]:a[1]<=0?[a[0],a[1],0]:a[0]>=0?[0,a[0],a[1]]:[a[0],0,a[1]]):r(e,i,n,o)},i}),r("Core/QuarticRealPolynomial",["./CubicRealPolynomial","./DeveloperError","./Math","./QuadraticRealPolynomial"],function(e,t,r,i){"use strict";function n(t,n,o,a){var s=t*t,l=n-3*s/8,u=o-n*t/2+s*t/8,c=a-o*t/4+n*s/16-3*s*s/256,h=e.computeRealRoots(1,2*l,l*l-4*c,-u*u);if(h.length>0){var d=-t/4,p=h[h.length-1];if(Math.abs(p)<r.EPSILON14){var m=i.computeRealRoots(1,l,c);if(2===m.length){var f,v=m[0],_=m[1];if(v>=0&&_>=0){var g=Math.sqrt(v),y=Math.sqrt(_);return[d-y,d-g,d+g,d+y]}if(v>=0&&0>_)return f=Math.sqrt(v),[d-f,d+f];if(0>v&&_>=0)return f=Math.sqrt(_),[d-f,d+f]}return[]}if(p>0){var C=Math.sqrt(p),E=(l+p-u/C)/2,S=(l+p+u/C)/2,w=i.computeRealRoots(1,C,E),T=i.computeRealRoots(1,-C,S);return 0!==w.length?(w[0]+=d,w[1]+=d,0!==T.length?(T[0]+=d,T[1]+=d,w[1]<=T[0]?[w[0],w[1],T[0],T[1]]:T[1]<=w[0]?[T[0],T[1],w[0],w[1]]:w[0]>=T[0]&&w[1]<=T[1]?[T[0],w[0],w[1],T[1]]:T[0]>=w[0]&&T[1]<=w[1]?[w[0],T[0],T[1],w[1]]:w[0]>T[0]&&w[0]<T[1]?[T[0],w[0],T[1],w[1]]:[w[0],T[0],w[1],T[1]]):w):0!==T.length?(T[0]+=d,T[1]+=d,T):[]}}return[]}function o(t,n,o,a){var s=o*o,l=n*n,u=t*t,c=-2*n,h=o*t+l-4*a,d=u*a-o*n*t+s,p=e.computeRealRoots(1,c,h,d);if(p.length>0){var m,f,v=p[0],_=n-v,g=_*_,y=t/2,C=_/2,E=g-4*a,S=g+4*Math.abs(a),w=u-4*v,T=u+4*Math.abs(v);if(0>v||w*S>E*T){var b=Math.sqrt(w);m=b/2,f=0===b?0:(t*C-o)/b}else{var x=Math.sqrt(E);m=0===x?0:(t*C-o)/x,f=x/2}var P,A;0===y&&0===m?(P=0,A=0):r.sign(y)===r.sign(m)?(P=y+m,A=v/P):(A=y-m,P=v/A);var I,M;0===C&&0===f?(I=0,M=0):r.sign(C)===r.sign(f)?(I=C+f,M=a/I):(M=C-f,I=a/M);var D=i.computeRealRoots(1,P,I),R=i.computeRealRoots(1,A,M);if(0!==D.length)return 0!==R.length?D[1]<=R[0]?[D[0],D[1],R[0],R[1]]:R[1]<=D[0]?[R[0],R[1],D[0],D[1]]:D[0]>=R[0]&&D[1]<=R[1]?[R[0],D[0],D[1],R[1]]:R[0]>=D[0]&&R[1]<=D[1]?[D[0],R[0],R[1],D[1]]:D[0]>R[0]&&D[0]<R[1]?[R[0],D[0],R[1],D[1]]:[D[0],R[0],D[1],R[1]]:D;if(0!==R.length)return R}return[]}var a={};return a.computeDiscriminant=function(e,t,r,i,n){var o=e*e,a=o*e,s=t*t,l=s*t,u=r*r,c=u*r,h=i*i,d=h*i,p=n*n,m=p*n,f=s*u*h-4*l*d-4*e*c*h+18*e*t*r*d-27*o*h*h+256*a*m+n*(18*l*r*i-4*s*c+16*e*u*u-80*e*t*u*i-6*e*s*h+144*o*r*h)+p*(144*e*s*r-27*s*s-128*o*u-192*o*t*i);return f},a.computeRealRoots=function(t,i,a,s,l){if(Math.abs(t)<r.EPSILON15)return e.computeRealRoots(i,a,s,l);var u=i/t,c=a/t,h=s/t,d=l/t,p=0>u?1:0;switch(p+=0>c?p+1:p,p+=0>h?p+1:p,p+=0>d?p+1:p){case 0:return n(u,c,h,d);case 1:return o(u,c,h,d);case 2:return o(u,c,h,d);case 3:return n(u,c,h,d);case 4:return n(u,c,h,d);case 5:return o(u,c,h,d);case 6:return n(u,c,h,d);case 7:return n(u,c,h,d);case 8:return o(u,c,h,d);case 9:return n(u,c,h,d);case 10:return n(u,c,h,d);case 11:return o(u,c,h,d);case 12:return n(u,c,h,d);case 13:return n(u,c,h,d);case 14:return n(u,c,h,d);case 15:return n(u,c,h,d);default:return void 0}},a}),r("Core/Ray",["./Cartesian3","./defaultValue","./defined","./DeveloperError"],function(e,t,r,i){"use strict";var n=function(r,i){i=e.clone(t(i,e.ZERO)),e.equals(i,e.ZERO)||e.normalize(i,i),this.origin=e.clone(t(r,e.ZERO)),this.direction=i};return n.getPoint=function(t,i,n){return r(n)||(n=new e),n=e.multiplyByScalar(t.direction,i,n),e.add(t.origin,n,n)},n}),r("Core/IntersectionTests",["./Cartesian3","./Cartographic","./defaultValue","./defined","./DeveloperError","./Math","./Matrix3","./QuadraticRealPolynomial","./QuarticRealPolynomial","./Ray"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(t,i,n,a,s){s=r(s,!1);var l,u,c,h,d,p=t.origin,m=t.direction,f=e.subtract(n,i,v),E=e.subtract(a,i,_),S=e.cross(m,E,g),w=e.dot(f,S);if(s){if(w<o.EPSILON6)return void 0;if(l=e.subtract(p,i,y),c=e.dot(l,S),0>c||c>w)return void 0;if(u=e.cross(l,f,C),h=e.dot(m,u),0>h||c+h>w)return void 0;d=e.dot(E,u)/w}else{if(Math.abs(w)<o.EPSILON6)return void 0;var T=1/w;if(l=e.subtract(p,i,y),c=e.dot(l,S)*T,0>c||c>1)return void 0;if(u=e.cross(l,f,C),h=e.dot(m,u)*T,0>h||c+h>1)return void 0;d=e.dot(E,u)*T}return d}function h(e,t,r,i){var n=t*t-4*e*r;if(0>n)return void 0;if(n>0){var o=1/(2*e),a=Math.sqrt(n),s=(-t+a)*o,l=(-t-a)*o;return l>s?(i.root0=s,i.root1=l):(i.root0=l,i.root1=s),i}var u=-t/(2*e);return 0===u?void 0:(i.root0=i.root1=u,i)}function d(t,r,n){i(n)||(n={});var o=t.origin,a=t.direction,s=r.center,l=r.radius*r.radius,u=e.subtract(o,s,g),c=e.dot(a,a),d=2*e.dot(a,u),p=e.magnitudeSquared(u)-l,m=h(c,d,p,S);return i(m)?(n.start=m.root0,n.stop=m.root1,n):void 0}function p(e,t,r){var i=e+t;return o.sign(e)!==o.sign(t)&&Math.abs(i/Math.max(Math.abs(e),Math.abs(t)))<r?0:i}function m(t,r,i,n,u){var c,h=n*n,d=u*u,m=(t[a.COLUMN1ROW1]-t[a.COLUMN2ROW2])*d,f=u*(n*p(t[a.COLUMN1ROW0],t[a.COLUMN0ROW1],o.EPSILON15)+r.y),v=t[a.COLUMN0ROW0]*h+t[a.COLUMN2ROW2]*d+n*r.x+i,_=d*p(t[a.COLUMN2ROW1],t[a.COLUMN1ROW2],o.EPSILON15),g=u*(n*p(t[a.COLUMN2ROW0],t[a.COLUMN0ROW2])+r.z),y=[];if(0===g&&0===_){if(c=s.computeRealRoots(m,f,v),0===c.length)return y;var C=c[0],E=Math.sqrt(Math.max(1-C*C,0));if(y.push(new e(n,u*C,u*-E)),y.push(new e(n,u*C,u*E)),2===c.length){var S=c[1],w=Math.sqrt(Math.max(1-S*S,0));y.push(new e(n,u*S,u*-w)),y.push(new e(n,u*S,u*w))}return y}var T=g*g,b=_*_,x=m*m,P=g*_,A=x+b,I=2*(f*m+P),M=2*v*m+f*f-b+T,D=2*(v*f-P),R=v*v-T;if(0===A&&0===I&&0===M&&0===D)return y;c=l.computeRealRoots(A,I,M,D,R);var O=c.length;if(0===O)return y;for(var N=0;O>N;++N){var L,F=c[N],B=F*F,V=Math.max(1-B,0),z=Math.sqrt(V);L=o.sign(m)===o.sign(v)?p(m*B+v,f*F,o.EPSILON12):o.sign(v)===o.sign(f*F)?p(m*B,f*F+v,o.EPSILON12):p(m*B+f*F,v,o.EPSILON12);var k=p(_*F,g,o.EPSILON15),U=L*k;0>U?y.push(new e(n,u*F,u*z)):U>0?y.push(new e(n,u*F,u*-z)):0!==z?(y.push(new e(n,u*F,u*-z)),y.push(new e(n,u*F,u*z)),++N):y.push(new e(n,u*F,u*z))}return y}var f={};f.rayPlane=function(t,r,n){i(n)||(n=new e);var a=t.origin,s=t.direction,l=r.normal,u=e.dot(l,s);if(Math.abs(u)<o.EPSILON15)return void 0;var c=(-r.distance-e.dot(l,a))/u;return 0>c?void 0:(n=e.multiplyByScalar(s,c,n),e.add(a,n,n))};var v=new e,_=new e,g=new e,y=new e,C=new e;f.rayTriangle=function(t,r,n,o,a,s){var l=c(t,r,n,o,a);return!i(l)||0>l?void 0:(i(s)||(s=new e),e.multiplyByScalar(t.direction,l,s),e.add(t.origin,s,s))};var E=new u;f.lineSegmentTriangle=function(t,r,n,o,a,s,l){var u=E;e.clone(t,u.origin),e.subtract(r,t,u.direction),e.normalize(u.direction,u.direction);var h=c(u,n,o,a,s);return!i(h)||0>h||h>e.distance(t,r)?void 0:(i(l)||(l=new e),e.multiplyByScalar(u.direction,h,l),e.add(u.origin,l,l))};var S={root0:0,root1:0};f.raySphere=function(e,t,r){return r=d(e,t,r),!i(r)||r.stop<0?void 0:(r.start=Math.max(r.start,0),r)};var w=new u;f.lineSegmentSphere=function(t,r,n,o){var a=w,s=(e.clone(t,a.origin),e.subtract(r,t,a.direction)),l=e.magnitude(s);return e.normalize(s,s),o=d(a,n,o),!i(o)||o.stop<0||o.start>l?void 0:(o.start=Math.max(o.start,0),o.stop=Math.min(o.stop,l),o)};var T=new e,b=new e;f.rayEllipsoid=function(t,r){var i,n,o,a,s,l=r.oneOverRadii,u=e.multiplyComponents(l,t.origin,T),c=e.multiplyComponents(l,t.direction,b),h=e.magnitudeSquared(u),d=e.dot(u,c);if(h>1){if(d>=0)return void 0;var p=d*d;if(i=h-1,n=e.magnitudeSquared(c),o=n*i,o>p)return void 0;if(p>o){a=d*d-o,s=-d+Math.sqrt(a);var m=s/n,f=i/s;return f>m?{start:m,stop:f}:{start:f,stop:m}}var v=Math.sqrt(i/n);return{start:v,stop:v}}return 1>h?(i=h-1,n=e.magnitudeSquared(c),o=n*i,a=d*d-o,s=-d+Math.sqrt(a),{start:0,stop:s/n}):0>d?(n=e.magnitudeSquared(c),{start:0,stop:-d/n}):void 0};var x=new e,P=new e,A=new e,I=new e,M=new e,D=new a,R=new a,O=new a,N=new a,L=new a,F=new a,B=new a,V=new e,z=new e,k=new t;f.grazingAltitudeLocation=function(t,r){var n=t.origin,s=t.direction,l=r.geodeticSurfaceNormal(n,x);if(e.dot(s,l)>=0)return n;var u=i(this.rayEllipsoid(t,r)),c=r.transformPositionToScaledSpace(s,x),h=e.normalize(c,c),d=e.mostOrthogonalAxis(c,I),p=e.normalize(e.cross(d,h,P),P),f=e.normalize(e.cross(h,p,A),A),v=D;v[0]=h.x,v[1]=h.y,v[2]=h.z,v[3]=p.x,v[4]=p.y,v[5]=p.z,v[6]=f.x,v[7]=f.y,v[8]=f.z;var _=a.transpose(v,R),g=a.fromScale(r.radii,O),y=a.fromScale(r.oneOverRadii,N),C=L;C[0]=0,C[1]=-s.z,C[2]=s.y,C[3]=s.z,C[4]=0,C[5]=-s.x,C[6]=-s.y,C[7]=s.x,C[8]=0;var E,S,w=a.multiply(a.multiply(_,y,F),C,F),T=a.multiply(a.multiply(w,g,B),v,B),b=a.multiplyByVector(w,n,M),U=m(T,e.negate(b,x),0,0,1),G=U.length;if(G>0){for(var W=e.clone(e.ZERO,z),H=Number.NEGATIVE_INFINITY,q=0;G>q;++q){E=a.multiplyByVector(g,a.multiplyByVector(v,U[q],V),V);var j=e.normalize(e.subtract(E,n,I),I),Y=e.dot(j,s);Y>H&&(H=Y,W=e.clone(E,W))}var X=r.cartesianToCartographic(W,k);return H=o.clamp(H,0,1),S=e.magnitude(e.subtract(W,n,I))*Math.sqrt(1-H*H),S=u?-S:S,X.height=S,r.cartographicToCartesian(X,new e)}return void 0};var U=new e;return f.lineSegmentPlane=function(t,r,n,a){i(a)||(a=new e);var s=e.subtract(r,t,U),l=n.normal,u=e.dot(l,s);if(Math.abs(u)<o.EPSILON6)return void 0;var c=e.dot(l,t),h=-(n.distance+c)/u;return 0>h||h>1?void 0:(e.multiplyByScalar(s,h,a),e.add(t,a,a),a)},f.trianglePlaneIntersection=function(t,r,i,n){var o=n.normal,a=n.distance,s=e.dot(o,t)+a<0,l=e.dot(o,r)+a<0,u=e.dot(o,i)+a<0,c=0;c+=s?1:0,c+=l?1:0,c+=u?1:0;var h,d;if((1===c||2===c)&&(h=new e,d=new e),1===c){if(s)return f.lineSegmentPlane(t,r,n,h),f.lineSegmentPlane(t,i,n,d),{positions:[t,r,i,h,d],indices:[0,3,4,1,2,4,1,4,3]};if(l)return f.lineSegmentPlane(r,i,n,h),f.lineSegmentPlane(r,t,n,d),{positions:[t,r,i,h,d],indices:[1,3,4,2,0,4,2,4,3]};if(u)return f.lineSegmentPlane(i,t,n,h),f.lineSegmentPlane(i,r,n,d),{positions:[t,r,i,h,d],indices:[2,3,4,0,1,4,0,4,3]}}else if(2===c){if(!s)return f.lineSegmentPlane(r,t,n,h),f.lineSegmentPlane(i,t,n,d),{positions:[t,r,i,h,d],indices:[1,2,4,1,4,3,0,3,4]};if(!l)return f.lineSegmentPlane(i,r,n,h),f.lineSegmentPlane(t,r,n,d),{positions:[t,r,i,h,d],indices:[2,0,4,2,4,3,1,3,4]};if(!u)return f.lineSegmentPlane(t,i,n,h),f.lineSegmentPlane(r,i,n,d),{positions:[t,r,i,h,d],indices:[0,1,4,0,4,3,2,3,4]}}return void 0},f}),r("Core/binarySearch",["./defined","./DeveloperError"],function(e,t){"use strict";var r=function(e,t,r){for(var i,n,o=0,a=e.length-1;a>=o;)if(i=~~((o+a)/2),n=r(e[i],t),0>n)o=i+1;else{if(!(n>0))return i;a=i-1}return~(a+1)};return r}),r("Core/EarthOrientationParametersSample",[],function(){"use strict";var e=function(e,t,r,i,n){this.xPoleWander=e,this.yPoleWander=t,this.xPoleOffset=r,this.yPoleOffset=i,this.ut1MinusUtc=n};return e}),r("ThirdParty/sprintf",[],function(){function e(){var e=/%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g,t=arguments,r=0,i=t[r++],n=function(e,t,r,i){r||(r=" ");var n=e.length>=t?"":Array(1+t-e.length>>>0).join(r);return i?e+n:n+e},o=function(e,t,r,i,o,a){var s=i-e.length;return s>0&&(e=r||!o?n(e,i,a,r):e.slice(0,t.length)+n("",s,"0",!0)+e.slice(t.length)),e},a=function(e,t,r,i,a,s,l){var u=e>>>0;return r=r&&u&&{2:"0b",8:"0",16:"0x"}[t]||"",e=r+n(u.toString(t),s||0,"0",!1),o(e,r,i,a,l)},s=function(e,t,r,i,n,a){return null!=i&&(e=e.slice(0,i)),o(e,"",t,r,n,a)},l=function(e,i,l,u,c,h,d){var p,m,f,v,_;if("%%"==e)return"%";for(var g=!1,y="",C=!1,E=!1,S=" ",w=l.length,T=0;l&&w>T;T++)switch(l.charAt(T)){case" ":y=" ";break;case"+":y="+";break;case"-":g=!0;break;case"'":S=l.charAt(T+1);break;case"0":C=!0;break;case"#":E=!0}if(u=u?"*"==u?+t[r++]:"*"==u.charAt(0)?+t[u.slice(1,-1)]:+u:0,0>u&&(u=-u,g=!0),!isFinite(u))throw new Error("sprintf: (minimum-)width must be finite");switch(h=h?"*"==h?+t[r++]:"*"==h.charAt(0)?+t[h.slice(1,-1)]:+h:"fFeE".indexOf(d)>-1?6:"d"==d?0:void 0,_=i?t[i.slice(0,-1)]:t[r++],d){case"s":return s(String(_),g,u,h,C,S);case"c":return s(String.fromCharCode(+_),g,u,h,C);case"b":return a(_,2,E,g,u,h,C);case"o":return a(_,8,E,g,u,h,C);case"x":return a(_,16,E,g,u,h,C);case"X":return a(_,16,E,g,u,h,C).toUpperCase();case"u":return a(_,10,E,g,u,h,C);case"i":case"d":return p=+_||0,p=Math.round(p-p%1),m=0>p?"-":y,_=m+n(String(Math.abs(p)),h,"0",!1),o(_,m,g,u,C);case"e":case"E":case"f":case"F":case"g":case"G":return p=+_,m=0>p?"-":y,f=["toExponential","toFixed","toPrecision"]["efg".indexOf(d.toLowerCase())],v=["toString","toUpperCase"]["eEfFgG".indexOf(d)%2],_=m+Math.abs(p)[f](h),o(_,m,g,u,C)[v]();default:return e}};return i.replace(e,l)}return e}),r("Core/GregorianDate",[],function(){"use strict";var e=function(e,t,r,i,n,o,a,s){this.year=e,this.month=t,this.day=r,this.hour=i,this.minute=n,this.second=o,this.millisecond=a,this.isLeapSecond=s};return e}),r("Core/isLeapYear",["./DeveloperError"],function(e){"use strict";function t(e){return e%4===0&&e%100!==0||e%400===0}return t}),r("Core/LeapSecond",[],function(){"use strict";var e=function(e,t){this.julianDate=e,this.offset=t};return e}),r("Core/TimeConstants",["./freezeObject"],function(e){"use strict";var t={SECONDS_PER_MILLISECOND:.001,SECONDS_PER_MINUTE:60,MINUTES_PER_HOUR:60,HOURS_PER_DAY:24,SECONDS_PER_HOUR:3600,MINUTES_PER_DAY:1440,SECONDS_PER_DAY:86400,DAYS_PER_JULIAN_CENTURY:36525,PICOSECOND:1e-9,MODIFIED_JULIAN_DATE_DIFFERENCE:2400000.5};return e(t)}),r("Core/TimeStandard",["./freezeObject"],function(e){"use strict";var t={UTC:0,TAI:1};return e(t)}),r("Core/JulianDate",["../ThirdParty/sprintf","./binarySearch","./defaultValue","./defined","./DeveloperError","./GregorianDate","./isLeapYear","./LeapSecond","./TimeConstants","./TimeStandard"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){return I.compare(e.julianDate,t.julianDate)}function h(e){g.julianDate=e;var r=I.leapSeconds,i=t(r,g,c);0>i&&(i=~i),i>=r.length&&(i=r.length-1);var n=r[i].offset;if(i>0){var o=I.secondsDifference(r[i].julianDate,e);o>n&&(i--,n=r[i].offset)}I.addSeconds(e,n,e)}function d(e,r){g.julianDate=e;var i=I.leapSeconds,n=t(i,g,c);if(0>n&&(n=~n),0===n)return I.addSeconds(e,-i[0].offset,r);if(n>=i.length)return I.addSeconds(e,-i[n-1].offset,r);var o=I.secondsDifference(i[n].julianDate,e);return 0===o?I.addSeconds(e,-i[n].offset,r):1>=o?void 0:I.addSeconds(e,-i[--n].offset,r)}function p(e,t,r){var i=t/l.SECONDS_PER_DAY|0;return e+=i,t-=l.SECONDS_PER_DAY*i,0>t&&(e--,t+=l.SECONDS_PER_DAY),r.dayNumber=e,r.secondsOfDay=t,r}function m(e,t,r,i,n,o,a){var s=(t-14)/12|0,u=e+4800+s,c=(1461*u/4|0)+(367*(t-2-12*s)/12|0)-(3*((u+100)/100|0)/4|0)+r-32075;i-=12,0>i&&(i+=24);var h=o+(i*l.SECONDS_PER_HOUR+n*l.SECONDS_PER_MINUTE+a*l.SECONDS_PER_MILLISECOND);return h>=43200&&(c-=1),[c,h]}var f=new o,v=[31,28,31,30,31,30,31,31,30,31,30,31],_=29,g=new s,y=/^(\d{4})$/,C=/^(\d{4})-(\d{2})$/,E=/^(\d{4})-?(\d{3})$/,S=/^(\d{4})-?W(\d{2})-?(\d{1})?$/,w=/^(\d{4})-?(\d{2})-?(\d{2})$/,T=/([Z+\-])?(\d{2})?:?(\d{2})?$/,b=/^(\d{2})(\.\d+)?/.source+T.source,x=/^(\d{2}):?(\d{2})(\.\d+)?/.source+T.source,P=/^(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?/.source+T.source,A="Invalid ISO 8601 date.",I=function(e,t,i){this.dayNumber=void 0,this.secondsOfDay=void 0,e=r(e,0),t=r(t,0),i=r(i,u.UTC);var n=0|e;t+=(e-n)*l.SECONDS_PER_DAY,p(n,t,this),i===u.UTC&&h(this)};I.fromDate=function(e,t){var r=m(e.getUTCFullYear(),e.getUTCMonth()+1,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds());return i(t)?(p(r[0],r[1],t),h(t),t):new I(r[0],r[1],u.UTC)},I.fromIso8601=function(e,t){e=e.replace(",",".");var r,o,s,l=e.split("T"),c=1,d=1,f=0,g=0,T=0,M=0,D=l[0],R=l[1];if(!i(D))throw new n(A);var O;if(l=D.match(w),null!==l){if(O=D.split("-").length-1,O>0&&2!==O)throw new n(A);r=+l[1],c=+l[2],d=+l[3]}else if(l=D.match(C),null!==l)r=+l[1],c=+l[2];else if(l=D.match(y),null!==l)r=+l[1];else{var N;if(l=D.match(E),null!==l){if(r=+l[1],N=+l[2],s=a(r),1>N||s&&N>366||!s&&N>365)throw new n(A)}else{if(l=D.match(S),null===l)throw new n(A);r=+l[1];var L=+l[2],F=+l[3]||0;if(O=D.split("-").length-1,O>0&&(!i(l[3])&&1!==O||i(l[3])&&2!==O))throw new n(A);var B=new Date(Date.UTC(r,0,4));N=7*L+F-B.getUTCDay()-3}o=new Date(Date.UTC(r,0,1)),o.setUTCDate(N),c=o.getUTCMonth()+1,d=o.getUTCDate()}if(s=a(r),1>c||c>12||1>d||(2!==c||!s)&&d>v[c-1]||s&&2===c&&d>_)throw new n(A);var V;if(i(R)){if(l=R.match(P),null!==l){if(O=R.split(":").length-1,O>0&&2!==O&&3!==O)throw new n(A);f=+l[1],g=+l[2],T=+l[3],M=1e3*+(l[4]||0),V=5}else if(l=R.match(x),null!==l){if(O=R.split(":").length-1,O>0&&1!==O)throw new n(A);f=+l[1],g=+l[2],T=60*+(l[3]||0),V=4}else{if(l=R.match(b),null===l)throw new n(A);f=+l[1],g=60*+(l[2]||0),V=3}if(g>=60||T>=61||f>24||24===f&&(g>0||T>0||M>0))throw new n(A);var z=l[V],k=+l[V+1],U=+(l[V+2]||0);switch(z){case"+":f-=k,g-=U;break;case"-":f+=k,g+=U;break;case"Z":break;default:g+=new Date(Date.UTC(r,c-1,d,f,g)).getTimezoneOffset()}}else g+=new Date(r,c-1,d).getTimezoneOffset();var G=60===T;for(G&&T--;g>=60;)g-=60,f++;for(;f>=24;)f-=24,d++;for(o=s&&2===c?_:v[c-1];d>o;)d-=o,c++,c>12&&(c-=12,r++),o=s&&2===c?_:v[c-1];for(;0>g;)g+=60,f--;for(;0>f;)f+=24,d--;for(;1>d;)c--,1>c&&(c+=12,r--),o=s&&2===c?_:v[c-1],d+=o;var W=m(r,c,d,f,g,T,M);return i(t)?(p(W[0],W[1],t),h(t)):t=new I(W[0],W[1],u.UTC),G&&I.addSeconds(t,1,t),t},I.now=function(e){return I.fromDate(new Date,e)};var M=new I(0,0,u.TAI);return I.toGregorianDate=function(e,t){var r=!1,n=d(e,M);i(n)||(I.addSeconds(e,-1,M),n=d(M,M),r=!0);var a=n.dayNumber,s=n.secondsOfDay;s>=43200&&(a+=1);var u=a+68569|0,c=4*u/146097|0;u=u-((146097*c+3)/4|0)|0;var h=4e3*(u+1)/1461001|0;u=u-(1461*h/4|0)+31|0;var p=80*u/2447|0,m=u-(2447*p/80|0)|0;u=p/11|0;var f=p+2-12*u|0,v=100*(c-49)+h+u|0,_=s/l.SECONDS_PER_HOUR|0,g=s-_*l.SECONDS_PER_HOUR,y=g/l.SECONDS_PER_MINUTE|0;g-=y*l.SECONDS_PER_MINUTE;var C=0|g,E=(g-C)/l.SECONDS_PER_MILLISECOND;return _+=12,_>23&&(_-=24),r&&(C+=1),i(t)?(t.year=v,t.month=f,t.day=m,t.hour=_,t.minute=y,t.second=C,t.millisecond=E,t.isLeapSecond=r,t):new o(v,f,m,_,y,C,E,r)},I.toDate=function(e){var t=I.toGregorianDate(e,f),r=t.second;return t.isLeapSecond&&(r-=1),new Date(Date.UTC(t.year,t.month-1,t.day,t.hour,t.minute,r,t.millisecond))},I.toIso8601=function(t,r){var n,o=I.toGregorianDate(t,o);return i(r)||0===o.millisecond?i(r)&&0!==r?(n=(.01*o.millisecond).toFixed(r).replace(".","").slice(0,r),e("%04d-%02d-%02dT%02d:%02d:%02d.%sZ",o.year,o.month,o.day,o.hour,o.minute,o.second,n)):e("%04d-%02d-%02dT%02d:%02d:%02dZ",o.year,o.month,o.day,o.hour,o.minute,o.second):(n=(.01*o.millisecond).toString().replace(".",""),e("%04d-%02d-%02dT%02d:%02d:%02d.%sZ",o.year,o.month,o.day,o.hour,o.minute,o.second,n))},I.clone=function(e,t){return i(e)?i(t)?(t.dayNumber=e.dayNumber,t.secondsOfDay=e.secondsOfDay,t):new I(e.dayNumber,e.secondsOfDay,u.TAI):void 0},I.compare=function(e,t){var r=e.dayNumber-t.dayNumber;return 0!==r?r:e.secondsOfDay-t.secondsOfDay},I.equals=function(e,t){return e===t||i(e)&&i(t)&&e.dayNumber===t.dayNumber&&e.secondsOfDay===t.secondsOfDay},I.equalsEpsilon=function(e,t,r){return e===t||i(e)&&i(t)&&Math.abs(I.secondsDifference(e,t))<=r},I.totalDays=function(e){return e.dayNumber+e.secondsOfDay/l.SECONDS_PER_DAY},I.secondsDifference=function(e,t){var r=(e.dayNumber-t.dayNumber)*l.SECONDS_PER_DAY;return r+(e.secondsOfDay-t.secondsOfDay)},I.daysDifference=function(e,t){var r=e.dayNumber-t.dayNumber,i=(e.secondsOfDay-t.secondsOfDay)/l.SECONDS_PER_DAY;return r+i},I.computeTaiMinusUtc=function(e){g.julianDate=e;var r=I.leapSeconds,i=t(r,g,c);return 0>i&&(i=~i,--i,0>i&&(i=0)),r[i].offset},I.addSeconds=function(e,t,r){return p(e.dayNumber,e.secondsOfDay+t,r)},I.addMinutes=function(e,t,r){var i=e.secondsOfDay+t*l.SECONDS_PER_MINUTE;return p(e.dayNumber,i,r)},I.addHours=function(e,t,r){var i=e.secondsOfDay+t*l.SECONDS_PER_HOUR;return p(e.dayNumber,i,r)},I.addDays=function(e,t,r){var i=e.dayNumber+t;return p(i,e.secondsOfDay,r)},I.lessThan=function(e,t){return I.compare(e,t)<0},I.lessThanOrEquals=function(e,t){return I.compare(e,t)<=0},I.greaterThan=function(e,t){return I.compare(e,t)>0},I.greaterThanOrEquals=function(e,t){return I.compare(e,t)>=0},I.prototype.clone=function(e){return I.clone(this,e)},I.prototype.equals=function(e){return I.equals(this,e)},I.prototype.equalsEpsilon=function(e,t){return I.equalsEpsilon(this,e,t)},I.prototype.toString=function(){return I.toIso8601(this)},I.leapSeconds=[new s(new I(2441317,43210,u.TAI),10),new s(new I(2441499,43211,u.TAI),11),new s(new I(2441683,43212,u.TAI),12),new s(new I(2442048,43213,u.TAI),13),new s(new I(2442413,43214,u.TAI),14),new s(new I(2442778,43215,u.TAI),15),new s(new I(2443144,43216,u.TAI),16),new s(new I(2443509,43217,u.TAI),17),new s(new I(2443874,43218,u.TAI),18),new s(new I(2444239,43219,u.TAI),19),new s(new I(2444786,43220,u.TAI),20),new s(new I(2445151,43221,u.TAI),21),new s(new I(2445516,43222,u.TAI),22),new s(new I(2446247,43223,u.TAI),23),new s(new I(2447161,43224,u.TAI),24),new s(new I(2447892,43225,u.TAI),25),new s(new I(2448257,43226,u.TAI),26),new s(new I(2448804,43227,u.TAI),27),new s(new I(2449169,43228,u.TAI),28),new s(new I(2449534,43229,u.TAI),29),new s(new I(2450083,43230,u.TAI),30),new s(new I(2450630,43231,u.TAI),31),new s(new I(2451179,43232,u.TAI),32),new s(new I(2453736,43233,u.TAI),33),new s(new I(2454832,43234,u.TAI),34),new s(new I(2456109,43235,u.TAI),35),new s(new I(2457204,43236,u.TAI),36)],I}),r("Core/EarthOrientationParameters",["../ThirdParty/when","./binarySearch","./defaultValue","./defined","./EarthOrientationParametersSample","./freezeObject","./JulianDate","./LeapSecond","./loadJson","./RuntimeError","./TimeConstants","./TimeStandard"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t){return a.compare(e.julianDate,t)}function p(e,r){if(!i(r.columnNames))return void(e._dataError="Error in loaded EOP data: The columnNames property is required.");if(!i(r.samples))return void(e._dataError="Error in loaded EOP data: The samples property is required.");var n=r.columnNames.indexOf("modifiedJulianDateUtc"),o=r.columnNames.indexOf("xPoleWanderRadians"),l=r.columnNames.indexOf("yPoleWanderRadians"),u=r.columnNames.indexOf("ut1MinusUtcSeconds"),p=r.columnNames.indexOf("xCelestialPoleOffsetRadians"),m=r.columnNames.indexOf("yCelestialPoleOffsetRadians"),f=r.columnNames.indexOf("taiMinusUtcSeconds");if(0>n||0>o||0>l||0>u||0>p||0>m||0>f)return void(e._dataError="Error in loaded EOP data: The columnNames property must include modifiedJulianDateUtc, xPoleWanderRadians, yPoleWanderRadians, ut1MinusUtcSeconds, xCelestialPoleOffsetRadians, yCelestialPoleOffsetRadians, and taiMinusUtcSeconds columns");var v=e._samples=r.samples,_=e._dates=[];e._dateColumn=n,e._xPoleWanderRadiansColumn=o,e._yPoleWanderRadiansColumn=l,e._ut1MinusUtcSecondsColumn=u,e._xCelestialPoleOffsetRadiansColumn=p,e._yCelestialPoleOffsetRadiansColumn=m,e._taiMinusUtcSecondsColumn=f,e._columnCount=r.columnNames.length,e._lastIndex=void 0;for(var g,y=e._addNewLeapSeconds,C=0,E=v.length;E>C;C+=e._columnCount){var S=v[C+n],w=v[C+f],T=S+c.MODIFIED_JULIAN_DATE_DIFFERENCE,b=new a(T,w,h.TAI);if(_.push(b),y){if(w!==g&&i(g)){var x=a.leapSeconds,P=t(x,b,d);if(0>P){var A=new s(b,w);x.splice(~P,0,A)}}g=w}}}function m(e,t,r,i,n){var o=r*i;n.xPoleWander=t[o+e._xPoleWanderRadiansColumn],n.yPoleWander=t[o+e._yPoleWanderRadiansColumn],n.xPoleOffset=t[o+e._xCelestialPoleOffsetRadiansColumn],n.yPoleOffset=t[o+e._yCelestialPoleOffsetRadiansColumn],n.ut1MinusUtc=t[o+e._ut1MinusUtcSecondsColumn]}function f(e,t,r){return t+e*(r-t)}function v(e,t,r,i,n,o,s){var l=e._columnCount;if(o>t.length-1)return s.xPoleWander=0,s.yPoleWander=0,s.xPoleOffset=0,s.yPoleOffset=0,s.ut1MinusUtc=0,s;var u=t[n],c=t[o];if(u.equals(c)||i.equals(u))return m(e,r,n,l,s),s;if(i.equals(c))return m(e,r,o,l,s),s;var h=a.secondsDifference(i,u)/a.secondsDifference(c,u),d=n*l,p=o*l,v=r[d+e._ut1MinusUtcSecondsColumn],_=r[p+e._ut1MinusUtcSecondsColumn],g=_-v;if(g>.5||-.5>g){var y=r[d+e._taiMinusUtcSecondsColumn],C=r[p+e._taiMinusUtcSecondsColumn];y!==C&&(c.equals(i)?v=_:_-=C-y)}return s.xPoleWander=f(h,r[d+e._xPoleWanderRadiansColumn],r[p+e._xPoleWanderRadiansColumn]),s.yPoleWander=f(h,r[d+e._yPoleWanderRadiansColumn],r[p+e._yPoleWanderRadiansColumn]),s.xPoleOffset=f(h,r[d+e._xCelestialPoleOffsetRadiansColumn],r[p+e._xCelestialPoleOffsetRadiansColumn]),s.yPoleOffset=f(h,r[d+e._yCelestialPoleOffsetRadiansColumn],r[p+e._yCelestialPoleOffsetRadiansColumn]),s.ut1MinusUtc=f(h,v,_),s}var _=function(t){if(t=r(t,r.EMPTY_OBJECT),this._dates=void 0,this._samples=void 0,this._dateColumn=-1,this._xPoleWanderRadiansColumn=-1,this._yPoleWanderRadiansColumn=-1,this._ut1MinusUtcSecondsColumn=-1,this._xCelestialPoleOffsetRadiansColumn=-1, -this._yCelestialPoleOffsetRadiansColumn=-1,this._taiMinusUtcSecondsColumn=-1,this._columnCount=0,this._lastIndex=-1,this._downloadPromise=void 0,this._dataError=void 0,this._addNewLeapSeconds=r(t.addNewLeapSeconds,!0),i(t.data))p(this,t.data);else if(i(t.url)){var n=this;this._downloadPromise=e(l(t.url),function(e){p(n,e)},function(){n._dataError="An error occurred while retrieving the EOP data from the URL "+t.url+"."})}else p(this,{columnNames:["dateIso8601","modifiedJulianDateUtc","xPoleWanderRadians","yPoleWanderRadians","ut1MinusUtcSeconds","lengthOfDayCorrectionSeconds","xCelestialPoleOffsetRadians","yCelestialPoleOffsetRadians","taiMinusUtcSeconds"],samples:[]})};return _.NONE=o({getPromiseToLoad:function(){return e()},compute:function(e,t){return i(t)?(t.xPoleWander=0,t.yPoleWander=0,t.xPoleOffset=0,t.yPoleOffset=0,t.ut1MinusUtc=0):t=new n(0,0,0,0,0),t}}),_.prototype.getPromiseToLoad=function(){return e(this._downloadPromise)},_.prototype.compute=function(e,r){if(!i(this._samples)){if(i(this._dataError))throw new u(this._dataError);return void 0}if(i(r)||(r=new n(0,0,0,0,0)),0===this._samples.length)return r.xPoleWander=0,r.yPoleWander=0,r.xPoleOffset=0,r.yPoleOffset=0,r.ut1MinusUtc=0,r;var o=this._dates,s=this._lastIndex,l=0,c=0;if(i(s)){var h=o[s],d=o[s+1],p=a.lessThanOrEquals(h,e),m=!i(d),f=m||a.greaterThanOrEquals(d,e);if(p&&f)return l=s,!m&&d.equals(e)&&++l,c=l+1,v(this,o,this._samples,e,l,c,r),r}var _=t(o,e,a.compare,this._dateColumn);return _>=0?(_<o.length-1&&o[_+1].equals(e)&&++_,l=_,c=_):(c=~_,l=c-1,0>l&&(l=0)),this._lastIndex=l,v(this,o,this._samples,e,l,c,r),r},_}),r("Core/Iau2006XysSample",[],function(){"use strict";var e=function(e,t,r){this.x=e,this.y=t,this.s=r};return e}),r("Core/Iau2006XysData",["../ThirdParty/when","./buildModuleUrl","./defaultValue","./defined","./Iau2006XysSample","./JulianDate","./loadJson","./TimeStandard"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t,r){var i=h;return i.dayNumber=t,i.secondsOfDay=r,o.daysDifference(i,e._sampleZeroDateTT)}function u(r,n){if(r._chunkDownloadsInProgress[n])return r._chunkDownloadsInProgress[n];var o=e.defer();r._chunkDownloadsInProgress[n]=o;var s,l=r._xysFileUrlTemplate;return s=i(l)?l.replace("{0}",n):t("Assets/IAU2006_XYS/IAU2006_XYS_"+n+".json"),e(a(s),function(e){r._chunkDownloadsInProgress[n]=!1;for(var t=r._samples,i=e.samples,a=n*r._samplesPerXysFile*3,s=0,l=i.length;l>s;++s)t[a+s]=i[s];o.resolve()}),o.promise}var c=function(e){e=r(e,r.EMPTY_OBJECT),this._xysFileUrlTemplate=e.xysFileUrlTemplate,this._interpolationOrder=r(e.interpolationOrder,9),this._sampleZeroJulianEphemerisDate=r(e.sampleZeroJulianEphemerisDate,2442396.5),this._sampleZeroDateTT=new o(this._sampleZeroJulianEphemerisDate,0,s.TAI),this._stepSizeDays=r(e.stepSizeDays,1),this._samplesPerXysFile=r(e.samplesPerXysFile,1e3),this._totalSamples=r(e.totalSamples,27426),this._samples=new Array(3*this._totalSamples),this._chunkDownloadsInProgress=[];for(var t=this._interpolationOrder,i=this._denominators=new Array(t+1),n=this._xTable=new Array(t+1),a=Math.pow(this._stepSizeDays,t),l=0;t>=l;++l){i[l]=a,n[l]=l*this._stepSizeDays;for(var u=0;t>=u;++u)u!==l&&(i[l]*=l-u);i[l]=1/i[l]}this._work=new Array(t+1),this._coef=new Array(t+1)},h=new o(0,0,s.TAI);return c.prototype.preload=function(t,r,i,n){var o=l(this,t,r),a=l(this,i,n),s=o/this._stepSizeDays-this._interpolationOrder/2|0;0>s&&(s=0);var c=a/this._stepSizeDays-this._interpolationOrder/2|0+this._interpolationOrder;c>=this._totalSamples&&(c=this._totalSamples-1);for(var h=s/this._samplesPerXysFile|0,d=c/this._samplesPerXysFile|0,p=[],m=h;d>=m;++m)p.push(u(this,m));return e.all(p)},c.prototype.computeXysRadians=function(e,t,r){var o=l(this,e,t);if(0>o)return void 0;var a=o/this._stepSizeDays|0;if(a>=this._totalSamples)return void 0;var s=this._interpolationOrder,c=a-(s/2|0);0>c&&(c=0);var h=c+s;h>=this._totalSamples&&(h=this._totalSamples-1,c=h-s,0>c&&(c=0));var d=!1,p=this._samples;if(i(p[3*c])||(u(this,c/this._samplesPerXysFile|0),d=!0),i(p[3*h])||(u(this,h/this._samplesPerXysFile|0),d=!0),d)return void 0;i(r)?(r.x=0,r.y=0,r.s=0):r=new n(0,0,0);var m,f,v=o-c*this._stepSizeDays,_=this._work,g=this._denominators,y=this._coef,C=this._xTable;for(m=0;s>=m;++m)_[m]=v-C[m];for(m=0;s>=m;++m){for(y[m]=1,f=0;s>=f;++f)f!==m&&(y[m]*=_[f]);y[m]*=g[m];var E=3*(c+m);r.x+=y[m]*p[E++],r.y+=y[m]*p[E++],r.s+=y[m]*p[E]}return r},c}),r("Core/Quaternion",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./FeatureDetection","./freezeObject","./Math","./Matrix3"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,r,i,n){this.x=t(e,0),this.y=t(r,0),this.z=t(i,0),this.w=t(n,0)},u=new e;l.fromAxisAngle=function(t,i,n){var o=i/2,a=Math.sin(o);u=e.normalize(t,u);var s=u.x*a,c=u.y*a,h=u.z*a,d=Math.cos(o);return r(n)?(n.x=s,n.y=c,n.z=h,n.w=d,n):new l(s,c,h,d)};var c=[1,2,0],h=new Array(3);l.fromRotationMatrix=function(e,t){var i,n,o,a,u,d=e[s.COLUMN0ROW0],p=e[s.COLUMN1ROW1],m=e[s.COLUMN2ROW2],f=d+p+m;if(f>0)i=Math.sqrt(f+1),u=.5*i,i=.5/i,n=(e[s.COLUMN1ROW2]-e[s.COLUMN2ROW1])*i,o=(e[s.COLUMN2ROW0]-e[s.COLUMN0ROW2])*i,a=(e[s.COLUMN0ROW1]-e[s.COLUMN1ROW0])*i;else{var v=c,_=0;p>d&&(_=1),m>d&&m>p&&(_=2);var g=v[_],y=v[g];i=Math.sqrt(e[s.getElementIndex(_,_)]-e[s.getElementIndex(g,g)]-e[s.getElementIndex(y,y)]+1);var C=h;C[_]=.5*i,i=.5/i,u=(e[s.getElementIndex(y,g)]-e[s.getElementIndex(g,y)])*i,C[g]=(e[s.getElementIndex(g,_)]+e[s.getElementIndex(_,g)])*i,C[y]=(e[s.getElementIndex(y,_)]+e[s.getElementIndex(_,y)])*i,n=-C[0],o=-C[1],a=-C[2]}return r(t)?(t.x=n,t.y=o,t.z=a,t.w=u,t):new l(n,o,a,u)};var d=new l;l.fromHeadingPitchRoll=function(t,r,i,n){var o=l.fromAxisAngle(e.UNIT_X,i,d),a=l.fromAxisAngle(e.UNIT_Y,-r,n);n=l.multiply(a,o,a);var s=l.fromAxisAngle(e.UNIT_Z,-t,d);return l.multiply(s,n,n)};var p=new e,m=new e,f=new l,v=new l,_=new l;l.packedLength=4,l.pack=function(e,r,i){i=t(i,0),r[i++]=e.x,r[i++]=e.y,r[i++]=e.z,r[i]=e.w},l.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new l),n.x=e[i],n.y=e[i+1],n.z=e[i+2],n.w=e[i+3],n},l.packedInterpolationLength=3,l.convertPackedArrayForInterpolation=function(e,t,r,i){l.unpack(e,4*r,_),l.conjugate(_,_);for(var n=0,o=r-t+1;o>n;n++){var a=3*n;l.unpack(e,4*(t+n),f),l.multiply(f,_,f),f.w<0&&l.negate(f,f),l.computeAxis(f,p);var s=l.computeAngle(f);i[a]=p.x*s,i[a+1]=p.y*s,i[a+2]=p.z*s}},l.unpackInterpolationResult=function(t,i,n,o,a){r(a)||(a=new l),e.fromArray(t,0,m);var s=e.magnitude(m);return l.unpack(i,4*o,v),0===s?l.clone(l.IDENTITY,f):l.fromAxisAngle(m,s,f),l.multiply(f,v,a)},l.clone=function(e,t){return r(e)?r(t)?(t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w,t):new l(e.x,e.y,e.z,e.w):void 0},l.conjugate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t.w=e.w,t},l.magnitudeSquared=function(e){return e.x*e.x+e.y*e.y+e.z*e.z+e.w*e.w},l.magnitude=function(e){return Math.sqrt(l.magnitudeSquared(e))},l.normalize=function(e,t){var r=1/l.magnitude(e),i=e.x*r,n=e.y*r,o=e.z*r,a=e.w*r;return t.x=i,t.y=n,t.z=o,t.w=a,t},l.inverse=function(e,t){var r=l.magnitudeSquared(e);return t=l.conjugate(e,t),l.multiplyByScalar(t,1/r,t)},l.add=function(e,t,r){return r.x=e.x+t.x,r.y=e.y+t.y,r.z=e.z+t.z,r.w=e.w+t.w,r},l.subtract=function(e,t,r){return r.x=e.x-t.x,r.y=e.y-t.y,r.z=e.z-t.z,r.w=e.w-t.w,r},l.negate=function(e,t){return t.x=-e.x,t.y=-e.y,t.z=-e.z,t.w=-e.w,t},l.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z+e.w*t.w},l.multiply=function(e,t,r){var i=e.x,n=e.y,o=e.z,a=e.w,s=t.x,l=t.y,u=t.z,c=t.w,h=a*s+i*c+n*u-o*l,d=a*l-i*u+n*c+o*s,p=a*u+i*l-n*s+o*c,m=a*c-i*s-n*l-o*u;return r.x=h,r.y=d,r.z=p,r.w=m,r},l.multiplyByScalar=function(e,t,r){return r.x=e.x*t,r.y=e.y*t,r.z=e.z*t,r.w=e.w*t,r},l.divideByScalar=function(e,t,r){return r.x=e.x/t,r.y=e.y/t,r.z=e.z/t,r.w=e.w/t,r},l.computeAxis=function(e,t){var r=e.w;if(Math.abs(r-1)<a.EPSILON6)return t.x=t.y=t.z=0,t;var i=1/Math.sqrt(1-r*r);return t.x=e.x*i,t.y=e.y*i,t.z=e.z*i,t},l.computeAngle=function(e){return Math.abs(e.w-1)<a.EPSILON6?0:2*Math.acos(e.w)};var g=new l;l.lerp=function(e,t,r,i){return g=l.multiplyByScalar(t,r,g),i=l.multiplyByScalar(e,1-r,i),l.add(g,i,i)};var y=new l,C=new l,E=new l;l.slerp=function(e,t,r,i){var n=l.dot(e,t),o=t;if(0>n&&(n=-n,o=y=l.negate(t,y)),1-n<a.EPSILON6)return l.lerp(e,o,r,i);var s=Math.acos(n);return C=l.multiplyByScalar(e,Math.sin((1-r)*s),C),E=l.multiplyByScalar(o,Math.sin(r*s),E),i=l.add(C,E,i),l.multiplyByScalar(i,1/Math.sin(s),i)},l.log=function(t,r){var i=a.acosClamped(t.w),n=0;return 0!==i&&(n=i/Math.sin(i)),e.multiplyByScalar(t,n,r)},l.exp=function(t,r){var i=e.magnitude(t),n=0;return 0!==i&&(n=Math.sin(i)/i),r.x=t.x*n,r.y=t.y*n,r.z=t.z*n,r.w=Math.cos(i),r};var S=new e,w=new e,T=new l,b=new l;l.computeInnerQuadrangle=function(t,r,i,n){var o=l.conjugate(r,T);l.multiply(o,i,b);var a=l.log(b,S);l.multiply(o,t,b);var s=l.log(b,w);return e.add(a,s,a),e.multiplyByScalar(a,.25,a),e.negate(a,a),l.exp(a,T),l.multiply(r,T,n)},l.squad=function(e,t,r,i,n,o){var a=l.slerp(e,t,n,T),s=l.slerp(r,i,n,b);return l.slerp(a,s,2*n*(1-n),o)};for(var x=new l,P=1.9011074535173003,A=n.supportsTypedArrays()?new Float32Array(8):[],I=n.supportsTypedArrays()?new Float32Array(8):[],M=n.supportsTypedArrays()?new Float32Array(8):[],D=n.supportsTypedArrays()?new Float32Array(8):[],R=0;7>R;++R){var O=R+1,N=2*O+1;A[R]=1/(O*N),I[R]=O/N}return A[7]=P/136,I[7]=8*P/17,l.fastSlerp=function(e,t,r,i){var n,o=l.dot(e,t);o>=0?n=1:(n=-1,o=-o);for(var a=o-1,s=1-r,u=r*r,c=s*s,h=7;h>=0;--h)M[h]=(A[h]*u-I[h])*a,D[h]=(A[h]*c-I[h])*a;var d=n*r*(1+M[0]*(1+M[1]*(1+M[2]*(1+M[3]*(1+M[4]*(1+M[5]*(1+M[6]*(1+M[7])))))))),p=s*(1+D[0]*(1+D[1]*(1+D[2]*(1+D[3]*(1+D[4]*(1+D[5]*(1+D[6]*(1+D[7])))))))),m=l.multiplyByScalar(e,p,x);return l.multiplyByScalar(t,d,i),l.add(m,i,i)},l.fastSquad=function(e,t,r,i,n,o){var a=l.fastSlerp(e,t,n,T),s=l.fastSlerp(r,i,n,b);return l.fastSlerp(a,s,2*n*(1-n),o)},l.equals=function(e,t){return e===t||r(e)&&r(t)&&e.x===t.x&&e.y===t.y&&e.z===t.z&&e.w===t.w},l.equalsEpsilon=function(e,t,i){return e===t||r(e)&&r(t)&&Math.abs(e.x-t.x)<=i&&Math.abs(e.y-t.y)<=i&&Math.abs(e.z-t.z)<=i&&Math.abs(e.w-t.w)<=i},l.ZERO=o(new l(0,0,0,0)),l.IDENTITY=o(new l(0,0,0,1)),l.prototype.clone=function(e){return l.clone(this,e)},l.prototype.equals=function(e){return l.equals(this,e)},l.prototype.equalsEpsilon=function(e,t){return l.equalsEpsilon(this,e,t)},l.prototype.toString=function(){return"("+this.x+", "+this.y+", "+this.z+", "+this.w+")"},l}),r("Core/Transforms",["../ThirdParty/when","./Cartesian2","./Cartesian3","./Cartesian4","./defaultValue","./defined","./DeveloperError","./EarthOrientationParameters","./EarthOrientationParametersSample","./Ellipsoid","./Iau2006XysData","./Iau2006XysSample","./JulianDate","./Math","./Matrix3","./Matrix4","./Quaternion","./TimeConstants"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";var g={},y=new r,C=new r,E=new r;g.eastNorthUpToFixedFrame=function(e,t,i){if(p.equalsEpsilon(e.x,0,p.EPSILON14)&&p.equalsEpsilon(e.y,0,p.EPSILON14)){var a=p.sign(e.z);return o(i)?(i[0]=0,i[1]=1,i[2]=0,i[3]=0,i[4]=-a,i[5]=0,i[6]=0,i[7]=0,i[8]=0,i[9]=0,i[10]=a,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(0,-a,0,e.x,1,0,0,e.y,0,0,a,e.z,0,0,0,1)}var s=y,l=C,c=E;return t=n(t,u.WGS84),t.geodeticSurfaceNormal(e,s),l.x=-e.y,l.y=e.x,l.z=0,r.normalize(l,l),r.cross(s,l,c),o(i)?(i[0]=l.x,i[1]=l.y,i[2]=l.z,i[3]=0,i[4]=c.x,i[5]=c.y,i[6]=c.z,i[7]=0,i[8]=s.x,i[9]=s.y,i[10]=s.z,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(l.x,c.x,s.x,e.x,l.y,c.y,s.y,e.y,l.z,c.z,s.z,e.z,0,0,0,1)};var S=new r,w=new r,T=new r;g.northEastDownToFixedFrame=function(e,t,i){if(p.equalsEpsilon(e.x,0,p.EPSILON14)&&p.equalsEpsilon(e.y,0,p.EPSILON14)){var a=p.sign(e.z);return o(i)?(i[0]=-a,i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=1,i[6]=0,i[7]=0,i[8]=0,i[9]=0,i[10]=-a,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(-a,0,0,e.x,0,1,0,e.y,0,0,-a,e.z,0,0,0,1)}var s=S,l=w,c=T;return t=n(t,u.WGS84),t.geodeticSurfaceNormal(e,s),l.x=-e.y,l.y=e.x,l.z=0,r.normalize(l,l),r.cross(s,l,c),o(i)?(i[0]=c.x,i[1]=c.y,i[2]=c.z,i[3]=0,i[4]=l.x,i[5]=l.y,i[6]=l.z,i[7]=0,i[8]=-s.x,i[9]=-s.y,i[10]=-s.z,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(c.x,l.x,-s.x,e.x,c.y,l.y,-s.y,e.y,c.z,l.z,-s.z,e.z,0,0,0,1)},g.northUpEastToFixedFrame=function(e,t,i){if(p.equalsEpsilon(e.x,0,p.EPSILON14)&&p.equalsEpsilon(e.y,0,p.EPSILON14)){var a=p.sign(e.z);return o(i)?(i[0]=-a,i[1]=0,i[2]=0,i[3]=0,i[4]=0,i[5]=0,i[6]=a,i[7]=0,i[8]=0,i[9]=1,i[10]=0,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(-a,0,0,e.x,0,0,1,e.y,0,a,0,e.z,0,0,0,1)}var s=y,l=C,c=E;return t=n(t,u.WGS84),t.geodeticSurfaceNormal(e,s),l.x=-e.y,l.y=e.x,l.z=0,r.normalize(l,l),r.cross(s,l,c),o(i)?(i[0]=c.x,i[1]=c.y,i[2]=c.z,i[3]=0,i[4]=s.x,i[5]=s.y,i[6]=s.z,i[7]=0,i[8]=l.x,i[9]=l.y,i[10]=l.z,i[11]=0,i[12]=e.x,i[13]=e.y,i[14]=e.z,i[15]=1,i):new f(c.x,s.x,l.x,e.x,c.y,s.y,l.y,e.y,c.z,s.z,l.z,e.z,0,0,0,1)};var b=new v,x=new r(1,1,1),P=new f;g.headingPitchRollToFixedFrame=function(e,t,i,n,o,a){var s=v.fromHeadingPitchRoll(t,i,n,b),l=f.fromTranslationQuaternionRotationScale(r.ZERO,s,x,P);return a=g.eastNorthUpToFixedFrame(e,o,a),f.multiply(a,l,a)};var A=new f,I=new m;g.headingPitchRollQuaternion=function(e,t,r,i,n,o){var a=g.headingPitchRollToFixedFrame(e,t,r,i,n,A),s=f.getRotation(a,I);return v.fromRotationMatrix(s,o)};var M=24110.54841,D=8640184.812866,R=.093104,O=-62e-7,N=1.1772758384668e-19,L=72921158553e-15,F=p.TWO_PI/86400,B=new d;g.computeTemeToPseudoFixedMatrix=function(e,t){B=d.addSeconds(e,-d.computeTaiMinusUtc(e),B);var r,i=B.dayNumber,n=B.secondsOfDay,a=i-2451545;r=n>=43200?(a+.5)/_.DAYS_PER_JULIAN_CENTURY:(a-.5)/_.DAYS_PER_JULIAN_CENTURY;var s=M+r*(D+r*(R+r*O)),l=s*F%p.TWO_PI,u=L+N*(i-2451545.5),c=(n+.5*_.SECONDS_PER_DAY)%_.SECONDS_PER_DAY,h=l+u*c,f=Math.cos(h),v=Math.sin(h);return o(t)?(t[0]=f,t[1]=-v,t[2]=0,t[3]=v,t[4]=f,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t):new m(f,v,0,-v,f,0,0,0,1)},g.iau2006XysData=new c,g.earthOrientationParameters=s.NONE;var V=32.184,z=2451545;g.preloadIcrfFixed=function(t){var r=t.start.dayNumber,i=t.start.secondsOfDay+V,n=t.stop.dayNumber,o=t.stop.secondsOfDay+V,a=g.iau2006XysData.preload(r,i,n,o),s=g.earthOrientationParameters.getPromiseToLoad();return e.all([a,s])},g.computeIcrfToFixedMatrix=function(e,t){o(t)||(t=new m);var r=g.computeFixedToIcrfMatrix(e,t);return o(r)?m.transpose(r,t):void 0};var k=new h(0,0,0),U=new l(0,0,0,0,0,0),G=new m,W=new m;g.computeFixedToIcrfMatrix=function(e,t){o(t)||(t=new m);var r=g.earthOrientationParameters.compute(e,U);if(!o(r))return void 0;var i=e.dayNumber,n=e.secondsOfDay+V,a=g.iau2006XysData.computeXysRadians(i,n,k);if(!o(a))return void 0;var s=a.x+r.xPoleOffset,l=a.y+r.yPoleOffset,u=1/(1+Math.sqrt(1-s*s-l*l)),c=G;c[0]=1-u*s*s,c[3]=-u*s*l,c[6]=s,c[1]=-u*s*l,c[4]=1-u*l*l,c[7]=l,c[2]=-s,c[5]=-l,c[8]=1-u*(s*s+l*l);var h=m.fromRotationZ(-a.s,W),f=m.multiply(c,h,G),v=e.dayNumber,y=e.secondsOfDay-d.computeTaiMinusUtc(e)+r.ut1MinusUtc,C=v-2451545,E=y/_.SECONDS_PER_DAY,S=.779057273264+E+.00273781191135448*(C+E);S=S%1*p.TWO_PI;var w=m.fromRotationZ(S,W),T=m.multiply(f,w,G),b=Math.cos(r.xPoleWander),x=Math.cos(r.yPoleWander),P=Math.sin(r.xPoleWander),A=Math.sin(r.yPoleWander),I=i-z+n/_.SECONDS_PER_DAY;I/=36525;var M=-47e-6*I*p.RADIANS_PER_DEGREE/3600,D=Math.cos(M),R=Math.sin(M),O=W;return O[0]=b*D,O[1]=b*R,O[2]=P,O[3]=-x*R+A*P*D,O[4]=x*D+A*P*R,O[5]=-A*b,O[6]=-A*R-x*P*D,O[7]=A*D-x*P*R,O[8]=x*b,m.multiply(T,O,t)};var H=new i;g.pointToWindowCoordinates=function(e,t,r,i){return i=g.pointToGLWindowCoordinates(e,t,r,i),i.y=2*t[5]-i.y,i},g.pointToGLWindowCoordinates=function(e,r,n,a){o(a)||(a=new t);var s=H;return f.multiplyByVector(e,i.fromElements(n.x,n.y,n.z,1,s),s),i.multiplyByScalar(s,1/s.w,s),f.multiplyByVector(r,s,s),t.fromCartesian4(s,a)};var q=new r,j=new r,Y=new r;return g.rotationMatrixFromPositionVelocity=function(e,t,i,a){var s=n(i,u.WGS84).geodeticSurfaceNormal(e,q),l=r.cross(t,s,j);r.equalsEpsilon(l,r.ZERO,p.EPSILON6)&&(l=r.clone(r.UNIT_X,l));var c=r.cross(l,t,Y);return r.cross(t,c,l),r.negate(l,l),o(a)||(a=new m),a[0]=t.x,a[1]=t.y,a[2]=t.z,a[3]=l.x,a[4]=l.y,a[5]=l.z,a[6]=c.x,a[7]=c.y,a[8]=c.z,a},g}),r("Core/EllipsoidTangentPlane",["./AxisAlignedBoundingBox","./Cartesian2","./Cartesian3","./Cartesian4","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./IntersectionTests","./Matrix3","./Matrix4","./Plane","./Ray","./Transforms"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new i,v=function(e,t){t=n(t,l.WGS84),e=t.scaleToGeodeticSurface(e);var i=m.eastNorthUpToFixedFrame(e,t);this._ellipsoid=t,this._origin=e,this._xAxis=r.fromCartesian4(h.getColumn(i,0,f)),this._yAxis=r.fromCartesian4(h.getColumn(i,1,f));var o=r.fromCartesian4(h.getColumn(i,2,f));this._plane=d.fromPointNormal(e,o)};a(v.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},origin:{get:function(){return this._origin}},plane:{get:function(){return this._plane}},xAxis:{get:function(){return this._xAxis}},yAxis:{get:function(){return this._yAxis}},zAxis:{get:function(){return this._plane.normal}}});var _=new e;v.fromPoints=function(t,r){var i=e.fromPoints(t,_);return new v(i.center,r)};var g=new p,y=new r;v.prototype.projectPointOntoPlane=function(e,i){var n=g;n.origin=e,r.normalize(e,n.direction);var a=u.rayPlane(n,this._plane,y);if(o(a)||(r.negate(n.direction,n.direction),a=u.rayPlane(n,this._plane,y)),o(a)){var s=r.subtract(a,this._origin,a),l=r.dot(this._xAxis,s),c=r.dot(this._yAxis,s);return o(i)?(i.x=l,i.y=c,i):new t(l,c)}return void 0},v.prototype.projectPointsOntoPlane=function(e,t){o(t)||(t=[]);for(var r=0,i=e.length,n=0;i>n;n++){var a=this.projectPointOntoPlane(e[n],t[r]);o(a)&&(t[r]=a,r++)}return t.length=r,t},v.prototype.projectPointToNearestOnPlane=function(e,i){o(i)||(i=new t);var n=g;n.origin=e,r.clone(this._plane.normal,n.direction);var a=u.rayPlane(n,this._plane,y);o(a)||(r.negate(n.direction,n.direction),a=u.rayPlane(n,this._plane,y));var s=r.subtract(a,this._origin,a),l=r.dot(this._xAxis,s),c=r.dot(this._yAxis,s);return i.x=l,i.y=c,i},v.prototype.projectPointsToNearestOnPlane=function(e,t){o(t)||(t=[]);var r=e.length;t.length=r;for(var i=0;r>i;i++)t[i]=this.projectPointToNearestOnPlane(e[i],t[i]);return t};var C=new r;return v.prototype.projectPointsOntoEllipsoid=function(e,t){var i=e.length;o(t)?t.length=i:t=new Array(i);for(var n=this._ellipsoid,a=this._origin,s=this._xAxis,l=this._yAxis,u=C,c=0;i>c;++c){var h=e[c];r.multiplyByScalar(s,h.x,u),o(t[c])||(t[c]=new r);var d=r.add(a,u,t[c]);r.multiplyByScalar(l,h.y,u),r.add(d,u,d),n.scaleToGeocentricSurface(d,d)}return t},v}),r("Core/OrientedBoundingBox",["./BoundingSphere","./Cartesian2","./Cartesian3","./Cartographic","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Intersect","./Interval","./Math","./Matrix3","./Plane","./Rectangle"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=function(e,t){this.center=r.clone(n(e,r.ZERO)),this.halfAxes=d.clone(n(t,d.ZERO))},v=new r,_=new r,g=new r,y=new r,C=new r,E=new d,S={unitary:new d,diagonal:new d};f.fromPoints=function(e,t){if(o(t)||(t=new f),!o(e)||0===e.length)return t.halfAxes=d.ZERO,t.center=r.ZERO,t;var i,n=e.length,a=r.clone(e[0],v);for(i=1;n>i;i++)r.add(a,e[i],a);var s=1/n;r.multiplyByScalar(a,s,a);var l,u=0,c=0,h=0,p=0,m=0,w=0;for(i=0;n>i;i++)l=r.subtract(e[i],a,_),u+=l.x*l.x,c+=l.x*l.y,h+=l.x*l.z,p+=l.y*l.y,m+=l.y*l.z,w+=l.z*l.z;u*=s,c*=s,h*=s,p*=s,m*=s,w*=s;var T=E;T[0]=u,T[1]=c,T[2]=h,T[3]=c,T[4]=p,T[5]=m,T[6]=h,T[7]=m,T[8]=w;var b=d.computeEigenDecomposition(T,S),x=d.transpose(b.unitary,t.halfAxes);l=r.subtract(e[0],a,_);var P=d.multiplyByVector(x,l,g),A=r.clone(P,y),I=r.clone(P,C);for(i=1;n>i;i++)l=r.subtract(e[i],a,l),d.multiplyByVector(x,l,P),r.minimumByComponent(I,P,I),r.maximumByComponent(A,P,A);var M=r.add(I,A,g);r.multiplyByScalar(M,.5,M),d.multiplyByVector(x,M,M),r.add(a,M,t.center);var D=r.subtract(A,I,g);return r.multiplyByScalar(D,.5,D),d.multiplyByScale(t.halfAxes,D,t.halfAxes),t};var w=new r,T=new r,b=function(e,t,i,n,a,s,l,u){o(u)||(u=new f);var c=u.halfAxes;d.setColumn(c,0,e.xAxis,c),d.setColumn(c,1,e.yAxis,c),d.setColumn(c,2,e.zAxis,c);var h=w;h.x=(t+i)/2,h.y=(n+a)/2,h.z=(s+l)/2;var p=T;p.x=(i-t)/2,p.y=(a-n)/2,p.z=(l-s)/2;var m=u.center;return h=d.multiplyByVector(c,h,h),r.add(e.origin,h,m),d.multiplyByScale(c,p,c),u},x=new i,P=new r,A=[new i,new i,new i,new i,new i,new i,new i,new i],I=[new r,new r,new r,new r,new r,new r,new r,new r],M=[new t,new t,new t,new t,new t,new t,new t,new t];f.fromRectangle=function(e,t,r,i,o){t=n(t,0),r=n(r,0),i=n(i,s.WGS84);var a=m.center(e,x),u=i.cartographicToCartesian(a,P),c=new l(u,i),h=c.plane,d=A[0],f=A[1],v=A[2],_=A[3],g=A[4],y=A[5],C=A[6],E=A[7],S=a.longitude,w=e.south<0&&e.north>0?0:a.latitude;C.latitude=y.latitude=g.latitude=e.south,E.latitude=_.latitude=w,d.latitude=f.latitude=v.latitude=e.north,C.longitude=E.longitude=d.longitude=e.west,y.longitude=f.longitude=S,g.longitude=_.longitude=v.longitude=e.east,v.height=f.height=d.height=E.height=C.height=y.height=g.height=_.height=r,i.cartographicArrayToCartesianArray(A,I),c.projectPointsToNearestOnPlane(I,M);var T=Math.min(M[6].x,M[7].x,M[0].x),D=Math.max(M[2].x,M[3].x,M[4].x),R=Math.min(M[4].y,M[5].y,M[6].y),O=Math.max(M[0].y,M[1].y,M[2].y);v.height=d.height=g.height=C.height=t,i.cartographicArrayToCartesianArray(A,I);var N=Math.min(p.getPointDistance(h,I[0]),p.getPointDistance(h,I[2]),p.getPointDistance(h,I[4]),p.getPointDistance(h,I[6])),L=r;return b(c,T,D,R,O,N,L,o)},f.clone=function(e,t){return o(e)?o(t)?(r.clone(e.center,t.center),d.clone(e.halfAxes,t.halfAxes),t):new f(e.center,e.halfAxes):void 0},f.intersectPlane=function(e,t){var i=e.center,n=t.normal,o=e.halfAxes,a=n.x,s=n.y,l=n.z,c=Math.abs(a*o[d.COLUMN0ROW0]+s*o[d.COLUMN0ROW1]+l*o[d.COLUMN0ROW2])+Math.abs(a*o[d.COLUMN1ROW0]+s*o[d.COLUMN1ROW1]+l*o[d.COLUMN1ROW2])+Math.abs(a*o[d.COLUMN2ROW0]+s*o[d.COLUMN2ROW1]+l*o[d.COLUMN2ROW2]),h=r.dot(n,i)+t.distance;return-c>=h?u.OUTSIDE:h>=c?u.INSIDE:u.INTERSECTING};var D=new r,R=new r,O=new r,N=new r;f.distanceSquaredTo=function(e,t){var i=r.subtract(t,e.center,w),n=e.halfAxes,o=d.getColumn(n,0,D),a=d.getColumn(n,1,R),s=d.getColumn(n,2,O),l=r.magnitude(o),u=r.magnitude(a),c=r.magnitude(s);r.normalize(o,o),r.normalize(a,a),r.normalize(s,s);var h=N;h.x=r.dot(i,o),h.y=r.dot(i,a),h.z=r.dot(i,s);var p,m=0;return h.x<-l?(p=h.x+l,m+=p*p):h.x>l&&(p=h.x-l,m+=p*p),h.y<-u?(p=h.y+u,m+=p*p):h.y>u&&(p=h.y-u,m+=p*p),h.z<-c?(p=h.z+c,m+=p*p):h.z>c&&(p=h.z-c,m+=p*p),m};var L=new r,F=new r;new r;f.computePlaneDistances=function(e,t,i,n){o(n)||(n=new c);var a=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,l=e.center,u=e.halfAxes,h=d.getColumn(u,0,D),p=d.getColumn(u,1,R),m=d.getColumn(u,2,O),f=r.add(h,p,L);r.add(f,m,f),r.add(f,l,f);var v=r.subtract(f,t,F),_=r.dot(i,v);return a=Math.min(_,a),s=Math.max(_,s),r.add(l,h,f),r.add(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.add(l,h,f),r.subtract(f,p,f),r.add(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.add(l,h,f),r.subtract(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.add(f,p,f),r.add(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.add(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.subtract(f,p,f),r.add(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),r.subtract(l,h,f),r.subtract(f,p,f),r.subtract(f,m,f),r.subtract(f,t,v),_=r.dot(i,v),a=Math.min(_,a),s=Math.max(_,s),n.start=a,n.stop=s,n};var B=new e;return f.isOccluded=function(t,r){var i=e.fromOrientedBoundingBox(t,B);return!r.isBoundingSphereVisible(i)},f.prototype.intersectPlane=function(e){return f.intersectPlane(this,e)},f.prototype.distanceSquaredTo=function(e){return f.distanceSquaredTo(this,e)},f.prototype.computePlaneDistances=function(e,t,r){return f.computePlaneDistances(this,e,t,r)},f.prototype.isOccluded=function(e){return f.isOccluded(this,e)},f.equals=function(e,t){return e===t||o(e)&&o(t)&&r.equals(e.center,t.center)&&d.equals(e.halfAxes,t.halfAxes)},f.prototype.clone=function(e){return f.clone(this,e)},f.prototype.equals=function(e){return f.equals(this,e)},f}),r("Core/Intersections2D",["./Cartesian3","./defined","./DeveloperError"],function(e,t,r){"use strict";var i={};return i.clipTriangleAtAxisAlignedThreshold=function(e,r,i,n,o,a){t(a)?a.length=0:a=[];var s,l,u;r?(s=e>i,l=e>n,u=e>o):(s=i>e,l=n>e,u=o>e);var c,h,d,p,m,f,v=s+l+u;return 1===v?s?(c=(e-i)/(n-i),h=(e-i)/(o-i),a.push(1),a.push(2),1!==h&&(a.push(-1),a.push(0),a.push(2),a.push(h)),1!==c&&(a.push(-1),a.push(0),a.push(1),a.push(c))):l?(d=(e-n)/(o-n),p=(e-n)/(i-n),a.push(2),a.push(0),1!==p&&(a.push(-1),a.push(1),a.push(0),a.push(p)),1!==d&&(a.push(-1),a.push(1),a.push(2),a.push(d))):u&&(m=(e-o)/(i-o),f=(e-o)/(n-o),a.push(0),a.push(1),1!==f&&(a.push(-1),a.push(2),a.push(1),a.push(f)),1!==m&&(a.push(-1),a.push(2),a.push(0),a.push(m))):2===v?s||i===e?l||n===e?u||o===e||(h=(e-i)/(o-i),d=(e-n)/(o-n),a.push(2),a.push(-1),a.push(0),a.push(2),a.push(h),a.push(-1),a.push(1),a.push(2),a.push(d)):(f=(e-o)/(n-o),c=(e-i)/(n-i),a.push(1),a.push(-1),a.push(2),a.push(1),a.push(f),a.push(-1),a.push(0),a.push(1),a.push(c)):(p=(e-n)/(i-n),m=(e-o)/(i-o),a.push(0),a.push(-1),a.push(1),a.push(0),a.push(p),a.push(-1),a.push(2),a.push(0),a.push(m)):3===v||(a.push(0),a.push(1),a.push(2)),a},i.computeBarycentricCoordinates=function(r,i,n,o,a,s,l,u,c){var h=n-l,d=l-a,p=s-u,m=o-u,f=1/(p*h+d*m),v=i-u,_=r-l,g=(p*_+d*v)*f,y=(-m*_+h*v)*f,C=1-g-y;return t(c)?(c.x=g,c.y=y,c.z=C,c):new e(g,y,C)},i}),r("Core/QuantizedMeshTerrainData",["../ThirdParty/when","./BoundingSphere","./Cartesian3","./defaultValue","./defined","./defineProperties","./DeveloperError","./IndexDatatype","./Intersections2D","./Math","./OrientedBoundingBox","./TaskProcessor","./TerrainMesh"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e,t,r){f.length=e.length;for(var i=!1,n=0,o=e.length;o>n;++n)f[n]=e[n],i=i||n>0&&t(e[n-1],e[n])>0;return i?(f.sort(t),s.createTypedArray(r,f)):e}var m=function(e){function t(e,t){return a[e]-a[t]}function r(e,t){return o[e]-o[t]}this._quantizedVertices=e.quantizedVertices,this._encodedNormals=e.encodedNormals,this._indices=e.indices,this._minimumHeight=e.minimumHeight,this._maximumHeight=e.maximumHeight,this._boundingSphere=e.boundingSphere,this._orientedBoundingBox=e.orientedBoundingBox,this._horizonOcclusionPoint=e.horizonOcclusionPoint;var n=this._quantizedVertices.length/3,o=this._uValues=this._quantizedVertices.subarray(0,n),a=this._vValues=this._quantizedVertices.subarray(n,2*n);this._heightValues=this._quantizedVertices.subarray(2*n,3*n);this._westIndices=p(e.westIndices,t,n),this._southIndices=p(e.southIndices,r,n),this._eastIndices=p(e.eastIndices,t,n),this._northIndices=p(e.northIndices,r,n),this._westSkirtHeight=e.westSkirtHeight,this._southSkirtHeight=e.southSkirtHeight,this._eastSkirtHeight=e.eastSkirtHeight,this._northSkirtHeight=e.northSkirtHeight,this._childTileMask=i(e.childTileMask,15),this._createdByUpsampling=i(e.createdByUpsampling,!1),this._waterMask=e.waterMask};o(m.prototype,{waterMask:{get:function(){return this._waterMask}}});var f=[],v=new h("createVerticesFromQuantizedTerrainMesh");m.prototype.createMesh=function(t,r,i,o){var a=t.ellipsoid,l=t.tileXYToRectangle(r,i,o),u=v.scheduleTask({minimumHeight:this._minimumHeight,maximumHeight:this._maximumHeight,quantizedVertices:this._quantizedVertices,octEncodedNormals:this._encodedNormals,indices:this._indices,westIndices:this._westIndices,southIndices:this._southIndices,eastIndices:this._eastIndices,northIndices:this._northIndices,westSkirtHeight:this._westSkirtHeight,southSkirtHeight:this._southSkirtHeight,eastSkirtHeight:this._eastSkirtHeight,northSkirtHeight:this._northSkirtHeight,rectangle:l,relativeToCenter:this._boundingSphere.center,ellipsoid:a});if(!n(u))return void 0;var c=this;return e(u,function(e){var t=c._quantizedVertices.length/3;t+=c._westIndices.length+c._southIndices.length+c._eastIndices.length+c._northIndices.length;var r=s.createTypedArray(t,e.indices);return new d(c._boundingSphere.center,new Float32Array(e.vertices),r,c._minimumHeight,c._maximumHeight,c._boundingSphere,c._horizonOcclusionPoint,n(c._encodedNormals)?7:6,c._orientedBoundingBox)})};var _=new h("upsampleQuantizedTerrainMesh");m.prototype.upsample=function(i,o,a,l,u,h,d){var p=2*o!==u,f=2*a===h,v=i.ellipsoid,g=i.tileXYToRectangle(u,h,d),y=_.scheduleTask({vertices:this._quantizedVertices,indices:this._indices,encodedNormals:this._encodedNormals,minimumHeight:this._minimumHeight,maximumHeight:this._maximumHeight,isEastChild:p,isNorthChild:f,childRectangle:g,ellipsoid:v});if(!n(y))return void 0;var C=Math.min(this._westSkirtHeight,this._eastSkirtHeight);C=Math.min(C,this._southSkirtHeight),C=Math.min(C,this._northSkirtHeight);var E=p?.5*C:this._westSkirtHeight,S=f?.5*C:this._southSkirtHeight,w=p?this._eastSkirtHeight:.5*C,T=f?this._northSkirtHeight:.5*C;return e(y,function(e){var i,o=new Uint16Array(e.vertices),a=s.createTypedArray(o.length/3,e.indices);return n(e.encodedNormals)&&(i=new Uint8Array(e.encodedNormals)),new m({quantizedVertices:o,indices:a,encodedNormals:i,minimumHeight:e.minimumHeight,maximumHeight:e.maximumHeight,boundingSphere:t.clone(e.boundingSphere),orientedBoundingBox:c.clone(e.orientedBoundingBox),horizonOcclusionPoint:r.clone(e.horizonOcclusionPoint),westIndices:e.westIndices,southIndices:e.southIndices,eastIndices:e.eastIndices,northIndices:e.northIndices,westSkirtHeight:E,southSkirtHeight:S,eastSkirtHeight:w,northSkirtHeight:T,childTileMask:0,createdByUpsampling:!0})})};var g=32767,y=new r;return m.prototype.interpolateHeight=function(e,t,r){var i=u.clamp((t-e.west)/e.width,0,1);i*=g;var n=u.clamp((r-e.south)/e.height,0,1);n*=g;for(var o=this._uValues,a=this._vValues,s=this._heightValues,c=this._indices,h=0,d=c.length;d>h;h+=3){var p=c[h],m=c[h+1],f=c[h+2],v=o[p],_=o[m],C=o[f],E=a[p],S=a[m],w=a[f],T=l.computeBarycentricCoordinates(i,n,v,E,_,S,C,w,y);if(T.x>=-1e-15&&T.y>=-1e-15&&T.z>=-1e-15){var b=T.x*s[p]+T.y*s[m]+T.z*s[f];return u.lerp(this._minimumHeight,this._maximumHeight,b/g)}}return void 0},m.prototype.isChildAvailable=function(e,t,r,i){var n=2;return r!==2*e&&++n,i!==2*t&&(n-=2),0!==(this._childTileMask&1<<n)},m.prototype.wasCreatedByUpsampling=function(){return this._createdByUpsampling},m}),r("Core/formatError",["./defined"],function(e){"use strict";var t=function(t){var r,i=t.name,n=t.message;r=e(i)&&e(n)?i+": "+n:t.toString();var o=t.stack;return e(o)&&(r+="\n"+o),r};return t}),r("Core/TileProviderError",["./defaultValue","./defined","./formatError"],function(e,t,r){"use strict";var i=function(t,r,i,n,o,a,s){this.provider=t,this.message=r,this.x=i,this.y=n,this.level=o,this.timesRetried=e(a,0),this.retry=!1,this.error=s};return i.handleError=function(e,n,o,a,s,l,u,c,h){var d=e;return t(e)?(d.provider=n,d.message=a,d.x=s,d.y=l,d.level=u,d.retry=!1,d.error=h,++d.timesRetried):d=new i(n,a,s,l,u,0,h),o.numberOfListeners>0?o.raiseEvent(d):console.log('An error occurred in "'+n.constructor.name+'": '+r(a)),d.retry&&t(c)&&c(),d},i.handleSuccess=function(e){t(e)&&(e.timesRetried=-1)},i}),r("Core/CesiumTerrainProvider",["../ThirdParty/Uri","../ThirdParty/when","./BoundingSphere","./Cartesian3","./Credit","./defaultValue","./defined","./defineProperties","./DeveloperError","./Event","./GeographicTilingScheme","./HeightmapTerrainData","./IndexDatatype","./joinUrls","./loadArrayBuffer","./loadJson","./Math","./Matrix3","./OrientedBoundingBox","./QuantizedMeshTerrainData","./RuntimeError","./TerrainProvider","./throttleRequestByServer","./TileProviderError"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";function T(e){if(a(e)&&0!==e.length){var t=e.join("-");return{Accept:"application/vnd.quantized-mesh;extensions="+t+",application/octet-stream;q=0.9,*/*;q=0.01"}}return{Accept:"application/vnd.quantized-mesh,application/octet-stream;q=0.9,*/*;q=0.01"}}function b(e,t,r,i,n,o){ -var a=new Uint16Array(t,0,e._heightmapWidth*e._heightmapWidth);return new h({buffer:a,childTileMask:new Uint8Array(t,a.byteLength,1)[0],waterMask:new Uint8Array(t,a.byteLength+1,t.byteLength-a.byteLength-1),width:e._heightmapWidth,height:e._heightmapWidth,structure:e._heightmapStructure})}function x(e,t,n,o,a,s){function l(e){return e>>1^-(1&e)}var u=0,c=3,h=c+1,p=Float64Array.BYTES_PER_ELEMENT*c,m=Float64Array.BYTES_PER_ELEMENT*h,f=3,_=Uint16Array.BYTES_PER_ELEMENT*f,C=3,E=Uint16Array.BYTES_PER_ELEMENT,S=E*C,w=new DataView(t),T=new i(w.getFloat64(u,!0),w.getFloat64(u+8,!0),w.getFloat64(u+16,!0));u+=p;var b=w.getFloat32(u,!0);u+=Float32Array.BYTES_PER_ELEMENT;var x=w.getFloat32(u,!0);u+=Float32Array.BYTES_PER_ELEMENT;var A=new r(new i(w.getFloat64(u,!0),w.getFloat64(u+8,!0),w.getFloat64(u+16,!0)),w.getFloat64(u+p,!0));u+=m;var I=new i(w.getFloat64(u,!0),w.getFloat64(u+8,!0),w.getFloat64(u+16,!0));u+=p;var D=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var R=new Uint16Array(t,u,3*D);u+=D*_,D>65536&&(E=Uint32Array.BYTES_PER_ELEMENT,S=E*C);var O,N=R.subarray(0,D),L=R.subarray(D,2*D),F=R.subarray(2*D,3*D),B=0,V=0,z=0;for(O=0;D>O;++O)B+=l(N[O]),V+=l(L[O]),z+=l(F[O]),N[O]=B,L[O]=V,F[O]=z;u%E!==0&&(u+=E-u%E);var k=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var U=d.createTypedArrayFromArrayBuffer(D,t,u,k*C);u+=k*S;var G=0;for(O=0;O<U.length;++O){var W=U[O];U[O]=G-W,0===W&&++G}var H=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var q=d.createTypedArrayFromArrayBuffer(D,t,u,H);u+=H*E;var j=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var Y=d.createTypedArrayFromArrayBuffer(D,t,u,j);u+=j*E;var X=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var Z=d.createTypedArrayFromArrayBuffer(D,t,u,X);u+=X*E;var K=w.getUint32(u,!0);u+=Uint32Array.BYTES_PER_ELEMENT;var J=d.createTypedArrayFromArrayBuffer(D,t,u,K);u+=K*E;for(var Q,$;u<w.byteLength;){var ee=w.getUint8(u,!0);u+=Uint8Array.BYTES_PER_ELEMENT;var te=w.getUint32(u,e._littleEndianExtensionSize);u+=Uint32Array.BYTES_PER_ELEMENT,ee===M.OCT_VERTEX_NORMALS&&e._requestVertexNormals?Q=new Uint8Array(t,u,2*D):ee===M.WATER_MASK&&e._requestWaterMask&&($=new Uint8Array(t,u,te)),u+=te}var re,ie=5*e.getLevelMaximumGeometricError(n),ne=e._tilingScheme.tileXYToRectangle(o,a,n);return ne.width<v.PI_OVER_TWO+v.EPSILON5&&(re=g.fromRectangle(ne,b,x,e._tilingScheme.ellipsoid)),new y({center:T,minimumHeight:b,maximumHeight:x,boundingSphere:A,orientedBoundingBox:re,horizonOcclusionPoint:I,quantizedVertices:R,encodedNormals:Q,indices:U,westIndices:q,southIndices:Y,eastIndices:Z,northIndices:J,westSkirtHeight:ie,southSkirtHeight:ie,eastSkirtHeight:ie,northSkirtHeight:ie,childTileMask:P(e,n,o,s),waterMask:$})}function P(e,t,r,i){var n=e._availableTiles;if(!n||0===n.length)return 15;var o=t+1;if(o>=n.length)return 0;var a=n[o],s=0;return s|=A(a,2*r,2*i)?1:0,s|=A(a,2*r+1,2*i)?2:0,s|=A(a,2*r,2*i+1)?4:0,s|=A(a,2*r+1,2*i+1)?8:0}function A(e,t,r){for(var i=0,n=e.length;n>i;++i){var o=e[i];if(t>=o.startX&&t<=o.endX&&r>=o.startY&&r<=o.endY)return!0}return!1}var I=function(r){function i(t){var r;if(!t.format)return r="The tile format is not specified in the layer.json file.",void(m=w.handleError(m,v,v._errorEvent,r,void 0,void 0,void 0,l));if(!t.tiles||0===t.tiles.length)return r="The layer.json file does not specify any tile URL templates.",void(m=w.handleError(m,v,v._errorEvent,r,void 0,void 0,void 0,l));if("heightmap-1.0"===t.format)v._heightmapStructure={heightScale:.2,heightOffset:-1e3,elementsPerHeight:1,stride:1,elementMultiplier:256,isBigEndian:!1},v._hasWaterMask=!0,v._requestWaterMask=!0;else if(0!==t.format.indexOf("quantized-mesh-1."))return r='The tile format "'+t.format+'" is invalid or not supported.',void(m=w.handleError(m,v,v._errorEvent,r,void 0,void 0,void 0,l));v._tileUrlTemplates=t.tiles;for(var i=0;i<v._tileUrlTemplates.length;++i){var o=new e(v._tileUrlTemplates[i]),s=new e(v._url);o.authority&&!s.authority&&(s.authority=o.authority,s.scheme=o.scheme),v._tileUrlTemplates[i]=p(s,o).toString().replace("{version}",t.version)}v._availableTiles=t.available;for(var i=0;i<v._availableTiles.length;i++)v._availableLevels&&-1===v._availableLevels.indexOf(i)&&(v._availableTiles[i]=[]);!a(v._credit)&&a(t.attribution)&&null!==t.attribution&&(v._credit=new n(t.attribution)),a(t.extensions)&&-1!==t.extensions.indexOf("octvertexnormals")?v._hasVertexNormals=!0:a(t.extensions)&&-1!==t.extensions.indexOf("vertexnormals")&&(v._hasVertexNormals=!0,v._littleEndianExtensionSize=!1),a(t.extensions)&&-1!==t.extensions.indexOf("watermask")&&(v._hasWaterMask=!0),v._ready=!0,v._readyPromise.resolve(!0)}function s(e){if(a(e)&&404===e.statusCode)return void i({tilejson:"2.1.0",format:"heightmap-1.0",version:"1.0.0",scheme:"tms",tiles:["{z}/{x}/{y}.terrain?v={version}"]});var t="An error occurred while accessing "+d+".";m=w.handleError(m,v,v._errorEvent,t,void 0,void 0,void 0,l)}function l(){var e=f(d);t(e,i,s)}this._availableLevels=r.availableLevels,this._url=r.url,this._proxy=r.proxy,this._rectangle=r.rectangle,this._tilingScheme=new c({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:1,ellipsoid:r.ellipsoid}),this._heightmapWidth=65,this._levelZeroMaximumGeometricError=E.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid,this._heightmapWidth,this._tilingScheme.getNumberOfXTilesAtLevel(0)),this._heightmapStructure=void 0,this._hasWaterMask=!1,this._hasVertexNormals=!1,this._requestVertexNormals=o(r.requestVertexNormals,!1),this._littleEndianExtensionSize=!0,this._requestWaterMask=o(r.requestWaterMask,!1),this._errorEvent=new u;var h=r.credit;"string"==typeof h&&(h=new n(h)),this._credit=h,this._ready=!1,this._readyPromise=t.defer();var d=p(this._url,"layer.json");a(this._proxy)&&(d=this._proxy.getURL(d));var m,v=this;l()},M={OCT_VERTEX_NORMALS:1,WATER_MASK:2};return I.prototype.requestTileGeometry=function(e,r,i,n){var s=this._tileUrlTemplates;if(0===s.length)return void 0;var l=this._tilingScheme.getNumberOfYTilesAtLevel(i),u=l-r-1,c=s[(e+u+i)%s.length].replace("{z}",i).replace("{x}",e).replace("{y}",u),h=this._proxy;a(h)&&(c=h.getURL(c));var d,p=[];this._requestVertexNormals&&this._hasVertexNormals&&p.push(this._littleEndianExtensionSize?"octvertexnormals":"vertexnormals"),this._requestWaterMask&&this._hasWaterMask&&p.push("watermask");var f=function(e){return m(e,T(p))};if(n=o(n,!0)){if(d=S(c,f),!a(d))return void 0}else d=f(c);var v=this;return t(d,function(t){return a(v._heightmapStructure)?b(v,t,i,e,r,u):x(v,t,i,e,r,u)})},s(I.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return this._credit}},tilingScheme:{get:function(){return this._tilingScheme}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},hasWaterMask:{get:function(){return this._hasWaterMask&&this._requestWaterMask}},hasVertexNormals:{get:function(){return this._hasVertexNormals&&this._requestVertexNormals}},requestVertexNormals:{get:function(){return this._requestVertexNormals}},requestWaterMask:{get:function(){return this._requestWaterMask}}}),I.prototype.getLevelMaximumGeometricError=function(e){return this._levelZeroMaximumGeometricError/(1<<e)},I.prototype.getTileDataAvailable=function(e,t,r){var i=this._availableTiles;if(i&&0!==i.length){if(r>=i.length)return!1;var n=i[r],o=this._tilingScheme.getNumberOfYTilesAtLevel(r),a=o-t-1;return A(n,e,a)}return void 0},I}),r("Core/EllipseGeometryLibrary",["./Cartesian3","./Math","./Matrix3","./Quaternion"],function(e,t,r,i){"use strict";function n(t,n,o,c,h,d,p,m,f,v){var _=t+n;e.multiplyByScalar(c,Math.cos(_),a),e.multiplyByScalar(o,Math.sin(_),s),e.add(a,s,a);var g=Math.cos(t);g*=g;var y=Math.sin(t);y*=y;var C=d/Math.sqrt(p*g+h*y),E=C/m;return i.fromAxisAngle(a,E,l),r.fromQuaternion(l,u),r.multiplyByVector(u,f,v),e.normalize(v,v),e.multiplyByScalar(v,m,v),v}var o={},a=new e,s=new e,l=new i,u=new r,c=new e,h=new e,d=new e,p=new e;o.raisePositionsToHeight=function(t,r,i){for(var n=r.ellipsoid,o=r.height,a=r.extrudedHeight,s=i?t.length/3*2:t.length/3,l=new Float64Array(3*s),u=t.length,m=i?u:0,f=0;u>f;f+=3){var v=f+1,_=f+2,g=e.fromArray(t,f,c);n.scaleToGeodeticSurface(g,g);var y=e.clone(g,h),C=n.geodeticSurfaceNormal(g,p),E=e.multiplyByScalar(C,o,d);e.add(g,E,g),i&&(e.multiplyByScalar(C,a,E),e.add(y,E,y),l[f+m]=y.x,l[v+m]=y.y,l[_+m]=y.z),l[f]=g.x,l[v]=g.y,l[_]=g.z}return l};var m=new e,f=new e,v=new e;return o.computeEllipsePositions=function(r,i,o){var a=r.semiMinorAxis,s=r.semiMajorAxis,l=r.rotation,u=r.center,p=8*r.granularity,_=a*a,g=s*s,y=s*a,C=e.magnitude(u),E=e.normalize(u,m),S=e.cross(e.UNIT_Z,u,f);S=e.normalize(S,S);var w=e.cross(E,S,v),T=1+Math.ceil(t.PI_OVER_TWO/p),b=t.PI_OVER_TWO/(T-1),x=t.PI_OVER_TWO-T*b;0>x&&(T-=Math.ceil(Math.abs(x)/b));var P,A,I,M,D,R=2*T*(T+1),O=i?new Array(3*R):void 0,N=0,L=c,F=h,B=3*(2*T+2*(T-1)),V=B-1,z=0,k=o?new Array(B):void 0;for(x=t.PI_OVER_TWO,P=0;T>P;++P){if(L=n(x,l,w,S,_,y,g,C,E,L),F=n(Math.PI-x,l,w,S,_,y,g,C,E,F),i){for(O[N++]=L.x,O[N++]=L.y,O[N++]=L.z,I=2*P+2,A=1;I-1>A;++A)M=A/(I-1),D=e.lerp(L,F,M,d),O[N++]=D.x,O[N++]=D.y,O[N++]=D.z;O[N++]=F.x,O[N++]=F.y,O[N++]=F.z}o&&(k[V--]=L.z,k[V--]=L.y,k[V--]=L.x,0!==P&&(k[z++]=F.x,k[z++]=F.y,k[z++]=F.z)),x=t.PI_OVER_TWO-(P+1)*b}for(P=T;P>0;--P){if(x=t.PI_OVER_TWO-(P-1)*b,L=n(-x,l,w,S,_,y,g,C,E,L),F=n(x+Math.PI,l,w,S,_,y,g,C,E,F),i){for(O[N++]=L.x,O[N++]=L.y,O[N++]=L.z,I=2*(P-1)+2,A=1;I-1>A;++A)M=A/(I-1),D=e.lerp(L,F,M,d),O[N++]=D.x,O[N++]=D.y,O[N++]=D.z;O[N++]=F.x,O[N++]=F.y,O[N++]=F.z}o&&(k[V--]=L.z,k[V--]=L.y,k[V--]=L.x,1!==P&&(k[z++]=F.x,k[z++]=F.y,k[z++]=F.z))}var U={};return i&&(U.positions=O,U.numPts=T),o&&(U.outerPositions=k),U},o}),r("Core/GeometryInstance",["./defaultValue","./defined","./DeveloperError","./Matrix4"],function(e,t,r,i){"use strict";var n=function(t){t=e(t,e.EMPTY_OBJECT),this.geometry=t.geometry,this.modelMatrix=i.clone(e(t.modelMatrix,i.IDENTITY)),this.id=t.id,this.pickPrimitive=t.pickPrimitive,this.attributes=e(t.attributes,{}),this.westHemisphereGeometry=void 0,this.eastHemisphereGeometry=void 0};return n}),r("Core/barycentricCoordinates",["./Cartesian2","./Cartesian3","./defined","./DeveloperError"],function(e,t,r,i){"use strict";var n=new t,o=new t,a=new t,s=function(i,s,l,u,c){r(c)||(c=new t);var h,d,p,m,f,v,_,g;r(s.z)?(h=t.subtract(l,s,n),d=t.subtract(u,s,o),p=t.subtract(i,s,a),m=t.dot(h,h),f=t.dot(h,d),v=t.dot(h,p),_=t.dot(d,d),g=t.dot(d,p)):(h=e.subtract(l,s,n),d=e.subtract(u,s,o),p=e.subtract(i,s,a),m=e.dot(h,h),f=e.dot(h,d),v=e.dot(h,p),_=e.dot(d,d),g=e.dot(d,p));var y=1/(m*_-f*f);return c.y=(_*v-f*g)*y,c.z=(m*g-f*v)*y,c.x=1-c.y-c.z,c};return s}),r("Core/EncodedCartesian3",["./Cartesian3","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(){this.high=e.clone(e.ZERO),this.low=e.clone(e.ZERO)};i.encode=function(e,r){t(r)||(r={high:0,low:0});var i;return e>=0?(i=65536*Math.floor(e/65536),r.high=i,r.low=e-i):(i=65536*Math.floor(-e/65536),r.high=-i,r.low=e+i),r};var n={high:0,low:0};i.fromCartesian=function(e,r){t(r)||(r=new i);var o=r.high,a=r.low;return i.encode(e.x,n),o.x=n.high,a.x=n.low,i.encode(e.y,n),o.y=n.high,a.y=n.low,i.encode(e.z,n),o.z=n.high,a.z=n.low,r};var o=new i;return i.writeElements=function(e,t,r){i.fromCartesian(e,o);var n=o.high,a=o.low;t[r]=n.x,t[r+1]=n.y,t[r+2]=n.z,t[r+3]=a.x,t[r+4]=a.y,t[r+5]=a.z},i}),r("Core/Tipsify",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i={};return i.calculateACMR=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.indices,n=r.maximumIndex,o=e(r.cacheSize,24),a=i.length;if(!t(n)){n=0;for(var s=0,l=i[s];a>s;)l>n&&(n=l),++s,l=i[s]}for(var u=[],c=0;n+1>c;c++)u[c]=0;for(var h=o+1,d=0;a>d;++d)h-u[i[d]]>o&&(u[i[d]]=h,++h);return(h-o+1)/(a/3)},i.tipsify=function(r){function i(e,t,r,i){for(;t.length>=1;){var n=t[t.length-1];if(t.splice(t.length-1,1),e[n].numLiveTriangles>0)return n}for(;i>o;){if(e[o].numLiveTriangles>0)return++o,o-1;++o}return-1}function n(e,t,r,n,o,a,s){for(var l,u=-1,c=-1,h=0;h<r.length;){var d=r[h];n[d].numLiveTriangles&&(l=0,o-n[d].timeStamp+2*n[d].numLiveTriangles<=t&&(l=o-n[d].timeStamp),(l>c||-1===c)&&(c=l,u=d)),++h}return-1===u?i(n,a,e,s):u}r=e(r,e.EMPTY_OBJECT);var o,a=r.indices,s=r.maximumIndex,l=e(r.cacheSize,24),u=a.length,c=0,h=0,d=a[h],p=u;if(t(s))c=s+1;else{for(;p>h;)d>c&&(c=d),++h,d=a[h];if(-1===c)return 0;++c}for(var m=[],f=0;c>f;f++)m[f]={numLiveTriangles:0,timeStamp:0,vertexTriangles:[]};h=0;for(var v=0;p>h;)m[a[h]].vertexTriangles.push(v),++m[a[h]].numLiveTriangles,m[a[h+1]].vertexTriangles.push(v),++m[a[h+1]].numLiveTriangles,m[a[h+2]].vertexTriangles.push(v),++m[a[h+2]].numLiveTriangles,++v,h+=3;var _=0,g=l+1;o=1;var y,C,E=[],S=[],w=0,T=[],b=u/3,x=[];for(f=0;b>f;f++)x[f]=!1;for(var P,A;-1!==_;){E=[],C=m[_],A=C.vertexTriangles.length;for(var I=0;A>I;++I)if(v=C.vertexTriangles[I],!x[v]){x[v]=!0,h=v+v+v;for(var M=0;3>M;++M)P=a[h],E.push(P),S.push(P),T[w]=P,++w,y=m[P],--y.numLiveTriangles,g-y.timeStamp>l&&(y.timeStamp=g,++g),++h}_=n(a,l,E,m,g,S,c)}return T},i}),r("Core/GeometryPipeline",["./AttributeCompression","./barycentricCoordinates","./BoundingSphere","./Cartesian2","./Cartesian3","./Cartesian4","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./EncodedCartesian3","./GeographicProjection","./Geometry","./GeometryAttribute","./GeometryInstance","./GeometryType","./IndexDatatype","./Intersect","./IntersectionTests","./Math","./Matrix3","./Matrix4","./Plane","./PrimitiveType","./Tipsify"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b){"use strict";function x(e,t,r,i,n){e[t++]=r,e[t++]=i,e[t++]=i,e[t++]=n,e[t++]=n,e[t]=r}function P(e){for(var t=e.length,r=t/3*6,i=_.createTypedArray(t,r),n=0,o=0;t>o;o+=3,n+=6)x(i,n,e[o],e[o+1],e[o+2]);return i}function A(e){var t=e.length;if(t>=3){var r=6*(t-2),i=_.createTypedArray(t,r);x(i,0,e[0],e[1],e[2]);for(var n=6,o=3;t>o;++o,n+=6)x(i,n,e[o-1],e[o],e[o-2]);return i}return new Uint16Array}function I(e){if(e.length>0){for(var t=e.length-1,r=6*(t-1),i=_.createTypedArray(t,r),n=e[0],o=0,a=1;t>a;++a,o+=6)x(i,o,n,e[a],e[a+1]);return i}return new Uint16Array}function M(e){var t={};for(var r in e)if(e.hasOwnProperty(r)&&u(e[r])&&u(e[r].values)){var i=e[r];t[r]=new m({componentDatatype:i.componentDatatype,componentsPerAttribute:i.componentsPerAttribute,normalize:i.normalize,values:[]})}return t}function D(e,t,r){for(var i in t)if(t.hasOwnProperty(i)&&u(t[i])&&u(t[i].values))for(var n=t[i],o=0;o<n.componentsPerAttribute;++o)e[i].values.push(n.values[r*n.componentsPerAttribute+o])}function R(e,t){if(u(t))for(var r=t.values,i=r.length,o=0;i>o;o+=3)n.unpack(r,o,oe),S.multiplyByPoint(e,oe,oe),n.pack(oe,r,o)}function O(e,t){if(u(t))for(var r=t.values,i=r.length,o=0;i>o;o+=3)n.unpack(r,o,oe),E.multiplyByVector(e,oe,oe),oe=n.normalize(oe,oe),n.pack(oe,r,o)}function N(e,t){var r,i=e.length,n={},o=e[0][t].attributes;for(r in o)if(o.hasOwnProperty(r)&&u(o[r])&&u(o[r].values)){for(var a=o[r],l=a.values.length,c=!0,h=1;i>h;++h){var d=e[h][t].attributes[r];if(!u(d)||a.componentDatatype!==d.componentDatatype||a.componentsPerAttribute!==d.componentsPerAttribute||a.normalize!==d.normalize){c=!1;break}l+=d.values.length}c&&(n[r]=new m({componentDatatype:a.componentDatatype,componentsPerAttribute:a.componentsPerAttribute,normalize:a.normalize,values:s.createTypedArray(a.componentDatatype,l)}))}return n}function L(e,t){var i,o,a,s,l,c,h,d=e.length,m=(e[0].modelMatrix,u(e[0][t].indices)),f=e[0][t].primitiveType,v=N(e,t);for(i in v)if(v.hasOwnProperty(i))for(l=v[i].values,s=0,o=0;d>o;++o)for(c=e[o][t].attributes[i].values,h=c.length,a=0;h>a;++a)l[s++]=c[a];var g;if(m){var y=0;for(o=0;d>o;++o)y+=e[o][t].indices.length;var C=p.computeNumberOfVertices(new p({attributes:v,primitiveType:T.POINTS})),E=_.createTypedArray(C,y),S=0,w=0;for(o=0;d>o;++o){var b=e[o][t].indices,x=b.length;for(s=0;x>s;++s)E[S++]=w+b[s];w+=p.computeNumberOfVertices(e[o][t])}g=E}var P,A=new n,I=0;for(o=0;d>o;++o){if(P=e[o][t].boundingSphere,!u(P)){A=void 0;break}n.add(P.center,A,A)}if(u(A))for(n.divideByScalar(A,d,A),o=0;d>o;++o){P=e[o][t].boundingSphere;var M=n.magnitude(n.subtract(P.center,A,le))+P.radius;M>I&&(I=M)}return new p({attributes:v,indices:g,primitiveType:f,boundingSphere:u(A)?new r(A,I):void 0})}function F(e){if(u(e.indices))return e;for(var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,t),i=0;t>i;++i)r[i]=i;return e.indices=r,e}function B(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,3*(t-2));r[0]=1,r[1]=0,r[2]=2;for(var i=3,n=3;t>n;++n)r[i++]=n-1,r[i++]=0,r[i++]=n;return e.indices=r,e.primitiveType=T.TRIANGLES,e}function V(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,3*(t-2));r[0]=0,r[1]=1,r[2]=2,t>3&&(r[3]=0,r[4]=2,r[5]=3);for(var i=6,n=3;t-1>n;n+=2)r[i++]=n,r[i++]=n-1,r[i++]=n+1,t>n+2&&(r[i++]=n,r[i++]=n+1,r[i++]=n+2);return e.indices=r,e.primitiveType=T.TRIANGLES,e}function z(e){if(u(e.indices))return e;for(var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,t),i=0;t>i;++i)r[i]=i;return e.indices=r,e}function k(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,2*(t-1));r[0]=0,r[1]=1;for(var i=2,n=2;t>n;++n)r[i++]=n-1,r[i++]=n;return e.indices=r,e.primitiveType=T.LINES,e}function U(e){var t=p.computeNumberOfVertices(e),r=_.createTypedArray(t,2*t);r[0]=0,r[1]=1;for(var i=2,n=2;t>n;++n)r[i++]=n-1,r[i++]=n;return r[i++]=t-1,r[i]=0,e.indices=r,e.primitiveType=T.LINES,e}function G(e){switch(e.primitiveType){case T.TRIANGLE_FAN:return B(e);case T.TRIANGLE_STRIP:return V(e);case T.TRIANGLES:return F(e);case T.LINE_STRIP:return k(e);case T.LINE_LOOP:return U(e);case T.LINES:return z(e)}return e}function W(e,t){Math.abs(e.y)<C.EPSILON6&&(t?e.y=-C.EPSILON6:e.y=C.EPSILON6)}function H(e,t,r){if(0!==e.y&&0!==t.y&&0!==r.y)return W(e,e.y<0),W(t,t.y<0),void W(r,r.y<0);var i,n=Math.abs(e.y),o=Math.abs(t.y),a=Math.abs(r.y);i=n>o?n>a?C.sign(e.y):C.sign(r.y):o>a?C.sign(t.y):C.sign(r.y);var s=0>i;W(e,s),W(t,s),W(r,s)}function q(e,t,r,i){n.add(e,n.multiplyByScalar(n.subtract(t,e,Ce),e.y/(e.y-t.y),Ce),r),n.clone(r,i),W(r,!0),W(i,!1)}function j(e,t,r){if(e.x>=0||t.x>=0||r.x>=0)return void 0;H(e,t,r);var i=e.y<0,n=t.y<0,o=r.y<0,a=0;a+=i?1:0,a+=n?1:0,a+=o?1:0;var s=be.indices;1===a?(s[1]=3,s[2]=4,s[5]=6,s[7]=6,s[8]=5,i?(q(e,t,Ee,we),q(e,r,Se,Te),s[0]=0,s[3]=1,s[4]=2,s[6]=1):n?(q(t,r,Ee,we),q(t,e,Se,Te),s[0]=1,s[3]=2,s[4]=0,s[6]=2):o&&(q(r,e,Ee,we),q(r,t,Se,Te),s[0]=2,s[3]=0,s[4]=1,s[6]=0)):2===a&&(s[2]=4,s[4]=4,s[5]=3,s[7]=5,s[8]=6,i?n?o||(q(r,e,Ee,we),q(r,t,Se,Te),s[0]=0,s[1]=1,s[3]=0,s[6]=2):(q(t,r,Ee,we),q(t,e,Se,Te),s[0]=2,s[1]=0,s[3]=2,s[6]=1):(q(e,t,Ee,we),q(e,r,Se,Te),s[0]=1,s[1]=2,s[3]=1,s[6]=0));var l=be.positions;return l[0]=e,l[1]=t,l[2]=r,l.length=3,(1===a||2===a)&&(l[3]=Ee,l[4]=Se,l[5]=we,l[6]=Te,l.length=7),be}function Y(e,t){var i=e.attributes;if(0===i.position.values.length)return void 0;for(var n in i)if(i.hasOwnProperty(n)&&u(i[n])&&u(i[n].values)){var o=i[n];o.values=s.createTypedArray(o.componentDatatype,o.values)}var a=p.computeNumberOfVertices(e);return e.indices=_.createTypedArray(a,e.indices),t&&(e.boundingSphere=r.fromVertices(i.position.values)),e}function X(e){var t=e.attributes,r={};for(var i in t)if(t.hasOwnProperty(i)&&u(t[i])&&u(t[i].values)){var n=t[i];r[i]=new m({componentDatatype:n.componentDatatype,componentsPerAttribute:n.componentsPerAttribute,normalize:n.normalize,values:[]})}return new p({attributes:r,indices:[],primitiveType:e.primitiveType})}function Z(e,t,r){var i=u(e.geometry.boundingSphere);t=Y(t,i),r=Y(r,i),u(r)&&!u(t)?e.geometry=r:!u(r)&&u(t)?e.geometry=t:(e.westHemisphereGeometry=t,e.eastHemisphereGeometry=r,e.geometry=void 0)}function K(e,r,o,a,s,l,c,h,d,p,m){if(u(l)||u(c)||u(h)||u(d)){var f=n.fromArray(s,3*e,xe),v=n.fromArray(s,3*r,Pe),_=n.fromArray(s,3*o,Ae),g=t(a,f,v,_,Ie);if(u(l)){var y=n.fromArray(l,3*e,xe),C=n.fromArray(l,3*r,Pe),E=n.fromArray(l,3*o,Ae);n.multiplyByScalar(y,g.x,y),n.multiplyByScalar(C,g.y,C),n.multiplyByScalar(E,g.z,E);var S=n.add(y,C,y);n.add(S,E,S),n.normalize(S,S),n.pack(S,p.normal.values,3*m)}if(u(c)){var w=n.fromArray(c,3*e,xe),T=n.fromArray(c,3*r,Pe),b=n.fromArray(c,3*o,Ae);n.multiplyByScalar(w,g.x,w),n.multiplyByScalar(T,g.y,T),n.multiplyByScalar(b,g.z,b);var x=n.add(w,T,w);n.add(x,b,x),n.normalize(x,x),n.pack(x,p.binormal.values,3*m)}if(u(h)){var P=n.fromArray(h,3*e,xe),A=n.fromArray(h,3*r,Pe),I=n.fromArray(h,3*o,Ae);n.multiplyByScalar(P,g.x,P),n.multiplyByScalar(A,g.y,A),n.multiplyByScalar(I,g.z,I);var M=n.add(P,A,P);n.add(M,I,M),n.normalize(M,M),n.pack(M,p.tangent.values,3*m)}if(u(d)){var D=i.fromArray(d,2*e,Me),R=i.fromArray(d,2*r,De),O=i.fromArray(d,2*o,Re);i.multiplyByScalar(D,g.x,D),i.multiplyByScalar(R,g.y,R),i.multiplyByScalar(O,g.z,O);var N=i.add(D,R,D);i.add(N,O,N),i.pack(N,p.st.values,2*m)}}}function J(e,t,r,i,n,o){var a=e.position.values.length/3;if(-1!==n){var s=i[n],l=r[s];return-1===l?(r[s]=a,e.position.values.push(o.x,o.y,o.z),t.push(a),a):(t.push(l),l)}return e.position.values.push(o.x,o.y,o.z),t.push(a),a}function Q(e){var t,r,i,o,a,s=e.geometry,l=s.attributes,c=l.position.values,h=u(l.normal)?l.normal.values:void 0,d=u(l.binormal)?l.binormal.values:void 0,p=u(l.tangent)?l.tangent.values:void 0,m=u(l.st)?l.st.values:void 0,f=s.indices,v=X(s),_=X(s),g=[];g.length=c.length/3;var y=[];for(y.length=c.length/3,a=0;a<g.length;++a)g[a]=-1,y[a]=-1;var C=f.length;for(a=0;C>a;a+=3){var E=f[a],S=f[a+1],w=f[a+2],T=n.fromArray(c,3*E),b=n.fromArray(c,3*S),x=n.fromArray(c,3*w),P=j(T,b,x);if(u(P)&&P.positions.length>3)for(var A=P.positions,I=P.indices,M=I.length,D=0;M>D;++D){var R=I[D],O=A[R];O.y<0?(t=_.attributes,r=_.indices,i=g):(t=v.attributes,r=v.indices,i=y),o=J(t,r,i,f,3>R?a+R:-1,O),K(E,S,w,O,c,h,d,p,m,t,o)}else u(P)&&(T=P.positions[0],b=P.positions[1],x=P.positions[2]),T.y<0?(t=_.attributes,r=_.indices,i=g):(t=v.attributes,r=v.indices,i=y),o=J(t,r,i,f,a,T),K(E,S,w,T,c,h,d,p,m,t,o),o=J(t,r,i,f,a+1,b),K(E,S,w,b,c,h,d,p,m,t,o),o=J(t,r,i,f,a+2,x),K(E,S,w,x,c,h,d,p,m,t,o)}Z(e,_,v)}function $(e){var t,r=e.geometry,i=r.attributes,o=i.position.values,a=r.indices,s=X(r),l=X(r),c=a.length,h=[];h.length=o.length/3;var d=[];for(d.length=o.length/3,t=0;t<h.length;++t)h[t]=-1,d[t]=-1;for(t=0;c>t;t+=2){var p=a[t],m=a[t+1],f=n.fromArray(o,3*p,xe),v=n.fromArray(o,3*m,Pe);Math.abs(f.y)<C.EPSILON6&&(f.y<0?f.y=-C.EPSILON6:f.y=C.EPSILON6),Math.abs(v.y)<C.EPSILON6&&(v.y<0?v.y=-C.EPSILON6:v.y=C.EPSILON6);var _=s.attributes,g=s.indices,E=d,S=l.attributes,w=l.indices,T=h,b=y.lineSegmentPlane(f,v,Oe,Ae);if(u(b)){var x=n.multiplyByScalar(n.UNIT_Y,5*C.EPSILON9,Ne);f.y<0&&(n.negate(x,x),_=l.attributes,g=l.indices,E=h,S=s.attributes,w=s.indices,T=d);var P=n.add(b,x,Le);J(_,g,E,a,t,f),J(_,g,E,a,-1,P),n.negate(x,x),n.add(b,x,P),J(S,w,T,a,-1,P),J(S,w,T,a,t+1,v)}else{var A,I,M;f.y<0?(A=l.attributes,I=l.indices,M=h):(A=s.attributes,I=s.indices,M=d),J(A,I,M,a,t,f),J(A,I,M,a,t+1,v)}}Z(e,l,s)}function ee(e){var t,r,a,s=e.geometry,l=s.attributes,c=l.position.values,h=l.prevPosition.values,d=l.nextPosition.values,p=l.expandAndWidth.values,m=(s.indices,u(l.st)?l.st.values:void 0),f=u(l.color)?l.color.values:void 0,v=X(s),_=X(s),g=c.length/3;for(t=0;g>t;t+=4){var E=t,S=t+1,w=t+2,T=t+3,b=n.fromArray(c,3*E,Ve),x=n.fromArray(c,3*S,ze),P=n.fromArray(c,3*w,ke),A=n.fromArray(c,3*T,Ue);Math.abs(b.y)<C.EPSILON6&&(b.y=C.EPSILON6*(P.y<0?-1:1),x.y=b.y),Math.abs(P.y)<C.EPSILON6&&(P.y=C.EPSILON6*(b.y<0?-1:1),A.y=P.y);var I=v.attributes,M=v.indices,D=_.attributes,R=_.indices,O=y.lineSegmentPlane(b,P,Oe,Ge);if(u(O)){var N=n.multiplyByScalar(n.UNIT_Y,5*C.EPSILON9,We);b.y<0&&(n.negate(N,N),I=_.attributes,M=_.indices,D=v.attributes,R=v.indices);var L=n.add(O,N,He);for(I.position.values.push(b.x,b.y,b.z,x.x,x.y,x.z),I.position.values.push(L.x,L.y,L.z),I.position.values.push(L.x,L.y,L.z),n.negate(N,N),n.add(O,N,L),D.position.values.push(L.x,L.y,L.z),D.position.values.push(L.x,L.y,L.z),D.position.values.push(P.x,P.y,P.z,A.x,A.y,A.z),r=3*E;3*E+6>r;++r)I.prevPosition.values.push(h[r]);for(I.prevPosition.values.push(b.x,b.y,b.z,b.x,b.y,b.z),D.prevPosition.values.push(b.x,b.y,b.z,b.x,b.y,b.z),r=3*w;3*w+6>r;++r)D.prevPosition.values.push(h[r]);for(r=3*E;3*E+6>r;++r)I.nextPosition.values.push(d[r]);for(I.nextPosition.values.push(P.x,P.y,P.z,P.x,P.y,P.z),D.nextPosition.values.push(P.x,P.y,P.z,P.x,P.y,P.z),r=3*w;3*w+6>r;++r)D.nextPosition.values.push(d[r]);var F=i.fromArray(p,2*E,Fe),B=Math.abs(F.y);I.expandAndWidth.values.push(-1,B,1,B),I.expandAndWidth.values.push(-1,-B,1,-B),D.expandAndWidth.values.push(-1,B,1,B),D.expandAndWidth.values.push(-1,-B,1,-B);var V=n.magnitudeSquared(n.subtract(O,b,Ue));if(V/=n.magnitudeSquared(n.subtract(P,b,Ue)),u(f)){var z=o.fromArray(f,4*E,qe),k=o.fromArray(f,4*w,qe),U=C.lerp(z.x,k.x,V),G=C.lerp(z.y,k.y,V),W=C.lerp(z.z,k.z,V),H=C.lerp(z.w,k.w,V);for(r=4*E;4*E+8>r;++r)I.color.values.push(f[r]);for(I.color.values.push(U,G,W,H),I.color.values.push(U,G,W,H),D.color.values.push(U,G,W,H),D.color.values.push(U,G,W,H),r=4*w;4*w+8>r;++r)D.color.values.push(f[r])}if(u(m)){var q=i.fromArray(m,2*E,Fe),j=i.fromArray(m,2*(t+3),Be),Y=C.lerp(q.x,j.x,V);for(r=2*E;2*E+4>r;++r)I.st.values.push(m[r]);for(I.st.values.push(Y,q.y),I.st.values.push(Y,j.y),D.st.values.push(Y,q.y),D.st.values.push(Y,j.y),r=2*w;2*w+4>r;++r)D.st.values.push(m[r])}a=I.position.values.length/3-4,M.push(a,a+2,a+1),M.push(a+1,a+2,a+3),a=D.position.values.length/3-4,R.push(a,a+2,a+1),R.push(a+1,a+2,a+3)}else{var K,J;for(b.y<0?(K=_.attributes,J=_.indices):(K=v.attributes,J=v.indices),K.position.values.push(b.x,b.y,b.z),K.position.values.push(x.x,x.y,x.z),K.position.values.push(P.x,P.y,P.z),K.position.values.push(A.x,A.y,A.z),r=3*t;3*t+12>r;++r)K.prevPosition.values.push(h[r]),K.nextPosition.values.push(d[r]);for(r=2*t;2*t+8>r;++r)K.expandAndWidth.values.push(p[r]),u(m)&&K.st.values.push(m[r]);if(u(f))for(r=4*t;4*t+16>r;++r)K.color.values.push(f[r]);a=K.position.values.length/3-4,J.push(a,a+2,a+1),J.push(a+1,a+2,a+3)}}Z(e,_,v)}var te={};te.toWireframe=function(e){var t=e.indices;if(u(t)){switch(e.primitiveType){case T.TRIANGLES:e.indices=P(t);break;case T.TRIANGLE_STRIP:e.indices=A(t);break;case T.TRIANGLE_FAN:e.indices=I(t);break;default:throw new c("geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN.")}e.primitiveType=T.LINES}return e},te.createLineSegmentsForVectors=function(e,t,i){t=l(t,"normal"),i=l(i,1e4);for(var n=e.attributes.position.values,o=e.attributes[t].values,a=n.length,c=new Float64Array(2*a),h=0,d=0;a>d;d+=3)c[h++]=n[d],c[h++]=n[d+1],c[h++]=n[d+2],c[h++]=n[d]+o[d]*i,c[h++]=n[d+1]+o[d+1]*i,c[h++]=n[d+2]+o[d+2]*i;var f,v=e.boundingSphere;return u(v)&&(f=new r(v.center,v.radius+i)),new p({attributes:{position:new m({componentDatatype:s.DOUBLE,componentsPerAttribute:3,values:c})},primitiveType:T.LINES,boundingSphere:f})},te.createAttributeLocations=function(e){var t,r=["position","positionHigh","positionLow","position3DHigh","position3DLow","position2DHigh","position2DLow","pickColor","normal","st","binormal","tangent","compressedAttributes"],i=e.attributes,n={},o=0,a=r.length;for(t=0;a>t;++t){var s=r[t];u(i[s])&&(n[s]=o++)}for(var l in i)i.hasOwnProperty(l)&&!u(n[l])&&(n[l]=o++);return n},te.reorderForPreVertexCache=function(e){var t=p.computeNumberOfVertices(e),r=e.indices;if(u(r)){for(var i=new Int32Array(t),n=0;t>n;n++)i[n]=-1;for(var o,a=r,l=a.length,c=_.createTypedArray(t,l),h=0,d=0,m=0;l>h;)o=i[a[h]],-1!==o?c[d]=o:(o=a[h],i[o]=m,c[d]=m,++m),++h,++d;e.indices=c;var f=e.attributes;for(var v in f)if(f.hasOwnProperty(v)&&u(f[v])&&u(f[v].values)){for(var g=f[v],y=g.values,C=0,E=g.componentsPerAttribute,S=s.createTypedArray(g.componentDatatype,m*E);t>C;){var w=i[C];if(-1!==w)for(n=0;E>n;n++)S[E*w+n]=y[E*C+n];++C}g.values=S}}return e},te.reorderForPostVertexCache=function(e,t){var r=e.indices;if(e.primitiveType===T.TRIANGLES&&u(r)){for(var i=r.length,n=0,o=0;i>o;o++)r[o]>n&&(n=r[o]);e.indices=b.tipsify({indices:r,maximumIndex:n,cacheSize:t})}return e},te.fitToUnsignedShortIndices=function(e){var t=[],r=p.computeNumberOfVertices(e);if(u(e.indices)&&r>=C.SIXTY_FOUR_KILOBYTES){var i,n=[],o=[],a=0,s=M(e.attributes),l=e.indices,c=l.length;e.primitiveType===T.TRIANGLES?i=3:e.primitiveType===T.LINES?i=2:e.primitiveType===T.POINTS&&(i=1);for(var h=0;c>h;h+=i){for(var d=0;i>d;++d){var m=l[h+d],f=n[m];u(f)||(f=a++,n[m]=f,D(s,e.attributes,m)),o.push(f)}a+i>=C.SIXTY_FOUR_KILOBYTES&&(t.push(new p({attributes:s,indices:o,primitiveType:e.primitiveType,boundingSphere:e.boundingSphere,boundingSphereCV:e.boundingSphereCV})),n=[],o=[],a=0,s=M(e.attributes))}0!==o.length&&t.push(new p({attributes:s,indices:o,primitiveType:e.primitiveType,boundingSphere:e.boundingSphere,boundingSphereCV:e.boundingSphereCV}))}else t.push(e);return t};var re=new n,ie=new a;te.projectTo2D=function(e,t,r,i,o){var a=e.attributes[t];o=u(o)?o:new d;for(var l=o.ellipsoid,h=a.values,p=new Float64Array(h.length),f=0,v=0;v<h.length;v+=3){var _=n.fromArray(h,v,re),g=l.cartesianToCartographic(_,ie);if(!u(g))throw new c("Could not project point ("+_.x+", "+_.y+", "+_.z+") to 2D.");var y=o.project(g,re);p[f++]=y.x,p[f++]=y.y,p[f++]=y.z}return e.attributes[r]=a,e.attributes[i]=new m({componentDatatype:s.DOUBLE,componentsPerAttribute:3,values:p}),delete e.attributes[t],e};var ne={high:0,low:0};te.encodeAttribute=function(e,t,r,i){for(var n=e.attributes[t],o=n.values,a=o.length,l=new Float32Array(a),u=new Float32Array(a),c=0;a>c;++c)h.encode(o[c],ne),l[c]=ne.high,u[c]=ne.low;var d=n.componentsPerAttribute;return e.attributes[r]=new m({componentDatatype:s.FLOAT,componentsPerAttribute:d,values:l}),e.attributes[i]=new m({componentDatatype:s.FLOAT,componentsPerAttribute:d,values:u}),delete e.attributes[t],e};var oe=new n,ae=new S,se=new E;te.transformToWorldCoordinates=function(e){var t=e.modelMatrix;if(S.equals(t,S.IDENTITY))return e;var i=e.geometry.attributes;R(t,i.position),R(t,i.prevPosition),R(t,i.nextPosition),(u(i.normal)||u(i.binormal)||u(i.tangent))&&(S.inverse(t,ae),S.transpose(ae,ae),S.getRotation(ae,se),O(se,i.normal),O(se,i.binormal),O(se,i.tangent));var n=e.geometry.boundingSphere;return u(n)&&(e.geometry.boundingSphere=r.transform(n,t,n)),e.modelMatrix=S.clone(S.IDENTITY),e};var le=new n;te.combineInstances=function(e){for(var t=[],r=[],i=e.length,n=0;i>n;++n){var o=e[n];u(o.geometry)?t.push(o):r.push(o)}var a=[];return t.length>0&&a.push(L(t,"geometry")),r.length>0&&(a.push(L(r,"westHemisphereGeometry")),a.push(L(r,"eastHemisphereGeometry"))),a};var ue=new n,ce=new n,he=new n,de=new n;te.computeNormal=function(e){for(var t=e.indices,r=e.attributes,i=r.position.values,o=r.position.values.length/3,a=t.length,l=new Array(o),u=new Array(a/3),c=new Array(a),h=0;o>h;h++)l[h]={indexOffset:0,count:0,currentCount:0};var d=0;for(h=0;a>h;h+=3){var p=t[h],f=t[h+1],v=t[h+2],_=3*p,g=3*f,y=3*v;ce.x=i[_],ce.y=i[_+1],ce.z=i[_+2],he.x=i[g],he.y=i[g+1],he.z=i[g+2],de.x=i[y],de.y=i[y+1],de.z=i[y+2],l[p].count++,l[f].count++,l[v].count++,n.subtract(he,ce,he),n.subtract(de,ce,de),u[d]=n.cross(he,de,new n),d++}var C=0;for(h=0;o>h;h++)l[h].indexOffset+=C,C+=l[h].count;d=0;var E;for(h=0;a>h;h+=3){E=l[t[h]];var S=E.indexOffset+E.currentCount;c[S]=d,E.currentCount++,E=l[t[h+1]],S=E.indexOffset+E.currentCount,c[S]=d,E.currentCount++,E=l[t[h+2]],S=E.indexOffset+E.currentCount,c[S]=d,E.currentCount++,d++}var w=new Float32Array(3*o);for(h=0;o>h;h++){var T=3*h;if(E=l[h],E.count>0){for(n.clone(n.ZERO,ue),d=0;d<E.count;d++)n.add(ue,u[c[E.indexOffset+d]],ue);n.normalize(ue,ue),w[T]=ue.x,w[T+1]=ue.y,w[T+2]=ue.z}else w[T]=0,w[T+1]=0,w[T+2]=1}return e.attributes.normal=new m({componentDatatype:s.FLOAT,componentsPerAttribute:3,values:w}),e};var pe=new n,me=new n,fe=new n;te.computeBinormalAndTangent=function(e){for(var t=(e.attributes,e.indices),r=e.attributes.position.values,i=e.attributes.normal.values,o=e.attributes.st.values,a=e.attributes.position.values.length/3,l=t.length,u=new Array(3*a),c=0;c<u.length;c++)u[c]=0;var h,d,p;for(c=0;l>c;c+=3){var f=t[c],v=t[c+1],_=t[c+2];h=3*f,d=3*v,p=3*_;var g=2*f,y=2*v,C=2*_,E=r[h],S=r[h+1],w=r[h+2],T=o[g],b=o[g+1],x=o[y+1]-b,P=o[C+1]-b,A=1/((o[y]-T)*P-(o[C]-T)*x),I=(P*(r[d]-E)-x*(r[p]-E))*A,M=(P*(r[d+1]-S)-x*(r[p+1]-S))*A,D=(P*(r[d+2]-w)-x*(r[p+2]-w))*A; -u[h]+=I,u[h+1]+=M,u[h+2]+=D,u[d]+=I,u[d+1]+=M,u[d+2]+=D,u[p]+=I,u[p+1]+=M,u[p+2]+=D}var R=new Float32Array(3*a),O=new Float32Array(3*a);for(c=0;a>c;c++){h=3*c,d=h+1,p=h+2;var N=n.fromArray(i,h,pe),L=n.fromArray(u,h,fe),F=n.dot(N,L);n.multiplyByScalar(N,F,me),n.normalize(n.subtract(L,me,L),L),O[h]=L.x,O[d]=L.y,O[p]=L.z,n.normalize(n.cross(N,L,L),L),R[h]=L.x,R[d]=L.y,R[p]=L.z}return e.attributes.tangent=new m({componentDatatype:s.FLOAT,componentsPerAttribute:3,values:O}),e.attributes.binormal=new m({componentDatatype:s.FLOAT,componentsPerAttribute:3,values:R}),e};var ve=new i,_e=new n,ge=new n,ye=new n;te.compressVertices=function(t){var r=t.attributes.normal,o=t.attributes.st;if(!u(r)&&!u(o))return t;var a,l,c,h,d=t.attributes.tangent,p=t.attributes.binormal;u(r)&&(a=r.values),u(o)&&(l=o.values),u(d)&&(c=d.values),p&&(h=p.values);var f=u(a)?a.length:l.length,v=u(a)?3:2,_=f/v,g=_,y=u(l)&&u(a)?2:1;y+=u(c)||u(h)?1:0,g*=y;for(var C=new Float32Array(g),E=0,S=0;_>S;++S){u(l)&&(i.fromArray(l,2*S,ve),C[E++]=e.compressTextureCoordinates(ve));var w=3*S;u(a)&&u(c)&&u(h)?(n.fromArray(a,w,_e),n.fromArray(c,w,ge),n.fromArray(h,w,ye),e.octPack(_e,ge,ye,ve),C[E++]=ve.x,C[E++]=ve.y):(u(a)&&(n.fromArray(a,w,_e),C[E++]=e.octEncodeFloat(_e)),u(c)&&(n.fromArray(c,w,_e),C[E++]=e.octEncodeFloat(_e)),u(h)&&(n.fromArray(h,w,_e),C[E++]=e.octEncodeFloat(_e)))}return t.attributes.compressedAttributes=new m({componentDatatype:s.FLOAT,componentsPerAttribute:y,values:C}),u(a)&&delete t.attributes.normal,u(l)&&delete t.attributes.st,u(c)&&delete t.attributes.tangent,u(h)&&delete t.attributes.binormal,t};var Ce=new n,Ee=new n,Se=new n,we=new n,Te=new n,be={positions:new Array(7),indices:new Array(9)},xe=new n,Pe=new n,Ae=new n,Ie=new n,Me=new i,De=new i,Re=new i,Oe=w.fromPointNormal(n.ZERO,n.UNIT_Y),Ne=new n,Le=new n,Fe=new i,Be=new i,Ve=new n,ze=new n,ke=new n,Ue=new n,Ge=new n,We=new n,He=new n,qe=new o;new o;return te.splitLongitude=function(e){var t=e.geometry,i=t.boundingSphere;if(u(i)){var n=i.center.x-i.radius;if(n>0||r.intersectPlane(i,w.ORIGIN_ZX_PLANE)!==g.INTERSECTING)return e}if(t.geometryType!==v.NONE)switch(t.geometryType){case v.POLYLINES:ee(e);break;case v.TRIANGLES:Q(e);break;case v.LINES:$(e)}else G(t),t.primitiveType===T.TRIANGLES?Q(e):t.primitiveType===T.LINES&&$(e);return e},te}),r("Core/EllipseGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./EllipseGeometryLibrary","./Ellipsoid","./GeographicProjection","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./Matrix3","./PrimitiveType","./Quaternion","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";function S(e,i,o){var a=i.vertexFormat,s=i.center,u=i.semiMajorAxis,h=i.semiMinorAxis,m=i.ellipsoid,f=i.stRotation,v=o?e.length/3*2:e.length/3,_=a.st?new Float32Array(2*v):void 0,y=a.normal?new Float32Array(3*v):void 0,E=a.tangent?new Float32Array(3*v):void 0,S=a.binormal?new Float32Array(3*v):void 0,w=0,T=L,b=F,x=B,P=new c(m),D=P.project(m.cartesianToCartographic(s,V),z),G=m.scaleToGeodeticSurface(s,A);m.geodeticSurfaceNormal(G,G);for(var W=C.fromAxisAngle(G,f,N),H=g.fromQuaternion(W,O),q=t.fromElements(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,k),j=t.fromElements(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,U),Y=e.length,X=o?Y:0,Z=X/3*2,K=0;Y>K;K+=3){var J=K+1,Q=K+2,$=r.fromArray(e,K,A);if(a.st){var ee=g.multiplyByVector(H,$,I),te=P.project(m.cartesianToCartographic(ee,V),M);r.subtract(te,D,te),R.x=(te.x+u)/(2*u),R.y=(te.y+h)/(2*h),q.x=Math.min(R.x,q.x),q.y=Math.min(R.y,q.y),j.x=Math.max(R.x,j.x),j.y=Math.max(R.y,j.y),o&&(_[w+Z]=R.x,_[w+1+Z]=R.y),_[w++]=R.x,_[w++]=R.y}T=m.geodeticSurfaceNormal($,T),(a.normal||a.tangent||a.binormal)&&((a.tangent||a.binormal)&&(b=r.cross(r.UNIT_Z,T,b),g.multiplyByVector(H,b,b)),a.normal&&(y[K]=T.x,y[J]=T.y,y[Q]=T.z,o&&(y[K+X]=-T.x,y[J+X]=-T.y,y[Q+X]=-T.z)),a.tangent&&(E[K]=b.x,E[J]=b.y,E[Q]=b.z,o&&(E[K+X]=-b.x,E[J+X]=-b.y,E[Q+X]=-b.z)),a.binormal&&(x=r.cross(T,b,x),S[K]=x.x,S[J]=x.y,S[Q]=x.z,o&&(S[K+X]=x.x,S[J+X]=x.y,S[Q+X]=x.z)))}if(a.st){Y=_.length;for(var re=0;Y>re;re+=2)_[re]=(_[re]-q.x)/(j.x-q.x),_[re+1]=(_[re+1]-q.y)/(j.y-q.y)}var ie=new p;if(a.position){var ne=l.raisePositionsToHeight(e,i,o);ie.position=new d({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:ne})}return a.st&&(ie.st=new d({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:_})),a.normal&&(ie.normal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:y})),a.tangent&&(ie.tangent=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:E})),a.binormal&&(ie.binormal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:S})),ie}function w(e){var t,r,i,n,o,a=new Array(2*e*(e+1)),s=0;for(n=1;e>n;++n){for(i=n*(n+1),t=(n-1)*n,a[s++]=i++,a[s++]=t,a[s++]=i,r=2*n,o=0;r-1>o;++o)a[s++]=i,a[s++]=t++,a[s++]=t,a[s++]=i++,a[s++]=t,a[s++]=i;a[s++]=i++,a[s++]=t,a[s++]=i}for(r=2*e,++i,++t,n=0;r-1>n;++n)a[s++]=i,a[s++]=t++,a[s++]=t,a[s++]=i++,a[s++]=t,a[s++]=i;for(++t,++i,n=e-1;n>0;--n){for(a[s++]=t++,a[s++]=t,a[s++]=i,r=2*n,o=0;r-1>o;++o)a[s++]=i,a[s++]=t++,a[s++]=t,a[s++]=i++,a[s++]=t,a[s++]=i;a[s++]=t++,a[s++]=t++,a[s++]=i++}return a}function T(t){var i=t.center;G=r.multiplyByScalar(t.ellipsoid.geodeticSurfaceNormal(i,G),t.height,G),G=r.add(i,G,G);var n=new e(G,t.semiMajorAxis),o=l.computeEllipsePositions(t,!0,!1),a=o.positions,s=o.numPts,u=S(a,t,!1),c=w(s);return c=v.createTypedArray(a.length/3,c),{boundingSphere:n,attributes:u,indices:c}}function b(e,i){var o=i.vertexFormat,a=i.center,s=i.semiMajorAxis,l=i.semiMinorAxis,u=i.ellipsoid,h=i.height,m=i.extrudedHeight,f=i.stRotation,v=e.length/3*2,_=new Float64Array(3*v),y=o.st?new Float32Array(2*v):void 0,E=o.normal?new Float32Array(3*v):void 0,S=o.tangent?new Float32Array(3*v):void 0,w=o.binormal?new Float32Array(3*v):void 0,T=0,b=L,x=F,P=B,G=new c(u),W=G.project(u.cartesianToCartographic(a,V),z),H=u.scaleToGeodeticSurface(a,A);u.geodeticSurfaceNormal(H,H);for(var q=C.fromAxisAngle(H,f,N),j=g.fromQuaternion(q,O),Y=t.fromElements(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,k),X=t.fromElements(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,U),Z=e.length,K=Z/3*2,J=0;Z>J;J+=3){var Q,$=J+1,ee=J+2,te=r.fromArray(e,J,A);if(o.st){var re=g.multiplyByVector(j,te,I),ie=G.project(u.cartesianToCartographic(re,V),M);r.subtract(ie,W,ie),R.x=(ie.x+s)/(2*s),R.y=(ie.y+l)/(2*l),Y.x=Math.min(R.x,Y.x),Y.y=Math.min(R.y,Y.y),X.x=Math.max(R.x,X.x),X.y=Math.max(R.y,X.y),y[T+K]=R.x,y[T+1+K]=R.y,y[T++]=R.x,y[T++]=R.y}te=u.scaleToGeodeticSurface(te,te),Q=r.clone(te,I),b=u.geodeticSurfaceNormal(te,b);var ne=r.multiplyByScalar(b,h,D);if(te=r.add(te,ne,te),ne=r.multiplyByScalar(b,m,ne),Q=r.add(Q,ne,Q),o.position&&(_[J+Z]=Q.x,_[$+Z]=Q.y,_[ee+Z]=Q.z,_[J]=te.x,_[$]=te.y,_[ee]=te.z),o.normal||o.tangent||o.binormal){P=r.clone(b,P);var oe=r.fromArray(e,(J+3)%Z,D);r.subtract(oe,te,oe);var ae=r.subtract(Q,te,M);b=r.normalize(r.cross(ae,oe,b),b),o.normal&&(E[J]=b.x,E[$]=b.y,E[ee]=b.z,E[J+Z]=b.x,E[$+Z]=b.y,E[ee+Z]=b.z),o.tangent&&(x=r.normalize(r.cross(P,b,x),x),S[J]=x.x,S[$]=x.y,S[ee]=x.z,S[J+Z]=x.x,S[J+1+Z]=x.y,S[J+2+Z]=x.z),o.binormal&&(w[J]=P.x,w[$]=P.y,w[ee]=P.z,w[J+Z]=P.x,w[$+Z]=P.y,w[ee+Z]=P.z)}}if(o.st){Z=y.length;for(var se=0;Z>se;se+=2)y[se]=(y[se]-Y.x)/(X.x-Y.x),y[se+1]=(y[se+1]-Y.y)/(X.y-Y.y)}var le=new p;return o.position&&(le.position=new d({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:_})),o.st&&(le.st=new d({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:y})),o.normal&&(le.normal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:E})),o.tangent&&(le.tangent=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:S})),o.binormal&&(le.binormal=new d({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:w})),le}function x(e){for(var t=e.length/3,r=v.createTypedArray(t,6*t),i=0,n=0;t>n;n++){var o=n,a=n+t,s=(o+1)%t,l=s+t;r[i++]=o,r[i++]=a,r[i++]=s,r[i++]=s,r[i++]=a,r[i++]=l}return r}function P(t){var i=t.center,n=t.ellipsoid,o=t.semiMajorAxis,a=r.multiplyByScalar(n.geodeticSurfaceNormal(i,A),t.height,A);W.center=r.add(i,a,W.center),W.radius=o,a=r.multiplyByScalar(n.geodeticSurfaceNormal(i,a),t.extrudedHeight,a),H.center=r.add(i,a,H.center),H.radius=o;var s=l.computeEllipsePositions(t,!0,!0),u=s.positions,c=s.numPts,d=s.outerPositions,p=e.union(W,H),_=S(u,t,!0),g=w(c),C=g.length;g.length=2*C;for(var E=u.length/3,T=0;C>T;T+=3)g[T+C]=g[T+2]+E,g[T+1+C]=g[T+1]+E,g[T+2+C]=g[T]+E;var P=v.createTypedArray(2*E/3,g),I=new h({attributes:_,indices:P,primitiveType:y.TRIANGLES}),M=b(d,t);g=x(d);var D=v.createTypedArray(2*d.length/3,g),R=new h({attributes:M,indices:D,primitiveType:y.TRIANGLES}),O=f.combineInstances([new m({geometry:I}),new m({geometry:R})]);return{boundingSphere:p,attributes:O[0].attributes,indices:O[0].indices}}var A=new r,I=new r,M=new r,D=new r,R=new t,O=new g,N=new C,L=new r,F=new r,B=new r,V=new i,z=new r,k=new t,U=new t,G=new r,W=new e,H=new e,q=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.center,i=o(e.ellipsoid,u.WGS84),n=e.semiMajorAxis,s=e.semiMinorAxis,l=o(e.granularity,_.RADIANS_PER_DEGREE),c=o(e.height,0),h=e.extrudedHeight,d=a(h)&&Math.abs(c-h)>1,p=o(e.vertexFormat,E.DEFAULT);this._center=r.clone(t),this._semiMajorAxis=n,this._semiMinorAxis=s,this._ellipsoid=u.clone(i),this._rotation=o(e.rotation,0),this._stRotation=o(e.stRotation,0),this._height=c,this._granularity=l,this._vertexFormat=E.clone(p),this._extrudedHeight=o(h,c),this._extrude=d,this._workerName="createEllipseGeometry"};q.packedLength=r.packedLength+u.packedLength+E.packedLength+8,q.pack=function(e,t,i){i=o(i,0),r.pack(e._center,t,i),i+=r.packedLength,u.pack(e._ellipsoid,t,i),i+=u.packedLength,E.pack(e._vertexFormat,t,i),i+=E.packedLength,t[i++]=e._semiMajorAxis,t[i++]=e._semiMinorAxis,t[i++]=e._rotation,t[i++]=e._stRotation,t[i++]=e._height,t[i++]=e._granularity,t[i++]=e._extrudedHeight,t[i]=e._extrude?1:0};var j=new r,Y=new u,X=new E,Z={center:j,ellipsoid:Y,vertexFormat:X,semiMajorAxis:void 0,semiMinorAxis:void 0,rotation:void 0,stRotation:void 0,height:void 0,granularity:void 0,extrudedHeight:void 0};return q.unpack=function(e,t,i){t=o(t,0);var n=r.unpack(e,t,j);t+=r.packedLength;var s=u.unpack(e,t,Y);t+=u.packedLength;var l=E.unpack(e,t,X);t+=E.packedLength;var c=e[t++],h=e[t++],d=e[t++],p=e[t++],m=e[t++],f=e[t++],v=e[t++],_=1===e[t];return a(i)?(i._center=r.clone(n,i._center),i._ellipsoid=u.clone(s,i._ellipsoid),i._vertexFormat=E.clone(l,i._vertexFormat),i._semiMajorAxis=c,i._semiMinorAxis=h,i._rotation=d,i._stRotation=p,i._height=m,i._granularity=f,i._extrudedHeight=v,i._extrude=_,i):(Z.height=m,Z.extrudedHeight=v,Z.granularity=f,Z.stRotation=p,Z.rotation=d,Z.semiMajorAxis=c,Z.semiMinorAxis=h,new q(Z))},q.createGeometry=function(e){e._center=e._ellipsoid.scaleToGeodeticSurface(e._center,e._center);var t,r={center:e._center,semiMajorAxis:e._semiMajorAxis,semiMinorAxis:e._semiMinorAxis,ellipsoid:e._ellipsoid,rotation:e._rotation,height:e._height,extrudedHeight:e._extrudedHeight,granularity:e._granularity,vertexFormat:e._vertexFormat,stRotation:e._stRotation};return e._extrude?(r.extrudedHeight=Math.min(e._extrudedHeight,e._height),r.height=Math.max(e._extrudedHeight,e._height),t=P(r)):t=T(r),new h({attributes:t.attributes,indices:t.indices,primitiveType:y.TRIANGLES,boundingSphere:t.boundingSphere})},q.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new q({center:e._center,semiMajorAxis:e._semiMajorAxis,semiMinorAxis:e._semiMinorAxis,ellipsoid:n,stRotation:e._stRotation,granularity:i,extrudedHeight:o,height:a,vertexFormat:E.POSITION_ONLY})},q}),r("Core/CircleGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipseGeometry","./Ellipsoid","./Math","./VertexFormat"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.radius,i={center:e.center,semiMajorAxis:r,semiMinorAxis:r,ellipsoid:e.ellipsoid,height:e.height,extrudedHeight:e.extrudedHeight,granularity:e.granularity,vertexFormat:e.vertexFormat,stRotation:e.stRotation};this._ellipseGeometry=new n(i),this._workerName="createCircleGeometry"};l.packedLength=n.packedLength,l.pack=function(e,t,r){n.pack(e._ellipseGeometry,t,r)};var u=new n({center:new e,semiMajorAxis:1,semiMinorAxis:1}),c={center:new e,radius:void 0,ellipsoid:o.clone(o.UNIT_SPHERE),height:void 0,extrudedHeight:void 0,granularity:void 0,vertexFormat:new s,stRotation:void 0,semiMajorAxis:void 0,semiMinorAxis:void 0};return l.unpack=function(t,i,a){var h=n.unpack(t,i,u);return c.center=e.clone(h._center,c.center),c.ellipsoid=o.clone(h._ellipsoid,c.ellipsoid),c.height=h._height,c.extrudedHeight=h._extrudedHeight,c.granularity=h._granularity,c.vertexFormat=s.clone(h._vertexFormat,c.vertexFormat),c.stRotation=h._stRotation,r(a)?(c.semiMajorAxis=h._semiMajorAxis,c.semiMinorAxis=h._semiMinorAxis,a._ellipseGeometry=new n(c),a):(c.radius=h._semiMajorAxis,new l(c))},l.createGeometry=function(e){return n.createGeometry(e._ellipseGeometry)},l.createShadowVolume=function(e,t,r){var i=e._ellipseGeometry._granularity,n=e._ellipseGeometry._ellipsoid,o=t(i,n),a=r(i,n);return new l({center:e._ellipseGeometry._center,radius:e._ellipseGeometry._semiMajorAxis,ellipsoid:n,stRotation:e._ellipseGeometry._stRotation,granularity:i,extrudedHeight:o,height:a,vertexFormat:s.POSITION_ONLY})},l}),r("Core/EllipseOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./EllipseGeometryLibrary","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(i){var n=i.center;_=t.multiplyByScalar(i.ellipsoid.geodeticSurfaceNormal(n,_),i.height,_),_=t.add(n,_,_);for(var o=new e(_,i.semiMajorAxis),s=a.computeEllipsePositions(i,!1,!0).outerPositions,l=new c({position:new u({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:a.raisePositionsToHeight(s,i,!1)})}),d=s.length/3,p=h.createTypedArray(d,2*d),m=0,f=0;d>f;++f)p[m++]=f,p[m++]=(f+1)%d;return{boundingSphere:o,attributes:l,indices:p}}function f(n){var o=i(n.numberOfVerticalLines,16);o=Math.max(o,0);var s=n.center,l=n.ellipsoid,d=n.semiMajorAxis,p=t.multiplyByScalar(l.geodeticSurfaceNormal(s,v),n.height,v);g.center=t.add(s,p,g.center),g.radius=d,p=t.multiplyByScalar(l.geodeticSurfaceNormal(s,p),n.extrudedHeight,p),y.center=t.add(s,p,y.center),y.radius=d;var m=a.computeEllipsePositions(n,!1,!0).outerPositions,f=new c({position:new u({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:a.raisePositionsToHeight(m,n,!0)})});m=f.position.values;var _=e.union(g,y),C=m.length/3,E=h.createTypedArray(C,2*C+2*o);C/=2;var S,w=0;for(S=0;C>S;++S)E[w++]=S,E[w++]=(S+1)%C,E[w++]=S+C,E[w++]=(S+1)%C+C;var T;if(o>0){var b=Math.min(o,C);T=Math.round(C/b)}var x=Math.min(T*o,C);if(o>0)for(S=0;x>S;S+=T)E[w++]=S,E[w++]=S+C;return{boundingSphere:_,attributes:f,indices:E}}var v=new t,_=new t,g=new e,y=new e,C=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.center,o=i(e.ellipsoid,s.WGS84),a=e.semiMajorAxis,l=e.semiMinorAxis,u=i(e.granularity,d.RADIANS_PER_DEGREE),c=i(e.height,0),h=e.extrudedHeight,p=n(h)&&Math.abs(c-h)>1;this._center=t.clone(r),this._semiMajorAxis=a,this._semiMinorAxis=l,this._ellipsoid=s.clone(o),this._rotation=i(e.rotation,0),this._height=c,this._granularity=u,this._extrudedHeight=h,this._extrude=p,this._numberOfVerticalLines=Math.max(i(e.numberOfVerticalLines,16),0),this._workerName="createEllipseOutlineGeometry"};C.packedLength=t.packedLength+s.packedLength+9,C.pack=function(e,r,o){o=i(o,0),t.pack(e._center,r,o),o+=t.packedLength,s.pack(e._ellipsoid,r,o),o+=s.packedLength,r[o++]=e._semiMajorAxis,r[o++]=e._semiMinorAxis,r[o++]=e._rotation,r[o++]=e._height,r[o++]=e._granularity,r[o++]=n(e._extrudedHeight)?1:0,r[o++]=i(e._extrudedHeight,0),r[o++]=e._extrude?1:0,r[o]=e._numberOfVerticalLines};var E=new t,S=new s,w={center:E,ellipsoid:S,semiMajorAxis:void 0,semiMinorAxis:void 0,rotation:void 0,height:void 0,granularity:void 0,extrudedHeight:void 0,numberOfVerticalLines:void 0};return C.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,E);r+=t.packedLength;var l=s.unpack(e,r,S);r+=s.packedLength;var u=e[r++],c=e[r++],h=e[r++],d=e[r++],p=e[r++],m=e[r++],f=e[r++],v=1===e[r++],_=e[r];return n(o)?(o._center=t.clone(a,o._center),o._ellipsoid=s.clone(l,o._ellipsoid),o._semiMajorAxis=u,o._semiMinorAxis=c,o._rotation=h,o._height=d,o._granularity=p,o._extrudedHeight=m?f:void 0,o._extrude=v,o._numberOfVerticalLines=_,o):(w.height=d,w.extrudedHeight=m?f:void 0,w.granularity=p,w.rotation=h,w.semiMajorAxis=u,w.semiMinorAxis=c,w.numberOfVerticalLines=_,new C(w))},C.createGeometry=function(e){e._center=e._ellipsoid.scaleToGeodeticSurface(e._center,e._center);var t,r={center:e._center,semiMajorAxis:e._semiMajorAxis,semiMinorAxis:e._semiMinorAxis,ellipsoid:e._ellipsoid,rotation:e._rotation,height:e._height,extrudedHeight:e._extrudedHeight,granularity:e._granularity,numberOfVerticalLines:e._numberOfVerticalLines};return e._extrude?(r.extrudedHeight=Math.min(e._extrudedHeight,e._height),r.height=Math.max(e._extrudedHeight,e._height),t=f(r)):t=m(r),new l({attributes:t.attributes,indices:t.indices,primitiveType:p.LINES,boundingSphere:t.boundingSphere})},C}),r("Core/CircleOutlineGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipseOutlineGeometry","./Ellipsoid"],function(e,t,r,i,n,o){"use strict";var a=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.radius,i={center:e.center,semiMajorAxis:r,semiMinorAxis:r,ellipsoid:e.ellipsoid,height:e.height,extrudedHeight:e.extrudedHeight,granularity:e.granularity,numberOfVerticalLines:e.numberOfVerticalLines};this._ellipseGeometry=new n(i),this._workerName="createCircleOutlineGeometry"};a.packedLength=n.packedLength,a.pack=function(e,t,r){n.pack(e._ellipseGeometry,t,r)};var s=new n({center:new e,semiMajorAxis:1,semiMinorAxis:1}),l={center:new e,radius:void 0,ellipsoid:o.clone(o.UNIT_SPHERE),height:void 0,extrudedHeight:void 0,granularity:void 0,numberOfVerticalLines:void 0,semiMajorAxis:void 0,semiMinorAxis:void 0};return a.unpack=function(t,i,u){var c=n.unpack(t,i,s);return l.center=e.clone(c._center,l.center),l.ellipsoid=o.clone(c._ellipsoid,l.ellipsoid),l.height=c._height,l.extrudedHeight=c._extrudedHeight,l.granularity=c._granularity,l.numberOfVerticalLines=c._numberOfVerticalLines,r(u)?(l.semiMajorAxis=c._semiMajorAxis,l.semiMinorAxis=c._semiMinorAxis,u._ellipseGeometry=new n(l),u):(l.radius=c._semiMajorAxis,new a(l))},a.createGeometry=function(e){return n.createGeometry(e._ellipseGeometry)},a}),r("Core/ClockRange",["./freezeObject"],function(e){"use strict";var t={UNBOUNDED:0,CLAMPED:1,LOOP_STOP:2};return e(t)}),r("Core/ClockStep",["./freezeObject"],function(e){"use strict";var t={TICK_DEPENDENT:0,SYSTEM_CLOCK_MULTIPLIER:1,SYSTEM_CLOCK:2};return e(t)}),r("Core/getTimestamp",["./defined"],function(e){"use strict";var t;return t="undefined"!=typeof performance&&e(performance.now)?function(){return performance.now()}:function(){return Date.now()}}),r("Core/Clock",["./ClockRange","./ClockStep","./defaultValue","./defined","./DeveloperError","./Event","./getTimestamp","./JulianDate"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(n){n=r(n,r.EMPTY_OBJECT);var l=n.startTime,u=!i(l),c=n.stopTime,h=!i(c),d=n.currentTime,p=!i(d);u&&h&&p?(d=s.now(),l=s.clone(d),c=s.addDays(d,1,new s)):u&&h?(l=s.clone(d),c=s.addDays(d,1,new s)):u&&p?(l=s.addDays(c,-1,new s),d=s.clone(l)):p&&h?(d=s.clone(l),c=s.addDays(l,1,new s)):p?d=s.clone(l):h?c=s.addDays(d,1,new s):u&&(l=s.clone(d)),this.startTime=l,this.stopTime=c,this.currentTime=d,this.multiplier=r(n.multiplier,1),this.clockStep=r(n.clockStep,t.SYSTEM_CLOCK_MULTIPLIER),this.clockRange=r(n.clockRange,e.UNBOUNDED),this.canAnimate=r(n.canAnimate,!0),this.shouldAnimate=r(n.shouldAnimate,!0),this.onTick=new o,this._lastSystemTime=a()};return l.prototype.tick=function(){var r=a(),i=s.clone(this.currentTime),n=this.startTime,o=this.stopTime,l=this.multiplier;if(this.canAnimate&&this.shouldAnimate)if(this.clockStep===t.SYSTEM_CLOCK)i=s.now(i);else{if(this.clockStep===t.TICK_DEPENDENT)i=s.addSeconds(i,l,i);else{var u=r-this._lastSystemTime;i=s.addSeconds(i,l*(u/1e3),i)}if(this.clockRange===e.CLAMPED)s.lessThan(i,n)?i=s.clone(n,i):s.greaterThan(i,o)&&(i=s.clone(o,i));else if(this.clockRange===e.LOOP_STOP)for(s.lessThan(i,n)&&(i=s.clone(n,i));s.greaterThan(i,o);)i=s.addSeconds(n,s.secondsDifference(i,o),i)}return this.currentTime=i,this._lastSystemTime=r,this.onTick.raiseEvent(this),i},l}),r("Core/Color",["./defaultValue","./defined","./DeveloperError","./FeatureDetection","./freezeObject","./Math"],function(e,t,r,i,n,o){"use strict";function a(e,t,r){return 0>r&&(r+=1),r>1&&(r-=1),1>6*r?e+6*(t-e)*r:1>2*r?t:2>3*r?e+(t-e)*(2/3-r)*6:e}var s=function(t,r,i,n){this.red=e(t,1),this.green=e(r,1),this.blue=e(i,1),this.alpha=e(n,1)};s.fromCartesian4=function(e,r){return t(r)?(r.red=e.x,r.green=e.y,r.blue=e.z,r.alpha=e.w,r):new s(e.x,e.y,e.z,e.w)},s.fromBytes=function(r,i,n,o,a){return r=s.byteToFloat(e(r,255)),i=s.byteToFloat(e(i,255)),n=s.byteToFloat(e(n,255)),o=s.byteToFloat(e(o,255)),t(a)?(a.red=r,a.green=i,a.blue=n,a.alpha=o,a):new s(r,i,n,o)},s.fromAlpha=function(e,r,i){return t(i)?(i.red=e.red,i.green=e.green,i.blue=e.blue,i.alpha=r,i):new s(e.red,e.green,e.blue,r)};var l,u,c;i.supportsTypedArrays()&&(l=new ArrayBuffer(4),u=new Uint32Array(l),c=new Uint8Array(l)),s.fromRgba=function(e){return u[0]=e,s.fromBytes(c[0],c[1],c[2],c[3])},s.fromHsl=function(t,r,i,n){t=e(t,0)%1,r=e(r,0),i=e(i,0),n=e(n,1);var o=i,l=i,u=i;if(0!==r){var c;c=.5>i?i*(1+r):i+r-i*r;var h=2*i-c;o=a(h,c,t+1/3),l=a(h,c,t),u=a(h,c,t-1/3)}return new s(o,l,u,n)},s.fromRandom=function(r,i){r=e(r,e.EMPTY_OBJECT);var n=r.red;if(!t(n)){var a=e(r.minimumRed,0),l=e(r.maximumRed,1);n=a+o.nextRandomNumber()*(l-a)}var u=r.green;if(!t(u)){var c=e(r.minimumGreen,0),h=e(r.maximumGreen,1);u=c+o.nextRandomNumber()*(h-c)}var d=r.blue;if(!t(d)){var p=e(r.minimumBlue,0),m=e(r.maximumBlue,1);d=p+o.nextRandomNumber()*(m-p)}var f=r.alpha;if(!t(f)){var v=e(r.minimumAlpha,0),_=e(r.maximumAlpha,1);f=v+o.nextRandomNumber()*(_-v)}return t(i)?(i.red=n,i.green=u,i.blue=d,i.alpha=f,i):new s(n,u,d,f)};var h=/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i,d=/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i,p=/^rgba?\(\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)\s*,\s*([0-9.]+%?)(?:\s*,\s*([0-9.]+))?\s*\)$/i,m=/^hsla?\(\s*([0-9.]+)\s*,\s*([0-9.]+%)\s*,\s*([0-9.]+%)(?:\s*,\s*([0-9.]+))?\s*\)$/i;return s.fromCssColorString=function(r){var i=s[r.toUpperCase()];if(t(i))return s.clone(i);var n=h.exec(r);return null!==n?new s(parseInt(n[1],16)/15,parseInt(n[2],16)/15,parseInt(n[3],16)/15):(n=d.exec(r),null!==n?new s(parseInt(n[1],16)/255,parseInt(n[2],16)/255,parseInt(n[3],16)/255):(n=p.exec(r),null!==n?new s(parseFloat(n[1])/("%"===n[1].substr(-1)?100:255),parseFloat(n[2])/("%"===n[2].substr(-1)?100:255),parseFloat(n[3])/("%"===n[3].substr(-1)?100:255),parseFloat(e(n[4],"1.0"))):(n=m.exec(r),null!==n?s.fromHsl(parseFloat(n[1])/360,parseFloat(n[2])/100,parseFloat(n[3])/100,parseFloat(e(n[4],"1.0"))):void 0)))},s.packedLength=4,s.pack=function(t,r,i){i=e(i,0),r[i++]=t.red,r[i++]=t.green,r[i++]=t.blue,r[i]=t.alpha},s.unpack=function(r,i,n){return i=e(i,0),t(n)||(n=new s),n.red=r[i++],n.green=r[i++],n.blue=r[i++],n.alpha=r[i],n},s.byteToFloat=function(e){return e/255},s.floatToByte=function(e){return 1===e?255:256*e|0},s.clone=function(e,r){return t(e)?t(r)?(r.red=e.red,r.green=e.green,r.blue=e.blue,r.alpha=e.alpha,r):new s(e.red,e.green,e.blue,e.alpha):void 0},s.equals=function(e,r){return e===r||t(e)&&t(r)&&e.red===r.red&&e.green===r.green&&e.blue===r.blue&&e.alpha===r.alpha},s.equalsArray=function(e,t,r){return e.red===t[r]&&e.green===t[r+1]&&e.blue===t[r+2]&&e.alpha===t[r+3]},s.prototype.clone=function(e){return s.clone(this,e)},s.prototype.equals=function(e){return s.equals(this,e)},s.prototype.equalsEpsilon=function(e,r){return this===e||t(e)&&Math.abs(this.red-e.red)<=r&&Math.abs(this.green-e.green)<=r&&Math.abs(this.blue-e.blue)<=r&&Math.abs(this.alpha-e.alpha)<=r},s.prototype.toString=function(){return"("+this.red+", "+this.green+", "+this.blue+", "+this.alpha+")"},s.prototype.toCssColorString=function(){var e=s.floatToByte(this.red),t=s.floatToByte(this.green),r=s.floatToByte(this.blue);return 1===this.alpha?"rgb("+e+","+t+","+r+")":"rgba("+e+","+t+","+r+","+this.alpha+")"},s.prototype.toBytes=function(e){var r=s.floatToByte(this.red),i=s.floatToByte(this.green),n=s.floatToByte(this.blue),o=s.floatToByte(this.alpha);return t(e)?(e[0]=r,e[1]=i,e[2]=n,e[3]=o,e):[r,i,n,o]},s.prototype.toRgba=function(){return c[0]=s.floatToByte(this.red),c[1]=s.floatToByte(this.green),c[2]=s.floatToByte(this.blue),c[3]=s.floatToByte(this.alpha),u[0]},s.prototype.brighten=function(e,t){return e=1-e,t.red=1-(1-this.red)*e,t.green=1-(1-this.green)*e,t.blue=1-(1-this.blue)*e,t.alpha=this.alpha,t},s.prototype.darken=function(e,t){return e=1-e,t.red=this.red*e,t.green=this.green*e,t.blue=this.blue*e,t.alpha=this.alpha,t},s.prototype.withAlpha=function(e,t){return s.fromAlpha(this,e,t)},s.ALICEBLUE=n(s.fromCssColorString("#F0F8FF")),s.ANTIQUEWHITE=n(s.fromCssColorString("#FAEBD7")),s.AQUA=n(s.fromCssColorString("#00FFFF")),s.AQUAMARINE=n(s.fromCssColorString("#7FFFD4")),s.AZURE=n(s.fromCssColorString("#F0FFFF")),s.BEIGE=n(s.fromCssColorString("#F5F5DC")),s.BISQUE=n(s.fromCssColorString("#FFE4C4")),s.BLACK=n(s.fromCssColorString("#000000")),s.BLANCHEDALMOND=n(s.fromCssColorString("#FFEBCD")),s.BLUE=n(s.fromCssColorString("#0000FF")),s.BLUEVIOLET=n(s.fromCssColorString("#8A2BE2")),s.BROWN=n(s.fromCssColorString("#A52A2A")),s.BURLYWOOD=n(s.fromCssColorString("#DEB887")),s.CADETBLUE=n(s.fromCssColorString("#5F9EA0")),s.CHARTREUSE=n(s.fromCssColorString("#7FFF00")),s.CHOCOLATE=n(s.fromCssColorString("#D2691E")),s.CORAL=n(s.fromCssColorString("#FF7F50")),s.CORNFLOWERBLUE=n(s.fromCssColorString("#6495ED")),s.CORNSILK=n(s.fromCssColorString("#FFF8DC")),s.CRIMSON=n(s.fromCssColorString("#DC143C")),s.CYAN=n(s.fromCssColorString("#00FFFF")),s.DARKBLUE=n(s.fromCssColorString("#00008B")),s.DARKCYAN=n(s.fromCssColorString("#008B8B")),s.DARKGOLDENROD=n(s.fromCssColorString("#B8860B")),s.DARKGRAY=n(s.fromCssColorString("#A9A9A9")),s.DARKGREEN=n(s.fromCssColorString("#006400")),s.DARKGREY=s.DARKGRAY,s.DARKKHAKI=n(s.fromCssColorString("#BDB76B")),s.DARKMAGENTA=n(s.fromCssColorString("#8B008B")),s.DARKOLIVEGREEN=n(s.fromCssColorString("#556B2F")),s.DARKORANGE=n(s.fromCssColorString("#FF8C00")),s.DARKORCHID=n(s.fromCssColorString("#9932CC")),s.DARKRED=n(s.fromCssColorString("#8B0000")),s.DARKSALMON=n(s.fromCssColorString("#E9967A")),s.DARKSEAGREEN=n(s.fromCssColorString("#8FBC8F")),s.DARKSLATEBLUE=n(s.fromCssColorString("#483D8B")),s.DARKSLATEGRAY=n(s.fromCssColorString("#2F4F4F")),s.DARKSLATEGREY=s.DARKSLATEGRAY,s.DARKTURQUOISE=n(s.fromCssColorString("#00CED1")),s.DARKVIOLET=n(s.fromCssColorString("#9400D3")),s.DEEPPINK=n(s.fromCssColorString("#FF1493")),s.DEEPSKYBLUE=n(s.fromCssColorString("#00BFFF")),s.DIMGRAY=n(s.fromCssColorString("#696969")),s.DIMGREY=s.DIMGRAY,s.DODGERBLUE=n(s.fromCssColorString("#1E90FF")),s.FIREBRICK=n(s.fromCssColorString("#B22222")),s.FLORALWHITE=n(s.fromCssColorString("#FFFAF0")),s.FORESTGREEN=n(s.fromCssColorString("#228B22")),s.FUSCHIA=n(s.fromCssColorString("#FF00FF")),s.GAINSBORO=n(s.fromCssColorString("#DCDCDC")),s.GHOSTWHITE=n(s.fromCssColorString("#F8F8FF")),s.GOLD=n(s.fromCssColorString("#FFD700")),s.GOLDENROD=n(s.fromCssColorString("#DAA520")),s.GRAY=n(s.fromCssColorString("#808080")),s.GREEN=n(s.fromCssColorString("#008000")),s.GREENYELLOW=n(s.fromCssColorString("#ADFF2F")),s.GREY=s.GRAY,s.HONEYDEW=n(s.fromCssColorString("#F0FFF0")),s.HOTPINK=n(s.fromCssColorString("#FF69B4")),s.INDIANRED=n(s.fromCssColorString("#CD5C5C")),s.INDIGO=n(s.fromCssColorString("#4B0082")),s.IVORY=n(s.fromCssColorString("#FFFFF0")),s.KHAKI=n(s.fromCssColorString("#F0E68C")),s.LAVENDER=n(s.fromCssColorString("#E6E6FA")),s.LAVENDAR_BLUSH=n(s.fromCssColorString("#FFF0F5")),s.LAWNGREEN=n(s.fromCssColorString("#7CFC00")),s.LEMONCHIFFON=n(s.fromCssColorString("#FFFACD")),s.LIGHTBLUE=n(s.fromCssColorString("#ADD8E6")),s.LIGHTCORAL=n(s.fromCssColorString("#F08080")),s.LIGHTCYAN=n(s.fromCssColorString("#E0FFFF")),s.LIGHTGOLDENRODYELLOW=n(s.fromCssColorString("#FAFAD2")),s.LIGHTGRAY=n(s.fromCssColorString("#D3D3D3")),s.LIGHTGREEN=n(s.fromCssColorString("#90EE90")),s.LIGHTGREY=s.LIGHTGRAY,s.LIGHTPINK=n(s.fromCssColorString("#FFB6C1")),s.LIGHTSEAGREEN=n(s.fromCssColorString("#20B2AA")),s.LIGHTSKYBLUE=n(s.fromCssColorString("#87CEFA")),s.LIGHTSLATEGRAY=n(s.fromCssColorString("#778899")),s.LIGHTSLATEGREY=s.LIGHTSLATEGRAY,s.LIGHTSTEELBLUE=n(s.fromCssColorString("#B0C4DE")),s.LIGHTYELLOW=n(s.fromCssColorString("#FFFFE0")),s.LIME=n(s.fromCssColorString("#00FF00")),s.LIMEGREEN=n(s.fromCssColorString("#32CD32")),s.LINEN=n(s.fromCssColorString("#FAF0E6")),s.MAGENTA=n(s.fromCssColorString("#FF00FF")),s.MAROON=n(s.fromCssColorString("#800000")),s.MEDIUMAQUAMARINE=n(s.fromCssColorString("#66CDAA")),s.MEDIUMBLUE=n(s.fromCssColorString("#0000CD")),s.MEDIUMORCHID=n(s.fromCssColorString("#BA55D3")),s.MEDIUMPURPLE=n(s.fromCssColorString("#9370DB")),s.MEDIUMSEAGREEN=n(s.fromCssColorString("#3CB371")),s.MEDIUMSLATEBLUE=n(s.fromCssColorString("#7B68EE")),s.MEDIUMSPRINGGREEN=n(s.fromCssColorString("#00FA9A")),s.MEDIUMTURQUOISE=n(s.fromCssColorString("#48D1CC")),s.MEDIUMVIOLETRED=n(s.fromCssColorString("#C71585")),s.MIDNIGHTBLUE=n(s.fromCssColorString("#191970")),s.MINTCREAM=n(s.fromCssColorString("#F5FFFA")),s.MISTYROSE=n(s.fromCssColorString("#FFE4E1")),s.MOCCASIN=n(s.fromCssColorString("#FFE4B5")),s.NAVAJOWHITE=n(s.fromCssColorString("#FFDEAD")),s.NAVY=n(s.fromCssColorString("#000080")),s.OLDLACE=n(s.fromCssColorString("#FDF5E6")),s.OLIVE=n(s.fromCssColorString("#808000")),s.OLIVEDRAB=n(s.fromCssColorString("#6B8E23")),s.ORANGE=n(s.fromCssColorString("#FFA500")),s.ORANGERED=n(s.fromCssColorString("#FF4500")),s.ORCHID=n(s.fromCssColorString("#DA70D6")),s.PALEGOLDENROD=n(s.fromCssColorString("#EEE8AA")),s.PALEGREEN=n(s.fromCssColorString("#98FB98")),s.PALETURQUOISE=n(s.fromCssColorString("#AFEEEE")),s.PALEVIOLETRED=n(s.fromCssColorString("#DB7093")),s.PAPAYAWHIP=n(s.fromCssColorString("#FFEFD5")),s.PEACHPUFF=n(s.fromCssColorString("#FFDAB9")),s.PERU=n(s.fromCssColorString("#CD853F")),s.PINK=n(s.fromCssColorString("#FFC0CB")),s.PLUM=n(s.fromCssColorString("#DDA0DD")),s.POWDERBLUE=n(s.fromCssColorString("#B0E0E6")),s.PURPLE=n(s.fromCssColorString("#800080")),s.RED=n(s.fromCssColorString("#FF0000")),s.ROSYBROWN=n(s.fromCssColorString("#BC8F8F")),s.ROYALBLUE=n(s.fromCssColorString("#4169E1")),s.SADDLEBROWN=n(s.fromCssColorString("#8B4513")),s.SALMON=n(s.fromCssColorString("#FA8072")),s.SANDYBROWN=n(s.fromCssColorString("#F4A460")),s.SEAGREEN=n(s.fromCssColorString("#2E8B57")),s.SEASHELL=n(s.fromCssColorString("#FFF5EE")),s.SIENNA=n(s.fromCssColorString("#A0522D")),s.SILVER=n(s.fromCssColorString("#C0C0C0")),s.SKYBLUE=n(s.fromCssColorString("#87CEEB")),s.SLATEBLUE=n(s.fromCssColorString("#6A5ACD")),s.SLATEGRAY=n(s.fromCssColorString("#708090")),s.SLATEGREY=s.SLATEGRAY,s.SNOW=n(s.fromCssColorString("#FFFAFA")),s.SPRINGGREEN=n(s.fromCssColorString("#00FF7F")),s.STEELBLUE=n(s.fromCssColorString("#4682B4")),s.TAN=n(s.fromCssColorString("#D2B48C")),s.TEAL=n(s.fromCssColorString("#008080")),s.THISTLE=n(s.fromCssColorString("#D8BFD8")),s.TOMATO=n(s.fromCssColorString("#FF6347")),s.TURQUOISE=n(s.fromCssColorString("#40E0D0")),s.VIOLET=n(s.fromCssColorString("#EE82EE")),s.WHEAT=n(s.fromCssColorString("#F5DEB3")),s.WHITE=n(s.fromCssColorString("#FFFFFF")),s.WHITESMOKE=n(s.fromCssColorString("#F5F5F5")),s.YELLOW=n(s.fromCssColorString("#FFFF00")),s.YELLOWGREEN=n(s.fromCssColorString("#9ACD32")),s.TRANSPARENT=n(new s(0,0,0,0)), -s}),r("Core/ColorGeometryInstanceAttribute",["./Color","./ComponentDatatype","./defaultValue","./defined","./defineProperties","./DeveloperError"],function(e,t,r,i,n,o){"use strict";var a=function(t,i,n,o){t=r(t,1),i=r(i,1),n=r(n,1),o=r(o,1),this.value=new Uint8Array([e.floatToByte(t),e.floatToByte(i),e.floatToByte(n),e.floatToByte(o)])};return n(a.prototype,{componentDatatype:{get:function(){return t.UNSIGNED_BYTE}},componentsPerAttribute:{get:function(){return 4}},normalize:{get:function(){return!0}}}),a.fromColor=function(e){return new a(e.red,e.green,e.blue,e.alpha)},a.toValue=function(e,t){return i(t)?e.toBytes(t):new Uint8Array(e.toBytes())},a}),r("Core/CornerType",["./freezeObject"],function(e){"use strict";var t={ROUNDED:0,MITERED:1,BEVELED:2};return e(t)}),r("Core/isArray",["./defined"],function(e){"use strict";var t=Array.isArray;return e(t)||(t=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),t}),r("Core/EllipsoidGeodesic",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Math"],function(e,t,r,i,n,o,a,s){"use strict";function l(e){var t=e._uSquared,r=e._ellipsoid.maximumRadius,i=e._ellipsoid.minimumRadius,n=(r-i)/r,o=Math.cos(e._startHeading),a=Math.sin(e._startHeading),s=(1-n)*Math.tan(e._start.latitude),l=1/Math.sqrt(1+s*s),u=l*s,c=Math.atan2(s,o),h=l*a,d=h*h,p=1-d,m=Math.sqrt(p),f=t/4,v=f*f,_=v*f,g=v*v,y=1+f-3*v/4+5*_/4-175*g/64,C=1-f+15*v/8-35*_/8,E=1-3*f+35*v/4,S=1-5*f,w=y*c-C*Math.sin(2*c)*f/2-E*Math.sin(4*c)*v/16-S*Math.sin(6*c)*_/48-5*Math.sin(8*c)*g/512,T=e._constants;T.a=r,T.b=i,T.f=n,T.cosineHeading=o,T.sineHeading=a,T.tanU=s,T.cosineU=l,T.sineU=u,T.sigma=c,T.sineAlpha=h,T.sineSquaredAlpha=d,T.cosineSquaredAlpha=p,T.cosineAlpha=m,T.u2Over4=f,T.u4Over16=v,T.u6Over64=_,T.u8Over256=g,T.a0=y,T.a1=C,T.a2=E,T.a3=S,T.distanceRatio=w}function u(e,t){return e*t*(4+e*(4-3*t))/16}function c(e,t,r,i,n,o,a){var s=u(e,r);return(1-s)*e*t*(i+s*n*(a+s*o*(2*a*a-1)))}function h(e,t,r,i,n,o,a){var l,u,h,d,p,m=(t-r)/t,f=o-i,v=Math.atan((1-m)*Math.tan(n)),_=Math.atan((1-m)*Math.tan(a)),g=Math.cos(v),y=Math.sin(v),C=Math.cos(_),E=Math.sin(_),S=g*C,w=g*E,T=y*E,b=y*C,x=f,P=s.TWO_PI,A=Math.cos(x),I=Math.sin(x);do{A=Math.cos(x),I=Math.sin(x);var M=w-b*A;h=Math.sqrt(C*C*I*I+M*M),u=T+S*A,l=Math.atan2(h,u);var D;0===h?(D=0,d=1):(D=S*I/h,d=1-D*D),P=x,p=u-2*T/d,isNaN(p)&&(p=0),x=f+c(m,D,d,l,h,u,p)}while(Math.abs(x-P)>s.EPSILON12);var R=d*(t*t-r*r)/(r*r),O=1+R*(4096+R*(R*(320-175*R)-768))/16384,N=R*(256+R*(R*(74-47*R)-128))/1024,L=p*p,F=N*h*(p+N*(u*(2*L-1)-N*p*(4*h*h-3)*(4*L-3)/6)/4),B=r*O*(l-F),V=Math.atan2(C*I,w-b*A),z=Math.atan2(g*I,w*A-b);e._distance=B,e._startHeading=V,e._endHeading=z,e._uSquared=R}function d(r,i,n,o){e.normalize(o.cartographicToCartesian(i,m),p),e.normalize(o.cartographicToCartesian(n,m),m);h(r,o.maximumRadius,o.minimumRadius,i.longitude,i.latitude,n.longitude,n.latitude),r._start=t.clone(i,r._start),r._end=t.clone(n,r._end),r._start.height=0,r._end.height=0,l(r)}var p=new e,m=new e,f=function(e,n,o){var s=r(o,a.WGS84);this._ellipsoid=s,this._start=new t,this._end=new t,this._constants={},this._startHeading=void 0,this._endHeading=void 0,this._distance=void 0,this._uSquared=void 0,i(e)&&i(n)&&d(this,e,n,s)};return n(f.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},surfaceDistance:{get:function(){return this._distance}},start:{get:function(){return this._start}},end:{get:function(){return this._end}},startHeading:{get:function(){return this._startHeading}},endHeading:{get:function(){return this._endHeading}}}),f.prototype.setEndPoints=function(e,t){d(this,e,t,this._ellipsoid)},f.prototype.interpolateUsingFraction=function(e,t){return this.interpolateUsingSurfaceDistance(this._distance*e,t)},f.prototype.interpolateUsingSurfaceDistance=function(e,r){var n=this._constants,o=n.distanceRatio+e/n.b,a=Math.cos(2*o),s=Math.cos(4*o),l=Math.cos(6*o),u=Math.sin(2*o),h=Math.sin(4*o),d=Math.sin(6*o),p=Math.sin(8*o),m=o*o,f=o*m,v=n.u8Over256,_=n.u2Over4,g=n.u6Over64,y=n.u4Over16,C=2*f*v*a/3+o*(1-_+7*y/4-15*g/4+579*v/64-(y-15*g/4+187*v/16)*a-(5*g/4-115*v/16)*s-29*v*l/16)+(_/2-y+71*g/32-85*v/16)*u+(5*y/16-5*g/4+383*v/96)*h-m*((g-11*v/2)*u+5*v*h/2)+(29*g/96-29*v/16)*d+539*v*p/1536,E=Math.asin(Math.sin(C)*n.cosineAlpha),S=Math.atan(n.a/n.b*Math.tan(E));C-=n.sigma;var w=Math.cos(2*n.sigma+C),T=Math.sin(C),b=Math.cos(C),x=n.cosineU*b,P=n.sineU*T,A=Math.atan2(T*n.sineHeading,x-P*n.cosineHeading),I=A-c(n.f,n.sineAlpha,n.cosineSquaredAlpha,C,T,b,w);return i(r)?(r.longitude=this._start.longitude+I,r.latitude=S,r.height=0,r):new t(this._start.longitude+I,S,0)},f}),r("Core/PolylinePipeline",["./Cartesian3","./Cartographic","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidGeodesic","./IntersectionTests","./isArray","./Math","./Matrix4","./Plane"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t,r){var i=T;i.length=e;var n;if(t===r){for(n=0;e>n;n++)i[n]=t;return i}var o=r-t,a=o/e;for(n=0;e>n;n++){var s=t+n*a;i[n]=s}return i}function p(t,r,i,n,o,a,s,l){var u=n.scaleToGeodeticSurface(t,A),c=n.scaleToGeodeticSurface(r,I),h=m.numberOfPoints(t,r,i),p=n.cartesianToCartographic(u,b),f=n.cartesianToCartographic(c,x),v=d(h,o,a);M.setEndPoints(p,f);var _=M.surfaceDistance/h,g=l;p.height=o;var y=n.cartographicToCartesian(p,P);e.pack(y,s,g),g+=3;for(var C=1;h>C;C++){var E=M.interpolateUsingSurfaceDistance(C*_,x);E.height=v[C],y=n.cartographicToCartesian(E,P),e.pack(y,s,g),g+=3}return g}var m={};m.numberOfPoints=function(t,r,i){var n=e.distance(t,r);return Math.ceil(n/i)};var f=new t;m.extractHeights=function(e,t){for(var r=e.length,i=new Array(r),n=0;r>n;n++){var o=e[n];i[n]=t.cartesianToCartographic(o,f).height}return i};var v=new c,_=new e,g=new e,y=new h(e.ZERO,0),C=new e,E=new h(e.ZERO,0),S=new e,w=new e,T=[],b=new t,x=new t,P=new e,A=new e,I=new e,M=new a;m.wrapLongitude=function(t,n){var o=[],a=[];if(i(t)&&t.length>0){n=r(n,c.IDENTITY);var l=c.inverseTransformation(n,v),u=c.multiplyByPoint(l,e.ZERO,_),d=c.multiplyByPointAsVector(l,e.UNIT_Y,g),p=h.fromPointNormal(u,d,y),m=c.multiplyByPointAsVector(l,e.UNIT_X,C),f=h.fromPointNormal(u,m,E),T=1;o.push(e.clone(t[0]));for(var b=o[0],x=t.length,P=1;x>P;++P){var A=t[P];if(h.getPointDistance(f,b)<0||h.getPointDistance(f,A)<0){var I=s.lineSegmentPlane(b,A,p,S);if(i(I)){var M=e.multiplyByScalar(d,5e-9,w);h.getPointDistance(p,b)<0&&e.negate(M,M),o.push(e.add(I,M,new e)),a.push(T+1),e.negate(M,M),o.push(e.add(I,M,new e)),T=1}}o.push(e.clone(t[P])),T++,b=A}a.push(T)}return{positions:o,lengths:a}};var D=u.EPSILON7;return m.removeDuplicates=function(t){var r=t.length;if(2>r)return t;var i,n,o;for(i=1;r>i&&(n=t[i-1],o=t[i],!e.equalsEpsilon(n,o,D));++i);if(i===r)return t;for(var a=t.slice(0,i);r>i;++i)o=t[i],e.equalsEpsilon(n,o,D)||(a.push(e.clone(o)),n=o);return a},m.generateArc=function(t){i(t)||(t={});var n=t.positions,a=n.length,s=r(t.ellipsoid,o.WGS84),c=r(t.height,0);if(1>a)return[];if(1===a){var h=s.scaleToGeodeticSurface(n[0],A);if(0!==c){var d=s.geodeticSurfaceNormal(h,P);e.multiplyByScalar(d,c,d),e.add(h,d,h)}return[h.x,h.y,h.z]}var f=t.minDistance;if(!i(f)){var v=r(t.granularity,u.RADIANS_PER_DEGREE);f=u.chordLength(v,s.maximumRadius)}var _,g=0;for(_=0;a-1>_;_++)g+=m.numberOfPoints(n[_],n[_+1],f);var y=3*(g+1),C=new Array(y),E=0,S=l(c);for(_=0;a-1>_;_++){var w=n[_],x=n[_+1],I=S?c[_]:c,M=S?c[_+1]:c;E=p(w,x,f,s,I,M,C,E)}T.length=0;var D=n[a-1],R=s.cartesianToCartographic(D,b);R.height=S?c[a-1]:c;var O=s.cartographicToCartesian(R,P);return e.pack(O,C,y-3),C},m.generateCartesianArc=function(t){for(var r=m.generateArc(t),i=r.length/3,n=new Array(i),o=0;i>o;o++)n[o]=e.unpack(r,3*o);return n},m}),r("Core/PolylineVolumeGeometryLibrary",["./Cartesian2","./Cartesian3","./Cartesian4","./Cartographic","./CornerType","./EllipsoidTangentPlane","./Math","./Matrix3","./Matrix4","./PolylinePipeline","./Quaternion","./Transforms"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t){for(var r=new Array(e.length),i=0;i<e.length;i++){var n=e[i];N=t.cartesianToCartographic(n,N),r[i]=N.height,e[i]=t.scaleToGeodeticSurface(n,n)}return r}function p(e,r,i,n){var o,a=e[0],s=e[1],l=t.angleBetween(a,s),u=Math.ceil(l/n),c=new Array(u);if(r===i){for(o=0;u>o;o++)c[o]=r;return c.push(i),c}var h=i-r,d=h/u;for(o=1;u>o;o++){var p=r+o*d;c[o]=p}return c[0]=r,c.push(i),c}function m(r,i,n,a){var s=new o(n,a),l=s.projectPointOntoPlane(t.add(n,r,Y),Y),u=s.projectPointOntoPlane(t.add(n,i,X),X),c=e.angleBetween(l,u);return u.x*l.y-u.y*l.x>=0?-c:c}function f(e,r,i,n,o,a,u,c){var d=k,p=U;F=h.eastNorthUpToFixedFrame(e,o,F),d=l.multiplyByPointAsVector(F,L,d),d=t.normalize(d,d);var f=m(d,r,e,o);V=s.fromRotationZ(f,V),G.z=a,F=l.multiplyTransformation(F,l.fromRotationTranslation(V,G,B),F);var v=z;v[0]=u;for(var _=0;c>_;_++)for(var g=0;g<i.length;g+=3)p=t.fromArray(i,g,p),p=s.multiplyByVector(v,p,p),p=l.multiplyByPoint(F,p,p),n.push(p.x,p.y,p.z);return n}function v(e,r,i,n,o,a,s){for(var l=0;l<e.length;l+=3){var u=t.fromArray(e,l,W);n=f(u,r,i,n,o,a[l/3],s,1)}return n}function _(e,t){var r=e.length,i=new Array(6*r),n=0,o=t.x+t.width/2,a=t.y+t.height/2,s=e[0];i[n++]=s.x-o,i[n++]=0,i[n++]=s.y-a;for(var l=1;r>l;l++){s=e[l];var u=s.x-o,c=s.y-a;i[n++]=u,i[n++]=0,i[n++]=c,i[n++]=u,i[n++]=0,i[n++]=c}return s=e[0],i[n++]=s.x-o,i[n++]=0,i[n++]=s.y-a,i}function g(e,t){for(var r=e.length,i=new Array(3*r),n=0,o=t.x+t.width/2,a=t.y+t.height/2,s=0;r>s;s++)i[n++]=e[s].x-o,i[n++]=0,i[n++]=e[s].y-a;return i}function y(e,r,i,o,l,u,h,d,p,m){var v,_=t.angleBetween(t.subtract(r,e,D),t.subtract(i,e,R)),g=o===n.BEVELED?0:Math.ceil(_/a.toRadians(5));v=l?s.fromQuaternion(c.fromAxisAngle(t.negate(e,D),_/(g+1),H),j):s.fromQuaternion(c.fromAxisAngle(e,_/(g+1),H),j);var y,C;if(r=t.clone(r,q),g>0)for(var E=m?2:1,S=0;g>S;S++)r=s.multiplyByVector(v,r,r),y=t.subtract(r,e,D),y=t.normalize(y,y),l||(y=t.negate(y,y)),C=u.scaleToGeodeticSurface(r,R),h=f(C,y,d,h,u,p,1,E);else y=t.subtract(r,e,D),y=t.normalize(y,y),l||(y=t.negate(y,y)),C=u.scaleToGeodeticSurface(r,R),h=f(C,y,d,h,u,p,1,1),i=t.clone(i,q),y=t.subtract(i,e,D),y=t.normalize(y,y),l||(y=t.negate(y,y)),C=u.scaleToGeodeticSurface(i,R),h=f(C,y,d,h,u,p,1,1);return h}function C(e,t){return a.equalsEpsilon(e.latitude,t.latitude,a.EPSILON6)&&a.equalsEpsilon(e.longitude,t.longitude,a.EPSILON6)}var E=[new t,new t],S=new t,w=new t,T=new t,b=new t,x=new t,P=new t,A=new t,I=new t,M=new t,D=new t,R=new t,O={},N=new i,L=new t(-1,0,0),F=new l,B=new l,V=new s,z=s.IDENTITY.clone(),k=new t,U=new r,G=new t,W=new t,H=new c,q=new t,j=new s;O.removeDuplicatesFromShape=function(t){for(var r=t.length,i=[],n=r-1,o=0;r>o;n=o++){var a=t[n],s=t[o];e.equals(a,s)||i.push(s)}return i};var Y=new t,X=new t;O.angleIsGreaterThanPi=function(e,r,i,n){var a=new o(i,n),s=a.projectPointOntoPlane(t.add(i,e,Y),Y),l=a.projectPointOntoPlane(t.add(i,r,X),X);return l.x*s.y-l.y*s.x>=0};var Z=new i,K=new i;O.removeDuplicatesFromPositions=function(e,t){var r=e.length;if(2>r)return e.slice(0);var i=[];i.push(e[0]);for(var n=1;r>n;++n){var o=e[n-1],a=e[n],s=t.cartesianToCartographic(o,Z),l=t.cartesianToCartographic(a,K);C(s,l)||i.push(a)}return i};var J=new t,Q=new t;return O.computePositions=function(e,r,i,o,s){var l=o._ellipsoid,c=d(e,l),h=o._granularity,m=o._cornerType,C=s?_(r,i):g(r,i),R=s?g(r,i):void 0,N=i.height/2,L=i.width/2,F=e.length,B=[],V=s?[]:void 0,z=S,k=w,U=T,G=b,W=x,H=P,q=A,j=I,Y=M,X=e[0],Z=e[1];G=l.geodeticSurfaceNormal(X,G),z=t.subtract(Z,X,z),z=t.normalize(z,z),j=t.cross(G,z,j),j=t.normalize(j,j);var K=c[0],$=c[1];s&&(V=f(X,j,R,V,l,K+N,1,1)),Y=t.clone(X,Y),X=Z,k=t.negate(z,k);for(var ee,te,re=1;F-1>re;re++){var ie=s?2:1;Z=e[re+1],z=t.subtract(Z,X,z),z=t.normalize(z,z),U=t.add(z,k,U),U=t.normalize(U,U),G=l.geodeticSurfaceNormal(X,G);var ne=t.multiplyByScalar(G,t.dot(z,G),J);t.subtract(z,ne,ne),t.normalize(ne,ne);var oe=t.multiplyByScalar(G,t.dot(k,G),Q);t.subtract(k,oe,oe),t.normalize(oe,oe);var ae=!a.equalsEpsilon(Math.abs(t.dot(ne,oe)),1,a.EPSILON7);if(ae){U=t.cross(U,G,U),U=t.cross(G,U,U),U=t.normalize(U,U);var se=1/Math.max(.25,t.magnitude(t.cross(U,k,D))),le=O.angleIsGreaterThanPi(z,k,X,l);le?(W=t.add(X,t.multiplyByScalar(U,se*L,U),W),H=t.add(W,t.multiplyByScalar(j,L,H),H),E[0]=t.clone(Y,E[0]),E[1]=t.clone(H,E[1]),ee=p(E,K+N,$+N,h),te=u.generateArc({positions:E,granularity:h,ellipsoid:l}),B=v(te,j,C,B,l,ee,1),j=t.cross(G,z,j),j=t.normalize(j,j),q=t.add(W,t.multiplyByScalar(j,L,q),q),m===n.ROUNDED||m===n.BEVELED?y(W,H,q,m,le,l,B,C,$+N,s):(U=t.negate(U,U),B=f(X,U,C,B,l,$+N,se,ie)),Y=t.clone(q,Y)):(W=t.add(X,t.multiplyByScalar(U,se*L,U),W),H=t.add(W,t.multiplyByScalar(j,-L,H),H),E[0]=t.clone(Y,E[0]),E[1]=t.clone(H,E[1]),ee=p(E,K+N,$+N,h),te=u.generateArc({positions:E,granularity:h,ellipsoid:l}),B=v(te,j,C,B,l,ee,1),j=t.cross(G,z,j),j=t.normalize(j,j),q=t.add(W,t.multiplyByScalar(j,-L,q),q),m===n.ROUNDED||m===n.BEVELED?y(W,H,q,m,le,l,B,C,$+N,s):B=f(X,U,C,B,l,$+N,se,ie),Y=t.clone(q,Y)),k=t.negate(z,k)}else B=f(Y,j,C,B,l,K+N,1,1),Y=X;K=$,$=c[re+1],X=Z}E[0]=t.clone(Y,E[0]),E[1]=t.clone(X,E[1]),ee=p(E,K+N,$+N,h),te=u.generateArc({positions:E,granularity:h,ellipsoid:l}),B=v(te,j,C,B,l,ee,1),s&&(V=f(X,j,R,V,l,$+N,1,1)),F=B.length;var ue=s?F+V.length:F,ce=new Float64Array(ue);return ce.set(B),s&&ce.set(V,F),ce},O}),r("Core/CorridorGeometryLibrary",["./Cartesian3","./CornerType","./defined","./isArray","./Math","./Matrix3","./PolylinePipeline","./PolylineVolumeGeometryLibrary","./Quaternion"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(r,i,a,s,u){var c=e.angleBetween(e.subtract(i,r,f),e.subtract(a,r,v)),h=s===t.BEVELED?1:Math.ceil(c/n.toRadians(5))+1,d=3*h,p=new Array(d);p[d-3]=a.x,p[d-2]=a.y,p[d-1]=a.z;var m;m=u?o.fromQuaternion(l.fromAxisAngle(e.negate(r,f),c/h,M),D):o.fromQuaternion(l.fromAxisAngle(r,c/h,M),D);var _=0;i=e.clone(i,f);for(var g=0;h>g;g++)i=o.multiplyByVector(m,i,i),p[_++]=i.x,p[_++]=i.y,p[_++]=i.z;return p}function c(r){var i=C,n=E,o=S,a=r[1];n=e.fromArray(r[1],a.length-3,n),o=e.fromArray(r[0],0,o),i=e.multiplyByScalar(e.add(n,o,i),.5,i);var s=u(i,n,o,t.ROUNDED,!1),l=r.length-1,c=r[l-1];a=r[l],n=e.fromArray(c,c.length-3,n),o=e.fromArray(a,0,o),i=e.multiplyByScalar(e.add(n,o,i),.5,i);var h=u(i,n,o,t.ROUNDED,!1);return[s,h]}function h(t,r,i,n){var o=f;return n?o=e.add(t,r,o):(r=e.negate(r,r),o=e.add(t,r,o)),[o.x,o.y,o.z,i.x,i.y,i.z]}function d(t,r,i,n){for(var o=new Array(t.length),a=new Array(t.length),s=e.multiplyByScalar(r,i,f),l=e.negate(s,v),u=0,c=t.length-1,h=0;h<t.length;h+=3){var d=e.fromArray(t,h,_),p=e.add(d,l,g);o[u++]=p.x,o[u++]=p.y,o[u++]=p.z;var m=e.add(d,s,g);a[c--]=m.z,a[c--]=m.y,a[c--]=m.x}return n.push(o,a),n}function p(e,t){for(var r=0;r<e.length;r++)e[r]=t.scaleToGeodeticSurface(e[r],e[r]);return e}var m={},f=new e,v=new e,_=new e,g=new e,y=[new e,new e],C=new e,E=new e,S=new e,w=new e,T=new e,b=new e,x=new e,P=new e,A=new e,I=new e,M=new l,D=new o;m.addAttribute=function(e,t,i,n){var o=t.x,a=t.y,s=t.z;r(i)&&(e[i]=o,e[i+1]=a,e[i+2]=s),r(n)&&(e[n]=s,e[n-1]=a,e[n-2]=o)};var R=new e,O=new e;m.computePositions=function(r){var i=r.granularity,o=r.positions,l=r.ellipsoid;o=p(o,l);var m=r.width/2,v=r.cornerType,_=r.saveAttributes,g=C,M=E,D=S,N=w,L=T,F=b,B=x,V=P,z=A,k=I,U=[],G=_?[]:void 0,W=_?[]:void 0,H=o[0],q=o[1];M=e.normalize(e.subtract(q,H,M),M),g=l.geodeticSurfaceNormal(H,g),N=e.normalize(e.cross(g,M,N),N),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z)),B=e.clone(H,B),H=q,D=e.negate(M,D);var j,Y,X=[],Z=o.length;for(Y=1;Z-1>Y;Y++){g=l.geodeticSurfaceNormal(H,g),q=o[Y+1],M=e.normalize(e.subtract(q,H,M),M),L=e.normalize(e.add(M,D,L),L);var K=e.multiplyByScalar(g,e.dot(M,g),R);e.subtract(M,K,K),e.normalize(K,K);var J=e.multiplyByScalar(g,e.dot(D,g),O);e.subtract(D,J,J),e.normalize(J,J);var Q=!n.equalsEpsilon(Math.abs(e.dot(K,J)),1,n.EPSILON7);if(Q){L=e.cross(L,g,L),L=e.cross(g,L,L);var $=m/Math.max(.25,e.magnitude(e.cross(L,D,f))),ee=s.angleIsGreaterThanPi(M,D,H,l);L=e.multiplyByScalar(L,$,L),ee?(V=e.add(H,L,V),k=e.add(V,e.multiplyByScalar(N,m,k),k),z=e.add(V,e.multiplyByScalar(N,2*m,z),z),y[0]=e.clone(B,y[0]),y[1]=e.clone(k,y[1]),j=a.generateArc({positions:y,granularity:i,ellipsoid:l}),U=d(j,N,m,U),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z)),F=e.clone(z,F),N=e.normalize(e.cross(g,M,N),N),z=e.add(V,e.multiplyByScalar(N,2*m,z),z),B=e.add(V,e.multiplyByScalar(N,m,B),B),v===t.ROUNDED||v===t.BEVELED?X.push({leftPositions:u(V,F,z,v,ee)}):X.push({leftPositions:h(H,e.negate(L,L),z,ee)})):(z=e.add(H,L,z),k=e.add(z,e.negate(e.multiplyByScalar(N,m,k),k),k),V=e.add(z,e.negate(e.multiplyByScalar(N,2*m,V),V),V),y[0]=e.clone(B,y[0]),y[1]=e.clone(k,y[1]),j=a.generateArc({positions:y,granularity:i,ellipsoid:l}),U=d(j,N,m,U),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z)),F=e.clone(V,F),N=e.normalize(e.cross(g,M,N),N),V=e.add(z,e.negate(e.multiplyByScalar(N,2*m,V),V),V),B=e.add(z,e.negate(e.multiplyByScalar(N,m,B),B),B),v===t.ROUNDED||v===t.BEVELED?X.push({rightPositions:u(z,F,V,v,ee)}):X.push({rightPositions:h(H,L,V,ee)})),D=e.negate(M,D)}H=q}g=l.geodeticSurfaceNormal(H,g),y[0]=e.clone(B,y[0]),y[1]=e.clone(H,y[1]),j=a.generateArc({positions:y,granularity:i,ellipsoid:l}),U=d(j,N,m,U),_&&(G.push(N.x,N.y,N.z),W.push(g.x,g.y,g.z));var te;return v===t.ROUNDED&&(te=c(U)),{positions:U,corners:X,lefts:G,normals:W,endPositions:te}};var N=new e,L=new e;return m.scaleToGeodeticHeight=function(t,r,n,o){var a=t.length,s=i(o)?o:new Array(t.length);s.length=t.length;for(var l=r,u=0;a>u;u+=3){var c=n.scaleToGeodeticSurface(e.fromArray(t,u,L),L),h=N;0!==r&&(h=n.geodeticSurfaceNormal(c,h),h=e.multiplyByScalar(h,l,h),c=e.add(c,h,c)),s[u]=c.x,s[u+1]=c.y,s[u+2]=c.z}return s},m}),r("Core/CorridorGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./CornerType","./CorridorGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e,r,i,o,a,s){var l=e.normals,u=e.tangents,c=e.binormals,h=t.normalize(t.cross(i,r,A),A);s.normal&&n.addAttribute(l,r,o,a),s.binormal&&n.addAttribute(c,i,o,a),s.tangent&&n.addAttribute(u,h,o,a)}function g(e,i,o){var s,l,u,m=e.positions,f=e.corners,v=e.endPositions,g=e.lefts,y=e.normals,C=new h,E=0,x=0,M=0;for(l=0;l<m.length;l+=2)u=m[l].length-3,E+=u,M+=2*u,x+=m[l+1].length-3;for(E+=3,x+=3,l=0;l<f.length;l++){s=f[l];var D=f[l].leftPositions;a(D)?(u=D.length,E+=u,M+=u):(u=f[l].rightPositions.length,x+=u,M+=u)}var R,O=a(v);O&&(R=v[0].length-3,E+=R,x+=R,R/=3,M+=6*R);var N,L,F,B,V,z,k=E+x,U=new Float64Array(k),G=i.normal?new Float32Array(k):void 0,W=i.tangent?new Float32Array(k):void 0,H=i.binormal?new Float32Array(k):void 0,q={normals:G,tangents:W,binormals:H},j=0,Y=k-1,X=S,Z=w,K=R/2,J=d.createTypedArray(k/3,M),Q=0;if(O){z=T,V=b;var $=v[0];for(X=t.fromArray(y,0,X),Z=t.fromArray(g,0,Z),l=0;K>l;l++)z=t.fromArray($,3*(K-1-l),z),V=t.fromArray($,3*(K+l),V),n.addAttribute(U,V,j),n.addAttribute(U,z,void 0,Y),_(q,X,Z,j,Y,i),L=j/3,B=L+1,N=(Y-2)/3,F=N-1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3}var ee=0,te=0,re=m[ee++],ie=m[ee++];U.set(re,j),U.set(ie,Y-ie.length+1),Z=t.fromArray(g,te,Z);var ne,oe;for(u=ie.length-3,l=0;u>l;l+=3)ne=o.geodeticSurfaceNormal(t.fromArray(re,l,A),A),oe=o.geodeticSurfaceNormal(t.fromArray(ie,u-l,I),I),X=t.normalize(t.add(ne,oe,X),X),_(q,X,Z,j,Y,i),L=j/3,B=L+1,N=(Y-2)/3,F=N-1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3;for(ne=o.geodeticSurfaceNormal(t.fromArray(re,u,A),A),oe=o.geodeticSurfaceNormal(t.fromArray(ie,u,I),I),X=t.normalize(t.add(ne,oe,X),X),te+=3,l=0;l<f.length;l++){var ae;s=f[l];var se,le,ue=s.leftPositions,ce=s.rightPositions,he=P,de=T,pe=b;if(X=t.fromArray(y,te,X),a(ue)){for(_(q,X,Z,void 0,Y,i),Y-=3,se=B,le=F,ae=0;ae<ue.length/3;ae++)he=t.fromArray(ue,3*ae,he),J[Q++]=se,J[Q++]=le-ae-1,J[Q++]=le-ae,n.addAttribute(U,he,void 0,Y),de=t.fromArray(U,3*(le-ae-1),de),pe=t.fromArray(U,3*se,pe),Z=t.normalize(t.subtract(de,pe,Z),Z),_(q,X,Z,void 0,Y,i),Y-=3;he=t.fromArray(U,3*se,he),de=t.subtract(t.fromArray(U,3*le,de),he,de),pe=t.subtract(t.fromArray(U,3*(le-ae),pe),he,pe),Z=t.normalize(t.add(de,pe,Z),Z),_(q,X,Z,j,void 0,i),j+=3}else{for(_(q,X,Z,j,void 0,i),j+=3,se=F,le=B,ae=0;ae<ce.length/3;ae++)he=t.fromArray(ce,3*ae,he),J[Q++]=se,J[Q++]=le+ae,J[Q++]=le+ae+1,n.addAttribute(U,he,j),de=t.fromArray(U,3*se,de),pe=t.fromArray(U,3*(le+ae),pe),Z=t.normalize(t.subtract(de,pe,Z),Z),_(q,X,Z,j,void 0,i),j+=3;he=t.fromArray(U,3*se,he),de=t.subtract(t.fromArray(U,3*(le+ae),de),he,de),pe=t.subtract(t.fromArray(U,3*le,pe),he,pe),Z=t.normalize(t.negate(t.add(pe,de,Z),Z),Z),_(q,X,Z,void 0,Y,i),Y-=3}for(re=m[ee++],ie=m[ee++],re.splice(0,3),ie.splice(ie.length-3,3),U.set(re,j),U.set(ie,Y-ie.length+1),u=ie.length-3,te+=3,Z=t.fromArray(g,te,Z),ae=0;ae<ie.length;ae+=3)ne=o.geodeticSurfaceNormal(t.fromArray(re,ae,A),A),oe=o.geodeticSurfaceNormal(t.fromArray(ie,u-ae,I),I),X=t.normalize(t.add(ne,oe,X),X),_(q,X,Z,j,Y,i),B=j/3,L=B-1,F=(Y-2)/3,N=F+1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3;j-=3,Y+=3}if(X=t.fromArray(y,y.length-3,X),_(q,X,Z,j,Y,i),O){j+=3,Y-=3,z=T,V=b;var me=v[1];for(l=0;K>l;l++)z=t.fromArray(me,3*(R-l-1),z),V=t.fromArray(me,3*l,V),n.addAttribute(U,z,void 0,Y),n.addAttribute(U,V,j),_(q,X,Z,j,Y,i),B=j/3,L=B-1,F=(Y-2)/3,N=F+1,J[Q++]=N,J[Q++]=L,J[Q++]=F,J[Q++]=F,J[Q++]=L,J[Q++]=B,j+=3,Y-=3}if(C.position=new c({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:U}),i.st){var fe,ve,_e=new Float32Array(k/3*2),ge=0;if(O){E/=3,x/=3;var ye=Math.PI/(R+1);ve=1/(E-R+1),fe=1/(x-R+1);var Ce,Ee=R/2;for(l=Ee+1;R+1>l;l++)Ce=p.PI_OVER_TWO+ye*l,_e[ge++]=fe*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce));for(l=1;x-R+1>l;l++)_e[ge++]=l*fe,_e[ge++]=0;for(l=R;l>Ee;l--)Ce=p.PI_OVER_TWO-l*ye,_e[ge++]=1-fe*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce));for(l=Ee;l>0;l--)Ce=p.PI_OVER_TWO-ye*l,_e[ge++]=1-ve*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce));for(l=E-R;l>0;l--)_e[ge++]=l*ve,_e[ge++]=1;for(l=1;Ee+1>l;l++)Ce=p.PI_OVER_TWO+ye*l,_e[ge++]=ve*(1+Math.cos(Ce)),_e[ge++]=.5*(1+Math.sin(Ce))}else{for(E/=3,x/=3,ve=1/(E-1),fe=1/(x-1),l=0;x>l;l++)_e[ge++]=l*fe,_e[ge++]=0;for(l=E;l>0;l--)_e[ge++]=(l-1)*ve,_e[ge++]=1}C.st=new c({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:_e})}return i.normal&&(C.normal=new c({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:q.normals})),i.tangent&&(C.tangent=new c({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:q.tangents})),i.binormal&&(C.binormal=new c({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:q.binormals})),{attributes:C,indices:J}}function y(e,r){if(!(r.normal||r.binormal||r.tangent||r.st))return e;var i,o,a=e.position.values;(r.normal||r.binormal)&&(i=e.normal.values,o=e.binormal.values);var s,l=e.position.values.length/18,u=3*l,c=2*l,h=2*u;if(r.normal||r.binormal||r.tangent){var d=r.normal?new Float32Array(6*u):void 0,p=r.binormal?new Float32Array(6*u):void 0,m=r.tangent?new Float32Array(6*u):void 0,f=S,v=w,_=T,g=b,y=x,C=P,E=h;for(s=0;u>s;s+=3){var A=E+h;f=t.fromArray(a,s,f),v=t.fromArray(a,s+u,v),_=t.fromArray(a,(s+3)%u,_),v=t.subtract(v,f,v),_=t.subtract(_,f,_),g=t.normalize(t.cross(v,_,g),g),r.normal&&(n.addAttribute(d,g,A),n.addAttribute(d,g,A+3),n.addAttribute(d,g,E),n.addAttribute(d,g,E+3)),(r.tangent||r.binormal)&&(C=t.fromArray(i,s,C),r.binormal&&(n.addAttribute(p,C,A),n.addAttribute(p,C,A+3),n.addAttribute(p,C,E),n.addAttribute(p,C,E+3)),r.tangent&&(y=t.normalize(t.cross(C,g,y),y),n.addAttribute(m,y,A),n.addAttribute(m,y,A+3),n.addAttribute(m,y,E),n.addAttribute(m,y,E+3))),E+=6}if(r.normal){for(d.set(i),s=0;u>s;s+=3)d[s+u]=-i[s],d[s+u+1]=-i[s+1],d[s+u+2]=-i[s+2];e.normal.values=d}else e.normal=void 0;if(r.binormal?(p.set(o),p.set(o,u),e.binormal.values=p):e.binormal=void 0,r.tangent){var I=e.tangent.values;m.set(I),m.set(I,u),e.tangent.values=m}}if(r.st){var M=e.st.values,D=new Float32Array(6*c);D.set(M),D.set(M,c);for(var R=2*c,O=0;2>O;O++){for(D[R++]=M[0],D[R++]=M[1],s=2;c>s;s+=2){var N=M[s],L=M[s+1];D[R++]=N,D[R++]=L,D[R++]=N,D[R++]=L}D[R++]=M[0],D[R++]=M[1]}e.st.values=D}return e}function C(e,t,r){r[t++]=e[0],r[t++]=e[1],r[t++]=e[2];for(var i=3;i<e.length;i+=3){var n=e[i],o=e[i+1],a=e[i+2];r[t++]=n,r[t++]=o,r[t++]=a,r[t++]=n,r[t++]=o,r[t++]=a}return r[t++]=e[0],r[t++]=e[1],r[t++]=e[2],r}function E(e,t){var r=new v({position:t.positon,normal:t.normal||t.binormal,tangent:t.tangent,binormal:t.normal||t.binormal,st:t.st}),i=e.ellipsoid,o=n.computePositions(e),a=g(o,r,i),s=e.height,l=e.extrudedHeight,u=a.attributes,c=a.indices,h=u.position.values,p=h.length,m=new Float64Array(6*p),f=new Float64Array(p);f.set(h);var _=new Float64Array(4*p);h=n.scaleToGeodeticHeight(h,s,i,h),_=C(h,0,_),f=n.scaleToGeodeticHeight(f,l,i,f),_=C(f,2*p,_),m.set(h),m.set(f,p),m.set(_,2*p),u.position.values=m,p/=3;var E,S=c.length,w=p+p,T=d.createTypedArray(m.length/3,2*S+3*w);T.set(c);var b=S;for(E=0;S>E;E+=3){var x=c[E],P=c[E+1],A=c[E+2];T[b++]=A+p,T[b++]=P+p,T[b++]=x+p}u=y(u,t);var I,M,D,R;for(E=0;w>E;E+=2)I=E+w,M=I+w,D=I+1,R=M+1,T[b++]=I,T[b++]=M,T[b++]=D,T[b++]=D,T[b++]=M,T[b++]=R;return{attributes:u,indices:T}}var S=new t,w=new t,T=new t,b=new t,x=new t,P=new t,A=new t,I=new t,M=function(e){e=o(e,o.EMPTY_OBJECT);var r=e.positions,n=e.width;this._positions=r,this._ellipsoid=l.clone(o(e.ellipsoid,l.WGS84)),this._vertexFormat=v.clone(o(e.vertexFormat,v.DEFAULT)),this._width=n,this._height=o(e.height,0),this._extrudedHeight=o(e.extrudedHeight,this._height),this._cornerType=o(e.cornerType,i.ROUNDED),this._granularity=o(e.granularity,p.RADIANS_PER_DEGREE),this._workerName="createCorridorGeometry",this.packedLength=1+r.length*t.packedLength+l.packedLength+v.packedLength+5};M.pack=function(e,r,i){i=o(i,0);var n=e._positions,a=n.length;r[i++]=a;for(var s=0;a>s;++s,i+=t.packedLength)t.pack(n[s],r,i);l.pack(e._ellipsoid,r,i),i+=l.packedLength,v.pack(e._vertexFormat,r,i),i+=v.packedLength,r[i++]=e._width,r[i++]=e._height,r[i++]=e._extrudedHeight,r[i++]=e._cornerType,r[i]=e._granularity};var D=l.clone(l.UNIT_SPHERE),R=new v,O={positions:void 0,ellipsoid:D,vertexFormat:R,width:void 0,height:void 0,extrudedHeight:void 0,cornerType:void 0,granularity:void 0};return M.unpack=function(e,r,i){r=o(r,0);for(var n=e[r++],s=new Array(n),u=0;n>u;++u,r+=t.packedLength)s[u]=t.unpack(e,r);var c=l.unpack(e,r,D);r+=l.packedLength;var h=v.unpack(e,r,R);r+=v.packedLength;var d=e[r++],p=e[r++],m=e[r++],f=e[r++],_=e[r];return a(i)?(i._positions=s,i._ellipsoid=l.clone(c,i._ellipsoid),i._vertexFormat=v.clone(h,i._vertexFormat),i._width=d,i._height=p,i._extrudedHeight=m,i._cornerType=f,i._granularity=_,i):(O.positions=s,O.width=d,O.height=p,O.extrudedHeight=m,O.cornerType=f,O.granularity=_,new M(O))},M.createGeometry=function(t){var r=t._positions,i=t._height,o=t._extrudedHeight,a=i!==o,s=m.removeDuplicates(r);if(s.length<2)return void 0;var l,c=t._ellipsoid,h=t._vertexFormat,d={ellipsoid:c,positions:s,width:t._width,cornerType:t._cornerType,granularity:t._granularity,saveAttributes:!0};if(a){var p=Math.max(i,o);o=Math.min(i,o),i=p,d.height=i,d.extrudedHeight=o,l=E(d,h)}else{var v=n.computePositions(d);l=g(v,h,c),l.attributes.position.values=n.scaleToGeodeticHeight(l.attributes.position.values,i,c,l.attributes.position.values)}var _=l.attributes,y=e.fromVertices(_.position.values,void 0,3);return h.position||(l.attributes.position.values=void 0),new u({attributes:_,indices:l.indices,primitiveType:f.TRIANGLES,boundingSphere:y})},M.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new M({positions:e._positions,width:e._width,cornerType:e._cornerType,ellipsoid:n,granularity:i,extrudedHeight:o,height:a,vertexFormat:v.POSITION_ONLY})},M}),r("Core/CorridorOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./CornerType","./CorridorGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(e,o){var s,l,u,p=[],m=e.positions,f=e.corners,v=e.endPositions,_=new h,E=0,S=0,w=0;for(l=0;l<m.length;l+=2)u=m[l].length-3,E+=u,w+=u/3*4,S+=m[l+1].length-3;for(E+=3,S+=3,l=0;l<f.length;l++){s=f[l];var T=f[l].leftPositions;a(T)?(u=T.length,E+=u,w+=u/3*2):(u=f[l].rightPositions.length,S+=u,w+=u/3*2)}var b,x=a(v);x&&(b=v[0].length-3,E+=b,S+=b,b/=3,w+=4*b);var P,A,I,M,D,R,O=E+S,N=new Float64Array(O),L=0,F=O-1,B=b/2,V=d.createTypedArray(O/3,w+4),z=0;if(V[z++]=L/3,V[z++]=(F-2)/3,x){p.push(L/3),R=g,D=y;var k=v[0];for(l=0;B>l;l++)R=t.fromArray(k,3*(B-1-l),R),D=t.fromArray(k,3*(B+l),D),n.addAttribute(N,D,L),n.addAttribute(N,R,void 0,F),A=L/3,M=A+1,P=(F-2)/3,I=P-1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3}var U=0,G=m[U++],W=m[U++];for(N.set(G,L),N.set(W,F-W.length+1),u=W.length-3,p.push(L/3,(F-2)/3),l=0;u>l;l+=3)A=L/3,M=A+1,P=(F-2)/3,I=P-1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3;for(l=0;l<f.length;l++){var H;s=f[l];var q,j=s.leftPositions,Y=s.rightPositions,X=C;if(a(j)){for(F-=3,q=I,p.push(M),H=0;H<j.length/3;H++)X=t.fromArray(j,3*H,X),V[z++]=q-H-1,V[z++]=q-H,n.addAttribute(N,X,void 0,F),F-=3;p.push(q-Math.floor(j.length/6)),o===i.BEVELED&&p.push((F-2)/3+1),L+=3}else{for(L+=3,q=M,p.push(I),H=0;H<Y.length/3;H++)X=t.fromArray(Y,3*H,X),V[z++]=q+H,V[z++]=q+H+1,n.addAttribute(N,X,L),L+=3;p.push(q+Math.floor(Y.length/6)),o===i.BEVELED&&p.push(L/3-1),F-=3}for(G=m[U++],W=m[U++],G.splice(0,3),W.splice(W.length-3,3),N.set(G,L),N.set(W,F-W.length+1),u=W.length-3,H=0;H<W.length;H+=3)M=L/3,A=M-1,I=(F-2)/3,P=I+1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3;L-=3,F+=3,p.push(L/3,(F-2)/3)}if(x){L+=3,F-=3,R=g,D=y;var Z=v[1];for(l=0;B>l;l++)R=t.fromArray(Z,3*(b-l-1),R),D=t.fromArray(Z,3*l,D),n.addAttribute(N,R,void 0,F),n.addAttribute(N,D,L),M=L/3,A=M-1,I=(F-2)/3,P=I+1,V[z++]=P,V[z++]=I,V[z++]=A,V[z++]=M,L+=3,F-=3;p.push(L/3)}else p.push(L/3,(F-2)/3);return V[z++]=L/3,V[z++]=(F-2)/3,_.position=new c({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:N}),{attributes:_,indices:V,wallIndices:p}}function _(e){var t=e.ellipsoid,r=n.computePositions(e),i=v(r,e.cornerType),o=i.wallIndices,a=e.height,s=e.extrudedHeight,l=i.attributes,u=i.indices,c=l.position.values,h=c.length,p=new Float64Array(h);p.set(c);var m=new Float64Array(2*h);c=n.scaleToGeodeticHeight(c,a,t,c),p=n.scaleToGeodeticHeight(p,s,t,p),m.set(c),m.set(p,h),l.position.values=m,h/=3;var f,_=u.length,g=d.createTypedArray(m.length/3,2*(_+o.length));g.set(u);var y=_;for(f=0;_>f;f+=2){var C=u[f],E=u[f+1];g[y++]=C+h,g[y++]=E+h}var S,w;for(f=0;f<o.length;f++)S=o[f],w=S+h,g[y++]=S,g[y++]=w;return{attributes:l,indices:g}}var g=new t,y=new t,C=new t,E=function(e){e=o(e,o.EMPTY_OBJECT);var r=e.positions,n=e.width;this._positions=r,this._ellipsoid=l.clone(o(e.ellipsoid,l.WGS84)),this._width=n,this._height=o(e.height,0),this._extrudedHeight=o(e.extrudedHeight,this._height),this._cornerType=o(e.cornerType,i.ROUNDED),this._granularity=o(e.granularity,p.RADIANS_PER_DEGREE),this._workerName="createCorridorOutlineGeometry",this.packedLength=1+r.length*t.packedLength+l.packedLength+5};E.pack=function(e,r,i){i=o(i,0);var n=e._positions,a=n.length;r[i++]=a;for(var s=0;a>s;++s,i+=t.packedLength)t.pack(n[s],r,i);l.pack(e._ellipsoid,r,i),i+=l.packedLength,r[i++]=e._width,r[i++]=e._height,r[i++]=e._extrudedHeight,r[i++]=e._cornerType,r[i]=e._granularity};var S=l.clone(l.UNIT_SPHERE),w={positions:void 0,ellipsoid:S,width:void 0,height:void 0,extrudedHeight:void 0,cornerType:void 0,granularity:void 0};return E.unpack=function(e,r,i){r=o(r,0);for(var n=e[r++],s=new Array(n),u=0;n>u;++u,r+=t.packedLength)s[u]=t.unpack(e,r);var c=l.unpack(e,r,S);r+=l.packedLength;var h=e[r++],d=e[r++],p=e[r++],m=e[r++],f=e[r];return a(i)?(i._positions=s,i._ellipsoid=l.clone(c,i._ellipsoid),i._width=h,i._height=d,i._extrudedHeight=p,i._cornerType=m,i._granularity=f,i):(w.positions=s, -w.width=h,w.height=d,w.extrudedHeight=p,w.cornerType=m,w.granularity=f,new E(w))},E.createGeometry=function(t){var r=t._positions,i=t._height,o=t._extrudedHeight,a=i!==o,s=m.removeDuplicates(r);if(s.length<2)return void 0;var l,c=t._ellipsoid,h={ellipsoid:c,positions:s,width:t._width,cornerType:t._cornerType,granularity:t._granularity,saveAttributes:!1};if(a){var d=Math.max(i,o);o=Math.min(i,o),i=d,h.height=i,h.extrudedHeight=o,l=_(h)}else{var p=n.computePositions(h);l=v(p,h.cornerType),l.attributes.position.values=n.scaleToGeodeticHeight(l.attributes.position.values,i,c,l.attributes.position.values)}var g=l.attributes,y=e.fromVertices(g.position.values,void 0,3);return new u({attributes:g,indices:l.indices,primitiveType:f.LINES,boundingSphere:y})},E}),r("Core/CylinderGeometryLibrary",["./Math"],function(e){"use strict";var t={};return t.computePositions=function(t,r,i,n,o){var a,s=.5*t,l=-s,u=n+n,c=o?2*u:u,h=new Float64Array(3*c),d=0,p=0,m=o?3*u:0,f=o?3*(u+n):3*n;for(a=0;n>a;a++){var v=a/n*e.TWO_PI,_=Math.cos(v),g=Math.sin(v),y=_*i,C=g*i,E=_*r,S=g*r;h[p+m]=y,h[p+m+1]=C,h[p+m+2]=l,h[p+f]=E,h[p+f+1]=S,h[p+f+2]=s,p+=3,o&&(h[d++]=y,h[d++]=C,h[d++]=l,h[d++]=E,h[d++]=S,h[d++]=s)}return h},t}),r("Core/CylinderGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CylinderGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new t,v=new r,_=new r,g=new r,y=new r,C=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.length,r=e.topRadius,i=e.bottomRadius,n=o(e.vertexFormat,m.DEFAULT),a=o(e.slices,128);this._length=t,this._topRadius=r,this._bottomRadius=i,this._vertexFormat=m.clone(n),this._slices=a,this._workerName="createCylinderGeometry"};C.packedLength=m.packedLength+4,C.pack=function(e,t,r){r=o(r,0),m.pack(e._vertexFormat,t,r),r+=m.packedLength,t[r++]=e._length,t[r++]=e._topRadius,t[r++]=e._bottomRadius,t[r]=e._slices};var E=new m,S={vertexFormat:E,length:void 0,topRadius:void 0,bottomRadius:void 0,slices:void 0};return C.unpack=function(e,t,r){t=o(t,0);var i=m.unpack(e,t,E);t+=m.packedLength;var n=e[t++],s=e[t++],l=e[t++],u=e[t];return a(r)?(r._vertexFormat=m.clone(i,r._vertexFormat),r._length=n,r._topRadius=s,r._bottomRadius=l,r._slices=u,r):(S.length=n,S.topRadius=s,S.bottomRadius=l,S.slices=u,new C(S))},C.createGeometry=function(o){var a,s=o._length,m=o._topRadius,C=o._bottomRadius,E=o._vertexFormat,S=o._slices,w=S+S,T=S+w,b=w+w,x=n.computePositions(s,m,C,S,!0),P=E.st?new Float32Array(2*b):void 0,A=E.normal?new Float32Array(3*b):void 0,I=E.tangent?new Float32Array(3*b):void 0,M=E.binormal?new Float32Array(3*b):void 0,D=E.normal||E.tangent||E.binormal;if(D){var R=E.tangent||E.binormal,O=0,N=0,L=0,F=v;F.z=0;var B=g,V=_;for(a=0;S>a;a++){var z=a/S*d.TWO_PI,k=Math.cos(z),U=Math.sin(z);D&&(F.x=k,F.y=U,R&&(B=r.normalize(r.cross(r.UNIT_Z,F,B),B)),E.normal&&(A[O++]=k,A[O++]=U,A[O++]=0,A[O++]=k,A[O++]=U,A[O++]=0),E.tangent&&(I[N++]=B.x,I[N++]=B.y,I[N++]=B.z,I[N++]=B.x,I[N++]=B.y,I[N++]=B.z),E.binormal&&(V=r.normalize(r.cross(F,B,V),V),M[L++]=V.x,M[L++]=V.y,M[L++]=V.z,M[L++]=V.x,M[L++]=V.y,M[L++]=V.z))}for(a=0;S>a;a++)E.normal&&(A[O++]=0,A[O++]=0,A[O++]=-1),E.tangent&&(I[N++]=1,I[N++]=0,I[N++]=0),E.binormal&&(M[L++]=0,M[L++]=-1,M[L++]=0);for(a=0;S>a;a++)E.normal&&(A[O++]=0,A[O++]=0,A[O++]=1),E.tangent&&(I[N++]=1,I[N++]=0,I[N++]=0),E.binormal&&(M[L++]=0,M[L++]=1,M[L++]=0)}var G=12*S-12,W=h.createTypedArray(b,G),H=0,q=0;for(a=0;S-1>a;a++)W[H++]=q,W[H++]=q+2,W[H++]=q+3,W[H++]=q,W[H++]=q+3,W[H++]=q+1,q+=2;for(W[H++]=w-2,W[H++]=0,W[H++]=1,W[H++]=w-2,W[H++]=1,W[H++]=w-1,a=1;S-1>a;a++)W[H++]=w+a+1,W[H++]=w+a,W[H++]=w;for(a=1;S-1>a;a++)W[H++]=T,W[H++]=T+a,W[H++]=T+a+1;var j=0;if(E.st){var Y=Math.max(m,C);for(a=0;b>a;a++){var X=r.fromArray(x,3*a,y);P[j++]=(X.x+Y)/(2*Y),P[j++]=(X.y+Y)/(2*Y)}}var Z=new c;E.position&&(Z.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:x})),E.normal&&(Z.normal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:A})),E.tangent&&(Z.tangent=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:I})),E.binormal&&(Z.binormal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:M})),E.st&&(Z.st=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:P})),f.x=.5*s,f.y=Math.max(C,m);var K=new e(r.ZERO,t.magnitude(f));return new l({attributes:Z,indices:W,primitiveType:p.TRIANGLES,boundingSphere:K})},C}),r("Core/CylinderOutlineGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CylinderGeometryLibrary","./defaultValue","./defined","./DeveloperError","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";var p=new t,m=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.length,r=e.topRadius,i=e.bottomRadius,n=o(e.slices,128),a=Math.max(o(e.numberOfVerticalLines,16),0);this._length=t,this._topRadius=r,this._bottomRadius=i,this._slices=n,this._numberOfVerticalLines=a,this._workerName="createCylinderOutlineGeometry"};m.packedLength=5,m.pack=function(e,t,r){r=o(r,0),t[r++]=e._length,t[r++]=e._topRadius,t[r++]=e._bottomRadius,t[r++]=e._slices,t[r]=e._numberOfVerticalLines};var f={length:void 0,topRadius:void 0,bottomRadius:void 0,slices:void 0,numberOfVerticalLines:void 0};return m.unpack=function(e,t,r){t=o(t,0);var i=e[t++],n=e[t++],s=e[t++],l=e[t++],u=e[t];return a(r)?(r._length=i,r._topRadius=n,r._bottomRadius=s,r._slices=l,r._numberOfVerticalLines=u,r):(f.length=i,f.topRadius=n,f.bottomRadius=s,f.slices=l,f.numberOfVerticalLines=u,new m(f))},m.createGeometry=function(o){var a,s=o._length,m=o._topRadius,f=o._bottomRadius,v=o._slices,_=o._numberOfVerticalLines,g=2*v,y=n.computePositions(s,m,f,v,!1),C=2*v;if(_>0){var E=Math.min(_,v);a=Math.round(v/E),C+=E}for(var S=h.createTypedArray(g,2*C),w=0,T=0;v-1>T;T++)S[w++]=T,S[w++]=T+1,S[w++]=T+v,S[w++]=T+1+v;if(S[w++]=v-1,S[w++]=0,S[w++]=v+v-1,S[w++]=v,_>0)for(T=0;v>T;T+=a)S[w++]=T,S[w++]=T+v;var b=new c;b.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:y}),p.x=.5*s,p.y=Math.max(f,m);var x=new e(r.ZERO,t.magnitude(p));return new l({attributes:b,indices:S,primitiveType:d.LINES,boundingSphere:x})},m}),r("Core/DefaultProxy",[],function(){"use strict";var e=function(e){this.proxy=e};return e.prototype.getURL=function(e){return this.proxy+"?"+encodeURIComponent(e)},e}),r("ThirdParty/Tween",[],function(){void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var e=e||function(){var e=[];return{REVISION:"13",getAll:function(){return e},removeAll:function(){e=[]},add:function(t){e.push(t)},remove:function(t){var r=e.indexOf(t);-1!==r&&e.splice(r,1)},update:function(t){if(0===e.length)return!1;var r=0;for(t=void 0!==t?t:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();r<e.length;)e[r].update(t)?r++:e.splice(r,1);return!0}}}();return e.Tween=function(t){var r=t,i={},n={},o={},a=1e3,s=0,l=!1,u=!1,c=!1,h=0,d=null,p=e.Easing.Linear.None,m=e.Interpolation.Linear,f=[],v=null,_=!1,g=null,y=null,C=null;for(var E in t)i[E]=parseFloat(t[E],10);this.to=function(e,t){return void 0!==t&&(a=t),n=e,this},this.start=function(t){e.add(this),u=!0,_=!1,d=void 0!==t?t:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now(),d+=h;for(var a in n){if(n[a]instanceof Array){if(0===n[a].length)continue;n[a]=[r[a]].concat(n[a])}i[a]=r[a],i[a]instanceof Array==!1&&(i[a]*=1),o[a]=i[a]||0}return this},this.stop=function(){return u?(e.remove(this),u=!1,null!==C&&C.call(r),this.stopChainedTweens(),this):this},this.stopChainedTweens=function(){for(var e=0,t=f.length;t>e;e++)f[e].stop()},this.delay=function(e){return h=e,this},this.repeat=function(e){return s=e,this},this.yoyo=function(e){return l=e,this},this.easing=function(e){return p=e,this},this.interpolation=function(e){return m=e,this},this.chain=function(){return f=arguments,this},this.onStart=function(e){return v=e,this},this.onUpdate=function(e){return g=e,this},this.onComplete=function(e){return y=e,this},this.onStop=function(e){return C=e,this},this.update=function(e){var t;if(d>e)return!0;_===!1&&(null!==v&&v.call(r),_=!0);var u=(e-d)/a;u=u>1?1:u;var C=p(u);for(t in n){var E=i[t]||0,S=n[t];S instanceof Array?r[t]=m(S,C):("string"==typeof S&&(S=E+parseFloat(S,10)),"number"==typeof S&&(r[t]=E+(S-E)*C))}if(null!==g&&g.call(r,C),1==u){if(s>0){isFinite(s)&&s--;for(t in o){if("string"==typeof n[t]&&(o[t]=o[t]+parseFloat(n[t],10)),l){var w=o[t];o[t]=n[t],n[t]=w}i[t]=o[t]}return l&&(c=!c),d=e+h,!0}null!==y&&y.call(r);for(var T=0,b=f.length;b>T;T++)f[T].start(e);return!1}return!0}},e.Easing={Linear:{None:function(e){return e}},Quadratic:{In:function(e){return e*e},Out:function(e){return e*(2-e)},InOut:function(e){return(e*=2)<1?.5*e*e:-.5*(--e*(e-2)-1)}},Cubic:{In:function(e){return e*e*e},Out:function(e){return--e*e*e+1},InOut:function(e){return(e*=2)<1?.5*e*e*e:.5*((e-=2)*e*e+2)}},Quartic:{In:function(e){return e*e*e*e},Out:function(e){return 1- --e*e*e*e},InOut:function(e){return(e*=2)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2)}},Quintic:{In:function(e){return e*e*e*e*e},Out:function(e){return--e*e*e*e*e+1},InOut:function(e){return(e*=2)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2)}},Sinusoidal:{In:function(e){return 1-Math.cos(e*Math.PI/2)},Out:function(e){return Math.sin(e*Math.PI/2)},InOut:function(e){return.5*(1-Math.cos(Math.PI*e))}},Exponential:{In:function(e){return 0===e?0:Math.pow(1024,e-1)},Out:function(e){return 1===e?1:1-Math.pow(2,-10*e)},InOut:function(e){return 0===e?0:1===e?1:(e*=2)<1?.5*Math.pow(1024,e-1):.5*(-Math.pow(2,-10*(e-1))+2)}},Circular:{In:function(e){return 1-Math.sqrt(1-e*e)},Out:function(e){return Math.sqrt(1- --e*e)},InOut:function(e){return(e*=2)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1)}},Elastic:{In:function(e){var t,r=.1,i=.4;return 0===e?0:1===e?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),-(r*Math.pow(2,10*(e-=1))*Math.sin(2*(e-t)*Math.PI/i)))},Out:function(e){var t,r=.1,i=.4;return 0===e?0:1===e?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),r*Math.pow(2,-10*e)*Math.sin(2*(e-t)*Math.PI/i)+1)},InOut:function(e){var t,r=.1,i=.4;return 0===e?0:1===e?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),(e*=2)<1?-.5*r*Math.pow(2,10*(e-=1))*Math.sin(2*(e-t)*Math.PI/i):r*Math.pow(2,-10*(e-=1))*Math.sin(2*(e-t)*Math.PI/i)*.5+1)}},Back:{In:function(e){var t=1.70158;return e*e*((t+1)*e-t)},Out:function(e){var t=1.70158;return--e*e*((t+1)*e+t)+1},InOut:function(e){var t=2.5949095;return(e*=2)<1?.5*e*e*((t+1)*e-t):.5*((e-=2)*e*((t+1)*e+t)+2)}},Bounce:{In:function(t){return 1-e.Easing.Bounce.Out(1-t)},Out:function(e){return 1/2.75>e?7.5625*e*e:2/2.75>e?7.5625*(e-=1.5/2.75)*e+.75:2.5/2.75>e?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},InOut:function(t){return.5>t?.5*e.Easing.Bounce.In(2*t):.5*e.Easing.Bounce.Out(2*t-1)+.5}}},e.Interpolation={Linear:function(t,r){var i=t.length-1,n=i*r,o=Math.floor(n),a=e.Interpolation.Utils.Linear;return 0>r?a(t[0],t[1],n):r>1?a(t[i],t[i-1],i-n):a(t[o],t[o+1>i?i:o+1],n-o)},Bezier:function(t,r){var i,n=0,o=t.length-1,a=Math.pow,s=e.Interpolation.Utils.Bernstein;for(i=0;o>=i;i++)n+=a(1-r,o-i)*a(r,i)*t[i]*s(o,i);return n},CatmullRom:function(t,r){var i=t.length-1,n=i*r,o=Math.floor(n),a=e.Interpolation.Utils.CatmullRom;return t[0]===t[i]?(0>r&&(o=Math.floor(n=i*(1+r))),a(t[(o-1+i)%i],t[o],t[(o+1)%i],t[(o+2)%i],n-o)):0>r?t[0]-(a(t[0],t[0],t[1],t[1],-n)-t[0]):r>1?t[i]-(a(t[i],t[i],t[i-1],t[i-1],n-i)-t[i]):a(t[o?o-1:0],t[o],t[o+1>i?i:o+1],t[o+2>i?i:o+2],n-o)},Utils:{Linear:function(e,t,r){return(t-e)*r+e},Bernstein:function(t,r){var i=e.Interpolation.Utils.Factorial;return i(t)/i(r)/i(t-r)},Factorial:function(){var e=[1];return function(t){var r,i=1;if(e[t])return e[t];for(r=t;r>1;r--)i*=r;return e[t]=i}}(),CatmullRom:function(e,t,r,i,n){var o=.5*(r-e),a=.5*(i-t),s=n*n,l=n*s;return(2*t-2*r+o+a)*l+(-3*t+3*r-2*o-a)*s+o*n+t}}},e}),r("Core/EasingFunction",["../ThirdParty/Tween","./freezeObject"],function(e,t){"use strict";var r={LINEAR_NONE:e.Easing.Linear.None,QUADRACTIC_IN:e.Easing.Quadratic.In,QUADRACTIC_OUT:e.Easing.Quadratic.Out,QUADRACTIC_IN_OUT:e.Easing.Quadratic.InOut,CUBIC_IN:e.Easing.Cubic.In,CUBIC_OUT:e.Easing.Cubic.Out,CUBIC_IN_OUT:e.Easing.Cubic.InOut,QUARTIC_IN:e.Easing.Quartic.In,QUARTIC_OUT:e.Easing.Quartic.Out,QUARTIC_IN_OUT:e.Easing.Quartic.InOut,QUINTIC_IN:e.Easing.Quintic.In,QUINTIC_OUT:e.Easing.Quintic.Out,QUINTIC_IN_OUT:e.Easing.Quintic.InOut,SINUSOIDAL_IN:e.Easing.Sinusoidal.In,SINUSOIDAL_OUT:e.Easing.Sinusoidal.Out,SINUSOIDAL_IN_OUT:e.Easing.Sinusoidal.InOut,EXPONENTIAL_IN:e.Easing.Exponential.In,EXPONENTIAL_OUT:e.Easing.Exponential.Out,EXPONENTIAL_IN_OUT:e.Easing.Exponential.InOut,CIRCULAR_IN:e.Easing.Circular.In,CIRCULAR_OUT:e.Easing.Circular.Out,CIRCULAR_IN_OUT:e.Easing.Circular.InOut,ELASTIC_IN:e.Easing.Elastic.In,ELASTIC_OUT:e.Easing.Elastic.Out,ELASTIC_IN_OUT:e.Easing.Elastic.InOut,BACK_IN:e.Easing.Back.In,BACK_OUT:e.Easing.Back.Out,BACK_IN_OUT:e.Easing.Back.InOut,BOUNCE_IN:e.Easing.Bounce.In,BOUNCE_OUT:e.Easing.Bounce.Out,BOUNCE_IN_OUT:e.Easing.Bounce.InOut};return t(r)}),r("Core/EllipsoidGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new r,v=new r,_=new r,g=new r,y=new r,C=new r(1,1,1),E=Math.cos,S=Math.sin,w=function(e){e=n(e,n.EMPTY_OBJECT);var t=n(e.radii,C),i=n(e.stackPartitions,64),o=n(e.slicePartitions,64),a=n(e.vertexFormat,m.DEFAULT);this._radii=r.clone(t),this._stackPartitions=i,this._slicePartitions=o,this._vertexFormat=m.clone(a),this._workerName="createEllipsoidGeometry"};w.packedLength=r.packedLength+m.packedLength+2,w.pack=function(e,t,i){i=n(i,0),r.pack(e._radii,t,i),i+=r.packedLength,m.pack(e._vertexFormat,t,i),i+=m.packedLength,t[i++]=e._stackPartitions,t[i]=e._slicePartitions};var T=new r,b=new m,x={radii:T,vertexFormat:b,stackPartitions:void 0,slicePartitions:void 0};return w.unpack=function(e,t,i){t=n(t,0);var a=r.unpack(e,t,T);t+=r.packedLength;var s=m.unpack(e,t,b);t+=m.packedLength;var l=e[t++],u=e[t];return o(i)?(i._radii=r.clone(a,i._radii),i._vertexFormat=m.clone(s,i._vertexFormat),i._stackPartitions=l,i._slicePartitions=u,i):(x.stackPartitions=l,x.slicePartitions=u,new w(x))},w.createGeometry=function(n){var o,a,m=n._radii,C=s.fromCartesian3(m),w=n._vertexFormat,T=n._slicePartitions+1,b=n._stackPartitions+1,x=b*T,P=new Float64Array(3*x),A=6*(T-1)*(b-1),I=h.createTypedArray(x,A),M=w.normal?new Float32Array(3*x):void 0,D=w.tangent?new Float32Array(3*x):void 0,R=w.binormal?new Float32Array(3*x):void 0,O=w.st?new Float32Array(2*x):void 0,N=new Array(T),L=new Array(T),F=0;for(o=0;T>o;o++){var B=d.TWO_PI*o/(T-1);N[o]=E(B),L[o]=S(B),P[F++]=0,P[F++]=0,P[F++]=m.z}for(o=1;b-1>o;o++){var V=Math.PI*o/(b-1),z=S(V),k=m.x*z,U=m.y*z,G=m.z*E(V);for(a=0;T>a;a++)P[F++]=N[a]*k,P[F++]=L[a]*U,P[F++]=G}for(o=0;T>o;o++)P[F++]=0,P[F++]=0,P[F++]=-m.z;var W=new c;w.position&&(W.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:P}));var H=0,q=0,j=0,Y=0;if(w.st||w.normal||w.tangent||w.binormal){for(o=0;x>o;o++){var X=r.fromArray(P,3*o,f),Z=C.geodeticSurfaceNormal(X,v);if(w.st){var K=t.negate(Z,y);t.magnitude(K)<d.EPSILON6&&(F=3*(o+T*Math.floor(.5*b)),F>P.length&&(F=3*(o-T*Math.floor(.5*b))),r.fromArray(P,F,K),C.geodeticSurfaceNormal(K,K),t.negate(K,K)),O[H++]=Math.atan2(K.y,K.x)/d.TWO_PI+.5,O[H++]=Math.asin(Z.z)/Math.PI+.5}if(w.normal&&(M[q++]=Z.x,M[q++]=Z.y,M[q++]=Z.z),w.tangent||w.binormal){var J=_;if(T>o||o>x-T-1?(r.cross(r.UNIT_X,Z,J),r.normalize(J,J)):(r.cross(r.UNIT_Z,Z,J),r.normalize(J,J)),w.tangent&&(D[j++]=J.x,D[j++]=J.y,D[j++]=J.z),w.binormal){var Q=r.cross(Z,J,g);r.normalize(Q,Q),R[Y++]=Q.x,R[Y++]=Q.y,R[Y++]=Q.z}}}w.st&&(W.st=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:O})),w.normal&&(W.normal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:M})),w.tangent&&(W.tangent=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:D})),w.binormal&&(W.binormal=new u({componentDatatype:i.FLOAT,componentsPerAttribute:3,values:R}))}for(F=0,o=0;b>o;o++){var $=o*T,ee=(o+1)*T;for(a=0;T-1>a;a++)I[F++]=ee+a,I[F++]=ee+a+1,I[F++]=$+a+1,I[F++]=ee+a,I[F++]=$+a+1,I[F++]=$+a}return new l({attributes:W,indices:I,primitiveType:p.TRIANGLES,boundingSphere:e.fromEllipsoid(C)})},w}),r("Core/EllipsoidOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";var p=new t(1,1,1),m=Math.cos,f=Math.sin,v=function(e){e=i(e,i.EMPTY_OBJECT);var r=i(e.radii,p),n=i(e.stackPartitions,10),o=i(e.slicePartitions,8),a=i(e.subdivisions,128);this._radii=t.clone(r),this._stackPartitions=n,this._slicePartitions=o,this._subdivisions=a,this._workerName="createEllipsoidOutlineGeometry"};v.packedLength=t.packedLength+3,v.pack=function(e,r,n){n=i(n,0),t.pack(e._radii,r,n),n+=t.packedLength,r[n++]=e._stackPartitions,r[n++]=e._slicePartitions,r[n]=e._subdivisions};var _=new t,g={radii:_,stackPartitions:void 0,slicePartitions:void 0,subdivisions:void 0};return v.unpack=function(e,r,o){r=i(r,0);var a=t.unpack(e,r,_);r+=t.packedLength;var s=e[r++],l=e[r++],u=e[r++];return n(o)?(o._radii=t.clone(a,o._radii),o._stackPartitions=s,o._slicePartitions=l,o._subdivisions=u,o):(g.stackPartitions=s,g.slicePartitions=l,g.subdivisions=u,new v(g))},v.createGeometry=function(t){var i,n,o,p,v,_,g=t._radii,y=a.fromCartesian3(g),C=t._stackPartitions,E=t._slicePartitions,S=t._subdivisions,w=S*(C+E-1),T=w-E+2,b=new Float64Array(3*T),x=c.createTypedArray(T,2*w),P=0,A=new Array(S),I=new Array(S);for(i=0;S>i;i++)o=h.TWO_PI*i/S,A[i]=m(o),I[i]=f(o);for(i=1;C>i;i++)for(p=Math.PI*i/C,v=m(p),_=f(p),n=0;S>n;n++)b[P++]=g.x*A[n]*_,b[P++]=g.y*I[n]*_,b[P++]=g.z*v;for(A.length=E,I.length=E,i=0;E>i;i++)o=h.TWO_PI*i/E,A[i]=m(o),I[i]=f(o);for(b[P++]=0,b[P++]=0,b[P++]=g.z,i=1;S>i;i++)for(p=Math.PI*i/S,v=m(p),_=f(p),n=0;E>n;n++)b[P++]=g.x*A[n]*_,b[P++]=g.y*I[n]*_,b[P++]=g.z*v;for(b[P++]=0,b[P++]=0,b[P++]=-g.z,P=0,i=0;C-1>i;++i){var M=i*S;for(n=0;S-1>n;++n)x[P++]=M+n,x[P++]=M+n+1;x[P++]=M+S-1,x[P++]=M}var D=S*(C-1);for(n=1;E+1>n;++n)x[P++]=D,x[P++]=D+n;for(i=0;S-2>i;++i){var R=i*E+1+D,O=(i+1)*E+1+D;for(n=0;E-1>n;++n)x[P++]=O+n,x[P++]=R+n;x[P++]=O+E-1,x[P++]=R+E-1}var N=b.length/3-1;for(n=N-1;n>N-E-1;--n)x[P++]=N,x[P++]=n;var L=new u({position:new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:b})});return new s({attributes:L,indices:x,primitiveType:d.LINES,boundingSphere:e.fromEllipsoid(y)})},v}),r("Core/EllipsoidTerrainProvider",["../ThirdParty/when","./defaultValue","./defined","./defineProperties","./Ellipsoid","./Event","./GeographicTilingScheme","./HeightmapTerrainData","./TerrainProvider"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(i){i=t(i,{}),this._tilingScheme=i.tilingScheme,r(this._tilingScheme)||(this._tilingScheme=new a({ellipsoid:t(i.ellipsoid,n.WGS84)})),this._levelZeroMaximumGeometricError=l.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid,64,this._tilingScheme.getNumberOfXTilesAtLevel(0));var u=16,c=16;this._terrainData=new s({buffer:new Uint8Array(u*c),width:16,height:16}),this._errorEvent=new o,this._readyPromise=e.resolve(!0)};return i(u.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return void 0}},tilingScheme:{get:function(){return this._tilingScheme}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},hasWaterMask:{get:function(){return!1}},hasVertexNormals:{get:function(){return!1}}}),u.prototype.requestTileGeometry=function(e,t,r,i){return this._terrainData},u.prototype.getLevelMaximumGeometricError=function(e){return this._levelZeroMaximumGeometricError/(1<<e)},u.prototype.getTileDataAvailable=function(e,t,r){return void 0},u}),r("Core/EllipsoidalOccluder",["./BoundingSphere","./Cartesian3","./defaultValue","./defined","./defineProperties","./DeveloperError","./Rectangle"],function(e,t,r,i,n,o,a){"use strict";function s(e,r,i){var n=e.transformPositionToScaledSpace(r,m),o=t.magnitudeSquared(n),a=Math.sqrt(o),s=t.divideByScalar(n,a,f);o=Math.max(1,o),a=Math.max(1,a);var l=t.dot(s,i),u=t.magnitude(t.cross(s,i,s)),c=1/a,h=Math.sqrt(o-1)*c;return 1/(l*c-u*h)}function l(e,r,i){return 0>=r||r===1/0||r!==r?void 0:t.multiplyByScalar(e,r,i)}function u(e,r){return e.transformPositionToScaledSpace(r,v),t.normalize(v,v)}var c=function(e,r){this._ellipsoid=e,this._cameraPosition=new t,this._cameraPositionInScaledSpace=new t,this._distanceToLimbInScaledSpaceSquared=0,i(r)&&(this.cameraPosition=r)};n(c.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},cameraPosition:{get:function(){return this._cameraPosition},set:function(e){var r=this._ellipsoid,i=r.transformPositionToScaledSpace(e,this._cameraPositionInScaledSpace),n=t.magnitudeSquared(i)-1;t.clone(e,this._cameraPosition),this._cameraPositionInScaledSpace=i,this._distanceToLimbInScaledSpaceSquared=n}}});var h=new t;c.prototype.isPointVisible=function(e){var t=this._ellipsoid,r=t.transformPositionToScaledSpace(e,h);return this.isScaledSpacePointVisible(r)},c.prototype.isScaledSpacePointVisible=function(e){if(this._distanceToLimbInScaledSpaceSquared<0)return!0;var r=this._cameraPositionInScaledSpace,i=this._distanceToLimbInScaledSpaceSquared,n=t.subtract(e,r,h),o=-t.dot(n,r),a=o>i&&o*o/t.magnitudeSquared(n)>i;return!a},c.prototype.computeHorizonCullingPoint=function(e,r,n){i(n)||(n=new t);for(var o=this._ellipsoid,a=u(o,e),c=0,h=0,d=r.length;d>h;++h){var p=r[h],m=s(o,p,a);c=Math.max(c,m)}return l(a,c,n)};var d=new t;c.prototype.computeHorizonCullingPointFromVertices=function(e,n,o,a,c){i(c)||(c=new t),a=r(a,t.ZERO);for(var h=this._ellipsoid,p=u(h,e),m=0,f=0,v=n.length;v>f;f+=o){d.x=n[f]+a.x,d.y=n[f+1]+a.y,d.z=n[f+2]+a.z;var _=s(h,d,p);m=Math.max(m,_)}return l(p,m,c)};var p=[];c.prototype.computeHorizonCullingPointFromRectangle=function(r,i,n){var o=a.subsample(r,i,0,p),s=e.fromPoints(o);return t.magnitude(s.center)<.1*i.minimumRadius?void 0:this.computeHorizonCullingPoint(s.center,o,n)};var m=new t,f=new t,v=new t;return c}),r("Core/EventHelper",["./defined","./DeveloperError"],function(e,t){"use strict";var r=function(){this._removalFunctions=[]};return r.prototype.add=function(e,t,r){var i=e.addEventListener(t,r);this._removalFunctions.push(i);var n=this;return function(){i();var e=n._removalFunctions;e.splice(e.indexOf(i),1)}},r.prototype.removeAll=function(){for(var e=this._removalFunctions,t=0,r=e.length;r>t;++t)e[t]();e.length=0},r}),r("Core/ExtrapolationType",["./freezeObject"],function(e){"use strict";var t={NONE:0,HOLD:1,EXTRAPOLATE:2};return e(t)}),r("Core/GeometryInstanceAttribute",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t){t=e(t,e.EMPTY_OBJECT),this.componentDatatype=t.componentDatatype,this.componentsPerAttribute=t.componentsPerAttribute,this.normalize=e(t.normalize,!1),this.value=t.value};return i}),r("Core/HeadingPitchRange",["./defaultValue","./defined"],function(e,t){"use strict";var r=function(t,r,i){this.heading=e(t,0),this.pitch=e(r,0),this.range=e(i,0)};return r.clone=function(e,i){return t(e)?(t(i)||(i=new r),i.heading=e.heading,i.pitch=e.pitch,i.range=e.range,i):void 0},r}),r("Core/HermitePolynomialApproximation",["./defaultValue","./defined","./DeveloperError","./Math"],function(e,t,r,i){"use strict";function n(e,t,r,i,o,a){var s,l,u,c=0;if(i>0){for(l=0;o>l;l++){for(s=!1,u=0;u<a.length&&!s;u++)l===a[u]&&(s=!0);s||(a.push(l),c+=n(e,t,r,i-1,o,a),a.splice(a.length-1,1))}return c}for(c=1,l=0;o>l;l++){for(s=!1,u=0;u<a.length&&!s;u++)l===a[u]&&(s=!0);s||(c*=e-r[t[l]])}return c}function o(e,t,r,n,o,a){for(var s,l,u=-1,c=t.length,h=c*(c+1)/2,d=0;o>d;d++){var p=Math.floor(d*h);for(s=0;c>s;s++)l=t[s]*o*(a+1)+d,e[p+s]=n[l];for(var m=1;c>m;m++){var f=0,v=Math.floor(m*(1-m)/2)+c*m,_=!1;for(s=0;c-m>s;s++){var g,y,C=r[t[s]],E=r[t[s+m]];if(0>=E-C)l=t[s]*o*(a+1)+o*m+d,g=n[l],y=g/i.factorial(m),e[p+v+f]=y,f++;else{var S=Math.floor((m-1)*(2-m)/2)+c*(m-1);g=e[p+S+s+1]-e[p+S+s],y=g/(E-C),e[p+v+f]=y,f++}_=_||0!==g}_&&(u=Math.max(u,m))}}return u}var a=i.factorial,s={type:"Hermite"};s.getRequiredDataPoints=function(t,r){return r=e(r,0),Math.max(Math.floor((t+1)/(r+1)),2)},s.interpolateOrderZero=function(e,r,i,o,s){t(s)||(s=new Array(o));var l,u,c,h,d,p,m=r.length,f=new Array(o);for(l=0;o>l;l++){s[l]=0;var v=new Array(m);for(f[l]=v,u=0;m>u;u++)v[u]=[]}var _=m,g=new Array(_);for(l=0;_>l;l++)g[l]=l;var y=m-1;for(h=0;o>h;h++){for(u=0;_>u;u++)p=g[u]*o+h,f[h][0].push(i[p]);for(l=1;_>l;l++){var C=!1;for(u=0;_-l>u;u++){var E,S=r[g[u]],w=r[g[u+l]];0>=w-S?(p=g[u]*o+o*l+h,E=i[p],f[h][l].push(E/a(l))):(E=f[h][l-1][u+1]-f[h][l-1][u],f[h][l].push(E/(w-S))),C=C||0!==E}C||(y=l-1)}}for(c=0,d=0;d>=c;c++)for(l=c;y>=l;l++){var T=n(e,g,r,c,l,[]);for(h=0;o>h;h++){var b=f[h][l][0];s[h+c*o]+=b*T}}return s};var l=[];return s.interpolate=function(e,r,i,a,s,u,c){var h=a*(u+1);t(c)||(c=new Array(h));for(var d=0;h>d;d++)c[d]=0;for(var p=r.length,m=new Array(p*(s+1)),f=0;p>f;f++)for(var v=0;s+1>v;v++)m[f*(s+1)+v]=f;for(var _=m.length,g=l,y=o(g,m,r,i,a,s),C=[],E=_*(_+1)/2,S=Math.min(y,u),w=0;S>=w;w++)for(f=w;y>=f;f++){C.length=0;for(var T=n(e,m,r,w,f,C),b=Math.floor(f*(1-f)/2)+_*f,x=0;a>x;x++){var P=Math.floor(x*E),A=g[P+b];c[x+w*a]+=A*T}}return c},s}),r("Core/IauOrientationParameters",[],function(){"use strict";var e=function(e,t,r,i){this.rightAscension=e,this.declination=t,this.rotation=r,this.rotationRate=i};return e}),r("Core/Iau2000Orientation",["./defined","./IauOrientationParameters","./JulianDate","./Math","./TimeConstants"],function(e,t,r,i,n){"use strict";var o={},a=32.184,s=2451545,l=-.0529921,u=-.1059842,c=13.0120009,h=13.3407154,d=.9856003,p=26.4057084,m=13.064993,f=.3287146,v=1.7484877,_=-.1589763,g=.0036096,y=.1643573,C=12.9590088,E=new r;return o.ComputeMoon=function(o,S){e(o)||(o=r.now()),E=r.addSeconds(o,a,E);var w=r.totalDays(E)-s,T=w/n.DAYS_PER_JULIAN_CENTURY,b=(125.045+l*w)*i.RADIANS_PER_DEGREE,x=(250.089+u*w)*i.RADIANS_PER_DEGREE,P=(260.008+c*w)*i.RADIANS_PER_DEGREE,A=(176.625+h*w)*i.RADIANS_PER_DEGREE,I=(357.529+d*w)*i.RADIANS_PER_DEGREE,M=(311.589+p*w)*i.RADIANS_PER_DEGREE,D=(134.963+m*w)*i.RADIANS_PER_DEGREE,R=(276.617+f*w)*i.RADIANS_PER_DEGREE,O=(34.226+v*w)*i.RADIANS_PER_DEGREE,N=(15.134+_*w)*i.RADIANS_PER_DEGREE,L=(119.743+g*w)*i.RADIANS_PER_DEGREE,F=(239.961+y*w)*i.RADIANS_PER_DEGREE,B=(25.053+C*w)*i.RADIANS_PER_DEGREE,V=Math.sin(b),z=Math.sin(x),k=Math.sin(P),U=Math.sin(A),G=Math.sin(I),W=Math.sin(M),H=Math.sin(D),q=Math.sin(R),j=Math.sin(O),Y=Math.sin(N),X=Math.sin(L),Z=Math.sin(F),K=Math.sin(B),J=Math.cos(b),Q=Math.cos(x),$=Math.cos(P),ee=Math.cos(A),te=Math.cos(I),re=Math.cos(M),ie=Math.cos(D),ne=Math.cos(R),oe=Math.cos(O),ae=Math.cos(N),se=Math.cos(L),le=Math.cos(F),ue=Math.cos(B),ce=(269.9949+.0031*T-3.8787*V-.1204*z+.07*k-.0172*U+.0072*W-.0052*Y+.0043*K)*i.RADIANS_PER_DEGREE,he=(66.5392+.013*T+1.5419*J+.0239*Q-.0278*$+.0068*ee-.0029*re+9e-4*ie+8e-4*ae-9e-4*ue)*i.RADIANS_PER_DEGREE,de=(38.3213+13.17635815*w-1.4e-12*w*w+3.561*V+.1208*z-.0642*k+.0158*U+.0252*G-.0066*W-.0047*H-.0046*q+.0028*j+.0052*Y+.004*X+.0019*Z-.0044*K)*i.RADIANS_PER_DEGREE,pe=(13.17635815-2.8e-12*w+3.561*J*l+.1208*Q*u-.0642*$*c+.0158*ee*h+.0252*te*d-.0066*re*p-.0047*ie*m-.0046*ne*f+.0028*oe*v+.0052*ae*_+.004*se*g+.0019*le*y-.0044*ue*C)/86400*i.RADIANS_PER_DEGREE;return e(S)||(S=new t),S.rightAscension=ce,S.declination=he,S.rotation=de,S.rotationRate=pe,S},o}),r("Core/IauOrientationAxes",["./Cartesian3","./defined","./Iau2000Orientation","./JulianDate","./Math","./Matrix3","./Quaternion"],function(e,t,r,i,n,o,a){"use strict";function s(r,i,a){var s=u;s.x=Math.cos(r+n.PI_OVER_TWO),s.y=Math.sin(r+n.PI_OVER_TWO),s.z=0;var l=Math.cos(i),d=h;d.x=l*Math.cos(r),d.y=l*Math.sin(r),d.z=Math.sin(i);var p=e.cross(d,s,c);return t(a)||(a=new o),a[0]=s.x,a[1]=p.x,a[2]=d.x,a[3]=s.y,a[4]=p.y,a[5]=d.y,a[6]=s.z,a[7]=p.z,a[8]=d.z,a}var l=function(e){t(e)&&"function"==typeof e||(e=r.ComputeMoon),this._computeFunction=e},u=new e,c=new e,h=new e,d=new o,p=new a;return l.prototype.evaluate=function(r,l){t(r)||(r=i.now());var u=this._computeFunction(r),c=s(u.rightAscension,u.declination,l),h=n.zeroToTwoPi(u.rotation),m=a.fromAxisAngle(e.UNIT_Z,h,p),f=o.fromQuaternion(a.conjugate(m,m),d),v=o.multiply(f,c,c);return v},l}),r("Core/InterpolationAlgorithm",["./DeveloperError"],function(e){"use strict";var t={};return t.type=void 0,t.getRequiredDataPoints=e.throwInstantiationError,t.interpolateOrderZero=e.throwInstantiationError,t.interpolate=e.throwInstantiationError,t}),r("Core/TimeInterval",["./defaultValue","./defined","./defineProperties","./DeveloperError","./freezeObject","./JulianDate"],function(e,t,r,i,n,o){"use strict";var a=function(r){r=e(r,e.EMPTY_OBJECT),this.start=t(r.start)?o.clone(r.start):new o,this.stop=t(r.stop)?o.clone(r.stop):new o,this.data=r.data,this.isStartIncluded=e(r.isStartIncluded,!0),this.isStopIncluded=e(r.isStopIncluded,!0)};r(a.prototype,{isEmpty:{get:function(){var e=o.compare(this.stop,this.start);return 0>e||0===e&&(!this.isStartIncluded||!this.isStopIncluded)}}});var s={start:void 0,stop:void 0,isStartIncluded:void 0,isStopIncluded:void 0,data:void 0};return a.fromIso8601=function(r,i){var n=r.iso8601.split("/"),l=o.fromIso8601(n[0]),u=o.fromIso8601(n[1]),c=e(r.isStartIncluded,!0),h=e(r.isStopIncluded,!0),d=r.data;return t(i)?(i.start=l,i.stop=u,i.isStartIncluded=c,i.isStopIncluded=h,i.data=d,i):(s.start=l,s.stop=u,s.isStartIncluded=c,s.isStopIncluded=h,s.data=d,new a(s))},a.toIso8601=function(e,t){return o.toIso8601(e.start,t)+"/"+o.toIso8601(e.stop,t)},a.clone=function(e,r){return t(e)?t(r)?(r.start=e.start,r.stop=e.stop,r.isStartIncluded=e.isStartIncluded,r.isStopIncluded=e.isStopIncluded,r.data=e.data,r):new a(e):void 0},a.equals=function(e,r,i){return e===r||t(e)&&t(r)&&(e.isEmpty&&r.isEmpty||e.isStartIncluded===r.isStartIncluded&&e.isStopIncluded===r.isStopIncluded&&o.equals(e.start,r.start)&&o.equals(e.stop,r.stop)&&(e.data===r.data||t(i)&&i(e.data,r.data)))},a.equalsEpsilon=function(e,r,i,n){return e===r||t(e)&&t(r)&&(e.isEmpty&&r.isEmpty||e.isStartIncluded===r.isStartIncluded&&e.isStopIncluded===r.isStopIncluded&&o.equalsEpsilon(e.start,r.start,i)&&o.equalsEpsilon(e.stop,r.stop,i)&&(e.data===r.data||t(n)&&n(e.data,r.data)))},a.intersect=function(e,r,i,n){if(!t(r))return a.clone(a.EMPTY,i);var s=e.start,l=e.stop,u=r.start,c=r.stop,h=o.greaterThanOrEquals(u,s)&&o.greaterThanOrEquals(l,u),d=!h&&o.lessThanOrEquals(u,s)&&o.lessThanOrEquals(s,c);if(!h&&!d)return a.clone(a.EMPTY,i);var p=e.isStartIncluded,m=e.isStopIncluded,f=r.isStartIncluded,v=r.isStopIncluded,_=o.lessThan(l,c);return i.start=h?u:s,i.isStartIncluded=p&&f||!o.equals(u,s)&&(h&&f||d&&p),i.stop=_?l:c,i.isStopIncluded=_?m:m&&v||!o.equals(c,l)&&v,i.data=t(n)?n(e.data,r.data):e.data,i},a.contains=function(e,t){if(e.isEmpty)return!1;var r=o.compare(e.start,t);if(0===r)return e.isStartIncluded;var i=o.compare(t,e.stop);return 0===i?e.isStopIncluded:0>r&&0>i},a.prototype.clone=function(e){return a.clone(this,e)},a.prototype.equals=function(e,t){return a.equals(this,e,t)},a.prototype.equalsEpsilon=function(e,t,r){return a.equalsEpsilon(this,e,t,r)},a.prototype.toString=function(){return a.toIso8601(this)},a.EMPTY=n(new a({start:new o,stop:new o,isStartIncluded:!1,isStopIncluded:!1})),a}),r("Core/Iso8601",["./freezeObject","./JulianDate","./TimeInterval"],function(e,t,r){ -"use strict";var i=e(t.fromIso8601("0000-01-01T00:00:00Z")),n=e(t.fromIso8601("9999-12-31T24:00:00Z")),o=e(new r({start:i,stop:n})),a={MINIMUM_VALUE:i,MAXIMUM_VALUE:n,MAXIMUM_INTERVAL:o};return a}),r("Core/KeyboardEventModifier",["./freezeObject"],function(e){"use strict";var t={SHIFT:0,CTRL:1,ALT:2};return e(t)}),r("Core/LagrangePolynomialApproximation",["./defined"],function(e){"use strict";var t={type:"Lagrange"};return t.getRequiredDataPoints=function(e){return Math.max(e+1,2)},t.interpolateOrderZero=function(t,r,i,n,o){e(o)||(o=new Array(n));var a,s,l=r.length;for(a=0;n>a;a++)o[a]=0;for(a=0;l>a;a++){var u=1;for(s=0;l>s;s++)if(s!==a){var c=r[a]-r[s];u*=(t-r[s])/c}for(s=0;n>s;s++)o[s]+=u*i[a*n+s]}return o},t}),r("Core/LinearApproximation",["./defined","./DeveloperError"],function(e,t){"use strict";var r={type:"Linear"};return r.getRequiredDataPoints=function(e){return 2},r.interpolateOrderZero=function(t,r,i,n,o){e(o)||(o=new Array(n));var a,s,l,u=r[0],c=r[1];for(a=0;n>a;a++)s=i[a],l=i[a+n],o[a]=((l-s)*t+c*s-u*l)/(c-u);return o},r}),r("Core/MapProjection",["./defineProperties","./DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return e(r.prototype,{ellipsoid:{get:t.throwInstantiationError}}),r.prototype.project=t.throwInstantiationError,r.prototype.unproject=t.throwInstantiationError,r}),r("Core/MapboxApi",["./defined"],function(e){"use strict";var t={};t.defaultAccessToken=void 0;var r=!1;return t.getAccessToken=function(i){return e(i)?i:e(t.defaultAccessToken)?t.defaultAccessToken:(r||(console.log("This application is using Cesium's default Mapbox access token. Please create a new access token for the application as soon as possible and prior to deployment by visiting https://www.mapbox.com/account/apps/, and provide your token to Cesium by setting the Cesium.MapboxApi.defaultAccessToken property before constructing the CesiumWidget or any other object that uses the Mapbox API."),r=!0),"pk.eyJ1IjoiYW5hbHl0aWNhbGdyYXBoaWNzIiwiYSI6IjA2YzBjOTM3YzFlYzljYmQ5NDAxZWI1Y2ZjNzZlM2E1In0.vDZL2SPFEpi_f7ziAIP_yw")},t}),r("Core/Matrix2",["./Cartesian2","./defaultValue","./defined","./DeveloperError","./freezeObject"],function(e,t,r,i,n){"use strict";var o=function(e,r,i,n){this[0]=t(e,0),this[1]=t(i,0),this[2]=t(r,0),this[3]=t(n,0)};o.packedLength=4,o.pack=function(e,r,i){i=t(i,0),r[i++]=e[0],r[i++]=e[1],r[i++]=e[2],r[i++]=e[3]},o.unpack=function(e,i,n){return i=t(i,0),r(n)||(n=new o),n[0]=e[i++],n[1]=e[i++],n[2]=e[i++],n[3]=e[i++],n},o.clone=function(e,t){return r(e)?r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t):new o(e[0],e[2],e[1],e[3]):void 0},o.fromArray=function(e,i,n){return i=t(i,0),r(n)||(n=new o),n[0]=e[i],n[1]=e[i+1],n[2]=e[i+2],n[3]=e[i+3],n},o.fromColumnMajorArray=function(e,t){return o.clone(e,t)},o.fromRowMajorArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[2],t[2]=e[1],t[3]=e[3],t):new o(e[0],e[1],e[2],e[3])},o.fromScale=function(e,t){return r(t)?(t[0]=e.x,t[1]=0,t[2]=0,t[3]=e.y,t):new o(e.x,0,0,e.y)},o.fromUniformScale=function(e,t){return r(t)?(t[0]=e,t[1]=0,t[2]=0,t[3]=e,t):new o(e,0,0,e)},o.fromRotation=function(e,t){var i=Math.cos(e),n=Math.sin(e);return r(t)?(t[0]=i,t[1]=n,t[2]=-n,t[3]=i,t):new o(i,-n,n,i)},o.toArray=function(e,t){return r(t)?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t):[e[0],e[1],e[2],e[3]]},o.getElementIndex=function(e,t){return 2*e+t},o.getColumn=function(e,t,r){var i=2*t,n=e[i],o=e[i+1];return r.x=n,r.y=o,r},o.setColumn=function(e,t,r,i){i=o.clone(e,i);var n=2*t;return i[n]=r.x,i[n+1]=r.y,i},o.getRow=function(e,t,r){var i=e[t],n=e[t+2];return r.x=i,r.y=n,r},o.setRow=function(e,t,r,i){return i=o.clone(e,i),i[t]=r.x,i[t+2]=r.y,i};var a=new e;o.getScale=function(t,r){return r.x=e.magnitude(e.fromElements(t[0],t[1],a)),r.y=e.magnitude(e.fromElements(t[2],t[3],a)),r};var s=new e;return o.getMaximumScale=function(t){return o.getScale(t,s),e.maximumComponent(s)},o.multiply=function(e,t,r){var i=e[0]*t[0]+e[2]*t[1],n=e[0]*t[2]+e[2]*t[3],o=e[1]*t[0]+e[3]*t[1],a=e[1]*t[2]+e[3]*t[3];return r[0]=i,r[1]=o,r[2]=n,r[3]=a,r},o.add=function(e,t,r){return r[0]=e[0]+t[0],r[1]=e[1]+t[1],r[2]=e[2]+t[2],r[3]=e[3]+t[3],r},o.subtract=function(e,t,r){return r[0]=e[0]-t[0],r[1]=e[1]-t[1],r[2]=e[2]-t[2],r[3]=e[3]-t[3],r},o.multiplyByVector=function(e,t,r){var i=e[0]*t.x+e[2]*t.y,n=e[1]*t.x+e[3]*t.y;return r.x=i,r.y=n,r},o.multiplyByScalar=function(e,t,r){return r[0]=e[0]*t,r[1]=e[1]*t,r[2]=e[2]*t,r[3]=e[3]*t,r},o.multiplyByScale=function(e,t,r){return r[0]=e[0]*t.x,r[1]=e[1]*t.x,r[2]=e[2]*t.y,r[3]=e[3]*t.y,r},o.negate=function(e,t){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=-e[3],t},o.transpose=function(e,t){var r=e[0],i=e[2],n=e[1],o=e[3];return t[0]=r,t[1]=i,t[2]=n,t[3]=o,t},o.abs=function(e,t){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t[3]=Math.abs(e[3]),t},o.equals=function(e,t){return e===t||r(e)&&r(t)&&e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]&&e[3]===t[3]},o.equalsArray=function(e,t,r){return e[0]===t[r]&&e[1]===t[r+1]&&e[2]===t[r+2]&&e[3]===t[r+3]},o.equalsEpsilon=function(e,t,i){return e===t||r(e)&&r(t)&&Math.abs(e[0]-t[0])<=i&&Math.abs(e[1]-t[1])<=i&&Math.abs(e[2]-t[2])<=i&&Math.abs(e[3]-t[3])<=i},o.IDENTITY=n(new o(1,0,0,1)),o.ZERO=n(new o(0,0,0,0)),o.COLUMN0ROW0=0,o.COLUMN0ROW1=1,o.COLUMN1ROW0=2,o.COLUMN1ROW1=3,o.prototype.clone=function(e){return o.clone(this,e)},o.prototype.equals=function(e){return o.equals(this,e)},o.prototype.equalsEpsilon=function(e,t){return o.equalsEpsilon(this,e,t)},o.prototype.toString=function(){return"("+this[0]+", "+this[2]+")\n("+this[1]+", "+this[3]+")"},o}),r("Core/NearFarScalar",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t,r,i,n){this.near=e(t,0),this.nearValue=e(r,0),this.far=e(i,1),this.farValue=e(n,0)};return i.clone=function(e,r){return t(e)?t(r)?(r.near=e.near,r.nearValue=e.nearValue,r.far=e.far,r.farValue=e.farValue,r):new i(e.near,e.nearValue,e.far,e.farValue):void 0},i.packedLength=4,i.pack=function(t,r,i){i=e(i,0),r[i++]=t.near,r[i++]=t.nearValue,r[i++]=t.far,r[i]=t.farValue},i.unpack=function(r,n,o){return n=e(n,0),t(o)||(o=new i),o.near=r[n++],o.nearValue=r[n++],o.far=r[n++],o.farValue=r[n],o},i.equals=function(e,r){return e===r||t(e)&&t(r)&&e.near===r.near&&e.nearValue===r.nearValue&&e.far===r.far&&e.farValue===r.farValue},i.prototype.clone=function(e){return i.clone(this,e)},i.prototype.equals=function(e){return i.equals(this,e)},i}),r("Core/Visibility",["./freezeObject"],function(e){"use strict";var t={NONE:-1,PARTIAL:0,FULL:1};return e(t)}),r("Core/Occluder",["./BoundingSphere","./Cartesian3","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Math","./Rectangle","./Visibility"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(e,r){this._occluderPosition=t.clone(e.center),this._occluderRadius=e.radius,this._horizonDistance=0,this._horizonPlaneNormal=void 0,this._horizonPlanePosition=void 0,this._cameraPosition=void 0,this.cameraPosition=r},h=new t;n(c.prototype,{position:{get:function(){return this._occluderPosition}},radius:{get:function(){return this._occluderRadius}},cameraPosition:{set:function(e){e=t.clone(e,this._cameraPosition);var r,i,n,o=t.subtract(this._occluderPosition,e,h),a=t.magnitudeSquared(o),s=this._occluderRadius*this._occluderRadius;if(a>s){r=Math.sqrt(a-s),a=1/Math.sqrt(a),i=t.multiplyByScalar(o,a,h);var l=r*r*a;n=t.add(e,t.multiplyByScalar(i,l,h),h)}else r=Number.MAX_VALUE;this._horizonDistance=r,this._horizonPlaneNormal=i,this._horizonPlanePosition=n,this._cameraPosition=e}}}),c.fromBoundingSphere=function(e,r,n){if(!i(e))throw new o("occluderBoundingSphere is required.");if(!i(r))throw new o("camera position is required.");return i(n)?(t.clone(e.center,n._occluderPosition),n._occluderRadius=e.radius,n.cameraPosition=r,n):new c(e,r)};var d=new t;c.prototype.isPointVisible=function(e){if(this._horizonDistance!==Number.MAX_VALUE){var r=t.subtract(e,this._occluderPosition,d),i=this._occluderRadius;if(i=t.magnitudeSquared(r)-i*i,i>0)return i=Math.sqrt(i)+this._horizonDistance,r=t.subtract(e,this._cameraPosition,r),i*i>t.magnitudeSquared(r)}return!1};var p=new t;c.prototype.isBoundingSphereVisible=function(e){var r=t.clone(e.center,p),i=e.radius;if(this._horizonDistance!==Number.MAX_VALUE){var n=t.subtract(r,this._occluderPosition,d),o=this._occluderRadius-i;if(o=t.magnitudeSquared(n)-o*o,i<this._occluderRadius)return o>0?(o=Math.sqrt(o)+this._horizonDistance,n=t.subtract(r,this._cameraPosition,n),o*o+i*i>t.magnitudeSquared(n)):!1;if(o>0){n=t.subtract(r,this._cameraPosition,n);var a=t.magnitudeSquared(n),s=this._occluderRadius*this._occluderRadius,l=i*i;return(this._horizonDistance*this._horizonDistance+s)*l>a*s?!0:(o=Math.sqrt(o)+this._horizonDistance,o*o+l>a)}return!0}return!1};var m=new t;c.prototype.computeVisibility=function(e){if(!i(e))throw new o("occludeeBS is required.");var r=t.clone(e.center),n=e.radius;if(n>this._occluderRadius)return u.FULL;if(this._horizonDistance!==Number.MAX_VALUE){var a=t.subtract(r,this._occluderPosition,m),s=this._occluderRadius-n,l=t.magnitudeSquared(a);if(s=l-s*s,s>0){s=Math.sqrt(s)+this._horizonDistance,a=t.subtract(r,this._cameraPosition,a);var c=t.magnitudeSquared(a);return c>s*s+n*n?u.NONE:(s=this._occluderRadius+n,s=l-s*s,s>0?(s=Math.sqrt(s)+this._horizonDistance,s*s+n*n>c?u.FULL:u.PARTIAL):(a=t.subtract(r,this._horizonPlanePosition,a),t.dot(a,this._horizonPlaneNormal)>-n?u.PARTIAL:u.FULL))}}return u.NONE};var f=new t;c.computeOccludeePoint=function(e,r,i){var n=t.clone(r),a=t.clone(e.center),s=e.radius,l=i.length;if(t.equals(a,r))throw new o("occludeePosition must be different than occluderBoundingSphere.center");var u=t.normalize(t.subtract(n,a,f),f),h=-t.dot(u,a),d=c._anyRotationVector(a,u,h),p=c._horizonToPlaneNormalDotProduct(e,u,h,d,i[0]);if(!p)return void 0;for(var m,v=1;l>v;++v){if(m=c._horizonToPlaneNormalDotProduct(e,u,h,d,i[v]),!m)return void 0;p>m&&(p=m)}if(.0017453283658983088>p)return void 0;var _=s/p;return t.add(a,t.multiplyByScalar(u,_,f),f)};var v=[];c.computeOccludeePointFromRectangle=function(i,n){n=r(n,a.WGS84);var o=l.subsample(i,n,0,v),s=e.fromPoints(o),u=t.ZERO;return t.equals(u,s.center)?void 0:c.computeOccludeePoint(new e(u,n.minimumRadius),s.center,o)};var _=new t;c._anyRotationVector=function(e,r,i){var n=t.abs(r,_),o=n.x>n.y?0:1;(0===o&&n.z>n.x||1===o&&n.z>n.y)&&(o=2);var a,s=new t;0===o?(n.x=e.x,n.y=e.y+1,n.z=e.z+1,a=t.UNIT_X):1===o?(n.x=e.x+1,n.y=e.y,n.z=e.z+1,a=t.UNIT_Y):(n.x=e.x+1,n.y=e.y+1,n.z=e.z,a=t.UNIT_Z);var l=(t.dot(r,n)+i)/-t.dot(r,a);return t.normalize(t.subtract(t.add(n,t.multiplyByScalar(a,l,s),n),e,n),n)};var g=new t;c._rotationVector=function(e,r,i,n,o){var a=t.subtract(n,e,g);if(a=t.normalize(a,a),t.dot(r,a)<.9999999847691291){var l=t.cross(r,a,a),u=t.magnitude(l);if(u>s.EPSILON13)return t.normalize(l,new t)}return o};var y=new t,C=new t,E=new t,S=new t;return c._horizonToPlaneNormalDotProduct=function(e,r,i,n,o){var a=t.clone(o,y),s=t.clone(e.center,C),l=e.radius,u=t.subtract(s,a,E),c=t.magnitudeSquared(u),h=l*l;if(h>c)return!1;var d=c-h,p=Math.sqrt(d),m=Math.sqrt(c),f=1/m,v=p*f,_=v*p;u=t.normalize(u,u);var g=t.add(a,t.multiplyByScalar(u,_,S),S),w=Math.sqrt(d-_*_),T=this._rotationVector(s,r,i,a,n),b=t.fromElements(T.x*T.x*u.x+(T.x*T.y-T.z)*u.y+(T.x*T.z+T.y)*u.z,(T.x*T.y+T.z)*u.x+T.y*T.y*u.y+(T.y*T.z-T.x)*u.z,(T.x*T.z-T.y)*u.x+(T.y*T.z+T.x)*u.y+T.z*T.z*u.z,y);b=t.normalize(b,b);var x=t.multiplyByScalar(b,w,y);T=t.normalize(t.subtract(t.add(g,x,E),s,E),E);var P=t.dot(r,T);T=t.normalize(t.subtract(t.subtract(g,x,T),s,T),T);var A=t.dot(r,T);return A>P?P:A},c}),r("Core/Packable",["./DeveloperError"],function(e){"use strict";var t={packedLength:void 0,pack:e.throwInstantiationError,unpack:e.throwInstantiationError};return t}),r("Core/PackableForInterpolation",["./DeveloperError"],function(e){"use strict";var t={packedInterpolationLength:void 0,convertPackedArrayForInterpolation:e.throwInstantiationError,unpackInterpolationResult:e.throwInstantiationError};return t}),r("ThirdParty/measureText",[],function(){var e=function(e,t){return document.defaultView.getComputedStyle(e,null).getPropertyValue(t)},t=function(t,r,i,n){var o=t.measureText(r),a=e(t.canvas,"font-family"),s=e(t.canvas,"font-size").replace("px",""),l=!/\S/.test(r);o.fontsize=s;var u=document.createElement("div");u.style.position="absolute",u.style.opacity=0,u.style.font=s+"px "+a,u.innerHTML=r+"<br/>"+r,document.body.appendChild(u),o.leading=1.2*s;var c=e(u,"height");if(c=c.replace("px",""),c>=2*s&&(o.leading=c/2|0),document.body.removeChild(u),l)o.ascent=0,o.descent=0,o.bounds={minx:0,maxx:o.width,miny:0,maxy:0},o.height=0;else{var h=document.createElement("canvas"),d=100;h.width=o.width+d,h.height=3*s,h.style.opacity=1,h.style.fontFamily=a,h.style.fontSize=s;var p=h.getContext("2d");p.font=s+"px "+a;var m=h.width,f=h.height,v=f/2;p.fillStyle="white",p.fillRect(-1,-1,m+2,f+2),i&&(p.strokeStyle="black",p.lineWidth=t.lineWidth,p.strokeText(r,d/2,v)),n&&(p.fillStyle="black",p.fillText(r,d/2,v));for(var _=p.getImageData(0,0,m,f).data,g=0,y=4*m,C=_.length;++g<C&&255===_[g];);var E=g/y|0;for(g=C-1;--g>0&&255===_[g];);var S=g/y|0;for(g=0;C>g&&255===_[g];)g+=y,g>=C&&(g=g-C+4);var w=g%y/4|0,T=1;for(g=C-3;g>=0&&255===_[g];)g-=y,0>g&&(g=C-3-4*T++);var b=g%y/4+1|0;o.ascent=v-E,o.descent=S-v,o.bounds={minx:w-d/2,maxx:b-d/2,miny:0,maxy:S-E},o.height=1+(S-E)}return o};return t}),r("Core/writeTextToCanvas",["../ThirdParty/measureText","./Color","./defaultValue","./defined","./DeveloperError"],function(e,t,r,i,n){"use strict";var o,a=function(n,a){if(""===n)return void 0;a=r(a,r.EMPTY_OBJECT);var s=r(a.font,"10px sans-serif"),l=r(a.stroke,!1),u=r(a.fill,!0),c=r(a.strokeWidth,1),h=document.createElement("canvas");h.width=1,h.height=1,h.style.font=s;var d=h.getContext("2d");i(o)||(i(d.imageSmoothingEnabled)?o="imageSmoothingEnabled":i(d.mozImageSmoothingEnabled)?o="mozImageSmoothingEnabled":i(d.webkitImageSmoothingEnabled)?o="webkitImageSmoothingEnabled":i(d.msImageSmoothingEnabled)&&(o="msImageSmoothingEnabled")),d.font=s,d.lineJoin="round",d.lineWidth=c,d[o]=!1,d.textBaseline=r(a.textBaseline,"bottom"),h.style.visibility="hidden",document.body.appendChild(h);var p=e(d,n,l,u);p.computedWidth=Math.max(p.width,p.bounds.maxx-p.bounds.minx),h.dimensions=p,document.body.removeChild(h),h.style.visibility="";var m=p.height-p.ascent;h.width=p.computedWidth,h.height=p.height;var f=h.height-m;if(d.font=s,d.lineJoin="round",d.lineWidth=c,d[o]=!1,l){var v=r(a.strokeColor,t.BLACK);d.strokeStyle=v.toCssColorString(),d.strokeText(n,0,f)}if(u){var _=r(a.fillColor,t.WHITE);d.fillStyle=_.toCssColorString(),d.fillText(n,0,f)}return h};return a}),r("Core/PinBuilder",["./buildModuleUrl","./Color","./defined","./DeveloperError","./loadImage","./writeTextToCanvas"],function(e,t,r,i,n,o){"use strict";function a(e,t,r){e.save(),e.scale(r/24,r/24),e.fillStyle=t.toCssColorString(),e.strokeStyle=t.brighten(.6,c).toCssColorString(),e.lineWidth=.846,e.beginPath(),e.moveTo(6.72,.422),e.lineTo(17.28,.422),e.bezierCurveTo(18.553,.422,19.577,1.758,19.577,3.415),e.lineTo(19.577,10.973),e.bezierCurveTo(19.577,12.63,18.553,13.966,17.282,13.966),e.lineTo(14.386,14.008),e.lineTo(11.826,23.578),e.lineTo(9.614,14.008),e.lineTo(6.719,13.965),e.bezierCurveTo(5.446,13.983,4.422,12.629,4.422,10.972),e.lineTo(4.422,3.416),e.bezierCurveTo(4.423,1.76,5.447,.423,6.718,.423),e.closePath(),e.fill(),e.stroke(),e.restore()}function s(e,r,i){var n=i/2.5,o=n,a=n;r.width>r.height?a=n*(r.height/r.width):r.width<r.height&&(o=n*(r.width/r.height));var s=(i-o)/2,l=7/24*i-a/2;e.globalCompositeOperation="destination-out",e.drawImage(r,s-1,l,o,a),e.drawImage(r,s,l-1,o,a),e.drawImage(r,s+1,l,o,a),e.drawImage(r,s,l+1,o,a),e.globalCompositeOperation="destination-over",e.fillStyle=t.BLACK.toCssColorString(),e.fillRect(s-1,l-1,o+1,a+1),e.globalCompositeOperation="destination-out",e.drawImage(r,s,l,o,a),e.globalCompositeOperation="destination-over",e.fillStyle=t.WHITE.toCssColorString(),e.fillRect(s,l,o,a)}function l(e,t,i,l,u){h[0]=e,h[1]=t,h[2]=i,h[3]=l;var c=JSON.stringify(h),d=u[c];if(r(d))return d;var p=document.createElement("canvas");p.width=l,p.height=l;var m=p.getContext("2d");if(a(m,i,l),r(e)){var f=n(e).then(function(e){return s(m,e,l),u[c]=p,p});return u[c]=f,f}if(r(t)){var v=o(t,{font:"bold "+l+"px sans-serif"});s(m,v,l)}return u[c]=p,p}var u=function(){this._cache={}};u.prototype.fromColor=function(e,t){return l(void 0,void 0,e,t,this._cache)},u.prototype.fromUrl=function(e,t,r){return l(e,void 0,t,r,this._cache)},u.prototype.fromMakiIconId=function(t,r,i){return l(e("Assets/Textures/maki/"+encodeURIComponent(t)+".png"),void 0,r,i,this._cache)},u.prototype.fromText=function(e,t,r){return l(void 0,e,t,r,this._cache)};var c=new t,h=new Array(4);return u}),r("Core/PixelFormat",["../Renderer/WebGLConstants","./freezeObject"],function(e,t){"use strict";var r={DEPTH_COMPONENT:e.DEPTH_COMPONENT,DEPTH_STENCIL:e.DEPTH_STENCIL,ALPHA:e.ALPHA,RGB:e.RGB,RGBA:e.RGBA,LUMINANCE:e.LUMINANCE,LUMINANCE_ALPHA:e.LUMINANCE_ALPHA,validate:function(e){return e===r.DEPTH_COMPONENT||e===r.DEPTH_STENCIL||e===r.ALPHA||e===r.RGB||e===r.RGBA||e===r.LUMINANCE||e===r.LUMINANCE_ALPHA},isColorFormat:function(e){return e===r.ALPHA||e===r.RGB||e===r.RGBA||e===r.LUMINANCE||e===r.LUMINANCE_ALPHA},isDepthFormat:function(e){return e===r.DEPTH_COMPONENT||e===r.DEPTH_STENCIL}};return t(r)}),r("Core/pointInsideTriangle",["./barycentricCoordinates","./Cartesian3"],function(e,t){"use strict";var r=new t,i=function(t,i,n,o){return e(t,i,n,o,r),r.x>0&&r.y>0&&r.z>0};return i}),r("Core/Queue",["../Core/defineProperties"],function(e){"use strict";var t=function(){this._array=[],this._offset=0,this._length=0};return e(t.prototype,{length:{get:function(){return this._length}}}),t.prototype.enqueue=function(e){this._array.push(e),this._length++},t.prototype.dequeue=function(){if(0===this._length)return void 0;var e=this._array,t=this._offset,r=e[t];return e[t]=void 0,t++,t>10&&2*t>e.length&&(this._array=e.slice(t),t=0),this._offset=t,this._length--,r},t.prototype.peek=function(){return 0===this._length?void 0:this._array[this._offset]},t.prototype.contains=function(e){return-1!==this._array.indexOf(e)},t.prototype.clear=function(){this._array.length=this._offset=this._length=0},t.prototype.sort=function(e){this._offset>0&&(this._array=this._array.slice(this._offset),this._offset=0),this._array.sort(e)},t}),r("Core/WindingOrder",["../Renderer/WebGLConstants","./freezeObject"],function(e,t){"use strict";var r={CLOCKWISE:e.CW,COUNTER_CLOCKWISE:e.CCW,validate:function(e){return e===r.CLOCKWISE||e===r.COUNTER_CLOCKWISE}};return t(r)}),r("Core/PolygonPipeline",["./Cartesian2","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./Math","./pointInsideTriangle","./PolylinePipeline","./PrimitiveType","./Queue","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(t,r,i){var n=e.subtract(r,t,F),o=e.subtract(i,r,B);return n.x*o.y-n.y*o.x>=0}function _(e){for(var t=e[0].x,r=0,i=0;i<e.length;i++)e[i].x>t&&(t=e[i].x,r=i);return r}function g(e){for(var t=e[0][0].x,r=0,i=0;i<e.length;i++){var n=e[i][_(e[i])].x;n>t&&(t=n,r=i)}return r}function y(e){for(var t=[],r=0;r<e.length;r++){var i=e[(r-1+e.length)%e.length],n=e[r],o=e[(r+1)%e.length];v(i,n,o)||t.push(n)}return t}function C(t,r){for(var i=0;i<t.length;i++)if(e.equals(r,t[i]))return i;return-1}function E(r,n,o){o=i(o,[]);var a=Number.MAX_VALUE,s=_(n),l=new e(n[s].x,r.y);o.push(s),o.push((s+1)%n.length);for(var u=n[0].x,c=u,h=1;h<n.length;++h)n[h].x<u?u=n[h].x:n[h].x>c&&(c=n[h].x);c+=c-u;var d=new t(c,r.y,0);for(h=0;h<n.length;h++){var p=n[h],m=n[(h+1)%n.length];if((p.x>=r.x||m.x>=r.x)&&(p.y>=r.y&&m.y<=r.y||p.y<=r.y&&m.y>=r.y)){var f=(m.y-p.y)*(d.x-r.x)-(m.x-p.x)*(d.y-r.y);if(0!==f){f=1/f;var v=((m.x-p.x)*(r.y-p.y)-(m.y-p.y)*(r.x-p.x))*f,g=((d.x-r.x)*(r.y-p.y)-(d.y-r.y)*(r.x-p.x))*f;if(v>=0&&1>=v&&g>=0&&1>=g){var y=new e(r.x+v*(d.x-r.x),r.y+v*(d.y-r.y)),C=e.subtract(y,r,V);f=e.magnitudeSquared(C),a>f&&(l=y,a=f,o[0]=h,o[1]=(h+1)%n.length)}}}}return l}function S(t,r){var i=g(r),n=r[i],o=_(n),a=n[o],s=[],l=E(a,t,s),u=C(t,l);if(-1!==u)return u;var d=e.magnitudeSquared(e.subtract(t[s[0]],a,z)),p=e.magnitudeSquared(e.subtract(t[s[1]],a,z)),m=p>d?t[s[0]]:t[s[1]],f=y(t),v=f.indexOf(m);-1!==v&&f.splice(v,1);for(var S=[],w=0;w<f.length;w++){var T=f[w];h(T,a,l,m)&&S.push(T)}var b=Number.MAX_VALUE;if(S.length>0){var x=e.fromElements(1,0,z);for(w=0;w<S.length;w++){var P=e.subtract(S[w],a,k),A=e.magnitude(x)*e.magnitudeSquared(P);if(0!==A){var I=Math.abs(c.acosClamped(e.dot(x,P)/A));b>I&&(b=I,m=S[w])}}}return t.indexOf(m)}function w(e,r,i){for(var n=ee.computeWindingOrder2D(e),o=0;o<r.length;o++){var a=r[o];t.equals(a[0],a[a.length-1])||a.push(a[0]);var l=ee.computeWindingOrder2D(a);l===n&&a.reverse()}var u=s.fromPoints(e,i),c=u.projectPointsOntoPlane(e),h=[];for(o=0;o<r.length;o++)h.push(u.projectPointsOntoPlane(r[o]));var d=S(c,h),p=g(h),m=_(h[p]),f=r[p],v=[];for(o=0;o<e.length;o++)v.push(e[o]);var y,C=[];if(0!==m)for(y=0;y<=f.length;y++){var E=(y+m)%f.length;0!==E&&C.push(f[E])}else for(y=0;y<f.length;y++)C.push(f[(y+m)%f.length]);var w=v.lastIndexOf(e[d]);C.push(e[w]);var T=v.slice(0,w+1),b=v.slice(w+1);return v=T.concat(C,b),r.splice(p,1),v}function T(e){var t=c.nextRandomNumber(),r=Math.floor(t*e);return r===e&&r--,r}function b(e,t,r,i){var n=i[e].position,o=i[t].position,a=i[r].position,s=a.x,l=a.y,u=n.x-s,c=n.y-l,h=o.x-s,d=o.y-l;return u*d-c*h}function x(e,t){return e.x*t.y-e.y*t.x}function P(e,t){var r=t.length,i=c.mod(e-1,r),n=c.mod(e+1,r);return 0===b(i,n,e,t)?!1:!0}function A(t,r){return e.magnitudeSquared(r)<e.magnitudeSquared(t)}function I(t,r,i){if(!P(t,i))return t;var n=i[t].position,o=i[r].position,a=i.length,s=c.mod(t-1,a);if(!P(s,i))return s;var l=c.mod(t+1,a);if(!P(l,i))return l;var u=e.subtract(i[s].position,n,W),h=e.subtract(i[l].position,n,H),d=e.subtract(o,n,q),p=x(u,d),m=x(h,d);if(0===p)return A(u,d)?U:G;if(0===m)return A(h,d)?U:G;var f=x(u,h);return 0>f?0>p&&m>0?U:G:f>0?p>0&&0>m?G:U:void 0}function M(e,t,r){return(e>t||e>r)&&(t>e||r>e)||t===r&&t===e}function D(t,r,i,n){var o=e.subtract(i,t,Y),a=r.x*n.y-r.y*n.x,s=a*a,l=e.magnitudeSquared(r),u=e.magnitudeSquared(n);if(s>j*l*u){var c=(o.x*n.y-o.y*n.x)/a;return e.add(t,e.multiplyByScalar(r,c,Y),Y)}return void 0}function R(t,r,i){for(var o=e.subtract(r,t,X),a=i.length,s=0;a>s;s++){var l=i[s].position,u=i[c.mod(s+1,a)].position;if(!(e.equals(t,l)||e.equals(r,u)||e.equals(t,u)||e.equals(r,l))){var h=e.subtract(u,l,Z),d=D(t,o,l,h);if(n(d)&&!(e.equals(d,t)||e.equals(d,r)||e.equals(d,l)||e.equals(d,u))){var p=d.x,m=d.y,f=M(p,t.x,r.x)&&M(m,t.y,r.y)&&M(p,l.x,u.x)&&M(m,l.y,u.y);if(f)return!0}}}return!1}function O(t,r,i){var n=I(t,r,i);if(n>=0)return n;var o=I(r,t,i);return o>=0?o:n!==U||o!==U||R(i[t].position,i[r].position,i)||e.equals(i[t].position,i[r].position)?J:K}function N(e){return 0===b(1,2,0,e)}function L(e){var t=e.length;if(3===t)return N(e)?[]:[e[0].index,e[1].index,e[2].index];if(e.length<3)throw new o("Invalid polygon: must have at least three vertices.");for(var r,i,n=0,a=10*e.length,s=J;K>s&&n++<a;){for(r=T(e.length),i=r+1;Math.abs(r-i)<2||Math.abs(r-i)>e.length-2;)i=T(e.length);if(r>i){var l=r;r=i,i=l}s=O(r,i,e)}if(s===K){var u=e.splice(r,i-r+1,e[r],e[i]);return L(e).concat(L(u))}return s>=0?(e.splice(s,1),L(e)):[]}var F=new e,B=new e,V=new e,z=new e(1,0),k=new e,U=-1,G=-2,W=new t,H=new t,q=new t,j=c.EPSILON14,Y=new e,X=(new e,new e),Z=new e,K=-1,J=-2,Q=new t,$=new t,ee={};ee.removeDuplicates=function(e){var r=d.removeDuplicates(e);return t.equals(r[0],r[r.length-1])?r.slice(1):r},ee.computeArea2D=function(e){for(var t=e.length,r=0,i=t-1,n=0;t>n;i=n++){var o=e[i],a=e[n];r+=o.x*a.y-a.x*o.y}return.5*r},ee.computeWindingOrder2D=function(e){var t=ee.computeArea2D(e);return t>0?f.COUNTER_CLOCKWISE:f.CLOCKWISE},ee.triangulate=function(e){for(var t=e.length,r=[],i=0;t>i;++i)r[i]={position:e[i],index:i};return L(r)};var te=new t,re=new t,ie=new t,ne=new t,oe=new t,ae=new t,se=new t;return ee.computeSubdivision=function(e,o,a,s){s=i(s,c.RADIANS_PER_DEGREE);var h,d=a.slice(0),m=o.length,f=new Array(3*m),v=0;for(h=0;m>h;h++){var _=o[h];f[v++]=_.x,f[v++]=_.y,f[v++]=_.z}for(var g=[],y={},C=e.maximumRadius,E=c.chordLength(s,C),S=E*E;d.length>0;){var w,T,b=d.pop(),x=d.pop(),P=d.pop(),A=t.fromArray(f,3*P,te),I=t.fromArray(f,3*x,re),M=t.fromArray(f,3*b,ie),D=t.multiplyByScalar(t.normalize(A,ne),C,ne),R=t.multiplyByScalar(t.normalize(I,oe),C,oe),O=t.multiplyByScalar(t.normalize(M,ae),C,ae),N=t.magnitudeSquared(t.subtract(D,R,se)),L=t.magnitudeSquared(t.subtract(R,O,se)),F=t.magnitudeSquared(t.subtract(O,D,se)),B=Math.max(N,L,F);B>S?N===B?(w=Math.min(P,x)+" "+Math.max(P,x),h=y[w],n(h)||(T=t.add(A,I,se),t.multiplyByScalar(T,.5,T),f.push(T.x,T.y,T.z),h=f.length/3-1,y[w]=h),d.push(P,h,b),d.push(h,x,b)):L===B?(w=Math.min(x,b)+" "+Math.max(x,b),h=y[w],n(h)||(T=t.add(I,M,se),t.multiplyByScalar(T,.5,T),f.push(T.x,T.y,T.z),h=f.length/3-1,y[w]=h),d.push(x,h,P),d.push(h,b,P)):F===B&&(w=Math.min(b,P)+" "+Math.max(b,P),h=y[w],n(h)||(T=t.add(M,A,se),t.multiplyByScalar(T,.5,T),f.push(T.x,T.y,T.z),h=f.length/3-1,y[w]=h),d.push(b,h,x),d.push(h,P,x)):(g.push(P),g.push(x),g.push(b))}return new l({attributes:{position:new u({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:f})},indices:g,primitiveType:p.TRIANGLES})},ee.scaleToGeodeticHeight=function(e,r,o,s){o=i(o,a.WGS84);var l=Q,u=$;if(r=i(r,0),s=i(s,!0),n(e)&&n(e.attributes)&&n(e.attributes.position))for(var c=e.attributes.position.values,h=c.length,d=0;h>d;d+=3)t.fromArray(c,d,u),s&&(u=o.scaleToGeodeticSurface(u,u)),l=o.geodeticSurfaceNormal(u,l),t.multiplyByScalar(l,r,l),t.add(u,l,u),c[d]=u.x,c[d+1]=u.y,c[d+2]=u.z;return e},ee.eliminateHoles=function(e,r,n){n=i(n,a.WGS84);for(var o=[],s=0;s<r.length;s++){for(var l=[],u=0;u<r[s].length;u++)l.push(t.clone(r[s][u]));o.push(l)}for(var c=e;o.length>0;)c=w(c,o,n);return c},ee}),r("Core/PolygonGeometryLibrary",["./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolygonPipeline","./PrimitiveType","./Queue","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(t,r,i,n){return e.subtract(r,t,_),e.multiplyByScalar(_,i/n,_),e.add(t,_,_),[_.x,_.y,_.z]}var v={};v.computeHierarchyPackedLength=function(t){for(var r=0,n=[t];n.length>0;){var o=n.pop();if(i(o)){r+=2;var a=o.positions,s=o.holes;if(i(a)&&(r+=a.length*e.packedLength),i(s))for(var l=s.length,u=0;l>u;++u)n.push(s[u])}}return r},v.packPolygonHierarchy=function(t,r,n){for(var o=[t];o.length>0;){var a=o.pop();if(i(a)){var s=a.positions,l=a.holes;if(r[n++]=i(s)?s.length:0,r[n++]=i(l)?l.length:0,i(s))for(var u=s.length,c=0;u>c;++c,n+=3)e.pack(s[c],r,n);if(i(l))for(var h=l.length,d=0;h>d;++d)o.push(l[d])}}return n},v.unpackPolygonHierarchy=function(t,r){for(var i=t[r++],n=t[r++],o=new Array(i),a=n>0?new Array(n):void 0,s=0;i>s;++s,r+=e.packedLength)o[s]=e.unpack(t,r);for(var l=0;n>l;++l)a[l]=v.unpackPolygonHierarchy(t,r),r=a[l].startingIndex,delete a[l].startingIndex;return{positions:o,holes:a,startingIndex:r}};var _=new e;v.subdivideLineCount=function(t,r,i){var n=e.distance(t,r),o=n/i,a=Math.max(0,Math.ceil(Math.log(o)/Math.log(2)));return Math.pow(2,a)},v.subdivideLine=function(t,r,n,o){var a=v.subdivideLineCount(t,r,n),s=e.distance(t,r),l=s/a;i(o)||(o=[]);var u=o;u.length=3*a;for(var c=0,h=0;a>h;h++){var d=f(t,r,h*l,s);u[c++]=d[0],u[c++]=d[1],u[c++]=d[2]}return u};var g=new e,y=new e,C=new e,E=new e;v.scaleToGeodeticHeightExtruded=function(t,o,a,s,l){s=r(s,n.WGS84);var u=g,c=y,h=C,d=E;if(i(t)&&i(t.attributes)&&i(t.attributes.position))for(var p=t.attributes.position.values,m=p.length/2,f=0;m>f;f+=3)e.fromArray(p,f,h),s.geodeticSurfaceNormal(h,u),d=s.scaleToGeodeticSurface(h,d),c=e.multiplyByScalar(u,a,c),c=e.add(d,c,c),p[f+m]=c.x,p[f+1+m]=c.y,p[f+2+m]=c.z,l&&(d=e.clone(h,d)),c=e.multiplyByScalar(u,o,c),c=e.add(d,c,c),p[f]=c.x,p[f+1]=c.y,p[f+2]=c.z;return t},v.polygonsFromHierarchy=function(e){var t=[],r=[],n=new p;for(n.enqueue(e);0!==n.length;){var o=n.dequeue(),a=o.positions,s=o.holes;if(a=h.removeDuplicates(a),!(a.length<3)){for(var l=i(s)?s.length:0,u=[],c=0;l>c;c++){var d=s[c];if(d.positions=h.removeDuplicates(d.positions),!(d.positions.length<3)){u.push(d.positions);var m=0;i(d.holes)&&(m=d.holes.length);for(var f=0;m>f;f++)n.enqueue(d.holes[f])}}r.push({outerRing:a,holes:u});var v=u.length>0?h.eliminateHoles(a,u):a;t.push(v)}}return{hierarchy:r,polygons:t}};var S=[];v.createGeometryFromPositions=function(e,r,i,n){var l=o.fromPoints(r,e),u=l.projectPointsOntoPlane(r,S),c=h.computeWindingOrder2D(u);c===m.CLOCKWISE&&(u.reverse(),r=r.slice().reverse());var p=h.triangulate(u);if(p.length<3&&(p=[0,1,2]),n){for(var f=r.length,v=new Array(3*f),_=0,g=0;f>g;g++){var y=r[g];v[_++]=y.x,v[_++]=y.y,v[_++]=y.z}return new a({attributes:{position:new s({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:v})},indices:p,primitiveType:d.TRIANGLES})}return h.computeSubdivision(e,r,p,i)};var w=[],T=new e,b=new e;return v.computeWallGeometry=function(r,i,n,o){var h,p,m,f,_,g=r.length,y=0;if(o)for(p=3*g*2,h=new Array(2*p),m=0;g>m;m++)f=r[m],_=r[(m+1)%g],h[y]=h[y+p]=f.x,++y,h[y]=h[y+p]=f.y,++y,h[y]=h[y+p]=f.z,++y,h[y]=h[y+p]=_.x,++y,h[y]=h[y+p]=_.y,++y,h[y]=h[y+p]=_.z,++y;else{var C=c.chordLength(n,i.maximumRadius),E=0;for(m=0;g>m;m++)E+=v.subdivideLineCount(r[m],r[(m+1)%g],C);for(p=3*(E+g),h=new Array(2*p),m=0;g>m;m++){f=r[m],_=r[(m+1)%g];for(var S=v.subdivideLine(f,_,C,w),x=S.length,P=0;x>P;++P,++y)h[y]=S[P],h[y+p]=S[P];h[y]=_.x,h[y+p]=_.x,++y,h[y]=_.y,h[y+p]=_.y,++y,h[y]=_.z,h[y+p]=_.z,++y}}g=h.length;var A=u.createTypedArray(g/3,g-6*r.length),I=0;for(g/=6,m=0;g>m;m++){var M=m,D=M+1,R=M+g,O=R+1;f=e.fromArray(h,3*M,T),_=e.fromArray(h,3*D,b),e.equalsEpsilon(f,_,c.EPSILON14)||(A[I++]=M,A[I++]=R,A[I++]=D,A[I++]=D,A[I++]=R,A[I++]=O)}return new a({attributes:new l({position:new s({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:h})}),indices:A,primitiveType:d.TRIANGLES})},v}),r("Core/PolygonGeometry",["./BoundingRectangle","./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./Matrix3","./PolygonGeometryLibrary","./PolygonPipeline","./Quaternion","./VertexFormat","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";function w(e,t,r,n){for(var o=C.fromAxisAngle(e._plane.normal,r,A),s=_.fromQuaternion(o,I),l=Number.POSITIVE_INFINITY,u=Number.NEGATIVE_INFINITY,c=Number.POSITIVE_INFINITY,h=Number.NEGATIVE_INFINITY,d=t.length,p=0;d>p;++p){var m=i.clone(t[p],P);_.multiplyByVector(s,m,m);var f=e.projectPointOntoPlane(m,x);a(f)&&(l=Math.min(l,f.x),u=Math.max(u,f.x),c=Math.min(c,f.y),h=Math.max(h,f.y))}return n.x=l,n.y=c,n.width=u-l,n.height=h-c,n}function T(e,t,o,a,s,l,c){if(e.st||e.normal||e.tangent||e.binormal){var d=u.fromPoints(o,a),p=w(d,o,s,M),m=B;m.x=p.x,m.y=p.y;var f=t.attributes.position.values,g=f.length,y=e.st?new Float32Array(2*(g/3)):void 0,E=e.normal?new Float32Array(g):void 0,S=e.tangent?new Float32Array(g):void 0,T=e.binormal?new Float32Array(g):void 0,b=0,x=0,P=R,A=O,I=N,G=!0,W=C.fromAxisAngle(d._plane.normal,s,k),H=_.fromQuaternion(W,U),q=g/2,j=g/3;l&&(g/=2);for(var Y=0;g>Y;Y+=3){var X=i.fromArray(f,Y,z);if(e.st){var Z=_.multiplyByVector(H,X,D),K=d.projectPointOntoPlane(Z,V);r.subtract(K,m,K),l&&(y[b+j]=K.x/p.width,y[b+1+j]=K.y/p.height),y[b]=K.x/p.width,y[b+1]=K.y/p.height,b+=2}if(e.normal||e.tangent||e.binormal){var J=x+1,Q=x+2;if(c){if(g>Y+3){var $=i.fromArray(f,Y+3,L);if(G){var ee=i.fromArray(f,Y+g,F);i.subtract($,X,$), -i.subtract(ee,X,ee),P=i.normalize(i.cross(ee,$,P),P),G=!1}i.equalsEpsilon($,X,v.EPSILON10)&&(G=!0)}(e.tangent||e.binormal)&&(I=a.geodeticSurfaceNormal(X,I),e.tangent&&(A=i.normalize(i.cross(I,P,A),A)))}else P=a.geodeticSurfaceNormal(X,P),(e.tangent||e.binormal)&&(A=i.cross(i.UNIT_Z,P,A),A=i.normalize(_.multiplyByVector(H,A,A),A),e.binormal&&(I=i.normalize(i.cross(P,A,I),I)));e.normal&&(l&&!c?(E[x+q]=-P.x,E[J+q]=-P.y,E[Q+q]=-P.z):(E[x+q]=P.x,E[J+q]=P.y,E[Q+q]=P.z),E[x]=P.x,E[J]=P.y,E[Q]=P.z),e.tangent&&(l&&!c?(S[x+q]=-A.x,S[J+q]=-A.y,S[Q+q]=-A.z):(S[x+q]=A.x,S[J+q]=A.y,S[Q+q]=A.z),S[x]=A.x,S[J]=A.y,S[Q]=A.z),e.binormal&&(l&&(T[x+q]=I.x,T[J+q]=I.y,T[Q+q]=I.z),T[x]=I.x,T[J]=I.y,T[Q]=I.z),x+=3}}e.st&&(t.attributes.st=new h({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:y})),e.normal&&(t.attributes.normal=new h({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:E})),e.tangent&&(t.attributes.tangent=new h({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:S})),e.binormal&&(t.attributes.binormal=new h({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:T}))}return t}function b(e,t,r,i,o){var a=g.createGeometryFromPositions(e,t,r,o),s=a.attributes.position.values,l=a.indices,m=s.concat(s),v=m.length/3,_=f.createTypedArray(v,2*l.length);_.set(l);var C,E=l.length,w=v/2;for(C=0;E>C;C+=3){var T=_[C]+w,b=_[C+1]+w,x=_[C+2]+w;_[C+E]=x,_[C+1+E]=b,_[C+2+E]=T}var P=new c({attributes:new d({position:new h({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:m})}),indices:_,primitiveType:a.primitiveType}),A={topAndBottom:new p({geometry:P}),walls:[]},I=i.outerRing,M=u.fromPoints(I,e),D=M.projectPointsOntoPlane(I,G),R=y.computeWindingOrder2D(D);R===S.CLOCKWISE&&(I=I.slice().reverse());var O=g.computeWallGeometry(I,e,r,o);A.walls.push(new p({geometry:O}));var N=i.holes;for(C=0;C<N.length;C++){var L=N[C];M=u.fromPoints(L,e),D=M.projectPointsOntoPlane(L,G),R=y.computeWindingOrder2D(D),R===S.COUNTER_CLOCKWISE&&(L=L.slice().reverse()),O=g.computeWallGeometry(L,e,r),A.walls.push(new p({geometry:O}))}return A}var x=new r,P=new i,A=new C,I=new _,M=new e,D=new i,R=new i,O=new i,N=new i,L=new i,F=new i,B=new r,V=new r,z=new i,k=new C,U=new _,G=[],W=function(e){var t=e.polygonHierarchy,r=o(e.vertexFormat,E.DEFAULT),i=o(e.ellipsoid,l.WGS84),n=o(e.granularity,v.RADIANS_PER_DEGREE),s=o(e.stRotation,0),u=o(e.height,0),c=o(e.perPositionHeight,!1),h=e.extrudedHeight,d=a(h);if(d&&!c){var p=h;h=Math.min(p,u),u=Math.max(p,u)}this._vertexFormat=E.clone(r),this._ellipsoid=l.clone(i),this._granularity=n,this._stRotation=s,this._height=u,this._extrudedHeight=o(h,0),this._extrude=d,this._polygonHierarchy=t,this._perPositionHeight=c,this._workerName="createPolygonGeometry",this.packedLength=g.computeHierarchyPackedLength(t)+l.packedLength+E.packedLength+7};W.fromPositions=function(e){e=o(e,o.EMPTY_OBJECT);var t={polygonHierarchy:{positions:e.positions},height:e.height,extrudedHeight:e.extrudedHeight,vertexFormat:e.vertexFormat,stRotation:e.stRotation,ellipsoid:e.ellipsoid,granularity:e.granularity,perPositionHeight:e.perPositionHeight};return new W(t)},W.pack=function(e,t,r){r=o(r,0),r=g.packPolygonHierarchy(e._polygonHierarchy,t,r),l.pack(e._ellipsoid,t,r),r+=l.packedLength,E.pack(e._vertexFormat,t,r),r+=E.packedLength,t[r++]=e._height,t[r++]=e._extrudedHeight,t[r++]=e._granularity,t[r++]=e._stRotation,t[r++]=e._extrude?1:0,t[r++]=e._perPositionHeight?1:0,t[r]=e.packedLength};var H=l.clone(l.UNIT_SPHERE),q=new E,j={polygonHierarchy:{}};return W.unpack=function(e,t,r){t=o(t,0);var i=g.unpackPolygonHierarchy(e,t);t=i.startingIndex,delete i.startingIndex;var n=l.unpack(e,t,H);t+=l.packedLength;var s=E.unpack(e,t,q);t+=E.packedLength;var u=e[t++],c=e[t++],h=e[t++],d=e[t++],p=1===e[t++],m=1===e[t++],f=e[t];return a(r)||(r=new W(j)),r._polygonHierarchy=i,r._ellipsoid=l.clone(n,r._ellipsoid),r._vertexFormat=E.clone(s,r._vertexFormat),r._height=u,r._extrudedHeight=c,r._granularity=h,r._stRotation=d,r._extrude=p,r._perPositionHeight=m,r.packedLength=f,r},W.createGeometry=function(e){var r,i,n,o=e._vertexFormat,a=e._ellipsoid,s=e._granularity,l=e._stRotation,u=e._height,h=e._extrudedHeight,d=e._extrude,v=e._polygonHierarchy,_=e._perPositionHeight,C=g.polygonsFromHierarchy(v),E=C.hierarchy,S=C.polygons;if(0===S.length)return void 0;n=S[0];var w,x,P=[];if(d)for(x=0;x<S.length;x++){w=b(a,S[x],s,E[x],_),i=w.topAndBottom,i.geometry=g.scaleToGeodeticHeightExtruded(i.geometry,u,h,a,_),i.geometry=T(o,i.geometry,n,a,l,!0,!1),P.push(i),r=w.walls;for(var A=0;A<r.length;A++){var I=r[A];I.geometry=g.scaleToGeodeticHeightExtruded(I.geometry,u,h,a,_),I.geometry=T(o,I.geometry,n,a,l,!0,!0),P.push(I)}}else for(x=0;x<S.length;x++)w=new p({geometry:g.createGeometryFromPositions(a,S[x],s,_)}),w.geometry=y.scaleToGeodeticHeight(w.geometry,u,a,!_),w.geometry=T(o,w.geometry,n,a,l,!1,!1),P.push(w);w=m.combineInstances(P)[0],w.attributes.position.values=new Float64Array(w.attributes.position.values),w.indices=f.createTypedArray(w.attributes.position.values.length/3,w.indices);var M=w.attributes,D=t.fromVertices(M.position.values);return o.position||delete M.position,new c({attributes:M,indices:w.indices,primitiveType:w.primitiveType,boundingSphere:D})},W.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new W({polygonHierarchy:e._polygonHierarchy,ellipsoid:n,stRotation:e._stRotation,granularity:i,perPositionHeight:!1,extrudedHeight:o,height:a,vertexFormat:E.POSITION_ONLY})},W}),r("Core/PolygonHierarchy",["./defined"],function(e){"use strict";var t=function(t,r){this.positions=e(t)?t:[],this.holes=e(r)?r:[]};return t}),r("Core/PolygonOutlineGeometry",["./BoundingSphere","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./EllipsoidTangentPlane","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./PolygonGeometryLibrary","./PolygonPipeline","./PrimitiveType","./Queue","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g){"use strict";function y(e,r,i,n){var o=a.fromPoints(r,e),h=o.projectPointsOntoPlane(r,E),p=f.computeWindingOrder2D(h);p===g.CLOCKWISE&&(h.reverse(),r=r.slice().reverse());var _,y,C=r.length,w=0;if(n)for(_=new Float64Array(2*C*3),y=0;C>y;y++){var T=r[y],b=r[(y+1)%C];_[w++]=T.x,_[w++]=T.y,_[w++]=T.z,_[w++]=b.x,_[w++]=b.y,_[w++]=b.z}else{var x=0;for(y=0;C>y;y++)x+=m.subdivideLineCount(r[y],r[(y+1)%C],i);for(_=new Float64Array(3*x),y=0;C>y;y++)for(var P=m.subdivideLine(r[y],r[(y+1)%C],i,S),A=P.length,I=0;A>I;++I)_[w++]=P[I]}C=_.length/3;var M=2*C,D=d.createTypedArray(C,M);for(w=0,y=0;C-1>y;y++)D[w++]=y,D[w++]=y+1;return D[w++]=C-1,D[w++]=0,new c({geometry:new s({attributes:new u({position:new l({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:_})}),indices:D,primitiveType:v.LINES})})}function C(e,r,i,n){var o=a.fromPoints(r,e),h=o.projectPointsOntoPlane(r,E),p=f.computeWindingOrder2D(h);p===g.CLOCKWISE&&(h.reverse(),r=r.slice().reverse());var _,y,C=r.length,w=new Array(C),T=0;if(n)for(_=new Float64Array(2*C*3*2),y=0;C>y;++y){w[y]=T/3;var b=r[y],x=r[(y+1)%C];_[T++]=b.x,_[T++]=b.y,_[T++]=b.z,_[T++]=x.x,_[T++]=x.y,_[T++]=x.z}else{var P=0;for(y=0;C>y;y++)P+=m.subdivideLineCount(r[y],r[(y+1)%C],i);for(_=new Float64Array(3*P*2),y=0;C>y;++y){w[y]=T/3;for(var A=m.subdivideLine(r[y],r[(y+1)%C],i,S),I=A.length,M=0;I>M;++M)_[T++]=A[M]}}C=_.length/6;var D=w.length,R=2*(2*C+D),O=d.createTypedArray(C,R);for(T=0,y=0;C>y;++y)O[T++]=y,O[T++]=(y+1)%C,O[T++]=y+C,O[T++]=(y+1)%C+C;for(y=0;D>y;y++){var N=w[y];O[T++]=N,O[T++]=N+C}return new c({geometry:new s({attributes:new u({position:new l({componentDatatype:t.DOUBLE,componentsPerAttribute:3,values:_})}),indices:O,primitiveType:v.LINES})})}var E=[],S=[],w=function(e){var t=e.polygonHierarchy,n=r(e.ellipsoid,o.WGS84),a=r(e.granularity,p.RADIANS_PER_DEGREE),s=r(e.height,0),l=r(e.perPositionHeight,!1),u=e.extrudedHeight,c=i(u);if(c&&!l){var h=u;u=Math.min(h,s),s=Math.max(h,s)}this._ellipsoid=o.clone(n),this._granularity=a,this._height=s,this._extrudedHeight=r(u,0),this._extrude=c,this._polygonHierarchy=t,this._perPositionHeight=l,this._workerName="createPolygonOutlineGeometry",this.packedLength=m.computeHierarchyPackedLength(t)+o.packedLength+6};w.pack=function(e,t,i){i=r(i,0),i=m.packPolygonHierarchy(e._polygonHierarchy,t,i),o.pack(e._ellipsoid,t,i),i+=o.packedLength,t[i++]=e._height,t[i++]=e._extrudedHeight,t[i++]=e._granularity,t[i++]=e._extrude?1:0,t[i++]=e._perPositionHeight?1:0,t[i++]=e.packedLength};var T=o.clone(o.UNIT_SPHERE),b={polygonHierarchy:{}};return w.unpack=function(e,t,n){t=r(t,0);var a=m.unpackPolygonHierarchy(e,t);t=a.startingIndex,delete a.startingIndex;var s=o.unpack(e,t,T);t+=o.packedLength;var l=e[t++],u=e[t++],c=e[t++],h=1===e[t++],d=1===e[t++],p=e[t++];return i(n)||(n=new w(b)),n._polygonHierarchy=a,n._ellipsoid=o.clone(s,n._ellipsoid),n._height=l,n._extrudedHeight=u,n._granularity=c,n._extrude=h,n._perPositionHeight=d,n.packedLength=p,n},w.fromPositions=function(e){e=r(e,r.EMPTY_OBJECT);var t={polygonHierarchy:{positions:e.positions},height:e.height,extrudedHeight:e.extrudedHeight,ellipsoid:e.ellipsoid,granularity:e.granularity,perPositionHeight:e.perPositionHeight};return new w(t)},w.createGeometry=function(t){var r=t._ellipsoid,n=t._granularity,o=t._height,a=t._extrudedHeight,l=t._extrude,u=t._polygonHierarchy,c=t._perPositionHeight,d=[],v=new _;v.enqueue(u);for(var g;0!==v.length;){var E=v.dequeue(),S=E.positions;if(S=f.removeDuplicates(S),!(S.length<3)){var w=E.holes?E.holes.length:0;for(g=0;w>g;g++){var T=E.holes[g];if(T.positions=f.removeDuplicates(T.positions),!(T.positions.length<3)){d.push(T.positions);var b=0;i(T.holes)&&(b=T.holes.length);for(var x=0;b>x;x++)v.enqueue(T.holes[x])}}d.push(S)}}if(0===d.length)return void 0;var P,A=[],I=p.chordLength(n,r.maximumRadius);if(l)for(g=0;g<d.length;g++)P=C(r,d[g],I,c),P.geometry=m.scaleToGeodeticHeightExtruded(P.geometry,o,a,r,c),A.push(P);else for(g=0;g<d.length;g++)P=y(r,d[g],I,c),P.geometry=f.scaleToGeodeticHeight(P.geometry,o,r,!c),A.push(P);P=h.combineInstances(A)[0];var M=e.fromVertices(P.attributes.position.values);return new s({attributes:P.attributes,indices:P.indices,primitiveType:P.primitiveType,boundingSphere:M})},w}),r("Core/PolylineGeometry",["./BoundingSphere","./Cartesian3","./Color","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryType","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e,t,i,n,o){var a=g;a.length=o;var s,l=i.red,u=i.green,c=i.blue,h=i.alpha,d=n.red,p=n.green,m=n.blue,f=n.alpha;if(r.equals(i,n)){for(s=0;o>s;s++)a[s]=r.clone(i);return a}var v=(d-l)/o,_=(p-u)/o,y=(m-c)/o,C=(f-h)/o;for(s=0;o>s;s++)a[s]=new r(l+s*v,u+s*_,c+s*y,h+s*C);return a}var g=[],y=function(e){e=n(e,n.EMPTY_OBJECT);var i=e.positions,a=e.colors,l=n(e.width,1),u=n(e.colorsPerVertex,!1);this._positions=i,this._colors=a,this._width=l,this._colorsPerVertex=u,this._vertexFormat=v.clone(n(e.vertexFormat,v.DEFAULT)),this._followSurface=n(e.followSurface,!0),this._granularity=n(e.granularity,p.RADIANS_PER_DEGREE),this._ellipsoid=s.clone(n(e.ellipsoid,s.WGS84)),this._workerName="createPolylineGeometry";var c=1+i.length*t.packedLength;c+=o(a)?1+a.length*r.packedLength:1,this.packedLength=c+s.packedLength+v.packedLength+4};y.pack=function(e,i,a){a=n(a,0);var l,u=e._positions,c=u.length;for(i[a++]=c,l=0;c>l;++l,a+=t.packedLength)t.pack(u[l],i,a);var h=e._colors;for(c=o(h)?h.length:0,i[a++]=c,l=0;c>l;++l,a+=r.packedLength)r.pack(h[l],i,a);s.pack(e._ellipsoid,i,a),a+=s.packedLength,v.pack(e._vertexFormat,i,a),a+=v.packedLength,i[a++]=e._width,i[a++]=e._colorsPerVertex?1:0,i[a++]=e._followSurface?1:0,i[a]=e._granularity};var C=s.clone(s.UNIT_SPHERE),E=new v,S={positions:void 0,colors:void 0,ellipsoid:C,vertexFormat:E,width:void 0,colorsPerVertex:void 0,followSurface:void 0,granularity:void 0};y.unpack=function(e,i,a){i=n(i,0);var l,u=e[i++],c=new Array(u);for(l=0;u>l;++l,i+=t.packedLength)c[l]=t.unpack(e,i);u=e[i++];var h=u>0?new Array(u):void 0;for(l=0;u>l;++l,i+=r.packedLength)h[l]=r.unpack(e,i);var d=s.unpack(e,i,C);i+=s.packedLength;var p=v.unpack(e,i,E);i+=v.packedLength;var m=e[i++],f=1===e[i++],_=1===e[i++],g=e[i];return o(a)?(a._positions=c,a._colors=h,a._ellipsoid=s.clone(d,a._ellipsoid),a._vertexFormat=v.clone(p,a._vertexFormat),a._width=m,a._colorsPerVertex=f,a._followSurface=_,a._granularity=g,a):(S.positions=c,S.colors=h,S.width=m,S.colorsPerVertex=f,S.followSurface=_,S.granularity=g,new y(S))};var w=new t,T=new t,b=new t,x=new t;return y.createGeometry=function(n){var a,s,v,y=n._width,C=n._vertexFormat,E=n._colors,S=n._colorsPerVertex,P=n._followSurface,A=n._granularity,I=n._ellipsoid,M=p.chordLength(A,I.maximumRadius),D=m.removeDuplicates(n._positions),R=D.length;if(2>R)return void 0;if(P){var O=m.extractHeights(D,I);if(o(E)){var N=1;for(a=0;R-1>a;++a)N+=m.numberOfPoints(D[a],D[a+1],M);var L=new Array(N),F=0;for(a=0;R-1>a;++a){var B=D[a],V=D[a+1],z=E[a],k=m.numberOfPoints(B,V,M);if(S&&N>a){var U=E[a+1],G=_(B,V,z,U,k),W=G.length;for(s=0;W>s;++s)L[F++]=G[s]}else for(s=0;k>s;++s)L[F++]=r.clone(z)}L[F]=r.clone(E[E.length-1]),E=L,g.length=0}D=m.generateCartesianArc({positions:D,minDistance:M,ellipsoid:I,height:O})}R=D.length;var H,q=4*R-4,j=new Float64Array(3*q),Y=new Float64Array(3*q),X=new Float64Array(3*q),Z=new Float32Array(2*q),K=C.st?new Float32Array(2*q):void 0,J=o(E)?new Uint8Array(4*q):void 0,Q=0,$=0,ee=0,te=0;for(s=0;R>s;++s){0===s?(H=w,t.subtract(D[0],D[1],H),t.add(D[0],H,H)):H=D[s-1],t.clone(H,b),t.clone(D[s],T),s===R-1?(H=w,t.subtract(D[R-1],D[R-2],H),t.add(D[R-1],H,H)):H=D[s+1],t.clone(H,x);var re,ie;o(J)&&(re=0===s||S?E[s]:E[s-1],s!==R-1&&(ie=E[s]));var ne=0===s?2:0,oe=s===R-1?2:4;for(v=ne;oe>v;++v){t.pack(T,j,Q),t.pack(b,Y,Q),t.pack(x,X,Q),Q+=3;var ae=0>v-2?-1:1;if(Z[$++]=2*(v%2)-1,Z[$++]=ae*y,C.st&&(K[ee++]=s/(R-1),K[ee++]=Math.max(Z[$-2],0)),o(J)){var se=2>v?re:ie;J[te++]=r.floatToByte(se.red),J[te++]=r.floatToByte(se.green),J[te++]=r.floatToByte(se.blue),J[te++]=r.floatToByte(se.alpha)}}}var le=new c;le.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:j}),le.prevPosition=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:Y}),le.nextPosition=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:X}),le.expandAndWidth=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:Z}),C.st&&(le.st=new u({componentDatatype:i.FLOAT,componentsPerAttribute:2,values:K})),o(J)&&(le.color=new u({componentDatatype:i.UNSIGNED_BYTE,componentsPerAttribute:4,values:J,normalize:!0}));var ue=d.createTypedArray(q,6*R-6),ce=0,he=0,de=R-1;for(s=0;de>s;++s)ue[he++]=ce,ue[he++]=ce+2,ue[he++]=ce+1,ue[he++]=ce+1,ue[he++]=ce+2,ue[he++]=ce+3,ce+=4;return new l({attributes:le,indices:ue,primitiveType:f.TRIANGLES,boundingSphere:e.fromPoints(D),geometryType:h.POLYLINES})},y}),r("Core/PolylineVolumeGeometry",["./BoundingRectangle","./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CornerType","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryPipeline","./IndexDatatype","./Math","./PolygonPipeline","./PolylineVolumeGeometryLibrary","./PrimitiveType","./VertexFormat","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";function E(e,r,i,o){var a=new d;o.position&&(a.position=new h({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:e}));var s,l,u,f,_,y,C=r.length,E=e.length/3,S=(E-2*C)/(2*C),w=v.triangulate(r),T=(S-1)*C*6+2*w.length,b=m.createTypedArray(E,T),x=2*C,P=0;for(s=0;S-1>s;s++){for(l=0;C-1>l;l++)u=2*l+s*C*2,y=u+x,f=u+1,_=f+x,b[P++]=f,b[P++]=u,b[P++]=_,b[P++]=_,b[P++]=u,b[P++]=y;u=2*C-2+s*C*2,f=u+1,_=f+x,y=u+x,b[P++]=f,b[P++]=u,b[P++]=_,b[P++]=_,b[P++]=u,b[P++]=y}if(o.st||o.tangent||o.binormal){var A,I,M=new Float32Array(2*E),D=1/(S-1),R=1/i.height,O=i.height/2,N=0;for(s=0;S>s;s++){for(A=s*D,I=R*(r[0].y+O),M[N++]=A,M[N++]=I,l=1;C>l;l++)I=R*(r[l].y+O),M[N++]=A,M[N++]=I,M[N++]=A,M[N++]=I;I=R*(r[0].y+O),M[N++]=A,M[N++]=I}for(l=0;C>l;l++)A=0,I=R*(r[l].y+O),M[N++]=A,M[N++]=I;for(l=0;C>l;l++)A=(S-1)*D,I=R*(r[l].y+O),M[N++]=A,M[N++]=I;a.st=new h({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:new Float32Array(M)})}var L=E-2*C;for(s=0;s<w.length;s+=3){var F=w[s]+L,B=w[s+1]+L,V=w[s+2]+L;b[P++]=F,b[P++]=B,b[P++]=V,b[P++]=V+C,b[P++]=B+C,b[P++]=F+C}var z=new c({attributes:a,indices:b,boundingSphere:t.fromVertices(e),primitiveType:g.TRIANGLES});return o.normal&&(z=p.computeNormal(z)),(o.tangent||o.binormal)&&(z=p.computeBinormalAndTangent(z),o.tangent||(z.attributes.tangent=void 0),o.binormal||(z.attributes.binormal=void 0),o.st||(z.attributes.st=void 0)),z}var S=function(e){e=a(e,a.EMPTY_OBJECT);var t=e.polylinePositions,n=e.shapePositions;this._positions=t,this._shape=n,this._ellipsoid=u.clone(a(e.ellipsoid,u.WGS84)),this._cornerType=a(e.cornerType,o.ROUNDED),this._vertexFormat=y.clone(a(e.vertexFormat,y.DEFAULT)),this._granularity=a(e.granularity,f.RADIANS_PER_DEGREE),this._workerName="createPolylineVolumeGeometry";var s=1+t.length*i.packedLength;s+=1+n.length*r.packedLength,this.packedLength=s+u.packedLength+y.packedLength+2};S.pack=function(e,t,n){n=a(n,0);var o,s=e._positions,l=s.length;for(t[n++]=l,o=0;l>o;++o,n+=i.packedLength)i.pack(s[o],t,n);var c=e._shape;for(l=c.length,t[n++]=l,o=0;l>o;++o,n+=r.packedLength)r.pack(c[o],t,n);u.pack(e._ellipsoid,t,n),n+=u.packedLength,y.pack(e._vertexFormat,t,n),n+=y.packedLength,t[n++]=e._cornerType,t[n]=e._granularity};var w=u.clone(u.UNIT_SPHERE),T=new y,b={polylinePositions:void 0,shapePositions:void 0,ellipsoid:w,vertexFormat:T,cornerType:void 0,granularity:void 0};S.unpack=function(e,t,n){t=a(t,0);var o,l=e[t++],c=new Array(l);for(o=0;l>o;++o,t+=i.packedLength)c[o]=i.unpack(e,t);l=e[t++];var h=new Array(l);for(o=0;l>o;++o,t+=r.packedLength)h[o]=r.unpack(e,t);var d=u.unpack(e,t,w);t+=u.packedLength;var p=y.unpack(e,t,T);t+=y.packedLength;var m=e[t++],f=e[t];return s(n)?(n._positions=c,n._shape=h,n._ellipsoid=u.clone(d,n._ellipsoid),n._vertexFormat=y.clone(p,n._vertexFormat),n._cornerType=m,n._granularity=f,n):(b.polylinePositions=c,b.shapePositions=h,b.cornerType=m,b.granularity=f,new S(b))};var x=new e;return S.createGeometry=function(t){var r=t._positions,i=_.removeDuplicatesFromPositions(r,t._ellipsoid),n=t._shape;if(n=_.removeDuplicatesFromShape(n),i.length<2||n.length<3)return void 0;v.computeWindingOrder2D(n)===C.CLOCKWISE&&n.reverse();var o=e.fromPoints(n,x),a=_.computePositions(i,n,o,t,!0);return E(a,n,o,t._vertexFormat)},S}),r("Core/PolylineVolumeOutlineGeometry",["./BoundingRectangle","./BoundingSphere","./Cartesian2","./Cartesian3","./ComponentDatatype","./CornerType","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolygonPipeline","./PolylineVolumeGeometryLibrary","./PrimitiveType","./WindingOrder"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g){"use strict";function y(e,r){var i=new d;i.position=new h({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:e});var o,a,s=r.length,l=i.position.values.length/3,u=e.length/3,m=u/s,f=p.createTypedArray(l,2*s*(m+1)),v=0;o=0;var g=o*s;for(a=0;s-1>a;a++)f[v++]=a+g,f[v++]=a+g+1;for(f[v++]=s-1+g,f[v++]=g,o=m-1,g=o*s,a=0;s-1>a;a++)f[v++]=a+g,f[v++]=a+g+1;for(f[v++]=s-1+g,f[v++]=g,o=0;m-1>o;o++){var y=s*o,C=y+s;for(a=0;s>a;a++)f[v++]=a+y,f[v++]=a+C}var E=new c({attributes:i,indices:p.createTypedArray(l,f),boundingSphere:t.fromVertices(e),primitiveType:_.LINES});return E}var C=function(e){e=a(e,a.EMPTY_OBJECT);var t=e.polylinePositions,n=e.shapePositions;this._positions=t,this._shape=n,this._ellipsoid=u.clone(a(e.ellipsoid,u.WGS84)),this._cornerType=a(e.cornerType,o.ROUNDED),this._granularity=a(e.granularity,m.RADIANS_PER_DEGREE),this._workerName="createPolylineVolumeOutlineGeometry";var s=1+t.length*i.packedLength;s+=1+n.length*r.packedLength,this.packedLength=s+u.packedLength+2};C.pack=function(e,t,n){n=a(n,0);var o,s=e._positions,l=s.length;for(t[n++]=l,o=0;l>o;++o,n+=i.packedLength)i.pack(s[o],t,n);var c=e._shape;for(l=c.length,t[n++]=l,o=0;l>o;++o,n+=r.packedLength)r.pack(c[o],t,n);u.pack(e._ellipsoid,t,n),n+=u.packedLength,t[n++]=e._cornerType,t[n]=e._granularity};var E=u.clone(u.UNIT_SPHERE),S={polylinePositions:void 0,shapePositions:void 0,ellipsoid:E,height:void 0,cornerType:void 0,granularity:void 0};C.unpack=function(e,t,n){t=a(t,0);var o,l=e[t++],c=new Array(l);for(o=0;l>o;++o,t+=i.packedLength)c[o]=i.unpack(e,t);l=e[t++];var h=new Array(l);for(o=0;l>o;++o,t+=r.packedLength)h[o]=r.unpack(e,t);var d=u.unpack(e,t,E);t+=u.packedLength;var p=e[t++],m=e[t];return s(n)?(n._positions=c,n._shape=h,n._ellipsoid=u.clone(d,n._ellipsoid),n._cornerType=p,n._granularity=m,n):(S.polylinePositions=c,S.shapePositions=h,S.cornerType=p,S.granularity=m,new C(S))};var w=new e;return C.createGeometry=function(t){var r=t._positions,i=v.removeDuplicatesFromPositions(r,t._ellipsoid),n=t._shape;if(n=v.removeDuplicatesFromShape(n),i.length<2||n.length<3)return void 0;f.computeWindingOrder2D(n)===g.CLOCKWISE&&n.reverse();var o=e.fromPoints(n,w),a=v.computePositions(i,n,o,t,!1);return y(a,n)},C}),r("Core/QuaternionSpline",["./defaultValue","./defined","./defineProperties","./DeveloperError","./Quaternion","./Spline"],function(e,t,r,i,n,o){"use strict";function a(e,r,i){var o=e.length,a=new Array(o);a[0]=t(r)?r:e[0],a[o-1]=t(i)?i:e[o-1];for(var s=1;o-1>s;++s)a[s]=n.computeInnerQuadrangle(e[s-1],e[s],e[s+1],new n);return a}function s(e){var r=e.points,i=e.innerQuadrangles,o=e.times;if(r.length<3){var a=o[0],s=1/(o[1]-a),l=r[0],u=r[1];return function(e,r){t(r)||(r=new n);var i=(e-a)*s;return n.fastSlerp(l,u,i,r)}}return function(a,s){t(s)||(s=new n);var l=e._lastTimeIndex=e.findTimeInterval(a,e._lastTimeIndex),u=(a-o[l])/(o[l+1]-o[l]),c=r[l],h=r[l+1],d=i[l],p=i[l+1];return n.fastSquad(c,h,d,p,u,s)}}var l=function(t){t=e(t,e.EMPTY_OBJECT);var r=t.points,i=t.times,n=t.firstInnerQuadrangle,o=t.lastInnerQuadrangle,l=a(r,n,o);this._times=i,this._points=r,this._innerQuadrangles=l,this._evaluateFunction=s(this),this._lastTimeIndex=0};return r(l.prototype,{times:{get:function(){return this._times}},points:{get:function(){return this._points}},innerQuadrangles:{get:function(){return this._innerQuadrangles}}}),l.prototype.findTimeInterval=o.prototype.findTimeInterval,l.prototype.evaluate=function(e,t){return this._evaluateFunction(e,t)},l}),r("Core/RectangleGeometryLibrary",["./Cartesian3","./Cartographic","./defined","./DeveloperError","./GeographicProjection","./Math","./Matrix2","./Rectangle"],function(e,t,r,i,n,o,a,s){"use strict";var l=Math.cos,u=Math.sin,c=Math.sqrt,h={};h.computePosition=function(e,t,i,n,o){var s=e.ellipsoid.radiiSquared,h=e.nwCorner,d=e.rectangle,p=h.latitude-e.granYCos*t+i*e.granXSin,m=l(p),f=u(p),v=s.z*f,_=h.longitude+t*e.granYSin+i*e.granXCos,g=m*l(_),y=m*u(_),C=s.x*g,E=s.y*y,S=c(C*g+E*y+v*f);n.x=C/S,n.y=E/S,n.z=v/S,r(e.vertexFormat)&&e.vertexFormat.st&&(o.x=(_-d.west)*e.lonScalar-.5,o.y=(p-d.south)*e.latScalar-.5,a.multiplyByVector(e.textureMatrix,o,o),o.x+=.5,o.y+=.5)};var d=new a,p=new e,m=new t,f=new e,v=new n;return h.computeOptions=function(t,n,l){var u,c,h,_,g,y=t._granularity,C=t._ellipsoid,E=t._surfaceHeight,S=t._rotation,w=t._extrudedHeight,T=n.east,b=n.west,x=n.north,P=n.south,A=x-P;b>T?(g=o.TWO_PI-b+T,u=Math.ceil(g/y)+1,c=Math.ceil(A/y)+1,h=g/(u-1),_=A/(c-1)):(g=T-b,u=Math.ceil(g/y)+1,c=Math.ceil(A/y)+1,h=g/(u-1),_=A/(c-1)),l=s.northwest(n,l);var I=s.center(n,m),M=_,D=h,R=0,O=0;if(r(S)){var N=Math.cos(S);M*=N,D*=N;var L=Math.sin(S);R=_*L,O=h*L,p=v.project(l,p),f=v.project(I,f),p=e.subtract(p,f,p);var F=a.fromRotation(S,d);p=a.multiplyByVector(F,p,p),p=e.add(p,f,p),l=v.unproject(p,l);var B=l.latitude,V=B+(u-1)*O,z=B-M*(c-1),k=B-M*(c-1)+(u-1)*O;x=Math.max(B,V,z,k),P=Math.min(B,V,z,k);var U=l.longitude,G=U+(u-1)*D,W=U+(c-1)*R,H=U+(c-1)*R+(u-1)*D;if(T=Math.max(U,G,W,H),b=Math.min(U,G,W,H),x<-o.PI_OVER_TWO||x>o.PI_OVER_TWO||P<-o.PI_OVER_TWO||P>o.PI_OVER_TWO)throw new i("Rotated extent is invalid.");n.north=x,n.south=P,n.east=T,n.west=b}return{granYCos:M,granYSin:R,granXCos:D,granXSin:O,ellipsoid:C,width:u,height:c,surfaceHeight:E,extrudedHeight:w,nwCorner:l,rectangle:n}},h}),r("Core/RectangleGeometry",["./BoundingSphere","./Cartesian2","./Cartesian3","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./GeometryInstance","./GeometryPipeline","./IndexDatatype","./Math","./Matrix2","./Matrix3","./PolygonPipeline","./PrimitiveType","./Quaternion","./Rectangle","./RectangleGeometryLibrary","./VertexFormat"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";function T(e,t){var r=new u({attributes:new h,primitiveType:y.TRIANGLES});return r.attributes.position=new c({componentDatatype:n.DOUBLE,componentsPerAttribute:3,values:t.positions}),e.normal&&(r.attributes.normal=new c({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:t.normals})),e.tangent&&(r.attributes.tangent=new c({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:t.tangents})),e.binormal&&(r.attributes.binormal=new c({componentDatatype:n.FLOAT,componentsPerAttribute:3,values:t.binormals})),r}function b(e,t,i,n){for(var o=e.length,a=t.normal?new Float32Array(o):void 0,s=t.tangent?new Float32Array(o):void 0,l=t.binormal?new Float32Array(o):void 0,u=0,c=N,h=O,d=R,p=0;o>p;p+=3){var m=r.fromArray(e,p,D),f=u+1,v=u+2;(t.normal||t.tangent||t.binormal)&&(d=i.geodeticSurfaceNormal(m,d),(t.tangent||t.binormal)&&(r.cross(r.UNIT_Z,d,h),_.multiplyByVector(n,h,h),r.normalize(h,h),t.binormal&&r.normalize(r.cross(d,h,c),c)),t.normal&&(a[u]=d.x,a[f]=d.y,a[v]=d.z),t.tangent&&(s[u]=h.x,s[f]=h.y,s[v]=h.z),t.binormal&&(l[u]=c.x,l[f]=c.y,l[v]=c.z)),u+=3}return T(t,{positions:e,normals:a,tangents:s,binormals:l})}function x(e,t,i){for(var n=e.length,o=t.normal?new Float32Array(n):void 0,a=t.tangent?new Float32Array(n):void 0,s=t.binormal?new Float32Array(n):void 0,l=0,u=0,c=0,h=!0,d=N,p=O,m=R,v=0;n>v;v+=6){var _=r.fromArray(e,v,D);if(t.normal||t.tangent||t.binormal){var g=r.fromArray(e,(v+6)%n,z);if(h){var y=r.fromArray(e,(v+3)%n,k);r.subtract(g,_,g),r.subtract(y,_,y),m=r.normalize(r.cross(y,g,m),m),h=!1}r.equalsEpsilon(g,_,f.EPSILON10)&&(h=!0),(t.tangent||t.binormal)&&(d=i.geodeticSurfaceNormal(_,d),t.tangent&&(p=r.normalize(r.cross(d,m,p),p))),t.normal&&(o[l++]=m.x,o[l++]=m.y,o[l++]=m.z,o[l++]=m.x,o[l++]=m.y,o[l++]=m.z),t.tangent&&(a[u++]=p.x,a[u++]=p.y,a[u++]=p.z,a[u++]=p.x,a[u++]=p.y,a[u++]=p.z),t.binormal&&(s[c++]=d.x,s[c++]=d.y,s[c++]=d.z,s[c++]=d.x,s[c++]=d.y,s[c++]=d.z)}}return T(t,{positions:e,normals:o,tangents:a,binormals:s})}function P(e){for(var t=e.vertexFormat,r=e.ellipsoid,i=e.size,o=e.height,a=e.width,s=t.position?new Float64Array(3*i):void 0,l=t.st?new Float32Array(2*i):void 0,u=0,h=0,d=D,p=F,f=Number.MAX_VALUE,v=Number.MAX_VALUE,_=Number.MIN_VALUE,g=Number.MIN_VALUE,y=0;o>y;++y)for(var C=0;a>C;++C)S.computePosition(e,y,C,d,p),s[u++]=d.x,s[u++]=d.y,s[u++]=d.z,t.st&&(l[h++]=p.x,l[h++]=p.y,f=Math.min(f,p.x),v=Math.min(v,p.y),_=Math.max(_,p.x),g=Math.max(g,p.y));if(t.st&&(0>f||0>v||_>1||g>1))for(var E=0;E<l.length;E+=2)l[E]=(l[E]-f)/(_-f),l[E+1]=(l[E+1]-v)/(g-v);for(var w=b(s,t,r,e.tangentRotationMatrix),T=6*(a-1)*(o-1),x=m.createTypedArray(i,T),P=0,A=0,I=0;o-1>I;++I){for(var M=0;a-1>M;++M){var R=P,O=R+a,N=O+1,L=R+1;x[A++]=R,x[A++]=O,x[A++]=L,x[A++]=L,x[A++]=O,x[A++]=N,++P}++P}return w.indices=x,t.st&&(w.attributes.st=new c({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:l})),w}function A(e,t,r,i,n){return e[t++]=i[r],e[t++]=i[r+1],e[t++]=i[r+2],e[t++]=n[r],e[t++]=n[r+1],e[t++]=n[r+2],e}function I(e,t,r,i){return e[t++]=i[r],e[t++]=i[r+1],e[t++]=i[r],e[t++]=i[r+1],e}function M(e){var t,i=e.vertexFormat,o=e.surfaceHeight,a=e.extrudedHeight,s=Math.min(a,o),l=Math.max(a,o),u=e.height,h=e.width,v=e.ellipsoid,_=P(e);if(f.equalsEpsilon(s,l,f.EPSILON10))return _;_=g.scaleToGeodeticHeight(_,l,v,!1);var y=new Float64Array(_.attributes.position.values),C=y.length,E=2*C,S=new Float64Array(E);S.set(y),_=g.scaleToGeodeticHeight(_,s,v);var w=_.attributes.position.values;S.set(w,C),_.attributes.position.values=S;var T,b=i.normal?new Float32Array(E):void 0,M=i.tangent?new Float32Array(E):void 0,D=i.binormal?new Float32Array(E):void 0,R=i.st?new Float32Array(E/3*2):void 0;if(i.normal){var O=_.attributes.normal.values;for(b.set(O),t=0;C>t;t++)O[t]=-O[t];b.set(O,C),_.attributes.normal.values=b}if(i.tangent){var N=_.attributes.tangent.values;for(M.set(N),t=0;C>t;t++)N[t]=-N[t];M.set(N,C),_.attributes.tangent.values=M}if(i.binormal){var L=_.attributes.binormal.values;D.set(L),D.set(L,C),_.attributes.binormal.values=D}i.st&&(T=_.attributes.st.values,R.set(T),R.set(T,C/3*2),_.attributes.st.values=R);var F=_.indices,B=F.length,V=C/3,U=m.createTypedArray(E/3,2*B);for(U.set(F),t=0;B>t;t+=3)U[t+B]=F[t+2]+V,U[t+1+B]=F[t+1]+V,U[t+2+B]=F[t]+V;_.indices=U;var G=2*h+2*u-4,W=2*(G+4),H=new Float64Array(3*W),q=i.st?new Float32Array(2*W):void 0,j=0,Y=0,X=h*u;for(t=0;X>t;t+=h)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);for(t=X-h;X>t;t++)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);for(t=X-1;t>0;t-=h)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);for(t=h-1;t>=0;t--)H=A(H,j,3*t,y,w),j+=6,i.st&&(q=I(q,Y,2*t,T),Y+=4);var Z=x(H,i,v);i.st&&(Z.attributes.st=new c({componentDatatype:n.FLOAT,componentsPerAttribute:2,values:q}));var K,J,Q,$,ee=m.createTypedArray(W,6*G);C=H.length/3;var te=0;for(t=0;C-1>t;t+=2){K=t,$=(K+2)%C;var re=r.fromArray(H,3*K,z),ie=r.fromArray(H,3*$,k);r.equalsEpsilon(re,ie,f.EPSILON10)||(J=(K+1)%C,Q=(J+2)%C,ee[te++]=K,ee[te++]=J,ee[te++]=$,ee[te++]=$,ee[te++]=J,ee[te++]=Q)}return Z.indices=ee,Z=p.combineInstances([new d({geometry:_}),new d({geometry:Z})]),Z[0]}var D=new r,R=new r,O=new r,N=new r,L=new E,F=new t,B=new e,V=new e,z=new r,k=new r,U=function(e){e=o(e,o.EMPTY_OBJECT);var t=e.rectangle,r=o(e.granularity,f.RADIANS_PER_DEGREE),i=o(e.ellipsoid,l.WGS84),n=o(e.height,0),s=o(e.rotation,0),u=o(e.stRotation,0),c=o(e.vertexFormat,w.DEFAULT),h=e.extrudedHeight,d=a(h),p=o(e.closeTop,!0),m=o(e.closeBottom,!0);this._rectangle=t,this._granularity=r,this._ellipsoid=l.clone(i),this._surfaceHeight=n,this._rotation=s,this._stRotation=u,this._vertexFormat=w.clone(c),this._extrudedHeight=o(h,0),this._extrude=d,this._closeTop=p,this._closeBottom=m,this._workerName="createRectangleGeometry"};U.packedLength=E.packedLength+l.packedLength+w.packedLength+8,U.pack=function(e,t,r){r=o(r,0),E.pack(e._rectangle,t,r),r+=E.packedLength,l.pack(e._ellipsoid,t,r),r+=l.packedLength,w.pack(e._vertexFormat,t,r),r+=w.packedLength,t[r++]=e._granularity,t[r++]=e._surfaceHeight,t[r++]=e._rotation,t[r++]=e._stRotation,t[r++]=e._extrudedHeight,t[r++]=e._extrude?1:0,t[r++]=e._closeTop?1:0,t[r]=e._closeBottom?1:0};var G=new E,W=l.clone(l.UNIT_SPHERE),H=new w,q={rectangle:G,ellipsoid:W,vertexFormat:H,granularity:void 0,height:void 0,rotation:void 0,stRotation:void 0,extrudedHeight:void 0,closeTop:void 0,closeBottom:void 0};U.unpack=function(e,t,r){t=o(t,0);var i=E.unpack(e,t,G);t+=E.packedLength;var n=l.unpack(e,t,W);t+=l.packedLength;var s=w.unpack(e,t,H);t+=w.packedLength;var u=e[t++],c=e[t++],h=e[t++],d=e[t++],p=e[t++],m=1===e[t++],f=1===e[t++],v=1===e[t];return a(r)?(r._rectangle=E.clone(i,r._rectangle),r._ellipsoid=l.clone(n,r._ellipsoid),r._vertexFormat=w.clone(s,r._vertexFormat),r._granularity=u,r._surfaceHeight=c,r._rotation=h,r._stRotation=d,r._extrudedHeight=m?p:void 0,r._extrude=m,r._closeTop=f,r._closeBottom=v,r):(q.granularity=u,q.height=c,q.rotation=h,q.stRotation=d,q.extrudedHeight=m?p:void 0,q.closeTop=f,q.closeBottom=v,new U(q))};var j=new v,Y=new _,X=new i,Z=new C,K=new i; -return U.createGeometry=function(t){var i=E.clone(t._rectangle,L),n=t._ellipsoid,o=t._surfaceHeight,s=t._extrude,l=t._extrudedHeight,c=t._stRotation,d=t._vertexFormat,p=S.computeOptions(t,i,X),m=j,f=Y;if(a(c)){v.fromRotation(-c,m);var y=E.center(i,K),w=n.cartographicToCartesian(y,z);r.normalize(w,w),C.fromAxisAngle(w,-c,Z),_.fromQuaternion(Z,f)}else v.clone(v.IDENTITY,m),_.clone(_.IDENTITY,f);p.lonScalar=1/i.width,p.latScalar=1/i.height,p.vertexFormat=d,p.textureMatrix=m,p.tangentRotationMatrix=f,p.size=p.width*p.height;var T,b;if(i=t._rectangle,s){T=M(p);var x=e.fromRectangle3D(i,n,o,V),A=e.fromRectangle3D(i,n,l,B);b=e.union(x,A)}else T=P(p),T=g.scaleToGeodeticHeight(T,o,n,!1),b=e.fromRectangle3D(i,n,o);return d.position||delete T.attributes.position,new u({attributes:new h(T.attributes),indices:T.indices,primitiveType:T.primitiveType,boundingSphere:b})},U.createShadowVolume=function(e,t,r){var i=e._granularity,n=e._ellipsoid,o=t(i,n),a=r(i,n);return new U({rectangle:e._rectangle,rotation:e._rotation,ellipsoid:n,stRotation:e._stRotation,granularity:i,extrudedHeight:a,height:o,closeTop:!0,closeBottom:!0,vertexFormat:w.POSITION_ONLY})},U}),r("Core/RectangleOutlineGeometry",["./BoundingSphere","./Cartesian3","./Cartographic","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolygonPipeline","./PrimitiveType","./Rectangle","./RectangleGeometryLibrary"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e){var t,r=e.size,n=e.height,o=e.width,a=new Float64Array(3*r),s=0,d=0,p=E;for(t=0;o>t;t++)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(t=o-1,d=1;n>d;d++)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(d=n-1,t=o-2;t>=0;t--)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(t=0,d=n-2;d>0;d--)v.computePosition(e,d,t,p),a[s++]=p.x,a[s++]=p.y,a[s++]=p.z;for(var f=a.length/3*2,_=h.createTypedArray(a.length/3,f),g=0,y=0;y<a.length/3-1;y++)_[g++]=y,_[g++]=y+1;_[g++]=a.length/3-1,_[g++]=0;var C=new l({attributes:new c,primitiveType:m.LINES});return C.attributes.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:a}),C.indices=_,C}function g(e){var t=e.surfaceHeight,r=e.extrudedHeight,i=e.ellipsoid,n=Math.min(r,t),o=Math.max(r,t),a=_(e);if(d.equalsEpsilon(n,o,d.EPSILON10))return a;var s=e.height,l=e.width;a=p.scaleToGeodeticHeight(a,o,i,!1);var u=a.attributes.position.values,c=u.length,m=new Float64Array(2*c);m.set(u),a=p.scaleToGeodeticHeight(a,n,i);var f=a.attributes.position.values;m.set(f,c),a.attributes.position.values=m;var v=m.length/3*2+8,g=h.createTypedArray(m.length/3,v);c=m.length/6;for(var y=0,C=0;c-1>C;C++)g[y++]=C,g[y++]=C+1,g[y++]=C+c,g[y++]=C+c+1;return g[y++]=c-1,g[y++]=0,g[y++]=c+c-1,g[y++]=c,g[y++]=0,g[y++]=c,g[y++]=l-1,g[y++]=c+l-1,g[y++]=l+s-2,g[y++]=l+s-2+c,g[y++]=2*l+s-3,g[y++]=2*l+s-3+c,a.indices=g,a}var y=new e,C=new e,E=new t,S=new f,w=function(e){e=n(e,n.EMPTY_OBJECT);var t=e.rectangle,r=n(e.granularity,d.RADIANS_PER_DEGREE),i=n(e.ellipsoid,s.WGS84),o=n(e.height,0),a=n(e.rotation,0),l=e.extrudedHeight;this._rectangle=t,this._granularity=r,this._ellipsoid=i,this._surfaceHeight=o,this._rotation=a,this._extrudedHeight=l,this._workerName="createRectangleOutlineGeometry"};w.packedLength=f.packedLength+s.packedLength+5,w.pack=function(e,t,r){r=n(r,0),f.pack(e._rectangle,t,r),r+=f.packedLength,s.pack(e._ellipsoid,t,r),r+=s.packedLength,t[r++]=e._granularity,t[r++]=e._surfaceHeight,t[r++]=e._rotation,t[r++]=o(e._extrudedHeight)?1:0,t[r]=n(e._extrudedHeight,0)};var T=new f,b=s.clone(s.UNIT_SPHERE),x={rectangle:T,ellipsoid:b,granularity:void 0,height:void 0,rotation:void 0,extrudedHeight:void 0};w.unpack=function(e,t,r){t=n(t,0);var i=f.unpack(e,t,T);t+=f.packedLength;var a=s.unpack(e,t,b);t+=s.packedLength;var l=e[t++],u=e[t++],c=e[t++],h=e[t++],d=e[t];return o(r)?(r._rectangle=f.clone(i,r._rectangle),r._ellipsoid=s.clone(a,r._ellipsoid),r._surfaceHeight=u,r._rotation=c,r._extrudedHeight=h?d:void 0,r):(x.granularity=l,x.height=u,x.rotation=c,x.extrudedHeight=h?d:void 0,new w(x))};var P=new r;return w.createGeometry=function(t){var r=f.clone(t._rectangle,S),i=t._ellipsoid,n=t._surfaceHeight,a=t._extrudedHeight,s=v.computeOptions(t,r,P);s.size=2*s.width+2*s.height-4;var u,c;if(r=t._rectangle,o(a)){u=g(s);var h=e.fromRectangle3D(r,i,n,C),d=e.fromRectangle3D(r,i,a,y);c=e.union(h,d)}else u=_(s),u=p.scaleToGeodeticHeight(u,n,i,!1),c=e.fromRectangle3D(r,i,n);return new l({attributes:u.attributes,indices:u.indices,primitiveType:m.LINES,boundingSphere:c})},w}),r("Core/ReferenceFrame",["./freezeObject"],function(e){"use strict";var t={FIXED:0,INERTIAL:1};return e(t)}),r("Core/ScreenSpaceEventType",["./freezeObject"],function(e){"use strict";var t={LEFT_DOWN:0,LEFT_UP:1,LEFT_CLICK:2,LEFT_DOUBLE_CLICK:3,RIGHT_DOWN:5,RIGHT_UP:6,RIGHT_CLICK:7,RIGHT_DOUBLE_CLICK:8,MIDDLE_DOWN:10,MIDDLE_UP:11,MIDDLE_CLICK:12,MIDDLE_DOUBLE_CLICK:13,MOUSE_MOVE:15,WHEEL:16,PINCH_START:17,PINCH_END:18,PINCH_MOVE:19};return e(t)}),r("Core/ScreenSpaceEventHandler",["./AssociativeArray","./Cartesian2","./defaultValue","./defined","./destroyObject","./DeveloperError","./FeatureDetection","./KeyboardEventModifier","./ScreenSpaceEventType"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t,r){var i=e._element;if(i===document)return r.x=t.clientX,r.y=t.clientY,r;var n=i.getBoundingClientRect();return r.x=t.clientX-n.left,r.y=t.clientY-n.top,r}function c(e,t){var r=e;return i(t)&&(r+="+"+t),r}function h(e){return e.shiftKey?s.SHIFT:e.ctrlKey?s.CTRL:e.altKey?s.ALT:void 0}function d(e,t,r,i){var n=function(t){i(e,t)};r.addEventListener(t,n,!1),e._removalFunctions.push(function(){r.removeEventListener(t,n,!1)})}function p(e){var t=e._element,r=i(t.disableRootEvents)?t:document;a.supportsPointerEvents()?(d(e,"pointerdown",t,b),d(e,"pointerup",t,x),d(e,"pointermove",t,P)):(d(e,"mousedown",t,f),d(e,"mouseup",r,v),d(e,"mousemove",r,_),d(e,"touchstart",t,C),d(e,"touchend",r,E),d(e,"touchmove",r,w)),d(e,"dblclick",t,g);var n;n="onwheel"in t?"wheel":i(document.onmousewheel)?"mousewheel":"DOMMouseScroll",d(e,n,t,y)}function m(e){for(var t=e._removalFunctions,r=0;r<t.length;++r)t[r]()}function f(e,r){if(!e._seenAnyTouchEvents){var n=r.button;e._buttonDown=n;var o;if(n===A.LEFT)o=l.LEFT_DOWN;else if(n===A.MIDDLE)o=l.MIDDLE_DOWN;else{if(n!==A.RIGHT)return;o=l.RIGHT_DOWN}var a=u(e,r,e._primaryPosition);t.clone(a,e._primaryStartPosition),t.clone(a,e._primaryPreviousPosition);var s=h(r),c=e.getInputAction(o,s);i(c)&&(t.clone(a,I.position),c(I),r.preventDefault())}}function v(e,r){if(!e._seenAnyTouchEvents){var n=r.button;e._buttonDown=void 0;var o,a;if(n===A.LEFT)o=l.LEFT_UP,a=l.LEFT_CLICK;else if(n===A.MIDDLE)o=l.MIDDLE_UP,a=l.MIDDLE_CLICK;else{if(n!==A.RIGHT)return;o=l.RIGHT_UP,a=l.RIGHT_CLICK}var s=h(r),c=e.getInputAction(o,s),d=e.getInputAction(a,s);if(i(c)||i(d)){var p=u(e,r,e._primaryPosition);if(i(c)&&(t.clone(p,M.position),c(M)),i(d)){var m=e._primaryStartPosition,f=m.x-p.x,v=m.y-p.y,_=Math.sqrt(f*f+v*v);_<e._clickPixelTolerance&&(t.clone(p,D.position),d(D))}}}}function _(e,r){if(!e._seenAnyTouchEvents){var n=h(r),o=u(e,r,e._primaryPosition),a=e._primaryPreviousPosition,s=e.getInputAction(l.MOUSE_MOVE,n);i(s)&&(t.clone(a,R.startPosition),t.clone(o,R.endPosition),s(R)),t.clone(o,a),i(e._buttonDown)&&r.preventDefault()}}function g(e,t){var r,n=t.button;if(n===A.LEFT)r=l.LEFT_DOUBLE_CLICK;else if(n===A.MIDDLE)r=l.MIDDLE_DOUBLE_CLICK;else{if(n!==A.RIGHT)return;r=l.RIGHT_DOUBLE_CLICK}var o=h(t),a=e.getInputAction(r,o);i(a)&&(u(e,t,O.position),a(O))}function y(e,t){var r;if(i(t.deltaY)){var n=t.deltaMode;r=n===t.DOM_DELTA_PIXEL?-t.deltaY:n===t.DOM_DELTA_LINE?40*-t.deltaY:120*-t.deltaY}else r=t.detail>0?-120*t.detail:t.wheelDelta;if(i(r)){var o=h(t),a=e.getInputAction(l.WHEEL,o);i(a)&&(a(r),t.preventDefault())}}function C(e,r){e._seenAnyTouchEvents=!0;var i,n,o,a=r.changedTouches,s=a.length,l=e._positions;for(i=0;s>i;++i)n=a[i],o=n.identifier,l.set(o,u(e,n,new t));S(e,r);var c=e._previousPositions;for(i=0;s>i;++i)n=a[i],o=n.identifier,c.set(o,t.clone(l.get(o)))}function E(e,t){e._seenAnyTouchEvents=!0;var r,i,n,o=t.changedTouches,a=o.length,s=e._positions;for(r=0;a>r;++r)i=o[r],n=i.identifier,s.remove(n);S(e,t);var l=e._previousPositions;for(r=0;a>r;++r)i=o[r],n=i.identifier,l.remove(n)}function S(e,r){var n,o,a=h(r),s=e._positions,u=e._previousPositions,c=s.length;if(1!==c&&e._buttonDown===A.LEFT&&(e._buttonDown=void 0,n=e.getInputAction(l.LEFT_UP,a),i(n)&&(t.clone(e._primaryPosition,F.position),n(F)),0===c&&(o=e.getInputAction(l.LEFT_CLICK,a),i(o)))){var d=e._primaryStartPosition,p=u.values[0],m=d.x-p.x,f=d.y-p.y,v=Math.sqrt(m*m+f*f);v<e._clickPixelTolerance&&(t.clone(e._primaryPosition,B.position),o(B))}if(2!==c&&e._isPinching&&(e._isPinching=!1,n=e.getInputAction(l.PINCH_END,a),i(n)&&n()),1===c){var _=s.values[0];t.clone(_,e._primaryPosition),t.clone(_,e._primaryStartPosition),t.clone(_,e._primaryPreviousPosition),e._buttonDown=A.LEFT,n=e.getInputAction(l.LEFT_DOWN,a),i(n)&&(t.clone(_,N.position),n(N)),r.preventDefault()}2===c&&(e._isPinching=!0,n=e.getInputAction(l.PINCH_START,a),i(n)&&(t.clone(s.values[0],L.position1),t.clone(s.values[1],L.position2),n(L)))}function w(e,r){e._seenAnyTouchEvents=!0;var n,o,a,s=r.changedTouches,l=s.length,c=e._positions;for(n=0;l>n;++n){o=s[n],a=o.identifier;var h=c.get(a);i(h)&&u(e,o,h)}T(e,r);var d=e._previousPositions;for(n=0;l>n;++n)o=s[n],a=o.identifier,t.clone(c.get(a),d.get(a))}function T(e,r){var n,o=h(r),a=e._positions,s=e._previousPositions,u=a.length;if(1===u&&e._buttonDown===A.LEFT){var c=a.values[0];t.clone(c,e._primaryPosition);var d=e._primaryPreviousPosition;n=e.getInputAction(l.MOUSE_MOVE,o),i(n)&&(t.clone(d,V.startPosition),t.clone(c,V.endPosition),n(V)),t.clone(c,d),r.preventDefault()}else if(2===u&&e._isPinching&&(n=e.getInputAction(l.PINCH_MOVE,o),i(n))){var p=a.values[0],m=a.values[1],f=s.values[0],v=s.values[1],_=m.x-p.x,g=m.y-p.y,y=.25*Math.sqrt(_*_+g*g),C=v.x-f.x,E=v.y-f.y,S=.25*Math.sqrt(C*C+E*E),w=.125*(m.y+p.y),T=.125*(v.y+f.y),b=Math.atan2(g,_),x=Math.atan2(E,C);t.fromElements(0,S,z.distance.startPosition),t.fromElements(0,y,z.distance.endPosition),t.fromElements(x,T,z.angleAndHeight.startPosition),t.fromElements(b,w,z.angleAndHeight.endPosition),n(z)}}function b(e,r){if(r.target.setPointerCapture(r.pointerId),"touch"===r.pointerType){var i=e._positions,n=r.pointerId;i.set(n,u(e,r,new t)),S(e,r);var o=e._previousPositions;o.set(n,t.clone(i.get(n)))}else f(e,r)}function x(e,t){if("touch"===t.pointerType){var r=e._positions,i=t.pointerId;r.remove(i),S(e,t);var n=e._previousPositions;n.remove(i)}else v(e,t)}function P(e,r){if("touch"===r.pointerType){var i=e._positions,n=r.pointerId;u(e,r,i.get(n)),T(e,r);var o=e._previousPositions;t.clone(i.get(n),o.get(n))}else _(e,r)}var A={LEFT:0,MIDDLE:1,RIGHT:2},I={position:new t},M={position:new t},D={position:new t},R={startPosition:new t,endPosition:new t},O={position:new t},N={position:new t},L={position1:new t,position2:new t},F={position:new t},B={position:new t},V={startPosition:new t,endPosition:new t},z={distance:{startPosition:new t,endPosition:new t},angleAndHeight:{startPosition:new t,endPosition:new t}},k=function(i){this._inputEvents={},this._buttonDown=void 0,this._isPinching=!1,this._seenAnyTouchEvents=!1,this._primaryStartPosition=new t,this._primaryPosition=new t,this._primaryPreviousPosition=new t,this._positions=new e,this._previousPositions=new e,this._removalFunctions=[],this._clickPixelTolerance=5,this._element=r(i,document),p(this)};return k.prototype.setInputAction=function(e,t,r){var i=c(t,r);this._inputEvents[i]=e},k.prototype.getInputAction=function(e,t){var r=c(e,t);return this._inputEvents[r]},k.prototype.removeInputAction=function(e,t){var r=c(e,t);delete this._inputEvents[r]},k.prototype.isDestroyed=function(){return!1},k.prototype.destroy=function(){return m(this),n(this)},k}),r("Core/ShowGeometryInstanceAttribute",["./ComponentDatatype","./defaultValue","./defined","./defineProperties","./DeveloperError"],function(e,t,r,i,n){"use strict";var o=function(e){e=t(e,!0),this.value=o.toValue(e)};return i(o.prototype,{componentDatatype:{get:function(){return e.UNSIGNED_BYTE}},componentsPerAttribute:{get:function(){return 1}},normalize:{get:function(){return!1}}}),o.toValue=function(e,t){return r(t)?(t[0]=e,t):new Uint8Array([e])},o}),r("Core/Simon1994PlanetaryPositions",["./Cartesian3","./defined","./DeveloperError","./JulianDate","./Math","./Matrix3","./TimeConstants","./TimeStandard"],function(e,t,r,i,n,o,a,s){"use strict";function l(e){var t=6.239996+.0172019696544*e;return.001657*Math.sin(t+.01671*Math.sin(t))}function u(e,t){t=i.addSeconds(e,C,t);var r=i.totalDays(t)-E;return t=i.addSeconds(t,l(r),t)}function c(i,a,s,l,u,c,p,m){if(0>s&&(s=-s,u+=n.PI),0>s||s>n.PI)throw new r("The inclination is out of range. Inclination must be greater than or equal to zero and less than or equal to Pi radians.");var v=i*(1-a),_=l-u,g=u,y=d(c-l,a),C=h(a,0);if("Hyperbolic"===C&&Math.abs(n.negativePiToPi(y))>=Math.acos(-1/a))throw new r("The true anomaly of the hyperbolic orbit lies outside of the bounds of the hyperbola.");f(_,s,g,I);var E=v*(1+a),S=Math.cos(y),w=Math.sin(y),T=1+a*S;if(T<=n.Epsilon10)throw new r("elements cannot be converted to cartesian");var b=E/T;return t(m)?(m.x=b*S,m.y=b*w,m.z=0):m=new e(b*S,b*w,0),o.multiplyByVector(I,m,m)}function h(e,t){if(0>e)throw new r("eccentricity cannot be negative.");return t>=e?"Circular":1-t>e?"Elliptical":1+t>=e?"Parabolic":"Hyperbolic"}function d(e,t){if(0>t||t>=1)throw new r("eccentricity out of range.");var i=p(e,t);return m(i,t)}function p(e,t){if(0>t||t>=1)throw new r("eccentricity out of range.");var i=Math.floor(e/n.TWO_PI);e-=i*n.TWO_PI;var o,a=e+t*Math.sin(e)/(1-Math.sin(e+t)+Math.sin(e)),s=Number.MAX_VALUE;for(o=0;M>o&&Math.abs(s-a)>D;++o){s=a;var l=s-t*Math.sin(s)-e,u=1-t*Math.cos(s);a=s-l/u}if(o>=M)throw new r("Kepler equation did not converge");return s=a+i*n.TWO_PI}function m(e,t){if(0>t||t>=1)throw new r("eccentricity out of range.");var i=Math.floor(e/n.TWO_PI);e-=i*n.TWO_PI;var o=Math.cos(e)-t,a=Math.sin(e)*Math.sqrt(1-t*t),s=Math.atan2(a,o);return s=n.zeroToTwoPi(s),0>e&&(s-=n.TWO_PI),s+=i*n.TWO_PI}function f(e,i,a,s){if(0>i||i>n.PI)throw new r("inclination out of range");var l=Math.cos(e),u=Math.sin(e),c=Math.cos(i),h=Math.sin(i),d=Math.cos(a),p=Math.sin(a);return t(s)?(s[0]=d*l-p*u*c,s[1]=p*l+d*u*c,s[2]=u*h,s[3]=-d*u-p*l*c,s[4]=-p*u+d*l*c,s[5]=l*h,s[6]=p*h,s[7]=-d*h,s[8]=c):s=new o(d*l-p*u*c,-d*u-p*l*c,p*h,p*l+d*u*c,-p*u+d*l*c,-d*h,u*h,l*h,c),s}function v(e,t){u(e,Ie);var r=Ie.dayNumber-S.dayNumber+(Ie.secondsOfDay-S.secondsOfDay)/a.SECONDS_PER_DAY,i=r/(10*a.DAYS_PER_JULIAN_CENTURY),n=.3595362*i,o=R+W*Math.cos(L*n)+J*Math.sin(L*n)+H*Math.cos(F*n)+Q*Math.sin(F*n)+q*Math.cos(B*n)+$*Math.sin(B*n)+j*Math.cos(V*n)+ee*Math.sin(V*n)+Y*Math.cos(z*n)+te*Math.sin(z*n)+X*Math.cos(k*n)+re*Math.sin(k*n)+Z*Math.cos(U*n)+ie*Math.sin(U*n)+K*Math.cos(G*n)+ne*Math.sin(G*n),s=O+N*i+pe*Math.cos(oe*n)+Ee*Math.sin(oe*n)+me*Math.cos(ae*n)+Se*Math.sin(ae*n)+fe*Math.cos(se*n)+we*Math.sin(se*n)+ve*Math.cos(le*n)+Te*Math.sin(le*n)+_e*Math.cos(ue*n)+be*Math.sin(ue*n)+ge*Math.cos(ce*n)+xe*Math.sin(ce*n)+ye*Math.cos(he*n)+Pe*Math.sin(he*n)+Ce*Math.cos(de*n)+Ae*Math.sin(de*n),l=.0167086342-.0004203654*i,h=102.93734808*x+11612.3529*P*i,d=469.97289*P*i,p=174.87317577*x-8679.27034*P*i;return c(o,l,d,h,p,s,T,t)}function _(e,t){u(e,Ie);var r=Ie.dayNumber-S.dayNumber+(Ie.secondsOfDay-S.secondsOfDay)/a.SECONDS_PER_DAY,i=r/a.DAYS_PER_JULIAN_CENTURY,n=i*i,o=n*i,s=o*i,l=383397.7725+.004*i,h=.055545526-1.6e-8*i,d=5.15668983*x,p=-8e-5*i+.02966*n-42e-6*o-1.3e-7*s,m=83.35324312*x,f=14643420.2669*i-38.2702*n-.045047*o+21301e-8*s,v=125.04455501*x,_=-6967919.3631*i+6.3602*n+.007625*o-3586e-8*s,g=218.31664563*x,y=1732559343.4847*i-6.391*n+.006588*o-3169e-8*s,C=297.85019547*x+P*(1602961601.209*i-6.3706*n+.006593*o-3169e-8*s),E=93.27209062*x+P*(1739527262.8478*i-12.7512*n-.001037*o+417e-8*s),T=134.96340251*x+P*(1717915923.2178*i+31.8792*n+.051635*o-2447e-7*s),A=357.52910918*x+P*(129596581.0481*i-.5532*n+136e-6*o-1149e-8*s),I=310.17137918*x-P*(6967051.436*i+6.2068*n+.007618*o-3219e-8*s),M=2*C,D=4*C,R=6*C,O=2*T,N=3*T,L=4*T,F=2*E;l+=3400.4*Math.cos(M)-635.6*Math.cos(M-T)-235.6*Math.cos(T)+218.1*Math.cos(M-A)+181*Math.cos(M+T),h+=.014216*Math.cos(M-T)+.008551*Math.cos(M-O)-.001383*Math.cos(T)+.001356*Math.cos(M+T)-.001147*Math.cos(D-N)-914e-6*Math.cos(D-O)+869e-6*Math.cos(M-A-T)-627e-6*Math.cos(M)-394e-6*Math.cos(D-L)+282e-6*Math.cos(M-A-O)-279e-6*Math.cos(C-T)-236e-6*Math.cos(O)+231e-6*Math.cos(D)+229e-6*Math.cos(R-L)-201e-6*Math.cos(O-F),p+=486.26*Math.cos(M-F)-40.13*Math.cos(M)+37.51*Math.cos(F)+25.73*Math.cos(O-F)+19.97*Math.cos(M-A-F),f+=-55609*Math.sin(M-T)-34711*Math.sin(M-O)-9792*Math.sin(T)+9385*Math.sin(D-N)+7505*Math.sin(D-O)+5318*Math.sin(M+T)+3484*Math.sin(D-L)-3417*Math.sin(M-A-T)-2530*Math.sin(R-L)-2376*Math.sin(M)-2075*Math.sin(M-N)-1883*Math.sin(O)-1736*Math.sin(R-5*T)+1626*Math.sin(A)-1370*Math.sin(R-N),_+=-5392*Math.sin(M-F)-540*Math.sin(A)-441*Math.sin(M)+423*Math.sin(F)-288*Math.sin(O-F),y+=-3332.9*Math.sin(M)+1197.4*Math.sin(M-T)-662.5*Math.sin(A)+396.3*Math.sin(T)-218*Math.sin(M-A);var B=2*I,V=3*I;p+=46.997*Math.cos(I)*i-.614*Math.cos(M-F+I)*i+.614*Math.cos(M-F-I)*i-.0297*Math.cos(B)*n-.0335*Math.cos(I)*n+.0012*Math.cos(M-F+B)*n-16e-5*Math.cos(I)*o+4e-5*Math.cos(V)*o+4e-5*Math.cos(B)*o;var z=2.116*Math.sin(I)*i-.111*Math.sin(M-F-I)*i-.0015*Math.sin(I)*n;f+=z,y+=z,_+=-520.77*Math.sin(I)*i+13.66*Math.sin(M-F+I)*i+1.12*Math.sin(M-I)*i-1.06*Math.sin(F-I)*i+.66*Math.sin(B)*n+.371*Math.sin(I)*n-.035*Math.sin(M-F+B)*n-.015*Math.sin(M-F+I)*n+.0014*Math.sin(I)*o-.0011*Math.sin(V)*o-9e-4*Math.sin(B)*o,l*=b;var k=d+p*P,U=m+f*P,G=g+y*P,W=v+_*P;return c(l,h,k,U,W,G,w,t)}function g(t,r){return r=_(t,r),e.multiplyByScalar(r,De,r)}var y={},C=32.184,E=2451545,S=new i(2451545,0,s.TAI),w=398600435e6,T=1.012300034*w*328900.56,b=1e3,x=n.RADIANS_PER_DEGREE,P=n.RADIANS_PER_ARCSECOND,A=14959787e4,I=new o,M=50,D=n.EPSILON8,R=1.0000010178*A,O=100.46645683*x,N=1295977422.83429*P,L=16002,F=21863,B=32004,V=10931,z=14529,k=16368,U=15318,G=32794,W=64e-7*A,H=-152*1e-7*A,q=62e-7*A,j=-8e-7*A,Y=32e-7*A,X=-41*1e-7*A,Z=19e-7*A,K=-11*1e-7*A,J=-150*1e-7*A,Q=-46*1e-7*A,$=68*1e-7*A,ee=54e-7*A,te=14e-7*A,re=24e-7*A,ie=-28*1e-7*A,ne=22e-7*A,oe=10,ae=16002,se=21863,le=10931,ue=1473,ce=32004,he=4387,de=73,pe=-325*1e-7,me=-322*1e-7,fe=-79*1e-7,ve=232*1e-7,_e=-52*1e-7,ge=97e-7,ye=55e-7,Ce=-41*1e-7,Ee=-105*1e-7,Se=-137*1e-7,we=258e-7,Te=35e-7,be=-116*1e-7,xe=-88*1e-7,Pe=-112*1e-7,Ae=-80*1e-7,Ie=new i(0,0,s.TAI),Me=.012300034,De=Me/(Me+1)*-1,Re=new o(1.0000000000000002,5.619723173785822e-16,4.690511510146299e-19,-5.154129427414611e-16,.9174820620691819,-.39777715593191376,-2.23970096136568e-16,.39777715593191376,.9174820620691819),Oe=new e;return y.computeSunPositionInEarthInertialFrame=function(r,n){return t(r)||(r=i.now()),t(n)||(n=new e),Oe=v(r,Oe),n=e.negate(Oe,n),g(r,Oe),e.subtract(n,Oe,n),o.multiplyByVector(Re,n,n),n},y.computeMoonPositionInEarthInertialFrame=function(e,r){return t(e)||(e=i.now()),r=_(e,r),o.multiplyByVector(Re,r,r),r},y}),r("Core/SimplePolylineGeometry",["./BoundingSphere","./Cartesian3","./Color","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PolylinePipeline","./PrimitiveType"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,t,i,n,o,a,s){var l,u=p.numberOfPoints(e,t,o),c=i.red,h=i.green,d=i.blue,m=i.alpha,f=n.red,v=n.green,_=n.blue,g=n.alpha;if(r.equals(i,n)){for(l=0;u>l;l++)a[s++]=r.floatToByte(c),a[s++]=r.floatToByte(h),a[s++]=r.floatToByte(d),a[s++]=r.floatToByte(m);return s}var y=(f-c)/u,C=(v-h)/u,E=(_-d)/u,S=(g-m)/u,w=s;for(l=0;u>l;l++)a[w++]=r.floatToByte(c+l*y),a[w++]=r.floatToByte(h+l*C),a[w++]=r.floatToByte(d+l*E),a[w++]=r.floatToByte(m+l*S);return w}var v=function(e){e=n(e,n.EMPTY_OBJECT);var i=e.positions,a=e.colors,l=n(e.colorsPerVertex,!1);this._positions=i,this._colors=a,this._colorsPerVertex=l,this._followSurface=n(e.followSurface,!0),this._granularity=n(e.granularity,d.RADIANS_PER_DEGREE),this._ellipsoid=n(e.ellipsoid,s.WGS84),this._workerName="createSimplePolylineGeometry";var u=1+i.length*t.packedLength;u+=o(a)?1+a.length*r.packedLength:1,this.packedLength=u+s.packedLength+3};v.pack=function(e,i,a){a=n(a,0);var l,u=e._positions,c=u.length;for(i[a++]=c,l=0;c>l;++l,a+=t.packedLength)t.pack(u[l],i,a);var h=e._colors;for(c=o(h)?h.length:0,i[a++]=c,l=0;c>l;++l,a+=r.packedLength)r.pack(h[l],i,a);s.pack(e._ellipsoid,i,a),a+=s.packedLength,i[a++]=e._colorsPerVertex?1:0,i[a++]=e._followSurface?1:0,i[a]=e._granularity},v.unpack=function(e,i,a){i=n(i,0);var l,u=e[i++],c=new Array(u);for(l=0;u>l;++l,i+=t.packedLength)c[l]=t.unpack(e,i);u=e[i++];var h=u>0?new Array(u):void 0;for(l=0;u>l;++l,i+=r.packedLength)h[l]=r.unpack(e,i);var d=s.unpack(e,i);i+=s.packedLength;var p=1===e[i++],m=1===e[i++],f=e[i];return o(a)?(a._positions=c,a._colors=h,a._ellipsoid=d,a._colorsPerVertex=p,a._followSurface=m,a._granularity=f,a):new v({positions:c,colors:h,ellipsoid:d,colorsPerVertex:p,followSurface:m,granularity:f})};var _=new Array(2),g=new Array(2),y={positions:_,height:g,ellipsoid:void 0,minDistance:void 0};return v.createGeometry=function(n){var a,s,v,C,E,S=n._positions,w=n._colors,T=n._colorsPerVertex,b=n._followSurface,x=n._granularity,P=n._ellipsoid,A=d.chordLength(x,P.maximumRadius),I=o(w)&&!T,M=S.length,D=0;if(b){var R=p.extractHeights(S,P),O=y;if(O.minDistance=A,O.ellipsoid=P,I){var N=0;for(a=0;M-1>a;a++)N+=p.numberOfPoints(S[a],S[a+1],A)+1;s=new Float64Array(3*N),C=new Uint8Array(4*N),O.positions=_,O.height=g;var L=0;for(a=0;M-1>a;++a){_[0]=S[a],_[1]=S[a+1],g[0]=R[a],g[1]=R[a+1];var F=p.generateArc(O);if(o(w)){var B=F.length/3;E=w[a];for(var V=0;B>V;++V)C[L++]=r.floatToByte(E.red),C[L++]=r.floatToByte(E.green),C[L++]=r.floatToByte(E.blue),C[L++]=r.floatToByte(E.alpha)}s.set(F,D),D+=F.length}}else if(O.positions=S,O.height=R,s=new Float64Array(p.generateArc(O)),o(w)){for(C=new Uint8Array(s.length/3*4),a=0;M-1>a;++a){var z=S[a],k=S[a+1],U=w[a],G=w[a+1];D=f(z,k,U,G,A,C,D)}var W=w[M-1];C[D++]=r.floatToByte(W.red),C[D++]=r.floatToByte(W.green),C[D++]=r.floatToByte(W.blue),C[D++]=r.floatToByte(W.alpha)}}else{v=I?2*M-2:M,s=new Float64Array(3*v),C=o(w)?new Uint8Array(4*v):void 0;var H=0,q=0;for(a=0;M>a;++a){var j=S[a];if(I&&a>0&&(t.pack(j,s,H),H+=3,E=w[a-1],C[q++]=r.floatToByte(E.red),C[q++]=r.floatToByte(E.green),C[q++]=r.floatToByte(E.blue),C[q++]=r.floatToByte(E.alpha)),I&&a===M-1)break;t.pack(j,s,H),H+=3,o(w)&&(E=w[a],C[q++]=r.floatToByte(E.red),C[q++]=r.floatToByte(E.green),C[q++]=r.floatToByte(E.blue),C[q++]=r.floatToByte(E.alpha))}}var Y=new c;Y.position=new u({componentDatatype:i.DOUBLE,componentsPerAttribute:3,values:s}),o(w)&&(Y.color=new u({componentDatatype:i.UNSIGNED_BYTE,componentsPerAttribute:4,values:C,normalize:!0})),v=s.length/3;var X=2*(v-1),Z=h.createTypedArray(v,X),K=0;for(a=0;v-1>a;++a)Z[K++]=a,Z[K++]=a+1;return new l({attributes:Y,indices:Z,primitiveType:m.LINES,boundingSphere:e.fromPoints(S)})},v}),r("Core/SphereGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipsoidGeometry","./VertexFormat"],function(e,t,r,i,n,o){"use strict";var a=function(r){var i=t(r.radius,1),o=new e(i,i,i),a={radii:o,stackPartitions:r.stackPartitions,slicePartitions:r.slicePartitions,vertexFormat:r.vertexFormat};this._ellipsoidGeometry=new n(a),this._workerName="createSphereGeometry"};a.packedLength=n.packedLength,a.pack=function(e,t,r){n.pack(e._ellipsoidGeometry,t,r)};var s=new n,l={radius:void 0,radii:new e,vertexFormat:new o,stackPartitions:void 0,slicePartitions:void 0};return a.unpack=function(t,i,u){var c=n.unpack(t,i,s);return l.vertexFormat=o.clone(c._vertexFormat,l.vertexFormat),l.stackPartitions=c._stackPartitions,l.slicePartitions=c._slicePartitions,r(u)?(e.clone(c._radii,l.radii),u._ellipsoidGeometry=new n(l),u):(l.radius=c._radii.x,new a(l))},a.createGeometry=function(e){return n.createGeometry(e._ellipsoidGeometry)},a}),r("Core/SphereOutlineGeometry",["./Cartesian3","./defaultValue","./defined","./DeveloperError","./EllipsoidOutlineGeometry"],function(e,t,r,i,n){"use strict";var o=function(r){var i=t(r.radius,1),o=new e(i,i,i),a={radii:o,stackPartitions:r.stackPartitions,slicePartitions:r.slicePartitions,subdivisions:r.subdivisions};this._ellipsoidGeometry=new n(a),this._workerName="createSphereOutlineGeometry"};o.packedLength=n.packedLength,o.pack=function(e,t,r){n.pack(e._ellipsoidGeometry,t,r)};var a=new n,s={radius:void 0,radii:new e,stackPartitions:void 0,slicePartitions:void 0,subdivisions:void 0};return o.unpack=function(t,i,l){var u=n.unpack(t,i,a);return s.stackPartitions=u._stackPartitions,s.slicePartitions=u._slicePartitions,s.subdivisions=u._subdivisions,r(l)?(e.clone(u._radii,s.radii),l._ellipsoidGeometry=new n(s),l):(s.radius=u._radii.x,new o(s))},o.createGeometry=function(e){return n.createGeometry(e._ellipsoidGeometry)},o}),r("Core/Spherical",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t,r,i){this.clock=e(t,0),this.cone=e(r,0),this.magnitude=e(i,1)};return i.fromCartesian3=function(e,r){var n=e.x,o=e.y,a=e.z,s=n*n+o*o;return t(r)||(r=new i),r.clock=Math.atan2(o,n),r.cone=Math.atan2(Math.sqrt(s),a),r.magnitude=Math.sqrt(s+a*a),r},i.clone=function(e,r){return t(e)?t(r)?(r.clock=e.clock,r.cone=e.cone,r.magnitude=e.magnitude,r):new i(e.clock,e.cone,e.magnitude):void 0},i.normalize=function(e,r){return t(r)?(r.clock=e.clock,r.cone=e.cone,r.magnitude=1,r):new i(e.clock,e.cone,1)},i.equals=function(e,r){return e===r||t(e)&&t(r)&&e.clock===r.clock&&e.cone===r.cone&&e.magnitude===r.magnitude},i.equalsEpsilon=function(r,i,n){return n=e(n,0),r===i||t(r)&&t(i)&&Math.abs(r.clock-i.clock)<=n&&Math.abs(r.cone-i.cone)<=n&&Math.abs(r.magnitude-i.magnitude)<=n},i.prototype.equals=function(e){return i.equals(this,e)},i.prototype.clone=function(e){return i.clone(this,e)},i.prototype.equalsEpsilon=function(e,t){return i.equalsEpsilon(this,e,t)},i.prototype.toString=function(){return"("+this.clock+", "+this.cone+", "+this.magnitude+")"},i}),r("Core/TerrainData",["./defineProperties","./DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return e(r.prototype,{waterMask:{get:t.throwInstantiationError}}),r.prototype.interpolateHeight=t.throwInstantiationError,r.prototype.isChildAvailable=t.throwInstantiationError,r.prototype.createMesh=t.throwInstantiationError,r.prototype.upsample=t.throwInstantiationError,r.prototype.wasCreatedByUpsampling=t.throwInstantiationError,r}),r("Core/TilingScheme",["./defineProperties","./DeveloperError"],function(e,t){"use strict";var r=function(e){throw new t("This type should not be instantiated directly. Instead, use WebMercatorTilingScheme or GeographicTilingScheme.")};return e(r.prototype,{ellipsoid:{get:t.throwInstantiationError},rectangle:{get:t.throwInstantiationError},projection:{get:t.throwInstantiationError}}),r.prototype.getNumberOfXTilesAtLevel=t.throwInstantiationError,r.prototype.getNumberOfYTilesAtLevel=t.throwInstantiationError,r.prototype.rectangleToNativeRectangle=t.throwInstantiationError,r.prototype.tileXYToNativeRectangle=t.throwInstantiationError,r.prototype.tileXYToRectangle=t.throwInstantiationError,r.prototype.positionToTileXY=t.throwInstantiationError,r}),r("Core/TimeIntervalCollection",["./binarySearch","./defaultValue","./defined","./defineProperties","./DeveloperError","./Event","./JulianDate","./TimeInterval"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t){return a.compare(e.start,t.start)}var u=function(e){if(this._intervals=[],this._changedEvent=new o,r(e))for(var t=e.length,i=0;t>i;i++)this.addInterval(e[i])};i(u.prototype,{changedEvent:{get:function(){return this._changedEvent}},start:{get:function(){var e=this._intervals;return 0===e.length?void 0:e[0].start}},isStartIncluded:{get:function(){var e=this._intervals;return 0===e.length?!1:e[0].isStartIncluded}},stop:{get:function(){var e=this._intervals,t=e.length;return 0===t?void 0:e[t-1].stop}},isStopIncluded:{get:function(){var e=this._intervals,t=e.length;return 0===t?!1:e[t-1].isStopIncluded}},length:{get:function(){return this._intervals.length}},isEmpty:{get:function(){return 0===this._intervals.length}}}),u.prototype.equals=function(e,t){if(this===e)return!0;if(!(e instanceof u))return!1;var r=this._intervals,i=e._intervals,n=r.length;if(n!==i.length)return!1;for(var o=0;n>o;o++)if(!s.equals(r[o],i[o],t))return!1;return!0},u.prototype.get=function(e){return this._intervals[e]},u.prototype.removeAll=function(){this._intervals.length>0&&(this._intervals.length=0,this._changedEvent.raiseEvent(this))},u.prototype.findIntervalContainingDate=function(e){var t=this.indexOf(e);return t>=0?this._intervals[t]:void 0},u.prototype.findDataForIntervalContainingDate=function(e){var t=this.indexOf(e);return t>=0?this._intervals[t].data:void 0},u.prototype.contains=function(e){return this.indexOf(e)>=0};var c=new s;return u.prototype.indexOf=function(t){var r=this._intervals;c.start=t,c.stop=t;var i=e(r,c,l);return i>=0?r[i].isStartIncluded?i:i>0&&r[i-1].stop.equals(t)&&r[i-1].isStopIncluded?i-1:~i:(i=~i,i>0&&i-1<r.length&&s.contains(r[i-1],t)?i-1:~i)},u.prototype.findInterval=function(e){e=t(e,t.EMPTY_OBJECT);for(var i=e.start,n=e.stop,o=e.isStartIncluded,a=e.isStopIncluded,s=this._intervals,l=0,u=s.length;u>l;l++){var c=s[l];if(!(r(i)&&!c.start.equals(i)||r(n)&&!c.stop.equals(n)||r(o)&&c.isStartIncluded!==o||r(a)&&c.isStopIncluded!==a))return s[l]}return void 0},u.prototype.addInterval=function(t,i){if(!t.isEmpty){var n,o,u=this._intervals;if(0===u.length||a.greaterThan(t.start,u[u.length-1].stop))return u.push(t),void this._changedEvent.raiseEvent(this);for(o=e(u,t,l),0>o?o=~o:o>0&&t.isStartIncluded&&u[o-1].isStartIncluded&&u[o-1].start.equals(t.start)?--o:o<u.length&&!t.isStartIncluded&&u[o].isStartIncluded&&u[o].start.equals(t.start)&&++o,o>0&&(n=a.compare(u[o-1].stop,t.start),(n>0||0===n&&(u[o-1].isStopIncluded||t.isStartIncluded))&&((r(i)?i(u[o-1].data,t.data):u[o-1].data===t.data)?(t=new s(a.greaterThan(t.stop,u[o-1].stop)?{start:u[o-1].start,stop:t.stop,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:t.isStopIncluded,data:t.data}:{start:u[o-1].start,stop:u[o-1].stop,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:u[o-1].isStopIncluded||t.stop.equals(u[o-1].stop)&&t.isStopIncluded,data:t.data}),u.splice(o-1,1),--o):(n=a.compare(u[o-1].stop,t.stop),n>0||0===n&&u[o-1].isStopIncluded&&!t.isStopIncluded?u.splice(o-1,1,new s({start:u[o-1].start,stop:t.start,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:!t.isStartIncluded,data:u[o-1].data}),new s({start:t.stop,stop:u[o-1].stop,isStartIncluded:!t.isStopIncluded,isStopIncluded:u[o-1].isStopIncluded,data:u[o-1].data})):u[o-1]=new s({start:u[o-1].start,stop:t.start,isStartIncluded:u[o-1].isStartIncluded,isStopIncluded:!t.isStartIncluded,data:u[o-1].data}))));o<u.length&&(n=a.compare(t.stop,u[o].start),n>0||0===n&&(t.isStopIncluded||u[o].isStartIncluded));)if(r(i)?i(u[o].data,t.data):u[o].data===t.data)t=new s({start:t.start,stop:a.greaterThan(u[o].stop,t.stop)?u[o].stop:t.stop,isStartIncluded:t.isStartIncluded,isStopIncluded:a.greaterThan(u[o].stop,t.stop)?u[o].isStopIncluded:t.isStopIncluded,data:t.data}),u.splice(o,1);else{if(u[o]=new s({start:t.stop,stop:u[o].stop,isStartIncluded:!t.isStopIncluded,isStopIncluded:u[o].isStopIncluded,data:u[o].data}),!u[o].isEmpty)break;u.splice(o,1)}u.splice(o,0,t),this._changedEvent.raiseEvent(this)}},u.prototype.removeInterval=function(t){if(t.isEmpty)return!1;var r=!1,i=this._intervals,n=e(i,t,l);0>n&&(n=~n);var o=t.start,u=t.stop,c=t.isStartIncluded,h=t.isStopIncluded;if(n>0){var d=i[n-1],p=d.stop;(a.greaterThan(p,o)||s.equals(p,o)&&d.isStopIncluded&&c)&&(r=!0, -(a.greaterThan(p,u)||d.isStopIncluded&&!h&&s.equals(p,u))&&i.splice(n,0,new s({start:u,stop:p,isStartIncluded:!h,isStopIncluded:d.isStopIncluded,data:d.data})),i[n-1]=new s({start:d.start,stop:o,isStartIncluded:d.isStartIncluded,isStopIncluded:!c,data:d.data}))}var m=i[n];for(n<i.length&&!c&&m.isStartIncluded&&o.equals(m.start)&&(r=!0,i.splice(n,0,new s({start:m.start,stop:m.start,isStartIncluded:!0,isStopIncluded:!0,data:m.data})),++n,m=i[n]);n<i.length&&a.greaterThan(u,m.stop);)r=!0,i.splice(n,1);return n<i.length&&u.equals(m.stop)&&(r=!0,!h&&m.isStopIncluded?(n+1<i.length&&i[n+1].start.equals(u)&&m.data===i[n+1].data?(i.splice(n,1),m=new s({start:m.start,stop:m.stop,isStartIncluded:!0,isStopIncluded:m.isStopIncluded,data:m.data})):m=new s({start:u,stop:u,isStartIncluded:!0,isStopIncluded:!0,data:m.data}),i[n]=m):i.splice(n,1)),n<i.length&&(a.greaterThan(u,m.start)||u.equals(m.start)&&h&&m.isStartIncluded)&&(r=!0,i[n]=new s({start:u,stop:m.stop,isStartIncluded:!h,isStopIncluded:m.isStopIncluded,data:m.data})),r&&this._changedEvent.raiseEvent(this),r},u.prototype.intersect=function(e,t,i){for(var n=0,o=0,l=new u,c=this._intervals,h=e._intervals;n<c.length&&o<h.length;){var d=c[n],p=h[o];if(a.lessThan(d.stop,p.start))++n;else if(a.lessThan(p.stop,d.start))++o;else{if(r(i)||r(t)&&t(d.data,p.data)||!r(t)&&p.data===d.data){var m=s.intersect(d,p,new s,i);m.isEmpty||l.addInterval(m,t)}a.lessThan(d.stop,p.stop)||d.stop.equals(p.stop)&&!d.isStopIncluded&&p.isStopIncluded?++n:++o}}return l},u}),r("Core/loadXML",["./loadWithXhr"],function(e){"use strict";var t=function(t,r){return e({url:t,responseType:"document",headers:r,overrideMimeType:"text/xml"})};return t}),r("Core/VRTheWorldTerrainProvider",["../ThirdParty/when","./Credit","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Event","./GeographicTilingScheme","./getImagePixels","./HeightmapTerrainData","./loadImage","./loadXML","./Math","./Rectangle","./TerrainProvider","./throttleRequestByServer","./TileProviderError"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,t){this.rectangle=e,this.maxLevel=t}function y(e,t,r,n){for(var o=e._tilingScheme,a=e._rectangles,s=o.tileXYToRectangle(t,r,n),l=0,u=0;u<a.length&&15!==l;++u){var c=a[u];if(!(c.maxLevel<=n)){var h=c.rectangle,d=m.intersection(h,s,S);i(d)&&(C(o,h,2*t,2*r,n+1)&&(l|=4),C(o,h,2*t+1,2*r,n+1)&&(l|=8),C(o,h,2*t,2*r+1,n+1)&&(l|=1),C(o,h,2*t+1,2*r+1,n+1)&&(l|=2))}}return l}function C(e,t,r,n,o){var a=e.tileXYToRectangle(r,n,o);return i(m.intersection(a,t,S))}var E=function(n){function u(e){var t=e.getElementsByTagName("SRS")[0].textContent;if("EPSG:4326"!==t)return void c("SRS "+t+" is not supported.");C._tilingScheme=new l({ellipsoid:E});var r=e.getElementsByTagName("TileFormat")[0];C._heightmapWidth=parseInt(r.getAttribute("width"),10),C._heightmapHeight=parseInt(r.getAttribute("height"),10),C._levelZeroMaximumGeometricError=f.getEstimatedLevelZeroGeometricErrorForAHeightmap(E,Math.min(C._heightmapWidth,C._heightmapHeight),C._tilingScheme.getNumberOfXTilesAtLevel(0));for(var i=e.getElementsByTagName("DataExtent"),n=0;n<i.length;++n){var o=i[n],a=p.toRadians(parseFloat(o.getAttribute("minx"))),s=p.toRadians(parseFloat(o.getAttribute("miny"))),u=p.toRadians(parseFloat(o.getAttribute("maxx"))),h=p.toRadians(parseFloat(o.getAttribute("maxy"))),d=parseInt(o.getAttribute("maxlevel"),10);C._rectangles.push(new g(new m(a,s,u,h),d))}C._ready=!0,C._readyPromise.resolve(!0)}function c(e){var t=r(e,"An error occurred while accessing "+C._url+".");y=_.handleError(y,C,C._errorEvent,t,void 0,void 0,void 0,h)}function h(){e(d(C._url),u,c)}if(n=r(n,r.EMPTY_OBJECT),!i(n.url))throw new o("options.url is required.");this._url=n.url,this._url.length>0&&"/"!==this._url[this._url.length-1]&&(this._url+="/"),this._errorEvent=new s,this._ready=!1,this._readyPromise=e.defer(),this._proxy=n.proxy,this._terrainDataStructure={heightScale:.001,heightOffset:-1e3,elementsPerHeight:3,stride:4,elementMultiplier:256,isBigEndian:!0};var v=n.credit;"string"==typeof v&&(v=new t(v)),this._credit=v,this._tilingScheme=void 0,this._rectangles=[];var y,C=this,E=r(n.ellipsoid,a.WGS84);h()};n(E.prototype,{errorEvent:{get:function(){return this._errorEvent}},credit:{get:function(){return this._credit}},tilingScheme:{get:function(){if(!this.ready)throw new o("requestTileGeometry must not be called before ready returns true.");return this._tilingScheme}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},hasWaterMask:{get:function(){return!1}},hasVertexNormals:{get:function(){return!1}}}),E.prototype.requestTileGeometry=function(t,n,a,s){if(!this.ready)throw new o("requestTileGeometry must not be called before ready returns true.");var l=this._tilingScheme.getNumberOfYTilesAtLevel(a),d=this._url+a+"/"+t+"/"+(l-n-1)+".tif?cesium=true",p=this._proxy;i(p)&&(d=p.getURL(d));var m;if(s=r(s,!0)){if(m=v(d,h),!i(m))return void 0}else m=h(d);var f=this;return e(m,function(e){return new c({buffer:u(e),width:f._heightmapWidth,height:f._heightmapHeight,childTileMask:y(f,t,n,a),structure:f._terrainDataStructure})})},E.prototype.getLevelMaximumGeometricError=function(e){if(!this.ready)throw new o("requestTileGeometry must not be called before ready returns true.");return this._levelZeroMaximumGeometricError/(1<<e)};var S=new m;return E.prototype.getTileDataAvailable=function(e,t,r){return void 0},E}),r("Core/WallGeometryLibrary",["./Cartographic","./defined","./DeveloperError","./EllipsoidTangentPlane","./Math","./PolygonPipeline","./PolylinePipeline","./WindingOrder"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t){return n.equalsEpsilon(e.latitude,t.latitude,n.EPSILON14)&&n.equalsEpsilon(e.longitude,t.longitude,n.EPSILON14)}function u(r,i,n,o){var a=i.length;if(2>a)return{positions:i};var s=t(o),u=t(n),c=new Array(a),p=new Array(a),m=new Array(a),f=i[0];c[0]=f;var v=r.cartesianToCartographic(f,h);u&&(v.height=n[0]),p[0]=v.height,s?m[0]=o[0]:m[0]=0;for(var _=1,g=1;a>g;++g){var y=i[g],C=r.cartesianToCartographic(y,d);u&&(C.height=n[g]),l(v,C)?v.height<C.height&&(p[_-1]=C.height):(c[_]=y,p[_]=C.height,s?m[_]=o[g]:m[_]=0,e.clone(C,v),++_)}return c.length=_,p.length=_,m.length=_,{positions:c,topHeights:p,bottomHeights:m}}var c={},h=new e,d=new e,p=new Array(2),m=new Array(2),f={positions:void 0,height:void 0,granularity:void 0,ellipsoid:void 0};return c.computePositions=function(e,t,r,l,c,h){var d=u(e,t,r,l);if(t=d.positions,r=d.topHeights,l=d.bottomHeights,t.length<2)return void 0;if(t.length>=3){var v=i.fromPoints(t,e),_=v.projectPointsOntoPlane(t);o.computeWindingOrder2D(_)===s.CLOCKWISE&&(t.reverse(),r.reverse(),l.reverse())}var g,y,C=t.length,E=n.chordLength(c,e.maximumRadius),S=f;if(S.minDistance=E,S.ellipsoid=e,h){var w,T=0;for(w=0;C-1>w;w++)T+=a.numberOfPoints(t[w],t[w+1],E)+1;g=new Float64Array(3*T),y=new Float64Array(3*T);var b=p,x=m;S.positions=b,S.height=x;var P=0;for(w=0;C-1>w;w++){b[0]=t[w],b[1]=t[w+1],x[0]=r[w],x[1]=r[w+1];var A=a.generateArc(S);g.set(A,P),x[0]=l[w],x[1]=l[w+1],y.set(a.generateArc(S),P),P+=A.length}}else S.positions=t,S.height=r,g=new Float64Array(a.generateArc(S)),S.height=l,y=new Float64Array(a.generateArc(S));return{bottomPositions:y,topPositions:g}},c}),r("Core/WallGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./VertexFormat","./WallGeometryLibrary"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=new t,v=new t,_=new t,g=new t,y=new t,C=new t,E=new t,S=new t,w=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.positions,o=e.maximumHeights,s=e.minimumHeights,l=i(e.vertexFormat,p.DEFAULT),u=i(e.granularity,h.RADIANS_PER_DEGREE),c=i(e.ellipsoid,a.WGS84);this._positions=r,this._minimumHeights=s,this._maximumHeights=o,this._vertexFormat=p.clone(l),this._granularity=u,this._ellipsoid=a.clone(c),this._workerName="createWallGeometry";var d=1+r.length*t.packedLength+2;n(s)&&(d+=s.length),n(o)&&(d+=o.length),this.packedLength=d+a.packedLength+p.packedLength+1};w.pack=function(e,r,o){o=i(o,0);var s,l=e._positions,u=l.length;for(r[o++]=u,s=0;u>s;++s,o+=t.packedLength)t.pack(l[s],r,o);var c=e._minimumHeights;if(u=n(c)?c.length:0,r[o++]=u,n(c))for(s=0;u>s;++s)r[o++]=c[s];var h=e._maximumHeights;if(u=n(h)?h.length:0,r[o++]=u,n(h))for(s=0;u>s;++s)r[o++]=h[s];a.pack(e._ellipsoid,r,o),o+=a.packedLength,p.pack(e._vertexFormat,r,o),o+=p.packedLength,r[o]=e._granularity};var T=a.clone(a.UNIT_SPHERE),b=new p,x={positions:void 0,minimumHeights:void 0,maximumHeights:void 0,ellipsoid:T,vertexFormat:b,granularity:void 0};return w.unpack=function(e,r,o){r=i(r,0);var s,l=e[r++],u=new Array(l);for(s=0;l>s;++s,r+=t.packedLength)u[s]=t.unpack(e,r);l=e[r++];var c;if(l>0)for(c=new Array(l),s=0;l>s;++s)c[s]=e[r++];l=e[r++];var h;if(l>0)for(h=new Array(l),s=0;l>s;++s)h[s]=e[r++];var d=a.unpack(e,r,T);r+=a.packedLength;var m=p.unpack(e,r,b);r+=p.packedLength;var f=e[r];return n(o)?(o._positions=u,o._minimumHeights=c,o._maximumHeights=h,o._ellipsoid=a.clone(d,o._ellipsoid),o._vertexFormat=p.clone(m,o._vertexFormat),o._granularity=f,o):(x.positions=u,x.minimumHeights=c,x.maximumHeights=h,x.granularity=f,new w(x))},w.fromConstantHeights=function(e){e=i(e,i.EMPTY_OBJECT);var t,r,o=e.positions,a=e.minimumHeight,s=e.maximumHeight,l=n(a),u=n(s);if(l||u){var c=o.length;t=l?new Array(c):void 0,r=u?new Array(c):void 0;for(var h=0;c>h;++h)l&&(t[h]=a),u&&(r[h]=s)}var d={positions:o,maximumHeights:r,minimumHeights:t,ellipsoid:e.ellipsoid,vertexFormat:e.vertexFormat};return new w(d)},w.createGeometry=function(i){var o=i._positions,a=i._minimumHeights,p=i._maximumHeights,w=i._vertexFormat,T=i._granularity,b=i._ellipsoid,x=m.computePositions(b,o,p,a,T,!0);if(!n(x))return void 0;var P=x.bottomPositions,A=x.topPositions,I=A.length,M=2*I,D=w.position?new Float64Array(M):void 0,R=w.normal?new Float32Array(M):void 0,O=w.tangent?new Float32Array(M):void 0,N=w.binormal?new Float32Array(M):void 0,L=w.st?new Float32Array(M/3*2):void 0,F=0,B=0,V=0,z=0,k=0,U=S,G=E,W=C,H=!0;I/=3;var q,j=0,Y=1/(I-o.length+1);for(q=0;I>q;++q){var X=3*q,Z=t.fromArray(A,X,f),K=t.fromArray(P,X,v);if(w.position&&(D[F++]=K.x,D[F++]=K.y,D[F++]=K.z,D[F++]=Z.x,D[F++]=Z.y,D[F++]=Z.z),w.st&&(L[k++]=j,L[k++]=0,L[k++]=j,L[k++]=1),w.normal||w.tangent||w.binormal){var J,Q=t.clone(t.ZERO,y),$=b.scaleToGeodeticSurface(t.fromArray(A,X,v),v);if(I>q+1&&(J=b.scaleToGeodeticSurface(t.fromArray(A,X+3,_),_),Q=t.fromArray(A,X+3,y)),H){var ee=t.subtract(Q,Z,g),te=t.subtract($,Z,f);U=t.normalize(t.cross(te,ee,U),U),H=!1}t.equalsEpsilon(J,$,h.EPSILON10)?H=!0:(j+=Y,w.tangent&&(G=t.normalize(t.subtract(J,$,G),G)),w.binormal&&(W=t.normalize(t.cross(U,G,W),W))),w.normal&&(R[B++]=U.x,R[B++]=U.y,R[B++]=U.z,R[B++]=U.x,R[B++]=U.y,R[B++]=U.z),w.tangent&&(O[z++]=G.x,O[z++]=G.y,O[z++]=G.z,O[z++]=G.x,O[z++]=G.y,O[z++]=G.z),w.binormal&&(N[V++]=W.x,N[V++]=W.y,N[V++]=W.z,N[V++]=W.x,N[V++]=W.y,N[V++]=W.z)}}var re=new u;w.position&&(re.position=new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:D})),w.normal&&(re.normal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:R})),w.tangent&&(re.tangent=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:O})),w.binormal&&(re.binormal=new l({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:N})),w.st&&(re.st=new l({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:L}));var ie=M/3;M-=6;var ne=c.createTypedArray(ie,M),oe=0;for(q=0;ie-2>q;q+=2){var ae=q,se=q+2,le=t.fromArray(D,3*ae,f),ue=t.fromArray(D,3*se,v);if(!t.equalsEpsilon(le,ue,h.EPSILON10)){var ce=q+1,he=q+3;ne[oe++]=ce,ne[oe++]=ae,ne[oe++]=he,ne[oe++]=he,ne[oe++]=ae,ne[oe++]=se}}return new s({attributes:re,indices:ne,primitiveType:d.TRIANGLES,boundingSphere:new e.fromVertices(D)})},w}),r("Core/WallOutlineGeometry",["./BoundingSphere","./Cartesian3","./ComponentDatatype","./defaultValue","./defined","./DeveloperError","./Ellipsoid","./Geometry","./GeometryAttribute","./GeometryAttributes","./IndexDatatype","./Math","./PrimitiveType","./WallGeometryLibrary"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=new t,f=new t,v=function(e){e=i(e,i.EMPTY_OBJECT);var r=e.positions,o=e.maximumHeights,s=e.minimumHeights,l=i(e.granularity,h.RADIANS_PER_DEGREE),u=i(e.ellipsoid,a.WGS84);this._positions=r,this._minimumHeights=s,this._maximumHeights=o,this._granularity=l,this._ellipsoid=a.clone(u),this._workerName="createWallOutlineGeometry";var c=1+r.length*t.packedLength+2;n(s)&&(c+=s.length),n(o)&&(c+=o.length),this.packedLength=c+a.packedLength+1};v.pack=function(e,r,o){o=i(o,0);var s,l=e._positions,u=l.length;for(r[o++]=u,s=0;u>s;++s,o+=t.packedLength)t.pack(l[s],r,o);var c=e._minimumHeights;if(u=n(c)?c.length:0,r[o++]=u,n(c))for(s=0;u>s;++s)r[o++]=c[s];var h=e._maximumHeights;if(u=n(h)?h.length:0,r[o++]=u,n(h))for(s=0;u>s;++s)r[o++]=h[s];a.pack(e._ellipsoid,r,o),o+=a.packedLength,r[o]=e._granularity};var _=a.clone(a.UNIT_SPHERE),g={positions:void 0,minimumHeights:void 0,maximumHeights:void 0,ellipsoid:_,granularity:void 0};return v.unpack=function(e,r,o){r=i(r,0);var s,l=e[r++],u=new Array(l);for(s=0;l>s;++s,r+=t.packedLength)u[s]=t.unpack(e,r);l=e[r++];var c;if(l>0)for(c=new Array(l),s=0;l>s;++s)c[s]=e[r++];l=e[r++];var h;if(l>0)for(h=new Array(l),s=0;l>s;++s)h[s]=e[r++];var d=a.unpack(e,r,_);r+=a.packedLength;var p=e[r];return n(o)?(o._positions=u,o._minimumHeights=c,o._maximumHeights=h,o._ellipsoid=a.clone(d,o._ellipsoid),o._granularity=p,o):(g.positions=u,g.minimumHeights=c,g.maximumHeights=h,g.granularity=p,new v(g))},v.fromConstantHeights=function(e){e=i(e,i.EMPTY_OBJECT);var t,r,o=e.positions,a=e.minimumHeight,s=e.maximumHeight,l=n(a),u=n(s);if(l||u){var c=o.length;t=l?new Array(c):void 0,r=u?new Array(c):void 0;for(var h=0;c>h;++h)l&&(t[h]=a),u&&(r[h]=s)}var d={positions:o,maximumHeights:r,minimumHeights:t,ellipsoid:e.ellipsoid};return new v(d)},v.createGeometry=function(i){var o=i._positions,a=i._minimumHeights,v=i._maximumHeights,_=i._granularity,g=i._ellipsoid,y=p.computePositions(g,o,v,a,_,!1);if(!n(y))return void 0;var C=y.bottomPositions,E=y.topPositions,S=E.length,w=2*S,T=new Float64Array(w),b=0;S/=3;var x;for(x=0;S>x;++x){var P=3*x,A=t.fromArray(E,P,m),I=t.fromArray(C,P,f);T[b++]=I.x,T[b++]=I.y,T[b++]=I.z,T[b++]=A.x,T[b++]=A.y,T[b++]=A.z}var M=new u({position:new l({componentDatatype:r.DOUBLE,componentsPerAttribute:3,values:T})}),D=w/3;w=2*D-4+D;var R=c.createTypedArray(D,w),O=0;for(x=0;D-2>x;x+=2){var N=x,L=x+2,F=t.fromArray(T,3*N,m),B=t.fromArray(T,3*L,f);if(!t.equalsEpsilon(F,B,h.EPSILON10)){var V=x+1,z=x+3;R[O++]=V,R[O++]=N,R[O++]=V,R[O++]=z,R[O++]=N,R[O++]=L}}return R[O++]=D-2,R[O++]=D-1,new s({attributes:M,indices:R,primitiveType:d.LINES,boundingSphere:new e.fromVertices(T)})},v}),r("Core/WebMercatorProjection",["./Cartesian3","./Cartographic","./defaultValue","./defined","./defineProperties","./DeveloperError","./Ellipsoid","./Math"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){this._ellipsoid=r(e,a.WGS84),this._semimajorAxis=this._ellipsoid.maximumRadius,this._oneOverSemimajorAxis=1/this._semimajorAxis};return n(l.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),l.mercatorAngleToGeodeticLatitude=function(e){return s.PI_OVER_TWO-2*Math.atan(Math.exp(-e))},l.geodeticLatitudeToMercatorAngle=function(e){e>l.MaximumLatitude?e=l.MaximumLatitude:e<-l.MaximumLatitude&&(e=-l.MaximumLatitude);var t=Math.sin(e);return.5*Math.log((1+t)/(1-t))},l.MaximumLatitude=l.mercatorAngleToGeodeticLatitude(Math.PI),l.prototype.project=function(t,r){var n=this._semimajorAxis,o=t.longitude*n,a=l.geodeticLatitudeToMercatorAngle(t.latitude)*n,s=t.height;return i(r)?(r.x=o,r.y=a,r.z=s,r):new e(o,a,s)},l.prototype.unproject=function(e,r){var n=this._oneOverSemimajorAxis,o=e.x*n,a=l.mercatorAngleToGeodeticLatitude(e.y*n),s=e.z;return i(r)?(r.longitude=o,r.latitude=a,r.height=s,r):new t(o,a,s)},l}),r("Core/WebMercatorTilingScheme",["./Cartesian2","./defaultValue","./defined","./defineProperties","./Ellipsoid","./Rectangle","./WebMercatorProjection"],function(e,t,r,i,n,o,a){"use strict";var s=function(i){if(i=t(i,{}),this._ellipsoid=t(i.ellipsoid,n.WGS84),this._numberOfLevelZeroTilesX=t(i.numberOfLevelZeroTilesX,1),this._numberOfLevelZeroTilesY=t(i.numberOfLevelZeroTilesY,1),this._projection=new a(this._ellipsoid),r(i.rectangleSouthwestInMeters)&&r(i.rectangleNortheastInMeters))this._rectangleSouthwestInMeters=i.rectangleSouthwestInMeters,this._rectangleNortheastInMeters=i.rectangleNortheastInMeters;else{var s=this._ellipsoid.maximumRadius*Math.PI;this._rectangleSouthwestInMeters=new e(-s,-s),this._rectangleNortheastInMeters=new e(s,s)}var l=this._projection.unproject(this._rectangleSouthwestInMeters),u=this._projection.unproject(this._rectangleNortheastInMeters);this._rectangle=new o(l.longitude,l.latitude,u.longitude,u.latitude)};return i(s.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},rectangle:{get:function(){return this._rectangle}},projection:{get:function(){return this._projection}}}),s.prototype.getNumberOfXTilesAtLevel=function(e){return this._numberOfLevelZeroTilesX<<e},s.prototype.getNumberOfYTilesAtLevel=function(e){return this._numberOfLevelZeroTilesY<<e},s.prototype.rectangleToNativeRectangle=function(e,t){var i=this._projection,n=i.project(o.southwest(e)),a=i.project(o.northeast(e));return r(t)?(t.west=n.x,t.south=n.y,t.east=a.x,t.north=a.y,t):new o(n.x,n.y,a.x,a.y)},s.prototype.tileXYToNativeRectangle=function(e,t,i,n){var a=this.getNumberOfXTilesAtLevel(i),s=this.getNumberOfYTilesAtLevel(i),l=(this._rectangleNortheastInMeters.x-this._rectangleSouthwestInMeters.x)/a,u=this._rectangleSouthwestInMeters.x+e*l,c=this._rectangleSouthwestInMeters.x+(e+1)*l,h=(this._rectangleNortheastInMeters.y-this._rectangleSouthwestInMeters.y)/s,d=this._rectangleNortheastInMeters.y-t*h,p=this._rectangleNortheastInMeters.y-(t+1)*h;return r(n)?(n.west=u,n.south=p,n.east=c,n.north=d,n):new o(u,p,c,d)},s.prototype.tileXYToRectangle=function(t,r,i,n){var o=this.tileXYToNativeRectangle(t,r,i,n),a=this._projection,s=a.unproject(new e(o.west,o.south)),l=a.unproject(new e(o.east,o.north));return o.west=s.longitude,o.south=s.latitude,o.east=l.longitude,o.north=l.latitude,o},s.prototype.positionToTileXY=function(t,i,n){var a=this._rectangle;if(!o.contains(a,t))return void 0;var s=this.getNumberOfXTilesAtLevel(i),l=this.getNumberOfYTilesAtLevel(i),u=this._rectangleNortheastInMeters.x-this._rectangleSouthwestInMeters.x,c=u/s,h=this._rectangleNortheastInMeters.y-this._rectangleSouthwestInMeters.y,d=h/l,p=this._projection,m=p.project(t),f=m.x-this._rectangleSouthwestInMeters.x,v=this._rectangleNortheastInMeters.y-m.y,_=f/c|0;_>=s&&(_=s-1);var g=v/d|0;return g>=l&&(g=l-1),r(n)?(n.x=_,n.y=g,n):new e(_,g)},s}),r("Core/appendForwardSlash",[],function(){"use strict";var e=function(e){return(0===e.length||"/"!==e[e.length-1])&&(e+="/"),e};return e}),r("Core/cancelAnimationFrame",["./defined"],function(e){"use strict";var t=window.cancelAnimationFrame;!function(){if(!e(t))for(var r=["webkit","moz","ms","o"],i=0,n=r.length;n>i&&!e(t);)t=window[r[i]+"CancelAnimationFrame"],e(t)||(t=window[r[i]+"CancelRequestAnimationFrame"]),++i;e(t)||(t=clearTimeout)}();var r=function(e){t(e)};return r}),r("Core/combine",["./defaultValue","./defined"],function(e,t){"use strict";var r=function(i,n,o){o=e(o,!1);var a,s,l,u={},c=t(i),h=t(n);if(c)for(a in i)i.hasOwnProperty(a)&&(s=i[a],h&&o&&"object"==typeof s&&n.hasOwnProperty(a)?(l=n[a],"object"==typeof l?u[a]=r(s,l,o):u[a]=s):u[a]=s);if(h)for(a in n)n.hasOwnProperty(a)&&!u.hasOwnProperty(a)&&(l=n[a],u[a]=l);return u};return r}),r("Core/createGuid",[],function(){"use strict";var e=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0,r="x"===e?t:3&t|8;return r.toString(16)})};return e}),r("Core/getFilenameFromUri",["../ThirdParty/Uri","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t){var r=new e(t);r.normalize();var i=r.path,n=i.lastIndexOf("/");return-1!==n&&(i=i.substr(n+1)),i};return i}),r("Core/getStringFromTypedArray",["./defaultValue","./defined","./DeveloperError"],function(e,t,r){"use strict";var i=function(t,r,n){return r=e(r,0),n=e(n,t.byteLength-r),t=t.subarray(r,r+n),i.decode(t)};return i.decodeWithTextDecoder=function(e){var t=new TextDecoder("utf-8");return t.decode(e)},i.decodeWithFromCharCode=function(e){for(var t="",r=e.length,i=0;r>i;++i)t+=String.fromCharCode(e[i]);return t},"undefined"!=typeof TextDecoder?i.decode=i.decodeWithTextDecoder:i.decode=i.decodeWithFromCharCode,i}),r("Core/getMagic",["../Core/defaultValue","../Core/getStringFromTypedArray"],function(e,t){"use strict";var r=function(r,i){return i=e(i,0),t(r,i,Math.min(4,r.length))};return r}),r("Core/objectToQuery",["./defined","./DeveloperError","./isArray"],function(e,t,r){"use strict";var i=function(e){var t="";for(var i in e)if(e.hasOwnProperty(i)){var n=e[i],o=encodeURIComponent(i)+"=";if(r(n))for(var a=0,s=n.length;s>a;++a)t+=o+encodeURIComponent(n[a])+"&";else t+=o+encodeURIComponent(n)+"&"}return t=t.slice(0,-1)};return i}),r("Core/queryToObject",["./defined","./DeveloperError","./isArray"],function(e,t,r){"use strict";var i=function(t){var i={};if(""===t)return i;for(var n=t.replace(/\+/g,"%20").split("&"),o=0,a=n.length;a>o;++o){var s=n[o].split("="),l=decodeURIComponent(s[0]),u=s[1];u=e(u)?decodeURIComponent(u):"";var c=i[l];"string"==typeof c?i[l]=[c,u]:r(c)?c.push(u):i[l]=u}return i};return i}),r("Core/loadJsonp",["../ThirdParty/Uri","../ThirdParty/when","./combine","./defaultValue","./defined","./DeveloperError","./objectToQuery","./queryToObject"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(o,u){u=i(u,i.EMPTY_OBJECT);var c;do c="loadJsonp"+Math.random().toString().substring(2,8);while(n(window[c]));var h=t.defer();window[c]=function(e){h.resolve(e);try{delete window[c]}catch(t){window[c]=void 0}};var d=new e(o),p=s(i(d.query,""));n(u.parameters)&&(p=r(u.parameters,p));var m=i(u.callbackParameterName,"callback");p[m]=c,d.query=a(p),o=d.toString();var f=u.proxy;return n(f)&&(o=f.getURL(o)),l.loadAndExecuteScript(o,c,h),h.promise};return l.loadAndExecuteScript=function(e,t,r){var i=document.createElement("script");i.async=!0,i.src=e;var n=document.getElementsByTagName("head")[0];i.onload=function(){i.onload=void 0,n.removeChild(i)},i.onerror=function(e){r.reject(e)},n.appendChild(i)},l.defaultLoadAndExecuteScript=l.loadAndExecuteScript,l}),r("Core/jsonp",["./deprecationWarning","./loadJsonp"],function(e,t){"use strict";var r=function(r,i){return e("jsonp","jsonp is deprecated. Use loadJsonp instead."),t(r,i)};return r.loadAndExecuteScript=function(e,r,i){t.loadAndExecuteScript(e,r,i)},r.defaultLoadAndExecuteScript=r.loadAndExecuteScript,r}),r("Core/loadBlob",["./loadWithXhr"],function(e){"use strict";var t=function(t,r){return e({url:t,responseType:"blob",headers:r})};return t}),r("Core/loadImageFromTypedArray",["../ThirdParty/when","./defined","./DeveloperError","./loadImage"],function(e,t,r,i){"use strict";var n=function(t,r){var n=new Blob([t],{type:r}),o=window.URL.createObjectURL(n);return i(o,!1).then(function(e){return window.URL.revokeObjectURL(o),e},function(t){return window.URL.revokeObjectURL(o),e.reject(t)})};return n}),r("Core/loadImageViaBlob",["../ThirdParty/when","./loadBlob","./loadImage"],function(e,t,r){"use strict";var i=/^data:/,n=function(n){return i.test(n)?r(n):t(n).then(function(t){var i=window.URL.createObjectURL(t);return r(i,!1).then(function(e){return e.blob=t,window.URL.revokeObjectURL(i),e},function(t){return window.URL.revokeObjectURL(i),e.reject(t)})})},o=function(){try{var e=new XMLHttpRequest;return e.open("GET","#",!0),e.responseType="blob","blob"===e.responseType}catch(t){return!1}}();return o?n:r}),r("Core/mergeSort",["./defined","./DeveloperError"],function(e,t){"use strict";function r(e,t,r,i,a,s){var l,u,c=a-i+1,h=s-a,d=n,p=o;for(l=0;c>l;++l)d[l]=e[i+l];for(u=0;h>u;++u)p[u]=e[a+u+1];l=0,u=0;for(var m=i;s>=m;++m){var f=d[l],v=p[u];c>l&&(u>=h||t(f,v,r)<=0)?(e[m]=f,++l):h>u&&(e[m]=v,++u)}}function i(e,t,n,o,a){if(!(o>=a)){var s=Math.floor(.5*(o+a));i(e,t,n,o,s),i(e,t,n,s+1,a),r(e,t,n,o,s,a)}}var n=[],o=[],a=function(e,t,r){var a=e.length,s=Math.ceil(.5*a);n.length=s,o.length=s,i(e,t,r,0,a-1),n.length=0,o.length=0};return a}),r("Core/requestAnimationFrame",["./defined","./getTimestamp"],function(e,t){"use strict";var r=window.requestAnimationFrame;!function(){if(!e(r))for(var i=["webkit","moz","ms","o"],n=0,o=i.length;o>n&&!e(r);)r=window[i[n]+"RequestAnimationFrame"],++n;if(!e(r)){var a=1e3/60,s=0;r=function(e){var r=t(),i=Math.max(a-(r-s),0);return s=r+i,setTimeout(function(){e(s)},i)}}}();var i=function(e){return r(e)};return i}),r("Core/sampleTerrain",["../ThirdParty/when","./defined","./DeveloperError"],function(e,t,r){"use strict";function i(t,r,i){var a,s=t.tilingScheme,l=[],u={};for(a=0;a<i.length;++a){var c=s.positionToTileXY(i[a],r),h=c.toString();if(!u.hasOwnProperty(h)){var d={x:c.x,y:c.y,level:r,tilingScheme:s,terrainProvider:t,positions:[]};u[h]=d,l.push(d)}u[h].positions.push(i[a])}var p=[];for(a=0;a<l.length;++a){var m=l[a],f=m.terrainProvider.requestTileGeometry(m.x,m.y,m.level,!1),v=e(f,n(m),o(m));p.push(v)}return e.all(p,function(){return i})}function n(e){var t=e.positions,r=e.tilingScheme.tileXYToRectangle(e.x,e.y,e.level);return function(e){for(var i=0;i<t.length;++i){var n=t[i];n.height=e.interpolateHeight(r,n.longitude,n.latitude)}}}function o(e){var t=e.positions;return function(){for(var e=0;e<t.length;++e){var r=t[e];r.height=void 0}}}var a=function(t,r,n){function o(){t.ready?e(i(t,r,n),function(e){a.resolve(e)}):setTimeout(o,10)}var a=e.defer();return o(),a.promise};return a}),r("Core/subdivideArray",["./defined","./DeveloperError"],function(e,t){"use strict";var r=function(e,t){for(var r=[],i=e.length,n=0;i>n;){var o=Math.ceil((i-n)/t--);r.push(e.slice(n,n+o)),n+=o}return r};return r}),r("Core/wrapFunction",["./DeveloperError"],function(e){"use strict";var t=function(e,t,r){return function(){r.apply(e,arguments),t.apply(e,arguments)}};return t}),r("DataSources/ConstantProperty",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event"],function(e,t,r,i,n){"use strict";var o=function(e){this._value=void 0,this._hasClone=!1,this._hasEquals=!1,this._definitionChanged=new n,this.setValue(e)};return r(o.prototype,{isConstant:{value:!0},definitionChanged:{get:function(){return this._definitionChanged}}}),o.prototype.getValue=function(e,t){return this._hasClone?this._value.clone(t):this._value},o.prototype.setValue=function(e){var r=this._value;if(r!==e){var i=t(e),n=i&&"function"==typeof e.clone,o=i&&"function"==typeof e.equals;this._hasClone=n,this._hasEquals=o;var a=!o||!e.equals(r);a&&(this._value=n?e.clone():e,this._definitionChanged.raiseEvent(this))}},o.prototype.equals=function(e){return this===e||e instanceof o&&(!this._hasEquals&&this._value===e._value||this._hasEquals&&this._value.equals(e._value))},o}),r("DataSources/createPropertyDescriptor",["../Core/defaultValue","../Core/defined","./ConstantProperty"],function(e,t,r){"use strict";function i(e,r,i,n,o){return{configurable:n,get:function(){return this[r]},set:function(n){var a=this[r],s=this[i];t(s)&&(s(),this[i]=void 0);var l=t(n);l&&!t(n.getValue)&&t(o)&&(n=o(n)),a!==n&&(this[r]=n,this._definitionChanged.raiseEvent(this,e,n,a)),t(n)&&t(n.definitionChanged)&&(this[i]=n.definitionChanged.addEventListener(function(){this._definitionChanged.raiseEvent(this,e,n,n)},this))}}}function n(e){return new r(e)}function o(t,r,o){return i(t,"_"+t.toString(),"_"+t.toString()+"Subscription",e(r,!1),e(o,n))}return o}),r("DataSources/BillboardGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._image=void 0,this._imageSubscription=void 0,this._imageSubRegion=void 0,this._imageSubRegionSubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._scale=void 0,this._scaleSubscription=void 0,this._rotation=void 0,this._rotationSubscription=void 0,this._alignedAxis=void 0,this._alignedAxisSubscription=void 0,this._horizontalOrigin=void 0,this._horizontalOriginSubscription=void 0,this._verticalOrigin=void 0,this._verticalOriginSubscription=void 0,this._color=void 0,this._colorSubscription=void 0,this._eyeOffset=void 0,this._eyeOffsetSubscription=void 0,this._pixelOffset=void 0,this._pixelOffsetSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._scaleByDistance=void 0,this._scaleByDistanceSubscription=void 0,this._translucencyByDistance=void 0,this._translucencyByDistanceSubscription=void 0,this._pixelOffsetScaleByDistance=void 0,this._pixelOffsetScaleByDistanceSubscription=void 0,this._sizeInMeters=void 0,this._sizeInMetersSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},image:o("image"),imageSubRegion:o("imageSubRegion"),scale:o("scale"),rotation:o("rotation"),alignedAxis:o("alignedAxis"),horizontalOrigin:o("horizontalOrigin"),verticalOrigin:o("verticalOrigin"),color:o("color"),eyeOffset:o("eyeOffset"),pixelOffset:o("pixelOffset"),show:o("show"),width:o("width"),height:o("height"),scaleByDistance:o("scaleByDistance"),translucencyByDistance:o("translucencyByDistance"),pixelOffsetScaleByDistance:o("pixelOffsetScaleByDistance"),sizeInMeters:o("sizeInMeters")}),a.prototype.clone=function(e){return t(e)?(e.color=this._color,e.eyeOffset=this._eyeOffset,e.horizontalOrigin=this._horizontalOrigin,e.image=this._image,e.imageSubRegion=this._imageSubRegion,e.pixelOffset=this._pixelOffset,e.scale=this._scale,e.rotation=this._rotation,e.alignedAxis=this._alignedAxis,e.show=this._show,e.verticalOrigin=this._verticalOrigin,e.width=this._width,e.height=this._height,e.scaleByDistance=this._scaleByDistance,e.translucencyByDistance=this._translucencyByDistance,e.pixelOffsetScaleByDistance=this._pixelOffsetScaleByDistance,e.sizeInMeters=this._sizeInMeters,e):new a(this)},a.prototype.merge=function(t){this.color=e(this._color,t.color),this.eyeOffset=e(this._eyeOffset,t.eyeOffset),this.horizontalOrigin=e(this._horizontalOrigin,t.horizontalOrigin),this.image=e(this._image,t.image),this.imageSubRegion=e(this._imageSubRegion,t.imageSubRegion),this.pixelOffset=e(this._pixelOffset,t.pixelOffset),this.scale=e(this._scale,t.scale),this.rotation=e(this._rotation,t.rotation),this.alignedAxis=e(this._alignedAxis,t.alignedAxis),this.show=e(this._show,t.show),this.verticalOrigin=e(this._verticalOrigin,t.verticalOrigin),this.width=e(this._width,t.width),this.height=e(this._height,t.height),this.scaleByDistance=e(this._scaleByDistance,t.scaleByDistance),this.translucencyByDistance=e(this._translucencyByDistance,t.translucencyByDistance),this.pixelOffsetScaleByDistance=e(this._pixelOffsetScaleByDistance,t.pixelOffsetScaleByDistance),this.sizeInMeters=e(this._sizeInMeters,t.sizeInMeters)},a}),r("Renderer/BufferUsage",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={STREAM_DRAW:t.STREAM_DRAW,STATIC_DRAW:t.STATIC_DRAW,DYNAMIC_DRAW:t.DYNAMIC_DRAW,validate:function(e){return e===r.STREAM_DRAW||e===r.STATIC_DRAW||e===r.DYNAMIC_DRAW}};return e(r)}),r("Renderer/Buffer",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/IndexDatatype","./BufferUsage","./WebGLConstants"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.context._gl,n=r.bufferTarget,o=r.typedArray,a=r.sizeInBytes,s=r.usage,l=t(o);l&&(a=o.byteLength);var u=i.createBuffer();i.bindBuffer(n,u), -i.bufferData(n,l?o:a,s),i.bindBuffer(n,null),this._gl=i,this._bufferTarget=n,this._sizeInBytes=a,this._usage=s,this._buffer=u,this.vertexArrayDestroyable=!0};return l.createVertexBuffer=function(e){return new l({context:e.context,bufferTarget:s.ARRAY_BUFFER,typedArray:e.typedArray,sizeInBytes:e.sizeInBytes,usage:e.usage})},l.createIndexBuffer=function(e){var t=e.context,i=e.indexDatatype,n=o.getSizeInBytes(i),a=new l({context:t,bufferTarget:s.ELEMENT_ARRAY_BUFFER,typedArray:e.typedArray,sizeInBytes:e.sizeInBytes,usage:e.usage}),u=a.sizeInBytes/n;return r(a,{indexDatatype:{get:function(){return i}},bytesPerIndex:{get:function(){return n}},numberOfIndices:{get:function(){return u}}}),a},r(l.prototype,{sizeInBytes:{get:function(){return this._sizeInBytes}},usage:{get:function(){return this._usage}}}),l.prototype._getBuffer=function(){return this._buffer},l.prototype.copyFromArrayView=function(t,r){r=e(r,0);var i=this._gl,n=this._bufferTarget;i.bindBuffer(n,this._buffer),i.bufferSubData(n,r,t),i.bindBuffer(n,null)},l.prototype.isDestroyed=function(){return!1},l.prototype.destroy=function(){return this._gl.deleteBuffer(this._buffer),i(this)},l}),r("Renderer/DrawCommand",["../Core/defaultValue","../Core/PrimitiveType"],function(e,t){"use strict";var r=function(r){r=e(r,e.EMPTY_OBJECT),this.boundingVolume=r.boundingVolume,this.orientedBoundingBox=r.orientedBoundingBox,this.cull=e(r.cull,!0),this.modelMatrix=r.modelMatrix,this.primitiveType=e(r.primitiveType,t.TRIANGLES),this.vertexArray=r.vertexArray,this.count=r.count,this.offset=e(r.offset,0),this.instanceCount=e(r.instanceCount,0),this.shaderProgram=r.shaderProgram,this.uniformMap=r.uniformMap,this.renderState=r.renderState,this.framebuffer=r.framebuffer,this.pass=r.pass,this.executeInClosestFrustum=e(r.executeInClosestFrustum,!1),this.owner=r.owner,this.debugShowBoundingVolume=e(r.debugShowBoundingVolume,!1),this.debugOverlappingFrustums=0,this.oit=void 0};return r.prototype.execute=function(e,t,r,i){e.draw(this,t,r,i)},r}),r("Renderer/ContextLimits",["../Core/defineProperties"],function(e){"use strict";var t={_maximumCombinedTextureImageUnits:0,_maximumCubeMapSize:0,_maximumFragmentUniformVectors:0,_maximumTextureImageUnits:0,_maximumRenderbufferSize:0,_maximumTextureSize:0,_maximumVaryingVectors:0,_maximumVertexAttributes:0,_maximumVertexTextureImageUnits:0,_maximumVertexUniformVectors:0,_minimumAliasedLineWidth:0,_maximumAliasedLineWidth:0,_minimumAliasedPointSize:0,_maximumAliasedPointSize:0,_maximumViewportWidth:0,_maximumViewportHeight:0,_maximumTextureFilterAnisotropy:0,_maximumDrawBuffers:0,_maximumColorAttachments:0,_highpFloatSupported:!1,_highpIntSupported:!1};return e(t,{maximumCombinedTextureImageUnits:{get:function(){return t._maximumCombinedTextureImageUnits}},maximumCubeMapSize:{get:function(){return t._maximumCubeMapSize}},maximumFragmentUniformVectors:{get:function(){return t._maximumFragmentUniformVectors}},maximumTextureImageUnits:{get:function(){return t._maximumTextureImageUnits}},maximumRenderbufferSize:{get:function(){return t._maximumRenderbufferSize}},maximumTextureSize:{get:function(){return t._maximumTextureSize}},maximumVaryingVectors:{get:function(){return t._maximumVaryingVectors}},maximumVertexAttributes:{get:function(){return t._maximumVertexAttributes}},maximumVertexTextureImageUnits:{get:function(){return t._maximumVertexTextureImageUnits}},maximumVertexUniformVectors:{get:function(){return t._maximumVertexUniformVectors}},minimumAliasedLineWidth:{get:function(){return t._minimumAliasedLineWidth}},maximumAliasedLineWidth:{get:function(){return t._maximumAliasedLineWidth}},minimumAliasedPointSize:{get:function(){return t._minimumAliasedPointSize}},maximumAliasedPointSize:{get:function(){return t._maximumAliasedPointSize}},maximumViewportWidth:{get:function(){return t._maximumViewportWidth}},maximumViewportHeight:{get:function(){return t._maximumViewportHeight}},maximumTextureFilterAnisotropy:{get:function(){return t._maximumTextureFilterAnisotropy}},maximumDrawBuffers:{get:function(){return t._maximumDrawBuffers}},maximumColorAttachments:{get:function(){return t._maximumColorAttachments}},highpFloatSupported:{get:function(){return t._highpFloatSupported}},highpIntSupported:{get:function(){return t._highpIntSupported}}}),t}),r("Renderer/RenderState",["../Core/BoundingRectangle","../Core/Color","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/RuntimeError","../Core/WindingOrder","./ContextLimits","./WebGLConstants"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t,r){r?e.enable(t):e.disable(t)}function c(e,t){e.frontFace(t.frontFace)}function h(e,t){var r=t.cull,i=r.enabled;u(e,e.CULL_FACE,i),i&&e.cullFace(r.face)}function d(e,t){e.lineWidth(t.lineWidth)}function p(e,t){var r=t.polygonOffset,i=r.enabled;u(e,e.POLYGON_OFFSET_FILL,i),i&&e.polygonOffset(r.factor,r.units)}function m(e,t,r){var n=t.scissorTest,o=i(r.scissorTest)?r.scissorTest.enabled:n.enabled;if(u(e,e.SCISSOR_TEST,o),o){var a=i(r.scissorTest)?r.scissorTest.rectangle:n.rectangle;e.scissor(a.x,a.y,a.width,a.height)}}function f(e,t){var r=t.depthRange;e.depthRange(r.near,r.far)}function v(e,t){var r=t.depthTest,i=r.enabled;u(e,e.DEPTH_TEST,i),i&&e.depthFunc(r.func)}function _(e,t){var r=t.colorMask;e.colorMask(r.red,r.green,r.blue,r.alpha)}function g(e,t){e.depthMask(t.depthMask)}function y(e,t){e.stencilMask(t.stencilMask)}function C(e,t,r){var n=t.blending,o=i(r.blendingEnabled)?r.blendingEnabled:n.enabled;u(e,e.BLEND,o),o&&(P(e,n.color),e.blendEquationSeparate(n.equationRgb,n.equationAlpha),e.blendFuncSeparate(n.functionSourceRgb,n.functionDestinationRgb,n.functionSourceAlpha,n.functionDestinationAlpha))}function E(e,t){var r=t.stencilTest,i=r.enabled;if(u(e,e.STENCIL_TEST,i),i){var n=r.frontFunction,o=r.backFunction,a=r.reference,s=r.mask;e.stencilFunc(r.frontFunction,r.reference,r.mask),e.stencilFuncSeparate(e.BACK,o,a,s),e.stencilFuncSeparate(e.FRONT,n,a,s);var l=r.frontOperation,c=l.fail,h=l.zFail,d=l.zPass;e.stencilOpSeparate(e.FRONT,c,h,d);var p=r.backOperation,m=p.fail,f=p.zFail,v=p.zPass;e.stencilOpSeparate(e.BACK,m,f,v)}}function S(e,t,r){var n=t.viewport;i(n)||(n=I,n.width=r.context.drawingBufferWidth,n.height=r.context.drawingBufferHeight),r.context.uniformState.viewport=n,e.viewport(n.x,n.y,n.width,n.height)}function w(e,t){var r=[];return e.frontFace!==t.frontFace&&r.push(c),(e.cull.enabled!==t.cull.enabled||e.cull.face!==t.cull.face)&&r.push(h),e.lineWidth!==t.lineWidth&&r.push(d),(e.polygonOffset.enabled!==t.polygonOffset.enabled||e.polygonOffset.factor!==t.polygonOffset.factor||e.polygonOffset.units!==t.polygonOffset.units)&&r.push(p),(e.depthRange.near!==t.depthRange.near||e.depthRange.far!==t.depthRange.far)&&r.push(f),(e.depthTest.enabled!==t.depthTest.enabled||e.depthTest.func!==t.depthTest.func)&&r.push(v),(e.colorMask.red!==t.colorMask.red||e.colorMask.green!==t.colorMask.green||e.colorMask.blue!==t.colorMask.blue||e.colorMask.alpha!==t.colorMask.alpha)&&r.push(_),e.depthMask!==t.depthMask&&r.push(g),e.stencilMask!==t.stencilMask&&r.push(y),(e.stencilTest.enabled!==t.stencilTest.enabled||e.stencilTest.frontFunction!==t.stencilTest.frontFunction||e.stencilTest.backFunction!==t.stencilTest.backFunction||e.stencilTest.reference!==t.stencilTest.reference||e.stencilTest.mask!==t.stencilTest.mask||e.stencilTest.frontOperation.fail!==t.stencilTest.frontOperation.fail||e.stencilTest.frontOperation.zFail!==t.stencilTest.frontOperation.zFail||e.stencilTest.backOperation.fail!==t.stencilTest.backOperation.fail||e.stencilTest.backOperation.zFail!==t.stencilTest.backOperation.zFail||e.stencilTest.backOperation.zPass!==t.stencilTest.backOperation.zPass)&&r.push(E),(e.sampleCoverage.enabled!==t.sampleCoverage.enabled||e.sampleCoverage.value!==t.sampleCoverage.value||e.sampleCoverage.invert!==t.sampleCoverage.invert)&&r.push(A),r}var T=function(n){var o=r(n,{}),s=r(o.cull,{}),u=r(o.polygonOffset,{}),c=r(o.scissorTest,{}),h=r(c.rectangle,{}),d=r(o.depthRange,{}),p=r(o.depthTest,{}),m=r(o.colorMask,{}),f=r(o.blending,{}),v=r(f.color,{}),_=r(o.stencilTest,{}),g=r(_.frontOperation,{}),y=r(_.backOperation,{}),C=r(o.sampleCoverage,{}),E=o.viewport;this.frontFace=r(o.frontFace,a.COUNTER_CLOCKWISE),this.cull={enabled:r(s.enabled,!1),face:r(s.face,l.BACK)},this.lineWidth=r(o.lineWidth,1),this.polygonOffset={enabled:r(u.enabled,!1),factor:r(u.factor,0),units:r(u.units,0)},this.scissorTest={enabled:r(c.enabled,!1),rectangle:e.clone(h)},this.depthRange={near:r(d.near,0),far:r(d.far,1)},this.depthTest={enabled:r(p.enabled,!1),func:r(p.func,l.LESS)},this.colorMask={red:r(m.red,!0),green:r(m.green,!0),blue:r(m.blue,!0),alpha:r(m.alpha,!0)},this.depthMask=r(o.depthMask,!0),this.stencilMask=r(o.stencilMask,-1),this.blending={enabled:r(f.enabled,!1),color:new t(r(v.red,0),r(v.green,0),r(v.blue,0),r(v.alpha,0)),equationRgb:r(f.equationRgb,l.FUNC_ADD),equationAlpha:r(f.equationAlpha,l.FUNC_ADD),functionSourceRgb:r(f.functionSourceRgb,l.ONE),functionSourceAlpha:r(f.functionSourceAlpha,l.ONE),functionDestinationRgb:r(f.functionDestinationRgb,l.ZERO),functionDestinationAlpha:r(f.functionDestinationAlpha,l.ZERO)},this.stencilTest={enabled:r(_.enabled,!1),frontFunction:r(_.frontFunction,l.ALWAYS),backFunction:r(_.backFunction,l.ALWAYS),reference:r(_.reference,0),mask:r(_.mask,-1),frontOperation:{fail:r(g.fail,l.KEEP),zFail:r(g.zFail,l.KEEP),zPass:r(g.zPass,l.KEEP)},backOperation:{fail:r(y.fail,l.KEEP),zFail:r(y.zFail,l.KEEP),zPass:r(y.zPass,l.KEEP)}},this.sampleCoverage={enabled:r(C.enabled,!1),value:r(C.value,1),invert:r(C.invert,!1)},this.viewport=i(E)?new e(E.x,E.y,E.width,E.height):void 0,this.id=0,this._applyFunctions=[]},b=0,x={};T.fromCache=function(e){var t=JSON.stringify(e),r=x[t];if(i(r))return++r.referenceCount,r.state;var n=new T(e),o=JSON.stringify(n);return r=x[o],i(r)||(n.id=b++,r={referenceCount:0,state:n},x[o]=r),++r.referenceCount,x[t]={referenceCount:1,state:r.state},r.state},T.removeFromCache=function(e){var t=new T(e),r=JSON.stringify(t),n=x[r],o=JSON.stringify(e),a=x[o];i(a)&&(--a.referenceCount,0===a.referenceCount&&(delete x[o],i(n)&&--n.referenceCount)),i(n)&&0===n.referenceCount&&delete x[r]},T.getCache=function(){return x},T.clearCache=function(){x={}};var P=function(e,t){e.blendColor(t.red,t.green,t.blue,t.alpha)},A=function(e,t){var r=t.sampleCoverage,i=r.enabled;u(e,e.SAMPLE_COVERAGE,i),i&&e.sampleCoverage(r.value,r.invert)},I=new e;return T.apply=function(e,t,r){c(e,t),h(e,t),d(e,t),p(e,t),f(e,t),v(e,t),_(e,t),g(e,t),y(e,t),E(e,t),A(e,t),m(e,t,r),C(e,t,r),S(e,t,r)},T.partialApply=function(e,t,r,n,o,a){if(t!==r){var s=r._applyFunctions[t.id];i(s)||(s=w(t,r),r._applyFunctions[t.id]=s);for(var l=s.length,u=0;l>u;++u)s[u](e,r)}var c=i(n.scissorTest)?n.scissorTest:t.scissorTest,h=i(o.scissorTest)?o.scissorTest:r.scissorTest;(c!==h||a)&&m(e,r,o);var d=i(n.blendingEnabled)?n.blendingEnabled:t.blending.enabled,p=i(o.blendingEnabled)?o.blendingEnabled:r.blending.enabled;(d!==p||p&&t.blending!==r.blending)&&C(e,r,o),(t!==r||n.context!==o.context)&&S(e,r,o)},T.getState=function(r){return{frontFace:r.frontFace,cull:{enabled:r.cull.enabled,face:r.cull.face},lineWidth:r.lineWidth,polygonOffset:{enabled:r.polygonOffset.enabled,factor:r.polygonOffset.factor,units:r.polygonOffset.units},scissorTest:{enabled:r.scissorTest.enabled,rectangle:e.clone(r.scissorTest.rectangle)},depthRange:{near:r.depthRange.near,far:r.depthRange.far},depthTest:{enabled:r.depthTest.enabled,func:r.depthTest.func},colorMask:{red:r.colorMask.red,green:r.colorMask.green,blue:r.colorMask.blue,alpha:r.colorMask.alpha},depthMask:r.depthMask,stencilMask:r.stencilMask,blending:{enabled:r.blending.enabled,color:t.clone(r.blending.color),equationRgb:r.blending.equationRgb,equationAlpha:r.blending.equationAlpha,functionSourceRgb:r.blending.functionSourceRgb,functionSourceAlpha:r.blending.functionSourceAlpha,functionDestinationRgb:r.blending.functionDestinationRgb,functionDestinationAlpha:r.blending.functionDestinationAlpha},stencilTest:{enabled:r.stencilTest.enabled,frontFunction:r.stencilTest.frontFunction,backFunction:r.stencilTest.backFunction,reference:r.stencilTest.reference,mask:r.stencilTest.mask,frontOperation:{fail:r.stencilTest.frontOperation.fail,zFail:r.stencilTest.frontOperation.zFail,zPass:r.stencilTest.frontOperation.zPass},backOperation:{fail:r.stencilTest.backOperation.fail,zFail:r.stencilTest.backOperation.zFail,zPass:r.stencilTest.backOperation.zPass}},sampleCoverage:{enabled:r.sampleCoverage.enabled,value:r.sampleCoverage.value,invert:r.sampleCoverage.invert},viewport:i(r.viewport)?e.clone(r.viewport):void 0}},T}),r("Renderer/AutomaticUniforms",["../Core/Cartesian3","../Core/Matrix4","./WebGLConstants"],function(e,t,r){"use strict";var i=new e,n=function(e){this._size=e.size,this._datatype=e.datatype,this.getValue=e.getValue};if("undefined"==typeof WebGLRenderingContext)return{};var o={};o[r.FLOAT]="float",o[r.FLOAT_VEC2]="vec2",o[r.FLOAT_VEC3]="vec3",o[r.FLOAT_VEC4]="vec4",o[r.INT]="int",o[r.INT_VEC2]="ivec2",o[r.INT_VEC3]="ivec3",o[r.INT_VEC4]="ivec4",o[r.BOOL]="bool",o[r.BOOL_VEC2]="bvec2",o[r.BOOL_VEC3]="bvec3",o[r.BOOL_VEC4]="bvec4",o[r.FLOAT_MAT2]="mat2",o[r.FLOAT_MAT3]="mat3",o[r.FLOAT_MAT4]="mat4",o[r.SAMPLER_2D]="sampler2D",o[r.SAMPLER_CUBE]="samplerCube",n.prototype.getDeclaration=function(e){var t="uniform "+o[this._datatype]+" "+e,r=this._size;return t+=1===r?";":"["+r.toString()+"];"};var a={czm_viewport:new n({size:1,datatype:r.FLOAT_VEC4,getValue:function(e){return e.viewportCartesian4}}),czm_viewportOrthographic:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.viewportOrthographic}}),czm_viewportTransformation:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.viewportTransformation}}),czm_globeDepthTexture:new n({size:1,datatype:r.SAMPLER_2D,getValue:function(e){return e.globeDepthTexture}}),czm_model:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.model}}),czm_inverseModel:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModel}}),czm_view:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.view}}),czm_view3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.view3D}}),czm_viewRotation:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.viewRotation}}),czm_viewRotation3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.viewRotation3D}}),czm_inverseView:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseView}}),czm_inverseView3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseView3D}}),czm_inverseViewRotation:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseViewRotation}}),czm_inverseViewRotation3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseViewRotation3D}}),czm_projection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.projection}}),czm_inverseProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseProjection}}),czm_inverseProjectionOIT:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseProjectionOIT}}),czm_infiniteProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.infiniteProjection}}),czm_modelView:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelView}}),czm_modelView3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelView3D}}),czm_modelViewRelativeToEye:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewRelativeToEye}}),czm_inverseModelView:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModelView}}),czm_inverseModelView3D:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModelView3D}}),czm_viewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.viewProjection}}),czm_inverseViewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseViewProjection}}),czm_modelViewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewProjection}}),czm_inverseModelViewProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.inverseModelViewProjection}}),czm_modelViewProjectionRelativeToEye:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewProjectionRelativeToEye}}),czm_modelViewInfiniteProjection:new n({size:1,datatype:r.FLOAT_MAT4,getValue:function(e){return e.modelViewInfiniteProjection}}),czm_normal:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.normal}}),czm_normal3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.normal3D}}),czm_inverseNormal:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseNormal}}),czm_inverseNormal3D:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.inverseNormal3D}}),czm_eyeHeight2D:new n({size:1,datatype:r.FLOAT_VEC2,getValue:function(e){return e.eyeHeight2D}}),czm_entireFrustum:new n({size:1,datatype:r.FLOAT_VEC2,getValue:function(e){return e.entireFrustum}}),czm_currentFrustum:new n({size:1,datatype:r.FLOAT_VEC2,getValue:function(e){return e.currentFrustum}}),czm_frustumPlanes:new n({size:1,datatype:r.FLOAT_VEC4,getValue:function(e){return e.frustumPlanes}}),czm_sunPositionWC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunPositionWC}}),czm_sunPositionColumbusView:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunPositionColumbusView}}),czm_sunDirectionEC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunDirectionEC}}),czm_sunDirectionWC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.sunDirectionWC}}),czm_moonDirectionEC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.moonDirectionEC}}),czm_encodedCameraPositionMCHigh:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.encodedCameraPositionMCHigh}}),czm_encodedCameraPositionMCLow:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return e.encodedCameraPositionMCLow}}),czm_viewerPositionWC:new n({size:1,datatype:r.FLOAT_VEC3,getValue:function(e){return t.getTranslation(e.inverseView,i)}}),czm_frameNumber:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.frameState.frameNumber}}),czm_morphTime:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.frameState.morphTime}}),czm_sceneMode:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.frameState.mode}}),czm_temeToPseudoFixed:new n({size:1,datatype:r.FLOAT_MAT3,getValue:function(e){return e.temeToPseudoFixedMatrix}}),czm_resolutionScale:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.resolutionScale}}),czm_fogDensity:new n({size:1,datatype:r.FLOAT,getValue:function(e){return e.fogDensity}})};return a}),r("Renderer/createUniform",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/defined","../Core/DeveloperError","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Core/RuntimeError"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t,r,i){this.name=r,this.value=void 0,this._value=0,this._gl=e,this._location=i}function h(t,r,i,n){this.name=i,this.value=void 0,this._value=new e,this._gl=t,this._location=n}function d(e,t,r,i){this.name=r,this.value=void 0,this._value=void 0,this._gl=e,this._location=i}function p(e,t,r,i){this.name=r,this.value=void 0,this._value=void 0,this._gl=e,this._location=i}function m(e,t,r,i){this.name=r,this.value=void 0,this._gl=e,this._location=i,this.textureUnitIndex=void 0}function f(e,t,r,i){this.name=r,this.value=void 0,this._value=0,this._gl=e,this._location=i}function v(t,r,i,n){this.name=i,this.value=void 0,this._value=new e,this._gl=t,this._location=n}function _(e,r,i,n){this.name=i,this.value=void 0,this._value=new t,this._gl=e,this._location=n}function g(e,t,i,n){this.name=i,this.value=void 0,this._value=new r,this._gl=e,this._location=n}function y(e,t,r,i){this.name=r,this.value=void 0,this._value=new Float32Array(4),this._gl=e,this._location=i}function C(e,t,r,i){this.name=r,this.value=void 0,this._value=new Float32Array(9),this._gl=e,this._location=i}function E(e,t,r,i){this.name=r,this.value=void 0,this._value=new Float32Array(16),this._gl=e,this._location=i}var S=function(e,t,r,i){switch(t.type){case e.FLOAT:return new c(e,t,r,i);case e.FLOAT_VEC2:return new h(e,t,r,i);case e.FLOAT_VEC3:return new d(e,t,r,i);case e.FLOAT_VEC4:return new p(e,t,r,i);case e.SAMPLER_2D:case e.SAMPLER_CUBE:return new m(e,t,r,i);case e.INT:case e.BOOL:return new f(e,t,r,i);case e.INT_VEC2:case e.BOOL_VEC2:return new v(e,t,r,i);case e.INT_VEC3:case e.BOOL_VEC3:return new _(e,t,r,i);case e.INT_VEC4:case e.BOOL_VEC4:return new g(e,t,r,i);case e.FLOAT_MAT2:return new y(e,t,r,i);case e.FLOAT_MAT3:return new C(e,t,r,i);case e.FLOAT_MAT4:return new E(e,t,r,i);default:throw new u("Unrecognized uniform type: "+t.type+' for uniform "'+r+'".')}};return c.prototype.set=function(){this.value!==this._value&&(this._value=this.value,this._gl.uniform1f(this._location,this.value))},h.prototype.set=function(){var t=this.value;e.equals(t,this._value)||(e.clone(t,this._value),this._gl.uniform2f(this._location,t.x,t.y))},d.prototype.set=function(){var e=this.value;if(n(e.red))i.equals(e,this._value)||(this._value=i.clone(e,this._value),this._gl.uniform3f(this._location,e.red,e.green,e.blue));else{if(!n(e.x))throw new o('Invalid vec3 value for uniform "'+this._activethis.name+'".');t.equals(e,this._value)||(this._value=t.clone(e,this._value),this._gl.uniform3f(this._location,e.x,e.y,e.z))}},p.prototype.set=function(){var e=this.value;if(n(e.red))i.equals(e,this._value)||(this._value=i.clone(e,this._value),this._gl.uniform4f(this._location,e.red,e.green,e.blue,e.alpha));else{if(!n(e.x))throw new o('Invalid vec4 value for uniform "'+this._activethis.name+'".');r.equals(e,this._value)||(this._value=r.clone(e,this._value),this._gl.uniform4f(this._location,e.x,e.y,e.z,e.w))}},m.prototype.set=function(){var e=this._gl;e.activeTexture(e.TEXTURE0+this.textureUnitIndex);var t=this.value;e.bindTexture(t._target,t._texture)},m.prototype._setSampler=function(e){return this.textureUnitIndex=e,this._gl.uniform1i(this._location,e),e+1},f.prototype.set=function(){this.value!==this._value&&(this._value=this.value,this._gl.uniform1i(this._location,this.value))},v.prototype.set=function(){var t=this.value;e.equals(t,this._value)||(e.clone(t,this._value),this._gl.uniform2i(this._location,t.x,t.y))},_.prototype.set=function(){var e=this.value;t.equals(e,this._value)||(t.clone(e,this._value),this._gl.uniform3i(this._location,e.x,e.y,e.z))},g.prototype.set=function(){var e=this.value;r.equals(e,this._value)||(r.clone(e,this._value),this._gl.uniform4i(this._location,e.x,e.y,e.z,e.w))},y.prototype.set=function(){a.equalsArray(this.value,this._value,0)||(a.toArray(this.value,this._value),this._gl.uniformMatrix2fv(this._location,!1,this._value))},C.prototype.set=function(){s.equalsArray(this.value,this._value,0)||(s.toArray(this.value,this._value),this._gl.uniformMatrix3fv(this._location,!1,this._value))},E.prototype.set=function(){l.equalsArray(this.value,this._value,0)||(l.toArray(this.value,this._value),this._gl.uniformMatrix4fv(this._location,!1,this._value))},S}),r("Renderer/createUniformArray",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Core/RuntimeError"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(n),this._gl=e,this._location=i[0]}function d(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(2*n),this._gl=e,this._location=i[0]}function p(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(3*n),this._gl=e,this._location=i[0]}function m(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(4*n),this._gl=e,this._location=i[0]}function f(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(n),this._gl=e,this._locations=i,this.textureUnitIndex=void 0}function v(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(n),this._gl=e,this._location=i[0]}function _(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(2*n),this._gl=e,this._location=i[0]}function g(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(3*n),this._gl=e,this._location=i[0]}function y(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Int32Array(4*n),this._gl=e,this._location=i[0]}function C(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(4*n),this._gl=e,this._location=i[0]}function E(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(9*n),this._gl=e,this._location=i[0]}function S(e,t,r,i){var n=i.length;this.name=r,this.value=new Array(n),this._value=new Float32Array(16*n),this._gl=e,this._location=i[0]}var w=function(e,t,r,i){switch(t.type){case e.FLOAT:return new h(e,t,r,i);case e.FLOAT_VEC2:return new d(e,t,r,i);case e.FLOAT_VEC3:return new p(e,t,r,i);case e.FLOAT_VEC4:return new m(e,t,r,i);case e.SAMPLER_2D:case e.SAMPLER_CUBE:return new f(e,t,r,i);case e.INT:case e.BOOL:return new v(e,t,r,i);case e.INT_VEC2:case e.BOOL_VEC2:return new _(e,t,r,i);case e.INT_VEC3:case e.BOOL_VEC3:return new g(e,t,r,i);case e.INT_VEC4:case e.BOOL_VEC4:return new y(e,t,r,i);case e.FLOAT_MAT2:return new C(e,t,r,i);case e.FLOAT_MAT3:return new E(e,t,r,i);case e.FLOAT_MAT4:return new S(e,t,r,i);default:throw new c("Unrecognized uniform type: "+t.type+' for uniform "'+r+'".')}};return h.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0;t>n;++n){var o=e[n];o!==r[n]&&(r[n]=o,i=!0)}i&&this._gl.uniform1fv(this._location,r)},d.prototype.set=function(){for(var t=this.value,r=t.length,i=this._value,n=!1,o=0,a=0;r>a;++a){var s=t[a];e.equalsArray(s,i,o)||(e.pack(s,i,o),n=!0),o+=2}n&&this._gl.uniform2fv(this._location,i)},p.prototype.set=function(){for(var e=this.value,r=e.length,i=this._value,o=!1,s=0,l=0;r>l;++l){var u=e[l];if(n(u.red))(u.red!==i[s]||u.green!==i[s+1]||u.blue!==i[s+2])&&(i[s]=u.red,i[s+1]=u.green,i[s+2]=u.blue,o=!0);else{if(!n(u.x))throw new a("Invalid vec3 value.");t.equalsArray(u,i,s)||(t.pack(u,i,s),o=!0)}s+=3}o&&this._gl.uniform3fv(this._location,i)},m.prototype.set=function(){for(var e=this.value,t=e.length,o=this._value,s=!1,l=0,u=0;t>u;++u){var c=e[u];if(n(c.red))i.equalsArray(c,o,l)||(i.pack(c,o,l),s=!0);else{if(!n(c.x))throw new a("Invalid vec4 value.");r.equalsArray(c,o,l)||(r.pack(c,o,l),s=!0)}l+=4}s&&this._gl.uniform4fv(this._location,o)},f.prototype.set=function(){for(var e=this._gl,t=e.TEXTURE0+this.textureUnitIndex,r=this.value,i=r.length,n=0;i>n;++n){var o=r[n];e.activeTexture(t+n),e.bindTexture(o._target,o._texture)}},f.prototype._setSampler=function(e){this.textureUnitIndex=e;for(var t=this._locations,r=t.length,i=0;r>i;++i){var n=e+i;this._gl.uniform1i(t[i],n)}return e+r},v.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0;t>n;++n){var o=e[n];o!==r[n]&&(r[n]=o,i=!0)}i&&this._gl.uniform1iv(this._location,r)},_.prototype.set=function(){for(var t=this.value,r=t.length,i=this._value,n=!1,o=0,a=0;r>a;++a){var s=t[a];e.equalsArray(s,i,o)||(e.pack(s,i,o),n=!0),o+=2}n&&this._gl.uniform2iv(this._location,i)},g.prototype.set=function(){for(var e=this.value,r=e.length,i=this._value,n=!1,o=0,a=0;r>a;++a){var s=e[a];t.equalsArray(s,i,o)||(t.pack(s,i,o),n=!0),o+=3}n&&this._gl.uniform3iv(this._location,i)},y.prototype.set=function(){for(var e=this.value,t=e.length,i=this._value,n=!1,o=0,a=0;t>a;++a){var s=e[a];r.equalsArray(s,i,o)||(r.pack(s,i,o),n=!0),o+=4}n&&this._gl.uniform4iv(this._location,i)},C.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0,o=0;t>o;++o){var a=e[o];s.equalsArray(a,r,n)||(s.pack(a,r,n),i=!0),n+=4}i&&this._gl.uniformMatrix2fv(this._location,!1,r)},E.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0,o=0;t>o;++o){var a=e[o];l.equalsArray(a,r,n)||(l.pack(a,r,n),i=!0),n+=9}i&&this._gl.uniformMatrix3fv(this._location,!1,r)},S.prototype.set=function(){for(var e=this.value,t=e.length,r=this._value,i=!1,n=0,o=0;t>o;++o){var a=e[o];u.equalsArray(a,r,n)||(u.pack(a,r,n),i=!0),n+=16}i&&this._gl.uniformMatrix4fv(this._location,!1,r)},w}),r("Renderer/ShaderProgram",["../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/RuntimeError","./AutomaticUniforms","./ContextLimits","./createUniform","./createUniformArray"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e){var t=[],i=e.match(/uniform.*?(?![^{]*})(?=[=\[;])/g);if(r(i))for(var n=i.length,o=0;n>o;o++){var a=i[o].trim(),s=a.slice(a.lastIndexOf(" ")+1);t.push(s)}return t}function d(e,t){var r={};if(!l.highpFloatSupported||!l.highpIntSupported){var i,n,o,a,s=h(e),u=h(t),c=s.length,d=u.length;for(i=0;c>i;i++)for(n=0;d>n;n++)if(s[i]===u[n]){o=s[i],a="czm_mediump_"+o;var p=new RegExp(o+"\\b","g");t=t.replace(p,a),r[a]=o}}return{fragmentShaderText:t,duplicateUniformNames:r}}function p(e,r){var i=r._vertexShaderText,n=r._fragmentShaderText,o=e.createShader(e.VERTEX_SHADER);e.shaderSource(o,i),e.compileShader(o);var s=e.createShader(e.FRAGMENT_SHADER);e.shaderSource(s,n),e.compileShader(s);var l=e.createProgram();e.attachShader(l,o),e.attachShader(l,s),e.deleteShader(o),e.deleteShader(s);var u=r._attributeLocations;if(t(u))for(var c in u)u.hasOwnProperty(c)&&e.bindAttribLocation(l,u[c],c);e.linkProgram(l);var h;if(!e.getProgramParameter(l,e.LINK_STATUS)){var d=r._debugShaders;if(!e.getShaderParameter(s,e.COMPILE_STATUS)){if(h=e.getShaderInfoLog(s),console.error(E+"Fragment shader compile log: "+h),t(d)){var p=d.getTranslatedShaderSource(s);""!==p?console.error(E+"Translated fragment shader source:\n"+p):console.error(E+"Fragment shader translation failed.")}throw e.deleteProgram(l),new a("Fragment shader failed to compile. Compile log: "+h)}if(!e.getShaderParameter(o,e.COMPILE_STATUS)){if(h=e.getShaderInfoLog(o),console.error(E+"Vertex shader compile log: "+h),t(d)){var m=d.getTranslatedShaderSource(o);""!==m?console.error(E+"Translated vertex shader source:\n"+m):console.error(E+"Vertex shader translation failed.")}throw e.deleteProgram(l),new a("Vertex shader failed to compile. Compile log: "+h)}throw h=e.getProgramInfoLog(l),console.error(E+"Shader program link log: "+h),t(d)&&(console.error(E+"Translated vertex shader source:\n"+d.getTranslatedShaderSource(o)),console.error(E+"Translated fragment shader source:\n"+d.getTranslatedShaderSource(s))),e.deleteProgram(l),new a("Program failed to link. Link log: "+h)}var f=r._logShaderCompilation;return f&&(h=e.getShaderInfoLog(o),t(h)&&h.length>0&&console.log(E+"Vertex shader compile log: "+h)),f&&(h=e.getShaderInfoLog(s),t(h)&&h.length>0&&console.log(E+"Fragment shader compile log: "+h)),f&&(h=e.getProgramInfoLog(l),t(h)&&h.length>0&&console.log(E+"Shader program link log: "+h)),l}function m(e,t,r){for(var i={},n=0;r>n;++n){var o=e.getActiveAttrib(t,n),a=e.getAttribLocation(t,o.name);i[o.name]={name:o.name,type:o.type,index:a}}return i}function f(e,r){for(var i={},n=[],o=[],a=e.getProgramParameter(r,e.ACTIVE_UNIFORMS),s=0;a>s;++s){var l=e.getActiveUniform(r,s),h="[0]",d=-1!==l.name.indexOf(h,l.name.length-h.length)?l.name.slice(0,l.name.length-3):l.name;if(0!==d.indexOf("gl_"))if(l.name.indexOf("[")<0){var p=e.getUniformLocation(r,d);if(null!==p){var m=u(e,l,d,p);i[d]=m,n.push(m),m._setSampler&&o.push(m)}}else{var f,v,_,g,y=d.indexOf("[");if(y>=0){if(f=i[d.slice(0,y)],!t(f))continue;v=f._locations, -v.length<=1&&(_=f.value,g=e.getUniformLocation(r,d),null!==g&&(v.push(g),_.push(e.getUniform(r,g))))}else{v=[];for(var C=0;C<l.size;++C)g=e.getUniformLocation(r,d+"["+C+"]"),null!==g&&v.push(g);f=c(e,l,d,v),i[d]=f,n.push(f),f._setSampler&&o.push(f)}}}return{uniformsByName:i,uniforms:n,samplerUniforms:o}}function v(e,r){var i=[],n=[];for(var o in r)if(r.hasOwnProperty(o)){var a=r[o],l=o,u=e._duplicateUniformNames[l];t(u)&&(a.name=u,l=u);var c=s[l];t(c)?i.push({uniform:a,automaticUniform:c}):n.push(a)}return{automaticUniforms:i,manualUniforms:n}}function _(e,t,r){e.useProgram(t);for(var i=0,n=r.length,o=0;n>o;++o)i=r[o]._setSampler(i);return e.useProgram(null),i}function g(e){if(!t(e._program)){var r=e._gl,i=p(r,e,e._debugShaders),n=r.getProgramParameter(i,r.ACTIVE_ATTRIBUTES),o=f(r,i),a=v(e,o.uniformsByName);e._program=i,e._numberOfVertexAttributes=n,e._vertexAttributes=m(r,i,n),e._uniformsByName=o.uniformsByName,e._uniforms=o.uniforms,e._automaticUniforms=a.automaticUniforms,e._manualUniforms=a.manualUniforms,e.maximumTextureUnitIndex=_(r,i,o.samplerUniforms)}}var y=0,C=function(e){var t=d(e.vertexShaderText,e.fragmentShaderText);this._gl=e.gl,this._logShaderCompilation=e.logShaderCompilation,this._debugShaders=e.debugShaders,this._attributeLocations=e.attributeLocations,this._program=void 0,this._numberOfVertexAttributes=void 0,this._vertexAttributes=void 0,this._uniformsByName=void 0,this._uniforms=void 0,this._automaticUniforms=void 0,this._manualUniforms=void 0,this._duplicateUniformNames=t.duplicateUniformNames,this._cachedShader=void 0,this.maximumTextureUnitIndex=void 0,this._vertexShaderSource=e.vertexShaderSource,this._vertexShaderText=e.vertexShaderText,this._fragmentShaderSource=e.fragmentShaderSource,this._fragmentShaderText=t.fragmentShaderText,this.id=y++};C.fromCache=function(t){return t=e(t,e.EMPTY_OBJECT),t.context.shaderCache.getShaderProgram(t)},C.replaceCache=function(t){return t=e(t,e.EMPTY_OBJECT),t.context.shaderCache.replaceShaderProgram(t)},i(C.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},vertexAttributes:{get:function(){return g(this),this._vertexAttributes}},numberOfVertexAttributes:{get:function(){return g(this),this._numberOfVertexAttributes}},allUniforms:{get:function(){return g(this),this._uniformsByName}}});var E="[Cesium WebGL] ";return C.prototype._bind=function(){g(this),this._gl.useProgram(this._program)},C.prototype._setUniforms=function(e,r,i){var n,a;if(t(e)){var s=this._manualUniforms;for(n=s.length,a=0;n>a;++a){var l=s[a];l.value=e[l.name]()}}var u=this._automaticUniforms;for(n=u.length,a=0;n>a;++a){var c=u[a];c.uniform.value=c.automaticUniform.getValue(r)}var h=this._uniforms;for(n=h.length,a=0;n>a;++a)h[a].set();if(i){var d=this._gl,p=this._program;if(d.validateProgram(p),!d.getProgramParameter(p,d.VALIDATE_STATUS))throw new o("Program validation failed. Program info log: "+d.getProgramInfoLog(p))}},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){return void this._cachedShader.cache.releaseShaderProgram(this)},C.prototype.finalDestroy=function(){return this._gl.deleteProgram(this._program),n(this)},C}),r("Shaders/Builtin/Constants/degreesPerRadian",[],function(){"use strict";return"const float czm_degreesPerRadian = 57.29577951308232;\n"}),r("Shaders/Builtin/Constants/depthRange",[],function(){"use strict";return"const czm_depthRangeStruct czm_depthRange = czm_depthRangeStruct(0.0, 1.0);\n"}),r("Shaders/Builtin/Constants/epsilon1",[],function(){"use strict";return"const float czm_epsilon1 = 0.1;\n"}),r("Shaders/Builtin/Constants/epsilon2",[],function(){"use strict";return"const float czm_epsilon2 = 0.01;\n"}),r("Shaders/Builtin/Constants/epsilon3",[],function(){"use strict";return"const float czm_epsilon3 = 0.001;\n"}),r("Shaders/Builtin/Constants/epsilon4",[],function(){"use strict";return"const float czm_epsilon4 = 0.0001;\n"}),r("Shaders/Builtin/Constants/epsilon5",[],function(){"use strict";return"const float czm_epsilon5 = 0.00001;\n"}),r("Shaders/Builtin/Constants/epsilon6",[],function(){"use strict";return"const float czm_epsilon6 = 0.000001;\n"}),r("Shaders/Builtin/Constants/epsilon7",[],function(){"use strict";return"const float czm_epsilon7 = 0.0000001;\n"}),r("Shaders/Builtin/Constants/infinity",[],function(){"use strict";return"const float czm_infinity = 5906376272000.0;\n"}),r("Shaders/Builtin/Constants/oneOverPi",[],function(){"use strict";return"const float czm_oneOverPi = 0.3183098861837907;\n"}),r("Shaders/Builtin/Constants/oneOverTwoPi",[],function(){"use strict";return"const float czm_oneOverTwoPi = 0.15915494309189535;\n"}),r("Shaders/Builtin/Constants/pi",[],function(){"use strict";return"const float czm_pi = 3.141592653589793;\n"}),r("Shaders/Builtin/Constants/piOverFour",[],function(){"use strict";return"const float czm_piOverFour = 0.7853981633974483;\n"}),r("Shaders/Builtin/Constants/piOverSix",[],function(){"use strict";return"const float czm_piOverSix = 0.5235987755982988;\n"}),r("Shaders/Builtin/Constants/piOverThree",[],function(){"use strict";return"const float czm_piOverThree = 1.0471975511965976;\n"}),r("Shaders/Builtin/Constants/piOverTwo",[],function(){"use strict";return"const float czm_piOverTwo = 1.5707963267948966;\n"}),r("Shaders/Builtin/Constants/radiansPerDegree",[],function(){"use strict";return"const float czm_radiansPerDegree = 0.017453292519943295;\n"}),r("Shaders/Builtin/Constants/sceneMode2D",[],function(){"use strict";return"const float czm_sceneMode2D = 2.0;\n"}),r("Shaders/Builtin/Constants/sceneMode3D",[],function(){"use strict";return"const float czm_sceneMode3D = 3.0;\n"}),r("Shaders/Builtin/Constants/sceneModeColumbusView",[],function(){"use strict";return"const float czm_sceneModeColumbusView = 1.0;\n"}),r("Shaders/Builtin/Constants/sceneModeMorphing",[],function(){"use strict";return"const float czm_sceneModeMorphing = 0.0;\n"}),r("Shaders/Builtin/Constants/solarRadius",[],function(){"use strict";return"const float czm_solarRadius = 695500000.0;\n"}),r("Shaders/Builtin/Constants/threePiOver2",[],function(){"use strict";return"const float czm_threePiOver2 = 4.71238898038469;\n"}),r("Shaders/Builtin/Constants/twoPi",[],function(){"use strict";return"const float czm_twoPi = 6.283185307179586;\n"}),r("Shaders/Builtin/Constants/webMercatorMaxLatitude",[],function(){"use strict";return"const float czm_webMercatorMaxLatitude = 1.4844222297453324;\n"}),r("Shaders/Builtin/Structs/depthRangeStruct",[],function(){"use strict";return"struct czm_depthRangeStruct\n{\nfloat near;\nfloat far;\n};\n"}),r("Shaders/Builtin/Structs/ellipsoid",[],function(){"use strict";return"struct czm_ellipsoid\n{\nvec3 center;\nvec3 radii;\nvec3 inverseRadii;\nvec3 inverseRadiiSquared;\n};\n"}),r("Shaders/Builtin/Structs/material",[],function(){"use strict";return"struct czm_material\n{\nvec3 diffuse;\nfloat specular;\nfloat shininess;\nvec3 normal;\nvec3 emission;\nfloat alpha;\n};\n"}),r("Shaders/Builtin/Structs/materialInput",[],function(){"use strict";return"struct czm_materialInput\n{\nfloat s;\nvec2 st;\nvec3 str;\nvec3 normalEC;\nmat3 tangentToEyeMatrix;\nvec3 positionToEyeEC;\n};\n"}),r("Shaders/Builtin/Structs/ray",[],function(){"use strict";return"struct czm_ray\n{\nvec3 origin;\nvec3 direction;\n};\n"}),r("Shaders/Builtin/Structs/raySegment",[],function(){"use strict";return"struct czm_raySegment\n{\nfloat start;\nfloat stop;\n};\nconst czm_raySegment czm_emptyRaySegment = czm_raySegment(-czm_infinity, -czm_infinity);\nconst czm_raySegment czm_fullRaySegment = czm_raySegment(0.0, czm_infinity);\n"}),r("Shaders/Builtin/Functions/RGBToXYZ",[],function(){"use strict";return"vec3 czm_RGBToXYZ(vec3 rgb)\n{\nconst mat3 RGB2XYZ = mat3(0.4124, 0.2126, 0.0193,\n0.3576, 0.7152, 0.1192,\n0.1805, 0.0722, 0.9505);\nvec3 xyz = RGB2XYZ * rgb;\nvec3 Yxy;\nYxy.r = xyz.g;\nfloat temp = dot(vec3(1.0), xyz);\nYxy.gb = xyz.rg / temp;\nreturn Yxy;\n}\n"}),r("Shaders/Builtin/Functions/XYZToRGB",[],function(){"use strict";return"vec3 czm_XYZToRGB(vec3 Yxy)\n{\nconst mat3 XYZ2RGB = mat3( 3.2405, -0.9693, 0.0556,\n-1.5371, 1.8760, -0.2040,\n-0.4985, 0.0416, 1.0572);\nvec3 xyz;\nxyz.r = Yxy.r * Yxy.g / Yxy.b;\nxyz.g = Yxy.r;\nxyz.b = Yxy.r * (1.0 - Yxy.g - Yxy.b) / Yxy.b;\nreturn XYZ2RGB * xyz;\n}\n"}),r("Shaders/Builtin/Functions/alphaWeight",[],function(){"use strict";return"float czm_alphaWeight(float a)\n{\nfloat z;\nif (czm_sceneMode != czm_sceneMode2D)\n{\nfloat x = 2.0 * (gl_FragCoord.x - czm_viewport.x) / czm_viewport.z - 1.0;\nfloat y = 2.0 * (gl_FragCoord.y - czm_viewport.y) / czm_viewport.w - 1.0;\nz = (gl_FragCoord.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\nvec4 q = vec4(x, y, z, 0.0);\nq /= gl_FragCoord.w;\nz = (czm_inverseProjectionOIT * q).z;\n}\nelse\n{\nz = gl_FragCoord.z * (czm_currentFrustum.y - czm_currentFrustum.x) + czm_currentFrustum.x;\n}\nreturn pow(a + 0.01, 4.0) + max(1e-2, min(3.0 * 1e3, 100.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0))));\n}\n"}),r("Shaders/Builtin/Functions/antialias",[],function(){"use strict";return"vec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist, float fuzzFactor)\n{\nfloat val1 = clamp(dist / fuzzFactor, 0.0, 1.0);\nfloat val2 = clamp((dist - 0.5) / fuzzFactor, 0.0, 1.0);\nval1 = val1 * (1.0 - val2);\nval1 = val1 * val1 * (3.0 - (2.0 * val1));\nval1 = pow(val1, 0.5);\nvec4 midColor = (color1 + color2) * 0.5;\nreturn mix(midColor, currentColor, val1);\n}\nvec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist)\n{\nreturn czm_antialias(color1, color2, currentColor, dist, 0.1);\n}\n"}),r("Shaders/Builtin/Functions/columbusViewMorph",[],function(){"use strict";return"vec4 czm_columbusViewMorph(vec4 position2D, vec4 position3D, float time)\n{\nvec3 p = mix(position2D.xyz, position3D.xyz, time);\nreturn vec4(p, 1.0);\n}\n"}),r("Shaders/Builtin/Functions/computePosition",[],function(){"use strict";return"vec4 czm_computePosition();\n"}),r("Shaders/Builtin/Functions/cosineAndSine",[],function(){"use strict";return"vec2 cordic(float angle)\n{\nvec2 vector = vec2(6.0725293500888267e-1, 0.0);\nfloat sense = (angle < 0.0) ? -1.0 : 1.0;\nmat2 rotation = mat2(1.0, sense, -sense, 1.0);\nvector = rotation * vector;\nangle -= sense * 7.8539816339744828e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfloat factor = sense * 5.0e-1;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 4.6364760900080609e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 2.5e-1;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 2.4497866312686414e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.25e-1;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.2435499454676144e-1;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 6.25e-2;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 6.2418809995957350e-2;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.125e-2;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.1239833430268277e-2;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.5625e-2;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.5623728620476831e-2;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 7.8125e-3;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 7.8123410601011111e-3;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.90625e-3;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.9062301319669718e-3;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.953125e-3;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.9531225164788188e-3;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 9.765625e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 9.7656218955931946e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 4.8828125e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 4.8828121119489829e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 2.44140625e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 2.4414062014936177e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.220703125e-4;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.2207031189367021e-4;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 6.103515625e-5;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 6.1035156174208773e-5;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.0517578125e-5;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.0517578115526096e-5;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.52587890625e-5;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.5258789061315762e-5;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 7.62939453125e-6;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 7.6293945311019700e-6;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 3.814697265625e-6;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 3.8146972656064961e-6;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.9073486328125e-6;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 1.9073486328101870e-6;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 9.5367431640625e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 9.5367431640596084e-7;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 4.76837158203125e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 4.7683715820308884e-7;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 2.384185791015625e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nangle -= sense * 2.3841857910155797e-7;\nsense = (angle < 0.0) ? -1.0 : 1.0;\nfactor = sense * 1.1920928955078125e-7;\nrotation[0][1] = factor;\nrotation[1][0] = -factor;\nvector = rotation * vector;\nreturn vector;\n}\nvec2 czm_cosineAndSine(float angle)\n{\nif (angle < -czm_piOverTwo || angle > czm_piOverTwo)\n{\nif (angle < 0.0)\n{\nreturn -cordic(angle + czm_pi);\n}\nelse\n{\nreturn -cordic(angle - czm_pi);\n}\n}\nelse\n{\nreturn cordic(angle);\n}\n}\n"}),r("Shaders/Builtin/Functions/decompressTextureCoordinates",[],function(){"use strict";return"vec2 czm_decompressTextureCoordinates(float encoded)\n{\nfloat temp = encoded / 4096.0;\nfloat stx = floor(temp) / 4096.0;\nfloat sty = temp - floor(temp);\nreturn vec2(stx, sty);\n}\n"}),r("Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates",[],function(){"use strict";return"mat3 czm_eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC)\n{\nvec3 tangentMC = normalize(vec3(-positionMC.y, positionMC.x, 0.0));\nvec3 tangentEC = normalize(czm_normal3D * tangentMC);\nvec3 bitangentEC = normalize(cross(normalEC, tangentEC));\nreturn mat3(\ntangentEC.x, tangentEC.y, tangentEC.z,\nbitangentEC.x, bitangentEC.y, bitangentEC.z,\nnormalEC.x, normalEC.y, normalEC.z);\n}\n"}),r("Shaders/Builtin/Functions/ellipsoidContainsPoint",[],function(){"use strict";return"bool czm_ellipsoidContainsPoint(czm_ellipsoid ellipsoid, vec3 point)\n{\nvec3 scaled = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(point, 1.0)).xyz;\nreturn (dot(scaled, scaled) <= 1.0);\n}\n"}),r("Shaders/Builtin/Functions/ellipsoidNew",[],function(){"use strict";return"czm_ellipsoid czm_ellipsoidNew(vec3 center, vec3 radii)\n{\nvec3 inverseRadii = vec3(1.0 / radii.x, 1.0 / radii.y, 1.0 / radii.z);\nvec3 inverseRadiiSquared = inverseRadii * inverseRadii;\nczm_ellipsoid temp = czm_ellipsoid(center, radii, inverseRadii, inverseRadiiSquared);\nreturn temp;\n}\n"}),r("Shaders/Builtin/Functions/ellipsoidWgs84TextureCoordinates",[],function(){"use strict";return"vec2 czm_ellipsoidWgs84TextureCoordinates(vec3 normal)\n{\nreturn vec2(atan(normal.y, normal.x) * czm_oneOverTwoPi + 0.5, asin(normal.z) * czm_oneOverPi + 0.5);\n}\n"}),r("Shaders/Builtin/Functions/equalsEpsilon",[],function(){"use strict";return"bool czm_equalsEpsilon(vec4 left, vec4 right, float epsilon) {\nreturn all(lessThanEqual(abs(left - right), vec4(epsilon)));\n}\nbool czm_equalsEpsilon(vec3 left, vec3 right, float epsilon) {\nreturn all(lessThanEqual(abs(left - right), vec3(epsilon)));\n}\nbool czm_equalsEpsilon(vec2 left, vec2 right, float epsilon) {\nreturn all(lessThanEqual(abs(left - right), vec2(epsilon)));\n}\nbool czm_equalsEpsilon(float left, float right, float epsilon) {\nreturn (abs(left - right) <= epsilon);\n}\n"}),r("Shaders/Builtin/Functions/eyeOffset",[],function(){"use strict";return"vec4 czm_eyeOffset(vec4 positionEC, vec3 eyeOffset)\n{\nvec4 p = positionEC;\nvec4 zEyeOffset = normalize(p) * eyeOffset.z;\np.xy += eyeOffset.xy + zEyeOffset.xy;\np.z += zEyeOffset.z;\nreturn p;\n}\n"}),r("Shaders/Builtin/Functions/eyeToWindowCoordinates",[],function(){"use strict";return"vec4 czm_eyeToWindowCoordinates(vec4 positionEC)\n{\nvec4 q = czm_projection * positionEC;\nq.xyz /= q.w;\nq.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz;\nreturn q;\n}\n"}),r("Shaders/Builtin/Functions/fog",[],function(){"use strict";return"vec3 czm_fog(float distanceToCamera, vec3 color, vec3 fogColor)\n{\nfloat scalar = distanceToCamera * czm_fogDensity;\nfloat fog = 1.0 - exp(-(scalar * scalar));\nreturn mix(color, fogColor, fog);\n}\n"}),r("Shaders/Builtin/Functions/geodeticSurfaceNormal",[],function(){"use strict";return"vec3 czm_geodeticSurfaceNormal(vec3 positionOnEllipsoid, vec3 ellipsoidCenter, vec3 oneOverEllipsoidRadiiSquared)\n{\nreturn normalize((positionOnEllipsoid - ellipsoidCenter) * oneOverEllipsoidRadiiSquared);\n}\n"}),r("Shaders/Builtin/Functions/getDefaultMaterial",[],function(){"use strict";return"czm_material czm_getDefaultMaterial(czm_materialInput materialInput)\n{\nczm_material material;\nmaterial.diffuse = vec3(0.0);\nmaterial.specular = 0.0;\nmaterial.shininess = 1.0;\nmaterial.normal = materialInput.normalEC;\nmaterial.emission = vec3(0.0);\nmaterial.alpha = 1.0;\nreturn material;\n}\n"}),r("Shaders/Builtin/Functions/getLambertDiffuse",[],function(){"use strict";return"float czm_getLambertDiffuse(vec3 lightDirectionEC, vec3 normalEC)\n{\nreturn max(dot(lightDirectionEC, normalEC), 0.0);\n}\n"}),r("Shaders/Builtin/Functions/getSpecular",[],function(){"use strict";return"float czm_getSpecular(vec3 lightDirectionEC, vec3 toEyeEC, vec3 normalEC, float shininess)\n{\nvec3 toReflectedLight = reflect(-lightDirectionEC, normalEC);\nfloat specular = max(dot(toReflectedLight, toEyeEC), 0.0);\nreturn pow(specular, shininess);\n}\n"}),r("Shaders/Builtin/Functions/getWaterNoise",[],function(){"use strict";return"vec4 czm_getWaterNoise(sampler2D normalMap, vec2 uv, float time, float angleInRadians)\n{\nfloat cosAngle = cos(angleInRadians);\nfloat sinAngle = sin(angleInRadians);\nvec2 s0 = vec2(1.0/17.0, 0.0);\nvec2 s1 = vec2(-1.0/29.0, 0.0);\nvec2 s2 = vec2(1.0/101.0, 1.0/59.0);\nvec2 s3 = vec2(-1.0/109.0, -1.0/57.0);\ns0 = vec2((cosAngle * s0.x) - (sinAngle * s0.y), (sinAngle * s0.x) + (cosAngle * s0.y));\ns1 = vec2((cosAngle * s1.x) - (sinAngle * s1.y), (sinAngle * s1.x) + (cosAngle * s1.y));\ns2 = vec2((cosAngle * s2.x) - (sinAngle * s2.y), (sinAngle * s2.x) + (cosAngle * s2.y));\ns3 = vec2((cosAngle * s3.x) - (sinAngle * s3.y), (sinAngle * s3.x) + (cosAngle * s3.y));\nvec2 uv0 = (uv/103.0) + (time * s0);\nvec2 uv1 = uv/107.0 + (time * s1) + vec2(0.23);\nvec2 uv2 = uv/vec2(897.0, 983.0) + (time * s2) + vec2(0.51);\nvec2 uv3 = uv/vec2(991.0, 877.0) + (time * s3) + vec2(0.71);\nuv0 = fract(uv0);\nuv1 = fract(uv1);\nuv2 = fract(uv2);\nuv3 = fract(uv3);\nvec4 noise = (texture2D(normalMap, uv0)) +\n(texture2D(normalMap, uv1)) +\n(texture2D(normalMap, uv2)) +\n(texture2D(normalMap, uv3));\nreturn ((noise / 4.0) - 0.5) * 2.0;\n}\n"}),r("Shaders/Builtin/Functions/getWgs84EllipsoidEC",[],function(){"use strict";return"czm_ellipsoid czm_getWgs84EllipsoidEC()\n{\nvec3 radii = vec3(6378137.0, 6378137.0, 6356752.314245);\nvec3 inverseRadii = vec3(1.0 / radii.x, 1.0 / radii.y, 1.0 / radii.z);\nvec3 inverseRadiiSquared = inverseRadii * inverseRadii;\nczm_ellipsoid temp = czm_ellipsoid(czm_view[3].xyz, radii, inverseRadii, inverseRadiiSquared);\nreturn temp;\n}\n"}),r("Shaders/Builtin/Functions/hue",[],function(){"use strict";return"vec3 czm_hue(vec3 rgb, float adjustment)\n{\nconst mat3 toYIQ = mat3(0.299, 0.587, 0.114,\n0.595716, -0.274453, -0.321263,\n0.211456, -0.522591, 0.311135);\nconst mat3 toRGB = mat3(1.0, 0.9563, 0.6210,\n1.0, -0.2721, -0.6474,\n1.0, -1.107, 1.7046);\nvec3 yiq = toYIQ * rgb;\nfloat hue = atan(yiq.z, yiq.y) + adjustment;\nfloat chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);\nvec3 color = vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));\nreturn toRGB * color;\n}\n"}),r("Shaders/Builtin/Functions/isEmpty",[],function(){"use strict";return"bool czm_isEmpty(czm_raySegment interval)\n{\nreturn (interval.stop < 0.0);\n}\n"}),r("Shaders/Builtin/Functions/isFull",[],function(){"use strict";return"bool czm_isFull(czm_raySegment interval)\n{\nreturn (interval.start == 0.0 && interval.stop == czm_infinity);\n}\n"}),r("Shaders/Builtin/Functions/latitudeToWebMercatorFraction",[],function(){"use strict";return"float czm_latitudeToWebMercatorFraction(float latitude, float southMercatorY, float oneOverMercatorHeight)\n{\nfloat sinLatitude = sin(latitude);\nfloat mercatorY = 0.5 * log((1.0 + sinLatitude) / (1.0 - sinLatitude));\nreturn (mercatorY - southMercatorY) * oneOverMercatorHeight;\n}\n"}),r("Shaders/Builtin/Functions/luminance",[],function(){"use strict";return"float czm_luminance(vec3 rgb)\n{\nconst vec3 W = vec3(0.2125, 0.7154, 0.0721);\nreturn dot(rgb, W);\n}\n"}),r("Shaders/Builtin/Functions/metersPerPixel",[],function(){"use strict";return"float czm_metersPerPixel(vec4 positionEC)\n{\nfloat width = czm_viewport.z;\nfloat height = czm_viewport.w;\nfloat pixelWidth;\nfloat pixelHeight;\nfloat top = czm_frustumPlanes.x;\nfloat bottom = czm_frustumPlanes.y;\nfloat left = czm_frustumPlanes.z;\nfloat right = czm_frustumPlanes.w;\nif (czm_sceneMode == czm_sceneMode2D)\n{\nfloat frustumWidth = right - left;\nfloat frustumHeight = top - bottom;\npixelWidth = frustumWidth / width;\npixelHeight = frustumHeight / height;\n}\nelse\n{\nfloat distanceToPixel = -positionEC.z;\nfloat inverseNear = 1.0 / czm_currentFrustum.x;\nfloat tanTheta = top * inverseNear;\npixelHeight = 2.0 * distanceToPixel * tanTheta / height;\ntanTheta = right * inverseNear;\npixelWidth = 2.0 * distanceToPixel * tanTheta / width;\n}\nreturn max(pixelWidth, pixelHeight);\n}\n"}),r("Shaders/Builtin/Functions/modelToWindowCoordinates",[],function(){"use strict";return"vec4 czm_modelToWindowCoordinates(vec4 position)\n{\nvec4 q = czm_modelViewProjection * position;\nq.xyz /= q.w;\nq.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz;\nreturn q;\n}\n"}),r("Shaders/Builtin/Functions/multiplyWithColorBalance",[],function(){"use strict";return"vec3 czm_multiplyWithColorBalance(vec3 left, vec3 right)\n{\nconst vec3 W = vec3(0.2125, 0.7154, 0.0721);\nvec3 target = left * right;\nfloat leftLuminance = dot(left, W);\nfloat rightLuminance = dot(right, W);\nfloat targetLuminance = dot(target, W);\nreturn ((leftLuminance + rightLuminance) / (2.0 * targetLuminance)) * target;\n}\n"}),r("Shaders/Builtin/Functions/nearFarScalar",[],function(){"use strict";return"float czm_nearFarScalar(vec4 nearFarScalar, float cameraDistSq)\n{\nfloat valueAtMin = nearFarScalar.y;\nfloat valueAtMax = nearFarScalar.w;\nfloat nearDistanceSq = nearFarScalar.x * nearFarScalar.x;\nfloat farDistanceSq = nearFarScalar.z * nearFarScalar.z;\nfloat t = (cameraDistSq - nearDistanceSq) / (farDistanceSq - nearDistanceSq);\nt = pow(clamp(t, 0.0, 1.0), 0.2);\nreturn mix(valueAtMin, valueAtMax, t);\n}\n"}),r("Shaders/Builtin/Functions/octDecode",[],function(){"use strict";return"vec3 czm_octDecode(vec2 encoded)\n{\nencoded = encoded / 255.0 * 2.0 - 1.0;\nvec3 v = vec3(encoded.x, encoded.y, 1.0 - abs(encoded.x) - abs(encoded.y));\nif (v.z < 0.0)\n{\nv.xy = (1.0 - abs(v.yx)) * czm_signNotZero(v.xy);\n}\nreturn normalize(v);\n}\nvec3 czm_octDecode(float encoded)\n{\nfloat temp = encoded / 256.0;\nfloat x = floor(temp);\nfloat y = (temp - x) * 256.0;\nreturn czm_octDecode(vec2(x, y));\n}\nvoid czm_octDecode(vec2 encoded, out vec3 vector1, out vec3 vector2, out vec3 vector3)\n{\nfloat temp = encoded.x / 65536.0;\nfloat x = floor(temp);\nfloat encodedFloat1 = (temp - x) * 65536.0;\ntemp = encoded.y / 65536.0;\nfloat y = floor(temp);\nfloat encodedFloat2 = (temp - y) * 65536.0;\nvector1 = czm_octDecode(encodedFloat1);\nvector2 = czm_octDecode(encodedFloat2);\nvector3 = czm_octDecode(vec2(x, y));\n}\n"}),r("Shaders/Builtin/Functions/packDepth",[],function(){"use strict";return"vec4 czm_packDepth(float depth)\n{\nvec4 enc = vec4(1.0, 255.0, 65025.0, 160581375.0) * depth;\nenc = fract(enc);\nenc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\nreturn enc;\n}\n"}),r("Shaders/Builtin/Functions/phong",[],function(){"use strict";return"float czm_private_getLambertDiffuseOfMaterial(vec3 lightDirectionEC, czm_material material)\n{\nreturn czm_getLambertDiffuse(lightDirectionEC, material.normal);\n}\nfloat czm_private_getSpecularOfMaterial(vec3 lightDirectionEC, vec3 toEyeEC, czm_material material)\n{\nreturn czm_getSpecular(lightDirectionEC, toEyeEC, material.normal, material.shininess);\n}\nvec4 czm_phong(vec3 toEye, czm_material material)\n{\nfloat diffuse = czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 0.0, 1.0), material);\nif (czm_sceneMode == czm_sceneMode3D) {\ndiffuse += czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 1.0, 0.0), material);\n}\nfloat specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material) + czm_private_getSpecularOfMaterial(czm_moonDirectionEC, toEye, material);\nvec3 materialDiffuse = material.diffuse * 0.5;\nvec3 ambient = materialDiffuse;\nvec3 color = ambient + material.emission;\ncolor += materialDiffuse * diffuse;\ncolor += material.specular * specular;\nreturn vec4(color, material.alpha);\n}\nvec4 czm_private_phong(vec3 toEye, czm_material material)\n{\nfloat diffuse = czm_private_getLambertDiffuseOfMaterial(czm_sunDirectionEC, material);\nfloat specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material);\nvec3 ambient = vec3(0.0);\nvec3 color = ambient + material.emission;\ncolor += material.diffuse * diffuse;\ncolor += material.specular * specular;\nreturn vec4(color, material.alpha);\n}\n"}),r("Shaders/Builtin/Functions/pointAlongRay",[],function(){"use strict";return"vec3 czm_pointAlongRay(czm_ray ray, float time)\n{\nreturn ray.origin + (time * ray.direction);\n}\n"}),r("Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval",[],function(){"use strict";return"czm_raySegment czm_rayEllipsoidIntersectionInterval(czm_ray ray, czm_ellipsoid ellipsoid)\n{\nvec3 q = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ray.origin, 1.0)).xyz;\nvec3 w = ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ray.direction, 0.0)).xyz;\nq = q - ellipsoid.inverseRadii * (czm_inverseModelView * vec4(ellipsoid.center, 1.0)).xyz;\nfloat q2 = dot(q, q);\nfloat qw = dot(q, w);\nif (q2 > 1.0)\n{\nif (qw >= 0.0)\n{\nreturn czm_emptyRaySegment;\n}\nelse\n{\nfloat qw2 = qw * qw;\nfloat difference = q2 - 1.0;\nfloat w2 = dot(w, w);\nfloat product = w2 * difference;\nif (qw2 < product)\n{\nreturn czm_emptyRaySegment;\n}\nelse if (qw2 > product)\n{\nfloat discriminant = qw * qw - product;\nfloat temp = -qw + sqrt(discriminant);\nfloat root0 = temp / w2;\nfloat root1 = difference / temp;\nif (root0 < root1)\n{\nczm_raySegment i = czm_raySegment(root0, root1);\nreturn i;\n}\nelse\n{\nczm_raySegment i = czm_raySegment(root1, root0);\nreturn i;\n}\n}\nelse\n{\nfloat root = sqrt(difference / w2);\nczm_raySegment i = czm_raySegment(root, root);\nreturn i;\n}\n}\n}\nelse if (q2 < 1.0)\n{\nfloat difference = q2 - 1.0;\nfloat w2 = dot(w, w);\nfloat product = w2 * difference;\nfloat discriminant = qw * qw - product;\nfloat temp = -qw + sqrt(discriminant);\nczm_raySegment i = czm_raySegment(0.0, temp / w2);\nreturn i;\n}\nelse\n{\nif (qw < 0.0)\n{\nfloat w2 = dot(w, w);\nczm_raySegment i = czm_raySegment(0.0, -qw / w2);\nreturn i;\n}\nelse\n{\nreturn czm_emptyRaySegment;\n}\n}\n}\n"}),r("Shaders/Builtin/Functions/saturation",[],function(){"use strict";return"vec3 czm_saturation(vec3 rgb, float adjustment)\n{\nconst vec3 W = vec3(0.2125, 0.7154, 0.0721);\nvec3 intensity = vec3(dot(rgb, W));\nreturn mix(intensity, rgb, adjustment);\n}\n"}),r("Shaders/Builtin/Functions/signNotZero",[],function(){"use strict";return"float czm_signNotZero(float value)\n{\nreturn value >= 0.0 ? 1.0 : -1.0;\n}\nvec2 czm_signNotZero(vec2 value)\n{\nreturn vec2(czm_signNotZero(value.x), czm_signNotZero(value.y));\n}\nvec3 czm_signNotZero(vec3 value)\n{\nreturn vec3(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z));\n}\nvec4 czm_signNotZero(vec4 value)\n{\nreturn vec4(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z), czm_signNotZero(value.w));\n}\n"}),r("Shaders/Builtin/Functions/tangentToEyeSpaceMatrix",[],function(){"use strict";return"mat3 czm_tangentToEyeSpaceMatrix(vec3 normalEC, vec3 tangentEC, vec3 binormalEC)\n{\nvec3 normal = normalize(normalEC);\nvec3 tangent = normalize(tangentEC);\nvec3 binormal = normalize(binormalEC);\nreturn mat3(tangent.x, tangent.y, tangent.z,\nbinormal.x, binormal.y, binormal.z,\nnormal.x, normal.y, normal.z);\n}\n"}),r("Shaders/Builtin/Functions/translateRelativeToEye",[],function(){"use strict";return"vec4 czm_translateRelativeToEye(vec3 high, vec3 low)\n{\nvec3 highDifference = high - czm_encodedCameraPositionMCHigh;\nvec3 lowDifference = low - czm_encodedCameraPositionMCLow;\nreturn vec4(highDifference + lowDifference, 1.0);\n}\n"}),r("Shaders/Builtin/Functions/translucentPhong",[],function(){"use strict";return"vec4 czm_translucentPhong(vec3 toEye, czm_material material)\n{\nfloat diffuse = czm_getLambertDiffuse(vec3(0.0, 0.0, 1.0), material.normal);\nif (czm_sceneMode == czm_sceneMode3D) {\ndiffuse += czm_getLambertDiffuse(vec3(0.0, 1.0, 0.0), material.normal);\n}\ndiffuse = clamp(diffuse, 0.0, 1.0);\nfloat specular = czm_getSpecular(czm_sunDirectionEC, toEye, material.normal, material.shininess);\nspecular += czm_getSpecular(czm_moonDirectionEC, toEye, material.normal, material.shininess);\nvec3 materialDiffuse = material.diffuse * 0.5;\nvec3 ambient = materialDiffuse;\nvec3 color = ambient + material.emission;\ncolor += materialDiffuse * diffuse;\ncolor += material.specular * specular;\nreturn vec4(color, material.alpha);\n}\n"}),r("Shaders/Builtin/Functions/transpose",[],function(){"use strict";return"mat2 czm_transpose(mat2 matrix)\n{\nreturn mat2(\nmatrix[0][0], matrix[1][0],\nmatrix[0][1], matrix[1][1]);\n}\nmat3 czm_transpose(mat3 matrix)\n{\nreturn mat3(\nmatrix[0][0], matrix[1][0], matrix[2][0],\nmatrix[0][1], matrix[1][1], matrix[2][1],\nmatrix[0][2], matrix[1][2], matrix[2][2]);\n}\nmat4 czm_transpose(mat4 matrix)\n{\nreturn mat4(\nmatrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],\nmatrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],\nmatrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],\nmatrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);\n}\n"; -}),r("Shaders/Builtin/Functions/unpackDepth",[],function(){"use strict";return"float czm_unpackDepth(vec4 packedDepth)\n{\nreturn dot(packedDepth, vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n}\n"}),r("Shaders/Builtin/Functions/windowToEyeCoordinates",[],function(){"use strict";return"vec4 czm_windowToEyeCoordinates(vec4 fragmentCoordinate)\n{\nfloat x = 2.0 * (fragmentCoordinate.x - czm_viewport.x) / czm_viewport.z - 1.0;\nfloat y = 2.0 * (fragmentCoordinate.y - czm_viewport.y) / czm_viewport.w - 1.0;\nfloat z = (fragmentCoordinate.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\nvec4 q = vec4(x, y, z, 1.0);\nq /= fragmentCoordinate.w;\nq = czm_inverseProjection * q;\nreturn q;\n}\n"}),r("Shaders/Builtin/CzmBuiltins",["./Constants/degreesPerRadian","./Constants/depthRange","./Constants/epsilon1","./Constants/epsilon2","./Constants/epsilon3","./Constants/epsilon4","./Constants/epsilon5","./Constants/epsilon6","./Constants/epsilon7","./Constants/infinity","./Constants/oneOverPi","./Constants/oneOverTwoPi","./Constants/pi","./Constants/piOverFour","./Constants/piOverSix","./Constants/piOverThree","./Constants/piOverTwo","./Constants/radiansPerDegree","./Constants/sceneMode2D","./Constants/sceneMode3D","./Constants/sceneModeColumbusView","./Constants/sceneModeMorphing","./Constants/solarRadius","./Constants/threePiOver2","./Constants/twoPi","./Constants/webMercatorMaxLatitude","./Structs/depthRangeStruct","./Structs/ellipsoid","./Structs/material","./Structs/materialInput","./Structs/ray","./Structs/raySegment","./Functions/RGBToXYZ","./Functions/XYZToRGB","./Functions/alphaWeight","./Functions/antialias","./Functions/columbusViewMorph","./Functions/computePosition","./Functions/cosineAndSine","./Functions/decompressTextureCoordinates","./Functions/eastNorthUpToEyeCoordinates","./Functions/ellipsoidContainsPoint","./Functions/ellipsoidNew","./Functions/ellipsoidWgs84TextureCoordinates","./Functions/equalsEpsilon","./Functions/eyeOffset","./Functions/eyeToWindowCoordinates","./Functions/fog","./Functions/geodeticSurfaceNormal","./Functions/getDefaultMaterial","./Functions/getLambertDiffuse","./Functions/getSpecular","./Functions/getWaterNoise","./Functions/getWgs84EllipsoidEC","./Functions/hue","./Functions/isEmpty","./Functions/isFull","./Functions/latitudeToWebMercatorFraction","./Functions/luminance","./Functions/metersPerPixel","./Functions/modelToWindowCoordinates","./Functions/multiplyWithColorBalance","./Functions/nearFarScalar","./Functions/octDecode","./Functions/packDepth","./Functions/phong","./Functions/pointAlongRay","./Functions/rayEllipsoidIntersectionInterval","./Functions/saturation","./Functions/signNotZero","./Functions/tangentToEyeSpaceMatrix","./Functions/translateRelativeToEye","./Functions/translucentPhong","./Functions/transpose","./Functions/unpackDepth","./Functions/windowToEyeCoordinates"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe,ae,se,le,ue,ce,he,de,pe,me,fe,ve,_e,ge,ye,Ce,Ee){"use strict";return{czm_degreesPerRadian:e,czm_depthRange:t,czm_epsilon1:r,czm_epsilon2:i,czm_epsilon3:n,czm_epsilon4:o,czm_epsilon5:a,czm_epsilon6:s,czm_epsilon7:l,czm_infinity:u,czm_oneOverPi:c,czm_oneOverTwoPi:h,czm_pi:d,czm_piOverFour:p,czm_piOverSix:m,czm_piOverThree:f,czm_piOverTwo:v,czm_radiansPerDegree:_,czm_sceneMode2D:g,czm_sceneMode3D:y,czm_sceneModeColumbusView:C,czm_sceneModeMorphing:E,czm_solarRadius:S,czm_threePiOver2:w,czm_twoPi:T,czm_webMercatorMaxLatitude:b,czm_depthRangeStruct:x,czm_ellipsoid:P,czm_material:A,czm_materialInput:I,czm_ray:M,czm_raySegment:D,czm_RGBToXYZ:R,czm_XYZToRGB:O,czm_alphaWeight:N,czm_antialias:L,czm_columbusViewMorph:F,czm_computePosition:B,czm_cosineAndSine:V,czm_decompressTextureCoordinates:z,czm_eastNorthUpToEyeCoordinates:k,czm_ellipsoidContainsPoint:U,czm_ellipsoidNew:G,czm_ellipsoidWgs84TextureCoordinates:W,czm_equalsEpsilon:H,czm_eyeOffset:q,czm_eyeToWindowCoordinates:j,czm_fog:Y,czm_geodeticSurfaceNormal:X,czm_getDefaultMaterial:Z,czm_getLambertDiffuse:K,czm_getSpecular:J,czm_getWaterNoise:Q,czm_getWgs84EllipsoidEC:$,czm_hue:ee,czm_isEmpty:te,czm_isFull:re,czm_latitudeToWebMercatorFraction:ie,czm_luminance:ne,czm_metersPerPixel:oe,czm_modelToWindowCoordinates:ae,czm_multiplyWithColorBalance:se,czm_nearFarScalar:le,czm_octDecode:ue,czm_packDepth:ce,czm_phong:he,czm_pointAlongRay:de,czm_rayEllipsoidIntersectionInterval:pe,czm_saturation:me,czm_signNotZero:fe,czm_tangentToEyeSpaceMatrix:ve,czm_translateRelativeToEye:_e,czm_translucentPhong:ge,czm_transpose:ye,czm_unpackDepth:Ce,czm_windowToEyeCoordinates:Ee}}),r("Renderer/ShaderSource",["../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Shaders/Builtin/CzmBuiltins","./AutomaticUniforms"],function(e,t,r,i,n){"use strict";function o(e){return e=e.replace(/\/\/.*/g,""),e.replace(/\/\*\*[\s\S]*?\*\//gm,function(e){for(var t=e.match(/\n/gm).length,r="",i=0;t>i;++i)r+="\n";return r})}function a(e,r,i){for(var n,a=0;a<i.length;++a)i[a].name===e&&(n=i[a]);return t(n)||(r=o(r),n={name:e,glslSource:r,dependsOn:[],requiredBy:[],evaluated:!1},i.push(n)),n}function s(e,r){if(!e.evaluated){e.evaluated=!0;var i=e.glslSource.match(/\bczm_[a-zA-Z0-9_]*/g);t(i)&&null!==i&&(i=i.filter(function(e,t){return i.indexOf(e)===t}),i.forEach(function(t){if(t!==e.name&&h._czmBuiltinsAndUniforms.hasOwnProperty(t)){var i=a(t,h._czmBuiltinsAndUniforms[t],r);e.dependsOn.push(i),i.requiredBy.push(e),s(i,r)}}))}}function l(e){for(var t=[],i=[];e.length>0;){var n=e.pop();i.push(n),0===n.requiredBy.length&&t.push(n)}for(;t.length>0;){var o=t.shift();e.push(o);for(var a=0;a<o.dependsOn.length;++a){var s=o.dependsOn[a],l=s.requiredBy.indexOf(o);s.requiredBy.splice(l,1),0===s.requiredBy.length&&t.push(s)}}for(var u=[],c=0;c<i.length;++c)0!==i[c].requiredBy.length&&u.push(i[c]);if(0!==u.length){var h="A circular dependency was found in the following built-in functions/structs/constants: \n";for(c=0;c<u.length;++c)h=h+u[c].name+"\n";throw new r(h)}}function u(e){var t=[],r=a("main",e,t);s(r,t),l(t);for(var i="",n=t.length-1;n>=0;--n)i=i+t[n].glslSource+"\n";return i.replace(r.glslSource,"")}function c(e,i){var n,a,s="",l=e.sources;if(t(l))for(n=0,a=l.length;a>n;++n)s+="\n#line 0\n"+l[n];s=o(s);var c;s=s.replace(/#version\s+(.*?)\n/gm,function(e,i){if(t(c)&&c!==i)throw new r("inconsistent versions found: "+c+" and "+i);return c=i,"\n"}),s=s.replace(/precision\s(lowp|mediump|highp)\s(float|int);/,"");var d=e.pickColorQualifier;t(d)&&(s=h.createPickFragmentShaderSource(s,d));var p="";t(c)&&(p="#version "+c),i&&(p+="#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n#else\n precision mediump float;\n#endif\n\n");var m=e.defines;if(t(m))for(n=0,a=m.length;a>n;++n){var f=m[n];0!==f.length&&(p+="#define "+f+"\n")}return e.includeBuiltIns&&(p+=u(s)),p+="\n#line 0\n",p+=s}var h=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.pickColorQualifier;this.defines=t(r.defines)?r.defines.slice(0):[],this.sources=t(r.sources)?r.sources.slice(0):[],this.pickColorQualifier=i,this.includeBuiltIns=e(r.includeBuiltIns,!0)};h.prototype.clone=function(){return new h({sources:this.sources,defines:this.defines,pickColorQuantifier:this.pickColorQualifier,includeBuiltIns:this.includeBuiltIns})},h.replaceMain=function(e,t){return t="void "+t+"()",e.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g,t)},h.prototype.createCombinedVertexShader=function(){return c(this,!1)},h.prototype.createCombinedFragmentShader=function(){return c(this,!0)},h._czmBuiltinsAndUniforms={};for(var d in i)i.hasOwnProperty(d)&&(h._czmBuiltinsAndUniforms[d]=i[d]);for(var p in n)if(n.hasOwnProperty(p)){var m=n[p];"function"==typeof m.getDeclaration&&(h._czmBuiltinsAndUniforms[p]=m.getDeclaration(p))}return h.createPickVertexShaderSource=function(e){var t=h.replaceMain(e,"czm_old_main"),r="attribute vec4 pickColor; \nvarying vec4 czm_pickColor; \nvoid main() \n{ \n czm_old_main(); \n czm_pickColor = pickColor; \n}";return t+"\n"+r},h.createPickFragmentShaderSource=function(e,t){var r=h.replaceMain(e,"czm_old_main"),i=t+" vec4 czm_pickColor; \nvoid main() \n{ \n czm_old_main(); \n if (gl_FragColor.a == 0.0) { \n discard; \n } \n gl_FragColor = czm_pickColor; \n}";return r+"\n"+i},h}),r("Renderer/VertexArray",["../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Geometry","../Core/IndexDatatype","../Core/Math","../Core/RuntimeError","./Buffer","./BufferUsage","./ContextLimits"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(i,n,o,a){var s=r(n.vertexBuffer),l=r(n.value),u=n.value?n.value.length:n.componentsPerAttribute,c={index:t(n.index,o),enabled:t(n.enabled,!0),vertexBuffer:n.vertexBuffer,value:l?n.value.slice(0):void 0,componentsPerAttribute:u,componentDatatype:t(n.componentDatatype,e.FLOAT),normalize:t(n.normalize,!1),offsetInBytes:t(n.offsetInBytes,0),strideInBytes:t(n.strideInBytes,0),instanceDivisor:t(n.instanceDivisor,0)};if(s)c.vertexAttrib=function(e){var t=this.index;e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer._getBuffer()),e.vertexAttribPointer(t,this.componentsPerAttribute,this.componentDatatype,this.normalize,this.strideInBytes,this.offsetInBytes),e.enableVertexAttribArray(t),this.instanceDivisor>0&&(a.glVertexAttribDivisor(t,this.instanceDivisor),a._vertexAttribDivisors[t]=this.instanceDivisor,a._previousDrawInstanced=!0)},c.disableVertexAttribArray=function(e){e.disableVertexAttribArray(this.index),this.instanceDivisor>0&&a.glVertexAttribDivisor(o,0)};else{switch(c.componentsPerAttribute){case 1:c.vertexAttrib=function(e){e.vertexAttrib1fv(this.index,this.value)};break;case 2:c.vertexAttrib=function(e){e.vertexAttrib2fv(this.index,this.value)};break;case 3:c.vertexAttrib=function(e){e.vertexAttrib3fv(this.index,this.value)};break;case 4:c.vertexAttrib=function(e){e.vertexAttrib4fv(this.index,this.value)}}c.disableVertexAttribArray=function(e){}}i.push(c)}function m(e,t,i){for(var n=0;n<t.length;++n){var o=t[n];o.enabled&&o.vertexAttrib(e)}r(i)&&e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,i._getBuffer())}function f(e){return e.values.length/e.componentsPerAttribute}function v(t){return e.getSizeInBytes(t.componentDatatype)*t.componentsPerAttribute}function _(t){var i,n,o,a=[];for(n in t)t.hasOwnProperty(n)&&r(t[n])&&r(t[n].values)&&(a.push(n),t[n].componentDatatype===e.DOUBLE&&(t[n].componentDatatype=e.FLOAT,t[n].values=e.createTypedArray(e.FLOAT,t[n].values)));var s,l=a.length;if(l>0)for(s=f(t[a[0]]),i=1;l>i;++i){var c=f(t[a[i]]);if(c!==s)throw new u("Each attribute list must have the same number of vertices. Attribute "+a[i]+" has a different number of vertices ("+c.toString()+") than attribute "+a[0]+" ("+s.toString()+").")}a.sort(function(r,i){return e.getSizeInBytes(t[i].componentDatatype)-e.getSizeInBytes(t[r].componentDatatype)});var h=0,d={};for(i=0;l>i;++i)n=a[i],o=t[n],d[n]=h,h+=v(o);if(h>0){var p=e.getSizeInBytes(t[a[0]].componentDatatype),m=h%p;0!==m&&(h+=p-m);var _=s*h,g=new ArrayBuffer(_),y={};for(i=0;l>i;++i){n=a[i];var C=e.getSizeInBytes(t[n].componentDatatype);y[n]={pointer:e.createTypedArray(t[n].componentDatatype,g),index:d[n]/C,strideInComponentType:h/C}}for(i=0;s>i;++i)for(var E=0;l>E;++E){n=a[E],o=t[n];for(var S=o.values,w=y[n],T=w.pointer,b=o.componentsPerAttribute,x=0;b>x;++x)T[w.index+x]=S[i*b+x];w.index+=w.strideInComponentType}return{buffer:g,offsetsInBytes:d,vertexSizeInBytes:h}}return void 0}function g(e){var t=e._context,r=e._hasInstancedAttributes;if(r||t._previousDrawInstanced){t._previousDrawInstanced=r;var i,n=t._vertexAttribDivisors,o=e._attributes,a=d.maximumVertexAttributes;if(r){var s=o.length;for(i=0;s>i;++i){var l=o[i];if(l.enabled){var u=l.instanceDivisor,c=l.index;u!==n[c]&&(t.glVertexAttribDivisor(c,u),n[c]=u)}}}else for(i=0;a>i;++i)n[i]>0&&(t.glVertexAttribDivisor(i,0),n[i]=0)}}var y=function(i){i=t(i,t.EMPTY_OBJECT);var n,o=i.context,a=o._gl,s=i.attributes,l=i.indexBuffer,u=[],c=1,h=!1,d=s.length;for(n=0;d>n;++n)p(u,s[n],n,o);for(d=u.length,n=0;d>n;++n){var f=u[n];if(r(f.vertexBuffer)&&0===f.instanceDivisor){var v=f.strideInBytes||f.componentsPerAttribute*e.getSizeInBytes(f.componentDatatype);c=f.vertexBuffer.sizeInBytes/v;break}}for(n=0;d>n;++n)if(u[n].instanceDivisor>0){h=!0;break}var _;o.vertexArrayObject&&(_=o.glCreateVertexArray(),o.glBindVertexArray(_),m(a,u,l),o.glBindVertexArray(null)),this._numberOfVertices=c,this._hasInstancedAttributes=h,this._context=o,this._gl=a,this._vao=_,this._attributes=u,this._indexBuffer=l};return y.fromGeometry=function(i){i=t(i,t.EMPTY_OBJECT);var n,o,u,d=i.context,p=t(i.geometry,t.EMPTY_OBJECT),m=t(i.bufferUsage,h.DYNAMIC_DRAW),f=t(i.attributeLocations,t.EMPTY_OBJECT),v=t(i.interleave,!1),g=i.vertexArrayAttributes,C=r(g)?g:[],E=p.attributes;if(v){var S=_(E);if(r(S)){u=c.createVertexBuffer({context:d,typedArray:S.buffer,usage:m});var w=S.offsetsInBytes,T=S.vertexSizeInBytes;for(n in E)E.hasOwnProperty(n)&&r(E[n])&&(o=E[n],r(o.values)?C.push({index:f[n],vertexBuffer:u,componentDatatype:o.componentDatatype,componentsPerAttribute:o.componentsPerAttribute,normalize:o.normalize,offsetInBytes:w[n],strideInBytes:T}):C.push({index:f[n],value:o.value,componentDatatype:o.componentDatatype,normalize:o.normalize}))}}else for(n in E)if(E.hasOwnProperty(n)&&r(E[n])){o=E[n];var b=o.componentDatatype;b===e.DOUBLE&&(b=e.FLOAT),u=void 0,r(o.values)&&(u=c.createVertexBuffer({context:d,typedArray:e.createTypedArray(b,o.values),usage:m})),C.push({index:f[n],vertexBuffer:u,value:o.value,componentDatatype:b,componentsPerAttribute:o.componentsPerAttribute,normalize:o.normalize})}var x,P=p.indices;return r(P)&&(x=a.computeNumberOfVertices(p)>=l.SIXTY_FOUR_KILOBYTES&&d.elementIndexUint?c.createIndexBuffer({context:d,typedArray:new Uint32Array(P),usage:m,indexDatatype:s.UNSIGNED_INT}):c.createIndexBuffer({context:d,typedArray:new Uint16Array(P),usage:m,indexDatatype:s.UNSIGNED_SHORT})),new y({context:d,attributes:C,indexBuffer:x})},i(y.prototype,{numberOfAttributes:{get:function(){return this._attributes.length}},numberOfVertices:{get:function(){return this._numberOfVertices}},indexBuffer:{get:function(){return this._indexBuffer}}}),y.prototype.getAttribute=function(e){return this._attributes[e]},y.prototype._bind=function(){r(this._vao)?(this._context.glBindVertexArray(this._vao),this._context.instancedArrays&&g(this)):m(this._gl,this._attributes,this._indexBuffer)},y.prototype._unBind=function(){if(r(this._vao))this._context.glBindVertexArray(null);else{for(var e=this._attributes,t=this._gl,i=0;i<e.length;++i){var n=e[i];n.enabled&&n.disableVertexAttribArray(t)}this._indexBuffer&&t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,null)}},y.prototype.isDestroyed=function(){return!1},y.prototype.destroy=function(){for(var e=this._attributes,t=0;t<e.length;++t){var i=e[t].vertexBuffer;r(i)&&!i.isDestroyed()&&i.vertexArrayDestroyable&&i.destroy()}var o=this._indexBuffer;return r(o)&&!o.isDestroyed()&&o.vertexArrayDestroyable&&o.destroy(),r(this._vao)&&this._context.glDeleteVertexArray(this._vao),n(this)},y}),r("Renderer/VertexArrayFacade",["../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Math","./Buffer","./BufferUsage","./VertexArray"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t){if(t.needsCommit&&t.vertexSizeInBytes>0){t.needsCommit=!1;var i=t.vertexBuffer,n=e._size*t.vertexSizeInBytes,o=r(i);if(!o||i.sizeInBytes<n)return o&&i.destroy(),t.vertexBuffer=a.createVertexBuffer({context:e._context,typedArray:t.arrayBuffer,usage:t.usage}),t.vertexBuffer.vertexArrayDestroyable=!1,!0;t.vertexBuffer.copyFromArrayView(t.arrayBuffer)}return!1}function c(e,t,r){if(e.needsCommit&&e.vertexSizeInBytes>0){var i=e.vertexSizeInBytes*t,n=e.vertexSizeInBytes*r;e.vertexBuffer.copyFromArrayView(new Uint8Array(e.arrayBuffer,i,n),i)}}function h(e){var t=e.va;if(r(t)){for(var i=t.length,n=0;i>n;++n)t[n].va.destroy();e.va=void 0}}var d=function(i,n,o,a){function s(t,r){return e.getSizeInBytes(r.componentDatatype)-e.getSizeInBytes(t.componentDatatype)}var l=d._verifyAttributes(n);o=t(o,0);for(var u,c,h=[],p={},m=l.length,f=0;m>f;++f){var v=l[f];v.vertexBuffer?h.push(v):(c=v.usage,u=p[c],r(u)||(u=p[c]=[]),u.push(v))}this._allBuffers=[];for(c in p)if(p.hasOwnProperty(c)){u=p[c],u.sort(s);var _=d._vertexSizeInBytes(u),g=u[0].usage,y={vertexSizeInBytes:_,vertexBuffer:void 0,usage:g,needsCommit:!1,arrayBuffer:void 0,arrayViews:d._createArrayViews(u,_)};this._allBuffers.push(y)}this._size=0,this._instanced=t(a,!1),this._precreated=h,this._context=i,this.writers=void 0,this.va=void 0,this.resize(o)};d._verifyAttributes=function(r){for(var i=[],o=0;o<r.length;++o){var a=r[o],l={index:t(a.index,o),enabled:t(a.enabled,!0),componentsPerAttribute:a.componentsPerAttribute,componentDatatype:t(a.componentDatatype,e.FLOAT),normalize:t(a.normalize,!1),vertexBuffer:a.vertexBuffer,usage:t(a.usage,s.STATIC_DRAW)};if(i.push(l),1!==l.componentsPerAttribute&&2!==l.componentsPerAttribute&&3!==l.componentsPerAttribute&&4!==l.componentsPerAttribute)throw new n("attribute.componentsPerAttribute must be in the range [1, 4].");var u=l.componentDatatype;if(!e.validate(u))throw new n("Attribute must have a valid componentDatatype or not specify it.");if(!s.validate(l.usage))throw new n("Attribute must have a valid usage or not specify it.")}for(var c=new Array(i.length),h=0;h<i.length;++h){var d=i[h],p=d.index;if(c[p])throw new n("Index "+p+" is used by more than one attribute.");c[p]=!0}return i},d._vertexSizeInBytes=function(t){for(var r=0,i=t.length,n=0;i>n;++n){var o=t[n];r+=o.componentsPerAttribute*e.getSizeInBytes(o.componentDatatype)}var a=i>0?e.getSizeInBytes(t[0].componentDatatype):0,s=a>0?r%a:0,l=0===s?0:a-s;return r+=l},d._createArrayViews=function(t,r){for(var i=[],n=0,o=t.length,a=0;o>a;++a){var s=t[a],l=s.componentDatatype;i.push({index:s.index,enabled:s.enabled,componentsPerAttribute:s.componentsPerAttribute,componentDatatype:l,normalize:s.normalize,offsetInBytes:n,vertexSizeInComponentType:r/e.getSizeInBytes(l),view:void 0}),n+=s.componentsPerAttribute*e.getSizeInBytes(l)}return i},d.prototype.resize=function(e){this._size=e;var t=this._allBuffers;this.writers=[];for(var r=0,i=t.length;i>r;++r){var n=t[r];d._resize(n,this._size),d._appendWriters(this.writers,n)}h(this)},d._resize=function(t,i){if(t.vertexSizeInBytes>0){var n=new ArrayBuffer(i*t.vertexSizeInBytes);if(r(t.arrayBuffer))for(var o=new Uint8Array(n),a=new Uint8Array(t.arrayBuffer),s=a.length,l=0;s>l;++l)o[l]=a[l];for(var u=t.arrayViews,c=u.length,h=0;c>h;++h){var d=u[h];d.view=e.createArrayBufferView(d.componentDatatype,n,d.offsetInBytes)}t.arrayBuffer=n}};var p=[function(e,t,r){return function(i,n){t[i*r]=n,e.needsCommit=!0}},function(e,t,r){return function(i,n,o){var a=i*r;t[a]=n,t[a+1]=o,e.needsCommit=!0}},function(e,t,r){return function(i,n,o,a){var s=i*r;t[s]=n,t[s+1]=o,t[s+2]=a,e.needsCommit=!0}},function(e,t,r){return function(i,n,o,a,s){var l=i*r;t[l]=n,t[l+1]=o,t[l+2]=a,t[l+3]=s,e.needsCommit=!0}}];return d._appendWriters=function(e,t){for(var r=t.arrayViews,i=r.length,n=0;i>n;++n){var o=r[n];e[o.index]=p[o.componentsPerAttribute-1](t,o.view,o.vertexSizeInComponentType)}},d.prototype.commit=function(e){var t,i,n,a=!1,s=this._allBuffers;for(i=0,n=s.length;n>i;++i)t=s[i],a=u(this,t)||a;if(a||!r(this.va)){h(this);for(var c=this.va=[],p=r(e)?Math.ceil(this._size/(o.SIXTY_FOUR_KILOBYTES-1)):1,m=0;p>m;++m){var f=[];for(i=0,n=s.length;n>i;++i){t=s[i];var v=m*t.vertexSizeInBytes*(o.SIXTY_FOUR_KILOBYTES-1);d._appendAttributes(f,t,v,this._instanced)}f=f.concat(this._precreated),c.push({va:new l({context:this._context,attributes:f,indexBuffer:e}),indicesCount:1.5*(m!==p-1?o.SIXTY_FOUR_KILOBYTES-1:this._size%(o.SIXTY_FOUR_KILOBYTES-1))})}}},d._appendAttributes=function(e,t,r,i){for(var n=t.arrayViews,o=n.length,a=0;o>a;++a){var s=n[a];e.push({index:s.index,enabled:s.enabled,componentsPerAttribute:s.componentsPerAttribute,componentDatatype:s.componentDatatype,normalize:s.normalize,vertexBuffer:t.vertexBuffer,offsetInBytes:r+s.offsetInBytes,strideInBytes:t.vertexSizeInBytes,instanceDivisor:i?1:0})}},d.prototype.subCommit=function(e,t){for(var r=this._allBuffers,i=0,n=r.length;n>i;++i)c(r[i],e,t)},d.prototype.endSubCommits=function(){for(var e=this._allBuffers,t=0,r=e.length;r>t;++t)e[t].needsCommit=!1},d.prototype.isDestroyed=function(){return!1},d.prototype.destroy=function(){for(var e=this._allBuffers,t=0,r=e.length;r>t;++t){var n=e[t];n.vertexBuffer=n.vertexBuffer&&n.vertexBuffer.destroy()}return h(this),i(this)},d}),r("Shaders/BillboardCollectionFS",[],function(){"use strict";return"uniform sampler2D u_atlas;\nvarying vec2 v_textureCoordinates;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#else\nvarying vec4 v_color;\n#endif\nvoid main()\n{\n#ifdef RENDER_FOR_PICK\nvec4 vertexColor = vec4(1.0, 1.0, 1.0, 1.0);\n#else\nvec4 vertexColor = v_color;\n#endif\nvec4 color = texture2D(u_atlas, v_textureCoordinates) * vertexColor;\nif (color.a == 0.0)\n{\ndiscard;\n}\n#ifdef RENDER_FOR_PICK\ngl_FragColor = v_pickColor;\n#else\ngl_FragColor = color;\n#endif\n}\n"}),r("Shaders/BillboardCollectionVS",[],function(){"use strict";return"#ifdef INSTANCED\nattribute vec2 direction;\n#endif\nattribute vec4 positionHighAndScale;\nattribute vec4 positionLowAndRotation;\nattribute vec4 compressedAttribute0;\nattribute vec4 compressedAttribute1;\nattribute vec4 compressedAttribute2;\nattribute vec4 eyeOffset;\nattribute vec4 scaleByDistance;\nattribute vec4 pixelOffsetScaleByDistance;\nvarying vec2 v_textureCoordinates;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#else\nvarying vec4 v_color;\n#endif\nconst float UPPER_BOUND = 32768.0;\nconst float SHIFT_LEFT16 = 65536.0;\nconst float SHIFT_LEFT8 = 256.0;\nconst float SHIFT_LEFT7 = 128.0;\nconst float SHIFT_LEFT5 = 32.0;\nconst float SHIFT_LEFT3 = 8.0;\nconst float SHIFT_LEFT2 = 4.0;\nconst float SHIFT_LEFT1 = 2.0;\nconst float SHIFT_RIGHT8 = 1.0 / 256.0;\nconst float SHIFT_RIGHT7 = 1.0 / 128.0;\nconst float SHIFT_RIGHT5 = 1.0 / 32.0;\nconst float SHIFT_RIGHT3 = 1.0 / 8.0;\nconst float SHIFT_RIGHT2 = 1.0 / 4.0;\nconst float SHIFT_RIGHT1 = 1.0 / 2.0;\nvec4 computePositionWindowCoordinates(vec4 positionEC, vec2 imageSize, float scale, vec2 direction, vec2 origin, vec2 translate, vec2 pixelOffset, vec3 alignedAxis, float rotation, bool sizeInMeters)\n{\nvec2 halfSize = imageSize * scale * czm_resolutionScale;\nhalfSize *= ((direction * 2.0) - 1.0);\nif (sizeInMeters)\n{\npositionEC.xy += halfSize;\n}\nvec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\nif (sizeInMeters)\n{\npositionWC.xy += (origin * abs(halfSize)) / czm_metersPerPixel(positionEC);\n}\nelse\n{\npositionWC.xy += (origin * abs(halfSize));\n}\n#if defined(ROTATION) || defined(ALIGNED_AXIS)\nif (!all(equal(alignedAxis, vec3(0.0))) || rotation != 0.0)\n{\nfloat angle = rotation;\nif (!all(equal(alignedAxis, vec3(0.0))))\n{\nvec3 pos = positionEC.xyz + czm_encodedCameraPositionMCHigh + czm_encodedCameraPositionMCLow;\nvec3 normal = normalize(cross(alignedAxis, pos));\nvec4 tangent = vec4(normalize(cross(pos, normal)), 0.0);\ntangent = czm_modelViewProjection * tangent;\nangle += sign(-tangent.x) * acos(tangent.y / length(tangent.xy));\n}\nfloat cosTheta = cos(angle);\nfloat sinTheta = sin(angle);\nmat2 rotationMatrix = mat2(cosTheta, sinTheta, -sinTheta, cosTheta);\nhalfSize = rotationMatrix * halfSize;\n}\n#endif\nif (!sizeInMeters)\n{\npositionWC.xy += halfSize;\n}\npositionWC.xy += translate;\npositionWC.xy += (pixelOffset * czm_resolutionScale);\nreturn positionWC;\n}\nvoid main()\n{\nvec3 positionHigh = positionHighAndScale.xyz;\nvec3 positionLow = positionLowAndRotation.xyz;\nfloat scale = positionHighAndScale.w;\n#if defined(ROTATION) || defined(ALIGNED_AXIS)\nfloat rotation = positionLowAndRotation.w;\n#else\nfloat rotation = 0.0;\n#endif\nfloat compressed = compressedAttribute0.x;\nvec2 pixelOffset;\npixelOffset.x = floor(compressed * SHIFT_RIGHT7);\ncompressed -= pixelOffset.x * SHIFT_LEFT7;\npixelOffset.x -= UPPER_BOUND;\nvec2 origin;\norigin.x = floor(compressed * SHIFT_RIGHT5);\ncompressed -= origin.x * SHIFT_LEFT5;\norigin.y = floor(compressed * SHIFT_RIGHT3);\ncompressed -= origin.y * SHIFT_LEFT3;\norigin -= vec2(1.0);\nfloat show = floor(compressed * SHIFT_RIGHT2);\ncompressed -= show * SHIFT_LEFT2;\n#ifdef INSTANCED\nvec2 textureCoordinatesBottomLeft = czm_decompressTextureCoordinates(compressedAttribute0.w);\nvec2 textureCoordinatesRange = czm_decompressTextureCoordinates(eyeOffset.w);\nvec2 textureCoordinates = textureCoordinatesBottomLeft + direction * textureCoordinatesRange;\n#else\nvec2 direction;\ndirection.x = floor(compressed * SHIFT_RIGHT1);\ndirection.y = compressed - direction.x * SHIFT_LEFT1;\nvec2 textureCoordinates = czm_decompressTextureCoordinates(compressedAttribute0.w);\n#endif\nfloat temp = compressedAttribute0.y * SHIFT_RIGHT8;\npixelOffset.y = -(floor(temp) - UPPER_BOUND);\nvec2 translate;\ntranslate.y = (temp - floor(temp)) * SHIFT_LEFT16;\ntemp = compressedAttribute0.z * SHIFT_RIGHT8;\ntranslate.x = floor(temp) - UPPER_BOUND;\ntranslate.y += (temp - floor(temp)) * SHIFT_LEFT8;\ntranslate.y -= UPPER_BOUND;\ntemp = compressedAttribute1.x * SHIFT_RIGHT8;\nvec2 imageSize = vec2(floor(temp), compressedAttribute2.w);\n#ifdef EYE_DISTANCE_TRANSLUCENCY\nvec4 translucencyByDistance;\ntranslucencyByDistance.x = compressedAttribute1.z;\ntranslucencyByDistance.z = compressedAttribute1.w;\ntranslucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\ntemp = compressedAttribute1.y * SHIFT_RIGHT8;\ntranslucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n#endif\n#ifdef ALIGNED_AXIS\nvec3 alignedAxis = czm_octDecode(floor(compressedAttribute1.y * SHIFT_RIGHT8));\n#else\nvec3 alignedAxis = vec3(0.0);\n#endif\n#ifdef RENDER_FOR_PICK\ntemp = compressedAttribute2.y;\n#else\ntemp = compressedAttribute2.x;\n#endif\nvec4 color;\ntemp = temp * SHIFT_RIGHT8;\ncolor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\ncolor.g = (temp - floor(temp)) * SHIFT_LEFT8;\ncolor.r = floor(temp);\ntemp = compressedAttribute2.z * SHIFT_RIGHT8;\nbool sizeInMeters = (temp - floor(temp)) * SHIFT_LEFT8 > 0.0;\ntemp = floor(temp) * SHIFT_RIGHT8;\n#ifdef RENDER_FOR_PICK\ncolor.a = (temp - floor(temp)) * SHIFT_LEFT8;\nvec4 pickColor = color / 255.0;\n#else\ncolor.a = floor(temp);\ncolor /= 255.0;\n#endif\nvec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\nvec4 positionEC = czm_modelViewRelativeToEye * p;\npositionEC = czm_eyeOffset(positionEC, eyeOffset.xyz);\npositionEC.xyz *= show;\n#if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY) || defined(EYE_DISTANCE_PIXEL_OFFSET)\nfloat lengthSq;\nif (czm_sceneMode == czm_sceneMode2D)\n{\nlengthSq = czm_eyeHeight2D.y;\n}\nelse\n{\nlengthSq = dot(positionEC.xyz, positionEC.xyz);\n}\n#endif\n#ifdef EYE_DISTANCE_SCALING\nscale *= czm_nearFarScalar(scaleByDistance, lengthSq);\nif (scale == 0.0)\n{\npositionEC.xyz = vec3(0.0);\n}\n#endif\n#ifdef EYE_DISTANCE_PIXEL_OFFSET\nfloat position = pixelOffsetScaleByDistance.x;\nfloat cutDistSq = pixelOffsetScaleByDistance.z * pixelOffsetScaleByDistance.z;\nfloat cameraDistSq = lengthSq;\nif (cutDistSq > 0.0 && cameraDistSq > cutDistSq)\n{\npositionEC.xyz = vec3(0.0);\n}\nelse if (position > 0.0)\n{\nfloat level = floor(pow(cameraDistSq / 1000000.0, 0.20));\nif (mod(position, pow(2.0, level)) > 0.5)\n{\npositionEC.xyz = vec3(0.0);\n}\n}\n#endif\nfloat translucency = 1.0;\n#ifdef EYE_DISTANCE_TRANSLUCENCY\ntranslucency = czm_nearFarScalar(translucencyByDistance, lengthSq);\nif (translucency == 0.0)\n{\npositionEC.xyz = vec3(0.0);\n}\n#endif\n#ifdef EYE_DISTANCE_PIXEL_OFFSET\nfloat pixelOffsetScale = czm_nearFarScalar(pixelOffsetScaleByDistance, lengthSq);\npixelOffset *= pixelOffsetScale;\n#endif\n#ifdef CLAMPED_TO_GROUND\npositionEC.z *= 0.995;\norigin.y = 1.0;\n#endif\nvec4 positionWC = computePositionWindowCoordinates(positionEC, imageSize, scale, direction, origin, translate, pixelOffset, alignedAxis, rotation, sizeInMeters);\ngl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0);\nv_textureCoordinates = textureCoordinates;\n#ifdef RENDER_FOR_PICK\nv_pickColor = pickColor;\n#else\nv_color = color;\nv_color.a *= translucency;\n#endif\n}\n"}),r("Scene/HeightReference",["../Core/freezeObject"],function(e){"use strict";var t={NONE:0,CLAMP_TO_GROUND:1,RELATIVE_TO_GROUND:2};return e(t)}),r("Scene/HorizontalOrigin",["../Core/freezeObject"],function(e){"use strict";var t={CENTER:0,LEFT:1,RIGHT:-1};return e(t)}),r("Scene/SceneMode",["../Core/freezeObject"],function(e){"use strict";var t={MORPHING:0,COLUMBUS_VIEW:1,SCENE2D:2,SCENE3D:3};return t.getMorphTime=function(e){return e===t.SCENE3D?1:e===t.MORPHING?void 0:0},e(t)}),r("Scene/SceneTransforms",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defined","../Core/DeveloperError","../Core/Math","../Core/Matrix4","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c={},h=new i(0,0,0,1),d=new i,p=new l;c.wgs84ToWindowCoordinates=function(e,t,r){var n=c.computeActualWgs84Position(e.frameState,t,h);if(!o(n))return void 0;var a=e.camera,s=l.multiply(a.frustum.projectionMatrix,a.viewMatrix,p);return l.multiplyByVector(s,i.fromElements(n.x,n.y,n.z,1,d),d),d.z<0&&e.mode!==u.SCENE2D?void 0:(r=c.clipToGLWindowCoordinates(e,d,r),r.y=e.canvas.clientHeight-r.y,r)},c.wgs84ToDrawingBufferCoordinates=function(e,t,r){var n=c.computeActualWgs84Position(e.frameState,t,h);if(!o(n))return void 0;var a=e.camera,s=l.multiply(a.frustum.projectionMatrix,a.viewMatrix,p);return l.multiplyByVector(s,i.fromElements(n.x,n.y,n.z,1,d),d),d.z<0&&e.mode!==u.SCENE2D?void 0:c.clipToDrawingBufferCoordinates(e,d,r)};var m=new r,f=new n;c.computeActualWgs84Position=function(e,t,i){var n=e.mode;if(n===u.SCENE3D)return r.clone(t,i);var a=e.mapProjection,l=a.ellipsoid.cartesianToCartographic(t,f);if(!o(l))return void 0;if(a.project(l,m),n===u.COLUMBUS_VIEW)return r.fromElements(m.z,m.x,m.y,i);if(n===u.SCENE2D)return r.fromElements(0,m.x,m.y,i);var c=e.morphTime;return r.fromElements(s.lerp(m.z,t.x,c),s.lerp(m.x,t.y,c),s.lerp(m.y,t.z,c),i)};var v=new r,_=new r,g=new e,y=new l;c.clipToGLWindowCoordinates=function(e,i,n){var o=e.canvas;return r.divideByScalar(i,i.w,v),g.width=o.clientWidth,g.height=o.clientHeight,l.computeViewportTransformation(g,0,1,y),l.multiplyByPoint(y,v,_),t.fromCartesian3(_,n)},c.clipToDrawingBufferCoordinates=function(e,i,n){return r.divideByScalar(i,i.w,v),g.width=e.drawingBufferWidth,g.height=e.drawingBufferHeight,l.computeViewportTransformation(g,0,1,y),l.multiplyByPoint(y,v,_),t.fromCartesian3(_,n)},c.transformWindowToDrawingBuffer=function(e,r,i){var n=e.canvas,o=e.drawingBufferWidth/n.clientWidth,a=e.drawingBufferHeight/n.clientHeight;return t.fromElements(r.x*o,r.y*a,i)};var C=new i,E=new i;return c.drawingBufferToWgs84Coordinates=function(e,t,n,o){var a=e.context,s=a.uniformState,u=s.viewport,c=(s.viewportTransformation,i.clone(i.UNIT_W,C));c.x=(t.x-u.x)/u.width*2-1,c.y=(t.y-u.y)/u.height*2-1,c.z=2*n-1,c.w=1;var h=l.multiplyByVector(s.inverseViewProjection,c,E),d=1/h.w;return r.multiplyByScalar(h,d,h),r.fromCartesian4(h,o)},c}),r("Scene/VerticalOrigin",["../Core/freezeObject"],function(e){"use strict";var t={CENTER:0,BOTTOM:1,TOP:-1};return e(t)}),r("Scene/Billboard",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix4","../Core/NearFarScalar","./HeightReference","./HorizontalOrigin","./SceneMode","./SceneTransforms","./VerticalOrigin"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,t){var r=e._billboardCollection; -l(r)&&(r._updateBillboard(e,t),e._dirty=!0)}var y=function(e,i){e=s(e,s.EMPTY_OBJECT),this._show=s(e.show,!0),this._position=r.clone(s(e.position,r.ZERO)),this._actualPosition=r.clone(this._position),this._pixelOffset=t.clone(s(e.pixelOffset,t.ZERO)),this._translate=new t(0,0),this._eyeOffset=r.clone(s(e.eyeOffset,r.ZERO)),this._verticalOrigin=s(e.verticalOrigin,_.CENTER),this._horizontalOrigin=s(e.horizontalOrigin,m.CENTER),this._scale=s(e.scale,1),this._color=o.clone(s(e.color,o.WHITE)),this._rotation=s(e.rotation,0),this._alignedAxis=r.clone(s(e.alignedAxis,r.ZERO)),this._width=e.width,this._height=e.height,this._scaleByDistance=e.scaleByDistance,this._translucencyByDistance=e.translucencyByDistance,this._pixelOffsetScaleByDistance=e.pixelOffsetScaleByDistance,this._heightReference=s(e.heightReference,p.NONE),this._sizeInMeters=s(e.sizeInMeters,!1),this._id=e.id,this._collection=s(e.collection,i),this._pickId=void 0,this._pickPrimitive=s(e._pickPrimitive,this),this._billboardCollection=i,this._dirty=!1,this._index=-1,this._imageIndex=-1,this._imageIndexPromise=void 0,this._imageId=void 0,this._image=void 0,this._imageSubRegion=void 0,this._imageWidth=void 0,this._imageHeight=void 0;var n=e.image,u=e.imageId;l(n)&&(l(u)||(u="string"==typeof n?n:l(n.src)?n.src:a()),this._imageId=u,this._image=n),l(e.imageSubRegion)&&(this._imageId=u,this._imageSubRegion=e.imageSubRegion),l(this._billboardCollection._textureAtlas)&&this._loadImage(),this._actualClampedPosition=void 0,this._removeCallbackFunc=void 0,this._mode=f.SCENE3D,this._updateClamping()},C=y.SHOW_INDEX=0,E=y.POSITION_INDEX=1,S=y.PIXEL_OFFSET_INDEX=2,w=y.EYE_OFFSET_INDEX=3,T=y.HORIZONTAL_ORIGIN_INDEX=4,b=y.VERTICAL_ORIGIN_INDEX=5,x=y.SCALE_INDEX=6,P=y.IMAGE_INDEX_INDEX=7,A=y.COLOR_INDEX=8,I=y.ROTATION_INDEX=9,M=y.ALIGNED_AXIS_INDEX=10,D=y.SCALE_BY_DISTANCE_INDEX=11,R=y.TRANSLUCENCY_BY_DISTANCE_INDEX=12,O=y.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX=13;y.NUMBER_OF_PROPERTIES=14,u(y.prototype,{show:{get:function(){return this._show},set:function(e){this._show!==e&&(this._show=e,g(this,C))}},position:{get:function(){return this._position},set:function(e){var t=this._position;r.equals(t,e)||(r.clone(e,t),r.clone(e,this._actualPosition),this._updateClamping(),g(this,E))}},heightReference:{get:function(){return this._heightReference},set:function(e){var t=this._heightReference;e!==t&&(this._heightReference=e,this._updateClamping(),g(this,E))}},pixelOffset:{get:function(){return this._pixelOffset},set:function(e){var r=this._pixelOffset;t.equals(r,e)||(t.clone(e,r),g(this,S))}},scaleByDistance:{get:function(){return this._scaleByDistance},set:function(e){var t=this._scaleByDistance;d.equals(t,e)||(this._scaleByDistance=d.clone(e,t),g(this,D))}},translucencyByDistance:{get:function(){return this._translucencyByDistance},set:function(e){var t=this._translucencyByDistance;d.equals(t,e)||(this._translucencyByDistance=d.clone(e,t),g(this,R))}},pixelOffsetScaleByDistance:{get:function(){return this._pixelOffsetScaleByDistance},set:function(e){var t=this._pixelOffsetScaleByDistance;d.equals(t,e)||(this._pixelOffsetScaleByDistance=d.clone(e,t),g(this,O))}},eyeOffset:{get:function(){return this._eyeOffset},set:function(e){var t=this._eyeOffset;r.equals(t,e)||(r.clone(e,t),g(this,w))}},horizontalOrigin:{get:function(){return this._horizontalOrigin},set:function(e){this._horizontalOrigin!==e&&(this._horizontalOrigin=e,g(this,T))}},verticalOrigin:{get:function(){return this._verticalOrigin},set:function(e){this._verticalOrigin!==e&&(this._verticalOrigin=e,g(this,b))}},scale:{get:function(){return this._scale},set:function(e){this._scale!==e&&(this._scale=e,g(this,x))}},color:{get:function(){return this._color},set:function(e){var t=this._color;o.equals(t,e)||(o.clone(e,t),g(this,A))}},rotation:{get:function(){return this._rotation},set:function(e){this._rotation!==e&&(this._rotation=e,g(this,I))}},alignedAxis:{get:function(){return this._alignedAxis},set:function(e){var t=this._alignedAxis;r.equals(t,e)||(r.clone(e,t),g(this,M))}},width:{get:function(){return s(this._width,this._imageWidth)},set:function(e){this._width!==e&&(this._width=e,g(this,P))}},height:{get:function(){return s(this._height,this._imageHeight)},set:function(e){this._height!==e&&(this._height=e,g(this,P))}},sizeInMeters:{get:function(){return this._sizeInMeters},set:function(e){this._sizeInMeters!==e&&(this._sizeInMeters=e,g(this,A))}},id:{get:function(){return this._id},set:function(e){this._id=e,l(this._pickId)&&(this._pickId.object.id=e)}},pickPrimitive:{get:function(){return this._pickPrimitive},set:function(e){this._pickPrimitive=e,l(this._pickId)&&(this._pickId.object.primitive=e)}},image:{get:function(){return this._imageId},set:function(e){l(e)?"string"==typeof e?this.setImage(e,e):l(e.src)?this.setImage(e.src,e):this.setImage(a(),e):(this._imageIndex=-1,this._imageSubRegion=void 0,this._imageId=void 0,this._image=void 0,this._imageIndexPromise=void 0,g(this,P))}},ready:{get:function(){return-1!==this._imageIndex}},_clampedPosition:{get:function(){return this._actualClampedPosition},set:function(e){this._actualClampedPosition=r.clone(e,this._actualClampedPosition),g(this,E)}}}),y.prototype.getPickId=function(e){return l(this._pickId)||(this._pickId=e.createPickId({primitive:this._pickPrimitive,collection:this._collection,id:this._id})),this._pickId},y.prototype._updateClamping=function(){y._updateClamping(this._billboardCollection,this)};var N=new n,L=new r;y._updateClamping=function(e,t){var i=e._scene;if(l(i)){var o=i.globe,a=o.ellipsoid,s=o._surface,u=i.frameState.mode,h=i.frameState.mapProjection,d=u!==t._mode;if(t._mode=u,(t._heightReference===p.NONE||d)&&l(t._removeCallbackFunc)&&(t._removeCallbackFunc(),t._removeCallbackFunc=void 0,t._clampedPosition=void 0),t._heightReference!==p.NONE&&l(t._position)){var m=a.cartesianToCartographic(t._position);if(l(m)){l(t._removeCallbackFunc)&&t._removeCallbackFunc();var v=function(e){if(t._heightReference===p.RELATIVE_TO_GROUND)if(t._mode===f.SCENE3D){var i=a.cartesianToCartographic(e,N);i.height+=m.height,a.cartographicToCartesian(i,e)}else e.x+=m.height;t._clampedPosition=r.clone(e,t._clampedPosition)};t._removeCallbackFunc=s.updateHeight(m,v);var _=o.getHeight(m);l(_)&&(n.clone(m,N),N.height=_,t._mode===f.SCENE3D?a.cartographicToCartesian(N,L):(h.project(N,L),r.fromElements(L.z,L.x,L.y,L)),v(L))}}}else if(t._heightReference!==p.NONE)throw new c("Height reference is not supported.")},y.prototype._loadImage=function(){var t,r=this._billboardCollection._textureAtlas,i=this._imageId,n=this._image,o=this._imageSubRegion;if(l(n)&&(t=r.addImage(i,n)),l(o)&&(t=r.addSubRegion(i,o)),this._imageIndexPromise=t,l(t)){var a=this;t.then(function(t){if(a._imageId===i&&a._image===n&&e.equals(a._imageSubRegion,o)){var s=r.textureCoordinates[t];a._imageWidth=r.texture.width*s.width,a._imageHeight=r.texture.height*s.height,a._imageIndex=t,a._ready=!0,a._image=void 0,a._imageIndexPromise=void 0,g(a,P)}}).otherwise(function(e){console.error("Error loading image for billboard: "+e),a._imageIndexPromise=void 0})}},y.prototype.setImage=function(e,t){this._imageId!==e&&(this._imageIndex=-1,this._imageSubRegion=void 0,this._imageId=e,this._image=t,l(this._billboardCollection._textureAtlas)&&this._loadImage())},y.prototype.setImageSubRegion=function(t,r){this._imageId===t&&e.equals(this._imageSubRegion,r)||(this._imageIndex=-1,this._imageId=t,this._imageSubRegion=e.clone(r),l(this._billboardCollection._textureAtlas)&&this._loadImage())},y.prototype._setTranslate=function(e){var r=this._translate;t.equals(r,e)||(t.clone(e,r),g(this,S))},y.prototype._getActualPosition=function(){return l(this._clampedPosition)?this._clampedPosition:this._actualPosition},y.prototype._setActualPosition=function(e){l(this._clampedPosition)||r.clone(e,this._actualPosition),g(this,E)};var F=new i;y._computeActualPosition=function(e,t,r,i){return l(e._clampedPosition)?(r.mode!==e._mode&&e._updateClamping(),e._clampedPosition):r.mode===f.SCENE3D?t:(h.multiplyByPoint(i,t,F),v.computeActualWgs84Position(r,F))};var B=new h,V=new i,z=new r,k=new t,U=new t;y._computeScreenSpacePosition=function(e,n,o,a,s,l){var u=s.camera,c=u.viewMatrix,d=u.frustum.projectionMatrix,p=h.multiplyTransformation(c,e,B),m=h.multiplyByVector(p,i.fromElements(n.x,n.y,n.z,1,V),V),f=r.multiplyComponents(o,r.normalize(m,z),z);m.x+=o.x+f.x,m.y+=o.y+f.y,m.z+=f.z;var _=h.multiplyByVector(d,m,V),g=v.clipToGLWindowCoordinates(s,_,l);a=t.clone(a,U),a.y=-a.y;var y=t.multiplyByScalar(a,s.context.uniformState.resolutionScale,k);return g.x+=y.x,g.y+=y.y,g};var G=new t(0,0);return y.prototype.computeScreenSpacePosition=function(e,r){var i=this._billboardCollection;l(r)||(r=new t),t.clone(this._pixelOffset,G),t.add(G,this._translate,G);var n=i.modelMatrix,o=this._getActualPosition(),a=y._computeScreenSpacePosition(n,o,this._eyeOffset,G,e,r);return a.y=e.canvas.clientHeight-a.y,a},y.prototype.equals=function(i){return this===i||l(i)&&this._id===i._id&&r.equals(this._position,i._position)&&this._imageId===i._imageId&&this._show===i._show&&this._scale===i._scale&&this._verticalOrigin===i._verticalOrigin&&this._horizontalOrigin===i._horizontalOrigin&&e.equals(this._imageSubRegion,i._imageSubRegion)&&o.equals(this._color,i._color)&&t.equals(this._pixelOffset,i._pixelOffset)&&t.equals(this._translate,i._translate)&&r.equals(this._eyeOffset,i._eyeOffset)&&d.equals(this._scaleByDistance,i._scaleByDistance)&&d.equals(this._translucencyByDistance,i._translucencyByDistance)&&d.equals(this._pixelOffsetScaleByDistance,i._pixelOffsetScaleByDistance)},y.prototype._destroy=function(){l(this._customData)&&(this._billboardCollection._scene.globe._surface.removeTileCustomData(this._customData),this._customData=void 0),this.image=void 0,this._pickId=this._pickId&&this._pickId.destroy(),this._billboardCollection=void 0},y}),r("Scene/BlendEquation",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={ADD:t.FUNC_ADD,SUBTRACT:t.FUNC_SUBTRACT,REVERSE_SUBTRACT:t.FUNC_REVERSE_SUBTRACT};return e(r)}),r("Scene/BlendFunction",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={ZERO:t.ZERO,ONE:t.ONE,SOURCE_COLOR:t.SRC_COLOR,ONE_MINUS_SOURCE_COLOR:t.ONE_MINUS_SRC_COLOR,DESTINATION_COLOR:t.DST_COLOR,ONE_MINUS_DESTINATION_COLOR:t.ONE_MINUS_DST_COLOR,SOURCE_ALPHA:t.SRC_ALPHA,ONE_MINUS_SOURCE_ALPHA:t.ONE_MINUS_SRC_ALPHA,DESTINATION_ALPHA:t.DST_ALPHA,ONE_MINUS_DESTINATION_ALPHA:t.ONE_MINUS_DST_ALPHA,CONSTANT_COLOR:t.CONSTANT_COLOR,ONE_MINUS_CONSTANT_COLOR:t.ONE_MINUS_CONSTANT_ALPHA,CONSTANT_ALPHA:t.CONSTANT_ALPHA,ONE_MINUS_CONSTANT_ALPHA:t.ONE_MINUS_CONSTANT_ALPHA,SOURCE_ALPHA_SATURATE:t.SRC_ALPHA_SATURATE};return e(r)}),r("Scene/BlendingState",["../Core/freezeObject","./BlendEquation","./BlendFunction"],function(e,t,r){"use strict";var i={DISABLED:e({enabled:!1}),ALPHA_BLEND:e({enabled:!0,equationRgb:t.ADD,equationAlpha:t.ADD,functionSourceRgb:r.SOURCE_ALPHA,functionSourceAlpha:r.SOURCE_ALPHA,functionDestinationRgb:r.ONE_MINUS_SOURCE_ALPHA,functionDestinationAlpha:r.ONE_MINUS_SOURCE_ALPHA}),PRE_MULTIPLIED_ALPHA_BLEND:e({enabled:!0,equationRgb:t.ADD,equationAlpha:t.ADD,functionSourceRgb:r.ONE,functionSourceAlpha:r.ONE,functionDestinationRgb:r.ONE_MINUS_SOURCE_ALPHA,functionDestinationAlpha:r.ONE_MINUS_SOURCE_ALPHA}),ADDITIVE_BLEND:e({enabled:!0,equationRgb:t.ADD,equationAlpha:t.ADD,functionSourceRgb:r.SOURCE_ALPHA,functionSourceAlpha:r.SOURCE_ALPHA,functionDestinationRgb:r.ONE,functionDestinationAlpha:r.ONE})};return e(i)}),r("Scene/Pass",["../Core/freezeObject"],function(e){"use strict";var t={COMPUTE:0,GLOBE:1,GROUND:2,OPAQUE:3,TRANSLUCENT:4,OVERLAY:5,NUMBER_OF_PASSES:6};return e(t)}),r("Renderer/Framebuffer",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/PixelFormat","./ContextLimits"],function(e,t,r,i,n,o,a){"use strict";function s(e,t,r){var i=e._gl;i.framebufferTexture2D(i.FRAMEBUFFER,t,r._target,r._texture,0)}function l(e,t,r){var i=e._gl;i.framebufferRenderbuffer(i.FRAMEBUFFER,t,i.RENDERBUFFER,r._getRenderbuffer())}var u=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.context._gl;a.maximumColorAttachments;this._gl=i,this._framebuffer=i.createFramebuffer(),this._colorTextures=[],this._colorRenderbuffers=[],this._activeColorAttachments=[],this._depthTexture=void 0,this._depthRenderbuffer=void 0,this._stencilRenderbuffer=void 0,this._depthStencilTexture=void 0,this._depthStencilRenderbuffer=void 0,this.destroyAttachments=e(r.destroyAttachments,!0);t(r.depthTexture)||t(r.depthRenderbuffer),t(r.depthStencilTexture)||t(r.depthStencilRenderbuffer);this._bind();var n,o,u,c,h;if(t(r.colorTextures)){var d=r.colorTextures;for(c=this._colorTextures.length=this._activeColorAttachments.length=d.length,u=0;c>u;++u)n=d[u],h=this._gl.COLOR_ATTACHMENT0+u,s(this,h,n),this._activeColorAttachments[u]=h,this._colorTextures[u]=n}if(t(r.colorRenderbuffers)){var p=r.colorRenderbuffers;for(c=this._colorRenderbuffers.length=this._activeColorAttachments.length=p.length,u=0;c>u;++u)o=p[u],h=this._gl.COLOR_ATTACHMENT0+u,l(this,h,o),this._activeColorAttachments[u]=h,this._colorRenderbuffers[u]=o}t(r.depthTexture)&&(n=r.depthTexture,s(this,this._gl.DEPTH_ATTACHMENT,n),this._depthTexture=n),t(r.depthRenderbuffer)&&(o=r.depthRenderbuffer,l(this,this._gl.DEPTH_ATTACHMENT,o),this._depthRenderbuffer=o),t(r.stencilRenderbuffer)&&(o=r.stencilRenderbuffer,l(this,this._gl.STENCIL_ATTACHMENT,o),this._stencilRenderbuffer=o),t(r.depthStencilTexture)&&(n=r.depthStencilTexture,s(this,this._gl.DEPTH_STENCIL_ATTACHMENT,n),this._depthStencilTexture=n),t(r.depthStencilRenderbuffer)&&(o=r.depthStencilRenderbuffer,l(this,this._gl.DEPTH_STENCIL_ATTACHMENT,o),this._depthStencilRenderbuffer=o),this._unBind()};return r(u.prototype,{status:{get:function(){this._bind();var e=this._gl.checkFramebufferStatus(this._gl.FRAMEBUFFER);return this._unBind(),e}},numberOfColorAttachments:{get:function(){return this._activeColorAttachments.length}},depthTexture:{get:function(){return this._depthTexture}},depthRenderbuffer:{get:function(){return this._depthRenderbuffer}},stencilRenderbuffer:{get:function(){return this._stencilRenderbuffer}},depthStencilTexture:{get:function(){return this._depthStencilTexture}},depthStencilRenderbuffer:{get:function(){return this._depthStencilRenderbuffer}},hasDepthAttachment:{get:function(){return!!(this.depthTexture||this.depthRenderbuffer||this.depthStencilTexture||this.depthStencilRenderbuffer)}}}),u.prototype._bind=function(){var e=this._gl;e.bindFramebuffer(e.FRAMEBUFFER,this._framebuffer)},u.prototype._unBind=function(){var e=this._gl;e.bindFramebuffer(e.FRAMEBUFFER,null)},u.prototype._getActiveColorAttachments=function(){return this._activeColorAttachments},u.prototype.getColorTexture=function(e){return this._colorTextures[e]},u.prototype.getColorRenderbuffer=function(e){return this._colorRenderbuffers[e]},u.prototype.isDestroyed=function(){return!1},u.prototype.destroy=function(){if(this.destroyAttachments){for(var e=0,r=this._colorTextures,n=r.length;n>e;++e){var o=r[e];t(o)&&o.destroy()}var a=this._colorRenderbuffers;for(n=a.length,e=0;n>e;++e){var s=a[e];t(s)&&s.destroy()}this._depthTexture=this._depthTexture&&this._depthTexture.destroy(),this._depthRenderbuffer=this._depthRenderbuffer&&this._depthRenderbuffer.destroy(),this._stencilRenderbuffer=this._stencilRenderbuffer&&this._stencilRenderbuffer.destroy(),this._depthStencilTexture=this._depthStencilTexture&&this._depthStencilTexture.destroy(),this._depthStencilRenderbuffer=this._depthStencilRenderbuffer&&this._depthStencilRenderbuffer.destroy()}return this._gl.deleteFramebuffer(this._framebuffer),i(this)},u}),r("Renderer/MipmapHint",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={DONT_CARE:t.DONT_CARE,FASTEST:t.FASTEST,NICEST:t.NICEST,validate:function(e){return e===r.DONT_CARE||e===r.FASTEST||e===r.NICEST}};return e(r)}),r("Renderer/PixelDatatype",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={UNSIGNED_BYTE:t.UNSIGNED_BYTE,UNSIGNED_SHORT:t.UNSIGNED_SHORT,UNSIGNED_INT:t.UNSIGNED_INT,FLOAT:t.FLOAT,UNSIGNED_INT_24_8:t.UNSIGNED_INT_24_8,UNSIGNED_SHORT_4_4_4_4:t.UNSIGNED_SHORT_4_4_4_4,UNSIGNED_SHORT_5_5_5_1:t.UNSIGNED_SHORT_5_5_5_1,UNSIGNED_SHORT_5_6_5:t.UNSIGNED_SHORT_5_6_5,validate:function(e){return e===r.UNSIGNED_BYTE||e===r.UNSIGNED_SHORT||e===r.UNSIGNED_INT||e===r.FLOAT||e===r.UNSIGNED_INT_24_8||e===r.UNSIGNED_SHORT_4_4_4_4||e===r.UNSIGNED_SHORT_5_5_5_1||e===r.UNSIGNED_SHORT_5_6_5}};return e(r)}),r("Renderer/TextureMagnificationFilter",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={NEAREST:t.NEAREST,LINEAR:t.LINEAR,validate:function(e){return e===r.NEAREST||e===r.LINEAR}};return e(r)}),r("Renderer/TextureMinificationFilter",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={NEAREST:t.NEAREST,LINEAR:t.LINEAR,NEAREST_MIPMAP_NEAREST:t.NEAREST_MIPMAP_NEAREST,LINEAR_MIPMAP_NEAREST:t.LINEAR_MIPMAP_NEAREST,NEAREST_MIPMAP_LINEAR:t.NEAREST_MIPMAP_LINEAR,LINEAR_MIPMAP_LINEAR:t.LINEAR_MIPMAP_LINEAR,validate:function(e){return e===r.NEAREST||e===r.LINEAR||e===r.NEAREST_MIPMAP_NEAREST||e===r.LINEAR_MIPMAP_NEAREST||e===r.NEAREST_MIPMAP_LINEAR||e===r.LINEAR_MIPMAP_LINEAR}};return e(r)}),r("Renderer/TextureWrap",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={CLAMP_TO_EDGE:t.CLAMP_TO_EDGE,REPEAT:t.REPEAT,MIRRORED_REPEAT:t.MIRRORED_REPEAT,validate:function(e){return e===r.CLAMP_TO_EDGE||e===r.REPEAT||e===r.MIRRORED_REPEAT}};return e(r)}),r("Renderer/Sampler",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","./TextureMagnificationFilter","./TextureMinificationFilter","./TextureWrap"],function(e,t,r,i,n,o,a){"use strict";var s=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.wrapS,a.CLAMP_TO_EDGE),s=e(r.wrapT,a.CLAMP_TO_EDGE),l=e(r.minificationFilter,o.LINEAR),u=e(r.magnificationFilter,n.LINEAR),c=t(r.maximumAnisotropy)?r.maximumAnisotropy:1;this._wrapS=i,this._wrapT=s,this._minificationFilter=l,this._magnificationFilter=u,this._maximumAnisotropy=c};return r(s.prototype,{wrapS:{get:function(){return this._wrapS}},wrapT:{get:function(){return this._wrapT}},minificationFilter:{get:function(){return this._minificationFilter}},magnificationFilter:{get:function(){return this._magnificationFilter}},maximumAnisotropy:{get:function(){return this._maximumAnisotropy}}}),s}),r("Renderer/Texture",["../Core/Cartesian2","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Math","../Core/PixelFormat","./ContextLimits","./MipmapHint","./PixelDatatype","./Sampler","./TextureMagnificationFilter","./TextureMinificationFilter","./TextureWrap","./WebGLConstants"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";var v=function(i){i=t(i,t.EMPTY_OBJECT);var n=i.context,a=i.source,l=r(a)?a.width:i.width,u=r(a)?a.height:i.height,d=t(i.pixelFormat,s.RGBA),p=t(i.pixelDatatype,c.UNSIGNED_BYTE),m=d;if(n.webgl2&&(d===s.DEPTH_STENCIL?m=f.DEPTH24_STENCIL8:d===s.DEPTH_COMPONENT&&(p===c.UNSIGNED_SHORT?m=f.DEPTH_COMPONENT16:p===c.UNSIGNED_INT&&(m=f.DEPTH_COMPONENT24))),p===c.FLOAT&&!n.floatingPointTexture)throw new o("When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension. Check context.floatingPointTexture.");if(s.isDepthFormat(d)&&!n.depthTexture)throw new o("When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, this WebGL implementation must support WEBGL_depth_texture. Check context.depthTexture.");var v=i.preMultiplyAlpha||d===s.RGB||d===s.LUMINANCE,_=t(i.flipY,!0),g=n._gl,y=g.TEXTURE_2D,C=g.createTexture();g.activeTexture(g.TEXTURE0),g.bindTexture(y,C),r(a)?(g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,v),g.pixelStorei(g.UNPACK_FLIP_Y_WEBGL,_),r(a.arrayBufferView)?g.texImage2D(y,0,m,l,u,0,d,p,a.arrayBufferView):r(a.framebuffer)?(a.framebuffer!==n.defaultFramebuffer&&a.framebuffer._bind(),g.copyTexImage2D(y,0,m,a.xOffset,a.yOffset,l,u,0),a.framebuffer!==n.defaultFramebuffer&&a.framebuffer._unBind()):g.texImage2D(y,0,m,d,p,a)):g.texImage2D(y,0,m,l,u,0,d,p,null),g.bindTexture(y,null),this._context=n,this._textureFilterAnisotropic=n._textureFilterAnisotropic,this._textureTarget=y,this._texture=C,this._pixelFormat=d,this._pixelDatatype=p,this._width=l,this._height=u,this._dimensions=new e(l,u),this._preMultiplyAlpha=v,this._flipY=_,this._sampler=void 0,this.sampler=r(i.sampler)?i.sampler:new h};return v.fromFramebuffer=function(e){e=t(e,t.EMPTY_OBJECT);var i=e.context,n=i._gl,o=t(e.pixelFormat,s.RGB),a=t(e.framebufferXOffset,0),l=t(e.framebufferYOffset,0),u=t(e.width,n.drawingBufferWidth),c=t(e.height,n.drawingBufferHeight),h=e.framebuffer,d=new v({context:i,width:u,height:c,pixelFormat:o,source:{framebuffer:r(h)?h:i.defaultFramebuffer,xOffset:a,yOffset:l,width:u,height:c}});return d},i(v.prototype,{sampler:{get:function(){return this._sampler},set:function(e){var t=e.minificationFilter,i=e.magnificationFilter,n=t===p.NEAREST_MIPMAP_NEAREST||t===p.NEAREST_MIPMAP_LINEAR||t===p.LINEAR_MIPMAP_NEAREST||t===p.LINEAR_MIPMAP_LINEAR;this._pixelDatatype===c.FLOAT&&(t=n?p.NEAREST_MIPMAP_NEAREST:p.NEAREST,i=d.NEAREST);var o=this._context._gl,a=this._textureTarget;o.activeTexture(o.TEXTURE0),o.bindTexture(a,this._texture),o.texParameteri(a,o.TEXTURE_MIN_FILTER,t),o.texParameteri(a,o.TEXTURE_MAG_FILTER,i),o.texParameteri(a,o.TEXTURE_WRAP_S,e.wrapS),o.texParameteri(a,o.TEXTURE_WRAP_T,e.wrapT),r(this._textureFilterAnisotropic)&&o.texParameteri(a,this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT,e.maximumAnisotropy),o.bindTexture(a,null),this._sampler=e}},pixelFormat:{get:function(){return this._pixelFormat}},pixelDatatype:{get:function(){return this._pixelDatatype}},dimensions:{get:function(){return this._dimensions}},preMultiplyAlpha:{get:function(){return this._preMultiplyAlpha}},flipY:{get:function(){return this._flipY}},width:{get:function(){return this._width}},height:{get:function(){return this._height}},_target:{get:function(){return this._textureTarget}}}),v.prototype.copyFrom=function(e,r,i){r=t(r,0),i=t(i,0);var n=this._context._gl,o=this._textureTarget;n.pixelStorei(n.UNPACK_PREMULTIPLY_ALPHA_WEBGL,this._preMultiplyAlpha),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,this._flipY),n.activeTexture(n.TEXTURE0),n.bindTexture(o,this._texture),e.arrayBufferView?n.texSubImage2D(o,0,r,i,e.width,e.height,this._pixelFormat,this._pixelDatatype,e.arrayBufferView):n.texSubImage2D(o,0,r,i,this._pixelFormat,this._pixelDatatype,e),n.bindTexture(o,null)},v.prototype.copyFromFramebuffer=function(e,r,i,n,o,a){e=t(e,0),r=t(r,0),i=t(i,0),n=t(n,0),o=t(o,this._width),a=t(a,this._height);var s=this._context._gl,l=this._textureTarget;s.activeTexture(s.TEXTURE0),s.bindTexture(l,this._texture),s.copyTexSubImage2D(l,0,e,r,i,n,o,a),s.bindTexture(l,null)},v.prototype.generateMipmap=function(e){e=t(e,u.DONT_CARE);var r=this._context._gl,i=this._textureTarget;r.hint(r.GENERATE_MIPMAP_HINT,e),r.activeTexture(r.TEXTURE0),r.bindTexture(i,this._texture),r.generateMipmap(i),r.bindTexture(i,null)},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){return this._context._gl.deleteTexture(this._texture),n(this)},v}),r("Scene/TextureAtlas",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/loadImage","../Core/PixelFormat","../Core/RuntimeError","../Renderer/Framebuffer","../Renderer/RenderState","../Renderer/Texture","../ThirdParty/when"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,r,n,o,a){this.bottomLeft=i(e,t.ZERO),this.topRight=i(r,t.ZERO),this.childNode1=n,this.childNode2=o,this.imageIndex=a}function v(r,i){var o=r._context,a=r.numberOfImages,s=2;if(a>0){var l=r._texture.width,u=r._texture.height,c=s*(l+i.width+r._borderWidthInPixels),m=s*(u+i.height+r._borderWidthInPixels),v=l/c,_=u/m,g=new f(new t(l+r._borderWidthInPixels,0),new t(c,u)),y=new f(new t,new t(c,u),r._root,g),C=new f(new t(0,u+r._borderWidthInPixels),new t(c,m)),E=new f(new t,new t(c,m),y,C);r._root=E;for(var S=0;S<r._textureCoordinates.length;S++){var w=r._textureCoordinates[S];n(w)&&(w.x*=v,w.y*=_,w.width*=v,w.height*=_)}var T=new p({context:r._context,width:c,height:m,pixelFormat:r._pixelFormat}),b=new h({context:o,colorTextures:[T],destroyAttachments:!1}),x=r._copyCommand,P={viewport:new e(0,0,l,u)};x.renderState=d.fromCache(P),b._bind(),x.execute(r._context),b._unBind(),b.destroy(),r._texture=T,d.removeFromCache(P),x.renderState=void 0}else{var A=s*(i.width+r._borderWidthInPixels),I=s*(i.height+r._borderWidthInPixels);r._texture=r._texture&&r._texture.destroy(),r._texture=new p({context:r._context,width:A,height:I,pixelFormat:r._pixelFormat}),r._root=new f(new t,new t(A,I))}}function _(e,r,i){if(!n(r))return void 0;if(!n(r.childNode1)&&!n(r.childNode2)){if(n(r.imageIndex))return void 0;var o=r.topRight.x-r.bottomLeft.x,a=r.topRight.y-r.bottomLeft.y,s=o-i.width,l=a-i.height;if(0>s||0>l)return void 0;if(0===s&&0===l)return r;if(s>l){r.childNode1=new f(new t(r.bottomLeft.x,r.bottomLeft.y),new t(r.bottomLeft.x+i.width,r.topRight.y));var u=r.bottomLeft.x+i.width+e._borderWidthInPixels;u<r.topRight.x&&(r.childNode2=new f(new t(u,r.bottomLeft.y),new t(r.topRight.x,r.topRight.y)))}else{r.childNode1=new f(new t(r.bottomLeft.x,r.bottomLeft.y),new t(r.topRight.x,r.bottomLeft.y+i.height));var c=r.bottomLeft.y+i.height+e._borderWidthInPixels;c<r.topRight.y&&(r.childNode2=new f(new t(r.bottomLeft.x,c),new t(r.topRight.x,r.topRight.y)))}return _(e,r.childNode1,i)}return _(e,r.childNode1,i)||_(e,r.childNode2,i)}function g(t,i,o){var a=_(t,t._root,i);if(n(a)){a.imageIndex=o;var s=t._texture.width,l=t._texture.height,u=a.topRight.x-a.bottomLeft.x,c=a.topRight.y-a.bottomLeft.y,h=a.bottomLeft.x/s,d=a.bottomLeft.y/l,p=u/s,m=c/l;t._textureCoordinates[o]=new e(h,d,p,m),t._texture.copyFrom(i,a.bottomLeft.x,a.bottomLeft.y)}else v(t,i),g(t,i,o);t._guid=r()}var y=new t(16,16),C=function(e){e=i(e,i.EMPTY_OBJECT);var n=i(e.borderWidthInPixels,1),o=i(e.initialSize,y);this._context=e.context,this._pixelFormat=i(e.pixelFormat,u.RGBA),this._borderWidthInPixels=n,this._textureCoordinates=[],this._guid=r(),this._idHash={},this._texture=new p({context:this._context,width:o.x,height:o.y,pixelFormat:this._pixelFormat}),this._root=new f(new t,new t(o.x,o.y));var a=this,s={u_texture:function(){return a._texture}},l="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n gl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n";this._copyCommand=this._context.createViewportQuadCommand(l,{uniformMap:s})};return o(C.prototype,{borderWidthInPixels:{get:function(){return this._borderWidthInPixels}},textureCoordinates:{get:function(){return this._textureCoordinates}},texture:{get:function(){return this._texture}},numberOfImages:{get:function(){return this._textureCoordinates.length}},guid:{get:function(){return this._guid}}}),C.prototype.addImage=function(e,t){var r=this._idHash[e];if(n(r))return r;"function"==typeof t?t=t(e):"string"==typeof t&&(t=l(t));var i=this;return r=m(t,function(e){if(i.isDestroyed())return-1;var t=i.numberOfImages;return g(i,e,t),t}),this._idHash[e]=r,r},C.prototype.addSubRegion=function(t,i){var o=this._idHash[t];if(!n(o))throw new c('image with id "'+t+'" not found in the atlas.');var a=this;return m(o,function(t){if(-1===t)return-1;var n=a._texture.width,o=a._texture.height,s=a.numberOfImages,l=a._textureCoordinates[t],u=l.x+i.x/n,c=l.y+i.y/o,h=i.width/n,d=i.height/o;return a._textureCoordinates.push(new e(u,c,h,d)),a._guid=r(),s})},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){return this._texture=this._texture&&this._texture.destroy(),a(this)},C}),r("Scene/BillboardCollection",["../Core/AttributeCompression","../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EncodedCartesian3","../Core/IndexDatatype","../Core/Math","../Core/Matrix4","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArrayFacade","../Shaders/BillboardCollectionFS","../Shaders/BillboardCollectionVS","./Billboard","./BlendingState","./HorizontalOrigin","./Pass","./SceneMode","./TextureAtlas"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e){for(var t=e.length,r=0;t>r;++r)e[r]&&e[r]._destroy()}function D(e){if(e._billboardsRemoved){e._billboardsRemoved=!1;for(var t=[],r=e._billboards,i=r.length,n=0,o=0;i>n;++n){var a=r[n];a&&(a._index=o++,t.push(a))}e._billboards=t}}function R(e){var t=16384,r=e.cache.billboardCollection_indexBufferBatched;if(s(r))return r;for(var i=6*t-6,n=new Uint16Array(i),o=0,a=0;i>o;o+=6,a+=4)n[o]=a,n[o+1]=a+1,n[o+2]=a+2,n[o+3]=a+0,n[o+4]=a+2,n[o+5]=a+3;return r=f.createIndexBuffer({context:e,typedArray:n,usage:v.STATIC_DRAW,indexDatatype:d.UNSIGNED_SHORT}),r.vertexArrayDestroyable=!1,e.cache.billboardCollection_indexBufferBatched=r,r}function O(e){var t=e.cache.billboardCollection_indexBufferInstanced;return s(t)?t:(t=f.createIndexBuffer({context:e,typedArray:new Uint16Array([0,1,2,0,2,3]),usage:v.STATIC_DRAW,indexDatatype:d.UNSIGNED_SHORT}),t.vertexArrayDestroyable=!1,e.cache.billboardCollection_indexBufferInstanced=t,t)}function N(e){var t=e.cache.billboardCollection_vertexBufferInstanced;return s(t)?t:(t=f.createVertexBuffer({context:e,typedArray:new Float32Array([0,0,1,0,1,1,0,1]),usage:v.STATIC_DRAW}),t.vertexArrayDestroyable=!1,e.cache.billboardCollection_vertexBufferInstanced=t,t)}function L(e,t,r,i){var n=[{index:Y.positionHighAndScale,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[Z]},{index:Y.positionLowAndRotation,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[Z]},{index:Y.compressedAttribute0,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[K]},{index:Y.compressedAttribute1,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[ae]},{index:Y.compressedAttribute2,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[re]},{index:Y.eyeOffset,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[J]},{index:Y.scaleByDistance,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[oe]},{index:Y.pixelOffsetScaleByDistance,componentsPerAttribute:4,componentDatatype:o.FLOAT,usage:r[se]}];i&&n.push({index:Y.direction,componentsPerAttribute:2,componentDatatype:o.FLOAT,vertexBuffer:N(e)});var a=i?t:4*t;return new E(e,n,a,i)}function F(e,r,i,n,o){var a,s=n[Y.positionHighAndScale],l=n[Y.positionLowAndRotation],u=o._getActualPosition();e._mode===A.SCENE3D&&(t.expand(e._baseVolume,u,e._baseVolume),e._boundingVolumeDirty=!0),h.fromCartesian(u,pe);var c=o.scale,d=o.rotation;0!==d&&(e._shaderRotation=!0),e._maxScale=Math.max(e._maxScale,c);var p=pe.high,m=pe.low;e._instanced?(a=o._index,s(a,p.x,p.y,p.z,c),l(a,m.x,m.y,m.z,d)):(a=4*o._index,s(a+0,p.x,p.y,p.z,c),s(a+1,p.x,p.y,p.z,c),s(a+2,p.x,p.y,p.z,c),s(a+3,p.x,p.y,p.z,c),l(a+0,m.x,m.y,m.z,d),l(a+1,m.x,m.y,m.z,d),l(a+2,m.x,m.y,m.z,d),l(a+3,m.x,m.y,m.z,d))}function B(t,r,i,n,o){var a,s=n[Y.compressedAttribute0],l=o.pixelOffset,u=l.x,c=l.y,h=o._translate,d=h.x,m=h.y;t._maxPixelOffset=Math.max(t._maxPixelOffset,Math.abs(u+d),Math.abs(-c+m));var f=o.horizontalOrigin,v=o.verticalOrigin,_=o.show;0===o.color.alpha&&(_=!1),t._allHorizontalCenter=t._allHorizontalCenter&&f===x.CENTER,t._allVerticalCenter=t._allVerticalCenter&&v===x.CENTER;var g=0,y=0,C=0,E=0,S=o._imageIndex;if(-1!==S){var w=i[S];g=w.x,y=w.y,C=w.width,E=w.height}var T=g+C,b=y+E,P=Math.floor(p.clamp(u,-fe,fe)+fe)*ge;P+=(f+1)*ye,P+=(v+1)*Ce,P+=(_?1:0)*Ee; -var A=Math.floor(p.clamp(c,-fe,fe)+fe)*_e,I=Math.floor(p.clamp(d,-fe,fe)+fe)*_e,M=(p.clamp(m,-fe,fe)+fe)*Se,D=Math.floor(M),R=Math.floor((M-D)*_e);A+=D,I+=R,me.x=g,me.y=y;var O=e.compressTextureCoordinates(me);me.x=T;var N=e.compressTextureCoordinates(me);me.y=b;var L=e.compressTextureCoordinates(me);me.x=g;var F=e.compressTextureCoordinates(me);t._instanced?(a=o._index,s(a,P,A,I,O)):(a=4*o._index,s(a+0,P+we,A,I,O),s(a+1,P+Te,A,I,N),s(a+2,P+be,A,I,L),s(a+3,P+xe,A,I,F))}function V(t,r,n,o,l){var u,c=o[Y.compressedAttribute1],h=l.alignedAxis;i.equals(h,i.ZERO)||(t._shaderAlignedAxis=!0);var d=0,m=1,f=1,v=1,_=l.translucencyByDistance;s(_)&&(d=_.near,m=_.nearValue,f=_.far,v=_.farValue,(1!==m||1!==v)&&(t._shaderTranslucencyByDistance=!0));var g=0,y=l._imageIndex;if(-1!==y){var C=n[y];g=C.width}var E=t._textureAtlas.texture.width,S=Math.ceil(.5*a(l.width,E*g));t._maxSize=Math.max(t._maxSize,S);var w=p.clamp(S,0,ve),T=0;Math.abs(i.magnitudeSquared(h)-1)<p.EPSILON6&&(T=e.octEncodeFloat(h)),m=p.clamp(m,0,1),m=1===m?255:255*m|0,w=w*_e+m,v=p.clamp(v,0,1),v=1===v?255:255*v|0,T=T*_e+v,t._instanced?(u=l._index,c(u,w,T,d,f)):(u=4*l._index,c(u+0,w,T,d,f),c(u+1,w,T,d,f),c(u+2,w,T,d,f),c(u+3,w,T,d,f))}function z(e,t,r,i,o){var s,l=i[Y.compressedAttribute2],u=o.color,c=o.getPickId(t).color,h=o.sizeInMeters?1:0;e._allSizedInMeters=e._allSizedInMeters&&1===h;var d=0,p=o._imageIndex;if(-1!==p){var m=r[p];d=m.height}var f=e._textureAtlas.texture.dimensions,v=Math.ceil(.5*a(o.height,f.y*d));e._maxSize=Math.max(e._maxSize,v);var _=n.floatToByte(u.red),g=n.floatToByte(u.green),y=n.floatToByte(u.blue),C=_*ve+g*_e+y;_=n.floatToByte(c.red),g=n.floatToByte(c.green),y=n.floatToByte(c.blue);var E=_*ve+g*_e+y,S=n.floatToByte(u.alpha)*ve+n.floatToByte(c.alpha)*_e+h;e._instanced?(s=o._index,l(s,C,E,S,v)):(s=4*o._index,l(s+0,C,E,S,v),l(s+1,C,E,S,v),l(s+2,C,E,S,v),l(s+3,C,E,S,v))}function k(t,r,i,n,o){var a,s=n[Y.eyeOffset],l=o.eyeOffset;if(t._maxEyeOffset=Math.max(t._maxEyeOffset,Math.abs(l.x),Math.abs(l.y),Math.abs(l.z)),t._instanced){var u=0,c=0,h=o._imageIndex;if(-1!==h){var d=i[h];u=d.width,c=d.height}me.x=u,me.y=c;var p=e.compressTextureCoordinates(me);a=o._index,s(a,l.x,l.y,l.z,p)}else a=4*o._index,s(a+0,l.x,l.y,l.z,0),s(a+1,l.x,l.y,l.z,0),s(a+2,l.x,l.y,l.z,0),s(a+3,l.x,l.y,l.z,0)}function U(e,t,r,i,n){var o,a=i[Y.scaleByDistance],l=0,u=1,c=1,h=1,d=n.scaleByDistance;s(d)&&(l=d.near,u=d.nearValue,c=d.far,h=d.farValue,(1!==u||1!==h)&&(e._shaderScaleByDistance=!0)),e._instanced?(o=n._index,a(o,l,u,c,h)):(o=4*n._index,a(o+0,l,u,c,h),a(o+1,l,u,c,h),a(o+2,l,u,c,h),a(o+3,l,u,c,h))}function G(e,t,r,i,n){var o,a=i[Y.pixelOffsetScaleByDistance],l=0,u=1,c=1,h=1,d=n.pixelOffsetScaleByDistance;s(d)&&(l=d.near,u=d.nearValue,c=d.far,h=d.farValue,(1!==u||1!==h)&&(e._shaderPixelOffsetScaleByDistance=!0)),e._instanced?(o=n._index,a(o,l,u,c,h)):(o=4*n._index,a(o+0,l,u,c,h),a(o+1,l,u,c,h),a(o+2,l,u,c,h),a(o+3,l,u,c,h))}function W(e,t,r,i,n){F(e,t,r,i,n),B(e,t,r,i,n),V(e,t,r,i,n),z(e,t,r,i,n),k(e,t,r,i,n),U(e,t,r,i,n),G(e,t,r,i,n)}function H(e,r,i,n,o,a){var l;n.mode===A.SCENE3D?(l=e._baseVolume,e._boundingVolumeDirty=!0):l=e._baseVolume2D;for(var u=[],c=0;i>c;++c){var h=r[c],d=h.position,p=T._computeActualPosition(h,d,n,o);s(p)&&(h._setActualPosition(p),a?u.push(p):t.expand(l,p,l))}a&&t.fromPoints(u,l)}function q(e,t){var r=t.mode,i=e._billboards,n=e._billboardsToUpdate,o=e._modelMatrix;e._createVertexArray||e._mode!==r||r!==A.SCENE3D&&!m.equals(o,e.modelMatrix)?(e._mode=r,m.clone(e.modelMatrix,o),e._createVertexArray=!0,(r===A.SCENE3D||r===A.SCENE2D||r===A.COLUMBUS_VIEW)&&H(e,i,i.length,t,o,!0)):r===A.MORPHING?H(e,i,i.length,t,o,!0):(r===A.SCENE2D||r===A.COLUMBUS_VIEW)&&H(e,n,e._billboardsToUpdateIndex,t,o,!1)}function j(e,t,r){var i=1;if(!e._allSizedInMeters||0!==e._maxPixelOffset){var n=t.camera,o=n.distanceToBoundingSphere(r),a=t.context,s=t.camera.frustum.getPixelDimensions(a.drawingBufferWidth,a.drawingBufferHeight,o,Pe);i=Math.max(s.x,s.y)}var l=i*e._maxScale*e._maxSize*2;e._allHorizontalCenter&&e._allVerticalCenter&&(l*=.5);var u=i*e._maxPixelOffset+e._maxEyeOffset;r.radius+=l+u}var Y,X=T.SHOW_INDEX,Z=T.POSITION_INDEX,K=T.PIXEL_OFFSET_INDEX,J=T.EYE_OFFSET_INDEX,Q=T.HORIZONTAL_ORIGIN_INDEX,$=T.VERTICAL_ORIGIN_INDEX,ee=T.SCALE_INDEX,te=T.IMAGE_INDEX_INDEX,re=T.COLOR_INDEX,ie=T.ROTATION_INDEX,ne=T.ALIGNED_AXIS_INDEX,oe=T.SCALE_BY_DISTANCE_INDEX,ae=T.TRANSLUCENCY_BY_DISTANCE_INDEX,se=T.PIXEL_OFFSET_SCALE_BY_DISTANCE_INDEX,le=T.NUMBER_OF_PROPERTIES,ue={positionHighAndScale:0,positionLowAndRotation:1,compressedAttribute0:2,compressedAttribute1:3,compressedAttribute2:4,eyeOffset:5,scaleByDistance:6,pixelOffsetScaleByDistance:7},ce={direction:0,positionHighAndScale:1,positionLowAndRotation:2,compressedAttribute0:3,compressedAttribute1:4,compressedAttribute2:5,eyeOffset:6,scaleByDistance:7,pixelOffsetScaleByDistance:8},he=function(e){e=a(e,a.EMPTY_OBJECT),this._scene=e.scene,this._textureAtlas=void 0,this._textureAtlasGUID=void 0,this._destroyTextureAtlas=!0,this._sp=void 0,this._rs=void 0,this._vaf=void 0,this._spPick=void 0,this._billboards=[],this._billboardsToUpdate=[],this._billboardsToUpdateIndex=0,this._billboardsRemoved=!1,this._createVertexArray=!1,this._shaderRotation=!1,this._compiledShaderRotation=!1,this._compiledShaderRotationPick=!1,this._shaderAlignedAxis=!1,this._compiledShaderAlignedAxis=!1,this._compiledShaderAlignedAxisPick=!1,this._shaderScaleByDistance=!1,this._compiledShaderScaleByDistance=!1,this._compiledShaderScaleByDistancePick=!1,this._shaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistancePick=!1,this._shaderPixelOffsetScaleByDistance=!1,this._compiledShaderPixelOffsetScaleByDistance=!1,this._compiledShaderPixelOffsetScaleByDistancePick=!1,this._propertiesChanged=new Uint32Array(le),this._maxSize=0,this._maxEyeOffset=0,this._maxScale=1,this._maxPixelOffset=0,this._allHorizontalCenter=!0,this._allVerticalCenter=!0,this._allSizedInMeters=!0,this._baseVolume=new t,this._baseVolumeWC=new t,this._baseVolume2D=new t,this._boundingVolume=new t,this._boundingVolumeDirty=!1,this._colorCommands=[],this._pickCommands=[],this.modelMatrix=m.clone(a(e.modelMatrix,m.IDENTITY)),this._modelMatrix=m.clone(m.IDENTITY),this.debugShowBoundingVolume=a(e.debugShowBoundingVolume,!1),this._mode=A.SCENE3D,this._buffersUsage=[v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW,v.STATIC_DRAW];var r=this;this._uniforms={u_atlas:function(){return r._textureAtlas.texture}}};l(he.prototype,{length:{get:function(){return D(this),this._billboards.length}},textureAtlas:{get:function(){return this._textureAtlas},set:function(e){this._textureAtlas!==e&&(this._textureAtlas=this._destroyTextureAtlas&&this._textureAtlas&&this._textureAtlas.destroy(),this._textureAtlas=e,this._createVertexArray=!0)}},destroyTextureAtlas:{get:function(){return this._destroyTextureAtlas},set:function(e){this._destroyTextureAtlas=e}}}),he.prototype.add=function(e){var t=new T(e,this);return t._index=this._billboards.length,this._billboards.push(t),this._createVertexArray=!0,t},he.prototype.remove=function(e){return this.contains(e)?(this._billboards[e._index]=null,this._billboardsRemoved=!0,this._createVertexArray=!0,e._destroy(),!0):!1},he.prototype.removeAll=function(){M(this._billboards),this._billboards=[],this._billboardsToUpdate=[],this._billboardsToUpdateIndex=0,this._billboardsRemoved=!1,this._createVertexArray=!0},he.prototype._updateBillboard=function(e,t){e._dirty||(this._billboardsToUpdate[this._billboardsToUpdateIndex++]=e),++this._propertiesChanged[t]},he.prototype.contains=function(e){return s(e)&&e._billboardCollection===this},he.prototype.get=function(e){return D(this),this._billboards[e]};var de;he.prototype.computeNewBuffersUsage=function(){for(var e=this._buffersUsage,t=!1,r=this._propertiesChanged,i=0;le>i;++i){var n=0===r[i]?v.STATIC_DRAW:v.STREAM_DRAW;t=t||e[i]!==n,e[i]=n}return t};var pe=new h,me=new r,fe=32768,ve=65536,_e=256,ge=128,ye=32,Ce=8,Ee=4,Se=1/256,we=0,Te=2,be=3,xe=1,Pe=new r,Ae=[];return he.prototype.update=function(e){D(this);var r=this._billboards,i=r.length,n=e.context;this._instanced=n.instancedArrays,Y=this._instanced?ce:ue,de=this._instanced?O:R;var o=this._textureAtlas;if(!s(o)){o=this._textureAtlas=new I({context:n});for(var a=0;i>a;++a)r[a]._loadImage()}var l=o.textureCoordinates;if(0!==l.length){q(this,e),r=this._billboards,i=r.length;var u=this._billboardsToUpdate,c=this._billboardsToUpdateIndex,h=this._propertiesChanged,d=o.guid,p=this._createVertexArray||this._textureAtlasGUID!==d;this._textureAtlasGUID=d;var f,v=e.passes,E=v.pick;if(p||!E&&this.computeNewBuffersUsage()){this._createVertexArray=!1;for(var T=0;le>T;++T)h[T]=0;if(this._vaf=this._vaf&&this._vaf.destroy(),i>0){this._vaf=L(n,i,this._buffersUsage,this._instanced),f=this._vaf.writers;for(var x=0;i>x;++x){var M=this._billboards[x];M._dirty=!1,W(this,n,l,f,M)}this._vaf.commit(de(n))}this._billboardsToUpdateIndex=0}else if(c>0){var N=Ae;N.length=0,(h[Z]||h[ie]||h[ee])&&N.push(F),(h[te]||h[K]||h[Q]||h[$]||h[X])&&(N.push(B),this._instanced&&N.push(k)),(h[te]||h[ne]||h[ae])&&N.push(V),(h[te]||h[re])&&N.push(z),h[J]&&N.push(k),h[oe]&&N.push(U),h[se]&&N.push(G);var H=N.length;if(f=this._vaf.writers,c/i>.1){for(var he=0;c>he;++he){var pe=u[he];pe._dirty=!1;for(var me=0;H>me;++me)N[me](this,n,l,f,pe)}this._vaf.commit(de(n))}else{for(var fe=0;c>fe;++fe){var ve=u[fe];ve._dirty=!1;for(var _e=0;H>_e;++_e)N[_e](this,n,l,f,ve);this._instanced?this._vaf.subCommit(ve._index,1):this._vaf.subCommit(4*ve._index,4)}this._vaf.endSubCommits()}this._billboardsToUpdateIndex=0}if(c>1.5*i&&(u.length=i),s(this._vaf)&&s(this._vaf.va)){this._boundingVolumeDirty&&(this._boundingVolumeDirty=!1,t.transform(this._baseVolume,this.modelMatrix,this._baseVolumeWC));var ge,ye=m.IDENTITY;e.mode===A.SCENE3D?(ye=this.modelMatrix,ge=t.clone(this._baseVolumeWC,this._boundingVolume)):ge=t.clone(this._baseVolume2D,this._boundingVolume),j(this,e,ge);var Ce,Ee,Se,we,Te,be,xe=e.commandList;if(v.render){var Pe=this._colorCommands;for(s(this._rs)||(this._rs=g.fromCache({depthTest:{enabled:!0},blending:b.ALPHA_BLEND})),s(this._sp)&&this._shaderRotation===this._compiledShaderRotation&&this._shaderAlignedAxis===this._compiledShaderAlignedAxis&&this._shaderScaleByDistance===this._compiledShaderScaleByDistance&&this._shaderTranslucencyByDistance===this._compiledShaderTranslucencyByDistance&&this._shaderPixelOffsetScaleByDistance===this._compiledShaderPixelOffsetScaleByDistance||(we=new C({sources:[w]}),this._instanced&&we.defines.push("INSTANCED"),this._shaderRotation&&we.defines.push("ROTATION"),this._shaderAlignedAxis&&we.defines.push("ALIGNED_AXIS"),this._shaderScaleByDistance&&we.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&we.defines.push("EYE_DISTANCE_TRANSLUCENCY"),this._shaderPixelOffsetScaleByDistance&&we.defines.push("EYE_DISTANCE_PIXEL_OFFSET"),s(this._scene)&&we.defines.push("CLAMPED_TO_GROUND"),this._sp=y.replaceCache({context:n,shaderProgram:this._sp,vertexShaderSource:we,fragmentShaderSource:S,attributeLocations:Y}),this._compiledShaderRotation=this._shaderRotation,this._compiledShaderAlignedAxis=this._shaderAlignedAxis,this._compiledShaderScaleByDistance=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistance=this._shaderTranslucencyByDistance,this._compiledShaderPixelOffsetScaleByDistance=this._shaderPixelOffsetScaleByDistance),Ce=this._vaf.va,Ee=Ce.length,Pe.length=Ee,be=0;Ee>be;++be)Se=Pe[be],s(Se)||(Se=Pe[be]=new _({pass:P.OPAQUE,owner:this})),Se.boundingVolume=ge,Se.modelMatrix=ye,Se.count=Ce[be].indicesCount,Se.shaderProgram=this._sp,Se.uniformMap=this._uniforms,Se.vertexArray=Ce[be].va,Se.renderState=this._rs,Se.debugShowBoundingVolume=this.debugShowBoundingVolume,this._instanced&&(Se.count=6,Se.instanceCount=i),xe.push(Se)}if(E){var Ie=this._pickCommands;for(s(this._spPick)&&this._shaderRotation===this._compiledShaderRotationPick&&this._shaderAlignedAxis===this._compiledShaderAlignedAxisPick&&this._shaderScaleByDistance===this._compiledShaderScaleByDistancePick&&this._shaderTranslucencyByDistance===this._compiledShaderTranslucencyByDistancePick&&this._shaderPixelOffsetScaleByDistance===this._compiledShaderPixelOffsetScaleByDistancePick||(we=new C({defines:["RENDER_FOR_PICK"],sources:[w]}),this._instanced&&we.defines.push("INSTANCED"),this._shaderRotation&&we.defines.push("ROTATION"),this._shaderAlignedAxis&&we.defines.push("ALIGNED_AXIS"),this._shaderScaleByDistance&&we.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&we.defines.push("EYE_DISTANCE_TRANSLUCENCY"),this._shaderPixelOffsetScaleByDistance&&we.defines.push("EYE_DISTANCE_PIXEL_OFFSET"),s(this._scene)&&we.defines.push("CLAMPED_TO_GROUND"),Te=new C({defines:["RENDER_FOR_PICK"],sources:[S]}),this._spPick=y.replaceCache({context:n,shaderProgram:this._spPick,vertexShaderSource:we,fragmentShaderSource:Te,attributeLocations:Y}),this._compiledShaderRotationPick=this._shaderRotation,this._compiledShaderAlignedAxisPick=this._shaderAlignedAxis,this._compiledShaderScaleByDistancePick=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistancePick=this._shaderTranslucencyByDistance,this._compiledShaderPixelOffsetScaleByDistancePick=this._shaderPixelOffsetScaleByDistance),Ce=this._vaf.va,Ee=Ce.length,Ie.length=Ee,be=0;Ee>be;++be)Se=Ie[be],s(Se)||(Se=Ie[be]=new _({pass:P.OPAQUE,owner:this})),Se.boundingVolume=ge,Se.modelMatrix=ye,Se.count=Ce[be].indicesCount,Se.shaderProgram=this._spPick,Se.uniformMap=this._uniforms,Se.vertexArray=Ce[be].va,Se.renderState=this._rs,this._instanced&&(Se.count=6,Se.instanceCount=i),xe.push(Se)}}}},he.prototype.isDestroyed=function(){return!1},he.prototype.destroy=function(){return this._textureAtlas=this._destroyTextureAtlas&&this._textureAtlas&&this._textureAtlas.destroy(),this._sp=this._sp&&this._sp.destroy(),this._spPick=this._spPick&&this._spPick.destroy(),this._vaf=this._vaf&&this._vaf.destroy(),M(this._billboards),u(this)},he}),r("DataSources/BoundingSphereState",["../Core/freezeObject"],function(e){"use strict";var t={DONE:0,PENDING:1,FAILED:2};return e(t)}),r("DataSources/Property",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Iso8601"],function(e,t,r,i,n){"use strict";var o=function(){i.throwInstantiationError()};return r(o.prototype,{isConstant:{get:i.throwInstantiationError},definitionChanged:{get:i.throwInstantiationError}}),o.prototype.getValue=i.throwInstantiationError,o.prototype.equals=i.throwInstantiationError,o.equals=function(e,r){return e===r||t(e)&&e.equals(r)},o.arrayEquals=function(e,r){if(e===r)return!0;if(!t(e)||!t(r)||e.length!==r.length)return!1;for(var i=e.length,n=0;i>n;n++)if(!o.equals(e[n],r[n]))return!1;return!0},o.isConstant=function(e){return!t(e)||e.isConstant},o.getValueOrUndefined=function(e,r,i){return t(e)?e.getValue(r,i):void 0},o.getValueOrDefault=function(r,i,n,o){return t(r)?e(r.getValue(i,o),n):n},o.getValueOrClonedDefault=function(e,r,i,n){var o;return t(e)&&(o=e.getValue(r,n)),t(o)||(o=i.clone(o)),o},o}),r("DataSources/BillboardVisualizer",["../Core/AssociativeArray","../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/NearFarScalar","../Scene/BillboardCollection","../Scene/HorizontalOrigin","../Scene/VerticalOrigin","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){if(o(e)){var r=e.billboard;o(r)&&(e.textureValue=void 0,e.billboard=void 0,r.show=!1,r.image=void 0,t.push(r._index))}}var f=n.WHITE,v=i.ZERO,_=r.ZERO,g=1,y=0,C=i.ZERO,E=c.CENTER,S=h.CENTER,w=!1,T=new i,b=new n,x=new i,P=new r,A=new l,I=new l,M=new l,D=new t,R=function(e){this.entity=e,this.billboard=void 0,this.textureValue=void 0},O=function(t,r){r.collectionChanged.addEventListener(O.prototype._onCollectionChanged,this),this._scene=t,this._unusedIndexes=[],this._billboardCollection=void 0,this._entityCollection=r,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return O.prototype.update=function(e){for(var t=this._items.values,r=this._unusedIndexes,i=0,n=t.length;n>i;i++){var a,s=t[i],l=s.entity,c=l._billboard,h=s.billboard,d=l.isShowing&&l.isAvailable(e)&&p.getValueOrDefault(c._show,e,!0);if(d&&(T=p.getValueOrUndefined(l._position,e,T),a=p.getValueOrUndefined(c._image,e),d=o(T)&&o(a)),d){if(!o(h)){var R=this._billboardCollection;o(R)||(R=new u,this._billboardCollection=R,this._scene.primitives.add(R));var O=r.length;h=O>0?R.get(r.pop()):R.add(),h.id=l,h.image=void 0,s.billboard=h}h.show=d,s.textureValue!==a&&(h.image=a,s.textureValue=a),h.position=T,h.color=p.getValueOrDefault(c._color,e,f,b),h.eyeOffset=p.getValueOrDefault(c._eyeOffset,e,v,x),h.pixelOffset=p.getValueOrDefault(c._pixelOffset,e,_,P),h.scale=p.getValueOrDefault(c._scale,e,g),h.rotation=p.getValueOrDefault(c._rotation,e,y),h.alignedAxis=p.getValueOrDefault(c._alignedAxis,e,C),h.horizontalOrigin=p.getValueOrDefault(c._horizontalOrigin,e,E),h.verticalOrigin=p.getValueOrDefault(c._verticalOrigin,e,S),h.width=p.getValueOrUndefined(c._width,e),h.height=p.getValueOrUndefined(c._height,e),h.scaleByDistance=p.getValueOrUndefined(c._scaleByDistance,e,A),h.translucencyByDistance=p.getValueOrUndefined(c._translucencyByDistance,e,I),h.pixelOffsetScaleByDistance=p.getValueOrUndefined(c._pixelOffsetScaleByDistance,e,M),h.sizeInMeters=p.getValueOrDefault(c._sizeInMeters,w);var N=p.getValueOrUndefined(c._imageSubRegion,e,D);o(N)&&h.setImageSubRegion(h._imageId,N)}else m(s,r)}return!0},O.prototype.getBoundingSphere=function(e,t){var r=this._items.get(e.id);return o(r)&&o(r.billboard)?(t.center=i.clone(r.billboard.position,t.center),t.radius=0,d.DONE):d.FAILED},O.prototype.isDestroyed=function(){return!1},O.prototype.destroy=function(){return this._entityCollection.collectionChanged.removeEventListener(O.prototype._onCollectionChanged,this),o(this._billboardCollection)&&this._scene.primitives.remove(this._billboardCollection),a(this)},O.prototype._onCollectionChanged=function(e,t,r,i){var n,a,s=this._unusedIndexes,l=this._items;for(n=t.length-1;n>-1;n--)a=t[n],o(a._billboard)&&o(a._position)&&l.set(a.id,new R(a));for(n=i.length-1;n>-1;n--)a=i[n],o(a._billboard)&&o(a._position)?l.contains(a.id)||l.set(a.id,new R(a)):(m(l.get(a.id),s),l.remove(a.id));for(n=r.length-1;n>-1;n--)a=r[n],m(l.get(a.id),s),l.remove(a.id)},O}),r("Shaders/Appearances/AllMaterialAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec3 v_tangentEC;\nvarying vec3 v_binormalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nmat3 tangentToEyeMatrix = czm_tangentToEyeSpaceMatrix(v_normalEC, v_tangentEC, v_binormalEC);\nvec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.tangentToEyeMatrix = tangentToEyeMatrix;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nmaterialInput.st = v_st;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/AllMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nattribute vec3 tangent;\nattribute vec3 binormal;\nattribute vec2 st;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec3 v_tangentEC;\nvarying vec3 v_binormalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\nv_tangentEC = czm_normal * tangent;\nv_binormalEC = czm_normal * binormal;\nv_st = st;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Shaders/Appearances/BasicMaterialAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nvec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/BasicMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Shaders/Appearances/TexturedMaterialAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nvec3 normalEC = normalize(v_normalEC);;\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nmaterialInput.st = v_st;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/TexturedMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nattribute vec2 st;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\nv_st = st;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Scene/CullFace",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={FRONT:t.FRONT,BACK:t.BACK,FRONT_AND_BACK:t.FRONT_AND_BACK};return e(r)}),r("Scene/Appearance",["../Core/clone","../Core/combine","../Core/defaultValue","../Core/defined","../Core/defineProperties","./BlendingState","./CullFace"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){e=r(e,r.EMPTY_OBJECT),this.material=e.material,this.translucent=r(e.translucent,!0),this._vertexShaderSource=e.vertexShaderSource,this._fragmentShaderSource=e.fragmentShaderSource,this._renderState=e.renderState,this._closed=r(e.closed,!1)};return n(s.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}}}),s.prototype.getFragmentShaderSource=function(){var e=[];return this.flat&&e.push("#define FLAT"),this.faceForward&&e.push("#define FACE_FORWARD"),i(this.material)&&e.push(this.material.shaderSource),e.push(this.fragmentShaderSource),e.join("\n")},s.prototype.isTranslucent=function(){return i(this.material)&&this.material.isTranslucent()||!i(this.material)&&this.translucent},s.prototype.getRenderState=function(){var t=this.isTranslucent(),r=e(this.renderState,!1);return t?(r.depthMask=!1,r.blending=o.ALPHA_BLEND):r.depthMask=!0,r},s.getDefaultRenderState=function(e,r,n){var s={depthTest:{enabled:!0}};return e&&(s.depthMask=!1,s.blending=o.ALPHA_BLEND),r&&(s.cull={enabled:!0,face:a.BACK}),i(n)&&(s=t(n,s,!0)),s},s}),r("Renderer/CubeMapFace",["../Core/defaultValue","../Core/defineProperties","../Core/DeveloperError","./PixelDatatype"],function(e,t,r,i){"use strict";var n=function(e,t,r,i,n,o,a,s,l){this._gl=e,this._texture=t,this._textureTarget=r,this._targetFace=i,this._pixelFormat=n,this._pixelDatatype=o,this._size=a,this._preMultiplyAlpha=s,this._flipY=l};return t(n.prototype,{pixelFormat:{get:function(){return this._pixelFormat}},pixelDatatype:{get:function(){return this._pixelDatatype}},_target:{get:function(){return this._targetFace}}}),n.prototype.copyFrom=function(t,r,i){r=e(r,0),i=e(i,0);var n=this._gl,o=this._textureTarget;n.pixelStorei(n.UNPACK_PREMULTIPLY_ALPHA_WEBGL,this._preMultiplyAlpha),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,this._flipY),n.activeTexture(n.TEXTURE0),n.bindTexture(o,this._texture),t.arrayBufferView?n.texSubImage2D(this._targetFace,0,r,i,t.width,t.height,this._pixelFormat,this._pixelDatatype,t.arrayBufferView):n.texSubImage2D(this._targetFace,0,r,i,this._pixelFormat,this._pixelDatatype,t),n.bindTexture(o,null)},n.prototype.copyFromFramebuffer=function(t,r,i,n,o,a){t=e(t,0),r=e(r,0),i=e(i,0),n=e(n,0),o=e(o,this._size),a=e(a,this._size);var s=this._gl,l=this._textureTarget;s.activeTexture(s.TEXTURE0),s.bindTexture(l,this._texture),s.copyTexSubImage2D(this._targetFace,0,t,r,i,n,o,a),s.bindTexture(l,null)},n}),r("Renderer/CubeMap",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Math","../Core/PixelFormat","./ContextLimits","./CubeMapFace","./MipmapHint","./PixelDatatype","./Sampler","./TextureMagnificationFilter","./TextureMinificationFilter","./TextureWrap"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";var f=function(r){function i(e,t){t.arrayBufferView?g.texImage2D(e,0,m,p,p,0,m,f,t.arrayBufferView):g.texImage2D(e,0,m,m,f,t)}r=e(r,e.EMPTY_OBJECT);var n,o,s=r.context,u=r.source;if(t(u)){var d=[u.positiveX,u.negativeX,u.positiveY,u.negativeY,u.positiveZ,u.negativeZ];n=d[0].width,o=d[0].height}else n=r.width,o=r.height;var p=n,m=e(r.pixelFormat,a.RGBA),f=e(r.pixelDatatype,c.UNSIGNED_BYTE),v=r.preMultiplyAlpha||m===a.RGB||m===a.LUMINANCE,_=e(r.flipY,!0),g=s._gl,y=g.TEXTURE_CUBE_MAP,C=g.createTexture();g.activeTexture(g.TEXTURE0),g.bindTexture(y,C),t(u)?(g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,v),g.pixelStorei(g.UNPACK_FLIP_Y_WEBGL,_),i(g.TEXTURE_CUBE_MAP_POSITIVE_X,u.positiveX),i(g.TEXTURE_CUBE_MAP_NEGATIVE_X,u.negativeX),i(g.TEXTURE_CUBE_MAP_POSITIVE_Y,u.positiveY),i(g.TEXTURE_CUBE_MAP_NEGATIVE_Y,u.negativeY),i(g.TEXTURE_CUBE_MAP_POSITIVE_Z,u.positiveZ),i(g.TEXTURE_CUBE_MAP_NEGATIVE_Z,u.negativeZ)):(g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_X,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_NEGATIVE_X,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_Y,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_NEGATIVE_Y,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_POSITIVE_Z,0,m,p,p,0,m,f,null),g.texImage2D(g.TEXTURE_CUBE_MAP_NEGATIVE_Z,0,m,p,p,0,m,f,null)),g.bindTexture(y,null),this._gl=g,this._textureFilterAnisotropic=s._textureFilterAnisotropic,this._textureTarget=y,this._texture=C,this._pixelFormat=m,this._pixelDatatype=f,this._size=p,this._preMultiplyAlpha=v,this._flipY=_,this._sampler=void 0,this._positiveX=new l(g,C,y,g.TEXTURE_CUBE_MAP_POSITIVE_X,m,f,p,v,_),this._negativeX=new l(g,C,y,g.TEXTURE_CUBE_MAP_NEGATIVE_X,m,f,p,v,_),this._positiveY=new l(g,C,y,g.TEXTURE_CUBE_MAP_POSITIVE_Y,m,f,p,v,_),this._negativeY=new l(g,C,y,g.TEXTURE_CUBE_MAP_NEGATIVE_Y,m,f,p,v,_),this._positiveZ=new l(g,C,y,g.TEXTURE_CUBE_MAP_POSITIVE_Z,m,f,p,v,_),this._negativeZ=new l(g,C,y,g.TEXTURE_CUBE_MAP_NEGATIVE_Z,m,f,p,v,_),this.sampler=new h};return r(f.prototype,{positiveX:{get:function(){return this._positiveX}},negativeX:{get:function(){return this._negativeX}},positiveY:{get:function(){return this._positiveY}},negativeY:{get:function(){return this._negativeY}},positiveZ:{get:function(){return this._positiveZ}},negativeZ:{get:function(){return this._negativeZ}},sampler:{get:function(){return this._sampler},set:function(e){var r=e.minificationFilter,i=e.magnificationFilter,n=r===p.NEAREST_MIPMAP_NEAREST||r===p.NEAREST_MIPMAP_LINEAR||r===p.LINEAR_MIPMAP_NEAREST||r===p.LINEAR_MIPMAP_LINEAR;this._pixelDatatype===c.FLOAT&&(r=n?p.NEAREST_MIPMAP_NEAREST:p.NEAREST,i=d.NEAREST);var o=this._gl,a=this._textureTarget;o.activeTexture(o.TEXTURE0),o.bindTexture(a,this._texture),o.texParameteri(a,o.TEXTURE_MIN_FILTER,r),o.texParameteri(a,o.TEXTURE_MAG_FILTER,i),o.texParameteri(a,o.TEXTURE_WRAP_S,e.wrapS),o.texParameteri(a,o.TEXTURE_WRAP_T,e.wrapT),t(this._textureFilterAnisotropic)&&o.texParameteri(a,this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT,e.maximumAnisotropy),o.bindTexture(a,null),this._sampler=e}},pixelFormat:{get:function(){return this._pixelFormat}},pixelDatatype:{get:function(){return this._pixelDatatype}},width:{get:function(){return this._size}},height:{get:function(){return this._size}},preMultiplyAlpha:{get:function(){return this._preMultiplyAlpha}},flipY:{get:function(){return this._flipY}},_target:{get:function(){return this._textureTarget}}}),f.prototype.generateMipmap=function(t){t=e(t,u.DONT_CARE);var r=this._gl,i=this._textureTarget;r.hint(r.GENERATE_MIPMAP_HINT,t),r.activeTexture(r.TEXTURE0),r.bindTexture(i,this._texture),r.generateMipmap(i),r.bindTexture(i,null)},f.prototype.isDestroyed=function(){return!1},f.prototype.destroy=function(){return this._gl.deleteTexture(this._texture),this._positiveX=i(this._positiveX),this._negativeX=i(this._negativeX),this._positiveY=i(this._positiveY),this._negativeY=i(this._negativeY),this._positiveZ=i(this._positiveZ),this._negativeZ=i(this._negativeZ),i(this)},f}),r("Shaders/Materials/BumpMapMaterial",[],function(){"use strict";return"uniform sampler2D image;\nuniform float strength;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nvec2 centerPixel = fract(repeat * st);\nfloat centerBump = texture2D(image, centerPixel).channel;\nfloat imageWidth = float(imageDimensions.x);\nvec2 rightPixel = fract(repeat * (st + vec2(1.0 / imageWidth, 0.0)));\nfloat rightBump = texture2D(image, rightPixel).channel;\nfloat imageHeight = float(imageDimensions.y);\nvec2 leftPixel = fract(repeat * (st + vec2(0.0, 1.0 / imageHeight)));\nfloat topBump = texture2D(image, leftPixel).channel;\nvec3 normalTangentSpace = normalize(vec3(centerBump - rightBump, centerBump - topBump, clamp(1.0 - strength, 0.1, 1.0)));\nvec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\nmaterial.normal = normalEC;\nmaterial.diffuse = vec3(0.01);\nreturn material;\n}\n"}),r("Shaders/Materials/CheckerboardMaterial",[],function(){"use strict";return"uniform vec4 lightColor;\nuniform vec4 darkColor;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat b = mod(floor(repeat.s * st.s) + floor(repeat.t * st.t), 2.0);\nfloat scaledWidth = fract(repeat.s * st.s);\nscaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\nfloat scaledHeight = fract(repeat.t * st.t);\nscaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\nfloat value = min(scaledWidth, scaledHeight);\nvec4 currentColor = mix(lightColor, darkColor, b);\nvec4 color = czm_antialias(lightColor, darkColor, currentColor, value, 0.03);\nmaterial.diffuse = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/DotMaterial",[],function(){"use strict";return"uniform vec4 lightColor;\nuniform vec4 darkColor;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat b = smoothstep(0.3, 0.32, length(fract(repeat * materialInput.st) - 0.5));\nvec4 color = mix(lightColor, darkColor, b);\nmaterial.diffuse = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"; -}),r("Shaders/Materials/FadeMaterial",[],function(){"use strict";return"uniform vec4 fadeInColor;\nuniform vec4 fadeOutColor;\nuniform float maximumDistance;\nuniform bool repeat;\nuniform vec2 fadeDirection;\nuniform vec2 time;\nfloat getTime(float t, float coord)\n{\nfloat scalar = 1.0 / maximumDistance;\nfloat q = distance(t, coord) * scalar;\nif (repeat)\n{\nfloat r = distance(t, coord + 1.0) * scalar;\nfloat s = distance(t, coord - 1.0) * scalar;\nq = min(min(r, s), q);\n}\nreturn clamp(q, 0.0, 1.0);\n}\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat s = getTime(time.x, st.s) * fadeDirection.s;\nfloat t = getTime(time.y, st.t) * fadeDirection.t;\nfloat u = length(vec2(s, t));\nvec4 color = mix(fadeInColor, fadeOutColor, u);\nmaterial.emission = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/GridMaterial",[],function(){"use strict";return"#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives : enable\n#endif\nuniform vec4 color;\nuniform float cellAlpha;\nuniform vec2 lineCount;\nuniform vec2 lineThickness;\nuniform vec2 lineOffset;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat scaledWidth = fract(lineCount.s * st.s - lineOffset.s);\nscaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\nfloat scaledHeight = fract(lineCount.t * st.t - lineOffset.t);\nscaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\nfloat value;\n#ifdef GL_OES_standard_derivatives\nconst float fuzz = 1.2;\nvec2 thickness = (lineThickness * czm_resolutionScale) - 1.0;\nvec2 dx = abs(dFdx(st));\nvec2 dy = abs(dFdy(st));\nvec2 dF = vec2(max(dx.s, dy.s), max(dx.t, dy.t)) * lineCount;\nvalue = min(\nsmoothstep(dF.s * thickness.s, dF.s * (fuzz + thickness.s), scaledWidth),\nsmoothstep(dF.t * thickness.t, dF.t * (fuzz + thickness.t), scaledHeight));\n#else\nconst float fuzz = 0.05;\nvec2 range = 0.5 - (lineThickness * 0.05);\nvalue = min(\n1.0 - smoothstep(range.s, range.s + fuzz, scaledWidth),\n1.0 - smoothstep(range.t, range.t + fuzz, scaledHeight));\n#endif\nfloat dRim = 1.0 - abs(dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC)));\nfloat sRim = smoothstep(0.8, 1.0, dRim);\nvalue *= (1.0 - sRim);\nvec3 halfColor = color.rgb * 0.5;\nmaterial.diffuse = halfColor;\nmaterial.emission = halfColor;\nmaterial.alpha = color.a * (1.0 - ((1.0 - cellAlpha) * value));\nreturn material;\n}\n"}),r("Shaders/Materials/NormalMapMaterial",[],function(){"use strict";return"uniform sampler2D image;\nuniform float strength;\nuniform vec2 repeat;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec4 textureValue = texture2D(image, fract(repeat * materialInput.st));\nvec3 normalTangentSpace = textureValue.channels;\nnormalTangentSpace.xy = normalTangentSpace.xy * 2.0 - 1.0;\nnormalTangentSpace.z = clamp(1.0 - strength, 0.1, 1.0);\nnormalTangentSpace = normalize(normalTangentSpace);\nvec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\nmaterial.normal = normalEC;\nreturn material;\n}\n"}),r("Shaders/Materials/PolylineArrowMaterial",[],function(){"use strict";return"#extension GL_OES_standard_derivatives : enable\nuniform vec4 color;\nvarying float v_width;\nfloat getPointOnLine(vec2 p0, vec2 p1, float x)\n{\nfloat slope = (p0.y - p1.y) / (p0.x - p1.x);\nreturn slope * (x - p0.x) + p0.y;\n}\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat base = 1.0 - abs(fwidth(st.s)) * 10.0;\nvec2 center = vec2(1.0, 0.5);\nfloat ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s);\nfloat ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s);\nfloat halfWidth = 0.15;\nfloat s = step(0.5 - halfWidth, st.t);\ns *= 1.0 - step(0.5 + halfWidth, st.t);\ns *= 1.0 - step(base, st.s);\nfloat t = step(base, materialInput.st.s);\nt *= 1.0 - step(ptOnUpperLine, st.t);\nt *= step(ptOnLowerLine, st.t);\nfloat dist;\nif (st.s < base)\n{\nfloat d1 = abs(st.t - (0.5 - halfWidth));\nfloat d2 = abs(st.t - (0.5 + halfWidth));\ndist = min(d1, d2);\n}\nelse\n{\nfloat d1 = czm_infinity;\nif (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth)\n{\nd1 = abs(st.s - base);\n}\nfloat d2 = abs(st.t - ptOnUpperLine);\nfloat d3 = abs(st.t - ptOnLowerLine);\ndist = min(min(d1, d2), d3);\n}\nvec4 outsideColor = vec4(0.0);\nvec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0));\nvec4 outColor = czm_antialias(outsideColor, color, currentColor, dist);\nmaterial.diffuse = outColor.rgb;\nmaterial.alpha = outColor.a;\nreturn material;\n}\n"}),r("Shaders/Materials/PolylineGlowMaterial",[],function(){"use strict";return"uniform vec4 color;\nuniform float glowPower;\nvarying float v_width;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat glow = glowPower / abs(st.t - 0.5) - (glowPower / 0.5);\nmaterial.emission = max(vec3(glow - 1.0 + color.rgb), color.rgb);\nmaterial.alpha = clamp(0.0, 1.0, glow) * color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/PolylineOutlineMaterial",[],function(){"use strict";return"uniform vec4 color;\nuniform vec4 outlineColor;\nuniform float outlineWidth;\nvarying float v_width;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nvec2 st = materialInput.st;\nfloat halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width;\nfloat b = step(0.5 - halfInteriorWidth, st.t);\nb *= 1.0 - step(0.5 + halfInteriorWidth, st.t);\nfloat d1 = abs(st.t - (0.5 - halfInteriorWidth));\nfloat d2 = abs(st.t - (0.5 + halfInteriorWidth));\nfloat dist = min(d1, d2);\nvec4 currentColor = mix(outlineColor, color, b);\nvec4 outColor = czm_antialias(outlineColor, color, currentColor, dist);\nmaterial.diffuse = outColor.rgb;\nmaterial.alpha = outColor.a;\nreturn material;\n}\n"}),r("Shaders/Materials/RimLightingMaterial",[],function(){"use strict";return"uniform vec4 color;\nuniform vec4 rimColor;\nuniform float width;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat d = 1.0 - dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC));\nfloat s = smoothstep(1.0 - width, 1.0, d);\nmaterial.diffuse = color.rgb;\nmaterial.emission = rimColor.rgb * s;\nmaterial.alpha = mix(color.a, rimColor.a, s);\nreturn material;\n}\n"}),r("Shaders/Materials/StripeMaterial",[],function(){"use strict";return"uniform vec4 evenColor;\nuniform vec4 oddColor;\nuniform float offset;\nuniform float repeat;\nuniform bool horizontal;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat coord = mix(materialInput.st.s, materialInput.st.t, float(horizontal));\nfloat value = fract((coord - offset) * (repeat * 0.5));\nfloat dist = min(value, min(abs(value - 0.5), 1.0 - value));\nvec4 currentColor = mix(evenColor, oddColor, step(0.5, value));\nvec4 color = czm_antialias(evenColor, oddColor, currentColor, dist);\nmaterial.diffuse = color.rgb;\nmaterial.alpha = color.a;\nreturn material;\n}\n"}),r("Shaders/Materials/Water",[],function(){"use strict";return"uniform sampler2D specularMap;\nuniform sampler2D normalMap;\nuniform vec4 baseWaterColor;\nuniform vec4 blendColor;\nuniform float frequency;\nuniform float animationSpeed;\nuniform float amplitude;\nuniform float specularIntensity;\nuniform float fadeFactor;\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\nczm_material material = czm_getDefaultMaterial(materialInput);\nfloat time = czm_frameNumber * animationSpeed;\nfloat fade = max(1.0, (length(materialInput.positionToEyeEC) / 10000000000.0) * frequency * fadeFactor);\nfloat specularMapValue = texture2D(specularMap, materialInput.st).r;\nvec4 noise = czm_getWaterNoise(normalMap, materialInput.st * frequency, time, 0.0);\nvec3 normalTangentSpace = noise.xyz * vec3(1.0, 1.0, (1.0 / amplitude));\nnormalTangentSpace.xy /= fade;\nnormalTangentSpace = mix(vec3(0.0, 0.0, 50.0), normalTangentSpace, specularMapValue);\nnormalTangentSpace = normalize(normalTangentSpace);\nfloat tsPerturbationRatio = clamp(dot(normalTangentSpace, vec3(0.0, 0.0, 1.0)), 0.0, 1.0);\nmaterial.alpha = specularMapValue;\nmaterial.diffuse = mix(blendColor.rgb, baseWaterColor.rgb, specularMapValue);\nmaterial.diffuse += (0.1 * tsPerturbationRatio);\nmaterial.normal = normalize(materialInput.tangentToEyeMatrix * normalTangentSpace);\nmaterial.specular = specularIntensity;\nmaterial.shininess = 10.0;\nreturn material;\n}\n"}),r("Scene/Material",["../Core/Cartesian2","../Core/clone","../Core/Color","../Core/combine","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/isArray","../Core/loadImage","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Renderer/CubeMap","../Renderer/Texture","../Shaders/Materials/BumpMapMaterial","../Shaders/Materials/CheckerboardMaterial","../Shaders/Materials/DotMaterial","../Shaders/Materials/FadeMaterial","../Shaders/Materials/GridMaterial","../Shaders/Materials/NormalMapMaterial","../Shaders/Materials/PolylineArrowMaterial","../Shaders/Materials/PolylineGlowMaterial","../Shaders/Materials/PolylineOutlineMaterial","../Shaders/Materials/RimLightingMaterial","../Shaders/Materials/StripeMaterial","../Shaders/Materials/Water","../ThirdParty/when"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e,r){e=o(e,o.EMPTY_OBJECT),r._strict=o(e.strict,!1),r._count=o(e.count,0),r._template=t(o(e.fabric,o.EMPTY_OBJECT)),r._template.uniforms=t(o(r._template.uniforms,o.EMPTY_OBJECT)),r._template.materials=t(o(r._template.materials,o.EMPTY_OBJECT)),r.type=a(r._template.type)?r._template.type:n(),r.shaderSource="",r.materials={},r.uniforms={},r._uniforms={},r._translucentFunctions=[];var s,l=H._materialCache.getMaterial(r.type);if(a(l)){var u=t(l.fabric,!0);r._template=i(r._template,u,!0),s=l.translucent}N(r),a(l)||H._materialCache.addMaterial(r.type,r),L(r),V(r),U(r);var c=0===r._translucentFunctions.length?!0:void 0;if(s=o(s,c),s=o(e.translucent,s),a(s))if("function"==typeof s){var h=function(){return s(r)};r._translucentFunctions.push(h)}else r._translucentFunctions.push(s)}function D(e,t,r,i){if(a(e))for(var n in e)if(e.hasOwnProperty(n)){var o=-1!==t.indexOf(n);(i&&!o||!i&&o)&&r(n,t)}}function R(e,t){for(var r="fabric: property name '"+e+"' is not valid. It should be ",i=0;i<t.length;i++){var n="'"+t[i]+"'";r+=i===t.length-1?"or "+n+".":n+", "}throw new u(r)}function O(e,t){var r="fabric: uniforms and materials cannot share the same property '"+e+"'";throw new u(r)}function N(e){var t=e._template,r=t.uniforms,i=t.materials,n=t.components;if(a(n)&&a(t.source))throw new u("fabric: cannot have source and components in the same template.");D(t,q,R,!0),D(n,j,R,!0);var o=[];for(var s in i)i.hasOwnProperty(s)&&o.push(s);D(r,o,O,!1)}function L(e){var t=e._template.components,r=e._template.source;if(a(r))e.shaderSource+=r+"\n";else{if(e.shaderSource+="czm_material czm_getMaterial(czm_materialInput materialInput)\n{\n",e.shaderSource+="czm_material material = czm_getDefaultMaterial(materialInput);\n",a(t))for(var i in t)t.hasOwnProperty(i)&&(e.shaderSource+="material."+i+" = "+t[i]+";\n");e.shaderSource+="return material;\n}\n"}}function F(e){return function(t,r){var i,n,o=t.uniforms,s=o[e],l=t._textures[e];if(s instanceof v&&s!==l){t._texturePaths[e]=void 0;var u=t._textures[e];return u!==t._defaultTexture&&u.destroy(),t._textures[e]=s,i=e+"Dimensions",void(o.hasOwnProperty(i)&&(n=o[i],n.x=s._width,n.y=s._height))}a(l)||(t._texturePaths[e]=void 0,a(t._defaultTexture)||(t._defaultTexture=r.defaultTexture),l=t._textures[e]=t._defaultTexture,i=e+"Dimensions",o.hasOwnProperty(i)&&(n=o[i],n.x=l._width,n.y=l._height)),s!==H.DefaultImageId&&s!==t._texturePaths[e]&&("string"==typeof s?I(h(s),function(r){t._loadedImages.push({id:e,image:r})}):s instanceof HTMLCanvasElement&&t._loadedImages.push({id:e,image:s}),t._texturePaths[e]=s)}}function B(e){return function(t,r){var i=t.uniforms[e];if(i instanceof f){var n=t._textures[e];return n!==t._defaultTexture&&n.destroy(),t._texturePaths[e]=void 0,void(t._textures[e]=i)}if(a(t._textures[e])||(t._texturePaths[e]=void 0,t._textures[e]=r.defaultCubeMap),i!==H.DefaultCubeMapId){var o=i.positiveX+i.negativeX+i.positiveY+i.negativeY+i.positiveZ+i.negativeZ;if(o!==t._texturePaths[e]){var s=[h(i.positiveX),h(i.negativeX),h(i.positiveY),h(i.negativeY),h(i.positiveZ),h(i.negativeZ)];I.all(s).then(function(r){t._loadedCubeMaps.push({id:e,images:r})}),t._texturePaths[e]=o}}}}function V(e){var t=e._template.uniforms;for(var r in t)t.hasOwnProperty(r)&&z(e,r)}function z(e,t){var r=e._strict,i=e._template.uniforms,n=i[t],o=k(n);if(!a(o))throw new u("fabric: uniform '"+t+"' has invalid type.");if("channels"===o){if(0===G(e,t,n,!1)&&r)throw new u("strict: shader source does not use channels '"+t+"'.")}else{if("sampler2D"===o){var s=t+"Dimensions";W(e,s)>0&&(i[s]={type:"ivec3",x:1,y:1},z(e,s))}var l=new RegExp("uniform\\s+"+o+"\\s+"+t+"\\s*;");if(!l.test(e.shaderSource)){var c="uniform "+o+" "+t+";";e.shaderSource=c+e.shaderSource}var h=t+"_"+e._count++;if(1===G(e,t,h)&&r)throw new u("strict: shader source does not use uniform '"+t+"'.");if(e.uniforms[t]=n,"sampler2D"===o)e._uniforms[h]=function(){return e._textures[t]},e._updateFunctions.push(F(t));else if("samplerCube"===o)e._uniforms[h]=function(){return e._textures[t]},e._updateFunctions.push(B(t));else if(-1!==o.indexOf("mat")){var d=new Y[o];e._uniforms[h]=function(){return Y[o].fromColumnMajorArray(e.uniforms[t],d)}}else e._uniforms[h]=function(){return e.uniforms[t]}}}function k(e){var t=e.type;if(!a(t)){var r=typeof e;if("number"===r)t="float";else if("boolean"===r)t="bool";else if("string"===r||e instanceof HTMLCanvasElement)t=/^([rgba]){1,4}$/i.test(e)?"channels":e===H.DefaultCubeMapId?"samplerCube":"sampler2D";else if("object"===r)if(c(e))(4===e.length||9===e.length||16===e.length)&&(t="mat"+Math.sqrt(e.length));else{var i=0;for(var n in e)e.hasOwnProperty(n)&&(i+=1);i>=2&&4>=i?t="vec"+i:6===i&&(t="samplerCube")}}return t}function U(e){var t=e._strict,r=e._template.materials;for(var n in r)if(r.hasOwnProperty(n)){var o=new H({strict:t,fabric:r[n],count:e._count});e._count=o._count,e._uniforms=i(e._uniforms,o._uniforms,!0),e.materials[n]=o,e._translucentFunctions=e._translucentFunctions.concat(o._translucentFunctions);var a="czm_getMaterial",s=a+"_"+e._count++;G(o,a,s),e.shaderSource=o.shaderSource+e.shaderSource;var l=s+"(materialInput)";if(0===G(e,n,l)&&t)throw new u("strict: shader source does not use material '"+n+"'.")}}function G(e,t,r,i){i=o(i,!0);var n=0,a="([\\w])?",s="([\\w"+(i?".":"")+"])?",l=new RegExp(s+t+a,"g");return e.shaderSource=e.shaderSource.replace(l,function(e,t,i){return t||i?e:(n+=1,r)}),n}function W(e,t,r){return G(e,t,t,r)}var H=function(e){this.type=void 0,this.shaderSource=void 0,this.materials=void 0,this.uniforms=void 0,this._uniforms=void 0,this.translucent=void 0,this._strict=void 0,this._template=void 0,this._count=void 0,this._texturePaths={},this._loadedImages=[],this._loadedCubeMaps=[],this._textures={},this._updateFunctions=[],this._defaultTexture=void 0,M(e,this),s(this,{type:{value:this.type,writable:!1}}),a(H._uniformList[this.type])||(H._uniformList[this.type]=Object.keys(this._uniforms))};H._uniformList={},H.fromType=function(e,t){var r=new H({fabric:{type:e}});if(a(t))for(var i in t)t.hasOwnProperty(i)&&(r.uniforms[i]=t[i]);return r},H.prototype.isTranslucent=function(){if(a(this.translucent))return"function"==typeof this.translucent?this.translucent():this.translucent;for(var e=!0,t=this._translucentFunctions,r=t.length,i=0;r>i;++i){var n=t[i];if(e="function"==typeof n?e&&n():e&&n,!e)break}return e},H.prototype.update=function(e){var t,r,i=this._loadedImages,n=i.length;for(t=0;n>t;++t){var o=i[t];r=o.id;var a=o.image,s=new v({context:e,source:a});this._textures[r]=s;var l=r+"Dimensions";if(this.uniforms.hasOwnProperty(l)){var u=this.uniforms[l];u.x=s._width,u.y=s._height}}i.length=0;var c=this._loadedCubeMaps;for(n=c.length,t=0;n>t;++t){var h=c[t];r=h.id;var d=h.images,p=new f({context:e,source:{positiveX:d[0],negativeX:d[1],positiveY:d[2],negativeY:d[3],positiveZ:d[4],negativeZ:d[5]}});this._textures[r]=p}c.length=0;var m=this._updateFunctions;for(n=m.length,t=0;n>t;++t)m[t](this,e);var _=this.materials;for(var g in _)_.hasOwnProperty(g)&&_[g].update(e)},H.prototype.isDestroyed=function(){return!1},H.prototype.destroy=function(){var e=this._textures;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];r!==this._defaultTexture&&r.destroy()}var i=this.materials;for(var n in i)i.hasOwnProperty(n)&&i[n].destroy();return l(this)};var q=["type","materials","uniforms","components","source"],j=["diffuse","specular","shininess","normal","emission","alpha"],Y={mat2:d,mat3:p,mat4:m};return H._materialCache={_materials:{},addMaterial:function(e,t){this._materials[e]=t},getMaterial:function(e){return this._materials[e]}},H.DefaultImageId="czm_defaultImage",H.DefaultCubeMapId="czm_defaultCubeMap",H.ColorType="Color",H._materialCache.addMaterial(H.ColorType,{fabric:{type:H.ColorType,uniforms:{color:new r(1,0,0,.5)},components:{diffuse:"color.rgb",alpha:"color.a"}},translucent:function(e){return e.uniforms.color.alpha<1}}),H.ImageType="Image",H._materialCache.addMaterial(H.ImageType,{fabric:{type:H.ImageType,uniforms:{image:H.DefaultImageId,repeat:new e(1,1)},components:{diffuse:"texture2D(image, fract(repeat * materialInput.st)).rgb",alpha:"texture2D(image, fract(repeat * materialInput.st)).a"}},translucent:!0}),H.DiffuseMapType="DiffuseMap",H._materialCache.addMaterial(H.DiffuseMapType,{fabric:{type:H.DiffuseMapType,uniforms:{image:H.DefaultImageId,channels:"rgb",repeat:new e(1,1)},components:{diffuse:"texture2D(image, fract(repeat * materialInput.st)).channels"}},translucent:!1}),H.AlphaMapType="AlphaMap",H._materialCache.addMaterial(H.AlphaMapType,{fabric:{type:H.AlphaMapType,uniforms:{image:H.DefaultImageId,channel:"a",repeat:new e(1,1)},components:{alpha:"texture2D(image, fract(repeat * materialInput.st)).channel"}},translucent:!0}),H.SpecularMapType="SpecularMap",H._materialCache.addMaterial(H.SpecularMapType,{fabric:{type:H.SpecularMapType,uniforms:{image:H.DefaultImageId,channel:"r",repeat:new e(1,1)},components:{specular:"texture2D(image, fract(repeat * materialInput.st)).channel"}},translucent:!1}),H.EmissionMapType="EmissionMap",H._materialCache.addMaterial(H.EmissionMapType,{fabric:{type:H.EmissionMapType,uniforms:{image:H.DefaultImageId,channels:"rgb",repeat:new e(1,1)},components:{emission:"texture2D(image, fract(repeat * materialInput.st)).channels"}},translucent:!1}),H.BumpMapType="BumpMap",H._materialCache.addMaterial(H.BumpMapType,{fabric:{type:H.BumpMapType,uniforms:{image:H.DefaultImageId,channel:"r",strength:.8,repeat:new e(1,1)},source:_},translucent:!1}),H.NormalMapType="NormalMap",H._materialCache.addMaterial(H.NormalMapType,{fabric:{type:H.NormalMapType,uniforms:{image:H.DefaultImageId,channels:"rgb",strength:.8,repeat:new e(1,1)},source:S},translucent:!1}),H.GridType="Grid",H._materialCache.addMaterial(H.GridType,{fabric:{type:H.GridType,uniforms:{color:new r(0,1,0,1),cellAlpha:.1,lineCount:new e(8,8),lineThickness:new e(1,1),lineOffset:new e(0,0)},source:E},translucent:function(e){var t=e.uniforms;return t.color.alpha<1||t.cellAlpha<1}}),H.StripeType="Stripe",H._materialCache.addMaterial(H.StripeType,{fabric:{type:H.StripeType,uniforms:{horizontal:!0,evenColor:new r(1,1,1,.5),oddColor:new r(0,0,1,.5),offset:0,repeat:5},source:P},translucent:function(e){var t=e.uniforms;return t.evenColor.alpha<1||t.oddColor.alpha<0}}),H.CheckerboardType="Checkerboard",H._materialCache.addMaterial(H.CheckerboardType,{fabric:{type:H.CheckerboardType,uniforms:{lightColor:new r(1,1,1,.5),darkColor:new r(0,0,0,.5),repeat:new e(5,5)},source:g},translucent:function(e){var t=e.uniforms;return t.lightColor.alpha<1||t.darkColor.alpha<0}}),H.DotType="Dot",H._materialCache.addMaterial(H.DotType,{fabric:{type:H.DotType,uniforms:{lightColor:new r(1,1,0,.75),darkColor:new r(0,1,1,.75),repeat:new e(5,5)},source:y},translucent:function(e){var t=e.uniforms;return t.lightColor.alpha<1||t.darkColor.alpha<0}}),H.WaterType="Water",H._materialCache.addMaterial(H.WaterType,{fabric:{type:H.WaterType,uniforms:{baseWaterColor:new r(.2,.3,.6,1),blendColor:new r(0,1,.699,1),specularMap:H.DefaultImageId,normalMap:H.DefaultImageId,frequency:10,animationSpeed:.01,amplitude:1,specularIntensity:.5,fadeFactor:1},source:A},translucent:function(e){var t=e.uniforms;return t.baseWaterColor.alpha<1||t.blendColor.alpha<0}}),H.RimLightingType="RimLighting",H._materialCache.addMaterial(H.RimLightingType,{fabric:{type:H.RimLightingType,uniforms:{color:new r(1,0,0,.7),rimColor:new r(1,1,1,.4),width:.3},source:x},translucent:function(e){var t=e.uniforms;return t.color.alpha<1||t.rimColor.alpha<0}}),H.FadeType="Fade",H._materialCache.addMaterial(H.FadeType,{fabric:{type:H.FadeType,uniforms:{fadeInColor:new r(1,0,0,1),fadeOutColor:new r(0,0,0,0),maximumDistance:.5,repeat:!0,fadeDirection:{x:!0,y:!0},time:new e(.5,.5)},source:C},translucent:function(e){var t=e.uniforms;return t.fadeInColor.alpha<1||t.fadeOutColor.alpha<0}}),H.PolylineArrowType="PolylineArrow",H._materialCache.addMaterial(H.PolylineArrowType,{fabric:{type:H.PolylineArrowType,uniforms:{color:new r(1,1,1,1)},source:w},translucent:!0}),H.PolylineGlowType="PolylineGlow",H._materialCache.addMaterial(H.PolylineGlowType,{fabric:{type:H.PolylineGlowType,uniforms:{color:new r(0,.5,1,1),glowPower:.25},source:T},translucent:!0}),H.PolylineOutlineType="PolylineOutline",H._materialCache.addMaterial(H.PolylineOutlineType,{fabric:{type:H.PolylineOutlineType,uniforms:{color:new r(1,1,1,1),outlineColor:new r(1,0,0,1),outlineWidth:1},source:b},translucent:function(e){var t=e.uniforms;return t.color.alpha<1||t.outlineColor.alpha<1}}),H}),r("Scene/MaterialAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/freezeObject","../Core/VertexFormat","../Shaders/Appearances/AllMaterialAppearanceFS","../Shaders/Appearances/AllMaterialAppearanceVS","../Shaders/Appearances/BasicMaterialAppearanceFS","../Shaders/Appearances/BasicMaterialAppearanceVS","../Shaders/Appearances/TexturedMaterialAppearanceFS","../Shaders/Appearances/TexturedMaterialAppearanceVS","./Appearance","./Material"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";var p=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.translucent,!0),n=e(r.closed,!1),o=e(r.materialSupport,p.MaterialSupport.TEXTURED);this.material=t(r.material)?r.material:d.fromType(d.ColorType),this.translucent=i,this._vertexShaderSource=e(r.vertexShaderSource,o.vertexShaderSource),this._fragmentShaderSource=e(r.fragmentShaderSource,o.fragmentShaderSource),this._renderState=h.getDefaultRenderState(i,n,r.renderState),this._closed=n,this._materialSupport=o,this._vertexFormat=o.vertexFormat,this._flat=e(r.flat,!1),this._faceForward=e(r.faceForward,!n)};return r(p.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},materialSupport:{get:function(){return this._materialSupport}},vertexFormat:{get:function(){return this._vertexFormat}},flat:{get:function(){return this._flat}},faceForward:{get:function(){return this._faceForward}}}),p.prototype.getFragmentShaderSource=h.prototype.getFragmentShaderSource,p.prototype.isTranslucent=h.prototype.isTranslucent,p.prototype.getRenderState=h.prototype.getRenderState,p.MaterialSupport={BASIC:i({vertexFormat:n.POSITION_AND_NORMAL,vertexShaderSource:l,fragmentShaderSource:s}),TEXTURED:i({vertexFormat:n.POSITION_NORMAL_AND_ST,vertexShaderSource:c,fragmentShaderSource:u}),ALL:i({vertexFormat:n.ALL,vertexShaderSource:a,fragmentShaderSource:o})},p}),r("Shaders/Appearances/PerInstanceColorAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec4 v_color;\nvoid main()\n{\nvec3 positionToEyeEC = -v_positionEC;\nvec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nczm_materialInput materialInput;\nmaterialInput.normalEC = normalEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getDefaultMaterial(materialInput);\nmaterial.diffuse = v_color.rgb;\nmaterial.alpha = v_color.a;\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n}\n"}),r("Shaders/Appearances/PerInstanceColorAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 normal;\nattribute vec4 color;\nvarying vec3 v_positionEC;\nvarying vec3 v_normalEC;\nvarying vec4 v_color;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_normalEC = czm_normal * normal;\nv_color = color;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Shaders/Appearances/PerInstanceFlatColorAppearanceFS",[],function(){"use strict";return"varying vec4 v_color;\nvoid main()\n{\ngl_FragColor = v_color;\n}\n"}),r("Shaders/Appearances/PerInstanceFlatColorAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec4 color;\nvarying vec4 v_color;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_color = color;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Scene/PerInstanceColorAppearance",["../Core/defaultValue","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/PerInstanceColorAppearanceFS","../Shaders/Appearances/PerInstanceColorAppearanceVS","../Shaders/Appearances/PerInstanceFlatColorAppearanceFS","../Shaders/Appearances/PerInstanceFlatColorAppearanceVS","./Appearance"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){t=e(t,e.EMPTY_OBJECT);var r=e(t.translucent,!0),u=e(t.closed,!1),c=e(t.flat,!1),h=c?a:n,d=c?o:i,p=c?l.FLAT_VERTEX_FORMAT:l.VERTEX_FORMAT;this.material=void 0,this.translucent=r,this._vertexShaderSource=e(t.vertexShaderSource,h),this._fragmentShaderSource=e(t.fragmentShaderSource,d),this._renderState=s.getDefaultRenderState(r,u,t.renderState),this._closed=u,this._vertexFormat=p,this._flat=c,this._faceForward=e(t.faceForward,!u)};return t(l.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return this._vertexFormat}},flat:{get:function(){return this._flat}},faceForward:{get:function(){return this._faceForward}}}),l.VERTEX_FORMAT=r.POSITION_AND_NORMAL,l.FLAT_VERTEX_FORMAT=r.POSITION_ONLY,l.prototype.getFragmentShaderSource=s.prototype.getFragmentShaderSource,l.prototype.isTranslucent=s.prototype.isTranslucent,l.prototype.getRenderState=s.prototype.getRenderState,l}),r("Scene/PrimitivePipeline",["../Core/BoundingSphere","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/Ellipsoid","../Core/FeatureDetection","../Core/GeographicProjection","../Core/Geometry","../Core/GeometryAttribute","../Core/GeometryAttributes","../Core/GeometryPipeline","../Core/IndexDatatype","../Core/Matrix4","../Core/WebMercatorProjection"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(e,t,r){var i,n=!r,o=e.length;if(!n&&o>1){var a=e[0].modelMatrix;for(i=1;o>i;++i)if(!m.equals(a,e[i].modelMatrix)){n=!0;break}}if(n)for(i=0;o>i;++i)d.transformToWorldCoordinates(e[i]);else m.multiplyTransformation(t,e[0].modelMatrix,t)}function _(e,i){var n=e.attributes,o=n.position,a=4*(o.values.length/o.componentsPerAttribute);n.pickColor=new c({componentDatatype:r.UNSIGNED_BYTE,componentsPerAttribute:4,normalize:!0,values:new Uint8Array(a)});for(var s=t.floatToByte(i.red),l=t.floatToByte(i.green),u=t.floatToByte(i.blue),h=t.floatToByte(i.alpha),d=n.pickColor.values,p=0;a>p;p+=4)d[p]=s,d[p+1]=l,d[p+2]=u,d[p+3]=h}function g(e,t){for(var r=e.length,i=0;r>i;++i){var o=e[i],a=t[i];n(o.geometry)?_(o.geometry,a):(_(o.westHemisphereGeometry,a),_(o.eastHemisphereGeometry,a))}}function y(e){var t,r=e.length,i=[],o=e[0].attributes;for(t in o)if(o.hasOwnProperty(t)){for(var a=o[t],s=!0,l=1;r>l;++l){var u=e[l].attributes[t];if(!n(u)||a.componentDatatype!==u.componentDatatype||a.componentsPerAttribute!==u.componentsPerAttribute||a.normalize!==u.normalize){s=!1;break}}s&&i.push(t)}return i}function C(e,t,i){for(var n=u.computeNumberOfVertices(t),o=i.length,a=0;o>a;++a){for(var s=i[a],l=e[s],h=l.componentDatatype,d=l.value,p=d.length,m=r.createTypedArray(h,n*p),f=0;n>f;++f)m.set(d,f*p);t.attributes[s]=new c({componentDatatype:h,componentsPerAttribute:p,normalize:l.normalize,values:m})}}function E(e,t){for(var r=e.length,i=0;r>i;++i){var o=e[i],a=o.attributes;n(o.geometry)?C(a,o.geometry,t):(C(a,o.westHemisphereGeometry,t),C(a,o.eastHemisphereGeometry,t))}}function S(t){var i,o,a=t.instances,s=t.pickIds,l=t.projection,u=t.elementIndexUintSupported,c=t.scene3DOnly,h=t.allowPicking,p=t.vertexCacheOptimize,m=t.compressVertices,f=t.modelMatrix,_=a.length;a[0].geometry.primitiveType;if(v(a,f,c),!c)for(i=0;_>i;++i)d.splitLongitude(a[i]);h&&g(a,s);var C=y(a);if(E(a,C),p)for(i=0;_>i;++i){var S=a[i];n(S.geometry)?(d.reorderForPostVertexCache(S.geometry),d.reorderForPreVertexCache(S.geometry)):(d.reorderForPostVertexCache(S.westHemisphereGeometry),d.reorderForPreVertexCache(S.westHemisphereGeometry),d.reorderForPostVertexCache(S.eastHemisphereGeometry),d.reorderForPreVertexCache(S.eastHemisphereGeometry))}var w=d.combineInstances(a);for(_=w.length,i=0;_>i;++i){o=w[i];var T,b=o.attributes;if(c)for(T in b)b.hasOwnProperty(T)&&b[T].componentDatatype===r.DOUBLE&&d.encodeAttribute(o,T,T+"3DHigh",T+"3DLow");else for(T in b)if(b.hasOwnProperty(T)&&b[T].componentDatatype===r.DOUBLE){var x=T+"3D",P=T+"2D";d.projectTo2D(o,T,x,P,l),n(o.boundingSphere)&&"position"===T&&(o.boundingSphereCV=e.fromVertices(o.attributes.position2D.values)),d.encodeAttribute(o,x,x+"High",x+"Low"),d.encodeAttribute(o,P,P+"High",P+"Low")}m&&d.compressVertices(o)}if(!u){var A=[];for(_=w.length,i=0;_>i;++i)o=w[i],A=A.concat(d.fitToUnsignedShortIndices(o));w=A}return w}function w(e,t,i){for(var n=[],o=e.attributes,a=i.length,s=0;a>s;++s){var l=i[s],u=o[l],c=u.componentDatatype;c===r.DOUBLE&&(c=r.FLOAT);var h=r.createTypedArray(c,u.values);n.push({index:t[l],componentDatatype:c,componentsPerAttribute:u.componentsPerAttribute,normalize:u.normalize,values:h}),delete o[l]}return n}function T(e,t,r,o,a,s,l,c,h){var d=u.computeNumberOfVertices(t);n(l[e])||(l[e]={boundingSphere:t.boundingSphere,boundingSphereCV:t.boundingSphereCV});for(var p=o.length,m=0;p>m;++m)for(var f=o[m],v=a[f],_=d;_>0;){for(var g,y=i(h[f],0),C=s[y],E=C.length,S=0;E>S&&(g=C[S],g.index!==v);++S);n(l[e][f])||(l[e][f]={dirty:!1,valid:!0,value:r[f].value,indices:[]});var w,T=g.values.length/g.componentsPerAttribute,b=i(c[f],0);T>b+_?(w=_,l[e][f].indices.push({attribute:g,offset:b,count:w}),c[f]=b+_):(w=T-b,l[e][f].indices.push({attribute:g,offset:b,count:w}),c[f]=0,h[f]=y+1),_-=w}}function b(e,t,r,i,o){var a,s,l,u=[],c=e.length,h={},d={};for(a=0;c>a;++a)s=e[a],l=s.attributes,n(s.geometry)&&T(a,s.geometry,l,o,i,r,u,h,d); -for(a=0;c>a;++a)s=e[a],l=s.attributes,n(s.westHemisphereGeometry)&&T(a,s.westHemisphereGeometry,l,o,i,r,u,h,d);for(a=0;c>a;++a)s=e[a],l=s.attributes,n(s.eastHemisphereGeometry)&&T(a,s.eastHemisphereGeometry,l,o,i,r,u,h,d);for(c=t.length,a=0;c>a;++a){s=t[a],l=s.attributes;var p={};u.push(p);for(var m=o.length,f=0;m>f;++f){var v=o[f];p[v]={dirty:!1,valid:!1,value:l[v].value,indices:[]}}}return u}function x(e,t){var r=e.attributes;for(var i in r)if(r.hasOwnProperty(i)){var o=r[i];n(o)&&n(o.values)&&t.push(o.values.buffer)}n(e.indices)&&t.push(e.indices.buffer)}function P(e,t){for(var r=e.length,i=0;r>i;++i)x(e[i],t)}function A(e,t){for(var r=e.length,i=0;r>i;++i)for(var n=e[i],o=n.length,a=0;o>a;++a)t.push(n[a].values.buffer)}function I(t){for(var r=1,i=t.length,o=0;i>o;o++){var a=t[o];if(++r,n(a)){var s=a.attributes;r+=6+2*e.packedLength+(n(a.indices)?a.indices.length:0);for(var l in s)if(s.hasOwnProperty(l)&&n(s[l])){var u=s[l];r+=5+u.values.length}}}return r}function M(e,t){for(var r=e.length,i=new Uint32Array(e.length),n=0;r>n;++n)i[n]=e[n].toRgba();return t.push(i.buffer),i}function D(e){for(var r=e.length,i=new Array(r),n=0;r>n;n++)i[n]=t.fromRgba(e[n]);return i}function R(e){for(var t=e.length,r=1+17*t,i=0;t>i;i++){var o=e[i].attributes;for(var a in o)if(o.hasOwnProperty(a)&&n(o[a])){var s=o[a];r+=5+s.value.length}}return r}function O(e,t){var r=new Float64Array(R(e)),i={},o=[],a=e.length,s=0;r[s++]=a;for(var l=0;a>l;l++){var u=e[l];m.pack(u.modelMatrix,r,s),s+=m.packedLength;var c=u.attributes,h=[];for(var d in c)c.hasOwnProperty(d)&&n(c[d])&&(h.push(d),n(i[d])||(i[d]=o.length,o.push(d)));r[s++]=h.length;for(var p=0;p<h.length;p++){var f=h[p],v=c[f];r[s++]=i[f],r[s++]=v.componentDatatype,r[s++]=v.componentsPerAttribute,r[s++]=v.normalize,r[s++]=v.value.length,r.set(v.value,s),s+=v.value.length}}return t.push(r.buffer),{stringTable:o,packedData:r}}function N(e){for(var t=e.packedData,i=e.stringTable,n=new Array(t[0]),o=0,a=1;a<t.length;){var s=m.unpack(t,a);a+=m.packedLength;for(var l={},u=t[a++],c=0;u>c;c++){for(var h=i[t[a++]],d=t[a++],p=t[a++],f=0!==t[a++],v=t[a++],_=r.createTypedArray(d,v),g=0;v>g;g++)_[g]=t[a++];l[h]={componentDatatype:d,componentsPerAttribute:p,normalize:f,value:_}}n[o++]={attributes:l,modelMatrix:s}}return n}function L(t){for(var r=t.length,i=1+r,o=0;r>o;o++){var a=t[o];i+=2,i+=n(a.boundingSphere)?e.packedLength:0,i+=n(a.boundingSphereCV)?e.packedLength:0;for(var s in a)if(a.hasOwnProperty(s)&&n(a[s])&&"boundingSphere"!==s&&"boundingSphereCV"!==s){var l=a[s];i+=4+3*l.indices.length+l.value.length}}return i}function F(t,r){var i=new Float64Array(L(t)),o=[],a=[],s={},l=t.length,u=0;i[u++]=l;for(var c=0;l>c;c++){var h=t[c],d=h.boundingSphere,p=n(d);i[u++]=p?1:0,p&&(e.pack(d,i,u),u+=e.packedLength),d=h.boundingSphereCV,p=n(d),i[u++]=p?1:0,p&&(e.pack(d,i,u),u+=e.packedLength);var m=[];for(var f in h)h.hasOwnProperty(f)&&n(h[f])&&"boundingSphere"!==f&&"boundingSphereCV"!==f&&(m.push(f),n(s[f])||(s[f]=o.length,o.push(f)));i[u++]=m.length;for(var v=0;v<m.length;v++){var _=m[v],g=h[_];i[u++]=s[_],i[u++]=g.valid?1:0;var y=g.indices,C=y.length;i[u++]=C;for(var E=0;C>E;E++){var S=y[E];i[u++]=S.count,i[u++]=S.offset;var w=a.indexOf(S.attribute);-1===w&&(w=a.length,a.push(S.attribute)),i[u++]=w}i[u++]=g.value.length,i.set(g.value,u),u+=g.value.length}}return r.push(i.buffer),{stringTable:o,packedData:i,attributeTable:a}}function B(t,i){for(var n=t.stringTable,o=t.attributeTable,a=t.packedData,s=new Array(a[0]),l=0,u=1,c=a.length;c>u;){var h={},d=1===a[u++];d&&(h.boundingSphere=e.unpack(a,u),u+=e.packedLength),d=1===a[u++],d&&(h.boundingSphereCV=e.unpack(a,u),u+=e.packedLength);for(var p=a[u++],m=0;p>m;m++){for(var f=n[a[u++]],v=1===a[u++],_=a[u++],g=_>0?new Array(_):void 0,y=0;_>y;y++){var C={};C.count=a[u++],C.offset=a[u++],C.attribute=o[a[u++]],g[y]=C}for(var E=a[u++],S=v?r.createTypedArray(g[0].attribute.componentDatatype,E):new Array(E),w=0;E>w;w++)S[w]=a[u++];h[f]={dirty:!1,valid:v,indices:g,value:S}}s[l++]=h}return s}if(!s.supportsTypedArrays())return{};var V={};return V.combineGeometry=function(e){var t,r,i,o,a,s=e.instances,l=e.invalidInstances;if(s.length>0){t=S(e),r=d.createAttributeLocations(t[0]),o=y(s),i=[],a=t.length;for(var u=0;a>u;++u){var c=t[u];i.push(w(c,r,o))}}o=n(o)?o:y(l);var h=b(s,l,i,r,o);return{geometries:t,modelMatrix:e.modelMatrix,attributeLocations:r,vaAttributes:i,vaAttributeLocations:h,validInstancesIndices:e.validInstancesIndices,invalidInstancesIndices:e.invalidInstancesIndices}},V.packCreateGeometryResults=function(t,r){var i=new Float64Array(I(t)),o=[],a={},s=t.length,l=0;i[l++]=s;for(var u=0;s>u;u++){var c=t[u],h=n(c);if(i[l++]=h?1:0,h){i[l++]=c.primitiveType,i[l++]=c.geometryType;var d=n(c.boundingSphere)?1:0;i[l++]=d,d&&e.pack(c.boundingSphere,i,l),l+=e.packedLength;var p=n(c.boundingSphereCV)?1:0;i[l++]=p,p&&e.pack(c.boundingSphereCV,i,l),l+=e.packedLength;var m=c.attributes,f=[];for(var v in m)m.hasOwnProperty(v)&&n(m[v])&&(f.push(v),n(a[v])||(a[v]=o.length,o.push(v)));i[l++]=f.length;for(var _=0;_<f.length;_++){var g=f[_],y=m[g];i[l++]=a[g],i[l++]=y.componentDatatype,i[l++]=y.componentsPerAttribute,i[l++]=y.normalize?1:0,i[l++]=y.values.length,i.set(y.values,l),l+=y.values.length}var C=n(c.indices)?c.indices.length:0;i[l++]=C,C>0&&(i.set(c.indices,l),l+=C)}}return r.push(i.buffer),{stringTable:o,packedData:i}},V.unpackCreateGeometryResults=function(t){for(var i,n=t.stringTable,o=t.packedData,a=new Array(o[0]),s=0,l=1;l<o.length;){var d=1===o[l++];if(d){var m,f,v=o[l++],_=o[l++],g=1===o[l++];g&&(m=e.unpack(o,l)),l+=e.packedLength;var y=1===o[l++];y&&(f=e.unpack(o,l)),l+=e.packedLength;var C,E,S,w=new h,T=o[l++];for(i=0;T>i;i++){var b=n[o[l++]],x=o[l++];S=o[l++];var P=0!==o[l++];C=o[l++],E=r.createTypedArray(x,C);for(var A=0;C>A;A++)E[A]=o[l++];w[b]=new c({componentDatatype:x,componentsPerAttribute:S,normalize:P,values:E})}var I;if(C=o[l++],C>0){var M=E.length/S;for(I=p.createTypedArray(M,C),i=0;C>i;i++)I[i]=o[l++]}a[s++]=new u({primitiveType:v,geometryType:_,boundingSphere:m,indices:I,attributes:w})}else a[s++]=void 0}return a},V.packCombineGeometryParameters=function(e,t){for(var r=e.createGeometryResults,i=r.length,n=0;i>n;n++)t.push(r[n].packedData.buffer);var o;return e.allowPicking&&(o=M(e.pickIds,t)),{createGeometryResults:e.createGeometryResults,packedInstances:O(e.instances,t),packedPickIds:o,ellipsoid:e.ellipsoid,isGeographic:e.projection instanceof l,elementIndexUintSupported:e.elementIndexUintSupported,scene3DOnly:e.scene3DOnly,allowPicking:e.allowPicking,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:e.modelMatrix}},V.unpackCombineGeometryParameters=function(e){for(var t=N(e.packedInstances),r=e.allowPicking,i=r?D(e.packedPickIds):void 0,o=e.createGeometryResults,s=o.length,u=0,c=[],h=[],d=[],p=[],v=[],_=0;s>_;_++)for(var g=V.unpackCreateGeometryResults(o[_]),y=g.length,C=0;y>C;C++){var E=g[C],S=t[u];n(E)?(S.geometry=E,c.push(S),d.push(u),r&&v.push(i[u])):(h.push(S),p.push(u)),++u}var w=a.clone(e.ellipsoid),T=e.isGeographic?new l(w):new f(w);return{instances:c,invalidInstances:h,validInstancesIndices:d,invalidInstancesIndices:p,pickIds:v,ellipsoid:w,projection:T,elementIndexUintSupported:e.elementIndexUintSupported,scene3DOnly:e.scene3DOnly,allowPicking:e.allowPicking,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:m.clone(e.modelMatrix)}},V.packCombineGeometryResults=function(e,t){return n(e.geometries)&&(P(e.geometries,t),A(e.vaAttributes,t)),{geometries:e.geometries,attributeLocations:e.attributeLocations,vaAttributes:e.vaAttributes,packedVaAttributeLocations:F(e.vaAttributeLocations,t),modelMatrix:e.modelMatrix,validInstancesIndices:e.validInstancesIndices,invalidInstancesIndices:e.invalidInstancesIndices}},V.unpackCombineGeometryResults=function(e){return{geometries:e.geometries,attributeLocations:e.attributeLocations,vaAttributes:e.vaAttributes,perInstanceAttributeLocations:B(e.packedVaAttributeLocations,e.vaAttributes),modelMatrix:e.modelMatrix}},V}),r("Scene/PrimitiveState",["../Core/freezeObject"],function(e){"use strict";var t={READY:0,CREATING:1,CREATED:2,COMBINING:3,COMBINED:4,COMPLETE:5,FAILED:6};return e(t)}),r("Scene/Primitive",["../Core/BoundingSphere","../Core/Cartesian3","../Core/clone","../Core/combine","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/FeatureDetection","../Core/Geometry","../Core/GeometryAttribute","../Core/GeometryAttributes","../Core/GeometryInstance","../Core/GeometryInstanceAttribute","../Core/isArray","../Core/Matrix4","../Core/subdivideArray","../Core/TaskProcessor","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../ThirdParty/when","./CullFace","./Pass","./PrimitivePipeline","./PrimitiveState","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R){"use strict";function O(e){return new d({componentDatatype:e.componentDatatype,componentsPerAttribute:e.componentsPerAttribute,normalize:e.normalize,values:new e.values.constructor(e.values)})}function N(t){var r=t.attributes,i=new p;for(var n in r)r.hasOwnProperty(n)&&a(r[n])&&(i[n]=O(r[n]));var o;if(a(t.indices)){var s=t.indices;o=new s.constructor(s)}return new h({attributes:i,indices:o,primitiveType:t.primitiveType,boundingSphere:e.clone(t.boundingSphere)})}function L(e){return new f({componentDatatype:e.componentDatatype,componentsPerAttribute:e.componentsPerAttribute,normalize:e.normalize,value:new e.value.constructor(e.value)})}function F(e,t){var r=e.attributes,i={};for(var n in r)r.hasOwnProperty(n)&&(i[n]=L(r[n]));return new m({geometry:t,modelMatrix:_.clone(e.modelMatrix),attributes:i,pickPrimitive:e.pickPrimitive,id:e.id})}function B(e,t){if(!e.compressVertices)return t;var r=-1!==t.search(/attribute\s+vec3\s+normal;/g),i=-1!==t.search(/attribute\s+vec2\s+st;/g);if(!r&&!i)return t;var n=-1!==t.search(/attribute\s+vec3\s+tangent;/g),o=-1!==t.search(/attribute\s+vec3\s+binormal;/g),a=i&&r?2:1;a+=n||o?1:0;var s=a>1?"vec"+a:"float",l="compressedAttributes",u="attribute "+s+" "+l+";",c="",h="";if(i){c+="vec2 st;\n";var d=a>1?l+".x":l;h+=" st = czm_decompressTextureCoordinates("+d+");\n"}r&&n&&o?(c+="vec3 normal;\nvec3 tangent;\nvec3 binormal;\n",h+=" czm_octDecode("+l+"."+(i?"yz":"xy")+", normal, tangent, binormal);\n"):(r&&(c+="vec3 normal;\n",h+=" normal = czm_octDecode("+l+(a>1?"."+(i?"y":"x"):"")+");\n"),n&&(c+="vec3 tangent;\n",h+=" tangent = czm_octDecode("+l+"."+(i&&r?"z":"y")+");\n"),o&&(c+="vec3 binormal;\n",h+=" binormal = czm_octDecode("+l+"."+(i&&r?"z":"y")+");\n"));var p=t;p=p.replace(/attribute\s+vec3\s+normal;/g,""),p=p.replace(/attribute\s+vec2\s+st;/g,""),p=p.replace(/attribute\s+vec3\s+tangent;/g,""),p=p.replace(/attribute\s+vec3\s+binormal;/g,""),p=b.replaceMain(p,"czm_non_compressed_main");var m="void main() \n{ \n"+h+" czm_non_compressed_main(); \n}";return[u,c,p,m].join("\n")}function V(e,t){e.vertexAttributes}function z(e,t,r){for(var i=[],n=r.length,s=0;n>s;++s){var l={primitive:o(r[s].pickPrimitive,t)};a(r[s].id)&&(l.id=r[s].id);var u=e.createPickId(l);t._pickIds.push(u),i.push(u.color)}return i}function k(e,t){return function(){return e[t]}}function U(e,t){var r,i,n,s,l=e._instanceIds;if(e._state===D.READY){r=v(e.geometryInstances)?e.geometryInstances:[e.geometryInstances];var u=e._numberOfInstances=r.length,c=[],h=[];for(n=0;u>n;++n)i=r[n].geometry,l.push(r[n].id),h.push({moduleName:i._workerName,geometry:i});if(!a(ee))for(ee=new Array(te),n=0;te>n;n++)ee[n]=new y("createGeometry",Number.POSITIVE_INFINITY);var d;for(h=g(h,te),n=0;n<h.length;n++){var p=0,m=h[n],f=m.length;for(s=0;f>s;++s)d=m[s],i=d.geometry,a(i.constructor.pack)&&(d.offset=p,p+=o(i.constructor.packedLength,i.packedLength));var C;if(p>0){var E=new Float64Array(p);for(C=[E.buffer],s=0;f>s;++s)d=m[s],i=d.geometry,a(i.constructor.pack)&&(i.constructor.pack(i,E,d.offset),d.geometry=E)}c.push(ee[n].scheduleTask({subTasks:h[n]},C))}e._state=D.CREATING,P.all(c,function(t){e._createGeometryResults=t,e._state=D.CREATED}).otherwise(function(r){J(e,t,D.FAILED,r)})}else if(e._state===D.CREATED){var S=[];r=v(e.geometryInstances)?e.geometryInstances:[e.geometryInstances];var w=e.allowPicking,T=t.scene3DOnly,b=t.mapProjection,x=re.scheduleTask(M.packCombineGeometryParameters({createGeometryResults:e._createGeometryResults,instances:r,pickIds:w?z(t.context,e,r):void 0,ellipsoid:b.ellipsoid,projection:b,elementIndexUintSupported:t.context.elementIndexUint,scene3DOnly:T,allowPicking:w,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:e.modelMatrix},S),S);e._createGeometryResults=void 0,e._state=D.COMBINING,P(x,function(r){var i=M.unpackCombineGeometryResults(r);e._geometries=i.geometries,e._attributeLocations=i.attributeLocations,e._vaAttributes=i.vaAttributes,e._perInstanceAttributeLocations=i.perInstanceAttributeLocations,e.modelMatrix=_.clone(i.modelMatrix,e.modelMatrix),e._validModelMatrix=!_.equals(e.modelMatrix,_.IDENTITY);for(var n=r.validInstancesIndices,o=r.invalidInstancesIndices,s=e._instanceIds,l=new Array(s.length),u=n.length,c=0;u>c;++c)l[c]=s[n[c]];for(var h=o.length,d=0;h>d;++d)l[u+d]=s[o[d]];e._instanceIds=l,a(e._geometries)?e._state=D.COMBINED:J(e,t,D.FAILED,void 0)}).otherwise(function(r){J(e,t,D.FAILED,r)})}}function G(e,t){var r,i,n=v(e.geometryInstances)?e.geometryInstances:[e.geometryInstances],o=e._numberOfInstances=n.length,s=new Array(o),l=new Array(o),u=[],c=e._instanceIds,h=0;for(i=0;o>i;i++){r=n[i];var d,p=r.geometry;d=a(p.attributes)&&a(p.primitiveType)?N(p):p.constructor.createGeometry(p),a(d)?(s[h]=d,l[h++]=F(r,d),c.push(r.id)):u.push(r)}s.length=h,l.length=h;var m=e.allowPicking,f=t.scene3DOnly,g=t.mapProjection,y=M.combineGeometry({instances:l,invalidInstances:u,pickIds:m?z(t.context,e,l):void 0,ellipsoid:g.ellipsoid,projection:g,elementIndexUintSupported:t.context.elementIndexUint,scene3DOnly:f,allowPicking:m,vertexCacheOptimize:e.vertexCacheOptimize,compressVertices:e.compressVertices,modelMatrix:e.modelMatrix});for(e._geometries=y.geometries,e._attributeLocations=y.attributeLocations,e._vaAttributes=y.vaAttributes,e._perInstanceAttributeLocations=y.vaAttributeLocations,e.modelMatrix=_.clone(y.modelMatrix,e.modelMatrix),e._validModelMatrix=!_.equals(e.modelMatrix,_.IDENTITY),i=0;i<u.length;++i)r=u[i],c.push(r.id);a(e._geometries)?e._state=D.COMBINED:J(e,t,D.FAILED,void 0)}function W(t,r){for(var i=t._attributeLocations,n=t._geometries,o=t._vaAttributes,s=r.scene3DOnly,l=r.context,u=[],c=n.length,h=0;c>h;++h){for(var d=n[h],p=o[h],m=p.length,f=0;m>f;++f){var v=p[f];v.vertexBuffer=C.createVertexBuffer({context:l,typedArray:v.values,usage:E.DYNAMIC_DRAW}),delete v.values}if(u.push(x.fromGeometry({context:l,geometry:d,attributeLocations:i,bufferUsage:E.STATIC_DRAW,interleave:t._interleave,vertexArrayAttributes:p})),a(t._createBoundingVolumeFunction))t._createBoundingVolumeFunction(r,d);else if(t._boundingSpheres.push(e.clone(d.boundingSphere)),t._boundingSphereWC.push(new e),!s){var _=d.boundingSphereCV.center,g=_.x,y=_.y,S=_.z;_.x=S,_.y=g,_.z=y,t._boundingSphereCV.push(e.clone(d.boundingSphereCV)),t._boundingSphere2D.push(new e),t._boundingSphereMorph.push(new e)}}t._va=u,t._primitiveType=n[0].primitiveType,t.releaseGeometryInstances&&(t.geometryInstances=void 0),t._geometries=void 0,J(t,r,D.COMPLETE,void 0)}function H(e,t,i,n){var o,a=i.getRenderState();n?(o=r(a,!1),o.cull={enabled:!0,face:A.BACK},e._frontFaceRS=w.fromCache(o),o.cull.face=A.FRONT,e._backFaceRS=w.fromCache(o)):(e._frontFaceRS=w.fromCache(a),e._backFaceRS=e._frontFaceRS),e.allowPicking?n?(o=r(a,!1),o.cull={enabled:!1},e._pickRS=w.fromCache(o)):e._pickRS=e._frontFaceRS:(o=r(a,!1),o.colorMask={red:!1,green:!1,blue:!1,alpha:!1},n?(o.cull={enabled:!1},e._pickRS=w.fromCache(o)):e._pickRS=w.fromCache(o))}function q(e,t,r){var i=t.context,n=Q._modifyShaderPosition(e,r.vertexShaderSource,t.scene3DOnly);n=Q._appendShowToShader(e,n),n=B(e,n);var o=r.getFragmentShaderSource(),a=e._attributeLocations;if(e._sp=T.replaceCache({context:i,shaderProgram:e._sp,vertexShaderSource:n,fragmentShaderSource:o,attributeLocations:a}),V(e._sp,a),e.allowPicking){var s=new b({sources:[o],pickColorQualifier:"varying"});e._pickSP=T.replaceCache({context:i,shaderProgram:e._pickSP,vertexShaderSource:b.createPickVertexShaderSource(n),fragmentShaderSource:s,attributeLocations:a})}else e._pickSP=T.fromCache({context:i,vertexShaderSource:n,fragmentShaderSource:o,attributeLocations:a});V(e._pickSP,a)}function j(e,t,r,n,o,s,l){var c=a(r)?r._uniforms:void 0,h={},d=t.uniforms;if(a(d))for(var p in d)if(d.hasOwnProperty(p)){if(a(c)&&a(c[p]))throw new u("Appearance and material have a uniform with the same name: "+p);h[p]=k(d,p)}var m=i(h,c);a(e.rtcCenter)&&(m.u_modifiedModelView=function(){return e._modifiedModelView});var f=n?I.TRANSLUCENT:I.OPAQUE;s.length=e._va.length*(o?2:1),l.length=e._va.length;for(var v=s.length,_=0,g=0,y=0;v>y;++y){var C;o&&(C=s[y],a(C)||(C=s[y]=new S({owner:e,primitiveType:e._primitiveType})),C.vertexArray=e._va[g],C.renderState=e._backFaceRS,C.shaderProgram=e._sp,C.uniformMap=m,C.pass=f,++y),C=s[y],a(C)||(C=s[y]=new S({owner:e,primitiveType:e._primitiveType})),C.vertexArray=e._va[g],C.renderState=e._frontFaceRS,C.shaderProgram=e._sp,C.uniformMap=m,C.pass=f;var E=l[_];a(E)||(E=l[_]=new S({owner:e,primitiveType:e._primitiveType})),E.vertexArray=e._va[g],E.renderState=e._pickRS,E.shaderProgram=e._pickSP,E.uniformMap=m,E.pass=f,++_,++g}}function Y(e){if(0!==e._dirtyAttributes.length){for(var t=e._dirtyAttributes,r=t.length,i=0;r>i;++i){for(var o=t[i],a=o.value,s=o.indices,l=s.length,u=0;l>u;++u){for(var c=s[u],h=c.offset,d=c.count,p=c.attribute,m=p.componentDatatype,f=p.componentsPerAttribute,v=n.createTypedArray(m,d*f),_=0;d>_;++_)v.set(a,_*f);var g=h*f*n.getSizeInBytes(m);p.vertexBuffer.copyFromArrayView(v,g)}o.dirty=!1}t.length=0}}function X(t,r,i,n,o,s,l,u){if(!_.equals(o,t._modelMatrix)){_.clone(o,t._modelMatrix);for(var c=t._boundingSpheres.length,h=0;c>h;++h){var d=t._boundingSpheres[h];a(d)&&(t._boundingSphereWC[h]=e.transform(d,o,t._boundingSphereWC[h]),r.scene3DOnly||(t._boundingSphere2D[h]=e.clone(t._boundingSphereCV[h],t._boundingSphere2D[h]),t._boundingSphere2D[h].center.x=0,t._boundingSphereMorph[h]=e.union(t._boundingSphereWC[h],t._boundingSphereCV[h])))}}if(a(t.rtcCenter)){var p=r.camera.viewMatrix;_.multiply(p,t._modelMatrix,t._modifiedModelView),_.multiplyByPoint(t._modifiedModelView,t.rtcCenter,ie),_.setTranslation(t._modifiedModelView,ie,t._modifiedModelView)}var m;r.mode===R.SCENE3D?m=t._boundingSphereWC:r.mode===R.COLUMBUS_VIEW?m=t._boundingSphereCV:r.mode===R.SCENE2D&&a(t._boundingSphere2D)?m=t._boundingSphere2D:a(t._boundingSphereMorph)&&(m=t._boundingSphereMorph);var f=r.commandList,v=r.passes;if(v.render)for(var g=i.length,y=0;g>y;++y){var C=u?Math.floor(y/2):y;i[y].modelMatrix=o,i[y].boundingVolume=m[C],i[y].cull=s,i[y].debugShowBoundingVolume=l,f.push(i[y])}if(v.pick)for(var E=n.length,S=0;E>S;++S)n[S].modelMatrix=o,n[S].boundingVolume=m[S],n[S].cull=s,f.push(n[S])}function Z(e,t){var r=t[e];return function(){return a(r)&&a(r.value)?t[e].value:r}}function K(e,t,r){return function(i){var n=t[e];n.value=i,!n.dirty&&n.valid&&(r.push(n),n.dirty=!0)}}function J(e,t,r,i){e._error=i,e._state=r,t.afterRender.push(function(){e._ready=e._state===D.COMPLETE||e._state===D.FAILED,a(i)?e._readyPromise.reject(i):e._readyPromise.resolve(e)})}var Q=function(e){e=o(e,o.EMPTY_OBJECT),this.geometryInstances=e.geometryInstances,this.appearance=e.appearance,this._appearance=void 0,this._material=void 0,this.modelMatrix=_.clone(o(e.modelMatrix,_.IDENTITY)),this._modelMatrix=new _,this.show=o(e.show,!0),this._vertexCacheOptimize=o(e.vertexCacheOptimize,!1),this._interleave=o(e.interleave,!1),this._releaseGeometryInstances=o(e.releaseGeometryInstances,!0),this._allowPicking=o(e.allowPicking,!0),this._asynchronous=o(e.asynchronous,!0),this._compressVertices=o(e.compressVertices,!0),this.cull=o(e.cull,!0),this.debugShowBoundingVolume=o(e.debugShowBoundingVolume,!1),this.rtcCenter=e.rtcCenter,this._modifiedModelView=new _,this._translucent=void 0,this._state=D.READY,this._geometries=[],this._vaAttributes=void 0,this._error=void 0,this._numberOfInstances=0,this._validModelMatrix=!1,this._boundingSpheres=[],this._boundingSphereWC=[],this._boundingSphereCV=[],this._boundingSphere2D=[],this._boundingSphereMorph=[],this._perInstanceAttributeLocations=void 0,this._perInstanceAttributeCache=[],this._instanceIds=[],this._lastPerInstanceAttributeIndex=0,this._dirtyAttributes=[],this._va=[],this._attributeLocations=void 0,this._primitiveType=void 0,this._frontFaceRS=void 0,this._backFaceRS=void 0,this._sp=void 0,this._pickRS=void 0,this._pickSP=void 0,this._pickIds=[],this._colorCommands=[],this._pickCommands=[],this._createBoundingVolumeFunction=e._createBoundingVolumeFunction,this._createRenderStatesFunction=e._createRenderStatesFunction,this._createShaderProgramFunction=e._createShaderProgramFunction,this._createCommandsFunction=e._createCommandsFunction,this._updateAndQueueCommandsFunction=e._updateAndQueueCommandsFunction,this._createGeometryResults=void 0,this._ready=!1,this._readyPromise=P.defer()};s(Q.prototype,{vertexCacheOptimize:{get:function(){return this._vertexCacheOptimize}},interleave:{get:function(){return this._interleave}},releaseGeometryInstances:{get:function(){return this._releaseGeometryInstances}},allowPicking:{get:function(){return this._allowPicking}},asynchronous:{get:function(){return this._asynchronous}},compressVertices:{get:function(){return this._compressVertices}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}}});var $=/attribute\s+vec(?:3|4)\s+(.*)3DHigh;/g;Q._modifyShaderPosition=function(e,t,r){for(var i,n="",o="",s="";null!==(i=$.exec(t));){var l=i[1],u="vec4 czm_compute"+l[0].toUpperCase()+l.substr(1)+"()";"vec4 czm_computePosition()"!==u&&(n+=u+";\n"),a(e.rtcCenter)?(t=t.replace(/attribute\s+vec(?:3|4)\s+position3DHigh;/g,""),t=t.replace(/attribute\s+vec(?:3|4)\s+position3DLow;/g,""),n+="uniform mat4 u_modifiedModelView;\n",o+="attribute vec4 position;\n",s+=u+"\n{\n return u_modifiedModelView * position;\n}\n\n",t=t.replace(/czm_modelViewRelativeToEye\s+\*\s+/g,""),t=t.replace(/czm_modelViewProjectionRelativeToEye/g,"czm_projection")):r?s+=u+"\n{\n return czm_translateRelativeToEye("+l+"3DHigh, "+l+"3DLow);\n}\n\n":(o+="attribute vec3 "+l+"2DHigh;\nattribute vec3 "+l+"2DLow;\n",s+=u+"\n{\n vec4 p;\n if (czm_morphTime == 1.0)\n {\n p = czm_translateRelativeToEye("+l+"3DHigh, "+l+"3DLow);\n }\n else if (czm_morphTime == 0.0)\n {\n p = czm_translateRelativeToEye("+l+"2DHigh.zxy, "+l+"2DLow.zxy);\n }\n else\n {\n p = czm_columbusViewMorph(\n czm_translateRelativeToEye("+l+"2DHigh.zxy, "+l+"2DLow.zxy),\n czm_translateRelativeToEye("+l+"3DHigh, "+l+"3DLow),\n czm_morphTime);\n }\n return p;\n}\n\n")}return[n,o,t,s].join("\n")},Q._appendShowToShader=function(e,t){if(!a(e._attributeLocations.show))return t;var r=b.replaceMain(t,"czm_non_show_main"),i="attribute float show;\nvoid main() \n{ \n czm_non_show_main(); \n gl_Position *= show; \n}";return r+"\n"+i};var ee,te=Math.max(c.hardwareConcurrency-1,1),re=new y("combineGeometry",Number.POSITIVE_INFINITY),ie=new t;return Q.prototype.update=function(e){if(!(!a(this.geometryInstances)&&0===this._va.length||a(this.geometryInstances)&&v(this.geometryInstances)&&0===this.geometryInstances.length||!a(this.appearance)||e.mode!==R.SCENE3D&&e.scene3DOnly||!e.passes.render&&!e.passes.pick)){if(a(this._error))throw this._error;if(a(this.rtcCenter)&&!e.scene3DOnly)throw new u("RTC rendering is only available for 3D only scenes.");if(this._state!==D.FAILED&&(this._state!==D.COMPLETE&&this._state!==D.COMBINED&&(this.asynchronous?U(this,e):G(this,e)),this._state===D.COMBINED&&W(this,e),this.show&&this._state===D.COMPLETE)){var t=this.appearance,r=t.material,i=!1,n=!1;this._appearance!==t?(this._appearance=t,this._material=r,i=!0,n=!0):this._material!==r&&(this._material=r,n=!0);var s=this._appearance.isTranslucent();this._translucent!==s&&(this._translucent=s,i=!0);var l=e.context;a(this._material)&&this._material.update(l);var c=t.closed&&s;if(i){var h=o(this._createRenderStatesFunction,H);h(this,l,t,c)}if(n){var d=o(this._createShaderProgramFunction,q);d(this,e,t)}if(i||n){var p=o(this._createCommandsFunction,j);p(this,t,r,s,c,this._colorCommands,this._pickCommands)}Y(this);var m=o(this._updateAndQueueCommandsFunction,X);m(this,e,this._colorCommands,this._pickCommands,this.modelMatrix,this.cull,this.debugShowBoundingVolume,c)}}},Q.prototype.getGeometryInstanceAttributes=function(e){for(var t=-1,r=this._lastPerInstanceAttributeIndex,i=this._instanceIds,n=i.length,o=0;n>o;++o){var l=(r+o)%n;if(e===i[l]){t=l;break}}if(-1===t)return void 0;var u=this._perInstanceAttributeCache[t];if(a(u))return u;var c=this._perInstanceAttributeLocations[t];u={};var h={},d=!1;for(var p in c)c.hasOwnProperty(p)&&(d=!0,h[p]={get:Z(p,c)},"boundingSphere"!==p&&"boundingSphereCV"!==p&&(h[p].set=K(p,c,this._dirtyAttributes)));return d&&s(u,h),this._lastPerInstanceAttributeIndex=t,this._perInstanceAttributeCache[t]=u,u},Q.prototype.isDestroyed=function(){return!1},Q.prototype.destroy=function(){var e,t;this._sp=this._sp&&this._sp.destroy(),this._pickSP=this._pickSP&&this._pickSP.destroy();var r=this._va;for(e=r.length,t=0;e>t;++t)r[t].destroy();this._va=void 0;var i=this._pickIds;for(e=i.length,t=0;e>t;++t)i[t].destroy();return this._pickIds=void 0,this._instanceIds=void 0,this._perInstanceAttributeCache=void 0,this._perInstanceAttributeLocations=void 0,this._attributeLocations=void 0,this._dirtyAttributes=void 0,l(this)},Q}),r("DataSources/ColorMaterialProperty",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./ConstantProperty","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this.color=e};return r(l.prototype,{isConstant:{get:function(){return s.isConstant(this._color)}},definitionChanged:{get:function(){return this._definitionChanged}},color:a("color")}),l.prototype.getType=function(e){return"Color"},l.prototype.getValue=function(r,i){return t(i)||(i={}),i.color=s.getValueOrClonedDefault(this._color,r,e.WHITE,i.color),i},l.prototype.equals=function(e){return this===e||e instanceof l&&s.equals(this._color,e._color)},l}),r("DataSources/dynamicGeometryGetBoundingSphere",["../Core/BoundingSphere","../Core/defined","../Core/DeveloperError","./BoundingSphereState"],function(e,t,r,i){"use strict";var n=function(r,n,o,a){var s;return t(n)&&n.show&&n.ready&&(s=n.getGeometryInstanceAttributes(r),t(s)&&t(s.boundingSphere))?(e.transform(s.boundingSphere,n.modelMatrix,a),i.DONE):t(o)&&o.show&&o.ready&&(s=o.getGeometryInstanceAttributes(r),t(s)&&t(s.boundingSphere))?(e.transform(s.boundingSphere,o.modelMatrix,a),i.DONE):t(n)&&!n.ready||t(o)&&!o.ready?i.PENDING:i.FAILED};return n}),r("DataSources/MaterialProperty",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Scene/Material"],function(e,t,r,i,n){"use strict";var o=function(){i.throwInstantiationError()};return r(o.prototype,{isConstant:{get:i.throwInstantiationError},definitionChanged:{get:i.throwInstantiationError}}),o.prototype.getType=i.throwInstantiationError,o.prototype.getValue=i.throwInstantiationError,o.prototype.equals=i.throwInstantiationError,o.getValue=function(r,i,o){var a;return t(i)&&(a=i.getType(r),t(a))?(t(o)&&o.type===a||(o=n.fromType(a)),i.getValue(r,o.uniforms),o):(t(o)&&o.type===n.ColorType||(o=n.fromType(n.ColorType)),e.clone(e.WHITE,o.uniforms.color),o)},o}),r("DataSources/BoxGeometryUpdater",["../Core/BoxGeometry","../Core/BoxOutlineGeometry","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(r.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(r.BLACK),x=new r,P=function(e){this.id=e,this.vertexFormat=void 0,this.dimensions=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"box",e.box,void 0)};a(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),a(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(t){var n,a,s=this._entity,l=s.isAvailable(t),u=new d(l&&s.isShowing&&this._showProperty.getValue(t)&&this._fillProperty.getValue(t));if(this._materialProperty instanceof v){var p=r.WHITE;o(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(p=this._materialProperty.color.getValue(t)),a=i.fromColor(p),n={show:u,color:a}}else n={show:u};return new c({id:s,geometry:e.fromDimensions(this._options),modelMatrix:s._getModelMatrix(h.MINIMUM_VALUE),attributes:n})},A.prototype.createOutlineGeometryInstance=function(e){var n=this._entity,o=n.isAvailable(e),a=C.getValueOrDefault(this._outlineColorProperty,e,r.BLACK);return new c({id:n,geometry:t.fromDimensions(this._options),modelMatrix:n._getModelMatrix(h.MINIMUM_VALUE),attributes:{show:new d(o&&n.isShowing&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)),color:i.fromColor(a)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),s(this)},A.prototype._onEntityPropertyChanged=function(e,t,r,i){if("availability"===t||"position"===t||"orientation"===t||"box"===t){var a=this._entity.box;if(!o(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=o(s)&&s.isConstant?s.getValue(h.MINIMUM_VALUE):!0,u=a.outline,c=o(u); -if(c&&u.isConstant&&(c=u.getValue(h.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.dimensions,f=e.position,_=a.show;if(!o(d)||!o(f)||o(_)&&_.isConstant&&!_.getValue(h.MINIMUM_VALUE))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var g=n(a.material,E),y=g instanceof v;this._materialProperty=g,this._fillProperty=n(s,w),this._showProperty=n(_,S),this._showOutlineProperty=n(a.outline,T),this._outlineColorProperty=c?n(a.outlineColor,b):void 0;var x=a.outlineWidth;if(this._fillEnabled=l,this._outlineEnabled=c,f.isConstant&&C.isConstant(e.orientation)&&d.isConstant&&C.isConstant(x)){var P=this._options;P.vertexFormat=y?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,P.dimensions=d.getValue(h.MINIMUM_VALUE,P.dimensions),this._outlineWidth=o(x)?x.getValue(h.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(n){var a=this._primitives;a.removeAndDestroy(this._primitive),a.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var s=this._geometryUpdater,l=s._entity,u=l.box;if(l.isShowing&&l.isAvailable(n)&&C.getValueOrDefault(u.show,n,!0)){var h=this._options,d=l._getModelMatrix(n),v=C.getValueOrUndefined(u.dimensions,n,h.dimensions);if(o(d)&&o(v)){if(h.dimensions=v,C.getValueOrDefault(u.fill,n,!0)){var _=y.getValue(n,s.fillMaterialProperty,this._material);this._material=_;var g=new p({material:_,translucent:_.isTranslucent(),closed:!0});h.vertexFormat=g.vertexFormat,this._primitive=a.add(new f({geometryInstances:new c({id:l,geometry:e.fromDimensions(h),modelMatrix:d}),appearance:g,asynchronous:!1}))}if(C.getValueOrDefault(u.outline,n,!1)){h.vertexFormat=m.VERTEX_FORMAT;var E=C.getValueOrClonedDefault(u.outlineColor,n,r.BLACK,x),S=C.getValueOrDefault(u.outlineWidth,n,1),w=1!==E.alpha;this._outlinePrimitive=a.add(new f({geometryInstances:new c({id:l,geometry:t.fromDimensions(h),modelMatrix:d,attributes:{color:i.fromColor(E)}}),appearance:new m({flat:!0,translucent:w,renderState:{lineWidth:s._scene.clampLineWidth(S)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),s(this)},A}),r("DataSources/ImageMaterialProperty",["../Core/Cartesian2","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=new e(1,1),l=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._image=void 0,this._imageSubscription=void 0,this._repeat=void 0,this._repeatSubscription=void 0,this.image=e.image,this.repeat=e.repeat};return i(l.prototype,{isConstant:{get:function(){return a.isConstant(this._image)&&a.isConstant(this._repeat)}},definitionChanged:{get:function(){return this._definitionChanged}},image:o("image"),repeat:o("repeat")}),l.prototype.getType=function(e){return"Image"},l.prototype.getValue=function(e,t){return r(t)||(t={}),t.image=a.getValueOrUndefined(this._image,e),t.repeat=a.getValueOrClonedDefault(this._repeat,e,s,t.repeat),t},l.prototype.equals=function(e){return this===e||e instanceof l&&a.equals(this._image,e._image)&&a.equals(this._repeat,e._repeat)},l}),r("DataSources/createMaterialPropertyDescriptor",["../Core/Color","../Core/DeveloperError","./ColorMaterialProperty","./createPropertyDescriptor","./ImageMaterialProperty"],function(e,t,r,i,n){"use strict";function o(t){if(t instanceof e)return new r(t);if("string"==typeof t||t instanceof HTMLCanvasElement){var i=new n;return i.image=t,i}}function a(e,t){return i(e,t,o)}return a}),r("DataSources/BoxGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._dimensions=void 0,this._dimensionsSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),dimensions:a("dimensions"),material:o("material"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth")}),s.prototype.clone=function(e){return t(e)?(e.dimensions=this.dimensions,e.show=this.show,e.material=this.material,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e):new s(this)},s.prototype.merge=function(t){this.dimensions=e(this.dimensions,t.dimensions),this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth)},s}),r("DataSources/CallbackProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event"],function(e,t,r,i){"use strict";var n=function(e,t){this._callback=void 0,this._isConstant=void 0,this._definitionChanged=new i,this.setCallback(e,t)};return t(n.prototype,{isConstant:{get:function(){return this._isConstant}},definitionChanged:{get:function(){return this._definitionChanged}}}),n.prototype.getValue=function(e,t){return this._callback(e,t)},n.prototype.setCallback=function(e,t){var r=this._callback!==e||this._isConstant!==t;this._callback=e,this._isConstant=t,r&&this._definitionChanged.raiseEvent(this)},n.prototype.equals=function(e){return this===e||e instanceof n&&this._callback===e._callback&&this._isConstant===e._isConstant},n}),r("DataSources/CheckerboardMaterialProperty",["../Core/Cartesian2","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=t.WHITE,u=t.BLACK,c=new e(2,2),h=function(e){e=r(e,r.EMPTY_OBJECT),this._definitionChanged=new o,this._evenColor=void 0,this._evenColorSubscription=void 0,this._oddColor=void 0,this._oddColorSubscription=void 0,this._repeat=void 0,this._repeatSubscription=void 0,this.evenColor=e.evenColor,this.oddColor=e.oddColor,this.repeat=e.repeat};return n(h.prototype,{isConstant:{get:function(){return s.isConstant(this._evenColor)&&s.isConstant(this._oddColor)&&s.isConstant(this._repeat)}},definitionChanged:{get:function(){return this._definitionChanged}},evenColor:a("evenColor"),oddColor:a("oddColor"),repeat:a("repeat")}),h.prototype.getType=function(e){return"Checkerboard"},h.prototype.getValue=function(e,t){return i(t)||(t={}),t.lightColor=s.getValueOrClonedDefault(this._evenColor,e,l,t.lightColor),t.darkColor=s.getValueOrClonedDefault(this._oddColor,e,u,t.darkColor),t.repeat=s.getValueOrDefault(this._repeat,e,c),t},h.prototype.equals=function(e){return this===e||e instanceof h&&s.equals(this._evenColor,e._evenColor)&&s.equals(this._oddColor,e._oddColor)&&s.equals(this._repeat,e._repeat)},h}),r("DataSources/PositionProperty",["../Core/Cartesian3","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix3","../Core/ReferenceFrame","../Core/Transforms"],function(e,t,r,i,n,o,a){"use strict";var s=function(){i.throwInstantiationError()};r(s.prototype,{isConstant:{get:i.throwInstantiationError},definitionChanged:{get:i.throwInstantiationError},referenceFrame:{get:i.throwInstantiationError}}),s.prototype.getValue=i.throwInstantiationError,s.prototype.getValueInReferenceFrame=i.throwInstantiationError,s.prototype.equals=i.throwInstantiationError;var l=new n;return s.convertToReferenceFrame=function(r,i,s,u,c){if(!t(i))return i;if(t(c)||(c=new e),s===u)return e.clone(i,c);var h=a.computeIcrfToFixedMatrix(r,l);return t(h)||(h=a.computeTemeToPseudoFixedMatrix(r,l)),s===o.INERTIAL?n.multiplyByVector(h,i,c):s===o.FIXED?n.multiplyByVector(n.transpose(h,l),i,c):void 0},s}),r("DataSources/ConstantPositionProperty",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","./PositionProperty"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(r,i){this._definitionChanged=new o,this._value=e.clone(r),this._referenceFrame=t(i,a.FIXED)};return i(l.prototype,{isConstant:{get:function(){return!r(this._value)||this._referenceFrame===a.FIXED}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return this._referenceFrame}}}),l.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,a.FIXED,t)},l.prototype.setValue=function(t,i){var n=!1;e.equals(this._value,t)||(n=!0,this._value=e.clone(t)),r(i)&&this._referenceFrame!==i&&(n=!0,this._referenceFrame=i),n&&this._definitionChanged.raiseEvent(this)},l.prototype.getValueInReferenceFrame=function(e,t,r){return s.convertToReferenceFrame(e,this._value,this._referenceFrame,t,r)},l.prototype.equals=function(t){return this===t||t instanceof l&&e.equals(this._value,t._value)&&this._referenceFrame===t._referenceFrame},l}),r("DataSources/CorridorGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._cornerType=void 0,this._cornerTypeSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),width:a("width"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),cornerType:a("cornerType")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.width=this.width,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.cornerType=this.cornerType,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.width=e(this.width,t.width),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.cornerType=e(this.cornerType,t.cornerType)},s}),r("DataSources/createRawPropertyDescriptor",["./createPropertyDescriptor"],function(e){"use strict";function t(e){return e}function r(r,i){return e(r,i,t)}return r}),r("DataSources/CylinderGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._length=void 0,this._lengthSubscription=void 0,this._topRadius=void 0,this._topRadiusSubscription=void 0,this._bottomRadius=void 0,this._bottomRadiusSubscription=void 0,this._numberOfVerticalLines=void 0,this._numberOfVerticalLinesSubscription=void 0,this._slices=void 0,this._slicesSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},length:a("length"),topRadius:a("topRadius"),bottomRadius:a("bottomRadius"),numberOfVerticalLines:a("numberOfVerticalLines"),slices:a("slices"),show:a("show"),material:o("material"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth")}),s.prototype.clone=function(e){return t(e)?(e.bottomRadius=this.bottomRadius,e.length=this.length,e.topRadius=this.topRadius,e.show=this.show,e.material=this.material,e.numberOfVerticalLines=this.numberOfVerticalLines,e.slices=this.slices,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e):new s(this)},s.prototype.merge=function(t){this.bottomRadius=e(this.bottomRadius,t.bottomRadius),this.length=e(this.length,t.length),this.topRadius=e(this.topRadius,t.topRadius),this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.numberOfVerticalLines=e(this.numberOfVerticalLines,t.numberOfVerticalLines),this.slices=e(this.slices,t.slices),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth)},s}),r("DataSources/EllipseGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._semiMajorAxis=void 0,this._semiMajorAxisSubscription=void 0,this._semiMinorAxis=void 0,this._semiMinorAxisSubscription=void 0,this._rotation=void 0,this._rotationSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._stRotation=void 0,this._stRotationSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._numberOfVerticalLines=void 0,this._numberOfVerticalLinesSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},semiMajorAxis:a("semiMajorAxis"),semiMinorAxis:a("semiMinorAxis"),rotation:a("rotation"),show:a("show"),material:o("material"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),stRotation:a("stRotation"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),numberOfVerticalLines:a("numberOfVerticalLines")}),s.prototype.clone=function(e){return t(e)?(e.rotation=this.rotation,e.semiMajorAxis=this.semiMajorAxis,e.semiMinorAxis=this.semiMinorAxis,e.show=this.show,e.material=this.material,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.stRotation=this.stRotation,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.numberOfVerticalLines=this.numberOfVerticalLines,e):new s(this)},s.prototype.merge=function(t){this.rotation=e(this.rotation,t.rotation),this.semiMajorAxis=e(this.semiMajorAxis,t.semiMajorAxis),this.semiMinorAxis=e(this.semiMinorAxis,t.semiMinorAxis),this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.stRotation=e(this.stRotation,t.stRotation),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.numberOfVerticalLines=e(this.numberOfVerticalLines,t.numberOfVerticalLines)},s}),r("DataSources/EllipsoidGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._radii=void 0,this._radiiSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._stackPartitions=void 0,this._stackPartitionsSubscription=void 0,this._slicePartitions=void 0,this._slicePartitionsSubscription=void 0,this._subdivisions=void 0,this._subdivisionsSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),radii:a("radii"),material:o("material"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),stackPartitions:a("stackPartitions"),slicePartitions:a("slicePartitions"),subdivisions:a("subdivisions")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.radii=this.radii,e.material=this.material,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.stackPartitions=this.stackPartitions,e.slicePartitions=this.slicePartitions,e.subdivisions=this.subdivisions,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.radii=e(this.radii,t.radii),this.material=e(this.material,t.material),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.stackPartitions=e(this.stackPartitions,t.stackPartitions),this.slicePartitions=e(this.slicePartitions,t.slicePartitions),this.subdivisions=e(this.subdivisions,t.subdivisions)},s}),r("DataSources/LabelGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._text=void 0,this._textSubscription=void 0,this._font=void 0,this._fontSubscription=void 0,this._style=void 0,this._styleSubscription=void 0,this._fillColor=void 0,this._fillColorSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._horizontalOrigin=void 0,this._horizontalOriginSubscription=void 0,this._verticalOrigin=void 0,this._verticalOriginSubscription=void 0,this._eyeOffset=void 0,this._eyeOffsetSubscription=void 0,this._pixelOffset=void 0,this._pixelOffsetSubscription=void 0,this._scale=void 0,this._scaleSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._translucencyByDistance=void 0,this._translucencyByDistanceSubscription=void 0,this._pixelOffsetScaleByDistance=void 0,this._pixelOffsetScaleByDistanceSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},text:o("text"),font:o("font"),style:o("style"),fillColor:o("fillColor"),outlineColor:o("outlineColor"),outlineWidth:o("outlineWidth"),horizontalOrigin:o("horizontalOrigin"),verticalOrigin:o("verticalOrigin"),eyeOffset:o("eyeOffset"),pixelOffset:o("pixelOffset"),scale:o("scale"),show:o("show"),translucencyByDistance:o("translucencyByDistance"),pixelOffsetScaleByDistance:o("pixelOffsetScaleByDistance")}),a.prototype.clone=function(e){return t(e)?(e.text=this.text,e.font=this.font,e.show=this.show,e.style=this.style,e.fillColor=this.fillColor,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.scale=this.scale,e.horizontalOrigin=this.horizontalOrigin,e.verticalOrigin=this.verticalOrigin,e.eyeOffset=this.eyeOffset,e.pixelOffset=this.pixelOffset,e.translucencyByDistance=this.translucencyByDistance,e.pixelOffsetScaleByDistance=this.pixelOffsetScaleByDistance,e):new a(this)},a.prototype.merge=function(t){this.text=e(this.text,t.text),this.font=e(this.font,t.font),this.show=e(this.show,t.show),this.style=e(this.style,t.style),this.fillColor=e(this.fillColor,t.fillColor),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.scale=e(this.scale,t.scale),this.horizontalOrigin=e(this.horizontalOrigin,t.horizontalOrigin),this.verticalOrigin=e(this.verticalOrigin,t.verticalOrigin),this.eyeOffset=e(this.eyeOffset,t.eyeOffset),this.pixelOffset=e(this.pixelOffset,t.pixelOffset),this.translucencyByDistance=e(this._translucencyByDistance,t.translucencyByDistance),this.pixelOffsetScaleByDistance=e(this._pixelOffsetScaleByDistance,t.pixelOffsetScaleByDistance)},a}),r("DataSources/ModelGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._show=void 0,this._showSubscription=void 0,this._scale=void 0,this._scaleSubscription=void 0,this._minimumPixelSize=void 0,this._minimumPixelSizeSubscription=void 0,this._maximumScale=void 0,this._maximumScaleSubscription=void 0,this._uri=void 0,this._uriSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:o("show"),scale:o("scale"),minimumPixelSize:o("minimumPixelSize"),maximumScale:o("maximumScale"),uri:o("uri")}),a.prototype.clone=function(e){return t(e)?(e.show=this.show,e.scale=this.scale,e.minimumPixelSize=this.minimumPixelSize,e.maximumScale=this.maximumScale,e.uri=this.uri,e):new a(this)},a.prototype.merge=function(t){this.show=e(this.show,t.show),this.scale=e(this.scale,t.scale),this.minimumPixelSize=e(this.minimumPixelSize,t.minimumPixelSize),this.maximumScale=e(this.maximumScale,t.maximumScale),this.uri=e(this.uri,t.uri)},a}),r("DataSources/PathGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._material=void 0,this._materialSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._resolution=void 0,this._resolutionSubscription=void 0,this._leadTime=void 0,this._leadTimeSubscription=void 0,this._trailTime=void 0,this._trailTimeSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),width:a("width"),resolution:a("resolution"),leadTime:a("leadTime"),trailTime:a("trailTime")}),s.prototype.clone=function(e){return t(e)?(e.material=this.material,e.width=this.width,e.resolution=this.resolution,e.show=this.show,e.leadTime=this.leadTime,e.trailTime=this.trailTime,e):new s(this)},s.prototype.merge=function(t){this.material=e(this.material,t.material),this.width=e(this.width,t.width),this.resolution=e(this.resolution,t.resolution),this.show=e(this.show,t.show),this.leadTime=e(this.leadTime,t.leadTime),this.trailTime=e(this.trailTime,t.trailTime)},s}),r("DataSources/PointGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createPropertyDescriptor"],function(e,t,r,i,n,o){"use strict";var a=function(t){this._color=void 0,this._colorSubscription=void 0,this._pixelSize=void 0,this._pixelSizeSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._show=void 0,this._showSubscription=void 0,this._scaleByDistance=void 0,this._scaleByDistanceSubscription=void 0,this._translucencyByDistance=void 0,this._translucencyByDistanceSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(a.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},color:o("color"),pixelSize:o("pixelSize"),outlineColor:o("outlineColor"),outlineWidth:o("outlineWidth"),show:o("show"),scaleByDistance:o("scaleByDistance"),translucencyByDistance:o("translucencyByDistance")}),a.prototype.clone=function(e){return t(e)?(e.color=this.color,e.pixelSize=this.pixelSize,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.show=this.show,e.scaleByDistance=this.scaleByDistance,e.translucencyByDistance=this._translucencyByDistance,e):new a(this)},a.prototype.merge=function(t){this.color=e(this.color,t.color),this.pixelSize=e(this.pixelSize,t.pixelSize),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.show=e(this.show,t.show),this.scaleByDistance=e(this.scaleByDistance,t.scaleByDistance),this.translucencyByDistance=e(this._translucencyByDistance,t.translucencyByDistance)},a}),r("DataSources/PolygonGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._hierarchy=void 0,this._hierarchySubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._stRotation=void 0,this._stRotationSubscription=void 0,this._perPositionHeight=void 0,this._perPositionHeightSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this._fill=void 0,this._fillSubscription=void 0,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),hierarchy:a("hierarchy"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),stRotation:a("stRotation"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),perPositionHeight:a("perPositionHeight")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.hierarchy=this.hierarchy,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.stRotation=this.stRotation,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.perPositionHeight=this.perPositionHeight,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.hierarchy=e(this.hierarchy,t.hierarchy),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.stRotation=e(this.stRotation,t.stRotation),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.perPositionHeight=e(this.perPositionHeight,t.perPositionHeight)},s}),r("DataSources/PolylineGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._followSurface=void 0,this._followSurfaceSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._widthSubscription=void 0,this._width=void 0,this._widthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),width:a("width"),followSurface:a("followSurface"),granularity:a("granularity")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions,e.width=this.width,e.followSurface=this.followSurface,e.granularity=this.granularity,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.width=e(this.width,t.width),this.followSurface=e(this.followSurface,t.followSurface),this.granularity=e(this.granularity,t.granularity)},s}),r("DataSources/PolylineVolumeGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._shape=void 0,this._shapeSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._cornerType=void 0,this._cornerTypeSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),shape:a("shape"),granularity:a("granularity"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),cornerType:a("cornerType")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions, -e.shape=this.shape,e.granularity=this.granularity,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.cornerType=this.cornerType,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.shape=e(this.shape,t.shape),this.granularity=e(this.granularity,t.granularity),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.cornerType=e(this.cornerType,t.cornerType)},s}),r("DataSources/RectangleGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._coordinates=void 0,this._coordinatesSubscription=void 0,this._height=void 0,this._heightSubscription=void 0,this._extrudedHeight=void 0,this._extrudedHeightSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._stRotation=void 0,this._stRotationSubscription=void 0,this._rotation=void 0,this._rotationSubscription=void 0,this._closeTop=void 0,this._closeTopSubscription=void 0,this._closeBottom=void 0,this._closeBottomSubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),coordinates:a("coordinates"),material:o("material"),height:a("height"),extrudedHeight:a("extrudedHeight"),granularity:a("granularity"),stRotation:a("stRotation"),rotation:a("rotation"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth"),closeTop:a("closeTop"),closeBottom:a("closeBottom")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.coordinates=this.coordinates,e.material=this.material,e.height=this.height,e.extrudedHeight=this.extrudedHeight,e.granularity=this.granularity,e.stRotation=this.stRotation,e.rotation=this.rotation,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e.closeTop=this.closeTop,e.closeBottom=this.closeBottom,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.coordinates=e(this.coordinates,t.coordinates),this.material=e(this.material,t.material),this.height=e(this.height,t.height),this.extrudedHeight=e(this.extrudedHeight,t.extrudedHeight),this.granularity=e(this.granularity,t.granularity),this.stRotation=e(this.stRotation,t.stRotation),this.rotation=e(this.rotation,t.rotation),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth),this.closeTop=e(this.closeTop,t.closeTop),this.closeBottom=e(this.closeBottom,t.closeBottom)},s}),r("DataSources/WallGraphics",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./createMaterialPropertyDescriptor","./createPropertyDescriptor"],function(e,t,r,i,n,o,a){"use strict";var s=function(t){this._show=void 0,this._showSubscription=void 0,this._material=void 0,this._materialSubscription=void 0,this._positions=void 0,this._positionsSubscription=void 0,this._minimumHeights=void 0,this._minimumHeightsSubscription=void 0,this._maximumHeights=void 0,this._maximumHeightsSubscription=void 0,this._granularity=void 0,this._granularitySubscription=void 0,this._fill=void 0,this._fillSubscription=void 0,this._outline=void 0,this._outlineSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this._definitionChanged=new n,this.merge(e(t,e.EMPTY_OBJECT))};return r(s.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},show:a("show"),material:o("material"),positions:a("positions"),minimumHeights:a("minimumHeights"),maximumHeights:a("maximumHeights"),granularity:a("granularity"),fill:a("fill"),outline:a("outline"),outlineColor:a("outlineColor"),outlineWidth:a("outlineWidth")}),s.prototype.clone=function(e){return t(e)?(e.show=this.show,e.material=this.material,e.positions=this.positions,e.minimumHeights=this.minimumHeights,e.maximumHeights=this.maximumHeights,e.granularity=this.granularity,e.fill=this.fill,e.outline=this.outline,e.outlineColor=this.outlineColor,e.outlineWidth=this.outlineWidth,e):new s(this)},s.prototype.merge=function(t){this.show=e(this.show,t.show),this.material=e(this.material,t.material),this.positions=e(this.positions,t.positions),this.minimumHeights=e(this.minimumHeights,t.minimumHeights),this.maximumHeights=e(this.maximumHeights,t.maximumHeights),this.granularity=e(this.granularity,t.granularity),this.fill=e(this.fill,t.fill),this.outline=e(this.outline,t.outline),this.outlineColor=e(this.outlineColor,t.outlineColor),this.outlineWidth=e(this.outlineWidth,t.outlineWidth)},s}),r("DataSources/Entity",["../Core/Cartesian3","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/Matrix3","../Core/Matrix4","../Core/Quaternion","../Core/Transforms","./BillboardGraphics","./BoxGraphics","./ConstantPositionProperty","./CorridorGraphics","./createPropertyDescriptor","./createRawPropertyDescriptor","./CylinderGraphics","./EllipseGraphics","./EllipsoidGraphics","./LabelGraphics","./ModelGraphics","./PathGraphics","./PointGraphics","./PolygonGraphics","./PolylineGraphics","./PolylineVolumeGraphics","./Property","./RectangleGraphics","./WallGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e){return new p(e)}function D(e){return f(e,void 0,M)}function R(e,t){return f(e,void 0,function(e){return e instanceof t?e:new t(e)})}function O(e,t,r){for(var i=t.length,n=0;i>n;n++){var o=t[n],a=o._show,s=!r&&a,l=r&&a;s!==l&&O(o,o._children,r)}e._definitionChanged.raiseEvent(e,"isShowing",r,!r)}var N=function(e){e=r(e,r.EMPTY_OBJECT);var n=e.id;i(n)||(n=t()),this._availability=void 0,this._id=n,this._definitionChanged=new a,this._name=e.name,this._show=r(e.show,!0),this._parent=void 0,this._propertyNames=["billboard","box","corridor","cylinder","description","ellipse","ellipsoid","label","model","orientation","path","point","polygon","polyline","polylineVolume","position","rectangle","viewFrom","wall"],this._billboard=void 0,this._billboardSubscription=void 0,this._box=void 0,this._boxSubscription=void 0,this._corridor=void 0,this._corridorSubscription=void 0,this._cylinder=void 0,this._cylinderSubscription=void 0,this._description=void 0,this._descriptionSubscription=void 0,this._ellipse=void 0,this._ellipseSubscription=void 0,this._ellipsoid=void 0,this._ellipsoidSubscription=void 0,this._label=void 0,this._labelSubscription=void 0,this._model=void 0,this._modelSubscription=void 0,this._orientation=void 0,this._orientationSubscription=void 0,this._path=void 0,this._pathSubscription=void 0,this._point=void 0,this._pointSubscription=void 0,this._polygon=void 0,this._polygonSubscription=void 0,this._polyline=void 0,this._polylineSubscription=void 0,this._polylineVolume=void 0,this._polylineVolumeSubscription=void 0,this._position=void 0,this._positionSubscription=void 0,this._rectangle=void 0,this._rectangleSubscription=void 0,this._viewFrom=void 0,this._viewFromSubscription=void 0,this._wall=void 0,this._wallSubscription=void 0,this._children=[],this.entityCollection=void 0,this.parent=e.parent,this.merge(e)};n(N.prototype,{availability:v("availability"),id:{get:function(){return this._id}},definitionChanged:{get:function(){return this._definitionChanged}},name:v("name"),show:{get:function(){return this._show},set:function(e){if(e!==this._show){var t=this.isShowing;this._show=e;var r=this.isShowing;t!==r&&O(this,this._children,r),this._definitionChanged.raiseEvent(this,"show",e,!e)}}},isShowing:{get:function(){return this._show&&(!i(this._parent)||this._parent.isShowing)}},parent:{get:function(){return this._parent},set:function(e){var t=this._parent;if(t!==e){var r=this.isShowing;if(i(t)){var n=t._children.indexOf(this);t._children.splice(n,1)}this._parent=e,i(e)&&e._children.push(this);var o=this.isShowing;r!==o&&O(this,this._children,o),this._definitionChanged.raiseEvent(this,"parent",e,t)}}},propertyNames:{get:function(){return this._propertyNames}},billboard:R("billboard",h),box:R("box",d),corridor:R("corridor",m),cylinder:R("cylinder",_),description:f("description"),ellipse:R("ellipse",g),ellipsoid:R("ellipsoid",y),label:R("label",C),model:R("model",E),orientation:f("orientation"),path:R("path",S),point:R("point",w),polygon:R("polygon",T),polyline:R("polyline",b),polylineVolume:R("polylineVolume",x),position:D("position"),rectangle:R("rectangle",A),viewFrom:f("viewFrom"),wall:R("wall",I)}),N.prototype.isAvailable=function(e){var t=this._availability;return!i(t)||t.contains(e)},N.prototype.addProperty=function(e){var t=this._propertyNames;t.push(e),Object.defineProperty(this,e,v(e,!0))},N.prototype.removeProperty=function(e){this._propertyNames;this._propertyNames.push(e),delete this[e]},N.prototype.merge=function(e){this.name=r(this.name,e.name),this.availability=r(e.availability,this.availability);for(var t=this._propertyNames,n=i(e._propertyNames)?e._propertyNames:Object.keys(e),o=n.length,a=0;o>a;a++){var s=n[a];if("parent"!==s){var l=this[s],u=e[s];i(l)||-1!==t.indexOf(s)||this.addProperty(s),i(u)&&(i(l)?i(l.merge)&&l.merge(u):i(u.merge)&&i(u.clone)?this[s]=u.clone():this[s]=u)}}};var L=new s,F=new e,B=new u;return N.prototype._getModelMatrix=function(e,t){var r=P.getValueOrUndefined(this._position,e,F);if(!i(r))return void 0;var n=P.getValueOrUndefined(this._orientation,e,B);return t=i(n)?l.fromRotationTranslation(s.fromQuaternion(n,L),r,t):c.eastNorthUpToFixedFrame(r,void 0,t)},N}),r("DataSources/EntityCollection",["../Core/AssociativeArray","../Core/createGuid","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/Iso8601","../Core/JulianDate","../Core/RuntimeError","../Core/TimeInterval","./Entity"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e){if(0===e._suspendCount){var t=e._addedEntities,r=e._removedEntities,i=e._changedEntities;(0!==i.length||0!==t.length||0!==r.length)&&(e._collectionChanged.raiseEvent(e,t.values,r.values,i.values),t.removeAll(),r.removeAll(),i.removeAll())}}var d={id:void 0},p=function(r){this._owner=r,this._entities=new e,this._addedEntities=new e,this._removedEntities=new e,this._changedEntities=new e,this._suspendCount=0,this._collectionChanged=new o,this._id=t()};return p.prototype.suspendEvents=function(){this._suspendCount++},p.prototype.resumeEvents=function(){this._suspendCount--,h(this)},p.collectionChangedEventCallback=void 0,i(p.prototype,{collectionChanged:{get:function(){return this._collectionChanged}},id:{get:function(){return this._id}},values:{get:function(){return this._entities.values}},owner:{get:function(){return this._owner}}}),p.prototype.computeAvailability=function(){for(var e=a.MAXIMUM_VALUE,t=a.MINIMUM_VALUE,i=this._entities.values,n=0,o=i.length;o>n;n++){var l=i[n],c=l.availability;if(r(c)){var h=c.start,d=c.stop;s.lessThan(h,e)&&!h.equals(a.MINIMUM_VALUE)&&(e=h),s.greaterThan(d,t)&&!d.equals(a.MAXIMUM_VALUE)&&(t=d)}}return a.MAXIMUM_VALUE.equals(e)&&(e=a.MINIMUM_VALUE),a.MINIMUM_VALUE.equals(t)&&(t=a.MAXIMUM_VALUE),new u({start:e,stop:t})},p.prototype.add=function(e){e instanceof c||(e=new c(e));var t=e.id,r=this._entities;if(r.contains(t))throw new l("An entity with id "+t+" already exists in this collection.");e.entityCollection=this,r.set(t,e);this._removedEntities;return this._removedEntities.remove(t)||this._addedEntities.set(t,e),e.definitionChanged.addEventListener(p.prototype._onEntityDefinitionChanged,this),h(this),e},p.prototype.remove=function(e){return r(e)?this.removeById(e.id):!1},p.prototype.contains=function(e){return this._entities.get(e.id)===e},p.prototype.removeById=function(e){if(!r(e))return!1;var t=this._entities,i=t.get(e);return this._entities.remove(e)?(this._addedEntities.remove(e)||(this._removedEntities.set(e,i),this._changedEntities.remove(e)),this._entities.remove(e),i.definitionChanged.removeEventListener(p.prototype._onEntityDefinitionChanged,this),h(this),!0):!1},p.prototype.removeAll=function(){for(var e=this._entities,t=e.length,i=e.values,n=this._addedEntities,o=this._removedEntities,a=0;t>a;a++){var s=i[a],l=s.id,u=n.get(l);r(u)||(s.definitionChanged.removeEventListener(p.prototype._onEntityDefinitionChanged,this),o.set(l,s))}e.removeAll(),n.removeAll(),this._changedEntities.removeAll(),h(this)},p.prototype.getById=function(e){return this._entities.get(e)},p.prototype.getOrCreateEntity=function(e){var t=this._entities.get(e);return r(t)||(d.id=e,t=new c(d),this.add(t)),t},p.prototype._onEntityDefinitionChanged=function(e){var t=e.id;this._addedEntities.contains(t)||this._changedEntities.set(t,e),h(this)},p}),r("DataSources/CompositeEntityCollection",["../Core/createGuid","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Math","./Entity","./EntityCollection"],function(e,t,r,i,n,o,a){"use strict";function s(e){for(var t=e.propertyNames,r=t.length,i=0;r>i;i++)e[t[i]]=void 0}function l(e,t,r,i){m[0]=r,m[1]=i.id,t[JSON.stringify(m)]=i.definitionChanged.addEventListener(f.prototype._onDefinitionChanged,e)}function u(e,t,r,i){m[0]=r,m[1]=i.id;var n=JSON.stringify(m);t[n](),t[n]=void 0}function c(e){if(e._shouldRecomposite=!0,0===e._suspendCount){var r,i,n,c,h,d,m=e._collections,v=m.length,_=e._collectionsCopy,g=_.length,y=e._composite,C=new a(e),E=e._eventHash;for(r=0;g>r;r++)for(h=_[r],h.collectionChanged.removeEventListener(f.prototype._onCollectionChanged,e),n=h.values,d=h.id,c=n.length-1;c>-1;c--)i=n[c],u(e,E,d,i);for(r=v-1;r>=0;r--)for(h=m[r],h.collectionChanged.addEventListener(f.prototype._onCollectionChanged,e),n=h.values,d=h.id,c=n.length-1;c>-1;c--){i=n[c],l(e,E,d,i);var S=C.getById(i.id);t(S)||(S=y.getById(i.id),t(S)?s(S):(p.id=i.id,S=new o(p)),C.add(S)),S.merge(i)}e._collectionsCopy=m.slice(0),y.suspendEvents(),y.removeAll();var w=C.values;for(r=0;r<w.length;r++)y.add(w[r]);y.resumeEvents()}}function h(e,t){var r=e.indexOf(t);return r}function d(e,t,r){var i=e._collections;if(t=n.clamp(t,0,i.length-1),r=n.clamp(r,0,i.length-1),t!==r){var o=i[t];i[t]=i[r],i[r]=o,c(e)}}var p={id:void 0},m=new Array(2),f=function(r){this._composite=new a(this),this._suspendCount=0,this._collections=t(r)?r.slice():[],this._collectionsCopy=[],this._id=e(),this._eventHash={},c(this),this._shouldRecomposite=!1};return r(f.prototype,{collectionChanged:{get:function(){return this._composite._collectionChanged}},id:{get:function(){return this._id}},values:{get:function(){return this._composite.values}}}),f.prototype.addCollection=function(e,r){var i=t(r);i?this._collections.splice(r,0,e):(r=this._collections.length,this._collections.push(e)),c(this)},f.prototype.removeCollection=function(e){var t=this._collections.indexOf(e);return-1!==t?(this._collections.splice(t,1),c(this),!0):!1},f.prototype.removeAllCollections=function(){this._collections.length=0,c(this)},f.prototype.containsCollection=function(e){return-1!==this._collections.indexOf(e)},f.prototype.contains=function(e){return this._composite.contains(e)},f.prototype.indexOfCollection=function(e){return this._collections.indexOf(e)},f.prototype.getCollection=function(e){return this._collections[e]},f.prototype.getCollectionsLength=function(){return this._collections.length},f.prototype.raiseCollection=function(e){var t=h(this._collections,e);d(this,t,t+1)},f.prototype.lowerCollection=function(e){var t=h(this._collections,e);d(this,t,t-1)},f.prototype.raiseCollectionToTop=function(e){var t=h(this._collections,e);t!==this._collections.length-1&&(this._collections.splice(t,1),this._collections.push(e),c(this))},f.prototype.lowerCollectionToBottom=function(e){var t=h(this._collections,e);0!==t&&(this._collections.splice(t,1),this._collections.splice(0,0,e),c(this))},f.prototype.suspendEvents=function(){this._suspendCount++,this._composite.suspendEvents()},f.prototype.resumeEvents=function(){this._suspendCount--,this._shouldRecomposite&&0===this._suspendCount&&(c(this),this._shouldRecomposite=!1),this._composite.resumeEvents()},f.prototype.computeAvailability=function(){return this._composite.computeAvailability()},f.prototype.getById=function(e){return this._composite.getById(e)},f.prototype._onCollectionChanged=function(e,r,i){var n=this._collectionsCopy,a=n.length,c=this._composite;c.suspendEvents();var h,d,m,f,v=i.length,_=this._eventHash,g=e.id;for(h=0;v>h;h++){var y=i[h];u(this,_,g,y);var C=y.id;for(d=a-1;d>=0;d--)m=n[d].getById(C),t(m)&&(t(f)||(f=c.getById(C),s(f)),f.merge(m));t(f)||c.removeById(C),f=void 0}var E=r.length;for(h=0;E>h;h++){var S=r[h];l(this,_,g,S);var w=S.id;for(d=a-1;d>=0;d--)m=n[d].getById(w),t(m)&&(t(f)||(f=c.getById(w),t(f)?s(f):(p.id=w,f=new o(p),c.add(f))),f.merge(m));f=void 0}c.resumeEvents()},f.prototype._onDefinitionChanged=function(e,r,i,n){for(var o=this._collections,a=this._composite,s=o.length,l=e.id,u=a.getById(l),c=u[r],h=!t(c),d=!0,p=s-1;p>=0;p--){var m=o[p].getById(e.id);if(t(m)){var f=m[r];if(t(f)){if(d){if(d=!1,!t(f.merge)||!t(f.clone)){c=f;break}c=f.clone(c)}c.merge(f)}}}h&&-1===u.propertyNames.indexOf(r)&&u.addProperty(r),u[r]=c},f}),r("DataSources/CompositeProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/EventHelper","../Core/TimeIntervalCollection","./Property"],function(e,t,r,i,n,o,a){"use strict";function s(t,r,i,n){var o=function(){i.raiseEvent(t)},a=[];r.removeAll();for(var s=n.length,l=0;s>l;l++){var u=n.get(l);e(u.data)&&-1===a.indexOf(u.data)&&r.add(u.data.definitionChanged,o)}}var l=function(){this._eventHelper=new n,this._definitionChanged=new i,this._intervals=new o,this._intervals.changedEvent.addEventListener(l.prototype._intervalsChanged,this)};return t(l.prototype,{isConstant:{get:function(){return this._intervals.isEmpty}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._intervals}}}),l.prototype.getValue=function(t,r){var i=this._intervals.findDataForIntervalContainingDate(t);return e(i)?i.getValue(t,r):void 0},l.prototype.equals=function(e){return this===e||e instanceof l&&this._intervals.equals(e._intervals,a.equals)},l.prototype._intervalsChanged=function(){s(this,this._eventHelper,this._definitionChanged,this._intervals),this._definitionChanged.raiseEvent(this)},l}),r("DataSources/CompositeMaterialProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./CompositeProperty","./Property"],function(e,t,r,i,n,o){"use strict";var a=function(){this._definitionChanged=new i,this._composite=new n,this._composite.definitionChanged.addEventListener(a.prototype._raiseDefinitionChanged,this)};return t(a.prototype,{isConstant:{get:function(){return this._composite.isConstant}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._composite._intervals}}}),a.prototype.getType=function(t){var r=this._composite._intervals.findDataForIntervalContainingDate(t);return e(r)?r.getType(t):void 0},a.prototype.getValue=function(t,r){var i=this._composite._intervals.findDataForIntervalContainingDate(t);return e(i)?i.getValue(t,r):void 0},a.prototype.equals=function(e){return this===e||e instanceof a&&this._composite.equals(e._composite,o.equals)},a.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},a}),r("DataSources/CompositePositionProperty",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","./CompositeProperty","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){this._referenceFrame=e(t,o.FIXED),this._definitionChanged=new n,this._composite=new a,this._composite.definitionChanged.addEventListener(l.prototype._raiseDefinitionChanged,this)};return r(l.prototype,{isConstant:{get:function(){return this._composite.isConstant}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._composite.intervals}},referenceFrame:{get:function(){return this._referenceFrame},set:function(e){this._referenceFrame=e}}}),l.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,o.FIXED,t)},l.prototype.getValueInReferenceFrame=function(e,r,i){var n=this._composite._intervals.findDataForIntervalContainingDate(e);return t(n)?n.getValueInReferenceFrame(e,r,i):void 0},l.prototype.equals=function(e){return this===e||e instanceof l&&this._referenceFrame===e._referenceFrame&&this._composite.equals(e._composite,s.equals)},l.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},l}),r("DataSources/CorridorGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/CorridorGeometry","../Core/CorridorOutlineGeometry","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.positions=void 0,this.width=void 0,this.cornerType=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"corridor",e.corridor,void 0)};a(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),a(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!o(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(i){var n,a,s=this._entity,l=s.isAvailable(i),u=new d(l&&s.isShowing&&this._showProperty.getValue(i)&&this._fillProperty.getValue(i));if(this._materialProperty instanceof v){var h=e.WHITE;o(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(h=this._materialProperty.color.getValue(i)),a=t.fromColor(h),n={show:u,color:a}}else n={show:u};return new c({id:s,geometry:new r(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var n=this._entity,o=n.isAvailable(r),a=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new c({id:n,geometry:new i(this._options),attributes:{show:new d(o&&n.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(a)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),s(this)},A.prototype._onEntityPropertyChanged=function(e,t,r,i){if("availability"===t||"corridor"===t){var a=this._entity.corridor;if(!o(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=o(s)&&s.isConstant?s.getValue(h.MINIMUM_VALUE):!0,u=a.outline,c=o(u);if(c&&u.isConstant&&(c=u.getValue(h.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.positions,f=a.show;if(o(f)&&f.isConstant&&!f.getValue(h.MINIMUM_VALUE)||!o(d))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=n(a.material,E),g=_ instanceof v;this._materialProperty=_,this._fillProperty=n(s,w),this._showProperty=n(f,S),this._showOutlineProperty=n(a.outline,T),this._outlineColorProperty=c?n(a.outlineColor,b):void 0;var y=a.height,x=a.extrudedHeight,P=a.granularity,A=a.width,I=a.outlineWidth,M=a.cornerType;if(this._isClosed=o(x),this._fillEnabled=l,this._outlineEnabled=c,d.isConstant&&C.isConstant(y)&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)&&C.isConstant(I)&&C.isConstant(M)){var D=this._options;D.vertexFormat=g?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,D.positions=d.getValue(h.MINIMUM_VALUE,D.positions),D.height=o(y)?y.getValue(h.MINIMUM_VALUE):void 0,D.extrudedHeight=o(x)?x.getValue(h.MINIMUM_VALUE):void 0,D.granularity=o(P)?P.getValue(h.MINIMUM_VALUE):void 0,D.width=o(A)?A.getValue(h.MINIMUM_VALUE):void 0,D.cornerType=o(M)?M.getValue(h.MINIMUM_VALUE):void 0,this._outlineWidth=o(I)?I.getValue(h.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(n){var a=this._primitives;a.removeAndDestroy(this._primitive),a.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var s=this._geometryUpdater,l=s._entity,u=l.corridor;if(l.isShowing&&l.isAvailable(n)&&C.getValueOrDefault(u.show,n,!0)){var h=this._options,d=C.getValueOrUndefined(u.positions,n,h.positions),v=C.getValueOrUndefined(u.width,n);if(o(d)&&o(v)){if(h.positions=d,h.width=v,h.height=C.getValueOrUndefined(u.height,n),h.extrudedHeight=C.getValueOrUndefined(u.extrudedHeight,n),h.granularity=C.getValueOrUndefined(u.granularity,n),h.cornerType=C.getValueOrUndefined(u.cornerType,n),!o(u.fill)||u.fill.getValue(n)){var _=y.getValue(n,s.fillMaterialProperty,this._material);this._material=_;var g=new p({material:_,translucent:_.isTranslucent(),closed:o(h.extrudedHeight)});h.vertexFormat=g.vertexFormat,this._primitive=a.add(new f({geometryInstances:new c({id:l,geometry:new r(h)}),appearance:g,asynchronous:!1}))}if(o(u.outline)&&u.outline.getValue(n)){h.vertexFormat=m.VERTEX_FORMAT;var E=C.getValueOrClonedDefault(u.outlineColor,n,e.BLACK,x),S=C.getValueOrDefault(u.outlineWidth,n,1),w=1!==E.alpha;this._outlinePrimitive=a.add(new f({geometryInstances:new c({id:l,geometry:new i(h),attributes:{color:t.fromColor(E)}}),appearance:new m({flat:!0,translucent:w,renderState:{lineWidth:s._scene.clampLineWidth(S)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),s(this)},A}),r("DataSources/DataSource",["../Core/defineProperties","../Core/DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return e(r.prototype,{name:{get:t.throwInstantiationError},clock:{get:t.throwInstantiationError},entities:{get:t.throwInstantiationError},isLoading:{get:t.throwInstantiationError},changedEvent:{get:t.throwInstantiationError},errorEvent:{get:t.throwInstantiationError},loadingEvent:{get:t.throwInstantiationError}}),r.prototype.update=t.throwInstantiationError,r.setLoading=function(e,t){e._isLoading!==t&&(t?e._entityCollection.suspendEvents():e._entityCollection.resumeEvents(),e._isLoading=t,e._loading.raiseEvent(e,t))},r}),r("DataSources/CustomDataSource",["../Core/defineProperties","../Core/Event","./DataSource","./EntityCollection"],function(e,t,r,i){"use strict";var n=function(e){this._name=e,this._clock=void 0,this._changed=new t,this._error=new t,this._isLoading=!1,this._loading=new t,this._entityCollection=new i(this)};return e(n.prototype,{name:{get:function(){return this._name},set:function(e){this._name!==e&&(this._name=e,this._changed.raiseEvent(this))}},clock:{get:function(){return this._clock},set:function(e){this._clock!==e&&(this._clock=e,this._changed.raiseEvent(this))}},entities:{get:function(){return this._entityCollection}},isLoading:{get:function(){return this._isLoading},set:function(e){r.setLoading(this,e)}},changedEvent:{get:function(){return this._changed}},errorEvent:{get:function(){return this._error}},loadingEvent:{get:function(){return this._loading}}}),n}),r("DataSources/CylinderGeometryUpdater",["../Core/Cartesian3","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/CylinderGeometry","../Core/CylinderOutlineGeometry","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";var S=new _(t.WHITE),w=new g(!0),T=new g(!0),b=new g(!1),x=new g(t.BLACK),P=new t,A=function(e){this.id=e,this.vertexFormat=void 0,this.length=void 0,this.topRadius=void 0,this.bottomRadius=void 0,this.slices=void 0,this.numberOfVerticalLines=void 0},I=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(I.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new c,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new A(e),this._onEntityPropertyChanged(e,"cylinder",e.cylinder,void 0)};s(I,{perInstanceColorAppearanceType:{value:f},materialAppearanceType:{value:m}}),s(I.prototype,{entity:{get:function(){return this._entity}}, -fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!a(this._entity.availability)&&E.isConstant(this._showProperty)&&E.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!a(this._entity.availability)&&E.isConstant(this._showProperty)&&E.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),I.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},I.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},I.prototype.createFillGeometryInstance=function(e){var n,o,s=this._entity,l=s.isAvailable(e),u=new p(l&&s.isShowing&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e));if(this._materialProperty instanceof _){var c=t.WHITE;a(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(c=this._materialProperty.color.getValue(e)),o=r.fromColor(c),n={show:u,color:o}}else n={show:u};return new h({id:s,geometry:new i(this._options),modelMatrix:s._getModelMatrix(d.MINIMUM_VALUE),attributes:n})},I.prototype.createOutlineGeometryInstance=function(e){var i=this._entity,o=i.isAvailable(e),a=E.getValueOrDefault(this._outlineColorProperty,e,t.BLACK);return new h({id:i,geometry:new n(this._options),modelMatrix:i._getModelMatrix(d.MINIMUM_VALUE),attributes:{show:new p(o&&i.isShowing&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)),color:r.fromColor(a)}})},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){this._entitySubscription(),l(this)},I.prototype._onEntityPropertyChanged=function(e,t,r,i){if("availability"===t||"position"===t||"orientation"===t||"cylinder"===t){var n=e.cylinder;if(!a(n))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=n.fill,l=a(s)&&s.isConstant?s.getValue(d.MINIMUM_VALUE):!0,u=n.outline,c=a(u);if(c&&u.isConstant&&(c=u.getValue(d.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var h=e.position,p=n.length,v=n.topRadius,g=n.bottomRadius,y=n.show;if(a(y)&&y.isConstant&&!y.getValue(d.MINIMUM_VALUE)||!a(h)||!a(p)||!a(v)||!a(g))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var C=o(n.material,S),P=C instanceof _;this._materialProperty=C,this._fillProperty=o(s,T),this._showProperty=o(y,w),this._showOutlineProperty=o(n.outline,b),this._outlineColorProperty=c?o(n.outlineColor,x):void 0;var A=n.slices,I=n.outlineWidth,M=n.numberOfVerticalLines;if(this._fillEnabled=l,this._outlineEnabled=c,h.isConstant&&E.isConstant(e.orientation)&&p.isConstant&&v.isConstant&&g.isConstant&&E.isConstant(A)&&E.isConstant(I)&&E.isConstant(M)){var D=this._options;D.vertexFormat=P?f.VERTEX_FORMAT:m.MaterialSupport.TEXTURED.vertexFormat,D.length=p.getValue(d.MINIMUM_VALUE),D.topRadius=v.getValue(d.MINIMUM_VALUE),D.bottomRadius=g.getValue(d.MINIMUM_VALUE),D.slices=a(A)?A.getValue(d.MINIMUM_VALUE):void 0,D.numberOfVerticalLines=a(M)?M.getValue(d.MINIMUM_VALUE):void 0,this._outlineWidth=a(I)?I.getValue(d.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},I.prototype.createDynamicUpdater=function(e){return new M(e,this)};var M=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new A(t._entity)};return M.prototype.update=function(e){var o=this._primitives;o.removeAndDestroy(this._primitive),o.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var s=this._geometryUpdater,l=s._entity,u=l.cylinder;if(l.isShowing&&l.isAvailable(e)&&E.getValueOrDefault(u.show,e,!0)){var c=this._options,d=l._getModelMatrix(e),p=E.getValueOrUndefined(u.length,e),_=E.getValueOrUndefined(u.topRadius,e),g=E.getValueOrUndefined(u.bottomRadius,e);if(a(d)&&a(p)&&a(_)&&a(g)){if(c.length=p,c.topRadius=_,c.bottomRadius=g,c.slices=E.getValueOrUndefined(u.slices,e),c.numberOfVerticalLines=E.getValueOrUndefined(u.numberOfVerticalLines,e),E.getValueOrDefault(u.fill,e,!0)){var y=C.getValue(e,s.fillMaterialProperty,this._material);this._material=y;var S=new m({material:y,translucent:y.isTranslucent(),closed:!0});c.vertexFormat=S.vertexFormat,this._primitive=o.add(new v({geometryInstances:new h({id:l,geometry:new i(c),modelMatrix:d}),appearance:S,asynchronous:!1}))}if(E.getValueOrDefault(u.outline,e,!1)){c.vertexFormat=f.VERTEX_FORMAT;var w=E.getValueOrClonedDefault(u.outlineColor,e,t.BLACK,P),T=E.getValueOrDefault(u.outlineWidth,e,1),b=1!==w.alpha;this._outlinePrimitive=o.add(new v({geometryInstances:new h({id:l,geometry:new n(c),modelMatrix:d,attributes:{color:r.fromColor(w)}}),appearance:new f({flat:!0,translucent:b,renderState:{lineWidth:s._scene.clampLineWidth(T)}}),asynchronous:!1}))}}}},M.prototype.getBoundingSphere=function(e,t){return y(e,this._primitive,this._outlinePrimitive,t)},M.prototype.isDestroyed=function(){return!1},M.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),l(this)},I}),r("Scene/LabelStyle",["../Core/freezeObject"],function(e){"use strict";var t={FILL:0,OUTLINE:1,FILL_AND_OUTLINE:2};return e(t)}),r("DataSources/DataSourceClock",["../Core/Clock","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/JulianDate","./createRawPropertyDescriptor"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(){this._startTime=void 0,this._stopTime=void 0,this._currentTime=void 0,this._clockRange=void 0,this._clockStep=void 0,this._multiplier=void 0,this._definitionChanged=new o};return i(l.prototype,{definitionChanged:{get:function(){return this._definitionChanged}},startTime:s("startTime"),stopTime:s("stopTime"),currentTime:s("currentTime"),clockRange:s("clockRange"),clockStep:s("clockStep"),multiplier:s("multiplier")}),l.prototype.clone=function(e){return r(e)||(e=new l),e.startTime=this.startTime,e.stopTime=this.stopTime,e.currentTime=this.currentTime,e.clockRange=this.clockRange,e.clockStep=this.clockStep,e.multiplier=this.multiplier,e},l.prototype.equals=function(e){return this===e||r(e)&&a.equals(this.startTime,e.startTime)&&a.equals(this.stopTime,e.stopTime)&&a.equals(this.currentTime,e.currentTime)&&this.clockRange===e.clockRange&&this.clockStep===e.clockStep&&this.multiplier===e.multiplier},l.prototype.merge=function(e){this.startTime=t(this.startTime,e.startTime),this.stopTime=t(this.stopTime,e.stopTime),this.currentTime=t(this.currentTime,e.currentTime),this.clockRange=t(this.clockRange,e.clockRange),this.clockStep=t(this.clockStep,e.clockStep),this.multiplier=t(this.multiplier,e.multiplier)},l.prototype.getValue=function(t){return r(t)||(t=new e),t.startTime=this.startTime,t.stopTime=this.stopTime,t.clockRange=this.clockRange,t.clockStep=this.clockStep,t.multiplier=this.multiplier,t.currentTime=this.currentTime,t},l}),r("DataSources/GridMaterialProperty",["../Core/Cartesian2","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=t.WHITE,u=.1,c=new e(8,8),h=new e(0,0),d=new e(1,1),p=function(e){e=r(e,r.EMPTY_OBJECT),this._definitionChanged=new o,this._color=void 0,this._colorSubscription=void 0,this._cellAlpha=void 0,this._cellAlphaSubscription=void 0,this._lineCount=void 0,this._lineCountSubscription=void 0,this._lineThickness=void 0,this._lineThicknessSubscription=void 0,this._lineOffset=void 0,this._lineOffsetSubscription=void 0,this.color=e.color,this.cellAlpha=e.cellAlpha,this.lineCount=e.lineCount,this.lineThickness=e.lineThickness,this.lineOffset=e.lineOffset};return n(p.prototype,{isConstant:{get:function(){return s.isConstant(this._color)&&s.isConstant(this._cellAlpha)&&s.isConstant(this._lineCount)&&s.isConstant(this._lineThickness)&&s.isConstant(this._lineOffset)}},definitionChanged:{get:function(){return this._definitionChanged}},color:a("color"),cellAlpha:a("cellAlpha"),lineCount:a("lineCount"),lineThickness:a("lineThickness"),lineOffset:a("lineOffset")}),p.prototype.getType=function(e){return"Grid"},p.prototype.getValue=function(e,t){return i(t)||(t={}),t.color=s.getValueOrClonedDefault(this._color,e,l,t.color),t.cellAlpha=s.getValueOrDefault(this._cellAlpha,e,u),t.lineCount=s.getValueOrClonedDefault(this._lineCount,e,c,t.lineCount),t.lineThickness=s.getValueOrClonedDefault(this._lineThickness,e,d,t.lineThickness),t.lineOffset=s.getValueOrClonedDefault(this._lineOffset,e,h,t.lineOffset),t},p.prototype.equals=function(e){return this===e||e instanceof p&&s.equals(this._color,e._color)&&s.equals(this._cellAlpha,e._cellAlpha)&&s.equals(this._lineCount,e._lineCount)&&s.equals(this._lineThickness,e._lineThickness)&&s.equals(this._lineOffset,e._lineOffset)},p}),r("DataSources/PolylineGlowMaterialProperty",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=e.WHITE,l=.25,u=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this._glowPower=void 0,this._glowPowerSubscription=void 0,this.color=e.color,this.glowPower=e.glowPower};return i(u.prototype,{isConstant:{get:function(){return a.isConstant(this._color)&&a.isConstant(this._glow)}},definitionChanged:{get:function(){return this._definitionChanged}},color:o("color"),glowPower:o("glowPower")}),u.prototype.getType=function(e){return"PolylineGlow"},u.prototype.getValue=function(e,t){return r(t)||(t={}),t.color=a.getValueOrClonedDefault(this._color,e,s,t.color),t.glowPower=a.getValueOrDefault(this._glowPower,e,l,t.glowPower),t},u.prototype.equals=function(e){return this===e||e instanceof u&&a.equals(this._color,e._color)&&a.equals(this._glowPower,e._glowPower)},u}),r("DataSources/PolylineOutlineMaterialProperty",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=e.WHITE,l=e.BLACK,u=1,c=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this._outlineColor=void 0,this._outlineColorSubscription=void 0,this._outlineWidth=void 0,this._outlineWidthSubscription=void 0,this.color=e.color,this.outlineColor=e.outlineColor,this.outlineWidth=e.outlineWidth};return i(c.prototype,{isConstant:{get:function(){return a.isConstant(this._color)&&a.isConstant(this._outlineColor)&&a.isConstant(this._outlineWidth)}},definitionChanged:{get:function(){return this._definitionChanged}},color:o("color"),outlineColor:o("outlineColor"),outlineWidth:o("outlineWidth")}),c.prototype.getType=function(e){return"PolylineOutline"},c.prototype.getValue=function(e,t){return r(t)||(t={}),t.color=a.getValueOrClonedDefault(this._color,e,s,t.color),t.outlineColor=a.getValueOrClonedDefault(this._outlineColor,e,l,t.outlineColor),t.outlineWidth=a.getValueOrDefault(this._outlineWidth,e,u),t},c.prototype.equals=function(e){return this===e||e instanceof c&&a.equals(this._color,e._color)&&a.equals(this._outlineColor,e._outlineColor)&&a.equals(this._outlineWidth,e._outlineWidth)},c}),r("DataSources/PositionPropertyArray",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/EventHelper","../Core/ReferenceFrame","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t,r){this._value=void 0,this._definitionChanged=new n,this._eventHelper=new o,this._referenceFrame=e(r,a.FIXED),this.setValue(t)};return r(l.prototype,{isConstant:{get:function(){var e=this._value;if(!t(e))return!0;for(var r=e.length,i=0;r>i;i++)if(!s.isConstant(e[i]))return!1;return!0}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return this._referenceFrame}}}),l.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,a.FIXED,t)},l.prototype.getValueInReferenceFrame=function(e,r,i){var n=this._value;if(!t(n))return void 0;var o=n.length;t(i)||(i=new Array(o));for(var a=0,s=0;o>a;){var l=n[a],u=l.getValueInReferenceFrame(e,r,i[a]);t(u)&&(i[s]=u,s++),a++}return i.length=s,i},l.prototype.setValue=function(e){var r=this._eventHelper;if(r.removeAll(),t(e)){this._value=e.slice();for(var i=e.length,n=0;i>n;n++){var o=e[n];t(o)&&r.add(o.definitionChanged,l.prototype._raiseDefinitionChanged,this)}}else this._value=void 0;this._definitionChanged.raiseEvent(this)},l.prototype.equals=function(e){return this===e||e instanceof l&&this._referenceFrame===e._referenceFrame&&s.arrayEquals(this._value,e._value)},l.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},l}),r("DataSources/ReferenceProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/RuntimeError","./Property"],function(e,t,r,i,n,o){"use strict";function a(t){var r=!0;if(t._resolveEntity){var i=t._targetCollection.getById(t._targetId);if(e(i)?(i.definitionChanged.addEventListener(l.prototype._onTargetEntityDefinitionChanged,t),t._targetEntity=i,t._resolveEntity=!1):(i=t._targetEntity,r=!1),!e(i))throw new n('target entity "'+t._targetId+'" could not be resolved.')}return r}function s(t){var r=t._targetProperty;if(t._resolveProperty){var i=a(t),o=t._targetPropertyNames;r=t._targetEntity;for(var s=o.length,l=0;s>l&&e(r);l++)r=r[o[l]];if(e(r))t._targetProperty=r,t._resolveProperty=!i;else if(!e(t._targetProperty))throw new n('targetProperty "'+t._targetId+"."+o.join(".")+'" could not be resolved.')}return r}var l=function(e,t,r){this._targetCollection=e,this._targetId=t,this._targetPropertyNames=r,this._targetProperty=void 0,this._targetEntity=void 0,this._definitionChanged=new i,this._resolveEntity=!0,this._resolveProperty=!0,e.collectionChanged.addEventListener(l.prototype._onCollectionChanged,this)};return t(l.prototype,{isConstant:{get:function(){return o.isConstant(s(this))}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return s(this).referenceFrame}},targetId:{get:function(){return this._targetId}},targetCollection:{get:function(){return this._targetCollection}},targetPropertyNames:{get:function(){return this._targetPropertyNames}},resolvedProperty:{get:function(){return s(this)}}}),l.fromString=function(e,t){for(var r,i=[],n=!0,o=!1,a="",s=0;s<t.length;++s){var u=t.charAt(s);o?(a+=u,o=!1):"\\"===u?o=!0:n&&"#"===u?(r=a,n=!1,a=""):n||"."!==u?a+=u:(i.push(a),a="")}return i.push(a),new l(e,r,i)},l.prototype.getValue=function(e,t){return s(this).getValue(e,t)},l.prototype.getValueInReferenceFrame=function(e,t,r){return s(this).getValueInReferenceFrame(e,t,r)},l.prototype.getType=function(e){return s(this).getType(e)},l.prototype.equals=function(e){if(this===e)return!0;var t=this._targetPropertyNames,r=e._targetPropertyNames;if(this._targetCollection!==e._targetCollection||this._targetId!==e._targetId||t.length!==r.length)return!1;for(var i=this._targetPropertyNames.length,n=0;i>n;n++)if(t[n]!==r[n])return!1;return!0},l.prototype._onTargetEntityDefinitionChanged=function(e,t,r,i){this._targetPropertyNames[0]===t&&(this._resolveProperty=!0,this._definitionChanged.raiseEvent(this))},l.prototype._onCollectionChanged=function(t,r,i){var n=this._targetEntity;e(n)&&(-1!==i.indexOf(n)?(n.definitionChanged.removeEventListener(l.prototype._onTargetEntityDefinitionChanged,this),this._resolveEntity=!0,this._resolveProperty=!0):this._resolveEntity&&(s(this),this._resolveEntity||this._definitionChanged.raiseEvent(this)))},l}),r("DataSources/Rotation",["../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/Math"],function(e,t,r,i){"use strict";var n={packedLength:1,pack:function(t,r,i){i=e(i,0),r[i]=t},unpack:function(t,r,i){return r=e(r,0),t[r]},convertPackedArrayForInterpolation:function(t,r,n,o){r=e(r,0),n=e(n,t.length);for(var a,s=0,l=n-r+1;l>s;s++){var u=t[r+s];0===s||Math.abs(a-u)<Math.PI?o[s]=u:o[s]=u-i.TWO_PI,a=u}},unpackInterpolationResult:function(e,t,r,n,o){return o=e[0],0>o?o+i.TWO_PI:o}};return n}),r("DataSources/SampledProperty",["../Core/binarySearch","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ExtrapolationType","../Core/JulianDate","../Core/LinearApproximation"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,t,r){var i,n=e.length,o=r.length,a=n+o;if(e.length=a,n!==t){var s=n-1;for(i=a-1;i>=t;i--)e[i]=e[s--]}for(i=0;o>i;i++)e[t++]=r[i]}function c(e,t){return e instanceof s?e:"string"==typeof e?s.fromIso8601(e):s.addSeconds(t,e,new s)}var h={packedLength:1,pack:function(e,r,i){i=t(i,0),r[i]=e},unpack:function(e,r,i){return r=t(r,0),e[r]}},d=[],p=[],m=function(t,i,n,o,a){for(var l,h,m,f,v,_,g=0;g<o.length;){v=c(o[g],t),m=e(i,v,s.compare);var y=0,C=0;if(0>m){for(m=~m,f=m*a,h=void 0,_=i[m];g<o.length&&(v=c(o[g],t),!(r(h)&&s.compare(h,v)>=0||r(_)&&s.compare(v,_)>=0));){for(d[y++]=v,g+=1,l=0;a>l;l++)p[C++]=o[g],g+=1;h=v}y>0&&(p.length=C,u(n,f,p),d.length=y,u(i,m,d))}else{for(l=0;a>l;l++)g++,n[m*a+l]=o[g];g++}}},f=function(e,i){var n=e;n===Number&&(n=h);var s,u=n.packedLength,c=t(n.packedInterpolationLength,u),d=0;if(r(i)){var p=i.length;s=new Array(p);for(var m=0;p>m;m++){var f=i[m];f===Number&&(f=h);var v=f.packedLength;u+=v,c+=t(f.packedInterpolationLength,v),s[m]=f}d=p}this._type=e,this._innerType=n,this._interpolationDegree=1,this._interpolationAlgorithm=l,this._numberOfPoints=0,this._times=[],this._values=[],this._xTable=[],this._yTable=[],this._packedLength=u,this._packedInterpolationLength=c,this._updateTableLength=!0,this._interpolationResult=new Array(c),this._definitionChanged=new o,this._derivativeTypes=i,this._innerDerivativeTypes=s,this._inputOrder=d,this._forwardExtrapolationType=a.NONE,this._forwardExtrapolationDuration=0,this._backwardExtrapolationType=a.NONE,this._backwardExtrapolationDuration=0};return i(f.prototype,{isConstant:{get:function(){return 0===this._values.length}},definitionChanged:{get:function(){return this._definitionChanged}},type:{get:function(){return this._type}},derivativeTypes:{get:function(){return this._derivativeTypes}},interpolationDegree:{get:function(){return this._interpolationDegree}},interpolationAlgorithm:{get:function(){return this._interpolationAlgorithm}},forwardExtrapolationType:{get:function(){return this._forwardExtrapolationType},set:function(e){this._forwardExtrapolationType!==e&&(this._forwardExtrapolationType=e,this._definitionChanged.raiseEvent(this))}},forwardExtrapolationDuration:{get:function(){return this._forwardExtrapolationDuration},set:function(e){this._forwardExtrapolationDuration!==e&&(this._forwardExtrapolationDuration=e,this._definitionChanged.raiseEvent(this))}},backwardExtrapolationType:{get:function(){return this._backwardExtrapolationType},set:function(e){this._backwardExtrapolationType!==e&&(this._backwardExtrapolationType=e,this._definitionChanged.raiseEvent(this))}},backwardExtrapolationDuration:{get:function(){return this._backwardExtrapolationDuration},set:function(e){this._backwardExtrapolationDuration!==e&&(this._backwardExtrapolationDuration=e,this._definitionChanged.raiseEvent(this))}}}),f.prototype.getValue=function(t,i){var n=this._times,o=n.length;if(0===o)return void 0;var l,u=this._innerType,c=this._values,h=e(n,t,s.compare);if(0>h){if(h=~h,0===h){var d=n[h];if(l=this._backwardExtrapolationDuration,this._backwardExtrapolationType===a.NONE||0!==l&&s.secondsDifference(d,t)>l)return void 0;if(this._backwardExtrapolationType===a.HOLD)return u.unpack(c,0,i)}if(h>=o){h=o-1;var p=n[h];if(l=this._forwardExtrapolationDuration,this._forwardExtrapolationType===a.NONE||0!==l&&s.secondsDifference(t,p)>l)return void 0;if(this._forwardExtrapolationType===a.HOLD)return h=o-1,u.unpack(c,h*u.packedLength,i)}var m=this._xTable,f=this._yTable,v=this._interpolationAlgorithm,_=this._packedInterpolationLength,g=this._inputOrder;if(this._updateTableLength){this._updateTableLength=!1;var y=Math.min(v.getRequiredDataPoints(this._interpolationDegree,g),o);y!==this._numberOfPoints&&(this._numberOfPoints=y,m.length=y,f.length=y*_)}var C=this._numberOfPoints-1;if(1>C)return void 0;var E=0,S=o-1,w=S-E+1;if(C+1>w);else{var T=h-(C/2|0)-1;E>T&&(T=E);var b=T+C;b>S&&(b=S,T=b-C,E>T&&(T=E)),E=T,S=b}for(var x=S-E+1,P=0;x>P;++P)m[P]=s.secondsDifference(n[E+P],n[S]);if(r(u.convertPackedArrayForInterpolation))u.convertPackedArrayForInterpolation(c,E,S,f);else for(var A=0,I=this._packedLength,M=E*I,D=(S+1)*I;D>M;)f[A]=c[M],M++,A++;var R,O=s.secondsDifference(t,n[S]);if(0!==g&&r(v.interpolate)){var N=Math.floor(_/(g+1));R=v.interpolate(O,m,f,N,g,g,this._interpolationResult)}else R=v.interpolateOrderZero(O,m,f,_,this._interpolationResult);return r(u.unpackInterpolationResult)?u.unpackInterpolationResult(R,c,E,S,i):u.unpack(R,0,i)}return u.unpack(c,h*this._packedLength,i)},f.prototype.setInterpolationOptions=function(e){var t=!1,r=e.interpolationAlgorithm,i=e.interpolationDegree;this._interpolationAlgorithm!==r&&(this._interpolationAlgorithm=r,t=!0),this._interpolationDegree!==i&&(this._interpolationDegree=i,t=!0),t&&(this._updateTableLength=!0,this._definitionChanged.raiseEvent(this))},f.prototype.addSample=function(e,t,i){var n=this._innerDerivativeTypes,o=r(n),a=this._innerType,s=[];if(s.push(e),a.pack(t,s,s.length),o)for(var l=n.length,u=0;l>u;u++)n[u].pack(i[u],s,s.length);m(void 0,this._times,this._values,s,this._packedLength),this._updateTableLength=!0,this._definitionChanged.raiseEvent(this)},f.prototype.addSamples=function(e,t,i){for(var n=this._innerDerivativeTypes,o=r(n),a=this._innerType,s=e.length,l=[],u=0;s>u;u++)if(l.push(e[u]),a.pack(t[u],l,l.length),o)for(var c=i[u],h=n.length,d=0;h>d;d++)n[d].pack(c[d],l,l.length);m(void 0,this._times,this._values,l,this._packedLength),this._updateTableLength=!0,this._definitionChanged.raiseEvent(this)},f.prototype.addSamplesPackedArray=function(e,t){m(t,this._times,this._values,e,this._packedLength),this._updateTableLength=!0,this._definitionChanged.raiseEvent(this)},f.prototype.equals=function(e){if(this===e)return!0;if(!r(e))return!1;if(this._type!==e._type||this._interpolationDegree!==e._interpolationDegree||this._interpolationAlgorithm!==e._interpolationAlgorithm)return!1;var t=this._derivativeTypes,i=r(t),n=e._derivativeTypes,o=r(n);if(i!==o)return!1;var a,l;if(i){if(l=t.length,l!==n.length)return!1;for(a=0;l>a;a++)if(t[a]!==n[a])return!1}var u=this._times,c=e._times;if(l=u.length,l!==c.length)return!1;for(a=0;l>a;a++)if(!s.equals(u[a],c[a]))return!1;var h=this._values,d=e._values;for(a=0;l>a;a++)if(h[a]!==d[a])return!1;return!0},f._mergeNewSamples=m,f}),r("DataSources/SampledPositionProperty",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","./PositionProperty","./Property","./SampledProperty"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(r,i){i=t(i,0);var n;if(i>0){n=new Array(i);for(var s=0;i>s;s++)n[s]=e}this._numberOfDerivatives=i,this._property=new u(e,n),this._definitionChanged=new o,this._referenceFrame=t(r,a.FIXED),this._property._definitionChanged.addEventListener(function(){this._definitionChanged.raiseEvent(this)},this)};return i(c.prototype,{isConstant:{get:function(){return this._property.isConstant}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return this._referenceFrame}},interpolationDegree:{get:function(){return this._property.interpolationDegree}},interpolationAlgorithm:{get:function(){return this._property.interpolationAlgorithm}},numberOfDerivatives:{get:function(){return this._numberOfDerivatives}},forwardExtrapolationType:{get:function(){return this._property.forwardExtrapolationType},set:function(e){this._property.forwardExtrapolationType=e}},forwardExtrapolationDuration:{get:function(){return this._property.forwardExtrapolationDuration},set:function(e){this._property.forwardExtrapolationDuration=e}},backwardExtrapolationType:{get:function(){return this._property.backwardExtrapolationType},set:function(e){this._property.backwardExtrapolationType=e}},backwardExtrapolationDuration:{get:function(){return this._property.backwardExtrapolationDuration},set:function(e){this._property.backwardExtrapolationDuration=e}}}),c.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,a.FIXED,t)},c.prototype.getValueInReferenceFrame=function(e,t,i){return i=this._property.getValue(e,i),r(i)?s.convertToReferenceFrame(e,i,this._referenceFrame,t,i):void 0},c.prototype.setInterpolationOptions=function(e){this._property.setInterpolationOptions(e)},c.prototype.addSample=function(e,t,r){this._numberOfDerivatives;this._property.addSample(e,t,r)},c.prototype.addSamples=function(e,t,r){this._property.addSamples(e,t,r)},c.prototype.addSamplesPackedArray=function(e,t){this._property.addSamplesPackedArray(e,t)},c.prototype.equals=function(e){return this===e||e instanceof c&&l.equals(this._property,e._property)&&this._referenceFrame===e._referenceFrame},c}),r("DataSources/StripeOrientation",["../Core/freezeObject"],function(e){"use strict";var t={HORIZONTAL:0,VERTICAL:1};return e(t)}),r("DataSources/StripeMaterialProperty",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","./createPropertyDescriptor","./Property","./StripeOrientation"],function(e,t,r,i,n,o,a,s){"use strict";var l=s.HORIZONTAL,u=e.WHITE,c=e.BLACK,h=0,d=1,p=function(e){e=t(e,t.EMPTY_OBJECT),this._definitionChanged=new n,this._orientation=void 0,this._orientationSubscription=void 0,this._evenColor=void 0,this._evenColorSubscription=void 0,this._oddColor=void 0,this._oddColorSubscription=void 0,this._offset=void 0,this._offsetSubscription=void 0,this._repeat=void 0,this._repeatSubscription=void 0,this.orientation=e.orientation,this.evenColor=e.evenColor,this.oddColor=e.oddColor,this.offset=e.offset,this.repeat=e.repeat};return i(p.prototype,{isConstant:{get:function(){return a.isConstant(this._orientation)&&a.isConstant(this._evenColor)&&a.isConstant(this._oddColor)&&a.isConstant(this._offset)&&a.isConstant(this._repeat)}},definitionChanged:{get:function(){return this._definitionChanged}},orientation:o("orientation"),evenColor:o("evenColor"),oddColor:o("oddColor"),offset:o("offset"),repeat:o("repeat")}),p.prototype.getType=function(e){return"Stripe"},p.prototype.getValue=function(e,t){return r(t)||(t={}),t.horizontal=a.getValueOrDefault(this._orientation,e,l)===s.HORIZONTAL,t.evenColor=a.getValueOrClonedDefault(this._evenColor,e,u,t.evenColor),t.oddColor=a.getValueOrClonedDefault(this._oddColor,e,c,t.oddColor),t.offset=a.getValueOrDefault(this._offset,e,h),t.repeat=a.getValueOrDefault(this._repeat,e,d),t},p.prototype.equals=function(e){return this===e||e instanceof p&&a.equals(this._orientation,e._orientation)&&a.equals(this._evenColor,e._evenColor)&&a.equals(this._oddColor,e._oddColor)&&a.equals(this._offset,e._offset)&&a.equals(this._repeat,e._repeat)},p}),r("DataSources/TimeIntervalCollectionPositionProperty",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/ReferenceFrame","../Core/TimeIntervalCollection","./PositionProperty","./Property"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(t){this._definitionChanged=new n,this._intervals=new a,this._intervals.changedEvent.addEventListener(u.prototype._intervalsChanged,this),this._referenceFrame=e(t,o.FIXED)};return r(u.prototype,{isConstant:{get:function(){return this._intervals.isEmpty}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._intervals}},referenceFrame:{get:function(){return this._referenceFrame}}}),u.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,o.FIXED,t)},u.prototype.getValueInReferenceFrame=function(e,r,i){var n=this._intervals.findDataForIntervalContainingDate(e);return t(n)?s.convertToReferenceFrame(e,n,this._referenceFrame,r,i):void 0},u.prototype.equals=function(e){return this===e||e instanceof u&&this._intervals.equals(e._intervals,l.equals)&&this._referenceFrame===e._referenceFrame},u.prototype._intervalsChanged=function(){this._definitionChanged.raiseEvent(this)},u}),r("DataSources/TimeIntervalCollectionProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/TimeIntervalCollection","./Property"],function(e,t,r,i,n,o){"use strict";var a=function(){this._definitionChanged=new i,this._intervals=new n,this._intervals.changedEvent.addEventListener(a.prototype._intervalsChanged,this)};return t(a.prototype,{isConstant:{get:function(){return this._intervals.isEmpty}},definitionChanged:{get:function(){return this._definitionChanged}},intervals:{get:function(){return this._intervals}}}),a.prototype.getValue=function(t,r){var i=this._intervals.findDataForIntervalContainingDate(t);return e(i)&&"function"==typeof i.clone?i.clone(r):i},a.prototype.equals=function(e){return this===e||e instanceof a&&this._intervals.equals(e._intervals,o.equals)},a.prototype._intervalsChanged=function(){this._definitionChanged.raiseEvent(this)},a}),r("DataSources/CzmlDataSource",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/ClockRange","../Core/ClockStep","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/ExtrapolationType","../Core/getFilenameFromUri","../Core/HermitePolynomialApproximation","../Core/isArray","../Core/Iso8601","../Core/JulianDate","../Core/LagrangePolynomialApproximation","../Core/LinearApproximation","../Core/loadJson","../Core/Math","../Core/Quaternion","../Core/Rectangle","../Core/ReferenceFrame","../Core/RuntimeError","../Core/Spherical","../Core/TimeInterval","../Core/TimeIntervalCollection","../Scene/HorizontalOrigin","../Scene/LabelStyle","../Scene/VerticalOrigin","../ThirdParty/Uri","../ThirdParty/when","./BillboardGraphics","./ColorMaterialProperty","./CompositeMaterialProperty","./CompositePositionProperty","./CompositeProperty","./ConstantPositionProperty","./ConstantProperty","./DataSource","./DataSourceClock","./EllipseGraphics","./EllipsoidGraphics","./EntityCollection","./GridMaterialProperty","./ImageMaterialProperty","./LabelGraphics","./ModelGraphics","./PathGraphics","./PointGraphics","./PolygonGraphics","./PolylineGlowMaterialProperty","./PolylineGraphics","./PolylineOutlineMaterialProperty","./PositionPropertyArray","./RectangleGraphics","./ReferenceProperty","./Rotation","./SampledPositionProperty","./SampledProperty","./StripeMaterialProperty","./StripeOrientation","./TimeIntervalCollectionPositionProperty","./TimeIntervalCollectionProperty","./WallGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe,ae,se,le,ue,ce,he,de,pe){"use strict";function me(e,t){return"#"===t[0]&&(t=$e+t), -oe.fromString(e,t)}function fe(e){var t=e.rgbaf;if(l(t))return t;var r=e.rgba;if(!l(r))return void 0;if(r.length===o.length)return[o.byteToFloat(r[0]),o.byteToFloat(r[1]),o.byteToFloat(r[2]),o.byteToFloat(r[3])];var i=r.length;t=new Array(i);for(var n=0;i>n;n+=5)t[n]=r[n],t[n+1]=o.byteToFloat(r[n+1]),t[n+2]=o.byteToFloat(r[n+2]),t[n+3]=o.byteToFloat(r[n+3]),t[n+4]=o.byteToFloat(r[n+4]);return t}function ve(e,t){var r=s(e.uri,e);if(l(t)){var i=new O(document.location.href);t=new O(t),r=new O(r).resolve(t.resolve(i)).toString()}return r}function _e(e){var t=e.wsenDegrees;if(l(t)){for(var r=t.length,i=0;r>i;i++)t[i]=S.toRadians(t[i]);return t}return e.wsen}function ge(e){if(l(e.cartesian))return e.cartesian;if(l(e.cartesianVelocity))return e.cartesianVelocity;if(l(e.unitCartesian))return e.unitCartesian;var r,i,n,o=e.unitSpherical;if(l(o)){if(i=o.length,2===i)tt.clock=o[0],tt.cone=o[1],t.fromSpherical(tt,et),n=[et.x,et.y,et.z];else{var a=0;for(n=new Array(i/3*4),r=0;i>r;r+=4)n[r]=o[a++],tt.clock=o[a++],tt.cone=o[a++],t.fromSpherical(tt,et),n[r+1]=et.x,n[r+2]=et.y,n[r+3]=et.z}return n}var s=e.cartographicRadians;if(l(s)){if(3===s.length)rt.longitude=s[0],rt.latitude=s[1],rt.height=s[2],h.WGS84.cartographicToCartesian(rt,et),n=[et.x,et.y,et.z];else for(i=s.length,n=new Array(i),r=0;i>r;r+=4)rt.longitude=s[r+1],rt.latitude=s[r+2],rt.height=s[r+3],h.WGS84.cartographicToCartesian(rt,et),n[r]=s[r],n[r+1]=et.x,n[r+2]=et.y,n[r+3]=et.z;return n}var u=e.cartographicDegrees;if(!l(u))throw new x(JSON.stringify(e)+" is not a valid CZML interval.");if(3===u.length)rt.longitude=S.toRadians(u[0]),rt.latitude=S.toRadians(u[1]),rt.height=u[2],h.WGS84.cartographicToCartesian(rt,et),n=[et.x,et.y,et.z];else for(i=u.length,n=new Array(i),r=0;i>r;r+=4)rt.longitude=S.toRadians(u[r+1]),rt.latitude=S.toRadians(u[r+2]),rt.height=u[r+3],h.WGS84.cartographicToCartesian(rt,et),n[r]=u[r],n[r+1]=et.x,n[r+2]=et.y,n[r+3]=et.z;return n}function ye(e,t){var r=e[t],i=e[t+1],n=e[t+2],o=e[t+3],a=1/Math.sqrt(r*r+i*i+n*n+o*o);e[t]=r*a,e[t+1]=i*a,e[t+2]=n*a,e[t+3]=o*a}function Ce(e){var t=e.unitQuaternion;if(l(t)){if(4===t.length)return ye(t,0),t;for(var r=1;r<t.length;r+=5)ye(t,r)}return t}function Ee(r,i,n){switch(r){case Boolean:return s(i["boolean"],i);case e:return i.cartesian2;case t:return ge(i);case o:return fe(i);case ce:return ce[s(i.stripeOrientation,i)];case M:return M[s(i.horizontalOrigin,i)];case Image:return ve(i,n);case g:return g.fromIso8601(s(i.date,i));case D:return D[s(i.labelStyle,i)];case ae:return s(i.number,i);case Number:return s(i.number,i);case String:return s(i.string,i);case Array:return i.array;case w:return Ce(i);case T:return _e(i);case O:return ve(i,n);case R:return R[s(i.verticalOrigin,i)];default:throw new x(r)}}function Se(e,t){var r=e.interpolationAlgorithm;(l(r)||l(e.interpolationDegree))&&t.setInterpolationOptions({interpolationAlgorithm:nt[r],interpolationDegree:e.interpolationDegree});var i=e.forwardExtrapolationType;l(i)&&(t.forwardExtrapolationType=p[i]);var n=e.forwardExtrapolationDuration;l(n)&&(t.forwardExtrapolationDuration=n);var o=e.backwardExtrapolationType;l(o)&&(t.backwardExtrapolationType=p[o]);var a=e.backwardExtrapolationDuration;l(a)&&(t.backwardExtrapolationDuration=a)}function we(e,t,r,i,n,o,a){var u,c=i.interval;l(c)?(ot.iso8601=c,u=A.fromIso8601(ot),l(n)&&(u=A.intersect(u,n,it))):l(n)&&(u=n);var h,d,p,m,f=l(i.reference),v=l(u)&&!u.equals(_.MAXIMUM_INTERVAL);f||(p=Ee(e,i,o),h=s(e.packedLength,1),m=s(p.length,1),d=!l(i.array)&&"string"!=typeof p&&m>h);var y="function"==typeof e.unpack&&e!==ae;if(!d&&!v)return void(f?t[r]=me(a,i.reference):y?t[r]=new U(e.unpack(p,0)):t[r]=new U(p));var C,E=t[r],S=i.epoch;if(l(S)&&(C=g.fromIso8601(S)),d&&!v)return E instanceof le||(E=new le(e),t[r]=E),E.addSamplesPackedArray(p,C),void Se(i,E);var w;if(!d&&v)return u=u.clone(),f?u.data=me(a,i.reference):y?u.data=e.unpack(p,0):u.data=p,l(E)||(E=f?new z:new de,t[r]=E),void(!f&&E instanceof de?E.intervals.addInterval(u):E instanceof z?(u.data=f?u.data:new U(u.data),E.intervals.addInterval(u)):(w=_.MAXIMUM_INTERVAL.clone(),w.data=E,E=new z,t[r]=E,E.intervals.addInterval(w),u.data=f?u.data:new U(u.data),E.intervals.addInterval(u)));l(E)||(E=new z,t[r]=E),E instanceof z||(w=_.MAXIMUM_INTERVAL.clone(),w.data=E,E=new z,t[r]=E,E.intervals.addInterval(w));var T=E.intervals;w=T.findInterval(u),l(w)&&w.data instanceof le||(w=u.clone(),w.data=new le(e),T.addInterval(w)),w.data.addSamplesPackedArray(p,C),Se(i,w.data)}function Te(e,t,r,i,n,o,a){if(l(i))if(v(i))for(var s=0,u=i.length;u>s;s++)we(e,t,r,i[s],n,o,a);else we(e,t,r,i,n,o,a)}function be(e,r,i,n,o,a){var u,c=i.interval;l(c)?(ot.iso8601=c,u=A.fromIso8601(ot),l(n)&&(u=A.intersect(u,n,it))):l(n)&&(u=n);var h,d,p,m=!1,f=l(i.cartesianVelocity)?1:0,v=t.packedLength*(f+1),y=l(i.reference),C=l(u)&&!u.equals(_.MAXIMUM_INTERVAL);if(y||(h=s(b[i.referenceFrame],void 0),d=ge(i),p=s(d.length,1),m=p>v),!m&&!C)return void(y?e[r]=me(a,i.reference):e[r]=new k(t.unpack(d),h));var E,S=e[r],w=i.epoch;if(l(w)&&(E=g.fromIso8601(w)),m&&!C)return(!(S instanceof se)||l(h)&&S.referenceFrame!==h)&&(S=new se(h,f),e[r]=S),S.addSamplesPackedArray(d,E),void Se(i,S);var T;if(!m&&C)return u=u.clone(),y?u.data=me(a,i.reference):u.data=t.unpack(d),l(S)||(S=y?new V(h):new he(h),e[r]=S),void(!y&&S instanceof he&&l(h)&&S.referenceFrame===h?S.intervals.addInterval(u):S instanceof V?(u.data=y?u.data:new k(u.data,h),S.intervals.addInterval(u)):(T=_.MAXIMUM_INTERVAL.clone(),T.data=S,S=new V(S.referenceFrame),e[r]=S,S.intervals.addInterval(T),u.data=y?u.data:new k(u.data,h),S.intervals.addInterval(u)));l(S)?S instanceof V||(T=_.MAXIMUM_INTERVAL.clone(),T.data=S,S=new V(S.referenceFrame),e[r]=S,S.intervals.addInterval(T)):(S=new V(h),e[r]=S);var x=S.intervals;T=x.findInterval(u),l(T)&&T.data instanceof se&&(!l(h)||T.data.referenceFrame===h)||(T=u.clone(),T.data=new se(h,f),x.addInterval(T)),T.data.addSamplesPackedArray(d,E),Se(i,T.data)}function xe(e,t,r,i,n,o){if(l(r))if(v(r))for(var a=0,s=r.length;s>a;a++)be(e,t,r[a],i,n,o);else be(e,t,r,i,n,o)}function Pe(t,r,i,n,a,s){var u,c=i.interval;l(c)?(ot.iso8601=c,u=A.fromIso8601(ot),l(n)&&(u=A.intersect(u,n,it))):l(n)&&(u=n);var h,d,p=t[r];if(l(u)){p instanceof B||(p=new B,t[r]=p);var m=p.intervals;d=m.findInterval({start:u.start,stop:u.stop}),l(d)?h=d.data:(d=u.clone(),m.addInterval(d))}else h=p;var f;l(i.solidColor)?(h instanceof F||(h=new F),f=i.solidColor,Te(o,h,"color",f.color,void 0,void 0,s)):l(i.grid)?(h instanceof Y||(h=new Y),f=i.grid,Te(o,h,"color",f.color,void 0,a,s),Te(Number,h,"cellAlpha",f.cellAlpha,void 0,a,s),Te(e,h,"lineThickness",f.lineThickness,void 0,a,s),Te(e,h,"lineOffset",f.lineOffset,void 0,a,s),Te(e,h,"lineCount",f.lineCount,void 0,a,s)):l(i.image)?(h instanceof X||(h=new X),f=i.image,Te(Image,h,"image",f.image,void 0,a,s),Te(e,h,"repeat",f.repeat,void 0,a,s)):l(i.stripe)?(h instanceof ue||(h=new ue),f=i.stripe,Te(ce,h,"orientation",f.orientation,void 0,a,s),Te(o,h,"evenColor",f.evenColor,void 0,a,s),Te(o,h,"oddColor",f.oddColor,void 0,a,s),Te(Number,h,"offset",f.offset,void 0,a,s),Te(Number,h,"repeat",f.repeat,void 0,a,s)):l(i.polylineOutline)?(h instanceof re||(h=new re),f=i.polylineOutline,Te(o,h,"color",f.color,void 0,a,s),Te(o,h,"outlineColor",f.outlineColor,void 0,a,s),Te(Number,h,"outlineWidth",f.outlineWidth,void 0,a,s)):l(i.polylineGlow)&&(h instanceof ee||(h=new ee),f=i.polylineGlow,Te(o,h,"color",f.color,void 0,a,s),Te(Number,h,"glowPower",f.glowPower,void 0,a,s)),l(d)?d.data=h:t[r]=h}function Ae(e,t,r,i,n,o){if(l(r))if(v(r))for(var a=0,s=r.length;s>a;a++)Pe(e,t,r[a],i,n,o);else Pe(e,t,r,i,n,o)}function Ie(e,t,r,i){e.name=s(t.name,e.name)}function Me(e,t,r,i){var n=t.description;l(n)&&Te(String,e,"description",n,void 0,i,r)}function De(e,t,r,i){var n=t.position;l(n)&&xe(e,"position",n,void 0,i,r)}function Re(e,r,i,n){var o=r.viewFrom;l(o)&&Te(t,e,"viewFrom",o,void 0,n,i)}function Oe(e,t,r,i){var n=t.orientation;l(n)&&Te(w,e,"orientation",n,void 0,i,r)}function Ne(e,r,i,n){var o,a,s=i.references;if(l(s)){var u=[];for(o=0,a=s.length;a>o;o++)u.push(me(n,s[o]));var c=i.interval;if(l(c)){if(c=A.fromIso8601(c),!(e[r]instanceof V)){c.data=new ie(u);var d=new V;d.intervals.addInterval(c),e[r]=d}}else e[r]=new ie(u)}else{var p=[],m=i.cartesian;if(l(m)){for(o=0,a=m.length;a>o;o+=3)p.push(new t(m[o],m[o+1],m[o+2]));i.array=p}else if(m=i.cartographicRadians,l(m)){for(o=0,a=m.length;a>o;o+=3)rt.longitude=m[o],rt.latitude=m[o+1],rt.height=m[o+2],p.push(h.WGS84.cartographicToCartesian(rt));i.array=p}else if(m=i.cartographicDegrees,l(m)){for(o=0,a=m.length;a>o;o+=3)p.push(t.fromDegrees(m[o],m[o+1],m[o+2]));i.array=p}l(i.array)&&Te(Array,e,r,i,void 0,void 0,n)}}function Le(e,t,r,i){if(l(r))if(v(r))for(var n=r.length,o=0;n>o;o++)Ne(e,t,r[o],i);else Ne(e,t,r,i)}function Fe(e,t,r,i){var n,o=t.availability;if(l(o)){var a;if(v(o))for(var s=o.length,u=0;s>u;u++)l(a)||(a=new I),ot.iso8601=o[u],n=A.fromIso8601(ot),a.addInterval(n);else ot.iso8601=o,n=A.fromIso8601(ot),a=new I,a.addInterval(n);e.availability=a}}function Be(r,i,n,a){var s=i.billboard;if(l(s)){var u,c=s.interval;l(c)&&(ot.iso8601=c,u=A.fromIso8601(ot));var h=r.billboard;l(h)||(r.billboard=h=new L),Te(o,h,"color",s.color,u,a,n),Te(t,h,"eyeOffset",s.eyeOffset,u,a,n),Te(M,h,"horizontalOrigin",s.horizontalOrigin,u,a,n),Te(Image,h,"image",s.image,u,a,n),Te(e,h,"pixelOffset",s.pixelOffset,u,a,n),Te(Number,h,"scale",s.scale,u,a,n),Te(ae,h,"rotation",s.rotation,u,a,n),Te(t,h,"alignedAxis",s.alignedAxis,u,a,n),Te(Boolean,h,"show",s.show,u,a,n),Te(R,h,"verticalOrigin",s.verticalOrigin,u,a,n),Te(Boolean,h,"sizeInMeters",s.sizeInMeters,u,a,n)}}function Ve(e,t){var r=e.version;if(l(r)&&"string"==typeof r){var i=r.split(".");if(2===i.length){if("1"!==i[0])throw new x("Cesium only supports CZML version 1.");t._version=r}}if(!l(t._version))throw new x("CZML version information invalid. It is expected to be a property on the document object in the <Major>.<Minor> version format.");var n=t._documentPacket;l(e.name)&&(n.name=e.name);var o=e.clock;if(l(o)){var a=n.clock;l(a)?(a.interval=s(o.interval,a.interval),a.currentTime=s(o.currentTime,a.currentTime),a.range=s(o.range,a.range),a.step=s(o.step,a.step),a.multiplier=s(o.multiplier,a.multiplier)):n.clock={interval:o.interval,currentTime:o.currentTime,range:o.range,step:o.step,multiplier:o.multiplier}}}function ze(e,t,r,i){var n=t.ellipse;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.ellipse;l(u)||(e.ellipse=u=new H),Te(Boolean,u,"show",n.show,a,i,r),Te(ae,u,"rotation",n.rotation,a,i,r),Te(Number,u,"semiMajorAxis",n.semiMajorAxis,a,i,r),Te(Number,u,"semiMinorAxis",n.semiMinorAxis,a,i,r),Te(Number,u,"height",n.height,a,i,r),Te(Number,u,"extrudedHeight",n.extrudedHeight,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(ae,u,"stRotation",n.stRotation,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Number,u,"numberOfVerticalLines",n.numberOfVerticalLines,a,i,r)}}function ke(e,r,i,n){var a=r.ellipsoid;if(l(a)){var s,u=a.interval;l(u)&&(ot.iso8601=u,s=A.fromIso8601(ot));var c=e.ellipsoid;l(c)||(e.ellipsoid=c=new q),Te(Boolean,c,"show",a.show,s,n,i),Te(t,c,"radii",a.radii,s,n,i),Ae(c,"material",a.material,s,n,i),Te(Boolean,c,"fill",a.fill,s,n,i),Te(Boolean,c,"outline",a.outline,s,n,i),Te(o,c,"outlineColor",a.outlineColor,s,n,i),Te(Number,c,"outlineWidth",a.outlineWidth,s,n,i)}}function Ue(r,i,n,a){var s=i.label;if(l(s)){var u,c=s.interval;l(c)&&(ot.iso8601=c,u=A.fromIso8601(ot));var h=r.label;l(h)||(r.label=h=new Z),Te(o,h,"fillColor",s.fillColor,u,a,n),Te(o,h,"outlineColor",s.outlineColor,u,a,n),Te(Number,h,"outlineWidth",s.outlineWidth,u,a,n),Te(t,h,"eyeOffset",s.eyeOffset,u,a,n),Te(M,h,"horizontalOrigin",s.horizontalOrigin,u,a,n),Te(String,h,"text",s.text,u,a,n),Te(e,h,"pixelOffset",s.pixelOffset,u,a,n),Te(Number,h,"scale",s.scale,u,a,n),Te(Boolean,h,"show",s.show,u,a,n),Te(R,h,"verticalOrigin",s.verticalOrigin,u,a,n),Te(String,h,"font",s.font,u,a,n),Te(D,h,"style",s.style,u,a,n)}}function Ge(e,t,r,i){var n=t.model;if(l(n)){var o,a=n.interval;l(a)&&(ot.iso8601=a,o=A.fromIso8601(ot));var s=e.model;l(s)||(e.model=s=new K),Te(Boolean,s,"show",n.show,o,i,r),Te(Number,s,"scale",n.scale,o,i,r),Te(Number,s,"minimumPixelSize",n.minimumPixelSize,o,i,r),Te(O,s,"uri",n.gltf,o,i,r)}}function We(e,t,r,i){var n=t.path;if(l(n)){var o,a=n.interval;l(a)&&(ot.iso8601=a,o=A.fromIso8601(ot));var s=e.path;l(s)||(e.path=s=new J),Te(Boolean,s,"show",n.show,o,i,r),Te(Number,s,"width",n.width,o,i,r),Te(Number,s,"resolution",n.resolution,o,i,r),Te(Number,s,"leadTime",n.leadTime,o,i,r),Te(Number,s,"trailTime",n.trailTime,o,i,r),Ae(s,"material",n.material,o,i,r)}}function He(e,t,r,i){var n=t.point;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.point;l(u)||(e.point=u=new Q),Te(o,u,"color",n.color,a,i,r),Te(Number,u,"pixelSize",n.pixelSize,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Boolean,u,"show",n.show,a,i,r)}}function qe(e,t,r,i){var n=t.polygon;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.polygon;l(u)||(e.polygon=u=new $),Te(Boolean,u,"show",n.show,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Number,u,"height",n.height,a,i,r),Te(Number,u,"extrudedHeight",n.extrudedHeight,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(ae,u,"stRotation",n.stRotation,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Boolean,u,"perPositionHeight",n.perPositionHeight,a,i,r),Le(u,"hierarchy",n.positions,r)}}function je(e,t,r,i){var n=t.rectangle;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.rectangle;l(u)||(e.rectangle=u=new ne),Te(Boolean,u,"show",n.show,a,i,r),Te(T,u,"coordinates",n.coordinates,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Number,u,"height",n.height,a,i,r),Te(Number,u,"extrudedHeight",n.extrudedHeight,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(ae,u,"rotation",n.rotation,a,i,r),Te(ae,u,"stRotation",n.stRotation,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Te(Boolean,u,"closeBottom",n.closeBottom,a,i,r),Te(Boolean,u,"closeTop",n.closeTop,a,i,r)}}function Ye(e,t,r,i){var n=t.wall;if(l(n)){var a,s=n.interval;l(s)&&(ot.iso8601=s,a=A.fromIso8601(ot));var u=e.wall;l(u)||(e.wall=u=new pe),Te(Boolean,u,"show",n.show,a,i,r),Ae(u,"material",n.material,a,i,r),Te(Array,u,"minimumHeights",n.minimumHeights,a,i,r),Te(Array,u,"maximumHeights",n.maximumHeights,a,i,r),Te(Number,u,"granularity",n.granularity,a,i,r),Te(Boolean,u,"fill",n.fill,a,i,r),Te(Boolean,u,"outline",n.outline,a,i,r),Te(o,u,"outlineColor",n.outlineColor,a,i,r),Te(Number,u,"outlineWidth",n.outlineWidth,a,i,r),Le(u,"positions",n.positions,r)}}function Xe(e,t,r,i){var n=t.polyline;if(l(n)){var o,a=n.interval;l(a)&&(ot.iso8601=a,o=A.fromIso8601(ot));var s=e.polyline;l(s)||(e.polyline=s=new te),Te(Boolean,s,"show",n.show,o,i,r),Te(Number,s,"width",n.width,o,i,r),Ae(s,"material",n.material,o,i,r),Te(Boolean,s,"followSurface",n.followSurface,o,i,r),Te(Number,s,"granularity",n.granularity,o,i,r),Le(s,"positions",n.positions,r)}}function Ze(e,t,r,i,n){var o=e.id;if(l(o)||(o=a()),$e=o,!l(n._version)&&"document"!==o)throw new x("The first CZML packet is required to be the document object.");if(e["delete"]===!0)t.removeById(o);else if("document"===o)Ve(e,n);else{var s=t.getOrCreateEntity(o),u=e.parent;l(u)&&(s.parent=t.getOrCreateEntity(u));for(var c=r.length-1;c>-1;c--)r[c](s,e,t,i)}$e=void 0}function Ke(e){var t,r=e._documentPacket.clock;if(!l(r)){if(!l(e._clock)){var o=e._entityCollection.computeAvailability();if(!o.start.equals(_.MINIMUM_VALUE)){var a=o.start,u=o.stop,c=g.secondsDifference(u,a),h=Math.round(c/120);return t=new W,t.startTime=g.clone(a),t.stopTime=g.clone(u),t.clockRange=i.LOOP_STOP,t.multiplier=h,t.currentTime=g.clone(a),t.clockStep=n.SYSTEM_CLOCK_MULTIPLIER,e._clock=t,!0}}return!1}if(l(e._clock)?t=e._clock.clone():(t=new W,t.startTime=_.MINIMUM_VALUE.clone(),t.stopTime=_.MAXIMUM_VALUE.clone(),t.currentTime=_.MINIMUM_VALUE.clone(),t.clockRange=i.LOOP_STOP,t.clockStep=n.SYSTEM_CLOCK_MULTIPLIER,t.multiplier=1),l(r.interval)){ot.iso8601=r.interval;var d=A.fromIso8601(ot);t.startTime=d.start,t.stopTime=d.stop}return l(r.currentTime)&&(t.currentTime=g.fromIso8601(r.currentTime)),l(r.range)&&(t.clockRange=s(i[r.range],i.LOOP_STOP)),l(r.step)&&(t.clockStep=s(n[r.step],n.SYSTEM_CLOCK_MULTIPLIER)),l(r.multiplier)&&(t.multiplier=r.multiplier),t.equals(e._clock)?!1:(e._clock=t.clone(e._clock),!0)}function Je(e,t,r,i){r=s(r,s.EMPTY_OBJECT);var n=t,o=r.sourceUri;return"string"==typeof t&&(n=E(t),o=s(o,t)),G.setLoading(e,!0),N(n,function(t){return Qe(e,t,o,i)}).otherwise(function(t){return G.setLoading(e,!1),e._error.raiseEvent(e,t),window.console.log(t),N.reject(t)})}function Qe(e,t,r,i){G.setLoading(e,!0);var n=e._entityCollection;i&&(e._version=void 0,e._documentPacket=new at,n.removeAll()),st._processCzml(t,n,r,void 0,e);var o=Ke(e),a=e._documentPacket;return l(a.name)&&e._name!==a.name?(e._name=a.name,o=!0):!l(e._name)&&l(r)&&(e._name=m(r),o=!0),G.setLoading(e,!1),o&&e._changed.raiseEvent(e),e}var $e,et=new t,tt=new P,rt=new r,it=new A,nt={HERMITE:f,LAGRANGE:y,LINEAR:C},ot={iso8601:void 0},at=function(){this.name=void 0,this.clock=void 0},st=function(e){this._name=e,this._changed=new d,this._error=new d,this._isLoading=!1,this._loading=new d,this._clock=void 0,this._documentPacket=new at,this._version=void 0,this._entityCollection=new j(this)};return st.load=function(e,t){return(new st).load(e,t)},u(st.prototype,{name:{get:function(){return this._name}},clock:{get:function(){return this._clock}},entities:{get:function(){return this._entityCollection}},isLoading:{get:function(){return this._isLoading}},changedEvent:{get:function(){return this._changed}},errorEvent:{get:function(){return this._error}},loadingEvent:{get:function(){return this._loading}}}),st.updaters=[Be,ze,ke,Ue,Ge,Ie,Me,We,He,qe,Xe,je,De,Re,Ye,Oe,Fe],st.prototype.process=function(e,t){return Je(this,e,t,!1)},st.prototype.load=function(e,t){return Je(this,e,t,!0)},st.processPacketData=Te,st.processPositionPacketData=xe,st.processMaterialPacketData=Ae,st._processCzml=function(e,t,r,i,n){if(i=l(i)?i:st.updaters,v(e))for(var o=0,a=e.length;a>o;o++)Ze(e[o],t,i,r,n);else Ze(e,t,i,r,n)},st}),r("DataSources/DataSourceCollection",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../ThirdParty/when"],function(e,t,r,i,n,o,a){"use strict";var s=function(){this._dataSources=[],this._dataSourceAdded=new o,this._dataSourceRemoved=new o};return r(s.prototype,{length:{get:function(){return this._dataSources.length}},dataSourceAdded:{get:function(){return this._dataSourceAdded}},dataSourceRemoved:{get:function(){return this._dataSourceRemoved}}}),s.prototype.add=function(e){var t=this,r=this._dataSources;return a(e,function(e){return r===t._dataSources&&(t._dataSources.push(e),t._dataSourceAdded.raiseEvent(t,e)),e})},s.prototype.remove=function(t,r){r=e(r,!1);var i=this._dataSources.indexOf(t);return-1!==i?(this._dataSources.splice(i,1),this._dataSourceRemoved.raiseEvent(this,t),r&&"function"==typeof t.destroy&&t.destroy(),!0):!1},s.prototype.removeAll=function(t){t=e(t,!1);for(var r=this._dataSources,i=0,n=r.length;n>i;++i){var o=r[i];this._dataSourceRemoved.raiseEvent(this,o),t&&"function"==typeof o.destroy&&o.destroy()}this._dataSources=[]},s.prototype.contains=function(e){return-1!==this.indexOf(e)},s.prototype.indexOf=function(e){return this._dataSources.indexOf(e)},s.prototype.get=function(e){return this._dataSources[e]},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this.removeAll(!0),i(this)},s}),r("DataSources/EllipseGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EllipseGeometry","../Core/EllipseOutlineGeometry","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.center=void 0,this.semiMajorAxis=void 0,this.semiMinorAxis=void 0,this.rotation=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0,this.stRotation=void 0,this.numberOfVerticalLines=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"ellipse",e.ellipse,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,l=a.isAvailable(r),u=new d(l&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var h=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||l)&&(h=this._materialProperty.color.getValue(r)),o=t.fromColor(h),n={show:u,color:o}}else n={show:u};return new c({id:a,geometry:new s(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new c({id:i,geometry:new l(this._options),attributes:{show:new d(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"position"===t||"ellipse"===t){var a=this._entity.ellipse;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(h.MINIMUM_VALUE):!0,u=a.outline,c=i(u);if(c&&u.isConstant&&(c=u.getValue(h.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=this._entity.position,f=a.semiMajorAxis,_=a.semiMinorAxis,g=a.show;if(i(g)&&g.isConstant&&!g.getValue(h.MINIMUM_VALUE)||!i(d)||!i(f)||!i(_))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var y=r(a.material,E),x=y instanceof v;this._materialProperty=y,this._fillProperty=r(s,w),this._showProperty=r(g,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=c?r(a.outlineColor,b):void 0;var P=a.rotation,A=a.height,I=a.extrudedHeight,M=a.granularity,D=a.stRotation,R=a.outlineWidth,O=a.numberOfVerticalLines;if(this._isClosed=i(I),this._fillEnabled=l,this._outlineEnabled=c,d.isConstant&&f.isConstant&&_.isConstant&&C.isConstant(P)&&C.isConstant(A)&&C.isConstant(I)&&C.isConstant(M)&&C.isConstant(D)&&C.isConstant(R)&&C.isConstant(O)){var N=this._options;N.vertexFormat=x?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,N.center=d.getValue(h.MINIMUM_VALUE,N.center),N.semiMajorAxis=f.getValue(h.MINIMUM_VALUE,N.semiMajorAxis),N.semiMinorAxis=_.getValue(h.MINIMUM_VALUE,N.semiMinorAxis),N.rotation=i(P)?P.getValue(h.MINIMUM_VALUE):void 0,N.height=i(A)?A.getValue(h.MINIMUM_VALUE):void 0,N.extrudedHeight=i(I)?I.getValue(h.MINIMUM_VALUE):void 0,N.granularity=i(M)?M.getValue(h.MINIMUM_VALUE):void 0,N.stRotation=i(D)?D.getValue(h.MINIMUM_VALUE):void 0,N.numberOfVerticalLines=i(O)?O.getValue(h.MINIMUM_VALUE):void 0,this._outlineWidth=i(R)?R.getValue(h.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,u=a.ellipse;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(u.show,r,!0)){var h=this._options,d=C.getValueOrUndefined(a.position,r,h.center),v=C.getValueOrUndefined(u.semiMajorAxis,r),_=C.getValueOrUndefined(u.semiMinorAxis,r);if(i(d)&&i(v)&&i(_)){if(h.center=d,h.semiMajorAxis=v,h.semiMinorAxis=_,h.rotation=C.getValueOrUndefined(u.rotation,r),h.height=C.getValueOrUndefined(u.height,r),h.extrudedHeight=C.getValueOrUndefined(u.extrudedHeight,r),h.granularity=C.getValueOrUndefined(u.granularity,r),h.stRotation=C.getValueOrUndefined(u.stRotation,r),h.numberOfVerticalLines=C.getValueOrUndefined(u.numberOfVerticalLines,r),C.getValueOrDefault(u.fill,r,!0)){var g=y.getValue(r,o.fillMaterialProperty,this._material);this._material=g;var E=new p({material:g,translucent:g.isTranslucent(),closed:i(h.extrudedHeight)});h.vertexFormat=E.vertexFormat,this._primitive=n.add(new f({geometryInstances:new c({id:a,geometry:new s(h)}),appearance:E,asynchronous:!1}))}if(C.getValueOrDefault(u.outline,r,!1)){h.vertexFormat=m.VERTEX_FORMAT;var S=C.getValueOrClonedDefault(u.outlineColor,r,e.BLACK,x),w=C.getValueOrDefault(u.outlineWidth,r,1),T=1!==S.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new c({id:a,geometry:new l(h),attributes:{color:t.fromColor(S)}}),appearance:new m({flat:!0,translucent:T,renderState:{lineWidth:o._scene.clampLineWidth(w)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/EllipsoidGeometryUpdater",["../Core/Cartesian3","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EllipsoidGeometry","../Core/EllipsoidOutlineGeometry","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/Matrix4","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","../Scene/SceneMode","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";var T=new y(t.WHITE),b=new C(!0),x=new C(!0),P=new C(!1),A=new C(t.BLACK),I=new e,M=new t,D=new e(1,1,1),R=function(e){this.id=e,this.vertexFormat=void 0,this.radii=void 0,this.stackPartitions=void 0,this.slicePartitions=void 0,this.subdivisions=void 0},O=function(e,t){this._scene=t,this._entity=e,this._entitySubscription=e.definitionChanged.addEventListener(O.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new c,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new R(e),this._onEntityPropertyChanged(e,"ellipsoid",e.ellipsoid,void 0)};o(O,{perInstanceColorAppearanceType:{value:v},materialAppearanceType:{value:f}}),o(O.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!n(this._entity.availability)&&w.isConstant(this._showProperty)&&w.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!n(this._entity.availability)&&w.isConstant(this._showProperty)&&w.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),O.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},O.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},O.prototype.createFillGeometryInstance=function(e){var i,o,a=this._entity,s=a.isAvailable(e),u=new m(s&&a.isShowing&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e));if(this._materialProperty instanceof y){var c=t.WHITE;n(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(c=this._materialProperty.color.getValue(e)),o=r.fromColor(c),i={show:u,color:o}}else i={show:u};return new h({id:a,geometry:new l(this._options),modelMatrix:a._getModelMatrix(d.MINIMUM_VALUE),attributes:i})},O.prototype.createOutlineGeometryInstance=function(e){var i=this._entity,n=i.isAvailable(e),o=w.getValueOrDefault(this._outlineColorProperty,e,t.BLACK);return new h({id:i,geometry:new u(this._options),modelMatrix:i._getModelMatrix(d.MINIMUM_VALUE),attributes:{show:new m(n&&i.isShowing&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)),color:r.fromColor(o)}})},O.prototype.isDestroyed=function(){return!1},O.prototype.destroy=function(){this._entitySubscription(),a(this)},O.prototype._onEntityPropertyChanged=function(e,t,r,o){if("availability"===t||"position"===t||"orientation"===t||"ellipsoid"===t){ -var a=e.ellipsoid;if(!n(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=n(s)&&s.isConstant?s.getValue(d.MINIMUM_VALUE):!0,u=a.outline,c=n(u);if(c&&u.isConstant&&(c=u.getValue(d.MINIMUM_VALUE)),!l&&!c)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var h=e.position,p=a.radii,m=a.show;if(n(m)&&m.isConstant&&!m.getValue(d.MINIMUM_VALUE)||!n(h)||!n(p))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=i(a.material,T),g=_ instanceof y;this._materialProperty=_,this._fillProperty=i(s,x),this._showProperty=i(m,b),this._showOutlineProperty=i(a.outline,P),this._outlineColorProperty=c?i(a.outlineColor,A):void 0,this._fillEnabled=l,this._outlineEnabled=c;var C=a.stackPartitions,E=a.slicePartitions,S=a.outlineWidth,I=a.subdivisions;if(h.isConstant&&w.isConstant(e.orientation)&&p.isConstant&&w.isConstant(C)&&w.isConstant(E)&&w.isConstant(S)&&w.isConstant(I)){var M=this._options;M.vertexFormat=g?v.VERTEX_FORMAT:f.MaterialSupport.TEXTURED.vertexFormat,M.radii=p.getValue(d.MINIMUM_VALUE,M.radii),M.stackPartitions=n(C)?C.getValue(d.MINIMUM_VALUE):void 0,M.slicePartitions=n(E)?E.getValue(d.MINIMUM_VALUE):void 0,M.subdivisions=n(I)?I.getValue(d.MINIMUM_VALUE):void 0,this._outlineWidth=n(S)?S.getValue(d.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},O.prototype.createDynamicUpdater=function(e){return new N(e,this)};var N=function(e,t){this._entity=t._entity,this._scene=t._scene,this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new R(t._entity),this._modelMatrix=new p,this._material=void 0,this._attributes=void 0,this._outlineAttributes=void 0,this._lastSceneMode=void 0,this._lastShow=void 0,this._lastOutlineShow=void 0,this._lastOutlineWidth=void 0,this._lastOutlineColor=void 0};return N.prototype.update=function(e){var o=this._entity,a=o.ellipsoid;if(!o.isShowing||!o.isAvailable(e)||!w.getValueOrDefault(a.show,e,!0))return n(this._primitive)&&(this._primitive.show=!1),void(n(this._outlinePrimitive)&&(this._outlinePrimitive.show=!1));var s=w.getValueOrUndefined(a.radii,e,I),c=o._getModelMatrix(e,this._modelMatrix);if(!n(c)||!n(s))return n(this._primitive)&&(this._primitive.show=!1),void(n(this._outlinePrimitive)&&(this._outlinePrimitive.show=!1));var d,y=w.getValueOrDefault(a.fill,e,!0),C=w.getValueOrDefault(a.outline,e,!1),E=w.getValueOrClonedDefault(a.outlineColor,e,t.BLACK,M),b=S.getValue(e,i(a.material,T),this._material);this._material=b;var x=w.getValueOrUndefined(a.stackPartitions,e),P=w.getValueOrUndefined(a.slicePartitions,e),A=w.getValueOrUndefined(a.subdivisions,e),R=w.getValueOrDefault(a.outlineWidth,e,1),O=this._scene.mode,N=O===g.SCENE3D,L=this._options,F=!N||this._lastSceneMode!==O||!n(this._primitive)||L.stackPartitions!==x||L.slicePartitions!==P||L.subdivisions!==A||this._lastOutlineWidth!==R;if(F){var B=this._primitives;B.removeAndDestroy(this._primitive),B.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0,this._lastSceneMode=O,this._lastOutlineWidth=R,L.stackPartitions=x,L.slicePartitions=P,L.subdivisions=A,L.radii=N?D:s,d=new f({material:b,translucent:b.isTranslucent(),closed:!0}),L.vertexFormat=d.vertexFormat,this._primitive=B.add(new _({geometryInstances:new h({id:o,geometry:new l(L),modelMatrix:N?void 0:c,attributes:{show:new m(y)}}),appearance:d,asynchronous:!1})),L.vertexFormat=v.VERTEX_FORMAT,this._outlinePrimitive=B.add(new _({geometryInstances:new h({id:o,geometry:new u(L),modelMatrix:N?void 0:c,attributes:{show:new m(C),color:r.fromColor(E)}}),appearance:new v({flat:!0,translucent:1!==E.alpha,renderState:{lineWidth:this._geometryUpdater._scene.clampLineWidth(R)}}),asynchronous:!1})),this._lastShow=y,this._lastOutlineShow=C,this._lastOutlineColor=t.clone(E,this._lastOutlineColor)}else if(this._primitive.ready){var V=this._primitive,z=this._outlinePrimitive;V.show=!0,z.show=!0,d=V.appearance,d.material=b;var k=this._attributes;n(k)||(k=V.getGeometryInstanceAttributes(o),this._attributes=k),y!==this._lastShow&&(k.show=m.toValue(y,k.show),this._lastShow=y);var U=this._outlineAttributes;n(U)||(U=z.getGeometryInstanceAttributes(o),this._outlineAttributes=U),C!==this._lastOutlineShow&&(U.show=m.toValue(C,U.show),this._lastOutlineShow=C),t.equals(E,this._lastOutlineColor)||(U.color=r.toValue(E,U.color),t.clone(E,this._lastOutlineColor))}N&&(s.x=Math.max(s.x,.001),s.y=Math.max(s.y,.001),s.z=Math.max(s.z,.001),c=p.multiplyByScale(c,s,c),this._primitive.modelMatrix=c,this._outlinePrimitive.modelMatrix=c)},N.prototype.getBoundingSphere=function(e,t){return E(e,this._primitive,this._outlinePrimitive,t)},N.prototype.isDestroyed=function(){return!1},N.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),a(this)},O}),r("DataSources/StaticGeometryColorBatch",["../Core/AssociativeArray","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defined","../Core/ShowGeometryInstanceAttribute","../Scene/Primitive","./BoundingSphereState"],function(e,t,r,i,n,o,a){"use strict";var s=new t,l=function(t,r,i,n){this.translucent=r,this.appearanceType=i,this.closed=n,this.primitives=t,this.createPrimitive=!1,this.primitive=void 0,this.oldPrimitive=void 0,this.geometry=new e,this.updaters=new e,this.updatersWithAttributes=new e,this.attributes=new e,this.subscriptions=new e,this.showsUpdated=new e,this.itemsToRemove=[]};l.prototype.add=function(e,t){var r=e.entity.id;if(this.createPrimitive=!0,this.geometry.set(r,t),this.updaters.set(r,e),e.hasConstantFill&&e.fillMaterialProperty.isConstant){var i=this;this.subscriptions.set(r,e.entity.definitionChanged.addEventListener(function(t,r,n,o){"isShowing"===r&&i.showsUpdated.set(t.id,e)}))}else this.updatersWithAttributes.set(r,e)},l.prototype.remove=function(e){var t=e.entity.id;if(this.createPrimitive=this.geometry.remove(t)||this.createPrimitive,this.updaters.remove(t)){this.updatersWithAttributes.remove(t);var r=this.subscriptions.get(t);i(r)&&(r(),this.subscriptions.remove(t))}},l.prototype.update=function(e){var a,l,u=!0,c=0,h=this.primitive,d=this.primitives;if(this.createPrimitive){var p=this.geometry.values,m=p.length;if(m>0){for(i(h)&&(i(this.oldPrimitive)?d.remove(h):this.oldPrimitive=h),l=0;m>l;l++){var f=p[l],v=f.attributes;a=this.attributes.get(f.id.id),i(a)&&(i(v.show)&&(v.show.value=a.show),i(v.color)&&(v.color.value=a.color))}h=new o({asynchronous:!0,geometryInstances:p,appearance:new this.appearanceType({translucent:this.translucent,closed:this.closed})}),d.add(h),u=!1}else{i(h)&&(d.remove(h),h=void 0);var _=this.oldPrimitive;i(_)&&(d.remove(_),this.oldPrimitive=void 0)}this.attributes.removeAll(),this.primitive=h,this.createPrimitive=!1}else if(i(h)&&h.ready){i(this.oldPrimitive)&&(d.remove(this.oldPrimitive),this.oldPrimitive=void 0);var g=this.updatersWithAttributes.values,y=g.length;for(l=0;y>l;l++){var C=g[l],E=this.geometry.get(C.entity.id);if(a=this.attributes.get(E.id.id),i(a)||(a=h.getGeometryInstanceAttributes(E.id),this.attributes.set(E.id.id,a)),!C.fillMaterialProperty.isConstant){var S=C.fillMaterialProperty.color;S.getValue(e,s),t.equals(a._lastColor,s)||(a._lastColor=t.clone(s,a._lastColor),a.color=r.toValue(s,a.color),(this.translucent&&255===a.color[3]||!this.translucent&&255!==a.color[3])&&(this.itemsToRemove[c++]=C))}var w=C.entity.isShowing&&(C.hasConstantFill||C.isFilled(e)),T=1===a.show[0];w!==T&&(a.show=n.toValue(w,a.show))}this.updateShows(h)}else i(h)&&!h.ready&&(u=!1);return this.itemsToRemove.length=c,u},l.prototype.updateShows=function(e){for(var t=this.showsUpdated.values,r=t.length,o=0;r>o;o++){var a=t[o],s=this.geometry.get(a.entity.id),l=this.attributes.get(s.id.id);i(l)||(l=e.getGeometryInstanceAttributes(s.id),this.attributes.set(s.id.id,l));var u=a.entity.isShowing,c=1===l.show[0];u!==c&&(l.show=n.toValue(u,l.show))}this.showsUpdated.removeAll()},l.prototype.contains=function(e){return this.updaters.contains(e.id)},l.prototype.getBoundingSphere=function(e,t){var r=this.primitive;if(!r.ready)return a.PENDING;var n=r.getGeometryInstanceAttributes(e);return!i(n)||!i(n.boundingSphere)||i(n.show)&&0===n.show[0]?a.FAILED:(n.boundingSphere.clone(t),a.DONE)},l.prototype.removeAllPrimitives=function(){var e=this.primitives,t=this.primitive;i(t)&&(e.remove(t),this.primitive=void 0,this.geometry.removeAll(),this.updaters.removeAll());var r=this.oldPrimitive;i(r)&&(e.remove(r),this.oldPrimitive=void 0)};var u=function(e,t,r){this._solidBatch=new l(e,!1,t,r),this._translucentBatch=new l(e,!0,t,r)};return u.prototype.add=function(e,t){var r=t.createFillGeometryInstance(e);255===r.attributes.color.value[3]?this._solidBatch.add(t,r):this._translucentBatch.add(t,r)},u.prototype.remove=function(e){this._solidBatch.remove(e)||this._translucentBatch.remove(e)},u.prototype.update=function(e){var t,r,i=this._solidBatch.update(e);i=this._translucentBatch.update(e)&&i;var n=this._solidBatch.itemsToRemove,o=n.length;if(o>0)for(t=0;o>t;t++)r=n[t],this._solidBatch.remove(r),this._translucentBatch.add(r,r.createFillGeometryInstance(e));n=this._translucentBatch.itemsToRemove;var a=n.length;if(a>0)for(t=0;a>t;t++)r=n[t],this._translucentBatch.remove(r),this._solidBatch.add(r,r.createFillGeometryInstance(e));return(o>0||a>0)&&(i=this._solidBatch.update(e)&&i,i=this._translucentBatch.update(e)&&i),i},u.prototype.getBoundingSphere=function(e,t){return this._solidBatch.contains(e)?this._solidBatch.getBoundingSphere(e,t):this._translucentBatch.contains(e)?this._translucentBatch.getBoundingSphere(e,t):a.FAILED},u.prototype.removeAllPrimitives=function(){this._solidBatch.removeAllPrimitives(),this._translucentBatch.removeAllPrimitives()},u}),r("DataSources/StaticGeometryPerMaterialBatch",["../Core/AssociativeArray","../Core/defined","../Core/ShowGeometryInstanceAttribute","../Scene/Primitive","./BoundingSphereState","./MaterialProperty"],function(e,t,r,i,n,o){"use strict";var a=function(t,r,i,n){this.primitives=t,this.appearanceType=r,this.materialProperty=i,this.closed=n,this.updaters=new e,this.createPrimitive=!0,this.primitive=void 0,this.oldPrimitive=void 0,this.geometry=new e,this.material=void 0,this.updatersWithAttributes=new e,this.attributes=new e,this.invalidated=!1,this.removeMaterialSubscription=i.definitionChanged.addEventListener(a.prototype.onMaterialChanged,this),this.subscriptions=new e,this.showsUpdated=new e};a.prototype.onMaterialChanged=function(){this.invalidated=!0},a.prototype.isMaterial=function(e){var r=this.materialProperty,i=e.fillMaterialProperty;return i===r?!0:t(r)?r.equals(i):!1},a.prototype.add=function(e,t){var r=t.entity.id;if(this.updaters.set(r,t),this.geometry.set(r,t.createFillGeometryInstance(e)),t.hasConstantFill&&t.fillMaterialProperty.isConstant){var i=this;this.subscriptions.set(r,t.entity.definitionChanged.addEventListener(function(e,r,n,o){"isShowing"===r&&i.showsUpdated.set(e.id,t)}))}else this.updatersWithAttributes.set(r,t);this.createPrimitive=!0},a.prototype.remove=function(e){var r=e.entity.id,i=this.updaters.remove(r);if(i){this.geometry.remove(r),this.updatersWithAttributes.remove(r);var n=this.subscriptions.get(r);t(n)&&(n(),this.subscriptions.remove(r))}return this.createPrimitive=i,i},a.prototype.update=function(e){var n,a,s=!0,l=this.primitive,u=this.primitives,c=this.geometry.values;if(this.createPrimitive){var h=c.length;if(h>0){for(t(l)&&(t(this.oldPrimitive)?u.remove(l):this.oldPrimitive=l),a=0;h>a;a++){var d=c[a],p=d.attributes;n=this.attributes.get(d.id.id),t(n)&&(t(p.show)&&(p.show.value=n.show),t(p.color)&&(p.color.value=n.color))}this.material=o.getValue(e,this.materialProperty,this.material),l=new i({asynchronous:!0,geometryInstances:c,appearance:new this.appearanceType({material:this.material,translucent:this.material.isTranslucent(),closed:this.closed})}),u.add(l),s=!1}else{t(l)&&(u.remove(l),l=void 0);var m=this.oldPrimitive;t(m)&&(u.remove(m),this.oldPrimitive=void 0)}this.attributes.removeAll(),this.primitive=l,this.createPrimitive=!1}else if(t(l)&&l.ready){t(this.oldPrimitive)&&(u.remove(this.oldPrimitive),this.oldPrimitive=void 0),this.material=o.getValue(e,this.materialProperty,this.material),this.primitive.appearance.material=this.material;var f=this.updatersWithAttributes.values,v=f.length;for(a=0;v>a;a++){var _=f[a],g=_.entity,y=this.geometry.get(g.id);n=this.attributes.get(y.id.id),t(n)||(n=l.getGeometryInstanceAttributes(y.id),this.attributes.set(y.id.id,n));var C=g.isShowing&&(_.hasConstantFill||_.isFilled(e)),E=1===n.show[0];C!==E&&(n.show=r.toValue(C,n.show))}this.updateShows(l)}else t(l)&&!l.ready&&(s=!1);return s},a.prototype.updateShows=function(e){for(var i=this.showsUpdated.values,n=i.length,o=0;n>o;o++){var a=i[o],s=a.entity,l=this.geometry.get(s.id),u=this.attributes.get(l.id.id);t(u)||(u=e.getGeometryInstanceAttributes(l.id),this.attributes.set(l.id.id,u));var c=s.isShowing,h=1===u.show[0];c!==h&&(u.show=r.toValue(c,u.show))}this.showsUpdated.removeAll()},a.prototype.contains=function(e){return this.updaters.contains(e.id)},a.prototype.getBoundingSphere=function(e,r){var i=this.primitive;if(!i.ready)return n.PENDING;var o=i.getGeometryInstanceAttributes(e);return!t(o)||!t(o.boundingSphere)||t(o.show)&&0===o.show[0]?n.FAILED:(o.boundingSphere.clone(r),n.DONE)},a.prototype.destroy=function(e){var r=this.primitive,i=this.primitives;t(r)&&i.remove(r);var n=this.oldPrimitive;t(n)&&i.remove(n),this.removeMaterialSubscription()};var s=function(e,t,r){this._items=[],this._primitives=e,this._appearanceType=t,this._closed=r};return s.prototype.add=function(e,t){for(var r=this._items,i=r.length,n=0;i>n;n++){var o=r[n];if(o.isMaterial(t))return void o.add(e,t)}var s=new a(this._primitives,this._appearanceType,t.fillMaterialProperty,this._closed);s.add(e,t),r.push(s)},s.prototype.remove=function(e){for(var t=this._items,r=t.length,i=r-1;i>=0;i--){var n=t[i];if(n.remove(e)){0===n.updaters.length&&(t.splice(i,1),n.destroy());break}}},s.prototype.update=function(e){var t,r=this._items,i=r.length;for(t=i-1;t>=0;t--){var n=r[t];if(n.invalidated){r.splice(t,1);for(var o=n.updaters.values,a=o.length,s=0;a>s;s++)this.add(e,o[s]);n.destroy()}}var l=!0;for(t=0;i>t;t++)l=r[t].update(e)&&l;return l},s.prototype.getBoundingSphere=function(e,t){for(var r=this._items,i=r.length,o=0;i>o;o++){var a=r[o];if(a.contains(e))return a.getBoundingSphere(e,t)}return n.FAILED},s.prototype.removeAllPrimitives=function(){for(var e=this._items,t=e.length,r=0;t>r;r++)e[r].destroy();this._items.length=0},s}),r("DataSources/StaticOutlineGeometryBatch",["../Core/AssociativeArray","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defined","../Core/ShowGeometryInstanceAttribute","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./BoundingSphereState"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t,r,i){this.translucent=r,this.primitives=t,this.createPrimitive=!1,this.primitive=void 0,this.oldPrimitive=void 0,this.geometry=new e,this.updaters=new e,this.updatersWithAttributes=new e,this.attributes=new e,this.itemsToRemove=[],this.width=i,this.subscriptions=new e,this.showsUpdated=new e};l.prototype.add=function(e,t){var r=e.entity.id;if(this.createPrimitive=!0,this.geometry.set(r,t),this.updaters.set(r,e),e.hasConstantOutline&&e.outlineColorProperty.isConstant){var i=this;this.subscriptions.set(r,e.entity.definitionChanged.addEventListener(function(t,r,n,o){"isShowing"===r&&i.showsUpdated.set(t.id,e)}))}else this.updatersWithAttributes.set(r,e)},l.prototype.remove=function(e){var t=e.entity.id;if(this.createPrimitive=this.geometry.remove(t)||this.createPrimitive,this.updaters.remove(t)){this.updatersWithAttributes.remove(t);var r=this.subscriptions.get(t);i(r)&&(r(),this.subscriptions.remove(t))}};var u=new t;l.prototype.update=function(e){var s,l,c=!0,h=0,d=this.primitive,p=this.primitives;if(this.createPrimitive){var m=this.geometry.values,f=m.length;if(f>0){for(i(d)&&(i(this.oldPrimitive)?p.remove(d):this.oldPrimitive=d),l=0;f>l;l++){var v=m[l],_=v.attributes;s=this.attributes.get(v.id.id),i(s)&&(i(_.show)&&(_.show.value=s.show),i(_.color)&&(_.color.value=s.color))}d=new a({asynchronous:!0,geometryInstances:m,appearance:new o({flat:!0,translucent:this.translucent,renderState:{lineWidth:this.width}})}),p.add(d),c=!1}else{i(d)&&(p.remove(d),d=void 0);var g=this.oldPrimitive;i(g)&&(p.remove(g),this.oldPrimitive=void 0)}this.attributes.removeAll(),this.primitive=d,this.createPrimitive=!1}else if(i(d)&&d.ready){i(this.oldPrimitive)&&(p.remove(this.oldPrimitive),this.oldPrimitive=void 0);var y=this.updatersWithAttributes.values,C=y.length;for(l=0;C>l;l++){var E=y[l],S=this.geometry.get(E.entity.id);if(s=this.attributes.get(S.id.id),i(s)||(s=d.getGeometryInstanceAttributes(S.id),this.attributes.set(S.id.id,s)),!E.outlineColorProperty.isConstant){var w=E.outlineColorProperty;w.getValue(e,u),t.equals(s._lastColor,u)||(s._lastColor=t.clone(u,s._lastColor),s.color=r.toValue(u,s.color),(this.translucent&&255===s.color[3]||!this.translucent&&255!==s.color[3])&&(this.itemsToRemove[h++]=E))}var T=E.entity.isShowing&&(E.hasConstantOutline||E.isOutlineVisible(e)),b=1===s.show[0];T!==b&&(s.show=n.toValue(T,s.show))}this.updateShows(d)}else i(d)&&!d.ready&&(c=!1);return this.itemsToRemove.length=h,c},l.prototype.updateShows=function(e){for(var t=this.showsUpdated.values,r=t.length,o=0;r>o;o++){var a=t[o],s=this.geometry.get(a.entity.id),l=this.attributes.get(s.id.id);i(l)||(l=e.getGeometryInstanceAttributes(s.id),this.attributes.set(s.id.id,l));var u=a.entity.isShowing,c=1===l.show[0];u!==c&&(l.show=n.toValue(u,l.show))}this.showsUpdated.removeAll()},l.prototype.contains=function(e){return this.updaters.contains(e.id)},l.prototype.getBoundingSphere=function(e,t){var r=this.primitive;if(!r.ready)return s.PENDING;var n=r.getGeometryInstanceAttributes(e);return!i(n)||!i(n.boundingSphere)||i(n.show)&&0===n.show[0]?s.FAILED:(n.boundingSphere.clone(t),s.DONE)},l.prototype.removeAllPrimitives=function(){var e=this.primitives,t=this.primitive;i(t)&&(e.remove(t),this.primitive=void 0,this.geometry.removeAll(),this.updaters.removeAll());var r=this.oldPrimitive;i(r)&&(e.remove(r),this.oldPrimitive=void 0)};var c=function(t,r){this._primitives=t,this._scene=r,this._solidBatches=new e,this._translucentBatches=new e};return c.prototype.add=function(e,t){var r,n,o=t.createOutlineGeometryInstance(e),a=this._scene.clampLineWidth(t.outlineWidth);255===o.attributes.color.value[3]?(r=this._solidBatches,n=r.get(a),i(n)||(n=new l(this._primitives,!1,a),r.set(a,n)),n.add(t,o)):(r=this._translucentBatches,n=r.get(a),i(n)||(n=new l(this._primitives,!0,a),r.set(a,n)),n.add(t,o))},c.prototype.remove=function(e){var t,r=this._solidBatches.values,i=r.length;for(t=0;i>t;t++)if(r[t].remove(e))return;var n=this._translucentBatches.values,o=n.length;for(t=0;o>t;t++)if(n[t].remove(e))return},c.prototype.update=function(e){var t,r,i,n,o,a=this._solidBatches.values,s=a.length,l=this._translucentBatches.values,u=l.length,c=!0,h=!1;do{for(h=!1,r=0;s>r;r++){n=a[r],c=n.update(e),o=n.itemsToRemove;var d=o.length;if(d>0)for(h=!0,t=0;d>t;t++)i=o[t],n.remove(i),this.add(e,i)}for(r=0;u>r;r++){n=l[r],c=n.update(e),o=n.itemsToRemove;var p=o.length;if(p>0)for(h=!0,t=0;p>t;t++)i=o[t],n.remove(i),this.add(e,i)}}while(h);return c},c.prototype.getBoundingSphere=function(e,t){var r,i=this._solidBatches.values,n=i.length;for(r=0;n>r;r++){var o=i[r];if(o.contains(e))return o.getBoundingSphere(e,t)}var a=this._translucentBatches.values,l=a.length;for(r=0;l>r;r++){var u=a[r];if(u.contains(e))return u.getBoundingSphere(e,t)}return s.FAILED},c.prototype.removeAllPrimitives=function(){var e,t=this._solidBatches.values,r=t.length;for(e=0;r>e;e++)t[e].removeAllPrimitives();var i=this._translucentBatches.values,n=i.length;for(e=0;n>e;e++)i[e].removeAllPrimitives()},c}),r("DataSources/GeometryVisualizer",["../Core/AssociativeArray","../Core/BoundingSphere","../Core/defined","../Core/destroyObject","../Core/DeveloperError","./BoundingSphereState","./ColorMaterialProperty","./StaticGeometryColorBatch","./StaticGeometryPerMaterialBatch","./StaticOutlineGeometryBatch"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){for(var r=e._batches,i=r.length,n=0;i>n;n++)r[n].remove(t)}function h(e,t,r){return r.isDynamic?void e._dynamicBatch.add(t,r):(r.outlineEnabled&&e._outlineBatch.add(t,r),void(r.fillEnabled&&(r.isClosed?r.fillMaterialProperty instanceof a?e._closedColorBatch.add(t,r):e._closedMaterialBatch.add(t,r):r.fillMaterialProperty instanceof a?e._openColorBatch.add(t,r):e._openMaterialBatch.add(t,r))))}var d=[],p=function(t){this._primitives=t,this._dynamicUpdaters=new e};p.prototype.add=function(e,t){this._dynamicUpdaters.set(t.entity.id,t.createDynamicUpdater(this._primitives))},p.prototype.remove=function(e){var t=e.entity.id,i=this._dynamicUpdaters.get(t);r(i)&&(this._dynamicUpdaters.remove(t),i.destroy())},p.prototype.update=function(e){for(var t=this._dynamicUpdaters.values,r=0,i=t.length;i>r;r++)t[r].update(e);return!0},p.prototype.removeAllPrimitives=function(){for(var e=this._dynamicUpdaters.values,t=0,r=e.length;r>t;t++)e[t].destroy();this._dynamicUpdaters.removeAll()},p.prototype.getBoundingSphere=function(e,t){var i=this._dynamicUpdaters.get(e.id);return r(i)&&r(i.getBoundingSphere)?i.getBoundingSphere(e,t):o.FAILED};var m=function(t,r,i){this._type=t;var n=r.primitives;this._scene=r,this._primitives=n,this._entityCollection=void 0,this._addedObjects=new e,this._removedObjects=new e,this._changedObjects=new e,this._outlineBatch=new u(n,r),this._closedColorBatch=new s(n,t.perInstanceColorAppearanceType,!0),this._closedMaterialBatch=new l(n,t.materialAppearanceType,!0),this._openColorBatch=new s(n,t.perInstanceColorAppearanceType,!1),this._openMaterialBatch=new l(n,t.materialAppearanceType,!1),this._dynamicBatch=new p(n),this._batches=[this._closedColorBatch,this._closedMaterialBatch,this._openColorBatch,this._openMaterialBatch,this._dynamicBatch,this._outlineBatch],this._subscriptions=new e,this._updaters=new e,this._entityCollection=i,i.collectionChanged.addEventListener(m.prototype._onCollectionChanged,this),this._onCollectionChanged(i,i.values,d)};m.prototype.update=function(e){var t,r,i,n,o=this._addedObjects,a=o.values,s=this._removedObjects,l=s.values,u=this._changedObjects,d=u.values;for(t=d.length-1;t>-1;t--)r=d[t],i=r.id,n=this._updaters.get(i),n.entity===r?(c(this,n),h(this,e,n)):(l.push(r),a.push(r));for(t=l.length-1;t>-1;t--)r=l[t],i=r.id,n=this._updaters.get(i),c(this,n),n.destroy(),this._updaters.remove(i),this._subscriptions.get(i)(),this._subscriptions.remove(i);for(t=a.length-1;t>-1;t--)r=a[t],i=r.id,n=new this._type(r,this._scene),this._updaters.set(i,n),h(this,e,n),this._subscriptions.set(i,n.geometryChanged.addEventListener(m._onGeometryChanged,this));o.removeAll(),s.removeAll(),u.removeAll();var p=!0,f=this._batches,v=f.length;for(t=0;v>t;t++)p=f[t].update(e)&&p;return p};var f=[],v=new t;return m.prototype.getBoundingSphere=function(e,r){for(var i=f,n=v,a=0,s=o.DONE,l=this._batches,u=l.length,c=0;u>c;c++){if(s=l[c].getBoundingSphere(e,n),s===o.PENDING)return o.PENDING;s===o.DONE&&(i[a]=t.clone(n,i[a]),a++)}return 0===a?o.FAILED:(i.length=a,t.fromBoundingSpheres(i,r),o.DONE)},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){this._entityCollection.collectionChanged.removeEventListener(m.prototype._onCollectionChanged,this),this._addedObjects.removeAll(),this._removedObjects.removeAll();var e,t=this._batches,r=t.length;for(e=0;r>e;e++)t[e].removeAllPrimitives();var n=this._subscriptions.values;for(r=n.length,e=0;r>e;e++)n[e]();return this._subscriptions.removeAll(),i(this)},m._onGeometryChanged=function(e){var t=this._removedObjects,i=this._changedObjects,n=e.entity,o=n.id;r(t.get(o))||r(i.get(o))||i.set(o,n)},m.prototype._onCollectionChanged=function(e,t,r){var i,n,o,a=this._addedObjects,s=this._removedObjects,l=this._changedObjects;for(i=r.length-1;i>-1;i--)o=r[i],n=o.id,a.remove(n)||(s.set(n,o),l.remove(n));for(i=t.length-1;i>-1;i--)o=t[i],n=o.id,s.remove(n)?l.set(n,o):a.set(n,o)},m}),r("Scene/Label",["../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/NearFarScalar","./Billboard","./HeightReference","./HorizontalOrigin","./LabelStyle","./VerticalOrigin"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e){e._rebindAllGlyphs||e._repositionAllGlyphs||e._labelCollection._labelsToUpdate.push(e),e._rebindAllGlyphs=!0}function m(e){e._rebindAllGlyphs||e._repositionAllGlyphs||e._labelCollection._labelsToUpdate.push(e),e._repositionAllGlyphs=!0}var f=function(n,o){n=i(n,i.EMPTY_OBJECT),this._text=i(n.text,""),this._show=i(n.show,!0),this._font=i(n.font,"30px sans-serif"),this._fillColor=r.clone(i(n.fillColor,r.WHITE)),this._outlineColor=r.clone(i(n.outlineColor,r.BLACK)),this._outlineWidth=i(n.outlineWidth,1),this._style=i(n.style,h.FILL),this._verticalOrigin=i(n.verticalOrigin,d.BOTTOM),this._horizontalOrigin=i(n.horizontalOrigin,c.LEFT),this._pixelOffset=e.clone(i(n.pixelOffset,e.ZERO)),this._eyeOffset=t.clone(i(n.eyeOffset,t.ZERO)),this._position=t.clone(i(n.position,t.ZERO)),this._scale=i(n.scale,1),this._id=n.id,this._translucencyByDistance=n.translucencyByDistance,this._pixelOffsetScaleByDistance=n.pixelOffsetScaleByDistance,this._heightReference=i(n.heightReference,u.NONE),this._labelCollection=o,this._glyphs=[],this._rebindAllGlyphs=!0,this._repositionAllGlyphs=!0,this._actualClampedPosition=void 0,this._removeCallbackFunc=void 0,this._mode=void 0,this._updateClamping()};return o(f.prototype,{show:{get:function(){return this._show},set:function(e){if(this._show!==e){this._show=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.show=e)}}}},position:{get:function(){return this._position},set:function(e){var r=this._position;if(!t.equals(r,e))if(t.clone(e,r),this._heightReference===u.NONE)for(var i=this._glyphs,o=0,a=i.length;a>o;o++){var s=i[o];n(s.billboard)&&(s.billboard.position=e)}else this._updateClamping()}},heightReference:{get:function(){return this._heightReference},set:function(e){e!==this._heightReference&&(this._heightReference=e,this._updateClamping())}},text:{get:function(){return this._text},set:function(e){this._text!==e&&(this._text=e,p(this))}},font:{get:function(){return this._font},set:function(e){this._font!==e&&(this._font=e,p(this))}},fillColor:{get:function(){return this._fillColor},set:function(e){var t=this._fillColor;r.equals(t,e)||(r.clone(e,t),p(this))}},outlineColor:{get:function(){return this._outlineColor},set:function(e){var t=this._outlineColor;r.equals(t,e)||(r.clone(e,t),p(this))}},outlineWidth:{get:function(){return this._outlineWidth},set:function(e){this._outlineWidth!==e&&(this._outlineWidth=e,p(this))}},style:{get:function(){return this._style},set:function(e){this._style!==e&&(this._style=e,p(this))}},pixelOffset:{get:function(){return this._pixelOffset},set:function(t){var r=this._pixelOffset;if(!e.equals(r,t)){e.clone(t,r);for(var i=this._glyphs,o=0,a=i.length;a>o;o++){var s=i[o];n(s.billboard)&&(s.billboard.pixelOffset=t)}}}},translucencyByDistance:{get:function(){return this._translucencyByDistance},set:function(e){var t=this._translucencyByDistance;if(!s.equals(t,e)){this._translucencyByDistance=s.clone(e,t);for(var r=this._glyphs,i=0,o=r.length;o>i;i++){var a=r[i];n(a.billboard)&&(a.billboard.translucencyByDistance=e)}}}},pixelOffsetScaleByDistance:{get:function(){return this._pixelOffsetScaleByDistance},set:function(e){var t=this._pixelOffsetScaleByDistance;if(!s.equals(t,e)){this._pixelOffsetScaleByDistance=s.clone(e,t);for(var r=this._glyphs,i=0,o=r.length;o>i;i++){var a=r[i];n(a.billboard)&&(a.billboard.pixelOffsetScaleByDistance=e)}}}},eyeOffset:{get:function(){return this._eyeOffset},set:function(e){var r=this._eyeOffset;if(!t.equals(r,e)){t.clone(e,r);for(var i=this._glyphs,o=0,a=i.length;a>o;o++){var s=i[o];n(s.billboard)&&(s.billboard.eyeOffset=e)}}}},horizontalOrigin:{get:function(){return this._horizontalOrigin},set:function(e){this._horizontalOrigin!==e&&(this._horizontalOrigin=e,m(this))}},verticalOrigin:{get:function(){return this._verticalOrigin},set:function(e){if(this._verticalOrigin!==e){this._verticalOrigin=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.verticalOrigin=e)}m(this)}}},scale:{get:function(){return this._scale},set:function(e){if(this._scale!==e){this._scale=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.scale=e)}m(this)}}},id:{get:function(){return this._id},set:function(e){if(this._id!==e){this._id=e;for(var t=this._glyphs,r=0,i=t.length;i>r;r++){var o=t[r];n(o.billboard)&&(o.billboard.id=e)}}}},_clampedPosition:{get:function(){return this._actualClampedPosition},set:function(e){this._actualClampedPosition=t.clone(e,this._actualClampedPosition);for(var r=this._glyphs,i=0,o=r.length;o>i;i++){var a=r[i];n(a.billboard)&&(a.billboard.position=e)}}}}),f.prototype._updateClamping=function(){l._updateClamping(this._labelCollection,this)},f.prototype.computeScreenSpacePosition=function(t,r){n(r)||(r=new e);var i=this._labelCollection,o=i.modelMatrix,a=l._computeActualPosition(this,this._position,t.frameState,o),s=l._computeScreenSpacePosition(o,a,this._eyeOffset,this._pixelOffset,t,r);return s.y=t.canvas.clientHeight-s.y,s},f.prototype.equals=function(i){return this===i||n(i)&&this._show===i._show&&this._scale===i._scale&&this._style===i._style&&this._verticalOrigin===i._verticalOrigin&&this._horizontalOrigin===i._horizontalOrigin&&this._text===i._text&&this._font===i._font&&t.equals(this._position,i._position)&&r.equals(this._fillColor,i._fillColor)&&r.equals(this._outlineColor,i._outlineColor)&&e.equals(this._pixelOffset,i._pixelOffset)&&t.equals(this._eyeOffset,i._eyeOffset)&&s.equals(this._translucencyByDistance,i._translucencyByDistance)&&s.equals(this._pixelOffsetScaleByDistance,i._pixelOffsetScaleByDistance)&&this._id===i._id},f.prototype.isDestroyed=function(){return!1},f}),r("Scene/LabelCollection",["../Core/Cartesian2","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Matrix4","../Core/writeTextToCanvas","./BillboardCollection","./HorizontalOrigin","./Label","./LabelStyle","./TextureAtlas","./VerticalOrigin"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(){this.textureInfo=void 0,this.dimensions=void 0,this.billboard=void 0}function f(e,t,r){this.labelCollection=e,this.index=t,this.dimensions=r}function v(e,t,r,i,n,o,a){return S.font=t,S.fillColor=r,S.strokeColor=i,S.strokeWidth=n,a===p.BOTTOM?S.textBaseline="bottom":a===p.TOP?S.textBaseline="top":S.textBaseline="middle",S.fill=o===h.FILL||o===h.FILL_AND_OUTLINE,S.stroke=o===h.OUTLINE||o===h.FILL_AND_OUTLINE,s(e,S)}function _(e,t){t.textureInfo=void 0,t.dimensions=void 0;var i=t.billboard;r(i)&&(i.show=!1,i.image=void 0,e._spareBillboards.push(i),t.billboard=void 0)}function g(e,t,r,i){e.addImage(t,r).then(function(e,t){i.index=e})}function y(e,t){var i,n,o,a=t._text,s=a.length,l=t._glyphs,c=l.length;if(c>s)for(n=s;c>n;++n)_(e,l[n]);l.length=s;var h=e._glyphTextureCache;for(o=0;s>o;++o){var d=a.charAt(o),p=t._font,y=t._fillColor,C=t._outlineColor,E=t._outlineWidth,S=t._style,w=t._verticalOrigin,T=JSON.stringify([d,p,y.toRgba(),C.toRgba(),E,+S,+w]),b=h[T];if(!r(b)){var x=v(d,p,y,C,E,S,w);b=new f(e,-1,x.dimensions),h[T]=b,x.width>0&&x.height>0&&g(e._textureAtlas,T,x,b)}if(i=l[o],r(i)?-1===b.index?_(e,i):r(i.textureInfo)&&(i.textureInfo=void 0):(i=new m, -l[o]=i),i.textureInfo=b,i.dimensions=b.dimensions,-1!==b.index){var P=i.billboard;r(P)||(P=e._spareBillboards.length>0?e._spareBillboards.pop():e._billboardCollection.add({collection:e}),i.billboard=P),P.show=t._show,P.position=t._position,P.eyeOffset=t._eyeOffset,P.pixelOffset=t._pixelOffset,P.horizontalOrigin=u.LEFT,P.verticalOrigin=t._verticalOrigin,P.scale=t._scale,P.pickPrimitive=t,P.id=t._id,P.image=T,P.translucencyByDistance=t._translucencyByDistance,P.pixelOffsetScaleByDistance=t._pixelOffsetScaleByDistance}}t._repositionAllGlyphs=!0}function C(e,t){var i,n,o=e._glyphs,a=0,s=0,l=0,c=o.length;for(l=0;c>l;++l)i=o[l],n=i.dimensions,a+=n.computedWidth,s=Math.max(s,n.height);var h=e._scale,d=e._horizontalOrigin,m=0;d===u.CENTER?m-=a/2*h:d===u.RIGHT&&(m-=a*h),w.x=m*t,w.y=0;var f=e._verticalOrigin;for(l=0;c>l;++l)i=o[l],n=i.dimensions,f===p.BOTTOM||n.height===s?w.y=-n.descent*h:f===p.TOP?w.y=-(s-n.height)*h-n.descent*h:f===p.CENTER&&(w.y=-(s-n.height)/2*h-n.descent*h),w.y*=t,r(i.billboard)&&i.billboard._setTranslate(w),w.x+=n.computedWidth*h*t}function E(e,t){for(var i=t._glyphs,o=0,a=i.length;a>o;++o)_(e,i[o]);t._labelCollection=void 0,r(t._removeCallbackFunc)&&t._removeCallbackFunc(),n(t)}var S={},w=new e,T=function(e){e=t(e,t.EMPTY_OBJECT),this._scene=e.scene,this._textureAtlas=void 0,this._billboardCollection=new l({scene:this._scene}),this._billboardCollection.destroyTextureAtlas=!1,this._spareBillboards=[],this._glyphTextureCache={},this._labels=[],this._labelsToUpdate=[],this._totalGlyphCount=0,this._resolutionScale=void 0,this.modelMatrix=a.clone(t(e.modelMatrix,a.IDENTITY)),this.debugShowBoundingVolume=t(e.debugShowBoundingVolume,!1)};return i(T.prototype,{length:{get:function(){return this._labels.length}}}),T.prototype.add=function(e){var t=new c(e,this);return this._labels.push(t),this._labelsToUpdate.push(t),t},T.prototype.remove=function(e){if(r(e)&&e._labelCollection===this){var t=this._labels.indexOf(e);if(-1!==t)return this._labels.splice(t,1),E(this,e),!0}return!1},T.prototype.removeAll=function(){for(var e=this._labels,t=0,r=e.length;r>t;++t)E(this,e[t]);e.length=0},T.prototype.contains=function(e){return r(e)&&e._labelCollection===this},T.prototype.get=function(e){return this._labels[e]},T.prototype.update=function(e){var t=this._billboardCollection;t.modelMatrix=this.modelMatrix,t.debugShowBoundingVolume=this.debugShowBoundingVolume;var i=e.context;r(this._textureAtlas)||(this._textureAtlas=new d({context:i}),t.textureAtlas=this._textureAtlas);var n=i.uniformState,o=n.resolutionScale,a=this._resolutionScale!==o;this._resolutionScale=o;var s;s=a?this._labels:this._labelsToUpdate;for(var l=s.length,u=0;l>u;++u){var c=s[u];if(!c.isDestroyed()){var h=c._glyphs.length;c._rebindAllGlyphs&&(y(this,c),c._rebindAllGlyphs=!1),(a||c._repositionAllGlyphs)&&(C(c,o),c._repositionAllGlyphs=!1);var p=c._glyphs.length-h;this._totalGlyphCount+=p}}this._labelsToUpdate.length=0,t.update(e)},T.prototype.isDestroyed=function(){return!1},T.prototype.destroy=function(){return this.removeAll(),this._billboardCollection=this._billboardCollection.destroy(),this._textureAtlas=this._textureAtlas&&this._textureAtlas.destroy(),n(this)},T}),r("DataSources/LabelVisualizer",["../Core/AssociativeArray","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/NearFarScalar","../Scene/HorizontalOrigin","../Scene/LabelCollection","../Scene/LabelStyle","../Scene/VerticalOrigin","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){if(n(e)){var r=e.label;n(r)&&(t.push(e.index),r.show=!1,e.label=void 0,e.index=-1)}}var f=1,v="30px sans-serif",_=c.FILL,g=i.WHITE,y=i.BLACK,C=1,E=t.ZERO,S=r.ZERO,w=l.CENTER,T=h.CENTER,b=new r,x=new i,P=new i,A=new r,I=new t,M=new s,D=new s,R=function(e){this.entity=e,this.label=void 0,this.index=void 0},O=function(t,r){r.collectionChanged.addEventListener(O.prototype._onCollectionChanged,this),this._scene=t,this._unusedIndexes=[],this._labelCollection=void 0,this._entityCollection=r,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return O.prototype.update=function(e){for(var t=this._items.values,r=this._unusedIndexes,i=0,o=t.length;o>i;i++){var a,s=t[i],l=s.entity,c=l._label,h=s.label,d=l.isShowing&&l.isAvailable(e)&&p.getValueOrDefault(c._show,e,!0);if(d&&(b=p.getValueOrUndefined(l._position,e,b),a=p.getValueOrUndefined(c._text,e),d=n(b)&&n(a)),d){if(!n(h)){var R=this._labelCollection;n(R)||(R=new u,this._labelCollection=R,this._scene.primitives.add(R));var O=r.length;if(O>0){var N=r.pop();s.index=N,h=R.get(N)}else h=R.add(),s.index=R.length-1;h.id=l,s.label=h}h.show=!0,h.position=b,h.text=a,h.scale=p.getValueOrDefault(c._scale,e,f),h.font=p.getValueOrDefault(c._font,e,v),h.style=p.getValueOrDefault(c._style,e,_),h.fillColor=p.getValueOrDefault(c._fillColor,e,g,x),h.outlineColor=p.getValueOrDefault(c._outlineColor,e,y,P),h.outlineWidth=p.getValueOrDefault(c._outlineWidth,e,C),h.pixelOffset=p.getValueOrDefault(c._pixelOffset,e,E,I),h.eyeOffset=p.getValueOrDefault(c._eyeOffset,e,S,A),h.horizontalOrigin=p.getValueOrDefault(c._horizontalOrigin,e,w),h.verticalOrigin=p.getValueOrDefault(c._verticalOrigin,e,T),h.translucencyByDistance=p.getValueOrUndefined(c._translucencyByDistance,e,M),h.pixelOffsetScaleByDistance=p.getValueOrUndefined(c._pixelOffsetScaleByDistance,e,D)}else m(s,r)}return!0},O.prototype.getBoundingSphere=function(e,t){var i=this._items.get(e.id);return n(i)&&n(i.label)?(t.center=r.clone(i.label.position,t.center),t.radius=0,d.DONE):d.FAILED},O.prototype.isDestroyed=function(){return!1},O.prototype.destroy=function(){return this._entityCollection.collectionChanged.removeEventListener(O.prototype._onCollectionChanged,this),n(this._labelCollection)&&this._scene.primitives.remove(this._labelCollection),o(this)},O.prototype._onCollectionChanged=function(e,t,r,i){var o,a,s=this._unusedIndexes,l=this._items;for(o=t.length-1;o>-1;o--)a=t[o],n(a._label)&&n(a._position)&&l.set(a.id,new R(a));for(o=i.length-1;o>-1;o--)a=i[o],n(a._label)&&n(a._position)?l.contains(a.id)||l.set(a.id,new R(a)):(m(l.get(a.id),s),l.remove(a.id));for(o=r.length-1;o>-1;o--)a=r[o],m(l.get(a.id),s),l.remove(a.id)},O}),r("ThirdParty/gltfDefaults",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/Quaternion","../Renderer/WebGLConstants"],function(e,t,r,i,n){"use strict";function o(e){r(e.accessors)||(e.accessors={});var i=e.accessors;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];o.byteStride=t(o.byteStride,0)}}function a(e){r(e.animations)||(e.animations={});var i=e.animations;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];r(o.channels)||(o.channels=[]),r(o.parameters)||(o.parameters={}),r(o.samplers)||(o.samplers={});var a=i.samplers;for(var s in a)if(a.hasOwnProperty(s)){var l=a[s];l.interpolation=t(l.interpolation,"LINEAR")}}}function s(e){r(e.asset)||(e.asset={});var i=e.asset;r(i.profile)&&"string"!=typeof i.profile||(i.profile={});var n=i.profile;i.premultipliedAlpha=t(i.premultipliedAlpha,!1),n.api=t(n.api,"WebGL"),n.version=t(n.version,"1.0.2"),r(e.version)&&(i.version=t(i.version,e.version),delete e.version),"number"==typeof i.version&&(i.version=i.version.toFixed(1).toString())}function l(e){r(e.buffers)||(e.buffers={});var i=e.buffers;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];o.type=t(o.type,"arraybuffer")}}function u(e){r(e.bufferViews)||(e.bufferViews={})}function c(e){r(e.cameras)||(e.cameras={})}function h(e){r(e.images)||(e.images={})}function d(e){r(e.extensions)||(e.extensions={});var i=e.extensions;r(i.KHR_materials_common)||(i.KHR_materials_common={});var n=i.KHR_materials_common;r(e.lights)?(n.lights=e.lights,delete e.lights):r(n.lights)||(n.lights={});var o=n.lights;for(var a in o)if(o.hasOwnProperty(a)){var s=o[a];if("ambient"===s.type){r(s.ambient)||(s.ambient={});var l=s.ambient;r(l.color)||(l.color=[1,1,1])}else if("directional"===s.type){r(s.directional)||(s.directional={});var u=s.directional;r(u.color)||(u.color=[1,1,1])}else if("point"===s.type){r(s.point)||(s.point={});var c=s.point;r(c.color)||(c.color=[1,1,1]),c.constantAttenuation=t(c.constantAttenuation,1),c.linearAttenuation=t(c.linearAttenuation,0),c.quadraticAttenuation=t(c.quadraticAttenuation,0)}else if("spot"===s.type){r(s.spot)||(s.spot={});var h=s.spot;r(h.color)||(h.color=[1,1,1]),h.constantAttenuation=t(h.constantAttenuation,1),h.fallOffAngle=t(h.fallOffAngle,3.14159265),h.fallOffExponent=t(h.fallOffExponent,0),h.linearAttenuation=t(h.linearAttenuation,0),h.quadraticAttenuation=t(h.quadraticAttenuation,0)}}}function p(e){r(e.materials)||(e.materials={});var t=e.materials;for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a=o.instanceTechnique;if(r(a)&&(o.technique=a.technique,o.values=a.values,delete o.instanceTechnique),!r(o.extensions))if(r(o.technique))r(o.values)||(o.values={});else{delete o.values,o.extensions={KHR_materials_common:{technique:"CONSTANT",transparent:!1,values:{emission:{type:n.FLOAT_VEC4,value:[.5,.5,.5,1]}}}},r(e.extensionsUsed)||(e.extensionsUsed=[]);var s=e.extensionsUsed;-1===s.indexOf("KHR_materials_common")&&s.push("KHR_materials_common")}}}function m(e){r(e.meshes)||(e.meshes={});var i=e.meshes;for(var o in i)if(i.hasOwnProperty(o)){var a=i[o];r(a.primitives)||(a.primitives=[]);for(var s=a.primitives.length,l=s.length,u=0;l>u;++u){var c=s[u];r(c.attributes)||(c.attributes={});var h=t(c.primitive,n.TRIANGLES);c.mode=t(c.mode,h)}}}function f(t){r(t.nodes)||(t.nodes={});var n=t.nodes,o=parseFloat(t.asset.version)<1,a=new e,s=new i;for(var l in n)if(n.hasOwnProperty(l)){var u=n[l];if(r(u.children)||(u.children=[]),o&&r(u.rotation)){var c=u.rotation;e.fromArray(c,0,a),i.fromAxisAngle(a,c[3],s),u.rotation=[s.x,s.y,s.z,s.w]}r(u.matrix)||(r(u.translation)||r(u.rotation)||r(u.scale)?(r(u.translation)||(u.translation=[0,0,0]),r(u.rotation)||(u.rotation=[0,0,0,1]),r(u.scale)||(u.scale=[1,1,1])):u.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);var h=u.instanceSkin;r(h)&&(u.skeletons=h.skeletons,u.skin=h.skin,u.meshes=h.meshes,delete u.instanceSkin)}}function v(e){r(e.programs)||(e.programs={});var t=e.programs;for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];r(n.attributes)||(n.attributes=[])}}function _(e){r(e.samplers)||(e.samplers={});var i=e.samplers;for(var o in i)if(i.hasOwnProperty(o)){var a=i[o];a.magFilter=t(a.magFilter,n.LINEAR),a.minFilter=t(a.minFilter,n.NEAREST_MIPMAP_LINEAR),a.wrapS=t(a.wrapS,n.REPEAT),a.wrapT=t(a.wrapT,n.REPEAT)}}function g(e){r(e.scenes)||(e.scenes={});var t=e.scenes;for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];r(n.node)||(n.node=[])}}function y(e){r(e.shaders)||(e.shaders={})}function C(e){r(e.skins)||(e.skins={});var t=e.skins;for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];r(n.bindShapeMatrix)&&(n.bindShapeMatrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1])}}function E(e){r(e.enable)||(e.enable=[]),r(e.disable)||(e.disable=[])}function S(e){r(e.techniques)||(e.techniques={});var i=e.techniques;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];r(o.parameters)||(o.parameters={});var a=o.parameters;for(var s in a){var l=a[s];l.node=t(l.node,l.source),l.source=void 0}var u=o.passes;if(r(u)){var c=t(o.pass,"defaultPass");if(u.hasOwnProperty(c)){var h=u[c],d=h.instanceProgram;o.attributes=t(o.attributes,d.attributes),o.program=t(o.program,d.program),o.uniforms=t(o.uniforms,d.uniforms),o.states=t(o.states,h.states)}o.passes=void 0,o.pass=void 0}r(o.attributes)||(o.attributes={}),r(o.uniforms)||(o.uniforms={}),r(o.states)||(o.states={}),E(o.states)}}function w(e){r(e.textures)||(e.textures={});var i=e.textures;for(var o in i)if(i.hasOwnProperty(o)){var a=i[o];a.format=t(a.format,n.RGBA),a.internalFormat=t(a.internalFormat,a.format),a.target=t(a.target,n.TEXTURE_2D),a.type=t(a.type,n.UNSIGNED_BYTE)}}var T=function(e){return r(e)?(r(e.allExtensions)&&(e.extensionsUsed=e.allExtensions,e.allExtensions=void 0),e.extensionsUsed=t(e.extensionsUsed,[]),o(e),a(e),s(e),l(e),u(e),c(e),h(e),d(e),p(e),m(e),f(e),v(e),_(e),g(e),y(e),C(e),S(e),w(e),e):void 0};return T}),r("Scene/getModelAccessor",["../Core/ComponentDatatype"],function(e){"use strict";var t={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},r=function(r){var i=r.componentType,n=t[r.type];return{componentsPerAttribute:n,createArrayBufferView:function(t,r,o){return e.createArrayBufferView(i,t,r,n*o)}}};return r}),r("Scene/ModelAnimationCache",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/LinearSpline","../Core/Matrix4","../Core/Quaternion","../Core/QuaternionSpline","../Renderer/WebGLConstants","./getModelAccessor"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e,r){var i=e.gltf,n=i.buffers,o=i.bufferViews,a=o[r.bufferView],s=n[a.buffer],u=a.byteOffset+r.byteOffset,c=r.count*l(r).componentsPerAttribute;return e.cacheKey+"//"+t(s.path,"")+"/"+u+"/"+c}function c(e,t,r){return e.cacheKey+"//"+t+"/"+r}var h=function(){},d={},p=new e;h.getAnimationParameterValues=function(t,i){var n=u(t,i),a=d[n];if(!r(a)){var c,h=t._loadResources,m=t.gltf,f=parseFloat(m.asset.version)<1,v=m.bufferViews,_=v[i.bufferView],g=i.componentType,y=i.type,C=i.count,E=h.getBuffer(_),S=l(i).createArrayBufferView(E.buffer,E.byteOffset+i.byteOffset,C);if(g===s.FLOAT&&"SCALAR"===y)a=S;else if(g===s.FLOAT&&"VEC3"===y)for(a=new Array(C),c=0;C>c;++c)a[c]=e.fromArray(S,3*c);else if(g===s.FLOAT&&"VEC4"===y)for(a=new Array(C),c=0;C>c;++c){var w=4*c;f?a[c]=o.fromAxisAngle(e.fromArray(S,w,p),S[w+3]):a[c]=o.unpack(S,w)}r(t.cacheKey)&&(d[n]=a)}return a};var m={},f=function(e){this._value=e};f.prototype.evaluate=function(e,t){return this._value},h.getAnimationSpline=function(e,t,n,o,l,u){var h=c(e,t,o),d=m[h];if(!r(d)){var p=u[l.input],v=e.gltf.accessors[n.parameters[l.output]],_=u[l.output];if(1===p.length&&1===_.length)d=new f(_[0]);else{var g=v.componentType,y=v.type;"LINEAR"===l.interpolation&&(g===s.FLOAT&&"VEC3"===y?d=new i({times:p,points:_}):g===s.FLOAT&&"VEC4"===y&&(d=new a({times:p,points:_})))}r(e.cacheKey)&&(m[h]=d)}return d};var v={};return h.getSkinInverseBindMatrices=function(e,t){var i=u(e,t),o=v[i];if(!r(o)){var a=e._loadResources,c=e.gltf,h=c.bufferViews,d=h[t.bufferView],p=t.componentType,m=t.type,f=t.count,_=a.getBuffer(d),g=l(t).createArrayBufferView(_.buffer,_.byteOffset+t.byteOffset,f);if(o=new Array(f),p===s.FLOAT&&"MAT4"===m)for(var y=0;f>y;++y)o[y]=n.fromArray(g,16*y);v[i]=o}return o},h}),r("Scene/ModelAnimationLoop",["../Core/freezeObject"],function(e){"use strict";var t={NONE:0,REPEAT:1,MIRRORED_REPEAT:2};return e(t)}),r("Scene/ModelAnimationState",["../Core/freezeObject"],function(e){"use strict";return e({STOPPED:0,ANIMATING:1})}),r("Scene/ModelAnimation",["../Core/defaultValue","../Core/defineProperties","../Core/Event","../Core/JulianDate","./ModelAnimationLoop","./ModelAnimationState"],function(e,t,r,i,n,o){"use strict";var a=function(t,a,s){this._name=t.name,this._startTime=i.clone(t.startTime),this._delay=e(t.delay,0),this._stopTime=t.stopTime,this.removeOnStop=e(t.removeOnStop,!1),this._speedup=e(t.speedup,1),this._reverse=e(t.reverse,!1),this._loop=e(t.loop,n.NONE),this.start=new r,this.update=new r,this.stop=new r,this._state=o.STOPPED,this._runtimeAnimation=s,this._computedStartTime=void 0,this._duration=void 0;var l=this;this._raiseStartEvent=function(){l.start.raiseEvent(a,l)},this._updateEventTime=0,this._raiseUpdateEvent=function(){l.update.raiseEvent(a,l,l._updateEventTime)},this._raiseStopEvent=function(){l.stop.raiseEvent(a,l)}};return t(a.prototype,{name:{get:function(){return this._name}},startTime:{get:function(){return this._startTime}},delay:{get:function(){return this._delay}},stopTime:{get:function(){return this._stopTime}},speedup:{get:function(){return this._speedup}},reverse:{get:function(){return this._reverse}},loop:{get:function(){return this._loop}}}),a}),r("Scene/ModelAnimationCollection",["../Core/clone","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/JulianDate","../Core/Math","./ModelAnimation","./ModelAnimationLoop","./ModelAnimationState"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t){for(var r=e.channelEvaluators,i=r.length,n=0;i>n;++n)r[n](t)}function d(e,t,r){return function(){e.animationRemoved.raiseEvent(t,r)}}var p=function(e){this.animationAdded=new o,this.animationRemoved=new o,this._model=e,this._scheduledAnimations=[],this._previousTime=void 0};i(p.prototype,{length:{get:function(){return this._scheduledAnimations.length}}}),p.prototype.add=function(e){e=t(e,t.EMPTY_OBJECT);var r=this._model,i=r._runtime.animations,n=i[e.name],o=new l(e,r,n);return this._scheduledAnimations.push(o),this.animationAdded.raiseEvent(r,o),o},p.prototype.addAll=function(r){r=t(r,t.EMPTY_OBJECT),r=e(r);for(var i=[],n=this._model._animationIds,o=n.length,a=0;o>a;++a)r.name=n[a],i.push(this.add(r));return i},p.prototype.remove=function(e){if(r(e)){var t=this._scheduledAnimations,i=t.indexOf(e);if(-1!==i)return t.splice(i,1),this.animationRemoved.raiseEvent(this._model,e),!0}return!1},p.prototype.removeAll=function(){var e=this._model,t=this._scheduledAnimations,r=t.length;this._scheduledAnimations=[];for(var i=0;r>i;++i)this.animationRemoved.raiseEvent(e,t[i])},p.prototype.contains=function(e){return r(e)?-1!==this._scheduledAnimations.indexOf(e):!1},p.prototype.get=function(e){return this._scheduledAnimations[e]};var m=[];return p.prototype.update=function(e){var i=this._scheduledAnimations,n=i.length;if(0===n)return this._previousTime=void 0,!1;if(a.equals(e.time,this._previousTime))return!1;this._previousTime=a.clone(e.time,this._previousTime);for(var o=!1,l=e.time,p=this._model,f=0;n>f;++f){var v=i[f],_=v._runtimeAnimation;r(v._computedStartTime)||(v._computedStartTime=a.addSeconds(t(v.startTime,l),v.delay,new a)),r(v._duration)||(v._duration=_.stopTime*(1/v.speedup));var g=v._computedStartTime,y=v._duration,C=v.stopTime,E=0!==y?a.secondsDifference(l,g)/y:0,S=E>=0,w=S&&(1>=E||v.loop===u.REPEAT||v.loop===u.MIRRORED_REPEAT)&&(!r(C)||a.lessThanOrEquals(l,C));if(w){if(v._state===c.STOPPED&&(v._state=c.ANIMATING,v.start.numberOfListeners>0&&e.afterRender.push(v._raiseStartEvent)),v.loop===u.REPEAT)E-=Math.floor(E);else if(v.loop===u.MIRRORED_REPEAT){var T=Math.floor(E),b=E-T;E=T%2===1?1-b:b}v.reverse&&(E=1-E);var x=E*y*v.speedup;x=s.clamp(x,_.startTime,_.stopTime),h(_,x),v.update.numberOfListeners>0&&(v._updateEventTime=x,e.afterRender.push(v._raiseUpdateEvent)),o=!0}else S&&v._state===c.ANIMATING&&(v._state=c.STOPPED,v.stop.numberOfListeners>0&&e.afterRender.push(v._raiseStopEvent),v.removeOnStop&&m.push(v))}n=m.length;for(var P=0;n>P;++P){var A=m[P];i.splice(i.indexOf(A),1),e.afterRender.push(d(this,p,A))}return m.length=0,o},p}),r("Scene/modelMaterialsCommon",["../Core/defaultValue","../Core/defined","../Renderer/WebGLConstants"],function(e,t,r){"use strict";function i(e){switch(e){case r.FLOAT:return"float";case r.FLOAT_VEC2:return"vec2";case r.FLOAT_VEC3:return"vec3";case r.FLOAT_VEC4:return"vec4";case r.FLOAT_MAT2:return"mat2";case r.FLOAT_MAT3:return"mat3";case r.FLOAT_MAT4:return"mat4";case r.SAMPLER_2D:return"sampler2D"}}function n(e){var i,n={};if(t(e.extensions)&&t(e.extensions.KHR_materials_common)&&(i=e.extensions.KHR_materials_common.lights),t(i)){var o=e.nodes;for(var a in o)if(o.hasOwnProperty(a)){var s=o[a];if(t(s.extensions)&&t(s.extensions.KHR_materials_common)){var l=s.extensions.KHR_materials_common.light;t(l)&&t(i[l])&&(i[l].node=a),delete s.extensions.KHR_materials_common}}var u=0;for(var c in i)if(i.hasOwnProperty(c)){var h=i[c],d=h.type;if("ambient"!==d&&!t(h.node)){delete i[c];continue}var p="light"+u.toString();switch(h.baseName=p,d){case"ambient":var m=h.ambient;n[p+"Color"]={type:r.FLOAT_VEC3,value:m.color};break;case"directional":var f=h.directional;n[p+"Color"]={type:r.FLOAT_VEC3,value:f.color},t(h.node)&&(n[p+"Transform"]={node:h.node,semantic:"MODELVIEW",type:r.FLOAT_MAT4});break;case"point":var v=h.point;n[p+"Color"]={type:r.FLOAT_VEC3,value:v.color},t(h.node)&&(n[p+"Transform"]={node:h.node,semantic:"MODELVIEW",type:r.FLOAT_MAT4}),n[p+"Attenuation"]={type:r.FLOAT_VEC3,value:[v.constantAttenuation,v.linearAttenuation,v.quadraticAttenuation]};break;case"spot":var _=h.spot;n[p+"Color"]={type:r.FLOAT_VEC3,value:_.color},t(h.node)&&(n[p+"Transform"]={node:h.node,semantic:"MODELVIEW",type:r.FLOAT_MAT4},n[p+"InverseTransform"]={node:h.node,semantic:"MODELVIEWINVERSE",type:r.FLOAT_MAT4,useInFragment:!0}),n[p+"Attenuation"]={type:r.FLOAT_VEC3,value:[_.constantAttenuation,_.linearAttenuation,_.quadraticAttenuation]},n[p+"FallOff"]={type:r.FLOAT_VEC2,value:[_.fallOffAngle,_.fallOffExponent]}}++u}}return n}function o(r,i,n){var o,a=e(n,0);do o=i+(a++).toString();while(t(r[o]));return o}function a(n,a,s){var d,p=n.techniques,m=n.shaders,f=n.programs,v=a.technique.toUpperCase();t(n.extensions)&&t(n.extensions.KHR_materials_common)&&(d=n.extensions.KHR_materials_common.lights);var _=e(a.jointCount,0),g=_>0,y=a.values,C="precision highp float;\n",E="precision highp float;\n",S=o(p,"technique",l),w=o(m,"vertexShader",u),T=o(m,"fragmentShader",c),b=o(f,"program",h),x="CONSTANT"!==v,P={modelViewMatrix:{semantic:"MODELVIEW",type:r.FLOAT_MAT4},projectionMatrix:{semantic:"PROJECTION",type:r.FLOAT_MAT4}};x&&(P.normalMatrix={semantic:"MODELVIEWINVERSETRANSPOSE",type:r.FLOAT_MAT3}),g&&(P.jointMatrix={count:_,semantic:"JOINTMATRIX",type:r.FLOAT_MAT4});var A,I=!1;for(var M in y)if(y.hasOwnProperty(M)){var D=y[M];A=M.toLowerCase(),I||D.type!==r.SAMPLER_2D||(I=!0),P[A]={type:D.type}}if(t(s))for(var R in s)s.hasOwnProperty(R)&&(P[R]=s[R]);var O={};for(var N in P)if(P.hasOwnProperty(N)){var L=P[N];O["u_"+N]=N;var F=t(L.count)?"["+L.count+"]":"";L.type!==r.FLOAT_MAT3&&L.type!==r.FLOAT_MAT4||L.useInFragment?(E+="uniform "+i(L.type)+" u_"+N+F+";\n",delete L.useInFragment):C+="uniform "+i(L.type)+" u_"+N+F+";\n"}var B="";g&&(B+=" mat4 skinMat = a_weight.x * u_jointMatrix[int(a_joint.x)];\n",B+=" skinMat += a_weight.y * u_jointMatrix[int(a_joint.y)];\n",B+=" skinMat += a_weight.z * u_jointMatrix[int(a_joint.z)];\n",B+=" skinMat += a_weight.w * u_jointMatrix[int(a_joint.w)];\n");var V={a_position:"position"};P.position={semantic:"POSITION",type:r.FLOAT_VEC3},C+="attribute vec3 a_position;\n",C+="varying vec3 v_positionEC;\n",B+=g?" vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);\n":" vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\n",B+=" v_positionEC = pos.xyz;\n",B+=" gl_Position = u_projectionMatrix * pos;\n",E+="varying vec3 v_positionEC;\n",x&&(V.a_normal="normal",P.normal={semantic:"NORMAL",type:r.FLOAT_VEC3},C+="attribute vec3 a_normal;\n",C+="varying vec3 v_normal;\n",B+=g?" v_normal = u_normalMatrix * mat3(skinMat) * a_normal;\n":" v_normal = u_normalMatrix * a_normal;\n",E+="varying vec3 v_normal;\n");var z;I&&(V.a_texcoord_0="texcoord_0",P.texcoord_0={semantic:"TEXCOORD_0",type:r.FLOAT_VEC2},z="v_texcoord_0",C+="attribute vec2 a_texcoord_0;\n",C+="varying vec2 "+z+";\n",B+=" "+z+" = a_texcoord_0;\n",E+="varying vec2 "+z+";\n"),g&&(V.a_joint="joint",P.joint={semantic:"JOINT",type:r.FLOAT_VEC4},V.a_weight="weight",P.weight={semantic:"WEIGHT",type:r.FLOAT_VEC4},C+="attribute vec4 a_joint;\n",C+="attribute vec4 a_weight;\n");var k=x&&("BLINN"===v||"PHONG"===v)&&t(P.specular)&&t(P.shininess),U=!1,G=!1,W="";for(var H in d)if(d.hasOwnProperty(H)){var q=d[H],j=q.type.toLowerCase(),Y=q.baseName;W+=" {\n";var X,Z,K="u_"+Y+"Color";"ambient"===j?(G=!0,W+=" ambientLight += "+K+";\n"):x&&(U=!0,X="v_"+Y+"Direction",Z="v_"+Y+"Position","point"!==j&&(C+="varying vec3 "+X+";\n",E+="varying vec3 "+X+";\n",B+=" "+X+" = mat3(u_"+Y+"Transform) * vec3(0.,0.,1.);\n","directional"===j&&(W+=" vec3 l = normalize("+X+");\n")),"directional"!==j?(C+="varying vec3 "+Z+";\n",E+="varying vec3 "+Z+";\n",B+=" "+Z+" = u_"+Y+"Transform[3].xyz;\n",W+=" vec3 VP = "+Z+" - v_positionEC;\n",W+=" vec3 l = normalize(VP);\n",W+=" float range = length(VP);\n",W+=" float attenuation = 1.0 / (u_"+Y+"Attenuation.x + ",W+="(u_"+Y+"Attenuation.y * range) + ",W+="(u_"+Y+"Attenuation.z * range * range));\n"):W+=" float attenuation = 1.0;\n","spot"===j&&(W+=" float spotDot = dot(l, normalize("+X+"));\n",W+=" if (spotDot < cos(u_"+Y+"FallOff.x * 0.5))\n",W+=" {\n",W+=" attenuation = 0.0;\n",W+=" }\n",W+=" else\n",W+=" {\n",W+=" attenuation *= max(0.0, pow(spotDot, u_"+Y+"FallOff.y));\n",W+=" }\n"),W+=" diffuseLight += "+K+"* max(dot(normal,l), 0.) * attenuation;\n",k&&("BLINN"===v?(W+=" vec3 h = normalize(l + viewDir);\n",W+=" float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\n"):(W+=" vec3 reflectDir = reflect(-l, normal);\n",W+=" float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\n"),W+=" specularLight += "+K+" * specularIntensity;\n")),W+=" }\n"}G||(W+=" ambientLight += vec3(0.2, 0.2, 0.2);\n"),U||"CONSTANT"===v||(W+=" vec3 l = normalize(czm_sunDirectionEC);\n",W+=" diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), 0.);\n",k&&("BLINN"===v?(W+=" vec3 h = normalize(l + viewDir);\n",W+=" float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\n"):(W+=" vec3 reflectDir = reflect(-l, normal);\n",W+=" float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\n"),W+=" specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity;\n")),C+="void main(void) {\n",C+=B,C+="}\n",E+="void main(void) {\n";var J=" vec3 color = vec3(0.0, 0.0, 0.0);\n";x&&(E+=" vec3 normal = normalize(v_normal);\n",a.doubleSided&&(E+=" if (gl_FrontFacing == false)\n",E+=" {\n",E+=" normal = -normal;\n",E+=" }\n"));var Q;"CONSTANT"!==v?(t(P.diffuse)&&(E+=P.diffuse.type===r.SAMPLER_2D?" vec4 diffuse = texture2D(u_diffuse, "+z+");\n":" vec4 diffuse = u_diffuse;\n",E+=" vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\n",J+=" color += diffuse.rgb * diffuseLight;\n"),k&&(E+=P.specular.type===r.SAMPLER_2D?" vec3 specular = texture2D(u_specular, "+z+").rgb;\n":" vec3 specular = u_specular.rgb;\n",E+=" vec3 specularLight = vec3(0.0, 0.0, 0.0);\n",J+=" color += specular * specularLight;\n"),Q=t(P.transparency)?" gl_FragColor = vec4(color * diffuse.a, diffuse.a * u_transparency);\n":" gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n"):Q=t(P.transparency)?" gl_FragColor = vec4(color, u_transparency);\n":" gl_FragColor = vec4(color, 1.0);\n",t(P.emission)&&(E+=P.emission.type===r.SAMPLER_2D?" vec3 emission = texture2D(u_emission, "+z+").rgb;\n":" vec3 emission = u_emission.rgb;\n",J+=" color += emission;\n"),(t(P.ambient)||"CONSTANT"!==v)&&(E+=t(P.ambient)?P.ambient.type===r.SAMPLER_2D?" vec3 ambient = texture2D(u_ambient, "+z+").rgb;\n":" vec3 ambient = u_ambient.rgb;\n":" vec3 ambient = diffuse.rgb;\n",J+=" color += ambient * ambientLight;\n"),E+=" vec3 viewDir = -normalize(v_positionEC);\n",E+=" vec3 ambientLight = vec3(0.0, 0.0, 0.0);\n",E+=W,E+=J,E+=Q,E+="}\n";var $;$=a.transparent?{enable:[r.DEPTH_TEST,r.BLEND],depthMask:!1,functions:{blendEquationSeparate:[r.FUNC_ADD,r.FUNC_ADD],blendFuncSeparate:[r.ONE,r.ONE_MINUS_SRC_ALPHA,r.ONE,r.ONE_MINUS_SRC_ALPHA]}}:a.doubleSided?{enable:[r.DEPTH_TEST]}:{enable:[r.CULL_FACE,r.DEPTH_TEST]},p[S]={attributes:V,parameters:P,program:b,states:$,uniforms:O},m[w]={type:r.VERTEX_SHADER,uri:"",extras:{source:C}},m[T]={type:r.FRAGMENT_SHADER,uri:"",extras:{source:E}};var ee=Object.keys(V);return f[b]={attributes:ee,fragmentShader:T,vertexShader:w},S}function s(t){var r="";r+="technique:"+t.technique+";";for(var i=t.values,n=Object.keys(i).sort(),o=n.length,a=0;o>a;++a){var s=n[a];if(i.hasOwnProperty(s)){var l=i[s];r+=s+":"+l.type.toString(),r+=";"}}var u=e(t.doubleSided,!1);r+=u.toString()+";";var c=e(t.transparent,!1);r+=c.toString()+";";var h=e(t.jointCount,0);return r+=h.toString()+";"}var l=0,u=0,c=0,h=0,d=function(e){if(!t(e))return void 0;var r=!1,i=e.extensionsUsed;if(t(i))for(var o=i.length,l=0;o>l;++l)if("KHR_materials_common"===i[l]){r=!0,i.splice(l,1);break}if(r){t(e.programs)||(e.programs={}),t(e.shaders)||(e.shaders={}),t(e.techniques)||(e.techniques={});var u=n(e),c={},h=e.materials;for(var d in h)if(h.hasOwnProperty(d)){var p=h[d];if(t(p.extensions)&&t(p.extensions.KHR_materials_common)){var m=p.extensions.KHR_materials_common,f=s(m),v=c[f];t(v)||(v=a(e,m,u),c[f]=v),p.values={};var _=m.values;for(var g in _)if(_.hasOwnProperty(g)){var y=_[g];p.values[g]=y.value}p.technique=v,delete p.extensions.KHR_materials_common}}t(e.extensions)&&delete e.extensions.KHR_materials_common}return e};return d}),r("Scene/ModelMaterial",["../Core/defined","../Core/defineProperties","../Core/DeveloperError"],function(e,t,r){"use strict";var i=function(e,t,r){this._name=t.name,this._id=r,this._uniformMap=e._uniformMaps[r]};return t(i.prototype,{name:{get:function(){return this._name}},id:{get:function(){return this._id}}}),i.prototype.setValue=function(e,t){var r=this._uniformMap.values[e];r.value=r.clone(t,r.value)},i.prototype.getValue=function(t){var r=this._uniformMap.values[t];return e(r)?r.value:void 0},i}),r("Scene/ModelMesh",["../Core/defineProperties"],function(e){"use strict";var t=function(e,t,r){for(var i=[],n=e.primitives,o=n.length,a=0;o>a;++a){var s=n[a];i[a]=t[s.material]}this._name=e.name,this._materials=i,this._id=r};return e(t.prototype,{name:{get:function(){return this._name}},id:{get:function(){return this._id}},materials:{get:function(){return this._materials}}}),t}),r("Scene/ModelNode",["../Core/defaultValue","../Core/defineProperties","../Core/Matrix4"],function(e,t,r){"use strict";var i=function(e,t,i,n,o){this._model=e,this._runtimeNode=i,this._name=t.name,this._id=n,this.useMatrix=!1,this._show=!0,this._matrix=r.clone(o)};return t(i.prototype,{name:{get:function(){return this._name}},id:{get:function(){return this._id}},show:{get:function(){return this._show},set:function(e){this._show!==e&&(this._show=e,this._model._perNodeShowDirty=!0)}},matrix:{get:function(){return this._matrix},set:function(e){this._matrix=r.clone(e,this._matrix),this.useMatrix=!0;var t=this._model;t._cesiumAnimationsDirty=!0,this._runtimeNode.dirtyNumber=t._maxDirtyNumber}}}),i.prototype.setMatrix=function(e){r.clone(e,this._matrix)},i}),r("Scene/Model",["../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/clone","../Core/combine","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/FeatureDetection","../Core/getMagic","../Core/getStringFromTypedArray","../Core/IndexDatatype","../Core/loadArrayBuffer","../Core/loadImage","../Core/loadImageFromTypedArray","../Core/loadText","../Core/Math","../Core/Matrix2","../Core/Matrix3","../Core/Matrix4","../Core/PrimitiveType","../Core/Quaternion","../Core/Queue","../Core/RuntimeError","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/Sampler","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/TextureMinificationFilter","../Renderer/TextureWrap","../Renderer/VertexArray","../Renderer/WebGLConstants","../ThirdParty/gltfDefaults","../ThirdParty/Uri","../ThirdParty/when","./getModelAccessor","./ModelAnimationCache","./ModelAnimationCollection","./modelMaterialsCommon","./ModelMaterial","./ModelMesh","./ModelNode","./Pass","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$){"use strict";function ee(){this.buffersToCreate=new A,this.buffers={},this.pendingBufferLoads=0,this.programsToCreate=new A,this.shaders={},this.pendingShaderLoads=0,this.texturesToCreate=new A,this.pendingTextureLoads=0,this.texturesToCreateFromBufferView=new A,this.pendingBufferViewToImage=0,this.createSamplers=!0,this.createSkins=!0, -this.createRuntimeAnimations=!0,this.createVertexArrays=!0,this.createRenderStates=!0,this.createUniformMaps=!0,this.createRuntimeNodes=!0,this.skinnedNodesNames=[]}function te(e,t){e._cachedGltf=t,e._animationIds=re(t)}function re(e){var t=[];if(l(e)&&l(e.gltf)){var r=e.gltf.animations;for(var i in r)r.hasOwnProperty(i)&&t.push(i)}return t}function ie(e){var t="",r=e.lastIndexOf("/");return-1!==r&&(t=e.substring(0,r+1)),t}function ne(e){var t=new W(document.location.href),r=new W(e);return r.resolve(t).toString()}function oe(e,t,r){return e.subarray(t,t+r)}function ae(e){var t=f(e);return"glTF"===t}function se(e){if(!ae(e))throw new d("bgltf is not a valid Binary glTF file.");var t=new DataView(e.buffer,e.byteOffset,e.byteLength),r=0;r+=Tt,r+=Tt,r+=Tt;var i=t.getUint32(r,!0);r+=Tt;var n=t.getUint32(r,!0);r+=Tt;var o=r,a=o+i;0!==n&&(o=i,i=n,a=0);var s=v(e,o,i);return{glTF:JSON.parse(s),binaryOffset:a}}function le(e,t,r){return e._runtime[t][r]}function ue(t){for(var i=(t.asset.version,t.nodes),n=t.meshes,o=t.accessors,a=t.scenes[t.scene].nodes,s=a.length,u=[],c=new r(Number.MAX_VALUE,Number.MAX_VALUE,Number.MAX_VALUE),h=new r(Number.MIN_VALUE,Number.MIN_VALUE,Number.MIN_VALUE),d=0;s>d;++d){var p=i[a[d]];for(p._transformToRoot=ye(p),u.push(p);u.length>0;){p=u.pop();var m=p._transformToRoot,f=p.meshes;if(l(f))for(var v=f.length,_=0;v>_;++_)for(var g=n[f[_]].primitives,y=g.length,C=0;y>C;++C){var E=g[C].attributes.POSITION;if(l(E)){var S=o[E],w=r.fromArray(S.min,0,bt),T=r.fromArray(S.max,0,xt);l(c)&&l(h)&&(b.multiplyByPoint(m,w,w),b.multiplyByPoint(m,T,T),r.minimumByComponent(c,w,c),r.maximumByComponent(h,T,h))}}for(var x=p.children,P=x.length,A=0;P>A;++A){var I=i[x[A]];I._transformToRoot=ye(I),b.multiplyTransformation(m,I._transformToRoot,I._transformToRoot),u.push(I)}delete p._transformToRoot}}var M=e.fromCornerPoints(c,h);return e.transformWithoutScale(M,_t,M)}function ce(e,t,r){return function(){e._loadError=new I("Failed to load "+t+": "+r),e._state=yt.FAILED}}function he(e,t){return function(r){var i=e._loadResources;i.buffers[t]=new Uint8Array(r),--i.pendingBufferLoads}}function de(e){var t=e.gltf.buffers;for(var r in t)if(t.hasOwnProperty(r)){var i=t[r];if("CESIUM_binary_glTF"===r||"KHR_binary_glTF"===r){var n=e._loadResources;n.buffers[r]=e._cachedGltf.bgltf}else if("arraybuffer"===i.type){++e._loadResources.pendingBufferLoads;var o=new W(i.uri),a=o.resolve(e._baseUri).toString();g(a).then(he(e,r)).otherwise(ce(e,"buffer",a))}else"text"===i.type}}function pe(e){var t=e.gltf.bufferViews;for(var r in t)t.hasOwnProperty(r)&&t[r].target===U.ARRAY_BUFFER&&e._loadResources.buffersToCreate.enqueue(r)}function me(e,t){return function(r){var i=e._loadResources;i.shaders[t]={source:r,bufferView:void 0},--i.pendingShaderLoads}}function fe(e){var t=e.gltf.shaders;for(var r in t)if(t.hasOwnProperty(r)){var i=t[r];if(l(i.extras)&&l(i.extras.source))e._loadResources.shaders[r]={source:i.extras.source,bufferView:void 0};else if(l(i.extensions)&&(l(i.extensions.CESIUM_binary_glTF)||l(i.extensions.KHR_binary_glTF))){var n;n=l(i.extensions.CESIUM_binary_glTF)?i.extensions.CESIUM_binary_glTF:i.extensions.KHR_binary_glTF,e._loadResources.shaders[r]={source:void 0,bufferView:n.bufferView}}else{++e._loadResources.pendingShaderLoads;var o=new W(i.uri),a=o.resolve(e._baseUri).toString();E(a).then(me(e,r)).otherwise(ce(e,"shader",a))}}}function ve(e){var t=e.gltf.programs;for(var r in t)t.hasOwnProperty(r)&&e._loadResources.programsToCreate.enqueue(r)}function _e(e,t){return function(r){var i=e._loadResources;--i.pendingTextureLoads,i.texturesToCreate.enqueue({name:t,image:r,bufferView:void 0})}}function ge(e){var t=e.gltf.images,r=e.gltf.textures;for(var i in r)if(r.hasOwnProperty(i)){var n=t[r[i].source];if(l(n.extensions)&&(l(n.extensions.CESIUM_binary_glTF)||l(n.extensions.KHR_binary_glTF))){var o;o=l(n.extensions.CESIUM_binary_glTF)?n.extensions.CESIUM_binary_glTF:n.extensions.KHR_binary_glTF,e._loadResources.texturesToCreateFromBufferView.enqueue({name:i,image:void 0,bufferView:o.bufferView,mimeType:o.mimeType})}else{++e._loadResources.pendingTextureLoads;var a=new W(n.uri),s=a.resolve(e._baseUri).toString();y(s).then(_e(e,i)).otherwise(ce(e,"image",s))}}}function ye(e,t){return l(e.matrix)?b.fromArray(e.matrix):b.fromTranslationQuaternionRotationScale(r.fromArray(e.translation,0,Pt),P.unpack(e.rotation,0,At),r.fromArray(e.scale,0,It))}function Ce(e){var t={},r={},i=[],n=e._loadResources.skinnedNodesNames,o=e.gltf.nodes;for(var a in o)if(o.hasOwnProperty(a)){var s=o[a],u={matrix:void 0,translation:void 0,rotation:void 0,scale:void 0,computedShow:!0,transformToRoot:new b,computedMatrix:new b,dirtyNumber:0,commands:[],inverseBindMatrices:void 0,bindShapeMatrix:void 0,joints:[],computedJointMatrices:[],jointName:s.jointName,children:[],parents:[],publicNode:void 0};u.publicNode=new J(e,s,u,a,ye(s)),t[a]=u,r[s.name]=u,l(s.skin)&&(n.push(a),i.push(u))}e._runtime.nodes=t,e._runtime.nodesByName=r,e._runtime.skinnedNodes=i}function Ee(e){var t={},r={},i=e.gltf.materials,n=e._uniformMaps;for(var o in i)if(i.hasOwnProperty(o)){n[o]={uniformMap:void 0,values:void 0,jointMatrixUniformName:void 0};var a=i[o],s=new Z(e,a,o);t[a.name]=s,r[o]=s}e._runtime.materialsByName=t,e._runtime.materialsById=r}function Se(e){var t={},r=e._runtime.materialsById,i=e.gltf.meshes;for(var n in i)if(i.hasOwnProperty(n)){var o=i[n];t[o.name]=new K(o,r,n)}e._runtime.meshesByName=t}function we(e){e._loadRendererResourcesFromCache||(de(e),pe(e),fe(e),ve(e),ge(e)),Ee(e),Se(e),Ce(e)}function Te(e,t){var r=e._loadResources;if(0===r.pendingBufferLoads){for(var i,n=e.gltf.bufferViews,o=e._rendererResources.buffers;r.buffersToCreate.length>0;){var a=r.buffersToCreate.dequeue();i=n[a];var s=M.createVertexBuffer({context:t,typedArray:r.getBuffer(i),usage:D.STATIC_DRAW});s.vertexArrayDestroyable=!1,o[a]=s}var u=e.gltf.accessors;for(var c in u)if(u.hasOwnProperty(c)){var h=u[c];if(i=n[h.bufferView],i.target===U.ELEMENT_ARRAY_BUFFER&&!l(o[h.bufferView])){var d=M.createIndexBuffer({context:t,typedArray:r.getBuffer(i),usage:D.STATIC_DRAW,indexDatatype:h.componentType});d.vertexArrayDestroyable=!1,o[h.bufferView]=d}}}}function be(e){for(var t={},r=e.length,i=0;r>i;++i)t[e[i]]=i;return t}function xe(e,t){if(l(t.source))return t.source;var r=e._loadResources,i=e.gltf,n=i.bufferViews[t.bufferView];return v(r.getBuffer(n))}function Pe(e,t,r){var i=t.gltf.programs,n=t._loadResources.shaders,o=i[e],a=be(o.attributes),s=xe(t,n[o.vertexShader]),l=xe(t,n[o.fragmentShader]);if(t._rendererResources.programs[e]=L.fromCache({context:r,vertexShaderSource:s,fragmentShaderSource:l,attributeLocations:a}),t.allowPicking){var u=new F({sources:[l],pickColorQualifier:"uniform"});t._rendererResources.pickPrograms[e]=L.fromCache({context:r,vertexShaderSource:s,fragmentShaderSource:u,attributeLocations:a})}}function Ae(e,t){var r,i=e._loadResources;if(0===i.pendingShaderLoads&&0===i.pendingBufferLoads)if(e.asynchronous)i.programsToCreate.length>0&&(r=i.programsToCreate.dequeue(),Pe(r,e,t));else for(;i.programsToCreate.length>0;)r=i.programsToCreate.dequeue(),Pe(r,e,t)}function Ie(e,t){return function(r){e.texturesToCreate.enqueue({name:t.name,image:r,bufferView:void 0}),--e.pendingBufferViewToImage}}function Me(e){var t=e._loadResources;if(0===t.pendingBufferLoads)for(;t.texturesToCreateFromBufferView.length>0;){var r=t.texturesToCreateFromBufferView.dequeue(),i=e.gltf,n=i.bufferViews[r.bufferView],o=Ie(t,r),a=ce(e,"image","name: "+r.name+", bufferView: "+r.bufferView);C(t.getBuffer(n),r.mimeType).then(o).otherwise(a),++t.pendingBufferViewToImage}}function De(e,t){var r=e._loadResources;if(r.createSamplers){r.createSamplers=!1;var i=e._rendererResources.samplers,n=e.gltf.samplers;for(var o in n)if(n.hasOwnProperty(o)){var a=n[o];i[o]=new N({wrapS:a.wrapS,wrapT:a.wrapT,minificationFilter:a.minFilter,magnificationFilter:a.magFilter})}}}function Re(e,t,r){var i=t.gltf.textures,n=i[e.name],o=t._rendererResources.samplers,a=o[n.sampler],s=a.minificationFilter===V.NEAREST_MIPMAP_NEAREST||a.minificationFilter===V.NEAREST_MIPMAP_LINEAR||a.minificationFilter===V.LINEAR_MIPMAP_NEAREST||a.minificationFilter===V.LINEAR_MIPMAP_LINEAR,l=s||a.wrapS===z.REPEAT||a.wrapS===z.MIRRORED_REPEAT||a.wrapT===z.REPEAT||a.wrapT===z.MIRRORED_REPEAT,u=e.image,c=!S.isPowerOfTwo(u.width)||!S.isPowerOfTwo(u.height);if(l&&c){var h=document.createElement("canvas");h.width=S.nextPowerOfTwo(u.width),h.height=S.nextPowerOfTwo(u.height);var d=h.getContext("2d");d.drawImage(u,0,0,u.width,u.height,0,0,h.width,h.height),u=h}var p;n.target===U.TEXTURE_2D&&(p=new B({context:r,source:u,pixelFormat:n.internalFormat,pixelDatatype:n.type,flipY:!1})),s&&p.generateMipmap(),p.sampler=a,t._rendererResources.textures[e.name]=p}function Oe(e,t){var r,i=e._loadResources;if(e.asynchronous)i.texturesToCreate.length>0&&(r=i.texturesToCreate.dequeue(),Re(r,e,t));else for(;i.texturesToCreate.length>0;)r=i.texturesToCreate.dequeue(),Re(r,e,t)}function Ne(e,t){var r=e.gltf,i=(r.programs,r.techniques),n=r.materials,o={},a=i[n[t.material].technique],s=a.parameters,l=a.attributes,u=e._rendererResources.programs[a.program].vertexAttributes;for(var c in u)if(u.hasOwnProperty(c)){var h=s[l[c]];o[h.semantic]=u[c].index}return o}function Le(e,t){for(var r=e.length,i=0;r>i;++i)for(var n=[e[i]];n.length>0;){var o=n.pop();if(o.jointName===t)return o;for(var a=o.children,s=a.length,l=0;s>l;++l)n.push(a[l])}return void 0}function Fe(e,t){for(var r=e.gltf,i=r.skins,n=r.nodes,o=e._runtime.nodes,a=e._loadResources.skinnedNodesNames,s=a.length,l=0;s>l;++l){var u=a[l],c=o[u],h=n[u],d=t[h.skin];c.inverseBindMatrices=d.inverseBindMatrices,c.bindShapeMatrix=d.bindShapeMatrix;for(var p=[],m=h.skeletons,f=m.length,v=0;f>v;++v)p.push(o[m[v]]);for(var _=i[h.skin].jointNames,g=_.length,y=0;g>y;++y){var C=_[y];c.joints.push(Le(p,C))}}}function Be(e){var t=e._loadResources;if(0===t.pendingBufferLoads&&t.createSkins){t.createSkins=!1;var r=e.gltf,i=r.accessors,n=r.skins,o={};for(var a in n)if(n.hasOwnProperty(a)){var s,l=n[a],u=i[l.inverseBindMatrices];b.equals(l.bindShapeMatrix,b.IDENTITY)||(s=b.clone(l.bindShapeMatrix)),o[a]={inverseBindMatrices:j.getSkinInverseBindMatrices(e,u),bindShapeMatrix:s}}Fe(e,o)}}function Ve(e,t,r,i){return function(n){t[r]=i.evaluate(n,t[r]),t.dirtyNumber=e._maxDirtyNumber}}function ze(e){var t=e._loadResources;if(t.finishedPendingLoads()&&t.createRuntimeAnimations){t.createRuntimeAnimations=!1,e._runtime.animations={};var r,i=e._runtime.nodes,n=e.gltf.animations,o=e.gltf.accessors;for(var a in n)if(n.hasOwnProperty(a)){var s=n[a],l=s.channels,u=s.parameters,c=s.samplers,h={};for(r in u)u.hasOwnProperty(r)&&(h[r]=j.getAnimationParameterValues(e,o[u[r]]));for(var d=Number.MAX_VALUE,p=-Number.MAX_VALUE,m=l.length,f=new Array(m),v=0;m>v;++v){var _=l[v],g=_.target,y=c[_.sampler],C=h[y.input];d=Math.min(d,C[0]),p=Math.max(p,C[C.length-1]);var E=j.getAnimationSpline(e,a,s,_.sampler,y,h);f[v]=Ve(e,i[g.id],g.path,E)}e._runtime.animations[a]={startTime:d,stopTime:p,channelEvaluators:f}}}}function ke(e,t){var r=e._loadResources;if(r.finishedBuffersCreation()&&r.finishedProgramCreation()&&r.createVertexArrays){r.createVertexArrays=!1;var i=e._rendererResources.buffers,n=e._rendererResources.vertexArrays,o=e.gltf,a=o.accessors,s=o.meshes;for(var u in s)if(s.hasOwnProperty(u))for(var c=s[u].primitives,h=c.length,d=0;h>d;++d){var p=c[d],m=Ne(e,p),f=[],v=p.attributes;for(var _ in v)if(v.hasOwnProperty(_)){var g=m[_];if(l(g)){var y=a[v[_]];f.push({index:g,vertexBuffer:i[y.bufferView],componentsPerAttribute:q(y).componentsPerAttribute,componentDatatype:y.componentType,normalize:!1,offsetInBytes:y.byteOffset,strideInBytes:y.byteStride})}}var C;if(l(p.indices)){var E=a[p.indices];C=i[E.bufferView]}n[u+".primitive."+d]=new k({context:t,attributes:f,indexBuffer:C})}}}function Ue(e){var t={};t[U.BLEND]=!1,t[U.CULL_FACE]=!1,t[U.DEPTH_TEST]=!1,t[U.POLYGON_OFFSET_FILL]=!1,t[U.SCISSOR_TEST]=!1;var r,i=e.enable,n=i.length;for(r=0;n>r;++r)t[i[r]]=!0;return t}function Ge(e,t){var r=e._loadResources;if(r.createRenderStates){r.createRenderStates=!1;var i=e._rendererResources.renderStates,n=e.gltf.techniques;for(var o in n)if(n.hasOwnProperty(o)){var a=n[o],u=a.states,c=Ue(u),h=s(u.functions,s.EMPTY_OBJECT),d=s(h.blendColor,[0,0,0,0]),p=s(h.blendEquationSeparate,[U.FUNC_ADD,U.FUNC_ADD]),m=s(h.blendFuncSeparate,[U.ONE,U.ONE,U.ZERO,U.ZERO]),f=s(h.colorMask,[!0,!0,!0,!0]),v=s(h.depthRange,[0,1]),_=s(h.polygonOffset,[0,0]),g=s(h.scissor,[0,0,0,0]);i[o]=O.fromCache({frontFace:l(h.frontFace)?h.frontFace[0]:U.CCW,cull:{enabled:c[U.CULL_FACE],face:l(h.cullFace)?h.cullFace[0]:U.BACK},lineWidth:l(h.lineWidth)?h.lineWidth[0]:1,polygonOffset:{enabled:c[U.POLYGON_OFFSET_FILL],factor:_[0],units:_[1]},scissorTest:{enabled:c[U.SCISSOR_TEST],rectangle:{x:g[0],y:g[1],width:g[2],height:g[3]}},depthRange:{near:v[0],far:v[1]},depthTest:{enabled:c[U.DEPTH_TEST],func:l(h.depthFunc)?h.depthFunc[0]:U.LESS},colorMask:{red:f[0],green:f[1],blue:f[2],alpha:f[3]},depthMask:l(h.depthMask)?h.depthMask[0]:!0,blending:{enabled:c[U.BLEND],color:{red:d[0],green:d[1],blue:d[2],alpha:d[3]},equationRgb:p[0],equationAlpha:p[1],functionSourceRgb:m[0],functionSourceAlpha:m[1],functionDestinationRgb:m[2],functionDestinationAlpha:m[3]}})}}}function We(e,t){var r={value:e,clone:function(e,t){return e},func:function(){return r.value}};return r}function He(e,r){var i={value:t.fromArray(e),clone:t.clone,func:function(){return i.value}};return i}function qe(e,t){var i={value:r.fromArray(e),clone:r.clone,func:function(){return i.value}};return i}function je(e,t){var r={value:i.fromArray(e),clone:i.clone,func:function(){return r.value}};return r}function Ye(e,t){var r={value:w.fromColumnMajorArray(e),clone:w.clone,func:function(){return r.value}};return r}function Xe(e,t){var r={value:T.fromColumnMajorArray(e),clone:T.clone,func:function(){return r.value}};return r}function Ze(e,t){var r={value:b.fromColumnMajorArray(e),clone:b.clone,func:function(){return r.value}};return r}function Ke(e,t){var r={value:t._rendererResources.textures[e],clone:function(e,t){return e},func:function(){return r.value}};return r}function Je(e,t,r,i){var n=t._runtime.nodes[e];return Rt[r](i,t,n)}function Qe(e,t){var r=e._loadResources;if(r.finishedTextureCreation()&&r.finishedProgramCreation()&&r.createUniformMaps){r.createUniformMaps=!1;var i=e.gltf,n=i.materials,o=i.techniques,a=(i.programs,e._uniformMaps);for(var s in n)if(n.hasOwnProperty(s)){var u,c=n[s],h=c.values,d=o[c.technique],p=d.parameters,m=d.uniforms,f={},v={};for(var _ in m)if(m.hasOwnProperty(_)){var g=m[_],y=p[g];if(l(h[g])){var C=Dt[y.type](h[g],e);f[_]=C.func,v[g]=C}else if(l(y.node))f[_]=Je(y.node,e,y.semantic,t.uniformState);else if(l(y.semantic))"JOINTMATRIX"!==y.semantic?f[_]=Mt[y.semantic](t.uniformState,e):u=_;else if(l(y.value)){var E=Dt[y.type](y.value,e);f[_]=E.func,v[g]=E}}var S=a[s];S.uniformMap=f,S.values=v,S.jointMatrixUniformName=u}}}function $e(e){return function(){return e}}function et(e){return function(){return e.computedJointMatrices}}function tt(t,i,n,u){for(var c=t._nodeCommands,h=t._pickIds,d=t.allowPicking,p=t._runtime.meshesByName,m=(t.debugShowBoundingVolume,t._rendererResources),f=m.vertexArrays,v=m.programs,g=m.pickPrograms,y=m.renderStates,C=t._uniformMaps,E=t.gltf,S=E.accessors,w=E.meshes,T=E.techniques,x=E.materials,P=i.meshes,A=P.length,I=0;A>I;++I)for(var M=P[I],D=w[M],O=D.primitives,N=O.length,L=0;N>L;++L){var F,B=O[L],V=S[B.indices],z=x[B.material],k=T[z.technique],U=B.attributes.POSITION;if(l(U)){var G=S[U];F=e.fromCornerPoints(r.fromArray(G.min),r.fromArray(G.max))}var W,H,j=f[M+".primitive."+L];if(l(V))H=V.count,W=V.byteOffset/_.getSizeInBytes(V.componentType);else{var Y=S[B.attributes.POSITION];H=Y.count;var X=q(Y);W=Y.byteOffset/(X.componentsPerAttribute*a.getSizeInBytes(Y.componentType))}var Z=C[B.material],K=Z.uniformMap;if(l(Z.jointMatrixUniformName)){var J={};J[Z.jointMatrixUniformName]=et(n),K=o(K,J)}var $,ee=y[z.technique],te=ee.blending.enabled,re={primitive:s(t.pickPrimitive,t),id:t.id,node:n.publicNode,mesh:p[D.name]},ie=new R({boundingVolume:new e,modelMatrix:new b,primitiveType:B.mode,vertexArray:j,count:H,offset:W,shaderProgram:v[k.program],uniformMap:K,renderState:ee,owner:re,pass:te?Q.TRANSLUCENT:Q.OPAQUE});if(d){var ne=u.createPickId(re);h.push(ne);var oe=o(K,{czm_pickColor:$e(ne.color)});$=new R({boundingVolume:new e,modelMatrix:new b,primitiveType:B.mode,vertexArray:j,count:H,offset:W,shaderProgram:g[k.program],uniformMap:oe,renderState:ee,owner:re,pass:te?Q.TRANSLUCENT:Q.OPAQUE})}var ae={show:!0,boundingSphere:F,command:ie,pickCommand:$};n.commands.push(ae),c.push(ae)}}function rt(e,t){var i=e._loadResources;if(i.finishedPendingLoads()&&i.finishedResourceCreation()&&i.createRuntimeNodes){i.createRuntimeNodes=!1;for(var n=[],o=e._runtime.nodes,a=e.gltf,s=(a.asset.version,a.nodes),u=a.scenes[a.scene],c=u.nodes,h=c.length,d=[],p=(new r,0);h>p;++p)for(d.push({parentRuntimeNode:void 0,gltfNode:s[c[p]],id:c[p]});d.length>0;){var m=d.pop(),f=m.parentRuntimeNode,v=m.gltfNode,_=o[m.id];if(0===_.parents.length)if(l(v.matrix))_.matrix=b.fromColumnMajorArray(v.matrix);else{var g=v.rotation;_.translation=r.fromArray(v.translation),_.rotation=P.unpack(g),_.scale=r.fromArray(v.scale)}l(f)?(f.children.push(_),_.parents.push(f)):n.push(_),l(v.meshes)&&tt(e,v,_,t);for(var y=v.children,C=y.length,E=0;C>E;++E)d.push({parentRuntimeNode:_,gltfNode:s[y[E]],id:y[E]})}e._runtime.rootNodes=n,e._runtime.nodes=o}}function it(e,t){if(e._loadRendererResourcesFromCache){var r=e._rendererResources,i=e._cachedRendererResources;r.buffers=i.buffers,r.vertexArrays=i.vertexArrays,r.programs=i.programs,r.pickPrograms=i.pickPrograms,r.textures=i.textures,r.samplers=i.samplers,r.renderStates=i.renderStates}else Te(e,t),Ae(e,t),De(e,t),Me(e),Oe(e,t);Be(e),ze(e),e._loadRendererResourcesFromCache||(ke(e,t),Ge(e,t)),Qe(e,t),rt(e,t)}function nt(e,t){var r=e.publicNode,i=r.matrix;r.useMatrix&&l(i)?b.clone(i,t):l(e.matrix)?b.clone(e.matrix,t):(b.fromTranslationQuaternionRotationScale(e.translation,e.rotation,e.scale,t),r.setMatrix(t))}function ot(t,i,n){for(var o=t._maxDirtyNumber,a=t.allowPicking,s=t._runtime.rootNodes,u=s.length,c=Ot,h=t._computedModelMatrix,d=0;u>d;++d){var p=s[d];for(nt(p,p.transformToRoot),c.push(p);c.length>0;){p=c.pop();var m=p.transformToRoot,f=p.commands;if(p.dirtyNumber===o||i||n){var v=f.length;if(v>0)for(var _=0;v>_;++_){var g=f[_],y=g.command;if(b.multiplyTransformation(h,m,y.modelMatrix),e.transform(g.boundingSphere,y.modelMatrix,y.boundingVolume),l(t._rtcCenter)&&r.add(t._rtcCenter,y.boundingVolume.center,y.boundingVolume.center),a){var C=g.pickCommand;b.clone(y.modelMatrix,C.modelMatrix),e.clone(y.boundingVolume,C.boundingVolume)}}else p.computedMatrix=b.multiplyTransformation(h,m,p.computedMatrix)}for(var E=p.children,S=E.length,w=0;S>w;++w){var T=E[w];T.dirtyNumber=Math.max(T.dirtyNumber,p.dirtyNumber),(T.dirtyNumber===o||n)&&(nt(T,T.transformToRoot),b.multiplyTransformation(m,T.transformToRoot,T.transformToRoot)),c.push(T)}}}++t._maxDirtyNumber}function at(e){for(var t=e._runtime.skinnedNodes,r=t.length,i=0;r>i;++i){var n=t[i];Nt=b.inverseTransformation(n.transformToRoot,Nt);for(var o=n.computedJointMatrices,a=n.joints,s=n.bindShapeMatrix,u=n.inverseBindMatrices,c=u.length,h=0;c>h;++h)l(o[h])||(o[h]=new b),o[h]=b.multiplyTransformation(Nt,a[h].transformToRoot,o[h]),o[h]=b.multiplyTransformation(o[h],u[h],o[h]),l(s)&&(o[h]=b.multiplyTransformation(o[h],s,o[h]))}}function st(e){for(var t=e._runtime.rootNodes,r=t.length,i=Ot,n=0;r>n;++n){var o=t[n];for(o.computedShow=o.publicNode.show,i.push(o);i.length>0;){o=i.pop();for(var a=o.computedShow,s=o.commands,l=s.length,u=0;l>u;++u)s[u].show=a;for(var c=o.children,h=c.length,d=0;h>d;++d){var p=c[d];p.computedShow=a&&p.publicNode.show,i.push(p)}}}}function lt(e,t){var r=e.id;if(e._id!==r){e._id=r;for(var i=e._pickIds,n=i.length,o=0;n>o;++o)i[o].object.id=r}}function ut(e){if(e._debugWireframe!==e.debugWireframe){e._debugWireframe=e.debugWireframe;for(var t=e.debugWireframe?x.LINES:x.TRIANGLES,r=e._nodeCommands,i=r.length,n=0;i>n;++n)r[n].command.primitiveType=t}}function ct(e){if(e.debugShowBoundingVolume!==e._debugShowBoundingVolume){e._debugShowBoundingVolume=e.debugShowBoundingVolume;for(var t=e.debugShowBoundingVolume,r=e._nodeCommands,i=r.length,n=0;i>n;n++)r[n].command.debugShowBoundingVolume=t}}function ht(e,t,r){Ft.center=e,Ft.radius=t;var i=r.camera,n=i.distanceToBoundingSphere(Ft),o=r.context,a=i.frustum.getPixelDimensions(o.drawingBufferWidth,o.drawingBufferHeight,n,Lt),s=Math.max(a.x,a.y);return s}function dt(e,t){var i=e.scale;if(0!==e.minimumPixelSize){var n=t.context,o=Math.max(n.drawingBufferWidth,n.drawingBufferHeight),a=e.modelMatrix;Bt.x=a[12],Bt.y=a[13],Bt.z=a[14],l(e._rtcCenter)&&r.add(e._rtcCenter,Bt,Bt);var s=e.boundingSphere.radius,u=ht(Bt,s,t),c=1/u,h=Math.min(2*c*s,o);h<e.minimumPixelSize&&(i=e.minimumPixelSize*u/(2*e._initialRadius))}return l(e.maximumScale)?Math.min(e.maximumScale,i):i}function pt(e){l(e._cacheKey)&&l(e._cachedGltf)&&0===--e._cachedGltf.count&&delete St[e._cacheKey],e._cachedGltf=void 0}function mt(e){var t=e.gltf.extensionsUsed;if(l(t))for(var r=t.length,i=0;r>i;++i){var n=t[i];"CESIUM_RTC"!==n&&"CESIUM_binary_glTF"!==n&&"KHR_binary_glTF"!==n&&"KHR_materials_common"!==n?(e._loadError=new I("Unsupported glTF Extension: "+n),e._state=yt.FAILED):"CESIUM_binary_glTF"===n&&c("CESIUM_binary_glTF extension","Use of the CESIUM_binary_glTF extension has been deprecated. Use the KHR_binary_glTF extension instead.")}}function ft(e){for(var t in e)e.hasOwnProperty(t)&&e[t].destroy()}function vt(e){ft(e.buffers),ft(e.vertexArrays),ft(e.programs),ft(e.pickPrograms),ft(e.textures)}if(!m.supportsTypedArrays())return{};var _t=b.fromRotationTranslation(T.fromRotationX(S.PI_OVER_TWO)),gt=new r,yt={NEEDS_LOAD:0,LOADING:1,LOADED:2,FAILED:3},Ct="model/vnd.gltf.binary,model/vnd.gltf+json,model/gltf.binary,model/gltf+json;q=0.8,application/json;q=0.2,*/*;q=0.01";ee.prototype.getBuffer=function(e){return oe(this.buffers[e.buffer],e.byteOffset,e.byteLength)},ee.prototype.finishedPendingLoads=function(){return 0===this.pendingBufferLoads&&0===this.pendingShaderLoads&&0===this.pendingTextureLoads},ee.prototype.finishedResourceCreation=function(){return 0===this.buffersToCreate.length&&0===this.programsToCreate.length&&0===this.texturesToCreate.length&&0===this.texturesToCreateFromBufferView.length&&0===this.pendingBufferViewToImage},ee.prototype.finishedBuffersCreation=function(){return 0===this.pendingBufferLoads&&0===this.buffersToCreate.length},ee.prototype.finishedProgramCreation=function(){return 0===this.pendingShaderLoads&&0===this.programsToCreate.length},ee.prototype.finishedTextureCreation=function(){return 0===this.pendingTextureLoads&&0===this.texturesToCreate.length&&0===this.texturesToCreateFromBufferView.length&&0===this.pendingBufferViewToImage};var Et=function(e){this._gltf=X(G(e.gltf)),this._bgltf=e.bgltf,this.ready=e.ready,this.modelsToLoad=[],this.count=0};u(Et.prototype,{gltf:{set:function(e){this._gltf=X(G(e))},get:function(){return this._gltf}},bgltf:{get:function(){return this._bgltf}}}),Et.prototype.makeReady=function(e,t){this.gltf=e,this._bgltf=t;for(var r=this.modelsToLoad,i=r.length,n=0;i>n;++n){var o=r[n];o.isDestroyed()||te(o,this)}this.modelsToLoad=void 0,this.ready=!0};var St={},wt=function(t){t=s(t,s.EMPTY_OBJECT);var r=t.cacheKey;this._cacheKey=r,this._cachedGltf=void 0,this._releaseGltfJson=s(t.releaseGltfJson,!1),this._animationIds=void 0;var i;if(l(r)&&l(St[r])&&St[r].ready)i=St[r],++i.count;else{var n=t.gltf;if(l(n)){if(n instanceof ArrayBuffer&&(n=new Uint8Array(n)),n instanceof Uint8Array){var o=se(n);0!==o.binaryOffset&&(n=new Uint8Array(n.buffer,o.binaryOffset)),i=new Et({gltf:o.glTF,bgltf:n,ready:!0})}else i=new Et({gltf:t.gltf,ready:!0});i.count=1,l(r)&&(St[r]=i)}}te(this,i),this._basePath=s(t.basePath,"");var a=new W(document.location.href),u=new W(this._basePath);this._baseUri=u.resolve(a),this.show=s(t.show,!0),this.modelMatrix=b.clone(s(t.modelMatrix,b.IDENTITY)),this._modelMatrix=b.clone(this.modelMatrix),this.scale=s(t.scale,1),this._scale=this.scale,this.minimumPixelSize=s(t.minimumPixelSize,0),this._minimumPixelSize=this.minimumPixelSize,this.maximumScale=t.maximumScale,this._maximumScale=this.maximumScale,this.id=t.id,this._id=t.id,this.pickPrimitive=t.pickPrimitive,this._allowPicking=s(t.allowPicking,!0),this._ready=!1,this._readyPromise=H.defer(),this.activeAnimations=new Y(this),this._asynchronous=s(t.asynchronous,!0),this.debugShowBoundingVolume=s(t.debugShowBoundingVolume,!1),this._debugShowBoundingVolume=!1,this.debugWireframe=s(t.debugWireframe,!1),this._debugWireframe=!1,this._computedModelMatrix=new b,this._initialRadius=void 0,this._boundingSphere=void 0,this._scaledBoundingSphere=new e,this._state=yt.NEEDS_LOAD,this._loadError=void 0,this._loadResources=void 0,this._perNodeShowDirty=!1,this._cesiumAnimationsDirty=!1,this._maxDirtyNumber=0,this._runtime={animations:void 0,rootNodes:void 0,nodes:void 0,nodesByName:void 0,skinnedNodes:void 0,meshesByName:void 0,materialsByName:void 0,materialsById:void 0},this._uniformMaps={},this._rendererResources={buffers:{},vertexArrays:{},programs:{},pickPrograms:{},textures:{},samplers:{},renderStates:{}},this._cachedRendererResources=void 0,this._loadRendererResourcesFromCache=!1,this._nodeCommands=[],this._pickIds=[],this._rtcCenter=void 0,this._rtcCenterEye=void 0};u(wt.prototype,{gltf:{get:function(){return l(this._cachedGltf)?this._cachedGltf.gltf:void 0}},releaseGltfJson:{get:function(){return this._releaseGltfJson}},cacheKey:{get:function(){return this._cacheKey}},basePath:{get:function(){return this._basePath}},boundingSphere:{get:function(){var e=b.getScale(this.modelMatrix,gt),t=l(this.maximumScale)?Math.min(this.maximumScale,this.scale):this.scale;r.multiplyByScalar(e,t,e);var i=this._scaledBoundingSphere;return i.center=r.multiplyComponents(this._boundingSphere.center,e,i.center),i.radius=r.maximumComponent(e)*this._initialRadius,l(this._rtcCenter)&&r.add(this._rtcCenter,i.center,i.center),i}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},asynchronous:{get:function(){return this._asynchronous}},allowPicking:{get:function(){return this._allowPicking}}});var Tt=Uint32Array.BYTES_PER_ELEMENT;wt.fromGltf=function(e){var t=e.url,r=s(e.cacheKey,ne(t));e=n(e),e.basePath=ie(t),e.cacheKey=r;var i=new wt(e);e.headers=l(e.headers)?n(e.headers):{},l(e.headers.Accept)||(e.headers.Accept=Ct);var o=St[r];return l(o)?o.ready||(++o.count,o.modelsToLoad.push(i)):(o=new Et({ready:!1}),o.count=1,o.modelsToLoad.push(i),te(i,o),St[r]=o,g(t,e.headers).then(function(e){var t=new Uint8Array(e);if(ae(t)){var r=se(t);0!==r.binaryOffset&&(t=new Uint8Array(e,r.binaryOffset)),o.makeReady(r.glTF,t)}else{var i=v(t);o.makeReady(JSON.parse(i))}}).otherwise(ce(i,"model",t))),i},wt._gltfCache=St,wt.prototype.getNode=function(e){var t=le(this,"nodesByName",e);return l(t)?t.publicNode:void 0},wt.prototype.getMesh=function(e){return le(this,"meshesByName",e)},wt.prototype.getMaterial=function(e){return le(this,"materialsByName",e)};var bt=new r,xt=new r,Pt=new r,At=new P,It=new r,Mt={MODEL:function(e,t){return function(){return e.model}},VIEW:function(e,t){return function(){return e.view}},PROJECTION:function(e,t){return function(){return e.projection}},MODELVIEW:function(e,t){return function(){return e.modelView}},CESIUM_RTC_MODELVIEW:function(e,t){var r=new b;return function(){return b.setTranslation(e.modelView,t._rtcCenterEye,r)}},MODELVIEWPROJECTION:function(e,t){return function(){return e.modelViewProjection}},MODELINVERSE:function(e,t){return function(){return e.inverseModel}},VIEWINVERSE:function(e,t){return function(){return e.inverseView}},PROJECTIONINVERSE:function(e,t){return function(){return e.inverseProjection}},MODELVIEWINVERSE:function(e,t){return function(){return e.inverseModelView}},MODELVIEWPROJECTIONINVERSE:function(e,t){return function(){return e.inverseModelViewProjection}},MODELINVERSETRANSPOSE:function(e,t){return function(){return e.inverseTranposeModel}},MODELVIEWINVERSETRANSPOSE:function(e,t){return function(){return e.normal}},VIEWPORT:function(e,t){return function(){return e.viewportCartesian4}}},Dt={};"undefined"!=typeof WebGLRenderingContext&&(Dt[U.FLOAT]=We,Dt[U.FLOAT_VEC2]=He,Dt[U.FLOAT_VEC3]=qe,Dt[U.FLOAT_VEC4]=je,Dt[U.INT]=We,Dt[U.INT_VEC2]=He,Dt[U.INT_VEC3]=qe,Dt[U.INT_VEC4]=je,Dt[U.BOOL]=We,Dt[U.BOOL_VEC2]=He,Dt[U.BOOL_VEC3]=qe,Dt[U.BOOL_VEC4]=je,Dt[U.FLOAT_MAT2]=Ye,Dt[U.FLOAT_MAT3]=Xe,Dt[U.FLOAT_MAT4]=Ze,Dt[U.SAMPLER_2D]=Ke);var Rt={MODEL:function(e,t,r){return function(){return r.computedMatrix}},VIEW:function(e,t,r){return function(){return e.view}},PROJECTION:function(e,t,r){return function(){return e.projection}},MODELVIEW:function(e,t,r){var i=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i)}},CESIUM_RTC_MODELVIEW:function(e,t,r){var i=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.setTranslation(i,t._rtcCenterEye,i)}},MODELVIEWPROJECTION:function(e,t,r){var i=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.multiply(e._projection,i,i)}},MODELINVERSE:function(e,t,r){var i=new b;return function(){return b.inverse(r.computedMatrix,i)}},VIEWINVERSE:function(e,t){return function(){return e.inverseView}},PROJECTIONINVERSE:function(e,t,r){return function(){return e.inverseProjection}},MODELVIEWINVERSE:function(e,t,r){var i=new b,n=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.inverse(i,n)}},MODELVIEWPROJECTIONINVERSE:function(e,t,r){var i=new b,n=new b;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.multiply(e._projection,i,i),b.inverse(i,n)}},MODELINVERSETRANSPOSE:function(e,t,r){var i=new b,n=new T;return function(){return b.inverse(r.computedMatrix,i),b.getRotation(i,n),T.transpose(n,n)}},MODELVIEWINVERSETRANSPOSE:function(e,t,r){var i=new b,n=new b,o=new T;return function(){return b.multiplyTransformation(e.view,r.computedMatrix,i),b.inverse(i,n),b.getRotation(n,o),T.transpose(o,o)}},VIEWPORT:function(e,t,r){return function(){return e.viewportCartesian4}}},Ot=[],Nt=new b,Lt=new t,Ft=new e,Bt=new r,Vt=function(e,t){this.buffers=void 0,this.vertexArrays=void 0,this.programs=void 0,this.pickPrograms=void 0,this.textures=void 0,this.samplers=void 0,this.renderStates=void 0,this.ready=!1,this.context=e,this.cacheKey=t,this.count=0};return Vt.prototype.release=function(){return 0===--this.count?(l(this.cacheKey)&&delete this.context.cache.modelRendererResourceCache[this.cacheKey],vt(this),h(this)):void 0},wt.prototype.update=function(e){if(e.mode===$.SCENE3D){var t=e.context;if(this._state===yt.NEEDS_LOAD&&l(this.gltf)){var i,n=this.cacheKey;if(l(n)){t.cache.modelRendererResourceCache=s(t.cache.modelRendererResourceCache,{});var o=t.cache.modelRendererResourceCache;if(i=o[this.cacheKey],l(i)){if(!i.ready)return;++i.count,this._loadRendererResourcesFromCache=!0}else i=new Vt(t,n),i.count=1,o[this.cacheKey]=i;this._cachedRendererResources=i}else i=new Vt(t),i.count=1,this._cachedRendererResources=i;if(this._state=yt.LOADING,this._boundingSphere=ue(this.gltf),this._initialRadius=this._boundingSphere.radius,mt(this),this._state!==yt.FAILED){var a=this.gltf.extensions;l(a)&&l(a.CESIUM_RTC)&&(this._rtcCenter=r.fromArray(a.CESIUM_RTC.center),this._rtcCenterEye=new r),this._loadResources=new ee,we(this)}}var u=!1;if(this._state===yt.FAILED)throw this._loadError;if(this._state===yt.LOADING){it(this,t);var c=this._loadResources;if(c.finishedPendingLoads()&&c.finishedResourceCreation()){this._state=yt.LOADED,this._loadResources=void 0;var h=this._rendererResources,d=this._cachedRendererResources;d.buffers=h.buffers,d.vertexArrays=h.vertexArrays,d.programs=h.programs,d.pickPrograms=h.pickPrograms,d.textures=h.textures,d.samplers=h.samplers, -d.renderStates=h.renderStates,d.ready=!0,this.releaseGltfJson&&pt(this),u=!0}}var p=this.show&&0!==this.scale;if(p&&this._state===yt.LOADED||u){var m=this.activeAnimations.update(e)||this._cesiumAnimationsDirty;this._cesiumAnimationsDirty=!1;var f=!b.equals(this._modelMatrix,this.modelMatrix)||this._scale!==this.scale||this._minimumPixelSize!==this.minimumPixelSize||0!==this.minimumPixelSize||this._maximumScale!==this.maximumScale;if(f||u){b.clone(this.modelMatrix,this._modelMatrix),this._scale=this.scale,this._minimumPixelSize=this.minimumPixelSize,this._maximumScale=this.maximumScale;var v=dt(this,e),_=this._computedModelMatrix;b.multiplyByUniformScale(this.modelMatrix,v,_),b.multiplyTransformation(_,_t,_)}(m||f||u)&&(ot(this,f,u),(m||u)&&at(this)),this._perNodeShowDirty&&(this._perNodeShowDirty=!1,st(this)),lt(this,t),ut(this),ct(this),l(this._rtcCenter)&&b.multiplyByPoint(e.camera.viewMatrix,this._rtcCenter,this._rtcCenterEye)}if(u){var g=this;return void e.afterRender.push(function(){g._ready=!0,g._readyPromise.resolve(g)})}if(p){var y,C,E=e.commandList,S=e.passes,w=this._nodeCommands,T=w.length;if(S.render)for(y=0;T>y;++y)C=w[y],C.show&&E.push(C.command);if(S.pick)for(y=0;T>y;++y)C=w[y],C.show&&E.push(C.pickCommand)}}},wt.prototype.isDestroyed=function(){return!1},wt.prototype.destroy=function(){this._rendererResources=void 0,this._cachedRendererResources=this._cachedRendererResources&&this._cachedRendererResources.release();for(var e=this._pickIds,t=e.length,r=0;t>r;++r)e[r].destroy();return pt(this),h(this)},wt}),r("DataSources/ModelVisualizer",["../Core/AssociativeArray","../Core/BoundingSphere","../Core/Cartesian3","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Matrix4","../Scene/Model","../Scene/ModelAnimationLoop","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t,r,n){var o=r[t.id];i(o)&&(n.removeAndDestroy(o.modelPrimitive),delete r[t.id])}function d(e){e.activeAnimations.addAll({loop:l.REPEAT})}function p(e){console.error(e)}var m=1,f=0,v=function(t,r){r.collectionChanged.addEventListener(v.prototype._onCollectionChanged,this),this._scene=t,this._primitives=t.primitives,this._entityCollection=r,this._modelHash={},this._entitiesToVisualize=new e,this._modelMatrixScratch=new a,this._onCollectionChanged(r,r.values,[],[])};return v.prototype.update=function(e){for(var t=(this._scene.context,this._entitiesToVisualize.values),r=this._modelHash,n=this._primitives,o=(this._scene,0),l=t.length;l>o;o++){var u,h,v=t[o],_=v._model,g=r[v.id],y=v.isShowing&&v.isAvailable(e)&&c.getValueOrDefault(_._show,e,!0);if(y&&(h=v._getModelMatrix(e,this._modelMatrixScratch),u=c.getValueOrUndefined(_._uri,e),y=i(h)&&i(u)),y){var C=i(g)?g.modelPrimitive:void 0;i(C)&&u===g.uri||(i(C)&&(n.removeAndDestroy(C),delete r[v.id]),C=s.fromGltf({url:u}),C.readyPromise.then(d).otherwise(p),C.id=v,n.add(C),g={modelPrimitive:C,uri:u},r[v.id]=g),C.show=!0,C.scale=c.getValueOrDefault(_._scale,e,m),C.minimumPixelSize=c.getValueOrDefault(_._minimumPixelSize,e,f),C.maximumScale=c.getValueOrUndefined(_._maximumScale,e),C.modelMatrix=a.clone(h,C.modelMatrix)}else i(g)&&(g.modelPrimitive.show=!1)}return!0},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){this._entityCollection.collectionChanged.removeEventListener(v.prototype._onCollectionChanged,this);for(var e=this._entitiesToVisualize.values,t=this._modelHash,r=this._primitives,i=e.length-1;i>-1;i--)h(this,e[i],t,r);return n(this)},v.prototype.getBoundingSphere=function(e,r){var n=this._modelHash[e.id];if(!i(n))return u.FAILED;var o=n.modelPrimitive;return i(o)&&o.show?o.ready?(t.transform(o.boundingSphere,o.modelMatrix,r),u.DONE):u.PENDING:u.FAILED},v.prototype._onCollectionChanged=function(e,t,r,n){var o,a,s=this._entitiesToVisualize,l=this._modelHash,u=this._primitives;for(o=t.length-1;o>-1;o--)a=t[o],i(a._model)&&i(a._position)&&s.set(a.id,a);for(o=n.length-1;o>-1;o--)a=n[o],i(a._model)&&i(a._position)?s.set(a.id,a):(h(this,a,l,u),s.remove(a.id));for(o=r.length-1;o>-1;o--)a=r[o],h(this,a,l,u),s.remove(a.id)},v}),r("Shaders/PolylineCommon",[],function(){"use strict";return"void clipLineSegmentToNearPlane(\nvec3 p0,\nvec3 p1,\nout vec4 positionWC,\nout bool clipped,\nout bool culledByNearPlane)\n{\nculledByNearPlane = false;\nclipped = false;\nvec3 p1ToP0 = p1 - p0;\nfloat magnitude = length(p1ToP0);\nvec3 direction = normalize(p1ToP0);\nfloat endPoint0Distance = -(czm_currentFrustum.x + p0.z);\nfloat denominator = -direction.z;\nif (endPoint0Distance < 0.0 && abs(denominator) < czm_epsilon7)\n{\nculledByNearPlane = true;\n}\nelse if (endPoint0Distance < 0.0 && abs(denominator) > czm_epsilon7)\n{\nfloat t = (czm_currentFrustum.x + p0.z) / denominator;\nif (t < 0.0 || t > magnitude)\n{\nculledByNearPlane = true;\n}\nelse\n{\np0 = p0 + t * direction;\nclipped = true;\n}\n}\npositionWC = czm_eyeToWindowCoordinates(vec4(p0, 1.0));\n}\nvec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious) {\nvec4 endPointWC, p0, p1;\nbool culledByNearPlane, clipped;\nvec4 positionEC = czm_modelViewRelativeToEye * position;\nvec4 prevEC = czm_modelViewRelativeToEye * previous;\nvec4 nextEC = czm_modelViewRelativeToEye * next;\nclipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, p0, clipped, culledByNearPlane);\nclipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, p1, clipped, culledByNearPlane);\nclipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, endPointWC, clipped, culledByNearPlane);\nif (culledByNearPlane)\n{\nreturn vec4(0.0, 0.0, 0.0, 1.0);\n}\nvec2 prevWC = normalize(p0.xy - endPointWC.xy);\nvec2 nextWC = normalize(p1.xy - endPointWC.xy);\nfloat expandWidth = width * 0.5;\nvec2 direction;\nif (czm_equalsEpsilon(normalize(previous.xyz - position.xyz), vec3(0.0), czm_epsilon1) || czm_equalsEpsilon(prevWC, -nextWC, czm_epsilon1))\n{\ndirection = vec2(-nextWC.y, nextWC.x);\n}\nelse if (czm_equalsEpsilon(normalize(next.xyz - position.xyz), vec3(0.0), czm_epsilon1) || clipped)\n{\ndirection = vec2(prevWC.y, -prevWC.x);\n}\nelse\n{\nvec2 normal = vec2(-nextWC.y, nextWC.x);\ndirection = normalize((nextWC + prevWC) * 0.5);\nif (dot(direction, normal) < 0.0)\n{\ndirection = -direction;\n}\nfloat sinAngle = abs(direction.x * nextWC.y - direction.y * nextWC.x);\nexpandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);\n}\nvec2 offset = direction * expandDirection * expandWidth * czm_resolutionScale;\nreturn vec4(endPointWC.xy + offset, -endPointWC.z, 1.0);\n}\n"}),r("Shaders/PolylineFS",[],function(){"use strict";return"varying vec2 v_st;\nvoid main()\n{\nczm_materialInput materialInput;\nmaterialInput.s = v_st.s;\nmaterialInput.st = v_st;\nmaterialInput.str = vec3(v_st, 0.0);\nczm_material material = czm_getMaterial(materialInput);\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n}\n"}),r("Shaders/PolylineVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 position2DHigh;\nattribute vec3 position2DLow;\nattribute vec3 prevPosition3DHigh;\nattribute vec3 prevPosition3DLow;\nattribute vec3 prevPosition2DHigh;\nattribute vec3 prevPosition2DLow;\nattribute vec3 nextPosition3DHigh;\nattribute vec3 nextPosition3DLow;\nattribute vec3 nextPosition2DHigh;\nattribute vec3 nextPosition2DLow;\nattribute vec4 texCoordExpandWidthAndShow;\nattribute vec4 pickColor;\nvarying vec2 v_st;\nvarying float v_width;\nvarying vec4 czm_pickColor;\nvoid main()\n{\nfloat texCoord = texCoordExpandWidthAndShow.x;\nfloat expandDir = texCoordExpandWidthAndShow.y;\nfloat width = abs(texCoordExpandWidthAndShow.z) + 0.5;\nbool usePrev = texCoordExpandWidthAndShow.z < 0.0;\nfloat show = texCoordExpandWidthAndShow.w;\nvec4 p, prev, next;\nif (czm_morphTime == 1.0)\n{\np = czm_translateRelativeToEye(position3DHigh.xyz, position3DLow.xyz);\nprev = czm_translateRelativeToEye(prevPosition3DHigh.xyz, prevPosition3DLow.xyz);\nnext = czm_translateRelativeToEye(nextPosition3DHigh.xyz, nextPosition3DLow.xyz);\n}\nelse if (czm_morphTime == 0.0)\n{\np = czm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy);\nprev = czm_translateRelativeToEye(prevPosition2DHigh.zxy, prevPosition2DLow.zxy);\nnext = czm_translateRelativeToEye(nextPosition2DHigh.zxy, nextPosition2DLow.zxy);\n}\nelse\n{\np = czm_columbusViewMorph(\nczm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy),\nczm_translateRelativeToEye(position3DHigh.xyz, position3DLow.xyz),\nczm_morphTime);\nprev = czm_columbusViewMorph(\nczm_translateRelativeToEye(prevPosition2DHigh.zxy, prevPosition2DLow.zxy),\nczm_translateRelativeToEye(prevPosition3DHigh.xyz, prevPosition3DLow.xyz),\nczm_morphTime);\nnext = czm_columbusViewMorph(\nczm_translateRelativeToEye(nextPosition2DHigh.zxy, nextPosition2DLow.zxy),\nczm_translateRelativeToEye(nextPosition3DHigh.xyz, nextPosition3DLow.xyz),\nczm_morphTime);\n}\nvec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\ngl_Position = czm_viewportOrthographic * positionWC * show;\nv_st = vec2(texCoord, clamp(expandDir, 0.0, 1.0));\nv_width = width;\nczm_pickColor = pickColor;\n}\n"}),r("Scene/Polyline",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix4","../Core/PolylinePipeline","./Material"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){++e._propertiesChanged[t];var r=e._polylineCollection;n(r)&&(r._updatePolyline(e,t),e._dirty=!0)}var h=function(o,a){o=i(o,i.EMPTY_OBJECT),this._show=i(o.show,!0),this._width=i(o.width,1),this._loop=i(o.loop,!1),this._material=o.material,n(this._material)||(this._material=u.fromType(u.ColorType,{color:new r(1,1,1,1)}));var c=o.positions;n(c)||(c=[]),this._positions=c,this._actualPositions=l.removeDuplicates(c),this._loop&&this._actualPositions.length>2&&(this._actualPositions===this._positions&&(this._actualPositions=c.slice()),this._actualPositions.push(t.clone(this._actualPositions[0]))),this._length=this._actualPositions.length,this._id=o.id;var h;n(a)&&(h=s.clone(a.modelMatrix)),this._modelMatrix=h,this._segments=l.wrapLongitude(this._actualPositions,h),this._actualLength=void 0,this._propertiesChanged=new Uint32Array(_),this._polylineCollection=a,this._dirty=!1,this._pickId=void 0,this._boundingVolume=e.fromPoints(this._actualPositions),this._boundingVolumeWC=e.transform(this._boundingVolume,this._modelMatrix),this._boundingVolume2D=new e},d=h.SHOW_INDEX=0,p=h.WIDTH_INDEX=1,m=h.POSITION_INDEX=2,f=h.MATERIAL_INDEX=3,v=h.POSITION_SIZE_INDEX=4,_=h.NUMBER_OF_PROPERTIES=5;return o(h.prototype,{show:{get:function(){return this._show},set:function(e){e!==this._show&&(this._show=e,c(this,d))}},positions:{get:function(){return this._positions},set:function(r){var i=l.removeDuplicates(r);this._loop&&i.length>2&&(i===r&&(i=r.slice()),i.push(t.clone(i[0]))),(this._actualPositions.length!==i.length||this._actualPositions.length!==this._length)&&c(this,v),this._positions=r,this._actualPositions=i,this._length=i.length,this._boundingVolume=e.fromPoints(this._actualPositions,this._boundingVolume),this._boundingVolumeWC=e.transform(this._boundingVolume,this._modelMatrix,this._boundingVolumeWC),c(this,m),this.update()}},material:{get:function(){return this._material},set:function(e){this._material!==e&&(this._material=e,c(this,f))}},width:{get:function(){return this._width},set:function(e){var t=this._width;e!==t&&(this._width=e,c(this,p))}},loop:{get:function(){return this._loop},set:function(e){if(e!==this._loop){var r=this._actualPositions;e?r.length>2&&!t.equals(r[0],r[r.length-1])&&(r.length===this._positions.length&&(this._actualPositions=r=this._positions.slice()),r.push(t.clone(r[0]))):r.length>2&&t.equals(r[0],r[r.length-1])&&(r.length-1===this._positions.length?this._actualPositions=this._positions:r.pop()),this._loop=e,c(this,v)}}},id:{get:function(){return this._id},set:function(e){this._id=e,n(this._pickId)&&(this._pickId.object.id=e)}}}),h.prototype.update=function(){var t=s.IDENTITY;n(this._polylineCollection)&&(t=this._polylineCollection.modelMatrix);var r=this._segments.positions.length,i=this._segments.lengths,o=this._propertiesChanged[m]>0||this._propertiesChanged[v]>0;if((!s.equals(t,this._modelMatrix)||o)&&(this._segments=l.wrapLongitude(this._actualPositions,t),this._boundingVolumeWC=e.transform(this._boundingVolume,t,this._boundingVolumeWC)),this._modelMatrix=t,this._segments.positions.length!==r)c(this,v);else for(var a=i.length,u=0;a>u;++u)if(i[u]!==this._segments.lengths[u]){c(this,v);break}},h.prototype.getPickId=function(e){return n(this._pickId)||(this._pickId=e.createPickId({primitive:this,collection:this._polylineCollection,id:this._id})),this._pickId},h.prototype._clean=function(){this._dirty=!1;for(var e=this._propertiesChanged,t=0;_-1>t;++t)e[t]=0},h.prototype._destroy=function(){this._pickId=this._pickId&&this._pickId.destroy(),this._material=this._material&&this._material.destroy(),this._polylineCollection=void 0},h}),r("Scene/PolylineCollection",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EncodedCartesian3","../Core/IndexDatatype","../Core/Intersect","../Core/Math","../Core/Matrix4","../Core/Plane","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../Shaders/PolylineCommon","../Shaders/PolylineFS","../Shaders/PolylineVS","./BlendingState","./Material","./Pass","./Polyline","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D){"use strict";function R(t,r,i,n,o){for(var a=r.context,l=r.commandList,u=i.length,c=0,h=!0,d=t._vertexArrays,p=t.debugShowBoundingVolume,m=d.length,f=0;m>f;++f)for(var v=d[f],_=v.buckets,g=_.length,C=0;g>C;++C){for(var E,S,w,T=_[C],b=T.offset,x=o?T.bucket.shaderProgram:T.bucket.pickShaderProgram,P=T.bucket.polylines,A=P.length,M=0,R=0;A>R;++R){var O=P[R],N=L(O._material);if(N!==E){if(s(E)&&M>0){var F=S.isTranslucent();c>=u?(w=new y({owner:t}),i.push(w)):w=i[c],++c,w.boundingVolume=e.clone(Q,w.boundingVolume),w.modelMatrix=n,w.shaderProgram=x,w.vertexArray=v.va,w.renderState=F?t._translucentRS:t._opaqueRS,w.pass=F?I.TRANSLUCENT:I.OPAQUE,w.debugShowBoundingVolume=o?p:!1,w.uniformMap=S._uniforms,w.count=M,w.offset=b,b+=M,M=0,h=!0,l.push(w)}S=O._material,S.update(a),E=N}for(var B=O._locatorBuckets,V=B.length,z=0;V>z;++z){var k=B[z];k.locator===T&&(M+=k.count)}var U;r.mode===D.SCENE3D?U=O._boundingVolumeWC:r.mode===D.COLUMBUS_VIEW?U=O._boundingVolume2D:r.mode===D.SCENE2D?s(O._boundingVolume2D)&&(U=e.clone(O._boundingVolume2D,$),U.center.x=0):s(O._boundingVolumeWC)&&s(O._boundingVolume2D)&&(U=e.union(O._boundingVolumeWC,O._boundingVolume2D,$)),h?(h=!1,e.clone(U,Q)):e.union(U,Q,Q)}s(E)&&M>0&&(c>=u?(w=new y({owner:t}),i.push(w)):w=i[c],++c,w.boundingVolume=e.clone(Q,w.boundingVolume),w.modelMatrix=n,w.shaderProgram=x,w.vertexArray=v.va,w.renderState=S.isTranslucent()?t._translucentRS:t._opaqueRS,w.pass=S.isTranslucent()?I.TRANSLUCENT:I.OPAQUE,w.debugShowBoundingVolume=o?p:!1,w.uniformMap=S._uniforms,w.count=M,w.offset=b,h=!0,l.push(w)),E=void 0}i.length=c}function O(e){for(var t=e._buffersUsage,r=!1,i=e._propertiesChanged,n=0;Z-2>n;++n){var o=t[n];i[n]?o.bufferUsage!==g.STREAM_DRAW?(r=!0,o.bufferUsage=g.STREAM_DRAW,o.frameCount=100):o.frameCount=100:o.bufferUsage!==g.STATIC_DRAW&&(0===o.frameCount?(r=!0,o.bufferUsage=g.STATIC_DRAW):o.frameCount--)}return r}function N(e,t,r){e._createVertexArray=!1,z(e),k(e),F(e);var i,n,a=[[]],l=a[0],u=[0],c=0,h=[[]],p=0,f=e._polylineBuckets;for(i in f)f.hasOwnProperty(i)&&(n=f[i],n.updateShader(t),p+=n.lengthOfPositions);if(p>0){var v,y=e._mode,C=new Float32Array(6*p*3),E=new Uint8Array(4*p),S=new Float32Array(4*p),T=0,b=0,x=0;for(i in f)if(f.hasOwnProperty(i)){n=f[i],n.write(C,E,S,T,b,x,t,r),y===D.MORPHING&&(s(v)||(v=new Float32Array(6*p*3)),n.writeForMorph(v,T));var P=n.lengthOfPositions;T+=6*P*3,b+=4*P,x+=4*P,c=n.updateIndices(a,u,h,c)}var A=e._buffersUsage[j].bufferUsage,I=e._buffersUsage[H].bufferUsage,M=e._buffersUsage[q].bufferUsage,R=I===g.STREAM_DRAW||M===g.STREAM_DRAW?g.STREAM_DRAW:g.STATIC_DRAW;e._positionBuffer=_.createVertexBuffer({context:t,typedArray:C,usage:A});var O;s(v)&&(O=_.createVertexBuffer({context:t,typedArray:v,usage:A})),e._pickColorBuffer=_.createVertexBuffer({context:t,typedArray:E,usage:g.STATIC_DRAW}),e._texCoordExpandWidthAndShowBuffer=_.createVertexBuffer({context:t,typedArray:S,usage:R});for(var N=4*Uint8Array.BYTES_PER_ELEMENT,L=3*Float32Array.BYTES_PER_ELEMENT,B=4*Float32Array.BYTES_PER_ELEMENT,V=0,U=a.length,G=0;U>G;++G)if(l=a[G],l.length>0){var W=new Uint16Array(l),Y=_.createIndexBuffer({context:t,typedArray:W,usage:g.STATIC_DRAW,indexDatatype:d.UNSIGNED_SHORT});V+=u[G];var X,Z,J,Q,$=6*(G*L*m.SIXTY_FOUR_KILOBYTES-V*L),te=L+$,re=L+te,ie=L+re,ne=L+ie,oe=L+ne,ae=G*N*m.SIXTY_FOUR_KILOBYTES-V*N,se=G*B*m.SIXTY_FOUR_KILOBYTES-V*B,le=[{index:K.position3DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:$,strideInBytes:6*L},{index:K.position3DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:te,strideInBytes:6*L},{index:K.position2DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:$,strideInBytes:6*L},{index:K.position2DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:te,strideInBytes:6*L},{index:K.prevPosition3DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:re,strideInBytes:6*L},{index:K.prevPosition3DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ie,strideInBytes:6*L},{index:K.prevPosition2DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:re,strideInBytes:6*L},{index:K.prevPosition2DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ie,strideInBytes:6*L},{index:K.nextPosition3DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ne,strideInBytes:6*L},{index:K.nextPosition3DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:oe,strideInBytes:6*L},{index:K.nextPosition2DHigh,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:ne,strideInBytes:6*L},{index:K.nextPosition2DLow,componentsPerAttribute:3,componentDatatype:o.FLOAT,offsetInBytes:oe,strideInBytes:6*L},{index:K.texCoordExpandWidthAndShow,componentsPerAttribute:4,componentDatatype:o.FLOAT,vertexBuffer:e._texCoordExpandWidthAndShowBuffer,offsetInBytes:se},{index:K.pickColor,componentsPerAttribute:4,componentDatatype:o.UNSIGNED_BYTE,vertexBuffer:e._pickColorBuffer,offsetInBytes:ae,normalize:!0}];y===D.SCENE3D?(X=e._positionBuffer,Z="vertexBuffer",J=ee,Q="value"):y===D.SCENE2D||y===D.COLUMBUS_VIEW?(X=ee,Z="value",J=e._positionBuffer,Q="vertexBuffer"):(X=O,Z="vertexBuffer",J=e._positionBuffer,Q="vertexBuffer"),le[0][Z]=X,le[1][Z]=X,le[2][Q]=J,le[3][Q]=J,le[4][Z]=X,le[5][Z]=X,le[6][Q]=J,le[7][Q]=J,le[8][Z]=X,le[9][Z]=X,le[10][Q]=J,le[11][Q]=J;var ue=new w({context:t,attributes:le,indexBuffer:Y});e._vertexArrays.push({va:ue,buckets:h[G]})}}}function L(e){var t=A._uniformList[e.type],r=t.length;te.length=2*r;for(var i=0,n=0;r>n;++n){var o=t[n];te[i]=o,te[i+1]=e._uniforms[o](),i+=2}return e.type+":"+JSON.stringify(te)}function F(e){for(var t=e._mode,r=e._modelMatrix,i=e._polylineBuckets={},n=e._polylines,o=n.length,a=0;o>a;++a){var l=n[a];if(l._actualPositions.length>1){l.update();var u=l.material,c=i[u.type];s(c)||(c=i[u.type]=new re(u,t,r)),c.addPolyline(l)}}}function B(e,t){var r=t.mode;e._mode===r&&f.equals(e._modelMatrix,e.modelMatrix)||(e._mode=r,e._modelMatrix=f.clone(e.modelMatrix),e._createVertexArray=!0)}function V(e){if(e._polylinesRemoved){e._polylinesRemoved=!1;for(var t=[],r=e._polylines.length,i=0,n=0;r>i;++i){var o=e._polylines[i];s(o)&&(o._index=n++,t.push(o))}e._polylines=t}}function z(e){for(var t=e._polylines,r=t.length,i=0;r>i;++i)if(s(t[i])){var n=t[i]._bucket;s(n)&&(n.shaderProgram=n.shaderProgram&&n.shaderProgram.destroy())}}function k(e){for(var t=e._vertexArrays.length,r=0;t>r;++r)e._vertexArrays[r].va.destroy();e._vertexArrays.length=0}function U(e){for(var t=e._polylines,r=t.length,i=0;r>i;++i)s(t[i])&&t[i]._destroy()}function G(e,t,r){this.count=e,this.offset=t,this.bucket=r}function W(e){return t.dot(t.UNIT_X,e._boundingVolume.center)<0||e._boundingVolume.intersectPlane(v.ORIGIN_ZX_PLANE)===p.INTERSECTING}var H=M.SHOW_INDEX,q=M.WIDTH_INDEX,j=M.POSITION_INDEX,Y=M.MATERIAL_INDEX,X=M.POSITION_SIZE_INDEX,Z=M.NUMBER_OF_PROPERTIES,K={texCoordExpandWidthAndShow:0,position3DHigh:1,position3DLow:2,position2DHigh:3,position2DLow:4,prevPosition3DHigh:5,prevPosition3DLow:6,prevPosition2DHigh:7,prevPosition2DLow:8,nextPosition3DHigh:9,nextPosition3DLow:10,nextPosition2DHigh:11,nextPosition2DLow:12,pickColor:13},J=function(e){e=a(e,a.EMPTY_OBJECT),this.modelMatrix=f.clone(a(e.modelMatrix,f.IDENTITY)),this._modelMatrix=f.clone(f.IDENTITY),this.debugShowBoundingVolume=a(e.debugShowBoundingVolume,!1),this._opaqueRS=void 0,this._translucentRS=void 0,this._colorCommands=[],this._pickCommands=[],this._polylinesUpdated=!1,this._polylinesRemoved=!1,this._createVertexArray=!1,this._propertiesChanged=new Uint32Array(Z),this._polylines=[],this._polylineBuckets={},this._buffersUsage=[{bufferUsage:g.STATIC_DRAW,frameCount:0},{bufferUsage:g.STATIC_DRAW,frameCount:0},{bufferUsage:g.STATIC_DRAW,frameCount:0}],this._mode=void 0,this._polylinesToUpdate=[],this._vertexArrays=[],this._positionBuffer=void 0,this._pickColorBuffer=void 0,this._texCoordExpandWidthAndShowBuffer=void 0};l(J.prototype,{length:{get:function(){return V(this),this._polylines.length}}}),J.prototype.add=function(e){var t=new M(e,this);return t._index=this._polylines.length,this._polylines.push(t),this._createVertexArray=!0,t},J.prototype.remove=function(e){if(this.contains(e)){if(this._polylines[e._index]=void 0,this._polylinesRemoved=!0,this._createVertexArray=!0,s(e._bucket)){var t=e._bucket;t.shaderProgram=t.shaderProgram&&t.shaderProgram.destroy(),t.pickShaderProgram=t.pickShaderProgram&&t.pickShaderProgram.destroy()}return e._destroy(),!0}return!1},J.prototype.removeAll=function(){z(this),U(this),this._polylineBuckets={},this._polylinesRemoved=!1,this._polylines.length=0,this._polylinesToUpdate.length=0,this._createVertexArray=!0},J.prototype.contains=function(e){return s(e)&&e._polylineCollection===this},J.prototype.get=function(e){return V(this),this._polylines[e]},J.prototype.update=function(e,t){if(V(this),0!==this._polylines.length){B(this,e);var r,i=e.context,n=e.mapProjection,o=this._propertiesChanged;if(this._createVertexArray||O(this))N(this,i,n);else if(this._polylinesUpdated){var a=this._polylinesToUpdate;if(this._mode!==D.SCENE3D)for(var l=a.length,u=0;l>u;++u)r=a[u],r.update();if(o[X]||o[Y])N(this,i,n);else for(var c=a.length,h=this._polylineBuckets,d=0;c>d;++d){r=a[d],o=r._propertiesChanged;var p=r._bucket,m=0;for(var v in h)if(h.hasOwnProperty(v)){if(h[v]===p){(o[j]||o[H]||o[q])&&p.writeUpdate(m,r,this._positionBuffer,this._texCoordExpandWidthAndShowBuffer,n);break}m+=h[v].lengthOfPositions}r._clean()}a.length=0,this._polylinesUpdated=!1}o=this._propertiesChanged;for(var _=0;Z>_;++_)o[_]=0;var g=f.IDENTITY;e.mode===D.SCENE3D&&(g=this.modelMatrix);var y=e.passes,E=0!==e.morphTime;if(s(this._opaqueRS)&&this._opaqueRS.depthTest.enabled===E||(this._opaqueRS=C.fromCache({depthMask:E,depthTest:{enabled:E}})),s(this._translucentRS)&&this._translucentRS.depthTest.enabled===E||(this._translucentRS=C.fromCache({blending:P.ALPHA_BLEND,depthMask:!E,depthTest:{enabled:E}})),y.render){var S=this._colorCommands;R(this,e,S,g,!0)}if(y.pick){var w=this._pickCommands;R(this,e,w,g,!1)}}};var Q=new e,$=new e;J.prototype.isDestroyed=function(){return!1},J.prototype.destroy=function(){return k(this),z(this),U(this),u(this)};var ee=[0,0,0],te=[];J.prototype._updatePolyline=function(e,t){this._polylinesUpdated=!0,this._polylinesToUpdate.push(e),++this._propertiesChanged[t]};var re=function(e,t,r){this.polylines=[],this.lengthOfPositions=0,this.material=e,this.shaderProgram=void 0,this.pickShaderProgram=void 0,this.mode=t,this.modelMatrix=r};re.prototype.addPolyline=function(e){var t=this.polylines;t.push(e),e._actualLength=this.getPolylinePositionsLength(e),this.lengthOfPositions+=e._actualLength,e._bucket=this},re.prototype.updateShader=function(e){if(!s(this.shaderProgram)){var t=new S({sources:[T,x]}),r=new S({sources:[this.material.shaderSource,b]}),i=new S({sources:r.sources,pickColorQualifier:"varying"});this.shaderProgram=E.fromCache({context:e,vertexShaderSource:t,fragmentShaderSource:r,attributeLocations:K}),this.pickShaderProgram=E.fromCache({context:e,vertexShaderSource:t,fragmentShaderSource:i,attributeLocations:K})}},re.prototype.getPolylinePositionsLength=function(e){var t;if(this.mode===D.SCENE3D||!W(e))return t=e._actualPositions.length,4*t-4;var r=0,i=e._segments.lengths;t=i.length;for(var n=0;t>n;++n)r+=4*i[n]-4;return r};var ie=new t,ne=new t,oe=new t,ae=new t;re.prototype.write=function(e,r,i,o,a,s,l,u){for(var c=this.mode,d=this.polylines,p=d.length,m=0;p>m;++m)for(var f,v=d[m],_=v.width,g=v.show&&_>0,y=this.getSegments(v,u),C=y.positions,E=y.lengths,S=C.length,w=v.getPickId(l).color,T=0,b=0,x=0;S>x;++x){0===x?v._loop?f=C[S-2]:(f=ae,t.subtract(C[0],C[1],f),t.add(C[0],f,f)):f=C[x-1],ne.x=f.x,ne.y=f.y,ne.z=c!==D.SCENE2D?f.z:0,f=C[x],ie.x=f.x,ie.y=f.y,ie.z=c!==D.SCENE2D?f.z:0,x===S-1?v._loop?f=C[1]:(f=ae,t.subtract(C[S-1],C[S-2],f),t.add(C[S-1],f,f)):f=C[x+1],oe.x=f.x,oe.y=f.y,oe.z=c!==D.SCENE2D?f.z:0;var P=E[T];x===b+P&&(b+=P,++T);for(var A=x-b===0,I=x===b+E[T]-1,M=A?2:0,R=I?2:4,O=M;R>O;++O){h.writeElements(ie,e,o),h.writeElements(ne,e,o+6),h.writeElements(oe,e,o+12),r[a]=n.floatToByte(w.red),r[a+1]=n.floatToByte(w.green),r[a+2]=n.floatToByte(w.blue),r[a+3]=n.floatToByte(w.alpha);var N=0>O-2?-1:1;i[s]=x/(S-1),i[s+1]=2*(O%2)-1,i[s+2]=N*_,i[s+3]=g,o+=18,a+=4,s+=4}}};var se=new t,le=new t,ue=new t,ce=new t;re.prototype.writeForMorph=function(e,r){for(var i=this.modelMatrix,n=this.polylines,o=n.length,a=0;o>a;++a)for(var s=n[a],l=s._segments.positions,u=s._segments.lengths,c=l.length,d=0,p=0,m=0;c>m;++m){var v;0===m?s._loop?v=l[c-2]:(v=ce,t.subtract(l[0],l[1],v),t.add(l[0],v,v)):v=l[m-1],v=f.multiplyByPoint(i,v,le);var _,g=f.multiplyByPoint(i,l[m],se);m===c-1?s._loop?_=l[1]:(_=ce,t.subtract(l[c-1],l[c-2],_),t.add(l[c-1],_,_)):_=l[m+1],_=f.multiplyByPoint(i,_,ue);var y=u[d];m===p+y&&(p+=y,++d);for(var C=m-p===0,E=m===p+u[d]-1,S=C?2:0,w=E?2:4,T=S;w>T;++T)h.writeElements(g,e,r),h.writeElements(v,e,r+6),h.writeElements(_,e,r+12),r+=18}};var he=new Array(1);re.prototype.updateIndices=function(e,t,r,i){var n=r.length-1,o=new G(0,i,this);r[n].push(o);var a=0,s=e[e.length-1],l=0;s.length>0&&(l=s[s.length-1]+1);for(var u=this.polylines,c=u.length,h=0;c>h;++h){var d=u[h];d._locatorBuckets=[];var p;if(this.mode===D.SCENE3D){p=he;var f=d._actualPositions.length;if(!(f>0))continue;p[0]=f}else p=d._segments.lengths;var v=p.length;if(v>0){for(var _=0,g=0;v>g;++g)for(var y=p[g]-1,C=0;y>C;++C)l+4>=m.SIXTY_FOUR_KILOBYTES-2&&(d._locatorBuckets.push({locator:o,count:_}),_=0,t.push(4),s=[],e.push(s),l=0,o.count=a,a=0,i=0,o=new G(0,0,this),r[++n]=[o]),s.push(l,l+2,l+1),s.push(l+1,l+2,l+3),_+=6,a+=6,i+=6,l+=4;d._locatorBuckets.push({locator:o,count:_}),l+4>=m.SIXTY_FOUR_KILOBYTES-2&&(t.push(0),s=[],e.push(s),l=0,o.count=a,i=0,a=0,o=new G(0,0,this),r[++n]=[o])}d._clean()}return o.count=a,i},re.prototype.getPolylineStartIndex=function(e){for(var t=this.polylines,r=0,i=t.length,n=0;i>n;++n){var o=t[n];if(o===e)break;r+=o._actualLength}return r};var de={positions:void 0,lengths:void 0},pe=new Array(1),me=new t,fe=new i;re.prototype.getSegments=function(r,i){var n=r._actualPositions;if(this.mode===D.SCENE3D)return pe[0]=n.length,de.positions=n,de.lengths=pe,de;W(r)&&(n=r._segments.positions);for(var o,a=i.ellipsoid,s=[],l=this.modelMatrix,u=n.length,c=me,h=0;u>h;++h)o=n[h],c=f.multiplyByPoint(l,o,c),s.push(i.project(a.cartesianToCartographic(c,fe)));if(s.length>0){r._boundingVolume2D=e.fromPoints(s,r._boundingVolume2D);var d=r._boundingVolume2D.center;r._boundingVolume2D.center=new t(d.z,d.x,d.y)}return de.positions=s,de.lengths=r._segments.lengths,de};var ve,_e;return re.prototype.writeUpdate=function(e,r,i,n,o){var a=this.mode,l=r._actualLength;if(l){e+=this.getPolylineStartIndex(r);var u=ve,c=_e,d=6*l*3;!s(u)||u.length<d?(u=ve=new Float32Array(d),c=_e=new Float32Array(4*l)):u.length>d&&(u=new Float32Array(u.buffer,0,d),c=new Float32Array(c.buffer,0,4*l));var p,m=0,f=0,v=this.getSegments(r,o),_=v.positions,g=v.lengths,y=0,C=0,E=r.width,S=r.show&&E>0;l=_.length;for(var w=0;l>w;++w){0===w?r._loop?p=_[l-2]:(p=ae,t.subtract(_[0],_[1],p),t.add(_[0],p,p)):p=_[w-1],ne.x=p.x,ne.y=p.y,ne.z=a!==D.SCENE2D?p.z:0,p=_[w],ie.x=p.x,ie.y=p.y,ie.z=a!==D.SCENE2D?p.z:0,w===l-1?r._loop?p=_[1]:(p=ae,t.subtract(_[l-1],_[l-2],p),t.add(_[l-1],p,p)):p=_[w+1],oe.x=p.x,oe.y=p.y,oe.z=a!==D.SCENE2D?p.z:0;var T=g[y];w===C+T&&(C+=T,++y);for(var b=w-C===0,x=w===C+g[y]-1,P=b?2:0,A=x?2:4,I=P;A>I;++I){h.writeElements(ie,u,m),h.writeElements(ne,u,m+6),h.writeElements(oe,u,m+12);var M=0>I-2?-1:1;c[f]=w/(l-1),c[f+1]=2*(I%2)-1,c[f+2]=M*E,c[f+3]=S,m+=18,f+=4}}i.copyFromArrayView(u,18*Float32Array.BYTES_PER_ELEMENT*e),n.copyFromArrayView(c,4*Float32Array.BYTES_PER_ELEMENT*e)}},J}),r("DataSources/ScaledPositionProperty",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/ReferenceFrame","./Property"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){this._definitionChanged=new n,this._value=void 0,this._removeSubscription=void 0,this.setValue(e)};return t(s.prototype,{isConstant:{get:function(){return a.isConstant(this._value)}},definitionChanged:{get:function(){return this._definitionChanged}},referenceFrame:{get:function(){return e(this._value)?this._value.referenceFrame:o.FIXED}}}),s.prototype.getValue=function(e,t){return this.getValueInReferenceFrame(e,o.FIXED,t)},s.prototype.setValue=function(t){this._value!==t&&(this._value=t,e(this._removeSubscription)&&(this._removeSubscription(),this._removeSubscription=void 0),e(t)&&(this._removeSubscription=t.definitionChanged.addEventListener(this._raiseDefinitionChanged,this)),this._definitionChanged.raiseEvent(this))},s.prototype.getValueInReferenceFrame=function(t,r,n){return e(this._value)?(n=this._value.getValueInReferenceFrame(t,r,n),e(n)?i.WGS84.scaleToGeodeticSurface(n,n):void 0):void 0},s.prototype.equals=function(e){return this===e||e instanceof s&&this._value===e._value},s.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},s}),r("DataSources/PathVisualizer",["../Core/AssociativeArray","../Core/Cartesian3","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/JulianDate","../Core/Matrix3","../Core/Matrix4","../Core/ReferenceFrame","../Core/TimeInterval","../Core/Transforms","../Scene/PolylineCollection","../Scene/SceneMode","./CompositePositionProperty","./ConstantPositionProperty","./MaterialProperty","./Property","./ReferenceProperty","./SampledPositionProperty","./ScaledPositionProperty","./TimeIntervalCollectionPositionProperty"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";function E(e,t,i,n,a,s,l,u,c){var h,d=u;h=e.getValueInReferenceFrame(t,s,c[d]),r(h)&&(c[d++]=h);for(var p,m,f,v=!r(a)||o.lessThanOrEquals(a,t)||o.greaterThanOrEquals(a,i),_=0,g=n.length,y=n[_],C=i,E=!1;g>_;){if(!v&&o.greaterThanOrEquals(y,a)&&(h=e.getValueInReferenceFrame(a,s,c[d]),r(h)&&(c[d++]=h),v=!0),o.greaterThan(y,t)&&o.lessThan(y,C)&&!y.equals(a)&&(h=e.getValueInReferenceFrame(y,s,c[d]),r(h)&&(c[d++]=h)), -g-1>_){if(l>0&&!E){var S=n[_+1],w=o.secondsDifference(S,y);E=w>l,E&&(p=Math.ceil(w/l),m=0,f=w/Math.max(p,2),p=Math.max(p-1,1))}if(E&&p>m){y=o.addSeconds(y,f,new o),m++;continue}}E=!1,_++,y=n[_]}return h=e.getValueInReferenceFrame(i,s,c[d]),r(h)&&(c[d++]=h),d}function S(e,t,i,n,a,s,l,u){for(var c,h=0,d=l,p=t,m=Math.max(s,60),f=!r(n)||o.lessThanOrEquals(n,t)||o.greaterThanOrEquals(n,i);o.lessThan(p,i);)!f&&o.greaterThanOrEquals(p,n)&&(f=!0,c=e.getValueInReferenceFrame(n,a,u[d]),r(c)&&(u[d]=c,d++)),c=e.getValueInReferenceFrame(p,a,u[d]),r(c)&&(u[d]=c,d++),h++,p=o.addSeconds(t,m*h,new o);return c=e.getValueInReferenceFrame(i,a,u[d]),r(c)&&(u[d]=c,d++),d}function w(e,t,i,n,a,s,l,c){R.start=t,R.stop=i;for(var h=l,d=e.intervals,p=0;p<d.length;p++){var m=d.get(p);if(!u.intersect(m,R,M).isEmpty){var f=m.start;m.isStartIncluded||(f=m.isStopIncluded?m.stop:o.addSeconds(m.start,o.secondsDifference(m.stop,m.start)/2,new o));var v=e.getValueInReferenceFrame(f,a,c[h]);r(v)&&(c[h]=v,h++)}}return h}function T(e,t,i,n,o,a,s,l){var u=e.getValueInReferenceFrame(t,o,l[s]);return r(u)&&(l[s++]=u),s}function b(e,t,r,i,n,a,s,l){D.start=t,D.stop=r;for(var c=s,h=e.intervals,d=0;d<h.length;d++){var p=h.get(d);if(!u.intersect(p,D,M).isEmpty){var m=p.start,f=p.stop,v=t;o.greaterThan(m,v)&&(v=m);var _=r;o.lessThan(f,_)&&(_=f),c=x(p.data,v,_,i,n,a,c,l)}}return c}function x(e,t,r,i,n,o,a,s){for(var l=e;l instanceof _||l instanceof y;)l instanceof _&&(l=l.resolvedProperty),l instanceof y&&(l=l._value);if(l instanceof g){var u=l._property._times;a=E(e,t,r,u,i,n,o,a,s)}else a=l instanceof p?b(e,t,r,i,n,o,a,s):l instanceof C?w(e,t,r,i,n,o,a,s):l instanceof m?T(e,t,r,i,n,o,a,s):S(e,t,r,i,n,o,a,s);return a}function P(e,t,i,n,o,a,s){r(s)||(s=[]);var l=x(e,t,i,n,o,a,0,s);return s.length=l,s}var A=60,I=1,M=new u,D=new u,R=new u,O=function(e){this.entity=e,this.polyline=void 0,this.index=void 0,this.updater=void 0},N=new a,L=function(e,t){this._unusedIndexes=[],this._polylineCollection=new h,this._scene=e,this._referenceFrame=t,e.primitives.add(this._polylineCollection)};L.prototype.update=function(e){if(this._referenceFrame===l.INERTIAL){var i=c.computeIcrfToFixedMatrix(e,N);r(i)||(i=c.computeTemeToPseudoFixedMatrix(e,N)),s.fromRotationTranslation(i,t.ZERO,this._polylineCollection.modelMatrix)}},L.prototype.updateObject=function(e,t){var i,n,a=t.entity,s=a._path,l=a._position,u=s._show,c=t.polyline,h=a.isShowing&&(!r(u)||u.getValue(e));if(h){var d=v.getValueOrUndefined(s._leadTime,e),p=v.getValueOrUndefined(s._trailTime,e),m=a._availability,_=r(m),g=r(d),y=r(p);if(h=_||g&&y){if(y&&(i=o.addSeconds(e,-p,new o)),g&&(n=o.addSeconds(e,d,new o)),_){var C=m.start,E=m.stop;(!y||o.greaterThan(C,i))&&(i=C),(!g||o.lessThan(E,n))&&(n=E)}h=o.lessThan(i,n)}}if(!h)return void(r(c)&&(this._unusedIndexes.push(t.index),t.polyline=void 0,c.show=!1,t.index=void 0));if(!r(c)){var S=this._unusedIndexes,w=S.length;if(w>0){var T=S.pop();c=this._polylineCollection.get(T),t.index=T}else t.index=this._polylineCollection.length,c=this._polylineCollection.add();c.id=a,t.polyline=c}var b=v.getValueOrDefault(s._resolution,e,A);c.show=!0,c.positions=P(l,i,n,e,this._referenceFrame,b,c.positions),c.material=f.getValue(e,s._material,c.material),c.width=v.getValueOrDefault(s._width,e,I)},L.prototype.removeObject=function(e){var t=e.polyline;r(t)&&(this._unusedIndexes.push(e.index),e.polyline=void 0,t.show=!1,e.index=void 0)},L.prototype.destroy=function(){return this._scene.primitives.remove(this._polylineCollection),i(this)};var F=function(t,r){r.collectionChanged.addEventListener(F.prototype._onCollectionChanged,this),this._scene=t,this._updaters={},this._entityCollection=r,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return F.prototype.update=function(e){var t=this._updaters;for(var i in t)t.hasOwnProperty(i)&&t[i].update(e);for(var n=this._items.values,o=0,a=n.length;a>o;o++){var s=n[o],u=s.entity,c=u._position,h=s.updater,p=l.FIXED;this._scene.mode===d.SCENE3D&&(p=c.referenceFrame);var m=this._updaters[p];h===m&&r(m)?m.updateObject(e,s):(r(h)&&h.removeObject(s),r(m)||(m=new L(this._scene,p),m.update(e),this._updaters[p]=m),s.updater=m,r(m)&&m.updateObject(e,s))}return!0},F.prototype.isDestroyed=function(){return!1},F.prototype.destroy=function(){this._entityCollection.collectionChanged.removeEventListener(F.prototype._onCollectionChanged,this);var e=this._updaters;for(var t in e)e.hasOwnProperty(t)&&e[t].destroy();return i(this)},F.prototype._onCollectionChanged=function(e,t,i,n){var o,a,s,l=this._items;for(o=t.length-1;o>-1;o--)a=t[o],r(a._path)&&r(a._position)&&l.set(a.id,new O(a));for(o=n.length-1;o>-1;o--)a=n[o],r(a._path)&&r(a._position)?l.contains(a.id)||l.set(a.id,new O(a)):(s=l.get(a.id),r(s)&&(s.updater.removeObject(s),l.remove(a.id)));for(o=i.length-1;o>-1;o--)a=i[o],s=l.get(a.id),r(s)&&(s.updater.removeObject(s),l.remove(a.id))},F._subSample=P,F}),r("Shaders/PointPrimitiveCollectionFS",[],function(){"use strict";return"varying vec4 v_color;\nvarying vec4 v_outlineColor;\nvarying float v_innerPercent;\nvarying float v_pixelDistance;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#endif\nvoid main()\n{\nfloat distanceToCenter = length(gl_PointCoord - vec2(0.5));\nfloat maxDistance = max(0.0, 0.5 - v_pixelDistance);\nfloat wholeAlpha = 1.0 - smoothstep(maxDistance, 0.5, distanceToCenter);\nfloat innerAlpha = 1.0 - smoothstep(maxDistance * v_innerPercent, 0.5 * v_innerPercent, distanceToCenter);\nvec4 color = mix(v_outlineColor, v_color, innerAlpha);\ncolor.a *= wholeAlpha;\nif (color.a < 0.005)\n{\ndiscard;\n}\n#ifdef RENDER_FOR_PICK\ngl_FragColor = v_pickColor;\n#else\ngl_FragColor = color;\n#endif\n}\n"}),r("Shaders/PointPrimitiveCollectionVS",[],function(){"use strict";return"uniform float u_maxTotalPointSize;\nattribute vec4 positionHighAndSize;\nattribute vec4 positionLowAndOutline;\nattribute vec4 compressedAttribute0;\nattribute vec4 compressedAttribute1;\nattribute vec4 scaleByDistance;\nvarying vec4 v_color;\nvarying vec4 v_outlineColor;\nvarying float v_innerPercent;\nvarying float v_pixelDistance;\n#ifdef RENDER_FOR_PICK\nvarying vec4 v_pickColor;\n#endif\nconst float SHIFT_LEFT8 = 256.0;\nconst float SHIFT_RIGHT8 = 1.0 / 256.0;\nvoid main()\n{\nvec3 positionHigh = positionHighAndSize.xyz;\nvec3 positionLow = positionLowAndOutline.xyz;\nfloat outlineWidthBothSides = 2.0 * positionLowAndOutline.w;\nfloat totalSize = positionHighAndSize.w + outlineWidthBothSides;\nfloat outlinePercent = outlineWidthBothSides / totalSize;\ntotalSize *= czm_resolutionScale;\ntotalSize += 3.0;\nfloat temp = compressedAttribute1.x * SHIFT_RIGHT8;\nfloat show = floor(temp);\n#ifdef EYE_DISTANCE_TRANSLUCENCY\nvec4 translucencyByDistance;\ntranslucencyByDistance.x = compressedAttribute1.z;\ntranslucencyByDistance.z = compressedAttribute1.w;\ntranslucencyByDistance.y = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\ntemp = compressedAttribute1.y * SHIFT_RIGHT8;\ntranslucencyByDistance.w = ((temp - floor(temp)) * SHIFT_LEFT8) / 255.0;\n#endif\nvec4 color;\nvec4 outlineColor;\n#ifdef RENDER_FOR_PICK\ncolor = vec4(0.0);\noutlineColor = vec4(0.0);\nvec4 pickColor;\ntemp = compressedAttribute0.z * SHIFT_RIGHT8;\npickColor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\npickColor.g = (temp - floor(temp)) * SHIFT_LEFT8;\npickColor.r = floor(temp);\n#else\ntemp = compressedAttribute0.x * SHIFT_RIGHT8;\ncolor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\ncolor.g = (temp - floor(temp)) * SHIFT_LEFT8;\ncolor.r = floor(temp);\ntemp = compressedAttribute0.y * SHIFT_RIGHT8;\noutlineColor.b = (temp - floor(temp)) * SHIFT_LEFT8;\ntemp = floor(temp) * SHIFT_RIGHT8;\noutlineColor.g = (temp - floor(temp)) * SHIFT_LEFT8;\noutlineColor.r = floor(temp);\n#endif\ntemp = compressedAttribute0.w * SHIFT_RIGHT8;\n#ifdef RENDER_FOR_PICK\npickColor.a = (temp - floor(temp)) * SHIFT_LEFT8;\npickColor = pickColor / 255.0;\n#endif\ntemp = floor(temp) * SHIFT_RIGHT8;\noutlineColor.a = (temp - floor(temp)) * SHIFT_LEFT8;\noutlineColor /= 255.0;\ncolor.a = floor(temp);\ncolor /= 255.0;\nvec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\nvec4 positionEC = czm_modelViewRelativeToEye * p;\npositionEC.xyz *= show;\n#if defined(EYE_DISTANCE_SCALING) || defined(EYE_DISTANCE_TRANSLUCENCY)\nfloat lengthSq;\nif (czm_sceneMode == czm_sceneMode2D)\n{\nlengthSq = czm_eyeHeight2D.y;\n}\nelse\n{\nlengthSq = dot(positionEC.xyz, positionEC.xyz);\n}\n#endif\n#ifdef EYE_DISTANCE_SCALING\ntotalSize *= czm_nearFarScalar(scaleByDistance, lengthSq);\n#endif\ntotalSize = min(totalSize, u_maxTotalPointSize);\nif (totalSize < 1.0)\n{\npositionEC.xyz = vec3(0.0);\ntotalSize = 1.0;\n}\nfloat translucency = 1.0;\n#ifdef EYE_DISTANCE_TRANSLUCENCY\ntranslucency = czm_nearFarScalar(translucencyByDistance, lengthSq);\nif (translucency < 0.004)\n{\npositionEC.xyz = vec3(0.0);\n}\n#endif\nvec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\ngl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0);\nv_color = color;\nv_color.a *= translucency;\nv_outlineColor = outlineColor;\nv_outlineColor.a *= translucency;\nv_innerPercent = 1.0 - outlinePercent;\nv_pixelDistance = 2.0 / totalSize;\ngl_PointSize = totalSize;\n#ifdef RENDER_FOR_PICK\nv_pickColor = pickColor;\n#endif\n}\n"}),r("Scene/PointPrimitive",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Matrix4","../Core/NearFarScalar","./SceneMode","./SceneTransforms"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";function d(e,t){var r=e._pointPrimitiveCollection;o(r)&&(r._updatePointPrimitive(e,t),e._dirty=!0)}var p=function(e,r){e=n(e,n.EMPTY_OBJECT),this._show=n(e.show,!0),this._position=t.clone(n(e.position,t.ZERO)),this._actualPosition=t.clone(this._position),this._color=i.clone(n(e.color,i.WHITE)),this._outlineColor=i.clone(n(e.outlineColor,i.TRANSPARENT)),this._outlineWidth=n(e.outlineWidth,0),this._pixelSize=n(e.pixelSize,10),this._scaleByDistance=e.scaleByDistance,this._translucencyByDistance=e.translucencyByDistance,this._id=e.id,this._collection=n(e.collection,r),this._pickId=void 0,this._pointPrimitiveCollection=r,this._dirty=!1,this._index=-1},m=p.SHOW_INDEX=0,f=p.POSITION_INDEX=1,v=p.COLOR_INDEX=2,_=p.OUTLINE_COLOR_INDEX=3,g=p.OUTLINE_WIDTH_INDEX=4,y=p.PIXEL_SIZE_INDEX=5,C=p.SCALE_BY_DISTANCE_INDEX=6,E=p.TRANSLUCENCY_BY_DISTANCE_INDEX=7;p.NUMBER_OF_PROPERTIES=8,a(p.prototype,{show:{get:function(){return this._show},set:function(e){this._show!==e&&(this._show=e,d(this,m))}},position:{get:function(){return this._position},set:function(e){var r=this._position;t.equals(r,e)||(t.clone(e,r),t.clone(e,this._actualPosition),d(this,f))}},scaleByDistance:{get:function(){return this._scaleByDistance},set:function(e){var t=this._scaleByDistance;u.equals(t,e)||(this._scaleByDistance=u.clone(e,t),d(this,C))}},translucencyByDistance:{get:function(){return this._translucencyByDistance},set:function(e){var t=this._translucencyByDistance;u.equals(t,e)||(this._translucencyByDistance=u.clone(e,t),d(this,E))}},pixelSize:{get:function(){return this._pixelSize},set:function(e){this._pixelSize!==e&&(this._pixelSize=e,d(this,y))}},color:{get:function(){return this._color},set:function(e){var t=this._color;i.equals(t,e)||(i.clone(e,t),d(this,v))}},outlineColor:{get:function(){return this._outlineColor},set:function(e){var t=this._outlineColor;i.equals(t,e)||(i.clone(e,t),d(this,_))}},outlineWidth:{get:function(){return this._outlineWidth},set:function(e){this._outlineWidth!==e&&(this._outlineWidth=e,d(this,g))}},id:{get:function(){return this._id},set:function(e){this._id=e,o(this._pickId)&&(this._pickId.object.id=e)}}}),p.prototype.getPickId=function(e){return o(this._pickId)||(this._pickId=e.createPickId({primitive:this,collection:this._collection,id:this._id})),this._pickId},p.prototype._getActualPosition=function(){return this._actualPosition},p.prototype._setActualPosition=function(e){t.clone(e,this._actualPosition),d(this,f)};var S=new r;p._computeActualPosition=function(e,t,r){return t.mode===c.SCENE3D?e:(l.multiplyByPoint(r,e,S),h.computeActualWgs84Position(t,S))};var w=new l,T=new r;return p._computeScreenSpacePosition=function(e,t,i,n){var o=i.camera,a=o.viewMatrix,s=o.frustum.projectionMatrix,u=l.multiplyTransformation(a,e,w),c=l.multiplyByVector(u,r.fromElements(t.x,t.y,t.z,1,T),T),d=l.multiplyByVector(s,c,T),p=h.clipToGLWindowCoordinates(i,d,n);return p},p.prototype.computeScreenSpacePosition=function(t,r){var i=this._pointPrimitiveCollection;o(r)||(r=new e);var n=i.modelMatrix,a=p._computeScreenSpacePosition(n,this._actualPosition,t,r);return a.y=t.canvas.clientHeight-a.y,a},p.prototype.equals=function(e){return this===e||o(e)&&this._id===e._id&&t.equals(this._position,e._position)&&i.equals(this._color,e._color)&&this._pixelSize===e._pixelSize&&this._outlineWidth===e._outlineWidth&&this._show===e._show&&i.equals(this._outlineColor,e._outlineColor)&&u.equals(this._scaleByDistance,e._scaleByDistance)&&u.equals(this._translucencyByDistance,e._translucencyByDistance)},p.prototype._destroy=function(){this._pickId=this._pickId&&this._pickId.destroy(),this._pointPrimitiveCollection=void 0},p}),r("Scene/PointPrimitiveCollection",["../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EncodedCartesian3","../Core/Math","../Core/Matrix4","../Core/PrimitiveType","../Renderer/BufferUsage","../Renderer/ContextLimits","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArrayFacade","../Shaders/PointPrimitiveCollectionFS","../Shaders/PointPrimitiveCollectionVS","./BlendingState","./Pass","./PointPrimitive","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x){"use strict";function P(e){for(var t=e.length,r=0;t>r;++r)e[r]&&e[r]._destroy()}function A(e){if(e._pointPrimitivesRemoved){e._pointPrimitivesRemoved=!1;for(var t=[],r=e._pointPrimitives,i=r.length,n=0,o=0;i>n;++n){var a=r[n];a&&(a._index=o++,t.push(a))}e._pointPrimitives=t}}function I(e,t,r){return new C(e,[{index:Y.positionHighAndSize,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[z]},{index:Y.positionLowAndShow,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[z]},{index:Y.compressedAttribute0,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[k]},{index:Y.compressedAttribute1,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[q]},{index:Y.scaleByDistance,componentsPerAttribute:4,componentDatatype:n.FLOAT,usage:r[H]}],t)}function M(t,r,i,n){var o=n._index,a=n._getActualPosition();t._mode===x.SCENE3D&&(e.expand(t._baseVolume,a,t._baseVolume),t._boundingVolumeDirty=!0),c.fromCartesian(a,Z);var s=n.pixelSize,l=n.outlineWidth;t._maxPixelSize=Math.max(t._maxPixelSize,s+l);var u=i[Y.positionHighAndSize],h=Z.high;u(o,h.x,h.y,h.z,s);var d=i[Y.positionLowAndOutline],p=Z.low;d(o,p.x,p.y,p.z,l)}function D(e,t,r,n){var o=n._index,a=n.color,s=n.getPickId(t).color,l=n.outlineColor,u=i.floatToByte(a.red),c=i.floatToByte(a.green),h=i.floatToByte(a.blue),d=u*K+c*J+h;u=i.floatToByte(l.red),c=i.floatToByte(l.green),h=i.floatToByte(l.blue);var p=u*K+c*J+h;u=i.floatToByte(s.red),c=i.floatToByte(s.green),h=i.floatToByte(s.blue);var m=u*K+c*J+h,f=i.floatToByte(a.alpha)*K+i.floatToByte(l.alpha)*J+i.floatToByte(s.alpha),v=r[Y.compressedAttribute0];v(o,d,p,m,f)}function R(e,t,r,i){var n=i._index,o=0,s=1,l=1,u=1,c=i.translucencyByDistance;a(c)&&(o=c.near,s=c.nearValue,l=c.far,u=c.farValue,(1!==s||1!==u)&&(e._shaderTranslucencyByDistance=!0));var d=i.show;0===i.color.alpha&&0===i.outlineColor.alpha&&(d=!1),s=h.clamp(s,0,1),s=1===s?255:255*s|0;var p=(d?1:0)*J+s;u=h.clamp(u,0,1),u=1===u?255:255*u|0;var m=u,f=r[Y.compressedAttribute1];f(n,p,m,o,l)}function O(e,t,r,i){var n=i._index,o=r[Y.scaleByDistance],s=0,l=1,u=1,c=1,h=i.scaleByDistance;a(h)&&(s=h.near,l=h.nearValue,u=h.far,c=h.farValue,(1!==l||1!==c)&&(e._shaderScaleByDistance=!0)),o(n,s,l,u,c)}function N(e,t,r,i){M(e,t,r,i),D(e,t,r,i),R(e,t,r,i),O(e,t,r,i)}function L(t,r,i,n,o,s){var l;n.mode===x.SCENE3D?(l=t._baseVolume,t._boundingVolumeDirty=!0):l=t._baseVolume2D;for(var u=[],c=0;i>c;++c){var h=r[c],d=h.position,p=b._computeActualPosition(d,n,o);a(p)&&(h._setActualPosition(p),s?u.push(p):e.expand(l,p,l))}s&&e.fromPoints(u,l)}function F(e,t){var r=t.mode,i=e._pointPrimitives,n=e._pointPrimitivesToUpdate,o=e._modelMatrix;e._createVertexArray||e._mode!==r||r!==x.SCENE3D&&!d.equals(o,e.modelMatrix)?(e._mode=r,d.clone(e.modelMatrix,o),e._createVertexArray=!0,(r===x.SCENE3D||r===x.SCENE2D||r===x.COLUMBUS_VIEW)&&L(e,i,i.length,t,o,!0)):r===x.MORPHING?L(e,i,i.length,t,o,!0):(r===x.SCENE2D||r===x.COLUMBUS_VIEW)&&L(e,n,e._pointPrimitivesToUpdateIndex,t,o,!1)}function B(e,t,i){var n=t.camera,o=n.frustum,a=r.subtract(n.positionWC,i.center,$),s=r.multiplyByScalar(n.directionWC,r.dot(a,n.directionWC),ee),l=Math.max(0,r.magnitude(s)-i.radius),u=t.context,c=o.getPixelDimensions(u.drawingBufferWidth,u.drawingBufferHeight,l,Q),h=Math.max(c.x,c.y),d=h*e._maxPixelSize;i.radius+=d}var V=b.SHOW_INDEX,z=b.POSITION_INDEX,k=b.COLOR_INDEX,U=b.OUTLINE_COLOR_INDEX,G=b.OUTLINE_WIDTH_INDEX,W=b.PIXEL_SIZE_INDEX,H=b.SCALE_BY_DISTANCE_INDEX,q=b.TRANSLUCENCY_BY_DISTANCE_INDEX,j=b.NUMBER_OF_PROPERTIES,Y={positionHighAndSize:0,positionLowAndOutline:1,compressedAttribute0:2,compressedAttribute1:3,scaleByDistance:4},X=function(t){t=o(t,o.EMPTY_OBJECT),this._sp=void 0,this._rs=void 0,this._vaf=void 0,this._spPick=void 0,this._pointPrimitives=[],this._pointPrimitivesToUpdate=[],this._pointPrimitivesToUpdateIndex=0,this._pointPrimitivesRemoved=!1,this._createVertexArray=!1,this._shaderScaleByDistance=!1,this._compiledShaderScaleByDistance=!1,this._compiledShaderScaleByDistancePick=!1,this._shaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistance=!1,this._compiledShaderTranslucencyByDistancePick=!1,this._propertiesChanged=new Uint32Array(j),this._maxPixelSize=1,this._baseVolume=new e,this._baseVolumeWC=new e,this._baseVolume2D=new e,this._boundingVolume=new e,this._boundingVolumeDirty=!1,this._colorCommands=[],this._pickCommands=[],this.modelMatrix=d.clone(o(t.modelMatrix,d.IDENTITY)),this._modelMatrix=d.clone(d.IDENTITY),this.debugShowBoundingVolume=o(t.debugShowBoundingVolume,!1),this._mode=x.SCENE3D,this._maxTotalPointSize=1,this._buffersUsage=[m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW,m.STATIC_DRAW];var r=this;this._uniforms={u_maxTotalPointSize:function(){return r._maxTotalPointSize}}};s(X.prototype,{length:{get:function(){return A(this),this._pointPrimitives.length}}}),X.prototype.add=function(e){var t=new b(e,this);return t._index=this._pointPrimitives.length,this._pointPrimitives.push(t),this._createVertexArray=!0,t},X.prototype.remove=function(e){return this.contains(e)?(this._pointPrimitives[e._index]=null,this._pointPrimitivesRemoved=!0,this._createVertexArray=!0,e._destroy(),!0):!1},X.prototype.removeAll=function(){P(this._pointPrimitives),this._pointPrimitives=[],this._pointPrimitivesToUpdate=[],this._pointPrimitivesToUpdateIndex=0,this._pointPrimitivesRemoved=!1,this._createVertexArray=!0},X.prototype._updatePointPrimitive=function(e,t){e._dirty||(this._pointPrimitivesToUpdate[this._pointPrimitivesToUpdateIndex++]=e),++this._propertiesChanged[t]},X.prototype.contains=function(e){return a(e)&&e._pointPrimitiveCollection===this},X.prototype.get=function(e){return A(this),this._pointPrimitives[e]},X.prototype.computeNewBuffersUsage=function(){for(var e=this._buffersUsage,t=!1,r=this._propertiesChanged,i=0;j>i;++i){var n=0===r[i]?m.STATIC_DRAW:m.STREAM_DRAW;t=t||e[i]!==n,e[i]=n}return t};var Z=new c,K=65536,J=256,Q=new t,$=new r,ee=new r,te=[];return X.prototype.update=function(t){A(this),this._maxTotalPointSize=f.maximumAliasedPointSize,F(this,t);var r,i=this._pointPrimitives,n=i.length,o=this._pointPrimitivesToUpdate,s=this._pointPrimitivesToUpdateIndex,l=this._propertiesChanged,u=this._createVertexArray,c=t.context,h=t.passes,m=h.pick;if(u||!m&&this.computeNewBuffersUsage()){this._createVertexArray=!1;for(var C=0;j>C;++C)l[C]=0;if(this._vaf=this._vaf&&this._vaf.destroy(),n>0){this._vaf=I(c,n,this._buffersUsage),r=this._vaf.writers;for(var b=0;n>b;++b){var P=this._pointPrimitives[b];P._dirty=!1,N(this,c,r,P)}this._vaf.commit()}this._pointPrimitivesToUpdateIndex=0}else if(s>0){var L=te;L.length=0,(l[z]||l[G]||l[W])&&L.push(M),(l[k]||l[U])&&L.push(D),(l[V]||l[q])&&L.push(R),l[H]&&L.push(O);var X=L.length;if(r=this._vaf.writers,s/n>.1){for(var Z=0;s>Z;++Z){var K=o[Z];K._dirty=!1;for(var J=0;X>J;++J)L[J](this,c,r,K)}this._vaf.commit()}else{for(var Q=0;s>Q;++Q){var $=o[Q];$._dirty=!1;for(var ee=0;X>ee;++ee)L[ee](this,c,r,$);this._vaf.subCommit($._index,1)}this._vaf.endSubCommits()}this._pointPrimitivesToUpdateIndex=0}if(s>1.5*n&&(o.length=n),a(this._vaf)&&a(this._vaf.va)){this._boundingVolumeDirty&&(this._boundingVolumeDirty=!1,e.transform(this._baseVolume,this.modelMatrix,this._baseVolumeWC));var re,ie=d.IDENTITY;t.mode===x.SCENE3D?(ie=this.modelMatrix,re=e.clone(this._baseVolumeWC,this._boundingVolume)):re=e.clone(this._baseVolume2D,this._boundingVolume),B(this,t,re);var ne,oe,ae,se,le,ue,ce=t.commandList;if(h.render){var he=this._colorCommands;for(a(this._rs)||(this._rs=_.fromCache({depthTest:{enabled:!0},blending:w.ALPHA_BLEND})),(!a(this._sp)||this._shaderScaleByDistance&&!this._compiledShaderScaleByDistance||this._shaderTranslucencyByDistance&&!this._compiledShaderTranslucencyByDistance)&&(le=new y({sources:[S]}),this._shaderScaleByDistance&&le.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&le.defines.push("EYE_DISTANCE_TRANSLUCENCY"),this._sp=g.replaceCache({context:c,shaderProgram:this._sp,vertexShaderSource:le,fragmentShaderSource:E,attributeLocations:Y}),this._compiledShaderScaleByDistance=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistance=this._shaderTranslucencyByDistance),ne=this._vaf.va,oe=ne.length,he.length=oe,se=0;oe>se;++se)ae=he[se],a(ae)||(ae=he[se]=new v({primitiveType:p.POINTS,pass:T.OPAQUE,owner:this})),ae.boundingVolume=re,ae.modelMatrix=ie,ae.shaderProgram=this._sp,ae.uniformMap=this._uniforms,ae.vertexArray=ne[se].va,ae.renderState=this._rs,ae.debugShowBoundingVolume=this.debugShowBoundingVolume,ce.push(ae)}if(m){var de=this._pickCommands;for((!a(this._spPick)||this._shaderScaleByDistance&&!this._compiledShaderScaleByDistancePick||this._shaderTranslucencyByDistance&&!this._compiledShaderTranslucencyByDistancePick)&&(le=new y({defines:["RENDER_FOR_PICK"],sources:[S]}),this._shaderScaleByDistance&&le.defines.push("EYE_DISTANCE_SCALING"),this._shaderTranslucencyByDistance&&le.defines.push("EYE_DISTANCE_TRANSLUCENCY"),ue=new y({defines:["RENDER_FOR_PICK"],sources:[E]}),this._spPick=g.replaceCache({context:c,shaderProgram:this._spPick,vertexShaderSource:le,fragmentShaderSource:ue,attributeLocations:Y}),this._compiledShaderScaleByDistancePick=this._shaderScaleByDistance,this._compiledShaderTranslucencyByDistancePick=this._shaderTranslucencyByDistance),ne=this._vaf.va,oe=ne.length,de.length=oe,se=0;oe>se;++se)ae=de[se],a(ae)||(ae=de[se]=new v({primitiveType:p.POINTS,pass:T.OPAQUE,owner:this})),ae.boundingVolume=re,ae.modelMatrix=ie,ae.shaderProgram=this._spPick,ae.uniformMap=this._uniforms,ae.vertexArray=ne[se].va,ae.renderState=this._rs,ce.push(ae)}}},X.prototype.isDestroyed=function(){return!1},X.prototype.destroy=function(){return this._sp=this._sp&&this._sp.destroy(),this._spPick=this._spPick&&this._spPick.destroy(),this._vaf=this._vaf&&this._vaf.destroy(),P(this._pointPrimitives),l(this)},X}),r("DataSources/PointVisualizer",["../Core/AssociativeArray","../Core/Cartesian3","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/NearFarScalar","../Scene/PointPrimitiveCollection","./BoundingSphereState","./Property"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){if(i(e)){var r=e.pointPrimitive;i(r)&&(e.pointPrimitive=void 0,r.show=!1,t.push(r._index))}}var h=r.WHITE,d=r.BLACK,p=0,m=1,f=new r,v=new t,_=new r,g=new a,y=new a,C=function(e){this.entity=e,this.pointPrimitive=void 0,this.color=void 0,this.outlineColor=void 0,this.pixelSize=void 0,this.outlineWidth=void 0},E=function(t,r){r.collectionChanged.addEventListener(E.prototype._onCollectionChanged,this),this._scene=t,this._unusedIndexes=[],this._entityCollection=r,this._pointPrimitiveCollection=void 0,this._items=new e,this._onCollectionChanged(r,r.values,[],[])};return E.prototype.update=function(e){for(var t=this._items.values,r=this._unusedIndexes,n=0,o=t.length;o>n;n++){var a=t[n],l=a.entity,C=l._point,E=a.pointPrimitive,S=l.isShowing&&l.isAvailable(e)&&u.getValueOrDefault(C._show,e,!0);if(S&&(v=u.getValueOrUndefined(l._position,e,v),S=i(v)),S){if(!i(E)){var w=this._pointPrimitiveCollection;i(w)||(w=new s,this._pointPrimitiveCollection=w,this._scene.primitives.add(w));var T=r.length;E=T>0?w.get(r.pop()):w.add(),E.id=l,a.pointPrimitive=E}E.show=!0,E.position=v,E.scaleByDistance=u.getValueOrUndefined(C._scaleByDistance,e,g),E.translucencyByDistance=u.getValueOrUndefined(C._translucencyByDistance,e,y),E.color=u.getValueOrDefault(C._color,e,h,f),E.outlineColor=u.getValueOrDefault(C._outlineColor,e,d,_),E.outlineWidth=u.getValueOrDefault(C._outlineWidth,e,p),E.pixelSize=u.getValueOrDefault(C._pixelSize,e,m)}else c(a,r)}return!0},E.prototype.getBoundingSphere=function(e,r){var n=this._items.get(e.id);return i(n)&&i(n.pointPrimitive)?(r.center=t.clone(n.pointPrimitive.position,r.center),r.radius=0,l.DONE):l.FAILED},E.prototype.isDestroyed=function(){return!1},E.prototype.destroy=function(){return this._entityCollection.collectionChanged.removeEventListener(E.prototype._onCollectionChanged,this),i(this._pointPrimitiveCollection)&&this._scene.primitives.remove(this._pointPrimitiveCollection),n(this)},E.prototype._onCollectionChanged=function(e,t,r,n){var o,a,s=this._unusedIndexes,l=this._items;for(o=t.length-1;o>-1;o--)a=t[o],i(a._point)&&i(a._position)&&l.set(a.id,new C(a));for(o=n.length-1;o>-1;o--)a=n[o],i(a._point)&&i(a._position)?l.contains(a.id)||l.set(a.id,new C(a)):(c(l.get(a.id),s),l.remove(a.id));for(o=r.length-1;o>-1;o--)a=r[o],c(l.get(a.id),s),l.remove(a.id)},E}),r("DataSources/PolygonGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/isArray","../Core/Iso8601","../Core/PolygonGeometry","../Core/PolygonHierarchy","../Core/PolygonOutlineGeometry","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";var w=new g(e.WHITE),T=new y(!0),b=new y(!0),x=new y(!1),P=new y(e.BLACK),A=new e,I=function(e){this.id=e,this.vertexFormat=void 0,this.polygonHierarchy=void 0,this.perPositionHeight=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0,this.stRotation=void 0},M=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(M.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new I(e),this._onEntityPropertyChanged(e,"polygon",e.polygon,void 0)};n(M,{perInstanceColorAppearanceType:{value:v},materialAppearanceType:{value:f}}),n(M.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&S.isConstant(this._showProperty)&&S.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&S.isConstant(this._showProperty)&&S.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),M.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},M.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},M.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new m(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof g){var c=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(c=this._materialProperty.color.getValue(r)),o=t.fromColor(c),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new h(this._options),attributes:n})},M.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=S.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new p(this._options),attributes:{show:new m(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},M.prototype.isDestroyed=function(){return!1},M.prototype.destroy=function(){this._entitySubscription(),o(this)},M.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"polygon"===t){var a=this._entity.polygon;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(c.MINIMUM_VALUE):!0,h=a.outline,p=i(h);if(p&&h.isConstant&&(p=h.getValue(c.MINIMUM_VALUE)),!l&&!p)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var m=a.hierarchy,_=a.show;if(i(_)&&_.isConstant&&!_.getValue(c.MINIMUM_VALUE)||!i(m))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var y=r(a.material,w),C=y instanceof g;this._materialProperty=y,this._fillProperty=r(s,b),this._showProperty=r(_,T),this._showOutlineProperty=r(a.outline,x),this._outlineColorProperty=p?r(a.outlineColor,P):void 0;var E=a.height,A=a.extrudedHeight,I=a.granularity,M=a.stRotation,D=a.outlineWidth,R=a.perPositionHeight;if(this._fillEnabled=l,this._outlineEnabled=p,m.isConstant&&S.isConstant(E)&&S.isConstant(A)&&S.isConstant(I)&&S.isConstant(M)&&S.isConstant(D)&&S.isConstant(R)){var O=this._options;O.vertexFormat=C?v.VERTEX_FORMAT:f.MaterialSupport.TEXTURED.vertexFormat;var N=m.getValue(c.MINIMUM_VALUE);u(N)&&(N=new d(N));var L=i(E)?E.getValue(c.MINIMUM_VALUE):void 0,F=i(A)?A.getValue(c.MINIMUM_VALUE):void 0;O.polygonHierarchy=N,O.height=L,O.extrudedHeight=F,O.granularity=i(I)?I.getValue(c.MINIMUM_VALUE):void 0,O.stRotation=i(M)?M.getValue(c.MINIMUM_VALUE):void 0,O.perPositionHeight=i(R)?R.getValue(c.MINIMUM_VALUE):void 0,this._outlineWidth=i(D)?D.getValue(c.MINIMUM_VALUE):1,this._isClosed=i(F)&&F!==L, -this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},M.prototype.createDynamicUpdater=function(e){return new D(e,this)};var D=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new I(t._entity)};return D.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.polygon;if(a.isShowing&&a.isAvailable(r)&&S.getValueOrDefault(s.show,r,!0)){var c=this._options,m=S.getValueOrUndefined(s.hierarchy,r);if(i(m)){if(u(m)?c.polygonHierarchy=new d(m):c.polygonHierarchy=m,c.height=S.getValueOrUndefined(s.height,r),c.extrudedHeight=S.getValueOrUndefined(s.extrudedHeight,r),c.granularity=S.getValueOrUndefined(s.granularity,r),c.stRotation=S.getValueOrUndefined(s.stRotation,r),c.perPositionHeight=S.getValueOrUndefined(s.perPositionHeight,r),S.getValueOrDefault(s.fill,r,!0)){var g=E.getValue(r,o.fillMaterialProperty,this._material);this._material=g;var y=new f({material:g,translucent:g.isTranslucent(),closed:i(c.extrudedHeight)&&c.extrudedHeight!==c.height});c.vertexFormat=y.vertexFormat,this._primitive=n.add(new _({geometryInstances:new l({id:a,geometry:new h(c)}),appearance:y,asynchronous:!1}))}if(S.getValueOrDefault(s.outline,r,!1)){c.vertexFormat=v.VERTEX_FORMAT;var C=S.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,A),w=S.getValueOrDefault(s.outlineWidth,r,1),T=1!==C.alpha;this._outlinePrimitive=n.add(new _({geometryInstances:new l({id:a,geometry:new p(c),attributes:{color:t.fromColor(C)}}),appearance:new v({flat:!0,translucent:T,renderState:{lineWidth:o._scene.clampLineWidth(w)}}),asynchronous:!1}))}}}},D.prototype.getBoundingSphere=function(e,t){return C(e,this._primitive,this._outlinePrimitive,t)},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},M}),r("Shaders/Appearances/PolylineColorAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 prevPosition3DHigh;\nattribute vec3 prevPosition3DLow;\nattribute vec3 nextPosition3DHigh;\nattribute vec3 nextPosition3DLow;\nattribute vec2 expandAndWidth;\nattribute vec4 color;\nvarying vec4 v_color;\nvoid main()\n{\nfloat expandDir = expandAndWidth.x;\nfloat width = abs(expandAndWidth.y) + 0.5;\nbool usePrev = expandAndWidth.y < 0.0;\nvec4 p = czm_computePosition();\nvec4 prev = czm_computePrevPosition();\nvec4 next = czm_computeNextPosition();\nv_color = color;\nvec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\ngl_Position = czm_viewportOrthographic * positionWC;\n}\n"}),r("Scene/PolylineColorAppearance",["../Core/defaultValue","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/PerInstanceFlatColorAppearanceFS","../Shaders/Appearances/PolylineColorAppearanceVS","../Shaders/PolylineCommon","./Appearance"],function(e,t,r,i,n,o,a){"use strict";var s=o+"\n"+n,l=i,u=function(t){t=e(t,e.EMPTY_OBJECT);var r=e(t.translucent,!0),i=!1,n=u.VERTEX_FORMAT;this.material=void 0,this.translucent=r,this._vertexShaderSource=e(t.vertexShaderSource,s),this._fragmentShaderSource=e(t.fragmentShaderSource,l),this._renderState=a.getDefaultRenderState(r,i,t.renderState),this._closed=i,this._vertexFormat=n};return t(u.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return this._vertexFormat}}}),u.VERTEX_FORMAT=r.POSITION_ONLY,u.prototype.getFragmentShaderSource=a.prototype.getFragmentShaderSource,u.prototype.isTranslucent=a.prototype.isTranslucent,u.prototype.getRenderState=a.prototype.getRenderState,u}),r("Shaders/Appearances/PolylineMaterialAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec3 prevPosition3DHigh;\nattribute vec3 prevPosition3DLow;\nattribute vec3 nextPosition3DHigh;\nattribute vec3 nextPosition3DLow;\nattribute vec2 expandAndWidth;\nattribute vec2 st;\nvarying float v_width;\nvarying vec2 v_st;\nvoid main()\n{\nfloat expandDir = expandAndWidth.x;\nfloat width = abs(expandAndWidth.y) + 0.5;\nbool usePrev = expandAndWidth.y < 0.0;\nvec4 p = czm_computePosition();\nvec4 prev = czm_computePrevPosition();\nvec4 next = czm_computeNextPosition();\nv_width = width;\nv_st = st;\nvec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev);\ngl_Position = czm_viewportOrthographic * positionWC;\n}\n"}),r("Scene/PolylineMaterialAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/PolylineMaterialAppearanceVS","../Shaders/PolylineCommon","../Shaders/PolylineFS","./Appearance","./Material"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=o+"\n"+n,c=a,h=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.translucent,!0),n=!1,o=h.VERTEX_FORMAT;this.material=t(r.material)?r.material:l.fromType(l.ColorType),this.translucent=i,this._vertexShaderSource=e(r.vertexShaderSource,u),this._fragmentShaderSource=e(r.fragmentShaderSource,c),this._renderState=s.getDefaultRenderState(i,n,r.renderState),this._closed=n,this._vertexFormat=o};return r(h.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return this._vertexFormat}}}),h.VERTEX_FORMAT=i.POSITION_AND_ST,h.prototype.getFragmentShaderSource=s.prototype.getFragmentShaderSource,h.prototype.isTranslucent=s.prototype.isTranslucent,h.prototype.getRenderState=s.prototype.getRenderState,h}),r("DataSources/PolylineGeometryUpdater",["../Core/BoundingSphere","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/PolylineGeometry","../Core/PolylinePipeline","../Core/ShowGeometryInstanceAttribute","../Scene/PolylineCollection","../Scene/PolylineColorAppearance","../Scene/PolylineMaterialAppearance","./BoundingSphereState","./ColorMaterialProperty","./ConstantProperty","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";var w={},T=new y(t.WHITE),b=new C(!0),x=function(e){this.id=e,this.vertexFormat=void 0,this.positions=void 0,this.width=void 0,this.followSurface=void 0,this.granularity=void 0},P=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(P.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._geometryChanged=new u,this._showProperty=void 0,this._materialProperty=void 0,this._options=new x(e),this._onEntityPropertyChanged(e,"polyline",e.polyline,void 0)};o(P,{perInstanceColorAppearanceType:{value:v},materialAppearanceType:{value:_}}),o(P.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!n(this._entity.availability)&&S.isConstant(this._showProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{value:!1},hasConstantOutline:{value:!0},outlineColorProperty:{value:void 0},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!1},geometryChanged:{get:function(){return this._geometryChanged}}}),P.prototype.isOutlineVisible=function(e){return!1},P.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)},P.prototype.createFillGeometryInstance=function(e){var i,o,a=this._entity,s=a.isAvailable(e),l=new m(s&&a.isShowing&&this._showProperty.getValue(e));if(this._materialProperty instanceof y){var u=t.WHITE;n(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(u=this._materialProperty.color.getValue(e)),i=r.fromColor(u),o={show:l,color:i}}else o={show:l};return new c({id:a,geometry:new d(this._options),attributes:o})},P.prototype.createOutlineGeometryInstance=function(e){},P.prototype.isDestroyed=function(){return!1},P.prototype.destroy=function(){this._entitySubscription(),a(this)},P.prototype._onEntityPropertyChanged=function(e,t,r,o){if("availability"===t||"polyline"===t){var a=this._entity.polyline;if(!n(a))return void(this._fillEnabled&&(this._fillEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.positions,l=a.show;if(n(l)&&l.isConstant&&!l.getValue(h.MINIMUM_VALUE)||!n(s))return void(this._fillEnabled&&(this._fillEnabled=!1,this._geometryChanged.raiseEvent(this)));var u=i(a.material,T),c=u instanceof y;this._materialProperty=u,this._showProperty=i(l,b),this._fillEnabled=!0;var d=a.width,p=a.followSurface,m=a.granularity;if(s.isConstant&&S.isConstant(d)&&S.isConstant(p)&&S.isConstant(m)){var f=this._options,g=s.getValue(h.MINIMUM_VALUE,f.positions);if(!n(g)||g.length<2)return void(this._fillEnabled&&(this._fillEnabled=!1,this._geometryChanged.raiseEvent(this)));f.vertexFormat=c?v.VERTEX_FORMAT:_.VERTEX_FORMAT,f.positions=g,f.width=n(d)?d.getValue(h.MINIMUM_VALUE):void 0,f.followSurface=n(p)?p.getValue(h.MINIMUM_VALUE):void 0,f.granularity=n(m)?m.getValue(h.MINIMUM_VALUE):void 0,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},P.prototype.createDynamicUpdater=function(e){return new I(e,this)};var A={positions:void 0,granularity:void 0,height:void 0,ellipsoid:void 0},I=function(e,t){var r=t._scene.id,i=w[r];!n(i)||i.isDestroyed()?(i=new f,w[r]=i,e.add(i)):e.contains(i)||e.add(i);var o=i.add();o.id=t._entity,this._line=o,this._primitives=e,this._geometryUpdater=t,this._positions=[],A.ellipsoid=t._scene.globe.ellipsoid};return I.prototype.update=function(e){var t=this._geometryUpdater,r=t._entity,i=r.polyline,o=this._line;if(!r.isShowing||!r.isAvailable(e)||!S.getValueOrDefault(i._show,e,!0))return void(o.show=!1);var a=i.positions,s=S.getValueOrUndefined(a,e,this._positions);if(!n(s)||s.length<2)return void(o.show=!1);var l=S.getValueOrDefault(i._followSurface,e,!0);l&&(A.positions=s,A.granularity=S.getValueOrUndefined(i._granularity,e),A.height=p.extractHeights(s,this._geometryUpdater._scene.globe.ellipsoid),s=p.generateCartesianArc(A)),o.show=!0,o.positions=s,o.material=E.getValue(e,t.fillMaterialProperty,o.material),o.width=S.getValueOrDefault(i._width,e,1)},I.prototype.getBoundingSphere=function(t,r){var i=this._line;return i.show&&i.positions.length>0?(e.fromPoints(i.positions,r),g.DONE):g.FAILED},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._geometryUpdater,t=e._scene.id,r=w[t];r.remove(this._line),0===r.length&&(this._primitives.removeAndDestroy(r),delete w[t]),a(this)},P}),r("DataSources/PolylineVolumeGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/PolylineVolumeGeometry","../Core/PolylineVolumeOutlineGeometry","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.polylinePositions=void 0,this.shapePositions=void 0,this.cornerType=void 0,this.granularity=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"polylineVolume",e.polylineVolume,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{value:!0},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new d(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var h=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(h=this._materialProperty.color.getValue(r)),o=t.fromColor(h),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new c(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new h(this._options),attributes:{show:new d(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"polylineVolume"===t){var a=this._entity.polylineVolume;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(u.MINIMUM_VALUE):!0,c=a.outline,h=i(c);if(h&&c.isConstant&&(h=c.getValue(u.MINIMUM_VALUE)),!l&&!h)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.positions,f=a.shape,_=a.show;if(!i(d)||!i(f)||i(_)&&_.isConstant&&!_.getValue(u.MINIMUM_VALUE))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var g=r(a.material,E),y=g instanceof v;this._materialProperty=g,this._fillProperty=r(s,w),this._showProperty=r(_,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=h?r(a.outlineColor,b):void 0;var x=a.granularity,P=a.outlineWidth,A=a.cornerType;if(this._fillEnabled=l,this._outlineEnabled=h,d.isConstant&&f.isConstant&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)){var I=this._options;I.vertexFormat=y?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,I.polylinePositions=d.getValue(u.MINIMUM_VALUE,I.polylinePositions),I.shapePositions=f.getValue(u.MINIMUM_VALUE,I.shape),I.granularity=i(x)?x.getValue(u.MINIMUM_VALUE):void 0,I.cornerType=i(A)?A.getValue(u.MINIMUM_VALUE):void 0,this._outlineWidth=i(P)?P.getValue(u.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.polylineVolume;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(s.show,r,!0)){var u=this._options,d=C.getValueOrUndefined(s.positions,r,u.polylinePositions),v=C.getValueOrUndefined(s.shape,r);if(i(d)&&i(v)){if(u.polylinePositions=d,u.shapePositions=v,u.granularity=C.getValueOrUndefined(s.granularity,r),u.cornerType=C.getValueOrUndefined(s.cornerType,r),!i(s.fill)||s.fill.getValue(r)){var _=y.getValue(r,o.fillMaterialProperty,this._material);this._material=_;var g=new p({material:_,translucent:_.isTranslucent(),closed:!0});u.vertexFormat=g.vertexFormat,this._primitive=n.add(new f({geometryInstances:new l({id:a,geometry:new c(u)}),appearance:g,asynchronous:!1}))}if(i(s.outline)&&s.outline.getValue(r)){u.vertexFormat=m.VERTEX_FORMAT;var E=C.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,x),S=C.getValueOrDefault(s.outlineWidth,r,1),w=1!==E.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new l({id:a,geometry:new h(u),attributes:{color:t.fromColor(E)}}),appearance:new m({flat:!0,translucent:w,renderState:{lineWidth:o._scene.clampLineWidth(S)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/RectangleGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/RectangleGeometry","../Core/RectangleOutlineGeometry","../Core/ShowGeometryInstanceAttribute","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.rectangle=void 0,this.closeBottom=void 0,this.closeTop=void 0,this.height=void 0,this.extrudedHeight=void 0,this.granularity=void 0,this.stRotation=void 0,this.rotation=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._isClosed=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"rectangle",e.rectangle,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return this._isClosed}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new d(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var h=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(h=this._materialProperty.color.getValue(r)),o=t.fromColor(h),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new c(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new h(this._options),attributes:{show:new d(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"rectangle"===t){var a=this._entity.rectangle;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(u.MINIMUM_VALUE):!0,c=a.outline,h=i(c);if(h&&c.isConstant&&(h=c.getValue(u.MINIMUM_VALUE)),!l&&!h)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.coordinates,f=a.show;if(i(f)&&f.isConstant&&!f.getValue(u.MINIMUM_VALUE)||!i(d))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=r(a.material,E),g=_ instanceof v;this._materialProperty=_,this._fillProperty=r(s,w),this._showProperty=r(f,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=h?r(a.outlineColor,b):void 0;var y=a.height,x=a.extrudedHeight,P=a.granularity,A=a.stRotation,I=a.rotation,M=a.outlineWidth,D=a.closeBottom,R=a.closeTop;if(this._fillEnabled=l,this._outlineEnabled=h,d.isConstant&&C.isConstant(y)&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)&&C.isConstant(I)&&C.isConstant(M)&&C.isConstant(D)&&C.isConstant(R)){var O=this._options;O.vertexFormat=g?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,O.rectangle=d.getValue(u.MINIMUM_VALUE,O.rectangle),O.height=i(y)?y.getValue(u.MINIMUM_VALUE):void 0,O.extrudedHeight=i(x)?x.getValue(u.MINIMUM_VALUE):void 0,O.granularity=i(P)?P.getValue(u.MINIMUM_VALUE):void 0,O.stRotation=i(A)?A.getValue(u.MINIMUM_VALUE):void 0,O.rotation=i(I)?I.getValue(u.MINIMUM_VALUE):void 0,O.closeBottom=i(D)?D.getValue(u.MINIMUM_VALUE):void 0,O.closeTop=i(R)?R.getValue(u.MINIMUM_VALUE):void 0,this._isClosed=i(x)&&i(O.closeTop)&&i(O.closeBottom)&&O.closeTop&&O.closeBottom,this._outlineWidth=i(M)?M.getValue(u.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0,this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.rectangle;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(s.show,r,!0)){var u=this._options,d=C.getValueOrUndefined(s.coordinates,r,u.rectangle);if(i(d)){if(u.rectangle=d,u.height=C.getValueOrUndefined(s.height,r),u.extrudedHeight=C.getValueOrUndefined(s.extrudedHeight,r),u.granularity=C.getValueOrUndefined(s.granularity,r),u.stRotation=C.getValueOrUndefined(s.stRotation,r),u.rotation=C.getValueOrUndefined(s.rotation,r),u.closeBottom=C.getValueOrUndefined(s.closeBottom,r),u.closeTop=C.getValueOrUndefined(s.closeTop,r),C.getValueOrDefault(s.fill,r,!0)){var v=y.getValue(r,o.fillMaterialProperty,this._material);this._material=v;var _=new p({material:v,translucent:v.isTranslucent(),closed:i(u.extrudedHeight)});u.vertexFormat=_.vertexFormat,this._primitive=n.add(new f({geometryInstances:new l({id:a,geometry:new c(u)}),appearance:_,asynchronous:!1}))}if(C.getValueOrDefault(s.outline,r,!1)){u.vertexFormat=m.VERTEX_FORMAT;var g=C.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,x),E=C.getValueOrDefault(s.outlineWidth,r,1),S=1!==g.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new l({id:a,geometry:new h(u),attributes:{color:t.fromColor(g)}}),appearance:new m({flat:!0,translucent:S,renderState:{lineWidth:o._scene.clampLineWidth(E)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/WallGeometryUpdater",["../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/GeometryInstance","../Core/Iso8601","../Core/ShowGeometryInstanceAttribute","../Core/WallGeometry","../Core/WallOutlineGeometry","../Scene/MaterialAppearance","../Scene/PerInstanceColorAppearance","../Scene/Primitive","./ColorMaterialProperty","./ConstantProperty","./dynamicGeometryGetBoundingSphere","./MaterialProperty","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";var E=new v(e.WHITE),S=new _(!0),w=new _(!0),T=new _(!1),b=new _(e.BLACK),x=new e,P=function(e){this.id=e,this.vertexFormat=void 0,this.positions=void 0,this.minimumHeights=void 0,this.maximumHeights=void 0,this.granularity=void 0},A=function(e,t){this._entity=e,this._scene=t,this._entitySubscription=e.definitionChanged.addEventListener(A.prototype._onEntityPropertyChanged,this),this._fillEnabled=!1,this._dynamic=!1,this._outlineEnabled=!1,this._geometryChanged=new s,this._showProperty=void 0,this._materialProperty=void 0,this._hasConstantOutline=!0,this._showOutlineProperty=void 0,this._outlineColorProperty=void 0,this._outlineWidth=1,this._options=new P(e),this._onEntityPropertyChanged(e,"wall",e.wall,void 0)};n(A,{perInstanceColorAppearanceType:{value:m},materialAppearanceType:{value:p}}),n(A.prototype,{entity:{get:function(){return this._entity}},fillEnabled:{get:function(){return this._fillEnabled}},hasConstantFill:{get:function(){return!this._fillEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._fillProperty)}},fillMaterialProperty:{get:function(){return this._materialProperty}},outlineEnabled:{get:function(){return this._outlineEnabled}},hasConstantOutline:{get:function(){return!this._outlineEnabled||!i(this._entity.availability)&&C.isConstant(this._showProperty)&&C.isConstant(this._showOutlineProperty)}},outlineColorProperty:{get:function(){return this._outlineColorProperty}},outlineWidth:{get:function(){return this._outlineWidth}},isDynamic:{get:function(){return this._dynamic}},isClosed:{get:function(){return!1}},geometryChanged:{get:function(){return this._geometryChanged}}}),A.prototype.isOutlineVisible=function(e){var t=this._entity;return this._outlineEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._showOutlineProperty.getValue(e)},A.prototype.isFilled=function(e){var t=this._entity;return this._fillEnabled&&t.isAvailable(e)&&this._showProperty.getValue(e)&&this._fillProperty.getValue(e)},A.prototype.createFillGeometryInstance=function(r){var n,o,a=this._entity,s=a.isAvailable(r),u=new c(s&&a.isShowing&&this._showProperty.getValue(r)&&this._fillProperty.getValue(r));if(this._materialProperty instanceof v){var d=e.WHITE;i(this._materialProperty.color)&&(this._materialProperty.color.isConstant||s)&&(d=this._materialProperty.color.getValue(r)),o=t.fromColor(d),n={show:u,color:o}}else n={show:u};return new l({id:a,geometry:new h(this._options),attributes:n})},A.prototype.createOutlineGeometryInstance=function(r){var i=this._entity,n=i.isAvailable(r),o=C.getValueOrDefault(this._outlineColorProperty,r,e.BLACK);return new l({id:i,geometry:new d(this._options),attributes:{show:new c(n&&i.isShowing&&this._showProperty.getValue(r)&&this._showOutlineProperty.getValue(r)),color:t.fromColor(o)}})},A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){this._entitySubscription(),o(this)},A.prototype._onEntityPropertyChanged=function(e,t,n,o){if("availability"===t||"wall"===t){var a=this._entity.wall;if(!i(a))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var s=a.fill,l=i(s)&&s.isConstant?s.getValue(u.MINIMUM_VALUE):!0,c=a.outline,h=i(c);if(h&&c.isConstant&&(h=c.getValue(u.MINIMUM_VALUE)),!l&&!h)return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var d=a.positions,f=a.show;if(i(f)&&f.isConstant&&!f.getValue(u.MINIMUM_VALUE)||!i(d))return void((this._fillEnabled||this._outlineEnabled)&&(this._fillEnabled=!1,this._outlineEnabled=!1,this._geometryChanged.raiseEvent(this)));var _=r(a.material,E),g=_ instanceof v;this._materialProperty=_,this._fillProperty=r(s,w),this._showProperty=r(f,S),this._showOutlineProperty=r(a.outline,T),this._outlineColorProperty=h?r(a.outlineColor,b):void 0;var y=a.minimumHeights,x=a.maximumHeights,P=a.outlineWidth,A=a.granularity;if(this._fillEnabled=l,this._outlineEnabled=h,d.isConstant&&C.isConstant(y)&&C.isConstant(x)&&C.isConstant(P)&&C.isConstant(A)){var I=this._options;I.vertexFormat=g?m.VERTEX_FORMAT:p.MaterialSupport.TEXTURED.vertexFormat,I.positions=d.getValue(u.MINIMUM_VALUE,I.positions),I.minimumHeights=i(y)?y.getValue(u.MINIMUM_VALUE,I.minimumHeights):void 0,I.maximumHeights=i(x)?x.getValue(u.MINIMUM_VALUE,I.maximumHeights):void 0,I.granularity=i(A)?A.getValue(u.MINIMUM_VALUE):void 0,this._outlineWidth=i(P)?P.getValue(u.MINIMUM_VALUE):1,this._dynamic=!1,this._geometryChanged.raiseEvent(this)}else this._dynamic||(this._dynamic=!0,this._geometryChanged.raiseEvent(this))}},A.prototype.createDynamicUpdater=function(e){return new I(e,this)};var I=function(e,t){this._primitives=e,this._primitive=void 0,this._outlinePrimitive=void 0,this._geometryUpdater=t,this._options=new P(t._entity)};return I.prototype.update=function(r){var n=this._primitives;n.removeAndDestroy(this._primitive),n.removeAndDestroy(this._outlinePrimitive),this._primitive=void 0, -this._outlinePrimitive=void 0;var o=this._geometryUpdater,a=o._entity,s=a.wall;if(a.isShowing&&a.isAvailable(r)&&C.getValueOrDefault(s.show,r,!0)){var u=this._options,c=C.getValueOrUndefined(s.positions,r,u.positions);if(i(c)){if(u.positions=c,u.minimumHeights=C.getValueOrUndefined(s.minimumHeights,r,u.minimumHeights),u.maximumHeights=C.getValueOrUndefined(s.maximumHeights,r,u.maximumHeights),u.granularity=C.getValueOrUndefined(s.granularity,r),C.getValueOrDefault(s.fill,r,!0)){var v=y.getValue(r,o.fillMaterialProperty,this._material);this._material=v;var _=new p({material:v,translucent:v.isTranslucent(),closed:i(u.extrudedHeight)});u.vertexFormat=_.vertexFormat,this._primitive=n.add(new f({geometryInstances:new l({id:a,geometry:new h(u)}),appearance:_,asynchronous:!1}))}if(C.getValueOrDefault(s.outline,r,!1)){u.vertexFormat=m.VERTEX_FORMAT;var g=C.getValueOrClonedDefault(s.outlineColor,r,e.BLACK,x),E=C.getValueOrDefault(s.outlineWidth,r,1),S=1!==g.alpha;this._outlinePrimitive=n.add(new f({geometryInstances:new l({id:a,geometry:new d(u),attributes:{color:t.fromColor(g)}}),appearance:new m({flat:!0,translucent:S,renderState:{lineWidth:o._scene.clampLineWidth(E)}}),asynchronous:!1}))}}}},I.prototype.getBoundingSphere=function(e,t){return g(e,this._primitive,this._outlinePrimitive,t)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){var e=this._primitives;e.removeAndDestroy(this._primitive),e.removeAndDestroy(this._outlinePrimitive),o(this)},A}),r("DataSources/DataSourceDisplay",["../Core/BoundingSphere","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EventHelper","./BillboardVisualizer","./BoundingSphereState","./BoxGeometryUpdater","./CorridorGeometryUpdater","./CustomDataSource","./CylinderGeometryUpdater","./EllipseGeometryUpdater","./EllipsoidGeometryUpdater","./GeometryVisualizer","./LabelVisualizer","./ModelVisualizer","./PathVisualizer","./PointVisualizer","./PolygonGeometryUpdater","./PolylineGeometryUpdater","./PolylineVolumeGeometryUpdater","./RectangleGeometryUpdater","./WallGeometryUpdater"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T){"use strict";var b=function(e){var r=e.scene,i=e.dataSourceCollection;this._eventHelper=new a,this._eventHelper.add(i.dataSourceAdded,this._onDataSourceAdded,this),this._eventHelper.add(i.dataSourceRemoved,this._onDataSourceRemoved,this),this._dataSourceCollection=i,this._scene=r,this._visualizersCallback=t(e.visualizersCallback,b.defaultVisualizersCallback);for(var n=0,o=i.length;o>n;n++)this._onDataSourceAdded(i,i.get(n));var s=new h;this._onDataSourceAdded(void 0,s),this._defaultDataSource=s};b.defaultVisualizersCallback=function(e,t){var r=t.entities;return[new s(e,r),new f(u,e,r),new f(d,e,r),new f(c,e,r),new f(p,e,r),new f(m,e,r),new f(C,e,r),new f(E,e,r),new f(S,e,r),new f(w,e,r),new f(T,e,r),new v(e,r),new _(e,r),new y(e,r),new g(e,r)]},i(b.prototype,{scene:{get:function(){return this._scene}},dataSources:{get:function(){return this._dataSourceCollection}},defaultDataSource:{get:function(){return this._defaultDataSource}}}),b.prototype.isDestroyed=function(){return!1},b.prototype.destroy=function(){this._eventHelper.removeAll();for(var e=this._dataSourceCollection,t=0,r=e.length;r>t;++t)this._onDataSourceRemoved(this._dataSourceCollection,e.get(t));return this._onDataSourceRemoved(void 0,this._defaultDataSource),n(this)},b.prototype.update=function(e){var t,i,n,o,a=!0,s=this._dataSourceCollection,l=s.length;for(t=0;l>t;t++){var u=s.get(t);for(r(u.update)&&(a=u.update(e)&&a),n=u._visualizers,o=n.length,i=0;o>i;i++)a=n[i].update(e)&&a}for(n=this._defaultDataSource._visualizers,o=n.length,i=0;o>i;i++)a=n[i].update(e)&&a;return a};var x=[],P=new e;return b.prototype.getBoundingSphere=function(t,i,n){var o,a,s=this._defaultDataSource;if(!s.entities.contains(t)){s=void 0;var u=this._dataSourceCollection;for(a=u.length,o=0;a>o;o++){var c=u.get(o);if(c.entities.contains(t)){s=c;break}}}if(!r(s))return l.FAILED;var h=x,d=P,p=0,m=l.DONE,f=s._visualizers,v=f.length;for(o=0;v>o;o++){var _=f[o];if(r(_.getBoundingSphere)){if(m=f[o].getBoundingSphere(t,d),!i&&m===l.PENDING)return l.PENDING;m===l.DONE&&(h[p]=e.clone(d,h[p]),p++)}}return 0===p?l.FAILED:(h.length=p,e.fromBoundingSpheres(h,n),l.DONE)},b.prototype._onDataSourceAdded=function(e,t){var r=this._visualizersCallback(this._scene,t);t._visualizers=r},b.prototype._onDataSourceRemoved=function(e,t){for(var r=t._visualizers,i=r.length,n=0;i>n;n++)r[n].destroy(),t._visualizers=void 0},b}),r("DataSources/DynamicGeometryUpdater",["../Core/DeveloperError"],function(e){"use strict";var t=function(){e.throwInstantiationError()};return t.prototype.update=e.throwInstantiationError,t.prototype.getBoundingSphere=e.throwInstantiationError,t.prototype.isDestroyed=e.throwInstantiationError,t.prototype.destroy=e.throwInstantiationError,t}),r("DataSources/EntityView",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartesian4","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/HeadingPitchRange","../Core/JulianDate","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Transforms","../Scene/SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,r,i,o,a,s,l){var d=e.scene.mode,f=a.getValue(s,e._lastCartesian);if(n(f)){var A,I,M,D=!1;if(d===m.SCENE3D){x=u.addSeconds(s,.001,x);var R=a.getValue(x,C);if(n(R)){var O,N=p.computeFixedToIcrfMatrix(s,v),L=p.computeFixedToIcrfMatrix(x,_);n(N)&&n(L)?O=h.transpose(N,g):(O=p.computeTemeToPseudoFixedMatrix(s,g),N=h.transpose(O,v),L=p.computeTemeToPseudoFixedMatrix(x,_),h.transpose(L,L));var F=h.multiplyByVector(N,f,T),B=h.multiplyByVector(L,R,b);t.subtract(F,B,w);var V=1e3*t.magnitude(w),z=3986004418e5,k=-z/(V*V-2*z/t.magnitude(F));0>k||k>P*l.maximumRadius?(A=E,t.normalize(f,A),t.negate(A,A),M=t.clone(t.UNIT_Z,S),I=t.cross(M,A,C),t.magnitude(I)>c.EPSILON7&&(t.normalize(A,A),t.normalize(I,I),M=t.cross(A,I,S),t.normalize(M,M),D=!0)):t.equalsEpsilon(f,R,c.EPSILON7)||(M=E,t.normalize(F,M),t.normalize(B,B),I=t.cross(M,B,S),t.equalsEpsilon(I,t.ZERO,c.EPSILON7)||(A=t.cross(I,M,C),h.multiplyByVector(O,A,A),h.multiplyByVector(O,I,I),h.multiplyByVector(O,M,M),t.normalize(A,A),t.normalize(I,I),t.normalize(M,M),D=!0))}}n(e._boundingSphereOffset)&&t.add(e._boundingSphereOffset,f,f);var U,G,W;o&&(U=t.clone(r.position,w),G=t.clone(r.direction,T),W=t.clone(r.up,b));var H=y;D?(H[0]=A.x,H[1]=A.y,H[2]=A.z,H[3]=0,H[4]=I.x,H[5]=I.y,H[6]=I.z,H[7]=0,H[8]=M.x,H[9]=M.y,H[10]=M.z,H[11]=0,H[12]=f.x,H[13]=f.y,H[14]=f.z,H[15]=0):p.eastNorthUpToFixedFrame(f,l,H),r._setTransform(H),o&&(t.clone(U,r.position),t.clone(G,r.direction),t.clone(W,r.up),t.cross(G,W,r.right))}if(i){var q=d===m.SCENE2D||t.equals(e._offset3D,t.ZERO)?void 0:e._offset3D;r.lookAtTransform(r.transform,q)}}var v=new h,_=new h,g=new h,y=new d,C=new t,E=new t,S=new t,w=new t,T=new t,b=new t,x=new u,P=1.25,A=function(r,n,o,a){this.entity=r,this.scene=n,this.ellipsoid=i(o,s.WGS84),this.boundingSphere=e.clone(a),this._boundingSphereOffset=void 0,this._lastEntity=void 0,this._mode=void 0,this._lastCartesian=new t,this._defaultOffset3D=void 0,this._offset3D=new t};o(A,{defaultOffset3D:{get:function(){return this._defaultOffset3D},set:function(e){this._defaultOffset3D=t.clone(e,new t)}}}),A.defaultOffset3D=new t(-14e3,3500,3500);var I=new l,M=new t;return A.prototype.update=function(e){var r=this.scene,i=this.entity,o=this.ellipsoid,a=r.mode;if(a!==m.MORPHING){var s=i.position,l=i!==this._lastEntity,u=a!==this._mode,h=this._offset3D,d=r.camera,p=l||u,v=!0;if(l){var _=i.viewFrom,g=n(_),y=this.boundingSphere;if(this._boundingSphereOffset=void 0,!g&&n(y)){var C=r.screenSpaceCameraController;C.minimumZoomDistance=Math.min(C.minimumZoomDistance,.5*y.radius),I.pitch=-c.PI_OVER_FOUR,I.range=0;var E=s.getValue(e,M);if(n(E)){var S=2-1/Math.max(1,t.magnitude(E)/o.maximumRadius);I.pitch*=S}d.viewBoundingSphere(y,I),this._boundingSphereOffset=t.subtract(y.center,i.position.getValue(e),new t),p=!1,v=!1}else g&&n(_.getValue(e,h))||t.clone(A._defaultOffset3D,h)}else u||r.mode===m.MORPHING||this._mode===m.SCENE2D||t.clone(d.position,h);this._lastEntity=i,this._mode=r.mode!==m.MORPHING?r.mode:this._mode,r.mode!==m.MORPHING&&f(this,d,p,v,s,e,o)}},A}),!function(){function e(e,t){function r(t){var r,i=e.arcs[0>t?~t:t],n=i[0];return e.transform?(r=[0,0],i.forEach(function(e){r[0]+=e[0],r[1]+=e[1]})):r=i[i.length-1],0>t?[r,n]:[n,r]}function i(e,t){for(var r in e){var i=e[r];delete t[i.start],delete i.start,delete i.end,i.forEach(function(e){n[0>e?~e:e]=1}),s.push(i)}}var n={},o={},a={},s=[],l=-1;return t.forEach(function(r,i){var n,o=e.arcs[0>r?~r:r];o.length<3&&!o[1][0]&&!o[1][1]&&(n=t[++l],t[l]=r,t[i]=n)}),t.forEach(function(e){var t,i,n=r(e),s=n[0],l=n[1];if(t=a[s])if(delete a[t.end],t.push(e),t.end=l,i=o[l]){delete o[i.start];var u=i===t?t:t.concat(i);o[u.start=t.start]=a[u.end=i.end]=u}else o[t.start]=a[t.end]=t;else if(t=o[l])if(delete o[t.start],t.unshift(e),t.start=s,i=a[s]){delete a[i.end];var c=i===t?t:i.concat(t);o[c.start=i.start]=a[c.end=t.end]=c}else o[t.start]=a[t.end]=t;else t=[e],o[t.start=s]=a[t.end=l]=t}),i(a,o),i(o,a),t.forEach(function(e){n[0>e?~e:e]||s.push([e])}),s}function t(t,r,i){function n(e){var t=0>e?~e:e;(c[t]||(c[t]=[])).push({i:e,g:u})}function o(e){e.forEach(n)}function a(e){e.forEach(o)}function s(e){"GeometryCollection"===e.type?e.geometries.forEach(s):e.type in h&&(u=e,h[e.type](e.arcs))}var l=[];if(arguments.length>1){var u,c=[],h={LineString:o,MultiLineString:a,Polygon:a,MultiPolygon:function(e){e.forEach(a)}};s(r),c.forEach(arguments.length<3?function(e){l.push(e[0].i)}:function(e){i(e[0].g,e[e.length-1].g)&&l.push(e[0].i)})}else for(var d=0,p=t.arcs.length;p>d;++d)l.push(d);return{type:"MultiLineString",arcs:e(t,l)}}function i(t,r){function i(e){e.forEach(function(t){t.forEach(function(t){(a[t=0>t?~t:t]||(a[t]=[])).push(e)})}),l.push(e)}function o(e){return d(s(t,{type:"Polygon",arcs:[e]}).coordinates[0])>0}var a={},l=[],u=[];return r.forEach(function(e){"Polygon"===e.type?i(e.arcs):"MultiPolygon"===e.type&&e.arcs.forEach(i)}),l.forEach(function(e){if(!e._){var t=[],r=[e];for(e._=1,u.push(t);e=r.pop();)t.push(e),e.forEach(function(e){e.forEach(function(e){a[0>e?~e:e].forEach(function(e){e._||(e._=1,r.push(e))})})})}}),l.forEach(function(e){delete e._}),{type:"MultiPolygon",arcs:u.map(function(r){var i=[];if(r.forEach(function(e){e.forEach(function(e){e.forEach(function(e){a[0>e?~e:e].length<2&&i.push(e)})})}),i=e(t,i),(n=i.length)>1)for(var s,l=o(r[0][0]),u=0;u<n;++u)if(l===o(i[u])){s=i[0],i[0]=i[u],i[u]=s;break}return i})}}function o(e,t){return"GeometryCollection"===t.type?{type:"FeatureCollection",features:t.geometries.map(function(t){return a(e,t)})}:a(e,t)}function a(e,t){var r={type:"Feature",id:t.id,properties:t.properties||{},geometry:s(e,t)};return null==t.id&&delete r.id,r}function s(e,t){function r(e,t){t.length&&t.pop();for(var r,i=c[0>e?~e:e],n=0,o=i.length;o>n;++n)t.push(r=i[n].slice()),u(r,n);0>e&&l(t,o)}function i(e){return e=e.slice(),u(e,0),e}function n(e){for(var t=[],i=0,n=e.length;n>i;++i)r(e[i],t);return t.length<2&&t.push(t[0].slice()),t}function o(e){for(var t=n(e);t.length<4;)t.push(t[0].slice());return t}function a(e){return e.map(o)}function s(e){var t=e.type;return"GeometryCollection"===t?{type:t,geometries:e.geometries.map(s)}:t in h?{type:t,coordinates:h[t](e)}:null}var u=v(e.transform),c=e.arcs,h={Point:function(e){return i(e.coordinates)},MultiPoint:function(e){return e.coordinates.map(i)},LineString:function(e){return n(e.arcs)},MultiLineString:function(e){return e.arcs.map(n)},Polygon:function(e){return a(e.arcs)},MultiPolygon:function(e){return e.arcs.map(a)}};return s(t)}function l(e,t){for(var r,i=e.length,n=i-t;n<--i;)r=e[n],e[n++]=e[i],e[i]=r}function u(e,t){for(var r=0,i=e.length;i>r;){var n=r+i>>>1;e[n]<t?r=n+1:i=n}return r}function c(e){function t(e,t){e.forEach(function(e){0>e&&(e=~e);var r=n[e];r?r.push(t):n[e]=[t]})}function r(e,r){e.forEach(function(e){t(e,r)})}function i(e,t){"GeometryCollection"===e.type?e.geometries.forEach(function(e){i(e,t)}):e.type in a&&a[e.type](e.arcs,t)}var n={},o=e.map(function(){return[]}),a={LineString:t,MultiLineString:r,Polygon:r,MultiPolygon:function(e,t){e.forEach(function(e){r(e,t)})}};e.forEach(i);for(var s in n)for(var l=n[s],c=l.length,h=0;c>h;++h)for(var d=h+1;c>d;++d){var p,m=l[h],f=l[d];(p=o[m])[s=u(p,f)]!==f&&p.splice(s,0,f),(p=o[f])[s=u(p,m)]!==m&&p.splice(s,0,m)}return o}function h(e,t){function r(e){o.remove(e),e[1][2]=t(e),o.push(e)}var i=v(e.transform),n=_(e.transform),o=f();return t||(t=p),e.arcs.forEach(function(e){for(var a,s,l=[],u=0,c=0,h=e.length;h>c;++c)s=e[c],i(e[c]=[s[0],s[1],1/0],c);for(var c=1,h=e.length-1;h>c;++c)a=e.slice(c-1,c+2),a[1][2]=t(a),l.push(a),o.push(a);for(var c=0,h=l.length;h>c;++c)a=l[c],a.previous=l[c-1],a.next=l[c+1];for(;a=o.pop();){var d=a.previous,p=a.next;a[1][2]<u?a[1][2]=u:u=a[1][2],d&&(d.next=p,d[2]=a[2],r(d)),p&&(p.previous=d,p[0]=a[0],r(p))}e.forEach(n)}),e}function d(e){for(var t,r=-1,i=e.length,n=e[i-1],o=0;++r<i;)t=n,n=e[r],o+=t[0]*n[1]-t[1]*n[0];return.5*o}function p(e){var t=e[0],r=e[1],i=e[2];return Math.abs((t[0]-i[0])*(r[1]-t[1])-(t[0]-r[0])*(i[1]-t[1]))}function m(e,t){return e[1][2]-t[1][2]}function f(){function e(e,t){for(;t>0;){var r=(t+1>>1)-1,n=i[r];if(m(e,n)>=0)break;i[n._=t]=n,i[e._=t=r]=e}}function t(e,t){for(;;){var r=t+1<<1,o=r-1,a=t,s=i[a];if(n>o&&m(i[o],s)<0&&(s=i[a=o]),n>r&&m(i[r],s)<0&&(s=i[a=r]),a===t)break;i[s._=t]=s,i[e._=t=a]=e}}var r={},i=[],n=0;return r.push=function(t){return e(i[t._=n]=t,n++),n},r.pop=function(){if(!(0>=n)){var e,r=i[0];return--n>0&&(e=i[n],t(i[e._=0]=e,0)),r}},r.remove=function(r){var o,a=r._;if(i[a]===r)return a!==--n&&(o=i[n],(m(o,r)<0?e:t)(i[o._=a]=o,a)),a},r}function v(e){if(!e)return g;var t,r,i=e.scale[0],n=e.scale[1],o=e.translate[0],a=e.translate[1];return function(e,s){s||(t=r=0),e[0]=(t+=e[0])*i+o,e[1]=(r+=e[1])*n+a}}function _(e){if(!e)return g;var t,r,i=e.scale[0],n=e.scale[1],o=e.translate[0],a=e.translate[1];return function(e,s){s||(t=r=0);var l=(e[0]-o)/i|0,u=(e[1]-a)/n|0;e[0]=l-t,e[1]=u-r,t=l,r=u}}function g(){}var y={version:"1.6.18",mesh:function(e){return s(e,t.apply(this,arguments))},meshArcs:t,merge:function(e){return s(e,i.apply(this,arguments))},mergeArcs:i,feature:o,neighbors:c,presimplify:h};"function"==typeof r&&r.amd?r("ThirdParty/topojson",y):"object"==typeof module&&module.exports?module.exports=y:this.topojson=y}(),r("DataSources/GeoJsonDataSource",["../Core/Cartesian3","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/getFilenameFromUri","../Core/loadJson","../Core/PinBuilder","../Core/PolygonHierarchy","../Core/RuntimeError","../Scene/VerticalOrigin","../ThirdParty/topojson","../ThirdParty/when","./BillboardGraphics","./CallbackProperty","./ColorMaterialProperty","./ConstantPositionProperty","./ConstantProperty","./DataSource","./EntityCollection","./PolygonGraphics","./PolylineGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b){"use strict";function x(t){return e.fromDegrees(t[0],t[1],t[2])}function P(e,t){var r="";for(var i in e)if(e.hasOwnProperty(i)){if(i===t||-1!==oe.indexOf(i))continue;var n=e[i];o(n)&&(r+="object"==typeof n?"<tr><th>"+i+"</th><td>"+P(n)+"</td></tr>":"<tr><th>"+i+"</th><td>"+n+"</td></tr>")}return r.length>0&&(r='<table class="cesium-infoBox-defaultTable"><tbody>'+r+"</tbody></table>"),r}function A(e,t,r){var i;return function(o,a){return n(i)||(i=e(t,r)),i}}function I(e,t){return new g(A(P,e,t),!0)}function M(e,t,i){var a=e.id;if(o(a)&&"Feature"===e.type){for(var s=2,l=a;n(t.getById(l));)l=a+"_"+s,s++;a=l}else a=r();var u=t.getOrCreateEntity(a),c=e.properties;if(o(c)){u.addProperty("properties"),u.properties=c;var h,d=c.title;if(o(d))u.name=d,h="title";else{var p=Number.MAX_VALUE;for(var m in c)if(c.hasOwnProperty(m)&&c[m]){var f=m.toLowerCase();if(p>1&&"title"===f){p=1,h=m;break}p>2&&"name"===f?(p=2,h=m):p>3&&/title/i.test(m)?(p=3,h=m):p>4&&/name/i.test(m)&&(p=4,h=m)}o(h)&&(u.name=c[h])}var v=c.description;n(v)?null!==v&&(u.description=new E(v)):u.description=i(c,h)}return u}function D(e,t){for(var r=new Array(e.length),i=0;i<e.length;i++)r[i]=t(e[i]);return r}function R(e,t,r,i,a){if(!n(t.geometry))throw new p("feature.geometry is required.");if(null===t.geometry)M(t,e._entityCollection,a.describe);else{var s=t.geometry.type,l=le[s];if(!o(l))throw new p("Unknown geometry type: "+s);l(e,t,t.geometry,i,a)}}function O(e,t,r,i,n){for(var o=t.features,a=0,s=o.length;s>a;a++)R(e,o[a],void 0,i,n)}function N(e,t,r,i,n){for(var a=r.geometries,s=0,l=a.length;l>s;s++){var u=a[s],c=u.type,h=le[c];if(!o(h))throw new p("Unknown geometry type: "+c);h(e,t,u,i,n)}}function L(e,r,a,s,l){var u=l.markerSymbol,c=l.markerColor,h=l.markerSize,d=r.properties;if(o(d)){var p=d["marker-color"];o(p)&&(c=t.fromCssColorString(p)),h=i(ne[d["marker-size"]],h);var f=d["marker-symbol"];o(f)&&(u=f)}ae[0]=u,ae[1]=c,ae[2]=h;var g;JSON.stringify(ae);g=n(u)?1===u.length?e._pinBuilder.fromText(u.toUpperCase(),c,h):e._pinBuilder.fromMakiIconId(u,c,h):e._pinBuilder.fromColor(c,h),e._promises.push(v(g,function(t){var i=new _;i.verticalOrigin=new E(m.BOTTOM),i.image=new E(t);var n=M(r,e._entityCollection,l.describe);n.billboard=i,n.position=new C(a(s))}))}function F(e,t,r,i,n){L(e,t,i,r.coordinates,n)}function B(e,t,r,i,n){for(var o=r.coordinates,a=0;a<o.length;a++)L(e,t,i,o[a],n)}function V(e,r,i,a,s){var l=s.strokeMaterialProperty,u=s.strokeWidthProperty,c=r.properties;if(o(c)){var h=c["stroke-width"];o(h)&&(u=new E(h));var d,p=c.stroke;o(p)&&(d=t.fromCssColorString(p));var m=c["stroke-opacity"];o(m)&&1!==m&&(n(d)||(d=l.color.clone()),d.alpha=m),n(d)&&(l=new y(d))}var f=new b;f.material=l,f.width=u,f.positions=new E(D(a,i));var v=M(r,e._entityCollection,s.describe);v.polyline=f}function z(e,t,r,i,n){V(e,t,i,r.coordinates,n)}function k(e,t,r,i,n){for(var o=r.coordinates,a=0;a<o.length;a++)V(e,t,i,o[a],n)}function U(e,r,i,a,s){if(0!==a.length&&0!==a[0].length){var l=s.strokeMaterialProperty.color,u=s.fillMaterialProperty,c=s.strokeWidthProperty,h=r.properties;if(o(h)){var p=h["stroke-width"];o(p)&&(c=new E(p));var m,f=h.stroke;o(f)&&(m=t.fromCssColorString(f));var v=h["stroke-opacity"];o(v)&&1!==v&&(n(m)||(m=s.strokeMaterialProperty.color.clone()),m.alpha=v),n(m)&&(l=new E(m));var _,g=h.fill;o(g)&&(_=t.fromCssColorString(g),_.alpha=u.color.alpha),v=h["fill-opacity"],o(v)&&v!==u.color.alpha&&(n(_)||(_=u.color.clone()),_.alpha=v),n(_)&&(u=new y(_))}var C=new T;C.outline=new E(!0),C.outlineColor=l,C.outlineWidth=c,C.material=u;for(var S=[],w=1,b=a.length;b>w;w++)S.push(new d(D(a[w],i)));var x=a[0];C.hierarchy=new E(new d(D(x,i),S)),x[0].length>2&&(C.perPositionHeight=new E(!0));var P=M(r,e._entityCollection,s.describe);P.polygon=C}}function G(e,t,r,i,n){U(e,t,i,r.coordinates,n)}function W(e,t,r,i,n){for(var o=r.coordinates,a=0;a<o.length;a++)U(e,t,i,o[a],n)}function H(e,t,r,i,n){for(var o in r.objects)if(r.objects.hasOwnProperty(o)){var a=f.feature(r,r.objects[o]),s=se[a.type];s(e,a,a,i,n)}}function q(e,t,r,i){var o;n(i)&&(o=u(i)),n(o)&&e._name!==o&&(e._name=o,e._changed.raiseEvent(e));var a=se[t.type];if(!n(a))throw new p("Unsupported GeoJSON object type: "+t.type);var s=x,l=t.crs;if(n(l)){if(null===l)throw new p("crs is null.");if(!n(l.properties))throw new p("crs.properties is undefined.");var c=l.properties;if("name"===l.type){if(s=Y[c.name],!n(s))throw new p("Unknown crs name: "+c.name)}else if("link"===l.type){var h=X[c.href];if(n(h)||(h=Z[c.type]),!n(h))throw new p("Unable to resolve crs link: "+JSON.stringify(c));s=h(c)}else{if("EPSG"!==l.type)throw new p("Unknown crs type: "+l.type);if(s=Y["EPSG:"+c.code],!n(s))throw new p("Unknown crs EPSG code: "+c.code)}}return v(s,function(i){return e._entityCollection.removeAll(),a(e,t,t,i,r),v.all(e._promises,function(){return e._promises.length=0,S.setLoading(e,!1),e})})}var j,Y={"urn:ogc:def:crs:OGC:1.3:CRS84":x,"EPSG:4326":x},X={},Z={},K=48,J=t.ROYALBLUE,Q=t.YELLOW,$=2,ee=t.fromBytes(255,255,0,100),te=new E($),re=new y(Q),ie=new y(ee),ne={small:24,medium:48,large:64},oe=["title","description","marker-size","marker-symbol","marker-color","stroke","stroke-opacity","stroke-width","fill","fill-opacity"],ae=new Array(4),se={Feature:R,FeatureCollection:O,GeometryCollection:N,LineString:z,MultiLineString:k,MultiPoint:B,MultiPolygon:W,Point:F,Polygon:G,Topology:H},le={GeometryCollection:N,LineString:z,MultiLineString:k,MultiPoint:B,MultiPolygon:W,Point:F,Polygon:G,Topology:H},ue=function(e){this._name=e,this._changed=new l,this._error=new l,this._isLoading=!1,this._loading=new l,this._entityCollection=new w(this),this._promises=[],this._pinBuilder=new h};return ue.load=function(e,t){return(new ue).load(e,t)},a(ue,{markerSize:{get:function(){return K},set:function(e){K=e}},markerSymbol:{get:function(){return j},set:function(e){j=e}},markerColor:{get:function(){return J},set:function(e){J=e}},stroke:{get:function(){return Q},set:function(e){Q=e,re.color.setValue(e)}},strokeWidth:{get:function(){return $},set:function(e){$=e,te.setValue(e)}},fill:{get:function(){return ee},set:function(e){ee=e,ie=new y(ee)}},crsNames:{get:function(){return Y}},crsLinkHrefs:{get:function(){return X}},crsLinkTypes:{get:function(){return Z}}}),a(ue.prototype,{name:{get:function(){return this._name}},clock:{value:void 0,writable:!1},entities:{get:function(){return this._entityCollection}},isLoading:{get:function(){return this._isLoading}},changedEvent:{get:function(){return this._changed}},errorEvent:{get:function(){return this._error}},loadingEvent:{get:function(){return this._loading}}}),ue.prototype.load=function(e,t){S.setLoading(this,!0);var r=e;t=i(t,i.EMPTY_OBJECT);var o=t.sourceUri;"string"==typeof e&&(n(o)||(o=e),r=c(e)),t={describe:i(t.describe,I),markerSize:i(t.markerSize,K),markerSymbol:i(t.markerSymbol,j),markerColor:i(t.markerColor,J),strokeWidthProperty:new E(i(t.strokeWidth,$)),strokeMaterialProperty:new y(i(t.stroke,Q)),fillMaterialProperty:new y(i(t.fill,ee))};var a=this;return v(r,function(e){return q(a,e,t,o)}).otherwise(function(e){return S.setLoading(a,!1),a._error.raiseEvent(a,e),window.console.log(e),v.reject(e)})},ue}),r("DataSources/GeometryUpdater",["../Core/defineProperties","../Core/DeveloperError"],function(e,t){"use strict";var r=function(e,r){t.throwInstantiationError()};return e(r,{perInstanceColorAppearanceType:{get:t.throwInstantiationError},materialAppearanceType:{get:t.throwInstantiationError}}),e(r.prototype,{entity:{get:t.throwInstantiationError},fillEnabled:{get:t.throwInstantiationError},hasConstantFill:{get:t.throwInstantiationError},fillMaterialProperty:{get:t.throwInstantiationError},outlineEnabled:{get:t.throwInstantiationError},hasConstantOutline:{get:t.throwInstantiationError},outlineColorProperty:{get:t.throwInstantiationError},outlineWidth:{get:t.throwInstantiationError},isDynamic:{get:t.throwInstantiationError},isClosed:{get:t.throwInstantiationError},geometryChanged:{get:t.throwInstantiationError}}),r.prototype.isOutlineVisible=t.throwInstantiationError,r.prototype.isFilled=t.throwInstantiationError,r.prototype.createFillGeometryInstance=t.throwInstantiationError,r.prototype.createOutlineGeometryInstance=t.throwInstantiationError,r.prototype.isDestroyed=t.throwInstantiationError,r.prototype.destroy=t.throwInstantiationError,r.prototype.createDynamicUpdater=t.throwInstantiationError,r}),function(e,t){"function"==typeof r&&r.amd?r("ThirdParty/Autolinker",[],function(){return e.Autolinker=t()}):"object"==typeof exports?module.exports=t():e.Autolinker=t()}(this,function(){var e=function(t){e.Util.assign(this,t);var r=this.hashtag;if(r!==!1&&"twitter"!==r&&"facebook"!==r)throw new Error("invalid `hashtag` cfg - see docs")};return e.prototype={constructor:e,urls:!0,email:!0,twitter:!0,phone:!0,hashtag:!1,newWindow:!0,stripPrefix:!0,truncate:void 0,className:"",htmlParser:void 0,matchParser:void 0,tagBuilder:void 0,link:function(e){for(var t=this.getHtmlParser(),r=t.parse(e),i=0,n=[],o=0,a=r.length;a>o;o++){var s=r[o],l=s.getType(),u=s.getText();if("element"===l)"a"===s.getTagName()&&(s.isClosing()?i=Math.max(i-1,0):i++),n.push(u);else if("entity"===l||"comment"===l)n.push(u);else if(0===i){var c=this.linkifyStr(u);n.push(c)}else n.push(u)}return n.join("")},linkifyStr:function(e){return this.getMatchParser().replace(e,this.createMatchReturnVal,this)},createMatchReturnVal:function(t){var r;if(this.replaceFn&&(r=this.replaceFn.call(this,this,t)),"string"==typeof r)return r;if(r===!1)return t.getMatchedText();if(r instanceof e.HtmlTag)return r.toAnchorString();var i=this.getTagBuilder(),n=i.build(t);return n.toAnchorString()},getHtmlParser:function(){var t=this.htmlParser;return t||(t=this.htmlParser=new e.htmlParser.HtmlParser),t},getMatchParser:function(){var t=this.matchParser;return t||(t=this.matchParser=new e.matchParser.MatchParser({urls:this.urls,email:this.email,twitter:this.twitter,phone:this.phone,hashtag:this.hashtag,stripPrefix:this.stripPrefix})),t},getTagBuilder:function(){var t=this.tagBuilder;return t||(t=this.tagBuilder=new e.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),t}},e.link=function(t,r){var i=new e(r);return i.link(t)},e.match={},e.htmlParser={},e.matchParser={},e.Util={abstractMethod:function(){throw"abstract"},trimRegex:/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,assign:function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e},extend:function(t,r){var i=t.prototype,n=function(){};n.prototype=i;var o;o=r.hasOwnProperty("constructor")?r.constructor:function(){i.constructor.apply(this,arguments)};var a=o.prototype=new n;return a.constructor=o,a.superclass=i,delete r.constructor,e.Util.assign(a,r),o},ellipsis:function(e,t,r){return e.length>t&&(r=null==r?"..":r,e=e.substring(0,t-r.length)+r),e},indexOf:function(e,t){if(Array.prototype.indexOf)return e.indexOf(t);for(var r=0,i=e.length;i>r;r++)if(e[r]===t)return r;return-1},splitAndCapture:function(e,t){if(!t.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var r,i=[],n=0;r=t.exec(e);)i.push(e.substring(n,r.index)),i.push(r[0]),n=r.index+r[0].length;return i.push(e.substring(n)),i},trim:function(e){return e.replace(this.trimRegex,"")}},e.HtmlTag=e.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(t){e.Util.assign(this,t),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(e){return this.tagName=e,this},getTagName:function(){return this.tagName||""},setAttr:function(e,t){var r=this.getAttrs();return r[e]=t,this},getAttr:function(e){return this.getAttrs()[e]},setAttrs:function(t){var r=this.getAttrs();return e.Util.assign(r,t),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(e){return this.setAttr("class",e)},addClass:function(t){for(var r,i=this.getClass(),n=this.whitespaceRegex,o=e.Util.indexOf,a=i?i.split(n):[],s=t.split(n);r=s.shift();)-1===o(a,r)&&a.push(r);return this.getAttrs()["class"]=a.join(" "),this},removeClass:function(t){for(var r,i=this.getClass(),n=this.whitespaceRegex,o=e.Util.indexOf,a=i?i.split(n):[],s=t.split(n);a.length&&(r=s.shift());){var l=o(a,r);-1!==l&&a.splice(l,1)}return this.getAttrs()["class"]=a.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(e){return-1!==(" "+this.getClass()+" ").indexOf(" "+e+" ")},setInnerHtml:function(e){return this.innerHtml=e,this},getInnerHtml:function(){return this.innerHtml||""},toAnchorString:function(){var e=this.getTagName(),t=this.buildAttrsStr();return t=t?" "+t:"",["<",e,t,">",this.getInnerHtml(),"</",e,">"].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var e=this.getAttrs(),t=[];for(var r in e)e.hasOwnProperty(r)&&t.push(r+'="'+e[r]+'"');return t.join(" ")}}),e.AnchorTagBuilder=e.Util.extend(Object,{constructor:function(t){e.Util.assign(this,t)},build:function(t){var r=new e.HtmlTag({tagName:"a",attrs:this.createAttrs(t.getType(),t.getAnchorHref()),innerHtml:this.processAnchorText(t.getAnchorText())});return r},createAttrs:function(e,t){var r={href:t},i=this.createCssClass(e);return i&&(r["class"]=i),this.newWindow&&(r.target="_blank"),r},createCssClass:function(e){var t=this.className;return t?t+" "+t+"-"+e:""},processAnchorText:function(e){return e=this.doTruncate(e)},doTruncate:function(t){return e.Util.ellipsis(t,this.truncate||Number.POSITIVE_INFINITY)}}),e.htmlParser.HtmlParser=e.Util.extend(Object,{htmlRegex:function(){var e=/!--([\s\S]+?)--/,t=/[0-9a-zA-Z][0-9a-zA-Z:]*/,r=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,i=/(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/,n=r.source+"(?:\\s*=\\s*"+i.source+")?";return new RegExp(["(?:","<(!DOCTYPE)","(?:","\\s+","(?:",n,"|",i.source+")",")*",">",")","|","(?:","<(/)?","(?:",e.source,"|","(?:","("+t.source+")","(?:","\\s+",n,")*","\\s*/?",")",")",">",")"].join(""),"gi")}(),htmlCharacterEntitiesRegex:/( | |<|<|>|>|"|"|')/gi,parse:function(e){for(var t,r,i=this.htmlRegex,n=0,o=[];null!==(t=i.exec(e));){var a=t[0],s=t[3],l=t[1]||t[4],u=!!t[2],c=e.substring(n,t.index);c&&(r=this.parseTextAndEntityNodes(c),o.push.apply(o,r)),s?o.push(this.createCommentNode(a,s)):o.push(this.createElementNode(a,l,u)),n=t.index+a.length}if(n<e.length){var h=e.substring(n);h&&(r=this.parseTextAndEntityNodes(h),o.push.apply(o,r))}return o},parseTextAndEntityNodes:function(t){for(var r=[],i=e.Util.splitAndCapture(t,this.htmlCharacterEntitiesRegex),n=0,o=i.length;o>n;n+=2){var a=i[n],s=i[n+1];a&&r.push(this.createTextNode(a)),s&&r.push(this.createEntityNode(s))}return r},createCommentNode:function(t,r){return new e.htmlParser.CommentNode({text:t,comment:e.Util.trim(r)})},createElementNode:function(t,r,i){return new e.htmlParser.ElementNode({text:t,tagName:r.toLowerCase(),closing:i})},createEntityNode:function(t){return new e.htmlParser.EntityNode({text:t})},createTextNode:function(t){return new e.htmlParser.TextNode({text:t})}}),e.htmlParser.HtmlNode=e.Util.extend(Object,{text:"",constructor:function(t){e.Util.assign(this,t)},getType:e.Util.abstractMethod,getText:function(){return this.text}}),e.htmlParser.CommentNode=e.Util.extend(e.htmlParser.HtmlNode,{comment:"",getType:function(){return"comment"},getComment:function(){return this.comment}}),e.htmlParser.ElementNode=e.Util.extend(e.htmlParser.HtmlNode,{tagName:"",closing:!1,getType:function(){return"element"},getTagName:function(){return this.tagName},isClosing:function(){return this.closing}}),e.htmlParser.EntityNode=e.Util.extend(e.htmlParser.HtmlNode,{getType:function(){return"entity"}}),e.htmlParser.TextNode=e.Util.extend(e.htmlParser.HtmlNode,{getType:function(){return"text"}}),e.matchParser.MatchParser=e.Util.extend(Object,{urls:!0,email:!0,twitter:!0,phone:!0,hashtag:!1,stripPrefix:!0,matcherRegex:function(){var e=/(^|[^\w])@(\w{1,15})/,t=/(^|[^\w])#(\w{1,15})/,r=/(?:[\-;:&=\+\$,\w\.]+@)/,i=/(?:\+?\d{1,3}[-\s.])?\(?\d{3}\)?[-\s.]?\d{3}[-\s.]\d{4}/,n=/(?:[A-Za-z][-.+A-Za-z0-9]+:(?![A-Za-z][-.+A-Za-z0-9]+:\/\/)(?!\d+\/?)(?:\/\/)?)/,o=/(?:www\.)/,a=/[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/,s=/\.(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/,l=/[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]?!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]]/; -return new RegExp(["(",e.source,")","|","(",r.source,a.source,s.source,")","|","(","(?:","(",n.source,a.source,")","|","(?:","(.?//)?",o.source,a.source,")","|","(?:","(.?//)?",a.source,s.source,")",")","(?:"+l.source+")?",")","|","(",i.source,")","|","(",t.source,")"].join(""),"gi")}(),charBeforeProtocolRelMatchRegex:/^(.)?\/\//,constructor:function(t){e.Util.assign(this,t),this.matchValidator=new e.MatchValidator},replace:function(e,t,r){var i=this;return e.replace(this.matcherRegex,function(e,n,o,a,s,l,u,c,h,d,p,m,f){var v=i.processCandidateMatch(e,n,o,a,s,l,u,c,h,d,p,m,f);if(v){var _=t.call(r,v.match);return v.prefixStr+_+v.suffixStr}return e})},processCandidateMatch:function(t,r,i,n,o,a,s,l,u,c,h,d,p){var m,f=l||u,v="",_="";if(a&&!this.urls||o&&!this.email||c&&!this.phone||r&&!this.twitter||h&&!this.hashtag||!this.matchValidator.isValidMatch(a,s,f))return null;if(this.matchHasUnbalancedClosingParen(t)&&(t=t.substr(0,t.length-1),_=")"),o)m=new e.match.Email({matchedText:t,email:o});else if(r)i&&(v=i,t=t.slice(1)),m=new e.match.Twitter({matchedText:t,twitterHandle:n});else if(c){var g=t.replace(/\D/g,"");m=new e.match.Phone({matchedText:t,number:g})}else if(h)d&&(v=d,t=t.slice(1)),m=new e.match.Hashtag({matchedText:t,serviceName:this.hashtag,hashtag:p});else{if(f){var y=f.match(this.charBeforeProtocolRelMatchRegex)[1]||"";y&&(v=y,t=t.slice(1))}m=new e.match.Url({matchedText:t,url:t,protocolUrlMatch:!!s,protocolRelativeMatch:!!f,stripPrefix:this.stripPrefix})}return{prefixStr:v,suffixStr:_,match:m}},matchHasUnbalancedClosingParen:function(e){var t=e.charAt(e.length-1);if(")"===t){var r=e.match(/\(/g),i=e.match(/\)/g),n=r&&r.length||0,o=i&&i.length||0;if(o>n)return!0}return!1}}),e.MatchValidator=e.Util.extend(Object,{invalidProtocolRelMatchRegex:/^[\w]\/\//,hasFullProtocolRegex:/^[A-Za-z][-.+A-Za-z0-9]+:\/\//,uriSchemeRegex:/^[A-Za-z][-.+A-Za-z0-9]+:/,hasWordCharAfterProtocolRegex:/:[^\s]*?[A-Za-z]/,isValidMatch:function(e,t,r){return t&&!this.isValidUriScheme(t)||this.urlMatchDoesNotHaveProtocolOrDot(e,t)||this.urlMatchDoesNotHaveAtLeastOneWordChar(e,t)||this.isInvalidProtocolRelativeMatch(r)?!1:!0},isValidUriScheme:function(e){var t=e.match(this.uriSchemeRegex)[0].toLowerCase();return"javascript:"!==t&&"vbscript:"!==t},urlMatchDoesNotHaveProtocolOrDot:function(e,t){return!(!e||t&&this.hasFullProtocolRegex.test(t)||-1!==e.indexOf("."))},urlMatchDoesNotHaveAtLeastOneWordChar:function(e,t){return e&&t?!this.hasWordCharAfterProtocolRegex.test(e):!1},isInvalidProtocolRelativeMatch:function(e){return!!e&&this.invalidProtocolRelMatchRegex.test(e)}}),e.match.Match=e.Util.extend(Object,{constructor:function(t){e.Util.assign(this,t)},getType:e.Util.abstractMethod,getMatchedText:function(){return this.matchedText},getAnchorHref:e.Util.abstractMethod,getAnchorText:e.Util.abstractMethod}),e.match.Email=e.Util.extend(e.match.Match,{getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),e.match.Hashtag=e.Util.extend(e.match.Match,{getType:function(){return"hashtag"},getHashtag:function(){return this.hashtag},getAnchorHref:function(){var e=this.serviceName,t=this.hashtag;switch(e){case"twitter":return"https://twitter.com/hashtag/"+t;case"facebook":return"https://www.facebook.com/hashtag/"+t;default:throw new Error("Unknown service name to point hashtag to: ",e)}},getAnchorText:function(){return"#"+this.hashtag}}),e.match.Phone=e.Util.extend(e.match.Match,{getType:function(){return"phone"},getNumber:function(){return this.number},getAnchorHref:function(){return"tel:"+this.number},getAnchorText:function(){return this.matchedText}}),e.match.Twitter=e.Util.extend(e.match.Match,{getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),e.match.Url=e.Util.extend(e.match.Match,{urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,protocolPrepended:!1,getType:function(){return"url"},getUrl:function(){var e=this.url;return this.protocolRelativeMatch||this.protocolUrlMatch||this.protocolPrepended||(e=this.url="http://"+e,this.protocolPrepended=!0),e},getAnchorHref:function(){var e=this.getUrl();return e.replace(/&/g,"&")},getAnchorText:function(){var e=this.getUrl();return this.protocolRelativeMatch&&(e=this.stripProtocolRelativePrefix(e)),this.stripPrefix&&(e=this.stripUrlPrefix(e)),e=this.removeTrailingSlash(e)},stripUrlPrefix:function(e){return e.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(e){return e.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(e){return"/"===e.charAt(e.length-1)&&(e=e.slice(0,-1)),e}}),e}),r("ThirdParty/zip",["../Core/buildModuleUrl","../Core/defineProperties"],function(e,t){var r={};return function(r){function i(){var e=-1,t=this;t.append=function(r){var i,n=t.table;for(i=0;i<r.length;i++)e=e>>>8^n[255&(e^r[i])]},t.get=function(){return~e}}function n(e,t,r){return e.slice?e.slice(t,t+r):e.webkitSlice?e.webkitSlice(t,t+r):e.mozSlice?e.mozSlice(t,t+r):e.msSlice?e.msSlice(t,t+r):void 0}function o(e,t){var r,i;return r=new ArrayBuffer(e),i=new Uint8Array(r),t&&i.set(t,0),{buffer:r,array:i,view:new DataView(r)}}function a(){}function s(e){function t(t,r){var o=new Blob([e],{type:k});i=new u(o),i.init(function(){n.size=i.size,t()},r)}function r(e,t,r,n){i.readUint8Array(e,t,r,n)}var i,n=this;n.size=0,n.init=t,n.readUint8Array=r}function l(e){function t(t){for(var r=e.length;"="==e.charAt(r-1);)r--;i=e.indexOf(",")+1,n.size=Math.floor(.75*(r-i)),t()}function r(t,r,n){var a,s=o(r),l=4*Math.floor(t/3),u=4*Math.ceil((t+r)/3),c=window.atob(e.substring(l+i,u+i)),h=t-3*Math.floor(l/4);for(a=h;h+r>a;a++)s.array[a-h]=c.charCodeAt(a);n(s.array)}var i,n=this;n.size=0,n.init=t,n.readUint8Array=r}function u(e){function t(t){this.size=e.size,t()}function r(t,r,i,o){var a=new FileReader;a.onload=function(e){i(new Uint8Array(e.target.result))},a.onerror=o,a.readAsArrayBuffer(n(e,t,r))}var i=this;i.size=0,i.init=t,i.readUint8Array=r}function c(){}function h(e){function t(e){n=new Blob([],{type:k}),e()}function r(e,t){n=new Blob([n,A?e:e.buffer],{type:k}),t()}function i(t,r){var i=new FileReader;i.onload=function(e){t(e.target.result)},i.onerror=r,i.readAsText(n,e)}var n,o=this;o.init=t,o.writeUint8Array=r,o.getData=i}function d(e){function t(t){o+="data:"+(e||"")+";base64,",t()}function r(e,t){var r,i=a.length,n=a;for(a="",r=0;r<3*Math.floor((i+e.length)/3)-i;r++)n+=String.fromCharCode(e[r]);for(;r<e.length;r++)a+=String.fromCharCode(e[r]);n.length>2?o+=window.btoa(n):a=n,t()}function i(e){e(o+window.btoa(a))}var n=this,o="",a="";n.init=t,n.writeUint8Array=r,n.getData=i}function p(e){function t(t){n=new Blob([],{type:e}),t()}function r(t,r){n=new Blob([n,A?t:t.buffer],{type:e}),r()}function i(e){e(n)}var n,o=this;o.init=t,o.writeUint8Array=r,o.getData=i}function m(e,t,r,i,n,o,a,s,l,u){function c(){e.removeEventListener(U,h,!1),s(m)}function h(e){var t=e.data,i=t.data;t.onappend&&(m+=i.length,r.writeUint8Array(i,function(){o(!1,i),d()},u)),t.onflush&&(i?(m+=i.length,r.writeUint8Array(i,function(){o(!1,i),c()},u)):c()),t.progress&&a&&a(p+t.current,n)}function d(){p=f*B,n>p?t.readUint8Array(i+p,Math.min(B,n-p),function(t){e.postMessage({append:!0,data:t}),f++,a&&a(p,n),o(!0,t)},l):e.postMessage({flush:!0})}var p,m,f=0;m=0,e.addEventListener(U,h,!1),d()}function f(e,t,r,i,n,o,a,s,l,u){function c(){var m;h=d*B,n>h?t.readUint8Array(i+h,Math.min(B,n-h),function(t){var s=e.append(t,function(){a&&a(i+h,n)});p+=s.length,o(!0,t),r.writeUint8Array(s,function(){o(!1,s),d++,setTimeout(c,1)},u),a&&a(h,n)},l):(m=e.flush(),m?(p+=m.length,r.writeUint8Array(m,function(){o(!1,m),s(p)},u)):s(p))}var h,d=0,p=0;c()}function v(e,t,n,o,a,s,l,u,c){function h(e,t){a&&!e&&v.append(t)}function d(e){s(e,v.get())}var p,v=new i;return r.zip.useWebWorkers?(p=new Worker(r.zip.workerScriptsPath+V),m(p,e,t,n,o,h,l,d,u,c)):f(new r.zip.Inflater,e,t,n,o,h,l,d,u,c),p}function _(e,t,n,o,a,s,l){function u(e,t){e&&p.append(t)}function c(e){o(e,p.get())}function h(){d.removeEventListener(U,h,!1),m(d,e,t,0,e.size,u,a,c,s,l)}var d,p=new i;return r.zip.useWebWorkers?(d=new Worker(r.zip.workerScriptsPath+z),d.addEventListener(U,h,!1),d.postMessage({init:!0,level:n})):f(new r.zip.Deflater,e,t,0,e.size,u,a,c,s,l),d}function g(e,t,r,n,o,a,s,l,u){function c(){var i=h*B;n>i?e.readUint8Array(r+i,Math.min(B,n-i),function(e){o&&d.append(e),s&&s(i,n,e),t.writeUint8Array(e,function(){h++,c()},u)},l):a(n,d.get())}var h=0,d=new i;c()}function y(e){var t,r,i="",n=["Ç","ü","é","â","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å","É","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü","ø","£","Ø","×","ƒ","á","í","ó","ú","ñ","Ñ","ª","º","¿","®","¬","½","¼","¡","«","»","_","_","_","¦","¦","Á","Â","À","©","¦","¦","+","+","¢","¥","+","+","-","-","+","-","+","ã","Ã","+","+","-","-","¦","-","+","¤","ð","Ð","Ê","Ë","È","i","Í","Î","Ï","+","+","_","_","¦","Ì","_","Ó","ß","Ô","Ò","õ","Õ","µ","þ","Þ","Ú","Û","Ù","ý","Ý","¯","´","­","±","_","¾","¶","§","÷","¸","°","¨","·","¹","³","²","_"," "];for(t=0;t<e.length;t++)r=255&e.charCodeAt(t),i+=r>127?n[r-128]:String.fromCharCode(r);return i}function C(e){return decodeURIComponent(escape(e))}function E(e){var t,r="";for(t=0;t<e.length;t++)r+=String.fromCharCode(e[t]);return r}function S(e){var t=(4294901760&e)>>16,r=65535&e;try{return new Date(1980+((65024&t)>>9),((480&t)>>5)-1,31&t,(63488&r)>>11,(2016&r)>>5,2*(31&r),0)}catch(i){}}function w(e,t,r,i,n){return e.version=t.view.getUint16(r,!0),e.bitFlag=t.view.getUint16(r+2,!0),e.compressionMethod=t.view.getUint16(r+4,!0),e.lastModDateRaw=t.view.getUint32(r+6,!0),e.lastModDate=S(e.lastModDateRaw),1===(1&e.bitFlag)?void n(M):((i||8!=(8&e.bitFlag))&&(e.crc32=t.view.getUint32(r+10,!0),e.compressedSize=t.view.getUint32(r+14,!0),e.uncompressedSize=t.view.getUint32(r+18,!0)),4294967295===e.compressedSize||4294967295===e.uncompressedSize?void n(D):(e.filenameLength=t.view.getUint16(r+22,!0),void(e.extraFieldLength=t.view.getUint16(r+24,!0))))}function T(e,t){function r(){}function i(r,n){e.readUint8Array(e.size-r,r,function(e){var t=o(e.length,e).view;1347093766!=t.getUint32(0)?i(r+1,n):n(t)},function(){t(R)})}return r.prototype.getData=function(r,i,n,a){function s(e,t){d&&d.terminate(),d=null,e&&e(t)}function l(e){var t=o(4);return t.view.setUint32(0,e),p.crc32==t.view.getUint32(0)}function u(e,t){a&&!l(t)?c():r.getData(function(e){s(i,e)})}function c(){s(t,L)}function h(){s(t,N)}var d,p=this;e.readUint8Array(p.offset,30,function(i){var s,l=o(i.length,i);return 1347093252!=l.view.getUint32(0)?void t(I):(w(p,l,4,!1,t),s=p.offset+30+p.filenameLength+p.extraFieldLength,void r.init(function(){0===p.compressionMethod?g(e,r,s,p.compressedSize,a,u,n,c,h):d=v(e,r,s,p.compressedSize,a,u,n,c,h)},h))},c)},{getEntries:function(n){return e.size<22?void t(I):void i(22,function(i){var a,s;a=i.getUint32(16,!0),s=i.getUint16(8,!0),e.readUint8Array(a,e.size-a,function(e){var i,a,l,u,c=0,h=[],d=o(e.length,e);for(i=0;s>i;i++){if(a=new r,1347092738!=d.view.getUint32(c))return void t(I);w(a,d,c+6,!0,t),a.commentLength=d.view.getUint16(c+32,!0),a.directory=16==(16&d.view.getUint8(c+38)),a.offset=d.view.getUint32(c+42,!0),l=E(d.array.subarray(c+46,c+46+a.filenameLength)),a.filename=2048===(2048&a.bitFlag)?C(l):y(l),a.directory||"/"!=a.filename.charAt(a.filename.length-1)||(a.directory=!0),u=E(d.array.subarray(c+46+a.filenameLength+a.extraFieldLength,c+46+a.filenameLength+a.extraFieldLength+a.commentLength)),a.comment=2048===(2048&a.bitFlag)?C(u):y(u),h.push(a),c+=46+a.filenameLength+a.extraFieldLength+a.commentLength}n(h)},function(){t(R)})})},close:function(e){e&&e()}}}function b(e){return unescape(encodeURIComponent(e))}function x(e){var t,r=[];for(t=0;t<e.length;t++)r.push(e.charCodeAt(t));return r}function P(e,t,r){function i(e,t){s&&s.terminate(),s=null,e&&e(t)}function n(){i(t,O)}function a(){i(t,L)}var s,l={},u=[],c=0;return{add:function(h,d,p,m,f){function v(t){var i;w=f.lastModDate||new Date,E=o(26),l[h]={headerArray:E.array,directory:f.directory,filename:S,offset:c,comment:x(b(f.comment||""))},E.view.setUint32(0,335546376),f.version&&E.view.setUint8(0,f.version),r||0===f.level||f.directory||E.view.setUint16(4,2048),E.view.setUint16(6,(w.getHours()<<6|w.getMinutes())<<5|w.getSeconds()/2,!0),E.view.setUint16(8,(w.getFullYear()-1980<<4|w.getMonth()+1)<<5|w.getDate(),!0),E.view.setUint16(22,S.length,!0),i=o(30+S.length),i.view.setUint32(0,1347093252),i.array.set(E.array,4),i.array.set(S,30),c+=i.array.length,e.writeUint8Array(i.array,t,n)}function y(t,r){var a=o(16);c+=t||0,a.view.setUint32(0,1347094280),"undefined"!=typeof r&&(E.view.setUint32(10,r,!0),a.view.setUint32(4,r,!0)),d&&(a.view.setUint32(8,t,!0),E.view.setUint32(14,t,!0),a.view.setUint32(12,d.size,!0),E.view.setUint32(18,d.size,!0)),e.writeUint8Array(a.array,function(){c+=16,i(p)},n)}function C(){return f=f||{},h=h.trim(),f.directory&&"/"!=h.charAt(h.length-1)&&(h+="/"),l.hasOwnProperty(h)?void t(F):(S=x(b(h)),u.push(h),void v(function(){d?r||0===f.level?g(d,e,0,d.size,!0,y,m,a,n):s=_(d,e,f.level,y,m,a,n):y()},n))}var E,S,w;d?d.init(C,a):C()},close:function(t){var r,a,s,h=0,d=0;for(a=0;a<u.length;a++)s=l[u[a]],h+=46+s.filename.length+s.comment.length;for(r=o(h+22),a=0;a<u.length;a++)s=l[u[a]],r.view.setUint32(d,1347092738),r.view.setUint16(d+4,5120),r.array.set(s.headerArray,d+6),r.view.setUint16(d+32,s.comment.length,!0),s.directory&&r.view.setUint8(d+38,16),r.view.setUint32(d+42,s.offset,!0),r.array.set(s.filename,d+46),r.array.set(s.comment,d+46+s.filename.length),d+=46+s.filename.length+s.comment.length;r.view.setUint32(d,1347093766),r.view.setUint16(d+8,u.length,!0),r.view.setUint16(d+10,u.length,!0),r.view.setUint32(d+12,h,!0),r.view.setUint32(d+16,c,!0),e.writeUint8Array(r.array,function(){i(function(){e.getData(t)})},n)}}}var A,I="File format is not recognized.",M="File contains encrypted entry.",D="File is using Zip64 (4gb+ file size).",R="Error while reading zip file.",O="Error while writing zip file.",N="Error while writing file data.",L="Error while reading file data.",F="File already exists.",B=524288,V="inflate.js",z="deflate.js",k="text/plain",U="message";try{A=0===new Blob([new DataView(new ArrayBuffer(0))]).size}catch(G){}i.prototype.table=function(){var e,t,r,i=[];for(e=0;256>e;e++){for(r=e,t=0;8>t;t++)1&r?r=r>>>1^3988292384:r>>>=1;i[e]=r}return i}(),s.prototype=new a,s.prototype.constructor=s,l.prototype=new a,l.prototype.constructor=l,u.prototype=new a,u.prototype.constructor=u,c.prototype.getData=function(e){e(this.data)},h.prototype=new c,h.prototype.constructor=h,d.prototype=new c,d.prototype.constructor=d,p.prototype=new c,p.prototype.constructor=p,r.zip={Reader:a,Writer:c,BlobReader:u,Data64URIReader:l,TextReader:s,BlobWriter:p,Data64URIWriter:d,TextWriter:h,createReader:function(e,t,r){e.init(function(){t(T(e,r))},r)},createWriter:function(e,t,r,i){e.init(function(){t(P(e,r,i))},r)},useWebWorkers:!0};var W;t(r.zip,{workerScriptsPath:{get:function(){return"undefined"==typeof W&&(W=e("ThirdParty/Workers/")),W}}})}(r),r.zip}),r("DataSources/KmlDataSource",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/ClockRange","../Core/ClockStep","../Core/Color","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/getFilenameFromUri","../Core/Iso8601","../Core/JulianDate","../Core/loadBlob","../Core/loadXML","../Core/Math","../Core/NearFarScalar","../Core/PinBuilder","../Core/PolygonHierarchy","../Core/Rectangle","../Core/RuntimeError","../Core/TimeInterval","../Core/TimeIntervalCollection","../Scene/HorizontalOrigin","../Scene/LabelStyle","../ThirdParty/Autolinker","../ThirdParty/Uri","../ThirdParty/when","../ThirdParty/zip","./BillboardGraphics","./CompositePositionProperty","./ConstantPositionProperty","./DataSource","./DataSourceClock","./Entity","./EntityCollection","./LabelGraphics","./PathGraphics","./PolygonGraphics","./PolylineGraphics","./PositionPropertyArray","./RectangleGraphics","./ReferenceProperty","./SampledPositionProperty","./ScaledPositionProperty","./TimeIntervalCollectionProperty","./WallGraphics"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K){"use strict";function J(e){var t=e.slice(0,Math.min(4,e.size)),r=D.defer(),i=new FileReader;return i.addEventListener("load",function(){r.resolve(1347093252===new DataView(i.result).getUint32(0,!1))}),i.addEventListener("error",function(){r.reject(i.error)}),i.readAsArrayBuffer(t),r.promise}function Q(e){var t=D.defer(),r=new FileReader;return r.addEventListener("load",function(){t.resolve(r.result)}),r.addEventListener("error",function(){t.reject(r.error)}),r.readAsText(e),t.promise}function $(e,t,r,i){t.getData(new R.TextWriter,function(e){r.kml=$e.parseFromString(e,"application/xml"),i.resolve()})}function ee(e,t,r,i){var n=s(Qe.detectFromFilename(t.filename),"application/octet-stream");t.getData(new R.Data64URIWriter(n),function(e){r[t.filename]=e,i.resolve()})}function te(e,t,r,i){for(var n=i.keys,o=new M("."),a=e.querySelectorAll(t),s=0;s<a.length;s++){var l=a[s],u=l.getAttribute(r),c=new M(u).resolve(o).toString(),h=n.indexOf(c);if(-1!==h){var d=n[h];l.setAttribute(r,i[d]),"a"===t&&null===l.getAttribute("download")&&l.setAttribute("download",d)}}}function re(e,t){return l(t)&&new M(e).isAbsolute()&&(e=t.getURL(e)),e}function ie(e,t){var r=le(e,"id");r=l(r)?r:a();var i=t.getOrCreateEntity(r);return l(i.kml)||(i.addProperty("kml"),i.kml=new ht),i}function ne(e,t){return"absolute"===e||"relativeToGround"===e||"relativeToSeaFloor"===t}function oe(e){if(!l(e))return r.fromDegrees(0,0,0);var t=e.match(/[^\s,\n]+/g);if(!u(t))return r.fromDegrees(0,0,0);var i=parseFloat(t[0]),n=parseFloat(t[1]),o=parseFloat(t[2]);return i=isNaN(i)?0:i,n=isNaN(n)?0:n,o=isNaN(o)?0:o,r.fromDegrees(i,n,o)}function ae(e){if(!l(e))return void 0;var t=e.textContent.match(/[^\s\n]+/g);if(!u(t))return void 0;for(var r=t.length,i=new Array(r),n=0,o=0;r>o;o++)i[n++]=oe(t[o]);return i}function se(e,t){if(!l(e))return void 0;var r=e.getAttribute(t);if(null!==r){var i=parseFloat(r);return isNaN(i)?void 0:i}return void 0}function le(e,t){if(!l(e))return void 0;var r=e.getAttribute(t);return null!==r?r:void 0}function ue(e,t,r){if(!l(e))return void 0;for(var i=e.childNodes,n=i.length,o=0;n>o;o++){var a=i[o];if(a.localName===t&&-1!==r.indexOf(a.namespaceURI))return a}return void 0}function ce(e,t,r){if(!l(e))return void 0;for(var i=[],n=e.getElementsByTagName(t),o=n.length,a=0;o>a;a++){var s=n[a];s.localName===t&&-1!==r.indexOf(s.namespaceURI)&&i.push(s)}return i}function he(e,t,r){if(!l(e))return[];for(var i=[],n=e.childNodes,o=n.length,a=0;o>a;a++){var s=n[a];s.localName===t&&-1!==r.indexOf(s.namespaceURI)&&i.push(s)}return i}function de(e,t,r){var i=ue(e,t,r);if(l(i)){var n=parseFloat(i.textContent);return isNaN(n)?void 0:n}return void 0}function pe(e,t,r){var i=ue(e,t,r);return l(i)?i.textContent.trim():void 0}function me(e,t,r){var i=ue(e,t,r);if(l(i)){var n=i.textContent.trim();return"1"===n||/^true$/i.test(n)}return void 0}function fe(e,t,r,i){if(!l(e))return void 0;var n=!1;if(l(i)){var o=i[e];l(o)&&(n=!0,e=o)}if(!n&&l(r)){var a=new M(document.location.href);r=new M(r),e=new M(e).resolve(r.resolve(a)).toString(),e=re(e,t)}return e}function ve(e,t){if(!l(e))return void 0;"#"===e[0]&&(e=e.substring(1));var r=parseInt(e.substring(0,2),16)/255,i=parseInt(e.substring(2,4),16)/255,n=parseInt(e.substring(4,6),16)/255,a=parseInt(e.substring(6,8),16)/255;return t?(a>0?at.maximumRed=a:at.red=0,n>0?at.maximumGreen=n:at.green=0,i>0?at.maximumBlue=i:at.blue=0,at.alpha=r,o.fromRandom(at)):new o(a,n,i,r)}function _e(e,t,r){var i=pe(e,t,r);return l(i)?ve(i,"random"===pe(e,"colorMode",r)):void 0}function ge(e){var t=ue(e,"TimeStamp",ot.kmlgx),r=pe(t,"when",ot.kmlgx);if(!l(t)||!l(r)||0===r.length)return void 0;var i=v.fromIso8601(r),n=new x;return n.addInterval(new b({start:i,stop:f.MAXIMUM_VALUE})),n}function ye(e){var t=ue(e,"TimeSpan",ot.kmlgx);if(!l(t))return void 0;var r,i=ue(t,"begin",ot.kmlgx),n=l(i)?v.fromIso8601(i.textContent):void 0,o=ue(t,"end",ot.kmlgx),a=l(o)?v.fromIso8601(o.textContent):void 0;if(l(n)&&l(a)){if(v.lessThan(a,n)){var s=n;n=a,a=s}r=new x,r.addInterval(new b({start:n,stop:a}))}else l(n)?(r=new x,r.addInterval(new b({start:n,stop:f.MAXIMUM_VALUE}))):l(a)&&(r=new x,r.addInterval(new b({start:f.MINIMUM_VALUE,stop:a})));return r}function Ce(){var e=new O;return e.width=tt,e.height=tt,e.scaleByDistance=new C(2414016,1,16093e3,.1),e}function Ee(){var e=new G;return e.outline=!0,e.outlineColor=o.WHITE,e}function Se(){var e=new k;return e.translucencyByDistance=new C(3e6,1,5e6,0),e.pixelOffset=new t(17,0),e.horizontalOrigin=P.LEFT,e.font="16px sans-serif",e.style=A.FILL_AND_OUTLINE,e}function we(i,n,o,a,u){var c=de(n,"scale",ot.kml),h=de(n,"heading",ot.kml),d=_e(n,"color",ot.kml),p=ue(n,"Icon",ot.kml),m=pe(p,"href",ot.kml),f=fe(m,i._proxy,a,u),v=de(p,"x",ot.gx),_=de(p,"y",ot.gx),g=de(p,"w",ot.gx),C=de(p,"h",ot.gx),E=ue(n,"hotSpot",ot.kml),S=se(E,"x"),w=se(E,"y"),T=le(E,"xunits"),b=le(E,"yunits"),x=o.billboard;l(x)||(x=Ce(i),o.billboard=x),x.image=f,x.scale=c,x.color=d,(l(v)||l(_)||l(g)||l(C))&&(x.imageSubRegion=new e(v,_,g,C)),l(h)&&0!==h&&(x.rotation=y.toRadians(-h),x.alignedAxis=r.UNIT_Z),c=s(c,1);var P,A;l(S)&&("pixels"===T?P=-S*c:"insetPixels"===T?P=(S-tt)*c:"fraction"===T&&(P=-tt*c*S),P+=.5*tt*c),l(w)&&("pixels"===b?A=w:"insetPixels"===b?A=-w:"fraction"===b&&(A=w*tt),A-=.5*tt*c),(l(P)||l(A))&&(x.pixelOffset=new t(P,A))}function Te(e,t,r,i,n){for(var a=0,u=t.childNodes.length;u>a;a++){var c=t.childNodes.item(a);if("IconStyle"===c.localName)we(e,c,r,i,n);else if("LabelStyle"===c.localName){var h=r.label;l(h)||(h=Se(),r.label=h),h.scale=s(de(c,"scale",ot.kml),h.scale),h.fillColor=s(_e(c,"color",ot.kml),h.fillColor),h.text=r.name}else if("LineStyle"===c.localName){var d=r.polyline;l(d)||(d=new W,r.polyline=d),d.width=de(c,"width",ot.kml),d.material=_e(c,"color",ot.kml)}else if("PolyStyle"===c.localName){var p=r.polygon;l(p)||(p=Ee(),r.polygon=p),p.material=s(_e(c,"color",ot.kml),p.material),p.fill=s(me(c,"fill",ot.kml),p.fill),p.outline=s(me(c,"outline",ot.kml),p.outline)}else if("BalloonStyle"===c.localName){var m=s(ve(pe(c,"bgColor",ot.kml)),o.WHITE),f=s(ve(pe(c,"textColor",ot.kml)),o.BLACK),v=pe(c,"text",ot.kml);r.addProperty("balloonStyle"),r.balloonStyle={bgColor:m,textColor:f,text:v}}}}function be(e,t,r,i,n,o){var a=new V,s=he(r,"Style",ot.kml),u=s.length;u>0&&Te(t,s[u-1],a,n,o);var c=pe(r,"styleUrl",ot.kml);if(l(c)){var h=c,d=i.getById(h);l(d)||(d=i.getById("#"+h)),l(d)&&a.merge(d)}return a}function xe(e,t,r){return D(g(re(t,e._proxy)),function(i){return Pe(e,i,r,t,!0)})}function Pe(e,t,r,i,n,o){var a,s,u,c,h=ce(t,"Style",ot.kml);if(l(h)){var d=h.length;for(a=0;d>a;a++)c=h[a],s=le(c,"id"),l(s)&&(s="#"+s,n&&l(i)&&(s=i+s),l(r.getById(s))||(u=new V({id:s}),r.add(u),Te(e,c,u,i,o)))}var p=ce(t,"StyleMap",ot.kml);if(l(p)){var m=p.length;for(a=0;m>a;a++){var f=p[a];if(s=le(f,"id"),l(s))for(var v=he(f,"Pair",ot.kml),_=0;_<v.length;_++){var g=v[_];if("normal"===pe(g,"key",ot.kml)){if(s="#"+s,n&&l(i)&&(s=i+s),!l(r.getById(s))){u=r.getOrCreateEntity(s);var y=pe(g,"styleUrl",ot.kml);if(l(y)){var C=r.getOrCreateEntity(y);l(C)&&u.merge(C)}else c=ue(g,"Style",ot.kml),Te(e,c,u,i,o)}break}}}}var E={},S=[],w=t.getElementsByTagName("styleUrl"),T=w.length;for(a=0;T>a;a++){var b=w[a].textContent;if("#"!==b[0]){var x=b.split("#");if(2===x.length){var P=x[0];if(!l(E[P])){if(l(i)){var A=new M(document.location.href);i=new M(i),P=new M(P).resolve(i.resolve(A)).toString()}S.push(xe(e,P,r,i))}}}}return S}function Ae(e,t,r){var i=new j(e._entityCollection,t.id,["position"]),n=new X(t.position);t.polyline=l(r.polyline)?r.polyline.clone():new W,t.polyline.positions=new H([i,n])}function Ie(e,t,r){return"relativeToSeaFloor"===r||"absolute"===t||"relativeToGround"===t?e:((l(t)&&"clampToGround"!==t||l(r)&&"clampToSeaFloor"!==r)&&window.console.log("KML - Unknown altitudeMode: "+s(t,r)),new X(e))}function Me(e,t,r){if(!l(e))return void 0;if("relativeToSeaFloor"===r||"absolute"===t||"relativeToGround"===t)return e;(l(t)&&"clampToGround"!==t||l(r)&&"clampToSeaFloor"!==r)&&window.console.log("KML - Unknown altitudeMode: "+s(t,r));for(var i=e.length,n=0;i>n;n++){var o=e[n];d.WGS84.scaleToGeodeticSurface(o,o)}return e}function De(e,r,i){var n=r.label;l(n)||(n=l(i.label)?i.label.clone():Se(),r.label=n),n.text=r.name;var a=r.billboard;if(l(a)||(a=l(i.billboard)?i.billboard.clone():Ce(),r.billboard=a),l(a.image)||(a.image=e._pinBuilder.fromColor(o.YELLOW,64)),l(a.scale)){var s=a.scale.getValue();0!==s?n.pixelOffset=new t(16*s+1,0):(n.pixelOffset=void 0,n.horizontalOrigin=void 0)}}function Re(e,t,r){var i=t.path;l(i)||(i=new U,i.leadTime=0,t.path=i);var n=r.polyline;l(n)&&(i.material=n.material,i.width=n.width)}function Oe(e,t,r,i){var n=pe(t,"coordinates",ot.kml),o=pe(t,"altitudeMode",ot.kml),a=pe(t,"altitudeMode",ot.gx),s=me(t,"extrude",ot.kml),l=oe(n);r.position=Ie(new L(l),o,a),De(e,r,i),s&&ne(o,a)&&Ae(e,r,i)}function Ne(e,t,r,i){var n=ue(t,"coordinates",ot.kml),a=pe(t,"altitudeMode",ot.kml),s=pe(t,"altitudeMode",ot.gx),u=me(t,"extrude",ot.kml),c=me(t,"tessellate",ot.kml),h=ne(a,s),d=ae(n),p=i.polyline;if(h&&u){var m=new K;r.wall=m,m.positions=d;var f=i.polygon;l(f)&&(m.fill=f.fill,m.outline=f.outline,m.material=f.material),l(p)&&(m.outlineColor=l(p.material)?p.material.color:o.WHITE,m.outlineWidth=p.width)}else p=l(p)?p.clone():new W,r.polyline=p,p.positions=Me(d,a,s),(!c||h)&&(p.followSurface=!1)}function Le(e,t,r,i){var n=ue(t,"outerBoundaryIs",ot.kml),a=ue(n,"LinearRing",ot.kml),s=ue(a,"coordinates",ot.kml),u=ae(s),c=me(t,"extrude",ot.kml),h=pe(t,"altitudeMode",ot.kml),d=pe(t,"altitudeMode",ot.gx),p=ne(h,d),m=l(i.polygon)?i.polygon.clone():Ee(),f=i.polyline;if(l(f)&&(m.outlineColor=l(f.material)?f.material.color:o.WHITE,m.outlineWidth=f.width),r.polygon=m,p&&(m.perPositionHeight=!0,m.extrudedHeight=c?0:void 0),l(u)){for(var v=new S(u),_=he(t,"innerBoundaryIs",ot.kml),g=0;g<_.length;g++){a=he(_[g],"LinearRing",ot.kml);for(var y=0;y<a.length;y++)s=ue(a[y],"coordinates",ot.kml),u=ae(s),l(u)&&v.holes.push(new S(u))}m.hierarchy=v}}function Fe(e,t,r,i){for(var n=pe(t,"altitudeMode",ot.kml),o=pe(t,"altitudeMode",ot.gx),a=he(t,"coord",ot.gx),s=he(t,"when",ot.kml),l=me(t,"extrude",ot.kml),u=ne(n,o),c=Math.min(a.length,s.length),h=[],d=[],p=0;c>p;p++){var m=oe(a[p].textContent);h.push(m),d.push(v.fromIso8601(s[p].textContent))}var f=new Y;f.addSamples(d,h),r.position=Ie(f,n,o),De(e,r,i),Re(e,r,i),r.availability=new x,s.length>0&&r.availability.addInterval(new b({start:d[0],stop:d[d.length-1]})),u&&l&&Ae(e,r,i)}function Be(e,t,r,i,n,o,a,s,l){var u=e[0],c=e[e.length-1],h=new Y;h.addSamples(e,t),r.intervals.addInterval(new b({start:u,stop:c,isStartIncluded:l,isStopIncluded:l,data:Ie(h,a,s)})),i.addInterval(new b({start:u,stop:c,isStartIncluded:l,isStopIncluded:l})),n.intervals.addInterval(new b({start:u,stop:c,isStartIncluded:l,isStopIncluded:l,data:o}))}function Ve(e,t,r,i){for(var n,o,a,s=me(t,"interpolate",ot.gx),u=he(t,"Track",ot.gx),c=!1,h=new Z,d=new x,p=new N,m=0,f=u.length;f>m;m++){var _=u[m],g=he(_,"when",ot.kml),y=he(_,"coord",ot.gx),C=pe(_,"altitudeMode",ot.kml),E=pe(_,"altitudeMode",ot.gx),S=ne(C,E),w=me(_,"extrude",ot.kml),T=Math.min(y.length,g.length),b=[];n=[];for(var P=0;T>P;P++){var A=oe(y[P].textContent);b.push(A),n.push(v.fromIso8601(g[P].textContent))}s&&(l(o)&&Be([o,n[0]],[a,b[0]],p,d,h,!1,"absolute",void 0,!1),o=n[T-1],a=b[b.length-1]),Be(n,b,p,d,h,S&&w,C,E,!0),c=c||S&&w}r.availability=d,r.position=p,De(e,r,i),Re(e,r,i),c&&(Ae(e,r,i),r.polyline.show=h)}function ze(e,t,r,i){for(var n=t.childNodes,o=0,a=n.length;a>o;o++){var s=n.item(o),u=lt[s.localName];if(l(u)){var c=ie(s,e._entityCollection);c.parent=r,c.name=r.name,c.availability=r.availability,c.description=r.description,c.kml=r.kml,u(e,s,c,i)}}}function ke(e,t){var r=ue(e,"ExtendedData",ot.kml);if(!l(r))return void 0;var i={},n=he(r,"Data",ot.kml);if(l(n))for(var o=n.length,a=0;o>a;a++){var s=n[a],u=le(s,"name");l(u)&&(i[u]={displayName:pe(s,"displayName",ot.kml),value:pe(s,"value",ot.kml)})}t.kml.extendedData=i}function Ue(e,t,r,i){var n,a,u,c=t.kml,h=c.extendedData,d=pe(e,"description",ot.kml),p=s(t.balloonStyle,r.balloonStyle),m=o.WHITE,f=o.BLACK,v=d;l(p)&&(m=s(p.bgColor,o.WHITE),f=s(p.textColor,o.BLACK),v=s(p.text,d));var _;if(l(v)){if(v=v.replace("$[name]",s(t.name,"")),v=v.replace("$[description]",s(d,"")),v=v.replace("$[address]",s(c.address,"")),v=v.replace("$[Snippet]",s(c.snippet,"")),v=v.replace("$[id]",t.id),v=v.replace("$[geDirections]",""),l(h)){var g=v.match(/\$\[.+?\]/g);if(null!==g)for(n=0;n<g.length;n++){var y=g[n],C=y.substr(2,y.length-3),E=/\/displayName$/.test(C);C=C.replace(/\/displayName$/,""),_=h[C],l(_)&&(_=E?_.displayName:_.value),l(_)&&(v=v.replace(y,s(_,"")))}}}else if(l(h)&&(u=Object.keys(h),u.length>0)){for(v='<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>',n=0;n<u.length;n++)a=u[n],_=h[a],v+="<tr><th>"+s(_.displayName,a)+"</th><td>"+s(_.value,"")+"</td></tr>";v+="</tbody></table>"}if(l(v)){v=et.link(v),st.innerHTML=v;var S=st.querySelectorAll("a");for(n=0;n<S.length;n++)S[n].setAttribute("target","_blank");l(i)&&i.keys.length>1&&(te(st,"a","href",i),te(st,"img","src",i));var w='<div class="cesium-infoBox-description-lighter" style="';w+="overflow:auto;",w+="word-wrap:break-word;",w+="background-color:"+m.toCssColorString()+";",w+="color:"+f.toCssColorString()+";",w+='">',w+=st.innerHTML+"</div>",st.innerHTML="",t.description=w}}function Ge(e,t,r,i,n,o,a){var u=ie(r,i),c=u.kml,h=be(u,e,r,n,o,a),d=pe(r,"name",ot.kml);u.name=d,u.parent=t;var p=ye(r);l(p)||(p=ge(r)),u.availability=p;var m=me(r,"visibility",ot.kml);u.show=s(m,!0);var f=ue(r,"author",ot.atom),v=c.author;v.name=pe(f,"name",ot.atom),v.uri=pe(f,"uri",ot.atom),v.email=pe(f,"email",ot.atom);var _=ue(r,"link",ot.atom),g=c.link;return g.href=le(_,"href"),g.hreflang=le(_,"hreflang"),g.rel=le(_,"rel"),g.type=le(_,"type"),g.title=le(_,"title"),g.length=le(_,"length"),c.address=pe(r,"address",ot.kml),c.phoneNumber=pe(r,"phoneNumber",ot.kml),c.snippet=pe(r,"Snippet",ot.kml),ke(r,u),Ue(r,u,h,a),{entity:u,styleEntity:h}}function We(e,t,r,i,n,o,a){for(var s=Object.keys(ut),l=s.length,u=0;l>u;u++)for(var c=s[u],h=ut[c],d=r.childNodes,p=d.length,m=0;p>m;m++){var f=d[m];f.localName===c&&-1!==ot.kml.indexOf(f.namespaceURI)&&h(e,t,f,i,n,o,a)}}function He(e,t,r,i,n,o,a){var s=Ge(e,t,r,i,n,o,a);We(e,s.entity,r,i,n,o,a)}function qe(e,t,r,i,n,o,a){for(var s=Ge(e,t,r,i,n,o,a),u=s.entity,c=s.styleEntity,h=!1,d=r.childNodes,p=0,m=d.length;m>p&&!h;p++){var f=d.item(p),v=lt[f.localName];l(v)&&(v(e,f,u,c),h=!0)}h||(u.merge(c),De(e,u,c))}function je(e,t,r,i,n,o,a){var s,u=Ge(e,t,r,i,n,o,a),c=u.entity,h=(u.stylEntity,!1),d=ae(ue(r,"LatLonQuad",ot.gx));if(l(d))s=Ee(),s.hierarchy=new S(d),c.polygon=s,h=!0;else{s=new q,c.rectangle=s;var p=ue(r,"LatLonBox",ot.kml);if(l(p)){var m=de(p,"west",ot.kml),f=de(p,"south",ot.kml),v=de(p,"east",ot.kml),_=de(p,"north",ot.kml);l(m)&&(m=y.negativePiToPi(y.toRadians(m))),l(f)&&(f=y.negativePiToPi(y.toRadians(f))),l(v)&&(v=y.negativePiToPi(y.toRadians(v))),l(_)&&(_=y.negativePiToPi(y.toRadians(_))),s.coordinates=new w(m,f,v,_);var g=de(p,"rotation",ot.kml);l(g)&&(s.rotation=y.toRadians(g))}}var C=ue(r,"Icon",ot.kml),E=pe(C,"href",ot.kml);l(E)?(h&&window.console.log("KML - gx:LatLonQuad Icon does not support texture projection."),s.material=fe(E,e._proxy,o,a)):s.material=_e(r,"color",ot.kml);var T=pe(r,"altitudeMode",ot.kml);l(T)?"absolute"===T?s.height=de(r,"altitude",ot.kml):"clampToGround"===T||window.console.log("KML - Unknown altitudeMode: "+T):(T=pe(r,"altitudeMode",ot.gx), -"relativeToSeaFloor"===T?(window.console.log("KML - altitudeMode relativeToSeaFloor is currently not supported, treating as absolute."),s.height=de(r,"altitude",ot.kml)):"clampToSeaFloor"===T?window.console.log("KML - altitudeMode clampToSeaFloor is currently not supported, treating as clampToGround."):l(T)&&window.console.log("KML - Unknown altitudeMode: "+T))}function Ye(e,t,r,i,n,o,a){window.console.log("KML - Unsupported feature: "+r.localName)}function Xe(e,t,r,i,n,o,a){var s=Ge(e,t,r,i,n,o,a),u=s.entity,c=ue(r,"Link",ot.kml);if(l(c)){var h=pe(c,"href",ot.kml);if(l(h)){h=fe(h,void 0,o,a);var d=new ct(e._proxy),p=D(d.load(h),function(){for(var t=d.entities.values,r=0;r<t.length;r++)e._entityCollection.suspendEvents(),t[r].parent=u,e._entityCollection.add(t[r]),e._entityCollection.resumeEvents()});e._promises.push(p)}}}function Ze(e,t,r,i,n,o,a){var s=ut[t.localName];l(s)?s(e,r,t,i,n,o,a):window.console.log("KML - Unsupported feature node: "+t.localName)}function Ke(e,t,r,o){var a=e._entityCollection;e._promises=[],a.removeAll();var s=t.documentElement,u="Document"===s.localName?s:ue(s,"Document",ot.kml),c=pe(u,"name",ot.kml);!l(c)&&l(r)&&(c=m(r));var h=new z(e);return D.all(Pe(e,t,h,r,!1,o),function(){var s=t.documentElement;if("kml"===s.localName)for(var u=s.childNodes,d=0;d<u.length;d++){var p=u[d];if(l(ut[p.localName])){s=p;break}}return Ze(e,s,void 0,a,h,r,o),D.all(e._promises,function(){var t,r=a.computeAvailability(),o=r.start,s=r.stop,l=v.equals(o,f.MINIMUM_VALUE),u=v.equals(s,f.MAXIMUM_VALUE);if(!l||!u){var h;l&&(h=new Date,h.setHours(0,0,0,0),o=v.fromDate(h)),u&&(h=new Date,h.setHours(24,0,0,0),s=v.fromDate(h)),t=new B,t.startTime=o,t.stopTime=s,t.currentTime=v.clone(o),t.clockRange=i.LOOP_STOP,t.clockStep=n.SYSTEM_CLOCK_MULTIPLIER,t.multiplier=Math.round(Math.min(Math.max(v.secondsDifference(s,o)/60,1),31556900))}var d=!1;return e._name!==c&&(e._name=c,d=!0),t!==e._clock&&(d=!0,e._clock=t),d&&e._changed.raiseEvent(e),F.setLoading(e,!1),e})})}function Je(e,t,r){var i=D.defer();return R.createReader(new R.BlobReader(t),function(t){t.getEntries(function(n){for(var o=[],a=!1,s={},u=0;u<n.length;u++){var c=n[u];if(!c.directory){var h=D.defer();o.push(h.promise),!a&&/\.kml$/i.test(c.filename)?(a=!0,$(t,c,s,h)):ee(t,c,s,h)}}D.all(o).then(function(){return t.close(),l(s.kml)?(s.keys=Object.keys(s),Ke(e,s.kml,r,s)):void i.reject(new T("KMZ file does not contain a KML document."))}).then(i.resolve).otherwise(i.reject)})},function(e){i.reject(e)}),i.promise}if("undefined"==typeof DOMParser)return{};var Qe={avi:"video/x-msvideo",bmp:"image/bmp",bz2:"application/x-bzip2",chm:"application/vnd.ms-htmlhelp",css:"text/css",csv:"text/csv",doc:"application/msword",dvi:"application/x-dvi",eps:"application/postscript",flv:"video/x-flv",gif:"image/gif",gz:"application/x-gzip",htm:"text/html",html:"text/html",ico:"image/vnd.microsoft.icon",jnlp:"application/x-java-jnlp-file",jpeg:"image/jpeg",jpg:"image/jpeg",m3u:"audio/x-mpegurl",m4v:"video/mp4",mathml:"application/mathml+xml",mid:"audio/midi",midi:"audio/midi",mov:"video/quicktime",mp3:"audio/mpeg",mp4:"video/mp4",mp4v:"video/mp4",mpeg:"video/mpeg",mpg:"video/mpeg",odp:"application/vnd.oasis.opendocument.presentation",ods:"application/vnd.oasis.opendocument.spreadsheet",odt:"application/vnd.oasis.opendocument.text",ogg:"application/ogg",pdf:"application/pdf",png:"image/png",pps:"application/vnd.ms-powerpoint",ppt:"application/vnd.ms-powerpoint",ps:"application/postscript",qt:"video/quicktime",rdf:"application/rdf+xml",rss:"application/rss+xml",rtf:"application/rtf",svg:"image/svg+xml",swf:"application/x-shockwave-flash",text:"text/plain",tif:"image/tiff",tiff:"image/tiff",txt:"text/plain",wav:"audio/x-wav",wma:"audio/x-ms-wma",wmv:"video/x-ms-wmv",xml:"application/xml",zip:"application/zip",detectFromFilename:function(e){var t=e.toLowerCase();return t=t.substr(t.lastIndexOf(".")+1),Qe[t]}},$e=new DOMParser,et=new I({stripPrefix:!1,twitter:!1,email:!1,replaceFn:function(e,t){return t.protocolUrlMatch?void 0:!1}}),tt=32,rt=[null,void 0,"http://www.opengis.net/kml/2.2","http://earth.google.com/kml/2.2","http://earth.google.com/kml/2.1","http://earth.google.com/kml/2.0"],it=["http://www.google.com/kml/ext/2.2"],nt=["http://www.w3.org/2005/Atom"],ot={kml:rt,gx:it,atom:nt,kmlgx:rt.concat(it)},at={},st=document.createElement("div"),lt={Point:Oe,LineString:Ne,LinearRing:Ne,Polygon:Le,Track:Fe,MultiTrack:Ve,MultiGeometry:ze},ut={Document:We,Folder:He,Placemark:qe,NetworkLink:Xe,GroundOverlay:je,PhotoOverlay:Ye,ScreenOverlay:Ye},ct=function(e){this._changed=new p,this._error=new p,this._loading=new p,this._clock=void 0,this._entityCollection=new z(this),this._name=void 0,this._isLoading=!1,this._proxy=e,this._pinBuilder=new E,this._promises=[]};ct.load=function(e,t){t=s(t,s.EMPTY_OBJECT);var r=new ct(t.proxy);return r.load(e,t)},c(ct.prototype,{name:{get:function(){return this._name}},clock:{get:function(){return this._clock}},entities:{get:function(){return this._entityCollection}},isLoading:{get:function(){return this._isLoading}},changedEvent:{get:function(){return this._changed}},errorEvent:{get:function(){return this._error}},loadingEvent:{get:function(){return this._loading}}}),ct.prototype.load=function(e,t){F.setLoading(this,!0),t=s(t,s.EMPTY_OBJECT);var r=t.sourceUri,i=e;"string"==typeof e&&(i=_(re(e,this._proxy)),r=s(r,e));var n=this;return D(i,function(e){return e instanceof Blob?J(e).then(function(t){return t?Je(n,e,r):D(Q(e)).then(function(e){var t,i;try{t=$e.parseFromString(e,"application/xml")}catch(o){i=o.toString()}if(l(i)||t.body||"parsererror"===t.documentElement.tagName){var a=l(i)?i:t.documentElement.firstChild.nodeValue;throw a||(a=t.body.innerText),new T(a)}return Ke(n,t,r,void 0)})}):D(Ke(n,e,r,void 0))}).otherwise(function(e){return F.setLoading(n,!1),n._error.raiseEvent(n,e),window.console.log(e),D.reject(e)})};var ht=function(){this.author={name:void 0,uri:void 0,email:void 0},this.link={href:void 0,hreflang:void 0,rel:void 0,type:void 0,title:void 0,length:void 0},this.address=void 0,this.phoneNumber=void 0,this.snippet=void 0,this.extendedData=void 0};return ct}),r("DataSources/PolylineArrowMaterialProperty",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","./ConstantProperty","./createPropertyDescriptor","./Property"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e){this._definitionChanged=new n,this._color=void 0,this._colorSubscription=void 0,this.color=e};return r(l.prototype,{isConstant:{get:function(){return s.isConstant(this._color)}},definitionChanged:{get:function(){return this._definitionChanged}},color:a("color")}),l.prototype.getType=function(e){return"PolylineArrow"},l.prototype.getValue=function(r,i){return t(i)||(i={}),i.color=s.getValueOrClonedDefault(this._color,r,e.WHITE,i.color),i},l.prototype.equals=function(e){return this===e||e instanceof l&&s.equals(this._color,e._color)},l}),r("DataSources/PropertyArray",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/EventHelper","./Property"],function(e,t,r,i,n,o){"use strict";var a=function(e){this._value=void 0,this._definitionChanged=new i,this._eventHelper=new n,this.setValue(e)};return t(a.prototype,{isConstant:{get:function(){var t=this._value;if(!e(t))return!0;for(var r=t.length,i=0;r>i;i++)if(!o.isConstant(t[i]))return!1;return!0}},definitionChanged:{get:function(){return this._definitionChanged}}}),a.prototype.getValue=function(t,r){var i=this._value;if(!e(i))return void 0;var n=i.length;e(r)||(r=new Array(n));for(var o=0,a=0;n>o;){var s=this._value[o],l=s.getValue(t,r[o]);e(l)&&(r[a]=l,a++),o++}return r.length=a,r},a.prototype.setValue=function(t){var r=this._eventHelper;if(r.removeAll(),e(t)){this._value=t.slice();for(var i=t.length,n=0;i>n;n++){var o=t[n];e(o)&&r.add(o.definitionChanged,a.prototype._raiseDefinitionChanged,this)}}else this._value=void 0;this._definitionChanged.raiseEvent(this)},a.prototype.equals=function(e){return this===e||e instanceof a&&o.arrayEquals(this._value,e._value)},a.prototype._raiseDefinitionChanged=function(){this._definitionChanged.raiseEvent(this)},a}),r("DataSources/VelocityOrientationProperty",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Ellipsoid","../Core/Event","../Core/JulianDate","../Core/Matrix3","../Core/Quaternion","../Core/Transforms","./Property"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";var d=function(e,r){this._position=void 0,this._subscription=void 0,this._ellipsoid=void 0,this._definitionChanged=new a,this.position=e,this.ellipsoid=t(r,o.WGS84)};i(d.prototype,{isConstant:{get:function(){return h.isConstant(this._position)}},definitionChanged:{get:function(){return this._definitionChanged}},position:{get:function(){return this._position},set:function(e){var t=this._position;t!==e&&(r(t)&&this._subscription(),this._position=e,r(e)&&(this._subscription=e._definitionChanged.addEventListener(function(){this._definitionChanged.raiseEvent(this)},this)),this._definitionChanged.raiseEvent(this))}},ellipsoid:{get:function(){return this._ellipsoid},set:function(e){var t=this._ellipsoid;t!==e&&(this._ellipsoid=e,this._definitionChanged.raiseEvent(this))}}});var p=new e,m=new e,f=new e,v=new s,_=new l,g=1/60;return d.prototype.getValue=function(t,i){var n=this._position;if(h.isConstant(n))return void 0;var o=n.getValue(t,p),a=n.getValue(s.addSeconds(t,g,v),m);if(!r(o))return void 0;if(!r(a)&&(a=o,o=n.getValue(s.addSeconds(t,-g,v),m),!r(o)))return void 0;if(e.equals(o,a))return void 0;var l=e.subtract(a,o,f);e.normalize(l,l);c.rotationMatrixFromPositionVelocity(o,l,this._ellipsoid,_);return u.fromRotationMatrix(_,i)},d.prototype.equals=function(e){return this===e||e instanceof d&&h.equals(this._position,e._position)&&(this._ellipsoid===e._ellipsoid||this._ellipsoid.equals(e._ellipsoid))},d}),r("DataSources/Visualizer",["../Core/DeveloperError"],function(e){"use strict";var t=function(){e.throwInstantiationError()};return t.prototype.update=e.throwInstantiationError,t.prototype.getBoundingSphere=e.throwInstantiationError,t.prototype.isDestroyed=e.throwInstantiationError,t.prototype.destroy=e.throwInstantiationError,t}),r("Renderer/ClearCommand",["../Core/Color","../Core/defaultValue","../Core/freezeObject"],function(e,t,r){"use strict";var i=function(e){e=t(e,t.EMPTY_OBJECT),this.color=e.color,this.depth=e.depth,this.stencil=e.stencil,this.renderState=e.renderState,this.framebuffer=e.framebuffer,this.owner=e.owner};return i.ALL=r(new i({color:new e(0,0,0,0),depth:1,stencil:0})),i.prototype.execute=function(e,t){e.clear(this,t)},i}),r("Renderer/ComputeCommand",["../Core/defaultValue","../Core/PrimitiveType","../Scene/Pass"],function(e,t,r){"use strict";var i=function(t){t=e(t,e.EMPTY_OBJECT),this.vertexArray=t.vertexArray,this.fragmentShaderSource=t.fragmentShaderSource,this.shaderProgram=t.shaderProgram,this.uniformMap=t.uniformMap,this.outputTexture=t.outputTexture,this.preExecute=t.preExecute,this.postExecute=t.postExecute,this.persists=e(t.persists,!1),this.pass=r.COMPUTE,this.owner=t.owner};return i.prototype.execute=function(e){e.execute(this)},i}),r("Shaders/ViewportQuadVS",[],function(){"use strict";return"attribute vec4 position;\nattribute vec2 textureCoordinates;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_Position = position;\nv_textureCoordinates = textureCoordinates;\n}\n"}),r("Renderer/ComputeEngine",["../Core/BoundingRectangle","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Geometry","../Core/GeometryAttribute","../Core/PrimitiveType","../Shaders/ViewportQuadVS","./BufferUsage","./ClearCommand","./DrawCommand","./Framebuffer","./RenderState","./ShaderProgram"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,t){return new f({context:e,colorTextures:[t],destroyAttachments:!1})}function y(e,t){return _.fromCache({context:e,vertexShaderSource:h,fragmentShaderSource:t,attributeLocations:{position:0,textureCoordinates:1}})}function C(t,r){return n(E)&&E.viewport.width===t&&E.viewport.height===r||(E=v.fromCache({viewport:new e(0,0,t,r)})),E}var E,S=function(e){this._context=e},w=new m({primitiveType:c.TRIANGLES}),T=new p({color:new t(0,0,0,0)});return S.prototype.execute=function(e){n(e.preExecute)&&e.preExecute(e);var t=e.outputTexture,r=t.width,i=t.height,o=this._context,a=n(e.vertexArray)?e.vertexArray:o.getViewportQuadVertexArray(),s=n(e.shaderProgram)?e.shaderProgram:y(o,e.fragmentShaderSource),l=g(o,t),u=C(r,i),c=e.uniformMap,h=T;h.framebuffer=l,h.renderState=u,h.execute(o);var d=w;d.vertexArray=a,d.renderState=u,d.shaderProgram=s,d.uniformMap=c,d.framebuffer=l,d.execute(o),l.destroy(),e.persists||(s.destroy(),n(e.vertexArray)&&a.destroy()),n(e.postExecute)&&e.postExecute(t)},S.prototype.isDestroyed=function(){return!1},S.prototype.destroy=function(){return a(this)},S}),r("Renderer/PassState",[],function(){"use strict";var e=function(e){this.context=e,this.framebuffer=void 0,this.blendingEnabled=void 0,this.scissorTest=void 0};return e}),r("Renderer/RenderbufferFormat",["../Core/freezeObject","./WebGLConstants"],function(e,t){"use strict";var r={RGBA4:t.RGBA4,RGB5_A1:t.RGB5_A1,RGB565:t.RGB565,DEPTH_COMPONENT16:t.DEPTH_COMPONENT16,STENCIL_INDEX8:t.STENCIL_INDEX8,DEPTH_STENCIL:t.DEPTH_STENCIL,validate:function(e){return e===r.RGBA4||e===r.RGB5_A1||e===r.RGB565||e===r.DEPTH_COMPONENT16||e===r.STENCIL_INDEX8||e===r.DEPTH_STENCIL}};return e(r)}),r("Renderer/Renderbuffer",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","./ContextLimits","./RenderbufferFormat"],function(e,t,r,i,n,o,a){"use strict";function s(r){r=e(r,e.EMPTY_OBJECT);var i=r.context,n=i._gl,s=(o.maximumRenderbufferSize,e(r.format,a.RGBA4)),l=t(r.width)?r.width:n.drawingBufferWidth,u=t(r.height)?r.height:n.drawingBufferHeight;this._gl=n,this._format=s,this._width=l,this._height=u,this._renderbuffer=this._gl.createRenderbuffer(),n.bindRenderbuffer(n.RENDERBUFFER,this._renderbuffer),n.renderbufferStorage(n.RENDERBUFFER,s,l,u),n.bindRenderbuffer(n.RENDERBUFFER,null)}return r(s.prototype,{format:{get:function(){return this._format}},width:{get:function(){return this._width}},height:{get:function(){return this._height}}}),s.prototype._getRenderbuffer=function(){return this._renderbuffer},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this._gl.deleteRenderbuffer(this._renderbuffer),i(this)},s}),r("Renderer/PickFramebuffer",["../Core/BoundingRectangle","../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","./Framebuffer","./PassState","./Renderbuffer","./RenderbufferFormat","./Texture"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(t){var r=new a(t);r.blendingEnabled=!1,r.scissorTest={enabled:!0,rectangle:new e},this._context=t,this._fb=void 0,this._passState=r,this._width=0,this._height=0};c.prototype.begin=function(t){var r=this._context,n=r.drawingBufferWidth,a=r.drawingBufferHeight;return e.clone(t,this._passState.scissorTest.rectangle),i(this._fb)&&this._width===n&&this._height===a||(this._width=n,this._height=a,this._fb=this._fb&&this._fb.destroy(),this._fb=new o({context:r,colorTextures:[new u({context:r,width:n,height:a})],depthStencilRenderbuffer:new s({context:r,format:l.DEPTH_STENCIL})}),this._passState.framebuffer=this._fb),this._passState};var h=new t;return c.prototype.end=function(e){for(var n=r(e.width,1),o=r(e.height,1),a=this._context,s=a.readPixels({x:e.x,y:e.y,width:n,height:o,framebuffer:this._fb}),l=Math.max(n,o),u=l*l,c=Math.floor(.5*n),d=Math.floor(.5*o),p=0,m=0,f=0,v=-1,_=0;u>_;++_){if(p>=-c&&c>=p&&m>=-d&&d>=m){var g=4*((d-m)*n+p+c);h.red=t.byteToFloat(s[g]),h.green=t.byteToFloat(s[g+1]),h.blue=t.byteToFloat(s[g+2]),h.alpha=t.byteToFloat(s[g+3]);var y=a.getObjectByPickColor(h);if(i(y))return y}if(p===m||0>p&&-p===m||p>0&&p===1-m){var C=f;f=-v,v=C}p+=f,m+=v}return void 0},c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return this._fb=this._fb&&this._fb.destroy(),n(this)},c}),r("Renderer/ShaderCache",["../Core/defined","../Core/defineProperties","../Core/destroyObject","./ShaderProgram","./ShaderSource"],function(e,t,r,i,n){"use strict";var o=function(e){this._context=e,this._shaders={},this._numberOfShaders=0,this._shadersToRelease={}};return t(o.prototype,{numberOfShaders:{get:function(){return this._numberOfShaders}}}),o.prototype.replaceShaderProgram=function(t){return e(t.shaderProgram)&&t.shaderProgram.destroy(),this.getShaderProgram(t)},o.prototype.getShaderProgram=function(e){var t=e.vertexShaderSource,r=e.fragmentShaderSource,o=e.attributeLocations;"string"==typeof t&&(t=new n({sources:[t]})),"string"==typeof r&&(r=new n({sources:[r]}));var a,s=t.createCombinedVertexShader(),l=r.createCombinedFragmentShader(),u=s+l+JSON.stringify(o);if(this._shaders[u])a=this._shaders[u],delete this._shadersToRelease[u];else{var c=this._context,h=new i({gl:c._gl,logShaderCompilation:c.logShaderCompilation,debugShaders:c.debugShaders,vertexShaderSource:t,vertexShaderText:s,fragmentShaderSource:r,fragmentShaderText:l,attributeLocations:o});a={cache:this,shaderProgram:h,keyword:u,count:0},h._cachedShader=a,this._shaders[u]=a,++this._numberOfShaders}return++a.count,a.shaderProgram},o.prototype.destroyReleasedShaderPrograms=function(){var e=this._shadersToRelease;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];delete this._shaders[r.keyword],r.shaderProgram.finalDestroy(),--this._numberOfShaders}this._shadersToRelease={}},o.prototype.releaseShaderProgram=function(e){if(e){var t=e._cachedShader;t&&0===--t.count&&(this._shadersToRelease[t.keyword]=t)}},o.prototype.isDestroyed=function(){return!1},o.prototype.destroy=function(){var e=this._shaders;for(var t in e)e.hasOwnProperty(t)&&e[t].shaderProgram.finalDestroy();return r(this)},o}),r("Renderer/UniformState",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defined","../Core/defineProperties","../Core/EncodedCartesian3","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Simon1994PlanetaryPositions","../Core/Transforms","../Scene/SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){c.clone(t,e._view),c.getRotation(t,e._viewRotation),e._view3DDirty=!0,e._inverseView3DDirty=!0,e._modelViewDirty=!0,e._modelView3DDirty=!0,e._modelViewRelativeToEyeDirty=!0,e._inverseModelViewDirty=!0,e._inverseModelView3DDirty=!0,e._viewProjectionDirty=!0,e._modelViewProjectionDirty=!0,e._modelViewProjectionRelativeToEyeDirty=!0,e._modelViewInfiniteProjectionDirty=!0,e._normalDirty=!0,e._inverseNormalDirty=!0,e._normal3DDirty=!0,e._inverseNormal3DDirty=!0}function f(e,t){c.clone(t,e._inverseView),c.getRotation(t,e._inverseViewRotation)}function v(e,t){c.clone(t,e._projection),e._inverseProjectionDirty=!0,e._inverseProjectionOITDirty=!0,e._viewProjectionDirty=!0,e._modelViewProjectionDirty=!0,e._modelViewProjectionRelativeToEyeDirty=!0}function _(e,t){c.clone(t,e._infiniteProjection),e._modelViewInfiniteProjectionDirty=!0}function g(e,t){r.clone(t.positionWC,e._cameraPosition),r.clone(t.directionWC,e._cameraDirection),r.clone(t.rightWC,e._cameraRight),r.clone(t.upWC,e._cameraUp),e._encodedCameraPositionMCDirty=!0}function y(e,t){o(d.computeIcrfToFixedMatrix(t.time,U))||(U=d.computeTemeToPseudoFixedMatrix(t.time,U));var i=h.computeSunPositionInEarthInertialFrame(t.time,e._sunPositionWC);u.multiplyByVector(U,i,i),r.normalize(i,e._sunDirectionWC),i=u.multiplyByVector(e.viewRotation3D,i,e._sunDirectionEC),r.normalize(i,i),i=h.computeMoonPositionInEarthInertialFrame(t.time,e._moonDirectionEC),u.multiplyByVector(U,i,i),u.multiplyByVector(e.viewRotation3D,i,i),r.normalize(i,i);var n=t.mapProjection,a=n.ellipsoid,s=a.cartesianToCartographic(e._sunPositionWC,G);n.project(s,e._sunPositionColumbusView)}function C(e){if(e._viewportDirty){var t=e._viewport;c.computeOrthographicOffCenter(t.x,t.x+t.width,t.y,t.y+t.height,0,1,e._viewportOrthographicMatrix),c.computeViewportTransformation(t,0,1,e._viewportTransformation),e._viewportDirty=!1}}function E(e){e._inverseProjectionDirty&&(e._inverseProjectionDirty=!1,c.inverse(e._projection,e._inverseProjection))}function S(e){e._inverseProjectionOITDirty&&(e._inverseProjectionOITDirty=!1,e._mode!==p.SCENE2D&&e._mode!==p.MORPHING?c.inverse(e._projection,e._inverseProjectionOIT):c.clone(c.IDENTITY,e._inverseProjectionOIT))}function w(e){e._modelViewDirty&&(e._modelViewDirty=!1,c.multiplyTransformation(e._view,e._model,e._modelView))}function T(e){e._modelView3DDirty&&(e._modelView3DDirty=!1,c.multiplyTransformation(e.view3D,e._model,e._modelView3D))}function b(e){e._inverseModelViewDirty&&(e._inverseModelViewDirty=!1,c.inverse(e.modelView,e._inverseModelView))}function x(e){e._inverseModelView3DDirty&&(e._inverseModelView3DDirty=!1,c.inverse(e.modelView3D,e._inverseModelView3D))}function P(e){e._viewProjectionDirty&&(e._viewProjectionDirty=!1,c.multiply(e._projection,e._view,e._viewProjection))}function A(e){e._inverseViewProjectionDirty&&(e._inverseViewProjectionDirty=!1,c.inverse(e.viewProjection,e._inverseViewProjection))}function I(e){e._modelViewProjectionDirty&&(e._modelViewProjectionDirty=!1,c.multiply(e._projection,e.modelView,e._modelViewProjection))}function M(e){if(e._modelViewRelativeToEyeDirty){e._modelViewRelativeToEyeDirty=!1;var t=e.modelView,r=e._modelViewRelativeToEye;r[0]=t[0],r[1]=t[1],r[2]=t[2],r[3]=t[3],r[4]=t[4],r[5]=t[5],r[6]=t[6],r[7]=t[7],r[8]=t[8],r[9]=t[9],r[10]=t[10],r[11]=t[11],r[12]=0,r[13]=0,r[14]=0,r[15]=t[15]}}function D(e){e._inverseModelViewProjectionDirty&&(e._inverseModelViewProjectionDirty=!1,c.inverse(e.modelViewProjection,e._inverseModelViewProjection))}function R(e){e._modelViewProjectionRelativeToEyeDirty&&(e._modelViewProjectionRelativeToEyeDirty=!1,c.multiply(e._projection,e.modelViewRelativeToEye,e._modelViewProjectionRelativeToEye))}function O(e){e._modelViewInfiniteProjectionDirty&&(e._modelViewInfiniteProjectionDirty=!1,c.multiply(e._infiniteProjection,e.modelView,e._modelViewInfiniteProjection))}function N(e){if(e._normalDirty){e._normalDirty=!1;var t=e._normal;c.getRotation(e.inverseModelView,t),u.transpose(t,t)}}function L(e){if(e._normal3DDirty){e._normal3DDirty=!1;var t=e._normal3D;c.getRotation(e.inverseModelView3D,t),u.transpose(t,t)}}function F(e){e._inverseNormalDirty&&(e._inverseNormalDirty=!1,c.getRotation(e.inverseModelView,e._inverseNormal))}function B(e){e._inverseNormal3DDirty&&(e._inverseNormal3DDirty=!1,c.getRotation(e.inverseModelView3D,e._inverseNormal3D))}function V(e){e._encodedCameraPositionMCDirty&&(e._encodedCameraPositionMCDirty=!1,c.multiplyByPoint(e.inverseModel,e._cameraPosition,W),s.fromCartesian(W,e._encodedCameraPositionMC))}function z(e,t,i,n,a,s,u,h){var m=H;m.x=e.y,m.y=e.z,m.z=e.x;var f=q;f.x=i.y,f.y=i.z,f.z=i.x;var v=j;v.x=n.y,v.y=n.z,v.z=n.x;var _=Y;_.x=t.y,_.y=t.z,_.z=t.x,s===p.SCENE2D&&(m.z=.5*a);var g=u.unproject(m,X);g.longitude=l.clamp(g.longitude,-Math.PI,Math.PI),g.latitude=l.clamp(g.latitude,-l.PI_OVER_TWO,l.PI_OVER_TWO);var y=u.ellipsoid,C=y.cartographicToCartesian(g,Z),E=d.eastNorthUpToFixedFrame(C,y,K);return c.multiplyByPointAsVector(E,f,f),c.multiplyByPointAsVector(E,v,v),c.multiplyByPointAsVector(E,_,_),o(h)||(h=new c),h[0]=f.x,h[1]=v.x,h[2]=-_.x,h[3]=0,h[4]=f.y,h[5]=v.y,h[6]=-_.y,h[7]=0,h[8]=f.z,h[9]=v.z,h[10]=-_.z,h[11]=0,h[12]=-r.dot(f,C),h[13]=-r.dot(v,C),h[14]=r.dot(_,C),h[15]=1,h}var k=function(){this.globeDepthTexture=void 0,this._viewport=new e,this._viewportCartesian4=new i,this._viewportDirty=!1,this._viewportOrthographicMatrix=c.clone(c.IDENTITY),this._viewportTransformation=c.clone(c.IDENTITY),this._model=c.clone(c.IDENTITY),this._view=c.clone(c.IDENTITY),this._inverseView=c.clone(c.IDENTITY),this._projection=c.clone(c.IDENTITY),this._infiniteProjection=c.clone(c.IDENTITY),this._entireFrustum=new t,this._currentFrustum=new t,this._frustumPlanes=new i,this._frameState=void 0,this._temeToPseudoFixed=u.clone(c.IDENTITY),this._view3DDirty=!0,this._view3D=new c,this._inverseView3DDirty=!0,this._inverseView3D=new c,this._inverseModelDirty=!0,this._inverseModel=new c,this._inverseTransposeModelDirty=!0,this._inverseTransposeModel=new u,this._viewRotation=new u,this._inverseViewRotation=new u,this._viewRotation3D=new u,this._inverseViewRotation3D=new u,this._inverseProjectionDirty=!0,this._inverseProjection=new c,this._inverseProjectionOITDirty=!0,this._inverseProjectionOIT=new c,this._modelViewDirty=!0,this._modelView=new c,this._modelView3DDirty=!0,this._modelView3D=new c,this._modelViewRelativeToEyeDirty=!0,this._modelViewRelativeToEye=new c,this._inverseModelViewDirty=!0,this._inverseModelView=new c,this._inverseModelView3DDirty=!0,this._inverseModelView3D=new c,this._viewProjectionDirty=!0,this._viewProjection=new c,this._inverseViewProjectionDirty=!0,this._inverseViewProjection=new c,this._modelViewProjectionDirty=!0,this._modelViewProjection=new c,this._inverseModelViewProjectionDirty=!0,this._inverseModelViewProjection=new c,this._modelViewProjectionRelativeToEyeDirty=!0,this._modelViewProjectionRelativeToEye=new c,this._modelViewInfiniteProjectionDirty=!0,this._modelViewInfiniteProjection=new c,this._normalDirty=!0,this._normal=new u,this._normal3DDirty=!0,this._normal3D=new u,this._inverseNormalDirty=!0,this._inverseNormal=new u,this._inverseNormal3DDirty=!0,this._inverseNormal3D=new u,this._encodedCameraPositionMCDirty=!0,this._encodedCameraPositionMC=new s,this._cameraPosition=new r,this._sunPositionWC=new r,this._sunPositionColumbusView=new r,this._sunDirectionWC=new r,this._sunDirectionEC=new r,this._moonDirectionEC=new r,this._mode=void 0,this._mapProjection=void 0,this._cameraDirection=new r,this._cameraRight=new r,this._cameraUp=new r,this._frustum2DWidth=0,this._eyeHeight2D=new t,this._resolutionScale=1,this._fogDensity=void 0};a(k.prototype,{frameState:{get:function(){return this._frameState}},viewport:{get:function(){return this._viewport},set:function(t){if(!e.equals(t,this._viewport)){e.clone(t,this._viewport);var r=this._viewport,i=this._viewportCartesian4;i.x=r.x,i.y=r.y,i.z=r.width,i.w=r.height,this._viewportDirty=!0}}},viewportCartesian4:{get:function(){return this._viewportCartesian4}},viewportOrthographic:{get:function(){return C(this),this._viewportOrthographicMatrix}},viewportTransformation:{get:function(){return C(this),this._viewportTransformation}},model:{get:function(){return this._model},set:function(e){c.clone(e,this._model),this._modelView3DDirty=!0,this._inverseModelView3DDirty=!0,this._inverseModelDirty=!0,this._inverseTransposeModelDirty=!0,this._modelViewDirty=!0,this._inverseModelViewDirty=!0,this._viewProjectionDirty=!0,this._inverseViewProjectionDirty=!0,this._modelViewRelativeToEyeDirty=!0,this._inverseModelViewDirty=!0,this._modelViewProjectionDirty=!0,this._inverseModelViewProjectionDirty=!0,this._modelViewProjectionRelativeToEyeDirty=!0,this._modelViewInfiniteProjectionDirty=!0,this._normalDirty=!0,this._inverseNormalDirty=!0,this._normal3DDirty=!0,this._inverseNormal3DDirty=!0,this._encodedCameraPositionMCDirty=!0}},inverseModel:{get:function(){return this._inverseModelDirty&&(this._inverseModelDirty=!1,c.inverse(this._model,this._inverseModel)),this._inverseModel}},inverseTranposeModel:{get:function(){var e=this._inverseTransposeModel;return this._inverseTransposeModelDirty&&(this._inverseTransposeModelDirty=!1,c.getRotation(this.inverseModel,e),u.transpose(e,e)),e}},view:{get:function(){return this._view}},view3D:{get:function(){return this._view3DDirty&&(this._mode===p.SCENE3D?c.clone(this._view,this._view3D):z(this._cameraPosition,this._cameraDirection,this._cameraRight,this._cameraUp,this._frustum2DWidth,this._mode,this._mapProjection,this._view3D),c.getRotation(this._view3D,this._viewRotation3D),this._view3DDirty=!1),this._view3D}},viewRotation:{get:function(){return this._viewRotation}},viewRotation3D:{get:function(){this.view3D;return this._viewRotation3D}},inverseView:{get:function(){return this._inverseView}},inverseView3D:{get:function(){return this._inverseView3DDirty&&(c.inverseTransformation(this.view3D,this._inverseView3D),c.getRotation(this._inverseView3D,this._inverseViewRotation3D),this._inverseView3DDirty=!1),this._inverseView3D}},inverseViewRotation:{get:function(){return this._inverseViewRotation}},inverseViewRotation3D:{get:function(){this.inverseView3D;return this._inverseViewRotation3D}},projection:{get:function(){return this._projection}},inverseProjection:{get:function(){return E(this),this._inverseProjection}},inverseProjectionOIT:{get:function(){return S(this),this._inverseProjectionOIT}},infiniteProjection:{get:function(){return this._infiniteProjection}},modelView:{get:function(){return w(this),this._modelView}},modelView3D:{get:function(){return T(this),this._modelView3D}},modelViewRelativeToEye:{get:function(){return M(this),this._modelViewRelativeToEye}},inverseModelView:{get:function(){return b(this),this._inverseModelView}},inverseModelView3D:{get:function(){return x(this),this._inverseModelView3D}},viewProjection:{get:function(){return P(this),this._viewProjection}},inverseViewProjection:{get:function(){return A(this),this._inverseViewProjection}},modelViewProjection:{get:function(){return I(this),this._modelViewProjection}},inverseModelViewProjection:{get:function(){return D(this),this._inverseModelViewProjection}},modelViewProjectionRelativeToEye:{get:function(){return R(this),this._modelViewProjectionRelativeToEye}},modelViewInfiniteProjection:{get:function(){return O(this),this._modelViewInfiniteProjection}},normal:{get:function(){return N(this),this._normal}},normal3D:{get:function(){return L(this),this._normal3D}},inverseNormal:{get:function(){return F(this),this._inverseNormal}},inverseNormal3D:{get:function(){return B(this),this._inverseNormal3D}},entireFrustum:{get:function(){return this._entireFrustum}},currentFrustum:{get:function(){return this._currentFrustum}},frustumPlanes:{get:function(){return this._frustumPlanes}},eyeHeight2D:{get:function(){return this._eyeHeight2D}},sunPositionWC:{get:function(){return this._sunPositionWC}},sunPositionColumbusView:{get:function(){return this._sunPositionColumbusView}},sunDirectionWC:{get:function(){return this._sunDirectionWC}},sunDirectionEC:{get:function(){return this._sunDirectionEC}},moonDirectionEC:{get:function(){return this._moonDirectionEC}},encodedCameraPositionMCHigh:{get:function(){return V(this),this._encodedCameraPositionMC.high}},encodedCameraPositionMCLow:{get:function(){return V(this),this._encodedCameraPositionMC.low}},temeToPseudoFixedMatrix:{get:function(){return this._temeToPseudoFixed}},resolutionScale:{get:function(){return this._resolutionScale}},fogDensity:{get:function(){return this._fogDensity}}});var U=new u,G=new n;k.prototype.updateFrustum=function(e){v(this,e.projectionMatrix),o(e.infiniteProjectionMatrix)&&_(this,e.infiniteProjectionMatrix),this._currentFrustum.x=e.near,this._currentFrustum.y=e.far,o(e.top)||(e=e._offCenterFrustum),this._frustumPlanes.x=e.top,this._frustumPlanes.y=e.bottom,this._frustumPlanes.z=e.left,this._frustumPlanes.w=e.right},k.prototype.update=function(e){this._mode=e.mode,this._mapProjection=e.mapProjection;var t=e.context._canvas;this._resolutionScale=t.width/t.clientWidth;var r=e.camera;m(this,r.viewMatrix),f(this,r.inverseViewMatrix),g(this,r),e.mode===p.SCENE2D?(this._frustum2DWidth=r.frustum.right-r.frustum.left,this._eyeHeight2D.x=.5*this._frustum2DWidth,this._eyeHeight2D.y=this._eyeHeight2D.x*this._eyeHeight2D.x):(this._frustum2DWidth=0,this._eyeHeight2D.x=0,this._eyeHeight2D.y=0),y(this,e),this._entireFrustum.x=r.frustum.near,this._entireFrustum.y=r.frustum.far,this.updateFrustum(r.frustum),this._fogDensity=e.fog.density,this._frameState=e,this._temeToPseudoFixed=d.computeTemeToPseudoFixedMatrix(e.time,this._temeToPseudoFixed); -};var W=new r,H=new r,q=new r,j=new r,Y=new r,X=new n,Z=new r,K=new c;return k}),r("Renderer/Context",["../Core/clone","../Core/Color","../Core/ComponentDatatype","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/FeatureDetection","../Core/Geometry","../Core/GeometryAttribute","../Core/Math","../Core/Matrix4","../Core/PrimitiveType","../Core/RuntimeError","../Shaders/ViewportQuadVS","./BufferUsage","./ClearCommand","./ContextLimits","./CubeMap","./DrawCommand","./PassState","./PickFramebuffer","./PixelDatatype","./RenderbufferFormat","./RenderState","./ShaderCache","./ShaderProgram","./Texture","./UniformState","./VertexArray","./WebGLConstants"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R){"use strict";function O(e,t){var r="WebGL Error: ";switch(t){case e.INVALID_ENUM:r+="INVALID_ENUM";break;case e.INVALID_VALUE:r+="INVALID_VALUE";break;case e.INVALID_OPERATION:r+="INVALID_OPERATION";break;case e.OUT_OF_MEMORY:r+="OUT_OF_MEMORY";break;case e.CONTEXT_LOST_WEBGL:r+="CONTEXT_LOST_WEBGL lost";break;default:r+="Unknown ("+t+")"}return r}function N(e,t,r,i){for(var n=O(e,i)+": "+t.name+"(",o=0;o<r.length;++o)0!==o&&(n+=", "),n+=r[o];return n+=");"}function L(e,t,r){var i=e.getError();if(i!==e.NO_ERROR)throw new f(N(e,t,r,i))}function F(e,t,r){return{get:function(){var i=e[t];return r(e,"get: "+t,i),e[t]},set:function(i){e[t]=i,r(e,"set: "+t,i)}}}function B(e,t){function r(r){return function(){var i=r.apply(e,arguments);return t(e,r,arguments),i}}if(!t)return e;var i={};for(var n in e){var o=e[n];"function"==typeof o?i[n]=r(o):Object.defineProperty(i,n,F(e,n,t))}return i}function V(e,t){for(var r=t.length,i=0;r>i;++i){var n=e.getExtension(t[i]);if(n)return n}return void 0}function z(e,t){if(e.validateFramebuffer){var r=e._gl,i=r.checkFramebufferStatus(r.FRAMEBUFFER);if(i!==r.FRAMEBUFFER_COMPLETE){var n;switch(i){case r.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:n="Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format.";break;case r.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:n="Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height.";break;case r.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:n="Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer.";break;case r.FRAMEBUFFER_UNSUPPORTED:n="Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions."}throw new l(n)}}}function k(e,t,r,i){var n=e._currentRenderState,o=e._currentPassState;e._currentRenderState=t,e._currentPassState=r,x.partialApply(e._gl,n,t,o,r,i)}function U(e,t){if(t!==e._currentFramebuffer){e._currentFramebuffer=t;var r=Y;if(o(t))t._bind(),z(e,t),r=t._getActiveColorAttachments();else{var i=e._gl;i.bindFramebuffer(i.FRAMEBUFFER,null)}e.drawBuffers&&e.glDrawBuffers(r)}}function G(e,t,r,i,o,a){var s=n(n(o,r.renderState),e._defaultRenderState);U(e,t),k(e,s,i,!1);var l=n(a,r.shaderProgram);l._bind(),e._maxFrameTextureUnitIndex=Math.max(e._maxFrameTextureUnitIndex,l.maximumTextureUnitIndex)}function W(e,t,r){var i=t.primitiveType,a=t.vertexArray,s=t.offset,l=t.count,u=t.instanceCount;e._us.model=n(t.modelMatrix,p.IDENTITY);var c=n(r,t.shaderProgram);c._setUniforms(t.uniformMap,e._us,e.validateShaderProgram),a._bind();var h=a.indexBuffer;o(h)?(s*=h.bytesPerIndex,l=n(l,h.numberOfIndices),0===u?e._gl.drawElements(i,l,h.indexDatatype,s):e.glDrawElementsInstanced(i,l,h.indexDatatype,s,u)):(l=n(l,a.numberOfVertices),0===u?e._gl.drawArrays(i,s,l):e.glDrawArraysInstanced(i,s,l,u)),a._unBind()}function H(e,t,r){this._pickObjects=e,this.key=t,this.color=r}var q=function(r,a){if("undefined"==typeof WebGLRenderingContext)throw new f("The browser does not support WebGL. Visit http://get.webgl.org.");this._canvas=r,a=e(a,!0),a=n(a,{}),a.allowTextureFilterAnisotropic=n(a.allowTextureFilterAnisotropic,!0);var s=n(a.webgl,{});s.alpha=n(s.alpha,!1);var l,u=!1,c="undefined"!=typeof WebGL2RenderingContext,h=!1;if(u&&c&&(l=r.getContext("webgl2",s)||r.getContext("experimental-webgl2",s)||void 0,o(l)&&(h=!0)),o(l)||(l=r.getContext("webgl",s)||r.getContext("experimental-webgl",s)||void 0),!o(l))throw new f("The browser supports WebGL, but initialization failed.");this._originalGLContext=l,this._webgl2=h,this._id=i(),this.validateFramebuffer=!1,this.validateShaderProgram=!1,this.logShaderCompilation=!1,this._throwOnWebGLError=!1,this._shaderCache=new P(this);var d=this._gl=this._originalGLContext;this._redBits=d.getParameter(d.RED_BITS),this._greenBits=d.getParameter(d.GREEN_BITS),this._blueBits=d.getParameter(d.BLUE_BITS),this._alphaBits=d.getParameter(d.ALPHA_BITS),this._depthBits=d.getParameter(d.DEPTH_BITS),this._stencilBits=d.getParameter(d.STENCIL_BITS),y._maximumCombinedTextureImageUnits=d.getParameter(d.MAX_COMBINED_TEXTURE_IMAGE_UNITS),y._maximumCubeMapSize=d.getParameter(d.MAX_CUBE_MAP_TEXTURE_SIZE),y._maximumFragmentUniformVectors=d.getParameter(d.MAX_FRAGMENT_UNIFORM_VECTORS),y._maximumTextureImageUnits=d.getParameter(d.MAX_TEXTURE_IMAGE_UNITS),y._maximumRenderbufferSize=d.getParameter(d.MAX_RENDERBUFFER_SIZE),y._maximumTextureSize=d.getParameter(d.MAX_TEXTURE_SIZE),y._maximumVaryingVectors=d.getParameter(d.MAX_VARYING_VECTORS),y._maximumVertexAttributes=d.getParameter(d.MAX_VERTEX_ATTRIBS),y._maximumVertexTextureImageUnits=d.getParameter(d.MAX_VERTEX_TEXTURE_IMAGE_UNITS),y._maximumVertexUniformVectors=d.getParameter(d.MAX_VERTEX_UNIFORM_VECTORS);var p=d.getParameter(d.ALIASED_LINE_WIDTH_RANGE);y._minimumAliasedLineWidth=p[0],y._maximumAliasedLineWidth=p[1];var m=d.getParameter(d.ALIASED_POINT_SIZE_RANGE);y._minimumAliasedPointSize=m[0],y._maximumAliasedPointSize=m[1];var v=d.getParameter(d.MAX_VIEWPORT_DIMS);y._maximumViewportWidth=v[0],y._maximumViewportHeight=v[1];var _=d.getShaderPrecisionFormat(d.FRAGMENT_SHADER,d.HIGH_FLOAT);y._highpFloatSupported=0!==_.precision;var g=d.getShaderPrecisionFormat(d.FRAGMENT_SHADER,d.HIGH_INT);y._highpIntSupported=0!==g.rangeMax,this._antialias=d.getContextAttributes().antialias,this._standardDerivatives=!!V(d,["OES_standard_derivatives"]),this._elementIndexUint=!!V(d,["OES_element_index_uint"]),this._depthTexture=!!V(d,["WEBGL_depth_texture","WEBKIT_WEBGL_depth_texture"]),this._textureFloat=!!V(d,["OES_texture_float"]),this._fragDepth=!!V(d,["EXT_frag_depth"]),this._debugShaders=V(d,["WEBGL_debug_shaders"]);var C=a.allowTextureFilterAnisotropic?V(d,["EXT_texture_filter_anisotropic","WEBKIT_EXT_texture_filter_anisotropic"]):void 0;this._textureFilterAnisotropic=C,y._maximumTextureFilterAnisotropy=o(C)?d.getParameter(C.MAX_TEXTURE_MAX_ANISOTROPY_EXT):1;var E,w,T,b,A,I,D,O,N,L;if(h){var F=this;E=function(){return F._gl.createVertexArray()},w=function(e){F._gl.bindVertexArray(e)},T=function(e){F._gl.deleteVertexArray(e)},b=function(e,t,r,i,n){d.drawElementsInstanced(e,t,r,i,n)},A=function(e,t,r,i){d.drawArraysInstanced(e,t,r,i)},I=function(e,t){d.vertexAttribDivisor(e,t)},D=function(e){d.drawBuffers(e)}}else O=V(d,["OES_vertex_array_object"]),o(O)&&(E=function(){return O.createVertexArrayOES()},w=function(e){O.bindVertexArrayOES(e)},T=function(e){O.deleteVertexArrayOES(e)}),N=V(d,["ANGLE_instanced_arrays"]),o(N)&&(b=function(e,t,r,i,n){N.drawElementsInstancedANGLE(e,t,r,i,n)},A=function(e,t,r,i){N.drawArraysInstancedANGLE(e,t,r,i)},I=function(e,t){N.vertexAttribDivisorANGLE(e,t)}),L=V(d,["WEBGL_draw_buffers"]),o(L)&&(D=function(e){L.drawBuffersWEBGL(e)});this.glCreateVertexArray=E,this.glBindVertexArray=w,this.glDeleteVertexArray=T,this.glDrawElementsInstanced=b,this.glDrawArraysInstanced=A,this.glVertexAttribDivisor=I,this.glDrawBuffers=D,this._vertexArrayObject=!!O,this._instancedArrays=!!N,this._drawBuffers=!!L,y._maximumDrawBuffers=this.drawBuffers?d.getParameter(R.MAX_DRAW_BUFFERS):1,y._maximumColorAttachments=this.drawBuffers?d.getParameter(R.MAX_COLOR_ATTACHMENTS):1;var B=d.getParameter(d.COLOR_CLEAR_VALUE);this._clearColor=new t(B[0],B[1],B[2],B[3]),this._clearDepth=d.getParameter(d.DEPTH_CLEAR_VALUE),this._clearStencil=d.getParameter(d.STENCIL_CLEAR_VALUE);var z=new M,k=new S(this),U=x.fromCache();this._defaultPassState=k,this._defaultRenderState=U,this._defaultTexture=void 0,this._defaultCubeMap=void 0,this._us=z,this._currentRenderState=U,this._currentPassState=k,this._currentFramebuffer=void 0,this._maxFrameTextureUnitIndex=0,this._vertexAttribDivisors=[],this._previousDrawInstanced=!1;for(var G=0;G<y._maximumVertexAttributes;G++)this._vertexAttribDivisors.push(0);this._pickObjects={},this._nextPickColor=new Uint32Array(1),this.options=a,this.cache={},x.apply(d,U,k)},j={};a(q.prototype,{id:{get:function(){return this._id}},webgl2:{get:function(){return this._webgl2}},canvas:{get:function(){return this._canvas}},shaderCache:{get:function(){return this._shaderCache}},uniformState:{get:function(){return this._us}},redBits:{get:function(){return this._redBits}},greenBits:{get:function(){return this._greenBits}},blueBits:{get:function(){return this._blueBits}},alphaBits:{get:function(){return this._alphaBits}},depthBits:{get:function(){return this._depthBits}},stencilBits:{get:function(){return this._stencilBits}},antialias:{get:function(){return this._antialias}},standardDerivatives:{get:function(){return this._standardDerivatives}},elementIndexUint:{get:function(){return this._elementIndexUint||this._webgl2}},depthTexture:{get:function(){return this._depthTexture}},floatingPointTexture:{get:function(){return this._textureFloat}},textureFilterAnisotropic:{get:function(){return!!this._textureFilterAnisotropic}},vertexArrayObject:{get:function(){return this._vertexArrayObject||this._webgl2}},fragmentDepth:{get:function(){return this._fragDepth}},instancedArrays:{get:function(){return this._instancedArrays||this._webgl2}},drawBuffers:{get:function(){return this._drawBuffers||this._webgl2}},debugShaders:{get:function(){return this._debugShaders}},throwOnWebGLError:{get:function(){return this._throwOnWebGLError},set:function(e){this._throwOnWebGLError=e,this._gl=B(this._originalGLContext,e?L:null)}},defaultTexture:{get:function(){return void 0===this._defaultTexture&&(this._defaultTexture=new I({context:this,source:{width:1,height:1,arrayBufferView:new Uint8Array([255,255,255,255])}})),this._defaultTexture}},defaultCubeMap:{get:function(){if(void 0===this._defaultCubeMap){var e={width:1,height:1,arrayBufferView:new Uint8Array([255,255,255,255])};this._defaultCubeMap=new C({context:this,source:{positiveX:e,negativeX:e,positiveY:e,negativeY:e,positiveZ:e,negativeZ:e}})}return this._defaultCubeMap}},drawingBufferHeight:{get:function(){return this._gl.drawingBufferHeight}},drawingBufferWidth:{get:function(){return this._gl.drawingBufferWidth}},defaultFramebuffer:{get:function(){return j}}});var Y;"undefined"!=typeof WebGLRenderingContext&&(Y=[R.BACK]);var X=new g;q.prototype.clear=function(e,r){e=n(e,X),r=n(r,this._defaultPassState);var i=this._gl,a=0,s=e.color,l=e.depth,u=e.stencil;o(s)&&(t.equals(this._clearColor,s)||(t.clone(s,this._clearColor),i.clearColor(s.red,s.green,s.blue,s.alpha)),a|=i.COLOR_BUFFER_BIT),o(l)&&(l!==this._clearDepth&&(this._clearDepth=l,i.clearDepth(l)),a|=i.DEPTH_BUFFER_BIT),o(u)&&(u!==this._clearStencil&&(this._clearStencil=u,i.clearStencil(u)),a|=i.STENCIL_BUFFER_BIT);var c=n(e.renderState,this._defaultRenderState);k(this,c,r,!0);var h=n(e.framebuffer,r.framebuffer);U(this,h),i.clear(a)},q.prototype.draw=function(e,t,r,i){t=n(t,this._defaultPassState);var o=n(e.framebuffer,t.framebuffer);G(this,o,e,t,r,i),W(this,e,i)},q.prototype.endFrame=function(){var e=this._gl;e.useProgram(null),this._currentFramebuffer=void 0,e.bindFramebuffer(e.FRAMEBUFFER,null);var t=Y;this.drawBuffers&&this.glDrawBuffers(t);var r=this._maxFrameTextureUnitIndex;this._maxFrameTextureUnitIndex=0;for(var i=0;r>i;++i)e.activeTexture(e.TEXTURE0+i),e.bindTexture(e.TEXTURE_2D,null),e.bindTexture(e.TEXTURE_CUBE_MAP,null)},q.prototype.readPixels=function(e){var t=this._gl;e=e||{};var r=Math.max(e.x||0,0),i=Math.max(e.y||0,0),n=e.width||t.drawingBufferWidth,o=e.height||t.drawingBufferHeight,a=e.framebuffer,s=new Uint8Array(4*n*o);return U(this,a),t.readPixels(r,i,n,o,t.RGBA,t.UNSIGNED_BYTE,s),s};var Z={position:0,textureCoordinates:1};return q.prototype.getViewportQuadVertexArray=function(){var e=this.cache.viewportQuad_vertexArray;if(!o(e)){var t=new c({attributes:{position:new h({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:[-1,-1,1,-1,1,1,-1,1]}),textureCoordinates:new h({componentDatatype:r.FLOAT,componentsPerAttribute:2,values:[0,0,1,0,1,1,0,1]})},indices:new Uint16Array([0,1,2,0,2,3]),primitiveType:m.TRIANGLES});e=D.fromGeometry({context:this,geometry:t,attributeLocations:Z,bufferUsage:_.STATIC_DRAW,interleave:!0}),this.cache.viewportQuad_vertexArray=e}return e},q.prototype.createViewportQuadCommand=function(e,t){return t=n(t,n.EMPTY_OBJECT),new E({vertexArray:this.getViewportQuadVertexArray(),primitiveType:m.TRIANGLES,renderState:t.renderState,shaderProgram:A.fromCache({context:this,vertexShaderSource:v,fragmentShaderSource:e,attributeLocations:Z}),uniformMap:t.uniformMap,owner:t.owner,framebuffer:t.framebuffer})},q.prototype.createPickFramebuffer=function(){return new w(this)},q.prototype.getObjectByPickColor=function(e){return this._pickObjects[e.toRgba()]},a(H.prototype,{object:{get:function(){return this._pickObjects[this.key]},set:function(e){this._pickObjects[this.key]=e}}}),H.prototype.destroy=function(){return void delete this._pickObjects[this.key]},q.prototype.createPickId=function(e){++this._nextPickColor[0];var r=this._nextPickColor[0];if(0===r)throw new f("Out of unique Pick IDs.");return this._pickObjects[r]=e,new H(this._pickObjects,r,t.fromRgba(r))},q.prototype.isDestroyed=function(){return!1},q.prototype.destroy=function(){var e=this.cache;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];o(r.destroy)&&r.destroy()}return this._shaderCache=this._shaderCache.destroy(),this._defaultTexture=this._defaultTexture&&this._defaultTexture.destroy(),this._defaultCubeMap=this._defaultCubeMap&&this._defaultCubeMap.destroy(),s(this)},q}),r("Renderer/loadCubeMap",["../Core/defined","../Core/DeveloperError","../Core/loadImage","../ThirdParty/when","./CubeMap"],function(e,t,r,i,n){"use strict";var o=function(e,t,o){var a=[r(t.positiveX,o),r(t.negativeX,o),r(t.positiveY,o),r(t.negativeY,o),r(t.positiveZ,o),r(t.negativeZ,o)];return i.all(a,function(t){return new n({context:e,source:{positiveX:t[0],negativeX:t[1],positiveY:t[2],negativeY:t[3],positiveZ:t[4],negativeZ:t[5]}})})};return o}),r("Scene/DiscardMissingTileImagePolicy",["../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/getImagePixels","../Core/loadImageViaBlob","../ThirdParty/when"],function(e,t,r,i,n,o){"use strict";var a=function(a){function s(e){t(e.blob)&&(u._missingImageByteLength=e.blob.size);var r=i(e);if(a.disableCheckIfAllPixelsAreTransparent){for(var n=!0,o=e.width,s=a.pixelsToCheck,l=0,c=s.length;n&&c>l;++l){var h=s[l],d=4*h.x+h.y*o,p=r[d+3];p>0&&(n=!1)}n&&(r=void 0)}u._missingImagePixels=r,u._isReady=!0}function l(){u._missingImagePixels=void 0,u._isReady=!0}if(a=e(a,e.EMPTY_OBJECT),!t(a.missingImageUrl))throw new r("options.missingImageUrl is required.");if(!t(a.pixelsToCheck))throw new r("options.pixelsToCheck is required.");this._pixelsToCheck=a.pixelsToCheck,this._missingImagePixels=void 0,this._missingImageByteLength=void 0,this._isReady=!1;var u=this;o(n(a.missingImageUrl),s,l)};return a.prototype.isReady=function(){return this._isReady},a.prototype.shouldDiscardImage=function(e){if(!this._isReady)throw new r("shouldDiscardImage must not be called before the discard policy is ready.");var n=this._pixelsToCheck,o=this._missingImagePixels;if(!t(o))return!1;if(t(e.blob)&&e.blob.size!==this._missingImageByteLength)return!1;for(var a=i(e),s=e.width,l=0,u=n.length;u>l;++l)for(var c=n[l],h=4*c.x+c.y*s,d=0;4>d;++d){var p=h+d;if(a[p]!==o[p])return!1}return!0},a}),r("Scene/ImageryLayerFeatureInfo",["../Core/defined"],function(e){"use strict";var t=function(){this.name=void 0,this.description=void 0,this.position=void 0,this.data=void 0,this.imageryLayer=void 0};return t.prototype.configureNameFromProperties=function(t){var r,i=10;for(var n in t)if(t.hasOwnProperty(n)&&t[n]){var o=n.toLowerCase();i>1&&"name"===o?(i=1,r=n):i>2&&"title"===o?(i=2,r=n):i>3&&/name/i.test(n)?(i=3,r=n):i>4&&/title/i.test(n)&&(i=4,r=n)}e(r)&&(this.name=t[r])},t.prototype.configureDescriptionFromProperties=function(t){function r(t){var i='<table class="cesium-infoBox-defaultTable">';for(var n in t)if(t.hasOwnProperty(n)){var o=t[n];e(o)&&(i+="object"==typeof o?"<tr><td>"+n+"</td><td>"+r(o)+"</td></tr>":"<tr><td>"+n+"</td><td>"+o+"</td></tr>")}return i+="</table>"}this.description=r(t)},t}),r("Scene/ImageryProvider",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/loadImage","../Core/loadImageViaBlob","../Core/throttleRequestByServer"],function(e,t,r,i,n,o){"use strict";var a=function(){this.defaultAlpha=void 0,this.defaultBrightness=void 0,this.defaultContrast=void 0,this.defaultHue=void 0,this.defaultSaturation=void 0,this.defaultGamma=void 0,r.throwInstantiationError()};return t(a.prototype,{ready:{get:r.throwInstantiationError},readyPromise:{get:r.throwInstantiationError},rectangle:{get:r.throwInstantiationError},tileWidth:{get:r.throwInstantiationError},tileHeight:{get:r.throwInstantiationError},maximumLevel:{get:r.throwInstantiationError},minimumLevel:{get:r.throwInstantiationError},tilingScheme:{get:r.throwInstantiationError},tileDiscardPolicy:{get:r.throwInstantiationError},errorEvent:{get:r.throwInstantiationError},credit:{get:r.throwInstantiationError},proxy:{get:r.throwInstantiationError},hasAlphaChannel:{get:r.throwInstantiationError}}),a.prototype.getTileCredits=r.throwInstantiationError,a.prototype.requestImage=r.throwInstantiationError,a.prototype.pickFeatures=r.throwInstantiationError,a.prototype.getTileDataAvailable=r.throwInstantiationError,a.loadImage=function(t,r){return e(t.tileDiscardPolicy)?o(r,n):o(r,i)},a}),r("Scene/ArcGisMapServerImageryProvider",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicProjection","../Core/GeographicTilingScheme","../Core/loadJson","../Core/loadJsonp","../Core/Math","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorProjection","../Core/WebMercatorTilingScheme","../ThirdParty/when","./DiscardMissingTileImagePolicy","./ImageryLayerFeatureInfo","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";function w(e,t,r,i){var n;if(e._useTiles)n=e._url+"/tile/"+i+"/"+r+"/"+t;else{var a=e._tilingScheme.tileXYToNativeRectangle(t,r,i),s=a.west+"%2C"+a.south+"%2C"+a.east+"%2C"+a.north;n=e._url+"/export?",n+="bbox="+s,n+=e._tilingScheme instanceof c?"&bboxSR=4326&imageSR=4326":"&bboxSR=3857&imageSR=3857",n+="&size="+e._tileWidth+"%2C"+e._tileHeight,n+="&format=png&transparent=true&f=image",e.layers&&(n+="&layers=show:"+e.layers)}var l=e._token;o(l)&&(-1===n.indexOf("?")&&(n+="?"),"?"!==n[n.length-1]&&(n+="&"),n+="token="+l);var u=e._proxy;return o(u)&&(n=u.getURL(n)),n}var T=function(t){function r(r){var n=r.tileInfo;if(o(n)){if(h._tileWidth=n.rows,h._tileHeight=n.cols,102100===n.spatialReference.wkid||102113===n.spatialReference.wkid)h._tilingScheme=new g({ellipsoid:t.ellipsoid});else{if(4326!==r.tileInfo.spatialReference.wkid){var a="Tile spatial reference WKID "+r.tileInfo.spatialReference.wkid+" is not supported.";return void(u=v.handleError(u,h,h._errorEvent,a,void 0,void 0,void 0,s))}h._tilingScheme=new c({ellipsoid:t.ellipsoid})}if(h._maximumLevel=r.tileInfo.lods.length-1,o(r.fullExtent)){if(o(r.fullExtent.spatialReference)&&o(r.fullExtent.spatialReference.wkid))if(102100===r.fullExtent.spatialReference.wkid||102113===r.fullExtent.spatialReference.wkid){var l=new _,d=l.unproject(new e(r.fullExtent.xmin,r.fullExtent.ymin)),p=l.unproject(new e(r.fullExtent.xmax,r.fullExtent.ymax));h._rectangle=new m(d.longitude,d.latitude,p.longitude,p.latitude)}else{if(4326!==r.fullExtent.spatialReference.wkid){var f="fullExtent.spatialReference WKID "+r.fullExtent.spatialReference.wkid+" is not supported.";return void(u=v.handleError(u,h,h._errorEvent,f,void 0,void 0,void 0,s))}h._rectangle=m.fromDegrees(r.fullExtent.xmin,r.fullExtent.ymin,r.fullExtent.xmax,r.fullExtent.ymax)}}else h._rectangle=h._tilingScheme.rectangle;o(h._tileDiscardPolicy)||(h._tileDiscardPolicy=new C({missingImageUrl:w(h,0,0,h._maximumLevel),pixelsToCheck:[new e(0,0),new e(200,20),new e(20,200),new e(80,110),new e(160,130)],disableCheckIfAllPixelsAreTransparent:!0})),h._useTiles=!0}else h._useTiles=!1;o(r.copyrightText)&&r.copyrightText.length>0&&(h._credit=new i(r.copyrightText)),h._ready=!0,h._readyPromise.resolve(!0),v.handleSuccess(u)}function a(e){var t="An error occurred while accessing "+h._url+".";u=v.handleError(u,h,h._errorEvent,t,void 0,void 0,void 0,s),h._readyPromise.reject(new f(t))}function s(){var e={f:"json"};o(h._token)&&(e.token=h._token);var t=d(h._url,{parameters:e,proxy:h._proxy});y(t,r,a)}t=n(t,{}),this._url=t.url,this._token=t.token,this._tileDiscardPolicy=t.tileDiscardPolicy,this._proxy=t.proxy,this._tileWidth=n(t.tileWidth,256),this._tileHeight=n(t.tileHeight,256),this._maximumLevel=t.maximumLevel,this._tilingScheme=n(t.tilingScheme,new c({ellipsoid:t.ellipsoid})),this._credit=void 0,this._useTiles=n(t.usePreCachedTilesIfAvailable,!0),this._rectangle=n(t.rectangle,this._tilingScheme.rectangle),this._layers=t.layers,this._enablePickFeatures=n(t.enablePickFeatures,!0),this._errorEvent=new l,this._ready=!1,this._readyPromise=y.defer();var u,h=this;this._useTiles?s():(this._ready=!0,this._readyPromise.resolve(!0))};return a(T.prototype,{url:{get:function(){return this._url}},token:{get:function(){return this._token}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},usingPrecachedTiles:{get:function(){return this._useTiles}},hasAlphaChannel:{get:function(){return!0}},layers:{get:function(){return this._layers}},enablePickFeatures:{get:function(){return this._enablePickFeatures}}}),T.prototype.getTileCredits=function(e,t,r){return void 0},T.prototype.requestImage=function(e,t,r){var i=w(this,e,t,r);return S.loadImage(this,i)},T.prototype.pickFeatures=function(e,i,n,a,s){if(!this._enablePickFeatures)return void 0;var l,u,d,m=this._tilingScheme.tileXYToNativeRectangle(e,i,n);if(this._tilingScheme instanceof c)l=p.toDegrees(a),u=p.toDegrees(s),d="4326";else{var f=this._tilingScheme.projection.project(new r(a,s,0));l=f.x,u=f.y,d="3857"}var v=this._url+"/identify?f=json&tolerance=2&geometryType=esriGeometryPoint";return v+="&geometry="+l+","+u,v+="&mapExtent="+m.west+","+m.south+","+m.east+","+m.north,v+="&imageDisplay="+this._tileWidth+","+this._tileHeight+",96",v+="&sr="+d,v+="&layers=visible",o(this._layers)&&(v+=":"+this._layers),o(this._token)&&(v+="&token="+this._token),o(this._proxy)&&(v=this._proxy.getURL(v)),h(v).then(function(e){var i=[],n=e.results;if(!o(n))return i;for(var a=0;a<n.length;++a){var s=n[a],l=new E;if(l.data=s,l.name=s.value,l.properties=s.attributes,l.configureDescriptionFromProperties(s.attributes),"esriGeometryPoint"===s.geometryType&&s.geometry){var u=s.geometry.spatialReference&&s.geometry.spatialReference.wkid?s.geometry.spatialReference.wkid:4326;if(4326===u||4283===u)l.position=r.fromDegrees(s.geometry.x,s.geometry.y,s.geometry.z);else if(102100===u||900913===u||3857===u){var c=new _;l.position=c.unproject(new t(s.geometry.x,s.geometry.y,s.geometry.z))}}i.push(l)}return i})},T}),r("Scene/BingMapsStyle",["../Core/freezeObject"],function(e){"use strict";var t={AERIAL:"Aerial",AERIAL_WITH_LABELS:"AerialWithLabels",ROAD:"Road",ORDNANCE_SURVEY:"OrdnanceSurvey",COLLINS_BART:"CollinsBart"};return e(t)}),r("Scene/BingMapsImageryProvider",["../Core/BingMapsApi","../Core/Cartesian2","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/loadJsonp","../Core/Math","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./BingMapsStyle","./DiscardMissingTileImagePolicy","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,t,r,i){var o=e._imageUrlTemplate,a=C.tileXYToQuadKey(t,r,i);o=o.replace("{quadkey}",a);var s=e._imageUrlSubdomains,l=(t+r+i)%s.length;o=o.replace("{subdomain}",s[l]);var u=e._proxy;return n(u)&&(o=u.getURL(o)),o}function y(e,t,r){++t;for(var i=[],o=0,a=e.length;a>o;++o){for(var s=e[o],l=s.coverageAreas,u=!1,h=0,d=s.coverageAreas.length;!u&&d>h;++h){var p=l[h];if(t>=p.zoomMin&&t<=p.zoomMax){var m=c.intersection(r,p.bbox,S);n(m)&&(u=!0)}}u&&i.push(s.credit)}return i}var C=function w(o){function a(e){var i=e.resourceSets[0].resources[0];S._tileWidth=i.imageWidth,S._tileHeight=i.imageHeight,S._maximumLevel=i.zoomMax-1,S._imageUrlSubdomains=i.imageUrlSubdomains,S._imageUrlTemplate=i.imageUrl.replace("{culture}",S._culture);var o=S._tileProtocol;if(!n(o)){var a=document.location.protocol;o=/^http/.test(a)?a:"http:"}S._imageUrlTemplate=S._imageUrlTemplate.replace(/^http:/,o),n(S._tileDiscardPolicy)||(S._tileDiscardPolicy=new v({missingImageUrl:g(S,0,0,S._maximumLevel),pixelsToCheck:[new t(0,0),new t(120,140),new t(130,160),new t(200,50),new t(200,200)],disableCheckIfAllPixelsAreTransparent:!0}));var s=S._attributionList=i.imageryProviders;s||(s=S._attributionList=[]);for(var l=0,h=s.length;h>l;++l){var p=s[l];p.credit=new r(p.attribution);for(var m=p.coverageAreas,f=0,_=p.coverageAreas.length;_>f;++f){var y=m[f],E=y.bbox;y.bbox=new c(u.toRadians(E[1]),u.toRadians(E[0]),u.toRadians(E[3]),u.toRadians(E[2]))}}S._ready=!0,S._readyPromise.resolve(!0),d.handleSuccess(C)}function _(e){var t="An error occurred while accessing "+E+".";C=d.handleError(C,S,S._errorEvent,t,void 0,void 0,void 0,y),S._readyPromise.reject(new h(t))}function y(){var e=l(E,{callbackParameterName:"jsonp",proxy:S._proxy});m(e,a,_)}o=i(o,{}),this._key=e.getKey(o.key),this._url=o.url,this._tileProtocol=o.tileProtocol,this._mapStyle=i(o.mapStyle,f.AERIAL),this._culture=i(o.culture,""),this._tileDiscardPolicy=o.tileDiscardPolicy,this._proxy=o.proxy,this._credit=new r("Bing Imagery",w._logoData,"http://www.bing.com"),this.defaultGamma=1,(this._mapStyle===f.AERIAL||this._mapStyle===f.AERIAL_WITH_LABELS)&&(this.defaultGamma=1.3),this._tilingScheme=new p({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:2,ellipsoid:o.ellipsoid}),this._tileWidth=void 0,this._tileHeight=void 0,this._maximumLevel=void 0,this._imageUrlTemplate=void 0,this._imageUrlSubdomains=void 0,this._errorEvent=new s,this._ready=!1,this._readyPromise=m.defer();var C,E=this._url+"/REST/v1/Imagery/Metadata/"+this._mapStyle+"?incl=ImageryProviders&key="+this._key,S=this;y()};o(C.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},key:{get:function(){return this._key}},mapStyle:{get:function(){return this._mapStyle}},culture:{get:function(){return this._culture}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!1}}});var E=new c;C.prototype.getTileCredits=function(e,t,r){if(!this._ready)throw new a("getTileCredits must not be called before the imagery provider is ready.");var i=this._tilingScheme.tileXYToRectangle(e,t,r,E);return y(this._attributionList,r,i)},C.prototype.requestImage=function(e,t,r){var i=g(this,e,t,r);return _.loadImage(this,i)},C.prototype.pickFeatures=function(){return void 0},C._logoData="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD0AAAAaCAYAAAAEy1RnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3gIDEgcPTMnXOQAAClZJREFUWMPdWGtsFNcV/u689uH1+sXaONhlWQzBENtxiUFBpBSLd60IpXHSNig4URtSYQUkRJNSi0igViVVVBJBaBsiAgKRQJSG8AgEHCCWU4iBCprY2MSgXfOI16y9D3s9Mzsztz9yB12WNU2i9Ecy0tHOzN4793zn3POdcy7BnRfJ8I7iB3SRDPeEExswLz8Y0DZIAYDIRGAgLQAm+7Xle31J3L3Anp1MZPY+BUBjorN332vgYhpgV1FRUd6TTz45ubq6OtDV1SXpuu5g//Oept9wNwlMyAi8IXDjyF245TsDTdivDMATCATGNDU1/WbhwoWPTZs2bWx1dXWhx+Oxrl+/PqTrus5t9W8KWEzjinTAYhro/xuBStwiIgBnJBLxKIoy1u/3V/r9/krDMMz3339/Z3t7e38ikUgCMDLEt8W+Q0cAI3McYTDDmZxh7DESG5Ni43jg9Gsa+X+OsxWxPSJTSj3JZFK5ZRVJErOzs8e6XC4fgGwALhbzDgAKU1hK28KEA6PMmTMn56233qpevnz5PQDcbJ7EzVUAuMrLy3MBeABkcWOEDELSyFe4y7iMoHkriZZlKYZh8ASHZDKpJJPJHAC5APIA5APIAeBlCjo5TwlpXnbOmTPHP3fu3KZVq1atZKBcDJQ9x7V48WJfc3Pzhp6enj+tXLnyR8w4MjdG4gyVDk7KICMClzKlLUrpbQMNw5AkScppbGz8cWdn57WjR4/2caw+DEBlYjO8wX1foZQWuN3uKZIklQD4G+fhlG0Yl8uVm5WVVW6app6dne0D0G8vnxbjJntHubCUOK/badZICyWanrJuAaeUknTQpmlKkUhEWbx48U8LCwtHhUKha+fPn+85fPhwV0tLyzUACSZx9jvMFhIByNFoVDEMw/qKB5HPvJfkUqBr9+7deklJyZ/j8bi5ffv2OAslieMLsG+m2DybT2QuzEQOsF5SUqJfvXo1yc2l6Xn6rgSRSCSEc+fOhVeuXLmwoqJixvTp0wcWLFgQ7unpudHR0dF97ty5z/fu3XseQJh5adjeerquy5ZlCalUivh8Pt8HH3ywzOPxyD09PZ81NjZ+2NnZaQEQx40b54vFYqaqquEVK1b4a2tr/WvWrDn18ssv144fP36SqqoD69ev371nz57rDLwAwHHkyJGfjRs3rtowDOv06dOnu7q6rs6bN2/s7Nmz9zIjDKenWoFZKg/AlMLCwl82Nzf/m3LX22+/fXb06NF/ALC8u7u7m6ZdkUhksL29/UpLS0vzunXrVgAoBzAaQBGAiY2NjUui0ei1RCLRFwwG/9PX19cVi8WCqqoOdHd3HysrK6sDMCccDl8IBoOtiqIsOnbs2D+i0eiV3t7ez8Ph8GeRSKRT07TB/v7+i1OnTp0HYBqABzs7O/+paVo0Fot1RyKRi/F4/Gp/f39XIpHoZnoUMn6wU+ZtRDaymwmxZFk2AWjvvvvuJ/F4PMn/n5+fn1VeXu6fOXNmbU1NzUOM4Bz8QqIoyg6HwxuLxfq3bdu2a+vWrW/09/dfKy0tffDVV199BEC20+n0ud3uQgBup9Pp83g8JYqieE+ePPnxxo0bt33xxRen8/Ly7n3hhRcWASh47bXX5pWVldWFw+GuXbt27XjzzTd3BoPBDq/XG1AUZRRHmAKPVfqaoKkgCCkA+oYNG84Eg0FHTU1N5ezZs8eWlJQ4CSF8/LvZYhJPQoQQpFKpwcrKyo1su9HBwUF99erVv588eXINgOOmacIwDEopdaZSKUIpxYkTJz6sr68/BMBav379RcMwZk2aNOl+AP+qq6t7xDTNVEVFxR+j0WgSAJk4ceKlTz/9tNzpdHpZvIvpjVW6pykhhBJCbkvwgiAQQogEQL558ybdtGlTsLm5OWJZdxZmlmWll5OUEEJN0zSGhob6GcOrALSzZ8/2apqWcLlc2axGACNRkRAimqaph0Kh68xIwwB0y7IMSZKcABz5+fkl8Xj8y2g0apOb5na7rYGBgS/JV54Q0qpAAoBKaS0jBWClg1ZVFeFw2AlgVF1dXeDpp5+eWVFRUVpcXOzgvQwAbrcbDJhdudlGpKZpGtx6JCcnRxIEQbQsS2PjbjM+AMvlchnMSBaXkr7ymCCIhmEYfMoVRVESBEHI0CaTTNubssUsQRBuubCtra33pZdeCk6YMCGwZs2aipqaGn9paWmuJEl3JP0bN258eeTIkRMABrm0YomiaImiKGVlZeWxLecAgBkzZvgdDkfWjRs3ggA0bpfpoiiahBCqKEqKAy2yULMA6MlkMp6Xl3cP1x2SWCwmFhQU+CmlFhfHNFOevpX4LcvSJUkyAeDQoUOh119//fpTTz01Zf78+UWBQCBHUZQ7yE/TNGPfvn0n33vvvSP79+//BECMeZsCMGRZNgRBgNPpHHXx4sVVDQ0Nf1+wYMGYJ554YikAevDgwUMA4oIgQJZlSggZdDqdBiGEZGdn6ww0tQlJURTT4/EMHz9+/MCjjz7622AwuHbZsmVbiouLvWvXrm1wOp3ZqVRqaKQTIInf1gAMl8ulU0q1CxcuBGOxmL5u3bryQCDgycrKEjORXGtra8eOHTsOHz169OyVK1cuA+hlRYrGlNRkWR7UNO2mYRiaz+cb3dLS8gYhhOi6Hj116tSOVatWHQNALcsaME0zLghClBDSZ9+zQsZ2SoJS2udwOKLPPffcvsrKyrJAIPDQ/v37txiGofX19V3r7e29UlBQMHqEVpjwnrYA6PF4PK6q6s2qqqqpZWVlitvtljOB7enpiWzbtu3wgQMHTre1tV0E0MeKkkGuIhMAqHv37u30er3Px+NxlyiKygMPPOAnhFiXLl0Kbd68uYPNsXbu3Lk6mUwaqqr2btmyZUdtbe3hd955pwvAEFNcO3jw4K/b2tqiqqpGIpGI4/HHH/9rQ0PDCa/XOyoSidDLly8PNTU1PcZ4QuNK1ju6NYHFRAGASXPnzv1Fa2vrxzTDpapqateuXR/Nnz+/SVGUhwFMBzCBFSLZLF75DsrJGpXRAH4EIABgPIBxAEoBFAPwARjFif1sNzZ25+VlOhaxufcCqAFQC+BhAPVLliz5XSqVUkOhUAuAKWnFyR3dlsw+fg+A+8eMGfPzTZs2bY9GozEb8JkzZ9qXLl36l+Li4l8B+AmAyQDGsGrOzfXNPGPawG2l85jksmcPm+vihH+2W1iF3bvZPN+sWbPuGx4eDrW3t+85fvz41o6OjmZN04Y0TYvV19cvYIbN5QqUjG2mwj5YAqDK4XDMe+aZZ55vbW09+sorr2yuqqpqYFatAuBn3uB7XzJCY297XeaUd2RoGzOJmHb6IjFj5D777LP3DQwMfDw8PBxSVbUvkUj0hEKhj1588cXH2O7zMSPdplumoxveMx5Zlj3jx4/39vb26gMDA4MsvgYZo+p8Pr7LqQX5Ds/U7d0jFxUVZS1atKg4Nzc317Isp67rZldXV6y5ufkmI78hFtcmrx8ZweMit6XsUs4+6kmlgbW+peLf9gyMZNCR374G0y/FxEzX8b/8+bkXEBxKFwAAAABJRU5ErkJggg==", -C.tileXYToQuadKey=function(e,t,r){for(var i="",n=r;n>=0;--n){var o=1<<n,a=0;0!==(e&o)&&(a|=1),0!==(t&o)&&(a|=2),i+=a}return i},C.quadKeyToTileXY=function(e){for(var t=0,r=0,i=e.length-1,n=i;n>=0;--n){var o=1<<n,a=+e[i-n];0!==(1&a)&&(t|=o),0!==(2&a)&&(r|=o)}return{x:t,y:r,level:i}};var S=new c;return C}),r("Scene/CullingVolume",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/Intersect","../Core/Plane"],function(e,t,r,i,n,o){"use strict";var a=function(e){this.planes=t(e,[])},s=new o(new e,0);return a.prototype.computeVisibility=function(e){for(var t=this.planes,r=!1,i=0,a=t.length;a>i;++i){var l=e.intersectPlane(o.fromCartesian4(t[i],s));if(l===n.OUTSIDE)return n.OUTSIDE;l===n.INTERSECTING&&(r=!0)}return r?n.INTERSECTING:n.INSIDE},a.prototype.computeVisibilityWithPlaneMask=function(e,t){if(t===a.MASK_OUTSIDE||t===a.MASK_INSIDE)return t;for(var r=a.MASK_INSIDE,i=this.planes,l=0,u=i.length;u>l;++l){var c=31>l?1<<l:0;if(!(31>l&&0===(t&c))){var h=e.intersectPlane(o.fromCartesian4(i[l],s));if(h===n.OUTSIDE)return a.MASK_OUTSIDE;h===n.INTERSECTING&&(r|=c)}}return r},a.MASK_OUTSIDE=4294967295,a.MASK_INSIDE=0,a.MASK_INDETERMINATE=2147483647,a}),r("Scene/PerspectiveOffCenterFrustum",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/Matrix4","./CullingVolume"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e){var t=e.top,r=e.bottom,i=e.right,n=e.left,o=e.near,a=e.far;(t!==e._top||r!==e._bottom||n!==e._left||i!==e._right||o!==e._near||a!==e._far)&&(e._left=n,e._right=i,e._top=t,e._bottom=r,e._near=o,e._far=a,e._perspectiveMatrix=l.computePerspectiveOffCenter(n,i,r,t,o,a,e._perspectiveMatrix),e._infinitePerspective=l.computeInfinitePerspectiveOffCenter(n,i,r,t,o,e._infinitePerspective))}var h=function(){this.left=void 0,this._left=void 0,this.right=void 0,this._right=void 0,this.top=void 0,this._top=void 0,this.bottom=void 0,this._bottom=void 0,this.near=1,this._near=this.near,this.far=5e8,this._far=this.far,this._cullingVolume=new u,this._perspectiveMatrix=new l,this._infinitePerspective=new l};o(h.prototype,{projectionMatrix:{get:function(){return c(this),this._perspectiveMatrix}},infiniteProjectionMatrix:{get:function(){return c(this),this._infinitePerspective}}});var d=new t,p=new t,m=new t,f=new t;return h.prototype.computeCullingVolume=function(e,i,o){var a=this._cullingVolume.planes,s=this.top,l=this.bottom,u=this.right,c=this.left,h=this.near,v=this.far,_=t.cross(i,o,d),g=p;t.multiplyByScalar(i,h,g),t.add(e,g,g);var y=m;t.multiplyByScalar(i,v,y),t.add(e,y,y);var C=f;t.multiplyByScalar(_,c,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(C,o,C);var E=a[0];return n(E)||(E=a[0]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),t.multiplyByScalar(_,u,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(o,C,C),E=a[1],n(E)||(E=a[1]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),t.multiplyByScalar(o,l,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(_,C,C),E=a[2],n(E)||(E=a[2]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),t.multiplyByScalar(o,s,C),t.add(g,C,C),t.subtract(C,e,C),t.normalize(C,C),t.cross(C,_,C),E=a[3],n(E)||(E=a[3]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,e),E=a[4],n(E)||(E=a[4]=new r),E.x=i.x,E.y=i.y,E.z=i.z,E.w=-t.dot(i,g),t.negate(i,C),E=a[5],n(E)||(E=a[5]=new r),E.x=C.x,E.y=C.y,E.z=C.z,E.w=-t.dot(C,y),this._cullingVolume},h.prototype.getPixelSize=function(t,r,o){a("PerspectiveOffCenterFrustum","getPixelSize is deprecated. Use getPixelDimensions instead."),c(this);var s=t.x,l=t.y;r=i(r,this.near);var u=1/this.near,h=this.top*u,d=2*r*h/l;h=this.right*u;var p=2*r*h/s;return n(o)?(o.x=p,o.y=d,o):new e(p,d)},h.prototype.getPixelDimensions=function(e,t,r,i){c(this);var n=1/this.near,o=this.top*n,a=2*r*o/t;o=this.right*n;var s=2*r*o/e;return i.x=s,i.y=a,i},h.prototype.clone=function(e){return n(e)||(e=new h),e.right=this.right,e.left=this.left,e.top=this.top,e.bottom=this.bottom,e.near=this.near,e.far=this.far,e._left=void 0,e._right=void 0,e._top=void 0,e._bottom=void 0,e._near=void 0,e._far=void 0,e},h.prototype.equals=function(e){return n(e)&&this.right===e.right&&this.left===e.left&&this.top===e.top&&this.bottom===e.bottom&&this.near===e.near&&this.far===e.far},h}),r("Scene/PerspectiveFrustum",["../Core/defined","../Core/defineProperties","../Core/DeveloperError","./PerspectiveOffCenterFrustum"],function(e,t,r,i){"use strict";function n(e){var t=e._offCenterFrustum;(e.fov!==e._fov||e.aspectRatio!==e._aspectRatio||e.near!==e._near||e.far!==e._far)&&(e._aspectRatio=e.aspectRatio,e._fov=e.fov,e._fovy=e.aspectRatio<=1?e.fov:2*Math.atan(Math.tan(.5*e.fov)/e.aspectRatio),e._near=e.near,e._far=e.far,e._sseDenominator=2*Math.tan(.5*e._fovy),t.top=e.near*Math.tan(.5*e._fovy),t.bottom=-t.top,t.right=e.aspectRatio*t.top,t.left=-t.right,t.near=e.near,t.far=e.far)}var o=function(){this._offCenterFrustum=new i,this.fov=void 0,this._fov=void 0,this._fovy=void 0,this._sseDenominator=void 0,this.aspectRatio=void 0,this._aspectRatio=void 0,this.near=1,this._near=this.near,this.far=5e8,this._far=this.far};return t(o.prototype,{projectionMatrix:{get:function(){return n(this),this._offCenterFrustum.projectionMatrix}},infiniteProjectionMatrix:{get:function(){return n(this),this._offCenterFrustum.infiniteProjectionMatrix}},fovy:{get:function(){return n(this),this._fovy}},sseDenominator:{get:function(){return n(this),this._sseDenominator}}}),o.prototype.computeCullingVolume=function(e,t,r){return n(this),this._offCenterFrustum.computeCullingVolume(e,t,r)},o.prototype.getPixelSize=function(e,t,r){return n(this),this._offCenterFrustum.getPixelSize(e,t,r)},o.prototype.getPixelDimensions=function(e,t,r,i){return n(this),this._offCenterFrustum.getPixelDimensions(e,t,r,i)},o.prototype.clone=function(t){return e(t)||(t=new o),t.aspectRatio=this.aspectRatio,t.fov=this.fov,t.near=this.near,t.far=this.far,t._aspectRatio=void 0,t._fov=void 0,t._near=void 0,t._far=void 0,this._offCenterFrustum.clone(t._offCenterFrustum),t},o.prototype.equals=function(t){return e(t)?(n(this),n(t),this.fov===t.fov&&this.aspectRatio===t.aspectRatio&&this.near===t.near&&this.far===t.far&&this._offCenterFrustum.equals(t._offCenterFrustum)):!1},o}),r("Scene/CameraFlightPath",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/EasingFunction","../Core/Math","./PerspectiveFrustum","./PerspectiveOffCenterFrustum","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,t,r){var i,n,o;if(e instanceof l){var a=Math.tan(.5*e.fovy);return i=e.near,n=e.near*a,o=e.aspectRatio*n,Math.max(t*i/o,r*i/n)}return e instanceof u?(i=e.near,n=e.top,o=e.right,Math.max(t*i/o,r*i/n)):Math.max(t,r)}function d(e,r,i,o,a){var l,u=a;if(!n(a)){var c=e.position,d=r,p=e.up,m=e.right,f=e.frustum,v=t.subtract(c,d,C),_=t.magnitude(t.multiplyByScalar(p,t.dot(v,p),E)),g=t.magnitude(t.multiplyByScalar(m,t.dot(v,m),E));l=Math.max(i,o),u=Math.min(.2*h(f,_,g),1e9)}if(n(a)&&u>a||u>l){var y=8,S=1e6,w=-Math.pow((u-i)*S,1/y),T=Math.pow((u-o)*S,1/y);return function(e){var t=e*(T-w)+w;return-Math.pow(t,y)/S+u}}return function(e){return s.lerp(i,o,e)}}function p(e,t){return s.equalsEpsilon(e,s.TWO_PI,s.EPSILON11)&&(e=0),t>e+Math.PI?e+=s.TWO_PI:t<e-Math.PI&&(e-=s.TWO_PI),e}function m(r,i,n,o,a,l,u){var c=r.camera,h=t.clone(c.position,S),m=c.pitch,f=p(c.heading,o),v=p(c.roll,l),_=d(c,n,h.z,n.z,u),g=function(t){var r=t.time/i;c.setView({orientation:{heading:s.lerp(f,o,r),pitch:s.lerp(m,a,r),roll:s.lerp(v,l,r)}}),e.lerp(h,n,r,c.position),c.position.z=_(r)};return g}function f(e,i,n,o,a,l,u){var c=e.camera,h=e.mapProjection,m=h.ellipsoid,f=r.clone(c.positionCartographic,w),v=c.pitch,_=p(c.heading,o),g=p(c.roll,l),y=m.cartesianToCartographic(n,T);y.height<=0&&(y.height=f.height),f.longitude=s.zeroToTwoPi(f.longitude),y.longitude=s.zeroToTwoPi(y.longitude);var C=f.longitude-y.longitude;C<-s.PI?f.longitude+=s.TWO_PI:C>s.PI&&(y.longitude+=s.TWO_PI);var E=d(c,n,f.height,y.height,u),S=function(e){var r=e.time/i,n=t.fromRadians(s.lerp(f.longitude,y.longitude,r),s.lerp(f.latitude,y.latitude,r),E(r));c.setView({destination:n,orientation:{heading:s.lerp(_,o,r),pitch:s.lerp(v,a,r),roll:s.lerp(g,l,r)}})};return S}function v(r,i,n,o,a,l,u){var c=r.camera,h=t.clone(c.position,S),m=p(c.heading,o),f=c.frustum.right-c.frustum.left,v=d(c,n,f,n.z,u),_=function(t){var r=t.time/i;c.setView({orientation:{heading:s.lerp(m,o,r)}}),e.lerp(h,n,r,c.position);var a=v(r),l=c.frustum,u=l.top/l.right,d=.5*(a-(l.right-l.left));l.right+=d,l.left-=d,l.top=u*l.right,l.bottom=-l.top};return _}function _(e,t){return{startObject:{},stopObject:{},duration:0,complete:e,cancel:t}}function g(e,t){var r=function(){"function"==typeof t&&t(),e.enableInputs=!0};return r}var y={},C=new t,E=new t,S=new t,w=new r,T=new r,b=(new t,new t,new t,new t,new r),x=new t;return y.createTween=function(r,o){o=i(o,i.EMPTY_OBJECT);var l=o.destination,u=r.mode;if(u===c.MORPHING)return _();var h=i(o.convert,!0),d=r.mapProjection,p=d.ellipsoid,y=o.maximumHeight,C=o.easingFunction;h&&u!==c.SCENE3D&&(p.cartesianToCartographic(l,b),l=d.project(b,x));var E=r.camera,S=o.endTransform;n(S)&&E._setTransform(S);var w=o.duration;n(w)||(w=Math.ceil(t.distance(E.position,l)/1e6)+2,w=Math.min(w,3));var T=i(o.heading,0),P=i(o.pitch,-s.PI_OVER_TWO),A=i(o.roll,0),I=r.screenSpaceCameraController;I.enableInputs=!1;var M=g(I,o.complete),D=g(I,o.cancel),R=E.frustum,O=r.mode===c.SCENE2D;if(O=O&&e.equalsEpsilon(E.position,l,s.EPSILON6),O=O&&s.equalsEpsilon(Math.max(R.right-R.left,R.top-R.bottom),l.z,s.EPSILON6),O=O||r.mode!==c.SCENE2D&&t.equalsEpsilon(l,E.position,s.EPSILON10)&&s.equalsEpsilon(s.negativePiToPi(T),s.negativePiToPi(E.heading),s.EPSILON10)&&s.equalsEpsilon(s.negativePiToPi(P),s.negativePiToPi(E.pitch),s.EPSILON10)&&s.equalsEpsilon(s.negativePiToPi(A),s.negativePiToPi(E.roll),s.EPSILON10))return _(M,D);var N=new Array(4);if(N[c.SCENE2D]=v,N[c.SCENE3D]=f,N[c.COLUMBUS_VIEW]=m,0>=w){var L=function(){var e=N[u](r,1,l,T,P,A,y);e({time:1}),"function"==typeof M&&M()};return _(L,D)}var F=N[u](r,w,l,T,P,A,y);if(!n(C)){var B=E.positionCartographic.height,V=u===c.SCENE3D?p.cartesianToCartographic(l).height:l.z;C=B>V&&B>11500?a.CUBIC_OUT:a.QUINTIC_IN_OUT}return{duration:w,easingFunction:C,startObject:{time:0},stopObject:{time:w},update:F,complete:M,cancel:D}},y}),r("Scene/Camera",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/EasingFunction","../Core/Ellipsoid","../Core/EllipsoidGeodesic","../Core/Event","../Core/HeadingPitchRange","../Core/IntersectionTests","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Quaternion","../Core/Ray","../Core/Rectangle","../Core/Transforms","./CameraFlightPath","./PerspectiveFrustum","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T){"use strict";function b(e){var r=e._right,i=e._up,n=e._direction,o=e._position,a=e._viewMatrix;a[0]=r.x,a[1]=i.x,a[2]=-n.x,a[3]=0,a[4]=r.y,a[5]=i.y,a[6]=-n.y,a[7]=0,a[8]=r.z,a[9]=i.z,a[10]=-n.z,a[11]=0,a[12]=-t.dot(r,o),a[13]=-t.dot(i,o),a[14]=t.dot(n,o),a[15]=1,_.multiply(a,e._actualInvTransform,e._viewMatrix),_.inverseTransformation(e._viewMatrix,e._invViewMatrix)}function x(e){var i=e._projection,n=i.ellipsoid,o=_.getColumn(e._transform,3,se),a=n.cartesianToCartographic(o,ne),s=i.project(a,oe),l=le;l.x=s.z,l.y=s.x,l.z=s.y,l.w=1;var u=r.add(_.getColumn(e._transform,0,ae),o,ae);n.cartesianToCartographic(u,a),i.project(a,s);var c=ue;c.x=s.z,c.y=s.x,c.z=s.y,c.w=0,t.subtract(c,l,c);var h=r.add(_.getColumn(e._transform,1,ae),o,ae);n.cartesianToCartographic(h,a),i.project(a,s);var d=ce;d.x=s.z,d.y=s.x,d.z=s.y,d.w=0,t.subtract(d,l,d);var p=he;t.cross(c,d,p),t.normalize(p,p),t.cross(d,p,c),t.normalize(c,c),t.cross(p,c,d),t.normalize(d,d),_.setColumn(e._actualTransform,0,c,e._actualTransform),_.setColumn(e._actualTransform,1,d,e._actualTransform),_.setColumn(e._actualTransform,2,p,e._actualTransform),_.setColumn(e._actualTransform,3,l,e._actualTransform)}function P(e){var i=e._projection,n=i.ellipsoid,o=_.getColumn(e._transform,3,se),a=n.cartesianToCartographic(o,ne),s=i.project(a,oe),l=le;l.x=s.z,l.y=s.x,l.z=s.y,l.w=1;var u=r.clone(r.UNIT_X,he),c=r.add(_.getColumn(e._transform,0,ae),o,ae);n.cartesianToCartographic(c,a),i.project(a,s);var h=ue;h.x=s.z,h.y=s.x,h.z=s.y,h.w=0,t.subtract(h,l,h),h.x=0;var d=ce;if(t.magnitudeSquared(h)>f.EPSILON10)t.cross(u,h,d);else{var p=r.add(_.getColumn(e._transform,1,ae),o,ae);n.cartesianToCartographic(p,a),i.project(a,s),d.x=s.z,d.y=s.x,d.z=s.y,d.w=0,t.subtract(d,l,d),d.x=0,t.magnitudeSquared(d)<f.EPSILON10&&(r.clone(r.UNIT_Y,h),r.clone(r.UNIT_Z,d))}t.cross(d,u,h),t.normalize(h,h),t.cross(u,h,d),t.normalize(d,d),_.setColumn(e._actualTransform,0,h,e._actualTransform),_.setColumn(e._actualTransform,1,d,e._actualTransform),_.setColumn(e._actualTransform,2,u,e._actualTransform),_.setColumn(e._actualTransform,3,l,e._actualTransform)}function A(e){var r=e._mode,i=!1,n=0;r===T.SCENE2D&&(n=e.frustum.right-e.frustum.left,i=n!==e._positionCartographic.height);var o=e._position,a=!t.equals(o,e.position)||i;a&&(o=t.clone(e.position,e._position));var s=e._direction,l=!t.equals(s,e.direction);l&&(s=t.clone(e.direction,e._direction));var u=e._up,c=!t.equals(u,e.up);c&&(u=t.clone(e.up,e._up));var h=e._right,d=!t.equals(h,e.right);d&&(h=t.clone(e.right,e._right));var p=e._transformChanged||e._modeChanged;e._transformChanged=!1,p&&(_.inverseTransformation(e._transform,e._invTransform),e._mode===T.COLUMBUS_VIEW||e._mode===T.SCENE2D?_.equals(_.IDENTITY,e._transform)?_.clone(ie.TRANSFORM_2D,e._actualTransform):e._mode===T.COLUMBUS_VIEW?x(e):P(e):_.clone(e._transform,e._actualTransform),_.inverseTransformation(e._actualTransform,e._actualInvTransform),e._modeChanged=!1);var m=e._actualTransform;if(a||p)if(e._positionWC=_.multiplyByPoint(m,o,e._positionWC),r===T.SCENE3D||r===T.MORPHING)e._positionCartographic=e._projection.ellipsoid.cartesianToCartographic(e._positionWC,e._positionCartographic);else{var v=de;v.x=e._positionWC.y,v.y=e._positionWC.z,v.z=e._positionWC.x,r===T.SCENE2D&&(v.z=n),e._projection.unproject(v,e._positionCartographic)}if(l||c||d){var g=t.dot(s,t.cross(u,h,de));if(Math.abs(1-g)>f.EPSILON2){s=t.normalize(s,e._direction),t.clone(s,e.direction);var y=1/t.magnitudeSquared(u),C=t.dot(u,s)*y,E=t.multiplyByScalar(s,C,de);u=t.normalize(t.subtract(u,E,e._up),e._up),t.clone(u,e.up),h=t.cross(s,u,e._right),t.clone(h,e.right)}}(l||p)&&(e._directionWC=_.multiplyByPointAsVector(m,s,e._directionWC)),(c||p)&&(e._upWC=_.multiplyByPointAsVector(m,u,e._upWC)),(d||p)&&(e._rightWC=_.multiplyByPointAsVector(m,h,e._rightWC)),(a||l||c||d||p)&&b(e)}function I(e,t){var r;return r=f.equalsEpsilon(Math.abs(e.z),1,f.EPSILON3)?Math.atan2(t.y,t.x)-f.PI_OVER_TWO:Math.atan2(e.y,e.x)-f.PI_OVER_TWO,f.TWO_PI-f.zeroToTwoPi(r)}function M(e){return f.PI_OVER_TWO-f.acosClamped(e.z)}function D(e,t,r){var i=0;return f.equalsEpsilon(Math.abs(e.z),1,f.EPSILON3)||(i=Math.atan2(-r.z,t.z),i=f.zeroToTwoPi(i+f.TWO_PI)),i}function R(e,r,i,n,o){var a=_.clone(e.transform,ye),s=E.eastNorthUpToFixedFrame(r,e._projection.ellipsoid,Ce);e._setTransform(s),t.clone(t.ZERO,e.position);var l=g.fromHeadingPitchRoll(i-f.PI_OVER_TWO,n,o,Ee),u=v.fromQuaternion(l,Se);v.getColumn(u,0,e.direction),v.getColumn(u,2,e.up),t.cross(e.direction,e.up,e.right),e._setTransform(a)}function O(e,r,i,n,o,a){var s=_.clone(e.transform,ye);if(e._setTransform(_.IDENTITY),!t.equals(r,e.positionWC)){if(a){var l=e._projection,u=l.ellipsoid.cartesianToCartographic(r,we);r=l.project(u,ge)}t.clone(r,e.position)}var c=g.fromHeadingPitchRoll(i-f.PI_OVER_TWO,n,o,Ee),h=v.fromQuaternion(c,Se);v.getColumn(h,0,e.direction),v.getColumn(h,2,e.up),t.cross(e.direction,e.up,e.right),e._setTransform(s)}function N(r,i,n,o){var a=-f.PI_OVER_TWO,s=0,l=_.clone(r.transform,ye);if(r._setTransform(_.IDENTITY),!t.equals(i,r.positionWC)){if(o){var u=r._projection,c=u.ellipsoid.cartesianToCartographic(i,we);i=u.project(c,ge)}e.clone(i,r.position);var h=.5*-i.z,d=-h,p=r.frustum;if(d>h){var m=p.top/p.right;p.right=d,p.left=h,p.top=p.right*m,p.bottom=-p.top}}var y=g.fromHeadingPitchRoll(n-f.PI_OVER_TWO,a,s,Ee),C=v.fromQuaternion(y,Se);v.getColumn(C,2,r.up),t.cross(r.direction,r.up,r.right),r._setTransform(l)}function L(e,r,i,n){var o=t.clone(i.direction,Te),a=t.clone(i.up,be);if(e._scene.mode===T.SCENE3D){var s=e._projection.ellipsoid,l=E.eastNorthUpToFixedFrame(r,s,pe),u=_.inverseTransformation(l,me);_.multiplyByPointAsVector(u,o,o),_.multiplyByPointAsVector(u,a,a)}var c=t.cross(o,a,xe);return n.heading=I(o,a),n.pitch=M(o),n.roll=D(o,a,c),n}function F(e,t){var r=e._maxCoord.x*e.maximumTranslateFactor;t.x>r&&(t.x=r),t.x<-r&&(t.x=-r);var i=e._maxCoord.y*e.maximumTranslateFactor;t.y>i&&(t.y=i),t.y<-i&&(t.y=-i)}function B(e,r){var i=e.position,n=t.normalize(i,Oe);if(o(e.constrainedAxis)){var a=t.equalsEpsilon(n,e.constrainedAxis,f.EPSILON2),s=t.equalsEpsilon(n,t.negate(e.constrainedAxis,Fe),f.EPSILON2);if(a||s)(a&&0>r||s&&r>0)&&e.rotate(e.right,r);else{var l=t.normalize(e.constrainedAxis,Ne),u=t.dot(n,l),c=f.acosClamped(u);if(r>0&&r>c&&(r=c-f.EPSILON4),o(e.constrainedAxisAngle)){var h=e.constrainedAxisAngle,d=c-h;0>r&&d>r&&(r=d+f.EPSILON4)}u=t.dot(n,t.negate(l,Fe)),c=f.acosClamped(u),0>r&&-r>c&&(r=-c+f.EPSILON4);var p=t.cross(l,n,Le);e.rotate(p,r)}}else e.rotate(e.right,r)}function V(e,t){o(e.constrainedAxis)?e.rotate(e.constrainedAxis,t):e.rotate(e.up,t)}function z(e,t){var r=e.frustum;t=.5*t;var i=r.right-t,n=r.left+t,o=e._maxCoord.x*e.maximumZoomFactor;i>o&&(i=o,n=-o),n>=i&&(i=1,n=-1);var a=r.top/r.right;r.right=i,r.left=n,r.top=r.right*a,r.bottom=-r.top}function k(e,t){e.move(e.direction,t)}function U(e,r,i){r=f.clamp(r,-f.PI_OVER_TWO,f.PI_OVER_TWO),e=f.zeroToTwoPi(e)-f.PI_OVER_TWO;var n=g.fromAxisAngle(t.UNIT_Y,-r,ze),o=g.fromAxisAngle(t.UNIT_Z,-e,ke),a=g.multiply(o,n,o),s=v.fromQuaternion(a,Ue),l=t.clone(t.UNIT_X,Ve);return v.multiplyByVector(s,l,l),t.negate(l,l),t.multiplyByScalar(l,i,l),l}function G(e,r,i,n){var o=Math.abs(t.dot(r,i));return o/n-t.dot(e,i)}function W(e,r,i,n){var a=e._projection.ellipsoid,s=n?e:$e,l=r.north,u=r.south,c=r.east,d=r.west;d>c&&(c+=f.TWO_PI);var p,m=.5*(d+c);if(u<-f.PI_OVER_TWO+f.RADIANS_PER_DEGREE&&l>f.PI_OVER_TWO-f.RADIANS_PER_DEGREE)p=0;else{var v=We;v.longitude=m,v.latitude=l,v.height=0;var _=He;_.longitude=m,_.latitude=u,_.height=0;var g=Ge;o(g)&&g.ellipsoid===a||(Ge=g=new h(void 0,void 0,a)),g.setEndPoints(v,_),p=g.interpolateUsingFraction(.5,We).latitude}var y=We;y.longitude=m,y.latitude=p,y.height=0;var C=a.cartographicToCartesian(y,Je),E=We;E.longitude=c,E.latitude=l;var S=a.cartographicToCartesian(E,qe);E.longitude=d;var w=a.cartographicToCartesian(E,Ye);E.longitude=m;var T=a.cartographicToCartesian(E,Ze);E.latitude=u;var b=a.cartographicToCartesian(E,Ke);E.longitude=c;var x=a.cartographicToCartesian(E,Xe);E.longitude=d;var P=a.cartographicToCartesian(E,je);t.subtract(w,C,w),t.subtract(x,C,x),t.subtract(S,C,S),t.subtract(P,C,P),t.subtract(T,C,T),t.subtract(b,C,b);var A=a.geodeticSurfaceNormal(C,s.direction);t.negate(A,A);var I=t.cross(A,t.UNIT_Z,s.right);t.normalize(I,I);var M=t.cross(I,A,s.up),D=Math.tan(.5*e.frustum.fovy),R=e.frustum.aspectRatio*D,O=Math.max(G(A,M,w,D),G(A,M,x,D),G(A,M,S,D),G(A,M,P,D),G(A,M,T,D),G(A,M,b,D),G(A,I,w,R),G(A,I,x,R),G(A,I,S,R),G(A,I,P,R),G(A,I,T,R),G(A,I,b,R));if(0>u&&l>0){var N=We;N.longitude=d,N.latitude=0,N.height=0;var L=a.cartographicToCartesian(N,Qe);t.subtract(L,C,L),O=Math.max(O,G(A,M,L,D),G(A,I,L,R)),N.longitude=c,L=a.cartographicToCartesian(N,Qe),t.subtract(L,C,L),O=Math.max(O,G(A,M,L,D),G(A,I,L,R))}return t.add(C,t.multiplyByScalar(A,-O,Qe),i)}function H(e,t,r){var i=e._projection;t.west>t.east&&(t=C.MAX_VALUE);var n=e._actualTransform,o=e._actualInvTransform,a=et;a.longitude=t.east,a.latitude=t.north;var s=i.project(a,tt);_.multiplyByPoint(n,s,s),_.multiplyByPoint(o,s,s),a.longitude=t.west,a.latitude=t.south;var l=i.project(a,rt);_.multiplyByPoint(n,l,l),_.multiplyByPoint(o,l,l);var u=Math.tan(.5*e.frustum.fovy),c=e.frustum.aspectRatio*u;return r.x=.5*(s.x-l.x)+l.x,r.y=.5*(s.y-l.y)+l.y,r.z=.5*Math.max((s.x-l.x)/c,(s.y-l.y)/u),r}function q(e,t,r){var i=e._projection;t.west>t.east&&(t=C.MAX_VALUE);var n=it;n.longitude=t.east,n.latitude=t.north;var o=i.project(n,nt);n.longitude=t.west,n.latitude=t.south;var a,s,l=i.project(n,ot),u=.5*Math.abs(o.x-l.x),c=.5*Math.abs(o.y-l.y),h=e.frustum.right/e.frustum.top,d=c*h;return u>d?(a=u,s=a/h):(s=c,a=d),c=Math.max(2*a,2*s),r.x=.5*(o.x-l.x)+l.x,r.y=.5*(o.y-l.y)+l.y,n=i.unproject(r,n),n.height=c,r=i.project(n,r)}function j(e,t,r,i){r=n(r,c.WGS84);var o=e.getPickRay(t,at),a=m.rayEllipsoid(o,r);if(!a)return void 0;var s=a.start>0?a.start:a.stop;return y.getPoint(o,s,i)}function Y(e,t,r,i){var n=e.getPickRay(t,st),o=n.origin;o.z=0;var a=r.unproject(o);return a.latitude<-f.PI_OVER_TWO||a.latitude>f.PI_OVER_TWO||a.longitude<-Math.PI||a.longitude>Math.PI?void 0:r.ellipsoid.cartographicToCartesian(a,i)}function X(e,r,i,n){var o=e.getPickRay(r,lt),a=-o.origin.x/o.direction.x;y.getPoint(o,a,n);var s=i.unproject(new t(n.y,n.z,0));return s.latitude<-f.PI_OVER_TWO||s.latitude>f.PI_OVER_TWO||s.longitude<-Math.PI||s.longitude>Math.PI?void 0:i.ellipsoid.cartographicToCartesian(s,n)}function Z(e,r,i){var n=e._scene.canvas,o=n.clientWidth,a=n.clientHeight,s=Math.tan(.5*e.frustum.fovy),l=e.frustum.aspectRatio*s,u=e.frustum.near,c=2/o*r.x-1,h=2/a*(a-r.y)-1,d=e.positionWC;t.clone(d,i.origin);var p=t.multiplyByScalar(e.directionWC,u,ut);t.add(d,p,p);var m=t.multiplyByScalar(e.rightWC,c*u*l,ct),f=t.multiplyByScalar(e.upWC,h*u*s,ht),v=t.add(p,m,i.direction);return t.add(v,f,v),t.subtract(v,d,v),t.normalize(v,v),i}function K(e,r,i){var n=e._scene.canvas,o=n.clientWidth,a=n.clientHeight,s=2/o*r.x-1;s*=.5*(e.frustum.right-e.frustum.left);var l=2/a*(a-r.y)-1;l*=.5*(e.frustum.top-e.frustum.bottom);var u=i.origin;return t.clone(e.position,u),t.multiplyByScalar(e.right,s,dt),t.add(dt,u,u),t.multiplyByScalar(e.up,l,dt),t.add(dt,u,u),t.clone(e.directionWC,i.direction),i}function J(e,r){var i=e.position,n=i.x<-e._maxCoord.x||i.x>e._maxCoord.x,o=i.y<-e._maxCoord.y||i.y>e._maxCoord.y,a=n||o,s=e.frustum,l=s.top,c=s.bottom,h=s.right,d=s.left,p=e._max2Dfrustum,m=h>e._max2Dfrustum.right;if(a||m){var v=t.clone(i);v.x>e._maxCoord.x?v.x=e._maxCoord.x:v.x<-e._maxCoord.x&&(v.x=-e._maxCoord.x),v.y>e._maxCoord.y?v.y=e._maxCoord.y:v.y<-e._maxCoord.y&&(v.y=-e._maxCoord.y);var _=function(r){a&&(e.position=t.lerp(i,v,r.time,e.position)),m&&(e.frustum.top=f.lerp(l,p.top,r.time),e.frustum.bottom=f.lerp(c,p.bottom,r.time),e.frustum.right=f.lerp(h,p.right,r.time),e.frustum.left=f.lerp(d,p.left,r.time))};return{easingFunction:u.EXPONENTIAL_OUT,startObject:{time:0},stopObject:{time:1},duration:r,update:_}}return void 0}function Q(e,r,i,n,o,a){var s=t.clone(r);i.y>n?s.y-=i.y-n:i.y<-n&&(s.y+=-n-i.y),i.z>o?s.z-=i.z-o:i.z<-o&&(s.z+=-o-i.z);var l=function(i){var n=t.lerp(r,s,i.time,new t);e.worldToCameraCoordinatesPoint(n,e.position)};return{easingFunction:u.EXPONENTIAL_OUT,startObject:{time:0},stopObject:{time:1},duration:a,update:l}}function $(e,r){var i=e.position,n=e.direction,o=e.worldToCameraCoordinatesVector(t.UNIT_X,ft),a=-t.dot(o,i)/t.dot(o,n),s=t.add(i,t.multiplyByScalar(n,a,vt),vt);e.cameraToWorldCoordinatesPoint(s,s),i=e.cameraToWorldCoordinatesPoint(e.position,_t);var l=Math.tan(.5*e.frustum.fovy),u=e.frustum.aspectRatio*l,c=t.magnitude(t.subtract(i,s,gt)),h=u*c,d=l*c,p=e._maxCoord.x,m=e._maxCoord.y,f=Math.max(h-p,p),v=Math.max(d-m,m);if(i.z<-f||i.z>f||i.y<-v||i.y>v){var _=s.y<-f||s.y>f,g=s.z<-v||s.z>v;if(_||g)return Q(e,i,s,f,v,r)}return void 0}function ee(e,t){var r=e.frustum,i=Math.tan(.5*r.fovy),n=r.aspectRatio*i;return Math.max(t/n,t/i)}function te(e,t){var r,i,n=e.frustum,o=n.right/n.top,a=t*o;return t>a?(r=t,i=r/o):(i=t,r=a),1.5*Math.max(r,i)}function re(e,t,r){o(r)||(r=p.clone(Et));var i=r.range;if(!o(i)||0===i){var n=t.radius;0===n?r.range=St:r.range=e._mode===T.SCENE2D?te(e,n):ee(e,n)}return r}var ie=function(e){this._scene=e,this._transform=_.clone(_.IDENTITY),this._invTransform=_.clone(_.IDENTITY),this._actualTransform=_.clone(_.IDENTITY),this._actualInvTransform=_.clone(_.IDENTITY),this._transformChanged=!1,this.position=new t,this._position=new t,this._positionWC=new t,this._positionCartographic=new i,this.direction=new t,this._direction=new t,this._directionWC=new t,this.up=new t,this._up=new t,this._upWC=new t,this.right=new t,this._right=new t,this._rightWC=new t,this.frustum=new w,this.frustum.aspectRatio=e.drawingBufferWidth/e.drawingBufferHeight,this.frustum.fov=f.toRadians(60),this.defaultMoveAmount=1e5,this.defaultLookAmount=Math.PI/60,this.defaultRotateAmount=Math.PI/3600,this.defaultZoomAmount=1e5,this.constrainedAxis=void 0,this.constrainedAxisAngle=void 0,this.maximumTranslateFactor=1.5,this.maximumZoomFactor=2.5,this._moveStart=new d,this._moveEnd=new d,this._viewMatrix=new _,this._invViewMatrix=new _,b(this),this._mode=T.SCENE3D,this._modeChanged=!0;var r=e.mapProjection;this._projection=r,this._maxCoord=r.project(new i(Math.PI,f.PI_OVER_TWO)),this._max2Dfrustum=void 0,W(this,ie.DEFAULT_VIEW_RECTANGLE,this.position,!0);var n=t.magnitude(this.position);n+=n*ie.DEFAULT_VIEW_FACTOR,t.normalize(this.position,this.position),t.multiplyByScalar(this.position,n,this.position)};ie.TRANSFORM_2D=new _(0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1),ie.TRANSFORM_2D_INVERSE=_.inverseTransformation(ie.TRANSFORM_2D,new _),ie.DEFAULT_VIEW_RECTANGLE=C.fromDegrees(-95,-20,-70,90),ie.DEFAULT_VIEW_FACTOR=.5;var ne=new i,oe=new t,ae=new t,se=new r,le=new r,ue=new r,ce=new r,he=new r,de=new t,pe=new _,me=new _;a(ie.prototype,{transform:{get:function(){return this._transform}},inverseTransform:{get:function(){return A(this),this._invTransform}},viewMatrix:{get:function(){return A(this),this._viewMatrix}},inverseViewMatrix:{get:function(){return A(this),this._invViewMatrix}},positionCartographic:{get:function(){return A(this),this._positionCartographic}},positionWC:{get:function(){return A(this),this._positionWC}},directionWC:{get:function(){return A(this),this._directionWC}},upWC:{get:function(){return A(this),this._upWC}},rightWC:{get:function(){return A(this),this._rightWC}},heading:{get:function(){if(this._mode!==T.MORPHING){var e=(this.positionWC,this._projection.ellipsoid),t=_.clone(this._transform,pe),r=E.eastNorthUpToFixedFrame(this.positionWC,e,me);this._setTransform(r);var i=I(this.direction,this.up);return this._setTransform(t),i}return void 0}},pitch:{get:function(){if(this._mode!==T.MORPHING){var e=(this.positionWC,this._projection.ellipsoid),t=_.clone(this._transform,pe),r=E.eastNorthUpToFixedFrame(this.positionWC,e,me);this._setTransform(r);var i=M(this.direction);return this._setTransform(t),i}return void 0}},roll:{get:function(){if(this._mode!==T.MORPHING){var e=(this.positionWC,this._projection.ellipsoid),t=_.clone(this._transform,pe),r=E.eastNorthUpToFixedFrame(this.positionWC,e,me);this._setTransform(r);var i=D(this.direction,this.up,this.right);return this._setTransform(t),i}return void 0}},moveStart:{get:function(){return this._moveStart}},moveEnd:{get:function(){return this._moveEnd}}}),ie.prototype.update=function(e){var t=!1;if(e!==this._mode&&(this._mode=e,this._modeChanged=e!==T.MORPHING,t=this._mode===T.SCENE2D),t){var r=this._max2Dfrustum=this.frustum.clone(),i=2,n=r.top/r.right;r.right=this._maxCoord.x*i,r.left=-r.right,r.top=n*r.right,r.bottom=-r.top}};var fe=new t,ve=new t,_e=new t;ie.prototype._setTransform=function(e){var r=t.clone(this.positionWC,fe),i=t.clone(this.upWC,ve),n=t.clone(this.directionWC,_e);_.clone(e,this._transform),this._transformChanged=!0,A(this);var o=this._actualInvTransform;_.multiplyByPoint(o,r,this.position),_.multiplyByPointAsVector(o,n,this.direction),_.multiplyByPointAsVector(o,i,this.up),t.cross(this.direction,this.up,this.right),A(this)};var ge=new t,ye=new _,Ce=new _,Ee=new g,Se=new v,we=new i,Te=new t,be=new t,xe=new t,Pe={destination:void 0,orientation:{direction:void 0,up:void 0,heading:void 0,pitch:void 0,roll:void 0},endTransform:void 0};ie.prototype.setView=function(e){e=n(e,n.EMPTY_OBJECT);var r=n(e.orientation,n.EMPTY_OBJECT),i=Pe,a=i.orientation;if(o(e.heading)||o(e.pitch)||o(e.roll)?(s("Camera.setView options","options.heading/pitch/roll has been moved to options.orientation.heading/pitch/roll."),a.heading=n(e.heading,this.heading),a.pitch=n(e.pitch,this.pitch),a.roll=n(e.roll,this.roll)):(a.heading=r.heading,a.pitch=r.pitch,a.roll=r.roll,a.direction=r.direction,a.up=r.up),o(e.position))s("Camera.setView options","options.position has been renamed to options.destination."),e.destination=e.position;else if(o(e.positionCartographic)){s("Camera.setView options","options.positionCartographic has been deprecated. Convert to a Cartesian3 and use options.position instead.");var l=this._projection,u=l.ellipsoid;e.destination=u.cartographicToCartesian(e.positionCartographic,ge)}else i.destination=e.destination;i.endTransform=e.endTransform,e=i,r=a;var c=this._mode;if(c!==T.MORPHING){o(e.endTransform)&&this._setTransform(e.endTransform);var h=!0,d=n(e.destination,t.clone(this.positionWC,ge));o(d)&&o(d.west)&&(d=this.getRectangleCameraCoordinates(d,ge),h=!1),o(r.direction)&&(r=L(this,d,r,Pe.orientation));var p=n(r.heading,0),m=n(r.pitch,-f.PI_OVER_TWO),v=n(r.roll,0);c===T.SCENE3D?R(this,d,p,m,v):c===T.SCENE2D?N(this,d,p,h):O(this,d,p,m,v,h)}},ie.prototype.worldToCameraCoordinates=function(e,t){return o(t)||(t=new r),A(this),_.multiplyByVector(this._actualInvTransform,e,t)},ie.prototype.worldToCameraCoordinatesPoint=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPoint(this._actualInvTransform,e,r)},ie.prototype.worldToCameraCoordinatesVector=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPointAsVector(this._actualInvTransform,e,r)},ie.prototype.cameraToWorldCoordinates=function(e,t){return o(t)||(t=new r),A(this),_.multiplyByVector(this._actualTransform,e,t)},ie.prototype.cameraToWorldCoordinatesPoint=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPoint(this._actualTransform,e,r)},ie.prototype.cameraToWorldCoordinatesVector=function(e,r){return o(r)||(r=new t),A(this),_.multiplyByPointAsVector(this._actualTransform,e,r)};var Ae=new t;ie.prototype.move=function(e,r){var i=this.position;t.multiplyByScalar(e,r,Ae),t.add(i,Ae,i),this._mode===T.SCENE2D&&F(this,i)},ie.prototype.moveForward=function(e){e=n(e,this.defaultMoveAmount),this.move(this.direction,e)},ie.prototype.moveBackward=function(e){e=n(e,this.defaultMoveAmount),this.move(this.direction,-e)},ie.prototype.moveUp=function(e){e=n(e,this.defaultMoveAmount),this.move(this.up,e)},ie.prototype.moveDown=function(e){e=n(e,this.defaultMoveAmount),this.move(this.up,-e)},ie.prototype.moveRight=function(e){e=n(e,this.defaultMoveAmount),this.move(this.right,e)},ie.prototype.moveLeft=function(e){e=n(e,this.defaultMoveAmount),this.move(this.right,-e)},ie.prototype.lookLeft=function(e){e=n(e,this.defaultLookAmount),this.look(this.up,-e)},ie.prototype.lookRight=function(e){e=n(e,this.defaultLookAmount),this.look(this.up,e)},ie.prototype.lookUp=function(e){e=n(e,this.defaultLookAmount),this.look(this.right,-e)},ie.prototype.lookDown=function(e){e=n(e,this.defaultLookAmount),this.look(this.right,e)};var Ie=new g,Me=new v;ie.prototype.look=function(e,t){var r=n(t,this.defaultLookAmount),i=g.fromAxisAngle(e,-r,Ie),o=v.fromQuaternion(i,Me),a=this.direction,s=this.up,l=this.right;v.multiplyByVector(o,a,a),v.multiplyByVector(o,s,s),v.multiplyByVector(o,l,l)},ie.prototype.twistLeft=function(e){e=n(e,this.defaultLookAmount),this.look(this.direction,e)},ie.prototype.twistRight=function(e){e=n(e,this.defaultLookAmount),this.look(this.direction,-e)};var De=new g,Re=new v;ie.prototype.rotate=function(e,r){ -var i=n(r,this.defaultRotateAmount),o=g.fromAxisAngle(e,-i,De),a=v.fromQuaternion(o,Re);v.multiplyByVector(a,this.position,this.position),v.multiplyByVector(a,this.direction,this.direction),v.multiplyByVector(a,this.up,this.up),t.cross(this.direction,this.up,this.right),t.cross(this.right,this.direction,this.up)},ie.prototype.rotateDown=function(e){e=n(e,this.defaultRotateAmount),B(this,e)},ie.prototype.rotateUp=function(e){e=n(e,this.defaultRotateAmount),B(this,-e)};var Oe=new t,Ne=new t,Le=new t,Fe=new t;ie.prototype.rotateRight=function(e){e=n(e,this.defaultRotateAmount),V(this,-e)},ie.prototype.rotateLeft=function(e){e=n(e,this.defaultRotateAmount),V(this,e)},ie.prototype.zoomIn=function(e){e=n(e,this.defaultZoomAmount),this._mode===T.SCENE2D?z(this,e):k(this,e)},ie.prototype.zoomOut=function(e){e=n(e,this.defaultZoomAmount),this._mode===T.SCENE2D?z(this,-e):k(this,-e)},ie.prototype.getMagnitude=function(){return this._mode===T.SCENE3D?t.magnitude(this.position):this._mode===T.COLUMBUS_VIEW?Math.abs(this.position.z):this._mode===T.SCENE2D?Math.max(this.frustum.right-this.frustum.left,this.frustum.top-this.frustum.bottom):void 0};var Be=new _;new _;ie.prototype.lookAt=function(e,t){var r=E.eastNorthUpToFixedFrame(e,c.WGS84,Be);this.lookAtTransform(r,t)};var Ve=new t,ze=new g,ke=new g,Ue=new v;ie.prototype.lookAtTransform=function(r,i){if(this._setTransform(r),o(i)){var n;if(n=o(i.heading)?U(i.heading,i.pitch,i.range):i,this._mode===T.SCENE2D){e.clone(e.ZERO,this.position),t.negate(n,this.up),this.up.z=0,t.magnitudeSquared(this.up)<f.EPSILON10&&t.clone(t.UNIT_Y,this.up),t.normalize(this.up,this.up),this._setTransform(_.IDENTITY),t.negate(t.UNIT_Z,this.direction),t.cross(this.direction,this.up,this.right),t.normalize(this.right,this.right);var a=this.frustum,s=a.top/a.right;return a.right=.5*t.magnitude(n),a.left=-a.right,a.top=s*a.right,a.bottom=-a.top,void this._setTransform(r)}t.clone(n,this.position),t.negate(this.position,this.direction),t.normalize(this.direction,this.direction),t.cross(this.direction,t.UNIT_Z,this.right),t.magnitudeSquared(this.right)<f.EPSILON10&&t.clone(t.UNIT_X,this.right),t.normalize(this.right,this.right),t.cross(this.right,this.direction,this.up),t.normalize(this.up,this.up)}};var Ge,We=new i,He=new i,qe=new t,je=new t,Ye=new t,Xe=new t,Ze=new t,Ke=new t,Je=new t,Qe=new t,$e={direction:new t,right:new t,up:new t},et=new i,tt=new t,rt=new t,it=new i,nt=new t,ot=new t;ie.prototype.getRectangleCameraCoordinates=function(e,r){var i=this._mode;return o(r)||(r=new t),i===T.SCENE3D?W(this,e,r):i===T.COLUMBUS_VIEW?H(this,e,r):i===T.SCENE2D?q(this,e,r):void 0},ie.prototype.viewRectangle=function(e){s("Camera.viewRectangle","Camera.viewRectangle has been deprecated. Use Camera.setView({ destination:rectangle }) instead"),this.setView({destination:e})};var at=new y,st=new y,lt=new y;ie.prototype.pickEllipsoid=function(e,r,i){if(o(i)||(i=new t),r=n(r,c.WGS84),this._mode===T.SCENE3D)i=j(this,e,r,i);else if(this._mode===T.SCENE2D)i=Y(this,e,this._projection,i);else{if(this._mode!==T.COLUMBUS_VIEW)return void 0;i=X(this,e,this._projection,i)}return i};var ut=new t,ct=new t,ht=new t,dt=new t;ie.prototype.getPickRay=function(e,t){o(t)||(t=new y);var r=this.frustum;return o(r.aspectRatio)&&o(r.fov)&&o(r.near)?Z(this,e,t):K(this,e,t)};var pt=new t,mt=new t;ie.prototype.distanceToBoundingSphere=function(e){var r=t.subtract(this.positionWC,e.center,pt),i=t.multiplyByScalar(this.directionWC,t.dot(r,this.directionWC),mt);return Math.max(0,t.magnitude(i)-e.radius)};var ft=new t,vt=new t,_t=new t,gt=new t;ie.prototype.createCorrectPositionTween=function(e){return this._mode===T.SCENE2D?J(this,e):this._mode===T.COLUMBUS_VIEW?$(this,e):void 0};var yt=new t,Ct=(new g,new v,new t,new t,new _,{destination:void 0,heading:void 0,pitch:void 0,roll:void 0,duration:void 0,complete:void 0,cancel:void 0,endTransform:void 0,maximumHeight:void 0,easingFunction:void 0});ie.prototype.flyTo=function(e){e=n(e,n.EMPTY_OBJECT);var t=e.destination,r=this._mode;if(r!==T.MORPHING){var i=n(e.orientation,n.EMPTY_OBJECT);if(o(i.direction)&&(i=L(this,t,i,Pe.orientation)),o(e.duration)&&e.duration<=0){var a=Pe;return a.destination=e.destination,a.orientation.heading=i.heading,a.orientation.pitch=i.pitch,a.orientation.roll=i.roll,a.endTransform=e.endTransform,this.setView(a),void("function"==typeof e.complete&&e.complete())}var s=o(t.west);s&&(t=this.getRectangleCameraCoordinates(t,yt)),Ct.destination=t,Ct.heading=i.heading,Ct.pitch=i.pitch,Ct.roll=i.roll,Ct.duration=e.duration,Ct.complete=e.complete,Ct.cancel=e.cancel,Ct.endTransform=e.endTransform,Ct.convert=s?!1:e.convert,Ct.maximumHeight=e.maximumHeight,Ct.easingFunction=e.easingFunction;var l=this._scene;l.tweens.add(S.createTween(l,Ct))}};var Et=new p(0,-f.PI_OVER_FOUR,0),St=100;ie.prototype.viewBoundingSphere=function(e,t){if(this._mode===T.MORPHING)throw new l("viewBoundingSphere is not supported while morphing.");t=re(this,e,t),this.lookAt(e.center,t)};var wt=new _,Tt=new t,bt=new t,xt=new t,Pt=new t,At=new r,It=new g,Mt=new v;return ie.prototype.flyToBoundingSphere=function(e,r){r=n(r,n.EMPTY_OBJECT);var i=this._mode===T.SCENE2D||this._mode===T.COLUMBUS_VIEW;this._setTransform(_.IDENTITY);var o,a=re(this,e,r.offset);o=i?t.multiplyByScalar(t.UNIT_Z,a.range,Tt):U(a.heading,a.pitch,a.range);var s=E.eastNorthUpToFixedFrame(e.center,c.WGS84,wt);_.multiplyByPoint(s,o,o);var l,u;if(!i){if(l=t.subtract(e.center,o,bt),t.normalize(l,l),u=_.multiplyByPointAsVector(s,t.UNIT_Z,xt),1-Math.abs(t.dot(l,u))<f.EPSILON6){var h=g.fromAxisAngle(l,a.heading,It),d=v.fromQuaternion(h,Mt);t.fromCartesian4(_.getColumn(s,1,At),u),v.multiplyByVector(d,u,u)}var p=t.cross(l,u,Pt);t.cross(p,l,u),t.normalize(u,u)}this.flyTo({destination:o,orientation:{direction:l,up:u},duration:r.duration,complete:r.complete,cancel:r.cancel,endTransform:r.endTransform,maximumHeight:r.maximumHeight,easingFunction:r.easingFunction})},ie.clone=function(e,r){return o(r)||(r=new ie(e._scene)),t.clone(e.position,r.position),t.clone(e.direction,r.direction),t.clone(e.up,r.up),t.clone(e.right,r.right),_.clone(e._transform,r.transform),r},ie}),r("Scene/CameraEventType",["../Core/freezeObject"],function(e){"use strict";var t={LEFT_DRAG:0,RIGHT_DRAG:1,MIDDLE_DRAG:2,WHEEL:3,PINCH:4};return e(t)}),r("Scene/CameraEventAggregator",["../Core/Cartesian2","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/KeyboardEventModifier","../Core/Math","../Core/ScreenSpaceEventHandler","../Core/ScreenSpaceEventType","./CameraEventType"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,r){var i=e;return t(r)&&(i+="+"+r),i}function h(t,r){e.clone(t.distance.startPosition,r.distance.startPosition),e.clone(t.distance.endPosition,r.distance.endPosition),e.clone(t.angleAndHeight.startPosition,r.angleAndHeight.startPosition),e.clone(t.angleAndHeight.endPosition,r.angleAndHeight.endPosition)}function d(r,i,n){var o=c(u.PINCH,i),a=r._update,s=r._isDown,d=r._eventStartPosition,p=r._pressTime,m=r._releaseTime;a[o]=!0,s[o]=!1,d[o]=new e;var f=r._movement[o];t(f)||(f=r._movement[o]={}),f.distance={startPosition:new e,endPosition:new e},f.angleAndHeight={startPosition:new e,endPosition:new e},f.prevAngle=0,r._eventHandler.setInputAction(function(e){r._buttonsDown++,s[o]=!0,p[o]=new Date},l.PINCH_START,i),r._eventHandler.setInputAction(function(){r._buttonsDown=Math.max(r._buttonsDown-1,0),s[o]=!1,m[o]=new Date},l.PINCH_END,i),r._eventHandler.setInputAction(function(t){if(s[o]){a[o]?(h(t,f),a[o]=!1,f.prevAngle=f.angleAndHeight.startPosition.x):(e.clone(t.distance.endPosition,f.distance.endPosition),e.clone(t.angleAndHeight.endPosition,f.angleAndHeight.endPosition));for(var r=f.angleAndHeight.endPosition.x,i=f.prevAngle,l=2*Math.PI;r>=i+Math.PI;)r-=l;for(;r<i-Math.PI;)r+=l;f.angleAndHeight.endPosition.x=-r*n.clientWidth/12,f.angleAndHeight.startPosition.x=-i*n.clientWidth/12}},l.PINCH_MOVE,i)}function p(r,i){var n=c(u.WHEEL,i),o=r._update;o[n]=!0;var s=r._movement[n];t(s)||(s=r._movement[n]={}),s.startPosition=new e,s.endPosition=new e,r._eventHandler.setInputAction(function(t){var r=15*a.toRadians(t);o[n]?(e.clone(e.ZERO,s.startPosition),s.endPosition.x=0,s.endPosition.y=r,o[n]=!1):s.endPosition.y=s.endPosition.y+r},l.WHEEL,i)}function m(r,i,n){var o=c(n,i),a=r._isDown,s=r._eventStartPosition,h=r._pressTime,d=r._releaseTime;a[o]=!1,s[o]=new e;var p=r._lastMovement[o];t(p)||(p=r._lastMovement[o]={startPosition:new e,endPosition:new e,valid:!1});var m,f;n===u.LEFT_DRAG?(m=l.LEFT_DOWN,f=l.LEFT_UP):n===u.RIGHT_DRAG?(m=l.RIGHT_DOWN,f=l.RIGHT_UP):n===u.MIDDLE_DRAG&&(m=l.MIDDLE_DOWN,f=l.MIDDLE_UP),r._eventHandler.setInputAction(function(t){r._buttonsDown++,p.valid=!1,a[o]=!0,h[o]=new Date,e.clone(t.position,s[o])},m,i),r._eventHandler.setInputAction(function(){r._buttonsDown=Math.max(r._buttonsDown-1,0),a[o]=!1,d[o]=new Date},f,i)}function f(t,r){e.clone(t.startPosition,r.startPosition),e.clone(t.endPosition,r.endPosition)}function v(r,i){var n=r._update,o=r._movement,a=r._lastMovement,s=r._isDown;for(var h in u)if(u.hasOwnProperty(h)){var d=u[h];if(t(d)){var p=c(d,i);n[p]=!0,t(r._lastMovement[p])||(r._lastMovement[p]={startPosition:new e,endPosition:new e,valid:!1}),t(r._movement[p])||(r._movement[p]={startPosition:new e,endPosition:new e})}}r._eventHandler.setInputAction(function(l){for(var h in u)if(u.hasOwnProperty(h)){var d=u[h];if(t(d)){var p=c(d,i);s[p]&&(n[p]?(f(o[p],a[p]),a[p].valid=!0,f(l,o[p]),n[p]=!1):e.clone(l.endPosition,o[p].endPosition))}}e.clone(l.endPosition,r._currentMousePosition)},l.MOUSE_MOVE,i)}var _=function(r){this._eventHandler=new s(r,!0),this._update={},this._movement={},this._lastMovement={},this._isDown={},this._eventStartPosition={},this._pressTime={},this._releaseTime={},this._buttonsDown=0,this._currentMousePosition=new e,p(this,void 0),d(this,void 0,r),m(this,void 0,u.LEFT_DRAG),m(this,void 0,u.RIGHT_DRAG),m(this,void 0,u.MIDDLE_DRAG),v(this,void 0);for(var i in o)if(o.hasOwnProperty(i)){var n=o[i];t(n)&&(p(this,n),d(this,n,r),m(this,n,u.LEFT_DRAG),m(this,n,u.RIGHT_DRAG),m(this,n,u.MIDDLE_DRAG),v(this,n))}};return r(_.prototype,{currentMousePosition:{get:function(){return this._currentMousePosition}},anyButtonDown:{get:function(){var e=!(this._update[c(u.WHEEL)]&&this._update[c(u.WHEEL,o.SHIFT)]&&this._update[c(u.WHEEL,o.CTRL)]&&this._update[c(u.WHEEL,o.ALT)]);return this._buttonsDown>0||e}}}),_.prototype.isMoving=function(e,t){var r=c(e,t);return!this._update[r]},_.prototype.getMovement=function(e,t){var r=c(e,t),i=this._movement[r];return i},_.prototype.getLastMovement=function(e,t){var r=c(e,t),i=this._lastMovement[r];return i.valid?i:void 0},_.prototype.isButtonDown=function(e,t){var r=c(e,t);return this._isDown[r]},_.prototype.getStartMousePosition=function(e,t){if(e===u.WHEEL||e===u.PINCH)return this._currentMousePosition;var r=c(e,t);return this._eventStartPosition[r]},_.prototype.getButtonPressTime=function(e,t){var r=c(e,t);return this._pressTime[r]},_.prototype.getButtonReleaseTime=function(e,t){var r=c(e,t);return this._releaseTime[r]},_.prototype.reset=function(){for(var e in this._update)this._update.hasOwnProperty(e)&&(this._update[e]=!0)},_.prototype.isDestroyed=function(){return!1},_.prototype.destroy=function(){return this._eventHandler=this._eventHandler&&this._eventHandler.destroy(),i(this)},_}),r("Scene/CreditDisplay",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError"],function(e,t,r,i,n){"use strict";function o(e,t,i){if(!r(e.element)){var n=e.text,o=e.link,a=document.createElement("span");if(e.hasLink()){var s=document.createElement("a");s.textContent=n,s.href=o,s.target="_blank",a.appendChild(s)}else a.textContent=n;a.className="cesium-credit-text",e.element=a}if(t.hasChildNodes()){var l=document.createElement("span");l.textContent=i,l.className="cesium-credit-delimiter",t.appendChild(l)}t.appendChild(e.element)}function a(e,t){if(!r(e.element)){var i=e.text,n=e.link,o=document.createElement("span"),a=document.createElement("img");if(a.src=e.imageUrl,a.style["vertical-align"]="bottom",r(i)&&(a.alt=i,a.title=i),e.hasLink()){var s=document.createElement("a");s.appendChild(a),s.href=n,s.target="_blank",o.appendChild(s)}else o.appendChild(a);o.className="cesium-credit-image",e.element=o}t.appendChild(e.element)}function s(t,r){for(var i=t.length,n=0;i>n;n++){var o=t[n];if(e.equals(o,r))return!0}return!1}function l(e){var t=e.element;if(r(t)){var i=t.parentNode;if(!e.hasImage()){var n=t.previousSibling;null===n&&(n=t.nextSibling),null!==n&&i.removeChild(n)}i.removeChild(t)}}function u(e,t){var i,n,a,s=e._displayedCredits.textCredits;for(i=0;i<t.length;i++)a=t[i],r(a)&&(n=s.indexOf(a),-1===n?o(a,e._textContainer,e._delimiter):s.splice(n,1));for(i=0;i<s.length;i++)a=s[i],r(a)&&l(a)}function c(e,t){var i,n,o,s=e._displayedCredits.imageCredits;for(i=0;i<t.length;i++)o=t[i],r(o)&&(n=s.indexOf(o),-1===n?a(o,e._imageContainer):s.splice(n,1));for(i=0;i<s.length;i++)o=s[i],r(o)&&l(o)}var h=function(e,r){var i=document.createElement("span");i.className="cesium-credit-imageContainer";var n=document.createElement("span");n.className="cesium-credit-textContainer",e.appendChild(i),e.appendChild(n),this._delimiter=t(r," • "),this._container=e,this._textContainer=n,this._imageContainer=i,this._defaultImageCredits=[],this._defaultTextCredits=[],this._displayedCredits={imageCredits:[],textCredits:[]},this._currentFrameCredits={imageCredits:[],textCredits:[]}};return h.prototype.addCredit=function(e){if(e.hasImage()){var t=this._currentFrameCredits.imageCredits;s(this._defaultImageCredits,e)||(t[e.id]=e)}else{var r=this._currentFrameCredits.textCredits;s(this._defaultTextCredits,e)||(r[e.id]=e)}},h.prototype.addDefaultCredit=function(e){if(e.hasImage()){var t=this._defaultImageCredits;s(t,e)||t.push(e)}else{var r=this._defaultTextCredits;s(r,e)||r.push(e)}},h.prototype.removeDefaultCredit=function(e){var t;e.hasImage()?(t=this._defaultImageCredits.indexOf(e),-1!==t&&this._defaultImageCredits.splice(t,1)):(t=this._defaultTextCredits.indexOf(e),-1!==t&&this._defaultTextCredits.splice(t,1))},h.prototype.beginFrame=function(){this._currentFrameCredits.imageCredits.length=0,this._currentFrameCredits.textCredits.length=0},h.prototype.endFrame=function(){var e=this._defaultTextCredits.concat(this._currentFrameCredits.textCredits),t=this._defaultImageCredits.concat(this._currentFrameCredits.imageCredits);u(this,e),c(this,t),this._displayedCredits.textCredits=e,this._displayedCredits.imageCredits=t},h.prototype.destroy=function(){return this._container.removeChild(this._textContainer),this._container.removeChild(this._imageContainer),i(this)},h.prototype.isDestroyed=function(){return!1},h}),r("Scene/DebugAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","./Appearance"],function(e,t,r,i,n){"use strict";var o=function(t){t=e(t,e.EMPTY_OBJECT);var r,o=t.attributeName,a=e(t.glslDatatype,"vec3"),s="v_"+o;if("normal"===o||"binormal"===o|"tangent"===o)r="vec4 getColor() { return vec4(("+s+" + vec3(1.0)) * 0.5, 1.0); }\n";else switch("st"===o&&(a="vec2"),a){case"float":r="vec4 getColor() { return vec4(vec3("+s+"), 1.0); }\n";break;case"vec2":r="vec4 getColor() { return vec4("+s+", 0.0, 1.0); }\n";break;case"vec3":r="vec4 getColor() { return vec4("+s+", 1.0); }\n";break;case"vec4":r="vec4 getColor() { return "+s+"; }\n";break;default:throw new i("options.glslDatatype must be float, vec2, vec3, or vec4.")}var l="attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute "+a+" "+o+";\nvarying "+a+" "+s+";\nvoid main()\n{\nvec4 p = czm_translateRelativeToEye(position3DHigh, position3DLow);\n"+s+" = "+o+";\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}",u="varying "+a+" "+s+";\n"+r+"\nvoid main()\n{\ngl_FragColor = getColor();\n}";this.material=void 0,this.translucent=e(t.translucent,!1),this._vertexShaderSource=e(t.vertexShaderSource,l),this._fragmentShaderSource=e(t.fragmentShaderSource,u),this._renderState=n.getDefaultRenderState(!1,!1,t.renderState),this._closed=e(t.closed,!1),this._attributeName=o,this._glslDatatype=a};return r(o.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},attributeName:{get:function(){return this._attributeName}},glslDatatype:{get:function(){return this._glslDatatype}}}),o.prototype.getFragmentShaderSource=n.prototype.getFragmentShaderSource,o.prototype.isTranslucent=n.prototype.isTranslucent,o.prototype.getRenderState=n.prototype.getRenderState,o}),r("Scene/DebugModelMatrixPrimitive",["../Core/Cartesian3","../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/GeometryInstance","../Core/Matrix4","../Core/PolylineGeometry","./PolylineColorAppearance","./Primitive"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(e){e=r(e,r.EMPTY_OBJECT),this.length=r(e.length,1e7),this._length=void 0,this.width=r(e.width,2),this._width=void 0,this.show=r(e.show,!0),this.modelMatrix=a.clone(r(e.modelMatrix,a.IDENTITY)),this._modelMatrix=new a,this.id=e.id,this._id=void 0,this._primitive=void 0};return c.prototype.update=function(r){if(this.show){if(!i(this._primitive)||!a.equals(this._modelMatrix,this.modelMatrix)||this._length!==this.length||this._width!==this.width||this._id!==this.id){this._modelMatrix=a.clone(this.modelMatrix,this._modelMatrix),this._length=this.length,this._width=this.width,this._id=this.id,i(this._primitive)&&this._primitive.destroy(),0===this.modelMatrix[12]&&0===this.modelMatrix[13]&&0===this.modelMatrix[14]&&(this.modelMatrix[14]=.01);var n=new o({geometry:new s({positions:[e.ZERO,e.UNIT_X],width:this.width,vertexFormat:l.VERTEX_FORMAT,colors:[t.RED,t.RED],followSurface:!1}),modelMatrix:a.multiplyByUniformScale(this.modelMatrix,this.length,new a),id:this.id,pickPrimitive:this}),c=new o({geometry:new s({positions:[e.ZERO,e.UNIT_Y],width:this.width,vertexFormat:l.VERTEX_FORMAT,colors:[t.GREEN,t.GREEN],followSurface:!1}),modelMatrix:a.multiplyByUniformScale(this.modelMatrix,this.length,new a),id:this.id,pickPrimitive:this}),h=new o({geometry:new s({positions:[e.ZERO,e.UNIT_Z],width:this.width,vertexFormat:l.VERTEX_FORMAT,colors:[t.BLUE,t.BLUE],followSurface:!1}),modelMatrix:a.multiplyByUniformScale(this.modelMatrix,this.length,new a),id:this.id,pickPrimitive:this});this._primitive=new u({geometryInstances:[n,c,h],appearance:new l,asynchronous:!1})}this._primitive.update(r)}},c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),n(this)},c}),r("Scene/DepthFunction",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={NEVER:t.NEVER,LESS:t.LESS,EQUAL:t.EQUAL,LESS_OR_EQUAL:t.LEQUAL,GREATER:t.GREATER,NOT_EQUAL:t.NOTEQUAL,GREATER_OR_EQUAL:t.GEQUAL,ALWAYS:t.ALWAYS};return e(r)}),r("Shaders/DepthPlaneFS",[],function(){"use strict";return"varying vec4 positionEC;\nvoid main()\n{\nczm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\nvec3 direction = normalize(positionEC.xyz);\nczm_ray ray = czm_ray(vec3(0.0), direction);\nczm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\nif (!czm_isEmpty(intersection))\n{\ngl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n}\nelse\n{\ndiscard;\n}\n}\n"}),r("Shaders/DepthPlaneVS",[],function(){"use strict";return"attribute vec4 position;\nvarying vec4 positionEC;\nvoid main()\n{\npositionEC = czm_modelView * position;\ngl_Position = czm_projection * positionEC;\n}\n"}),r("Scene/DepthPlane",["../Core/BoundingSphere","../Core/Cartesian3","../Core/ComponentDatatype","../Core/defined","../Core/FeatureDetection","../Core/Geometry","../Core/GeometryAttribute","../Core/PrimitiveType","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/VertexArray","../Shaders/DepthPlaneFS","../Shaders/DepthPlaneVS","./DepthFunction","./Pass","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_){"use strict";function g(e,r){var i=e.radii,n=r.camera.positionWC,o=t.multiplyComponents(e.oneOverRadii,n,E),a=t.magnitude(o),s=t.normalize(o,S),l=t.normalize(t.cross(t.UNIT_Z,o,w),w),u=t.normalize(t.cross(s,l,T),T),c=Math.sqrt(t.magnitudeSquared(o)-1),h=t.multiplyByScalar(s,1/a,E),d=c/a,p=t.multiplyByScalar(l,d,S),m=t.multiplyByScalar(u,d,w),f=t.add(h,m,T);t.subtract(f,p,f),t.multiplyComponents(i,f,f),t.pack(f,C,0);var v=t.subtract(h,m,T);t.subtract(v,p,v),t.multiplyComponents(i,v,v),t.pack(v,C,3);var _=t.add(h,m,T);t.add(_,p,_),t.multiplyComponents(i,_,_),t.pack(_,C,6);var g=t.subtract(h,m,T);return t.add(g,p,g),t.multiplyComponents(i,g,g),t.pack(g,C,9),C}var y=function(){this._rs=void 0,this._sp=void 0,this._va=void 0,this._command=void 0,this._mode=void 0},C=n.supportsTypedArrays()?new Float32Array(12):[],E=new t,S=new t,w=new t,T=new t;return y.prototype.update=function(n){if(this._mode=n.mode,n.mode===_.SCENE3D){var y=n.context,C=n.mapProjection.ellipsoid;i(this._command)||(this._rs=c.fromCache({cull:{enabled:!0},depthTest:{enabled:!0,func:f.ALWAYS},colorMask:{red:!1,green:!1,blue:!1,alpha:!1}}),this._sp=h.fromCache({context:y,vertexShaderSource:m,fragmentShaderSource:p,attributeLocations:{position:0}}),this._command=new u({renderState:this._rs,shaderProgram:this._sp,boundingVolume:new e(t.ZERO,C.maximumRadius),pass:v.OPAQUE,owner:this}));var E=g(C,n);if(i(this._va))this._va.getAttribute(0).vertexBuffer.copyFromArrayView(E);else{var S=new o({attributes:{position:new a({componentDatatype:r.FLOAT,componentsPerAttribute:3,values:E})},indices:[0,1,2,2,1,3],primitiveType:s.TRIANGLES});this._va=d.fromGeometry({context:y,geometry:S,attributeLocations:{position:0},bufferUsage:l.DYNAMIC_DRAW}),this._command.vertexArray=this._va}}},y.prototype.execute=function(e,t){this._mode===_.SCENE3D&&this._command.execute(e,t)},y.prototype.isDestroyed=function(){return!1},y.prototype.destroy=function(){this._sp=this._sp&&this._sp.destroy(),this._va=this._va&&this._va.destroy()},y}),r("Shaders/EllipsoidFS",[],function(){"use strict";return"#ifdef WRITE_DEPTH\n#ifdef GL_EXT_frag_depth\n#extension GL_EXT_frag_depth : enable\n#endif\n#endif\nuniform vec3 u_radii;\nuniform vec3 u_oneOverEllipsoidRadiiSquared;\nvarying vec3 v_positionEC;\nvec4 computeEllipsoidColor(czm_ray ray, float intersection, float side)\n{\nvec3 positionEC = czm_pointAlongRay(ray, intersection);\nvec3 positionMC = (czm_inverseModelView * vec4(positionEC, 1.0)).xyz;\nvec3 geodeticNormal = normalize(czm_geodeticSurfaceNormal(positionMC, vec3(0.0), u_oneOverEllipsoidRadiiSquared));\nvec3 sphericalNormal = normalize(positionMC / u_radii);\nvec3 normalMC = geodeticNormal * side;\nvec3 normalEC = normalize(czm_normal * normalMC);\nvec2 st = czm_ellipsoidWgs84TextureCoordinates(sphericalNormal);\nvec3 positionToEyeEC = -positionEC;\nczm_materialInput materialInput;\nmaterialInput.s = st.s;\nmaterialInput.st = st;\nmaterialInput.str = (positionMC + u_radii) / u_radii;\nmaterialInput.normalEC = normalEC;\nmaterialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(positionMC, normalEC);\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef ONLY_SUN_LIGHTING\nreturn czm_private_phong(normalize(positionToEyeEC), material);\n#else\nreturn czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\nvoid main()\n{\nfloat maxRadius = max(u_radii.x, max(u_radii.y, u_radii.z)) * 1.5;\nvec3 direction = normalize(v_positionEC);\nvec3 ellipsoidCenter = czm_modelView[3].xyz;\nfloat t1 = -1.0;\nfloat t2 = -1.0;\nfloat b = -2.0 * dot(direction, ellipsoidCenter);\nfloat c = dot(ellipsoidCenter, ellipsoidCenter) - maxRadius * maxRadius;\nfloat discriminant = b * b - 4.0 * c;\nif (discriminant >= 0.0) {\nt1 = (-b - sqrt(discriminant)) * 0.5;\nt2 = (-b + sqrt(discriminant)) * 0.5;\n}\nif (t1 < 0.0 && t2 < 0.0) {\ndiscard;\n}\nfloat t = min(t1, t2);\nif (t < 0.0) {\nt = 0.0;\n}\nczm_ellipsoid ellipsoid = czm_ellipsoidNew(ellipsoidCenter, u_radii);\nczm_ray ray = czm_ray(t * direction, direction);\nczm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\nif (czm_isEmpty(intersection))\n{\ndiscard;\n}\nvec4 outsideFaceColor = (intersection.start != 0.0) ? computeEllipsoidColor(ray, intersection.start, 1.0) : vec4(0.0);\nvec4 insideFaceColor = (outsideFaceColor.a < 1.0) ? computeEllipsoidColor(ray, intersection.stop, -1.0) : vec4(0.0);\ngl_FragColor = mix(insideFaceColor, outsideFaceColor, outsideFaceColor.a);\ngl_FragColor.a = 1.0 - (1.0 - insideFaceColor.a) * (1.0 - outsideFaceColor.a);\n#ifdef WRITE_DEPTH\n#ifdef GL_EXT_frag_depth\nt = (intersection.start != 0.0) ? intersection.start : intersection.stop;\nvec3 positionEC = czm_pointAlongRay(ray, t);\nvec4 positionCC = czm_projection * vec4(positionEC, 1.0);\nfloat z = positionCC.z / positionCC.w;\nfloat n = czm_depthRange.near;\nfloat f = czm_depthRange.far;\ngl_FragDepthEXT = (z * (f - n) + f + n) * 0.5;\n#endif\n#endif\n}\n"}),r("Shaders/EllipsoidVS",[],function(){"use strict";return"attribute vec3 position;\nuniform vec3 u_radii;\nvarying vec3 v_positionEC;\nvoid main()\n{\nvec4 p = vec4(u_radii * position, 1.0);\nv_positionEC = (czm_modelView * p).xyz;\ngl_Position = czm_modelViewProjection * p;\ngl_Position.z = clamp(gl_Position.z, czm_depthRange.near, czm_depthRange.far);\n}\n"}),r("Scene/EllipsoidPrimitive",["../Core/BoundingSphere","../Core/BoxGeometry","../Core/Cartesian3","../Core/combine","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Matrix4","../Core/VertexFormat","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../Shaders/EllipsoidFS","../Shaders/EllipsoidVS","./BlendingState","./CullFace","./Material","./Pass","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";function w(e){var i=e.cache.ellipsoidPrimitive_vertexArray;if(o(i))return i;var n=t.createGeometry(t.fromDimensions({dimensions:new r(2,2,2),vertexFormat:u.POSITION_ONLY}));return i=f.fromGeometry({context:e,geometry:n,attributeLocations:T,bufferUsage:c.STATIC_DRAW,interleave:!0}),e.cache.ellipsoidPrimitive_vertexArray=i,i}var T={position:0},b=function(t){t=n(t,n.EMPTY_OBJECT),this.center=r.clone(n(t.center,r.ZERO)),this._center=new r,this.radii=r.clone(t.radii),this._radii=new r,this._oneOverEllipsoidRadiiSquared=new r,this._boundingSphere=new e,this.modelMatrix=l.clone(n(t.modelMatrix,l.IDENTITY)),this._modelMatrix=new l,this._computedModelMatrix=new l,this.show=n(t.show,!0),this.material=n(t.material,C.fromType(C.ColorType)),this._material=void 0,this._translucent=void 0,this.id=t.id,this._id=void 0,this.debugShowBoundingVolume=n(t.debugShowBoundingVolume,!1),this.onlySunLighting=n(t.onlySunLighting,!1),this._onlySunLighting=!1,this._depthTestEnabled=n(t.depthTestEnabled,!0),this._sp=void 0,this._rs=void 0,this._va=void 0,this._pickSP=void 0,this._pickId=void 0,this._colorCommand=new h({owner:n(t._owner,this)}),this._pickCommand=new h({owner:n(t._owner,this)});var i=this;this._uniforms={u_radii:function(){return i.radii},u_oneOverEllipsoidRadiiSquared:function(){return i._oneOverEllipsoidRadiiSquared}},this._pickUniforms={czm_pickColor:function(){return i._pickId.color}}};return b.prototype.update=function(t){if(this.show&&t.mode===S.SCENE3D&&o(this.center)&&o(this.radii)){var n=t.context,a=this.material.isTranslucent(),s=this._translucent!==a;(!o(this._rs)||s)&&(this._translucent=a,this._rs=d.fromCache({cull:{enabled:!0,face:y.FRONT},depthTest:{enabled:this._depthTestEnabled},depthMask:!a&&n.fragmentDepth,blending:a?g.ALPHA_BLEND:void 0})),o(this._va)||(this._va=w(n));var u=!1,c=this.radii;if(!r.equals(this._radii,c)){r.clone(c,this._radii);var h=this._oneOverEllipsoidRadiiSquared;h.x=1/(c.x*c.x),h.y=1/(c.y*c.y),h.z=1/(c.z*c.z),u=!0}l.equals(this.modelMatrix,this._modelMatrix)&&r.equals(this.center,this._center)||(l.clone(this.modelMatrix,this._modelMatrix),r.clone(this.center,this._center),l.multiplyByTranslation(this.modelMatrix,this.center,this._computedModelMatrix),u=!0),u&&(r.clone(r.ZERO,this._boundingSphere.center),this._boundingSphere.radius=r.maximumComponent(c),e.transform(this._boundingSphere,this._computedModelMatrix,this._boundingSphere));var f=this._material!==this.material;this._material=this.material,this._material.update(n);var C=this.onlySunLighting!==this._onlySunLighting;this._onlySunLighting=this.onlySunLighting;var b,x=this._colorCommand;(f||C||s)&&(b=new m({sources:[this.material.shaderSource,v]}),this.onlySunLighting&&b.defines.push("ONLY_SUN_LIGHTING"),!a&&n.fragmentDepth&&b.defines.push("WRITE_DEPTH"),this._sp=p.replaceCache({context:n,shaderProgram:this._sp,vertexShaderSource:_,fragmentShaderSource:b,attributeLocations:T}),x.vertexArray=this._va,x.renderState=this._rs,x.shaderProgram=this._sp,x.uniformMap=i(this._uniforms,this.material._uniforms),x.executeInClosestFrustum=a);var P=t.commandList,A=t.passes;if(A.render&&(x.boundingVolume=this._boundingSphere,x.debugShowBoundingVolume=this.debugShowBoundingVolume,x.modelMatrix=this._computedModelMatrix,x.pass=a?E.TRANSLUCENT:E.OPAQUE,P.push(x)),A.pick){var I=this._pickCommand;o(this._pickId)&&this._id===this.id||(this._id=this.id,this._pickId=this._pickId&&this._pickId.destroy(),this._pickId=n.createPickId({primitive:this,id:this.id})),(f||C||!o(this._pickSP))&&(b=new m({sources:[this.material.shaderSource,v],pickColorQualifier:"uniform"}),this.onlySunLighting&&b.defines.push("ONLY_SUN_LIGHTING"),!a&&n.fragmentDepth&&b.defines.push("WRITE_DEPTH"),this._pickSP=p.replaceCache({context:n,shaderProgram:this._pickSP,vertexShaderSource:_,fragmentShaderSource:b,attributeLocations:T}),I.vertexArray=this._va,I.renderState=this._rs,I.shaderProgram=this._pickSP,I.uniformMap=i(i(this._uniforms,this._pickUniforms),this.material._uniforms),I.executeInClosestFrustum=a),I.boundingVolume=this._boundingSphere,I.modelMatrix=this._computedModelMatrix,I.pass=a?E.TRANSLUCENT:E.OPAQUE,P.push(I)}}},b.prototype.isDestroyed=function(){return!1},b.prototype.destroy=function(){return this._sp=this._sp&&this._sp.destroy(),this._pickSP=this._pickSP&&this._pickSP.destroy(),this._pickId=this._pickId&&this._pickId.destroy(),a(this)},b}),r("Shaders/Appearances/EllipsoidSurfaceAppearanceFS",[],function(){"use strict";return"varying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_st;\nvoid main()\n{\nczm_materialInput materialInput;\nvec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n#ifdef FACE_FORWARD\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\nmaterialInput.s = v_st.s;\nmaterialInput.st = v_st;\nmaterialInput.str = vec3(v_st, 0.0);\nmaterialInput.normalEC = normalEC;\nmaterialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\nvec3 positionToEyeEC = -v_positionEC;\nmaterialInput.positionToEyeEC = positionToEyeEC;\nczm_material material = czm_getMaterial(materialInput);\n#ifdef FLAT\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\n#endif\n}\n"}),r("Shaders/Appearances/EllipsoidSurfaceAppearanceVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec2 st;\nvarying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_st;\nvoid main()\n{\nvec4 p = czm_computePosition();\nv_positionMC = position3DHigh + position3DLow;\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;\nv_st = st;\ngl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"}),r("Scene/EllipsoidSurfaceAppearance",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/VertexFormat","../Shaders/Appearances/EllipsoidSurfaceAppearanceFS","../Shaders/Appearances/EllipsoidSurfaceAppearanceVS","./Appearance","./Material"],function(e,t,r,i,n,o,a,s){ -"use strict";var l=function(r){r=e(r,e.EMPTY_OBJECT);var i=e(r.translucent,!0),l=e(r.aboveGround,!1);this.material=t(r.material)?r.material:s.fromType(s.ColorType),this.translucent=e(r.translucent,!0),this._vertexShaderSource=e(r.vertexShaderSource,o),this._fragmentShaderSource=e(r.fragmentShaderSource,n),this._renderState=a.getDefaultRenderState(i,!l,r.renderState),this._closed=!1,this._flat=e(r.flat,!1),this._faceForward=e(r.faceForward,l),this._aboveGround=l};return r(l.prototype,{vertexShaderSource:{get:function(){return this._vertexShaderSource}},fragmentShaderSource:{get:function(){return this._fragmentShaderSource}},renderState:{get:function(){return this._renderState}},closed:{get:function(){return this._closed}},vertexFormat:{get:function(){return l.VERTEX_FORMAT}},flat:{get:function(){return this._flat}},faceForward:{get:function(){return this._faceForward}},aboveGround:{get:function(){return this._aboveGround}}}),l.VERTEX_FORMAT=i.POSITION_AND_ST,l.prototype.getFragmentShaderSource=a.prototype.getFragmentShaderSource,l.prototype.isTranslucent=a.prototype.isTranslucent,l.prototype.getRenderState=a.prototype.getRenderState,l}),r("Shaders/PostProcessFilters/FXAA",[],function(){"use strict";return"#ifndef FXAA_PRESET\n#define FXAA_PRESET 3\n#endif\n#if (FXAA_PRESET == 3)\n#define FXAA_EDGE_THRESHOLD (1.0/8.0)\n#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n#define FXAA_SEARCH_STEPS 16\n#define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n#define FXAA_SUBPIX_CAP (3.0/4.0)\n#define FXAA_SUBPIX_TRIM (1.0/4.0)\n#endif\n#if (FXAA_PRESET == 4)\n#define FXAA_EDGE_THRESHOLD (1.0/8.0)\n#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n#define FXAA_SEARCH_STEPS 24\n#define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n#define FXAA_SUBPIX_CAP (3.0/4.0)\n#define FXAA_SUBPIX_TRIM (1.0/4.0)\n#endif\n#if (FXAA_PRESET == 5)\n#define FXAA_EDGE_THRESHOLD (1.0/8.0)\n#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)\n#define FXAA_SEARCH_STEPS 32\n#define FXAA_SEARCH_THRESHOLD (1.0/4.0)\n#define FXAA_SUBPIX_CAP (3.0/4.0)\n#define FXAA_SUBPIX_TRIM (1.0/4.0)\n#endif\n#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))\nfloat FxaaLuma(vec3 rgb) {\nreturn rgb.y * (0.587/0.299) + rgb.x;\n}\nvec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) {\nreturn (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b);\n}\nvec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) {\nfloat x = pos.x + float(off.x) * rcpFrame.x;\nfloat y = pos.y + float(off.y) * rcpFrame.y;\nreturn texture2D(tex, vec2(x, y));\n}\nvec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame)\n{\nvec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz;\nvec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz;\nvec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz;\nvec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz;\nvec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz;\nfloat lumaN = FxaaLuma(rgbN);\nfloat lumaW = FxaaLuma(rgbW);\nfloat lumaM = FxaaLuma(rgbM);\nfloat lumaE = FxaaLuma(rgbE);\nfloat lumaS = FxaaLuma(rgbS);\nfloat rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));\nfloat rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));\nfloat range = rangeMax - rangeMin;\nif(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD))\n{\nreturn rgbM;\n}\nvec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS;\nfloat lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;\nfloat rangeL = abs(lumaL - lumaM);\nfloat blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE;\nblendL = min(FXAA_SUBPIX_CAP, blendL);\nvec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz;\nvec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz;\nvec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz;\nvec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz;\nrgbL += (rgbNW + rgbNE + rgbSW + rgbSE);\nrgbL *= vec3(1.0/9.0);\nfloat lumaNW = FxaaLuma(rgbNW);\nfloat lumaNE = FxaaLuma(rgbNE);\nfloat lumaSW = FxaaLuma(rgbSW);\nfloat lumaSE = FxaaLuma(rgbSE);\nfloat edgeVert =\nabs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) +\nabs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) +\nabs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE));\nfloat edgeHorz =\nabs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) +\nabs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) +\nabs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));\nbool horzSpan = edgeHorz >= edgeVert;\nfloat lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;\nif(!horzSpan)\n{\nlumaN = lumaW;\nlumaS = lumaE;\n}\nfloat gradientN = abs(lumaN - lumaM);\nfloat gradientS = abs(lumaS - lumaM);\nlumaN = (lumaN + lumaM) * 0.5;\nlumaS = (lumaS + lumaM) * 0.5;\nif (gradientN < gradientS)\n{\nlumaN = lumaS;\nlumaN = lumaS;\ngradientN = gradientS;\nlengthSign *= -1.0;\n}\nvec2 posN;\nposN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);\nposN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);\ngradientN *= FXAA_SEARCH_THRESHOLD;\nvec2 posP = posN;\nvec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);\nfloat lumaEndN = lumaN;\nfloat lumaEndP = lumaN;\nbool doneN = false;\nbool doneP = false;\nposN += offNP * vec2(-1.0, -1.0);\nposP += offNP * vec2( 1.0, 1.0);\nfor(int i = 0; i < FXAA_SEARCH_STEPS; i++) {\nif(!doneN)\n{\nlumaEndN = FxaaLuma(texture2D(tex, posN.xy).xyz);\n}\nif(!doneP)\n{\nlumaEndP = FxaaLuma(texture2D(tex, posP.xy).xyz);\n}\ndoneN = doneN || (abs(lumaEndN - lumaN) >= gradientN);\ndoneP = doneP || (abs(lumaEndP - lumaN) >= gradientN);\nif(doneN && doneP)\n{\nbreak;\n}\nif(!doneN)\n{\nposN -= offNP;\n}\nif(!doneP)\n{\nposP += offNP;\n}\n}\nfloat dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;\nfloat dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;\nbool directionN = dstN < dstP;\nlumaEndN = directionN ? lumaEndN : lumaEndP;\nif(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))\n{\nlengthSign = 0.0;\n}\nfloat spanLength = (dstP + dstN);\ndstN = directionN ? dstN : dstP;\nfloat subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign;\nvec3 rgbF = texture2D(tex, vec2(\npos.x + (horzSpan ? 0.0 : subPixelOffset),\npos.y + (horzSpan ? subPixelOffset : 0.0))).xyz;\nreturn FxaaLerp3(rgbL, rgbF, blendL);\n}\nuniform sampler2D u_texture;\nuniform vec2 u_step;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = vec4(FxaaPixelShader(v_textureCoordinates, u_texture, u_step), 1.0);\n}\n"}),r("Scene/FXAA",["../Core/Cartesian2","../Core/Color","../Core/defined","../Core/destroyObject","../Core/PixelFormat","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/Renderbuffer","../Renderer/RenderbufferFormat","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/FXAA"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e){e._fbo=e._fbo&&e._fbo.destroy(),e._texture=e._texture&&e._texture.destroy(),e._depthTexture=e._depthTexture&&e._depthTexture.destroy(),e._depthRenderbuffer=e._depthRenderbuffer&&e._depthRenderbuffer.destroy(),e._fbo=void 0,e._texture=void 0,e._depthTexture=void 0,e._depthRenderbuffer=void 0,r(e._command)&&(e._command.shaderProgram=e._command.shaderProgram&&e._command.shaderProgram.destroy(),e._command=void 0)}var m=function(e){this._texture=void 0,this._depthTexture=void 0,this._depthRenderbuffer=void 0,this._fbo=void 0,this._command=void 0;var r=new o({color:new t(0,0,0,0),depth:1,owner:this});this._clearCommand=r};return m.prototype.update=function(t){var i=t.drawingBufferWidth,o=t.drawingBufferHeight,p=this._texture,m=!r(p)||p.width!==i||p.height!==o;if(m&&(this._texture=this._texture&&this._texture.destroy(),this._depthTexture=this._depthTexture&&this._depthTexture.destroy(),this._depthRenderbuffer=this._depthRenderbuffer&&this._depthRenderbuffer.destroy(),this._texture=new h({context:t,width:i,height:o,pixelFormat:n.RGBA,pixelDatatype:s.UNSIGNED_BYTE}),t.depthTexture?this._depthTexture=new h({context:t,width:i,height:o,pixelFormat:n.DEPTH_COMPONENT,pixelDatatype:s.UNSIGNED_SHORT}):this._depthRenderbuffer=new l({context:t,width:i,height:o,format:u.DEPTH_COMPONENT16})),(!r(this._fbo)||m)&&(this._fbo=this._fbo&&this._fbo.destroy(),this._fbo=new a({context:t,colorTextures:[this._texture],depthTexture:this._depthTexture,depthRenderbuffer:this._depthRenderbuffer,destroyAttachments:!1})),r(this._command)||(this._command=t.createViewportQuadCommand(d,{renderState:c.fromCache(),owner:this})),m){var f=this,v=new e(1/this._texture.width,1/this._texture.height);this._command.uniformMap={u_texture:function(){return f._texture},u_step:function(){return v}}}},m.prototype.execute=function(e,t){this._command.execute(e,t)},m.prototype.clear=function(e,r,i){var n=r.framebuffer;r.framebuffer=this._fbo,t.clone(i,this._clearCommand.color),this._clearCommand.execute(e,r),r.framebuffer=n},m.prototype.getColorFramebuffer=function(){return this._fbo},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return p(this),i(this)},m}),r("Scene/Fog",["../Core/Cartesian3","../Core/defined","../Core/Math","./SceneMode"],function(e,t,r,i){"use strict";function n(e){var t=a,r=t.length;if(e<t[0])return d=0;if(e>t[r-1])return d=r-2;if(e>=t[d]){if(r>d+1&&e<t[d+1])return d;if(r>d+2&&e<t[d+2])return++d,d}else if(d-1>=0&&e>=t[d-1])return--d,d;var i;for(i=0;r-2>i&&!(e>=t[i]&&e<t[i+1]);++i);return d=i}for(var o=function(){this.enabled=!0,this.density=2e-4,this.screenSpaceErrorFactor=2},a=[359.393,800.749,1275.6501,2151.1192,3141.7763,4777.5198,6281.2493,12364.307,15900.765,49889.0549,78026.8259,99260.7344,120036.3873,151011.0158,156091.1953,203849.3112,274866.9803,319916.3149,493552.0528,628733.5874],s=[2e-5,2e-4,1e-4,7e-5,5e-5,4e-5,3e-5,19e-6,1e-5,85e-7,62e-7,58e-7,53e-7,52e-7,51e-7,42e-7,4e-6,34e-7,26e-7,22e-7],l=0;l<s.length;++l)s[l]*=1e6;for(var u=s[1],c=s[s.length-1],h=0;h<s.length;++h)s[h]=(s[h]-c)/(u-c);var d=0,p=new e;return o.prototype.update=function(o){var l=o.fog.enabled=this.enabled;if(l){var h=o.camera,d=h.positionCartographic;if(!t(d)||d.height>8e5||o.mode!==i.SCENE3D)return void(o.fog.enabled=!1);var m=d.height,f=n(m),v=r.clamp((m-a[f])/(a[f+1]-a[f]),0,1),_=r.lerp(s[f],s[f+1],v),g=1e6*this.density,y=g/u*c;_=_*(g-y)*1e-6;var C=e.normalize(h.positionWC,p),E=r.clamp(e.dot(h.directionWC,C),0,1);_*=1-E,o.fog.density=_,o.fog.sse=this.screenSpaceErrorFactor}},o}),r("Scene/FrameRateMonitor",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/getTimestamp","../Core/TimeConstants"],function(e,t,r,i,n,o,a,s){"use strict";function l(e,t){if(!(e._pauseCount>0)){var r=a();if(e._needsQuietPeriod)e._needsQuietPeriod=!1,e._frameTimes.length=0,e._quietPeriodEndTime=r+e.quietPeriod/s.SECONDS_PER_MILLISECOND,e._warmupPeriodEndTime=e._quietPeriodEndTime+(e.warmupPeriod+e.samplingWindow)/s.SECONDS_PER_MILLISECOND;else if(r>=e._quietPeriodEndTime){e._frameTimes.push(r);var i=r-e.samplingWindow/s.SECONDS_PER_MILLISECOND;if(e._frameTimes.length>=2&&e._frameTimes[0]<=i){for(;e._frameTimes.length>=2&&e._frameTimes[1]<i;)e._frameTimes.shift();var n=(r-e._frameTimes[0])/(e._frameTimes.length-1);e._lastFramesPerSecond=1e3/n;var o=1e3/(r>e._warmupPeriodEndTime?e.minimumFrameRateAfterWarmup:e.minimumFrameRateDuringWarmup);n>o?e._frameRateIsLow||(e._frameRateIsLow=!0,e._needsQuietPeriod=!0,e.lowFrameRate.raiseEvent(e.scene,e._lastFramesPerSecond)):e._frameRateIsLow&&(e._frameRateIsLow=!1,e._needsQuietPeriod=!0,e.nominalFrameRate.raiseEvent(e.scene,e._lastFramesPerSecond))}}}}function u(e){document[e._hiddenPropertyName]?e.pause():e.unpause()}var c=function(r){function i(){u(n)}this._scene=r.scene,this.samplingWindow=e(r.samplingWindow,c.defaultSettings.samplingWindow),this.quietPeriod=e(r.quietPeriod,c.defaultSettings.quietPeriod),this.warmupPeriod=e(r.warmupPeriod,c.defaultSettings.warmupPeriod),this.minimumFrameRateDuringWarmup=e(r.minimumFrameRateDuringWarmup,c.defaultSettings.minimumFrameRateDuringWarmup),this.minimumFrameRateAfterWarmup=e(r.minimumFrameRateAfterWarmup,c.defaultSettings.minimumFrameRateAfterWarmup),this._lowFrameRate=new o,this._nominalFrameRate=new o,this._frameTimes=[],this._needsQuietPeriod=!0,this._quietPeriodEndTime=0,this._warmupPeriodEndTime=0,this._frameRateIsLow=!1,this._lastFramesPerSecond=void 0,this._pauseCount=0;var n=this;this._preRenderRemoveListener=this._scene.preRender.addEventListener(function(e,t){l(n,t)}),this._hiddenPropertyName=t(document.hidden)?"hidden":t(document.mozHidden)?"mozHidden":t(document.msHidden)?"msHidden":t(document.webkitHidden)?"webkitHidden":void 0;var a=t(document.hidden)?"visibilitychange":t(document.mozHidden)?"mozvisibilitychange":t(document.msHidden)?"msvisibilitychange":t(document.webkitHidden)?"webkitvisibilitychange":void 0;this._visibilityChangeRemoveListener=void 0,t(a)&&(document.addEventListener(a,i,!1),this._visibilityChangeRemoveListener=function(){document.removeEventListener(a,i,!1)})};return c.defaultSettings={samplingWindow:5,quietPeriod:2,warmupPeriod:5,minimumFrameRateDuringWarmup:4,minimumFrameRateAfterWarmup:8},c.fromScene=function(e){return(!t(e._frameRateMonitor)||e._frameRateMonitor.isDestroyed())&&(e._frameRateMonitor=new c({scene:e})),e._frameRateMonitor},r(c.prototype,{scene:{get:function(){return this._scene}},lowFrameRate:{get:function(){return this._lowFrameRate}},nominalFrameRate:{get:function(){return this._nominalFrameRate}},lastFramesPerSecond:{get:function(){return this._lastFramesPerSecond}}}),c.prototype.pause=function(){++this._pauseCount,1===this._pauseCount&&(this._frameTimes.length=0,this._lastFramesPerSecond=void 0)},c.prototype.unpause=function(){--this._pauseCount,this._pauseCount<=0&&(this._pauseCount=0,this._needsQuietPeriod=!0)},c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return this._preRenderRemoveListener(),t(this._visibilityChangeRemoveListener)&&this._visibilityChangeRemoveListener(),i(this)},c}),r("Scene/FrameState",["./SceneMode"],function(e){"use strict";var t=function(t,r){this.context=t,this.commandList=[],this.mode=e.SCENE3D,this.morphTime=e.getMorphTime(e.SCENE3D),this.frameNumber=0,this.time=void 0,this.mapProjection=void 0,this.camera=void 0,this.cullingVolume=void 0,this.occluder=void 0,this.passes={render:!1,pick:!1},this.creditDisplay=r,this.afterRender=[],this.scene3DOnly=!1,this.fog={enabled:!1,density:void 0,sse:void 0}};return t}),r("Scene/FrustumCommands",["../Core/defaultValue","./Pass"],function(e,t){"use strict";var r=function(r,i){this.near=e(r,0),this.far=e(i,0);for(var n=t.NUMBER_OF_PASSES,o=new Array(n),a=new Array(n),s=0;n>s;++s)o[s]=[],a[s]=0;this.commands=o,this.indices=a};return r}),r("Scene/GetFeatureInfoFormat",["../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/definedNotNull","../Core/DeveloperError","../Core/RuntimeError","./ImageryLayerFeatureInfo"],function(e,t,r,i,n,o,a){"use strict";function s(t){for(var r=[],n=t.features,o=0;o<n.length;++o){var s=n[o],l=new a;if(l.data=s,l.properties=s.properties,l.configureNameFromProperties(s.properties),l.configureDescriptionFromProperties(s.properties),i(s.geometry)&&"Point"===s.geometry.type){var u=s.geometry.coordinates[0],c=s.geometry.coordinates[1];l.position=e.fromDegrees(u,c)}r.push(l)}return r}function l(e){var t=e.documentElement;if("MultiFeatureCollection"===t.localName&&t.namespaceURI===v)return u(e);if("FeatureInfoResponse"===t.localName&&t.namespaceURI===_)return c(e);if("FeatureCollection"===t.localName&&t.namespaceURI===g)return h(e);if("ServiceExceptionReport"===t.localName)throw new o((new XMLSerializer).serializeToString(t));return p(e)}function u(e){for(var t=[],r=e.documentElement,i=r.getElementsByTagNameNS(v,"Feature"),n=0;n<i.length;++n){for(var o=i[n],s={},l=o.getElementsByTagNameNS(v,"Val"),u=0;u<l.length;++u){var c=l[u];if(c.hasAttribute("ref")){var h=c.getAttribute("ref"),d=c.textContent.trim();s[h]=d}}var p=new a;p.data=o,p.properties=s,p.configureNameFromProperties(s),p.configureDescriptionFromProperties(s),t.push(p)}return t}function c(e){for(var t=[],r=e.documentElement,i=r.getElementsByTagNameNS(_,"FIELDS"),n=0;n<i.length;++n){for(var o=i[n],s={},l=o.attributes,u=0;u<l.length;++u){var c=l[u];s[c.name]=c.value}var h=new a;h.data=o,h.properties=s,h.configureNameFromProperties(s),h.configureDescriptionFromProperties(s),t.push(h)}return t}function h(e){for(var t=[],r=e.documentElement,i=r.getElementsByTagNameNS(y,"featureMember"),n=0;n<i.length;++n){var o=i[n],s={};d(o,s);var l=new a;l.data=o,l.properties=s,l.configureNameFromProperties(s),l.configureDescriptionFromProperties(s),t.push(l)}return t}function d(e,t){for(var r=!0,i=0;i<e.children.length;++i){var n=e.children[i];n.nodeType===Node.ELEMENT_NODE&&(r=!1),"Point"!==n.localName&&"LineString"!==n.localName&&"Polygon"!==n.localName&&n.hasChildNodes()&&d(n,t)&&(t[n.localName]=n.textContent)}return r}function p(e){var t=(new XMLSerializer).serializeToString(e),r=document.createElement("div"),i=document.createElement("pre");i.textContent=t,r.appendChild(i);var n=new a;return n.data=e,n.description=r.innerHTML,[n]}function m(e){if(C.test(e))return void 0;if(E.test(e))return void 0;var t,r=S.exec(e);r&&r.length>1&&(t=r[1]);var i=new a;return i.name=t,i.description=e,i.data=e,[i]}var f=function(e,t,i){this.type=e,r(t)||("json"===e?t="application/json":"xml"===e?t="text/xml":"html"===e?t="text/html":"text"===e&&(t="text/plain")),this.format=t,r(i)||("json"===e?i=s:"xml"===e?i=l:"html"===e?i=m:"text"===e&&(i=m)),this.callback=i},v="http://www.mapinfo.com/mxp",_="http://www.esri.com/wms",g="http://www.opengis.net/wfs",y="http://www.opengis.net/gml",C=/<body>\s*<\/body>/im,E=/<ServiceExceptionReport([\s\S]*)<\/ServiceExceptionReport>/im,S=/<title>([\s\S]*)<\/title>/im;return f}),r("Shaders/GlobeFS",[],function(){"use strict";return"uniform vec4 u_initialColor;\n#if TEXTURE_UNITS > 0\nuniform sampler2D u_dayTextures[TEXTURE_UNITS];\nuniform vec4 u_dayTextureTranslationAndScale[TEXTURE_UNITS];\n#ifdef APPLY_ALPHA\nuniform float u_dayTextureAlpha[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_BRIGHTNESS\nuniform float u_dayTextureBrightness[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_CONTRAST\nuniform float u_dayTextureContrast[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_HUE\nuniform float u_dayTextureHue[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_SATURATION\nuniform float u_dayTextureSaturation[TEXTURE_UNITS];\n#endif\n#ifdef APPLY_GAMMA\nuniform float u_dayTextureOneOverGamma[TEXTURE_UNITS];\n#endif\nuniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS];\n#endif\n#ifdef SHOW_REFLECTIVE_OCEAN\nuniform sampler2D u_waterMask;\nuniform vec4 u_waterMaskTranslationAndScale;\nuniform float u_zoomedOutOceanSpecularIntensity;\n#endif\n#ifdef SHOW_OCEAN_WAVES\nuniform sampler2D u_oceanNormalMap;\n#endif\n#ifdef ENABLE_DAYNIGHT_SHADING\nuniform vec2 u_lightingFadeDistance;\n#endif\nvarying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_textureCoordinates;\nvarying vec3 v_normalMC;\nvarying vec3 v_normalEC;\n#ifdef FOG\nvarying float v_distance;\nvarying vec3 v_rayleighColor;\nvarying vec3 v_mieColor;\n#endif\nvec4 sampleAndBlend(\nvec4 previousColor,\nsampler2D texture,\nvec2 tileTextureCoordinates,\nvec4 textureCoordinateRectangle,\nvec4 textureCoordinateTranslationAndScale,\nfloat textureAlpha,\nfloat textureBrightness,\nfloat textureContrast,\nfloat textureHue,\nfloat textureSaturation,\nfloat textureOneOverGamma)\n{\nvec2 alphaMultiplier = step(textureCoordinateRectangle.st, tileTextureCoordinates);\ntextureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;\nalphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates);\ntextureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y;\nvec2 translation = textureCoordinateTranslationAndScale.xy;\nvec2 scale = textureCoordinateTranslationAndScale.zw;\nvec2 textureCoordinates = tileTextureCoordinates * scale + translation;\nvec4 value = texture2D(texture, textureCoordinates);\nvec3 color = value.rgb;\nfloat alpha = value.a;\n#ifdef APPLY_BRIGHTNESS\ncolor = mix(vec3(0.0), color, textureBrightness);\n#endif\n#ifdef APPLY_CONTRAST\ncolor = mix(vec3(0.5), color, textureContrast);\n#endif\n#ifdef APPLY_HUE\ncolor = czm_hue(color, textureHue);\n#endif\n#ifdef APPLY_SATURATION\ncolor = czm_saturation(color, textureSaturation);\n#endif\n#ifdef APPLY_GAMMA\ncolor = pow(color, vec3(textureOneOverGamma));\n#endif\nfloat sourceAlpha = alpha * textureAlpha;\nfloat outAlpha = mix(previousColor.a, 1.0, sourceAlpha);\nvec3 outColor = mix(previousColor.rgb * previousColor.a, color, sourceAlpha) / outAlpha;\nreturn vec4(outColor, outAlpha);\n}\nvec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates);\nvec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float specularMapValue);\nvoid main()\n{\nvec4 color = computeDayColor(u_initialColor, clamp(v_textureCoordinates, 0.0, 1.0));\n#ifdef SHOW_TILE_BOUNDARIES\nif (v_textureCoordinates.x < (1.0/256.0) || v_textureCoordinates.x > (255.0/256.0) ||\nv_textureCoordinates.y < (1.0/256.0) || v_textureCoordinates.y > (255.0/256.0))\n{\ncolor = vec4(1.0, 0.0, 0.0, 1.0);\n}\n#endif\n#if defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING)\nvec3 normalMC = normalize(czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\nvec3 normalEC = normalize(czm_normal3D * normalMC);\n#endif\n#ifdef SHOW_REFLECTIVE_OCEAN\nvec2 waterMaskTranslation = u_waterMaskTranslationAndScale.xy;\nvec2 waterMaskScale = u_waterMaskTranslationAndScale.zw;\nvec2 waterMaskTextureCoordinates = v_textureCoordinates * waterMaskScale + waterMaskTranslation;\nfloat mask = texture2D(u_waterMask, waterMaskTextureCoordinates).r;\nif (mask > 0.0)\n{\nmat3 enuToEye = czm_eastNorthUpToEyeCoordinates(v_positionMC, normalEC);\nvec2 ellipsoidTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC);\nvec2 ellipsoidFlippedTextureCoordinates = czm_ellipsoidWgs84TextureCoordinates(normalMC.zyx);\nvec2 textureCoordinates = mix(ellipsoidTextureCoordinates, ellipsoidFlippedTextureCoordinates, czm_morphTime * smoothstep(0.9, 0.95, normalMC.z));\ncolor = computeWaterColor(v_positionEC, textureCoordinates, enuToEye, color, mask);\n}\n#endif\n#ifdef ENABLE_VERTEX_LIGHTING\nfloat diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalize(v_normalEC)) * 0.9 + 0.3, 0.0, 1.0);\nvec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);\n#elif defined(ENABLE_DAYNIGHT_SHADING)\nfloat diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * 5.0 + 0.3, 0.0, 1.0);\nfloat cameraDist = length(czm_view[3]);\nfloat fadeOutDist = u_lightingFadeDistance.x;\nfloat fadeInDist = u_lightingFadeDistance.y;\nfloat t = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0);\ndiffuseIntensity = mix(1.0, diffuseIntensity, t);\nvec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a);\n#else\nvec4 finalColor = color;\n#endif\n#ifdef FOG\nconst float fExposure = 2.0;\nvec3 fogColor = v_mieColor + finalColor.rgb * v_rayleighColor;\nfogColor = vec3(1.0) - exp(-fExposure * fogColor);\ngl_FragColor = vec4(czm_fog(v_distance, finalColor.rgb, fogColor), finalColor.a);\n#else\ngl_FragColor = finalColor;\n#endif\n}\n#ifdef SHOW_REFLECTIVE_OCEAN\nfloat waveFade(float edge0, float edge1, float x)\n{\nfloat y = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\nreturn pow(1.0 - y, 5.0);\n}\nfloat linearFade(float edge0, float edge1, float x)\n{\nreturn clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\nconst float oceanFrequencyLowAltitude = 825000.0;\nconst float oceanAnimationSpeedLowAltitude = 0.004;\nconst float oceanOneOverAmplitudeLowAltitude = 1.0 / 2.0;\nconst float oceanSpecularIntensity = 0.5;\nconst float oceanFrequencyHighAltitude = 125000.0;\nconst float oceanAnimationSpeedHighAltitude = 0.008;\nconst float oceanOneOverAmplitudeHighAltitude = 1.0 / 2.0;\nvec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat3 enuToEye, vec4 imageryColor, float maskValue)\n{\nvec3 positionToEyeEC = -positionEyeCoordinates;\nfloat positionToEyeECLength = length(positionToEyeEC);\nvec3 normalizedpositionToEyeEC = normalize(normalize(positionToEyeEC));\nfloat waveIntensity = waveFade(70000.0, 1000000.0, positionToEyeECLength);\n#ifdef SHOW_OCEAN_WAVES\nfloat time = czm_frameNumber * oceanAnimationSpeedHighAltitude;\nvec4 noise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyHighAltitude, time, 0.0);\nvec3 normalTangentSpaceHighAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeHighAltitude);\ntime = czm_frameNumber * oceanAnimationSpeedLowAltitude;\nnoise = czm_getWaterNoise(u_oceanNormalMap, textureCoordinates * oceanFrequencyLowAltitude, time, 0.0);\nvec3 normalTangentSpaceLowAltitude = vec3(noise.xy, noise.z * oceanOneOverAmplitudeLowAltitude);\nfloat highAltitudeFade = linearFade(0.0, 60000.0, positionToEyeECLength);\nfloat lowAltitudeFade = 1.0 - linearFade(20000.0, 60000.0, positionToEyeECLength);\nvec3 normalTangentSpace =\n(highAltitudeFade * normalTangentSpaceHighAltitude) +\n(lowAltitudeFade * normalTangentSpaceLowAltitude);\nnormalTangentSpace = normalize(normalTangentSpace);\nnormalTangentSpace.xy *= waveIntensity;\nnormalTangentSpace = normalize(normalTangentSpace);\n#else\nvec3 normalTangentSpace = vec3(0.0, 0.0, 1.0);\n#endif\nvec3 normalEC = enuToEye * normalTangentSpace;\nconst vec3 waveHighlightColor = vec3(0.3, 0.45, 0.6);\nfloat diffuseIntensity = czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * maskValue;\nvec3 diffuseHighlight = waveHighlightColor * diffuseIntensity;\n#ifdef SHOW_OCEAN_WAVES\nfloat tsPerturbationRatio = normalTangentSpace.z;\nvec3 nonDiffuseHighlight = mix(waveHighlightColor * 5.0 * (1.0 - tsPerturbationRatio), vec3(0.0), diffuseIntensity);\n#else\nvec3 nonDiffuseHighlight = vec3(0.0);\n#endif\nfloat specularIntensity = czm_getSpecular(czm_sunDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0) + 0.25 * czm_getSpecular(czm_moonDirectionEC, normalizedpositionToEyeEC, normalEC, 10.0);\nfloat surfaceReflectance = mix(0.0, mix(u_zoomedOutOceanSpecularIntensity, oceanSpecularIntensity, waveIntensity), maskValue);\nfloat specular = specularIntensity * surfaceReflectance;\nreturn vec4(imageryColor.rgb + diffuseHighlight + nonDiffuseHighlight + specular, imageryColor.a);\n}\n#endif\n"}),r("Shaders/GlobeFSPole",[],function(){"use strict";return"uniform vec3 u_color;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nczm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC();\nvec3 direction = normalize(czm_windowToEyeCoordinates(gl_FragCoord).xyz);\nczm_ray ray = czm_ray(vec3(0.0), direction);\nczm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid);\nif (!czm_isEmpty(intersection))\n{\nvec3 positionEC = czm_pointAlongRay(ray, intersection.start);\nvec3 positionMC = (czm_inverseModelView * vec4(positionEC, 1.0)).xyz;\nvec3 normalMC = normalize(czm_geodeticSurfaceNormal(positionMC, vec3(0.0), vec3(1.0)));\nvec3 normalEC = normalize(czm_normal * normalMC);\nvec3 startDayColor = u_color;\ngl_FragColor = vec4(startDayColor, 1.0);\n}\nelse\n{\ndiscard;\n}\n}\n"}),r("Shaders/GlobeVS",[],function(){"use strict";return"attribute vec4 position3DAndHeight;\nattribute vec3 textureCoordAndEncodedNormals;\nuniform vec3 u_center3D;\nuniform mat4 u_modifiedModelView;\nuniform vec4 u_tileRectangle;\nuniform vec2 u_southAndNorthLatitude;\nuniform vec2 u_southMercatorYAndOneOverHeight;\nvarying vec3 v_positionMC;\nvarying vec3 v_positionEC;\nvarying vec2 v_textureCoordinates;\nvarying vec3 v_normalMC;\nvarying vec3 v_normalEC;\n#ifdef FOG\nvarying float v_distance;\nvarying vec3 v_mieColor;\nvarying vec3 v_rayleighColor;\n#endif\nvec4 getPosition(vec3 position3DWC);\nfloat get2DYPositionFraction();\nvec4 getPosition3DMode(vec3 position3DWC)\n{\nreturn czm_projection * (u_modifiedModelView * vec4(position3DAndHeight.xyz, 1.0));\n}\nfloat get2DMercatorYPositionFraction()\n{\nconst float maxTileWidth = 0.003068;\nfloat positionFraction = textureCoordAndEncodedNormals.y;\nfloat southLatitude = u_southAndNorthLatitude.x;\nfloat northLatitude = u_southAndNorthLatitude.y;\nif (northLatitude - southLatitude > maxTileWidth)\n{\nfloat southMercatorY = u_southMercatorYAndOneOverHeight.x;\nfloat oneOverMercatorHeight = u_southMercatorYAndOneOverHeight.y;\nfloat currentLatitude = mix(southLatitude, northLatitude, textureCoordAndEncodedNormals.y);\ncurrentLatitude = clamp(currentLatitude, -czm_webMercatorMaxLatitude, czm_webMercatorMaxLatitude);\npositionFraction = czm_latitudeToWebMercatorFraction(currentLatitude, southMercatorY, oneOverMercatorHeight);\n}\nreturn positionFraction;\n}\nfloat get2DGeographicYPositionFraction()\n{\nreturn textureCoordAndEncodedNormals.y;\n}\nvec4 getPositionPlanarEarth(vec3 position3DWC, float height2D)\n{\nfloat yPositionFraction = get2DYPositionFraction();\nvec4 rtcPosition2D = vec4(height2D, mix(u_tileRectangle.st, u_tileRectangle.pq, vec2(textureCoordAndEncodedNormals.x, yPositionFraction)), 1.0);\nreturn czm_projection * (u_modifiedModelView * rtcPosition2D);\n}\nvec4 getPosition2DMode(vec3 position3DWC)\n{\nreturn getPositionPlanarEarth(position3DWC, 0.0);\n}\nvec4 getPositionColumbusViewMode(vec3 position3DWC)\n{\nreturn getPositionPlanarEarth(position3DWC, position3DAndHeight.w);\n}\nvec4 getPositionMorphingMode(vec3 position3DWC)\n{\nfloat yPositionFraction = get2DYPositionFraction();\nvec4 position2DWC = vec4(0.0, mix(u_tileRectangle.st, u_tileRectangle.pq, vec2(textureCoordAndEncodedNormals.x, yPositionFraction)), 1.0);\nvec4 morphPosition = czm_columbusViewMorph(position2DWC, vec4(position3DWC, 1.0), czm_morphTime);\nreturn czm_modelViewProjection * morphPosition;\n}\nvoid main()\n{\nvec3 position3DWC = position3DAndHeight.xyz + u_center3D;\ngl_Position = getPosition(position3DWC);\n#if defined(ENABLE_VERTEX_LIGHTING)\nv_positionEC = (czm_modelView3D * vec4(position3DWC, 1.0)).xyz;\nv_positionMC = position3DWC;\nfloat encodedNormal = textureCoordAndEncodedNormals.z;\nv_normalMC = czm_octDecode(encodedNormal);\nv_normalEC = czm_normal3D * v_normalMC;\n#elif defined(SHOW_REFLECTIVE_OCEAN) || defined(ENABLE_DAYNIGHT_SHADING)\nv_positionEC = (czm_modelView3D * vec4(position3DWC, 1.0)).xyz;\nv_positionMC = position3DWC;\n#endif\nv_textureCoordinates = textureCoordAndEncodedNormals.xy;\n#ifdef FOG\nAtmosphereColor atmosColor = computeGroundAtmosphereFromSpace(position3DWC);\nv_mieColor = atmosColor.mie;\nv_rayleighColor = atmosColor.rayleigh;\nv_distance = length((czm_modelView3D * vec4(position3DWC, 1.0)).xyz);\n#endif\n}\n"}),r("Shaders/GlobeVSPole",[],function(){"use strict";return"attribute vec4 position;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nfloat x = (position.x - czm_viewport.x) / czm_viewport.z;\nfloat y = (position.y - czm_viewport.y) / czm_viewport.w;\nv_textureCoordinates = vec2(x, y);\ngl_Position = czm_viewportOrthographic * position;\n}\n"}),r("Shaders/GroundAtmosphere",[],function(){"use strict";return"const float fInnerRadius = 6378137.0;\nconst float fOuterRadius = 6378137.0 * 1.025;\nconst float fOuterRadius2 = fOuterRadius * fOuterRadius;\nconst float Kr = 0.0025;\nconst float Km = 0.0015;\nconst float ESun = 15.0;\nconst float fKrESun = Kr * ESun;\nconst float fKmESun = Km * ESun;\nconst float fKr4PI = Kr * 4.0 * czm_pi;\nconst float fKm4PI = Km * 4.0 * czm_pi;\nconst float fScale = 1.0 / (fOuterRadius - fInnerRadius);\nconst float fScaleDepth = 0.25;\nconst float fScaleOverScaleDepth = fScale / fScaleDepth;\nstruct AtmosphereColor\n{\nvec3 mie;\nvec3 rayleigh;\n};\nconst int nSamples = 2;\nconst float fSamples = 2.0;\nfloat scale(float fCos)\n{\nfloat x = 1.0 - fCos;\nreturn fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n}\nAtmosphereColor computeGroundAtmosphereFromSpace(vec3 v3Pos)\n{\nvec3 v3InvWavelength = vec3(1.0 / pow(0.650, 4.0), 1.0 / pow(0.570, 4.0), 1.0 / pow(0.475, 4.0));\nvec3 v3Ray = v3Pos - czm_viewerPositionWC;\nfloat fFar = length(v3Ray);\nv3Ray /= fFar;\nfloat fCameraHeight = length(czm_viewerPositionWC);\nfloat fCameraHeight2 = fCameraHeight * fCameraHeight;\nfloat B = 2.0 * length(czm_viewerPositionWC) * dot(normalize(czm_viewerPositionWC), v3Ray);\nfloat C = fCameraHeight2 - fOuterRadius2;\nfloat fDet = max(0.0, B*B - 4.0 * C);\nfloat fNear = 0.5 * (-B - sqrt(fDet));\nvec3 v3Start = czm_viewerPositionWC + v3Ray * fNear;\nfFar -= fNear;\nfloat fDepth = exp((fInnerRadius - fOuterRadius) / fScaleDepth);\nfloat fLightAngle = 1.0;\nfloat fCameraAngle = dot(-v3Ray, v3Pos) / length(v3Pos);\nfloat fCameraScale = scale(fCameraAngle);\nfloat fLightScale = scale(fLightAngle);\nfloat fCameraOffset = fDepth*fCameraScale;\nfloat fTemp = (fLightScale + fCameraScale);\nfloat fSampleLength = fFar / fSamples;\nfloat fScaledLength = fSampleLength * fScale;\nvec3 v3SampleRay = v3Ray * fSampleLength;\nvec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\nvec3 v3FrontColor = vec3(0.0);\nvec3 v3Attenuate = vec3(0.0);\nfor(int i=0; i<nSamples; i++)\n{\nfloat fHeight = length(v3SamplePoint);\nfloat fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\nfloat fScatter = fDepth*fTemp - fCameraOffset;\nv3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\nv3FrontColor += v3Attenuate * (fDepth * fScaledLength);\nv3SamplePoint += v3SampleRay;\n}\nAtmosphereColor color;\ncolor.mie = v3FrontColor * (v3InvWavelength * fKrESun + fKmESun);\ncolor.rayleigh = v3Attenuate;\nreturn color;\n}\n"; -}),r("Scene/terrainAttributeLocations",[],function(){"use strict";return{position3DAndHeight:0,textureCoordAndEncodedNormals:1}}),r("Scene/GlobeSurfaceShaderSet",["../Core/defined","../Core/destroyObject","../Renderer/ShaderProgram","../Scene/SceneMode","../Scene/terrainAttributeLocations"],function(e,t,r,i,n){"use strict";function o(e,t,r){this.numberOfDayTextures=e,this.flags=t,this.shaderProgram=r}function a(){this.baseVertexShaderSource=void 0,this.baseFragmentShaderSource=void 0,this._attributeLocations=n,this._shadersByTexturesFlags=[],this._pickShaderPrograms=[]}function s(e){var t,r="vec4 getPosition(vec3 position3DWC) { return getPosition3DMode(position3DWC); }",n="vec4 getPosition(vec3 position3DWC) { return getPosition2DMode(position3DWC); }",o="vec4 getPosition(vec3 position3DWC) { return getPositionColumbusViewMode(position3DWC); }",a="vec4 getPosition(vec3 position3DWC) { return getPositionMorphingMode(position3DWC); }";switch(e){case i.SCENE3D:t=r;break;case i.SCENE2D:t=n;break;case i.COLUMBUS_VIEW:t=o;break;case i.MORPHING:t=a}return t}function l(e){var t="float get2DYPositionFraction() { return get2DGeographicYPositionFraction(); }",r="float get2DYPositionFraction() { return get2DMercatorYPositionFraction(); }";return e?r:t}return a.prototype.getShaderProgram=function(t,i,n,a,u,c,h,d,p,m,f,v,_,g,y,C){var E=i|u<<2|c<<3|h<<4|d<<5|p<<6|m<<7|f<<8|v<<9|_<<10|g<<11|y<<12|C<<13,S=n.surfaceShader;if(e(S)&&S.numberOfDayTextures===a&&S.flags===E)return S.shaderProgram;var w=this._shadersByTexturesFlags[a];if(e(w)||(w=this._shadersByTexturesFlags[a]=[]),S=w[E],!e(S)){var T=this.baseVertexShaderSource.clone(),b=this.baseFragmentShaderSource.clone();b.defines.push("TEXTURE_UNITS "+a),u&&b.defines.push("APPLY_BRIGHTNESS"),c&&b.defines.push("APPLY_CONTRAST"),h&&b.defines.push("APPLY_HUE"),d&&b.defines.push("APPLY_SATURATION"),p&&b.defines.push("APPLY_GAMMA"),m&&b.defines.push("APPLY_ALPHA"),f&&(b.defines.push("SHOW_REFLECTIVE_OCEAN"),T.defines.push("SHOW_REFLECTIVE_OCEAN")),v&&b.defines.push("SHOW_OCEAN_WAVES"),_&&(g?(T.defines.push("ENABLE_VERTEX_LIGHTING"),b.defines.push("ENABLE_VERTEX_LIGHTING")):(T.defines.push("ENABLE_DAYNIGHT_SHADING"),b.defines.push("ENABLE_DAYNIGHT_SHADING"))),C&&(T.defines.push("FOG"),b.defines.push("FOG"));for(var x=" vec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates)\n {\n vec4 color = initialColor;\n",P=0;a>P;++P)x+=" color = sampleAndBlend(\n color,\n u_dayTextures["+P+"],\n textureCoordinates,\n u_dayTextureTexCoordsRectangle["+P+"],\n u_dayTextureTranslationAndScale["+P+"],\n "+(m?"u_dayTextureAlpha["+P+"]":"1.0")+",\n "+(u?"u_dayTextureBrightness["+P+"]":"0.0")+",\n "+(c?"u_dayTextureContrast["+P+"]":"0.0")+",\n "+(h?"u_dayTextureHue["+P+"]":"0.0")+",\n "+(d?"u_dayTextureSaturation["+P+"]":"0.0")+",\n "+(p?"u_dayTextureOneOverGamma["+P+"]":"0.0")+"\n );\n";x+=" return color;\n }",b.sources.push(x),T.sources.push(s(i)),T.sources.push(l(y));var A=r.fromCache({context:t,vertexShaderSource:T,fragmentShaderSource:b,attributeLocations:this._attributeLocations});S=w[E]=new o(a,E,A)}return n.surfaceShader=S,S.shaderProgram},a.prototype.getPickShaderProgram=function(t,i,n){var o=i|n<<2,a=this._pickShaderPrograms[o];if(!e(a)){var u=this.baseVertexShaderSource.clone();u.sources.push(s(i)),u.sources.push(l(n));var c="void main()\n{\n gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n}\n";a=this._pickShaderPrograms[o]=r.fromCache({context:t,vertexShaderSource:u,fragmentShaderSource:c,attributeLocations:this._attributeLocations})}return a},a.prototype.destroy=function(){var r=this._shadersByTexturesFlags;for(var i in r)if(r.hasOwnProperty(i)){var n=r[i];if(!e(n))continue;for(var o in n)if(n.hasOwnProperty(o)){var a=n[o];e(a)&&a.shaderProgram.destroy()}}return t(this)},a}),r("Scene/ImageryState",["../Core/freezeObject"],function(e){"use strict";var t={UNLOADED:0,TRANSITIONING:1,RECEIVED:2,TEXTURE_LOADED:3,READY:4,FAILED:5,INVALID:6,PLACEHOLDER:7};return e(t)}),r("Scene/QuadtreeTileLoadState",["../Core/freezeObject"],function(e){"use strict";var t={START:0,LOADING:1,DONE:2,FAILED:3};return e(t)}),r("Scene/TerrainState",["../Core/freezeObject"],function(e){"use strict";var t={FAILED:0,UNLOADED:1,RECEIVING:2,RECEIVED:3,TRANSFORMING:4,TRANSFORMED:5,READY:6};return e(t)}),r("Scene/TileTerrain",["../Core/BoundingSphere","../Core/Cartesian3","../Core/ComponentDatatype","../Core/defined","../Core/DeveloperError","../Core/IndexDatatype","../Core/OrientedBoundingBox","../Core/TileProviderError","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/VertexArray","../ThirdParty/when","./terrainAttributeLocations","./TerrainState"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t,r,n,o){function a(t){e.data=t,e.state=p.RECEIVED}function l(){e.state=p.FAILED;var i="Failed to obtain terrain tile X: "+r+" Y: "+n+" Level: "+o+".";t._requestError=s.handleError(t._requestError,t,t.errorEvent,i,r,n,o,u)}function u(){e.data=t.requestTileGeometry(r,n,o),i(e.data)?(e.state=p.RECEIVING,h(e.data,a,l)):e.state=p.UNLOADED}u()}function f(e,t,r,n,o,a){var s=r.tilingScheme,l=e.data,u=l.createMesh(s,n,o,a);i(u)&&(e.state=p.TRANSFORMING,h(u,function(t){e.mesh=t,e.state=p.TRANSFORMED},function(){e.state=p.FAILED}))}function v(e,t,n,a,s,h){var m,f,v=r.FLOAT,_=e.mesh.vertices,g=l.createVertexBuffer({context:t,typedArray:_,usage:u.STATIC_DRAW});n.hasVertexNormals?(m=7*r.getSizeInBytes(v),f=3):(m=6*r.getSizeInBytes(v),f=2);var y=4,C=[{index:d.position3DAndHeight,vertexBuffer:g,componentDatatype:v,componentsPerAttribute:y,offsetInBytes:0,strideInBytes:m},{index:d.textureCoordAndEncodedNormals,vertexBuffer:g,componentDatatype:v,componentsPerAttribute:f,offsetInBytes:y*r.getSizeInBytes(v),strideInBytes:m}],E=e.mesh.indices.indexBuffers||{},S=E[t.id];if(!i(S)||S.isDestroyed()){var w=e.mesh.indices,T=2===w.BYTES_PER_ELEMENT?o.UNSIGNED_SHORT:o.UNSIGNED_INT;S=l.createIndexBuffer({context:t,typedArray:w,usage:u.STATIC_DRAW,indexDatatype:T}),S.vertexArrayDestroyable=!1,S.referenceCount=1,E[t.id]=S,e.mesh.indices.indexBuffers=E}else++S.referenceCount;e.vertexArray=new c({context:t,attributes:C,indexBuffer:S}),e.state=p.READY}var _=function(e){this.state=p.UNLOADED,this.data=void 0,this.mesh=void 0,this.vertexArray=void 0,this.upsampleDetails=e};return _.prototype.freeResources=function(){if(this.state=p.UNLOADED,this.data=void 0,this.mesh=void 0,i(this.vertexArray)){var e=this.vertexArray.indexBuffer;this.vertexArray.destroy(),this.vertexArray=void 0,!e.isDestroyed()&&i(e.referenceCount)&&(--e.referenceCount,0===e.referenceCount&&e.destroy())}},_.prototype.publishToTile=function(r){var i=r.data,n=this.mesh;t.clone(n.center,i.center),i.minimumHeight=n.minimumHeight,i.maximumHeight=n.maximumHeight,i.boundingSphere3D=e.clone(n.boundingSphere3D,i.boundingSphere3D),i.orientedBoundingBox=a.clone(n.orientedBoundingBox,i.orientedBoundingBox),r.data.occludeePointInScaledSpace=t.clone(n.occludeePointInScaledSpace,i.occludeePointInScaledSpace),i.freeVertexArray(),i.vertexArray=this.vertexArray,this.vertexArray=void 0},_.prototype.processLoadStateMachine=function(e,t,r,i,n){this.state===p.UNLOADED&&m(this,t,r,i,n),this.state===p.RECEIVED&&f(this,e,t,r,i,n),this.state===p.TRANSFORMED&&v(this,e,t,r,i,n)},_.prototype.processUpsampleStateMachine=function(e,t,r,n,o){if(this.state===p.UNLOADED){var a=this.upsampleDetails,s=a.data,l=a.x,u=a.y,c=a.level;if(this.data=s.upsample(t.tilingScheme,l,u,c,r,n,o),!i(this.data))return;this.state=p.RECEIVING;var d=this;h(this.data,function(e){d.data=e,d.state=p.RECEIVED},function(){d.state=p.FAILED})}this.state===p.RECEIVED&&f(this,e,t,r,n,o),this.state===p.TRANSFORMED&&v(this,e,t,r,n,o)},_}),r("Scene/GlobeSurfaceTile",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/IntersectionTests","../Core/PixelFormat","../Core/Rectangle","../Renderer/PixelDatatype","../Renderer/Sampler","../Renderer/Texture","../Renderer/TextureMagnificationFilter","../Renderer/TextureMinificationFilter","../Renderer/TextureWrap","./ImageryState","./QuadtreeTileLoadState","./SceneMode","./TerrainState","./TileTerrain"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C){"use strict";function E(e,r,i,n,a,s,l){if(t.unpack(n,s*a,l),t.add(e.center,l,l),o(r)&&r!==g.SCENE3D){var u=i.ellipsoid,c=u.cartesianToCartographic(l);i.project(c,l),t.fromElements(l.z,l.x,l.y,l)}return l}function S(e,r,i){var n=e.data,a=T(e);o(a)&&(n.upsampledTerrain=new C(a)),P(e,r)&&(n.loadedTerrain=new C);for(var s=0,l=i.length;l>s;++s){var c=i.get(s);c.show&&c._createTileImagerySkeletons(e,r)}var h=e.tilingScheme.ellipsoid,d=e.rectangle;h.cartographicToCartesian(u.southwest(d),n.southwestCornerCartesian),h.cartographicToCartesian(u.northeast(d),n.northeastCornerCartesian),k.longitude=d.west,k.latitude=.5*(d.south+d.north),k.height=0;var p=h.cartographicToCartesian(k,V),m=t.cross(p,t.UNIT_Z,F);t.normalize(m,n.westNormal),k.longitude=d.east;var f=h.cartographicToCartesian(k,z),v=t.cross(t.UNIT_Z,f,F);t.normalize(v,n.eastNormal);var _=h.geodeticSurfaceNormalCartographic(u.southeast(d),B),g=t.subtract(p,f,F),y=t.cross(_,g,B);t.normalize(y,n.southNormal);var E=h.geodeticSurfaceNormalCartographic(u.northwest(d),B),S=t.cross(g,E,B);t.normalize(S,n.northNormal)}function w(e,t,r){var i=e.data,a=i.loadedTerrain,s=i.upsampledTerrain,l=!1;o(a)&&(a.processLoadStateMachine(t,r,e.x,e.y,e.level),a.state>=y.RECEIVED&&(i.terrainData!==a.data&&(i.terrainData=a.data,I(t,i),x(e)),l=!0),a.state===y.READY?(a.publishToTile(e),i.pickTerrain=n(i.loadedTerrain,i.upsampledTerrain),i.loadedTerrain=void 0,i.upsampledTerrain=void 0):a.state===y.FAILED&&(i.loadedTerrain=void 0)),!l&&o(s)&&(s.processUpsampleStateMachine(t,r,e.x,e.y,e.level),s.state>=y.RECEIVED&&i.terrainData!==s.data&&(i.terrainData=s.data,r.hasWaterMask&&M(e),b(e)),s.state===y.READY?(s.publishToTile(e),i.pickTerrain=i.upsampledTerrain,i.upsampledTerrain=void 0):s.state===y.FAILED&&(i.upsampledTerrain=void 0))}function T(e){for(var t=e.parent;o(t)&&o(t.data)&&!o(t.data.terrainData);)t=t.parent;return o(t)&&o(t.data)?{data:t.data.terrainData,x:t.x,y:t.y,level:t.level}:void 0}function b(e){var t=e.data;if(o(e._children))for(var r=0;4>r;++r){var i=e._children[r];if(i.state!==_.START){var n=i.data;if(o(n.terrainData)&&!n.terrainData.wasCreatedByUpsampling())continue;o(n.upsampledTerrain)&&n.upsampledTerrain.freeResources(),n.upsampledTerrain=new C({data:t.terrainData,x:e.x,y:e.y,level:e.level}),i.state=_.LOADING}}}function x(e){var t=e.data;if(o(e.children))for(var r=0;4>r;++r){var i=e.children[r];if(i.state!==_.START){var n=i.data;if(o(n.terrainData)&&!n.terrainData.wasCreatedByUpsampling())continue;o(n.upsampledTerrain)&&n.upsampledTerrain.freeResources(),n.upsampledTerrain=new C({data:t.terrainData,x:e.x,y:e.y,level:e.level}),t.terrainData.isChildAvailable(e.x,e.y,i.x,i.y)&&(o(n.loadedTerrain)||(n.loadedTerrain=new C)),i.state=_.LOADING}}}function P(e,t){var r=t.getTileDataAvailable(e.x,e.y,e.level);if(o(r))return r;var i=e.parent;return o(i)?o(i.data)&&o(i.data.terrainData)?i.data.terrainData.isChildAvailable(i.x,i.y,e.x,e.y):!1:!0}function A(e){var t=e.cache.tile_waterMaskData;if(!o(t)){var r=new d({context:e,pixelFormat:l.LUMINANCE,pixelDatatype:c.UNSIGNED_BYTE,source:{arrayBufferView:new Uint8Array([255]),width:1,height:1}});r.referenceCount=1;var i=new h({wrapS:f.CLAMP_TO_EDGE,wrapT:f.CLAMP_TO_EDGE,minificationFilter:m.LINEAR,magnificationFilter:p.LINEAR});t={allWaterTexture:r,sampler:i,destroy:function(){this.allWaterTexture.destroy()}},e.cache.tile_waterMaskData=t}return t}function I(e,t){var i=t.waterMaskTexture;o(i)&&(--i.referenceCount,0===i.referenceCount&&i.destroy(),t.waterMaskTexture=void 0);var n=t.terrainData.waterMask;if(o(n)){var a,s=A(e),u=n.length;if(1===u){if(0===n[0])return;a=s.allWaterTexture}else{var h=Math.sqrt(u);a=new d({context:e,pixelFormat:l.LUMINANCE,pixelDatatype:c.UNSIGNED_BYTE,source:{width:h,height:h,arrayBufferView:n},sampler:s.sampler}),a.referenceCount=0}++a.referenceCount,t.waterMaskTexture=a,r.fromElements(0,0,1,1,t.waterMaskTranslationAndScale)}}function M(e){for(var t=e.data,r=e.parent;o(r)&&!o(r.data.terrainData)||r.data.terrainData.wasCreatedByUpsampling();)r=r.parent;if(o(r)&&o(r.data.waterMaskTexture)){t.waterMaskTexture=r.data.waterMaskTexture,++t.waterMaskTexture.referenceCount;var i=r.rectangle,n=e.rectangle,a=n.width,s=n.height,l=a/i.width,u=s/i.height;t.waterMaskTranslationAndScale.x=l*(n.west-i.west)/a,t.waterMaskTranslationAndScale.y=u*(n.south-i.south)/s,t.waterMaskTranslationAndScale.z=l,t.waterMaskTranslationAndScale.w=u}}var D=function(){this.imagery=[],this.southwestCornerCartesian=new t,this.northeastCornerCartesian=new t,this.westNormal=new t,this.southNormal=new t,this.eastNormal=new t,this.northNormal=new t,this.waterMaskTexture=void 0,this.waterMaskTranslationAndScale=new r(0,0,1,1),this.terrainData=void 0,this.center=new t,this.vertexArray=void 0,this.minimumHeight=0,this.maximumHeight=0,this.boundingSphere3D=new e,this.boundingSphere2D=new e,this.orientedBoundingBox=void 0,this.occludeePointInScaledSpace=new t,this.loadedTerrain=void 0,this.upsampledTerrain=void 0,this.pickBoundingSphere=new e,this.pickTerrain=void 0,this.surfaceShader=void 0};D.irregularZoomLevels=!1,a(D.prototype,{eligibleForUnloading:{get:function(){for(var e=this.loadedTerrain,t=o(e)&&(e.state===y.RECEIVING||e.state===y.TRANSFORMING),r=this.upsampledTerrain,i=o(r)&&(r.state===y.RECEIVING||r.state===y.TRANSFORMING),n=!t&&!i,a=this.imagery,s=0,l=a.length;n&&l>s;++s){var u=a[s];n=!o(u.loadingImagery)||u.loadingImagery.state!==v.TRANSITIONING}return n}}});var R=new t,O=new t,N=new t,L=new t;D.prototype.pick=function(e,r,i,n,a){var l=this.pickTerrain;if(!o(l))return void 0;var u=l.mesh;if(!o(u))return void 0;for(var c=u.vertices,h=u.stride,d=u.indices,p=d.length,m=0;p>m;m+=3){var f=d[m],v=d[m+1],_=d[m+2],g=E(this,r,i,c,h,f,R),y=E(this,r,i,c,h,v,O),C=E(this,r,i,c,h,_,N),S=s.rayTriangle(e,g,y,C,n,L);if(o(S))return t.clone(S,a)}return void 0},D.prototype.freeResources=function(){o(this.waterMaskTexture)&&(--this.waterMaskTexture.referenceCount,0===this.waterMaskTexture.referenceCount&&this.waterMaskTexture.destroy(),this.waterMaskTexture=void 0),this.terrainData=void 0,o(this.loadedTerrain)&&(this.loadedTerrain.freeResources(),this.loadedTerrain=void 0),o(this.upsampledTerrain)&&(this.upsampledTerrain.freeResources(),this.upsampledTerrain=void 0),o(this.pickTerrain)&&(this.pickTerrain.freeResources(),this.pickTerrain=void 0);var e,t,r=this.imagery;for(e=0,t=r.length;t>e;++e)r[e].freeResources();this.imagery.length=0,this.freeVertexArray()},D.prototype.freeVertexArray=function(){var e;o(this.vertexArray)&&(e=this.vertexArray.indexBuffer,this.vertexArray=this.vertexArray.destroy(),!e.isDestroyed()&&o(e.referenceCount)&&(--e.referenceCount,0===e.referenceCount&&e.destroy())),o(this.wireframeVertexArray)&&(e=this.wireframeVertexArray.indexBuffer,this.wireframeVertexArray=this.wireframeVertexArray.destroy(),!e.isDestroyed()&&o(e.referenceCount)&&(--e.referenceCount,0===e.referenceCount&&e.destroy()))},D.processStateMachine=function(e,t,r,i,n){var a=e.data;o(a)||(a=e.data=new D),e.state===_.START&&(S(e,i,n),e.state=_.LOADING),e.state===_.LOADING&&w(e,t,i);for(var s=o(a.vertexArray),l=!o(a.loadedTerrain)&&!o(a.upsampledTerrain),u=D.irregularZoomLevels?!1:o(a.terrainData)&&a.terrainData.wasCreatedByUpsampling(),c=a.imagery,h=0,d=c.length;d>h;++h){var p=c[h];if(o(p.loadingImagery)){if(p.loadingImagery.state===v.PLACEHOLDER){var m=p.loadingImagery.imageryLayer;if(m.imageryProvider.ready){p.freeResources(),c.splice(h,1),m._createTileImagerySkeletons(e,i,h),--h,d=c.length;continue}u=!1}var f=p.processStateMachine(e,t,r);l=l&&f,s=s&&(f||o(p.readyImagery)),u=u&&o(p.loadingImagery)&&(p.loadingImagery.state===v.FAILED||p.loadingImagery.state===v.INVALID)}else u=!1}e.upsampledFromParent=u,h===d&&(s&&(e.renderable=!0),l&&(e.state=_.DONE))};var F=new t,B=new t,V=new t,z=new t,k=new i;return D}),r("Shaders/ReprojectWebMercatorFS",[],function(){"use strict";return"uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n"}),r("Shaders/ReprojectWebMercatorVS",[],function(){"use strict";return"attribute vec4 position;\nattribute float webMercatorT;\nuniform vec2 u_textureDimensions;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nv_textureCoordinates = vec2(position.x, webMercatorT);\ngl_Position = czm_viewportOrthographic * (position * vec4(u_textureDimensions, 1.0, 1.0));\n}\n"}),r("Scene/Imagery",["../Core/defined","../Core/destroyObject","./ImageryState"],function(e,t,r){"use strict";var i=function(t,i,n,o,a){if(this.imageryLayer=t,this.x=i,this.y=n,this.level=o,0!==o){var s=i/2|0,l=n/2|0,u=o-1;this.parent=t.getImageryFromCache(s,l,u)}if(this.state=r.UNLOADED,this.imageUrl=void 0,this.image=void 0,this.texture=void 0,this.credits=void 0,this.referenceCount=0,!e(a)&&t.imageryProvider.ready){var c=t.imageryProvider.tilingScheme;a=c.tileXYToRectangle(i,n,o)}this.rectangle=a};return i.createPlaceholder=function(e){var t=new i(e,0,0,0);return t.addReference(),t.state=r.PLACEHOLDER,t},i.prototype.addReference=function(){++this.referenceCount},i.prototype.releaseReference=function(){return--this.referenceCount,0===this.referenceCount?(this.imageryLayer.removeImageryFromCache(this),e(this.parent)&&this.parent.releaseReference(),e(this.image)&&e(this.image.destroy)&&this.image.destroy(),e(this.texture)&&this.texture.destroy(),t(this),0):this.referenceCount},i.prototype.processStateMachine=function(e,t){this.state===r.UNLOADED&&(this.state=r.TRANSITIONING,this.imageryLayer._requestImagery(this)),this.state===r.RECEIVED&&(this.state=r.TRANSITIONING,this.imageryLayer._createTexture(e,this)),this.state===r.TEXTURE_LOADED&&(this.state=r.TRANSITIONING,this.imageryLayer._reprojectTexture(e,t,this))},i}),r("Scene/TileImagery",["../Core/defined","./ImageryState"],function(e,t){"use strict";var r=function(e,t){this.readyImagery=void 0,this.loadingImagery=e,this.textureCoordinateRectangle=t,this.textureTranslationAndScale=void 0};return r.prototype.freeResources=function(){e(this.readyImagery)&&this.readyImagery.releaseReference(),e(this.loadingImagery)&&this.loadingImagery.releaseReference()},r.prototype.processStateMachine=function(r,i,n){var o=this.loadingImagery,a=o.imageryLayer,s=o.imageryLayer.imageryProvider;if(!e(s.getTileDataAvailable)||s.getTileDataAvailable(o.x,o.y,o.level)?o.processStateMachine(i,n):o.state=t.INVALID,o.state===t.READY)return e(this.readyImagery)&&this.readyImagery.releaseReference(),this.readyImagery=this.loadingImagery,this.loadingImagery=void 0,this.textureTranslationAndScale=a._calculateTextureTranslationAndScale(r,this),!0;for(var l,u=o.parent;e(u)&&u.state!==t.READY;)u.state!==t.FAILED&&u.state!==t.INVALID&&(l=l||u),u=u.parent;return this.readyImagery!==u&&(e(this.readyImagery)&&this.readyImagery.releaseReference(),this.readyImagery=u,e(u)&&(u.addReference(),this.textureTranslationAndScale=a._calculateTextureTranslationAndScale(r,this))),o.state===t.FAILED||o.state===t.INVALID?e(l)?(l.processStateMachine(i,n),!1):!0:!1},r}),r("Scene/ImageryLayer",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian4","../Core/Color","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/FeatureDetection","../Core/GeographicTilingScheme","../Core/IndexDatatype","../Core/Math","../Core/PixelFormat","../Core/PrimitiveType","../Core/Rectangle","../Core/TerrainProvider","../Core/TileProviderError","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/ClearCommand","../Renderer/ComputeCommand","../Renderer/ContextLimits","../Renderer/DrawCommand","../Renderer/Framebuffer","../Renderer/MipmapHint","../Renderer/RenderState","../Renderer/Sampler","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/TextureMagnificationFilter","../Renderer/TextureMinificationFilter","../Renderer/TextureWrap","../Renderer/VertexArray","../Shaders/ReprojectWebMercatorFS","../Shaders/ReprojectWebMercatorVS","../ThirdParty/when","./Imagery","./ImageryState","./TileImagery"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k){"use strict";function U(e,t,r,i){if(d.isPowerOfTwo(i.width)&&d.isPowerOfTwo(i.height)){var n=t.cache.imageryLayer_mipmapSampler;if(!a(n)){var s=S.maximumTextureFilterAnisotropy;n=t.cache.imageryLayer_mipmapSampler=new P({wrapS:O.CLAMP_TO_EDGE,wrapT:O.CLAMP_TO_EDGE,minificationFilter:R.LINEAR_MIPMAP_LINEAR,magnificationFilter:D.LINEAR,maximumAnisotropy:Math.min(s,o(e._maximumAnisotropy,s))})}i.generateMipmap(b.NICEST),i.sampler=n}else{var l=t.cache.imageryLayer_nonMipmapSampler;a(l)||(l=t.cache.imageryLayer_nonMipmapSampler=new P({wrapS:O.CLAMP_TO_EDGE,wrapT:O.CLAMP_TO_EDGE,minificationFilter:R.LINEAR,magnificationFilter:D.LINEAR})),i.sampler=l}r.state=z.READY}function G(e,t,r){return JSON.stringify([e,t,r])}function W(e,t,r,i){var n=t.cache.imageryLayer_reproject;if(!a(n)){n=t.cache.imageryLayer_reproject={vertexArray:void 0,shaderProgram:void 0,sampler:void 0,destroy:function(){a(this.framebuffer)&&this.framebuffer.destroy(),a(this.vertexArray)&&this.vertexArray.destroy(),a(this.shaderProgram)&&this.shaderProgram.destroy()}};for(var o=new Float32Array(256),s=0,l=0;64>l;++l){var u=l/63;o[s++]=0,o[s++]=u,o[s++]=1,o[s++]=u}var c={position:0,webMercatorT:1},p=v.getRegularGridIndices(2,64),m=g.createIndexBuffer({context:t,typedArray:p,usage:y.STATIC_DRAW,indexDatatype:h.UNSIGNED_SHORT});n.vertexArray=new N({context:t,attributes:[{index:c.position,vertexBuffer:g.createVertexBuffer({context:t,typedArray:o,usage:y.STATIC_DRAW}),componentsPerAttribute:2},{index:c.webMercatorT,vertexBuffer:g.createVertexBuffer({context:t,sizeInBytes:512,usage:y.STREAM_DRAW}),componentsPerAttribute:1}],indexBuffer:m});var f=new I({sources:[F]});n.shaderProgram=A.fromCache({context:t,vertexShaderSource:f,fragmentShaderSource:L,attributeLocations:c}),n.sampler=new P({wrapS:O.CLAMP_TO_EDGE,wrapT:O.CLAMP_TO_EDGE,minificationFilter:R.LINEAR,magnificationFilter:D.LINEAR})}r.sampler=n.sampler;var _=r.width,C=r.height;Z.textureDimensions.x=_,Z.textureDimensions.y=C,Z.texture=r;var E=Math.sin(i.south),S=.5*Math.log((1+E)/(1-E));E=Math.sin(i.north);var w=.5*Math.log((1+E)/(1-E)),T=1/(w-S),x=new M({context:t,width:_,height:C,pixelFormat:r.pixelFormat,pixelDatatype:r.pixelDatatype,preMultiplyAlpha:r.preMultiplyAlpha});d.isPowerOfTwo(_)&&d.isPowerOfTwo(C)&&x.generateMipmap(b.NICEST);for(var B=i.south,V=i.north,z=K,k=0,U=0;64>U;++U){var G=U/63,W=d.lerp(B,V,G);E=Math.sin(W);var H=.5*Math.log((1+E)/(1-E)),q=(H-S)*T;z[k++]=q,z[k++]=q}n.vertexArray.getAttribute(1).vertexBuffer.copyFromArrayView(z),e.shaderProgram=n.shaderProgram,e.outputTexture=x,e.uniformMap=Z,e.vertexArray=n.vertexArray}function H(e,t,r){var i=e._imageryProvider,n=i.tilingScheme,o=n.ellipsoid,a=e._imageryProvider.tilingScheme instanceof c?1:Math.cos(r),s=n.rectangle,l=o.maximumRadius*s.width*a/(i.tileWidth*n.getNumberOfXTilesAtLevel(0)),u=l/t,h=Math.log(u)/Math.log(2),d=Math.round(h);return 0|d}var q=function J(e,t){this._imageryProvider=e,t=o(t,{}),this.alpha=o(t.alpha,o(e.defaultAlpha,1)),this.brightness=o(t.brightness,o(e.defaultBrightness,J.DEFAULT_BRIGHTNESS)),this.contrast=o(t.contrast,o(e.defaultContrast,J.DEFAULT_CONTRAST)),this.hue=o(t.hue,o(e.defaultHue,J.DEFAULT_HUE)),this.saturation=o(t.saturation,o(e.defaultSaturation,J.DEFAULT_SATURATION)),this.gamma=o(t.gamma,o(e.defaultGamma,J.DEFAULT_GAMMA)),this.show=o(t.show,!0),this._minimumTerrainLevel=t.minimumTerrainLevel,this._maximumTerrainLevel=t.maximumTerrainLevel,this._rectangle=o(t.rectangle,f.MAX_VALUE),this._maximumAnisotropy=t.maximumAnisotropy,this._imageryCache={},this._skeletonPlaceholder=new k(V.createPlaceholder(this)),this._show=!0,this._layerIndex=-1,this._isBaseLayer=!1,this._requestImageError=void 0};s(q.prototype,{imageryProvider:{get:function(){return this._imageryProvider}},rectangle:{get:function(){return this._rectangle}}}),q.DEFAULT_BRIGHTNESS=1,q.DEFAULT_CONTRAST=1,q.DEFAULT_HUE=0,q.DEFAULT_SATURATION=1,q.DEFAULT_GAMMA=1,q.prototype.isBaseLayer=function(){return this._isBaseLayer},q.prototype.isDestroyed=function(){return!1},q.prototype.destroy=function(){return l(this)};var j=new f,Y=new f,X=new f;q.prototype._createTileImagerySkeletons=function(e,t,i){var n=e.data;if(a(this._minimumTerrainLevel)&&e.level<this._minimumTerrainLevel)return!1;if(a(this._maximumTerrainLevel)&&e.level>this._maximumTerrainLevel)return!1;var o=this._imageryProvider;if(a(i)||(i=n.imagery.length),!o.ready)return this._skeletonPlaceholder.loadingImagery.addReference(),n.imagery.splice(i,0,this._skeletonPlaceholder),!0;var s=f.intersection(o.rectangle,this._rectangle,j),l=f.intersection(e.rectangle,s,Y);if(!a(l)){if(!this.isBaseLayer())return!1;var u=s,c=e.rectangle;l=Y,c.south>=u.north?l.north=l.south=u.north:c.north<=u.south?l.north=l.south=u.south:(l.south=Math.max(c.south,u.south),l.north=Math.min(c.north,u.north)),c.west>=u.east?l.west=l.east=u.east:c.east<=u.west?l.west=l.east=u.west:(l.west=Math.max(c.west,u.west),l.east=Math.min(c.east,u.east))}var h=0;l.south>0?h=l.south:l.north<0&&(h=l.north);var d=1,p=d*t.getLevelMaximumGeometricError(e.level),m=H(this,p,h);m=Math.max(0,m);var v=o.maximumLevel;if(m>v&&(m=v),a(o.minimumLevel)){var _=o.minimumLevel;_>m&&(m=_)}var g=o.tilingScheme,y=g.positionToTileXY(f.northwest(l),m),C=g.positionToTileXY(f.southeast(l),m),E=e.rectangle.height/512,S=e.rectangle.width/512,w=g.tileXYToRectangle(y.x,y.y,m);Math.abs(w.south-e.rectangle.north)<S&&y.y<C.y&&++y.y,Math.abs(w.east-e.rectangle.west)<E&&y.x<C.x&&++y.x;var T=g.tileXYToRectangle(C.x,C.y,m);Math.abs(T.north-e.rectangle.south)<S&&C.y>y.y&&--C.y,Math.abs(T.west-e.rectangle.east)<E&&C.x>y.x&&--C.x;var b,x,P=e.rectangle,A=g.tileXYToRectangle(y.x,y.y,m),I=f.intersection(A,s,X),M=0,D=1;!this.isBaseLayer()&&Math.abs(I.west-e.rectangle.west)>=E&&(M=Math.min(1,(I.west-P.west)/P.width)),!this.isBaseLayer()&&Math.abs(I.north-e.rectangle.north)>=S&&(D=Math.max(0,(I.north-P.south)/P.height));for(var R=D,O=y.x;O<=C.x;O++){b=M,A=g.tileXYToRectangle(O,y.y,m),I=f.intersection(A,s,X),M=Math.min(1,(I.east-P.west)/P.width),O===C.x&&(this.isBaseLayer()||Math.abs(I.east-e.rectangle.east)<E)&&(M=1),D=R;for(var N=y.y;N<=C.y;N++){x=D,A=g.tileXYToRectangle(O,N,m),I=f.intersection(A,s,X),D=Math.max(0,(I.south-P.south)/P.height),N===C.y&&(this.isBaseLayer()||Math.abs(I.south-e.rectangle.south)<S)&&(D=0);var L=new r(b,D,M,x),F=this.getImageryFromCache(O,N,m,A);n.imagery.splice(i,0,new k(F,L)),++i}}return!0},q.prototype._calculateTextureTranslationAndScale=function(e,t){var i=t.readyImagery.rectangle,n=e.rectangle,o=n.width,a=n.height,s=o/i.width,l=a/i.height;return new r(s*(n.west-i.west)/o,l*(n.south-i.south)/a,s,l)},q.prototype._requestImagery=function(e){function t(t){return a(t)?(e.image=t,e.state=z.RECEIVED,void _.handleSuccess(o._requestImageError)):r()}function r(t){e.state=z.FAILED;var r="Failed to obtain image tile X: "+e.x+" Y: "+e.y+" Level: "+e.level+".";o._requestImageError=_.handleError(o._requestImageError,n,n.errorEvent,r,e.x,e.y,e.level,i,t)}function i(){e.state=z.TRANSITIONING;var i=n.requestImage(e.x,e.y,e.level);return a(i)?(a(n.getTileCredits)&&(e.credits=n.getTileCredits(e.x,e.y,e.level)),void B(i,t,r)):void(e.state=z.UNLOADED)}var n=this._imageryProvider,o=this;i()},q.prototype._createTexture=function(e,t){var r=this._imageryProvider;if(a(r.tileDiscardPolicy)){var i=r.tileDiscardPolicy;if(a(i)){if(!i.isReady())return void(t.state=z.RECEIVED);if(i.shouldDiscardImage(t.image))return void(t.state=z.INVALID)}}var n=new M({context:e,source:t.image,pixelFormat:r.hasAlphaChannel?p.RGBA:p.RGB});t.texture=n,t.image=void 0,t.state=z.TEXTURE_LOADED},q.prototype._reprojectTexture=function(e,t,r){var i=r.texture,n=r.rectangle;if(!(this._imageryProvider.tilingScheme instanceof c)&&n.width/i.width>1e-5){var o=this,a=new E({persists:!0,owner:this,preExecute:function(t){W(t,e,i,r.rectangle)},postExecute:function(t){i.destroy(),r.texture=t,U(o,e,r,t)}});t.push(a)}else U(this,e,r,i)},q.prototype.getImageryFromCache=function(e,t,r,i){var n=G(e,t,r),o=this._imageryCache[n];return a(o)||(o=new V(this,e,t,r,i),this._imageryCache[n]=o),o.addReference(),o},q.prototype.removeImageryFromCache=function(e){var t=G(e.x,e.y,e.level);delete this._imageryCache[t]};var Z={u_textureDimensions:function(){return this.textureDimensions},u_texture:function(){return this.texture},textureDimensions:new t,texture:void 0},K=u.supportsTypedArrays()?new Float32Array(128):void 0;return q}),r("Scene/GlobeSurfaceTileProvider",["../Core/BoundingSphere","../Core/BoxOutlineGeometry","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/FeatureDetection","../Core/GeometryInstance","../Core/GeometryPipeline","../Core/IndexDatatype","../Core/Intersect","../Core/Math","../Core/Matrix4","../Core/OrientedBoundingBox","../Core/PrimitiveType","../Core/Rectangle","../Core/SphereOutlineGeometry","../Core/Visibility","../Core/WebMercatorProjection","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/ContextLimits","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/VertexArray","../Scene/BlendingState","../Scene/DepthFunction","../Scene/Pass","../Scene/PerInstanceColorAppearance","../Scene/Primitive","../ThirdParty/when","./GlobeSurfaceTile","./ImageryLayer","./ImageryState","./QuadtreeTileLoadState","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G){"use strict";function W(e,t){var r=e.loadingImagery;l(r)||(r=e.readyImagery);var i=t.loadingImagery;return l(i)||(i=t.readyImagery),r.imageryLayer._layerIndex-i.imageryLayer._layerIndex}function H(){var e={u_initialColor:function(){return this.initialColor},u_zoomedOutOceanSpecularIntensity:function(){return this.zoomedOutOceanSpecularIntensity},u_oceanNormalMap:function(){return this.oceanNormalMap},u_lightingFadeDistance:function(){return this.lightingFadeDistance},u_center3D:function(){return this.center3D},u_tileRectangle:function(){return this.tileRectangle},u_modifiedModelView:function(){return this.modifiedModelView},u_dayTextures:function(){return this.dayTextures},u_dayTextureTranslationAndScale:function(){return this.dayTextureTranslationAndScale},u_dayTextureTexCoordsRectangle:function(){return this.dayTextureTexCoordsRectangle},u_dayTextureAlpha:function(){return this.dayTextureAlpha},u_dayTextureBrightness:function(){return this.dayTextureBrightness},u_dayTextureContrast:function(){return this.dayTextureContrast},u_dayTextureHue:function(){return this.dayTextureHue},u_dayTextureSaturation:function(){return this.dayTextureSaturation},u_dayTextureOneOverGamma:function(){return this.dayTextureOneOverGamma},u_dayIntensity:function(){return this.dayIntensity},u_southAndNorthLatitude:function(){return this.southAndNorthLatitude},u_southMercatorYAndOneOverHeight:function(){return this.southMercatorYAndOneOverHeight},u_waterMask:function(){return this.waterMask},u_waterMaskTranslationAndScale:function(){return this.waterMaskTranslationAndScale},initialColor:new n(0,0,.5,1),zoomedOutOceanSpecularIntensity:.5,oceanNormalMap:void 0,lightingFadeDistance:new r(65e5,9e6),center3D:void 0,modifiedModelView:new y,tileRectangle:new n,dayTextures:[],dayTextureTranslationAndScale:[],dayTextureTexCoordsRectangle:[],dayTextureAlpha:[],dayTextureBrightness:[],dayTextureContrast:[],dayTextureHue:[],dayTextureSaturation:[],dayTextureOneOverGamma:[],dayIntensity:0,southAndNorthLatitude:new r, -southMercatorYAndOneOverHeight:new r,waterMask:void 0,waterMaskTranslationAndScale:new n};return e}function q(e,t,r){var i=r.data;if(!l(i.wireframeVertexArray)&&!l(i.meshForWireframePromise)&&(i.meshForWireframePromise=i.terrainData.createMesh(t._terrainProvider.tilingScheme,r.x,r.y,r.level),l(i.meshForWireframePromise))){var n=i.vertexArray;B(i.meshForWireframePromise,function(t){i.vertexArray===n&&(i.wireframeVertexArray=j(e,i.vertexArray,t)),i.meshForWireframePromise=void 0})}}function j(e,t,r){var i={indices:r.indices,primitiveType:E.TRIANGLES};f.toWireframe(i);var n=i.indices,o=x.createIndexBuffer({context:e,typedArray:n,usage:P.STATIC_DRAW,indexDatatype:v.UNSIGNED_SHORT});return new D({context:e,attributes:t._attributes,indexBuffer:o})}function Y(t,r,a){var s=r.data,u=a.camera.viewMatrix,c=A.maximumTextureImageUnits,h=s.waterMaskTexture,d=t.hasWaterMask&&l(h),p=t.oceanNormalMap,m=d&&l(p),f=t.terrainProvider.ready&&t.terrainProvider.hasVertexNormals,v=a.fog.enabled;d&&--c,m&&--c;var _=s.center,w=Q,T=0,x=0,P=0,M=0,D=!1;if(a.mode!==G.SCENE3D){var R=a.mapProjection,O=R.project(S.southwest(r.rectangle),te),L=R.project(S.northeast(r.rectangle),re);w.x=O.x,w.y=O.y,w.z=L.x,w.w=L.y,a.mode!==G.MORPHING&&(_=$,_.x=0,_.y=.5*(w.z+w.x),_.z=.5*(w.w+w.y),w.x-=_.y,w.y-=_.z,w.z-=_.y,w.w-=_.z),R instanceof b&&(T=r.rectangle.south,x=r.rectangle.north,P=b.geodeticLatitudeToMercatorAngle(T),M=1/(b.geodeticLatitudeToMercatorAngle(x)-P),D=!0)}var F=y.multiplyByPoint(u,_,ee);y.setTranslation(u,F,J);var B=s.imagery,V=0,U=B.length,W=t._renderState,j=t._blendRenderState,Y=W,X=t._firstPassInitialColor,Z=a.context;l(t._debug.boundingSphereTile)||ce();do{var K,ie,ne=0;t._drawCommands.length<=t._usedDrawCommands?(K=new I,K.owner=r,K.cull=!1,K.boundingVolume=new e,K.orientedBoundingBox=void 0,ie=H(),t._drawCommands.push(K),t._uniformMaps.push(ie)):(K=t._drawCommands[t._usedDrawCommands],ie=t._uniformMaps[t._usedDrawCommands]),K.owner=r,++t._usedDrawCommands,r===t._debug.boundingSphereTile&&(l(s.orientedBoundingBox)?le(s.orientedBoundingBox,o.RED).update(a):l(s.boundingSphere3D)&&ue(s.boundingSphere3D,o.RED).update(a)),n.clone(X,ie.initialColor),ie.oceanNormalMap=p,ie.lightingFadeDistance.x=t.lightingFadeOutDistance,ie.lightingFadeDistance.y=t.lightingFadeInDistance,ie.zoomedOutOceanSpecularIntensity=t.zoomedOutOceanSpecularIntensity,ie.center3D=s.center,n.clone(w,ie.tileRectangle),ie.southAndNorthLatitude.x=T,ie.southAndNorthLatitude.y=x,ie.southMercatorYAndOneOverHeight.x=P,ie.southMercatorYAndOneOverHeight.y=M,y.clone(J,ie.modifiedModelView);for(var oe=v&&g.fog(r._distance,a.fog.density)>g.EPSILON3,ae=!1,se=!1,de=!1,pe=!1,me=!1,fe=!1;c>ne&&U>V;){var ve=B[V],_e=ve.readyImagery;if(++V,l(_e)&&_e.state===k.READY&&0!==_e.imageryLayer.alpha){var ge=_e.imageryLayer;if(l(ve.textureTranslationAndScale)||(ve.textureTranslationAndScale=ge._calculateTextureTranslationAndScale(r,ve)),ie.dayTextures[ne]=_e.texture,ie.dayTextureTranslationAndScale[ne]=ve.textureTranslationAndScale,ie.dayTextureTexCoordsRectangle[ne]=ve.textureCoordinateRectangle,ie.dayTextureAlpha[ne]=ge.alpha,fe=fe||1!==ie.dayTextureAlpha[ne],ie.dayTextureBrightness[ne]=ge.brightness,ae=ae||ie.dayTextureBrightness[ne]!==z.DEFAULT_BRIGHTNESS,ie.dayTextureContrast[ne]=ge.contrast,se=se||ie.dayTextureContrast[ne]!==z.DEFAULT_CONTRAST,ie.dayTextureHue[ne]=ge.hue,de=de||ie.dayTextureHue[ne]!==z.DEFAULT_HUE,ie.dayTextureSaturation[ne]=ge.saturation,pe=pe||ie.dayTextureSaturation[ne]!==z.DEFAULT_SATURATION,ie.dayTextureOneOverGamma[ne]=1/ge.gamma,me=me||ie.dayTextureOneOverGamma[ne]!==1/z.DEFAULT_GAMMA,l(_e.credits))for(var ye=a.creditDisplay,Ce=_e.credits,Ee=0,Se=Ce.length;Se>Ee;++Ee)ye.addCredit(Ce[Ee]);++ne}}ie.dayTextures.length=ne,ie.waterMask=h,n.clone(s.waterMaskTranslationAndScale,ie.waterMaskTranslationAndScale),K.shaderProgram=t._surfaceShaderSet.getShaderProgram(Z,a.mode,s,ne,ae,se,de,pe,me,fe,d,m,t.enableLighting,f,D,oe),K.renderState=Y,K.primitiveType=E.TRIANGLES,K.vertexArray=s.vertexArray,K.uniformMap=ie,K.pass=N.GLOBE,t._debug.wireframe&&(q(Z,t,r),l(s.wireframeVertexArray)&&(K.vertexArray=s.wireframeVertexArray,K.primitiveType=E.LINES));var we=K.boundingVolume,Te=K.orientedBoundingBox;a.mode!==G.SCENE3D?(e.fromRectangleWithHeights2D(r.rectangle,a.mapProjection,s.minimumHeight,s.maximumHeight,we),i.fromElements(we.center.z,we.center.x,we.center.y,we.center),a.mode===G.MORPHING&&(we=e.union(s.boundingSphere3D,we,we))):(K.boundingVolume=e.clone(s.boundingSphere3D,we),K.orientedBoundingBox=C.clone(s.orientedBoundingBox,Te)),a.commandList.push(K),Y=j,X=he}while(U>V)}function X(e,t,r){var i;e._pickCommands.length<=e._usedPickCommands?(i=new I,i.cull=!1,e._pickCommands.push(i)):i=e._pickCommands[e._usedPickCommands],++e._usedPickCommands;var n=r.projection instanceof b;i.shaderProgram=e._surfaceShaderSet.getShaderProgram(r.context,r.mode,n),i.renderState=e._pickRenderState,i.owner=t.owner,i.primitiveType=t.primitiveType,i.vertexArray=t.vertexArray,i.uniformMap=t.uniformMap,i.boundingVolume=t.boundingVolume,i.orientedBoundingBox=i.orientedBoundingBox,i.pass=t.pass,r.commandList.push(i)}var Z=function de(e){V.irregularZoomLevels|=!!e.terrainProvider._availableLevels,this.lightingFadeOutDistance=65e5,this.lightingFadeInDistance=9e6,this.hasWaterMask=!1,this.oceanNormalMap=void 0,this.zoomedOutOceanSpecularIntensity=.5,this.enableLighting=!1,this._quadtree=void 0,this._terrainProvider=e.terrainProvider,this._imageryLayers=e.imageryLayers,this._surfaceShaderSet=e.surfaceShaderSet,this._renderState=void 0,this._blendRenderState=void 0,this._pickRenderState=void 0,this._errorEvent=new d,this._imageryLayers.layerAdded.addEventListener(de.prototype._onLayerAdded,this),this._imageryLayers.layerRemoved.addEventListener(de.prototype._onLayerRemoved,this),this._imageryLayers.layerMoved.addEventListener(de.prototype._onLayerMoved,this),this._imageryLayers.layerShownOrHidden.addEventListener(de.prototype._onLayerShownOrHidden,this),this._layerOrderChanged=!1,this._tilesToRenderByTextureCount=[],this._drawCommands=[],this._uniformMaps=[],this._pickCommands=[],this._usedDrawCommands=0,this._usedPickCommands=0,this._debug={wireframe:!1,boundingSphereTile:void 0},this._baseColor=void 0,this._firstPassInitialColor=void 0,this.baseColor=new o(0,0,.5,1)};u(Z.prototype,{baseColor:{get:function(){return this._baseColor},set:function(e){this._baseColor=e,this._firstPassInitialColor=n.fromColor(e,this._firstPassInitialColor)}},quadtree:{get:function(){return this._quadtree},set:function(e){this._quadtree=e}},ready:{get:function(){return this._terrainProvider.ready&&(0===this._imageryLayers.length||this._imageryLayers.get(0).imageryProvider.ready)}},tilingScheme:{get:function(){return this._terrainProvider.tilingScheme}},errorEvent:{get:function(){return this._errorEvent}},terrainProvider:{get:function(){return this._terrainProvider},set:function(e){this._terrainProvider!==e&&(this._terrainProvider=e,V.irregularZoomLevels|=!!e._availableLevels,l(this._quadtree)&&this._quadtree.invalidateAllTiles())}}}),Z.prototype.beginUpdate=function(e){this._imageryLayers._update(),this._layerOrderChanged&&(this._layerOrderChanged=!1,this._quadtree.forEachLoadedTile(function(e){e.data.imagery.sort(W)}));var t,r,i=this._tilesToRenderByTextureCount;for(t=0,r=i.length;r>t;++t){var n=i[t];l(n)&&(n.length=0)}this._usedDrawCommands=0;var o=e.creditDisplay;this._terrainProvider.ready&&l(this._terrainProvider.credit)&&o.addCredit(this._terrainProvider.credit);var a=this._imageryLayers;for(t=0,r=a.length;r>t;++t){var s=a.get(t).imageryProvider;V.irregularZoomLevels|=!!s._availableLevels,s.ready&&l(s.credit)&&o.addCredit(s.credit)}},Z.prototype.endUpdate=function(e){l(this._renderState)||(this._renderState=M.fromCache({cull:{enabled:!0},depthTest:{enabled:!0,func:O.LESS}}),this._blendRenderState=M.fromCache({cull:{enabled:!0},depthTest:{enabled:!0,func:O.LESS_OR_EQUAL},blending:R.ALPHA_BLEND}));for(var t=this._tilesToRenderByTextureCount,r=0,i=t.length;i>r;++r){var n=t[r];if(l(n))for(var o=0,a=n.length;a>o;++o)Y(this,n[o],e)}},Z.prototype.updateForPick=function(e){l(this._pickRenderState)||(this._pickRenderState=M.fromCache({colorMask:{red:!1,green:!1,blue:!1,alpha:!1},depthTest:{enabled:!0}})),this._usedPickCommands=0;for(var t=this._drawCommands,r=(this._tilesToRenderByTextureCount,0),i=this._usedDrawCommands;i>r;++r)X(this,t[r],e)},Z.prototype.getLevelMaximumGeometricError=function(e){return this._terrainProvider.getLevelMaximumGeometricError(e)},Z.prototype.loadTile=function(e,t){V.processStateMachine(t,e.context,e.commandList,this._terrainProvider,this._imageryLayers)};var K=new e;Z.prototype.computeTileVisibility=function(t,r,n){var o=this.computeDistanceToTile(t,r);if(t._distance=o,r.fog.enabled&&g.fog(o,r.fog.density)>=1)return T.NONE;var a=t.data,u=r.cullingVolume,c=s(a.orientedBoundingBox,a.boundingSphere3D);r.mode!==G.SCENE3D&&(c=K,e.fromRectangleWithHeights2D(t.rectangle,r.mapProjection,a.minimumHeight,a.maximumHeight,c),i.fromElements(c.center.z,c.center.x,c.center.y,c.center),r.mode===G.MORPHING&&(c=e.union(a.boundingSphere3D,c,c)));var h=u.computeVisibility(c);if(h===_.OUTSIDE)return T.NONE;if(r.mode===G.SCENE3D){var d=a.occludeePointInScaledSpace;return l(d)?n.ellipsoid.isScaledSpacePointVisible(d)?h:T.NONE:h}return h};var J=(p.supportsTypedArrays()?new Float32Array(1):void 0,new y),Q=new n,$=new i,ee=new i,te=new i,re=new i;Z.prototype.showTileThisFrame=function(e,t){for(var r=0,i=e.data.imagery,n=0,o=i.length;o>n;++n){var a=i[n];l(a.readyImagery)&&0!==a.readyImagery.imageryLayer.alpha&&++r}var s=this._tilesToRenderByTextureCount[r];l(s)||(s=[],this._tilesToRenderByTextureCount[r]=s),s.push(e);var u=this._debug;++u.tilesRendered,u.texturesRendered+=r};var ie=new i,ne=new i,oe=new i(0,-1,0),ae=new i(0,0,-1),se=new i;Z.prototype.computeDistanceToTile=function(e,t){var r=e.data,n=r.southwestCornerCartesian,o=r.northeastCornerCartesian,a=r.westNormal,s=r.southNormal,l=r.eastNormal,u=r.northNormal,c=r.maximumHeight;t.mode!==G.SCENE3D&&(n=t.mapProjection.project(S.southwest(e.rectangle),ie),n.z=n.y,n.y=n.x,n.x=0,o=t.mapProjection.project(S.northeast(e.rectangle),ne),o.z=o.y,o.y=o.x,o.x=0,a=oe,l=i.UNIT_Y,s=ae,u=i.UNIT_Z,c=0);var h,d=t.camera.positionWC,p=t.camera.positionCartographic,m=i.subtract(d,n,se),f=i.dot(m,a),v=i.dot(m,s),_=i.subtract(d,o,se),g=i.dot(_,l),y=i.dot(_,u);h=t.mode===G.SCENE3D?p.height:d.x;var C=h-c,E=0;return f>0?E+=f*f:g>0&&(E+=g*g),v>0?E+=v*v:y>0&&(E+=y*y),C>0&&(E+=C*C),Math.sqrt(E)},Z.prototype.isDestroyed=function(){return!1},Z.prototype.destroy=function(){return this._tileProvider=this._tileProvider&&this._tileProvider.destroy(),c(this)},Z.prototype._onLayerAdded=function(e,t){if(e.show){var r=this._terrainProvider;this._quadtree.forEachLoadedTile(function(t){e._createTileImagerySkeletons(t,r)&&(t.state=U.LOADING)}),this._layerOrderChanged=!0}},Z.prototype._onLayerRemoved=function(e,t){this._quadtree.forEachLoadedTile(function(t){for(var r=t.data.imagery,i=-1,n=0,o=0,a=r.length;a>o;++o){var s=r[o],u=s.loadingImagery;if(l(u)||(u=s.readyImagery),u.imageryLayer===e)-1===i&&(i=o),s.freeResources(),++n;else if(-1!==i)break}-1!==i&&r.splice(i,n)})},Z.prototype._onLayerMoved=function(e,t,r){this._layerOrderChanged=!0},Z.prototype._onLayerShownOrHidden=function(e,t,r){r?this._onLayerAdded(e,t):this._onLayerRemoved(e,t)};var le,ue,ce;!function(){function e(e){return new F({geometryInstances:e,appearance:new L({translucent:!1,flat:!0}),asynchronous:!1})}var r,n,o=new m({geometry:t.fromDimensions({dimensions:new i(2,2,2)})}),s=new m({geometry:new w({radius:1})}),u=new y;le=function(t,i){return t===r?n:(ce(),r=t,u=y.fromRotationTranslation(t.halfAxes,t.center,u),o.modelMatrix=u,o.attributes.color=a.fromColor(i),n=e(o))},ue=function(t,i){return t===r?n:(ce(),r=t,u=y.fromTranslation(t.center,u),u=y.multiplyByUniformScale(u,t.radius,u),s.modelMatrix=u,s.attributes.color=a.fromColor(i),n=e(s))},ce=function(){l(n)&&(n.destroy(),n=void 0,r=void 0)}}();var he=new n(0,0,0,0);return Z}),r("Scene/ImageryLayerCollection",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Event","../Core/Math","../Core/Rectangle","../ThirdParty/when","./ImageryLayer"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t){var r=e.indexOf(t);return r}function h(e,t,r){var i=e._layers;if(t=a.clamp(t,0,i.length-1),r=a.clamp(r,0,i.length-1),t!==r){var n=i[t];i[t]=i[r],i[r]=n,e._update(),e.layerMoved.raiseEvent(n,r,t)}}var d=function(){this._layers=[],this.layerAdded=new o,this.layerRemoved=new o,this.layerMoved=new o,this.layerShownOrHidden=new o};r(d.prototype,{length:{get:function(){return this._layers.length}}}),d.prototype.add=function(e,r){var i=t(r);i?this._layers.splice(r,0,e):(r=this._layers.length,this._layers.push(e)),this._update(),this.layerAdded.raiseEvent(e,r)},d.prototype.addImageryProvider=function(e,t){var r=new u(e);return this.add(r,t),r},d.prototype.remove=function(t,r){r=e(r,!0);var i=this._layers.indexOf(t);return-1!==i?(this._layers.splice(i,1),this._update(),this.layerRemoved.raiseEvent(t,i),r&&t.destroy(),!0):!1},d.prototype.removeAll=function(t){t=e(t,!0);for(var r=this._layers,i=0,n=r.length;n>i;i++){var o=r[i];this.layerRemoved.raiseEvent(o,i),t&&o.destroy()}this._layers=[]},d.prototype.contains=function(e){return-1!==this.indexOf(e)},d.prototype.indexOf=function(e){return this._layers.indexOf(e)},d.prototype.get=function(e){return this._layers[e]},d.prototype.raise=function(e){var t=c(this._layers,e);h(this,t,t+1)},d.prototype.lower=function(e){var t=c(this._layers,e);h(this,t,t-1)},d.prototype.raiseToTop=function(e){var t=c(this._layers,e);t!==this._layers.length-1&&(this._layers.splice(t,1),this._layers.push(e),this._update(),this.layerMoved.raiseEvent(e,this._layers.length-1,t))},d.prototype.lowerToBottom=function(e){var t=c(this._layers,e);0!==t&&(this._layers.splice(t,1),this._layers.splice(0,0,e),this._update(),this.layerMoved.raiseEvent(e,0,t))};var p=new s;return d.prototype.pickImageryLayerFeatures=function(e,r){var i=r.globe.pick(e,r);if(!t(i))return void 0;for(var n,o=r.globe.ellipsoid.cartesianToCartographic(i),u=r.globe._surface._tilesToRender,c=(u.length,0);!t(n)&&c<u.length;++c){var h=u[c];s.contains(h.rectangle,o)&&(n=h)}if(!t(n))return void 0;for(var d=(n.rectangle,n.data.imagery),m=[],f=[],v=d.length-1;v>=0;--v){var _=d[v],g=_.readyImagery;if(t(g)){var y=g.imageryLayer.imageryProvider;if(t(y.pickFeatures)&&s.contains(g.rectangle,o)){var C=p,E=1/1024;if(C.west=a.lerp(n.rectangle.west,n.rectangle.east,_.textureCoordinateRectangle.x-E),C.east=a.lerp(n.rectangle.west,n.rectangle.east,_.textureCoordinateRectangle.z+E),C.south=a.lerp(n.rectangle.south,n.rectangle.north,_.textureCoordinateRectangle.y-E),C.north=a.lerp(n.rectangle.south,n.rectangle.north,_.textureCoordinateRectangle.w+E),s.contains(C,o)){var S=y.pickFeatures(g.x,g.y,g.level,o.longitude,o.latitude);t(S)&&(m.push(S),f.push(g.imageryLayer))}}}}return 0===m.length?void 0:l.all(m,function(e){for(var r=[],i=0;i<e.length;++i){var n=e[i],a=f[i];if(t(n)&&n.length>0)for(var s=0;s<n.length;++s){var l=n[s];l.imageryLayer=a,t(l.position)||(l.position=o),r.push(l)}}return r})},d.prototype.isDestroyed=function(){return!1},d.prototype.destroy=function(){return this.removeAll(!0),i(this)},d.prototype._update=function(){for(var e,r,i=!0,n=this._layers,o=0,a=n.length;a>o;++o)r=n[o],r._layerIndex=o,r.show?(r._isBaseLayer=i,i=!1):r._isBaseLayer=!1,r.show!==r._show&&(t(r._show)&&(t(e)||(e=[]),e.push(r)),r._show=r.show);if(t(e))for(o=0,a=e.length;a>o;++o)r=e[o],this.layerShownOrHidden.raiseEvent(r,r._layerIndex,r.show)},d}),r("Scene/QuadtreeOccluders",["../Core/Cartesian3","../Core/defineProperties","../Core/EllipsoidalOccluder"],function(e,t,r){"use strict";var i=function(t){this._ellipsoid=new r(t.ellipsoid,e.ZERO)};return t(i.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),i}),r("Scene/QuadtreeTile",["../Core/defined","../Core/defineProperties","../Core/Cartographic","../Core/DeveloperError","../Core/Rectangle","./QuadtreeTileLoadState"],function(e,t,r,i,n,o){"use strict";var a=function(e){this._tilingScheme=e.tilingScheme,this._x=e.x,this._y=e.y,this._level=e.level,this._parent=e.parent,this._rectangle=this._tilingScheme.tileXYToRectangle(this._x,this._y,this._level),this._children=void 0,this._replacementPrevious=void 0,this._replacementNext=void 0,this._distance=0,this._customData=[],this._frameUpdated=void 0,this._frameRendered=void 0,this.state=o.START,this.renderable=!1,this.upsampledFromParent=!1,this.data=void 0};return a.createLevelZeroTiles=function(t){if(!e(t))throw new i("tilingScheme is required.");for(var r=t.getNumberOfXTilesAtLevel(0),n=t.getNumberOfYTilesAtLevel(0),o=new Array(r*n),s=0,l=0;n>l;++l)for(var u=0;r>u;++u)o[s++]=new a({tilingScheme:t,x:u,y:l,level:0});return o},a.createMinimumLevelTiles=function(e,t,i){for(var n=r.fromRadians(i.west,i.south),o=r.fromRadians(i.east,i.north),s=e.positionToTileXY(n,t),l=e.positionToTileXY(o,t),u=new Array,c=l.y;c<=s.y;c++)for(var h=s.x;h<=l.x;h++)u.push(new a({tilingScheme:e,x:h,y:c,level:t}));return u},a.prototype._updateCustomData=function(t,r,i){var o,a,s,l=this.customData;if(e(r)&&e(i)){for(o=0;o<i.length;++o){a=i[o];for(var u=0;u<l.length;++u)if(l[u]===a){l.splice(u,1);break}}for(s=this._rectangle,o=0;o<r.length;++o)a=r[o],n.contains(s,a.positionCartographic)&&l.push(a);this._frameUpdated=t}else{var c=this._parent;if(e(c)&&this._frameUpdated!==c._frameUpdated){l.length=0,s=this._rectangle;var h=c.customData;for(o=0;o<h.length;++o)a=h[o],n.contains(s,a.positionCartographic)&&l.push(a);this._frameUpdated=c._frameUpdated}}},t(a.prototype,{tilingScheme:{get:function(){return this._tilingScheme}},x:{get:function(){return this._x}},y:{get:function(){return this._y}},level:{get:function(){return this._level}},parent:{get:function(){return this._parent}},rectangle:{get:function(){return this._rectangle}},children:{get:function(){if(!e(this._children)){var t=this.tilingScheme,r=this.level+1,i=2*this.x,n=2*this.y;this._children=[new a({tilingScheme:t,x:i,y:n,level:r,parent:this}),new a({tilingScheme:t,x:i+1,y:n,level:r,parent:this}),new a({tilingScheme:t,x:i,y:n+1,level:r,parent:this}),new a({tilingScheme:t,x:i+1,y:n+1,level:r,parent:this})]}return this._children}},customData:{get:function(){return this._customData}},needsLoading:{get:function(){return this.state<o.DONE}},eligibleForUnloading:{get:function(){var t=!0;return e(this.data)&&(t=this.data.eligibleForUnloading,e(t)||(t=!0)),t}}}),a.prototype.freeResources=function(){if(this.state=o.START,this.renderable=!1,this.upsampledFromParent=!1,e(this.data)&&e(this.data.freeResources)&&this.data.freeResources(),e(this._children)){for(var t=0,r=this._children.length;r>t;++t)this._children[t].freeResources();this._children=void 0}},a}),r("Scene/TileReplacementQueue",["../Core/defined"],function(e){"use strict";function t(e,t){var r=t.replacementPrevious,i=t.replacementNext;t===e._lastBeforeStartOfFrame&&(e._lastBeforeStartOfFrame=i),t===e.head?e.head=i:r.replacementNext=i,t===e.tail?e.tail=r:i.replacementPrevious=r,t.replacementPrevious=void 0,t.replacementNext=void 0,--e.count}var r=function(){this.head=void 0,this.tail=void 0,this.count=0,this._lastBeforeStartOfFrame=void 0};return r.prototype.markStartOfRenderFrame=function(){this._lastBeforeStartOfFrame=this.head},r.prototype.trimTiles=function(r){for(var i=this.tail,n=!0;n&&e(this._lastBeforeStartOfFrame)&&this.count>r&&e(i);){n=i!==this._lastBeforeStartOfFrame;var o=i.replacementPrevious;i.eligibleForUnloading&&(i.freeResources(),t(this,i)),i=o}},r.prototype.markTileRendered=function(r){var i=this.head;return i===r?void(r===this._lastBeforeStartOfFrame&&(this._lastBeforeStartOfFrame=r.replacementNext)):(++this.count,e(i)?((e(r.replacementPrevious)||e(r.replacementNext))&&t(this,r),r.replacementPrevious=void 0,r.replacementNext=i,i.replacementPrevious=r,void(this.head=r)):(r.replacementPrevious=void 0,r.replacementNext=void 0,this.head=r,void(this.tail=r)))},r}),r("Scene/QuadtreePrimitive",["../Core/Cartesian3","../Core/Cartesian2","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/getTimestamp","../Core/Math","../Core/Queue","../Core/Ray","../Core/Rectangle","../Core/Visibility","./QuadtreeOccluders","./QuadtreeTile","./QuadtreeTileLoadState","./SceneMode","./TileReplacementQueue"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g){"use strict";function y(e,t){var r=e._debug;if(!r.suspendLodUpdate){var i,o,a=e._tilesToRender;a.length=0;var s=e._tileTraversalQueue;if(s.clear(),r.maxDepth=0,r.tilesVisited=0,r.tilesCulled=0,r.tilesRendered=0,r.tilesWaitingForChildren=0,e._tileLoadQueue.length=0,e._tileReplacementQueue.markStartOfRenderFrame(),!n(e._levelZeroTiles)){if(!e._tileProvider.ready)return;var l=e._tileProvider.tilingScheme,u=e._tileProvider._terrainProvider;if(u&&u._availableLevels&&u._rectangle){var c=u._availableLevels[0];e._levelZeroTiles=f.createMinimumLevelTiles(l,c,u._rectangle)}else e._levelZeroTiles=f.createLevelZeroTiles(l)}e._occluders.ellipsoid.cameraPosition=t.camera.positionWC;var h,d=e._tileProvider,m=e._occluders,v=e._levelZeroTiles,_=e._addHeightCallbacks,g=e._removeHeightCallbacks,y=t.frameNumber;if(_.length>0||g.length>0){for(i=0,o=v.length;o>i;++i)h=v[i],h._updateCustomData(y,_,g);_.length=0,g.length=0}for(i=0,o=v.length;o>i;++i)h=v[i],e._tileReplacementQueue.markTileRendered(h),h.needsLoading&&T(e,h),h.renderable&&d.computeTileVisibility(h,t,m)!==p.NONE?s.enqueue(h):(++r.tilesCulled,h.renderable||++r.tilesWaitingForChildren);for(n(e.sseCorrector)&&e.sseCorrector.newFrameState(t);n(h=s.dequeue());)if(++r.tilesVisited,e._tileReplacementQueue.markTileRendered(h),h._updateCustomData(y),h.level>r.maxDepth&&(r.maxDepth=h.level),C(e,t,h)<e.maximumScreenSpaceError)S(e,h);else if(w(e,h)){var E=h.children;for(i=0,o=E.length;o>i;++i)d.computeTileVisibility(E[i],t,m)!==p.NONE?s.enqueue(E[i]):++r.tilesCulled}else S(e,h);r.enableDebugOutput&&(r.tilesVisited!==r.lastTilesVisited||r.tilesRendered!==r.lastTilesRendered||r.tilesCulled!==r.lastTilesCulled||r.maxDepth!==r.lastMaxDepth||r.tilesWaitingForChildren!==r.lastTilesWaitingForChildren)&&(console.log("Visited "+r.tilesVisited+", Rendered: "+r.tilesRendered+", Culled: "+r.tilesCulled+", Max Depth: "+r.maxDepth+", Waiting for children: "+r.tilesWaitingForChildren),r.lastTilesVisited=r.tilesVisited,r.lastTilesRendered=r.tilesRendered,r.lastTilesCulled=r.tilesCulled,r.lastMaxDepth=r.maxDepth,r.lastTilesWaitingForChildren=r.tilesWaitingForChildren)}}function C(e,t,r){if(t.mode===_.SCENE2D)return E(e,t,r);var i=e._tileProvider.getLevelMaximumGeometricError(r.level),o=r._distance,a=t.context.drawingBufferHeight,s=t.camera.frustum.sseDenominator,l=i*a/(o*s);return t.fog.enabled&&(l-=u.fog(o,t.fog.density)*t.fog.sse),n(e.sseCorrector)&&(l=e.sseCorrector.correct(t,r,o,l)),l}function E(e,t,r){var i=t.camera,n=i.frustum,o=t.context,a=o.drawingBufferWidth,s=o.drawingBufferHeight,l=e._tileProvider.getLevelMaximumGeometricError(r.level),u=Math.max(n.top-n.bottom,n.right-n.left)/Math.max(a,s);return l/u}function S(e,t){e._tilesToRender.push(t),++e._debug.tilesRendered}function w(e,t){for(var r=!0,i=!0,n=t.children,o=0,a=n.length;a>o;++o){var s=n[o];e._tileReplacementQueue.markTileRendered(s),i=i&&s.upsampledFromParent,r=r&&s.renderable,s.needsLoading&&T(e,s)}return r||++e._debug.tilesWaitingForChildren,r&&!i}function T(e,t){e._tileLoadQueue.push(t)}function b(e,t){var r=e._tileLoadQueue,i=e._tileProvider;if(0!==r.length){e._tileReplacementQueue.trimTiles(e.tileCacheSize);for(var n=l(),o=e._loadQueueTimeSlice,a=n+o,s=r.length-1;s>=0;--s){var u=r[s];if(e._tileReplacementQueue.markTileRendered(u),i.loadTile(t,u),l()>=a)break}}}function x(t,i){for(var o=t._tileToUpdateHeights,a=t._tileProvider.terrainProvider,s=l(),u=t._updateHeightsTimeSlice,c=s+u,h=i.mode,p=i.mapProjection,m=p.ellipsoid;o.length>0;){var f=o[o.length-1];f!==t._lastTileUpdated&&(t._lastTileIndex=0);for(var v=f.customData,g=v.length,y=!1,C=t._lastTileIndex;g>C;++C){var E=v[C];if(f.level>E.level){n(E.position)||(E.position=m.cartographicToCartesian(E.positionCartographic)),h===_.SCENE3D?(e.clone(e.ZERO,M.origin),e.normalize(E.position,M.direction)):(r.clone(E.positionCartographic,D),D.height=-11500,p.project(D,R),e.fromElements(R.z,R.x,R.y,R),e.clone(R,M.origin),e.clone(e.UNIT_X,M.direction));var S=f.data.pick(M,h,p,!1,R);n(S)&&E.callback(S),E.level=f.level}else if(f.level===E.level){for(var w,T=f.children,b=T.length,x=0;b>x&&(w=T[x],!d.contains(w.rectangle,E.positionCartographic));++x);var P=a.getTileDataAvailable(w.x,w.y,w.level);(n(P)&&!P||n(parent)&&n(parent.data)&&n(parent.data.terrainData)&&!parent.data.terrainData.isChildAvailable(parent.x,parent.y,w.x,w.y))&&E.removeFunc()}if(l()>=c){y=!0;break}}if(y){t._lastTileUpdated=f,t._lastTileIndex=C;break}o.pop()}}function P(e,t){return e._distance-t._distance}function A(e,t){var r=e._tileProvider,i=e._tilesToRender,n=e._tileToUpdateHeights;i.sort(P);for(var o=0,a=i.length;a>o;++o){var s=i[o];r.showTileThisFrame(s,t),s._frameRendered!==t.frameNumber-1&&n.push(s),s._frameRendered=t.frameNumber}x(e,t)}var I=function(e){this._sseCorrector=e.sseCorrector,this._tileProvider=e.tileProvider,this._tileProvider.quadtree=this,this._debug={enableDebugOutput:!1,maxDepth:0,tilesVisited:0,tilesCulled:0,tilesRendered:0,tilesWaitingForChildren:0,lastMaxDepth:-1,lastTilesVisited:-1,lastTilesCulled:-1,lastTilesRendered:-1,lastTilesWaitingForChildren:-1,suspendLodUpdate:!1};var t=this._tileProvider.tilingScheme,r=t.ellipsoid;this._tilesToRender=[],this._tileTraversalQueue=new c,this._tileLoadQueue=[],this._tileReplacementQueue=new g,this._levelZeroTiles=void 0,this._levelZeroTilesReady=!1,this._loadQueueTimeSlice=5,this._addHeightCallbacks=[],this._removeHeightCallbacks=[],this._tileToUpdateHeights=[],this._lastTileIndex=0,this._updateHeightsTimeSlice=2,this.maximumScreenSpaceError=i(e.maximumScreenSpaceError,2),this.tileCacheSize=i(e.tileCacheSize,100),this._occluders=new m({ellipsoid:r})};o(I.prototype,{tileProvider:{get:function(){return this._tileProvider}}}),I.prototype.invalidateAllTiles=function(){var e=this._tileReplacementQueue;e.head=void 0,e.tail=void 0,e.count=0;var t=this._levelZeroTiles;if(n(t))for(var r=0;r<t.length;++r){for(var i=t[r],o=i.customData,a=o.length,s=0;a>s;++s){var l=o[s];l.level=0,this._addHeightCallbacks.push(l)}t[r].freeResources()}this._levelZeroTiles=void 0},I.prototype.forEachLoadedTile=function(e){for(var t=this._tileReplacementQueue.head;n(t);)t.state!==v.START&&e(t),t=t.replacementNext},I.prototype.forEachRenderedTile=function(e){for(var t=this._tilesToRender,r=0,i=t.length;i>r;++r)e(t[r])},I.prototype.updateHeight=function(e,t){var r=this,i={position:void 0,positionCartographic:e,level:-1,callback:t};return i.removeFunc=function(){r._removeHeightCallbacks.push(i)},r._addHeightCallbacks.push(i),i.removeFunc},I.prototype.update=function(e){var t=e.passes;t.render&&(this._tileProvider.beginUpdate(e),y(this,e),b(this,e),A(this,e),this._tileProvider.endUpdate(e)),t.pick&&this._tilesToRender.length>0&&this._tileProvider.endUpdate(e)},I.prototype.isDestroyed=function(){return!1},I.prototype.destroy=function(){this._tileProvider=this._tileProvider&&this._tileProvider.destroy()};var M=new h,D=new r,R=new e;return I}),r("Scene/Globe",["../Core/BoundingRectangle","../Core/BoundingSphere","../Core/buildModuleUrl","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/combine","../Core/ComponentDatatype","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/EllipsoidTerrainProvider","../Core/FeatureDetection","../Core/GeographicProjection","../Core/Geometry","../Core/GeometryAttribute","../Core/Intersect","../Core/IntersectionTests","../Core/loadImage","../Core/Math","../Core/Matrix4","../Core/Occluder","../Core/PrimitiveType","../Core/Ray","../Core/Rectangle","../Core/Transforms","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/VertexArray","../Shaders/GlobeFS","../Shaders/GlobeFSPole","../Shaders/GlobeVS","../Shaders/GlobeVSPole","../Shaders/GroundAtmosphere","../ThirdParty/when","./GlobeSurfaceShaderSet","./GlobeSurfaceTileProvider","./ImageryLayerCollection","./Pass","./QuadtreePrimitive","./SceneMode","./terrainAttributeLocations"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X){"use strict";function Z(e){return function(r,i){var n=t.distanceSquaredTo(r.pickBoundingSphere,e),o=t.distanceSquaredTo(i.pickBoundingSphere,e);return n-o}}function K(t,r,i,o,a,s){le.longitude=0,le.latitude=o;var l=t._ellipsoid.cartographicToCartesian(le,ue);le.longitude=Math.PI;var u=t._ellipsoid.cartographicToCartesian(le,ce),c=.5*n.magnitude(n.subtract(l,u,oe),oe);le.longitude=0,le.latitude=i;var h,d=t._ellipsoid.cartographicToCartesian(le,ue),p=r.camera.direction;h=1-n.dot(se,p)<S.EPSILON6?n.UNIT_X:n.normalize(n.cross(p,n.UNIT_Z,oe),oe);var m=n.add(d,n.multiplyByScalar(h,c,oe),oe),f=n.add(d,n.multiplyByScalar(n.normalize(n.cross(n.UNIT_Z,h,ae),ae),c,ae),ae);A.pointToGLWindowCoordinates(a,s,d,d),A.pointToGLWindowCoordinates(a,s,m,m),A.pointToGLWindowCoordinates(a,s,f,f);var v=Math.floor(Math.max(n.distance(f,d),n.distance(m,d))),_=v;return new e(Math.floor(d.x)-v,Math.floor(d.y)-_,2*v,2*_)}function J(e,r){var i=e.terrainProvider;if(r.mode===Y.SCENE3D&&i.ready){var n=i.tilingScheme.rectangle,o=r.context,l=o.uniformState.viewProjection,c=he;c.width=o.drawingBufferWidth,c.height=o.drawingBufferHeight;var h,d,p,m,f,v,C,E=w.computeViewportTransformation(c,0,1,de),b=.05,x=e._occluder;n.north<S.PI_OVER_TWO&&(h=new P(-Math.PI,n.north,Math.PI,S.PI_OVER_TWO),d=t.fromRectangle3D(h,e._ellipsoid),p=r.cullingVolume.computeVisibility(d)===y.OUTSIDE,m=T.computeOccludeePointFromRectangle(h,e._ellipsoid),f=m&&!x.isPointVisible(m,0)||!x.isBoundingSphereVisible(d),e._drawNorthPole=!p&&!f,e._drawNorthPole&&(C=K(e,r,h.north,h.south-b,l,E),pe[0]=C.x,pe[1]=C.y,pe[2]=C.x+C.width,pe[3]=C.y,pe[4]=C.x+C.width,pe[5]=C.y+C.height,pe[6]=C.x,pe[7]=C.y+C.height,u(e._northPoleCommand.vertexArray)?e._northPoleCommand.vertexArray.getAttribute(0).vertexBuffer.copyFromArrayView(pe):(e._northPoleCommand.boundingVolume=t.fromRectangle3D(h,e._ellipsoid),v=new _({attributes:{position:new g({componentDatatype:s.FLOAT,componentsPerAttribute:2,values:pe})}}),e._northPoleCommand.vertexArray=L.fromGeometry({context:o,geometry:v,attributeLocations:{position:0},bufferUsage:I.STREAM_DRAW})))),n.south>-S.PI_OVER_TWO&&(h=new P(-Math.PI,-S.PI_OVER_TWO,Math.PI,n.south),d=t.fromRectangle3D(h,e._ellipsoid),p=r.cullingVolume.computeVisibility(d)===y.OUTSIDE,m=T.computeOccludeePointFromRectangle(h,e._ellipsoid),f=m&&!x.isPointVisible(m)||!x.isBoundingSphereVisible(d),e._drawSouthPole=!p&&!f,e._drawSouthPole&&(C=K(e,r,h.south,h.north+b,l,E),pe[0]=C.x,pe[1]=C.y,pe[2]=C.x+C.width,pe[3]=C.y,pe[4]=C.x+C.width,pe[5]=C.y+C.height,pe[6]=C.x,pe[7]=C.y+C.height,u(e._southPoleCommand.vertexArray)?e._southPoleCommand.vertexArray.getAttribute(0).vertexBuffer.copyFromArrayView(pe):(e._southPoleCommand.boundingVolume=t.fromRectangle3D(h,e._ellipsoid),v=new _({attributes:{position:new g({componentDatatype:s.FLOAT,componentsPerAttribute:2,values:pe})}}),e._southPoleCommand.vertexArray=L.fromGeometry({context:o,geometry:v,attributeLocations:{position:0},bufferUsage:I.STREAM_DRAW}))));var A=0,M=e._imageryLayerCollection.length>0?e._imageryLayerCollection.get(0):void 0;u(M)&&u(M.imageryProvider)&&u(M.imageryProvider.getPoleIntensity)&&(A=M.imageryProvider.getPoleIntensity());var D={u_dayIntensity:function(){return A}};if(!u(e._northPoleCommand.uniformMap)){var R=a(D,{u_color:function(){return e.northPoleColor}});e._northPoleCommand.uniformMap=a(R,e._drawUniforms); -}if(!u(e._southPoleCommand.uniformMap)){var O=a(D,{u_color:function(){return e.southPoleColor}});e._southPoleCommand.uniformMap=a(O,e._drawUniforms)}}}var Q=function(e){e=l(e,p.WGS84);var o=new m({ellipsoid:e}),a=new H;this._ellipsoid=e,this._imageryLayerCollection=a,this._surfaceShaderSet=new G,this._surfaceShaderSet.baseVertexShaderSource=new O({sources:[k,V]}),this._surfaceShaderSet.baseFragmentShaderSource=new O({sources:[F]}),this._surface=new j({tileProvider:new W({terrainProvider:o,imageryLayers:a,surfaceShaderSet:this._surfaceShaderSet})}),this._occluder=new T(new t(n.ZERO,e.minimumRadius),n.ZERO),this._rsColor=void 0,this._rsColorWithoutDepthTest=void 0,this._northPoleCommand=new M({pass:q.OPAQUE,owner:this}),this._southPoleCommand=new M({pass:q.OPAQUE,owner:this}),this._drawNorthPole=!1,this._drawSouthPole=!1,this._mode=Y.SCENE3D,this.terrainProvider=o,this.northPoleColor=new n(2/255,6/255,18/255),this.southPoleColor=new n(1,1,1),this.show=!0,this.oceanNormalMapUrl=r("Assets/Textures/waterNormalsSmall.jpg"),this._oceanNormalMapUrl=void 0,this.maximumScreenSpaceError=2,this.tileCacheSize=100,this.enableLighting=!1,this.lightingFadeOutDistance=65e5,this.lightingFadeInDistance=9e6,this.showWaterEffect=!0,this.depthTestAgainstTerrain=!1,this._oceanNormalMap=void 0,this._zoomedOutOceanSpecularIntensity=.5,this._lightingFadeDistance=new i(this.lightingFadeOutDistance,this.lightingFadeInDistance);var s=this;this._drawUniforms={u_zoomedOutOceanSpecularIntensity:function(){return s._zoomedOutOceanSpecularIntensity},u_oceanNormalMap:function(){return s._oceanNormalMap},u_lightingFadeDistance:function(){return s._lightingFadeDistance}}};c(Q.prototype,{ellipsoid:{get:function(){return this._ellipsoid}},imageryLayers:{get:function(){return this._imageryLayerCollection}},baseColor:{get:function(){return this._surface.tileProvider.baseColor},set:function(e){this._surface.tileProvider.baseColor=e}}});var $=[],ee={start:0,stop:0};Q.prototype.pick=function(e,r,i){var o=r.mode,a=r.mapProjection,s=$;s.length=0;var l,c,h=this._surface._tilesToRender,d=h.length;for(c=0;d>c;++c){l=h[c];var p=l.data;if(u(p)){var m=p.pickBoundingSphere;o!==Y.SCENE3D?(t.fromRectangleWithHeights2D(l.rectangle,a,p.minimumHeight,p.maximumHeight,m),n.fromElements(m.center.z,m.center.x,m.center.y,m.center)):t.clone(p.boundingSphere3D,m);var f=C.raySphere(e,m,ee);u(f)&&s.push(p)}}s.sort(Z(e.origin));var v;for(d=s.length,c=0;d>c&&(v=s[c].pick(e,r.mode,r.mapProjection,!0,i),!u(v));++c);return v};var te=new n,re=new n,ie=new o,ne=new x;Q.prototype.getHeight=function(e){var t=this._surface._levelZeroTiles;if(u(t)){var r,i,o=t.length;for(i=0;o>i&&(r=t[i],!P.contains(r.rectangle,e));++i);if(!u(r)||!P.contains(r.rectangle,e))return void 0;for(;r.renderable;){var a=r.children;for(o=a.length,i=0;o>i&&(r=a[i],!P.contains(r.rectangle,e));++i);}for(;u(r)&&(!u(r.data)||!u(r.data.pickTerrain));)r=r.parent;if(!u(r))return void 0;var s=this._surface._tileProvider.tilingScheme.ellipsoid,l=s.cartographicToCartesian(e,te),c=ne;n.normalize(l,c.direction);var h=r.data.pick(c,void 0,void 0,!1,re);return u(h)?s.cartesianToCartographic(h,ie).height:void 0}};var oe=new n,ae=new n,se=n.negate(n.UNIT_Z,new n),le=new o(0,0),ue=new n,ce=new n,he=new e,de=new w,pe=f.supportsTypedArrays()?new Float32Array(8):[];return Q.prototype.update=function(e){if(this.show){var t=e.context,r=t.drawingBufferWidth,i=t.drawingBufferHeight;if(0!==r&&0!==i){var n=e.mode,o=(e.mapProjection,!1);this._mode===n&&u(this._rsColor)||(o=!0,n===Y.SCENE3D||n===Y.COLUMBUS_VIEW?(this._rsColor=D.fromCache({cull:{enabled:!0},depthTest:{enabled:!0}}),this._rsColorWithoutDepthTest=D.fromCache({cull:{enabled:!0}})):(this._rsColor=D.fromCache({cull:{enabled:!0}}),this._rsColorWithoutDepthTest=D.fromCache({cull:{enabled:!0}}))),this._mode=n;var a=this._northPoleCommand,s=this._southPoleCommand;a.renderState=this._rsColorWithoutDepthTest,s.renderState=this._rsColorWithoutDepthTest;var l=this._surface,c=l.tileProvider,h=this.terrainProvider,d=this.showWaterEffect&&h.ready&&h.hasWaterMask;if(d&&this.oceanNormalMapUrl!==this._oceanNormalMapUrl){var p=this.oceanNormalMapUrl;if(this._oceanNormalMapUrl=p,u(p)){var m=this;U(E(p),function(e){p===m.oceanNormalMapUrl&&(m._oceanNormalMap=m._oceanNormalMap&&m._oceanNormalMap.destroy(),m._oceanNormalMap=new N({context:t,source:e}))})}else this._oceanNormalMap=this._oceanNormalMap&&this._oceanNormalMap.destroy()}if(!u(a.shaderProgram)||!u(s.shaderProgram)){var f=R.replaceCache({context:t,shaderProgram:a.shaderProgram,vertexShaderSource:z,fragmentShaderSource:B,attributeLocations:X});a.shaderProgram=f,s.shaderProgram=f}this._occluder.cameraPosition=e.camera.positionWC,J(this,e);var v=e.commandList,_=e.passes;_.render&&(n===Y.SCENE3D&&(this._drawNorthPole&&v.push(a),this._drawSouthPole&&v.push(s)),n===Y.SCENE3D?this._zoomedOutOceanSpecularIntensity=.5:this._zoomedOutOceanSpecularIntensity=0,l.maximumScreenSpaceError=this.maximumScreenSpaceError,l.tileCacheSize=this.tileCacheSize,c.terrainProvider=this.terrainProvider,c.lightingFadeOutDistance=this.lightingFadeOutDistance,c.lightingFadeInDistance=this.lightingFadeInDistance,c.zoomedOutOceanSpecularIntensity=this._zoomedOutOceanSpecularIntensity,c.hasWaterMask=d,c.oceanNormalMap=this._oceanNormalMap,c.enableLighting=this.enableLighting,l.update(e)),_.pick&&l.update(e)}}},Q.prototype.isDestroyed=function(){return!1},Q.prototype.destroy=function(){return this._northPoleCommand.vertexArray=this._northPoleCommand.vertexArray&&this._northPoleCommand.vertexArray.destroy(),this._southPoleCommand.vertexArray=this._southPoleCommand.vertexArray&&this._southPoleCommand.vertexArray.destroy(),this._surfaceShaderSet=this._surfaceShaderSet&&this._surfaceShaderSet.destroy(),this._northPoleCommand.shaderProgram=this._northPoleCommand.shaderProgram&&this._northPoleCommand.shaderProgram.destroy(),this._southPoleCommand.shaderProgram=this._northPoleCommand.shaderProgram,this._surface=this._surface&&this._surface.destroy(),this._oceanNormalMap=this._oceanNormalMap&&this._oceanNormalMap.destroy(),h(this)},Q}),r("Shaders/PostProcessFilters/PassThrough",[],function(){"use strict";return"uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n"}),r("Scene/GlobeDepth",["../Core/Color","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/PixelFormat","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/PassThrough"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e,r,i){if(!t(e._debugGlobeDepthViewportCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n float n_range = czm_depthRange.near;\n float f_range = czm_depthRange.far;\n float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n}\n";e._debugGlobeDepthViewportCommand=r.createViewportQuadCommand(n,{uniformMap:{u_texture:function(){return e._globeDepthTexture}},owner:e})}e._debugGlobeDepthViewportCommand.execute(r,i)}function d(e){e._colorTexture=e._colorTexture&&!e._colorTexture.isDestroyed()&&e._colorTexture.destroy(),e._depthStencilTexture=e._depthStencilTexture&&!e._depthStencilTexture.isDestroyed()&&e._depthStencilTexture.destroy(),e._globeDepthTexture=e._globeDepthTexture&&!e._globeDepthTexture.isDestroyed()&&e._globeDepthTexture.destroy()}function p(e){e.framebuffer=e.framebuffer&&!e.framebuffer.isDestroyed()&&e.framebuffer.destroy(),e._copyDepthFramebuffer=e._copyDepthFramebuffer&&!e._copyDepthFramebuffer.isDestroyed()&&e._copyDepthFramebuffer.destroy()}function m(e,t,r,i){e._colorTexture=new u({context:t,width:r,height:i,pixelFormat:n.RGBA,pixelDatatype:s.UNSIGNED_BYTE}),e._depthStencilTexture=new u({context:t,width:r,height:i,pixelFormat:n.DEPTH_STENCIL,pixelDatatype:s.UNSIGNED_INT_24_8}),e._globeDepthTexture=new u({context:t,width:r,height:i,pixelFormat:n.RGBA,pixelDatatype:s.UNSIGNED_BYTE})}function f(e,t,r,i){d(e),p(e),m(e,t,r,i),e.framebuffer=new a({context:t,colorTextures:[e._colorTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._copyDepthFramebuffer=new a({context:t,colorTextures:[e._globeDepthTexture],destroyAttachments:!1})}function v(e,r){var i=r.drawingBufferWidth,n=r.drawingBufferHeight,o=e._colorTexture,a=!t(o)||o.width!==i||o.height!==n;(!t(e.framebuffer)||a)&&f(e,r,i,n)}function _(r,i){if(!t(r._copyDepthCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n}\n";r._copyDepthCommand=i.createViewportQuadCommand(n,{renderState:l.fromCache(),uniformMap:{u_texture:function(){return r._depthStencilTexture}},owner:r})}r._copyDepthCommand.framebuffer=r._copyDepthFramebuffer,t(r._copyColorCommand)||(r._copyColorCommand=i.createViewportQuadCommand(c,{renderState:l.fromCache(),uniformMap:{u_texture:function(){return r._colorTexture}},owner:r})),t(r._clearColorCommand)||(r._clearColorCommand=new o({color:new e(0,0,0,0),stencil:0,owner:r})),r._clearColorCommand.framebuffer=r.framebuffer}var g=function(){this._colorTexture=void 0,this._depthStencilTexture=void 0,this._globeDepthTexture=void 0,this.framebuffer=void 0,this._copyDepthFramebuffer=void 0,this._clearColorCommand=void 0,this._copyColorCommand=void 0,this._copyDepthCommand=void 0,this._debugGlobeDepthViewportCommand=void 0};return g.prototype.executeDebugGlobeDepth=function(e,t){h(this,e,t)},g.prototype.update=function(e){v(this,e),_(this,e),e.uniformState.globeDepthTexture=void 0},g.prototype.executeCopyDepth=function(e,r){t(this._copyDepthCommand)&&(this._copyDepthCommand.execute(e,r),e.uniformState.globeDepthTexture=this._globeDepthTexture)},g.prototype.executeCopyColor=function(e,r){t(this._copyColorCommand)&&this._copyColorCommand.execute(e,r)},g.prototype.clear=function(r,i,n){var o=this._clearColorCommand;t(o)&&(e.clone(n,o.color),o.execute(r,i))},g.prototype.isDestroyed=function(){return!1},g.prototype.destroy=function(){d(this),p(this),t(this._copyColorCommand)&&(this._copyColorCommand.shaderProgram=this._copyColorCommand.shaderProgram.destroy()),t(this._copyDepthCommand)&&(this._copyDepthCommand.shaderProgram=this._copyDepthCommand.shaderProgram.destroy());var e=this._debugGlobeDepthViewportCommand;return t(e)&&(e.shaderProgram=e.shaderProgram.destroy()),i(this)},g}),r("Scene/GoogleEarthImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicTilingScheme","../Core/loadText","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t,i,n){var o=e._imageUrlTemplate;o=o.replace("{x}",t),o=o.replace("{y}",i),o=o.replace("{zoom}",n+1);var a=e._proxy;return r(a)&&(o=a.getURL(o)),o}var f=function v(i){function n(e){var t;try{t=JSON.parse(e)}catch(n){t=JSON.parse(e.replace(/([\[\{,])[\n\r ]*([A-Za-z0-9]+)[\n\r ]*:/g,'$1"$2":'))}for(var o,s=0;s<t.layers.length;s++)if(t.layers[s].id===g._channel){o=t.layers[s];break}var d;if(!r(o))throw d="Could not find layer with channel (id) of "+g._channel+".",f=c.handleError(f,g,g._errorEvent,d,void 0,void 0,void 0,m),new u(d);if(!r(o.version))throw d="Could not find a version in channel (id) "+g._channel+".",f=c.handleError(f,g,g._errorEvent,d,void 0,void 0,void 0,m),new u(d);if(g._version=o.version,r(t.projection)&&"flat"===t.projection)g._tilingScheme=new a({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:2,rectangle:new l(-Math.PI,-Math.PI,Math.PI,Math.PI),ellipsoid:i.ellipsoid});else{if(r(t.projection)&&"mercator"!==t.projection)throw d="Unsupported projection "+t.projection+".",f=c.handleError(f,g,g._errorEvent,d,void 0,void 0,void 0,m),new u(d);g._tilingScheme=new h({numberOfLevelZeroTilesX:2,numberOfLevelZeroTilesY:2,ellipsoid:i.ellipsoid})}g._imageUrlTemplate=g._imageUrlTemplate.replace("{request}",g._requestType).replace("{channel}",g._channel).replace("{version}",g._version),g._ready=!0,g._readyPromise.resolve(!0),c.handleSuccess(f)}function p(e){var t="An error occurred while accessing "+_+".";f=c.handleError(f,g,g._errorEvent,t,void 0,void 0,void 0,m),g._readyPromise.reject(new u(t))}function m(){var e=r(g._proxy)?g._proxy.getURL(_):_,t=s(e);d(t,n,p)}i=t(i,{}),this._url=i.url,this._path=t(i.path,"/default_map"),this._tileDiscardPolicy=i.tileDiscardPolicy,this._proxy=i.proxy,this._channel=i.channel,this._requestType="ImageryMaps",this._credit=new e("Google Imagery",v._logoData,"http://www.google.com/enterprise/mapsearth/products/earthenterprise.html"),this.defaultGamma=1.9,this._tilingScheme=void 0,this._version=void 0,this._tileWidth=256,this._tileHeight=256,this._maximumLevel=i.maximumLevel,this._imageUrlTemplate=this._url+this._path+"/query?request={request}&channel={channel}&version={version}&x={x}&y={y}&z={zoom}",this._errorEvent=new o,this._ready=!1,this._readyPromise=d.defer();var f,_=this._url+this._path+"/query?request=Json&vars=geeServerDefs&is2d=t",g=this;m()};return i(f.prototype,{url:{get:function(){return this._url}},path:{get:function(){return this._path}},proxy:{get:function(){return this._proxy}},channel:{get:function(){return this._channel}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},version:{get:function(){return this._version}},requestType:{get:function(){return this._requestType}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),f.prototype.getTileCredits=function(e,t,r){return void 0},f.prototype.requestImage=function(e,t,r){var i=m(this,e,t,r);return p.loadImage(this,i)},f.prototype.pickFeatures=function(){return void 0},f._logoData="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAnCAYAAACmP2LfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAHdElNRQfcDB4TJDr1mp5kAAAAGnRFWHRTb2Z0d2FyZQBQYWludC5ORVQgdjMuNS4xMDD0cqEAAB1zSURBVHhe7ZwHeFTFFsf/u+l9N70npOxuSAKEFFIhCSH0qhEQUHkgKCgWUFGBB6IoCAoo0ntooaRvEkIIBBBpoYSa3nvvfd+5u4sQUigPfMX8v2/Y3Tkzs3fv/d0z58zcgF69Ql1SY+MM1wQJem44ZeiJk8beEOqPwG6uC7ZqyElb9eo/JZEIkH2nRQkBIlNMauuPCS3uGN/kjkmNDghoskBAgzrZ2NLmf1+JwIKQpYsoxdmIV9+N07onCegzBPM9bOdmYKnazF6g/1N6UySPqSJzvCaaiLHtP8G/Phq+FRfgU5ogKWUXMLT6Mvzqr2BE40mMadqO8c3zMabBC6PqDDC8SlY60t9HByCLVTKu+ERmHr5TWI9wjVxEaOZivWo1pil8D1tZeWnLXv1l8iZ3PF2kjymiWRgvCoJv5U243IyAXcQq8A9Mg9W+4bDe6wv+kVGwCZkL+4Sf4ZR+BZ5VGQR3EkbWn8Hopm3wq54Lz2JD6ah/P21XGopQ9Qoc16jGSqVyTJWbQbUsibFXf42mihTwZpsvAtp3k0dOhFOSEH1+ngaDefrgjFCgFkxY8fCisCBvKgODzxRh9qslBFGfYmDGLbiV5mBwRRo8KtPhVBgPu8teMP7u73chD6kMRYRGBY5xqrFKqQwz5SdTbS/Qf5mmUYw8rf01CjHC4VP7AHZxO6E3qy9ZZCQNnio2rE/4o9/tkxiQUYp+KRXgx8XC5FsXcLz/hkCrDUU4pxLHuDVYpdwL9F+qqSJZKlPwenskfOoI5tN7YPCJGVme7wKYr5EBXzgYfW+mwTI0Gjrznaj2WW+I/y8dVPdDGLcKRzXrsEqlHO8oTKHaXqAZWe9hQXCi63NhHWYI3ilfWIW/YLjqL2JRiOFBJRz+LffhcPs09D+0J8vzn3zXdBnYnp8Mi6NboTWzH9X8fVc+DhDQodxqAroe36lU9AJNWr4cEAjNwI8OAC9cT1rbUfzwGeCfKiL7dGnNc+q1NiO80b4BY1oT4V6WDcsdc6j2xbyq4wMWrA9rQmeWFn36ey/jBaoPQ4hmLYI0G/AtAf22fC/QDols8ITrIYi/Bl6knbS2o3gRbxHQxQQ0k0S/gCa2v4OJovPwacqAQ1ICjL40klr+UrWoQbFBETo18jCpZsOoFODkvuCNJYoHW3QKXFEM7ETRcKfiQe8d6NVIFImXvg4skhY40mxnQYVRIIeA1qrHEc1GrFSpxFtP99AiFbDbNKDZpAzzGkVYVcvBuBJQEo/9/6C+dyjPitwLwak74D8V6Bfw0P5VShjXFoTR7TfhUZkL29M/wfATJan1lauWC3aDOgyaVDCuTgbf1bFkfmtkye1ogsK2asivLYfCglIoD8qCknI2NHuG4QSVGMgQyMbt0fioRYh9VYcRU7QX55uDcaHtFOJEsThMtmWtQgxsDodsWaC0c3ea3MzGBJEqxrfbYmzr6xjfPAeTmt5HQPO7eK1xDibUz8eY+k8xtHYJPCtXwvHOu7AXMrMTsF/TH8HajTis1YwVqpWY0TXQDKy1OpBr5EJA52Fukxx+bmKxtjWx2DuaWawNlZD5qhzyo9KhpHAbKpJO/6t65UCPbPHA2PYrGNacgkElabCJJDev/MpDhUKKnuq44LRoYEK1IiswkS1zYCfk5y+F0qjvoTwqBOof34dGeAnUL1ZCLboEnJ9zoe0QD/Nuj00UBVXRabzVLETM3S0ICfwA8yc7Y6C3ANYbZsA7aQ1W1xzEfZEQ6dT2BkG9pP4ouo7jGE1u42JS20QMrzkCr4xwuN4+AM+cYII3EaNar2J86zmMrP8DHulCON4NhU3YWuhOYy6SZENpH9cfx7WacFC7BSvUqjBDsRPQIiugURvazeqYVaqAw6dYrJ9WQy7gayj4nYDy3HtQOVQGpYRqKEWXQf2HdGha/AFdae9Xr4czz0ubISRA75ECbSut7agegO75OLxpahze8j5GtifBpzEDLiV30Dd2mNT6StWiCbVmLt5rUkBQCEt2zWzIMSA8HgrIBkLD+Sp0jhHISYXQ/KMYukfvQ3fQxq68XCTBHId/tMTg7LV1CFs4BszJ6hBarBgHlcRv8H7tbuSKQpFPYGe0BmND+nZ0npECaPKf0r4UIxsuoF/IMpitsAVnrA4s15uh3x8fwLXkLobUZGJIXTqcUzbDaJE5FAVq0t4S7dEcjqMEc6B2K5arVWN6Z6AbdOmm5mJelQKOHWSxF44Cy4CqxW0s6RwchCovFRohdGNfLgX3WiZ0N4aD++y7jfwYJUrAPCle/ZjKV+BFTSegrGAZIm3QjXhBytTWB3zhByzryMUU986jz16wD+96ijCNUIAgmkc3tS6G7GERjCbgR82B4OTbEESqIiCIcqsIYzoGGyrBEMSmgh8xBoIIAR2fAHZhj8Z9DOhl9FHeKkSDvn809fuc+iyCddRYaiOZBTvIt1YJfs0b4N+WDO+GHPLQN2Ab7S61vjJV60C9SRPvNSqzTpxlyQfS1dGUmjppK7gW16B/LhN6abnQu5cDwzO3YNhhqqK4WJY887sEdGzWFpxfOxmDpKZOOvgWFB8sx9L6nShvP4FyUQjKGg5gScpGKEqbUE7RxiGYv6QQ4zIG/r4D2m88sjEy/EIW/a6+TQ4gHe5VhXCvy4JL7gLYnesI2i6t4Tii04r92u1YKt767gB0ozrkGzmY26zEOh7Hkt+kAKhLTX9qOVVdg9aoNOjcToR+wUVKLYKgN0Zq7l7884wn9CKgr4AfWw/B6SwqKQRKOdXVghe9CpbherASSjtIpGpxRIHFjwygNreoXy0lb+lU7lHJBP9kPcGXQnBNghUB/Lh44fbUp5JA+5Hs71LbPPLCVRDEJZDNGIJgeQI6mG6KegKzldq1U7tGKjQmHR8vwl86kgRoAQN0xBw6ztn0nQ/ocxEdQ7L4d/BjG6g+m8aZTL/xsXPuW82Fb8t+DG1Ox5D6XAwqvQ67OA+p9ZWoUQPsei78mjSwNU9GLmEzVGZJTd3qFPTn3YZhXgYMMjNhlHsDxms/hNWfoUdrNPgEc2h7BG5d/Bo7Blt0BuNxXf4MVmXrkdRyEHWiY6hr2oc7mevRX2wc18gioEeI1+N9a+/CNnImVAZ0mhEoNOPAJT8MHjUF8KTiWhqHgbfMpVaJdhLQh3XasU9bJAZ6ekeg6zQwgEKuLSWysmd3QGmatLqD8qDNug3dCX/AIPk4jGr2wDB/JXTmkan70IvmZTY/rB9BdZlKLkG0lG0d5klAObKsw1+jzyFiWPnRawiaDrMYwTyMwMwh220WP2IWFVfqN4CKO8E3n0C6R/ZUej9Y2kUiMdDRFTRePH3nA3q/m7xpAEtAXl0QrkTwscnmS/3eptdzNEYevZLnZ5booqk8tuYs9tAny+n1LL1mghezlcULH0VtHamOZhvhIvoNOXQsd2EZIbluYnlWaMO75TCFG9kYXJ8H14o76H/10Z3yClSrCm6jGtbWK7LC7kIlYRfUmY2XHnUa+mbXYRSfCuNCptyE6b1jMBD/EPKwchQPLxGdxOWWI8iKXYBPqLozgI8pfA5YBWvxbfMeNLUfRmPTLjRnr8YKsdGvRQ5j2zZTSSRQ78H+7GhxfScFAINypsG9ukDspZ0LKKE+O0pqlGi71ggcIqD3dga6RhFKjSqYT+VEFkvu/E9Q+HNWKaE2VVDgVkPFqwAaay5CN3En9M59BM2vfKDs7AvljjPGE5LlharQdL+LoCmhOHU0rIUyD+NgVTOa+q2iVQiIcAKpHtbhXuJOjPqeVCRYThNE6VTvKNs3hM3cHGIxntxKyCbP7Erj1lHZJbVIJAG6iiCroZCAPGukvOyASJbvCgoaAoKoAQ1kHcGC7nmZDkmhBR2PfSQLtkcl4zCSAE2eO6qExYuYxrE4KqdvelBiM4+ncYQy1IY8d0wbhUSLJAZGbsUceNYdwJCGPAyuy4NbZToG3JoO1Qk9AvHvqF4ejo0KCKlisyl04Jw+AE1ma71HRUJP+QqM1t2HcVEyTEoSYVYQCuN3HenCt4XDhGA+KorAnYZ9KIj5ELOl3XpU/k/wrt+OmraDaG7cjpacbxFvYAAZDG5Vw/DWCxjRdp+ATsWAS6+D69H1+XDNsoVb1T06b0VwzCmBIOYdqUWibTojcFBH1CXQctBtUcA6Oh/RmVC4sBmKA5j6erC1qqE4sRpqG25A43QIOHuXgvOmP5R4ZH6m5UY2L9SSLjZ5sKjjsI/o8olH8ngjCZoSgmw9DMIl3t42Up0g+pq89/sEjLK47knZhSkSuDepJP4JOyNJyEFAR8VQKMOR1nbWM69yxNJYwh+VLE90ffPyxLE3EwL9Jq0huWQqwL1iA7zq8+FVl0+epgBO6T+gb2TH+OglqgastxtZrNNlkLt8E5oJx6HZdab7mFZBk3UZRjMewCT7HkzLfodZxREYr5sBjiIBPYiAPt8ehvSGPSg5vwjzpd16VNkmmDTswp22QDTXbkJrxhJkzHGDFoUQmvBpvo2hrZl0TnLhlLIYfUO7nt7dSg3hURcP1/JiDEgphuXBqVKLRFsfA3oJAf3mI6Cr2OjTwGYdqWGzzmZD6WoYVCfehdqsZKjuuwS1oB1Q+5piHac3oaxBzZ9vLZ4nHEeesoXg6niDPSYWP9yUgD5PHu48eKE64krHcErchHIEuRysTpAXjObQWIYEHiV4EQYEojp5aEoyY+IIpOQugKYYOnIdJXrdJ63PtWwXMQM6m6SVT4gfZkbHV0XHsVtaQ3K8yoJr0YfwoHDDq5ZiQSqDik/B4Q9taYtn18gyNia1qGJsmTrGlUjK2FJ1jCjRwOASDnkxDvN95ZD/og5yl0qgfCMJ2leDoeksHaFHXYOJVyrMkm/DrPwMzGr2wmjnLGipthyHL0W7t9pDkduwF2U3lmGFtvbTdyirt0OreT+iWwPRUrUBbSkLkT/fCUZwKVYikBMwpDlPXNzLwuAQ2rWX8KzUh2dDDJyLSmB7/S5Mf3WRWiR6CPSezkCXQs6qBnLCKsheyoXqnTCoL9oOFd9/Qtl9KJT6UJMX3/zhCz8iuCjhiviSYtMx3ZTJBN8lCE7eIRgF0p6krRRaRBDskTTGySBKws5SuUjJHYUiMQdpzCUE0Q3y5MnSDhJJQg5JUvjSgO5hHZofaioGmvc40IycMgbRtJktjgOZ5Ma9irzSg46xYHcaVEZevkgBHqUWGFK+FENKQ+BdGAq/wiMYWbwHI6h4FwTDOes0BMKFMHxPNg9qn1dANakYanfuQSs5FJoTpaP1qBswsSGgb9+EeUU0Af0LDH4dBhXlmv3wajuOpPYQFDcEojxtNQ6sn9ZzUsiofjfUWg/iYOt+tJatRtvN95DqZgxNuKTKwLV4Jdyqc8Wz1uCGTLjmDIVDQqewQ8anwpJi6GsYkF4Ey2O/QvsfXKlJIgboAwT07s5AZ0G1TylUIsuhdKMI6vcuQ3PVAqg+9UZ8JvGEywiuNoIwD4IzaV2X+HSa1otgE3+NwJImVkycG0kx8snfyUZJW+QFApeSu+hN9BpIn6n+ZBp9bqDv+C8Fum+8IpzzJNOmR3UhTaGFcC07iAHXmamuZw28C/S/aIt+CcthF7+ToN0EQdhqOFzcBu/Sm/ApvAGX3DzYXIiF9jtWTJf74L6ZC83UfGg8SId2xnloSZKxp+gWjC0J6KSrMK8KhmnlSugtInpkCzaBV78Hl5oPoaLpECrLt+Bi4jfgS7t1q+YDUGsPwj5KDFsLlqD97JuIpmpZmP+TftM1ezjlxsOllM4H3eReDWHwKrOBW84jqMeK5OBTv4Bu6HxxgqU1s/N3MkAHSoH+ioCe+gjoJHB0s8ENLID6/UJo3E+GVlwoNEwY278tXhR50RhmeexzgmM8JXjdF36MHwEoiXn70Csv6gxBm8PiRc6gJFD1HDzFpq1cP0omo5QJZAfqQzH0f6uHZjQgeR4cC/IJZCnUtSkYVPAWBiX2/CdU/S7Ql+9TgtFCTaiP0qAEXA2yRsqwuzECziWZcM4tgv2DSljF7ID+l+JNh9+hY38HuvcYmLOhk5EEnVPfQOmpW+33YGaXhj53E2BWuxvGebOh5cPUX/sWSgXrsa9mB2qaDqCK4C7I2IA3jn8u7tat2g6D034MIbWb0fZgHlr2DscXUhNNuYdkYRPrg/7JiXDMLYBrZS6GNEZgVJM/JjWY4I16G4xr/BCDq2nKjjoAvY+Zpwo7eXBskQK9Swr0lEdAn4a2wk3o/DMNWmn54KYUQIuZsebGQuXFQ42H4kfNk4QckSOkNZ1lGkGAUoInOKkAm2jJsVtH+om9Nj9ytZxNcNdhljXByo+JJXj/i4G2u2xM02YInPJLxFB7VudTPH0ZHkWu0hbPpwHpfnAszoFDVgVsb1fDMmoL9L8S7wTFQE/1AvR33oB+QSp0czKgl34B2iO9uwJCKib5SGaZjbqLPlkhMG1YDr1gQyioSs24vQTDitagsnIL6loCUVu9C2EJK9FjYtsWBNP2Q7hb9A155zdwY5mTeGexo0w32hEcy2F7JQaOqZfgk38KY6rDMKFBiGHNt+iGPgCNYd0/s/sbAb2fgN5JQC9Wq8bkR0AzioOOx3Xo30mGbnY+tNMKoJOQCm03qfnFxRf6E1yUFAqZJcyuZRWuQmB+TWHJcgJfkjPxImcSSIUsXviMx/O9DvqfALrPDjb6nhuBAWkZ5JFKKTYuIqhz4FUdAo9CGwzO7Ra2LjUg0w9OxdlwyKxAXzHQm8lDi4HeAT1WMPSHnYXR7aswKE6Gfl4K9PdfgZ6+uG8XSmMbKyXD/LsEmFduglH2NHA7rA3Hvg+Ve1/gYO4KNFRvQUPLQVRU7MG4yn1dJ4eiULAo3JhW9xsa77+Hml8GY8FQ425uAM5wRRivNoPlTjs4XhoH35oLGFZ/S/wglyDkbWmrrsUAvY+A3kHlSwJ6ihKzCvLnuQyElmIs9LdfhmHxA+jn5kI3jcrRFOjxU6DTbTx9DybsOBh0f034EeYEVyaFD0IYhnQ9y1pTIsiPvU5AnKYkUBL78yKmQhDLgDRPSWtPp/HFkFtHqFCfRBr73wX67qsD+qFsEubCnqKBAZllcCkkT12RjSHVMfApH0bJXfcH+aQGZg6FU1EWeeoK2NwgoMM3Q++zP/fq/Smf2g392ZEwzk2Acfl9GBHURmuSYPyn132oHBizH8B8wjX0SadQI2cWtOZZQbHTdEgRn8XN93EiczFayn5GU3Mg7lJMPab5SEeoCWZZ0TF4Ne/A/ZSPUbXdDz9Qdddrrk/KtcwR7jX34VXDzGCFGFT0GzyLu922x069kdiv145tOu34jlOHBWoz4arUAZQt0LYOhmFcHJ2H6zAsYnZDc2FwKhv60+m9UQrLUJ4hSYQAVhpM1O6jj30EDD33Q6frZyoY8cMVaWZZR560kuB5V9H6iVUas+Py5L1/IHsT2ZldR4nEkMdkUd8Y8tYd43mLIMhYhenDWvgjQSQiGFOkiEv0rEAzK2u8yG10M2WwBWFdb6q9NKDNd6rCOuYD9L2VI/57QMfcEniU5cCnJgG+lR9haAnz4MzT5ZjmA4e8HBqnGtYXamF+nK7bpx0uwHxoqGyE3sKD5HHjYVJ1C6Z5qTD5Ph2G1hnQEV/0LBhxU2E+4yYsbgTCJGsuNBfYQrnjA0CPxDo2CRYJ0xGesgD1ZWvQ3LQbKeSJ54uC0UcUDVVRGExFR/FB2y7cSf4C+Zv9sXSUeQ9P2z2pQdnmBHQsPKqKqFCyWJsM75o1GMw8O/iEhFZs/KK9CD9wRfhCTYTP1dqwnBOHrQYz8IuuH5ZxxI/MLQZH5kfoeu6D4cVQGNecgXHFbRgXZsD4Xg5MjqfDeE0KTBbRDLXsLiwOR8HkxCJoOs+Eavdr08ZBBGdYP7rYzAZILsH3LYUYtgSsAXlYRwLqW0r8Ksl2id4/Onaz47IE+kayUfwddYhsgwkqXRrLgOpHEuyhVF9B7ytoTAL//qNjeFagGfGEi5nvYPEifqOx/ek4p1J/8aKBWC8N6Icy2+oL6zOhECTmw46SuoHZpXBn/pK7/DK8K1bCp3Q0vAv7wqfIBD55OuS9teFVYASPfAFccseThw+E4Ho5LOMqYB6ZCeOdK6H1bleJH2sOOPZradqlC3otDqY5F2GafQmmCZdgFnMBZteEML2yCnprh0CZWVp66gbDuD5Q2uSLUacm43jSB0gq+h55JeuRX7wRqUUbkJL8DS4GTcPqCdZgduZ6XiZjgvcp9fIY3aAH/yY+3KvcMDBjLSXQBXDML4VbaQG8a9PgUxcOzyIneKY/Or6FHDO8q7INY+RiMFJaJijE4i2VeEylej/FDs99TAPH8Dvofv8bDK/vhVHxMRhX0W+vOgXTijiY5UXANGkNnYeRUGN2VrsPNx6XVaQNgRNM03sBgUjeOKJJ/Cr+LNzFsg61YB5/elyKtic0qM031CaZAG0gqJnVEuYBIoI49gy9D6DXrQR3GoU2j3YE+WE2FI9TGBG1FLywnhNbPt1Y/OhY+o5iGqsGNmdLaVxfqZUB+g0Iztwi2AOkNZ3FCzOm30bHeHK9tKYHKfPZMFhlAtM9c2EpjALv93zY3qlE/8xyOOUVUTiSBrfy83CvDIdbRZC4uJSGwzHzd0qgkmEVfRnGW/dC79vPobtkFLRmm0HDpVt43MnrzoOm/dfQeeOf0P3wB+guJogXrIDuhHfAsdOFbKdQ5GkaYQbNNYNht2c8/AOnYNKB6Ri//Q14zRwIuohdPC76pCbWKGFCkx9GNC7B0NZD8CiJh8Odi7A59zud7EuwvU4hVUYZBhUXwqsqA56V0RiUM1Dam36UoiyFuprQhc6fRZuKKhV5+rcLKD2hrPQ+NPsvgNb0j6C9eCG0v/kU2l9/BK0ZM8EdRJQ833noG8Qib6lDkA0lYD6i8GIJlffZ/IhhbJtQjW4TP164EiWWztTnH9T+a4L/MxpjAn02hWWYDAQnefSZzm7Io7zDOpiSzGh3grwPwd3zDccPZdH4phBEkXcWBrD4wlE07qObw5pmBUGsK43T/YPfgmAFWEe5U2EeCXhGcV5nQ3u2KrTf6w+jdTNhtud7mB/ZC4vg43QAwbAMDYLF0e3os+8HGP80D7oLx0F9dD+oj9AGZ4Y85K0Yj/Vs3kQiFgeybFPIySiDzdwAz9O3JzHjPNtYk8gjv948FOOatlGodR0Dk07Bau9n0F8wFBp+luBO1CXeuDD51Q3830PRP7UIzgUlcC0vhHPRSdic6eI53ecT3W0sKyjI2EFRxhzyz3sOO8voBkEUTclYhAyshCwr642PR79diwlbBOEs8vLMFjgbbuelhpeoz5rEDxsNNl/+9ON5RWJOLsXCysQdh5IhWWbzhUmoel6v/l/RxGpZTKgbh3EtEZQMp5AX2ASd2f3AVu7695ky/7nOuc2U/BZSCFIGp+I82F/rfprsVa/+Mk0sZ2F0tTvGNZ+gRO8B7C/HQ92beWine+/IDWDBbJUmbBN/hUNOGRyyStH34vfQeP3ZV4R61atXIu9Kefg1rIB/XRJciwso9nymLXmxbP+wxcCsVAxIKwfv1AZoDH96jN6rXr1SuVeowKsuFINrs+BSXATbc59JLU/XwCwdDMw7B/vUEpgHfQYZ7v9HCNar/2E55ynDpSwYrhXF4uKUeQiY0/Oy3kM555nCITcJgmvp0F30Yo8L9KpXL1X9E2XhkPoVBuYWwbmolKDOhmv+WHiXyGNkgbTRE1pOublXkRycCz+AfUoRzPdsgKJN1w/19KpXf7n6xlnCPikE/SkWdswrozDkNoZUfIWhFTYYWaPy4a6NkgSR2XAZXSOLIWUWcCv7FP1T7sH8wFZwp7ycxz971auXIm4AG+b77MFLEKLv7ULJMy0FefCsPAOv0t0YUrIMg0s+gVfxYrgVbIJLUSzsrl2F2ZZl4L7J/Pdp/956ca969UrEna0O41/HwSJ4F3in42Fz5Trsbt5Bv3u30e9uImyvnoV15GGY/LIA6kOZP1966pZ8r3r1n5eqhwZ0F/aB4ToHGK9zh/FPHjD60RE6H1tDaaA2cdy7mvFfI+BffksPNrEksu0AAAAASUVORK5CYII=",f}),r("Scene/GridImageryProvider",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","../Core/GeographicTilingScheme","../ThirdParty/when"],function(e,t,r,i,n,o,a){"use strict";var s=new e(1,1,1,.4),l=new e(0,1,0,.05),u=new e(0,.5,0,.2),c=function(e){e=t(e,t.EMPTY_OBJECT),this._tilingScheme=r(e.tilingScheme)?e.tilingScheme:new o({ellipsoid:e.ellipsoid}),this._cells=t(e.cells,8),this._color=t(e.color,s),this._glowColor=t(e.glowColor,l),this._glowWidth=t(e.glowWidth,6),this._backgroundColor=t(e.backgroundColor,u),this._errorEvent=new n,this._tileWidth=t(e.tileWidth,256),this._tileHeight=t(e.tileHeight,256),this._canvasSize=t(e.canvasSize,256),this._canvas=this._createGridCanvas(),this._readyPromise=a.resolve(!0)};return i(c.prototype,{proxy:{get:function(){return void 0}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return void 0}},minimumLevel:{get:function(){return void 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return void 0}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return void 0}},hasAlphaChannel:{get:function(){return!0}}}),c.prototype._drawGrid=function(e){for(var t=0,r=this._canvasSize,i=0;i<=this._cells;++i){var n=i/this._cells,o=1+n*(r-1);e.moveTo(o,t),e.lineTo(o,r),e.moveTo(t,o),e.lineTo(r,o)}e.stroke()},c.prototype._createGridCanvas=function(){var e=document.createElement("canvas");e.width=this._canvasSize,e.height=this._canvasSize;var t=0,r=this._canvasSize,i=e.getContext("2d"),n=this._backgroundColor.toCssColorString();i.fillStyle=n,i.fillRect(t,t,r,r);var o=this._glowColor.toCssColorString();i.strokeStyle=o,i.lineWidth=this._glowWidth,i.strokeRect(t,t,r,r),this._drawGrid(i),i.lineWidth=.5*this._glowWidth,i.strokeRect(t,t,r,r),this._drawGrid(i);var a=this._color.toCssColorString();return i.strokeStyle=a,i.lineWidth=2,i.strokeRect(t,t,r,r),i.lineWidth=1,this._drawGrid(i),e},c.prototype.getTileCredits=function(e,t,r){return void 0},c.prototype.requestImage=function(e,t,r){return this._canvas},c.prototype.pickFeatures=function(){return void 0},c}),r("Shaders/ShadowVolumeFS",[],function(){"use strict";return"#extension GL_EXT_frag_depth : enable\nvarying float v_WindowZ;\nvarying vec4 v_color;\nvoid writeDepthClampedToFarPlane()\n{\ngl_FragDepthEXT = min(v_WindowZ * gl_FragCoord.w, 1.0);\n}\nvoid main(void)\n{\ngl_FragColor = v_color;\nwriteDepthClampedToFarPlane();\n}\n"}),r("Shaders/ShadowVolumeVS",[],function(){"use strict";return"attribute vec3 position3DHigh;\nattribute vec3 position3DLow;\nattribute vec4 color;\nvarying float v_WindowZ;\nvarying vec4 v_color;\nvec4 depthClampFarPlane(vec4 vertexInClipCoordinates)\n{\nv_WindowZ = (0.5 * (vertexInClipCoordinates.z / vertexInClipCoordinates.w) + 0.5) * vertexInClipCoordinates.w;\nvertexInClipCoordinates.z = min(vertexInClipCoordinates.z, vertexInClipCoordinates.w);\nreturn vertexInClipCoordinates;\n}\nvoid main()\n{\nv_color = color;\nvec4 position = czm_computePosition();\ngl_Position = depthClampFarPlane(czm_modelViewProjectionRelativeToEye * position);\n}\n"}),r("Scene/StencilFunction",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={NEVER:t.NEVER,LESS:t.LESS,EQUAL:t.EQUAL,LESS_OR_EQUAL:t.LEQUAL,GREATER:t.GREATER,NOT_EQUAL:t.NOTEQUAL,GREATER_OR_EQUAL:t.GEQUAL,ALWAYS:t.ALWAYS};return e(r)}),r("Scene/StencilOperation",["../Core/freezeObject","../Renderer/WebGLConstants"],function(e,t){"use strict";var r={ZERO:t.ZERO,KEEP:t.KEEP,REPLACE:t.REPLACE,INCREMENT:t.INCR,DECREMENT:t.DECR,INVERT:t.INVERT,INCREMENT_WRAP:t.INCR_WRAP,DECREMENT_WRAP:t.DECR_WRAP};return e(r)}),r("Scene/GroundPrimitive",["../Core/BoundingSphere","../Core/Cartesian3","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/GeometryInstance","../Core/isArray","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/OrientedBoundingBox","../Core/Rectangle","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Shaders/ShadowVolumeFS","../Shaders/ShadowVolumeVS","../ThirdParty/when","./BlendingState","./DepthFunction","./Pass","./PerInstanceColorAppearance","./Primitive","./SceneMode","./StencilFunction","./StencilOperation"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I){"use strict";function M(e,t){var r=t.maximumRadius,i=r/Math.cos(.5*e)-r;return B._maxHeight+i}function D(e,t){return B._minHeight}function R(r,i,n){for(var o=n.attributes.position3DHigh.values,a=n.attributes.position3DLow.values,s=o.length,l=i.mapProjection.ellipsoid,u=Number.POSITIVE_INFINITY,c=Number.POSITIVE_INFINITY,h=Number.NEGATIVE_INFINITY,d=Number.NEGATIVE_INFINITY,m=0;s>m;m+=3){var f=t.unpack(o,m,G),v=t.unpack(a,m,W),_=t.add(f,v,H),g=l.cartesianToCartographic(_,q),y=g.latitude,C=g.longitude;u=Math.min(u,y),c=Math.min(c,C),h=Math.max(h,y),d=Math.max(d,C)}var E=j;E.north=h,E.south=u,E.east=d,E.west=c;var S=p.fromRectangle(E,B._maxHeight,B._minOBBHeight,l);if(r._boundingVolumes.push(S),!i.scene3DOnly){var w=i.mapProjection,T=e.fromRectangleWithHeights2D(E,w,B._maxHeight,B._minOBBHeight);t.fromElements(T.center.z,T.center.x,T.center.y,T.center),r._boundingVolumes2D.push(T)}}function O(e,t,r,i){n(e._rsStencilPreloadPass)||(e._rsStencilPreloadPass=v.fromCache(V),e._rsStencilDepthPass=v.fromCache(z),e._rsColorPass=v.fromCache(k),e._rsPickPass=v.fromCache(U))}function N(e,t,r){if(!n(e._sp)){var i=t.context,o=x._modifyShaderPosition(e,C,t.scene3DOnly);o=x._appendShowToShader(e._primitive,o);var a=y,s=e._primitive._attributeLocations;if(e._sp=_.replaceCache({context:i,shaderProgram:e._sp,vertexShaderSource:o,fragmentShaderSource:a,attributeLocations:s}),e._primitive.allowPicking){var l=new g({sources:[a],pickColorQualifier:"varying"});e._spPick=_.replaceCache({context:i,shaderProgram:e._spPick,vertexShaderSource:g.createPickVertexShaderSource(o),fragmentShaderSource:l,attributeLocations:s})}else e._spPick=_.fromCache({context:i,vertexShaderSource:o,fragmentShaderSource:a,attributeLocations:s})}}function L(e,t,r,i,o,a,s){var l=e._primitive,u=3*l._va.length;a.length=u,s.length=u;for(var c=0,h=0;u>h;h+=3){var d=l._va[c],p=a[h];n(p)||(p=a[h]=new f({owner:e,primitiveType:l._primitiveType})),p.vertexArray=d,p.renderState=e._rsStencilPreloadPass,p.shaderProgram=e._sp,p.uniformMap={},p.pass=T.GROUND,p=a[h+1],n(p)||(p=a[h+1]=new f({owner:e,primitiveType:l._primitiveType})),p.vertexArray=d,p.renderState=e._rsStencilDepthPass,p.shaderProgram=e._sp,p.uniformMap={},p.pass=T.GROUND,p=a[h+2],n(p)||(p=a[h+2]=new f({owner:e,primitiveType:l._primitiveType})),p.vertexArray=d,p.renderState=e._rsColorPass,p.shaderProgram=e._sp,p.uniformMap={},p.pass=T.GROUND,s[h]=a[h],s[h+1]=a[h+1],p=s[h+2],n(p)||(p=s[h+2]=new f({owner:e,primitiveType:l._primitiveType -})),p.vertexArray=d,p.renderState=e._rsPickPass,p.shaderProgram=e._spPick,p.uniformMap={},p.pass=T.GROUND}}function F(e,t,r,i,o,a,s,l){var u;t.mode===P.SCENE3D?u=e._boundingVolumes:t.mode!==P.SCENE3D&&n(e._boundingVolumes2D)&&(u=e._boundingVolumes2D);var c=t.commandList,h=t.passes;if(h.render)for(var d=r.length,p=0;d>p;++p)r[p].modelMatrix=o,r[p].boundingVolume=u[Math.floor(p/3)],r[p].cull=a,r[p].debugShowBoundingVolume=s,c.push(r[p]);if(h.pick)for(var m=i.length,f=0;m>f;++f)i[f].modelMatrix=o,i[f].boundingVolume=u[Math.floor(f/3)],i[f].cull=a,c.push(i[f])}var B=function(e){e=i(e,i.EMPTY_OBJECT),this.geometryInstance=e.geometryInstance,this.show=i(e.show,!0),this.debugShowBoundingVolume=i(e.debugShowBoundingVolume,!1),this._sp=void 0,this._spPick=void 0,this._rsStencilPreloadPass=void 0,this._rsStencilDepthPass=void 0,this._rsColorPass=void 0,this._rsPickPass=void 0,this._boundingVolumes=[],this._boundingVolumes2D=[],this._ready=!1,this._readyPromise=E.defer(),this._primitive=void 0;var t=new b({flat:!0});this._primitiveOptions={geometryInstances:void 0,appearance:t,vertexCacheOptimize:i(e.vertexCacheOptimize,!1),interleave:i(e.interleave,!1),releaseGeometryInstances:i(e.releaseGeometryInstances,!0),allowPicking:i(e.allowPicking,!0),asynchronous:i(e.asynchronous,!0),compressVertices:i(e.compressVertices,!0),_createRenderStatesFunction:void 0,_createShaderProgramFunction:void 0,_createCommandsFunction:void 0}};o(B.prototype,{vertexCacheOptimize:{get:function(){return this._primitiveOptions.vertexCacheOptimize}},interleave:{get:function(){return this._primitiveOptions.interleave}},releaseGeometryInstances:{get:function(){return this._primitiveOptions.releaseGeometryInstances}},allowPicking:{get:function(){return this._primitiveOptions.allowPicking}},asynchronous:{get:function(){return this._primitiveOptions.asynchronous}},compressVertices:{get:function(){return this._primitiveOptions.compressVertices}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}}}),B.isSupported=function(e){return e.context.fragmentDepth},B._maxHeight=9e3,B._minHeight=-1e5,B._minOBBHeight=-11500;var V={colorMask:{red:!1,green:!1,blue:!1,alpha:!1},stencilTest:{enabled:!0,frontFunction:A.ALWAYS,frontOperation:{fail:I.KEEP,zFail:I.DECREMENT_WRAP,zPass:I.DECREMENT_WRAP},backFunction:A.ALWAYS,backOperation:{fail:I.KEEP,zFail:I.INCREMENT_WRAP,zPass:I.INCREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!1},depthMask:!1},z={colorMask:{red:!1,green:!1,blue:!1,alpha:!1},stencilTest:{enabled:!0,frontFunction:A.ALWAYS,frontOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.INCREMENT_WRAP},backFunction:A.ALWAYS,backOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!0,func:w.LESS_OR_EQUAL},depthMask:!1},k={stencilTest:{enabled:!0,frontFunction:A.NOT_EQUAL,frontOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},backFunction:A.NOT_EQUAL,backOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!1},depthMask:!1,blending:S.ALPHA_BLEND},U={stencilTest:{enabled:!0,frontFunction:A.NOT_EQUAL,frontOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},backFunction:A.NOT_EQUAL,backOperation:{fail:I.KEEP,zFail:I.KEEP,zPass:I.DECREMENT_WRAP},reference:0,mask:-1},depthTest:{enabled:!1},depthMask:!1},G=new t,W=new t,H=new t,q=new r,j=new m;return B.prototype.update=function(e){var t=e.context;if(t.fragmentDepth&&this.show&&(n(this._primitive)||n(this.geometryInstance))){if(!n(this._primitive)){var r=this.geometryInstance,i=r.geometry,o=i.constructor;n(o)&&n(o.createShadowVolume)&&(r=new l({geometry:o.createShadowVolume(i,D,M),attributes:r.attributes,modelMatrix:d.IDENTITY,id:r.id,pickPrimitive:this}));var a=this._primitiveOptions;a.geometryInstances=r;var s=this;this._primitiveOptions._createBoundingVolumeFunction=function(e,t){R(s,e,t)},this._primitiveOptions._createRenderStatesFunction=function(e,t,r,i){O(s,t)},this._primitiveOptions._createShaderProgramFunction=function(e,t,r){N(s,t)},this._primitiveOptions._createCommandsFunction=function(e,t,r,i,n,o,a){L(s,void 0,void 0,!0,!1,o,a)},this._primitiveOptions._updateAndQueueCommandsFunction=function(e,t,r,i,n,o,a,l){F(s,t,r,i,n,o,a,l)},this._primitive=new x(a),this._primitive.readyPromise.then(function(e){s._ready=!0,s.releaseGeometryInstances&&(s.geometryInstance=void 0);var t=e._error;n(t)?s._readyPromise.reject(t):s._readyPromise.resolve(s)})}this._primitive.debugShowBoundingVolume=this.debugShowBoundingVolume,this._primitive.update(e)}},B.prototype.getGeometryInstanceAttributes=function(e){return this._primitive.getGeometryInstanceAttributes(e)},B.prototype.isDestroyed=function(){return!1},B.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),this._sp=this._sp&&this._sp.destroy(),this._spPick=this._spPick&&this._spPick.destroy(),a(this)},B}),r("Scene/UrlTemplateImageryProvider",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartographic","../Core/combine","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/freezeObject","../Core/GeographicTilingScheme","../Core/loadJson","../Core/loadText","../Core/loadWithXhr","../Core/loadXML","../Core/Math","../Core/Rectangle","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";function S(e,t,r,i){return ne=!1,ae=!1,T(e,e._urlParts,function(n){return n(e,t,r,i)})}function w(e,t,r,i,n,o,a){return ne=!1,ae=!1,le=!1,he=!1,T(e,e._pickFeaturesUrlParts,function(s){return s(e,t,r,i,n,o,a)})}function T(e,t,r){for(var i="",n=0;n<t.length;++n){var o=t[n];i+="string"==typeof o?o:encodeURIComponent(r(o))}var s=e._proxy;return a(s)&&(i=s.getURL(i)),i}function b(e,t){if(!a(e))return void 0;for(var r,i,n=[],o=0,s=Object.keys(t);o<e.length;){r=Number.MAX_VALUE,i=void 0;for(var l=0;l<s.length;++l){var u=e.indexOf(s[l],o);u>=0&&r>u&&(r=u,i=s[l])}a(i)?(r>o&&n.push(e.substring(o,r)),n.push(t[i]),o=r+i.length):(n.push(e.substring(o)),o=e.length)}return n}function x(e,t,r,i){return t}function P(e,t,r,i){return e.tilingScheme.getNumberOfXTilesAtLevel(i)-t-1}function A(e,t,r,i){return r}function I(e,t,r,i){return e.tilingScheme.getNumberOfYTilesAtLevel(i)-r-1}function M(e,t,r,i){var n=e.maximumLevel;return a(n)&&n>i?n-i-1:i}function D(e,t,r,i){return i}function R(e,t,r,i){var n=(t+r+i)%e._subdomains.length;return e._subdomains[n]}function O(e,t,r,i){ne||(e.tilingScheme.tileXYToRectangle(t,r,i,oe),oe.west=v.toDegrees(oe.west),oe.south=v.toDegrees(oe.south),oe.east=v.toDegrees(oe.east),oe.north=v.toDegrees(oe.north),ne=!0)}function N(e,t,r,i){return O(e,t,r,i),oe.west}function L(e,t,r,i){return O(e,t,r,i),oe.south}function F(e,t,r,i){return O(e,t,r,i),oe.east}function B(e,t,r,i){return O(e,t,r,i),oe.north}function V(e,t,r,i){ae||(e.tilingScheme.tileXYToNativeRectangle(t,r,i,se),ae=!0)}function z(e,t,r,i){return V(e,t,r,i),se.west}function k(e,t,r,i){return V(e,t,r,i),se.south}function U(e,t,r,i){return V(e,t,r,i),se.east}function G(e,t,r,i){return V(e,t,r,i),se.north}function W(e,t,r,i){return e.tileWidth}function H(e,t,r,i){return e.tileHeight}function q(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),ue.x}function j(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),ue.y}function Y(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),e.tileWidth-ue.x-1}function X(e,t,r,i,n,o,a){return Z(e,t,r,i,n,o),e.tileHeight-ue.y-1}function Z(e,t,r,i,n,o,a){if(!le){ee(e,t,r,i,n,o);var s=de,l=e.tilingScheme.tileXYToNativeRectangle(t,r,i,ce);ue.x=e.tileWidth*(s.x-l.west)/l.width|0,ue.y=e.tileHeight*(l.north-s.y)/l.height|0,le=!0}}function K(e,t,r,i,n,o,a){return v.toDegrees(n)}function J(e,t,r,i,n,o,a){return v.toDegrees(o)}function Q(e,t,r,i,n,o,a){return ee(e,t,r,i,n,o),de.x}function $(e,t,r,i,n,o,a){return ee(e,t,r,i,n,o),de.y}function ee(e,t,r,i,n,o,a){if(!he){var s;if(e.tilingScheme instanceof h)de.x=v.toDegrees(n),de.y=v.toDegrees(o);else{var l=pe;l.longitude=n,l.latitude=o,s=e.tilingScheme.projection.project(l,de)}he=!0}}function te(e,t,r,i,n,o,a){return a}function re(e,t,r){for(var i=0,n=e.length;n>i;++i){var o=e[i];if(t>=o.startX&&t<=o.endX&&r>=o.startY&&r<=o.endY)return!0}return!1}var ie=function(e){this._url=e.url,this._pickFeaturesUrl=e.pickFeaturesUrl,this._proxy=e.proxy,this._tileDiscardPolicy=e.tileDiscardPolicy,this._getFeatureInfoFormats=e.getFeatureInfoFormats,this._errorEvent=new u,this._subdomains=e.subdomains,Array.isArray(this._subdomains)?this._subdomains=this._subdomains.slice():a(this._subdomains)&&this._subdomains.length>0?this._subdomains=this._subdomains.split(""):this._subdomains=["a","b","c"],this._tileWidth=o(e.tileWidth,256),this._tileHeight=o(e.tileHeight,256),this._minimumLevel=o(e.minimumLevel,0),this._maximumLevel=e.maximumLevel,this._minimumRetrievingLevel=o(e.minimumRetrievingLevel,0),this._maximumRetrievingLevel=o(e.maximumRetrievingLevel,1/0),this._availableLevels=e.availableLevels,this._tilingScheme=o(e.tilingScheme,new y({ellipsoid:e.ellipsoid})),this._rectangle=o(e.rectangle,this._tilingScheme.rectangle),this._rectangle=_.intersection(this._rectangle,this._tilingScheme.rectangle),this._hasAlphaChannel=o(e.hasAlphaChannel,!0);var t=e.credit;if("string"==typeof t&&(t=new n(t)),this._credit=t,this._urlParts=b(this._url,me),this._pickFeaturesUrlParts=b(this._pickFeaturesUrl,fe),this._ready=!e.metadataUrl,this._readyPromise=C.defer(),!this._ready){var r=e.metadataUrl+"layer.json";a(this._proxy)&&(r=this._proxy.getURL(r));var i,s=this,l=function(e){s._availableTiles=e.available;for(var t=0;t<s._availableTiles.length;t++)s._availableLevels&&-1===s._availableLevels.indexOf(t)&&(s._availableTiles[t]=[]);s._ready=!0,s._readyPromise.resolve(!0)},c=function(e){s._ready=!0;var t="An error occurred while accessing "+r+".";i=g.handleError(i,s,s._errorEvent,t,void 0,void 0,void 0,h)},h=function(){var e=d(r);C(e,l,c)};h()}};s(ie.prototype,{url:{get:function(){return this._url}},pickFeaturesUrl:{get:function(){return this._pickFeaturesUrl}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return this._hasAlphaChannel}}}),ie.prototype.getTileCredits=function(e,t,r){return void 0},ie.prototype.getTileDataAvailable=function(e,t,r){var i=this._availableTiles;if(i&&0!==i.length){if(r>=i.length)return!1;var n=i[r],o=this._tilingScheme.getNumberOfYTilesAtLevel(r),a=o-t-1;return re(n,e,a)}return this._availableLevels&&-1===this._availableLevels.indexOf(r)?!1:!0},ie.transparentCanvas=function(){var e=document.createElement("canvas"),t=e.getContext("2d");return t.width=256,t.height=256,t.fillStyle="rgba(255, 0, 0, 0)",t.fillRect(0,0,255,255),e}(),ie.prototype.requestImage=function(e,t,r){if(r<this._minimumRetrievingLevel||r>this._maximumRetrievingLevel||!this.getTileDataAvailable(e,t,r))return ie.transparentCanvas;var i=S(this,e,t,r);return E.loadImage(this,i)},ie.prototype.pickFeatures=function(e,t,r,i,n){function o(e,t){return e.callback(t)}function s(){if(l>=u._getFeatureInfoFormats.length)return C([]);var a=u._getFeatureInfoFormats[l],c=w(u,e,t,r,i,n,a.format);return++l,"json"===a.type?d(c).then(a.callback).otherwise(s):"xml"===a.type?f(c).then(a.callback).otherwise(s):"text"===a.type||"html"===a.type?p(c).then(a.callback).otherwise(s):m({url:c,responseType:a.format}).then(o.bind(void 0,a)).otherwise(s)}if(!a(this._pickFeaturesUrl)||0===this._getFeatureInfoFormats.length)return void 0;var l=0,u=this;return s()};var ne=!1,oe=new _,ae=!1,se=new _,le=!1,ue=new e,ce=new _,he=!1,de=new t,pe=new r,me={"{x}":x,"{y}":A,"{z}":D,"{s}":R,"{reverseX}":P,"{reverseY}":I,"{reverseZ}":M,"{westDegrees}":N,"{southDegrees}":L,"{eastDegrees}":F,"{northDegrees}":B,"{westProjected}":z,"{southProjected}":k,"{eastProjected}":U,"{northProjected}":G,"{width}":W,"{height}":H},fe=i(me,{"{i}":q,"{j}":j,"{reverseI}":Y,"{reverseJ}":X,"{longitudeDegrees}":K,"{latitudeDegrees}":J,"{longitudeProjected}":Q,"{latitudeProjected}":$,"{format}":te});return ie}),r("Scene/MapboxImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/MapboxApi","./UrlTemplateImageryProvider"],function(e,t,r,i,n,o,a){"use strict";var s=/\/$/,l=new e("© Mapbox © OpenStreetMap",void 0,"https://www.mapbox.com/about/maps/"),u=[new e("Improve this map",void 0,"https://www.mapbox.com/map-feedback/")],c=function(i){i=t(i,t.EMPTY_OBJECT);var n=i.mapId,c=t(i.url,"//api.mapbox.com/v4/");this._url=c,this._mapId=n,this._accessToken=o.getAccessToken(i.accessToken);var h=t(i.format,"png");this._format=h.replace(".","");var d=c;if(s.test(c)||(d+="/"),d+=n+"/{z}/{x}/{y}."+this._format,r(this._accessToken)&&(d+="?access_token="+this._accessToken),r(i.credit)){var p=i.credit;"string"==typeof p&&(p=new e(p)),l=p,u.length=0}this._imageryProvider=new a({url:d,proxy:i.proxy,credit:l,ellipsoid:i.ellipsoid,minimumLevel:i.minimumLevel,maximumLevel:i.maximumLevel,rectangle:i.rectangle})};return i(c.prototype,{url:{get:function(){return this._url}},ready:{get:function(){return this._imageryProvider.ready}},readyPromise:{get:function(){return this._imageryProvider.readyPromise}},rectangle:{get:function(){return this._imageryProvider.rectangle}},tileWidth:{get:function(){return this._imageryProvider.tileWidth}},tileHeight:{get:function(){return this._imageryProvider.tileHeight}},maximumLevel:{get:function(){return this._imageryProvider.maximumLevel}},minimumLevel:{get:function(){return this._imageryProvider.minimumLevel}},tilingScheme:{get:function(){return this._imageryProvider.tilingScheme}},tileDiscardPolicy:{get:function(){return this._imageryProvider.tileDiscardPolicy}},errorEvent:{get:function(){return this._imageryProvider.errorEvent}},credit:{get:function(){return this._imageryProvider.credit}},proxy:{get:function(){return this._imageryProvider.proxy}},hasAlphaChannel:{get:function(){return this._imageryProvider.hasAlphaChannel}}}),c.prototype.getTileCredits=function(e,t,r){return u},c.prototype.requestImage=function(e,t,r){return this._imageryProvider.requestImage(e,t,r)},c.prototype.pickFeatures=function(e,t,r,i,n){return this._imageryProvider.pickFeatures(e,t,r,i,n)},c}),r("Scene/Moon",["../Core/buildModuleUrl","../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/Ellipsoid","../Core/IauOrientationAxes","../Core/Matrix3","../Core/Matrix4","../Core/Simon1994PlanetaryPositions","../Core/Transforms","./EllipsoidPrimitive","./Material"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(t){t=r(t,r.EMPTY_OBJECT);var n=t.textureUrl;i(n)||(n=e("Assets/Textures/moonSmall.jpg")),this.show=r(t.show,!0),this.textureUrl=n,this._ellipsoid=r(t.ellipsoid,a.MOON),this.onlySunLighting=r(t.onlySunLighting,!0),this._ellipsoidPrimitive=new d({radii:this.ellipsoid.radii,material:p.fromType(p.ImageType),depthTestEnabled:!1,_owner:this}),this._ellipsoidPrimitive.material.translucent=!1,this._axes=new s};n(m.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}});var f=new l,v=new l,_=new t,g=[];return m.prototype.update=function(e){if(this.show){var t=this._ellipsoidPrimitive;t.material.uniforms.image=this.textureUrl,t.onlySunLighting=this.onlySunLighting;var r=e.time;i(h.computeIcrfToFixedMatrix(r,f))||h.computeTemeToPseudoFixedMatrix(r,f);var n=this._axes.evaluate(r,v);l.transpose(n,n),l.multiply(f,n,n);var o=c.computeMoonPositionInEarthInertialFrame(r,_);l.multiplyByVector(f,o,o),u.fromRotationTranslation(n,o,t.modelMatrix);var a=e.commandList;return e.commandList=g,g.length=0,t.update(e),e.commandList=a,1===g.length?g[0]:void 0}},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return this._ellipsoidPrimitive=this._ellipsoidPrimitive&&this._ellipsoidPrimitive.destroy(),o(this)},m}),r("Scene/NeverTileDiscardPolicy",[],function(){"use strict";var e=function(e){};return e.prototype.isReady=function(){return!0},e.prototype.shouldDiscardImage=function(e){return!1},e}),r("Shaders/AdjustTranslucentFS",[],function(){"use strict";return"#ifdef MRT\n#extension GL_EXT_draw_buffers : enable\n#endif\nuniform vec4 u_bgColor;\nuniform sampler2D u_depthTexture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nif (texture2D(u_depthTexture, v_textureCoordinates).r < 1.0)\n{\n#ifdef MRT\ngl_FragData[0] = u_bgColor;\ngl_FragData[1] = vec4(u_bgColor.a);\n#else\ngl_FragColor = u_bgColor;\n#endif\nreturn;\n}\ndiscard;\n}\n"}),r("Shaders/CompositeOITFS",[],function(){"use strict";return"uniform sampler2D u_opaque;\nuniform sampler2D u_accumulation;\nuniform sampler2D u_revealage;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec4 opaque = texture2D(u_opaque, v_textureCoordinates);\nvec4 accum = texture2D(u_accumulation, v_textureCoordinates);\nfloat r = texture2D(u_revealage, v_textureCoordinates).r;\n#ifdef MRT\nvec4 transparent = vec4(accum.rgb / clamp(r, 1e-4, 5e4), accum.a);\n#else\nvec4 transparent = vec4(accum.rgb / clamp(accum.a, 1e-4, 5e4), r);\n#endif\ngl_FragColor = (1.0 - transparent.a) * transparent + transparent.a * opaque;\n}\n"}),r("Scene/OIT",["../Core/Color","../Core/defined","../Core/destroyObject","../Core/PixelFormat","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/Texture","../Renderer/WebGLConstants","../Shaders/AdjustTranslucentFS","../Shaders/CompositeOITFS","./BlendEquation","./BlendFunction"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(e){e._accumulationTexture=e._accumulationTexture&&!e._accumulationTexture.isDestroyed()&&e._accumulationTexture.destroy(),e._revealageTexture=e._revealageTexture&&!e._revealageTexture.isDestroyed()&&e._revealageTexture.destroy()}function _(e){e._translucentFBO=e._translucentFBO&&!e._translucentFBO.isDestroyed()&&e._translucentFBO.destroy(),e._alphaFBO=e._alphaFBO&&!e._alphaFBO.isDestroyed()&&e._alphaFBO.destroy(),e._adjustTranslucentFBO=e._adjustTranslucentFBO&&!e._adjustTranslucentFBO.isDestroyed()&&e._adjustTranslucentFBO.destroy(),e._adjustAlphaFBO=e._adjustAlphaFBO&&!e._adjustAlphaFBO.isDestroyed()&&e._adjustAlphaFBO.destroy()}function g(e){v(e),_(e)}function y(e,t,r,n){v(e),e._accumulationTexture=new c({context:t,width:r,height:n,pixelFormat:i.RGBA,pixelDatatype:a.FLOAT}),e._revealageTexture=new c({context:t,width:r,height:n,pixelFormat:i.RGBA,pixelDatatype:a.FLOAT})}function C(e,t){_(e);var r=h.FRAMEBUFFER_COMPLETE,i=!0;if(e._translucentMRTSupport&&(e._translucentFBO=new o({context:t,colorTextures:[e._accumulationTexture,e._revealageTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._adjustTranslucentFBO=new o({context:t,colorTextures:[e._accumulationTexture,e._revealageTexture],destroyAttachments:!1}),(e._translucentFBO.status!==r||e._adjustTranslucentFBO.status!==r)&&(_(e),e._translucentMRTSupport=!1)),!e._translucentMRTSupport){e._translucentFBO=new o({context:t,colorTextures:[e._accumulationTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._alphaFBO=new o({context:t,colorTextures:[e._revealageTexture],depthStencilTexture:e._depthStencilTexture,destroyAttachments:!1}),e._adjustTranslucentFBO=new o({context:t,colorTextures:[e._accumulationTexture],destroyAttachments:!1}),e._adjustAlphaFBO=new o({context:t,colorTextures:[e._revealageTexture],destroyAttachments:!1});var n=e._translucentFBO.status===r,a=e._alphaFBO.status===r,s=e._adjustTranslucentFBO.status===r,l=e._adjustAlphaFBO.status===r;n&&a&&s&&l||(g(e),e._translucentMultipassSupport=!1,i=!1)}return i}function E(e,r,i,n){var o=i[n.id];if(!t(o)){var a=s.getState(n);a.depthMask=!1,a.blending=r,o=s.fromCache(a),i[n.id]=o}return o}function S(e,t,r){return E(t,R,e._translucentRenderStateCache,r)}function w(e,t,r){return E(t,O,e._translucentRenderStateCache,r)}function T(e,t,r){return E(t,N,e._alphaRenderStateCache,r)}function b(e,r,i,n){var o=r.id,a=i[o];if(!t(a)){var s=r._attributeLocations,c=r.fragmentShaderSource.clone();c.sources=c.sources.map(function(e){return e=u.replaceMain(e,"czm_translucent_main"),e=e.replace(/gl_FragColor/g,"czm_gl_FragColor"),e=e.replace(/\bdiscard\b/g,"czm_discard = true"),e=e.replace(/czm_phong/g,"czm_translucentPhong")}),c.sources.splice(0,0,(-1!==n.indexOf("gl_FragData")?"#extension GL_EXT_draw_buffers : enable \n":"")+"vec4 czm_gl_FragColor;\nbool czm_discard = false;\n"),c.sources.push("void main()\n{\n czm_translucent_main();\n if (czm_discard)\n {\n discard;\n }\n"+n+"}\n"),a=l.fromCache({context:e,vertexShaderSource:r.vertexShaderSource,fragmentShaderSource:c,attributeLocations:s}),i[o]=a}return a}function x(e,t,r){return b(t,r,e._translucentShaderCache,L)}function P(e,t,r){return b(t,r,e._translucentShaderCache,F)}function A(e,t,r){return b(t,r,e._alphaShaderCache,B)}function I(e,r,i,n,o){var a,s,l,u,c=r.context,h=n.framebuffer,d=o.length;n.framebuffer=e._adjustTranslucentFBO,e._adjustTranslucentCommand.execute(c,n),n.framebuffer=e._adjustAlphaFBO,e._adjustAlphaCommand.execute(c,n);var p=e._opaqueFBO;for(n.framebuffer=e._translucentFBO,u=0;d>u;++u)a=o[u],t(a.oit)&&a.shaderProgram.id===a.oit.shaderProgramId||(a.oit={colorRenderState:w(e,c,a.renderState),alphaRenderState:T(e,c,a.renderState),colorShaderProgram:P(e,c,a.shaderProgram),alphaShaderProgram:A(e,c,a.shaderProgram),shaderProgramId:a.shaderProgram.id}),s=a.oit.colorRenderState,l=a.oit.colorShaderProgram,i(a,r,c,n,s,l,p);for(n.framebuffer=e._alphaFBO,u=0;d>u;++u)a=o[u],s=a.oit.alphaRenderState,l=a.oit.alphaShaderProgram,i(a,r,c,n,s,l,p);n.framebuffer=h}function M(e,r,i,n,o){var a=r.context,s=n.framebuffer,l=o.length;n.framebuffer=e._adjustTranslucentFBO,e._adjustTranslucentCommand.execute(a,n);var u=e._opaqueFBO;n.framebuffer=e._translucentFBO;for(var c=0;l>c;++c){var h=o[c];t(h.oit)&&h.shaderProgram.id===h.oit.shaderProgramId||(h.oit={translucentRenderState:S(e,a,h.renderState),translucentShaderProgram:x(e,a,h.shaderProgram),shaderProgramId:h.shaderProgram.id});var d=h.oit.translucentRenderState,p=h.oit.translucentShaderProgram;i(h,r,a,n,d,p,u)}n.framebuffer=s}var D=function(t){this._translucentMultipassSupport=!1,this._translucentMRTSupport=!1;var r=t.floatingPointTexture&&t.depthTexture;this._translucentMRTSupport=t.drawBuffers&&r,this._translucentMultipassSupport=!this._translucentMRTSupport&&r,this._opaqueFBO=void 0,this._opaqueTexture=void 0,this._depthStencilTexture=void 0,this._accumulationTexture=void 0,this._translucentFBO=void 0,this._alphaFBO=void 0,this._adjustTranslucentFBO=void 0,this._adjustAlphaFBO=void 0,this._opaqueClearCommand=new n({color:new e(0,0,0,0),owner:this}),this._translucentMRTClearCommand=new n({color:new e(0,0,0,1),owner:this}),this._translucentMultipassClearCommand=new n({color:new e(0,0,0,0),owner:this}),this._alphaClearCommand=new n({color:new e(1,1,1,1),owner:this}),this._translucentRenderStateCache={},this._alphaRenderStateCache={},this._translucentShaderCache={},this._alphaShaderCache={},this._compositeCommand=void 0,this._adjustTranslucentCommand=void 0,this._adjustAlphaCommand=void 0};D.prototype.update=function(e,r){if(this.isSupported()){this._opaqueFBO=r,this._opaqueTexture=r.getColorTexture(0),this._depthStencilTexture=r.depthStencilTexture;var i=this._opaqueTexture.width,n=this._opaqueTexture.height,o=this._accumulationTexture,a=!t(o)||o.width!==i||o.height!==n;if(a&&y(this,e,i,n),t(this._translucentFBO)&&!a||C(this,e)){var l,c,h=this;t(this._compositeCommand)||(l=new u({sources:[p]}),this._translucentMRTSupport&&l.defines.push("MRT"),c={u_opaque:function(){return h._opaqueTexture},u_accumulation:function(){return h._accumulationTexture},u_revealage:function(){return h._revealageTexture}},this._compositeCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this})),t(this._adjustTranslucentCommand)||(this._translucentMRTSupport?(l=new u({defines:["MRT"],sources:[d]}),c={u_bgColor:function(){return h._translucentMRTClearCommand.color},u_depthTexture:function(){return h._depthStencilTexture}},this._adjustTranslucentCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this})):this._translucentMultipassSupport&&(l=new u({sources:[d]}),c={u_bgColor:function(){return h._translucentMultipassClearCommand.color},u_depthTexture:function(){return h._depthStencilTexture}},this._adjustTranslucentCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this}),c={u_bgColor:function(){return h._alphaClearCommand.color},u_depthTexture:function(){return h._depthStencilTexture}},this._adjustAlphaCommand=e.createViewportQuadCommand(l,{renderState:s.fromCache(),uniformMap:c,owner:this})))}}};var R={enabled:!0,color:new e(0,0,0,0),equationRgb:m.ADD,equationAlpha:m.ADD,functionSourceRgb:f.ONE,functionDestinationRgb:f.ONE,functionSourceAlpha:f.ZERO,functionDestinationAlpha:f.ONE_MINUS_SOURCE_ALPHA},O={enabled:!0,color:new e(0,0,0,0),equationRgb:m.ADD,equationAlpha:m.ADD,functionSourceRgb:f.ONE,functionDestinationRgb:f.ONE,functionSourceAlpha:f.ONE,functionDestinationAlpha:f.ONE},N={enabled:!0,color:new e(0,0,0,0),equationRgb:m.ADD,equationAlpha:m.ADD,functionSourceRgb:f.ZERO,functionDestinationRgb:f.ONE_MINUS_SOURCE_ALPHA,functionSourceAlpha:f.ZERO,functionDestinationAlpha:f.ONE_MINUS_SOURCE_ALPHA},L=" vec3 Ci = czm_gl_FragColor.rgb * czm_gl_FragColor.a;\n float ai = czm_gl_FragColor.a;\n float wzi = czm_alphaWeight(ai);\n gl_FragData[0] = vec4(Ci * wzi, ai);\n gl_FragData[1] = vec4(ai * wzi);\n",F=" vec3 Ci = czm_gl_FragColor.rgb * czm_gl_FragColor.a;\n float ai = czm_gl_FragColor.a;\n float wzi = czm_alphaWeight(ai);\n gl_FragColor = vec4(Ci, ai) * wzi;\n",B=" float ai = czm_gl_FragColor.a;\n gl_FragColor = vec4(ai);\n";return D.prototype.executeCommands=function(e,t,r,i){return this._translucentMRTSupport?void M(this,e,t,r,i):void I(this,e,t,r,i)},D.prototype.execute=function(e,t){this._compositeCommand.execute(e,t)},D.prototype.clear=function(t,r,i){var n=r.framebuffer;r.framebuffer=this._opaqueFBO,e.clone(i,this._opaqueClearCommand.color),this._opaqueClearCommand.execute(t,r),r.framebuffer=this._translucentFBO;var o=this._translucentMRTSupport?this._translucentMRTClearCommand:this._translucentMultipassClearCommand;o.execute(t,r),this._translucentMultipassSupport&&(r.framebuffer=this._alphaFBO,this._alphaClearCommand.execute(t,r)),r.framebuffer=n},D.prototype.isSupported=function(){return this._translucentMRTSupport||this._translucentMultipassSupport},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){g(this),t(this._compositeCommand)&&(this._compositeCommand.shaderProgram=this._compositeCommand.shaderProgram&&this._compositeCommand.shaderProgram.destroy()),t(this._adjustTranslucentCommand)&&(this._adjustTranslucentCommand.shaderProgram=this._adjustTranslucentCommand.shaderProgram&&this._adjustTranslucentCommand.shaderProgram.destroy()),t(this._adjustAlphaCommand)&&(this._adjustAlphaCommand.shaderProgram=this._adjustAlphaCommand.shaderProgram&&this._adjustAlphaCommand.shaderProgram.destroy());var e,i=this._translucentShaderCache;for(e in i)i.hasOwnProperty(e)&&t(i[e])&&i[e].destroy();this._translucentShaderCache={},i=this._alphaShaderCache;for(e in i)i.hasOwnProperty(e)&&t(i[e])&&i[e].destroy();return this._alphaShaderCache={},r(this)},D}),r("Scene/OpenStreetMapImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/Rectangle","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e,t,i,n){var o=e._url+n+"/"+t+"/"+i+"."+e._fileExtension,a=e._proxy;return r(a)&&(o=a.getURL(o)),o}var h=/\/$/,d=new e("MapQuest, Open Street Map and contributors, CC-BY-SA"),p=function(r){r=t(r,{});var i=t(r.url,"//a.tile.openstreetmap.org/");h.test(i)||(i+="/"),this._url=i,this._fileExtension=t(r.fileExtension,"png"),this._proxy=r.proxy,this._tileDiscardPolicy=r.tileDiscardPolicy,this._tilingScheme=new s({ellipsoid:r.ellipsoid}),this._tileWidth=256,this._tileHeight=256,this._minimumLevel=t(r.minimumLevel,0),this._maximumLevel=r.maximumLevel,this._rectangle=t(r.rectangle,this._tilingScheme.rectangle);var u=this._tilingScheme.positionToTileXY(a.southwest(this._rectangle),this._minimumLevel),c=this._tilingScheme.positionToTileXY(a.northeast(this._rectangle),this._minimumLevel),p=(Math.abs(c.x-u.x)+1)*(Math.abs(c.y-u.y)+1);if(p>4)throw new n("The imagery provider's rectangle and minimumLevel indicate that there are "+p+" tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.");this._errorEvent=new o,this._ready=!0,this._readyPromise=l.resolve(!0);var m=t(r.credit,d);"string"==typeof m&&(m=new e(m)),this._credit=m};return i(p.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),p.prototype.getTileCredits=function(e,t,r){return void 0},p.prototype.requestImage=function(e,t,r){var i=c(this,e,t,r);return u.loadImage(this,i)},p.prototype.pickFeatures=function(){return void 0},p}),r("Scene/OrthographicFrustum",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/Matrix4","./CullingVolume"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(e){(e.top!==e._top||e.bottom!==e._bottom||e.left!==e._left||e.right!==e._right||e.near!==e._near||e.far!==e._far)&&(e._left=e.left,e._right=e.right,e._top=e.top,e._bottom=e.bottom,e._near=e.near,e._far=e.far,e._orthographicMatrix=s.computeOrthographicOffCenter(e.left,e.right,e.bottom,e.top,e.near,e.far,e._orthographicMatrix))}var c=function(){this.left=void 0,this._left=void 0,this.right=void 0,this._right=void 0,this.top=void 0,this._top=void 0,this.bottom=void 0,this._bottom=void 0,this.near=1,this._near=this.near,this.far=5e8,this._far=this.far,this._cullingVolume=new l,this._orthographicMatrix=new s};n(c.prototype,{projectionMatrix:{get:function(){return u(this),this._orthographicMatrix}}});var h=new t,d=new t,p=new t,m=new t;return c.prototype.computeCullingVolume=function(e,n,o){var a=this._cullingVolume.planes,s=this.top,l=this.bottom,u=this.right,c=this.left,f=this.near,v=this.far,_=t.cross(n,o,h),g=d;t.multiplyByScalar(n,f,g),t.add(e,g,g);var y=p;t.multiplyByScalar(_,c,y),t.add(g,y,y);var C=a[0];return i(C)||(C=a[0]=new r),C.x=_.x,C.y=_.y,C.z=_.z,C.w=-t.dot(_,y),t.multiplyByScalar(_,u,y),t.add(g,y,y),C=a[1],i(C)||(C=a[1]=new r),C.x=-_.x,C.y=-_.y,C.z=-_.z,C.w=-t.dot(t.negate(_,m),y),t.multiplyByScalar(o,l,y), -t.add(g,y,y),C=a[2],i(C)||(C=a[2]=new r),C.x=o.x,C.y=o.y,C.z=o.z,C.w=-t.dot(o,y),t.multiplyByScalar(o,s,y),t.add(g,y,y),C=a[3],i(C)||(C=a[3]=new r),C.x=-o.x,C.y=-o.y,C.z=-o.z,C.w=-t.dot(t.negate(o,m),y),C=a[4],i(C)||(C=a[4]=new r),C.x=n.x,C.y=n.y,C.z=n.z,C.w=-t.dot(n,g),t.multiplyByScalar(n,v,y),t.add(e,y,y),C=a[5],i(C)||(C=a[5]=new r),C.x=-n.x,C.y=-n.y,C.z=-n.z,C.w=-t.dot(t.negate(n,m),y),this._cullingVolume},c.prototype.getPixelSize=function(t,r,n){o("OrthographicFrustum","getPixelSize is deprecated. Use getPixelDimensions instead."),u(this);var a=this.right-this.left,s=this.top-this.bottom,l=a/t.x,c=s/t.y;return i(n)?(n.x=l,n.y=c,n):new e(l,c)},c.prototype.getPixelDimensions=function(e,t,r,i){u(this);var n=this.right-this.left,o=this.top-this.bottom,a=n/e,s=o/t;return i.x=a,i.y=s,i},c.prototype.clone=function(e){return i(e)||(e=new c),e.left=this.left,e.right=this.right,e.top=this.top,e.bottom=this.bottom,e.near=this.near,e.far=this.far,e._left=void 0,e._right=void 0,e._top=void 0,e._bottom=void 0,e._near=void 0,e._far=void 0,e},c.prototype.equals=function(e){return i(e)&&this.right===e.right&&this.left===e.left&&this.top===e.top&&this.bottom===e.bottom&&this.near===e.near&&this.far===e.far},c}),r("Widgets/getElement",["../Core/DeveloperError"],function(e){"use strict";var t=function(e){if("string"==typeof e){var t=document.getElementById(e);e=t}return e};return t}),r("Scene/PerformanceDisplay",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/getTimestamp","../Widgets/getElement"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){e=t(e,t.EMPTY_OBJECT);var i=a(e.container);if(!r(i))throw new n("container is required");this._container=i;var o=document.createElement("div");o.className="cesium-performanceDisplay";var s=document.createElement("div");s.className="cesium-performanceDisplay-fps",this._fpsText=document.createTextNode(""),s.appendChild(this._fpsText);var l=document.createElement("div");l.className="cesium-performanceDisplay-ms",this._msText=document.createTextNode(""),l.appendChild(this._msText),o.appendChild(l),o.appendChild(s),this._container.appendChild(o),this._lastFpsSampleTime=void 0,this._frameCount=0,this._time=void 0,this._fps=0,this._frameTime=0};return s.prototype.update=function(){if(!r(this._time))return this._lastFpsSampleTime=o(),void(this._time=o());var e=this._time,t=o();this._time=t;var i=t-e;this._frameCount++;var n=this._fps,a=t-this._lastFpsSampleTime;a>1e3&&(n=1e3*this._frameCount/a|0,this._lastFpsSampleTime=t,this._frameCount=0),n!==this._fps&&(this._fpsText.nodeValue=n+" FPS",this._fps=n),i!==this._frameTime&&(this._msText.nodeValue=i.toFixed(2)+" MS",this._frameTime=i)},s.prototype.destroy=function(){return i(this)},s}),r("Scene/PickDepth",["../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/PixelFormat","../Renderer/Framebuffer","../Renderer/PixelDatatype","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/PassThrough"],function(e,t,r,i,n,o,a,s,l){"use strict";function u(t,r,i){if(!e(t._debugPickDepthViewportCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n float n_range = czm_depthRange.near;\n float f_range = czm_depthRange.far;\n float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n}\n";t._debugPickDepthViewportCommand=r.createViewportQuadCommand(n,{uniformMap:{u_texture:function(){return t._depthTexture}},owner:t})}t._debugPickDepthViewportCommand.execute(r,i)}function c(e){e._depthTexture=e._depthTexture&&!e._depthTexture.isDestroyed()&&e._depthTexture.destroy()}function h(e){e.framebuffer=e.framebuffer&&!e.framebuffer.isDestroyed()&&e.framebuffer.destroy()}function d(e,t,r,n){e._depthTexture=new s({context:t,width:r,height:n,pixelFormat:i.RGBA,pixelDatatype:o.UNSIGNED_BYTE})}function p(e,t,r,i){c(e),h(e),d(e,t,r,i),e.framebuffer=new n({context:t,colorTextures:[e._depthTexture],destroyAttachments:!1})}function m(t,r,i){var n=i.width,o=i.height,a=t._depthTexture,s=!e(a)||a.width!==n||a.height!==o;(!e(t.framebuffer)||s)&&p(t,r,n,o)}function f(t,r,i){if(!e(t._copyDepthCommand)){var n="uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\n gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n}\n";t._copyDepthCommand=r.createViewportQuadCommand(n,{renderState:a.fromCache(),uniformMap:{u_texture:function(){return t._textureToCopy}},owner:t})}t._textureToCopy=i,t._copyDepthCommand.framebuffer=t.framebuffer}var v=function(){this.framebuffer=void 0,this._depthTexture=void 0,this._textureToCopy=void 0,this._copyDepthCommand=void 0,this._debugPickDepthViewportCommand=void 0};return v.prototype.executeDebugPickDepth=function(e,t){u(this,e,t)},v.prototype.update=function(e,t){m(this,e,t),f(this,e,t)},v.prototype.executeCopyDepth=function(e,t){this._copyDepthCommand.execute(e,t)},v.prototype.isDestroyed=function(){return!1},v.prototype.destroy=function(){return c(this),h(this),this._copyDepthCommand.shaderProgram=e(this._copyDepthCommand.shaderProgram)&&this._copyDepthCommand.shaderProgram.destroy(),r(this)},v}),r("Scene/Polygon",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/GeometryInstance","../Core/Math","../Core/PolygonGeometry","./EllipsoidSurfaceAppearance","./Material","./Primitive"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(i){n("Polygon","Polygon has been deprecated. Use PolygonGeometry or Entity.polygon instead."),i=t(i,t.EMPTY_OBJECT),this.ellipsoid=t(i.ellipsoid,s.WGS84),this._ellipsoid=void 0,this.granularity=t(i.granularity,u.RADIANS_PER_DEGREE),this._granularity=void 0,this.height=t(i.height,0),this._height=void 0,this.textureRotationAngle=t(i.textureRotationAngle,0),this._textureRotationAngle=void 0,this.show=t(i.show,!0);var o=d.fromType(d.ColorType,{color:new e(1,1,0,.5)});this.material=t(i.material,o),this.id=i.id,this._id=void 0,this.asynchronous=t(i.asynchronous,!0),this.debugShowBoundingVolume=t(i.debugShowBoundingVolume,!1),this._positions=void 0,this._polygonHierarchy=void 0,this._createPrimitive=!1,this._primitive=void 0,r(i.positions)?this.positions=i.positions:r(i.polygonHierarchy)&&this.configureFromPolygonHierarchy(i.polygonHierarchy)};return i(m.prototype,{positions:{get:function(){return this._positions},set:function(e){this._positions=e,this._polygonHierarchy=void 0,this._createPrimitive=!0}}}),m.prototype.configureFromPolygonHierarchy=function(e){this._positions=void 0,this._polygonHierarchy=e,this._createPrimitive=!0},m.prototype.update=function(e){if(this.show&&(this._createPrimitive||r(this._primitive))){if(this._createPrimitive||this._ellipsoid!==this.ellipsoid||this._granularity!==this.granularity||this._height!==this.height||this._textureRotationAngle!==this.textureRotationAngle||this._id!==this.id){if(this._createPrimitive=!1,this._ellipsoid=this.ellipsoid,this._granularity=this.granularity,this._height=this.height,this._textureRotationAngle=this.textureRotationAngle,this._id=this.id,this._primitive=this._primitive&&this._primitive.destroy(),!r(this._positions)&&!r(this._polygonHierarchy))return;var t;t=new l(r(this._positions)?{geometry:c.fromPositions({positions:this._positions,height:this.height,vertexFormat:h.VERTEX_FORMAT,stRotation:this.textureRotationAngle,ellipsoid:this.ellipsoid,granularity:this.granularity}),id:this.id,pickPrimitive:this}:{geometry:new c({polygonHierarchy:this._polygonHierarchy,height:this.height,vertexFormat:h.VERTEX_FORMAT,stRotation:this.textureRotationAngle,ellipsoid:this.ellipsoid,granularity:this.granularity}),id:this.id,pickPrimitive:this}),this._primitive=new p({geometryInstances:t,appearance:new h({aboveGround:this.height>0}),asynchronous:this.asynchronous})}var i=this._primitive;i.debugShowBoundingVolume=this.debugShowBoundingVolume,i.appearance.material=this.material,i.update(e)}},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),o(this)},m}),r("Scene/PrimitiveCollection",["../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError"],function(e,t,r,i,n,o){"use strict";function a(e,t){return e._primitives.indexOf(t)}var s=function(r){r=t(r,t.EMPTY_OBJECT),this._primitives=[],this._guid=e(),this.show=t(r.show,!0),this.destroyPrimitives=t(r.destroyPrimitives,!0)};return i(s.prototype,{length:{get:function(){return this._primitives.length}}}),s.prototype.add=function(e){var t=e._external=e._external||{},r=t._composites=t._composites||{};return r[this._guid]={collection:this},this._primitives.push(e),e},s.prototype.remove=function(e){if(this.contains(e)){var t=this._primitives.indexOf(e);if(-1!==t)return this._primitives.splice(t,1),delete e._external._composites[this._guid],this.destroyPrimitives&&e.destroy(),!0}return!1},s.prototype.removeAndDestroy=function(e){var t=this.remove(e);return t&&!this.destroyPrimitives&&e.destroy(),t},s.prototype.removeAll=function(){if(this.destroyPrimitives)for(var e=this._primitives,t=e.length,r=0;t>r;++r)e[r].destroy();this._primitives=[]},s.prototype.contains=function(e){return!!(r(e)&&e._external&&e._external._composites&&e._external._composites[this._guid])},s.prototype.raise=function(e){if(r(e)){var t=a(this,e),i=this._primitives;if(t!==i.length-1){var n=i[t];i[t]=i[t+1],i[t+1]=n}}},s.prototype.raiseToTop=function(e){if(r(e)){var t=a(this,e),i=this._primitives;t!==i.length-1&&(i.splice(t,1),i.push(e))}},s.prototype.lower=function(e){if(r(e)){var t=a(this,e),i=this._primitives;if(0!==t){var n=i[t];i[t]=i[t-1],i[t-1]=n}}},s.prototype.lowerToBottom=function(e){if(r(e)){var t=a(this,e),i=this._primitives;0!==t&&(i.splice(t,1),i.unshift(e))}},s.prototype.get=function(e){return this._primitives[e]},s.prototype.update=function(e){if(this.show)for(var t=this._primitives,r=0;r<t.length;++r)t[r].update(e)},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this.removeAll(),n(this)},s}),r("Scene/QuadtreeTileProvider",["../Core/defineProperties","../Core/DeveloperError"],function(e,t){"use strict";var r=function(){t.throwInstantiationError()};return r.computeDefaultLevelZeroMaximumGeometricError=function(e){return 2*e.ellipsoid.maximumRadius*Math.PI*.25/(65*e.getNumberOfXTilesAtLevel(0))},e(r.prototype,{quadtree:{get:t.throwInstantiationError,set:t.throwInstantiationError},ready:{get:t.throwInstantiationError},tilingScheme:{get:t.throwInstantiationError},errorEvent:{get:t.throwInstantiationError}}),r.prototype.beginUpdate=t.throwInstantiationError,r.prototype.endUpdate=t.throwInstantiationError,r.prototype.getLevelMaximumGeometricError=t.throwInstantiationError,r.prototype.loadTile=t.throwInstantiationError,r.prototype.computeTileVisibility=t.throwInstantiationError,r.prototype.showTileThisFrame=t.throwInstantiationError,r.prototype.computeDistanceToTile=t.throwInstantiationError,r.prototype.isDestroyed=t.throwInstantiationError,r.prototype.destroy=t.throwInstantiationError,r}),r("Scene/RectanglePrimitive",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/deprecationWarning","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/GeometryInstance","../Core/Math","../Core/Rectangle","../Core/RectangleGeometry","./EllipsoidSurfaceAppearance","./Material","./Primitive"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";var m=function(r){i("RectanglePrimitive","RectanglePrimitive has been deprecated. Use RectangleGeometry or Entity.rectangle instead."),r=t(r,t.EMPTY_OBJECT),this.ellipsoid=t(r.ellipsoid,a.WGS84),this._ellipsoid=void 0,this.rectangle=u.clone(r.rectangle),this._rectangle=void 0,this.granularity=t(r.granularity,l.RADIANS_PER_DEGREE),this._granularity=void 0,this.height=t(r.height,0),this._height=void 0,this.rotation=t(r.rotation,0),this._rotation=void 0,this.textureRotationAngle=t(r.textureRotationAngle,0),this._textureRotationAngle=void 0,this.show=t(r.show,!0);var n=d.fromType(d.ColorType,{color:new e(1,1,0,.5)});this.material=t(r.material,n),this.id=r.id,this._id=void 0,this.asynchronous=t(r.asynchronous,!0),this.debugShowBoundingVolume=t(r.debugShowBoundingVolume,!1),this._primitive=void 0};return m.prototype.update=function(e){if(this.show&&r(this.rectangle)){if(!u.equals(this._rectangle,this.rectangle)||this._ellipsoid!==this.ellipsoid||this._granularity!==this.granularity||this._height!==this.height||this._rotation!==this.rotation||this._textureRotationAngle!==this.textureRotationAngle||this._id!==this.id){this._rectangle=u.clone(this.rectangle,this._rectangle),this._ellipsoid=this.ellipsoid,this._granularity=this.granularity,this._height=this.height,this._rotation=this.rotation,this._textureRotationAngle=this.textureRotationAngle,this._id=this.id;var t=new s({geometry:new c({rectangle:this.rectangle,vertexFormat:h.VERTEX_FORMAT,ellipsoid:this.ellipsoid,granularity:this.granularity,height:this.height,rotation:this.rotation,stRotation:this.textureRotationAngle}),id:this.id,pickPrimitive:this});r(this._primitive)&&this._primitive.destroy(),this._primitive=new p({geometryInstances:t,appearance:new h({aboveGround:this.height>0}),asynchronous:this.asynchronous})}var i=this._primitive;i.appearance.material=this.material,i.debugShowBoundingVolume=this.debugShowBoundingVolume,i.update(e)}},m.prototype.isDestroyed=function(){return!1},m.prototype.destroy=function(){return this._primitive=this._primitive&&this._primitive.destroy(),n(this)},m}),r("Scene/SceneTransitioner",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/EasingFunction","../Core/Ellipsoid","../Core/Math","../Core/Matrix4","../Core/ScreenSpaceEventHandler","../Core/ScreenSpaceEventType","./Camera","./OrthographicFrustum","./PerspectiveFrustum","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m){"use strict";function f(e,t){if(e._scene.completeMorphOnUserInput){e._morphHandler=new u(e._scene.canvas,!1);var r=function(){e._morphCancelled=!0,t(e)};e._completeMorph=r,e._morphHandler.setInputAction(r,c.LEFT_DOWN),e._morphHandler.setInputAction(r,c.MIDDLE_DOWN),e._morphHandler.setInputAction(r,c.RIGHT_DOWN),e._morphHandler.setInputAction(r,c.WHEEL)}}function v(e){for(var t=e._currentTweens,r=0;r<t.length;++r)t[r].cancelTween();e._currentTweens.length=0,e._morphHandler=e._morphHandler&&e._morphHandler.destroy()}function _(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY);var u=s.position,c=s.direction,h=s.up,d=e.clone(t._camera2D.position),p=e.clone(t._camera2D.direction),m=e.clone(t._camera2D.up),f=function(t){s.position=y(u,d,t.time),s.direction=y(c,p,t.time),s.up=y(h,m,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)},v=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:f});t._currentTweens.push(v),x(t,a,0,1,r,n)}function g(e,t,r,i){t*=.5;var n=e._scene.camera;n._setTransform(l.IDENTITY),w(e,t,r,function(){n.frustum=e._cameraCV.frustum.clone(),_(e,t,r,i)})}function y(t,r,i){return e.lerp(t,r,i,new e)}function C(t,r,i){var n=t._scene,a=n.camera,l=a.position,u=a.frustum.fov,c=.5*s.RADIANS_PER_DEGREE,h=e.magnitude(l)*Math.tan(.5*u);a.frustum.far=h/Math.tan(.5*c)+1e7;var d=function(t){a.frustum.fov=s.lerp(u,c,t.time);var r=h/Math.tan(.5*a.frustum.fov),i=new e;a.position=e.multiplyByScalar(e.normalize(a.position,i),r,i)},p=n.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:d,complete:function(){a.frustum=t._camera2D.frustum.clone(),i(t)}});t._currentTweens.push(p)}function E(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY);var u=i.maximumRadius,c=e.clone(s.position),h=e.clone(s.direction),d=e.clone(s.up),p=Math.tan(.5*t._cameraCV.frustum.fovy),m=t._cameraCV.frustum.aspectRatio*p,f=u*Math.PI/m,v=new e;v=e.multiplyByScalar(e.normalize(t._camera2D.position,v),f,v);var _=e.clone(t._camera2D.direction),g=e.clone(t._camera2D.up),E=function(t){s.position=y(c,v,t.time),s.direction=y(h,_,t.time),s.up=y(d,g,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)};r*=.5;var S=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:E,complete:function(){C(t,r,n)}});t._currentTweens.push(S)}function S(t,r,i,n){r*=.5;var o=i.maximumRadius,a=Math.tan(.5*t._camera3D.frustum.fovy),s=t._camera3D.frustum.aspectRatio*a,l=o*Math.PI/s,u={},c=new e;u.position2D=e.multiplyByScalar(e.normalize(t._camera2D.position2D,c),l,c),u.direction2D=e.clone(t._camera2D.direction2D),u.up2D=e.clone(t._camera2D.up2D);var h=function(){C(t,r,n)};b(t,r,u,h)}function w(t,r,i,n){var a=t._scene,l=a.camera,u=i.maximumRadius,c=Math.tan(.5*t._cameraCV.frustum.fovy),h=t._cameraCV.frustum.aspectRatio*c,d=u*Math.PI/h,p=new e;p=e.multiplyByScalar(e.normalize(t._camera2D.position,p),d,p);var m=l.frustum.top,f=l.frustum.bottom,v=l.frustum.right,_=l.frustum.left,g=t._camera2D.frustum,C=t._cameraCV.frustum,E=e.clone(l.position),S=function(e){l.position=y(E,p,e.time),l.frustum.top=s.lerp(m,g.top,e.time),l.frustum.bottom=s.lerp(f,g.bottom,e.time),l.frustum.right=s.lerp(v,g.right,e.time),l.frustum.left=s.lerp(_,g.left,e.time)},w=(v-_)/(2*u*Math.PI),T=1;w>T&&(w=0);var b=(T-w)*r;if(b<s.EPSILON6){if(e.equalsEpsilon(E,p,s.EPSILON6))return l.position=p,l.frustum=C.clone(),void n(t);b=r,w=0,T=1}var x=a.tweens.add({easingFunction:o.QUARTIC_OUT,duration:b,startObject:{time:w},stopObject:{time:T},update:S,complete:function(){l.frustum=C.clone(),n(t)}});t._currentTweens.push(x)}function T(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY),r*=.5;var u=function(){var i=e.clone(s.position),l=e.clone(s.direction),u=e.clone(s.up),c=e.clone(t._cameraCV.position),h=e.clone(t._cameraCV.direction),d=e.clone(t._cameraCV.up),p=function(t){s.position=y(i,c,t.time),s.direction=y(l,h,t.time),s.up=y(u,d,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)},m=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:p,complete:function(){n(t)}});t._currentTweens.push(m)};w(t,r,i,u)}function b(t,r,i,n){var a=t._scene,s=a.camera;s._setTransform(l.IDENTITY);var u=e.clone(s.position),c=e.clone(s.direction),h=e.clone(s.up),d=e.clone(i.position2D),p=e.clone(i.direction2D),m=e.clone(i.up2D),f=function(t){s.position=y(u,d,t.time),s.direction=y(c,p,t.time),s.up=y(h,m,t.time),s.right=e.cross(s.direction,s.up,s.right),e.normalize(s.right,s.right)},v=a.tweens.add({duration:r,easingFunction:o.QUARTIC_OUT,startObject:{time:0},stopObject:{time:1},update:f,complete:function(){s.position=d,s.direction=p,s.up=m,s.right=e.cross(p,m,s.right),e.normalize(s.right,s.right)}});t._currentTweens.push(v),x(t,a,1,0,r,n)}function x(e,t,i,n,a,s){var l={object:t,property:"morphTime",startValue:i,stopValue:n,duration:a,easingFunction:o.QUARTIC_OUT};r(s)&&(l.complete=function(){s(e)});var u=t.tweens.addProperty(l);e._currentTweens.push(u)}function P(e){var t=e._scene,r=t.drawingBufferHeight/t.drawingBufferWidth,i=e._camera2D.frustum;i.top=i.right*r,i.bottom=-i.top,r=1/r,i=e._cameraCV.frustum,i.aspectRatio=r,i=e._camera3D.frustum,i.aspectRatio=r;var n=t.camera;switch(t.mode){case m.SCENE3D:n.frustum=e._camera3D.frustum.clone();break;case m.COLUMBUS_VIEW:n.frustum=e._cameraCV.frustum.clone();break;case m.SCENE2D:n.frustum=e._camera2D.frustum.clone()}}function A(t){var i=t._scene;if(i._mode=m.SCENE3D,i.morphTime=m.getMorphTime(m.SCENE3D),v(t),P(t),t._previousMode!==m.MORPHING||t._morphCancelled){t._morphCancelled=!1;var n=i.camera;n.position=e.clone(t._camera3D.position),n.direction=e.clone(t._camera3D.direction),n.up=e.clone(t._camera3D.up),n.right=e.cross(n.direction,n.up,n.right),e.normalize(n.right,n.right)}var o=r(t._completeMorph);t._completeMorph=void 0,i.camera.update(i.mode),t._scene.morphComplete.raiseEvent(t,t._previousMode,m.SCENE3D,o)}function I(t){var i=t._scene;i._mode=m.SCENE2D,i.morphTime=m.getMorphTime(m.SCENE2D),v(t),P(t);var n=i.camera;e.clone(t._camera2D.position,n.position),e.clone(t._camera2D.direction,n.direction),e.clone(t._camera2D.up,n.up),e.cross(n.direction,n.up,n.right),e.normalize(n.right,n.right);var o=r(t._completeMorph);t._completeMorph=void 0,i.camera.update(i.mode),t._scene.morphComplete.raiseEvent(t,t._previousMode,m.SCENE2D,o)}function M(t){var i=t._scene;if(i._mode=m.COLUMBUS_VIEW,i.morphTime=m.getMorphTime(m.COLUMBUS_VIEW),v(t),P(t),t._previousModeMode!==m.MORPHING||t._morphCancelled){t._morphCancelled=!1;var n=i.camera;e.clone(t._cameraCV.position,n.position),e.clone(t._cameraCV.direction,n.direction),e.clone(t._cameraCV.up,n.up),e.cross(n.direction,n.up,n.right),e.normalize(n.right,n.right)}var o=r(t._completeMorph);t._completeMorph=void 0,i.camera.update(i.mode),t._scene.morphComplete.raiseEvent(t,t._previousMode,m.COLUMBUS_VIEW,o)}var D=function(r,i){this._scene=r,i=t(i,a.WGS84);var n=i.maximumRadius,o=new e(0,0,2*n),u=new e;u=e.normalize(e.negate(o,u),u);var c=e.clone(e.UNIT_Y),m=l.multiplyByPoint(h.TRANSFORM_2D,o,new e),f=l.multiplyByPointAsVector(h.TRANSFORM_2D,u,new e),v=l.multiplyByPointAsVector(h.TRANSFORM_2D,c,new e),_=new d;_.right=n*Math.PI,_.left=-_.right,_.top=_.right*(r.drawingBufferHeight/r.drawingBufferWidth),_.bottom=-_.top,this._camera2D={position:o,direction:u,up:c,position2D:m,direction2D:f,up2D:v,frustum:_},o=new e(0,-1,1),o=e.multiplyByScalar(e.normalize(o,o),5*n,o),u=new e,u=e.normalize(e.subtract(e.ZERO,o,u),u);var g=new e;g=e.normalize(e.cross(u,e.UNIT_Z,g),g),c=new e,c=e.normalize(e.cross(g,u,c),c),m=l.multiplyByPoint(h.TRANSFORM_2D,o,new e),f=l.multiplyByPointAsVector(h.TRANSFORM_2D,u,new e);var y=l.multiplyByPointAsVector(h.TRANSFORM_2D,g,new e);v=new e,v=e.normalize(e.cross(y,f,v),v),_=new p,_.aspectRatio=r.drawingBufferWidth/r.drawingBufferHeight,_.fov=s.toRadians(60),this._cameraCV={position:o,direction:u,up:c,position2D:m,direction2D:f,up2D:v,frustum:_},o=new e,o=e.multiplyByScalar(e.normalize(new e(0,-2,1),o),2*n,o),u=new e,u=e.normalize(e.subtract(e.ZERO,o,u),u),g=new e,g=e.normalize(e.cross(u,e.UNIT_Z,g),g),c=new e,c=e.normalize(e.cross(g,u,c),c),this._camera3D={position:o,direction:u,up:c,frustum:_},this._currentTweens=[],this._morphHandler=void 0,this._morphCancelled=!1,this._completeMorph=void 0};return D.prototype.completeMorph=function(){r(this._completeMorph)&&this._completeMorph()},D.prototype.morphTo2D=function(e,t){r(this._completeMorph)&&this._completeMorph();var i=this._scene;this._previousMode=i.mode,this._previousMode!==m.SCENE2D&&this._previousMode!==m.MORPHING&&(this._scene.morphStart.raiseEvent(this,this._previousMode,m.SCENE2D,!0),P(this),i._mode=m.MORPHING,f(this,I),this._previousMode===m.COLUMBUS_VIEW?E(this,e,t,I):S(this,e,t,I),0===e&&r(this._completeMorph)&&this._completeMorph())},D.prototype.morphToColumbusView=function(e,t){r(this._completeMorph)&&this._completeMorph();var i=this._scene;this._previousMode=i.mode,this._previousMode!==m.COLUMBUS_VIEW&&this._previousMode!==m.MORPHING&&(this._scene.morphStart.raiseEvent(this,this._previousMode,m.COLUMBUS_VIEW,!0),P(this),i._mode=m.MORPHING,f(this,M),this._previousMode===m.SCENE2D?T(this,e,t,M):b(this,e,this._cameraCV,M),0===e&&r(this._completeMorph)&&this._completeMorph())},D.prototype.morphTo3D=function(e,t){r(this._completeMorph)&&this._completeMorph();var i=this._scene;this._previousMode=i.mode,this._previousMode!==m.SCENE3D&&this._previousMode!==m.MORPHING&&(this._scene.morphStart.raiseEvent(this,this._previousMode,m.SCENE3D,!0),P(this),i._mode=m.MORPHING,f(this,A),this._previousMode===m.SCENE2D?g(this,e,t,A):_(this,e,t,A),0===e&&r(this._completeMorph)&&this._completeMorph())},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){return v(this),i(this)},D}),r("Scene/TweenCollection",["../Core/clone","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/EasingFunction","../Core/getTimestamp","../Core/TimeConstants","../ThirdParty/Tween"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(t,r,i,n,o,a,s,l,u,c){this._tweens=t,this._tweenjs=r,this._startObject=e(i),this._stopObject=e(n),this._duration=o,this._delay=a,this._easingFunction=s,this._update=l,this._complete=u,this.cancel=c,this.needsStart=!0};i(u.prototype,{startObject:{get:function(){return this._startObject}},stopObject:{get:function(){return this._stopObject}},duration:{get:function(){return this._duration}},delay:{get:function(){return this._delay}},easingFunction:{get:function(){return this._easingFunction}},update:{get:function(){return this._update}},complete:{get:function(){return this._complete}},tweenjs:{get:function(){return this._tweenjs}}}),u.prototype.cancelTween=function(){this._tweens.remove(this)};var c=function(){this._tweens=[]};return i(c.prototype,{length:{get:function(){return this._tweens.length}}}),c.prototype.add=function(i){if(i=t(i,t.EMPTY_OBJECT),0===i.duration)return r(i.complete)&&i.complete(),new u(this);var n=i.duration/s.SECONDS_PER_MILLISECOND,a=t(i.delay,0),c=a/s.SECONDS_PER_MILLISECOND,h=t(i.easingFunction,o.LINEAR_NONE),d=i.startObject,p=new l.Tween(d);p.to(e(i.stopObject),n),p.delay(c),p.easing(h),r(i.update)&&p.onUpdate(function(){i.update(d)}),p.onComplete(t(i.complete,null)),p.repeat(t(i._repeat,0));var m=new u(this,p,i.startObject,i.stopObject,i.duration,a,h,i.update,i.complete,i.cancel);return this._tweens.push(m),m},c.prototype.addProperty=function(e){function r(e){i[n]=e.value}e=t(e,t.EMPTY_OBJECT);var i=e.object,n=e.property,o=e.startValue,a=e.stopValue;return this.add({startObject:{value:o},stopObject:{value:a},duration:t(e.duration,3),delay:e.delay,easingFunction:e.easingFunction,update:r,complete:e.complete,cancel:e.cancel,_repeat:e._repeat})},c.prototype.addAlpha=function(e){function i(e){for(var t=o.length,r=0;t>r;++r)n.uniforms[o[r]].alpha=e.alpha}e=t(e,t.EMPTY_OBJECT);var n=e.material,o=[];for(var a in n.uniforms)n.uniforms.hasOwnProperty(a)&&r(n.uniforms[a])&&r(n.uniforms[a].alpha)&&o.push(a);return this.add({startObject:{alpha:t(e.startValue,0)},stopObject:{alpha:t(e.stopValue,1)},duration:t(e.duration,3),delay:e.delay,easingFunction:e.easingFunction,update:i,complete:e.complete,cancel:e.cancel})},c.prototype.addOffsetIncrement=function(e){e=t(e,t.EMPTY_OBJECT);var r=e.material,i=r.uniforms;return this.addProperty({object:i,property:"offset",startValue:i.offset,stopValue:i.offset+1,duration:e.duration,delay:e.delay,easingFunction:e.easingFunction,update:e.update,cancel:e.cancel,_repeat:1/0})},c.prototype.remove=function(e){if(!r(e))return!1;var t=this._tweens.indexOf(e);return-1!==t?(e.tweenjs.stop(),r(e.cancel)&&e.cancel(),this._tweens.splice(t,1),!0):!1},c.prototype.removeAll=function(){for(var e=this._tweens,t=0;t<e.length;++t){var i=e[t];i.tweenjs.stop(),r(i.cancel)&&i.cancel()}e.length=0},c.prototype.contains=function(e){return r(e)&&-1!==this._tweens.indexOf(e)},c.prototype.get=function(e){return this._tweens[e]},c.prototype.update=function(e){var t=this._tweens,i=0;for(e=r(e)?e/s.SECONDS_PER_MILLISECOND:a();i<t.length;){var n=t[i],o=n.tweenjs;n.needsStart?(n.needsStart=!1,o.start(e)):o.update(e)?i++:(o.stop(),t.splice(i,1))}},c}),r("Scene/ScreenSpaceCameraController",["../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Cartographic","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/Ellipsoid","../Core/IntersectionTests","../Core/isArray","../Core/KeyboardEventModifier","../Core/Math","../Core/Matrix3","../Core/Matrix4","../Core/Plane","../Core/Quaternion","../Core/Ray","../Core/Transforms","./CameraEventAggregator","./CameraEventType","./SceneMode","./SceneTransforms","./TweenCollection"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w){"use strict";function T(e,t){if(0>e)return 0;var r=25*(1-t);return Math.exp(-r*e)}function b(t){return e.equalsEpsilon(t.startPosition,t.endPosition,d.EPSILON14)}function x(t,r,i,n,a,s,l){var u=s[l];o(u)||(u=s[l]={startPosition:new e,endPosition:new e,motion:new e,active:!1});var c=t.getButtonPressTime(r,i),h=t.getButtonReleaseTime(r,i),d=c&&h&&(h.getTime()-c.getTime())/1e3,p=new Date,m=h&&(p.getTime()-h.getTime())/1e3;if(c&&h&&$>d){var f=T(m,n);if(u.active)u.startPosition=e.clone(u.endPosition,u.startPosition),u.endPosition=e.multiplyByScalar(u.motion,f,u.endPosition),u.endPosition=e.add(u.startPosition,u.endPosition,u.endPosition),u.motion=e.clone(e.ZERO,u.motion);else{var v=t.getLastMovement(r,i);if(!o(v)||b(v))return;u.motion.x=.5*(v.endPosition.x-v.startPosition.x),u.motion.y=.5*(v.endPosition.y-v.startPosition.y),u.startPosition=e.clone(v.startPosition,u.startPosition),u.endPosition=e.multiplyByScalar(u.motion,f,u.endPosition),u.endPosition=e.add(u.startPosition,u.endPosition,u.endPosition),u.active=!0}if(isNaN(u.endPosition.x)||isNaN(u.endPosition.y)||e.distance(u.startPosition,u.endPosition)<.5)return void(u.active=!1);if(!t.isButtonDown(r,i)){var _=t.getStartMousePosition(r,i);a(s,_,u)}}else u.active=!1}function P(e,t,r,i,n,a){if(o(r)){var s=e._aggregator;c(r)||(ee[0]=r,r=ee);for(var l=r.length,u=0;l>u;++u){var h=r[u],d=o(h.eventType)?h.eventType:h,p=h.modifier,m=s.isMoving(d,p)&&s.getMovement(d,p),f=s.getStartMousePosition(d,p);e.enableInputs&&t&&(m?i(e,f,m):1>n&&x(s,d,p,n,i,e,a))}}}function A(r,i,n,a,s,l){var u=1;o(l)&&(u=d.clamp(Math.abs(l),.25,1));var c=r.minimumZoomDistance*u,h=r.maximumZoomDistance,p=s-c,m=a*p;m=d.clamp(m,r._minimumZoomRate,r._maximumZoomRate);var f=n.endPosition.y-n.startPosition.y,v=f/r._scene.canvas.clientHeight;v=Math.min(v,r.maximumMovementRatio);var _=m*v;if(!(_>0&&Math.abs(s-c)<1||0>_&&Math.abs(s-h)<1)){c>s-_?_=s-c-1:s-_>h&&(_=s-h);var g,y=r._scene,C=y.camera,w=y.mode;if(o(r._globe)&&(g=w!==E.SCENE2D?N(r,i,re):C.getPickRay(i,te).origin),!o(g))return void C.zoomIn(_);var T=e.equals(i,r._zoomMouseStart),b=r._zoomingOnVector,x=r._rotatingZoom;T||(r._zoomMouseStart=e.clone(i,r._zoomMouseStart),r._zoomWorldPosition=t.clone(g,r._zoomWorldPosition),b=r._zoomingOnVector=!1,x=r._rotatingZoom=!1);var P=w===E.COLUMBUS_VIEW;if(!T||x){if(w===E.SCENE2D){var A=r._zoomWorldPosition,I=C.position;if(!t.equals(A,I)){var M=t.subtract(A,I,ne);t.normalize(M,M);var D=t.distance(A,I)*_/(.5*C.getMagnitude());C.move(M,.5*D)}}else if(w===E.SCENE3D){var R=t.normalize(C.position,ce);if(C.positionCartographic.height<3e3&&Math.abs(t.dot(C.direction,R))<.6)P=!0;else{var O=y.canvas,L=oe;L.x=O.clientWidth/2,L.y=O.clientHeight/2;var F=N(r,L,ae);if(o(F)){var B=t.normalize(F,se),V=t.normalize(r._zoomWorldPosition,le),z=t.dot(V,B);if(z>0){var k=d.acosClamped(z),U=t.cross(V,B,ue),G=Math.abs(k)>d.toRadians(20)?.75*C.positionCartographic.height:C.positionCartographic.height-_,W=_/G;C.rotate(U,k*W)}}else P=!0}}r._rotatingZoom=!P}if(!T&&P||b){var H,q=S.wgs84ToWindowCoordinates(y,r._zoomWorldPosition,ie);H=w!==E.COLUMBUS_VIEW&&e.equals(i,r._zoomMouseStart)&&o(q)?C.getPickRay(q,te):C.getPickRay(i,te);var j=H.direction;w===E.COLUMBUS_VIEW&&t.fromElements(j.y,j.z,j.x,j),C.move(j,_),r._zoomingOnVector=!0}else C.zoomIn(_)}}function I(e,r,i){var n=e._scene,o=n.camera,a=o.getPickRay(i.startPosition,he).origin,s=o.getPickRay(i.endPosition,de).origin,l=t.subtract(a,s,pe),u=t.magnitude(l);u>0&&(t.normalize(l,l),o.move(l,u))}function M(e,t,r){o(r.distance)&&(r=r.distance);var i=e._scene,n=i.camera;A(e,t,r,e._zoomFactor,n.getMagnitude())}function D(t,r,i){if(o(i.angleAndHeight))return void R(t,r,i.angleAndHeight);var n=t._scene,a=n.camera,s=n.canvas,l=s.clientWidth,u=s.clientHeight,c=me;c.x=2/l*i.startPosition.x-1,c.y=2/u*(u-i.startPosition.y)-1,c=e.normalize(c,c); -var h=fe;h.x=2/l*i.endPosition.x-1,h.y=2/u*(u-i.endPosition.y)-1,h=e.normalize(h,h);var p=d.acosClamped(c.x);c.y<0&&(p=d.TWO_PI-p);var m=d.acosClamped(h.x);h.y<0&&(m=d.TWO_PI-m);var f=m-p;a.twistRight(f)}function R(e,t,r){var i=e._rotateFactor*e._rotateRateRangeAdjustment;i>e._maximumRotateRate&&(i=e._maximumRotateRate),i<e._minimumRotateRate&&(i=e._minimumRotateRate);var n=e._scene,o=n.camera,a=n.canvas,s=(r.endPosition.x-r.startPosition.x)/a.clientWidth;s=Math.min(s,e.maximumMovementRatio);var l=i*s*Math.PI*4;o.twistRight(l)}function O(e){var t=e._tweens;e._aggregator.anyButtonDown&&t.removeAll();var r=e._scene,i=r.camera;if(t.contains(e._tween)||(m.equals(m.IDENTITY,i.transform)?(P(e,e.enableTranslate,e.translateEventTypes,I,e.inertiaTranslate,"_lastInertiaTranslateMovement"),P(e,e.enableZoom,e.zoomEventTypes,M,e.inertiaZoom,"_lastInertiaZoomMovement"),P(e,e.enableRotate,e.tiltEventTypes,D,e.inertiaSpin,"_lastInertiaTiltMovement")):(P(e,e.enableRotate,e.translateEventTypes,D,e.inertiaSpin,"_lastInertiaSpinMovement"),P(e,e.enableZoom,e.zoomEventTypes,M,e.inertiaZoom,"_lastInertiaZoomMovement"))),!(e._aggregator.anyButtonDown||o(e._lastInertiaZoomMovement)&&e._lastInertiaZoomMovement.active||o(e._lastInertiaTranslateMovement)&&e._lastInertiaTranslateMovement.active||t.contains(e._tween))){var n=i.createCorrectPositionTween(e.bounceAnimationTime);o(n)&&(e._tween=t.add(n))}t.update()}function N(e,r,i){var n=e._scene,a=e._globe,s=n.camera;if(!o(a))return void 0;var l;n.pickPositionSupported&&(l=n.pickPosition(r,_e));var u=s.getPickRay(r,ve),c=a.pick(u,n,ge),h=o(l)?t.distance(l,s.positionWC):Number.POSITIVE_INFINITY,d=o(c)?t.distance(c,s.positionWC):Number.POSITIVE_INFINITY;return d>h?t.clone(l,i):t.clone(c,i)}function L(r,i,n){if(t.equals(i,r._translateMousePosition)||(r._looking=!1),t.equals(i,r._strafeMousePosition)||(r._strafing=!1),r._looking)return void Z(r,i,n);if(r._strafing)return void U(r,i,n);var a,s=r._scene,l=s.camera,c=e.clone(n.startPosition,xe),h=e.clone(n.endPosition,Pe),p=l.getPickRay(c,ye),m=t.clone(t.ZERO,Te),v=t.UNIT_X;if(l.position.z<r.minimumPickingTerrainHeight&&(a=N(r,c,Ee),o(a)&&(m.x=a.x)),m.x>l.position.z&&o(a))return t.clone(a,r._strafeStartPosition),r._strafing=!0,U(r,i,n),void(r._strafeMousePosition=e.clone(i,r._strafeMousePosition));var _=f.fromPointNormal(m,v,be);p=l.getPickRay(c,ye);var g=u.rayPlane(p,_,Ee),y=l.getPickRay(h,Ce),C=u.rayPlane(y,_,Se);if(!o(g)||!o(C))return r._looking=!0,Z(r,i,n),void e.clone(i,r._translateMousePosition);var E=t.subtract(g,C,we),S=E.x;E.x=E.y,E.y=E.z,E.z=S;var w=t.magnitude(E);w>d.EPSILON6&&(t.normalize(E,E),l.move(E,w))}function F(t,r,i){if(o(i.angleAndHeight)&&(i=i.angleAndHeight),e.equals(r,t._tiltCenterMousePosition)||(t._tiltCVOffMap=!1,t._looking=!1),t._looking)return void Z(t,r,i);var n=t._scene,a=n.camera,s=t._maxCoord,l=Math.abs(a.position.x)-s.x<0&&Math.abs(a.position.y)-s.y<0;t._tiltCVOffMap||!l||a.position.z>t.minimumPickingTerrainHeight?(t._tiltCVOffMap=!0,B(t,r,i)):V(t,r,i)}function B(r,i,n){var a=r._scene,s=a.camera,u=a.canvas,c=Ae;c.x=u.clientWidth/2,c.y=u.clientHeight/2;var h,p=s.getPickRay(c,Ie),f=t.UNIT_X,v=p.origin,_=p.direction,y=t.dot(f,_);if(Math.abs(y)>d.EPSILON6&&(h=-t.dot(f,v)/y),!o(h)||0>=h)return r._looking=!0,Z(r,i,n),void e.clone(i,r._tiltCenterMousePosition);var C=t.multiplyByScalar(_,h,Me);t.add(v,C,C);var E=a.mapProjection,S=E.ellipsoid;t.fromElements(C.y,C.z,C.x,C);var w=E.unproject(C,Be);S.cartographicToCartesian(w,C);var T=g.eastNorthUpToFixedFrame(C,S,Re),b=r._globe,x=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var P=m.clone(s.transform,Ve);s._setTransform(T),W(r,i,n,t.UNIT_Z),s._setTransform(P),r._globe=b,r._ellipsoid=x;var A=x.maximumRadius;r._rotateFactor=1/A,r._rotateRateRangeAdjustment=A}function V(r,i,n){var a,s,c=r._ellipsoid,h=r._scene,_=h.camera,y=t.UNIT_X;if(e.equals(i,r._tiltCenterMousePosition))a=t.clone(r._tiltCenter,Me);else{if(_.position.z<r.minimumPickingTerrainHeight&&(a=N(r,i,Me)),!o(a)){s=_.getPickRay(i,Ie);var C,E=s.origin,S=s.direction,w=t.dot(y,S);if(Math.abs(w)>d.EPSILON6&&(C=-t.dot(y,E)/w),!o(C)||0>=C)return r._looking=!0,Z(r,i,n),void e.clone(i,r._tiltCenterMousePosition);a=t.multiplyByScalar(S,C,Me),t.add(E,a,a)}e.clone(i,r._tiltCenterMousePosition),t.clone(a,r._tiltCenter)}var T=h.canvas,b=Ae;b.x=T.clientWidth/2,b.y=r._tiltCenterMousePosition.y,s=_.getPickRay(b,Ie);var x=t.clone(t.ZERO,Ne);x.x=a.x;var P=f.fromPointNormal(x,y,Le),A=u.rayPlane(s,P,De),I=_._projection;c=I.ellipsoid,t.fromElements(a.y,a.z,a.x,a);var M=I.unproject(a,Be);c.cartographicToCartesian(M,a);var D,R=g.eastNorthUpToFixedFrame(a,c,Re);o(A)?(t.fromElements(A.y,A.z,A.x,A),M=I.unproject(A,Be),c.cartographicToCartesian(M,A),D=g.eastNorthUpToFixedFrame(A,c,Oe)):D=R;var O=r._globe,L=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var F=t.UNIT_Z,B=m.clone(_.transform,Ve);_._setTransform(R);var V=t.cross(t.UNIT_Z,t.normalize(_.position,Fe),Fe),z=t.dot(_.right,V);if(W(r,i,n,F,!1,!0),_._setTransform(D),0>z){n.startPosition.y>n.endPosition.y&&(F=void 0);var k=_.constrainedAxis;_.constrainedAxis=void 0,W(r,i,n,F,!0,!1),_.constrainedAxis=k}else W(r,i,n,F,!0,!1);if(o(_.constrainedAxis)){var U=t.cross(_.direction,_.constrainedAxis,vt);t.equalsEpsilon(U,t.ZERO,d.EPSILON6)||(t.dot(U,_.right)<0&&t.negate(U,U),t.cross(U,_.direction,_.up),t.cross(_.direction,_.up,_.right),t.normalize(_.up,_.up),t.normalize(_.right,_.right))}_._setTransform(B),r._globe=O,r._ellipsoid=L;var G=L.maximumRadius;r._rotateFactor=1/G,r._rotateRateRangeAdjustment=G;var H=t.clone(_.positionWC,Fe);if(J(r),!t.equals(_.positionWC,H)){_._setTransform(D),_.worldToCameraCoordinatesPoint(H,H);var q=t.magnitudeSquared(H);t.magnitudeSquared(_.position)>q&&(t.normalize(_.position,_.position),t.multiplyByScalar(_.position,Math.sqrt(q),_.position));var j=t.angleBetween(H,_.position),Y=t.cross(H,_.position,H);t.normalize(Y,Y);var X=v.fromAxisAngle(Y,j,ze),K=p.fromQuaternion(X,ke);p.multiplyByVector(K,_.direction,_.direction),p.multiplyByVector(K,_.up,_.up),t.cross(_.direction,_.up,_.right),t.cross(_.right,_.direction,_.up),_._setTransform(B)}}function z(e,r,i){o(i.distance)&&(i=i.distance);var n=e._scene,a=n.camera,s=n.canvas,l=Ue;l.x=s.clientWidth/2,l.y=s.clientHeight/2;var u,c=a.getPickRay(l,Ge);a.position.z<e.minimumPickingTerrainHeight&&(u=N(e,l,We));var h;if(o(u))h=t.distance(c.origin,u);else{var d=t.UNIT_X,p=c.origin,m=c.direction;h=-t.dot(d,p)/t.dot(d,m)}A(e,r,i,e._zoomFactor,h)}function k(e){var t=e._scene,r=t.camera;if(m.equals(m.IDENTITY,r.transform)){var i=e._tweens;if(e._aggregator.anyButtonDown&&i.removeAll(),P(e,e.enableTilt,e.tiltEventTypes,F,e.inertiaSpin,"_lastInertiaTiltMovement"),P(e,e.enableTranslate,e.translateEventTypes,L,e.inertiaTranslate,"_lastInertiaTranslateMovement"),P(e,e.enableZoom,e.zoomEventTypes,z,e.inertiaZoom,"_lastInertiaZoomMovement"),P(e,e.enableLook,e.lookEventTypes,Z),!(e._aggregator.anyButtonDown||o(e._lastInertiaZoomMovement)&&e._lastInertiaZoomMovement.active||o(e._lastInertiaTranslateMovement)&&e._lastInertiaTranslateMovement.active||i.contains(e._tween))){var n=r.createCorrectPositionTween(e.bounceAnimationTime);o(n)&&(e._tween=i.add(n))}i.update()}else P(e,e.enableRotate,e.rotateEventTypes,W,e.inertiaSpin,"_lastInertiaSpinMovement"),P(e,e.enableZoom,e.zoomEventTypes,q,e.inertiaZoom,"_lastInertiaZoomMovement")}function U(e,r,i){var n=e._scene,a=n.camera,s=N(e,i.startPosition,Ke);if(o(s)){var l=i.endPosition,c=a.getPickRay(l,He),h=t.clone(a.direction,Ye);n.mode===E.COLUMBUS_VIEW&&t.fromElements(h.z,h.x,h.y,h);var d=f.fromPointNormal(s,h,qe),p=u.rayPlane(c,d,je);o(p)&&(h=t.subtract(s,p,h),n.mode===E.COLUMBUS_VIEW&&t.fromElements(h.y,h.z,h.x,h),t.add(a.position,h,a.position))}}function G(r,i,n){var a=r._scene,s=a.camera;if(!m.equals(s.transform,m.IDENTITY))return void W(r,i,n);var u,c,h,d,p=r._ellipsoid.geodeticSurfaceNormal(s.position,$e),f=r._ellipsoid.cartesianToCartographic(s.positionWC,Ze).height,v=r._globe,_=!1;if(o(v)&&f<r.minimumPickingTerrainHeight&&(d=N(r,n.startPosition,Ke),o(d))){var g=s.getPickRay(n.startPosition,ve),y=r._ellipsoid.geodeticSurfaceNormal(d);_=Math.abs(t.dot(g.direction,y))<.05,_&&!r._looking&&(r._rotating=!1,r._strafing=!0)}return e.equals(i,r._rotateMousePosition)?void(r._looking?Z(r,i,n,p):r._rotating?W(r,i,n):r._strafing?(t.clone(d,r._strafeStartPosition),U(r,i,n)):(u=t.magnitude(r._rotateStartPosition),c=Je,c.x=c.y=c.z=u,h=l.fromCartesian3(c,Qe),H(r,i,n,h))):(r._looking=!1,r._rotating=!1,r._strafing=!1,o(v)&&f<r.minimumPickingTerrainHeight?o(d)?t.magnitude(s.position)<t.magnitude(d)?(t.clone(d,r._strafeStartPosition),r._strafing=!0,U(r,i,n)):(u=t.magnitude(d),c=Je,c.x=c.y=c.z=u,h=l.fromCartesian3(c,Qe),H(r,i,n,h),t.clone(d,r._rotateStartPosition)):(r._looking=!0,Z(r,i,n,p)):o(s.pickEllipsoid(n.startPosition,r._ellipsoid,Xe))?(H(r,i,n,r._ellipsoid),t.clone(Xe,r._rotateStartPosition)):f>r.minimumTrackBallHeight?(r._rotating=!0,W(r,i,n)):(r._looking=!0,Z(r,i,n,p)),void e.clone(i,r._rotateMousePosition))}function W(e,r,i,a,s,l){s=n(s,!1),l=n(l,!1);var u=e._scene,c=u.camera,h=u.canvas,d=c.constrainedAxis;o(a)&&(c.constrainedAxis=a);var p=t.magnitude(c.position),m=e._rotateFactor*(p-e._rotateRateRangeAdjustment);m>e._maximumRotateRate&&(m=e._maximumRotateRate),m<e._minimumRotateRate&&(m=e._minimumRotateRate);var f=(i.startPosition.x-i.endPosition.x)/h.clientWidth,v=(i.startPosition.y-i.endPosition.y)/h.clientHeight;f=Math.min(f,e.maximumMovementRatio),v=Math.min(v,e.maximumMovementRatio);var _=m*f*Math.PI*2,g=m*v*Math.PI;s||c.rotateRight(_),l||c.rotateUp(g),c.constrainedAxis=d}function H(r,i,n,a){var s=r._scene,l=s.camera,u=e.clone(n.startPosition,at),c=e.clone(n.endPosition,st),h=l.pickEllipsoid(u,a,et),p=l.pickEllipsoid(c,a,tt);if(!o(h)||!o(p))return r._rotating=!0,void W(r,i,n);if(h=l.worldToCameraCoordinates(h,h),p=l.worldToCameraCoordinates(p,p),o(l.constrainedAxis)){var m=l.constrainedAxis,f=t.mostOrthogonalAxis(m,rt);t.cross(f,m,f),t.normalize(f,f);var v=t.cross(m,f,it),_=t.magnitude(h),g=t.dot(m,h),y=Math.acos(g/_),C=t.multiplyByScalar(m,g,nt);t.subtract(h,C,C),t.normalize(C,C);var E=t.magnitude(p),S=t.dot(m,p),w=Math.acos(S/E),T=t.multiplyByScalar(m,S,ot);t.subtract(p,T,T),t.normalize(T,T);var b=Math.acos(t.dot(C,f));t.dot(C,v)<0&&(b=d.TWO_PI-b);var x=Math.acos(t.dot(T,f));t.dot(T,v)<0&&(x=d.TWO_PI-x);var P,A=b-x;P=t.equalsEpsilon(m,l.position,d.EPSILON2)?l.right:t.cross(m,l.position,rt);var I,M=t.cross(m,P,rt),D=t.dot(M,t.subtract(h,m,it)),R=t.dot(M,t.subtract(p,m,it));I=D>0&&R>0?w-y:D>0&&0>=R?t.dot(l.position,m)>0?-y-w:y+w:y-w,l.rotateRight(A),l.rotateUp(I)}else{t.normalize(h,h),t.normalize(p,p);var O=t.dot(h,p),N=t.cross(h,p,rt);if(1>O&&!t.equalsEpsilon(N,t.ZERO,d.EPSILON14)){var L=Math.acos(O);l.rotate(N,L)}}}function q(e,r,i){o(i.distance)&&(i=i.distance);var n=e._ellipsoid,a=e._scene,s=a.camera,l=a.canvas,u=Ue;u.x=l.clientWidth/2,u.y=l.clientHeight/2;var c,h=s.getPickRay(u,Ge),d=n.cartesianToCartographic(s.position,ut).height;d<e.minimumPickingTerrainHeight&&(c=N(e,u,We));var p;p=o(c)?t.distance(h.origin,c):d;var m=t.normalize(s.position,lt);A(e,r,i,e._zoomFactor,p,t.dot(m,s.direction))}function j(t,r,i){var n=t._scene,a=n.camera;if(m.equals(a.transform,m.IDENTITY)){if(o(i.angleAndHeight)&&(i=i.angleAndHeight),e.equals(r,t._tiltCenterMousePosition)||(t._tiltOnEllipsoid=!1,t._looking=!1),t._looking){var s=t._ellipsoid.geodeticSurfaceNormal(a.position,Et);return void Z(t,r,i,s)}var l=t._ellipsoid,u=l.cartesianToCartographic(a.position,Ct);t._tiltOnEllipsoid||u.height>t.minimumCollisionTerrainHeight?(t._tiltOnEllipsoid=!0,Y(t,r,i)):X(t,r,i)}}function Y(r,i,n){var a=r._ellipsoid,s=r._scene,c=s.camera,h=.25*r.minimumZoomDistance,p=a.cartesianToCartographic(c.positionWC,St).height;if(!(p-h-1<d.EPSILON3&&n.endPosition.y-n.startPosition.y<0)){var f=s.canvas,v=ct;v.x=f.clientWidth/2,v.y=f.clientHeight/2;var y,C=c.getPickRay(v,ht),E=u.rayEllipsoid(C,a);if(o(E))y=_.getPoint(C,E.start,dt);else{if(!(p>r.minimumTrackBallHeight)){r._looking=!0;var S=r._ellipsoid.geodeticSurfaceNormal(c.position,Et);return Z(r,i,n,S),void e.clone(i,r._tiltCenterMousePosition)}var w=u.grazingAltitudeLocation(C,a);if(!o(w))return;var T=a.cartesianToCartographic(w,Ct);T.height=0,y=a.cartographicToCartesian(T,dt)}var b=g.eastNorthUpToFixedFrame(y,a,mt),x=r._globe,P=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var A=m.clone(c.transform,_t);c._setTransform(b),W(r,i,n,t.UNIT_Z),c._setTransform(A),r._globe=x,r._ellipsoid=P;var I=P.maximumRadius;r._rotateFactor=1/I,r._rotateRateRangeAdjustment=I}}function X(r,i,n){var a,s,c,h=r._ellipsoid,f=r._scene,y=f.camera;if(e.equals(i,r._tiltCenterMousePosition))a=t.clone(r._tiltCenter,dt);else{if(a=N(r,i,dt),!o(a)){if(s=y.getPickRay(i,ht),c=u.rayEllipsoid(s,h),!o(c)){var C=h.cartesianToCartographic(y.position,Ct);if(C.height<=r.minimumTrackBallHeight){r._looking=!0;var E=r._ellipsoid.geodeticSurfaceNormal(y.position,Et);Z(r,i,n,E),e.clone(i,r._tiltCenterMousePosition)}return}a=_.getPoint(s,c.start,dt)}e.clone(i,r._tiltCenterMousePosition),t.clone(a,r._tiltCenter)}var S=f.canvas,w=ct;w.x=S.clientWidth/2,w.y=r._tiltCenterMousePosition.y,s=y.getPickRay(w,ht);var T=t.magnitude(a),b=t.fromElements(T,T,T,Je),x=l.fromCartesian3(b,Qe);if(c=u.rayEllipsoid(s,x),o(c)){var P=t.magnitude(s.origin)>T?c.start:c.stop,A=_.getPoint(s,P,pt),I=g.eastNorthUpToFixedFrame(a,h,mt),M=g.eastNorthUpToFixedFrame(A,x,ft),D=r._globe,R=r._ellipsoid;r._globe=void 0,r._ellipsoid=l.UNIT_SPHERE,r._rotateFactor=1,r._rotateRateRangeAdjustment=1;var O=t.UNIT_Z,L=m.clone(y.transform,_t);y._setTransform(I);var F=t.cross(A,y.positionWC,vt),B=t.dot(y.rightWC,F);if(W(r,i,n,O,!1,!0),y._setTransform(M),0>B){n.startPosition.y>n.endPosition.y&&(O=void 0);var V=y.constrainedAxis;y.constrainedAxis=void 0,W(r,i,n,O,!0,!1),y.constrainedAxis=V}else W(r,i,n,O,!0,!1);if(o(y.constrainedAxis)){var z=t.cross(y.direction,y.constrainedAxis,vt);t.equalsEpsilon(z,t.ZERO,d.EPSILON6)||(t.dot(z,y.right)<0&&t.negate(z,z),t.cross(z,y.direction,y.up),t.cross(y.direction,y.up,y.right),t.normalize(y.up,y.up),t.normalize(y.right,y.right))}y._setTransform(L),r._globe=D,r._ellipsoid=R;var k=R.maximumRadius;r._rotateFactor=1/k,r._rotateRateRangeAdjustment=k;var U=t.clone(y.positionWC,vt);if(J(r),!t.equals(y.positionWC,U)){y._setTransform(M),y.worldToCameraCoordinatesPoint(U,U);var G=t.magnitudeSquared(U);t.magnitudeSquared(y.position)>G&&(t.normalize(y.position,y.position),t.multiplyByScalar(y.position,Math.sqrt(G),y.position));var H=t.angleBetween(U,y.position),q=t.cross(U,y.position,U);t.normalize(q,q);var j=v.fromAxisAngle(q,H,gt),Y=p.fromQuaternion(j,yt);p.multiplyByVector(Y,y.direction,y.direction),p.multiplyByVector(Y,y.up,y.up),t.cross(y.direction,y.up,y.right),t.cross(y.right,y.direction,y.up),y._setTransform(L)}}}function Z(e,r,i,a){var s=e._scene,l=s.camera,u=wt;u.x=i.startPosition.x,u.y=0;var c=Tt;c.x=i.endPosition.x,c.y=0;var h=l.getPickRay(u,bt).direction,p=l.getPickRay(c,xt).direction,m=0,f=t.dot(h,p);1>f&&(m=Math.acos(f)),m=i.startPosition.x>i.endPosition.x?-m:m;var v=e._horizontalRotationAxis;if(o(a)?l.look(a,-m):o(v)?l.look(v,-m):l.lookLeft(m),u.x=0,u.y=i.startPosition.y,c.x=0,c.y=i.endPosition.y,h=l.getPickRay(u,bt).direction,p=l.getPickRay(c,xt).direction,m=0,f=t.dot(h,p),1>f&&(m=Math.acos(f)),m=i.startPosition.y>i.endPosition.y?-m:m,a=n(a,v),o(a)){var _=l.direction,g=t.negate(a,Pt),y=t.equalsEpsilon(_,a,d.EPSILON2),C=t.equalsEpsilon(_,g,d.EPSILON2);if(y||C)(y&&0>m||C&&m>0)&&l.look(l.right,-m);else{f=t.dot(_,a);var E=d.acosClamped(f);m>0&&m>E&&(m=E-d.EPSILON4),f=t.dot(_,g),E=d.acosClamped(f),0>m&&-m>E&&(m=-E+d.EPSILON4);var S=t.cross(a,_,At);l.look(S,m)}}else l.lookUp(m)}function K(e){P(e,e.enableRotate,e.rotateEventTypes,G,e.inertiaSpin,"_lastInertiaSpinMovement"),P(e,e.enableZoom,e.zoomEventTypes,q,e.inertiaZoom,"_lastInertiaZoomMovement"),P(e,e.enableTilt,e.tiltEventTypes,j,e.inertiaSpin,"_lastInertiaTiltMovement"),P(e,e.enableLook,e.lookEventTypes,Z)}function J(e){if(e.enableCollisionDetection){var r=e._scene,i=r.mode,n=r.globe;if(o(n)&&i!==E.SCENE2D&&i!==E.MORPHING){var a,s,l=r.camera,u=n.ellipsoid,c=r.mapProjection;m.equals(l.transform,m.IDENTITY)||(a=m.clone(l.transform),s=t.magnitude(l.position),l._setTransform(m.IDENTITY));var h=It;i===E.SCENE3D?u.cartesianToCartographic(l.position,h):c.unproject(l.position,h);var d=!1;if(h.height<e.minimumCollisionTerrainHeight){var p=n.getHeight(h);o(p)&&(p+=e.minimumZoomDistance,h.height<p&&(h.height=p,i===E.SCENE3D?u.cartographicToCartesian(h,l.position):c.project(h,l.position),d=!0))}o(a)&&(l._setTransform(a),d&&(t.normalize(l.position,l.position),t.negate(l.position,l.direction),t.multiplyByScalar(l.position,Math.max(s,e.minimumZoomDistance),l.position),t.normalize(l.direction,l.direction),t.cross(l.direction,l.up,l.right),t.cross(l.right,l.direction,l.up)))}}}var Q=function(r){this.enableInputs=!0,this.enableTranslate=!0,this.enableZoom=!0,this.enableRotate=!0,this.enableTilt=!0,this.enableLook=!0,this.inertiaSpin=.9,this.inertiaTranslate=.9,this.inertiaZoom=.8,this.maximumMovementRatio=.1,this.bounceAnimationTime=3,this.minimumZoomDistance=1,this.maximumZoomDistance=Number.POSITIVE_INFINITY,this.translateEventTypes=C.LEFT_DRAG,this.zoomEventTypes=[C.RIGHT_DRAG,C.WHEEL,C.PINCH],this.rotateEventTypes=C.LEFT_DRAG,this.tiltEventTypes=[C.MIDDLE_DRAG,C.PINCH,{eventType:C.LEFT_DRAG,modifier:h.CTRL},{eventType:C.RIGHT_DRAG,modifier:h.CTRL}],this.lookEventTypes={eventType:C.LEFT_DRAG,modifier:h.SHIFT},this.minimumPickingTerrainHeight=15e4,this.minimumCollisionTerrainHeight=15e3,this.minimumTrackBallHeight=75e5,this.enableCollisionDetection=!0,this._scene=r,this._globe=void 0,this._ellipsoid=void 0,this._aggregator=new y(r.canvas),this._lastInertiaSpinMovement=void 0,this._lastInertiaZoomMovement=void 0,this._lastInertiaTranslateMovement=void 0,this._lastInertiaWheelZoomMovement=void 0,this._lastInertiaTiltMovement=void 0,this._tweens=new w,this._tween=void 0,this._horizontalRotationAxis=void 0,this._tiltCenterMousePosition=new e(-1,-1),this._tiltCenter=new t,this._rotateMousePosition=new e(-1,-1),this._rotateStartPosition=new t,this._strafeStartPosition=new t,this._zoomMouseStart=new e,this._zoomWorldPosition=new t,this._tiltCVOffMap=!1,this._looking=!1,this._rotating=!1,this._strafing=!1,this._zoomingOnVector=!1,this._rotatingZoom=!1;var n=r.mapProjection;this._maxCoord=n.project(new i(Math.PI,d.PI_OVER_TWO)),this._zoomFactor=5,this._rotateFactor=void 0,this._rotateRateRangeAdjustment=void 0,this._maximumRotateRate=1.77,this._minimumRotateRate=2e-4,this._translateFactor=1,this._minimumZoomRate=20,this._maximumZoomRate=5906376272e3},$=.4,ee=[],te=new _,re=new t,ie=new e,ne=new t,oe=new e,ae=new t,se=new t,le=new t,ue=new t,ce=new t,he=new _,de=new _,pe=new t,me=new e,fe=new e,ve=new _,_e=new t,ge=new t,ye=new _,Ce=new _,Ee=new t,Se=new t,we=new t,Te=new t,be=new f(t.ZERO,0),xe=new e,Pe=new e,Ae=new e,Ie=new _,Me=new t,De=new t,Re=new m,Oe=new m,Ne=new t,Le=new f(t.ZERO,0),Fe=new t,Be=new i,Ve=new m,ze=new v,ke=new p,Ue=new e,Ge=new _,We=new t,He=new _,qe=new f(t.ZERO,0),je=new t,Ye=new t,Xe=new t,Ze=(new _,new i),Ke=new t,Je=new t,Qe=new l,$e=new t,et=r.clone(r.UNIT_W),tt=r.clone(r.UNIT_W),rt=new t,it=new t,nt=new t,ot=new t,at=new e,st=new e,lt=new t,ut=new i,ct=new e,ht=new _,dt=new t,pt=new t,mt=new m,ft=new m,vt=new t,_t=new m,gt=new v,yt=new p,Ct=new i,Et=new t,St=new i,wt=new e,Tt=new e,bt=new _,xt=new _,Pt=new t,At=new t,It=new i;return Q.prototype.update=function(){m.equals(this._scene.camera.transform,m.IDENTITY)?(this._globe=this._scene.globe,this._ellipsoid=o(this._globe)?this._globe.ellipsoid:this._scene.mapProjection.ellipsoid):(this._globe=void 0,this._ellipsoid=l.UNIT_SPHERE);var e=this._ellipsoid.maximumRadius;this._rotateFactor=1/e,this._rotateRateRangeAdjustment=e;var r=this._scene,i=r.mode;i===E.SCENE2D?O(this):i===E.COLUMBUS_VIEW?(this._horizontalRotationAxis=t.UNIT_Z,k(this)):i===E.SCENE3D&&(this._horizontalRotationAxis=void 0,K(this)),J(this),this._aggregator.reset()},Q.prototype.isDestroyed=function(){return!1},Q.prototype.destroy=function(){return this._tweens.removeAll(),this._aggregator=this._aggregator&&this._aggregator.destroy(),a(this)},Q}),r("Shaders/PostProcessFilters/AdditiveBlend",[],function(){"use strict";return"uniform sampler2D u_texture0;\nuniform sampler2D u_texture1;\nuniform vec2 u_center;\nuniform float u_radius;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec4 color0 = texture2D(u_texture0, v_textureCoordinates);\nvec4 color1 = texture2D(u_texture1, v_textureCoordinates);\nfloat x = length(gl_FragCoord.xy - u_center) / u_radius;\nfloat t = smoothstep(0.5, 0.8, x);\ngl_FragColor = mix(color0 + color1, color0, t);\n}\n"}),r("Shaders/PostProcessFilters/BrightPass",[],function(){"use strict";return"uniform sampler2D u_texture;\nuniform float u_avgLuminance;\nuniform float u_threshold;\nuniform float u_offset;\nvarying vec2 v_textureCoordinates;\nfloat key(float avg)\n{\nfloat guess = 1.5 - (1.5 / (avg * 0.1 + 1.0));\nreturn max(0.0, guess) + 0.1;\n}\nvoid main()\n{\nvec4 color = texture2D(u_texture, v_textureCoordinates);\nvec3 xyz = czm_RGBToXYZ(color.rgb);\nfloat luminance = xyz.r;\nfloat scaledLum = key(u_avgLuminance) * luminance / u_avgLuminance;\nfloat brightLum = max(scaledLum - u_threshold, 0.0);\nfloat brightness = brightLum / (u_offset + brightLum);\nxyz.r = brightness;\ngl_FragColor = vec4(czm_XYZToRGB(xyz), 1.0);\n}\n"}),r("Shaders/PostProcessFilters/GaussianBlur1D",[],function(){"use strict";return"#define SAMPLES 8\nuniform float delta;\nuniform float sigma;\nuniform float direction;\nuniform sampler2D u_texture;\nuniform vec2 u_step;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec2 st = v_textureCoordinates;\nvec2 dir = vec2(1.0 - direction, direction);\nvec3 g;\ng.x = 1.0 / (sqrt(czm_twoPi) * sigma);\ng.y = exp((-0.5 * delta * delta) / (sigma * sigma));\ng.z = g.y * g.y;\nvec4 result = texture2D(u_texture, st) * g.x;\nfor (int i = 1; i < SAMPLES; ++i)\n{\ng.xy *= g.yz;\nvec2 offset = float(i) * dir * u_step;\nresult += texture2D(u_texture, st - offset) * g.x;\nresult += texture2D(u_texture, st + offset) * g.x;\n}\ngl_FragColor = result;\n}\n"}),r("Scene/SunPostProcess",["../Core/BoundingRectangle","../Core/Cartesian2","../Core/Cartesian4","../Core/Color","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/Math","../Core/Matrix4","../Core/PixelFormat","../Core/Transforms","../Renderer/ClearCommand","../Renderer/Framebuffer","../Renderer/PassState","../Renderer/PixelDatatype","../Renderer/Renderbuffer","../Renderer/RenderbufferFormat","../Renderer/RenderState","../Renderer/Texture","../Shaders/PostProcessFilters/AdditiveBlend","../Shaders/PostProcessFilters/BrightPass","../Shaders/PostProcessFilters/GaussianBlur1D","../Shaders/PostProcessFilters/PassThrough"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S){"use strict";var w=function(){this._fbo=void 0,this._downSampleFBO1=void 0,this._downSampleFBO2=void 0,this._clearFBO1Command=void 0,this._clearFBO2Command=void 0,this._downSampleCommand=void 0,this._brightPassCommand=void 0,this._blurXCommand=void 0,this._blurYCommand=void 0,this._blendCommand=void 0,this._fullScreenCommand=void 0,this._downSamplePassState=new p,this._downSamplePassState.scissorTest={enable:!0,rectangle:new e},this._upSamplePassState=new p,this._upSamplePassState.scissorTest={enabled:!0,rectangle:new e},this._uCenter=new t,this._uRadius=void 0,this._blurStep=new t};w.prototype.clear=function(e,t){var r=this._clearFBO1Command;i.clone(n(t,i.BLACK),r.color),r.execute(e),r=this._clearFBO2Command,i.clone(n(t,i.BLACK),r.color),r.execute(e)},w.prototype.execute=function(e,t){this._downSampleCommand.execute(e,this._downSamplePassState),this._brightPassCommand.execute(e,this._downSamplePassState),this._blurXCommand.execute(e,this._downSamplePassState),this._blurYCommand.execute(e,this._downSamplePassState),this._fullScreenCommand.framebuffer=t,this._blendCommand.framebuffer=t,this._fullScreenCommand.execute(e),this._blendCommand.execute(e,this._upSamplePassState)};var T=new e,b=new e,x=new r,P=new t,A=new t,I=new l;return w.prototype.update=function(e){var r=e.drawingBufferWidth,n=e.drawingBufferHeight,a=this;if(!o(this._downSampleCommand)){this._clearFBO1Command=new h({color:new i}),this._clearFBO2Command=new h({color:new i});var p,w={};this._downSampleCommand=e.createViewportQuadCommand(S,{renderState:p,uniformMap:w,owner:this}),w={u_avgLuminance:function(){return.5},u_threshold:function(){return.25},u_offset:function(){return.1}},this._brightPassCommand=e.createViewportQuadCommand(C,{renderState:p,uniformMap:w,owner:this});var M=1,D=2;w={delta:function(){return M},sigma:function(){return D},direction:function(){return 0}},this._blurXCommand=e.createViewportQuadCommand(E,{renderState:p,uniformMap:w,owner:this}),w={delta:function(){return M},sigma:function(){return D},direction:function(){return 1}},this._blurYCommand=e.createViewportQuadCommand(E,{renderState:p,uniformMap:w,owner:this}),w={u_center:function(){return a._uCenter},u_radius:function(){return a._uRadius}},this._blendCommand=e.createViewportQuadCommand(y,{renderState:p,uniformMap:w,owner:this}),w={},this._fullScreenCommand=e.createViewportQuadCommand(S,{renderState:p,uniformMap:w,owner:this})}var R=Math.pow(2,Math.ceil(Math.log(r)/Math.log(2))-2),O=Math.pow(2,Math.ceil(Math.log(n)/Math.log(2))-2),N=Math.max(R,O),L=T;L.width=r,L.height=n;var F=b;F.width=N,F.height=N;var B=this._fbo,V=o(B)&&B.getColorTexture(0)||void 0;if(!o(V)||V.width!==r||V.height!==n){B=B&&B.destroy(),this._downSampleFBO1=this._downSampleFBO1&&this._downSampleFBO1.destroy(),this._downSampleFBO2=this._downSampleFBO2&&this._downSampleFBO2.destroy(),this._blurStep.x=this._blurStep.y=1/N;var z=[new g({context:e,width:r,height:n})];B=e.depthTexture?this._fbo=new d({context:e,colorTextures:z,depthTexture:new g({context:e,width:r,height:n,pixelFormat:u.DEPTH_COMPONENT,pixelDatatype:m.UNSIGNED_SHORT})}):this._fbo=new d({context:e,colorTextures:z,depthRenderbuffer:new f({context:e,format:v.DEPTH_COMPONENT16})}),this._downSampleFBO1=new d({context:e,colorTextures:[new g({context:e,width:N,height:N})]}),this._downSampleFBO2=new d({context:e,colorTextures:[new g({context:e,width:N,height:N})]}),this._clearFBO1Command.framebuffer=this._downSampleFBO1,this._clearFBO2Command.framebuffer=this._downSampleFBO2,this._downSampleCommand.framebuffer=this._downSampleFBO1,this._brightPassCommand.framebuffer=this._downSampleFBO2,this._blurXCommand.framebuffer=this._downSampleFBO1,this._blurYCommand.framebuffer=this._downSampleFBO2;var k=_.fromCache({viewport:F}),U=_.fromCache();this._downSampleCommand.uniformMap.u_texture=function(){return B.getColorTexture(0)},this._downSampleCommand.renderState=k,this._brightPassCommand.uniformMap.u_texture=function(){return a._downSampleFBO1.getColorTexture(0)},this._brightPassCommand.renderState=k,this._blurXCommand.uniformMap.u_texture=function(){return a._downSampleFBO2.getColorTexture(0)},this._blurXCommand.uniformMap.u_step=function(){return a._blurStep},this._blurXCommand.renderState=k,this._blurYCommand.uniformMap.u_texture=function(){return a._downSampleFBO1.getColorTexture(0)},this._blurYCommand.uniformMap.u_step=function(){return a._blurStep},this._blurYCommand.renderState=k,this._blendCommand.uniformMap.u_texture0=function(){return B.getColorTexture(0)},this._blendCommand.uniformMap.u_texture1=function(){return a._downSampleFBO2.getColorTexture(0)},this._blendCommand.renderState=U,this._fullScreenCommand.uniformMap.u_texture=function(){return B.getColorTexture(0)},this._fullScreenCommand.renderState=U}var G=e.uniformState,W=G.sunPositionWC,H=G.view,q=G.viewProjection,j=G.projection,Y=l.computeViewportTransformation(L,0,1,I),X=l.multiplyByPoint(H,W,x),Z=c.pointToGLWindowCoordinates(q,Y,W,P);X.x+=s.SOLAR_RADIUS;var K=c.pointToGLWindowCoordinates(j,Y,X,X),J=30*t.magnitude(t.subtract(K,Z,K))*2,Q=A;Q.x=J,Q.y=J;var $=this._upSamplePassState.scissorTest.rectangle;return $.x=Math.max(Z.x-.5*Q.x,0),$.y=Math.max(Z.y-.5*Q.y,0),$.width=Math.min(Q.x,r),$.height=Math.min(Q.y,n),this._uCenter=t.clone(Z,this._uCenter),this._uRadius=.5*Math.max(Q.x,Q.y),Y=l.computeViewportTransformation(F,0,1,I),Z=c.pointToGLWindowCoordinates(q,Y,W,P),Q.x*=R/r,Q.y*=O/n,$=this._downSamplePassState.scissorTest.rectangle,$.x=Math.max(Z.x-.5*Q.x,0),$.y=Math.max(Z.y-.5*Q.y,0),$.width=Math.min(Q.x,r),$.height=Math.min(Q.y,n),this._downSamplePassState.context=e,this._upSamplePassState.context=e,this._fbo},w.prototype.isDestroyed=function(){return!1},w.prototype.destroy=function(){return this._fbo=this._fbo&&this._fbo.destroy(),this._downSampleFBO1=this._downSampleFBO1&&this._downSampleFBO1.destroy(),this._downSampleFBO2=this._downSampleFBO2&&this._downSampleFBO2.destroy(),this._downSampleCommand=this._downSampleCommand&&this._downSampleCommand.shaderProgram&&this._downSampleCommand.shaderProgram.destroy(),this._brightPassCommand=this._brightPassCommand&&this._brightPassCommand.shaderProgram&&this._brightPassCommand.shaderProgram.destroy(),this._blurXCommand=this._blurXCommand&&this._blurXCommand.shaderProgram&&this._blurXCommand.shaderProgram.destroy(),this._blurYCommand=this._blurYCommand&&this._blurYCommand.shaderProgram&&this._blurYCommand.shaderProgram.destroy(),this._blendCommand=this._blendCommand&&this._blendCommand.shaderProgram&&this._blendCommand.shaderProgram.destroy(),this._fullScreenCommand=this._fullScreenCommand&&this._fullScreenCommand.shaderProgram&&this._fullScreenCommand.shaderProgram.destroy(),a(this)},w}),r("Scene/Scene",["../Core/BoundingRectangle","../Core/BoundingSphere","../Core/BoxGeometry","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/ColorGeometryInstanceAttribute","../Core/createGuid","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/DeveloperError","../Core/EllipsoidGeometry","../Core/Event","../Core/GeographicProjection","../Core/GeometryInstance","../Core/GeometryPipeline","../Core/getTimestamp","../Core/Intersect","../Core/Interval","../Core/JulianDate","../Core/Math","../Core/Matrix4","../Core/mergeSort","../Core/Occluder","../Core/ShowGeometryInstanceAttribute","../Renderer/ClearCommand","../Renderer/ComputeEngine","../Renderer/Context","../Renderer/ContextLimits","../Renderer/PassState","../Renderer/ShaderProgram","../Renderer/ShaderSource","./Camera","./CreditDisplay","./CullingVolume","./DepthPlane","./Fog","./FrameState","./FrustumCommands","./FXAA","./GlobeDepth","./OIT","./OrthographicFrustum","./Pass","./PerformanceDisplay","./PerInstanceColorAppearance","./PerspectiveFrustum","./PerspectiveOffCenterFrustum","./PickDepth","./Primitive","./PrimitiveCollection","./SceneMode","./SceneTransforms","./SceneTransitioner","./ScreenSpaceCameraController","./SunPostProcess","./TweenCollection"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe){"use strict";function ae(e,t){var r=Math.max(Math.abs(e.x),Math.abs(t.x)),i=Math.max(Math.abs(e.y),Math.abs(t.y)),n=Math.max(Math.abs(e.z),Math.abs(t.z));return Math.max(Math.max(r,i),n)}function se(e,t,r){var i=1/Math.max(1,ae(e.position,t.position));return n.multiplyByScalar(e.position,i,Le),n.multiplyByScalar(t.position,i,Fe),n.equalsEpsilon(Le,Fe,r)&&n.equalsEpsilon(e.direction,t.direction,r)&&n.equalsEpsilon(e.up,t.up,r)&&n.equalsEpsilon(e.right,t.right,r)&&T.equalsEpsilon(e.transform,t.transform,r)}function le(e){var t=e.globe;if(e._mode===ee.SCENE3D&&c(t)){var r=t.ellipsoid;return Be.radius=r.minimumRadius,Ne=x.fromBoundingSphere(Be,e._camera.positionWC,Ne)}return void 0}function ue(e){e.render=!1,e.pick=!1}function ce(e,t,r){var i=e._camera,n=e._frameState;n.commandList.length=0,n.mode=e._mode,n.morphTime=e.morphTime,n.mapProjection=e.mapProjection, -n.frameNumber=t,n.time=S.clone(r,n.time),n.camera=i,n.cullingVolume=i.frustum.computeCullingVolume(i.positionWC,i.directionWC,i.upWC),n.occluder=le(e),ue(n.passes)}function he(e,t,r,i,n){n.length=i;for(var o=0;i>o;++o){var a=Math.max(e,Math.pow(r,o)*e),s=Math.min(t,r*a),l=n[o];c(l)?(l.near=a,l.far=s):l=n[o]=new U(a,s)}}function de(e,t,r){e.debugShowFrustums&&(t.debugOverlappingFrustums=0);for(var i=e._frustumCommandsList,n=i.length,o=0;n>o;++o){var a=i[o],s=a.near,l=a.far;if(!(r.start>l)){if(r.stop<s)break;var u=t instanceof A?j.OPAQUE:t.pass,h=a.indices[u]++;if(a.commands[u][h]=t,e.debugShowFrustums&&(t.debugOverlappingFrustums|=1<<o),t.executeInClosestFrustum)break}}if(e.debugShowFrustums){var d=e._debugFrustumStatistics.commandsInFrustums;d[t.debugOverlappingFrustums]=c(d[t.debugOverlappingFrustums])?d[t.debugOverlappingFrustums]+1:1,++e._debugFrustumStatistics.totalCommands}}function pe(e){var t=e._computeCommandList,r=e._overlayCommandList,i=e._frameState.commandList,n=e._frameState.cullingVolume,o=e._camera,a=o.directionWC,s=o.positionWC;e.debugShowFrustums&&(e._debugFrustumStatistics={totalCommands:0,commandsInFrustums:{}});for(var l=e._frustumCommandsList,u=l.length,h=j.NUMBER_OF_PASSES,d=0;u>d;++d)for(var p=0;h>p;++p)l[d].indices[p]=0;t.length=0,r.length=0;var m,f=Number.MAX_VALUE,v=Number.MIN_VALUE,_=!1;e._frameState.mode===ee.SCENE3D&&(m=e._frameState.occluder);for(var g=Ve.planes,y=0;5>y;++y)g[y]=n.planes[y];n=Ve;for(var E=i.length,S=0;E>S;++S){var w=i[S],T=w.pass;if(T===j.COMPUTE)t.push(w);else if(T===j.OVERLAY)r.push(w);else{var b=w.boundingVolume;if(c(b)){if(w.cull&&(n.computeVisibility(b)===C.OUTSIDE||c(m)&&b.isOccluded(m)))continue;ze=b.computePlaneDistances(s,a,ze),f=Math.min(f,ze.start),v=Math.max(v,ze.stop)}else ze.start=o.frustum.near,ze.stop=o.frustum.far,_=!(w instanceof A);de(e,w,ze)}}_?(f=o.frustum.near,v=o.frustum.far):(f=Math.min(Math.max(f,o.frustum.near),o.frustum.far),v=Math.max(Math.min(v,o.frustum.far),f));var x=e.farToNearRatio,P=Math.ceil(Math.log(v/f)/Math.log(x));f!==Number.MAX_VALUE&&(P!==u||0!==l.length&&(f<l[0].near||v>l[u-1].far))&&(he(f,v,x,P,l),pe(e))}function me(e){var t={},r=e.vertexAttributes;for(var i in r)r.hasOwnProperty(i)&&(t[i]=r[i].index);return t}function fe(e,t,r){var i=t.context,n=u(r,e.shaderProgram),o=n.fragmentShaderSource.clone();o.sources=o.sources.map(function(e){return e=N.replaceMain(e,"czm_Debug_main")});var s="void main() \n{ \n czm_Debug_main(); \n";if(t.debugShowCommands){c(e._debugColor)||(e._debugColor=a.fromRandom());var l=e._debugColor;s+=" gl_FragColor.rgb *= vec3("+l.red+", "+l.green+", "+l.blue+"); \n"}if(t.debugShowFrustums){var h=1&e.debugOverlappingFrustums?"1.0":"0.0",d=2&e.debugOverlappingFrustums?"1.0":"0.0",p=4&e.debugOverlappingFrustums?"1.0":"0.0";s+=" gl_FragColor.rgb *= vec3("+h+", "+d+", "+p+"); \n"}s+="}",o.sources.push(s);var m=me(n);return O.fromCache({context:i,vertexShaderSource:n.vertexShaderSource,fragmentShaderSource:o,attributeLocations:m})}function ve(e,t,r,i,n){if(c(e.shaderProgram)||c(n)){var o=fe(e,t,n);e.execute(t.context,r,i,o),o.destroy()}}function _e(e,t,i,o,a,l,u){if((!c(t.debugCommandFilter)||t.debugCommandFilter(e))&&(t.debugShowCommands||t.debugShowFrustums?ve(e,t,o,a,l):e.execute(i,o,a,l),e.debugShowBoundingVolume&&c(e.boundingVolume))){var h=t._frameState,d=e.boundingVolume;c(t._debugVolume)&&t._debugVolume.destroy();var p,f=n.clone(d.center);if(h.mode!==ee.SCENE3D){f=T.multiplyByPoint(ke,f,f);var v=h.mapProjection,y=v.unproject(f);f=v.ellipsoid.cartographicToCartesian(y)}if(c(d.radius)){var C=d.radius;p=g.toWireframe(m.createGeometry(new m({radii:new n(C,C,C),vertexFormat:X.FLAT_VERTEX_FORMAT}))),t._debugVolume=new Q({geometryInstances:new _({geometry:p,modelMatrix:T.multiplyByTranslation(T.IDENTITY,f,new T),attributes:{color:new s(1,0,0,1)}}),appearance:new X({flat:!0,translucent:!1}),asynchronous:!1})}else{var E=d.halfAxes;p=g.toWireframe(r.createGeometry(r.fromDimensions({dimensions:new n(2,2,2),vertexFormat:X.FLAT_VERTEX_FORMAT}))),t._debugVolume=new Q({geometryInstances:new _({geometry:p,modelMatrix:T.fromRotationTranslation(E,f,new T),attributes:{color:new s(1,0,0,1)}}),appearance:new X({flat:!0,translucent:!1}),asynchronous:!1})}var S=h.commandList,w=h.commandList=[];t._debugVolume.update(h);var b;c(u)&&(b=o.framebuffer,o.framebuffer=u),w[0].execute(i,o),c(b)&&(o.framebuffer=b),h.commandList=S}}function ge(e,t){if(c(e)){for(var r=t.mode===ee.SCENE3D?t.occluder:void 0,i=t.cullingVolume,n=Ve.planes,o=0;5>o;++o)n[o]=i.planes[o];i=Ve;var a=e.boundingVolume;return!(!c(e)||c(e.boundingVolume)&&e.cull&&(i.computeVisibility(a)===C.OUTSIDE||c(r)&&a.isOccluded(r)))}}function ye(e,t,r){return t.boundingVolume.distanceSquaredTo(r)-e.boundingVolume.distanceSquaredTo(r)}function Ce(e,t,r,i){var n=e.context;b(i,ye,e._camera.positionWC);for(var o=i.length,a=0;o>a;++a)t(i[a],e,n,r)}function Ee(e,t){var r=e._debugGlobeDepths[t];return!c(r)&&e.context.depthTexture&&(r=new W,e._debugGlobeDepths[t]=r),r}function Se(e,t){var r=e._pickDepths[t];return c(r)||(r=new J,e._pickDepths[t]=r),r}function we(e,t,r,i){var n,o,s=e._frameState,l=e._camera,u=e.context,h=u.uniformState;c(e.sun)&&e.sunBloom!==e._sunBloom?(e.sunBloom?e._sunPostProcess=new ne:c(e._sunPostProcess)&&(e._sunPostProcess=e._sunPostProcess.destroy()),e._sunBloom=e.sunBloom):!c(e.sun)&&c(e._sunPostProcess)&&(e._sunPostProcess=e._sunPostProcess.destroy(),e._sunBloom=!1);var d,p=s.passes.render,m=p&&c(e.skyBox)?e.skyBox.update(s):void 0,f=c(e.globe)&&e.globe._surface._tilesToRender.length>0,v=p&&c(e.skyAtmosphere)?e.skyAtmosphere.update(s):void 0,_=p&&c(e.sun)?e.sun.update(e):void 0,g=c(_)?_.drawCommand:void 0,y=c(_)?_.computeCommand:void 0,C=ge(g,s),E=p&&c(e.moon)?e.moon.update(s):void 0,S=ge(E,s),w=t.framebuffer;d=c(l.frustum.fov)?l.frustum.clone(Ue):c(l.frustum.infiniteProjectionMatrix)?l.frustum.clone(Ge):l.frustum.clone(We);var T=e._clearColorCommand;a.clone(r,T.color),T.execute(u,t);var b=!i&&c(e._globeDepth);b&&(e._globeDepth.update(u),e._globeDepth.clear(u,t,r));var x=!1,P=e._frustumCommandsList,A=P.length;for(n=0;A>n;++n)if(P[n].indices[j.TRANSLUCENT]>0){x=!0;break}var I=c(e.globe)&&(!e.globe.depthTestAgainstTerrain||e.mode===ee.SCENE2D),M=I&&e.mode===ee.SCENE3D;M&&e._depthPlane.update(s);var D=!i&&x&&c(e._oit)&&e._oit.isSupported();D&&(e._oit.update(u,e._globeDepth.framebuffer),e._oit.clear(u,t,r),D=D&&e._oit.isSupported());var R=!i&&e.fxaa;if(R&&(e._fxaa.update(u),e._fxaa.clear(u,t,r)),C&&e.sunBloom?t.framebuffer=e._sunPostProcess.update(u):b?t.framebuffer=e._globeDepth.framebuffer:R&&(t.framebuffer=e._fxaa.getColorFramebuffer()),c(t.framebuffer)&&T.execute(u,t),d.near=l.frustum.near,d.far=l.frustum.far,h.updateFrustum(d),c(m)&&_e(m,e,u,t),c(v)&&f&&_e(v,e,u,t),C&&(c(y)&&y.execute(e._computeEngine),g.execute(u,t),e.sunBloom)){var O;O=b?e._globeDepth.framebuffer:R?e._fxaa.getColorFramebuffer():w,e._sunPostProcess.execute(u,O),t.framebuffer=O}S&&E.execute(u,t);var N;D?(c(e._executeOITFunction)||(e._executeOITFunction=function(e,t,r,i){e._oit.executeCommands(e,t,r,i)}),N=e._executeOITFunction):N=Ce;var L=e._depthClearCommand;for(n=0;A>n;++n){var F=A-n-1,B=P[F];d.near=0!==F?B.near*Oe:B.near,d.far=B.far;var V,z=e.debugShowGlobeDepth?Ee(e,F):e._globeDepth;e.debugShowGlobeDepth&&c(z)&&b&&(V=t.framebuffer,t.framebuffer=z.framebuffer),h.updateFrustum(d),L.execute(u,t);var k=B.commands[j.GLOBE],U=B.indices[j.GLOBE];for(o=0;U>o;++o)_e(k[o],e,u,t);for(c(z)&&b&&(e.copyGlobeDepth||e.debugShowGlobeDepth)&&(z.update(u),z.executeCopyDepth(u,t)),e.debugShowGlobeDepth&&c(z)&&b&&(t.framebuffer=V),k=B.commands[j.GROUND],U=B.indices[j.GROUND],o=0;U>o;++o)_e(k[o],e,u,t);I&&(L.execute(u,t),M&&e._depthPlane.execute(u,t));for(var G=j.GROUND+1,W=j.TRANSLUCENT,H=G;W>H;++H)for(k=B.commands[H],U=B.indices[H],o=0;U>o;++o)_e(k[o],e,u,t);if(0!==F&&(d.near=B.near,h.updateFrustum(d)),k=B.commands[j.TRANSLUCENT],k.length=B.indices[j.TRANSLUCENT],N(e,_e,t,k),c(z)&&b){var q=Se(e,F);q.update(u,z.framebuffer.depthStencilTexture),q.executeCopyDepth(u,t)}}if(e.debugShowGlobeDepth&&b){var Y=Ee(e,e.debugShowDepthFrustum-1);Y.executeDebugGlobeDepth(u,t)}if(e.debugShowPickDepth&&b){var X=Se(e,e.debugShowDepthFrustum-1);X.executeDebugPickDepth(u,t)}D&&(t.framebuffer=R?e._fxaa.getColorFramebuffer():void 0,e._oit.execute(u,t)),R&&(!D&&b&&(t.framebuffer=e._fxaa.getColorFramebuffer(),e._globeDepth.executeCopyColor(u,t)),t.framebuffer=w,e._fxaa.execute(u,t)),D||R||!b||(t.framebuffer=w,e._globeDepth.executeCopyColor(u,t))}function Te(e){for(var t=e._computeCommandList,r=t.length,i=0;r>i;++i)t[i].execute(e._computeEngine)}function be(e,t){for(var r=e.context,i=e._overlayCommandList,n=i.length,o=0;n>o;++o)i[o].execute(r,t)}function xe(e){var t=e._frameState;e._globe&&e._globe.update(t),e._groundPrimitives.update(t),e._primitives.update(t)}function Pe(e){for(var t=e.afterRender,r=0,i=t.length;i>r;++r)t[r]();t.length=0}function Ae(e,t){c(t)||(t=S.now());var r=e._camera;se(r,e._cameraClone,w.EPSILON6)?e._cameraStartFired&&y()-e._cameraMovedTime>e.cameraEventWaitTime&&(r.moveEnd.raiseEvent(),e._cameraStartFired=!1):(e._cameraStartFired||(r.moveStart.raiseEvent(),e._cameraStartFired=!0),e._cameraMovedTime=y(),L.clone(r,e._cameraClone)),e._preRender.raiseEvent(e,t);var i=e.context,n=i.uniformState,o=e._frameState,s=w.incrementWrap(o.frameNumber,15e6,1);ce(e,s,t),o.passes.render=!0,o.creditDisplay.beginFrame(),e.fog.update(o),n.update(o),e._computeCommandList.length=0,e._overlayCommandList.length=0,xe(e),pe(e);var l=e._passState;if(l.framebuffer=void 0,l.blendingEnabled=void 0,l.scissorTest=void 0,Te(e),we(e,l,u(e.backgroundColor,a.BLACK)),be(e,l),o.creditDisplay.endFrame(),e.debugShowFramesPerSecond){if(!c(e._performanceDisplay)){var h=document.createElement("div");h.className="cesium-performanceDisplay-defaultContainer";var d=e._canvas.parentNode;d.appendChild(h);var p=new Y({container:h});e._performanceDisplay=p,e._performanceContainer=h}e._performanceDisplay.update()}else c(e._performanceDisplay)&&(e._performanceDisplay=e._performanceDisplay&&e._performanceDisplay.destroy(),e._performanceContainer.parentNode.removeChild(e._performanceContainer));i.endFrame(),Pe(o),e._postRender.raiseEvent(e,t)}function Ie(e,t,r,i){var o=e._camera,a=o.frustum,s=e.drawingBufferWidth,l=e.drawingBufferHeight,u=2/s*t.x-1;u*=.5*(a.right-a.left);var c=2/l*(l-t.y)-1;c*=.5*(a.top-a.bottom);var h=T.clone(o.transform,Xe);o._setTransform(T.IDENTITY);var d=n.clone(o.position,qe);n.multiplyByScalar(o.right,u,je),n.add(je,d,d),n.multiplyByScalar(o.up,c,je),n.add(je,d,d),o._setTransform(h),n.fromElements(d.z,d.x,d.y,d);var p=a.getPixelDimensions(s,l,1,Ye),m=He;return m.right=.5*p.x,m.left=-m.right,m.top=.5*p.y,m.bottom=-m.top,m.near=a.near,m.far=a.far,m.computeCullingVolume(d,o.directionWC,o.upWC)}function Me(e,t,r,i){var n=e._camera,o=n.frustum,a=o.near,s=e.drawingBufferWidth,l=e.drawingBufferHeight,u=Math.tan(.5*o.fovy),c=o.aspectRatio*u,h=2/s*t.x-1,d=2/l*(l-t.y)-1,p=h*a*c,m=d*a*u,f=o.getPixelDimensions(s,l,1,Ye),v=f.x*r*.5,_=f.y*i*.5,g=Ze;return g.top=m+_,g.bottom=m-_,g.right=p+v,g.left=p-v,g.near=a,g.far=o.far,g.computeCullingVolume(n.positionWC,n.directionWC,n.upWC)}function De(e,t,r,i){return e._mode===ee.SCENE2D?Ie(e,t,r,i):Me(e,t,r,i)}var Re=function(e){e=u(e,u.EMPTY_OBJECT);var t=e.canvas,r=e.contextOptions,i=e.creditContainer,n=new M(t,r);c(i)||(i=document.createElement("div"),i.style.position="absolute",i.style.bottom="0",i.style["text-shadow"]="0px 0px 2px #000000",i.style.color="#ffffff",i.style["font-size"]="10px",i.style["padding-right"]="5px",t.parentNode.appendChild(i)),this._id=l(),this._frameState=new k(n,new F(i)),this._frameState.scene3DOnly=u(e.scene3DOnly,!1),this._passState=new R(n),this._canvas=t,this._context=n,this._computeEngine=new I(n),this._globe=void 0,this._primitives=new $,this._groundPrimitives=new $,this._tweens=new oe,this._shaderFrameCount=0,this._sunPostProcess=void 0,this._computeCommandList=[],this._frustumCommandsList=[],this._overlayCommandList=[],this._pickFramebuffer=void 0,this._useOIT=u(e.orderIndependentTranslucency,!0),this._executeOITFunction=void 0;var o;n.depthTexture&&(o=new W);var s;this._useOIT&&c(o)&&(s=new H(n)),this._globeDepth=o,this._depthPlane=new V,this._oit=s,this._fxaa=new G,this._clearColorCommand=new A({color:new a,stencil:0,owner:this}),this._depthClearCommand=new A({depth:1,owner:this}),this._pickDepths=[],this._debugGlobeDepths=[],this._transitioner=new re(this),this._renderError=new f,this._preRender=new f,this._postRender=new f,this._cameraStartFired=!1,this._cameraMovedTime=void 0,this.rethrowRenderErrors=!1,this.completeMorphOnUserInput=!0,this.morphStart=new f,this.morphComplete=new f,this.skyBox=void 0,this.skyAtmosphere=void 0,this.sun=void 0,this.sunBloom=!0,this._sunBloom=void 0,this.moon=void 0,this.backgroundColor=a.clone(a.BLACK),this._mode=ee.SCENE3D,this._mapProjection=c(e.mapProjection)?e.mapProjection:new v,this._transitioner=new re(this,this._mapProjection.ellipsoid),this.morphTime=1,this.farToNearRatio=1e3,this.debugCommandFilter=void 0,this.debugShowCommands=!1,this.debugShowFrustums=!1,this._debugFrustumStatistics=void 0,this.debugShowFramesPerSecond=!1,this.debugShowGlobeDepth=!1,this.debugShowDepthFrustum=1,this.fxaa=!0,this.cameraEventWaitTime=500,this.copyGlobeDepth=!1,this.fog=new z,this._performanceDisplay=void 0,this._debugVolume=void 0;var h=new L(this);this._camera=h,this._cameraClone=L.clone(h),this._screenSpaceCameraController=new ie(this);var d=h.frustum.near,p=h.frustum.far,m=Math.ceil(Math.log(p/d)/Math.log(this.farToNearRatio));he(d,p,this.farToNearRatio,m,this._frustumCommandsList),ce(this,0,S.now()),this.initializeFrame()},Oe=.99;h(Re.prototype,{canvas:{get:function(){return this._canvas}},drawingBufferHeight:{get:function(){return this._context.drawingBufferHeight}},drawingBufferWidth:{get:function(){return this._context.drawingBufferWidth}},maximumAliasedLineWidth:{get:function(){return D.maximumAliasedLineWidth}},maximumCubeMapSize:{get:function(){return D.maximumCubeMapSize}},pickPositionSupported:{get:function(){return this._context.depthTexture}},globe:{get:function(){return this._globe},set:function(e){this._globe=this._globe&&this._globe.destroy(),this._globe=e}},primitives:{get:function(){return this._primitives}},groundPrimitives:{get:function(){return this._groundPrimitives}},camera:{get:function(){return this._camera}},screenSpaceCameraController:{get:function(){return this._screenSpaceCameraController}},mapProjection:{get:function(){return this._mapProjection}},frameState:{get:function(){return this._frameState}},tweens:{get:function(){return this._tweens}},imageryLayers:{get:function(){return this.globe.imageryLayers}},terrainProvider:{get:function(){return this.globe.terrainProvider},set:function(e){this.globe.terrainProvider=e}},renderError:{get:function(){return this._renderError}},preRender:{get:function(){return this._preRender}},postRender:{get:function(){return this._postRender}},context:{get:function(){return this._context}},debugFrustumStatistics:{get:function(){return this._debugFrustumStatistics}},scene3DOnly:{get:function(){return this._frameState.scene3DOnly}},orderIndependentTranslucency:{get:function(){return c(this._oit)}},id:{get:function(){return this._id}},mode:{get:function(){return this._mode},set:function(e){e===ee.SCENE2D?this.morphTo2D(0):e===ee.SCENE3D?this.morphTo3D(0):e===ee.COLUMBUS_VIEW&&this.morphToColumbusView(0),this._mode=e}},numberOfFrustums:{get:function(){return this._frustumCommandsList.length}}});var Ne,Le=new n,Fe=new n,Be=new t,Ve=new B,ze=new E,ke=new T(0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1);ke=T.inverseTransformation(ke,ke);var Ue=new Z,Ge=new K,We=new q;Re.prototype.initializeFrame=function(){120===this._shaderFrameCount++&&(this._shaderFrameCount=0,this._context.shaderCache.destroyReleasedShaderPrograms()),this._tweens.update(),this._camera.update(this._mode),this._screenSpaceCameraController.update()},Re.prototype.render=function(e){try{Ae(this,e)}catch(t){if(this._renderError.raiseEvent(this,t),this.rethrowRenderErrors)throw t}},Re.prototype.clampLineWidth=function(e){this._context;return Math.max(D.minimumAliasedLineWidth,Math.min(e,D.maximumAliasedLineWidth))};var He=new q,qe=new n,je=new n,Ye=(new i,new i),Xe=new T,Ze=new K,Ke=3,Je=3,Qe=new e(0,0,Ke,Je),$e=new a(0,0,0,0),et=new i;Re.prototype.pick=function(e){var t=this._context,r=t.uniformState,i=this._frameState,n=te.transformWindowToDrawingBuffer(this,e,et);c(this._pickFramebuffer)||(this._pickFramebuffer=t.createPickFramebuffer()),ce(this,i.frameNumber,i.time),i.cullingVolume=De(this,n,Ke,Je),i.passes.pick=!0,r.update(i),xe(this),pe(this),Qe.x=n.x-.5*(Ke-1),Qe.y=this.drawingBufferHeight-n.y-.5*(Je-1),we(this,this._pickFramebuffer.begin(Qe),$e,!0);var o=this._pickFramebuffer.end(Qe);return t.endFrame(),Pe(i),o};var tt=(new n,new n,new o),rt=new o(1,1/255,1/65025,1/160581375);return Re.prototype.pickPosition=function(e,t){var r=this._context,i=r.uniformState,n=te.transformWindowToDrawingBuffer(this,e,et);n.y=this.drawingBufferHeight-n.y;var a,s=this._camera;c(s.frustum.fov)?a=s.frustum.clone(Ue):c(s.frustum.infiniteProjectionMatrix)&&(a=s.frustum.clone(Ge));for(var l=this.numberOfFrustums,u=0;l>u;++u){var h=Se(this,u),d=r.readPixels({x:n.x,y:n.y,width:1,height:1,framebuffer:h.framebuffer}),p=o.unpack(d,0,tt);o.divideByScalar(p,255,p);var m=o.dot(p,rt);if(m>0&&1>m){var f=this._frustumCommandsList[u];return a.near=f.near*(0!==u?Oe:1),a.far=f.far,i.updateFrustum(a),te.drawingBufferToWgs84Coordinates(this,n,m,t)}}return void 0},Re.prototype.drillPick=function(e,t){var r,i,n=[],o=[],a=[];c(t)||(t=Number.MAX_VALUE);for(var s=this.pick(e);c(s)&&c(s.primitive)&&(n.push(s),!(0>=--t));){var l=s.primitive,u=!1;"function"==typeof l.getGeometryInstanceAttributes&&c(s.id)&&(i=l.getGeometryInstanceAttributes(s.id),c(i)&&c(i.show)&&(u=!0,i.show=P.toValue(!1,i.show),a.push(i))),u||(l.show=!1,o.push(l)),s=this.pick(e)}for(r=0;r<o.length;++r)o[r].show=!0;for(r=0;r<a.length;++r)i=a[r],i.show=P.toValue(!0,i.show);return n},Re.prototype.completeMorph=function(){this._transitioner.completeMorph()},Re.prototype.morphTo2D=function(e){var t,r=this.globe;t=c(r)?r.ellipsoid:this.mapProjection.ellipsoid,e=u(e,2),this._transitioner.morphTo2D(e,t)},Re.prototype.morphToColumbusView=function(e){var t,r=this.globe;t=c(r)?r.ellipsoid:this.mapProjection.ellipsoid,e=u(e,2),this._transitioner.morphToColumbusView(e,t)},Re.prototype.morphTo3D=function(e){var t,r=this.globe;t=c(r)?r.ellipsoid:this.mapProjection.ellipsoid,e=u(e,2),this._transitioner.morphTo3D(e,t)},Re.prototype.isDestroyed=function(){return!1},Re.prototype.destroy=function(){return this._tweens.removeAll(),this._computeEngine=this._computeEngine&&this._computeEngine.destroy(),this._screenSpaceCameraController=this._screenSpaceCameraController&&this._screenSpaceCameraController.destroy(),this._pickFramebuffer=this._pickFramebuffer&&this._pickFramebuffer.destroy(),this._primitives=this._primitives&&this._primitives.destroy(),this._groundPrimitives=this._groundPrimitives&&this._groundPrimitives.destroy(),this._globe=this._globe&&this._globe.destroy(),this.skyBox=this.skyBox&&this.skyBox.destroy(),this.skyAtmosphere=this.skyAtmosphere&&this.skyAtmosphere.destroy(),this._debugSphere=this._debugSphere&&this._debugSphere.destroy(),this.sun=this.sun&&this.sun.destroy(),this._sunPostProcess=this._sunPostProcess&&this._sunPostProcess.destroy(),this._depthPlane=this._depthPlane&&this._depthPlane.destroy(),this._transitioner.destroy(),c(this._globeDepth)&&this._globeDepth.destroy(),c(this._oit)&&this._oit.destroy(),this._fxaa.destroy(),this._context=this._context&&this._context.destroy(),this._frameState.creditDisplay.destroy(),c(this._performanceDisplay)&&(this._performanceDisplay=this._performanceDisplay&&this._performanceDisplay.destroy(),this._performanceContainer.parentNode.removeChild(this._performanceContainer)),d(this)},Re}),r("Scene/SingleTileImageryProvider",["../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicTilingScheme","../Core/loadImage","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../ThirdParty/when"],function(e,t,r,i,n,o,a,s,l,u,c,h){"use strict";var d=function(i){function n(e){E._image=e,E._tileWidth=e.width,E._tileHeight=e.height,E._ready=!0,E._readyPromise.resolve(!0),c.handleSuccess(E._errorEvent)}function d(e){var t="Failed to load image "+g+".";C=c.handleError(C,E,E._errorEvent,t,0,0,0,p,e),E._readyPromise.reject(new u(t))}function p(){h(s(g),n,d)}i=t(i,{});var m=i.url;this._url=m;var f=i.proxy;this._proxy=f;var v=t(i.rectangle,l.MAX_VALUE),_=new a({rectangle:v,numberOfLevelZeroTilesX:1,numberOfLevelZeroTilesY:1,ellipsoid:i.ellipsoid});this._tilingScheme=_,this._image=void 0,this._texture=void 0,this._tileWidth=0,this._tileHeight=0,this._errorEvent=new o,this._ready=!1,this._readyPromise=h.defer();var g=m;r(f)&&(g=f.getURL(g));var y=i.credit;"string"==typeof y&&(y=new e(y)),this._credit=y;var C,E=this;p()};return i(d.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return 0}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return void 0}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),d.prototype.getTileCredits=function(e,t,r){return void 0},d.prototype.requestImage=function(e,t,r){return this._image},d.prototype.pickFeatures=function(){return void 0},d}),r("Shaders/SkyAtmosphereFS",[],function(){"use strict";return"const float g = -0.95;\nconst float g2 = g * g;\nvarying vec3 v_rayleighColor;\nvarying vec3 v_mieColor;\nvarying vec3 v_toCamera;\nvarying vec3 v_positionEC;\nvoid main (void)\n{\nfloat fCos = dot(czm_sunDirectionWC, normalize(v_toCamera)) / length(v_toCamera);\nfloat fRayleighPhase = 0.75 * (1.0 + fCos * fCos);\nfloat fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos * fCos) / pow(1.0 + g2 - 2.0 * g * fCos, 1.5);\nconst float fExposure = 2.0;\nvec3 rgb = fRayleighPhase * v_rayleighColor + fMiePhase * v_mieColor;\nrgb = vec3(1.0) - exp(-fExposure * rgb);\nfloat l = czm_luminance(rgb);\ngl_FragColor = vec4(rgb, min(smoothstep(0.0, 0.1, l), 1.0) * smoothstep(0.0, 1.0, czm_morphTime));\n}\n"}),r("Shaders/SkyAtmosphereVS",[],function(){"use strict";return"attribute vec4 position;\nuniform float fCameraHeight;\nuniform float fCameraHeight2;\nuniform float fOuterRadius;\nuniform float fOuterRadius2;\nuniform float fInnerRadius;\nuniform float fScale;\nuniform float fScaleDepth;\nuniform float fScaleOverScaleDepth;\nconst float Kr = 0.0025;\nconst float fKr4PI = Kr * 4.0 * czm_pi;\nconst float Km = 0.0015;\nconst float fKm4PI = Km * 4.0 * czm_pi;\nconst float ESun = 15.0;\nconst float fKmESun = Km * ESun;\nconst float fKrESun = Kr * ESun;\nconst vec3 v3InvWavelength = vec3(\n5.60204474633241,\n9.473284437923038,\n19.643802610477206);\nconst float rayleighScaleDepth = 0.25;\nconst int nSamples = 2;\nconst float fSamples = 2.0;\nvarying vec3 v_rayleighColor;\nvarying vec3 v_mieColor;\nvarying vec3 v_toCamera;\nfloat scale(float fCos)\n{\nfloat x = 1.0 - fCos;\nreturn fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));\n}\nvoid main(void)\n{\nvec3 v3Pos = position.xyz;\nvec3 v3Ray = v3Pos - czm_viewerPositionWC;\nfloat fFar = length(v3Ray);\nv3Ray /= fFar;\n#ifdef SKY_FROM_SPACE\nfloat B = 2.0 * dot(czm_viewerPositionWC, v3Ray);\nfloat C = fCameraHeight2 - fOuterRadius2;\nfloat fDet = max(0.0, B*B - 4.0 * C);\nfloat fNear = 0.5 * (-B - sqrt(fDet));\nvec3 v3Start = czm_viewerPositionWC + v3Ray * fNear;\nfFar -= fNear;\nfloat fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;\nfloat fStartDepth = exp(-1.0 / fScaleDepth);\nfloat fStartOffset = fStartDepth*scale(fStartAngle);\n#else\nvec3 v3Start = czm_viewerPositionWC;\nfloat fHeight = length(v3Start);\nfloat fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fCameraHeight));\nfloat fStartAngle = dot(v3Ray, v3Start) / fHeight;\nfloat fStartOffset = fDepth*scale(fStartAngle);\n#endif\nfloat fSampleLength = fFar / fSamples;\nfloat fScaledLength = fSampleLength * fScale;\nvec3 v3SampleRay = v3Ray * fSampleLength;\nvec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;\nvec3 v3FrontColor = vec3(0.0, 0.0, 0.0);\nfor(int i=0; i<nSamples; i++)\n{\nfloat fHeight = length(v3SamplePoint);\nfloat fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));\nvec3 lightPosition = normalize(czm_viewerPositionWC);\nfloat fLightAngle = dot(lightPosition, v3SamplePoint) / fHeight;\nfloat fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;\nfloat fScatter = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle)));\nvec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));\nv3FrontColor += v3Attenuate * (fDepth * fScaledLength);\nv3SamplePoint += v3SampleRay;\n}\nv_mieColor = v3FrontColor * fKmESun;\nv_rayleighColor = v3FrontColor * (v3InvWavelength * fKrESun);\nv_toCamera = czm_viewerPositionWC - v3Pos;\ngl_Position = czm_modelViewProjection * position;\n}\n"}),r("Scene/SkyAtmosphere",["../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/Ellipsoid","../Core/EllipsoidGeometry","../Core/GeometryPipeline","../Core/VertexFormat","../Renderer/BufferUsage","../Renderer/DrawCommand","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/ShaderSource","../Renderer/VertexArray","../Shaders/SkyAtmosphereFS","../Shaders/SkyAtmosphereVS","./BlendingState","./CullFace","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y){"use strict";var C=function(r){r=t(r,o.WGS84),this.show=!0,this._ellipsoid=r,this._command=new c({owner:this}),this._spSkyFromSpace=void 0,this._spSkyFromAtmosphere=void 0,this._fCameraHeight=void 0,this._fCameraHeight2=void 0,this._outerRadius=e.maximumComponent(e.multiplyByScalar(r.radii,1.025,new e));var i=r.maximumRadius,n=.25,a=this;this._command.uniformMap={fCameraHeight:function(){return a._fCameraHeight},fCameraHeight2:function(){return a._fCameraHeight2},fOuterRadius:function(){return a._outerRadius},fOuterRadius2:function(){return a._outerRadius*a._outerRadius},fInnerRadius:function(){return i},fScale:function(){return 1/(a._outerRadius-i)},fScaleDepth:function(){return n},fScaleOverScaleDepth:function(){return 1/(a._outerRadius-i)/n}}};return i(C.prototype,{ellipsoid:{get:function(){return this._ellipsoid}}}),C.prototype.update=function(t){if(!this.show)return void 0;if(t.mode!==y.SCENE3D&&t.mode!==y.MORPHING)return void 0;if(!t.passes.render)return void 0;var i=this._command;if(!r(i.vertexArray)){var n=t.context,o=a.createGeometry(new a({radii:e.multiplyByScalar(this._ellipsoid.radii,1.025,new e),slicePartitions:256,stackPartitions:256,vertexFormat:l.POSITION_ONLY}));i.vertexArray=m.fromGeometry({context:n,geometry:o,attributeLocations:s.createAttributeLocations(o),bufferUsage:u.STATIC_DRAW}),i.renderState=h.fromCache({cull:{enabled:!0,face:g.FRONT},blending:_.ALPHA_BLEND});var c=new p({defines:["SKY_FROM_SPACE"],sources:[v]});this._spSkyFromSpace=d.fromCache({context:n,vertexShaderSource:c,fragmentShaderSource:f}),c=new p({defines:["SKY_FROM_ATMOSPHERE"],sources:[v]}),this._spSkyFromAtmosphere=d.fromCache({context:n,vertexShaderSource:c,fragmentShaderSource:f})}var C=t.camera.positionWC;return this._fCameraHeight2=e.magnitudeSquared(C),this._fCameraHeight=Math.sqrt(this._fCameraHeight2),this._fCameraHeight>this._outerRadius?i.shaderProgram=this._spSkyFromSpace:i.shaderProgram=this._spSkyFromAtmosphere,i},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){var e=this._command;return e.vertexArray=e.vertexArray&&e.vertexArray.destroy(),this._spSkyFromSpace=this._spSkyFromSpace&&this._spSkyFromSpace.destroy(),this._spSkyFromAtmosphere=this._spSkyFromAtmosphere&&this._spSkyFromAtmosphere.destroy(),n(this)},C}),r("Shaders/SkyBoxFS",[],function(){"use strict";return"uniform samplerCube u_cubeMap;\nvarying vec3 v_texCoord;\nvoid main()\n{\nvec3 rgb = textureCube(u_cubeMap, normalize(v_texCoord)).rgb;\ngl_FragColor = vec4(rgb, czm_morphTime);\n}\n"}),r("Shaders/SkyBoxVS",[],function(){"use strict";return"attribute vec3 position;\nvarying vec3 v_texCoord;\nvoid main()\n{\nvec3 p = czm_viewRotation * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position));\ngl_Position = czm_projection * vec4(p, 1.0);\nv_texCoord = position.xyz;\n}\n"}),r("Scene/SkyBox",["../Core/BoxGeometry","../Core/Cartesian3","../Core/defaultValue","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Core/GeometryPipeline","../Core/Matrix4","../Core/VertexFormat","../Renderer/BufferUsage","../Renderer/CubeMap","../Renderer/DrawCommand","../Renderer/loadCubeMap","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/VertexArray","../Shaders/SkyBoxFS","../Shaders/SkyBoxVS","./BlendingState","./SceneMode"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y){"use strict";var C=function(e){this.sources=e.sources,this._sources=void 0,this.show=r(e.show,!0),this._command=new h({modelMatrix:s.clone(s.IDENTITY),owner:this}),this._cubeMap=void 0};return C.prototype.update=function(r){if(!this.show)return void 0;if(r.mode!==y.SCENE3D&&r.mode!==y.MORPHING)return void 0;if(!r.passes.render)return void 0;var n=r.context;if(this._sources!==this.sources){this._sources=this.sources;var o=this.sources;"string"==typeof o.positiveX?d(n,this._sources).then(function(e){h._cubeMap=h._cubeMap&&h._cubeMap.destroy(),h._cubeMap=e}):(this._cubeMap=this._cubeMap&&this._cubeMap.destroy(),this._cubeMap=new c({context:n,source:o}))}var s=this._command;if(!i(s.vertexArray)){var h=this;s.uniformMap={u_cubeMap:function(){return h._cubeMap}};var C=e.createGeometry(e.fromDimensions({dimensions:new t(2,2,2),vertexFormat:l.POSITION_ONLY})),E=a.createAttributeLocations(C);s.vertexArray=f.fromGeometry({context:n,geometry:C,attributeLocations:E,bufferUsage:u.STATIC_DRAW}),s.shaderProgram=m.fromCache({context:n,vertexShaderSource:_,fragmentShaderSource:v,attributeLocations:E}),s.renderState=p.fromCache({blending:g.ALPHA_BLEND})}return i(this._cubeMap)?s:void 0},C.prototype.isDestroyed=function(){return!1},C.prototype.destroy=function(){var e=this._command;return e.vertexArray=e.vertexArray&&e.vertexArray.destroy(),e.shaderProgram=e.shaderProgram&&e.shaderProgram.destroy(),this._cubeMap=this._cubeMap&&this._cubeMap.destroy(),n(this)},C}),r("Shaders/SunFS",[],function(){"use strict";return"uniform sampler2D u_texture;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\ngl_FragColor = texture2D(u_texture, v_textureCoordinates);\n}\n"}),r("Shaders/SunTextureFS",[],function(){"use strict";return"uniform float u_glowLengthTS;\nuniform float u_radiusTS;\nvarying vec2 v_textureCoordinates;\nvec2 rotate(vec2 p, vec2 direction)\n{\nreturn vec2(p.x * direction.x - p.y * direction.y, p.x * direction.y + p.y * direction.x);\n}\nvec4 addBurst(vec2 position, vec2 direction)\n{\nvec2 rotatedPosition = rotate(position, direction) * vec2(25.0, 0.75);\nfloat radius = length(rotatedPosition);\nfloat burst = 1.0 - smoothstep(0.0, 0.55, radius);\nreturn vec4(burst);\n}\nvoid main()\n{\nvec2 position = v_textureCoordinates - vec2(0.5);\nfloat radius = length(position);\nfloat surface = step(radius, u_radiusTS);\nvec4 color = vec4(1.0, 1.0, surface + 0.2, surface);\nfloat glow = 1.0 - smoothstep(0.0, 0.55, radius);\ncolor.ba += mix(vec2(0.0), vec2(1.0), glow) * 0.75;\nvec4 burst = vec4(0.0);\nburst += 0.4 * addBurst(position, vec2(0.38942, 0.92106));\nburst += 0.4 * addBurst(position, vec2(0.99235, 0.12348));\nburst += 0.4 * addBurst(position, vec2(0.60327, -0.79754));\nburst += 0.3 * addBurst(position, vec2(0.31457, 0.94924));\nburst += 0.3 * addBurst(position, vec2(0.97931, 0.20239));\nburst += 0.3 * addBurst(position, vec2(0.66507, -0.74678));\ncolor += clamp(burst, vec4(0.0), vec4(1.0)) * 0.15;\ngl_FragColor = clamp(color, vec4(0.0), vec4(1.0));\n}\n"; -}),r("Shaders/SunVS",[],function(){"use strict";return"attribute vec2 direction;\nuniform float u_size;\nvarying vec2 v_textureCoordinates;\nvoid main()\n{\nvec4 position;\nif (czm_morphTime == 1.0)\n{\nposition = vec4(czm_sunPositionWC, 1.0);\n}\nelse\n{\nposition = vec4(czm_sunPositionColumbusView.zxy, 1.0);\n}\nvec4 positionEC = czm_view * position;\nvec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\nvec2 halfSize = vec2(u_size * 0.5);\nhalfSize *= ((direction * 2.0) - 1.0);\ngl_Position = czm_viewportOrthographic * vec4(positionWC.xy + halfSize, -positionWC.z, 1.0);\nv_textureCoordinates = direction;\n}\n"}),r("Scene/Sun",["../Core/BoundingRectangle","../Core/BoundingSphere","../Core/Cartesian2","../Core/Cartesian3","../Core/Cartesian4","../Core/Color","../Core/ComponentDatatype","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/IndexDatatype","../Core/Math","../Core/Matrix4","../Core/PixelFormat","../Core/PrimitiveType","../Renderer/Buffer","../Renderer/BufferUsage","../Renderer/ClearCommand","../Renderer/ComputeCommand","../Renderer/DrawCommand","../Renderer/Framebuffer","../Renderer/RenderState","../Renderer/ShaderProgram","../Renderer/Texture","../Renderer/VertexArray","../Shaders/SunFS","../Shaders/SunTextureFS","../Shaders/SunVS","./BlendingState","./SceneMode","./SceneTransforms"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M){"use strict";var D=function(){this.show=!0,this._drawCommand=new y({primitiveType:m.TRIANGLES,boundingVolume:new t,owner:this}),this._commands={drawCommand:this._drawCommand,computeCommand:void 0},this._boundingVolume=new t,this._boundingVolume2D=new t,this._texture=void 0,this._drawingBufferWidth=void 0,this._drawingBufferHeight=void 0,this._radiusTS=void 0,this._size=void 0,this.glowFactor=1,this._glowFactorDirty=!1;var e=this;this._uniformMap={u_texture:function(){return e._texture},u_size:function(){return e._size}}};l(D.prototype,{glowFactor:{get:function(){return this._glowFactor},set:function(e){e=Math.max(e,0),this._glowFactor=e,this._glowFactorDirty=!0}}});var R=new r,O=new r,N=new n,L=new n;return D.prototype.update=function(e){var n=e.frameState,o=e.context;if(!this.show)return void 0;var l=n.mode;if(l===I.SCENE2D||l===I.MORPHING)return void 0;if(!n.passes.render)return void 0;var u=e.drawingBufferWidth,m=e.drawingBufferHeight;if(!s(this._texture)||u!==this._drawingBufferWidth||m!==this._drawingBufferHeight||this._glowFactorDirty){this._texture=this._texture&&this._texture.destroy(),this._drawingBufferWidth=u,this._drawingBufferHeight=m,this._glowFactorDirty=!1;var _=Math.max(u,m);_=Math.pow(2,Math.ceil(Math.log(_)/Math.log(2))-2),this._texture=new w({context:o,width:_,height:_,pixelFormat:p.RGBA}),this._glowLengthTS=5*this._glowFactor,this._radiusTS=1/(1+2*this._glowLengthTS)*.5;var y=this,C={u_glowLengthTS:function(){return y._glowLengthTS},u_radiusTS:function(){return y._radiusTS}};this._commands.computeCommand=new g({fragmentShaderSource:x,outputTexture:this._texture,uniformMap:C,persists:!1,owner:this,postExecute:function(){y._commands.computeCommand=void 0}})}var D=this._drawCommand;if(!s(D.vertexArray)){var F={direction:0},B=new Uint8Array(8);B[0]=0,B[1]=0,B[2]=255,B[3]=0,B[4]=255,B[5]=255,B[6]=0,B[7]=255;var V=f.createVertexBuffer({context:o,typedArray:B,usage:v.STATIC_DRAW}),z=[{index:F.direction,vertexBuffer:V,componentsPerAttribute:2,normalize:!0,componentDatatype:a.UNSIGNED_BYTE}],k=f.createIndexBuffer({context:o,typedArray:new Uint16Array([0,1,2,0,2,3]),usage:v.STATIC_DRAW,indexDatatype:c.UNSIGNED_SHORT});D.vertexArray=new T({context:o,attributes:z,indexBuffer:k}),D.shaderProgram=S.fromCache({context:o,vertexShaderSource:P,fragmentShaderSource:b,attributeLocations:F}),D.renderState=E.fromCache({blending:A.ALPHA_BLEND}),D.uniformMap=this._uniformMap}var U=o.uniformState.sunPositionWC,G=o.uniformState.sunPositionColumbusView,W=this._boundingVolume,H=this._boundingVolume2D;i.clone(U,W.center),H.center.x=G.z,H.center.y=G.x,H.center.z=G.y,W.radius=h.SOLAR_RADIUS+h.SOLAR_RADIUS*this._glowLengthTS,H.radius=W.radius,l===I.SCENE3D?t.clone(W,D.boundingVolume):l===I.COLUMBUS_VIEW&&t.clone(H,D.boundingVolume);var q=M.computeActualWgs84Position(n,U,L),j=i.magnitude(i.subtract(q,e.camera.position,L)),Y=o.uniformState.projection,X=N;X.x=0,X.y=0,X.z=-j,X.w=1;var Z=d.multiplyByVector(Y,X,L),K=M.clipToDrawingBufferCoordinates(e,Z,R);X.x=h.SOLAR_RADIUS;var J=d.multiplyByVector(Y,X,L),Q=M.clipToDrawingBufferCoordinates(e,J,O);return this._size=Math.ceil(r.magnitude(r.subtract(Q,K,L))),this._size=2*this._size*(1+2*this._glowLengthTS),this._commands},D.prototype.isDestroyed=function(){return!1},D.prototype.destroy=function(){var e=this._drawCommand;return e.vertexArray=e.vertexArray&&e.vertexArray.destroy(),e.shaderProgram=e.shaderProgram&&e.shaderProgram.destroy(),this._texture=this._texture&&this._texture.destroy(),u(this)},D}),r("Scene/TileCoordinatesImageryProvider",["../Core/Color","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/Event","../Core/GeographicTilingScheme","../ThirdParty/when"],function(e,t,r,i,n,o,a){"use strict";var s=function(i){i=t(i,t.EMPTY_OBJECT),this._tilingScheme=r(i.tilingScheme)?i.tilingScheme:new o({ellipsoid:i.ellipsoid}),this._color=t(i.color,e.YELLOW),this._errorEvent=new n,this._tileWidth=t(i.tileWidth,256),this._tileHeight=t(i.tileHeight,256),this._readyPromise=a.resolve(!0)};return i(s.prototype,{proxy:{get:function(){return void 0}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return void 0}},minimumLevel:{get:function(){return void 0}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._tilingScheme.rectangle}},tileDiscardPolicy:{get:function(){return void 0}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return!0}},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return void 0}},hasAlphaChannel:{get:function(){return!0}}}),s.prototype.getTileCredits=function(e,t,r){return void 0},s.prototype.requestImage=function(e,t,r){var i=document.createElement("canvas");i.width=256,i.height=256;var n=i.getContext("2d"),o=this._color.toCssColorString();n.strokeStyle=o,n.lineWidth=2,n.strokeRect(1,1,255,255);var a="L"+r+"X"+e+"Y"+t;return n.font="bold 25px Arial",n.textAlign="center",n.fillStyle="black",n.fillText(a,127,127),n.fillStyle=o,n.fillText(a,124,124),i},s.prototype.pickFeatures=function(){return void 0},s}),r("Scene/TileDiscardPolicy",["../Core/DeveloperError"],function(e){"use strict";var t=function(t){e.throwInstantiationError()};return t.prototype.isReady=e.throwInstantiationError,t.prototype.shouldDiscardImage=e.throwInstantiationError,t}),r("Scene/TileMapServiceImageryProvider",["../Core/Cartesian2","../Core/Cartographic","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/GeographicTilingScheme","../Core/joinUrls","../Core/loadXML","../Core/Rectangle","../Core/RuntimeError","../Core/TileProviderError","../Core/WebMercatorTilingScheme","../ThirdParty/when","./ImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v){"use strict";function _(e,t,r,i){var o=e._tilingScheme.getNumberOfYTilesAtLevel(i),a=u(e._url,i+"/"+t+"/"+(o-r-1)+"."+e._fileExtension),s=e._proxy;return n(s)&&(a=s.getURL(a)),a}var g=function(o){function a(r){for(var a,s,c,f,v=/tileformat/i,y=/tileset/i,S=/tilesets/i,w=/boundingbox/i,T=/srs/i,b=[],x=r.childNodes[0].childNodes,P=0;P<x.length;P++)if(v.test(x.item(P).nodeName))a=x.item(P);else if(S.test(x.item(P).nodeName)){c=x.item(P);for(var A=x.item(P).childNodes,I=0;I<A.length;I++)y.test(A.item(I).nodeName)&&b.push(A.item(I))}else w.test(x.item(P).nodeName)?s=x.item(P):T.test(x.item(P).nodeName)&&(f=x.item(P).textContent);E._fileExtension=i(E._fileExtension,a.getAttribute("extension")),E._tileWidth=i(E._tileWidth,parseInt(a.getAttribute("width"),10)),E._tileHeight=i(E._tileHeight,parseInt(a.getAttribute("height"),10)),E._minimumLevel=i(E._minimumLevel,parseInt(b[0].getAttribute("order"),10)),E._maximumLevel=i(E._maximumLevel,parseInt(b[b.length-1].getAttribute("order"),10));var M=c.getAttribute("profile"),D=!1;if(("geodetic"===M||"mercator"===M)&&(D=!0),!n(E._tilingScheme))if("geodetic"===M||"global-geodetic"===M)E._tilingScheme=new l({ellipsoid:o.ellipsoid});else{if("mercator"!==M&&"global-mercator"!==M){var R=u(g,"tilemapresource.xml")+"specifies an unsupported profile attribute, "+M+".";return C=p.handleError(C,E,E._errorEvent,R,void 0,void 0,void 0,_),void E._readyPromise.reject(new d(R))}E._tilingScheme=new m({ellipsoid:o.ellipsoid})}var O=E._tilingScheme;if(!n(E._rectangle)){var N,L,F,B;if(D)N=new e(parseFloat(s.getAttribute("miny")),parseFloat(s.getAttribute("minx"))),L=new e(parseFloat(s.getAttribute("maxy")),parseFloat(s.getAttribute("maxx"))),F=t.fromDegrees(N.x,N.y),B=t.fromDegrees(L.x,L.y);else if(N=new e(parseFloat(s.getAttribute("minx")),parseFloat(s.getAttribute("miny"))),L=new e(parseFloat(s.getAttribute("maxx")),parseFloat(s.getAttribute("maxy"))),E._tilingScheme instanceof l)F=t.fromDegrees(N.x,N.y),B=t.fromDegrees(L.x,L.y);else{var V=E._tilingScheme.projection;F=V.unproject(N),B=V.unproject(L)}E._rectangle=new h(F.longitude,F.latitude,B.longitude,B.latitude)}E._rectangle.west<O.rectangle.west&&(E._rectangle.west=O.rectangle.west),E._rectangle.east>O.rectangle.east&&(E._rectangle.east=O.rectangle.east),E._rectangle.south<O.rectangle.south&&(E._rectangle.south=O.rectangle.south),E._rectangle.north>O.rectangle.north&&(E._rectangle.north=O.rectangle.north);var z=O.positionToTileXY(h.southwest(E._rectangle),E._minimumLevel),k=O.positionToTileXY(h.northeast(E._rectangle),E._minimumLevel),U=(Math.abs(k.x-z.x)+1)*(Math.abs(k.y-z.y)+1);U>4&&(E._minimumLevel=0),E._tilingScheme=O,E._ready=!0,E._readyPromise.resolve(!0)}function v(e){E._fileExtension=i(o.fileExtension,"png"),E._tileWidth=i(o.tileWidth,256),E._tileHeight=i(o.tileHeight,256),E._minimumLevel=i(o.minimumLevel,0),E._maximumLevel=o.maximumLevel,E._tilingScheme=n(o.tilingScheme)?o.tilingScheme:new m({ellipsoid:o.ellipsoid}),E._rectangle=i(o.rectangle,E._tilingScheme.rectangle),E._ready=!0,E._readyPromise.resolve(!0)}function _(){var e=u(g,"tilemapresource.xml"),t=E._proxy;n(t)&&(e=t.getURL(e)),f(c(e),a,v)}o=i(o,{});var g=o.url;this._url=g,this._ready=!1,this._readyPromise=f.defer(),this._proxy=o.proxy,this._tileDiscardPolicy=o.tileDiscardPolicy,this._errorEvent=new s,this._fileExtension=o.fileExtension,this._tileWidth=o.tileWidth,this._tileHeight=o.tileHeight,this._minimumLevel=o.minimumLevel,this._maximumLevel=o.maximumLevel,this._rectangle=h.clone(o.rectangle),this._tilingScheme=o.tilingScheme;var y=o.credit;"string"==typeof y&&(y=new r(y)),this._credit=y;var C,E=this;_()};return o(g.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},ready:{get:function(){return this._ready}},readyPromise:{get:function(){return this._readyPromise.promise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),g.prototype.getTileCredits=function(e,t,r){return void 0},g.prototype.requestImage=function(e,t,r){var i=_(this,e,t,r);return v.loadImage(this,i)},g.prototype.pickFeatures=function(){return void 0},g}),r("Scene/TileState",["../Core/freezeObject"],function(e){"use strict";var t={START:0,LOADING:1,READY:2,UPSAMPLED_ONLY:3};return e(t)}),r("Shaders/ViewportQuadFS",[],function(){"use strict";return"varying vec2 v_textureCoordinates;\nvoid main()\n{\nczm_materialInput materialInput;\nmaterialInput.s = v_textureCoordinates.s;\nmaterialInput.st = v_textureCoordinates;\nmaterialInput.str = vec3(v_textureCoordinates, 0.0);\nmaterialInput.normalEC = vec3(0.0, 0.0, -1.0);\nczm_material material = czm_getMaterial(materialInput);\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n}\n"}),r("Scene/ViewportQuad",["../Core/BoundingRectangle","../Core/Color","../Core/defined","../Core/destroyObject","../Core/DeveloperError","../Renderer/RenderState","../Renderer/ShaderSource","../Shaders/ViewportQuadFS","./BlendingState","./Material","./Pass"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";var h=function(i,n){this.show=!0,r(i)||(i=new e),this.rectangle=e.clone(i),r(n)||(n=u.fromType(u.ColorType,{color:new t(1,1,1,1)})),this.material=n,this._material=void 0,this._overlayCommand=void 0,this._rs=void 0};return h.prototype.update=function(t){if(this.show){var i=this._rs;r(i)&&e.equals(i.viewport,this.rectangle)||(this._rs=o.fromCache({blending:l.ALPHA_BLEND,viewport:this.rectangle}));var n=t.passes;if(n.render){var u=t.context;if(this._material!==this.material||!r(this._overlayCommand)){this._material=this.material,r(this._overlayCommand)&&this._overlayCommand.shaderProgram.destroy();var h=new a({sources:[this._material.shaderSource,s]});this._overlayCommand=u.createViewportQuadCommand(h,{renderState:this._rs,uniformMap:this._material._uniforms,owner:this}),this._overlayCommand.pass=c.OVERLAY}this._material.update(u),this._overlayCommand.uniformMap=this._material._uniforms,t.commandList.push(this._overlayCommand)}}},h.prototype.isDestroyed=function(){return!1},h.prototype.destroy=function(){return r(this._overlayCommand)&&(this._overlayCommand.shaderProgram=this._overlayCommand.shaderProgram&&this._overlayCommand.shaderProgram.destroy()),i(this)},h}),r("Scene/WebMapServiceImageryProvider",["../Core/combine","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/deprecationWarning","../Core/DeveloperError","../Core/freezeObject","../Core/GeographicTilingScheme","../Core/objectToQuery","../Core/queryToObject","../Core/WebMercatorTilingScheme","../ThirdParty/Uri","./GetFeatureInfoFormat","./UrlTemplateImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e){var t={};for(var r in e)e.hasOwnProperty(r)&&(t[r.toLowerCase()]=e[r]);return t}var f=function v(i){function n(e,t){r(d[e])||(d[e]=t),r(g)&&!r(g[e])&&(g[e]=t)}i=t(i,t.EMPTY_OBJECT),this._url=i.url,this._layers=i.layers;var o=t(i.getFeatureInfoFormats,v.DefaultGetFeatureInfoFormats),a=new h(i.url),d=u(t(a.query,"")),f=e(m(t(i.parameters,t.EMPTY_OBJECT)),v.DefaultParameters);d=e(f,d);var _,g;if(t(i.enablePickFeatures,!0)){_=new h(i.url),g=u(t(_.query,""));var y=e(m(t(i.getFeatureInfoParameters,t.EMPTY_OBJECT)),v.GetFeatureInfoDefaultParameters);g=e(y,g)}n("layers",i.layers),n("srs",i.tilingScheme instanceof c?"EPSG:3857":"EPSG:4326"),n("bbox","{westProjected},{southProjected},{eastProjected},{northProjected}"),n("width","{width}"),n("height","{height}"),a.query=l(d);var C,E=a.toString().replace(/%7B/g,"{").replace(/%7D/g,"}");r(g)&&(r(g.query_layers)||(g.query_layers=i.layers),r(g.x)||(g.x="{i}"),r(g.y)||(g.y="{j}"),r(g.info_format)||(g.info_format="{format}"),_.query=l(g),C=_.toString().replace(/%7B/g,"{").replace(/%7D/g,"}")),this._tileProvider=new p({url:E,pickFeaturesUrl:C,tilingScheme:t(i.tilingScheme,new s({ellipsoid:i.ellipsoid})),rectangle:i.rectangle,tileWidth:i.tileWidth,tileHeight:i.tileHeight,minimumLevel:i.minimumLevel,maximumLevel:i.maximumLevel,minimumRetrievingLevel:i.minimumRetrievingLevel,proxy:i.proxy,subdomains:i.subdomains,tileDiscardPolicy:i.tileDiscardPolicy,credit:i.credit,getFeatureInfoFormats:o})};return i(f.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._tileProvider.proxy}},layers:{get:function(){return this._layers}},tileWidth:{get:function(){return this._tileProvider.tileWidth}},tileHeight:{get:function(){return this._tileProvider.tileHeight}},maximumLevel:{get:function(){return this._tileProvider.maximumLevel}},minimumLevel:{get:function(){return this._tileProvider.minimumLevel}},tilingScheme:{get:function(){return this._tileProvider.tilingScheme}},rectangle:{get:function(){return this._tileProvider.rectangle}},tileDiscardPolicy:{get:function(){return this._tileProvider.tileDiscardPolicy}},errorEvent:{get:function(){return this._tileProvider.errorEvent}},ready:{get:function(){return this._tileProvider.ready}},readyPromise:{get:function(){return this._tileProvider.readyPromise}},credit:{get:function(){return this._tileProvider.credit}},hasAlphaChannel:{get:function(){return this._tileProvider.hasAlphaChannel}}}),f.prototype.getTileCredits=function(e,t,r){return this._tileProvider.getTileCredits(e,t,r)},f.prototype.requestImage=function(e,t,r){return this._tileProvider.requestImage(e,t,r)},f.prototype.pickFeatures=function(e,t,r,i,n){return this._tileProvider.pickFeatures(e,t,r,i,n)},f.DefaultParameters=a({service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"}),f.GetFeatureInfoDefaultParameters=a({service:"WMS",version:"1.1.1",request:"GetFeatureInfo"}),f.DefaultGetFeatureInfoFormats=a([a(new d("json","application/json")),a(new d("xml","text/xml")),a(new d("text","text/html"))]),f}),r("Scene/WebMapTileServiceImageryProvider",["../Core/combine","../Core/Credit","../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../Core/freezeObject","../Core/objectToQuery","../Core/queryToObject","../Core/Rectangle","../Core/WebMercatorTilingScheme","../ThirdParty/Uri","../ThirdParty/when","./ImageryProvider","./UrlTemplateImageryProvider"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f){"use strict";function v(t,n,o,a){var s,c=t._tileMatrixLabels,h=i(c)?c[a]:a.toString(),p=t._subdomains;if(t._url.indexOf("{")>=0)s=t._url.replace("{style}",t._style).replace("{Style}",t._style).replace("{TileMatrixSet}",t._tileMatrixSetID).replace("{TileMatrix}",h).replace("{TileRow}",o.toString()).replace("{TileCol}",n.toString()).replace("{s}",p[(n+o+a)%p.length]);else{var m=new d(t._url),f=u(r(m.query,""));f=e(g,f),f.tilematrix=h,f.layer=t._layer,f.style=t._style,f.tilerow=o,f.tilecol=n,f.tilematrixset=t._tileMatrixSetID,f.format=t._format,m.query=l(f),s=m.toString()}var v=t._proxy;return i(v)&&(s=v.getURL(s)),s}var _=function(e){if(e=r(e,r.EMPTY_OBJECT),!i(e.url))throw new o("options.url is required.");if(!i(e.layer))throw new o("options.layer is required.");if(!i(e.style))throw new o("options.style is required.");if(!i(e.tileMatrixSetID))throw new o("options.tileMatrixSetID is required.");this._url=e.url,this._layer=e.layer,this._style=e.style,this._tileMatrixSetID=e.tileMatrixSetID,this._tileMatrixLabels=e.tileMatrixLabels,this._format=r(e.format,"image/jpeg"),this._proxy=e.proxy,this._tileDiscardPolicy=e.tileDiscardPolicy,this._tilingScheme=i(e.tilingScheme)?e.tilingScheme:new h({ellipsoid:e.ellipsoid}),this._tileWidth=r(e.tileWidth,256),this._tileHeight=r(e.tileHeight,256),this._minimumRetrievingLevel=r(e.minimumRetrievingLevel,0),this._minimumLevel=r(e.minimumLevel,0),this._maximumLevel=e.maximumLevel,this._rectangle=r(e.rectangle,this._tilingScheme.rectangle),this._readyPromise=p.resolve(!0);var n=this._tilingScheme.positionToTileXY(c.southwest(this._rectangle),this._minimumLevel),s=this._tilingScheme.positionToTileXY(c.northeast(this._rectangle),this._minimumLevel),l=(Math.abs(s.x-n.x)+1)*(Math.abs(s.y-n.y)+1);if(l>4)throw new o("The imagery provider's rectangle and minimumLevel indicate that there are "+l+" tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.");this._errorEvent=new a;var u=e.credit;this._credit="string"==typeof u?new t(u):u,this._subdomains=e.subdomains,Array.isArray(this._subdomains)?this._subdomains=this._subdomains.slice():i(this._subdomains)&&this._subdomains.length>0?this._subdomains=this._subdomains.split(""):this._subdomains=["a","b","c"]},g=s({service:"WMTS",version:"1.0.0",request:"GetTile"});return n(_.prototype,{url:{get:function(){return this._url}},proxy:{get:function(){return this._proxy}},tileWidth:{get:function(){return this._tileWidth}},tileHeight:{get:function(){return this._tileHeight}},maximumLevel:{get:function(){return this._maximumLevel}},minimumLevel:{get:function(){return this._minimumLevel}},tilingScheme:{get:function(){return this._tilingScheme}},rectangle:{get:function(){return this._rectangle}},tileDiscardPolicy:{get:function(){return this._tileDiscardPolicy}},errorEvent:{get:function(){return this._errorEvent}},format:{get:function(){return this._format}},ready:{value:!0},readyPromise:{get:function(){return this._readyPromise}},credit:{get:function(){return this._credit}},hasAlphaChannel:{get:function(){return!0}}}),_.prototype.getTileCredits=function(e,t,r){return void 0},_.prototype.requestImage=function(e,t,r){if(r<this._minimumRetrievingLevel)return f.transparentCanvas;var i=v(this,e,t,r);return m.loadImage(this,i)},_.prototype.pickFeatures=function(){return void 0},_}),r("Scene/createTangentSpaceDebugPrimitive",["../Core/ColorGeometryInstanceAttribute","../Core/defaultValue","../Core/defined","../Core/DeveloperError","../Core/GeometryInstance","../Core/GeometryPipeline","../Core/Matrix4","./PerInstanceColorAppearance","./Primitive"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(i){i=t(i,t.EMPTY_OBJECT);var u=[],c=i.geometry;r(c.attributes)&&r(c.primitiveType)||(c=c.constructor.createGeometry(c));var h=c.attributes,d=a.clone(t(i.modelMatrix,a.IDENTITY)),p=t(i.length,1e4);return r(h.normal)&&u.push(new n({geometry:o.createLineSegmentsForVectors(c,"normal",p),attributes:{color:new e(1,0,0,1)},modelMatrix:d})),r(h.binormal)&&u.push(new n({geometry:o.createLineSegmentsForVectors(c,"binormal",p),attributes:{color:new e(0,1,0,1)},modelMatrix:d})),r(h.tangent)&&u.push(new n({geometry:o.createLineSegmentsForVectors(c,"tangent",p),attributes:{color:new e(0,0,1,1)},modelMatrix:d})),u.length>0?new l({asynchronous:!1,geometryInstances:u,appearance:new s({flat:!0,translucent:!1})}):void 0};return u}),function(){!function(e){var i=this||(0,eval)("this"),n=i.document,o=i.navigator,a=i.jQuery,s=i.JSON;!function(e){"function"==typeof t&&"object"==typeof exports&&"object"==typeof module?e(module.exports||exports,t):"function"==typeof r&&r.amd?r("ThirdParty/knockout-3.2.0",["exports","require"],e):e(i.ko={})}(function(t,r){function l(e,t){return null===e||typeof e in p?e===t:!1}function u(t,r){var i;return function(){i||(i=setTimeout(function(){i=e,t()},r))}}function c(e,t){var r;return function(){clearTimeout(r),r=setTimeout(e,t)}}function h(e,t,r,i){d.d[e]={init:function(e,n,o,a,s){var l,u;return d.s(function(){var o=d.a.c(n()),a=!r!=!o,c=!u;(c||t||a!==l)&&(c&&d.Y.la()&&(u=d.a.ia(d.f.childNodes(e),!0)),a?(c||d.f.T(e,d.a.ia(u)),d.Ca(i?i(s,o):s,e)):d.f.ja(e),l=a)},null,{o:e}),{controlsDescendantBindings:!0}}},d.h.ha[e]=!1,d.f.Q[e]=!0}var d="undefined"!=typeof t?t:{};d.b=function(e,t){for(var r=e.split("."),i=d,n=0;n<r.length-1;n++)i=i[r[n]];i[r[r.length-1]]=t},d.A=function(e,t,r){e[t]=r},d.version="3.2.0",d.b("version",d.version),d.a=function(){function t(e,t){for(var r in e)e.hasOwnProperty(r)&&t(r,e[r])}function r(e,t){if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function l(e,t){return e.__proto__=t,e}var u={__proto__:[]}instanceof Array,c={},h={};c[o&&/Firefox\/2/i.test(o.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"],c.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" "),t(c,function(e,t){if(t.length)for(var r=0,i=t.length;i>r;r++)h[t[r]]=e});var p={propertychange:!0},m=n&&function(){for(var t=3,r=n.createElement("div"),i=r.getElementsByTagName("i");r.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->",i[0];);return t>4?t:e}();return{vb:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],u:function(e,t){for(var r=0,i=e.length;i>r;r++)t(e[r],r)},m:function(e,t){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(e,t);for(var r=0,i=e.length;i>r;r++)if(e[r]===t)return r;return-1},qb:function(e,t,r){for(var i=0,n=e.length;n>i;i++)if(t.call(r,e[i],i))return e[i];return null},ua:function(e,t){var r=d.a.m(e,t);r>0?e.splice(r,1):0===r&&e.shift()},rb:function(e){e=e||[];for(var t=[],r=0,i=e.length;i>r;r++)0>d.a.m(t,e[r])&&t.push(e[r]);return t},Da:function(e,t){e=e||[];for(var r=[],i=0,n=e.length;n>i;i++)r.push(t(e[i],i));return r},ta:function(e,t){e=e||[];for(var r=[],i=0,n=e.length;n>i;i++)t(e[i],i)&&r.push(e[i]);return r},ga:function(e,t){if(t instanceof Array)e.push.apply(e,t);else for(var r=0,i=t.length;i>r;r++)e.push(t[r]);return e},ea:function(e,t,r){var i=d.a.m(d.a.Xa(e),t);0>i?r&&e.push(t):r||e.splice(i,1)},xa:u,extend:r,za:l,Aa:u?l:r,G:t,na:function(e,t){if(!e)return e;var r,i={};for(r in e)e.hasOwnProperty(r)&&(i[r]=t(e[r],r,e));return i},Ka:function(e){for(;e.firstChild;)d.removeNode(e.firstChild)},oc:function(e){e=d.a.S(e);for(var t=n.createElement("div"),r=0,i=e.length;i>r;r++)t.appendChild(d.R(e[r]));return t},ia:function(e,t){for(var r=0,i=e.length,n=[];i>r;r++){var o=e[r].cloneNode(!0);n.push(t?d.R(o):o)}return n},T:function(e,t){if(d.a.Ka(e),t)for(var r=0,i=t.length;i>r;r++)e.appendChild(t[r])},Lb:function(e,t){var r=e.nodeType?[e]:e;if(0<r.length){for(var i=r[0],n=i.parentNode,o=0,a=t.length;a>o;o++)n.insertBefore(t[o],i);for(o=0,a=r.length;a>o;o++)d.removeNode(r[o])}},ka:function(e,t){if(e.length){for(t=8===t.nodeType&&t.parentNode||t;e.length&&e[0].parentNode!==t;)e.shift();if(1<e.length){var r=e[0],i=e[e.length-1];for(e.length=0;r!==i;)if(e.push(r),r=r.nextSibling,!r)return;e.push(i)}}return e},Nb:function(e,t){7>m?e.setAttribute("selected",t):e.selected=t},cb:function(t){return null===t||t===e?"":t.trim?t.trim():t.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},vc:function(e,t){return e=e||"",t.length>e.length?!1:e.substring(0,t.length)===t},cc:function(e,t){if(e===t)return!0;if(11===e.nodeType)return!1;if(t.contains)return t.contains(3===e.nodeType?e.parentNode:e);if(t.compareDocumentPosition)return 16==(16&t.compareDocumentPosition(e));for(;e&&e!=t;)e=e.parentNode;return!!e},Ja:function(e){return d.a.cc(e,e.ownerDocument.documentElement)},ob:function(e){return!!d.a.qb(e,d.a.Ja)},t:function(e){return e&&e.tagName&&e.tagName.toLowerCase()},n:function(e,t,r){var i=m&&p[t];if(!i&&a)a(e).bind(t,r);else if(i||"function"!=typeof e.addEventListener){if("undefined"==typeof e.attachEvent)throw Error("Browser doesn't support addEventListener or attachEvent");var n=function(t){r.call(e,t)},o="on"+t;e.attachEvent(o,n),d.a.w.da(e,function(){e.detachEvent(o,n)})}else e.addEventListener(t,r,!1)},oa:function(e,t){if(!e||!e.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var r;if("input"===d.a.t(e)&&e.type&&"click"==t.toLowerCase()?(r=e.type,r="checkbox"==r||"radio"==r):r=!1,a&&!r)a(e).trigger(t);else if("function"==typeof n.createEvent){if("function"!=typeof e.dispatchEvent)throw Error("The supplied element doesn't support dispatchEvent");r=n.createEvent(h[t]||"HTMLEvents"),r.initEvent(t,!0,!0,i,0,0,0,0,0,!1,!1,!1,!1,0,e),e.dispatchEvent(r)}else if(r&&e.click)e.click();else{if("undefined"==typeof e.fireEvent)throw Error("Browser doesn't support triggering events");e.fireEvent("on"+t)}},c:function(e){return d.C(e)?e():e},Xa:function(e){return d.C(e)?e.v():e},Ba:function(e,t,r){if(t){var i=/\S+/g,n=e.className.match(i)||[];d.a.u(t.match(i),function(e){d.a.ea(n,e,r)}),e.className=n.join(" ")}},bb:function(t,r){var i=d.a.c(r);(null===i||i===e)&&(i="");var n=d.f.firstChild(t);!n||3!=n.nodeType||d.f.nextSibling(n)?d.f.T(t,[t.ownerDocument.createTextNode(i)]):n.data=i,d.a.fc(t)},Mb:function(e,t){if(e.name=t,7>=m)try{e.mergeAttributes(n.createElement("<input name='"+e.name+"'/>"),!1)}catch(r){}},fc:function(e){m>=9&&(e=1==e.nodeType?e:e.parentNode,e.style&&(e.style.zoom=e.style.zoom))},dc:function(e){if(m){var t=e.style.width;e.style.width=0,e.style.width=t}},sc:function(e,t){e=d.a.c(e),t=d.a.c(t);for(var r=[],i=e;t>=i;i++)r.push(i);return r},S:function(e){for(var t=[],r=0,i=e.length;i>r;r++)t.push(e[r]);return t},yc:6===m,zc:7===m,L:m,xb:function(e,t){for(var r=d.a.S(e.getElementsByTagName("input")).concat(d.a.S(e.getElementsByTagName("textarea"))),i="string"==typeof t?function(e){return e.name===t}:function(e){return t.test(e.name)},n=[],o=r.length-1;o>=0;o--)i(r[o])&&n.push(r[o]);return n},pc:function(e){return"string"==typeof e&&(e=d.a.cb(e))?s&&s.parse?s.parse(e):new Function("return "+e)():null},eb:function(e,t,r){if(!s||!s.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");return s.stringify(d.a.c(e),t,r)},qc:function(e,r,i){i=i||{};var o=i.params||{},a=i.includeFields||this.vb,s=e;if("object"==typeof e&&"form"===d.a.t(e))for(var s=e.action,l=a.length-1;l>=0;l--)for(var u=d.a.xb(e,a[l]),c=u.length-1;c>=0;c--)o[u[c].name]=u[c].value;r=d.a.c(r);var h=n.createElement("form");h.style.display="none",h.action=s,h.method="post";for(var p in r)e=n.createElement("input"),e.type="hidden",e.name=p,e.value=d.a.eb(d.a.c(r[p])),h.appendChild(e);t(o,function(e,t){var r=n.createElement("input");r.type="hidden",r.name=e,r.value=t,h.appendChild(r)}),n.body.appendChild(h),i.submitter?i.submitter(h):h.submit(),setTimeout(function(){h.parentNode.removeChild(h)},0)}}}(),d.b("utils",d.a),d.b("utils.arrayForEach",d.a.u),d.b("utils.arrayFirst",d.a.qb),d.b("utils.arrayFilter",d.a.ta),d.b("utils.arrayGetDistinctValues",d.a.rb),d.b("utils.arrayIndexOf",d.a.m),d.b("utils.arrayMap",d.a.Da),d.b("utils.arrayPushAll",d.a.ga),d.b("utils.arrayRemoveItem",d.a.ua),d.b("utils.extend",d.a.extend),d.b("utils.fieldsIncludedWithJsonPost",d.a.vb),d.b("utils.getFormFields",d.a.xb),d.b("utils.peekObservable",d.a.Xa),d.b("utils.postJson",d.a.qc),d.b("utils.parseJson",d.a.pc),d.b("utils.registerEventHandler",d.a.n),d.b("utils.stringifyJson",d.a.eb),d.b("utils.range",d.a.sc),d.b("utils.toggleDomNodeCssClass",d.a.Ba),d.b("utils.triggerEvent",d.a.oa),d.b("utils.unwrapObservable",d.a.c),d.b("utils.objectForEach",d.a.G),d.b("utils.addOrRemoveItem",d.a.ea),d.b("unwrap",d.a.c),Function.prototype.bind||(Function.prototype.bind=function(e){var t=this,r=Array.prototype.slice.call(arguments);return e=r.shift(),function(){return t.apply(e,r.concat(Array.prototype.slice.call(arguments)))}}),d.a.e=new function(){function t(t,o){var a=t[i];if(!a||"null"===a||!n[a]){if(!o)return e;a=t[i]="ko"+r++,n[a]={}}return n[a]}var r=0,i="__ko__"+(new Date).getTime(),n={};return{get:function(r,i){var n=t(r,!1);return n===e?e:n[i]},set:function(r,i,n){(n!==e||t(r,!1)!==e)&&(t(r,!0)[i]=n)},clear:function(e){var t=e[i];return t?(delete n[t],e[i]=null,!0):!1},F:function(){return r++ +i}}},d.b("utils.domData",d.a.e),d.b("utils.domData.clear",d.a.e.clear),d.a.w=new function(){function t(t,r){var n=d.a.e.get(t,i);return n===e&&r&&(n=[],d.a.e.set(t,i,n)),n}function r(e){var i=t(e,!1);if(i)for(var i=i.slice(0),n=0;n<i.length;n++)i[n](e);if(d.a.e.clear(e),d.a.w.cleanExternalData(e),o[e.nodeType])for(i=e.firstChild;e=i;)i=e.nextSibling,8===e.nodeType&&r(e)}var i=d.a.e.F(),n={1:!0,8:!0,9:!0},o={1:!0,9:!0};return{da:function(e,r){if("function"!=typeof r)throw Error("Callback must be a function");t(e,!0).push(r)},Kb:function(r,n){var o=t(r,!1);o&&(d.a.ua(o,n),0==o.length&&d.a.e.set(r,i,e))},R:function(e){if(n[e.nodeType]&&(r(e),o[e.nodeType])){var t=[];d.a.ga(t,e.getElementsByTagName("*"));for(var i=0,a=t.length;a>i;i++)r(t[i])}return e},removeNode:function(e){d.R(e),e.parentNode&&e.parentNode.removeChild(e)},cleanExternalData:function(e){a&&"function"==typeof a.cleanData&&a.cleanData([e])}}},d.R=d.a.w.R, -d.removeNode=d.a.w.removeNode,d.b("cleanNode",d.R),d.b("removeNode",d.removeNode),d.b("utils.domNodeDisposal",d.a.w),d.b("utils.domNodeDisposal.addDisposeCallback",d.a.w.da),d.b("utils.domNodeDisposal.removeDisposeCallback",d.a.w.Kb),function(){d.a.ba=function(e){var t;if(a){if(a.parseHTML)t=a.parseHTML(e)||[];else if((t=a.clean([e]))&&t[0]){for(e=t[0];e.parentNode&&11!==e.parentNode.nodeType;)e=e.parentNode;e.parentNode&&e.parentNode.removeChild(e)}}else{var r=d.a.cb(e).toLowerCase();for(t=n.createElement("div"),r=r.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!r.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!r.indexOf("<td")||!r.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""],e="ignored<div>"+r[1]+e+r[2]+"</div>","function"==typeof i.innerShiv?t.appendChild(i.innerShiv(e)):t.innerHTML=e;r[0]--;)t=t.lastChild;t=d.a.S(t.lastChild.childNodes)}return t},d.a.$a=function(t,r){if(d.a.Ka(t),r=d.a.c(r),null!==r&&r!==e)if("string"!=typeof r&&(r=r.toString()),a)a(t).html(r);else for(var i=d.a.ba(r),n=0;n<i.length;n++)t.appendChild(i[n])}}(),d.b("utils.parseHtmlFragment",d.a.ba),d.b("utils.setHtml",d.a.$a),d.D=function(){function t(e,r){if(e)if(8==e.nodeType){var i=d.D.Gb(e.nodeValue);null!=i&&r.push({bc:e,mc:i})}else if(1==e.nodeType)for(var i=0,n=e.childNodes,o=n.length;o>i;i++)t(n[i],r)}var r={};return{Ua:function(e){if("function"!=typeof e)throw Error("You can only pass a function to ko.memoization.memoize()");var t=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);return r[t]=e,"<!--[ko_memo:"+t+"]-->"},Rb:function(t,i){var n=r[t];if(n===e)throw Error("Couldn't find any memo with ID "+t+". Perhaps it's already been unmemoized.");try{return n.apply(null,i||[]),!0}finally{delete r[t]}},Sb:function(e,r){var i=[];t(e,i);for(var n=0,o=i.length;o>n;n++){var a=i[n].bc,s=[a];r&&d.a.ga(s,r),d.D.Rb(i[n].mc,s),a.nodeValue="",a.parentNode&&a.parentNode.removeChild(a)}},Gb:function(e){return(e=e.match(/^\[ko_memo\:(.*?)\]$/))?e[1]:null}}}(),d.b("memoization",d.D),d.b("memoization.memoize",d.D.Ua),d.b("memoization.unmemoize",d.D.Rb),d.b("memoization.parseMemoText",d.D.Gb),d.b("memoization.unmemoizeDomNodeAndDescendants",d.D.Sb),d.La={throttle:function(e,t){e.throttleEvaluation=t;var r=null;return d.j({read:e,write:function(i){clearTimeout(r),r=setTimeout(function(){e(i)},t)}})},rateLimit:function(e,t){var r,i,n;"number"==typeof t?r=t:(r=t.timeout,i=t.method),n="notifyWhenChangesStop"==i?c:u,e.Ta(function(e){return n(e,r)})},notify:function(e,t){e.equalityComparer="always"==t?null:l}};var p={undefined:1,"boolean":1,number:1,string:1};d.b("extenders",d.La),d.Pb=function(e,t,r){this.target=e,this.wa=t,this.ac=r,this.Cb=!1,d.A(this,"dispose",this.K)},d.Pb.prototype.K=function(){this.Cb=!0,this.ac()},d.P=function(){d.a.Aa(this,d.P.fn),this.M={}};var m="change",f={U:function(e,t,r){var i=this;r=r||m;var n=new d.Pb(i,t?e.bind(t):e,function(){d.a.ua(i.M[r],n),i.nb&&i.nb()});return i.va&&i.va(r),i.M[r]||(i.M[r]=[]),i.M[r].push(n),n},notifySubscribers:function(e,t){if(t=t||m,this.Ab(t))try{d.k.Ea();for(var r,i=this.M[t].slice(0),n=0;r=i[n];++n)r.Cb||r.wa(e)}finally{d.k.end()}},Ta:function(e){var t,r,i,n=this,o=d.C(n);n.qa||(n.qa=n.notifySubscribers,n.notifySubscribers=function(e,t){t&&t!==m?"beforeChange"===t?n.kb(e):n.qa(e,t):n.lb(e)});var a=e(function(){o&&i===n&&(i=n()),t=!1,n.Pa(r,i)&&n.qa(r=i)});n.lb=function(e){t=!0,i=e,a()},n.kb=function(e){t||(r=e,n.qa(e,"beforeChange"))}},Ab:function(e){return this.M[e]&&this.M[e].length},yb:function(){var e=0;return d.a.G(this.M,function(t,r){e+=r.length}),e},Pa:function(e,t){return!this.equalityComparer||!this.equalityComparer(e,t)},extend:function(e){var t=this;return e&&d.a.G(e,function(e,r){var i=d.La[e];"function"==typeof i&&(t=i(t,r)||t)}),t}};d.A(f,"subscribe",f.U),d.A(f,"extend",f.extend),d.A(f,"getSubscriptionsCount",f.yb),d.a.xa&&d.a.za(f,Function.prototype),d.P.fn=f,d.Db=function(e){return null!=e&&"function"==typeof e.U&&"function"==typeof e.notifySubscribers},d.b("subscribable",d.P),d.b("isSubscribable",d.Db),d.Y=d.k=function(){function e(e){i.push(r),r=e}function t(){r=i.pop()}var r,i=[],n=0;return{Ea:e,end:t,Jb:function(e){if(r){if(!d.Db(e))throw Error("Only subscribable things can act as dependencies");r.wa(e,e.Vb||(e.Vb=++n))}},B:function(r,i,n){try{return e(),r.apply(i,n||[])}finally{t()}},la:function(){return r?r.s.la():void 0},ma:function(){return r?r.ma:void 0}}}(),d.b("computedContext",d.Y),d.b("computedContext.getDependenciesCount",d.Y.la),d.b("computedContext.isInitial",d.Y.ma),d.b("computedContext.isSleeping",d.Y.Ac),d.p=function(e){function t(){return 0<arguments.length?(t.Pa(r,arguments[0])&&(t.X(),r=arguments[0],t.W()),this):(d.k.Jb(t),r)}var r=e;return d.P.call(t),d.a.Aa(t,d.p.fn),t.v=function(){return r},t.W=function(){t.notifySubscribers(r)},t.X=function(){t.notifySubscribers(r,"beforeChange")},d.A(t,"peek",t.v),d.A(t,"valueHasMutated",t.W),d.A(t,"valueWillMutate",t.X),t},d.p.fn={equalityComparer:l};var v=d.p.rc="__ko_proto__";d.p.fn[v]=d.p,d.a.xa&&d.a.za(d.p.fn,d.P.fn),d.Ma=function(t,r){return null===t||t===e||t[v]===e?!1:t[v]===r?!0:d.Ma(t[v],r)},d.C=function(e){return d.Ma(e,d.p)},d.Ra=function(e){return"function"==typeof e&&e[v]===d.p||"function"==typeof e&&e[v]===d.j&&e.hc?!0:!1},d.b("observable",d.p),d.b("isObservable",d.C),d.b("isWriteableObservable",d.Ra),d.b("isWritableObservable",d.Ra),d.aa=function(e){if(e=e||[],"object"!=typeof e||!("length"in e))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");return e=d.p(e),d.a.Aa(e,d.aa.fn),e.extend({trackArrayChanges:!0})},d.aa.fn={remove:function(e){for(var t=this.v(),r=[],i="function"!=typeof e||d.C(e)?function(t){return t===e}:e,n=0;n<t.length;n++){var o=t[n];i(o)&&(0===r.length&&this.X(),r.push(o),t.splice(n,1),n--)}return r.length&&this.W(),r},removeAll:function(t){if(t===e){var r=this.v(),i=r.slice(0);return this.X(),r.splice(0,r.length),this.W(),i}return t?this.remove(function(e){return 0<=d.a.m(t,e)}):[]},destroy:function(e){var t=this.v(),r="function"!=typeof e||d.C(e)?function(t){return t===e}:e;this.X();for(var i=t.length-1;i>=0;i--)r(t[i])&&(t[i]._destroy=!0);this.W()},destroyAll:function(t){return t===e?this.destroy(function(){return!0}):t?this.destroy(function(e){return 0<=d.a.m(t,e)}):[]},indexOf:function(e){var t=this();return d.a.m(t,e)},replace:function(e,t){var r=this.indexOf(e);r>=0&&(this.X(),this.v()[r]=t,this.W())}},d.a.u("pop push reverse shift sort splice unshift".split(" "),function(e){d.aa.fn[e]=function(){var t=this.v();return this.X(),this.sb(t,e,arguments),t=t[e].apply(t,arguments),this.W(),t}}),d.a.u(["slice"],function(e){d.aa.fn[e]=function(){var t=this();return t[e].apply(t,arguments)}}),d.a.xa&&d.a.za(d.aa.fn,d.p.fn),d.b("observableArray",d.aa);var _="arrayChange";d.La.trackArrayChanges=function(e){function t(){if(!r){r=!0;var t=e.notifySubscribers;e.notifySubscribers=function(e,r){return r&&r!==m||++n,t.apply(this,arguments)};var o=[].concat(e.v()||[]);i=null,e.U(function(t){if(t=[].concat(t||[]),e.Ab(_)){var r;(!i||n>1)&&(i=d.a.Fa(o,t,{sparse:!0})),r=i,r.length&&e.notifySubscribers(r,_)}o=t,i=null,n=0})}}if(!e.sb){var r=!1,i=null,n=0,o=e.U;e.U=e.subscribe=function(e,r,i){return i===_&&t(),o.apply(this,arguments)},e.sb=function(e,t,o){function a(e,t,r){return s[s.length]={status:e,value:t,index:r}}if(r&&!n){var s=[],l=e.length,u=o.length,c=0;switch(t){case"push":c=l;case"unshift":for(t=0;u>t;t++)a("added",o[t],c+t);break;case"pop":c=l-1;case"shift":l&&a("deleted",e[c],c);break;case"splice":t=Math.min(Math.max(0,0>o[0]?l+o[0]:o[0]),l);for(var l=1===u?l:Math.min(t+(o[1]||0),l),u=t+u-2,c=Math.max(l,u),h=[],p=[],m=2;c>t;++t,++m)l>t&&p.push(a("deleted",e[t],t)),u>t&&h.push(a("added",o[m],t));d.a.wb(p,h);break;default:return}i=s}}}},d.s=d.j=function(t,r,i){function n(){d.a.G(b,function(e,t){t.K()}),b={}}function o(){n(),x=0,v=!0,p=!1}function a(){var e=l.throttleEvaluation;e&&e>=0?(clearTimeout(P),P=setTimeout(s,e)):l.ib?l.ib():s()}function s(t){if(m){if(g)throw Error("A 'pure' computed must not be called recursively")}else if(!v){if(w&&w()){if(!f)return void T()}else f=!1;if(m=!0,y)try{var i={};d.k.Ea({wa:function(e,t){i[t]||(i[t]=1,++x)},s:l,ma:e}),x=0,h=_.call(r)}finally{d.k.end(),m=!1}else try{var n=b,o=x;d.k.Ea({wa:function(e,t){v||(o&&n[t]?(b[t]=n[t],++x,delete n[t],--o):b[t]||(b[t]=e.U(a),++x))},s:l,ma:g?e:!x}),b={},x=0;try{var s=r?_.call(r):_()}finally{d.k.end(),o&&d.a.G(n,function(e,t){t.K()}),p=!1}l.Pa(h,s)&&(l.notifySubscribers(h,"beforeChange"),h=s,!0!==t&&l.notifySubscribers(h))}finally{m=!1}x||T()}}function l(){if(0<arguments.length){if("function"!=typeof C)throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return C.apply(r,arguments),this}return d.k.Jb(l),p&&s(!0),h}function u(){return p&&!x&&s(!0),h}function c(){return p||x>0}var h,p=!0,m=!1,f=!1,v=!1,_=t,g=!1,y=!1;if(_&&"object"==typeof _?(i=_,_=i.read):(i=i||{},_||(_=i.read)),"function"!=typeof _)throw Error("Pass a function that returns the value of the ko.computed");var C=i.write,E=i.disposeWhenNodeIsRemoved||i.o||null,S=i.disposeWhen||i.Ia,w=S,T=o,b={},x=0,P=null;r||(r=i.owner),d.P.call(l),d.a.Aa(l,d.j.fn),l.v=u,l.la=function(){return x},l.hc="function"==typeof i.write,l.K=function(){T()},l.Z=c;var A=l.Ta;return l.Ta=function(e){A.call(l,e),l.ib=function(){l.kb(h),p=!0,l.lb(l)}},i.pure?(y=g=!0,l.va=function(){y&&(y=!1,s(!0))},l.nb=function(){l.yb()||(n(),y=p=!0)}):i.deferEvaluation&&(l.va=function(){u(),delete l.va}),d.A(l,"peek",l.v),d.A(l,"dispose",l.K),d.A(l,"isActive",l.Z),d.A(l,"getDependenciesCount",l.la),E&&(f=!0,E.nodeType&&(w=function(){return!d.a.Ja(E)||S&&S()})),y||i.deferEvaluation||s(),E&&c()&&E.nodeType&&(T=function(){d.a.w.Kb(E,T),o()},d.a.w.da(E,T)),l},d.jc=function(e){return d.Ma(e,d.j)},f=d.p.rc,d.j[f]=d.p,d.j.fn={equalityComparer:l},d.j.fn[f]=d.j,d.a.xa&&d.a.za(d.j.fn,d.P.fn),d.b("dependentObservable",d.j),d.b("computed",d.j),d.b("isComputed",d.jc),d.Ib=function(e,t){return"function"==typeof e?d.s(e,t,{pure:!0}):(e=d.a.extend({},e),e.pure=!0,d.s(e,t))},d.b("pureComputed",d.Ib),function(){function t(n,o,a){if(a=a||new i,n=o(n),"object"!=typeof n||null===n||n===e||n instanceof Date||n instanceof String||n instanceof Number||n instanceof Boolean)return n;var s=n instanceof Array?[]:{};return a.save(n,s),r(n,function(r){var i=o(n[r]);switch(typeof i){case"boolean":case"number":case"string":case"function":s[r]=i;break;case"object":case"undefined":var l=a.get(i);s[r]=l!==e?l:t(i,o,a)}}),s}function r(e,t){if(e instanceof Array){for(var r=0;r<e.length;r++)t(r);"function"==typeof e.toJSON&&t("toJSON")}else for(r in e)t(r)}function i(){this.keys=[],this.hb=[]}d.Qb=function(e){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return t(e,function(e){for(var t=0;d.C(e)&&10>t;t++)e=e();return e})},d.toJSON=function(e,t,r){return e=d.Qb(e),d.a.eb(e,t,r)},i.prototype={save:function(e,t){var r=d.a.m(this.keys,e);r>=0?this.hb[r]=t:(this.keys.push(e),this.hb.push(t))},get:function(t){return t=d.a.m(this.keys,t),t>=0?this.hb[t]:e}}}(),d.b("toJS",d.Qb),d.b("toJSON",d.toJSON),function(){d.i={q:function(t){switch(d.a.t(t)){case"option":return!0===t.__ko__hasDomDataOptionValue__?d.a.e.get(t,d.d.options.Va):7>=d.a.L?t.getAttributeNode("value")&&t.getAttributeNode("value").specified?t.value:t.text:t.value;case"select":return 0<=t.selectedIndex?d.i.q(t.options[t.selectedIndex]):e;default:return t.value}},ca:function(t,r,i){switch(d.a.t(t)){case"option":switch(typeof r){case"string":d.a.e.set(t,d.d.options.Va,e),"__ko__hasDomDataOptionValue__"in t&&delete t.__ko__hasDomDataOptionValue__,t.value=r;break;default:d.a.e.set(t,d.d.options.Va,r),t.__ko__hasDomDataOptionValue__=!0,t.value="number"==typeof r?r:""}break;case"select":(""===r||null===r)&&(r=e);for(var n,o=-1,a=0,s=t.options.length;s>a;++a)if(n=d.i.q(t.options[a]),n==r||""==n&&r===e){o=a;break}(i||o>=0||r===e&&1<t.size)&&(t.selectedIndex=o);break;default:(null===r||r===e)&&(r=""),t.value=r}}}}(),d.b("selectExtensions",d.i),d.b("selectExtensions.readValue",d.i.q),d.b("selectExtensions.writeValue",d.i.ca),d.h=function(){function e(e){e=d.a.cb(e),123===e.charCodeAt(0)&&(e=e.slice(1,-1));var t,r,a=[],s=e.match(i),l=0;if(s){s.push(",");for(var u,c=0;u=s[c];++c){var h=u.charCodeAt(0);if(44===h){if(0>=l){t&&a.push(r?{key:t,value:r.join("")}:{unknown:t}),t=r=l=0;continue}}else if(58===h){if(!r)continue}else if(47===h&&c&&1<u.length)(h=s[c-1].match(n))&&!o[h[0]]&&(e=e.substr(e.indexOf(u)+1),s=e.match(i),s.push(","),c=-1,u="/");else if(40===h||123===h||91===h)++l;else if(41===h||125===h||93===h)--l;else if(!t&&!r){t=34===h||39===h?u.slice(1,-1):u;continue}r?r.push(u):r=[u]}}return a}var t=["true","false","null","undefined"],r=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,i=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),n=/[\])"'A-Za-z0-9_$]+$/,o={"in":1,"return":1,"typeof":1},a={};return{ha:[],V:a,Wa:e,ya:function(i,n){function o(e,i){var n;if(!c){var h=d.getBindingHandler(e);if(h&&h.preprocess&&!(i=h.preprocess(i,e,o)))return;(h=a[e])&&(n=i,0<=d.a.m(t,n)?n=!1:(h=n.match(r),n=null===h?!1:h[1]?"Object("+h[1]+")"+h[2]:n),h=n),h&&l.push("'"+e+"':function(_z){"+n+"=_z}")}u&&(i="function(){return "+i+" }"),s.push("'"+e+"':"+i)}n=n||{};var s=[],l=[],u=n.valueAccessors,c=n.bindingParams,h="string"==typeof i?e(i):i;return d.a.u(h,function(e){o(e.key||e.unknown,e.value)}),l.length&&o("_ko_property_writers","{"+l.join(",")+" }"),s.join(",")},lc:function(e,t){for(var r=0;r<e.length;r++)if(e[r].key==t)return!0;return!1},pa:function(e,t,r,i,n){e&&d.C(e)?!d.Ra(e)||n&&e.v()===i||e(i):(e=t.get("_ko_property_writers"))&&e[r]&&e[r](i)}}}(),d.b("expressionRewriting",d.h),d.b("expressionRewriting.bindingRewriteValidators",d.h.ha),d.b("expressionRewriting.parseObjectLiteral",d.h.Wa),d.b("expressionRewriting.preProcessBindings",d.h.ya),d.b("expressionRewriting._twoWayBindings",d.h.V),d.b("jsonExpressionRewriting",d.h),d.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",d.h.ya),function(){function e(e){return 8==e.nodeType&&a.test(o?e.text:e.nodeValue)}function t(e){return 8==e.nodeType&&s.test(o?e.text:e.nodeValue)}function r(r,i){for(var n=r,o=1,a=[];n=n.nextSibling;){if(t(n)&&(o--,0===o))return a;a.push(n),e(n)&&o++}if(!i)throw Error("Cannot find closing comment tag to match: "+r.nodeValue);return null}function i(e,t){var i=r(e,t);return i?0<i.length?i[i.length-1].nextSibling:e.nextSibling:null}var o=n&&"<!--test-->"===n.createComment("test").text,a=o?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,s=o?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,l={ul:!0,ol:!0};d.f={Q:{},childNodes:function(t){return e(t)?r(t):t.childNodes},ja:function(t){if(e(t)){t=d.f.childNodes(t);for(var r=0,i=t.length;i>r;r++)d.removeNode(t[r])}else d.a.Ka(t)},T:function(t,r){if(e(t)){d.f.ja(t);for(var i=t.nextSibling,n=0,o=r.length;o>n;n++)i.parentNode.insertBefore(r[n],i)}else d.a.T(t,r)},Hb:function(t,r){e(t)?t.parentNode.insertBefore(r,t.nextSibling):t.firstChild?t.insertBefore(r,t.firstChild):t.appendChild(r)},Bb:function(t,r,i){i?e(t)?t.parentNode.insertBefore(r,i.nextSibling):i.nextSibling?t.insertBefore(r,i.nextSibling):t.appendChild(r):d.f.Hb(t,r)},firstChild:function(r){return e(r)?!r.nextSibling||t(r.nextSibling)?null:r.nextSibling:r.firstChild},nextSibling:function(r){return e(r)&&(r=i(r)),r.nextSibling&&t(r.nextSibling)?null:r.nextSibling},gc:e,xc:function(e){return(e=(o?e.text:e.nodeValue).match(a))?e[1]:null},Fb:function(r){if(l[d.a.t(r)]){var n=r.firstChild;if(n)do if(1===n.nodeType){var o;o=n.firstChild;var a=null;if(o)do if(a)a.push(o);else if(e(o)){var s=i(o,!0);s?o=s:a=[o]}else t(o)&&(a=[o]);while(o=o.nextSibling);if(o=a)for(a=n.nextSibling,s=0;s<o.length;s++)a?r.insertBefore(o[s],a):r.appendChild(o[s])}while(n=n.nextSibling)}}}}(),d.b("virtualElements",d.f),d.b("virtualElements.allowedBindings",d.f.Q),d.b("virtualElements.emptyNode",d.f.ja),d.b("virtualElements.insertAfter",d.f.Bb),d.b("virtualElements.prepend",d.f.Hb),d.b("virtualElements.setDomNodeChildren",d.f.T),function(){d.J=function(){this.Yb={}},d.a.extend(d.J.prototype,{nodeHasBindings:function(e){switch(e.nodeType){case 1:return null!=e.getAttribute("data-bind")||d.g.getComponentNameForNode(e);case 8:return d.f.gc(e);default:return!1}},getBindings:function(e,t){var r=this.getBindingsString(e,t),r=r?this.parseBindingsString(r,t,e):null;return d.g.mb(r,e,t,!1)},getBindingAccessors:function(e,t){var r=this.getBindingsString(e,t),r=r?this.parseBindingsString(r,t,e,{valueAccessors:!0}):null;return d.g.mb(r,e,t,!0)},getBindingsString:function(e){switch(e.nodeType){case 1:return e.getAttribute("data-bind");case 8:return d.f.xc(e);default:return null}},parseBindingsString:function(e,t,r,i){try{var n,o=this.Yb,a=e+(i&&i.valueAccessors||"");if(!(n=o[a])){var s,l="with($context){with($data||{}){return{"+d.h.ya(e,i)+"}}}";s=new Function("$context","$element",l),n=o[a]=s}return n(t,r)}catch(u){throw u.message="Unable to parse bindings.\nBindings value: "+e+"\nMessage: "+u.message,u}}}),d.J.instance=new d.J}(),d.b("bindingProvider",d.J),function(){function t(e){return function(){return e}}function r(e){return e()}function n(e){return d.a.na(d.k.B(e),function(t,r){return function(){return e()[r]}})}function o(e,t){return n(this.getBindings.bind(this,e,t))}function s(e,t,r){var i,n=d.f.firstChild(t),o=d.J.instance,a=o.preprocessNode;if(a){for(;i=n;)n=d.f.nextSibling(i),a.call(o,i);n=d.f.firstChild(t)}for(;i=n;)n=d.f.nextSibling(i),l(e,i,r)}function l(e,t,r){var i=!0,n=1===t.nodeType;n&&d.f.Fb(t),(n&&r||d.J.instance.nodeHasBindings(t))&&(i=c(t,null,e,r).shouldBindDescendants),i&&!p[d.a.t(t)]&&s(e,t,!n)}function u(e){var t=[],r={},i=[];return d.a.G(e,function n(o){if(!r[o]){var a=d.getBindingHandler(o);a&&(a.after&&(i.push(o),d.a.u(a.after,function(t){if(e[t]){if(-1!==d.a.m(i,t))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+i.join(", "));n(t)}}),i.length--),t.push({key:o,zb:a})),r[o]=!0}}),t}function c(t,i,n,a){var s=d.a.e.get(t,m);if(!i){if(s)throw Error("You cannot apply bindings multiple times to the same element.");d.a.e.set(t,m,!0)}!s&&a&&d.Ob(t,n);var l;if(i&&"function"!=typeof i)l=i;else{var c=d.J.instance,h=c.getBindingAccessors||o,p=d.j(function(){return(l=i?i(n,t):h.call(c,t,n))&&n.I&&n.I(),l},null,{o:t});l&&p.Z()||(p=null)}var f;if(l){var v=p?function(e){return function(){return r(p()[e])}}:function(e){return l[e]},_=function(){return d.a.na(p?p():l,r)};_.get=function(e){return l[e]&&r(v(e))},_.has=function(e){return e in l},a=u(l),d.a.u(a,function(r){var i=r.zb.init,o=r.zb.update,a=r.key;if(8===t.nodeType&&!d.f.Q[a])throw Error("The binding '"+a+"' cannot be used with virtual elements");try{"function"==typeof i&&d.k.B(function(){var r=i(t,v(a),_,n.$data,n);if(r&&r.controlsDescendantBindings){if(f!==e)throw Error("Multiple bindings ("+f+" and "+a+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");f=a}}),"function"==typeof o&&d.j(function(){o(t,v(a),_,n.$data,n)},null,{o:t})}catch(s){throw s.message='Unable to process binding "'+a+": "+l[a]+'"\nMessage: '+s.message,s}})}return{shouldBindDescendants:f===e}}function h(e){return e&&e instanceof d.N?e:new d.N(e)}d.d={};var p={script:!0};d.getBindingHandler=function(e){return d.d[e]},d.N=function(t,r,i,n){var o,a=this,s="function"==typeof t&&!d.C(t),l=d.j(function(){var e=s?t():t,o=d.a.c(e);return r?(r.I&&r.I(),d.a.extend(a,r),l&&(a.I=l)):(a.$parents=[],a.$root=o,a.ko=d),a.$rawData=e,a.$data=o,i&&(a[i]=o),n&&n(a,r,o),a.$data},null,{Ia:function(){return o&&!d.a.ob(o)},o:!0});l.Z()&&(a.I=l,l.equalityComparer=null,o=[],l.Tb=function(t){o.push(t),d.a.w.da(t,function(t){d.a.ua(o,t),o.length||(l.K(),a.I=l=e)})})},d.N.prototype.createChildContext=function(e,t,r){return new d.N(e,this,t,function(e,t){e.$parentContext=t,e.$parent=t.$data,e.$parents=(t.$parents||[]).slice(0),e.$parents.unshift(e.$parent),r&&r(e)})},d.N.prototype.extend=function(e){return new d.N(this.I||this.$data,this,null,function(t,r){t.$rawData=r.$rawData,d.a.extend(t,"function"==typeof e?e():e)})};var m=d.a.e.F(),f=d.a.e.F();d.Ob=function(e,t){return 2!=arguments.length?d.a.e.get(e,f):(d.a.e.set(e,f,t),void(t.I&&t.I.Tb(e)))},d.ra=function(e,t,r){return 1===e.nodeType&&d.f.Fb(e),c(e,t,h(r),!0)},d.Wb=function(e,r,i){return i=h(i),d.ra(e,"function"==typeof r?n(r.bind(null,i,e)):d.a.na(r,t),i)},d.Ca=function(e,t){1!==t.nodeType&&8!==t.nodeType||s(h(e),t,!0)},d.pb=function(e,t){if(!a&&i.jQuery&&(a=i.jQuery),t&&1!==t.nodeType&&8!==t.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");t=t||i.document.body,l(h(e),t,!0)},d.Ha=function(t){switch(t.nodeType){case 1:case 8:var r=d.Ob(t);if(r)return r;if(t.parentNode)return d.Ha(t.parentNode)}return e},d.$b=function(t){return(t=d.Ha(t))?t.$data:e},d.b("bindingHandlers",d.d),d.b("applyBindings",d.pb),d.b("applyBindingsToDescendants",d.Ca),d.b("applyBindingAccessorsToNode",d.ra),d.b("applyBindingsToNode",d.Wb),d.b("contextFor",d.Ha),d.b("dataFor",d.$b)}(),function(e){function t(t,i){var a,s=n.hasOwnProperty(t)?n[t]:e;s||(s=n[t]=new d.P,r(t,function(e){o[t]=e,delete n[t],a?s.notifySubscribers(e):setTimeout(function(){s.notifySubscribers(e)},0)}),a=!0),s.U(i)}function r(e,t){i("getConfig",[e],function(r){r?i("loadComponent",[e,r],function(e){t(e)}):t(null)})}function i(t,r,n,o){o||(o=d.g.loaders.slice(0));var a=o.shift();if(a){var s=a[t];if(s){var l=!1;if(s.apply(a,r.concat(function(e){l?n(null):null!==e?n(e):i(t,r,n,o)}))!==e&&(l=!0,!a.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.")}else i(t,r,n,o)}else n(null)}var n={},o={};d.g={get:function(r,i){var n=o.hasOwnProperty(r)?o[r]:e;n?setTimeout(function(){i(n)},0):t(r,i)},tb:function(e){delete o[e]},jb:i},d.g.loaders=[],d.b("components",d.g),d.b("components.get",d.g.get),d.b("components.clearCachedDefinition",d.g.tb)}(),function(){function e(e,t,r,i){function n(){0===--a&&i(o)}var o={},a=2,l=r.template;r=r.viewModel,l?s(t,l,function(t){d.g.jb("loadTemplate",[e,t],function(e){o.template=e,n()})}):n(),r?s(t,r,function(t){d.g.jb("loadViewModel",[e,t],function(e){o[c]=e,n()})}):n()}function t(e,r,i){if("function"==typeof r)i(function(e){return new r(e)});else if("function"==typeof r[c])i(r[c]);else if("instance"in r){var n=r.instance;i(function(){return n})}else"viewModel"in r?t(e,r.viewModel,i):e("Unknown viewModel value: "+r)}function o(e){switch(d.a.t(e)){case"script":return d.a.ba(e.text);case"textarea":return d.a.ba(e.value);case"template":if(a(e.content))return d.a.ia(e.content.childNodes)}return d.a.ia(e.childNodes)}function a(e){return i.DocumentFragment?e instanceof DocumentFragment:e&&11===e.nodeType}function s(e,t,n){"string"==typeof t.require?r||i.require?(r||i.require)([t.require],n):e("Uses require, but no AMD loader is present"):n(t)}function l(e){return function(t){throw Error("Component '"+e+"': "+t)}}var u={};d.g.tc=function(e,t){if(!t)throw Error("Invalid configuration for "+e);if(d.g.Qa(e))throw Error("Component "+e+" is already registered");u[e]=t},d.g.Qa=function(e){return e in u},d.g.wc=function(e){delete u[e],d.g.tb(e)},d.g.ub={getConfig:function(e,t){t(u.hasOwnProperty(e)?u[e]:null)},loadComponent:function(t,r,i){var n=l(t);s(n,r,function(r){e(t,n,r,i)})},loadTemplate:function(e,t,r){if(e=l(e),"string"==typeof t)r(d.a.ba(t));else if(t instanceof Array)r(t);else if(a(t))r(d.a.S(t.childNodes));else if(t.element)if(t=t.element,i.HTMLElement?t instanceof HTMLElement:t&&t.tagName&&1===t.nodeType)r(o(t));else if("string"==typeof t){var s=n.getElementById(t);s?r(o(s)):e("Cannot find element with ID "+t)}else e("Unknown element type: "+t);else e("Unknown template value: "+t)},loadViewModel:function(e,r,i){t(l(e),r,i)}};var c="createViewModel";d.b("components.register",d.g.tc),d.b("components.isRegistered",d.g.Qa),d.b("components.unregister",d.g.wc),d.b("components.defaultLoader",d.g.ub),d.g.loaders.push(d.g.ub),d.g.Ub=u}(),function(){function e(e,r){var i=e.getAttribute("params");if(i){var i=t.parseBindingsString(i,r,e,{valueAccessors:!0,bindingParams:!0}),i=d.a.na(i,function(t){return d.s(t,null,{o:e})}),n=d.a.na(i,function(t){return t.Z()?d.s(function(){return d.a.c(t())},null,{o:e}):t.v()});return n.hasOwnProperty("$raw")||(n.$raw=i),n}return{$raw:{}}}d.g.getComponentNameForNode=function(e){return e=d.a.t(e),d.g.Qa(e)&&e},d.g.mb=function(t,r,i,n){if(1===r.nodeType){var o=d.g.getComponentNameForNode(r);if(o){if(t=t||{},t.component)throw Error('Cannot use the "component" binding on a custom element matching a component');var a={name:o,params:e(r,i)};t.component=n?function(){return a}:a}}return t};var t=new d.J;9>d.a.L&&(d.g.register=function(e){return function(t){return n.createElement(t),e.apply(this,arguments)}}(d.g.register),n.createDocumentFragment=function(e){return function(){var t,r=e(),i=d.g.Ub;for(t in i)i.hasOwnProperty(t)&&r.createElement(t);return r}}(n.createDocumentFragment))}(),function(){var e=0;d.d.component={init:function(t,r,i,n,o){function a(){var e=s&&s.dispose;"function"==typeof e&&e.call(s),l=null}var s,l;return d.a.w.da(t,a),d.s(function(){var i,n,u=d.a.c(r());if("string"==typeof u?i=u:(i=d.a.c(u.name),n=d.a.c(u.params)),!i)throw Error("No component name specified");var c=l=++e;d.g.get(i,function(e){if(l===c){if(a(),!e)throw Error("Unknown component '"+i+"'");var r=e.template;if(!r)throw Error("Component '"+i+"' has no template");r=d.a.ia(r),d.f.T(t,r);var r=n,u=e.createViewModel;e=u?u.call(e,r,{element:t}):r,r=o.createChildContext(e),s=e,d.Ca(r,t)}})},null,{o:t}),{controlsDescendantBindings:!0}}},d.f.Q.component=!0}();var g={"class":"className","for":"htmlFor"};d.d.attr={update:function(t,r){var i=d.a.c(r())||{};d.a.G(i,function(r,i){i=d.a.c(i);var n=!1===i||null===i||i===e;n&&t.removeAttribute(r),8>=d.a.L&&r in g?(r=g[r],n?t.removeAttribute(r):t[r]=i):n||t.setAttribute(r,i.toString()),"name"===r&&d.a.Mb(t,n?"":i.toString())})}},function(){d.d.checked={after:["value","attr"],init:function(t,r,i){function n(){var e=t.checked,n=h?a():e;if(!d.Y.ma()&&(!l||e)){var o=d.k.B(r);u?c!==n?(e&&(d.a.ea(o,n,!0),d.a.ea(o,c,!1)),c=n):d.a.ea(o,n,e):d.h.pa(o,i,"checked",n,!0)}}function o(){var e=d.a.c(r());t.checked=u?0<=d.a.m(e,a()):s?e:a()===e}var a=d.Ib(function(){return i.has("checkedValue")?d.a.c(i.get("checkedValue")):i.has("value")?d.a.c(i.get("value")):t.value}),s="checkbox"==t.type,l="radio"==t.type;if(s||l){var u=s&&d.a.c(r())instanceof Array,c=u?a():e,h=l||u;l&&!t.name&&d.d.uniqueName.init(t,function(){return!0}),d.s(n,null,{o:t}),d.a.n(t,"click",n),d.s(o,null,{o:t})}}},d.h.V.checked=!0,d.d.checkedValue={update:function(e,t){e.value=d.a.c(t())}}}(),d.d.css={update:function(e,t){var r=d.a.c(t());"object"==typeof r?d.a.G(r,function(t,r){r=d.a.c(r),d.a.Ba(e,t,r)}):(r=String(r||""),d.a.Ba(e,e.__ko__cssValue,!1),e.__ko__cssValue=r,d.a.Ba(e,r,!0))}},d.d.enable={update:function(e,t){var r=d.a.c(t());r&&e.disabled?e.removeAttribute("disabled"):r||e.disabled||(e.disabled=!0)}},d.d.disable={update:function(e,t){d.d.enable.update(e,function(){return!d.a.c(t())})}},d.d.event={init:function(e,t,r,i,n){var o=t()||{};d.a.G(o,function(o){"string"==typeof o&&d.a.n(e,o,function(e){var a,s=t()[o];if(s){try{var l=d.a.S(arguments);i=n.$data,l.unshift(i),a=s.apply(i,l)}finally{!0!==a&&(e.preventDefault?e.preventDefault():e.returnValue=!1)}!1===r.get(o+"Bubble")&&(e.cancelBubble=!0,e.stopPropagation&&e.stopPropagation())}})})}},d.d.foreach={Eb:function(e){return function(){var t=e(),r=d.a.Xa(t);return r&&"number"!=typeof r.length?(d.a.c(t),{foreach:r.data,as:r.as,includeDestroyed:r.includeDestroyed,afterAdd:r.afterAdd,beforeRemove:r.beforeRemove,afterRender:r.afterRender,beforeMove:r.beforeMove,afterMove:r.afterMove,templateEngine:d.O.Oa}):{foreach:t,templateEngine:d.O.Oa}}},init:function(e,t){return d.d.template.init(e,d.d.foreach.Eb(t))},update:function(e,t,r,i,n){return d.d.template.update(e,d.d.foreach.Eb(t),r,i,n)}},d.h.ha.foreach=!1,d.f.Q.foreach=!0,d.d.hasfocus={init:function(e,t,r){function i(i){e.__ko_hasfocusUpdating=!0;var n=e.ownerDocument;if("activeElement"in n){var o;try{o=n.activeElement}catch(a){o=n.body}i=o===e}n=t(),d.h.pa(n,r,"hasfocus",i,!0),e.__ko_hasfocusLastValue=i,e.__ko_hasfocusUpdating=!1}var n=i.bind(null,!0),o=i.bind(null,!1);d.a.n(e,"focus",n),d.a.n(e,"focusin",n),d.a.n(e,"blur",o),d.a.n(e,"focusout",o)},update:function(e,t){var r=!!d.a.c(t());e.__ko_hasfocusUpdating||e.__ko_hasfocusLastValue===r||(r?e.focus():e.blur(),d.k.B(d.a.oa,null,[e,r?"focusin":"focusout"]))}},d.h.V.hasfocus=!0,d.d.hasFocus=d.d.hasfocus,d.h.V.hasFocus=!0,d.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(e,t){d.a.$a(e,t())}},h("if"),h("ifnot",!1,!0),h("with",!0,!1,function(e,t){return e.createChildContext(t)});var y={};d.d.options={init:function(e){if("select"!==d.a.t(e))throw Error("options binding applies only to SELECT elements");for(;0<e.length;)e.remove(0);return{controlsDescendantBindings:!0}},update:function(t,r,i){function n(){return d.a.ta(t.options,function(e){return e.selected})}function o(e,t,r){var i=typeof t;return"function"==i?t(e):"string"==i?e[t]:r}function a(e,r){if(h.length){var i=0<=d.a.m(h,d.i.q(r[0]));d.a.Nb(r[0],i),p&&!i&&d.k.B(d.a.oa,null,[t,"change"])}}var s=0!=t.length&&t.multiple?t.scrollTop:null,l=d.a.c(r()),u=i.get("optionsIncludeDestroyed");r={};var c,h;h=t.multiple?d.a.Da(n(),d.i.q):0<=t.selectedIndex?[d.i.q(t.options[t.selectedIndex])]:[],l&&("undefined"==typeof l.length&&(l=[l]),c=d.a.ta(l,function(t){return u||t===e||null===t||!d.a.c(t._destroy)}),i.has("optionsCaption")&&(l=d.a.c(i.get("optionsCaption")),null!==l&&l!==e&&c.unshift(y)));var p=!1;r.beforeRemove=function(e){t.removeChild(e)},l=a,i.has("optionsAfterRender")&&(l=function(t,r){a(0,r),d.k.B(i.get("optionsAfterRender"),null,[r[0],t!==y?t:e])}),d.a.Za(t,c,function(r,n,a){return a.length&&(h=a[0].selected?[d.i.q(a[0])]:[],p=!0),n=t.ownerDocument.createElement("option"),r===y?(d.a.bb(n,i.get("optionsCaption")),d.i.ca(n,e)):(a=o(r,i.get("optionsValue"),r),d.i.ca(n,d.a.c(a)),r=o(r,i.get("optionsText"),a),d.a.bb(n,r)),[n]},r,l),d.k.B(function(){i.get("valueAllowUnset")&&i.has("value")?d.i.ca(t,d.a.c(i.get("value")),!0):(t.multiple?h.length&&n().length<h.length:h.length&&0<=t.selectedIndex?d.i.q(t.options[t.selectedIndex])!==h[0]:h.length||0<=t.selectedIndex)&&d.a.oa(t,"change")}),d.a.dc(t),s&&20<Math.abs(s-t.scrollTop)&&(t.scrollTop=s)}},d.d.options.Va=d.a.e.F(),d.d.selectedOptions={after:["options","foreach"],init:function(e,t,r){d.a.n(e,"change",function(){var i=t(),n=[];d.a.u(e.getElementsByTagName("option"),function(e){e.selected&&n.push(d.i.q(e))}),d.h.pa(i,r,"selectedOptions",n)})},update:function(e,t){if("select"!=d.a.t(e))throw Error("values binding applies only to SELECT elements");var r=d.a.c(t());r&&"number"==typeof r.length&&d.a.u(e.getElementsByTagName("option"),function(e){var t=0<=d.a.m(r,d.i.q(e));d.a.Nb(e,t)})}},d.h.V.selectedOptions=!0,d.d.style={update:function(t,r){var i=d.a.c(r()||{});d.a.G(i,function(r,i){i=d.a.c(i),(null===i||i===e||!1===i)&&(i=""),t.style[r]=i})}},d.d.submit={init:function(e,t,r,i,n){if("function"!=typeof t())throw Error("The value for a submit binding must be a function");d.a.n(e,"submit",function(r){var i,o=t();try{i=o.call(n.$data,e)}finally{!0!==i&&(r.preventDefault?r.preventDefault():r.returnValue=!1)}})}},d.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(e,t){d.a.bb(e,t())}},d.f.Q.text=!0,function(){if(i&&i.navigator)var t=function(e){return e?parseFloat(e[1]):void 0},r=i.opera&&i.opera.version&&parseInt(i.opera.version()),n=i.navigator.userAgent,o=t(n.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),a=t(n.match(/Firefox\/([^ ]*)/)); -if(10>d.a.L)var s=d.a.e.F(),l=d.a.e.F(),u=function(e){var t=this.activeElement;(t=t&&d.a.e.get(t,l))&&t(e)},c=function(e,t){var r=e.ownerDocument;d.a.e.get(r,s)||(d.a.e.set(r,s,!0),d.a.n(r,"selectionchange",u)),d.a.e.set(e,l,t)};d.d.textInput={init:function(t,i,n){function s(e,r){d.a.n(t,e,r)}function l(){var r=d.a.c(i());(null===r||r===e)&&(r=""),m!==e&&r===m?setTimeout(l,4):t.value!==r&&(f=r,t.value=r)}function u(){p||(m=t.value,p=setTimeout(h,4))}function h(){clearTimeout(p),m=p=e;var r=t.value;f!==r&&(f=r,d.h.pa(i(),n,"textInput",r))}var p,m,f=t.value;10>d.a.L?(s("propertychange",function(e){"value"===e.propertyName&&h()}),8==d.a.L&&(s("keyup",h),s("keydown",h)),8<=d.a.L&&(c(t,h),s("dragend",u))):(s("input",h),5>o&&"textarea"===d.a.t(t)?(s("keydown",u),s("paste",u),s("cut",u)):11>r?s("keydown",u):4>a&&(s("DOMAutoComplete",h),s("dragdrop",h),s("drop",h))),s("change",h),d.s(l,null,{o:t})}},d.h.V.textInput=!0,d.d.textinput={preprocess:function(e,t,r){r("textInput",e)}}}(),d.d.uniqueName={init:function(e,t){if(t()){var r="ko_unique_"+ ++d.d.uniqueName.Zb;d.a.Mb(e,r)}}},d.d.uniqueName.Zb=0,d.d.value={after:["options","foreach"],init:function(e,t,r){if("input"!=e.tagName.toLowerCase()||"checkbox"!=e.type&&"radio"!=e.type){var i=["change"],n=r.get("valueUpdate"),o=!1,a=null;n&&("string"==typeof n&&(n=[n]),d.a.ga(i,n),i=d.a.rb(i));var s=function(){a=null,o=!1;var i=t(),n=d.i.q(e);d.h.pa(i,r,"value",n)};!d.a.L||"input"!=e.tagName.toLowerCase()||"text"!=e.type||"off"==e.autocomplete||e.form&&"off"==e.form.autocomplete||-1!=d.a.m(i,"propertychange")||(d.a.n(e,"propertychange",function(){o=!0}),d.a.n(e,"focus",function(){o=!1}),d.a.n(e,"blur",function(){o&&s()})),d.a.u(i,function(t){var r=s;d.a.vc(t,"after")&&(r=function(){a=d.i.q(e),setTimeout(s,0)},t=t.substring(5)),d.a.n(e,t,r)});var l=function(){var i=d.a.c(t()),n=d.i.q(e);if(null!==a&&i===a)setTimeout(l,0);else if(i!==n)if("select"===d.a.t(e)){var o=r.get("valueAllowUnset"),n=function(){d.i.ca(e,i,o)};n(),o||i===d.i.q(e)?setTimeout(n,0):d.k.B(d.a.oa,null,[e,"change"])}else d.i.ca(e,i)};d.s(l,null,{o:e})}else d.ra(e,{checkedValue:t})},update:function(){}},d.h.V.value=!0,d.d.visible={update:function(e,t){var r=d.a.c(t()),i="none"!=e.style.display;r&&!i?e.style.display="":!r&&i&&(e.style.display="none")}},function(e){d.d[e]={init:function(t,r,i,n,o){return d.d.event.init.call(this,t,function(){var t={};return t[e]=r(),t},i,n,o)}}}("click"),d.H=function(){},d.H.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource")},d.H.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock")},d.H.prototype.makeTemplateSource=function(e,t){if("string"==typeof e){t=t||n;var r=t.getElementById(e);if(!r)throw Error("Cannot find template with ID "+e);return new d.r.l(r)}if(1==e.nodeType||8==e.nodeType)return new d.r.fa(e);throw Error("Unknown template type: "+e)},d.H.prototype.renderTemplate=function(e,t,r,i){return e=this.makeTemplateSource(e,i),this.renderTemplateSource(e,t,r)},d.H.prototype.isTemplateRewritten=function(e,t){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(e,t).data("isRewritten")},d.H.prototype.rewriteTemplate=function(e,t,r){e=this.makeTemplateSource(e,r),t=t(e.text()),e.text(t),e.data("isRewritten",!0)},d.b("templateEngine",d.H),d.fb=function(){function e(e,t,r,i){e=d.h.Wa(e);for(var n=d.h.ha,o=0;o<e.length;o++){var a=e[o].key;if(n.hasOwnProperty(a)){var s=n[a];if("function"==typeof s){if(a=s(e[o].value))throw Error(a)}else if(!s)throw Error("This template engine does not support the '"+a+"' binding within its templates")}}return r="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+d.h.ya(e,{valueAccessors:!0})+" } })()},'"+r.toLowerCase()+"')",i.createJavaScriptEvaluatorBlock(r)+t}var t=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,r=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{ec:function(e,t,r){t.isTemplateRewritten(e,r)||t.rewriteTemplate(e,function(e){return d.fb.nc(e,t)},r)},nc:function(i,n){return i.replace(t,function(t,r,i,o,a){return e(a,r,i,n)}).replace(r,function(t,r){return e(r,"<!-- ko -->","#comment",n)})},Xb:function(e,t){return d.D.Ua(function(r,i){var n=r.nextSibling;n&&n.nodeName.toLowerCase()===t&&d.ra(n,e,i)})}}}(),d.b("__tr_ambtns",d.fb.Xb),function(){d.r={},d.r.l=function(e){this.l=e},d.r.l.prototype.text=function(){var e=d.a.t(this.l),e="script"===e?"text":"textarea"===e?"value":"innerHTML";if(0==arguments.length)return this.l[e];var t=arguments[0];"innerHTML"===e?d.a.$a(this.l,t):this.l[e]=t};var t=d.a.e.F()+"_";d.r.l.prototype.data=function(e){return 1===arguments.length?d.a.e.get(this.l,t+e):void d.a.e.set(this.l,t+e,arguments[1])};var r=d.a.e.F();d.r.fa=function(e){this.l=e},d.r.fa.prototype=new d.r.l,d.r.fa.prototype.text=function(){if(0==arguments.length){var t=d.a.e.get(this.l,r)||{};return t.gb===e&&t.Ga&&(t.gb=t.Ga.innerHTML),t.gb}d.a.e.set(this.l,r,{gb:arguments[0]})},d.r.l.prototype.nodes=function(){return 0==arguments.length?(d.a.e.get(this.l,r)||{}).Ga:void d.a.e.set(this.l,r,{Ga:arguments[0]})},d.b("templateSources",d.r),d.b("templateSources.domElement",d.r.l),d.b("templateSources.anonymousTemplate",d.r.fa)}(),function(){function t(e,t,r){var i;for(t=d.f.nextSibling(t);e&&(i=e)!==t;)e=d.f.nextSibling(i),r(i,e)}function r(e,r){if(e.length){var i=e[0],n=e[e.length-1],o=i.parentNode,a=d.J.instance,s=a.preprocessNode;if(s){if(t(i,n,function(e,t){var r=e.previousSibling,o=s.call(a,e);o&&(e===i&&(i=o[0]||t),e===n&&(n=o[o.length-1]||r))}),e.length=0,!i)return;i===n?e.push(i):(e.push(i,n),d.a.ka(e,o))}t(i,n,function(e){1!==e.nodeType&&8!==e.nodeType||d.pb(r,e)}),t(i,n,function(e){1!==e.nodeType&&8!==e.nodeType||d.D.Sb(e,[r])}),d.a.ka(e,o)}}function i(e){return e.nodeType?e:0<e.length?e[0]:null}function n(e,t,n,a,s){s=s||{};var l=e&&i(e),l=l&&l.ownerDocument,u=s.templateEngine||o;if(d.fb.ec(n,u,l),n=u.renderTemplate(n,a,s,l),"number"!=typeof n.length||0<n.length&&"number"!=typeof n[0].nodeType)throw Error("Template engine must return an array of DOM nodes");switch(l=!1,t){case"replaceChildren":d.f.T(e,n),l=!0;break;case"replaceNode":d.a.Lb(e,n),l=!0;break;case"ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+t)}return l&&(r(n,a),s.afterRender&&d.k.B(s.afterRender,null,[n,a.$data])),n}var o;d.ab=function(t){if(t!=e&&!(t instanceof d.H))throw Error("templateEngine must inherit from ko.templateEngine");o=t},d.Ya=function(t,r,a,s,l){if(a=a||{},(a.templateEngine||o)==e)throw Error("Set a template engine before calling renderTemplate");if(l=l||"replaceChildren",s){var u=i(s);return d.j(function(){var e=r&&r instanceof d.N?r:new d.N(d.a.c(r)),o=d.C(t)?t():"function"==typeof t?t(e.$data,e):t,e=n(s,l,o,e,a);"replaceNode"==l&&(s=e,u=i(s))},null,{Ia:function(){return!u||!d.a.Ja(u)},o:u&&"replaceNode"==l?u.parentNode:u})}return d.D.Ua(function(e){d.Ya(t,r,a,e,"replaceNode")})},d.uc=function(t,i,o,a,s){function l(e,t){r(t,c),o.afterRender&&o.afterRender(t,e)}function u(e,r){c=s.createChildContext(e,o.as,function(e){e.$index=r});var i=d.C(t)?t():"function"==typeof t?t(e,c):t;return n(null,"ignoreTargetNode",i,c,o)}var c;return d.j(function(){var t=d.a.c(i)||[];"undefined"==typeof t.length&&(t=[t]),t=d.a.ta(t,function(t){return o.includeDestroyed||t===e||null===t||!d.a.c(t._destroy)}),d.k.B(d.a.Za,null,[a,t,u,o,l])},null,{o:a})};var a=d.a.e.F();d.d.template={init:function(e,t){var r=d.a.c(t());return"string"==typeof r||r.name?d.f.ja(e):(r=d.f.childNodes(e),r=d.a.oc(r),new d.r.fa(e).nodes(r)),{controlsDescendantBindings:!0}},update:function(t,r,i,n,o){var s,l=r();r=d.a.c(l),i=!0,n=null,"string"==typeof r?r={}:(l=r.name,"if"in r&&(i=d.a.c(r["if"])),i&&"ifnot"in r&&(i=!d.a.c(r.ifnot)),s=d.a.c(r.data)),"foreach"in r?n=d.uc(l||t,i&&r.foreach||[],r,t,o):i?(o="data"in r?o.createChildContext(s,r.as):o,n=d.Ya(l||t,o,r,t)):d.f.ja(t),o=n,(s=d.a.e.get(t,a))&&"function"==typeof s.K&&s.K(),d.a.e.set(t,a,o&&o.Z()?o:e)}},d.h.ha.template=function(e){return e=d.h.Wa(e),1==e.length&&e[0].unknown||d.h.lc(e,"name")?null:"This template engine does not support anonymous templates nested within its templates"},d.f.Q.template=!0}(),d.b("setTemplateEngine",d.ab),d.b("renderTemplate",d.Ya),d.a.wb=function(e,t,r){if(e.length&&t.length){var i,n,o,a,s;for(i=n=0;(!r||r>i)&&(a=e[n]);++n){for(o=0;s=t[o];++o)if(a.value===s.value){a.moved=s.index,s.moved=a.index,t.splice(o,1),i=o=0;break}i+=o}}},d.a.Fa=function(){function e(e,t,r,i,n){var o,a,s,l,u,c=Math.min,h=Math.max,p=[],m=e.length,f=t.length,v=f-m||1,_=m+f+1;for(o=0;m>=o;o++)for(l=s,p.push(s=[]),u=c(f,o+v),a=h(0,o-1);u>=a;a++)s[a]=a?o?e[o-1]===t[a-1]?l[a-1]:c(l[a]||_,s[a-1]||_)+1:a+1:o+1;for(c=[],h=[],v=[],o=m,a=f;o||a;)f=p[o][a]-1,a&&f===p[o][a-1]?h.push(c[c.length]={status:r,value:t[--a],index:a}):o&&f===p[o-1][a]?v.push(c[c.length]={status:i,value:e[--o],index:o}):(--a,--o,n.sparse||c.push({status:"retained",value:t[a]}));return d.a.wb(h,v,10*m),c.reverse()}return function(t,r,i){return i="boolean"==typeof i?{dontLimitMoves:i}:i||{},t=t||[],r=r||[],t.length<=r.length?e(t,r,"added","deleted",i):e(r,t,"deleted","added",i)}}(),d.b("utils.compareArrays",d.a.Fa),function(){function t(t,r,i,n,o){var a=[],s=d.j(function(){var e=r(i,o,d.a.ka(a,t))||[];0<a.length&&(d.a.Lb(a,e),n&&d.k.B(n,null,[i,e,o])),a.length=0,d.a.ga(a,e)},null,{o:t,Ia:function(){return!d.a.ob(a)}});return{$:a,j:s.Z()?s:e}}var r=d.a.e.F();d.a.Za=function(i,n,o,a,s){function l(e,t){C=h[t],_!==t&&(w[e]=C),C.Na(_++),d.a.ka(C.$,i),f.push(C),y.push(C)}function u(e,t){if(e)for(var r=0,i=t.length;i>r;r++)t[r]&&d.a.u(t[r].$,function(i){e(i,r,t[r].sa)})}n=n||[],a=a||{};var c=d.a.e.get(i,r)===e,h=d.a.e.get(i,r)||[],p=d.a.Da(h,function(e){return e.sa}),m=d.a.Fa(p,n,a.dontLimitMoves),f=[],v=0,_=0,g=[],y=[];n=[];for(var C,E,S,w=[],p=[],T=0;E=m[T];T++)switch(S=E.moved,E.status){case"deleted":S===e&&(C=h[v],C.j&&C.j.K(),g.push.apply(g,d.a.ka(C.$,i)),a.beforeRemove&&(n[T]=C,y.push(C))),v++;break;case"retained":l(T,v++);break;case"added":S!==e?l(T,S):(C={sa:E.value,Na:d.p(_++)},f.push(C),y.push(C),c||(p[T]=C))}u(a.beforeMove,w),d.a.u(g,a.beforeRemove?d.R:d.removeNode);for(var b,T=0,c=d.f.firstChild(i);C=y[T];T++){for(C.$||d.a.extend(C,t(i,o,C.sa,s,C.Na)),v=0;m=C.$[v];c=m.nextSibling,b=m,v++)m!==c&&d.f.Bb(i,m,b);!C.ic&&s&&(s(C.sa,C.$,C.Na),C.ic=!0)}u(a.beforeRemove,n),u(a.afterMove,w),u(a.afterAdd,p),d.a.e.set(i,r,f)}}(),d.b("utils.setDomNodeChildrenFromArrayMapping",d.a.Za),d.O=function(){this.allowTemplateRewriting=!1},d.O.prototype=new d.H,d.O.prototype.renderTemplateSource=function(e){var t=(9>d.a.L?0:e.nodes)?e.nodes():null;return t?d.a.S(t.cloneNode(!0).childNodes):(e=e.text(),d.a.ba(e))},d.O.Oa=new d.O,d.ab(d.O.Oa),d.b("nativeTemplateEngine",d.O),function(){d.Sa=function(){var e=this.kc=function(){if(!a||!a.tmpl)return 0;try{if(0<=a.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(e){}return 1}();this.renderTemplateSource=function(t,r,i){if(i=i||{},2>e)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var o=t.data("precompiled");return o||(o=t.text()||"",o=a.template(null,"{{ko_with $item.koBindingContext}}"+o+"{{/ko_with}}"),t.data("precompiled",o)),t=[r.$data],r=a.extend({koBindingContext:r},i.templateOptions),r=a.tmpl(o,t,r),r.appendTo(n.createElement("div")),a.fragments={},r},this.createJavaScriptEvaluatorBlock=function(e){return"{{ko_code ((function() { return "+e+" })()) }}"},this.addTemplate=function(e,t){n.write("<script type='text/html' id='"+e+"'>"+t+"</script>")},e>0&&(a.tmpl.tag.ko_code={open:"__.push($1 || '');"},a.tmpl.tag.ko_with={open:"with($1) {",close:"} "})},d.Sa.prototype=new d.H;var e=new d.Sa;0<e.kc&&d.ab(e),d.b("jqueryTmplTemplateEngine",d.Sa)}()})}()}(),r("ThirdParty/knockout-es5",[],function(){"use strict";function e(e,r){if(!e)throw new Error("When calling ko.track, you must pass an object as the first parameter.");var n=this,o=t(e,!0);return r=r||Object.getOwnPropertyNames(e),r.forEach(function(t){if(t!==h&&t!==d&&!(t in o)){var r=e[t],a=r instanceof Array,s=n.isObservable(r)?r:a?n.observableArray(r):n.observable(r);Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:s,set:n.isWriteableObservable(s)?s:void 0}),o[t]=s,a&&i(n,s)}}),e}function t(e,t){var r=e[h];return!r&&t&&(r={},Object.defineProperty(e,h,{value:r})),r}function r(t,r,i){var n=this,o={owner:t,deferEvaluation:!0};if("function"==typeof i)o.read=i;else{if("value"in i)throw new Error('For ko.defineProperty, you must not specify a "value" for the property. You must provide a "get" function.');if("function"!=typeof i.get)throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, or an options object containing a function called "get".');o.read=i.get,o.write=i.set}return t[r]=n.computed(o),e.call(n,t,[r]),t}function i(e,t){var r=null;e.computed(function(){r&&(r.dispose(),r=null);var i=t();i instanceof Array&&(r=n(e,t,i))})}function n(e,t,r){var i=o(e,r);return i.subscribe(t)}function o(e,t){var r=t[d];if(!r){r=new e.subscribable,Object.defineProperty(t,d,{value:r});var i={};a(t,r,i),s(e,t,r,i)}return r}function a(e,t,r){["pop","push","reverse","shift","sort","splice","unshift"].forEach(function(i){var n=e[i];e[i]=function(){var e=n.apply(this,arguments);return r.pause!==!0&&t.notifySubscribers(this),e}})}function s(e,t,r,i){["remove","removeAll","destroy","destroyAll","replace"].forEach(function(n){Object.defineProperty(t,n,{enumerable:!1,value:function(){var o;i.pause=!0;try{o=e.observableArray.fn[n].apply(e.observableArray(t),arguments)}finally{i.pause=!1}return r.notifySubscribers(t),o}})})}function l(e,r){if(!e)return null;var i=t(e,!1);return i&&i[r]||null}function u(e,t){var r=l(e,t);r&&r.valueHasMutated()}function c(t){t.track=e,t.getObservable=l,t.valueHasMutated=u,t.defineProperty=r}var h="__knockoutObservables",d="__knockoutSubscribable";return{attachToKo:c}}),r("Widgets/SvgPathBindingHandler",[],function(){"use strict";var e="http://www.w3.org/2000/svg",t="cesium-svgPath-svg",r={register:function(r){r.bindingHandlers.cesiumSvgPath={init:function(i,n){var o=document.createElementNS(e,"svg:svg");o.setAttribute("class",t);var a=document.createElementNS(e,"path");return o.appendChild(a),r.virtualElements.setDomNodeChildren(i,[o]),r.computed({read:function(){var e=r.unwrap(n());a.setAttribute("d",r.unwrap(e.path));var i=r.unwrap(e.width),s=r.unwrap(e.height);o.setAttribute("width",i),o.setAttribute("height",s),o.setAttribute("viewBox","0 0 "+i+" "+s),e.css&&o.setAttribute("class",t+" "+r.unwrap(e.css))},disposeWhenNodeIsRemoved:i}),{controlsDescendantBindings:!0}}},r.virtualElements.allowedBindings.cesiumSvgPath=!0}};return r}),r("ThirdParty/knockout",["./knockout-3.2.0","./knockout-es5","../Widgets/SvgPathBindingHandler"],function(e,t,r){"use strict";return t.attachToKo(e),r.register(e),e}),r("Widgets/subscribeAndEvaluate",["../ThirdParty/knockout"],function(e){"use strict";var t=function(t,r,i,n,o){return i.call(n,t[r]),e.getObservable(t,r).subscribe(i,n,o)};return t}),r("Widgets/Animation/Animation",["../../Core/Color","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../getElement","../subscribeAndEvaluate"],function(e,t,r,i,n,o,a){"use strict";function s(t){return e.fromCssColorString(window.getComputedStyle(t).getPropertyValue("color"))}function l(e){var t=document.createElementNS(v,e.tagName);for(var r in e)if(e.hasOwnProperty(r)&&"tagName"!==r)if("children"===r){var i,n=e.children.length;for(i=0;n>i;++i)t.appendChild(l(e.children[i]))}else 0===r.indexOf("xlink:")?t.setAttributeNS(_,r.substring(6),e[r]):"textContent"===r?t.textContent=e[r]:t.setAttribute(r,e[r]);return t}function u(e,t,r){var i=document.createElementNS(v,"text");i.setAttribute("x",e),i.setAttribute("y",t),i.setAttribute("class","cesium-animation-svgText");var n=document.createElementNS(v,"tspan");return n.textContent=r,i.appendChild(n),i}function c(e,t,r){e.setAttribute("transform","translate(100,100) rotate("+r+")"),t.setAttribute("transform","rotate("+r+")")}function h(e,t){var r=t.alpha,i=1-r;return x.red=e.red*i+t.red*r,x.green=e.green*i+t.green*r,x.blue=e.blue*i+t.blue*r,x.toCssColorString()}function d(e,t,r){var i={tagName:"g","class":"cesium-animation-rectButton",transform:"translate("+e+","+t+")",children:[{tagName:"rect","class":"cesium-animation-buttonGlow",width:32,height:32,rx:2,ry:2},{tagName:"rect","class":"cesium-animation-buttonMain",width:32,height:32,rx:4,ry:4},{tagName:"use","class":"cesium-animation-buttonPath","xlink:href":r},{tagName:"title",textContent:""}]};return l(i)}function p(e,t,r){var i={tagName:"g","class":"cesium-animation-rectButton",transform:"translate("+e+","+t+")",children:[{tagName:"use","class":"cesium-animation-buttonGlow","xlink:href":"#animation_pathWingButton"},{tagName:"use","class":"cesium-animation-buttonMain","xlink:href":"#animation_pathWingButton"},{tagName:"use","class":"cesium-animation-buttonPath","xlink:href":r},{tagName:"title",textContent:""}]};return l(i)}function m(e,t){var r=e._viewModel,i=r.shuttleRingDragging;if(!i||f===e)if("mousedown"===t.type||i&&"mousemove"===t.type||"touchstart"===t.type&&1===t.touches.length||i&&"touchmove"===t.type&&1===t.touches.length){var n,o,a=e._centerX,s=e._centerY,l=e._svgNode,u=l.getBoundingClientRect();if("touchstart"===t.type||"touchmove"===t.type?(n=t.touches[0].clientX,o=t.touches[0].clientY):(n=t.clientX,o=t.clientY),!i&&(n>u.right||n<u.left||o<u.top||o>u.bottom))return;var c=e._shuttleRingPointer.getBoundingClientRect(),h=n-a-u.left,d=o-s-u.top,p=180*Math.atan2(d,h)/Math.PI+90;p>180&&(p-=360);var m=r.shuttleRingAngle;i||n<c.right&&n>c.left&&o>c.top&&o<c.bottom?(f=e,r.shuttleRingDragging=!0,r.shuttleRingAngle=p):m>p?r.slower():p>m&&r.faster(),t.preventDefault()}else e===f&&(f=void 0),r.shuttleRingDragging=!1}var f,v="http://www.w3.org/2000/svg",_="http://www.w3.org/1999/xlink",g=e.fromCssColorString("rgba(247,250,255,0.384)"),y=e.fromCssColorString("rgba(143,191,255,0.216)"),C=e.fromCssColorString("rgba(153,197,255,0.098)"),E=e.fromCssColorString("rgba(255,255,255,0.086)"),S=e.fromCssColorString("rgba(255,255,255,0.267)"),w=e.fromCssColorString("rgba(255,255,255,0)"),T=e.fromCssColorString("rgba(66,67,68,0.3)"),b=e.fromCssColorString("rgba(0,0,0,0.5)"),x=new e,P=function(e,t){this._viewModel=t,this.svgElement=e,this._enabled=void 0,this._toggled=void 0;var r=this;this._clickFunction=function(){var e=r._viewModel.command;e.canExecute&&e()},e.addEventListener("click",this._clickFunction,!0),this._subscriptions=[a(t,"toggled",this.setToggled,this),a(t,"tooltip",this.setTooltip,this),a(t.command,"canExecute",this.setEnabled,this)]};P.prototype.destroy=function(){this.svgElement.removeEventListener("click",this._clickFunction,!0);for(var e=this._subscriptions,t=0,r=e.length;r>t;t++)e[t].dispose();i(this)},P.prototype.isDestroyed=function(){return!1},P.prototype.setEnabled=function(e){if(this._enabled!==e){if(this._enabled=e,!e)return void this.svgElement.setAttribute("class","cesium-animation-buttonDisabled");if(this._toggled)return void this.svgElement.setAttribute("class","cesium-animation-rectButton cesium-animation-buttonToggled");this.svgElement.setAttribute("class","cesium-animation-rectButton")}},P.prototype.setToggled=function(e){this._toggled!==e&&(this._toggled=e,this._enabled&&(e?this.svgElement.setAttribute("class","cesium-animation-rectButton cesium-animation-buttonToggled"):this.svgElement.setAttribute("class","cesium-animation-rectButton")))},P.prototype.setTooltip=function(e){this.svgElement.getElementsByTagName("title")[0].textContent=e};var A=function(e,t){e=o(e),this._viewModel=t,this._container=e,this._centerX=0,this._centerY=0,this._defsElement=void 0,this._svgNode=void 0,this._topG=void 0,this._lastHeight=void 0,this._lastWidth=void 0;var r=document.createElement("style");r.textContent=".cesium-animation-rectButton .cesium-animation-buttonGlow { filter: url(#animation_blurred); }.cesium-animation-rectButton .cesium-animation-buttonMain { fill: url(#animation_buttonNormal); }.cesium-animation-buttonToggled .cesium-animation-buttonMain { fill: url(#animation_buttonToggled); }.cesium-animation-rectButton:hover .cesium-animation-buttonMain { fill: url(#animation_buttonHovered); }.cesium-animation-buttonDisabled .cesium-animation-buttonMain { fill: url(#animation_buttonDisabled); }.cesium-animation-shuttleRingG .cesium-animation-shuttleRingSwoosh { fill: url(#animation_shuttleRingSwooshGradient); }.cesium-animation-shuttleRingG:hover .cesium-animation-shuttleRingSwoosh { fill: url(#animation_shuttleRingSwooshHovered); }.cesium-animation-shuttleRingPointer { fill: url(#animation_shuttleRingPointerGradient); }.cesium-animation-shuttleRingPausePointer { fill: url(#animation_shuttleRingPointerPaused); }.cesium-animation-knobOuter { fill: url(#animation_knobOuter); }.cesium-animation-knobInner { fill: url(#animation_knobInner); }",document.head.insertBefore(r,document.head.childNodes[0]);var i=document.createElement("div");i.className="cesium-animation-theme",i.innerHTML='<div class="cesium-animation-themeNormal"></div><div class="cesium-animation-themeHover"></div><div class="cesium-animation-themeSelect"></div><div class="cesium-animation-themeDisabled"></div><div class="cesium-animation-themeKnob"></div><div class="cesium-animation-themePointer"></div><div class="cesium-animation-themeSwoosh"></div><div class="cesium-animation-themeSwooshHover"></div>',this._theme=i,this._themeNormal=i.childNodes[0],this._themeHover=i.childNodes[1],this._themeSelect=i.childNodes[2],this._themeDisabled=i.childNodes[3],this._themeKnob=i.childNodes[4],this._themePointer=i.childNodes[5],this._themeSwoosh=i.childNodes[6],this._themeSwooshHover=i.childNodes[7];var n=document.createElementNS(v,"svg:svg");this._svgNode=n,n.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink",_);var s=document.createElementNS(v,"g");this._topG=s,this._realtimeSVG=new P(p(3,4,"#animation_pathClock"),t.playRealtimeViewModel),this._playReverseSVG=new P(d(44,99,"#animation_pathPlayReverse"),t.playReverseViewModel),this._playForwardSVG=new P(d(124,99,"#animation_pathPlay"),t.playForwardViewModel),this._pauseSVG=new P(d(84,99,"#animation_pathPause"),t.pauseViewModel);var h=document.createElementNS(v,"g");h.appendChild(this._realtimeSVG.svgElement),h.appendChild(this._playReverseSVG.svgElement),h.appendChild(this._playForwardSVG.svgElement),h.appendChild(this._pauseSVG.svgElement);var f=l({tagName:"circle","class":"cesium-animation-shuttleRingBack",cx:100,cy:100,r:99});this._shuttleRingBackPanel=f;var g=l({tagName:"g","class":"cesium-animation-shuttleRingSwoosh",children:[{tagName:"use",transform:"translate(100,97) scale(-1,1)","xlink:href":"#animation_pathSwooshFX"},{tagName:"use",transform:"translate(100,97)","xlink:href":"#animation_pathSwooshFX"},{tagName:"line",x1:100,y1:8,x2:100,y2:22}]});this._shuttleRingSwooshG=g,this._shuttleRingPointer=l({tagName:"use","class":"cesium-animation-shuttleRingPointer","xlink:href":"#animation_pathPointer"});var y=l({tagName:"g",transform:"translate(100,100)"});this._knobOuter=l({tagName:"circle","class":"cesium-animation-knobOuter",cx:0,cy:0,r:71});var C=61,E=l({tagName:"circle","class":"cesium-animation-knobInner",cx:0,cy:0,r:C});this._knobDate=u(0,-24,""),this._knobTime=u(0,-7,""),this._knobStatus=u(0,-41,"");var S=l({tagName:"circle","class":"cesium-animation-blank",cx:0,cy:0,r:C}),w=document.createElementNS(v,"g");w.setAttribute("class","cesium-animation-shuttleRingG"),e.appendChild(i),s.appendChild(w),s.appendChild(y),s.appendChild(h),w.appendChild(f),w.appendChild(g),w.appendChild(this._shuttleRingPointer),y.appendChild(this._knobOuter),y.appendChild(E),y.appendChild(this._knobDate),y.appendChild(this._knobTime),y.appendChild(this._knobStatus),y.appendChild(S),n.appendChild(s),e.appendChild(n);var T=this,b=function(e){m(T,e)};this._mouseCallback=b,f.addEventListener("mousedown",b,!0),f.addEventListener("touchstart",b,!0),g.addEventListener("mousedown",b,!0),g.addEventListener("touchstart",b,!0),document.addEventListener("mousemove",b,!0),document.addEventListener("touchmove",b,!0),document.addEventListener("mouseup",b,!0),document.addEventListener("touchend",b,!0),this._shuttleRingPointer.addEventListener("mousedown",b,!0),this._shuttleRingPointer.addEventListener("touchstart",b,!0),this._knobOuter.addEventListener("mousedown",b,!0),this._knobOuter.addEventListener("touchstart",b,!0);var x,A=this._knobTime.childNodes[0],I=this._knobDate.childNodes[0],M=this._knobStatus.childNodes[0];this._subscriptions=[a(t.pauseViewModel,"toggled",function(e){x!==e&&(x=e,x?T._shuttleRingPointer.setAttribute("class","cesium-animation-shuttleRingPausePointer"):T._shuttleRingPointer.setAttribute("class","cesium-animation-shuttleRingPointer"))}),a(t,"shuttleRingAngle",function(e){c(T._shuttleRingPointer,T._knobOuter,e)}),a(t,"dateLabel",function(e){I.textContent!==e&&(I.textContent=e)}),a(t,"timeLabel",function(e){A.textContent!==e&&(A.textContent=e)}),a(t,"multiplierLabel",function(e){M.textContent!==e&&(M.textContent=e)})],this.applyThemeChanges(),this.resize()};return r(A.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),A.prototype.isDestroyed=function(){return!1},A.prototype.destroy=function(){var e=this._mouseCallback;this._shuttleRingBackPanel.removeEventListener("mousedown",e,!0),this._shuttleRingBackPanel.removeEventListener("touchstart",e,!0),this._shuttleRingSwooshG.removeEventListener("mousedown",e,!0),this._shuttleRingSwooshG.removeEventListener("touchstart",e,!0),document.removeEventListener("mousemove",e,!0),document.removeEventListener("touchmove",e,!0),document.removeEventListener("mouseup",e,!0),document.removeEventListener("touchend",e,!0),this._shuttleRingPointer.removeEventListener("mousedown",e,!0),this._shuttleRingPointer.removeEventListener("touchstart",e,!0),this._knobOuter.removeEventListener("mousedown",e,!0),this._knobOuter.removeEventListener("touchstart",e,!0),this._container.removeChild(this._svgNode),this._container.removeChild(this._theme),this._realtimeSVG.destroy(),this._playReverseSVG.destroy(),this._playForwardSVG.destroy(),this._pauseSVG.destroy();for(var t=this._subscriptions,r=0,n=t.length;n>r;r++)t[r].dispose();return i(this)},A.prototype.resize=function(){var e=this._container.clientWidth,t=this._container.clientHeight;if(e!==this._lastWidth||t!==this._lastHeight){var r=this._svgNode,i=200,n=132,o=e,a=t;0===e&&0===t?(o=i,a=n):0===e?(a=t,o=i*(t/n)):0===t&&(o=e,a=n*(e/i));var s=o/i,l=a/n;r.style.cssText="width: "+o+"px; height: "+a+"px; position: absolute; bottom: 0; left: 0; overflow: hidden;",r.setAttribute("width",o),r.setAttribute("height",a),r.setAttribute("viewBox","0 0 "+o+" "+a),this._topG.setAttribute("transform","scale("+s+","+l+")"),this._centerX=Math.max(1,100*s),this._centerY=Math.max(1,100*l),this._lastHeight=e,this._lastWidth=t}},A.prototype.applyThemeChanges=function(){var e=s(this._themeNormal),r=s(this._themeHover),i=s(this._themeSelect),n=s(this._themeDisabled),o=s(this._themeKnob),a=s(this._themePointer),u=s(this._themeSwoosh),c=s(this._themeSwooshHover),d=l({tagName:"defs",children:[{id:"animation_buttonNormal",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(e,g)},{tagName:"stop",offset:"12%","stop-color":h(e,y)},{tagName:"stop",offset:"46%","stop-color":h(e,C)},{tagName:"stop",offset:"81%","stop-color":h(e,E)}]},{id:"animation_buttonHovered",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(r,g)},{tagName:"stop",offset:"12%","stop-color":h(r,y)},{tagName:"stop",offset:"46%","stop-color":h(r,C)},{tagName:"stop",offset:"81%","stop-color":h(r,E)}]},{id:"animation_buttonToggled",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(i,g)},{tagName:"stop",offset:"12%","stop-color":h(i,y)},{tagName:"stop",offset:"46%","stop-color":h(i,C)},{tagName:"stop",offset:"81%","stop-color":h(i,E)}]},{id:"animation_buttonDisabled",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-color":h(n,S)},{tagName:"stop",offset:"75%","stop-color":h(n,w)}]},{id:"animation_blurred",tagName:"filter",width:"200%",height:"200%",x:"-50%",y:"-50%",children:[{tagName:"feGaussianBlur",stdDeviation:4,"in":"SourceGraphic"}]},{id:"animation_shuttleRingSwooshGradient",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-opacity":.2,"stop-color":u.toCssColorString()},{tagName:"stop",offset:"85%","stop-opacity":.85,"stop-color":u.toCssColorString()},{tagName:"stop",offset:"95%","stop-opacity":.05,"stop-color":u.toCssColorString()}]},{id:"animation_shuttleRingSwooshHovered",tagName:"linearGradient",x1:"50%",y1:"0%",x2:"50%",y2:"100%",children:[{tagName:"stop",offset:"0%","stop-opacity":.2,"stop-color":c.toCssColorString()},{tagName:"stop",offset:"85%","stop-opacity":.85,"stop-color":c.toCssColorString()},{tagName:"stop",offset:"95%","stop-opacity":.05,"stop-color":c.toCssColorString()}]},{id:"animation_shuttleRingPointerGradient",tagName:"linearGradient",x1:"0%",y1:"50%",x2:"100%",y2:"50%",children:[{tagName:"stop",offset:"0%","stop-color":a.toCssColorString()},{tagName:"stop",offset:"40%","stop-color":a.toCssColorString()},{tagName:"stop",offset:"60%","stop-color":h(a,b)},{tagName:"stop",offset:"100%","stop-color":h(a,b)}]},{id:"animation_shuttleRingPointerPaused",tagName:"linearGradient",x1:"0%",y1:"50%",x2:"100%",y2:"50%",children:[{tagName:"stop",offset:"0%","stop-color":"#CCC"},{tagName:"stop",offset:"40%","stop-color":"#CCC"},{tagName:"stop",offset:"60%","stop-color":"#555"},{tagName:"stop",offset:"100%","stop-color":"#555"}]},{id:"animation_knobOuter",tagName:"linearGradient",x1:"20%",y1:"0%",x2:"90%",y2:"100%",children:[{tagName:"stop",offset:"5%","stop-color":h(o,g)},{tagName:"stop",offset:"60%","stop-color":h(o,T)},{tagName:"stop",offset:"85%","stop-color":h(o,y)}]},{id:"animation_knobInner",tagName:"linearGradient",x1:"20%",y1:"0%",x2:"90%",y2:"100%",children:[{tagName:"stop",offset:"5%","stop-color":h(o,T)},{tagName:"stop",offset:"60%","stop-color":h(o,g)},{tagName:"stop",offset:"85%","stop-color":h(o,E)}]},{id:"animation_pathReset",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M24.316,5.318,9.833,13.682,9.833,5.5,5.5,5.5,5.5,25.5,9.833,25.5,9.833,17.318,24.316,25.682z"},{id:"animation_pathPause",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M13,5.5,7.5,5.5,7.5,25.5,13,25.5zM24.5,5.5,19,5.5,19,25.5,24.5,25.5z"},{id:"animation_pathPlay",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M6.684,25.682L24.316,15.5L6.684,5.318V25.682z"},{id:"animation_pathPlayReverse",tagName:"path",transform:"translate(16,16) scale(-0.85,0.85) translate(-16,-16)",d:"M6.684,25.682L24.316,15.5L6.684,5.318V25.682z"},{id:"animation_pathLoop",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-16)",d:"M24.249,15.499c-0.009,4.832-3.918,8.741-8.75,8.75c-2.515,0-4.768-1.064-6.365-2.763l2.068-1.442l-7.901-3.703l0.744,8.694l2.193-1.529c2.244,2.594,5.562,4.242,9.26,4.242c6.767,0,12.249-5.482,12.249-12.249H24.249zM15.499,6.75c2.516,0,4.769,1.065,6.367,2.764l-2.068,1.443l7.901,3.701l-0.746-8.693l-2.192,1.529c-2.245-2.594-5.562-4.245-9.262-4.245C8.734,3.25,3.25,8.734,3.249,15.499H6.75C6.758,10.668,10.668,6.758,15.499,6.75z"},{id:"animation_pathClock",tagName:"path",transform:"translate(16,16) scale(0.85) translate(-16,-15.5)",d:"M15.5,2.374C8.251,2.375,2.376,8.251,2.374,15.5C2.376,22.748,8.251,28.623,15.5,28.627c7.249-0.004,13.124-5.879,13.125-13.127C28.624,8.251,22.749,2.375,15.5,2.374zM15.5,25.623C9.909,25.615,5.385,21.09,5.375,15.5C5.385,9.909,9.909,5.384,15.5,5.374c5.59,0.01,10.115,4.535,10.124,10.125C25.615,21.09,21.091,25.615,15.5,25.623zM8.625,15.5c-0.001-0.552-0.448-0.999-1.001-1c-0.553,0-1,0.448-1,1c0,0.553,0.449,1,1,1C8.176,16.5,8.624,16.053,8.625,15.5zM8.179,18.572c-0.478,0.277-0.642,0.889-0.365,1.367c0.275,0.479,0.889,0.641,1.365,0.365c0.479-0.275,0.643-0.887,0.367-1.367C9.27,18.461,8.658,18.297,8.179,18.572zM9.18,10.696c-0.479-0.276-1.09-0.112-1.366,0.366s-0.111,1.09,0.365,1.366c0.479,0.276,1.09,0.113,1.367-0.366C9.821,11.584,9.657,10.973,9.18,10.696zM22.822,12.428c0.478-0.275,0.643-0.888,0.366-1.366c-0.275-0.478-0.89-0.642-1.366-0.366c-0.479,0.278-0.642,0.89-0.366,1.367C21.732,12.54,22.344,12.705,22.822,12.428zM12.062,21.455c-0.478-0.275-1.089-0.111-1.366,0.367c-0.275,0.479-0.111,1.09,0.366,1.365c0.478,0.277,1.091,0.111,1.365-0.365C12.704,22.344,12.54,21.732,12.062,21.455zM12.062,9.545c0.479-0.276,0.642-0.888,0.366-1.366c-0.276-0.478-0.888-0.642-1.366-0.366s-0.642,0.888-0.366,1.366C10.973,9.658,11.584,9.822,12.062,9.545zM22.823,18.572c-0.48-0.275-1.092-0.111-1.367,0.365c-0.275,0.479-0.112,1.092,0.367,1.367c0.477,0.275,1.089,0.113,1.365-0.365C23.464,19.461,23.3,18.848,22.823,18.572zM19.938,7.813c-0.477-0.276-1.091-0.111-1.365,0.366c-0.275,0.48-0.111,1.091,0.366,1.367s1.089,0.112,1.366-0.366C20.581,8.702,20.418,8.089,19.938,7.813zM23.378,14.5c-0.554,0.002-1.001,0.45-1.001,1c0.001,0.552,0.448,1,1.001,1c0.551,0,1-0.447,1-1C24.378,14.949,23.929,14.5,23.378,14.5zM15.501,6.624c-0.552,0-1,0.448-1,1l-0.466,7.343l-3.004,1.96c-0.478,0.277-0.642,0.889-0.365,1.365c0.275,0.479,0.889,0.643,1.365,0.367l3.305-1.676C15.39,16.99,15.444,17,15.501,17c0.828,0,1.5-0.671,1.5-1.5l-0.5-7.876C16.501,7.072,16.053,6.624,15.501,6.624zM15.501,22.377c-0.552,0-1,0.447-1,1s0.448,1,1,1s1-0.447,1-1S16.053,22.377,15.501,22.377zM18.939,21.455c-0.479,0.277-0.643,0.889-0.366,1.367c0.275,0.477,0.888,0.643,1.366,0.365c0.478-0.275,0.642-0.889,0.366-1.365C20.028,21.344,19.417,21.18,18.939,21.455z" -},{id:"animation_pathWingButton",tagName:"path",d:"m 4.5,0.5 c -2.216,0 -4,1.784 -4,4 l 0,24 c 0,2.216 1.784,4 4,4 l 13.71875,0 C 22.478584,27.272785 27.273681,22.511272 32.5,18.25 l 0,-13.75 c 0,-2.216 -1.784,-4 -4,-4 l -24,0 z"},{id:"animation_pathPointer",tagName:"path",d:"M-15,-65,-15,-55,15,-55,15,-65,0,-95z"},{id:"animation_pathSwooshFX",tagName:"path",d:"m 85,0 c 0,16.617 -4.813944,35.356 -13.131081,48.4508 h 6.099803 c 8.317138,-13.0948 13.13322,-28.5955 13.13322,-45.2124 0,-46.94483 -38.402714,-85.00262 -85.7743869,-85.00262 -1.0218522,0 -2.0373001,0.0241 -3.0506131,0.0589 45.958443,1.59437 82.723058,35.77285 82.723058,81.70532 z"}]});t(this._defsElement)?this._svgNode.replaceChild(d,this._defsElement):this._svgNode.appendChild(d),this._defsElement=d},A}),r("Widgets/createCommand",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../Core/Event","../ThirdParty/knockout"],function(e,t,r,i,n,o){"use strict";var a=function(t,i){function a(){var e,r={args:arguments,cancel:!1};return s.raiseEvent(r),r.cancel||(e=t.apply(null,arguments),l.raiseEvent(e)),e}i=e(i,!0);var s=new n,l=new n;return a.canExecute=i,o.track(a,["canExecute"]),r(a,{beforeExecute:{value:s},afterExecute:{value:l}}),a};return a}),r("Widgets/ToggleButtonViewModel",["../Core/defaultValue","../Core/defined","../Core/defineProperties","../Core/DeveloperError","../ThirdParty/knockout"],function(e,t,r,i,n){"use strict";var o=function(t,r){this._command=t,r=e(r,e.EMPTY_OBJECT),this.toggled=e(r.toggled,!1),this.tooltip=e(r.tooltip,""),n.track(this,["toggled","tooltip"])};return r(o.prototype,{command:{get:function(){return this._command}}}),o}),r("Widgets/Animation/AnimationViewModel",["../../Core/binarySearch","../../Core/ClockRange","../../Core/ClockStep","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/JulianDate","../../ThirdParty/knockout","../../ThirdParty/sprintf","../createCommand","../ToggleButtonViewModel"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(e){e.clockStep===r.SYSTEM_CLOCK&&(e.clockStep=r.SYSTEM_CLOCK_MULTIPLIER,e.multiplier=1)}function d(e){h(e),e.shouldAnimate=!0}function p(e,t){return e-t}function m(t,r){var i=e(r,t,p);return 0>i?~i:i}function f(e,t){if(Math.abs(e)<=g)return e/g;var r,i,n=g,o=y,a=0;return e>0?(r=Math.log(t[t.length-1]),i=(r-a)/(o-n),Math.exp(a+i*(e-n))):(r=Math.log(-t[0]),i=(r-a)/(o-n),-Math.exp(a+i*(Math.abs(e)-n)))}function v(e,t,i){if(i.clockStep===r.SYSTEM_CLOCK)return g;if(Math.abs(e)<=1)return e*g;var n=t[t.length-1];e>n?e=n:-n>e&&(e=-n);var o,a,s=g,l=y,u=0;return e>0?(o=Math.log(n),a=(o-u)/(l-s),(Math.log(e)-u)/a+s):(o=Math.log(-t[0]),a=(o-u)/(l-s),-((Math.log(Math.abs(e))-u)/a+s))}var _=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],g=15,y=105,C=function(e){var i=this;this._clockViewModel=e,this._allShuttleRingTicks=[],this._dateFormatter=C.defaultDateFormatter,this._timeFormatter=C.defaultTimeFormatter,this.shuttleRingDragging=!1,this.snapToTicks=!1,s.track(this,["_allShuttleRingTicks","_dateFormatter","_timeFormatter","shuttleRingDragging","snapToTicks"]),this._sortedFilteredPositiveTicks=[],this.setShuttleRingTicks(C.defaultTicks),this.timeLabel=void 0,s.defineProperty(this,"timeLabel",function(){return i._timeFormatter(i._clockViewModel.currentTime,i)}),this.dateLabel=void 0,s.defineProperty(this,"dateLabel",function(){return i._dateFormatter(i._clockViewModel.currentTime,i)}),this.multiplierLabel=void 0,s.defineProperty(this,"multiplierLabel",function(){var e=i._clockViewModel;if(e.clockStep===r.SYSTEM_CLOCK)return"Today";var t=e.multiplier;return t%1===0?t.toFixed(0)+"x":t.toFixed(3).replace(/0{0,3}$/,"")+"x"}),this.shuttleRingAngle=void 0,s.defineProperty(this,"shuttleRingAngle",{get:function(){return v(e.multiplier,i._allShuttleRingTicks,e)},set:function(e){e=Math.max(Math.min(e,y),-y);var t=i._allShuttleRingTicks,n=i._clockViewModel;if(n.clockStep=r.SYSTEM_CLOCK_MULTIPLIER,Math.abs(e)===y)return void(n.multiplier=e>0?t[t.length-1]:t[0]);var o=f(e,t);if(i.snapToTicks)o=t[m(o,t)];else if(0!==o){var a=Math.abs(o);if(a>100){var s=a.toFixed(0).length-2,l=Math.pow(10,s);o=Math.round(o/l)*l|0}else a>g?o=Math.round(o):a>1?o=+o.toFixed(1):a>0&&(o=+o.toFixed(2))}n.multiplier=o}}),this._canAnimate=void 0,s.defineProperty(this,"_canAnimate",function(){var e=i._clockViewModel,r=e.clockRange;if(i.shuttleRingDragging||r===t.UNBOUNDED)return!0;var n=e.multiplier,o=e.currentTime,s=e.startTime,l=!1;if(r===t.LOOP_STOP)l=a.greaterThan(o,s)||o.equals(s)&&n>0;else{var u=e.stopTime;l=a.greaterThan(o,s)&&a.lessThan(o,u)||o.equals(s)&&n>0||o.equals(u)&&0>n}return l||(e.shouldAnimate=!1),l}),this._isSystemTimeAvailable=void 0,s.defineProperty(this,"_isSystemTimeAvailable",function(){var e=i._clockViewModel,r=e.clockRange;if(r===t.UNBOUNDED)return!0;var n=e.systemTime;return a.greaterThanOrEquals(n,e.startTime)&&a.lessThanOrEquals(n,e.stopTime)}),this._isAnimating=void 0,s.defineProperty(this,"_isAnimating",function(){return i._clockViewModel.shouldAnimate&&(i._canAnimate||i.shuttleRingDragging)});var n=u(function(){var e=i._clockViewModel;e.shouldAnimate?(h(e),e.shouldAnimate=!1):i._canAnimate&&d(e)});this._pauseViewModel=new c(n,{toggled:s.computed(function(){return!i._isAnimating}),tooltip:"Pause"});var o=u(function(){var e=i._clockViewModel;h(e);var t=e.multiplier;t>0&&(e.multiplier=-t),e.shouldAnimate=!0});this._playReverseViewModel=new c(o,{toggled:s.computed(function(){return i._isAnimating&&e.multiplier<0}),tooltip:"Play Reverse"});var l=u(function(){var e=i._clockViewModel;h(e);var t=e.multiplier;0>t&&(e.multiplier=-t),e.shouldAnimate=!0});this._playForwardViewModel=new c(l,{toggled:s.computed(function(){return i._isAnimating&&e.multiplier>0&&e.clockStep!==r.SYSTEM_CLOCK}),tooltip:"Play Forward"});var p=u(function(){var e=i._clockViewModel;e.clockStep=r.SYSTEM_CLOCK,e.multiplier=1,e.shouldAnimate=!0},s.getObservable(this,"_isSystemTimeAvailable"));this._playRealtimeViewModel=new c(p,{toggled:s.computed(function(){return e.shouldAnimate&&e.clockStep===r.SYSTEM_CLOCK}),tooltip:s.computed(function(){return i._isSystemTimeAvailable?"Today (real-time)":"Current time not in range"})}),this._slower=u(function(){var e=i._clockViewModel;h(e);var t=i._allShuttleRingTicks,r=e.multiplier,n=m(r,t)-1;n>=0&&(e.multiplier=t[n])}),this._faster=u(function(){var e=i._clockViewModel;h(e);var t=i._allShuttleRingTicks,r=e.multiplier,n=m(r,t)+1;n<t.length&&(e.multiplier=t[n])})};return C.defaultDateFormatter=function(e,t){var r=a.toGregorianDate(e);return _[r.month-1]+" "+r.day+" "+r.year},C.defaultTicks=[.001,.002,.005,.01,.02,.05,.1,.25,.5,1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,21600,43200,86400,172800,345600,604800],C.defaultTimeFormatter=function(e,t){var r=a.toGregorianDate(e),i=Math.round(r.millisecond);return Math.abs(t._clockViewModel.multiplier)<1?l("%02d:%02d:%02d.%03d",r.hour,r.minute,r.second,i):l("%02d:%02d:%02d UTC",r.hour,r.minute,r.second)},C.prototype.getShuttleRingTicks=function(){return this._sortedFilteredPositiveTicks.slice(0)},C.prototype.setShuttleRingTicks=function(e){var t,r,i,n={},o=this._sortedFilteredPositiveTicks;for(o.length=0,t=0,r=e.length;r>t;++t)i=e[t],n.hasOwnProperty(i)||(n[i]=!0,o.push(i));o.sort(p);var a=[];for(r=o.length,t=r-1;t>=0;--t)i=o[t],0!==i&&a.push(-i);Array.prototype.push.apply(a,o),this._allShuttleRingTicks=a},n(C.prototype,{slower:{get:function(){return this._slower}},faster:{get:function(){return this._faster}},clockViewModel:{get:function(){return this._clockViewModel}},pauseViewModel:{get:function(){return this._pauseViewModel}},playReverseViewModel:{get:function(){return this._playReverseViewModel}},playForwardViewModel:{get:function(){return this._playForwardViewModel}},playRealtimeViewModel:{get:function(){return this._playRealtimeViewModel}},dateFormatter:{get:function(){return this._dateFormatter},set:function(e){this._dateFormatter=e}},timeFormatter:{get:function(){return this._timeFormatter},set:function(e){this._timeFormatter=e}}}),C._maxShuttleRingAngle=y,C._realtimeShuttleRingAngle=g,C}),r("Widgets/BaseLayerPicker/BaseLayerPickerViewModel",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/EllipsoidTerrainProvider","../../Core/isArray","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(r){r=e(r,e.EMPTY_OBJECT);var i=r.globe,l=e(r.imageryProviderViewModels,[]),u=e(r.terrainProviderViewModels,[]);this._globe=i,this.imageryProviderViewModels=l.slice(0),this.terrainProviderViewModels=u.slice(0),this.dropDownVisible=!1,a.track(this,["imageryProviderViewModels","terrainProviderViewModels","dropDownVisible"]),this.buttonTooltip=void 0,a.defineProperty(this,"buttonTooltip",function(){var e=this.selectedImagery,r=this.selectedTerrain,i=t(e)?e.name:void 0,n=t(r)?r.name:void 0;return t(i)&&t(n)?i+"\n"+n:t(i)?i:n}),this.buttonImageUrl=void 0,a.defineProperty(this,"buttonImageUrl",function(){var e=this.selectedImagery;return t(e)?e.iconUrl:void 0}),this.selectedImagery=void 0;var c=a.observable();this._currentImageryProviders=[],a.defineProperty(this,"selectedImagery",{get:function(){return c()},set:function(e){if(c()===e)return void(this.dropDownVisible=!1);var r,i=this._currentImageryProviders,n=i.length,a=this._globe.imageryLayers;for(r=0;n>r;r++)for(var s=a.length,l=0;s>l;l++){var u=a.get(l);if(u.imageryProvider===i[r]){a.remove(u);break}}if(t(e)){var h=e.creationCommand();if(o(h)){var d=h.length;for(r=d-1;r>=0;r--)a.addImageryProvider(h[r],0);this._currentImageryProviders=h.slice(0)}else this._currentImageryProviders=[h],a.addImageryProvider(h,0)}c(e),this.dropDownVisible=!1}}),this.selectedTerrain=void 0;var h=a.observable();a.defineProperty(this,"selectedTerrain",{get:function(){return h()},set:function(e){if(h()===e)return void(this.dropDownVisible=!1);var r;t(e)&&(r=e.creationCommand()),this._globe.depthTestAgainstTerrain=!(r instanceof n),this._globe.terrainProvider=r,h(e),this.dropDownVisible=!1}});var d=this;this._toggleDropDown=s(function(){d.dropDownVisible=!d.dropDownVisible}),this.selectedImagery=e(r.selectedImageryProviderViewModel,l[0]),this.selectedTerrain=e(r.selectedTerrainProviderViewModel,u[0])};return r(l.prototype,{toggleDropDown:{get:function(){return this._toggleDropDown}},globe:{get:function(){return this._globe}}}),l}),r("Widgets/BaseLayerPicker/BaseLayerPicker",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./BaseLayerPickerViewModel"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(e,t){e=a(e);var r=new s(t),i=document.createElement("button");i.type="button",i.className="cesium-button cesium-toolbar-button",i.setAttribute("data-bind","attr: { title: buttonTooltip },click: toggleDropDown"),e.appendChild(i);var l=document.createElement("img");l.setAttribute("draggable","false"),l.className="cesium-baseLayerPicker-selected",l.setAttribute("data-bind","attr: { src: buttonImageUrl }"),i.appendChild(l);var u=document.createElement("div");u.className="cesium-baseLayerPicker-dropDown",u.setAttribute("data-bind",'css: { "cesium-baseLayerPicker-dropDown-visible" : dropDownVisible }'),e.appendChild(u);var c=document.createElement("div");c.className="cesium-baseLayerPicker-sectionTitle",c.setAttribute("data-bind","visible: imageryProviderViewModels.length > 0"),c.innerHTML="Imagery",u.appendChild(c);var h=document.createElement("div");h.className="cesium-baseLayerPicker-choices",h.setAttribute("data-bind","foreach: imageryProviderViewModels"),u.appendChild(h);var d=document.createElement("div");d.className="cesium-baseLayerPicker-item",d.setAttribute("data-bind",'css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedImagery },attr: { title: tooltip },visible: creationCommand.canExecute,click: function($data) { $parent.selectedImagery = $data; }'),h.appendChild(d);var p=document.createElement("img");p.className="cesium-baseLayerPicker-itemIcon",p.setAttribute("data-bind","attr: { src: iconUrl }"),p.setAttribute("draggable","false"),d.appendChild(p);var m=document.createElement("div");m.className="cesium-baseLayerPicker-itemLabel",m.setAttribute("data-bind","text: name"),d.appendChild(m);var f=document.createElement("div");f.className="cesium-baseLayerPicker-sectionTitle",f.setAttribute("data-bind","visible: terrainProviderViewModels.length > 0"),f.innerHTML="Terrain",u.appendChild(f);var v=document.createElement("div");v.className="cesium-baseLayerPicker-choices",v.setAttribute("data-bind","foreach: terrainProviderViewModels"),u.appendChild(v);var _=document.createElement("div");_.className="cesium-baseLayerPicker-item",_.setAttribute("data-bind",'css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedTerrain },attr: { title: tooltip },visible: creationCommand.canExecute,click: function($data) { $parent.selectedTerrain = $data; }'),v.appendChild(_);var g=document.createElement("img");g.className="cesium-baseLayerPicker-itemIcon",g.setAttribute("data-bind","attr: { src: iconUrl }"),g.setAttribute("draggable","false"),_.appendChild(g);var y=document.createElement("div");y.className="cesium-baseLayerPicker-itemLabel",y.setAttribute("data-bind","text: name"),_.appendChild(y),o.applyBindings(r,i),o.applyBindings(r,u),this._viewModel=r,this._container=e,this._element=i,this._dropPanel=u,this._closeDropDown=function(e){i.contains(e.target)||u.contains(e.target)||(r.dropDownVisible=!1)},n.supportsPointerEvents()?document.addEventListener("pointerdown",this._closeDropDown,!0):(document.addEventListener("mousedown",this._closeDropDown,!0),document.addEventListener("touchstart",this._closeDropDown,!0))};return t(l.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),l.prototype.isDestroyed=function(){return!1},l.prototype.destroy=function(){return n.supportsPointerEvents()?document.removeEventListener("pointerdown",this._closeDropDown,!0):(document.removeEventListener("mousedown",this._closeDropDown,!0),document.removeEventListener("touchstart",this._closeDropDown,!0)),o.cleanNode(this._element),o.cleanNode(this._dropPanel),this._container.removeChild(this._element),this._container.removeChild(this._dropPanel),r(this)},l}),r("Widgets/BaseLayerPicker/ProviderViewModel",["../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n){"use strict";var o=function(t){var r=t.creationFunction;e(r.canExecute)||(r=n(r)),this._creationCommand=r,this.name=t.name,this.tooltip=t.tooltip,this.iconUrl=t.iconUrl,i.track(this,["name","tooltip","iconUrl"])};return t(o.prototype,{creationCommand:{get:function(){return this._creationCommand}}}),o}),r("Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels",["../../Core/buildModuleUrl","../../Scene/ArcGisMapServerImageryProvider","../../Scene/BingMapsImageryProvider","../../Scene/BingMapsStyle","../../Scene/MapboxImageryProvider","../../Scene/OpenStreetMapImageryProvider","../../Scene/TileMapServiceImageryProvider","../BaseLayerPicker/ProviderViewModel"],function(e,t,r,i,n,o,a,s){"use strict";function l(){var l=[];return l.push(new s({name:"Bing Maps Aerial",iconUrl:e("Widgets/Images/ImageryProviders/bingAerial.png"),tooltip:"Bing Maps aerial imagery \nhttp://www.bing.com/maps",creationFunction:function(){return new r({url:"//dev.virtualearth.net",mapStyle:i.AERIAL})}})),l.push(new s({name:"Bing Maps Aerial with Labels",iconUrl:e("Widgets/Images/ImageryProviders/bingAerialLabels.png"),tooltip:"Bing Maps aerial imagery with label overlays \nhttp://www.bing.com/maps",creationFunction:function(){return new r({url:"//dev.virtualearth.net",mapStyle:i.AERIAL_WITH_LABELS})}})),l.push(new s({name:"Bing Maps Roads",iconUrl:e("Widgets/Images/ImageryProviders/bingRoads.png"),tooltip:"Bing Maps standard road maps\nhttp://www.bing.com/maps",creationFunction:function(){return new r({url:"//dev.virtualearth.net",mapStyle:i.ROAD})}})),l.push(new s({name:"Mapbox Satellite",tooltip:"Mapbox satellite imagery https://www.mapbox.com/maps/",iconUrl:e("Widgets/Images/ImageryProviders/mapboxSatellite.png"),creationFunction:function(){return new n({mapId:"mapbox.satellite"})}})),l.push(new s({name:"Mapbox Streets",tooltip:"Mapbox streets imagery https://www.mapbox.com/maps/",iconUrl:e("Widgets/Images/ImageryProviders/mapboxTerrain.png"),creationFunction:function(){return new n({mapId:"mapbox.streets"})}})),l.push(new s({name:"Mapbox Streets Classic",tooltip:"Mapbox streets basic imagery https://www.mapbox.com/maps/",iconUrl:e("Widgets/Images/ImageryProviders/mapboxStreets.png"),creationFunction:function(){return new n({mapId:"mapbox.streets-basic"})}})),l.push(new s({name:"ESRI World Imagery",iconUrl:e("Widgets/Images/ImageryProviders/esriWorldImagery.png"),tooltip:"World Imagery provides one meter or better satellite and aerial imagery in many parts of the world and lower resolution satellite imagery worldwide. The map includes NASA Blue Marble: Next Generation 500m resolution imagery at small scales (above 1:1,000,000), i-cubed 15m eSAT imagery at medium-to-large scales (down to 1:70,000) for the world, and USGS 15m Landsat imagery for Antarctica. The map features 0.3m resolution imagery in the continental United States and 0.6m resolution imagery in parts of Western Europe from DigitalGlobe. In other parts of the world, 1 meter resolution imagery is available from GeoEye IKONOS, i-cubed Nationwide Prime, Getmapping, AeroGRID, IGN Spain, and IGP Portugal. Additionally, imagery at different resolutions has been contributed by the GIS User Community.\nhttp://www.esri.com",creationFunction:function(){return new t({url:"//services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",enablePickFeatures:!1})}})),l.push(new s({name:"ESRI World Street Map",iconUrl:e("Widgets/Images/ImageryProviders/esriWorldStreetMap.png"),tooltip:"This worldwide street map presents highway-level data for the world. Street-level data includes the United States; much of Canada; Japan; most countries in Europe; Australia and New Zealand; India; parts of South America including Argentina, Brazil, Chile, Colombia, and Venezuela; Ghana; and parts of southern Africa including Botswana, Lesotho, Namibia, South Africa, and Swaziland.\nhttp://www.esri.com",creationFunction:function(){return new t({url:"//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",enablePickFeatures:!1})}})),l.push(new s({name:"ESRI National Geographic",iconUrl:e("Widgets/Images/ImageryProviders/esriNationalGeographic.png"),tooltip:"This web map contains the National Geographic World Map service. This map service is designed to be used as a general reference map for informational and educational purposes as well as a basemap by GIS professionals and other users for creating web maps and web mapping applications.\nhttp://www.esri.com",creationFunction:function(){return new t({url:"//services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/",enablePickFeatures:!1})}})),l.push(new s({name:"Open­Street­Map",iconUrl:e("Widgets/Images/ImageryProviders/openStreetMap.png"),tooltip:"OpenStreetMap (OSM) is a collaborative project to create a free editable map of the world.\nhttp://www.openstreetmap.org",creationFunction:function(){return new o({url:"//a.tile.openstreetmap.org/"})}})),l.push(new s({name:"Stamen Watercolor",iconUrl:e("Widgets/Images/ImageryProviders/stamenWatercolor.png"),tooltip:"Reminiscent of hand drawn maps, Stamen watercolor maps apply raster effect area washes and organic edges over a paper texture to add warm pop to any map.\nhttp://maps.stamen.com",creationFunction:function(){return new o({url:"//stamen-tiles.a.ssl.fastly.net/watercolor/",credit:"Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA."})}})),l.push(new s({name:"Stamen Toner",iconUrl:e("Widgets/Images/ImageryProviders/stamenToner.png"),tooltip:"A high contrast black and white map.\nhttp://maps.stamen.com",creationFunction:function(){return new o({url:"//stamen-tiles.a.ssl.fastly.net/toner/",credit:"Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA."})}})),l.push(new s({name:"MapQuest Open­Street­Map",iconUrl:e("Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png"),tooltip:"OpenStreetMap (OSM) is a collaborative project to create a free editable map of the world.\nhttp://www.openstreetmap.org",creationFunction:function(){return new o({url:"//otile1-s.mqcdn.com/tiles/1.0.0/osm/"})}})),l.push(new s({name:"The Black Marble",iconUrl:e("Widgets/Images/ImageryProviders/blackMarble.png"),tooltip:"The lights of cities and villages trace the outlines of civilization in this global view of the Earth at night as seen by NASA/NOAA's Suomi NPP satellite.",creationFunction:function(){return new a({url:"//cesiumjs.org/blackmarble",maximumLevel:8,credit:"Black Marble imagery courtesy NASA Earth Observatory"})}})),l.push(new s({name:"Natural Earth II",iconUrl:e("Widgets/Images/ImageryProviders/naturalEarthII.png"),tooltip:"Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/",creationFunction:function(){return new a({url:e("Assets/Textures/NaturalEarthII")})}})),l}return l}),r("Widgets/BaseLayerPicker/createDefaultTerrainProviderViewModels",["../../Core/buildModuleUrl","../../Core/CesiumTerrainProvider","../../Core/EllipsoidTerrainProvider","../BaseLayerPicker/ProviderViewModel"],function(e,t,r,i){"use strict";function n(){var n=[];return n.push(new i({name:"WGS84 Ellipsoid",iconUrl:e("Widgets/Images/TerrainProviders/Ellipsoid.png"),tooltip:"WGS84 standard ellipsoid, also known as EPSG:4326",creationFunction:function(){return new r}})),n.push(new i({name:"STK World Terrain meshes",iconUrl:e("Widgets/Images/TerrainProviders/STK.png"),tooltip:"High-resolution, mesh-based terrain for the entire globe. Free for use on the Internet. Closed-network options are available.\nhttp://www.agi.com",creationFunction:function(){return new t({url:"//assets.agi.com/stk-terrain/world",requestWaterMask:!0,requestVertexNormals:!0})}})),n}return n}),r("Widgets/CesiumInspector/CesiumInspectorViewModel",["../../Core/Color","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/Rectangle","../../Core/ScreenSpaceEventHandler","../../Core/ScreenSpaceEventType","../../Scene/DebugModelMatrixPrimitive","../../Scene/PerformanceDisplay","../../Scene/TileCoordinatesImageryProvider","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s,l,u,c,h,d){"use strict";function p(e){var r;if(t(e)){r="Command Statistics";var i=e.commandsInFrustums;for(var n in i)if(i.hasOwnProperty(n)){var o,a=parseInt(n,10);if(7===a)o="1, 2 and 3";else{for(var s=[],l=2;l>=0;l--){var u=Math.pow(2,l);a>=u&&(s.push(l+1),a-=u)}o=s.reverse().join(" and ")}r+="<br>    "+i[n]+" in frustum "+o}r+="<br>Total: "+e.totalCommands}return r}function m(e,t,r){var i=Math.min(r,t);return i=Math.max(i,e)}var f=function(e,r){var i=this,n=e.canvas,p=new a(n);this._eventHandler=p,this._scene=e,this._canvas=n,this._primitive=void 0,this._tile=void 0,this._modelMatrixPrimitive=void 0,this._performanceDisplay=void 0,this._performanceContainer=r;var f=this._scene.globe;f.depthTestAgainstTerrain=!0,this.frustums=!1,this.performance=!1,this.shaderCacheText="",this.primitiveBoundingSphere=!1,this.primitiveReferenceFrame=!1,this.filterPrimitive=!1,this.tileBoundingSphere=!1,this.filterTile=!1,this.wireframe=!1,this.globeDepth=!1,this.pickDepth=!1,this.depthFrustum=1,this._numberOfFrustums=1,this.depthFrustumText="1 of 1",this.suspendUpdates=!1,this.tileCoordinates=!1,this.frustumStatisticText="",this.tileText="",this.hasPickedPrimitive=!1,this.hasPickedTile=!1,this.pickPimitiveActive=!1,this.pickTileActive=!1,this.dropDownVisible=!0,this.generalVisible=!0,this.primitivesVisible=!1,this.terrainVisible=!1,this.generalSwitchText="-",this.primitivesSwitchText="+",this.terrainSwitchText="+",h.track(this,["filterTile","suspendUpdates","dropDownVisible","shaderCacheText","frustums","frustumStatisticText","pickTileActive","pickPrimitiveActive","hasPickedPrimitive","hasPickedTile","tileText","generalVisible","generalSwitchText","primitivesVisible","primitivesSwitchText","terrainVisible","terrainSwitchText","depthFrustumText"]),this._toggleDropDown=d(function(){i.dropDownVisible=!i.dropDownVisible}),this._toggleGeneral=d(function(){i.generalVisible=!i.generalVisible,i.generalSwitchText=i.generalVisible?"-":"+"}),this._togglePrimitives=d(function(){i.primitivesVisible=!i.primitivesVisible,i.primitivesSwitchText=i.primitivesVisible?"-":"+"}),this._toggleTerrain=d(function(){i.terrainVisible=!i.terrainVisible,i.terrainSwitchText=i.terrainVisible?"-":"+"}),this._showFrustums=d(function(){return i.frustums?i._scene.debugShowFrustums=!0:i._scene.debugShowFrustums=!1,!0}),this._showPerformance=d(function(){return i.performance?i._performanceDisplay=new u({container:i._performanceContainer}):i._performanceContainer.innerHTML="",!0}),this._showPrimitiveBoundingSphere=d(function(){return i._primitive.debugShowBoundingVolume=i.primitiveBoundingSphere,!0}),this._showPrimitiveReferenceFrame=d(function(){if(i.primitiveReferenceFrame){var e=i._primitive.modelMatrix;i._modelMatrixPrimitive=new l({modelMatrix:e}),i._scene.primitives.add(i._modelMatrixPrimitive)}else t(i._modelMatrixPrimitive)&&(i._scene.primitives.remove(i._modelMatrixPrimitive),i._modelMatrixPrimitive=void 0);return!0}),this._doFilterPrimitive=d(function(){return i.filterPrimitive?i._scene.debugCommandFilter=function(e){return t(i._modelMatrixPrimitive)&&e.owner===i._modelMatrixPrimitive._primitive?!0:t(i._primitive)?e.owner===i._primitive||e.owner===i._primitive._billboardCollection||e.owner.primitive===i._primitive:!1}:i._scene.debugCommandFilter=void 0,!0}),this._showWireframe=d(function(){return f._surface.tileProvider._debug.wireframe=i.wireframe,!0}),this._showGlobeDepth=d(function(){return i._scene.debugShowGlobeDepth=i.globeDepth,!0}),this._showPickDepth=d(function(){return i._scene.debugShowPickDepth=i.pickDepth,!0}),this._incrementDepthFrustum=d(function(){var e=i.depthFrustum+1;return i.depthFrustum=m(1,i._numberOfFrustums,e),i.scene.debugShowDepthFrustum=i.depthFrustum,!0}),this._decrementDepthFrustum=d(function(){var e=i.depthFrustum-1;return i.depthFrustum=m(1,i._numberOfFrustums,e),i.scene.debugShowDepthFrustum=i.depthFrustum,!0}),this._doSuspendUpdates=d(function(){return f._surface._debug.suspendLodUpdate=i.suspendUpdates,i.suspendUpdates||(i.filterTile=!1),!0});var v;this._showTileCoordinates=d(function(){return i.tileCoordinates&&!t(v)?v=e.imageryLayers.addImageryProvider(new c({tilingScheme:e.terrainProvider.tilingScheme})):!i.tileCoordinates&&t(v)&&(e.imageryLayers.remove(v),v=void 0),!0}),this._showTileBoundingSphere=d(function(){return i.tileBoundingSphere?f._surface.tileProvider._debug.boundingSphereTile=i._tile:f._surface.tileProvider._debug.boundingSphereTile=void 0,!0}),this._doFilterTile=d(function(){return i.filterTile?(i.suspendUpdates=!0,i.doSuspendUpdates(),f._surface._tilesToRender=[],t(i._tile)&&f._surface._tilesToRender.push(i._tile)):(i.suspendUpdates=!1,i.doSuspendUpdates()),!0});var _=function(e){p.removeInputAction(s.LEFT_CLICK),i.pickPrimitiveActive=!1;var r=i._scene.pick({x:e.position.x,y:e.position.y});t(r)&&(i.primitive=t(r.collection)?r.collection:r.primitive)};this._pickPrimitive=d(function(){i.pickPrimitiveActive=!i.pickPrimitiveActive,i.pickPrimitiveActive?p.setInputAction(_,s.LEFT_CLICK):p.removeInputAction(s.LEFT_CLICK)});var g=function(e){var r,n=f.ellipsoid,a=i._scene.camera.pickEllipsoid({x:e.position.x,y:e.position.y},n);if(t(a))for(var l=n.cartesianToCartographic(a),u=f._surface.tileProvider._tilesToRenderByTextureCount,c=0;!r&&c<u.length;++c){var h=u[c];if(t(h))for(var d=0;!r&&d<h.length;++d){var m=h[d];o.contains(m.rectangle,l)&&(r=m)}}i.tile=r,p.removeInputAction(s.LEFT_CLICK),i.pickTileActive=!1};this._pickTile=d(function(){i.pickTileActive=!i.pickTileActive,i.pickTileActive?p.setInputAction(g,s.LEFT_CLICK):p.removeInputAction(s.LEFT_CLICK)})};return r(f.prototype,{scene:{get:function(){return this._scene}},performanceContainer:{get:function(){return this._performanceContainer}},toggleDropDown:{get:function(){return this._toggleDropDown}},showFrustums:{get:function(){return this._showFrustums}},showPerformance:{get:function(){return this._showPerformance}},showPrimitiveBoundingSphere:{get:function(){return this._showPrimitiveBoundingSphere}},showPrimitiveReferenceFrame:{get:function(){return this._showPrimitiveReferenceFrame}},doFilterPrimitive:{get:function(){return this._doFilterPrimitive}},showWireframe:{get:function(){return this._showWireframe}},showGlobeDepth:{get:function(){return this._showGlobeDepth}},showPickDepth:{get:function(){return this._showPickDepth}},incrementDepthFrustum:{get:function(){return this._incrementDepthFrustum}},decrementDepthFrustum:{get:function(){return this._decrementDepthFrustum}},doSuspendUpdates:{get:function(){return this._doSuspendUpdates}},showTileCoordinates:{get:function(){return this._showTileCoordinates}},showTileBoundingSphere:{get:function(){return this._showTileBoundingSphere}},doFilterTile:{get:function(){return this._doFilterTile}},toggleGeneral:{get:function(){return this._toggleGeneral}},togglePrimitives:{get:function(){return this._togglePrimitives}},toggleTerrain:{get:function(){return this._toggleTerrain}},pickPrimitive:{get:function(){return this._pickPrimitive}},pickTile:{get:function(){return this._pickTile}},selectParent:{get:function(){var e=this;return d(function(){e.tile=e.tile.parent})}},selectNW:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[0]})}},selectNE:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[1]})}},selectSW:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[2]})}},selectSE:{get:function(){var e=this;return d(function(){e.tile=e.tile.children[3]})}},primitive:{set:function(e){var r=this._primitive;e!==r&&(this.hasPickedPrimitive=!0,t(r)&&(r.debugShowBoundingVolume=!1),this._scene.debugCommandFilter=void 0,t(this._modelMatrixPrimitive)&&(this._scene.primitives.remove(this._modelMatrixPrimitive),this._modelMatrixPrimitive=void 0),this._primitive=e,e.show=!1,setTimeout(function(){e.show=!0},50),this.showPrimitiveBoundingSphere(),this.showPrimitiveReferenceFrame(),this.doFilterPrimitive())},get:function(){return this._primitive}},tile:{set:function(e){if(t(e)){this.hasPickedTile=!0;var r=this._tile;e!==r&&(this.tileText="L: "+e.level+" X: "+e.x+" Y: "+e.y,this.tileText+="<br>SW corner: "+e.rectangle.west+", "+e.rectangle.south,this.tileText+="<br>NE corner: "+e.rectangle.east+", "+e.rectangle.north,this.tileText+="<br>Min: "+e.data.minimumHeight+" Max: "+e.data.maximumHeight),this._tile=e,this.showTileBoundingSphere(),this.doFilterTile()}else this.hasPickedTile=!1,this._tile=void 0},get:function(){return this._tile}},update:{get:function(){var e=this;return function(){e.frustums&&(e.frustumStatisticText=p(e._scene.debugFrustumStatistics));var t=e._scene.numberOfFrustums;e._numberOfFrustums=t;var r=m(1,t,e.depthFrustum);e.depthFrustum=r,e.scene.debugShowDepthFrustum=r,e.depthFrustumText=r+" of "+t,e.performance&&e._performanceDisplay.update(),e.primitiveReferenceFrame&&(e._modelMatrixPrimitive.modelMatrix=e._primitive.modelMatrix),e.shaderCacheText="Cached shaders: "+e._scene.context.shaderCache.numberOfShaders}}}}),f.prototype.isDestroyed=function(){return!1},f.prototype.destroy=function(){return this._eventHandler.destroy(),i(this)},f}),r("Widgets/CesiumInspector/CesiumInspector",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./CesiumInspectorViewModel"],function(e,t,r,i,n,o,a){ -"use strict";var s=function(t,r){if(!e(t))throw new i("container is required.");if(!e(r))throw new i("scene is required.");t=o(t);var s=document.createElement("div"),l=new a(r,s);this._viewModel=l,this._container=t;var u=document.createElement("div");this._element=u;var c=document.createElement("div");c.textContent="Cesium Inspector",c.className="cesium-cesiumInspector-button",c.setAttribute("data-bind","click: toggleDropDown"),u.appendChild(c),u.className="cesium-cesiumInspector",u.setAttribute("data-bind",'css: { "cesium-cesiumInspector-visible" : dropDownVisible, "cesium-cesiumInspector-hidden" : !dropDownVisible }'),t.appendChild(this._element);var h=document.createElement("div");this._panel=h,h.className="cesium-cesiumInspector-dropDown",u.appendChild(h);var d=document.createElement("div");d.className="cesium-cesiumInspector-sectionHeader";var p=document.createElement("span");p.className="cesium-cesiumInspector-toggleSwitch",p.setAttribute("data-bind","click: toggleGeneral, text: generalSwitchText"),d.appendChild(p),d.appendChild(document.createTextNode("General")),h.appendChild(d);var m=document.createElement("div");m.className="cesium-cesiumInspector-section",m.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : generalVisible, "cesium-cesiumInspector-hide" : !generalVisible}'),h.appendChild(m);var f=document.createElement("div");m.appendChild(f);var v=document.createElement("div");v.className="cesium-cesiumInspector-frustumStats",v.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : frustums, "cesium-cesiumInspector-hide" : !frustums}, html: frustumStatisticText');var _=document.createElement("input");_.type="checkbox",_.setAttribute("data-bind","checked: frustums, click: showFrustums"),f.appendChild(_),f.appendChild(document.createTextNode("Show Frustums")),f.appendChild(v);var g=document.createElement("div");m.appendChild(g);var y=document.createElement("input");y.type="checkbox",y.setAttribute("data-bind","checked: performance, click: showPerformance"),g.appendChild(y),g.appendChild(document.createTextNode("Performance Display")),s.className="cesium-cesiumInspector-performanceDisplay",m.appendChild(s);var C=document.createElement("div");C.className="cesium-cesiumInspector-shaderCache",C.setAttribute("data-bind","html: shaderCacheText"),m.appendChild(C);var E=document.createElement("div");m.appendChild(E);var S=document.createElement("input");S.type="checkbox",S.setAttribute("data-bind","checked: globeDepth, click: showGlobeDepth"),E.appendChild(S),E.appendChild(document.createTextNode("Show globe depth"));var w=document.createElement("div");E.appendChild(w);var T=document.createElement("div");m.appendChild(T);var b=document.createElement("input");b.type="checkbox",b.setAttribute("data-bind","checked: pickDepth, click: showPickDepth"),T.appendChild(b),T.appendChild(document.createTextNode("Show pick depth"));var x=document.createElement("div");m.appendChild(x);var P=document.createElement("span");P.setAttribute("data-bind",'html: "     Frustum:"'),x.appendChild(P);var A=document.createElement("span");A.setAttribute("data-bind","text: depthFrustumText"),x.appendChild(A);var I=document.createElement("input");I.type="button",I.value="-",I.className="cesium-cesiumInspector-pickButton",I.setAttribute("data-bind","click: decrementDepthFrustum"),x.appendChild(I);var M=document.createElement("input");M.type="button",M.value="+",M.className="cesium-cesiumInspector-pickButton",M.setAttribute("data-bind","click: incrementDepthFrustum"),x.appendChild(M);var D=document.createElement("div");D.className="cesium-cesiumInspector-sectionHeader",p=document.createElement("span"),p.className="cesium-cesiumInspector-toggleSwitch",p.setAttribute("data-bind","click: togglePrimitives, text: primitivesSwitchText"),D.appendChild(p),D.appendChild(document.createTextNode("Primitives")),h.appendChild(D);var R=document.createElement("div");R.className="cesium-cesiumInspector-section",R.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : primitivesVisible, "cesium-cesiumInspector-hide" : !primitivesVisible}'),h.appendChild(R);var O=document.createElement("div");O.className="cesium-cesiumInspector-pickSection",R.appendChild(O);var N=document.createElement("input");N.type="button",N.value="Pick a primitive",N.className="cesium-cesiumInspector-pickButton",N.setAttribute("data-bind",'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickPrimitiveActive}, click: pickPrimitive');var L=document.createElement("div");L.className="cesium-cesiumInspector-center",L.appendChild(N),O.appendChild(L);var F=document.createElement("div");O.appendChild(F);var B=document.createElement("input");B.type="checkbox",B.setAttribute("data-bind","checked: primitiveBoundingSphere, click: showPrimitiveBoundingSphere, enable: hasPickedPrimitive"),F.appendChild(B),F.appendChild(document.createTextNode("Show bounding sphere"));var V=document.createElement("div");O.appendChild(V);var z=document.createElement("input");z.type="checkbox",z.setAttribute("data-bind","checked: primitiveReferenceFrame, click: showPrimitiveReferenceFrame, enable: hasPickedPrimitive"),V.appendChild(z),V.appendChild(document.createTextNode("Show reference frame"));var k=document.createElement("div");this._primitiveOnly=k,O.appendChild(k);var U=document.createElement("input");U.type="checkbox",U.setAttribute("data-bind","checked: filterPrimitive, click: doFilterPrimitive, enable: hasPickedPrimitive"),k.appendChild(U),k.appendChild(document.createTextNode("Show only selected"));var G=document.createElement("div");G.className="cesium-cesiumInspector-sectionHeader",p=document.createElement("span"),p.className="cesium-cesiumInspector-toggleSwitch",p.setAttribute("data-bind","click: toggleTerrain, text: terrainSwitchText"),G.appendChild(p),G.appendChild(document.createTextNode("Terrain")),h.appendChild(G);var W=document.createElement("div");W.className="cesium-cesiumInspector-section",W.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : terrainVisible, "cesium-cesiumInspector-hide" : !terrainVisible}'),h.appendChild(W);var H=document.createElement("div");H.className="cesium-cesiumInspector-pickSection",W.appendChild(H);var q=document.createElement("input");q.type="button",q.value="Pick a tile",q.className="cesium-cesiumInspector-pickButton",q.setAttribute("data-bind",'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickTileActive}, click: pickTile'),L=document.createElement("div"),L.appendChild(q),L.className="cesium-cesiumInspector-center",H.appendChild(L);var j=document.createElement("div");H.appendChild(j);var Y=document.createElement("input");Y.type="button",Y.value="Parent",Y.className="cesium-cesiumInspector-pickButton",Y.setAttribute("data-bind","click: selectParent");var X=document.createElement("input");X.type="button",X.value="NW",X.className="cesium-cesiumInspector-pickButton",X.setAttribute("data-bind","click: selectNW");var Z=document.createElement("input");Z.type="button",Z.value="NE",Z.className="cesium-cesiumInspector-pickButton",Z.setAttribute("data-bind","click: selectNE");var K=document.createElement("input");K.type="button",K.value="SW",K.className="cesium-cesiumInspector-pickButton",K.setAttribute("data-bind","click: selectSW");var J=document.createElement("input");J.type="button",J.value="SE",J.className="cesium-cesiumInspector-pickButton",J.setAttribute("data-bind","click: selectSE");var Q=document.createElement("div");Q.className="cesium-cesiumInspector-tileText",j.className="cesium-cesiumInspector-frustumStats",j.appendChild(Q),j.setAttribute("data-bind",'css: {"cesium-cesiumInspector-show" : hasPickedTile, "cesium-cesiumInspector-hide" : !hasPickedTile}'),Q.setAttribute("data-bind","html: tileText");var $=document.createElement("div");$.className="cesium-cesiumInspector-relativeText",$.textContent="Select relative:",j.appendChild($);var ee=document.createElement("table"),te=document.createElement("tr"),re=document.createElement("tr"),ie=document.createElement("td");ie.appendChild(Y);var ne=document.createElement("td");ne.appendChild(X);var oe=document.createElement("td");oe.appendChild(Z),te.appendChild(ie),te.appendChild(ne),te.appendChild(oe);var ae=document.createElement("td"),se=document.createElement("td");se.appendChild(K);var le=document.createElement("td");le.appendChild(J),re.appendChild(ae),re.appendChild(se),re.appendChild(le),ee.appendChild(te),ee.appendChild(re),j.appendChild(ee);var ue=document.createElement("div");H.appendChild(ue);var ce=document.createElement("input");ce.type="checkbox",ce.setAttribute("data-bind","checked: tileBoundingSphere, enable: hasPickedTile, click: showTileBoundingSphere"),ue.appendChild(ce),ue.appendChild(document.createTextNode("Show bounding volume"));var he=document.createElement("div");H.appendChild(he);var de=document.createElement("input");de.type="checkbox",de.setAttribute("data-bind","checked: filterTile, enable: hasPickedTile, click: doFilterTile"),he.appendChild(de),he.appendChild(document.createTextNode("Show only selected"));var pe=document.createElement("div");W.appendChild(pe);var me=document.createElement("input");me.type="checkbox",me.setAttribute("data-bind","checked: wireframe, click: showWireframe"),pe.appendChild(me),pe.appendChild(document.createTextNode("Wireframe"));var fe=document.createElement("div");W.appendChild(fe);var ve=document.createElement("input");ve.type="checkbox",ve.setAttribute("data-bind","checked: suspendUpdates, click: doSuspendUpdates"),fe.appendChild(ve),fe.appendChild(document.createTextNode("Suspend LOD update"));var _e=document.createElement("div");W.appendChild(_e);var ge=document.createElement("input");ge.type="checkbox",ge.setAttribute("data-bind","checked: tileCoordinates, click: showTileCoordinates"),_e.appendChild(ge),_e.appendChild(document.createTextNode("Show tile coordinates")),n.applyBindings(l,this._element)};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return n.cleanNode(this._element),this._container.removeChild(this._element),this.viewModel.destroy(),r(this)},s}),r("Widgets/CesiumWidget/CesiumWidget",["../../Core/buildModuleUrl","../../Core/Cartesian3","../../Core/Clock","../../Core/Credit","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/Ellipsoid","../../Core/formatError","../../Core/requestAnimationFrame","../../Core/ScreenSpaceEventHandler","../../Scene/BingMapsImageryProvider","../../Scene/Globe","../../Scene/Moon","../../Scene/Scene","../../Scene/SceneMode","../../Scene/SkyAtmosphere","../../Scene/SkyBox","../../Scene/Sun","../getElement"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E){"use strict";function S(t){return e("Assets/Textures/SkyBox/tycho2t3_80_"+t+".jpg")}function w(e){function t(i){if(!e.isDestroyed())if(e._useDefaultRenderLoop)try{var n=e._targetFrameRate;if(o(n)){var a=1e3/n,s=i-r;s>a&&(e.resize(),e.render(),r=i-s%a),h(t)}else e.resize(),e.render(),h(t)}catch(l){if(e._useDefaultRenderLoop=!1,e._renderLoopRunning=!1,e._showRenderLoopErrors){var u="An error occurred while rendering. Rendering has stopped.";e.showErrorPanel(u,void 0,l)}}else e._renderLoopRunning=!1}e._renderLoopRunning=!0;var r=0;h(t)}function T(e){var t=e._canvas,r=t.clientWidth,i=t.clientHeight,o=n(window.devicePixelRatio,1)*e._resolutionScale;e._canvasWidth=r,e._canvasHeight=i,r*=o,i*=o,t.width=r,t.height=i,e._canRender=0!==r&&0!==i}function b(e){var t=e._canvas,r=t.width,i=t.height;if(0!==r&&0!==i){var n=e._scene.camera.frustum;o(n.aspectRatio)?n.aspectRatio=r/i:(n.top=n.right*(i/r),n.bottom=-n.top)}}var x="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHYAAAAaCAYAAABikagwAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB9wGGRQyF371QVsAABOHSURBVGje7Vp5cFTHmf91v2Nm3owGnYMuEEJCOBiEjDlsDMYQjGMOOwmXcWxiLywpJ9iuTXZd612corJssFOxi8LerXizxEGUvWsivNxxHHCQ8WYBYSFzmUMCCXQjaUajOd/V+4f6Kc14kI/KZv/xq+p6M/PmO15/9/c1wa0vwpcMQAHgBuAFoPG7mz8jAGwASQBxADFhJQGYACwAjK+vrr/AJQ8jVMqfuwH4AGQByAaQnTNqXGHWqHGFbq8/g1BJsgw9GQ12Bds/qWsxEvEeAEEAfQDCAKKCgPGVcP//BOsIVQHgAZAJIACgsHTqvDvK7150T2bR2DFaZm6W4slwUypR20yaiUg4OtDbcaP36rlPPt6/7f2B3q5mAB0AeriAE18J9y93kVu4X4W73BwAhQBK5v/gZ98ZVXXvDG92IJMx569MQDEoK0tPmOHu1s4L7799sH7vtvcAXAPQCaCfu2qLu+7h+Eh3sS8Bcyt48iVgPos2+4J7jS+BIx2etDBSynfH/Xq46y0CUL70n3/zXMmUuXepWoZHFCQhFIQARCBFJYV6/Nn+QHnVBH9Ovq/51JFWADpfJhcqEzyDcx9ukTTr/xr2VnDpng0nuHR0h1u3wvWF6EspgBIAFYAfQAGAsuU/rfm7kePvvJ0QiTj6QSgBISS9ujEGSikkxaXklIwfK8uK2Xru2HVurWKspZyezGmmWwp/LqVsupPQub4grPQ5YIejKQvPJAGflLLJSBGmxPEqKXhU4XdJEBq7BR5Z+L+DKx3MTTHWEaybx9WCud/btCJQMeX2Qevk+NPoks0YPArF/RUj0NyXxOmO2CAy1a1OmL9yUVfTmatXTx52EildYFQVNlgRmBR1xQJgCBbPBAVUhcw8lTObLz0FVk4RIEmJJyJNZzFBiCTFBRL+f50rriFUATRFiZSU/XYEAw6X5LlIUghZqXvl5p8pfycRZsgjymlKGw1Adm7JbRUVs785nwGghP5pp9mfFMOxWstmuC3gwdcrRqA/buJUWwyKRMAYgydrZNZt9337623njn+ixyN9nAmdM5nBvYOPfxc3mnEmTQ4T5VZv8hfz8aUKnocJd5tvVhxAhOMADzNefleFjRUFa/D/xzi8LQhIEpTG4VXnNBzlZYISufk7juCfqaAoLkHYcZ6HBAEM8O+ObJz3HcFDpJfDJwWYfiHMMTklviocKHv6I3+zRFLdKhEEatmALBFIBIibNhQ6KFyJEjT2JHDoUj/a+nVIVIBhBGOnzptWXzhmTFfT2TZBOH4AgSeeeGJqRUVFqdfr9btcLnVQXwapmqZpJZPJRCgUCh47duzie++9dwWAXl5enrlp06bF0WhUM01TYYwRrmg2vzNKqS3Lsunz+Yy6urpTP//5z09blkVLSkryVq9ePT03NzegqqqbUnqTGyOEMNM0k319fX2///3vz9bW1l4DYD700EPFy5Ytm65pmvbBBx9c2rp166Wnnnqq7MEHH5zAGIu8/vrr+w8ePPgJVwrRO2gAcg8cOLA2mUx62tvbB9avX39s+fLlo++///5JXNiwbXugpqam9tChQ2cEj6NzuQwlsi+//PKSzMzMQtu2qcfjMZqbm09v2LDht4J3sQEQOU2Jo8mKKzt7VEU5lSgFBi3PZkBZrgv3lGbCo1Jc7I7iSGN40JcQgoGkhXdO94ESQJEoGI+1k/M9mDKqQHEv++akl186e45rNAAE3njjjccWLFhwfyAQyJEkiabGbcc7JJNJva2trX3Lli3vvPbaa+eKi4uLV6xY8d10cf5TcZ8x5OXl5b366qs9lFLtrbfeWldVVXW7pmkuxhjS0SSEIJlMGitXrrz2/PPPv1lTU3NtypQp0x955JG/kmVZdrlcR7du3WrOnTt33pIlS+YDwNGjR68ePHiwjVtukm+wI9ichQsXPgUAHR0d3evXr78xc+bMu9asWbOQUjpENz8/v/jQoUP/IiiH40UzAeQvW7Zs1rp16/7a5/NpDr/19fWlGzZsOM4tNsphkc5iPaXTvl6uuDUvY4MZLwNQ4Ffw+LR8+KQQTCuJSQUFcMsEe88FoSkSKCFwyWSISQbg9pEefHdGAJHIdUydVjFecL3K448/Pm3hwoUPBAKBHFGIlmU5pRCRpMGEze12q2PHjh2zatWqeTt37gwODAxkOQIJhUJ6Y2Njn6IojFJqE0KYsGyPx0POnTvXnUgkfGvXrr1j5syZU7iFsKampv5YLBZ34GzbJgAwatSo7MzMTE95eXnZT37yk0dramr+PRQKZSQSCdPn88nBYNADID8UCmkAYBiGGQ6Hna6cksbdZliWZUuSRKPRKAAUBINBfywWM30+n+yEtenTp9+5YsWKGTt37oxwz+a44RwARc8+++xSr9eriQrY398v8311CUncTTHN0Q7Vl1OQJymq4iBwyxQPT8qDVwri1d1/i8ttp/AP39mOBeMn41pQx9mOGFSZ3qT52ZqMR6aMRGvXKfzbgX9Ea3PnSLEdOWXKlK/5/X4/AFy8ePHG6tWr90QikS5VVaOEEIsxRhljngcffLBi8+bNjxBCUFJSMrKkpMRvGIbboXP27Nn+2bNn/3cgEIgSQmKEEAOARQixKKVxRVEioVAoYtu2dMcdd4x24Hbv3t3+ox/96ONoNBqklMa4ppNkMinNnz8///nnn6/y+Xw0mUxaANy6rrsdl28YhguAX9d1F98jwn9TUjJkJ5N1DWV0ti0ByDAMw+PsbzQatX0+Hy0oKMhcvnz5nP3791+IxWJRIUaPfO655+ZVVlaOA4BoNGprmkZ5uJJThZouKyYAqOrWVEKoE7cwszQDlQUK3jr8S5y++iEIIXh55/fwylOH8e3KHHSEdfQnLFBuRbJEsLQyF27Sh3eO/iuudV+EaSuqkJF6MjMzs9xutwIAv/rVr06eOHHiEwCtPBHQOaPaxYsXLxcXF8cKCwtzOzo6+ltbW4OFhYU+h2nDMAgAqbu7W8xkLSEBcsos1bbtocZIIBBQs7Ky5Pb2dkvXdV1wfaipqemsqak5yF1bFABljNEU4Sj87nia1LKHCJWGLLh6AkDhiksAoLq6um/VqlWZWVlZ8gMPPHDHwoULK2tqasJcYJ7y8vKyb33rW/f4/X43YwybNm26vnnz5pIUb0tvVe44maSVjEfizDJtmwFlOS4srczGiQvv4ncnd4ASAkIo+mN92LLrB/j7Vb/GQxOz8Z/1PTDsQXc6p3QEqopU7Dr6S5y8fAiKpCKhs6SQSUqyLKsO4d7e3j4AvbxD1csFQQF4EolEaP369TVCFjuiqKiogG8w5s6dm8sY++ZwcfbZZ5/dvHXr1isnT55scVz+rFmz8urr6xc4Ls22bZZIJExd181oNGr09PREDx06dPmFF144Ho/HTVGIjiE4guECoyl1LYTPcppGEAghDAAikUjixRdfbHnppZfKfD6fa82aNfMOHz7cHgwGbwBwr1ix4u677rqrgsfU4I4dO66lCPZTXSkqpOaMa60e7mjuosw0RmYoWHf3SLT3NOKt91+CbsZBeOlDCcX5luP4rw9fw4wSH+4p9cMlU3xtpAfLJmej/vIR7PnjLyDRwXeKhoxubokWAOYkDXxTLE5brB11oTZMCrWoNQgymJwZhsHC4bAZjUaNaDRqxGIx3VnxeDzJky8TQGLHjh3n9u3bd6ytrS3U2dkZ6e3tjfX398cHBgYS8XjcIIQQr9frKioq8ldWVhb88Ic/vHfbtm3zAXhs25aHUx7uEt1COeXEXM3JfAWLvWnSxRhLbNu2rampqSlMCME3vvGNyXPmzKkCUFZeXn776tWr72WMwbZtvPDCCx+5XK6wo6BcOdhwQ4Chuu/KR39onDGS9T80u9ivkgiqD/0UbT2NcKvelMaEhXfrqlGaPwEPT5qH0lwvqopcaOtpxPb3/gmGmYBEFRBC0HUlfp67tQQALxMKYsaYU+tlcSadNN8NIOO+++4bnZ2d7Q+Hw+zIkSNJxtiQ9TQ1NUW3bNnSmJWVlZBlWaeUWs5SVTUxYsSIRF1dXScAwzTN2MMPP7w3Pz//ZFVVVUFubq7L6/VKmqZRl8ulKIriVlVVmz59ev6cOXMCLpeLLliwYDyAOpGm08SglA659mQy6eHTrwiPtRYXbi6vP2/yjI61AoDL5Ur09vZ2bt++/ezGjRvvppSSjRs3Lti9e/fvnnzyyfHjx48fyRjDwYMHL9TW1jYWFhZ6xfIs3UhUTlPQRwGE9Gv/c/ba9YGi2rPv0FONf/iUUB3Lj8SDqD60GYtmdGBcYSVOnL+K39b9Gp19zVDkwZzBSpLY9Qv9Z3lKHgOgmaYZd9zg1KlTS994441L3G3lcD6oo/1btmxZFwgEctrb27vWrFlzwLIs2cmKW1pa4q+//vp1AbchdIKiPGZHAJDFixcHpk+ffnsoFNLefvvt3ra2Nl0YSDhdt4zy8vLwsWPHsl0ul6ooigSACuEZXKBJwzAMxhhUVZW8Xm8uH5hQ3mCwOf95VVVVYx03yQVhUEpNQbBxADfefPPN6NKlS8dUVlYWVlZW5r344osz1q1bV8IYQzAYjFVXV5+IxWIdkiTlpfDCUgcC6Sw2CqBvw4ZN+7/9d+Wzo1avT5HU9N1tMpj4dfU14z/efxletx9xPYpIPAhVccO2bVBKcf189I/h3mSLkBi5b9y40RWLxZJer9f12GOPTa6oqMjq6enpJYQYlFLGyx21tLQ0MGnSpDGEECQSCZMQIjuNCF6aqI8++mheVlZWJrdYkzcoLEVREj6fL1FfX39x165dzfPnzy/7/ve/v1LXdWvlypVde/bsuRKLxQyn1LEsS2aMeebNm1fs8/lkxhgsy7IAJBRF0Yc2TZZ1AANNTU0djoJt2rRpzqxZs/K6urq6JUnSCSHMMAxZ07SsxYsXV1JKCWMMAwMDMQBhVVWTjtU6gr1y5Yq1d+/ej8aNG5eraZr6zDPPjPV4PBJjDLW1ted27dr1MYCYqqpDcpMkyRIaEyydxToxNgagr7e3t+XEe0rNxPkjnvhTznNr4Sb0KBL6YO9BovJQnRXptTqaPgr9wTLsDgAhTkOurq4+unz58vs1TRvl9/vVuXPnljHGxgqxw2GcEjLYJLlw4cKV06dPd06bNo04+MePH+/ftm3bNNG1iW5KVVVl//79ew4cONC8d+/ey88884ysKIp85513jpo8eXJh2pHX4EUIITh58uRFAN1utzvHcb0ejycGoKuurk5vbW29u7i4ODB69OisJ5988i4xxDhsKIoiEUJgmqZ94MCBOgBdmqaVODxrmhbhiaP+4x//+N2lS5dOmjBhwhiPxyMBQFdXV191dfX7tm23AdBdLtdQzFYUxWmb3iRcmqbh7vQfOz9+v/PdjvP6kcHuE288MJZWuM4Smw1mgkQvHw/v6Wga+BjADY53AEDfmTNnLq9du/Znp06datB13RA3ROwGmaZphcPhgX379v326aefftO27Tafz9fJGGOmadqMMSbLMpEkiaZbjDFommYQQsK1tbWNr7zyymvhcLifEIJbwRBCmGVZ1vHjxz9atGjRLwA0Z2dndzpdHb/fHwTQcuLEiYann3761fPnz3+i67pBCCGUUkoIofwjpZQS27ZZd3f3ja1bt1Zv3LhxL4CrmZmZPYQQkxCCjIyMEIB2AG0Amrdv3/6beDweNwzD1nXdPHXq1Indu3cf48+7MjIyupw98ng8EW4wCWH4kHbQLgsnJ4oAlN332Ji1hbeps6lEaLohQLrhQCJi9zcei77TcLh9H4CrALp4rLN5LBvBE4scAP6JEyfmBQIBL6VUopSCMcYGBgYSly5dCvX19YW5QkQAmD6fz3PvvfeWxmIxr2EYHqFXPBRrKKWWJEmG1+uNtbW1dTU0NNzgz7wA/OXl5bkFBQV+XsYQwVpZMpk0jh8/3snpRQCYo0aN8k6YMCHX5XLRa9euBRsaGnr4Jnp458c7ceLEbK/X6xL5MQzDbGhoCNq2HeO4YgBYWVmZv6KiIkdVVbS0tHQ3NDR0CsORrDlz5oyllHoYY3p9ff31cDjczeGhaVrGkiVLSg3DkLu7u/s+/PDDFn4UKeJYLhnmAJvGs9QCAKOnLMhfNHqSNl/LlHOpTORbWa4et2ORXqv1wgf9NVfO9B7nTYcuPvlICq02t9CJ8ggjOJomodOF0ZQtHNvxCC08pBnbmcIhO53jdA7mpXaKUkOSWGoxYaaKlIa7IozT0uET+XDGehDGhhBGb6bTmBHezeb8OyNPCPQk/ptzeHConCSfcZDNI1hWQXaBVl5254hZmSPVce4MKUdxEQ+VJMnUbcNIWJFoyOzoa02eOX2k+yg/79TFNWkgZchOUobe4vA63WzUEmpYsa+dCoM0Izgz5aQkTUOPpGvUpKFJBaUR8Q03cLdT8NkppyEgPGOCYcnCiNASsn2SwrstDA2Gxnbkc5xSdHGrcmaBWYoqZ+YUe4pcXuqXJCobupWIhaze3vZohzAfdOaKN2mSwPxwR0ZSZ6uptZoIN9yxFCYIiqV5v3THStgwNNPhvtXxFgzDP9K8q52Cj6ZRNnaLffoUDfI5zhVLgrvxCN0Ux5URYXYYF84Wf2qqf4uDV591ZuiLHir7c8F+mZOU5M+Iazg8n3mYjnxORkV3I6dxg6KrMQW3Yaexlq+uv8D1v2IL+t4z3B/NAAAAAElFTkSuQmCC",P=function(e,a){e=E(e),a=n(a,{});var s=document.createElement("div");s.className="cesium-widget",e.appendChild(s);var l=document.createElement("canvas");l.oncontextmenu=function(){return!1},l.onselectstart=function(){return!1},s.appendChild(l);var c=document.createElement("div");c.className="cesium-widget-credits";var h=o(a.creditContainer)?E(a.creditContainer):s;h.appendChild(c);var w=n(a.showRenderLoopErrors,!0);this._element=s,this._container=e,this._canvas=l,this._canvasWidth=0,this._canvasHeight=0,this._creditContainer=c,this._canRender=!1,this._renderLoopRunning=!1,this._showRenderLoopErrors=w,this._resolutionScale=1,this._forceResize=!1,this._clock=o(a.clock)?a.clock:new r,T(this);try{var P=new v({canvas:l,contextOptions:a.contextOptions,creditContainer:c,mapProjection:a.mapProjection,orderIndependentTranslucency:a.orderIndependentTranslucency,scene3DOnly:n(a.scene3DOnly,!1)});this._scene=P,P.camera.constrainedAxis=t.UNIT_Z,b(this);var A=n(P.mapProjection.ellipsoid,u.WGS84),I=P.frameState.creditDisplay,M=new i("Cesium",x,"http://cesiumjs.org/");I.addDefaultCredit(M);var D=a.globe;o(D)||(D=new m(A)),D!==!1&&(P.globe=D);var R=a.skyBox;o(R)||(R=new y({sources:{positiveX:S("px"),negativeX:S("mx"),positiveY:S("py"),negativeY:S("my"),positiveZ:S("pz"),negativeZ:S("mz")}})),R!==!1&&(P.skyBox=R,P.sun=new C,P.moon=new f);var O=a.skyAtmosphere;o(O)||(O=new g(A)),O!==!1&&(P.skyAtmosphere=O);var N=a.globe===!1?!1:a.imageryProvider;o(N)||(N=new p({url:"//dev.virtualearth.net"})),N!==!1&&P.imageryLayers.addImageryProvider(N),o(a.terrainProvider)&&a.globe!==!1&&(P.terrainProvider=a.terrainProvider),this._screenSpaceEventHandler=new d(l,!1),o(a.sceneMode)&&(a.sceneMode===_.SCENE2D&&this._scene.morphTo2D(0),a.sceneMode===_.COLUMBUS_VIEW&&this._scene.morphToColumbusView(0)),this._useDefaultRenderLoop=void 0,this.useDefaultRenderLoop=n(a.useDefaultRenderLoop,!0),this._targetFrameRate=void 0,this.targetFrameRate=a.targetFrameRate;var L=this;P.renderError.addEventListener(function(e,t){if(L._useDefaultRenderLoop=!1,L._renderLoopRunning=!1,L._showRenderLoopErrors){var r="An error occurred while rendering. Rendering has stopped.";L.showErrorPanel(r,void 0,t)}})}catch(F){if(w){var B="Error constructing CesiumWidget.",V='Visit <a href="http://get.webgl.org">http://get.webgl.org</a> to verify that your web browser and hardware support WebGL. Consider trying a different web browser or updating your video drivers. Detailed error information is below:';this.showErrorPanel(B,V,F)}throw F}};return a(P.prototype,{container:{get:function(){return this._container}},canvas:{get:function(){return this._canvas}},creditContainer:{get:function(){return this._creditContainer}},scene:{get:function(){return this._scene}},imageryLayers:{get:function(){return this._scene.imageryLayers}},terrainProvider:{get:function(){return this._scene.terrainProvider},set:function(e){this._scene.terrainProvider=e}},camera:{get:function(){return this._scene.camera}},clock:{get:function(){return this._clock}},screenSpaceEventHandler:{get:function(){return this._screenSpaceEventHandler}},targetFrameRate:{get:function(){return this._targetFrameRate},set:function(e){if(0>=e)throw new l("targetFrameRate must be greater than 0.");this._targetFrameRate=e}},useDefaultRenderLoop:{get:function(){return this._useDefaultRenderLoop},set:function(e){this._useDefaultRenderLoop!==e&&(this._useDefaultRenderLoop=e,e&&!this._renderLoopRunning&&w(this))}},resolutionScale:{get:function(){return this._resolutionScale},set:function(e){if(0>=e)throw new l("resolutionScale must be greater than 0.");this._resolutionScale=e,this._forceResize=!0}}}),P.prototype.showErrorPanel=function(e,t,r){var i=this._element,n=document.createElement("div");n.className="cesium-widget-errorPanel";var a=document.createElement("div");a.className="cesium-widget-errorPanel-content",n.appendChild(a);var s=document.createElement("div");s.className="cesium-widget-errorPanel-header",s.appendChild(document.createTextNode(e)),a.appendChild(s);var l=document.createElement("div");l.className="cesium-widget-errorPanel-scroll",a.appendChild(l);var u=function(){l.style.maxHeight=Math.max(Math.round(.9*i.clientHeight-100),30)+"px"};if(u(),o(window.addEventListener)&&window.addEventListener("resize",u,!1),o(t)){var h=document.createElement("div");h.className="cesium-widget-errorPanel-message",h.innerHTML="<p>"+t+"</p>",l.appendChild(h)}var d="(no error details available)";o(r)&&(d=c(r));var p=document.createElement("div");p.className="cesium-widget-errorPanel-message",p.appendChild(document.createTextNode(d)),l.appendChild(p);var m=document.createElement("div");m.className="cesium-widget-errorPanel-buttonPanel",a.appendChild(m);var f=document.createElement("button");f.setAttribute("type","button"),f.className="cesium-button",f.appendChild(document.createTextNode("OK")),f.onclick=function(){o(u)&&o(window.removeEventListener)&&window.removeEventListener("resize",u,!1),i.removeChild(n)},m.appendChild(f),i.appendChild(n),"undefined"!=typeof console&&console.error(e+"\n"+t+"\n"+d)},P.prototype.isDestroyed=function(){return!1},P.prototype.destroy=function(){this._scene=this._scene&&this._scene.destroy(),this._container.removeChild(this._element),s(this)},P.prototype.resize=function(){var e=this._canvas,t=e.clientWidth,r=e.clientHeight;(this._forceResize||this._canvasWidth!==t||this._canvasHeight!==r)&&(this._forceResize=!1,T(this),b(this))},P.prototype.render=function(){if(this._canRender){this._scene.initializeFrame();var e=this._clock.tick();this._scene.render(e)}else this._clock.tick()},P}),r("Widgets/ClockViewModel",["../Core/Clock","../Core/defined","../Core/defineProperties","../Core/destroyObject","../Core/EventHelper","../Core/JulianDate","../ThirdParty/knockout"],function(e,t,r,i,n,o,a){"use strict";var s=function(r){t(r)||(r=new e),this._clock=r,this._eventHelper=new n,this._eventHelper.add(r.onTick,this.synchronize,this);var i=a.observable(r.startTime);i.equalityComparer=o.equals,this.systemTime=a.observable(o.now()),this.systemTime.equalityComparer=o.equals,a.track(this,["systemTime"]),this.startTime=void 0,a.defineProperty(this,"startTime",{get:i,set:function(e){i(e),r.startTime=e}});var s=a.observable(r.stopTime);s.equalityComparer=o.equals,this.stopTime=void 0,a.defineProperty(this,"stopTime",{get:s,set:function(e){r.stopTime=e,s(e)}});var l=a.observable(r.currentTime);l.equalityComparer=o.equals,this.currentTime=void 0,a.defineProperty(this,"currentTime",{get:l,set:function(e){r.currentTime=e,l(e)}});var u=a.observable(r.multiplier);this.multiplier=void 0,a.defineProperty(this,"multiplier",{get:u,set:function(e){r.multiplier=e,u(e)}});var c=a.observable(r.clockStep);c.equalityComparer=function(e,t){return e===t},this.clockStep=void 0,a.defineProperty(this,"clockStep",{get:c,set:function(e){c(e),r.clockStep=e}});var h=a.observable(r.clockRange);h.equalityComparer=function(e,t){return e===t},this.clockRange=void 0,a.defineProperty(this,"clockRange",{get:h,set:function(e){h(e),r.clockRange=e}});var d=a.observable(r.canAnimate);this.canAnimate=void 0,a.defineProperty(this,"canAnimate",{get:d,set:function(e){d(e),r.canAnimate=e}});var p=a.observable(r.shouldAnimate);this.shouldAnimate=void 0,a.defineProperty(this,"shouldAnimate",{get:p,set:function(e){p(e),r.shouldAnimate=e}})};return r(s.prototype,{clock:{get:function(){return this._clock}}}),s.prototype.synchronize=function(){var e=this._clock,t=e.startTime,r=e.stopTime,i=e.currentTime,n=e.multiplier,a=e.clockStep,s=e.clockRange,l=e.canAnimate,u=e.shouldAnimate;this.systemTime=o.now(),this.startTime=t,this.stopTime=r,this.currentTime=i,this.multiplier=n,this.clockStep=a,this.clockRange=s,this.canAnimate=l,this.shouldAnimate=u},s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){this._eventHelper.removeAll(),i(this)},s}),r("Widgets/Command",["../Core/DeveloperError"],function(e){"use strict";var t=function(){this.canExecute=void 0,this.beforeExecute=void 0,this.afterExecute=void 0,e.throwInstantiationError()};return t}),r("Widgets/FullscreenButton/FullscreenButtonViewModel",["../../Core/defaultValue","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/Fullscreen","../../ThirdParty/knockout","../createCommand","../getElement"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){var r=this,i=o.observable(n.fullscreen),l=o.observable(n.enabled);this.isFullscreen=void 0,o.defineProperty(this,"isFullscreen",{get:function(){return i()}}),this.isFullscreenEnabled=void 0,o.defineProperty(this,"isFullscreenEnabled",{get:function(){return l()},set:function(e){l(e&&n.enabled)}}),this.tooltip=void 0,o.defineProperty(this,"tooltip",function(){return this.isFullscreenEnabled?i()?"Exit full screen":"Full screen":"Full screen unavailable"}),this._command=a(function(){n.fullscreen?n.exitFullscreen():n.requestFullscreen(r._fullscreenElement)},o.getObservable(this,"isFullscreenEnabled")),this._fullscreenElement=e(s(t),document.body),this._callback=function(){i(n.fullscreen)},document.addEventListener(n.changeEventName,this._callback)};return t(l.prototype,{fullscreenElement:{get:function(){return this._fullscreenElement},set:function(e){this._fullscreenElement=e}},command:{get:function(){return this._command}}}),l.prototype.isDestroyed=function(){return!1},l.prototype.destroy=function(){document.removeEventListener(n.changeEventName,this._callback),r(this)},l}),r("Widgets/FullscreenButton/FullscreenButton",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./FullscreenButtonViewModel"],function(e,t,r,i,n,o,a){"use strict";var s="M 83.96875 17.5625 L 83.96875 17.59375 L 76.65625 24.875 L 97.09375 24.96875 L 76.09375 45.96875 L 81.9375 51.8125 L 102.78125 30.9375 L 102.875 51.15625 L 110.15625 43.875 L 110.1875 17.59375 L 83.96875 17.5625 z M 44.125 17.59375 L 17.90625 17.625 L 17.9375 43.90625 L 25.21875 51.1875 L 25.3125 30.96875 L 46.15625 51.8125 L 52 45.96875 L 31 25 L 51.4375 24.90625 L 44.125 17.59375 z M 46.0625 76.03125 L 25.1875 96.875 L 25.09375 76.65625 L 17.8125 83.9375 L 17.8125 110.21875 L 44 110.25 L 51.3125 102.9375 L 30.90625 102.84375 L 51.875 81.875 L 46.0625 76.03125 z M 82 76.15625 L 76.15625 82 L 97.15625 103 L 76.71875 103.0625 L 84.03125 110.375 L 110.25 110.34375 L 110.21875 84.0625 L 102.9375 76.8125 L 102.84375 97 L 82 76.15625 z",l="M 104.34375 17.5625 L 83.5 38.4375 L 83.40625 18.21875 L 76.125 25.5 L 76.09375 51.78125 L 102.3125 51.8125 L 102.3125 51.78125 L 109.625 44.5 L 89.1875 44.40625 L 110.1875 23.40625 L 104.34375 17.5625 z M 23.75 17.59375 L 17.90625 23.4375 L 38.90625 44.4375 L 18.5 44.53125 L 25.78125 51.8125 L 52 51.78125 L 51.96875 25.53125 L 44.6875 18.25 L 44.625 38.46875 L 23.75 17.59375 z M 25.6875 76.03125 L 18.375 83.3125 L 38.78125 83.40625 L 17.8125 104.40625 L 23.625 110.25 L 44.5 89.375 L 44.59375 109.59375 L 51.875 102.3125 L 51.875 76.0625 L 25.6875 76.03125 z M 102.375 76.15625 L 76.15625 76.1875 L 76.1875 102.4375 L 83.46875 109.71875 L 83.5625 89.53125 L 104.40625 110.375 L 110.25 104.53125 L 89.25 83.53125 L 109.6875 83.46875 L 102.375 76.15625 z",u=function(e,t){e=o(e);var r=new a(t);r._exitFullScreenPath=l,r._enterFullScreenPath=s;var i=document.createElement("button");i.type="button",i.className="cesium-button cesium-fullscreenButton",i.setAttribute("data-bind","attr: { title: tooltip },click: command,enable: isFullscreenEnabled,cesiumSvgPath: { path: isFullscreen ? _exitFullScreenPath : _enterFullScreenPath, width: 128, height: 128 }"),e.appendChild(i),n.applyBindings(r,i),this._container=e,this._viewModel=r,this._element=i};return t(u.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),u.prototype.isDestroyed=function(){return!1},u.prototype.destroy=function(){return this._viewModel.destroy(),n.cleanNode(this._element),this._container.removeChild(this._element),r(this)},u}),r("Widgets/Geocoder/GeocoderViewModel",["../../Core/BingMapsApi","../../Core/Cartesian3","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/Event","../../Core/loadJsonp","../../Core/Matrix4","../../Core/Rectangle","../../Scene/SceneMode","../../ThirdParty/knockout","../../ThirdParty/when","../createCommand"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p){"use strict";function m(e,t){e._scene.camera.flyTo({destination:t,complete:function(){e._complete.raiseEvent()},duration:e._flightDuration,endTransform:l.IDENTITY,convert:!1})}function f(e){var r=e.searchText;if(!/^\s*$/.test(r)){var i=r.match(/[^\s,\n]+/g);if(2===i.length||3===i.length){var n=+i[0],o=+i[1],a=3===i.length?+i[2]:300;if(!isNaN(n)&&!isNaN(o)&&!isNaN(a))return void m(e,t.fromDegrees(n,o,a))}e._isSearchInProgress=!0;var l=s(e._url+"REST/v1/Locations",{parameters:{query:r,key:e._key},callbackParameterName:"jsonp"}),c=e._geocodeInProgress=d(l,function(t){if(!c.cancel){if(e._isSearchInProgress=!1,0===t.resourceSets.length)return void(e.searchText=e._searchText+" (not found)");var r=t.resourceSets[0];if(0===r.resources.length)return void(e.searchText=e._searchText+" (not found)");var i=r.resources[0];e._searchText=i.name;var n=i.bbox,o=n[0],a=n[1],s=n[2],l=n[3];m(e,u.fromDegrees(a,o,l,s))}},function(){ -c.cancel||(e._isSearchInProgress=!1,e.searchText=e._searchText+" (error)")})}}function v(e){e._isSearchInProgress=!1,i(e._geocodeInProgress)&&(e._geocodeInProgress.cancel=!0,e._geocodeInProgress=void 0)}var _=function(t){this._url=r(t.url,"//dev.virtualearth.net/"),this._url.length>0&&"/"!==this._url[this._url.length-1]&&(this._url+="/"),this._key=e.getKey(t.key),this._scene=t.scene,this._flightDuration=t.flightDuration,this._searchText="",this._isSearchInProgress=!1,this._geocodeInProgress=void 0,this._complete=new a;var i=this;this._searchCommand=p(function(){i.isSearchInProgress?v(i):f(i)}),h.track(this,["_searchText","_isSearchInProgress"]),this.isSearchInProgress=void 0,h.defineProperty(this,"isSearchInProgress",{get:function(){return this._isSearchInProgress}}),this.searchText=void 0,h.defineProperty(this,"searchText",{get:function(){return this.isSearchInProgress?"Searching...":this._searchText},set:function(e){this._searchText=e}}),this.flightDuration=void 0,h.defineProperty(this,"flightDuration",{get:function(){return this._flightDuration},set:function(e){this._flightDuration=e}})};return n(_.prototype,{url:{get:function(){return this._url}},key:{get:function(){return this._key}},complete:{get:function(){return this._complete}},scene:{get:function(){return this._scene}},search:{get:function(){return this._searchCommand}}}),_}),r("Widgets/Geocoder/Geocoder",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./GeocoderViewModel"],function(e,t,r,i,n,o,a,s){"use strict";var l="M29.772,26.433l-7.126-7.126c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127L29.772,26.433zM7.203,13.885c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486c-0.007,3.58-2.905,6.476-6.484,6.484C10.106,20.361,7.209,17.465,7.203,13.885z",u="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z",c=function(e){var t=a(e.container),r=new s(e);r._startSearchPath=l,r._stopSearchPath=u;var i=document.createElement("form");i.setAttribute("data-bind","submit: search");var c=document.createElement("input");c.type="search",c.className="cesium-geocoder-input",c.setAttribute("placeholder","Enter an address or landmark..."),c.setAttribute("data-bind",'value: searchText,valueUpdate: "afterkeydown",disable: isSearchInProgress,css: { "cesium-geocoder-input-wide" : searchText.length > 0 }'),i.appendChild(c);var h=document.createElement("span");h.className="cesium-geocoder-searchButton",h.setAttribute("data-bind","click: search,cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, width: 32, height: 32 }"),i.appendChild(h),t.appendChild(i),o.applyBindings(r,i),this._container=t,this._viewModel=r,this._form=i,this._onInputBegin=function(e){t.contains(e.target)||c.blur()},this._onInputEnd=function(e){t.contains(e.target)&&c.focus()},n.supportsPointerEvents()?(document.addEventListener("pointerdown",this._onInputBegin,!0),document.addEventListener("pointerup",this._onInputEnd,!0)):(document.addEventListener("mousedown",this._onInputBegin,!0),document.addEventListener("mouseup",this._onInputEnd,!0),document.addEventListener("touchstart",this._onInputBegin,!0),document.addEventListener("touchend",this._onInputEnd,!0))};return t(c.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return n.supportsPointerEvents()?(document.removeEventListener("pointerdown",this._onInputBegin,!0),document.removeEventListener("pointerup",this._onInputEnd,!0)):(document.removeEventListener("mousedown",this._onInputBegin,!0),document.removeEventListener("mouseup",this._onInputEnd,!0),document.removeEventListener("touchstart",this._onInputBegin,!0),document.removeEventListener("touchend",this._onInputEnd,!0)),o.cleanNode(this._form),this._container.removeChild(this._form),r(this)},c}),r("Widgets/HomeButton/HomeButtonViewModel",["../../Core/Cartesian3","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/Matrix4","../../Core/Rectangle","../../Scene/Camera","../../Scene/SceneMode","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s,l,u,c){"use strict";function h(t,i){var n=t.mode;if(r(t)&&n===l.MORPHING&&t.completeMorph(),n===l.SCENE2D)t.camera.flyTo({destination:a.MAX_VALUE,duration:i,endTransform:o.IDENTITY});else if(n===l.SCENE3D){var u=t.camera.getRectangleCameraCoordinates(s.DEFAULT_VIEW_RECTANGLE),c=e.magnitude(u);c+=c*s.DEFAULT_VIEW_FACTOR,e.normalize(u,u),e.multiplyByScalar(u,c,u),t.camera.flyTo({destination:u,duration:i,endTransform:o.IDENTITY})}else if(n===l.COLUMBUS_VIEW){var h=t.globe.ellipsoid.maximumRadius,p=new e(0,-1,1);p=e.multiplyByScalar(e.normalize(p,p),5*h,p),t.camera.flyTo({destination:p,duration:i,orientation:{heading:0,pitch:-Math.acos(e.normalize(p,d).z),roll:0},endTransform:o.IDENTITY,convert:!1})}}var d=new e,p=function(e,t){this._scene=e,this._duration=t;var r=this;this._command=c(function(){h(r._scene,r._duration)}),this.tooltip="View Home",u.track(this,["tooltip"])};return i(p.prototype,{scene:{get:function(){return this._scene}},command:{get:function(){return this._command}},duration:{get:function(){return this._duration},set:function(e){this._duration=e}}}),p}),r("Widgets/HomeButton/HomeButton",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./HomeButtonViewModel"],function(e,t,r,i,n,o,a){"use strict";var s=function(e,t,r){e=o(e);var i=new a(t,r);i._svgPath="M14,4l-10,8.75h20l-4.25-3.7188v-4.6562h-2.812v2.1875l-2.938-2.5625zm-7.0938,9.906v10.094h14.094v-10.094h-14.094zm2.1876,2.313h3.3122v4.25h-3.3122v-4.25zm5.8442,1.281h3.406v6.438h-3.406v-6.438z";var s=document.createElement("button");s.type="button",s.className="cesium-button cesium-toolbar-button cesium-home-button",s.setAttribute("data-bind","attr: { title: tooltip },click: command,cesiumSvgPath: { path: _svgPath, width: 28, height: 28 }"),e.appendChild(s),n.applyBindings(i,s),this._container=e,this._viewModel=i,this._element=s};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return n.cleanNode(this._element),this._container.removeChild(this._element),r(this)},s}),r("Widgets/InfoBox/InfoBoxViewModel",["../../Core/defined","../../Core/defineProperties","../../Core/Event","../../ThirdParty/knockout"],function(e,t,r,i){"use strict";var n="M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4853444 22.104033 11.423165 24.0625 13.84375 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 8.975298 28.305952 7.03125 25.875 7.03125 L 13.84375 7.03125 z",o="M 27.34375 1.65625 L 5.28125 27.9375 L 8.09375 30.3125 L 30.15625 4.03125 L 27.34375 1.65625 z M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4724893 20.232036 9.5676108 20.7379 9.75 21.21875 L 21.65625 7.03125 L 13.84375 7.03125 z M 28.21875 7.71875 L 14.53125 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 9.8371439 29.456025 8.4902779 28.21875 7.71875 z",a=function(){this._cameraClicked=new r,this._closeClicked=new r,this.maxHeight=500,this.enableCamera=!1,this.isCameraTracking=!1,this.showInfo=!1,this.titleText="",this.description="",i.track(this,["showInfo","titleText","description","maxHeight","enableCamera","isCameraTracking"]),this._loadingIndicatorHtml='<div class="cesium-infoBox-loadingContainer"><span class="cesium-infoBox-loading"></span></div>',this.cameraIconPath=void 0,i.defineProperty(this,"cameraIconPath",{get:function(){return!this.enableCamera||this.isCameraTracking?o:n}}),i.defineProperty(this,"_bodyless",{get:function(){return!e(this.description)||0===this.description.length}})};return a.prototype.maxHeightOffset=function(e){return this.maxHeight-e+"px"},t(a.prototype,{cameraClicked:{get:function(){return this._cameraClicked}},closeClicked:{get:function(){return this._closeClicked}}}),a}),r("Widgets/InfoBox/InfoBox",["../../Core/buildModuleUrl","../../Core/Color","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","../subscribeAndEvaluate","./InfoBoxViewModel"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(i){i=s(i);var n=document.createElement("div");n.className="cesium-infoBox",n.setAttribute("data-bind",'css: { "cesium-infoBox-visible" : showInfo, "cesium-infoBox-bodyless" : _bodyless }'),i.appendChild(n);var o=document.createElement("div");o.className="cesium-infoBox-title",o.setAttribute("data-bind","text: titleText"),n.appendChild(o);var c=document.createElement("button");c.type="button",c.className="cesium-button cesium-infoBox-camera",c.setAttribute("data-bind",'attr: { title: "Focus camera on object" },click: function () { cameraClicked.raiseEvent(this); },enable: enableCamera,cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }'),n.appendChild(c);var h=document.createElement("button");h.type="button",h.className="cesium-infoBox-close",h.setAttribute("data-bind","click: function () { closeClicked.raiseEvent(this); }"),h.innerHTML="×",n.appendChild(h);var d=document.createElement("iframe");d.className="cesium-infoBox-iframe",d.setAttribute("sandbox","allow-same-origin allow-popups allow-forms"),d.setAttribute("data-bind","style : { maxHeight : maxHeightOffset(40) }"),d.setAttribute("allowfullscreen",!0),n.appendChild(d);var p=new u;a.applyBindings(p,n),this._container=i,this._element=n,this._frame=d,this._viewModel=p,this._descriptionSubscription=void 0;var m=this;d.addEventListener("load",function(){var i=d.contentDocument,o=i.createElement("link");o.href=e("Widgets/InfoBox/InfoBoxDescription.css"),o.rel="stylesheet",o.type="text/css";var a=i.createElement("div");a.className="cesium-infoBox-description",i.head.appendChild(o),i.body.appendChild(a),m._descriptionSubscription=l(p,"description",function(e){d.style.height="5px",a.innerHTML=e;var i=null,o=a.firstElementChild;if(null!==o&&1===a.childNodes.length){var s=window.getComputedStyle(o);if(null!==s){var l=s["background-color"],u=t.fromCssColorString(l);r(u)&&0!==u.alpha&&(i=s["background-color"])}}n.style["background-color"]=i;var c=a.getBoundingClientRect().height;d.style.height=c+"px"})}),d.setAttribute("src","about:blank")};return i(c.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}},frame:{get:function(){return this._frame}}}),c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){var e=this._container;return a.cleanNode(this._element),e.removeChild(this._element),r(this._descriptionSubscription)&&this._descriptionSubscription.dispose(),n(this)},c}),r("Widgets/NavigationHelpButton/NavigationHelpButtonViewModel",["../../Core/defineProperties","../../ThirdParty/knockout","../createCommand"],function(e,t,r){"use strict";var i=function(){this.showInstructions=!1;var e=this;this._command=r(function(){e.showInstructions=!e.showInstructions}),this._showClick=r(function(){e._touch=!1}),this._showTouch=r(function(){e._touch=!0}),this._touch=!1,this.tooltip="Navigation Instructions",t.track(this,["tooltip","showInstructions","_touch"])};return e(i.prototype,{command:{get:function(){return this._command}},showClick:{get:function(){return this._showClick}},showTouch:{get:function(){return this._showTouch}}}),i}),r("Widgets/NavigationHelpButton/NavigationHelpButton",["../../Core/buildModuleUrl","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./NavigationHelpButtonViewModel"],function(e,t,r,i,n,o,a,s,l,u){"use strict";var c=function(r){var i=l(r.container),n=new u,o=t(r.instructionsInitiallyVisible,!1);n.showInstructions=o,n._svgPath="M16,1.466C7.973,1.466,1.466,7.973,1.466,16c0,8.027,6.507,14.534,14.534,14.534c8.027,0,14.534-6.507,14.534-14.534C30.534,7.973,24.027,1.466,16,1.466z M17.328,24.371h-2.707v-2.596h2.707V24.371zM17.328,19.003v0.858h-2.707v-1.057c0-3.19,3.63-3.696,3.63-5.963c0-1.034-0.924-1.826-2.134-1.826c-1.254,0-2.354,0.924-2.354,0.924l-1.541-1.915c0,0,1.519-1.584,4.137-1.584c2.487,0,4.796,1.54,4.796,4.136C21.156,16.208,17.328,16.627,17.328,19.003z";var c=document.createElement("span");c.className="cesium-navigationHelpButton-wrapper",i.appendChild(c);var h=document.createElement("button");h.type="button",h.className="cesium-button cesium-toolbar-button cesium-navigation-help-button",h.setAttribute("data-bind","attr: { title: tooltip },click: command,cesiumSvgPath: { path: _svgPath, width: 32, height: 32 }"),c.appendChild(h);var d=document.createElement("div");d.className="cesium-navigation-help",d.setAttribute("data-bind",'css: { "cesium-navigation-help-visible" : showInstructions}'),c.appendChild(d);var p=document.createElement("button");p.type="button",p.className="cesium-navigation-button cesium-navigation-button-left",p.setAttribute("data-bind",'click: showClick, css: {"cesium-navigation-button-selected": !_touch, "cesium-navigation-button-unselected": _touch}');var m=document.createElement("img");m.src=e("Widgets/Images/NavigationHelp/Mouse.svg"),m.className="cesium-navigation-button-icon",m.style.width="25px",m.style.height="25px",p.appendChild(m),p.appendChild(document.createTextNode("Mouse"));var f=document.createElement("button");f.type="button",f.className="cesium-navigation-button cesium-navigation-button-right",f.setAttribute("data-bind",'click: showTouch, css: {"cesium-navigation-button-selected": _touch, "cesium-navigation-button-unselected": !_touch}');var v=document.createElement("img");v.src=e("Widgets/Images/NavigationHelp/Touch.svg"),v.className="cesium-navigation-button-icon",v.style.width="25px",v.style.height="25px",f.appendChild(v),f.appendChild(document.createTextNode("Touch")),d.appendChild(p),d.appendChild(f);var _=document.createElement("div");_.className="cesium-click-navigation-help cesium-navigation-help-instructions",_.setAttribute("data-bind",'css: { "cesium-click-navigation-help-visible" : !_touch}'),_.innerHTML=' <table> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/MouseLeft.svg")+'" width="48" height="48" /></td> <td> <div class="cesium-navigation-help-pan">Pan view</div> <div class="cesium-navigation-help-details">Left click + drag</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/MouseRight.svg")+'" width="48" height="48" /></td> <td> <div class="cesium-navigation-help-zoom">Zoom view</div> <div class="cesium-navigation-help-details">Right click + drag, or</div> <div class="cesium-navigation-help-details">Mouse wheel scroll</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/MouseMiddle.svg")+'" width="48" height="48" /></td> <td> <div class="cesium-navigation-help-rotate">Rotate view</div> <div class="cesium-navigation-help-details">Middle click + drag, or</div> <div class="cesium-navigation-help-details">CTRL + Left/Right click + drag</div> </td> </tr> </table>',d.appendChild(_);var g=document.createElement("div");g.className="cesium-touch-navigation-help cesium-navigation-help-instructions",g.setAttribute("data-bind",'css: { "cesium-touch-navigation-help-visible" : _touch}'),g.innerHTML=' <table> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchDrag.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-pan">Pan view</div> <div class="cesium-navigation-help-details">One finger drag</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchZoom.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-zoom">Zoom view</div> <div class="cesium-navigation-help-details">Two finger pinch</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchTilt.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-rotate">Tilt view</div> <div class="cesium-navigation-help-details">Two finger drag, same direction</div> </td> </tr> <tr> <td><img src="'+e("Widgets/Images/NavigationHelp/TouchRotate.svg")+'" width="70" height="48" /></td> <td> <div class="cesium-navigation-help-tilt">Rotate view</div> <div class="cesium-navigation-help-details">Two finger drag, opposite direction</div> </td> </tr> </table>',d.appendChild(g),s.applyBindings(n,c),this._container=i,this._viewModel=n,this._wrapper=c,this._closeInstructions=function(e){c.contains(e.target)||(n.showInstructions=!1)},a.supportsPointerEvents()?document.addEventListener("pointerdown",this._closeInstructions,!0):(document.addEventListener("mousedown",this._closeInstructions,!0),document.addEventListener("touchstart",this._closeInstructions,!0))};return i(c.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),c.prototype.isDestroyed=function(){return!1},c.prototype.destroy=function(){return a.supportsPointerEvents()?document.removeEventListener("pointerdown",this._closeInstructions,!0):(document.removeEventListener("mousedown",this._closeInstructions,!0),document.removeEventListener("touchstart",this._closeInstructions,!0)),s.cleanNode(this._wrapper),this._container.removeChild(this._wrapper),n(this)},c}),r("Widgets/PerformanceWatchdog/PerformanceWatchdogViewModel",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Scene/FrameRateMonitor","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s){"use strict";var l=function(t){this._scene=t.scene,this.lowFrameRateMessage=e(t.lowFrameRateMessage,"This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers."),this.lowFrameRateMessageDismissed=!1,this.showingLowFrameRateMessage=!1,a.track(this,["lowFrameRateMessage","lowFrameRateMessageDismissed","showingLowFrameRateMessage"]);var r=this;this._dismissMessage=s(function(){r.showingLowFrameRateMessage=!1,r.lowFrameRateMessageDismissed=!0});var i=o.fromScene(t.scene);this._unsubscribeLowFrameRate=i.lowFrameRate.addEventListener(function(){r.lowFrameRateMessageDismissed||(r.showingLowFrameRateMessage=!0)}),this._unsubscribeNominalFrameRate=i.nominalFrameRate.addEventListener(function(){r.showingLowFrameRateMessage=!1})};return r(l.prototype,{scene:{get:function(){return this._scene}},dismissMessage:{get:function(){return this._dismissMessage}}}),l.prototype.destroy=function(){return this._unsubscribeLowFrameRate(),this._unsubscribeNominalFrameRate(),i(this)},l}),r("Widgets/PerformanceWatchdog/PerformanceWatchdog",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./PerformanceWatchdogViewModel"],function(e,t,r,i,n,o,a){"use strict";var s=function(e){var t=o(e.container),r=new a(e),i=document.createElement("div");i.className="cesium-performance-watchdog-message-area",i.setAttribute("data-bind","visible: showingLowFrameRateMessage");var s=document.createElement("button");s.setAttribute("type","button"),s.className="cesium-performance-watchdog-message-dismiss",s.innerHTML="×",s.setAttribute("data-bind","click: dismissMessage"),i.appendChild(s);var l=document.createElement("div");l.className="cesium-performance-watchdog-message",l.setAttribute("data-bind","html: lowFrameRateMessage"),i.appendChild(l),t.appendChild(i),n.applyBindings(r,i),this._container=t,this._viewModel=r,this._element=i};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){return this._viewModel.destroy(),n.cleanNode(this._element),this._container.removeChild(this._element),r(this)},s}),r("Widgets/SceneModePicker/SceneModePickerViewModel",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/EventHelper","../../Scene/SceneMode","../../ThirdParty/knockout","../createCommand"],function(e,t,r,i,n,o,a,s,l){"use strict";var u=function(t,r){this._scene=t;var i=this,n=function(e,t,r,n){i.sceneMode=r,i.dropDownVisible=!1};this._eventHelper=new o,this._eventHelper.add(t.morphStart,n),this._duration=e(r,2),this.sceneMode=t.mode,this.dropDownVisible=!1,this.tooltip2D="2D",this.tooltip3D="3D",this.tooltipColumbusView="Columbus View",s.track(this,["sceneMode","dropDownVisible","tooltip2D","tooltip3D","tooltipColumbusView"]),this.selectedTooltip=void 0,s.defineProperty(this,"selectedTooltip",function(){var e=i.sceneMode;return e===a.SCENE2D?i.tooltip2D:e===a.SCENE3D?i.tooltip3D:i.tooltipColumbusView}),this._toggleDropDown=l(function(){i.dropDownVisible=!i.dropDownVisible}),this._morphTo2D=l(function(){t.morphTo2D(i._duration)}),this._morphTo3D=l(function(){t.morphTo3D(i._duration)}),this._morphToColumbusView=l(function(){t.morphToColumbusView(i._duration)}),this._sceneMode=a};return r(u.prototype,{scene:{get:function(){return this._scene}},duration:{get:function(){return this._duration},set:function(e){this._duration=e}},toggleDropDown:{get:function(){return this._toggleDropDown}},morphTo2D:{get:function(){return this._morphTo2D}},morphTo3D:{get:function(){return this._morphTo3D}},morphToColumbusView:{get:function(){return this._morphToColumbusView}}}),u.prototype.isDestroyed=function(){return!1},u.prototype.destroy=function(){this._eventHelper.removeAll(),i(this)},u}),r("Widgets/SceneModePicker/SceneModePicker",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/FeatureDetection","../../ThirdParty/knockout","../getElement","./SceneModePickerViewModel"],function(e,t,r,i,n,o,a,s){"use strict";var l="m 32.401392,4.9330437 c -7.087603,0 -14.096095,2.884602 -19.10793,7.8946843 -5.0118352,5.010083 -7.9296167,11.987468 -7.9296167,19.072999 0,7.085531 2.9177815,14.097848 7.9296167,19.107931 4.837653,4.835961 11.541408,7.631372 18.374354,7.82482 0.05712,0.01231 0.454119,0.139729 0.454119,0.139729 l 0.03493,-0.104797 c 0.08246,7.84e-4 0.162033,0.03493 0.244525,0.03493 0.08304,0 0.161515,-0.03414 0.244526,-0.03493 l 0.03493,0.104797 c 0,0 0.309474,-0.129487 0.349323,-0.139729 6.867765,-0.168094 13.582903,-2.965206 18.444218,-7.82482 2.558195,-2.5573 4.551081,-5.638134 5.903547,-8.977584 1.297191,-3.202966 2.02607,-6.661489 2.02607,-10.130347 0,-6.237309 -2.366261,-12.31219 -6.322734,-17.116794 -0.0034,-0.02316 0.0049,-0.04488 0,-0.06986 -0.01733,-0.08745 -0.104529,-0.278855 -0.104797,-0.279458 -5.31e-4,-0.0012 -0.522988,-0.628147 -0.523984,-0.62878 -3.47e-4,-2.2e-4 -0.133444,-0.03532 -0.244525,-0.06987 C 51.944299,13.447603 51.751076,13.104317 51.474391,12.827728 46.462556,7.8176457 39.488996,4.9330437 32.401392,4.9330437 z m -2.130866,3.5281554 0.104797,9.6762289 c -4.111695,-0.08361 -7.109829,-0.423664 -9.257041,-0.943171 1.198093,-2.269271 2.524531,-4.124404 3.91241,-5.414496 2.167498,-2.0147811 3.950145,-2.8540169 5.239834,-3.3185619 z m 2.794579,0 c 1.280302,0.4754953 3.022186,1.3285948 5.065173,3.2486979 1.424667,1.338973 2.788862,3.303645 3.982275,5.728886 -2.29082,0.403367 -5.381258,0.621049 -8.942651,0.698645 L 33.065105,8.4611991 z m 5.728886,0.2445256 c 4.004072,1.1230822 7.793098,3.1481363 10.724195,6.0782083 0.03468,0.03466 0.07033,0.06991 0.104797,0.104797 -0.45375,0.313891 -0.923054,0.663002 -1.956205,1.082899 -0.647388,0.263114 -1.906242,0.477396 -2.829511,0.733577 -1.382296,-2.988132 -3.027146,-5.368585 -4.785716,-7.0213781 -0.422866,-0.397432 -0.835818,-0.6453247 -1.25756,-0.9781032 z m -15.33525,0.7685092 c -0.106753,0.09503 -0.207753,0.145402 -0.31439,0.244526 -1.684973,1.5662541 -3.298068,3.8232211 -4.680919,6.5672591 -0.343797,-0.14942 -1.035052,-0.273198 -1.292493,-0.419186 -0.956528,-0.542427 -1.362964,-1.022024 -1.537018,-1.292493 -0.0241,-0.03745 -0.01868,-0.0401 -0.03493,-0.06986 2.250095,-2.163342 4.948824,-3.869984 7.859752,-5.0302421 z m -9.641296,7.0912431 c 0.464973,0.571618 0.937729,1.169056 1.956205,1.746612 0.349907,0.198425 1.107143,0.335404 1.537018,0.523983 -1.20166,3.172984 -1.998037,7.051901 -2.165798,11.772162 C 14.256557,30.361384 12.934823,30.161483 12.280427,29.90959 10.644437,29.279855 9.6888882,28.674891 9.1714586,28.267775 8.6540289,27.860658 8.6474751,27.778724 8.6474751,27.778724 l -0.069864,0.03493 C 9.3100294,23.691285 11.163248,19.798527 13.817445,16.565477 z m 37.552149,0.523984 c 2.548924,3.289983 4.265057,7.202594 4.890513,11.318043 -0.650428,0.410896 -1.756876,1.001936 -3.563088,1.606882 -1.171552,0.392383 -3.163859,0.759153 -4.960377,1.117832 -0.04367,-4.752703 -0.784809,-8.591423 -1.88634,-11.807094 0.917574,-0.263678 2.170552,-0.486495 2.864443,-0.76851 1.274693,-0.518066 2.003942,-1.001558 2.654849,-1.467153 z m -31.439008,2.619917 c 2.487341,0.672766 5.775813,1.137775 10.479669,1.222628 l 0.104797,10.689263 0,0.03493 0,0.733577 c -5.435005,-0.09059 -9.512219,-0.519044 -12.610536,-1.117831 0.106127,-4.776683 0.879334,-8.55791 2.02607,-11.562569 z m 23.264866,0.31439 c 1.073459,3.067541 1.833795,6.821314 1.816476,11.702298 -3.054474,0.423245 -7.062018,0.648559 -11.702298,0.698644 l 0,-0.838373 -0.104796,-10.654331 c 4.082416,-0.0864 7.404468,-0.403886 9.990618,-0.908238 z M 8.2632205,30.922625 c 0.7558676,0.510548 1.5529563,1.013339 3.0041715,1.57195 0.937518,0.360875 2.612202,0.647642 3.91241,0.978102 0.112814,3.85566 0.703989,7.107756 1.606883,9.920754 -1.147172,-0.324262 -2.644553,-0.640648 -3.423359,-0.978102 -1.516688,-0.657177 -2.386627,-1.287332 -2.864443,-1.71168 -0.477816,-0.424347 -0.489051,-0.489051 -0.489051,-0.489051 L 9.8002387,40.319395 C 8.791691,37.621767 8.1584238,34.769583 8.1584238,31.900727 c 0,-0.330153 0.090589,-0.648169 0.1047967,-0.978102 z m 48.2763445,0.419186 c 0.0047,0.188973 0.06986,0.36991 0.06986,0.558916 0,2.938869 -0.620228,5.873558 -1.676747,8.628261 -0.07435,0.07583 -0.06552,0.07411 -0.454119,0.349323 -0.606965,0.429857 -1.631665,1.042044 -3.318562,1.676747 -1.208528,0.454713 -3.204964,0.850894 -5.135038,1.25756 0.84593,-2.765726 1.41808,-6.005357 1.606883,-9.815957 2.232369,-0.413371 4.483758,-0.840201 5.938479,-1.327425 1.410632,-0.472457 2.153108,-0.89469 2.96924,-1.327425 z m -38.530252,2.864443 c 3.208141,0.56697 7.372279,0.898588 12.575603,0.978103 l 0.174662,9.885821 c -4.392517,-0.06139 -8.106722,-0.320566 -10.863925,-0.803441 -1.051954,-2.664695 -1.692909,-6.043794 -1.88634,-10.060483 z m 26.793022,0.31439 c -0.246298,3.923551 -0.877762,7.263679 -1.816476,9.885822 -2.561957,0.361954 -5.766249,0.560708 -9.431703,0.62878 l -0.174661,-9.815957 c 4.491734,-0.04969 8.334769,-0.293032 11.42284,-0.698645 z M 12.035901,44.860585 c 0.09977,0.04523 0.105535,0.09465 0.209594,0.139729 1.337656,0.579602 3.441099,1.058072 5.589157,1.537018 1.545042,3.399208 3.548524,5.969402 5.589157,7.789888 -3.034411,-1.215537 -5.871615,-3.007978 -8.174142,-5.309699 -1.245911,-1.245475 -2.271794,-2.662961 -3.213766,-4.156936 z m 40.69605,0 c -0.941972,1.493975 -1.967855,2.911461 -3.213765,4.156936 -2.74253,2.741571 -6.244106,4.696717 -9.955686,5.868615 0.261347,-0.241079 0.507495,-0.394491 0.768509,-0.663713 1.674841,-1.727516 3.320792,-4.181056 4.645987,-7.265904 2.962447,-0.503021 5.408965,-1.122293 7.161107,-1.781544 0.284034,-0.106865 0.337297,-0.207323 0.593848,-0.31439 z m -31.404076,2.305527 c 2.645807,0.376448 5.701178,0.649995 9.466635,0.698645 l 0.139729,7.789888 c -1.38739,-0.480844 -3.316218,-1.29837 -5.659022,-3.388427 -1.388822,-1.238993 -2.743668,-3.0113 -3.947342,-5.100106 z m 20.365491,0.104797 c -1.04872,2.041937 -2.174337,3.779068 -3.353494,4.995309 -1.853177,1.911459 -3.425515,2.82679 -4.611055,3.353494 l -0.139729,-7.789887 c 3.13091,-0.05714 5.728238,-0.278725 8.104278,-0.558916 z",u="m 2.9825053,17.550598 0,1.368113 0,26.267766 0,1.368113 1.36811,0 54.9981397,0 1.36811,0 0,-1.368113 0,-26.267766 0,-1.368113 -1.36811,0 -54.9981397,0 -1.36811,0 z m 2.73623,2.736226 10.3292497,0 0,10.466063 -10.3292497,0 0,-10.466063 z m 13.0654697,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 10.32926,0 0,10.466063 -10.32926,0 0,-10.466063 z m -41.9326497,13.202288 10.3292497,0 0,10.329252 -10.3292497,0 0,-10.329252 z m 13.0654697,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 10.32926,0 0,10.329252 -10.32926,0 0,-10.329252 z",c="m 14.723969,17.675598 -0.340489,0.817175 -11.1680536,26.183638 -0.817175,1.872692 2.076986,0 54.7506996,0 2.07698,0 -0.81717,-1.872692 -11.16805,-26.183638 -0.34049,-0.817175 -0.91933,0 -32.414586,0 -0.919322,0 z m 1.838643,2.723916 6.196908,0 -2.928209,10.418977 -7.729111,0 4.460412,-10.418977 z m 9.02297,0 4.903049,0 0,10.418977 -7.831258,0 2.928209,-10.418977 z m 7.626964,0 5.584031,0 2.62176,10.418977 -8.205791,0 0,-10.418977 z m 8.410081,0 5.51593,0 4.46042,10.418977 -7.38863,0 -2.58772,-10.418977 z m -30.678091,13.142892 8.103649,0 -2.89416,10.282782 -9.6018026,0 4.3923136,-10.282782 z m 10.929711,0 8.614384,0 0,10.282782 -11.508544,0 2.89416,-10.282782 z m 11.338299,0 8.852721,0 2.58772,10.282782 -11.440441,0 0,-10.282782 z m 11.678781,0 7.86531,0 4.39231,10.282782 -9.6699,0 -2.58772,-10.282782 z",h=function(e,t,r){e=a(e);var i=new s(t,r);i._globePath=l,i._flatMapPath=u,i._columbusViewPath=c;var h=document.createElement("span");h.className="cesium-sceneModePicker-wrapper cesium-toolbar-button",e.appendChild(h);var d=document.createElement("button");d.type="button",d.className="cesium-button cesium-toolbar-button",d.setAttribute("data-bind",'css: { "cesium-sceneModePicker-button2D": sceneMode === _sceneMode.SCENE2D, "cesium-sceneModePicker-button3D": sceneMode === _sceneMode.SCENE3D, "cesium-sceneModePicker-buttonColumbusView": sceneMode === _sceneMode.COLUMBUS_VIEW, "cesium-sceneModePicker-selected": dropDownVisible },attr: { title: selectedTooltip },click: toggleDropDown'),d.innerHTML='<!-- ko cesiumSvgPath: { path: _globePath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon3D" } --><!-- /ko --><!-- ko cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon2D" } --><!-- /ko --><!-- ko cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-iconColumbusView" } --><!-- /ko -->', -h.appendChild(d);var p=document.createElement("button");p.type="button",p.className="cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon",p.setAttribute("data-bind",'css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE3D)) || (!dropDownVisible && (sceneMode === _sceneMode.SCENE3D)), "cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE3D, "cesium-sceneModePicker-hidden" : !dropDownVisible },attr: { title: tooltip3D },click: morphTo3D,cesiumSvgPath: { path: _globePath, width: 64, height: 64 }'),h.appendChild(p);var m=document.createElement("button");m.type="button",m.className="cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon",m.setAttribute("data-bind",'css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE2D)), "cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE2D, "cesium-sceneModePicker-hidden" : !dropDownVisible },attr: { title: tooltip2D },click: morphTo2D,cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64 }'),h.appendChild(m);var f=document.createElement("button");f.type="button",f.className="cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon",f.setAttribute("data-bind",'css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.COLUMBUS_VIEW)) || (!dropDownVisible && (sceneMode === _sceneMode.COLUMBUS_VIEW)), "cesium-sceneModePicker-none" : sceneMode === _sceneMode.COLUMBUS_VIEW, "cesium-sceneModePicker-hidden" : !dropDownVisible},attr: { title: tooltipColumbusView },click: morphToColumbusView,cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64 }'),h.appendChild(f),o.applyBindings(i,h),this._viewModel=i,this._container=e,this._wrapper=h,this._closeDropDown=function(e){h.contains(e.target)||(i.dropDownVisible=!1)},n.supportsPointerEvents()?document.addEventListener("pointerdown",this._closeDropDown,!0):(document.addEventListener("mousedown",this._closeDropDown,!0),document.addEventListener("touchstart",this._closeDropDown,!0))};return t(h.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),h.prototype.isDestroyed=function(){return!1},h.prototype.destroy=function(){return this._viewModel.destroy(),n.supportsPointerEvents()?document.removeEventListener("pointerdown",this._closeDropDown,!0):(document.removeEventListener("mousedown",this._closeDropDown,!0),document.removeEventListener("touchstart",this._closeDropDown,!0)),o.cleanNode(this._wrapper),this._container.removeChild(this._wrapper),r(this)},h}),r("Widgets/SelectionIndicator/SelectionIndicatorViewModel",["../../Core/Cartesian2","../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/EasingFunction","../../Scene/SceneTransforms","../../ThirdParty/knockout"],function(e,t,r,i,n,o,a,s){"use strict";var l=new e,u="-1000px",c=function(e,i,n){this._scene=e,this._screenPositionX=u,this._screenPositionY=u,this._tweens=e.tweens,this._container=t(n,document.body),this._selectionIndicatorElement=i,this._scale=1,this.position=void 0,this.showSelection=!1,s.track(this,["position","_screenPositionX","_screenPositionY","_scale","showSelection"]),this.isVisible=void 0,s.defineProperty(this,"isVisible",{get:function(){return this.showSelection&&r(this.position)}}),s.defineProperty(this,"_transform",{get:function(){return"scale("+this._scale+")"}}),this.computeScreenSpacePosition=function(t,r){return a.wgs84ToWindowCoordinates(e,t,r)}};return c.prototype.update=function(){if(this.showSelection&&r(this.position)){var e=this.computeScreenSpacePosition(this.position,l);if(r(e)){var t=this._container,i=t.parentNode.clientWidth,n=t.parentNode.clientHeight,o=this._selectionIndicatorElement.clientWidth,a=.5*o;e.x=Math.min(Math.max(e.x,-o),i+o)-a,e.y=Math.min(Math.max(e.y,-o),n+o)-a,this._screenPositionX=Math.floor(e.x+.25)+"px",this._screenPositionY=Math.floor(e.y+.25)+"px"}else this._screenPositionX=u,this._screenPositionY=u}},c.prototype.animateAppear=function(){this._tweens.addProperty({object:this,property:"_scale",startValue:2,stopValue:1,duration:.8,easingFunction:o.EXPONENTIAL_OUT})},c.prototype.animateDepart=function(){this._tweens.addProperty({object:this,property:"_scale",startValue:this._scale,stopValue:1.5,duration:.8,easingFunction:o.EXPONENTIAL_OUT})},i(c.prototype,{container:{get:function(){return this._container}},selectionIndicatorElement:{get:function(){return this._selectionIndicatorElement}},scene:{get:function(){return this._scene}}}),c}),r("Widgets/SelectionIndicator/SelectionIndicator",["../../Core/defined","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../ThirdParty/knockout","../getElement","./SelectionIndicatorViewModel"],function(e,t,r,i,n,o,a){"use strict";var s=function(e,t){e=o(e),this._container=e;var r=document.createElement("div");r.className="cesium-selection-wrapper",r.setAttribute("data-bind",'style: { "top" : _screenPositionY, "left" : _screenPositionX },css: { "cesium-selection-wrapper-visible" : isVisible }'),e.appendChild(r),this._element=r;var i="http://www.w3.org/2000/svg",s="M -34 -34 L -34 -11.25 L -30 -15.25 L -30 -30 L -15.25 -30 L -11.25 -34 L -34 -34 z M 11.25 -34 L 15.25 -30 L 30 -30 L 30 -15.25 L 34 -11.25 L 34 -34 L 11.25 -34 z M -34 11.25 L -34 34 L -11.25 34 L -15.25 30 L -30 30 L -30 15.25 L -34 11.25 z M 34 11.25 L 30 15.25 L 30 30 L 15.25 30 L 11.25 34 L 34 34 L 34 11.25 z",l=document.createElementNS(i,"svg:svg");l.setAttribute("width",160),l.setAttribute("height",160),l.setAttribute("viewBox","0 0 160 160");var u=document.createElementNS(i,"g");u.setAttribute("transform","translate(80,80)"),l.appendChild(u);var c=document.createElementNS(i,"path");c.setAttribute("data-bind","attr: { transform: _transform }"),c.setAttribute("d",s),u.appendChild(c),r.appendChild(l);var h=new a(t,this._element,this._container);this._viewModel=h,n.applyBindings(this._viewModel,this._element)};return t(s.prototype,{container:{get:function(){return this._container}},viewModel:{get:function(){return this._viewModel}}}),s.prototype.isDestroyed=function(){return!1},s.prototype.destroy=function(){var e=this._container;return n.cleanNode(this._element),e.removeChild(this._element),r(this)},s}),r("Widgets/Timeline/TimelineHighlightRange",["../../Core/defaultValue","../../Core/JulianDate"],function(e,t){"use strict";function r(t,r,i){this._color=t,this._height=r,this._base=e(i,0)}return r.prototype.getHeight=function(){return this._height},r.prototype.getBase=function(){return this._base},r.prototype.getStartTime=function(){return this._start},r.prototype.getStopTime=function(){return this._stop},r.prototype.setRange=function(e,t){this._start=e,this._stop=t},r.prototype.render=function(e){var r="";if(this._start&&this._stop&&this._color){var i=t.secondsDifference(this._start,e.epochJulian),n=Math.round(e.timeBarWidth*e.getAlpha(i)),o=t.secondsDifference(this._stop,e.epochJulian),a=Math.round(e.timeBarWidth*e.getAlpha(o))-n;0>n&&(a+=n,n=0),n+a>e.timeBarWidth&&(a=e.timeBarWidth-n),a>0&&(r='<span class="cesium-timeline-highlight" style="left: '+n.toString()+"px; width: "+a.toString()+"px; bottom: "+this._base.toString()+"px; height: "+this._height+"px; background-color: "+this._color+';"></span>')}return r},r}),r("Widgets/Timeline/TimelineTrack",["../../Core/Color","../../Core/defined","../../Core/JulianDate"],function(e,t,r){"use strict";function i(t,r,i,n){this.interval=t,this.height=r,this.color=i||new e(.5,.5,.5,1),this.backgroundColor=n||new e(0,0,0,0)}return i.prototype.render=function(e,i){var n=this.interval.start,o=this.interval.stop,a=i.startJulian,s=r.addSeconds(i.startJulian,i.duration,new r);if(r.lessThan(n,a)&&r.greaterThan(o,s))e.fillStyle=this.color.toCssColorString(),e.fillRect(0,i.y,i.timeBarWidth,this.height);else if(r.lessThanOrEquals(n,s)&&r.greaterThanOrEquals(o,a)){var l,u,c;for(l=0;l<i.timeBarWidth;++l){var h=r.addSeconds(i.startJulian,l/i.timeBarWidth*i.duration,new r);!t(u)&&r.greaterThanOrEquals(h,n)?u=l:!t(c)&&r.greaterThanOrEquals(h,o)&&(c=l)}e.fillStyle=this.backgroundColor.toCssColorString(),e.fillRect(0,i.y,i.timeBarWidth,this.height),t(u)&&(t(c)||(c=i.timeBarWidth),e.fillStyle=this.color.toCssColorString(),e.fillRect(u,i.y,Math.max(c-u,1),this.height))}},i}),r("Widgets/Timeline/Timeline",["../../Core/ClockRange","../../Core/defined","../../Core/destroyObject","../../Core/DeveloperError","../../Core/JulianDate","../getElement","./TimelineHighlightRange","./TimelineTrack"],function(e,t,r,i,n,o,a,s){"use strict";function l(e){return 10>e?"0"+e.toString():e.toString()}function u(e){return function(t){e._mouseMode!==_.touchOnly&&(0===t.button?(e._mouseMode=_.scrub,e._scrubElement&&(e._scrubElement.style.backgroundPosition="-16px 0"),e._onMouseMove(t)):(e._mouseX=t.clientX,2===t.button?e._mouseMode=_.zoom:e._mouseMode=_.slide)),t.preventDefault()}}function c(e){return function(t){e._mouseMode=_.none,e._scrubElement&&(e._scrubElement.style.backgroundPosition="0px 0px"),e._timelineDrag=0,e._timelineDragLocation=void 0}}function h(e){return function(t){var r;if(e._mouseMode===_.scrub){t.preventDefault();var i=t.clientX-e._topDiv.getBoundingClientRect().left;0>i?(e._timelineDragLocation=0,e._timelineDrag=-.01*e._timeBarSecondsSpan):i>e._topDiv.clientWidth?(e._timelineDragLocation=e._topDiv.clientWidth,e._timelineDrag=.01*e._timeBarSecondsSpan):(e._timelineDragLocation=void 0,e._setTimeBarTime(i,i*e._timeBarSecondsSpan/e._topDiv.clientWidth))}else if(e._mouseMode===_.slide){if(r=e._mouseX-t.clientX,e._mouseX=t.clientX,0!==r){var o=r*e._timeBarSecondsSpan/e._topDiv.clientWidth;e.zoomTo(n.addSeconds(e._startJulian,o,new n),n.addSeconds(e._endJulian,o,new n))}}else e._mouseMode===_.zoom&&(r=e._mouseX-t.clientX,e._mouseX=t.clientX,0!==r&&e.zoomFrom(Math.pow(1.01,r)))}}function d(e){return function(t){var r=t.wheelDeltaY||t.wheelDelta||-t.detail;v=Math.max(Math.min(Math.abs(r),v),1),r/=v,e.zoomFrom(Math.pow(1.05,-r))}}function p(e){return function(t){var r,i,o=t.touches.length,a=e._topDiv.getBoundingClientRect().left;t.preventDefault(),e._mouseMode=_.touchOnly,1===o?(r=n.secondsDifference(e._scrubJulian,e._startJulian),i=Math.round(r*e._topDiv.clientWidth/e._timeBarSecondsSpan+a),Math.abs(t.touches[0].clientX-i)<50?(e._touchMode=g.scrub,e._scrubElement&&(e._scrubElement.style.backgroundPosition=1===o?"-16px 0":"0 0")):(e._touchMode=g.singleTap,e._touchState.centerX=t.touches[0].clientX-a)):2===o?(e._touchMode=g.slideZoom,e._touchState.centerX=.5*(t.touches[0].clientX+t.touches[1].clientX)-a,e._touchState.spanX=Math.abs(t.touches[0].clientX-t.touches[1].clientX)):e._touchMode=g.ignore}}function m(e){return function(t){var r=t.touches.length,i=e._topDiv.getBoundingClientRect().left;e._touchMode===g.singleTap?(e._touchMode=g.scrub,e._handleTouchMove(t)):e._touchMode===g.scrub&&e._handleTouchMove(t),e._mouseMode=_.touchOnly,1!==r?e._touchMode=r>0?g.ignore:g.none:e._touchMode===g.slideZoom&&(e._touchState.centerX=t.touches[0].clientX-i),e._scrubElement&&(e._scrubElement.style.backgroundPosition="0 0")}}function f(e){return function(r){var i,o,a,s,l,u,c=1,h=e._topDiv.getBoundingClientRect().left;e._touchMode===g.singleTap&&(e._touchMode=g.slideZoom),e._mouseMode=_.touchOnly,e._touchMode===g.scrub?(r.preventDefault(),1===r.changedTouches.length&&(o=r.changedTouches[0].clientX-h,o>=0&&o<=e._topDiv.clientWidth&&e._setTimeBarTime(o,o*e._timeBarSecondsSpan/e._topDiv.clientWidth))):e._touchMode===g.slideZoom&&(a=r.touches.length,2===a?(s=.5*(r.touches[0].clientX+r.touches[1].clientX)-h,l=Math.abs(r.touches[0].clientX-r.touches[1].clientX)):1===a&&(s=r.touches[0].clientX-h,l=0),t(s)&&(l>0&&e._touchState.spanX>0?(c=e._touchState.spanX/l,u=n.addSeconds(e._startJulian,(e._touchState.centerX*e._timeBarSecondsSpan-s*e._timeBarSecondsSpan*c)/e._topDiv.clientWidth,new n)):(i=e._touchState.centerX-s,u=n.addSeconds(e._startJulian,i*e._timeBarSecondsSpan/e._topDiv.clientWidth,new n)),e.zoomTo(u,n.addSeconds(u,e._timeBarSecondsSpan*c,new n)),e._touchState.centerX=s,e._touchState.spanX=l))}}var v=1e12,_={none:0,scrub:1,slide:2,zoom:3,touchOnly:4},g={none:0,scrub:1,slideZoom:2,singleTap:3,ignore:4},y=[.001,.002,.005,.01,.02,.05,.1,.25,.5,1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,21600,43200,86400,172800,345600,604800,1296e3,2592e3,5184e3,7776e3,15552e3,31536e3,63072e3,126144e3,15768e4,31536e4,63072e4,126144e4,15768e5,31536e5,63072e5,126144e5,15768e6,31536e6],C=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],E=function(e,t){e=o(e),this.container=e;var r=document.createElement("div");r.className="cesium-timeline-main",e.appendChild(r),this._topDiv=r,this._endJulian=void 0,this._epochJulian=void 0,this._lastXPos=void 0,this._scrubElement=void 0,this._startJulian=void 0,this._timeBarSecondsSpan=void 0,this._clock=t,this._scrubJulian=t.currentTime,this._mainTicSpan=-1,this._mouseMode=_.none,this._touchMode=g.none,this._touchState={centerX:0,spanX:0},this._mouseX=0,this._timelineDrag=0,this._timelineDragLocation=void 0,this._lastHeight=void 0,this._lastWidth=void 0,this._topDiv.innerHTML='<div class="cesium-timeline-bar"></div><div class="cesium-timeline-trackContainer"><canvas class="cesium-timeline-tracks" width="10" height="1"></canvas></div><div class="cesium-timeline-needle"></div><span class="cesium-timeline-ruler"></span>',this._timeBarEle=this._topDiv.childNodes[0],this._trackContainer=this._topDiv.childNodes[1],this._trackListEle=this._topDiv.childNodes[1].childNodes[0],this._needleEle=this._topDiv.childNodes[2],this._rulerEle=this._topDiv.childNodes[3],this._context=this._trackListEle.getContext("2d"),this._trackList=[],this._highlightRanges=[],this.zoomTo(t.startTime,t.stopTime),this._onMouseDown=u(this),this._onMouseUp=c(this),this._onMouseMove=h(this),this._onMouseWheel=d(this),this._onTouchStart=p(this),this._onTouchMove=f(this),this._onTouchEnd=m(this);var i=this._timeBarEle;document.addEventListener("mouseup",this._onMouseUp,!1),document.addEventListener("mousemove",this._onMouseMove,!1),i.addEventListener("mousedown",this._onMouseDown,!1),i.addEventListener("DOMMouseScroll",this._onMouseWheel,!1),i.addEventListener("mousewheel",this._onMouseWheel,!1),i.addEventListener("touchstart",this._onTouchStart,!1),i.addEventListener("touchmove",this._onTouchMove,!1),i.addEventListener("touchend",this._onTouchEnd,!1),this._topDiv.oncontextmenu=function(){return!1},t.onTick.addEventListener(this.updateFromClock,this),this.updateFromClock()};return E.prototype.addEventListener=function(e,t,r){this._topDiv.addEventListener(e,t,r)},E.prototype.removeEventListener=function(e,t,r){this._topDiv.removeEventListener(e,t,r)},E.prototype.isDestroyed=function(){return!1},E.prototype.destroy=function(){this._clock.onTick.removeEventListener(this.updateFromClock,this),document.removeEventListener("mouseup",this._onMouseUp,!1),document.removeEventListener("mousemove",this._onMouseMove,!1);var e=this._timeBarEle;e.removeEventListener("mousedown",this._onMouseDown,!1),e.removeEventListener("DOMMouseScroll",this._onMouseWheel,!1),e.removeEventListener("mousewheel",this._onMouseWheel,!1),e.removeEventListener("touchstart",this._onTouchStart,!1),e.removeEventListener("touchmove",this._onTouchMove,!1),e.removeEventListener("touchend",this._onTouchEnd,!1),this.container.removeChild(this._topDiv),r(this)},E.prototype.addHighlightRange=function(e,t,r){var i=new a(e,t,r);return this._highlightRanges.push(i),this.resize(),i},E.prototype.addTrack=function(e,t,r,i){var n=new s(e,t,r,i);return this._trackList.push(n),this._lastHeight=void 0,this.resize(),n},E.prototype.zoomTo=function(t,r){if(this._startJulian=t,this._endJulian=r,this._timeBarSecondsSpan=n.secondsDifference(r,t),this._clock&&this._clock.clockRange!==e.UNBOUNDED){var i=this._clock.startTime,o=this._clock.stopTime,a=n.secondsDifference(o,i),s=n.secondsDifference(i,this._startJulian),l=n.secondsDifference(o,this._endJulian);this._timeBarSecondsSpan>=a?(this._timeBarSecondsSpan=a,this._startJulian=this._clock.startTime,this._endJulian=this._clock.stopTime):s>0?(this._endJulian=n.addSeconds(this._endJulian,s,new n),this._startJulian=i,this._timeBarSecondsSpan=n.secondsDifference(this._endJulian,this._startJulian)):0>l&&(this._startJulian=n.addSeconds(this._startJulian,l,new n),this._endJulian=o,this._timeBarSecondsSpan=n.secondsDifference(this._endJulian,this._startJulian))}this._makeTics();var u=document.createEvent("Event");u.initEvent("setzoom",!0,!0),u.startJulian=this._startJulian,u.endJulian=this._endJulian,u.epochJulian=this._epochJulian,u.totalSpan=this._timeBarSecondsSpan,u.mainTicSpan=this._mainTicSpan,this._topDiv.dispatchEvent(u)},E.prototype.zoomFrom=function(e){var t=n.secondsDifference(this._scrubJulian,this._startJulian);e>1||0>t||t>this._timeBarSecondsSpan?t=.5*this._timeBarSecondsSpan:t+=t-.5*this._timeBarSecondsSpan;var r=this._timeBarSecondsSpan-t;this.zoomTo(n.addSeconds(this._startJulian,t-t*e,new n),n.addSeconds(this._endJulian,r*e-r,new n))},E.prototype.makeLabel=function(e){var t=n.toGregorianDate(e),r=t.millisecond,i=" UTC";if(r>0&&this._timeBarSecondsSpan<3600){for(i=Math.floor(r).toString();i.length<3;)i="0"+i;i="."+i}return C[t.month-1]+" "+t.day+" "+t.year+" "+l(t.hour)+":"+l(t.minute)+":"+l(t.second)+i},E.prototype.smallestTicInPixels=7,E.prototype._makeTics=function(){function e(e){return Math.floor(S/e)*e}function t(e,t){return Math.ceil(e/t+.5)*t}function r(e){return(e-S)/v}function i(e,t){return e-t*Math.round(e/t)}var o,a=this._timeBarEle,s=n.secondsDifference(this._scrubJulian,this._startJulian),l=Math.round(s*this._topDiv.clientWidth/this._timeBarSecondsSpan),u=l-8,c=this;this._needleEle.style.left=l.toString()+"px";var h="",d=.01,p=31536e6,m=1e-10,f=0,v=this._timeBarSecondsSpan;d>v?(v=d,this._timeBarSecondsSpan=d,this._endJulian=n.addSeconds(this._startJulian,d,new n)):v>p&&(v=p,this._timeBarSecondsSpan=p,this._endJulian=n.addSeconds(this._startJulian,p,new n));var _=this._timeBarEle.clientWidth;10>_&&(_=10);var g,C=this._startJulian,E=Math.min(v/_*1e-5,.4);g=v>31536e4?n.fromIso8601(n.toDate(C).toISOString().substring(0,2)+"00-01-01T00:00:00Z"):v>31536e3?n.fromIso8601(n.toDate(C).toISOString().substring(0,3)+"0-01-01T00:00:00Z"):v>86400?n.fromIso8601(n.toDate(C).toISOString().substring(0,4)+"-01-01T00:00:00Z"):n.fromIso8601(n.toDate(C).toISOString().substring(0,10)+"T00:00:00Z");var S=n.secondsDifference(this._startJulian,n.addSeconds(g,E,new n)),w=S+v;this._epochJulian=g,this._rulerEle.innerHTML=this.makeLabel(n.addSeconds(this._endJulian,-d,new n));var T=this._rulerEle.offsetWidth+20;30>T&&(T=180);var b=f;f-=m;var x={startTime:S,startJulian:C,epochJulian:g,duration:v,timeBarWidth:_,getAlpha:r};this._highlightRanges.forEach(function(e){h+=e.render(x)});var P=0,A=0,I=0,M=T/_;M>1&&(M=1),M*=this._timeBarSecondsSpan;var D,R=-1,O=-1,N=y.length;for(D=0;N>D;++D){var L=y[D];if(++R,P=L,L>M&&L>f)break;0>O&&_*(L/this._timeBarSecondsSpan)>=this.smallestTicInPixels&&(O=R)}if(R>0){for(;R>0;)if(--R,Math.abs(i(P,y[R]))<1e-5){y[R]>=f&&(A=y[R]);break}if(O>=0)for(;R>O;){if(Math.abs(i(A,y[O]))<1e-5&&y[O]>=f){I=y[O];break}++O}}f=b,f>m&&1e-5>I&&Math.abs(f-P)>m&&(I=f,P+m>=f&&(A=0));var F,B=-999999;if(_*(I/this._timeBarSecondsSpan)>=3)for(o=e(I);w>=o;o=t(o,I))h+='<span class="cesium-timeline-ticTiny" style="left: '+Math.round(_*r(o)).toString()+'px;"></span>';if(_*(A/this._timeBarSecondsSpan)>=3)for(o=e(A);w>=o;o=t(o,A))h+='<span class="cesium-timeline-ticSub" style="left: '+Math.round(_*r(o)).toString()+'px;"></span>';if(_*(P/this._timeBarSecondsSpan)>=2){this._mainTicSpan=P,w+=P,o=e(P);for(var V=n.computeTaiMinusUtc(g);w>=o;){var z=n.addSeconds(C,o-S,new n);if(P>2.1){var k=n.computeTaiMinusUtc(z);Math.abs(k-V)>.1&&(o+=k-V,z=n.addSeconds(C,o-S,new n))}var U=Math.round(_*r(o)),G=this.makeLabel(z);this._rulerEle.innerHTML=G,F=this._rulerEle.offsetWidth,10>F&&(F=T);var W=U-(F/2-1);W>B?(B=W+F+5,h+='<span class="cesium-timeline-ticMain" style="left: '+U.toString()+'px;"></span><span class="cesium-timeline-ticLabel" style="left: '+W.toString()+'px;">'+G+"</span>"):h+='<span class="cesium-timeline-ticSub" style="left: '+U.toString()+'px;"></span>',o=t(o,P)}}else this._mainTicSpan=-1;h+='<span class="cesium-timeline-icon16" style="left:'+u+'px;bottom:0;background-position: 0px 0px;"></span>',a.innerHTML=h,this._scrubElement=a.lastChild,this._context.clearRect(0,0,this._trackListEle.width,this._trackListEle.height),x.y=0,this._trackList.forEach(function(e){e.render(c._context,x),x.y+=e.height})},E.prototype.updateFromClock=function(){this._scrubJulian=this._clock.currentTime;var e=this._scrubElement;if(t(this._scrubElement)){var r=n.secondsDifference(this._scrubJulian,this._startJulian),i=Math.round(r*this._topDiv.clientWidth/this._timeBarSecondsSpan);this._lastXPos!==i&&(this._lastXPos=i,e.style.left=i-8+"px",this._needleEle.style.left=i+"px")}t(this._timelineDragLocation)&&(this._setTimeBarTime(this._timelineDragLocation,this._timelineDragLocation*this._timeBarSecondsSpan/this._topDiv.clientWidth),this.zoomTo(n.addSeconds(this._startJulian,this._timelineDrag,new n),n.addSeconds(this._endJulian,this._timelineDrag,new n)))},E.prototype._setTimeBarTime=function(e,t){if(e=Math.round(e),this._scrubJulian=n.addSeconds(this._startJulian,t,new n),this._scrubElement){var r=e-8;this._scrubElement.style.left=r.toString()+"px",this._needleEle.style.left=e.toString()+"px"}var i=document.createEvent("Event");i.initEvent("settime",!0,!0),i.clientX=e,i.timeSeconds=t,i.timeJulian=this._scrubJulian,i.clock=this._clock,this._topDiv.dispatchEvent(i)},E.prototype.resize=function(){var e=this.container.clientWidth,t=this.container.clientHeight;if(e!==this._lastWidth||t!==this._lastHeight){this._trackContainer.style.height=t+"px";var r=1;this._trackList.forEach(function(e){r+=e.height}),this._trackListEle.style.height=r.toString()+"px",this._trackListEle.width=this._trackListEle.clientWidth,this._trackListEle.height=r,this._makeTics(),this._lastWidth=e,this._lastHeight=t}},E}),r("Widgets/Viewer/Viewer",["../../Core/BoundingSphere","../../Core/Cartesian3","../../Core/defaultValue","../../Core/defined","../../Core/definedNotNull","../../Core/defineProperties","../../Core/destroyObject","../../Core/DeveloperError","../../Core/EventHelper","../../Core/isArray","../../Core/Matrix4","../../Core/ScreenSpaceEventType","../../DataSources/BoundingSphereState","../../DataSources/ConstantPositionProperty","../../DataSources/DataSourceCollection","../../DataSources/DataSourceDisplay","../../DataSources/Entity","../../DataSources/EntityView","../../DataSources/Property","../../Scene/SceneMode","../../ThirdParty/knockout","../../ThirdParty/when","../Animation/Animation","../Animation/AnimationViewModel","../BaseLayerPicker/BaseLayerPicker","../BaseLayerPicker/createDefaultImageryProviderViewModels","../BaseLayerPicker/createDefaultTerrainProviderViewModels","../CesiumWidget/CesiumWidget","../ClockViewModel","../FullscreenButton/FullscreenButton","../Geocoder/Geocoder","../getElement","../HomeButton/HomeButton","../InfoBox/InfoBox","../NavigationHelpButton/NavigationHelpButton","../SceneModePicker/SceneModePicker","../SelectionIndicator/SelectionIndicator","../subscribeAndEvaluate","../Timeline/Timeline"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V){"use strict";function z(e){var t=e.clock;t.currentTime=e.timeJulian,t.shouldAnimate=!1}function k(e,t){var n=e.scene.pick(t.position);if(i(n)){var o=r(n.id,n.primitive.id);if(o instanceof v)return o}return i(e.scene.globe)?G(e,t.position):void 0}function U(e,t,r){if(i(r)){var n=r.clock;i(n)&&(n.getValue(t),i(e)&&(e.updateFromClock(),e.zoomTo(n.startTime,n.stopTime)))}}function G(e,t){var r=e.scene,n=r.camera.getPickRay(t),o=r.imageryLayers.pickImageryLayerFeatures(n,r);if(i(o)){var a=new v({id:"Loading...",description:"Loading feature information..."});return E(o,function(t){if(e.selectedEntity===a){if(!i(t)||0===t.length)return void(e.selectedEntity=W());var r=t[0],n=new v({id:r.name,description:r.description});if(i(r.position)){var o=e.scene.globe.ellipsoid.cartographicToCartesian(r.position,K);n.position=new p(o)}e.selectedEntity=n}},function(){e.selectedEntity===a&&(e.selectedEntity=W())}),a}}function W(){return new v({id:"None",description:"No features found."})}function H(e,t,n,o){j(e);var a=E.defer();return e._zoomPromise=a,e._zoomIsFlight=o,e._zoomOptions=n,E(t,function(t){if(e._zoomPromise===a)if(t.isLoading&&i(t.loadingEvent))var n=t.loadingEvent.addEventListener(function(){n(),e._zoomPromise===a&&(e._zoomTarget=t.entities.values.slice(0))});else t=r(t.values,t),i(t.entities)&&(t=t.entities.values),u(t)?e._zoomTarget=t.slice(0):e._zoomTarget=[t]}),a.promise}function q(e){e._zoomPromise=void 0,e._zoomTarget=void 0,e._zoomOptions=void 0}function j(e){var t=e._zoomPromise;i(t)&&(q(e),t.resolve(!1))}function Y(t){var n=t._zoomTarget;if(i(n)&&t.scene.mode!==y.MORPHING){for(var o=t._zoomPromise,a=[],s=0,l=n.length;l>s;s++){var u=t._dataSourceDisplay.getBoundingSphere(n[s],!1,Z);if(u===d.PENDING)return;u!==d.FAILED&&a.push(e.clone(Z))}if(0===a.length)return void j(t);t.trackedEntity=void 0;var h=t.scene,p=h.camera,m=e.fromBoundingSpheres(a),f=h.screenSpaceCameraController;if(f.minimumZoomDistance=Math.min(f.minimumZoomDistance,.5*m.radius),t._zoomIsFlight){var v=r(t._zoomOptions,{}),_={duration:v.duration,maximumHeight:v.maximumHeight,complete:function(){o.resolve(!0)},cancel:function(){o.resolve(!1)},offset:v.offset};q(t),p.flyToBoundingSphere(m,_)}else p.viewBoundingSphere(m,t._zoomOptions),p.lookAtTransform(c.IDENTITY),q(t),o.resolve(!0)}}function X(e){if(e._needTrackedEntityUpdate){var t=e._trackedEntity,r=e.clock.currentTime,n=g.getValueOrUndefined(t.position,r);if(i(n)){var o=e.scene,a=e._dataSourceDisplay.getBoundingSphere(t,!1,Z);if(a!==d.PENDING){var s=o.mode;(s===y.COLUMBUS_VIEW||s===y.SCENE2D)&&(o.screenSpaceCameraController.enableTranslate=!1),(s===y.COLUMBUS_VIEW||s===y.SCENE3D)&&(o.screenSpaceCameraController.enableTilt=!1);var l=a!==d.FAILED?Z:void 0;e._entityView=new _(t,o,o.mapProjection.ellipsoid,l),e._entityView.update(r),e._needTrackedEntityUpdate=!1}}}}var Z=new e,K=new t,J=function(e,t){function o(e){var t=k(Ce,e);i(t)&&(g.getValueOrUndefined(t.position,Ce.clock.currentTime)?Ce.trackedEntity=t:Ce.zoomTo(t))}function a(e){Ce.selectedEntity=k(Ce,e)}e=D(e),t=r(t,r.EMPTY_OBJECT);var u=!(i(t.globe)&&t.globe===!1||i(t.baseLayerPicker)&&t.baseLayerPicker===!1),c=document.createElement("div");c.className="cesium-viewer",e.appendChild(c);var d=document.createElement("div");d.className="cesium-viewer-cesiumWidgetContainer",c.appendChild(d);var p=document.createElement("div");p.className="cesium-viewer-bottom",c.appendChild(p);var v=r(t.scene3DOnly,!1),_=new P(d,{terrainProvider:t.terrainProvider,imageryProvider:u?!1:t.imageryProvider,clock:t.clock,skyBox:t.skyBox,skyAtmosphere:t.skyAtmosphere,sceneMode:t.sceneMode,mapProjection:t.mapProjection,globe:t.globe,orderIndependentTranslucency:t.orderIndependentTranslucency,contextOptions:t.contextOptions,useDefaultRenderLoop:t.useDefaultRenderLoop,targetFrameRate:t.targetFrameRate,showRenderLoopErrors:t.showRenderLoopErrors,creditContainer:i(t.creditContainer)?t.creditContainer:p,scene3DOnly:v}),y=t.dataSources,E=!1;i(y)||(y=new m,E=!0);var U=new f({scene:_.scene,dataSourceCollection:y}),G=_.clock,W=new A(G),H=new l;H.add(G.onTick,J.prototype._onTick,this);var q;if(!i(t.selectionIndicator)||t.selectionIndicator!==!1){var j=document.createElement("div");j.className="cesium-viewer-selectionIndicatorContainer",c.appendChild(j),q=new F(j,_.scene)}var Y;if(!i(t.infoBox)||t.infoBox!==!1){var X=document.createElement("div");X.className="cesium-viewer-infoBoxContainer",c.appendChild(X),Y=new O(X);var Z=Y.viewModel;H.add(Z.cameraClicked,J.prototype._onInfoBoxCameraClicked,this),H.add(Z.closeClicked,J.prototype._onInfoBoxClockClicked,this)}var K=document.createElement("div");K.className="cesium-viewer-toolbar",c.appendChild(K);var Q;if(!i(t.geocoder)||t.geocoder!==!1){var $=document.createElement("div");$.className="cesium-viewer-geocoderContainer",K.appendChild($),Q=new M({container:$,scene:_.scene}),H.add(Q.viewModel.search.beforeExecute,J.prototype._clearObjects,this)}var ee;if(i(t.homeButton)&&t.homeButton===!1||(ee=new R(K,_.scene),i(Q)&&H.add(ee.viewModel.command.afterExecute,function(){var e=Q.viewModel;e.searchText="",e.isSearchInProgress&&e.search()}),H.add(ee.viewModel.command.beforeExecute,J.prototype._clearTrackedObject,this)),t.sceneModePicker===!0&&v)throw new s("options.sceneModePicker is not available when options.scene3DOnly is set to true.");var te;v||i(t.sceneModePicker)&&t.sceneModePicker===!1||(te=new L(K,_.scene));var re,ie;if(u){var ne=r(t.imageryProviderViewModels,b()),oe=r(t.terrainProviderViewModels,x());re=new T(K,{globe:_.scene.globe,imageryProviderViewModels:ne,selectedImageryProviderViewModel:t.selectedImageryProviderViewModel,terrainProviderViewModels:oe,selectedTerrainProviderViewModel:t.selectedTerrainProviderViewModel});var ae=K.getElementsByClassName("cesium-baseLayerPicker-dropDown");ie=ae[0]}var se;if(!i(t.navigationHelpButton)||t.navigationHelpButton!==!1){var le=!0;try{if(n(window.localStorage)){var ue=window.localStorage.getItem("cesium-hasSeenNavHelp");i(ue)&&Boolean(ue)?le=!1:window.localStorage.setItem("cesium-hasSeenNavHelp","true")}}catch(ce){}se=new N({container:K,instructionsInitiallyVisible:r(t.navigationInstructionsInitiallyVisible,le)})}var he;if(!i(t.animation)||t.animation!==!1){var de=document.createElement("div");de.className="cesium-viewer-animationContainer",c.appendChild(de),he=new S(de,new w(W))}var pe;if(!i(t.timeline)||t.timeline!==!1){var me=document.createElement("div");me.className="cesium-viewer-timelineContainer",c.appendChild(me),pe=new V(me,G),pe.addEventListener("settime",z,!1),pe.zoomTo(G.startTime,G.stopTime)}var fe,ve;if(i(t.fullscreenButton)&&t.fullscreenButton===!1)i(pe)&&(pe.container.style.right=0);else{var _e=document.createElement("div");_e.className="cesium-viewer-fullscreenContainer",c.appendChild(_e),fe=new I(_e,t.fullscreenElement),ve=B(fe.viewModel,"isFullscreenEnabled",function(e){_e.style.display=e?"block":"none",i(pe)&&(pe.container.style.right=_e.clientWidth+"px",pe.resize())})}this._baseLayerPickerDropDown=ie,this._fullscreenSubscription=ve,this._dataSourceChangedListeners={},this._automaticallyTrackDataSourceClocks=r(t.automaticallyTrackDataSourceClocks,!0),this._container=e,this._bottomContainer=p,this._element=c,this._cesiumWidget=_,this._selectionIndicator=q,this._infoBox=Y,this._dataSourceCollection=y,this._destroyDataSourceCollection=E,this._dataSourceDisplay=U,this._clockViewModel=W,this._toolbar=K,this._homeButton=ee,this._sceneModePicker=te,this._baseLayerPicker=re,this._navigationHelpButton=se,this._animation=he,this._timeline=pe,this._fullscreenButton=fe,this._geocoder=Q,this._eventHelper=H,this._lastWidth=0,this._lastHeight=0,this._allowDataSourcesToSuspendAnimation=!0,this._entityView=void 0,this._enableInfoOrSelection=i(Y)||i(q),this._clockTrackedDataSource=void 0,this._trackedEntity=void 0,this._needTrackedEntityUpdate=!1,this._selectedEntity=void 0,this._clockTrackedDataSource=void 0,this._forceResize=!1,this._zoomIsFlight=!1,this._zoomTarget=void 0,this._zoomPromise=void 0,this._zoomOptions=void 0,C.track(this,["_trackedEntity","_selectedEntity","_clockTrackedDataSource"]),H.add(y.dataSourceAdded,J.prototype._onDataSourceAdded,this),H.add(y.dataSourceRemoved,J.prototype._onDataSourceRemoved,this),H.add(_.scene.preRender,J.prototype.resize,this),H.add(_.scene.postRender,J.prototype._postRender,this);for(var ge=y.length,ye=0;ge>ye;ye++)this._dataSourceAdded(y,y.get(ye));this._dataSourceAdded(void 0,U.defaultDataSource),H.add(y.dataSourceAdded,J.prototype._dataSourceAdded,this),H.add(y.dataSourceRemoved,J.prototype._dataSourceRemoved,this);var Ce=this; -_.screenSpaceEventHandler.setInputAction(a,h.LEFT_CLICK),_.screenSpaceEventHandler.setInputAction(o,h.LEFT_DOUBLE_CLICK)};return o(J.prototype,{container:{get:function(){return this._container}},bottomContainer:{get:function(){return this._bottomContainer}},cesiumWidget:{get:function(){return this._cesiumWidget}},selectionIndicator:{get:function(){return this._selectionIndicator}},infoBox:{get:function(){return this._infoBox}},geocoder:{get:function(){return this._geocoder}},homeButton:{get:function(){return this._homeButton}},sceneModePicker:{get:function(){return this._sceneModePicker}},baseLayerPicker:{get:function(){return this._baseLayerPicker}},navigationHelpButton:{get:function(){return this._navigationHelpButton}},animation:{get:function(){return this._animation}},timeline:{get:function(){return this._timeline}},fullscreenButton:{get:function(){return this._fullscreenButton}},dataSourceDisplay:{get:function(){return this._dataSourceDisplay}},entities:{get:function(){return this._dataSourceDisplay.defaultDataSource.entities}},dataSources:{get:function(){return this._dataSourceCollection}},canvas:{get:function(){return this._cesiumWidget.canvas}},cesiumLogo:{get:function(){return this._cesiumWidget.cesiumLogo}},scene:{get:function(){return this._cesiumWidget.scene}},imageryLayers:{get:function(){return this.scene.imageryLayers}},terrainProvider:{get:function(){return this.scene.terrainProvider},set:function(e){this.scene.terrainProvider=e}},camera:{get:function(){return this.scene.camera}},clock:{get:function(){return this._cesiumWidget.clock}},screenSpaceEventHandler:{get:function(){return this._cesiumWidget.screenSpaceEventHandler}},targetFrameRate:{get:function(){return this._cesiumWidget.targetFrameRate},set:function(e){this._cesiumWidget.targetFrameRate=e}},useDefaultRenderLoop:{get:function(){return this._cesiumWidget.useDefaultRenderLoop},set:function(e){this._cesiumWidget.useDefaultRenderLoop=e}},resolutionScale:{get:function(){return this._cesiumWidget.resolutionScale},set:function(e){this._cesiumWidget.resolutionScale=e,this._forceResize=!0}},allowDataSourcesToSuspendAnimation:{get:function(){return this._allowDataSourcesToSuspendAnimation},set:function(e){this._allowDataSourcesToSuspendAnimation=e}},trackedEntity:{get:function(){return this._trackedEntity},set:function(e){if(this._trackedEntity!==e){this._trackedEntity=e,j(this);var t=this.scene,r=t.mode;if(!i(e)||!i(e.position))return this._needTrackedEntityUpdate=!1,(r===y.COLUMBUS_VIEW||r===y.SCENE2D)&&(t.screenSpaceCameraController.enableTranslate=!0),(r===y.COLUMBUS_VIEW||r===y.SCENE3D)&&(t.screenSpaceCameraController.enableTilt=!0),this._entityView=void 0,void this.camera.lookAtTransform(c.IDENTITY);this._needTrackedEntityUpdate=!0}}},selectedEntity:{get:function(){return this._selectedEntity},set:function(e){if(this._selectedEntity!==e){this._selectedEntity=e;var t=i(this._selectionIndicator)?this._selectionIndicator.viewModel:void 0;i(e)?i(t)&&t.animateAppear():i(t)&&t.animateDepart()}}},clockTrackedDataSource:{get:function(){return this._clockTrackedDataSource},set:function(e){this._clockTrackedDataSource!==e&&(this._clockTrackedDataSource=e,U(this._timeline,this.clock,e))}}}),J.prototype.extend=function(e,t){e(this,t)},J.prototype.resize=function(){var e=this._cesiumWidget,t=this._container,r=t.clientWidth,n=t.clientHeight,o=i(this._animation),a=i(this._timeline);if(this._forceResize||r!==this._lastWidth||n!==this._lastHeight){e.resize(),this._forceResize=!1;var s=n-125,l=this._baseLayerPickerDropDown;i(l)&&(l.style.maxHeight=s+"px"),i(this._infoBox)&&(this._infoBox.viewModel.maxHeight=s);var u,c=this._timeline,h=0,d=0,p=0;if(o&&"hidden"!==window.getComputedStyle(this._animation.container).visibility){var m=this._lastWidth;u=this._animation.container,r>900?(h=169,900>=m&&(u.style.width="169px",u.style.height="112px",this._animation.resize())):r>=600?(h=136,(600>m||m>900)&&(u.style.width="136px",u.style.height="90px",this._animation.resize())):(h=106,(m>600||0===m)&&(u.style.width="106px",u.style.height="70px",this._animation.resize())),d=h+5}if(a&&"hidden"!==window.getComputedStyle(this._timeline.container).visibility){var f=this._fullscreenButton,v=c.container,_=v.style;p=v.clientHeight+3,_.left=h+"px",i(f)&&(_.right=f.container.clientWidth+"px"),c.resize()}this._bottomContainer.style.left=d+"px",this._bottomContainer.style.bottom=p+"px",this._lastWidth=r,this._lastHeight=n}},J.prototype.forceResize=function(){this._lastWidth=0,this.resize()},J.prototype.render=function(){this._cesiumWidget.render()},J.prototype.isDestroyed=function(){return!1},J.prototype.destroy=function(){var e;this.screenSpaceEventHandler.removeInputAction(h.LEFT_CLICK),this.screenSpaceEventHandler.removeInputAction(h.LEFT_DOUBLE_CLICK);var t=this.dataSources,r=t.length;for(e=0;r>e;e++)this._dataSourceRemoved(t,t.get(e));return this._dataSourceRemoved(void 0,this._dataSourceDisplay.defaultDataSource),this._container.removeChild(this._element),this._element.removeChild(this._toolbar),this._eventHelper.removeAll(),i(this._geocoder)&&(this._geocoder=this._geocoder.destroy()),i(this._homeButton)&&(this._homeButton=this._homeButton.destroy()),i(this._sceneModePicker)&&(this._sceneModePicker=this._sceneModePicker.destroy()),i(this._baseLayerPicker)&&(this._baseLayerPicker=this._baseLayerPicker.destroy()),i(this._animation)&&(this._element.removeChild(this._animation.container),this._animation=this._animation.destroy()),i(this._timeline)&&(this._timeline.removeEventListener("settime",z,!1),this._element.removeChild(this._timeline.container),this._timeline=this._timeline.destroy()),i(this._fullscreenButton)&&(this._fullscreenSubscription.dispose(),this._element.removeChild(this._fullscreenButton.container),this._fullscreenButton=this._fullscreenButton.destroy()),i(this._infoBox)&&(this._element.removeChild(this._infoBox.container),this._infoBox=this._infoBox.destroy()),i(this._selectionIndicator)&&(this._element.removeChild(this._selectionIndicator.container),this._selectionIndicator=this._selectionIndicator.destroy()),this._clockViewModel=this._clockViewModel.destroy(),this._dataSourceDisplay=this._dataSourceDisplay.destroy(),this._cesiumWidget=this._cesiumWidget.destroy(),this._destroyDataSourceCollection&&(this._dataSourceCollection=this._dataSourceCollection.destroy()),a(this)},J.prototype._dataSourceAdded=function(e,t){var r=t.entities;r.collectionChanged.addEventListener(J.prototype._onEntityCollectionChanged,this)},J.prototype._dataSourceRemoved=function(e,t){var r=t.entities;r.collectionChanged.removeEventListener(J.prototype._onEntityCollectionChanged,this),i(this.trackedEntity)&&r.getById(this.trackedEntity.id)===this.trackedEntity&&(this.trackedEntity=void 0),i(this.selectedEntity)&&r.getById(this.selectedEntity.id)===this.selectedEntity&&(this.selectedEntity=void 0)},J.prototype._onTick=function(e){var n=e.currentTime,o=this._dataSourceDisplay.update(n);this._allowDataSourcesToSuspendAnimation&&(this._clockViewModel.canAnimate=o);var a=this._entityView;i(a)&&a.update(n);var s,l=!1,u=this.selectedEntity,c=i(u)&&this._enableInfoOrSelection;if(c&&u.isShowing&&u.isAvailable(n)){var h=this._dataSourceDisplay.getBoundingSphere(u,!0,Z);h!==d.FAILED?s=Z.center:i(u.position)&&(s=u.position.getValue(n,s)),l=i(s)}var p=i(this._selectionIndicator)?this._selectionIndicator.viewModel:void 0;i(p)&&(p.position=t.clone(s,p.position),p.showSelection=c&&l,p.update());var m=i(this._infoBox)?this._infoBox.viewModel:void 0;i(m)&&(m.showInfo=c,m.enableCamera=l,m.isCameraTracking=this.trackedEntity===this.selectedEntity,c?(m.titleText=r(u.name,u.id),m.description=g.getValueOrDefault(u.description,n,"")):(m.titleText="",m.description=""))},J.prototype._onEntityCollectionChanged=function(e,t,r){for(var i=r.length,n=0;i>n;n++){var o=r[n];this.trackedEntity===o&&(this.trackedEntity=void 0),this.selectedEntity===o&&(this.selectedEntity=void 0)}},J.prototype._onInfoBoxCameraClicked=function(e){if(e.isCameraTracking&&this.trackedEntity===this.selectedEntity)this.trackedEntity=void 0;else{var t=this.selectedEntity,r=t.position;i(r)?this.trackedEntity=this.selectedEntity:this.zoomTo(this.selectedEntity)}},J.prototype._clearTrackedObject=function(){this.trackedEntity=void 0},J.prototype._onInfoBoxClockClicked=function(e){this.selectedEntity=void 0},J.prototype._clearObjects=function(){this.trackedEntity=void 0,this.selectedEntity=void 0},J.prototype._onDataSourceChanged=function(e){this.clockTrackedDataSource===e&&U(this.timeline,this.clock,e)},J.prototype._onDataSourceAdded=function(e,t){this._automaticallyTrackDataSourceClocks&&(this.clockTrackedDataSource=t);var r=t.entities.id,i=this._eventHelper.add(t.changedEvent,J.prototype._onDataSourceChanged,this);this._dataSourceChangedListeners[r]=i},J.prototype._onDataSourceRemoved=function(e,t){var r=this.clockTrackedDataSource===t,i=t.entities.id;if(this._dataSourceChangedListeners[i](),this._dataSourceChangedListeners[i]=void 0,r){var n=e.length;this._automaticallyTrackDataSourceClocks&&n>0?this.clockTrackedDataSource=e.get(n-1):this.clockTrackedDataSource=void 0}},J.prototype.zoomTo=function(e,t){return H(this,e,t,!1)},J.prototype.flyTo=function(e,t){return H(this,e,t,!0)},J.prototype._postRender=function(){Y(this),X(this)},J}),r("Widgets/Viewer/viewerCesiumInspectorMixin",["../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../CesiumInspector/CesiumInspector"],function(e,t,r,i){"use strict";var n=function(n){if(!e(n))throw new r("viewer is required.");var o=document.createElement("div");o.className="cesium-viewer-cesiumInspectorContainer",n.container.appendChild(o);var a=new i(o,n.scene);t(n,{cesiumInspector:{get:function(){return a}}}),n.scene.postRender.addEventListener(function(){n.cesiumInspector.viewModel.update()})};return n}),r("Widgets/Viewer/viewerDragDropMixin",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../../Core/Event","../../Core/wrapFunction","../../DataSources/CzmlDataSource","../../DataSources/GeoJsonDataSource","../../DataSources/KmlDataSource","../getElement"],function(e,t,r,i,n,o,a,s,l,u){"use strict";function c(e){e.stopPropagation(),e.preventDefault()}function h(e,r){var i=e;t(i)&&(i.removeEventListener("drop",r,!1),i.removeEventListener("dragenter",c,!1),i.removeEventListener("dragover",c,!1),i.removeEventListener("dragexit",c,!1))}function d(e,t){e.addEventListener("drop",t,!1),e.addEventListener("dragenter",c,!1),e.addEventListener("dragover",c,!1),e.addEventListener("dragexit",c,!1)}function p(e,r,i){return function(n){var o=r.name;try{var u;if(/\.czml$/i.test(o))u=a.load(JSON.parse(n.target.result),{sourceUri:o});else if(/\.geojson$/i.test(o)||/\.json$/i.test(o)||/\.topojson$/i.test(o))u=s.load(JSON.parse(n.target.result),{sourceUri:o});else{if(!/\.(kml|kmz)$/i.test(o))return void e.dropError.raiseEvent(e,o,"Unrecognized file: "+o);u=l.load(r,{sourceUri:o,proxy:i})}t(u)&&e.dataSources.add(u).then(function(t){e.flyToOnDrop&&e.flyTo(t)}).otherwise(function(t){e.dropError.raiseEvent(e,o,t)})}catch(c){e.dropError.raiseEvent(e,o,c)}}}function m(e,t){return function(r){e.dropError.raiseEvent(e,t.name,r.target.error)}}var f=function(t,i){function a(e){c(e),v&&(t.entities.removeAll(),t.dataSources.removeAll());for(var r=e.dataTransfer.files,i=r.length,n=0;i>n;n++){var o=r[n],a=new FileReader;a.onload=p(t,o,g),a.onerror=m(t,o),a.readAsText(o)}}i=e(i,e.EMPTY_OBJECT);var s=!0,l=!0,f=new n,v=e(i.clearOnDrop,!0),_=e(i.dropTarget,t.container),g=i.proxy;_=u(_),r(t,{dropTarget:{get:function(){return _},set:function(e){h(_,a),_=e,d(_,a)}},dropEnabled:{get:function(){return s},set:function(e){e!==s&&(e?d(_,a):h(_,a),s=e)}},dropError:{get:function(){return f}},clearOnDrop:{get:function(){return v},set:function(e){v=e}},flyToOnDrop:{get:function(){return l},set:function(e){l=e}},proxy:{get:function(){return g},set:function(e){g=e}}}),d(_,a),t.destroy=o(t,t.destroy,function(){t.dropEnabled=!1}),t._handleDrop=a};return f}),r("Widgets/Viewer/viewerPerformanceWatchdogMixin",["../../Core/defaultValue","../../Core/defined","../../Core/defineProperties","../../Core/DeveloperError","../PerformanceWatchdog/PerformanceWatchdog"],function(e,t,r,i,n){"use strict";var o=function(o,a){if(!t(o))throw new i("viewer is required.");a=e(a,e.EMPTY_OBJECT);var s=new n({scene:o.scene,container:o.bottomContainer,lowFrameRateMessage:a.lowFrameRateMessage});r(o,{performanceWatchdog:{get:function(){return s}}})};return o}),r("Workers/createTaskProcessorWorker",["../Core/defaultValue","../Core/defined","../Core/formatError"],function(e,t,r){"use strict";var i=function(i){var n,o=[],a={id:void 0,result:void 0,error:void 0};return function(s){var l=s.data;o.length=0,a.id=l.id,a.error=void 0,a.result=void 0;try{a.result=i(l.parameters,o)}catch(u){u instanceof Error?a.error={name:u.name,message:u.message,stack:u.stack}:a.error=u}t(n)||(n=e(self.webkitPostMessage,self.postMessage)),l.canTransferArrayBuffer||(o.length=0);try{n(a,o)}catch(u){a.result=void 0,a.error="postMessage failed with error: "+r(u)+"\n with responseMessage: "+JSON.stringify(a),n(a)}}};return i}),r("Cesium",["./Core/ArcGisImageServerTerrainProvider","./Core/AssociativeArray","./Core/AttributeCompression","./Core/AxisAlignedBoundingBox","./Core/BingMapsApi","./Core/BoundingRectangle","./Core/BoundingSphere","./Core/BoxGeometry","./Core/BoxOutlineGeometry","./Core/Cartesian2","./Core/Cartesian3","./Core/Cartesian4","./Core/Cartographic","./Core/CatmullRomSpline","./Core/CesiumTerrainProvider","./Core/CircleGeometry","./Core/CircleOutlineGeometry","./Core/Clock","./Core/ClockRange","./Core/ClockStep","./Core/Color","./Core/ColorGeometryInstanceAttribute","./Core/ComponentDatatype","./Core/CornerType","./Core/CorridorGeometry","./Core/CorridorGeometryLibrary","./Core/CorridorOutlineGeometry","./Core/Credit","./Core/CubicRealPolynomial","./Core/CylinderGeometry","./Core/CylinderGeometryLibrary","./Core/CylinderOutlineGeometry","./Core/DefaultProxy","./Core/DeveloperError","./Core/EarthOrientationParameters","./Core/EarthOrientationParametersSample","./Core/EasingFunction","./Core/EllipseGeometry","./Core/EllipseGeometryLibrary","./Core/EllipseOutlineGeometry","./Core/Ellipsoid","./Core/EllipsoidGeodesic","./Core/EllipsoidGeometry","./Core/EllipsoidOutlineGeometry","./Core/EllipsoidTangentPlane","./Core/EllipsoidTerrainProvider","./Core/EllipsoidalOccluder","./Core/EncodedCartesian3","./Core/Event","./Core/EventHelper","./Core/ExtrapolationType","./Core/FeatureDetection","./Core/Fullscreen","./Core/GeographicProjection","./Core/GeographicTilingScheme","./Core/Geometry","./Core/GeometryAttribute","./Core/GeometryAttributes","./Core/GeometryInstance","./Core/GeometryInstanceAttribute","./Core/GeometryPipeline","./Core/GeometryType","./Core/GregorianDate","./Core/HeadingPitchRange","./Core/HeightmapTerrainData","./Core/HeightmapTessellator","./Core/HermitePolynomialApproximation","./Core/HermiteSpline","./Core/Iau2000Orientation","./Core/Iau2006XysData","./Core/Iau2006XysSample","./Core/IauOrientationAxes","./Core/IauOrientationParameters","./Core/IndexDatatype","./Core/InterpolationAlgorithm","./Core/Intersect","./Core/IntersectionTests","./Core/Intersections2D","./Core/Interval","./Core/Iso8601","./Core/JulianDate","./Core/KeyboardEventModifier","./Core/LagrangePolynomialApproximation","./Core/LeapSecond","./Core/LinearApproximation","./Core/LinearSpline","./Core/MapProjection","./Core/MapboxApi","./Core/Math","./Core/Matrix2","./Core/Matrix3","./Core/Matrix4","./Core/NearFarScalar","./Core/Occluder","./Core/OrientedBoundingBox","./Core/Packable","./Core/PackableForInterpolation","./Core/PinBuilder","./Core/PixelFormat","./Core/Plane","./Core/PolygonGeometry","./Core/PolygonGeometryLibrary","./Core/PolygonHierarchy","./Core/PolygonOutlineGeometry","./Core/PolygonPipeline","./Core/PolylineGeometry","./Core/PolylinePipeline","./Core/PolylineVolumeGeometry","./Core/PolylineVolumeGeometryLibrary","./Core/PolylineVolumeOutlineGeometry","./Core/PrimitiveType","./Core/QuadraticRealPolynomial","./Core/QuantizedMeshTerrainData","./Core/QuarticRealPolynomial","./Core/Quaternion","./Core/QuaternionSpline","./Core/Queue","./Core/Ray","./Core/Rectangle","./Core/RectangleGeometry","./Core/RectangleGeometryLibrary","./Core/RectangleOutlineGeometry","./Core/ReferenceFrame","./Core/RequestErrorEvent","./Core/RuntimeError","./Core/ScreenSpaceEventHandler","./Core/ScreenSpaceEventType","./Core/ShowGeometryInstanceAttribute","./Core/Simon1994PlanetaryPositions","./Core/SimplePolylineGeometry","./Core/SphereGeometry","./Core/SphereOutlineGeometry","./Core/Spherical","./Core/Spline","./Core/TaskProcessor","./Core/TerrainData","./Core/TerrainMesh","./Core/TerrainProvider","./Core/TileProviderError","./Core/TilingScheme","./Core/TimeConstants","./Core/TimeInterval","./Core/TimeIntervalCollection","./Core/TimeStandard","./Core/Tipsify","./Core/Transforms","./Core/TridiagonalSystemSolver","./Core/VRTheWorldTerrainProvider","./Core/VertexFormat","./Core/Visibility","./Core/WallGeometry","./Core/WallGeometryLibrary","./Core/WallOutlineGeometry","./Core/WebMercatorProjection","./Core/WebMercatorTilingScheme","./Core/WindingOrder","./Core/appendForwardSlash","./Core/barycentricCoordinates","./Core/binarySearch","./Core/buildModuleUrl","./Core/cancelAnimationFrame","./Core/clone","./Core/combine","./Core/createGuid","./Core/defaultValue","./Core/defineProperties","./Core/defined","./Core/definedNotNull","./Core/deprecationWarning","./Core/destroyObject","./Core/formatError","./Core/freezeObject","./Core/getFilenameFromUri","./Core/getImagePixels","./Core/getMagic","./Core/getStringFromTypedArray","./Core/getTimestamp","./Core/isArray","./Core/isCrossOriginUrl","./Core/isLeapYear","./Core/joinUrls","./Core/jsonp","./Core/loadArrayBuffer","./Core/loadBlob","./Core/loadImage","./Core/loadImageFromTypedArray","./Core/loadImageViaBlob","./Core/loadJson","./Core/loadJsonp","./Core/loadText","./Core/loadWithXhr","./Core/loadXML","./Core/mergeSort","./Core/objectToQuery","./Core/parseResponseHeaders","./Core/pointInsideTriangle","./Core/queryToObject","./Core/requestAnimationFrame","./Core/sampleTerrain","./Core/subdivideArray","./Core/throttleRequestByServer","./Core/wrapFunction","./Core/writeTextToCanvas","./DataSources/BillboardGraphics","./DataSources/BillboardVisualizer","./DataSources/BoundingSphereState","./DataSources/BoxGeometryUpdater","./DataSources/BoxGraphics","./DataSources/CallbackProperty","./DataSources/CheckerboardMaterialProperty","./DataSources/ColorMaterialProperty","./DataSources/CompositeEntityCollection","./DataSources/CompositeMaterialProperty","./DataSources/CompositePositionProperty","./DataSources/CompositeProperty","./DataSources/ConstantPositionProperty","./DataSources/ConstantProperty","./DataSources/CorridorGeometryUpdater","./DataSources/CorridorGraphics","./DataSources/CustomDataSource","./DataSources/CylinderGeometryUpdater","./DataSources/CylinderGraphics","./DataSources/CzmlDataSource","./DataSources/DataSource","./DataSources/DataSourceClock","./DataSources/DataSourceCollection","./DataSources/DataSourceDisplay","./DataSources/DynamicGeometryUpdater","./DataSources/EllipseGeometryUpdater","./DataSources/EllipseGraphics","./DataSources/EllipsoidGeometryUpdater","./DataSources/EllipsoidGraphics","./DataSources/Entity","./DataSources/EntityCollection","./DataSources/EntityView","./DataSources/GeoJsonDataSource","./DataSources/GeometryUpdater","./DataSources/GeometryVisualizer","./DataSources/GridMaterialProperty","./DataSources/ImageMaterialProperty","./DataSources/KmlDataSource","./DataSources/LabelGraphics","./DataSources/LabelVisualizer","./DataSources/MaterialProperty","./DataSources/ModelGraphics","./DataSources/ModelVisualizer","./DataSources/PathGraphics","./DataSources/PathVisualizer","./DataSources/PointGraphics","./DataSources/PointVisualizer","./DataSources/PolygonGeometryUpdater","./DataSources/PolygonGraphics","./DataSources/PolylineArrowMaterialProperty","./DataSources/PolylineGeometryUpdater","./DataSources/PolylineGlowMaterialProperty","./DataSources/PolylineGraphics","./DataSources/PolylineOutlineMaterialProperty","./DataSources/PolylineVolumeGeometryUpdater","./DataSources/PolylineVolumeGraphics","./DataSources/PositionProperty","./DataSources/PositionPropertyArray","./DataSources/Property","./DataSources/PropertyArray","./DataSources/RectangleGeometryUpdater","./DataSources/RectangleGraphics","./DataSources/ReferenceProperty","./DataSources/Rotation","./DataSources/SampledPositionProperty","./DataSources/SampledProperty","./DataSources/ScaledPositionProperty","./DataSources/StaticGeometryColorBatch","./DataSources/StaticGeometryPerMaterialBatch","./DataSources/StaticOutlineGeometryBatch","./DataSources/StripeMaterialProperty","./DataSources/StripeOrientation","./DataSources/TimeIntervalCollectionPositionProperty","./DataSources/TimeIntervalCollectionProperty","./DataSources/VelocityOrientationProperty","./DataSources/Visualizer","./DataSources/WallGeometryUpdater","./DataSources/WallGraphics","./DataSources/createMaterialPropertyDescriptor","./DataSources/createPropertyDescriptor","./DataSources/createRawPropertyDescriptor","./DataSources/dynamicGeometryGetBoundingSphere","./Renderer/AutomaticUniforms","./Renderer/Buffer","./Renderer/BufferUsage","./Renderer/ClearCommand","./Renderer/ComputeCommand","./Renderer/ComputeEngine","./Renderer/Context","./Renderer/ContextLimits","./Renderer/CubeMap","./Renderer/CubeMapFace","./Renderer/DrawCommand","./Renderer/Framebuffer","./Renderer/MipmapHint","./Renderer/PassState","./Renderer/PickFramebuffer","./Renderer/PixelDatatype","./Renderer/RenderState","./Renderer/Renderbuffer","./Renderer/RenderbufferFormat","./Renderer/Sampler","./Renderer/ShaderCache","./Renderer/ShaderProgram","./Renderer/ShaderSource","./Renderer/Texture","./Renderer/TextureMagnificationFilter","./Renderer/TextureMinificationFilter","./Renderer/TextureWrap","./Renderer/UniformState","./Renderer/VertexArray","./Renderer/VertexArrayFacade","./Renderer/WebGLConstants","./Renderer/createUniform","./Renderer/createUniformArray","./Renderer/loadCubeMap","./Scene/Appearance","./Scene/ArcGisMapServerImageryProvider","./Scene/Billboard","./Scene/BillboardCollection","./Scene/BingMapsImageryProvider","./Scene/BingMapsStyle","./Scene/BlendEquation","./Scene/BlendFunction","./Scene/BlendingState","./Scene/Camera","./Scene/CameraEventAggregator","./Scene/CameraEventType","./Scene/CameraFlightPath","./Scene/CreditDisplay","./Scene/CullFace","./Scene/CullingVolume","./Scene/DebugAppearance","./Scene/DebugModelMatrixPrimitive","./Scene/DepthFunction","./Scene/DepthPlane","./Scene/DiscardMissingTileImagePolicy","./Scene/EllipsoidPrimitive","./Scene/EllipsoidSurfaceAppearance","./Scene/FXAA","./Scene/Fog","./Scene/FrameRateMonitor","./Scene/FrameState","./Scene/FrustumCommands","./Scene/GetFeatureInfoFormat","./Scene/Globe","./Scene/GlobeDepth","./Scene/GlobeSurfaceShaderSet","./Scene/GlobeSurfaceTile","./Scene/GlobeSurfaceTileProvider","./Scene/GoogleEarthImageryProvider","./Scene/GridImageryProvider","./Scene/GroundPrimitive","./Scene/HeightReference","./Scene/HorizontalOrigin","./Scene/Imagery","./Scene/ImageryLayer","./Scene/ImageryLayerCollection","./Scene/ImageryLayerFeatureInfo","./Scene/ImageryProvider","./Scene/ImageryState","./Scene/Label","./Scene/LabelCollection","./Scene/LabelStyle","./Scene/MapboxImageryProvider","./Scene/Material","./Scene/MaterialAppearance","./Scene/Model","./Scene/ModelAnimation","./Scene/ModelAnimationCache","./Scene/ModelAnimationCollection","./Scene/ModelAnimationLoop","./Scene/ModelAnimationState","./Scene/ModelMaterial","./Scene/ModelMesh","./Scene/ModelNode","./Scene/Moon","./Scene/NeverTileDiscardPolicy","./Scene/OIT","./Scene/OpenStreetMapImageryProvider","./Scene/OrthographicFrustum","./Scene/Pass","./Scene/PerInstanceColorAppearance","./Scene/PerformanceDisplay","./Scene/PerspectiveFrustum","./Scene/PerspectiveOffCenterFrustum","./Scene/PickDepth","./Scene/PointPrimitive","./Scene/PointPrimitiveCollection","./Scene/Polygon","./Scene/Polyline","./Scene/PolylineCollection","./Scene/PolylineColorAppearance","./Scene/PolylineMaterialAppearance","./Scene/Primitive","./Scene/PrimitiveCollection","./Scene/PrimitivePipeline","./Scene/PrimitiveState","./Scene/QuadtreeOccluders","./Scene/QuadtreePrimitive","./Scene/QuadtreeTile","./Scene/QuadtreeTileLoadState","./Scene/QuadtreeTileProvider","./Scene/RectanglePrimitive","./Scene/Scene","./Scene/SceneMode","./Scene/SceneTransforms","./Scene/SceneTransitioner","./Scene/ScreenSpaceCameraController","./Scene/SingleTileImageryProvider","./Scene/SkyAtmosphere","./Scene/SkyBox","./Scene/StencilFunction","./Scene/StencilOperation","./Scene/Sun","./Scene/SunPostProcess","./Scene/TerrainState","./Scene/TextureAtlas","./Scene/TileCoordinatesImageryProvider","./Scene/TileDiscardPolicy","./Scene/TileImagery","./Scene/TileMapServiceImageryProvider","./Scene/TileReplacementQueue","./Scene/TileState","./Scene/TileTerrain","./Scene/TweenCollection","./Scene/UrlTemplateImageryProvider","./Scene/VerticalOrigin","./Scene/ViewportQuad","./Scene/WebMapServiceImageryProvider","./Scene/WebMapTileServiceImageryProvider","./Scene/createTangentSpaceDebugPrimitive","./Scene/getModelAccessor","./Scene/modelMaterialsCommon","./Scene/terrainAttributeLocations","./Shaders/AdjustTranslucentFS","./Shaders/Appearances/AllMaterialAppearanceFS","./Shaders/Appearances/AllMaterialAppearanceVS","./Shaders/Appearances/BasicMaterialAppearanceFS","./Shaders/Appearances/BasicMaterialAppearanceVS","./Shaders/Appearances/EllipsoidSurfaceAppearanceFS","./Shaders/Appearances/EllipsoidSurfaceAppearanceVS","./Shaders/Appearances/PerInstanceColorAppearanceFS","./Shaders/Appearances/PerInstanceColorAppearanceVS","./Shaders/Appearances/PerInstanceFlatColorAppearanceFS","./Shaders/Appearances/PerInstanceFlatColorAppearanceVS","./Shaders/Appearances/PolylineColorAppearanceVS","./Shaders/Appearances/PolylineMaterialAppearanceVS","./Shaders/Appearances/TexturedMaterialAppearanceFS","./Shaders/Appearances/TexturedMaterialAppearanceVS","./Shaders/BillboardCollectionFS","./Shaders/BillboardCollectionVS","./Shaders/Builtin/Constants/degreesPerRadian","./Shaders/Builtin/Constants/depthRange","./Shaders/Builtin/Constants/epsilon1","./Shaders/Builtin/Constants/epsilon2","./Shaders/Builtin/Constants/epsilon3","./Shaders/Builtin/Constants/epsilon4","./Shaders/Builtin/Constants/epsilon5","./Shaders/Builtin/Constants/epsilon6","./Shaders/Builtin/Constants/epsilon7","./Shaders/Builtin/Constants/infinity","./Shaders/Builtin/Constants/oneOverPi","./Shaders/Builtin/Constants/oneOverTwoPi","./Shaders/Builtin/Constants/pi","./Shaders/Builtin/Constants/piOverFour","./Shaders/Builtin/Constants/piOverSix","./Shaders/Builtin/Constants/piOverThree","./Shaders/Builtin/Constants/piOverTwo","./Shaders/Builtin/Constants/radiansPerDegree","./Shaders/Builtin/Constants/sceneMode2D","./Shaders/Builtin/Constants/sceneMode3D","./Shaders/Builtin/Constants/sceneModeColumbusView","./Shaders/Builtin/Constants/sceneModeMorphing","./Shaders/Builtin/Constants/solarRadius","./Shaders/Builtin/Constants/threePiOver2","./Shaders/Builtin/Constants/twoPi","./Shaders/Builtin/Constants/webMercatorMaxLatitude","./Shaders/Builtin/CzmBuiltins","./Shaders/Builtin/Functions/RGBToXYZ","./Shaders/Builtin/Functions/XYZToRGB","./Shaders/Builtin/Functions/alphaWeight","./Shaders/Builtin/Functions/antialias","./Shaders/Builtin/Functions/columbusViewMorph","./Shaders/Builtin/Functions/computePosition","./Shaders/Builtin/Functions/cosineAndSine","./Shaders/Builtin/Functions/decompressTextureCoordinates","./Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates","./Shaders/Builtin/Functions/ellipsoidContainsPoint","./Shaders/Builtin/Functions/ellipsoidNew","./Shaders/Builtin/Functions/ellipsoidWgs84TextureCoordinates","./Shaders/Builtin/Functions/equalsEpsilon","./Shaders/Builtin/Functions/eyeOffset","./Shaders/Builtin/Functions/eyeToWindowCoordinates","./Shaders/Builtin/Functions/fog","./Shaders/Builtin/Functions/geodeticSurfaceNormal","./Shaders/Builtin/Functions/getDefaultMaterial","./Shaders/Builtin/Functions/getLambertDiffuse","./Shaders/Builtin/Functions/getSpecular","./Shaders/Builtin/Functions/getWaterNoise","./Shaders/Builtin/Functions/getWgs84EllipsoidEC","./Shaders/Builtin/Functions/hue","./Shaders/Builtin/Functions/isEmpty","./Shaders/Builtin/Functions/isFull","./Shaders/Builtin/Functions/latitudeToWebMercatorFraction","./Shaders/Builtin/Functions/luminance","./Shaders/Builtin/Functions/metersPerPixel","./Shaders/Builtin/Functions/modelToWindowCoordinates","./Shaders/Builtin/Functions/multiplyWithColorBalance","./Shaders/Builtin/Functions/nearFarScalar","./Shaders/Builtin/Functions/octDecode","./Shaders/Builtin/Functions/packDepth","./Shaders/Builtin/Functions/phong","./Shaders/Builtin/Functions/pointAlongRay","./Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval","./Shaders/Builtin/Functions/saturation","./Shaders/Builtin/Functions/signNotZero","./Shaders/Builtin/Functions/tangentToEyeSpaceMatrix","./Shaders/Builtin/Functions/translateRelativeToEye","./Shaders/Builtin/Functions/translucentPhong","./Shaders/Builtin/Functions/transpose","./Shaders/Builtin/Functions/unpackDepth","./Shaders/Builtin/Functions/windowToEyeCoordinates","./Shaders/Builtin/Structs/depthRangeStruct","./Shaders/Builtin/Structs/ellipsoid","./Shaders/Builtin/Structs/material","./Shaders/Builtin/Structs/materialInput","./Shaders/Builtin/Structs/ray","./Shaders/Builtin/Structs/raySegment","./Shaders/CompositeOITFS","./Shaders/DepthPlaneFS","./Shaders/DepthPlaneVS","./Shaders/EllipsoidFS","./Shaders/EllipsoidVS","./Shaders/GlobeFS","./Shaders/GlobeFSPole","./Shaders/GlobeVS","./Shaders/GlobeVSPole","./Shaders/GroundAtmosphere","./Shaders/Materials/BumpMapMaterial","./Shaders/Materials/CheckerboardMaterial","./Shaders/Materials/DotMaterial","./Shaders/Materials/FadeMaterial","./Shaders/Materials/GridMaterial","./Shaders/Materials/NormalMapMaterial","./Shaders/Materials/PolylineArrowMaterial","./Shaders/Materials/PolylineGlowMaterial","./Shaders/Materials/PolylineOutlineMaterial","./Shaders/Materials/RimLightingMaterial","./Shaders/Materials/StripeMaterial","./Shaders/Materials/Water","./Shaders/PointPrimitiveCollectionFS","./Shaders/PointPrimitiveCollectionVS","./Shaders/PolylineCommon","./Shaders/PolylineFS","./Shaders/PolylineVS","./Shaders/PostProcessFilters/AdditiveBlend","./Shaders/PostProcessFilters/BrightPass","./Shaders/PostProcessFilters/FXAA","./Shaders/PostProcessFilters/GaussianBlur1D","./Shaders/PostProcessFilters/PassThrough","./Shaders/ReprojectWebMercatorFS","./Shaders/ReprojectWebMercatorVS","./Shaders/ShadowVolumeFS","./Shaders/ShadowVolumeVS","./Shaders/SkyAtmosphereFS","./Shaders/SkyAtmosphereVS","./Shaders/SkyBoxFS","./Shaders/SkyBoxVS","./Shaders/SunFS","./Shaders/SunTextureFS","./Shaders/SunVS","./Shaders/ViewportQuadFS","./Shaders/ViewportQuadVS","./ThirdParty/Autolinker","./ThirdParty/Tween","./ThirdParty/Uri","./ThirdParty/gltfDefaults","./ThirdParty/knockout-3.2.0","./ThirdParty/knockout-es5","./ThirdParty/knockout","./ThirdParty/measureText","./ThirdParty/mersenne-twister","./ThirdParty/sprintf","./ThirdParty/topojson","./ThirdParty/when","./ThirdParty/zip","./Widgets/Animation/Animation","./Widgets/Animation/AnimationViewModel","./Widgets/BaseLayerPicker/BaseLayerPicker","./Widgets/BaseLayerPicker/BaseLayerPickerViewModel","./Widgets/BaseLayerPicker/ProviderViewModel","./Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels","./Widgets/BaseLayerPicker/createDefaultTerrainProviderViewModels","./Widgets/CesiumInspector/CesiumInspector","./Widgets/CesiumInspector/CesiumInspectorViewModel","./Widgets/CesiumWidget/CesiumWidget","./Widgets/ClockViewModel","./Widgets/Command","./Widgets/FullscreenButton/FullscreenButton","./Widgets/FullscreenButton/FullscreenButtonViewModel","./Widgets/Geocoder/Geocoder","./Widgets/Geocoder/GeocoderViewModel","./Widgets/HomeButton/HomeButton","./Widgets/HomeButton/HomeButtonViewModel","./Widgets/InfoBox/InfoBox","./Widgets/InfoBox/InfoBoxViewModel","./Widgets/NavigationHelpButton/NavigationHelpButton","./Widgets/NavigationHelpButton/NavigationHelpButtonViewModel","./Widgets/PerformanceWatchdog/PerformanceWatchdog","./Widgets/PerformanceWatchdog/PerformanceWatchdogViewModel","./Widgets/SceneModePicker/SceneModePicker","./Widgets/SceneModePicker/SceneModePickerViewModel","./Widgets/SelectionIndicator/SelectionIndicator","./Widgets/SelectionIndicator/SelectionIndicatorViewModel","./Widgets/SvgPathBindingHandler","./Widgets/Timeline/Timeline","./Widgets/Timeline/TimelineHighlightRange","./Widgets/Timeline/TimelineTrack","./Widgets/ToggleButtonViewModel","./Widgets/Viewer/Viewer","./Widgets/Viewer/viewerCesiumInspectorMixin","./Widgets/Viewer/viewerDragDropMixin","./Widgets/Viewer/viewerPerformanceWatchdogMixin","./Widgets/createCommand","./Widgets/getElement","./Widgets/subscribeAndEvaluate","./Workers/createTaskProcessorWorker"],function(e,t,r,i,n,o,a,s,l,u,c,h,d,p,m,f,v,_,g,y,C,E,S,w,T,b,x,P,A,I,M,D,R,O,N,L,F,B,V,z,k,U,G,W,H,q,j,Y,X,Z,K,J,Q,$,ee,te,re,ie,ne,oe,ae,se,le,ue,ce,he,de,pe,me,fe,ve,_e,ge,ye,Ce,Ee,Se,we,Te,be,xe,Pe,Ae,Ie,Me,De,Re,Oe,Ne,Le,Fe,Be,Ve,ze,ke,Ue,Ge,We,He,qe,je,Ye,Xe,Ze,Ke,Je,Qe,$e,et,tt,rt,it,nt,ot,at,st,lt,ut,ct,ht,dt,pt,mt,ft,vt,_t,gt,yt,Ct,Et,St,wt,Tt,bt,xt,Pt,At,It,Mt,Dt,Rt,Ot,Nt,Lt,Ft,Bt,Vt,zt,kt,Ut,Gt,Wt,Ht,qt,jt,Yt,Xt,Zt,Kt,Jt,Qt,$t,er,tr,rr,ir,nr,or,ar,sr,lr,ur,cr,hr,dr,pr,mr,fr,vr,_r,gr,yr,Cr,Er,Sr,wr,Tr,br,xr,Pr,Ar,Ir,Mr,Dr,Rr,Or,Nr,Lr,Fr,Br,Vr,zr,kr,Ur,Gr,Wr,Hr,qr,jr,Yr,Xr,Zr,Kr,Jr,Qr,$r,ei,ti,ri,ii,ni,oi,ai,si,li,ui,ci,hi,di,pi,mi,fi,vi,_i,gi,yi,Ci,Ei,Si,wi,Ti,bi,xi,Pi,Ai,Ii,Mi,Di,Ri,Oi,Ni,Li,Fi,Bi,Vi,zi,ki,Ui,Gi,Wi,Hi,qi,ji,Yi,Xi,Zi,Ki,Ji,Qi,$i,en,tn,rn,nn,on,an,sn,ln,un,cn,hn,dn,pn,mn,fn,vn,_n,gn,yn,Cn,En,Sn,wn,Tn,bn,xn,Pn,An,In,Mn,Dn,Rn,On,Nn,Ln,Fn,Bn,Vn,zn,kn,Un,Gn,Wn,Hn,qn,jn,Yn,Xn,Zn,Kn,Jn,Qn,$n,eo,to,ro,io,no,oo,ao,so,lo,uo,co,ho,po,mo,fo,vo,_o,go,yo,Co,Eo,So,wo,To,bo,xo,Po,Ao,Io,Mo,Do,Ro,Oo,No,Lo,Fo,Bo,Vo,zo,ko,Uo,Go,Wo,Ho,qo,jo,Yo,Xo,Zo,Ko,Jo,Qo,$o,ea,ta,ra,ia,na,oa,aa,sa,la,ua,ca,ha,da,pa,ma,fa,va,_a,ga,ya,Ca,Ea,Sa,wa,Ta,ba,xa,Pa,Aa,Ia,Ma,Da,Ra,Oa,Na,La,Fa,Ba,Va,za,ka,Ua,Ga,Wa,Ha,qa,ja,Ya,Xa,Za,Ka,Ja,Qa,$a,es,ts,rs,is,ns,os,as,ss,ls,us,cs,hs,ds,ps,ms,fs,vs,_s,gs,ys,Cs,Es,Ss,ws,Ts,bs,xs,Ps,As,Is,Ms,Ds,Rs,Os,Ns,Ls,Fs,Bs,Vs,zs,ks,Us,Gs,Ws,Hs,qs,js,Ys,Xs,Zs,Ks,Js,Qs,$s,el,tl,rl,il,nl,ol,al,sl,ll,ul,cl,hl,dl,pl,ml,fl,vl,_l,gl,yl,Cl,El,Sl,wl,Tl,bl,xl,Pl,Al,Il,Ml,Dl,Rl,Ol,Nl,Ll,Fl,Bl,Vl,zl,kl,Ul,Gl,Wl,Hl,ql,jl,Yl,Xl,Zl,Kl,Jl,Ql,$l,eu,tu,ru,iu,nu,ou,au,su,lu,uu,cu,hu,du,pu,mu,fu,vu,_u,gu,yu,Cu,Eu,Su,wu,Tu,bu,xu,Pu,Au,Iu,Mu,Du,Ru,Ou,Nu,Lu,Fu,Bu,Vu,zu,ku,Uu,Gu,Wu,Hu,qu,ju,Yu,Xu,Zu,Ku,Ju,Qu,$u,ec,tc,rc,ic,nc,oc,ac,sc,lc,uc,cc,hc,dc,pc,mc,fc,vc,_c,gc,yc,Cc,Ec,Sc,wc,Tc,bc,xc,Pc,Ac,Ic,Mc,Dc,Rc,Oc,Nc,Lc,Fc,Bc,Vc){ -"use strict";var zc={VERSION:"1.15",_shaders:{}};return zc.ArcGisImageServerTerrainProvider=e,zc.AssociativeArray=t,zc.AttributeCompression=r,zc.AxisAlignedBoundingBox=i,zc.BingMapsApi=n,zc.BoundingRectangle=o,zc.BoundingSphere=a,zc.BoxGeometry=s,zc.BoxOutlineGeometry=l,zc.Cartesian2=u,zc.Cartesian3=c,zc.Cartesian4=h,zc.Cartographic=d,zc.CatmullRomSpline=p,zc.CesiumTerrainProvider=m,zc.CircleGeometry=f,zc.CircleOutlineGeometry=v,zc.Clock=_,zc.ClockRange=g,zc.ClockStep=y,zc.Color=C,zc.ColorGeometryInstanceAttribute=E,zc.ComponentDatatype=S,zc.CornerType=w,zc.CorridorGeometry=T,zc.CorridorGeometryLibrary=b,zc.CorridorOutlineGeometry=x,zc.Credit=P,zc.CubicRealPolynomial=A,zc.CylinderGeometry=I,zc.CylinderGeometryLibrary=M,zc.CylinderOutlineGeometry=D,zc.DefaultProxy=R,zc.DeveloperError=O,zc.EarthOrientationParameters=N,zc.EarthOrientationParametersSample=L,zc.EasingFunction=F,zc.EllipseGeometry=B,zc.EllipseGeometryLibrary=V,zc.EllipseOutlineGeometry=z,zc.Ellipsoid=k,zc.EllipsoidGeodesic=U,zc.EllipsoidGeometry=G,zc.EllipsoidOutlineGeometry=W,zc.EllipsoidTangentPlane=H,zc.EllipsoidTerrainProvider=q,zc.EllipsoidalOccluder=j,zc.EncodedCartesian3=Y,zc.Event=X,zc.EventHelper=Z,zc.ExtrapolationType=K,zc.FeatureDetection=J,zc.Fullscreen=Q,zc.GeographicProjection=$,zc.GeographicTilingScheme=ee,zc.Geometry=te,zc.GeometryAttribute=re,zc.GeometryAttributes=ie,zc.GeometryInstance=ne,zc.GeometryInstanceAttribute=oe,zc.GeometryPipeline=ae,zc.GeometryType=se,zc.GregorianDate=le,zc.HeadingPitchRange=ue,zc.HeightmapTerrainData=ce,zc.HeightmapTessellator=he,zc.HermitePolynomialApproximation=de,zc.HermiteSpline=pe,zc.Iau2000Orientation=me,zc.Iau2006XysData=fe,zc.Iau2006XysSample=ve,zc.IauOrientationAxes=_e,zc.IauOrientationParameters=ge,zc.IndexDatatype=ye,zc.InterpolationAlgorithm=Ce,zc.Intersect=Ee,zc.IntersectionTests=Se,zc.Intersections2D=we,zc.Interval=Te,zc.Iso8601=be,zc.JulianDate=xe,zc.KeyboardEventModifier=Pe,zc.LagrangePolynomialApproximation=Ae,zc.LeapSecond=Ie,zc.LinearApproximation=Me,zc.LinearSpline=De,zc.MapProjection=Re,zc.MapboxApi=Oe,zc.Math=Ne,zc.Matrix2=Le,zc.Matrix3=Fe,zc.Matrix4=Be,zc.NearFarScalar=Ve,zc.Occluder=ze,zc.OrientedBoundingBox=ke,zc.Packable=Ue,zc.PackableForInterpolation=Ge,zc.PinBuilder=We,zc.PixelFormat=He,zc.Plane=qe,zc.PolygonGeometry=je,zc.PolygonGeometryLibrary=Ye,zc.PolygonHierarchy=Xe,zc.PolygonOutlineGeometry=Ze,zc.PolygonPipeline=Ke,zc.PolylineGeometry=Je,zc.PolylinePipeline=Qe,zc.PolylineVolumeGeometry=$e,zc.PolylineVolumeGeometryLibrary=et,zc.PolylineVolumeOutlineGeometry=tt,zc.PrimitiveType=rt,zc.QuadraticRealPolynomial=it,zc.QuantizedMeshTerrainData=nt,zc.QuarticRealPolynomial=ot,zc.Quaternion=at,zc.QuaternionSpline=st,zc.Queue=lt,zc.Ray=ut,zc.Rectangle=ct,zc.RectangleGeometry=ht,zc.RectangleGeometryLibrary=dt,zc.RectangleOutlineGeometry=pt,zc.ReferenceFrame=mt,zc.RequestErrorEvent=ft,zc.RuntimeError=vt,zc.ScreenSpaceEventHandler=_t,zc.ScreenSpaceEventType=gt,zc.ShowGeometryInstanceAttribute=yt,zc.Simon1994PlanetaryPositions=Ct,zc.SimplePolylineGeometry=Et,zc.SphereGeometry=St,zc.SphereOutlineGeometry=wt,zc.Spherical=Tt,zc.Spline=bt,zc.TaskProcessor=xt,zc.TerrainData=Pt,zc.TerrainMesh=At,zc.TerrainProvider=It,zc.TileProviderError=Mt,zc.TilingScheme=Dt,zc.TimeConstants=Rt,zc.TimeInterval=Ot,zc.TimeIntervalCollection=Nt,zc.TimeStandard=Lt,zc.Tipsify=Ft,zc.Transforms=Bt,zc.TridiagonalSystemSolver=Vt,zc.VRTheWorldTerrainProvider=zt,zc.VertexFormat=kt,zc.Visibility=Ut,zc.WallGeometry=Gt,zc.WallGeometryLibrary=Wt,zc.WallOutlineGeometry=Ht,zc.WebMercatorProjection=qt,zc.WebMercatorTilingScheme=jt,zc.WindingOrder=Yt,zc.appendForwardSlash=Xt,zc.barycentricCoordinates=Zt,zc.binarySearch=Kt,zc.buildModuleUrl=Jt,zc.cancelAnimationFrame=Qt,zc.clone=$t,zc.combine=er,zc.createGuid=tr,zc.defaultValue=rr,zc.defineProperties=ir,zc.defined=nr,zc.definedNotNull=or,zc.deprecationWarning=ar,zc.destroyObject=sr,zc.formatError=lr,zc.freezeObject=ur,zc.getFilenameFromUri=cr,zc.getImagePixels=hr,zc.getMagic=dr,zc.getStringFromTypedArray=pr,zc.getTimestamp=mr,zc.isArray=fr,zc.isCrossOriginUrl=vr,zc.isLeapYear=_r,zc.joinUrls=gr,zc.jsonp=yr,zc.loadArrayBuffer=Cr,zc.loadBlob=Er,zc.loadImage=Sr,zc.loadImageFromTypedArray=wr,zc.loadImageViaBlob=Tr,zc.loadJson=br,zc.loadJsonp=xr,zc.loadText=Pr,zc.loadWithXhr=Ar,zc.loadXML=Ir,zc.mergeSort=Mr,zc.objectToQuery=Dr,zc.parseResponseHeaders=Rr,zc.pointInsideTriangle=Or,zc.queryToObject=Nr,zc.requestAnimationFrame=Lr,zc.sampleTerrain=Fr,zc.subdivideArray=Br,zc.throttleRequestByServer=Vr,zc.wrapFunction=zr,zc.writeTextToCanvas=kr,zc.BillboardGraphics=Ur,zc.BillboardVisualizer=Gr,zc.BoundingSphereState=Wr,zc.BoxGeometryUpdater=Hr,zc.BoxGraphics=qr,zc.CallbackProperty=jr,zc.CheckerboardMaterialProperty=Yr,zc.ColorMaterialProperty=Xr,zc.CompositeEntityCollection=Zr,zc.CompositeMaterialProperty=Kr,zc.CompositePositionProperty=Jr,zc.CompositeProperty=Qr,zc.ConstantPositionProperty=$r,zc.ConstantProperty=ei,zc.CorridorGeometryUpdater=ti,zc.CorridorGraphics=ri,zc.CustomDataSource=ii,zc.CylinderGeometryUpdater=ni,zc.CylinderGraphics=oi,zc.CzmlDataSource=ai,zc.DataSource=si,zc.DataSourceClock=li,zc.DataSourceCollection=ui,zc.DataSourceDisplay=ci,zc.DynamicGeometryUpdater=hi,zc.EllipseGeometryUpdater=di,zc.EllipseGraphics=pi,zc.EllipsoidGeometryUpdater=mi,zc.EllipsoidGraphics=fi,zc.Entity=vi,zc.EntityCollection=_i,zc.EntityView=gi,zc.GeoJsonDataSource=yi,zc.GeometryUpdater=Ci,zc.GeometryVisualizer=Ei,zc.GridMaterialProperty=Si,zc.ImageMaterialProperty=wi,zc.KmlDataSource=Ti,zc.LabelGraphics=bi,zc.LabelVisualizer=xi,zc.MaterialProperty=Pi,zc.ModelGraphics=Ai,zc.ModelVisualizer=Ii,zc.PathGraphics=Mi,zc.PathVisualizer=Di,zc.PointGraphics=Ri,zc.PointVisualizer=Oi,zc.PolygonGeometryUpdater=Ni,zc.PolygonGraphics=Li,zc.PolylineArrowMaterialProperty=Fi,zc.PolylineGeometryUpdater=Bi,zc.PolylineGlowMaterialProperty=Vi,zc.PolylineGraphics=zi,zc.PolylineOutlineMaterialProperty=ki,zc.PolylineVolumeGeometryUpdater=Ui,zc.PolylineVolumeGraphics=Gi,zc.PositionProperty=Wi,zc.PositionPropertyArray=Hi,zc.Property=qi,zc.PropertyArray=ji,zc.RectangleGeometryUpdater=Yi,zc.RectangleGraphics=Xi,zc.ReferenceProperty=Zi,zc.Rotation=Ki,zc.SampledPositionProperty=Ji,zc.SampledProperty=Qi,zc.ScaledPositionProperty=$i,zc.StaticGeometryColorBatch=en,zc.StaticGeometryPerMaterialBatch=tn,zc.StaticOutlineGeometryBatch=rn,zc.StripeMaterialProperty=nn,zc.StripeOrientation=on,zc.TimeIntervalCollectionPositionProperty=an,zc.TimeIntervalCollectionProperty=sn,zc.VelocityOrientationProperty=ln,zc.Visualizer=un,zc.WallGeometryUpdater=cn,zc.WallGraphics=hn,zc.createMaterialPropertyDescriptor=dn,zc.createPropertyDescriptor=pn,zc.createRawPropertyDescriptor=mn,zc.dynamicGeometryGetBoundingSphere=fn,zc.AutomaticUniforms=vn,zc.Buffer=_n,zc.BufferUsage=gn,zc.ClearCommand=yn,zc.ComputeCommand=Cn,zc.ComputeEngine=En,zc.Context=Sn,zc.ContextLimits=wn,zc.CubeMap=Tn,zc.CubeMapFace=bn,zc.DrawCommand=xn,zc.Framebuffer=Pn,zc.MipmapHint=An,zc.PassState=In,zc.PickFramebuffer=Mn,zc.PixelDatatype=Dn,zc.RenderState=Rn,zc.Renderbuffer=On,zc.RenderbufferFormat=Nn,zc.Sampler=Ln,zc.ShaderCache=Fn,zc.ShaderProgram=Bn,zc.ShaderSource=Vn,zc.Texture=zn,zc.TextureMagnificationFilter=kn,zc.TextureMinificationFilter=Un,zc.TextureWrap=Gn,zc.UniformState=Wn,zc.VertexArray=Hn,zc.VertexArrayFacade=qn,zc.WebGLConstants=jn,zc.createUniform=Yn,zc.createUniformArray=Xn,zc.loadCubeMap=Zn,zc.Appearance=Kn,zc.ArcGisMapServerImageryProvider=Jn,zc.Billboard=Qn,zc.BillboardCollection=$n,zc.BingMapsImageryProvider=eo,zc.BingMapsStyle=to,zc.BlendEquation=ro,zc.BlendFunction=io,zc.BlendingState=no,zc.Camera=oo,zc.CameraEventAggregator=ao,zc.CameraEventType=so,zc.CameraFlightPath=lo,zc.CreditDisplay=uo,zc.CullFace=co,zc.CullingVolume=ho,zc.DebugAppearance=po,zc.DebugModelMatrixPrimitive=mo,zc.DepthFunction=fo,zc.DepthPlane=vo,zc.DiscardMissingTileImagePolicy=_o,zc.EllipsoidPrimitive=go,zc.EllipsoidSurfaceAppearance=yo,zc.FXAA=Co,zc.Fog=Eo,zc.FrameRateMonitor=So,zc.FrameState=wo,zc.FrustumCommands=To,zc.GetFeatureInfoFormat=bo,zc.Globe=xo,zc.GlobeDepth=Po,zc.GlobeSurfaceShaderSet=Ao,zc.GlobeSurfaceTile=Io,zc.GlobeSurfaceTileProvider=Mo,zc.GoogleEarthImageryProvider=Do,zc.GridImageryProvider=Ro,zc.GroundPrimitive=Oo,zc.HeightReference=No,zc.HorizontalOrigin=Lo,zc.Imagery=Fo,zc.ImageryLayer=Bo,zc.ImageryLayerCollection=Vo,zc.ImageryLayerFeatureInfo=zo,zc.ImageryProvider=ko,zc.ImageryState=Uo,zc.Label=Go,zc.LabelCollection=Wo,zc.LabelStyle=Ho,zc.MapboxImageryProvider=qo,zc.Material=jo,zc.MaterialAppearance=Yo,zc.Model=Xo,zc.ModelAnimation=Zo,zc.ModelAnimationCache=Ko,zc.ModelAnimationCollection=Jo,zc.ModelAnimationLoop=Qo,zc.ModelAnimationState=$o,zc.ModelMaterial=ea,zc.ModelMesh=ta,zc.ModelNode=ra,zc.Moon=ia,zc.NeverTileDiscardPolicy=na,zc.OIT=oa,zc.OpenStreetMapImageryProvider=aa,zc.OrthographicFrustum=sa,zc.Pass=la,zc.PerInstanceColorAppearance=ua,zc.PerformanceDisplay=ca,zc.PerspectiveFrustum=ha,zc.PerspectiveOffCenterFrustum=da,zc.PickDepth=pa,zc.PointPrimitive=ma,zc.PointPrimitiveCollection=fa,zc.Polygon=va,zc.Polyline=_a,zc.PolylineCollection=ga,zc.PolylineColorAppearance=ya,zc.PolylineMaterialAppearance=Ca,zc.Primitive=Ea,zc.PrimitiveCollection=Sa,zc.PrimitivePipeline=wa,zc.PrimitiveState=Ta,zc.QuadtreeOccluders=ba,zc.QuadtreePrimitive=xa,zc.QuadtreeTile=Pa,zc.QuadtreeTileLoadState=Aa,zc.QuadtreeTileProvider=Ia,zc.RectanglePrimitive=Ma,zc.Scene=Da,zc.SceneMode=Ra,zc.SceneTransforms=Oa,zc.SceneTransitioner=Na,zc.ScreenSpaceCameraController=La,zc.SingleTileImageryProvider=Fa,zc.SkyAtmosphere=Ba,zc.SkyBox=Va,zc.StencilFunction=za,zc.StencilOperation=ka,zc.Sun=Ua,zc.SunPostProcess=Ga,zc.TerrainState=Wa,zc.TextureAtlas=Ha,zc.TileCoordinatesImageryProvider=qa,zc.TileDiscardPolicy=ja,zc.TileImagery=Ya,zc.TileMapServiceImageryProvider=Xa,zc.TileReplacementQueue=Za,zc.TileState=Ka,zc.TileTerrain=Ja,zc.TweenCollection=Qa,zc.UrlTemplateImageryProvider=$a,zc.VerticalOrigin=es,zc.ViewportQuad=ts,zc.WebMapServiceImageryProvider=rs,zc.WebMapTileServiceImageryProvider=is,zc.createTangentSpaceDebugPrimitive=ns,zc.getModelAccessor=os,zc.modelMaterialsCommon=as,zc.terrainAttributeLocations=ss,zc._shaders.AdjustTranslucentFS=ls,zc._shaders.AllMaterialAppearanceFS=us,zc._shaders.AllMaterialAppearanceVS=cs,zc._shaders.BasicMaterialAppearanceFS=hs,zc._shaders.BasicMaterialAppearanceVS=ds,zc._shaders.EllipsoidSurfaceAppearanceFS=ps,zc._shaders.EllipsoidSurfaceAppearanceVS=ms,zc._shaders.PerInstanceColorAppearanceFS=fs,zc._shaders.PerInstanceColorAppearanceVS=vs,zc._shaders.PerInstanceFlatColorAppearanceFS=_s,zc._shaders.PerInstanceFlatColorAppearanceVS=gs,zc._shaders.PolylineColorAppearanceVS=ys,zc._shaders.PolylineMaterialAppearanceVS=Cs,zc._shaders.TexturedMaterialAppearanceFS=Es,zc._shaders.TexturedMaterialAppearanceVS=Ss,zc._shaders.BillboardCollectionFS=ws,zc._shaders.BillboardCollectionVS=Ts,zc._shaders.degreesPerRadian=bs,zc._shaders.depthRange=xs,zc._shaders.epsilon1=Ps,zc._shaders.epsilon2=As,zc._shaders.epsilon3=Is,zc._shaders.epsilon4=Ms,zc._shaders.epsilon5=Ds,zc._shaders.epsilon6=Rs,zc._shaders.epsilon7=Os,zc._shaders.infinity=Ns,zc._shaders.oneOverPi=Ls,zc._shaders.oneOverTwoPi=Fs,zc._shaders.pi=Bs,zc._shaders.piOverFour=Vs,zc._shaders.piOverSix=zs,zc._shaders.piOverThree=ks,zc._shaders.piOverTwo=Us,zc._shaders.radiansPerDegree=Gs,zc._shaders.sceneMode2D=Ws,zc._shaders.sceneMode3D=Hs,zc._shaders.sceneModeColumbusView=qs,zc._shaders.sceneModeMorphing=js,zc._shaders.solarRadius=Ys,zc._shaders.threePiOver2=Xs,zc._shaders.twoPi=Zs,zc._shaders.webMercatorMaxLatitude=Ks,zc._shaders.CzmBuiltins=Js,zc._shaders.RGBToXYZ=Qs,zc._shaders.XYZToRGB=$s,zc._shaders.alphaWeight=el,zc._shaders.antialias=tl,zc._shaders.columbusViewMorph=rl,zc._shaders.computePosition=il,zc._shaders.cosineAndSine=nl,zc._shaders.decompressTextureCoordinates=ol,zc._shaders.eastNorthUpToEyeCoordinates=al,zc._shaders.ellipsoidContainsPoint=sl,zc._shaders.ellipsoidNew=ll,zc._shaders.ellipsoidWgs84TextureCoordinates=ul,zc._shaders.equalsEpsilon=cl,zc._shaders.eyeOffset=hl,zc._shaders.eyeToWindowCoordinates=dl,zc._shaders.fog=pl,zc._shaders.geodeticSurfaceNormal=ml,zc._shaders.getDefaultMaterial=fl,zc._shaders.getLambertDiffuse=vl,zc._shaders.getSpecular=_l,zc._shaders.getWaterNoise=gl,zc._shaders.getWgs84EllipsoidEC=yl,zc._shaders.hue=Cl,zc._shaders.isEmpty=El,zc._shaders.isFull=Sl,zc._shaders.latitudeToWebMercatorFraction=wl,zc._shaders.luminance=Tl,zc._shaders.metersPerPixel=bl,zc._shaders.modelToWindowCoordinates=xl,zc._shaders.multiplyWithColorBalance=Pl,zc._shaders.nearFarScalar=Al,zc._shaders.octDecode=Il,zc._shaders.packDepth=Ml,zc._shaders.phong=Dl,zc._shaders.pointAlongRay=Rl,zc._shaders.rayEllipsoidIntersectionInterval=Ol,zc._shaders.saturation=Nl,zc._shaders.signNotZero=Ll,zc._shaders.tangentToEyeSpaceMatrix=Fl,zc._shaders.translateRelativeToEye=Bl,zc._shaders.translucentPhong=Vl,zc._shaders.transpose=zl,zc._shaders.unpackDepth=kl,zc._shaders.windowToEyeCoordinates=Ul,zc._shaders.depthRangeStruct=Gl,zc._shaders.ellipsoid=Wl,zc._shaders.material=Hl,zc._shaders.materialInput=ql,zc._shaders.ray=jl,zc._shaders.raySegment=Yl,zc._shaders.CompositeOITFS=Xl,zc._shaders.DepthPlaneFS=Zl,zc._shaders.DepthPlaneVS=Kl,zc._shaders.EllipsoidFS=Jl,zc._shaders.EllipsoidVS=Ql,zc._shaders.GlobeFS=$l,zc._shaders.GlobeFSPole=eu,zc._shaders.GlobeVS=tu,zc._shaders.GlobeVSPole=ru,zc._shaders.GroundAtmosphere=iu,zc._shaders.BumpMapMaterial=nu,zc._shaders.CheckerboardMaterial=ou,zc._shaders.DotMaterial=au,zc._shaders.FadeMaterial=su,zc._shaders.GridMaterial=lu,zc._shaders.NormalMapMaterial=uu,zc._shaders.PolylineArrowMaterial=cu,zc._shaders.PolylineGlowMaterial=hu,zc._shaders.PolylineOutlineMaterial=du,zc._shaders.RimLightingMaterial=pu,zc._shaders.StripeMaterial=mu,zc._shaders.Water=fu,zc._shaders.PointPrimitiveCollectionFS=vu,zc._shaders.PointPrimitiveCollectionVS=_u,zc._shaders.PolylineCommon=gu,zc._shaders.PolylineFS=yu,zc._shaders.PolylineVS=Cu,zc._shaders.AdditiveBlend=Eu,zc._shaders.BrightPass=Su,zc._shaders.FXAA=wu,zc._shaders.GaussianBlur1D=Tu,zc._shaders.PassThrough=bu,zc._shaders.ReprojectWebMercatorFS=xu,zc._shaders.ReprojectWebMercatorVS=Pu,zc._shaders.ShadowVolumeFS=Au,zc._shaders.ShadowVolumeVS=Iu,zc._shaders.SkyAtmosphereFS=Mu,zc._shaders.SkyAtmosphereVS=Du,zc._shaders.SkyBoxFS=Ru,zc._shaders.SkyBoxVS=Ou,zc._shaders.SunFS=Nu,zc._shaders.SunTextureFS=Lu,zc._shaders.SunVS=Fu,zc._shaders.ViewportQuadFS=Bu,zc._shaders.ViewportQuadVS=Vu,zc.Autolinker=zu,zc.Tween=ku,zc.Uri=Uu,zc.gltfDefaults=Gu,zc["knockout-3.2.0"]=Wu,zc["knockout-es5"]=Hu,zc.knockout=qu,zc.measureText=ju,zc["mersenne-twister"]=Yu,zc.sprintf=Xu,zc.topojson=Zu,zc.when=Ku,zc.zip=Ju,zc.Animation=Qu,zc.AnimationViewModel=$u,zc.BaseLayerPicker=ec,zc.BaseLayerPickerViewModel=tc,zc.ProviderViewModel=rc,zc.createDefaultImageryProviderViewModels=ic,zc.createDefaultTerrainProviderViewModels=nc,zc.CesiumInspector=oc,zc.CesiumInspectorViewModel=ac,zc.CesiumWidget=sc,zc.ClockViewModel=lc,zc.Command=uc,zc.FullscreenButton=cc,zc.FullscreenButtonViewModel=hc,zc.Geocoder=dc,zc.GeocoderViewModel=pc,zc.HomeButton=mc,zc.HomeButtonViewModel=fc,zc.InfoBox=vc,zc.InfoBoxViewModel=_c,zc.NavigationHelpButton=gc,zc.NavigationHelpButtonViewModel=yc,zc.PerformanceWatchdog=Cc,zc.PerformanceWatchdogViewModel=Ec,zc.SceneModePicker=Sc,zc.SceneModePickerViewModel=wc,zc.SelectionIndicator=Tc,zc.SelectionIndicatorViewModel=bc,zc.SvgPathBindingHandler=xc,zc.Timeline=Pc,zc.TimelineHighlightRange=Ac,zc.TimelineTrack=Ic,zc.ToggleButtonViewModel=Mc,zc.Viewer=Dc,zc.viewerCesiumInspectorMixin=Rc,zc.viewerDragDropMixin=Oc,zc.viewerPerformanceWatchdogMixin=Nc,zc.createCommand=Lc,zc.getElement=Fc,zc.subscribeAndEvaluate=Bc,zc.createTaskProcessorWorker=Vc,zc}),t(["Cesium"],function(e){"use strict";var t="undefined"!=typeof window?window:"undefined"!=typeof self?self:{};t.Cesium=e},void 0,!0)}();// Ol3-Cesium. See https://github.com/openlayers/ol3-cesium/ +// Ol3-Cesium. See https://github.com/openlayers/ol3-cesium/ // License: https://github.com/openlayers/ol3-cesium/blob/master/LICENSE -// Version: v1.9-33-gc68901a - -(function(){var k,m=this;function n(a){return void 0!==a} -function p(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; -else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function aa(a){var b=p(a);return"array"==b||"object"==b&&"number"==typeof a.length}function q(a){return"string"==typeof a}function ba(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function t(a){return a[ca]||(a[ca]=++da)}var ca="closure_uid_"+(1E9*Math.random()>>>0),da=0;function ea(a,b,c){return a.call.apply(a.bind,arguments)} -function fa(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function ha(a,b,c){ha=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?ea:fa;return ha.apply(null,arguments)}var ia=Date.now||function(){return+new Date}; -function u(a,b){var c=a.split("."),d=m;c[0]in d||!d.execScript||d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&n(b)?d[e]=b:d[e]?d=d[e]:d=d[e]={}}function v(a,b){function c(){}c.prototype=b.prototype;a.Ra=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.Ua=function(a,c,f){for(var g=Array(arguments.length-2),h=2;h<arguments.length;h++)g[h-2]=arguments[h];return b.prototype[c].apply(a,g)}};function ja(a,b){for(var c in a)b.call(void 0,a[c],c,a)}var ka="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function la(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<ka.length;f++)c=ka[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};function w(a,b){this.map=a;this.i=a.getView();this.scene=b;a.getLayerGroup().getLayers();this.b=a.getLayerGroup();this.A={};this.g={};this.c={}}w.prototype.Z=function(){ma(this);na(this,this.b)};w.prototype.W=function(){}; -function na(a,b){for(var c=[b];0<c.length;){var d=c.splice(0,1)[0],e=t(d),f=null;d instanceof ol.layer.Group?(oa(a,d),(f=a.T(d))||d.getLayers().forEach(function(a){c.push(a)})):f=a.T(d);null!==f&&(a.A[e]=f,a.g[e]=d.on("change:zIndex",a.W,a),f.forEach(function(a){this.aa(a)},a))}a.W()}function pa(a,b){var c=t(b),d=a.A[c];d&&(d.forEach(function(a){this.ma(a,!1);this.ea(a)},a),ol.Observable.unByKey(a.g[c]),delete a.g[c]);delete a.A[c];return!!d} -function qa(a,b){if(b!==a.b){var c=t(b);a.c[c].forEach(function(a){ol.Observable.unByKey(a)});delete a.c[c];delete a.A[c]}}function ra(a,b){if(b)for(var c=[b];0<c.length;){var d=c.splice(0,1)[0],e=pa(a,d);d instanceof ol.layer.Group&&(qa(a,d),e&&d.getLayers().forEach(function(a){c.push(a)}))}} -function oa(a,b){var c=t(b),d=[];a.c[c]=d;var e=[],f=function(){var a=b.getLayers();n(a)&&(e=[a.on("add",function(a){na(this,a.element)},this),a.on("remove",function(a){ra(this,a.element)},this)],d.push.apply(d,e))}.bind(a);f();d.push(b.on("change:layers",function(){e.forEach(function(a){var b=d.indexOf(a);0<=b&&d.splice(b,1);ol.Observable.unByKey(a)});f()}))}function ma(a){a.la(!0);ja(a.j,function(a){a.forEach(ol.Observable.unByKey)});ja(a.l,ol.Observable.unByKey);a.j={};a.l={};a.A={}};function x(a,b){this.c=a;this.f=a.f;this.h=b;this.b=this.a.bind(this);this.l=new Cesium.Matrix4;this.j=0;this.g=!1;this.f.postRender.addEventListener(this.qa.bind(this));this.i="";this.i="onwheel"in this.f.canvas?"wheel":document.onmousewheel?"mousewheel":"DOMMouseScroll";this.oa=Cesium.loadWithXhr.load;this.pa=Cesium.TaskProcessor.prototype.b;this.na=Cesium.Camera.prototype.setView;this.$=Cesium.Camera.prototype.move;this.Sa=Cesium.Camera.prototype.rotate;this.H=Cesium.Camera.prototype.lookAt;this.D= -Cesium.Camera.prototype.flyTo;sa(this)}function y(a,b){a.f.canvas.addEventListener(b,a.b,!1)} -function sa(a){y(a,"mousemove");y(a,"mousedown");y(a,"mouseup");y(a,"touchstart");y(a,"touchend");y(a,"touchmove");window.PointerEvent&&(y(a,"pointerdown"),y(a,"pointerup"),y(a,"pointermove"));y(a,a.i);window.addEventListener("resize",a.b,!1);Cesium.loadWithXhr.load=function(b,c,d,e,f,g,h,l,r){g.promise.always(a.b);a.oa(b,c,d,e,f,g,h,l,r)};Cesium.TaskProcessor.prototype.b=function(b,c){var d=a.pa.call(this,b,c),e=this;if(!e.a){var f=e._worker;e.a=f.onmessage;f.onmessage=function(b){e.a(b);a.a()}}return d}; -Cesium.Camera.prototype.setView=function(){a.na.apply(this,arguments);a.a()};Cesium.Camera.prototype.move=function(){a.$.apply(this,arguments);a.a()};Cesium.Camera.prototype.rotate=function(){a.Sa.apply(this,arguments);a.a()};Cesium.Camera.prototype.lookAt=function(){a.H.apply(this,arguments);a.a()};Cesium.Camera.prototype.flyTo=function(){a.D.apply(this,arguments);a.a()};a.c.o.getLayerGroup().on("change",a.b)} -x.prototype.qa=function(){var a=Date.now(),b=this.f,c=b.camera;Cesium.Matrix4.equalsEpsilon(this.l,c.viewMatrix,1E-5)||(this.j=a);var d=b.globe._surface,d=!d._tileProvider.ready||0<d._tileLoadQueue.length||0<d._debug.tilesWaitingForChildren,b=b.tweens;1E3>a-this.j||d||0!=b.length||(this.h&&console.log("stopping rendering @ "+Date.now()),this.c.Y(!0),this.g=!0);Cesium.Matrix4.clone(c.viewMatrix,this.l)};x.prototype.s=function(){this.a()}; -x.prototype.a=function(){this.h&&this.g&&console.log("starting rendering @ "+Date.now());Date.now();this.c.Y(!1);this.g=!1};x.prototype.ra=function(a){this.h=a};var ta=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")};function ua(a){if(!va.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(wa,"&"));-1!=a.indexOf("<")&&(a=a.replace(xa,"<"));-1!=a.indexOf(">")&&(a=a.replace(ya,">"));-1!=a.indexOf('"')&&(a=a.replace(za,"""));-1!=a.indexOf("'")&&(a=a.replace(Aa,"'"));-1!=a.indexOf("\x00")&&(a=a.replace(Ba,"�"));return a}var wa=/&/g,xa=/</g,ya=/>/g,za=/"/g,Aa=/'/g,Ba=/\x00/g,va=/[\x00&<>"']/; -function Ca(a,b){return a<b?-1:a>b?1:0};function Da(){};var A=Array.prototype;function Ea(a,b){A.forEach.call(a,b,void 0)}function Fa(a){var b=a.length;if(0<b){for(var c=Array(b),d=0;d<b;d++)c[d]=a[d];return c}return[]}function Ga(a,b){a.sort(b||Ha)}function Ia(a,b){for(var c=0;c<a.length;c++)a[c]={index:c,value:a[c]};var d=b||Ha;Ga(a,function(a,b){return d(a.value,b.value)||a.index-b.index});for(c=0;c<a.length;c++)a[c]=a[c].value}function Ha(a,b){return a>b?1:a<b?-1:0};var B;a:{var Ja=m.navigator;if(Ja){var Ka=Ja.userAgent;if(Ka){B=Ka;break a}}B=""}function C(a){return-1!=B.indexOf(a)};var La=C("Opera")||C("OPR"),D=C("Trident")||C("MSIE"),Ma=C("Edge"),E=C("Gecko")&&!(-1!=B.toLowerCase().indexOf("webkit")&&!C("Edge"))&&!(C("Trident")||C("MSIE"))&&!C("Edge"),G=-1!=B.toLowerCase().indexOf("webkit")&&!C("Edge");G&&C("Mobile");C("Macintosh");C("Windows");C("Linux")||C("CrOS");var Na=m.navigator||null;Na&&(Na.appVersion||"").indexOf("X11");C("Android");!C("iPhone")||C("iPod")||C("iPad");C("iPad"); -function Oa(){var a=B;if(E)return/rv\:([^\);]+)(\)|;)/.exec(a);if(Ma)return/Edge\/([\d\.]+)/.exec(a);if(D)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(G)return/WebKit\/(\S+)/.exec(a)}function Pa(){var a=m.document;return a?a.documentMode:void 0}var Qa=function(){if(La&&m.opera){var a=m.opera.version;return"function"==p(a)?a():a}var a="",b=Oa();b&&(a=b?b[1]:"");return D&&(b=Pa(),b>parseFloat(a))?String(b):a}(),Ra={}; -function H(a){var b;if(!(b=Ra[a])){b=0;for(var c=ta(String(Qa)).split("."),d=ta(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&f<e;f++){var g=c[f]||"",h=d[f]||"",l=RegExp("(\\d*)(\\D*)","g"),r=RegExp("(\\d*)(\\D*)","g");do{var z=l.exec(g)||["","",""],F=r.exec(h)||["","",""];if(0==z[0].length&&0==F[0].length)break;b=Ca(0==z[1].length?0:parseInt(z[1],10),0==F[1].length?0:parseInt(F[1],10))||Ca(0==z[2].length,0==F[2].length)||Ca(z[2],F[2])}while(0==b)}b=Ra[a]=0<=b}return b} -var Sa=m.document,Ta=Sa&&D?Pa()||("CSS1Compat"==Sa.compatMode?parseInt(Qa,10):5):void 0;var Ua=!D||9<=Ta,Va=D&&!H("9");!G||H("528");E&&H("1.9b")||D&&H("8")||La&&H("9.5")||G&&H("528");E&&!H("8")||D&&H("9");function I(){0!=Wa&&t(this);this.h=this.h;this.H=this.H}var Wa=0;I.prototype.h=!1;function J(a,b){this.type=a;this.a=this.target=b}J.prototype.b=function(){};function Xa(a){Xa[" "](a);return a}Xa[" "]=function(){};function K(a,b){J.call(this,a?a.type:"");this.c=this.a=this.target=null;if(a){this.type=a.type;this.target=a.target||a.srcElement;this.a=b;var c=a.relatedTarget;if(c&&E)try{Xa(c.nodeName)}catch(d){}this.c=a;a.defaultPrevented&&this.b()}}v(K,J);K.prototype.b=function(){K.Ra.b.call(this);var a=this.c;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Va)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var L="closure_listenable_"+(1E6*Math.random()|0),Ya=0;function Za(a,b,c,d,e){this.listener=a;this.proxy=null;this.src=b;this.type=c;this.M=!!d;this.O=e;++Ya;this.G=this.L=!1}function $a(a){a.G=!0;a.listener=null;a.proxy=null;a.src=null;a.O=null};function M(a){this.src=a;this.a={};this.b=0}M.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.a[f];a||(a=this.a[f]=[],this.b++);var g=ab(a,b,d,e);-1<g?(b=a[g],c||(b.L=!1)):(b=new Za(b,this.src,f,!!d,e),b.L=c,a.push(b));return b};M.prototype.remove=function(a,b,c,d){a=a.toString();if(!(a in this.a))return!1;var e=this.a[a];b=ab(e,b,c,d);return-1<b?($a(e[b]),A.splice.call(e,b,1),0==e.length&&(delete this.a[a],this.b--),!0):!1}; -function bb(a,b){var c=b.type;if(c in a.a){var d=a.a[c],e=A.indexOf.call(d,b,void 0),f;(f=0<=e)&&A.splice.call(d,e,1);f&&($a(b),0==a.a[c].length&&(delete a.a[c],a.b--))}}function ab(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e];if(!f.G&&f.listener==b&&f.M==!!c&&f.O==d)return e}return-1};var eb="closure_lm_"+(1E6*Math.random()|0),fb={},gb=0;function hb(a,b,c,d,e){if("array"==p(b)){for(var f=0;f<b.length;f++)hb(a,b[f],c,d,e);return null}c=ib(c);return a&&a[L]?a.l(b,c,d,e):jb(a,b,c,!1,d,e)} -function jb(a,b,c,d,e,f){if(!b)throw Error("Invalid event type");var g=!!e,h=N(a);h||(a[eb]=h=new M(a));c=h.add(b,c,d,e,f);if(c.proxy)return c;d=kb();c.proxy=d;d.src=a;d.listener=c;if(a.addEventListener)a.addEventListener(b.toString(),d,g);else if(a.attachEvent)a.attachEvent(lb(b.toString()),d);else throw Error("addEventListener and attachEvent are unavailable.");gb++;return c} -function kb(){var a=mb,b=Ua?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b}function nb(a,b,c,d,e){if("array"==p(b))for(var f=0;f<b.length;f++)nb(a,b[f],c,d,e);else c=ib(c),a&&a[L]?a.C.add(String(b),c,!0,d,e):jb(a,b,c,!0,d,e)} -function ob(a,b,c,d,e){if("array"==p(b))for(var f=0;f<b.length;f++)ob(a,b[f],c,d,e);else(c=ib(c),a&&a[L])?a.C.remove(String(b),c,d,e):a&&(a=N(a))&&(b=a.a[b.toString()],a=-1,b&&(a=ab(b,c,!!d,e)),(c=-1<a?b[a]:null)&&O(c))}function O(a){if("number"!=typeof a&&a&&!a.G){var b=a.src;if(b&&b[L])bb(b.C,a);else{var c=a.type,d=a.proxy;b.removeEventListener?b.removeEventListener(c,d,a.M):b.detachEvent&&b.detachEvent(lb(c),d);gb--;(c=N(b))?(bb(c,a),0==c.b&&(c.src=null,b[eb]=null)):$a(a)}}} -function lb(a){return a in fb?fb[a]:fb[a]="on"+a}function pb(a,b,c,d){var e=!0;if(a=N(a))if(b=a.a[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var f=b[a];f&&f.M==c&&!f.G&&(f=qb(f,d),e=e&&!1!==f)}return e}function qb(a,b){var c=a.listener,d=a.O||a.src;a.L&&O(a);return c.call(d,b)} -function mb(a,b){if(a.G)return!0;if(!Ua){var c;if(!(c=b))a:{c=["window","event"];for(var d=m,e;e=c.shift();)if(null!=d[e])d=d[e];else{c=null;break a}c=d}e=c;c=new K(e,this);d=!0;if(!(0>e.keyCode||void 0!=e.returnValue)){a:{var f=!1;if(0==e.keyCode)try{e.keyCode=-1;break a}catch(l){f=!0}if(f||void 0==e.returnValue)e.returnValue=!0}e=[];for(f=c.a;f;f=f.parentNode)e.push(f);for(var f=a.type,g=e.length-1;0<=g;g--){c.a=e[g];var h=pb(e[g],f,!0,c),d=d&&h}for(g=0;g<e.length;g++)c.a=e[g],h=pb(e[g],f,!1,c), -d=d&&h}return d}return qb(a,new K(b,this))}function N(a){a=a[eb];return a instanceof M?a:null}var rb="__closure_events_fn_"+(1E9*Math.random()>>>0);function ib(a){if("function"==p(a))return a;a[rb]||(a[rb]=function(b){return a.handleEvent(b)});return a[rb]};function sb(a){var b;b=b||0;return function(){return a.apply(this,Array.prototype.slice.call(arguments,0,b))}};function P(a,b,c){I.call(this);this.a=null;this.g=!1;this.l=a;this.j=c;this.b=b||window;this.c=ha(this.i,this)}v(P,I);P.prototype.start=function(){tb(this);this.g=!1;var a=ub(this),b=vb(this);a&&!b&&this.b.mozRequestAnimationFrame?(this.a=hb(this.b,"MozBeforePaint",this.c),this.b.mozRequestAnimationFrame(null),this.g=!0):this.a=a&&b?a.call(this.b,this.c):this.b.setTimeout(sb(this.c),20)}; -function tb(a){if(null!=a.a){var b=ub(a),c=vb(a);b&&!c&&a.b.mozRequestAnimationFrame?O(a.a):b&&c?c.call(a.b,a.a):a.b.clearTimeout(a.a)}a.a=null}P.prototype.i=function(){this.g&&this.a&&O(this.a);this.a=null;this.l.call(this.j,ia())};function ub(a){a=a.b;return a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||null} -function vb(a){a=a.b;return a.cancelAnimationFrame||a.cancelRequestAnimationFrame||a.webkitCancelRequestAnimationFrame||a.mozCancelRequestAnimationFrame||a.oCancelRequestAnimationFrame||a.msCancelRequestAnimationFrame||null};function Q(a,b){this.a=a;this.b=null;this.l=n(b)?b:null;this.h=!1;this.j=new Cesium.Event;this.c=document.createElement(wb);this.c.width=1;this.c.height=1;this.a.on("change",function(){xb(this)},this);xb(this)} -Object.defineProperties(Q.prototype,{ready:{get:function(){return this.h}},rectangle:{get:function(){return this.s}},tileWidth:{get:function(){var a=this.a.getTileGrid();return null===a?256:a.getTileSize(0)}},tileHeight:{get:function(){return this.tileWidth}},maximumLevel:{get:function(){var a=this.a.getTileGrid();return null===a?18:a.getMaxZoom()}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this.g}},tileDiscardPolicy:{get:function(){}},errorEvent:{get:function(){return this.j}}, -credit:{get:function(){return this.i}},proxy:{get:function(){}},hasAlphaChannel:{get:function(){return!0}},Va:{get:function(){}}});function xb(a){if(!a.h&&"ready"==a.a.getState()){var b=a.a.getProjection();a.b=null!=b?b:a.l;if(a.b==ol.proj.get("EPSG:4326"))a.g=new Cesium.GeographicTilingScheme;else if(a.b==ol.proj.get("EPSG:3857"))a.g=new Cesium.WebMercatorTilingScheme;else return;a.s=a.g.rectangle;b=yb(a.a);a.i=null===b?void 0:b;a.h=!0}} -function yb(a){var b="",c=a.getAttributions();null===c||c.forEach(function(a){b+=a.getHTML().replace(/<\/?[^>]+(>|$)/g,"")+" "});var d,e;0==b.length&&(a=a.getLogo(),n(a)&&("string"==typeof a?d=a:(d=a.src,e=a.href)));return n(d)||0<b.length?new Cesium.Credit(b,d,e):null}Q.prototype.getTileCredits=function(){};Q.prototype.getTileCredits=Q.prototype.getTileCredits; -Q.prototype.requestImage=function(a,b,c){var d=this.a.getTileUrlFunction();if(null===d||null===this.b)return this.c;a=d([this.g instanceof Cesium.GeographicTilingScheme?c+1:c,a,-b-1],1,this.b);return n(a)?Cesium.ImageryProvider.loadImage(this,a):this.c};Q.prototype.requestImage=Q.prototype.requestImage;function zb(a,b,c,d,e){var f=Cesium.Math.clamp,g=Cesium.defaultValue;e=e||{};var h=g(e.duration,500),l=g(e.easing,ol.easing.linear),r=e.callback,z=ia(),F=0,cb=new Cesium.Matrix4,db=new P(function(e){e=l(f((e-z)/h,0,1));a.transform.clone(cb);var g=(e-F)*b;F=e;a.lookAtTransform(d);a.rotate(c,g);a.lookAtTransform(cb);1>e?db.start():r&&r()});db.start()}function Ab(a,b){var c=a.camera.getPickRay(b);return a.globe.pick(c,a)||a.camera.pickEllipsoid(b)} -function Bb(a){var b=a.canvas,b=new Cesium.Cartesian2(b.clientWidth/2,b.clientHeight/2);return Ab(a,b)}function Cb(a,b,c){var d=new Cesium.Cartesian3,e=new Cesium.Cartesian3,f=new Cesium.Cartesian3;Cesium.Cartesian3.normalize(a,d);Cesium.Cartesian3.normalize(b,e);Cesium.Cartesian3.cross(d,e,f);a=Cesium.Cartesian3.dot(d,e);b=Cesium.Cartesian3.magnitude(f);c=Cesium.Cartesian3.dot(c,f);f=Math.atan2(b,a);return 0<=c?f:-f} -function Db(a,b){var c=a.camera,d=c.frustum.fovy/2,e;e=a.camera;var f=e.direction,g=Cesium.Quaternion.fromAxisAngle(e.right,e.frustum.fovy/2),g=Cesium.Matrix3.fromQuaternion(g),h=new Cesium.Cartesian3;Cesium.Matrix3.multiplyByVector(g,f,h);e=new Cesium.Ray(e.position,h);e=Cesium.Cartesian3.clone(e.direction);Cesium.Cartesian3.negate(e,e);f=new Cesium.Cartesian3;Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(b,f);g=new Cesium.Cartesian3;Cesium.Cartesian3.negate(c.right,g);return Cb(f,e,g)+d} -function Eb(a,b,c){n(c)&&(c=c.getHeight(b),b.height=n(c)?c:0);c=Cesium.Ellipsoid.WGS84;b=c.cartographicToCartesian(b);var d=a.position,e=new Cesium.Cartesian3;c.geocentricSurfaceNormal(d,e);a.lookAt(d,b,e)}function Fb(a,b){if(null===a||null===b)return null;var c=ol.proj.transformExtent(a,b,"EPSG:4326");return Cesium.Rectangle.fromDegrees(c[0],c[1],c[2],c[3])} -function Gb(a,b){if(!(a instanceof ol.layer.Tile))return null;var c=null,c=a.getSource();if(!(c instanceof ol.source.WMTS)&&c instanceof ol.source.TileImage){var d=c.getProjection();if(null===d)d=b;else if(d!==b)return null;var e=d===ol.proj.get("EPSG:3857"),d=d===ol.proj.get("EPSG:4326");if(e||d)c=new Q(c,b);else return null}else return null;e={};d=a.getExtent();null!=d&&null!==b&&(e.rectangle=Fb(d,b));return new Cesium.ImageryLayer(c,e)} -function Hb(a,b){var c=a.getOpacity();n(c)&&(b.alpha=c);c=a.getVisible();n(c)&&(b.show=c)}function R(a){return 2<a.length?Cesium.Cartesian3.fromDegrees(a[0],a[1],a[2]):Cesium.Cartesian3.fromDegrees(a[0],a[1])}function Ib(a){for(var b=[],c=0;c<a.length;++c)b.push(R(a[c]));return b}function S(a,b){var c=ol.proj.get("EPSG:4326"),d=ol.proj.get(b);if(d!==c){var e=a.getProperties();a=a.clone();a.transform(d,c);a.setProperties(e)}return a} -function Jb(a){a=a||"black";if(Array.isArray(a))return new Cesium.Color(Cesium.Color.byteToFloat(a[0]),Cesium.Color.byteToFloat(a[1]),Cesium.Color.byteToFloat(a[2]),a[3]);if("string"==typeof a)return Cesium.Color.fromCssColorString(a)};function T(a,b){this.f=a;this.b=a.camera;this.o=b;this.j=this.a=null;this.h=this.c=Kb;this.g=this.i=0;this.s=null;this.l=!1;this.o.on("change:view",function(){Lb(this,this.o.getView())},this);Lb(this,this.o.getView())}function Kb(a,b,c){c=c||a.length;if(b)for(var d=0;d<c;++d)b[d]=a[d];return a} -function Lb(a,b){null!==a.a&&(ol.Observable.unByKey(a.j),a.j=null);a.a=b;if(null===b)a.c=Kb,a.h=Kb;else{var c=ol.proj.getTransform(b.getProjection(),"EPSG:4326"),d=ol.proj.getTransform("EPSG:4326",b.getProjection());a.c=c;a.h=d;a.j=b.on("propertychange",a.Ca,a);a.K()}}k=T.prototype;k.Ca=function(){this.l||this.K()};k.Oa=function(a){null===this.a||this.a.setRotation(a)};k.Ea=function(){if(null!==this.a){var a=this.a.getRotation();return n(a)?a:0}};k.Qa=function(a){this.i=a;Mb(this)};k.Ba=function(){return this.i}; -k.Ma=function(a){this.g=a;Mb(this);this.B()};k.ya=function(){return this.g};k.Ha=function(a){null===this.a||this.a.setCenter(a)};k.getCenter=function(){return null===this.a?void 0:this.a.getCenter()};k.Ia=function(a){null!==this.c&&(a=this.c(a),a=new Cesium.Cartographic(a[0]*Math.PI/180,a[1]*Math.PI/180,this.ka()),this.b.position=Cesium.Ellipsoid.WGS84.cartographicToCartesian(a),this.B())}; -k.Fa=function(){if(null!==this.h){var a=Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.b.position);return this.h([180*a.longitude/Math.PI,180*a.latitude/Math.PI])}};k.La=function(a){var b=Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.b.position);b.height=a;this.b.position=Cesium.Ellipsoid.WGS84.cartographicToCartesian(b);this.B()};k.ka=function(){return Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.b.position).height}; -k.Ga=function(a){null!==this.c&&(a=this.c(a),a=Cesium.Cartographic.fromDegrees(a[0],a[1]),Eb(this.b,a,this.f.globe),this.B())}; -function Mb(a){if(null!==a.a&&null!==a.c){var b=a.a.getCenter();if(b){b=a.c(b);b=new Cesium.Cartographic(b[0]*Math.PI/180,b[1]*Math.PI/180);if(a.f.globe){var c=a.f.globe.getHeight(b);b.height=n(c)?c:0}b=Cesium.Ellipsoid.WGS84.cartographicToCartesian(b);c={pitch:a.i-Cesium.Math.PI_OVER_TWO,heading:-a.a.getRotation(),roll:void 0};a.b.setView({destination:b,orientation:c});a.b.moveBackward(a.g);Nb(a,!0)}}} -k.K=function(){if(null!==this.a&&null!==this.c){var a=this.a.getCenter();if(null!=a){var b=this.c(a),a=this.a.getResolution(),a=n(a)?a:0,b=b[1]*Math.PI/180,c=this.f.canvas,d=this.b.frustum.fovy,e=this.a.getProjection().getMetersPerUnit();this.g=a*c.clientHeight*e*Math.cos(Math.abs(b))/2/Math.tan(d/2);Mb(this)}}}; -k.B=function(){if(null!==this.a&&null!==this.h){this.l=!0;var a=Cesium.Ellipsoid.WGS84,b=this.f,c=Bb(b),d=c;d||(d=b.globe,b=this.b.positionCartographic.clone(),d=d.getHeight(b),b.height=n(d)?d:0,d=Cesium.Ellipsoid.WGS84.cartographicToCartesian(b));this.g=Cesium.Cartesian3.distance(d,this.b.position);b=a.cartesianToCartographic(d);this.a.setCenter(this.h([180*b.longitude/Math.PI,180*b.latitude/Math.PI]));this.a.setResolution(Ob(this,this.g,b?b.latitude:0));if(c){d=this.b.position;b=new Cesium.Cartesian3; -a.geocentricSurfaceNormal(c,b);a=new Cesium.Cartesian3;Cesium.Cartesian3.subtract(d,c,a);Cesium.Cartesian3.normalize(a,a);var d=this.b.up,e=this.b.right,f=new Cesium.Cartesian3(-c.y,c.x,0),e=Cesium.Cartesian3.angleBetween(e,f),c=Cesium.Cartesian3.cross(c,d,new Cesium.Cartesian3).z;this.a.setRotation(0>c?e:-e);c=Math.acos(Cesium.Cartesian3.dot(b,a));this.i=isNaN(c)?0:c}else this.a.setRotation(this.b.heading),this.i=-this.b.pitch+Math.PI/2;this.l=!1}}; -function Nb(a,b){var c=a.s,d=a.b.viewMatrix;c&&Cesium.Matrix4.equalsEpsilon(c,d,1E-5)||(a.s=d.clone(),!0!==b&&a.B())}function Ob(a,b,c){var d=a.f.canvas,e=a.b.frustum.fovy;a=a.a.getProjection().getMetersPerUnit();return 2*b*Math.tan(e/2)/a/Math.cos(Math.abs(c))/d.clientHeight};function Pb(a,b){var c=new Cesium.BillboardCollection({scene:b}),d=new Cesium.PrimitiveCollection;this.b=[];this.a=new Cesium.PrimitiveCollection;this.c={projection:a,billboards:c,featureToCesiumMap:{},primitives:d};this.a.add(c);this.a.add(d)}Pb.prototype.destroy=function(){this.b.forEach(ol.Observable.unByKey);this.b.length=0};function U(){I.call(this);this.C=new M(this);this.s=this}v(U,I);U.prototype[L]=!0;U.prototype.removeEventListener=function(a,b,c,d){ob(this,a,b,c,d)};function Qb(a,b){var c=a.s,d=b,e=d.type||d;if(q(d))d=new J(d,c);else if(d instanceof J)d.target=d.target||c;else{var f=d,d=new J(e,c);la(d,f)}c=d.a=c;Rb(c,e,!0,d);Rb(c,e,!1,d)}U.prototype.l=function(a,b,c,d){return this.C.add(String(a),b,!1,c,d)}; -function Rb(a,b,c,d){if(b=a.C.a[String(b)]){b=b.concat();for(var e=!0,f=0;f<b.length;++f){var g=b[f];if(g&&!g.G&&g.M==c){var h=g.listener,l=g.O||g.src;g.L&&bb(a.C,g);e=!1!==h.call(l,d)&&e}}}};function V(a){a=n(a)?a:{};U.call(this);this.b=this.f=null;this.a=new Cesium.RectanglePrimitive({asynchronous:!1,rectangle:new Cesium.Rectangle,material:Cesium.Material.fromType(Cesium.Material.ColorType)});this.a.material.uniforms.color=new Cesium.Color(0,0,1,.5);this.c=n(a.Da)?a.Da:Cesium.KeyboardEventModifier.SHIFT;this.g=null}v(V,U); -V.prototype.D=function(a){var b=this.f.globe.ellipsoid;a=this.f.camera.getPickRay(a.position);a=this.f.globe.pick(a,this.f);n(a)&&(this.b.setInputAction(this.i.bind(this),Cesium.ScreenSpaceEventType.MOUSE_MOVE),this.b.setInputAction(this.j.bind(this),Cesium.ScreenSpaceEventType.LEFT_UP),n(this.c)&&(this.b.setInputAction(this.i.bind(this),Cesium.ScreenSpaceEventType.MOUSE_MOVE,this.c),this.b.setInputAction(this.j.bind(this),Cesium.ScreenSpaceEventType.LEFT_UP,this.c)),b=b.cartesianToCartographic(a), -a=this.a.rectangle,a.north=a.south=b.latitude,a.east=a.west=b.longitude,this.a.height=b.height,this.a.show=!0,Qb(this,{type:"boxstart",position:b}),this.f.primitives.contains(this.a)||this.f.primitives.add(this.a),this.f.screenSpaceCameraController.enableInputs=!1,this.g=b)}; -V.prototype.i=function(a){var b=this.f.globe.ellipsoid;a=this.f.camera.getPickRay(a.endPosition);a=this.f.globe.pick(a,this.f);n(a)&&(b=b.cartesianToCartographic(a),this.a.height=Math.max(this.a.height,b.height),b.latitude<this.g.latitude?this.a.rectangle.south=b.latitude:this.a.rectangle.north=b.latitude,b.longitude<this.g.longitude?this.a.rectangle.west=b.longitude:this.a.rectangle.east=b.longitude)}; -V.prototype.j=function(a){var b=this.f.globe.ellipsoid;a=this.f.camera.getPickRay(a.position);a=this.f.globe.pick(a,this.f);n(a)&&(b=b.cartesianToCartographic(a),this.a.show=!1,Qb(this,{type:"boxend",position:b}),this.b.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP),this.b.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE),n(this.c)&&(this.b.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP,this.c),this.b.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE,this.c)));this.f.screenSpaceCameraController.enableInputs= -!0};V.prototype.$=function(a){null===a?(this.f.primitives.contains(this.a)&&this.f.primitives.remove(this.a),null!==this.b&&(this.b.destroy(),this.b=null)):(this.b=new Cesium.ScreenSpaceEventHandler(a.canvas),this.b.setInputAction(this.D.bind(this),Cesium.ScreenSpaceEventType.LEFT_DOWN,this.c));this.f=a};function W(a){this.scene=a;this.a=this.Ka.bind(this)}k=W.prototype;k.Ka=function(a){var b=a.target,c=b.olcs_cancellers;if(c)if(a=a.feature,n(a)){var b=t(a),d=c[b];d&&(d(),delete c[b])}else{for(d in c)if(c.hasOwnProperty(d))c[d]();b.olcs_cancellers={}}}; -function Sb(a,b,c,d,e,f,g){var h={flat:!0,renderState:{depthTest:{enabled:!0}}};n(g)&&(h.renderState||(h.renderState={}),h.renderState.lineWidth=g);e=new Cesium.GeometryInstance({geometry:e,attributes:{color:Cesium.ColorGeometryInstanceAttribute.fromColor(f)}});a.N(b,c,d)==Cesium.HeightReference.CLAMP_TO_GROUND?a=new Cesium.GroundPrimitive({geometryInstance:e}):(a=new Cesium.PerInstanceColorAppearance(h),a=new Cesium.Primitive({geometryInstances:e,appearance:a}));d=a;d.olLayer=b;d.olFeature=c;return a} -function X(a,b){var c=a.getFill()?a.getFill().getColor():null,d=a.getStroke()?a.getStroke().getColor():null,e="black";d&&b?e=d:c&&(e=c);return Jb(e)}function Tb(a,b){var c=b.getStroke()?b.getStroke().getWidth():1;return Math.min(c,a.scene.maximumAliasedLineWidth)}function Ub(a,b,c,d,e,f,g){var h=X(g,!1),l=X(g,!0),r=new Cesium.PrimitiveCollection;g.getFill()&&(e=Sb(a,b,c,d,e,h),r.add(e));g.getStroke()&&(g=Tb(a,g),e=Sb(a,b,c,d,f,l,g),r.add(e));return r} -function Vb(a,b,c,d,e,f){var g;f instanceof Cesium.PrimitiveCollection?g=f:(g=new Cesium.PrimitiveCollection,g.add(f));if(!e.getText())return g;e=e.getText();(a=a.ga(b,c,d,e))&&g.add(a);return g}k.da=function(a,b,c,d){a=a.add(b);a.olLayer=c;a.olFeature=d;return a}; -k.fa=function(a,b,c,d,e){c=S(c,d);d=c.getCenter();var f=3==d.length?d[2]:0,g=d.slice();g[0]+=c.getRadius();d=R(d);var g=R(g),h=Cesium.Cartesian3.distance(d,g),g=new Cesium.CircleGeometry({center:d,radius:h,height:f});d=new Cesium.CircleOutlineGeometry({center:d,radius:h,extrudedHeight:f,height:f});d=Ub(this,a,b,c,g,d,e);return Vb(this,a,b,c,e,d)}; -k.U=function(a,b,c,d,e){c=S(c,d);var f=Ib(c.getCoordinates());d=new Cesium.PolylineMaterialAppearance({material:this.ia(0,e,!0)});f=new Cesium.PolylineGeometry({positions:f,width:Tb(this,e),vertexFormat:d.vertexFormat});d=new Cesium.Primitive({geometryInstances:new Cesium.GeometryInstance({geometry:f}),appearance:d});d.olLayer=a;d.olFeature=b;return Vb(this,a,b,c,e,d)}; -k.V=function(a,b,c,d,e){c=S(c,d);for(var f=c.getLinearRings(),g=d={},h=0;h<f.length;++h){var l=f[h].getCoordinates(),l=Ib(l);0==h?d.positions=l:(d.holes={positions:l},d=d.holes)}f=new Cesium.PolygonGeometry({polygonHierarchy:g,perPositionHeight:!0});d=new Cesium.PolygonOutlineGeometry({polygonHierarchy:d,perPositionHeight:!0});d=Ub(this,a,b,c,f,d,e);return Vb(this,a,b,c,e,d)}; -k.N=function(a,b,c){c=c.get("altitudeMode");n(c)||(c=b.get("altitudeMode"));n(c)||(c=a.get("altitudeMode"));a=Cesium.HeightReference.NONE;"clampToGround"===c?a=Cesium.HeightReference.CLAMP_TO_GROUND:"relativeToGround"===c&&(a=Cesium.HeightReference.RELATIVE_TO_GROUND);return a}; -k.R=function(a,b,c,d,e,f,g){c=S(c,d);var h=e.getImage();if(h){h instanceof ol.style.Icon&&h.load();var l=h.getImage(1),r=function(){if(null!==l&&(l instanceof HTMLCanvasElement||l instanceof Image||l instanceof HTMLImageElement)){var d=c.getCoordinates(),d=R(d),e,r=h.getOpacity();n(r)&&(e=new Cesium.Color(1,1,1,r));r=this.N(a,b,c);e=this.da(f,{image:l,color:e,heightReference:r,verticalOrigin:Cesium.VerticalOrigin.BOTTOM,position:d},a,b);g&&g(e)}}.bind(this);if(l instanceof Image&&(""==l.src||0==l.naturalHeight|| -0==l.naturalWidth||!l.complete)){var z=!1;d=a.getSource();d instanceof ol.source.ImageVector&&(d=d.getSource());d.on(["removefeature","clear"],this.a);d.olcs_cancellers=d.olcs_cancellers||{};d.olcs_cancellers[t(b)]=function(){z=!0};nb(l,"load",function(){f.isDestroyed()||z||r()})}else r()}return e.getText()?Vb(this,a,b,c,e,new Cesium.Primitive):null}; -k.ha=function(a,b,c,d,e,f,g){function h(c,f){var g=new Cesium.PrimitiveCollection;c.forEach(function(c){g.add(f(a,b,c,d,e))});return g}switch(c.getType()){case "MultiPoint":c=c.getPoints();if(e.getText()){var l=new Cesium.PrimitiveCollection;c.forEach(function(c){(c=this.R(a,b,c,d,e,f,g))&&l.add(c)}.bind(this));return l}c.forEach(function(c){this.R(a,b,c,d,e,f,g)});return null;case "MultiLineString":return c=c.getLineStrings(),h(c,this.U.bind(this));case "MultiPolygon":return c=c.getPolygons(),h(c, -this.V.bind(this));default:Da("Unhandled multi geometry type"+c.getType())}}; -k.ga=function(a,b,c,d){var e=d.getText(),f=new Cesium.LabelCollection({scene:this.scene}),g=ol.extent.getCenter(c.getExtent());if(c instanceof ol.geom.SimpleGeometry){var h=c.getFirstCoordinate();g[2]=3==h.length?h[2]:0}h={};h.position=R(g);h.text=e;h.heightReference=this.N(a,b,c);c=d.getOffsetX();e=d.getOffsetY();0!=c&&0!=e&&(c=new Cesium.Cartesian2(c,e),h.pixelOffset=c);c=d.getFont();null!=c&&(h.font=c);c=void 0;d.getFill()&&(h.fillColor=X(d,!1),c=Cesium.LabelStyle.FILL);d.getStroke()&&(h.outlineWidth= -Tb(this,d),h.outlineColor=X(d,!0),c=Cesium.LabelStyle.OUTLINE);d.getFill()&&d.getStroke()&&(c=Cesium.LabelStyle.FILL_AND_OUTLINE);h.style=c;switch(d.getTextAlign()){case "left":c=Cesium.HorizontalOrigin.LEFT;break;case "right":c=Cesium.HorizontalOrigin.RIGHT;break;default:c=Cesium.HorizontalOrigin.CENTER}h.horizontalOrigin=c;if(d.getTextBaseline()){var l;switch(d.getTextBaseline()){case "top":l=Cesium.VerticalOrigin.TOP;break;case "middle":l=Cesium.VerticalOrigin.CENTER;break;case "bottom":l=Cesium.VerticalOrigin.BOTTOM; -break;case "alphabetic":l=Cesium.VerticalOrigin.TOP;break;case "hanging":l=Cesium.VerticalOrigin.BOTTOM;break;default:d.getTextBaseline()}h.verticalOrigin=l}d=f.add(h);d.olLayer=a;d.olFeature=b;return f};k.ia=function(a,b,c){a=b.getFill();b=b.getStroke();if(c&&!b||!c&&!a)return null;a=c?b.getColor():a.getColor();a=Jb(a);return c&&b.getLineDash()?Cesium.Material.fromType("Stripe",{horizontal:!1,repeat:500,evenColor:a,oddColor:new Cesium.Color(0,0,0,0)}):Cesium.Material.fromType("Color",{color:a})}; -k.S=function(a,b,c,d){a=b.getStyleFunction();var e;n(a)&&(e=a.call(b,d));null==e&&null!=c&&(e=c(b,d));return n(e)?e[0]:null}; -k.P=function(a,b,c,d,e){function f(a){d.featureToCesiumMap[t(b)]=a}e=e||b.getGeometry();var g=d.projection;if(!e)return null;switch(e.getType()){case "GeometryCollection":var h=new Cesium.PrimitiveCollection;e.getGeometries().forEach(function(e){e&&(e=this.P(a,b,c,d,e))&&h.add(e)}.bind(this));return h;case "Point":return(e=this.R(a,b,e,g,c,d.billboards,f))?e:null;case "Circle":return this.fa(a,b,e,g,c);case "LineString":return this.U(a,b,e,g,c);case "Polygon":return this.V(a,b,e,g,c);case "MultiPoint":case "MultiLineString":case "MultiPolygon":return(e= -this.ha(a,b,e,g,c,d.billboards,f))?e:null;case "LinearRing":throw Error("LinearRing should only be part of polygon.");default:throw Error("Ol geom type not handled : "+e.getType());}}; -k.ja=function(a,b,c){var d=a.getSource();d instanceof ol.source.ImageVector&&(d=d.getSource());var d=d.getFeatures(),e=b.getProjection();b=b.getResolution();if(!n(b)||!e)throw Error("View not ready");for(var e=new Pb(e,this.scene),f=e.c,g=0;g<d.length;++g){var h=d[g];if(null!=h){var l;a instanceof ol.layer.Image?l=a.getSource().getStyleFunction():l=a.getStyleFunction();var r=this.S(0,h,l,b);r&&(r=this.P(a,h,r,f))&&(c[t(h)]=r,e.a.add(r))}}return e}; -k.convert=function(a,b,c,d){var e=b.getProjection();b=b.getResolution();if(!n(b)||!e)return null;var f;a instanceof ol.layer.Image?f=a.getSource().getStyleFunction():f=a.getStyleFunction();f=this.S(0,c,f,b);if(!f)return null;d.projection=e;return this.P(a,c,f,d)};var Wb=!D||9<=Ta;!E&&!D||D&&9<=Ta||E&&H("1.9.1");D&&H("9");var wb="CANVAS";function Xb(a){var b=document;return q(a)?b.getElementById(a):a} -function Yb(a){var b=a||document,c=null;if(b.getElementsByClassName)c=b.getElementsByClassName("ol-overlaycontainer")[0];else if(b.querySelectorAll&&b.querySelector)c=b.querySelector(".ol-overlaycontainer");else{var d,b=document;a=a||b;if(a.querySelectorAll&&a.querySelector)a=a.querySelectorAll(".ol-overlaycontainer");else if(a.getElementsByClassName){var e=a.getElementsByClassName("ol-overlaycontainer");a=e}else{e=a.getElementsByTagName("*");d={};for(b=c=0;a=e[b];b++){var f=a.className,g;if(g="function"== -typeof f.split)g=0<=A.indexOf.call(f.split(/\s+/),"ol-overlaycontainer",void 0);g&&(d[c++]=a)}d.length=c;a=d}c=a[0]}return c||null}function Zb(a,b){ja(b,function(b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:$b.hasOwnProperty(d)?a.setAttribute($b[d],b):0==d.lastIndexOf("aria-",0)||0==d.lastIndexOf("data-",0)?a.setAttribute(d,b):a[d]=b})} -var $b={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:"height",maxlength:"maxLength",role:"role",rowspan:"rowSpan",type:"type",usemap:"useMap",valign:"vAlign",width:"width"}; -function ac(a,b,c){var d=arguments,e=document,f=d[0],g=d[1];if(!Wb&&g&&(g.name||g.type)){f=["<",f];g.name&&f.push(' name="',ua(g.name),'"');if(g.type){f.push(' type="',ua(g.type),'"');var h={};la(h,g);delete h.type;g=h}f.push(">");f=f.join("")}f=e.createElement(f);g&&(q(g)?f.className=g:"array"==p(g)?f.className=g.join(" "):Zb(f,g));2<d.length&&bc(e,f,d);return f} -function bc(a,b,c){function d(c){c&&b.appendChild(q(c)?a.createTextNode(c):c)}for(var e=2;e<c.length;e++){var f=c[e];if(!aa(f)||ba(f)&&0<f.nodeType)d(f);else{var g;a:{if(f&&"number"==typeof f.length){if(ba(f)){g="function"==typeof f.item||"string"==typeof f.item;break a}if("function"==p(f)){g="function"==typeof f.item;break a}}g=!1}Ea(g?Fa(f):f,d)}}}function cc(a){if(n(a.nextElementSibling))a=a.nextElementSibling;else for(a=a.nextSibling;a&&1!=a.nodeType;)a=a.nextSibling;return a};function Y(a,b){this.u=b.imageryLayers;this.F=new Cesium.ImageryLayerCollection;w.call(this,a,b)}v(Y,w);k=Y.prototype;k.aa=function(a){this.u.add(a);this.F.add(a)};k.ea=function(a){a.destroy()};k.ma=function(a,b){this.u.remove(a,b);this.F.remove(a,!1)};k.la=function(a){for(var b=0;b<this.F.length;++b)this.u.remove(this.F.get(b),a);this.F.removeAll(!1)};k.ca=function(a,b){var c=Gb(a,b);return c?[c]:null}; -k.T=function(a){var b=this.i.getProjection(),c=this.ca(a,b);if(null!==c){a.on(["change:opacity","change:visible"],function(){for(var b=0;b<c.length;++b)Hb(a,c[b])});for(b=0;b<c.length;++b)Hb(a,c[b]);a.on("change:extent",function(){for(var b=0;b<c.length;++b)this.u.remove(c[b],!0),this.F.remove(c[b],!1);delete this.A[t(a)];this.Z()},this);a.on("change",function(){for(var a=0;a<c.length;++a){var b=this.u.indexOf(c[a]);0<=b&&(this.u.remove(c[a],!1),this.u.add(c[a],b))}},this)}return Array.isArray(c)? -c:null};k.W=function(){for(var a=[],b={},c=[this.b];0<c.length;){var d=c.splice(0,1)[0];a.push(d);b[t(d)]=d.getZIndex();d instanceof ol.layer.Group&&(d=d.getLayers(),n(d)&&d.forEach(function(a){c.push(a)}))}Ia(a,function(a,c){return b[t(a)]-b[t(c)]});a.forEach(function(a){a=t(a);(a=this.A[a])&&a.forEach(this.Ja,this)},this)};k.Ja=function(a){this.u.raiseToTop(a)};function dc(a,b,c){this.h=c||new W(b);this.a=new Cesium.PrimitiveCollection;b.primitives.add(this.a);this.a.destroyPrimitives=!1;w.call(this,a,b)}v(dc,w);k=dc.prototype;k.aa=function(a){a.a.counterpart=a;this.a.add(a.a)};k.ea=function(a){a.a.destroy()};k.ma=function(a,b){a.destroy();this.a.destroyPrimitives=b;this.a.remove(a.a);this.a.destroyPrimitives=!1}; -k.la=function(a){if(this.a.destroyPrimitives=a)for(a=0;a<this.a.length;++a)this.a.get(a).counterpart.destroy();this.a.removeAll();this.a.destroyPrimitives=!1}; -k.T=function(a){if(!(a instanceof ol.layer.Vector||a instanceof ol.layer.Image&&a.getSource()instanceof ol.source.ImageVector))return null;var b=a.getSource();a.getSource()instanceof ol.source.ImageVector&&(b=a.getSource().getSource());var c=this.i,d={},e=this.h.ja(a,c,d),f=e.a,g=e.b;f.show=a.getVisible();g.push(a.on("change:visible",function(){f.show=a.getVisible()}));var h=function(b){var g=this.h.convert(a,c,b,e.c);g&&(d[t(b)]=g,f.add(g))}.bind(this),l=function(a){var b=a.getGeometry();a=t(a); -if(!b||"Point"==b.getType()){var b=e.c,c=b.featureToCesiumMap[a];delete b.featureToCesiumMap[a];c instanceof Cesium.Billboard&&b.billboards.remove(c)}b=d[a];delete d[a];null!=b&&f.remove(b)}.bind(this);g.push(b.on("addfeature",function(a){h(a.feature)},this));g.push(b.on("removefeature",function(a){l(a.feature)},this));g.push(b.on("changefeature",function(a){a=a.feature;l(a);h(a)},this));return e?[e]:null};function Z(a){this.b=null;this.o=a.map;this.j=1;this.l=this.s=0;this.i=!0;this.g=ac("DIV",{style:"position:absolute;top:0;left:0;width:100%;height:100%;visibility:hidden;"});var b=Xb(a.target||null);if(b)b.appendChild(this.g);else{var c=this.o.getViewport();(c=Yb(c))&&c.parentNode&&c.parentNode.insertBefore(this.g,c)}this.h=null==b;this.a=ac(wb,{style:"position:absolute;top:0;left:0;width:100%;height:100%;"});this.a.oncontextmenu=function(){return!1};this.a.onselectstart=function(){return!1};this.g.appendChild(this.a); -this.v=!1;this.X=[];this.c=null;this.f=new Cesium.Scene({canvas:this.a,scene3DOnly:!0});b=this.f.screenSpaceCameraController;b.inertiaSpin=0;b.inertiaTranslate=0;b.inertiaZoom=0;b.tiltEventTypes.push({eventType:Cesium.CameraEventType.LEFT_DRAG,modifier:Cesium.KeyboardEventModifier.SHIFT});b.tiltEventTypes.push({eventType:Cesium.CameraEventType.LEFT_DRAG,modifier:Cesium.KeyboardEventModifier.ALT});b.enableLook=!1;this.f.camera.constrainedAxis=Cesium.Cartesian3.UNIT_Z;this.I=new T(this.f,this.o);this.H= -new Cesium.Globe(Cesium.Ellipsoid.WGS84);this.f.globe=this.H;this.f.skyAtmosphere=new Cesium.SkyAtmosphere;this.D=new Cesium.DataSourceCollection;this.sa=new Cesium.DataSourceDisplay({scene:this.f,dataSourceCollection:this.D});a=n(a.createSynchronizers)?a.createSynchronizers(this.o,this.f):[new Y(this.o,this.f),new dc(this.o,this.f)];ec(this);for(b=a.length-1;0<=b;--b)a[b].Z();this.h&&(a=cc(this.a),null!=a&&(a.style.display="none"));this.J=new P(function(){if(!this.ba){var a=Cesium.JulianDate.now(); -this.f.initializeFrame();ec(this);this.sa.update(a);this.f.render(a);this.v&&Nb(this.I)}this.J.start()},void 0,this);this.ba=!1}function ec(a){var b=a.a.clientWidth,c=a.a.clientHeight;if(b!==a.s||c!==a.l||a.i){var d=(window.devicePixelRatio||1)*a.j;a.i=!1;a.s=b;a.l=c;b*=d;c*=d;a.a.width=b;a.a.height=c;a.f.camera.frustum.aspectRatio=b/c}}k=Z.prototype;k.va=function(){return this.I};k.Aa=function(){return this.o};k.wa=function(){return this.f};k.xa=function(){return this.D};k.za=function(){return this.v}; -k.Na=function(a){if(this.v!=a)if(this.v=a,this.g.style.visibility=this.v?"visible":"hidden",this.v){if(this.h){var b=this.o.getInteractions();b.forEach(function(a){this.X.push(a)},this);b.clear();a=this.o.getLayerGroup();a.getVisible()&&(this.c=a,this.c.setVisible(!1))}this.I.K();this.J.start()}else this.h&&(b=this.o.getInteractions(),this.X.forEach(function(a){b.push(a)}),this.X.length=0,null!==this.c&&(this.c.setVisible(!0),this.c=null)),this.I.B(),tb(this.J)}; -k.Ta=function(a,b){if(!this.v){this.I.K();var c=this.H.ellipsoid,d=this.f.camera,e=c.cartesianToCartographic(d.position);e.height<a&&(e.height=a,d.position=c.cartographicToCartesian(e));this.J.start();var f=this;setTimeout(function(){!f.v&&tb(f.J)},b)}};k.Y=function(a){this.ba=a};k.ta=function(){this.b||(this.b=new x(this,!1))};k.ua=function(){return this.b};k.Pa=function(a){a=Math.max(0,a);a!==this.j&&(this.j=Math.max(0,a),this.i=!0,this.b&&this.b.s())};function fc(a,b){Y.call(this,a,b)}v(fc,Y);fc.prototype.ca=function(a){var b=null;if(!(a instanceof ol.layer.Group)&&a.getSource()instanceof ol.source.Vector)return null;a=a.getCesiumImageryProvider;return a?(b=a())?(Array.isArray(b)?b:[b]).map(function(a){return new Cesium.ImageryLayer(a)}):null:null};u("olcs.AbstractSynchronizer",w);w.prototype.synchronize=w.prototype.Z;x.prototype.restartRenderLoop=x.prototype.s;x.prototype.setDebug=x.prototype.ra;u("olcs.Camera",T);T.prototype.setHeading=T.prototype.Oa;T.prototype.getHeading=T.prototype.Ea;T.prototype.setTilt=T.prototype.Qa;T.prototype.getTilt=T.prototype.Ba;T.prototype.setDistance=T.prototype.Ma;T.prototype.getDistance=T.prototype.ya;T.prototype.setCenter=T.prototype.Ha;T.prototype.getCenter=T.prototype.getCenter;T.prototype.setPosition=T.prototype.Ia; -T.prototype.getPosition=T.prototype.Fa;T.prototype.setAltitude=T.prototype.La;T.prototype.getAltitude=T.prototype.ka;T.prototype.lookAt=T.prototype.Ga;T.prototype.readFromView=T.prototype.K;T.prototype.updateView=T.prototype.B;u("olcs.core.computePixelSizeAtCoordinate",function(a,b){var c=a.camera,d=a.canvas,e=c.frustum,d=new Cesium.Cartesian2(d.clientWidth,d.clientHeight),c=Cesium.Cartesian3.magnitude(Cesium.Cartesian3.subtract(c.position,b,new Cesium.Cartesian3));return e.getPixelSize(d,c)}); -u("olcs.core.applyHeightOffsetToGeometry",function(a,b){a.applyTransform(function(a,d,e){if(n(e)&&3<=e)for(a=0;a<d.length;a+=e)d[a+2]+=b;return d})});u("olcs.core.rotateAroundAxis",zb); -u("olcs.core.setHeadingUsingBottomCenter",function(a,b,c,d){var e=a.camera;a=Db(a,c);a=Cesium.Quaternion.fromAxisAngle(e.right,a);var f=Cesium.Matrix3.fromQuaternion(a),g=new Cesium.Cartesian3;Cesium.Cartesian3.subtract(e.position,c,g);a=new Cesium.Cartesian3;Cesium.Matrix3.multiplyByVector(f,g,a);Cesium.Cartesian3.add(a,c,a);c=Cesium.Matrix4.fromTranslation(a);zb(e,b,a,c,d)});u("olcs.core.pickOnTerrainOrEllipsoid",Ab); -u("olcs.core.pickBottomPoint",function(a){var b=a.canvas,b=new Cesium.Cartesian2(b.clientWidth/2,b.clientHeight);return Ab(a,b)});u("olcs.core.pickCenterPoint",Bb); -u("olcs.core.computeSignedTiltAngleOnGlobe",function(a){var b=a.camera,c=new Cesium.Ray(b.position,b.direction);a=a.globe.pick(c,a);if(!a){var d=Cesium.IntersectionTests.rayEllipsoid(c,Cesium.Ellipsoid.WGS84);d&&(a=Cesium.Ray.getPoint(c,d.start))}if(a)return c=new Cesium.Cartesian3,Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(a,c),b=Cb(b.direction,c,b.right)-Math.PI,Cesium.Math.convertLongitudeRange(b)});u("olcs.core.computeAngleToZenith",Db);u("olcs.core.lookAt",Eb); -u("olcs.core.extentToRectangle",Fb);u("olcs.core.tileLayerToImageryLayer",Gb);u("olcs.core.updateCesiumLayerProperties",Hb);u("olcs.core.ol4326CoordinateToCesiumCartesian",R);u("olcs.core.ol4326CoordinateArrayToCsCartesians",Ib);u("olcs.core.olGeometryCloneTo4326",S);u("olcs.core.convertColorToCesium",Jb);u("olcs.DragBox",V);V.prototype.setScene=V.prototype.$;V.prototype.listen=V.prototype.l;u("olcs.FeatureConverter",W);W.prototype.csAddBillboard=W.prototype.da; -W.prototype.olCircleGeometryToCesium=W.prototype.fa;W.prototype.olLineStringGeometryToCesium=W.prototype.U;W.prototype.olPolygonGeometryToCesium=W.prototype.V;W.prototype.getHeightReference=W.prototype.N;W.prototype.olPointGeometryToCesium=W.prototype.R;W.prototype.olMultiGeometryToCesium=W.prototype.ha;W.prototype.olGeometry4326TextPartToCesium=W.prototype.ga;W.prototype.olStyleToCesium=W.prototype.ia;W.prototype.computePlainStyle=W.prototype.S;W.prototype.olFeatureToCesium=W.prototype.P; -W.prototype.olVectorLayerToCesium=W.prototype.ja;W.prototype.convert=W.prototype.convert;u("olcs.OLCesium",Z);Z.prototype.getCamera=Z.prototype.va;Z.prototype.getOlMap=Z.prototype.Aa;Z.prototype.getCesiumScene=Z.prototype.wa;Z.prototype.getDataSources=Z.prototype.xa;Z.prototype.getEnabled=Z.prototype.za;Z.prototype.setEnabled=Z.prototype.Na;Z.prototype.warmUp=Z.prototype.Ta;Z.prototype.setBlockCesiumRendering=Z.prototype.Y;Z.prototype.enableAutoRenderLoop=Z.prototype.ta; -Z.prototype.getAutoRenderLoop=Z.prototype.ua;Z.prototype.setResolutionScale=Z.prototype.Pa;u("olcs.RasterSynchronizer",Y);u("olcs.VectorSynchronizer",dc);u("ga.GaRasterSynchronizer",fc);})(); +// Version: v1.9-43-gdbbc31d + +var k,aa=aa||{},ba=this;function ca(b){return void 0!==b}function da(){} +function ea(b){var c=typeof b;if("object"==c)if(b){if(b instanceof Array)return"array";if(b instanceof Object)return c;var d=Object.prototype.toString.call(b);if("[object Window]"==d)return"object";if("[object Array]"==d||"number"==typeof b.length&&"undefined"!=typeof b.splice&&"undefined"!=typeof b.propertyIsEnumerable&&!b.propertyIsEnumerable("splice"))return"array";if("[object Function]"==d||"undefined"!=typeof b.call&&"undefined"!=typeof b.propertyIsEnumerable&&!b.propertyIsEnumerable("call"))return"function"}else return"null"; +else if("function"==c&&"undefined"==typeof b.call)return"object";return c}function fa(b){return"array"==ea(b)}function ga(b){var c=ea(b);return"array"==c||"object"==c&&"number"==typeof b.length}function ha(b){return"string"==typeof b}function ia(b){return"number"==typeof b}function la(b){return"function"==ea(b)}function ma(b){var c=typeof b;return"object"==c&&null!=b||"function"==c}function u(b){return b[na]||(b[na]=++oa)}var na="closure_uid_"+(1E9*Math.random()>>>0),oa=0; +function pa(b,c,d){return b.call.apply(b.bind,arguments)}function qa(b,c,d){if(!b)throw Error();if(2<arguments.length){var e=Array.prototype.slice.call(arguments,2);return function(){var d=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(d,e);return b.apply(c,d)}}return function(){return b.apply(c,arguments)}}function ra(b,c,d){ra=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?pa:qa;return ra.apply(null,arguments)} +function sa(b,c){var d=Array.prototype.slice.call(arguments,1);return function(){var c=d.slice();c.push.apply(c,arguments);return b.apply(this,c)}}var ta=Date.now||function(){return+new Date};function w(b,c){var d=b.split("."),e=ba;d[0]in e||!e.execScript||e.execScript("var "+d[0]);for(var f;d.length&&(f=d.shift());)!d.length&&ca(c)?e[f]=c:e[f]?e=e[f]:e=e[f]={}} +function y(b,c){function d(){}d.prototype=c.prototype;b.ka=c.prototype;b.prototype=new d;b.prototype.constructor=b;b.Ol=function(b,d,g){for(var h=Array(arguments.length-2),l=2;l<arguments.length;l++)h[l-2]=arguments[l];return c.prototype[d].apply(b,h)}};function ua(b,c,d){for(var e in b)c.call(d,b[e],e,b)}function wa(b,c){for(var d in b)if(c.call(void 0,b[d],d,b))return!0;return!1}function xa(b){var c=0,d;for(d in b)c++;return c}function ya(b){var c=[],d=0,e;for(e in b)c[d++]=b[e];return c}function Ba(b){var c=[],d=0,e;for(e in b)c[d++]=e;return c}function Da(b){for(var c in b)return!1;return!0}function Ea(b){for(var c in b)delete b[c]}function Ga(b,c,d){return c in b?b[c]:d}function Ha(b,c){var d=[];return c in b?b[c]:b[c]=d} +function Ia(b){var c={},d;for(d in b)c[d]=b[d];return c}function Ja(b){var c=ea(b);if("object"==c||"array"==c){if(la(b.clone))return b.clone();var c="array"==c?[]:{},d;for(d in b)c[d]=Ja(b[d]);return c}return b}var Ka="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "); +function La(b,c){for(var d,e,f=1;f<arguments.length;f++){e=arguments[f];for(d in e)b[d]=e[d];for(var g=0;g<Ka.length;g++)d=Ka[g],Object.prototype.hasOwnProperty.call(e,d)&&(b[d]=e[d])}};var Ma;var Na=String.prototype.trim?function(b){return b.trim()}:function(b){return b.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")};function Oa(b){if(!Pa.test(b))return b;-1!=b.indexOf("&")&&(b=b.replace(Qa,"&"));-1!=b.indexOf("<")&&(b=b.replace(Ra,"<"));-1!=b.indexOf(">")&&(b=b.replace(Sa,">"));-1!=b.indexOf('"')&&(b=b.replace(Ta,"""));-1!=b.indexOf("'")&&(b=b.replace(Ua,"'"));-1!=b.indexOf("\x00")&&(b=b.replace(Va,"�"));return b} +var Qa=/&/g,Ra=/</g,Sa=/>/g,Ta=/"/g,Ua=/'/g,Va=/\x00/g,Pa=/[\x00&<>"']/,Wa=String.prototype.repeat?function(b,c){return b.repeat(c)}:function(b,c){return Array(c+1).join(b)};function Ya(b){b=ca(void 0)?b.toFixed(void 0):String(b);var c=b.indexOf(".");-1==c&&(c=b.length);return Wa("0",Math.max(0,2-c))+b} +function Za(b,c){for(var d=0,e=Na(String(b)).split("."),f=Na(String(c)).split("."),g=Math.max(e.length,f.length),h=0;0==d&&h<g;h++){var l=e[h]||"",m=f[h]||"",n=RegExp("(\\d*)(\\D*)","g"),p=RegExp("(\\d*)(\\D*)","g");do{var q=n.exec(l)||["","",""],r=p.exec(m)||["","",""];if(0==q[0].length&&0==r[0].length)break;d=$a(0==q[1].length?0:parseInt(q[1],10),0==r[1].length?0:parseInt(r[1],10))||$a(0==q[2].length,0==r[2].length)||$a(q[2],r[2])}while(0==d)}return d}function $a(b,c){return b<c?-1:b>c?1:0};var ab=Array.prototype;function bb(b,c){return ab.indexOf.call(b,c,void 0)}function db(b,c){ab.forEach.call(b,c,void 0)}function eb(b,c){return ab.filter.call(b,c,void 0)}function fb(b){var c;a:{c=gb;for(var d=b.length,e=ha(b)?b.split(""):b,f=0;f<d;f++)if(f in e&&c.call(void 0,e[f],f,b)){c=f;break a}c=-1}return 0>c?null:ha(b)?b.charAt(c):b[c]}function hb(b,c){var d=bb(b,c),e;(e=0<=d)&&ab.splice.call(b,d,1);return e}function ib(b){return ab.concat.apply(ab,arguments)} +function jb(b){var c=b.length;if(0<c){for(var d=Array(c),e=0;e<c;e++)d[e]=b[e];return d}return[]}function mb(b,c){for(var d=1;d<arguments.length;d++){var e=arguments[d];if(ga(e)){var f=b.length||0,g=e.length||0;b.length=f+g;for(var h=0;h<g;h++)b[f+h]=e[h]}else b.push(e)}}function nb(b,c,d,e){ab.splice.apply(b,ob(arguments,1))}function ob(b,c,d){return 2>=arguments.length?ab.slice.call(b,c):ab.slice.call(b,c,d)}function pb(b,c){b.sort(c||qb)} +function rb(b,c){for(var d=0;d<b.length;d++)b[d]={index:d,value:b[d]};var e=c||qb;pb(b,function(b,c){return e(b.value,c.value)||b.index-c.index});for(d=0;d<b.length;d++)b[d]=b[d].value}function sb(b,c){if(!ga(b)||!ga(c)||b.length!=c.length)return!1;for(var d=b.length,e=tb,f=0;f<d;f++)if(!e(b[f],c[f]))return!1;return!0}function qb(b,c){return b>c?1:b<c?-1:0}function tb(b,c){return b===c};var ub;a:{var vb=ba.navigator;if(vb){var wb=vb.userAgent;if(wb){ub=wb;break a}}ub=""}function xb(b){return-1!=ub.indexOf(b)};function yb(){return xb("iPhone")&&!xb("iPod")&&!xb("iPad")};var zb=xb("Opera")||xb("OPR"),Ab=xb("Trident")||xb("MSIE"),Bb=xb("Edge"),Cb=xb("Gecko")&&!(-1!=ub.toLowerCase().indexOf("webkit")&&!xb("Edge"))&&!(xb("Trident")||xb("MSIE"))&&!xb("Edge"),Db=-1!=ub.toLowerCase().indexOf("webkit")&&!xb("Edge");Db&&xb("Mobile");var Eb=xb("Macintosh"),Fb=xb("Windows"),Gb=xb("Linux")||xb("CrOS"),Hb=ba.navigator||null;Hb&&(Hb.appVersion||"").indexOf("X11");xb("Android");yb();xb("iPad"); +function Ib(){var b=ub;if(Cb)return/rv\:([^\);]+)(\)|;)/.exec(b);if(Bb)return/Edge\/([\d\.]+)/.exec(b);if(Ab)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(b);if(Db)return/WebKit\/(\S+)/.exec(b)}function Jb(){var b=ba.document;return b?b.documentMode:void 0}var Kb=function(){if(zb&&ba.opera){var b;var c=ba.opera.version;try{b=c()}catch(d){b=c}return b}b="";(c=Ib())&&(b=c?c[1]:"");return Ab&&(c=Jb(),c>parseFloat(b))?String(c):b}(),Lb={};function Mb(b){return Lb[b]||(Lb[b]=0<=Za(Kb,b))} +var Nb=ba.document,Ob=Nb&&Ab?Jb()||("CSS1Compat"==Nb.compatMode?parseInt(Kb,10):5):void 0;var Pb=!Ab||9<=Ob,Qb=!Ab||9<=Ob,Rb=Ab&&!Mb("9");!Db||Mb("528");Cb&&Mb("1.9b")||Ab&&Mb("8")||zb&&Mb("9.5")||Db&&Mb("528");Cb&&!Mb("8")||Ab&&Mb("9");function Sb(){0!=Tb&&(Ub[u(this)]=this);this.fa=this.fa;this.la=this.la}var Tb=0,Ub={};Sb.prototype.fa=!1;Sb.prototype.Fc=function(){if(!this.fa&&(this.fa=!0,this.ba(),0!=Tb)){var b=u(this);delete Ub[b]}};function Vb(b,c){var d=sa(Wb,c);b.fa?d.call(void 0):(b.la||(b.la=[]),b.la.push(ca(void 0)?ra(d,void 0):d))}Sb.prototype.ba=function(){if(this.la)for(;this.la.length;)this.la.shift()()};function Wb(b){b&&"function"==typeof b.Fc&&b.Fc()};function Xb(b,c){this.type=b;this.b=this.target=c;this.s=!1;this.Yf=!0}Xb.prototype.i=function(){this.s=!0};Xb.prototype.preventDefault=function(){this.Yf=!1};function Zb(b){b.i()};var $b=Ab?"focusout":"DOMFocusOut";function ac(b){ac[" "](b);return b}ac[" "]=da;function bc(b,c){Xb.call(this,b?b.type:"");this.relatedTarget=this.b=this.target=null;this.u=this.c=this.button=this.screenY=this.screenX=this.clientY=this.clientX=this.offsetY=this.offsetX=0;this.D=this.g=this.f=this.j=!1;this.state=null;this.l=!1;this.a=null;if(b){var d=this.type=b.type,e=b.changedTouches?b.changedTouches[0]:null;this.target=b.target||b.srcElement;this.b=c;var f=b.relatedTarget;if(f){if(Cb){var g;a:{try{ac(f.nodeName);g=!0;break a}catch(h){}g=!1}g||(f=null)}}else"mouseover"==d? +f=b.fromElement:"mouseout"==d&&(f=b.toElement);this.relatedTarget=f;null===e?(this.offsetX=Db||void 0!==b.offsetX?b.offsetX:b.layerX,this.offsetY=Db||void 0!==b.offsetY?b.offsetY:b.layerY,this.clientX=void 0!==b.clientX?b.clientX:b.pageX,this.clientY=void 0!==b.clientY?b.clientY:b.pageY,this.screenX=b.screenX||0,this.screenY=b.screenY||0):(this.clientX=void 0!==e.clientX?e.clientX:e.pageX,this.clientY=void 0!==e.clientY?e.clientY:e.pageY,this.screenX=e.screenX||0,this.screenY=e.screenY||0);this.button= +b.button;this.c=b.keyCode||0;this.u=b.charCode||("keypress"==d?b.keyCode:0);this.j=b.ctrlKey;this.f=b.altKey;this.g=b.shiftKey;this.D=b.metaKey;this.l=Eb?b.metaKey:b.ctrlKey;this.state=b.state;this.a=b;b.defaultPrevented&&this.preventDefault()}}y(bc,Xb);var cc=[1,4,2];function dc(b){return(Pb?0==b.a.button:"click"==b.type?!0:!!(b.a.button&cc[0]))&&!(Db&&Eb&&b.j)}bc.prototype.i=function(){bc.ka.i.call(this);this.a.stopPropagation?this.a.stopPropagation():this.a.cancelBubble=!0}; +bc.prototype.preventDefault=function(){bc.ka.preventDefault.call(this);var b=this.a;if(b.preventDefault)b.preventDefault();else if(b.returnValue=!1,Rb)try{if(b.ctrlKey||112<=b.keyCode&&123>=b.keyCode)b.keyCode=-1}catch(c){}};var ec="closure_listenable_"+(1E6*Math.random()|0);function fc(b){return!(!b||!b[ec])}var gc=0;function hc(b,c,d,e,f){this.listener=b;this.proxy=null;this.src=c;this.type=d;this.Xb=!!e;this.Pc=f;this.key=++gc;this.Sb=this.Cc=!1}function ic(b){b.Sb=!0;b.listener=null;b.proxy=null;b.src=null;b.Pc=null};function jc(b){this.src=b;this.a={};this.f=0}jc.prototype.add=function(b,c,d,e,f){var g=b.toString();b=this.a[g];b||(b=this.a[g]=[],this.f++);var h=kc(b,c,e,f);-1<h?(c=b[h],d||(c.Cc=!1)):(c=new hc(c,this.src,g,!!e,f),c.Cc=d,b.push(c));return c};jc.prototype.remove=function(b,c,d,e){b=b.toString();if(!(b in this.a))return!1;var f=this.a[b];c=kc(f,c,d,e);return-1<c?(ic(f[c]),ab.splice.call(f,c,1),0==f.length&&(delete this.a[b],this.f--),!0):!1}; +function lc(b,c){var d=c.type;if(!(d in b.a))return!1;var e=hb(b.a[d],c);e&&(ic(c),0==b.a[d].length&&(delete b.a[d],b.f--));return e}function mc(b,c,d){var e=ca(c),f=e?c.toString():"",g=ca(d);return wa(b.a,function(b){for(var c=0;c<b.length;++c)if(!(e&&b[c].type!=f||g&&b[c].Xb!=d))return!0;return!1})}function kc(b,c,d,e){for(var f=0;f<b.length;++f){var g=b[f];if(!g.Sb&&g.listener==c&&g.Xb==!!d&&g.Pc==e)return f}return-1};var nc="closure_lm_"+(1E6*Math.random()|0),oc={},pc=0;function z(b,c,d,e,f){if(fa(c)){for(var g=0;g<c.length;g++)z(b,c[g],d,e,f);return null}d=qc(d);return fc(b)?b.Uc(c,d,e,f):rc(b,c,d,!1,e,f)} +function rc(b,c,d,e,f,g){if(!c)throw Error("Invalid event type");var h=!!f,l=sc(b);l||(b[nc]=l=new jc(b));d=l.add(c,d,e,f,g);if(d.proxy)return d;e=tc();d.proxy=e;e.src=b;e.listener=d;if(b.addEventListener)b.addEventListener(c.toString(),e,h);else if(b.attachEvent)b.attachEvent(uc(c.toString()),e);else throw Error("addEventListener and attachEvent are unavailable.");pc++;return d} +function tc(){var b=vc,c=Qb?function(d){return b.call(c.src,c.listener,d)}:function(d){d=b.call(c.src,c.listener,d);if(!d)return d};return c}function wc(b,c,d,e,f){if(fa(c)){for(var g=0;g<c.length;g++)wc(b,c[g],d,e,f);return null}d=qc(d);return fc(b)?b.Ra.add(String(c),d,!0,e,f):rc(b,c,d,!0,e,f)} +function xc(b,c,d,e,f){if(fa(c))for(var g=0;g<c.length;g++)xc(b,c[g],d,e,f);else(d=qc(d),fc(b))?b.Ra.remove(String(c),d,e,f):b&&(b=sc(b))&&(c=b.a[c.toString()],b=-1,c&&(b=kc(c,d,!!e,f)),(d=-1<b?c[b]:null)&&yc(d))}function yc(b){if(ia(b)||!b||b.Sb)return!1;var c=b.src;if(fc(c))return lc(c.Ra,b);var d=b.type,e=b.proxy;c.removeEventListener?c.removeEventListener(d,e,b.Xb):c.detachEvent&&c.detachEvent(uc(d),e);pc--;(d=sc(c))?(lc(d,b),0==d.f&&(d.src=null,c[nc]=null)):ic(b);return!0} +function uc(b){return b in oc?oc[b]:oc[b]="on"+b}function zc(b,c,d,e){var f=!0;if(b=sc(b))if(c=b.a[c.toString()])for(c=c.concat(),b=0;b<c.length;b++){var g=c[b];g&&g.Xb==d&&!g.Sb&&(g=Ac(g,e),f=f&&!1!==g)}return f}function Ac(b,c){var d=b.listener,e=b.Pc||b.src;b.Cc&&yc(b);return d.call(e,c)} +function vc(b,c){if(b.Sb)return!0;if(!Qb){var d;if(!(d=c))a:{d=["window","event"];for(var e=ba,f;f=d.shift();)if(null!=e[f])e=e[f];else{d=null;break a}d=e}f=d;d=new bc(f,this);e=!0;if(!(0>f.keyCode||void 0!=f.returnValue)){a:{var g=!1;if(0==f.keyCode)try{f.keyCode=-1;break a}catch(m){g=!0}if(g||void 0==f.returnValue)f.returnValue=!0}f=[];for(g=d.b;g;g=g.parentNode)f.push(g);for(var g=b.type,h=f.length-1;!d.s&&0<=h;h--){d.b=f[h];var l=zc(f[h],g,!0,d),e=e&&l}for(h=0;!d.s&&h<f.length;h++)d.b=f[h],l= +zc(f[h],g,!1,d),e=e&&l}return e}return Ac(b,new bc(c,this))}function sc(b){b=b[nc];return b instanceof jc?b:null}var Bc="__closure_events_fn_"+(1E9*Math.random()>>>0);function qc(b){if(la(b))return b;b[Bc]||(b[Bc]=function(c){return b.handleEvent(c)});return b[Bc]};function Cc(){Sb.call(this);this.Ra=new jc(this);this.Ac=this;this.Qa=null}y(Cc,Sb);Cc.prototype[ec]=!0;k=Cc.prototype;k.addEventListener=function(b,c,d,e){z(this,b,c,d,e)};k.removeEventListener=function(b,c,d,e){xc(this,b,c,d,e)}; +k.B=function(b){var c,d=this.Qa;if(d)for(c=[];d;d=d.Qa)c.push(d);var d=this.Ac,e=b.type||b;if(ha(b))b=new Xb(b,d);else if(b instanceof Xb)b.target=b.target||d;else{var f=b;b=new Xb(e,d);La(b,f)}var f=!0,g;if(c)for(var h=c.length-1;!b.s&&0<=h;h--)g=b.b=c[h],f=Dc(g,e,!0,b)&&f;b.s||(g=b.b=d,f=Dc(g,e,!0,b)&&f,b.s||(f=Dc(g,e,!1,b)&&f));if(c)for(h=0;!b.s&&h<c.length;h++)g=b.b=c[h],f=Dc(g,e,!1,b)&&f;return f}; +k.ba=function(){Cc.ka.ba.call(this);if(this.Ra){var b=this.Ra,c=0,d;for(d in b.a){for(var e=b.a[d],f=0;f<e.length;f++)++c,ic(e[f]);delete b.a[d];b.f--}}this.Qa=null};k.Uc=function(b,c,d,e){return this.Ra.add(String(b),c,!1,d,e)};function Dc(b,c,d,e){c=b.Ra.a[String(c)];if(!c)return!0;c=c.concat();for(var f=!0,g=0;g<c.length;++g){var h=c[g];if(h&&!h.Sb&&h.Xb==d){var l=h.listener,m=h.Pc||h.src;h.Cc&&lc(b.Ra,h);f=!1!==l.call(m,e)&&f}}return f&&0!=e.Yf} +function Ec(b,c,d){return mc(b.Ra,ca(c)?String(c):void 0,d)};function Fc(){Cc.call(this);this.f=0}y(Fc,Cc);function Gc(b){yc(b)}k=Fc.prototype;k.A=function(){++this.f;this.B("change")};k.W=function(){return this.f};k.K=function(b,c,d){return z(this,b,c,!1,d)};k.X=function(b,c,d){return wc(this,b,c,!1,d)};k.Y=function(b,c,d){xc(this,b,c,!1,d)};k.Z=Gc;function Hc(b,c,d){Xb.call(this,b);this.key=c;this.oldValue=d}y(Hc,Xb);function Ic(b){Fc.call(this);u(this);this.s={};void 0!==b&&this.M(b)}y(Ic,Fc);var Jc={};function Kc(b){return Jc.hasOwnProperty(b)?Jc[b]:Jc[b]="change:"+b}k=Ic.prototype;k.get=function(b){var c;this.s.hasOwnProperty(b)&&(c=this.s[b]);return c};k.P=function(){return Object.keys(this.s)};k.S=function(){var b={},c;for(c in this.s)b[c]=this.s[c];return b}; +function Lc(b,c,d){var e;e=Kc(c);b.B(new Hc(e,c,d));b.B(new Hc("propertychange",c,d))}k.C=function(b,c,d){d?this.s[b]=c:(d=this.s[b],this.s[b]=c,d!==c&&Lc(this,b,d))};k.M=function(b,c){for(var d in b)this.C(d,b[d],c)};k.$=function(b,c){if(b in this.s){var d=this.s[b];delete this.s[b];c||Lc(this,b,d)}};function Mc(b,c,d){Xb.call(this,b,d);this.element=c}y(Mc,Xb);function A(b){Ic.call(this);this.a=b?b:[];Nc(this)}y(A,Ic);k=A.prototype;k.clear=function(){for(;0<this.qb();)this.pop()};k.$d=function(b){var c,d;c=0;for(d=b.length;c<d;++c)this.push(b[c]);return this};k.forEach=function(b,c){this.a.forEach(b,c)};k.Li=function(){return this.a};k.item=function(b){return this.a[b]};k.qb=function(){return this.get("length")};k.Qc=function(b,c){nb(this.a,b,0,c);Nc(this);this.B(new Mc("add",c,this))}; +k.pop=function(){return this.qe(this.qb()-1)};k.push=function(b){var c=this.a.length;this.Qc(c,b);return c};k.remove=function(b){var c=this.a,d,e;d=0;for(e=c.length;d<e;++d)if(c[d]===b)return this.qe(d)};k.qe=function(b){var c=this.a[b];ab.splice.call(this.a,b,1);Nc(this);this.B(new Mc("remove",c,this));return c};k.$k=function(b,c){var d=this.qb();if(b<d)d=this.a[b],this.a[b]=c,this.B(new Mc("remove",d,this)),this.B(new Mc("add",c,this));else{for(;d<b;++d)this.Qc(d,void 0);this.Qc(b,c)}}; +function Nc(b){b.C("length",b.a.length)};function Oc(b){this.length=b.length||b;for(var c=0;c<this.length;c++)this[c]=b[c]||0}Oc.prototype.a=4;Oc.prototype.f=function(b,c){c=c||0;for(var d=0;d<b.length&&c+d<this.length;d++)this[c+d]=b[d]};Oc.prototype.toString=Array.prototype.join;"undefined"==typeof Float32Array&&(Oc.BYTES_PER_ELEMENT=4,Oc.prototype.BYTES_PER_ELEMENT=Oc.prototype.a,Oc.prototype.set=Oc.prototype.f,Oc.prototype.toString=Oc.prototype.toString,w("Float32Array",Oc));function Pc(b){this.length=b.length||b;for(var c=0;c<this.length;c++)this[c]=b[c]||0}Pc.prototype.a=8;Pc.prototype.f=function(b,c){c=c||0;for(var d=0;d<b.length&&c+d<this.length;d++)this[c+d]=b[d]};Pc.prototype.toString=Array.prototype.join;if("undefined"==typeof Float64Array){try{Pc.BYTES_PER_ELEMENT=8}catch(b){}Pc.prototype.BYTES_PER_ELEMENT=Pc.prototype.a;Pc.prototype.set=Pc.prototype.f;Pc.prototype.toString=Pc.prototype.toString;w("Float64Array",Pc)};function Qc(){var b=Array(16);b[0]=0;b[1]=0;b[2]=0;b[3]=0;b[4]=0;b[5]=0;b[6]=0;b[7]=0;b[8]=0;b[9]=0;b[10]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=0;return b} +function Rc(b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],l=b[5],m=b[6],n=b[7],p=b[8],q=b[9],r=b[10],t=b[11],B=b[12],X=b[13],x=b[14],E=b[15],v=d*l-e*h,Ca=d*m-f*h,Fa=d*n-g*h,ja=e*m-f*l,P=e*n-g*l,Aa=f*n-g*m,va=p*X-q*B,kb=p*x-r*B,Xa=p*E-t*B,cb=q*x-r*X,lb=q*E-t*X,ka=r*E-t*x,za=v*ka-Ca*lb+Fa*cb+ja*Xa-P*kb+Aa*va;0!=za&&(za=1/za,c[0]=(l*ka-m*lb+n*cb)*za,c[1]=(-e*ka+f*lb-g*cb)*za,c[2]=(X*Aa-x*P+E*ja)*za,c[3]=(-q*Aa+r*P-t*ja)*za,c[4]=(-h*ka+m*Xa-n*kb)*za,c[5]=(d*ka-f*Xa+g*kb)*za,c[6]=(-B*Aa+x*Fa-E*Ca)*za,c[7]= +(p*Aa-r*Fa+t*Ca)*za,c[8]=(h*lb-l*Xa+n*va)*za,c[9]=(-d*lb+e*Xa-g*va)*za,c[10]=(B*P-X*Fa+E*v)*za,c[11]=(-p*P+q*Fa-t*v)*za,c[12]=(-h*cb+l*kb-m*va)*za,c[13]=(d*cb-e*kb+f*va)*za,c[14]=(-B*ja+X*Ca-x*v)*za,c[15]=(p*ja-q*Ca+r*v)*za)}function Sc(b,c,d){var e=b[1]*c+b[5]*d+0*b[9]+b[13],f=b[2]*c+b[6]*d+0*b[10]+b[14],g=b[3]*c+b[7]*d+0*b[11]+b[15];b[12]=b[0]*c+b[4]*d+0*b[8]+b[12];b[13]=e;b[14]=f;b[15]=g}new Float64Array(3);new Float64Array(3);new Float64Array(4);new Float64Array(4);new Float64Array(4);new Float64Array(16);function Tc(b,c){var d=b%c;return 0>d*c?d+c:d}function Uc(b,c,d){return b+d*(c-b)};function Vc(b,c){b[0]+=c[0];b[1]+=c[1]}function Wc(b,c){var d=b[0],e=b[1],f=c[0],g=c[1],h=f[0],f=f[1],l=g[0],g=g[1],m=l-h,n=g-f,d=0===m&&0===n?0:(m*(d-h)+n*(e-f))/(m*m+n*n||0);0>=d||(1<=d?(h=l,f=g):(h+=d*m,f+=d*n));return[h,f]}function Xc(b,c){var d=Tc(b+180,360)-180,e=Math.abs(Math.round(3600*d));return Math.floor(e/3600)+"\u00b0 "+Ya(Math.floor(e/60%60))+"\u2032 "+Ya(Math.floor(e%60))+"\u2033 "+c.charAt(0>d?1:0)} +function Yc(b,c,d){return b?c.replace("{x}",b[0].toFixed(d)).replace("{y}",b[1].toFixed(d)):""}function Zc(b,c){for(var d=!0,e=b.length-1;0<=e;--e)if(b[e]!=c[e]){d=!1;break}return d}function $c(b,c){var d=Math.cos(c),e=Math.sin(c),f=b[1]*d+b[0]*e;b[0]=b[0]*d-b[1]*e;b[1]=f}function bd(b,c){var d=b[0]-c[0],e=b[1]-c[1];return d*d+e*e}function cd(b,c){return bd(b,Wc(b,c))};function dd(b,c,d){void 0===d&&(d=[0,0]);d[0]=b[0]+2*c;d[1]=b[1]+2*c;return d}function ed(b,c,d){void 0===d&&(d=[0,0]);d[0]=b[0]*c+.5|0;d[1]=b[1]*c+.5|0;return d}function fd(b,c){if(fa(b))return b;void 0===c?c=[b,b]:(c[0]=b,c[1]=b);return c};function gd(b){for(var c=hd(),d=0,e=b.length;d<e;++d)id(c,b[d]);return c}function jd(b,c){var d=Math.min.apply(null,b),e=Math.min.apply(null,c),f=Math.max.apply(null,b),g=Math.max.apply(null,c);return kd(d,e,f,g,void 0)}function ld(b,c,d){return d?(d[0]=b[0]-c,d[1]=b[1]-c,d[2]=b[2]+c,d[3]=b[3]+c,d):[b[0]-c,b[1]-c,b[2]+c,b[3]+c]}function md(b,c){return c?(c[0]=b[0],c[1]=b[1],c[2]=b[2],c[3]=b[3],c):b.slice()} +function nd(b,c,d){c=c<b[0]?b[0]-c:b[2]<c?c-b[2]:0;b=d<b[1]?b[1]-d:b[3]<d?d-b[3]:0;return c*c+b*b}function od(b,c){return pd(b,c[0],c[1])}function qd(b,c){return b[0]<=c[0]&&c[2]<=b[2]&&b[1]<=c[1]&&c[3]<=b[3]}function pd(b,c,d){return b[0]<=c&&c<=b[2]&&b[1]<=d&&d<=b[3]}function rd(b,c){var d=b[1],e=b[2],f=b[3],g=c[0],h=c[1],l=0;g<b[0]?l=l|16:g>e&&(l=l|4);h<d?l|=8:h>f&&(l|=2);0===l&&(l=1);return l}function hd(){return[Infinity,Infinity,-Infinity,-Infinity]} +function kd(b,c,d,e,f){return f?(f[0]=b,f[1]=c,f[2]=d,f[3]=e,f):[b,c,d,e]}function sd(b,c){var d=b[0],e=b[1];return kd(d,e,d,e,c)}function td(b,c,d,e,f){f=kd(Infinity,Infinity,-Infinity,-Infinity,f);return ud(f,b,c,d,e)}function vd(b,c){return b[0]==c[0]&&b[2]==c[2]&&b[1]==c[1]&&b[3]==c[3]}function wd(b,c){c[0]<b[0]&&(b[0]=c[0]);c[2]>b[2]&&(b[2]=c[2]);c[1]<b[1]&&(b[1]=c[1]);c[3]>b[3]&&(b[3]=c[3])} +function id(b,c){c[0]<b[0]&&(b[0]=c[0]);c[0]>b[2]&&(b[2]=c[0]);c[1]<b[1]&&(b[1]=c[1]);c[1]>b[3]&&(b[3]=c[1])}function ud(b,c,d,e,f){for(;d<e;d+=f){var g=b,h=c[d],l=c[d+1];g[0]=Math.min(g[0],h);g[1]=Math.min(g[1],l);g[2]=Math.max(g[2],h);g[3]=Math.max(g[3],l)}return b}function xd(b,c,d){var e;return(e=c.call(d,[b[0],b[1]]))||(e=c.call(d,[b[2],b[1]]))||(e=c.call(d,[b[2],b[3]]))?e:(e=c.call(d,yd(b)))?e:!1}function zd(b){var c=0;Ad(b)||(c=Bd(b)*Dd(b));return c} +function Ed(b){return[(b[0]+b[2])/2,(b[1]+b[3])/2]}function Fd(b,c,d,e){var f=c*e[0]/2;e=c*e[1]/2;c=Math.cos(d);d=Math.sin(d);f=[-f,-f,f,f];e=[-e,e,-e,e];var g,h,l;for(g=0;4>g;++g)h=f[g],l=e[g],f[g]=b[0]+h*c-l*d,e[g]=b[1]+h*d+l*c;return jd(f,e)}function Dd(b){return b[3]-b[1]}function Gd(b,c){var d=hd();Hd(b,c)&&(d[0]=b[0]>c[0]?b[0]:c[0],d[1]=b[1]>c[1]?b[1]:c[1],d[2]=b[2]<c[2]?b[2]:c[2],d[3]=b[3]<c[3]?b[3]:c[3]);return d}function yd(b){return[b[0],b[3]]}function Bd(b){return b[2]-b[0]} +function Hd(b,c){return b[0]<=c[2]&&b[2]>=c[0]&&b[1]<=c[3]&&b[3]>=c[1]}function Ad(b){return b[2]<b[0]||b[3]<b[1]};function Id(){};function Jd(b,c,d){return Math.min(Math.max(b,c),d)}var Kd=function(){var b;"cosh"in Math?b=Math.cosh:b=function(b){b=Math.exp(b);return(b+1/b)/2};return b}();function Ld(b,c,d,e){b=d-b;c=e-c;return b*b+c*c}function Md(b){return b*Math.PI/180};function Nd(b,c,d){return b+"/"+c+"/"+d}function Od(b){return Nd(b[0],b[1],b[2])};function Pd(b,c,d,e){this.a=b;this.f=c;this.c=d;this.b=e}Pd.prototype.contains=function(b){return Qd(this,b[1],b[2])};function Rd(b,c){return b.a<=c.a&&c.f<=b.f&&b.c<=c.c&&c.b<=b.b}function Qd(b,c,d){return b.a<=c&&c<=b.f&&b.c<=d&&d<=b.b}function Sd(b){return b.b-b.c+1}Pd.prototype.s=function(){return this.a};Pd.prototype.getMinX=Pd.prototype.s;Pd.prototype.g=function(){return this.f};Pd.prototype.getMaxX=Pd.prototype.g;Pd.prototype.j=function(){return this.c};Pd.prototype.getMinY=Pd.prototype.j; +Pd.prototype.i=function(){return this.b};Pd.prototype.getMaxY=Pd.prototype.i;/* + + Latitude/longitude spherical geodesy formulae taken from + http://www.movable-type.co.uk/scripts/latlong.html + Licensed under CC-BY-3.0. +*/ +function Td(b){this.radius=b}function Ud(b,c){var d=Md(b[1]),e=Md(c[1]),f=(e-d)/2,g=Md(c[0]-b[0])/2,d=Math.sin(f)*Math.sin(f)+Math.sin(g)*Math.sin(g)*Math.cos(d)*Math.cos(e);return 2*Vd.radius*Math.atan2(Math.sqrt(d),Math.sqrt(1-d))}Td.prototype.offset=function(b,c,d){var e=Md(b[1]);c/=this.radius;var f=Math.asin(Math.sin(e)*Math.cos(c)+Math.cos(e)*Math.sin(c)*Math.cos(d));return[180*(Md(b[0])+Math.atan2(Math.sin(d)*Math.sin(c)*Math.cos(e),Math.cos(c)-Math.sin(e)*Math.sin(f)))/Math.PI,180*f/Math.PI]};var Vd=new Td(6370997);var Wd={};Wd.degrees=2*Math.PI*Vd.radius/360;Wd.ft=.3048;Wd.m=1;Wd["us-ft"]=1200/3937; +function Xd(b){this.a=b.code;this.b=b.units;this.g=void 0!==b.extent?b.extent:null;this.l=void 0!==b.worldExtent?b.worldExtent:null;this.i=void 0!==b.axisOrientation?b.axisOrientation:"enu";this.c=void 0!==b.global?b.global:!1;this.f=!(!this.c||!this.g);this.j=void 0!==b.getPointResolution?b.getPointResolution:this.Gh;this.s=null;var c=Yd,d=b.code;if("function"==typeof proj4&&void 0===c[d]){var e=proj4.defs(d);if(void 0!==e){void 0!==e.axis&&void 0===b.axisOrientation&&(this.i=e.axis);void 0===b.units&& +(b=e.units,void 0===e.to_meter||void 0!==b&&void 0!==Wd[b]||(b=e.to_meter.toString(),Wd[b]=e.to_meter),this.b=b);var f,g;for(f in c)if(c=proj4.defs(f),void 0!==c)if(b=Zd(f),c===e)$d([b,this]);else{g=proj4(f,d);c=g.forward;g=g.inverse;b=Zd(b);var h=Zd(this);ae(b,h,be(c));ae(h,b,be(g))}}}}k=Xd.prototype;k.dh=function(){return this.a};k.G=function(){return this.g};k.Hj=function(){return this.b};k.nb=function(){return Wd[this.b]};k.Sh=function(){return this.l};k.ui=function(){return this.c}; +k.fl=function(b){this.c=b;this.f=!(!b||!this.g)};k.Ij=function(b){this.g=b;this.f=!(!this.c||!b)};k.sl=function(b){this.l=b};k.el=function(b){this.j=b};k.Gh=function(b,c){if("degrees"==this.b)return b;var d=ce(this,Zd("EPSG:4326")),e=[c[0]-b/2,c[1],c[0]+b/2,c[1],c[0],c[1]-b/2,c[0],c[1]+b/2],e=d(e,e,2),d=(Ud(e.slice(0,2),e.slice(2,4))+Ud(e.slice(4,6),e.slice(6,8)))/2,e=this.nb();void 0!==e&&(d/=e);return d};k.getPointResolution=function(b,c){return this.j(b,c)};var Yd={},de={}; +function $d(b){ee(b);b.forEach(function(c){b.forEach(function(b){c!==b&&ae(c,b,fe)})})}function ge(b){Yd[b.a]=b;ae(b,b,fe)}function ee(b){var c=[];b.forEach(function(b){c.push(ge(b))})}function he(b){return b?ha(b)?Zd(b):b:Zd("EPSG:3857")}function ae(b,c,d){b=b.a;c=c.a;b in de||(de[b]={});de[b][c]=d} +function be(b){return function(c,d,e){var f=c.length;e=void 0!==e?e:2;d=void 0!==d?d:Array(f);var g,h;for(h=0;h<f;h+=e)for(g=b([c[h],c[h+1]]),d[h]=g[0],d[h+1]=g[1],g=e-1;2<=g;--g)d[h+g]=c[h+g];return d}}function Zd(b){var c;b instanceof Xd?c=b:ha(b)?(c=Yd[b],void 0===c&&"function"==typeof proj4&&void 0!==proj4.defs(b)&&(c=new Xd({code:b}),ge(c))):c=null;return c}function ie(b,c){return b===c?!0:b.a===c.a?b.b===c.b:ce(b,c)===fe}function je(b,c){var d=Zd(b),e=Zd(c);return ce(d,e)} +function ce(b,c){var d=b.a,e=c.a,f;d in de&&e in de[d]&&(f=de[d][e]);void 0===f&&(f=ke);return f}function ke(b,c){if(void 0!==c&&b!==c){for(var d=0,e=b.length;d<e;++d)c[d]=b[d];b=c}return b}function fe(b,c){var d;if(void 0!==c){d=0;for(var e=b.length;d<e;++d)c[d]=b[d];d=c}else d=b.slice();return d}function le(b,c,d){return je(c,d)(b,void 0,b.length)}function me(b,c,d){c=je(c,d);b=[b[0],b[1],b[0],b[3],b[2],b[1],b[2],b[3]];c(b,b,2);return jd([b[0],b[2],b[4],b[6]],[b[1],b[3],b[5],b[7]])};function ne(b){Ic.call(this);this.i=Zd(b.projection);this.j=void 0!==b.attributions?b.attributions:null;this.J=b.logo;this.D=void 0!==b.state?b.state:"ready";this.F=void 0!==b.wrapX?b.wrapX:!1}y(ne,Ic);k=ne.prototype;k.Hf=Id;k.Ob=function(){return this.j};k.Hb=function(){return this.J};k.Pb=function(){return this.i};k.Qb=function(){return this.D};function oe(b){return b.F}k.Tb=function(b){this.j=b;this.A()};function pe(b){Ic.call(this);var c=Ia(b);c.opacity=void 0!==b.opacity?b.opacity:1;c.visible=void 0!==b.visible?b.visible:!0;c.zIndex=void 0!==b.zIndex?b.zIndex:0;c.maxResolution=void 0!==b.maxResolution?b.maxResolution:Infinity;c.minResolution=void 0!==b.minResolution?b.minResolution:0;this.M(c)}y(pe,Ic); +function qe(b){var c=b.tb(),d=b.Nd(),e=b.Ha(),f=b.G(),g=b.ma(),h=b.Ib(),l=b.Jb();return{layer:b,opacity:Jd(c,0,1),v:d,visible:e,kc:!0,extent:f,zIndex:g,maxResolution:h,minResolution:Math.max(l,0)}}k=pe.prototype;k.G=function(){return this.get("extent")};k.Ib=function(){return this.get("maxResolution")};k.Jb=function(){return this.get("minResolution")};k.tb=function(){return this.get("opacity")};k.Ha=function(){return this.get("visible")};k.ma=function(){return this.get("zIndex")}; +k.oc=function(b){this.C("extent",b)};k.wc=function(b){this.C("maxResolution",b)};k.xc=function(b){this.C("minResolution",b)};k.pc=function(b){this.C("opacity",b)};k.ub=function(b){this.C("visible",b)};k.qc=function(b){this.C("zIndex",b)};function C(b){var c=b||{};b=Ia(c);delete b.layers;c=c.layers;pe.call(this,b);this.b=[];this.a={};z(this,Kc("layers"),this.ai,!1,this);c?fa(c)&&(c=new A(c.slice())):c=new A;this.bg(c)}y(C,pe);k=C.prototype;k.Nc=function(){this.Ha()&&this.A()}; +k.ai=function(){this.b.forEach(yc);this.b.length=0;var b=this.Na();this.b.push(z(b,"add",this.$h,!1,this),z(b,"remove",this.bi,!1,this));ua(this.a,function(b){b.forEach(yc)});Ea(this.a);var b=b.a,c,d,e;c=0;for(d=b.length;c<d;c++)e=b[c],this.a[u(e).toString()]=[z(e,"propertychange",this.Nc,!1,this),z(e,"change",this.Nc,!1,this)];this.A()};k.$h=function(b){b=b.element;var c=u(b).toString();this.a[c]=[z(b,"propertychange",this.Nc,!1,this),z(b,"change",this.Nc,!1,this)];this.A()}; +k.bi=function(b){b=u(b.element).toString();this.a[b].forEach(yc);delete this.a[b];this.A()};k.Na=function(){return this.get("layers")};k.bg=function(b){this.C("layers",b)}; +k.Id=function(b){var c=void 0!==b?b:[],d=c.length;this.Na().forEach(function(b){b.Id(c)});b=qe(this);var e,f;for(e=c.length;d<e;d++)f=c[d],f.opacity*=b.opacity,f.visible=f.visible&&b.visible,f.maxResolution=Math.min(f.maxResolution,b.maxResolution),f.minResolution=Math.max(f.minResolution,b.minResolution),void 0!==b.extent&&(f.extent=void 0!==f.extent?Gd(f.extent,b.extent):b.extent);return c};k.Nd=function(){return"ready"};function re(b,c){this.map=b;this.view=b.ja();this.scene=c;b.Oa().Na();this.c=b.Oa();this.pb={};this.b={};this.f={}}re.prototype.ze=function(){se(this);te(this,this.c)};re.prototype.me=function(){};function te(b,c){for(var d=[c];0<d.length;){var e=d.splice(0,1)[0],f=u(e),g=null;e instanceof C?(ue(b,e),(g=b.xd(e))||e.Na().forEach(function(b){d.push(b)})):g=b.xd(e);null!==g&&(b.pb[f]=g,b.b[f]=e.K("change:zIndex",b.me,b),g.forEach(function(b){this.Le(b)},b))}b.me()} +function ve(b,c){var d=u(c),e=b.pb[d];e&&(e.forEach(function(b){this.Wf(b,!1);this.Ue(b)},b),yc(b.b[d]),delete b.b[d]);delete b.pb[d];return!!e}function we(b,c){if(c!==b.c){var d=u(c);b.f[d].forEach(function(b){yc(b)});delete b.f[d];delete b.pb[d]}}function xe(b,c){if(c)for(var d=[c];0<d.length;){var e=d.splice(0,1)[0],f=ve(b,e);e instanceof C&&(we(b,e),f&&e.Na().forEach(function(b){d.push(b)}))}} +function ue(b,c){var d=u(c),e=[];b.f[d]=e;var f=[],g=function(){var b=c.Na();ca(b)&&(f=[b.K("add",function(b){te(this,b.element)},this),b.K("remove",function(b){xe(this,b.element)},this)],e.push.apply(e,f))}.bind(b);g();e.push(c.K("change:layers",function(){f.forEach(function(b){var c=e.indexOf(b);0<=c&&e.splice(c,1);yc(b)});g()}))}function se(b){b.Uf(!0);ua(b.f,function(b){b.forEach(Gc)});ua(b.b,Gc);b.f={};b.b={};b.pb={}};function ye(b,c){this.c=b;this.O=b.O;this.i=c;this.f=this.a.bind(this);this.j=new Cesium.Matrix4;this.b=0;this.g=!1;this.O.postRender.addEventListener(this.I.bind(this));this.s="";this.s="onwheel"in this.O.canvas?"wheel":document.onmousewheel?"mousewheel":"DOMMouseScroll";this.fa=Cesium.loadWithXhr.load;this.J=Cesium.TaskProcessor.prototype.f;this.la=Cesium.Camera.prototype.setView;this.v=Cesium.Camera.prototype.move;this.F=Cesium.Camera.prototype.rotate;this.D=Cesium.Camera.prototype.lookAt;this.u= +Cesium.Camera.prototype.flyTo;ze(this)}function Ae(b,c){b.O.canvas.addEventListener(c,b.f,!1)} +function ze(b){Ae(b,"mousemove");Ae(b,"mousedown");Ae(b,"mouseup");Ae(b,"touchstart");Ae(b,"touchend");Ae(b,"touchmove");window.PointerEvent&&(Ae(b,"pointerdown"),Ae(b,"pointerup"),Ae(b,"pointermove"));Ae(b,b.s);window.addEventListener("resize",b.f,!1);Cesium.loadWithXhr.load=function(c,d,e,f,g,h,l,m,n){h.promise.always(b.f);b.fa(c,d,e,f,g,h,l,m,n)};Cesium.TaskProcessor.prototype.f=function(c,d){var e=b.J.call(this,c,d),f=this;if(!f.a){var g=f._worker;f.a=g.onmessage;g.onmessage=function(c){f.a(c); +b.a()}}return e};Cesium.Camera.prototype.setView=function(){b.la.apply(this,arguments);b.a()};Cesium.Camera.prototype.move=function(){b.v.apply(this,arguments);b.a()};Cesium.Camera.prototype.rotate=function(){b.F.apply(this,arguments);b.a()};Cesium.Camera.prototype.lookAt=function(){b.D.apply(this,arguments);b.a()};Cesium.Camera.prototype.flyTo=function(){b.u.apply(this,arguments);b.a()};b.c.H.Oa().K("change",b.f)} +ye.prototype.I=function(){var b=Date.now(),c=this.O,d=c.camera;Cesium.Matrix4.equalsEpsilon(this.j,d.viewMatrix,1E-5)||(this.b=b);var e=c.globe._surface,e=!e._tileProvider.ready||0<e._tileLoadQueue.length||0<e._debug.tilesWaitingForChildren,c=c.tweens;1E3>b-this.b||e||0!=c.length||(this.i&&console.log("stopping rendering @ "+Date.now()),this.c.re(!0),this.g=!0);Cesium.Matrix4.clone(d.viewMatrix,this.j)};ye.prototype.l=function(){this.a()}; +ye.prototype.a=function(){this.i&&this.g&&console.log("starting rendering @ "+Date.now());this.b=Date.now();this.c.re(!1);this.g=!1};ye.prototype.L=function(b){this.i=b};function Be(b){return function(){return b}}var Ce=Be(!1),De=Be(!0);function Ee(b){var c;c=c||0;return function(){return b.apply(this,Array.prototype.slice.call(arguments,0,c))}}function Fe(b){var c=arguments,d=c.length;return function(){for(var b=0;b<d;b++)if(!c[b].apply(this,arguments))return!1;return!0}};function Ge(b,c,d){Sb.call(this);this.a=null;this.c=!1;this.s=b;this.i=d;this.f=c||window;this.b=ra(this.g,this)}y(Ge,Sb);Ge.prototype.start=function(){He(this);this.c=!1;var b=Ie(this),c=Je(this);b&&!c&&this.f.mozRequestAnimationFrame?(this.a=z(this.f,"MozBeforePaint",this.b),this.f.mozRequestAnimationFrame(null),this.c=!0):this.a=b&&c?b.call(this.f,this.b):this.f.setTimeout(Ee(this.b),20)}; +function He(b){if(null!=b.a){var c=Ie(b),d=Je(b);c&&!d&&b.f.mozRequestAnimationFrame?yc(b.a):c&&d?d.call(b.f,b.a):b.f.clearTimeout(b.a)}b.a=null}Ge.prototype.g=function(){this.c&&this.a&&yc(this.a);this.a=null;this.s.call(this.i,ta())};Ge.prototype.ba=function(){He(this);Ge.ka.ba.call(this)};function Ie(b){b=b.f;return b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame||b.oRequestAnimationFrame||b.msRequestAnimationFrame||null} +function Je(b){b=b.f;return b.cancelAnimationFrame||b.cancelRequestAnimationFrame||b.webkitCancelRequestAnimationFrame||b.mozCancelRequestAnimationFrame||b.oCancelRequestAnimationFrame||b.msCancelRequestAnimationFrame||null};function Ke(){};function Le(b,c,d,e,f,g){Xb.call(this,b,c);this.vectorContext=d;this.frameState=e;this.context=f;this.glContext=g}y(Le,Xb);function D(b){var c=Ia(b);delete c.source;pe.call(this,c);this.b=this.g=this.c=null;b.map&&this.setMap(b.map);z(this,Kc("source"),this.ki,!1,this);this.yc(b.source?b.source:null)}y(D,pe);k=D.prototype;k.Id=function(b){b=b?b:[];b.push(qe(this));return b};k.da=function(){return this.get("source")||null};k.Nd=function(){var b=this.da();return b?b.D:"undefined"};k.Gj=function(){this.A()};k.ki=function(){this.b&&(yc(this.b),this.b=null);var b=this.da();b&&(this.b=z(b,"change",this.Gj,!1,this));this.A()}; +k.setMap=function(b){yc(this.c);this.c=null;b||this.A();yc(this.g);this.g=null;b&&(this.c=z(b,"precompose",function(b){var d=qe(this);d.kc=!1;d.zIndex=Infinity;b.frameState.layerStatesArray.push(d);b.frameState.layerStates[u(this)]=d},!1,this),this.g=z(this,"change",b.render,!1,b),this.A())};k.yc=function(b){this.C("source",b)};function F(b){b=b?b:{};var c=Ia(b);delete c.preload;delete c.useInterimTilesOnError;D.call(this,c);this.j(void 0!==b.preload?b.preload:0);this.l(void 0!==b.useInterimTilesOnError?b.useInterimTilesOnError:!0)}y(F,D);F.prototype.a=function(){return this.get("preload")};F.prototype.j=function(b){this.C("preload",b)};F.prototype.i=function(){return this.get("useInterimTilesOnError")};F.prototype.l=function(b){this.C("useInterimTilesOnError",b)};function Me(b,c){Cc.call(this);this.a=b;this.state=c;this.f=null;this.key=""}y(Me,Cc);function Ne(b){b.B("change")}Me.prototype.de=function(){return u(this).toString()};function Oe(b,c,d,e,f){Me.call(this,b,c);this.i=d;this.b=new Image;null!==e&&(this.b.crossOrigin=e);this.c={};this.g=null;this.s=f}y(Oe,Me);k=Oe.prototype;k.ba=function(){1==this.state&&Pe(this);this.f&&Wb(this.f);Oe.ka.ba.call(this)};k.Mb=function(b){if(void 0!==b){var c=u(b);if(c in this.c)return this.c[c];b=Da(this.c)?this.b:this.b.cloneNode(!1);return this.c[c]=b}return this.b};k.de=function(){return this.i};k.Vi=function(){this.state=3;Pe(this);Ne(this)}; +k.Wi=function(){this.state=this.b.naturalWidth&&this.b.naturalHeight?2:4;Pe(this);Ne(this)};k.load=function(){0==this.state&&(this.state=1,Ne(this),this.g=[wc(this.b,"error",this.Vi,!1,this),wc(this.b,"load",this.Wi,!1,this)],this.s(this,this.i))};function Pe(b){b.g.forEach(yc);b.g=null};function Qe(){this.c=0;this.b={};this.a=this.f=null}k=Qe.prototype;k.clear=function(){this.c=0;this.b={};this.a=this.f=null};k.forEach=function(b,c){for(var d=this.f;d;)b.call(c,d.Ab,d.Vd,this),d=d.Ma};k.get=function(b){b=this.b[b];if(b===this.a)return b.Ab;b===this.f?(this.f=this.f.Ma,this.f.jb=null):(b.Ma.jb=b.jb,b.jb.Ma=b.Ma);b.Ma=null;b.jb=this.a;this.a=this.a.Ma=b;return b.Ab};k.fc=function(){return this.c};k.P=function(){var b=Array(this.c),c=0,d;for(d=this.a;d;d=d.jb)b[c++]=d.Vd;return b}; +k.ob=function(){var b=Array(this.c),c=0,d;for(d=this.a;d;d=d.jb)b[c++]=d.Ab;return b};k.pop=function(){var b=this.f;delete this.b[b.Vd];b.Ma&&(b.Ma.jb=null);this.f=b.Ma;this.f||(this.a=null);--this.c;return b.Ab};k.replace=function(b,c){this.get(b);this.b[b].Ab=c};function Re(b,c,d){d={Vd:c,Ma:null,jb:b.a,Ab:d};b.a?b.a.Ma=d:b.f=d;b.a=d;b.b[c]=d;++b.c};function Se(b){Qe.call(this);this.g=void 0!==b?b:2048}y(Se,Qe);function Te(b){return b.fc()>b.g}function Ue(b,c){for(var d,e;Te(b)&&!(d=b.f.Ab,e=d.a[0].toString(),e in c&&c[e].contains(d.a));)b.pop().Fc()};var Ve=!Ab||9<=Ob;!Cb&&!Ab||Ab&&9<=Ob||Cb&&Mb("1.9.1");Ab&&Mb("9");function We(b,c){this.x=ca(b)?b:0;this.y=ca(c)?c:0}k=We.prototype;k.clone=function(){return new We(this.x,this.y)};k.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};k.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};k.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};k.scale=function(b,c){var d=ia(c)?c:b;this.x*=b;this.y*=d;return this};function Xe(b,c){this.width=b;this.height=c}k=Xe.prototype;k.clone=function(){return new Xe(this.width,this.height)};k.Ig=function(){return this.width*this.height};k.Pa=function(){return!this.Ig()};k.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};k.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};k.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this}; +k.scale=function(b,c){var d=ia(c)?c:b;this.width*=b;this.height*=d;return this};function Ye(b){return b?new Ze($e(b)):Ma||(Ma=new Ze)}function af(b){var c=document;return ha(b)?c.getElementById(b):b} +function bf(b){var c=b||document,d=null;if(c.getElementsByClassName)d=c.getElementsByClassName("ol-overlaycontainer")[0];else if(c.querySelectorAll&&c.querySelector)d=c.querySelector(".ol-overlaycontainer");else{var e,c=document;b=b||c;if(b.querySelectorAll&&b.querySelector)b=b.querySelectorAll(".ol-overlaycontainer");else if(b.getElementsByClassName){var f=b.getElementsByClassName("ol-overlaycontainer");b=f}else{f=b.getElementsByTagName("*");e={};for(c=d=0;b=f[c];c++){var g=b.className,h;if(h="function"== +typeof g.split)h=0<=bb(g.split(/\s+/),"ol-overlaycontainer");h&&(e[d++]=b)}e.length=d;b=e}d=b[0]}return d||null}function cf(b,c){ua(c,function(c,e){"style"==e?b.style.cssText=c:"class"==e?b.className=c:"for"==e?b.htmlFor=c:df.hasOwnProperty(e)?b.setAttribute(df[e],c):0==e.lastIndexOf("aria-",0)||0==e.lastIndexOf("data-",0)?b.setAttribute(e,c):b[e]=c})} +var df={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:"height",maxlength:"maxLength",role:"role",rowspan:"rowSpan",type:"type",usemap:"useMap",valign:"vAlign",width:"width"};function ff(b){b=b.document.documentElement;return new Xe(b.clientWidth,b.clientHeight)} +function gf(b,c,d){var e=arguments,f=document,g=e[0],h=e[1];if(!Ve&&h&&(h.name||h.type)){g=["<",g];h.name&&g.push(' name="',Oa(h.name),'"');if(h.type){g.push(' type="',Oa(h.type),'"');var l={};La(l,h);delete l.type;h=l}g.push(">");g=g.join("")}g=f.createElement(g);h&&(ha(h)?g.className=h:fa(h)?g.className=h.join(" "):cf(g,h));2<e.length&&hf(f,g,e,2);return g} +function hf(b,c,d,e){function f(d){d&&c.appendChild(ha(d)?b.createTextNode(d):d)}for(;e<d.length;e++){var g=d[e];!ga(g)||ma(g)&&0<g.nodeType?f(g):db(jf(g)?jb(g):g,f)}}function kf(b,c){hf($e(b),b,arguments,1)}function lf(b){b&&b.parentNode&&b.parentNode.removeChild(b)}function mf(b){if(ca(b.nextElementSibling))b=b.nextElementSibling;else for(b=b.nextSibling;b&&1!=b.nodeType;)b=b.nextSibling;return b} +function nf(b,c){if(b.contains&&1==c.nodeType)return b==c||b.contains(c);if("undefined"!=typeof b.compareDocumentPosition)return b==c||Boolean(b.compareDocumentPosition(c)&16);for(;c&&b!=c;)c=c.parentNode;return c==b}function $e(b){return 9==b.nodeType?b:b.ownerDocument||b.document}function jf(b){if(b&&"number"==typeof b.length){if(ma(b))return"function"==typeof b.item||"string"==typeof b.item;if(la(b))return"function"==typeof b.item}return!1}function Ze(b){this.a=b||ba.document||document} +Ze.prototype.M=cf;Ze.prototype.appendChild=function(b,c){b.appendChild(c)};Ze.prototype.contains=nf;function of(b,c){var d=document.createElement("CANVAS");b&&(d.width=b);c&&(d.height=c);return d.getContext("2d")};var pf=!((xb("Chrome")||xb("CriOS"))&&!xb("Opera")&&!xb("OPR")&&!xb("Edge"))||yb()||xb("iPad")||xb("iPod");function qf(b,c,d,e){var f=le(d,c,b);d=c.getPointResolution(e,d);c=c.nb();void 0!==c&&(d*=c);c=b.nb();void 0!==c&&(d/=c);b=b.getPointResolution(d,f)/d;isFinite(b)&&!isNaN(b)&&0<b&&(d/=b);return d}function rf(b,c,d,e){b=d-b;c=e-c;var f=Math.sqrt(b*b+c*c);return[Math.round(d+b/f),Math.round(e+c/f)]} +function sf(b,c,d,e,f,g,h,l,m,n){var p=of(Math.round(d*b),Math.round(d*c));if(0===m.length)return p.canvas;p.scale(d,d);var q=hd();m.forEach(function(b){wd(q,b.extent)});var r=of(Math.round(d*Bd(q)/e),Math.round(d*Dd(q)/e));r.scale(d/e,d/e);r.translate(-q[0],q[3]);m.forEach(function(b){r.drawImage(b.image,b.extent[0],-b.extent[3],Bd(b.extent),Dd(b.extent))});var t=yd(h);l.c.forEach(function(b){var c=b.source,f=b.target,h=c[1][0],l=c[1][1],m=c[2][0],n=c[2][1];b=(f[0][0]-t[0])/g;var ja=-(f[0][1]-t[1])/ +g,P=(f[1][0]-t[0])/g,Aa=-(f[1][1]-t[1])/g,va=(f[2][0]-t[0])/g,kb=-(f[2][1]-t[1])/g,f=c[0][0],c=c[0][1],h=h-f,l=l-c,m=m-f,n=n-c;a:{h=[[h,l,0,0,P-b],[m,n,0,0,va-b],[0,0,h,l,Aa-ja],[0,0,m,n,kb-ja]];l=h.length;for(m=0;m<l;m++){for(var n=m,Xa=Math.abs(h[m][m]),cb=m+1;cb<l;cb++){var lb=Math.abs(h[cb][m]);lb>Xa&&(Xa=lb,n=cb)}if(0===Xa){h=null;break a}Xa=h[n];h[n]=h[m];h[m]=Xa;for(n=m+1;n<l;n++)for(Xa=-h[n][m]/h[m][m],cb=m;cb<l+1;cb++)h[n][cb]=m==cb?0:h[n][cb]+Xa*h[m][cb]}m=Array(l);for(n=l-1;0<=n;n--)for(m[n]= +h[n][l]/h[n][n],Xa=n-1;0<=Xa;Xa--)h[Xa][l]-=h[Xa][n]*m[n];h=m}h&&(p.save(),p.beginPath(),pf?(m=(b+P+va)/3,n=(ja+Aa+kb)/3,l=rf(m,n,b,ja),P=rf(m,n,P,Aa),va=rf(m,n,va,kb),p.moveTo(l[0],l[1]),p.lineTo(P[0],P[1]),p.lineTo(va[0],va[1])):(p.moveTo(b,ja),p.lineTo(P,Aa),p.lineTo(va,kb)),p.closePath(),p.clip(),p.transform(h[0],h[2],h[1],h[3],b,ja),p.translate(q[0]-f,q[3]-c),p.scale(e/d,-e/d),p.drawImage(r.canvas,0,0),p.restore())});n&&(p.save(),p.strokeStyle="black",p.lineWidth=1,l.c.forEach(function(b){var c= +b.target;b=(c[0][0]-t[0])/g;var d=-(c[0][1]-t[1])/g,e=(c[1][0]-t[0])/g,f=-(c[1][1]-t[1])/g,h=(c[2][0]-t[0])/g,c=-(c[2][1]-t[1])/g;p.beginPath();p.moveTo(b,d);p.lineTo(e,f);p.lineTo(h,c);p.closePath();p.stroke()}),p.restore());return p.canvas};function tf(b,c,d,e,f){this.b=b;this.g=c;var g={},h=je(this.g,this.b);this.f=function(b){var c=b[0]+"/"+b[1];g[c]||(g[c]=h(b));return g[c]};this.i=e;this.u=f*f;this.c=[];this.j=!1;this.l=this.b.f&&!!e&&!!this.b.G()&&Bd(e)==Bd(this.b.G());this.a=this.b.G()?Bd(this.b.G()):null;this.s=this.g.G()?Bd(this.g.G()):null;b=yd(d);c=[d[2],d[3]];e=[d[2],d[1]];d=[d[0],d[1]];f=this.f(b);var l=this.f(c),m=this.f(e),n=this.f(d);uf(this,b,c,e,d,f,l,m,n,10);if(this.j){var p=Infinity;this.c.forEach(function(b){p=Math.min(p, +b.source[0][0],b.source[1][0],b.source[2][0])});this.c.forEach(function(b){if(Math.max(b.source[0][0],b.source[1][0],b.source[2][0])-p>this.a/2){var c=[[b.source[0][0],b.source[0][1]],[b.source[1][0],b.source[1][1]],[b.source[2][0],b.source[2][1]]];c[0][0]-p>this.a/2&&(c[0][0]-=this.a);c[1][0]-p>this.a/2&&(c[1][0]-=this.a);c[2][0]-p>this.a/2&&(c[2][0]-=this.a);Math.max(c[0][0],c[1][0],c[2][0])-Math.min(c[0][0],c[1][0],c[2][0])<this.a/2&&(b.source=c)}},this)}g={}} +function uf(b,c,d,e,f,g,h,l,m,n){var p=gd([g,h,l,m]),q=b.a?Bd(p)/b.a:null,r=b.b.f&&.5<q&&1>q,t=!1;if(0<n){if(b.g.c&&b.s)var B=gd([c,d,e,f]),t=t|.25<Bd(B)/b.s;!r&&b.b.c&&q&&(t|=.25<q)}if(t||!b.i||Hd(p,b.i)){if(!(t||isFinite(g[0])&&isFinite(g[1])&&isFinite(h[0])&&isFinite(h[1])&&isFinite(l[0])&&isFinite(l[1])&&isFinite(m[0])&&isFinite(m[1])))if(0<n)t=!0;else return;if(0<n&&(t||(q=b.f([(c[0]+e[0])/2,(c[1]+e[1])/2]),p=r?(Tc(g[0],b.a)+Tc(l[0],b.a))/2-Tc(q[0],b.a):(g[0]+l[0])/2-q[0],q=(g[1]+l[1])/2-q[1], +t=p*p+q*q>b.u),t)){Math.abs(c[0]-e[0])<=Math.abs(c[1]-e[1])?(r=[(d[0]+e[0])/2,(d[1]+e[1])/2],p=b.f(r),q=[(f[0]+c[0])/2,(f[1]+c[1])/2],t=b.f(q),uf(b,c,d,r,q,g,h,p,t,n-1),uf(b,q,r,e,f,t,p,l,m,n-1)):(r=[(c[0]+d[0])/2,(c[1]+d[1])/2],p=b.f(r),q=[(e[0]+f[0])/2,(e[1]+f[1])/2],t=b.f(q),uf(b,c,r,q,f,g,p,t,m,n-1),uf(b,r,d,e,q,p,h,l,t,n-1));return}if(r){if(!b.l)return;b.j=!0}b.c.push({source:[g,l,m],target:[c,e,f]});b.c.push({source:[g,h,l],target:[c,d,e]})}} +function vf(b){var c=hd();b.c.forEach(function(b){b=b.source;id(c,b[0]);id(c,b[1]);id(c,b[2])});return c};function wf(b,c,d,e,f,g,h,l,m,n,p){Me.call(this,[f,g,h],0);this.v=void 0!==p?p:!1;this.D=l;this.i=null;this.g={};this.s=c;this.l=e;this.b=[];this.c=null;this.j=0;h=e.Ka(this.a);p=this.l.G();g=this.s.G();h=p?Gd(h,p):h;if(0===zd(h))this.state=4;else if((p=b.G())&&(g?g=Gd(g,p):g=p),e=e.V(f),e=qf(b,d,Ed(h),e),!isFinite(e)||isNaN(e)||0>=e)this.state=4;else if(this.u=new tf(b,d,h,g,e*(void 0!==n?n:.5)),0===this.u.c.length)this.state=4;else if(this.j=xf(c,e),d=vf(this.u),g&&(b.f?(d[1]=Jd(d[1],g[1],g[3]), +d[3]=Jd(d[3],g[1],g[3])):d=Gd(d,g)),zd(d))if(b=c.fb(d,this.j),100>(b.f-b.a+1)*Sd(b)){for(c=b.a;c<=b.f;c++)for(d=b.c;d<=b.b;d++)(n=m(this.j,c,d,l))&&this.b.push(n);0===this.b.length&&(this.state=4)}else this.state=3;else this.state=4}y(wf,Me);wf.prototype.ba=function(){1==this.state&&(this.c.forEach(yc),this.c=null);wf.ka.ba.call(this)};wf.prototype.Mb=function(b){if(void 0!==b){var c=u(b);if(c in this.g)return this.g[c];b=Da(this.g)?this.i:this.i.cloneNode(!1);return this.g[c]=b}return this.i}; +function yf(b){var c=[];b.b.forEach(function(b){b&&2==b.state&&c.push({extent:this.s.Ka(b.a),image:b.Mb()})},b);b.b.length=0;var d=b.a,e=d[0],f=b.l.La(e),g=ia(f)?f:f[0],f=ia(f)?f:f[1],e=b.l.V(e),h=b.s.V(b.j),d=b.l.Ka(d);b.i=sf(g,f,b.D,h,b.s.G(),e,d,b.u,c,b.v);b.state=2;Ne(b)} +wf.prototype.load=function(){if(0==this.state){this.state=1;Ne(this);var b=0;this.c=[];this.b.forEach(function(c){var d=c.state;if(0==d||1==d){b++;var e;e=c.Uc("change",function(){var d=c.state;if(2==d||3==d||4==d)yc(e),b--,0===b&&(this.c.forEach(yc),this.c=null,yf(this))},!1,this);this.c.push(e)}},this);this.b.forEach(function(b){0==b.state&&b.load()});0===b&&yf(this)}};function zf(b,c){var d=/\{z\}/g,e=/\{x\}/g,f=/\{y\}/g,g=/\{-y\}/g;return function(h){if(h)return b.replace(d,h[0].toString()).replace(e,h[1].toString()).replace(f,function(){return(-h[2]-1).toString()}).replace(g,function(){return(Sd(c.f?c.f[h[0]]:null)+h[2]).toString()})}}function Af(b,c){for(var d=b.length,e=Array(d),f=0;f<d;++f)e[f]=zf(b[f],c);return Bf(e)}function Bf(b){return 1===b.length?b[0]:function(c,d,e){if(c)return b[Tc((c[1]<<c[0])+c[2],b.length)](c,d,e)}}function Cf(){} +function Df(b){var c=[],d=/\{(\d)-(\d)\}/.exec(b)||/\{([a-z])-([a-z])\}/.exec(b);if(d){var e=d[2].charCodeAt(0),f;for(f=d[1].charCodeAt(0);f<=e;++f)c.push(b.replace(d[0],String.fromCharCode(f)))}else c.push(b);return c};function Ef(b,c,d){var e=b.length;if(b[0]<=c)return 0;if(!(c<=b[e-1]))if(0<d)for(d=1;d<e;++d){if(b[d]<c)return d-1}else if(0>d)for(d=1;d<e;++d){if(b[d]<=c)return d}else for(d=1;d<e;++d){if(b[d]==c)return d;if(b[d]<c)return b[d-1]-c<c-b[d]?d-1:d}return e-1};function Ff(b){this.minZoom=void 0!==b.minZoom?b.minZoom:0;this.a=b.resolutions;this.maxZoom=this.a.length-1;this.b=void 0!==b.origin?b.origin:null;this.g=null;void 0!==b.origins&&(this.g=b.origins);var c=b.extent;void 0===c||this.b||this.g||(this.b=yd(c));this.i=null;void 0!==b.tileSizes&&(this.i=b.tileSizes);this.j=void 0!==b.tileSize?b.tileSize:this.i?null:256;this.u=void 0!==c?c:null;this.f=null;void 0!==b.sizes?this.f=b.sizes.map(function(b){return new Pd(Math.min(0,b[0]),Math.max(b[0]-1,-1), +Math.min(0,b[1]),Math.max(b[1]-1,-1))},this):c&&Gf(this,c);this.c=[0,0]}var Hf=[0,0,0];function If(b,c,d,e,f){f=b.Ka(c,f);for(c=c[0]-1;c>=b.minZoom;){if(d.call(null,c,b.fb(f,c,e)))return!0;--c}return!1}k=Ff.prototype;k.G=function(){return this.u};k.df=function(){return this.maxZoom};k.ef=function(){return this.minZoom};k.Aa=function(b){return this.b?this.b:this.g[b]};k.V=function(b){return this.a[b]};k.Qf=function(){return this.a}; +function Jf(b,c,d,e){return c[0]<b.maxZoom?(e=b.Ka(c,e),b.fb(e,c[0]+1,d)):null}function Kf(b,c,d,e){Lf(b,c[0],c[1],d,!1,Hf);var f=Hf[1],g=Hf[2];Lf(b,c[2],c[3],d,!0,Hf);b=Hf[1];c=Hf[2];void 0!==e?(e.a=f,e.f=b,e.c=g,e.b=c):e=new Pd(f,b,g,c);return e}k.fb=function(b,c,d){c=this.V(c);return Kf(this,b,c,d)};function Mf(b,c){var d=b.Aa(c[0]),e=b.V(c[0]),f=fd(b.La(c[0]),b.c);return[d[0]+(c[1]+.5)*f[0]*e,d[1]+(c[2]+.5)*f[1]*e]} +k.Ka=function(b,c){var d=this.Aa(b[0]),e=this.V(b[0]),f=fd(this.La(b[0]),this.c),g=d[0]+b[1]*f[0]*e,d=d[1]+b[2]*f[1]*e;return kd(g,d,g+f[0]*e,d+f[1]*e,c)};k.Od=function(b,c,d){return Lf(this,b[0],b[1],c,!1,d)};function Lf(b,c,d,e,f,g){var h=xf(b,e),l=e/b.V(h),m=b.Aa(h);b=fd(b.La(h),b.c);c=l*Math.floor((c-m[0])/e+(f?.5:0))/b[0];d=l*Math.floor((d-m[1])/e+(f?0:.5))/b[1];f?(c=Math.ceil(c)-1,d=Math.ceil(d)-1):(c=Math.floor(c),d=Math.floor(d));f=c;void 0!==g?(g[0]=h,g[1]=f,g[2]=d):g=[h,f,d];return g} +k.Pd=function(b,c,d){c=this.V(c);return Lf(this,b[0],b[1],c,!1,d)};k.La=function(b){return this.j?this.j:this.i[b]};function xf(b,c){var d=Ef(b.a,c,0);return Jd(d,b.minZoom,b.maxZoom)}function Gf(b,c){for(var d=b.a.length,e=Array(d),f=b.minZoom;f<d;++f)e[f]=b.fb(c,f);b.f=e}function Nf(b){var c=b.s;if(!c){for(var c=Of(b),d=Dd(c),e=Bd(c),f=fd(256),d=Math.max(e/f[0],d/f[1]),e=Array(43),f=0;43>f;++f)e[f]=d/Math.pow(2,f);c=new Ff({extent:c,origin:yd(c),resolutions:e,tileSize:void 0});b.s=c}return c} +function Of(b){b=Zd(b);var c=b.G();c||(b=180*Wd.degrees/b.nb(),c=kd(-b,-b,b,b));return c}Ff.prototype.getTileRangeForExtentAndZ=Ff.prototype.fb;function Pf(b){ne.call(this,{attributions:b.attributions,extent:b.extent,logo:b.logo,projection:b.projection,state:b.state,wrapX:b.wrapX});this.ya=void 0!==b.opaque?b.opaque:!1;this.ra=void 0!==b.tilePixelRatio?b.tilePixelRatio:1;this.tileGrid=void 0!==b.tileGrid?b.tileGrid:null;this.a=new Se(b.Oe);this.c=[0,0]}y(Pf,ne);k=Pf.prototype;k.If=function(){return Te(this.a)};k.Jf=function(b,c){var d=this.ic(b);d&&Ue(d,c)}; +function Qf(b,c,d,e,f){c=b.ic(c);if(!c)return!1;for(var g=!0,h,l,m=e.a;m<=e.f;++m)for(var n=e.c;n<=e.b;++n)h=b.Gb(d,m,n),l=!1,c.b.hasOwnProperty(h)&&(h=c.get(h),(l=2===h.state)&&(l=!1!==f(h))),l||(g=!1);return g}k.Ze=function(){return 0};k.bf=function(){return""};k.Gb=Nd;k.Qd=function(){return this.tileGrid};k.Wa=function(b){return this.tileGrid?this.tileGrid:Nf(b)};k.ic=function(b){var c=this.i;return c&&!ie(c,b)?null:this.a}; +k.Lc=function(b,c,d){c=this.Wa(d);return ed(fd(c.La(b),this.c),this.ra,this.c)};k.ng=Id;function Rf(b,c){Xb.call(this,b);this.tile=c}y(Rf,Xb);function Sf(b){Pf.call(this,{attributions:b.attributions,Oe:b.Oe,extent:b.extent,logo:b.logo,opaque:b.opaque,projection:b.projection,state:b.state?b.state:void 0,tileGrid:b.tileGrid,tilePixelRatio:b.tilePixelRatio,wrapX:b.wrapX});this.tileLoadFunction=b.tileLoadFunction;this.tileUrlFunction=b.tileUrlFunction?b.tileUrlFunction:Cf;this.urls=null;b.urls?b.tileUrlFunction?this.urls=b.urls:this.md(b.urls):b.url&&this.ad(b.url);b.tileUrlFunction&&this.Ub(b.tileUrlFunction)}y(Sf,Pf);k=Sf.prototype; +k.Rd=function(){return this.tileLoadFunction};k.Sd=function(){return this.tileUrlFunction};k.Td=function(){return this.urls};k.Vj=function(b){b=b.target;switch(b.state){case 1:this.B(new Rf("tileloadstart",b));break;case 2:this.B(new Rf("tileloadend",b));break;case 3:this.B(new Rf("tileloaderror",b))}};k.ye=function(b){this.a.clear();this.tileLoadFunction=b;this.A()};k.Ub=function(b){this.a.clear();this.tileUrlFunction=b;this.A()};k.ad=function(b){this.Ub(Af(Df(b),this.tileGrid));this.urls=[b]}; +k.md=function(b){this.Ub(Af(b,this.tileGrid));this.urls=b};k.ng=function(b,c,d){b=this.Gb(b,c,d);this.a.b.hasOwnProperty(b)&&this.a.get(b)};function G(b){Sf.call(this,{attributions:b.attributions,extent:b.extent,logo:b.logo,opaque:b.opaque,projection:b.projection,state:void 0!==b.state?b.state:void 0,tileGrid:b.tileGrid,tileLoadFunction:b.tileLoadFunction?b.tileLoadFunction:Tf,tilePixelRatio:b.tilePixelRatio,tileUrlFunction:b.tileUrlFunction,url:b.url,urls:b.urls,wrapX:b.wrapX});this.crossOrigin=void 0!==b.crossOrigin?b.crossOrigin:null;this.tileClass=void 0!==b.tileClass?b.tileClass:Oe;this.g={};this.u={};this.Ea=b.reprojectionErrorThreshold; +this.L=!1}y(G,Sf);k=G.prototype;k.If=function(){return Te(this.a)?!0:wa(this.g,function(b){return Te(b)})};k.Jf=function(b,c){var d=this.ic(b);Ue(this.a,this.a==d?c:{});ua(this.g,function(b){Ue(b,b==d?c:{})})};k.Wa=function(b){var c=this.i;return!this.tileGrid||c&&!ie(c,b)?(c=u(b).toString(),c in this.u||(this.u[c]=Nf(b)),this.u[c]):this.tileGrid};k.ic=function(b){var c=this.i;if(!c||ie(c,b))return this.a;b=u(b).toString();b in this.g||(this.g[b]=new Se);return this.g[b]}; +function Uf(b,c,d,e,f,g,h){e=c=[c,d,e];var l=void 0!==g?g:b.i;d=b.Wa(l);if(b.F&&l.c){var m=e;e=m[0];var n=Mf(d,m),l=Of(l);od(l,n)?e=m:(m=Bd(l),n[0]+=m*Math.ceil((l[0]-n[0])/m),e=d.Pd(n,e))}m=e[0];n=e[1];l=e[2];if(d.minZoom>m||m>d.maxZoom)d=!1;else{var p=d.G();d=(d=p?d.fb(p,m):d.f?d.f[m]:null)?Qd(d,n,l):!0}f=(d=d?e:null)?b.tileUrlFunction(d,f,g):void 0;f=new b.tileClass(c,void 0!==f?0:4,void 0!==f?f:"",b.crossOrigin,b.tileLoadFunction);f.key=h;z(f,"change",b.Vj,!1,b);return f} +function Vf(b,c,d,e,f,g){if(b.i&&g&&!ie(b.i,g)){f=b.ic(g);var h=b.Gb(c,d,e);if(f.b.hasOwnProperty(h))return f.get(h);var l=b.i,m=b.Wa(l),n=b.Wa(g);b=new wf(l,m,g,n,c,d,e,b.ra,ra(function(b,c,d,e){return Wf(this,b,c,d,e,l)},b),b.Ea,b.L);Re(f,h,b);return b}return Wf(b,c,d,e,f,g)} +function Wf(b,c,d,e,f,g){var h=null,l=b.Gb(c,d,e),m=b.bf();if(b.a.b.hasOwnProperty(l)){if(h=b.a.get(l),h.key!=m){var n=h;h.f&&h.f.key==m?(h=h.f,2==n.state&&(h.f=n)):(h=Uf(b,c,d,e,f,g,m),2==n.state?h.f=n:n.f&&2==n.f.state&&(h.f=n.f,n.f=null));h.f&&(h.f.f=null);b.a.replace(l,h)}}else h=Uf(b,c,d,e,f,g,m),Re(b.a,l,h);return h}k.ve=function(b){this.L!=b&&(this.L=b,ua(this.g,function(b){b.clear()}),this.A())};k.xe=function(b,c){var d=Zd(b);d&&(d=u(d).toString(),d in this.u||(this.u[d]=c))}; +function Tf(b,c){b.Mb().src=c};var Xf=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;function Yf(b,c){if(b)for(var d=b.split("&"),e=0;e<d.length;e++){var f=d[e].indexOf("="),g=null,h=null;0<=f?(g=d[e].substring(0,f),h=d[e].substring(f+1)):g=d[e];c(g,h?decodeURIComponent(h.replace(/\+/g," ")):"")}} +function Zf(b){if(b[1]){var c=b[0],d=c.indexOf("#");0<=d&&(b.push(c.substr(d)),b[0]=c=c.substr(0,d));d=c.indexOf("?");0>d?b[1]="?":d==c.length-1&&(b[1]=void 0)}return b.join("")}function $f(b,c,d){if(fa(c))for(var e=0;e<c.length;e++)$f(b,String(c[e]),d);else null!=c&&d.push("&",b,""===c?"":"=",encodeURIComponent(String(c)))}function ag(b,c){for(var d in c)$f(d,c[d],b);return b};function bg(b){this.s=b.matrixIds;Ff.call(this,{extent:b.extent,origin:b.origin,origins:b.origins,resolutions:b.resolutions,tileSize:b.tileSize,tileSizes:b.tileSizes,sizes:b.sizes})}y(bg,Ff);bg.prototype.l=function(){return this.s};function H(b){function c(b){b="KVP"==e?Zf(ag([b],g)):b.replace(/\{(\w+?)\}/g,function(b,c){return c.toLowerCase()in g?g[c.toLowerCase()]:b});return function(c){if(c){var d={TileMatrix:f.s[c[0]],TileCol:c[1],TileRow:-c[2]-1};La(d,h);c=b;return c="KVP"==e?Zf(ag([c],d)):c.replace(/\{(\w+?)\}/g,function(b,c){return d[c]})}}}this.ea=void 0!==b.version?b.version:"1.0.0";this.I=void 0!==b.format?b.format:"image/jpeg";this.b=void 0!==b.dimensions?b.dimensions:{};this.l="";cg(this);this.U=b.layer;this.v=b.matrixSet; +this.ca=b.style;var d=b.urls;void 0===d&&void 0!==b.url&&(d=Df(b.url));var e=this.qa=void 0!==b.requestEncoding?b.requestEncoding:"KVP",f=b.tileGrid,g={layer:this.U,style:this.ca,tilematrixset:this.v};"KVP"==e&&La(g,{Service:"WMTS",Request:"GetTile",Version:this.ea,Format:this.I});var h=this.b,l=d&&0<d.length?Bf(d.map(c)):Cf;G.call(this,{attributions:b.attributions,crossOrigin:b.crossOrigin,logo:b.logo,projection:b.projection,reprojectionErrorThreshold:b.reprojectionErrorThreshold,tileClass:b.tileClass, +tileGrid:f,tileLoadFunction:b.tileLoadFunction,tilePixelRatio:b.tilePixelRatio,tileUrlFunction:l,urls:d,wrapX:void 0!==b.wrapX?b.wrapX:!1})}y(H,G);k=H.prototype;k.gh=function(){return this.b};k.Wj=function(){return this.I};k.bf=function(){return this.l};k.Xj=function(){return this.U};k.zh=function(){return this.v};k.Jh=function(){return this.qa};k.Yj=function(){return this.ca};k.Qh=function(){return this.ea};function cg(b){var c=0,d=[],e;for(e in b.b)d[c++]=e+"-"+b.b[e];b.l=d.join("/")} +k.Al=function(b){La(this.b,b);cg(this);this.A()};function dg(b,c){this.a=b;this.f=null;this.j=ca(c)?c:null;this.g=!1;this.s=new Cesium.Event;this.b=document.createElement("CANVAS");this.b.width=1;this.b.height=1;this.a.K("change",function(){eg(this)},this);eg(this)} +Object.defineProperties(dg.prototype,{ready:{get:function(){return this.g}},rectangle:{get:function(){return this.l}},tileWidth:{get:function(){var b=this.a.tileGrid;return null===b?256:b.La(0)}},tileHeight:{get:function(){return this.tileWidth}},maximumLevel:{get:function(){var b=this.a.tileGrid;return null===b?18:b.maxZoom}},minimumLevel:{get:function(){return 0}},tilingScheme:{get:function(){return this.c}},tileDiscardPolicy:{get:function(){}},errorEvent:{get:function(){return this.s}},credit:{get:function(){return this.i}}, +proxy:{get:function(){}},hasAlphaChannel:{get:function(){return!0}},Pl:{get:function(){}}});function eg(b){if(!b.g&&"ready"==b.a.D){var c=b.a.i;b.f=null!=c?c:b.j;if(b.f==Zd("EPSG:4326"))b.c=new Cesium.GeographicTilingScheme;else if(b.f==Zd("EPSG:3857"))b.c=new Cesium.WebMercatorTilingScheme;else return;b.l=b.c.rectangle;c=fg(b.a);b.i=null===c?void 0:c;b.g=!0}} +function fg(b){var c="",d=b.j;null===d||d.forEach(function(b){c+=b.a().replace(/<\/?[^>]+(>|$)/g,"")+" "});var e,f;0==c.length&&(b=b.J,ca(b)&&("string"==typeof b?e=b:(e=b.src,f=b.href)));return ca(e)||0<c.length?new Cesium.Credit(c,e,f):null}dg.prototype.getTileCredits=function(){};dg.prototype.getTileCredits=dg.prototype.getTileCredits; +dg.prototype.requestImage=function(b,c,d){var e=this.a.tileUrlFunction;if(null===e||null===this.f)return this.b;b=e([this.c instanceof Cesium.GeographicTilingScheme?d+1:d,b,-c-1],1,this.f);return ca(b)?Cesium.ImageryProvider.loadImage(this,b):this.b};dg.prototype.requestImage=dg.prototype.requestImage;function gg(b,c,d,e,f){var g=Cesium.Math.clamp,h=Cesium.defaultValue;f=f||{};var l=h(f.duration,500),m=h(f.easing,hg),n=f.callback,p=ta(),q=0,r=new Cesium.Matrix4,t=new Ge(function(f){f=m(g((f-p)/l,0,1));b.transform.clone(r);var h=(f-q)*c;q=f;b.lookAtTransform(e);b.rotate(d,h);b.lookAtTransform(r);1>f?t.start():n&&n()});t.start()}function ig(b,c){var d=b.camera.getPickRay(c);return b.globe.pick(d,b)||b.camera.pickEllipsoid(c)} +function jg(b){var c=b.canvas,c=new Cesium.Cartesian2(c.clientWidth/2,c.clientHeight/2);return ig(b,c)}function kg(b,c,d){var e=new Cesium.Cartesian3,f=new Cesium.Cartesian3,g=new Cesium.Cartesian3;Cesium.Cartesian3.normalize(b,e);Cesium.Cartesian3.normalize(c,f);Cesium.Cartesian3.cross(e,f,g);b=Cesium.Cartesian3.dot(e,f);c=Cesium.Cartesian3.magnitude(g);d=Cesium.Cartesian3.dot(d,g);g=Math.atan2(c,b);return 0<=d?g:-g} +function lg(b,c){var d=b.camera,e=d.frustum.fovy/2,f;f=b.camera;var g=f.direction,h=Cesium.Quaternion.fromAxisAngle(f.right,f.frustum.fovy/2),h=Cesium.Matrix3.fromQuaternion(h),l=new Cesium.Cartesian3;Cesium.Matrix3.multiplyByVector(h,g,l);f=new Cesium.Ray(f.position,l);f=Cesium.Cartesian3.clone(f.direction);Cesium.Cartesian3.negate(f,f);g=new Cesium.Cartesian3;Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(c,g);h=new Cesium.Cartesian3;Cesium.Cartesian3.negate(d.right,h);return kg(g,f,h)+e} +function mg(b,c,d){ca(d)&&(d=d.getHeight(c),c.height=ca(d)?d:0);d=Cesium.Ellipsoid.WGS84;c=d.cartographicToCartesian(c);var e=b.position,f=new Cesium.Cartesian3;d.geocentricSurfaceNormal(e,f);b.lookAt(e,c,f)}function ng(b,c){if(null===b||null===c)return null;var d=me(b,c,"EPSG:4326");return Cesium.Rectangle.fromDegrees(d[0],d[1],d[2],d[3])} +function og(b,c){if(!(b instanceof F))return null;var d=null,d=b.da();if(!(d instanceof H)&&d instanceof G){var e=d.i;if(null===e)e=c;else if(e!==c)return null;var f=e===Zd("EPSG:3857"),e=e===Zd("EPSG:4326");if(f||e)d=new dg(d,c);else return null}else return null;f={};e=b.G();null!=e&&null!==c&&(f.rectangle=ng(e,c));return new Cesium.ImageryLayer(d,f)}function rg(b,c){var d=b.tb();ca(d)&&(c.alpha=d);d=b.Ha();ca(d)&&(c.show=d)} +function sg(b){return 2<b.length?Cesium.Cartesian3.fromDegrees(b[0],b[1],b[2]):Cesium.Cartesian3.fromDegrees(b[0],b[1])}function tg(b){for(var c=[],d=0;d<b.length;++d)c.push(sg(b[d]));return c}function ug(b,c){var d=Zd("EPSG:4326"),e=Zd(c);if(e!==d){var f=b.S();b=b.clone();b.transform(e,d);b.M(f)}return b} +function vg(b){b=b||"black";if(Array.isArray(b))return new Cesium.Color(Cesium.Color.byteToFloat(b[0]),Cesium.Color.byteToFloat(b[1]),Cesium.Color.byteToFloat(b[2]),b[3]);if("string"==typeof b)return Cesium.Color.fromCssColorString(b)};function wg(b,c){this.O=b;this.f=b.camera;this.H=c;this.s=this.a=null;this.g=this.b=xg;this.c=this.i=0;this.l=null;this.j=!1;this.H.K("change:view",function(){yg(this,this.H.ja())},this);yg(this,this.H.ja())}function xg(b,c,d){d=d||b.length;if(c)for(var e=0;e<d;++e)c[e]=b[e];return b}function yg(b,c){null!==b.a&&(yc(b.s),b.s=null);b.a=c;if(null===c)b.b=xg,b.g=xg;else{var d=je(c.a,"EPSG:4326"),e=je("EPSG:4326",c.a);b.b=d;b.g=e;b.s=c.K("propertychange",b.oi,b);b.uc()}}k=wg.prototype; +k.oi=function(){this.j||this.uc()};k.gl=function(b){null===this.a||this.a.Nb(b)};k.vk=function(){if(null!==this.a){var b=this.a.xa();return ca(b)?b:0}};k.ql=function(b){this.i=b;zg(this)};k.Oh=function(){return this.i};k.al=function(b){this.c=b;zg(this);this.zb()};k.uk=function(){return this.c};k.yk=function(b){null===this.a||this.a.Ca(b)};k.tk=function(){return null===this.a?void 0:this.a.wa()}; +k.zk=function(b){null!==this.b&&(b=this.b(b),b=new Cesium.Cartographic(b[0]*Math.PI/180,b[1]*Math.PI/180,this.Rf()),this.f.position=Cesium.Ellipsoid.WGS84.cartographicToCartesian(b),this.zb())};k.wk=function(){if(null!==this.g){var b=Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.f.position);return this.g([180*b.longitude/Math.PI,180*b.latitude/Math.PI])}}; +k.Zk=function(b){var c=Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.f.position);c.height=b;this.f.position=Cesium.Ellipsoid.WGS84.cartographicToCartesian(c);this.zb()};k.Rf=function(){return Cesium.Ellipsoid.WGS84.cartesianToCartographic(this.f.position).height};k.xk=function(b){null!==this.b&&(b=this.b(b),b=Cesium.Cartographic.fromDegrees(b[0],b[1]),mg(this.f,b,this.O.globe),this.zb())}; +function zg(b){if(null!==b.a&&null!==b.b){var c=b.a.wa();if(c){c=b.b(c);c=new Cesium.Cartographic(c[0]*Math.PI/180,c[1]*Math.PI/180);if(b.O.globe){var d=b.O.globe.getHeight(c);c.height=ca(d)?d:0}c=Cesium.Ellipsoid.WGS84.cartographicToCartesian(c);d={pitch:b.i-Cesium.Math.PI_OVER_TWO,heading:-b.a.xa(),roll:void 0};b.f.setView({destination:c,orientation:d});b.f.moveBackward(b.c);Ag(b,!0)}}} +k.uc=function(){if(null!==this.a&&null!==this.b){var b=this.a.wa();if(null!=b){var b=this.b(b),c=this.a.V();this.c=(ca(c)?c:0)*this.O.canvas.clientHeight*this.a.a.nb()*Math.cos(Math.abs(b[1]*Math.PI/180))/2/Math.tan(this.f.frustum.fovy/2);zg(this)}}}; +k.zb=function(){if(null!==this.a&&null!==this.g){this.j=!0;var b=Cesium.Ellipsoid.WGS84,c=this.O,d=jg(c),e=d;e||(e=c.globe,c=this.f.positionCartographic.clone(),e=e.getHeight(c),c.height=ca(e)?e:0,e=Cesium.Ellipsoid.WGS84.cartographicToCartesian(c));this.c=Cesium.Cartesian3.distance(e,this.f.position);c=b.cartesianToCartographic(e);this.a.Ca(this.g([180*c.longitude/Math.PI,180*c.latitude/Math.PI]));this.a.xb(2*this.c*Math.tan(this.f.frustum.fovy/2)/this.a.a.nb()/Math.cos(Math.abs(c?c.latitude:0))/ +this.O.canvas.clientHeight);if(d){e=this.f.position;c=new Cesium.Cartesian3;b.geocentricSurfaceNormal(d,c);b=new Cesium.Cartesian3;Cesium.Cartesian3.subtract(e,d,b);Cesium.Cartesian3.normalize(b,b);var e=this.f.up,f=this.f.right,g=new Cesium.Cartesian3(-d.y,d.x,0),f=Cesium.Cartesian3.angleBetween(f,g),d=Cesium.Cartesian3.cross(d,e,new Cesium.Cartesian3).z;this.a.Nb(0>d?f:-f);d=Math.acos(Cesium.Cartesian3.dot(c,b));this.i=isNaN(d)?0:d}else this.a.Nb(this.f.heading),this.i=-this.f.pitch+Math.PI/2;this.j= +!1}};function Ag(b,c){var d=b.l,e=b.f.viewMatrix;d&&Cesium.Matrix4.equalsEpsilon(d,e,1E-5)||(b.l=e.clone(),!0!==c&&b.zb())};function Bg(b,c){var d=new Cesium.BillboardCollection({scene:c}),e=new Cesium.PrimitiveCollection;this.f=[];this.a=new Cesium.PrimitiveCollection;this.b={projection:b,billboards:d,featureToCesiumMap:{},primitives:e};this.a.add(d);this.a.add(e)}Bg.prototype.destroy=function(){this.f.forEach(Gc);this.f.length=0};function Cg(b){b=ca(b)?b:{};Cc.call(this);this.f=this.O=null;this.a=new Cesium.RectanglePrimitive({asynchronous:!1,rectangle:new Cesium.Rectangle,material:Cesium.Material.fromType(Cesium.Material.ColorType)});this.a.material.uniforms.color=new Cesium.Color(0,0,1,.5);this.b=ca(b.wi)?b.wi:Cesium.KeyboardEventModifier.SHIFT;this.c=null}y(Cg,Cc); +Cg.prototype.s=function(b){var c=this.O.globe.ellipsoid;b=this.O.camera.getPickRay(b.position);b=this.O.globe.pick(b,this.O);ca(b)&&(this.f.setInputAction(this.i.bind(this),Cesium.ScreenSpaceEventType.MOUSE_MOVE),this.f.setInputAction(this.g.bind(this),Cesium.ScreenSpaceEventType.LEFT_UP),ca(this.b)&&(this.f.setInputAction(this.i.bind(this),Cesium.ScreenSpaceEventType.MOUSE_MOVE,this.b),this.f.setInputAction(this.g.bind(this),Cesium.ScreenSpaceEventType.LEFT_UP,this.b)),c=c.cartesianToCartographic(b), +b=this.a.rectangle,b.north=b.south=c.latitude,b.east=b.west=c.longitude,this.a.height=c.height,this.a.show=!0,this.B({type:"boxstart",position:c}),this.O.primitives.contains(this.a)||this.O.primitives.add(this.a),this.O.screenSpaceCameraController.enableInputs=!1,this.c=c)}; +Cg.prototype.i=function(b){var c=this.O.globe.ellipsoid;b=this.O.camera.getPickRay(b.endPosition);b=this.O.globe.pick(b,this.O);ca(b)&&(c=c.cartesianToCartographic(b),this.a.height=Math.max(this.a.height,c.height),c.latitude<this.c.latitude?this.a.rectangle.south=c.latitude:this.a.rectangle.north=c.latitude,c.longitude<this.c.longitude?this.a.rectangle.west=c.longitude:this.a.rectangle.east=c.longitude)}; +Cg.prototype.g=function(b){var c=this.O.globe.ellipsoid;b=this.O.camera.getPickRay(b.position);b=this.O.globe.pick(b,this.O);ca(b)&&(c=c.cartesianToCartographic(b),this.a.show=!1,this.B({type:"boxend",position:c}),this.f.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP),this.f.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE),ca(this.b)&&(this.f.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP,this.b),this.f.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE,this.b)));this.O.screenSpaceCameraController.enableInputs= +!0};Cg.prototype.j=function(b){null===b?(this.O.primitives.contains(this.a)&&this.O.primitives.remove(this.a),null!==this.f&&(this.f.destroy(),this.f=null)):(this.f=new Cesium.ScreenSpaceEventHandler(b.canvas),this.f.setInputAction(this.s.bind(this),Cesium.ScreenSpaceEventType.LEFT_DOWN,this.b));this.O=b};function Dg(){Ic.call(this);this.u=hd();this.D=-1;this.g={};this.l=this.i=0}y(Dg,Ic);k=Dg.prototype;k.Ta=function(b,c){var d=c?c:[NaN,NaN];this.Ia(b[0],b[1],d,Infinity);return d};k.Qe=function(b){return this.sb(b[0],b[1])};k.sb=Ce;k.G=function(b){this.D!=this.f&&(this.u=this.Dc(this.u),this.D=this.f);var c=this.u;b?(b[0]=c[0],b[1]=c[1],b[2]=c[2],b[3]=c[3]):b=c;return b};k.Za=function(b){return this.gc(b*b)};k.transform=function(b,c){this.Eb(je(b,c));return this};function Eg(b,c,d,e,f,g){var h=f[0],l=f[1],m=f[4],n=f[5],p=f[12];f=f[13];for(var q=g?g:[],r=0;c<d;c+=e){var t=b[c],B=b[c+1];q[r++]=h*t+m*B+p;q[r++]=l*t+n*B+f}g&&q.length!=r&&(q.length=r);return q};function Fg(){Dg.call(this);this.b="XY";this.a=2;this.o=null}y(Fg,Dg);function Gg(b){if("XY"==b)return 2;if("XYZ"==b||"XYM"==b)return 3;if("XYZM"==b)return 4}k=Fg.prototype;k.sb=Ce;k.Dc=function(b){return td(this.o,0,this.o.length,this.a,b)};k.Va=function(){return this.o.slice(0,this.a)};k.ga=function(){return this.o};k.cb=function(){return this.o.slice(this.o.length-this.a)};k.eb=function(){return this.b}; +k.gc=function(b){this.l!=this.f&&(Ea(this.g),this.i=0,this.l=this.f);if(0>b||0!==this.i&&b<=this.i)return this;var c=b.toString();if(this.g.hasOwnProperty(c))return this.g[c];var d=this.Kb(b);if(d.ga().length<this.o.length)return this.g[c]=d;this.i=b;return this};k.Kb=function(){return this};k.pa=function(){return this.a};function Hg(b,c,d){b.a=Gg(c);b.b=c;b.o=d} +function Ig(b,c,d,e){if(c)d=Gg(c);else{for(c=0;c<e;++c){if(0===d.length){b.b="XY";b.a=2;return}d=d[0]}d=d.length;c=2==d?"XY":3==d?"XYZ":4==d?"XYZM":void 0}b.b=c;b.a=d}k.Eb=function(b){this.o&&(b(this.o,this.o,this.a),this.A())};k.fe=function(b,c){var d=this.ga();if(d){var e=this.pa(),f=d.length,g=d?d:[],h=0,l,m;for(l=0;l<f;l+=e)for(g[h++]=d[l]+b,g[h++]=d[l+1]+c,m=l+2;m<l+e;++m)g[h++]=d[m];d&&g.length!=h&&(g.length=h);this.A()}};function Jg(b){this.scene=b;this.a=this.Bk.bind(this)}k=Jg.prototype;k.Bk=function(b){var c=b.target,d=c.olcs_cancellers;if(d)if(b=b.feature,ca(b)){var c=u(b),e=d[c];e&&(e(),delete d[c])}else{for(e in d)if(d.hasOwnProperty(e))d[e]();c.olcs_cancellers={}}}; +function Kg(b,c,d,e,f,g,h){var l={flat:!0,renderState:{depthTest:{enabled:!0}}};ca(h)&&(l.renderState||(l.renderState={}),l.renderState.lineWidth=h);f=new Cesium.GeometryInstance({geometry:f,attributes:{color:Cesium.ColorGeometryInstanceAttribute.fromColor(g)}});b.Hc(c,d,e)==Cesium.HeightReference.CLAMP_TO_GROUND?b=new Cesium.GroundPrimitive({geometryInstance:f}):(b=new Cesium.PerInstanceColorAppearance(l),b=new Cesium.Primitive({geometryInstances:f,appearance:b}));e=b;e.olLayer=c;e.olFeature=d;return b} +function Lg(b,c){var d=b.va()?b.va().a:null,e=b.sa()?b.sa().a:null,f="black";e&&c?f=e:d&&(f=d);return vg(f)}function Mg(b,c){return Math.min(c.sa()?c.sa().f:1,b.scene.maximumAliasedLineWidth)}function Ng(b,c,d,e,f,g,h){var l=Lg(h,!1),m=Lg(h,!0),n=new Cesium.PrimitiveCollection;h.va()&&(f=Kg(b,c,d,e,f,l),n.add(f));h.sa()&&(f=Kg(b,c,d,e,g,m,Mg(b,h)),n.add(f));return n} +function Og(b,c,d,e,f,g){var h;g instanceof Cesium.PrimitiveCollection?h=g:(h=new Cesium.PrimitiveCollection,h.add(g));if(!f.na())return h;(b=b.of(c,d,e,f.na()))&&h.add(b);return h}k.Se=function(b,c,d,e){b=b.add(c);b.olLayer=d;b.olFeature=e;return b}; +k.nf=function(b,c,d,e,f){d=ug(d,e);e=d.lc();var g=3==e.length?e[2]:0,h=e.slice();h[0]+=d.ee();e=sg(e);var h=sg(h),l=Cesium.Cartesian3.distance(e,h),h=new Cesium.CircleGeometry({center:e,radius:l,height:g});e=new Cesium.CircleOutlineGeometry({center:e,radius:l,extrudedHeight:g,height:g});e=Ng(this,b,c,d,h,e,f);return Og(this,b,c,d,f,e)}; +k.Yd=function(b,c,d,e,f){d=ug(d,e);var g=tg(d.T());e=new Cesium.PolylineMaterialAppearance({material:this.qf(0,f,!0)});g=new Cesium.PolylineGeometry({positions:g,width:Mg(this,f),vertexFormat:e.vertexFormat});e=new Cesium.Primitive({geometryInstances:new Cesium.GeometryInstance({geometry:g}),appearance:e});e.olLayer=b;e.olFeature=c;return Og(this,b,c,d,f,e)}; +k.Zd=function(b,c,d,e,f){d=ug(d,e);for(var g=d.Kd(),h=e={},l=0;l<g.length;++l){var m=g[l].T(),m=tg(m);0==l?e.positions=m:(e.holes={positions:m},e=e.holes)}g=new Cesium.PolygonGeometry({polygonHierarchy:h,perPositionHeight:!0});e=new Cesium.PolygonOutlineGeometry({polygonHierarchy:e,perPositionHeight:!0});e=Ng(this,b,c,d,g,e,f);return Og(this,b,c,d,f,e)}; +k.Hc=function(b,c,d){d=d.get("altitudeMode");ca(d)||(d=c.get("altitudeMode"));ca(d)||(d=b.get("altitudeMode"));b=Cesium.HeightReference.NONE;"clampToGround"===d?b=Cesium.HeightReference.CLAMP_TO_GROUND:"relativeToGround"===d&&(b=Cesium.HeightReference.RELATIVE_TO_GROUND);return b}; +k.Wc=function(b,c,d,e,f,g,h){d=ug(d,e);var l=f.a;if(l){l instanceof Pg&&l.load();var m=l.ib(1),n=function(){if(null!==m&&(m instanceof HTMLCanvasElement||m instanceof Image||m instanceof HTMLImageElement)){var e=d.T(),e=sg(e),f,n=l.u;ca(n)&&(f=new Cesium.Color(1,1,1,n));n=this.Hc(b,c,d);f=this.Se(g,{image:m,color:f,heightReference:n,verticalOrigin:Cesium.VerticalOrigin.BOTTOM,position:e},b,c);h&&h(f)}}.bind(this);if(m instanceof Image&&(""==m.src||0==m.naturalHeight||0==m.naturalWidth||!m.complete)){var p= +!1;e=b.da();e instanceof Qg&&(e=e.b);e.K(["removefeature","clear"],this.a);var q=e.olcs_cancellers;q||(q=e.olcs_cancellers={});q[u(c)]=function(){p=!0};wc(m,"load",function(){g.isDestroyed()||p||n()})}else n()}return f.na()?Og(this,b,c,d,f,new Cesium.Primitive):null}; +k.pf=function(b,c,d,e,f,g,h){function l(d,g){var h=new Cesium.PrimitiveCollection;d.forEach(function(d){h.add(g(b,c,d,e,f))});return h}switch(d.N()){case "MultiPoint":d=d.ge();if(f.na()){var m=new Cesium.PrimitiveCollection;d.forEach(function(d){(d=this.Wc(b,c,d,e,f,g,h))&&m.add(d)}.bind(this));return m}d.forEach(function(d){this.Wc(b,c,d,e,f,g,h)});return null;case "MultiLineString":return d=d.Jd(),l(d,this.Yd.bind(this));case "MultiPolygon":return d=d.Ld(),l(d,this.Zd.bind(this))}}; +k.of=function(b,c,d,e){var f=e.na(),g=new Cesium.LabelCollection({scene:this.scene}),h=Ed(d.G());if(d instanceof Fg){var l=d.Va();h[2]=3==l.length?l[2]:0}l={};l.position=sg(h);l.text=f;l.heightReference=this.Hc(b,c,d);d=e.b;f=e.c;0!=d&&0!=f&&(d=new Cesium.Cartesian2(d,f),l.pixelOffset=d);d=e.f;null!=d&&(l.font=d);d=void 0;e.va()&&(l.fillColor=Lg(e,!1),d=Cesium.LabelStyle.FILL);e.sa()&&(l.outlineWidth=Mg(this,e),l.outlineColor=Lg(e,!0),d=Cesium.LabelStyle.OUTLINE);e.va()&&e.sa()&&(d=Cesium.LabelStyle.FILL_AND_OUTLINE); +l.style=d;switch(e.i){case "left":d=Cesium.HorizontalOrigin.LEFT;break;case "right":d=Cesium.HorizontalOrigin.RIGHT;break;default:d=Cesium.HorizontalOrigin.CENTER}l.horizontalOrigin=d;if(e.a){var m;switch(e.a){case "top":m=Cesium.VerticalOrigin.TOP;break;case "middle":m=Cesium.VerticalOrigin.CENTER;break;case "bottom":m=Cesium.VerticalOrigin.BOTTOM;break;case "alphabetic":m=Cesium.VerticalOrigin.TOP;break;case "hanging":m=Cesium.VerticalOrigin.BOTTOM}l.verticalOrigin=m}e=g.add(l);e.olLayer=b;e.olFeature= +c;return g};k.qf=function(b,c,d){b=c.va();c=c.sa();if(d&&!c||!d&&!b)return null;b=d?c.a:b.a;b=vg(b);return d&&c.b?Cesium.Material.fromType("Stripe",{horizontal:!1,repeat:500,evenColor:b,oddColor:new Cesium.Color(0,0,0,0)}):Cesium.Material.fromType("Color",{color:b})};k.wd=function(b,c,d,e){b=c.Lb();var f;ca(b)&&(f=b.call(c,e));null==f&&null!=d&&(f=d(c,e));return ca(f)?f[0]:null}; +k.Vc=function(b,c,d,e,f){function g(b){e.featureToCesiumMap[u(c)]=b}f=f||c.R();var h=e.projection;if(!f)return null;switch(f.N()){case "GeometryCollection":var l=new Cesium.PrimitiveCollection;f.Ye().forEach(function(f){f&&(f=this.Vc(b,c,d,e,f))&&l.add(f)}.bind(this));return l;case "Point":return(f=this.Wc(b,c,f,h,d,e.billboards,g))?f:null;case "Circle":return this.nf(b,c,f,h,d);case "LineString":return this.Yd(b,c,f,h,d);case "Polygon":return this.Zd(b,c,f,h,d);case "MultiPoint":case "MultiLineString":case "MultiPolygon":return(f= +this.pf(b,c,f,h,d,e.billboards,g))?f:null;case "LinearRing":throw Error("LinearRing should only be part of polygon.");default:throw Error("Ol geom type not handled : "+f.N());}}; +k.rf=function(b,c,d){var e=c.a;c=c.V();if(!ca(c)||!e)throw Error("View not ready");var f=b.da();if(b instanceof I)if(f instanceof Qg)f=f.b;else return new Bg(e,this.scene);for(var f=f.ke(),e=new Bg(e,this.scene),g=e.b,h=0;h<f.length;++h){var l=f[h];if(null!=l){var m;m=b instanceof I?b.da().g:b.a;if(m=this.wd(0,l,m,c))if(m=this.Vc(b,l,m,g))d[u(l)]=m,e.a.add(m)}}return e}; +k.convert=function(b,c,d,e){var f=c.a;c=c.V();if(!ca(c)||!f)return null;var g;if(b instanceof I)if(g=b.da(),g instanceof Qg)g=g.g;else return null;else g=b.a;c=this.wd(0,d,g,c);if(!c)return null;e.projection=f;return this.Vc(b,d,c,e)};function Rg(b,c){this.ab=c.imageryLayers;this.Rb=new Cesium.ImageryLayerCollection;re.call(this,b,c)}y(Rg,re);k=Rg.prototype;k.Le=function(b){this.ab.add(b);this.Rb.add(b)};k.Ue=function(b){b.destroy()};k.Wf=function(b,c){this.ab.remove(b,c);this.Rb.remove(b,!1)};k.Uf=function(b){for(var c=0;c<this.Rb.length;++c)this.ab.remove(this.Rb.get(c),b);this.Rb.removeAll(!1)};k.Re=function(b,c){var d=og(b,c);return d?[d]:null}; +k.xd=function(b){var c=this.Re(b,this.view.a);if(null!==c){b.K(["change:opacity","change:visible"],function(){for(var d=0;d<c.length;++d)rg(b,c[d])});for(var d=0;d<c.length;++d)rg(b,c[d]);b.K("change:extent",function(){for(var d=0;d<c.length;++d)this.ab.remove(c[d],!0),this.Rb.remove(c[d],!1);delete this.pb[u(b)];this.ze()},this);b.K("change",function(){for(var b=0;b<c.length;++b){var d=this.ab.indexOf(c[b]);0<=d&&(this.ab.remove(c[b],!1),this.ab.add(c[b],d))}},this)}return Array.isArray(c)?c:null}; +k.me=function(){for(var b=[],c={},d=[this.c];0<d.length;){var e=d.splice(0,1)[0];b.push(e);c[u(e)]=e.ma();e instanceof C&&(e=e.Na(),ca(e)&&e.forEach(function(b){d.push(b)}))}rb(b,function(b,d){return c[u(b)]-c[u(d)]});b.forEach(function(b){b=u(b);(b=this.pb[b])&&b.forEach(this.Ak,this)},this)};k.Ak=function(b){this.ab.raiseToTop(b)};var Sg=/^#(?:[0-9a-f]{3}){1,2}$/i,Tg=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i,Ug=/^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;function Vg(b){return fa(b)?b:Wg(b)}function Xg(b){if(!ha(b)){var c=b[0];c!=(c|0)&&(c=c+.5|0);var d=b[1];d!=(d|0)&&(d=d+.5|0);var e=b[2];e!=(e|0)&&(e=e+.5|0);b="rgba("+c+","+d+","+e+","+b[3]+")"}return b} +var Wg=function(){var b={},c=0;return function(d){var e;if(b.hasOwnProperty(d))e=b[d];else{if(1024<=c){e=0;for(var f in b)0===(e++&3)&&(delete b[f],--c)}var g,h;Sg.exec(d)?(h=3==d.length-1?1:2,e=parseInt(d.substr(1+0*h,h),16),f=parseInt(d.substr(1+1*h,h),16),g=parseInt(d.substr(1+2*h,h),16),1==h&&(e=(e<<4)+e,f=(f<<4)+f,g=(g<<4)+g),e=[e,f,g,1]):(h=Ug.exec(d))?(e=Number(h[1]),f=Number(h[2]),g=Number(h[3]),h=Number(h[4]),e=[e,f,g,h],e=Yg(e,e)):(h=Tg.exec(d))?(e=Number(h[1]),f=Number(h[2]),g=Number(h[3]), +e=[e,f,g,1],e=Yg(e,e)):e=void 0;b[d]=e;++c}return e}}();function Yg(b,c){var d=c||[];d[0]=Jd(b[0]+.5|0,0,255);d[1]=Jd(b[1]+.5|0,0,255);d[2]=Jd(b[2]+.5|0,0,255);d[3]=Jd(b[3],0,1);return d};var Zg=ba.devicePixelRatio||1,$g=!1,ah=function(){if(!("HTMLCanvasElement"in ba))return!1;try{var b=of();return b?(void 0!==b.setLineDash&&($g=!0),!0):!1}catch(c){return!1}}(),bh="DeviceOrientationEvent"in ba,ch="geolocation"in ba.navigator,dh="ontouchstart"in ba,eh="PointerEvent"in ba,fh=!!ba.navigator.msPointerEnabled;var gh=[0,0,0,1],hh=[],ih=[0,0,0,1];function jh(b){b=b||{};this.a=void 0!==b.color?b.color:null;this.f=void 0}jh.prototype.b=function(){return this.a};jh.prototype.c=function(b){this.a=b;this.f=void 0};jh.prototype.Sa=function(){void 0===this.f&&(this.f="f"+(this.a?Xg(this.a):"-"));return this.f};function kh(b){this.u=b.opacity;this.F=b.rotateWithView;this.D=b.rotation;this.s=b.scale;this.la=b.snapToPixel}k=kh.prototype;k.cd=function(){return this.u};k.Jc=function(){return this.F};k.dd=function(){return this.D};k.ed=function(){return this.s};k.Kc=function(){return this.la};k.fd=function(b){this.u=b};k.gd=function(b){this.D=b};k.hd=function(b){this.s=b};function lh(){this.f=-1};function mh(){this.f=-1;this.f=64;this.a=Array(4);this.g=Array(this.f);this.c=this.b=0;this.reset()}y(mh,lh);mh.prototype.reset=function(){this.a[0]=1732584193;this.a[1]=4023233417;this.a[2]=2562383102;this.a[3]=271733878;this.c=this.b=0}; +function nh(b,c,d){d||(d=0);var e=Array(16);if(ha(c))for(var f=0;16>f;++f)e[f]=c.charCodeAt(d++)|c.charCodeAt(d++)<<8|c.charCodeAt(d++)<<16|c.charCodeAt(d++)<<24;else for(f=0;16>f;++f)e[f]=c[d++]|c[d++]<<8|c[d++]<<16|c[d++]<<24;c=b.a[0];d=b.a[1];var f=b.a[2],g=b.a[3],h=0,h=c+(g^d&(f^g))+e[0]+3614090360&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[1]+3905402710&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+(d^g&(c^d))+e[2]+606105819&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^ +c))+e[3]+3250441966&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(g^d&(f^g))+e[4]+4118548399&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[5]+1200080426&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+(d^g&(c^d))+e[6]+2821735955&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^c))+e[7]+4249261313&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(g^d&(f^g))+e[8]+1770035416&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[9]+2336552879&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+ +(d^g&(c^d))+e[10]+4294925233&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^c))+e[11]+2304563134&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(g^d&(f^g))+e[12]+1804603682&4294967295;c=d+(h<<7&4294967295|h>>>25);h=g+(f^c&(d^f))+e[13]+4254626195&4294967295;g=c+(h<<12&4294967295|h>>>20);h=f+(d^g&(c^d))+e[14]+2792965006&4294967295;f=g+(h<<17&4294967295|h>>>15);h=d+(c^f&(g^c))+e[15]+1236535329&4294967295;d=f+(h<<22&4294967295|h>>>10);h=c+(f^g&(d^f))+e[1]+4129170786&4294967295;c=d+(h<<5&4294967295| +h>>>27);h=g+(d^f&(c^d))+e[6]+3225465664&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[11]+643717713&4294967295;f=g+(h<<14&4294967295|h>>>18);h=d+(g^c&(f^g))+e[0]+3921069994&4294967295;d=f+(h<<20&4294967295|h>>>12);h=c+(f^g&(d^f))+e[5]+3593408605&4294967295;c=d+(h<<5&4294967295|h>>>27);h=g+(d^f&(c^d))+e[10]+38016083&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[15]+3634488961&4294967295;f=g+(h<<14&4294967295|h>>>18);h=d+(g^c&(f^g))+e[4]+3889429448&4294967295;d=f+(h<<20&4294967295| +h>>>12);h=c+(f^g&(d^f))+e[9]+568446438&4294967295;c=d+(h<<5&4294967295|h>>>27);h=g+(d^f&(c^d))+e[14]+3275163606&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[3]+4107603335&4294967295;f=g+(h<<14&4294967295|h>>>18);h=d+(g^c&(f^g))+e[8]+1163531501&4294967295;d=f+(h<<20&4294967295|h>>>12);h=c+(f^g&(d^f))+e[13]+2850285829&4294967295;c=d+(h<<5&4294967295|h>>>27);h=g+(d^f&(c^d))+e[2]+4243563512&4294967295;g=c+(h<<9&4294967295|h>>>23);h=f+(c^d&(g^c))+e[7]+1735328473&4294967295;f=g+(h<<14&4294967295| +h>>>18);h=d+(g^c&(f^g))+e[12]+2368359562&4294967295;d=f+(h<<20&4294967295|h>>>12);h=c+(d^f^g)+e[5]+4294588738&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[8]+2272392833&4294967295;g=c+(h<<11&4294967295|h>>>21);h=f+(g^c^d)+e[11]+1839030562&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[14]+4259657740&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(d^f^g)+e[1]+2763975236&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[4]+1272893353&4294967295;g=c+(h<<11&4294967295|h>>>21);h=f+(g^ +c^d)+e[7]+4139469664&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[10]+3200236656&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(d^f^g)+e[13]+681279174&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[0]+3936430074&4294967295;g=c+(h<<11&4294967295|h>>>21);h=f+(g^c^d)+e[3]+3572445317&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[6]+76029189&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(d^f^g)+e[9]+3654602809&4294967295;c=d+(h<<4&4294967295|h>>>28);h=g+(c^d^f)+e[12]+3873151461&4294967295; +g=c+(h<<11&4294967295|h>>>21);h=f+(g^c^d)+e[15]+530742520&4294967295;f=g+(h<<16&4294967295|h>>>16);h=d+(f^g^c)+e[2]+3299628645&4294967295;d=f+(h<<23&4294967295|h>>>9);h=c+(f^(d|~g))+e[0]+4096336452&4294967295;c=d+(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[7]+1126891415&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[14]+2878612391&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[5]+4237533241&4294967295;d=f+(h<<21&4294967295|h>>>11);h=c+(f^(d|~g))+e[12]+1700485571&4294967295;c=d+ +(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[3]+2399980690&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[10]+4293915773&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[1]+2240044497&4294967295;d=f+(h<<21&4294967295|h>>>11);h=c+(f^(d|~g))+e[8]+1873313359&4294967295;c=d+(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[15]+4264355552&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[6]+2734768916&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[13]+1309151649&4294967295; +d=f+(h<<21&4294967295|h>>>11);h=c+(f^(d|~g))+e[4]+4149444226&4294967295;c=d+(h<<6&4294967295|h>>>26);h=g+(d^(c|~f))+e[11]+3174756917&4294967295;g=c+(h<<10&4294967295|h>>>22);h=f+(c^(g|~d))+e[2]+718787259&4294967295;f=g+(h<<15&4294967295|h>>>17);h=d+(g^(f|~c))+e[9]+3951481745&4294967295;b.a[0]=b.a[0]+c&4294967295;b.a[1]=b.a[1]+(f+(h<<21&4294967295|h>>>11))&4294967295;b.a[2]=b.a[2]+f&4294967295;b.a[3]=b.a[3]+g&4294967295} +mh.prototype.update=function(b,c){ca(c)||(c=b.length);for(var d=c-this.f,e=this.g,f=this.b,g=0;g<c;){if(0==f)for(;g<=d;)nh(this,b,g),g+=this.f;if(ha(b))for(;g<c;){if(e[f++]=b.charCodeAt(g++),f==this.f){nh(this,e);f=0;break}}else for(;g<c;)if(e[f++]=b[g++],f==this.f){nh(this,e);f=0;break}}this.b=f;this.c+=c};function oh(b){b=b||{};this.a=void 0!==b.color?b.color:null;this.c=b.lineCap;this.b=void 0!==b.lineDash?b.lineDash:null;this.g=b.lineJoin;this.i=b.miterLimit;this.f=b.width;this.s=void 0}k=oh.prototype;k.hk=function(){return this.a};k.vh=function(){return this.c};k.ik=function(){return this.b};k.wh=function(){return this.g};k.Ah=function(){return this.i};k.jk=function(){return this.f};k.kk=function(b){this.a=b;this.s=void 0};k.jl=function(b){this.c=b;this.s=void 0}; +k.lk=function(b){this.b=b;this.s=void 0};k.kl=function(b){this.g=b;this.s=void 0};k.ll=function(b){this.i=b;this.s=void 0};k.rl=function(b){this.f=b;this.s=void 0}; +k.Sa=function(){if(void 0===this.s){var b="s"+(this.a?Xg(this.a):"-")+","+(void 0!==this.c?this.c.toString():"-")+","+(this.b?this.b.toString():"-")+","+(void 0!==this.g?this.g:"-")+","+(void 0!==this.i?this.i.toString():"-")+","+(void 0!==this.f?this.f.toString():"-"),c=new mh;c.update(b);var d=Array((56>c.b?c.f:2*c.f)-c.b);d[0]=128;for(b=1;b<d.length-8;++b)d[b]=0;for(var e=8*c.c,b=d.length-8;b<d.length;++b)d[b]=e&255,e/=256;c.update(d);d=Array(16);for(b=e=0;4>b;++b)for(var f=0;32>f;f+=8)d[e++]= +c.a[b]>>>f&255;if(8192>=d.length)c=String.fromCharCode.apply(null,d);else for(c="",b=0;b<d.length;b+=8192)c+=String.fromCharCode.apply(null,ob(d,b,b+8192));this.s=c}return this.s};function ph(b){b=b||{};this.i=this.a=this.g=null;this.c=void 0!==b.fill?b.fill:null;this.f=void 0!==b.stroke?b.stroke:null;this.b=b.radius;this.v=[0,0];this.l=this.fa=this.j=null;var c=b.atlasManager,d,e=null,f,g=0;this.f&&(f=Xg(this.f.a),g=this.f.f,void 0===g&&(g=1),e=this.f.b,$g||(e=null));var h=2*(this.b+g)+1;f={strokeStyle:f,zc:g,size:h,lineDash:e};void 0===c?(this.a=document.createElement("CANVAS"),this.a.height=h,this.a.width=h,d=h=this.a.width,c=this.a.getContext("2d"),this.Mf(f,c,0,0),this.c? +this.i=this.a:(c=this.i=document.createElement("CANVAS"),c.height=f.size,c.width=f.size,c=c.getContext("2d"),this.Lf(f,c,0,0))):(h=Math.round(h),(e=!this.c)&&(d=ra(this.Lf,this,f)),g=this.Sa(),f=c.add(g,h,h,ra(this.Mf,this,f),d),this.a=f.image,this.v=[f.offsetX,f.offsetY],d=f.image.width,this.i=e?f.si:this.a);this.j=[h/2,h/2];this.fa=[h,h];this.l=[d,d];kh.call(this,{opacity:1,rotateWithView:!1,rotation:0,scale:1,snapToPixel:void 0!==b.snapToPixel?b.snapToPixel:!0})}y(ph,kh);k=ph.prototype;k.mb=function(){return this.j}; +k.Zj=function(){return this.c};k.le=function(){return this.i};k.ib=function(){return this.a};k.tc=function(){return 2};k.Ic=function(){return this.l};k.Aa=function(){return this.v};k.$j=function(){return this.b};k.Ya=function(){return this.fa};k.ak=function(){return this.f};k.Xd=Id;k.load=Id;k.Ae=Id; +k.Mf=function(b,c,d,e){c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();c.arc(b.size/2,b.size/2,this.b,0,2*Math.PI,!0);this.c&&(c.fillStyle=Xg(this.c.a),c.fill());this.f&&(c.strokeStyle=b.strokeStyle,c.lineWidth=b.zc,b.lineDash&&c.setLineDash(b.lineDash),c.stroke());c.closePath()}; +k.Lf=function(b,c,d,e){c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();c.arc(b.size/2,b.size/2,this.b,0,2*Math.PI,!0);c.fillStyle=Xg(gh);c.fill();this.f&&(c.strokeStyle=b.strokeStyle,c.lineWidth=b.zc,b.lineDash&&c.setLineDash(b.lineDash),c.stroke());c.closePath()};k.Sa=function(){var b=this.f?this.f.Sa():"-",c=this.c?this.c.Sa():"-";this.g&&b==this.g[1]&&c==this.g[2]&&this.b==this.g[3]||(this.g=["c"+b+c+(void 0!==this.b?this.b.toString():"-"),b,c,this.b]);return this.g[0]};function qh(b){b=b||{};this.b=null;this.f=rh;void 0!==b.geometry&&this.Pf(b.geometry);this.g=void 0!==b.fill?b.fill:null;this.a=void 0!==b.image?b.image:null;this.i=void 0!==b.stroke?b.stroke:null;this.s=void 0!==b.text?b.text:null;this.c=b.zIndex}k=qh.prototype;k.R=function(){return this.b};k.ph=function(){return this.f};k.va=function(){return this.g};k.mk=function(){return this.a};k.sa=function(){return this.i};k.na=function(){return this.s};k.ma=function(){return this.c}; +k.Pf=function(b){la(b)?this.f=b:ha(b)?this.f=function(c){return c.get(b)}:b?void 0!==b&&(this.f=function(){return b}):this.f=rh;this.b=b};k.nk=function(b){this.c=b};function sh(b){if(!la(b)){var c;c=fa(b)?b:[b];b=function(){return c}}return b}var th=null;function uh(){if(!th){var b=new jh({color:"rgba(255,255,255,0.4)"}),c=new oh({color:"#3399CC",width:1.25});th=[new qh({image:new ph({fill:b,stroke:c,radius:5}),fill:b,stroke:c})]}return th} +function vh(){var b={},c=[255,255,255,1],d=[0,153,255,1];b.Polygon=[new qh({fill:new jh({color:[255,255,255,.5]})})];b.MultiPolygon=b.Polygon;b.LineString=[new qh({stroke:new oh({color:c,width:5})}),new qh({stroke:new oh({color:d,width:3})})];b.MultiLineString=b.LineString;b.Circle=b.Polygon.concat(b.LineString);b.Point=[new qh({image:new ph({radius:6,fill:new jh({color:d}),stroke:new oh({color:c,width:1.5})}),zIndex:Infinity})];b.MultiPoint=b.Point;b.GeometryCollection=b.Polygon.concat(b.LineString, +b.Point);return b}function rh(b){return b.R()}w("ol.style.defaultStyleFunction",uh);function J(b){b=b?b:{};var c=Ia(b);delete c.style;delete c.renderBuffer;delete c.updateWhileAnimating;delete c.updateWhileInteracting;D.call(this,c);this.j=void 0!==b.renderBuffer?b.renderBuffer:100;this.i=null;this.a=void 0;this.l(b.style);this.F=void 0!==b.updateWhileAnimating?b.updateWhileAnimating:!1;this.J=void 0!==b.updateWhileInteracting?b.updateWhileInteracting:!1}y(J,D);J.prototype.u=function(){return this.i};J.prototype.D=function(){return this.a}; +J.prototype.l=function(b){this.i=void 0!==b?b:uh;this.a=null===b?void 0:sh(this.i);this.A()};function wh(b,c,d){this.g=d||new Jg(c);this.a=new Cesium.PrimitiveCollection;c.primitives.add(this.a);this.a.destroyPrimitives=!1;re.call(this,b,c)}y(wh,re);k=wh.prototype;k.Le=function(b){b.a.counterpart=b;this.a.add(b.a)};k.Ue=function(b){b.a.destroy()};k.Wf=function(b,c){b.destroy();this.a.destroyPrimitives=c;this.a.remove(b.a);this.a.destroyPrimitives=!1}; +k.Uf=function(b){if(this.a.destroyPrimitives=b)for(b=0;b<this.a.length;++b)this.a.get(b).counterpart.destroy();this.a.removeAll();this.a.destroyPrimitives=!1}; +k.xd=function(b){if(!(b instanceof J||b instanceof I&&b.da()instanceof Qg))return null;var c=b.da();c instanceof Qg&&(c=c.b);var d=this.view,e={},f=this.g.rf(b,d,e),g=f.a,h=f.f;g.show=b.Ha();h.push(b.K("change:visible",function(){g.show=b.Ha()}));var l=function(c){var h=this.g.convert(b,d,c,f.b);h&&(e[u(c)]=h,g.add(h))}.bind(this),m=function(b){var c=b.R();b=u(b);if(!c||"Point"==c.N()){var c=f.b,d=c.featureToCesiumMap[b];delete c.featureToCesiumMap[b];d instanceof Cesium.Billboard&&c.billboards.remove(d)}c= +e[b];delete e[b];null!=c&&g.remove(c)}.bind(this);h.push(c.K("addfeature",function(b){l(b.feature)},this));h.push(c.K("removefeature",function(b){m(b.feature)},this));h.push(c.K("changefeature",function(b){b=b.feature;m(b);l(b)},this));return f?[f]:null};function xh(b){this.f=null;this.H=b.map;this.j=1;this.l=this.u=0;this.s=!0;this.c=gf("DIV",{style:"position:absolute;top:0;left:0;width:100%;height:100%;visibility:hidden;"});var c=af(b.target||null);if(c)c.appendChild(this.c);else{var d=bf(this.H.a);d&&d.parentNode&&d.parentNode.insertBefore(this.c,d)}this.g=null==c;this.a=gf("CANVAS",{style:"position:absolute;top:0;left:0;width:100%;height:100%;"});this.a.oncontextmenu=function(){return!1};this.a.onselectstart=function(){return!1};this.c.appendChild(this.a); +this.bb=!1;this.i=[];this.b=null;this.O=new Cesium.Scene({canvas:this.a,scene3DOnly:!0});c=this.O.screenSpaceCameraController;c.inertiaSpin=0;c.inertiaTranslate=0;c.inertiaZoom=0;c.tiltEventTypes.push({eventType:Cesium.CameraEventType.LEFT_DRAG,modifier:Cesium.KeyboardEventModifier.SHIFT});c.tiltEventTypes.push({eventType:Cesium.CameraEventType.LEFT_DRAG,modifier:Cesium.KeyboardEventModifier.ALT});c.enableLook=!1;this.O.camera.constrainedAxis=Cesium.Cartesian3.UNIT_Z;this.Wb=new wg(this.O,this.H); +this.v=new Cesium.Globe(Cesium.Ellipsoid.WGS84);this.O.globe=this.v;this.O.skyAtmosphere=new Cesium.SkyAtmosphere;this.D=new Cesium.DataSourceCollection;this.Mg=new Cesium.DataSourceDisplay({scene:this.O,dataSourceCollection:this.D});b=ca(b.createSynchronizers)?b.createSynchronizers(this.H,this.O):[new Rg(this.H,this.O),new wh(this.H,this.O)];this.Oc();for(c=b.length-1;0<=c;--c)b[c].ze();this.g&&(b=mf(this.a),null!=b&&(b.style.display="none"));this.Yb=new Ge(function(){if(!this.Ne){var b=Cesium.JulianDate.now(); +this.O.initializeFrame();this.Oc();this.Mg.update(b);this.O.render(b);this.bb&&Ag(this.Wb)}this.Yb.start()},void 0,this);this.Ne=!1}k=xh.prototype;k.Oc=function(){var b=this.a.clientWidth,c=this.a.clientHeight;if(b!==this.u||c!==this.l||this.s){var d=(window.devicePixelRatio||1)*this.j;this.s=!1;this.u=b;this.l=c;b*=d;c*=d;this.a.width=b;this.a.height=c;this.O.camera.frustum.aspectRatio=b/c}};k.$g=function(){return this.Wb};k.Dh=function(){return this.H};k.ah=function(){return this.O};k.fh=function(){return this.D}; +k.hh=function(){return this.bb};k.bl=function(b){if(this.bb!=b)if(this.bb=b,this.c.style.visibility=this.bb?"visible":"hidden",this.bb){if(this.g){var c=this.H.c;c.forEach(function(b){this.i.push(b)},this);c.clear();b=this.H.Oa();b.Ha()&&(this.b=b,this.b.ub(!1))}this.Wb.uc();this.Yb.start()}else this.g&&(c=this.H.c,this.i.forEach(function(b){c.push(b)}),this.i.length=0,null!==this.b&&(this.b.ub(!0),this.b=null)),this.Wb.zb(),He(this.Yb)}; +k.Bl=function(b,c){if(!this.bb){this.Wb.uc();var d=this.v.ellipsoid,e=this.O.camera,f=d.cartesianToCartographic(e.position);f.height<b&&(f.height=b,e.position=d.cartographicToCartesian(f));this.Yb.start();var g=this;setTimeout(function(){!g.bb&&He(g.Yb)},c)}};k.re=function(b){this.Ne=b};k.Og=function(){this.f||(this.f=new ye(this,!1))};k.Yg=function(){return this.f};k.nl=function(b){b=Math.max(0,b);b!==this.j&&(this.j=Math.max(0,b),this.s=!0,this.f&&this.f.l())};function yh(b,c){Rg.call(this,b,c)}y(yh,Rg);yh.prototype.Re=function(b){var c=null;if(b instanceof D&&b.da()instanceof K)return null;b=b.getCesiumImageryProvider;return b?(c=b())?(Array.isArray(c)?c:[c]).map(function(b){return new Cesium.ImageryLayer(b)}):null:null};function zh(b){return function(c){if(c)return[Jd(c[0],b[0],b[2]),Jd(c[1],b[1],b[3])]}}function Ah(b){return b};function Bh(b){return function(c,d,e){if(void 0!==c)return c=Ef(b,c,e),c=Jd(c+d,0,b.length-1),b[c]}}function Ch(b,c,d){return function(e,f,g){if(void 0!==e)return e=Math.max(Math.floor(Math.log(c/e)/Math.log(b)+(0<g?0:0>g?1:.5))+f,0),void 0!==d&&(e=Math.min(e,d)),c/Math.pow(b,e)}};function Dh(b){if(void 0!==b)return 0}function Eh(b,c){if(void 0!==b)return b+c}function Fh(b){var c=2*Math.PI/b;return function(b,e){if(void 0!==b)return b=Math.floor((b+e)/c+.5)*c}}function Gh(){var b=Md(5);return function(c,d){if(void 0!==c)return Math.abs(c+d)<=b?0:c+d}};function Hh(b,c,d){this.center=b;this.resolution=c;this.rotation=d};function Ih(b,c,d,e){for(var f=0,g=b[d-e],h=b[d-e+1];c<d;c+=e)var l=b[c],m=b[c+1],f=f+(h*l-g*m),g=l,h=m;return f/2}function Jh(b,c,d,e){var f=0,g,h;g=0;for(h=d.length;g<h;++g){var l=d[g],f=f+Ih(b,c,l,e);c=l}return f};function Kh(b,c,d,e,f,g,h){var l=b[c],m=b[c+1],n=b[d]-l,p=b[d+1]-m;if(0!==n||0!==p)if(g=((f-l)*n+(g-m)*p)/(n*n+p*p),1<g)c=d;else if(0<g){for(f=0;f<e;++f)h[f]=Uc(b[c+f],b[d+f],g);h.length=e;return}for(f=0;f<e;++f)h[f]=b[c+f];h.length=e}function Lh(b,c,d,e,f){var g=b[c],h=b[c+1];for(c+=e;c<d;c+=e){var l=b[c],m=b[c+1],g=Ld(g,h,l,m);g>f&&(f=g);g=l;h=m}return f}function Mh(b,c,d,e,f){var g,h;g=0;for(h=d.length;g<h;++g){var l=d[g];f=Lh(b,c,l,e,f);c=l}return f} +function Nh(b,c,d,e,f,g,h,l,m,n,p){if(c==d)return n;var q;if(0===f){q=Ld(h,l,b[c],b[c+1]);if(q<n){for(p=0;p<e;++p)m[p]=b[c+p];m.length=e;return q}return n}for(var r=p?p:[NaN,NaN],t=c+e;t<d;)if(Kh(b,t-e,t,e,h,l,r),q=Ld(h,l,r[0],r[1]),q<n){n=q;for(p=0;p<e;++p)m[p]=r[p];m.length=e;t+=e}else t+=e*Math.max((Math.sqrt(q)-Math.sqrt(n))/f|0,1);if(g&&(Kh(b,d-e,c,e,h,l,r),q=Ld(h,l,r[0],r[1]),q<n)){n=q;for(p=0;p<e;++p)m[p]=r[p];m.length=e}return n} +function Oh(b,c,d,e,f,g,h,l,m,n,p){p=p?p:[NaN,NaN];var q,r;q=0;for(r=d.length;q<r;++q){var t=d[q];n=Nh(b,c,t,e,f,g,h,l,m,n,p);c=t}return n};function Ph(b,c){var d=0,e,f;e=0;for(f=c.length;e<f;++e)b[d++]=c[e];return d}function Qh(b,c,d,e){var f,g;f=0;for(g=d.length;f<g;++f){var h=d[f],l;for(l=0;l<e;++l)b[c++]=h[l]}return c}function Rh(b,c,d,e,f){f=f?f:[];var g=0,h,l;h=0;for(l=d.length;h<l;++h)c=Qh(b,c,d[h],e),f[g++]=c;f.length=g;return f};function Sh(b,c,d,e,f){f=void 0!==f?f:[];for(var g=0;c<d;c+=e)f[g++]=b.slice(c,c+e);f.length=g;return f}function Th(b,c,d,e,f){f=void 0!==f?f:[];var g=0,h,l;h=0;for(l=d.length;h<l;++h){var m=d[h];f[g++]=Sh(b,c,m,e,f[g]);c=m}f.length=g;return f};function Uh(b,c,d,e,f,g,h){var l=(d-c)/e;if(3>l){for(;c<d;c+=e)g[h++]=b[c],g[h++]=b[c+1];return h}var m=Array(l);m[0]=1;m[l-1]=1;d=[c,d-e];for(var n=0,p;0<d.length;){var q=d.pop(),r=d.pop(),t=0,B=b[r],X=b[r+1],x=b[q],E=b[q+1];for(p=r+e;p<q;p+=e){var v;v=b[p];var Ca=b[p+1],Fa=B,ja=X,P=x-Fa,Aa=E-ja;if(0!==P||0!==Aa){var va=((v-Fa)*P+(Ca-ja)*Aa)/(P*P+Aa*Aa);1<va?(Fa=x,ja=E):0<va&&(Fa+=P*va,ja+=Aa*va)}v=Ld(v,Ca,Fa,ja);v>t&&(n=p,t=v)}t>f&&(m[(n-c)/e]=1,r+e<n&&d.push(r,n),n+e<q&&d.push(n,q))}for(p=0;p< +l;++p)m[p]&&(g[h++]=b[c+p*e],g[h++]=b[c+p*e+1]);return h} +function Vh(b,c,d,e,f,g,h,l){var m,n;m=0;for(n=d.length;m<n;++m){var p=d[m];a:{var q=b,r=p,t=e,B=f,X=g;if(c!=r){var x=B*Math.round(q[c]/B),E=B*Math.round(q[c+1]/B);c+=t;X[h++]=x;X[h++]=E;var v=void 0,Ca=void 0;do if(v=B*Math.round(q[c]/B),Ca=B*Math.round(q[c+1]/B),c+=t,c==r){X[h++]=v;X[h++]=Ca;break a}while(v==x&&Ca==E);for(;c<r;){var Fa,ja;Fa=B*Math.round(q[c]/B);ja=B*Math.round(q[c+1]/B);c+=t;if(Fa!=v||ja!=Ca){var P=v-x,Aa=Ca-E,va=Fa-x,kb=ja-E;P*kb==Aa*va&&(0>P&&va<P||P==va||0<P&&va>P)&&(0>Aa&& +kb<Aa||Aa==kb||0<Aa&&kb>Aa)||(X[h++]=v,X[h++]=Ca,x=v,E=Ca);v=Fa;Ca=ja}}X[h++]=v;X[h++]=Ca}}l.push(h);c=p}return h};function Wh(b,c){Fg.call(this);this.c=this.j=-1;this.ia(b,c)}y(Wh,Fg);k=Wh.prototype;k.clone=function(){var b=new Wh(null);Hg(b,this.b,this.o.slice());b.A();return b};k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;this.c!=this.f&&(this.j=Math.sqrt(Lh(this.o,0,this.o.length,this.a,0)),this.c=this.f);return Nh(this.o,0,this.o.length,this.a,this.j,!0,b,c,d,e)};k.hj=function(){return Ih(this.o,0,this.o.length,this.a)};k.T=function(){return Sh(this.o,0,this.o.length,this.a)}; +k.Kb=function(b){var c=[];c.length=Uh(this.o,0,this.o.length,this.a,b,c,0);b=new Wh(null);Hg(b,"XY",c);b.A();return b};k.N=function(){return"LinearRing"};k.ia=function(b,c){b?(Ig(this,c,b,1),this.o||(this.o=[]),this.o.length=Qh(this.o,0,b,this.a)):Hg(this,"XY",null);this.A()};function L(b,c){Fg.call(this);this.ia(b,c)}y(L,Fg);k=L.prototype;k.clone=function(){var b=new L(null);Hg(b,this.b,this.o.slice());b.A();return b};k.Ia=function(b,c,d,e){var f=this.o;b=Ld(b,c,f[0],f[1]);if(b<e){e=this.a;for(c=0;c<e;++c)d[c]=f[c];d.length=e;return b}return e};k.T=function(){return this.o?this.o.slice():[]};k.Dc=function(b){return sd(this.o,b)};k.N=function(){return"Point"};k.ta=function(b){return pd(b,this.o[0],this.o[1])}; +k.ia=function(b,c){b?(Ig(this,c,b,0),this.o||(this.o=[]),this.o.length=Ph(this.o,b)):Hg(this,"XY",null);this.A()};function Xh(b,c,d,e,f){return!xd(f,function(f){return!Yh(b,c,d,e,f[0],f[1])})}function Yh(b,c,d,e,f,g){for(var h=!1,l=b[d-e],m=b[d-e+1];c<d;c+=e){var n=b[c],p=b[c+1];m>g!=p>g&&f<(n-l)*(g-m)/(p-m)+l&&(h=!h);l=n;m=p}return h}function Zh(b,c,d,e,f,g){if(0===d.length||!Yh(b,c,d[0],e,f,g))return!1;var h;c=1;for(h=d.length;c<h;++c)if(Yh(b,d[c-1],d[c],e,f,g))return!1;return!0};function $h(b,c,d,e,f,g,h){var l,m,n,p,q,r=f[g+1],t=[],B=d[0];n=b[B-e];q=b[B-e+1];for(l=c;l<B;l+=e){p=b[l];m=b[l+1];if(r<=q&&m<=r||q<=r&&r<=m)n=(r-q)/(m-q)*(p-n)+n,t.push(n);n=p;q=m}B=NaN;q=-Infinity;t.sort();n=t[0];l=1;for(m=t.length;l<m;++l){p=t[l];var X=Math.abs(p-n);X>q&&(n=(n+p)/2,Zh(b,c,d,e,n,r)&&(B=n,q=X));n=p}isNaN(B)&&(B=f[g]);return h?(h.push(B,r),h):[B,r]};function ai(b,c,d,e,f,g){for(var h=[b[c],b[c+1]],l=[],m;c+e<d;c+=e){l[0]=b[c+e];l[1]=b[c+e+1];if(m=f.call(g,h,l))return m;h[0]=l[0];h[1]=l[1]}return!1};function bi(b,c,d,e,f){var g=ud(hd(),b,c,d,e);return Hd(f,g)?qd(f,g)||g[0]>=f[0]&&g[2]<=f[2]||g[1]>=f[1]&&g[3]<=f[3]?!0:ai(b,c,d,e,function(b,c){var d=!1,e=rd(f,b),g=rd(f,c);if(1===e||1===g)d=!0;else{var q=f[0],r=f[1],t=f[2],B=f[3],X=c[0],x=c[1],E=(x-b[1])/(X-b[0]);g&2&&!(e&2)&&(d=X-(x-B)/E,d=d>=q&&d<=t);d||!(g&4)||e&4||(d=x-(X-t)*E,d=d>=r&&d<=B);d||!(g&8)||e&8||(d=X-(x-r)/E,d=d>=q&&d<=t);d||!(g&16)||e&16||(d=x-(X-q)*E,d=d>=r&&d<=B)}return d}):!1} +function ci(b,c,d,e,f){var g=d[0];if(!(bi(b,c,g,e,f)||Yh(b,c,g,e,f[0],f[1])||Yh(b,c,g,e,f[0],f[3])||Yh(b,c,g,e,f[2],f[1])||Yh(b,c,g,e,f[2],f[3])))return!1;if(1===d.length)return!0;c=1;for(g=d.length;c<g;++c)if(Xh(b,d[c-1],d[c],e,f))return!1;return!0};function di(b,c,d,e){for(var f=0,g=b[d-e],h=b[d-e+1];c<d;c+=e)var l=b[c],m=b[c+1],f=f+(l-g)*(m+h),g=l,h=m;return 0<f}function ei(b,c,d,e){var f=0;e=void 0!==e?e:!1;var g,h;g=0;for(h=c.length;g<h;++g){var l=c[g],f=di(b,f,l,d);if(0===g){if(e&&f||!e&&!f)return!1}else if(e&&!f||!e&&f)return!1;f=l}return!0} +function fi(b,c,d,e,f){f=void 0!==f?f:!1;var g,h;g=0;for(h=d.length;g<h;++g){var l=d[g],m=di(b,c,l,e);if(0===g?f&&m||!f&&!m:f&&!m||!f&&m)for(var m=b,n=l,p=e;c<n-p;){var q;for(q=0;q<p;++q){var r=m[c+q];m[c+q]=m[n-p+q];m[n-p+q]=r}c+=p;n-=p}c=l}return c}function gi(b,c,d,e){var f=0,g,h;g=0;for(h=c.length;g<h;++g)f=fi(b,f,c[g],d,e);return f};function M(b,c){Fg.call(this);this.c=[];this.v=-1;this.F=null;this.L=this.J=this.I=-1;this.j=null;this.ia(b,c)}y(M,Fg);k=M.prototype;k.Fg=function(b){this.o?mb(this.o,b.ga()):this.o=b.ga().slice();this.c.push(this.o.length);this.A()};k.clone=function(){var b=new M(null);hi(b,this.b,this.o.slice(),this.c.slice());return b}; +k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;this.J!=this.f&&(this.I=Math.sqrt(Mh(this.o,0,this.c,this.a,0)),this.J=this.f);return Oh(this.o,0,this.c,this.a,this.I,!0,b,c,d,e)};k.sb=function(b,c){return Zh(this.hb(),0,this.c,this.a,b,c)};k.lj=function(){return Jh(this.hb(),0,this.c,this.a)};k.T=function(b){var c;void 0!==b?(c=this.hb().slice(),fi(c,0,this.c,this.a,b)):c=this.o;return Th(c,0,this.c,this.a)};k.Ua=function(){return this.c}; +function ii(b){if(b.v!=b.f){var c=Ed(b.G());b.F=$h(b.hb(),0,b.c,b.a,c,0);b.v=b.f}return b.F}k.th=function(){return new L(ii(this))};k.yh=function(){return this.c.length};k.cf=function(b){if(0>b||this.c.length<=b)return null;var c=new Wh(null);Hg(c,this.b,this.o.slice(0===b?0:this.c[b-1],this.c[b]));c.A();return c};k.Kd=function(){var b=this.b,c=this.o,d=this.c,e=[],f=0,g,h;g=0;for(h=d.length;g<h;++g){var l=d[g],m=new Wh(null),n=m;Hg(n,b,c.slice(f,l));n.A();e.push(m);f=l}return e}; +k.hb=function(){if(this.L!=this.f){var b=this.o;ei(b,this.c,this.a)?this.j=b:(this.j=b.slice(),this.j.length=fi(this.j,0,this.c,this.a));this.L=this.f}return this.j};k.Kb=function(b){var c=[],d=[];c.length=Vh(this.o,0,this.c,this.a,Math.sqrt(b),c,0,d);b=new M(null);hi(b,"XY",c,d);return b};k.N=function(){return"Polygon"};k.ta=function(b){return ci(this.hb(),0,this.c,this.a,b)}; +k.ia=function(b,c){if(b){Ig(this,c,b,2);this.o||(this.o=[]);var d=Rh(this.o,0,b,this.a,this.c);this.o.length=0===d.length?0:d[d.length-1];this.A()}else hi(this,"XY",null,this.c)};function hi(b,c,d,e){Hg(b,c,d);b.c=e;b.A()};function N(b){Ic.call(this);b=b||{};this.b=[0,0];var c={};c.center=void 0!==b.center?b.center:null;this.a=he(b.projection);var d,e,f,g=void 0!==b.minZoom?b.minZoom:0;d=void 0!==b.maxZoom?b.maxZoom:28;var h=void 0!==b.zoomFactor?b.zoomFactor:2;if(void 0!==b.resolutions)d=b.resolutions,e=d[0],f=d[d.length-1],d=Bh(d);else{e=he(b.projection);f=e.G();var l=(f?Math.max(Bd(f),Dd(f)):360*Wd.degrees/Wd[e.b])/256/Math.pow(2,0),m=l/Math.pow(2,28);e=b.maxResolution;void 0!==e?g=0:e=l/Math.pow(h,g);f=b.minResolution; +void 0===f&&(f=void 0!==b.maxZoom?void 0!==b.maxResolution?e/Math.pow(h,d):l/Math.pow(h,d):m);d=g+Math.floor(Math.log(e/f)/Math.log(h));f=e/Math.pow(h,d-g);d=Ch(h,e,d-g)}this.c=e;this.j=f;this.g=g;g=void 0!==b.extent?zh(b.extent):Ah;(void 0!==b.enableRotation?b.enableRotation:1)?(e=b.constrainRotation,e=void 0===e||!0===e?Gh():!1===e?Eh:ia(e)?Fh(e):Eh):e=Dh;this.i=new Hh(g,d,e);void 0!==b.resolution?c.resolution=b.resolution:void 0!==b.zoom&&(c.resolution=this.constrainResolution(this.c,b.zoom-this.g)); +c.rotation=void 0!==b.rotation?b.rotation:0;this.M(c)}y(N,Ic);k=N.prototype;k.Ec=function(b){return this.i.center(b)};k.constrainResolution=function(b,c,d){return this.i.resolution(b,c||0,d||0)};k.constrainRotation=function(b,c){return this.i.rotation(b,c||0)};k.wa=function(){return this.get("center")};k.Jg=function(b){var c=this.wa(),d=this.V(),e=this.xa();return Fd(c,d,e,b)};k.bj=function(){return this.a};k.V=function(){return this.get("resolution")}; +k.Md=function(b,c){return Math.max(Bd(b)/c[0],Dd(b)/c[1])};k.xa=function(){return this.get("rotation")};function ji(b){var c=b.wa(),d=b.a,e=b.V();b=b.xa();return{center:[Math.round(c[0]/e)*e,Math.round(c[1]/e)*e],projection:void 0!==d?d:null,resolution:e,rotation:b}}k.Th=function(){var b,c=this.V();if(void 0!==c){var d,e=0;do{d=this.constrainResolution(this.c,e);if(d==c){b=e;break}++e}while(d>this.j)}return void 0!==b?this.g+b:b}; +k.We=function(b,c,d){if(!(b instanceof Fg)){var e=b[0],f=b[1],g=b[2],h=b[3],e=[e,f,e,h,g,h,g,f,e,f],f=new M(null);hi(f,"XY",e,[e.length]);b=f}e=d||{};d=void 0!==e.padding?e.padding:[0,0,0,0];var h=void 0!==e.constrainResolution?e.constrainResolution:!0,f=void 0!==e.nearest?e.nearest:!1,l;void 0!==e.minResolution?l=e.minResolution:void 0!==e.maxZoom?l=this.constrainResolution(this.c,e.maxZoom-this.g,0):l=0;var m=b.ga(),g=this.xa(),e=Math.cos(-g),g=Math.sin(-g),n=Infinity,p=Infinity,q=-Infinity,r=-Infinity; +b=b.pa();for(var t=0,B=m.length;t<B;t+=b)var X=m[t]*e-m[t+1]*g,x=m[t]*g+m[t+1]*e,n=Math.min(n,X),p=Math.min(p,x),q=Math.max(q,X),r=Math.max(r,x);c=this.Md([n,p,q,r],[c[0]-d[1]-d[3],c[1]-d[0]-d[2]]);c=isNaN(c)?l:Math.max(c,l);h&&(l=this.constrainResolution(c,0,0),!f&&l<c&&(l=this.constrainResolution(l,-1,0)),c=l);this.xb(c);g=-g;l=(n+q)/2+(d[1]-d[3])/2*c;c=(p+r)/2+(d[0]-d[2])/2*c;this.Ca([l*e-c*g,c*e+l*g])}; +k.Lg=function(b,c,d){var e=this.xa(),f=Math.cos(-e),e=Math.sin(-e),g=b[0]*f-b[1]*e;b=b[1]*f+b[0]*e;var h=this.V(),g=g+(c[0]/2-d[0])*h;b+=(d[1]-c[1]/2)*h;e=-e;this.Ca([g*f-b*e,b*f+g*e])};k.rotate=function(b,c){if(void 0!==c){var d,e=this.wa();void 0!==e&&(d=[e[0]-c[0],e[1]-c[1]],$c(d,b-this.xa()),Vc(d,c));this.Ca(d)}this.Nb(b)};k.Ca=function(b){this.C("center",b)};function ki(b,c){b.b[1]+=c}k.xb=function(b){this.C("resolution",b)};k.Nb=function(b){this.C("rotation",b)}; +k.tl=function(b){b=this.constrainResolution(this.c,b-this.g,0);this.xb(b)};N.prototype.getResolutionForExtent=N.prototype.Md;function li(b){return 1-Math.pow(1-b,3)}function mi(b){return 3*b*b-2*b*b*b}function hg(b){return b}function ni(b){return.5>b?mi(2*b):1-mi(2*(b-.5))};function oi(b){var c=b.source,d=b.start?b.start:Date.now(),e=c[0],f=c[1],g=void 0!==b.duration?b.duration:1E3,h=b.easing?b.easing:mi;return function(b,c){if(c.time<d)return c.animate=!0,c.viewHints[0]+=1,!0;if(c.time<d+g){var n=1-h((c.time-d)/g),p=e-c.viewState.center[0],q=f-c.viewState.center[1];c.animate=!0;c.viewState.center[0]+=n*p;c.viewState.center[1]+=n*q;c.viewHints[0]+=1;return!0}return!1}} +function pi(b){var c=b.rotation?b.rotation:0,d=b.start?b.start:Date.now(),e=void 0!==b.duration?b.duration:1E3,f=b.easing?b.easing:mi,g=b.anchor?b.anchor:null;return function(b,l){if(l.time<d)return l.animate=!0,l.viewHints[0]+=1,!0;if(l.time<d+e){var m=1-f((l.time-d)/e),m=(c-l.viewState.rotation)*m;l.animate=!0;l.viewState.rotation+=m;if(g){var n=l.viewState.center;n[0]-=g[0];n[1]-=g[1];$c(n,m);Vc(n,g)}l.viewHints[0]+=1;return!0}return!1}} +function qi(b){var c=b.resolution,d=b.start?b.start:Date.now(),e=void 0!==b.duration?b.duration:1E3,f=b.easing?b.easing:mi;return function(b,h){if(h.time<d)return h.animate=!0,h.viewHints[0]+=1,!0;if(h.time<d+e){var l=1-f((h.time-d)/e),m=c-h.viewState.resolution;h.animate=!0;h.viewState.resolution+=l*m;h.viewHints[0]+=1;return!0}return!1}};function ri(b){if(b.classList)return b.classList;b=b.className;return ha(b)&&b.match(/\S+/g)||[]}function si(b,c){var d;b.classList?d=b.classList.contains(c):(d=ri(b),d=0<=bb(d,c));return d}function ti(b,c){b.classList?b.classList.add(c):si(b,c)||(b.className+=0<b.className.length?" "+c:c)}function ui(b,c){b.classList?b.classList.remove(c):si(b,c)&&(b.className=eb(ri(b),function(b){return b!=c}).join(" "))};function vi(b,c,d,e){this.top=b;this.right=c;this.bottom=d;this.left=e}k=vi.prototype;k.clone=function(){return new vi(this.top,this.right,this.bottom,this.left)};k.contains=function(b){return this&&b?b instanceof vi?b.left>=this.left&&b.right<=this.right&&b.top>=this.top&&b.bottom<=this.bottom:b.x>=this.left&&b.x<=this.right&&b.y>=this.top&&b.y<=this.bottom:!1}; +k.ceil=function(){this.top=Math.ceil(this.top);this.right=Math.ceil(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.ceil(this.left);return this};k.floor=function(){this.top=Math.floor(this.top);this.right=Math.floor(this.right);this.bottom=Math.floor(this.bottom);this.left=Math.floor(this.left);return this};k.round=function(){this.top=Math.round(this.top);this.right=Math.round(this.right);this.bottom=Math.round(this.bottom);this.left=Math.round(this.left);return this}; +k.scale=function(b,c){var d=ia(c)?c:b;this.left*=b;this.right*=b;this.top*=d;this.bottom*=d;return this};function wi(b,c){var d=$e(b);return d.defaultView&&d.defaultView.getComputedStyle&&(d=d.defaultView.getComputedStyle(b,null))?d[c]||d.getPropertyValue(c)||"":""}function xi(b,c){return wi(b,c)||(b.currentStyle?b.currentStyle[c]:null)||b.style&&b.style[c]} +function yi(b){var c;try{c=b.getBoundingClientRect()}catch(d){return{left:0,top:0,right:0,bottom:0}}Ab&&b.ownerDocument.body&&(b=b.ownerDocument,c.left-=b.documentElement.clientLeft+b.body.clientLeft,c.top-=b.documentElement.clientTop+b.body.clientTop);return c}function zi(b){if(1==b.nodeType)return b=yi(b),new We(b.left,b.top);b=b.changedTouches?b.changedTouches[0]:b;return new We(b.clientX,b.clientY)} +function Ai(b){var c=Bi;if("none"!=xi(b,"display"))return c(b);var d=b.style,e=d.display,f=d.visibility,g=d.position;d.visibility="hidden";d.position="absolute";d.display="inline";b=c(b);d.display=e;d.position=g;d.visibility=f;return b}function Bi(b){var c=b.offsetWidth,d=b.offsetHeight,e=Db&&!c&&!d;return ca(c)&&!e||!b.getBoundingClientRect?new Xe(c,d):(b=yi(b),new Xe(b.right-b.left,b.bottom-b.top))}function Ci(b,c){b.style.display=c?"":"none"} +function Di(b,c,d,e){if(/^\d+px?$/.test(c))return parseInt(c,10);var f=b.style[d],g=b.runtimeStyle[d];b.runtimeStyle[d]=b.currentStyle[d];b.style[d]=c;c=b.style[e];b.style[d]=f;b.runtimeStyle[d]=g;return c}function Ei(b,c){var d=b.currentStyle?b.currentStyle[c]:null;return d?Di(b,d,"left","pixelLeft"):0}var Fi={thin:2,medium:4,thick:6}; +function Gi(b,c){if("none"==(b.currentStyle?b.currentStyle[c+"Style"]:null))return 0;var d=b.currentStyle?b.currentStyle[c+"Width"]:null;return d in Fi?Fi[d]:Di(b,d,"left","pixelLeft")};function Hi(b,c,d){Xb.call(this,b);this.map=c;this.frameState=void 0!==d?d:null}y(Hi,Xb);function Ii(b){Ic.call(this);this.element=b.element?b.element:null;this.H=this.I=null;this.g=[];this.render=b.render?b.render:Id;b.target&&this.u(b.target)}y(Ii,Ic);Ii.prototype.ba=function(){lf(this.element);Ii.ka.ba.call(this)};Ii.prototype.J=function(){return this.H}; +Ii.prototype.setMap=function(b){this.H&&lf(this.element);0<this.g.length&&(this.g.forEach(yc),this.g.length=0);if(this.H=b)(this.I?this.I:b.F).appendChild(this.element),this.render!==Id&&this.g.push(z(b,"postrender",this.render,!1,this)),b.render()};Ii.prototype.u=function(b){this.I=af(b)};function Ji(b){b=b?b:{};this.D=document.createElement("UL");this.j=document.createElement("LI");this.D.appendChild(this.j);Ci(this.j,!1);this.c=void 0!==b.collapsed?b.collapsed:!0;this.i=void 0!==b.collapsible?b.collapsible:!0;this.i||(this.c=!1);var c=b.className?b.className:"ol-attribution",d=b.tipLabel?b.tipLabel:"Attributions",e=b.collapseLabel?b.collapseLabel:"\u00bb";this.v=ha(e)?gf("SPAN",{},e):e;e=b.label?b.label:"i";this.F=ha(e)?gf("SPAN",{},e):e;d=gf("BUTTON",{type:"button",title:d},this.i&& +!this.c?this.v:this.F);z(d,"click",this.U,!1,this);z(d,["mouseout",$b],function(){this.blur()},!1);c=gf("DIV",c+" ol-unselectable ol-control"+(this.c&&this.i?" ol-collapsed":"")+(this.i?"":" ol-uncollapsible"),this.D,d);Ii.call(this,{element:c,render:b.render?b.render:Ki,target:b.target});this.l=!0;this.b={};this.a={};this.L={}}y(Ji,Ii); +function Ki(b){if(b=b.frameState){var c,d,e,f,g,h,l,m,n,p,q=b.layerStatesArray,r=Ia(b.attributions),t={},B=b.viewState.projection;d=0;for(c=q.length;d<c;d++)if(h=q[d].layer.da())if(p=u(h).toString(),n=h.j)for(e=0,f=n.length;e<f;e++)if(l=n[e],m=u(l).toString(),!(m in r)){if(g=b.usedTiles[p]){var X=h.Wa(B);g=l.f(g,X,B)}else g=!1;g?(m in t&&delete t[m],r[m]=l):t[m]=l}c=[r,t];d=c[0];c=c[1];for(var x in this.b)x in d?(this.a[x]||(Ci(this.b[x],!0),this.a[x]=!0),delete d[x]):x in c?(this.a[x]&&(Ci(this.b[x], +!1),delete this.a[x]),delete c[x]):(lf(this.b[x]),delete this.b[x],delete this.a[x]);for(x in d)e=document.createElement("LI"),e.innerHTML=d[x].a(),this.D.appendChild(e),this.b[x]=e,this.a[x]=!0;for(x in c)e=document.createElement("LI"),e.innerHTML=c[x].a(),Ci(e,!1),this.D.appendChild(e),this.b[x]=e;x=!Da(this.a)||!Da(b.logos);this.l!=x&&(Ci(this.element,x),this.l=x);x&&Da(this.a)?ti(this.element,"ol-logo-only"):ui(this.element,"ol-logo-only");var E;b=b.logos;x=this.L;for(E in x)E in b||(lf(x[E]), +delete x[E]);for(var v in b)v in x||(E=new Image,E.src=v,d=b[v],""===d?d=E:(d=gf("A",{href:d}),d.appendChild(E)),this.j.appendChild(d),x[v]=d);Ci(this.j,!Da(b))}else this.l&&(Ci(this.element,!1),this.l=!1)}Ji.prototype.U=function(b){b.preventDefault();b=this.element;si(b,"ol-collapsed")?ui(b,"ol-collapsed"):ti(b,"ol-collapsed");if(this.c){b=this.F;var c=b.parentNode;c&&c.replaceChild(this.v,b)}else b=this.v,(c=b.parentNode)&&c.replaceChild(this.F,b);this.c=!this.c};function Li(b){b=b?b:{};var c=b.className?b.className:"ol-rotate",d=b.label?b.label:"\u21e7";this.a=null;ha(d)?this.a=gf("SPAN","ol-compass",d):(this.a=d,ti(this.a,"ol-compass"));d=gf("BUTTON",{"class":c+"-reset",type:"button",title:b.tipLabel?b.tipLabel:"Reset rotation"},this.a);z(d,"click",Li.prototype.l,!1,this);c=gf("DIV",c+" ol-unselectable ol-control",d);d=b.render?b.render:Mi;this.c=b.resetNorth?b.resetNorth:void 0;Ii.call(this,{element:c,render:d,target:b.target});this.i=void 0!==b.duration? +b.duration:250;this.b=void 0!==b.autoHide?b.autoHide:!0;this.j=void 0;this.b&&ti(this.element,"ol-hidden")}y(Li,Ii);Li.prototype.l=function(b){b.preventDefault();if(void 0!==this.c)this.c();else{b=this.H;var c=b.ja();if(c){var d=c.xa();void 0!==d&&(0<this.i&&(d%=2*Math.PI,d<-Math.PI&&(d+=2*Math.PI),d>Math.PI&&(d-=2*Math.PI),b.Fa(pi({rotation:d,duration:this.i,easing:li}))),c.Nb(0))}}}; +function Mi(b){if(b=b.frameState){b=b.viewState.rotation;if(b!=this.j){var c="rotate("+b+"rad)";if(this.b){var d=this.element;0===b?ti(d,"ol-hidden"):ui(d,"ol-hidden")}this.a.style.msTransform=c;this.a.style.webkitTransform=c;this.a.style.transform=c}this.j=b}};function Ni(b){b=b?b:{};var c=b.className?b.className:"ol-zoom",d=b.delta?b.delta:1,e=b.zoomOutLabel?b.zoomOutLabel:"\u2212",f=b.zoomOutTipLabel?b.zoomOutTipLabel:"Zoom out",g=gf("BUTTON",{"class":c+"-in",type:"button",title:b.zoomInTipLabel?b.zoomInTipLabel:"Zoom in"},b.zoomInLabel?b.zoomInLabel:"+");z(g,"click",sa(Ni.prototype.b,d),!1,this);e=gf("BUTTON",{"class":c+"-out",type:"button",title:f},e);z(e,"click",sa(Ni.prototype.b,-d),!1,this);c=gf("DIV",c+" ol-unselectable ol-control",g,e);Ii.call(this, +{element:c,target:b.target});this.a=void 0!==b.duration?b.duration:250}y(Ni,Ii);Ni.prototype.b=function(b,c){c.preventDefault();var d=this.H,e=d.ja();if(e){var f=e.V();f&&(0<this.a&&d.Fa(qi({resolution:f,duration:this.a,easing:li})),d=e.constrainResolution(f,b),e.xb(d))}};function Oi(b){b=b?b:{};var c=new A;(void 0!==b.zoom?b.zoom:1)&&c.push(new Ni(b.zoomOptions));(void 0!==b.rotate?b.rotate:1)&&c.push(new Li(b.rotateOptions));(void 0!==b.attribution?b.attribution:1)&&c.push(new Ji(b.attributionOptions));return c};function Pi(b){b=b?b:{};var c=gf("DIV",b.className?b.className:"ol-mouse-position");Ii.call(this,{element:c,render:b.render?b.render:Qi,target:b.target});z(this,Kc("projection"),this.dj,!1,this);b.coordinateFormat&&this.Zf(b.coordinateFormat);b.projection&&this.Af(Zd(b.projection));this.j=b.undefinedHTML?b.undefinedHTML:"";this.i=c.innerHTML;this.c=this.b=this.a=null}y(Pi,Ii); +function Qi(b){b=b.frameState;b?this.a!=b.viewState.projection&&(this.a=b.viewState.projection,this.b=null):this.a=null;Ri(this,this.c)}k=Pi.prototype;k.dj=function(){this.b=null};k.Xe=function(){return this.get("coordinateFormat")};k.zf=function(){return this.get("projection")};k.cj=function(b){this.c=this.H.Gc(b.a);Ri(this,this.c)};k.di=function(){Ri(this,null);this.c=null}; +k.setMap=function(b){Pi.ka.setMap.call(this,b);b&&(b=b.a,this.g.push(z(b,"mousemove",this.cj,!1,this),z(b,"mouseout",this.di,!1,this)))};k.Zf=function(b){this.C("coordinateFormat",b)};k.Af=function(b){this.C("projection",b)};function Ri(b,c){var d=b.j;if(c&&b.a){if(!b.b){var e=b.zf();b.b=e?ce(b.a,e):ke}if(e=b.H.ua(c))b.b(e,e),d=(d=b.Xe())?d(e):e.toString()}b.i&&d==b.i||(b.element.innerHTML=d,b.i=d)};var Si; +function Ti(){var b=ba.MessageChannel;"undefined"===typeof b&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!xb("Presto")&&(b=function(){var b=document.createElement("IFRAME");b.style.display="none";b.src="";document.documentElement.appendChild(b);var c=b.contentWindow,b=c.document;b.open();b.write("");b.close();var d="callImmediate"+Math.random(),e="file:"==c.location.protocol?"*":c.location.protocol+"//"+c.location.host,b=ra(function(b){if(("*"==e||b.origin==e)&&b.data== +d)this.port1.onmessage()},this);c.addEventListener("message",b,!1);this.port1={};this.port2={postMessage:function(){c.postMessage(d,e)}}});if("undefined"!==typeof b&&!xb("Trident")&&!xb("MSIE")){var c=new b,d={},e=d;c.port1.onmessage=function(){if(ca(d.next)){d=d.next;var b=d.Pe;d.Pe=null;b()}};return function(b){e.next={Pe:b};e=e.next;c.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?function(b){var c=document.createElement("SCRIPT"); +c.onreadystatechange=function(){c.onreadystatechange=null;c.parentNode.removeChild(c);c=null;b();b=null};document.documentElement.appendChild(c)}:function(b){ba.setTimeout(b,0)}};function Ui(b,c){this.H={};this.a=[];this.b=this.f=0;var d=arguments.length;if(1<d){if(d%2)throw Error("Uneven number of arguments");for(var e=0;e<d;e+=2)Vi(this,arguments[e],arguments[e+1])}else if(b){b instanceof Ui?(d=b.P(),e=b.ob()):(d=Ba(b),e=ya(b));for(var f=0;f<d.length;f++)Vi(this,d[f],e[f])}}k=Ui.prototype;k.fc=function(){return this.f};k.ob=function(){Wi(this);for(var b=[],c=0;c<this.a.length;c++)b.push(this.H[this.a[c]]);return b};k.P=function(){Wi(this);return this.a.concat()}; +k.Pa=function(){return 0==this.f};k.clear=function(){this.H={};this.b=this.f=this.a.length=0};k.remove=function(b){return Xi(this.H,b)?(delete this.H[b],this.f--,this.b++,this.a.length>2*this.f&&Wi(this),!0):!1};function Wi(b){if(b.f!=b.a.length){for(var c=0,d=0;c<b.a.length;){var e=b.a[c];Xi(b.H,e)&&(b.a[d++]=e);c++}b.a.length=d}if(b.f!=b.a.length){for(var f={},d=c=0;c<b.a.length;)e=b.a[c],Xi(f,e)||(b.a[d++]=e,f[e]=1),c++;b.a.length=d}}k.get=function(b,c){return Xi(this.H,b)?this.H[b]:c}; +function Vi(b,c,d){Xi(b.H,c)||(b.f++,b.a.push(c),b.b++);b.H[c]=d}k.forEach=function(b,c){for(var d=this.P(),e=0;e<d.length;e++){var f=d[e],g=this.get(f);b.call(c,g,f,this)}};k.clone=function(){return new Ui(this)};function Xi(b,c){return Object.prototype.hasOwnProperty.call(b,c)};function Zi(){this.a=ta()}new Zi;Zi.prototype.reset=function(){this.a=ta()};Zi.prototype.get=function(){return this.a};function $i(b){Cc.call(this);this.a=b||window;this.f=z(this.a,"resize",this.Oc,!1,this);this.b=ff(this.a||window)}y($i,Cc);$i.prototype.ba=function(){$i.ka.ba.call(this);this.f&&(yc(this.f),this.f=null);this.b=this.a=null};$i.prototype.Oc=function(){var b=ff(this.a||window),c=this.b;b==c||b&&c&&b.width==c.width&&b.height==c.height||(this.b=b,this.B("resize"))};function aj(b,c,d,e,f){if(!(Ab||Bb||Db&&Mb("525")))return!0;if(Eb&&f)return bj(b);if(f&&!e)return!1;ia(c)&&(c=cj(c));if(!d&&(17==c||18==c||Eb&&91==c))return!1;if((Db||Bb)&&e&&d)switch(b){case 220:case 219:case 221:case 192:case 186:case 189:case 187:case 188:case 190:case 191:case 192:case 222:return!1}if(Ab&&e&&c==b)return!1;switch(b){case 13:return!0;case 27:return!(Db||Bb)}return bj(b)} +function bj(b){if(48<=b&&57>=b||96<=b&&106>=b||65<=b&&90>=b||(Db||Bb)&&0==b)return!0;switch(b){case 32:case 43:case 63:case 64:case 107:case 109:case 110:case 111:case 186:case 59:case 189:case 187:case 61:case 188:case 190:case 191:case 192:case 222:case 219:case 220:case 221:return!0;default:return!1}}function cj(b){if(Cb)b=dj(b);else if(Eb&&Db)a:switch(b){case 93:b=91;break a}return b} +function dj(b){switch(b){case 61:return 187;case 59:return 186;case 173:return 189;case 224:return 91;case 0:return 224;default:return b}};function ej(b,c){Cc.call(this);b&&fj(this,b,c)}y(ej,Cc);k=ej.prototype;k.jc=null;k.Rc=null;k.Ud=null;k.Sc=null;k.Ba=-1;k.gb=-1;k.sd=!1; +var gj={3:13,12:144,63232:38,63233:40,63234:37,63235:39,63236:112,63237:113,63238:114,63239:115,63240:116,63241:117,63242:118,63243:119,63244:120,63245:121,63246:122,63247:123,63248:44,63272:46,63273:36,63275:35,63276:33,63277:34,63289:144,63302:45},hj={Up:38,Down:40,Left:37,Right:39,Enter:13,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,"U+007F":46,Home:36,End:35,PageUp:33,PageDown:34,Insert:45},ij=Ab||Bb||Db&&Mb("525"),jj=Eb&&Cb; +ej.prototype.a=function(b){if(Db||Bb)if(17==this.Ba&&!b.j||18==this.Ba&&!b.f||Eb&&91==this.Ba&&!b.D)this.gb=this.Ba=-1;-1==this.Ba&&(b.j&&17!=b.c?this.Ba=17:b.f&&18!=b.c?this.Ba=18:b.D&&91!=b.c&&(this.Ba=91));ij&&!aj(b.c,this.Ba,b.g,b.j,b.f)?this.handleEvent(b):(this.gb=cj(b.c),jj&&(this.sd=b.f))};ej.prototype.f=function(b){this.gb=this.Ba=-1;this.sd=b.f}; +ej.prototype.handleEvent=function(b){var c=b.a,d,e,f=c.altKey;Ab&&"keypress"==b.type?(d=this.gb,e=13!=d&&27!=d?c.keyCode:0):(Db||Bb)&&"keypress"==b.type?(d=this.gb,e=0<=c.charCode&&63232>c.charCode&&bj(d)?c.charCode:0):zb&&!Db?(d=this.gb,e=bj(d)?c.keyCode:0):(d=c.keyCode||this.gb,e=c.charCode||0,jj&&(f=this.sd),Eb&&63==e&&224==d&&(d=191));var g=d=cj(d),h=c.keyIdentifier;d?63232<=d&&d in gj?g=gj[d]:25==d&&b.g&&(g=9):h&&h in hj&&(g=hj[h]);b=g==this.Ba;this.Ba=g;c=new kj(g,e,b,c);c.f=f;this.B(c)}; +function fj(b,c,d){b.Sc&&lj(b);b.jc=c;b.Rc=z(b.jc,"keypress",b,d);b.Ud=z(b.jc,"keydown",b.a,d,b);b.Sc=z(b.jc,"keyup",b.f,d,b)}function lj(b){b.Rc&&(yc(b.Rc),yc(b.Ud),yc(b.Sc),b.Rc=null,b.Ud=null,b.Sc=null);b.jc=null;b.Ba=-1;b.gb=-1}ej.prototype.ba=function(){ej.ka.ba.call(this);lj(this)};function kj(b,c,d,e){bc.call(this,e);this.type="key";this.c=b;this.u=c;this.repeat=d}y(kj,bc);function mj(b,c){Cc.call(this);var d=this.a=b;(d=ma(d)&&1==d.nodeType?this.a:this.a?this.a.body:null)&&xi(d,"direction");this.f=z(this.a,Cb?"DOMMouseScroll":"mousewheel",this,c)}y(mj,Cc); +mj.prototype.handleEvent=function(b){var c=0,d=0;b=b.a;if("mousewheel"==b.type){c=1;if(Ab||Db&&(Fb||Mb("532.0")))c=40;d=nj(-b.wheelDelta,c);c=ca(b.wheelDeltaX)?nj(-b.wheelDeltaY,c):d}else d=b.detail,100<d?d=3:-100>d&&(d=-3),ca(b.axis)&&b.axis===b.HORIZONTAL_AXIS||(c=d);ia(this.b)&&(c=Math.min(Math.max(c,-this.b),this.b));d=new oj(d,b,0,c);this.B(d)};function nj(b,c){return Db&&(Eb||Gb)&&0!=b%c?b:b/c}mj.prototype.ba=function(){mj.ka.ba.call(this);yc(this.f);this.f=null}; +function oj(b,c,d,e){bc.call(this,c);this.type="mousewheel";this.detail=b;this.v=e}y(oj,bc);function pj(b,c,d){Xb.call(this,b);this.a=c;b=d?d:{};this.buttons=qj(b);this.pressure=rj(b,this.buttons);this.bubbles="bubbles"in b?b.bubbles:!1;this.cancelable="cancelable"in b?b.cancelable:!1;this.view="view"in b?b.view:null;this.detail="detail"in b?b.detail:null;this.screenX="screenX"in b?b.screenX:0;this.screenY="screenY"in b?b.screenY:0;this.clientX="clientX"in b?b.clientX:0;this.clientY="clientY"in b?b.clientY:0;this.button="button"in b?b.button:0;this.relatedTarget="relatedTarget"in b?b.relatedTarget: +null;this.pointerId="pointerId"in b?b.pointerId:0;this.width="width"in b?b.width:0;this.height="height"in b?b.height:0;this.pointerType="pointerType"in b?b.pointerType:"";this.isPrimary="isPrimary"in b?b.isPrimary:!1;c.preventDefault&&(this.preventDefault=function(){c.preventDefault()})}y(pj,Xb);function qj(b){if(b.buttons||sj)b=b.buttons;else switch(b.which){case 1:b=1;break;case 2:b=4;break;case 3:b=2;break;default:b=0}return b} +function rj(b,c){var d=0;b.pressure?d=b.pressure:d=c?.5:0;return d}var sj=!1;try{sj=1===(new MouseEvent("click",{buttons:1})).buttons}catch(b){};function tj(b,c){this.a=b;this.g=c};function uj(b){tj.call(this,b,{mousedown:this.xi,mousemove:this.yi,mouseup:this.Bi,mouseover:this.Ai,mouseout:this.zi});this.f=b.f;this.b=[]}y(uj,tj);function vj(b,c){for(var d=b.b,e=c.clientX,f=c.clientY,g=0,h=d.length,l;g<h&&(l=d[g]);g++){var m=Math.abs(f-l[1]);if(25>=Math.abs(e-l[0])&&25>=m)return!0}return!1}function wj(b){var c=xj(b,b.a),d=c.preventDefault;c.preventDefault=function(){b.preventDefault();d()};c.pointerId=1;c.isPrimary=!0;c.pointerType="mouse";return c}k=uj.prototype; +k.xi=function(b){if(!vj(this,b)){if((1).toString()in this.f){var c=wj(b);yj(this.a,zj,c,b);delete this.f[(1).toString()]}c=wj(b);this.f[(1).toString()]=b;yj(this.a,Aj,c,b)}};k.yi=function(b){if(!vj(this,b)){var c=wj(b);yj(this.a,Bj,c,b)}};k.Bi=function(b){if(!vj(this,b)){var c=this.f[(1).toString()];c&&c.button===b.button&&(c=wj(b),yj(this.a,Cj,c,b),delete this.f[(1).toString()])}};k.Ai=function(b){if(!vj(this,b)){var c=wj(b);Dj(this.a,c,b)}}; +k.zi=function(b){if(!vj(this,b)){var c=wj(b);Ej(this.a,c,b)}};function Fj(b){tj.call(this,b,{MSPointerDown:this.Gi,MSPointerMove:this.Hi,MSPointerUp:this.Ki,MSPointerOut:this.Ii,MSPointerOver:this.Ji,MSPointerCancel:this.Fi,MSGotPointerCapture:this.Di,MSLostPointerCapture:this.Ei});this.f=b.f;this.b=["","unavailable","touch","pen","mouse"]}y(Fj,tj);function Gj(b,c){var d=c;ia(c.a.pointerType)&&(d=xj(c,c.a),d.pointerType=b.b[c.a.pointerType]);return d}k=Fj.prototype;k.Gi=function(b){this.f[b.a.pointerId.toString()]=b;var c=Gj(this,b);yj(this.a,Aj,c,b)}; +k.Hi=function(b){var c=Gj(this,b);yj(this.a,Bj,c,b)};k.Ki=function(b){var c=Gj(this,b);yj(this.a,Cj,c,b);delete this.f[b.a.pointerId.toString()]};k.Ii=function(b){var c=Gj(this,b);Ej(this.a,c,b)};k.Ji=function(b){var c=Gj(this,b);Dj(this.a,c,b)};k.Fi=function(b){var c=Gj(this,b);yj(this.a,zj,c,b);delete this.f[b.a.pointerId.toString()]};k.Ei=function(b){this.a.B(new pj("lostpointercapture",b,b.a))};k.Di=function(b){this.a.B(new pj("gotpointercapture",b,b.a))};function Hj(b){tj.call(this,b,{pointerdown:this.Fk,pointermove:this.Gk,pointerup:this.Jk,pointerout:this.Hk,pointerover:this.Ik,pointercancel:this.Ek,gotpointercapture:this.Uh,lostpointercapture:this.vi})}y(Hj,tj);k=Hj.prototype;k.Fk=function(b){Ij(this.a,b)};k.Gk=function(b){Ij(this.a,b)};k.Jk=function(b){Ij(this.a,b)};k.Hk=function(b){Ij(this.a,b)};k.Ik=function(b){Ij(this.a,b)};k.Ek=function(b){Ij(this.a,b)};k.vi=function(b){Ij(this.a,b)};k.Uh=function(b){Ij(this.a,b)};function Jj(b,c){tj.call(this,b,{touchstart:this.yl,touchmove:this.xl,touchend:this.wl,touchcancel:this.vl});this.f=b.f;this.s=c;this.b=void 0;this.i=0;this.c=void 0}y(Jj,tj);k=Jj.prototype;k.Xf=function(){this.i=0;this.c=void 0}; +function Kj(b,c,d){c=xj(c,d);c.pointerId=d.identifier+2;c.bubbles=!0;c.cancelable=!0;c.detail=b.i;c.button=0;c.buttons=1;c.width=d.webkitRadiusX||d.radiusX||0;c.height=d.webkitRadiusY||d.radiusY||0;c.pressure=d.webkitForce||d.force||.5;c.isPrimary=b.b===d.identifier;c.pointerType="touch";c.clientX=d.clientX;c.clientY=d.clientY;c.screenX=d.screenX;c.screenY=d.screenY;return c} +function Lj(b,c,d){function e(){c.preventDefault()}var f=Array.prototype.slice.call(c.a.changedTouches),g=f.length,h,l;for(h=0;h<g;++h)l=Kj(b,c,f[h]),l.preventDefault=e,d.call(b,c,l)} +k.yl=function(b){var c=b.a.touches,d=Ba(this.f),e=d.length;if(e>=c.length){var f=[],g,h,l;for(g=0;g<e;++g){h=d[g];l=this.f[h];var m;if(!(m=1==h))a:{m=c.length;for(var n=void 0,p=0;p<m;p++)if(n=c[p],n.identifier===h-2){m=!0;break a}m=!1}m||f.push(l.vb)}for(g=0;g<f.length;++g)this.td(b,f[g])}c=xa(this.f);if(!(d=0===c)){if(c=1===c)c=(1).toString()in this.f;d=c}d&&(this.b=b.a.changedTouches[0].identifier,void 0!==this.c&&ba.clearTimeout(this.c));Mj(this,b);this.i++;Lj(this,b,this.Dk)}; +k.Dk=function(b,c){this.f[c.pointerId]={target:c.target,vb:c,Sf:c.target};var d=this.a;c.bubbles=!0;yj(d,Nj,c,b);d=this.a;c.bubbles=!1;yj(d,Oj,c,b);yj(this.a,Aj,c,b)};k.xl=function(b){b.preventDefault();Lj(this,b,this.Ci)};k.Ci=function(b,c){var d=this.f[c.pointerId];if(d){var e=d.vb,f=d.Sf;yj(this.a,Bj,c,b);e&&f!==c.target&&(e.relatedTarget=c.target,c.relatedTarget=f,e.target=f,c.target?(Ej(this.a,e,b),Dj(this.a,c,b)):(c.target=f,c.relatedTarget=null,this.td(b,c)));d.vb=c;d.Sf=c.target}}; +k.wl=function(b){Mj(this,b);Lj(this,b,this.zl)};k.zl=function(b,c){yj(this.a,Cj,c,b);this.a.vb(c,b);var d=this.a;c.bubbles=!1;yj(d,Pj,c,b);delete this.f[c.pointerId];c.isPrimary&&(this.b=void 0,this.c=ba.setTimeout(ra(this.Xf,this),200))};k.vl=function(b){Lj(this,b,this.td)};k.td=function(b,c){yj(this.a,zj,c,b);this.a.vb(c,b);var d=this.a;c.bubbles=!1;yj(d,Pj,c,b);delete this.f[c.pointerId];c.isPrimary&&(this.b=void 0,this.c=ba.setTimeout(ra(this.Xf,this),200))}; +function Mj(b,c){var d=b.s.b,e=c.a.changedTouches[0];if(b.b===e.identifier){var f=[e.clientX,e.clientY];d.push(f);ba.setTimeout(function(){hb(d,f)},2500)}};function Qj(b){Cc.call(this);this.g=b;this.f={};this.c={};this.a=[];eh?Rj(this,new Hj(this)):fh?Rj(this,new Fj(this)):(b=new uj(this),Rj(this,b),dh&&Rj(this,new Jj(this,b)));b=this.a.length;for(var c,d=0;d<b;d++)c=this.a[d],Sj(this,Object.keys(c.g))}y(Qj,Cc);function Rj(b,c){var d=Object.keys(c.g);d&&(d.forEach(function(b){var d=c.g[b];d&&(this.c[b]=ra(d,c))},b),b.a.push(c))}Qj.prototype.b=function(b){var c=this.c[b.type];c&&c(b)}; +function Sj(b,c){c.forEach(function(b){z(this.g,b,this.b,!1,this)},b)}function Tj(b,c){c.forEach(function(b){xc(this.g,b,this.b,!1,this)},b)}function xj(b,c){for(var d={},e,f=0,g=Uj.length;f<g;f++)e=Uj[f][0],d[e]=b[e]||c[e]||Uj[f][1];return d}Qj.prototype.vb=function(b,c){b.bubbles=!0;yj(this,Vj,b,c)};function Ej(b,c,d){b.vb(c,d);var e=c.relatedTarget;e&&nf(c.target,e)||(c.bubbles=!1,yj(b,Pj,c,d))} +function Dj(b,c,d){c.bubbles=!0;yj(b,Nj,c,d);var e=c.relatedTarget;e&&nf(c.target,e)||(c.bubbles=!1,yj(b,Oj,c,d))}function yj(b,c,d,e){b.B(new pj(c,e,d))}function Ij(b,c){b.B(new pj(c.type,c,c.a))}Qj.prototype.ba=function(){for(var b=this.a.length,c,d=0;d<b;d++)c=this.a[d],Tj(this,Object.keys(c.g));Qj.ka.ba.call(this)}; +var Bj="pointermove",Aj="pointerdown",Cj="pointerup",Nj="pointerover",Vj="pointerout",Oj="pointerenter",Pj="pointerleave",zj="pointercancel",Uj=[["bubbles",!1],["cancelable",!1],["view",null],["detail",null],["screenX",0],["screenY",0],["clientX",0],["clientY",0],["ctrlKey",!1],["altKey",!1],["shiftKey",!1],["metaKey",!1],["button",0],["relatedTarget",null],["buttons",0],["pointerId",0],["width",0],["height",0],["pressure",0],["tiltX",0],["tiltY",0],["pointerType",""],["hwTimestamp",0],["isPrimary", +!1],["type",""],["target",null],["currentTarget",null],["which",0]];function Wj(b,c,d,e,f){Hi.call(this,b,c,f);this.a=d;this.originalEvent=d.a;this.pixel=c.Gc(this.originalEvent);this.coordinate=c.ua(this.pixel);this.dragging=void 0!==e?e:!1}y(Wj,Hi);Wj.prototype.preventDefault=function(){Wj.ka.preventDefault.call(this);this.a.preventDefault()};Wj.prototype.i=function(){Wj.ka.i.call(this);this.a.i()};function Xj(b,c,d,e,f){Wj.call(this,b,c,d.a,e,f);this.f=d}y(Xj,Wj); +function Yj(b){Cc.call(this);this.H=b;this.g=0;this.i=!1;this.f=this.s=this.b=null;b=this.H.a;this.u=0;this.l={};this.c=new Qj(b);this.a=null;this.s=z(this.c,Aj,this.fi,!1,this);this.j=z(this.c,Bj,this.Qk,!1,this)}y(Yj,Cc);function Zj(b,c){var d;d=new Xj(ak,b.H,c);b.B(d);0!==b.g?(ba.clearTimeout(b.g),b.g=0,d=new Xj(bk,b.H,c),b.B(d)):b.g=ba.setTimeout(ra(function(){this.g=0;var b=new Xj(ck,this.H,c);this.B(b)},b),250)} +function dk(b,c){c.type==ek||c.type==fk?delete b.l[c.pointerId]:c.type==gk&&(b.l[c.pointerId]=!0);b.u=xa(b.l)}k=Yj.prototype;k.lf=function(b){dk(this,b);var c=new Xj(ek,this.H,b);this.B(c);!this.i&&0===b.button&&Zj(this,this.f);0===this.u&&(this.b.forEach(yc),this.b=null,this.i=!1,this.f=null,Wb(this.a),this.a=null)}; +k.fi=function(b){dk(this,b);var c=new Xj(gk,this.H,b);this.B(c);this.f=b;this.b||(this.a=new Qj(document),this.b=[z(this.a,hk,this.Xi,!1,this),z(this.a,ek,this.lf,!1,this),z(this.c,fk,this.lf,!1,this)])};k.Xi=function(b){if(b.clientX!=this.f.clientX||b.clientY!=this.f.clientY){this.i=!0;var c=new Xj(ik,this.H,b,this.i);this.B(c)}b.preventDefault()};k.Qk=function(b){this.B(new Xj(b.type,this.H,b,!(!this.f||b.clientX==this.f.clientX&&b.clientY==this.f.clientY)))}; +k.ba=function(){this.j&&(yc(this.j),this.j=null);this.s&&(yc(this.s),this.s=null);this.b&&(this.b.forEach(yc),this.b=null);this.a&&(Wb(this.a),this.a=null);this.c&&(Wb(this.c),this.c=null);Yj.ka.ba.call(this)};var ck="singleclick",ak="click",bk="dblclick",ik="pointerdrag",hk="pointermove",gk="pointerdown",ek="pointerup",fk="pointercancel",jk={Nl:ck,Cl:ak,Dl:bk,Gl:ik,Jl:hk,Fl:gk,Ml:ek,Ll:"pointerover",Kl:"pointerout",Hl:"pointerenter",Il:"pointerleave",El:fk};function kk(b,c,d,e,f){Cc.call(this);this.s=f;this.extent=b;this.b=d;this.resolution=c;this.state=e}y(kk,Cc);function lk(b){b.B("change")}kk.prototype.G=function(){return this.extent};kk.prototype.V=function(){return this.resolution};function mk(b,c,d,e,f,g,h,l){b[0]=1;b[1]=0;b[2]=0;b[3]=0;b[4]=0;b[5]=1;b[6]=0;b[7]=0;b[8]=0;b[9]=0;b[10]=1;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;0===c&&0===d||Sc(b,c,d);if(1!=e||1!=f){c=b[1]*e;d=b[2]*e;var m=b[3]*e,n=b[4]*f,p=b[5]*f,q=b[6]*f;f=b[7]*f;var r=1*b[8],t=1*b[9],B=1*b[10],X=1*b[11],x=b[12],E=b[13],v=b[14],Ca=b[15];b[0]*=e;b[1]=c;b[2]=d;b[3]=m;b[4]=n;b[5]=p;b[6]=q;b[7]=f;b[8]=r;b[9]=t;b[10]=B;b[11]=X;b[12]=x;b[13]=E;b[14]=v;b[15]=Ca}0!==g&&(e=b[0],c=b[1],d=b[2],m=b[3],n=b[4],p=b[5],q=b[6], +f=b[7],r=Math.cos(g),g=Math.sin(g),b[0]=e*r+n*g,b[1]=c*r+p*g,b[2]=d*r+q*g,b[3]=m*r+f*g,b[4]=e*-g+n*r,b[5]=c*-g+p*r,b[6]=d*-g+q*r,b[7]=m*-g+f*r);0===h&&0===l||Sc(b,h,l);return b}function nk(b,c,d){var e=b[1],f=b[5],g=b[13],h=c[0];c=c[1];d[0]=b[0]*h+b[4]*c+b[12];d[1]=e*h+f*c+g;return d};function ok(b){Fc.call(this);this.a=b}y(ok,Fc);ok.prototype.rc=Id;ok.prototype.ie=function(b,c,d,e){b=b.slice();nk(c.pixelToCoordinateMatrix,b,b);if(this.rc(b,c,De,this))return d.call(e,this.a)};function pk(b,c,d){return function(e,f){return Qf(b,c,e,f,function(b){d[e]||(d[e]={});d[e][b.a.toString()]=b})}}ok.prototype.I=function(b){2===b.target.state&&qk(this)};function qk(b){var c=b.a;c.Ha()&&"ready"==c.Nd()&&b.A()} +function rk(b,c){c.If()&&b.postRenderFunctions.push(sa(function(b,c,f){c=u(b).toString();b.Jf(f.viewState.projection,f.usedTiles[c])},c))}function sk(b,c){if(c){var d,e,f;e=0;for(f=c.length;e<f;++e)d=c[e],b[u(d).toString()]=d}}function tk(b,c){var d=c.J;void 0!==d&&(ha(d)?b.logos[d]="":ma(d)&&(b.logos[d.src]=d.href))} +function uk(b,c,d,e){c=u(c).toString();d=d.toString();c in b?d in b[c]?(b=b[c][d],e.a<b.a&&(b.a=e.a),e.f>b.f&&(b.f=e.f),e.c<b.c&&(b.c=e.c),e.b>b.b&&(b.b=e.b)):b[c][d]=e:(b[c]={},b[c][d]=e)}function vk(b,c,d){return[c*(Math.round(b[0]/c)+d[0]%2/2),c*(Math.round(b[1]/c)+d[1]%2/2)]} +function wk(b,c,d,e,f,g,h,l){var m=u(c).toString();m in b.wantedTiles||(b.wantedTiles[m]={});var n=b.wantedTiles[m];b=b.tileQueue;var p=d.minZoom,q,r,t,B,X,x;for(x=h;x>=p;--x)for(r=d.fb(g,x,r),t=d.V(x),B=r.a;B<=r.f;++B)for(X=r.c;X<=r.b;++X)if(h-x<=l){if(q=Vf(c,x,B,X,e,f),0==q.state&&(n[Od(q.a)]=!0,!(q.de()in b.b))){var E=b;q=[q,m,Mf(d,q.a),t];var v=E.s(q);Infinity!=v&&(E.a.push(q),E.f.push(v),E.b[E.g(q)]=!0,xk(E,0,E.a.length-1))}}else c.ng(x,B,X,f)};function Pg(b){b=b||{};this.g=void 0!==b.anchor?b.anchor:[.5,.5];this.c=null;this.f=void 0!==b.anchorOrigin?b.anchorOrigin:"top-left";this.j=void 0!==b.anchorXUnits?b.anchorXUnits:"fraction";this.l=void 0!==b.anchorYUnits?b.anchorYUnits:"fraction";var c=void 0!==b.crossOrigin?b.crossOrigin:null,d=void 0!==b.img?b.img:null,e=void 0!==b.imgSize?b.imgSize:null,f=b.src;void 0!==f&&0!==f.length||!d||(f=d.src);var g=void 0!==b.src?0:2,h=yk.af(),l=h.get(f,c);l||(l=new zk(d,f,e,c,g),h.a[c+":"+f]=l,++h.f); +this.a=l;this.fa=void 0!==b.offset?b.offset:[0,0];this.b=void 0!==b.offsetOrigin?b.offsetOrigin:"top-left";this.i=null;this.v=void 0!==b.size?b.size:null;kh.call(this,{opacity:void 0!==b.opacity?b.opacity:1,rotation:void 0!==b.rotation?b.rotation:0,scale:void 0!==b.scale?b.scale:1,snapToPixel:void 0!==b.snapToPixel?b.snapToPixel:!0,rotateWithView:void 0!==b.rotateWithView?b.rotateWithView:!1})}y(Pg,kh);k=Pg.prototype; +k.mb=function(){if(this.c)return this.c;var b=this.g,c=this.Ya();if("fraction"==this.j||"fraction"==this.l){if(!c)return null;b=this.g.slice();"fraction"==this.j&&(b[0]*=c[0]);"fraction"==this.l&&(b[1]*=c[1])}if("top-left"!=this.f){if(!c)return null;b===this.g&&(b=this.g.slice());if("top-right"==this.f||"bottom-right"==this.f)b[0]=-b[0]+c[0];if("bottom-left"==this.f||"bottom-right"==this.f)b[1]=-b[1]+c[1]}return this.c=b};k.ib=function(){return this.a.a};k.Ic=function(){return this.a.b};k.tc=function(){return this.a.f}; +k.le=function(){var b=this.a;if(!b.g)if(b.j){var c=b.b[0],d=b.b[1],e=of(c,d);e.fillRect(0,0,c,d);b.g=e.canvas}else b.g=b.a;return b.g};k.Aa=function(){if(this.i)return this.i;var b=this.fa;if("top-left"!=this.b){var c=this.Ya(),d=this.a.b;if(!c||!d)return null;b=b.slice();if("top-right"==this.b||"bottom-right"==this.b)b[0]=d[0]-c[0]-b[0];if("bottom-left"==this.b||"bottom-right"==this.b)b[1]=d[1]-c[1]-b[1]}return this.i=b};k.bk=function(){return this.a.i};k.Ya=function(){return this.v?this.v:this.a.b}; +k.Xd=function(b,c){return z(this.a,"change",b,!1,c)};k.load=function(){this.a.load()};k.Ae=function(b,c){xc(this.a,"change",b,!1,c)};function zk(b,c,d,e,f){Cc.call(this);this.g=null;this.a=b?b:new Image;null!==e&&(this.a.crossOrigin=e);this.c=null;this.f=f;this.b=d;this.i=c;this.j=!1;2==this.f&&Ak(this)}y(zk,Cc);function Ak(b){var c=of(1,1);try{c.drawImage(b.a,0,0),c.getImageData(0,0,1,1)}catch(d){b.j=!0}}zk.prototype.s=function(){this.f=3;this.c.forEach(yc);this.c=null;this.B("change")}; +zk.prototype.l=function(){this.f=2;this.b=[this.a.width,this.a.height];this.c.forEach(yc);this.c=null;Ak(this);this.B("change")};zk.prototype.load=function(){if(0==this.f){this.f=1;this.c=[wc(this.a,"error",this.s,!1,this),wc(this.a,"load",this.l,!1,this)];try{this.a.src=this.i}catch(b){this.s()}}};function yk(){this.a={};this.f=0}(function(){var b=yk;b.af=function(){return b.mf?b.mf:b.mf=new b}})();yk.prototype.clear=function(){this.a={};this.f=0}; +yk.prototype.get=function(b,c){var d=c+":"+b;return d in this.a?this.a[d]:null};function Bk(b,c){Sb.call(this);this.H=c;this.f={};this.c={}}y(Bk,Sb);Bk.prototype.ba=function(){ua(this.f,Wb);Bk.ka.ba.call(this)};function Ck(){var b=yk.af();if(32<b.f){var c=0,d,e;for(d in b.a){e=b.a[d];var f;if(f=0===(c++&3))fc(e)?e=Ec(e,void 0,void 0):(e=sc(e),e=!!e&&mc(e,void 0,void 0)),f=!e;f&&(delete b.a[d],--b.f)}}} +function Dk(b,c,d,e,f,g,h){function l(b){var c=u(b).toString();if(!(c in q))return q[c]=!0,e.call(f,b,null)}var m,n=d.viewState,p=n.resolution,q={},r=n.projection,n=c;if(r.f){var r=r.G(),t=Bd(r),B=c[0];if(B<r[0]||B>r[2])n=[B+t*Math.ceil((r[0]-B)/t),c[1]]}r=d.layerStatesArray;for(t=r.length-1;0<=t;--t){var B=r[t],X=B.layer;if(!B.kc||B.visible&&p>=B.minResolution&&p<B.maxResolution&&g.call(h,X)){var x=Ek(b,X);X.da()&&(m=x.rc(oe(X.da())?n:c,d,B.kc?e:l,f));if(m)return m}}} +function Ek(b,c){var d=u(c).toString();if(d in b.f)return b.f[d];var e;e=c instanceof I?new Fk(c):c instanceof F?new Gk(c):c instanceof J?new Hk(c):null;b.f[d]=e;b.c[d]=z(e,"change",b.s,!1,b);return e}Bk.prototype.s=function(){this.H.render()};Bk.prototype.i=Id;Bk.prototype.l=function(b,c){for(var d in this.f)if(!(c&&d in c.layerStates)){var e=d,f=this.f[e];delete this.f[e];yc(this.c[e]);delete this.c[e];Wb(f)}};function Ik(b,c){return b.zIndex-c.zIndex};function Jk(b,c){this.s=b;this.g=c;this.a=[];this.f=[];this.b={}}Jk.prototype.clear=function(){this.a.length=0;this.f.length=0;Ea(this.b)};Jk.prototype.fc=function(){return this.a.length};Jk.prototype.Pa=function(){return 0===this.a.length};function Kk(b,c){for(var d=b.a,e=b.f,f=d.length,g=d[c],h=e[c],l=c;c<f>>1;){var m=2*c+1,n=2*c+2,m=n<f&&e[n]<e[m]?n:m;d[c]=d[m];e[c]=e[m];c=m}d[c]=g;e[c]=h;xk(b,l,c)} +function xk(b,c,d){var e=b.a;b=b.f;for(var f=e[d],g=b[d];d>c;){var h=d-1>>1;if(b[h]>g)e[d]=e[h],b[d]=b[h],d=h;else break}e[d]=f;b[d]=g};function Lk(b,c){Jk.call(this,function(c){return b.apply(null,c)},function(b){return b[0].de()});this.j=c;this.c=0}y(Lk,Jk);Lk.prototype.i=function(b){b=b.target;var c=b.state;if(2===c||3===c||4===c)xc(b,"change",this.i,!1,this),--this.c,this.j()};function Mk(b,c,d){this.c=b;this.b=c;this.i=d;this.a=[];this.f=this.g=0}Mk.prototype.update=function(b,c){this.a.push(b,c,Date.now())};function Nk(b,c){var d=b.c,e=b.f,f=b.b-e,g=Math.log(b.b/b.f)/b.c;return oi({source:c,duration:g,easing:function(b){return e*(Math.exp(d*b*g)-1)/f}})};function Ok(b){Ic.call(this);this.H=null;this.l(!0);this.handleEvent=b.handleEvent}y(Ok,Ic);Ok.prototype.j=function(){return this.get("active")};Ok.prototype.l=function(b){this.C("active",b)};Ok.prototype.setMap=function(b){this.H=b};function Pk(b,c,d,e,f){if(void 0!==d){var g=c.xa(),h=c.wa();void 0!==g&&h&&f&&0<f&&(b.Fa(pi({rotation:g,duration:f,easing:li})),e&&b.Fa(oi({source:h,duration:f,easing:li})));c.rotate(d,e)}} +function Qk(b,c,d,e,f){var g=c.V();d=c.constrainResolution(g,d,0);Rk(b,c,d,e,f)}function Rk(b,c,d,e,f){if(d){var g=c.V(),h=c.wa();void 0!==g&&h&&d!==g&&f&&0<f&&(b.Fa(qi({resolution:g,duration:f,easing:li})),e&&b.Fa(oi({source:h,duration:f,easing:li})));if(e){var l;b=c.wa();f=c.V();void 0!==b&&void 0!==f&&(l=[e[0]-d*(e[0]-b[0])/f,e[1]-d*(e[1]-b[1])/f]);c.Ca(l)}c.xb(d)}};function Sk(b){b=b?b:{};this.a=b.delta?b.delta:1;Ok.call(this,{handleEvent:Tk});this.b=void 0!==b.duration?b.duration:250}y(Sk,Ok);function Tk(b){var c=!1,d=b.a;if(b.type==bk){var c=b.map,e=b.coordinate,d=d.g?-this.a:this.a,f=c.ja();Qk(c,f,d,e,this.b);b.preventDefault();c=!0}return!c};function Uk(b){b=b.a;return b.f&&!b.l&&b.g}function Vk(b){return b.type==ck}function Wk(b){b=b.a;return!b.f&&!b.l&&!b.g}function Xk(b){b=b.a;return!b.f&&!b.l&&b.g}function Yk(b){b=b.a.target.tagName;return"INPUT"!==b&&"SELECT"!==b&&"TEXTAREA"!==b}function Zk(b){return"mouse"==b.f.pointerType};function $k(b){b=b?b:{};Ok.call(this,{handleEvent:b.handleEvent?b.handleEvent:al});this.Bb=b.handleDownEvent?b.handleDownEvent:Ce;this.Cb=b.handleDragEvent?b.handleDragEvent:Id;this.Db=b.handleMoveEvent?b.handleMoveEvent:Id;this.Vb=b.handleUpEvent?b.handleUpEvent:Ce;this.D=!1;this.U={};this.c=[]}y($k,Ok);function bl(b){for(var c=b.length,d=0,e=0,f=0;f<c;f++)d+=b[f].clientX,e+=b[f].clientY;return[d/c,e/c]} +function al(b){if(!(b instanceof Xj))return!0;var c=!1,d=b.type;if(d===gk||d===ik||d===ek)d=b.f,b.type==ek?delete this.U[d.pointerId]:b.type==gk?this.U[d.pointerId]=d:d.pointerId in this.U&&(this.U[d.pointerId]=d),this.c=ya(this.U);this.D&&(b.type==ik?this.Cb(b):b.type==ek&&(this.D=this.Vb(b)));b.type==gk?(this.D=b=this.Bb(b),c=this.yb(b)):b.type==hk&&this.Db(b);return!c}$k.prototype.yb=function(b){return b};function cl(b){$k.call(this,{handleDownEvent:dl,handleDragEvent:el,handleUpEvent:fl});b=b?b:{};this.a=b.kinetic;this.b=this.g=null;this.u=b.condition?b.condition:Wk;this.i=!1}y(cl,$k);function el(b){var c=bl(this.c);this.a&&this.a.update(c[0],c[1]);if(this.b){var d=this.b[0]-c[0],e=c[1]-this.b[1];b=b.map;var f=b.ja(),g=ji(f),e=d=[d,e],h=g.resolution;e[0]*=h;e[1]*=h;$c(d,g.rotation);Vc(d,g.center);d=f.Ec(d);b.render();f.Ca(d)}this.b=c} +function fl(b){b=b.map;var c=b.ja();if(0===this.c.length){var d;if(d=!this.i&&this.a)if(d=this.a,6>d.a.length)d=!1;else{var e=Date.now()-d.i,f=d.a.length-3;if(d.a[f+2]<e)d=!1;else{for(var g=f-3;0<g&&d.a[g+2]>e;)g-=3;var e=d.a[f+2]-d.a[g+2],h=d.a[f]-d.a[g],f=d.a[f+1]-d.a[g+1];d.g=Math.atan2(f,h);d.f=Math.sqrt(h*h+f*f)/e;d=d.f>d.b}}d&&(d=this.a,d=(d.b-d.f)/d.c,f=this.a.g,g=c.wa(),this.g=Nk(this.a,g),b.Fa(this.g),g=b.Ga(g),d=b.ua([g[0]-d*Math.cos(f),g[1]-d*Math.sin(f)]),d=c.Ec(d),c.Ca(d));ki(c,-1);b.render(); +return!1}this.b=null;return!0}function dl(b){if(0<this.c.length&&this.u(b)){var c=b.map,d=c.ja();this.b=null;this.D||ki(d,1);c.render();this.g&&hb(c.I,this.g)&&(d.Ca(b.frameState.viewState.center),this.g=null);this.a&&(b=this.a,b.a.length=0,b.g=0,b.f=0);this.i=1<this.c.length;return!0}return!1}cl.prototype.yb=Ce;function gl(b){b=b?b:{};$k.call(this,{handleDownEvent:hl,handleDragEvent:il,handleUpEvent:jl});this.b=b.condition?b.condition:Uk;this.a=void 0;this.g=void 0!==b.duration?b.duration:250}y(gl,$k);function il(b){if(Zk(b)){var c=b.map,d=c.rb();b=b.pixel;d=Math.atan2(d[1]/2-b[1],b[0]-d[0]/2);if(void 0!==this.a){b=d-this.a;var e=c.ja(),f=e.xa();c.render();Pk(c,e,f-b)}this.a=d}} +function jl(b){if(!Zk(b))return!0;b=b.map;var c=b.ja();ki(c,-1);var d=c.xa(),e=this.g,d=c.constrainRotation(d,0);Pk(b,c,d,void 0,e);return!1}function hl(b){return Zk(b)&&dc(b.a)&&this.b(b)?(b=b.map,ki(b.ja(),1),b.render(),this.a=void 0,!0):!1}gl.prototype.yb=Ce;function kl(b){this.b=null;this.a=document.createElement("div");this.a.style.position="absolute";this.a.className="ol-box "+b;this.f=this.c=this.H=null}y(kl,Sb);kl.prototype.ba=function(){this.setMap(null);kl.ka.ba.call(this)};function ll(b){var c=b.c,d=b.f;b=b.a.style;b.left=Math.min(c[0],d[0])+"px";b.top=Math.min(c[1],d[1])+"px";b.width=Math.abs(d[0]-c[0])+"px";b.height=Math.abs(d[1]-c[1])+"px"} +kl.prototype.setMap=function(b){if(this.H){this.H.J.removeChild(this.a);var c=this.a.style;c.left=c.top=c.width=c.height="inherit"}(this.H=b)&&this.H.J.appendChild(this.a)};function ml(b){var c=b.c,d=b.f,c=[c,[c[0],d[1]],d,[d[0],c[1]]].map(b.H.ua,b.H);c[4]=c[0].slice();b.b?b.b.ia([c]):b.b=new M([c])}kl.prototype.R=function(){return this.b};function nl(b,c){Xb.call(this,b);this.coordinate=c}y(nl,Xb);function pl(b){$k.call(this,{handleDownEvent:ql,handleDragEvent:rl,handleUpEvent:sl});b=b?b:{};this.b=new kl(b.className||"ol-dragbox");this.a=null;this.u=b.condition?b.condition:De}y(pl,$k);function rl(b){if(Zk(b)){var c=this.b;b=b.pixel;c.c=this.a;c.f=b;ml(c);ll(c)}}pl.prototype.R=function(){return this.b.R()};pl.prototype.i=Id; +function sl(b){if(!Zk(b))return!0;this.b.setMap(null);var c=b.pixel[0]-this.a[0],d=b.pixel[1]-this.a[1];64<=c*c+d*d&&(this.i(b),this.B(new nl("boxend",b.coordinate)));return!1}function ql(b){if(Zk(b)&&dc(b.a)&&this.u(b)){this.a=b.pixel;this.b.setMap(b.map);var c=this.b,d=this.a;c.c=this.a;c.f=d;ml(c);ll(c);this.B(new nl("boxstart",b.coordinate));return!0}return!1};function tl(b){b=b?b:{};var c=b.condition?b.condition:Xk;this.g=void 0!==b.duration?b.duration:200;pl.call(this,{condition:c,className:b.className||"ol-dragzoom"})}y(tl,pl);tl.prototype.i=function(){var b=this.H,c=b.ja(),d=b.rb(),e=this.R().G(),d=c.constrainResolution(c.Md(e,d)),f=c.V(),g=c.wa();b.Fa(qi({resolution:f,duration:this.g,easing:li}));b.Fa(oi({source:g,duration:this.g,easing:li}));c.Ca(Ed(e));c.xb(d)};function ul(b){Ok.call(this,{handleEvent:vl});b=b||{};this.a=void 0!==b.condition?b.condition:Fe(Wk,Yk);this.b=void 0!==b.duration?b.duration:100;this.c=void 0!==b.pixelDelta?b.pixelDelta:128}y(ul,Ok); +function vl(b){var c=!1;if("key"==b.type){var d=b.a.c;if(this.a(b)&&(40==d||37==d||39==d||38==d)){var e=b.map,c=e.ja(),f=c.V()*this.c,g=0,h=0;40==d?h=-f:37==d?g=-f:39==d?g=f:h=f;d=[g,h];$c(d,c.xa());f=this.b;if(g=c.wa())f&&0<f&&e.Fa(oi({source:g,duration:f,easing:hg})),e=c.Ec([g[0]+d[0],g[1]+d[1]]),c.Ca(e);b.preventDefault();c=!0}}return!c};function wl(b){Ok.call(this,{handleEvent:xl});b=b?b:{};this.b=b.condition?b.condition:Yk;this.a=b.delta?b.delta:1;this.c=void 0!==b.duration?b.duration:100}y(wl,Ok);function xl(b){var c=!1;if("key"==b.type){var d=b.a.u;if(this.b(b)&&(43==d||45==d)){c=b.map;d=43==d?this.a:-this.a;c.render();var e=c.ja();Qk(c,e,d,void 0,this.c);b.preventDefault();c=!0}}return!c};function yl(b){Ok.call(this,{handleEvent:zl});b=b||{};this.a=0;this.u=void 0!==b.duration?b.duration:250;this.D=void 0!==b.useAnchor?b.useAnchor:!0;this.c=null;this.g=this.b=void 0}y(yl,Ok);function zl(b){var c=!1;if("mousewheel"==b.type){var c=b.map,d=b.a;this.D&&(this.c=b.coordinate);this.a+=d.v;void 0===this.b&&(this.b=Date.now());d=Math.max(80-(Date.now()-this.b),0);ba.clearTimeout(this.g);this.g=ba.setTimeout(ra(this.i,this,c),d);b.preventDefault();c=!0}return!c} +yl.prototype.i=function(b){var c=Jd(this.a,-1,1),d=b.ja();b.render();Qk(b,d,-c,this.c,this.u);this.a=0;this.c=null;this.g=this.b=void 0};function Al(b){$k.call(this,{handleDownEvent:Bl,handleDragEvent:Cl,handleUpEvent:Dl});b=b||{};this.b=null;this.g=void 0;this.a=!1;this.i=0;this.v=void 0!==b.threshold?b.threshold:.3;this.u=void 0!==b.duration?b.duration:250}y(Al,$k); +function Cl(b){var c=0,d=this.c[0],e=this.c[1],d=Math.atan2(e.clientY-d.clientY,e.clientX-d.clientX);void 0!==this.g&&(c=d-this.g,this.i+=c,!this.a&&Math.abs(this.i)>this.v&&(this.a=!0));this.g=d;b=b.map;d=zi(b.a);e=bl(this.c);e[0]-=d.x;e[1]-=d.y;this.b=b.ua(e);this.a&&(d=b.ja(),e=d.xa(),b.render(),Pk(b,d,e+c,this.b))}function Dl(b){if(2>this.c.length){b=b.map;var c=b.ja();ki(c,-1);if(this.a){var d=c.xa(),e=this.b,f=this.u,d=c.constrainRotation(d,0);Pk(b,c,d,e,f)}return!1}return!0} +function Bl(b){return 2<=this.c.length?(b=b.map,this.b=null,this.g=void 0,this.a=!1,this.i=0,this.D||ki(b.ja(),1),b.render(),!0):!1}Al.prototype.yb=Ce;function El(b){$k.call(this,{handleDownEvent:Fl,handleDragEvent:Gl,handleUpEvent:Hl});b=b?b:{};this.b=null;this.i=void 0!==b.duration?b.duration:400;this.a=void 0;this.g=1}y(El,$k);function Gl(b){var c=1,d=this.c[0],e=this.c[1],f=d.clientX-e.clientX,d=d.clientY-e.clientY,f=Math.sqrt(f*f+d*d);void 0!==this.a&&(c=this.a/f);this.a=f;1!=c&&(this.g=c);b=b.map;var f=b.ja(),d=f.V(),e=zi(b.a),g=bl(this.c);g[0]-=e.x;g[1]-=e.y;this.b=b.ua(g);b.render();Rk(b,f,d*c,this.b)} +function Hl(b){if(2>this.c.length){b=b.map;var c=b.ja();ki(c,-1);var d=c.V(),e=this.b,f=this.i,d=c.constrainResolution(d,0,this.g-1);Rk(b,c,d,e,f);return!1}return!0}function Fl(b){return 2<=this.c.length?(b=b.map,this.b=null,this.a=void 0,this.g=1,this.D||ki(b.ja(),1),b.render(),!0):!1}El.prototype.yb=Ce;function Il(b){b=b?b:{};var c=new A,d=new Mk(-.005,.05,100);(void 0!==b.altShiftDragRotate?b.altShiftDragRotate:1)&&c.push(new gl);(void 0!==b.doubleClickZoom?b.doubleClickZoom:1)&&c.push(new Sk({delta:b.zoomDelta,duration:b.zoomDuration}));(void 0!==b.dragPan?b.dragPan:1)&&c.push(new cl({kinetic:d}));(void 0!==b.pinchRotate?b.pinchRotate:1)&&c.push(new Al);(void 0!==b.pinchZoom?b.pinchZoom:1)&&c.push(new El({duration:b.zoomDuration}));if(void 0!==b.keyboard?b.keyboard:1)c.push(new ul),c.push(new wl({delta:b.zoomDelta, +duration:b.zoomDuration}));(void 0!==b.mouseWheelZoom?b.mouseWheelZoom:1)&&c.push(new yl({duration:b.zoomDuration}));(void 0!==b.shiftDragZoom?b.shiftDragZoom:1)&&c.push(new tl({duration:b.zoomDuration}));return c};function Jl(b){Xd.call(this,{code:b,units:"m",extent:Kl,global:!0,worldExtent:Ll})}y(Jl,Xd);Jl.prototype.getPointResolution=function(b,c){return b/Kd(c[1]/6378137)};var Ml=6378137*Math.PI,Kl=[-Ml,-Ml,Ml,Ml],Ll=[-180,-85,180,85],Nl="EPSG:3857 EPSG:102100 EPSG:102113 EPSG:900913 urn:ogc:def:crs:EPSG:6.18:3:3857 urn:ogc:def:crs:EPSG::3857 http://www.opengis.net/gml/srs/epsg.xml#3857".split(" ").map(function(b){return new Jl(b)}); +function Ol(b,c,d){var e=b.length;d=1<d?d:2;void 0===c&&(2<d?c=b.slice():c=Array(e));for(var f=0;f<e;f+=d)c[f]=6378137*Math.PI*b[f]/180,c[f+1]=6378137*Math.log(Math.tan(Math.PI*(b[f+1]+90)/360));return c}function Pl(b,c,d){var e=b.length;d=1<d?d:2;void 0===c&&(2<d?c=b.slice():c=Array(e));for(var f=0;f<e;f+=d)c[f]=180*b[f]/(6378137*Math.PI),c[f+1]=360*Math.atan(Math.exp(b[f+1]/6378137))/Math.PI-90;return c};function Ql(b,c){Xd.call(this,{code:b,units:"degrees",extent:Rl,axisOrientation:c,global:!0,worldExtent:Rl})}y(Ql,Xd);Ql.prototype.getPointResolution=function(b){return b}; +var Rl=[-180,-90,180,90],Sl=[new Ql("CRS:84"),new Ql("EPSG:4326","neu"),new Ql("urn:ogc:def:crs:EPSG::4326","neu"),new Ql("urn:ogc:def:crs:EPSG:6.6:4326","neu"),new Ql("urn:ogc:def:crs:OGC:1.3:CRS84"),new Ql("urn:ogc:def:crs:OGC:2:84"),new Ql("http://www.opengis.net/gml/srs/epsg.xml#4326","neu"),new Ql("urn:x-ogc:def:crs:EPSG:4326","neu")];function I(b){D.call(this,b?b:{})}y(I,D);function Tl(b,c,d,e,f){this.Ac={};this.b=b;this.F=c;this.s=d;this.fa=e;this.Vb=f;this.g=this.a=this.f=this.qa=this.Qa=this.ea=null;this.ya=this.ra=this.D=this.L=this.I=this.J=0;this.Ea=!1;this.i=this.$a=0;this.lb=!1;this.U=0;this.c="";this.l=this.la=this.Cb=this.Bb=0;this.ca=this.u=this.j=null;this.v=[];this.Db=Qc()} +function Ul(b,c,d){if(b.g){c=Eg(c,0,d,2,b.fa,b.v);d=b.b;var e=b.Db,f=d.globalAlpha;1!=b.D&&(d.globalAlpha=f*b.D);var g=b.$a;b.Ea&&(g+=b.Vb);var h,l;h=0;for(l=c.length;h<l;h+=2){var m=c[h]-b.J,n=c[h+1]-b.I;b.lb&&(m=m+.5|0,n=n+.5|0);if(0!==g||1!=b.i){var p=m+b.J,q=n+b.I;mk(e,p,q,b.i,b.i,g,-p,-q);d.setTransform(e[0],e[1],e[4],e[5],e[12],e[13])}d.drawImage(b.g,b.ra,b.ya,b.U,b.L,m,n,b.U,b.L)}0===g&&1==b.i||d.setTransform(1,0,0,1,0,0);1!=b.D&&(d.globalAlpha=f)}} +function Vl(b,c,d,e){var f=0;if(b.ca&&""!==b.c){b.j&&Wl(b,b.j);b.u&&Xl(b,b.u);var g=b.ca,h=b.b,l=b.qa;l?(l.font!=g.font&&(l.font=h.font=g.font),l.textAlign!=g.textAlign&&(l.textAlign=h.textAlign=g.textAlign),l.textBaseline!=g.textBaseline&&(l.textBaseline=h.textBaseline=g.textBaseline)):(h.font=g.font,h.textAlign=g.textAlign,h.textBaseline=g.textBaseline,b.qa={font:g.font,textAlign:g.textAlign,textBaseline:g.textBaseline});c=Eg(c,f,d,e,b.fa,b.v);for(g=b.b;f<d;f+=e){h=c[f]+b.Bb;l=c[f+1]+b.Cb;if(0!== +b.la||1!=b.l){var m=mk(b.Db,h,l,b.l,b.l,b.la,-h,-l);g.setTransform(m[0],m[1],m[4],m[5],m[12],m[13])}b.u&&g.strokeText(b.c,h,l);b.j&&g.fillText(b.c,h,l)}0===b.la&&1==b.l||g.setTransform(1,0,0,1,0,0)}}function Yl(b,c,d,e,f,g){var h=b.b;b=Eg(c,d,e,f,b.fa,b.v);h.moveTo(b[0],b[1]);for(c=2;c<b.length;c+=2)h.lineTo(b[c],b[c+1]);g&&h.lineTo(b[0],b[1]);return e}function Zl(b,c,d,e,f){var g=b.b,h,l;h=0;for(l=e.length;h<l;++h)d=Yl(b,c,d,e[h],f,!0),g.closePath();return d}k=Tl.prototype; +k.yd=function(b){if(Hd(this.s,b.G())){if(this.f||this.a){this.f&&Wl(this,this.f);this.a&&Xl(this,this.a);var c;c=this.fa;var d=this.v,e=b.ga();if(e){var f=b.pa();c=Eg(e,0,e.length,f,c,d)}else c=null;d=c[2]-c[0];e=c[3]-c[1];d=Math.sqrt(d*d+e*e);e=this.b;e.beginPath();e.arc(c[0],c[1],d,0,2*Math.PI);this.f&&e.fill();this.a&&e.stroke()}""!==this.c&&Vl(this,b.lc(),2,2)}};k.Ng=function(b,c){var d=b.a,e,f;e=0;for(f=d.length;e<f;++e){var g=d[e];$l[g.N()].call(this,g,c)}}; +k.Dd=function(b){var c=b.ga();b=b.pa();this.g&&Ul(this,c,c.length);""!==this.c&&Vl(this,c,c.length,b)};k.Bd=function(b){var c=b.ga();b=b.pa();this.g&&Ul(this,c,c.length);""!==this.c&&Vl(this,c,c.length,b)};k.zd=function(b){if(Hd(this.s,b.G())){if(this.a){Xl(this,this.a);var c=this.b,d=b.ga();c.beginPath();Yl(this,d,0,d.length,b.pa(),!1);c.stroke()}""!==this.c&&(b=am(b),Vl(this,b,2,2))}}; +k.Ad=function(b){var c=b.G();if(Hd(this.s,c)){if(this.a){Xl(this,this.a);var c=this.b,d=b.ga(),e=0,f=b.Ua(),g=b.pa();c.beginPath();var h,l;h=0;for(l=f.length;h<l;++h)e=Yl(this,d,e,f[h],g,!1);c.stroke()}""!==this.c&&(b=bm(b),Vl(this,b,b.length,2))}};k.Ed=function(b){if(Hd(this.s,b.G())){if(this.a||this.f){this.f&&Wl(this,this.f);this.a&&Xl(this,this.a);var c=this.b;c.beginPath();Zl(this,b.hb(),0,b.Ua(),b.pa());this.f&&c.fill();this.a&&c.stroke()}""!==this.c&&(b=ii(b),Vl(this,b,2,2))}}; +k.Cd=function(b){if(Hd(this.s,b.G())){if(this.a||this.f){this.f&&Wl(this,this.f);this.a&&Xl(this,this.a);var c=this.b,d=cm(b),e=0,f=b.c,g=b.pa(),h,l;h=0;for(l=f.length;h<l;++h){var m=f[h];c.beginPath();e=Zl(this,d,e,m,g);this.f&&c.fill();this.a&&c.stroke()}}""!==this.c&&(b=dm(b),Vl(this,b,b.length,2))}};function em(b){var c=Object.keys(b.Ac).map(Number);pb(c);var d,e,f,g,h;d=0;for(e=c.length;d<e;++d)for(f=b.Ac[c[d].toString()],g=0,h=f.length;g<h;++g)f[g](b)} +function Wl(b,c){var d=b.b,e=b.ea;e?e.fillStyle!=c.fillStyle&&(e.fillStyle=d.fillStyle=c.fillStyle):(d.fillStyle=c.fillStyle,b.ea={fillStyle:c.fillStyle})} +function Xl(b,c){var d=b.b,e=b.Qa;e?(e.lineCap!=c.lineCap&&(e.lineCap=d.lineCap=c.lineCap),$g&&!sb(e.lineDash,c.lineDash)&&d.setLineDash(e.lineDash=c.lineDash),e.lineJoin!=c.lineJoin&&(e.lineJoin=d.lineJoin=c.lineJoin),e.lineWidth!=c.lineWidth&&(e.lineWidth=d.lineWidth=c.lineWidth),e.miterLimit!=c.miterLimit&&(e.miterLimit=d.miterLimit=c.miterLimit),e.strokeStyle!=c.strokeStyle&&(e.strokeStyle=d.strokeStyle=c.strokeStyle)):(d.lineCap=c.lineCap,$g&&d.setLineDash(c.lineDash),d.lineJoin=c.lineJoin,d.lineWidth= +c.lineWidth,d.miterLimit=c.miterLimit,d.strokeStyle=c.strokeStyle,b.Qa={lineCap:c.lineCap,lineDash:c.lineDash,lineJoin:c.lineJoin,lineWidth:c.lineWidth,miterLimit:c.miterLimit,strokeStyle:c.strokeStyle})} +k.wb=function(b,c){if(b){var d=b.a;this.f={fillStyle:Xg(d?d:gh)}}else this.f=null;if(c){var d=c.a,e=c.c,f=c.b,g=c.g,h=c.f,l=c.i;this.a={lineCap:void 0!==e?e:"round",lineDash:f?f:hh,lineJoin:void 0!==g?g:"round",lineWidth:this.F*(void 0!==h?h:1),miterLimit:void 0!==l?l:10,strokeStyle:Xg(d?d:ih)}}else this.a=null}; +k.ue=function(b){if(b){var c=b.mb(),d=b.ib(1),e=b.Aa(),f=b.Ya();this.J=c[0];this.I=c[1];this.L=f[1];this.g=d;this.D=b.u;this.ra=e[0];this.ya=e[1];this.Ea=b.F;this.$a=b.D;this.i=b.s;this.lb=b.la;this.U=f[0]}else this.g=null}; +k.kb=function(b){if(b){var c=b.va();c?(c=c.a,this.j={fillStyle:Xg(c?c:gh)}):this.j=null;var d=b.sa();if(d){var c=d.a,e=d.c,f=d.b,g=d.g,h=d.f,d=d.i;this.u={lineCap:void 0!==e?e:"round",lineDash:f?f:hh,lineJoin:void 0!==g?g:"round",lineWidth:void 0!==h?h:1,miterLimit:void 0!==d?d:10,strokeStyle:Xg(c?c:ih)}}else this.u=null;var c=b.f,e=b.b,f=b.c,g=b.s,h=b.g,d=b.na(),l=b.i;b=b.a;this.ca={font:void 0!==c?c:"10px sans-serif",textAlign:void 0!==l?l:"center",textBaseline:void 0!==b?b:"middle"};this.c=void 0!== +d?d:"";this.Bb=void 0!==e?this.F*e:0;this.Cb=void 0!==f?this.F*f:0;this.la=void 0!==g?g:0;this.l=this.F*(void 0!==h?h:1)}else this.c=""};var $l={Point:Tl.prototype.Dd,LineString:Tl.prototype.zd,Polygon:Tl.prototype.Ed,MultiPoint:Tl.prototype.Bd,MultiLineString:Tl.prototype.Ad,MultiPolygon:Tl.prototype.Cd,GeometryCollection:Tl.prototype.Ng,Circle:Tl.prototype.yd};function fm(b){ok.call(this,b);this.L=Qc()}y(fm,ok); +fm.prototype.D=function(b,c,d){gm(this,"precompose",d,b,void 0);var e=this.$c();if(e){var f=c.extent,g=void 0!==f;if(g){var h=b.pixelRatio,l=yd(f),m=[f[2],f[3]],n=[f[2],f[1]],f=[f[0],f[1]];nk(b.coordinateToPixelMatrix,l,l);nk(b.coordinateToPixelMatrix,m,m);nk(b.coordinateToPixelMatrix,n,n);nk(b.coordinateToPixelMatrix,f,f);d.save();d.beginPath();d.moveTo(l[0]*h,l[1]*h);d.lineTo(m[0]*h,m[1]*h);d.lineTo(n[0]*h,n[1]*h);d.lineTo(f[0]*h,f[1]*h);d.clip()}h=this.$e();l=d.globalAlpha;d.globalAlpha=c.opacity; +0===b.viewState.rotation?d.drawImage(e,0,0,+e.width,+e.height,Math.round(h[12]),Math.round(h[13]),Math.round(e.width*h[0]),Math.round(e.height*h[5])):(d.setTransform(h[0],h[1],h[4],h[5],h[12],h[13]),d.drawImage(e,0,0),d.setTransform(1,0,0,1,0,0));d.globalAlpha=l;g&&d.restore()}gm(this,"postcompose",d,b,void 0)};function gm(b,c,d,e,f){var g=b.a;Ec(g,c)&&(b=void 0!==f?f:hm(b,e,0),b=new Tl(d,e.pixelRatio,e.extent,b,e.viewState.rotation),g.B(new Le(c,g,b,e,d,null)),em(b))} +function hm(b,c,d){var e=c.viewState,f=c.pixelRatio;return mk(b.L,f*c.size[0]/2,f*c.size[1]/2,f/e.resolution,-f/e.resolution,-e.rotation,-e.center[0]+d,-e.center[1])}function im(b,c){var d=[0,0];nk(c,b,d);return d} +var jm=function(){var b=null,c=null;return function(d){if(!b){b=of(1,1);c=b.createImageData(1,1);var e=c.data;e[0]=42;e[1]=84;e[2]=126;e[3]=255}var e=b.canvas,f=d[0]<=e.width&&d[1]<=e.height;f||(e.width=d[0],e.height=d[1],e=d[0]-1,d=d[1]-1,b.putImageData(c,e,d),d=b.getImageData(e,d,1,1),f=sb(c.data,d.data));return f}}();var km=["Polygon","LineString","Image","Text"];function lm(b,c,d){this.ya=b;this.ea=c;this.g=null;this.i=0;this.resolution=d;this.U=this.L=null;this.f=[];this.b=[];this.qa=Qc();this.a=[];this.Qa=[];this.ra=Qc()}y(lm,Ke); +function mm(b,c,d,e,f,g){var h=b.b.length,l=b.Gd(),m=[c[d],c[d+1]],n=[NaN,NaN],p=!0,q,r,t;for(q=d+f;q<e;q+=f)n[0]=c[q],n[1]=c[q+1],t=rd(l,n),t!==r?(p&&(b.b[h++]=m[0],b.b[h++]=m[1]),b.b[h++]=n[0],b.b[h++]=n[1],p=!1):1===t?(b.b[h++]=n[0],b.b[h++]=n[1],p=!1):p=!0,m[0]=n[0],m[1]=n[1],r=t;q===d+f&&(b.b[h++]=m[0],b.b[h++]=m[1]);g&&(b.b[h++]=c[d],b.b[h++]=c[d+1]);return h}function nm(b,c){b.L=[0,c,0];b.f.push(b.L);b.U=[0,c,0];b.a.push(b.U)} +function om(b,c,d,e,f,g,h,l,m){var n;n=b.qa;if(e[0]==n[0]&&e[1]==n[1]&&e[4]==n[4]&&e[5]==n[5]&&e[12]==n[12]&&e[13]==n[13])n=b.Qa;else{n=Eg(b.b,0,b.b.length,2,e,b.Qa);var p=b.qa;p[0]=e[0];p[1]=e[1];p[2]=e[2];p[3]=e[3];p[4]=e[4];p[5]=e[5];p[6]=e[6];p[7]=e[7];p[8]=e[8];p[9]=e[9];p[10]=e[10];p[11]=e[11];p[12]=e[12];p[13]=e[13];p[14]=e[14];p[15]=e[15]}e=!Da(g);var p=0,q=h.length,r=0,t;b=b.ra;for(var B,X,x,E;p<q;){var v=h[p],Ca,Fa,ja,P;switch(v[0]){case 0:r=v[1];e&&g[u(r).toString()]||!r.R()?p=v[2]:void 0=== +m||Hd(m,r.R().G())?++p:p=v[2];break;case 1:c.beginPath();++p;break;case 2:r=v[1];t=n[r];v=n[r+1];P=n[r+2]-t;r=n[r+3]-v;c.arc(t,v,Math.sqrt(P*P+r*r),0,2*Math.PI,!0);++p;break;case 3:c.closePath();++p;break;case 4:r=v[1];t=v[2];Ca=v[3];ja=v[4]*d;var Aa=v[5]*d,va=v[6];Fa=v[7];var kb=v[8],Xa=v[9];x=v[11];E=v[12];var cb=v[13],lb=v[14];for(v[10]&&(x+=f);r<t;r+=2){v=n[r]-ja;P=n[r+1]-Aa;cb&&(v=v+.5|0,P=P+.5|0);if(1!=E||0!==x){var ka=v+ja,za=P+Aa;mk(b,ka,za,E,E,x,-ka,-za);c.setTransform(b[0],b[1],b[4],b[5], +b[12],b[13])}ka=c.globalAlpha;1!=Fa&&(c.globalAlpha=ka*Fa);c.drawImage(Ca,kb,Xa,lb,va,v,P,lb*d,va*d);1!=Fa&&(c.globalAlpha=ka);1==E&&0===x||c.setTransform(1,0,0,1,0,0)}++p;break;case 5:r=v[1];t=v[2];ja=v[3];Aa=v[4]*d;va=v[5]*d;x=v[6];E=v[7]*d;Ca=v[8];for(Fa=v[9];r<t;r+=2){v=n[r]+Aa;P=n[r+1]+va;if(1!=E||0!==x)mk(b,v,P,E,E,x,-v,-P),c.setTransform(b[0],b[1],b[4],b[5],b[12],b[13]);Fa&&c.strokeText(ja,v,P);Ca&&c.fillText(ja,v,P);1==E&&0===x||c.setTransform(1,0,0,1,0,0)}++p;break;case 6:if(void 0!==l&& +(r=v[1],r=l(r)))return r;++p;break;case 7:c.fill();++p;break;case 8:r=v[1];t=v[2];v=n[r];P=n[r+1];x=v+.5|0;E=P+.5|0;if(x!==B||E!==X)c.moveTo(v,P),B=x,X=E;for(r+=2;r<t;r+=2)if(v=n[r],P=n[r+1],x=v+.5|0,E=P+.5|0,x!==B||E!==X)c.lineTo(v,P),B=x,X=E;++p;break;case 9:c.fillStyle=v[1];++p;break;case 10:B=void 0!==v[7]?v[7]:!0;X=v[2];c.strokeStyle=v[1];c.lineWidth=B?X*d:X;c.lineCap=v[3];c.lineJoin=v[4];c.miterLimit=v[5];$g&&c.setLineDash(v[6]);X=B=NaN;++p;break;case 11:c.font=v[1];c.textAlign=v[2];c.textBaseline= +v[3];++p;break;case 12:c.stroke();++p;break;default:++p}}}function pm(b){var c=b.a;c.reverse();var d,e=c.length,f,g,h=-1;for(d=0;d<e;++d)if(f=c[d],g=f[0],6==g)h=d;else if(0==g){f[2]=d;f=b.a;for(g=d;h<g;){var l=f[h];f[h]=f[g];f[g]=l;++h;--g}h=-1}}function qm(b,c){b.L[2]=b.f.length;b.L=null;b.U[2]=b.a.length;b.U=null;var d=[6,c];b.f.push(d);b.a.push(d)}lm.prototype.Zc=Id;lm.prototype.Gd=function(){return this.ea}; +function rm(b,c,d){lm.call(this,b,c,d);this.l=this.ca=null;this.I=this.J=this.fa=this.la=this.F=this.v=this.D=this.u=this.j=this.s=this.c=void 0}y(rm,lm);rm.prototype.Dd=function(b,c){if(this.l){nm(this,c);var d=b.ga(),e=b.pa(),f=this.b.length,d=mm(this,d,0,d.length,e,!1);this.f.push([4,f,d,this.l,this.c,this.s,this.j,this.u,this.D,this.v,this.F,this.la,this.fa,this.J,this.I]);this.a.push([4,f,d,this.ca,this.c,this.s,this.j,this.u,this.D,this.v,this.F,this.la,this.fa,this.J,this.I]);qm(this,c)}}; +rm.prototype.Bd=function(b,c){if(this.l){nm(this,c);var d=b.ga(),e=b.pa(),f=this.b.length,d=mm(this,d,0,d.length,e,!1);this.f.push([4,f,d,this.l,this.c,this.s,this.j,this.u,this.D,this.v,this.F,this.la,this.fa,this.J,this.I]);this.a.push([4,f,d,this.ca,this.c,this.s,this.j,this.u,this.D,this.v,this.F,this.la,this.fa,this.J,this.I]);qm(this,c)}};rm.prototype.Zc=function(){pm(this);this.s=this.c=void 0;this.l=this.ca=null;this.I=this.J=this.la=this.F=this.v=this.D=this.u=this.fa=this.j=void 0}; +rm.prototype.ue=function(b){var c=b.mb(),d=b.Ya(),e=b.le(1),f=b.ib(1),g=b.Aa();this.c=c[0];this.s=c[1];this.ca=e;this.l=f;this.j=d[1];this.u=b.u;this.D=g[0];this.v=g[1];this.F=b.F;this.la=b.D;this.fa=b.s;this.J=b.la;this.I=d[0]};function sm(b,c,d){lm.call(this,b,c,d);this.c={dc:void 0,Zb:void 0,$b:null,ac:void 0,bc:void 0,cc:void 0,Wd:0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}y(sm,lm); +function tm(b,c,d,e,f){var g=b.b.length;c=mm(b,c,d,e,f,!1);g=[8,g,c];b.f.push(g);b.a.push(g);return e}k=sm.prototype;k.Gd=function(){this.g||(this.g=md(this.ea),0<this.i&&ld(this.g,this.resolution*(this.i+1)/2,this.g));return this.g}; +function um(b){var c=b.c,d=c.strokeStyle,e=c.lineCap,f=c.lineDash,g=c.lineJoin,h=c.lineWidth,l=c.miterLimit;c.dc==d&&c.Zb==e&&sb(c.$b,f)&&c.ac==g&&c.bc==h&&c.cc==l||(c.Wd!=b.b.length&&(b.f.push([12]),c.Wd=b.b.length),b.f.push([10,d,h,e,g,l,f],[1]),c.dc=d,c.Zb=e,c.$b=f,c.ac=g,c.bc=h,c.cc=l)} +k.zd=function(b,c){var d=this.c,e=d.lineWidth;void 0!==d.strokeStyle&&void 0!==e&&(um(this),nm(this,c),this.a.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash],[1]),d=b.ga(),e=b.pa(),tm(this,d,0,d.length,e),this.a.push([12]),qm(this,c))}; +k.Ad=function(b,c){var d=this.c,e=d.lineWidth;if(void 0!==d.strokeStyle&&void 0!==e){um(this);nm(this,c);this.a.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash],[1]);var d=b.Ua(),e=b.ga(),f=b.pa(),g=0,h,l;h=0;for(l=d.length;h<l;++h)g=tm(this,e,g,d[h],f);this.a.push([12]);qm(this,c)}};k.Zc=function(){this.c.Wd!=this.b.length&&this.f.push([12]);pm(this);this.c=null}; +k.wb=function(b,c){var d=c.a;this.c.strokeStyle=Xg(d?d:ih);d=c.c;this.c.lineCap=void 0!==d?d:"round";d=c.b;this.c.lineDash=d?d:hh;d=c.g;this.c.lineJoin=void 0!==d?d:"round";d=c.f;this.c.lineWidth=void 0!==d?d:1;d=c.i;this.c.miterLimit=void 0!==d?d:10;this.c.lineWidth>this.i&&(this.i=this.c.lineWidth,this.g=null)}; +function vm(b,c,d){lm.call(this,b,c,d);this.c={Te:void 0,dc:void 0,Zb:void 0,$b:null,ac:void 0,bc:void 0,cc:void 0,fillStyle:void 0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}y(vm,lm); +function wm(b,c,d,e,f){var g=b.c,h=[1];b.f.push(h);b.a.push(h);var l,h=0;for(l=e.length;h<l;++h){var m=e[h],n=b.b.length;d=mm(b,c,d,m,f,!0);d=[8,n,d];n=[3];b.f.push(d,n);b.a.push(d,n);d=m}c=[7];b.a.push(c);void 0!==g.fillStyle&&b.f.push(c);void 0!==g.strokeStyle&&(g=[12],b.f.push(g),b.a.push(g));return d}k=vm.prototype; +k.yd=function(b,c){var d=this.c,e=d.strokeStyle;if(void 0!==d.fillStyle||void 0!==e){xm(this);nm(this,c);this.a.push([9,Xg(gh)]);void 0!==d.strokeStyle&&this.a.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash]);var f=b.ga(),g=b.pa(),e=this.b.length;mm(this,f,0,f.length,g,!1);f=[1];e=[2,e];this.f.push(f,e);this.a.push(f,e);e=[7];this.a.push(e);void 0!==d.fillStyle&&this.f.push(e);void 0!==d.strokeStyle&&(d=[12],this.f.push(d),this.a.push(d));qm(this,c)}}; +k.Ed=function(b,c){var d=this.c,e=d.strokeStyle;if(void 0!==d.fillStyle||void 0!==e){xm(this);nm(this,c);this.a.push([9,Xg(gh)]);void 0!==d.strokeStyle&&this.a.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash]);var d=b.Ua(),e=b.hb(),f=b.pa();wm(this,e,0,d,f);qm(this,c)}}; +k.Cd=function(b,c){var d=this.c,e=d.strokeStyle;if(void 0!==d.fillStyle||void 0!==e){xm(this);nm(this,c);this.a.push([9,Xg(gh)]);void 0!==d.strokeStyle&&this.a.push([10,d.strokeStyle,d.lineWidth,d.lineCap,d.lineJoin,d.miterLimit,d.lineDash]);var d=b.c,e=cm(b),f=b.pa(),g=0,h,l;h=0;for(l=d.length;h<l;++h)g=wm(this,e,g,d[h],f);qm(this,c)}};k.Zc=function(){pm(this);this.c=null;var b=this.ya;if(0!==b){var c=this.b,d,e;d=0;for(e=c.length;d<e;++d)c[d]=b*Math.round(c[d]/b)}}; +k.Gd=function(){this.g||(this.g=md(this.ea),0<this.i&&ld(this.g,this.resolution*(this.i+1)/2,this.g));return this.g}; +k.wb=function(b,c){var d=this.c;if(b){var e=b.a;d.fillStyle=Xg(e?e:gh)}else d.fillStyle=void 0;c?(e=c.a,d.strokeStyle=Xg(e?e:ih),e=c.c,d.lineCap=void 0!==e?e:"round",e=c.b,d.lineDash=e?e.slice():hh,e=c.g,d.lineJoin=void 0!==e?e:"round",e=c.f,d.lineWidth=void 0!==e?e:1,e=c.i,d.miterLimit=void 0!==e?e:10,d.lineWidth>this.i&&(this.i=d.lineWidth,this.g=null)):(d.strokeStyle=void 0,d.lineCap=void 0,d.lineDash=null,d.lineJoin=void 0,d.lineWidth=void 0,d.miterLimit=void 0)}; +function xm(b){var c=b.c,d=c.fillStyle,e=c.strokeStyle,f=c.lineCap,g=c.lineDash,h=c.lineJoin,l=c.lineWidth,m=c.miterLimit;void 0!==d&&c.Te!=d&&(b.f.push([9,d]),c.Te=c.fillStyle);void 0===e||c.dc==e&&c.Zb==f&&c.$b==g&&c.ac==h&&c.bc==l&&c.cc==m||(b.f.push([10,e,l,f,h,m,g]),c.dc=e,c.Zb=f,c.$b=g,c.ac=h,c.bc=l,c.cc=m)}function ym(b,c,d){lm.call(this,b,c,d);this.J=this.fa=this.la=null;this.l="";this.F=this.v=this.D=this.u=0;this.j=this.s=this.c=null}y(ym,lm); +function zm(b,c,d,e,f){if(""!==b.l&&b.j&&(b.c||b.s)){if(b.c){var g=b.c,h=b.la;if(!h||h.fillStyle!=g.fillStyle){var l=[9,g.fillStyle];b.f.push(l);b.a.push(l);h?h.fillStyle=g.fillStyle:b.la={fillStyle:g.fillStyle}}}b.s&&(g=b.s,h=b.fa,h&&h.lineCap==g.lineCap&&h.lineDash==g.lineDash&&h.lineJoin==g.lineJoin&&h.lineWidth==g.lineWidth&&h.miterLimit==g.miterLimit&&h.strokeStyle==g.strokeStyle||(l=[10,g.strokeStyle,g.lineWidth,g.lineCap,g.lineJoin,g.miterLimit,g.lineDash,!1],b.f.push(l),b.a.push(l),h?(h.lineCap= +g.lineCap,h.lineDash=g.lineDash,h.lineJoin=g.lineJoin,h.lineWidth=g.lineWidth,h.miterLimit=g.miterLimit,h.strokeStyle=g.strokeStyle):b.fa={lineCap:g.lineCap,lineDash:g.lineDash,lineJoin:g.lineJoin,lineWidth:g.lineWidth,miterLimit:g.miterLimit,strokeStyle:g.strokeStyle}));g=b.j;h=b.J;h&&h.font==g.font&&h.textAlign==g.textAlign&&h.textBaseline==g.textBaseline||(l=[11,g.font,g.textAlign,g.textBaseline],b.f.push(l),b.a.push(l),h?(h.font=g.font,h.textAlign=g.textAlign,h.textBaseline=g.textBaseline):b.J= +{font:g.font,textAlign:g.textAlign,textBaseline:g.textBaseline});nm(b,f);g=b.b.length;c=mm(b,c,0,d,e,!1);c=[5,g,c,b.l,b.u,b.D,b.v,b.F,!!b.c,!!b.s];b.f.push(c);b.a.push(c);qm(b,f)}} +ym.prototype.kb=function(b){if(b){var c=b.va();c?(c=c.a,c=Xg(c?c:gh),this.c?this.c.fillStyle=c:this.c={fillStyle:c}):this.c=null;var d=b.sa();if(d){var c=d.a,e=d.c,f=d.b,g=d.g,h=d.f,d=d.i,e=void 0!==e?e:"round",f=f?f.slice():hh,g=void 0!==g?g:"round",h=void 0!==h?h:1,d=void 0!==d?d:10,c=Xg(c?c:ih);if(this.s){var l=this.s;l.lineCap=e;l.lineDash=f;l.lineJoin=g;l.lineWidth=h;l.miterLimit=d;l.strokeStyle=c}else this.s={lineCap:e,lineDash:f,lineJoin:g,lineWidth:h,miterLimit:d,strokeStyle:c}}else this.s= +null;var m=b.f,c=b.b,e=b.c,f=b.s,h=b.g,d=b.na(),g=b.i,l=b.a;b=void 0!==m?m:"10px sans-serif";g=void 0!==g?g:"center";l=void 0!==l?l:"middle";this.j?(m=this.j,m.font=b,m.textAlign=g,m.textBaseline=l):this.j={font:b,textAlign:g,textBaseline:l};this.l=void 0!==d?d:"";this.u=void 0!==c?c:0;this.D=void 0!==e?e:0;this.v=void 0!==f?f:0;this.F=void 0!==h?h:1}else this.l=""};function Am(b,c,d,e){this.s=b;this.f=c;this.i=d;this.b=e;this.a={};this.c=of(1,1);this.g=Qc()} +function Bm(b){for(var c in b.a){var d=b.a[c],e;for(e in d)d[e].Zc()}}function Cm(b,c,d,e,f,g){var h=b.g;mk(h,.5,.5,1/d,-1/d,-e,-c[0],-c[1]);var l=b.c;l.clearRect(0,0,1,1);var m;void 0!==b.b&&(m=hd(),id(m,c),ld(m,d*b.b,m));return Dm(b,l,h,e,f,function(b){if(0<l.getImageData(0,0,1,1).data[3]){if(b=g(b))return b;l.clearRect(0,0,1,1)}},m)}function Em(b,c,d){var e=void 0!==c?c.toString():"0";c=b.a[e];void 0===c&&(c={},b.a[e]=c);e=c[d];void 0===e&&(e=new Fm[d](b.s,b.f,b.i),c[d]=e);return e} +Am.prototype.Pa=function(){return Da(this.a)};function Gm(b,c,d,e,f,g){var h=Object.keys(b.a).map(Number);pb(h);var l=b.f,m=l[0],n=l[1],p=l[2],l=l[3],m=[m,n,m,l,p,l,p,n];Eg(m,0,8,2,e,m);c.save();c.beginPath();c.moveTo(m[0],m[1]);c.lineTo(m[2],m[3]);c.lineTo(m[4],m[5]);c.lineTo(m[6],m[7]);c.closePath();c.clip();for(var q,r,m=0,n=h.length;m<n;++m)for(q=b.a[h[m].toString()],p=0,l=km.length;p<l;++p)r=q[km[p]],void 0!==r&&om(r,c,d,e,f,g,r.f,void 0);c.restore()} +function Dm(b,c,d,e,f,g,h){var l=Object.keys(b.a).map(Number);pb(l,function(b,c){return c-b});var m,n,p,q,r;m=0;for(n=l.length;m<n;++m)for(q=b.a[l[m].toString()],p=km.length-1;0<=p;--p)if(r=q[km[p]],void 0!==r&&(r=om(r,c,1,d,e,f,r.a,g,h)))return r}var Fm={Image:rm,LineString:sm,Polygon:vm,Text:ym};function Hm(b,c,d,e){this.b=b;this.a=c;this.g=d;this.c=e}k=Hm.prototype;k.get=function(b){return this.c[b]};k.Ua=function(){return this.g};k.G=function(){this.f||(this.f="Point"===this.b?sd(this.a):td(this.a,0,this.a.length,2));return this.f};k.ga=Hm.prototype.hb=function(){return this.a};k.R=function(){return this};k.S=function(){return this.c};k.gc=Hm.prototype.R;k.pa=Be(2);k.Lb=Id;k.N=function(){return this.b};function Im(b,c){return u(b)-u(c)}function Jm(b,c){var d=.5*b/c;return d*d}function Km(b,c,d,e,f,g){var h=!1,l,m;if(l=d.a)m=l.tc(),2==m||3==m?l.Ae(f,g):(0==m&&l.load(),l.Xd(f,g),h=!0);if(f=(0,d.f)(c))e=f.gc(e),(0,Lm[e.N()])(b,e,d,c);return h} +var Lm={Point:function(b,c,d,e){var f=d.a;if(f){if(2!=f.tc())return;var g=Em(b,d.ma(),"Image");g.ue(f);g.Dd(c,e)}if(f=d.na())b=Em(b,d.ma(),"Text"),b.kb(f),zm(b,c.ga(),2,2,e)},LineString:function(b,c,d,e){var f=d.sa();if(f){var g=Em(b,d.ma(),"LineString");g.wb(null,f);g.zd(c,e)}if(f=d.na())b=Em(b,d.ma(),"Text"),b.kb(f),zm(b,am(c),2,2,e)},Polygon:function(b,c,d,e){var f=d.va(),g=d.sa();if(f||g){var h=Em(b,d.ma(),"Polygon");h.wb(f,g);h.Ed(c,e)}if(f=d.na())b=Em(b,d.ma(),"Text"),b.kb(f),zm(b,ii(c),2,2, +e)},MultiPoint:function(b,c,d,e){var f=d.a;if(f){if(2!=f.tc())return;var g=Em(b,d.ma(),"Image");g.ue(f);g.Bd(c,e)}if(f=d.na())b=Em(b,d.ma(),"Text"),b.kb(f),d=c.ga(),zm(b,d,d.length,c.pa(),e)},MultiLineString:function(b,c,d,e){var f=d.sa();if(f){var g=Em(b,d.ma(),"LineString");g.wb(null,f);g.Ad(c,e)}if(f=d.na())b=Em(b,d.ma(),"Text"),b.kb(f),c=bm(c),zm(b,c,c.length,2,e)},MultiPolygon:function(b,c,d,e){var f=d.va(),g=d.sa();if(g||f){var h=Em(b,d.ma(),"Polygon");h.wb(f,g);h.Cd(c,e)}if(f=d.na())b=Em(b, +d.ma(),"Text"),b.kb(f),c=dm(c),zm(b,c,c.length,2,e)},GeometryCollection:function(b,c,d,e){c=c.a;var f,g;f=0;for(g=c.length;f<g;++f)(0,Lm[c[f].N()])(b,c[f],d,e)},Circle:function(b,c,d,e){var f=d.va(),g=d.sa();if(f||g){var h=Em(b,d.ma(),"Polygon");h.wb(f,g);h.yd(c,e)}if(f=d.na())b=Em(b,d.ma(),"Text"),b.kb(f),zm(b,c.lc(),2,2,e)}};function Mm(b,c,d,e,f,g){this.g=void 0!==g?g:null;kk.call(this,b,c,d,void 0!==g?0:2,e);this.f=f}y(Mm,kk);Mm.prototype.a=function(b){this.state=b?3:2;lk(this)};Mm.prototype.load=function(){0==this.state&&(this.state=1,lk(this),this.g(ra(this.a,this)))};Mm.prototype.c=function(){return this.f};function Nm(b,c,d,e,f,g){this.v=c;this.D=b.G();var h=c.G(),l=h?Gd(d,h):d,h=qf(b,c,Ed(l),e);this.l=new tf(b,c,l,this.D,.5*h);this.i=e;this.g=d;b=vf(this.l);this.u=(this.a=g(b,h,f))?this.a.b:1;this.f=this.j=null;f=2;g=[];this.a&&(f=0,g=this.a.s);kk.call(this,d,e,this.u,f,g)}y(Nm,kk);Nm.prototype.ba=function(){1==this.state&&(yc(this.f),this.f=null);Nm.ka.ba.call(this)};Nm.prototype.c=function(){return this.j}; +function Om(b){var c=b.a.state;2==c&&(b.j=sf(Bd(b.g)/b.i,Dd(b.g)/b.i,b.u,b.a.V(),0,b.i,b.g,b.l,[{extent:b.a.G(),image:b.a.c()}]));b.state=c;lk(b)}Nm.prototype.load=function(){if(0==this.state){this.state=1;lk(this);var b=this.a.state;2==b||3==b?Om(this):(this.f=this.a.Uc("change",function(){var b=this.a.state;if(2==b||3==b)yc(this.f),this.f=null,Om(this)},!1,this),this.a.load())}};function Pm(b){ne.call(this,{attributions:b.attributions,extent:b.extent,logo:b.logo,projection:b.projection,state:b.state});this.I=void 0!==b.resolutions?b.resolutions:null;this.a=null;this.qa=0}y(Pm,ne);function Qm(b,c){if(b.I){var d=Ef(b.I,c,0);c=b.I[d]}return c} +function Rm(b,c,d,e,f){var g=b.i;if(g&&f&&!ie(g,f)){if(b.a){if(b.qa==b.f&&ie(b.a.v,f)&&b.a.V()==d&&b.a.b==e&&vd(b.a.G(),c))return b.a;b.a.Fc();b.a=null}b.a=new Nm(g,f,c,d,e,ra(function(b,c,d){return this.Hd(b,c,d,g)},b));b.qa=b.f;return b.a}g&&(f=g);return b.Hd(c,d,e,f)}Pm.prototype.ya=function(b){b=b.target;switch(b.state){case 1:this.B(new Sm(Tm,b));break;case 2:this.B(new Sm(Um,b));break;case 3:this.B(new Sm(Vm,b))}};function Wm(b,c){b.c().src=c}function Sm(b,c){Xb.call(this,b);this.image=c} +y(Sm,Xb);var Tm="imageloadstart",Um="imageloadend",Vm="imageloaderror";function Xm(b){Pm.call(this,{attributions:b.attributions,logo:b.logo,projection:b.projection,resolutions:b.resolutions,state:void 0!==b.state?b.state:void 0});this.ca=b.canvasFunction;this.L=null;this.U=0;this.ea=void 0!==b.ratio?b.ratio:1.5}y(Xm,Pm); +Xm.prototype.Hd=function(b,c,d,e){c=Qm(this,c);var f=this.L;if(f&&this.U==this.f&&f.V()==c&&f.b==d&&qd(f.G(),b))return f;var g=b=b.slice(),h=this.ea,l=(g[2]-g[0])/2*(h-1),h=(g[3]-g[1])/2*(h-1);g[0]-=l;g[2]+=l;g[1]-=h;g[3]+=h;(e=this.ca(b,c,d,[Bd(b)/c*d,Dd(b)/c*d],e))&&(f=new Mm(b,c,d,this.j,e));this.L=f;this.U=this.f;return f};function Ym(b){Ic.call(this);this.g=void 0;this.a="geometry";this.c=null;this.i=void 0;this.b=null;z(this,Kc(this.a),this.Mc,!1,this);void 0!==b&&(b instanceof Dg||!b?this.Xa(b):this.M(b))}y(Ym,Ic);k=Ym.prototype;k.clone=function(){var b=new Ym(this.S());b.ld(this.a);var c=this.R();c&&b.Xa(c.clone());(c=this.c)&&b.be(c);return b};k.R=function(){return this.get(this.a)};k.Ja=function(){return this.g};k.qh=function(){return this.a};k.Oi=function(){return this.c};k.Lb=function(){return this.i}; +k.Pi=function(){this.A()};k.Mc=function(){this.b&&(yc(this.b),this.b=null);var b=this.R();b&&(this.b=z(b,"change",this.Pi,!1,this));this.A()};k.Xa=function(b){this.C(this.a,b)};k.be=function(b){this.i=(this.c=b)?Zm(b):void 0;this.A()};k.te=function(b){this.g=b;this.A()};k.ld=function(b){xc(this,Kc(this.a),this.Mc,!1,this);this.a=b;z(this,Kc(this.a),this.Mc,!1,this);this.Mc()};function Zm(b){if(!la(b)){var c;c=fa(b)?b:[b];b=function(){return c}}return b};function $m(b,c,d){if(la(b))d&&(b=ra(b,d));else if(b&&"function"==typeof b.handleEvent)b=ra(b.handleEvent,b);else throw Error("Invalid listener argument");return 2147483647<c?-1:ba.setTimeout(b,c||0)};var an=ba.JSON.parse,bn=ba.JSON.stringify;function cn(){}cn.prototype.a=null;function dn(b){var c;(c=b.a)||(c={},en(b)&&(c[0]=!0,c[1]=!0),c=b.a=c);return c};var gn;function hn(){}y(hn,cn);function jn(b){return(b=en(b))?new ActiveXObject(b):new XMLHttpRequest}function en(b){if(!b.f&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var c=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],d=0;d<c.length;d++){var e=c[d];try{return new ActiveXObject(e),b.f=e}catch(f){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return b.f}gn=new hn;function kn(b){Cc.call(this);this.L=new Ui;this.l=b||null;this.a=!1;this.j=this.aa=null;this.g=this.U=this.v="";this.f=this.D=this.c=this.u=!1;this.s=0;this.b=null;this.i=ln;this.F=this.ea=!1}y(kn,Cc);var ln="",mn=/^https?$/i,nn=["POST","PUT"]; +function on(b,c){if(b.aa)throw Error("[goog.net.XhrIo] Object is active with another request="+b.v+"; newUri="+c);b.v=c;b.g="";b.U="GET";b.u=!1;b.a=!0;b.aa=b.l?jn(b.l):jn(gn);b.j=b.l?dn(b.l):dn(gn);b.aa.onreadystatechange=ra(b.J,b);try{b.D=!0,b.aa.open("GET",String(c),!0),b.D=!1}catch(g){pn(b,g);return}var d=b.L.clone(),e=fb(d.P()),f=ba.FormData&&!1;!(0<=bb(nn,"GET"))||e||f||Vi(d,"Content-Type","application/x-www-form-urlencoded;charset=utf-8");d.forEach(function(b,c){this.aa.setRequestHeader(c,b)}, +b);b.i&&(b.aa.responseType=b.i);"withCredentials"in b.aa&&(b.aa.withCredentials=b.ea);try{qn(b),0<b.s&&(b.F=rn(b.aa),b.F?(b.aa.timeout=b.s,b.aa.ontimeout=ra(b.I,b)):b.b=$m(b.I,b.s,b)),b.c=!0,b.aa.send(""),b.c=!1}catch(g){pn(b,g)}}function rn(b){return Ab&&Mb(9)&&ia(b.timeout)&&ca(b.ontimeout)}function gb(b){return"content-type"==b.toLowerCase()} +kn.prototype.I=function(){"undefined"!=typeof aa&&this.aa&&(this.g="Timed out after "+this.s+"ms, aborting",this.B("timeout"),this.aa&&this.a&&(this.a=!1,this.f=!0,this.aa.abort(),this.f=!1,this.B("complete"),this.B("abort"),sn(this)))};function pn(b,c){b.a=!1;b.aa&&(b.f=!0,b.aa.abort(),b.f=!1);b.g=c;tn(b);sn(b)}function tn(b){b.u||(b.u=!0,b.B("complete"),b.B("error"))}kn.prototype.ba=function(){this.aa&&(this.a&&(this.a=!1,this.f=!0,this.aa.abort(),this.f=!1),sn(this,!0));kn.ka.ba.call(this)}; +kn.prototype.J=function(){this.fa||(this.D||this.c||this.f?un(this):this.ca())};kn.prototype.ca=function(){un(this)};function un(b){if(b.a&&"undefined"!=typeof aa&&(!b.j[1]||4!=vn(b)||2!=wn(b)))if(b.c&&4==vn(b))$m(b.J,0,b);else if(b.B("readystatechange"),4==vn(b)){b.a=!1;try{if(xn(b))b.B("complete"),b.B("success");else{var c;try{c=2<vn(b)?b.aa.statusText:""}catch(d){c=""}b.g=c+" ["+wn(b)+"]";tn(b)}}finally{sn(b)}}} +function sn(b,c){if(b.aa){qn(b);var d=b.aa,e=b.j[0]?da:null;b.aa=null;b.j=null;c||b.B("ready");try{d.onreadystatechange=e}catch(f){}}}function qn(b){b.aa&&b.F&&(b.aa.ontimeout=null);ia(b.b)&&(ba.clearTimeout(b.b),b.b=null)} +function xn(b){var c=wn(b),d;a:switch(c){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:d=!0;break a;default:d=!1}if(!d){if(c=0===c)b=String(b.v).match(Xf)[1]||null,!b&&ba.self&&ba.self.location&&(b=ba.self.location.protocol,b=b.substr(0,b.length-1)),c=!mn.test(b?b.toLowerCase():"");d=c}return d}function vn(b){return b.aa?b.aa.readyState:0}function wn(b){try{return 2<vn(b)?b.aa.status:-1}catch(c){return-1}}function yn(b){try{return b.aa?b.aa.responseText:""}catch(c){return""}} +function zn(b){try{if(!b.aa)return null;if("response"in b.aa)return b.aa.response;switch(b.i){case ln:case "text":return b.aa.responseText;case "arraybuffer":if("mozResponseArrayBuffer"in b.aa)return b.aa.mozResponseArrayBuffer}return null}catch(c){return null}};function An(){if(!Ab)return!1;try{return new ActiveXObject("MSXML2.DOMDocument"),!0}catch(b){return!1}}var Bn=Ab&&An();function Cn(b){var c=b.xml;if(c)return c;if("undefined"!=typeof XMLSerializer)return(new XMLSerializer).serializeToString(b);throw Error("Your browser does not support serializing XML documents");};var Dn;a:if(document.implementation&&document.implementation.createDocument)Dn=document.implementation.createDocument("","",null);else{if(Bn){var En=new ActiveXObject("MSXML2.DOMDocument");if(En){En.resolveExternals=!1;En.validateOnParse=!1;try{En.setProperty("ProhibitDTD",!0),En.setProperty("MaxXMLSize",2048),En.setProperty("MaxElementDepth",256)}catch(b){}}if(En){Dn=En;break a}}throw Error("Your browser does not support creating new documents");}var Fn=Dn; +function Gn(b,c){return Fn.createElementNS(b,c)}function Hn(b,c){b||(b="");return Fn.createNode(1,c,b)}var In=document.implementation&&document.implementation.createDocument?Gn:Hn;function Jn(b){return Kn(b,!1,[]).join("")}function Kn(b,c,d){if(4==b.nodeType||3==b.nodeType)c?d.push(String(b.nodeValue).replace(/(\r\n|\r|\n)/g,"")):d.push(b.nodeValue);else for(b=b.firstChild;b;b=b.nextSibling)Kn(b,c,d);return d}function Ln(b){return b.localName} +function Mn(b){var c=b.localName;return void 0!==c?c:b.baseName}var Nn=Ab?Mn:Ln;function On(b){return b instanceof Document}function Pn(b){return ma(b)&&9==b.nodeType}var Qn=Ab?Pn:On;function Rn(b){return b instanceof Node}function Sn(b){return ma(b)&&void 0!==b.nodeType}var Tn=Ab?Sn:Rn;function Un(b,c,d,e){b.setAttributeNS(c,d,e)}function Vn(b,c,d,e){c?(c=b.ownerDocument.createNode(2,d,c),c.nodeValue=e,b.setAttributeNode(c)):b.setAttribute(d,e)} +var Wn=document.implementation&&document.implementation.createDocument?Un:Vn;function Xn(b){return(new DOMParser).parseFromString(b,"application/xml")}function Yn(b,c){return function(d,e){var f=b.call(c,d,e);void 0!==f&&mb(e[e.length-1],f)}}function Zn(b,c){return function(d,e){var f=b.call(void 0!==c?c:this,d,e);void 0!==f&&e[e.length-1].push(f)}}function $n(b){return function(c,d){var e=b.call(this,c,d);void 0!==e&&(d[d.length-1]=e)}} +function ao(b){return function(c,d){var e=b.call(this,c,d);void 0!==e&&Ha(d[d.length-1],c.localName).push(e)}}function O(b,c){return function(d,e){var f=b.call(this,d,e);void 0!==f&&(e[e.length-1][void 0!==c?c:d.localName]=f)}}function bo(b){return function(c,d,e){b.call(this,c,d,e);e[e.length-1].node.appendChild(c)}}function co(b){return function(c,d,e){c=d[d.length-1].node;d=b;void 0===d&&(d=e);e=void 0;e=c.namespaceURI;return In(e,d)}}var eo=co(); +function fo(b,c){for(var d=c.length,e=Array(d),f=0;f<d;++f)e[f]=b[c[f]];return e}function Q(b,c,d){d=void 0!==d?d:{};var e,f;e=0;for(f=b.length;e<f;++e)d[b[e]]=c;return d}function go(b,c,d,e){for(c=c.firstElementChild;c;c=c.nextElementSibling){var f=b[c.namespaceURI];void 0!==f&&(f=f[c.localName],void 0!==f&&f.call(e,c,d))}}function ho(b,c,d,e,f){e.push(b);go(c,d,e,f);return e.pop()} +function io(b,c,d,e,f,g,h){f.push(b);b=(void 0!==g?g:e).length;for(var l,m,n=0;n<b;++n)l=e[n],void 0!==l&&(m=d.call(h,l,f,void 0!==g?g[n]:void 0),void 0!==m&&c[m.namespaceURI][m.localName].call(h,m,l,f));f.pop()};function jo(b,c,d){return function(e,f,g){var h=new kn;h.i="arraybuffer"==c.N()?"arraybuffer":"text";z(h,"complete",function(b){b=b.target;if(xn(b)){var e=c.N(),f;if("json"==e)f=yn(b);else if("text"==e)f=yn(b);else if("xml"==e){if(!Ab)try{f=b.aa?b.aa.responseXML:null}catch(h){f=null}f||(f=Xn(yn(b)))}else"arraybuffer"==e&&(f=zn(b));f&&(e=c.jd(f,{featureProjection:g}),2==d.length?d.call(this,e,c.vc(f)):d.call(this,e))}Wb(b)},!1,this);la(b)?on(h,b(e,f,g)):on(h,b)}} +function ko(b,c){return jo(b,c,function(b){this.rd(b)})};function lo(){return[[-Infinity,-Infinity,Infinity,Infinity]]};var mo; +(function(){var b={Ve:{}};(function(){function c(b,d){if(!(this instanceof c))return new c(b,d);this.qd=Math.max(4,b||9);this.Je=Math.max(2,Math.ceil(.4*this.qd));d&&this.xg(d);this.clear()}function d(b,c){b.bbox=e(b,0,b.children.length,c)}function e(b,c,d,e){for(var g=[Infinity,Infinity,-Infinity,-Infinity],h;c<d;c++)h=b.children[c],f(g,b.za?e(h):h.bbox);return g}function f(b,c){b[0]=Math.min(b[0],c[0]);b[1]=Math.min(b[1],c[1]);b[2]=Math.max(b[2],c[2]);b[3]=Math.max(b[3],c[3])}function g(b,c){return b.bbox[0]- +c.bbox[0]}function h(b,c){return b.bbox[1]-c.bbox[1]}function l(b){return(b[2]-b[0])*(b[3]-b[1])}function m(b){return b[2]-b[0]+(b[3]-b[1])}function n(b,c){return b[0]<=c[0]&&b[1]<=c[1]&&c[2]<=b[2]&&c[3]<=b[3]}function p(b,c){return c[0]<=b[2]&&c[1]<=b[3]&&c[2]>=b[0]&&c[3]>=b[1]}function q(b,c,d,e,f){for(var g=[c,d],h;g.length;)d=g.pop(),c=g.pop(),d-c<=e||(h=c+Math.ceil((d-c)/e/2)*e,r(b,c,d,h,f),g.push(c,h,h,d))}function r(b,c,d,e,f){for(var g,h,l,m,n;d>c;){600<d-c&&(g=d-c+1,h=e-c+1,l=Math.log(g), +m=.5*Math.exp(2*l/3),n=.5*Math.sqrt(l*m*(g-m)/g)*(0>h-g/2?-1:1),l=Math.max(c,Math.floor(e-h*m/g+n)),h=Math.min(d,Math.floor(e+(g-h)*m/g+n)),r(b,l,h,e,f));g=b[e];h=c;m=d;t(b,c,e);for(0<f(b[d],g)&&t(b,c,d);h<m;){t(b,h,m);h++;for(m--;0>f(b[h],g);)h++;for(;0<f(b[m],g);)m--}0===f(b[c],g)?t(b,c,m):(m++,t(b,m,d));m<=e&&(c=m+1);e<=m&&(d=m-1)}}function t(b,c,d){var e=b[c];b[c]=b[d];b[d]=e}c.prototype={all:function(){return this.Fe(this.data,[])},search:function(b){var c=this.data,d=[],e=this.Da;if(!p(b,c.bbox))return d; +for(var f=[],g,h,l,m;c;){g=0;for(h=c.children.length;g<h;g++)l=c.children[g],m=c.za?e(l):l.bbox,p(b,m)&&(c.za?d.push(l):n(b,m)?this.Fe(l,d):f.push(l));c=f.pop()}return d},load:function(b){if(!b||!b.length)return this;if(b.length<this.Je){for(var c=0,d=b.length;c<d;c++)this.oa(b[c]);return this}b=this.He(b.slice(),0,b.length-1,0);this.data.children.length?this.data.height===b.height?this.Ke(this.data,b):(this.data.height<b.height&&(c=this.data,this.data=b,b=c),this.Ie(b,this.data.height-b.height-1, +!0)):this.data=b;return this},oa:function(b){b&&this.Ie(b,this.data.height-1);return this},clear:function(){this.data={children:[],height:1,bbox:[Infinity,Infinity,-Infinity,-Infinity],za:!0};return this},remove:function(b){if(!b)return this;for(var c=this.data,d=this.Da(b),e=[],f=[],g,h,l,m;c||e.length;){c||(c=e.pop(),h=e[e.length-1],g=f.pop(),m=!0);if(c.za&&(l=c.children.indexOf(b),-1!==l)){c.children.splice(l,1);e.push(c);this.wg(e);break}m||c.za||!n(c.bbox,d)?h?(g++,c=h.children[g],m=!1):c=null: +(e.push(c),f.push(g),g=0,h=c,c=c.children[0])}return this},Da:function(b){return b},ud:function(b,c){return b[0]-c[0]},vd:function(b,c){return b[1]-c[1]},toJSON:function(){return this.data},Fe:function(b,c){for(var d=[];b;)b.za?c.push.apply(c,b.children):d.push.apply(d,b.children),b=d.pop();return c},He:function(b,c,e,f){var g=e-c+1,h=this.qd,l;if(g<=h)return l={children:b.slice(c,e+1),height:1,bbox:null,za:!0},d(l,this.Da),l;f||(f=Math.ceil(Math.log(g)/Math.log(h)),h=Math.ceil(g/Math.pow(h,f-1))); +l={children:[],height:f,bbox:null};var g=Math.ceil(g/h),h=g*Math.ceil(Math.sqrt(h)),m,n,p;for(q(b,c,e,h,this.ud);c<=e;c+=h)for(n=Math.min(c+h-1,e),q(b,c,n,g,this.vd),m=c;m<=n;m+=g)p=Math.min(m+g-1,n),l.children.push(this.He(b,m,p,f-1));d(l,this.Da);return l},vg:function(b,c,d,e){for(var f,g,h,m,n,p,q,r;;){e.push(c);if(c.za||e.length-1===d)break;q=r=Infinity;f=0;for(g=c.children.length;f<g;f++)h=c.children[f],n=l(h.bbox),p=h.bbox,p=(Math.max(p[2],b[2])-Math.min(p[0],b[0]))*(Math.max(p[3],b[3])-Math.min(p[1], +b[1]))-n,p<r?(r=p,q=n<q?n:q,m=h):p===r&&n<q&&(q=n,m=h);c=m}return c},Ie:function(b,c,d){var e=this.Da;d=d?b.bbox:e(b);var e=[],g=this.vg(d,this.data,c,e);g.children.push(b);for(f(g.bbox,d);0<=c;)if(e[c].children.length>this.qd)this.yg(e,c),c--;else break;this.sg(d,e,c)},yg:function(b,c){var e=b[c],f=e.children.length,g=this.Je;this.tg(e,g,f);f=this.ug(e,g,f);f={children:e.children.splice(f,e.children.length-f),height:e.height};e.za&&(f.za=!0);d(e,this.Da);d(f,this.Da);c?b[c-1].children.push(f):this.Ke(e, +f)},Ke:function(b,c){this.data={children:[b,c],height:b.height+1};d(this.data,this.Da)},ug:function(b,c,d){var f,g,h,m,n,p,q;n=p=Infinity;for(f=c;f<=d-c;f++)g=e(b,0,f,this.Da),h=e(b,f,d,this.Da),m=Math.max(0,Math.min(g[2],h[2])-Math.max(g[0],h[0]))*Math.max(0,Math.min(g[3],h[3])-Math.max(g[1],h[1])),g=l(g)+l(h),m<n?(n=m,q=f,p=g<p?g:p):m===n&&g<p&&(p=g,q=f);return q},tg:function(b,c,d){var e=b.za?this.ud:g,f=b.za?this.vd:h,l=this.Ge(b,c,d,e);c=this.Ge(b,c,d,f);l<c&&b.children.sort(e)},Ge:function(b, +c,d,g){b.children.sort(g);g=this.Da;var h=e(b,0,c,g),l=e(b,d-c,d,g),n=m(h)+m(l),p,q;for(p=c;p<d-c;p++)q=b.children[p],f(h,b.za?g(q):q.bbox),n+=m(h);for(p=d-c-1;p>=c;p--)q=b.children[p],f(l,b.za?g(q):q.bbox),n+=m(l);return n},sg:function(b,c,d){for(;0<=d;d--)f(c[d].bbox,b)},wg:function(b){for(var c=b.length-1,e;0<=c;c--)0===b[c].children.length?0<c?(e=b[c-1].children,e.splice(e.indexOf(b[c]),1)):this.clear():d(b[c],this.Da)},xg:function(b){var c=["return a"," - b",";"];this.ud=new Function("a","b", +c.join(b[0]));this.vd=new Function("a","b",c.join(b[1]));this.Da=new Function("a","return [a"+b.join(", a")+"];")}};"undefined"!==typeof b?b.Ve=c:"undefined"!==typeof self?self.a=c:window.a=c})();mo=b.Ve})();function no(b){this.f=mo(b);this.a={}}k=no.prototype;k.oa=function(b,c){var d=[b[0],b[1],b[2],b[3],c];this.f.oa(d);this.a[u(c)]=d};k.load=function(b,c){for(var d=Array(c.length),e=0,f=c.length;e<f;e++){var g=b[e],h=c[e],g=[g[0],g[1],g[2],g[3],h];d[e]=g;this.a[u(h)]=g}this.f.load(d)};k.remove=function(b){b=u(b);var c=this.a[b];delete this.a[b];return null!==this.f.remove(c)};k.update=function(b,c){var d=u(c);vd(this.a[d].slice(0,4),b)||(this.remove(c),this.oa(b,c))}; +function oo(b){return b.f.all().map(function(b){return b[4]})}function po(b,c){return b.f.search(c).map(function(b){return b[4]})}k.forEach=function(b,c){return qo(oo(this),b,c)};function ro(b,c,d,e){return qo(po(b,c),d,e)}function qo(b,c,d){for(var e,f=0,g=b.length;f<g&&!(e=c.call(d,b[f]));f++);return e}k.Pa=function(){return Da(this.a)};k.clear=function(){this.f.clear();this.a={}};k.G=function(){return this.f.data.bbox};function K(b){b=b||{};ne.call(this,{attributions:b.attributions,logo:b.logo,projection:void 0,state:"ready",wrapX:void 0!==b.wrapX?b.wrapX:!0});this.v=Id;void 0!==b.loader?this.v=b.loader:void 0!==b.url&&(this.v=ko(b.url,b.format));this.L=void 0!==b.strategy?b.strategy:lo;var c=void 0!==b.useSpatialIndex?b.useSpatialIndex:!0;this.a=c?new no:null;this.I=new no;this.c={};this.g={};this.l={};this.u={};this.b=null;var d,e;b.features instanceof A?(d=b.features,e=d.a):fa(b.features)&&(e=b.features);c|| +void 0!==d||(d=new A(e));void 0!==e&&so(this,e);void 0!==d&&to(this,d)}y(K,ne);k=K.prototype;k.bd=function(b){var c=u(b).toString();if(uo(this,c,b)){vo(this,c,b);var d=b.R();d?(c=d.G(),this.a&&this.a.oa(c,b)):this.c[c]=b;this.B(new wo("addfeature",b))}this.A()};function vo(b,c,d){b.u[c]=[z(d,"change",b.Kf,!1,b),z(d,"propertychange",b.Kf,!1,b)]}function uo(b,c,d){var e=!0,f=d.Ja();void 0!==f?f.toString()in b.g?e=!1:b.g[f.toString()]=d:b.l[c]=d;return e}k.rd=function(b){so(this,b);this.A()}; +function so(b,c){var d,e,f,g,h=[],l=[],m=[];e=0;for(f=c.length;e<f;e++)g=c[e],d=u(g).toString(),uo(b,d,g)&&l.push(g);e=0;for(f=l.length;e<f;e++){g=l[e];d=u(g).toString();vo(b,d,g);var n=g.R();n?(d=n.G(),h.push(d),m.push(g)):b.c[d]=g}b.a&&b.a.load(h,m);e=0;for(f=l.length;e<f;e++)b.B(new wo("addfeature",l[e]))} +function to(b,c){var d=!1;z(b,"addfeature",function(b){d||(d=!0,c.push(b.feature),d=!1)});z(b,"removefeature",function(b){d||(d=!0,c.remove(b.feature),d=!1)});z(c,"add",function(b){d||(b=b.element,d=!0,this.bd(b),d=!1)},!1,b);z(c,"remove",function(b){d||(b=b.element,d=!0,this.sc(b),d=!1)},!1,b);b.b=c} +k.clear=function(b){if(b){for(var c in this.u)this.u[c].forEach(yc);this.b||(this.u={},this.g={},this.l={})}else b=this.Vf,this.a&&(this.a.forEach(b,this),ua(this.c,b,this));this.b&&this.b.clear();this.a&&this.a.clear();this.I.clear();this.c={};this.B(new wo("clear"));this.A()};k.Pg=function(b,c){if(this.a)return this.a.forEach(b,c);if(this.b)return this.b.forEach(b,c)};function xo(b,c,d){b.Fb([c[0],c[1],c[0],c[1]],function(b){if(b.R().Qe(c))return d.call(void 0,b)})} +k.Fb=function(b,c,d){if(this.a)return ro(this.a,b,c,d);if(this.b)return this.b.forEach(c,d)};k.Rg=function(b,c,d){return this.Fb(b,function(e){if(e.R().ta(b)&&(e=c.call(d,e)))return e})};k.lh=function(){return this.b};k.ke=function(){var b;this.b?b=this.b.a:this.a&&(b=oo(this.a),Da(this.c)||mb(b,ya(this.c)));return b};k.kh=function(b){var c=[];xo(this,b,function(b){c.push(b)});return c};k.mh=function(b){return po(this.a,b)}; +k.bh=function(b){var c=b[0],d=b[1],e=null,f=[NaN,NaN],g=Infinity,h=[-Infinity,-Infinity,Infinity,Infinity];ro(this.a,h,function(b){var m=b.R(),n=g;g=m.Ia(c,d,f,g);g<n&&(e=b,b=Math.sqrt(g),h[0]=c-b,h[1]=d-b,h[2]=c+b,h[3]=d+b)});return e};k.G=function(){return this.a.G()};k.jh=function(b){b=this.g[b.toString()];return void 0!==b?b:null}; +k.Kf=function(b){b=b.target;var c=u(b).toString(),d=b.R();d?(d=d.G(),c in this.c?(delete this.c[c],this.a&&this.a.oa(d,b)):this.a&&this.a.update(d,b)):c in this.c||(this.a&&this.a.remove(b),this.c[c]=b);d=b.Ja();void 0!==d?(d=d.toString(),c in this.l?(delete this.l[c],this.g[d]=b):this.g[d]!==b&&(yo(this,b),this.g[d]=b)):c in this.l||(yo(this,b),this.l[c]=b);this.A();this.B(new wo("changefeature",b))};k.Pa=function(){return this.a.Pa()&&Da(this.c)}; +function zo(b,c,d,e){var f=b.I;c=b.L(c,d);var g,h;g=0;for(h=c.length;g<h;++g){var l=c[g];ro(f,l,function(b){return qd(b.extent,l)})||(b.v.call(b,l,d,e),f.oa(l,{extent:l.slice()}))}}k.sc=function(b){var c=u(b).toString();c in this.c?delete this.c[c]:this.a&&this.a.remove(b);this.Vf(b);this.A()};k.Vf=function(b){var c=u(b).toString();this.u[c].forEach(yc);delete this.u[c];var d=b.Ja();void 0!==d?delete this.g[d.toString()]:delete this.l[c];this.B(new wo("removefeature",b))}; +function yo(b,c){for(var d in b.g)if(b.g[d]===c){delete b.g[d];break}}function wo(b,c){Xb.call(this,b);this.feature=c}y(wo,Xb);function Qg(b){this.b=b.source;this.ra=Qc();this.c=of();this.l=[0,0];this.u=null;Xm.call(this,{attributions:b.attributions,canvasFunction:ra(this.Kg,this),logo:b.logo,projection:b.projection,ratio:b.ratio,resolutions:b.resolutions,state:this.b.D});this.v=null;this.g=void 0;this.Gf(b.style);z(this.b,"change",this.Nj,void 0,this)}y(Qg,Xm);k=Qg.prototype; +k.Kg=function(b,c,d,e,f){var g=new Am(.5*c/d,b,c);zo(this.b,b,c,f);var h=!1;this.b.Fb(b,function(b){var e;if(!(e=h)){var f;(e=b.Lb())?f=e.call(b,c):this.g&&(f=this.g(b,c));if(f){var p,q=!1;e=0;for(p=f.length;e<p;++e)q=Km(g,b,f[e],Jm(c,d),this.Mj,this)||q;e=q}else e=!1}h=e},this);Bm(g);if(h)return null;this.l[0]!=e[0]||this.l[1]!=e[1]?(this.c.canvas.width=e[0],this.c.canvas.height=e[1],this.l[0]=e[0],this.l[1]=e[1]):this.c.clearRect(0,0,e[0],e[1]);b=Ao(this,Ed(b),c,d,e);Gm(g,this.c,d,b,0,{});this.u= +g;return this.c.canvas};k.Hf=function(b,c,d,e,f){if(this.u){var g={};return Cm(this.u,b,c,0,e,function(b){var c=u(b).toString();if(!(c in g))return g[c]=!0,f(b)})}};k.Jj=function(){return this.b};k.Kj=function(){return this.v};k.Lj=function(){return this.g};function Ao(b,c,d,e,f){return mk(b.ra,f[0]/2,f[1]/2,e/d,-e/d,0,-c[0],-c[1])}k.Mj=function(){this.A()};k.Nj=function(){this.D=this.b.D;this.A()};k.Gf=function(b){this.v=void 0!==b?b:uh;this.g=b?sh(this.v):void 0;this.A()};function Fk(b){fm.call(this,b);this.g=null;this.i=Qc();this.b=this.c=null}y(Fk,fm);k=Fk.prototype;k.rc=function(b,c,d,e){var f=this.a;return f.da().Hf(b,c.viewState.resolution,c.viewState.rotation,c.skippedFeatureUids,function(b){return d.call(e,b,f)})}; +k.ie=function(b,c,d,e){if(this.$c())if(this.a.da()instanceof Qg){if(b=b.slice(),nk(c.pixelToCoordinateMatrix,b,b),this.rc(b,c,De,this))return d.call(e,this.a)}else if(this.c||(this.c=Qc(),Rc(this.i,this.c)),c=im(b,this.c),this.b||(this.b=of(1,1)),this.b.clearRect(0,0,1,1),this.b.drawImage(this.$c(),c[0],c[1],1,1,0,0,1,1),0<this.b.getImageData(0,0,1,1).data[3])return d.call(e,this.a)};k.$c=function(){return this.g?this.g.c():null};k.$e=function(){return this.i}; +k.je=function(b,c){var d=b.pixelRatio,e=b.viewState,f=e.center,g=e.resolution,h=e.rotation,l=this.a.da(),m=b.viewHints,n=b.extent;void 0!==c.extent&&(n=Gd(n,c.extent));if(!m[0]&&!m[1]&&!Ad(n)){if(m=e=Rm(l,n,g,d,e.projection))m=e,n=m.state,2!=n&&3!=n&&z(m,"change",this.I,!1,this),0==n&&(m.load(),n=m.state),m=2==n;m&&(this.g=e)}if(this.g){var e=this.g,m=e.G(),n=e.V(),p=e.b,g=d*n/(g*p);mk(this.i,d*b.size[0]/2,d*b.size[1]/2,g,g,h,p*(m[0]-f[0])/n,p*(f[1]-m[3])/n);this.c=null;sk(b.attributions,e.s);tk(b, +l)}return!0};function Gk(b){fm.call(this,b);this.b=this.i=null;this.l=!1;this.s=null;this.u=Qc();this.g=null;this.F=this.J=this.v=NaN;this.j=this.c=null;this.U=[0,0]}y(Gk,fm);Gk.prototype.$c=function(){return this.i};Gk.prototype.$e=function(){return this.u}; +Gk.prototype.je=function(b,c){function d(b){b=b.state;return 2==b||4==b||3==b&&!kb}var e=b.pixelRatio,f=b.viewState,g=f.projection,h=this.a,l=h.da(),m=l.Wa(g),n=l.Ze(),p=xf(m,f.resolution),q=l.Lc(p,b.pixelRatio,g),r=q[0]/fd(m.La(p),this.U)[0],t=m.V(p),r=t/r,B=f.center,X;t==f.resolution?(B=vk(B,t,b.size),X=Fd(B,t,f.rotation,b.size)):X=b.extent;void 0!==c.extent&&(X=Gd(X,c.extent));if(Ad(X))return!1;var x=Kf(m,X,t),E=q[0]*(x.f-x.a+1),v=q[1]*Sd(x),Ca,Fa;this.i?(Ca=this.i,Fa=this.s,this.b[0]<E||this.b[1]< +v||this.J!==q[0]||this.F!==q[1]||this.l&&(this.b[0]>E||this.b[1]>v)?(Ca.width=E,Ca.height=v,this.b=[E,v],this.l=!jm(this.b),this.c=null):(E=this.b[0],v=this.b[1],p==this.v&&Rd(this.c,x)||(this.c=null))):(Fa=of(E,v),this.i=Fa.canvas,this.b=[E,v],this.s=Fa,this.l=!jm(this.b));var ja,P;this.c?(v=this.c,E=v.f-v.a+1):(E/=q[0],v/=q[1],ja=x.a-Math.floor((E-(x.f-x.a+1))/2),P=x.c-Math.floor((v-Sd(x))/2),this.v=p,this.J=q[0],this.F=q[1],this.c=new Pd(ja,ja+E-1,P,P+v-1),this.j=Array(E*v),v=this.c);Ca={};Ca[p]= +{};var Aa=[],va=pk(l,g,Ca),kb=h.i(),Xa=hd(),cb=new Pd(0,0,0,0),lb,ka,za;for(P=x.a;P<=x.f;++P)for(za=x.c;za<=x.b;++za)ka=Vf(l,p,P,za,e,g),!d(ka)&&ka.f&&(ka=ka.f),d(ka)?Ca[p][Od(ka.a)]=ka:(lb=If(m,ka.a,va,cb,Xa),lb||(Aa.push(ka),(lb=Jf(m,ka.a,cb,Xa))&&va(p+1,lb)));va=0;for(lb=Aa.length;va<lb;++va)ka=Aa[va],P=q[0]*(ka.a[1]-v.a),za=q[1]*(v.b-ka.a[2]),Fa.clearRect(P,za,q[0],q[1]);Aa=Object.keys(Ca).map(Number);pb(Aa);var fn=l.ya,pg=yd(m.Ka([p,v.a,v.b],Xa)),ad,qg,Yb,ef,Cd,Yi,va=0;for(lb=Aa.length;va<lb;++va)if(ad= +Aa[va],q=l.Lc(ad,e,g),ef=Ca[ad],ad==p)for(qg in ef)ka=ef[qg],ja=(ka.a[2]-v.c)*E+(ka.a[1]-v.a),this.j[ja]!=ka&&(P=q[0]*(ka.a[1]-v.a),za=q[1]*(v.b-ka.a[2]),Yb=ka.state,4!=Yb&&(3!=Yb||kb)&&fn||Fa.clearRect(P,za,q[0],q[1]),2==Yb&&Fa.drawImage(ka.Mb(),n,n,q[0],q[1],P,za,q[0],q[1]),this.j[ja]=ka);else for(qg in ad=m.V(ad)/t,ef)for(ka=ef[qg],ja=m.Ka(ka.a,Xa),P=(ja[0]-pg[0])/r,za=(pg[1]-ja[3])/r,Yi=ad*q[0],Cd=ad*q[1],Yb=ka.state,4!=Yb&&fn||Fa.clearRect(P,za,Yi,Cd),2==Yb&&Fa.drawImage(ka.Mb(),n,n,q[0],q[1], +P,za,Yi,Cd),ka=m.fb(ja,p,cb),ja=Math.max(ka.a,v.a),za=Math.min(ka.f,v.f),P=Math.max(ka.c,v.c),ka=Math.min(ka.b,v.b),Yb=ja;Yb<=za;++Yb)for(Cd=P;Cd<=ka;++Cd)ja=(Cd-v.c)*E+(Yb-v.a),this.j[ja]=void 0;uk(b.usedTiles,l,p,x);wk(b,l,m,e,g,X,p,h.a());rk(b,l);tk(b,l);mk(this.u,e*b.size[0]/2,e*b.size[1]/2,e*r/f.resolution,e*r/f.resolution,f.rotation,(pg[0]-B[0])/r,(B[1]-pg[1])/r);this.g=null;return!0}; +Gk.prototype.ie=function(b,c,d,e){if(this.s&&(this.g||(this.g=Qc(),Rc(this.u,this.g)),b=im(b,this.g),0<this.s.getImageData(b[0],b[1],1,1).data[3]))return d.call(e,this.a)};function Hk(b){fm.call(this,b);this.c=!1;this.l=-1;this.j=NaN;this.i=hd();this.b=this.s=null;this.g=of()}y(Hk,fm); +Hk.prototype.D=function(b,c,d){var e=b.extent,f=b.pixelRatio,g=c.kc?b.skippedFeatureUids:{},h=b.viewState,l=h.projection,h=h.rotation,m=l.G(),n=this.a.da(),p=hm(this,b,0);gm(this,"precompose",d,b,p);var q=this.b;if(q&&!q.Pa()){var r;Ec(this.a,"render")?(this.g.canvas.width=d.canvas.width,this.g.canvas.height=d.canvas.height,r=this.g):r=d;var t=r.globalAlpha;r.globalAlpha=c.opacity;Gm(q,r,f,p,h,g);if(n.F&&l.f&&!qd(m,e)){c=e[0];l=Bd(m);for(n=0;c<m[0];)--n,p=l*n,p=hm(this,b,p),Gm(q,r,f,p,h,g),c+=l;n= +0;for(c=e[2];c>m[2];)++n,p=l*n,p=hm(this,b,p),Gm(q,r,f,p,h,g),c-=l;p=hm(this,b,0)}r!=d&&(gm(this,"render",r,b,p),d.drawImage(r.canvas,0,0));r.globalAlpha=t}gm(this,"postcompose",d,b,p)};Hk.prototype.rc=function(b,c,d,e){if(this.b){var f=c.viewState.resolution,g=c.viewState.rotation,h=this.a,l=c.layerStates[u(h)],m={};return Cm(this.b,b,f,g,l.kc?c.skippedFeatureUids:{},function(b){var c=u(b).toString();if(!(c in m))return m[c]=!0,d.call(e,b,h)})}};Hk.prototype.u=function(){qk(this)}; +Hk.prototype.je=function(b){function c(b){var c,e=b.Lb();e?c=e.call(b,n):(e=d.a)&&(c=e(b,n));if(c){if(c){e=!1;if(fa(c))for(var f=0,g=c.length;f<g;++f)e=Km(r,b,c[f],Jm(n,p),this.u,this)||e;else e=Km(r,b,c,Jm(n,p),this.u,this)||e;b=e}else b=!1;this.c=this.c||b}}var d=this.a,e=d.da();sk(b.attributions,e.j);tk(b,e);var f=b.viewHints[0],g=b.viewHints[1],h=d.F,l=d.J;if(!this.c&&!h&&f||!l&&g)return!0;var m=b.extent,l=b.viewState,f=l.projection,n=l.resolution,p=b.pixelRatio,g=d.f,q=d.j,h=d.get("renderOrder"); +void 0===h&&(h=Im);m=ld(m,q*n);q=l.projection.G();e.F&&l.projection.f&&!qd(q,b.extent)&&(b=Math.max(Bd(m)/2,Bd(q)),m[0]=q[0]-b,m[2]=q[2]+b);if(!this.c&&this.j==n&&this.l==g&&this.s==h&&qd(this.i,m))return!0;Wb(this.b);this.b=null;this.c=!1;var r=new Am(.5*n/p,m,n,d.j);zo(e,m,n,f);if(h){var t=[];e.Fb(m,function(b){t.push(b)},this);pb(t,h);t.forEach(c,this)}else e.Fb(m,c,this);Bm(r);this.j=n;this.l=g;this.s=h;this.i=m;this.b=r;return!0};function Bo(b,c){Bk.call(this,0,c);this.g=of();this.a=this.g.canvas;this.a.style.width="100%";this.a.style.height="100%";this.a.className="ol-unselectable";b.insertBefore(this.a,b.childNodes[0]||null);this.b=!0;this.j=Qc()}y(Bo,Bk); +function Co(b,c,d){var e=b.H,f=b.g;if(Ec(e,c)){var g=d.extent,h=d.pixelRatio,l=d.viewState.rotation,m=d.pixelRatio,n=d.viewState,p=n.resolution;b=mk(b.j,b.a.width/2,b.a.height/2,m/p,-m/p,-n.rotation,-n.center[0],-n.center[1]);g=new Tl(f,h,g,b,l);e.B(new Le(c,e,g,d,f,null));em(g)}}Bo.prototype.N=function(){return"canvas"}; +Bo.prototype.i=function(b){if(b){var c=this.g,d=b.size[0]*b.pixelRatio,e=b.size[1]*b.pixelRatio;this.a.width!=d||this.a.height!=e?(this.a.width=d,this.a.height=e):c.clearRect(0,0,this.a.width,this.a.height);d=b.viewState;e=b.coordinateToPixelMatrix;mk(e,b.size[0]/2,b.size[1]/2,1/d.resolution,-1/d.resolution,-d.rotation,-d.center[0],-d.center[1]);Rc(e,b.pixelToCoordinateMatrix);Co(this,"precompose",b);d=b.layerStatesArray;rb(d,Ik);var e=b.viewState.resolution,f,g,h,l;f=0;for(g=d.length;f<g;++f)l=d[f], +h=l.layer,h=Ek(this,h),l.visible&&e>=l.minResolution&&e<l.maxResolution&&"ready"==l.v&&h.je(b,l)&&h.D(b,l,c);Co(this,"postcompose",b);this.b||(Ci(this.a,!0),this.b=!0);for(var m in this.f)if(!(m in b.layerStates)){b.postRenderFunctions.push(ra(this.l,this));break}b.postRenderFunctions.push(Ck)}else this.b&&(Ci(this.a,!1),this.b=!1)};var Do=["canvas","webgl","dom"]; +function R(b){Ic.call(this);var c=Eo(b);this.Cb=void 0!==b.loadTilesWhileAnimating?b.loadTilesWhileAnimating:!1;this.Db=void 0!==b.loadTilesWhileInteracting?b.loadTilesWhileInteracting:!1;this.od=void 0!==b.pixelRatio?b.pixelRatio:Zg;this.Vb=c.logos;this.u=new Ge(this.Wk,void 0,this);Vb(this,this.u);this.lb=Qc();this.pd=Qc();this.Bb=0;this.b=null;this.ya=hd();this.v=this.L=null;this.a=gf("DIV","ol-viewport");this.a.style.position="relative";this.a.style.overflow="hidden";this.a.style.width="100%"; +this.a.style.height="100%";this.a.style.msTouchAction="none";this.a.style.touchAction="none";dh&&ti(this.a,"ol-touch");this.J=gf("DIV","ol-overlaycontainer");this.a.appendChild(this.J);this.F=gf("DIV","ol-overlaycontainer-stopevent");z(this.F,["click","dblclick","mousedown","touchstart","MSPointerDown",gk,Cb?"DOMMouseScroll":"mousewheel"],Zb);this.a.appendChild(this.F);b=new Yj(this);z(b,ya(jk),this.kf,!1,this);Vb(this,b);this.qa=c.keyboardEventTarget;this.D=new ej;z(this.D,"key",this.jf,!1,this); +Vb(this,this.D);b=new mj(this.a);z(b,"mousewheel",this.jf,!1,this);Vb(this,b);this.g=c.controls;this.c=c.interactions;this.i=c.overlays;this.ca={};this.j=new c.Yk(this.a,this);Vb(this,this.j);this.$a=new $i;Vb(this,this.$a);this.U=this.l=null;this.I=[];this.ra=[];this.Ea=new Lk(ra(this.Nh,this),ra(this.mi,this));this.ea={};z(this,Kc("layergroup"),this.Xh,!1,this);z(this,Kc("view"),this.ni,!1,this);z(this,Kc("size"),this.ji,!1,this);z(this,Kc("target"),this.li,!1,this);this.M(c.values);this.g.forEach(function(b){b.setMap(this)}, +this);z(this.g,"add",function(b){b.element.setMap(this)},!1,this);z(this.g,"remove",function(b){b.element.setMap(null)},!1,this);this.c.forEach(function(b){b.setMap(this)},this);z(this.c,"add",function(b){b.element.setMap(this)},!1,this);z(this.c,"remove",function(b){b.element.setMap(null)},!1,this);this.i.forEach(this.Me,this);z(this.i,"add",function(b){this.Me(b.element)},!1,this);z(this.i,"remove",function(b){var c=b.element.Ja();void 0!==c&&delete this.ca[c.toString()];b.element.setMap(null)}, +!1,this)}y(R,Ic);k=R.prototype;k.zg=function(b){this.g.push(b)};k.Ag=function(b){this.c.push(b)};k.Bg=function(b){this.Oa().Na().push(b)};k.Cg=function(b){this.i.push(b)};k.Me=function(b){var c=b.Ja();void 0!==c&&(this.ca[c.toString()]=b);b.setMap(this)};k.Fa=function(b){this.render();Array.prototype.push.apply(this.I,arguments)};k.ba=function(){lf(this.a);R.ka.ba.call(this)}; +k.Fd=function(b,c,d,e,f){if(this.b)return b=this.ua(b),Dk(this.j,b,this.b,c,void 0!==d?d:null,void 0!==e?e:De,void 0!==f?f:null)};k.Yi=function(b,c,d,e,f){if(this.b){a:{var g=this.j,h=this.b;d=void 0!==d?d:null;e=void 0!==e?e:De;f=void 0!==f?f:null;var l,m=h.viewState.resolution,n=h.layerStatesArray,p;for(p=n.length-1;0<=p;--p){l=n[p];var q=l.layer;if(l.visible&&m>=l.minResolution&&m<l.maxResolution&&e.call(f,q)&&(l=Ek(g,q).ie(b,h,c,d))){b=l;break a}}b=void 0}return b}}; +k.ri=function(b,c,d){if(!this.b)return!1;b=this.ua(b);var e=this.j;return void 0!==Dk(e,b,this.b,De,e,void 0!==c?c:De,void 0!==d?d:null)};k.ih=function(b){return this.ua(this.Gc(b))};k.Gc=function(b){var c;c=this.a;b=zi(b);c=zi(c);c=new We(b.x-c.x,b.y-c.y);return[c.x,c.y]};k.wf=function(){return this.get("target")};k.hc=function(){var b=this.wf();return void 0!==b?af(b):null};k.ua=function(b){var c=this.b;return c?(b=b.slice(),nk(c.pixelToCoordinateMatrix,b,b)):null};k.eh=function(){return this.g}; +k.Fh=function(){return this.i};k.Eh=function(b){b=this.ca[b.toString()];return void 0!==b?b:null};k.sh=function(){return this.c};k.Oa=function(){return this.get("layergroup")};k.Zi=function(){return this.Oa().Na()};k.Ga=function(b){var c=this.b;return c?(b=b.slice(0,2),nk(c.coordinateToPixelMatrix,b,b)):null};k.rb=function(){return this.get("size")};k.ja=function(){return this.get("view")};k.Rh=function(){return this.a}; +k.Nh=function(b,c,d,e){var f=this.b;if(!(f&&c in f.wantedTiles&&f.wantedTiles[c][Od(b.a)]))return Infinity;b=d[0]-f.focus[0];d=d[1]-f.focus[1];return 65536*Math.log(e)+Math.sqrt(b*b+d*d)/e};k.jf=function(b,c){var d=new Wj(c||b.type,this,b);this.kf(d)};k.kf=function(b){if(this.b){this.U=b.coordinate;b.frameState=this.b;var c=this.c.a,d;if(!1!==this.B(b))for(d=c.length-1;0<=d;d--){var e=c[d];if(e.j()&&!e.handleEvent(b))break}}}; +k.ii=function(){var b=this.b,c=this.Ea;if(!c.Pa()){var d=16,e=d,f=0;b&&(f=b.viewHints,f[0]&&(d=this.Cb?8:0,e=2),f[1]&&(d=this.Db?8:0,e=2),f=xa(b.wantedTiles));d*=f;e*=f;if(c.c<d){var f=c.s,g=c.a,h=c.f,l=0,m=g.length,n,p,q;for(p=0;p<m;++p)n=g[p],q=f(n),Infinity==q?delete c.b[c.g(n)]:(h[l]=q,g[l++]=n);g.length=l;h.length=l;for(f=(c.a.length>>1)-1;0<=f;f--)Kk(c,f);for(f=0;c.c<d&&f<e&&0<c.fc();)g=c,l=g.a,m=g.f,h=l[0],1==l.length?(l.length=0,m.length=0):(l[0]=l.pop(),m[0]=m.pop(),Kk(g,0)),l=g.g(h),delete g.b[l], +g=h[0],0===g.state&&(z(g,"change",c.i,!1,c),g.load(),++c.c,++f)}}c=this.ra;e=0;for(d=c.length;e<d;++e)c[e](this,b);c.length=0};k.ji=function(){this.render()};k.li=function(){var b=this.hc();lj(this.D);b?(b.appendChild(this.a),fj(this.D,this.qa?this.qa:b),this.l||(this.l=z(this.$a,"resize",this.Be,!1,this))):(lf(this.a),this.l&&(yc(this.l),this.l=null));this.Be()};k.mi=function(){this.render()};k.pi=function(){this.render()}; +k.ni=function(){this.L&&(yc(this.L),this.L=null);var b=this.ja();b&&(this.L=z(b,"propertychange",this.pi,!1,this));this.render()};k.Yh=function(){this.render()};k.Zh=function(){this.render()};k.Xh=function(){this.v&&(this.v.forEach(yc),this.v=null);var b=this.Oa();b&&(this.v=[z(b,"propertychange",this.Zh,!1,this),z(b,"change",this.Yh,!1,this)]);this.render()};k.Xk=function(){var b=this.u;He(b);b.g()};k.render=function(){null!=this.u.a||this.u.start()};k.Rk=function(b){return this.g.remove(b)}; +k.Sk=function(b){return this.c.remove(b)};k.Uk=function(b){return this.Oa().Na().remove(b)};k.Vk=function(b){return this.i.remove(b)}; +k.Wk=function(b){var c,d,e,f=this.rb(),g=this.ja(),h=null;if(c=void 0!==f&&0<f[0]&&0<f[1]&&g)c=!!g.wa()&&void 0!==g.V();if(c){var h=g.b.slice(),l=this.Oa().Id(),m={};c=0;for(d=l.length;c<d;++c)m[u(l[c].layer)]=l[c];e=ji(g);h={animate:!1,attributions:{},coordinateToPixelMatrix:this.lb,extent:null,focus:this.U?this.U:e.center,index:this.Bb++,layerStates:m,layerStatesArray:l,logos:Ia(this.Vb),pixelRatio:this.od,pixelToCoordinateMatrix:this.pd,postRenderFunctions:[],size:f,skippedFeatureUids:this.ea, +tileQueue:this.Ea,time:b,usedTiles:{},viewState:e,viewHints:h,wantedTiles:{}}}if(h){b=this.I;c=f=0;for(d=b.length;c<d;++c)g=b[c],g(this,h)&&(b[f++]=g);b.length=f;h.extent=Fd(e.center,e.resolution,e.rotation,h.size)}this.b=h;this.j.i(h);h&&(h.animate&&this.render(),Array.prototype.push.apply(this.ra,h.postRenderFunctions),0!==this.I.length||h.viewHints[0]||h.viewHints[1]||vd(h.extent,this.ya)||(this.B(new Hi("moveend",this,h)),md(h.extent,this.ya)));this.B(new Hi("postrender",this,h));c=e=this.ii; +this&&(c=ra(e,this));!la(ba.setImmediate)||ba.Window&&ba.Window.prototype&&ba.Window.prototype.setImmediate==ba.setImmediate?(Si||(Si=Ti()),Si(c)):ba.setImmediate(c)};k.il=function(b){this.C("layergroup",b)};k.we=function(b){this.C("size",b)};k.$i=function(b){this.C("target",b)};k.aj=function(b){this.C("view",b)};k.jg=function(b){b=u(b).toString();this.ea[b]=!0;this.render()}; +k.Be=function(){var b=this.hc();if(b){var c=$e(b),d=Ab&&b.currentStyle,e;if(e=d)Ye(c),e=!0;if(e&&"auto"!=d.width&&"auto"!=d.height&&!d.boxSizing)c=Di(b,d.width,"width","pixelWidth"),b=Di(b,d.height,"height","pixelHeight"),b=new Xe(c,b);else{d=new Xe(b.offsetWidth,b.offsetHeight);if(Ab){c=Ei(b,"paddingLeft");e=Ei(b,"paddingRight");var f=Ei(b,"paddingTop"),g=Ei(b,"paddingBottom"),c=new vi(f,e,g,c)}else c=wi(b,"paddingLeft"),e=wi(b,"paddingRight"),f=wi(b,"paddingTop"),g=wi(b,"paddingBottom"),c=new vi(parseFloat(f), +parseFloat(e),parseFloat(g),parseFloat(c));!Ab||9<=Ob?(e=wi(b,"borderLeftWidth"),f=wi(b,"borderRightWidth"),g=wi(b,"borderTopWidth"),b=wi(b,"borderBottomWidth"),b=new vi(parseFloat(g),parseFloat(f),parseFloat(b),parseFloat(e))):(e=Gi(b,"borderLeft"),f=Gi(b,"borderRight"),g=Gi(b,"borderTop"),b=Gi(b,"borderBottom"),b=new vi(g,f,b,e));b=new Xe(d.width-b.left-c.left-c.right-b.right,d.height-b.top-c.top-c.bottom-b.bottom)}this.we([b.width,b.height])}else this.we(void 0)}; +k.kg=function(b){b=u(b).toString();delete this.ea[b];this.render()}; +function Eo(b){var c=null;void 0!==b.keyboardEventTarget&&(c=ha(b.keyboardEventTarget)?document.getElementById(b.keyboardEventTarget):b.keyboardEventTarget);var d={},e={};if(void 0===b.logo||"boolean"==typeof b.logo&&b.logo)e["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszWWMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvYasvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvXH1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1VkbMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLPVcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqTacrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaarldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+HizeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDnBAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSFhYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJREFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxCBrb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7ahgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCnB3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDgq82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC"]="http://openlayers.org/"; +else{var f=b.logo;ha(f)?e[f]="":ma(f)&&(e[f.src]=f.href)}f=b.layers instanceof C?b.layers:new C({layers:b.layers});d.layergroup=f;d.target=b.target;d.view=void 0!==b.view?b.view:new N;var f=Bk,g;void 0!==b.renderer?fa(b.renderer)?g=b.renderer:ha(b.renderer)&&(g=[b.renderer]):g=Do;var h,l;h=0;for(l=g.length;h<l;++h)if("canvas"==g[h]&&ah){f=Bo;break}var m;void 0!==b.controls?m=fa(b.controls)?new A(b.controls.slice()):b.controls:m=Oi();var n;void 0!==b.interactions?n=fa(b.interactions)?new A(b.interactions.slice()): +b.interactions:n=Il();b=void 0!==b.overlays?fa(b.overlays)?new A(b.overlays.slice()):b.overlays:new A;return{controls:m,interactions:n,keyboardEventTarget:c,logos:e,overlays:b,Yk:f,values:d}}$d(Nl);$d(Sl);Sl.forEach(function(b){Nl.forEach(function(c){ae(b,c,Ol);ae(c,b,Pl)})});function Fo(b){Ic.call(this);this.l=b.id;this.j=void 0!==b.insertFirst?b.insertFirst:!0;this.u=void 0!==b.stopEvent?b.stopEvent:!0;this.b=gf("DIV",{"class":"ol-overlay-container"});this.b.style.position="absolute";this.autoPan=void 0!==b.autoPan?b.autoPan:!1;this.g=void 0!==b.autoPanAnimation?b.autoPanAnimation:{};this.i=void 0!==b.autoPanMargin?b.autoPanMargin:20;this.a={Bc:"",Tc:"",kd:"",nd:"",visible:!0};this.c=null;z(this,Kc("element"),this.Vh,!1,this);z(this,Kc("map"),this.ci,!1,this);z(this, +Kc("offset"),this.ei,!1,this);z(this,Kc("position"),this.gi,!1,this);z(this,Kc("positioning"),this.hi,!1,this);void 0!==b.element&&this.$f(b.element);this.cg(void 0!==b.offset?b.offset:[0,0]);this.fg(void 0!==b.positioning?b.positioning:"top-left");void 0!==b.position&&this.yf(b.position)}y(Fo,Ic);k=Fo.prototype;k.ce=function(){return this.get("element")};k.Ja=function(){return this.l};k.Yc=function(){return this.get("map")};k.ff=function(){return this.get("offset")};k.xf=function(){return this.get("position")}; +k.gf=function(){return this.get("positioning")};k.Vh=function(){for(var b=this.b,c;c=b.firstChild;)b.removeChild(c);(b=this.ce())&&kf(this.b,b)};k.ci=function(){this.c&&(lf(this.b),yc(this.c),this.c=null);var b=this.Yc();b&&(this.c=z(b,"postrender",this.render,!1,this),Go(this),b=this.u?b.F:b.J,this.j?b.insertBefore(this.b,b.childNodes[0]||null):kf(b,this.b))};k.render=function(){Go(this)};k.ei=function(){Go(this)}; +k.gi=function(){Go(this);if(void 0!==this.get("position")&&this.autoPan){var b=this.Yc();if(void 0!==b&&b.hc()){var c=Ho(b.hc(),b.rb()),d=this.ce(),e=d.offsetWidth,f=d.currentStyle||window.getComputedStyle(d),e=e+(parseInt(f.marginLeft,10)+parseInt(f.marginRight,10)),f=d.offsetHeight,g=d.currentStyle||window.getComputedStyle(d),f=f+(parseInt(g.marginTop,10)+parseInt(g.marginBottom,10)),h=Ho(d,[e,f]),d=this.i;qd(c,h)||(e=h[0]-c[0],f=c[2]-h[2],g=h[1]-c[1],h=c[3]-h[3],c=[0,0],0>e?c[0]=e-d:0>f&&(c[0]= +Math.abs(f)+d),0>g?c[1]=g-d:0>h&&(c[1]=Math.abs(h)+d),0===c[0]&&0===c[1])||(d=b.ja().wa(),e=b.Ga(d),c=[e[0]+c[0],e[1]+c[1]],this.g&&(this.g.source=d,b.Fa(oi(this.g))),b.ja().Ca(b.ua(c)))}}};k.hi=function(){Go(this)};k.$f=function(b){this.C("element",b)};k.setMap=function(b){this.C("map",b)};k.cg=function(b){this.C("offset",b)};k.yf=function(b){this.C("position",b)}; +function Ho(b,c){var d=$e(b),e=new We(0,0),f;f=d?$e(d):document;var g;(g=!Ab||9<=Ob)||(Ye(f),g=!0);b!=(g?f.documentElement:f.body)&&(f=yi(b),g=Ye(d).a,d=g.scrollingElement?g.scrollingElement:Db?g.body||g.documentElement:g.documentElement,g=g.parentWindow||g.defaultView,d=Ab&&Mb("10")&&g.pageYOffset!=d.scrollTop?new We(d.scrollLeft,d.scrollTop):new We(g.pageXOffset||d.scrollLeft,g.pageYOffset||d.scrollTop),e.x=f.left+d.x,e.y=f.top+d.y);return[e.x,e.y,e.x+c[0],e.y+c[1]]} +k.fg=function(b){this.C("positioning",b)};function Io(b,c){b.a.visible!==c&&(Ci(b.b,c),b.a.visible=c)} +function Go(b){var c=b.Yc(),d=b.xf();if(void 0!==c&&c.b&&void 0!==d){var d=c.Ga(d),e=c.rb(),c=b.b.style,f=b.ff(),g=b.gf(),h=f[0],f=f[1];if("bottom-right"==g||"center-right"==g||"top-right"==g)""!==b.a.Tc&&(b.a.Tc=c.left=""),h=Math.round(e[0]-d[0]-h)+"px",b.a.kd!=h&&(b.a.kd=c.right=h);else{""!==b.a.kd&&(b.a.kd=c.right="");if("bottom-center"==g||"center-center"==g||"top-center"==g)h-=Ai(b.b).width/2;h=Math.round(d[0]+h)+"px";b.a.Tc!=h&&(b.a.Tc=c.left=h)}if("bottom-left"==g||"bottom-center"==g||"bottom-right"== +g)""!==b.a.nd&&(b.a.nd=c.top=""),d=Math.round(e[1]-d[1]-f)+"px",b.a.Bc!=d&&(b.a.Bc=c.bottom=d);else{""!==b.a.Bc&&(b.a.Bc=c.bottom="");if("center-left"==g||"center-center"==g||"center-right"==g)f-=Ai(b.b).height/2;d=Math.round(d[1]+f)+"px";b.a.nd!=d&&(b.a.nd=c.top=d)}Io(b,!0)}else Io(b,!1)};function Jo(b){b=b?b:{};var c=b.className?b.className:"ol-scale-line";this.i=gf("DIV",c+"-inner");this.c=gf("DIV",c+" ol-unselectable",this.i);this.l=null;this.j=void 0!==b.minWidth?b.minWidth:64;this.a=!1;this.F=void 0;this.D="";this.b=null;Ii.call(this,{element:this.c,render:b.render?b.render:Ko,target:b.target});z(this,Kc("units"),this.U,!1,this);this.L(b.units||"metric")}y(Jo,Ii);var Lo=[1,2,5];Jo.prototype.v=function(){return this.get("units")}; +function Ko(b){(b=b.frameState)?this.l=b.viewState:this.l=null;Mo(this)}Jo.prototype.U=function(){Mo(this)};Jo.prototype.L=function(b){this.C("units",b)}; +function Mo(b){var c=b.l;if(c){var d=c.center,e=c.projection,c=e.getPointResolution(c.resolution,d),f=e.b,g=b.v();"degrees"!=f||"metric"!=g&&"imperial"!=g&&"us"!=g&&"nautical"!=g?"degrees"!=f&&"degrees"==g?(b.b||(b.b=ce(e,Zd("EPSG:4326"))),d=Math.cos(Md(b.b(d)[1])),e=Vd.radius,e/=Wd[f],c*=180/(Math.PI*d*e)):b.b=null:(b.b=null,d=Math.cos(Md(d[1])),c*=Math.PI*d*Vd.radius/180);d=b.j*c;f="";"degrees"==g?d<1/60?(f="\u2033",c*=3600):1>d?(f="\u2032",c*=60):f="\u00b0":"imperial"==g?.9144>d?(f="in",c/=.0254): +1609.344>d?(f="ft",c/=.3048):(f="mi",c/=1609.344):"nautical"==g?(c/=1852,f="nm"):"metric"==g?1>d?(f="mm",c*=1E3):1E3>d?f="m":(f="km",c/=1E3):"us"==g&&(.9144>d?(f="in",c*=39.37):1609.344>d?(f="ft",c/=.30480061):(f="mi",c/=1609.3472));for(d=3*Math.floor(Math.log(b.j*c)/Math.log(10));;){e=Lo[d%3]*Math.pow(10,Math.floor(d/3));g=Math.round(e/c);if(isNaN(g)){Ci(b.c,!1);b.a=!1;return}if(g>=b.j)break;++d}c=e+" "+f;b.D!=c&&(b.i.innerHTML=c,b.D=c);b.F!=g&&(b.i.style.width=g+"px",b.F=g);b.a||(Ci(b.c,!0),b.a= +!0)}else b.a&&(Ci(b.c,!1),b.a=!1)};function No(b){b=b?b:{};this.a=b.extent?b.extent:null;var c=b.className?b.className:"ol-zoom-extent",d=gf("BUTTON",{type:"button",title:b.tipLabel?b.tipLabel:"Fit to extent"},b.label?b.label:"E");z(d,"click",this.b,!1,this);c=gf("DIV",c+" ol-unselectable ol-control",d);Ii.call(this,{element:c,target:b.target})}y(No,Ii);No.prototype.b=function(b){b.preventDefault();var c=this.H;b=c.ja();var d=this.a?this.a:b.a.G(),c=c.rb();b.We(d,c)};function Oo(b){Ic.call(this);b=b?b:{};this.a=null;z(this,Kc("tracking"),this.Ni,!1,this);this.ae(void 0!==b.tracking?b.tracking:!1)}y(Oo,Ic);k=Oo.prototype;k.ba=function(){this.ae(!1);Oo.ka.ba.call(this)}; +k.Ck=function(b){b=b.a;if(null!==b.alpha){var c=Md(b.alpha);this.C("alpha",c);"boolean"==typeof b.absolute&&b.absolute?this.C("heading",c):ia(b.webkitCompassHeading)&&-1!=b.webkitCompassAccuracy&&this.C("heading",Md(b.webkitCompassHeading))}null!==b.beta&&this.C("beta",Md(b.beta));null!==b.gamma&&this.C("gamma",Md(b.gamma));this.A()};k.Wg=function(){return this.get("alpha")};k.Zg=function(){return this.get("beta")};k.oh=function(){return this.get("gamma")};k.Mi=function(){return this.get("heading")}; +k.sf=function(){return this.get("tracking")};k.Ni=function(){if(bh){var b=this.sf();b&&!this.a?this.a=z(ba,"deviceorientation",this.Ck,!1,this):!b&&this.a&&(yc(this.a),this.a=null)}};k.ae=function(b){this.C("tracking",b)};function Po(){this.defaultDataProjection=null}function Qo(b,c,d){var e;d&&(e={dataProjection:d.dataProjection?d.dataProjection:b.vc(c),featureProjection:d.featureProjection});return Ro(b,e)}function Ro(b,c){var d;c&&(d={featureProjection:c.featureProjection,dataProjection:c.dataProjection?c.dataProjection:b.defaultDataProjection,rightHanded:c.rightHanded});return d} +function So(b,c,d){var e=d?Zd(d.featureProjection):null;d=d?Zd(d.dataProjection):null;return e&&d&&!ie(e,d)?b instanceof Dg?(c?b.clone():b).transform(c?e:d,c?d:e):me(c?b.slice():b,c?e:d,c?d:e):b};function To(){this.defaultDataProjection=null}y(To,Po);function Uo(b){return ma(b)?b:ha(b)?(b=an(b))?b:null:null}k=To.prototype;k.N=function(){return"json"};k.oe=function(b,c){return Vo(this,Uo(b),Qo(this,b,c))};k.jd=function(b,c){var d;var e=Uo(b);d=Qo(this,b,c);if("Feature"==e.type)d=[Vo(this,e,d)];else if("FeatureCollection"==e.type){var f=[],e=e.features,g,h;g=0;for(h=e.length;g<h;++g)f.push(Vo(this,e[g],d));d=f}else d=[];return d};k.Tf=function(b,c){var d=Uo(b),e=Qo(this,b,c);return Wo(d,e)}; +k.vc=function(b){return(b=Uo(b).crs)?"name"==b.type?Zd(b.properties.name):"EPSG"==b.type?Zd("EPSG:"+b.properties.code):null:this.defaultDataProjection};k.pg=function(b,c){return bn(this.a(b,c))};k.Ce=function(b,c){return bn(this.b(b,c))};k.qg=function(b,c){return bn(this.c(b,c))};function Xo(b,c,d,e,f){var g=NaN,h=NaN,l=(d-c)/e;if(0!==l)if(1==l)g=b[c],h=b[c+1];else if(2==l)g=.5*b[c]+.5*b[c+e],h=.5*b[c+1]+.5*b[c+e+1];else{var h=b[c],l=b[c+1],m=0,g=[0],n;for(n=c+e;n<d;n+=e){var p=b[n],q=b[n+1],m=m+Math.sqrt((p-h)*(p-h)+(q-l)*(q-l));g.push(m);h=p;l=q}d=.5*m;for(var r,h=qb,l=0,m=g.length;l<m;)n=l+m>>1,p=h(d,g[n]),0<p?l=n+1:(m=n,r=!p);r=r?l:~l;0>r?(d=(d-g[-r-2])/(g[-r-1]-g[-r-2]),c+=(-r-2)*e,g=Uc(b[c],b[c+e],d),h=Uc(b[c+1],b[c+e+1],d)):(g=b[c+r*e],h=b[c+r*e+1])}return f?(f[0]= +g,f[1]=h,f):[g,h]}function Yo(b,c,d,e,f,g){if(d==c)return null;if(f<b[c+e-1])return g?(d=b.slice(c,c+e),d[e-1]=f,d):null;if(b[d-1]<f)return g?(d=b.slice(d-e,d),d[e-1]=f,d):null;if(f==b[c+e-1])return b.slice(c,c+e);c/=e;for(d/=e;c<d;)g=c+d>>1,f<b[(g+1)*e-1]?d=g:c=g+1;d=b[c*e-1];if(f==d)return b.slice((c-1)*e,(c-1)*e+e);g=(f-d)/(b[(c+1)*e-1]-d);d=[];var h;for(h=0;h<e-1;++h)d.push(Uc(b[(c-1)*e+h],b[c*e+h],g));d.push(f);return d} +function Zo(b,c,d,e,f,g){var h=0;if(g)return Yo(b,h,c[c.length-1],d,e,f);if(e<b[d-1])return f?(b=b.slice(0,d),b[d-1]=e,b):null;if(b[b.length-1]<e)return f?(b=b.slice(b.length-d),b[d-1]=e,b):null;f=0;for(g=c.length;f<g;++f){var l=c[f];if(h!=l){if(e<b[h+d-1])break;if(e<=b[l-1])return Yo(b,h,l,d,e,!1);h=l}}return null};function S(b,c){Fg.call(this);this.c=null;this.v=this.F=this.j=-1;this.ia(b,c)}y(S,Fg);k=S.prototype;k.Dg=function(b){this.o?mb(this.o,b):this.o=b.slice();this.A()};k.clone=function(){var b=new S(null);$o(b,this.b,this.o.slice());return b};k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;this.v!=this.f&&(this.F=Math.sqrt(Lh(this.o,0,this.o.length,this.a,0)),this.v=this.f);return Nh(this.o,0,this.o.length,this.a,this.F,!1,b,c,d,e)}; +k.Tg=function(b,c){return ai(this.o,0,this.o.length,this.a,b,c)};k.fj=function(b,c){return"XYM"!=this.b&&"XYZM"!=this.b?null:Yo(this.o,0,this.o.length,this.a,b,void 0!==c?c:!1)};k.T=function(){return Sh(this.o,0,this.o.length,this.a)};k.gj=function(){var b=this.o,c=this.a,d=b[0],e=b[1],f=0,g;for(g=0+c;g<this.o.length;g+=c)var h=b[g],l=b[g+1],f=f+Math.sqrt((h-d)*(h-d)+(l-e)*(l-e)),d=h,e=l;return f};function am(b){b.j!=b.f&&(b.c=Xo(b.o,0,b.o.length,b.a,b.c),b.j=b.f);return b.c} +k.Kb=function(b){var c=[];c.length=Uh(this.o,0,this.o.length,this.a,b,c,0);b=new S(null);$o(b,"XY",c);return b};k.N=function(){return"LineString"};k.ta=function(b){return bi(this.o,0,this.o.length,this.a,b)};k.ia=function(b,c){b?(Ig(this,c,b,1),this.o||(this.o=[]),this.o.length=Qh(this.o,0,b,this.a),this.A()):$o(this,"XY",null)};function $o(b,c,d){Hg(b,c,d);b.A()};function T(b,c){Fg.call(this);this.c=[];this.j=this.v=-1;this.ia(b,c)}y(T,Fg);k=T.prototype;k.Eg=function(b){this.o?mb(this.o,b.ga().slice()):this.o=b.ga().slice();this.c.push(this.o.length);this.A()};k.clone=function(){var b=new T(null);ap(b,this.b,this.o.slice(),this.c.slice());return b};k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;this.j!=this.f&&(this.v=Math.sqrt(Mh(this.o,0,this.c,this.a,0)),this.j=this.f);return Oh(this.o,0,this.c,this.a,this.v,!1,b,c,d,e)}; +k.ij=function(b,c,d){return"XYM"!=this.b&&"XYZM"!=this.b||0===this.o.length?null:Zo(this.o,this.c,this.a,b,void 0!==c?c:!1,void 0!==d?d:!1)};k.T=function(){return Th(this.o,0,this.c,this.a)};k.Ua=function(){return this.c};k.xh=function(b){if(0>b||this.c.length<=b)return null;var c=new S(null);$o(c,this.b,this.o.slice(0===b?0:this.c[b-1],this.c[b]));return c}; +k.Jd=function(){var b=this.o,c=this.c,d=this.b,e=[],f=0,g,h;g=0;for(h=c.length;g<h;++g){var l=c[g],m=new S(null);$o(m,d,b.slice(f,l));e.push(m);f=l}return e};function bm(b){var c=[],d=b.o,e=0,f=b.c;b=b.a;var g,h;g=0;for(h=f.length;g<h;++g){var l=f[g],e=Xo(d,e,l,b);mb(c,e);e=l}return c}k.Kb=function(b){var c=[],d=[],e=this.o,f=this.c,g=this.a,h=0,l=0,m,n;m=0;for(n=f.length;m<n;++m){var p=f[m],l=Uh(e,h,p,g,b,c,l);d.push(l);h=p}c.length=l;b=new T(null);ap(b,"XY",c,d);return b};k.N=function(){return"MultiLineString"}; +k.ta=function(b){a:{var c=this.o,d=this.c,e=this.a,f=0,g,h;g=0;for(h=d.length;g<h;++g){if(bi(c,f,d[g],e,b)){b=!0;break a}f=d[g]}b=!1}return b};k.ia=function(b,c){if(b){Ig(this,c,b,2);this.o||(this.o=[]);var d=Rh(this.o,0,b,this.a,this.c);this.o.length=0===d.length?0:d[d.length-1];this.A()}else ap(this,"XY",null,this.c)};function ap(b,c,d,e){Hg(b,c,d);b.c=e;b.A()} +function bp(b,c){var d=b.b,e=[],f=[],g,h;g=0;for(h=c.length;g<h;++g){var l=c[g];0===g&&(d=l.b);mb(e,l.ga());f.push(e.length)}ap(b,d,e,f)};function U(b,c){Fg.call(this);this.ia(b,c)}y(U,Fg);k=U.prototype;k.Gg=function(b){this.o?mb(this.o,b.ga()):this.o=b.ga().slice();this.A()};k.clone=function(){var b=new U(null);Hg(b,this.b,this.o.slice());b.A();return b};k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;var f=this.o,g=this.a,h,l,m;h=0;for(l=f.length;h<l;h+=g)if(m=Ld(b,c,f[h],f[h+1]),m<e){e=m;for(m=0;m<g;++m)d[m]=f[h+m];d.length=g}return e};k.T=function(){return Sh(this.o,0,this.o.length,this.a)}; +k.jj=function(b){var c=this.o?this.o.length/this.a:0;if(0>b||c<=b)return null;c=new L(null);Hg(c,this.b,this.o.slice(b*this.a,(b+1)*this.a));c.A();return c};k.ge=function(){var b=this.o,c=this.b,d=this.a,e=[],f,g;f=0;for(g=b.length;f<g;f+=d){var h=new L(null),l=h;Hg(l,c,b.slice(f,f+d));l.A();e.push(h)}return e};k.N=function(){return"MultiPoint"};k.ta=function(b){var c=this.o,d=this.a,e,f,g,h;e=0;for(f=c.length;e<f;e+=d)if(g=c[e],h=c[e+1],pd(b,g,h))return!0;return!1}; +k.ia=function(b,c){b?(Ig(this,c,b,1),this.o||(this.o=[]),this.o.length=Qh(this.o,0,b,this.a)):Hg(this,"XY",null);this.A()};function V(b,c){Fg.call(this);this.c=[];this.v=-1;this.F=null;this.L=this.J=this.I=-1;this.j=null;this.ia(b,c)}y(V,Fg);k=V.prototype;k.Hg=function(b){if(this.o){var c=this.o.length;mb(this.o,b.ga());b=b.Ua().slice();var d,e;d=0;for(e=b.length;d<e;++d)b[d]+=c}else this.o=b.ga().slice(),b=b.Ua().slice(),this.c.push();this.c.push(b);this.A()};k.clone=function(){var b=new V(null),c=Ja(this.c);cp(b,this.b,this.o.slice(),c);return b}; +k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;if(this.J!=this.f){var f=this.c,g=0,h=0,l,m;l=0;for(m=f.length;l<m;++l)var n=f[l],h=Mh(this.o,g,n,this.a,h),g=n[n.length-1];this.I=Math.sqrt(h);this.J=this.f}f=cm(this);g=this.c;h=this.a;l=this.I;m=0;var n=[NaN,NaN],p,q;p=0;for(q=g.length;p<q;++p){var r=g[p];e=Oh(f,m,r,h,l,!0,b,c,d,e,n);m=r[r.length-1]}return e}; +k.sb=function(b,c){var d;a:{d=cm(this);var e=this.c,f=0;if(0!==e.length){var g,h;g=0;for(h=e.length;g<h;++g){var l=e[g];if(Zh(d,f,l,this.a,b,c)){d=!0;break a}f=l[l.length-1]}}d=!1}return d};k.kj=function(){var b=cm(this),c=this.c,d=0,e=0,f,g;f=0;for(g=c.length;f<g;++f)var h=c[f],e=e+Jh(b,d,h,this.a),d=h[h.length-1];return e}; +k.T=function(b){var c;void 0!==b?(c=cm(this).slice(),gi(c,this.c,this.a,b)):c=this.o;b=c;c=this.c;var d=this.a,e=0,f=[],g=0,h,l;h=0;for(l=c.length;h<l;++h){var m=c[h];f[g++]=Th(b,e,m,d,f[g]);e=m[m.length-1]}f.length=g;return f}; +function dm(b){if(b.v!=b.f){var c=b.o,d=b.c,e=b.a,f=0,g=[],h,l,m=hd();h=0;for(l=d.length;h<l;++h){var n=d[h],m=td(c,f,n[0],e);g.push((m[0]+m[2])/2,(m[1]+m[3])/2);f=n[n.length-1]}c=cm(b);d=b.c;e=b.a;f=0;h=[];l=0;for(m=d.length;l<m;++l)n=d[l],h=$h(c,f,n,e,g,2*l,h),f=n[n.length-1];b.F=h;b.v=b.f}return b.F}k.uh=function(){var b=new U(null),c=dm(this).slice();Hg(b,"XY",c);b.A();return b}; +function cm(b){if(b.L!=b.f){var c=b.o,d;a:{d=b.c;var e,f;e=0;for(f=d.length;e<f;++e)if(!ei(c,d[e],b.a,void 0)){d=!1;break a}d=!0}d?b.j=c:(b.j=c.slice(),b.j.length=gi(b.j,b.c,b.a));b.L=b.f}return b.j}k.Kb=function(b){var c=[],d=[],e=this.o,f=this.c,g=this.a;b=Math.sqrt(b);var h=0,l=0,m,n;m=0;for(n=f.length;m<n;++m){var p=f[m],q=[],l=Vh(e,h,p,g,b,c,l,q);d.push(q);h=p[p.length-1]}c.length=l;e=new V(null);cp(e,"XY",c,d);return e}; +k.Hh=function(b){if(0>b||this.c.length<=b)return null;var c;0===b?c=0:(c=this.c[b-1],c=c[c.length-1]);b=this.c[b].slice();var d=b[b.length-1];if(0!==c){var e,f;e=0;for(f=b.length;e<f;++e)b[e]-=c}e=new M(null);hi(e,this.b,this.o.slice(c,d),b);return e};k.Ld=function(){var b=this.b,c=this.o,d=this.c,e=[],f=0,g,h,l,m;g=0;for(h=d.length;g<h;++g){var n=d[g].slice(),p=n[n.length-1];if(0!==f)for(l=0,m=n.length;l<m;++l)n[l]-=f;l=new M(null);hi(l,b,c.slice(f,p),n);e.push(l);f=p}return e};k.N=function(){return"MultiPolygon"}; +k.ta=function(b){a:{var c=cm(this),d=this.c,e=this.a,f=0,g,h;g=0;for(h=d.length;g<h;++g){var l=d[g];if(ci(c,f,l,e,b)){b=!0;break a}f=l[l.length-1]}b=!1}return b};k.ia=function(b,c){if(b){Ig(this,c,b,3);this.o||(this.o=[]);var d=this.o,e=this.a,f=this.c,g=0,f=f?f:[],h=0,l,m;l=0;for(m=b.length;l<m;++l)g=Rh(d,g,b[l],e,f[h]),f[h++]=g,g=g[g.length-1];f.length=h;0===f.length?this.o.length=0:(d=f[f.length-1],this.o.length=0===d.length?0:d[d.length-1]);this.A()}else cp(this,"XY",null,this.c)}; +function cp(b,c,d,e){Hg(b,c,d);b.c=e;b.A()};function W(b){Dg.call(this);this.a=b?b:null;dp(this)}y(W,Dg);function ep(b){var c=[],d,e;d=0;for(e=b.length;d<e;++d)c.push(b[d].clone());return c}function fp(b){var c,d;if(b.a)for(c=0,d=b.a.length;c<d;++c)xc(b.a[c],"change",b.A,!1,b)}function dp(b){var c,d;if(b.a)for(c=0,d=b.a.length;c<d;++c)z(b.a[c],"change",b.A,!1,b)}k=W.prototype;k.clone=function(){var b=new W(null);b.ag(this.a);return b}; +k.Ia=function(b,c,d,e){if(e<nd(this.G(),b,c))return e;var f=this.a,g,h;g=0;for(h=f.length;g<h;++g)e=f[g].Ia(b,c,d,e);return e};k.sb=function(b,c){var d=this.a,e,f;e=0;for(f=d.length;e<f;++e)if(d[e].sb(b,c))return!0;return!1};k.Dc=function(b){kd(Infinity,Infinity,-Infinity,-Infinity,b);for(var c=this.a,d=0,e=c.length;d<e;++d)wd(b,c[d].G());return b};k.Ye=function(){return ep(this.a)}; +k.gc=function(b){this.l!=this.f&&(Ea(this.g),this.i=0,this.l=this.f);if(0>b||0!==this.i&&b<this.i)return this;var c=b.toString();if(this.g.hasOwnProperty(c))return this.g[c];var d=[],e=this.a,f=!1,g,h;g=0;for(h=e.length;g<h;++g){var l=e[g],m=l.gc(b);d.push(m);m!==l&&(f=!0)}if(f)return b=new W(null),fp(b),b.a=d,dp(b),b.A(),this.g[c]=b;this.i=b;return this};k.N=function(){return"GeometryCollection"};k.ta=function(b){var c=this.a,d,e;d=0;for(e=c.length;d<e;++d)if(c[d].ta(b))return!0;return!1}; +k.Pa=function(){return 0===this.a.length};k.ag=function(b){b=ep(b);fp(this);this.a=b;dp(this);this.A()};k.Eb=function(b){var c=this.a,d,e;d=0;for(e=c.length;d<e;++d)c[d].Eb(b);this.A()};k.fe=function(b,c){var d=this.a,e,f;e=0;for(f=d.length;e<f;++e)d[e].fe(b,c);this.A()};k.ba=function(){fp(this);W.ka.ba.call(this)};function gp(b){b=b?b:{};this.defaultDataProjection=null;this.defaultDataProjection=Zd(b.defaultDataProjection?b.defaultDataProjection:"EPSG:4326");this.f=b.geometryName}y(gp,To);function Wo(b,c){return b?So((0,hp[b.type])(b),!1,c):null}function ip(b,c){return(0,jp[b.N()])(So(b,!0,c),c)} +var hp={Point:function(b){return new L(b.coordinates)},LineString:function(b){return new S(b.coordinates)},Polygon:function(b){return new M(b.coordinates)},MultiPoint:function(b){return new U(b.coordinates)},MultiLineString:function(b){return new T(b.coordinates)},MultiPolygon:function(b){return new V(b.coordinates)},GeometryCollection:function(b,c){var d=b.geometries.map(function(b){return Wo(b,c)});return new W(d)}},jp={Point:function(b){return{type:"Point",coordinates:b.T()}},LineString:function(b){return{type:"LineString", +coordinates:b.T()}},Polygon:function(b,c){var d;c&&(d=c.rightHanded);return{type:"Polygon",coordinates:b.T(d)}},MultiPoint:function(b){return{type:"MultiPoint",coordinates:b.T()}},MultiLineString:function(b){return{type:"MultiLineString",coordinates:b.T()}},MultiPolygon:function(b,c){var d;c&&(d=c.rightHanded);return{type:"MultiPolygon",coordinates:b.T(d)}},GeometryCollection:function(b,c){return{type:"GeometryCollection",geometries:b.a.map(function(b){return ip(b,c)})}},Circle:function(){return{type:"GeometryCollection", +geometries:[]}}};function Vo(b,c,d){d=Wo(c.geometry,d);var e=new Ym;b.f&&e.ld(b.f);e.Xa(d);void 0!==c.id&&e.te(c.id);c.properties&&e.M(c.properties);return e}gp.prototype.a=function(b,c){c=Ro(this,c);var d={type:"Feature"},e=b.Ja();void 0!==e&&(d.id=e);e=b.R();d.geometry=e?ip(e,c):null;e=b.S();delete e[b.a];d.properties=Da(e)?null:e;return d};gp.prototype.b=function(b,c){c=Ro(this,c);var d=[],e,f;e=0;for(f=b.length;e<f;++e)d.push(this.a(b[e],c));return{type:"FeatureCollection",features:d}}; +gp.prototype.c=function(b,c){return ip(b,Ro(this,c))};function kp(){this.defaultDataProjection=null}y(kp,Po);k=kp.prototype;k.N=function(){return"xml"};k.oe=function(b,c){if(Qn(b))return lp(this,b,c);if(Tn(b)){var d;d=0<=mp.indexOf(b.namespaceURI)?(d=this.pe(b,[Qo(this,b,c)]))?d:null:null;return d}return ha(b)?(d=Xn(b),lp(this,d,c)):null};function lp(b,c,d){b=np(b,c,d);return 0<b.length?b[0]:null}k.jd=function(b,c){if(Qn(b))return np(this,b,c);if(Tn(b))return op(this,b,c);if(ha(b)){var d=Xn(b);return np(this,d,c)}return[]}; +function np(b,c,d){var e=[];for(c=c.firstChild;c;c=c.nextSibling)1==c.nodeType&&mb(e,op(b,c,d));return e}k.Tf=function(b,c){if(Qn(b))return this.g(b,c);if(Tn(b))return this.j(b,c);if(ha(b)){var d=Xn(b);return this.g(d,c)}return null};k.vc=function(b){return Qn(b)||Tn(b)?this.defaultDataProjection:ha(b)?(Xn(b),this.defaultDataProjection):null};k.pg=function(b,c){var d=this.l(b,c);return Cn(d)};k.Ce=function(b,c){var d=this.f(b,c);return Cn(d)};k.qg=function(b,c){var d=this.u(b,c);return Cn(d)};function pp(b){b=Jn(b);return qp(b)}function qp(b){if(b=/^\s*(true|1)|(false|0)\s*$/.exec(b))return void 0!==b[1]||!1}function rp(b){b=Jn(b);return sp(b)}function sp(b){if(b=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(b))return parseFloat(b[1])}function tp(b){b=Jn(b);return up(b)}function up(b){if(b=/^\s*(\d+)\s*$/.exec(b))return parseInt(b[1],10)}function vp(b){return Jn(b).trim()}function wp(b,c){xp(b,c?"1":"0")}function yp(b,c){b.appendChild(Fn.createTextNode(c.toPrecision()))} +function xp(b,c){b.appendChild(Fn.createTextNode(c))};function zp(b,c){this.f=this.s=this.b="";this.j=null;this.c=this.a="";this.g=!1;var d;b instanceof zp?(this.g=ca(c)?c:b.g,Ap(this,b.b),this.s=b.s,this.f=b.f,Bp(this,b.j),this.a=b.a,Cp(this,b.i.clone()),this.c=b.c):b&&(d=String(b).match(Xf))?(this.g=!!c,Ap(this,d[1]||"",!0),this.s=Dp(d[2]||""),this.f=Dp(d[3]||"",!0),Bp(this,d[4]),this.a=Dp(d[5]||"",!0),Cp(this,d[6]||"",!0),this.c=Dp(d[7]||"")):(this.g=!!c,this.i=new Ep(null,0,this.g))} +zp.prototype.toString=function(){var b=[],c=this.b;c&&b.push(Fp(c,Gp,!0),":");var d=this.f;if(d||"file"==c)b.push("//"),(c=this.s)&&b.push(Fp(c,Gp,!0),"@"),b.push(encodeURIComponent(String(d)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),d=this.j,null!=d&&b.push(":",String(d));if(d=this.a)this.f&&"/"!=d.charAt(0)&&b.push("/"),b.push(Fp(d,"/"==d.charAt(0)?Hp:Ip,!0));(d=this.i.toString())&&b.push("?",d);(d=this.c)&&b.push("#",Fp(d,Jp));return b.join("")};zp.prototype.clone=function(){return new zp(this)}; +function Ap(b,c,d){b.b=d?Dp(c,!0):c;b.b&&(b.b=b.b.replace(/:$/,""))}function Bp(b,c){if(c){c=Number(c);if(isNaN(c)||0>c)throw Error("Bad port number "+c);b.j=c}else b.j=null}function Cp(b,c,d){c instanceof Ep?(b.i=c,Kp(b.i,b.g)):(d||(c=Fp(c,Lp)),b.i=new Ep(c,0,b.g))}function Mp(b){return b instanceof zp?b.clone():new zp(b,void 0)} +function Np(b,c){b instanceof zp||(b=Mp(b));c instanceof zp||(c=Mp(c));var d=b,e=c,f=d.clone(),g=!!e.b;g?Ap(f,e.b):g=!!e.s;g?f.s=e.s:g=!!e.f;g?f.f=e.f:g=null!=e.j;var h=e.a;if(g)Bp(f,e.j);else if(g=!!e.a)if("/"!=h.charAt(0)&&(d.f&&!d.a?h="/"+h:(d=f.a.lastIndexOf("/"),-1!=d&&(h=f.a.substr(0,d+1)+h))),d=h,".."==d||"."==d)h="";else if(-1!=d.indexOf("./")||-1!=d.indexOf("/.")){for(var h=0==d.lastIndexOf("/",0),d=d.split("/"),l=[],m=0;m<d.length;){var n=d[m++];"."==n?h&&m==d.length&&l.push(""):".."==n? +((1<l.length||1==l.length&&""!=l[0])&&l.pop(),h&&m==d.length&&l.push("")):(l.push(n),h=!0)}h=l.join("/")}else h=d;g?f.a=h:g=""!==e.i.toString();g?Cp(f,Dp(e.i.toString())):g=!!e.c;g&&(f.c=e.c);return f}function Dp(b,c){return b?c?decodeURI(b.replace(/%25/g,"%2525")):decodeURIComponent(b):""}function Fp(b,c,d){return ha(b)?(b=encodeURI(b).replace(c,Op),d&&(b=b.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),b):null}function Op(b){b=b.charCodeAt(0);return"%"+(b>>4&15).toString(16)+(b&15).toString(16)} +var Gp=/[#\/\?@]/g,Ip=/[\#\?:]/g,Hp=/[\#\?]/g,Lp=/[\#\?@]/g,Jp=/#/g;function Ep(b,c,d){this.b=this.a=null;this.f=b||null;this.c=!!d}function Pp(b){b.a||(b.a=new Ui,b.b=0,b.f&&Yf(b.f,function(c,d){b.add(decodeURIComponent(c.replace(/\+/g," ")),d)}))}k=Ep.prototype;k.fc=function(){Pp(this);return this.b};k.add=function(b,c){Pp(this);this.f=null;b=Qp(this,b);var d=this.a.get(b);d||Vi(this.a,b,d=[]);d.push(c);this.b++;return this}; +k.remove=function(b){Pp(this);b=Qp(this,b);return Xi(this.a.H,b)?(this.f=null,this.b-=this.a.get(b).length,this.a.remove(b)):!1};k.clear=function(){this.a=this.f=null;this.b=0};k.Pa=function(){Pp(this);return 0==this.b};k.P=function(){Pp(this);for(var b=this.a.ob(),c=this.a.P(),d=[],e=0;e<c.length;e++)for(var f=b[e],g=0;g<f.length;g++)d.push(c[e]);return d}; +k.ob=function(b){Pp(this);var c=[];if(ha(b)){var d=b;Pp(this);d=Qp(this,d);Xi(this.a.H,d)&&(c=ib(c,this.a.get(Qp(this,b))))}else for(b=this.a.ob(),d=0;d<b.length;d++)c=ib(c,b[d]);return c};k.get=function(b,c){var d=b?this.ob(b):[];return 0<d.length?String(d[0]):c}; +k.toString=function(){if(this.f)return this.f;if(!this.a)return"";for(var b=[],c=this.a.P(),d=0;d<c.length;d++)for(var e=c[d],f=encodeURIComponent(String(e)),e=this.ob(e),g=0;g<e.length;g++){var h=f;""!==e[g]&&(h+="="+encodeURIComponent(String(e[g])));b.push(h)}return this.f=b.join("&")};k.clone=function(){var b=new Ep;b.f=this.f;this.a&&(b.a=this.a.clone(),b.b=this.b);return b};function Qp(b,c){var d=String(c);b.c&&(d=d.toLowerCase());return d} +function Kp(b,c){c&&!b.c&&(Pp(b),b.f=null,b.a.forEach(function(b,c){var f=c.toLowerCase();c!=f&&(this.remove(c),this.remove(f),0<b.length&&(this.f=null,Vi(this.a,Qp(this,f),jb(b)),this.b+=b.length))},b));b.c=c};function Rp(b){b=b||{};this.f=b.font;this.s=b.rotation;this.g=b.scale;this.u=b.text;this.i=b.textAlign;this.a=b.textBaseline;this.j=void 0!==b.fill?b.fill:new jh({color:"#333"});this.l=void 0!==b.stroke?b.stroke:null;this.b=void 0!==b.offsetX?b.offsetX:0;this.c=void 0!==b.offsetY?b.offsetY:0}k=Rp.prototype;k.nh=function(){return this.f};k.Bh=function(){return this.b};k.Ch=function(){return this.c};k.va=function(){return this.j};k.pk=function(){return this.s};k.qk=function(){return this.g};k.sa=function(){return this.l}; +k.na=function(){return this.u};k.Lh=function(){return this.i};k.Mh=function(){return this.a};k.dl=function(b){this.f=b};k.dg=function(b){this.b=b};k.eg=function(b){this.c=b};k.cl=function(b){this.j=b};k.rk=function(b){this.s=b};k.sk=function(b){this.g=b};k.ol=function(b){this.l=b};k.gg=function(b){this.u=b};k.hg=function(b){this.i=b};k.pl=function(b){this.a=b};function Sp(b){b=b?b:{};this.defaultDataProjection=null;this.defaultDataProjection=Zd("EPSG:4326");this.b=b.defaultStyle?b.defaultStyle:Tp;this.c=void 0!==b.extractStyles?b.extractStyles:!0;this.s=void 0!==b.writeStyles?b.writeStyles:!0;this.a={};this.i=void 0!==b.showPointNames?b.showPointNames:!0}y(Sp,kp); +var Up=["http://www.google.com/kml/ext/2.2"],mp=[null,"http://earth.google.com/kml/2.0","http://earth.google.com/kml/2.1","http://earth.google.com/kml/2.2","http://www.opengis.net/kml/2.2"],Vp=[255,255,255,1],Wp=new jh({color:Vp}),Xp=[20,2],Yp=[64,64],Zp=new Pg({anchor:Xp,anchorOrigin:"bottom-left",anchorXUnits:"pixels",anchorYUnits:"pixels",crossOrigin:"anonymous",rotation:0,scale:.5,size:Yp,src:"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"}),$p=new oh({color:Vp,width:1}),aq=new Rp({font:"bold 16px Helvetica", +fill:Wp,stroke:new oh({color:[51,51,51,1],width:2}),scale:.8}),Tp=[new qh({fill:Wp,image:Zp,text:aq,stroke:$p,zIndex:0})],bq={fraction:"fraction",pixels:"pixels"};function cq(b,c){var d=null,e=[0,0],f="start";b.a&&(d=b.a.Ic())&&2==d.length&&(e[0]=b.a.s*d[0]/2,e[1]=-b.a.s*d[1]/2,f="left");Da(b.na())?d=new Rp({text:c,offsetX:e[0],offsetY:e[1],textAlign:f}):(d=Ia(b.na()),d.gg(c),d.hg(f),d.dg(e[0]),d.eg(e[1]));return new qh({text:d})} +function dq(b,c,d,e,f){return function(){var g=f,h="";g&&this.R()&&(g="Point"===this.R().N());g&&(h=this.S().name,g=g&&h);if(b)return g?(g=cq(b[0],h),b.concat(g)):b;if(c){var l=eq(c,d,e);return g?(g=cq(l[0],h),l.concat(g)):l}return g?(g=cq(d[0],h),d.concat(g)):d}}function eq(b,c,d){return fa(b)?b:ha(b)?(!(b in d)&&"#"+b in d&&(b="#"+b),eq(d[b],c,d)):c} +function fq(b){b=Jn(b);if(b=/^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(b))return b=b[1],[parseInt(b.substr(6,2),16),parseInt(b.substr(4,2),16),parseInt(b.substr(2,2),16),parseInt(b.substr(0,2),16)/255]}function gq(b){b=Jn(b);for(var c=[],d=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i,e;e=d.exec(b);)c.push(parseFloat(e[1]),parseFloat(e[2]),e[3]?parseFloat(e[3]):0),b=b.substr(e[0].length);return""!==b?void 0:c} +function hq(b){var c=Jn(b);return b.baseURI?Np(b.baseURI,c.trim()).toString():c.trim()}function iq(b){b=rp(b);if(void 0!==b)return Math.sqrt(b)}function jq(b,c){return ho(null,kq,b,c)}function lq(b,c){var d=ho({o:[],og:[]},mq,b,c);if(d){var e=d.o,d=d.og,f,g;f=0;for(g=Math.min(e.length,d.length);f<g;++f)e[4*f+3]=d[f];d=new S(null);$o(d,"XYZM",e);return d}}function nq(b,c){var d=ho({},oq,b,c),e=ho(null,pq,b,c);if(e){var f=new S(null);$o(f,"XYZ",e);f.M(d);return f}} +function qq(b,c){var d=ho({},oq,b,c),e=ho(null,pq,b,c);if(e){var f=new M(null);hi(f,"XYZ",e,[e.length]);f.M(d);return f}} +function rq(b,c){var d=ho([],sq,b,c);if(!d)return null;if(0===d.length)return new W(d);var e=!0,f=d[0].N(),g,h,l;h=1;for(l=d.length;h<l;++h)if(g=d[h],g.N()!=f){e=!1;break}if(e){if("Point"==f){g=d[0];e=g.b;f=g.ga();h=1;for(l=d.length;h<l;++h)g=d[h],mb(f,g.ga());g=new U(null);Hg(g,e,f);g.A();tq(g,d);return g}if("LineString"==f)return g=new T(null),bp(g,d),tq(g,d),g;if("Polygon"==f){g=new V(null);h=g.b;l=[];var e=[],m,n,f=0;for(m=d.length;f<m;++f){var p=d[f];0===f&&(h=p.b);var q=l.length;n=p.Ua();var r, +t;r=0;for(t=n.length;r<t;++r)n[r]+=q;mb(l,p.ga());e.push(n)}cp(g,h,l,e);tq(g,d);return g}return"GeometryCollection"==f?new W(d):null}return new W(d)}function uq(b,c){var d=ho({},oq,b,c),e=ho(null,pq,b,c);if(e){var f=new L(null);Hg(f,"XYZ",e);f.A();f.M(d);return f}}function vq(b,c){var d=ho({},oq,b,c),e=ho([null],wq,b,c);if(e&&e[0]){var f=new M(null),g=e[0],h=[g.length],l,m;l=1;for(m=e.length;l<m;++l)mb(g,e[l]),h.push(g.length);hi(f,"XYZ",g,h);f.M(d);return f}} +function xq(b,c){var d=ho({},yq,b,c);if(!d)return null;var e="fillStyle"in d?d.fillStyle:Wp,f=d.fill;void 0===f||f||(e=null);var f="imageStyle"in d?d.imageStyle:Zp,g="textStyle"in d?d.textStyle:aq,h="strokeStyle"in d?d.strokeStyle:$p,d=d.outline;void 0===d||d||(h=null);return[new qh({fill:e,image:f,stroke:h,text:g,zIndex:void 0})]} +function tq(b,c){var d=c.length,e=Array(c.length),f=Array(c.length),g,h,l,m;l=m=!1;for(h=0;h<d;++h)g=c[h],e[h]=g.get("extrude"),f[h]=g.get("altitudeMode"),l=l||void 0!==e[h],m=m||f[h];l&&b.C("extrude",e);m&&b.C("altitudeMode",f)}function zq(b,c){go(Aq,b,c)} +var Bq=Q(mp,{value:$n(vp)}),Aq=Q(mp,{Data:function(b,c){var d=b.getAttribute("name");if(null!==d){var e=ho(void 0,Bq,b,c);e&&(c[c.length-1][d]=e)}},SchemaData:function(b,c){go(Cq,b,c)}}),oq=Q(mp,{extrude:O(pp),altitudeMode:O(vp)}),kq=Q(mp,{coordinates:$n(gq)}),wq=Q(mp,{innerBoundaryIs:function(b,c){var d=ho(void 0,Dq,b,c);d&&c[c.length-1].push(d)},outerBoundaryIs:function(b,c){var d=ho(void 0,Eq,b,c);d&&(c[c.length-1][0]=d)}}),mq=Q(mp,{when:function(b,c){var d=c[c.length-1].og,e=Jn(b);if(e=/^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/.exec(e)){var f= +Date.UTC(parseInt(e[1],10),e[3]?parseInt(e[3],10)-1:0,e[5]?parseInt(e[5],10):1,e[7]?parseInt(e[7],10):0,e[8]?parseInt(e[8],10):0,e[9]?parseInt(e[9],10):0);if(e[10]&&"Z"!=e[10]){var g="-"==e[11]?-1:1,f=f+60*g*parseInt(e[12],10);e[13]&&(f+=3600*g*parseInt(e[13],10))}d.push(f)}else d.push(0)}},Q(Up,{coord:function(b,c){var d=c[c.length-1].o,e=Jn(b);(e=/^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i.exec(e))?d.push(parseFloat(e[1]), +parseFloat(e[2]),parseFloat(e[3]),0):d.push(0,0,0,0)}})),pq=Q(mp,{coordinates:$n(gq)}),Fq=Q(mp,{href:O(hq)},Q(Up,{x:O(rp),y:O(rp),w:O(rp),h:O(rp)})),Gq=Q(mp,{Icon:O(function(b,c){var d=ho({},Fq,b,c);return d?d:null}),heading:O(rp),hotSpot:O(function(b){var c=b.getAttribute("xunits"),d=b.getAttribute("yunits");return{x:parseFloat(b.getAttribute("x")),De:bq[c],y:parseFloat(b.getAttribute("y")),Ee:bq[d]}}),scale:O(iq)}),Dq=Q(mp,{LinearRing:$n(jq)}),Hq=Q(mp,{color:O(fq),scale:O(iq)}),Iq=Q(mp,{color:O(fq), +width:O(rp)}),sq=Q(mp,{LineString:Zn(nq),LinearRing:Zn(qq),MultiGeometry:Zn(rq),Point:Zn(uq),Polygon:Zn(vq)}),Jq=Q(Up,{Track:Zn(lq)}),Lq=Q(mp,{ExtendedData:zq,Link:function(b,c){go(Kq,b,c)},address:O(vp),description:O(vp),name:O(vp),open:O(pp),phoneNumber:O(vp),visibility:O(pp)}),Kq=Q(mp,{href:O(hq)}),Eq=Q(mp,{LinearRing:$n(jq)}),Mq=Q(mp,{Style:O(xq),key:O(vp),styleUrl:O(function(b){var c=Jn(b).trim();return b.baseURI?Np(b.baseURI,c).toString():c})}),Oq=Q(mp,{ExtendedData:zq,MultiGeometry:O(rq,"geometry"), +LineString:O(nq,"geometry"),LinearRing:O(qq,"geometry"),Point:O(uq,"geometry"),Polygon:O(vq,"geometry"),Style:O(xq),StyleMap:function(b,c){var d=ho(void 0,Nq,b,c);if(d){var e=c[c.length-1];fa(d)?e.Style=d:ha(d)&&(e.styleUrl=d)}},address:O(vp),description:O(vp),name:O(vp),open:O(pp),phoneNumber:O(vp),styleUrl:O(hq),visibility:O(pp)},Q(Up,{MultiTrack:O(function(b,c){var d=ho([],Jq,b,c);if(d){var e=new T(null);bp(e,d);return e}},"geometry"),Track:O(lq,"geometry")})),Pq=Q(mp,{color:O(fq),fill:O(pp),outline:O(pp)}), +Cq=Q(mp,{SimpleData:function(b,c){var d=b.getAttribute("name");if(null!==d){var e=vp(b);c[c.length-1][d]=e}}}),yq=Q(mp,{IconStyle:function(b,c){var d=ho({},Gq,b,c);if(d){var e=c[c.length-1],f="Icon"in d?d.Icon:{},g;g=(g=f.href)?g:"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png";var h,l,m,n=d.hotSpot;n?(h=[n.x,n.y],l=n.De,m=n.Ee):"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"===g?(h=Xp,m=l="pixels"):/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(g)&&(h=[.5,0],m=l="fraction"); +var p,n=f.x,q=f.y;void 0!==n&&void 0!==q&&(p=[n,q]);var r,n=f.w,f=f.h;void 0!==n&&void 0!==f&&(r=[n,f]);var t,f=d.heading;void 0!==f&&(t=Md(f));d=d.scale;"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"==g&&(r=Yp,void 0===d&&(d=.5));h=new Pg({anchor:h,anchorOrigin:"bottom-left",anchorXUnits:l,anchorYUnits:m,crossOrigin:"anonymous",offset:p,offsetOrigin:"bottom-left",rotation:t,scale:d,size:r,src:g});e.imageStyle=h}},LabelStyle:function(b,c){var d=ho({},Hq,b,c);d&&(c[c.length-1].textStyle= +new Rp({fill:new jh({color:"color"in d?d.color:Vp}),scale:d.scale}))},LineStyle:function(b,c){var d=ho({},Iq,b,c);d&&(c[c.length-1].strokeStyle=new oh({color:"color"in d?d.color:Vp,width:"width"in d?d.width:1}))},PolyStyle:function(b,c){var d=ho({},Pq,b,c);if(d){var e=c[c.length-1];e.fillStyle=new jh({color:"color"in d?d.color:Vp});var f=d.fill;void 0!==f&&(e.fill=f);d=d.outline;void 0!==d&&(e.outline=d)}}}),Nq=Q(mp,{Pair:function(b,c){var d=ho({},Mq,b,c);if(d){var e=d.key;e&&"normal"==e&&((e=d.styleUrl)&& +(c[c.length-1]=e),(d=d.Style)&&(c[c.length-1]=d))}}});k=Sp.prototype;k.ne=function(b,c){Nn(b);var d=Q(mp,{Document:Yn(this.ne,this),Folder:Yn(this.ne,this),Placemark:Zn(this.pe,this),Style:ra(this.Pk,this),StyleMap:ra(this.Ok,this)});if(d=ho([],d,b,c,this))return d}; +k.pe=function(b,c){var d=ho({geometry:null},Oq,b,c);if(d){var e=new Ym,f=b.getAttribute("id");null!==f&&e.te(f);var f=c[0],g=d.geometry;g&&So(g,!1,f);e.Xa(g);delete d.geometry;this.c&&e.be(dq(d.Style,d.styleUrl,this.b,this.a,this.i));delete d.Style;e.M(d);return e}};k.Pk=function(b,c){var d=b.getAttribute("id");if(null!==d){var e=xq(b,c);e&&(d=b.baseURI?Np(b.baseURI,"#"+d).toString():"#"+d,this.a[d]=e)}}; +k.Ok=function(b,c){var d=b.getAttribute("id");if(null!==d){var e=ho(void 0,Nq,b,c);e&&(d=b.baseURI?Np(b.baseURI,"#"+d).toString():"#"+d,this.a[d]=e)}};function op(b,c,d){if(!(0<=mp.indexOf(c.namespaceURI)))return[];var e;e=Nn(c);if("Document"==e||"Folder"==e)return(e=b.ne(c,[Qo(b,c,d)]))?e:[];if("Placemark"==e)return(b=b.pe(c,[Qo(b,c,d)]))?[b]:[];if("kml"==e){e=[];for(c=c.firstElementChild;c;c=c.nextElementSibling){var f=op(b,c,d);f&&mb(e,f)}return e}return[]} +k.Mk=function(b){if(Qn(b))return Qq(this,b);if(Tn(b))return Rq(this,b);if(ha(b))return b=Xn(b),Qq(this,b)};function Qq(b,c){var d;for(d=c.firstChild;d;d=d.nextSibling)if(1==d.nodeType){var e=Rq(b,d);if(e)return e}} +function Rq(b,c){var d;for(d=c.firstElementChild;d;d=d.nextElementSibling)if(0<=mp.indexOf(d.namespaceURI)&&"name"==d.localName)return vp(d);for(d=c.firstElementChild;d;d=d.nextElementSibling){var e=Nn(d);if(0<=mp.indexOf(d.namespaceURI)&&("Document"==e||"Folder"==e||"Placemark"==e||"kml"==e)&&(e=Rq(b,d)))return e}}k.Nk=function(b){var c=[];Qn(b)?mb(c,Sq(this,b)):Tn(b)?mb(c,Tq(this,b)):ha(b)&&(b=Xn(b),mb(c,Sq(this,b)));return c}; +function Sq(b,c){var d,e=[];for(d=c.firstChild;d;d=d.nextSibling)1==d.nodeType&&mb(e,Tq(b,d));return e}function Tq(b,c){var d,e=[];for(d=c.firstElementChild;d;d=d.nextElementSibling)if(0<=mp.indexOf(d.namespaceURI)&&"NetworkLink"==d.localName){var f=ho({},Lq,d,[]);e.push(f)}for(d=c.firstElementChild;d;d=d.nextElementSibling)f=Nn(d),!(0<=mp.indexOf(d.namespaceURI))||"Document"!=f&&"Folder"!=f&&"kml"!=f||mb(e,Tq(b,d));return e} +function Uq(b,c){var d=Vg(c),d=[255*(4==d.length?d[3]:1),d[2],d[1],d[0]],e;for(e=0;4>e;++e){var f=parseInt(d[e],10).toString(16);d[e]=1==f.length?"0"+f:f}xp(b,d.join(""))}function Vq(b,c,d){io({node:b},Wq,Xq,[c],d)} +function Yq(b,c,d){var e={node:b};c.Ja()&&b.setAttribute("id",c.Ja());b=c.S();var f=c.Lb();if(f&&(f=f.call(c,0))&&0<f.length){var g=f[0];this.s&&(b.Style=f[0]);(f=g.na())&&(b.name=f.na())}f=Zq[d[d.length-1].node.namespaceURI];b=fo(b,f);io(e,$q,eo,b,d,f);b=d[0];(c=c.R())&&(c=So(c,!0,b));io(e,$q,ar,[c],d)}function br(b,c,d){var e=c.ga();b={node:b};b.layout=c.b;b.stride=c.pa();io(b,cr,dr,[e],d)}function er(b,c,d){c=c.Kd();var e=c.shift();b={node:b};io(b,fr,gr,c,d);io(b,fr,hr,[e],d)} +function ir(b,c){yp(b,c*c)} +var jr=Q(mp,["Document","Placemark"]),mr=Q(mp,{Document:bo(function(b,c,d){io({node:b},kr,lr,c,d,void 0,this)}),Placemark:bo(Yq)}),kr=Q(mp,{Placemark:bo(Yq)}),nr={Point:"Point",LineString:"LineString",LinearRing:"LinearRing",Polygon:"Polygon",MultiPoint:"MultiGeometry",MultiLineString:"MultiGeometry",MultiPolygon:"MultiGeometry"},or=Q(mp,["href"],Q(Up,["x","y","w","h"])),pr=Q(mp,{href:bo(xp)},Q(Up,{x:bo(yp),y:bo(yp),w:bo(yp),h:bo(yp)})),qr=Q(mp,["scale","heading","Icon","hotSpot"]),sr=Q(mp,{Icon:bo(function(b, +c,d){b={node:b};var e=or[d[d.length-1].node.namespaceURI],f=fo(c,e);io(b,pr,eo,f,d,e);e=or[Up[0]];f=fo(c,e);io(b,pr,rr,f,d,e)}),heading:bo(yp),hotSpot:bo(function(b,c){b.setAttribute("x",c.x);b.setAttribute("y",c.y);b.setAttribute("xunits",c.De);b.setAttribute("yunits",c.Ee)}),scale:bo(ir)}),tr=Q(mp,["color","scale"]),ur=Q(mp,{color:bo(Uq),scale:bo(ir)}),vr=Q(mp,["color","width"]),wr=Q(mp,{color:bo(Uq),width:bo(yp)}),Wq=Q(mp,{LinearRing:bo(br)}),xr=Q(mp,{LineString:bo(br),Point:bo(br),Polygon:bo(er)}), +Zq=Q(mp,"name open visibility address phoneNumber description styleUrl Style".split(" ")),$q=Q(mp,{MultiGeometry:bo(function(b,c,d){b={node:b};var e=c.N(),f,g;"MultiPoint"==e?(f=c.ge(),g=yr):"MultiLineString"==e?(f=c.Jd(),g=zr):"MultiPolygon"==e&&(f=c.Ld(),g=Ar);io(b,xr,g,f,d)}),LineString:bo(br),LinearRing:bo(br),Point:bo(br),Polygon:bo(er),Style:bo(function(b,c,d){b={node:b};var e={},f=c.va(),g=c.sa(),h=c.a;c=c.na();h instanceof Pg&&(e.IconStyle=h);c&&(e.LabelStyle=c);g&&(e.LineStyle=g);f&&(e.PolyStyle= +f);c=Br[d[d.length-1].node.namespaceURI];e=fo(e,c);io(b,Cr,eo,e,d,c)}),address:bo(xp),description:bo(xp),name:bo(xp),open:bo(wp),phoneNumber:bo(xp),styleUrl:bo(xp),visibility:bo(wp)}),cr=Q(mp,{coordinates:bo(function(b,c,d){d=d[d.length-1];var e=d.layout;d=d.stride;var f;"XY"==e||"XYM"==e?f=2:("XYZ"==e||"XYZM"==e)&&(f=3);var g,h=c.length,l="";if(0<h){l+=c[0];for(e=1;e<f;++e)l+=","+c[e];for(g=d;g<h;g+=d)for(l+=" "+c[g],e=1;e<f;++e)l+=","+c[g+e]}xp(b,l)})}),fr=Q(mp,{outerBoundaryIs:bo(Vq),innerBoundaryIs:bo(Vq)}), +Dr=Q(mp,{color:bo(Uq)}),Br=Q(mp,["IconStyle","LabelStyle","LineStyle","PolyStyle"]),Cr=Q(mp,{IconStyle:bo(function(b,c,d){b={node:b};var e={},f=c.Ya(),g=c.Ic(),h={href:c.a.i};if(f){h.w=f[0];h.h=f[1];var l=c.mb(),m=c.Aa();m&&g&&0!==m[0]&&m[1]!==f[1]&&(h.x=m[0],h.y=g[1]-(m[1]+f[1]));l&&0!==l[0]&&l[1]!==f[1]&&(e.hotSpot={x:l[0],De:"pixels",y:f[1]-l[1],Ee:"pixels"})}e.Icon=h;f=c.s;1!==f&&(e.scale=f);c=c.D;0!==c&&(e.heading=c);c=qr[d[d.length-1].node.namespaceURI];e=fo(e,c);io(b,sr,eo,e,d,c)}),LabelStyle:bo(function(b, +c,d){b={node:b};var e={},f=c.va();f&&(e.color=f.a);(c=c.g)&&1!==c&&(e.scale=c);c=tr[d[d.length-1].node.namespaceURI];e=fo(e,c);io(b,ur,eo,e,d,c)}),LineStyle:bo(function(b,c,d){b={node:b};var e=vr[d[d.length-1].node.namespaceURI];c=fo({color:c.a,width:c.f},e);io(b,wr,eo,c,d,e)}),PolyStyle:bo(function(b,c,d){io({node:b},Dr,Er,[c.a],d)})});function rr(b,c,d){return In(Up[0],"gx:"+d)}function lr(b,c){return In(c[c.length-1].node.namespaceURI,"Placemark")} +function ar(b,c){if(b)return In(c[c.length-1].node.namespaceURI,nr[b.N()])}var Er=co("color"),dr=co("coordinates"),gr=co("innerBoundaryIs"),yr=co("Point"),zr=co("LineString"),Xq=co("LinearRing"),Ar=co("Polygon"),hr=co("outerBoundaryIs"); +Sp.prototype.f=function(b,c){c=Ro(this,c);var d=In(mp[4],"kml");Wn(d,"http://www.w3.org/2000/xmlns/","xmlns:gx",Up[0]);Wn(d,"http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");Wn(d,"http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation","http://www.opengis.net/kml/2.2 https://developers.google.com/kml/schema/kml22gx.xsd");var e={node:d},f={};1<b.length?f.Document=b:1==b.length&&(f.Placemark=b[0]);var g=jr[d.namespaceURI],f=fo(f,g);io(e,mr,eo,f,[c],g,this); +return d};function Fr(b){return b.getAttributeNS("http://www.w3.org/1999/xlink","href")};function Gr(){}Gr.prototype.a=function(b){return Qn(b)?Hr(this,b):Tn(b)?Ir(this,b):ha(b)?(b=Xn(b),Hr(this,b)):null};function Jr(){this.version=void 0}y(Jr,Gr);function Hr(b,c){for(var d=c.firstChild;d;d=d.nextSibling)if(1==d.nodeType)return Ir(b,d);return null}function Ir(b,c){b.version=c.getAttribute("version").trim();var d=ho({version:b.version},Kr,c,[]);return d?d:null}function Lr(b,c){return ho({},Mr,b,c)}function Nr(b,c){return ho({},Or,b,c)}function Pr(b,c){var d=Lr(b,c);if(d){var e=[up(b.getAttribute("width")),up(b.getAttribute("height"))];d.size=e;return d}}function Qr(b,c){return ho([],Rr,b,c)} +var Sr=[null,"http://www.opengis.net/wms"],Kr=Q(Sr,{Service:O(function(b,c){return ho({},Tr,b,c)}),Capability:O(function(b,c){return ho({},Ur,b,c)})}),Ur=Q(Sr,{Request:O(function(b,c){return ho({},Vr,b,c)}),Exception:O(function(b,c){return ho([],Wr,b,c)}),Layer:O(function(b,c){return ho({},Xr,b,c)})}),Tr=Q(Sr,{Name:O(vp),Title:O(vp),Abstract:O(vp),KeywordList:O(Qr),OnlineResource:O(Fr),ContactInformation:O(function(b,c){return ho({},Yr,b,c)}),Fees:O(vp),AccessConstraints:O(vp),LayerLimit:O(tp),MaxWidth:O(tp), +MaxHeight:O(tp)}),Yr=Q(Sr,{ContactPersonPrimary:O(function(b,c){return ho({},Zr,b,c)}),ContactPosition:O(vp),ContactAddress:O(function(b,c){return ho({},$r,b,c)}),ContactVoiceTelephone:O(vp),ContactFacsimileTelephone:O(vp),ContactElectronicMailAddress:O(vp)}),Zr=Q(Sr,{ContactPerson:O(vp),ContactOrganization:O(vp)}),$r=Q(Sr,{AddressType:O(vp),Address:O(vp),City:O(vp),StateOrProvince:O(vp),PostCode:O(vp),Country:O(vp)}),Wr=Q(Sr,{Format:Zn(vp)}),Xr=Q(Sr,{Name:O(vp),Title:O(vp),Abstract:O(vp),KeywordList:O(Qr), +CRS:ao(vp),EX_GeographicBoundingBox:O(function(b,c){var d=ho({},as,b,c);if(d){var e=d.westBoundLongitude,f=d.southBoundLatitude,g=d.eastBoundLongitude,d=d.northBoundLatitude;return void 0===e||void 0===f||void 0===g||void 0===d?void 0:[e,f,g,d]}}),BoundingBox:ao(function(b){var c=[sp(b.getAttribute("minx")),sp(b.getAttribute("miny")),sp(b.getAttribute("maxx")),sp(b.getAttribute("maxy"))],d=[sp(b.getAttribute("resx")),sp(b.getAttribute("resy"))];return{crs:b.getAttribute("CRS"),extent:c,res:d}}),Dimension:ao(function(b){return{name:b.getAttribute("name"), +units:b.getAttribute("units"),unitSymbol:b.getAttribute("unitSymbol"),"default":b.getAttribute("default"),multipleValues:qp(b.getAttribute("multipleValues")),nearestValue:qp(b.getAttribute("nearestValue")),current:qp(b.getAttribute("current")),values:vp(b)}}),Attribution:O(function(b,c){return ho({},bs,b,c)}),AuthorityURL:ao(function(b,c){var d=Lr(b,c);if(d)return d.name=b.getAttribute("name"),d}),Identifier:ao(vp),MetadataURL:ao(function(b,c){var d=Lr(b,c);if(d)return d.type=b.getAttribute("type"), +d}),DataURL:ao(Lr),FeatureListURL:ao(Lr),Style:ao(function(b,c){return ho({},cs,b,c)}),MinScaleDenominator:O(rp),MaxScaleDenominator:O(rp),Layer:ao(function(b,c){var d=c[c.length-1],e=ho({},Xr,b,c);if(e){var f=qp(b.getAttribute("queryable"));void 0===f&&(f=d.queryable);e.queryable=void 0!==f?f:!1;f=up(b.getAttribute("cascaded"));void 0===f&&(f=d.cascaded);e.cascaded=f;f=qp(b.getAttribute("opaque"));void 0===f&&(f=d.opaque);e.opaque=void 0!==f?f:!1;f=qp(b.getAttribute("noSubsets"));void 0===f&&(f= +d.noSubsets);e.noSubsets=void 0!==f?f:!1;(f=sp(b.getAttribute("fixedWidth")))||(f=d.fixedWidth);e.fixedWidth=f;(f=sp(b.getAttribute("fixedHeight")))||(f=d.fixedHeight);e.fixedHeight=f;["Style","CRS","AuthorityURL"].forEach(function(b){if(b in d){var c=Ha(e,b),c=c.concat(d[b]);e[b]=c}});"EX_GeographicBoundingBox BoundingBox Dimension Attribution MinScaleDenominator MaxScaleDenominator".split(" ").forEach(function(b){b in e||(e[b]=d[b])});return e}})}),bs=Q(Sr,{Title:O(vp),OnlineResource:O(Fr),LogoURL:O(Pr)}), +as=Q(Sr,{westBoundLongitude:O(rp),eastBoundLongitude:O(rp),southBoundLatitude:O(rp),northBoundLatitude:O(rp)}),Vr=Q(Sr,{GetCapabilities:O(Nr),GetMap:O(Nr),GetFeatureInfo:O(Nr)}),Or=Q(Sr,{Format:ao(vp),DCPType:ao(function(b,c){return ho({},ds,b,c)})}),ds=Q(Sr,{HTTP:O(function(b,c){return ho({},es,b,c)})}),es=Q(Sr,{Get:O(Lr),Post:O(Lr)}),cs=Q(Sr,{Name:O(vp),Title:O(vp),Abstract:O(vp),LegendURL:ao(Pr),StyleSheetURL:O(Lr),StyleURL:O(Lr)}),Mr=Q(Sr,{Format:O(vp),OnlineResource:O(Fr)}),Rr=Q(Sr,{Keyword:Zn(vp)});var fs=new Td(6378137);function gs(b){Ic.call(this);b=b||{};this.a=null;this.c=ke;this.b=void 0;z(this,Kc("projection"),this.Ti,!1,this);z(this,Kc("tracking"),this.Ui,!1,this);void 0!==b.projection&&this.vf(Zd(b.projection));void 0!==b.trackingOptions&&this.ig(b.trackingOptions);this.Xc(void 0!==b.tracking?b.tracking:!1)}y(gs,Ic);k=gs.prototype;k.ba=function(){this.Xc(!1);gs.ka.ba.call(this)};k.Ti=function(){var b=this.tf();b&&(this.c=ce(Zd("EPSG:4326"),b),this.a&&this.C("position",this.c(this.a)))}; +k.Ui=function(){if(ch){var b=this.uf();b&&void 0===this.b?this.b=ba.navigator.geolocation.watchPosition(ra(this.Kk,this),ra(this.Lk,this),this.hf()):b||void 0===this.b||(ba.navigator.geolocation.clearWatch(this.b),this.b=void 0)}}; +k.Kk=function(b){var c=b.coords;this.C("accuracy",c.accuracy);this.C("altitude",null===c.altitude?void 0:c.altitude);this.C("altitudeAccuracy",null===c.altitudeAccuracy?void 0:c.altitudeAccuracy);this.C("heading",null===c.heading?void 0:Md(c.heading));this.a?(this.a[0]=c.longitude,this.a[1]=c.latitude):this.a=[c.longitude,c.latitude];b=this.c(this.a);this.C("position",b);this.C("speed",null===c.speed?void 0:c.speed);b=this.a;var d=c.accuracy,c=[],e;for(e=0;32>e;++e)mb(c,fs.offset(b,d,2*Math.PI*e/ +32));c.push(c[0],c[1]);b=new M(null);hi(b,"XY",c,[c.length]);b.Eb(this.c);this.C("accuracyGeometry",b);this.A()};k.Lk=function(b){b.type="error";this.Xc(!1);this.B(b)};k.Ug=function(){return this.get("accuracy")};k.Vg=function(){return this.get("accuracyGeometry")||null};k.Qi=function(){return this.get("altitude")};k.Xg=function(){return this.get("altitudeAccuracy")};k.Ri=function(){return this.get("heading")};k.Si=function(){return this.get("position")};k.tf=function(){return this.get("projection")}; +k.Kh=function(){return this.get("speed")};k.uf=function(){return this.get("tracking")};k.hf=function(){return this.get("trackingOptions")};k.vf=function(b){this.C("projection",b)};k.Xc=function(b){this.C("tracking",b)};k.ig=function(b){this.C("trackingOptions",b)};function Y(b,c,d){Fg.call(this);this.se(b,c?c:0,d)}y(Y,Fg);k=Y.prototype;k.clone=function(){var b=new Y(null);Hg(b,this.b,this.o.slice());b.A();return b};k.Ia=function(b,c,d,e){var f=this.o;b-=f[0];var g=c-f[1];c=b*b+g*g;if(c<e){if(0===c)for(e=0;e<this.a;++e)d[e]=f[e];else for(e=this.ee()/Math.sqrt(c),d[0]=f[0]+e*b,d[1]=f[1]+e*g,e=2;e<this.a;++e)d[e]=f[e];d.length=this.a;return c}return e};k.sb=function(b,c){var d=this.o,e=b-d[0],d=c-d[1];return e*e+d*d<=hs(this)}; +k.lc=function(){return this.o.slice(0,this.a)};k.Dc=function(b){var c=this.o,d=c[this.a]-c[0];return kd(c[0]-d,c[1]-d,c[0]+d,c[1]+d,b)};k.ee=function(){return Math.sqrt(hs(this))};function hs(b){var c=b.o[b.a]-b.o[0];b=b.o[b.a+1]-b.o[1];return c*c+b*b}k.N=function(){return"Circle"};k.ta=function(b){var c=this.G();return Hd(b,c)?(c=this.lc(),b[0]<=c[0]&&b[2]>=c[0]||b[1]<=c[1]&&b[3]>=c[1]?!0:xd(b,this.Qe,this)):!1}; +k.ej=function(b){var c=this.a,d=b.slice();d[c]=d[0]+(this.o[c]-this.o[0]);var e;for(e=1;e<c;++e)d[c+e]=b[e];Hg(this,this.b,d);this.A()};k.se=function(b,c,d){if(b){Ig(this,d,b,0);this.o||(this.o=[]);d=this.o;b=Ph(d,b);d[b++]=d[0]+c;var e;c=1;for(e=this.a;c<e;++c)d[b++]=d[c];d.length=b}else Hg(this,"XY",null);this.A()};k.ml=function(b){this.o[this.a]=this.o[0]+b;this.A()};function is(b,c,d,e,f,g,h){kk.call(this,b,c,d,0,e);this.j=f;this.a=new Image;null!==g&&(this.a.crossOrigin=g);this.g={};this.f=null;this.state=0;this.i=h}y(is,kk);is.prototype.c=function(b){if(void 0!==b){var c;b=u(b);if(b in this.g)return this.g[b];Da(this.g)?c=this.a:c=this.a.cloneNode(!1);return this.g[b]=c}return this.a};is.prototype.l=function(){this.state=3;this.f.forEach(yc);this.f=null;lk(this)}; +is.prototype.u=function(){void 0===this.resolution&&(this.resolution=Dd(this.extent)/this.a.height);this.state=2;this.f.forEach(yc);this.f=null;lk(this)};is.prototype.load=function(){0==this.state&&(this.state=1,lk(this),this.f=[wc(this.a,"error",this.l,!1,this),wc(this.a,"load",this.u,!1,this)],this.i(this,this.j))};function js(b,c){Xb.call(this,b);this.feature=c}y(js,Xb); +function ks(b){$k.call(this,{handleDownEvent:ls,handleEvent:ms,handleUpEvent:ns});this.ca=null;this.I=!1;this.lb=b.source?b.source:null;this.Ea=b.features?b.features:null;this.pd=b.snapTolerance?b.snapTolerance:12;this.L=b.type;this.b=os(this.L);this.ya=b.minPoints?b.minPoints:this.b===ps?3:2;this.ra=b.maxPoints?b.maxPoints:Infinity;var c=b.geometryFunction;if(!c)if("Circle"===this.L)c=function(b,c){var d=c?c:new Y([NaN,NaN]);d.se(b[0],Math.sqrt(bd(b[0],b[1])));return d};else{var d,c=this.b;c===qs? +d=L:c===rs?d=S:c===ps&&(d=M);c=function(b,c){var g=c;g?g.ia(b):g=new d(b);return g}}this.v=c;this.J=this.u=this.a=this.F=this.g=this.i=null;this.rg=b.clickTolerance?b.clickTolerance*b.clickTolerance:36;this.ea=new J({source:new K({useSpatialIndex:!1,wrapX:b.wrapX?b.wrapX:!1}),style:b.style?b.style:ss()});this.$a=b.geometryName;this.od=b.condition?b.condition:Wk;this.qa=b.freehandCondition?b.freehandCondition:Xk;z(this,Kc("active"),this.mg,!1,this)}y(ks,$k); +function ss(){var b=vh();return function(c){return b[c.R().N()]}}k=ks.prototype;k.setMap=function(b){ks.ka.setMap.call(this,b);this.mg()};function ms(b){var c=!this.I;this.I&&b.type===ik?(ts(this,b),c=!1):b.type===hk?c=us(this,b):b.type===bk&&(c=!1);return al.call(this,b)&&c}function ls(b){if(this.od(b))return this.ca=b.pixel,!0;if(this.b!==rs&&this.b!==ps||!this.qa(b))return!1;this.ca=b.pixel;this.I=!0;this.i||vs(this,b);return!0} +function ns(b){this.I=!1;var c=this.ca,d=b.pixel,e=c[0]-d[0],c=c[1]-d[1],d=!0;e*e+c*c<=this.rg&&(us(this,b),this.i?this.b===ws?this.ec():xs(this,b)?this.ec():ts(this,b):(vs(this,b),this.b===qs&&this.ec()),d=!1);return d} +function us(b,c){if(b.i){var d=c.coordinate,e=b.g.R(),f;b.b===qs?f=b.a:b.b===ps?(f=b.a[0],f=f[f.length-1],xs(b,c)&&(d=b.i.slice())):(f=b.a,f=f[f.length-1]);f[0]=d[0];f[1]=d[1];b.v(b.a,e);b.F&&b.F.R().ia(d);e instanceof M&&b.b!==ps?(b.u||(b.u=new Ym(new S(null))),e=e.cf(0),d=b.u.R(),$o(d,e.b,e.ga())):b.J&&(d=b.u.R(),d.ia(b.J));ys(b)}else d=c.coordinate.slice(),b.F?b.F.R().ia(d):(b.F=new Ym(new L(d)),ys(b));return!0} +function xs(b,c){var d=!1;if(b.g){var e=!1,f=[b.i];b.b===rs?e=b.a.length>b.ya:b.b===ps&&(e=b.a[0].length>b.ya,f=[b.a[0][0],b.a[0][b.a[0].length-2]]);if(e)for(var e=c.map,g=0,h=f.length;g<h;g++){var l=f[g],m=e.Ga(l),n=c.pixel,d=n[0]-m[0],m=n[1]-m[1],n=b.I&&b.qa(c)?1:b.pd;if(d=Math.sqrt(d*d+m*m)<=n){b.i=l;break}}}return d} +function vs(b,c){var d=c.coordinate;b.i=d;b.b===qs?b.a=d.slice():b.b===ps?(b.a=[[d.slice(),d.slice()]],b.J=b.a[0]):(b.a=[d.slice(),d.slice()],b.b===ws&&(b.J=b.a));b.J&&(b.u=new Ym(new S(b.J)));d=b.v(b.a);b.g=new Ym;b.$a&&b.g.ld(b.$a);b.g.Xa(d);ys(b);b.B(new js("drawstart",b.g))} +function ts(b,c){var d=c.coordinate,e=b.g.R(),f,g;if(b.b===rs)b.i=d.slice(),g=b.a,g.push(d.slice()),f=g.length>b.ra,b.v(g,e);else if(b.b===ps){g=b.a[0];g.push(d.slice());if(f=g.length>b.ra)b.i=g[0];b.v(b.a,e)}ys(b);f&&b.ec()}k.Tk=function(){var b=this.g.R(),c,d;this.b===rs?(c=this.a,c.splice(-2,1),this.v(c,b)):this.b===ps&&(c=this.a[0],c.splice(-2,1),d=this.u.R(),d.ia(c),this.v(this.a,b));0===c.length&&(this.i=null);ys(this)}; +k.ec=function(){var b=zs(this),c=this.a,d=b.R();this.b===rs?(c.pop(),this.v(c,d)):this.b===ps&&(c[0].pop(),c[0].push(c[0][0]),this.v(c,d));"MultiPoint"===this.L?b.Xa(new U([c])):"MultiLineString"===this.L?b.Xa(new T([c])):"MultiPolygon"===this.L&&b.Xa(new V([c]));this.B(new js("drawend",b));this.Ea&&this.Ea.push(b);this.lb&&this.lb.bd(b)};function zs(b){b.i=null;var c=b.g;c&&(b.g=null,b.F=null,b.u=null,b.ea.da().clear(!0));return c} +k.mj=function(b){var c=b.R();this.g=b;this.a=c.T();b=this.a[this.a.length-1];this.i=b.slice();this.a.push(b.slice());ys(this);this.B(new js("drawstart",this.g))};k.yb=Ce;function ys(b){var c=[];b.g&&c.push(b.g);b.u&&c.push(b.u);b.F&&c.push(b.F);b=b.ea.da();b.clear(!0);b.rd(c)}k.mg=function(){var b=this.H,c=this.j();b&&c||zs(this);this.ea.setMap(c?b:null)}; +function os(b){var c;"Point"===b||"MultiPoint"===b?c=qs:"LineString"===b||"MultiLineString"===b?c=rs:"Polygon"===b||"MultiPolygon"===b?c=ps:"Circle"===b&&(c=ws);return c}var qs="Point",rs="LineString",ps="Polygon",ws="Circle";function As(b,c,d){Xb.call(this,b);this.features=c;this.mapBrowserPointerEvent=d}y(As,Xb); +function Bs(b){$k.call(this,{handleDownEvent:Cs,handleDragEvent:Ds,handleEvent:Es,handleUpEvent:Fs});this.ra=b.deleteCondition?b.deleteCondition:Fe(Wk,Vk);this.qa=this.b=null;this.ca=[0,0];this.v=this.I=!1;this.a=new no;this.F=void 0!==b.pixelTolerance?b.pixelTolerance:10;this.i=this.ea=!1;this.g=null;this.J=new J({source:new K({useSpatialIndex:!1,wrapX:!!b.wrapX}),style:b.style?b.style:Gs(),updateWhileAnimating:!0,updateWhileInteracting:!0});this.L={Point:this.tj,LineString:this.Cf,LinearRing:this.Cf, +Polygon:this.uj,MultiPoint:this.rj,MultiLineString:this.qj,MultiPolygon:this.sj,GeometryCollection:this.pj};this.u=b.features;this.u.forEach(this.he,this);z(this.u,"add",this.nj,!1,this);z(this.u,"remove",this.oj,!1,this)}y(Bs,$k);k=Bs.prototype;k.he=function(b){var c=b.R();c.N()in this.L&&this.L[c.N()].call(this,b,c);(c=this.H)&&Hs(this,this.ca,c);z(b,"change",this.Bf,!1,this)};function Is(b,c){b.v||(b.v=!0,b.B(new As("modifystart",b.u,c)))} +function Js(b,c){Ks(b,c);b.b&&0===b.u.qb()&&(b.J.da().sc(b.b),b.b=null);xc(c,"change",b.Bf,!1,b)}function Ks(b,c){var d=b.a,e=[];d.forEach(function(b){c===b.feature&&e.push(b)});for(var f=e.length-1;0<=f;--f)d.remove(e[f])}k.setMap=function(b){this.J.setMap(b);Bs.ka.setMap.call(this,b)};k.nj=function(b){this.he(b.element)};k.Bf=function(b){this.i||(b=b.target,Js(this,b),this.he(b))};k.oj=function(b){Js(this,b.element)}; +k.tj=function(b,c){var d=c.T(),d={feature:b,geometry:c,ha:[d,d]};this.a.oa(c.G(),d)};k.rj=function(b,c){var d=c.T(),e,f,g;f=0;for(g=d.length;f<g;++f)e=d[f],e={feature:b,geometry:c,depth:[f],index:f,ha:[e,e]},this.a.oa(c.G(),e)};k.Cf=function(b,c){var d=c.T(),e,f,g,h;e=0;for(f=d.length-1;e<f;++e)g=d.slice(e,e+2),h={feature:b,geometry:c,index:e,ha:g},this.a.oa(gd(g),h)}; +k.qj=function(b,c){var d=c.T(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:b,geometry:c,depth:[h],index:f,ha:m},this.a.oa(gd(m),n)};k.uj=function(b,c){var d=c.T(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:b,geometry:c,depth:[h],index:f,ha:m},this.a.oa(gd(m),n)}; +k.sj=function(b,c){var d=c.T(),e,f,g,h,l,m,n,p,q,r;m=0;for(n=d.length;m<n;++m)for(p=d[m],h=0,l=p.length;h<l;++h)for(e=p[h],f=0,g=e.length-1;f<g;++f)q=e.slice(f,f+2),r={feature:b,geometry:c,depth:[h,m],index:f,ha:q},this.a.oa(gd(q),r)};k.pj=function(b,c){var d,e=c.a;for(d=0;d<e.length;++d)this.L[e[d].N()].call(this,b,e[d])};function Ls(b,c){var d=b.b;d?d.R().ia(c):(d=new Ym(new L(c)),b.b=d,b.J.da().bd(d))}function Ms(b,c){return b.index-c.index} +function Cs(b){Hs(this,b.pixel,b.map);this.g=[];this.v=!1;var c=this.b;if(c){var d=[],c=c.R().T(),e=gd([c]),e=po(this.a,e),f={};e.sort(Ms);for(var g=0,h=e.length;g<h;++g){var l=e[g],m=l.ha,n=u(l.feature),p=l.depth;p&&(n+="-"+p.join("-"));f[n]||(f[n]=Array(2));if(Zc(m[0],c)&&!f[n][0])this.g.push([l,0]),f[n][0]=l;else if(Zc(m[1],c)&&!f[n][1]){if("LineString"!==l.geometry.N()&&"MultiLineString"!==l.geometry.N()||!f[n][0]||0!==f[n][0].index)this.g.push([l,1]),f[n][1]=l}else u(m)in this.qa&&!f[n][0]&& +!f[n][1]&&d.push([l,c])}d.length&&Is(this,b);for(g=d.length-1;0<=g;--g)this.ti.apply(this,d[g])}return!!this.b} +function Ds(b){this.I=!1;Is(this,b);b=b.coordinate;for(var c=0,d=this.g.length;c<d;++c){for(var e=this.g[c],f=e[0],g=f.depth,h=f.geometry,l=h.T(),m=f.ha,e=e[1];b.length<h.pa();)b.push(0);switch(h.N()){case "Point":l=b;m[0]=m[1]=b;break;case "MultiPoint":l[f.index]=b;m[0]=m[1]=b;break;case "LineString":l[f.index+e]=b;m[e]=b;break;case "MultiLineString":l[g[0]][f.index+e]=b;m[e]=b;break;case "Polygon":l[g[0]][f.index+e]=b;m[e]=b;break;case "MultiPolygon":l[g[1]][g[0]][f.index+e]=b,m[e]=b}f=h;this.i= +!0;f.ia(l);this.i=!1}Ls(this,b)}function Fs(b){for(var c,d=this.g.length-1;0<=d;--d)c=this.g[d][0],this.a.update(gd(c.ha),c);this.v&&(this.B(new As("modifyend",this.u,b)),this.v=!1);return!1} +function Es(b){if(!(b instanceof Xj))return!0;var c;b.map.ja().b.slice()[1]||b.type!=hk||this.D||(this.ca=b.pixel,Hs(this,b.pixel,b.map));if(this.b&&this.ra(b))if(b.type==ck&&this.I)c=!0;else{this.b.R();Is(this,b);c=this.g;var d={},e,f,g,h,l,m,n,p,q;for(l=c.length-1;0<=l;--l)if(g=c[l],p=g[0],h=p.geometry,f=h.T(),q=u(p.feature),p.depth&&(q+="-"+p.depth.join("-")),n=e=m=void 0,0===g[1]?(e=p,m=p.index):1==g[1]&&(n=p,m=p.index+1),q in d||(d[q]=[n,e,m]),g=d[q],void 0!==n&&(g[0]=n),void 0!==e&&(g[1]=e), +void 0!==g[0]&&void 0!==g[1]){e=f;q=!1;n=m-1;switch(h.N()){case "MultiLineString":f[p.depth[0]].splice(m,1);q=!0;break;case "LineString":f.splice(m,1);q=!0;break;case "MultiPolygon":e=e[p.depth[1]];case "Polygon":e=e[p.depth[0]],4<e.length&&(m==e.length-1&&(m=0),e.splice(m,1),q=!0,0===m&&(e.pop(),e.push(e[0]),n=e.length-1))}q&&(this.a.remove(g[0]),this.a.remove(g[1]),e=h,this.i=!0,e.ia(f),this.i=!1,f={depth:p.depth,feature:p.feature,geometry:p.geometry,index:n,ha:[g[0].ha[0],g[1].ha[1]]},this.a.oa(gd(f.ha), +f),Ns(this,h,m,p.depth,-1),this.b&&(this.J.da().sc(this.b),this.b=null))}c=!0;this.B(new As("modifyend",this.u,b));this.v=!1}b.type==ck&&(this.I=!1);return al.call(this,b)&&!c} +function Hs(b,c,d){function e(b,c){return cd(f,b.ha)-cd(f,c.ha)}var f=d.ua(c),g=d.ua([c[0]-b.F,c[1]+b.F]),h=d.ua([c[0]+b.F,c[1]-b.F]),g=gd([g,h]),g=po(b.a,g);if(0<g.length){g.sort(e);var h=g[0].ha,l=Wc(f,h),m=d.Ga(l);if(Math.sqrt(bd(c,m))<=b.F){c=d.Ga(h[0]);d=d.Ga(h[1]);c=bd(m,c);d=bd(m,d);b.ea=Math.sqrt(Math.min(c,d))<=b.F;b.ea&&(l=c>d?h[1]:h[0]);Ls(b,l);d={};d[u(h)]=!0;c=1;for(m=g.length;c<m;++c)if(l=g[c].ha,Zc(h[0],l[0])&&Zc(h[1],l[1])||Zc(h[0],l[1])&&Zc(h[1],l[0]))d[u(l)]=!0;else break;b.qa=d; +return}}b.b&&(b.J.da().sc(b.b),b.b=null)} +k.ti=function(b,c){for(var d=b.ha,e=b.feature,f=b.geometry,g=b.depth,h=b.index,l;c.length<f.pa();)c.push(0);switch(f.N()){case "MultiLineString":l=f.T();l[g[0]].splice(h+1,0,c);break;case "Polygon":l=f.T();l[g[0]].splice(h+1,0,c);break;case "MultiPolygon":l=f.T();l[g[1]][g[0]].splice(h+1,0,c);break;case "LineString":l=f.T();l.splice(h+1,0,c);break;default:return}this.i=!0;f.ia(l);this.i=!1;l=this.a;l.remove(b);Ns(this,f,h,g,1);var m={ha:[d[0],c],feature:e,geometry:f,depth:g,index:h};l.oa(gd(m.ha), +m);this.g.push([m,1]);d={ha:[c,d[1]],feature:e,geometry:f,depth:g,index:h+1};l.oa(gd(d.ha),d);this.g.push([d,0]);this.I=!0};function Ns(b,c,d,e,f){ro(b.a,c.G(),function(b){b.geometry===c&&(void 0===e||void 0===b.depth||sb(b.depth,e))&&b.index>d&&(b.index+=f)})}function Gs(){var b=vh();return function(){return b.Point}};function Os(b,c,d,e){Xb.call(this,b);this.selected=c;this.deselected=d;this.mapBrowserEvent=e}y(Os,Xb); +function Ps(b){Ok.call(this,{handleEvent:Qs});b=b?b:{};this.D=b.condition?b.condition:Vk;this.i=b.addCondition?b.addCondition:Ce;this.v=b.removeCondition?b.removeCondition:Ce;this.F=b.toggleCondition?b.toggleCondition:Xk;this.u=b.multi?b.multi:!1;this.c=b.filter?b.filter:De;var c;if(b.layers)if(la(b.layers))c=b.layers;else{var d=b.layers;c=function(b){return 0<=d.indexOf(b)}}else c=De;this.g=c;this.a={};this.b=new J({source:new K({useSpatialIndex:!1,features:b.features,wrapX:b.wrapX}),style:b.style? +b.style:Rs(),updateWhileAnimating:!0,updateWhileInteracting:!0});b=this.b.da().b;z(b,"add",this.vj,!1,this);z(b,"remove",this.yj,!1,this)}y(Ps,Ok);k=Ps.prototype;k.wj=function(){return this.b.da().b};k.xj=function(b){b=u(b);return this.a[b]}; +function Qs(b){if(!this.D(b))return!0;var c=this.i(b),d=this.v(b),e=this.F(b),f=!c&&!d&&!e,g=b.map,h=this.b.da().b,l=[],m=[],n=!1;if(f)g.Fd(b.pixel,function(b,c){if(c&&this.c(b,c)){m.push(b);var d=u(b);this.a[d]=c;return!this.u}},this,this.g),0<m.length&&1==h.qb()&&h.item(0)==m[0]||(n=!0,0!==h.qb()&&(l=Array.prototype.concat(h.a),h.clear()),h.$d(m),0===m.length?Ea(this.a):0<l.length&&l.forEach(function(b){b=u(b);delete this.a[b]},this));else{g.Fd(b.pixel,function(b,f){if(!(0<=h.a.indexOf(b))){if((c|| +e)&&this.c(b,f)){m.push(b);var g=u(b);this.a[g]=f}}else if(d||e)l.push(b),g=u(b),delete this.a[g]},this,this.g);for(f=l.length-1;0<=f;--f)h.remove(l[f]);h.$d(m);if(0<m.length||0<l.length)n=!0}n&&this.B(new Os("select",m,l,b));return"pointermove"==b.type}k.setMap=function(b){var c=this.H,d=this.b.da().b;null===c||d.forEach(c.kg,c);Ps.ka.setMap.call(this,b);this.b.setMap(b);null===b||d.forEach(b.jg,b)}; +function Rs(){var b=vh();mb(b.Polygon,b.LineString);mb(b.GeometryCollection,b.LineString);return function(c){return b[c.R().N()]}}k.vj=function(b){b=b.element;var c=this.H;null===c||c.jg(b)};k.yj=function(b){b=b.element;var c=this.H;null===c||c.kg(b)};function Ss(b){$k.call(this,{handleEvent:Ts,handleDownEvent:De,handleUpEvent:Us});b=b?b:{};this.i=b.source?b.source:null;this.g=b.features?b.features:null;this.ca=[];this.v={};this.F={};this.I={};this.u={};this.J=null;this.b=void 0!==b.pixelTolerance?b.pixelTolerance:10;this.ea=ra(Vs,this);this.a=new no;this.L={Point:this.Ej,LineString:this.Ff,LinearRing:this.Ff,Polygon:this.Fj,MultiPoint:this.Cj,MultiLineString:this.Bj,MultiPolygon:this.Dj,GeometryCollection:this.Aj}}y(Ss,$k);k=Ss.prototype; +k.mc=function(b,c){var d=void 0!==c?c:!0,e=b.R(),f=this.L[e.N()];if(f){var g=u(b);this.I[g]=e.G(hd());f.call(this,b,e);d&&(this.F[g]=e.K("change",ra(this.Wh,this,b),this),this.v[g]=b.K(Kc(b.a),this.zj,this))}};k.Qg=function(b){this.mc(b)};k.Sg=function(b){this.nc(b)};k.Df=function(b){var c;b instanceof wo?c=b.feature:b instanceof Mc&&(c=b.element);this.mc(c)};k.Ef=function(b){var c;b instanceof wo?c=b.feature:b instanceof Mc&&(c=b.element);this.nc(c)}; +k.zj=function(b){b=b.b;this.nc(b,!0);this.mc(b,!0)};k.Wh=function(b){if(this.D){var c=u(b);c in this.u||(this.u[c]=b)}else this.lg(b)};k.nc=function(b,c){var d=void 0!==c?c:!0,e=u(b),f=this.I[e];if(f){var g=this.a,h=[];ro(g,f,function(c){b===c.feature&&h.push(c)});for(f=h.length-1;0<=f;--f)g.remove(h[f]);d&&(yc(this.F[e]),delete this.F[e],yc(this.v[e]),delete this.v[e])}}; +k.setMap=function(b){var c=this.H,d=this.ca,e;this.g?e=this.g:this.i&&(e=this.i.ke());c&&(d.forEach(Gc),d.length=0,e.forEach(this.Sg,this));Ss.ka.setMap.call(this,b);b&&(this.g?(d.push(this.g.K("add",this.Df,this)),d.push(this.g.K("remove",this.Ef,this))):this.i&&(d.push(this.i.K("addfeature",this.Df,this)),d.push(this.i.K("removefeature",this.Ef,this))),e.forEach(this.Qg,this))};k.yb=Ce;k.lg=function(b){this.nc(b,!1);this.mc(b,!1)}; +k.Aj=function(b,c){var d,e=c.a;for(d=0;d<e.length;++d)this.L[e[d].N()].call(this,b,e[d])};k.Ff=function(b,c){var d=c.T(),e,f,g,h;e=0;for(f=d.length-1;e<f;++e)g=d.slice(e,e+2),h={feature:b,ha:g},this.a.oa(gd(g),h)};k.Bj=function(b,c){var d=c.T(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:b,ha:m},this.a.oa(gd(m),n)};k.Cj=function(b,c){var d=c.T(),e,f,g;f=0;for(g=d.length;f<g;++f)e=d[f],e={feature:b,ha:[e,e]},this.a.oa(c.G(),e)}; +k.Dj=function(b,c){var d=c.T(),e,f,g,h,l,m,n,p,q,r;m=0;for(n=d.length;m<n;++m)for(p=d[m],h=0,l=p.length;h<l;++h)for(e=p[h],f=0,g=e.length-1;f<g;++f)q=e.slice(f,f+2),r={feature:b,ha:q},this.a.oa(gd(q),r)};k.Ej=function(b,c){var d=c.T(),d={feature:b,ha:[d,d]};this.a.oa(c.G(),d)};k.Fj=function(b,c){var d=c.T(),e,f,g,h,l,m,n;h=0;for(l=d.length;h<l;++h)for(e=d[h],f=0,g=e.length-1;f<g;++f)m=e.slice(f,f+2),n={feature:b,ha:m},this.a.oa(gd(m),n)}; +function Ts(b){var c,d,e=b.pixel,f=b.coordinate;c=b.map;var g=c.ua([e[0]-this.b,e[1]+this.b]);d=c.ua([e[0]+this.b,e[1]-this.b]);var g=gd([g,d]),h=po(this.a,g),l=!1,g=!1,m=null;d=null;0<h.length&&(this.J=f,h.sort(this.ea),h=h[0].ha,m=Wc(f,h),d=c.Ga(m),Math.sqrt(bd(e,d))<=this.b&&(g=!0,e=c.Ga(h[0]),f=c.Ga(h[1]),e=bd(d,e),f=bd(d,f),l=Math.sqrt(Math.min(e,f))<=this.b))&&(m=e>f?h[1]:h[0],d=c.Ga(m),d=[Math.round(d[0]),Math.round(d[1])]);c=m;g&&(b.coordinate=c.slice(0,2),b.pixel=d);return al.call(this,b)} +function Us(){var b=ya(this.u);b.length&&(b.forEach(this.lg,this),this.u={});return!1}function Vs(b,c){return cd(this.J,b.ha)-cd(this.J,c.ha)};function Ws(b){b=b||{};Pm.call(this,{attributions:b.attributions,logo:b.logo,projection:b.projection,resolutions:b.resolutions});this.ra=void 0!==b.crossOrigin?b.crossOrigin:null;this.l=b.url;this.L=void 0!==b.imageLoadFunction?b.imageLoadFunction:Wm;this.c=b.params;this.v=!0;Xs(this);this.ea=b.serverType;this.Ea=void 0!==b.hidpi?b.hidpi:!0;this.b=null;this.U=[0,0];this.ca=0;this.u=void 0!==b.ratio?b.ratio:1.5}y(Ws,Pm);var Ys=[101,101];k=Ws.prototype; +k.Oj=function(b,c,d,e){if(void 0!==this.l){var f=Fd(b,c,0,Ys),g={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.c.LAYERS};La(g,this.c,e);e=Math.floor((f[3]-b[1])/c);g[this.v?"I":"X"]=Math.floor((b[0]-f[0])/c);g[this.v?"J":"Y"]=e;return Zs(this,f,Ys,1,Zd(d),g)}};k.Pj=function(){return this.c}; +k.Hd=function(b,c,d,e){if(void 0===this.l)return null;c=Qm(this,c);1==d||this.Ea&&void 0!==this.ea||(d=1);b=b.slice();var f=(b[0]+b[2])/2,g=(b[1]+b[3])/2,h=c/d,l=Bd(b)/h,h=Dd(b)/h,m=this.b;if(m&&this.ca==this.f&&m.V()==c&&m.b==d&&qd(m.G(),b))return m;if(1!=this.u){var m=this.u*Bd(b)/2,n=this.u*Dd(b)/2;b[0]=f-m;b[1]=g-n;b[2]=f+m;b[3]=g+n}f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};La(f,this.c);this.U[0]=Math.ceil(l*this.u);this.U[1]=Math.ceil(h*this.u);e=Zs(this, +b,this.U,d,e,f);this.b=new is(b,c,d,this.j,e,this.ra,this.L);this.ca=this.f;z(this.b,"change",this.ya,!1,this);return this.b};k.rh=function(){return this.L}; +function Zs(b,c,d,e,f,g){g[b.v?"CRS":"SRS"]=f.a;"STYLES"in b.c||(g.STYLES=new String(""));if(1!=e)switch(b.ea){case "geoserver":e=90*e+.5|0;g.FORMAT_OPTIONS="FORMAT_OPTIONS"in g?g.FORMAT_OPTIONS+(";dpi:"+e):"dpi:"+e;break;case "mapserver":g.MAP_RESOLUTION=90*e;break;case "carmentaserver":case "qgis":g.DPI=90*e}g.WIDTH=d[0];g.HEIGHT=d[1];d=f.i;var h;b.v&&"ne"==d.substr(0,2)?h=[c[1],c[0],c[3],c[2]]:h=c;g.BBOX=h.join(",");return Zf(ag([b.l],g))}k.Ph=function(){return this.l}; +k.hl=function(b){this.b=null;this.L=b;this.A()};k.Qj=function(b){b!=this.l&&(this.l=b,this.b=null,this.A())};k.Rj=function(b){La(this.c,b);Xs(this);this.b=null;this.A()};function Xs(b){b.v=0<=Za(Ga(b.c,"VERSION","1.3.0"),"1.3")};function Z(b){b=b||{};var c=void 0!==b.params?b.params:{};G.call(this,{attributions:b.attributions,crossOrigin:b.crossOrigin,logo:b.logo,opaque:!Ga(c,"TRANSPARENT",!0),projection:b.projection,reprojectionErrorThreshold:b.reprojectionErrorThreshold,tileGrid:b.tileGrid,tileLoadFunction:b.tileLoadFunction,tileUrlFunction:ra(this.ul,this),url:b.url,urls:b.urls,wrapX:void 0!==b.wrapX?b.wrapX:!0});this.v=void 0!==b.gutter?b.gutter:0;this.b=c;this.l=!0;this.I=b.serverType;this.ca=void 0!==b.hidpi?b.hidpi: +!0;this.U="";$s(this);this.ea=hd();at(this)}y(Z,G);k=Z.prototype; +k.Sj=function(b,c,d,e){d=Zd(d);var f=this.tileGrid;f||(f=this.Wa(d));c=f.Od(b,c);if(!(f.a.length<=c[0])){var g=f.V(c[0]),h=f.Ka(c,this.ea),f=fd(f.La(c[0]),this.c),l=this.v;0!==l&&(f=dd(f,l,this.c),h=ld(h,g*l,h));l={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.b.LAYERS};La(l,this.b,e);e=Math.floor((h[3]-b[1])/g);l[this.l?"I":"X"]=Math.floor((b[0]-h[0])/g);l[this.l?"J":"Y"]=e;return bt(this,c,f,h,1,d,l)}};k.Ze=function(){return this.v}; +k.Gb=function(b,c,d){return this.U+Z.ka.Gb.call(this,b,c,d)};k.Tj=function(){return this.b}; +function bt(b,c,d,e,f,g,h){var l=b.urls;if(l){h.WIDTH=d[0];h.HEIGHT=d[1];h[b.l?"CRS":"SRS"]=g.a;"STYLES"in b.b||(h.STYLES=new String(""));if(1!=f)switch(b.I){case "geoserver":d=90*f+.5|0;h.FORMAT_OPTIONS="FORMAT_OPTIONS"in h?h.FORMAT_OPTIONS+(";dpi:"+d):"dpi:"+d;break;case "mapserver":h.MAP_RESOLUTION=90*f;break;case "carmentaserver":case "qgis":h.DPI=90*f}g=g.i;b.l&&"ne"==g.substr(0,2)&&(b=e[0],e[0]=e[1],e[1]=b,b=e[2],e[2]=e[3],e[3]=b);h.BBOX=e.join(",");return Zf(ag([1==l.length?l[0]:l[Tc((c[1]<< +c[0])+c[2],l.length)]],h))}}k.Lc=function(b,c,d){b=Z.ka.Lc.call(this,b,c,d);return 1!=c&&this.ca&&void 0!==this.I?ed(b,c,this.c):b};function $s(b){var c=0,d=[];if(b.urls){var e,f;e=0;for(f=b.urls.length;e<f;++e)d[c++]=b.urls[e]}for(var g in b.b)d[c++]=g+"-"+b.b[g];b.U=d.join("#")} +k.ul=function(b,c,d){var e=this.tileGrid;e||(e=this.Wa(d));if(!(e.a.length<=b[0])){1==c||this.ca&&void 0!==this.I||(c=1);var f=e.V(b[0]),g=e.Ka(b,this.ea),e=fd(e.La(b[0]),this.c),h=this.v;0!==h&&(e=dd(e,h,this.c),g=ld(g,f*h,g));1!=c&&(e=ed(e,c,this.c));f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};La(f,this.b);return bt(this,b,e,g,c,d,f)}};k.Uj=function(b){La(this.b,b);$s(this);at(this);this.A()};function at(b){b.l=0<=Za(Ga(b.b,"VERSION","1.3.0"),"1.3")};function ct(b){this.v=this.c=this.g=null;this.l=void 0!==b.fill?b.fill:null;this.I=[0,0];this.a=b.points;this.b=void 0!==b.radius?b.radius:b.radius1;this.i=void 0!==b.radius2?b.radius2:this.b;this.j=void 0!==b.angle?b.angle:0;this.f=void 0!==b.stroke?b.stroke:null;this.J=this.L=this.fa=null;var c=b.atlasManager,d="",e="",f=0,g=null,h,l=0;this.f&&(h=Xg(this.f.a),l=this.f.f,void 0===l&&(l=1),g=this.f.b,$g||(g=null),e=this.f.g,void 0===e&&(e="round"),d=this.f.c,void 0===d&&(d="round"),f=this.f.i,void 0=== +f&&(f=10));var m=2*(this.b+l)+1,d={strokeStyle:h,zc:l,size:m,lineCap:d,lineDash:g,lineJoin:e,miterLimit:f};if(void 0===c){this.c=document.createElement("CANVAS");this.c.height=m;this.c.width=m;var c=m=this.c.width,n=this.c.getContext("2d");this.Of(d,n,0,0);this.l?this.v=this.c:(n=this.v=document.createElement("CANVAS"),n.height=d.size,n.width=d.size,n=n.getContext("2d"),this.Nf(d,n,0,0))}else m=Math.round(m),(e=!this.l)&&(n=ra(this.Nf,this,d)),f=this.Sa(),n=c.add(f,m,m,ra(this.Of,this,d),n),this.c= +n.image,this.I=[n.offsetX,n.offsetY],c=n.image.width,this.v=e?n.si:this.c;this.fa=[m/2,m/2];this.L=[m,m];this.J=[c,c];kh.call(this,{opacity:1,rotateWithView:!1,rotation:void 0!==b.rotation?b.rotation:0,scale:1,snapToPixel:void 0!==b.snapToPixel?b.snapToPixel:!0})}y(ct,kh);k=ct.prototype;k.mb=function(){return this.fa};k.ck=function(){return this.j};k.dk=function(){return this.l};k.le=function(){return this.v};k.ib=function(){return this.c};k.Ic=function(){return this.J};k.tc=function(){return 2}; +k.Aa=function(){return this.I};k.ek=function(){return this.a};k.fk=function(){return this.b};k.Ih=function(){return this.i};k.Ya=function(){return this.L};k.gk=function(){return this.f};k.Xd=Id;k.load=Id;k.Ae=Id; +k.Of=function(b,c,d,e){var f;c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();this.i!==this.b&&(this.a*=2);for(d=0;d<=this.a;d++)e=2*d*Math.PI/this.a-Math.PI/2+this.j,f=0===d%2?this.b:this.i,c.lineTo(b.size/2+f*Math.cos(e),b.size/2+f*Math.sin(e));this.l&&(c.fillStyle=Xg(this.l.a),c.fill());this.f&&(c.strokeStyle=b.strokeStyle,c.lineWidth=b.zc,b.lineDash&&c.setLineDash(b.lineDash),c.lineCap=b.lineCap,c.lineJoin=b.lineJoin,c.miterLimit=b.miterLimit,c.stroke());c.closePath()}; +k.Nf=function(b,c,d,e){c.setTransform(1,0,0,1,0,0);c.translate(d,e);c.beginPath();this.i!==this.b&&(this.a*=2);var f;for(d=0;d<=this.a;d++)f=2*d*Math.PI/this.a-Math.PI/2+this.j,e=0===d%2?this.b:this.i,c.lineTo(b.size/2+e*Math.cos(f),b.size/2+e*Math.sin(f));c.fillStyle=gh;c.fill();this.f&&(c.strokeStyle=b.strokeStyle,c.lineWidth=b.zc,b.lineDash&&c.setLineDash(b.lineDash),c.stroke());c.closePath()}; +k.Sa=function(){var b=this.f?this.f.Sa():"-",c=this.l?this.l.Sa():"-";this.g&&b==this.g[1]&&c==this.g[2]&&this.b==this.g[3]&&this.i==this.g[4]&&this.j==this.g[5]&&this.a==this.g[6]||(this.g=["r"+b+c+(void 0!==this.b?this.b.toString():"-")+(void 0!==this.i?this.i.toString():"-")+(void 0!==this.j?this.j.toString():"-")+(void 0!==this.a?this.a.toString():"-"),b,c,this.b,this.i,this.j,this.a]);return this.g[0]};w("olcs.AbstractSynchronizer",re);re.prototype.synchronize=re.prototype.ze;ye.prototype.restartRenderLoop=ye.prototype.l;ye.prototype.setDebug=ye.prototype.L;w("olcs.Camera",wg);wg.prototype.setHeading=wg.prototype.gl;wg.prototype.getHeading=wg.prototype.vk;wg.prototype.setTilt=wg.prototype.ql;wg.prototype.getTilt=wg.prototype.Oh;wg.prototype.setDistance=wg.prototype.al;wg.prototype.getDistance=wg.prototype.uk;wg.prototype.setCenter=wg.prototype.yk;wg.prototype.getCenter=wg.prototype.tk; +wg.prototype.setPosition=wg.prototype.zk;wg.prototype.getPosition=wg.prototype.wk;wg.prototype.setAltitude=wg.prototype.Zk;wg.prototype.getAltitude=wg.prototype.Rf;wg.prototype.lookAt=wg.prototype.xk;wg.prototype.readFromView=wg.prototype.uc;wg.prototype.updateView=wg.prototype.zb; +w("olcs.core.computePixelSizeAtCoordinate",function(b,c){var d=b.camera,e=b.canvas,f=d.frustum,e=new Cesium.Cartesian2(e.clientWidth,e.clientHeight),d=Cesium.Cartesian3.magnitude(Cesium.Cartesian3.subtract(d.position,c,new Cesium.Cartesian3));return f.getPixelSize(e,d)});w("olcs.core.applyHeightOffsetToGeometry",function(b,c){b.Eb(function(b,e,f){if(ca(f)&&3<=f)for(b=0;b<e.length;b+=f)e[b+2]+=c;return e})});w("olcs.core.rotateAroundAxis",gg); +w("olcs.core.setHeadingUsingBottomCenter",function(b,c,d,e){var f=b.camera;b=lg(b,d);b=Cesium.Quaternion.fromAxisAngle(f.right,b);var g=Cesium.Matrix3.fromQuaternion(b),h=new Cesium.Cartesian3;Cesium.Cartesian3.subtract(f.position,d,h);b=new Cesium.Cartesian3;Cesium.Matrix3.multiplyByVector(g,h,b);Cesium.Cartesian3.add(b,d,b);d=Cesium.Matrix4.fromTranslation(b);gg(f,c,b,d,e)});w("olcs.core.pickOnTerrainOrEllipsoid",ig); +w("olcs.core.pickBottomPoint",function(b){var c=b.canvas,c=new Cesium.Cartesian2(c.clientWidth/2,c.clientHeight);return ig(b,c)});w("olcs.core.pickCenterPoint",jg); +w("olcs.core.computeSignedTiltAngleOnGlobe",function(b){var c=b.camera,d=new Cesium.Ray(c.position,c.direction);b=b.globe.pick(d,b);if(!b){var e=Cesium.IntersectionTests.rayEllipsoid(d,Cesium.Ellipsoid.WGS84);e&&(b=Cesium.Ray.getPoint(d,e.start))}if(b)return d=new Cesium.Cartesian3,Cesium.Ellipsoid.WGS84.geocentricSurfaceNormal(b,d),c=kg(c.direction,d,c.right)-Math.PI,Cesium.Math.convertLongitudeRange(c)});w("olcs.core.computeAngleToZenith",lg);w("olcs.core.lookAt",mg); +w("olcs.core.extentToRectangle",ng);w("olcs.core.tileLayerToImageryLayer",og);w("olcs.core.updateCesiumLayerProperties",rg);w("olcs.core.ol4326CoordinateToCesiumCartesian",sg);w("olcs.core.ol4326CoordinateArrayToCsCartesians",tg);w("olcs.core.olGeometryCloneTo4326",ug);w("olcs.core.convertColorToCesium",vg);w("olcs.DragBox",Cg);Cg.prototype.setScene=Cg.prototype.j;Cg.prototype.listen=Cg.prototype.Uc;w("olcs.FeatureConverter",Jg);Jg.prototype.csAddBillboard=Jg.prototype.Se; +Jg.prototype.olCircleGeometryToCesium=Jg.prototype.nf;Jg.prototype.olLineStringGeometryToCesium=Jg.prototype.Yd;Jg.prototype.olPolygonGeometryToCesium=Jg.prototype.Zd;Jg.prototype.getHeightReference=Jg.prototype.Hc;Jg.prototype.olPointGeometryToCesium=Jg.prototype.Wc;Jg.prototype.olMultiGeometryToCesium=Jg.prototype.pf;Jg.prototype.olGeometry4326TextPartToCesium=Jg.prototype.of;Jg.prototype.olStyleToCesium=Jg.prototype.qf;Jg.prototype.computePlainStyle=Jg.prototype.wd; +Jg.prototype.olFeatureToCesium=Jg.prototype.Vc;Jg.prototype.olVectorLayerToCesium=Jg.prototype.rf;Jg.prototype.convert=Jg.prototype.convert;w("olcs.OLCesium",xh);xh.prototype.getCamera=xh.prototype.$g;xh.prototype.getOlMap=xh.prototype.Dh;xh.prototype.getCesiumScene=xh.prototype.ah;xh.prototype.getDataSources=xh.prototype.fh;xh.prototype.getEnabled=xh.prototype.hh;xh.prototype.setEnabled=xh.prototype.bl;xh.prototype.warmUp=xh.prototype.Bl;xh.prototype.setBlockCesiumRendering=xh.prototype.re; +xh.prototype.enableAutoRenderLoop=xh.prototype.Og;xh.prototype.getAutoRenderLoop=xh.prototype.Yg;xh.prototype.setResolutionScale=xh.prototype.nl;w("olcs.RasterSynchronizer",Rg);w("olcs.VectorSynchronizer",wh);w("olcs.GaRasterSynchronizer",yh);w("ol.Collection",A);A.prototype.clear=A.prototype.clear;A.prototype.extend=A.prototype.$d;A.prototype.forEach=A.prototype.forEach;A.prototype.getArray=A.prototype.Li;A.prototype.item=A.prototype.item;A.prototype.getLength=A.prototype.qb; +A.prototype.insertAt=A.prototype.Qc;A.prototype.pop=A.prototype.pop;A.prototype.push=A.prototype.push;A.prototype.remove=A.prototype.remove;A.prototype.removeAt=A.prototype.qe;A.prototype.setAt=A.prototype.$k;A.prototype.get=A.prototype.get;A.prototype.getKeys=A.prototype.P;A.prototype.getProperties=A.prototype.S;A.prototype.set=A.prototype.C;A.prototype.setProperties=A.prototype.M;A.prototype.unset=A.prototype.$;A.prototype.changed=A.prototype.A;A.prototype.dispatchEvent=A.prototype.B; +A.prototype.getRevision=A.prototype.W;A.prototype.on=A.prototype.K;A.prototype.once=A.prototype.X;A.prototype.un=A.prototype.Y;A.prototype.unByKey=A.prototype.Z;w("ol.DeviceOrientation",Oo);Oo.prototype.getAlpha=Oo.prototype.Wg;Oo.prototype.getBeta=Oo.prototype.Zg;Oo.prototype.getGamma=Oo.prototype.oh;Oo.prototype.getHeading=Oo.prototype.Mi;Oo.prototype.getTracking=Oo.prototype.sf;Oo.prototype.setTracking=Oo.prototype.ae;Oo.prototype.get=Oo.prototype.get;Oo.prototype.getKeys=Oo.prototype.P; +Oo.prototype.getProperties=Oo.prototype.S;Oo.prototype.set=Oo.prototype.C;Oo.prototype.setProperties=Oo.prototype.M;Oo.prototype.unset=Oo.prototype.$;Oo.prototype.changed=Oo.prototype.A;Oo.prototype.dispatchEvent=Oo.prototype.B;Oo.prototype.getRevision=Oo.prototype.W;Oo.prototype.on=Oo.prototype.K;Oo.prototype.once=Oo.prototype.X;Oo.prototype.un=Oo.prototype.Y;Oo.prototype.unByKey=Oo.prototype.Z;w("ol.Feature",Ym);Ym.prototype.clone=Ym.prototype.clone;Ym.prototype.getGeometry=Ym.prototype.R; +Ym.prototype.getId=Ym.prototype.Ja;Ym.prototype.getGeometryName=Ym.prototype.qh;Ym.prototype.getStyle=Ym.prototype.Oi;Ym.prototype.getStyleFunction=Ym.prototype.Lb;Ym.prototype.setGeometry=Ym.prototype.Xa;Ym.prototype.setStyle=Ym.prototype.be;Ym.prototype.setId=Ym.prototype.te;Ym.prototype.setGeometryName=Ym.prototype.ld;Ym.prototype.get=Ym.prototype.get;Ym.prototype.getKeys=Ym.prototype.P;Ym.prototype.getProperties=Ym.prototype.S;Ym.prototype.set=Ym.prototype.C;Ym.prototype.setProperties=Ym.prototype.M; +Ym.prototype.unset=Ym.prototype.$;Ym.prototype.changed=Ym.prototype.A;Ym.prototype.dispatchEvent=Ym.prototype.B;Ym.prototype.getRevision=Ym.prototype.W;Ym.prototype.on=Ym.prototype.K;Ym.prototype.once=Ym.prototype.X;Ym.prototype.un=Ym.prototype.Y;Ym.prototype.unByKey=Ym.prototype.Z;w("ol.Geolocation",gs);gs.prototype.getAccuracy=gs.prototype.Ug;gs.prototype.getAccuracyGeometry=gs.prototype.Vg;gs.prototype.getAltitude=gs.prototype.Qi;gs.prototype.getAltitudeAccuracy=gs.prototype.Xg; +gs.prototype.getHeading=gs.prototype.Ri;gs.prototype.getPosition=gs.prototype.Si;gs.prototype.getProjection=gs.prototype.tf;gs.prototype.getSpeed=gs.prototype.Kh;gs.prototype.getTracking=gs.prototype.uf;gs.prototype.getTrackingOptions=gs.prototype.hf;gs.prototype.setProjection=gs.prototype.vf;gs.prototype.setTracking=gs.prototype.Xc;gs.prototype.setTrackingOptions=gs.prototype.ig;gs.prototype.get=gs.prototype.get;gs.prototype.getKeys=gs.prototype.P;gs.prototype.getProperties=gs.prototype.S; +gs.prototype.set=gs.prototype.C;gs.prototype.setProperties=gs.prototype.M;gs.prototype.unset=gs.prototype.$;gs.prototype.changed=gs.prototype.A;gs.prototype.dispatchEvent=gs.prototype.B;gs.prototype.getRevision=gs.prototype.W;gs.prototype.on=gs.prototype.K;gs.prototype.once=gs.prototype.X;gs.prototype.un=gs.prototype.Y;gs.prototype.unByKey=gs.prototype.Z;Oe.prototype.getImage=Oe.prototype.Mb;w("ol.Map",R);R.prototype.addControl=R.prototype.zg;R.prototype.addInteraction=R.prototype.Ag; +R.prototype.addLayer=R.prototype.Bg;R.prototype.addOverlay=R.prototype.Cg;R.prototype.beforeRender=R.prototype.Fa;R.prototype.forEachFeatureAtPixel=R.prototype.Fd;R.prototype.forEachLayerAtPixel=R.prototype.Yi;R.prototype.hasFeatureAtPixel=R.prototype.ri;R.prototype.getEventCoordinate=R.prototype.ih;R.prototype.getEventPixel=R.prototype.Gc;R.prototype.getTarget=R.prototype.wf;R.prototype.getTargetElement=R.prototype.hc;R.prototype.getCoordinateFromPixel=R.prototype.ua;R.prototype.getControls=R.prototype.eh; +R.prototype.getOverlays=R.prototype.Fh;R.prototype.getOverlayById=R.prototype.Eh;R.prototype.getInteractions=R.prototype.sh;R.prototype.getLayerGroup=R.prototype.Oa;R.prototype.getLayers=R.prototype.Zi;R.prototype.getPixelFromCoordinate=R.prototype.Ga;R.prototype.getSize=R.prototype.rb;R.prototype.getView=R.prototype.ja;R.prototype.getViewport=R.prototype.Rh;R.prototype.renderSync=R.prototype.Xk;R.prototype.render=R.prototype.render;R.prototype.removeControl=R.prototype.Rk; +R.prototype.removeInteraction=R.prototype.Sk;R.prototype.removeLayer=R.prototype.Uk;R.prototype.removeOverlay=R.prototype.Vk;R.prototype.setLayerGroup=R.prototype.il;R.prototype.setSize=R.prototype.we;R.prototype.setTarget=R.prototype.$i;R.prototype.setView=R.prototype.aj;R.prototype.updateSize=R.prototype.Be;R.prototype.get=R.prototype.get;R.prototype.getKeys=R.prototype.P;R.prototype.getProperties=R.prototype.S;R.prototype.set=R.prototype.C;R.prototype.setProperties=R.prototype.M; +R.prototype.unset=R.prototype.$;R.prototype.changed=R.prototype.A;R.prototype.dispatchEvent=R.prototype.B;R.prototype.getRevision=R.prototype.W;R.prototype.on=R.prototype.K;R.prototype.once=R.prototype.X;R.prototype.un=R.prototype.Y;R.prototype.unByKey=R.prototype.Z;Wj.prototype.originalEvent=Wj.prototype.originalEvent;Wj.prototype.pixel=Wj.prototype.pixel;Wj.prototype.coordinate=Wj.prototype.coordinate;Wj.prototype.dragging=Wj.prototype.dragging;Wj.prototype.preventDefault=Wj.prototype.preventDefault; +Wj.prototype.stopPropagation=Wj.prototype.i;Wj.prototype.map=Wj.prototype.map;Wj.prototype.frameState=Wj.prototype.frameState;w("ol.Observable.unByKey",Gc);w("ol.Overlay",Fo);Fo.prototype.getElement=Fo.prototype.ce;Fo.prototype.getId=Fo.prototype.Ja;Fo.prototype.getMap=Fo.prototype.Yc;Fo.prototype.getOffset=Fo.prototype.ff;Fo.prototype.getPosition=Fo.prototype.xf;Fo.prototype.getPositioning=Fo.prototype.gf;Fo.prototype.setElement=Fo.prototype.$f;Fo.prototype.setMap=Fo.prototype.setMap; +Fo.prototype.setOffset=Fo.prototype.cg;Fo.prototype.setPosition=Fo.prototype.yf;Fo.prototype.setPositioning=Fo.prototype.fg;Fo.prototype.get=Fo.prototype.get;Fo.prototype.getKeys=Fo.prototype.P;Fo.prototype.getProperties=Fo.prototype.S;Fo.prototype.set=Fo.prototype.C;Fo.prototype.setProperties=Fo.prototype.M;Fo.prototype.unset=Fo.prototype.$;Fo.prototype.changed=Fo.prototype.A;Fo.prototype.dispatchEvent=Fo.prototype.B;Fo.prototype.getRevision=Fo.prototype.W;Fo.prototype.on=Fo.prototype.K; +Fo.prototype.once=Fo.prototype.X;Fo.prototype.un=Fo.prototype.Y;Fo.prototype.unByKey=Fo.prototype.Z;w("ol.View",N);N.prototype.constrainCenter=N.prototype.Ec;N.prototype.constrainResolution=N.prototype.constrainResolution;N.prototype.constrainRotation=N.prototype.constrainRotation;N.prototype.getCenter=N.prototype.wa;N.prototype.calculateExtent=N.prototype.Jg;N.prototype.getProjection=N.prototype.bj;N.prototype.getResolution=N.prototype.V;N.prototype.getRotation=N.prototype.xa; +N.prototype.getZoom=N.prototype.Th;N.prototype.fit=N.prototype.We;N.prototype.centerOn=N.prototype.Lg;N.prototype.rotate=N.prototype.rotate;N.prototype.setCenter=N.prototype.Ca;N.prototype.setResolution=N.prototype.xb;N.prototype.setRotation=N.prototype.Nb;N.prototype.setZoom=N.prototype.tl;N.prototype.get=N.prototype.get;N.prototype.getKeys=N.prototype.P;N.prototype.getProperties=N.prototype.S;N.prototype.set=N.prototype.C;N.prototype.setProperties=N.prototype.M;N.prototype.unset=N.prototype.$; +N.prototype.changed=N.prototype.A;N.prototype.dispatchEvent=N.prototype.B;N.prototype.getRevision=N.prototype.W;N.prototype.on=N.prototype.K;N.prototype.once=N.prototype.X;N.prototype.un=N.prototype.Y;N.prototype.unByKey=N.prototype.Z; +w("ol.animation.bounce",function(b){var c=b.resolution,d=b.start?b.start:Date.now(),e=void 0!==b.duration?b.duration:1E3,f=b.easing?b.easing:ni;return function(b,h){if(h.time<d)return h.animate=!0,h.viewHints[0]+=1,!0;if(h.time<d+e){var l=f((h.time-d)/e),m=c-h.viewState.resolution;h.animate=!0;h.viewState.resolution+=l*m;h.viewHints[0]+=1;return!0}return!1}});w("ol.animation.pan",oi);w("ol.animation.rotate",pi);w("ol.animation.zoom",qi);w("ol.color.asArray",Vg);w("ol.color.asString",Xg); +w("ol.control.MousePosition",Pi);Pi.prototype.getCoordinateFormat=Pi.prototype.Xe;Pi.prototype.getProjection=Pi.prototype.zf;Pi.prototype.setMap=Pi.prototype.setMap;Pi.prototype.setCoordinateFormat=Pi.prototype.Zf;Pi.prototype.setProjection=Pi.prototype.Af;Pi.prototype.getMap=Pi.prototype.J;Pi.prototype.setMap=Pi.prototype.setMap;Pi.prototype.setTarget=Pi.prototype.u;Pi.prototype.get=Pi.prototype.get;Pi.prototype.getKeys=Pi.prototype.P;Pi.prototype.getProperties=Pi.prototype.S;Pi.prototype.set=Pi.prototype.C; +Pi.prototype.setProperties=Pi.prototype.M;Pi.prototype.unset=Pi.prototype.$;Pi.prototype.changed=Pi.prototype.A;Pi.prototype.dispatchEvent=Pi.prototype.B;Pi.prototype.getRevision=Pi.prototype.W;Pi.prototype.on=Pi.prototype.K;Pi.prototype.once=Pi.prototype.X;Pi.prototype.un=Pi.prototype.Y;Pi.prototype.unByKey=Pi.prototype.Z;w("ol.control.ScaleLine",Jo);Jo.prototype.getUnits=Jo.prototype.v;Jo.prototype.setUnits=Jo.prototype.L;Jo.prototype.getMap=Jo.prototype.J;Jo.prototype.setMap=Jo.prototype.setMap; +Jo.prototype.setTarget=Jo.prototype.u;Jo.prototype.get=Jo.prototype.get;Jo.prototype.getKeys=Jo.prototype.P;Jo.prototype.getProperties=Jo.prototype.S;Jo.prototype.set=Jo.prototype.C;Jo.prototype.setProperties=Jo.prototype.M;Jo.prototype.unset=Jo.prototype.$;Jo.prototype.changed=Jo.prototype.A;Jo.prototype.dispatchEvent=Jo.prototype.B;Jo.prototype.getRevision=Jo.prototype.W;Jo.prototype.on=Jo.prototype.K;Jo.prototype.once=Jo.prototype.X;Jo.prototype.un=Jo.prototype.Y;Jo.prototype.unByKey=Jo.prototype.Z; +w("ol.control.ZoomToExtent",No);No.prototype.getMap=No.prototype.J;No.prototype.setMap=No.prototype.setMap;No.prototype.setTarget=No.prototype.u;No.prototype.get=No.prototype.get;No.prototype.getKeys=No.prototype.P;No.prototype.getProperties=No.prototype.S;No.prototype.set=No.prototype.C;No.prototype.setProperties=No.prototype.M;No.prototype.unset=No.prototype.$;No.prototype.changed=No.prototype.A;No.prototype.dispatchEvent=No.prototype.B;No.prototype.getRevision=No.prototype.W;No.prototype.on=No.prototype.K; +No.prototype.once=No.prototype.X;No.prototype.un=No.prototype.Y;No.prototype.unByKey=No.prototype.Z;w("ol.control.defaults",Oi);w("ol.coordinate.format",Yc);w("ol.coordinate.toStringHDMS",function(b){return b?Xc(b[1],"NS")+" "+Xc(b[0],"EW"):""});w("ol.coordinate.toStringXY",function(b,c){return Yc(b,"{x}, {y}",c)});w("ol.easing.easeOut",li);w("ol.easing.linear",hg);w("ol.extent.buffer",ld);w("ol.extent.containsCoordinate",od);w("ol.extent.containsXY",pd);w("ol.extent.getCenter",Ed); +w("ol.extent.getHeight",Dd);w("ol.extent.getWidth",Bd);w("ol.extent.intersects",Hd);w("ol.format.GeoJSON",gp);gp.prototype.readFeature=gp.prototype.oe;gp.prototype.readFeatures=gp.prototype.jd;gp.prototype.readGeometry=gp.prototype.Tf;gp.prototype.readProjection=gp.prototype.vc;gp.prototype.writeFeature=gp.prototype.pg;gp.prototype.writeFeatureObject=gp.prototype.a;gp.prototype.writeFeatures=gp.prototype.Ce;gp.prototype.writeFeaturesObject=gp.prototype.b;gp.prototype.writeGeometry=gp.prototype.qg; +gp.prototype.writeGeometryObject=gp.prototype.c;w("ol.format.KML",Sp);Sp.prototype.readFeature=Sp.prototype.oe;Sp.prototype.readFeatures=Sp.prototype.jd;Sp.prototype.readName=Sp.prototype.Mk;Sp.prototype.readNetworkLinks=Sp.prototype.Nk;Sp.prototype.readProjection=Sp.prototype.vc;Sp.prototype.writeFeatures=Sp.prototype.Ce;Sp.prototype.writeFeaturesNode=Sp.prototype.f;w("ol.format.WMSCapabilities",Jr);Jr.prototype.read=Jr.prototype.a;w("ol.geom.Circle",Y);Y.prototype.clone=Y.prototype.clone; +Y.prototype.getCenter=Y.prototype.lc;Y.prototype.getRadius=Y.prototype.ee;Y.prototype.getType=Y.prototype.N;Y.prototype.intersectsExtent=Y.prototype.ta;Y.prototype.setCenter=Y.prototype.ej;Y.prototype.setCenterAndRadius=Y.prototype.se;Y.prototype.setRadius=Y.prototype.ml;Y.prototype.transform=Y.prototype.transform;Y.prototype.getFirstCoordinate=Y.prototype.Va;Y.prototype.getLastCoordinate=Y.prototype.cb;Y.prototype.getLayout=Y.prototype.eb;Y.prototype.getClosestPoint=Y.prototype.Ta; +Y.prototype.getExtent=Y.prototype.G;Y.prototype.simplify=Y.prototype.Za;Y.prototype.get=Y.prototype.get;Y.prototype.getKeys=Y.prototype.P;Y.prototype.getProperties=Y.prototype.S;Y.prototype.set=Y.prototype.C;Y.prototype.setProperties=Y.prototype.M;Y.prototype.unset=Y.prototype.$;Y.prototype.changed=Y.prototype.A;Y.prototype.dispatchEvent=Y.prototype.B;Y.prototype.getRevision=Y.prototype.W;Y.prototype.on=Y.prototype.K;Y.prototype.once=Y.prototype.X;Y.prototype.un=Y.prototype.Y; +Y.prototype.unByKey=Y.prototype.Z;w("ol.geom.GeometryCollection",W);W.prototype.clone=W.prototype.clone;W.prototype.getGeometries=W.prototype.Ye;W.prototype.getType=W.prototype.N;W.prototype.intersectsExtent=W.prototype.ta;W.prototype.setGeometries=W.prototype.ag;W.prototype.applyTransform=W.prototype.Eb;W.prototype.translate=W.prototype.fe;W.prototype.getClosestPoint=W.prototype.Ta;W.prototype.getExtent=W.prototype.G;W.prototype.simplify=W.prototype.Za;W.prototype.transform=W.prototype.transform; +W.prototype.get=W.prototype.get;W.prototype.getKeys=W.prototype.P;W.prototype.getProperties=W.prototype.S;W.prototype.set=W.prototype.C;W.prototype.setProperties=W.prototype.M;W.prototype.unset=W.prototype.$;W.prototype.changed=W.prototype.A;W.prototype.dispatchEvent=W.prototype.B;W.prototype.getRevision=W.prototype.W;W.prototype.on=W.prototype.K;W.prototype.once=W.prototype.X;W.prototype.un=W.prototype.Y;W.prototype.unByKey=W.prototype.Z;w("ol.geom.LinearRing",Wh);Wh.prototype.clone=Wh.prototype.clone; +Wh.prototype.getArea=Wh.prototype.hj;Wh.prototype.getCoordinates=Wh.prototype.T;Wh.prototype.getType=Wh.prototype.N;Wh.prototype.setCoordinates=Wh.prototype.ia;Wh.prototype.getFirstCoordinate=Wh.prototype.Va;Wh.prototype.getLastCoordinate=Wh.prototype.cb;Wh.prototype.getLayout=Wh.prototype.eb;Wh.prototype.getClosestPoint=Wh.prototype.Ta;Wh.prototype.getExtent=Wh.prototype.G;Wh.prototype.simplify=Wh.prototype.Za;Wh.prototype.transform=Wh.prototype.transform;Wh.prototype.get=Wh.prototype.get; +Wh.prototype.getKeys=Wh.prototype.P;Wh.prototype.getProperties=Wh.prototype.S;Wh.prototype.set=Wh.prototype.C;Wh.prototype.setProperties=Wh.prototype.M;Wh.prototype.unset=Wh.prototype.$;Wh.prototype.changed=Wh.prototype.A;Wh.prototype.dispatchEvent=Wh.prototype.B;Wh.prototype.getRevision=Wh.prototype.W;Wh.prototype.on=Wh.prototype.K;Wh.prototype.once=Wh.prototype.X;Wh.prototype.un=Wh.prototype.Y;Wh.prototype.unByKey=Wh.prototype.Z;w("ol.geom.LineString",S);S.prototype.appendCoordinate=S.prototype.Dg; +S.prototype.clone=S.prototype.clone;S.prototype.forEachSegment=S.prototype.Tg;S.prototype.getCoordinateAtM=S.prototype.fj;S.prototype.getCoordinates=S.prototype.T;S.prototype.getLength=S.prototype.gj;S.prototype.getType=S.prototype.N;S.prototype.intersectsExtent=S.prototype.ta;S.prototype.setCoordinates=S.prototype.ia;S.prototype.getFirstCoordinate=S.prototype.Va;S.prototype.getLastCoordinate=S.prototype.cb;S.prototype.getLayout=S.prototype.eb;S.prototype.getClosestPoint=S.prototype.Ta; +S.prototype.getExtent=S.prototype.G;S.prototype.simplify=S.prototype.Za;S.prototype.transform=S.prototype.transform;S.prototype.get=S.prototype.get;S.prototype.getKeys=S.prototype.P;S.prototype.getProperties=S.prototype.S;S.prototype.set=S.prototype.C;S.prototype.setProperties=S.prototype.M;S.prototype.unset=S.prototype.$;S.prototype.changed=S.prototype.A;S.prototype.dispatchEvent=S.prototype.B;S.prototype.getRevision=S.prototype.W;S.prototype.on=S.prototype.K;S.prototype.once=S.prototype.X; +S.prototype.un=S.prototype.Y;S.prototype.unByKey=S.prototype.Z;w("ol.geom.MultiLineString",T);T.prototype.appendLineString=T.prototype.Eg;T.prototype.clone=T.prototype.clone;T.prototype.getCoordinateAtM=T.prototype.ij;T.prototype.getCoordinates=T.prototype.T;T.prototype.getLineString=T.prototype.xh;T.prototype.getLineStrings=T.prototype.Jd;T.prototype.getType=T.prototype.N;T.prototype.intersectsExtent=T.prototype.ta;T.prototype.setCoordinates=T.prototype.ia;T.prototype.getFirstCoordinate=T.prototype.Va; +T.prototype.getLastCoordinate=T.prototype.cb;T.prototype.getLayout=T.prototype.eb;T.prototype.getClosestPoint=T.prototype.Ta;T.prototype.getExtent=T.prototype.G;T.prototype.simplify=T.prototype.Za;T.prototype.transform=T.prototype.transform;T.prototype.get=T.prototype.get;T.prototype.getKeys=T.prototype.P;T.prototype.getProperties=T.prototype.S;T.prototype.set=T.prototype.C;T.prototype.setProperties=T.prototype.M;T.prototype.unset=T.prototype.$;T.prototype.changed=T.prototype.A; +T.prototype.dispatchEvent=T.prototype.B;T.prototype.getRevision=T.prototype.W;T.prototype.on=T.prototype.K;T.prototype.once=T.prototype.X;T.prototype.un=T.prototype.Y;T.prototype.unByKey=T.prototype.Z;w("ol.geom.MultiPoint",U);U.prototype.appendPoint=U.prototype.Gg;U.prototype.clone=U.prototype.clone;U.prototype.getCoordinates=U.prototype.T;U.prototype.getPoint=U.prototype.jj;U.prototype.getPoints=U.prototype.ge;U.prototype.getType=U.prototype.N;U.prototype.intersectsExtent=U.prototype.ta; +U.prototype.setCoordinates=U.prototype.ia;U.prototype.getFirstCoordinate=U.prototype.Va;U.prototype.getLastCoordinate=U.prototype.cb;U.prototype.getLayout=U.prototype.eb;U.prototype.getClosestPoint=U.prototype.Ta;U.prototype.getExtent=U.prototype.G;U.prototype.simplify=U.prototype.Za;U.prototype.transform=U.prototype.transform;U.prototype.get=U.prototype.get;U.prototype.getKeys=U.prototype.P;U.prototype.getProperties=U.prototype.S;U.prototype.set=U.prototype.C;U.prototype.setProperties=U.prototype.M; +U.prototype.unset=U.prototype.$;U.prototype.changed=U.prototype.A;U.prototype.dispatchEvent=U.prototype.B;U.prototype.getRevision=U.prototype.W;U.prototype.on=U.prototype.K;U.prototype.once=U.prototype.X;U.prototype.un=U.prototype.Y;U.prototype.unByKey=U.prototype.Z;w("ol.geom.MultiPolygon",V);V.prototype.appendPolygon=V.prototype.Hg;V.prototype.clone=V.prototype.clone;V.prototype.getArea=V.prototype.kj;V.prototype.getCoordinates=V.prototype.T;V.prototype.getInteriorPoints=V.prototype.uh; +V.prototype.getPolygon=V.prototype.Hh;V.prototype.getPolygons=V.prototype.Ld;V.prototype.getType=V.prototype.N;V.prototype.intersectsExtent=V.prototype.ta;V.prototype.setCoordinates=V.prototype.ia;V.prototype.getFirstCoordinate=V.prototype.Va;V.prototype.getLastCoordinate=V.prototype.cb;V.prototype.getLayout=V.prototype.eb;V.prototype.getClosestPoint=V.prototype.Ta;V.prototype.getExtent=V.prototype.G;V.prototype.simplify=V.prototype.Za;V.prototype.transform=V.prototype.transform;V.prototype.get=V.prototype.get; +V.prototype.getKeys=V.prototype.P;V.prototype.getProperties=V.prototype.S;V.prototype.set=V.prototype.C;V.prototype.setProperties=V.prototype.M;V.prototype.unset=V.prototype.$;V.prototype.changed=V.prototype.A;V.prototype.dispatchEvent=V.prototype.B;V.prototype.getRevision=V.prototype.W;V.prototype.on=V.prototype.K;V.prototype.once=V.prototype.X;V.prototype.un=V.prototype.Y;V.prototype.unByKey=V.prototype.Z;w("ol.geom.Point",L);L.prototype.clone=L.prototype.clone;L.prototype.getCoordinates=L.prototype.T; +L.prototype.getType=L.prototype.N;L.prototype.intersectsExtent=L.prototype.ta;L.prototype.setCoordinates=L.prototype.ia;L.prototype.getFirstCoordinate=L.prototype.Va;L.prototype.getLastCoordinate=L.prototype.cb;L.prototype.getLayout=L.prototype.eb;L.prototype.getClosestPoint=L.prototype.Ta;L.prototype.getExtent=L.prototype.G;L.prototype.simplify=L.prototype.Za;L.prototype.transform=L.prototype.transform;L.prototype.get=L.prototype.get;L.prototype.getKeys=L.prototype.P;L.prototype.getProperties=L.prototype.S; +L.prototype.set=L.prototype.C;L.prototype.setProperties=L.prototype.M;L.prototype.unset=L.prototype.$;L.prototype.changed=L.prototype.A;L.prototype.dispatchEvent=L.prototype.B;L.prototype.getRevision=L.prototype.W;L.prototype.on=L.prototype.K;L.prototype.once=L.prototype.X;L.prototype.un=L.prototype.Y;L.prototype.unByKey=L.prototype.Z;w("ol.geom.Polygon",M);M.prototype.appendLinearRing=M.prototype.Fg;M.prototype.clone=M.prototype.clone;M.prototype.getArea=M.prototype.lj; +M.prototype.getCoordinates=M.prototype.T;M.prototype.getInteriorPoint=M.prototype.th;M.prototype.getLinearRingCount=M.prototype.yh;M.prototype.getLinearRing=M.prototype.cf;M.prototype.getLinearRings=M.prototype.Kd;M.prototype.getType=M.prototype.N;M.prototype.intersectsExtent=M.prototype.ta;M.prototype.setCoordinates=M.prototype.ia;M.prototype.getFirstCoordinate=M.prototype.Va;M.prototype.getLastCoordinate=M.prototype.cb;M.prototype.getLayout=M.prototype.eb;M.prototype.getClosestPoint=M.prototype.Ta; +M.prototype.getExtent=M.prototype.G;M.prototype.simplify=M.prototype.Za;M.prototype.transform=M.prototype.transform;M.prototype.get=M.prototype.get;M.prototype.getKeys=M.prototype.P;M.prototype.getProperties=M.prototype.S;M.prototype.set=M.prototype.C;M.prototype.setProperties=M.prototype.M;M.prototype.unset=M.prototype.$;M.prototype.changed=M.prototype.A;M.prototype.dispatchEvent=M.prototype.B;M.prototype.getRevision=M.prototype.W;M.prototype.on=M.prototype.K;M.prototype.once=M.prototype.X; +M.prototype.un=M.prototype.Y;M.prototype.unByKey=M.prototype.Z;w("ol.has.DEVICE_ORIENTATION",bh);w("ol.has.DEVICE_PIXEL_RATIO",Zg);w("ol.interaction.DragBox",pl);pl.prototype.getGeometry=pl.prototype.R;pl.prototype.getActive=pl.prototype.j;pl.prototype.setActive=pl.prototype.l;pl.prototype.get=pl.prototype.get;pl.prototype.getKeys=pl.prototype.P;pl.prototype.getProperties=pl.prototype.S;pl.prototype.set=pl.prototype.C;pl.prototype.setProperties=pl.prototype.M;pl.prototype.unset=pl.prototype.$; +pl.prototype.changed=pl.prototype.A;pl.prototype.dispatchEvent=pl.prototype.B;pl.prototype.getRevision=pl.prototype.W;pl.prototype.on=pl.prototype.K;pl.prototype.once=pl.prototype.X;pl.prototype.un=pl.prototype.Y;pl.prototype.unByKey=pl.prototype.Z;w("ol.interaction.DragZoom",tl);tl.prototype.getGeometry=tl.prototype.R;tl.prototype.getActive=tl.prototype.j;tl.prototype.setActive=tl.prototype.l;tl.prototype.get=tl.prototype.get;tl.prototype.getKeys=tl.prototype.P;tl.prototype.getProperties=tl.prototype.S; +tl.prototype.set=tl.prototype.C;tl.prototype.setProperties=tl.prototype.M;tl.prototype.unset=tl.prototype.$;tl.prototype.changed=tl.prototype.A;tl.prototype.dispatchEvent=tl.prototype.B;tl.prototype.getRevision=tl.prototype.W;tl.prototype.on=tl.prototype.K;tl.prototype.once=tl.prototype.X;tl.prototype.un=tl.prototype.Y;tl.prototype.unByKey=tl.prototype.Z;w("ol.interaction.Draw",ks);ks.prototype.removeLastPoint=ks.prototype.Tk;ks.prototype.finishDrawing=ks.prototype.ec;ks.prototype.extend=ks.prototype.mj; +ks.prototype.getActive=ks.prototype.j;ks.prototype.setActive=ks.prototype.l;ks.prototype.get=ks.prototype.get;ks.prototype.getKeys=ks.prototype.P;ks.prototype.getProperties=ks.prototype.S;ks.prototype.set=ks.prototype.C;ks.prototype.setProperties=ks.prototype.M;ks.prototype.unset=ks.prototype.$;ks.prototype.changed=ks.prototype.A;ks.prototype.dispatchEvent=ks.prototype.B;ks.prototype.getRevision=ks.prototype.W;ks.prototype.on=ks.prototype.K;ks.prototype.once=ks.prototype.X;ks.prototype.un=ks.prototype.Y; +ks.prototype.unByKey=ks.prototype.Z;w("ol.interaction.KeyboardPan",ul);ul.prototype.getActive=ul.prototype.j;ul.prototype.setActive=ul.prototype.l;ul.prototype.get=ul.prototype.get;ul.prototype.getKeys=ul.prototype.P;ul.prototype.getProperties=ul.prototype.S;ul.prototype.set=ul.prototype.C;ul.prototype.setProperties=ul.prototype.M;ul.prototype.unset=ul.prototype.$;ul.prototype.changed=ul.prototype.A;ul.prototype.dispatchEvent=ul.prototype.B;ul.prototype.getRevision=ul.prototype.W; +ul.prototype.on=ul.prototype.K;ul.prototype.once=ul.prototype.X;ul.prototype.un=ul.prototype.Y;ul.prototype.unByKey=ul.prototype.Z;w("ol.interaction.KeyboardZoom",wl);wl.prototype.getActive=wl.prototype.j;wl.prototype.setActive=wl.prototype.l;wl.prototype.get=wl.prototype.get;wl.prototype.getKeys=wl.prototype.P;wl.prototype.getProperties=wl.prototype.S;wl.prototype.set=wl.prototype.C;wl.prototype.setProperties=wl.prototype.M;wl.prototype.unset=wl.prototype.$;wl.prototype.changed=wl.prototype.A; +wl.prototype.dispatchEvent=wl.prototype.B;wl.prototype.getRevision=wl.prototype.W;wl.prototype.on=wl.prototype.K;wl.prototype.once=wl.prototype.X;wl.prototype.un=wl.prototype.Y;wl.prototype.unByKey=wl.prototype.Z;w("ol.interaction.Modify",Bs);Bs.prototype.getActive=Bs.prototype.j;Bs.prototype.setActive=Bs.prototype.l;Bs.prototype.get=Bs.prototype.get;Bs.prototype.getKeys=Bs.prototype.P;Bs.prototype.getProperties=Bs.prototype.S;Bs.prototype.set=Bs.prototype.C;Bs.prototype.setProperties=Bs.prototype.M; +Bs.prototype.unset=Bs.prototype.$;Bs.prototype.changed=Bs.prototype.A;Bs.prototype.dispatchEvent=Bs.prototype.B;Bs.prototype.getRevision=Bs.prototype.W;Bs.prototype.on=Bs.prototype.K;Bs.prototype.once=Bs.prototype.X;Bs.prototype.un=Bs.prototype.Y;Bs.prototype.unByKey=Bs.prototype.Z;w("ol.interaction.Select",Ps);Ps.prototype.getFeatures=Ps.prototype.wj;Ps.prototype.getLayer=Ps.prototype.xj;Ps.prototype.setMap=Ps.prototype.setMap;Ps.prototype.getActive=Ps.prototype.j;Ps.prototype.setActive=Ps.prototype.l; +Ps.prototype.get=Ps.prototype.get;Ps.prototype.getKeys=Ps.prototype.P;Ps.prototype.getProperties=Ps.prototype.S;Ps.prototype.set=Ps.prototype.C;Ps.prototype.setProperties=Ps.prototype.M;Ps.prototype.unset=Ps.prototype.$;Ps.prototype.changed=Ps.prototype.A;Ps.prototype.dispatchEvent=Ps.prototype.B;Ps.prototype.getRevision=Ps.prototype.W;Ps.prototype.on=Ps.prototype.K;Ps.prototype.once=Ps.prototype.X;Ps.prototype.un=Ps.prototype.Y;Ps.prototype.unByKey=Ps.prototype.Z;w("ol.interaction.Snap",Ss); +Ss.prototype.addFeature=Ss.prototype.mc;Ss.prototype.removeFeature=Ss.prototype.nc;Ss.prototype.getActive=Ss.prototype.j;Ss.prototype.setActive=Ss.prototype.l;Ss.prototype.get=Ss.prototype.get;Ss.prototype.getKeys=Ss.prototype.P;Ss.prototype.getProperties=Ss.prototype.S;Ss.prototype.set=Ss.prototype.C;Ss.prototype.setProperties=Ss.prototype.M;Ss.prototype.unset=Ss.prototype.$;Ss.prototype.changed=Ss.prototype.A;Ss.prototype.dispatchEvent=Ss.prototype.B;Ss.prototype.getRevision=Ss.prototype.W; +Ss.prototype.on=Ss.prototype.K;Ss.prototype.once=Ss.prototype.X;Ss.prototype.un=Ss.prototype.Y;Ss.prototype.unByKey=Ss.prototype.Z;w("ol.interaction.defaults",Il);w("ol.layer.Group",C);C.prototype.getLayers=C.prototype.Na;C.prototype.setLayers=C.prototype.bg;C.prototype.getExtent=C.prototype.G;C.prototype.getMaxResolution=C.prototype.Ib;C.prototype.getMinResolution=C.prototype.Jb;C.prototype.getOpacity=C.prototype.tb;C.prototype.getVisible=C.prototype.Ha;C.prototype.getZIndex=C.prototype.ma; +C.prototype.setExtent=C.prototype.oc;C.prototype.setMaxResolution=C.prototype.wc;C.prototype.setMinResolution=C.prototype.xc;C.prototype.setOpacity=C.prototype.pc;C.prototype.setVisible=C.prototype.ub;C.prototype.setZIndex=C.prototype.qc;C.prototype.get=C.prototype.get;C.prototype.getKeys=C.prototype.P;C.prototype.getProperties=C.prototype.S;C.prototype.set=C.prototype.C;C.prototype.setProperties=C.prototype.M;C.prototype.unset=C.prototype.$;C.prototype.changed=C.prototype.A; +C.prototype.dispatchEvent=C.prototype.B;C.prototype.getRevision=C.prototype.W;C.prototype.on=C.prototype.K;C.prototype.once=C.prototype.X;C.prototype.un=C.prototype.Y;C.prototype.unByKey=C.prototype.Z;w("ol.layer.Image",I);I.prototype.getSource=I.prototype.da;I.prototype.setMap=I.prototype.setMap;I.prototype.setSource=I.prototype.yc;I.prototype.getExtent=I.prototype.G;I.prototype.getMaxResolution=I.prototype.Ib;I.prototype.getMinResolution=I.prototype.Jb;I.prototype.getOpacity=I.prototype.tb; +I.prototype.getVisible=I.prototype.Ha;I.prototype.getZIndex=I.prototype.ma;I.prototype.setExtent=I.prototype.oc;I.prototype.setMaxResolution=I.prototype.wc;I.prototype.setMinResolution=I.prototype.xc;I.prototype.setOpacity=I.prototype.pc;I.prototype.setVisible=I.prototype.ub;I.prototype.setZIndex=I.prototype.qc;I.prototype.get=I.prototype.get;I.prototype.getKeys=I.prototype.P;I.prototype.getProperties=I.prototype.S;I.prototype.set=I.prototype.C;I.prototype.setProperties=I.prototype.M; +I.prototype.unset=I.prototype.$;I.prototype.changed=I.prototype.A;I.prototype.dispatchEvent=I.prototype.B;I.prototype.getRevision=I.prototype.W;I.prototype.on=I.prototype.K;I.prototype.once=I.prototype.X;I.prototype.un=I.prototype.Y;I.prototype.unByKey=I.prototype.Z;w("ol.layer.Layer",D);D.prototype.getSource=D.prototype.da;D.prototype.setMap=D.prototype.setMap;D.prototype.setSource=D.prototype.yc;D.prototype.getExtent=D.prototype.G;D.prototype.getMaxResolution=D.prototype.Ib; +D.prototype.getMinResolution=D.prototype.Jb;D.prototype.getOpacity=D.prototype.tb;D.prototype.getVisible=D.prototype.Ha;D.prototype.getZIndex=D.prototype.ma;D.prototype.setExtent=D.prototype.oc;D.prototype.setMaxResolution=D.prototype.wc;D.prototype.setMinResolution=D.prototype.xc;D.prototype.setOpacity=D.prototype.pc;D.prototype.setVisible=D.prototype.ub;D.prototype.setZIndex=D.prototype.qc;D.prototype.get=D.prototype.get;D.prototype.getKeys=D.prototype.P;D.prototype.getProperties=D.prototype.S; +D.prototype.set=D.prototype.C;D.prototype.setProperties=D.prototype.M;D.prototype.unset=D.prototype.$;D.prototype.changed=D.prototype.A;D.prototype.dispatchEvent=D.prototype.B;D.prototype.getRevision=D.prototype.W;D.prototype.on=D.prototype.K;D.prototype.once=D.prototype.X;D.prototype.un=D.prototype.Y;D.prototype.unByKey=D.prototype.Z;w("ol.layer.Tile",F);F.prototype.getPreload=F.prototype.a;F.prototype.getSource=F.prototype.da;F.prototype.setPreload=F.prototype.j; +F.prototype.getUseInterimTilesOnError=F.prototype.i;F.prototype.setUseInterimTilesOnError=F.prototype.l;F.prototype.setMap=F.prototype.setMap;F.prototype.setSource=F.prototype.yc;F.prototype.getExtent=F.prototype.G;F.prototype.getMaxResolution=F.prototype.Ib;F.prototype.getMinResolution=F.prototype.Jb;F.prototype.getOpacity=F.prototype.tb;F.prototype.getVisible=F.prototype.Ha;F.prototype.getZIndex=F.prototype.ma;F.prototype.setExtent=F.prototype.oc;F.prototype.setMaxResolution=F.prototype.wc; +F.prototype.setMinResolution=F.prototype.xc;F.prototype.setOpacity=F.prototype.pc;F.prototype.setVisible=F.prototype.ub;F.prototype.setZIndex=F.prototype.qc;F.prototype.get=F.prototype.get;F.prototype.getKeys=F.prototype.P;F.prototype.getProperties=F.prototype.S;F.prototype.set=F.prototype.C;F.prototype.setProperties=F.prototype.M;F.prototype.unset=F.prototype.$;F.prototype.changed=F.prototype.A;F.prototype.dispatchEvent=F.prototype.B;F.prototype.getRevision=F.prototype.W;F.prototype.on=F.prototype.K; +F.prototype.once=F.prototype.X;F.prototype.un=F.prototype.Y;F.prototype.unByKey=F.prototype.Z;w("ol.layer.Vector",J);J.prototype.getSource=J.prototype.da;J.prototype.getStyle=J.prototype.u;J.prototype.getStyleFunction=J.prototype.D;J.prototype.setStyle=J.prototype.l;J.prototype.setMap=J.prototype.setMap;J.prototype.setSource=J.prototype.yc;J.prototype.getExtent=J.prototype.G;J.prototype.getMaxResolution=J.prototype.Ib;J.prototype.getMinResolution=J.prototype.Jb;J.prototype.getOpacity=J.prototype.tb; +J.prototype.getVisible=J.prototype.Ha;J.prototype.getZIndex=J.prototype.ma;J.prototype.setExtent=J.prototype.oc;J.prototype.setMaxResolution=J.prototype.wc;J.prototype.setMinResolution=J.prototype.xc;J.prototype.setOpacity=J.prototype.pc;J.prototype.setVisible=J.prototype.ub;J.prototype.setZIndex=J.prototype.qc;J.prototype.get=J.prototype.get;J.prototype.getKeys=J.prototype.P;J.prototype.getProperties=J.prototype.S;J.prototype.set=J.prototype.C;J.prototype.setProperties=J.prototype.M; +J.prototype.unset=J.prototype.$;J.prototype.changed=J.prototype.A;J.prototype.dispatchEvent=J.prototype.B;J.prototype.getRevision=J.prototype.W;J.prototype.on=J.prototype.K;J.prototype.once=J.prototype.X;J.prototype.un=J.prototype.Y;J.prototype.unByKey=J.prototype.Z;w("ol.proj.Projection",Xd);Xd.prototype.getCode=Xd.prototype.dh;Xd.prototype.getExtent=Xd.prototype.G;Xd.prototype.getUnits=Xd.prototype.Hj;Xd.prototype.getMetersPerUnit=Xd.prototype.nb;Xd.prototype.getWorldExtent=Xd.prototype.Sh; +Xd.prototype.isGlobal=Xd.prototype.ui;Xd.prototype.setGlobal=Xd.prototype.fl;Xd.prototype.setExtent=Xd.prototype.Ij;Xd.prototype.setWorldExtent=Xd.prototype.sl;Xd.prototype.setGetPointResolution=Xd.prototype.el;Xd.prototype.getPointResolution=Xd.prototype.getPointResolution;w("ol.proj.get",Zd);w("ol.proj.transform",le);w("ol.proj.transformExtent",me);w("ol.style.Circle",ph);ph.prototype.getFill=ph.prototype.Zj;ph.prototype.getImage=ph.prototype.ib;ph.prototype.getRadius=ph.prototype.$j; +ph.prototype.getStroke=ph.prototype.ak;ph.prototype.getOpacity=ph.prototype.cd;ph.prototype.getRotateWithView=ph.prototype.Jc;ph.prototype.getRotation=ph.prototype.dd;ph.prototype.getScale=ph.prototype.ed;ph.prototype.getSnapToPixel=ph.prototype.Kc;ph.prototype.setOpacity=ph.prototype.fd;ph.prototype.setRotation=ph.prototype.gd;ph.prototype.setScale=ph.prototype.hd;w("ol.style.Fill",jh);jh.prototype.getColor=jh.prototype.b;jh.prototype.setColor=jh.prototype.c;w("ol.style.Icon",Pg); +Pg.prototype.getAnchor=Pg.prototype.mb;Pg.prototype.getImage=Pg.prototype.ib;Pg.prototype.getOrigin=Pg.prototype.Aa;Pg.prototype.getSrc=Pg.prototype.bk;Pg.prototype.getSize=Pg.prototype.Ya;Pg.prototype.load=Pg.prototype.load;Pg.prototype.getOpacity=Pg.prototype.cd;Pg.prototype.getRotateWithView=Pg.prototype.Jc;Pg.prototype.getRotation=Pg.prototype.dd;Pg.prototype.getScale=Pg.prototype.ed;Pg.prototype.getSnapToPixel=Pg.prototype.Kc;Pg.prototype.setOpacity=Pg.prototype.fd;Pg.prototype.setRotation=Pg.prototype.gd; +Pg.prototype.setScale=Pg.prototype.hd;w("ol.style.Image",kh);kh.prototype.getOpacity=kh.prototype.cd;kh.prototype.getRotateWithView=kh.prototype.Jc;kh.prototype.getRotation=kh.prototype.dd;kh.prototype.getScale=kh.prototype.ed;kh.prototype.getSnapToPixel=kh.prototype.Kc;kh.prototype.setOpacity=kh.prototype.fd;kh.prototype.setRotation=kh.prototype.gd;kh.prototype.setScale=kh.prototype.hd;w("ol.style.RegularShape",ct);ct.prototype.getAnchor=ct.prototype.mb;ct.prototype.getAngle=ct.prototype.ck; +ct.prototype.getFill=ct.prototype.dk;ct.prototype.getImage=ct.prototype.ib;ct.prototype.getOrigin=ct.prototype.Aa;ct.prototype.getPoints=ct.prototype.ek;ct.prototype.getRadius=ct.prototype.fk;ct.prototype.getRadius2=ct.prototype.Ih;ct.prototype.getSize=ct.prototype.Ya;ct.prototype.getStroke=ct.prototype.gk;ct.prototype.getOpacity=ct.prototype.cd;ct.prototype.getRotateWithView=ct.prototype.Jc;ct.prototype.getRotation=ct.prototype.dd;ct.prototype.getScale=ct.prototype.ed; +ct.prototype.getSnapToPixel=ct.prototype.Kc;ct.prototype.setOpacity=ct.prototype.fd;ct.prototype.setRotation=ct.prototype.gd;ct.prototype.setScale=ct.prototype.hd;w("ol.style.Stroke",oh);oh.prototype.getColor=oh.prototype.hk;oh.prototype.getLineCap=oh.prototype.vh;oh.prototype.getLineDash=oh.prototype.ik;oh.prototype.getLineJoin=oh.prototype.wh;oh.prototype.getMiterLimit=oh.prototype.Ah;oh.prototype.getWidth=oh.prototype.jk;oh.prototype.setColor=oh.prototype.kk;oh.prototype.setLineCap=oh.prototype.jl; +oh.prototype.setLineDash=oh.prototype.lk;oh.prototype.setLineJoin=oh.prototype.kl;oh.prototype.setMiterLimit=oh.prototype.ll;oh.prototype.setWidth=oh.prototype.rl;w("ol.style.Style",qh);qh.prototype.getGeometry=qh.prototype.R;qh.prototype.getGeometryFunction=qh.prototype.ph;qh.prototype.getFill=qh.prototype.va;qh.prototype.getImage=qh.prototype.mk;qh.prototype.getStroke=qh.prototype.sa;qh.prototype.getText=qh.prototype.na;qh.prototype.getZIndex=qh.prototype.ma;qh.prototype.setGeometry=qh.prototype.Pf; +qh.prototype.setZIndex=qh.prototype.nk;w("ol.style.Text",Rp);Rp.prototype.getFont=Rp.prototype.nh;Rp.prototype.getOffsetX=Rp.prototype.Bh;Rp.prototype.getOffsetY=Rp.prototype.Ch;Rp.prototype.getFill=Rp.prototype.va;Rp.prototype.getRotation=Rp.prototype.pk;Rp.prototype.getScale=Rp.prototype.qk;Rp.prototype.getStroke=Rp.prototype.sa;Rp.prototype.getText=Rp.prototype.na;Rp.prototype.getTextAlign=Rp.prototype.Lh;Rp.prototype.getTextBaseline=Rp.prototype.Mh;Rp.prototype.setFont=Rp.prototype.dl; +Rp.prototype.setOffsetX=Rp.prototype.dg;Rp.prototype.setOffsetY=Rp.prototype.eg;Rp.prototype.setFill=Rp.prototype.cl;Rp.prototype.setRotation=Rp.prototype.rk;Rp.prototype.setScale=Rp.prototype.sk;Rp.prototype.setStroke=Rp.prototype.ol;Rp.prototype.setText=Rp.prototype.gg;Rp.prototype.setTextAlign=Rp.prototype.hg;Rp.prototype.setTextBaseline=Rp.prototype.pl;w("ol.source.ImageVector",Qg);Qg.prototype.getSource=Qg.prototype.Jj;Qg.prototype.getStyle=Qg.prototype.Kj;Qg.prototype.getStyleFunction=Qg.prototype.Lj; +Qg.prototype.setStyle=Qg.prototype.Gf;Qg.prototype.getAttributions=Qg.prototype.Ob;Qg.prototype.getLogo=Qg.prototype.Hb;Qg.prototype.getProjection=Qg.prototype.Pb;Qg.prototype.getState=Qg.prototype.Qb;Qg.prototype.setAttributions=Qg.prototype.Tb;Qg.prototype.get=Qg.prototype.get;Qg.prototype.getKeys=Qg.prototype.P;Qg.prototype.getProperties=Qg.prototype.S;Qg.prototype.set=Qg.prototype.C;Qg.prototype.setProperties=Qg.prototype.M;Qg.prototype.unset=Qg.prototype.$;Qg.prototype.changed=Qg.prototype.A; +Qg.prototype.dispatchEvent=Qg.prototype.B;Qg.prototype.getRevision=Qg.prototype.W;Qg.prototype.on=Qg.prototype.K;Qg.prototype.once=Qg.prototype.X;Qg.prototype.un=Qg.prototype.Y;Qg.prototype.unByKey=Qg.prototype.Z;w("ol.source.ImageWMS",Ws);Ws.prototype.getGetFeatureInfoUrl=Ws.prototype.Oj;Ws.prototype.getParams=Ws.prototype.Pj;Ws.prototype.getImageLoadFunction=Ws.prototype.rh;Ws.prototype.getUrl=Ws.prototype.Ph;Ws.prototype.setImageLoadFunction=Ws.prototype.hl;Ws.prototype.setUrl=Ws.prototype.Qj; +Ws.prototype.updateParams=Ws.prototype.Rj;Ws.prototype.getAttributions=Ws.prototype.Ob;Ws.prototype.getLogo=Ws.prototype.Hb;Ws.prototype.getProjection=Ws.prototype.Pb;Ws.prototype.getState=Ws.prototype.Qb;Ws.prototype.setAttributions=Ws.prototype.Tb;Ws.prototype.get=Ws.prototype.get;Ws.prototype.getKeys=Ws.prototype.P;Ws.prototype.getProperties=Ws.prototype.S;Ws.prototype.set=Ws.prototype.C;Ws.prototype.setProperties=Ws.prototype.M;Ws.prototype.unset=Ws.prototype.$;Ws.prototype.changed=Ws.prototype.A; +Ws.prototype.dispatchEvent=Ws.prototype.B;Ws.prototype.getRevision=Ws.prototype.W;Ws.prototype.on=Ws.prototype.K;Ws.prototype.once=Ws.prototype.X;Ws.prototype.un=Ws.prototype.Y;Ws.prototype.unByKey=Ws.prototype.Z;w("ol.source.TileImage",G);G.prototype.setRenderReprojectionEdges=G.prototype.ve;G.prototype.setTileGridForProjection=G.prototype.xe;G.prototype.getTileLoadFunction=G.prototype.Rd;G.prototype.getTileUrlFunction=G.prototype.Sd;G.prototype.getUrls=G.prototype.Td; +G.prototype.setTileLoadFunction=G.prototype.ye;G.prototype.setTileUrlFunction=G.prototype.Ub;G.prototype.setUrl=G.prototype.ad;G.prototype.setUrls=G.prototype.md;G.prototype.getTileGrid=G.prototype.Qd;G.prototype.getAttributions=G.prototype.Ob;G.prototype.getLogo=G.prototype.Hb;G.prototype.getProjection=G.prototype.Pb;G.prototype.getState=G.prototype.Qb;G.prototype.setAttributions=G.prototype.Tb;G.prototype.get=G.prototype.get;G.prototype.getKeys=G.prototype.P;G.prototype.getProperties=G.prototype.S; +G.prototype.set=G.prototype.C;G.prototype.setProperties=G.prototype.M;G.prototype.unset=G.prototype.$;G.prototype.changed=G.prototype.A;G.prototype.dispatchEvent=G.prototype.B;G.prototype.getRevision=G.prototype.W;G.prototype.on=G.prototype.K;G.prototype.once=G.prototype.X;G.prototype.un=G.prototype.Y;G.prototype.unByKey=G.prototype.Z;w("ol.source.TileWMS",Z);Z.prototype.getGetFeatureInfoUrl=Z.prototype.Sj;Z.prototype.getParams=Z.prototype.Tj;Z.prototype.updateParams=Z.prototype.Uj; +Z.prototype.setRenderReprojectionEdges=Z.prototype.ve;Z.prototype.setTileGridForProjection=Z.prototype.xe;Z.prototype.getTileLoadFunction=Z.prototype.Rd;Z.prototype.getTileUrlFunction=Z.prototype.Sd;Z.prototype.getUrls=Z.prototype.Td;Z.prototype.setTileLoadFunction=Z.prototype.ye;Z.prototype.setTileUrlFunction=Z.prototype.Ub;Z.prototype.setUrl=Z.prototype.ad;Z.prototype.setUrls=Z.prototype.md;Z.prototype.getTileGrid=Z.prototype.Qd;Z.prototype.getAttributions=Z.prototype.Ob;Z.prototype.getLogo=Z.prototype.Hb; +Z.prototype.getProjection=Z.prototype.Pb;Z.prototype.getState=Z.prototype.Qb;Z.prototype.setAttributions=Z.prototype.Tb;Z.prototype.get=Z.prototype.get;Z.prototype.getKeys=Z.prototype.P;Z.prototype.getProperties=Z.prototype.S;Z.prototype.set=Z.prototype.C;Z.prototype.setProperties=Z.prototype.M;Z.prototype.unset=Z.prototype.$;Z.prototype.changed=Z.prototype.A;Z.prototype.dispatchEvent=Z.prototype.B;Z.prototype.getRevision=Z.prototype.W;Z.prototype.on=Z.prototype.K;Z.prototype.once=Z.prototype.X; +Z.prototype.un=Z.prototype.Y;Z.prototype.unByKey=Z.prototype.Z;w("ol.source.Vector",K);K.prototype.addFeature=K.prototype.bd;K.prototype.addFeatures=K.prototype.rd;K.prototype.clear=K.prototype.clear;K.prototype.forEachFeature=K.prototype.Pg;K.prototype.forEachFeatureInExtent=K.prototype.Fb;K.prototype.forEachFeatureIntersectingExtent=K.prototype.Rg;K.prototype.getFeaturesCollection=K.prototype.lh;K.prototype.getFeatures=K.prototype.ke;K.prototype.getFeaturesAtCoordinate=K.prototype.kh; +K.prototype.getFeaturesInExtent=K.prototype.mh;K.prototype.getClosestFeatureToCoordinate=K.prototype.bh;K.prototype.getExtent=K.prototype.G;K.prototype.getFeatureById=K.prototype.jh;K.prototype.removeFeature=K.prototype.sc;K.prototype.getAttributions=K.prototype.Ob;K.prototype.getLogo=K.prototype.Hb;K.prototype.getProjection=K.prototype.Pb;K.prototype.getState=K.prototype.Qb;K.prototype.setAttributions=K.prototype.Tb;K.prototype.get=K.prototype.get;K.prototype.getKeys=K.prototype.P; +K.prototype.getProperties=K.prototype.S;K.prototype.set=K.prototype.C;K.prototype.setProperties=K.prototype.M;K.prototype.unset=K.prototype.$;K.prototype.changed=K.prototype.A;K.prototype.dispatchEvent=K.prototype.B;K.prototype.getRevision=K.prototype.W;K.prototype.on=K.prototype.K;K.prototype.once=K.prototype.X;K.prototype.un=K.prototype.Y;K.prototype.unByKey=K.prototype.Z;w("ol.source.WMTS",H);H.prototype.getDimensions=H.prototype.gh;H.prototype.getFormat=H.prototype.Wj;H.prototype.getLayer=H.prototype.Xj; +H.prototype.getMatrixSet=H.prototype.zh;H.prototype.getRequestEncoding=H.prototype.Jh;H.prototype.getStyle=H.prototype.Yj;H.prototype.getVersion=H.prototype.Qh;H.prototype.updateDimensions=H.prototype.Al;H.prototype.setRenderReprojectionEdges=H.prototype.ve;H.prototype.setTileGridForProjection=H.prototype.xe;H.prototype.getTileLoadFunction=H.prototype.Rd;H.prototype.getTileUrlFunction=H.prototype.Sd;H.prototype.getUrls=H.prototype.Td;H.prototype.setTileLoadFunction=H.prototype.ye; +H.prototype.setTileUrlFunction=H.prototype.Ub;H.prototype.setUrl=H.prototype.ad;H.prototype.setUrls=H.prototype.md;H.prototype.getTileGrid=H.prototype.Qd;H.prototype.getAttributions=H.prototype.Ob;H.prototype.getLogo=H.prototype.Hb;H.prototype.getProjection=H.prototype.Pb;H.prototype.getState=H.prototype.Qb;H.prototype.setAttributions=H.prototype.Tb;H.prototype.get=H.prototype.get;H.prototype.getKeys=H.prototype.P;H.prototype.getProperties=H.prototype.S;H.prototype.set=H.prototype.C; +H.prototype.setProperties=H.prototype.M;H.prototype.unset=H.prototype.$;H.prototype.changed=H.prototype.A;H.prototype.dispatchEvent=H.prototype.B;H.prototype.getRevision=H.prototype.W;H.prototype.on=H.prototype.K;H.prototype.once=H.prototype.X;H.prototype.un=H.prototype.Y;H.prototype.unByKey=H.prototype.Z;w("ol.tilegrid.TileGrid",Ff);Ff.prototype.getMaxZoom=Ff.prototype.df;Ff.prototype.getMinZoom=Ff.prototype.ef;Ff.prototype.getOrigin=Ff.prototype.Aa;Ff.prototype.getResolution=Ff.prototype.V; +Ff.prototype.getResolutions=Ff.prototype.Qf;Ff.prototype.getTileCoordExtent=Ff.prototype.Ka;Ff.prototype.getTileCoordForCoordAndResolution=Ff.prototype.Od;Ff.prototype.getTileCoordForCoordAndZ=Ff.prototype.Pd;Ff.prototype.getTileSize=Ff.prototype.La;w("ol.tilegrid.WMTS",bg);bg.prototype.getMatrixIds=bg.prototype.l;bg.prototype.getMaxZoom=bg.prototype.df;bg.prototype.getMinZoom=bg.prototype.ef;bg.prototype.getOrigin=bg.prototype.Aa;bg.prototype.getResolution=bg.prototype.V; +bg.prototype.getResolutions=bg.prototype.Qf;bg.prototype.getTileCoordExtent=bg.prototype.Ka;bg.prototype.getTileCoordForCoordAndResolution=bg.prototype.Od;bg.prototype.getTileCoordForCoordAndZ=bg.prototype.Pd;bg.prototype.getTileSize=bg.prototype.La; diff --git a/test/specs/Loader.spec.js b/test/specs/Loader.spec.js index 9157eb3751..14e80bb31b 100644 --- a/test/specs/Loader.spec.js +++ b/test/specs/Loader.spec.js @@ -44,7 +44,7 @@ beforeEach(function() { }); }); - module('ga'); + module('geoadmin'); // Configure the $translate service in such a way that no // requests to translation files are performed.